summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/removed/o2cb2
-rw-r--r--Documentation/ABI/removed/raw13942
-rw-r--r--Documentation/ABI/testing/evm23
-rw-r--r--Documentation/ABI/testing/sysfs-bus-bcma8
-rw-r--r--Documentation/ABI/testing/sysfs-bus-pci-drivers-ehci_hcd46
-rw-r--r--Documentation/ABI/testing/sysfs-bus-usb15
-rw-r--r--Documentation/ABI/testing/sysfs-class-backlight-driver-adp887016
-rw-r--r--Documentation/ABI/testing/sysfs-class-devfreq52
-rw-r--r--Documentation/ABI/testing/sysfs-class-net-mesh8
-rw-r--r--Documentation/ABI/testing/sysfs-class-scsi_host13
-rw-r--r--Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff7
-rw-r--r--Documentation/DocBook/80211.tmpl11
-rw-r--r--Documentation/DocBook/media/v4l/controls.xml38
-rw-r--r--Documentation/DocBook/uio-howto.tmpl2
-rw-r--r--Documentation/PCI/pci.txt2
-rw-r--r--Documentation/blackfin/bfin-gpio-notes.txt2
-rw-r--r--Documentation/block/biodoc.txt2
-rw-r--r--Documentation/bus-virt-phys-mapping.txt2
-rw-r--r--Documentation/cdrom/packet-writing.txt2
-rw-r--r--Documentation/cgroups/memory.txt85
-rw-r--r--Documentation/cpu-freq/governors.txt2
-rw-r--r--Documentation/development-process/4.Coding2
-rw-r--r--Documentation/devicetree/bindings/arm/l2cc.txt44
-rw-r--r--Documentation/devicetree/bindings/gpio/led.txt2
-rw-r--r--Documentation/devicetree/bindings/net/can/fsl-flexcan.txt63
-rw-r--r--Documentation/devicetree/bindings/net/smsc911x.txt38
-rw-r--r--Documentation/driver-model/binding.txt4
-rw-r--r--Documentation/driver-model/device.txt65
-rw-r--r--Documentation/feature-removal-schedule.txt17
-rw-r--r--Documentation/filesystems/9p.txt2
-rw-r--r--Documentation/filesystems/caching/object.txt6
-rw-r--r--Documentation/filesystems/locks.txt11
-rw-r--r--Documentation/filesystems/nfs/idmapper.txt2
-rw-r--r--Documentation/filesystems/pohmelfs/design_notes.txt5
-rw-r--r--Documentation/filesystems/proc.txt2
-rw-r--r--Documentation/filesystems/sysfs.txt10
-rw-r--r--Documentation/filesystems/vfs.txt3
-rw-r--r--Documentation/frv/booting.txt6
-rw-r--r--Documentation/hwmon/ad731425
-rw-r--r--Documentation/hwmon/adm127540
-rw-r--r--Documentation/hwmon/coretemp14
-rw-r--r--Documentation/hwmon/exynos4_tmu81
-rw-r--r--Documentation/hwmon/lm7561
-rw-r--r--Documentation/hwmon/ltc2978103
-rw-r--r--Documentation/hwmon/max160657
-rw-r--r--Documentation/hwmon/pmbus13
-rw-r--r--Documentation/hwmon/pmbus-core283
-rw-r--r--Documentation/hwmon/zl6100125
-rw-r--r--Documentation/input/input.txt2
-rw-r--r--Documentation/ioctl/ioctl-number.txt2
-rw-r--r--Documentation/kernel-docs.txt4
-rw-r--r--Documentation/kernel-parameters.txt41
-rw-r--r--Documentation/laptops/thinkpad-acpi.txt4
-rw-r--r--Documentation/media-framework.txt4
-rw-r--r--Documentation/memory-barriers.txt2
-rw-r--r--Documentation/networking/00-INDEX116
-rw-r--r--Documentation/networking/batman-adv.txt8
-rw-r--r--Documentation/networking/dmfe.txt3
-rw-r--r--Documentation/networking/ip-sysctl.txt23
-rw-r--r--Documentation/networking/mac80211-injection.txt4
-rw-r--r--Documentation/networking/netdevices.txt4
-rw-r--r--Documentation/networking/scaling.txt37
-rw-r--r--Documentation/networking/stmmac.txt44
-rw-r--r--Documentation/pinctrl.txt950
-rw-r--r--Documentation/power/00-INDEX2
-rw-r--r--Documentation/power/basic-pm-debugging.txt26
-rw-r--r--Documentation/power/devices.txt8
-rw-r--r--Documentation/power/pm_qos_interface.txt92
-rw-r--r--Documentation/power/runtime_pm.txt24
-rw-r--r--Documentation/power/suspend-and-cpuhotplug.txt275
-rw-r--r--Documentation/power/userland-swsusp.txt3
-rw-r--r--Documentation/rfkill.txt3
-rw-r--r--Documentation/scsi/aic7xxx_old.txt2
-rw-r--r--Documentation/scsi/scsi_mid_low_api.txt5
-rw-r--r--Documentation/security/keys-trusted-encrypted.txt3
-rw-r--r--Documentation/sound/oss/PAS163
-rw-r--r--Documentation/spi/pxa2xx4
-rw-r--r--Documentation/stable_kernel_rules.txt14
-rw-r--r--Documentation/timers/highres.txt2
-rw-r--r--Documentation/usb/dma.txt6
-rw-r--r--Documentation/usb/dwc3.txt45
-rw-r--r--Documentation/usb/power-management.txt34
-rw-r--r--Documentation/virtual/lguest/lguest.c2
-rw-r--r--Documentation/vm/numa4
-rw-r--r--Documentation/vm/slub.txt2
-rw-r--r--Documentation/vm/transhuge.txt7
-rw-r--r--Documentation/zh_CN/SubmitChecklist109
-rw-r--r--MAINTAINERS315
-rw-r--r--Makefile2
-rw-r--r--arch/alpha/Kconfig2
-rw-r--r--arch/alpha/include/asm/fcntl.h2
-rw-r--r--arch/alpha/include/asm/sysinfo.h9
-rw-r--r--arch/alpha/include/asm/thread_info.h8
-rw-r--r--arch/alpha/kernel/osf_sys.c12
-rw-r--r--arch/alpha/kernel/srm_env.c5
-rw-r--r--arch/alpha/kernel/systbls.S2
-rw-r--r--arch/arm/Kconfig85
-rw-r--r--arch/arm/Kconfig.debug91
-rw-r--r--arch/arm/Makefile3
-rw-r--r--arch/arm/boot/Makefile9
-rw-r--r--arch/arm/boot/compressed/Makefile8
-rw-r--r--arch/arm/boot/compressed/mmcif-sh7372.c2
-rw-r--r--arch/arm/boot/compressed/sdhi-sh7372.c2
-rw-r--r--arch/arm/boot/dts/tegra-harmony.dts12
-rw-r--r--arch/arm/boot/dts/tegra-seaboard.dts6
-rw-r--r--arch/arm/common/gic.c17
-rw-r--r--arch/arm/common/pl330.c2
-rw-r--r--arch/arm/common/vic.c4
-rw-r--r--arch/arm/configs/integrator_defconfig19
-rw-r--r--arch/arm/include/asm/Kbuild17
-rw-r--r--arch/arm/include/asm/auxvec.h4
-rw-r--r--arch/arm/include/asm/bitsperlong.h1
-rw-r--r--arch/arm/include/asm/bug.h55
-rw-r--r--arch/arm/include/asm/cachetype.h5
-rw-r--r--arch/arm/include/asm/cputime.h6
-rw-r--r--arch/arm/include/asm/cputype.h6
-rw-r--r--arch/arm/include/asm/device.h3
-rw-r--r--arch/arm/include/asm/dma-mapping.h2
-rw-r--r--arch/arm/include/asm/ecard.h1
-rw-r--r--arch/arm/include/asm/emergency-restart.h6
-rw-r--r--arch/arm/include/asm/errno.h6
-rw-r--r--arch/arm/include/asm/exception.h19
-rw-r--r--arch/arm/include/asm/futex.h34
-rw-r--r--arch/arm/include/asm/hardware/cache-l2x0.h53
-rw-r--r--arch/arm/include/asm/io.h40
-rw-r--r--arch/arm/include/asm/ioctl.h1
-rw-r--r--arch/arm/include/asm/irq_regs.h1
-rw-r--r--arch/arm/include/asm/kdebug.h1
-rw-r--r--arch/arm/include/asm/local.h1
-rw-r--r--arch/arm/include/asm/local64.h1
-rw-r--r--arch/arm/include/asm/localtimer.h6
-rw-r--r--arch/arm/include/asm/mach/arch.h3
-rw-r--r--arch/arm/include/asm/memory.h7
-rw-r--r--arch/arm/include/asm/module.h4
-rw-r--r--arch/arm/include/asm/outercache.h7
-rw-r--r--arch/arm/include/asm/page.h42
-rw-r--r--arch/arm/include/asm/percpu.h6
-rw-r--r--arch/arm/include/asm/pgalloc.h4
-rw-r--r--arch/arm/include/asm/pgtable-2level-hwdef.h93
-rw-r--r--arch/arm/include/asm/pgtable-2level-types.h67
-rw-r--r--arch/arm/include/asm/pgtable-2level.h143
-rw-r--r--arch/arm/include/asm/pgtable-hwdef.h77
-rw-r--r--arch/arm/include/asm/pgtable.h141
-rw-r--r--arch/arm/include/asm/pmu.h10
-rw-r--r--arch/arm/include/asm/poll.h1
-rw-r--r--arch/arm/include/asm/resource.h6
-rw-r--r--arch/arm/include/asm/sections.h1
-rw-r--r--arch/arm/include/asm/siginfo.h6
-rw-r--r--arch/arm/include/asm/sizes.h21
-rw-r--r--arch/arm/include/asm/smp.h11
-rw-r--r--arch/arm/include/asm/system.h11
-rw-r--r--arch/arm/include/asm/tlbflush.h4
-rw-r--r--arch/arm/include/asm/topology.h33
-rw-r--r--arch/arm/include/asm/unistd.h4
-rw-r--r--arch/arm/kernel/Makefile3
-rw-r--r--arch/arm/kernel/armksyms.c3
-rw-r--r--arch/arm/kernel/asm-offsets.c12
-rw-r--r--arch/arm/kernel/bios32.c9
-rw-r--r--arch/arm/kernel/calls.S2
-rw-r--r--arch/arm/kernel/debug.S4
-rw-r--r--arch/arm/kernel/ecard.c36
-rw-r--r--arch/arm/kernel/entry-armv.S44
-rw-r--r--arch/arm/kernel/head.S135
-rw-r--r--arch/arm/kernel/irq.c2
-rw-r--r--arch/arm/kernel/machine_kexec.c35
-rw-r--r--arch/arm/kernel/module.c2
-rw-r--r--arch/arm/kernel/perf_event_v7.c4
-rw-r--r--arch/arm/kernel/pmu.c26
-rw-r--r--arch/arm/kernel/process.c2
-rw-r--r--arch/arm/kernel/relocate_kernel.S3
-rw-r--r--arch/arm/kernel/setup.c52
-rw-r--r--arch/arm/kernel/smp.c55
-rw-r--r--arch/arm/kernel/smp_scu.c12
-rw-r--r--arch/arm/kernel/smp_twd.c4
-rw-r--r--arch/arm/kernel/time.c6
-rw-r--r--arch/arm/kernel/topology.c148
-rw-r--r--arch/arm/kernel/traps.c32
-rw-r--r--arch/arm/kernel/vmlinux.lds.S18
-rw-r--r--arch/arm/lib/backtrace.S6
-rw-r--r--arch/arm/lib/div64.S8
-rw-r--r--arch/arm/lib/uaccess_with_memcpy.c1
-rw-r--r--arch/arm/mach-at91/Makefile.boot6
-rw-r--r--arch/arm/mach-at91/at91sam9261.c2
-rw-r--r--arch/arm/mach-bcmring/Kconfig2
-rw-r--r--arch/arm/mach-bcmring/Makefile.boot2
-rw-r--r--arch/arm/mach-bcmring/arch.c4
-rw-r--r--arch/arm/mach-bcmring/irq.c1
-rw-r--r--arch/arm/mach-bcmring/timer.c1
-rw-r--r--arch/arm/mach-clps711x/Makefile.boot2
-rw-r--r--arch/arm/mach-clps711x/clep7312.c3
-rw-r--r--arch/arm/mach-clps711x/edb7211-arch.c3
-rw-r--r--arch/arm/mach-clps711x/fortunet.c3
-rw-r--r--arch/arm/mach-clps711x/p720t.c3
-rw-r--r--arch/arm/mach-cns3xxx/Makefile.boot2
-rw-r--r--arch/arm/mach-cns3xxx/include/mach/entry-macro.S1
-rw-r--r--arch/arm/mach-cns3xxx/include/mach/system.h1
-rw-r--r--arch/arm/mach-cns3xxx/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-cns3xxx/pcie.c2
-rw-r--r--arch/arm/mach-davinci/Makefile.boot4
-rw-r--r--arch/arm/mach-davinci/board-da850-evm.c28
-rw-r--r--arch/arm/mach-davinci/include/mach/psc.h2
-rw-r--r--arch/arm/mach-davinci/sleep.S6
-rw-r--r--arch/arm/mach-dove/Makefile.boot2
-rw-r--r--arch/arm/mach-dove/common.c2
-rw-r--r--arch/arm/mach-ebsa110/Makefile.boot2
-rw-r--r--arch/arm/mach-ebsa110/include/mach/io.h2
-rw-r--r--arch/arm/mach-ep93xx/Makefile.boot10
-rw-r--r--arch/arm/mach-ep93xx/include/mach/ts72xx.h26
-rw-r--r--arch/arm/mach-exynos4/Kconfig1
-rw-r--r--arch/arm/mach-exynos4/Makefile.boot2
-rw-r--r--arch/arm/mach-exynos4/clock.c10
-rw-r--r--arch/arm/mach-exynos4/cpu.c11
-rw-r--r--arch/arm/mach-exynos4/include/mach/irqs.h5
-rw-r--r--arch/arm/mach-exynos4/include/mach/regs-pmu.h2
-rw-r--r--arch/arm/mach-exynos4/irq-eint.c7
-rw-r--r--arch/arm/mach-exynos4/mach-universal_c210.c4
-rw-r--r--arch/arm/mach-exynos4/mct.c10
-rw-r--r--arch/arm/mach-exynos4/platsmp.c12
-rw-r--r--arch/arm/mach-exynos4/setup-keypad.c11
-rw-r--r--arch/arm/mach-exynos4/setup-usb-phy.c2
-rw-r--r--arch/arm/mach-footbridge/Kconfig3
-rw-r--r--arch/arm/mach-footbridge/Makefile.boot2
-rw-r--r--arch/arm/mach-footbridge/cats-hw.c3
-rw-r--r--arch/arm/mach-footbridge/dc21285.c1
-rw-r--r--arch/arm/mach-footbridge/include/mach/io.h2
-rw-r--r--arch/arm/mach-footbridge/netwinder-hw.c3
-rw-r--r--arch/arm/mach-gemini/Makefile.boot4
-rw-r--r--arch/arm/mach-h720x/Makefile.boot2
-rw-r--r--arch/arm/mach-imx/Makefile.boot10
-rw-r--r--arch/arm/mach-imx/mach-cpuimx27.c2
-rw-r--r--arch/arm/mach-imx/mach-cpuimx35.c2
-rw-r--r--arch/arm/mach-imx/mach-eukrea_cpuimx25.c2
-rw-r--r--arch/arm/mach-integrator/Makefile.boot2
-rw-r--r--arch/arm/mach-integrator/core.c4
-rw-r--r--arch/arm/mach-integrator/include/mach/io.h2
-rw-r--r--arch/arm/mach-integrator/include/mach/platform.h12
-rw-r--r--arch/arm/mach-integrator/integrator_ap.c94
-rw-r--r--arch/arm/mach-integrator/pci_v3.c2
-rw-r--r--arch/arm/mach-iop13xx/Makefile.boot2
-rw-r--r--arch/arm/mach-iop32x/Makefile.boot2
-rw-r--r--arch/arm/mach-iop33x/Makefile.boot2
-rw-r--r--arch/arm/mach-ixp2000/Makefile.boot2
-rw-r--r--arch/arm/mach-ixp23xx/Makefile.boot2
-rw-r--r--arch/arm/mach-ixp4xx/Makefile.boot2
-rw-r--r--arch/arm/mach-ixp4xx/common-pci.c3
-rw-r--r--arch/arm/mach-ixp4xx/include/mach/io.h2
-rw-r--r--arch/arm/mach-kirkwood/Makefile.boot2
-rw-r--r--arch/arm/mach-ks8695/Makefile.boot2
-rw-r--r--arch/arm/mach-lpc32xx/Makefile.boot2
-rw-r--r--arch/arm/mach-mmp/Makefile.boot2
-rw-r--r--arch/arm/mach-mmp/aspenite.c2
-rw-r--r--arch/arm/mach-mmp/include/mach/pxa168.h7
-rw-r--r--arch/arm/mach-mmp/pxa168.c46
-rw-r--r--arch/arm/mach-mmp/ttc_dkb.c2
-rw-r--r--arch/arm/mach-msm/Makefile.boot2
-rw-r--r--arch/arm/mach-msm/board-halibut.c4
-rw-r--r--arch/arm/mach-msm/board-mahimahi.c4
-rw-r--r--arch/arm/mach-msm/board-msm7x30.c22
-rw-r--r--arch/arm/mach-msm/board-msm8960.c22
-rw-r--r--arch/arm/mach-msm/board-msm8x60.c25
-rw-r--r--arch/arm/mach-msm/board-sapphire.c4
-rw-r--r--arch/arm/mach-msm/board-trout.c4
-rw-r--r--arch/arm/mach-msm/clock.c2
-rw-r--r--arch/arm/mach-msm/include/mach/memory.h6
-rw-r--r--arch/arm/mach-msm/platsmp.c6
-rw-r--r--arch/arm/mach-mv78xx0/Makefile.boot2
-rw-r--r--arch/arm/mach-mx5/Makefile.boot6
-rw-r--r--arch/arm/mach-mxs/Makefile.boot2
-rw-r--r--arch/arm/mach-netx/Makefile.boot2
-rw-r--r--arch/arm/mach-nomadik/Makefile.boot2
-rw-r--r--arch/arm/mach-nuc93x/Makefile.boot2
-rw-r--r--arch/arm/mach-nuc93x/time.c2
-rw-r--r--arch/arm/mach-omap1/Makefile.boot2
-rw-r--r--arch/arm/mach-omap1/pm_bus.c1
-rw-r--r--arch/arm/mach-omap2/Kconfig2
-rw-r--r--arch/arm/mach-omap2/Makefile11
-rw-r--r--arch/arm/mach-omap2/Makefile.boot2
-rw-r--r--arch/arm/mach-omap2/board-2430sdp.c3
-rw-r--r--arch/arm/mach-omap2/clock3xxx_data.c2
-rw-r--r--arch/arm/mach-omap2/clock44xx_data.c10
-rw-r--r--arch/arm/mach-omap2/clockdomain.c2
-rw-r--r--arch/arm/mach-omap2/hsmmc.c12
-rw-r--r--arch/arm/mach-omap2/omap-smp.c10
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_2430_data.c1
-rw-r--r--arch/arm/mach-omap2/pm.c2
-rw-r--r--arch/arm/mach-omap2/powerdomain.c25
-rw-r--r--arch/arm/mach-omap2/smartreflex.c2
-rw-r--r--arch/arm/mach-omap2/usb-musb.c3
-rw-r--r--arch/arm/mach-orion5x/Makefile.boot2
-rw-r--r--arch/arm/mach-orion5x/common.c4
-rw-r--r--arch/arm/mach-orion5x/common.h4
-rw-r--r--arch/arm/mach-orion5x/dns323-setup.c2
-rw-r--r--arch/arm/mach-orion5x/pci.c1
-rw-r--r--arch/arm/mach-pnx4008/Makefile.boot2
-rw-r--r--arch/arm/mach-prima2/Makefile.boot2
-rw-r--r--arch/arm/mach-prima2/clock.c1
-rw-r--r--arch/arm/mach-prima2/irq.c1
-rw-r--r--arch/arm/mach-prima2/rstc.c1
-rw-r--r--arch/arm/mach-prima2/timer.c1
-rw-r--r--arch/arm/mach-pxa/Makefile.boot2
-rw-r--r--arch/arm/mach-pxa/cm-x300.c4
-rw-r--r--arch/arm/mach-pxa/corgi.c4
-rw-r--r--arch/arm/mach-pxa/eseries.c3
-rw-r--r--arch/arm/mach-pxa/eseries.h3
-rw-r--r--arch/arm/mach-pxa/irq.c2
-rw-r--r--arch/arm/mach-pxa/poodle.c4
-rw-r--r--arch/arm/mach-pxa/saar.c2
-rw-r--r--arch/arm/mach-pxa/spitz.c4
-rw-r--r--arch/arm/mach-pxa/tosa.c4
-rw-r--r--arch/arm/mach-pxa/xcep.c3
-rw-r--r--arch/arm/mach-realview/Makefile.boot4
-rw-r--r--arch/arm/mach-realview/core.c3
-rw-r--r--arch/arm/mach-realview/core.h4
-rw-r--r--arch/arm/mach-realview/include/mach/board-pb1176.h1
-rw-r--r--arch/arm/mach-realview/include/mach/system.h1
-rw-r--r--arch/arm/mach-realview/platsmp.c10
-rw-r--r--arch/arm/mach-realview/realview_pb1176.c48
-rw-r--r--arch/arm/mach-realview/realview_pbx.c6
-rw-r--r--arch/arm/mach-rpc/Makefile.boot2
-rw-r--r--arch/arm/mach-rpc/include/mach/hardware.h25
-rw-r--r--arch/arm/mach-rpc/include/mach/io.h193
-rw-r--r--arch/arm/mach-rpc/riscpc.c2
-rw-r--r--arch/arm/mach-s3c2410/Makefile.boot4
-rw-r--r--arch/arm/mach-s3c2410/include/mach/io.h2
-rw-r--r--arch/arm/mach-s3c2410/s3c2410.c2
-rw-r--r--arch/arm/mach-s3c2412/mach-smdk2413.c3
-rw-r--r--arch/arm/mach-s3c2412/mach-vstms.c5
-rw-r--r--arch/arm/mach-s3c2412/s3c2412.c2
-rw-r--r--arch/arm/mach-s3c2416/s3c2416.c2
-rw-r--r--arch/arm/mach-s3c2440/s3c2440.c2
-rw-r--r--arch/arm/mach-s3c2440/s3c2442.c2
-rw-r--r--arch/arm/mach-s3c2443/clock.c2
-rw-r--r--arch/arm/mach-s3c64xx/Makefile.boot2
-rw-r--r--arch/arm/mach-s3c64xx/mach-smdk6410.c39
-rw-r--r--arch/arm/mach-s3c64xx/pm.c1
-rw-r--r--arch/arm/mach-s5p64x0/Makefile.boot2
-rw-r--r--arch/arm/mach-s5p64x0/irq-eint.c2
-rw-r--r--arch/arm/mach-s5pc100/Makefile.boot2
-rw-r--r--arch/arm/mach-s5pv210/Makefile.boot2
-rw-r--r--arch/arm/mach-s5pv210/clock.c6
-rw-r--r--arch/arm/mach-s5pv210/pm.c2
-rw-r--r--arch/arm/mach-sa1100/Makefile1
-rw-r--r--arch/arm/mach-sa1100/Makefile.boot5
-rw-r--r--arch/arm/mach-sa1100/assabet.c3
-rw-r--r--arch/arm/mach-sa1100/include/mach/io.h6
-rw-r--r--arch/arm/mach-sa1100/include/mach/simpad.h94
-rw-r--r--arch/arm/mach-sa1100/leds-simpad.c100
-rw-r--r--arch/arm/mach-sa1100/leds.c2
-rw-r--r--arch/arm/mach-sa1100/leds.h1
-rw-r--r--arch/arm/mach-sa1100/simpad.c213
-rw-r--r--arch/arm/mach-shark/Makefile.boot2
-rw-r--r--arch/arm/mach-shmobile/Makefile.boot2
-rw-r--r--arch/arm/mach-shmobile/board-ag5evm.c3
-rw-r--r--arch/arm/mach-shmobile/board-ap4evb.c7
-rw-r--r--arch/arm/mach-shmobile/board-mackerel.c17
-rw-r--r--arch/arm/mach-shmobile/clock-sh7372.c31
-rw-r--r--arch/arm/mach-shmobile/clock-sh73a0.c2
-rw-r--r--arch/arm/mach-shmobile/include/mach/common.h4
-rw-r--r--arch/arm/mach-shmobile/include/mach/sh7372.h17
-rw-r--r--arch/arm/mach-shmobile/intc-sh7372.c59
-rw-r--r--arch/arm/mach-shmobile/platsmp.c6
-rw-r--r--arch/arm/mach-shmobile/pm-sh7372.c342
-rw-r--r--arch/arm/mach-shmobile/pm_runtime.c1
-rw-r--r--arch/arm/mach-shmobile/setup-sh7372.c201
-rw-r--r--arch/arm/mach-shmobile/sleep-sh7372.S221
-rw-r--r--arch/arm/mach-spear3xx/Makefile.boot2
-rw-r--r--arch/arm/mach-spear6xx/Makefile.boot2
-rw-r--r--arch/arm/mach-tcc8k/Makefile.boot2
-rw-r--r--arch/arm/mach-tegra/Makefile.boot2
-rw-r--r--arch/arm/mach-tegra/board-harmony.c4
-rw-r--r--arch/arm/mach-tegra/board-paz00.c4
-rw-r--r--arch/arm/mach-tegra/board-trimslice.c4
-rw-r--r--arch/arm/mach-tegra/cpu-tegra.c1
-rw-r--r--arch/arm/mach-tegra/platsmp.c8
-rw-r--r--arch/arm/mach-u300/Kconfig2
-rw-r--r--arch/arm/mach-u300/Makefile2
-rw-r--r--arch/arm/mach-u300/Makefile.boot4
-rw-r--r--arch/arm/mach-u300/core.c84
-rw-r--r--arch/arm/mach-u300/include/mach/syscon.h136
-rw-r--r--arch/arm/mach-u300/mmc.c16
-rw-r--r--arch/arm/mach-u300/padmux.c367
-rw-r--r--arch/arm/mach-u300/padmux.h39
-rw-r--r--arch/arm/mach-u300/spi.c20
-rw-r--r--arch/arm/mach-ux500/Kconfig1
-rw-r--r--arch/arm/mach-ux500/Makefile.boot2
-rw-r--r--arch/arm/mach-ux500/platsmp.c10
-rw-r--r--arch/arm/mach-versatile/Makefile.boot2
-rw-r--r--arch/arm/mach-vexpress/Makefile.boot2
-rw-r--r--arch/arm/mach-vexpress/ct-ca9x4.c6
-rw-r--r--arch/arm/mach-vexpress/hotplug.c9
-rw-r--r--arch/arm/mach-vexpress/include/mach/io.h2
-rw-r--r--arch/arm/mach-vexpress/v2m.c7
-rw-r--r--arch/arm/mach-vt8500/Makefile.boot2
-rw-r--r--arch/arm/mach-vt8500/include/mach/io.h2
-rw-r--r--arch/arm/mach-w90x900/Makefile.boot2
-rw-r--r--arch/arm/mach-w90x900/cpu.c2
-rw-r--r--arch/arm/mach-zynq/Makefile.boot2
-rw-r--r--arch/arm/mm/abort-macro.S2
-rw-r--r--arch/arm/mm/alignment.c20
-rw-r--r--arch/arm/mm/cache-l2x0.c235
-rw-r--r--arch/arm/mm/cache-v7.S20
-rw-r--r--arch/arm/mm/dma-mapping.c8
-rw-r--r--arch/arm/mm/fault.c1
-rw-r--r--arch/arm/mm/init.c9
-rw-r--r--arch/arm/mm/ioremap.c21
-rw-r--r--arch/arm/mm/mm.h4
-rw-r--r--arch/arm/mm/mmu.c18
-rw-r--r--arch/arm/mm/proc-arm920.S2
-rw-r--r--arch/arm/mm/proc-arm926.S2
-rw-r--r--arch/arm/mm/proc-sa1100.S10
-rw-r--r--arch/arm/mm/proc-v6.S16
-rw-r--r--arch/arm/mm/proc-v7.S8
-rw-r--r--arch/arm/mm/proc-xsc3.S6
-rw-r--r--arch/arm/plat-mxc/Kconfig2
-rw-r--r--arch/arm/plat-mxc/devices.c53
-rw-r--r--arch/arm/plat-mxc/include/mach/devices-common.h16
-rw-r--r--arch/arm/plat-omap/Kconfig1
-rw-r--r--arch/arm/plat-omap/omap_device.c6
-rw-r--r--arch/arm/plat-s5p/clock.c2
-rw-r--r--arch/arm/plat-s5p/irq-gpioint.c21
-rw-r--r--arch/arm/plat-samsung/clock.c11
-rw-r--r--arch/arm/plat-samsung/include/plat/backlight.h2
-rw-r--r--arch/arm/plat-samsung/include/plat/clock.h8
-rw-r--r--arch/arm/plat-samsung/include/plat/watchdog-reset.h10
-rw-r--r--arch/arm/plat-samsung/irq-vic-timer.c5
-rw-r--r--arch/arm/tools/mach-types26
-rw-r--r--arch/arm/vfp/Makefile2
-rw-r--r--arch/avr32/kernel/syscall_table.S2
-rw-r--r--arch/blackfin/mach-common/entry.S2
-rw-r--r--arch/cris/Kconfig4
-rw-r--r--arch/cris/arch-v10/Kconfig12
-rw-r--r--arch/cris/arch-v10/drivers/Kconfig1
-rw-r--r--arch/cris/arch-v10/kernel/entry.S2
-rw-r--r--arch/cris/arch-v32/drivers/Kconfig1
-rw-r--r--arch/cris/arch-v32/kernel/entry.S2
-rw-r--r--arch/cris/arch-v32/lib/nand_init.S178
-rw-r--r--arch/cris/include/asm/serial.h9
-rw-r--r--arch/frv/kernel/entry.S2
-rw-r--r--arch/h8300/Kconfig2
-rw-r--r--arch/h8300/kernel/syscalls.S2
-rw-r--r--arch/ia64/hp/common/sba_iommu.c12
-rw-r--r--arch/ia64/hp/sim/simeth.c2
-rw-r--r--arch/ia64/kernel/entry.S2
-rw-r--r--arch/m32r/kernel/syscall_table.S2
-rw-r--r--arch/m68k/Kconfig195
-rw-r--r--arch/m68k/Kconfig.bus55
-rw-r--r--arch/m68k/Kconfig.cpu429
-rw-r--r--arch/m68k/Kconfig.devices123
-rw-r--r--arch/m68k/Kconfig.machine (renamed from arch/m68k/Kconfig.nommu)562
-rw-r--r--arch/m68k/Kconfig.mmu411
-rw-r--r--arch/m68k/Makefile168
-rw-r--r--arch/m68k/Makefile_mm121
-rw-r--r--arch/m68k/Makefile_no124
-rw-r--r--arch/m68k/include/asm/entry.h255
-rw-r--r--arch/m68k/include/asm/entry_mm.h128
-rw-r--r--arch/m68k/include/asm/entry_no.h181
-rw-r--r--arch/m68k/include/asm/m520xsim.h26
-rw-r--r--arch/m68k/include/asm/mcfqspi.h8
-rw-r--r--arch/m68k/include/asm/page_mm.h2
-rw-r--r--arch/m68k/include/asm/page_no.h3
-rw-r--r--arch/m68k/include/asm/processor.h6
-rw-r--r--arch/m68k/include/asm/sections.h2
-rw-r--r--arch/m68k/kernel/Makefile24
-rw-r--r--arch/m68k/kernel/Makefile_mm17
-rw-r--r--arch/m68k/kernel/Makefile_no10
-rw-r--r--arch/m68k/kernel/entry_no.S6
-rw-r--r--arch/m68k/kernel/setup_no.c4
-rw-r--r--arch/m68k/kernel/syscalltable.S2
-rw-r--r--arch/m68k/kernel/traps.c1108
-rw-r--r--arch/m68k/kernel/traps_mm.c1207
-rw-r--r--arch/m68k/kernel/traps_no.c361
-rw-r--r--arch/m68k/kernel/vectors.c145
-rw-r--r--arch/m68k/kernel/vmlinux.lds_no.S1
-rw-r--r--arch/m68k/lib/memcpy.c9
-rw-r--r--arch/m68k/mac/macints.c2
-rw-r--r--arch/m68k/mac/misc.c40
-rw-r--r--arch/m68k/mm/init_no.c21
-rw-r--r--arch/m68k/platform/520x/config.c6
-rw-r--r--arch/m68k/platform/520x/gpio.c50
-rw-r--r--arch/m68k/platform/68328/Makefile5
-rw-r--r--arch/m68k/platform/68328/entry.S18
-rw-r--r--arch/m68k/platform/68360/Makefile6
-rw-r--r--arch/m68k/platform/68360/entry.S4
-rw-r--r--arch/m68k/platform/coldfire/entry.S6
-rw-r--r--arch/m68k/q40/README2
-rw-r--r--arch/microblaze/include/asm/dma-mapping.h2
-rw-r--r--arch/microblaze/kernel/syscall_table.S2
-rw-r--r--arch/microblaze/mm/init.c6
-rw-r--r--arch/mips/Kconfig14
-rw-r--r--arch/mips/alchemy/common/platform.c2
-rw-r--r--arch/mips/alchemy/common/power.c22
-rw-r--r--arch/mips/alchemy/devboards/bcsr.c4
-rw-r--r--arch/mips/alchemy/devboards/db1200/setup.c7
-rw-r--r--arch/mips/ar7/irq.c3
-rw-r--r--arch/mips/bcm47xx/Kconfig31
-rw-r--r--arch/mips/bcm47xx/Makefile3
-rw-r--r--arch/mips/bcm47xx/gpio.c82
-rw-r--r--arch/mips/bcm47xx/irq.c12
-rw-r--r--arch/mips/bcm47xx/nvram.c29
-rw-r--r--arch/mips/bcm47xx/serial.c46
-rw-r--r--arch/mips/bcm47xx/setup.c90
-rw-r--r--arch/mips/bcm47xx/time.c16
-rw-r--r--arch/mips/bcm47xx/wgt634u.c14
-rw-r--r--arch/mips/bcm63xx/irq.c1
-rw-r--r--arch/mips/cobalt/irq.c1
-rw-r--r--arch/mips/dec/setup.c4
-rw-r--r--arch/mips/emma/markeins/irq.c2
-rw-r--r--arch/mips/include/asm/lasat/lasat.h6
-rw-r--r--arch/mips/include/asm/mach-bcm47xx/bcm47xx.h26
-rw-r--r--arch/mips/include/asm/mach-bcm47xx/gpio.h108
-rw-r--r--arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h1
-rw-r--r--arch/mips/include/asm/mach-powertv/dma-coherence.h1
-rw-r--r--arch/mips/include/asm/stackframe.h4
-rw-r--r--arch/mips/jz4740/gpio.c52
-rw-r--r--arch/mips/kernel/ftrace.c39
-rw-r--r--arch/mips/kernel/i8259.c3
-rw-r--r--arch/mips/kernel/linux32.c7
-rw-r--r--arch/mips/kernel/scall32-o32.S2
-rw-r--r--arch/mips/kernel/scall64-64.S2
-rw-r--r--arch/mips/kernel/scall64-n32.S4
-rw-r--r--arch/mips/kernel/scall64-o32.S4
-rw-r--r--arch/mips/kernel/signal.c3
-rw-r--r--arch/mips/kernel/traps.c16
-rw-r--r--arch/mips/kernel/vpe.c2
-rw-r--r--arch/mips/lantiq/irq.c6
-rw-r--r--arch/mips/lantiq/xway/ebu.c1
-rw-r--r--arch/mips/lantiq/xway/pmu.c1
-rw-r--r--arch/mips/lasat/interrupt.c1
-rw-r--r--arch/mips/loongson/fuloong-2e/irq.c1
-rw-r--r--arch/mips/loongson/lemote-2f/irq.c3
-rw-r--r--arch/mips/mm/mmap.c48
-rw-r--r--arch/mips/mm/tlbex.c6
-rw-r--r--arch/mips/mti-malta/malta-int.c6
-rw-r--r--arch/mips/netlogic/xlr/Makefile2
-rw-r--r--arch/mips/pci/pci-bcm47xx.c6
-rw-r--r--arch/mips/pci/pci-lantiq.c9
-rw-r--r--arch/mips/pci/pci-rc32434.c2
-rw-r--r--arch/mips/pmc-sierra/msp71xx/msp_irq.c6
-rw-r--r--arch/mips/pnx8550/common/int.c2
-rw-r--r--arch/mips/sgi-ip22/ip22-int.c10
-rw-r--r--arch/mips/sni/rm200.c1
-rw-r--r--arch/mips/txx9/generic/setup_tx4939.c2
-rw-r--r--arch/mips/vr41xx/common/irq.c1
-rw-r--r--arch/mn10300/Kconfig2
-rw-r--r--arch/mn10300/kernel/entry.S2
-rw-r--r--arch/mn10300/kernel/irq.c1
-rw-r--r--arch/openrisc/Kconfig2
-rw-r--r--arch/openrisc/include/asm/dma-mapping.h61
-rw-r--r--arch/openrisc/include/asm/sigcontext.h7
-rw-r--r--arch/openrisc/kernel/dma.c28
-rw-r--r--arch/openrisc/kernel/signal.c29
-rw-r--r--arch/parisc/Kconfig4
-rw-r--r--arch/parisc/include/asm/dma-mapping.h2
-rw-r--r--arch/parisc/kernel/pci-dma.c2
-rw-r--r--arch/parisc/kernel/syscall_table.S2
-rw-r--r--arch/powerpc/Kconfig2
-rw-r--r--arch/powerpc/boot/dts/p1010rdb.dts10
-rw-r--r--arch/powerpc/boot/dts/p1010si.dtsi10
-rw-r--r--arch/powerpc/boot/dts/p1023rds.dts2
-rw-r--r--arch/powerpc/configs/40x/acadia_defconfig11
-rw-r--r--arch/powerpc/configs/40x/ep405_defconfig5
-rw-r--r--arch/powerpc/configs/40x/hcu4_defconfig5
-rw-r--r--arch/powerpc/configs/40x/kilauea_defconfig9
-rw-r--r--arch/powerpc/configs/40x/makalu_defconfig9
-rw-r--r--arch/powerpc/configs/40x/walnut_defconfig5
-rw-r--r--arch/powerpc/configs/44x/arches_defconfig9
-rw-r--r--arch/powerpc/configs/44x/bamboo_defconfig5
-rw-r--r--arch/powerpc/configs/44x/bluestone_defconfig9
-rw-r--r--arch/powerpc/configs/44x/canyonlands_defconfig9
-rw-r--r--arch/powerpc/configs/44x/ebony_defconfig5
-rw-r--r--arch/powerpc/configs/44x/eiger_defconfig9
-rw-r--r--arch/powerpc/configs/44x/icon_defconfig5
-rw-r--r--arch/powerpc/configs/44x/katmai_defconfig5
-rw-r--r--arch/powerpc/configs/44x/redwood_defconfig11
-rw-r--r--arch/powerpc/configs/44x/sam440ep_defconfig5
-rw-r--r--arch/powerpc/configs/44x/sequoia_defconfig5
-rw-r--r--arch/powerpc/configs/44x/taishan_defconfig5
-rw-r--r--arch/powerpc/configs/44x/warp_defconfig5
-rw-r--r--arch/powerpc/configs/85xx/p1023rds_defconfig1
-rw-r--r--arch/powerpc/configs/corenet32_smp_defconfig1
-rw-r--r--arch/powerpc/configs/corenet64_smp_defconfig5
-rw-r--r--arch/powerpc/configs/mpc85xx_defconfig1
-rw-r--r--arch/powerpc/configs/mpc85xx_smp_defconfig1
-rw-r--r--arch/powerpc/configs/ppc40x_defconfig5
-rw-r--r--arch/powerpc/configs/ppc44x_defconfig5
-rw-r--r--arch/powerpc/include/asm/qe.h2
-rw-r--r--arch/powerpc/include/asm/systbl.h2
-rw-r--r--arch/powerpc/platforms/40x/Kconfig12
-rw-r--r--arch/powerpc/platforms/44x/Kconfig54
-rw-r--r--arch/powerpc/platforms/85xx/Kconfig2
-rw-r--r--arch/powerpc/platforms/cell/Kconfig8
-rw-r--r--arch/powerpc/platforms/embedded6xx/storcenter.c2
-rw-r--r--arch/powerpc/platforms/powermac/pci.c14
-rw-r--r--arch/powerpc/sysdev/fsl_rio.c5
-rw-r--r--arch/powerpc/sysdev/qe_lib/qe.c2
-rw-r--r--arch/s390/Kconfig1
-rw-r--r--arch/s390/hypfs/hypfs_diag.c3
-rw-r--r--arch/s390/include/asm/elf.h3
-rw-r--r--arch/s390/include/asm/pgtable.h2
-rw-r--r--arch/s390/include/asm/qdio.h78
-rw-r--r--arch/s390/kernel/asm-offsets.c3
-rw-r--r--arch/s390/kernel/compat_wrapper.S6
-rw-r--r--arch/s390/kernel/early.c14
-rw-r--r--arch/s390/kernel/entry64.S6
-rw-r--r--arch/s390/kernel/ipl.c7
-rw-r--r--arch/s390/kernel/suspend.c118
-rw-r--r--arch/s390/kernel/swsusp_asm64.S3
-rw-r--r--arch/s390/kernel/syscalls.S2
-rw-r--r--arch/s390/kvm/kvm-s390.c5
-rw-r--r--arch/s390/mm/pgtable.c17
-rw-r--r--arch/sh/include/asm/ptrace.h2
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7757.c1
-rw-r--r--arch/sh/kernel/idle.c2
-rw-r--r--arch/sh/kernel/syscalls_32.S2
-rw-r--r--arch/sh/kernel/syscalls_64.S2
-rw-r--r--arch/sh/kernel/traps_32.c37
-rw-r--r--arch/sparc/include/asm/pgtsrmmu.h2
-rw-r--r--arch/sparc/include/asm/sigcontext.h14
-rw-r--r--arch/sparc/include/asm/spitfire.h2
-rw-r--r--arch/sparc/include/asm/xor_64.h4
-rw-r--r--arch/sparc/kernel/Makefile1
-rw-r--r--arch/sparc/kernel/cpu.c12
-rw-r--r--arch/sparc/kernel/cpumap.c2
-rw-r--r--arch/sparc/kernel/head_64.S25
-rw-r--r--arch/sparc/kernel/irq.h2
-rw-r--r--arch/sparc/kernel/pci.c3
-rw-r--r--arch/sparc/kernel/process_32.c3
-rw-r--r--arch/sparc/kernel/process_64.c3
-rw-r--r--arch/sparc/kernel/setup_32.c2
-rw-r--r--arch/sparc/kernel/setup_64.c28
-rw-r--r--arch/sparc/kernel/signal32.c205
-rw-r--r--arch/sparc/kernel/signal_32.c204
-rw-r--r--arch/sparc/kernel/signal_64.c140
-rw-r--r--arch/sparc/kernel/sigutil.h9
-rw-r--r--arch/sparc/kernel/sigutil_32.c120
-rw-r--r--arch/sparc/kernel/sigutil_64.c93
-rw-r--r--arch/sparc/kernel/sys32.S1
-rw-r--r--arch/sparc/kernel/systbls_32.S2
-rw-r--r--arch/sparc/kernel/systbls_64.S4
-rw-r--r--arch/sparc/mm/init_64.c5
-rw-r--r--arch/sparc/mm/leon_mm.c2
-rw-r--r--arch/tile/kernel/intvec_32.S2
-rw-r--r--arch/tile/lib/atomic_asm_32.S2
-rw-r--r--arch/um/Kconfig.x864
-rw-r--r--arch/um/Makefile2
-rw-r--r--arch/um/drivers/line.c61
-rw-r--r--arch/um/drivers/net_kern.c2
-rw-r--r--arch/um/drivers/xterm.c1
-rw-r--r--arch/um/include/asm/ptrace-generic.h4
-rw-r--r--arch/um/include/shared/line.h1
-rw-r--r--arch/um/include/shared/registers.h2
-rw-r--r--arch/um/kernel/process.c2
-rw-r--r--arch/um/kernel/ptrace.c28
-rw-r--r--arch/um/os-Linux/registers.c9
-rw-r--r--arch/um/os-Linux/skas/mem.c2
-rw-r--r--arch/um/os-Linux/skas/process.c19
-rw-r--r--arch/um/sys-i386/asm/ptrace.h5
-rw-r--r--arch/um/sys-i386/ptrace.c28
-rw-r--r--arch/um/sys-i386/shared/sysdep/ptrace.h1
-rw-r--r--arch/um/sys-x86_64/ptrace.c12
-rw-r--r--arch/um/sys-x86_64/shared/sysdep/ptrace.h1
-rw-r--r--arch/unicore32/include/asm/io.h2
-rw-r--r--arch/x86/Kconfig2
-rw-r--r--arch/x86/Kconfig.debug2
-rw-r--r--arch/x86/boot/header.S2
-rw-r--r--arch/x86/ia32/ia32entry.S2
-rw-r--r--arch/x86/include/asm/alternative-asm.h1
-rw-r--r--arch/x86/include/asm/alternative.h4
-rw-r--r--arch/x86/include/asm/cpufeature.h2
-rw-r--r--arch/x86/include/asm/dma-mapping.h2
-rw-r--r--arch/x86/include/asm/pvclock.h2
-rw-r--r--arch/x86/include/asm/unistd_64.h2
-rw-r--r--arch/x86/include/asm/xen/page.h6
-rw-r--r--arch/x86/kernel/amd_gart_64.c2
-rw-r--r--arch/x86/kernel/apic/x2apic_uv_x.c1
-rw-r--r--arch/x86/kernel/apm_32.c2
-rw-r--r--arch/x86/kernel/cpu/mtrr/main.c2
-rw-r--r--arch/x86/kernel/cpu/perf_event.c3
-rw-r--r--arch/x86/kernel/entry_32.S8
-rw-r--r--arch/x86/kernel/kprobes.c4
-rw-r--r--arch/x86/kernel/pci-dma.c4
-rw-r--r--arch/x86/kernel/process_32.c2
-rw-r--r--arch/x86/kernel/rtc.c23
-rw-r--r--arch/x86/kernel/syscall_table_32.S2
-rw-r--r--arch/x86/kernel/vsyscall_64.c2
-rw-r--r--arch/x86/kvm/emulate.c2
-rw-r--r--arch/x86/kvm/mmu.c3
-rw-r--r--arch/x86/mm/init.c3
-rw-r--r--arch/x86/mm/mmio-mod.c1
-rw-r--r--arch/x86/pci/acpi.c20
-rw-r--r--arch/x86/pci/xen.c32
-rw-r--r--arch/x86/platform/mrst/mrst.c24
-rw-r--r--arch/x86/platform/mrst/vrtc.c9
-rw-r--r--arch/x86/platform/olpc/olpc.c4
-rw-r--r--arch/x86/vdso/vdso32/sysenter.S2
-rw-r--r--arch/x86/xen/Kconfig11
-rw-r--r--arch/x86/xen/enlighten.c1
-rw-r--r--arch/x86/xen/mmu.c58
-rw-r--r--arch/x86/xen/p2m.c128
-rw-r--r--arch/x86/xen/setup.c283
-rw-r--r--arch/x86/xen/smp.c11
-rw-r--r--arch/x86/xen/time.c5
-rw-r--r--arch/x86/xen/xen-asm_32.S8
-rw-r--r--arch/xtensa/include/asm/unistd.h2
-rw-r--r--arch/xtensa/platforms/iss/network.c2
-rw-r--r--block/blk-cgroup.c37
-rw-r--r--block/blk-core.c28
-rw-r--r--block/blk-softirq.c2
-rw-r--r--block/blk-sysfs.c15
-rw-r--r--block/cfq-iosched.c20
-rw-r--r--crypto/ghash-generic.c6
-rw-r--r--drivers/Kconfig4
-rw-r--r--drivers/Makefile4
-rw-r--r--drivers/acpi/acpica/acconfig.h2
-rw-r--r--drivers/acpi/apei/Kconfig1
-rw-r--r--drivers/acpi/apei/apei-base.c2
-rw-r--r--drivers/acpi/processor_idle.c2
-rw-r--r--drivers/acpi/sleep.c24
-rw-r--r--drivers/atm/eni.c5
-rw-r--r--drivers/atm/idt77252.c11
-rw-r--r--drivers/atm/iphase.c265
-rw-r--r--drivers/atm/iphase.h395
-rw-r--r--drivers/atm/lanai.c3
-rw-r--r--drivers/base/class.c17
-rw-r--r--drivers/base/core.c5
-rw-r--r--drivers/base/dd.c3
-rw-r--r--drivers/base/devres.c1
-rw-r--r--drivers/base/devtmpfs.c2
-rw-r--r--drivers/base/firmware_class.c11
-rw-r--r--drivers/base/memory.c62
-rw-r--r--drivers/base/platform.c56
-rw-r--r--drivers/base/power/Makefile4
-rw-r--r--drivers/base/power/clock_ops.c198
-rw-r--r--drivers/base/power/common.c86
-rw-r--r--drivers/base/power/domain.c352
-rw-r--r--drivers/base/power/main.c42
-rw-r--r--drivers/base/power/opp.c30
-rw-r--r--drivers/base/power/power.h10
-rw-r--r--drivers/base/power/qos.c419
-rw-r--r--drivers/base/power/runtime.c127
-rw-r--r--drivers/base/power/wakeup.c4
-rw-r--r--drivers/base/regmap/Kconfig2
-rw-r--r--drivers/base/regmap/Makefile3
-rw-r--r--drivers/base/regmap/internal.h128
-rw-r--r--drivers/base/regmap/regcache-indexed.c64
-rw-r--r--drivers/base/regmap/regcache-lzo.c361
-rw-r--r--drivers/base/regmap/regcache-rbtree.c345
-rw-r--r--drivers/base/regmap/regcache.c401
-rw-r--r--drivers/base/regmap/regmap-debugfs.c209
-rw-r--r--drivers/base/regmap/regmap-i2c.c2
-rw-r--r--drivers/base/regmap/regmap-spi.c2
-rw-r--r--drivers/base/regmap/regmap.c226
-rw-r--r--drivers/bcma/Kconfig13
-rw-r--r--drivers/bcma/Makefile2
-rw-r--r--drivers/bcma/bcma_private.h16
-rw-r--r--drivers/bcma/core.c2
-rw-r--r--drivers/bcma/driver_chipcommon.c53
-rw-r--r--drivers/bcma/driver_chipcommon_pmu.c191
-rw-r--r--drivers/bcma/driver_mips.c256
-rw-r--r--drivers/bcma/driver_pci.c16
-rw-r--r--drivers/bcma/host_soc.c183
-rw-r--r--drivers/bcma/main.c82
-rw-r--r--drivers/bcma/scan.c348
-rw-r--r--drivers/bcma/sprom.c15
-rw-r--r--drivers/block/drbd/drbd_bitmap.c5
-rw-r--r--drivers/block/drbd/drbd_int.h3
-rw-r--r--drivers/block/drbd/drbd_nl.c4
-rw-r--r--drivers/block/floppy.c8
-rw-r--r--drivers/block/rbd.c2
-rw-r--r--drivers/block/xen-blkback/blkback.c2
-rw-r--r--drivers/block/xen-blkback/common.h3
-rw-r--r--drivers/block/xen-blkback/xenbus.c6
-rw-r--r--drivers/bluetooth/ath3k.c1
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c4
-rw-r--r--drivers/bluetooth/btusb.c27
-rw-r--r--drivers/bluetooth/btwilink.c16
-rw-r--r--drivers/char/agp/backend.c3
-rw-r--r--drivers/char/apm-emulation.c21
-rw-r--r--drivers/char/msm_smd_pkt.c5
-rw-r--r--drivers/char/raw.c3
-rw-r--r--drivers/char/rtc.c7
-rw-r--r--drivers/char/tpm/Kconfig1
-rw-r--r--drivers/char/tpm/tpm.c12
-rw-r--r--drivers/char/tpm/tpm_nsc.c2
-rw-r--r--drivers/clocksource/sh_cmt.c34
-rw-r--r--drivers/connector/cn_proc.c26
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c2
-rw-r--r--drivers/cpufreq/pcc-cpufreq.c3
-rw-r--r--drivers/cpuidle/cpuidle.c2
-rw-r--r--drivers/cpuidle/governors/ladder.c2
-rw-r--r--drivers/cpuidle/governors/menu.c2
-rw-r--r--drivers/devfreq/Kconfig75
-rw-r--r--drivers/devfreq/Makefile5
-rw-r--r--drivers/devfreq/devfreq.c601
-rw-r--r--drivers/devfreq/governor.h24
-rw-r--r--drivers/devfreq/governor_performance.c29
-rw-r--r--drivers/devfreq/governor_powersave.c29
-rw-r--r--drivers/devfreq/governor_simpleondemand.c88
-rw-r--r--drivers/devfreq/governor_userspace.c116
-rw-r--r--drivers/dma/ste_dma40.c42
-rw-r--r--drivers/firewire/ohci.c3
-rw-r--r--drivers/firewire/sbp2.c4
-rw-r--r--drivers/firmware/google/gsmi.c2
-rw-r--r--drivers/gpio/gpio-generic.c15
-rw-r--r--drivers/gpio/gpio-omap.c2
-rw-r--r--drivers/gpio/gpio-pca953x.c1
-rw-r--r--drivers/gpu/drm/drm_crtc.c2
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c1
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c4
-rw-r--r--drivers/gpu/drm/i915/intel_display.c26
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h3
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c88
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_sgdma.c7
-rw-r--r--drivers/gpu/drm/nouveau/nv04_crtc.c15
-rw-r--r--drivers/gpu/drm/nouveau/nv50_crtc.c12
-rw-r--r--drivers/gpu/drm/radeon/atom.c15
-rw-r--r--drivers/gpu/drm/radeon/atom.h1
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c2
-rw-r--r--drivers/gpu/drm/radeon/atombios_dp.c28
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c86
-rw-r--r--drivers/gpu/drm/radeon/ni.c48
-rw-r--r--drivers/gpu/drm/radeon/r100.c22
-rw-r--r--drivers/gpu/drm/radeon/r200.c4
-rw-r--r--drivers/gpu/drm/radeon/r600.c14
-rw-r--r--drivers/gpu/drm/radeon/radeon.h7
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.h8
-rw-r--r--drivers/gpu/drm/radeon/radeon_clocks.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_combios.c8
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c50
-rw-r--r--drivers/gpu/drm/radeon/radeon_cursor.c40
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c21
-rw-r--r--drivers/gpu/drm/radeon/radeon_encoders.c35
-rw-r--r--drivers/gpu/drm/radeon/radeon_fence.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_test.c34
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c30
-rw-r--r--drivers/gpu/drm/radeon/rv770.c51
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c15
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_util.c4
-rw-r--r--drivers/hid/Kconfig43
-rw-r--r--drivers/hid/Makefile4
-rw-r--r--drivers/hid/hid-apple.c21
-rw-r--r--drivers/hid/hid-axff.c36
-rw-r--r--drivers/hid/hid-core.c82
-rw-r--r--drivers/hid/hid-debug.c5
-rw-r--r--drivers/hid/hid-ids.h28
-rw-r--r--drivers/hid/hid-input.c11
-rw-r--r--drivers/hid/hid-lg.c29
-rw-r--r--drivers/hid/hid-lg.h4
-rw-r--r--drivers/hid/hid-lg4ff.c403
-rw-r--r--drivers/hid/hid-lgff.c13
-rw-r--r--drivers/hid/hid-logitech-dj.c922
-rw-r--r--drivers/hid/hid-logitech-dj.h123
-rw-r--r--drivers/hid/hid-magicmouse.c73
-rw-r--r--drivers/hid/hid-multitouch.c93
-rw-r--r--drivers/hid/hid-picolcd.c2
-rw-r--r--drivers/hid/hid-primax.c117
-rw-r--r--drivers/hid/hid-prodikeys.c8
-rw-r--r--drivers/hid/hid-roccat-kone.c63
-rw-r--r--drivers/hid/hid-roccat-kovaplus.c17
-rw-r--r--drivers/hid/hid-roccat-pyra.c23
-rw-r--r--drivers/hid/hid-sjoy.c75
-rw-r--r--drivers/hid/hid-wacom.c101
-rw-r--r--drivers/hid/hid-wiimote.c1071
-rw-r--r--drivers/hid/hid-zydacron.c4
-rw-r--r--drivers/hid/hidraw.c11
-rw-r--r--drivers/hid/usbhid/hid-core.c9
-rw-r--r--drivers/hid/usbhid/hid-quirks.c4
-rw-r--r--drivers/hid/usbhid/hiddev.c2
-rw-r--r--drivers/hwmon/Kconfig21
-rw-r--r--drivers/hwmon/Makefile2
-rw-r--r--drivers/hwmon/ad7314.c186
-rw-r--r--drivers/hwmon/coretemp.c216
-rw-r--r--drivers/hwmon/ds620.c2
-rw-r--r--drivers/hwmon/exynos4_tmu.c524
-rw-r--r--drivers/hwmon/f71882fg.c231
-rw-r--r--drivers/hwmon/i5k_amb.c42
-rw-r--r--drivers/hwmon/lm75.c39
-rw-r--r--drivers/hwmon/max16065.c2
-rw-r--r--drivers/hwmon/ntc_thermistor.c3
-rw-r--r--drivers/hwmon/pmbus/Kconfig28
-rw-r--r--drivers/hwmon/pmbus/Makefile2
-rw-r--r--drivers/hwmon/pmbus/adm1275.c159
-rw-r--r--drivers/hwmon/pmbus/lm25066.c17
-rw-r--r--drivers/hwmon/pmbus/ltc2978.c408
-rw-r--r--drivers/hwmon/pmbus/max16064.c3
-rw-r--r--drivers/hwmon/pmbus/max34440.c13
-rw-r--r--drivers/hwmon/pmbus/max8688.c9
-rw-r--r--drivers/hwmon/pmbus/pmbus.c10
-rw-r--r--drivers/hwmon/pmbus/pmbus.h23
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c94
-rw-r--r--drivers/hwmon/pmbus/ucd9000.c19
-rw-r--r--drivers/hwmon/pmbus/ucd9200.c11
-rw-r--r--drivers/hwmon/pmbus/zl6100.c256
-rw-r--r--drivers/hwmon/w83627ehf.c252
-rw-r--r--drivers/hwmon/w83791d.c4
-rw-r--r--drivers/i2c/busses/i2c-designware.c2
-rw-r--r--drivers/i2c/busses/i2c-nomadik.c9
-rw-r--r--drivers/i2c/busses/i2c-omap.c29
-rw-r--r--drivers/i2c/busses/i2c-pxa-pci.c5
-rw-r--r--drivers/i2c/busses/i2c-tegra.c60
-rw-r--r--drivers/ide/Kconfig26
-rw-r--r--drivers/ide/ide-disk.c7
-rw-r--r--drivers/infiniband/hw/amso1100/c2.c11
-rw-r--r--drivers/infiniband/hw/cxgb3/Makefile2
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cm.c10
-rw-r--r--drivers/infiniband/hw/cxgb4/Makefile2
-rw-r--r--drivers/infiniband/hw/mlx4/Kconfig3
-rw-r--r--drivers/infiniband/hw/nes/nes_nic.c29
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c7
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c23
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c2
-rw-r--r--drivers/input/joystick/analog.c2
-rw-r--r--drivers/input/keyboard/adp5588-keys.c1
-rw-r--r--drivers/input/keyboard/ep93xx_keypad.c1
-rw-r--r--drivers/input/keyboard/tegra-kbc.c2
-rw-r--r--drivers/input/misc/ad714x-i2c.c81
-rw-r--r--drivers/input/misc/ad714x-spi.c68
-rw-r--r--drivers/input/misc/ad714x.c116
-rw-r--r--drivers/input/misc/ad714x.h35
-rw-r--r--drivers/input/misc/cm109.c2
-rw-r--r--drivers/input/misc/mma8450.c2
-rw-r--r--drivers/input/misc/mpu3050.c2
-rw-r--r--drivers/input/misc/rotary_encoder.c2
-rw-r--r--drivers/input/mouse/bcm5974.c60
-rw-r--r--drivers/input/tablet/wacom_sys.c31
-rw-r--r--drivers/input/tablet/wacom_wac.c56
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c12
-rw-r--r--drivers/input/touchscreen/max11801_ts.c3
-rw-r--r--drivers/input/touchscreen/tnetv107x-ts.c1
-rw-r--r--drivers/input/touchscreen/wacom_w8001.c2
-rw-r--r--drivers/iommu/amd_iommu.c18
-rw-r--r--drivers/iommu/dmar.c2
-rw-r--r--drivers/iommu/intel-iommu.c75
-rw-r--r--drivers/isdn/i4l/isdn_common.c4
-rw-r--r--drivers/isdn/mISDN/dsp_core.c3
-rw-r--r--drivers/isdn/mISDN/l1oip_codec.c6
-rw-r--r--drivers/leds/Kconfig2
-rw-r--r--drivers/leds/leds-ams-delta.c1
-rw-r--r--drivers/leds/leds-bd2802.c5
-rw-r--r--drivers/leds/leds-hp6xx.c1
-rw-r--r--drivers/leds/ledtrig-timer.c2
-rw-r--r--drivers/md/dm-crypt.c2
-rw-r--r--drivers/md/dm-flakey.c4
-rw-r--r--drivers/md/dm-kcopyd.c1
-rw-r--r--drivers/md/dm-raid.c2
-rw-r--r--drivers/md/dm-table.c32
-rw-r--r--drivers/md/linear.h2
-rw-r--r--drivers/md/md.c50
-rw-r--r--drivers/md/md.h2
-rw-r--r--drivers/md/multipath.c3
-rw-r--r--drivers/md/raid1.c17
-rw-r--r--drivers/md/raid10.c52
-rw-r--r--drivers/md/raid5.c8
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c2
-rw-r--r--drivers/media/dvb/dvb-usb/af9005-remote.c2
-rw-r--r--drivers/media/dvb/dvb-usb/af9005.c2
-rw-r--r--drivers/media/dvb/dvb-usb/vp7045.c26
-rw-r--r--drivers/media/dvb/frontends/dib3000.h2
-rw-r--r--drivers/media/dvb/frontends/dib3000mb.c2
-rw-r--r--drivers/media/radio/wl128x/fmdrv_v4l2.c2
-rw-r--r--drivers/media/rc/nuvoton-cir.c45
-rw-r--r--drivers/media/rc/nuvoton-cir.h1
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.h2
-rw-r--r--drivers/media/video/gspca/ov519.c22
-rw-r--r--drivers/media/video/gspca/sonixj.c6
-rw-r--r--drivers/media/video/omap/omap_vout.c13
-rw-r--r--drivers/media/video/omap3isp/ispccdc.c1
-rw-r--r--drivers/media/video/pwc/pwc-v4l.c2
-rw-r--r--drivers/media/video/uvc/uvc_driver.c2
-rw-r--r--drivers/media/video/uvc/uvc_entity.c2
-rw-r--r--drivers/media/video/uvc/uvc_video.c10
-rw-r--r--drivers/media/video/uvc/uvcvideo.h2
-rw-r--r--drivers/media/video/v4l2-dev.c11
-rw-r--r--drivers/media/video/v4l2-device.c2
-rw-r--r--drivers/media/video/via-camera.c6
-rw-r--r--drivers/mfd/Kconfig3
-rw-r--r--drivers/mfd/jz4740-adc.c2
-rw-r--r--drivers/mfd/max8997.c5
-rw-r--r--drivers/mfd/omap-usb-host.c2
-rw-r--r--drivers/mfd/tps65910-irq.c2
-rw-r--r--drivers/mfd/twl4030-madc.c5
-rw-r--r--drivers/mfd/wm831x-core.c437
-rw-r--r--drivers/mfd/wm831x-i2c.c76
-rw-r--r--drivers/mfd/wm831x-spi.c204
-rw-r--r--drivers/mfd/wm8350-gpio.c4
-rw-r--r--drivers/mfd/wm8400-core.c106
-rw-r--r--drivers/mfd/wm8994-core.c178
-rw-r--r--drivers/misc/Kconfig1
-rw-r--r--drivers/misc/ab8500-pwm.c2
-rw-r--r--drivers/misc/fsa9480.c4
-rw-r--r--drivers/misc/lis3lv02d/lis3lv02d.c14
-rw-r--r--drivers/misc/pch_phub.c10
-rw-r--r--drivers/misc/pti.c14
-rw-r--r--drivers/misc/ti-st/st_core.c10
-rw-r--r--drivers/misc/ti-st/st_kim.c33
-rw-r--r--drivers/misc/ti-st/st_ll.c19
-rw-r--r--drivers/mmc/card/block.c3
-rw-r--r--drivers/mmc/core/core.c35
-rw-r--r--drivers/mmc/core/host.c12
-rw-r--r--drivers/mmc/core/host.h8
-rw-r--r--drivers/mmc/core/sd.c81
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c1
-rw-r--r--drivers/mmc/host/sdhci-s3c.c2
-rw-r--r--drivers/mmc/host/sh_mobile_sdhi.c4
-rw-r--r--drivers/mtd/Kconfig2
-rw-r--r--drivers/mtd/ubi/debug.h2
-rw-r--r--drivers/net/Kconfig3389
-rw-r--r--drivers/net/Makefile326
-rw-r--r--drivers/net/appletalk/cops.c2
-rw-r--r--drivers/net/appletalk/ltpc.c2
-rw-r--r--drivers/net/arcnet/Kconfig14
-rw-r--r--drivers/net/arcnet/Makefile1
-rw-r--r--drivers/net/arcnet/com20020.c2
-rw-r--r--drivers/net/arcnet/com20020_cs.c (renamed from drivers/net/pcmcia/com20020_cs.c)0
-rw-r--r--drivers/net/arm/Kconfig74
-rw-r--r--drivers/net/arm/Makefile14
-rw-r--r--drivers/net/benet/Kconfig6
-rw-r--r--drivers/net/bna/bfa_ioc_ct.c516
-rw-r--r--drivers/net/bna/bfi_ctreg.h646
-rw-r--r--drivers/net/bna/bfi_ll.h438
-rw-r--r--drivers/net/bna/bna_ctrl.c3076
-rw-r--r--drivers/net/bna/bna_hw.h1490
-rw-r--r--drivers/net/bna/bna_txrx.c4185
-rw-r--r--drivers/net/bonding/bond_3ad.c10
-rw-r--r--drivers/net/bonding/bond_alb.c3
-rw-r--r--drivers/net/bonding/bond_main.c113
-rw-r--r--drivers/net/bonding/bond_sysfs.c46
-rw-r--r--drivers/net/bonding/bonding.h8
-rw-r--r--drivers/net/caif/caif_hsi.c436
-rw-r--r--drivers/net/caif/caif_spi.c4
-rw-r--r--drivers/net/can/at91_can.c2
-rw-r--r--drivers/net/can/dev.c14
-rw-r--r--drivers/net/can/flexcan.c189
-rw-r--r--drivers/net/can/mscan/mscan.c37
-rw-r--r--drivers/net/can/sja1000/Kconfig14
-rw-r--r--drivers/net/can/sja1000/Makefile2
-rw-r--r--drivers/net/can/sja1000/ems_pcmcia.c331
-rw-r--r--drivers/net/can/sja1000/peak_pci.c291
-rw-r--r--drivers/net/can/sja1000/plx_pci.c4
-rw-r--r--drivers/net/can/sja1000/sja1000.c2
-rw-r--r--drivers/net/can/sja1000/sja1000.h2
-rw-r--r--drivers/net/can/sja1000/sja1000_of_platform.c2
-rw-r--r--drivers/net/can/slcan.c2
-rw-r--r--drivers/net/can/ti_hecc.c4
-rw-r--r--drivers/net/can/vcan.c2
-rw-r--r--drivers/net/cris/eth_v10.c2
-rw-r--r--drivers/net/dummy.c2
-rw-r--r--drivers/net/ethernet/3com/3c501.c (renamed from drivers/net/3c501.c)2
-rw-r--r--drivers/net/ethernet/3com/3c501.h (renamed from drivers/net/3c501.h)0
-rw-r--r--drivers/net/ethernet/3com/3c509.c (renamed from drivers/net/3c509.c)2
-rw-r--r--drivers/net/ethernet/3com/3c515.c (renamed from drivers/net/3c515.c)2
-rw-r--r--drivers/net/ethernet/3com/3c574_cs.c (renamed from drivers/net/pcmcia/3c574_cs.c)2
-rw-r--r--drivers/net/ethernet/3com/3c589_cs.c (renamed from drivers/net/pcmcia/3c589_cs.c)2
-rw-r--r--drivers/net/ethernet/3com/3c59x.c (renamed from drivers/net/3c59x.c)15
-rw-r--r--drivers/net/ethernet/3com/Kconfig122
-rw-r--r--drivers/net/ethernet/3com/Makefile11
-rw-r--r--drivers/net/ethernet/3com/typhoon.c (renamed from drivers/net/typhoon.c)15
-rw-r--r--drivers/net/ethernet/3com/typhoon.h (renamed from drivers/net/typhoon.h)0
-rw-r--r--drivers/net/ethernet/8390/3c503.c (renamed from drivers/net/3c503.c)2
-rw-r--r--drivers/net/ethernet/8390/3c503.h (renamed from drivers/net/3c503.h)0
-rw-r--r--drivers/net/ethernet/8390/8390.c (renamed from drivers/net/8390.c)2
-rw-r--r--drivers/net/ethernet/8390/8390.h (renamed from drivers/net/8390.h)0
-rw-r--r--drivers/net/ethernet/8390/8390p.c (renamed from drivers/net/8390p.c)2
-rw-r--r--drivers/net/ethernet/8390/Kconfig337
-rw-r--r--drivers/net/ethernet/8390/Makefile29
-rw-r--r--drivers/net/ethernet/8390/ac3200.c (renamed from drivers/net/ac3200.c)2
-rw-r--r--drivers/net/ethernet/8390/apne.c (renamed from drivers/net/apne.c)0
-rw-r--r--drivers/net/ethernet/8390/ax88796.c (renamed from drivers/net/ax88796.c)2
-rw-r--r--drivers/net/ethernet/8390/axnet_cs.c (renamed from drivers/net/pcmcia/axnet_cs.c)4
-rw-r--r--drivers/net/ethernet/8390/e2100.c (renamed from drivers/net/e2100.c)2
-rw-r--r--drivers/net/ethernet/8390/es3210.c (renamed from drivers/net/es3210.c)0
-rw-r--r--drivers/net/ethernet/8390/etherh.c (renamed from drivers/net/arm/etherh.c)4
-rw-r--r--drivers/net/ethernet/8390/hp-plus.c (renamed from drivers/net/hp-plus.c)2
-rw-r--r--drivers/net/ethernet/8390/hp.c (renamed from drivers/net/hp.c)0
-rw-r--r--drivers/net/ethernet/8390/hydra.c (renamed from drivers/net/hydra.c)2
-rw-r--r--drivers/net/ethernet/8390/lib8390.c (renamed from drivers/net/lib8390.c)0
-rw-r--r--drivers/net/ethernet/8390/lne390.c (renamed from drivers/net/lne390.c)0
-rw-r--r--drivers/net/ethernet/8390/mac8390.c (renamed from drivers/net/mac8390.c)2
-rw-r--r--drivers/net/ethernet/8390/ne-h8300.c (renamed from drivers/net/ne-h8300.c)2
-rw-r--r--drivers/net/ethernet/8390/ne.c (renamed from drivers/net/ne.c)0
-rw-r--r--drivers/net/ethernet/8390/ne2.c (renamed from drivers/net/ne2.c)0
-rw-r--r--drivers/net/ethernet/8390/ne2k-pci.c (renamed from drivers/net/ne2k-pci.c)2
-rw-r--r--drivers/net/ethernet/8390/ne3210.c (renamed from drivers/net/ne3210.c)0
-rw-r--r--drivers/net/ethernet/8390/pcnet_cs.c (renamed from drivers/net/pcmcia/pcnet_cs.c)4
-rw-r--r--drivers/net/ethernet/8390/smc-mca.c (renamed from drivers/net/smc-mca.c)2
-rw-r--r--drivers/net/ethernet/8390/smc-ultra.c (renamed from drivers/net/smc-ultra.c)2
-rw-r--r--drivers/net/ethernet/8390/smc-ultra32.c (renamed from drivers/net/smc-ultra32.c)2
-rw-r--r--drivers/net/ethernet/8390/stnic.c (renamed from drivers/net/stnic.c)0
-rw-r--r--drivers/net/ethernet/8390/wd.c (renamed from drivers/net/wd.c)2
-rw-r--r--drivers/net/ethernet/8390/zorro8390.c (renamed from drivers/net/zorro8390.c)2
-rw-r--r--drivers/net/ethernet/Kconfig177
-rw-r--r--drivers/net/ethernet/Makefile74
-rw-r--r--drivers/net/ethernet/adaptec/Kconfig36
-rw-r--r--drivers/net/ethernet/adaptec/Makefile5
-rw-r--r--drivers/net/ethernet/adaptec/starfire.c (renamed from drivers/net/starfire.c)13
-rw-r--r--drivers/net/ethernet/adi/Kconfig69
-rw-r--r--drivers/net/ethernet/adi/Makefile5
-rw-r--r--drivers/net/ethernet/adi/bfin_mac.c (renamed from drivers/net/bfin_mac.c)2
-rw-r--r--drivers/net/ethernet/adi/bfin_mac.h (renamed from drivers/net/bfin_mac.h)0
-rw-r--r--drivers/net/ethernet/aeroflex/Kconfig11
-rw-r--r--drivers/net/ethernet/aeroflex/Makefile5
-rw-r--r--drivers/net/ethernet/aeroflex/greth.c (renamed from drivers/net/greth.c)32
-rw-r--r--drivers/net/ethernet/aeroflex/greth.h (renamed from drivers/net/greth.h)1
-rw-r--r--drivers/net/ethernet/alteon/Kconfig48
-rw-r--r--drivers/net/ethernet/alteon/Makefile5
-rw-r--r--drivers/net/ethernet/alteon/acenic.c (renamed from drivers/net/acenic.c)16
-rw-r--r--drivers/net/ethernet/alteon/acenic.h (renamed from drivers/net/acenic.h)0
-rw-r--r--drivers/net/ethernet/amd/7990.c (renamed from drivers/net/7990.c)0
-rw-r--r--drivers/net/ethernet/amd/7990.h (renamed from drivers/net/7990.h)0
-rw-r--r--drivers/net/ethernet/amd/Kconfig195
-rw-r--r--drivers/net/ethernet/amd/Makefile20
-rw-r--r--drivers/net/ethernet/amd/a2065.c (renamed from drivers/net/a2065.c)2
-rw-r--r--drivers/net/ethernet/amd/a2065.h (renamed from drivers/net/a2065.h)0
-rw-r--r--drivers/net/ethernet/amd/am79c961a.c (renamed from drivers/net/arm/am79c961a.c)5
-rw-r--r--drivers/net/ethernet/amd/am79c961a.h (renamed from drivers/net/arm/am79c961a.h)0
-rw-r--r--drivers/net/ethernet/amd/amd8111e.c (renamed from drivers/net/amd8111e.c)2
-rw-r--r--drivers/net/ethernet/amd/amd8111e.h (renamed from drivers/net/amd8111e.h)0
-rw-r--r--drivers/net/ethernet/amd/ariadne.c (renamed from drivers/net/ariadne.c)2
-rw-r--r--drivers/net/ethernet/amd/ariadne.h (renamed from drivers/net/ariadne.h)0
-rw-r--r--drivers/net/ethernet/amd/atarilance.c (renamed from drivers/net/atarilance.c)2
-rw-r--r--drivers/net/ethernet/amd/au1000_eth.c (renamed from drivers/net/au1000_eth.c)2
-rw-r--r--drivers/net/ethernet/amd/au1000_eth.h (renamed from drivers/net/au1000_eth.h)0
-rw-r--r--drivers/net/ethernet/amd/declance.c (renamed from drivers/net/declance.c)2
-rw-r--r--drivers/net/ethernet/amd/depca.c (renamed from drivers/net/depca.c)2
-rw-r--r--drivers/net/ethernet/amd/depca.h (renamed from drivers/net/depca.h)2
-rw-r--r--drivers/net/ethernet/amd/hplance.c (renamed from drivers/net/hplance.c)2
-rw-r--r--drivers/net/ethernet/amd/hplance.h (renamed from drivers/net/hplance.h)0
-rw-r--r--drivers/net/ethernet/amd/lance.c (renamed from drivers/net/lance.c)2
-rw-r--r--drivers/net/ethernet/amd/mvme147.c (renamed from drivers/net/mvme147.c)2
-rw-r--r--drivers/net/ethernet/amd/ni65.c (renamed from drivers/net/ni65.c)2
-rw-r--r--drivers/net/ethernet/amd/ni65.h (renamed from drivers/net/ni65.h)0
-rw-r--r--drivers/net/ethernet/amd/nmclan_cs.c (renamed from drivers/net/pcmcia/nmclan_cs.c)2
-rw-r--r--drivers/net/ethernet/amd/pcnet32.c (renamed from drivers/net/pcnet32.c)204
-rw-r--r--drivers/net/ethernet/amd/sun3lance.c (renamed from drivers/net/sun3lance.c)2
-rw-r--r--drivers/net/ethernet/amd/sunlance.c (renamed from drivers/net/sunlance.c)2
-rw-r--r--drivers/net/ethernet/apple/Kconfig77
-rw-r--r--drivers/net/ethernet/apple/Makefile8
-rw-r--r--drivers/net/ethernet/apple/bmac.c (renamed from drivers/net/bmac.c)2
-rw-r--r--drivers/net/ethernet/apple/bmac.h (renamed from drivers/net/bmac.h)0
-rw-r--r--drivers/net/ethernet/apple/mac89x0.c (renamed from drivers/net/mac89x0.c)2
-rw-r--r--drivers/net/ethernet/apple/mace.c (renamed from drivers/net/mace.c)2
-rw-r--r--drivers/net/ethernet/apple/mace.h (renamed from drivers/net/mace.h)0
-rw-r--r--drivers/net/ethernet/apple/macmace.c (renamed from drivers/net/macmace.c)11
-rw-r--r--drivers/net/ethernet/atheros/Kconfig70
-rw-r--r--drivers/net/ethernet/atheros/Makefile8
-rw-r--r--drivers/net/ethernet/atheros/atl1c/Makefile (renamed from drivers/net/atl1c/Makefile)0
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c.h (renamed from drivers/net/atl1c/atl1c.h)0
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c_ethtool.c (renamed from drivers/net/atl1c/atl1c_ethtool.c)0
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c_hw.c (renamed from drivers/net/atl1c/atl1c_hw.c)0
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c_hw.h (renamed from drivers/net/atl1c/atl1c_hw.h)0
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c_main.c (renamed from drivers/net/atl1c/atl1c_main.c)13
-rw-r--r--drivers/net/ethernet/atheros/atl1e/Makefile (renamed from drivers/net/atl1e/Makefile)0
-rw-r--r--drivers/net/ethernet/atheros/atl1e/atl1e.h (renamed from drivers/net/atl1e/atl1e.h)0
-rw-r--r--drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c (renamed from drivers/net/atl1e/atl1e_ethtool.c)0
-rw-r--r--drivers/net/ethernet/atheros/atl1e/atl1e_hw.c (renamed from drivers/net/atl1e/atl1e_hw.c)0
-rw-r--r--drivers/net/ethernet/atheros/atl1e/atl1e_hw.h (renamed from drivers/net/atl1e/atl1e_hw.h)0
-rw-r--r--drivers/net/ethernet/atheros/atl1e/atl1e_main.c (renamed from drivers/net/atl1e/atl1e_main.c)19
-rw-r--r--drivers/net/ethernet/atheros/atl1e/atl1e_param.c (renamed from drivers/net/atl1e/atl1e_param.c)0
-rw-r--r--drivers/net/ethernet/atheros/atlx/Makefile (renamed from drivers/net/atlx/Makefile)0
-rw-r--r--drivers/net/ethernet/atheros/atlx/atl1.c (renamed from drivers/net/atlx/atl1.c)27
-rw-r--r--drivers/net/ethernet/atheros/atlx/atl1.h (renamed from drivers/net/atlx/atl1.h)0
-rw-r--r--drivers/net/ethernet/atheros/atlx/atl2.c (renamed from drivers/net/atlx/atl2.c)2
-rw-r--r--drivers/net/ethernet/atheros/atlx/atl2.h (renamed from drivers/net/atlx/atl2.h)0
-rw-r--r--drivers/net/ethernet/atheros/atlx/atlx.c (renamed from drivers/net/atlx/atlx.c)0
-rw-r--r--drivers/net/ethernet/atheros/atlx/atlx.h (renamed from drivers/net/atlx/atlx.h)0
-rw-r--r--drivers/net/ethernet/broadcom/Kconfig122
-rw-r--r--drivers/net/ethernet/broadcom/Makefile11
-rw-r--r--drivers/net/ethernet/broadcom/b44.c (renamed from drivers/net/b44.c)2
-rw-r--r--drivers/net/ethernet/broadcom/b44.h (renamed from drivers/net/b44.h)0
-rw-r--r--drivers/net/ethernet/broadcom/bcm63xx_enet.c (renamed from drivers/net/bcm63xx_enet.c)4
-rw-r--r--drivers/net/ethernet/broadcom/bcm63xx_enet.h (renamed from drivers/net/bcm63xx_enet.h)0
-rw-r--r--drivers/net/ethernet/broadcom/bnx2.c (renamed from drivers/net/bnx2.c)94
-rw-r--r--drivers/net/ethernet/broadcom/bnx2.h (renamed from drivers/net/bnx2.h)12
-rw-r--r--drivers/net/ethernet/broadcom/bnx2_fw.h (renamed from drivers/net/bnx2_fw.h)0
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/Makefile (renamed from drivers/net/bnx2x/Makefile)0
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x.h (renamed from drivers/net/bnx2x/bnx2x.h)209
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c (renamed from drivers/net/bnx2x/bnx2x_cmn.c)92
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h (renamed from drivers/net/bnx2x/bnx2x_cmn.h)12
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c (renamed from drivers/net/bnx2x/bnx2x_dcb.c)6
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h (renamed from drivers/net/bnx2x/bnx2x_dcb.h)0
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h (renamed from drivers/net/bnx2x/bnx2x_dump.h)0
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c (renamed from drivers/net/bnx2x/bnx2x_ethtool.c)78
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h (renamed from drivers/net/bnx2x/bnx2x_fw_defs.h)0
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h (renamed from drivers/net/bnx2x/bnx2x_fw_file_hdr.h)0
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h (renamed from drivers/net/bnx2x/bnx2x_hsi.h)2
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h (renamed from drivers/net/bnx2x/bnx2x_init.h)0
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h (renamed from drivers/net/bnx2x/bnx2x_init_ops.h)0
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c (renamed from drivers/net/bnx2x/bnx2x_link.c)196
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h (renamed from drivers/net/bnx2x/bnx2x_link.h)0
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c (renamed from drivers/net/bnx2x/bnx2x_main.c)259
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h (renamed from drivers/net/bnx2x/bnx2x_reg.h)19
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c (renamed from drivers/net/bnx2x/bnx2x_sp.c)67
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h (renamed from drivers/net/bnx2x/bnx2x_sp.h)0
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c (renamed from drivers/net/bnx2x/bnx2x_stats.c)53
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h (renamed from drivers/net/bnx2x/bnx2x_stats.h)0
-rw-r--r--drivers/net/ethernet/broadcom/cnic.c (renamed from drivers/net/cnic.c)35
-rw-r--r--drivers/net/ethernet/broadcom/cnic.h (renamed from drivers/net/cnic.h)4
-rw-r--r--drivers/net/ethernet/broadcom/cnic_defs.h (renamed from drivers/net/cnic_defs.h)1
-rw-r--r--drivers/net/ethernet/broadcom/cnic_if.h (renamed from drivers/net/cnic_if.h)0
-rw-r--r--drivers/net/ethernet/broadcom/sb1250-mac.c (renamed from drivers/net/sb1250-mac.c)2
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c (renamed from drivers/net/tg3.c)1448
-rw-r--r--drivers/net/ethernet/broadcom/tg3.h (renamed from drivers/net/tg3.h)4
-rw-r--r--drivers/net/ethernet/brocade/Kconfig23
-rw-r--r--drivers/net/ethernet/brocade/Makefile5
-rw-r--r--drivers/net/ethernet/brocade/bna/Kconfig17
-rw-r--r--drivers/net/ethernet/brocade/bna/Makefile (renamed from drivers/net/bna/Makefile)5
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_cee.c (renamed from drivers/net/bna/bfa_cee.c)5
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_cee.h (renamed from drivers/net/bna/bfa_cee.h)0
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_cs.h (renamed from drivers/net/bna/bfa_cs.h)0
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_defs.h (renamed from drivers/net/bna/bfa_defs.h)64
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_defs_cna.h (renamed from drivers/net/bna/bfa_defs_cna.h)8
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_defs_mfg_comm.h (renamed from drivers/net/bna/bfa_defs_mfg_comm.h)69
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_defs_status.h (renamed from drivers/net/bna/bfa_defs_status.h)0
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_ioc.c (renamed from drivers/net/bna/bfa_ioc.c)459
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_ioc.h (renamed from drivers/net/bna/bfa_ioc.h)68
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_ioc_ct.c878
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_msgq.c669
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_msgq.h130
-rw-r--r--drivers/net/ethernet/brocade/bna/bfi.h (renamed from drivers/net/bna/bfi.h)257
-rw-r--r--drivers/net/ethernet/brocade/bna/bfi_cna.h (renamed from drivers/net/bna/bfi_cna.h)0
-rw-r--r--drivers/net/ethernet/brocade/bna/bfi_enet.h901
-rw-r--r--drivers/net/ethernet/brocade/bna/bfi_reg.h452
-rw-r--r--drivers/net/ethernet/brocade/bna/bna.h (renamed from drivers/net/bna/bna.h)351
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_enet.c2144
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_hw_defs.h422
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_tx_rx.c3798
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_types.h (renamed from drivers/net/bna/bna_types.h)656
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.c (renamed from drivers/net/bna/bnad.c)1178
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.h (renamed from drivers/net/bna/bnad.h)101
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad_ethtool.c (renamed from drivers/net/bna/bnad_ethtool.c)490
-rw-r--r--drivers/net/ethernet/brocade/bna/cna.h (renamed from drivers/net/bna/cna.h)43
-rw-r--r--drivers/net/ethernet/brocade/bna/cna_fwimg.c (renamed from drivers/net/bna/cna_fwimg.c)48
-rw-r--r--drivers/net/ethernet/cadence/Kconfig45
-rw-r--r--drivers/net/ethernet/cadence/Makefile6
-rw-r--r--drivers/net/ethernet/cadence/at91_ether.c (renamed from drivers/net/arm/at91_ether.c)2
-rw-r--r--drivers/net/ethernet/cadence/at91_ether.h (renamed from drivers/net/arm/at91_ether.h)0
-rw-r--r--drivers/net/ethernet/cadence/macb.c (renamed from drivers/net/macb.c)2
-rw-r--r--drivers/net/ethernet/cadence/macb.h (renamed from drivers/net/macb.h)0
-rw-r--r--drivers/net/ethernet/chelsio/Kconfig107
-rw-r--r--drivers/net/ethernet/chelsio/Makefile8
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/Makefile (renamed from drivers/net/chelsio/Makefile)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/common.h (renamed from drivers/net/chelsio/common.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/cphy.h (renamed from drivers/net/chelsio/cphy.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/cpl5_cmd.h (renamed from drivers/net/chelsio/cpl5_cmd.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/cxgb2.c (renamed from drivers/net/chelsio/cxgb2.c)4
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/elmer0.h (renamed from drivers/net/chelsio/elmer0.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/espi.c (renamed from drivers/net/chelsio/espi.c)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/espi.h (renamed from drivers/net/chelsio/espi.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/fpga_defs.h (renamed from drivers/net/chelsio/fpga_defs.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/gmac.h (renamed from drivers/net/chelsio/gmac.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/mv88e1xxx.c (renamed from drivers/net/chelsio/mv88e1xxx.c)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/mv88e1xxx.h (renamed from drivers/net/chelsio/mv88e1xxx.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/mv88x201x.c (renamed from drivers/net/chelsio/mv88x201x.c)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/my3126.c (renamed from drivers/net/chelsio/my3126.c)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/pm3393.c (renamed from drivers/net/chelsio/pm3393.c)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/regs.h (renamed from drivers/net/chelsio/regs.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/sge.c (renamed from drivers/net/chelsio/sge.c)13
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/sge.h (renamed from drivers/net/chelsio/sge.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/subr.c (renamed from drivers/net/chelsio/subr.c)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/suni1x10gexp_regs.h (renamed from drivers/net/chelsio/suni1x10gexp_regs.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/tp.c (renamed from drivers/net/chelsio/tp.c)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/tp.h (renamed from drivers/net/chelsio/tp.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/vsc7326.c (renamed from drivers/net/chelsio/vsc7326.c)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/vsc7326_reg.h (renamed from drivers/net/chelsio/vsc7326_reg.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/Makefile (renamed from drivers/net/cxgb3/Makefile)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/adapter.h (renamed from drivers/net/cxgb3/adapter.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/ael1002.c (renamed from drivers/net/cxgb3/ael1002.c)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/aq100x.c (renamed from drivers/net/cxgb3/aq100x.c)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/common.h (renamed from drivers/net/cxgb3/common.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_ctl_defs.h (renamed from drivers/net/cxgb3/cxgb3_ctl_defs.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_defs.h (renamed from drivers/net/cxgb3/cxgb3_defs.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_ioctl.h (renamed from drivers/net/cxgb3/cxgb3_ioctl.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c (renamed from drivers/net/cxgb3/cxgb3_main.c)3
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c (renamed from drivers/net/cxgb3/cxgb3_offload.c)23
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.h (renamed from drivers/net/cxgb3/cxgb3_offload.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/firmware_exports.h (renamed from drivers/net/cxgb3/firmware_exports.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/l2t.c (renamed from drivers/net/cxgb3/l2t.c)15
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/l2t.h (renamed from drivers/net/cxgb3/l2t.h)16
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/mc5.c (renamed from drivers/net/cxgb3/mc5.c)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/regs.h (renamed from drivers/net/cxgb3/regs.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/sge.c (renamed from drivers/net/cxgb3/sge.c)16
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/sge_defs.h (renamed from drivers/net/cxgb3/sge_defs.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/t3_cpl.h (renamed from drivers/net/cxgb3/t3_cpl.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/t3_hw.c (renamed from drivers/net/cxgb3/t3_hw.c)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/t3cdev.h (renamed from drivers/net/cxgb3/t3cdev.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/version.h (renamed from drivers/net/cxgb3/version.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/vsc8211.c (renamed from drivers/net/cxgb3/vsc8211.c)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/xgmac.c (renamed from drivers/net/cxgb3/xgmac.c)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/Makefile (renamed from drivers/net/cxgb4/Makefile)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4.h (renamed from drivers/net/cxgb4/cxgb4.h)2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c (renamed from drivers/net/cxgb4/cxgb4_main.c)8
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h (renamed from drivers/net/cxgb4/cxgb4_uld.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/l2t.c (renamed from drivers/net/cxgb4/l2t.c)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/l2t.h (renamed from drivers/net/cxgb4/l2t.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/sge.c (renamed from drivers/net/cxgb4/sge.c)49
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_hw.c (renamed from drivers/net/cxgb4/t4_hw.c)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_hw.h (renamed from drivers/net/cxgb4/t4_hw.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_msg.h (renamed from drivers/net/cxgb4/t4_msg.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_regs.h (renamed from drivers/net/cxgb4/t4_regs.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h (renamed from drivers/net/cxgb4/t4fw_api.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/Makefile (renamed from drivers/net/cxgb4vf/Makefile)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/adapter.h (renamed from drivers/net/cxgb4vf/adapter.h)2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c (renamed from drivers/net/cxgb4vf/cxgb4vf_main.c)2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/sge.c (renamed from drivers/net/cxgb4vf/sge.c)94
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h (renamed from drivers/net/cxgb4vf/t4vf_common.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/t4vf_defs.h (renamed from drivers/net/cxgb4vf/t4vf_defs.h)0
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c (renamed from drivers/net/cxgb4vf/t4vf_hw.c)0
-rw-r--r--drivers/net/ethernet/cirrus/Kconfig50
-rw-r--r--drivers/net/ethernet/cirrus/Makefile6
-rw-r--r--drivers/net/ethernet/cirrus/cs89x0.c (renamed from drivers/net/cs89x0.c)2
-rw-r--r--drivers/net/ethernet/cirrus/cs89x0.h (renamed from drivers/net/cs89x0.h)0
-rw-r--r--drivers/net/ethernet/cirrus/ep93xx_eth.c (renamed from drivers/net/arm/ep93xx_eth.c)0
-rw-r--r--drivers/net/ethernet/cisco/Kconfig23
-rw-r--r--drivers/net/ethernet/cisco/Makefile5
-rw-r--r--drivers/net/ethernet/cisco/enic/Kconfig9
-rw-r--r--drivers/net/ethernet/cisco/enic/Makefile (renamed from drivers/net/enic/Makefile)0
-rw-r--r--drivers/net/ethernet/cisco/enic/cq_desc.h (renamed from drivers/net/enic/cq_desc.h)0
-rw-r--r--drivers/net/ethernet/cisco/enic/cq_enet_desc.h (renamed from drivers/net/enic/cq_enet_desc.h)0
-rw-r--r--drivers/net/ethernet/cisco/enic/enic.h (renamed from drivers/net/enic/enic.h)15
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_dev.c (renamed from drivers/net/enic/enic_dev.c)0
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_dev.h (renamed from drivers/net/enic/enic_dev.h)19
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_main.c (renamed from drivers/net/enic/enic_main.c)202
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_pp.c (renamed from drivers/net/enic/enic_pp.c)192
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_pp.h (renamed from drivers/net/enic/enic_pp.h)15
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_res.c (renamed from drivers/net/enic/enic_res.c)0
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_res.h (renamed from drivers/net/enic/enic_res.h)0
-rw-r--r--drivers/net/ethernet/cisco/enic/rq_enet_desc.h (renamed from drivers/net/enic/rq_enet_desc.h)0
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_cq.c (renamed from drivers/net/enic/vnic_cq.c)0
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_cq.h (renamed from drivers/net/enic/vnic_cq.h)0
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_dev.c (renamed from drivers/net/enic/vnic_dev.c)28
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_dev.h (renamed from drivers/net/enic/vnic_dev.h)2
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_devcmd.h (renamed from drivers/net/enic/vnic_devcmd.h)0
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_enet.h (renamed from drivers/net/enic/vnic_enet.h)0
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_intr.c (renamed from drivers/net/enic/vnic_intr.c)0
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_intr.h (renamed from drivers/net/enic/vnic_intr.h)0
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_nic.h (renamed from drivers/net/enic/vnic_nic.h)0
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_resource.h (renamed from drivers/net/enic/vnic_resource.h)0
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_rq.c (renamed from drivers/net/enic/vnic_rq.c)0
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_rq.h (renamed from drivers/net/enic/vnic_rq.h)0
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_rss.h (renamed from drivers/net/enic/vnic_rss.h)0
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_stats.h (renamed from drivers/net/enic/vnic_stats.h)0
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_vic.c (renamed from drivers/net/enic/vnic_vic.c)0
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_vic.h (renamed from drivers/net/enic/vnic_vic.h)0
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_wq.c (renamed from drivers/net/enic/vnic_wq.c)0
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_wq.h (renamed from drivers/net/enic/vnic_wq.h)0
-rw-r--r--drivers/net/ethernet/cisco/enic/wq_enet_desc.h (renamed from drivers/net/enic/wq_enet_desc.h)0
-rw-r--r--drivers/net/ethernet/davicom/Kconfig24
-rw-r--r--drivers/net/ethernet/davicom/Makefile5
-rw-r--r--drivers/net/ethernet/davicom/dm9000.c (renamed from drivers/net/dm9000.c)13
-rw-r--r--drivers/net/ethernet/davicom/dm9000.h (renamed from drivers/net/dm9000.h)0
-rw-r--r--drivers/net/ethernet/dec/Kconfig37
-rw-r--r--drivers/net/ethernet/dec/Makefile6
-rw-r--r--drivers/net/ethernet/dec/ewrk3.c (renamed from drivers/net/ewrk3.c)2
-rw-r--r--drivers/net/ethernet/dec/ewrk3.h (renamed from drivers/net/ewrk3.h)0
-rw-r--r--drivers/net/ethernet/dec/tulip/21142.c (renamed from drivers/net/tulip/21142.c)3
-rw-r--r--drivers/net/ethernet/dec/tulip/Kconfig (renamed from drivers/net/tulip/Kconfig)21
-rw-r--r--drivers/net/ethernet/dec/tulip/Makefile (renamed from drivers/net/tulip/Makefile)0
-rw-r--r--drivers/net/ethernet/dec/tulip/de2104x.c (renamed from drivers/net/tulip/de2104x.c)2
-rw-r--r--drivers/net/ethernet/dec/tulip/de4x5.c (renamed from drivers/net/tulip/de4x5.c)2
-rw-r--r--drivers/net/ethernet/dec/tulip/de4x5.h (renamed from drivers/net/tulip/de4x5.h)2
-rw-r--r--drivers/net/ethernet/dec/tulip/dmfe.c (renamed from drivers/net/tulip/dmfe.c)2
-rw-r--r--drivers/net/ethernet/dec/tulip/eeprom.c (renamed from drivers/net/tulip/eeprom.c)2
-rw-r--r--drivers/net/ethernet/dec/tulip/interrupt.c (renamed from drivers/net/tulip/interrupt.c)3
-rw-r--r--drivers/net/ethernet/dec/tulip/media.c (renamed from drivers/net/tulip/media.c)3
-rw-r--r--drivers/net/ethernet/dec/tulip/pnic.c (renamed from drivers/net/tulip/pnic.c)3
-rw-r--r--drivers/net/ethernet/dec/tulip/pnic2.c (renamed from drivers/net/tulip/pnic2.c)3
-rw-r--r--drivers/net/ethernet/dec/tulip/timer.c (renamed from drivers/net/tulip/timer.c)3
-rw-r--r--drivers/net/ethernet/dec/tulip/tulip.h (renamed from drivers/net/tulip/tulip.h)3
-rw-r--r--drivers/net/ethernet/dec/tulip/tulip_core.c (renamed from drivers/net/tulip/tulip_core.c)5
-rw-r--r--drivers/net/ethernet/dec/tulip/uli526x.c (renamed from drivers/net/tulip/uli526x.c)2
-rw-r--r--drivers/net/ethernet/dec/tulip/winbond-840.c (renamed from drivers/net/tulip/winbond-840.c)2
-rw-r--r--drivers/net/ethernet/dec/tulip/xircom_cb.c (renamed from drivers/net/tulip/xircom_cb.c)0
-rw-r--r--drivers/net/ethernet/dlink/Kconfig86
-rw-r--r--drivers/net/ethernet/dlink/Makefile8
-rw-r--r--drivers/net/ethernet/dlink/de600.c (renamed from drivers/net/de600.c)0
-rw-r--r--drivers/net/ethernet/dlink/de600.h (renamed from drivers/net/de600.h)0
-rw-r--r--drivers/net/ethernet/dlink/de620.c (renamed from drivers/net/de620.c)2
-rw-r--r--drivers/net/ethernet/dlink/de620.h (renamed from drivers/net/de620.h)0
-rw-r--r--drivers/net/ethernet/dlink/dl2k.c (renamed from drivers/net/dl2k.c)107
-rw-r--r--drivers/net/ethernet/dlink/dl2k.h (renamed from drivers/net/dl2k.h)110
-rw-r--r--drivers/net/ethernet/dlink/sundance.c (renamed from drivers/net/sundance.c)2
-rw-r--r--drivers/net/ethernet/dnet.c (renamed from drivers/net/dnet.c)0
-rw-r--r--drivers/net/ethernet/dnet.h (renamed from drivers/net/dnet.h)0
-rw-r--r--drivers/net/ethernet/emulex/Kconfig23
-rw-r--r--drivers/net/ethernet/emulex/Makefile5
-rw-r--r--drivers/net/ethernet/emulex/benet/Kconfig6
-rw-r--r--drivers/net/ethernet/emulex/benet/Makefile (renamed from drivers/net/benet/Makefile)0
-rw-r--r--drivers/net/ethernet/emulex/benet/be.h (renamed from drivers/net/benet/be.h)132
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.c (renamed from drivers/net/benet/be_cmds.c)307
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.h (renamed from drivers/net/benet/be_cmds.h)104
-rw-r--r--drivers/net/ethernet/emulex/benet/be_ethtool.c (renamed from drivers/net/benet/be_ethtool.c)168
-rw-r--r--drivers/net/ethernet/emulex/benet/be_hw.h (renamed from drivers/net/benet/be_hw.h)21
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c (renamed from drivers/net/benet/be_main.c)915
-rw-r--r--drivers/net/ethernet/ethoc.c (renamed from drivers/net/ethoc.c)2
-rw-r--r--drivers/net/ethernet/faraday/Kconfig40
-rw-r--r--drivers/net/ethernet/faraday/Makefile6
-rw-r--r--drivers/net/ethernet/faraday/ftgmac100.c (renamed from drivers/net/ftgmac100.c)4
-rw-r--r--drivers/net/ethernet/faraday/ftgmac100.h (renamed from drivers/net/ftgmac100.h)0
-rw-r--r--drivers/net/ethernet/faraday/ftmac100.c (renamed from drivers/net/ftmac100.c)5
-rw-r--r--drivers/net/ethernet/faraday/ftmac100.h (renamed from drivers/net/ftmac100.h)0
-rw-r--r--drivers/net/ethernet/fealnx.c (renamed from drivers/net/fealnx.c)2
-rw-r--r--drivers/net/ethernet/freescale/Kconfig88
-rw-r--r--drivers/net/ethernet/freescale/Makefile18
-rw-r--r--drivers/net/ethernet/freescale/fec.c (renamed from drivers/net/fec.c)117
-rw-r--r--drivers/net/ethernet/freescale/fec.h (renamed from drivers/net/fec.h)0
-rw-r--r--drivers/net/ethernet/freescale/fec_mpc52xx.c (renamed from drivers/net/fec_mpc52xx.c)2
-rw-r--r--drivers/net/ethernet/freescale/fec_mpc52xx.h (renamed from drivers/net/fec_mpc52xx.h)0
-rw-r--r--drivers/net/ethernet/freescale/fec_mpc52xx_phy.c (renamed from drivers/net/fec_mpc52xx_phy.c)0
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/Kconfig (renamed from drivers/net/fs_enet/Kconfig)3
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/Makefile (renamed from drivers/net/fs_enet/Makefile)0
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/fec.h (renamed from drivers/net/fs_enet/fec.h)0
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c (renamed from drivers/net/fs_enet/fs_enet-main.c)2
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/fs_enet.h (renamed from drivers/net/fs_enet/fs_enet.h)0
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/mac-fcc.c (renamed from drivers/net/fs_enet/mac-fcc.c)0
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/mac-fec.c (renamed from drivers/net/fs_enet/mac-fec.c)0
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/mac-scc.c (renamed from drivers/net/fs_enet/mac-scc.c)0
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c (renamed from drivers/net/fs_enet/mii-bitbang.c)0
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/mii-fec.c (renamed from drivers/net/fs_enet/mii-fec.c)0
-rw-r--r--drivers/net/ethernet/freescale/fsl_pq_mdio.c (renamed from drivers/net/fsl_pq_mdio.c)0
-rw-r--r--drivers/net/ethernet/freescale/fsl_pq_mdio.h (renamed from drivers/net/fsl_pq_mdio.h)0
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c (renamed from drivers/net/gianfar.c)21
-rw-r--r--drivers/net/ethernet/freescale/gianfar.h (renamed from drivers/net/gianfar.h)0
-rw-r--r--drivers/net/ethernet/freescale/gianfar_ethtool.c (renamed from drivers/net/gianfar_ethtool.c)39
-rw-r--r--drivers/net/ethernet/freescale/gianfar_ptp.c (renamed from drivers/net/gianfar_ptp.c)0
-rw-r--r--drivers/net/ethernet/freescale/gianfar_sysfs.c (renamed from drivers/net/gianfar_sysfs.c)0
-rw-r--r--drivers/net/ethernet/freescale/ucc_geth.c (renamed from drivers/net/ucc_geth.c)12
-rw-r--r--drivers/net/ethernet/freescale/ucc_geth.h (renamed from drivers/net/ucc_geth.h)0
-rw-r--r--drivers/net/ethernet/freescale/ucc_geth_ethtool.c (renamed from drivers/net/ucc_geth_ethtool.c)0
-rw-r--r--drivers/net/ethernet/fujitsu/Kconfig54
-rw-r--r--drivers/net/ethernet/fujitsu/Makefile7
-rw-r--r--drivers/net/ethernet/fujitsu/at1700.c (renamed from drivers/net/at1700.c)2
-rw-r--r--drivers/net/ethernet/fujitsu/eth16i.c (renamed from drivers/net/eth16i.c)2
-rw-r--r--drivers/net/ethernet/fujitsu/fmvj18x_cs.c (renamed from drivers/net/pcmcia/fmvj18x_cs.c)2
-rw-r--r--drivers/net/ethernet/hp/Kconfig32
-rw-r--r--drivers/net/ethernet/hp/Makefile5
-rw-r--r--drivers/net/ethernet/hp/hp100.c (renamed from drivers/net/hp100.c)4
-rw-r--r--drivers/net/ethernet/hp/hp100.h (renamed from drivers/net/hp100.h)0
-rw-r--r--drivers/net/ethernet/i825xx/3c505.c (renamed from drivers/net/3c505.c)2
-rw-r--r--drivers/net/ethernet/i825xx/3c505.h (renamed from drivers/net/3c505.h)0
-rw-r--r--drivers/net/ethernet/i825xx/3c507.c (renamed from drivers/net/3c507.c)0
-rw-r--r--drivers/net/ethernet/i825xx/3c523.c (renamed from drivers/net/3c523.c)2
-rw-r--r--drivers/net/ethernet/i825xx/3c523.h (renamed from drivers/net/3c523.h)0
-rw-r--r--drivers/net/ethernet/i825xx/3c527.c (renamed from drivers/net/3c527.c)2
-rw-r--r--drivers/net/ethernet/i825xx/3c527.h (renamed from drivers/net/3c527.h)0
-rw-r--r--drivers/net/ethernet/i825xx/82596.c (renamed from drivers/net/82596.c)2
-rw-r--r--drivers/net/ethernet/i825xx/Kconfig183
-rw-r--r--drivers/net/ethernet/i825xx/Makefile20
-rw-r--r--drivers/net/ethernet/i825xx/eepro.c (renamed from drivers/net/eepro.c)2
-rw-r--r--drivers/net/ethernet/i825xx/eexpress.c (renamed from drivers/net/eexpress.c)2
-rw-r--r--drivers/net/ethernet/i825xx/eexpress.h (renamed from drivers/net/eexpress.h)0
-rw-r--r--drivers/net/ethernet/i825xx/ether1.c (renamed from drivers/net/arm/ether1.c)2
-rw-r--r--drivers/net/ethernet/i825xx/ether1.h (renamed from drivers/net/arm/ether1.h)0
-rw-r--r--drivers/net/ethernet/i825xx/lasi_82596.c (renamed from drivers/net/lasi_82596.c)0
-rw-r--r--drivers/net/ethernet/i825xx/lib82596.c (renamed from drivers/net/lib82596.c)2
-rw-r--r--drivers/net/ethernet/i825xx/lp486e.c (renamed from drivers/net/lp486e.c)2
-rw-r--r--drivers/net/ethernet/i825xx/ni52.c (renamed from drivers/net/ni52.c)2
-rw-r--r--drivers/net/ethernet/i825xx/ni52.h (renamed from drivers/net/ni52.h)0
-rw-r--r--drivers/net/ethernet/i825xx/sni_82596.c (renamed from drivers/net/sni_82596.c)0
-rw-r--r--drivers/net/ethernet/i825xx/sun3_82586.c (renamed from drivers/net/sun3_82586.c)2
-rw-r--r--drivers/net/ethernet/i825xx/sun3_82586.h (renamed from drivers/net/sun3_82586.h)0
-rw-r--r--drivers/net/ethernet/i825xx/znet.c (renamed from drivers/net/znet.c)2
-rw-r--r--drivers/net/ethernet/ibm/Kconfig48
-rw-r--r--drivers/net/ethernet/ibm/Makefile8
-rw-r--r--drivers/net/ethernet/ibm/ehea/Makefile (renamed from drivers/net/ehea/Makefile)0
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea.h (renamed from drivers/net/ehea/ehea.h)21
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_ethtool.c (renamed from drivers/net/ehea/ehea_ethtool.c)33
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_hw.h (renamed from drivers/net/ehea/ehea_hw.h)25
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_main.c (renamed from drivers/net/ehea/ehea_main.c)544
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_phyp.c (renamed from drivers/net/ehea/ehea_phyp.c)0
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_phyp.h (renamed from drivers/net/ehea/ehea_phyp.h)0
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_qmr.c (renamed from drivers/net/ehea/ehea_qmr.c)0
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_qmr.h (renamed from drivers/net/ehea/ehea_qmr.h)2
-rw-r--r--drivers/net/ethernet/ibm/emac/Kconfig (renamed from drivers/net/ibm_newemac/Kconfig)40
-rw-r--r--drivers/net/ethernet/ibm/emac/Makefile11
-rw-r--r--drivers/net/ethernet/ibm/emac/core.c (renamed from drivers/net/ibm_newemac/core.c)22
-rw-r--r--drivers/net/ethernet/ibm/emac/core.h (renamed from drivers/net/ibm_newemac/core.h)16
-rw-r--r--drivers/net/ethernet/ibm/emac/debug.c (renamed from drivers/net/ibm_newemac/debug.c)0
-rw-r--r--drivers/net/ethernet/ibm/emac/debug.h (renamed from drivers/net/ibm_newemac/debug.h)2
-rw-r--r--drivers/net/ethernet/ibm/emac/emac.h (renamed from drivers/net/ibm_newemac/emac.h)0
-rw-r--r--drivers/net/ethernet/ibm/emac/mal.c (renamed from drivers/net/ibm_newemac/mal.c)6
-rw-r--r--drivers/net/ethernet/ibm/emac/mal.h (renamed from drivers/net/ibm_newemac/mal.h)4
-rw-r--r--drivers/net/ethernet/ibm/emac/phy.c (renamed from drivers/net/ibm_newemac/phy.c)0
-rw-r--r--drivers/net/ethernet/ibm/emac/phy.h (renamed from drivers/net/ibm_newemac/phy.h)0
-rw-r--r--drivers/net/ethernet/ibm/emac/rgmii.c (renamed from drivers/net/ibm_newemac/rgmii.c)0
-rw-r--r--drivers/net/ethernet/ibm/emac/rgmii.h (renamed from drivers/net/ibm_newemac/rgmii.h)4
-rw-r--r--drivers/net/ethernet/ibm/emac/tah.c (renamed from drivers/net/ibm_newemac/tah.c)0
-rw-r--r--drivers/net/ethernet/ibm/emac/tah.h (renamed from drivers/net/ibm_newemac/tah.h)4
-rw-r--r--drivers/net/ethernet/ibm/emac/zmii.c (renamed from drivers/net/ibm_newemac/zmii.c)0
-rw-r--r--drivers/net/ethernet/ibm/emac/zmii.h (renamed from drivers/net/ibm_newemac/zmii.h)4
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.c (renamed from drivers/net/ibmveth.c)75
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.h (renamed from drivers/net/ibmveth.h)0
-rw-r--r--drivers/net/ethernet/ibm/iseries_veth.c (renamed from drivers/net/iseries_veth.c)2
-rw-r--r--drivers/net/ethernet/icplus/Kconfig14
-rw-r--r--drivers/net/ethernet/icplus/Makefile5
-rw-r--r--drivers/net/ethernet/icplus/ipg.c (renamed from drivers/net/ipg.c)199
-rw-r--r--drivers/net/ethernet/icplus/ipg.h (renamed from drivers/net/ipg.h)0
-rw-r--r--drivers/net/ethernet/intel/Kconfig222
-rw-r--r--drivers/net/ethernet/intel/Makefile12
-rw-r--r--drivers/net/ethernet/intel/e100.c (renamed from drivers/net/e100.c)6
-rw-r--r--drivers/net/ethernet/intel/e1000/Makefile (renamed from drivers/net/e1000/Makefile)0
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000.h (renamed from drivers/net/e1000/e1000.h)14
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_ethtool.c (renamed from drivers/net/e1000/e1000_ethtool.c)4
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_hw.c (renamed from drivers/net/e1000/e1000_hw.c)28
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_hw.h (renamed from drivers/net/e1000/e1000_hw.h)0
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_main.c (renamed from drivers/net/e1000/e1000_main.c)219
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_osdep.h (renamed from drivers/net/e1000/e1000_osdep.h)0
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_param.c (renamed from drivers/net/e1000/e1000_param.c)0
-rw-r--r--drivers/net/ethernet/intel/e1000e/80003es2lan.c (renamed from drivers/net/e1000e/es2lan.c)9
-rw-r--r--drivers/net/ethernet/intel/e1000e/82571.c (renamed from drivers/net/e1000e/82571.c)25
-rw-r--r--drivers/net/ethernet/intel/e1000e/Makefile (renamed from drivers/net/e1000e/Makefile)2
-rw-r--r--drivers/net/ethernet/intel/e1000e/defines.h (renamed from drivers/net/e1000e/defines.h)0
-rw-r--r--drivers/net/ethernet/intel/e1000e/e1000.h (renamed from drivers/net/e1000e/e1000.h)39
-rw-r--r--drivers/net/ethernet/intel/e1000e/ethtool.c (renamed from drivers/net/e1000e/ethtool.c)101
-rw-r--r--drivers/net/ethernet/intel/e1000e/hw.h (renamed from drivers/net/e1000e/hw.h)0
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.c (renamed from drivers/net/e1000e/ich8lan.c)134
-rw-r--r--drivers/net/ethernet/intel/e1000e/lib.c (renamed from drivers/net/e1000e/lib.c)0
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c (renamed from drivers/net/e1000e/netdev.c)349
-rw-r--r--drivers/net/ethernet/intel/e1000e/param.c (renamed from drivers/net/e1000e/param.c)0
-rw-r--r--drivers/net/ethernet/intel/e1000e/phy.c (renamed from drivers/net/e1000e/phy.c)0
-rw-r--r--drivers/net/ethernet/intel/igb/Makefile (renamed from drivers/net/igb/Makefile)0
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_82575.c (renamed from drivers/net/igb/e1000_82575.c)43
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_82575.h (renamed from drivers/net/igb/e1000_82575.h)2
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_defines.h (renamed from drivers/net/igb/e1000_defines.h)4
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_hw.h (renamed from drivers/net/igb/e1000_hw.h)0
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_mac.c (renamed from drivers/net/igb/e1000_mac.c)72
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_mac.h (renamed from drivers/net/igb/e1000_mac.h)1
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_mbx.c (renamed from drivers/net/igb/e1000_mbx.c)2
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_mbx.h (renamed from drivers/net/igb/e1000_mbx.h)0
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_nvm.c (renamed from drivers/net/igb/e1000_nvm.c)0
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_nvm.h (renamed from drivers/net/igb/e1000_nvm.h)0
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_phy.c (renamed from drivers/net/igb/e1000_phy.c)6
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_phy.h (renamed from drivers/net/igb/e1000_phy.h)0
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_regs.h (renamed from drivers/net/igb/e1000_regs.h)1
-rw-r--r--drivers/net/ethernet/intel/igb/igb.h (renamed from drivers/net/igb/igb.h)221
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ethtool.c (renamed from drivers/net/igb/igb_ethtool.c)47
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c (renamed from drivers/net/igb/igb_main.c)2289
-rw-r--r--drivers/net/ethernet/intel/igbvf/Makefile (renamed from drivers/net/igbvf/Makefile)0
-rw-r--r--drivers/net/ethernet/intel/igbvf/defines.h (renamed from drivers/net/igbvf/defines.h)0
-rw-r--r--drivers/net/ethernet/intel/igbvf/ethtool.c (renamed from drivers/net/igbvf/ethtool.c)61
-rw-r--r--drivers/net/ethernet/intel/igbvf/igbvf.h (renamed from drivers/net/igbvf/igbvf.h)0
-rw-r--r--drivers/net/ethernet/intel/igbvf/mbx.c (renamed from drivers/net/igbvf/mbx.c)2
-rw-r--r--drivers/net/ethernet/intel/igbvf/mbx.h (renamed from drivers/net/igbvf/mbx.h)0
-rw-r--r--drivers/net/ethernet/intel/igbvf/netdev.c (renamed from drivers/net/igbvf/netdev.c)56
-rw-r--r--drivers/net/ethernet/intel/igbvf/regs.h (renamed from drivers/net/igbvf/regs.h)0
-rw-r--r--drivers/net/ethernet/intel/igbvf/vf.c (renamed from drivers/net/igbvf/vf.c)0
-rw-r--r--drivers/net/ethernet/intel/igbvf/vf.h (renamed from drivers/net/igbvf/vf.h)0
-rw-r--r--drivers/net/ethernet/intel/ixgb/Makefile (renamed from drivers/net/ixgb/Makefile)0
-rw-r--r--drivers/net/ethernet/intel/ixgb/ixgb.h (renamed from drivers/net/ixgb/ixgb.h)2
-rw-r--r--drivers/net/ethernet/intel/ixgb/ixgb_ee.c (renamed from drivers/net/ixgb/ixgb_ee.c)2
-rw-r--r--drivers/net/ethernet/intel/ixgb/ixgb_ee.h (renamed from drivers/net/ixgb/ixgb_ee.h)4
-rw-r--r--drivers/net/ethernet/intel/ixgb/ixgb_ethtool.c (renamed from drivers/net/ixgb/ixgb_ethtool.c)102
-rw-r--r--drivers/net/ethernet/intel/ixgb/ixgb_hw.c (renamed from drivers/net/ixgb/ixgb_hw.c)2
-rw-r--r--drivers/net/ethernet/intel/ixgb/ixgb_hw.h (renamed from drivers/net/ixgb/ixgb_hw.h)4
-rw-r--r--drivers/net/ethernet/intel/ixgb/ixgb_ids.h (renamed from drivers/net/ixgb/ixgb_ids.h)0
-rw-r--r--drivers/net/ethernet/intel/ixgb/ixgb_main.c (renamed from drivers/net/ixgb/ixgb_main.c)78
-rw-r--r--drivers/net/ethernet/intel/ixgb/ixgb_osdep.h (renamed from drivers/net/ixgb/ixgb_osdep.h)1
-rw-r--r--drivers/net/ethernet/intel/ixgb/ixgb_param.c (renamed from drivers/net/ixgb/ixgb_param.c)18
-rw-r--r--drivers/net/ethernet/intel/ixgbe/Makefile (renamed from drivers/net/ixgbe/Makefile)0
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe.h (renamed from drivers/net/ixgbe/ixgbe.h)87
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c (renamed from drivers/net/ixgbe/ixgbe_82598.c)45
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c (renamed from drivers/net/ixgbe/ixgbe_82599.c)147
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_common.c (renamed from drivers/net/ixgbe/ixgbe_common.c)188
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_common.h (renamed from drivers/net/ixgbe/ixgbe_common.h)2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c (renamed from drivers/net/ixgbe/ixgbe_dcb.c)58
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h (renamed from drivers/net/ixgbe/ixgbe_dcb.h)7
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c (renamed from drivers/net/ixgbe/ixgbe_dcb_82598.c)9
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.h (renamed from drivers/net/ixgbe/ixgbe_dcb_82598.h)0
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c (renamed from drivers/net/ixgbe/ixgbe_dcb_82599.c)56
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h (renamed from drivers/net/ixgbe/ixgbe_dcb_82599.h)2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c (renamed from drivers/net/ixgbe/ixgbe_dcb_nl.c)173
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c (renamed from drivers/net/ixgbe/ixgbe_ethtool.c)307
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c (renamed from drivers/net/ixgbe/ixgbe_fcoe.c)47
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h (renamed from drivers/net/ixgbe/ixgbe_fcoe.h)2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c (renamed from drivers/net/ixgbe/ixgbe_main.c)2304
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c (renamed from drivers/net/ixgbe/ixgbe_mbx.c)2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h (renamed from drivers/net/ixgbe/ixgbe_mbx.h)0
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c (renamed from drivers/net/ixgbe/ixgbe_phy.c)33
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h (renamed from drivers/net/ixgbe/ixgbe_phy.h)0
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c (renamed from drivers/net/ixgbe/ixgbe_sriov.c)255
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h (renamed from drivers/net/ixgbe/ixgbe_sriov.h)6
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_type.h (renamed from drivers/net/ixgbe/ixgbe_type.h)80
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c (renamed from drivers/net/ixgbe/ixgbe_x540.c)92
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/Makefile (renamed from drivers/net/ixgbevf/Makefile)0
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/defines.h (renamed from drivers/net/ixgbevf/defines.h)0
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ethtool.c (renamed from drivers/net/ixgbevf/ethtool.c)50
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ixgbevf.h (renamed from drivers/net/ixgbevf/ixgbevf.h)8
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c (renamed from drivers/net/ixgbevf/ixgbevf_main.c)107
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/mbx.c (renamed from drivers/net/ixgbevf/mbx.c)2
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/mbx.h (renamed from drivers/net/ixgbevf/mbx.h)0
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/regs.h (renamed from drivers/net/ixgbevf/regs.h)0
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/vf.c (renamed from drivers/net/ixgbevf/vf.c)0
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/vf.h (renamed from drivers/net/ixgbevf/vf.h)0
-rw-r--r--drivers/net/ethernet/jme.c (renamed from drivers/net/jme.c)15
-rw-r--r--drivers/net/ethernet/jme.h (renamed from drivers/net/jme.h)1
-rw-r--r--drivers/net/ethernet/korina.c (renamed from drivers/net/korina.c)3
-rw-r--r--drivers/net/ethernet/lantiq_etop.c (renamed from drivers/net/lantiq_etop.c)2
-rw-r--r--drivers/net/ethernet/marvell/Kconfig111
-rw-r--r--drivers/net/ethernet/marvell/Makefile8
-rw-r--r--drivers/net/ethernet/marvell/mv643xx_eth.c (renamed from drivers/net/mv643xx_eth.c)21
-rw-r--r--drivers/net/ethernet/marvell/pxa168_eth.c (renamed from drivers/net/pxa168_eth.c)1
-rw-r--r--drivers/net/ethernet/marvell/skge.c (renamed from drivers/net/skge.c)88
-rw-r--r--drivers/net/ethernet/marvell/skge.h (renamed from drivers/net/skge.h)0
-rw-r--r--drivers/net/ethernet/marvell/sky2.c (renamed from drivers/net/sky2.c)126
-rw-r--r--drivers/net/ethernet/marvell/sky2.h (renamed from drivers/net/sky2.h)0
-rw-r--r--drivers/net/ethernet/mellanox/Kconfig23
-rw-r--r--drivers/net/ethernet/mellanox/Makefile5
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/Kconfig27
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/Makefile (renamed from drivers/net/mlx4/Makefile)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/alloc.c (renamed from drivers/net/mlx4/alloc.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/catas.c (renamed from drivers/net/mlx4/catas.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/cmd.c (renamed from drivers/net/mlx4/cmd.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/cq.c (renamed from drivers/net/mlx4/cq.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_cq.c (renamed from drivers/net/mlx4/en_cq.c)31
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_ethtool.c (renamed from drivers/net/mlx4/en_ethtool.c)14
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_main.c (renamed from drivers/net/mlx4/en_main.c)6
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c (renamed from drivers/net/mlx4/en_netdev.c)116
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_port.c (renamed from drivers/net/mlx4/en_port.c)24
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_port.h (renamed from drivers/net/mlx4/en_port.h)11
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_resources.c (renamed from drivers/net/mlx4/en_resources.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_rx.c (renamed from drivers/net/mlx4/en_rx.c)74
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_selftest.c (renamed from drivers/net/mlx4/en_selftest.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_tx.c (renamed from drivers/net/mlx4/en_tx.c)38
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/eq.c (renamed from drivers/net/mlx4/eq.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/fw.c (renamed from drivers/net/mlx4/fw.c)1
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/fw.h (renamed from drivers/net/mlx4/fw.h)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/icm.c (renamed from drivers/net/mlx4/icm.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/icm.h (renamed from drivers/net/mlx4/icm.h)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/intf.c (renamed from drivers/net/mlx4/intf.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/main.c (renamed from drivers/net/mlx4/main.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mcg.c (renamed from drivers/net/mlx4/mcg.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4.h (renamed from drivers/net/mlx4/mlx4.h)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h (renamed from drivers/net/mlx4/mlx4_en.h)22
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mr.c (renamed from drivers/net/mlx4/mr.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/pd.c (renamed from drivers/net/mlx4/pd.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/port.c (renamed from drivers/net/mlx4/port.c)15
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/profile.c (renamed from drivers/net/mlx4/profile.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/qp.c (renamed from drivers/net/mlx4/qp.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/reset.c (renamed from drivers/net/mlx4/reset.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/sense.c (renamed from drivers/net/mlx4/sense.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/srq.c (renamed from drivers/net/mlx4/srq.c)0
-rw-r--r--drivers/net/ethernet/micrel/Kconfig69
-rw-r--r--drivers/net/ethernet/micrel/Makefile9
-rw-r--r--drivers/net/ethernet/micrel/ks8695net.c (renamed from drivers/net/arm/ks8695net.c)4
-rw-r--r--drivers/net/ethernet/micrel/ks8695net.h (renamed from drivers/net/arm/ks8695net.h)0
-rw-r--r--drivers/net/ethernet/micrel/ks8842.c (renamed from drivers/net/ks8842.c)0
-rw-r--r--drivers/net/ethernet/micrel/ks8851.c (renamed from drivers/net/ks8851.c)0
-rw-r--r--drivers/net/ethernet/micrel/ks8851.h (renamed from drivers/net/ks8851.h)0
-rw-r--r--drivers/net/ethernet/micrel/ks8851_mll.c (renamed from drivers/net/ks8851_mll.c)0
-rw-r--r--drivers/net/ethernet/micrel/ksz884x.c (renamed from drivers/net/ksz884x.c)5
-rw-r--r--drivers/net/ethernet/microchip/Kconfig38
-rw-r--r--drivers/net/ethernet/microchip/Makefile5
-rw-r--r--drivers/net/ethernet/microchip/enc28j60.c (renamed from drivers/net/enc28j60.c)2
-rw-r--r--drivers/net/ethernet/microchip/enc28j60_hw.h (renamed from drivers/net/enc28j60_hw.h)0
-rw-r--r--drivers/net/ethernet/mipsnet.c (renamed from drivers/net/mipsnet.c)2
-rw-r--r--drivers/net/ethernet/myricom/Kconfig47
-rw-r--r--drivers/net/ethernet/myricom/Makefile5
-rw-r--r--drivers/net/ethernet/myricom/myri10ge/Makefile (renamed from drivers/net/myri10ge/Makefile)0
-rw-r--r--drivers/net/ethernet/myricom/myri10ge/myri10ge.c (renamed from drivers/net/myri10ge/myri10ge.c)31
-rw-r--r--drivers/net/ethernet/myricom/myri10ge/myri10ge_mcp.h (renamed from drivers/net/myri10ge/myri10ge_mcp.h)0
-rw-r--r--drivers/net/ethernet/myricom/myri10ge/myri10ge_mcp_gen_header.h (renamed from drivers/net/myri10ge/myri10ge_mcp_gen_header.h)0
-rw-r--r--drivers/net/ethernet/natsemi/Kconfig83
-rw-r--r--drivers/net/ethernet/natsemi/Makefile10
-rw-r--r--drivers/net/ethernet/natsemi/ibmlana.c (renamed from drivers/net/ibmlana.c)2
-rw-r--r--drivers/net/ethernet/natsemi/ibmlana.h (renamed from drivers/net/ibmlana.h)0
-rw-r--r--drivers/net/ethernet/natsemi/jazzsonic.c (renamed from drivers/net/jazzsonic.c)2
-rw-r--r--drivers/net/ethernet/natsemi/macsonic.c (renamed from drivers/net/macsonic.c)11
-rw-r--r--drivers/net/ethernet/natsemi/natsemi.c (renamed from drivers/net/natsemi.c)2
-rw-r--r--drivers/net/ethernet/natsemi/ns83820.c (renamed from drivers/net/ns83820.c)9
-rw-r--r--drivers/net/ethernet/natsemi/sonic.c (renamed from drivers/net/sonic.c)0
-rw-r--r--drivers/net/ethernet/natsemi/sonic.h (renamed from drivers/net/sonic.h)0
-rw-r--r--drivers/net/ethernet/natsemi/xtsonic.c (renamed from drivers/net/xtsonic.c)2
-rw-r--r--drivers/net/ethernet/neterion/Kconfig55
-rw-r--r--drivers/net/ethernet/neterion/Makefile6
-rw-r--r--drivers/net/ethernet/neterion/s2io-regs.h (renamed from drivers/net/s2io-regs.h)0
-rw-r--r--drivers/net/ethernet/neterion/s2io.c (renamed from drivers/net/s2io.c)22
-rw-r--r--drivers/net/ethernet/neterion/s2io.h (renamed from drivers/net/s2io.h)0
-rw-r--r--drivers/net/ethernet/neterion/vxge/Makefile (renamed from drivers/net/vxge/Makefile)0
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-config.c (renamed from drivers/net/vxge/vxge-config.c)11
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-config.h (renamed from drivers/net/vxge/vxge-config.h)4
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-ethtool.c (renamed from drivers/net/vxge/vxge-ethtool.c)0
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-ethtool.h (renamed from drivers/net/vxge/vxge-ethtool.h)0
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-main.c (renamed from drivers/net/vxge/vxge-main.c)30
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-main.h (renamed from drivers/net/vxge/vxge-main.h)0
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-reg.h (renamed from drivers/net/vxge/vxge-reg.h)0
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-traffic.c (renamed from drivers/net/vxge/vxge-traffic.c)12
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-traffic.h (renamed from drivers/net/vxge/vxge-traffic.h)0
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-version.h (renamed from drivers/net/vxge/vxge-version.h)0
-rw-r--r--drivers/net/ethernet/netx-eth.c (renamed from drivers/net/netx-eth.c)2
-rw-r--r--drivers/net/ethernet/nuvoton/Kconfig31
-rw-r--r--drivers/net/ethernet/nuvoton/Makefile5
-rw-r--r--drivers/net/ethernet/nuvoton/w90p910_ether.c (renamed from drivers/net/arm/w90p910_ether.c)2
-rw-r--r--drivers/net/ethernet/nvidia/Kconfig32
-rw-r--r--drivers/net/ethernet/nvidia/Makefile5
-rw-r--r--drivers/net/ethernet/nvidia/forcedeth.c (renamed from drivers/net/forcedeth.c)43
-rw-r--r--drivers/net/ethernet/octeon/Kconfig (renamed from drivers/net/octeon/Kconfig)6
-rw-r--r--drivers/net/ethernet/octeon/Makefile5
-rw-r--r--drivers/net/ethernet/octeon/octeon_mgmt.c (renamed from drivers/net/octeon/octeon_mgmt.c)4
-rw-r--r--drivers/net/ethernet/oki-semi/Kconfig23
-rw-r--r--drivers/net/ethernet/oki-semi/Makefile5
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/Kconfig22
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/Makefile (renamed from drivers/net/pch_gbe/Makefile)0
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h (renamed from drivers/net/pch_gbe/pch_gbe.h)12
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_api.c (renamed from drivers/net/pch_gbe/pch_gbe_api.c)0
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_api.h (renamed from drivers/net/pch_gbe/pch_gbe_api.h)0
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c (renamed from drivers/net/pch_gbe/pch_gbe_ethtool.c)4
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c (renamed from drivers/net/pch_gbe/pch_gbe_main.c)349
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c (renamed from drivers/net/pch_gbe/pch_gbe_param.c)0
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.c (renamed from drivers/net/pch_gbe/pch_gbe_phy.c)0
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.h (renamed from drivers/net/pch_gbe/pch_gbe_phy.h)0
-rw-r--r--drivers/net/ethernet/packetengines/Kconfig47
-rw-r--r--drivers/net/ethernet/packetengines/Makefile6
-rw-r--r--drivers/net/ethernet/packetengines/hamachi.c (renamed from drivers/net/hamachi.c)2
-rw-r--r--drivers/net/ethernet/packetengines/yellowfin.c (renamed from drivers/net/yellowfin.c)2
-rw-r--r--drivers/net/ethernet/pasemi/Kconfig30
-rw-r--r--drivers/net/ethernet/pasemi/Makefile5
-rw-r--r--drivers/net/ethernet/pasemi/pasemi_mac.c (renamed from drivers/net/pasemi_mac.c)15
-rw-r--r--drivers/net/ethernet/pasemi/pasemi_mac.h (renamed from drivers/net/pasemi_mac.h)0
-rw-r--r--drivers/net/ethernet/pasemi/pasemi_mac_ethtool.c (renamed from drivers/net/pasemi_mac_ethtool.c)0
-rw-r--r--drivers/net/ethernet/qlogic/Kconfig54
-rw-r--r--drivers/net/ethernet/qlogic/Makefile8
-rw-r--r--drivers/net/ethernet/qlogic/netxen/Makefile (renamed from drivers/net/netxen/Makefile)0
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic.h (renamed from drivers/net/netxen/netxen_nic.h)10
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c (renamed from drivers/net/netxen/netxen_nic_ctx.c)0
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c (renamed from drivers/net/netxen/netxen_nic_ethtool.c)3
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h (renamed from drivers/net/netxen/netxen_nic_hdr.h)0
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c (renamed from drivers/net/netxen/netxen_nic_hw.c)0
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.h (renamed from drivers/net/netxen/netxen_nic_hw.h)0
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c (renamed from drivers/net/netxen/netxen_nic_init.c)8
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c (renamed from drivers/net/netxen/netxen_nic_main.c)178
-rw-r--r--drivers/net/ethernet/qlogic/qla3xxx.c (renamed from drivers/net/qla3xxx.c)14
-rw-r--r--drivers/net/ethernet/qlogic/qla3xxx.h (renamed from drivers/net/qla3xxx.h)0
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/Makefile (renamed from drivers/net/qlcnic/Makefile)0
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic.h (renamed from drivers/net/qlcnic/qlcnic.h)32
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c (renamed from drivers/net/qlcnic/qlcnic_ctx.c)312
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c (renamed from drivers/net/qlcnic/qlcnic_ethtool.c)56
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h (renamed from drivers/net/qlcnic/qlcnic_hdr.h)4
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c (renamed from drivers/net/qlcnic/qlcnic_hw.c)4
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c (renamed from drivers/net/qlcnic/qlcnic_init.c)21
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c (renamed from drivers/net/qlcnic/qlcnic_main.c)185
-rw-r--r--drivers/net/ethernet/qlogic/qlge/Makefile (renamed from drivers/net/qlge/Makefile)0
-rw-r--r--drivers/net/ethernet/qlogic/qlge/qlge.h (renamed from drivers/net/qlge/qlge.h)0
-rw-r--r--drivers/net/ethernet/qlogic/qlge/qlge_dbg.c (renamed from drivers/net/qlge/qlge_dbg.c)0
-rw-r--r--drivers/net/ethernet/qlogic/qlge/qlge_ethtool.c (renamed from drivers/net/qlge/qlge_ethtool.c)0
-rw-r--r--drivers/net/ethernet/qlogic/qlge/qlge_main.c (renamed from drivers/net/qlge/qlge_main.c)26
-rw-r--r--drivers/net/ethernet/qlogic/qlge/qlge_mpi.c (renamed from drivers/net/qlge/qlge_mpi.c)0
-rw-r--r--drivers/net/ethernet/racal/Kconfig33
-rw-r--r--drivers/net/ethernet/racal/Makefile5
-rw-r--r--drivers/net/ethernet/racal/ni5010.c (renamed from drivers/net/ni5010.c)2
-rw-r--r--drivers/net/ethernet/racal/ni5010.h (renamed from drivers/net/ni5010.h)0
-rw-r--r--drivers/net/ethernet/rdc/Kconfig35
-rw-r--r--drivers/net/ethernet/rdc/Makefile5
-rw-r--r--drivers/net/ethernet/rdc/r6040.c (renamed from drivers/net/r6040.c)10
-rw-r--r--drivers/net/ethernet/realtek/8139cp.c (renamed from drivers/net/8139cp.c)19
-rw-r--r--drivers/net/ethernet/realtek/8139too.c (renamed from drivers/net/8139too.c)2
-rw-r--r--drivers/net/ethernet/realtek/Kconfig130
-rw-r--r--drivers/net/ethernet/realtek/Makefile9
-rw-r--r--drivers/net/ethernet/realtek/atp.c (renamed from drivers/net/atp.c)2
-rw-r--r--drivers/net/ethernet/realtek/atp.h (renamed from drivers/net/atp.h)0
-rw-r--r--drivers/net/ethernet/realtek/r8169.c (renamed from drivers/net/r8169.c)599
-rw-r--r--drivers/net/ethernet/realtek/sc92031.c (renamed from drivers/net/sc92031.c)10
-rw-r--r--drivers/net/ethernet/renesas/Kconfig19
-rw-r--r--drivers/net/ethernet/renesas/Makefile5
-rw-r--r--drivers/net/ethernet/renesas/sh_eth.c (renamed from drivers/net/sh_eth.c)46
-rw-r--r--drivers/net/ethernet/renesas/sh_eth.h (renamed from drivers/net/sh_eth.h)17
-rw-r--r--drivers/net/ethernet/s6gmac.c (renamed from drivers/net/s6gmac.c)0
-rw-r--r--drivers/net/ethernet/seeq/Kconfig47
-rw-r--r--drivers/net/ethernet/seeq/Makefile7
-rw-r--r--drivers/net/ethernet/seeq/ether3.c (renamed from drivers/net/arm/ether3.c)2
-rw-r--r--drivers/net/ethernet/seeq/ether3.h (renamed from drivers/net/arm/ether3.h)0
-rw-r--r--drivers/net/ethernet/seeq/seeq8005.c (renamed from drivers/net/seeq8005.c)2
-rw-r--r--drivers/net/ethernet/seeq/seeq8005.h (renamed from drivers/net/seeq8005.h)0
-rw-r--r--drivers/net/ethernet/seeq/sgiseeq.c (renamed from drivers/net/sgiseeq.c)2
-rw-r--r--drivers/net/ethernet/seeq/sgiseeq.h (renamed from drivers/net/sgiseeq.h)0
-rw-r--r--drivers/net/ethernet/sfc/Kconfig (renamed from drivers/net/sfc/Kconfig)4
-rw-r--r--drivers/net/ethernet/sfc/Makefile (renamed from drivers/net/sfc/Makefile)0
-rw-r--r--drivers/net/ethernet/sfc/bitfield.h (renamed from drivers/net/sfc/bitfield.h)0
-rw-r--r--drivers/net/ethernet/sfc/efx.c (renamed from drivers/net/sfc/efx.c)64
-rw-r--r--drivers/net/ethernet/sfc/efx.h (renamed from drivers/net/sfc/efx.h)7
-rw-r--r--drivers/net/ethernet/sfc/enum.h (renamed from drivers/net/sfc/enum.h)0
-rw-r--r--drivers/net/ethernet/sfc/ethtool.c (renamed from drivers/net/sfc/ethtool.c)111
-rw-r--r--drivers/net/ethernet/sfc/falcon.c (renamed from drivers/net/sfc/falcon.c)2
-rw-r--r--drivers/net/ethernet/sfc/falcon_boards.c (renamed from drivers/net/sfc/falcon_boards.c)0
-rw-r--r--drivers/net/ethernet/sfc/falcon_xmac.c (renamed from drivers/net/sfc/falcon_xmac.c)0
-rw-r--r--drivers/net/ethernet/sfc/filter.c (renamed from drivers/net/sfc/filter.c)0
-rw-r--r--drivers/net/ethernet/sfc/filter.h (renamed from drivers/net/sfc/filter.h)0
-rw-r--r--drivers/net/ethernet/sfc/io.h (renamed from drivers/net/sfc/io.h)6
-rw-r--r--drivers/net/ethernet/sfc/mac.h (renamed from drivers/net/sfc/mac.h)0
-rw-r--r--drivers/net/ethernet/sfc/mcdi.c (renamed from drivers/net/sfc/mcdi.c)46
-rw-r--r--drivers/net/ethernet/sfc/mcdi.h (renamed from drivers/net/sfc/mcdi.h)0
-rw-r--r--drivers/net/ethernet/sfc/mcdi_mac.c (renamed from drivers/net/sfc/mcdi_mac.c)0
-rw-r--r--drivers/net/ethernet/sfc/mcdi_pcol.h (renamed from drivers/net/sfc/mcdi_pcol.h)0
-rw-r--r--drivers/net/ethernet/sfc/mcdi_phy.c (renamed from drivers/net/sfc/mcdi_phy.c)0
-rw-r--r--drivers/net/ethernet/sfc/mdio_10g.c (renamed from drivers/net/sfc/mdio_10g.c)0
-rw-r--r--drivers/net/ethernet/sfc/mdio_10g.h (renamed from drivers/net/sfc/mdio_10g.h)0
-rw-r--r--drivers/net/ethernet/sfc/mtd.c (renamed from drivers/net/sfc/mtd.c)0
-rw-r--r--drivers/net/ethernet/sfc/net_driver.h (renamed from drivers/net/sfc/net_driver.h)0
-rw-r--r--drivers/net/ethernet/sfc/nic.c (renamed from drivers/net/sfc/nic.c)7
-rw-r--r--drivers/net/ethernet/sfc/nic.h (renamed from drivers/net/sfc/nic.h)5
-rw-r--r--drivers/net/ethernet/sfc/phy.h (renamed from drivers/net/sfc/phy.h)0
-rw-r--r--drivers/net/ethernet/sfc/qt202x_phy.c (renamed from drivers/net/sfc/qt202x_phy.c)0
-rw-r--r--drivers/net/ethernet/sfc/regs.h (renamed from drivers/net/sfc/regs.h)0
-rw-r--r--drivers/net/ethernet/sfc/rx.c (renamed from drivers/net/sfc/rx.c)4
-rw-r--r--drivers/net/ethernet/sfc/selftest.c (renamed from drivers/net/sfc/selftest.c)0
-rw-r--r--drivers/net/ethernet/sfc/selftest.h (renamed from drivers/net/sfc/selftest.h)0
-rw-r--r--drivers/net/ethernet/sfc/siena.c (renamed from drivers/net/sfc/siena.c)27
-rw-r--r--drivers/net/ethernet/sfc/spi.h (renamed from drivers/net/sfc/spi.h)0
-rw-r--r--drivers/net/ethernet/sfc/tenxpress.c (renamed from drivers/net/sfc/tenxpress.c)0
-rw-r--r--drivers/net/ethernet/sfc/tx.c (renamed from drivers/net/sfc/tx.c)21
-rw-r--r--drivers/net/ethernet/sfc/txc43128_phy.c (renamed from drivers/net/sfc/txc43128_phy.c)0
-rw-r--r--drivers/net/ethernet/sfc/workarounds.h (renamed from drivers/net/sfc/workarounds.h)2
-rw-r--r--drivers/net/ethernet/sgi/Kconfig36
-rw-r--r--drivers/net/ethernet/sgi/Makefile6
-rw-r--r--drivers/net/ethernet/sgi/ioc3-eth.c (renamed from drivers/net/ioc3-eth.c)2
-rw-r--r--drivers/net/ethernet/sgi/meth.c (renamed from drivers/net/meth.c)0
-rw-r--r--drivers/net/ethernet/sgi/meth.h (renamed from drivers/net/meth.h)0
-rw-r--r--drivers/net/ethernet/sis/Kconfig53
-rw-r--r--drivers/net/ethernet/sis/Makefile6
-rw-r--r--drivers/net/ethernet/sis/sis190.c (renamed from drivers/net/sis190.c)2
-rw-r--r--drivers/net/ethernet/sis/sis900.c (renamed from drivers/net/sis900.c)2
-rw-r--r--drivers/net/ethernet/sis/sis900.h (renamed from drivers/net/sis900.h)0
-rw-r--r--drivers/net/ethernet/smsc/Kconfig136
-rw-r--r--drivers/net/ethernet/smsc/Makefile11
-rw-r--r--drivers/net/ethernet/smsc/epic100.c (renamed from drivers/net/epic100.c)2
-rw-r--r--drivers/net/ethernet/smsc/smc911x.c (renamed from drivers/net/smc911x.c)2
-rw-r--r--drivers/net/ethernet/smsc/smc911x.h (renamed from drivers/net/smc911x.h)0
-rw-r--r--drivers/net/ethernet/smsc/smc9194.c (renamed from drivers/net/smc9194.c)2
-rw-r--r--drivers/net/ethernet/smsc/smc9194.h (renamed from drivers/net/smc9194.h)0
-rw-r--r--drivers/net/ethernet/smsc/smc91c92_cs.c (renamed from drivers/net/pcmcia/smc91c92_cs.c)2
-rw-r--r--drivers/net/ethernet/smsc/smc91x.c (renamed from drivers/net/smc91x.c)2
-rw-r--r--drivers/net/ethernet/smsc/smc91x.h (renamed from drivers/net/smc91x.h)0
-rw-r--r--drivers/net/ethernet/smsc/smsc911x.c (renamed from drivers/net/smsc911x.c)91
-rw-r--r--drivers/net/ethernet/smsc/smsc911x.h (renamed from drivers/net/smsc911x.h)0
-rw-r--r--drivers/net/ethernet/smsc/smsc9420.c (renamed from drivers/net/smsc9420.c)2
-rw-r--r--drivers/net/ethernet/smsc/smsc9420.h (renamed from drivers/net/smsc9420.h)0
-rw-r--r--drivers/net/ethernet/stmicro/Kconfig23
-rw-r--r--drivers/net/ethernet/stmicro/Makefile5
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Kconfig (renamed from drivers/net/stmmac/Kconfig)41
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Makefile (renamed from drivers/net/stmmac/Makefile)5
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/chain_mode.c137
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/common.h (renamed from drivers/net/stmmac/common.h)89
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/descs.h (renamed from drivers/net/stmmac/descs.h)0
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/descs_com.h126
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac100.h (renamed from drivers/net/stmmac/dwmac100.h)0
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000.h (renamed from drivers/net/stmmac/dwmac1000.h)0
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c (renamed from drivers/net/stmmac/dwmac1000_core.c)11
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c (renamed from drivers/net/stmmac/dwmac1000_dma.c)14
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c (renamed from drivers/net/stmmac/dwmac100_core.c)12
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c (renamed from drivers/net/stmmac/dwmac100_dma.c)0
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h (renamed from drivers/net/stmmac/dwmac_dma.h)1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c (renamed from drivers/net/stmmac/dwmac_lib.c)0
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/enh_desc.c (renamed from drivers/net/stmmac/enh_desc.c)22
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/mmc.h131
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/mmc_core.c265
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/norm_desc.c (renamed from drivers/net/stmmac/norm_desc.c)14
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/ring_mode.c126
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h (renamed from drivers/net/stmmac/stmmac.h)8
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c (renamed from drivers/net/stmmac/stmmac_ethtool.c)148
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c (renamed from drivers/net/stmmac/stmmac_main.c)479
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c (renamed from drivers/net/stmmac/stmmac_mdio.c)0
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_timer.c (renamed from drivers/net/stmmac/stmmac_timer.c)0
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_timer.h (renamed from drivers/net/stmmac/stmmac_timer.h)0
-rw-r--r--drivers/net/ethernet/sun/Kconfig88
-rw-r--r--drivers/net/ethernet/sun/Makefile11
-rw-r--r--drivers/net/ethernet/sun/cassini.c (renamed from drivers/net/cassini.c)28
-rw-r--r--drivers/net/ethernet/sun/cassini.h (renamed from drivers/net/cassini.h)0
-rw-r--r--drivers/net/ethernet/sun/niu.c (renamed from drivers/net/niu.c)34
-rw-r--r--drivers/net/ethernet/sun/niu.h (renamed from drivers/net/niu.h)0
-rw-r--r--drivers/net/ethernet/sun/sunbmac.c (renamed from drivers/net/sunbmac.c)33
-rw-r--r--drivers/net/ethernet/sun/sunbmac.h (renamed from drivers/net/sunbmac.h)17
-rw-r--r--drivers/net/ethernet/sun/sungem.c (renamed from drivers/net/sungem.c)16
-rw-r--r--drivers/net/ethernet/sun/sungem.h (renamed from drivers/net/sungem.h)0
-rw-r--r--drivers/net/ethernet/sun/sunhme.c (renamed from drivers/net/sunhme.c)11
-rw-r--r--drivers/net/ethernet/sun/sunhme.h (renamed from drivers/net/sunhme.h)0
-rw-r--r--drivers/net/ethernet/sun/sunqe.c (renamed from drivers/net/sunqe.c)2
-rw-r--r--drivers/net/ethernet/sun/sunqe.h (renamed from drivers/net/sunqe.h)0
-rw-r--r--drivers/net/ethernet/sun/sunvnet.c (renamed from drivers/net/sunvnet.c)2
-rw-r--r--drivers/net/ethernet/sun/sunvnet.h (renamed from drivers/net/sunvnet.h)0
-rw-r--r--drivers/net/ethernet/tehuti/Kconfig27
-rw-r--r--drivers/net/ethernet/tehuti/Makefile5
-rw-r--r--drivers/net/ethernet/tehuti/tehuti.c (renamed from drivers/net/tehuti.c)20
-rw-r--r--drivers/net/ethernet/tehuti/tehuti.h (renamed from drivers/net/tehuti.h)0
-rw-r--r--drivers/net/ethernet/ti/Kconfig77
-rw-r--r--drivers/net/ethernet/ti/Makefile9
-rw-r--r--drivers/net/ethernet/ti/cpmac.c (renamed from drivers/net/cpmac.c)2
-rw-r--r--drivers/net/ethernet/ti/davinci_cpdma.c (renamed from drivers/net/davinci_cpdma.c)0
-rw-r--r--drivers/net/ethernet/ti/davinci_cpdma.h (renamed from drivers/net/davinci_cpdma.h)0
-rw-r--r--drivers/net/ethernet/ti/davinci_emac.c (renamed from drivers/net/davinci_emac.c)2
-rw-r--r--drivers/net/ethernet/ti/davinci_mdio.c (renamed from drivers/net/davinci_mdio.c)0
-rw-r--r--drivers/net/ethernet/ti/tlan.c (renamed from drivers/net/tlan.c)2
-rw-r--r--drivers/net/ethernet/ti/tlan.h (renamed from drivers/net/tlan.h)0
-rw-r--r--drivers/net/ethernet/tile/Kconfig15
-rw-r--r--drivers/net/ethernet/tile/Makefile (renamed from drivers/net/tile/Makefile)0
-rw-r--r--drivers/net/ethernet/tile/tilepro.c (renamed from drivers/net/tile/tilepro.c)4
-rw-r--r--drivers/net/ethernet/toshiba/Kconfig57
-rw-r--r--drivers/net/ethernet/toshiba/Makefile10
-rw-r--r--drivers/net/ethernet/toshiba/ps3_gelic_net.c (renamed from drivers/net/ps3_gelic_net.c)2
-rw-r--r--drivers/net/ethernet/toshiba/ps3_gelic_net.h (renamed from drivers/net/ps3_gelic_net.h)0
-rw-r--r--drivers/net/ethernet/toshiba/ps3_gelic_wireless.c (renamed from drivers/net/ps3_gelic_wireless.c)2
-rw-r--r--drivers/net/ethernet/toshiba/ps3_gelic_wireless.h (renamed from drivers/net/ps3_gelic_wireless.h)0
-rw-r--r--drivers/net/ethernet/toshiba/spider_net.c (renamed from drivers/net/spider_net.c)6
-rw-r--r--drivers/net/ethernet/toshiba/spider_net.h (renamed from drivers/net/spider_net.h)2
-rw-r--r--drivers/net/ethernet/toshiba/spider_net_ethtool.c (renamed from drivers/net/spider_net_ethtool.c)0
-rw-r--r--drivers/net/ethernet/toshiba/tc35815.c (renamed from drivers/net/tc35815.c)2
-rw-r--r--drivers/net/ethernet/tundra/Kconfig29
-rw-r--r--drivers/net/ethernet/tundra/Makefile5
-rw-r--r--drivers/net/ethernet/tundra/tsi108_eth.c (renamed from drivers/net/tsi108_eth.c)13
-rw-r--r--drivers/net/ethernet/tundra/tsi108_eth.h (renamed from drivers/net/tsi108_eth.h)0
-rw-r--r--drivers/net/ethernet/via/Kconfig59
-rw-r--r--drivers/net/ethernet/via/Makefile6
-rw-r--r--drivers/net/ethernet/via/via-rhine.c (renamed from drivers/net/via-rhine.c)2
-rw-r--r--drivers/net/ethernet/via/via-velocity.c (renamed from drivers/net/via-velocity.c)163
-rw-r--r--drivers/net/ethernet/via/via-velocity.h (renamed from drivers/net/via-velocity.h)0
-rw-r--r--drivers/net/ethernet/xilinx/Kconfig36
-rw-r--r--drivers/net/ethernet/xilinx/Makefile7
-rw-r--r--drivers/net/ethernet/xilinx/ll_temac.h (renamed from drivers/net/ll_temac.h)0
-rw-r--r--drivers/net/ethernet/xilinx/ll_temac_main.c (renamed from drivers/net/ll_temac_main.c)35
-rw-r--r--drivers/net/ethernet/xilinx/ll_temac_mdio.c (renamed from drivers/net/ll_temac_mdio.c)0
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_emaclite.c (renamed from drivers/net/xilinx_emaclite.c)0
-rw-r--r--drivers/net/ethernet/xircom/Kconfig31
-rw-r--r--drivers/net/ethernet/xircom/Makefile5
-rw-r--r--drivers/net/ethernet/xircom/xirc2ps_cs.c (renamed from drivers/net/pcmcia/xirc2ps_cs.c)2
-rw-r--r--drivers/net/ethernet/xscale/Kconfig32
-rw-r--r--drivers/net/ethernet/xscale/Makefile6
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/Kconfig (renamed from drivers/net/ixp2000/Kconfig)2
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/Makefile (renamed from drivers/net/ixp2000/Makefile)0
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/caleb.c (renamed from drivers/net/ixp2000/caleb.c)0
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/caleb.h (renamed from drivers/net/ixp2000/caleb.h)0
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/enp2611.c (renamed from drivers/net/ixp2000/enp2611.c)0
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/ixp2400-msf.c (renamed from drivers/net/ixp2000/ixp2400-msf.c)0
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/ixp2400-msf.h (renamed from drivers/net/ixp2000/ixp2400-msf.h)0
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/ixp2400_rx.uc (renamed from drivers/net/ixp2000/ixp2400_rx.uc)0
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/ixp2400_rx.ucode (renamed from drivers/net/ixp2000/ixp2400_rx.ucode)0
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/ixp2400_tx.uc (renamed from drivers/net/ixp2000/ixp2400_tx.uc)0
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/ixp2400_tx.ucode (renamed from drivers/net/ixp2000/ixp2400_tx.ucode)0
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/ixpdev.c (renamed from drivers/net/ixp2000/ixpdev.c)0
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/ixpdev.h (renamed from drivers/net/ixp2000/ixpdev.h)0
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/ixpdev_priv.h (renamed from drivers/net/ixp2000/ixpdev_priv.h)0
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/pm3386.c (renamed from drivers/net/ixp2000/pm3386.c)0
-rw-r--r--drivers/net/ethernet/xscale/ixp2000/pm3386.h (renamed from drivers/net/ixp2000/pm3386.h)0
-rw-r--r--drivers/net/ethernet/xscale/ixp4xx_eth.c (renamed from drivers/net/arm/ixp4xx_eth.c)2
-rw-r--r--drivers/net/fddi/Kconfig77
-rw-r--r--drivers/net/fddi/Makefile6
-rw-r--r--drivers/net/fddi/defxx.c (renamed from drivers/net/defxx.c)2
-rw-r--r--drivers/net/fddi/defxx.h (renamed from drivers/net/defxx.h)0
-rw-r--r--drivers/net/fddi/skfp/Makefile (renamed from drivers/net/skfp/Makefile)0
-rw-r--r--drivers/net/fddi/skfp/cfm.c (renamed from drivers/net/skfp/cfm.c)0
-rw-r--r--drivers/net/fddi/skfp/drvfbi.c (renamed from drivers/net/skfp/drvfbi.c)0
-rw-r--r--drivers/net/fddi/skfp/ecm.c (renamed from drivers/net/skfp/ecm.c)0
-rw-r--r--drivers/net/fddi/skfp/ess.c (renamed from drivers/net/skfp/ess.c)0
-rw-r--r--drivers/net/fddi/skfp/fplustm.c (renamed from drivers/net/skfp/fplustm.c)0
-rw-r--r--drivers/net/fddi/skfp/h/cmtdef.h (renamed from drivers/net/skfp/h/cmtdef.h)4
-rw-r--r--drivers/net/fddi/skfp/h/fddi.h (renamed from drivers/net/skfp/h/fddi.h)0
-rw-r--r--drivers/net/fddi/skfp/h/fddimib.h (renamed from drivers/net/skfp/h/fddimib.h)0
-rw-r--r--drivers/net/fddi/skfp/h/fplustm.h (renamed from drivers/net/skfp/h/fplustm.h)0
-rw-r--r--drivers/net/fddi/skfp/h/hwmtm.h (renamed from drivers/net/skfp/h/hwmtm.h)2
-rw-r--r--drivers/net/fddi/skfp/h/mbuf.h (renamed from drivers/net/skfp/h/mbuf.h)0
-rw-r--r--drivers/net/fddi/skfp/h/osdef1st.h (renamed from drivers/net/skfp/h/osdef1st.h)0
-rw-r--r--drivers/net/fddi/skfp/h/sba.h (renamed from drivers/net/skfp/h/sba.h)4
-rw-r--r--drivers/net/fddi/skfp/h/sba_def.h (renamed from drivers/net/skfp/h/sba_def.h)0
-rw-r--r--drivers/net/fddi/skfp/h/skfbi.h (renamed from drivers/net/skfp/h/skfbi.h)0
-rw-r--r--drivers/net/fddi/skfp/h/skfbiinc.h (renamed from drivers/net/skfp/h/skfbiinc.h)2
-rw-r--r--drivers/net/fddi/skfp/h/smc.h (renamed from drivers/net/skfp/h/smc.h)14
-rw-r--r--drivers/net/fddi/skfp/h/smt.h (renamed from drivers/net/skfp/h/smt.h)0
-rw-r--r--drivers/net/fddi/skfp/h/smt_p.h (renamed from drivers/net/skfp/h/smt_p.h)0
-rw-r--r--drivers/net/fddi/skfp/h/smtstate.h (renamed from drivers/net/skfp/h/smtstate.h)0
-rw-r--r--drivers/net/fddi/skfp/h/supern_2.h (renamed from drivers/net/skfp/h/supern_2.h)0
-rw-r--r--drivers/net/fddi/skfp/h/targethw.h (renamed from drivers/net/skfp/h/targethw.h)6
-rw-r--r--drivers/net/fddi/skfp/h/targetos.h (renamed from drivers/net/skfp/h/targetos.h)2
-rw-r--r--drivers/net/fddi/skfp/h/types.h (renamed from drivers/net/skfp/h/types.h)0
-rw-r--r--drivers/net/fddi/skfp/hwmtm.c (renamed from drivers/net/skfp/hwmtm.c)0
-rw-r--r--drivers/net/fddi/skfp/hwt.c (renamed from drivers/net/skfp/hwt.c)0
-rw-r--r--drivers/net/fddi/skfp/pcmplc.c (renamed from drivers/net/skfp/pcmplc.c)0
-rw-r--r--drivers/net/fddi/skfp/pmf.c (renamed from drivers/net/skfp/pmf.c)0
-rw-r--r--drivers/net/fddi/skfp/queue.c (renamed from drivers/net/skfp/queue.c)0
-rw-r--r--drivers/net/fddi/skfp/rmt.c (renamed from drivers/net/skfp/rmt.c)0
-rw-r--r--drivers/net/fddi/skfp/skfddi.c (renamed from drivers/net/skfp/skfddi.c)2
-rw-r--r--drivers/net/fddi/skfp/smt.c (renamed from drivers/net/skfp/smt.c)0
-rw-r--r--drivers/net/fddi/skfp/smtdef.c (renamed from drivers/net/skfp/smtdef.c)0
-rw-r--r--drivers/net/fddi/skfp/smtinit.c (renamed from drivers/net/skfp/smtinit.c)0
-rw-r--r--drivers/net/fddi/skfp/smttimer.c (renamed from drivers/net/skfp/smttimer.c)0
-rw-r--r--drivers/net/fddi/skfp/srf.c (renamed from drivers/net/skfp/srf.c)0
-rw-r--r--drivers/net/hippi/Kconfig39
-rw-r--r--drivers/net/hippi/Makefile5
-rw-r--r--drivers/net/hippi/rrunner.c (renamed from drivers/net/rrunner.c)0
-rw-r--r--drivers/net/hippi/rrunner.h (renamed from drivers/net/rrunner.h)0
-rw-r--r--drivers/net/ibm_newemac/Makefile11
-rw-r--r--drivers/net/irda/Kconfig2
-rw-r--r--drivers/net/irda/sh_irda.c124
-rw-r--r--drivers/net/macvlan.c10
-rw-r--r--drivers/net/macvtap.c183
-rw-r--r--drivers/net/netconsole.c13
-rw-r--r--drivers/net/octeon/Makefile2
-rw-r--r--drivers/net/pci-skeleton.c1923
-rw-r--r--drivers/net/pcmcia/Kconfig123
-rw-r--r--drivers/net/pcmcia/Makefile16
-rw-r--r--drivers/net/phy/Kconfig2
-rw-r--r--drivers/net/phy/broadcom.c2
-rw-r--r--drivers/net/phy/dp83640.c218
-rw-r--r--drivers/net/phy/icplus.c100
-rw-r--r--drivers/net/phy/mdio-gpio.c2
-rw-r--r--drivers/net/phy/national.c17
-rw-r--r--drivers/net/phy/phy_device.c4
-rw-r--r--drivers/net/phy/vitesse.c34
-rw-r--r--drivers/net/plip/Kconfig38
-rw-r--r--drivers/net/plip/Makefile5
-rw-r--r--drivers/net/plip/plip.c (renamed from drivers/net/plip.c)0
-rw-r--r--drivers/net/ppp/Kconfig175
-rw-r--r--drivers/net/ppp/Makefile13
-rw-r--r--drivers/net/ppp/bsd_comp.c (renamed from drivers/net/bsd_comp.c)0
-rw-r--r--drivers/net/ppp/ppp_async.c (renamed from drivers/net/ppp_async.c)0
-rw-r--r--drivers/net/ppp/ppp_deflate.c (renamed from drivers/net/ppp_deflate.c)0
-rw-r--r--drivers/net/ppp/ppp_generic.c (renamed from drivers/net/ppp_generic.c)7
-rw-r--r--drivers/net/ppp/ppp_mppe.c (renamed from drivers/net/ppp_mppe.c)0
-rw-r--r--drivers/net/ppp/ppp_mppe.h (renamed from drivers/net/ppp_mppe.h)0
-rw-r--r--drivers/net/ppp/ppp_synctty.c (renamed from drivers/net/ppp_synctty.c)0
-rw-r--r--drivers/net/ppp/pppoe.c (renamed from drivers/net/pppoe.c)0
-rw-r--r--drivers/net/ppp/pppox.c (renamed from drivers/net/pppox.c)0
-rw-r--r--drivers/net/ppp/pptp.c (renamed from drivers/net/pptp.c)22
-rw-r--r--drivers/net/rionet.c23
-rw-r--r--drivers/net/slip/Kconfig79
-rw-r--r--drivers/net/slip/Makefile6
-rw-r--r--drivers/net/slip/slhc.c (renamed from drivers/net/slhc.c)0
-rw-r--r--drivers/net/slip/slip.c (renamed from drivers/net/slip.c)29
-rw-r--r--drivers/net/slip/slip.h (renamed from drivers/net/slip.h)9
-rw-r--r--drivers/net/sungem_phy.c7
-rw-r--r--drivers/net/tokenring/3c359.c2
-rw-r--r--drivers/net/tokenring/Kconfig15
-rw-r--r--drivers/net/tokenring/Makefile21
-rw-r--r--drivers/net/tokenring/ibmtr.c2
-rw-r--r--drivers/net/tokenring/ibmtr_cs.c (renamed from drivers/net/pcmcia/ibmtr_cs.c)2
-rw-r--r--drivers/net/tokenring/lanstreamer.c2
-rw-r--r--drivers/net/tokenring/olympic.c2
-rw-r--r--drivers/net/tokenring/smctr.c2
-rw-r--r--drivers/net/tokenring/tms380tr.c2
-rw-r--r--drivers/net/tun.c2
-rw-r--r--drivers/net/usb/Kconfig3
-rw-r--r--drivers/net/usb/asix.c412
-rw-r--r--drivers/net/usb/catc.c2
-rw-r--r--drivers/net/usb/cdc_ncm.c47
-rw-r--r--drivers/net/usb/dm9601.c2
-rw-r--r--drivers/net/usb/int51x1.c2
-rw-r--r--drivers/net/usb/ipheth.c5
-rw-r--r--drivers/net/usb/kaweth.c2
-rw-r--r--drivers/net/usb/lg-vl600.c19
-rw-r--r--drivers/net/usb/mcs7830.c2
-rw-r--r--drivers/net/usb/pegasus.c2
-rw-r--r--drivers/net/usb/rtl8150.c113
-rw-r--r--drivers/net/usb/smsc75xx.c2
-rw-r--r--drivers/net/usb/smsc95xx.c2
-rw-r--r--drivers/net/usb/usbnet.c8
-rw-r--r--drivers/net/virtio_net.c42
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c56
-rw-r--r--drivers/net/vmxnet3/vmxnet3_ethtool.c2
-rw-r--r--drivers/net/wan/hdlc_ppp.c14
-rw-r--r--drivers/net/wan/hdlc_x25.c16
-rw-r--r--drivers/net/wan/lapbether.c3
-rw-r--r--drivers/net/wan/sbni.c2
-rw-r--r--drivers/net/wan/x25_asy.c3
-rw-r--r--drivers/net/wimax/i2400m/usb.c4
-rw-r--r--drivers/net/wireless/Kconfig1
-rw-r--r--drivers/net/wireless/Makefile5
-rw-r--r--drivers/net/wireless/adm8211.c3
-rw-r--r--drivers/net/wireless/airo.c4
-rw-r--r--drivers/net/wireless/at76c50x-usb.c18
-rw-r--r--drivers/net/wireless/ath/Kconfig1
-rw-r--r--drivers/net/wireless/ath/Makefile1
-rw-r--r--drivers/net/wireless/ath/ath.h53
-rw-r--r--drivers/net/wireless/ath/ath5k/ahb.c4
-rw-r--r--drivers/net/wireless/ath/ath5k/ani.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/ani.h4
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h98
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c18
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c37
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h55
-rw-r--r--drivers/net/wireless/ath/ath5k/caps.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.c15
-rw-r--r--drivers/net/wireless/ath/ath5k/desc.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/dma.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.c10
-rw-r--r--drivers/net/wireless/ath/ath5k/gpio.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/initvals.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/led.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/mac80211-ops.c13
-rw-r--r--drivers/net/wireless/ath/ath5k/pci.c4
-rw-r--r--drivers/net/wireless/ath/ath5k/pcu.c5
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c91
-rw-r--r--drivers/net/wireless/ath/ath5k/qcu.c10
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c79
-rw-r--r--drivers/net/wireless/ath/ath5k/rfkill.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/sysfs.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/trace.h3
-rw-r--r--drivers/net/wireless/ath/ath6kl/Kconfig15
-rw-r--r--drivers/net/wireless/ath/ath6kl/Makefile37
-rw-r--r--drivers/net/wireless/ath/ath6kl/bmi.c689
-rw-r--r--drivers/net/wireless/ath/ath6kl/bmi.h250
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c1914
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.h39
-rw-r--r--drivers/net/wireless/ath/ath6kl/common.h97
-rw-r--r--drivers/net/wireless/ath/ath6kl/core.h637
-rw-r--r--drivers/net/wireless/ath/ath6kl/debug.c934
-rw-r--r--drivers/net/wireless/ath/ath6kl/debug.h138
-rw-r--r--drivers/net/wireless/ath/ath6kl/hif-ops.h77
-rw-r--r--drivers/net/wireless/ath/ath6kl/hif.h208
-rw-r--r--drivers/net/wireless/ath/ath6kl/htc.c2478
-rw-r--r--drivers/net/wireless/ath/ath6kl/htc.h607
-rw-r--r--drivers/net/wireless/ath/ath6kl/htc_hif.c641
-rw-r--r--drivers/net/wireless/ath/ath6kl/htc_hif.h92
-rw-r--r--drivers/net/wireless/ath/ath6kl/init.c1727
-rw-r--r--drivers/net/wireless/ath/ath6kl/main.c1477
-rw-r--r--drivers/net/wireless/ath/ath6kl/sdio.c949
-rw-r--r--drivers/net/wireless/ath/ath6kl/target.h364
-rw-r--r--drivers/net/wireless/ath/ath6kl/testmode.c167
-rw-r--r--drivers/net/wireless/ath/ath6kl/testmode.h36
-rw-r--r--drivers/net/wireless/ath/ath6kl/txrx.c1478
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.c3127
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.h2282
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile1
-rw-r--r--drivers/net/wireless/ath/ath9k/ahb.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.c17
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.h6
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_initvals.h131
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_phy.c43
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9001_initvals.h266
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_calib.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_hw.c56
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_initvals.h3403
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_mac.c257
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h206
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_calib.c280
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_eeprom.c312
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_eeprom.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_hw.c610
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mac.c378
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_paprd.c24
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.c125
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.h130
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_rtt.c153
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_rtt.h28
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9462_1p0_initvals.h1833
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h1928
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h1673
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h34
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c80
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.c18
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/common.c32
-rw-r--r--drivers/net/wireless/ath/ath9k/common.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c493
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h68
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.c7
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.h17
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_4k.c272
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_9287.c169
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_def.c241
-rw-r--r--drivers/net/wireless/ath/ath9k/gpio.c15
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_gpio.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c29
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c33
-rw-r--r--drivers/net/wireless/ath/ath9k/hw-ops.h78
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c257
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h83
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c81
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c59
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h57
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c639
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c57
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.c44
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.h6
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c119
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h83
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c894
-rw-r--r--drivers/net/wireless/ath/carl9170/Kconfig14
-rw-r--r--drivers/net/wireless/ath/carl9170/carl9170.h24
-rw-r--r--drivers/net/wireless/ath/carl9170/cmd.c34
-rw-r--r--drivers/net/wireless/ath/carl9170/cmd.h1
-rw-r--r--drivers/net/wireless/ath/carl9170/fw.c3
-rw-r--r--drivers/net/wireless/ath/carl9170/fwcmd.h11
-rw-r--r--drivers/net/wireless/ath/carl9170/main.c240
-rw-r--r--drivers/net/wireless/ath/carl9170/phy.c16
-rw-r--r--drivers/net/wireless/ath/carl9170/version.h4
-rw-r--r--drivers/net/wireless/ath/main.c8
-rw-r--r--drivers/net/wireless/ath/regd.h2
-rw-r--r--drivers/net/wireless/ath/regd_common.h2
-rw-r--r--drivers/net/wireless/b43/Kconfig22
-rw-r--r--drivers/net/wireless/b43/b43.h65
-rw-r--r--drivers/net/wireless/b43/bus.c2
-rw-r--r--drivers/net/wireless/b43/dma.c157
-rw-r--r--drivers/net/wireless/b43/dma.h16
-rw-r--r--drivers/net/wireless/b43/main.c136
-rw-r--r--drivers/net/wireless/b43/phy_common.c32
-rw-r--r--drivers/net/wireless/b43/phy_common.h2
-rw-r--r--drivers/net/wireless/b43/phy_ht.c205
-rw-r--r--drivers/net/wireless/b43/phy_ht.h19
-rw-r--r--drivers/net/wireless/b43/phy_lcn.c853
-rw-r--r--drivers/net/wireless/b43/phy_lcn.h19
-rw-r--r--drivers/net/wireless/b43/phy_n.c575
-rw-r--r--drivers/net/wireless/b43/phy_n.h4
-rw-r--r--drivers/net/wireless/b43/pio.c12
-rw-r--r--drivers/net/wireless/b43/radio_2055.c1
-rw-r--r--drivers/net/wireless/b43/radio_2056.c2
-rw-r--r--drivers/net/wireless/b43/radio_2056.h26
-rw-r--r--drivers/net/wireless/b43/radio_2059.c2
-rw-r--r--drivers/net/wireless/b43/tables_nphy.c1
-rw-r--r--drivers/net/wireless/b43/tables_phy_ht.c86
-rw-r--r--drivers/net/wireless/b43/tables_phy_ht.h4
-rw-r--r--drivers/net/wireless/b43/tables_phy_lcn.c690
-rw-r--r--drivers/net/wireless/b43/tables_phy_lcn.h18
-rw-r--r--drivers/net/wireless/b43/xmit.c138
-rw-r--r--drivers/net/wireless/b43/xmit.h72
-rw-r--r--drivers/net/wireless/b43legacy/b43legacy.h5
-rw-r--r--drivers/net/wireless/b43legacy/dma.c374
-rw-r--r--drivers/net/wireless/b43legacy/dma.h107
-rw-r--r--drivers/net/wireless/b43legacy/main.c11
-rw-r--r--drivers/net/wireless/brcm80211/Kconfig35
-rw-r--r--drivers/net/wireless/brcm80211/Makefile23
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/Makefile33
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmchip.h32
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c371
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c626
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd.h776
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h57
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c498
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c895
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h58
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c1356
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h60
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c4591
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h252
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c3868
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h375
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/Makefile51
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/aiutils.c2079
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/aiutils.h378
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/ampdu.c1241
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/ampdu.h30
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/antsel.c307
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/antsel.h29
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.c23
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.h92
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/channel.c1591
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/channel.h53
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/d11.h1898
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/dma.c1425
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/dma.h120
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c1696
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h108
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/main.c8775
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/main.h735
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/nicpci.c835
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/nicpci.h82
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/otp.c426
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/otp.h36
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c2988
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_hal.h301
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h1169
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c5154
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.h121
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c28876
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.c308
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.h42
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_radio.h1533
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phyreg_n.h167
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c3250
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.h54
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.c10630
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.h50
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy_shim.c225
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h182
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/pmu.c458
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/pmu.h38
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/pub.h634
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/rate.c514
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/rate.h250
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/scb.h82
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/srom.c1298
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/srom.h34
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/stf.c436
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/stf.h42
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/types.h352
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.c109
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.h58
-rw-r--r--drivers/net/wireless/brcm80211/brcmutil/Makefile28
-rw-r--r--drivers/net/wireless/brcm80211/brcmutil/utils.c386
-rw-r--r--drivers/net/wireless/brcm80211/include/brcm_hw_ids.h59
-rw-r--r--drivers/net/wireless/brcm80211/include/brcmu_utils.h195
-rw-r--r--drivers/net/wireless/brcm80211/include/brcmu_wifi.h239
-rw-r--r--drivers/net/wireless/brcm80211/include/chipcommon.h284
-rw-r--r--drivers/net/wireless/brcm80211/include/defs.h104
-rw-r--r--drivers/net/wireless/brcm80211/include/soc.h90
-rw-r--r--drivers/net/wireless/hostap/hostap_main.c6
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.c25
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c42
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_tx.c2
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-3945-led.c1
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-3945-rs.c14
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-3945.c1
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-4965-led.c1
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-4965-rs.c1
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-4965-tx.c2
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-4965.c1
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-core.c10
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-core.h6
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-hcmd.c2
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-led.c1
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-tx.c4
-rw-r--r--drivers/net/wireless/iwlegacy/iwl3945-base.c9
-rw-r--r--drivers/net/wireless/iwlegacy/iwl4965-base.c11
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig43
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile38
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c58
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-2000.c90
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000-hw.h88
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c104
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c93
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-calib.c133
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c299
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-hw.h32
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-lib.c1120
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c117
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rx.c (renamed from drivers/net/wireless/iwlwifi/iwl-rx.c)302
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rxon.c104
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-sta.c943
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tt.c82
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tt.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c992
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-ucode.c121
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c1504
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.h216
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-bus.h90
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-cfg.h (renamed from drivers/net/wireless/iwlwifi/iwl-6000-hw.h)66
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h62
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c405
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h179
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h18
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h48
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c450
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h556
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-devtrace.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c306
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.h11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fh.h20
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-helpers.h184
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.c192
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.h61
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.c16
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-pci.c72
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c21
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c794
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-shared.h534
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c832
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.h138
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sv-open.c30
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-int-pcie.h82
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h436
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c1435
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c (renamed from drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c)701
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie.c1998
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-rx-pcie.c979
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.c1115
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h278
-rw-r--r--drivers/net/wireless/iwmc3200wifi/cfg80211.c6
-rw-r--r--drivers/net/wireless/libertas/README25
-rw-r--r--drivers/net/wireless/libertas/cfg.c120
-rw-r--r--drivers/net/wireless/libertas/cfg.h1
-rw-r--r--drivers/net/wireless/libertas/cmd.c6
-rw-r--r--drivers/net/wireless/libertas/decl.h6
-rw-r--r--drivers/net/wireless/libertas/dev.h30
-rw-r--r--drivers/net/wireless/libertas/ethtool.c1
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c277
-rw-r--r--drivers/net/wireless/libertas/if_spi.c4
-rw-r--r--drivers/net/wireless/libertas/if_usb.c34
-rw-r--r--drivers/net/wireless/libertas/main.c249
-rw-r--r--drivers/net/wireless/libertas/mesh.c79
-rw-r--r--drivers/net/wireless/libertas/mesh.h27
-rw-r--r--drivers/net/wireless/libertas/rx.c1
-rw-r--r--drivers/net/wireless/libertas/tx.c1
-rw-r--r--drivers/net/wireless/libertas_tf/deb_defs.h2
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c9
-rw-r--r--drivers/net/wireless/mwifiex/11n_aggr.c5
-rw-r--r--drivers/net/wireless/mwifiex/11n_aggr.h1
-rw-r--r--drivers/net/wireless/mwifiex/Kconfig11
-rw-r--r--drivers/net/wireless/mwifiex/Makefile3
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c392
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.h3
-rw-r--r--drivers/net/wireless/mwifiex/cfp.c10
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c37
-rw-r--r--drivers/net/wireless/mwifiex/decl.h9
-rw-r--r--drivers/net/wireless/mwifiex/fw.h51
-rw-r--r--drivers/net/wireless/mwifiex/init.c96
-rw-r--r--drivers/net/wireless/mwifiex/ioctl.h5
-rw-r--r--drivers/net/wireless/mwifiex/join.c35
-rw-r--r--drivers/net/wireless/mwifiex/main.c282
-rw-r--r--drivers/net/wireless/mwifiex/main.h107
-rw-r--r--drivers/net/wireless/mwifiex/pcie.c1948
-rw-r--r--drivers/net/wireless/mwifiex/pcie.h148
-rw-r--r--drivers/net/wireless/mwifiex/scan.c1647
-rw-r--r--drivers/net/wireless/mwifiex/sdio.c19
-rw-r--r--drivers/net/wireless/mwifiex/sdio.h24
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c64
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmdresp.c2
-rw-r--r--drivers/net/wireless/mwifiex/sta_event.c9
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c295
-rw-r--r--drivers/net/wireless/mwifiex/sta_tx.c2
-rw-r--r--drivers/net/wireless/mwifiex/txrx.c45
-rw-r--r--drivers/net/wireless/mwifiex/util.c5
-rw-r--r--drivers/net/wireless/mwifiex/util.h9
-rw-r--r--drivers/net/wireless/mwifiex/wmm.c36
-rw-r--r--drivers/net/wireless/mwl8k.c16
-rw-r--r--drivers/net/wireless/orinoco/main.c2
-rw-r--r--drivers/net/wireless/orinoco/orinoco_usb.c2
-rw-r--r--drivers/net/wireless/orinoco/wext.c1
-rw-r--r--drivers/net/wireless/p54/eeprom.c26
-rw-r--r--drivers/net/wireless/p54/fwio.c2
-rw-r--r--drivers/net/wireless/p54/main.c116
-rw-r--r--drivers/net/wireless/p54/p54.h18
-rw-r--r--drivers/net/wireless/p54/p54spi.c2
-rw-r--r--drivers/net/wireless/p54/txrx.c72
-rw-r--r--drivers/net/wireless/ray_cs.c2
-rw-r--r--drivers/net/wireless/rndis_wlan.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c49
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c42
-rw-r--r--drivers/net/wireless/rt2x00/rt2800.h3
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c245
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.h10
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c61
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c25
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h33
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c22
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c53
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c7
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.h5
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c31
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c41
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c7
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/dev.c5
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187/dev.c5
-rw-r--r--drivers/net/wireless/rtlwifi/base.c167
-rw-r--r--drivers/net/wireless/rtlwifi/base.h2
-rw-r--r--drivers/net/wireless/rtlwifi/core.c19
-rw-r--r--drivers/net/wireless/rtlwifi/debug.c2
-rw-r--r--drivers/net/wireless/rtlwifi/pci.c62
-rw-r--r--drivers/net/wireless/rtlwifi/pci.h30
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/def.h153
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/sw.c77
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/trx.c116
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/trx.h6
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/def.h4
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/mac.c4
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/mac.h6
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/rf.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/sw.c35
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/trx.c34
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/def.h170
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/hw.c15
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/sw.c63
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/trx.c121
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/trx.h6
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/def.h41
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/hw.c22
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/reg.h1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/sw.c64
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/trx.c169
-rw-r--r--drivers/net/wireless/rtlwifi/usb.c41
-rw-r--r--drivers/net/wireless/rtlwifi/wifi.h54
-rw-r--r--drivers/net/wireless/wl1251/cmd.h2
-rw-r--r--drivers/net/wireless/wl1251/main.c3
-rw-r--r--drivers/net/wireless/wl1251/wl12xx_80211.h2
-rw-r--r--drivers/net/wireless/wl12xx/Kconfig10
-rw-r--r--drivers/net/wireless/wl12xx/Makefile6
-rw-r--r--drivers/net/wireless/wl12xx/acx.c384
-rw-r--r--drivers/net/wireless/wl12xx/acx.h413
-rw-r--r--drivers/net/wireless/wl12xx/boot.c51
-rw-r--r--drivers/net/wireless/wl12xx/boot.h3
-rw-r--r--drivers/net/wireless/wl12xx/cmd.c866
-rw-r--r--drivers/net/wireless/wl12xx/cmd.h354
-rw-r--r--drivers/net/wireless/wl12xx/conf.h387
-rw-r--r--drivers/net/wireless/wl12xx/debugfs.c105
-rw-r--r--drivers/net/wireless/wl12xx/event.c56
-rw-r--r--drivers/net/wireless/wl12xx/event.h80
-rw-r--r--drivers/net/wireless/wl12xx/init.c113
-rw-r--r--drivers/net/wireless/wl12xx/io.h1
-rw-r--r--drivers/net/wireless/wl12xx/main.c1344
-rw-r--r--drivers/net/wireless/wl12xx/ps.c12
-rw-r--r--drivers/net/wireless/wl12xx/reg.h75
-rw-r--r--drivers/net/wireless/wl12xx/rx.c69
-rw-r--r--drivers/net/wireless/wl12xx/rx.h18
-rw-r--r--drivers/net/wireless/wl12xx/scan.c200
-rw-r--r--drivers/net/wireless/wl12xx/scan.h31
-rw-r--r--drivers/net/wireless/wl12xx/sdio.c6
-rw-r--r--drivers/net/wireless/wl12xx/sdio_test.c17
-rw-r--r--drivers/net/wireless/wl12xx/spi.c4
-rw-r--r--drivers/net/wireless/wl12xx/testmode.c50
-rw-r--r--drivers/net/wireless/wl12xx/tx.c192
-rw-r--r--drivers/net/wireless/wl12xx/tx.h26
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h174
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx_80211.h27
-rw-r--r--drivers/net/wireless/wl3501_cs.c2
-rw-r--r--drivers/net/wireless/zd1201.c2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c2
-rw-r--r--drivers/net/xen-netback/interface.c4
-rw-r--r--drivers/net/xen-netback/netback.c58
-rw-r--r--drivers/net/xen-netfront.c38
-rw-r--r--drivers/nfc/Kconfig11
-rw-r--r--drivers/nfc/Makefile1
-rw-r--r--drivers/nfc/nfcwilink.c342
-rw-r--r--drivers/nfc/pn533.c21
-rw-r--r--drivers/parisc/sba_iommu.c16
-rw-r--r--drivers/pci/hotplug/pcihp_slot.c4
-rw-r--r--drivers/pci/pci.c6
-rw-r--r--drivers/pci/probe.c59
-rw-r--r--drivers/pci/xen-pcifront.c5
-rw-r--r--drivers/pcmcia/sa1100_simpad.c35
-rw-r--r--drivers/pinctrl/Kconfig43
-rw-r--r--drivers/pinctrl/Makefile8
-rw-r--r--drivers/pinctrl/core.c598
-rw-r--r--drivers/pinctrl/core.h71
-rw-r--r--drivers/pinctrl/pinmux-sirf.c1215
-rw-r--r--drivers/pinctrl/pinmux-u300.c1135
-rw-r--r--drivers/pinctrl/pinmux.c1190
-rw-r--r--drivers/pinctrl/pinmux.h47
-rw-r--r--drivers/platform/x86/Kconfig5
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c2
-rw-r--r--drivers/power/max8997_charger.c1
-rw-r--r--drivers/power/max8998_charger.c1
-rw-r--r--drivers/power/s3c_adc_battery.c1
-rw-r--r--drivers/rapidio/rio-scan.c3
-rw-r--r--drivers/rtc/rtc-ep93xx.c16
-rw-r--r--drivers/rtc/rtc-imxdi.c1
-rw-r--r--drivers/rtc/rtc-lib.c2
-rw-r--r--drivers/rtc/rtc-s3c.c105
-rw-r--r--drivers/rtc/rtc-twl.c60
-rw-r--r--drivers/s390/block/dasd_ioctl.c10
-rw-r--r--drivers/s390/char/sclp_cmd.c6
-rw-r--r--drivers/s390/cio/blacklist.c3
-rw-r--r--drivers/s390/cio/cio.c8
-rw-r--r--drivers/s390/cio/qdio.h38
-rw-r--r--drivers/s390/cio/qdio_debug.c3
-rw-r--r--drivers/s390/cio/qdio_main.c208
-rw-r--r--drivers/s390/cio/qdio_setup.c83
-rw-r--r--drivers/s390/cio/qdio_thinint.c88
-rw-r--r--drivers/s390/net/lcs.c2
-rw-r--r--drivers/s390/net/qeth_core.h50
-rw-r--r--drivers/s390/net/qeth_core_main.c780
-rw-r--r--drivers/s390/net/qeth_l2_main.c4
-rw-r--r--drivers/s390/net/qeth_l3.h4
-rw-r--r--drivers/s390/net/qeth_l3_main.c92
-rw-r--r--drivers/s390/net/qeth_l3_sys.c110
-rw-r--r--drivers/scsi/3w-9xxx.c2
-rw-r--r--drivers/scsi/Kconfig1
-rw-r--r--drivers/scsi/Makefile2
-rw-r--r--drivers/scsi/aacraid/commsup.c2
-rw-r--r--drivers/scsi/aacraid/src.c1
-rw-r--r--drivers/scsi/aic7xxx/Kconfig.aic79xx3
-rw-r--r--drivers/scsi/aic7xxx/Kconfig.aic7xxx3
-rw-r--r--drivers/scsi/aic94xx/aic94xx_dump.c2
-rw-r--r--drivers/scsi/bfa/bfad_drv.h1
-rw-r--r--drivers/scsi/bnx2fc/Kconfig3
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc.h4
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_fcoe.c6
-rw-r--r--drivers/scsi/bnx2i/Kconfig3
-rw-r--r--drivers/scsi/bnx2i/bnx2i.h2
-rw-r--r--drivers/scsi/bnx2i/bnx2i_hwi.c2
-rw-r--r--drivers/scsi/cxgbi/cxgb3i/Kbuild2
-rw-r--r--drivers/scsi/cxgbi/cxgb3i/Kconfig3
-rw-r--r--drivers/scsi/cxgbi/cxgb3i/cxgb3i.c3
-rw-r--r--drivers/scsi/cxgbi/cxgb4i/Kbuild2
-rw-r--r--drivers/scsi/cxgbi/cxgb4i/Kconfig3
-rw-r--r--drivers/scsi/cxgbi/cxgb4i/cxgb4i.c1
-rw-r--r--drivers/scsi/cxgbi/libcxgbi.c22
-rw-r--r--drivers/scsi/cxgbi/libcxgbi.h2
-rw-r--r--drivers/scsi/fcoe/fcoe.c20
-rw-r--r--drivers/scsi/fcoe/fcoe_transport.c7
-rw-r--r--drivers/scsi/hpsa.c57
-rw-r--r--drivers/scsi/isci/host.c13
-rw-r--r--drivers/scsi/isci/host.h3
-rw-r--r--drivers/scsi/isci/init.c47
-rw-r--r--drivers/scsi/isci/phy.c15
-rw-r--r--drivers/scsi/isci/registers.h12
-rw-r--r--drivers/scsi/isci/request.c30
-rw-r--r--drivers/scsi/isci/unsolicited_frame_control.c2
-rw-r--r--drivers/scsi/isci/unsolicited_frame_control.h2
-rw-r--r--drivers/scsi/libfc/fc_exch.c59
-rw-r--r--drivers/scsi/libfc/fc_fcp.c11
-rw-r--r--drivers/scsi/libfc/fc_lport.c11
-rw-r--r--drivers/scsi/libsas/sas_expander.c12
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.c2
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c1
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_config.c1
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.c1
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c1
-rw-r--r--drivers/scsi/mvsas/mv_sas.h1
-rw-r--r--drivers/scsi/pmcraid.c1
-rw-r--r--drivers/scsi/pmcraid.h1
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c7
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c36
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h5
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c3
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h29
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c282
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c109
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.c25
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c39
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
-rw-r--r--drivers/scsi/qla4xxx/Kconfig2
-rw-r--r--drivers/scsi/sg.c18
-rw-r--r--drivers/sh/intc/chip.c3
-rw-r--r--drivers/spi/spi-fsl-spi.c3
-rw-r--r--drivers/spi/spi-imx.c4
-rw-r--r--drivers/spi/spi-topcliff-pch.c93
-rw-r--r--drivers/ssb/main.c24
-rw-r--r--drivers/staging/Kconfig4
-rw-r--r--drivers/staging/Makefile5
-rw-r--r--drivers/staging/ath6kl/Kconfig158
-rw-r--r--drivers/staging/ath6kl/Makefile122
-rw-r--r--drivers/staging/ath6kl/TODO25
-rw-r--r--drivers/staging/ath6kl/bmi/include/bmi_internal.h54
-rw-r--r--drivers/staging/ath6kl/bmi/src/bmi.c1010
-rw-r--r--drivers/staging/ath6kl/hif/common/hif_sdio_common.h87
-rw-r--r--drivers/staging/ath6kl/hif/sdio/linux_sdio/include/hif_internal.h131
-rw-r--r--drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c1273
-rw-r--r--drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif_scatter.c393
-rw-r--r--drivers/staging/ath6kl/htc2/AR6000/ar6k.c1479
-rw-r--r--drivers/staging/ath6kl/htc2/AR6000/ar6k.h401
-rw-r--r--drivers/staging/ath6kl/htc2/AR6000/ar6k_events.c783
-rw-r--r--drivers/staging/ath6kl/htc2/AR6000/ar6k_gmbox.c755
-rw-r--r--drivers/staging/ath6kl/htc2/AR6000/ar6k_gmbox_hciuart.c1284
-rw-r--r--drivers/staging/ath6kl/htc2/htc.c575
-rw-r--r--drivers/staging/ath6kl/htc2/htc_debug.h38
-rw-r--r--drivers/staging/ath6kl/htc2/htc_internal.h211
-rw-r--r--drivers/staging/ath6kl/htc2/htc_recv.c1572
-rw-r--r--drivers/staging/ath6kl/htc2/htc_send.c1018
-rw-r--r--drivers/staging/ath6kl/htc2/htc_services.c450
-rw-r--r--drivers/staging/ath6kl/include/a_config.h31
-rw-r--r--drivers/staging/ath6kl/include/a_debug.h195
-rw-r--r--drivers/staging/ath6kl/include/a_drv.h32
-rw-r--r--drivers/staging/ath6kl/include/a_drv_api.h204
-rw-r--r--drivers/staging/ath6kl/include/a_osapi.h32
-rw-r--r--drivers/staging/ath6kl/include/aggr_recv_api.h140
-rw-r--r--drivers/staging/ath6kl/include/ar3kconfig.h65
-rw-r--r--drivers/staging/ath6kl/include/ar6000_api.h32
-rw-r--r--drivers/staging/ath6kl/include/ar6000_diag.h48
-rw-r--r--drivers/staging/ath6kl/include/ar6kap_common.h44
-rw-r--r--drivers/staging/ath6kl/include/athbtfilter.h135
-rw-r--r--drivers/staging/ath6kl/include/bmi.h134
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/AR6K_version.h52
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/addrs.h90
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/apb_athr_wlan_map.h40
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/apb_map.h40
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/mbox_host_reg.h24
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/mbox_reg.h552
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/mbox_wlan_host_reg.h471
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/mbox_wlan_reg.h589
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/rtc_reg.h187
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/rtc_wlan_reg.h162
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/uart_reg.h40
-rw-r--r--drivers/staging/ath6kl/include/common/athdefs.h75
-rw-r--r--drivers/staging/ath6kl/include/common/bmi_msg.h233
-rw-r--r--drivers/staging/ath6kl/include/common/cnxmgmt.h36
-rw-r--r--drivers/staging/ath6kl/include/common/dbglog.h126
-rw-r--r--drivers/staging/ath6kl/include/common/dbglog_id.h558
-rw-r--r--drivers/staging/ath6kl/include/common/discovery.h75
-rw-r--r--drivers/staging/ath6kl/include/common/epping_test.h111
-rw-r--r--drivers/staging/ath6kl/include/common/gmboxif.h70
-rw-r--r--drivers/staging/ath6kl/include/common/gpio_reg.h9
-rw-r--r--drivers/staging/ath6kl/include/common/htc.h227
-rw-r--r--drivers/staging/ath6kl/include/common/htc_services.h52
-rw-r--r--drivers/staging/ath6kl/include/common/pkt_log.h45
-rw-r--r--drivers/staging/ath6kl/include/common/roaming.h41
-rw-r--r--drivers/staging/ath6kl/include/common/targaddrs.h395
-rw-r--r--drivers/staging/ath6kl/include/common/testcmd.h185
-rw-r--r--drivers/staging/ath6kl/include/common/tlpm.h38
-rw-r--r--drivers/staging/ath6kl/include/common/wlan_defs.h79
-rw-r--r--drivers/staging/ath6kl/include/common/wmi.h3220
-rw-r--r--drivers/staging/ath6kl/include/common/wmix.h271
-rw-r--r--drivers/staging/ath6kl/include/common_drv.h104
-rw-r--r--drivers/staging/ath6kl/include/dbglog_api.h52
-rw-r--r--drivers/staging/ath6kl/include/dl_list.h153
-rw-r--r--drivers/staging/ath6kl/include/dset_api.h65
-rw-r--r--drivers/staging/ath6kl/include/hci_transport_api.h259
-rw-r--r--drivers/staging/ath6kl/include/hif.h456
-rw-r--r--drivers/staging/ath6kl/include/host_version.h52
-rw-r--r--drivers/staging/ath6kl/include/htc_api.h575
-rw-r--r--drivers/staging/ath6kl/include/htc_packet.h227
-rw-r--r--drivers/staging/ath6kl/include/wlan_api.h128
-rw-r--r--drivers/staging/ath6kl/include/wmi_api.h441
-rw-r--r--drivers/staging/ath6kl/miscdrv/ar3kconfig.c565
-rw-r--r--drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c572
-rw-r--r--drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.h75
-rw-r--r--drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c969
-rw-r--r--drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.h113
-rw-r--r--drivers/staging/ath6kl/miscdrv/common_drv.c910
-rw-r--r--drivers/staging/ath6kl/miscdrv/credit_dist.c417
-rw-r--r--drivers/staging/ath6kl/miscdrv/miscdrv.h42
-rw-r--r--drivers/staging/ath6kl/os/linux/ar6000_drv.c6267
-rw-r--r--drivers/staging/ath6kl/os/linux/ar6000_pm.c626
-rw-r--r--drivers/staging/ath6kl/os/linux/ar6000_raw_if.c455
-rw-r--r--drivers/staging/ath6kl/os/linux/cfg80211.c1892
-rw-r--r--drivers/staging/ath6kl/os/linux/export_hci_transport.c124
-rw-r--r--drivers/staging/ath6kl/os/linux/hci_bridge.c1141
-rw-r--r--drivers/staging/ath6kl/os/linux/include/ar6000_drv.h776
-rw-r--r--drivers/staging/ath6kl/os/linux/include/ar6k_pal.h36
-rw-r--r--drivers/staging/ath6kl/os/linux/include/ar6xapi_linux.h190
-rw-r--r--drivers/staging/ath6kl/os/linux/include/athdrv_linux.h1217
-rw-r--r--drivers/staging/ath6kl/os/linux/include/cfg80211.h61
-rw-r--r--drivers/staging/ath6kl/os/linux/include/config_linux.h51
-rw-r--r--drivers/staging/ath6kl/os/linux/include/debug_linux.h50
-rw-r--r--drivers/staging/ath6kl/os/linux/include/export_hci_transport.h76
-rw-r--r--drivers/staging/ath6kl/os/linux/include/ieee80211_ioctl.h177
-rw-r--r--drivers/staging/ath6kl/os/linux/include/osapi_linux.h339
-rw-r--r--drivers/staging/ath6kl/os/linux/include/wlan_config.h108
-rw-r--r--drivers/staging/ath6kl/os/linux/include/wmi_filter_linux.h300
-rw-r--r--drivers/staging/ath6kl/os/linux/netbuf.c231
-rw-r--r--drivers/staging/ath6kl/reorder/aggr_rx_internal.h117
-rw-r--r--drivers/staging/ath6kl/reorder/rcv_aggr.c661
-rw-r--r--drivers/staging/ath6kl/wlan/include/ieee80211.h397
-rw-r--r--drivers/staging/ath6kl/wlan/include/ieee80211_node.h93
-rw-r--r--drivers/staging/ath6kl/wlan/src/wlan_node.c636
-rw-r--r--drivers/staging/ath6kl/wlan/src/wlan_recv_beacon.c199
-rw-r--r--drivers/staging/ath6kl/wlan/src/wlan_utils.c58
-rw-r--r--drivers/staging/ath6kl/wmi/wmi.c6444
-rw-r--r--drivers/staging/ath6kl/wmi/wmi_host.h102
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd_linux.c2
-rw-r--r--drivers/staging/brcm80211/brcmsmac/mac80211_if.c19
-rw-r--r--drivers/staging/brcm80211/brcmsmac/otp.c1
-rw-r--r--drivers/staging/brcm80211/brcmsmac/types.h1
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.c4
-rw-r--r--drivers/staging/cxt1e1/Kconfig3
-rw-r--r--drivers/staging/et131x/et1310_tx.c12
-rw-r--r--drivers/staging/et131x/et131x_netdev.c2
-rw-r--r--drivers/staging/hv/netvsc_drv.c8
-rw-r--r--drivers/staging/iio/addac/adt7316-i2c.c2
-rw-r--r--drivers/staging/iio/dds/ad9832.c2
-rw-r--r--drivers/staging/octeon/ethernet-rgmii.c1
-rw-r--r--drivers/staging/octeon/ethernet-rx.c3
-rw-r--r--drivers/staging/octeon/ethernet-spi.c1
-rw-r--r--drivers/staging/octeon/ethernet.c12
-rw-r--r--drivers/staging/rtl8187se/r8180_core.c2
-rw-r--r--drivers/staging/rtl8192e/r8192E_core.c2
-rw-r--r--drivers/staging/rtl8192u/r8192U_core.c2
-rw-r--r--drivers/staging/slicoss/slicoss.c2
-rw-r--r--drivers/staging/tidspbridge/core/dsp-clock.c1
-rw-r--r--drivers/staging/vt6655/device_main.c2
-rw-r--r--drivers/staging/vt6656/main_usb.c2
-rw-r--r--drivers/staging/winbond/wbusb.c2
-rw-r--r--drivers/staging/wlags49_h2/wl_netdev.c2
-rw-r--r--drivers/staging/wlan-ng/p80211netdev.c2
-rw-r--r--drivers/staging/zcache/tmem.c2
-rw-r--r--drivers/staging/zcache/zcache-main.c10
-rw-r--r--drivers/target/Makefile1
-rw-r--r--drivers/target/iscsi/iscsi_target.c40
-rw-r--r--drivers/target/iscsi/iscsi_target_auth.c34
-rw-r--r--drivers/target/iscsi/iscsi_target_configfs.c4
-rw-r--r--drivers/target/iscsi/iscsi_target_core.h4
-rw-r--r--drivers/target/iscsi/iscsi_target_erl1.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_erl2.c49
-rw-r--r--drivers/target/iscsi/iscsi_target_login.c16
-rw-r--r--drivers/target/iscsi/iscsi_target_nego.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_parameters.c45
-rw-r--r--drivers/target/iscsi/iscsi_target_tmr.c6
-rw-r--r--drivers/target/iscsi/iscsi_target_util.c294
-rw-r--r--drivers/target/iscsi/iscsi_target_util.h1
-rw-r--r--drivers/target/loopback/tcm_loop.c18
-rw-r--r--drivers/target/target_core_alua.c21
-rw-r--r--drivers/target/target_core_cdb.c141
-rw-r--r--drivers/target/target_core_configfs.c16
-rw-r--r--drivers/target/target_core_device.c118
-rw-r--r--drivers/target/target_core_fabric_configfs.c3
-rw-r--r--drivers/target/target_core_fabric_lib.c12
-rw-r--r--drivers/target/target_core_file.c56
-rw-r--r--drivers/target/target_core_file.h4
-rw-r--r--drivers/target/target_core_iblock.c274
-rw-r--r--drivers/target/target_core_iblock.h2
-rw-r--r--drivers/target/target_core_pr.c9
-rw-r--r--drivers/target/target_core_pscsi.c261
-rw-r--r--drivers/target/target_core_pscsi.h1
-rw-r--r--drivers/target/target_core_rd.c43
-rw-r--r--drivers/target/target_core_rd.h2
-rw-r--r--drivers/target/target_core_scdb.c105
-rw-r--r--drivers/target/target_core_scdb.h10
-rw-r--r--drivers/target/target_core_stat.c1
-rw-r--r--drivers/target/target_core_tmr.c251
-rw-r--r--drivers/target/target_core_tpg.c66
-rw-r--r--drivers/target/target_core_transport.c1660
-rw-r--r--drivers/target/target_core_ua.c1
-rw-r--r--drivers/target/tcm_fc/tcm_fc.h12
-rw-r--r--drivers/target/tcm_fc/tfc_cmd.c108
-rw-r--r--drivers/target/tcm_fc/tfc_conf.c26
-rw-r--r--drivers/target/tcm_fc/tfc_io.c63
-rw-r--r--drivers/target/tcm_fc/tfc_sess.c1
-rw-r--r--drivers/tty/Kconfig6
-rw-r--r--drivers/tty/pty.c17
-rw-r--r--drivers/tty/serial/8250.c8
-rw-r--r--drivers/tty/serial/8250_pci.c12
-rw-r--r--drivers/tty/serial/8250_pnp.c3
-rw-r--r--drivers/tty/serial/atmel_serial.c4
-rw-r--r--drivers/tty/serial/lantiq.c4
-rw-r--r--drivers/tty/serial/max3107-aava.c2
-rw-r--r--drivers/tty/serial/max3107.c2
-rw-r--r--drivers/tty/serial/mrst_max3110.c4
-rw-r--r--drivers/tty/serial/omap-serial.c3
-rw-r--r--drivers/tty/serial/pch_uart.c3
-rw-r--r--drivers/tty/serial/samsung.c8
-rw-r--r--drivers/tty/serial/serial_core.c5
-rw-r--r--drivers/tty/serial/sh-sci.c72
-rw-r--r--drivers/tty/serial/ucc_uart.c2
-rw-r--r--drivers/tty/tty_io.c3
-rw-r--r--drivers/uio/uio.c14
-rw-r--r--drivers/uio/uio_pci_generic.c5
-rw-r--r--drivers/uio/uio_pdrv_genirq.c2
-rw-r--r--drivers/usb/Kconfig16
-rw-r--r--drivers/usb/Makefile4
-rw-r--r--drivers/usb/class/cdc-acm.c11
-rw-r--r--drivers/usb/class/cdc-wdm.c8
-rw-r--r--drivers/usb/class/usbtmc.c5
-rw-r--r--drivers/usb/core/config.c111
-rw-r--r--drivers/usb/core/devices.c4
-rw-r--r--drivers/usb/core/devio.c57
-rw-r--r--drivers/usb/core/driver.c25
-rw-r--r--drivers/usb/core/endpoint.c2
-rw-r--r--drivers/usb/core/hcd-pci.c2
-rw-r--r--drivers/usb/core/hcd.c38
-rw-r--r--drivers/usb/core/hub.c326
-rw-r--r--drivers/usb/core/message.c2
-rw-r--r--drivers/usb/core/quirks.c24
-rw-r--r--drivers/usb/core/sysfs.c59
-rw-r--r--drivers/usb/core/urb.c2
-rw-r--r--drivers/usb/core/usb.c1
-rw-r--r--drivers/usb/core/usb.h7
-rw-r--r--drivers/usb/dwc3/Kconfig25
-rw-r--r--drivers/usb/dwc3/Makefile36
-rw-r--r--drivers/usb/dwc3/core.c484
-rw-r--r--drivers/usb/dwc3/core.h768
-rw-r--r--drivers/usb/dwc3/debug.h50
-rw-r--r--drivers/usb/dwc3/debugfs.c441
-rw-r--r--drivers/usb/dwc3/dwc3-omap.c401
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c219
-rw-r--r--drivers/usb/dwc3/ep0.c804
-rw-r--r--drivers/usb/dwc3/gadget.c2104
-rw-r--r--drivers/usb/dwc3/gadget.h211
-rw-r--r--drivers/usb/dwc3/io.h54
-rw-r--r--drivers/usb/gadget/Kconfig47
-rw-r--r--drivers/usb/gadget/Makefile4
-rw-r--r--drivers/usb/gadget/acm_ms.c256
-rw-r--r--drivers/usb/gadget/amd5536udc.c20
-rw-r--r--drivers/usb/gadget/amd5536udc.h9
-rw-r--r--drivers/usb/gadget/at91_udc.c32
-rw-r--r--drivers/usb/gadget/at91_udc.h10
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c13
-rw-r--r--drivers/usb/gadget/cdc2.c9
-rw-r--r--drivers/usb/gadget/ci13xxx_msm.c11
-rw-r--r--drivers/usb/gadget/ci13xxx_udc.c2
-rw-r--r--drivers/usb/gadget/composite.c37
-rw-r--r--drivers/usb/gadget/config.c9
-rw-r--r--drivers/usb/gadget/dbgp.c1
-rw-r--r--drivers/usb/gadget/dummy_hcd.c13
-rw-r--r--drivers/usb/gadget/epautoconf.c12
-rw-r--r--drivers/usb/gadget/ether.c9
-rw-r--r--drivers/usb/gadget/f_audio.c15
-rw-r--r--drivers/usb/gadget/f_ecm.c9
-rw-r--r--drivers/usb/gadget/f_eem.c9
-rw-r--r--drivers/usb/gadget/f_fs.c9
-rw-r--r--drivers/usb/gadget/f_hid.c9
-rw-r--r--drivers/usb/gadget/f_loopback.c9
-rw-r--r--drivers/usb/gadget/f_mass_storage.c196
-rw-r--r--drivers/usb/gadget/f_midi.c998
-rw-r--r--drivers/usb/gadget/f_ncm.c9
-rw-r--r--drivers/usb/gadget/f_obex.c9
-rw-r--r--drivers/usb/gadget/f_phonet.c11
-rw-r--r--drivers/usb/gadget/f_rndis.c9
-rw-r--r--drivers/usb/gadget/f_sourcesink.c9
-rw-r--r--drivers/usb/gadget/f_subset.c9
-rw-r--r--drivers/usb/gadget/f_uvc.c1
-rw-r--r--drivers/usb/gadget/f_uvc.h1
-rw-r--r--drivers/usb/gadget/file_storage.c254
-rw-r--r--drivers/usb/gadget/fsl_qe_udc.c2
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c55
-rw-r--r--drivers/usb/gadget/fusb300_udc.c16
-rw-r--r--drivers/usb/gadget/fusb300_udc.h10
-rw-r--r--drivers/usb/gadget/g_ffs.c9
-rw-r--r--drivers/usb/gadget/gadget_chips.h3
-rw-r--r--drivers/usb/gadget/gmidi.c1292
-rw-r--r--drivers/usb/gadget/hid.c9
-rw-r--r--drivers/usb/gadget/imx_udc.c4
-rw-r--r--drivers/usb/gadget/imx_udc.h5
-rw-r--r--drivers/usb/gadget/inode.c9
-rw-r--r--drivers/usb/gadget/langwell_udc.c149
-rw-r--r--drivers/usb/gadget/langwell_udc.h12
-rw-r--r--drivers/usb/gadget/m66592-udc.c16
-rw-r--r--drivers/usb/gadget/m66592-udc.h10
-rw-r--r--drivers/usb/gadget/mass_storage.c11
-rw-r--r--drivers/usb/gadget/multi.c9
-rw-r--r--drivers/usb/gadget/mv_udc.h26
-rw-r--r--drivers/usb/gadget/mv_udc_core.c564
-rw-r--r--drivers/usb/gadget/mv_udc_phy.c214
-rw-r--r--drivers/usb/gadget/ncm.c9
-rw-r--r--drivers/usb/gadget/ndis.h6
-rw-r--r--drivers/usb/gadget/net2272.c78
-rw-r--r--drivers/usb/gadget/net2280.c89
-rw-r--r--drivers/usb/gadget/net2280.h9
-rw-r--r--drivers/usb/gadget/omap_udc.c18
-rw-r--r--drivers/usb/gadget/pch_udc.c15
-rw-r--r--drivers/usb/gadget/printer.c25
-rw-r--r--drivers/usb/gadget/pxa25x_udc.c30
-rw-r--r--drivers/usb/gadget/pxa25x_udc.h17
-rw-r--r--drivers/usb/gadget/pxa27x_udc.c12
-rw-r--r--drivers/usb/gadget/pxa27x_udc.h9
-rw-r--r--drivers/usb/gadget/r8a66597-udc.c516
-rw-r--r--drivers/usb/gadget/r8a66597-udc.h73
-rw-r--r--drivers/usb/gadget/s3c-hsotg.c10
-rw-r--r--drivers/usb/gadget/s3c-hsudc.c69
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c16
-rw-r--r--drivers/usb/gadget/s3c2410_udc.h10
-rw-r--r--drivers/usb/gadget/storage_common.c185
-rw-r--r--drivers/usb/gadget/u_ether.c9
-rw-r--r--drivers/usb/gadget/u_ether.h9
-rw-r--r--drivers/usb/gadget/u_serial.c3
-rw-r--r--drivers/usb/gadget/udc-core.c21
-rw-r--r--drivers/usb/gadget/uvc.h2
-rw-r--r--drivers/usb/gadget/uvc_queue.c1
-rw-r--r--drivers/usb/gadget/uvc_v4l2.c2
-rw-r--r--drivers/usb/gadget/uvc_video.c1
-rw-r--r--drivers/usb/gadget/webcam.c2
-rw-r--r--drivers/usb/gadget/zero.c9
-rw-r--r--drivers/usb/host/Kconfig28
-rw-r--r--drivers/usb/host/Makefile3
-rw-r--r--drivers/usb/host/ehci-ath79.c2
-rw-r--r--drivers/usb/host/ehci-au1xxx.c4
-rw-r--r--drivers/usb/host/ehci-dbg.c19
-rw-r--r--drivers/usb/host/ehci-fsl.c6
-rw-r--r--drivers/usb/host/ehci-hcd.c64
-rw-r--r--drivers/usb/host/ehci-hub.c17
-rw-r--r--drivers/usb/host/ehci-mxc.c2
-rw-r--r--drivers/usb/host/ehci-octeon.c2
-rw-r--r--drivers/usb/host/ehci-omap.c2
-rw-r--r--drivers/usb/host/ehci-orion.c2
-rw-r--r--drivers/usb/host/ehci-pci.c7
-rw-r--r--drivers/usb/host/ehci-ps3.c2
-rw-r--r--drivers/usb/host/ehci-pxa168.c363
-rw-r--r--drivers/usb/host/ehci-q.c31
-rw-r--r--drivers/usb/host/ehci-s5p.c5
-rw-r--r--drivers/usb/host/ehci-sched.c41
-rw-r--r--drivers/usb/host/ehci-sh.c2
-rw-r--r--drivers/usb/host/ehci-spear.c2
-rw-r--r--drivers/usb/host/ehci-tegra.c2
-rw-r--r--drivers/usb/host/ehci-vt8500.c2
-rw-r--r--drivers/usb/host/ehci-xls.c161
-rw-r--r--drivers/usb/host/ehci.h24
-rw-r--r--drivers/usb/host/fhci-hcd.c9
-rw-r--r--drivers/usb/host/fhci-sched.c19
-rw-r--r--drivers/usb/host/imx21-hcd.c2
-rw-r--r--drivers/usb/host/isp116x-hcd.c2
-rw-r--r--drivers/usb/host/isp1362-hcd.c8
-rw-r--r--drivers/usb/host/isp1760-hcd.c418
-rw-r--r--drivers/usb/host/isp1760-hcd.h5
-rw-r--r--drivers/usb/host/isp1760-if.c80
-rw-r--r--drivers/usb/host/ohci-ath79.c2
-rw-r--r--drivers/usb/host/ohci-au1xxx.c2
-rw-r--r--drivers/usb/host/ohci-da8xx.c2
-rw-r--r--drivers/usb/host/ohci-ep93xx.c2
-rw-r--r--drivers/usb/host/ohci-hcd.c5
-rw-r--r--drivers/usb/host/ohci-hub.c5
-rw-r--r--drivers/usb/host/ohci-octeon.c2
-rw-r--r--drivers/usb/host/ohci-omap.c4
-rw-r--r--drivers/usb/host/ohci-omap3.c4
-rw-r--r--drivers/usb/host/ohci-pnx4008.c2
-rw-r--r--drivers/usb/host/ohci-pnx8550.c2
-rw-r--r--drivers/usb/host/ohci-ppc-of.c2
-rw-r--r--drivers/usb/host/ohci-ppc-soc.c2
-rw-r--r--drivers/usb/host/ohci-ps3.c2
-rw-r--r--drivers/usb/host/ohci-pxa27x.c2
-rw-r--r--drivers/usb/host/ohci-q.c4
-rw-r--r--drivers/usb/host/ohci-s3c2410.c2
-rw-r--r--drivers/usb/host/ohci-sa1111.c2
-rw-r--r--drivers/usb/host/ohci-sh.c2
-rw-r--r--drivers/usb/host/ohci-sm501.c2
-rw-r--r--drivers/usb/host/ohci-spear.c2
-rw-r--r--drivers/usb/host/ohci-ssb.c2
-rw-r--r--drivers/usb/host/ohci-tmio.c2
-rw-r--r--drivers/usb/host/ohci-xls.c151
-rw-r--r--drivers/usb/host/r8a66597-hcd.c4
-rw-r--r--drivers/usb/host/sl811-hcd.c2
-rw-r--r--drivers/usb/host/uhci-hcd.c66
-rw-r--r--drivers/usb/host/uhci-q.c6
-rw-r--r--drivers/usb/host/xhci-ext-caps.h6
-rw-r--r--drivers/usb/host/xhci-hub.c158
-rw-r--r--drivers/usb/host/xhci-mem.c371
-rw-r--r--drivers/usb/host/xhci-pci.c107
-rw-r--r--drivers/usb/host/xhci-ring.c189
-rw-r--r--drivers/usb/host/xhci.c1179
-rw-r--r--drivers/usb/host/xhci.h187
-rw-r--r--drivers/usb/misc/adutux.c14
-rw-r--r--drivers/usb/misc/ftdi-elan.c2
-rw-r--r--drivers/usb/misc/idmouse.c2
-rw-r--r--drivers/usb/misc/iowarrior.c2
-rw-r--r--drivers/usb/misc/ldusb.c4
-rw-r--r--drivers/usb/misc/legousbtower.c4
-rw-r--r--drivers/usb/misc/usblcd.c129
-rw-r--r--drivers/usb/misc/usbled.c25
-rw-r--r--drivers/usb/misc/usbtest.c31
-rw-r--r--drivers/usb/mon/mon_bin.c2
-rw-r--r--drivers/usb/musb/blackfin.c1
-rw-r--r--drivers/usb/musb/cppi_dma.c26
-rw-r--r--drivers/usb/musb/musb_core.h12
-rw-r--r--drivers/usb/musb/musb_gadget.c77
-rw-r--r--drivers/usb/musb/musb_gadget_ep0.c8
-rw-r--r--drivers/usb/musb/musb_host.c2
-rw-r--r--drivers/usb/musb/musb_regs.h6
-rw-r--r--drivers/usb/musb/musbhsdma.c2
-rw-r--r--drivers/usb/musb/tusb6010.c1
-rw-r--r--drivers/usb/musb/tusb6010_omap.c1
-rw-r--r--drivers/usb/musb/ux500_dma.c38
-rw-r--r--drivers/usb/otg/isp1301_omap.c2
-rw-r--r--drivers/usb/otg/twl6030-usb.c16
-rw-r--r--drivers/usb/renesas_usbhs/Kconfig2
-rw-r--r--drivers/usb/renesas_usbhs/Makefile8
-rw-r--r--drivers/usb/renesas_usbhs/common.c236
-rw-r--r--drivers/usb/renesas_usbhs/common.h60
-rw-r--r--drivers/usb/renesas_usbhs/fifo.c222
-rw-r--r--drivers/usb/renesas_usbhs/fifo.h22
-rw-r--r--drivers/usb/renesas_usbhs/mod.c81
-rw-r--r--drivers/usb/renesas_usbhs/mod.h57
-rw-r--r--drivers/usb/renesas_usbhs/mod_gadget.c130
-rw-r--r--drivers/usb/renesas_usbhs/mod_host.c1312
-rw-r--r--drivers/usb/renesas_usbhs/pipe.c200
-rw-r--r--drivers/usb/renesas_usbhs/pipe.h27
-rw-r--r--drivers/usb/serial/Kconfig1
-rw-r--r--drivers/usb/serial/digi_acceleport.c2
-rw-r--r--drivers/usb/serial/ftdi_sio.c111
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h7
-rw-r--r--drivers/usb/serial/io_edgeport.c4
-rw-r--r--drivers/usb/serial/ipw.c33
-rw-r--r--drivers/usb/serial/mos7720.c1
-rw-r--r--drivers/usb/serial/mos7840.c1
-rw-r--r--drivers/usb/serial/opticon.c2
-rw-r--r--drivers/usb/serial/option.c262
-rw-r--r--drivers/usb/serial/pl2303.c4
-rw-r--r--drivers/usb/serial/pl2303.h5
-rw-r--r--drivers/usb/serial/qcserial.c2
-rw-r--r--drivers/usb/serial/sierra.c2
-rw-r--r--drivers/usb/serial/symbolserial.c2
-rw-r--r--drivers/usb/serial/usb-serial.c8
-rw-r--r--drivers/usb/serial/usb_wwan.c2
-rw-r--r--drivers/usb/storage/Kconfig2
-rw-r--r--drivers/usb/storage/realtek_cr.c117
-rw-r--r--drivers/usb/storage/transport.c34
-rw-r--r--drivers/usb/storage/usb.c16
-rw-r--r--drivers/usb/usb-common.c35
-rw-r--r--drivers/usb/usb-skeleton.c2
-rw-r--r--drivers/usb/wusbcore/wa-hc.c2
-rw-r--r--drivers/uwb/uwb-internal.h1
-rw-r--r--drivers/video/backlight/adp8870_bl.c2
-rw-r--r--drivers/video/backlight/backlight.c2
-rw-r--r--drivers/video/backlight/ep93xx_bl.c2
-rw-r--r--drivers/video/backlight/pwm_bl.c9
-rw-r--r--drivers/video/igafb.c2
-rw-r--r--drivers/virtio/virtio_ring.c10
-rw-r--r--drivers/w1/masters/ds2490.c4
-rw-r--r--drivers/w1/masters/matrox_w1.c4
-rw-r--r--drivers/w1/slaves/w1_ds2408.c2
-rw-r--r--drivers/w1/slaves/w1_smem.c4
-rw-r--r--drivers/w1/slaves/w1_therm.c4
-rw-r--r--drivers/w1/w1.c4
-rw-r--r--drivers/w1/w1.h2
-rw-r--r--drivers/w1/w1_family.c2
-rw-r--r--drivers/w1/w1_family.h2
-rw-r--r--drivers/w1/w1_int.c2
-rw-r--r--drivers/w1/w1_int.h2
-rw-r--r--drivers/w1/w1_io.c2
-rw-r--r--drivers/w1/w1_log.h2
-rw-r--r--drivers/w1/w1_netlink.c2
-rw-r--r--drivers/w1/w1_netlink.h2
-rw-r--r--drivers/watchdog/bcm47xx_wdt.c27
-rw-r--r--drivers/watchdog/hpwdt.c9
-rw-r--r--drivers/watchdog/lantiq_wdt.c8
-rw-r--r--drivers/watchdog/sbc_epx_c3.c2
-rw-r--r--drivers/watchdog/smsc37b787_wdt.c2
-rw-r--r--drivers/watchdog/watchdog_dev.c14
-rw-r--r--drivers/xen/Kconfig10
-rw-r--r--drivers/xen/Makefile4
-rw-r--r--drivers/xen/balloon.c62
-rw-r--r--drivers/xen/events.c87
-rw-r--r--drivers/xen/gntdev.c39
-rw-r--r--drivers/xen/grant-table.c6
-rw-r--r--drivers/xen/pci.c105
-rw-r--r--drivers/xen/swiotlb-xen.c70
-rw-r--r--drivers/xen/xen-pciback/conf_space.c1
-rw-r--r--drivers/xen/xen-pciback/conf_space_header.c5
-rw-r--r--drivers/xen/xen-pciback/conf_space_quirks.c3
-rw-r--r--drivers/xen/xen-pciback/passthrough.c34
-rw-r--r--drivers/xen/xen-pciback/pci_stub.c35
-rw-r--r--drivers/xen/xen-pciback/pciback.h32
-rw-r--r--drivers/xen/xen-pciback/pciback_ops.c1
-rw-r--r--drivers/xen/xen-pciback/vpci.c35
-rw-r--r--drivers/xen/xen-pciback/xenbus.c29
-rw-r--r--drivers/xen/xen-selfballoon.c67
-rw-r--r--drivers/xen/xenbus/xenbus_comms.c4
-rw-r--r--drivers/xen/xenbus/xenbus_probe.c101
-rw-r--r--drivers/xen/xenbus/xenbus_probe_backend.c2
-rw-r--r--drivers/xen/xenbus/xenbus_probe_frontend.c121
-rw-r--r--drivers/xen/xenbus/xenbus_xs.c17
-rw-r--r--drivers/zorro/zorro-driver.c8
-rw-r--r--drivers/zorro/zorro.c7
-rw-r--r--fs/9p/v9fs.c33
-rw-r--r--fs/9p/v9fs_vfs.h6
-rw-r--r--fs/9p/vfs_dir.c14
-rw-r--r--fs/9p/vfs_file.c36
-rw-r--r--fs/9p/vfs_inode.c141
-rw-r--r--fs/9p/vfs_inode_dotl.c86
-rw-r--r--fs/9p/vfs_super.c2
-rw-r--r--fs/attr.c5
-rw-r--r--fs/block_dev.c7
-rw-r--r--fs/btrfs/btrfs_inode.h6
-rw-r--r--fs/btrfs/file-item.c4
-rw-r--r--fs/btrfs/file.c49
-rw-r--r--fs/btrfs/free-space-cache.c4
-rw-r--r--fs/btrfs/inode.c40
-rw-r--r--fs/btrfs/ioctl.c51
-rw-r--r--fs/btrfs/transaction.c4
-rw-r--r--fs/btrfs/xattr.c59
-rw-r--r--fs/ceph/mds_client.c2
-rw-r--r--fs/ceph/super.c4
-rw-r--r--fs/cifs/cifsencrypt.c54
-rw-r--r--fs/cifs/cifsfs.c10
-rw-r--r--fs/cifs/cifssmb.c3
-rw-r--r--fs/cifs/connect.c8
-rw-r--r--fs/cifs/xattr.c40
-rw-r--r--fs/coda/coda_linux.h5
-rw-r--r--fs/compat.c6
-rw-r--r--fs/configfs/inode.c3
-rw-r--r--fs/configfs/item.c2
-rw-r--r--fs/debugfs/inode.c2
-rw-r--r--fs/eventpoll.c2
-rw-r--r--fs/ext2/xattr_security.c34
-rw-r--r--fs/ext3/inode.c4
-rw-r--r--fs/ext3/namei.c3
-rw-r--r--fs/ext3/xattr_security.c36
-rw-r--r--fs/ext4/ext4.h1
-rw-r--r--fs/ext4/inode.c7
-rw-r--r--fs/ext4/namei.c3
-rw-r--r--fs/ext4/page-io.c18
-rw-r--r--fs/ext4/xattr_security.c36
-rw-r--r--fs/fuse/dev.c16
-rw-r--r--fs/fuse/file.c84
-rw-r--r--fs/fuse/fuse_i.h8
-rw-r--r--fs/fuse/inode.c13
-rw-r--r--fs/gfs2/inode.c38
-rw-r--r--fs/gfs2/log.c4
-rw-r--r--fs/gfs2/meta_io.c6
-rw-r--r--fs/gfs2/ops_fstype.c2
-rw-r--r--fs/gfs2/quota.c2
-rw-r--r--fs/hfsplus/super.c15
-rw-r--r--fs/hfsplus/wrapper.c4
-rw-r--r--fs/hugetlbfs/inode.c1
-rw-r--r--fs/inode.c24
-rw-r--r--fs/jffs2/security.c35
-rw-r--r--fs/jfs/xattr.c57
-rw-r--r--fs/lockd/host.c25
-rw-r--r--fs/lockd/svc.c2
-rw-r--r--fs/locks.c225
-rw-r--r--fs/namei.c41
-rw-r--r--fs/namespace.c2
-rw-r--r--fs/nfs/blocklayout/blocklayout.c58
-rw-r--r--fs/nfs/blocklayout/blocklayout.h4
-rw-r--r--fs/nfs/blocklayout/blocklayoutdev.c35
-rw-r--r--fs/nfs/callback.c4
-rw-r--r--fs/nfs/client.c11
-rw-r--r--fs/nfs/delegation.c2
-rw-r--r--fs/nfs/fscache-index.c4
-rw-r--r--fs/nfs/idmap.c25
-rw-r--r--fs/nfs/inode.c16
-rw-r--r--fs/nfs/internal.h10
-rw-r--r--fs/nfs/nfs4_fs.h32
-rw-r--r--fs/nfs/nfs4filelayout.c33
-rw-r--r--fs/nfs/nfs4proc.c113
-rw-r--r--fs/nfs/nfs4renewd.c12
-rw-r--r--fs/nfs/nfs4state.c6
-rw-r--r--fs/nfs/pnfs.c52
-rw-r--r--fs/nfs/pnfs.h5
-rw-r--r--fs/nfs/read.c40
-rw-r--r--fs/nfs/super.c42
-rw-r--r--fs/nfs/unlink.c4
-rw-r--r--fs/nfs/write.c75
-rw-r--r--fs/nfsd/export.c16
-rw-r--r--fs/nfsd/nfs4callback.c20
-rw-r--r--fs/nfsd/nfs4proc.c374
-rw-r--r--fs/nfsd/nfs4recover.c53
-rw-r--r--fs/nfsd/nfs4state.c1794
-rw-r--r--fs/nfsd/nfs4xdr.c380
-rw-r--r--fs/nfsd/nfsctl.c1
-rw-r--r--fs/nfsd/nfsd.h33
-rw-r--r--fs/nfsd/nfsfh.c39
-rw-r--r--fs/nfsd/state.h174
-rw-r--r--fs/nfsd/vfs.c31
-rw-r--r--fs/nfsd/vfs.h29
-rw-r--r--fs/nfsd/xdr4.h28
-rw-r--r--fs/ocfs2/xattr.c38
-rw-r--r--fs/proc/task_mmu.c80
-rw-r--r--fs/quota/quota.c2
-rw-r--r--fs/reiserfs/journal.c9
-rw-r--r--fs/reiserfs/resize.c4
-rw-r--r--fs/reiserfs/xattr_security.c4
-rw-r--r--fs/squashfs/Kconfig6
-rw-r--r--fs/stat.c2
-rw-r--r--fs/sysfs/dir.c182
-rw-r--r--fs/sysfs/file.c56
-rw-r--r--fs/sysfs/inode.c16
-rw-r--r--fs/sysfs/sysfs.h17
-rw-r--r--fs/ubifs/debug.h6
-rw-r--r--fs/xattr.c63
-rw-r--r--fs/xfs/Makefile119
-rw-r--r--fs/xfs/kmem.c (renamed from fs/xfs/linux-2.6/kmem.c)0
-rw-r--r--fs/xfs/kmem.h (renamed from fs/xfs/linux-2.6/kmem.h)7
-rw-r--r--fs/xfs/mrlock.h (renamed from fs/xfs/linux-2.6/mrlock.h)0
-rw-r--r--fs/xfs/time.h (renamed from fs/xfs/linux-2.6/time.h)0
-rw-r--r--fs/xfs/uuid.c (renamed from fs/xfs/support/uuid.c)0
-rw-r--r--fs/xfs/uuid.h (renamed from fs/xfs/support/uuid.h)0
-rw-r--r--fs/xfs/xfs.h3
-rw-r--r--fs/xfs/xfs_acl.c (renamed from fs/xfs/linux-2.6/xfs_acl.c)0
-rw-r--r--fs/xfs/xfs_aops.c (renamed from fs/xfs/linux-2.6/xfs_aops.c)3
-rw-r--r--fs/xfs/xfs_aops.h (renamed from fs/xfs/linux-2.6/xfs_aops.h)0
-rw-r--r--fs/xfs/xfs_buf.c (renamed from fs/xfs/linux-2.6/xfs_buf.c)0
-rw-r--r--fs/xfs/xfs_buf.h (renamed from fs/xfs/linux-2.6/xfs_buf.h)0
-rw-r--r--fs/xfs/xfs_buf_item.c3
-rw-r--r--fs/xfs/xfs_discard.c (renamed from fs/xfs/linux-2.6/xfs_discard.c)0
-rw-r--r--fs/xfs/xfs_discard.h (renamed from fs/xfs/linux-2.6/xfs_discard.h)0
-rw-r--r--fs/xfs/xfs_dquot.c (renamed from fs/xfs/quota/xfs_dquot.c)0
-rw-r--r--fs/xfs/xfs_dquot.h (renamed from fs/xfs/quota/xfs_dquot.h)0
-rw-r--r--fs/xfs/xfs_dquot_item.c (renamed from fs/xfs/quota/xfs_dquot_item.c)10
-rw-r--r--fs/xfs/xfs_dquot_item.h (renamed from fs/xfs/quota/xfs_dquot_item.h)0
-rw-r--r--fs/xfs/xfs_export.c (renamed from fs/xfs/linux-2.6/xfs_export.c)0
-rw-r--r--fs/xfs/xfs_export.h (renamed from fs/xfs/linux-2.6/xfs_export.h)0
-rw-r--r--fs/xfs/xfs_file.c (renamed from fs/xfs/linux-2.6/xfs_file.c)0
-rw-r--r--fs/xfs/xfs_fs_subr.c (renamed from fs/xfs/linux-2.6/xfs_fs_subr.c)0
-rw-r--r--fs/xfs/xfs_globals.c (renamed from fs/xfs/linux-2.6/xfs_globals.c)0
-rw-r--r--fs/xfs/xfs_inode_item.c10
-rw-r--r--fs/xfs/xfs_ioctl.c (renamed from fs/xfs/linux-2.6/xfs_ioctl.c)0
-rw-r--r--fs/xfs/xfs_ioctl.h (renamed from fs/xfs/linux-2.6/xfs_ioctl.h)0
-rw-r--r--fs/xfs/xfs_ioctl32.c (renamed from fs/xfs/linux-2.6/xfs_ioctl32.c)0
-rw-r--r--fs/xfs/xfs_ioctl32.h (renamed from fs/xfs/linux-2.6/xfs_ioctl32.h)0
-rw-r--r--fs/xfs/xfs_iops.c (renamed from fs/xfs/linux-2.6/xfs_iops.c)53
-rw-r--r--fs/xfs/xfs_iops.h (renamed from fs/xfs/linux-2.6/xfs_iops.h)0
-rw-r--r--fs/xfs/xfs_linux.h (renamed from fs/xfs/linux-2.6/xfs_linux.h)29
-rw-r--r--fs/xfs/xfs_message.c (renamed from fs/xfs/linux-2.6/xfs_message.c)0
-rw-r--r--fs/xfs/xfs_message.h (renamed from fs/xfs/linux-2.6/xfs_message.h)0
-rw-r--r--fs/xfs/xfs_qm.c (renamed from fs/xfs/quota/xfs_qm.c)0
-rw-r--r--fs/xfs/xfs_qm.h (renamed from fs/xfs/quota/xfs_qm.h)0
-rw-r--r--fs/xfs/xfs_qm_bhv.c (renamed from fs/xfs/quota/xfs_qm_bhv.c)0
-rw-r--r--fs/xfs/xfs_qm_stats.c (renamed from fs/xfs/quota/xfs_qm_stats.c)0
-rw-r--r--fs/xfs/xfs_qm_stats.h (renamed from fs/xfs/quota/xfs_qm_stats.h)0
-rw-r--r--fs/xfs/xfs_qm_syscalls.c (renamed from fs/xfs/quota/xfs_qm_syscalls.c)0
-rw-r--r--fs/xfs/xfs_quota_priv.h (renamed from fs/xfs/quota/xfs_quota_priv.h)0
-rw-r--r--fs/xfs/xfs_quotaops.c (renamed from fs/xfs/linux-2.6/xfs_quotaops.c)2
-rw-r--r--fs/xfs/xfs_stats.c (renamed from fs/xfs/linux-2.6/xfs_stats.c)0
-rw-r--r--fs/xfs/xfs_stats.h (renamed from fs/xfs/linux-2.6/xfs_stats.h)0
-rw-r--r--fs/xfs/xfs_super.c (renamed from fs/xfs/linux-2.6/xfs_super.c)49
-rw-r--r--fs/xfs/xfs_super.h (renamed from fs/xfs/linux-2.6/xfs_super.h)0
-rw-r--r--fs/xfs/xfs_sync.c (renamed from fs/xfs/linux-2.6/xfs_sync.c)0
-rw-r--r--fs/xfs/xfs_sync.h (renamed from fs/xfs/linux-2.6/xfs_sync.h)0
-rw-r--r--fs/xfs/xfs_sysctl.c (renamed from fs/xfs/linux-2.6/xfs_sysctl.c)0
-rw-r--r--fs/xfs/xfs_sysctl.h (renamed from fs/xfs/linux-2.6/xfs_sysctl.h)0
-rw-r--r--fs/xfs/xfs_trace.c (renamed from fs/xfs/linux-2.6/xfs_trace.c)4
-rw-r--r--fs/xfs/xfs_trace.h (renamed from fs/xfs/linux-2.6/xfs_trace.h)0
-rw-r--r--fs/xfs/xfs_trans.h2
-rw-r--r--fs/xfs/xfs_trans_ail.c83
-rw-r--r--fs/xfs/xfs_trans_dquot.c (renamed from fs/xfs/quota/xfs_trans_dquot.c)0
-rw-r--r--fs/xfs/xfs_trans_priv.h8
-rw-r--r--fs/xfs/xfs_vnode.h (renamed from fs/xfs/linux-2.6/xfs_vnode.h)0
-rw-r--r--fs/xfs/xfs_xattr.c (renamed from fs/xfs/linux-2.6/xfs_xattr.c)0
-rw-r--r--include/asm-generic/fcntl.h5
-rw-r--r--include/asm-generic/unistd.h2
-rw-r--r--include/asm-generic/vmlinux.lds.h1
-rw-r--r--include/linux/atalk.h3
-rw-r--r--include/linux/ax25.h2
-rw-r--r--include/linux/basic_mmio_gpio.h15
-rw-r--r--include/linux/bcma/bcma.h9
-rw-r--r--include/linux/bcma/bcma_driver_chipcommon.h94
-rw-r--r--include/linux/bcma/bcma_driver_mips.h51
-rw-r--r--include/linux/bcma/bcma_soc.h16
-rw-r--r--include/linux/blk_types.h6
-rw-r--r--include/linux/blkdev.h1
-rw-r--r--include/linux/caif/caif_socket.h7
-rw-r--r--include/linux/can.h4
-rw-r--r--include/linux/can/Kbuild1
-rw-r--r--include/linux/can/bcm.h3
-rw-r--r--include/linux/can/core.h2
-rw-r--r--include/linux/can/dev.h1
-rw-r--r--include/linux/can/error.h2
-rw-r--r--include/linux/can/gw.h162
-rw-r--r--include/linux/can/netlink.h2
-rw-r--r--include/linux/can/raw.h2
-rw-r--r--include/linux/capability.h3
-rw-r--r--include/linux/ceph/messenger.h1
-rw-r--r--include/linux/cn_proc.h11
-rw-r--r--include/linux/compat.h1
-rw-r--r--include/linux/connector.h2
-rw-r--r--include/linux/devfreq.h238
-rw-r--r--include/linux/device-mapper.h5
-rw-r--r--include/linux/device.h12
-rw-r--r--include/linux/drbd_tag_magic.h2
-rw-r--r--include/linux/dynamic_debug.h76
-rw-r--r--include/linux/ethtool.h180
-rw-r--r--include/linux/evm.h100
-rw-r--r--include/linux/filter.h2
-rw-r--r--include/linux/freezer.h4
-rw-r--r--include/linux/fs.h15
-rw-r--r--include/linux/fuse.h9
-rw-r--r--include/linux/hid.h3
-rw-r--r--include/linux/ieee80211.h156
-rw-r--r--include/linux/if.h1
-rw-r--r--include/linux/if_ether.h2
-rw-r--r--include/linux/if_link.h10
-rw-r--r--include/linux/if_macvlan.h1
-rw-r--r--include/linux/if_packet.h119
-rw-r--r--include/linux/if_pppol2tp.h2
-rw-r--r--include/linux/if_pppox.h9
-rw-r--r--include/linux/ima.h13
-rw-r--r--include/linux/in.h2
-rw-r--r--include/linux/inet_diag.h3
-rw-r--r--include/linux/integrity.h39
-rw-r--r--include/linux/io-mapping.h2
-rw-r--r--include/linux/ip6_tunnel.h2
-rw-r--r--include/linux/ipx.h2
-rw-r--r--include/linux/irda.h9
-rw-r--r--include/linux/irqdomain.h1
-rw-r--r--include/linux/isdn.h2
-rw-r--r--include/linux/kernel.h2
-rw-r--r--include/linux/kvm.h1
-rw-r--r--include/linux/l2tp.h7
-rw-r--r--include/linux/lapb.h3
-rw-r--r--include/linux/llc.h10
-rw-r--r--include/linux/memcontrol.h19
-rw-r--r--include/linux/mfd/wm831x/core.h12
-rw-r--r--include/linux/mfd/wm831x/pdata.h3
-rw-r--r--include/linux/mfd/wm8400-private.h7
-rw-r--r--include/linux/mfd/wm8994/core.h9
-rw-r--r--include/linux/mfd/wm8994/pdata.h2
-rw-r--r--include/linux/mii.h210
-rw-r--r--include/linux/mlx4/device.h1
-rw-r--r--include/linux/mm_types.h11
-rw-r--r--include/linux/moduleparam.h20
-rw-r--r--include/linux/namei.h3
-rw-r--r--include/linux/net_tstamp.h13
-rw-r--r--include/linux/netdevice.h30
-rw-r--r--include/linux/netfilter/xt_connlimit.h1
-rw-r--r--include/linux/netfilter/xt_conntrack.h1
-rw-r--r--include/linux/netfilter/xt_iprange.h1
-rw-r--r--include/linux/netfilter_arp/arp_tables.h14
-rw-r--r--include/linux/netfilter_decnet.h3
-rw-r--r--include/linux/netfilter_ipv4.h3
-rw-r--r--include/linux/netfilter_ipv4/ip_tables.h20
-rw-r--r--include/linux/netfilter_ipv6.h3
-rw-r--r--include/linux/netfilter_ipv6/ip6_tables.h22
-rw-r--r--include/linux/netlink.h2
-rw-r--r--include/linux/netrom.h2
-rw-r--r--include/linux/nfc.h8
-rw-r--r--include/linux/nfs4.h21
-rw-r--r--include/linux/nfs_fs.h1
-rw-r--r--include/linux/nfs_page.h1
-rw-r--r--include/linux/nfs_xdr.h5
-rw-r--r--include/linux/nfsd/Kbuild2
-rw-r--r--include/linux/nfsd/const.h55
-rw-r--r--include/linux/nfsd/export.h2
-rw-r--r--include/linux/nfsd/nfsfh.h7
-rw-r--r--include/linux/nfsd/syscall.h116
-rw-r--r--include/linux/nl80211.h238
-rw-r--r--include/linux/opp.h12
-rw-r--r--include/linux/pci.h5
-rw-r--r--include/linux/perf_event.h24
-rw-r--r--include/linux/personality.h1
-rw-r--r--include/linux/phonet.h5
-rw-r--r--include/linux/phy.h2
-rw-r--r--include/linux/pinctrl/machine.h107
-rw-r--r--include/linux/pinctrl/pinctrl.h133
-rw-r--r--include/linux/pinctrl/pinmux.h117
-rw-r--r--include/linux/platform_data/dwc3-omap.h47
-rw-r--r--include/linux/platform_data/exynos4_tmu.h83
-rw-r--r--include/linux/platform_data/mv_usb.h50
-rw-r--r--include/linux/platform_data/ntc_thermistor.h2
-rw-r--r--include/linux/platform_device.h48
-rw-r--r--include/linux/pm.h26
-rw-r--r--include/linux/pm_clock.h71
-rw-r--r--include/linux/pm_domain.h26
-rw-r--r--include/linux/pm_qos.h155
-rw-r--r--include/linux/pm_qos_params.h38
-rw-r--r--include/linux/pm_runtime.h42
-rw-r--r--include/linux/ptp_classify.h13
-rw-r--r--include/linux/pwm_backlight.h1
-rw-r--r--include/linux/regmap.h79
-rw-r--r--include/linux/regulator/consumer.h2
-rw-r--r--include/linux/rfkill-gpio.h4
-rw-r--r--include/linux/rio_regs.h18
-rw-r--r--include/linux/rose.h7
-rw-r--r--include/linux/sched.h4
-rw-r--r--include/linux/security.h32
-rw-r--r--include/linux/sh_eth.h (renamed from arch/sh/include/asm/sh_eth.h)2
-rw-r--r--include/linux/skbuff.h263
-rw-r--r--include/linux/snmp.h2
-rw-r--r--include/linux/ssb/ssb.h2
-rw-r--r--include/linux/ssb/ssb_regs.h40
-rw-r--r--include/linux/sungem_phy.h (renamed from drivers/net/sungem_phy.h)2
-rw-r--r--include/linux/sunrpc/clnt.h11
-rw-r--r--include/linux/sunrpc/rpc_pipe_fs.h2
-rw-r--r--include/linux/sunrpc/svc.h32
-rw-r--r--include/linux/suspend.h95
-rw-r--r--include/linux/swap.h6
-rw-r--r--include/linux/syscalls.h3
-rw-r--r--include/linux/sysctl.h2
-rw-r--r--include/linux/sysfs.h1
-rw-r--r--include/linux/tcp.h7
-rw-r--r--include/linux/ti_wilink_st.h27
-rw-r--r--include/linux/tipc_config.h4
-rw-r--r--include/linux/tty.h2
-rw-r--r--include/linux/tty_driver.h3
-rw-r--r--include/linux/uio_driver.h7
-rw-r--r--include/linux/un.h4
-rw-r--r--include/linux/usb.h20
-rw-r--r--include/linux/usb/ch9.h29
-rw-r--r--include/linux/usb/gadget.h4
-rw-r--r--include/linux/usb/hcd.h3
-rw-r--r--include/linux/usb/r8a66597.h60
-rw-r--r--include/linux/usb/renesas_usbhs.h14
-rw-r--r--include/linux/virtio.h5
-rw-r--r--include/linux/writeback.h11
-rw-r--r--include/linux/x25.h3
-rw-r--r--include/linux/xattr.h19
-rw-r--r--include/media/pwc-ioctl.h1
-rw-r--r--include/media/videobuf-dma-sg.h2
-rw-r--r--include/net/9p/9p.h43
-rw-r--r--include/net/9p/client.h8
-rw-r--r--include/net/9p/transport.h10
-rw-r--r--include/net/addrconf.h2
-rw-r--r--include/net/bluetooth/hci.h10
-rw-r--r--include/net/bluetooth/hci_core.h25
-rw-r--r--include/net/bluetooth/l2cap.h11
-rw-r--r--include/net/bluetooth/mgmt.h16
-rw-r--r--include/net/bluetooth/smp.h17
-rw-r--r--include/net/caif/caif_hsi.h37
-rw-r--r--include/net/cfg80211-wext.h55
-rw-r--r--include/net/cfg80211.h390
-rw-r--r--include/net/dcbevent.h18
-rw-r--r--include/net/dcbnl.h3
-rw-r--r--include/net/dst.h9
-rw-r--r--include/net/flow.h25
-rw-r--r--include/net/ieee80211_radiotap.h1
-rw-r--r--include/net/if_inet6.h1
-rw-r--r--include/net/inet_ecn.h8
-rw-r--r--include/net/inet_timewait_sock.h3
-rw-r--r--include/net/ip.h12
-rw-r--r--include/net/ip_vs.h1
-rw-r--r--include/net/iucv/af_iucv.h52
-rw-r--r--include/net/iucv/iucv.h36
-rw-r--r--include/net/lapb.h2
-rw-r--r--include/net/lib80211.h3
-rw-r--r--include/net/mac80211.h294
-rw-r--r--include/net/nfc/nci.h313
-rw-r--r--include/net/nfc/nci_core.h184
-rw-r--r--include/net/nfc/nfc.h (renamed from include/net/nfc.h)11
-rw-r--r--include/net/regulatory.h16
-rw-r--r--include/net/request_sock.h3
-rw-r--r--include/net/sch_generic.h24
-rw-r--r--include/net/scm.h5
-rw-r--r--include/net/sctp/command.h1
-rw-r--r--include/net/sctp/structs.h1
-rw-r--r--include/net/secure_seq.h2
-rw-r--r--include/net/sock.h15
-rw-r--r--include/net/tcp.h93
-rw-r--r--include/net/transp_v6.h1
-rw-r--r--include/net/udplite.h63
-rw-r--r--include/rdma/ib_addr.h6
-rw-r--r--include/sound/pcm.h4
-rw-r--r--include/target/configfs_macros.h4
-rw-r--r--include/target/target_core_base.h71
-rw-r--r--include/target/target_core_fabric_ops.h6
-rw-r--r--include/target/target_core_tmr.h2
-rw-r--r--include/target/target_core_transport.h75
-rw-r--r--include/trace/events/9p.h176
-rw-r--r--include/trace/events/regmap.h136
-rw-r--r--include/trace/events/rpm.h99
-rw-r--r--include/trace/events/writeback.h10
-rw-r--r--include/xen/balloon.h5
-rw-r--r--include/xen/grant_table.h1
-rw-r--r--include/xen/interface/io/xs_wire.h6
-rw-r--r--include/xen/interface/physdev.h34
-rw-r--r--include/xen/page.h12
-rw-r--r--init/main.c23
-rw-r--r--kernel/Makefile2
-rw-r--r--kernel/async.c4
-rw-r--r--kernel/cred.c18
-rw-r--r--kernel/events/core.c67
-rw-r--r--kernel/freezer.c2
-rw-r--r--kernel/futex.c10
-rw-r--r--kernel/irq/chip.c2
-rw-r--r--kernel/irq/irqdomain.c6
-rw-r--r--kernel/irq/manage.c1
-rw-r--r--kernel/kmod.c4
-rw-r--r--kernel/params.c21
-rw-r--r--kernel/posix-cpu-timers.c12
-rw-r--r--kernel/power/Kconfig4
-rw-r--r--kernel/power/Makefile4
-rw-r--r--kernel/power/console.c4
-rw-r--r--kernel/power/hibernate.c53
-rw-r--r--kernel/power/main.c102
-rw-r--r--kernel/power/power.h4
-rw-r--r--kernel/power/process.c30
-rw-r--r--kernel/power/qos.c (renamed from kernel/pm_qos_params.c)273
-rw-r--r--kernel/power/snapshot.c18
-rw-r--r--kernel/power/suspend.c17
-rw-r--r--kernel/power/swap.c818
-rw-r--r--kernel/printk.c2
-rw-r--r--kernel/ptrace.c23
-rw-r--r--kernel/resource.c7
-rw-r--r--kernel/sched.c69
-rw-r--r--kernel/sched_rt.c4
-rw-r--r--kernel/signal.c24
-rw-r--r--kernel/sys.c39
-rw-r--r--kernel/sys_ni.c1
-rw-r--r--kernel/sysctl_binary.c4
-rw-r--r--kernel/sysctl_check.c2
-rw-r--r--kernel/taskstats.c1
-rw-r--r--kernel/time/alarmtimer.c18
-rw-r--r--kernel/trace/Makefile3
-rw-r--r--kernel/trace/rpm-traces.c20
-rw-r--r--kernel/tsacct.c15
-rw-r--r--kernel/workqueue.c7
-rw-r--r--lib/Kconfig.debug44
-rw-r--r--lib/Makefile4
-rw-r--r--lib/dynamic_debug.c174
-rw-r--r--lib/hexdump.c15
-rw-r--r--lib/idr.c2
-rw-r--r--lib/kobject_uevent.c2
-rw-r--r--lib/sha1.c1
-rw-r--r--lib/xz/xz_dec_bcj.c27
-rw-r--r--mm/backing-dev.c30
-rw-r--r--mm/filemap.c6
-rw-r--r--mm/memcontrol.c198
-rw-r--r--mm/mempolicy.c9
-rw-r--r--mm/migrate.c8
-rw-r--r--mm/page-writeback.c15
-rw-r--r--mm/page_cgroup.c3
-rw-r--r--mm/shmem.c4
-rw-r--r--mm/slub.c2
-rw-r--r--mm/vmalloc.c8
-rw-r--r--mm/vmscan.c71
-rw-r--r--mm/vmstat.c4
-rw-r--r--net/802/garp.c4
-rw-r--r--net/802/stp.c4
-rw-r--r--net/8021q/vlan.c2
-rw-r--r--net/8021q/vlan_core.c2
-rw-r--r--net/8021q/vlan_dev.c4
-rw-r--r--net/9p/client.c469
-rw-r--r--net/9p/protocol.c99
-rw-r--r--net/9p/protocol.h4
-rw-r--r--net/9p/trans_common.c53
-rw-r--r--net/9p/trans_common.h21
-rw-r--r--net/9p/trans_virtio.c326
-rw-r--r--net/appletalk/ddp.c5
-rw-r--r--net/atm/br2684.c7
-rw-r--r--net/atm/lec.c2
-rw-r--r--net/batman-adv/Makefile2
-rw-r--r--net/batman-adv/aggregation.c293
-rw-r--r--net/batman-adv/aggregation.h46
-rw-r--r--net/batman-adv/bat_iv_ogm.c1170
-rw-r--r--net/batman-adv/bat_ogm.h35
-rw-r--r--net/batman-adv/bat_sysfs.c2
-rw-r--r--net/batman-adv/bitarray.c6
-rw-r--r--net/batman-adv/gateway_client.c10
-rw-r--r--net/batman-adv/hard-interface.c88
-rw-r--r--net/batman-adv/hard-interface.h1
-rw-r--r--net/batman-adv/hash.h25
-rw-r--r--net/batman-adv/main.c4
-rw-r--r--net/batman-adv/main.h8
-rw-r--r--net/batman-adv/originator.c21
-rw-r--r--net/batman-adv/packet.h19
-rw-r--r--net/batman-adv/routing.c669
-rw-r--r--net/batman-adv/routing.h17
-rw-r--r--net/batman-adv/send.c313
-rw-r--r--net/batman-adv/send.h9
-rw-r--r--net/batman-adv/soft-interface.c44
-rw-r--r--net/batman-adv/translation-table.c206
-rw-r--r--net/batman-adv/translation-table.h21
-rw-r--r--net/batman-adv/types.h5
-rw-r--r--net/batman-adv/unicast.c6
-rw-r--r--net/batman-adv/unicast.h2
-rw-r--r--net/batman-adv/vis.c10
-rw-r--r--net/bluetooth/af_bluetooth.c36
-rw-r--r--net/bluetooth/bnep/bnep.h1
-rw-r--r--net/bluetooth/bnep/core.c18
-rw-r--r--net/bluetooth/bnep/netdev.c2
-rw-r--r--net/bluetooth/cmtp/capi.c3
-rw-r--r--net/bluetooth/cmtp/cmtp.h1
-rw-r--r--net/bluetooth/cmtp/core.c25
-rw-r--r--net/bluetooth/hci_conn.c16
-rw-r--r--net/bluetooth/hci_core.c61
-rw-r--r--net/bluetooth/hci_event.c53
-rw-r--r--net/bluetooth/hci_sock.c18
-rw-r--r--net/bluetooth/hci_sysfs.c2
-rw-r--r--net/bluetooth/hidp/core.c32
-rw-r--r--net/bluetooth/l2cap_core.c279
-rw-r--r--net/bluetooth/l2cap_sock.c34
-rw-r--r--net/bluetooth/mgmt.c212
-rw-r--r--net/bluetooth/rfcomm/core.c22
-rw-r--r--net/bluetooth/rfcomm/sock.c31
-rw-r--r--net/bluetooth/sco.c33
-rw-r--r--net/bluetooth/smp.c421
-rw-r--r--net/bridge/br_device.c7
-rw-r--r--net/bridge/br_fdb.c23
-rw-r--r--net/bridge/br_if.c56
-rw-r--r--net/bridge/br_input.c33
-rw-r--r--net/bridge/br_multicast.c21
-rw-r--r--net/bridge/br_netlink.c1
-rw-r--r--net/bridge/br_private.h8
-rw-r--r--net/bridge/br_sysfs_br.c34
-rw-r--r--net/bridge/netfilter/Kconfig2
-rw-r--r--net/bridge/netfilter/ebtable_broute.c4
-rw-r--r--net/caif/caif_dev.c6
-rw-r--r--net/caif/cfcnfg.c38
-rw-r--r--net/caif/cfctrl.c23
-rw-r--r--net/caif/cfdbgl.c7
-rw-r--r--net/caif/cfdgml.c7
-rw-r--r--net/caif/cffrml.c7
-rw-r--r--net/caif/cfmuxl.c6
-rw-r--r--net/caif/cfrfml.c7
-rw-r--r--net/caif/cfserl.c7
-rw-r--r--net/caif/cfsrvl.c8
-rw-r--r--net/caif/cfutill.c7
-rw-r--r--net/caif/cfveil.c7
-rw-r--r--net/caif/cfvidl.c7
-rw-r--r--net/can/Kconfig11
-rw-r--r--net/can/Makefile3
-rw-r--r--net/can/af_can.c8
-rw-r--r--net/can/af_can.h2
-rw-r--r--net/can/bcm.c55
-rw-r--r--net/can/gw.c957
-rw-r--r--net/can/proc.c2
-rw-r--r--net/can/raw.c2
-rw-r--r--net/ceph/ceph_common.c1
-rw-r--r--net/ceph/messenger.c1
-rw-r--r--net/ceph/msgpool.c40
-rw-r--r--net/ceph/osd_client.c26
-rw-r--r--net/ceph/osdmap.c84
-rw-r--r--net/core/datagram.c24
-rw-r--r--net/core/dev.c347
-rw-r--r--net/core/dev_addr_lists.c4
-rw-r--r--net/core/dst.c15
-rw-r--r--net/core/ethtool.c20
-rw-r--r--net/core/fib_rules.c13
-rw-r--r--net/core/filter.c4
-rw-r--r--net/core/flow.c50
-rw-r--r--net/core/kmap_skb.h2
-rw-r--r--net/core/link_watch.c9
-rw-r--r--net/core/neighbour.c52
-rw-r--r--net/core/net-sysfs.c12
-rw-r--r--net/core/netpoll.c8
-rw-r--r--net/core/pktgen.c25
-rw-r--r--net/core/rtnetlink.c34
-rw-r--r--net/core/scm.c10
-rw-r--r--net/core/secure_seq.c2
-rw-r--r--net/core/skbuff.c196
-rw-r--r--net/core/sock.c23
-rw-r--r--net/core/timestamping.c12
-rw-r--r--net/core/user_dma.c6
-rw-r--r--net/dcb/dcbnl.c30
-rw-r--r--net/dccp/ccids/ccid2.c84
-rw-r--r--net/dccp/ccids/ccid2.h6
-rw-r--r--net/dccp/dccp.h1
-rw-r--r--net/dccp/feat.c202
-rw-r--r--net/dccp/feat.h1
-rw-r--r--net/dccp/proto.c1
-rw-r--r--net/decnet/dn_dev.c6
-rw-r--r--net/dsa/slave.c3
-rw-r--r--net/ethernet/eth.c2
-rw-r--r--net/ieee802154/6lowpan.c891
-rw-r--r--net/ieee802154/6lowpan.h212
-rw-r--r--net/ieee802154/Kconfig6
-rw-r--r--net/ieee802154/Makefile8
-rw-r--r--net/ipv4/af_inet.c9
-rw-r--r--net/ipv4/cipso_ipv4.c2
-rw-r--r--net/ipv4/devinet.c6
-rw-r--r--net/ipv4/fib_semantics.c10
-rw-r--r--net/ipv4/fib_trie.c12
-rw-r--r--net/ipv4/gre.c4
-rw-r--r--net/ipv4/icmp.c5
-rw-r--r--net/ipv4/igmp.c14
-rw-r--r--net/ipv4/inet_diag.c5
-rw-r--r--net/ipv4/inet_lro.c10
-rw-r--r--net/ipv4/inet_timewait_sock.c1
-rw-r--r--net/ipv4/ip_fragment.c40
-rw-r--r--net/ipv4/ip_gre.c2
-rw-r--r--net/ipv4/ip_output.c17
-rw-r--r--net/ipv4/ip_sockglue.c7
-rw-r--r--net/ipv4/ipip.c10
-rw-r--r--net/ipv4/ipmr.c8
-rw-r--r--net/ipv4/netfilter/ip_queue.c12
-rw-r--r--net/ipv4/netfilter/nf_nat_amanda.c4
-rw-r--r--net/ipv4/netfilter/nf_nat_core.c24
-rw-r--r--net/ipv4/netfilter/nf_nat_ftp.c4
-rw-r--r--net/ipv4/netfilter/nf_nat_h323.c36
-rw-r--r--net/ipv4/netfilter/nf_nat_irc.c4
-rw-r--r--net/ipv4/netfilter/nf_nat_pptp.c16
-rw-r--r--net/ipv4/netfilter/nf_nat_sip.c28
-rw-r--r--net/ipv4/netfilter/nf_nat_snmp_basic.c4
-rw-r--r--net/ipv4/netfilter/nf_nat_standalone.c6
-rw-r--r--net/ipv4/netfilter/nf_nat_tftp.c4
-rw-r--r--net/ipv4/proc.c2
-rw-r--r--net/ipv4/route.c53
-rw-r--r--net/ipv4/syncookies.c2
-rw-r--r--net/ipv4/tcp.c97
-rw-r--r--net/ipv4/tcp_input.c250
-rw-r--r--net/ipv4/tcp_ipv4.c117
-rw-r--r--net/ipv4/tcp_minisocks.c5
-rw-r--r--net/ipv4/tcp_output.c152
-rw-r--r--net/ipv4/tcp_timer.c2
-rw-r--r--net/ipv4/udp.c11
-rw-r--r--net/ipv4/xfrm4_policy.c14
-rw-r--r--net/ipv6/addrconf.c85
-rw-r--r--net/ipv6/af_inet6.c1
-rw-r--r--net/ipv6/datagram.c9
-rw-r--r--net/ipv6/exthdrs.c7
-rw-r--r--net/ipv6/icmp.c28
-rw-r--r--net/ipv6/inet6_connection_sock.c9
-rw-r--r--net/ipv6/ip6_fib.c4
-rw-r--r--net/ipv6/ip6_flowlabel.c8
-rw-r--r--net/ipv6/ip6_output.c28
-rw-r--r--net/ipv6/ip6_tunnel.c54
-rw-r--r--net/ipv6/ip6mr.c8
-rw-r--r--net/ipv6/ipv6_sockglue.c13
-rw-r--r--net/ipv6/mcast.c2
-rw-r--r--net/ipv6/ndisc.c42
-rw-r--r--net/ipv6/netfilter/ip6_queue.c12
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c4
-rw-r--r--net/ipv6/raw.c15
-rw-r--r--net/ipv6/reassembly.c4
-rw-r--r--net/ipv6/route.c37
-rw-r--r--net/ipv6/sit.c15
-rw-r--r--net/ipv6/syncookies.c6
-rw-r--r--net/ipv6/tcp_ipv6.c90
-rw-r--r--net/ipv6/udp.c8
-rw-r--r--net/ipv6/xfrm6_output.c56
-rw-r--r--net/irda/irlan/irlan_eth.c2
-rw-r--r--net/irda/irsysctl.c6
-rw-r--r--net/irda/qos.c6
-rw-r--r--net/iucv/Kconfig14
-rw-r--r--net/iucv/af_iucv.c870
-rw-r--r--net/iucv/iucv.c23
-rw-r--r--net/l2tp/l2tp_core.c4
-rw-r--r--net/l2tp/l2tp_ppp.c9
-rw-r--r--net/lapb/lapb_iface.c29
-rw-r--r--net/mac80211/Kconfig25
-rw-r--r--net/mac80211/agg-rx.c25
-rw-r--r--net/mac80211/agg-tx.c64
-rw-r--r--net/mac80211/cfg.c497
-rw-r--r--net/mac80211/debugfs.c71
-rw-r--r--net/mac80211/debugfs_netdev.c59
-rw-r--r--net/mac80211/debugfs_sta.c37
-rw-r--r--net/mac80211/driver-ops.h91
-rw-r--r--net/mac80211/driver-trace.h117
-rw-r--r--net/mac80211/ht.c8
-rw-r--r--net/mac80211/ibss.c16
-rw-r--r--net/mac80211/ieee80211_i.h104
-rw-r--r--net/mac80211/iface.c26
-rw-r--r--net/mac80211/key.c4
-rw-r--r--net/mac80211/main.c29
-rw-r--r--net/mac80211/mesh.c213
-rw-r--r--net/mac80211/mesh.h38
-rw-r--r--net/mac80211/mesh_hwmp.c177
-rw-r--r--net/mac80211/mesh_pathtbl.c481
-rw-r--r--net/mac80211/mesh_plink.c257
-rw-r--r--net/mac80211/mlme.c140
-rw-r--r--net/mac80211/pm.c2
-rw-r--r--net/mac80211/rate.c37
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c13
-rw-r--r--net/mac80211/rx.c199
-rw-r--r--net/mac80211/scan.c6
-rw-r--r--net/mac80211/spectmgmt.c6
-rw-r--r--net/mac80211/sta_info.c977
-rw-r--r--net/mac80211/sta_info.h171
-rw-r--r--net/mac80211/status.c251
-rw-r--r--net/mac80211/tx.c557
-rw-r--r--net/mac80211/util.c280
-rw-r--r--net/mac80211/wme.c20
-rw-r--r--net/mac80211/wme.h3
-rw-r--r--net/mac80211/work.c10
-rw-r--r--net/mac80211/wpa.c3
-rw-r--r--net/netfilter/Kconfig2
-rw-r--r--net/netfilter/core.c4
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c133
-rw-r--r--net/netfilter/ipvs/ip_vs_sync.c6
-rw-r--r--net/netfilter/nf_conntrack_core.c12
-rw-r--r--net/netfilter/nf_conntrack_ecache.c8
-rw-r--r--net/netfilter/nf_conntrack_extend.c4
-rw-r--r--net/netfilter/nf_conntrack_helper.c6
-rw-r--r--net/netfilter/nf_conntrack_netlink.c6
-rw-r--r--net/netfilter/nf_conntrack_pptp.c1
-rw-r--r--net/netfilter/nf_conntrack_proto_gre.c4
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c6
-rw-r--r--net/netfilter/nf_log.c10
-rw-r--r--net/netfilter/nf_queue.c6
-rw-r--r--net/netfilter/nfnetlink.c6
-rw-r--r--net/netfilter/nfnetlink_queue.c4
-rw-r--r--net/netfilter/x_tables.c5
-rw-r--r--net/netfilter/xt_rateest.c9
-rw-r--r--net/netlabel/netlabel_domainhash.c6
-rw-r--r--net/netlabel/netlabel_unlabeled.c6
-rw-r--r--net/netlink/af_netlink.c7
-rw-r--r--net/nfc/Kconfig2
-rw-r--r--net/nfc/Makefile1
-rw-r--r--net/nfc/core.c83
-rw-r--r--net/nfc/nci/Kconfig10
-rw-r--r--net/nfc/nci/Makefile7
-rw-r--r--net/nfc/nci/core.c797
-rw-r--r--net/nfc/nci/data.c247
-rw-r--r--net/nfc/nci/lib.c94
-rw-r--r--net/nfc/nci/ntf.c258
-rw-r--r--net/nfc/nci/rsp.c226
-rw-r--r--net/nfc/netlink.c56
-rw-r--r--net/nfc/nfc.h6
-rw-r--r--net/nfc/rawsock.c13
-rw-r--r--net/packet/af_packet.c992
-rw-r--r--net/phonet/af_phonet.c4
-rw-r--r--net/phonet/pn_dev.c6
-rw-r--r--net/phonet/socket.c6
-rw-r--r--net/rds/Kconfig1
-rw-r--r--net/rds/ib_cm.c6
-rw-r--r--net/rds/ib_rdma.c112
-rw-r--r--net/rds/iw_rdma.c13
-rw-r--r--net/rds/xlist.h80
-rw-r--r--net/rfkill/core.c2
-rw-r--r--net/rfkill/rfkill-gpio.c11
-rw-r--r--net/rfkill/rfkill-regulator.c1
-rw-r--r--net/sched/act_mirred.c3
-rw-r--r--net/sched/cls_flow.c188
-rw-r--r--net/sched/cls_rsvp.h27
-rw-r--r--net/sched/sch_sfb.c13
-rw-r--r--net/sctp/associola.c1
-rw-r--r--net/sctp/outqueue.c4
-rw-r--r--net/sctp/protocol.c2
-rw-r--r--net/sctp/sm_make_chunk.c1
-rw-r--r--net/sctp/sm_sideeffect.c5
-rw-r--r--net/sctp/sm_statefuns.c11
-rw-r--r--net/socket.c14
-rw-r--r--net/sunrpc/addr.c6
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c28
-rw-r--r--net/sunrpc/clnt.c4
-rw-r--r--net/sunrpc/rpc_pipe.c23
-rw-r--r--net/sunrpc/rpcb_clnt.c6
-rw-r--r--net/sunrpc/svc.c33
-rw-r--r--net/sunrpc/svc_xprt.c13
-rw-r--r--net/sunrpc/svcsock.c23
-rw-r--r--net/tipc/bcast.c111
-rw-r--r--net/tipc/bcast.h1
-rw-r--r--net/tipc/bearer.c8
-rw-r--r--net/tipc/bearer.h4
-rw-r--r--net/tipc/config.h1
-rw-r--r--net/tipc/discover.c6
-rw-r--r--net/tipc/eth_media.c32
-rw-r--r--net/tipc/link.c111
-rw-r--r--net/tipc/link.h1
-rw-r--r--net/tipc/name_distr.c35
-rw-r--r--net/tipc/net.c11
-rw-r--r--net/tipc/node.c45
-rw-r--r--net/tipc/node.h10
-rw-r--r--net/tipc/socket.c51
-rw-r--r--net/tipc/subscr.c3
-rw-r--r--net/tipc/subscr.h6
-rw-r--r--net/unix/af_unix.c24
-rw-r--r--net/wireless/core.c9
-rw-r--r--net/wireless/core.h6
-rw-r--r--net/wireless/lib80211.c15
-rw-r--r--net/wireless/lib80211_crypt_ccmp.c2
-rw-r--r--net/wireless/lib80211_crypt_tkip.c4
-rw-r--r--net/wireless/lib80211_crypt_wep.c4
-rw-r--r--net/wireless/mesh.c3
-rw-r--r--net/wireless/mlme.c16
-rw-r--r--net/wireless/nl80211.c408
-rw-r--r--net/wireless/nl80211.h4
-rw-r--r--net/wireless/reg.c48
-rw-r--r--net/wireless/reg.h2
-rw-r--r--net/wireless/scan.c28
-rw-r--r--net/wireless/sme.c17
-rw-r--r--net/wireless/sysfs.c6
-rw-r--r--net/wireless/util.c194
-rw-r--r--net/wireless/wext-compat.c137
-rw-r--r--net/wireless/wext-compat.h8
-rw-r--r--net/wireless/wext-sme.c3
-rw-r--r--net/x25/af_x25.c40
-rw-r--r--net/x25/x25_dev.c6
-rw-r--r--net/x25/x25_facilities.c10
-rw-r--r--net/x25/x25_in.c43
-rw-r--r--net/x25/x25_link.c3
-rw-r--r--net/x25/x25_subr.c14
-rw-r--r--net/xfrm/xfrm_input.c5
-rw-r--r--net/xfrm/xfrm_ipcomp.c13
-rw-r--r--net/xfrm/xfrm_policy.c10
-rw-r--r--net/xfrm/xfrm_replay.c98
-rw-r--r--net/xfrm/xfrm_user.c4
-rwxr-xr-xscripts/checkpatch.pl7
-rwxr-xr-xscripts/get_maintainer.pl2
-rw-r--r--security/Kconfig6
-rw-r--r--security/Makefile4
-rw-r--r--security/apparmor/apparmorfs.c2
-rw-r--r--security/apparmor/ipc.c1
-rw-r--r--security/apparmor/lib.c1
-rw-r--r--security/apparmor/policy_unpack.c12
-rw-r--r--security/apparmor/procattr.c1
-rw-r--r--security/commoncap.c16
-rw-r--r--security/integrity/Kconfig7
-rw-r--r--security/integrity/Makefile12
-rw-r--r--security/integrity/evm/Kconfig13
-rw-r--r--security/integrity/evm/Makefile7
-rw-r--r--security/integrity/evm/evm.h38
-rw-r--r--security/integrity/evm/evm_crypto.c216
-rw-r--r--security/integrity/evm/evm_main.c384
-rw-r--r--security/integrity/evm/evm_posix_acl.c26
-rw-r--r--security/integrity/evm/evm_secfs.c108
-rw-r--r--security/integrity/iint.c172
-rw-r--r--security/integrity/ima/Kconfig1
-rw-r--r--security/integrity/ima/Makefile2
-rw-r--r--security/integrity/ima/ima.h30
-rw-r--r--security/integrity/ima/ima_api.c7
-rw-r--r--security/integrity/ima/ima_fs.c2
-rw-r--r--security/integrity/ima/ima_iint.c169
-rw-r--r--security/integrity/ima/ima_main.c13
-rw-r--r--security/integrity/integrity.h50
-rw-r--r--security/keys/Makefile2
-rw-r--r--security/keys/encrypted-keys/Makefile6
-rw-r--r--security/keys/encrypted-keys/ecryptfs_format.c (renamed from security/keys/ecryptfs_format.c)0
-rw-r--r--security/keys/encrypted-keys/ecryptfs_format.h (renamed from security/keys/ecryptfs_format.h)0
-rw-r--r--security/keys/encrypted-keys/encrypted.c (renamed from security/keys/encrypted.c)49
-rw-r--r--security/keys/encrypted-keys/encrypted.h (renamed from security/keys/encrypted.h)11
-rw-r--r--security/keys/encrypted-keys/masterkey_trusted.c45
-rw-r--r--security/keys/gc.c386
-rw-r--r--security/keys/internal.h4
-rw-r--r--security/keys/key.c121
-rw-r--r--security/keys/keyring.c3
-rw-r--r--security/keys/process_keys.c16
-rw-r--r--security/keys/trusted.c19
-rw-r--r--security/security.c77
-rw-r--r--security/selinux/exports.c1
-rw-r--r--security/selinux/hooks.c13
-rw-r--r--security/selinux/include/avc_ss.h6
-rw-r--r--security/selinux/include/security.h8
-rw-r--r--security/selinux/netlink.c2
-rw-r--r--security/selinux/nlmsgtab.c1
-rw-r--r--security/selinux/selinuxfs.c5
-rw-r--r--security/selinux/ss/conditional.c2
-rw-r--r--security/selinux/ss/conditional.h1
-rw-r--r--security/selinux/ss/policydb.c2
-rw-r--r--security/selinux/ss/services.c3
-rw-r--r--security/smack/smack.h24
-rw-r--r--security/smack/smack_access.c134
-rw-r--r--security/smack/smack_lsm.c266
-rw-r--r--security/smack/smackfs.c277
-rw-r--r--security/tomoyo/Kconfig2
-rw-r--r--security/tomoyo/Makefile4
-rw-r--r--security/tomoyo/audit.c7
-rw-r--r--security/tomoyo/common.c228
-rw-r--r--security/tomoyo/common.h189
-rw-r--r--security/tomoyo/condition.c71
-rw-r--r--security/tomoyo/domain.c209
-rw-r--r--security/tomoyo/environ.c122
-rw-r--r--security/tomoyo/file.c42
-rw-r--r--security/tomoyo/gc.c540
-rw-r--r--security/tomoyo/group.c61
-rw-r--r--security/tomoyo/memory.c39
-rw-r--r--security/tomoyo/network.c771
-rw-r--r--security/tomoyo/realpath.c32
-rw-r--r--security/tomoyo/securityfs_if.c123
-rw-r--r--security/tomoyo/tomoyo.c62
-rw-r--r--security/tomoyo/util.c80
-rw-r--r--sound/core/memalloc.c4
-rw-r--r--sound/core/pcm_lib.c33
-rw-r--r--sound/core/pcm_native.c2
-rw-r--r--sound/oss/Kconfig4
-rw-r--r--sound/pci/fm801.c15
-rw-r--r--sound/pci/hda/hda_codec.c6
-rw-r--r--sound/pci/hda/hda_intel.c10
-rw-r--r--sound/pci/hda/patch_cirrus.c2
-rw-r--r--sound/pci/hda/patch_conexant.c58
-rw-r--r--sound/pci/hda/patch_realtek.c43
-rw-r--r--sound/pci/hda/patch_sigmatel.c2
-rw-r--r--sound/soc/blackfin/bf5xx-ad193x.c6
-rw-r--r--sound/soc/blackfin/bf5xx-ad73311.c2
-rw-r--r--sound/soc/codecs/ad193x.c11
-rw-r--r--sound/soc/codecs/ad193x.h5
-rw-r--r--sound/soc/codecs/ssm2602.c3
-rw-r--r--sound/soc/codecs/sta32x.c1
-rw-r--r--sound/soc/codecs/wm8753.c4
-rw-r--r--sound/soc/codecs/wm8962.c38
-rw-r--r--sound/soc/codecs/wm8996.c28
-rw-r--r--sound/soc/davinci/Kconfig1
-rw-r--r--sound/soc/ep93xx/ep93xx-i2s.c5
-rw-r--r--sound/soc/fsl/fsl_dma.c2
-rw-r--r--sound/soc/fsl/mpc5200_dma.c6
-rw-r--r--sound/soc/fsl/mpc8610_hpcd.c18
-rw-r--r--sound/soc/fsl/p1022_ds.c4
-rw-r--r--sound/soc/imx/imx-pcm-fiq.c1
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.c2
-rw-r--r--sound/soc/omap/ams-delta.c6
-rw-r--r--sound/soc/omap/mcpdm.c2
-rw-r--r--sound/soc/omap/mcpdm.h2
-rw-r--r--sound/soc/omap/omap-mcbsp.c6
-rw-r--r--sound/soc/pxa/zylonite.c8
-rw-r--r--sound/soc/samsung/Kconfig1
-rw-r--r--sound/soc/samsung/h1940_uda1380.c1
-rw-r--r--sound/soc/samsung/rx1950_uda1380.c1
-rw-r--r--sound/soc/samsung/speyside_wm8962.c6
-rw-r--r--sound/soc/soc-cache.c12
-rw-r--r--sound/soc/soc-core.c24
-rw-r--r--sound/soc/soc-dapm.c2
-rw-r--r--sound/soc/soc-io.c23
-rw-r--r--sound/soc/soc-jack.c4
-rw-r--r--sound/soc/soc-pcm.c3
-rw-r--r--sound/soc/tegra/tegra_wm8903.c4
-rw-r--r--sound/usb/card.c9
-rw-r--r--tools/perf/Makefile9
-rw-r--r--tools/perf/arch/arm/util/dwarf-regs.c3
-rw-r--r--tools/perf/builtin-record.c3
-rw-r--r--tools/perf/builtin-test.c2
-rw-r--r--tools/perf/builtin-top.c9
-rw-r--r--tools/perf/util/config.c4
-rw-r--r--tools/perf/util/event.c5
-rw-r--r--tools/perf/util/event.h2
-rw-r--r--tools/perf/util/evlist.c13
-rw-r--r--tools/perf/util/evlist.h1
-rw-r--r--tools/perf/util/evsel.c57
-rw-r--r--tools/perf/util/probe-finder.c2
-rw-r--r--tools/perf/util/python.c2
-rw-r--r--tools/perf/util/session.h3
-rw-r--r--tools/perf/util/sort.c10
-rw-r--r--tools/perf/util/symbol.c153
-rw-r--r--tools/power/cpupower/Makefile7
-rw-r--r--tools/power/cpupower/debug/x86_64/Makefile8
l---------tools/power/cpupower/debug/x86_64/centrino-decode.c1
l---------tools/power/cpupower/debug/x86_64/powernow-k8-decode.c1
-rw-r--r--tools/power/cpupower/man/cpupower-frequency-info.16
-rw-r--r--tools/power/cpupower/man/cpupower-frequency-set.18
-rw-r--r--tools/power/cpupower/man/cpupower.114
-rw-r--r--tools/power/cpupower/utils/builtin.h7
-rw-r--r--tools/power/cpupower/utils/cpufreq-info.c42
-rw-r--r--tools/power/cpupower/utils/cpufreq-set.c29
-rw-r--r--tools/power/cpupower/utils/cpuidle-info.c24
-rw-r--r--tools/power/cpupower/utils/cpupower-info.c20
-rw-r--r--tools/power/cpupower/utils/cpupower-set.c25
-rw-r--r--tools/power/cpupower/utils/cpupower.c91
-rw-r--r--tools/power/cpupower/utils/helpers/helpers.h12
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.c50
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.h2
-rw-r--r--tools/power/cpupower/utils/helpers/topology.c5
-rw-r--r--tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c2
-rw-r--r--tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c66
-rw-r--r--tools/power/cpupower/utils/idle_monitor/mperf_monitor.c177
-rw-r--r--virt/kvm/assigned-dev.c2
-rw-r--r--virt/kvm/iommu.c4
4061 files changed, 258320 insertions, 129256 deletions
diff --git a/Documentation/ABI/removed/o2cb b/Documentation/ABI/removed/o2cb
index 7f5daa465093..20c91adca6d4 100644
--- a/Documentation/ABI/removed/o2cb
+++ b/Documentation/ABI/removed/o2cb
@@ -1,6 +1,6 @@
What: /sys/o2cb symlink
Date: May 2011
-KernelVersion: 2.6.40
+KernelVersion: 3.0
Contact: ocfs2-devel@oss.oracle.com
Description: This is a symlink: /sys/o2cb to /sys/fs/o2cb. The symlink is
removed when new versions of ocfs2-tools which know to look
diff --git a/Documentation/ABI/removed/raw1394 b/Documentation/ABI/removed/raw1394
index 490aa1efc4ae..ec333e676322 100644
--- a/Documentation/ABI/removed/raw1394
+++ b/Documentation/ABI/removed/raw1394
@@ -5,7 +5,7 @@ Description:
/dev/raw1394 was a character device file that allowed low-level
access to FireWire buses. Its major drawbacks were its inability
to implement sensible device security policies, and its low level
- of abstraction that required userspace clients do duplicate much
+ of abstraction that required userspace clients to duplicate much
of the kernel's ieee1394 core functionality.
Replaced by /dev/fw*, i.e. the <linux/firewire-cdev.h> ABI of
firewire-core.
diff --git a/Documentation/ABI/testing/evm b/Documentation/ABI/testing/evm
new file mode 100644
index 000000000000..8374d4557e5d
--- /dev/null
+++ b/Documentation/ABI/testing/evm
@@ -0,0 +1,23 @@
+What: security/evm
+Date: March 2011
+Contact: Mimi Zohar <zohar@us.ibm.com>
+Description:
+ EVM protects a file's security extended attributes(xattrs)
+ against integrity attacks. The initial method maintains an
+ HMAC-sha1 value across the extended attributes, storing the
+ value as the extended attribute 'security.evm'.
+
+ EVM depends on the Kernel Key Retention System to provide it
+ with a trusted/encrypted key for the HMAC-sha1 operation.
+ The key is loaded onto the root's keyring using keyctl. Until
+ EVM receives notification that the key has been successfully
+ loaded onto the keyring (echo 1 > <securityfs>/evm), EVM
+ can not create or validate the 'security.evm' xattr, but
+ returns INTEGRITY_UNKNOWN. Loading the key and signaling EVM
+ should be done as early as possible. Normally this is done
+ in the initramfs, which has already been measured as part
+ of the trusted boot. For more information on creating and
+ loading existing trusted/encrypted keys, refer to:
+ Documentation/keys-trusted-encrypted.txt. (A sample dracut
+ patch, which loads the trusted/encrypted key and enables
+ EVM, is available from http://linux-ima.sourceforge.net/#EVM.)
diff --git a/Documentation/ABI/testing/sysfs-bus-bcma b/Documentation/ABI/testing/sysfs-bus-bcma
index 06b62badddd1..721b4aea3020 100644
--- a/Documentation/ABI/testing/sysfs-bus-bcma
+++ b/Documentation/ABI/testing/sysfs-bus-bcma
@@ -1,6 +1,6 @@
What: /sys/bus/bcma/devices/.../manuf
Date: May 2011
-KernelVersion: 2.6.40
+KernelVersion: 3.0
Contact: Rafał Miłecki <zajec5@gmail.com>
Description:
Each BCMA core has it's manufacturer id. See
@@ -8,7 +8,7 @@ Description:
What: /sys/bus/bcma/devices/.../id
Date: May 2011
-KernelVersion: 2.6.40
+KernelVersion: 3.0
Contact: Rafał Miłecki <zajec5@gmail.com>
Description:
There are a few types of BCMA cores, they can be identified by
@@ -16,7 +16,7 @@ Description:
What: /sys/bus/bcma/devices/.../rev
Date: May 2011
-KernelVersion: 2.6.40
+KernelVersion: 3.0
Contact: Rafał Miłecki <zajec5@gmail.com>
Description:
BCMA cores of the same type can still slightly differ depending
@@ -24,7 +24,7 @@ Description:
What: /sys/bus/bcma/devices/.../class
Date: May 2011
-KernelVersion: 2.6.40
+KernelVersion: 3.0
Contact: Rafał Miłecki <zajec5@gmail.com>
Description:
Each BCMA core is identified by few fields, including class it
diff --git a/Documentation/ABI/testing/sysfs-bus-pci-drivers-ehci_hcd b/Documentation/ABI/testing/sysfs-bus-pci-drivers-ehci_hcd
new file mode 100644
index 000000000000..60c60fa624b2
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-pci-drivers-ehci_hcd
@@ -0,0 +1,46 @@
+What: /sys/bus/pci/drivers/ehci_hcd/.../companion
+ /sys/bus/usb/devices/usbN/../companion
+Date: January 2007
+KernelVersion: 2.6.21
+Contact: Alan Stern <stern@rowland.harvard.edu>
+Description:
+ PCI-based EHCI USB controllers (i.e., high-speed USB-2.0
+ controllers) are often implemented along with a set of
+ "companion" full/low-speed USB-1.1 controllers. When a
+ high-speed device is plugged in, the connection is routed
+ to the EHCI controller; when a full- or low-speed device
+ is plugged in, the connection is routed to the companion
+ controller.
+
+ Sometimes you want to force a high-speed device to connect
+ at full speed, which can be accomplished by forcing the
+ connection to be routed to the companion controller.
+ That's what this file does. Writing a port number to the
+ file causes connections on that port to be routed to the
+ companion controller, and writing the negative of a port
+ number returns the port to normal operation.
+
+ For example: To force the high-speed device attached to
+ port 4 on bus 2 to run at full speed:
+
+ echo 4 >/sys/bus/usb/devices/usb2/../companion
+
+ To return the port to high-speed operation:
+
+ echo -4 >/sys/bus/usb/devices/usb2/../companion
+
+ Reading the file gives the list of ports currently forced
+ to the companion controller.
+
+ Note: Some EHCI controllers do not have companions; they
+ may contain an internal "transaction translator" or they
+ may be attached directly to a "rate-matching hub". This
+ mechanism will not work with such controllers. Also, it
+ cannot be used to force a port on a high-speed hub to
+ connect at full speed.
+
+ Note: When this file was first added, it appeared in a
+ different sysfs directory. The location given above is
+ correct for 2.6.35 (and probably several earlier kernel
+ versions as well).
+
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb
index 294aa864a60a..e647378e9e88 100644
--- a/Documentation/ABI/testing/sysfs-bus-usb
+++ b/Documentation/ABI/testing/sysfs-bus-usb
@@ -142,3 +142,18 @@ Description:
such devices.
Users:
usb_modeswitch
+
+What: /sys/bus/usb/devices/.../power/usb2_hardware_lpm
+Date: September 2011
+Contact: Andiry Xu <andiry.xu@amd.com>
+Description:
+ If CONFIG_USB_SUSPEND is set and a USB 2.0 lpm-capable device
+ is plugged in to a xHCI host which support link PM, it will
+ perform a LPM test; if the test is passed and host supports
+ USB2 hardware LPM (xHCI 1.0 feature), USB2 hardware LPM will
+ be enabled for the device and the USB device directory will
+ contain a file named power/usb2_hardware_lpm. The file holds
+ a string value (enable or disable) indicating whether or not
+ USB2 hardware LPM is enabled for the device. Developer can
+ write y/Y/1 or n/N/0 to the file to enable/disable the
+ feature.
diff --git a/Documentation/ABI/testing/sysfs-class-backlight-driver-adp8870 b/Documentation/ABI/testing/sysfs-class-backlight-driver-adp8870
index aa11dbdd794b..4a9c545bda4b 100644
--- a/Documentation/ABI/testing/sysfs-class-backlight-driver-adp8870
+++ b/Documentation/ABI/testing/sysfs-class-backlight-driver-adp8870
@@ -4,8 +4,8 @@ What: /sys/class/backlight/<backlight>/l2_bright_max
What: /sys/class/backlight/<backlight>/l3_office_max
What: /sys/class/backlight/<backlight>/l4_indoor_max
What: /sys/class/backlight/<backlight>/l5_dark_max
-Date: Mai 2011
-KernelVersion: 2.6.40
+Date: May 2011
+KernelVersion: 3.0
Contact: device-drivers-devel@blackfin.uclinux.org
Description:
Control the maximum brightness for <ambient light zone>
@@ -18,8 +18,8 @@ What: /sys/class/backlight/<backlight>/l2_bright_dim
What: /sys/class/backlight/<backlight>/l3_office_dim
What: /sys/class/backlight/<backlight>/l4_indoor_dim
What: /sys/class/backlight/<backlight>/l5_dark_dim
-Date: Mai 2011
-KernelVersion: 2.6.40
+Date: May 2011
+KernelVersion: 3.0
Contact: device-drivers-devel@blackfin.uclinux.org
Description:
Control the dim brightness for <ambient light zone>
@@ -29,8 +29,8 @@ Description:
this <ambient light zone>.
What: /sys/class/backlight/<backlight>/ambient_light_level
-Date: Mai 2011
-KernelVersion: 2.6.40
+Date: May 2011
+KernelVersion: 3.0
Contact: device-drivers-devel@blackfin.uclinux.org
Description:
Get conversion value of the light sensor.
@@ -39,8 +39,8 @@ Description:
8000 (max ambient brightness)
What: /sys/class/backlight/<backlight>/ambient_light_zone
-Date: Mai 2011
-KernelVersion: 2.6.40
+Date: May 2011
+KernelVersion: 3.0
Contact: device-drivers-devel@blackfin.uclinux.org
Description:
Get/Set current ambient light zone. Reading returns
diff --git a/Documentation/ABI/testing/sysfs-class-devfreq b/Documentation/ABI/testing/sysfs-class-devfreq
new file mode 100644
index 000000000000..23d78b5aab11
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-devfreq
@@ -0,0 +1,52 @@
+What: /sys/class/devfreq/.../
+Date: September 2011
+Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+ Provide a place in sysfs for the devfreq objects.
+ This allows accessing various devfreq specific variables.
+ The name of devfreq object denoted as ... is same as the
+ name of device using devfreq.
+
+What: /sys/class/devfreq/.../governor
+Date: September 2011
+Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+ The /sys/class/devfreq/.../governor shows the name of the
+ governor used by the corresponding devfreq object.
+
+What: /sys/class/devfreq/.../cur_freq
+Date: September 2011
+Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+ The /sys/class/devfreq/.../cur_freq shows the current
+ frequency of the corresponding devfreq object.
+
+What: /sys/class/devfreq/.../central_polling
+Date: September 2011
+Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+ The /sys/class/devfreq/.../central_polling shows whether
+ the devfreq ojbect is using devfreq-provided central
+ polling mechanism or not.
+
+What: /sys/class/devfreq/.../polling_interval
+Date: September 2011
+Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+ The /sys/class/devfreq/.../polling_interval shows and sets
+ the requested polling interval of the corresponding devfreq
+ object. The values are represented in ms. If the value is
+ less than 1 jiffy, it is considered to be 0, which means
+ no polling. This value is meaningless if the governor is
+ not polling; thus. If the governor is not using
+ devfreq-provided central polling
+ (/sys/class/devfreq/.../central_polling is 0), this value
+ may be useless.
+
+What: /sys/class/devfreq/.../userspace/set_freq
+Date: September 2011
+Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+ The /sys/class/devfreq/.../userspace/set_freq shows and
+ sets the requested frequency for the devfreq object if
+ userspace governor is in effect.
diff --git a/Documentation/ABI/testing/sysfs-class-net-mesh b/Documentation/ABI/testing/sysfs-class-net-mesh
index 748fe1701d25..b02001488eef 100644
--- a/Documentation/ABI/testing/sysfs-class-net-mesh
+++ b/Documentation/ABI/testing/sysfs-class-net-mesh
@@ -22,6 +22,14 @@ Description:
mesh will be fragmented or silently discarded if the
packet size exceeds the outgoing interface MTU.
+What: /sys/class/net/<mesh_iface>/mesh/ap_isolation
+Date: May 2011
+Contact: Antonio Quartulli <ordex@autistici.org>
+Description:
+ Indicates whether the data traffic going from a
+ wireless client to another wireless client will be
+ silently dropped.
+
What: /sys/class/net/<mesh_iface>/mesh/gw_bandwidth
Date: October 2010
Contact: Marek Lindner <lindner_marek@yahoo.de>
diff --git a/Documentation/ABI/testing/sysfs-class-scsi_host b/Documentation/ABI/testing/sysfs-class-scsi_host
new file mode 100644
index 000000000000..29a4f892e433
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-scsi_host
@@ -0,0 +1,13 @@
+What: /sys/class/scsi_host/hostX/isci_id
+Date: June 2011
+Contact: Dave Jiang <dave.jiang@intel.com>
+Description:
+ This file contains the enumerated host ID for the Intel
+ SCU controller. The Intel(R) C600 Series Chipset SATA/SAS
+ Storage Control Unit embeds up to two 4-port controllers in
+ a single PCI device. The controllers are enumerated in order
+ which usually means the lowest number scsi_host corresponds
+ with the first controller, but this association is not
+ guaranteed. The 'isci_id' attribute unambiguously identifies
+ the controller index: '0' for the first controller,
+ '1' for the second.
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
new file mode 100644
index 000000000000..9aec8ef228b0
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
@@ -0,0 +1,7 @@
+What: /sys/module/hid_logitech/drivers/hid:logitech/<dev>/range.
+Date: July 2011
+KernelVersion: 3.2
+Contact: Michal Malý <madcatxster@gmail.com>
+Description: Display minimum, maximum and current range of the steering
+ wheel. Writing a value within min and max boundaries sets the
+ range of the wheel.
diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl
index 445289cd0e65..2014155c899d 100644
--- a/Documentation/DocBook/80211.tmpl
+++ b/Documentation/DocBook/80211.tmpl
@@ -433,8 +433,18 @@
Insert notes about VLAN interfaces with hw crypto here or
in the hw crypto chapter.
</para>
+ <section id="ps-client">
+ <title>support for powersaving clients</title>
+!Pinclude/net/mac80211.h AP support for powersaving clients
+ </section>
!Finclude/net/mac80211.h ieee80211_get_buffered_bc
!Finclude/net/mac80211.h ieee80211_beacon_get
+!Finclude/net/mac80211.h ieee80211_sta_eosp_irqsafe
+!Finclude/net/mac80211.h ieee80211_frame_release_type
+!Finclude/net/mac80211.h ieee80211_sta_ps_transition
+!Finclude/net/mac80211.h ieee80211_sta_ps_transition_ni
+!Finclude/net/mac80211.h ieee80211_sta_set_buffered
+!Finclude/net/mac80211.h ieee80211_sta_block_awake
</chapter>
<chapter id="multi-iface">
@@ -460,7 +470,6 @@
!Finclude/net/mac80211.h sta_notify_cmd
!Finclude/net/mac80211.h ieee80211_find_sta
!Finclude/net/mac80211.h ieee80211_find_sta_by_ifaddr
-!Finclude/net/mac80211.h ieee80211_sta_block_awake
</chapter>
<chapter id="hardware-scan-offload">
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index 85164016ed26..23fdf79f8cf3 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -1455,7 +1455,7 @@ Applicable to the H264 encoder.</entry>
</row>
<row><entry></entry></row>
- <row>
+ <row id="v4l2-mpeg-video-h264-vui-sar-idc">
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC</constant>&nbsp;</entry>
<entry>enum&nbsp;v4l2_mpeg_video_h264_vui_sar_idc</entry>
</row>
@@ -1561,7 +1561,7 @@ Applicable to the H264 encoder.</entry>
</row>
<row><entry></entry></row>
- <row>
+ <row id="v4l2-mpeg-video-h264-level">
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_LEVEL</constant>&nbsp;</entry>
<entry>enum&nbsp;v4l2_mpeg_video_h264_level</entry>
</row>
@@ -1641,7 +1641,7 @@ Possible values are:</entry>
</row>
<row><entry></entry></row>
- <row>
+ <row id="v4l2-mpeg-video-mpeg4-level">
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL</constant>&nbsp;</entry>
<entry>enum&nbsp;v4l2_mpeg_video_mpeg4_level</entry>
</row>
@@ -1689,9 +1689,9 @@ Possible values are:</entry>
</row>
<row><entry></entry></row>
- <row>
+ <row id="v4l2-mpeg-video-h264-profile">
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_PROFILE</constant>&nbsp;</entry>
- <entry>enum&nbsp;v4l2_mpeg_h264_profile</entry>
+ <entry>enum&nbsp;v4l2_mpeg_video_h264_profile</entry>
</row>
<row><entry spanname="descr">The profile information for H264.
Applicable to the H264 encoder.
@@ -1774,9 +1774,9 @@ Possible values are:</entry>
</row>
<row><entry></entry></row>
- <row>
+ <row id="v4l2-mpeg-video-mpeg4-profile">
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE</constant>&nbsp;</entry>
- <entry>enum&nbsp;v4l2_mpeg_mpeg4_profile</entry>
+ <entry>enum&nbsp;v4l2_mpeg_video_mpeg4_profile</entry>
</row>
<row><entry spanname="descr">The profile information for MPEG4.
Applicable to the MPEG4 encoder.
@@ -1820,9 +1820,9 @@ Applicable to the encoder.
</row>
<row><entry></entry></row>
- <row>
+ <row id="v4l2-mpeg-video-multi-slice-mode">
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE</constant>&nbsp;</entry>
- <entry>enum&nbsp;v4l2_mpeg_multi_slice_mode</entry>
+ <entry>enum&nbsp;v4l2_mpeg_video_multi_slice_mode</entry>
</row>
<row><entry spanname="descr">Determines how the encoder should handle division of frame into slices.
Applicable to the encoder.
@@ -1868,9 +1868,9 @@ Applicable to the encoder.</entry>
</row>
<row><entry></entry></row>
- <row>
+ <row id="v4l2-mpeg-video-h264-loop-filter-mode">
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE</constant>&nbsp;</entry>
- <entry>enum&nbsp;v4l2_mpeg_h264_loop_filter_mode</entry>
+ <entry>enum&nbsp;v4l2_mpeg_video_h264_loop_filter_mode</entry>
</row>
<row><entry spanname="descr">Loop filter mode for H264 encoder.
Possible values are:</entry>
@@ -1913,9 +1913,9 @@ Applicable to the H264 encoder.</entry>
</row>
<row><entry></entry></row>
- <row>
+ <row id="v4l2-mpeg-video-h264-entropy-mode">
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE</constant>&nbsp;</entry>
- <entry>enum&nbsp;v4l2_mpeg_h264_symbol_mode</entry>
+ <entry>enum&nbsp;v4l2_mpeg_video_h264_entropy_mode</entry>
</row>
<row><entry spanname="descr">Entropy coding mode for H264 - CABAC/CAVALC.
Applicable to the H264 encoder.
@@ -2140,9 +2140,9 @@ previous frames. Applicable to the H264 encoder.</entry>
</row>
<row><entry></entry></row>
- <row>
+ <row id="v4l2-mpeg-video-header-mode">
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_HEADER_MODE</constant>&nbsp;</entry>
- <entry>enum&nbsp;v4l2_mpeg_header_mode</entry>
+ <entry>enum&nbsp;v4l2_mpeg_video_header_mode</entry>
</row>
<row><entry spanname="descr">Determines whether the header is returned as the first buffer or is
it returned together with the first frame. Applicable to encoders.
@@ -2320,9 +2320,9 @@ Valid only when H.264 and macroblock level RC is enabled (<constant>V4L2_CID_MPE
Applicable to the H264 encoder.</entry>
</row>
<row><entry></entry></row>
- <row>
+ <row id="v4l2-mpeg-mfc51-video-frame-skip-mode">
<entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE</constant>&nbsp;</entry>
- <entry>enum&nbsp;v4l2_mpeg_mfc51_frame_skip_mode</entry>
+ <entry>enum&nbsp;v4l2_mpeg_mfc51_video_frame_skip_mode</entry>
</row>
<row><entry spanname="descr">
Indicates in what conditions the encoder should skip frames. If encoding a frame would cause the encoded stream to be larger then
@@ -2361,9 +2361,9 @@ the stream will meet tight bandwidth contraints. Applicable to encoders.
</entry>
</row>
<row><entry></entry></row>
- <row>
+ <row id="v4l2-mpeg-mfc51-video-force-frame-type">
<entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE</constant>&nbsp;</entry>
- <entry>enum&nbsp;v4l2_mpeg_mfc51_force_frame_type</entry>
+ <entry>enum&nbsp;v4l2_mpeg_mfc51_video_force_frame_type</entry>
</row>
<row><entry spanname="descr">Force a frame type for the next queued buffer. Applicable to encoders.
Possible values are:</entry>
diff --git a/Documentation/DocBook/uio-howto.tmpl b/Documentation/DocBook/uio-howto.tmpl
index 7c4b514d62b1..54883de5d5f9 100644
--- a/Documentation/DocBook/uio-howto.tmpl
+++ b/Documentation/DocBook/uio-howto.tmpl
@@ -529,7 +529,7 @@ memory (e.g. allocated with <function>kmalloc()</function>). There's also
</para></listitem>
<listitem><para>
-<varname>unsigned long addr</varname>: Required if the mapping is used.
+<varname>phys_addr_t addr</varname>: Required if the mapping is used.
Fill in the address of your memory block. This address is the one that
appears in sysfs.
</para></listitem>
diff --git a/Documentation/PCI/pci.txt b/Documentation/PCI/pci.txt
index 6148d4080f88..aa09e5476bba 100644
--- a/Documentation/PCI/pci.txt
+++ b/Documentation/PCI/pci.txt
@@ -314,7 +314,7 @@ from the PCI device config space. Use the values in the pci_dev structure
as the PCI "bus address" might have been remapped to a "host physical"
address by the arch/chip-set specific kernel support.
-See Documentation/IO-mapping.txt for how to access device registers
+See Documentation/io-mapping.txt for how to access device registers
or device memory.
The device driver needs to call pci_request_region() to verify
diff --git a/Documentation/blackfin/bfin-gpio-notes.txt b/Documentation/blackfin/bfin-gpio-notes.txt
index f731c1e56475..d36b01f778b9 100644
--- a/Documentation/blackfin/bfin-gpio-notes.txt
+++ b/Documentation/blackfin/bfin-gpio-notes.txt
@@ -1,5 +1,5 @@
/*
- * File: Documentation/blackfin/bfin-gpio-note.txt
+ * File: Documentation/blackfin/bfin-gpio-notes.txt
* Based on:
* Author:
*
diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt
index c6d84cfd2f56..e418dc0a7086 100644
--- a/Documentation/block/biodoc.txt
+++ b/Documentation/block/biodoc.txt
@@ -186,7 +186,7 @@ a virtual address mapping (unlike the earlier scheme of virtual address
do not have a corresponding kernel virtual address space mapping) and
low-memory pages.
-Note: Please refer to Documentation/PCI/PCI-DMA-mapping.txt for a discussion
+Note: Please refer to Documentation/DMA-API-HOWTO.txt for a discussion
on PCI high mem DMA aspects and mapping of scatter gather lists, and support
for 64 bit PCI.
diff --git a/Documentation/bus-virt-phys-mapping.txt b/Documentation/bus-virt-phys-mapping.txt
index 1b5aa10df845..2bc55ff3b4d1 100644
--- a/Documentation/bus-virt-phys-mapping.txt
+++ b/Documentation/bus-virt-phys-mapping.txt
@@ -1,6 +1,6 @@
[ NOTE: The virt_to_bus() and bus_to_virt() functions have been
superseded by the functionality provided by the PCI DMA interface
- (see Documentation/PCI/PCI-DMA-mapping.txt). They continue
+ (see Documentation/DMA-API-HOWTO.txt). They continue
to be documented below for historical purposes, but new code
must not use them. --davidm 00/12/12 ]
diff --git a/Documentation/cdrom/packet-writing.txt b/Documentation/cdrom/packet-writing.txt
index 13c251d5add6..2834170d821e 100644
--- a/Documentation/cdrom/packet-writing.txt
+++ b/Documentation/cdrom/packet-writing.txt
@@ -109,7 +109,7 @@ this interface. (see http://tom.ist-im-web.de/download/pktcdvd )
For a description of the sysfs interface look into the file:
- Documentation/ABI/testing/sysfs-block-pktcdvd
+ Documentation/ABI/testing/sysfs-class-pktcdvd
Using the pktcdvd debugfs interface
diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt
index 6f3c598971fc..06eb6d957c83 100644
--- a/Documentation/cgroups/memory.txt
+++ b/Documentation/cgroups/memory.txt
@@ -380,7 +380,7 @@ will be charged as a new owner of it.
5.2 stat file
-5.2.1 memory.stat file includes following statistics
+memory.stat file includes following statistics
# per-memory cgroup local status
cache - # of bytes of page cache memory.
@@ -438,89 +438,6 @@ Note:
file_mapped is accounted only when the memory cgroup is owner of page
cache.)
-5.2.2 memory.vmscan_stat
-
-memory.vmscan_stat includes statistics information for memory scanning and
-freeing, reclaiming. The statistics shows memory scanning information since
-memory cgroup creation and can be reset to 0 by writing 0 as
-
- #echo 0 > ../memory.vmscan_stat
-
-This file contains following statistics.
-
-[param]_[file_or_anon]_pages_by_[reason]_[under_heararchy]
-[param]_elapsed_ns_by_[reason]_[under_hierarchy]
-
-For example,
-
- scanned_file_pages_by_limit indicates the number of scanned
- file pages at vmscan.
-
-Now, 3 parameters are supported
-
- scanned - the number of pages scanned by vmscan
- rotated - the number of pages activated at vmscan
- freed - the number of pages freed by vmscan
-
-If "rotated" is high against scanned/freed, the memcg seems busy.
-
-Now, 2 reason are supported
-
- limit - the memory cgroup's limit
- system - global memory pressure + softlimit
- (global memory pressure not under softlimit is not handled now)
-
-When under_hierarchy is added in the tail, the number indicates the
-total memcg scan of its children and itself.
-
-elapsed_ns is a elapsed time in nanosecond. This may include sleep time
-and not indicates CPU usage. So, please take this as just showing
-latency.
-
-Here is an example.
-
-# cat /cgroup/memory/A/memory.vmscan_stat
-scanned_pages_by_limit 9471864
-scanned_anon_pages_by_limit 6640629
-scanned_file_pages_by_limit 2831235
-rotated_pages_by_limit 4243974
-rotated_anon_pages_by_limit 3971968
-rotated_file_pages_by_limit 272006
-freed_pages_by_limit 2318492
-freed_anon_pages_by_limit 962052
-freed_file_pages_by_limit 1356440
-elapsed_ns_by_limit 351386416101
-scanned_pages_by_system 0
-scanned_anon_pages_by_system 0
-scanned_file_pages_by_system 0
-rotated_pages_by_system 0
-rotated_anon_pages_by_system 0
-rotated_file_pages_by_system 0
-freed_pages_by_system 0
-freed_anon_pages_by_system 0
-freed_file_pages_by_system 0
-elapsed_ns_by_system 0
-scanned_pages_by_limit_under_hierarchy 9471864
-scanned_anon_pages_by_limit_under_hierarchy 6640629
-scanned_file_pages_by_limit_under_hierarchy 2831235
-rotated_pages_by_limit_under_hierarchy 4243974
-rotated_anon_pages_by_limit_under_hierarchy 3971968
-rotated_file_pages_by_limit_under_hierarchy 272006
-freed_pages_by_limit_under_hierarchy 2318492
-freed_anon_pages_by_limit_under_hierarchy 962052
-freed_file_pages_by_limit_under_hierarchy 1356440
-elapsed_ns_by_limit_under_hierarchy 351386416101
-scanned_pages_by_system_under_hierarchy 0
-scanned_anon_pages_by_system_under_hierarchy 0
-scanned_file_pages_by_system_under_hierarchy 0
-rotated_pages_by_system_under_hierarchy 0
-rotated_anon_pages_by_system_under_hierarchy 0
-rotated_file_pages_by_system_under_hierarchy 0
-freed_pages_by_system_under_hierarchy 0
-freed_anon_pages_by_system_under_hierarchy 0
-freed_file_pages_by_system_under_hierarchy 0
-elapsed_ns_by_system_under_hierarchy 0
-
5.3 swappiness
Similar to /proc/sys/vm/swappiness, but affecting a hierarchy of groups only.
diff --git a/Documentation/cpu-freq/governors.txt b/Documentation/cpu-freq/governors.txt
index e74d0a2eb1cf..d221781dabaa 100644
--- a/Documentation/cpu-freq/governors.txt
+++ b/Documentation/cpu-freq/governors.txt
@@ -132,7 +132,7 @@ The sampling rate is limited by the HW transition latency:
transition_latency * 100
Or by kernel restrictions:
If CONFIG_NO_HZ is set, the limit is 10ms fixed.
-If CONFIG_NO_HZ is not set or no_hz=off boot parameter is used, the
+If CONFIG_NO_HZ is not set or nohz=off boot parameter is used, the
limits depend on the CONFIG_HZ option:
HZ=1000: min=20000us (20ms)
HZ=250: min=80000us (80ms)
diff --git a/Documentation/development-process/4.Coding b/Documentation/development-process/4.Coding
index 83f5f5b365a3..e3cb6a56653a 100644
--- a/Documentation/development-process/4.Coding
+++ b/Documentation/development-process/4.Coding
@@ -278,7 +278,7 @@ enabled, a configurable percentage of memory allocations will be made to
fail; these failures can be restricted to a specific range of code.
Running with fault injection enabled allows the programmer to see how the
code responds when things go badly. See
-Documentation/fault-injection/fault-injection.text for more information on
+Documentation/fault-injection/fault-injection.txt for more information on
how to use this facility.
Other kinds of errors can be found with the "sparse" static analysis tool.
diff --git a/Documentation/devicetree/bindings/arm/l2cc.txt b/Documentation/devicetree/bindings/arm/l2cc.txt
new file mode 100644
index 000000000000..7ca52161e7ab
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/l2cc.txt
@@ -0,0 +1,44 @@
+* ARM L2 Cache Controller
+
+ARM cores often have a separate level 2 cache controller. There are various
+implementations of the L2 cache controller with compatible programming models.
+The ARM L2 cache representation in the device tree should be done as follows:
+
+Required properties:
+
+- compatible : should be one of:
+ "arm,pl310-cache"
+ "arm,l220-cache"
+ "arm,l210-cache"
+- cache-unified : Specifies the cache is a unified cache.
+- cache-level : Should be set to 2 for a level 2 cache.
+- reg : Physical base address and size of cache controller's memory mapped
+ registers.
+
+Optional properties:
+
+- arm,data-latency : Cycles of latency for Data RAM accesses. Specifies 3 cells of
+ read, write and setup latencies. Minimum valid values are 1. Controllers
+ without setup latency control should use a value of 0.
+- arm,tag-latency : Cycles of latency for Tag RAM accesses. Specifies 3 cells of
+ read, write and setup latencies. Controllers without setup latency control
+ should use 0. Controllers without separate read and write Tag RAM latency
+ values should only use the first cell.
+- arm,dirty-latency : Cycles of latency for Dirty RAMs. This is a single cell.
+- arm,filter-ranges : <start length> Starting address and length of window to
+ filter. Addresses in the filter window are directed to the M1 port. Other
+ addresses will go to the M0 port.
+- interrupts : 1 combined interrupt.
+
+Example:
+
+L2: cache-controller {
+ compatible = "arm,pl310-cache";
+ reg = <0xfff12000 0x1000>;
+ arm,data-latency = <1 1 1>;
+ arm,tag-latency = <2 2 2>;
+ arm,filter-latency = <0x80000000 0x8000000>;
+ cache-unified;
+ cache-level = <2>;
+ interrupts = <45>;
+};
diff --git a/Documentation/devicetree/bindings/gpio/led.txt b/Documentation/devicetree/bindings/gpio/led.txt
index 064db928c3c1..141087cf3107 100644
--- a/Documentation/devicetree/bindings/gpio/led.txt
+++ b/Documentation/devicetree/bindings/gpio/led.txt
@@ -8,7 +8,7 @@ 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/powerpc/booting-without-of.txt. Active
+ for devices" in Documentation/devicetree/booting-without-of.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).
diff --git a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
index 1a729f089866..1ad80d5865a9 100644
--- a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
+++ b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
@@ -1,61 +1,24 @@
-CAN Device Tree Bindings
-------------------------
-2011 Freescale Semiconductor, Inc.
+Flexcan CAN contoller on Freescale's ARM and PowerPC system-on-a-chip (SOC).
-fsl,flexcan-v1.0 nodes
------------------------
-In addition to the required compatible-, reg- and interrupt-properties, you can
-also specify which clock source shall be used for the controller.
+Required properties:
-CPI Clock- Can Protocol Interface Clock
- This CLK_SRC bit of CTRL(control register) selects the clock source to
- the CAN Protocol Interface(CPI) to be either the peripheral clock
- (driven by the PLL) or the crystal oscillator clock. The selected clock
- is the one fed to the prescaler to generate the Serial Clock (Sclock).
- The PRESDIV field of CTRL(control register) controls a prescaler that
- generates the Serial Clock (Sclock), whose period defines the
- time quantum used to compose the CAN waveform.
+- compatible : Should be "fsl,<processor>-flexcan"
-Can Engine Clock Source
- There are two sources for CAN clock
- - Platform Clock It represents the bus clock
- - Oscillator Clock
+ An implementation should also claim any of the following compatibles
+ that it is fully backwards compatible with:
- Peripheral Clock (PLL)
- --------------
- |
- --------- -------------
- | |CPI Clock | Prescaler | Sclock
- | |---------------->| (1.. 256) |------------>
- --------- -------------
- | |
- -------------- ---------------------CLK_SRC
- Oscillator Clock
+ - fsl,p1010-flexcan
-- fsl,flexcan-clock-source : CAN Engine Clock Source.This property selects
- the peripheral clock. PLL clock is fed to the
- prescaler to generate the Serial Clock (Sclock).
- Valid values are "oscillator" and "platform"
- "oscillator": CAN engine clock source is oscillator clock.
- "platform" The CAN engine clock source is the bus clock
- (platform clock).
+- reg : Offset and length of the register set for this device
+- interrupts : Interrupt tuple for this device
+- clock-frequency : The oscillator frequency driving the flexcan device
-- fsl,flexcan-clock-divider : for the reference and system clock, an additional
- clock divider can be specified.
-- clock-frequency: frequency required to calculate the bitrate for FlexCAN.
+Example:
-Note:
- - v1.0 of flexcan-v1.0 represent the IP block version for P1010 SOC.
- - P1010 does not have oscillator as the Clock Source.So the default
- Clock Source is platform clock.
-Examples:
-
- can0@1c000 {
- compatible = "fsl,flexcan-v1.0";
+ can@1c000 {
+ compatible = "fsl,p1010-flexcan";
reg = <0x1c000 0x1000>;
interrupts = <48 0x2>;
interrupt-parent = <&mpic>;
- fsl,flexcan-clock-source = "platform";
- fsl,flexcan-clock-divider = <2>;
- clock-frequency = <fixed by u-boot>;
+ clock-frequency = <200000000>; // filled in by bootloader
};
diff --git a/Documentation/devicetree/bindings/net/smsc911x.txt b/Documentation/devicetree/bindings/net/smsc911x.txt
new file mode 100644
index 000000000000..adb5b5744ecd
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/smsc911x.txt
@@ -0,0 +1,38 @@
+* Smart Mixed-Signal Connectivity (SMSC) LAN911x/912x Controller
+
+Required properties:
+- compatible : Should be "smsc,lan<model>", "smsc,lan9115"
+- reg : Address and length of the io space for SMSC LAN
+- interrupts : Should contain SMSC LAN interrupt line
+- interrupt-parent : Should be the phandle for the interrupt controller
+ that services interrupts for this device
+- phy-mode : String, operation mode of the PHY interface.
+ Supported values are: "mii", "gmii", "sgmii", "tbi", "rmii",
+ "rgmii", "rgmii-id", "rgmii-rxid", "rgmii-txid", "rtbi", "smii".
+
+Optional properties:
+- reg-shift : Specify the quantity to shift the register offsets by
+- reg-io-width : Specify the size (in bytes) of the IO accesses that
+ should be performed on the device. Valid value for SMSC LAN is
+ 2 or 4. If it's omitted or invalid, the size would be 2.
+- smsc,irq-active-high : Indicates the IRQ polarity is active-high
+- smsc,irq-push-pull : Indicates the IRQ type is push-pull
+- smsc,force-internal-phy : Forces SMSC LAN controller to use
+ internal PHY
+- smsc,force-external-phy : Forces SMSC LAN controller to use
+ external PHY
+- smsc,save-mac-address : Indicates that mac address needs to be saved
+ before resetting the controller
+- local-mac-address : 6 bytes, mac address
+
+Examples:
+
+lan9220@f4000000 {
+ compatible = "smsc,lan9220", "smsc,lan9115";
+ reg = <0xf4000000 0x2000000>;
+ phy-mode = "mii";
+ interrupt-parent = <&gpio1>;
+ interrupts = <31>;
+ reg-io-width = <4>;
+ smsc,irq-push-pull;
+};
diff --git a/Documentation/driver-model/binding.txt b/Documentation/driver-model/binding.txt
index f7ec9d625bfc..abfc8e290d53 100644
--- a/Documentation/driver-model/binding.txt
+++ b/Documentation/driver-model/binding.txt
@@ -48,10 +48,6 @@ devclass_add_device is called to enumerate the device within the class
and actually register it with the class, which happens with the
class's register_dev callback.
-NOTE: The device class structures and core routines to manipulate them
-are not in the mainline kernel, so the discussion is still a bit
-speculative.
-
Driver
~~~~~~
diff --git a/Documentation/driver-model/device.txt b/Documentation/driver-model/device.txt
index bdefe728a737..1e70220d20f4 100644
--- a/Documentation/driver-model/device.txt
+++ b/Documentation/driver-model/device.txt
@@ -45,33 +45,52 @@ struct device_attribute {
const char *buf, size_t count);
};
-Attributes of devices can be exported via drivers using a simple
-procfs-like interface.
+Attributes of devices can be exported by a device driver through sysfs.
Please see Documentation/filesystems/sysfs.txt for more information
on how sysfs works.
+As explained in Documentation/kobject.txt, device attributes must be be
+created before the KOBJ_ADD uevent is generated. The only way to realize
+that is by defining an attribute group.
+
Attributes are declared using a macro called DEVICE_ATTR:
#define DEVICE_ATTR(name,mode,show,store)
Example:
-DEVICE_ATTR(power,0644,show_power,store_power);
+static DEVICE_ATTR(type, 0444, show_type, NULL);
+static DEVICE_ATTR(power, 0644, show_power, store_power);
-This declares a structure of type struct device_attribute named
-'dev_attr_power'. This can then be added and removed to the device's
-directory using:
+This declares two structures of type struct device_attribute with respective
+names 'dev_attr_type' and 'dev_attr_power'. These two attributes can be
+organized as follows into a group:
-int device_create_file(struct device *device, struct device_attribute * entry);
-void device_remove_file(struct device * dev, struct device_attribute * attr);
+static struct attribute *dev_attrs[] = {
+ &dev_attr_type.attr,
+ &dev_attr_power.attr,
+ NULL,
+};
-Example:
+static struct attribute_group dev_attr_group = {
+ .attrs = dev_attrs,
+};
+
+static const struct attribute_group *dev_attr_groups[] = {
+ &dev_attr_group,
+ NULL,
+};
+
+This array of groups can then be associated with a device by setting the
+group pointer in struct device before device_register() is invoked:
-device_create_file(dev,&dev_attr_power);
-device_remove_file(dev,&dev_attr_power);
+ dev->groups = dev_attr_groups;
+ device_register(dev);
-The file name will be 'power' with a mode of 0644 (-rw-r--r--).
+The device_register() function will use the 'groups' pointer to create the
+device attributes and the device_unregister() function will use this pointer
+to remove the device attributes.
Word of warning: While the kernel allows device_create_file() and
device_remove_file() to be called on a device at any time, userspace has
@@ -84,24 +103,4 @@ not know about the new attributes.
This is important for device driver that need to publish additional
attributes for a device at driver probe time. If the device driver simply
calls device_create_file() on the device structure passed to it, then
-userspace will never be notified of the new attributes. Instead, it should
-probably use class_create() and class->dev_attrs to set up a list of
-desired attributes in the modules_init function, and then in the .probe()
-hook, and then use device_create() to create a new device as a child
-of the probed device. The new device will generate a new uevent and
-properly advertise the new attributes to userspace.
-
-For example, if a driver wanted to add the following attributes:
-struct device_attribute mydriver_attribs[] = {
- __ATTR(port_count, 0444, port_count_show),
- __ATTR(serial_number, 0444, serial_number_show),
- NULL
-};
-
-Then in the module init function is would do:
- mydriver_class = class_create(THIS_MODULE, "my_attrs");
- mydriver_class.dev_attr = mydriver_attribs;
-
-And assuming 'dev' is the struct device passed into the probe hook, the driver
-probe function would do something like:
- device_create(&mydriver_class, dev, chrdev, &private_data, "my_name");
+userspace will never be notified of the new attributes.
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index c4a6e148732a..d5ac362daef5 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -592,3 +592,20 @@ Why: In 3.0, we can now autodetect internal 3G device and already have
interface that was used by acer-wmi driver. It will replaced by
information log when acer-wmi initial.
Who: Lee, Chun-Yi <jlee@novell.com>
+
+----------------------------
+
+What: The XFS nodelaylog mount option
+When: 3.3
+Why: The delaylog mode that has been the default since 2.6.39 has proven
+ stable, and the old code is in the way of additional improvements in
+ the log code.
+Who: Christoph Hellwig <hch@lst.de>
+
+----------------------------
+
+What: iwlagn alias support
+When: 3.5
+Why: The iwlagn module has been renamed iwlwifi. The alias will be around
+ for backward compatibility for several cycles and then dropped.
+Who: Don Fry <donald.h.fry@intel.com>
diff --git a/Documentation/filesystems/9p.txt b/Documentation/filesystems/9p.txt
index 13de64c7f0ab..2c0321442845 100644
--- a/Documentation/filesystems/9p.txt
+++ b/Documentation/filesystems/9p.txt
@@ -92,7 +92,7 @@ OPTIONS
wfdno=n the file descriptor for writing with trans=fd
- maxdata=n the number of bytes to use for 9p packet payload (msize)
+ msize=n the number of bytes to use for 9p packet payload
port=n port to connect to on the remote server
diff --git a/Documentation/filesystems/caching/object.txt b/Documentation/filesystems/caching/object.txt
index e8b0a35d8fe5..58313348da87 100644
--- a/Documentation/filesystems/caching/object.txt
+++ b/Documentation/filesystems/caching/object.txt
@@ -127,9 +127,9 @@ fscache_enqueue_object()).
PROVISION OF CPU TIME
---------------------
-The work to be done by the various states is given CPU time by the threads of
-the slow work facility (see Documentation/slow-work.txt). This is used in
-preference to the workqueue facility because:
+The work to be done by the various states was given CPU time by the threads of
+the slow work facility. This was used in preference to the workqueue facility
+because:
(1) Threads may be completely occupied for very long periods of time by a
particular work item. These state actions may be doing sequences of
diff --git a/Documentation/filesystems/locks.txt b/Documentation/filesystems/locks.txt
index fab857accbd6..2cf81082581d 100644
--- a/Documentation/filesystems/locks.txt
+++ b/Documentation/filesystems/locks.txt
@@ -53,11 +53,12 @@ fcntl(), with all the problems that implies.
1.3 Mandatory Locking As A Mount Option
---------------------------------------
-Mandatory locking, as described in 'Documentation/filesystems/mandatory.txt'
-was prior to this release a general configuration option that was valid for
-all mounted filesystems. This had a number of inherent dangers, not the
-least of which was the ability to freeze an NFS server by asking it to read
-a file for which a mandatory lock existed.
+Mandatory locking, as described in
+'Documentation/filesystems/mandatory-locking.txt' was prior to this release a
+general configuration option that was valid for all mounted filesystems. This
+had a number of inherent dangers, not the least of which was the ability to
+freeze an NFS server by asking it to read a file for which a mandatory lock
+existed.
From this release of the kernel, mandatory locking can be turned on and off
on a per-filesystem basis, using the mount options 'mand' and 'nomand'.
diff --git a/Documentation/filesystems/nfs/idmapper.txt b/Documentation/filesystems/nfs/idmapper.txt
index 9c8fd6148656..120fd3cf7fd9 100644
--- a/Documentation/filesystems/nfs/idmapper.txt
+++ b/Documentation/filesystems/nfs/idmapper.txt
@@ -47,7 +47,7 @@ request-key will find the first matching line and corresponding program. In
this case, /some/other/program will handle all uid lookups and
/usr/sbin/nfs.idmap will handle gid, user, and group lookups.
-See <file:Documentation/security/keys-request-keys.txt> for more information
+See <file:Documentation/security/keys-request-key.txt> for more information
about the request-key function.
diff --git a/Documentation/filesystems/pohmelfs/design_notes.txt b/Documentation/filesystems/pohmelfs/design_notes.txt
index dcf833587162..8aef91335701 100644
--- a/Documentation/filesystems/pohmelfs/design_notes.txt
+++ b/Documentation/filesystems/pohmelfs/design_notes.txt
@@ -58,8 +58,9 @@ data transfers.
POHMELFS clients operate with a working set of servers and are capable of balancing read-only
operations (like lookups or directory listings) between them according to IO priorities.
Administrators can add or remove servers from the set at run-time via special commands (described
-in Documentation/pohmelfs/info.txt file). Writes are replicated to all servers, which are connected
-with write permission turned on. IO priority and permissions can be changed in run-time.
+in Documentation/filesystems/pohmelfs/info.txt file). Writes are replicated to all servers, which
+are connected with write permission turned on. IO priority and permissions can be changed in
+run-time.
POHMELFS is capable of full data channel encryption and/or strong crypto hashing.
One can select any kernel supported cipher, encryption mode, hash type and operation mode
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index db3b1aba32a3..0ec91f03422e 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -1263,7 +1263,7 @@ review the kernel documentation in the directory /usr/src/linux/Documentation.
This chapter is heavily based on the documentation included in the pre 2.2
kernels, and became part of it in version 2.2.1 of the Linux kernel.
-Please see: Documentation/sysctls/ directory for descriptions of these
+Please see: Documentation/sysctl/ directory for descriptions of these
entries.
------------------------------------------------------------------------------
diff --git a/Documentation/filesystems/sysfs.txt b/Documentation/filesystems/sysfs.txt
index 597f728e7b4e..07235caec22c 100644
--- a/Documentation/filesystems/sysfs.txt
+++ b/Documentation/filesystems/sysfs.txt
@@ -4,7 +4,7 @@ sysfs - _The_ filesystem for exporting kernel objects.
Patrick Mochel <mochel@osdl.org>
Mike Murphy <mamurph@cs.clemson.edu>
-Revised: 15 July 2010
+Revised: 16 August 2011
Original: 10 January 2003
@@ -370,3 +370,11 @@ int driver_create_file(struct device_driver *, const struct driver_attribute *);
void driver_remove_file(struct device_driver *, const struct driver_attribute *);
+Documentation
+~~~~~~~~~~~~~
+
+The sysfs directory structure and the attributes in each directory define an
+ABI between the kernel and user space. As for any ABI, it is important that
+this ABI is stable and properly documented. All new sysfs attributes must be
+documented in Documentation/ABI. See also Documentation/ABI/README for more
+information.
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index 52d8fb81cfff..43cbd0821721 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -1053,9 +1053,6 @@ manipulate dentries:
and the dentry is returned. The caller must use dput()
to free the dentry when it finishes using it.
-For further information on dentry locking, please refer to the document
-Documentation/filesystems/dentry-locking.txt.
-
Mount Options
=============
diff --git a/Documentation/frv/booting.txt b/Documentation/frv/booting.txt
index 37c4d84a0e57..9bdf4b46e741 100644
--- a/Documentation/frv/booting.txt
+++ b/Documentation/frv/booting.txt
@@ -180,9 +180,3 @@ separated by spaces:
This tells the kernel what program to run initially. By default this is
/sbin/init, but /sbin/sash or /bin/sh are common alternatives.
-
- (*) vdc=...
-
- This option configures the MB93493 companion chip visual display
- driver. Please see Documentation/frv/mb93493/vdc.txt for more
- information.
diff --git a/Documentation/hwmon/ad7314 b/Documentation/hwmon/ad7314
new file mode 100644
index 000000000000..1912549c7467
--- /dev/null
+++ b/Documentation/hwmon/ad7314
@@ -0,0 +1,25 @@
+Kernel driver ad7314
+====================
+
+Supported chips:
+ * Analog Devices AD7314
+ Prefix: 'ad7314'
+ Datasheet: Publicly available at Analog Devices website.
+ * Analog Devices ADT7301
+ Prefix: 'adt7301'
+ Datasheet: Publicly available at Analog Devices website.
+ * Analog Devices ADT7302
+ Prefix: 'adt7302'
+ Datasheet: Publicly available at Analog Devices website.
+
+Description
+-----------
+
+Driver supports the above parts. The ad7314 has a 10 bit
+sensor with 1lsb = 0.25 degrees centigrade. The adt7301 and
+adt7302 have 14 bit sensors with 1lsb = 0.03125 degrees centigrade.
+
+Notes
+-----
+
+Currently power down mode is not supported.
diff --git a/Documentation/hwmon/adm1275 b/Documentation/hwmon/adm1275
index 097b3ccc4be7..ab70d96d2dfd 100644
--- a/Documentation/hwmon/adm1275
+++ b/Documentation/hwmon/adm1275
@@ -6,6 +6,10 @@ Supported chips:
Prefix: 'adm1275'
Addresses scanned: -
Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1275.pdf
+ * Analog Devices ADM1276
+ Prefix: 'adm1276'
+ Addresses scanned: -
+ Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1276.pdf
Author: Guenter Roeck <guenter.roeck@ericsson.com>
@@ -13,13 +17,13 @@ Author: Guenter Roeck <guenter.roeck@ericsson.com>
Description
-----------
-This driver supports hardware montoring for Analog Devices ADM1275 Hot-Swap
-Controller and Digital Power Monitor.
+This driver supports hardware montoring for Analog Devices ADM1275 and ADM1276
+Hot-Swap Controller and Digital Power Monitor.
-The ADM1275 is a hot-swap controller that allows a circuit board to be removed
-from or inserted into a live backplane. It also features current and voltage
-readback via an integrated 12-bit analog-to-digital converter (ADC), accessed
-using a PMBus. interface.
+ADM1275 and ADM1276 are hot-swap controllers that allow a circuit board to be
+removed from or inserted into a live backplane. They also feature current and
+voltage readback via an integrated 12-bit analog-to-digital converter (ADC),
+accessed using a PMBus interface.
The driver is a client driver to the core PMBus driver. Please see
Documentation/hwmon/pmbus for details on PMBus client drivers.
@@ -48,17 +52,25 @@ attributes are write-only, all other attributes are read-only.
in1_label "vin1" or "vout1" depending on chip variant and
configuration.
-in1_input Measured voltage. From READ_VOUT register.
-in1_min Minumum Voltage. From VOUT_UV_WARN_LIMIT register.
-in1_max Maximum voltage. From VOUT_OV_WARN_LIMIT register.
-in1_min_alarm Voltage low alarm. From VOLTAGE_UV_WARNING status.
-in1_max_alarm Voltage high alarm. From VOLTAGE_OV_WARNING status.
+in1_input Measured voltage.
+in1_min Minumum Voltage.
+in1_max Maximum voltage.
+in1_min_alarm Voltage low alarm.
+in1_max_alarm Voltage high alarm.
in1_highest Historical maximum voltage.
in1_reset_history Write any value to reset history.
curr1_label "iout1"
-curr1_input Measured current. From READ_IOUT register.
-curr1_max Maximum current. From IOUT_OC_WARN_LIMIT register.
-curr1_max_alarm Current high alarm. From IOUT_OC_WARN_LIMIT register.
+curr1_input Measured current.
+curr1_max Maximum current.
+curr1_max_alarm Current high alarm.
+curr1_lcrit Critical minimum current. Depending on the chip
+ configuration, either curr1_lcrit or curr1_crit is
+ supported, but not both.
+curr1_lcrit_alarm Critical current low alarm.
+curr1_crit Critical maximum current. Depending on the chip
+ configuration, either curr1_lcrit or curr1_crit is
+ supported, but not both.
+curr1_crit_alarm Critical current high alarm.
curr1_highest Historical maximum current.
curr1_reset_history Write any value to reset history.
diff --git a/Documentation/hwmon/coretemp b/Documentation/hwmon/coretemp
index fa8776ab9b18..84d46c0c71a3 100644
--- a/Documentation/hwmon/coretemp
+++ b/Documentation/hwmon/coretemp
@@ -35,13 +35,6 @@ the Out-Of-Spec bit. Following table summarizes the exported sysfs files:
All Sysfs entries are named with their core_id (represented here by 'X').
tempX_input - Core temperature (in millidegrees Celsius).
tempX_max - All cooling devices should be turned on (on Core2).
- Initialized with IA32_THERM_INTERRUPT. When the CPU
- temperature reaches this temperature, an interrupt is
- generated and tempX_max_alarm is set.
-tempX_max_hyst - If the CPU temperature falls below than temperature,
- an interrupt is generated and tempX_max_alarm is reset.
-tempX_max_alarm - Set if the temperature reaches or exceeds tempX_max.
- Reset if the temperature drops to or below tempX_max_hyst.
tempX_crit - Maximum junction temperature (in millidegrees Celsius).
tempX_crit_alarm - Set when Out-of-spec bit is set, never clears.
Correct CPU operation is no longer guaranteed.
@@ -49,9 +42,10 @@ tempX_label - Contains string "Core X", where X is processor
number. For Package temp, this will be "Physical id Y",
where Y is the package number.
-The TjMax temperature is set to 85 degrees C if undocumented model specific
-register (UMSR) 0xee has bit 30 set. If not the TjMax is 100 degrees C as
-(sometimes) documented in processor datasheet.
+On CPU models which support it, TjMax is read from a model-specific register.
+On other models, it is set to an arbitrary value based on weak heuristics.
+If these heuristics don't work for you, you can pass the correct TjMax value
+as a module parameter (tjmax).
Appendix A. Known TjMax lists (TBD):
Some information comes from ark.intel.com
diff --git a/Documentation/hwmon/exynos4_tmu b/Documentation/hwmon/exynos4_tmu
new file mode 100644
index 000000000000..c3c6b41db607
--- /dev/null
+++ b/Documentation/hwmon/exynos4_tmu
@@ -0,0 +1,81 @@
+Kernel driver exynos4_tmu
+=================
+
+Supported chips:
+* ARM SAMSUNG EXYNOS4 series of SoC
+ Prefix: 'exynos4-tmu'
+ Datasheet: Not publicly available
+
+Authors: Donggeun Kim <dg77.kim@samsung.com>
+
+Description
+-----------
+
+This driver allows to read temperature inside SAMSUNG EXYNOS4 series of SoC.
+
+The chip only exposes the measured 8-bit temperature code value
+through a register.
+Temperature can be taken from the temperature code.
+There are three equations converting from temperature to temperature code.
+
+The three equations are:
+ 1. Two point trimming
+ Tc = (T - 25) * (TI2 - TI1) / (85 - 25) + TI1
+
+ 2. One point trimming
+ Tc = T + TI1 - 25
+
+ 3. No trimming
+ Tc = T + 50
+
+ Tc: Temperature code, T: Temperature,
+ TI1: Trimming info for 25 degree Celsius (stored at TRIMINFO register)
+ Temperature code measured at 25 degree Celsius which is unchanged
+ TI2: Trimming info for 85 degree Celsius (stored at TRIMINFO register)
+ Temperature code measured at 85 degree Celsius which is unchanged
+
+TMU(Thermal Management Unit) in EXYNOS4 generates interrupt
+when temperature exceeds pre-defined levels.
+The maximum number of configurable threshold is four.
+The threshold levels are defined as follows:
+ Level_0: current temperature > trigger_level_0 + threshold
+ Level_1: current temperature > trigger_level_1 + threshold
+ Level_2: current temperature > trigger_level_2 + threshold
+ Level_3: current temperature > trigger_level_3 + threshold
+
+ The threshold and each trigger_level are set
+ through the corresponding registers.
+
+When an interrupt occurs, this driver notify user space of
+one of four threshold levels for the interrupt
+through kobject_uevent_env and sysfs_notify functions.
+Although an interrupt condition for level_0 can be set,
+it is not notified to user space through sysfs_notify function.
+
+Sysfs Interface
+---------------
+name name of the temperature sensor
+ RO
+
+temp1_input temperature
+ RO
+
+temp1_max temperature for level_1 interrupt
+ RO
+
+temp1_crit temperature for level_2 interrupt
+ RO
+
+temp1_emergency temperature for level_3 interrupt
+ RO
+
+temp1_max_alarm alarm for level_1 interrupt
+ RO
+
+temp1_crit_alarm
+ alarm for level_2 interrupt
+ RO
+
+temp1_emergency_alarm
+ alarm for level_3 interrupt
+ RO
diff --git a/Documentation/hwmon/lm75 b/Documentation/hwmon/lm75
index a1790401fdde..c91a1d15fa28 100644
--- a/Documentation/hwmon/lm75
+++ b/Documentation/hwmon/lm75
@@ -12,26 +12,46 @@ Supported chips:
Addresses scanned: I2C 0x48 - 0x4f
Datasheet: Publicly available at the National Semiconductor website
http://www.national.com/
- * Dallas Semiconductor DS75
- Prefix: 'lm75'
- Addresses scanned: I2C 0x48 - 0x4f
- Datasheet: Publicly available at the Dallas Semiconductor website
- http://www.maxim-ic.com/
- * Dallas Semiconductor DS1775
- Prefix: 'lm75'
- Addresses scanned: I2C 0x48 - 0x4f
+ * Dallas Semiconductor DS75, DS1775
+ Prefixes: 'ds75', 'ds1775'
+ Addresses scanned: none
Datasheet: Publicly available at the Dallas Semiconductor website
http://www.maxim-ic.com/
* Maxim MAX6625, MAX6626
- Prefix: 'lm75'
- Addresses scanned: I2C 0x48 - 0x4b
+ Prefixes: 'max6625', 'max6626'
+ Addresses scanned: none
Datasheet: Publicly available at the Maxim website
http://www.maxim-ic.com/
* Microchip (TelCom) TCN75
Prefix: 'lm75'
- Addresses scanned: I2C 0x48 - 0x4f
+ Addresses scanned: none
+ Datasheet: Publicly available at the Microchip website
+ http://www.microchip.com/
+ * Microchip MCP9800, MCP9801, MCP9802, MCP9803
+ Prefix: 'mcp980x'
+ Addresses scanned: none
Datasheet: Publicly available at the Microchip website
http://www.microchip.com/
+ * Analog Devices ADT75
+ Prefix: 'adt75'
+ Addresses scanned: none
+ Datasheet: Publicly available at the Analog Devices website
+ http://www.analog.com/adt75
+ * ST Microelectronics STDS75
+ Prefix: 'stds75'
+ Addresses scanned: none
+ Datasheet: Publicly available at the ST website
+ http://www.st.com/internet/analog/product/121769.jsp
+ * Texas Instruments TMP100, TMP101, TMP105, TMP75, TMP175, TMP275
+ Prefixes: 'tmp100', 'tmp101', 'tmp105', 'tmp175', 'tmp75', 'tmp275'
+ Addresses scanned: none
+ Datasheet: Publicly available at the Texas Instruments website
+ http://www.ti.com/product/tmp100
+ http://www.ti.com/product/tmp101
+ http://www.ti.com/product/tmp105
+ http://www.ti.com/product/tmp75
+ http://www.ti.com/product/tmp175
+ http://www.ti.com/product/tmp275
Author: Frodo Looijaard <frodol@dds.nl>
@@ -50,21 +70,16 @@ range of -55 to +125 degrees.
The LM75 only updates its values each 1.5 seconds; reading it more often
will do no harm, but will return 'old' values.
-The LM75 is usually used in combination with LM78-like chips, to measure
-the temperature of the processor(s).
-
-The DS75, DS1775, MAX6625, and MAX6626 are supported as well.
-They are not distinguished from an LM75. While most of these chips
-have three additional bits of accuracy (12 vs. 9 for the LM75),
-the additional bits are not supported. Not only that, but these chips will
-not be detected if not in 9-bit precision mode (use the force parameter if
-needed).
-
-The TCN75 is supported as well, and is not distinguished from an LM75.
+The original LM75 was typically used in combination with LM78-like chips
+on PC motherboards, to measure the temperature of the processor(s). Clones
+are now used in various embedded designs.
The LM75 is essentially an industry standard; there may be other
LM75 clones not listed here, with or without various enhancements,
-that are supported.
+that are supported. The clones are not detected by the driver, unless
+they reproduce the exact register tricks of the original LM75, and must
+therefore be instantiated explicitly. The specific enhancements (such as
+higher resolution) are not currently supported by the driver.
The LM77 is not supported, contrary to what we pretended for a long time.
Both chips are simply not compatible, value encoding differs.
diff --git a/Documentation/hwmon/ltc2978 b/Documentation/hwmon/ltc2978
new file mode 100644
index 000000000000..c365f9beb5dd
--- /dev/null
+++ b/Documentation/hwmon/ltc2978
@@ -0,0 +1,103 @@
+Kernel driver ltc2978
+=====================
+
+Supported chips:
+ * Linear Technology LTC2978
+ Prefix: 'ltc2978'
+ Addresses scanned: -
+ Datasheet: http://cds.linear.com/docs/Datasheet/2978fa.pdf
+ * Linear Technology LTC3880
+ Prefix: 'ltc3880'
+ Addresses scanned: -
+ Datasheet: http://cds.linear.com/docs/Datasheet/3880f.pdf
+
+Author: Guenter Roeck <guenter.roeck@ericsson.com>
+
+
+Description
+-----------
+
+The LTC2978 is an octal power supply monitor, supervisor, sequencer and
+margin controller. The LTC3880 is a dual, PolyPhase DC/DC synchronous
+step-down switching regulator controller.
+
+
+Usage Notes
+-----------
+
+This driver does not probe for PMBus devices. You will have to instantiate
+devices explicitly.
+
+Example: the following commands will load the driver for an LTC2978 at address
+0x60 on I2C bus #1:
+
+# modprobe ltc2978
+# echo ltc2978 0x60 > /sys/bus/i2c/devices/i2c-1/new_device
+
+
+Sysfs attributes
+----------------
+
+in1_label "vin"
+in1_input Measured input voltage.
+in1_min Minimum input voltage.
+in1_max Maximum input voltage.
+in1_lcrit Critical minimum input voltage.
+in1_crit Critical maximum input voltage.
+in1_min_alarm Input voltage low alarm.
+in1_max_alarm Input voltage high alarm.
+in1_lcrit_alarm Input voltage critical low alarm.
+in1_crit_alarm Input voltage critical high alarm.
+in1_lowest Lowest input voltage. LTC2978 only.
+in1_highest Highest input voltage.
+in1_reset_history Reset history. Writing into this attribute will reset
+ history for all attributes.
+
+in[2-9]_label "vout[1-8]". Channels 3 to 9 on LTC2978 only.
+in[2-9]_input Measured output voltage.
+in[2-9]_min Minimum output voltage.
+in[2-9]_max Maximum output voltage.
+in[2-9]_lcrit Critical minimum output voltage.
+in[2-9]_crit Critical maximum output voltage.
+in[2-9]_min_alarm Output voltage low alarm.
+in[2-9]_max_alarm Output voltage high alarm.
+in[2-9]_lcrit_alarm Output voltage critical low alarm.
+in[2-9]_crit_alarm Output voltage critical high alarm.
+in[2-9]_lowest Lowest output voltage. LTC2978 only.
+in[2-9]_highest Lowest output voltage.
+in[2-9]_reset_history Reset history. Writing into this attribute will reset
+ history for all attributes.
+
+temp[1-3]_input Measured temperature.
+ On LTC2978, only one temperature measurement is
+ supported and reflects the internal temperature.
+ On LTC3880, temp1 and temp2 report external
+ temperatures, and temp3 reports the internal
+ temperature.
+temp[1-3]_min Mimimum temperature.
+temp[1-3]_max Maximum temperature.
+temp[1-3]_lcrit Critical low temperature.
+temp[1-3]_crit Critical high temperature.
+temp[1-3]_min_alarm Chip temperature low alarm.
+temp[1-3]_max_alarm Chip temperature high alarm.
+temp[1-3]_lcrit_alarm Chip temperature critical low alarm.
+temp[1-3]_crit_alarm Chip temperature critical high alarm.
+temp[1-3]_lowest Lowest measured temperature. LTC2978 only.
+temp[1-3]_highest Highest measured temperature.
+temp[1-3]_reset_history Reset history. Writing into this attribute will reset
+ history for all attributes.
+
+power[1-2]_label "pout[1-2]". LTC3880 only.
+power[1-2]_input Measured power.
+
+curr1_label "iin". LTC3880 only.
+curr1_input Measured input current.
+curr1_max Maximum input current.
+curr1_max_alarm Input current high alarm.
+
+curr[2-3]_label "iout[1-2]". LTC3880 only.
+curr[2-3]_input Measured input current.
+curr[2-3]_max Maximum input current.
+curr[2-3]_crit Critical input current.
+curr[2-3]_max_alarm Input current high alarm.
+curr[2-3]_crit_alarm Input current critical high alarm.
diff --git a/Documentation/hwmon/max16065 b/Documentation/hwmon/max16065
index 44b4f61e04f9..c11f64a1f2ad 100644
--- a/Documentation/hwmon/max16065
+++ b/Documentation/hwmon/max16065
@@ -62,6 +62,13 @@ can be safely used to identify the chip. You will have to instantiate
the devices explicitly. Please see Documentation/i2c/instantiating-devices for
details.
+WARNING: Do not access chip registers using the i2cdump command, and do not use
+any of the i2ctools commands on a command register (0xa5 to 0xac). The chips
+supported by this driver interpret any access to a command register (including
+read commands) as request to execute the command in question. This may result in
+power loss, board resets, and/or Flash corruption. Worst case, your board may
+turn into a brick.
+
Sysfs entries
-------------
diff --git a/Documentation/hwmon/pmbus b/Documentation/hwmon/pmbus
index c36c1c1a62bb..15ac911ce51b 100644
--- a/Documentation/hwmon/pmbus
+++ b/Documentation/hwmon/pmbus
@@ -8,11 +8,6 @@ Supported chips:
Addresses scanned: -
Datasheet:
http://archive.ericsson.net/service/internet/picov/get?DocNo=28701-EN/LZT146395
- * Linear Technology LTC2978
- Octal PMBus Power Supply Monitor and Controller
- Prefix: 'ltc2978'
- Addresses scanned: -
- Datasheet: http://cds.linear.com/docs/Datasheet/2978fa.pdf
* ON Semiconductor ADP4000, NCP4200, NCP4208
Prefixes: 'adp4000', 'ncp4200', 'ncp4208'
Addresses scanned: -
@@ -20,6 +15,14 @@ Supported chips:
http://www.onsemi.com/pub_link/Collateral/ADP4000-D.PDF
http://www.onsemi.com/pub_link/Collateral/NCP4200-D.PDF
http://www.onsemi.com/pub_link/Collateral/JUNE%202009-%20REV.%200.PDF
+ * Lineage Power
+ Prefixes: 'pdt003', 'pdt006', 'pdt012', 'udt020'
+ Addresses scanned: -
+ Datasheets:
+ http://www.lineagepower.com/oem/pdf/PDT003A0X.pdf
+ http://www.lineagepower.com/oem/pdf/PDT006A0X.pdf
+ http://www.lineagepower.com/oem/pdf/PDT012A0X.pdf
+ http://www.lineagepower.com/oem/pdf/UDT020A0X.pdf
* Generic PMBus devices
Prefix: 'pmbus'
Addresses scanned: -
diff --git a/Documentation/hwmon/pmbus-core b/Documentation/hwmon/pmbus-core
new file mode 100644
index 000000000000..31e4720fed18
--- /dev/null
+++ b/Documentation/hwmon/pmbus-core
@@ -0,0 +1,283 @@
+PMBus core driver and internal API
+==================================
+
+Introduction
+============
+
+[from pmbus.org] The Power Management Bus (PMBus) is an open standard
+power-management protocol with a fully defined command language that facilitates
+communication with power converters and other devices in a power system. The
+protocol is implemented over the industry-standard SMBus serial interface and
+enables programming, control, and real-time monitoring of compliant power
+conversion products. This flexible and highly versatile standard allows for
+communication between devices based on both analog and digital technologies, and
+provides true interoperability which will reduce design complexity and shorten
+time to market for power system designers. Pioneered by leading power supply and
+semiconductor companies, this open power system standard is maintained and
+promoted by the PMBus Implementers Forum (PMBus-IF), comprising 30+ adopters
+with the objective to provide support to, and facilitate adoption among, users.
+
+Unfortunately, while PMBus commands are standardized, there are no mandatory
+commands, and manufacturers can add as many non-standard commands as they like.
+Also, different PMBUs devices act differently if non-supported commands are
+executed. Some devices return an error, some devices return 0xff or 0xffff and
+set a status error flag, and some devices may simply hang up.
+
+Despite all those difficulties, a generic PMBus device driver is still useful
+and supported since kernel version 2.6.39. However, it was necessary to support
+device specific extensions in addition to the core PMBus driver, since it is
+simply unknown what new device specific functionality PMBus device developers
+come up with next.
+
+To make device specific extensions as scalable as possible, and to avoid having
+to modify the core PMBus driver repeatedly for new devices, the PMBus driver was
+split into core, generic, and device specific code. The core code (in
+pmbus_core.c) provides generic functionality. The generic code (in pmbus.c)
+provides support for generic PMBus devices. Device specific code is responsible
+for device specific initialization and, if needed, maps device specific
+functionality into generic functionality. This is to some degree comparable
+to PCI code, where generic code is augmented as needed with quirks for all kinds
+of devices.
+
+PMBus device capabilities auto-detection
+========================================
+
+For generic PMBus devices, code in pmbus.c attempts to auto-detect all supported
+PMBus commands. Auto-detection is somewhat limited, since there are simply too
+many variables to consider. For example, it is almost impossible to autodetect
+which PMBus commands are paged and which commands are replicated across all
+pages (see the PMBus specification for details on multi-page PMBus devices).
+
+For this reason, it often makes sense to provide a device specific driver if not
+all commands can be auto-detected. The data structures in this driver can be
+used to inform the core driver about functionality supported by individual
+chips.
+
+Some commands are always auto-detected. This applies to all limit commands
+(lcrit, min, max, and crit attributes) as well as associated alarm attributes.
+Limits and alarm attributes are auto-detected because there are simply too many
+possible combinations to provide a manual configuration interface.
+
+PMBus internal API
+==================
+
+The API between core and device specific PMBus code is defined in
+drivers/hwmon/pmbus/pmbus.h. In addition to the internal API, pmbus.h defines
+standard PMBus commands and virtual PMBus commands.
+
+Standard PMBus commands
+-----------------------
+
+Standard PMBus commands (commands values 0x00 to 0xff) are defined in the PMBUs
+specification.
+
+Virtual PMBus commands
+----------------------
+
+Virtual PMBus commands are provided to enable support for non-standard
+functionality which has been implemented by several chip vendors and is thus
+desirable to support.
+
+Virtual PMBus commands start with command value 0x100 and can thus easily be
+distinguished from standard PMBus commands (which can not have values larger
+than 0xff). Support for virtual PMBus commands is device specific and thus has
+to be implemented in device specific code.
+
+Virtual commands are named PMBUS_VIRT_xxx and start with PMBUS_VIRT_BASE. All
+virtual commands are word sized.
+
+There are currently two types of virtual commands.
+
+- READ commands are read-only; writes are either ignored or return an error.
+- RESET commands are read/write. Reading reset registers returns zero
+ (used for detection), writing any value causes the associated history to be
+ reset.
+
+Virtual commands have to be handled in device specific driver code. Chip driver
+code returns non-negative values if a virtual command is supported, or a
+negative error code if not. The chip driver may return -ENODATA or any other
+Linux error code in this case, though an error code other than -ENODATA is
+handled more efficiently and thus preferred. Either case, the calling PMBus
+core code will abort if the chip driver returns an error code when reading
+or writing virtual registers (in other words, the PMBus core code will never
+send a virtual command to a chip).
+
+PMBus driver information
+------------------------
+
+PMBus driver information, defined in struct pmbus_driver_info, is the main means
+for device specific drivers to pass information to the core PMBus driver.
+Specifically, it provides the following information.
+
+- For devices supporting its data in Direct Data Format, it provides coefficients
+ for converting register values into normalized data. This data is usually
+ provided by chip manufacturers in device datasheets.
+- Supported chip functionality can be provided to the core driver. This may be
+ necessary for chips which react badly if non-supported commands are executed,
+ and/or to speed up device detection and initialization.
+- Several function entry points are provided to support overriding and/or
+ augmenting generic command execution. This functionality can be used to map
+ non-standard PMBus commands to standard commands, or to augment standard
+ command return values with device specific information.
+
+ API functions
+ -------------
+
+ Functions provided by chip driver
+ ---------------------------------
+
+ All functions return the command return value (read) or zero (write) if
+ successful. A return value of -ENODATA indicates that there is no manufacturer
+ specific command, but that a standard PMBus command may exist. Any other
+ negative return value indicates that the commands does not exist for this
+ chip, and that no attempt should be made to read or write the standard
+ command.
+
+ As mentioned above, an exception to this rule applies to virtual commands,
+ which _must_ be handled in driver specific code. See "Virtual PMBus Commands"
+ above for more details.
+
+ Command execution in the core PMBus driver code is as follows.
+
+ if (chip_access_function) {
+ status = chip_access_function();
+ if (status != -ENODATA)
+ return status;
+ }
+ if (command >= PMBUS_VIRT_BASE) /* For word commands/registers only */
+ return -EINVAL;
+ return generic_access();
+
+ Chip drivers may provide pointers to the following functions in struct
+ pmbus_driver_info. All functions are optional.
+
+ int (*read_byte_data)(struct i2c_client *client, int page, int reg);
+
+ Read byte from page <page>, register <reg>.
+ <page> may be -1, which means "current page".
+
+ int (*read_word_data)(struct i2c_client *client, int page, int reg);
+
+ Read word from page <page>, register <reg>.
+
+ int (*write_word_data)(struct i2c_client *client, int page, int reg,
+ u16 word);
+
+ Write word to page <page>, register <reg>.
+
+ int (*write_byte)(struct i2c_client *client, int page, u8 value);
+
+ Write byte to page <page>, register <reg>.
+ <page> may be -1, which means "current page".
+
+ int (*identify)(struct i2c_client *client, struct pmbus_driver_info *info);
+
+ Determine supported PMBus functionality. This function is only necessary
+ if a chip driver supports multiple chips, and the chip functionality is not
+ pre-determined. It is currently only used by the generic pmbus driver
+ (pmbus.c).
+
+ Functions exported by core driver
+ ---------------------------------
+
+ Chip drivers are expected to use the following functions to read or write
+ PMBus registers. Chip drivers may also use direct I2C commands. If direct I2C
+ commands are used, the chip driver code must not directly modify the current
+ page, since the selected page is cached in the core driver and the core driver
+ will assume that it is selected. Using pmbus_set_page() to select a new page
+ is mandatory.
+
+ int pmbus_set_page(struct i2c_client *client, u8 page);
+
+ Set PMBus page register to <page> for subsequent commands.
+
+ int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg);
+
+ Read word data from <page>, <reg>. Similar to i2c_smbus_read_word_data(), but
+ selects page first.
+
+ int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg,
+ u16 word);
+
+ Write word data to <page>, <reg>. Similar to i2c_smbus_write_word_data(), but
+ selects page first.
+
+ int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg);
+
+ Read byte data from <page>, <reg>. Similar to i2c_smbus_read_byte_data(), but
+ selects page first. <page> may be -1, which means "current page".
+
+ int pmbus_write_byte(struct i2c_client *client, int page, u8 value);
+
+ Write byte data to <page>, <reg>. Similar to i2c_smbus_write_byte(), but
+ selects page first. <page> may be -1, which means "current page".
+
+ void pmbus_clear_faults(struct i2c_client *client);
+
+ Execute PMBus "Clear Fault" command on all chip pages.
+ This function calls the device specific write_byte function if defined.
+ Therefore, it must _not_ be called from that function.
+
+ bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg);
+
+ Check if byte register exists. Return true if the register exists, false
+ otherwise.
+ This function calls the device specific write_byte function if defined to
+ obtain the chip status. Therefore, it must _not_ be called from that function.
+
+ bool pmbus_check_word_register(struct i2c_client *client, int page, int reg);
+
+ Check if word register exists. Return true if the register exists, false
+ otherwise.
+ This function calls the device specific write_byte function if defined to
+ obtain the chip status. Therefore, it must _not_ be called from that function.
+
+ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
+ struct pmbus_driver_info *info);
+
+ Execute probe function. Similar to standard probe function for other drivers,
+ with the pointer to struct pmbus_driver_info as additional argument. Calls
+ identify function if supported. Must only be called from device probe
+ function.
+
+ void pmbus_do_remove(struct i2c_client *client);
+
+ Execute driver remove function. Similar to standard driver remove function.
+
+ const struct pmbus_driver_info
+ *pmbus_get_driver_info(struct i2c_client *client);
+
+ Return pointer to struct pmbus_driver_info as passed to pmbus_do_probe().
+
+
+PMBus driver platform data
+==========================
+
+PMBus platform data is defined in include/linux/i2c/pmbus.h. Platform data
+currently only provides a flag field with a single bit used.
+
+#define PMBUS_SKIP_STATUS_CHECK (1 << 0)
+
+struct pmbus_platform_data {
+ u32 flags; /* Device specific flags */
+};
+
+
+Flags
+-----
+
+PMBUS_SKIP_STATUS_CHECK
+
+During register detection, skip checking the status register for
+communication or command errors.
+
+Some PMBus chips respond with valid data when trying to read an unsupported
+register. For such chips, checking the status register is mandatory when
+trying to determine if a chip register exists or not.
+Other PMBus chips don't support the STATUS_CML register, or report
+communication errors for no explicable reason. For such chips, checking the
+status register must be disabled.
+
+Some i2c controllers do not support single-byte commands (write commands with
+no data, i2c_smbus_write_byte()). With such controllers, clearing the status
+register is impossible, and the PMBUS_SKIP_STATUS_CHECK flag must be set.
diff --git a/Documentation/hwmon/zl6100 b/Documentation/hwmon/zl6100
new file mode 100644
index 000000000000..7617798b5c97
--- /dev/null
+++ b/Documentation/hwmon/zl6100
@@ -0,0 +1,125 @@
+Kernel driver zl6100
+====================
+
+Supported chips:
+ * Intersil / Zilker Labs ZL2004
+ Prefix: 'zl2004'
+ Addresses scanned: -
+ Datasheet: http://www.intersil.com/data/fn/fn6847.pdf
+ * Intersil / Zilker Labs ZL2006
+ Prefix: 'zl2006'
+ Addresses scanned: -
+ Datasheet: http://www.intersil.com/data/fn/fn6850.pdf
+ * Intersil / Zilker Labs ZL2008
+ Prefix: 'zl2008'
+ Addresses scanned: -
+ Datasheet: http://www.intersil.com/data/fn/fn6859.pdf
+ * Intersil / Zilker Labs ZL2105
+ Prefix: 'zl2105'
+ Addresses scanned: -
+ Datasheet: http://www.intersil.com/data/fn/fn6851.pdf
+ * Intersil / Zilker Labs ZL2106
+ Prefix: 'zl2106'
+ Addresses scanned: -
+ Datasheet: http://www.intersil.com/data/fn/fn6852.pdf
+ * Intersil / Zilker Labs ZL6100
+ Prefix: 'zl6100'
+ Addresses scanned: -
+ Datasheet: http://www.intersil.com/data/fn/fn6876.pdf
+ * Intersil / Zilker Labs ZL6105
+ Prefix: 'zl6105'
+ Addresses scanned: -
+ Datasheet: http://www.intersil.com/data/fn/fn6906.pdf
+
+Author: Guenter Roeck <guenter.roeck@ericsson.com>
+
+
+Description
+-----------
+
+This driver supports hardware montoring for Intersil / Zilker Labs ZL6100 and
+compatible digital DC-DC controllers.
+
+The driver is a client driver to the core PMBus driver. Please see
+Documentation/hwmon/pmbus and Documentation.hwmon/pmbus-core for details
+on PMBus client drivers.
+
+
+Usage Notes
+-----------
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices for
+details.
+
+WARNING: Do not access chip registers using the i2cdump command, and do not use
+any of the i2ctools commands on a command register used to save and restore
+configuration data (0x11, 0x12, 0x15, 0x16, and 0xf4). The chips supported by
+this driver interpret any access to those command registers (including read
+commands) as request to execute the command in question. Unless write accesses
+to those registers are protected, this may result in power loss, board resets,
+and/or Flash corruption. Worst case, your board may turn into a brick.
+
+
+Platform data support
+---------------------
+
+The driver supports standard PMBus driver platform data.
+
+
+Module parameters
+-----------------
+
+delay
+-----
+
+Some Intersil/Zilker Labs DC-DC controllers require a minimum interval between
+I2C bus accesses. According to Intersil, the minimum interval is 2 ms, though
+1 ms appears to be sufficient and has not caused any problems in testing.
+The problem is known to affect ZL6100, ZL2105, and ZL2008. It is known not to
+affect ZL2004 and ZL6105. The driver automatically sets the interval to 1 ms
+except for ZL2004 and ZL6105. To enable manual override, the driver provides a
+writeable module parameter, 'delay', which can be used to set the interval to
+a value between 0 and 65,535 microseconds.
+
+
+Sysfs entries
+-------------
+
+The following attributes are supported. Limits are read-write; all other
+attributes are read-only.
+
+in1_label "vin"
+in1_input Measured input voltage.
+in1_min Minimum input voltage.
+in1_max Maximum input voltage.
+in1_lcrit Critical minumum input voltage.
+in1_crit Critical maximum input voltage.
+in1_min_alarm Input voltage low alarm.
+in1_max_alarm Input voltage high alarm.
+in1_lcrit_alarm Input voltage critical low alarm.
+in1_crit_alarm Input voltage critical high alarm.
+
+in2_label "vout1"
+in2_input Measured output voltage.
+in2_lcrit Critical minumum output Voltage.
+in2_crit Critical maximum output voltage.
+in2_lcrit_alarm Critical output voltage critical low alarm.
+in2_crit_alarm Critical output voltage critical high alarm.
+
+curr1_label "iout1"
+curr1_input Measured output current.
+curr1_lcrit Critical minimum output current.
+curr1_crit Critical maximum output current.
+curr1_lcrit_alarm Output current critical low alarm.
+curr1_crit_alarm Output current critical high alarm.
+
+temp[12]_input Measured temperature.
+temp[12]_min Minimum temperature.
+temp[12]_max Maximum temperature.
+temp[12]_lcrit Critical low temperature.
+temp[12]_crit Critical high temperature.
+temp[12]_min_alarm Chip temperature low alarm.
+temp[12]_max_alarm Chip temperature high alarm.
+temp[12]_lcrit_alarm Chip temperature critical low alarm.
+temp[12]_crit_alarm Chip temperature critical high alarm.
diff --git a/Documentation/input/input.txt b/Documentation/input/input.txt
index b93c08442e3c..b3d6787b4fb1 100644
--- a/Documentation/input/input.txt
+++ b/Documentation/input/input.txt
@@ -111,7 +111,7 @@ LCDs and many other purposes.
The monitor and speaker controls should be easy to add to the hid/input
interface, but for the UPSs and LCDs it doesn't make much sense. For this,
-the hiddev interface was designed. See Documentation/usb/hiddev.txt
+the hiddev interface was designed. See Documentation/hid/hiddev.txt
for more information about it.
The usage of the usbhid module is very simple, it takes no parameters,
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 845a191004b1..54078ed96b37 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -319,4 +319,6 @@ Code Seq#(hex) Include File Comments
<mailto:thomas@winischhofer.net>
0xF4 00-1F video/mbxfb.h mbxfb
<mailto:raph@8d.com>
+0xF6 all LTTng Linux Trace Toolkit Next Generation
+ <mailto:mathieu.desnoyers@efficios.com>
0xFD all linux/dm-ioctl.h
diff --git a/Documentation/kernel-docs.txt b/Documentation/kernel-docs.txt
index 0e0734b509d8..eda1eb1451a0 100644
--- a/Documentation/kernel-docs.txt
+++ b/Documentation/kernel-docs.txt
@@ -300,7 +300,7 @@
* Title: "The Kernel Hacking HOWTO"
Author: Various Talented People, and Rusty.
- Location: in kernel tree, Documentation/DocBook/kernel-hacking/
+ Location: in kernel tree, Documentation/DocBook/kernel-hacking.tmpl
(must be built as "make {htmldocs | psdocs | pdfdocs})
Keywords: HOWTO, kernel contexts, deadlock, locking, modules,
symbols, return conventions.
@@ -351,7 +351,7 @@
* Title: "Linux Kernel Locking HOWTO"
Author: Various Talented People, and Rusty.
- Location: in kernel tree, Documentation/DocBook/kernel-locking/
+ Location: in kernel tree, Documentation/DocBook/kernel-locking.tmpl
(must be built as "make {htmldocs | psdocs | pdfdocs})
Keywords: locks, locking, spinlock, semaphore, atomic, race
condition, bottom halves, tasklets, softirqs.
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 614d0382e2cb..2af94a23a6a4 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -49,6 +49,7 @@ parameter is applicable:
EDD BIOS Enhanced Disk Drive Services (EDD) is enabled
EFI EFI Partitioning (GPT) is enabled
EIDE EIDE/ATAPI support is enabled.
+ EVM Extended Verification Module
FB The frame buffer device is enabled.
FTRACE Function tracing enabled.
GCOV GCOV profiling is enabled.
@@ -163,7 +164,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
rsdt -- prefer RSDT over (default) XSDT
copy_dsdt -- copy DSDT to memory
- See also Documentation/power/pm.txt, pci=noacpi
+ See also Documentation/power/runtime_pm.txt, pci=noacpi
acpi_rsdp= [ACPI,EFI,KEXEC]
Pass the RSDP address to the kernel, mostly used
@@ -319,7 +320,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
amijoy.map= [HW,JOY] Amiga joystick support
Map of devices attached to JOY0DAT and JOY1DAT
Format: <a>,<b>
- See also Documentation/kernel/input/joystick.txt
+ See also Documentation/input/joystick.txt
analog.map= [HW,JOY] Analog joystick and gamepad support
Specifies type or capabilities of an analog joystick
@@ -408,7 +409,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
bttv.radio= Most important insmod options are available as
kernel args too.
bttv.pll= See Documentation/video4linux/bttv/Insmod-options
- bttv.tuner= and Documentation/video4linux/bttv/CARDLIST
+ bttv.tuner=
bulk_remove=off [PPC] This parameter disables the use of the pSeries
firmware feature for flushing multiple hpte entries
@@ -724,7 +725,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
elevator= [IOSCHED]
Format: {"cfq" | "deadline" | "noop"}
- See Documentation/block/as-iosched.txt and
+ See Documentation/block/cfq-iosched.txt and
Documentation/block/deadline-iosched.txt for details.
elfcorehdr= [IA-64,PPC,SH,X86]
@@ -760,12 +761,17 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
This option is obsoleted by the "netdev=" option, which
has equivalent usage. See its documentation for details.
+ evm= [EVM]
+ Format: { "fix" }
+ Permit 'security.evm' to be updated regardless of
+ current integrity status.
+
failslab=
fail_page_alloc=
fail_make_request=[KNL]
General fault injection mechanism.
Format: <interval>,<probability>,<space>,<times>
- See also /Documentation/fault-injection/.
+ See also Documentation/fault-injection/.
floppy= [HW]
See Documentation/blockdev/floppy.txt.
@@ -2086,9 +2092,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
Override pmtimer IOPort with a hex value.
e.g. pmtmr=0x508
- pnp.debug [PNP]
- Enable PNP debug messages. This depends on the
- CONFIG_PNP_DEBUG_MESSAGES option.
+ pnp.debug=1 [PNP]
+ Enable PNP debug messages (depends on the
+ CONFIG_PNP_DEBUG_MESSAGES option). Change at run-time
+ via /sys/module/pnp/parameters/debug. We always show
+ current resource usage; turning this on also shows
+ possible settings and some assignment information.
pnpacpi= [ACPI]
{ off }
@@ -2237,6 +2246,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
in <PAGE_SIZE> units (needed only for swap files).
See Documentation/power/swsusp-and-swap-files.txt
+ resumedelay= [HIBERNATION] Delay (in seconds) to pause before attempting to
+ read the resume files
+
+ resumewait [HIBERNATION] Wait (indefinitely) for resume device to show up.
+ Useful for devices that are detected asynchronously
+ (e.g. USB and MMC devices).
+
hibernate= [HIBERNATION]
noresume Don't check if there's a hibernation image
present during boot.
@@ -2372,7 +2388,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
Format: <integer>
sonypi.*= [HW] Sony Programmable I/O Control Device driver
- See Documentation/sonypi.txt
+ See Documentation/laptops/sonypi.txt
specialix= [HW,SERIAL] Specialix multi-serial port adapter
See Documentation/serial/specialix.txt.
@@ -2703,10 +2719,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
functions are at fixed addresses, they make nice
targets for exploits that can control RIP.
- emulate [default] Vsyscalls turn into traps and are
- emulated reasonably safely.
+ emulate Vsyscalls turn into traps and are emulated
+ reasonably safely.
- native Vsyscalls are native syscall instructions.
+ native [default] Vsyscalls are native syscall
+ instructions.
This is a little bit faster than trapping
and makes a few dynamic recompilers work
better than they would in emulation mode.
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
index 61815483efa3..3ff0dad62d36 100644
--- a/Documentation/laptops/thinkpad-acpi.txt
+++ b/Documentation/laptops/thinkpad-acpi.txt
@@ -736,7 +736,7 @@ status as "unknown". The available commands are:
sysfs notes:
The ThinkLight sysfs interface is documented by the LED class
-documentation, in Documentation/leds-class.txt. The ThinkLight LED name
+documentation, in Documentation/leds/leds-class.txt. The ThinkLight LED name
is "tpacpi::thinklight".
Due to limitations in the sysfs LED class, if the status of the ThinkLight
@@ -833,7 +833,7 @@ All of the above can be turned on and off and can be made to blink.
sysfs notes:
The ThinkPad LED sysfs interface is described in detail by the LED class
-documentation, in Documentation/leds-class.txt.
+documentation, in Documentation/leds/leds-class.txt.
The LEDs are named (in LED ID order, from 0 to 12):
"tpacpi::power", "tpacpi:orange:batt", "tpacpi:green:batt",
diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
index 669b5fb03a86..3a0f879533ce 100644
--- a/Documentation/media-framework.txt
+++ b/Documentation/media-framework.txt
@@ -9,8 +9,8 @@ Introduction
------------
The media controller API is documented in DocBook format in
-Documentation/DocBook/v4l/media-controller.xml. This document will focus on
-the kernel-side implementation of the media framework.
+Documentation/DocBook/media/v4l/media-controller.xml. This document will focus
+on the kernel-side implementation of the media framework.
Abstract media device model
diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt
index f0d3a8026a56..2759f7c188f0 100644
--- a/Documentation/memory-barriers.txt
+++ b/Documentation/memory-barriers.txt
@@ -438,7 +438,7 @@ There are certain things that the Linux kernel memory barriers do not guarantee:
[*] For information on bus mastering DMA and coherency please read:
Documentation/PCI/pci.txt
- Documentation/PCI/PCI-DMA-mapping.txt
+ Documentation/DMA-API-HOWTO.txt
Documentation/DMA-API.txt
diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX
index 4edd78dfb362..bbce1215434a 100644
--- a/Documentation/networking/00-INDEX
+++ b/Documentation/networking/00-INDEX
@@ -1,13 +1,21 @@
00-INDEX
- this file
+3c359.txt
+ - information on the 3Com TokenLink Velocity XL (3c5359) driver.
3c505.txt
- information on the 3Com EtherLink Plus (3c505) driver.
+3c509.txt
+ - information on the 3Com Etherlink III Series Ethernet cards.
6pack.txt
- info on the 6pack protocol, an alternative to KISS for AX.25
DLINK.txt
- info on the D-Link DE-600/DE-620 parallel port pocket adapters
PLIP.txt
- PLIP: The Parallel Line Internet Protocol device driver
+README.ipw2100
+ - README for the Intel PRO/Wireless 2100 driver.
+README.ipw2200
+ - README for the Intel PRO/Wireless 2915ABG and 2200BG driver.
README.sb1000
- info on General Instrument/NextLevel SURFboard1000 cable modem.
alias.txt
@@ -20,8 +28,12 @@ atm.txt
- info on where to get ATM programs and support for Linux.
ax25.txt
- info on using AX.25 and NET/ROM code for Linux
+batman-adv.txt
+ - B.A.T.M.A.N routing protocol on top of layer 2 Ethernet Frames.
baycom.txt
- info on the driver for Baycom style amateur radio modems
+bonding.txt
+ - Linux Ethernet Bonding Driver HOWTO: link aggregation in Linux.
bridge.txt
- where to get user space programs for ethernet bridging with Linux.
can.txt
@@ -34,32 +46,60 @@ cxacru.txt
- Conexant AccessRunner USB ADSL Modem
cxacru-cf.py
- Conexant AccessRunner USB ADSL Modem configuration file parser
+cxgb.txt
+ - Release Notes for the Chelsio N210 Linux device driver.
+dccp.txt
+ - the Datagram Congestion Control Protocol (DCCP) (RFC 4340..42).
de4x5.txt
- the Digital EtherWORKS DE4?? and DE5?? PCI Ethernet driver
decnet.txt
- info on using the DECnet networking layer in Linux.
depca.txt
- the Digital DEPCA/EtherWORKS DE1?? and DE2?? LANCE Ethernet driver
+dl2k.txt
+ - README for D-Link DL2000-based Gigabit Ethernet Adapters (dl2k.ko).
+dm9000.txt
+ - README for the Simtec DM9000 Network driver.
dmfe.txt
- info on the Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver.
+dns_resolver.txt
+ - The DNS resolver module allows kernel servies to make DNS queries.
+driver.txt
+ - Softnet driver issues.
e100.txt
- info on Intel's EtherExpress PRO/100 line of 10/100 boards
e1000.txt
- info on Intel's E1000 line of gigabit ethernet boards
+e1000e.txt
+ - README for the Intel Gigabit Ethernet Driver (e1000e).
eql.txt
- serial IP load balancing
ewrk3.txt
- the Digital EtherWORKS 3 DE203/4/5 Ethernet driver
+fib_trie.txt
+ - Level Compressed Trie (LC-trie) notes: a structure for routing.
filter.txt
- Linux Socket Filtering
fore200e.txt
- FORE Systems PCA-200E/SBA-200E ATM NIC driver info.
framerelay.txt
- info on using Frame Relay/Data Link Connection Identifier (DLCI).
+gen_stats.txt
+ - Generic networking statistics for netlink users.
+generic_hdlc.txt
+ - The generic High Level Data Link Control (HDLC) layer.
generic_netlink.txt
- info on Generic Netlink
+gianfar.txt
+ - Gianfar Ethernet Driver.
ieee802154.txt
- Linux IEEE 802.15.4 implementation, API and drivers
+ifenslave.c
+ - Configure network interfaces for parallel routing (bonding).
+igb.txt
+ - README for the Intel Gigabit Ethernet Driver (igb).
+igbvf.txt
+ - README for the Intel Gigabit Ethernet Driver (igbvf).
ip-sysctl.txt
- /proc/sys/net/ipv4/* variables
ip_dynaddr.txt
@@ -68,41 +108,117 @@ ipddp.txt
- AppleTalk-IP Decapsulation and AppleTalk-IP Encapsulation
iphase.txt
- Interphase PCI ATM (i)Chip IA Linux driver info.
+ipv6.txt
+ - Options to the ipv6 kernel module.
+ipvs-sysctl.txt
+ - Per-inode explanation of the /proc/sys/net/ipv4/vs interface.
irda.txt
- where to get IrDA (infrared) utilities and info for Linux.
+ixgb.txt
+ - README for the Intel 10 Gigabit Ethernet Driver (ixgb).
+ixgbe.txt
+ - README for the Intel 10 Gigabit Ethernet Driver (ixgbe).
+ixgbevf.txt
+ - README for the Intel Virtual Function (VF) Driver (ixgbevf).
+l2tp.txt
+ - User guide to the L2TP tunnel protocol.
lapb-module.txt
- programming information of the LAPB module.
ltpc.txt
- the Apple or Farallon LocalTalk PC card driver
+mac80211-injection.txt
+ - HOWTO use packet injection with mac80211
multicast.txt
- Behaviour of cards under Multicast
+multiqueue.txt
+ - HOWTO for multiqueue network device support.
+netconsole.txt
+ - The network console module netconsole.ko: configuration and notes.
+netdev-features.txt
+ - Network interface features API description.
netdevices.txt
- info on network device driver functions exported to the kernel.
+netif-msg.txt
+ - Design of the network interface message level setting (NETIF_MSG_*).
+nfc.txt
+ - The Linux Near Field Communication (NFS) subsystem.
olympic.txt
- IBM PCI Pit/Pit-Phy/Olympic Token Ring driver info.
+operstates.txt
+ - Overview of network interface operational states.
+packet_mmap.txt
+ - User guide to memory mapped packet socket rings (PACKET_[RT]X_RING).
+phonet.txt
+ - The Phonet packet protocol used in Nokia cellular modems.
+phy.txt
+ - The PHY abstraction layer.
+pktgen.txt
+ - User guide to the kernel packet generator (pktgen.ko).
policy-routing.txt
- IP policy-based routing
+ppp_generic.txt
+ - Information about the generic PPP driver.
+proc_net_tcp.txt
+ - Per inode overview of the /proc/net/tcp and /proc/net/tcp6 interfaces.
+radiotap-headers.txt
+ - Background on radiotap headers.
ray_cs.txt
- Raylink Wireless LAN card driver info.
+rds.txt
+ - Background on the reliable, ordered datagram delivery method RDS.
+regulatory.txt
+ - Overview of the Linux wireless regulatory infrastructure.
+rxrpc.txt
+ - Guide to the RxRPC protocol.
+s2io.txt
+ - Release notes for Neterion Xframe I/II 10GbE driver.
+scaling.txt
+ - Explanation of network scaling techniques: RSS, RPS, RFS, aRFS, XPS.
+sctp.txt
+ - Notes on the Linux kernel implementation of the SCTP protocol.
+secid.txt
+ - Explanation of the secid member in flow structures.
skfp.txt
- SysKonnect FDDI (SK-5xxx, Compaq Netelligent) driver info.
smc9.txt
- the driver for SMC's 9000 series of Ethernet cards
smctr.txt
- SMC TokenCard TokenRing Linux driver info.
+spider-net.txt
+ - README for the Spidernet Driver (as found in PS3 / Cell BE).
+stmmac.txt
+ - README for the STMicro Synopsys Ethernet driver.
+tc-actions-env-rules.txt
+ - rules for traffic control (tc) actions.
+timestamping.txt
+ - overview of network packet timestamping variants.
tcp.txt
- short blurb on how TCP output takes place.
+tcp-thin.txt
+ - kernel tuning options for low rate 'thin' TCP streams.
tlan.txt
- ThunderLAN (Compaq Netelligent 10/100, Olicom OC-2xxx) driver info.
tms380tr.txt
- SysKonnect Token Ring ISA/PCI adapter driver info.
+tproxy.txt
+ - Transparent proxy support user guide.
tuntap.txt
- TUN/TAP device driver, allowing user space Rx/Tx of packets.
+udplite.txt
+ - UDP-Lite protocol (RFC 3828) introduction.
vortex.txt
- info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) Ethernet cards.
+vxge.txt
+ - README for the Neterion X3100 PCIe Server Adapter.
x25.txt
- general info on X.25 development.
x25-iface.txt
- description of the X.25 Packet Layer to LAPB device interface.
+xfrm_proc.txt
+ - description of the statistics package for XFRM.
+xfrm_sync.txt
+ - sync patches for XFRM enable migration of an SA between hosts.
+xfrm_sysctl.txt
+ - description of the XFRM configuration options.
z8530drv.txt
- info about Linux driver for Z8530 based HDLC cards for AX.25
diff --git a/Documentation/networking/batman-adv.txt b/Documentation/networking/batman-adv.txt
index 88d4afbdef98..c86d03f18a5b 100644
--- a/Documentation/networking/batman-adv.txt
+++ b/Documentation/networking/batman-adv.txt
@@ -1,4 +1,4 @@
-[state: 17-04-2011]
+[state: 21-08-2011]
BATMAN-ADV
----------
@@ -68,9 +68,9 @@ All mesh wide settings can be found in batman's own interface
folder:
# ls /sys/class/net/bat0/mesh/
-# aggregated_ogms gw_bandwidth hop_penalty
-# bonding gw_mode orig_interval
-# fragmentation gw_sel_class vis_mode
+# aggregated_ogms fragmentation gw_sel_class vis_mode
+# ap_isolation gw_bandwidth hop_penalty
+# bonding gw_mode orig_interval
There is a special folder for debugging information:
diff --git a/Documentation/networking/dmfe.txt b/Documentation/networking/dmfe.txt
index 8006c227fda2..25320bf19c86 100644
--- a/Documentation/networking/dmfe.txt
+++ b/Documentation/networking/dmfe.txt
@@ -1,3 +1,5 @@
+Note: This driver doesn't have a maintainer.
+
Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver for Linux.
This program is free software; you can redistribute it and/or
@@ -55,7 +57,6 @@ Test and make sure PCI latency is now correct for all cases.
Authors:
Sten Wang <sten_wang@davicom.com.tw > : Original Author
-Tobias Ringstrom <tori@unhappy.mine.nu> : Current Maintainer
Contributors:
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index db2a4067013c..cb7f3148035d 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -992,7 +992,7 @@ bindv6only - BOOLEAN
TRUE: disable IPv4-mapped address feature
FALSE: enable IPv4-mapped address feature
- Default: FALSE (as specified in RFC2553bis)
+ Default: FALSE (as specified in RFC3493)
IPv6 Fragmentation:
@@ -1042,9 +1042,14 @@ conf/interface/*:
The functional behaviour for certain settings is different
depending on whether local forwarding is enabled or not.
-accept_ra - BOOLEAN
+accept_ra - INTEGER
Accept Router Advertisements; autoconfigure using them.
+ It also determines whether or not to transmit Router
+ Solicitations. If and only if the functional setting is to
+ accept Router Advertisements, Router Solicitations will be
+ transmitted.
+
Possible values are:
0 Do not accept Router Advertisements.
1 Accept Router Advertisements if forwarding is disabled.
@@ -1106,7 +1111,7 @@ dad_transmits - INTEGER
The amount of Duplicate Address Detection probes to send.
Default: 1
-forwarding - BOOLEAN
+forwarding - INTEGER
Configure interface-specific Host/Router behaviour.
Note: It is recommended to have the same setting on all
@@ -1115,14 +1120,14 @@ forwarding - BOOLEAN
Possible values are:
0 Forwarding disabled
1 Forwarding enabled
- 2 Forwarding enabled (Hybrid Mode)
FALSE (0):
By default, Host behaviour is assumed. This means:
1. IsRouter flag is not set in Neighbour Advertisements.
- 2. Router Solicitations are being sent when necessary.
+ 2. If accept_ra is TRUE (default), transmit Router
+ Solicitations.
3. If accept_ra is TRUE (default), accept Router
Advertisements (and do autoconfiguration).
4. If accept_redirects is TRUE (default), accept Redirects.
@@ -1133,16 +1138,10 @@ forwarding - BOOLEAN
This means exactly the reverse from the above:
1. IsRouter flag is set in Neighbour Advertisements.
- 2. Router Solicitations are not sent.
+ 2. Router Solicitations are not sent unless accept_ra is 2.
3. Router Advertisements are ignored unless accept_ra is 2.
4. Redirects are ignored.
- TRUE (2):
-
- Hybrid mode. Same behaviour as TRUE, except for:
-
- 2. Router Solicitations are being sent when necessary.
-
Default: 0 (disabled) if global forwarding is disabled (default),
otherwise 1 (enabled).
diff --git a/Documentation/networking/mac80211-injection.txt b/Documentation/networking/mac80211-injection.txt
index b30e81ad5307..3a930072b161 100644
--- a/Documentation/networking/mac80211-injection.txt
+++ b/Documentation/networking/mac80211-injection.txt
@@ -23,6 +23,10 @@ radiotap headers and used to control injection:
IEEE80211_RADIOTAP_F_FRAG: frame will be fragmented if longer than the
current fragmentation threshold.
+ * IEEE80211_RADIOTAP_TX_FLAGS
+
+ IEEE80211_RADIOTAP_F_TX_NOACK: frame should be sent without waiting for
+ an ACK even if it is a unicast frame
The injection code can also skip all other currently defined radiotap fields
facilitating replay of captured radiotap headers directly.
diff --git a/Documentation/networking/netdevices.txt b/Documentation/networking/netdevices.txt
index 87b3d15f523a..89358341682a 100644
--- a/Documentation/networking/netdevices.txt
+++ b/Documentation/networking/netdevices.txt
@@ -73,7 +73,7 @@ dev->hard_start_xmit:
has to lock by itself when needed. It is recommended to use a try lock
for this and return NETDEV_TX_LOCKED when the spin lock fails.
The locking there should also properly protect against
- set_multicast_list. Note that the use of NETIF_F_LLTX is deprecated.
+ set_rx_mode. Note that the use of NETIF_F_LLTX is deprecated.
Don't use it for new drivers.
Context: Process with BHs disabled or BH (timer),
@@ -92,7 +92,7 @@ dev->tx_timeout:
Context: BHs disabled
Notes: netif_queue_stopped() is guaranteed true
-dev->set_multicast_list:
+dev->set_rx_mode:
Synchronization: netif_tx_lock spinlock.
Context: BHs disabled
diff --git a/Documentation/networking/scaling.txt b/Documentation/networking/scaling.txt
index 7254b4b5910e..a177de21d28e 100644
--- a/Documentation/networking/scaling.txt
+++ b/Documentation/networking/scaling.txt
@@ -27,7 +27,7 @@ applying a filter to each packet that assigns it to one of a small number
of logical flows. Packets for each flow are steered to a separate receive
queue, which in turn can be processed by separate CPUs. This mechanism is
generally known as “Receive-side Scaling†(RSS). The goal of RSS and
-the other scaling techniques to increase performance uniformly.
+the other scaling techniques is to increase performance uniformly.
Multi-queue distribution can also be used for traffic prioritization, but
that is not the focus of these techniques.
@@ -52,7 +52,8 @@ module parameter for specifying the number of hardware queues to
configure. In the bnx2x driver, for instance, this parameter is called
num_queues. A typical RSS configuration would be to have one receive queue
for each CPU if the device supports enough queues, or otherwise at least
-one for each cache domain at a particular cache level (L1, L2, etc.).
+one for each memory domain, where a memory domain is a set of CPUs that
+share a particular memory level (L1, L2, NUMA node, etc.).
The indirection table of an RSS device, which resolves a queue by masked
hash, is usually programmed by the driver at initialization. The
@@ -72,7 +73,7 @@ of queues to IRQs can be determined from /proc/interrupts. By default,
an IRQ may be handled on any CPU. Because a non-negligible part of packet
processing takes place in receive interrupt handling, it is advantageous
to spread receive interrupts between CPUs. To manually adjust the IRQ
-affinity of each interrupt see Documentation/IRQ-affinity. Some systems
+affinity of each interrupt see Documentation/IRQ-affinity.txt. Some systems
will be running irqbalance, a daemon that dynamically optimizes IRQ
assignments and as a result may override any manual settings.
@@ -82,11 +83,17 @@ RSS should be enabled when latency is a concern or whenever receive
interrupt processing forms a bottleneck. Spreading load between CPUs
decreases queue length. For low latency networking, the optimal setting
is to allocate as many queues as there are CPUs in the system (or the
-NIC maximum, if lower). Because the aggregate number of interrupts grows
-with each additional queue, the most efficient high-rate configuration
+NIC maximum, if lower). The most efficient high-rate configuration
is likely the one with the smallest number of receive queues where no
-CPU that processes receive interrupts reaches 100% utilization. Per-cpu
-load can be observed using the mpstat utility.
+receive queue overflows due to a saturated CPU, because in default
+mode with interrupt coalescing enabled, the aggregate number of
+interrupts (and thus work) grows with each additional queue.
+
+Per-cpu load can be observed using the mpstat utility, but note that on
+processors with hyperthreading (HT), each hyperthread is represented as
+a separate CPU. For interrupt handling, HT has shown no benefit in
+initial tests, so limit the number of queues to the number of CPU cores
+in the system.
RPS: Receive Packet Steering
@@ -145,7 +152,7 @@ the bitmap.
== Suggested Configuration
For a single queue device, a typical RPS configuration would be to set
-the rps_cpus to the CPUs in the same cache domain of the interrupting
+the rps_cpus to the CPUs in the same memory domain of the interrupting
CPU. If NUMA locality is not an issue, this could also be all CPUs in
the system. At high interrupt rate, it might be wise to exclude the
interrupting CPU from the map since that already performs much work.
@@ -154,7 +161,7 @@ For a multi-queue system, if RSS is configured so that a hardware
receive queue is mapped to each CPU, then RPS is probably redundant
and unnecessary. If there are fewer hardware queues than CPUs, then
RPS might be beneficial if the rps_cpus for each queue are the ones that
-share the same cache domain as the interrupting CPU for that queue.
+share the same memory domain as the interrupting CPU for that queue.
RFS: Receive Flow Steering
@@ -179,10 +186,10 @@ are steered using plain RPS. Multiple table entries may point to the
same CPU. Indeed, with many flows and few CPUs, it is very likely that
a single application thread handles flows with many different flow hashes.
-rps_sock_table is a global flow table that contains the *desired* CPU for
-flows: the CPU that is currently processing the flow in userspace. Each
-table value is a CPU index that is updated during calls to recvmsg and
-sendmsg (specifically, inet_recvmsg(), inet_sendmsg(), inet_sendpage()
+rps_sock_flow_table is a global flow table that contains the *desired* CPU
+for flows: the CPU that is currently processing the flow in userspace.
+Each table value is a CPU index that is updated during calls to recvmsg
+and sendmsg (specifically, inet_recvmsg(), inet_sendmsg(), inet_sendpage()
and tcp_splice_read()).
When the scheduler moves a thread to a new CPU while it has outstanding
@@ -236,7 +243,7 @@ configured. The number of entries in the global flow table is set through:
The number of entries in the per-queue flow table are set through:
- /sys/class/net/<dev>/queues/tx-<n>/rps_flow_cnt
+ /sys/class/net/<dev>/queues/rx-<n>/rps_flow_cnt
== Suggested Configuration
@@ -326,7 +333,7 @@ The queue chosen for transmitting a particular flow is saved in the
corresponding socket structure for the flow (e.g. a TCP connection).
This transmit queue is used for subsequent packets sent on the flow to
prevent out of order (ooo) packets. The choice also amortizes the cost
-of calling get_xps_queues() over all packets in the connection. To avoid
+of calling get_xps_queues() over all packets in the flow. To avoid
ooo packets, the queue for a flow can subsequently only be changed if
skb->ooo_okay is set for a packet in the flow. This flag indicates that
there are no outstanding packets in the flow, so the transmit queue can
diff --git a/Documentation/networking/stmmac.txt b/Documentation/networking/stmmac.txt
index 57a24108b845..8d67980fabe8 100644
--- a/Documentation/networking/stmmac.txt
+++ b/Documentation/networking/stmmac.txt
@@ -76,7 +76,16 @@ core.
4.5) DMA descriptors
Driver handles both normal and enhanced descriptors. The latter has been only
-tested on DWC Ether MAC 10/100/1000 Universal version 3.41a.
+tested on DWC Ether MAC 10/100/1000 Universal version 3.41a and later.
+
+STMMAC supports DMA descriptor to operate both in dual buffer (RING)
+and linked-list(CHAINED) mode. In RING each descriptor points to two
+data buffer pointers whereas in CHAINED mode they point to only one data
+buffer pointer. RING mode is the default.
+
+In CHAINED mode each descriptor will have pointer to next descriptor in
+the list, hence creating the explicit chaining in the descriptor itself,
+whereas such explicit chaining is not possible in RING mode.
4.6) Ethtool support
Ethtool is supported. Driver statistics and internal errors can be taken using:
@@ -235,7 +244,38 @@ reset procedure etc).
o enh_desc.c: functions for handling enhanced descriptors
o norm_desc.c: functions for handling normal descriptors
-5) TODO:
+5) Debug Information
+
+The driver exports many information i.e. internal statistics,
+debug information, MAC and DMA registers etc.
+
+These can be read in several ways depending on the
+type of the information actually needed.
+
+For example a user can be use the ethtool support
+to get statistics: e.g. using: ethtool -S ethX
+(that shows the Management counters (MMC) if supported)
+or sees the MAC/DMA registers: e.g. using: ethtool -d ethX
+
+Compiling the Kernel with CONFIG_DEBUG_FS and enabling the
+STMMAC_DEBUG_FS option the driver will export the following
+debugfs entries:
+
+/sys/kernel/debug/stmmaceth/descriptors_status
+ To show the DMA TX/RX descriptor rings
+
+Developer can also use the "debug" module parameter to get
+further debug information.
+
+In the end, there are other macros (that cannot be enabled
+via menuconfig) to turn-on the RX/TX DMA debugging,
+specific MAC core debug printk etc. Others to enable the
+debug in the TX and RX processes.
+All these are only useful during the developing stage
+and should never enabled inside the code for general usage.
+In fact, these can generate an huge amount of debug messages.
+
+6) TODO:
o XGMAC is not supported.
o Review the timer optimisation code to use an embedded device that will be
available in new chip generations.
diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt
new file mode 100644
index 000000000000..b04cb7d45a16
--- /dev/null
+++ b/Documentation/pinctrl.txt
@@ -0,0 +1,950 @@
+PINCTRL (PIN CONTROL) subsystem
+This document outlines the pin control subsystem in Linux
+
+This subsystem deals with:
+
+- Enumerating and naming controllable pins
+
+- Multiplexing of pins, pads, fingers (etc) see below for details
+
+The intention is to also deal with:
+
+- Software-controlled biasing and driving mode specific pins, such as
+ pull-up/down, open drain etc, load capacitance configuration when controlled
+ by software, etc.
+
+
+Top-level interface
+===================
+
+Definition of PIN CONTROLLER:
+
+- A pin controller is a piece of hardware, usually a set of registers, that
+ can control PINs. It may be able to multiplex, bias, set load capacitance,
+ set drive strength etc for individual pins or groups of pins.
+
+Definition of PIN:
+
+- PINS are equal to pads, fingers, balls or whatever packaging input or
+ output line you want to control and these are denoted by unsigned integers
+ in the range 0..maxpin. This numberspace is local to each PIN CONTROLLER, so
+ there may be several such number spaces in a system. This pin space may
+ be sparse - i.e. there may be gaps in the space with numbers where no
+ pin exists.
+
+When a PIN CONTROLLER is instatiated, it will register a descriptor to the
+pin control framework, and this descriptor contains an array of pin descriptors
+describing the pins handled by this specific pin controller.
+
+Here is an example of a PGA (Pin Grid Array) chip seen from underneath:
+
+ A B C D E F G H
+
+ 8 o o o o o o o o
+
+ 7 o o o o o o o o
+
+ 6 o o o o o o o o
+
+ 5 o o o o o o o o
+
+ 4 o o o o o o o o
+
+ 3 o o o o o o o o
+
+ 2 o o o o o o o o
+
+ 1 o o o o o o o o
+
+To register a pin controller and name all the pins on this package we can do
+this in our driver:
+
+#include <linux/pinctrl/pinctrl.h>
+
+const struct pinctrl_pin_desc __refdata foo_pins[] = {
+ PINCTRL_PIN(0, "A1"),
+ PINCTRL_PIN(1, "A2"),
+ PINCTRL_PIN(2, "A3"),
+ ...
+ PINCTRL_PIN(61, "H6"),
+ PINCTRL_PIN(62, "H7"),
+ PINCTRL_PIN(63, "H8"),
+};
+
+static struct pinctrl_desc foo_desc = {
+ .name = "foo",
+ .pins = foo_pins,
+ .npins = ARRAY_SIZE(foo_pins),
+ .maxpin = 63,
+ .owner = THIS_MODULE,
+};
+
+int __init foo_probe(void)
+{
+ struct pinctrl_dev *pctl;
+
+ pctl = pinctrl_register(&foo_desc, <PARENT>, NULL);
+ if (IS_ERR(pctl))
+ pr_err("could not register foo pin driver\n");
+}
+
+Pins usually have fancier names than this. You can find these in the dataheet
+for your chip. Notice that the core pinctrl.h file provides a fancy macro
+called PINCTRL_PIN() to create the struct entries. As you can see I enumerated
+the pins from 0 in the upper left corner to 63 in the lower right corner,
+this enumeration was arbitrarily chosen, in practice you need to think
+through your numbering system so that it matches the layout of registers
+and such things in your driver, or the code may become complicated. You must
+also consider matching of offsets to the GPIO ranges that may be handled by
+the pin controller.
+
+For a padring with 467 pads, as opposed to actual pins, I used an enumeration
+like this, walking around the edge of the chip, which seems to be industry
+standard too (all these pads had names, too):
+
+
+ 0 ..... 104
+ 466 105
+ . .
+ . .
+ 358 224
+ 357 .... 225
+
+
+Pin groups
+==========
+
+Many controllers need to deal with groups of pins, so the pin controller
+subsystem has a mechanism for enumerating groups of pins and retrieving the
+actual enumerated pins that are part of a certain group.
+
+For example, say that we have a group of pins dealing with an SPI interface
+on { 0, 8, 16, 24 }, and a group of pins dealing with an I2C interface on pins
+on { 24, 25 }.
+
+These two groups are presented to the pin control subsystem by implementing
+some generic pinctrl_ops like this:
+
+#include <linux/pinctrl/pinctrl.h>
+
+struct foo_group {
+ const char *name;
+ const unsigned int *pins;
+ const unsigned num_pins;
+};
+
+static unsigned int spi0_pins[] = { 0, 8, 16, 24 };
+static unsigned int i2c0_pins[] = { 24, 25 };
+
+static const struct foo_group foo_groups[] = {
+ {
+ .name = "spi0_grp",
+ .pins = spi0_pins,
+ .num_pins = ARRAY_SIZE(spi0_pins),
+ },
+ {
+ .name = "i2c0_grp",
+ .pins = i2c0_pins,
+ .num_pins = ARRAY_SIZE(i2c0_pins),
+ },
+};
+
+
+static int foo_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
+{
+ if (selector >= ARRAY_SIZE(foo_groups))
+ return -EINVAL;
+ return 0;
+}
+
+static const char *foo_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ return foo_groups[selector].name;
+}
+
+static int foo_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+ unsigned ** const pins,
+ unsigned * const num_pins)
+{
+ *pins = (unsigned *) foo_groups[selector].pins;
+ *num_pins = foo_groups[selector].num_pins;
+ return 0;
+}
+
+static struct pinctrl_ops foo_pctrl_ops = {
+ .list_groups = foo_list_groups,
+ .get_group_name = foo_get_group_name,
+ .get_group_pins = foo_get_group_pins,
+};
+
+
+static struct pinctrl_desc foo_desc = {
+ ...
+ .pctlops = &foo_pctrl_ops,
+};
+
+The pin control subsystem will call the .list_groups() function repeatedly
+beginning on 0 until it returns non-zero to determine legal selectors, then
+it will call the other functions to retrieve the name and pins of the group.
+Maintaining the data structure of the groups is up to the driver, this is
+just a simple example - in practice you may need more entries in your group
+structure, for example specific register ranges associated with each group
+and so on.
+
+
+Interaction with the GPIO subsystem
+===================================
+
+The GPIO drivers may want to perform operations of various types on the same
+physical pins that are also registered as pin controller pins.
+
+Since the pin controller subsystem have its pinspace local to the pin
+controller we need a mapping so that the pin control subsystem can figure out
+which pin controller handles control of a certain GPIO pin. Since a single
+pin controller may be muxing several GPIO ranges (typically SoCs that have
+one set of pins but internally several GPIO silicon blocks, each modeled as
+a struct gpio_chip) any number of GPIO ranges can be added to a pin controller
+instance like this:
+
+struct gpio_chip chip_a;
+struct gpio_chip chip_b;
+
+static struct pinctrl_gpio_range gpio_range_a = {
+ .name = "chip a",
+ .id = 0,
+ .base = 32,
+ .npins = 16,
+ .gc = &chip_a;
+};
+
+static struct pinctrl_gpio_range gpio_range_a = {
+ .name = "chip b",
+ .id = 0,
+ .base = 48,
+ .npins = 8,
+ .gc = &chip_b;
+};
+
+
+{
+ struct pinctrl_dev *pctl;
+ ...
+ pinctrl_add_gpio_range(pctl, &gpio_range_a);
+ pinctrl_add_gpio_range(pctl, &gpio_range_b);
+}
+
+So this complex system has one pin controller handling two different
+GPIO chips. Chip a has 16 pins and chip b has 8 pins. They are mapped in
+the global GPIO pin space at:
+
+chip a: [32 .. 47]
+chip b: [48 .. 55]
+
+When GPIO-specific functions in the pin control subsystem are called, these
+ranges will be used to look up the apropriate pin controller by inspecting
+and matching the pin to the pin ranges across all controllers. When a
+pin controller handling the matching range is found, GPIO-specific functions
+will be called on that specific pin controller.
+
+For all functionalities dealing with pin biasing, pin muxing etc, the pin
+controller subsystem will subtract the range's .base offset from the passed
+in gpio pin number, and pass that on to the pin control driver, so the driver
+will get an offset into its handled number range. Further it is also passed
+the range ID value, so that the pin controller knows which range it should
+deal with.
+
+For example: if a user issues pinctrl_gpio_set_foo(50), the pin control
+subsystem will find that the second range on this pin controller matches,
+subtract the base 48 and call the
+pinctrl_driver_gpio_set_foo(pinctrl, range, 2) where the latter function has
+this signature:
+
+int pinctrl_driver_gpio_set_foo(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *rangeid,
+ unsigned offset);
+
+Now the driver knows that we want to do some GPIO-specific operation on the
+second GPIO range handled by "chip b", at offset 2 in that specific range.
+
+(If the GPIO subsystem is ever refactored to use a local per-GPIO controller
+pin space, this mapping will need to be augmented accordingly.)
+
+
+PINMUX interfaces
+=================
+
+These calls use the pinmux_* naming prefix. No other calls should use that
+prefix.
+
+
+What is pinmuxing?
+==================
+
+PINMUX, also known as padmux, ballmux, alternate functions or mission modes
+is a way for chip vendors producing some kind of electrical packages to use
+a certain physical pin (ball, pad, finger, etc) for multiple mutually exclusive
+functions, depending on the application. By "application" in this context
+we usually mean a way of soldering or wiring the package into an electronic
+system, even though the framework makes it possible to also change the function
+at runtime.
+
+Here is an example of a PGA (Pin Grid Array) chip seen from underneath:
+
+ A B C D E F G H
+ +---+
+ 8 | o | o o o o o o o
+ | |
+ 7 | o | o o o o o o o
+ | |
+ 6 | o | o o o o o o o
+ +---+---+
+ 5 | o | o | o o o o o o
+ +---+---+ +---+
+ 4 o o o o o o | o | o
+ | |
+ 3 o o o o o o | o | o
+ | |
+ 2 o o o o o o | o | o
+ +-------+-------+-------+---+---+
+ 1 | o o | o o | o o | o | o |
+ +-------+-------+-------+---+---+
+
+This is not tetris. The game to think of is chess. Not all PGA/BGA packages
+are chessboard-like, big ones have "holes" in some arrangement according to
+different design patterns, but we're using this as a simple example. Of the
+pins you see some will be taken by things like a few VCC and GND to feed power
+to the chip, and quite a few will be taken by large ports like an external
+memory interface. The remaining pins will often be subject to pin multiplexing.
+
+The example 8x8 PGA package above will have pin numbers 0 thru 63 assigned to
+its physical pins. It will name the pins { A1, A2, A3 ... H6, H7, H8 } using
+pinctrl_register_pins() and a suitable data set as shown earlier.
+
+In this 8x8 BGA package the pins { A8, A7, A6, A5 } can be used as an SPI port
+(these are four pins: CLK, RXD, TXD, FRM). In that case, pin B5 can be used as
+some general-purpose GPIO pin. However, in another setting, pins { A5, B5 } can
+be used as an I2C port (these are just two pins: SCL, SDA). Needless to say,
+we cannot use the SPI port and I2C port at the same time. However in the inside
+of the package the silicon performing the SPI logic can alternatively be routed
+out on pins { G4, G3, G2, G1 }.
+
+On the botton row at { A1, B1, C1, D1, E1, F1, G1, H1 } we have something
+special - it's an external MMC bus that can be 2, 4 or 8 bits wide, and it will
+consume 2, 4 or 8 pins respectively, so either { A1, B1 } are taken or
+{ A1, B1, C1, D1 } or all of them. If we use all 8 bits, we cannot use the SPI
+port on pins { G4, G3, G2, G1 } of course.
+
+This way the silicon blocks present inside the chip can be multiplexed "muxed"
+out on different pin ranges. Often contemporary SoC (systems on chip) will
+contain several I2C, SPI, SDIO/MMC, etc silicon blocks that can be routed to
+different pins by pinmux settings.
+
+Since general-purpose I/O pins (GPIO) are typically always in shortage, it is
+common to be able to use almost any pin as a GPIO pin if it is not currently
+in use by some other I/O port.
+
+
+Pinmux conventions
+==================
+
+The purpose of the pinmux functionality in the pin controller subsystem is to
+abstract and provide pinmux settings to the devices you choose to instantiate
+in your machine configuration. It is inspired by the clk, GPIO and regulator
+subsystems, so devices will request their mux setting, but it's also possible
+to request a single pin for e.g. GPIO.
+
+Definitions:
+
+- FUNCTIONS can be switched in and out by a driver residing with the pin
+ control subsystem in the drivers/pinctrl/* directory of the kernel. The
+ pin control driver knows the possible functions. In the example above you can
+ identify three pinmux functions, one for spi, one for i2c and one for mmc.
+
+- FUNCTIONS are assumed to be enumerable from zero in a one-dimensional array.
+ In this case the array could be something like: { spi0, i2c0, mmc0 }
+ for the three available functions.
+
+- FUNCTIONS have PIN GROUPS as defined on the generic level - so a certain
+ function is *always* associated with a certain set of pin groups, could
+ be just a single one, but could also be many. In the example above the
+ function i2c is associated with the pins { A5, B5 }, enumerated as
+ { 24, 25 } in the controller pin space.
+
+ The Function spi is associated with pin groups { A8, A7, A6, A5 }
+ and { G4, G3, G2, G1 }, which are enumerated as { 0, 8, 16, 24 } and
+ { 38, 46, 54, 62 } respectively.
+
+ Group names must be unique per pin controller, no two groups on the same
+ controller may have the same name.
+
+- The combination of a FUNCTION and a PIN GROUP determine a certain function
+ for a certain set of pins. The knowledge of the functions and pin groups
+ and their machine-specific particulars are kept inside the pinmux driver,
+ from the outside only the enumerators are known, and the driver core can:
+
+ - Request the name of a function with a certain selector (>= 0)
+ - A list of groups associated with a certain function
+ - Request that a certain group in that list to be activated for a certain
+ function
+
+ As already described above, pin groups are in turn self-descriptive, so
+ the core will retrieve the actual pin range in a certain group from the
+ driver.
+
+- FUNCTIONS and GROUPS on a certain PIN CONTROLLER are MAPPED to a certain
+ device by the board file, device tree or similar machine setup configuration
+ mechanism, similar to how regulators are connected to devices, usually by
+ name. Defining a pin controller, function and group thus uniquely identify
+ the set of pins to be used by a certain device. (If only one possible group
+ of pins is available for the function, no group name need to be supplied -
+ the core will simply select the first and only group available.)
+
+ In the example case we can define that this particular machine shall
+ use device spi0 with pinmux function fspi0 group gspi0 and i2c0 on function
+ fi2c0 group gi2c0, on the primary pin controller, we get mappings
+ like these:
+
+ {
+ {"map-spi0", spi0, pinctrl0, fspi0, gspi0},
+ {"map-i2c0", i2c0, pinctrl0, fi2c0, gi2c0}
+ }
+
+ Every map must be assigned a symbolic name, pin controller and function.
+ The group is not compulsory - if it is omitted the first group presented by
+ the driver as applicable for the function will be selected, which is
+ useful for simple cases.
+
+ The device name is present in map entries tied to specific devices. Maps
+ without device names are referred to as SYSTEM pinmuxes, such as can be taken
+ by the machine implementation on boot and not tied to any specific device.
+
+ It is possible to map several groups to the same combination of device,
+ pin controller and function. This is for cases where a certain function on
+ a certain pin controller may use different sets of pins in different
+ configurations.
+
+- PINS for a certain FUNCTION using a certain PIN GROUP on a certain
+ PIN CONTROLLER are provided on a first-come first-serve basis, so if some
+ other device mux setting or GPIO pin request has already taken your physical
+ pin, you will be denied the use of it. To get (activate) a new setting, the
+ old one has to be put (deactivated) first.
+
+Sometimes the documentation and hardware registers will be oriented around
+pads (or "fingers") rather than pins - these are the soldering surfaces on the
+silicon inside the package, and may or may not match the actual number of
+pins/balls underneath the capsule. Pick some enumeration that makes sense to
+you. Define enumerators only for the pins you can control if that makes sense.
+
+Assumptions:
+
+We assume that the number possible function maps to pin groups is limited by
+the hardware. I.e. we assume that there is no system where any function can be
+mapped to any pin, like in a phone exchange. So the available pins groups for
+a certain function will be limited to a few choices (say up to eight or so),
+not hundreds or any amount of choices. This is the characteristic we have found
+by inspecting available pinmux hardware, and a necessary assumption since we
+expect pinmux drivers to present *all* possible function vs pin group mappings
+to the subsystem.
+
+
+Pinmux drivers
+==============
+
+The pinmux core takes care of preventing conflicts on pins and calling
+the pin controller driver to execute different settings.
+
+It is the responsibility of the pinmux driver to impose further restrictions
+(say for example infer electronic limitations due to load etc) to determine
+whether or not the requested function can actually be allowed, and in case it
+is possible to perform the requested mux setting, poke the hardware so that
+this happens.
+
+Pinmux drivers are required to supply a few callback functions, some are
+optional. Usually the enable() and disable() functions are implemented,
+writing values into some certain registers to activate a certain mux setting
+for a certain pin.
+
+A simple driver for the above example will work by setting bits 0, 1, 2, 3 or 4
+into some register named MUX to select a certain function with a certain
+group of pins would work something like this:
+
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+struct foo_group {
+ const char *name;
+ const unsigned int *pins;
+ const unsigned num_pins;
+};
+
+static const unsigned spi0_0_pins[] = { 0, 8, 16, 24 };
+static const unsigned spi0_1_pins[] = { 38, 46, 54, 62 };
+static const unsigned i2c0_pins[] = { 24, 25 };
+static const unsigned mmc0_1_pins[] = { 56, 57 };
+static const unsigned mmc0_2_pins[] = { 58, 59 };
+static const unsigned mmc0_3_pins[] = { 60, 61, 62, 63 };
+
+static const struct foo_group foo_groups[] = {
+ {
+ .name = "spi0_0_grp",
+ .pins = spi0_0_pins,
+ .num_pins = ARRAY_SIZE(spi0_0_pins),
+ },
+ {
+ .name = "spi0_1_grp",
+ .pins = spi0_1_pins,
+ .num_pins = ARRAY_SIZE(spi0_1_pins),
+ },
+ {
+ .name = "i2c0_grp",
+ .pins = i2c0_pins,
+ .num_pins = ARRAY_SIZE(i2c0_pins),
+ },
+ {
+ .name = "mmc0_1_grp",
+ .pins = mmc0_1_pins,
+ .num_pins = ARRAY_SIZE(mmc0_1_pins),
+ },
+ {
+ .name = "mmc0_2_grp",
+ .pins = mmc0_2_pins,
+ .num_pins = ARRAY_SIZE(mmc0_2_pins),
+ },
+ {
+ .name = "mmc0_3_grp",
+ .pins = mmc0_3_pins,
+ .num_pins = ARRAY_SIZE(mmc0_3_pins),
+ },
+};
+
+
+static int foo_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
+{
+ if (selector >= ARRAY_SIZE(foo_groups))
+ return -EINVAL;
+ return 0;
+}
+
+static const char *foo_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ return foo_groups[selector].name;
+}
+
+static int foo_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+ unsigned ** const pins,
+ unsigned * const num_pins)
+{
+ *pins = (unsigned *) foo_groups[selector].pins;
+ *num_pins = foo_groups[selector].num_pins;
+ return 0;
+}
+
+static struct pinctrl_ops foo_pctrl_ops = {
+ .list_groups = foo_list_groups,
+ .get_group_name = foo_get_group_name,
+ .get_group_pins = foo_get_group_pins,
+};
+
+struct foo_pmx_func {
+ const char *name;
+ const char * const *groups;
+ const unsigned num_groups;
+};
+
+static const char * const spi0_groups[] = { "spi0_1_grp" };
+static const char * const i2c0_groups[] = { "i2c0_grp" };
+static const char * const mmc0_groups[] = { "mmc0_1_grp", "mmc0_2_grp",
+ "mmc0_3_grp" };
+
+static const struct foo_pmx_func foo_functions[] = {
+ {
+ .name = "spi0",
+ .groups = spi0_groups,
+ .num_groups = ARRAY_SIZE(spi0_groups),
+ },
+ {
+ .name = "i2c0",
+ .groups = i2c0_groups,
+ .num_groups = ARRAY_SIZE(i2c0_groups),
+ },
+ {
+ .name = "mmc0",
+ .groups = mmc0_groups,
+ .num_groups = ARRAY_SIZE(mmc0_groups),
+ },
+};
+
+int foo_list_funcs(struct pinctrl_dev *pctldev, unsigned selector)
+{
+ if (selector >= ARRAY_SIZE(foo_functions))
+ return -EINVAL;
+ return 0;
+}
+
+const char *foo_get_fname(struct pinctrl_dev *pctldev, unsigned selector)
+{
+ return myfuncs[selector].name;
+}
+
+static int foo_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ *groups = foo_functions[selector].groups;
+ *num_groups = foo_functions[selector].num_groups;
+ return 0;
+}
+
+int foo_enable(struct pinctrl_dev *pctldev, unsigned selector,
+ unsigned group)
+{
+ u8 regbit = (1 << group);
+
+ writeb((readb(MUX)|regbit), MUX)
+ return 0;
+}
+
+int foo_disable(struct pinctrl_dev *pctldev, unsigned selector,
+ unsigned group)
+{
+ u8 regbit = (1 << group);
+
+ writeb((readb(MUX) & ~(regbit)), MUX)
+ return 0;
+}
+
+struct pinmux_ops foo_pmxops = {
+ .list_functions = foo_list_funcs,
+ .get_function_name = foo_get_fname,
+ .get_function_groups = foo_get_groups,
+ .enable = foo_enable,
+ .disable = foo_disable,
+};
+
+/* Pinmux operations are handled by some pin controller */
+static struct pinctrl_desc foo_desc = {
+ ...
+ .pctlops = &foo_pctrl_ops,
+ .pmxops = &foo_pmxops,
+};
+
+In the example activating muxing 0 and 1 at the same time setting bits
+0 and 1, uses one pin in common so they would collide.
+
+The beauty of the pinmux subsystem is that since it keeps track of all
+pins and who is using them, it will already have denied an impossible
+request like that, so the driver does not need to worry about such
+things - when it gets a selector passed in, the pinmux subsystem makes
+sure no other device or GPIO assignment is already using the selected
+pins. Thus bits 0 and 1 in the control register will never be set at the
+same time.
+
+All the above functions are mandatory to implement for a pinmux driver.
+
+
+Pinmux interaction with the GPIO subsystem
+==========================================
+
+The function list could become long, especially if you can convert every
+individual pin into a GPIO pin independent of any other pins, and then try
+the approach to define every pin as a function.
+
+In this case, the function array would become 64 entries for each GPIO
+setting and then the device functions.
+
+For this reason there is an additional function a pinmux driver can implement
+to enable only GPIO on an individual pin: .gpio_request_enable(). The same
+.free() function as for other functions is assumed to be usable also for
+GPIO pins.
+
+This function will pass in the affected GPIO range identified by the pin
+controller core, so you know which GPIO pins are being affected by the request
+operation.
+
+Alternatively it is fully allowed to use named functions for each GPIO
+pin, the pinmux_request_gpio() will attempt to obtain the function "gpioN"
+where "N" is the global GPIO pin number if no special GPIO-handler is
+registered.
+
+
+Pinmux board/machine configuration
+==================================
+
+Boards and machines define how a certain complete running system is put
+together, including how GPIOs and devices are muxed, how regulators are
+constrained and how the clock tree looks. Of course pinmux settings are also
+part of this.
+
+A pinmux config for a machine looks pretty much like a simple regulator
+configuration, so for the example array above we want to enable i2c and
+spi on the second function mapping:
+
+#include <linux/pinctrl/machine.h>
+
+static struct pinmux_map pmx_mapping[] = {
+ {
+ .ctrl_dev_name = "pinctrl.0",
+ .function = "spi0",
+ .dev_name = "foo-spi.0",
+ },
+ {
+ .ctrl_dev_name = "pinctrl.0",
+ .function = "i2c0",
+ .dev_name = "foo-i2c.0",
+ },
+ {
+ .ctrl_dev_name = "pinctrl.0",
+ .function = "mmc0",
+ .dev_name = "foo-mmc.0",
+ },
+};
+
+The dev_name here matches to the unique device name that can be used to look
+up the device struct (just like with clockdev or regulators). The function name
+must match a function provided by the pinmux driver handling this pin range.
+
+As you can see we may have several pin controllers on the system and thus
+we need to specify which one of them that contain the functions we wish
+to map. The map can also use struct device * directly, so there is no
+inherent need to use strings to specify .dev_name or .ctrl_dev_name, these
+are for the situation where you do not have a handle to the struct device *,
+for example if they are not yet instantiated or cumbersome to obtain.
+
+You register this pinmux mapping to the pinmux subsystem by simply:
+
+ ret = pinmux_register_mappings(&pmx_mapping, ARRAY_SIZE(pmx_mapping));
+
+Since the above construct is pretty common there is a helper macro to make
+it even more compact which assumes you want to use pinctrl.0 and position
+0 for mapping, for example:
+
+static struct pinmux_map pmx_mapping[] = {
+ PINMUX_MAP_PRIMARY("I2CMAP", "i2c0", "foo-i2c.0"),
+};
+
+
+Complex mappings
+================
+
+As it is possible to map a function to different groups of pins an optional
+.group can be specified like this:
+
+...
+{
+ .name = "spi0-pos-A",
+ .ctrl_dev_name = "pinctrl.0",
+ .function = "spi0",
+ .group = "spi0_0_grp",
+ .dev_name = "foo-spi.0",
+},
+{
+ .name = "spi0-pos-B",
+ .ctrl_dev_name = "pinctrl.0",
+ .function = "spi0",
+ .group = "spi0_1_grp",
+ .dev_name = "foo-spi.0",
+},
+...
+
+This example mapping is used to switch between two positions for spi0 at
+runtime, as described further below under the heading "Runtime pinmuxing".
+
+Further it is possible to match several groups of pins to the same function
+for a single device, say for example in the mmc0 example above, where you can
+additively expand the mmc0 bus from 2 to 4 to 8 pins. If we want to use all
+three groups for a total of 2+2+4 = 8 pins (for an 8-bit MMC bus as is the
+case), we define a mapping like this:
+
+...
+{
+ .name "2bit"
+ .ctrl_dev_name = "pinctrl.0",
+ .function = "mmc0",
+ .group = "mmc0_0_grp",
+ .dev_name = "foo-mmc.0",
+},
+{
+ .name "4bit"
+ .ctrl_dev_name = "pinctrl.0",
+ .function = "mmc0",
+ .group = "mmc0_0_grp",
+ .dev_name = "foo-mmc.0",
+},
+{
+ .name "4bit"
+ .ctrl_dev_name = "pinctrl.0",
+ .function = "mmc0",
+ .group = "mmc0_1_grp",
+ .dev_name = "foo-mmc.0",
+},
+{
+ .name "8bit"
+ .ctrl_dev_name = "pinctrl.0",
+ .function = "mmc0",
+ .group = "mmc0_0_grp",
+ .dev_name = "foo-mmc.0",
+},
+{
+ .name "8bit"
+ .ctrl_dev_name = "pinctrl.0",
+ .function = "mmc0",
+ .group = "mmc0_1_grp",
+ .dev_name = "foo-mmc.0",
+},
+{
+ .name "8bit"
+ .ctrl_dev_name = "pinctrl.0",
+ .function = "mmc0",
+ .group = "mmc0_2_grp",
+ .dev_name = "foo-mmc.0",
+},
+...
+
+The result of grabbing this mapping from the device with something like
+this (see next paragraph):
+
+ pmx = pinmux_get(&device, "8bit");
+
+Will be that you activate all the three bottom records in the mapping at
+once. Since they share the same name, pin controller device, funcion and
+device, and since we allow multiple groups to match to a single device, they
+all get selected, and they all get enabled and disable simultaneously by the
+pinmux core.
+
+
+Pinmux requests from drivers
+============================
+
+Generally it is discouraged to let individual drivers get and enable pinmuxes.
+So if possible, handle the pinmuxes in platform code or some other place where
+you have access to all the affected struct device * pointers. In some cases
+where a driver needs to switch between different mux mappings at runtime
+this is not possible.
+
+A driver may request a certain mux to be activated, usually just the default
+mux like this:
+
+#include <linux/pinctrl/pinmux.h>
+
+struct foo_state {
+ struct pinmux *pmx;
+ ...
+};
+
+foo_probe()
+{
+ /* Allocate a state holder named "state" etc */
+ struct pinmux pmx;
+
+ pmx = pinmux_get(&device, NULL);
+ if IS_ERR(pmx)
+ return PTR_ERR(pmx);
+ pinmux_enable(pmx);
+
+ state->pmx = pmx;
+}
+
+foo_remove()
+{
+ pinmux_disable(state->pmx);
+ pinmux_put(state->pmx);
+}
+
+If you want to grab a specific mux mapping and not just the first one found for
+this device you can specify a specific mapping name, for example in the above
+example the second i2c0 setting: pinmux_get(&device, "spi0-pos-B");
+
+This get/enable/disable/put sequence can just as well be handled by bus drivers
+if you don't want each and every driver to handle it and you know the
+arrangement on your bus.
+
+The semantics of the get/enable respective disable/put is as follows:
+
+- pinmux_get() is called in process context to reserve the pins affected with
+ a certain mapping and set up the pinmux core and the driver. It will allocate
+ a struct from the kernel memory to hold the pinmux state.
+
+- pinmux_enable()/pinmux_disable() is quick and can be called from fastpath
+ (irq context) when you quickly want to set up/tear down the hardware muxing
+ when running a device driver. Usually it will just poke some values into a
+ register.
+
+- pinmux_disable() is called in process context to tear down the pin requests
+ and release the state holder struct for the mux setting.
+
+Usually the pinmux core handled the get/put pair and call out to the device
+drivers bookkeeping operations, like checking available functions and the
+associated pins, whereas the enable/disable pass on to the pin controller
+driver which takes care of activating and/or deactivating the mux setting by
+quickly poking some registers.
+
+The pins are allocated for your device when you issue the pinmux_get() call,
+after this you should be able to see this in the debugfs listing of all pins.
+
+
+System pinmux hogging
+=====================
+
+A system pinmux map entry, i.e. a pinmux setting that does not have a device
+associated with it, can be hogged by the core when the pin controller is
+registered. This means that the core will attempt to call pinmux_get() and
+pinmux_enable() on it immediately after the pin control device has been
+registered.
+
+This is enabled by simply setting the .hog_on_boot field in the map to true,
+like this:
+
+{
+ .name "POWERMAP"
+ .ctrl_dev_name = "pinctrl.0",
+ .function = "power_func",
+ .hog_on_boot = true,
+},
+
+Since it may be common to request the core to hog a few always-applicable
+mux settings on the primary pin controller, there is a convenience macro for
+this:
+
+PINMUX_MAP_PRIMARY_SYS_HOG("POWERMAP", "power_func")
+
+This gives the exact same result as the above construction.
+
+
+Runtime pinmuxing
+=================
+
+It is possible to mux a certain function in and out at runtime, say to move
+an SPI port from one set of pins to another set of pins. Say for example for
+spi0 in the example above, we expose two different groups of pins for the same
+function, but with different named in the mapping as described under
+"Advanced mapping" above. So we have two mappings named "spi0-pos-A" and
+"spi0-pos-B".
+
+This snippet first muxes the function in the pins defined by group A, enables
+it, disables and releases it, and muxes it in on the pins defined by group B:
+
+foo_switch()
+{
+ struct pinmux pmx;
+
+ /* Enable on position A */
+ pmx = pinmux_get(&device, "spi0-pos-A");
+ if IS_ERR(pmx)
+ return PTR_ERR(pmx);
+ pinmux_enable(pmx);
+
+ /* This releases the pins again */
+ pinmux_disable(pmx);
+ pinmux_put(pmx);
+
+ /* Enable on position B */
+ pmx = pinmux_get(&device, "spi0-pos-B");
+ if IS_ERR(pmx)
+ return PTR_ERR(pmx);
+ pinmux_enable(pmx);
+ ...
+}
+
+The above has to be done from process context.
diff --git a/Documentation/power/00-INDEX b/Documentation/power/00-INDEX
index 45e9d4a91284..a4d682f54231 100644
--- a/Documentation/power/00-INDEX
+++ b/Documentation/power/00-INDEX
@@ -26,6 +26,8 @@ s2ram.txt
- How to get suspend to ram working (and debug it when it isn't)
states.txt
- System power management states
+suspend-and-cpuhotplug.txt
+ - Explains the interaction between Suspend-to-RAM (S3) and CPU hotplug
swsusp-and-swap-files.txt
- Using swap files with software suspend (to disk)
swsusp-dmcrypt.txt
diff --git a/Documentation/power/basic-pm-debugging.txt b/Documentation/power/basic-pm-debugging.txt
index ddd78172ef73..40a4c65f380a 100644
--- a/Documentation/power/basic-pm-debugging.txt
+++ b/Documentation/power/basic-pm-debugging.txt
@@ -173,7 +173,7 @@ kernel messages using the serial console. This may provide you with some
information about the reasons of the suspend (resume) failure. Alternatively,
it may be possible to use a FireWire port for debugging with firescope
(ftp://ftp.firstfloor.org/pub/ak/firescope/). On x86 it is also possible to
-use the PM_TRACE mechanism documented in Documentation/s2ram.txt .
+use the PM_TRACE mechanism documented in Documentation/power/s2ram.txt .
2. Testing suspend to RAM (STR)
@@ -201,3 +201,27 @@ case, you may be able to search for failing drivers by following the procedure
analogous to the one described in section 1. If you find some failing drivers,
you will have to unload them every time before an STR transition (ie. before
you run s2ram), and please report the problems with them.
+
+There is a debugfs entry which shows the suspend to RAM statistics. Here is an
+example of its output.
+ # mount -t debugfs none /sys/kernel/debug
+ # cat /sys/kernel/debug/suspend_stats
+ success: 20
+ fail: 5
+ failed_freeze: 0
+ failed_prepare: 0
+ failed_suspend: 5
+ failed_suspend_noirq: 0
+ failed_resume: 0
+ failed_resume_noirq: 0
+ failures:
+ last_failed_dev: alarm
+ adc
+ last_failed_errno: -16
+ -16
+ last_failed_step: suspend
+ suspend
+Field success means the success number of suspend to RAM, and field fail means
+the failure number. Others are the failure number of different steps of suspend
+to RAM. suspend_stats just lists the last 2 failed devices, error number and
+failed step of suspend.
diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt
index 3384d5996be2..646a89e0c07d 100644
--- a/Documentation/power/devices.txt
+++ b/Documentation/power/devices.txt
@@ -152,7 +152,9 @@ try to use its wakeup mechanism. device_set_wakeup_enable() affects this flag;
for the most part drivers should not change its value. The initial value of
should_wakeup is supposed to be false for the majority of devices; the major
exceptions are power buttons, keyboards, and Ethernet adapters whose WoL
-(wake-on-LAN) feature has been set up with ethtool.
+(wake-on-LAN) feature has been set up with ethtool. It should also default
+to true for devices that don't generate wakeup requests on their own but merely
+forward wakeup requests from one bus to another (like PCI bridges).
Whether or not a device is capable of issuing wakeup events is a hardware
matter, and the kernel is responsible for keeping track of it. By contrast,
@@ -279,10 +281,6 @@ When the system goes into the standby or memory sleep state, the phases are:
time.) Unlike the other suspend-related phases, during the prepare
phase the device tree is traversed top-down.
- In addition to that, if device drivers need to allocate additional
- memory to be able to hadle device suspend correctly, that should be
- done in the prepare phase.
-
After the prepare callback method returns, no new children may be
registered below the device. The method may also prepare the device or
driver in some way for the upcoming system power transition (for
diff --git a/Documentation/power/pm_qos_interface.txt b/Documentation/power/pm_qos_interface.txt
index bfed898a03fc..17e130a80347 100644
--- a/Documentation/power/pm_qos_interface.txt
+++ b/Documentation/power/pm_qos_interface.txt
@@ -4,14 +4,19 @@ This interface provides a kernel and user mode interface for registering
performance expectations by drivers, subsystems and user space applications on
one of the parameters.
-Currently we have {cpu_dma_latency, network_latency, network_throughput} as the
-initial set of pm_qos parameters.
+Two different PM QoS frameworks are available:
+1. PM QoS classes for cpu_dma_latency, network_latency, network_throughput.
+2. the per-device PM QoS framework provides the API to manage the per-device latency
+constraints.
Each parameters have defined units:
* latency: usec
* timeout: usec
* throughput: kbs (kilo bit / sec)
+
+1. PM QoS framework
+
The infrastructure exposes multiple misc device nodes one per implemented
parameter. The set of parameters implement is defined by pm_qos_power_init()
and pm_qos_params.h. This is done because having the available parameters
@@ -23,14 +28,18 @@ an aggregated target value. The aggregated target value is updated with
changes to the request list or elements of the list. Typically the
aggregated target value is simply the max or min of the request values held
in the parameter list elements.
+Note: the aggregated target value is implemented as an atomic variable so that
+reading the aggregated value does not require any locking mechanism.
+
From kernel mode the use of this interface is simple:
-handle = pm_qos_add_request(param_class, target_value):
-Will insert an element into the list for that identified PM_QOS class with the
+void pm_qos_add_request(handle, param_class, target_value):
+Will insert an element into the list for that identified PM QoS class with the
target value. Upon change to this list the new target is recomputed and any
registered notifiers are called only if the target value is now different.
-Clients of pm_qos need to save the returned handle.
+Clients of pm_qos need to save the returned handle for future use in other
+pm_qos API functions.
void pm_qos_update_request(handle, new_target_value):
Will update the list element pointed to by the handle with the new target value
@@ -42,6 +51,20 @@ Will remove the element. After removal it will update the aggregate target and
call the notification tree if the target was changed as a result of removing
the request.
+int pm_qos_request(param_class):
+Returns the aggregated value for a given PM QoS class.
+
+int pm_qos_request_active(handle):
+Returns if the request is still active, i.e. it has not been removed from a
+PM QoS class constraints list.
+
+int pm_qos_add_notifier(param_class, notifier):
+Adds a notification callback function to the PM QoS class. The callback is
+called when the aggregated value for the PM QoS class is changed.
+
+int pm_qos_remove_notifier(int param_class, notifier):
+Removes the notification callback function for the PM QoS class.
+
From user mode:
Only processes can register a pm_qos request. To provide for automatic
@@ -63,4 +86,63 @@ To remove the user mode request for a target value simply close the device
node.
+2. PM QoS per-device latency framework
+
+For each device a list of performance requests is maintained along with
+an aggregated target value. The aggregated target value is updated with
+changes to the request list or elements of the list. Typically the
+aggregated target value is simply the max or min of the request values held
+in the parameter list elements.
+Note: the aggregated target value is implemented as an atomic variable so that
+reading the aggregated value does not require any locking mechanism.
+
+
+From kernel mode the use of this interface is the following:
+
+int dev_pm_qos_add_request(device, handle, value):
+Will insert an element into the list for that identified device with the
+target value. Upon change to this list the new target is recomputed and any
+registered notifiers are called only if the target value is now different.
+Clients of dev_pm_qos need to save the handle for future use in other
+dev_pm_qos API functions.
+
+int dev_pm_qos_update_request(handle, new_value):
+Will update the list element pointed to by the handle with the new target value
+and recompute the new aggregated target, calling the notification trees if the
+target is changed.
+
+int dev_pm_qos_remove_request(handle):
+Will remove the element. After removal it will update the aggregate target and
+call the notification trees if the target was changed as a result of removing
+the request.
+
+s32 dev_pm_qos_read_value(device):
+Returns the aggregated value for a given device's constraints list.
+
+
+Notification mechanisms:
+The per-device PM QoS framework has 2 different and distinct notification trees:
+a per-device notification tree and a global notification tree.
+
+int dev_pm_qos_add_notifier(device, notifier):
+Adds a notification callback function for the device.
+The callback is called when the aggregated value of the device constraints list
+is changed.
+
+int dev_pm_qos_remove_notifier(device, notifier):
+Removes the notification callback function for the device.
+
+int dev_pm_qos_add_global_notifier(notifier):
+Adds a notification callback function in the global notification tree of the
+framework.
+The callback is called when the aggregated value for any device is changed.
+
+int dev_pm_qos_remove_global_notifier(notifier):
+Removes the notification callback function from the global notification tree
+of the framework.
+
+
+From user mode:
+No API for user space access to the per-device latency constraints is provided
+yet - still under discussion.
diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt
index 4ce5450ab6e8..0e856088db7c 100644
--- a/Documentation/power/runtime_pm.txt
+++ b/Documentation/power/runtime_pm.txt
@@ -43,13 +43,18 @@ struct dev_pm_ops {
...
};
-The ->runtime_suspend(), ->runtime_resume() and ->runtime_idle() callbacks are
-executed by the PM core for either the device type, or the class (if the device
-type's struct dev_pm_ops object does not exist), or the bus type (if the
-device type's and class' struct dev_pm_ops objects do not exist) of the given
-device (this allows device types to override callbacks provided by bus types or
-classes if necessary). The bus type, device type and class callbacks are
-referred to as subsystem-level callbacks in what follows.
+The ->runtime_suspend(), ->runtime_resume() and ->runtime_idle() callbacks
+are executed by the PM core for either the power domain, or the device type
+(if the device power domain's struct dev_pm_ops does not exist), or the class
+(if the device power domain's and type's struct dev_pm_ops object does not
+exist), or the bus type (if the device power domain's, type's and class'
+struct dev_pm_ops objects do not exist) of the given device, so the priority
+order of callbacks from high to low is that power domain callbacks, device
+type callbacks, class callbacks and bus type callbacks, and the high priority
+one will take precedence over low priority one. The bus type, device type and
+class callbacks are referred to as subsystem-level callbacks in what follows,
+and generally speaking, the power domain callbacks are used for representing
+power domains within a SoC.
By default, the callbacks are always invoked in process context with interrupts
enabled. However, subsystems can use the pm_runtime_irq_safe() helper function
@@ -431,8 +436,7 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
void pm_runtime_irq_safe(struct device *dev);
- set the power.irq_safe flag for the device, causing the runtime-PM
- suspend and resume callbacks (but not the idle callback) to be invoked
- with interrupts disabled
+ callbacks to be invoked with interrupts off
void pm_runtime_mark_last_busy(struct device *dev);
- set the power.last_busy field to the current time
@@ -478,12 +482,14 @@ pm_runtime_autosuspend_expiration()
If pm_runtime_irq_safe() has been called for a device then the following helper
functions may also be used in interrupt context:
+pm_runtime_idle()
pm_runtime_suspend()
pm_runtime_autosuspend()
pm_runtime_resume()
pm_runtime_get_sync()
pm_runtime_put_sync()
pm_runtime_put_sync_suspend()
+pm_runtime_put_sync_autosuspend()
5. Runtime PM Initialization, Device Probing and Removal
diff --git a/Documentation/power/suspend-and-cpuhotplug.txt b/Documentation/power/suspend-and-cpuhotplug.txt
new file mode 100644
index 000000000000..f28f9a6f0347
--- /dev/null
+++ b/Documentation/power/suspend-and-cpuhotplug.txt
@@ -0,0 +1,275 @@
+Interaction of Suspend code (S3) with the CPU hotplug infrastructure
+
+ (C) 2011 Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
+
+
+I. How does the regular CPU hotplug code differ from how the Suspend-to-RAM
+ infrastructure uses it internally? And where do they share common code?
+
+Well, a picture is worth a thousand words... So ASCII art follows :-)
+
+[This depicts the current design in the kernel, and focusses only on the
+interactions involving the freezer and CPU hotplug and also tries to explain
+the locking involved. It outlines the notifications involved as well.
+But please note that here, only the call paths are illustrated, with the aim
+of describing where they take different paths and where they share code.
+What happens when regular CPU hotplug and Suspend-to-RAM race with each other
+is not depicted here.]
+
+On a high level, the suspend-resume cycle goes like this:
+
+|Freeze| -> |Disable nonboot| -> |Do suspend| -> |Enable nonboot| -> |Thaw |
+|tasks | | cpus | | | | cpus | |tasks|
+
+
+More details follow:
+
+ Suspend call path
+ -----------------
+
+ Write 'mem' to
+ /sys/power/state
+ syfs file
+ |
+ v
+ Acquire pm_mutex lock
+ |
+ v
+ Send PM_SUSPEND_PREPARE
+ notifications
+ |
+ v
+ Freeze tasks
+ |
+ |
+ v
+ disable_nonboot_cpus()
+ /* start */
+ |
+ v
+ Acquire cpu_add_remove_lock
+ |
+ v
+ Iterate over CURRENTLY
+ online CPUs
+ |
+ |
+ | ----------
+ v | L
+ ======> _cpu_down() |
+ | [This takes cpuhotplug.lock |
+ Common | before taking down the CPU |
+ code | and releases it when done] | O
+ | While it is at it, notifications |
+ | are sent when notable events occur, |
+ ======> by running all registered callbacks. |
+ | | O
+ | |
+ | |
+ v |
+ Note down these cpus in | P
+ frozen_cpus mask ----------
+ |
+ v
+ Disable regular cpu hotplug
+ by setting cpu_hotplug_disabled=1
+ |
+ v
+ Release cpu_add_remove_lock
+ |
+ v
+ /* disable_nonboot_cpus() complete */
+ |
+ v
+ Do suspend
+
+
+
+Resuming back is likewise, with the counterparts being (in the order of
+execution during resume):
+* enable_nonboot_cpus() which involves:
+ | Acquire cpu_add_remove_lock
+ | Reset cpu_hotplug_disabled to 0, thereby enabling regular cpu hotplug
+ | Call _cpu_up() [for all those cpus in the frozen_cpus mask, in a loop]
+ | Release cpu_add_remove_lock
+ v
+
+* thaw tasks
+* send PM_POST_SUSPEND notifications
+* Release pm_mutex lock.
+
+
+It is to be noted here that the pm_mutex lock is acquired at the very
+beginning, when we are just starting out to suspend, and then released only
+after the entire cycle is complete (i.e., suspend + resume).
+
+
+
+ Regular CPU hotplug call path
+ -----------------------------
+
+ Write 0 (or 1) to
+ /sys/devices/system/cpu/cpu*/online
+ sysfs file
+ |
+ |
+ v
+ cpu_down()
+ |
+ v
+ Acquire cpu_add_remove_lock
+ |
+ v
+ If cpu_hotplug_disabled is 1
+ return gracefully
+ |
+ |
+ v
+ ======> _cpu_down()
+ | [This takes cpuhotplug.lock
+ Common | before taking down the CPU
+ code | and releases it when done]
+ | While it is at it, notifications
+ | are sent when notable events occur,
+ ======> by running all registered callbacks.
+ |
+ |
+ v
+ Release cpu_add_remove_lock
+ [That's it!, for
+ regular CPU hotplug]
+
+
+
+So, as can be seen from the two diagrams (the parts marked as "Common code"),
+regular CPU hotplug and the suspend code path converge at the _cpu_down() and
+_cpu_up() functions. They differ in the arguments passed to these functions,
+in that during regular CPU hotplug, 0 is passed for the 'tasks_frozen'
+argument. But during suspend, since the tasks are already frozen by the time
+the non-boot CPUs are offlined or onlined, the _cpu_*() functions are called
+with the 'tasks_frozen' argument set to 1.
+[See below for some known issues regarding this.]
+
+
+Important files and functions/entry points:
+------------------------------------------
+
+kernel/power/process.c : freeze_processes(), thaw_processes()
+kernel/power/suspend.c : suspend_prepare(), suspend_enter(), suspend_finish()
+kernel/cpu.c: cpu_[up|down](), _cpu_[up|down](), [disable|enable]_nonboot_cpus()
+
+
+
+II. What are the issues involved in CPU hotplug?
+ -------------------------------------------
+
+There are some interesting situations involving CPU hotplug and microcode
+update on the CPUs, as discussed below:
+
+[Please bear in mind that the kernel requests the microcode images from
+userspace, using the request_firmware() function defined in
+drivers/base/firmware_class.c]
+
+
+a. When all the CPUs are identical:
+
+ This is the most common situation and it is quite straightforward: we want
+ to apply the same microcode revision to each of the CPUs.
+ To give an example of x86, the collect_cpu_info() function defined in
+ arch/x86/kernel/microcode_core.c helps in discovering the type of the CPU
+ and thereby in applying the correct microcode revision to it.
+ But note that the kernel does not maintain a common microcode image for the
+ all CPUs, in order to handle case 'b' described below.
+
+
+b. When some of the CPUs are different than the rest:
+
+ In this case since we probably need to apply different microcode revisions
+ to different CPUs, the kernel maintains a copy of the correct microcode
+ image for each CPU (after appropriate CPU type/model discovery using
+ functions such as collect_cpu_info()).
+
+
+c. When a CPU is physically hot-unplugged and a new (and possibly different
+ type of) CPU is hot-plugged into the system:
+
+ In the current design of the kernel, whenever a CPU is taken offline during
+ a regular CPU hotplug operation, upon receiving the CPU_DEAD notification
+ (which is sent by the CPU hotplug code), the microcode update driver's
+ callback for that event reacts by freeing the kernel's copy of the
+ microcode image for that CPU.
+
+ Hence, when a new CPU is brought online, since the kernel finds that it
+ doesn't have the microcode image, it does the CPU type/model discovery
+ afresh and then requests the userspace for the appropriate microcode image
+ for that CPU, which is subsequently applied.
+
+ For example, in x86, the mc_cpu_callback() function (which is the microcode
+ update driver's callback registered for CPU hotplug events) calls
+ microcode_update_cpu() which would call microcode_init_cpu() in this case,
+ instead of microcode_resume_cpu() when it finds that the kernel doesn't
+ have a valid microcode image. This ensures that the CPU type/model
+ discovery is performed and the right microcode is applied to the CPU after
+ getting it from userspace.
+
+
+d. Handling microcode update during suspend/hibernate:
+
+ Strictly speaking, during a CPU hotplug operation which does not involve
+ physically removing or inserting CPUs, the CPUs are not actually powered
+ off during a CPU offline. They are just put to the lowest C-states possible.
+ Hence, in such a case, it is not really necessary to re-apply microcode
+ when the CPUs are brought back online, since they wouldn't have lost the
+ image during the CPU offline operation.
+
+ This is the usual scenario encountered during a resume after a suspend.
+ However, in the case of hibernation, since all the CPUs are completely
+ powered off, during restore it becomes necessary to apply the microcode
+ images to all the CPUs.
+
+ [Note that we don't expect someone to physically pull out nodes and insert
+ nodes with a different type of CPUs in-between a suspend-resume or a
+ hibernate/restore cycle.]
+
+ In the current design of the kernel however, during a CPU offline operation
+ as part of the suspend/hibernate cycle (the CPU_DEAD_FROZEN notification),
+ the existing copy of microcode image in the kernel is not freed up.
+ And during the CPU online operations (during resume/restore), since the
+ kernel finds that it already has copies of the microcode images for all the
+ CPUs, it just applies them to the CPUs, avoiding any re-discovery of CPU
+ type/model and the need for validating whether the microcode revisions are
+ right for the CPUs or not (due to the above assumption that physical CPU
+ hotplug will not be done in-between suspend/resume or hibernate/restore
+ cycles).
+
+
+III. Are there any known problems when regular CPU hotplug and suspend race
+ with each other?
+
+Yes, they are listed below:
+
+1. When invoking regular CPU hotplug, the 'tasks_frozen' argument passed to
+ the _cpu_down() and _cpu_up() functions is *always* 0.
+ This might not reflect the true current state of the system, since the
+ tasks could have been frozen by an out-of-band event such as a suspend
+ operation in progress. Hence, it will lead to wrong notifications being
+ sent during the cpu online/offline events (eg, CPU_ONLINE notification
+ instead of CPU_ONLINE_FROZEN) which in turn will lead to execution of
+ inappropriate code by the callbacks registered for such CPU hotplug events.
+
+2. If a regular CPU hotplug stress test happens to race with the freezer due
+ to a suspend operation in progress at the same time, then we could hit the
+ situation described below:
+
+ * A regular cpu online operation continues its journey from userspace
+ into the kernel, since the freezing has not yet begun.
+ * Then freezer gets to work and freezes userspace.
+ * If cpu online has not yet completed the microcode update stuff by now,
+ it will now start waiting on the frozen userspace in the
+ TASK_UNINTERRUPTIBLE state, in order to get the microcode image.
+ * Now the freezer continues and tries to freeze the remaining tasks. But
+ due to this wait mentioned above, the freezer won't be able to freeze
+ the cpu online hotplug task and hence freezing of tasks fails.
+
+ As a result of this task freezing failure, the suspend operation gets
+ aborted.
diff --git a/Documentation/power/userland-swsusp.txt b/Documentation/power/userland-swsusp.txt
index 1101bee4e822..0e870825c1b9 100644
--- a/Documentation/power/userland-swsusp.txt
+++ b/Documentation/power/userland-swsusp.txt
@@ -77,7 +77,8 @@ SNAPSHOT_SET_SWAP_AREA - set the resume partition and the offset (in <PAGE_SIZE>
resume_swap_area, as defined in kernel/power/suspend_ioctls.h,
containing the resume device specification and the offset); for swap
partitions the offset is always 0, but it is different from zero for
- swap files (see Documentation/swsusp-and-swap-files.txt for details).
+ swap files (see Documentation/power/swsusp-and-swap-files.txt for
+ details).
SNAPSHOT_PLATFORM_SUPPORT - enable/disable the hibernation platform support,
depending on the argument value (enable, if the argument is nonzero)
diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt
index 83668e5dd17f..03c9d9299c6b 100644
--- a/Documentation/rfkill.txt
+++ b/Documentation/rfkill.txt
@@ -117,5 +117,4 @@ The contents of these variables corresponds to the "name", "state" and
"type" sysfs files explained above.
-For further details consult Documentation/ABI/stable/dev-rfkill and
-Documentation/ABI/stable/sysfs-class-rfkill.
+For further details consult Documentation/ABI/stable/sysfs-class-rfkill.
diff --git a/Documentation/scsi/aic7xxx_old.txt b/Documentation/scsi/aic7xxx_old.txt
index 7bd210ab45a1..ecfc474f36a8 100644
--- a/Documentation/scsi/aic7xxx_old.txt
+++ b/Documentation/scsi/aic7xxx_old.txt
@@ -444,7 +444,7 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
Kernel Compile options
------------------------------
The various kernel compile time options for this driver are now fairly
- well documented in the file Documentation/Configure.help. In order to
+ well documented in the file drivers/scsi/Kconfig. In order to
see this documentation, you need to use one of the advanced configuration
programs (menuconfig and xconfig). If you are using the "make menuconfig"
method of configuring your kernel, then you would simply highlight the
diff --git a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt
index 5f17d29c59b5..a340b18cd4eb 100644
--- a/Documentation/scsi/scsi_mid_low_api.txt
+++ b/Documentation/scsi/scsi_mid_low_api.txt
@@ -55,11 +55,6 @@ or in the same directory as the C source code. For example to find a url
about the USB mass storage driver see the
/usr/src/linux/drivers/usb/storage directory.
-The Linux kernel source Documentation/DocBook/scsidrivers.tmpl file
-refers to this file. With the appropriate DocBook tool-set, this permits
-users to generate html, ps and pdf renderings of information within this
-file (e.g. the interface functions).
-
Driver structure
================
Traditionally an LLD for the SCSI subsystem has been at least two files in
diff --git a/Documentation/security/keys-trusted-encrypted.txt b/Documentation/security/keys-trusted-encrypted.txt
index 5f50ccabfc8a..c9e4855ed3d7 100644
--- a/Documentation/security/keys-trusted-encrypted.txt
+++ b/Documentation/security/keys-trusted-encrypted.txt
@@ -156,4 +156,5 @@ Load an encrypted key "evm" from saved blob:
Other uses for trusted and encrypted keys, such as for disk and file encryption
are anticipated. In particular the new format 'ecryptfs' has been defined in
in order to use encrypted keys to mount an eCryptfs filesystem. More details
-about the usage can be found in the file 'Documentation/keys-ecryptfs.txt'.
+about the usage can be found in the file
+'Documentation/security/keys-ecryptfs.txt'.
diff --git a/Documentation/sound/oss/PAS16 b/Documentation/sound/oss/PAS16
index 951b3dce51b4..3dca4b75988e 100644
--- a/Documentation/sound/oss/PAS16
+++ b/Documentation/sound/oss/PAS16
@@ -60,8 +60,7 @@ With PAS16 you can use two audio device files at the same time. /dev/dsp (and
The new stuff for 2.3.99 and later
============================================================================
-The following configuration options from Documentation/Configure.help
-are relevant to configuring the PAS16:
+The following configuration options are relevant to configuring the PAS16:
Sound card support
CONFIG_SOUND
diff --git a/Documentation/spi/pxa2xx b/Documentation/spi/pxa2xx
index 00511e08db78..3352f97430e4 100644
--- a/Documentation/spi/pxa2xx
+++ b/Documentation/spi/pxa2xx
@@ -2,7 +2,7 @@ PXA2xx SPI on SSP driver HOWTO
===================================================
This a mini howto on the pxa2xx_spi driver. The driver turns a PXA2xx
synchronous serial port into a SPI master controller
-(see Documentation/spi/spi_summary). The driver has the following features
+(see Documentation/spi/spi-summary). The driver has the following features
- Support for any PXA2xx SSP
- SSP PIO and SSP DMA data transfers.
@@ -85,7 +85,7 @@ Declaring Slave Devices
-----------------------
Typically each SPI slave (chip) is defined in the arch/.../mach-*/board-*.c
using the "spi_board_info" structure found in "linux/spi/spi.h". See
-"Documentation/spi/spi_summary" for additional information.
+"Documentation/spi/spi-summary" for additional information.
Each slave device attached to the PXA must provide slave specific configuration
information via the structure "pxa2xx_spi_chip" found in
diff --git a/Documentation/stable_kernel_rules.txt b/Documentation/stable_kernel_rules.txt
index e213f45cf9d7..21fd05c28e73 100644
--- a/Documentation/stable_kernel_rules.txt
+++ b/Documentation/stable_kernel_rules.txt
@@ -24,10 +24,10 @@ Rules on what kind of patches are accepted, and which ones are not, into the
Procedure for submitting patches to the -stable tree:
- Send the patch, after verifying that it follows the above rules, to
- stable@kernel.org. You must note the upstream commit ID in the changelog
- of your submission.
+ stable@vger.kernel.org. You must note the upstream commit ID in the
+ changelog of your submission.
- To have the patch automatically included in the stable tree, add the tag
- Cc: stable@kernel.org
+ Cc: stable@vger.kernel.org
in the sign-off area. Once the patch is merged it will be applied to
the stable tree without anything else needing to be done by the author
or subsystem maintainer.
@@ -35,10 +35,10 @@ Procedure for submitting patches to the -stable tree:
cherry-picked than this can be specified in the following format in
the sign-off area:
- Cc: <stable@kernel.org> # .32.x: a1f84a3: sched: Check for idle
- Cc: <stable@kernel.org> # .32.x: 1b9508f: sched: Rate-limit newidle
- Cc: <stable@kernel.org> # .32.x: fd21073: sched: Fix affinity logic
- Cc: <stable@kernel.org> # .32.x
+ Cc: <stable@vger.kernel.org> # .32.x: a1f84a3: sched: Check for idle
+ Cc: <stable@vger.kernel.org> # .32.x: 1b9508f: sched: Rate-limit newidle
+ Cc: <stable@vger.kernel.org> # .32.x: fd21073: sched: Fix affinity logic
+ Cc: <stable@vger.kernel.org> # .32.x
Signed-off-by: Ingo Molnar <mingo@elte.hu>
The tag sequence has the meaning of:
diff --git a/Documentation/timers/highres.txt b/Documentation/timers/highres.txt
index 21332233cef1..e8789976e77c 100644
--- a/Documentation/timers/highres.txt
+++ b/Documentation/timers/highres.txt
@@ -30,7 +30,7 @@ hrtimer base infrastructure
---------------------------
The hrtimer base infrastructure was merged into the 2.6.16 kernel. Details of
-the base implementation are covered in Documentation/hrtimers/hrtimer.txt. See
+the base implementation are covered in Documentation/timers/hrtimers.txt. See
also figure #2 (OLS slides p. 15)
The main differences to the timer wheel, which holds the armed timer_list type
diff --git a/Documentation/usb/dma.txt b/Documentation/usb/dma.txt
index 84ef865237db..444651e70d95 100644
--- a/Documentation/usb/dma.txt
+++ b/Documentation/usb/dma.txt
@@ -7,7 +7,7 @@ API OVERVIEW
The big picture is that USB drivers can continue to ignore most DMA issues,
though they still must provide DMA-ready buffers (see
-Documentation/PCI/PCI-DMA-mapping.txt). That's how they've worked through
+Documentation/DMA-API-HOWTO.txt). That's how they've worked through
the 2.4 (and earlier) kernels.
OR: they can now be DMA-aware.
@@ -57,7 +57,7 @@ and effects like cache-trashing can impose subtle penalties.
force a consistent memory access ordering by using memory barriers. It's
not using a streaming DMA mapping, so it's good for small transfers on
systems where the I/O would otherwise thrash an IOMMU mapping. (See
- Documentation/PCI/PCI-DMA-mapping.txt for definitions of "coherent" and
+ Documentation/DMA-API-HOWTO.txt for definitions of "coherent" and
"streaming" DMA mappings.)
Asking for 1/Nth of a page (as well as asking for N pages) is reasonably
@@ -88,7 +88,7 @@ WORKING WITH EXISTING BUFFERS
Existing buffers aren't usable for DMA without first being mapped into the
DMA address space of the device. However, most buffers passed to your
driver can safely be used with such DMA mapping. (See the first section
-of Documentation/PCI/PCI-DMA-mapping.txt, titled "What memory is DMA-able?")
+of Documentation/DMA-API-HOWTO.txt, titled "What memory is DMA-able?")
- When you're using scatterlists, you can map everything at once. On some
systems, this kicks in an IOMMU and turns the scatterlists into single
diff --git a/Documentation/usb/dwc3.txt b/Documentation/usb/dwc3.txt
new file mode 100644
index 000000000000..7b590edae145
--- /dev/null
+++ b/Documentation/usb/dwc3.txt
@@ -0,0 +1,45 @@
+
+ TODO
+~~~~~~
+Please pick something while reading :)
+
+- Convert interrupt handler to per-ep-thread-irq
+
+ As it turns out some DWC3-commands ~1ms to complete. Currently we spin
+ until the command completes which is bad.
+
+ Implementation idea:
+ - dwc core implements a demultiplexing irq chip for interrupts per
+ endpoint. The interrupt numbers are allocated during probe and belong
+ to the device. If MSI provides per-endpoint interrupt this dummy
+ interrupt chip can be replaced with "real" interrupts.
+ - interrupts are requested / allocated on usb_ep_enable() and removed on
+ usb_ep_disable(). Worst case are 32 interrupts, the lower limit is two
+ for ep0/1.
+ - dwc3_send_gadget_ep_cmd() will sleep in wait_for_completion_timeout()
+ until the command completes.
+ - the interrupt handler is split into the following pieces:
+ - primary handler of the device
+ goes through every event and calls generic_handle_irq() for event
+ it. On return from generic_handle_irq() in acknowledges the event
+ counter so interrupt goes away (eventually).
+
+ - threaded handler of the device
+ none
+
+ - primary handler of the EP-interrupt
+ reads the event and tries to process it. Everything that requries
+ sleeping is handed over to the Thread. The event is saved in an
+ per-endpoint data-structure.
+ We probably have to pay attention not to process events once we
+ handed something to thread so we don't process event X prio Y
+ where X > Y.
+
+ - threaded handler of the EP-interrupt
+ handles the remaining EP work which might sleep such as waiting
+ for command completion.
+
+ Latency:
+ There should be no increase in latency since the interrupt-thread has a
+ high priority and will be run before an average task in user land
+ (except the user changed priorities).
diff --git a/Documentation/usb/power-management.txt b/Documentation/usb/power-management.txt
index c9ffa9ced7ee..12511c98cc4f 100644
--- a/Documentation/usb/power-management.txt
+++ b/Documentation/usb/power-management.txt
@@ -439,10 +439,10 @@ cause autosuspends to fail with -EBUSY if the driver needs to use the
device.
External suspend calls should never be allowed to fail in this way,
-only autosuspend calls. The driver can tell them apart by checking
-the PM_EVENT_AUTO bit in the message.event argument to the suspend
-method; this bit will be set for internal PM events (autosuspend) and
-clear for external PM events.
+only autosuspend calls. The driver can tell them apart by applying
+the PMSG_IS_AUTO() macro to the message argument to the suspend
+method; it will return True for internal PM events (autosuspend) and
+False for external PM events.
Mutual exclusion
@@ -487,3 +487,29 @@ succeed, it may still remain active and thus cause the system to
resume as soon as the system suspend is complete. Or the remote
wakeup may fail and get lost. Which outcome occurs depends on timing
and on the hardware and firmware design.
+
+
+ xHCI hardware link PM
+ ---------------------
+
+xHCI host controller provides hardware link power management to usb2.0
+(xHCI 1.0 feature) and usb3.0 devices which support link PM. By
+enabling hardware LPM, the host can automatically put the device into
+lower power state(L1 for usb2.0 devices, or U1/U2 for usb3.0 devices),
+which state device can enter and resume very quickly.
+
+The user interface for controlling USB2 hardware LPM is located in the
+power/ subdirectory of each USB device's sysfs directory, that is, in
+/sys/bus/usb/devices/.../power/ where "..." is the device's ID. The
+relevant attribute files is usb2_hardware_lpm.
+
+ power/usb2_hardware_lpm
+
+ When a USB2 device which support LPM is plugged to a
+ xHCI host root hub which support software LPM, the
+ host will run a software LPM test for it; if the device
+ enters L1 state and resume successfully and the host
+ supports USB2 hardware LPM, this file will show up and
+ driver will enable hardware LPM for the device. You
+ can write y/Y/1 or n/N/0 to the file to enable/disable
+ USB2 hardware LPM manually. This is for test purpose mainly.
diff --git a/Documentation/virtual/lguest/lguest.c b/Documentation/virtual/lguest/lguest.c
index d928c134dee6..c095d79cae73 100644
--- a/Documentation/virtual/lguest/lguest.c
+++ b/Documentation/virtual/lguest/lguest.c
@@ -436,7 +436,7 @@ static unsigned long load_bzimage(int fd)
/*
* Go back to the start of the file and read the header. It should be
- * a Linux boot header (see Documentation/x86/i386/boot.txt)
+ * a Linux boot header (see Documentation/x86/boot.txt)
*/
lseek(fd, 0, SEEK_SET);
read(fd, &boot, sizeof(boot));
diff --git a/Documentation/vm/numa b/Documentation/vm/numa
index a200a386429d..ade01274212d 100644
--- a/Documentation/vm/numa
+++ b/Documentation/vm/numa
@@ -109,11 +109,11 @@ to improve NUMA locality using various CPU affinity command line interfaces,
such as taskset(1) and numactl(1), and program interfaces such as
sched_setaffinity(2). Further, one can modify the kernel's default local
allocation behavior using Linux NUMA memory policy.
-[see Documentation/vm/numa_memory_policy.]
+[see Documentation/vm/numa_memory_policy.txt.]
System administrators can restrict the CPUs and nodes' memories that a non-
privileged user can specify in the scheduling or NUMA commands and functions
-using control groups and CPUsets. [see Documentation/cgroups/CPUsets.txt]
+using control groups and CPUsets. [see Documentation/cgroups/cpusets.txt]
On architectures that do not hide memoryless nodes, Linux will include only
zones [nodes] with memory in the zonelists. This means that for a memoryless
diff --git a/Documentation/vm/slub.txt b/Documentation/vm/slub.txt
index 07375e73981a..f464f47bc60d 100644
--- a/Documentation/vm/slub.txt
+++ b/Documentation/vm/slub.txt
@@ -17,7 +17,7 @@ data and perform operation on the slabs. By default slabinfo only lists
slabs that have data in them. See "slabinfo -h" for more options when
running the command. slabinfo can be compiled with
-gcc -o slabinfo Documentation/vm/slabinfo.c
+gcc -o slabinfo tools/slub/slabinfo.c
Some of the modes of operation of slabinfo require that slub debugging
be enabled on the command line. F.e. no tracking information will be
diff --git a/Documentation/vm/transhuge.txt b/Documentation/vm/transhuge.txt
index 0924aaca3302..29bdf62aac09 100644
--- a/Documentation/vm/transhuge.txt
+++ b/Documentation/vm/transhuge.txt
@@ -123,10 +123,11 @@ be automatically shutdown if it's set to "never".
khugepaged runs usually at low frequency so while one may not want to
invoke defrag algorithms synchronously during the page faults, it
should be worth invoking defrag at least in khugepaged. However it's
-also possible to disable defrag in khugepaged:
+also possible to disable defrag in khugepaged by writing 0 or enable
+defrag in khugepaged by writing 1:
-echo yes >/sys/kernel/mm/transparent_hugepage/khugepaged/defrag
-echo no >/sys/kernel/mm/transparent_hugepage/khugepaged/defrag
+echo 0 >/sys/kernel/mm/transparent_hugepage/khugepaged/defrag
+echo 1 >/sys/kernel/mm/transparent_hugepage/khugepaged/defrag
You can also control how many pages khugepaged should scan at each
pass:
diff --git a/Documentation/zh_CN/SubmitChecklist b/Documentation/zh_CN/SubmitChecklist
deleted file mode 100644
index 4c741d6bc048..000000000000
--- a/Documentation/zh_CN/SubmitChecklist
+++ /dev/null
@@ -1,109 +0,0 @@
-Chinese translated version of Documentation/SubmitChecklist
-
-If you have any comment or update to the content, please contact the
-original document maintainer directly. However, if you have a problem
-communicating in English you can also ask the Chinese maintainer for
-help. Contact the Chinese maintainer if this translation is outdated
-or if there is a problem with the translation.
-
-Chinese maintainer: Harry Wei <harryxiyou@gmail.com>
----------------------------------------------------------------------
-Documentation/SubmitChecklist µÄÖÐÎÄ·­Òë
-
-Èç¹ûÏëÆÀÂÛ»ò¸üб¾ÎĵÄÄÚÈÝ£¬ÇëÖ±½ÓÁªÏµÔ­ÎĵµµÄά»¤Õß¡£Èç¹ûÄãʹÓÃÓ¢ÎÄ
-½»Á÷ÓÐÀ§ÄѵĻ°£¬Ò²¿ÉÒÔÏòÖÐÎÄ°æά»¤ÕßÇóÖú¡£Èç¹û±¾·­Òë¸üв»¼°Ê±»òÕß·­
-Òë´æÔÚÎÊÌ⣬ÇëÁªÏµÖÐÎÄ°æά»¤Õß¡£
-
-ÖÐÎÄ°æά»¤Õߣº ¼ÖÍþÍþ Harry Wei <harryxiyou@gmail.com>
-ÖÐÎÄ°æ·­ÒëÕߣº ¼ÖÍþÍþ Harry Wei <harryxiyou@gmail.com>
-ÖÐÎÄ°æУÒëÕߣº ¼ÖÍþÍþ Harry Wei <harryxiyou@gmail.com>
-
-
-ÒÔÏÂΪÕýÎÄ
----------------------------------------------------------------------
-LinuxÄÚºËÌá½»Çåµ¥
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-ÕâÀïÓÐһЩÄں˿ª·¢ÕßÓ¦¸Ã×öµÄ»ù±¾ÊÂÇ飬Èç¹ûËûÃÇÏë¿´µ½×Ô¼ºµÄÄں˲¹¶¡Ìá½»
-±»½ÓÊܵĸü¿ì¡£
-
-ÕâЩ¶¼Êdz¬³öDocumentation/SubmittingPatchesÎĵµÀïËùÌṩµÄÒÔ¼°ÆäËû
-¹ØÓÚÌá½»LinuxÄں˲¹¶¡µÄ˵Ã÷¡£
-
-1£ºÈç¹ûÄãʹÓÃÁËÒ»¸ö¹¦ÄÜÄÇô¾Í#include¶¨Òå/ÉùÃ÷ÄǸö¹¦ÄܵÄÄǸöÎļþ¡£
- ²»ÒªÒÀ¿¿ÆäËû¼ä½ÓÒýÈ붨Òå/ÉùÃ÷ÄǸö¹¦ÄܵÄÍ·Îļþ¡£
-
-2£º¹¹½¨¼ò½àÊÊÓûòÕ߸ü¸ÄCONFIGÑ¡Ïî =y£¬=m£¬»òÕß=n¡£
- ²»ÒªÓбàÒ뾯¸æ/´íÎó£¬ ²»ÒªÓÐÁ´½Ó¾¯¸æ/´íÎó¡£
-
-2b£ºÍ¨¹ý allnoconfig, allmodconfig
-
-2c£ºµ±Ê¹Óà 0=builddir ³É¹¦µØ¹¹½¨
-
-3£ºÍ¨¹ýʹÓñ¾µØ½»²æ±àÒ빤¾ß»òÕßÆäËûһЩ¹¹½¨²úËù£¬ÔÚ¶àCPU¿ò¼ÜÉϹ¹½¨¡£
-
-4£ºppc64 ÊÇÒ»¸öºÜºÃµÄ¼ì²é½»²æ±àÒëµÄ¿ò¼Ü£¬ÒòΪËüÍùÍù°Ñ¡®unsigned long¡¯
- µ±64λֵÀ´Ê¹Óá£
-
-5£º°´ÕÕDocumentation/CodingStyleÎļþÀïµÄÏêϸÃèÊö£¬¼ì²éÄã²¹¶¡µÄÕûÌå·ç¸ñ¡£
- ʹÓò¹¶¡·ç¸ñ¼ì²éËöËéµÄÎ¥¹æ(scripts/checkpatch.pl)£¬ÉóºËÔ±ÓÅÏÈÌá½»¡£
- ÄãÓ¦¸Ãµ÷ÕûÒÅÁôÔÚÄã²¹¶¡ÖеÄËùÓÐÎ¥¹æ¡£
-
-6£ºÈκθüлòÕ߸Ķ¯CONFIGÑ¡Ï²»ÄÜ´òÂÒÅäÖò˵¥¡£
-
-7£ºËùÓеÄKconfigÑ¡Ïî¸üж¼ÒªÓÐ˵Ã÷ÎÄ×Ö¡£
-
-8£ºÒѾ­ÈÏÕæµØ×ܽáÁËÏà¹ØµÄKconfig×éºÏ¡£ÕâÊǺÜÄÑͨ¹ý²âÊÔ×öºÃµÄ--ÄÔÁ¦ÔÚÕâÀïϽµ¡£
-
-9£º¼ì²é¾ßÓмò½àÐÔ¡£
-
-10£ºÊ¹ÓÃ'make checkstack'ºÍ'make namespacecheck'¼ì²é£¬È»ºóÐÞ¸ÄËùÕÒµ½µÄÎÊÌâ¡£
- ×¢Ò⣺¶ÑÕ»¼ì²é²»»áÃ÷È·µØ³öÏÖÎÊÌ⣬µ«ÊÇÈκεÄÒ»¸öº¯ÊýÔÚ¶ÑÕ»ÉÏʹÓöàÓÚ512×Ö½Ú
- ¶¼Òª×¼±¸Ð޸ġ£
-
-11£º°üº¬kernel-docµ½È«¾ÖÄÚºËAPIsÎļþ¡££¨²»ÒªÇó¾²Ì¬µÄº¯Êý£¬µ«ÊÇ°üº¬Ò²ÎÞËùν¡££©
- ʹÓÃ'make htmldocs'»òÕß'make mandocs'À´¼ì²ékernel-doc£¬È»ºóÐÞ¸ÄÈκÎ
- ·¢ÏÖµÄÎÊÌâ¡£
-
-12£ºÒѾ­Í¨¹ýCONFIG_PREEMPT, CONFIG_DEBUG_PREEMPT,
- CONFIG_DEBUG_SLAB, CONFIG_DEBUG_PAGEALLOC, CONFIG_DEBUG_MUTEXES,
- CONFIG_DEBUG_SPINLOCK, CONFIG_DEBUG_ATOMIC_SLEEP²âÊÔ£¬²¢ÇÒͬʱ¶¼
- ʹÄÜ¡£
-
-13£ºÒѾ­¶¼¹¹½¨²¢ÇÒʹÓûòÕß²»Ê¹Óà CONFIG_SMP ºÍ CONFIG_PREEMPT²âÊÔÖ´ÐÐʱ¼ä¡£
-
-14£ºÈç¹û²¹¶¡Ó°ÏìIO/Disk£¬µÈµÈ£ºÒѾ­Í¨¹ýʹÓûòÕß²»Ê¹Óà CONFIG_LBDAF ²âÊÔ¡£
-
-15£ºËùÓеÄcodepathsÒѾ­ÐÐʹËùÓÐlockdepÆôÓù¦ÄÜ¡£
-
-16£ºËùÓеÄ/proc¼Ç¼¸üж¼Òª×÷³ÉÎļþ·ÅÔÚDocumentation/Ŀ¼Ï¡£
-
-17£ºËùÓеÄÄÚºËÆô¶¯²ÎÊý¸üж¼±»¼Ç¼µ½Documentation/kernel-parameters.txtÎļþÖС£
-
-18£ºËùÓеÄÄ£¿é²ÎÊý¸üж¼ÓÃMODULE_PARM_DESC()¼Ç¼¡£
-
-19£ºËùÓеÄÓû§¿Õ¼ä½Ó¿Ú¸üж¼±»¼Ç¼µ½Documentation/ABI/¡£²é¿´Documentation/ABI/README
- ¿ÉÒÔ»ñµÃ¸ü¶àµÄÐÅÏ¢¡£¸Ä±äÓû§¿Õ¼ä½Ó¿ÚµÄ²¹¶¡Ó¦¸Ã±»Óʼþ³­Ë͸ølinux-api@vger.kernel.org¡£
-
-20£º¼ì²éËüÊDz»ÊǶ¼Í¨¹ý`make headers_check'¡£
-
-21£ºÒѾ­Í¨¹ýÖÁÉÙÒýÈëslabºÍpage-allocationʧ°Ü¼ì²é¡£²é¿´Documentation/fault-injection/¡£
-
-22£ºÐ¼ÓÈëµÄÔ´ÂëÒѾ­Í¨¹ý`gcc -W'£¨Ê¹ÓÃ"make EXTRA_CFLAGS=-W"£©±àÒë¡£ÕâÑù½«²úÉúºÜ¶à·³ÄÕ£¬
- µ«ÊǶÔÓÚÑ°ÕÒ©¶´ºÜÓÐÒæ´¦£¬ÀýÈç:"warning: comparison between signed and unsigned"¡£
-
-23£ºµ±Ëü±»ºÏ²¢µ½-mm²¹¶¡¼¯ºóÔÙ²âÊÔ£¬ÓÃÀ´È·¶¨ËüÊÇ·ñ»¹ºÍ²¹¶¡¶ÓÁÐÖеÄÆäËû²¹¶¡Ò»Æð¹¤×÷ÒÔ¼°ÔÚVM£¬VFS
- ºÍÆäËû×ÓϵͳÖи÷¸ö±ä»¯¡£
-
-24£ºËùÓеÄÄÚ´æÆÁÕÏ{e.g., barrier(), rmb(), wmb()}ÐèÒªÔÚÔ´´úÂëÖеÄÒ»¸ö×¢ÊÍÀ´½âÊÍËûÃǶ¼ÊǸÉʲôµÄ
- ÒÔ¼°Ô­Òò¡£
-
-25£ºÈç¹ûÓÐÈκÎÊäÈëÊä³ö¿ØÖƵIJ¹¶¡±»Ìí¼Ó£¬Ò²Òª¸üÐÂDocumentation/ioctl/ioctl-number.txt¡£
-
-26£ºÈç¹ûÄãµÄ¸ü¸Ä´úÂëÒÀ¿¿»òÕßʹÓÃÈκεÄÄÚºËAPIs»òÕßÓëÏÂÃæµÄkconfig·ûºÅÓйØϵµÄ¹¦ÄÜ£¬Äã¾ÍÒª
- ʹÓÃÏà¹ØµÄkconfig·ûºÅ¹Ø±Õ£¬ and/or =m£¨Èç¹ûÑ¡ÏîÌṩ£©[ÔÚͬһʱ¼ä²»ÊÇËùÓõĶ¼ÆôÓ㬽ö½ö¸÷¸ö»òÕß×ÔÓÉ
- ×éºÏËûÃÇ]£º
-
- CONFIG_SMP, CONFIG_SYSFS, CONFIG_PROC_FS, CONFIG_INPUT, CONFIG_PCI,
- CONFIG_BLOCK, CONFIG_PM, CONFIG_HOTPLUG, CONFIG_MAGIC_SYSRQ,
- CONFIG_NET, CONFIG_INET=n (ºóÒ»¸öʹÓà CONFIG_NET=y)
diff --git a/MAINTAINERS b/MAINTAINERS
index 069ee3b5c651..566ab1c23a3d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -117,20 +117,20 @@ Maintainers List (try to look for most precise areas first)
M: Philip Blundell <philb@gnu.org>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/3c505*
+F: drivers/net/ethernet/i825xx/3c505*
3C59X NETWORK DRIVER
M: Steffen Klassert <klassert@mathematik.tu-chemnitz.de>
L: netdev@vger.kernel.org
S: Maintained
F: Documentation/networking/vortex.txt
-F: drivers/net/3c59x.c
+F: drivers/net/ethernet/3com/3c59x.c
3CR990 NETWORK DRIVER
M: David Dillow <dave@thedillows.org>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/typhoon*
+F: drivers/net/ethernet/3com/typhoon*
3WARE SAS/SATA-RAID SCSI DRIVERS (3W-XXXX, 3W-9XXX, 3W-SAS)
M: Adam Radford <linuxraid@lsi.com>
@@ -156,7 +156,7 @@ M: Realtek linux nic maintainers <nic_swsd@realtek.com>
M: Francois Romieu <romieu@fr.zoreil.com>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/r8169.c
+F: drivers/net/ethernet/realtek/r8169.c
8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
M: Greg Kroah-Hartman <gregkh@suse.de>
@@ -170,8 +170,7 @@ F: include/linux/serial_8250.h
8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.]
L: netdev@vger.kernel.org
S: Orphan / Obsolete
-F: drivers/net/*8390*
-F: drivers/net/ax88796.c
+F: drivers/net/ethernet/8390/
9P FILE SYSTEM
M: Eric Van Hensbergen <ericvh@gmail.com>
@@ -214,7 +213,7 @@ ACENIC DRIVER
M: Jes Sorensen <jes@trained-monkey.org>
L: linux-acenic@sunsite.dk
S: Maintained
-F: drivers/net/acenic*
+F: drivers/net/ethernet/alteon/acenic*
ACER ASPIRE ONE TEMPERATURE AND FAN DRIVER
M: Peter Feuerer <peter@piie.net>
@@ -746,7 +745,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
W: http://www.arm.linux.org.uk/
S: Maintained
F: arch/arm/mach-ebsa110/
-F: drivers/net/arm/am79c961a.*
+F: drivers/net/ethernet/amd/am79c961a.*
ARM/EZX SMARTPHONES (A780, A910, A1200, E680, ROKR E2 and ROKR E6)
M: Daniel Ribeiro <drwyrm@gmail.com>
@@ -1015,7 +1014,8 @@ F: arch/arm/include/asm/hardware/ioc.h
F: arch/arm/include/asm/hardware/iomd.h
F: arch/arm/include/asm/hardware/memc.h
F: arch/arm/mach-rpc/
-F: drivers/net/arm/ether*
+F: drivers/net/ethernet/i825xx/ether1*
+F: drivers/net/ethernet/seeq/ether3*
F: drivers/scsi/arm/
ARM/SHARK MACHINE SUPPORT
@@ -1127,7 +1127,7 @@ F: arch/arm/mach-nuc93x/
F: drivers/input/keyboard/w90p910_keypad.c
F: drivers/input/touchscreen/w90p910_ts.c
F: drivers/watchdog/nuc900_wdt.c
-F: drivers/net/arm/w90p910_ether.c
+F: drivers/net/ethernet/nuvoton/w90p910_ether.c
F: drivers/mtd/nand/nuc900_nand.c
F: drivers/rtc/rtc-nuc900.c
F: drivers/spi/spi_nuc900.c
@@ -1230,7 +1230,7 @@ F: Documentation/aoe/
F: drivers/block/aoe/
ATHEROS ATH GENERIC UTILITIES
-M: "Luis R. Rodriguez" <lrodriguez@atheros.com>
+M: "Luis R. Rodriguez" <mcgrof@qca.qualcomm.com>
L: linux-wireless@vger.kernel.org
S: Supported
F: drivers/net/wireless/ath/*
@@ -1238,7 +1238,7 @@ F: drivers/net/wireless/ath/*
ATHEROS ATH5K WIRELESS DRIVER
M: Jiri Slaby <jirislaby@gmail.com>
M: Nick Kossifidis <mickflemm@gmail.com>
-M: "Luis R. Rodriguez" <lrodriguez@atheros.com>
+M: "Luis R. Rodriguez" <mcgrof@qca.qualcomm.com>
M: Bob Copeland <me@bobcopeland.com>
L: linux-wireless@vger.kernel.org
L: ath5k-devel@lists.ath5k.org
@@ -1246,11 +1246,19 @@ W: http://wireless.kernel.org/en/users/Drivers/ath5k
S: Maintained
F: drivers/net/wireless/ath/ath5k/
+ATHEROS ATH6KL WIRELESS DRIVER
+M: Kalle Valo <kvalo@qca.qualcomm.com>
+L: linux-wireless@vger.kernel.org
+W: http://wireless.kernel.org/en/users/Drivers/ath6kl
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath6kl.git
+S: Supported
+F: drivers/net/wireless/ath/ath6kl/
+
ATHEROS ATH9K WIRELESS DRIVER
-M: "Luis R. Rodriguez" <lrodriguez@atheros.com>
-M: Jouni Malinen <jmalinen@atheros.com>
-M: Vasanthakumar Thiagarajan <vasanth@atheros.com>
-M: Senthil Balasubramanian <senthilkumar@atheros.com>
+M: "Luis R. Rodriguez" <mcgrof@qca.qualcomm.com>
+M: Jouni Malinen <jouni@qca.qualcomm.com>
+M: Vasanthakumar Thiagarajan <vthiagar@qca.qualcomm.com>
+M: Senthil Balasubramanian <senthilb@qca.qualcomm.com>
L: linux-wireless@vger.kernel.org
L: ath9k-devel@lists.ath9k.org
W: http://wireless.kernel.org/en/users/Drivers/ath9k
@@ -1278,12 +1286,11 @@ F: drivers/input/misc/ati_remote2.c
ATLX ETHERNET DRIVERS
M: Jay Cliburn <jcliburn@gmail.com>
M: Chris Snook <chris.snook@gmail.com>
-M: Jie Yang <jie.yang@atheros.com>
L: netdev@vger.kernel.org
W: http://sourceforge.net/projects/atl1
W: http://atl1.sourceforge.net
S: Maintained
-F: drivers/net/atlx/
+F: drivers/net/ethernet/atheros/
ATM
M: Chas Williams <chas@cmf.nrl.navy.mil>
@@ -1323,7 +1330,7 @@ F: include/video/atmel_lcdc.h
ATMEL MACB ETHERNET DRIVER
M: Nicolas Ferre <nicolas.ferre@atmel.com>
S: Supported
-F: drivers/net/macb.*
+F: drivers/net/ethernet/cadence/
ATMEL SPI DRIVER
M: Nicolas Ferre <nicolas.ferre@atmel.com>
@@ -1446,7 +1453,7 @@ BLACKFIN EMAC DRIVER
L: uclinux-dist-devel@blackfin.uclinux.org
W: http://blackfin.uclinux.org
S: Supported
-F: drivers/net/bfin_mac.*
+F: drivers/net/ethernet/adi/
BLACKFIN RTC DRIVER
M: Mike Frysinger <vapier.adi@gmail.com>
@@ -1527,27 +1534,27 @@ BROADCOM B44 10/100 ETHERNET DRIVER
M: Gary Zambrano <zambrano@broadcom.com>
L: netdev@vger.kernel.org
S: Supported
-F: drivers/net/b44.*
+F: drivers/net/ethernet/broadcom/b44.*
BROADCOM BNX2 GIGABIT ETHERNET DRIVER
M: Michael Chan <mchan@broadcom.com>
L: netdev@vger.kernel.org
S: Supported
-F: drivers/net/bnx2.*
-F: drivers/net/bnx2_*
+F: drivers/net/ethernet/broadcom/bnx2.*
+F: drivers/net/ethernet/broadcom/bnx2_*
BROADCOM BNX2X 10 GIGABIT ETHERNET DRIVER
M: Eilon Greenstein <eilong@broadcom.com>
L: netdev@vger.kernel.org
S: Supported
-F: drivers/net/bnx2x/
+F: drivers/net/ethernet/broadcom/bnx2x/
BROADCOM TG3 GIGABIT ETHERNET DRIVER
M: Matt Carlson <mcarlson@broadcom.com>
M: Michael Chan <mchan@broadcom.com>
L: netdev@vger.kernel.org
S: Supported
-F: drivers/net/tg3.*
+F: drivers/net/ethernet/broadcom/tg3.*
BROADCOM BRCM80211 IEEE802.11n WIRELESS DRIVER
M: Brett Rudley <brudley@broadcom.com>
@@ -1574,10 +1581,9 @@ F: drivers/scsi/bfa/
BROCADE BNA 10 GIGABIT ETHERNET DRIVER
M: Rasesh Mody <rmody@brocade.com>
-M: Debashis Dutt <ddutt@brocade.com>
L: netdev@vger.kernel.org
S: Supported
-F: drivers/net/bna/
+F: drivers/net/ethernet/brocade/bna/
BSG (block layer generic sg v4 driver)
M: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
@@ -1665,7 +1671,7 @@ CAN NETWORK LAYER
M: Oliver Hartkopp <socketcan@hartkopp.net>
M: Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
M: Urs Thuermann <urs.thuermann@volkswagen.de>
-L: socketcan-core@lists.berlios.de (subscribers-only)
+L: linux-can@vger.kernel.org
L: netdev@vger.kernel.org
W: http://developer.berlios.de/projects/socketcan/
S: Maintained
@@ -1677,7 +1683,7 @@ F: include/linux/can/raw.h
CAN NETWORK DRIVERS
M: Wolfgang Grandegger <wg@grandegger.com>
-L: socketcan-core@lists.berlios.de (subscribers-only)
+L: linux-can@vger.kernel.org
L: netdev@vger.kernel.org
W: http://developer.berlios.de/projects/socketcan/
S: Maintained
@@ -1758,17 +1764,16 @@ F: Documentation/zh_CN/
CISCO VIC ETHERNET NIC DRIVER
M: Christian Benvenuti <benve@cisco.com>
-M: Vasanthy Kolluri <vkolluri@cisco.com>
M: Roopa Prabhu <roprabhu@cisco.com>
M: David Wang <dwang2@cisco.com>
S: Supported
-F: drivers/net/enic/
+F: drivers/net/ethernet/cisco/enic/
CIRRUS LOGIC EP93XX ETHERNET DRIVER
M: Hartley Sweeten <hsweeten@visionengravers.com>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/arm/ep93xx_eth.c
+F: drivers/net/ethernet/cirrus/ep93xx_eth.c
CIRRUS LOGIC EP93XX OHCI USB HOST DRIVER
M: Lennert Buytenhek <kernel@wantstofly.org>
@@ -1883,7 +1888,7 @@ S: Maintained
F: drivers/connector/
CONTROL GROUPS (CGROUPS)
-M: Paul Menage <menage@google.com>
+M: Paul Menage <paul@paulmenage.org>
M: Li Zefan <lizf@cn.fujitsu.com>
L: containers@lists.linux-foundation.org
S: Maintained
@@ -1908,7 +1913,7 @@ CPMAC ETHERNET DRIVER
M: Florian Fainelli <florian@openwrt.org>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/cpmac.c
+F: drivers/net/ethernet/ti/cpmac.c
CPU FREQUENCY DRIVERS
M: Dave Jones <davej@redhat.com>
@@ -1932,7 +1937,7 @@ S: Maintained
F: tools/power/cpupower
CPUSETS
-M: Paul Menage <menage@google.com>
+M: Paul Menage <paul@paulmenage.org>
W: http://www.bullopensource.org/cpuset/
W: http://oss.sgi.com/projects/cpusets/
S: Supported
@@ -1995,7 +2000,7 @@ M: Divy Le Ray <divy@chelsio.com>
L: netdev@vger.kernel.org
W: http://www.chelsio.com
S: Supported
-F: drivers/net/cxgb3/
+F: drivers/net/ethernet/chelsio/cxgb3/
CXGB3 IWARP RNIC DRIVER (IW_CXGB3)
M: Steve Wise <swise@chelsio.com>
@@ -2009,7 +2014,7 @@ M: Dimitris Michailidis <dm@chelsio.com>
L: netdev@vger.kernel.org
W: http://www.chelsio.com
S: Supported
-F: drivers/net/cxgb4/
+F: drivers/net/ethernet/chelsio/cxgb4/
CXGB4 IWARP RNIC DRIVER (IW_CXGB4)
M: Steve Wise <swise@chelsio.com>
@@ -2023,14 +2028,14 @@ M: Casey Leedom <leedom@chelsio.com>
L: netdev@vger.kernel.org
W: http://www.chelsio.com
S: Supported
-F: drivers/net/cxgb4vf/
+F: drivers/net/ethernet/chelsio/cxgb4vf/
STMMAC ETHERNET DRIVER
M: Giuseppe Cavallaro <peppe.cavallaro@st.com>
L: netdev@vger.kernel.org
W: http://www.stlinux.com
S: Supported
-F: drivers/net/stmmac/
+F: drivers/net/ethernet/stmicro/stmmac/
CYBERPRO FB DRIVER
M: Russell King <linux@arm.linux.org.uk>
@@ -2074,7 +2079,7 @@ DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER
L: netdev@vger.kernel.org
S: Orphan
F: Documentation/networking/dmfe.txt
-F: drivers/net/tulip/dmfe.c
+F: drivers/net/ethernet/tulip/dmfe.c
DC390/AM53C974 SCSI driver
M: Kurt Garloff <garloff@suse.de>
@@ -2113,7 +2118,7 @@ F: net/decnet/
DEFXX FDDI NETWORK DRIVER
M: "Maciej W. Rozycki" <macro@linux-mips.org>
S: Maintained
-F: drivers/net/defxx.*
+F: drivers/net/fddi/defxx.*
DELL LAPTOP DRIVER
M: Matthew Garrett <mjg59@srcf.ucam.org>
@@ -2139,6 +2144,14 @@ M: Matthew Garrett <mjg59@srcf.ucam.org>
S: Maintained
F: drivers/platform/x86/dell-wmi.c
+DESIGNWARE USB3 DRD IP DRIVER
+M: Felipe Balbi <balbi@ti.com>
+L: linux-usb@vger.kernel.org
+L: linux-omap@vger.kernel.org
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
+S: Maintained
+F: drivers/usb/dwc3/
+
DEVICE NUMBER REGISTRY
M: Torben Mathiasen <device@lanana.org>
W: http://lanana.org/docs/device-list/index.html
@@ -2297,6 +2310,12 @@ L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/wan/dscc4.c
+DYNAMIC DEBUG
+M: Jason Baron <jbaron@redhat.com>
+S: Maintained
+F: lib/dynamic_debug.c
+F: include/linux/dynamic_debug.h
+
DZ DECSTATION DZ11 SERIAL DRIVER
M: "Maciej W. Rozycki" <macro@linux-mips.org>
S: Maintained
@@ -2463,10 +2482,10 @@ S: Supported
F: drivers/infiniband/hw/ehca/
EHEA (IBM pSeries eHEA 10Gb ethernet adapter) DRIVER
-M: Breno Leitao <leitao@linux.vnet.ibm.com>
+M: Thadeu Lima de Souza Cascardo <cascardo@linux.vnet.ibm.com>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/ehea/
+F: drivers/net/ethernet/ibm/ehea/
EMBEDDED LINUX
M: Paul Gortmaker <paul.gortmaker@windriver.com>
@@ -2511,7 +2530,7 @@ ETHEREXPRESS-16 NETWORK DRIVER
M: Philip Blundell <philb@gnu.org>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/eexpress.*
+F: drivers/net/ethernet/i825xx/eexpress.*
ETHERNET BRIDGE
M: Stephen Hemminger <shemminger@linux-foundation.org>
@@ -2525,7 +2544,7 @@ F: net/bridge/
ETHERTEAM 16I DRIVER
M: Mika Kuoppala <miku@iki.fi>
S: Maintained
-F: drivers/net/eth16i.c
+F: drivers/net/ethernet/fujitsu/eth16i.c
EXT2 FILE SYSTEM
M: Jan Kara <jack@suse.cz>
@@ -2555,6 +2574,11 @@ S: Maintained
F: Documentation/filesystems/ext4.txt
F: fs/ext4/
+Extended Verification Module (EVM)
+M: Mimi Zohar <zohar@us.ibm.com>
+S: Supported
+F: security/integrity/evm/
+
F71805F HARDWARE MONITORING DRIVER
M: Jean Delvare <khali@linux-fr.org>
L: lm-sensors@lm-sensors.org
@@ -2649,11 +2673,11 @@ F: drivers/net/wan/dlci.c
F: drivers/net/wan/sdla.c
FRAMEBUFFER LAYER
-M: Paul Mundt <lethal@linux-sh.org>
+M: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
L: linux-fbdev@vger.kernel.org
W: http://linux-fbdev.sourceforge.net/
Q: http://patchwork.kernel.org/project/linux-fbdev/list/
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/lethal/fbdev-2.6.git
+T: git git://github.com/schandinat/linux-2.6.git fbdev-next
S: Maintained
F: Documentation/fb/
F: Documentation/devicetree/bindings/fb/
@@ -2689,7 +2713,7 @@ M: Vitaly Bordug <vbordug@ru.mvista.com>
L: linuxppc-dev@lists.ozlabs.org
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/fs_enet/
+F: drivers/net/ethernet/freescale/fs_enet/
F: include/linux/fs_enet_pd.h
FREESCALE QUICC ENGINE LIBRARY
@@ -2711,7 +2735,7 @@ M: Li Yang <leoli@freescale.com>
L: netdev@vger.kernel.org
L: linuxppc-dev@lists.ozlabs.org
S: Maintained
-F: drivers/net/ucc_geth*
+F: drivers/net/ethernet/freescale/ucc_geth*
FREESCALE QUICC ENGINE UCC UART DRIVER
M: Timur Tabi <timur@freescale.com>
@@ -2736,7 +2760,7 @@ F: fs/freevxfs/
FREEZER
M: Pavel Machek <pavel@ucw.cz>
M: "Rafael J. Wysocki" <rjw@sisk.pl>
-L: linux-pm@lists.linux-foundation.org
+L: linux-pm@vger.kernel.org
S: Supported
F: Documentation/power/freezing-of-tasks.txt
F: include/linux/freezer.h
@@ -2998,7 +3022,7 @@ F: drivers/video/hgafb.c
HIBERNATION (aka Software Suspend, aka swsusp)
M: Pavel Machek <pavel@ucw.cz>
M: "Rafael J. Wysocki" <rjw@sisk.pl>
-L: linux-pm@lists.linux-foundation.org
+L: linux-pm@vger.kernel.org
S: Supported
F: arch/x86/power/
F: drivers/base/power/
@@ -3049,6 +3073,7 @@ S: Maintained
F: include/linux/hippidevice.h
F: include/linux/if_hippi.h
F: net/802/hippi.c
+F: drivers/net/hippi/
HOST AP DRIVER
M: Jouni Malinen <j@w1.fi>
@@ -3066,7 +3091,7 @@ F: drivers/platform/x86/tc1100-wmi.c
HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
M: Jaroslav Kysela <perex@perex.cz>
S: Maintained
-F: drivers/net/hp100.*
+F: drivers/net/ethernet/hp/hp100.*
HPET: High Precision Event Timers driver
M: Clemens Ladisch <clemens@ladisch.de>
@@ -3164,7 +3189,7 @@ IBM Power Virtual Ethernet Device Driver
M: Santiago Leon <santil@linux.vnet.ibm.com>
L: netdev@vger.kernel.org
S: Supported
-F: drivers/net/ibmveth.*
+F: drivers/net/ethernet/ibm/ibmveth.*
IBM ServeRAID RAID DRIVER
P: Jack Hammer
@@ -3192,7 +3217,7 @@ F: drivers/ide/ide-cd*
IDLE-I7300
M: Andy Henroid <andrew.d.henroid@intel.com>
-L: linux-pm@lists.linux-foundation.org
+L: linux-pm@vger.kernel.org
S: Supported
F: drivers/idle/i7300_idle.c
@@ -3262,9 +3287,20 @@ F: Documentation/input/multi-touch-protocol.txt
F: drivers/input/input-mt.c
K: \b(ABS|SYN)_MT_
+INTEL C600 SERIES SAS CONTROLLER DRIVER
+M: Intel SCU Linux support <intel-linux-scu@intel.com>
+M: Dan Williams <dan.j.williams@intel.com>
+M: Dave Jiang <dave.jiang@intel.com>
+M: Ed Nadolski <edmund.nadolski@intel.com>
+L: linux-scsi@vger.kernel.org
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/djbw/isci.git
+S: Maintained
+F: drivers/scsi/isci/
+F: firmware/isci/
+
INTEL IDLE DRIVER
M: Len Brown <lenb@kernel.org>
-L: linux-pm@lists.linux-foundation.org
+L: linux-pm@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-idle-2.6.git
S: Supported
F: drivers/idle/intel_idle.c
@@ -3305,7 +3341,7 @@ M: David Woodhouse <dwmw2@infradead.org>
L: iommu@lists.linux-foundation.org
T: git git://git.infradead.org/iommu-2.6.git
S: Supported
-F: drivers/pci/intel-iommu.c
+F: drivers/iommu/intel-iommu.c
F: include/linux/intel-iommu.h
INTEL IOP-ADMA DMA DRIVER
@@ -3320,7 +3356,7 @@ F: arch/arm/mach-ixp4xx/include/mach/qmgr.h
F: arch/arm/mach-ixp4xx/include/mach/npe.h
F: arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
F: arch/arm/mach-ixp4xx/ixp4xx_npe.c
-F: drivers/net/arm/ixp4xx_eth.c
+F: drivers/net/ethernet/xscale/ixp4xx_eth.c
F: drivers/net/wan/ixp4xx_hss.c
INTEL IXP4XX RANDOM NUMBER GENERATOR SUPPORT
@@ -3332,7 +3368,7 @@ INTEL IXP2000 ETHERNET DRIVER
M: Lennert Buytenhek <kernel@wantstofly.org>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/ixp2000/
+F: drivers/net/ethernet/xscale/ixp2000/
INTEL ETHERNET DRIVERS (e100/e1000/e1000e/igb/igbvf/ixgb/ixgbe/ixgbevf)
M: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
@@ -3341,13 +3377,13 @@ M: Bruce Allan <bruce.w.allan@intel.com>
M: Carolyn Wyborny <carolyn.wyborny@intel.com>
M: Don Skidmore <donald.c.skidmore@intel.com>
M: Greg Rose <gregory.v.rose@intel.com>
-M: PJ Waskiewicz <peter.p.waskiewicz.jr@intel.com>
+M: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
M: Alex Duyck <alexander.h.duyck@intel.com>
M: John Ronciak <john.ronciak@intel.com>
L: e1000-devel@lists.sourceforge.net
W: http://e1000.sourceforge.net/
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-2.6.git
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-next-2.6.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-next.git
S: Supported
F: Documentation/networking/e100.txt
F: Documentation/networking/e1000.txt
@@ -3357,18 +3393,11 @@ F: Documentation/networking/igbvf.txt
F: Documentation/networking/ixgb.txt
F: Documentation/networking/ixgbe.txt
F: Documentation/networking/ixgbevf.txt
-F: drivers/net/e100.c
-F: drivers/net/e1000/
-F: drivers/net/e1000e/
-F: drivers/net/igb/
-F: drivers/net/igbvf/
-F: drivers/net/ixgb/
-F: drivers/net/ixgbe/
-F: drivers/net/ixgbevf/
+F: drivers/net/ethernet/intel/
INTEL MRST PMU DRIVER
M: Len Brown <len.brown@intel.com>
-L: linux-pm@lists.linux-foundation.org
+L: linux-pm@vger.kernel.org
S: Supported
F: arch/x86/platform/mrst/pmu.*
@@ -3416,7 +3445,7 @@ M: Wey-Yi Guy <wey-yi.w.guy@intel.com>
M: Intel Linux Wireless <ilw@linux.intel.com>
L: linux-wireless@vger.kernel.org
W: http://intellinuxwireless.org
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-2.6.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi.git
S: Supported
F: drivers/net/wireless/iwlwifi/
@@ -3432,7 +3461,7 @@ IOC3 ETHERNET DRIVER
M: Ralf Baechle <ralf@linux-mips.org>
L: linux-mips@linux-mips.org
S: Maintained
-F: drivers/net/ioc3-eth.c
+F: drivers/net/ethernet/sgi/ioc3-eth.c
IOC3 SERIAL DRIVER
M: Pat Gefre <pfg@sgi.com>
@@ -3450,7 +3479,7 @@ M: Francois Romieu <romieu@fr.zoreil.com>
M: Sorbica Shieh <sorbica@icplus.com.tw>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/ipg.*
+F: drivers/net/ethernet/icplus/ipg.*
IPATH DRIVER
M: Mike Marciniszyn <infinipath@qlogic.com>
@@ -3598,7 +3627,7 @@ JME NETWORK DRIVER
M: Guo-Fu Tseng <cooldavid@cooldavid.org>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/jme.*
+F: drivers/net/ethernet/jme.*
JOURNALLING FLASH FILE SYSTEM V2 (JFFS2)
M: David Woodhouse <dwmw2@infradead.org>
@@ -4059,7 +4088,7 @@ S: Maintained
M32R ARCHITECTURE
M: Hirokazu Takata <takata@linux-m32r.org>
-L: linux-m32r@ml.linux-m32r.org
+L: linux-m32r@ml.linux-m32r.org (moderated for non-subscribers)
L: linux-m32r-ja@ml.linux-m32r.org (in Japanese)
W: http://www.linux-m32r.org/
S: Maintained
@@ -4129,7 +4158,7 @@ MARVELL MV643XX ETHERNET DRIVER
M: Lennert Buytenhek <buytenh@wantstofly.org>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/mv643xx_eth.*
+F: drivers/net/ethernet/marvell/mv643xx_eth.*
F: include/linux/mv643xx.h
MARVELL MWIFIEX WIRELESS DRIVER
@@ -4228,7 +4257,7 @@ F: include/mtd/
MICROBLAZE ARCHITECTURE
M: Michal Simek <monstr@monstr.eu>
-L: microblaze-uclinux@itee.uq.edu.au
+L: microblaze-uclinux@itee.uq.edu.au (moderated for non-subscribers)
W: http://www.monstr.eu/fdt/
T: git git://git.monstr.eu/linux-2.6-microblaze.git
S: Supported
@@ -4343,12 +4372,12 @@ M: Andrew Gallatin <gallatin@myri.com>
L: netdev@vger.kernel.org
W: http://www.myri.com/scs/download-Myri10GE.html
S: Supported
-F: drivers/net/myri10ge/
+F: drivers/net/ethernet/myricom/myri10ge/
NATSEMI ETHERNET DRIVER (DP8381x)
M: Tim Hockin <thockin@hockin.org>
S: Maintained
-F: drivers/net/natsemi.c
+F: drivers/net/ethernet/natsemi/natsemi.c
NATIVE INSTRUMENTS USB SOUND INTERFACE DRIVER
M: Daniel Mack <zonque@gmail.com>
@@ -4388,9 +4417,8 @@ W: http://trac.neterion.com/cgi-bin/trac.cgi/wiki/Linux?Anonymous
W: http://trac.neterion.com/cgi-bin/trac.cgi/wiki/X3100Linux?Anonymous
S: Supported
F: Documentation/networking/s2io.txt
-F: drivers/net/s2io*
F: Documentation/networking/vxge.txt
-F: drivers/net/vxge/
+F: drivers/net/ethernet/neterion/
NETFILTER/IPTABLES/IPCHAINS
P: Rusty Russell
@@ -4404,7 +4432,8 @@ L: netfilter@vger.kernel.org
L: coreteam@netfilter.org
W: http://www.netfilter.org/
W: http://www.iptables.org/
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-2.6.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-2.6.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next-2.6.git
S: Supported
F: include/linux/netfilter*
F: include/linux/netfilter/
@@ -4450,8 +4479,8 @@ M: "David S. Miller" <davem@davemloft.net>
L: netdev@vger.kernel.org
W: http://www.linuxfoundation.org/en/Net
W: http://patchwork.ozlabs.org/project/netdev/list/
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6.git
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git
S: Maintained
F: net/
F: include/net/
@@ -4503,11 +4532,23 @@ F: include/linux/if_*
F: include/linux/*device.h
NETXEN (1/10) GbE SUPPORT
-M: Amit Kumar Salecha <amit.salecha@qlogic.com>
+M: Sony Chacko <sony.chacko@qlogic.com>
+M: Rajesh Borundia <rajesh.borundia@qlogic.com>
L: netdev@vger.kernel.org
W: http://www.qlogic.com
S: Supported
-F: drivers/net/netxen/
+F: drivers/net/ethernet/qlogic/netxen/
+
+NFC SUBSYSTEM
+M: Lauro Ramos Venancio <lauro.venancio@openbossa.org>
+M: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
+M: Samuel Ortiz <sameo@linux.intel.com>
+L: linux-wireless@vger.kernel.org
+S: Maintained
+F: net/nfc/
+F: include/linux/nfc.h
+F: include/net/nfc/
+F: drivers/nfc/
NFS, SUNRPC, AND LOCKD CLIENTS
M: Trond Myklebust <Trond.Myklebust@netapp.com>
@@ -4528,7 +4569,7 @@ M: Jan-Pascal van Best <janpascal@vanbest.org>
M: Andreas Mohr <andi@lisas.de>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/ni5010.*
+F: drivers/net/ethernet/racal/ni5010.*
NILFS2 FILESYSTEM
M: KONISHI Ryusuke <konishi.ryusuke@lab.ntt.co.jp>
@@ -4731,7 +4772,7 @@ K: of_match_table
OPENRISC ARCHITECTURE
M: Jonas Bonn <jonas@southpole.se>
W: http://openrisc.net
-L: linux@lists.openrisc.net
+L: linux@lists.openrisc.net (moderated for non-subscribers)
S: Maintained
T: git git://openrisc.net/~jonas/linux
F: arch/openrisc
@@ -4774,7 +4815,7 @@ F: drivers/net/wireless/orinoco/
OSD LIBRARY and FILESYSTEM
M: Boaz Harrosh <bharrosh@panasas.com>
-M: Benny Halevy <bhalevy@panasas.com>
+M: Benny Halevy <bhalevy@tonian.com>
L: osd-dev@open-osd.org
W: http://open-osd.org
T: git git://git.open-osd.org/open-osd.git
@@ -4794,7 +4835,7 @@ PA SEMI ETHERNET DRIVER
M: Olof Johansson <olof@lixom.net>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/pasemi_mac.*
+F: drivers/net/ethernet/pasemi/*
PA SEMI SMBUS DRIVER
M: Olof Johansson <olof@lixom.net>
@@ -4941,7 +4982,7 @@ PCNET32 NETWORK DRIVER
M: Don Fry <pcnet32@frontier.com>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/pcnet32.c
+F: drivers/net/ethernet/amd/pcnet32.c
PCRYPT PARALLEL CRYPTO ENGINE
M: Steffen Klassert <steffen.klassert@secunet.com>
@@ -5001,6 +5042,11 @@ L: linux-mtd@lists.infradead.org
S: Maintained
F: drivers/mtd/devices/phram.c
+PIN CONTROL SUBSYSTEM
+M: Linus Walleij <linus.walleij@linaro.org>
+S: Maintained
+F: drivers/pinmux/
+
PKTCDVD DRIVER
M: Peter Osterlund <petero2@telia.com>
S: Maintained
@@ -5073,7 +5119,7 @@ PPP PROTOCOL DRIVERS AND COMPRESSORS
M: Paul Mackerras <paulus@samba.org>
L: linux-ppp@vger.kernel.org
S: Maintained
-F: drivers/net/ppp_*
+F: drivers/net/ppp/ppp_*
PPP OVER ATM (RFC 2364)
M: Mitchell Blank Jr <mitch@sfgoth.com>
@@ -5084,8 +5130,8 @@ F: include/linux/atmppp.h
PPP OVER ETHERNET
M: Michal Ostrowski <mostrows@earthlink.net>
S: Maintained
-F: drivers/net/pppoe.c
-F: drivers/net/pppox.c
+F: drivers/net/ppp/pppoe.c
+F: drivers/net/ppp/pppox.c
PPP OVER L2TP
M: James Chapman <jchapman@katalix.com>
@@ -5106,7 +5152,7 @@ PPTP DRIVER
M: Dmitry Kozlov <xeb@mail.ru>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/pptp.c
+F: drivers/net/ppp/pptp.c
W: http://sourceforge.net/projects/accel-pptp
PREEMPTIBLE KERNEL
@@ -5135,7 +5181,7 @@ M: Geoff Levand <geoff@infradead.org>
L: netdev@vger.kernel.org
L: cbe-oss-dev@lists.ozlabs.org
S: Maintained
-F: drivers/net/ps3_gelic_net.*
+F: drivers/net/ethernet/toshiba/ps3_gelic_net.*
PS3 PLATFORM SUPPORT
M: Geoff Levand <geoff@infradead.org>
@@ -5253,23 +5299,24 @@ M: linux-driver@qlogic.com
L: netdev@vger.kernel.org
S: Supported
F: Documentation/networking/LICENSE.qla3xxx
-F: drivers/net/qla3xxx.*
+F: drivers/net/ethernet/qlogic/qla3xxx.*
QLOGIC QLCNIC (1/10)Gb ETHERNET DRIVER
-M: Amit Kumar Salecha <amit.salecha@qlogic.com>
M: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
+M: Sony Chacko <sony.chacko@qlogic.com>
M: linux-driver@qlogic.com
L: netdev@vger.kernel.org
S: Supported
-F: drivers/net/qlcnic/
+F: drivers/net/ethernet/qlogic/qlcnic/
QLOGIC QLGE 10Gb ETHERNET DRIVER
+M: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
M: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
M: Ron Mercer <ron.mercer@qlogic.com>
M: linux-driver@qlogic.com
L: netdev@vger.kernel.org
S: Supported
-F: drivers/net/qlge/
+F: drivers/net/ethernet/qlogic/qlge/
QNX4 FILESYSTEM
M: Anders Larsen <al@alarsen.net>
@@ -5351,7 +5398,7 @@ RDC R6040 FAST ETHERNET DRIVER
M: Florian Fainelli <florian@openwrt.org>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/r6040.c
+F: drivers/net/ethernet/rdc/r6040.c
RDS - RELIABLE DATAGRAM SOCKETS
M: Andy Grover <andy.grover@oracle.com>
@@ -5532,6 +5579,7 @@ F: include/media/*7146*
SAMSUNG AUDIO (ASoC) DRIVERS
M: Jassi Brar <jassisinghbrar@gmail.com>
+M: Sangbeom Kim <sbkim73@samsung.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Supported
F: sound/soc/samsung
@@ -5754,7 +5802,7 @@ M: Ajit Khaparde <ajit.khaparde@emulex.com>
L: netdev@vger.kernel.org
W: http://www.emulex.com
S: Supported
-F: drivers/net/benet/
+F: drivers/net/ethernet/emulex/benet/
SFC NETWORK DRIVER
M: Solarflare linux maintainers <linux-net-drivers@solarflare.com>
@@ -5762,7 +5810,7 @@ M: Steve Hodgson <shodgson@solarflare.com>
M: Ben Hutchings <bhutchings@solarflare.com>
L: netdev@vger.kernel.org
S: Supported
-F: drivers/net/sfc/
+F: drivers/net/ethernet/sfc/
SGI GRU DRIVER
M: Jack Steiner <steiner@sgi.com>
@@ -5828,14 +5876,14 @@ SIS 190 ETHERNET DRIVER
M: Francois Romieu <romieu@fr.zoreil.com>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/sis190.c
+F: drivers/net/ethernet/sis/sis190.c
SIS 900/7016 FAST ETHERNET DRIVER
M: Daniele Venzano <venza@brownhat.org>
W: http://www.brownhat.org/sis900.html
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/sis900.*
+F: drivers/net/ethernet/sis/sis900.*
SIS 96X I2C/SMBUS DRIVER
M: "Mark M. Hoffman" <mhoffman@lightlink.com>
@@ -5862,8 +5910,7 @@ SKGE, SKY2 10/100/1000 GIGABIT ETHERNET DRIVERS
M: Stephen Hemminger <shemminger@linux-foundation.org>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/skge.*
-F: drivers/net/sky2.*
+F: drivers/net/ethernet/marvell/sk*
SLAB ALLOCATOR
M: Christoph Lameter <cl@linux-foundation.org>
@@ -5877,7 +5924,7 @@ F: mm/sl?b.c
SMC91x ETHERNET DRIVER
M: Nicolas Pitre <nico@fluxnic.net>
S: Odd Fixes
-F: drivers/net/smc91x.*
+F: drivers/net/ethernet/smsc/smc91x.*
SMM665 HARDWARE MONITOR DRIVER
M: Guenter Roeck <linux@roeck-us.net>
@@ -5912,13 +5959,13 @@ M: Steve Glendinning <steve.glendinning@smsc.com>
L: netdev@vger.kernel.org
S: Supported
F: include/linux/smsc911x.h
-F: drivers/net/smsc911x.*
+F: drivers/net/ethernet/smsc/smsc911x.*
SMSC9420 PCI ETHERNET DRIVER
M: Steve Glendinning <steve.glendinning@smsc.com>
L: netdev@vger.kernel.org
S: Supported
-F: drivers/net/smsc9420.*
+F: drivers/net/ethernet/smsc/smsc9420.*
SN-IA64 (Itanium) SUB-PLATFORM
M: Jes Sorensen <jes@sgi.com>
@@ -5952,7 +5999,7 @@ SONIC NETWORK DRIVER
M: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/sonic.*
+F: drivers/net/ethernet/natsemi/sonic.*
SONICS SILICON BACKPLANE DRIVER (SSB)
M: Michael Buesch <m@bues.ch>
@@ -6093,7 +6140,7 @@ M: Jens Osterkamp <jens@de.ibm.com>
L: netdev@vger.kernel.org
S: Supported
F: Documentation/networking/spider_net.txt
-F: drivers/net/spider_net*
+F: drivers/net/ethernet/toshiba/spider_net*
SPU FILE SYSTEM
M: Jeremy Kerr <jk@ozlabs.org>
@@ -6140,12 +6187,6 @@ M: Jakub Schmidtke <sjakub@gmail.com>
S: Odd Fixes
F: drivers/staging/asus_oled/
-STAGING - ATHEROS ATH6KL WIRELESS DRIVER
-M: Luis R. Rodriguez <mcgrof@gmail.com>
-M: Naveen Singh <nsingh@atheros.com>
-S: Odd Fixes
-F: drivers/staging/ath6kl/
-
STAGING - COMEDI
M: Ian Abbott <abbotti@mev.co.uk>
M: Mori Hess <fmhess@users.sourceforge.net>
@@ -6271,7 +6312,7 @@ F: drivers/staging/xgifb/
STARFIRE/DURALAN NETWORK DRIVER
M: Ion Badulescu <ionut@badula.org>
S: Odd Fixes
-F: drivers/net/starfire*
+F: drivers/net/ethernet/adaptec/starfire*
SUN3/3X
M: Sam Creasey <sammy@sammy.net>
@@ -6280,6 +6321,7 @@ S: Maintained
F: arch/m68k/kernel/*sun3*
F: arch/m68k/sun3*/
F: arch/m68k/include/asm/sun3*
+F: drivers/net/ethernet/i825xx/sun3*
SUPERH
M: Paul Mundt <lethal@linux-sh.org>
@@ -6296,7 +6338,7 @@ SUSPEND TO RAM
M: Len Brown <len.brown@intel.com>
M: Pavel Machek <pavel@ucw.cz>
M: "Rafael J. Wysocki" <rjw@sisk.pl>
-L: linux-pm@lists.linux-foundation.org
+L: linux-pm@vger.kernel.org
S: Supported
F: Documentation/power/
F: arch/x86/kernel/acpi/
@@ -6356,19 +6398,18 @@ F: net/ipv4/tcp_lp.c
TEGRA SUPPORT
M: Colin Cross <ccross@android.com>
-M: Erik Gilling <konkers@android.com>
M: Olof Johansson <olof@lixom.net>
+M: Stephen Warren <swarren@nvidia.com>
L: linux-tegra@vger.kernel.org
-T: git git://android.git.kernel.org/kernel/tegra.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/olof/tegra.git
S: Supported
F: arch/arm/mach-tegra
TEHUTI ETHERNET DRIVER
-M: Alexander Indenbaum <baum@tehutinetworks.net>
M: Andy Gospodarek <andy@greyhouse.net>
L: netdev@vger.kernel.org
S: Supported
-F: drivers/net/tehuti*
+F: drivers/net/ethernet/tehuti/*
Telecom Clock Driver for MCPL0010
M: Mark Gross <mark.gross@intel.com>
@@ -6419,7 +6460,7 @@ W: http://www.tilera.com/scm/
S: Supported
F: arch/tile/
F: drivers/tty/hvc/hvc_tile.c
-F: drivers/net/tile/
+F: drivers/net/ethernet/tile/
F: drivers/edac/tile_edac.c
TLAN NETWORK DRIVER
@@ -6428,7 +6469,7 @@ L: tlan-devel@lists.sourceforge.net (subscribers-only)
W: http://sourceforge.net/projects/tlan/
S: Maintained
F: Documentation/networking/tlan.txt
-F: drivers/net/tlan.*
+F: drivers/net/ethernet/ti/tlan.*
TOMOYO SECURITY MODULE
M: Kentaro Takeda <takedakn@nttdata.co.jp>
@@ -6438,7 +6479,7 @@ L: tomoyo-users-en@lists.sourceforge.jp (subscribers-only, for users in English)
L: tomoyo-dev@lists.sourceforge.jp (subscribers-only, for developers in Japanese)
L: tomoyo-users@lists.sourceforge.jp (subscribers-only, for users in Japanese)
W: http://tomoyo.sourceforge.jp/
-T: quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.4.x/tomoyo-lsm/patches/
+T: quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.5.x/tomoyo-lsm/patches/
S: Maintained
F: security/tomoyo/
@@ -6522,7 +6563,7 @@ TULIP NETWORK DRIVERS
M: Grant Grundler <grundler@parisc-linux.org>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/tulip/
+F: drivers/net/ethernet/tulip/
TUN/TAP driver
M: Maxim Krasnyansky <maxk@qualcomm.com>
@@ -6568,7 +6609,7 @@ W: http://uclinux-h8.sourceforge.jp/
S: Supported
F: arch/h8300/
F: drivers/ide/ide-h8300.c
-F: drivers/net/ne-h8300.c
+F: drivers/net/ethernet/8390/ne-h8300.c
UDF FILESYSTEM
M: Jan Kara <jack@suse.cz>
@@ -6996,7 +7037,7 @@ F: include/linux/vhost.h
VIA RHINE NETWORK DRIVER
M: Roger Luethi <rl@hellgate.ch>
S: Maintained
-F: drivers/net/via-rhine.c
+F: drivers/net/ethernet/via/via-rhine.c
VIAPRO SMBUS DRIVER
M: Jean Delvare <khali@linux-fr.org>
@@ -7024,7 +7065,7 @@ VIA VELOCITY NETWORK DRIVER
M: Francois Romieu <romieu@fr.zoreil.com>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/via-velocity.*
+F: drivers/net/ethernet/via/via-velocity.*
VLAN (802.1Q)
M: Patrick McHardy <kaber@trash.net>
@@ -7087,7 +7128,7 @@ S: Supported
F: drivers/mmc/host/vub300.c
W1 DALLAS'S 1-WIRE BUS
-M: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+M: Evgeniy Polyakov <zbr@ioremap.net>
S: Maintained
F: Documentation/w1/
F: drivers/w1/
@@ -7133,6 +7174,12 @@ L: linux-scsi@vger.kernel.org
S: Maintained
F: drivers/scsi/wd7000.c
+WIIMOTE HID DRIVER
+M: David Herrmann <dh.herrmann@googlemail.com>
+L: linux-input@vger.kernel.org
+S: Maintained
+F: drivers/hid/hid-wiimote*
+
WINBOND CIR DRIVER
M: David Härdeman <david@hardeman.nu>
S: Maintained
@@ -7199,6 +7246,9 @@ W: http://opensource.wolfsonmicro.com/content/linux-drivers-wolfson-devices
S: Supported
F: Documentation/hwmon/wm83??
F: drivers/leds/leds-wm83*.c
+F: drivers/input/misc/wm831x-on.c
+F: drivers/input/touchscreen/wm831x-ts.c
+F: drivers/input/touchscreen/wm97*.c
F: drivers/mfd/wm8*.c
F: drivers/power/wm83*.c
F: drivers/rtc/rtc-wm83*.c
@@ -7208,6 +7258,7 @@ F: drivers/watchdog/wm83*_wdt.c
F: include/linux/mfd/wm831x/
F: include/linux/mfd/wm8350/
F: include/linux/mfd/wm8400*
+F: include/linux/wm97xx.h
F: include/sound/wm????.h
F: sound/soc/codecs/wm*
diff --git a/Makefile b/Makefile
index 788511f86a62..07bc92544e9c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 3
PATCHLEVEL = 1
SUBLEVEL = 0
-EXTRAVERSION = -rc3
+EXTRAVERSION =
NAME = "Divemaster Edition"
# *DOCUMENTATION*
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 60cde53d266c..8bb936226dee 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -51,7 +51,7 @@ config GENERIC_CMOS_UPDATE
def_bool y
config GENERIC_GPIO
- def_bool y
+ bool
config ZONE_DMA
bool
diff --git a/arch/alpha/include/asm/fcntl.h b/arch/alpha/include/asm/fcntl.h
index 1b71ca70c9f6..6d9e805f18a7 100644
--- a/arch/alpha/include/asm/fcntl.h
+++ b/arch/alpha/include/asm/fcntl.h
@@ -51,8 +51,6 @@
#define F_EXLCK 16 /* or 3 */
#define F_SHLCK 32 /* or 4 */
-#define F_INPROGRESS 64
-
#include <asm-generic/fcntl.h>
#endif
diff --git a/arch/alpha/include/asm/sysinfo.h b/arch/alpha/include/asm/sysinfo.h
index 086aba284df2..e77d77cd07b8 100644
--- a/arch/alpha/include/asm/sysinfo.h
+++ b/arch/alpha/include/asm/sysinfo.h
@@ -27,13 +27,4 @@
#define UAC_NOFIX 2
#define UAC_SIGBUS 4
-
-#ifdef __KERNEL__
-
-/* This is the shift that is applied to the UAC bits as stored in the
- per-thread flags. See thread_info.h. */
-#define UAC_SHIFT 6
-
-#endif
-
#endif /* __ASM_ALPHA_SYSINFO_H */
diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h
index 6f32f9c84a2d..ff73db022342 100644
--- a/arch/alpha/include/asm/thread_info.h
+++ b/arch/alpha/include/asm/thread_info.h
@@ -74,9 +74,9 @@ register struct thread_info *__current_thread_info __asm__("$8");
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
#define TIF_POLLING_NRFLAG 8 /* poll_idle is polling NEED_RESCHED */
#define TIF_DIE_IF_KERNEL 9 /* dik recursion lock */
-#define TIF_UAC_NOPRINT 10 /* see sysinfo.h */
-#define TIF_UAC_NOFIX 11
-#define TIF_UAC_SIGBUS 12
+#define TIF_UAC_NOPRINT 10 /* ! Preserve sequence of following */
+#define TIF_UAC_NOFIX 11 /* ! flags as they match */
+#define TIF_UAC_SIGBUS 12 /* ! userspace part of 'osf_sysinfo' */
#define TIF_MEMDIE 13 /* is terminating due to OOM killer */
#define TIF_RESTORE_SIGMASK 14 /* restore signal mask in do_signal */
#define TIF_FREEZE 16 /* is freezing for suspend */
@@ -97,7 +97,7 @@ register struct thread_info *__current_thread_info __asm__("$8");
#define _TIF_ALLWORK_MASK (_TIF_WORK_MASK \
| _TIF_SYSCALL_TRACE)
-#define ALPHA_UAC_SHIFT 10
+#define ALPHA_UAC_SHIFT TIF_UAC_NOPRINT
#define ALPHA_UAC_MASK (1 << TIF_UAC_NOPRINT | 1 << TIF_UAC_NOFIX | \
1 << TIF_UAC_SIGBUS)
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 326f0a2d56e5..01e8715e26d9 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -42,6 +42,7 @@
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/sysinfo.h>
+#include <asm/thread_info.h>
#include <asm/hwrpb.h>
#include <asm/processor.h>
@@ -633,9 +634,10 @@ SYSCALL_DEFINE5(osf_getsysinfo, unsigned long, op, void __user *, buffer,
case GSI_UACPROC:
if (nbytes < sizeof(unsigned int))
return -EINVAL;
- w = (current_thread_info()->flags >> UAC_SHIFT) & UAC_BITMASK;
- if (put_user(w, (unsigned int __user *)buffer))
- return -EFAULT;
+ w = (current_thread_info()->flags >> ALPHA_UAC_SHIFT) &
+ UAC_BITMASK;
+ if (put_user(w, (unsigned int __user *)buffer))
+ return -EFAULT;
return 1;
case GSI_PROC_TYPE:
@@ -756,8 +758,8 @@ SYSCALL_DEFINE5(osf_setsysinfo, unsigned long, op, void __user *, buffer,
case SSIN_UACPROC:
again:
old = current_thread_info()->flags;
- new = old & ~(UAC_BITMASK << UAC_SHIFT);
- new = new | (w & UAC_BITMASK) << UAC_SHIFT;
+ new = old & ~(UAC_BITMASK << ALPHA_UAC_SHIFT);
+ new = new | (w & UAC_BITMASK) << ALPHA_UAC_SHIFT;
if (cmpxchg(&current_thread_info()->flags,
old, new) != old)
goto again;
diff --git a/arch/alpha/kernel/srm_env.c b/arch/alpha/kernel/srm_env.c
index f0df3fbd8402..b9fc6c309d2e 100644
--- a/arch/alpha/kernel/srm_env.c
+++ b/arch/alpha/kernel/srm_env.c
@@ -4,9 +4,8 @@
*
* (C) 2001,2002,2006 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
*
- * This driver is at all a modified version of Erik Mouw's
- * Documentation/DocBook/procfs_example.c, so: thank
- * you, Erik! He can be reached via email at
+ * This driver is a modified version of Erik Mouw's example proc
+ * interface, so: thank you, Erik! He can be reached via email at
* <J.A.K.Mouw@its.tudelft.nl>. It is based on an idea
* provided by DEC^WCompaq^WIntel's "Jumpstart" CD. They
* included a patch like this as well. Thanks for idea!
diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S
index b9c28f3f1956..6acea1f96de3 100644
--- a/arch/alpha/kernel/systbls.S
+++ b/arch/alpha/kernel/systbls.S
@@ -360,7 +360,7 @@ sys_call_table:
.quad sys_newuname
.quad sys_nanosleep /* 340 */
.quad sys_mremap
- .quad sys_nfsservctl
+ .quad sys_ni_syscall /* old nfsservctl */
.quad sys_setresuid
.quad sys_getresuid
.quad sys_pciconfig_read /* 345 */
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 325d2f55744d..795126ea4935 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -3,7 +3,7 @@ config ARM
default y
select HAVE_AOUT
select HAVE_DMA_API_DEBUG
- select HAVE_IDE
+ select HAVE_IDE if PCI || ISA || PCMCIA
select HAVE_MEMBLOCK
select RTC_LIB
select SYS_SUPPORTS_APM_EMULATION
@@ -195,7 +195,8 @@ config VECTORS_BASE
The base address of exception vectors.
config ARM_PATCH_PHYS_VIRT
- bool "Patch physical to virtual translations at runtime"
+ bool "Patch physical to virtual translations at runtime" if EMBEDDED
+ default y
depends on !XIP_KERNEL && MMU
depends on !ARCH_REALVIEW || !SPARSEMEM
help
@@ -204,16 +205,16 @@ config ARM_PATCH_PHYS_VIRT
kernel in system memory.
This can only be used with non-XIP MMU kernels where the base
- of physical memory is at a 16MB boundary, or theoretically 64K
- for the MSM machine class.
+ of physical memory is at a 16MB boundary.
+
+ Only disable this option if you know that you do not require
+ this feature (eg, building a kernel for a single machine) and
+ you need to shrink the kernel to the minimal size.
-config ARM_PATCH_PHYS_VIRT_16BIT
+
+config GENERIC_BUG
def_bool y
- depends on ARM_PATCH_PHYS_VIRT && ARCH_MSM
- help
- This option extends the physical to virtual translation patching
- to allow physical memory down to a theoretical minimum of 64K
- boundaries.
+ depends on BUG
source "init/Kconfig"
@@ -301,7 +302,6 @@ config ARCH_AT91
select ARCH_REQUIRE_GPIOLIB
select HAVE_CLK
select CLKDEV_LOOKUP
- select ARM_PATCH_PHYS_VIRT if MMU
help
This enables support for systems based on the Atmel AT91RM9200,
AT91SAM9 and AT91CAP9 processors.
@@ -385,6 +385,7 @@ config ARCH_FOOTBRIDGE
select CPU_SA110
select FOOTBRIDGE
select GENERIC_CLOCKEVENTS
+ select HAVE_IDE
help
Support for systems based on the DC21285 companion chip
("FootBridge"), such as the Simtec CATS and the Rebel NetWinder.
@@ -631,6 +632,8 @@ config ARCH_PXA
select SPARSE_IRQ
select AUTO_ZRELADDR
select MULTI_IRQ_HANDLER
+ select ARM_CPU_SUSPEND if PM
+ select HAVE_IDE
help
Support for Intel/Marvell's PXA2xx/PXA3xx processor line.
@@ -671,6 +674,7 @@ config ARCH_RPC
select NO_IOPORT
select ARCH_SPARSEMEM_ENABLE
select ARCH_USES_GETTIMEOFFSET
+ select HAVE_IDE
help
On the Acorn Risc-PC, Linux can support the internal IDE disk and
CD-ROM interface, serial and parallel port, and the floppy drive.
@@ -689,6 +693,7 @@ config ARCH_SA1100
select HAVE_SCHED_CLOCK
select TICK_ONESHOT
select ARCH_REQUIRE_GPIOLIB
+ select HAVE_IDE
help
Support for StrongARM 11x0 based boards.
@@ -1270,6 +1275,32 @@ config ARM_ERRATA_754327
This workaround defines cpu_relax() as smp_mb(), preventing correctly
written polling loops from denying visibility of updates to memory.
+config ARM_ERRATA_364296
+ bool "ARM errata: Possible cache data corruption with hit-under-miss enabled"
+ depends on CPU_V6 && !SMP
+ help
+ This options enables the workaround for the 364296 ARM1136
+ r0p2 erratum (possible cache data corruption with
+ hit-under-miss enabled). It sets the undocumented bit 31 in
+ the auxiliary control register and the FI bit in the control
+ register, thus disabling hit-under-miss without putting the
+ processor into full low interrupt latency mode. ARM11MPCore
+ is not affected.
+
+config ARM_ERRATA_764369
+ bool "ARM errata: Data cache line maintenance operation by MVA may not succeed"
+ depends on CPU_V7 && SMP
+ help
+ This option enables the workaround for erratum 764369
+ affecting Cortex-A9 MPCore with two or more processors (all
+ current revisions). Under certain timing circumstances, a data
+ cache line maintenance operation by MVA targeting an Inner
+ Shareable memory region may fail to proceed up to either the
+ Point of Coherency or to the Point of Unification of the
+ system. This workaround adds a DSB instruction before the
+ relevant cache maintenance functions and sets a specific bit
+ in the diagnostic control register of the SCU.
+
endmenu
source "arch/arm/common/Kconfig"
@@ -1348,6 +1379,7 @@ config SMP
MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4 || \
ARCH_EXYNOS4 || ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || \
ARCH_MSM_SCORPIONMP || ARCH_SHMOBILE
+ depends on MMU
select USE_GENERIC_SMP_HELPERS
select HAVE_ARM_SCU if !ARCH_MSM_SCORPIONMP
help
@@ -1361,7 +1393,7 @@ config SMP
processor machines. On a single processor machine, the kernel will
run faster if you say N here.
- See also <file:Documentation/i386/IO-APIC.txt>,
+ See also <file:Documentation/x86/i386/IO-APIC.txt>,
<file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
<http://tldp.org/HOWTO/SMP-HOWTO.html>.
@@ -1380,6 +1412,31 @@ config SMP_ON_UP
If you don't know what to do here, say Y.
+config ARM_CPU_TOPOLOGY
+ bool "Support cpu topology definition"
+ depends on SMP && CPU_V7
+ default y
+ help
+ Support ARM cpu topology definition. The MPIDR register defines
+ affinity between processors which is then used to describe the cpu
+ topology of an ARM System.
+
+config SCHED_MC
+ bool "Multi-core scheduler support"
+ depends on ARM_CPU_TOPOLOGY
+ help
+ Multi-core scheduler support improves the CPU scheduler's decision
+ making when dealing with multi-core CPU chips at a cost of slightly
+ increased overhead in some places. If unsure say N here.
+
+config SCHED_SMT
+ bool "SMT scheduler support"
+ depends on ARM_CPU_TOPOLOGY
+ help
+ Improves the CPU scheduler's decision making when dealing with
+ MultiThreading at a cost of slightly increased overhead in some
+ places. If unsure say N here.
+
config HAVE_ARM_SCU
bool
help
@@ -1455,6 +1512,7 @@ config THUMB2_KERNEL
depends on CPU_V7 && !CPU_V6 && !CPU_V6K && EXPERIMENTAL
select AEABI
select ARM_ASM_UNIFIED
+ select ARM_UNWIND
help
By enabling this option, the kernel will be compiled in
Thumb-2 mode. A compiler/assembler that understand the unified
@@ -2074,6 +2132,9 @@ config ARCH_SUSPEND_POSSIBLE
CPU_V6 || CPU_V6K || CPU_V7 || CPU_XSC3 || CPU_XSCALE
def_bool y
+config ARM_CPU_SUSPEND
+ def_bool PM_SLEEP
+
endmenu
source "net/Kconfig"
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 81cbe40c159c..df3eb3ccd769 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -65,13 +65,71 @@ config DEBUG_USER
# These options are only for real kernel hackers who want to get their hands dirty.
config DEBUG_LL
- bool "Kernel low-level debugging functions"
+ bool "Kernel low-level debugging functions (read help!)"
depends on DEBUG_KERNEL
help
Say Y here to include definitions of printascii, printch, printhex
in the kernel. This is helpful if you are debugging code that
executes before the console is initialized.
+ Note that selecting this option will limit the kernel to a single
+ UART definition, as specified below. Attempting to boot the kernel
+ image on a different platform *will not work*, so this option should
+ not be enabled for kernels that are intended to be portable.
+
+choice
+ prompt "Kernel low-level debugging port"
+ depends on DEBUG_LL
+
+ config DEBUG_LL_UART_NONE
+ bool "No low-level debugging UART"
+ help
+ Say Y here if your platform doesn't provide a UART option
+ below. This relies on your platform choosing the right UART
+ definition internally in order for low-level debugging to
+ work.
+
+ config DEBUG_ICEDCC
+ bool "Kernel low-level debugging via EmbeddedICE DCC channel"
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to the EmbeddedICE macrocell's DCC channel using
+ co-processor 14. This is known to work on the ARM9 style ICE
+ channel and on the XScale with the PEEDI.
+
+ Note that the system will appear to hang during boot if there
+ is nothing connected to read from the DCC.
+
+ config DEBUG_FOOTBRIDGE_COM1
+ bool "Kernel low-level debugging messages via footbridge 8250 at PCI COM1"
+ depends on FOOTBRIDGE
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to the 8250 at PCI COM1.
+
+ config DEBUG_DC21285_PORT
+ bool "Kernel low-level debugging messages via footbridge serial port"
+ depends on FOOTBRIDGE
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to the serial port in the DC21285 (Footbridge).
+
+ config DEBUG_CLPS711X_UART1
+ bool "Kernel low-level debugging messages via UART1"
+ depends on ARCH_CLPS711X
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to the first serial port on these devices.
+
+ config DEBUG_CLPS711X_UART2
+ bool "Kernel low-level debugging messages via UART2"
+ depends on ARCH_CLPS711X
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to the second serial port on these devices.
+
+endchoice
+
config EARLY_PRINTK
bool "Early printk"
depends on DEBUG_LL
@@ -80,43 +138,14 @@ config EARLY_PRINTK
kernel low-level debugging functions. Add earlyprintk to your
kernel parameters to enable this console.
-config DEBUG_ICEDCC
- bool "Kernel low-level debugging via EmbeddedICE DCC channel"
- depends on DEBUG_LL
- help
- Say Y here if you want the debug print routines to direct their
- output to the EmbeddedICE macrocell's DCC channel using
- co-processor 14. This is known to work on the ARM9 style ICE
- channel and on the XScale with the PEEDI.
-
- It does include a timeout to ensure that the system does not
- totally freeze when there is nothing connected to read.
-
config OC_ETM
bool "On-chip ETM and ETB"
- select ARM_AMBA
+ depends on ARM_AMBA
help
Enables the on-chip embedded trace macrocell and embedded trace
buffer driver that will allow you to collect traces of the
kernel code.
-config DEBUG_DC21285_PORT
- bool "Kernel low-level debugging messages via footbridge serial port"
- depends on DEBUG_LL && FOOTBRIDGE
- help
- Say Y here if you want the debug print routines to direct their
- output to the serial port in the DC21285 (Footbridge). Saying N
- will cause the debug messages to appear on the first 16550
- serial port.
-
-config DEBUG_CLPS711X_UART2
- bool "Kernel low-level debugging messages via UART2"
- depends on DEBUG_LL && ARCH_CLPS711X
- help
- Say Y here if you want the debug print routines to direct their
- output to the second serial port on these devices. Saying N will
- cause the debug messages to appear on the first serial port.
-
config DEBUG_S3C_UART
depends on PLAT_SAMSUNG
int "S3C UART to use for low-level debug"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 70c424eaf7b0..5665c2a3b652 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -128,6 +128,9 @@ textofs-$(CONFIG_PM_H1940) := 0x00108000
ifeq ($(CONFIG_ARCH_SA1100),y)
textofs-$(CONFIG_SA1111) := 0x00208000
endif
+textofs-$(CONFIG_ARCH_MSM7X30) := 0x00208000
+textofs-$(CONFIG_ARCH_MSM8X60) := 0x00208000
+textofs-$(CONFIG_ARCH_MSM8960) := 0x00208000
# Machine directory name. This list is sorted alphanumerically
# by CONFIG_* macro name.
diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
index a1edfd5a129a..176062ac7f07 100644
--- a/arch/arm/boot/Makefile
+++ b/arch/arm/boot/Makefile
@@ -78,7 +78,16 @@ endif
$(obj)/uImage: STARTADDR=$(LOADADDR)
+check_for_multiple_loadaddr = \
+if [ $(words $(LOADADDR)) -gt 1 ]; then \
+ echo 'multiple load addresses: $(LOADADDR)'; \
+ echo 'This is incompatible with uImages'; \
+ echo 'Specify LOADADDR on the commandline to build an uImage'; \
+ false; \
+fi
+
$(obj)/uImage: $(obj)/zImage FORCE
+ @$(check_for_multiple_loadaddr)
$(call if_changed,uimage)
@echo ' Image $@ is ready'
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 0c74a6fab952..a6b30b35ca65 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -139,8 +139,16 @@ bad_syms=$$($(CROSS_COMPILE)nm $@ | sed -n 's/^.\{8\} [bc] \(.*\)/\1/p') && \
( echo "following symbols must have non local/private scope:" >&2; \
echo "$$bad_syms" >&2; rm -f $@; false )
+check_for_multiple_zreladdr = \
+if [ $(words $(ZRELADDR)) -gt 1 -a "$(CONFIG_AUTO_ZRELADDR)" = "" ]; then \
+ echo 'multiple zreladdrs: $(ZRELADDR)'; \
+ echo 'This needs CONFIG_AUTO_ZRELADDR to be set'; \
+ false; \
+fi
+
$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
$(addprefix $(obj)/, $(OBJS)) $(lib1funcs) FORCE
+ @$(check_for_multiple_zreladdr)
$(call if_changed,ld)
@$(check_for_bad_syms)
diff --git a/arch/arm/boot/compressed/mmcif-sh7372.c b/arch/arm/boot/compressed/mmcif-sh7372.c
index b6f61d9a5a1b..672ae95db5c3 100644
--- a/arch/arm/boot/compressed/mmcif-sh7372.c
+++ b/arch/arm/boot/compressed/mmcif-sh7372.c
@@ -82,7 +82,7 @@ asmlinkage void mmc_loader(unsigned char *buf, unsigned long len)
/* Disable clock to MMC hardware block */
- __raw_writel(__raw_readl(SMSTPCR3) & (1 << 12), SMSTPCR3);
+ __raw_writel(__raw_readl(SMSTPCR3) | (1 << 12), SMSTPCR3);
mmc_update_progress(MMC_PROGRESS_DONE);
}
diff --git a/arch/arm/boot/compressed/sdhi-sh7372.c b/arch/arm/boot/compressed/sdhi-sh7372.c
index d403a8b24d7f..d279294f2381 100644
--- a/arch/arm/boot/compressed/sdhi-sh7372.c
+++ b/arch/arm/boot/compressed/sdhi-sh7372.c
@@ -85,7 +85,7 @@ asmlinkage void mmc_loader(unsigned short *buf, unsigned long len)
goto err;
/* Disable clock to SDHI1 hardware block */
- __raw_writel(__raw_readl(SMSTPCR3) & (1 << 13), SMSTPCR3);
+ __raw_writel(__raw_readl(SMSTPCR3) | (1 << 13), SMSTPCR3);
mmc_update_progress(MMC_PROGRESS_DONE);
diff --git a/arch/arm/boot/dts/tegra-harmony.dts b/arch/arm/boot/dts/tegra-harmony.dts
index 4c053340ce33..e5818668d091 100644
--- a/arch/arm/boot/dts/tegra-harmony.dts
+++ b/arch/arm/boot/dts/tegra-harmony.dts
@@ -57,14 +57,14 @@
};
sdhci@c8000200 {
- gpios = <&gpio 69 0>, /* cd, gpio PI5 */
- <&gpio 57 0>, /* wp, gpio PH1 */
- <&gpio 155 0>; /* power, gpio PT3 */
+ cd-gpios = <&gpio 69 0>; /* gpio PI5 */
+ wp-gpios = <&gpio 57 0>; /* gpio PH1 */
+ power-gpios = <&gpio 155 0>; /* gpio PT3 */
};
sdhci@c8000600 {
- gpios = <&gpio 58 0>, /* cd, gpio PH2 */
- <&gpio 59 0>, /* wp, gpio PH3 */
- <&gpio 70 0>; /* power, gpio PI6 */
+ cd-gpios = <&gpio 58 0>; /* gpio PH2 */
+ wp-gpios = <&gpio 59 0>; /* gpio PH3 */
+ power-gpios = <&gpio 70 0>; /* gpio PI6 */
};
};
diff --git a/arch/arm/boot/dts/tegra-seaboard.dts b/arch/arm/boot/dts/tegra-seaboard.dts
index 1940cae00748..64cedca6fc79 100644
--- a/arch/arm/boot/dts/tegra-seaboard.dts
+++ b/arch/arm/boot/dts/tegra-seaboard.dts
@@ -21,8 +21,8 @@
};
sdhci@c8000400 {
- gpios = <&gpio 69 0>, /* cd, gpio PI5 */
- <&gpio 57 0>, /* wp, gpio PH1 */
- <&gpio 70 0>; /* power, gpio PI6 */
+ cd-gpios = <&gpio 69 0>; /* gpio PI5 */
+ wp-gpios = <&gpio 57 0>; /* gpio PH1 */
+ power-gpios = <&gpio 70 0>; /* gpio PI6 */
};
};
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 3227ca952a12..666b278e56d7 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -180,7 +180,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
return -EINVAL;
mask = 0xff << shift;
- bit = 1 << (cpu + shift);
+ bit = 1 << (cpu_logical_map(cpu) + shift);
spin_lock(&irq_controller_lock);
val = readl_relaxed(reg) & ~mask;
@@ -259,9 +259,15 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
unsigned int irq_start)
{
unsigned int gic_irqs, irq_limit, i;
+ u32 cpumask;
void __iomem *base = gic->dist_base;
- u32 cpumask = 1 << smp_processor_id();
+ u32 cpu = 0;
+#ifdef CONFIG_SMP
+ cpu = cpu_logical_map(smp_processor_id());
+#endif
+
+ cpumask = 1 << cpu;
cpumask |= cpumask << 8;
cpumask |= cpumask << 16;
@@ -382,7 +388,12 @@ void __cpuinit gic_enable_ppi(unsigned int irq)
#ifdef CONFIG_SMP
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
{
- unsigned long map = *cpus_addr(*mask);
+ int cpu;
+ unsigned long map = 0;
+
+ /* Convert our logical CPU mask into a physical one. */
+ for_each_cpu(cpu, mask)
+ map |= 1 << cpu_logical_map(cpu);
/*
* Ensure that stores to Normal memory are visible to the
diff --git a/arch/arm/common/pl330.c b/arch/arm/common/pl330.c
index 97912fa48782..7129cfbdacd6 100644
--- a/arch/arm/common/pl330.c
+++ b/arch/arm/common/pl330.c
@@ -1546,7 +1546,7 @@ int pl330_chan_ctrl(void *ch_id, enum pl330_chan_op op)
/* Start the next */
case PL330_OP_START:
- if (!_start(thrd))
+ if (!_thrd_active(thrd) && !_start(thrd))
ret = -EIO;
break;
diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
index 7aa4262ada7a..01f18a421b17 100644
--- a/arch/arm/common/vic.c
+++ b/arch/arm/common/vic.c
@@ -259,7 +259,6 @@ static void __init vic_disable(void __iomem *base)
writel(0, base + VIC_INT_SELECT);
writel(0, base + VIC_INT_ENABLE);
writel(~0, base + VIC_INT_ENABLE_CLEAR);
- writel(0, base + VIC_IRQ_STATUS);
writel(0, base + VIC_ITCR);
writel(~0, base + VIC_INT_SOFT_CLEAR);
}
@@ -347,7 +346,8 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
/* Identify which VIC cell this one is, by reading the ID */
for (i = 0; i < 4; i++) {
- u32 addr = ((u32)base & PAGE_MASK) + 0xfe0 + (i * 4);
+ void __iomem *addr;
+ addr = (void __iomem *)((u32)base & PAGE_MASK) + 0xfe0 + (i * 4);
cellid |= (readl(addr) & 0xff) << (8 * i);
}
vendor = (cellid >> 12) & 0xff;
diff --git a/arch/arm/configs/integrator_defconfig b/arch/arm/configs/integrator_defconfig
index 7196ade07e27..1103f62a1964 100644
--- a/arch/arm/configs/integrator_defconfig
+++ b/arch/arm/configs/integrator_defconfig
@@ -1,5 +1,6 @@
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
+CONFIG_TINY_RCU=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
@@ -8,20 +9,29 @@ CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_ARCH_INTEGRATOR=y
CONFIG_ARCH_INTEGRATOR_AP=y
+CONFIG_ARCH_INTEGRATOR_CP=y
CONFIG_CPU_ARM720T=y
CONFIG_CPU_ARM920T=y
+CONFIG_CPU_ARM922T=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_ARM1020=y
+CONFIG_CPU_ARM1022=y
+CONFIG_CPU_ARM1026=y
CONFIG_PCI=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
CONFIG_LEDS=y
CONFIG_LEDS_CPU=y
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=ttyAM0,38400n8 root=/dev/nfs ip=bootp mem=32M"
+CONFIG_CMDLINE="console=ttyAM0,38400n8 root=/dev/nfs ip=bootp"
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_FPE_NWFPE=y
-CONFIG_PM=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -32,7 +42,6 @@ CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
# CONFIG_IPV6 is not set
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_AFS_PARTS=y
CONFIG_MTD_CHAR=y
@@ -40,6 +49,7 @@ CONFIG_MTD_BLOCK=y
CONFIG_MTD_CFI=y
CONFIG_MTD_CFI_ADV_OPTIONS=y
CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_PHYSMAP=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=8192
@@ -56,6 +66,8 @@ CONFIG_FB_MODE_HELPERS=y
CONFIG_FB_MATROX=y
CONFIG_FB_MATROX_MILLENIUM=y
CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_PL030=y
CONFIG_EXT2_FS=y
CONFIG_TMPFS=y
CONFIG_JFFS2_FS=y
@@ -68,4 +80,3 @@ CONFIG_NFSD_V3=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_ERRORS=y
diff --git a/arch/arm/include/asm/Kbuild b/arch/arm/include/asm/Kbuild
index 6550db3aa5c7..960abceb8e14 100644
--- a/arch/arm/include/asm/Kbuild
+++ b/arch/arm/include/asm/Kbuild
@@ -1,3 +1,20 @@
include include/asm-generic/Kbuild.asm
header-y += hwcap.h
+
+generic-y += auxvec.h
+generic-y += bitsperlong.h
+generic-y += cputime.h
+generic-y += emergency-restart.h
+generic-y += errno.h
+generic-y += ioctl.h
+generic-y += irq_regs.h
+generic-y += kdebug.h
+generic-y += local.h
+generic-y += local64.h
+generic-y += percpu.h
+generic-y += poll.h
+generic-y += resource.h
+generic-y += sections.h
+generic-y += siginfo.h
+generic-y += sizes.h
diff --git a/arch/arm/include/asm/auxvec.h b/arch/arm/include/asm/auxvec.h
deleted file mode 100644
index c0536f6b29a7..000000000000
--- a/arch/arm/include/asm/auxvec.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef __ASMARM_AUXVEC_H
-#define __ASMARM_AUXVEC_H
-
-#endif
diff --git a/arch/arm/include/asm/bitsperlong.h b/arch/arm/include/asm/bitsperlong.h
deleted file mode 100644
index 6dc0bb0c13b2..000000000000
--- a/arch/arm/include/asm/bitsperlong.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/bitsperlong.h>
diff --git a/arch/arm/include/asm/bug.h b/arch/arm/include/asm/bug.h
index 4d88425a4169..9abe7a07d5ac 100644
--- a/arch/arm/include/asm/bug.h
+++ b/arch/arm/include/asm/bug.h
@@ -3,21 +3,58 @@
#ifdef CONFIG_BUG
-#ifdef CONFIG_DEBUG_BUGVERBOSE
-extern void __bug(const char *file, int line) __attribute__((noreturn));
-
-/* give file/line information */
-#define BUG() __bug(__FILE__, __LINE__)
+/*
+ * Use a suitable undefined instruction to use for ARM/Thumb2 bug handling.
+ * We need to be careful not to conflict with those used by other modules and
+ * the register_undef_hook() system.
+ */
+#ifdef CONFIG_THUMB2_KERNEL
+#define BUG_INSTR_VALUE 0xde02
+#define BUG_INSTR_TYPE ".hword "
#else
+#define BUG_INSTR_VALUE 0xe7f001f2
+#define BUG_INSTR_TYPE ".word "
+#endif
-/* this just causes an oops */
-#define BUG() do { *(int *)0 = 0; } while (1)
-#endif
+#define BUG() _BUG(__FILE__, __LINE__, BUG_INSTR_VALUE)
+#define _BUG(file, line, value) __BUG(file, line, value)
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+
+/*
+ * The extra indirection is to ensure that the __FILE__ string comes through
+ * OK. Many version of gcc do not support the asm %c parameter which would be
+ * preferable to this unpleasantness. We use mergeable string sections to
+ * avoid multiple copies of the string appearing in the kernel image.
+ */
+
+#define __BUG(__file, __line, __value) \
+do { \
+ BUILD_BUG_ON(sizeof(struct bug_entry) != 12); \
+ asm volatile("1:\t" BUG_INSTR_TYPE #__value "\n" \
+ ".pushsection .rodata.str, \"aMS\", %progbits, 1\n" \
+ "2:\t.asciz " #__file "\n" \
+ ".popsection\n" \
+ ".pushsection __bug_table,\"a\"\n" \
+ "3:\t.word 1b, 2b\n" \
+ "\t.hword " #__line ", 0\n" \
+ ".popsection"); \
+ unreachable(); \
+} while (0)
+
+#else /* not CONFIG_DEBUG_BUGVERBOSE */
+
+#define __BUG(__file, __line, __value) \
+do { \
+ asm volatile(BUG_INSTR_TYPE #__value); \
+ unreachable(); \
+} while (0)
+#endif /* CONFIG_DEBUG_BUGVERBOSE */
#define HAVE_ARCH_BUG
-#endif
+#endif /* CONFIG_BUG */
#include <asm-generic/bug.h>
diff --git a/arch/arm/include/asm/cachetype.h b/arch/arm/include/asm/cachetype.h
index c023db09fcc1..7ea78144ae22 100644
--- a/arch/arm/include/asm/cachetype.h
+++ b/arch/arm/include/asm/cachetype.h
@@ -7,6 +7,7 @@
#define CACHEID_VIPT (CACHEID_VIPT_ALIASING|CACHEID_VIPT_NONALIASING)
#define CACHEID_ASID_TAGGED (1 << 3)
#define CACHEID_VIPT_I_ALIASING (1 << 4)
+#define CACHEID_PIPT (1 << 5)
extern unsigned int cacheid;
@@ -16,6 +17,7 @@ extern unsigned int cacheid;
#define cache_is_vipt_aliasing() cacheid_is(CACHEID_VIPT_ALIASING)
#define icache_is_vivt_asid_tagged() cacheid_is(CACHEID_ASID_TAGGED)
#define icache_is_vipt_aliasing() cacheid_is(CACHEID_VIPT_I_ALIASING)
+#define icache_is_pipt() cacheid_is(CACHEID_PIPT)
/*
* __LINUX_ARM_ARCH__ is the minimum supported CPU architecture
@@ -26,7 +28,8 @@ extern unsigned int cacheid;
#if __LINUX_ARM_ARCH__ >= 7
#define __CACHEID_ARCH_MIN (CACHEID_VIPT_NONALIASING |\
CACHEID_ASID_TAGGED |\
- CACHEID_VIPT_I_ALIASING)
+ CACHEID_VIPT_I_ALIASING |\
+ CACHEID_PIPT)
#elif __LINUX_ARM_ARCH__ >= 6
#define __CACHEID_ARCH_MIN (~CACHEID_VIVT)
#else
diff --git a/arch/arm/include/asm/cputime.h b/arch/arm/include/asm/cputime.h
deleted file mode 100644
index 3a8002a5fec7..000000000000
--- a/arch/arm/include/asm/cputime.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ARM_CPUTIME_H
-#define __ARM_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* __ARM_CPUTIME_H */
diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h
index cd4458f64171..cb47d28cbe1f 100644
--- a/arch/arm/include/asm/cputype.h
+++ b/arch/arm/include/asm/cputype.h
@@ -8,6 +8,7 @@
#define CPUID_CACHETYPE 1
#define CPUID_TCM 2
#define CPUID_TLBTYPE 3
+#define CPUID_MPIDR 5
#define CPUID_EXT_PFR0 "c1, 0"
#define CPUID_EXT_PFR1 "c1, 1"
@@ -70,6 +71,11 @@ static inline unsigned int __attribute_const__ read_cpuid_tcmstatus(void)
return read_cpuid(CPUID_TCM);
}
+static inline unsigned int __attribute_const__ read_cpuid_mpidr(void)
+{
+ return read_cpuid(CPUID_MPIDR);
+}
+
/*
* Intel's XScale3 core supports some v6 features (supersections, L2)
* but advertises itself as v5 as it does not support the v6 ISA. For
diff --git a/arch/arm/include/asm/device.h b/arch/arm/include/asm/device.h
index 9f390ce335cb..6615f03f56a5 100644
--- a/arch/arm/include/asm/device.h
+++ b/arch/arm/include/asm/device.h
@@ -10,6 +10,9 @@ struct dev_archdata {
#ifdef CONFIG_DMABOUNCE
struct dmabounce_device_info *dmabounce;
#endif
+#ifdef CONFIG_IOMMU_API
+ void *iommu; /* private IOMMU data */
+#endif
};
struct pdev_archdata {
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index 7a21d0bf7134..28b7ee8d7398 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -32,7 +32,7 @@ static inline unsigned long dma_to_pfn(struct device *dev, dma_addr_t addr)
static inline void *dma_to_virt(struct device *dev, dma_addr_t addr)
{
- return (void *)__bus_to_virt(addr);
+ return (void *)__bus_to_virt((unsigned long)addr);
}
static inline dma_addr_t virt_to_dma(struct device *dev, void *addr)
diff --git a/arch/arm/include/asm/ecard.h b/arch/arm/include/asm/ecard.h
index 29f2610efc70..eaea14676d57 100644
--- a/arch/arm/include/asm/ecard.h
+++ b/arch/arm/include/asm/ecard.h
@@ -161,7 +161,6 @@ struct expansion_card {
/* Private internal data */
const char *card_desc; /* Card description */
- CONST unsigned int podaddr; /* Base Linux address for card */
CONST loader_t loader; /* loader program */
u64 dma_mask;
};
diff --git a/arch/arm/include/asm/emergency-restart.h b/arch/arm/include/asm/emergency-restart.h
deleted file mode 100644
index 108d8c48e42e..000000000000
--- a/arch/arm/include/asm/emergency-restart.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_EMERGENCY_RESTART_H
-#define _ASM_EMERGENCY_RESTART_H
-
-#include <asm-generic/emergency-restart.h>
-
-#endif /* _ASM_EMERGENCY_RESTART_H */
diff --git a/arch/arm/include/asm/errno.h b/arch/arm/include/asm/errno.h
deleted file mode 100644
index 6e60f0612bb6..000000000000
--- a/arch/arm/include/asm/errno.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ARM_ERRNO_H
-#define _ARM_ERRNO_H
-
-#include <asm-generic/errno.h>
-
-#endif
diff --git a/arch/arm/include/asm/exception.h b/arch/arm/include/asm/exception.h
new file mode 100644
index 000000000000..5abaf5bbd985
--- /dev/null
+++ b/arch/arm/include/asm/exception.h
@@ -0,0 +1,19 @@
+/*
+ * Annotations for marking C functions as exception handlers.
+ *
+ * These should only be used for C functions that are called from the low
+ * level exception entry code and not any intervening C code.
+ */
+#ifndef __ASM_ARM_EXCEPTION_H
+#define __ASM_ARM_EXCEPTION_H
+
+#include <linux/ftrace.h>
+
+#define __exception __attribute__((section(".exception.text")))
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+#define __exception_irq_entry __irq_entry
+#else
+#define __exception_irq_entry __exception
+#endif
+
+#endif /* __ASM_ARM_EXCEPTION_H */
diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
index 8c73900da9ed..253cc86318bf 100644
--- a/arch/arm/include/asm/futex.h
+++ b/arch/arm/include/asm/futex.h
@@ -25,17 +25,17 @@
#ifdef CONFIG_SMP
-#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
+#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \
smp_mb(); \
__asm__ __volatile__( \
- "1: ldrex %1, [%2]\n" \
+ "1: ldrex %1, [%3]\n" \
" " insn "\n" \
- "2: strex %1, %0, [%2]\n" \
- " teq %1, #0\n" \
+ "2: strex %2, %0, [%3]\n" \
+ " teq %2, #0\n" \
" bne 1b\n" \
" mov %0, #0\n" \
- __futex_atomic_ex_table("%4") \
- : "=&r" (ret), "=&r" (oldval) \
+ __futex_atomic_ex_table("%5") \
+ : "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \
: "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \
: "cc", "memory")
@@ -73,14 +73,14 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
#include <linux/preempt.h>
#include <asm/domain.h>
-#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
+#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \
__asm__ __volatile__( \
- "1: " T(ldr) " %1, [%2]\n" \
+ "1: " T(ldr) " %1, [%3]\n" \
" " insn "\n" \
- "2: " T(str) " %0, [%2]\n" \
+ "2: " T(str) " %0, [%3]\n" \
" mov %0, #0\n" \
- __futex_atomic_ex_table("%4") \
- : "=&r" (ret), "=&r" (oldval) \
+ __futex_atomic_ex_table("%5") \
+ : "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \
: "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \
: "cc", "memory")
@@ -117,7 +117,7 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
int cmp = (encoded_op >> 24) & 15;
int oparg = (encoded_op << 8) >> 20;
int cmparg = (encoded_op << 20) >> 20;
- int oldval = 0, ret;
+ int oldval = 0, ret, tmp;
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;
@@ -129,19 +129,19 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
switch (op) {
case FUTEX_OP_SET:
- __futex_atomic_op("mov %0, %3", ret, oldval, uaddr, oparg);
+ __futex_atomic_op("mov %0, %4", ret, oldval, tmp, uaddr, oparg);
break;
case FUTEX_OP_ADD:
- __futex_atomic_op("add %0, %1, %3", ret, oldval, uaddr, oparg);
+ __futex_atomic_op("add %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
break;
case FUTEX_OP_OR:
- __futex_atomic_op("orr %0, %1, %3", ret, oldval, uaddr, oparg);
+ __futex_atomic_op("orr %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
break;
case FUTEX_OP_ANDN:
- __futex_atomic_op("and %0, %1, %3", ret, oldval, uaddr, ~oparg);
+ __futex_atomic_op("and %0, %1, %4", ret, oldval, tmp, uaddr, ~oparg);
break;
case FUTEX_OP_XOR:
- __futex_atomic_op("eor %0, %1, %3", ret, oldval, uaddr, oparg);
+ __futex_atomic_op("eor %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
break;
default:
ret = -ENOSYS;
diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h
index 16bd48031583..434edccdf7f3 100644
--- a/arch/arm/include/asm/hardware/cache-l2x0.h
+++ b/arch/arm/include/asm/hardware/cache-l2x0.h
@@ -45,8 +45,15 @@
#define L2X0_CLEAN_INV_LINE_PA 0x7F0
#define L2X0_CLEAN_INV_LINE_IDX 0x7F8
#define L2X0_CLEAN_INV_WAY 0x7FC
-#define L2X0_LOCKDOWN_WAY_D 0x900
-#define L2X0_LOCKDOWN_WAY_I 0x904
+/*
+ * The lockdown registers repeat 8 times for L310, the L210 has only one
+ * D and one I lockdown register at 0x0900 and 0x0904.
+ */
+#define L2X0_LOCKDOWN_WAY_D_BASE 0x900
+#define L2X0_LOCKDOWN_WAY_I_BASE 0x904
+#define L2X0_LOCKDOWN_STRIDE 0x08
+#define L2X0_ADDR_FILTER_START 0xC00
+#define L2X0_ADDR_FILTER_END 0xC04
#define L2X0_TEST_OPERATION 0xF00
#define L2X0_LINE_DATA 0xF10
#define L2X0_LINE_TAG 0xF30
@@ -60,11 +67,26 @@
#define L2X0_CACHE_ID_PART_MASK (0xf << 6)
#define L2X0_CACHE_ID_PART_L210 (1 << 6)
#define L2X0_CACHE_ID_PART_L310 (3 << 6)
+#define L2X0_CACHE_ID_RTL_MASK 0x3f
+#define L2X0_CACHE_ID_RTL_R0P0 0x0
+#define L2X0_CACHE_ID_RTL_R1P0 0x2
+#define L2X0_CACHE_ID_RTL_R2P0 0x4
+#define L2X0_CACHE_ID_RTL_R3P0 0x5
+#define L2X0_CACHE_ID_RTL_R3P1 0x6
+#define L2X0_CACHE_ID_RTL_R3P2 0x8
#define L2X0_AUX_CTRL_MASK 0xc0000fff
+#define L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT 0
+#define L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK 0x7
+#define L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT 3
+#define L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK (0x7 << 3)
+#define L2X0_AUX_CTRL_TAG_LATENCY_SHIFT 6
+#define L2X0_AUX_CTRL_TAG_LATENCY_MASK (0x7 << 6)
+#define L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT 9
+#define L2X0_AUX_CTRL_DIRTY_LATENCY_MASK (0x7 << 9)
#define L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT 16
#define L2X0_AUX_CTRL_WAY_SIZE_SHIFT 17
-#define L2X0_AUX_CTRL_WAY_SIZE_MASK (0x3 << 17)
+#define L2X0_AUX_CTRL_WAY_SIZE_MASK (0x7 << 17)
#define L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT 22
#define L2X0_AUX_CTRL_NS_LOCKDOWN_SHIFT 26
#define L2X0_AUX_CTRL_NS_INT_CTRL_SHIFT 27
@@ -72,8 +94,33 @@
#define L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT 29
#define L2X0_AUX_CTRL_EARLY_BRESP_SHIFT 30
+#define L2X0_LATENCY_CTRL_SETUP_SHIFT 0
+#define L2X0_LATENCY_CTRL_RD_SHIFT 4
+#define L2X0_LATENCY_CTRL_WR_SHIFT 8
+
+#define L2X0_ADDR_FILTER_EN 1
+
#ifndef __ASSEMBLY__
extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask);
+extern int l2x0_of_init(__u32 aux_val, __u32 aux_mask);
+
+struct l2x0_regs {
+ unsigned long phy_base;
+ unsigned long aux_ctrl;
+ /*
+ * Whether the following registers need to be saved/restored
+ * depends on platform
+ */
+ unsigned long tag_latency;
+ unsigned long data_latency;
+ unsigned long filter_start;
+ unsigned long filter_end;
+ unsigned long prefetch_ctrl;
+ unsigned long pwr_ctrl;
+};
+
+extern struct l2x0_regs l2x0_saved_regs;
+
#endif
#endif
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index d66605dea55a..065d100fa63e 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -80,6 +80,7 @@ extern void __iomem *__arm_ioremap_caller(unsigned long, size_t, unsigned int,
extern void __iomem *__arm_ioremap_pfn(unsigned long, unsigned long, size_t, unsigned int);
extern void __iomem *__arm_ioremap(unsigned long, size_t, unsigned int);
+extern void __iomem *__arm_ioremap_exec(unsigned long, size_t, bool cached);
extern void __iounmap(volatile void __iomem *addr);
/*
@@ -110,6 +111,27 @@ static inline void __iomem *__typesafe_io(unsigned long addr)
#include <mach/io.h>
/*
+ * This is the limit of PC card/PCI/ISA IO space, which is by default
+ * 64K if we have PC card, PCI or ISA support. Otherwise, default to
+ * zero to prevent ISA/PCI drivers claiming IO space (and potentially
+ * oopsing.)
+ *
+ * Only set this larger if you really need inb() et.al. to operate over
+ * a larger address space. Note that SOC_COMMON ioremaps each sockets
+ * IO space area, and so inb() et.al. must be defined to operate as per
+ * readb() et.al. on such platforms.
+ */
+#ifndef IO_SPACE_LIMIT
+#if defined(CONFIG_PCMCIA_SOC_COMMON) || defined(CONFIG_PCMCIA_SOC_COMMON_MODULE)
+#define IO_SPACE_LIMIT ((resource_size_t)0xffffffff)
+#elif defined(CONFIG_PCI) || defined(CONFIG_ISA) || defined(CONFIG_PCCARD)
+#define IO_SPACE_LIMIT ((resource_size_t)0xffff)
+#else
+#define IO_SPACE_LIMIT ((resource_size_t)0)
+#endif
+#endif
+
+/*
* IO port access primitives
* -------------------------
*
@@ -189,11 +211,11 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
* IO port primitives for more information.
*/
#ifdef __mem_pci
-#define readb_relaxed(c) ({ u8 __v = __raw_readb(__mem_pci(c)); __v; })
-#define readw_relaxed(c) ({ u16 __v = le16_to_cpu((__force __le16) \
- __raw_readw(__mem_pci(c))); __v; })
-#define readl_relaxed(c) ({ u32 __v = le32_to_cpu((__force __le32) \
- __raw_readl(__mem_pci(c))); __v; })
+#define readb_relaxed(c) ({ u8 __r = __raw_readb(__mem_pci(c)); __r; })
+#define readw_relaxed(c) ({ u16 __r = le16_to_cpu((__force __le16) \
+ __raw_readw(__mem_pci(c))); __r; })
+#define readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32) \
+ __raw_readl(__mem_pci(c))); __r; })
#define writeb_relaxed(v,c) ((void)__raw_writeb(v,__mem_pci(c)))
#define writew_relaxed(v,c) ((void)__raw_writew((__force u16) \
@@ -238,7 +260,7 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
* ioremap and friends.
*
* ioremap takes a PCI memory address, as specified in
- * Documentation/IO-mapping.txt.
+ * Documentation/io-mapping.txt.
*
*/
#ifndef __arch_ioremap
@@ -260,10 +282,16 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
#define ioread16(p) ({ unsigned int __v = le16_to_cpu((__force __le16)__raw_readw(p)); __iormb(); __v; })
#define ioread32(p) ({ unsigned int __v = le32_to_cpu((__force __le32)__raw_readl(p)); __iormb(); __v; })
+#define ioread16be(p) ({ unsigned int __v = be16_to_cpu((__force __be16)__raw_readw(p)); __iormb(); __v; })
+#define ioread32be(p) ({ unsigned int __v = be32_to_cpu((__force __be32)__raw_readl(p)); __iormb(); __v; })
+
#define iowrite8(v,p) ({ __iowmb(); (void)__raw_writeb(v, p); })
#define iowrite16(v,p) ({ __iowmb(); (void)__raw_writew((__force __u16)cpu_to_le16(v), p); })
#define iowrite32(v,p) ({ __iowmb(); (void)__raw_writel((__force __u32)cpu_to_le32(v), p); })
+#define iowrite16be(v,p) ({ __iowmb(); (void)__raw_writew((__force __u16)cpu_to_be16(v), p); })
+#define iowrite32be(v,p) ({ __iowmb(); (void)__raw_writel((__force __u32)cpu_to_be32(v), p); })
+
#define ioread8_rep(p,d,c) __raw_readsb(p,d,c)
#define ioread16_rep(p,d,c) __raw_readsw(p,d,c)
#define ioread32_rep(p,d,c) __raw_readsl(p,d,c)
diff --git a/arch/arm/include/asm/ioctl.h b/arch/arm/include/asm/ioctl.h
deleted file mode 100644
index b279fe06dfe5..000000000000
--- a/arch/arm/include/asm/ioctl.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/ioctl.h>
diff --git a/arch/arm/include/asm/irq_regs.h b/arch/arm/include/asm/irq_regs.h
deleted file mode 100644
index 3dd9c0b70270..000000000000
--- a/arch/arm/include/asm/irq_regs.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/irq_regs.h>
diff --git a/arch/arm/include/asm/kdebug.h b/arch/arm/include/asm/kdebug.h
deleted file mode 100644
index 6ece1b037665..000000000000
--- a/arch/arm/include/asm/kdebug.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/kdebug.h>
diff --git a/arch/arm/include/asm/local.h b/arch/arm/include/asm/local.h
deleted file mode 100644
index c11c530f74d0..000000000000
--- a/arch/arm/include/asm/local.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/local.h>
diff --git a/arch/arm/include/asm/local64.h b/arch/arm/include/asm/local64.h
deleted file mode 100644
index 36c93b5cc239..000000000000
--- a/arch/arm/include/asm/local64.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/local64.h>
diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h
index 080d74f8128d..6fd955d34c65 100644
--- a/arch/arm/include/asm/localtimer.h
+++ b/arch/arm/include/asm/localtimer.h
@@ -10,6 +10,8 @@
#ifndef __ASM_ARM_LOCALTIMER_H
#define __ASM_ARM_LOCALTIMER_H
+#include <linux/errno.h>
+
struct clock_event_device;
/*
@@ -22,6 +24,10 @@ void percpu_timer_setup(void);
*/
asmlinkage void do_local_timer(struct pt_regs *);
+/*
+ * Called from C code
+ */
+void handle_local_timer(struct pt_regs *);
#ifdef CONFIG_LOCAL_TIMERS
diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h
index 217aa1911dd7..c5699987fa98 100644
--- a/arch/arm/include/asm/mach/arch.h
+++ b/arch/arm/include/asm/mach/arch.h
@@ -34,8 +34,7 @@ struct machine_desc {
unsigned int reserve_lp1 :1; /* never has lp1 */
unsigned int reserve_lp2 :1; /* never has lp2 */
unsigned int soft_reboot :1; /* soft reboot */
- void (*fixup)(struct machine_desc *,
- struct tag *, char **,
+ void (*fixup)(struct tag *, char **,
struct meminfo *);
void (*reserve)(void);/* reserve mem blocks */
void (*map_io)(void);/* IO mapping function */
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index b8de516e600e..441fc4fe8263 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -160,7 +160,6 @@
* so that all we need to do is modify the 8-bit constant field.
*/
#define __PV_BITS_31_24 0x81000000
-#define __PV_BITS_23_16 0x00810000
extern unsigned long __pv_phys_offset;
#define PHYS_OFFSET __pv_phys_offset
@@ -178,9 +177,6 @@ static inline unsigned long __virt_to_phys(unsigned long x)
{
unsigned long t;
__pv_stub(x, t, "add", __PV_BITS_31_24);
-#ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
- __pv_stub(t, t, "add", __PV_BITS_23_16);
-#endif
return t;
}
@@ -188,9 +184,6 @@ static inline unsigned long __phys_to_virt(unsigned long x)
{
unsigned long t;
__pv_stub(x, t, "sub", __PV_BITS_31_24);
-#ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
- __pv_stub(t, t, "sub", __PV_BITS_23_16);
-#endif
return t;
}
#else
diff --git a/arch/arm/include/asm/module.h b/arch/arm/include/asm/module.h
index 543b44916d2c..6c6809f982f1 100644
--- a/arch/arm/include/asm/module.h
+++ b/arch/arm/include/asm/module.h
@@ -31,11 +31,7 @@ struct mod_arch_specific {
/* Add __virt_to_phys patching state as well */
#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
-#ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
-#define MODULE_ARCH_VERMAGIC_P2V "p2v16 "
-#else
#define MODULE_ARCH_VERMAGIC_P2V "p2v8 "
-#endif
#else
#define MODULE_ARCH_VERMAGIC_P2V ""
#endif
diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h
index d8387437ec5a..53426c66352a 100644
--- a/arch/arm/include/asm/outercache.h
+++ b/arch/arm/include/asm/outercache.h
@@ -34,6 +34,7 @@ struct outer_cache_fns {
void (*sync)(void);
#endif
void (*set_debug)(unsigned long);
+ void (*resume)(void);
};
#ifdef CONFIG_OUTER_CACHE
@@ -74,6 +75,12 @@ static inline void outer_disable(void)
outer_cache.disable();
}
+static inline void outer_resume(void)
+{
+ if (outer_cache.resume)
+ outer_cache.resume();
+}
+
#else
static inline void outer_inv_range(phys_addr_t start, phys_addr_t end)
diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h
index ac75d0848889..ca94653f1ecb 100644
--- a/arch/arm/include/asm/page.h
+++ b/arch/arm/include/asm/page.h
@@ -151,47 +151,7 @@ extern void __cpu_copy_user_highpage(struct page *to, struct page *from,
#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
extern void copy_page(void *to, const void *from);
-typedef unsigned long pteval_t;
-
-#undef STRICT_MM_TYPECHECKS
-
-#ifdef STRICT_MM_TYPECHECKS
-/*
- * These are used to make use of C type-checking..
- */
-typedef struct { pteval_t pte; } pte_t;
-typedef struct { unsigned long pmd; } pmd_t;
-typedef struct { unsigned long pgd[2]; } pgd_t;
-typedef struct { unsigned long pgprot; } pgprot_t;
-
-#define pte_val(x) ((x).pte)
-#define pmd_val(x) ((x).pmd)
-#define pgd_val(x) ((x).pgd[0])
-#define pgprot_val(x) ((x).pgprot)
-
-#define __pte(x) ((pte_t) { (x) } )
-#define __pmd(x) ((pmd_t) { (x) } )
-#define __pgprot(x) ((pgprot_t) { (x) } )
-
-#else
-/*
- * .. while these make it easier on the compiler
- */
-typedef pteval_t pte_t;
-typedef unsigned long pmd_t;
-typedef unsigned long pgd_t[2];
-typedef unsigned long pgprot_t;
-
-#define pte_val(x) (x)
-#define pmd_val(x) (x)
-#define pgd_val(x) ((x)[0])
-#define pgprot_val(x) (x)
-
-#define __pte(x) (x)
-#define __pmd(x) (x)
-#define __pgprot(x) (x)
-
-#endif /* STRICT_MM_TYPECHECKS */
+#include <asm/pgtable-2level-types.h>
#endif /* CONFIG_MMU */
diff --git a/arch/arm/include/asm/percpu.h b/arch/arm/include/asm/percpu.h
deleted file mode 100644
index b4e32d8ec072..000000000000
--- a/arch/arm/include/asm/percpu.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ARM_PERCPU
-#define __ARM_PERCPU
-
-#include <asm-generic/percpu.h>
-
-#endif
diff --git a/arch/arm/include/asm/pgalloc.h b/arch/arm/include/asm/pgalloc.h
index 22de005f159c..3e08fd3fbb6b 100644
--- a/arch/arm/include/asm/pgalloc.h
+++ b/arch/arm/include/asm/pgalloc.h
@@ -105,9 +105,9 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
}
static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t pte,
- unsigned long prot)
+ pmdval_t prot)
{
- unsigned long pmdval = (pte + PTE_HWTABLE_OFF) | prot;
+ pmdval_t pmdval = (pte + PTE_HWTABLE_OFF) | prot;
pmdp[0] = __pmd(pmdval);
pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));
flush_pmd_entry(pmdp);
diff --git a/arch/arm/include/asm/pgtable-2level-hwdef.h b/arch/arm/include/asm/pgtable-2level-hwdef.h
new file mode 100644
index 000000000000..5cfba15cb401
--- /dev/null
+++ b/arch/arm/include/asm/pgtable-2level-hwdef.h
@@ -0,0 +1,93 @@
+/*
+ * arch/arm/include/asm/pgtable-2level-hwdef.h
+ *
+ * Copyright (C) 1995-2002 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _ASM_PGTABLE_2LEVEL_HWDEF_H
+#define _ASM_PGTABLE_2LEVEL_HWDEF_H
+
+/*
+ * Hardware page table definitions.
+ *
+ * + Level 1 descriptor (PMD)
+ * - common
+ */
+#define PMD_TYPE_MASK (_AT(pmdval_t, 3) << 0)
+#define PMD_TYPE_FAULT (_AT(pmdval_t, 0) << 0)
+#define PMD_TYPE_TABLE (_AT(pmdval_t, 1) << 0)
+#define PMD_TYPE_SECT (_AT(pmdval_t, 2) << 0)
+#define PMD_BIT4 (_AT(pmdval_t, 1) << 4)
+#define PMD_DOMAIN(x) (_AT(pmdval_t, (x)) << 5)
+#define PMD_PROTECTION (_AT(pmdval_t, 1) << 9) /* v5 */
+/*
+ * - section
+ */
+#define PMD_SECT_BUFFERABLE (_AT(pmdval_t, 1) << 2)
+#define PMD_SECT_CACHEABLE (_AT(pmdval_t, 1) << 3)
+#define PMD_SECT_XN (_AT(pmdval_t, 1) << 4) /* v6 */
+#define PMD_SECT_AP_WRITE (_AT(pmdval_t, 1) << 10)
+#define PMD_SECT_AP_READ (_AT(pmdval_t, 1) << 11)
+#define PMD_SECT_TEX(x) (_AT(pmdval_t, (x)) << 12) /* v5 */
+#define PMD_SECT_APX (_AT(pmdval_t, 1) << 15) /* v6 */
+#define PMD_SECT_S (_AT(pmdval_t, 1) << 16) /* v6 */
+#define PMD_SECT_nG (_AT(pmdval_t, 1) << 17) /* v6 */
+#define PMD_SECT_SUPER (_AT(pmdval_t, 1) << 18) /* v6 */
+#define PMD_SECT_AF (_AT(pmdval_t, 0))
+
+#define PMD_SECT_UNCACHED (_AT(pmdval_t, 0))
+#define PMD_SECT_BUFFERED (PMD_SECT_BUFFERABLE)
+#define PMD_SECT_WT (PMD_SECT_CACHEABLE)
+#define PMD_SECT_WB (PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE)
+#define PMD_SECT_MINICACHE (PMD_SECT_TEX(1) | PMD_SECT_CACHEABLE)
+#define PMD_SECT_WBWA (PMD_SECT_TEX(1) | PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE)
+#define PMD_SECT_NONSHARED_DEV (PMD_SECT_TEX(2))
+
+/*
+ * - coarse table (not used)
+ */
+
+/*
+ * + Level 2 descriptor (PTE)
+ * - common
+ */
+#define PTE_TYPE_MASK (_AT(pteval_t, 3) << 0)
+#define PTE_TYPE_FAULT (_AT(pteval_t, 0) << 0)
+#define PTE_TYPE_LARGE (_AT(pteval_t, 1) << 0)
+#define PTE_TYPE_SMALL (_AT(pteval_t, 2) << 0)
+#define PTE_TYPE_EXT (_AT(pteval_t, 3) << 0) /* v5 */
+#define PTE_BUFFERABLE (_AT(pteval_t, 1) << 2)
+#define PTE_CACHEABLE (_AT(pteval_t, 1) << 3)
+
+/*
+ * - extended small page/tiny page
+ */
+#define PTE_EXT_XN (_AT(pteval_t, 1) << 0) /* v6 */
+#define PTE_EXT_AP_MASK (_AT(pteval_t, 3) << 4)
+#define PTE_EXT_AP0 (_AT(pteval_t, 1) << 4)
+#define PTE_EXT_AP1 (_AT(pteval_t, 2) << 4)
+#define PTE_EXT_AP_UNO_SRO (_AT(pteval_t, 0) << 4)
+#define PTE_EXT_AP_UNO_SRW (PTE_EXT_AP0)
+#define PTE_EXT_AP_URO_SRW (PTE_EXT_AP1)
+#define PTE_EXT_AP_URW_SRW (PTE_EXT_AP1|PTE_EXT_AP0)
+#define PTE_EXT_TEX(x) (_AT(pteval_t, (x)) << 6) /* v5 */
+#define PTE_EXT_APX (_AT(pteval_t, 1) << 9) /* v6 */
+#define PTE_EXT_COHERENT (_AT(pteval_t, 1) << 9) /* XScale3 */
+#define PTE_EXT_SHARED (_AT(pteval_t, 1) << 10) /* v6 */
+#define PTE_EXT_NG (_AT(pteval_t, 1) << 11) /* v6 */
+
+/*
+ * - small page
+ */
+#define PTE_SMALL_AP_MASK (_AT(pteval_t, 0xff) << 4)
+#define PTE_SMALL_AP_UNO_SRO (_AT(pteval_t, 0x00) << 4)
+#define PTE_SMALL_AP_UNO_SRW (_AT(pteval_t, 0x55) << 4)
+#define PTE_SMALL_AP_URO_SRW (_AT(pteval_t, 0xaa) << 4)
+#define PTE_SMALL_AP_URW_SRW (_AT(pteval_t, 0xff) << 4)
+
+#define PHYS_MASK (~0UL)
+
+#endif
diff --git a/arch/arm/include/asm/pgtable-2level-types.h b/arch/arm/include/asm/pgtable-2level-types.h
new file mode 100644
index 000000000000..66cb5b0e89c5
--- /dev/null
+++ b/arch/arm/include/asm/pgtable-2level-types.h
@@ -0,0 +1,67 @@
+/*
+ * arch/arm/include/asm/pgtable-2level-types.h
+ *
+ * Copyright (C) 1995-2003 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _ASM_PGTABLE_2LEVEL_TYPES_H
+#define _ASM_PGTABLE_2LEVEL_TYPES_H
+
+#include <asm/types.h>
+
+typedef u32 pteval_t;
+typedef u32 pmdval_t;
+
+#undef STRICT_MM_TYPECHECKS
+
+#ifdef STRICT_MM_TYPECHECKS
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef struct { pteval_t pte; } pte_t;
+typedef struct { pmdval_t pmd; } pmd_t;
+typedef struct { pmdval_t pgd[2]; } pgd_t;
+typedef struct { pteval_t pgprot; } pgprot_t;
+
+#define pte_val(x) ((x).pte)
+#define pmd_val(x) ((x).pmd)
+#define pgd_val(x) ((x).pgd[0])
+#define pgprot_val(x) ((x).pgprot)
+
+#define __pte(x) ((pte_t) { (x) } )
+#define __pmd(x) ((pmd_t) { (x) } )
+#define __pgprot(x) ((pgprot_t) { (x) } )
+
+#else
+/*
+ * .. while these make it easier on the compiler
+ */
+typedef pteval_t pte_t;
+typedef pmdval_t pmd_t;
+typedef pmdval_t pgd_t[2];
+typedef pteval_t pgprot_t;
+
+#define pte_val(x) (x)
+#define pmd_val(x) (x)
+#define pgd_val(x) ((x)[0])
+#define pgprot_val(x) (x)
+
+#define __pte(x) (x)
+#define __pmd(x) (x)
+#define __pgprot(x) (x)
+
+#endif /* STRICT_MM_TYPECHECKS */
+
+#endif /* _ASM_PGTABLE_2LEVEL_TYPES_H */
diff --git a/arch/arm/include/asm/pgtable-2level.h b/arch/arm/include/asm/pgtable-2level.h
new file mode 100644
index 000000000000..470457e1cfc5
--- /dev/null
+++ b/arch/arm/include/asm/pgtable-2level.h
@@ -0,0 +1,143 @@
+/*
+ * arch/arm/include/asm/pgtable-2level.h
+ *
+ * Copyright (C) 1995-2002 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _ASM_PGTABLE_2LEVEL_H
+#define _ASM_PGTABLE_2LEVEL_H
+
+/*
+ * Hardware-wise, we have a two level page table structure, where the first
+ * level has 4096 entries, and the second level has 256 entries. Each entry
+ * is one 32-bit word. Most of the bits in the second level entry are used
+ * by hardware, and there aren't any "accessed" and "dirty" bits.
+ *
+ * Linux on the other hand has a three level page table structure, which can
+ * be wrapped to fit a two level page table structure easily - using the PGD
+ * and PTE only. However, Linux also expects one "PTE" table per page, and
+ * at least a "dirty" bit.
+ *
+ * Therefore, we tweak the implementation slightly - we tell Linux that we
+ * have 2048 entries in the first level, each of which is 8 bytes (iow, two
+ * hardware pointers to the second level.) The second level contains two
+ * hardware PTE tables arranged contiguously, preceded by Linux versions
+ * which contain the state information Linux needs. We, therefore, end up
+ * with 512 entries in the "PTE" level.
+ *
+ * This leads to the page tables having the following layout:
+ *
+ * pgd pte
+ * | |
+ * +--------+
+ * | | +------------+ +0
+ * +- - - - + | Linux pt 0 |
+ * | | +------------+ +1024
+ * +--------+ +0 | Linux pt 1 |
+ * | |-----> +------------+ +2048
+ * +- - - - + +4 | h/w pt 0 |
+ * | |-----> +------------+ +3072
+ * +--------+ +8 | h/w pt 1 |
+ * | | +------------+ +4096
+ *
+ * See L_PTE_xxx below for definitions of bits in the "Linux pt", and
+ * PTE_xxx for definitions of bits appearing in the "h/w pt".
+ *
+ * PMD_xxx definitions refer to bits in the first level page table.
+ *
+ * The "dirty" bit is emulated by only granting hardware write permission
+ * iff the page is marked "writable" and "dirty" in the Linux PTE. This
+ * means that a write to a clean page will cause a permission fault, and
+ * the Linux MM layer will mark the page dirty via handle_pte_fault().
+ * For the hardware to notice the permission change, the TLB entry must
+ * be flushed, and ptep_set_access_flags() does that for us.
+ *
+ * The "accessed" or "young" bit is emulated by a similar method; we only
+ * allow accesses to the page if the "young" bit is set. Accesses to the
+ * page will cause a fault, and handle_pte_fault() will set the young bit
+ * for us as long as the page is marked present in the corresponding Linux
+ * PTE entry. Again, ptep_set_access_flags() will ensure that the TLB is
+ * up to date.
+ *
+ * However, when the "young" bit is cleared, we deny access to the page
+ * by clearing the hardware PTE. Currently Linux does not flush the TLB
+ * for us in this case, which means the TLB will retain the transation
+ * until either the TLB entry is evicted under pressure, or a context
+ * switch which changes the user space mapping occurs.
+ */
+#define PTRS_PER_PTE 512
+#define PTRS_PER_PMD 1
+#define PTRS_PER_PGD 2048
+
+#define PTE_HWTABLE_PTRS (PTRS_PER_PTE)
+#define PTE_HWTABLE_OFF (PTE_HWTABLE_PTRS * sizeof(pte_t))
+#define PTE_HWTABLE_SIZE (PTRS_PER_PTE * sizeof(u32))
+
+/*
+ * PMD_SHIFT determines the size of the area a second-level page table can map
+ * PGDIR_SHIFT determines what a third-level page table entry can map
+ */
+#define PMD_SHIFT 21
+#define PGDIR_SHIFT 21
+
+#define PMD_SIZE (1UL << PMD_SHIFT)
+#define PMD_MASK (~(PMD_SIZE-1))
+#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
+#define PGDIR_MASK (~(PGDIR_SIZE-1))
+
+/*
+ * section address mask and size definitions.
+ */
+#define SECTION_SHIFT 20
+#define SECTION_SIZE (1UL << SECTION_SHIFT)
+#define SECTION_MASK (~(SECTION_SIZE-1))
+
+/*
+ * ARMv6 supersection address mask and size definitions.
+ */
+#define SUPERSECTION_SHIFT 24
+#define SUPERSECTION_SIZE (1UL << SUPERSECTION_SHIFT)
+#define SUPERSECTION_MASK (~(SUPERSECTION_SIZE-1))
+
+#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE)
+
+/*
+ * "Linux" PTE definitions.
+ *
+ * We keep two sets of PTEs - the hardware and the linux version.
+ * This allows greater flexibility in the way we map the Linux bits
+ * onto the hardware tables, and allows us to have YOUNG and DIRTY
+ * bits.
+ *
+ * The PTE table pointer refers to the hardware entries; the "Linux"
+ * entries are stored 1024 bytes below.
+ */
+#define L_PTE_PRESENT (_AT(pteval_t, 1) << 0)
+#define L_PTE_YOUNG (_AT(pteval_t, 1) << 1)
+#define L_PTE_FILE (_AT(pteval_t, 1) << 2) /* only when !PRESENT */
+#define L_PTE_DIRTY (_AT(pteval_t, 1) << 6)
+#define L_PTE_RDONLY (_AT(pteval_t, 1) << 7)
+#define L_PTE_USER (_AT(pteval_t, 1) << 8)
+#define L_PTE_XN (_AT(pteval_t, 1) << 9)
+#define L_PTE_SHARED (_AT(pteval_t, 1) << 10) /* shared(v6), coherent(xsc3) */
+
+/*
+ * These are the memory types, defined to be compatible with
+ * pre-ARMv6 CPUs cacheable and bufferable bits: XXCB
+ */
+#define L_PTE_MT_UNCACHED (_AT(pteval_t, 0x00) << 2) /* 0000 */
+#define L_PTE_MT_BUFFERABLE (_AT(pteval_t, 0x01) << 2) /* 0001 */
+#define L_PTE_MT_WRITETHROUGH (_AT(pteval_t, 0x02) << 2) /* 0010 */
+#define L_PTE_MT_WRITEBACK (_AT(pteval_t, 0x03) << 2) /* 0011 */
+#define L_PTE_MT_MINICACHE (_AT(pteval_t, 0x06) << 2) /* 0110 (sa1100, xscale) */
+#define L_PTE_MT_WRITEALLOC (_AT(pteval_t, 0x07) << 2) /* 0111 */
+#define L_PTE_MT_DEV_SHARED (_AT(pteval_t, 0x04) << 2) /* 0100 */
+#define L_PTE_MT_DEV_NONSHARED (_AT(pteval_t, 0x0c) << 2) /* 1100 */
+#define L_PTE_MT_DEV_WC (_AT(pteval_t, 0x09) << 2) /* 1001 */
+#define L_PTE_MT_DEV_CACHED (_AT(pteval_t, 0x0b) << 2) /* 1011 */
+#define L_PTE_MT_MASK (_AT(pteval_t, 0x0f) << 2)
+
+#endif /* _ASM_PGTABLE_2LEVEL_H */
diff --git a/arch/arm/include/asm/pgtable-hwdef.h b/arch/arm/include/asm/pgtable-hwdef.h
index fd1521d5cb9d..183111164ce9 100644
--- a/arch/arm/include/asm/pgtable-hwdef.h
+++ b/arch/arm/include/asm/pgtable-hwdef.h
@@ -10,81 +10,6 @@
#ifndef _ASMARM_PGTABLE_HWDEF_H
#define _ASMARM_PGTABLE_HWDEF_H
-/*
- * Hardware page table definitions.
- *
- * + Level 1 descriptor (PMD)
- * - common
- */
-#define PMD_TYPE_MASK (3 << 0)
-#define PMD_TYPE_FAULT (0 << 0)
-#define PMD_TYPE_TABLE (1 << 0)
-#define PMD_TYPE_SECT (2 << 0)
-#define PMD_BIT4 (1 << 4)
-#define PMD_DOMAIN(x) ((x) << 5)
-#define PMD_PROTECTION (1 << 9) /* v5 */
-/*
- * - section
- */
-#define PMD_SECT_BUFFERABLE (1 << 2)
-#define PMD_SECT_CACHEABLE (1 << 3)
-#define PMD_SECT_XN (1 << 4) /* v6 */
-#define PMD_SECT_AP_WRITE (1 << 10)
-#define PMD_SECT_AP_READ (1 << 11)
-#define PMD_SECT_TEX(x) ((x) << 12) /* v5 */
-#define PMD_SECT_APX (1 << 15) /* v6 */
-#define PMD_SECT_S (1 << 16) /* v6 */
-#define PMD_SECT_nG (1 << 17) /* v6 */
-#define PMD_SECT_SUPER (1 << 18) /* v6 */
-
-#define PMD_SECT_UNCACHED (0)
-#define PMD_SECT_BUFFERED (PMD_SECT_BUFFERABLE)
-#define PMD_SECT_WT (PMD_SECT_CACHEABLE)
-#define PMD_SECT_WB (PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE)
-#define PMD_SECT_MINICACHE (PMD_SECT_TEX(1) | PMD_SECT_CACHEABLE)
-#define PMD_SECT_WBWA (PMD_SECT_TEX(1) | PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE)
-#define PMD_SECT_NONSHARED_DEV (PMD_SECT_TEX(2))
-
-/*
- * - coarse table (not used)
- */
-
-/*
- * + Level 2 descriptor (PTE)
- * - common
- */
-#define PTE_TYPE_MASK (3 << 0)
-#define PTE_TYPE_FAULT (0 << 0)
-#define PTE_TYPE_LARGE (1 << 0)
-#define PTE_TYPE_SMALL (2 << 0)
-#define PTE_TYPE_EXT (3 << 0) /* v5 */
-#define PTE_BUFFERABLE (1 << 2)
-#define PTE_CACHEABLE (1 << 3)
-
-/*
- * - extended small page/tiny page
- */
-#define PTE_EXT_XN (1 << 0) /* v6 */
-#define PTE_EXT_AP_MASK (3 << 4)
-#define PTE_EXT_AP0 (1 << 4)
-#define PTE_EXT_AP1 (2 << 4)
-#define PTE_EXT_AP_UNO_SRO (0 << 4)
-#define PTE_EXT_AP_UNO_SRW (PTE_EXT_AP0)
-#define PTE_EXT_AP_URO_SRW (PTE_EXT_AP1)
-#define PTE_EXT_AP_URW_SRW (PTE_EXT_AP1|PTE_EXT_AP0)
-#define PTE_EXT_TEX(x) ((x) << 6) /* v5 */
-#define PTE_EXT_APX (1 << 9) /* v6 */
-#define PTE_EXT_COHERENT (1 << 9) /* XScale3 */
-#define PTE_EXT_SHARED (1 << 10) /* v6 */
-#define PTE_EXT_NG (1 << 11) /* v6 */
-
-/*
- * - small page
- */
-#define PTE_SMALL_AP_MASK (0xff << 4)
-#define PTE_SMALL_AP_UNO_SRO (0x00 << 4)
-#define PTE_SMALL_AP_UNO_SRW (0x55 << 4)
-#define PTE_SMALL_AP_URO_SRW (0xaa << 4)
-#define PTE_SMALL_AP_URW_SRW (0xff << 4)
+#include <asm/pgtable-2level-hwdef.h>
#endif
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 5750704e0271..8ade1840c6f2 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -24,6 +24,8 @@
#include <mach/vmalloc.h>
#include <asm/pgtable-hwdef.h>
+#include <asm/pgtable-2level.h>
+
/*
* Just any arbitrary offset to the start of the vmalloc VM area: the
* current 8MB value just means that there will be a 8MB "hole" after the
@@ -41,79 +43,6 @@
#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#endif
-/*
- * Hardware-wise, we have a two level page table structure, where the first
- * level has 4096 entries, and the second level has 256 entries. Each entry
- * is one 32-bit word. Most of the bits in the second level entry are used
- * by hardware, and there aren't any "accessed" and "dirty" bits.
- *
- * Linux on the other hand has a three level page table structure, which can
- * be wrapped to fit a two level page table structure easily - using the PGD
- * and PTE only. However, Linux also expects one "PTE" table per page, and
- * at least a "dirty" bit.
- *
- * Therefore, we tweak the implementation slightly - we tell Linux that we
- * have 2048 entries in the first level, each of which is 8 bytes (iow, two
- * hardware pointers to the second level.) The second level contains two
- * hardware PTE tables arranged contiguously, preceded by Linux versions
- * which contain the state information Linux needs. We, therefore, end up
- * with 512 entries in the "PTE" level.
- *
- * This leads to the page tables having the following layout:
- *
- * pgd pte
- * | |
- * +--------+
- * | | +------------+ +0
- * +- - - - + | Linux pt 0 |
- * | | +------------+ +1024
- * +--------+ +0 | Linux pt 1 |
- * | |-----> +------------+ +2048
- * +- - - - + +4 | h/w pt 0 |
- * | |-----> +------------+ +3072
- * +--------+ +8 | h/w pt 1 |
- * | | +------------+ +4096
- *
- * See L_PTE_xxx below for definitions of bits in the "Linux pt", and
- * PTE_xxx for definitions of bits appearing in the "h/w pt".
- *
- * PMD_xxx definitions refer to bits in the first level page table.
- *
- * The "dirty" bit is emulated by only granting hardware write permission
- * iff the page is marked "writable" and "dirty" in the Linux PTE. This
- * means that a write to a clean page will cause a permission fault, and
- * the Linux MM layer will mark the page dirty via handle_pte_fault().
- * For the hardware to notice the permission change, the TLB entry must
- * be flushed, and ptep_set_access_flags() does that for us.
- *
- * The "accessed" or "young" bit is emulated by a similar method; we only
- * allow accesses to the page if the "young" bit is set. Accesses to the
- * page will cause a fault, and handle_pte_fault() will set the young bit
- * for us as long as the page is marked present in the corresponding Linux
- * PTE entry. Again, ptep_set_access_flags() will ensure that the TLB is
- * up to date.
- *
- * However, when the "young" bit is cleared, we deny access to the page
- * by clearing the hardware PTE. Currently Linux does not flush the TLB
- * for us in this case, which means the TLB will retain the transation
- * until either the TLB entry is evicted under pressure, or a context
- * switch which changes the user space mapping occurs.
- */
-#define PTRS_PER_PTE 512
-#define PTRS_PER_PMD 1
-#define PTRS_PER_PGD 2048
-
-#define PTE_HWTABLE_PTRS (PTRS_PER_PTE)
-#define PTE_HWTABLE_OFF (PTE_HWTABLE_PTRS * sizeof(pte_t))
-#define PTE_HWTABLE_SIZE (PTRS_PER_PTE * sizeof(u32))
-
-/*
- * PMD_SHIFT determines the size of the area a second-level page table can map
- * PGDIR_SHIFT determines what a third-level page table entry can map
- */
-#define PMD_SHIFT 21
-#define PGDIR_SHIFT 21
-
#define LIBRARY_TEXT_START 0x0c000000
#ifndef __ASSEMBLY__
@@ -124,12 +53,6 @@ extern void __pgd_error(const char *file, int line, pgd_t);
#define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte)
#define pmd_ERROR(pmd) __pmd_error(__FILE__, __LINE__, pmd)
#define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd)
-#endif /* !__ASSEMBLY__ */
-
-#define PMD_SIZE (1UL << PMD_SHIFT)
-#define PMD_MASK (~(PMD_SIZE-1))
-#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
-#define PGDIR_MASK (~(PGDIR_SIZE-1))
/*
* This is the lowest virtual address we can permit any user space
@@ -138,60 +61,6 @@ extern void __pgd_error(const char *file, int line, pgd_t);
*/
#define FIRST_USER_ADDRESS PAGE_SIZE
-#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE)
-
-/*
- * section address mask and size definitions.
- */
-#define SECTION_SHIFT 20
-#define SECTION_SIZE (1UL << SECTION_SHIFT)
-#define SECTION_MASK (~(SECTION_SIZE-1))
-
-/*
- * ARMv6 supersection address mask and size definitions.
- */
-#define SUPERSECTION_SHIFT 24
-#define SUPERSECTION_SIZE (1UL << SUPERSECTION_SHIFT)
-#define SUPERSECTION_MASK (~(SUPERSECTION_SIZE-1))
-
-/*
- * "Linux" PTE definitions.
- *
- * We keep two sets of PTEs - the hardware and the linux version.
- * This allows greater flexibility in the way we map the Linux bits
- * onto the hardware tables, and allows us to have YOUNG and DIRTY
- * bits.
- *
- * The PTE table pointer refers to the hardware entries; the "Linux"
- * entries are stored 1024 bytes below.
- */
-#define L_PTE_PRESENT (_AT(pteval_t, 1) << 0)
-#define L_PTE_YOUNG (_AT(pteval_t, 1) << 1)
-#define L_PTE_FILE (_AT(pteval_t, 1) << 2) /* only when !PRESENT */
-#define L_PTE_DIRTY (_AT(pteval_t, 1) << 6)
-#define L_PTE_RDONLY (_AT(pteval_t, 1) << 7)
-#define L_PTE_USER (_AT(pteval_t, 1) << 8)
-#define L_PTE_XN (_AT(pteval_t, 1) << 9)
-#define L_PTE_SHARED (_AT(pteval_t, 1) << 10) /* shared(v6), coherent(xsc3) */
-
-/*
- * These are the memory types, defined to be compatible with
- * pre-ARMv6 CPUs cacheable and bufferable bits: XXCB
- */
-#define L_PTE_MT_UNCACHED (_AT(pteval_t, 0x00) << 2) /* 0000 */
-#define L_PTE_MT_BUFFERABLE (_AT(pteval_t, 0x01) << 2) /* 0001 */
-#define L_PTE_MT_WRITETHROUGH (_AT(pteval_t, 0x02) << 2) /* 0010 */
-#define L_PTE_MT_WRITEBACK (_AT(pteval_t, 0x03) << 2) /* 0011 */
-#define L_PTE_MT_MINICACHE (_AT(pteval_t, 0x06) << 2) /* 0110 (sa1100, xscale) */
-#define L_PTE_MT_WRITEALLOC (_AT(pteval_t, 0x07) << 2) /* 0111 */
-#define L_PTE_MT_DEV_SHARED (_AT(pteval_t, 0x04) << 2) /* 0100 */
-#define L_PTE_MT_DEV_NONSHARED (_AT(pteval_t, 0x0c) << 2) /* 1100 */
-#define L_PTE_MT_DEV_WC (_AT(pteval_t, 0x09) << 2) /* 1001 */
-#define L_PTE_MT_DEV_CACHED (_AT(pteval_t, 0x0b) << 2) /* 1011 */
-#define L_PTE_MT_MASK (_AT(pteval_t, 0x0f) << 2)
-
-#ifndef __ASSEMBLY__
-
/*
* The pgprot_* and protection_map entries will be fixed up in runtime
* to include the cachable and bufferable bits based on memory policy,
@@ -327,10 +196,10 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
static inline pte_t *pmd_page_vaddr(pmd_t pmd)
{
- return __va(pmd_val(pmd) & PAGE_MASK);
+ return __va(pmd_val(pmd) & PHYS_MASK & (s32)PAGE_MASK);
}
-#define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd)))
+#define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK))
/* we don't need complex calculations here as the pmd is folded into the pgd */
#define pmd_addr_end(addr,end) (end)
@@ -351,7 +220,7 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd)
#define pte_offset_map(pmd,addr) (__pte_map(pmd) + pte_index(addr))
#define pte_unmap(pte) __pte_unmap(pte)
-#define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT)
+#define pte_pfn(pte) ((pte_val(pte) & PHYS_MASK) >> PAGE_SHIFT)
#define pfn_pte(pfn,prot) __pte(__pfn_to_phys(pfn) | pgprot_val(prot))
#define pte_page(pte) pfn_to_page(pte_pfn(pte))
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 67c70a31a1be..b7e82c4aced6 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -41,7 +41,7 @@ struct arm_pmu_platdata {
* encoded error on failure.
*/
extern struct platform_device *
-reserve_pmu(enum arm_pmu_type device);
+reserve_pmu(enum arm_pmu_type type);
/**
* release_pmu() - Relinquish control of the performance counters
@@ -62,26 +62,26 @@ release_pmu(enum arm_pmu_type type);
* the actual hardware initialisation.
*/
extern int
-init_pmu(enum arm_pmu_type device);
+init_pmu(enum arm_pmu_type type);
#else /* CONFIG_CPU_HAS_PMU */
#include <linux/err.h>
static inline struct platform_device *
-reserve_pmu(enum arm_pmu_type device)
+reserve_pmu(enum arm_pmu_type type)
{
return ERR_PTR(-ENODEV);
}
static inline int
-release_pmu(struct platform_device *pdev)
+release_pmu(enum arm_pmu_type type)
{
return -ENODEV;
}
static inline int
-init_pmu(enum arm_pmu_type device)
+init_pmu(enum arm_pmu_type type)
{
return -ENODEV;
}
diff --git a/arch/arm/include/asm/poll.h b/arch/arm/include/asm/poll.h
deleted file mode 100644
index c98509d3149e..000000000000
--- a/arch/arm/include/asm/poll.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/poll.h>
diff --git a/arch/arm/include/asm/resource.h b/arch/arm/include/asm/resource.h
deleted file mode 100644
index 734b581b5b6a..000000000000
--- a/arch/arm/include/asm/resource.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ARM_RESOURCE_H
-#define _ARM_RESOURCE_H
-
-#include <asm-generic/resource.h>
-
-#endif
diff --git a/arch/arm/include/asm/sections.h b/arch/arm/include/asm/sections.h
deleted file mode 100644
index 2b8c5160388f..000000000000
--- a/arch/arm/include/asm/sections.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/sections.h>
diff --git a/arch/arm/include/asm/siginfo.h b/arch/arm/include/asm/siginfo.h
deleted file mode 100644
index 5e21852e6039..000000000000
--- a/arch/arm/include/asm/siginfo.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASMARM_SIGINFO_H
-#define _ASMARM_SIGINFO_H
-
-#include <asm-generic/siginfo.h>
-
-#endif
diff --git a/arch/arm/include/asm/sizes.h b/arch/arm/include/asm/sizes.h
deleted file mode 100644
index 154b89b81d3e..000000000000
--- a/arch/arm/include/asm/sizes.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-/* Size definitions
- * Copyright (C) ARM Limited 1998. All rights reserved.
- */
-#include <asm-generic/sizes.h>
-
-#define SZ_48M (SZ_32M + SZ_16M)
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index e42d96a45d3e..0a17b62538c2 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -33,6 +33,11 @@ extern void show_ipi_list(struct seq_file *, int);
asmlinkage void do_IPI(int ipinr, struct pt_regs *regs);
/*
+ * Called from C code, this handles an IPI.
+ */
+void handle_IPI(int ipinr, struct pt_regs *regs);
+
+/*
* Setup the set of possible CPUs (via set_cpu_possible)
*/
extern void smp_init_cpus(void);
@@ -66,6 +71,12 @@ extern void platform_secondary_init(unsigned int cpu);
extern void platform_smp_prepare_cpus(unsigned int);
/*
+ * Logical CPU mapping.
+ */
+extern int __cpu_logical_map[NR_CPUS];
+#define cpu_logical_map(cpu) __cpu_logical_map[cpu]
+
+/*
* Initial data for bringing up a secondary CPU.
*/
struct secondary_data {
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 832888d0c20c..984014b92647 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -57,18 +57,12 @@
#ifndef __ASSEMBLY__
+#include <linux/compiler.h>
#include <linux/linkage.h>
#include <linux/irqflags.h>
#include <asm/outercache.h>
-#define __exception __attribute__((section(".exception.text")))
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
-#define __exception_irq_entry __irq_entry
-#else
-#define __exception_irq_entry __exception
-#endif
-
struct thread_info;
struct task_struct;
@@ -97,14 +91,13 @@ void hook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int,
#define xchg(ptr,x) \
((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-extern asmlinkage void __backtrace(void);
extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
struct mm_struct;
extern void show_pte(struct mm_struct *mm, unsigned long addr);
extern void __show_regs(struct pt_regs *);
-extern int cpu_architecture(void);
+extern int __pure cpu_architecture(void);
extern void cpu_init(void);
void arm_machine_restart(char mode, const char *cmd);
diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h
index 8077145698ff..02b2f8203982 100644
--- a/arch/arm/include/asm/tlbflush.h
+++ b/arch/arm/include/asm/tlbflush.h
@@ -471,7 +471,7 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
* these operations. This is typically used when we are removing
* PMD entries.
*/
-static inline void flush_pmd_entry(pmd_t *pmd)
+static inline void flush_pmd_entry(void *pmd)
{
const unsigned int __tlb_flag = __cpu_tlb_flags;
@@ -487,7 +487,7 @@ static inline void flush_pmd_entry(pmd_t *pmd)
dsb();
}
-static inline void clean_pmd_entry(pmd_t *pmd)
+static inline void clean_pmd_entry(void *pmd)
{
const unsigned int __tlb_flag = __cpu_tlb_flags;
diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h
index accbd7cad9b5..a7e457ed27c3 100644
--- a/arch/arm/include/asm/topology.h
+++ b/arch/arm/include/asm/topology.h
@@ -1,6 +1,39 @@
#ifndef _ASM_ARM_TOPOLOGY_H
#define _ASM_ARM_TOPOLOGY_H
+#ifdef CONFIG_ARM_CPU_TOPOLOGY
+
+#include <linux/cpumask.h>
+
+struct cputopo_arm {
+ int thread_id;
+ int core_id;
+ int socket_id;
+ cpumask_t thread_sibling;
+ cpumask_t core_sibling;
+};
+
+extern struct cputopo_arm cpu_topology[NR_CPUS];
+
+#define topology_physical_package_id(cpu) (cpu_topology[cpu].socket_id)
+#define topology_core_id(cpu) (cpu_topology[cpu].core_id)
+#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling)
+#define topology_thread_cpumask(cpu) (&cpu_topology[cpu].thread_sibling)
+
+#define mc_capable() (cpu_topology[0].socket_id != -1)
+#define smt_capable() (cpu_topology[0].thread_id != -1)
+
+void init_cpu_topology(void);
+void store_cpu_topology(unsigned int cpuid);
+const struct cpumask *cpu_coregroup_mask(unsigned int cpu);
+
+#else
+
+static inline void init_cpu_topology(void) { }
+static inline void store_cpu_topology(unsigned int cpuid) { }
+
+#endif
+
#include <asm-generic/topology.h>
#endif /* _ASM_ARM_TOPOLOGY_H */
diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h
index 2c04ed5efeb5..c60a2944f95b 100644
--- a/arch/arm/include/asm/unistd.h
+++ b/arch/arm/include/asm/unistd.h
@@ -478,8 +478,8 @@
/*
* Unimplemented (or alternatively implemented) syscalls
*/
-#define __IGNORE_fadvise64_64 1
-#define __IGNORE_migrate_pages 1
+#define __IGNORE_fadvise64_64
+#define __IGNORE_migrate_pages
#endif /* __KERNEL__ */
#endif /* __ASM_ARM_UNISTD_H */
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index f7887dc53c1f..68036eece340 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -29,7 +29,7 @@ obj-$(CONFIG_MODULES) += armksyms.o module.o
obj-$(CONFIG_ARTHUR) += arthur.o
obj-$(CONFIG_ISA_DMA) += dma-isa.o
obj-$(CONFIG_PCI) += bios32.o isa.o
-obj-$(CONFIG_PM_SLEEP) += sleep.o
+obj-$(CONFIG_ARM_CPU_SUSPEND) += sleep.o
obj-$(CONFIG_HAVE_SCHED_CLOCK) += sched_clock.o
obj-$(CONFIG_SMP) += smp.o smp_tlb.o
obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o
@@ -66,6 +66,7 @@ obj-$(CONFIG_IWMMXT) += iwmmxt.o
obj-$(CONFIG_CPU_HAS_PMU) += pmu.o
obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt
+obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o
ifneq ($(CONFIG_ARCH_EBSA110),y)
obj-y += io.o
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index aeef960ff795..8e3c6f11b0a1 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -49,9 +49,6 @@ extern void __aeabi_ulcmp(void);
extern void fpundefinstr(void);
-
-EXPORT_SYMBOL(__backtrace);
-
/* platform dependent support */
EXPORT_SYMBOL(__udelay);
EXPORT_SYMBOL(__const_udelay);
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
index 16baba2e4369..1429d8989fb9 100644
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -20,6 +20,7 @@
#include <asm/thread_info.h>
#include <asm/memory.h>
#include <asm/procinfo.h>
+#include <asm/hardware/cache-l2x0.h>
#include <linux/kbuild.h>
/*
@@ -92,6 +93,17 @@ int main(void)
DEFINE(S_OLD_R0, offsetof(struct pt_regs, ARM_ORIG_r0));
DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs));
BLANK();
+#ifdef CONFIG_CACHE_L2X0
+ DEFINE(L2X0_R_PHY_BASE, offsetof(struct l2x0_regs, phy_base));
+ DEFINE(L2X0_R_AUX_CTRL, offsetof(struct l2x0_regs, aux_ctrl));
+ DEFINE(L2X0_R_TAG_LATENCY, offsetof(struct l2x0_regs, tag_latency));
+ DEFINE(L2X0_R_DATA_LATENCY, offsetof(struct l2x0_regs, data_latency));
+ DEFINE(L2X0_R_FILTER_START, offsetof(struct l2x0_regs, filter_start));
+ DEFINE(L2X0_R_FILTER_END, offsetof(struct l2x0_regs, filter_end));
+ DEFINE(L2X0_R_PREFETCH_CTRL, offsetof(struct l2x0_regs, prefetch_ctrl));
+ DEFINE(L2X0_R_PWR_CTRL, offsetof(struct l2x0_regs, pwr_ctrl));
+ BLANK();
+#endif
#ifdef CONFIG_CPU_HAS_ASID
DEFINE(MM_CONTEXT_ID, offsetof(struct mm_struct, context.id));
BLANK();
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index d6df359408f0..c0d9203fc75e 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -412,6 +412,9 @@ void pcibios_fixup_bus(struct pci_bus *bus)
printk(KERN_INFO "PCI: bus%d: Fast back to back transfers %sabled\n",
bus->number, (features & PCI_COMMAND_FAST_BACK) ? "en" : "dis");
}
+#ifdef CONFIG_HOTPLUG
+EXPORT_SYMBOL(pcibios_fixup_bus);
+#endif
/*
* Convert from Linux-centric to bus-centric addresses for bridge devices.
@@ -431,6 +434,7 @@ pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
region->start = res->start - offset;
region->end = res->end - offset;
}
+EXPORT_SYMBOL(pcibios_resource_to_bus);
void __devinit
pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
@@ -447,12 +451,7 @@ pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
res->start = region->start + offset;
res->end = region->end + offset;
}
-
-#ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pcibios_fixup_bus);
-EXPORT_SYMBOL(pcibios_resource_to_bus);
EXPORT_SYMBOL(pcibios_bus_to_resource);
-#endif
/*
* Swizzle the device pin each time we cross a bridge.
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index 80f7896cc016..9943e9e74a1b 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -178,7 +178,7 @@
CALL(sys_ni_syscall) /* vm86 */
CALL(sys_ni_syscall) /* was sys_query_module */
CALL(sys_poll)
- CALL(sys_nfsservctl)
+ CALL(sys_ni_syscall) /* was nfsservctl */
/* 170 */ CALL(sys_setresgid16)
CALL(sys_getresgid16)
CALL(sys_prctl)
diff --git a/arch/arm/kernel/debug.S b/arch/arm/kernel/debug.S
index bcd66e00bdbe..0f852d082fcf 100644
--- a/arch/arm/kernel/debug.S
+++ b/arch/arm/kernel/debug.S
@@ -151,6 +151,8 @@ printhex: adr r2, hexbuf
b printascii
ENDPROC(printhex2)
+hexbuf: .space 16
+
.ltorg
ENTRY(printascii)
@@ -175,5 +177,3 @@ ENTRY(printch)
mov r0, #0
b 1b
ENDPROC(printch)
-
-hexbuf: .space 16
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c
index d16500110ee9..4dd0edab6a65 100644
--- a/arch/arm/kernel/ecard.c
+++ b/arch/arm/kernel/ecard.c
@@ -237,7 +237,7 @@ static void ecard_init_pgtables(struct mm_struct *mm)
memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (IO_SIZE / PGDIR_SIZE));
- src_pgd = pgd_offset(mm, EASI_BASE);
+ src_pgd = pgd_offset(mm, (unsigned long)EASI_BASE);
dst_pgd = pgd_offset(mm, EASI_START);
memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (EASI_SIZE / PGDIR_SIZE));
@@ -674,44 +674,37 @@ static int __init ecard_probeirqhw(void)
#define ecard_probeirqhw() (0)
#endif
-#ifndef IO_EC_MEMC8_BASE
-#define IO_EC_MEMC8_BASE 0
-#endif
-
-static unsigned int __ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed)
+static void __iomem *__ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed)
{
- unsigned long address = 0;
+ void __iomem *address = NULL;
int slot = ec->slot_no;
if (ec->slot_no == 8)
- return IO_EC_MEMC8_BASE;
+ return ECARD_MEMC8_BASE;
ectcr &= ~(1 << slot);
switch (type) {
case ECARD_MEMC:
if (slot < 4)
- address = IO_EC_MEMC_BASE + (slot << 12);
+ address = ECARD_MEMC_BASE + (slot << 14);
break;
case ECARD_IOC:
if (slot < 4)
- address = IO_EC_IOC_BASE + (slot << 12);
-#ifdef IO_EC_IOC4_BASE
+ address = ECARD_IOC_BASE + (slot << 14);
else
- address = IO_EC_IOC4_BASE + ((slot - 4) << 12);
-#endif
+ address = ECARD_IOC4_BASE + ((slot - 4) << 14);
if (address)
- address += speed << 17;
+ address += speed << 19;
break;
-#ifdef IO_EC_EASI_BASE
case ECARD_EASI:
- address = IO_EC_EASI_BASE + (slot << 22);
+ address = ECARD_EASI_BASE + (slot << 24);
if (speed == ECARD_FAST)
ectcr |= 1 << slot;
break;
-#endif
+
default:
break;
}
@@ -990,6 +983,7 @@ ecard_probe(int slot, card_type_t type)
ecard_t **ecp;
ecard_t *ec;
struct ex_ecid cid;
+ void __iomem *addr;
int i, rc;
ec = ecard_alloc_card(type, slot);
@@ -999,7 +993,7 @@ ecard_probe(int slot, card_type_t type)
}
rc = -ENODEV;
- if ((ec->podaddr = __ecard_address(ec, type, ECARD_SYNC)) == 0)
+ if ((addr = __ecard_address(ec, type, ECARD_SYNC)) == NULL)
goto nodev;
cid.r_zero = 1;
@@ -1019,7 +1013,7 @@ ecard_probe(int slot, card_type_t type)
ec->cid.fiqmask = cid.r_fiqmask;
ec->cid.fiqoff = ecard_gets24(cid.r_fiqoff);
ec->fiqaddr =
- ec->irqaddr = (void __iomem *)ioaddr(ec->podaddr);
+ ec->irqaddr = addr;
if (ec->cid.is) {
ec->irqmask = ec->cid.irqmask;
@@ -1048,10 +1042,8 @@ ecard_probe(int slot, card_type_t type)
set_irq_flags(ec->irq, IRQF_VALID);
}
-#ifdef IO_EC_MEMC8_BASE
if (slot == 8)
ec->irq = 11;
-#endif
#ifdef CONFIG_ARCH_RPC
/* On RiscPC, only first two slots have DMA capability */
if (slot < 2)
@@ -1097,9 +1089,7 @@ static int __init ecard_init(void)
ecard_probe(slot, ECARD_IOC);
}
-#ifdef IO_EC_MEMC8_BASE
ecard_probe(8, ECARD_IOC);
-#endif
irqhw = ecard_probeirqhw();
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index a87cbf889ff4..9ad50c4208ae 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -24,6 +24,7 @@
#include <asm/unwind.h>
#include <asm/unistd.h>
#include <asm/tls.h>
+#include <asm/system.h>
#include "entry-header.S"
#include <asm/entry-macro-multi.S>
@@ -262,8 +263,7 @@ __und_svc:
ldr r0, [r4, #-4]
#else
ldrh r0, [r4, #-2] @ Thumb instruction at LR - 2
- and r9, r0, #0xf800
- cmp r9, #0xe800 @ 32-bit instruction if xx >= 0
+ cmp r0, #0xe800 @ 32-bit instruction if xx >= 0
ldrhhs r9, [r4] @ bottom 16 bits
orrhs r0, r9, r0, lsl #16
#endif
@@ -440,18 +440,46 @@ __und_usr:
#endif
beq call_fpe
@ Thumb instruction
-#if __LINUX_ARM_ARCH__ >= 7
+#if CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7
+/*
+ * Thumb-2 instruction handling. Note that because pre-v6 and >= v6 platforms
+ * can never be supported in a single kernel, this code is not applicable at
+ * all when __LINUX_ARM_ARCH__ < 6. This allows simplifying assumptions to be
+ * made about .arch directives.
+ */
+#if __LINUX_ARM_ARCH__ < 7
+/* If the target CPU may not be Thumb-2-capable, a run-time check is needed: */
+#define NEED_CPU_ARCHITECTURE
+ ldr r5, .LCcpu_architecture
+ ldr r5, [r5]
+ cmp r5, #CPU_ARCH_ARMv7
+ blo __und_usr_unknown
+/*
+ * The following code won't get run unless the running CPU really is v7, so
+ * coding round the lack of ldrht on older arches is pointless. Temporarily
+ * override the assembler target arch with the minimum required instead:
+ */
+ .arch armv6t2
+#endif
2:
ARM( ldrht r5, [r4], #2 )
THUMB( ldrht r5, [r4] )
THUMB( add r4, r4, #2 )
- and r0, r5, #0xf800 @ mask bits 111x x... .... ....
- cmp r0, #0xe800 @ 32bit instruction if xx != 0
+ cmp r5, #0xe800 @ 32bit instruction if xx != 0
blo __und_usr_unknown
3: ldrht r0, [r4]
add r2, r2, #2 @ r2 is PC + 2, make it PC + 4
orr r0, r0, r5, lsl #16
+
+#if __LINUX_ARM_ARCH__ < 7
+/* If the target arch was overridden, change it back: */
+#ifdef CONFIG_CPU_32v6K
+ .arch armv6k
#else
+ .arch armv6
+#endif
+#endif /* __LINUX_ARM_ARCH__ < 7 */
+#else /* !(CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7) */
b __und_usr_unknown
#endif
UNWIND(.fnend )
@@ -578,6 +606,12 @@ call_fpe:
movw_pc lr @ CP#14 (Debug)
movw_pc lr @ CP#15 (Control)
+#ifdef NEED_CPU_ARCHITECTURE
+ .align 2
+.LCcpu_architecture:
+ .word __cpu_architecture
+#endif
+
#ifdef CONFIG_NEON
.align 6
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 742b6108a001..239703dbdf4f 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -21,6 +21,7 @@
#include <asm/memory.h>
#include <asm/thread_info.h>
#include <asm/system.h>
+#include <asm/pgtable.h>
#ifdef CONFIG_DEBUG_LL
#include <mach/debug-macro.S>
@@ -38,11 +39,14 @@
#error KERNEL_RAM_VADDR must start at 0xXXXX8000
#endif
+#define PG_DIR_SIZE 0x4000
+#define PMD_ORDER 2
+
.globl swapper_pg_dir
- .equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x4000
+ .equ swapper_pg_dir, KERNEL_RAM_VADDR - PG_DIR_SIZE
.macro pgtbl, rd, phys
- add \rd, \phys, #TEXT_OFFSET - 0x4000
+ add \rd, \phys, #TEXT_OFFSET - PG_DIR_SIZE
.endm
#ifdef CONFIG_XIP_KERNEL
@@ -148,11 +152,11 @@ __create_page_tables:
pgtbl r4, r8 @ page table address
/*
- * Clear the 16K level 1 swapper page table
+ * Clear the swapper page table
*/
mov r0, r4
mov r3, #0
- add r6, r0, #0x4000
+ add r6, r0, #PG_DIR_SIZE
1: str r3, [r0], #4
str r3, [r0], #4
str r3, [r0], #4
@@ -171,30 +175,30 @@ __create_page_tables:
sub r0, r0, r3 @ virt->phys offset
add r5, r5, r0 @ phys __enable_mmu
add r6, r6, r0 @ phys __enable_mmu_end
- mov r5, r5, lsr #20
- mov r6, r6, lsr #20
+ mov r5, r5, lsr #SECTION_SHIFT
+ mov r6, r6, lsr #SECTION_SHIFT
-1: orr r3, r7, r5, lsl #20 @ flags + kernel base
- str r3, [r4, r5, lsl #2] @ identity mapping
- teq r5, r6
- addne r5, r5, #1 @ next section
- bne 1b
+1: orr r3, r7, r5, lsl #SECTION_SHIFT @ flags + kernel base
+ str r3, [r4, r5, lsl #PMD_ORDER] @ identity mapping
+ cmp r5, r6
+ addlo r5, r5, #1 @ next section
+ blo 1b
/*
* Now setup the pagetables for our kernel direct
* mapped region.
*/
mov r3, pc
- mov r3, r3, lsr #20
- orr r3, r7, r3, lsl #20
- add r0, r4, #(KERNEL_START & 0xff000000) >> 18
- str r3, [r0, #(KERNEL_START & 0x00f00000) >> 18]!
+ mov r3, r3, lsr #SECTION_SHIFT
+ orr r3, r7, r3, lsl #SECTION_SHIFT
+ add r0, r4, #(KERNEL_START & 0xff000000) >> (SECTION_SHIFT - PMD_ORDER)
+ str r3, [r0, #((KERNEL_START & 0x00f00000) >> SECTION_SHIFT) << PMD_ORDER]!
ldr r6, =(KERNEL_END - 1)
- add r0, r0, #4
- add r6, r4, r6, lsr #18
+ add r0, r0, #1 << PMD_ORDER
+ add r6, r4, r6, lsr #(SECTION_SHIFT - PMD_ORDER)
1: cmp r0, r6
- add r3, r3, #1 << 20
- strls r3, [r0], #4
+ add r3, r3, #1 << SECTION_SHIFT
+ strls r3, [r0], #1 << PMD_ORDER
bls 1b
#ifdef CONFIG_XIP_KERNEL
@@ -203,11 +207,11 @@ __create_page_tables:
*/
add r3, r8, #TEXT_OFFSET
orr r3, r3, r7
- add r0, r4, #(KERNEL_RAM_VADDR & 0xff000000) >> 18
- str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]!
+ add r0, r4, #(KERNEL_RAM_VADDR & 0xff000000) >> (SECTION_SHIFT - PMD_ORDER)
+ str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> (SECTION_SHIFT - PMD_ORDER)]!
ldr r6, =(_end - 1)
add r0, r0, #4
- add r6, r4, r6, lsr #18
+ add r6, r4, r6, lsr #(SECTION_SHIFT - PMD_ORDER)
1: cmp r0, r6
add r3, r3, #1 << 20
strls r3, [r0], #4
@@ -218,12 +222,12 @@ __create_page_tables:
* Then map boot params address in r2 or
* the first 1MB of ram if boot params address is not specified.
*/
- mov r0, r2, lsr #20
- movs r0, r0, lsl #20
+ mov r0, r2, lsr #SECTION_SHIFT
+ movs r0, r0, lsl #SECTION_SHIFT
moveq r0, r8
sub r3, r0, r8
add r3, r3, #PAGE_OFFSET
- add r3, r4, r3, lsr #18
+ add r3, r4, r3, lsr #(SECTION_SHIFT - PMD_ORDER)
orr r6, r7, r0
str r6, [r3]
@@ -236,21 +240,21 @@ __create_page_tables:
*/
addruart r7, r3
- mov r3, r3, lsr #20
- mov r3, r3, lsl #2
+ mov r3, r3, lsr #SECTION_SHIFT
+ mov r3, r3, lsl #PMD_ORDER
add r0, r4, r3
rsb r3, r3, #0x4000 @ PTRS_PER_PGD*sizeof(long)
cmp r3, #0x0800 @ limit to 512MB
movhi r3, #0x0800
add r6, r0, r3
- mov r3, r7, lsr #20
+ mov r3, r7, lsr #SECTION_SHIFT
ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags
- orr r3, r7, r3, lsl #20
+ orr r3, r7, r3, lsl #SECTION_SHIFT
1: str r3, [r0], #4
- add r3, r3, #1 << 20
- teq r0, r6
- bne 1b
+ add r3, r3, #1 << SECTION_SHIFT
+ cmp r0, r6
+ blo 1b
#else /* CONFIG_DEBUG_ICEDCC */
/* we don't need any serial debugging mappings for ICEDCC */
@@ -262,7 +266,7 @@ __create_page_tables:
* If we're using the NetWinder or CATS, we also need to map
* in the 16550-type serial port for the debug messages
*/
- add r0, r4, #0xff000000 >> 18
+ add r0, r4, #0xff000000 >> (SECTION_SHIFT - PMD_ORDER)
orr r3, r7, #0x7c000000
str r3, [r0]
#endif
@@ -272,10 +276,10 @@ __create_page_tables:
* Similar reasons here - for debug. This is
* only for Acorn RiscPC architectures.
*/
- add r0, r4, #0x02000000 >> 18
+ add r0, r4, #0x02000000 >> (SECTION_SHIFT - PMD_ORDER)
orr r3, r7, #0x02000000
str r3, [r0]
- add r0, r4, #0xd8000000 >> 18
+ add r0, r4, #0xd8000000 >> (SECTION_SHIFT - PMD_ORDER)
str r3, [r0]
#endif
#endif
@@ -488,13 +492,8 @@ __fixup_pv_table:
add r5, r5, r3 @ adjust table end address
add r7, r7, r3 @ adjust __pv_phys_offset address
str r8, [r7] @ save computed PHYS_OFFSET to __pv_phys_offset
-#ifndef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
mov r6, r3, lsr #24 @ constant for add/sub instructions
teq r3, r6, lsl #24 @ must be 16MiB aligned
-#else
- mov r6, r3, lsr #16 @ constant for add/sub instructions
- teq r3, r6, lsl #16 @ must be 64kiB aligned
-#endif
THUMB( it ne @ cross section branch )
bne __error
str r6, [r7, #4] @ save to __pv_offset
@@ -510,20 +509,8 @@ ENDPROC(__fixup_pv_table)
.text
__fixup_a_pv_table:
#ifdef CONFIG_THUMB2_KERNEL
-#ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
- lsls r0, r6, #24
- lsr r6, #8
- beq 1f
- clz r7, r0
- lsr r0, #24
- lsl r0, r7
- bic r0, 0x0080
- lsrs r7, #1
- orrcs r0, #0x0080
- orr r0, r0, r7, lsl #12
-#endif
-1: lsls r6, #24
- beq 4f
+ lsls r6, #24
+ beq 2f
clz r7, r6
lsr r6, #24
lsl r6, r7
@@ -532,43 +519,25 @@ __fixup_a_pv_table:
orrcs r6, #0x0080
orr r6, r6, r7, lsl #12
orr r6, #0x4000
- b 4f
-2: @ at this point the C flag is always clear
- add r7, r3
-#ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
- ldrh ip, [r7]
- tst ip, 0x0400 @ the i bit tells us LS or MS byte
- beq 3f
- cmp r0, #0 @ set C flag, and ...
- biceq ip, 0x0400 @ immediate zero value has a special encoding
- streqh ip, [r7] @ that requires the i bit cleared
-#endif
-3: ldrh ip, [r7, #2]
+ b 2f
+1: add r7, r3
+ ldrh ip, [r7, #2]
and ip, 0x8f00
- orrcc ip, r6 @ mask in offset bits 31-24
- orrcs ip, r0 @ mask in offset bits 23-16
+ orr ip, r6 @ mask in offset bits 31-24
strh ip, [r7, #2]
-4: cmp r4, r5
+2: cmp r4, r5
ldrcc r7, [r4], #4 @ use branch for delay slot
- bcc 2b
+ bcc 1b
bx lr
#else
-#ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
- and r0, r6, #255 @ offset bits 23-16
- mov r6, r6, lsr #8 @ offset bits 31-24
-#else
- mov r0, #0 @ just in case...
-#endif
- b 3f
-2: ldr ip, [r7, r3]
+ b 2f
+1: ldr ip, [r7, r3]
bic ip, ip, #0x000000ff
- tst ip, #0x400 @ rotate shift tells us LS or MS byte
- orrne ip, ip, r6 @ mask in offset bits 31-24
- orreq ip, ip, r0 @ mask in offset bits 23-16
+ orr ip, ip, r6 @ mask in offset bits 31-24
str ip, [r7, r3]
-3: cmp r4, r5
+2: cmp r4, r5
ldrcc r7, [r4], #4 @ use branch for delay slot
- bcc 2b
+ bcc 1b
mov pc, lr
#endif
ENDPROC(__fixup_a_pv_table)
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index de3dcab8610b..53919b230e8b 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -35,8 +35,8 @@
#include <linux/list.h>
#include <linux/kallsyms.h>
#include <linux/proc_fs.h>
-#include <linux/ftrace.h>
+#include <asm/exception.h>
#include <asm/system.h>
#include <asm/mach/arch.h>
#include <asm/mach/irq.h>
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
index e59bbd496c39..c1b4463dcc83 100644
--- a/arch/arm/kernel/machine_kexec.c
+++ b/arch/arm/kernel/machine_kexec.c
@@ -32,6 +32,24 @@ static atomic_t waiting_for_crash_ipi;
int machine_kexec_prepare(struct kimage *image)
{
+ unsigned long page_list;
+ void *reboot_code_buffer;
+ page_list = image->head & PAGE_MASK;
+
+ reboot_code_buffer = page_address(image->control_code_page);
+
+ /* Prepare parameters for reboot_code_buffer*/
+ kexec_start_address = image->start;
+ kexec_indirection_page = page_list;
+ kexec_mach_type = machine_arch_type;
+ kexec_boot_atags = image->start - KEXEC_ARM_ZIMAGE_OFFSET + KEXEC_ARM_ATAGS_OFFSET;
+
+ /* copy our kernel relocation code to the control code page */
+ memcpy(reboot_code_buffer,
+ relocate_new_kernel, relocate_new_kernel_size);
+
+ flush_icache_range((unsigned long) reboot_code_buffer,
+ (unsigned long) reboot_code_buffer + KEXEC_CONTROL_PAGE_SIZE);
return 0;
}
@@ -82,31 +100,14 @@ void (*kexec_reinit)(void);
void machine_kexec(struct kimage *image)
{
- unsigned long page_list;
unsigned long reboot_code_buffer_phys;
void *reboot_code_buffer;
-
- page_list = image->head & PAGE_MASK;
-
/* we need both effective and real address here */
reboot_code_buffer_phys =
page_to_pfn(image->control_code_page) << PAGE_SHIFT;
reboot_code_buffer = page_address(image->control_code_page);
- /* Prepare parameters for reboot_code_buffer*/
- kexec_start_address = image->start;
- kexec_indirection_page = page_list;
- kexec_mach_type = machine_arch_type;
- kexec_boot_atags = image->start - KEXEC_ARM_ZIMAGE_OFFSET + KEXEC_ARM_ATAGS_OFFSET;
-
- /* copy our kernel relocation code to the control code page */
- memcpy(reboot_code_buffer,
- relocate_new_kernel, relocate_new_kernel_size);
-
-
- flush_icache_range((unsigned long) reboot_code_buffer,
- (unsigned long) reboot_code_buffer + KEXEC_CONTROL_PAGE_SIZE);
printk(KERN_INFO "Bye!\n");
if (kexec_reinit)
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
index cc2020c2c709..1e9be5d25e56 100644
--- a/arch/arm/kernel/module.c
+++ b/arch/arm/kernel/module.c
@@ -33,7 +33,7 @@
* recompiling the whole kernel when CONFIG_XIP_KERNEL is turned on/off.
*/
#undef MODULES_VADDR
-#define MODULES_VADDR (((unsigned long)_etext + ~PGDIR_MASK) & PGDIR_MASK)
+#define MODULES_VADDR (((unsigned long)_etext + ~PMD_MASK) & PMD_MASK)
#endif
#ifdef CONFIG_MMU
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index 4c851834f68e..6be3e2e4d838 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -321,8 +321,8 @@ static const unsigned armv7_a9_perf_map[PERF_COUNT_HW_MAX] = {
[PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES,
[PERF_COUNT_HW_INSTRUCTIONS] =
ARMV7_PERFCTR_INST_OUT_OF_RENAME_STAGE,
- [PERF_COUNT_HW_CACHE_REFERENCES] = ARMV7_PERFCTR_COHERENT_LINE_HIT,
- [PERF_COUNT_HW_CACHE_MISSES] = ARMV7_PERFCTR_COHERENT_LINE_MISS,
+ [PERF_COUNT_HW_CACHE_REFERENCES] = ARMV7_PERFCTR_DCACHE_ACCESS,
+ [PERF_COUNT_HW_CACHE_MISSES] = ARMV7_PERFCTR_DCACHE_REFILL,
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE,
[PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
[PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_CLOCK_CYCLES,
diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c
index 2b70709376c3..c53474fe84df 100644
--- a/arch/arm/kernel/pmu.c
+++ b/arch/arm/kernel/pmu.c
@@ -31,7 +31,7 @@ static int __devinit pmu_register(struct platform_device *pdev,
{
if (type < 0 || type >= ARM_NUM_PMU_DEVICES) {
pr_warning("received registration request for unknown "
- "device %d\n", type);
+ "PMU device type %d\n", type);
return -EINVAL;
}
@@ -112,17 +112,17 @@ static int __init register_pmu_driver(void)
device_initcall(register_pmu_driver);
struct platform_device *
-reserve_pmu(enum arm_pmu_type device)
+reserve_pmu(enum arm_pmu_type type)
{
struct platform_device *pdev;
- if (test_and_set_bit_lock(device, &pmu_lock)) {
+ if (test_and_set_bit_lock(type, &pmu_lock)) {
pdev = ERR_PTR(-EBUSY);
- } else if (pmu_devices[device] == NULL) {
- clear_bit_unlock(device, &pmu_lock);
+ } else if (pmu_devices[type] == NULL) {
+ clear_bit_unlock(type, &pmu_lock);
pdev = ERR_PTR(-ENODEV);
} else {
- pdev = pmu_devices[device];
+ pdev = pmu_devices[type];
}
return pdev;
@@ -130,11 +130,11 @@ reserve_pmu(enum arm_pmu_type device)
EXPORT_SYMBOL_GPL(reserve_pmu);
int
-release_pmu(enum arm_pmu_type device)
+release_pmu(enum arm_pmu_type type)
{
- if (WARN_ON(!pmu_devices[device]))
+ if (WARN_ON(!pmu_devices[type]))
return -EINVAL;
- clear_bit_unlock(device, &pmu_lock);
+ clear_bit_unlock(type, &pmu_lock);
return 0;
}
EXPORT_SYMBOL_GPL(release_pmu);
@@ -182,17 +182,17 @@ init_cpu_pmu(void)
}
int
-init_pmu(enum arm_pmu_type device)
+init_pmu(enum arm_pmu_type type)
{
int err = 0;
- switch (device) {
+ switch (type) {
case ARM_PMU_DEVICE_CPU:
err = init_cpu_pmu();
break;
default:
- pr_warning("attempt to initialise unknown device %d\n",
- device);
+ pr_warning("attempt to initialise PMU of unknown "
+ "type %d\n", type);
err = -EINVAL;
}
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 1a347f481e5e..fd0814076ff6 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -319,7 +319,7 @@ void show_regs(struct pt_regs * regs)
printk("\n");
printk("Pid: %d, comm: %20s\n", task_pid_nr(current), current->comm);
__show_regs(regs);
- __backtrace();
+ dump_stack();
}
ATOMIC_NOTIFIER_HEAD(thread_notify_head);
diff --git a/arch/arm/kernel/relocate_kernel.S b/arch/arm/kernel/relocate_kernel.S
index 9cf4cbf8f95b..d0cdedf4864d 100644
--- a/arch/arm/kernel/relocate_kernel.S
+++ b/arch/arm/kernel/relocate_kernel.S
@@ -57,7 +57,8 @@ relocate_new_kernel:
mov r0,#0
ldr r1,kexec_mach_type
ldr r2,kexec_boot_atags
- mov pc,lr
+ ARM( mov pc, lr )
+ THUMB( bx lr )
.align
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 70bca649e925..3fe93f75b55a 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -29,6 +29,8 @@
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/memblock.h>
+#include <linux/bug.h>
+#include <linux/compiler.h>
#include <asm/unified.h>
#include <asm/cpu.h>
@@ -42,6 +44,7 @@
#include <asm/cacheflush.h>
#include <asm/cachetype.h>
#include <asm/tlbflush.h>
+#include <asm/system.h>
#include <asm/prom.h>
#include <asm/mach/arch.h>
@@ -115,6 +118,13 @@ struct outer_cache_fns outer_cache __read_mostly;
EXPORT_SYMBOL(outer_cache);
#endif
+/*
+ * Cached cpu_architecture() result for use by assembler code.
+ * C code should use the cpu_architecture() function instead of accessing this
+ * variable directly.
+ */
+int __cpu_architecture __read_mostly = CPU_ARCH_UNKNOWN;
+
struct stack {
u32 irq[3];
u32 abt[3];
@@ -210,7 +220,7 @@ static const char *proc_arch[] = {
"?(17)",
};
-int cpu_architecture(void)
+static int __get_cpu_architecture(void)
{
int cpu_arch;
@@ -243,11 +253,22 @@ int cpu_architecture(void)
return cpu_arch;
}
+int __pure cpu_architecture(void)
+{
+ BUG_ON(__cpu_architecture == CPU_ARCH_UNKNOWN);
+
+ return __cpu_architecture;
+}
+
static int cpu_has_aliasing_icache(unsigned int arch)
{
int aliasing_icache;
unsigned int id_reg, num_sets, line_size;
+ /* PIPT caches never alias. */
+ if (icache_is_pipt())
+ return 0;
+
/* arch specifies the register format */
switch (arch) {
case CPU_ARCH_ARMv7:
@@ -280,18 +301,25 @@ static void __init cacheid_init(void)
if (arch >= CPU_ARCH_ARMv6) {
if ((cachetype & (7 << 29)) == 4 << 29) {
/* ARMv7 register format */
+ arch = CPU_ARCH_ARMv7;
cacheid = CACHEID_VIPT_NONALIASING;
- if ((cachetype & (3 << 14)) == 1 << 14)
+ switch (cachetype & (3 << 14)) {
+ case (1 << 14):
cacheid |= CACHEID_ASID_TAGGED;
- else if (cpu_has_aliasing_icache(CPU_ARCH_ARMv7))
- cacheid |= CACHEID_VIPT_I_ALIASING;
- } else if (cachetype & (1 << 23)) {
- cacheid = CACHEID_VIPT_ALIASING;
+ break;
+ case (3 << 14):
+ cacheid |= CACHEID_PIPT;
+ break;
+ }
} else {
- cacheid = CACHEID_VIPT_NONALIASING;
- if (cpu_has_aliasing_icache(CPU_ARCH_ARMv6))
- cacheid |= CACHEID_VIPT_I_ALIASING;
+ arch = CPU_ARCH_ARMv6;
+ if (cachetype & (1 << 23))
+ cacheid = CACHEID_VIPT_ALIASING;
+ else
+ cacheid = CACHEID_VIPT_NONALIASING;
}
+ if (cpu_has_aliasing_icache(arch))
+ cacheid |= CACHEID_VIPT_I_ALIASING;
} else {
cacheid = CACHEID_VIVT;
}
@@ -299,10 +327,11 @@ static void __init cacheid_init(void)
printk("CPU: %s data cache, %s instruction cache\n",
cache_is_vivt() ? "VIVT" :
cache_is_vipt_aliasing() ? "VIPT aliasing" :
- cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown",
+ cache_is_vipt_nonaliasing() ? "PIPT / VIPT nonaliasing" : "unknown",
cache_is_vivt() ? "VIVT" :
icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" :
icache_is_vipt_aliasing() ? "VIPT aliasing" :
+ icache_is_pipt() ? "PIPT" :
cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown");
}
@@ -413,6 +442,7 @@ static void __init setup_processor(void)
}
cpu_name = list->cpu_name;
+ __cpu_architecture = __get_cpu_architecture();
#ifdef MULTI_CPU
processor = *list->proc;
@@ -860,7 +890,7 @@ static struct machine_desc * __init setup_machine_tags(unsigned int nr)
}
if (mdesc->fixup)
- mdesc->fixup(mdesc, tags, &from, &meminfo);
+ mdesc->fixup(tags, &from, &meminfo);
if (tags->hdr.tag == ATAG_CORE) {
if (meminfo.nr_banks != 0)
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index d88ff0230e82..854ce33715f4 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -16,7 +16,6 @@
#include <linux/cache.h>
#include <linux/profile.h>
#include <linux/errno.h>
-#include <linux/ftrace.h>
#include <linux/mm.h>
#include <linux/err.h>
#include <linux/cpu.h>
@@ -31,6 +30,8 @@
#include <asm/cacheflush.h>
#include <asm/cpu.h>
#include <asm/cputype.h>
+#include <asm/exception.h>
+#include <asm/topology.h>
#include <asm/mmu_context.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
@@ -39,6 +40,7 @@
#include <asm/tlbflush.h>
#include <asm/ptrace.h>
#include <asm/localtimer.h>
+#include <asm/smp_plat.h>
/*
* as from 2.5, kernels no longer have an init_tasks structure
@@ -259,6 +261,20 @@ void __ref cpu_die(void)
}
#endif /* CONFIG_HOTPLUG_CPU */
+int __cpu_logical_map[NR_CPUS];
+
+void __init smp_setup_processor_id(void)
+{
+ int i;
+ u32 cpu = is_smp() ? read_cpuid_mpidr() & 0xff : 0;
+
+ cpu_logical_map(0) = cpu;
+ for (i = 1; i < NR_CPUS; ++i)
+ cpu_logical_map(i) = i == cpu ? 0 : i;
+
+ printk(KERN_INFO "Booting Linux on physical CPU %d\n", cpu);
+}
+
/*
* Called by both boot and secondaries to move global data into
* per-processor storage.
@@ -268,6 +284,8 @@ static void __cpuinit smp_store_cpu_info(unsigned int cpuid)
struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid);
cpu_info->loops_per_jiffy = loops_per_jiffy;
+
+ store_cpu_topology(cpuid);
}
/*
@@ -301,17 +319,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
*/
platform_secondary_init(cpu);
- /*
- * Enable local interrupts.
- */
notify_cpu_starting(cpu);
- local_irq_enable();
- local_fiq_enable();
-
- /*
- * Setup the percpu timer for this CPU.
- */
- percpu_timer_setup();
calibrate_delay();
@@ -323,10 +331,23 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
* before we continue.
*/
set_cpu_online(cpu, true);
+
+ /*
+ * Setup the percpu timer for this CPU.
+ */
+ percpu_timer_setup();
+
while (!cpu_active(cpu))
cpu_relax();
/*
+ * cpu_active bit is set, so it's safe to enalbe interrupts
+ * now.
+ */
+ local_irq_enable();
+ local_fiq_enable();
+
+ /*
* OK, it's off to the idle thread for us
*/
cpu_idle();
@@ -358,6 +379,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
{
unsigned int ncores = num_possible_cpus();
+ init_cpu_topology();
+
smp_store_cpu_info(smp_processor_id());
/*
@@ -460,6 +483,11 @@ static void ipi_timer(void)
#ifdef CONFIG_LOCAL_TIMERS
asmlinkage void __exception_irq_entry do_local_timer(struct pt_regs *regs)
{
+ handle_local_timer(regs);
+}
+
+void handle_local_timer(struct pt_regs *regs)
+{
struct pt_regs *old_regs = set_irq_regs(regs);
int cpu = smp_processor_id();
@@ -567,6 +595,11 @@ static void ipi_cpu_stop(unsigned int cpu)
*/
asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs)
{
+ handle_IPI(ipinr, regs);
+}
+
+void handle_IPI(int ipinr, struct pt_regs *regs)
+{
unsigned int cpu = smp_processor_id();
struct pt_regs *old_regs = set_irq_regs(regs);
diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c
index 79ed5e7f204a..8f5dd7963356 100644
--- a/arch/arm/kernel/smp_scu.c
+++ b/arch/arm/kernel/smp_scu.c
@@ -13,6 +13,7 @@
#include <asm/smp_scu.h>
#include <asm/cacheflush.h>
+#include <asm/cputype.h>
#define SCU_CTRL 0x00
#define SCU_CONFIG 0x04
@@ -33,10 +34,19 @@ unsigned int __init scu_get_core_count(void __iomem *scu_base)
/*
* Enable the SCU
*/
-void __init scu_enable(void __iomem *scu_base)
+void scu_enable(void __iomem *scu_base)
{
u32 scu_ctrl;
+#ifdef CONFIG_ARM_ERRATA_764369
+ /* Cortex-A9 only */
+ if ((read_cpuid(CPUID_ID) & 0xff0ffff0) == 0x410fc090) {
+ scu_ctrl = __raw_readl(scu_base + 0x30);
+ if (!(scu_ctrl & 1))
+ __raw_writel(scu_ctrl | 0x1, scu_base + 0x30);
+ }
+#endif
+
scu_ctrl = __raw_readl(scu_base + SCU_CTRL);
/* already enabled? */
if (scu_ctrl & 1)
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 2c277d40cee6..01c186222f3b 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -137,8 +137,8 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
+ clockevents_register_device(clk);
+
/* Make sure our local interrupt controller has this enabled */
gic_enable_ppi(clk->irq);
-
- clockevents_register_device(clk);
}
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index cb634c3e28e9..5a54b95d6bd2 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -39,13 +39,11 @@
*/
static struct sys_timer *system_timer;
-#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
+#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) || \
+ defined(CONFIG_NVRAM) || defined(CONFIG_NVRAM_MODULE)
/* this needs a better home */
DEFINE_SPINLOCK(rtc_lock);
-
-#ifdef CONFIG_RTC_DRV_CMOS_MODULE
EXPORT_SYMBOL(rtc_lock);
-#endif
#endif /* pc-style 'CMOS' RTC support */
/* change this if you have some constant time drift */
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
new file mode 100644
index 000000000000..1040c00405d0
--- /dev/null
+++ b/arch/arm/kernel/topology.c
@@ -0,0 +1,148 @@
+/*
+ * arch/arm/kernel/topology.c
+ *
+ * Copyright (C) 2011 Linaro Limited.
+ * Written by: Vincent Guittot
+ *
+ * based on arch/sh/kernel/topology.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
+#include <linux/init.h>
+#include <linux/percpu.h>
+#include <linux/node.h>
+#include <linux/nodemask.h>
+#include <linux/sched.h>
+
+#include <asm/cputype.h>
+#include <asm/topology.h>
+
+#define MPIDR_SMP_BITMASK (0x3 << 30)
+#define MPIDR_SMP_VALUE (0x2 << 30)
+
+#define MPIDR_MT_BITMASK (0x1 << 24)
+
+/*
+ * These masks reflect the current use of the affinity levels.
+ * The affinity level can be up to 16 bits according to ARM ARM
+ */
+
+#define MPIDR_LEVEL0_MASK 0x3
+#define MPIDR_LEVEL0_SHIFT 0
+
+#define MPIDR_LEVEL1_MASK 0xF
+#define MPIDR_LEVEL1_SHIFT 8
+
+#define MPIDR_LEVEL2_MASK 0xFF
+#define MPIDR_LEVEL2_SHIFT 16
+
+struct cputopo_arm cpu_topology[NR_CPUS];
+
+const struct cpumask *cpu_coregroup_mask(unsigned int cpu)
+{
+ return &cpu_topology[cpu].core_sibling;
+}
+
+/*
+ * store_cpu_topology is called at boot when only one cpu is running
+ * and with the mutex cpu_hotplug.lock locked, when several cpus have booted,
+ * which prevents simultaneous write access to cpu_topology array
+ */
+void store_cpu_topology(unsigned int cpuid)
+{
+ struct cputopo_arm *cpuid_topo = &cpu_topology[cpuid];
+ unsigned int mpidr;
+ unsigned int cpu;
+
+ /* If the cpu topology has been already set, just return */
+ if (cpuid_topo->core_id != -1)
+ return;
+
+ mpidr = read_cpuid_mpidr();
+
+ /* create cpu topology mapping */
+ if ((mpidr & MPIDR_SMP_BITMASK) == MPIDR_SMP_VALUE) {
+ /*
+ * This is a multiprocessor system
+ * multiprocessor format & multiprocessor mode field are set
+ */
+
+ if (mpidr & MPIDR_MT_BITMASK) {
+ /* core performance interdependency */
+ cpuid_topo->thread_id = (mpidr >> MPIDR_LEVEL0_SHIFT)
+ & MPIDR_LEVEL0_MASK;
+ cpuid_topo->core_id = (mpidr >> MPIDR_LEVEL1_SHIFT)
+ & MPIDR_LEVEL1_MASK;
+ cpuid_topo->socket_id = (mpidr >> MPIDR_LEVEL2_SHIFT)
+ & MPIDR_LEVEL2_MASK;
+ } else {
+ /* largely independent cores */
+ cpuid_topo->thread_id = -1;
+ cpuid_topo->core_id = (mpidr >> MPIDR_LEVEL0_SHIFT)
+ & MPIDR_LEVEL0_MASK;
+ cpuid_topo->socket_id = (mpidr >> MPIDR_LEVEL1_SHIFT)
+ & MPIDR_LEVEL1_MASK;
+ }
+ } else {
+ /*
+ * This is an uniprocessor system
+ * we are in multiprocessor format but uniprocessor system
+ * or in the old uniprocessor format
+ */
+ cpuid_topo->thread_id = -1;
+ cpuid_topo->core_id = 0;
+ cpuid_topo->socket_id = -1;
+ }
+
+ /* update core and thread sibling masks */
+ for_each_possible_cpu(cpu) {
+ struct cputopo_arm *cpu_topo = &cpu_topology[cpu];
+
+ if (cpuid_topo->socket_id == cpu_topo->socket_id) {
+ cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
+ if (cpu != cpuid)
+ cpumask_set_cpu(cpu,
+ &cpuid_topo->core_sibling);
+
+ if (cpuid_topo->core_id == cpu_topo->core_id) {
+ cpumask_set_cpu(cpuid,
+ &cpu_topo->thread_sibling);
+ if (cpu != cpuid)
+ cpumask_set_cpu(cpu,
+ &cpuid_topo->thread_sibling);
+ }
+ }
+ }
+ smp_wmb();
+
+ printk(KERN_INFO "CPU%u: thread %d, cpu %d, socket %d, mpidr %x\n",
+ cpuid, cpu_topology[cpuid].thread_id,
+ cpu_topology[cpuid].core_id,
+ cpu_topology[cpuid].socket_id, mpidr);
+}
+
+/*
+ * init_cpu_topology is called at boot when only one cpu is running
+ * which prevent simultaneous write access to cpu_topology array
+ */
+void init_cpu_topology(void)
+{
+ unsigned int cpu;
+
+ /* init core mask */
+ for_each_possible_cpu(cpu) {
+ struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]);
+
+ cpu_topo->thread_id = -1;
+ cpu_topo->core_id = -1;
+ cpu_topo->socket_id = -1;
+ cpumask_clear(&cpu_topo->core_sibling);
+ cpumask_clear(&cpu_topo->thread_sibling);
+ }
+ smp_wmb();
+}
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index bc9f9da782cb..7f5b99eb2c50 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -21,12 +21,14 @@
#include <linux/kdebug.h>
#include <linux/module.h>
#include <linux/kexec.h>
+#include <linux/bug.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/atomic.h>
#include <asm/cacheflush.h>
+#include <asm/exception.h>
#include <asm/system.h>
#include <asm/unistd.h>
#include <asm/traps.h>
@@ -270,6 +272,8 @@ void die(const char *str, struct pt_regs *regs, int err)
spin_lock_irq(&die_lock);
console_verbose();
bust_spinlocks(1);
+ if (!user_mode(regs))
+ report_bug(regs->ARM_pc, regs);
ret = __die(str, err, thread, regs);
if (regs && kexec_should_crash(thread->task))
@@ -301,6 +305,24 @@ void arm_notify_die(const char *str, struct pt_regs *regs,
}
}
+#ifdef CONFIG_GENERIC_BUG
+
+int is_valid_bugaddr(unsigned long pc)
+{
+#ifdef CONFIG_THUMB2_KERNEL
+ unsigned short bkpt;
+#else
+ unsigned long bkpt;
+#endif
+
+ if (probe_kernel_address((unsigned *)pc, bkpt))
+ return 0;
+
+ return bkpt == BUG_INSTR_VALUE;
+}
+
+#endif
+
static LIST_HEAD(undef_hook);
static DEFINE_SPINLOCK(undef_lock);
@@ -706,16 +728,6 @@ baddataabort(int code, unsigned long instr, struct pt_regs *regs)
arm_notify_die("unknown data abort code", regs, &info, instr, 0);
}
-void __attribute__((noreturn)) __bug(const char *file, int line)
-{
- printk(KERN_CRIT"kernel BUG at %s:%d!\n", file, line);
- *(int *)0 = 0;
-
- /* Avoid "noreturn function does return" */
- for (;;);
-}
-EXPORT_SYMBOL(__bug);
-
void __readwrite_bug(const char *fn)
{
printk("%s called, but not implemented\n", fn);
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index bf977f8514f6..20b3041e0860 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -21,10 +21,13 @@
#define ARM_CPU_KEEP(x)
#endif
-#if defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK)
+#if (defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK)) || \
+ defined(CONFIG_GENERIC_BUG)
#define ARM_EXIT_KEEP(x) x
+#define ARM_EXIT_DISCARD(x)
#else
#define ARM_EXIT_KEEP(x)
+#define ARM_EXIT_DISCARD(x) x
#endif
OUTPUT_ARCH(arm)
@@ -39,6 +42,11 @@ jiffies = jiffies_64 + 4;
SECTIONS
{
/*
+ * XXX: The linker does not define how output sections are
+ * assigned to input sections when there are multiple statements
+ * matching the same input section name. There is no documented
+ * order of matching.
+ *
* unwind exit sections must be discarded before the rest of the
* unwind sections get included.
*/
@@ -47,6 +55,9 @@ SECTIONS
*(.ARM.extab.exit.text)
ARM_CPU_DISCARD(*(.ARM.exidx.cpuexit.text))
ARM_CPU_DISCARD(*(.ARM.extab.cpuexit.text))
+ ARM_EXIT_DISCARD(EXIT_TEXT)
+ ARM_EXIT_DISCARD(EXIT_DATA)
+ EXIT_CALL
#ifndef CONFIG_HOTPLUG
*(.ARM.exidx.devexit.text)
*(.ARM.extab.devexit.text)
@@ -58,6 +69,8 @@ SECTIONS
#ifndef CONFIG_SMP_ON_UP
*(.alt.smp.init)
#endif
+ *(.discard)
+ *(.discard.*)
}
#ifdef CONFIG_XIP_KERNEL
@@ -279,9 +292,6 @@ SECTIONS
STABS_DEBUG
.comment 0 : { *(.comment) }
-
- /* Default discards */
- DISCARDS
}
/*
diff --git a/arch/arm/lib/backtrace.S b/arch/arm/lib/backtrace.S
index a673297b0cf1..cd07b5814c23 100644
--- a/arch/arm/lib/backtrace.S
+++ b/arch/arm/lib/backtrace.S
@@ -22,15 +22,10 @@
#define mask r7
#define offset r8
-ENTRY(__backtrace)
- mov r1, #0x10
- mov r0, fp
-
ENTRY(c_backtrace)
#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK)
mov pc, lr
-ENDPROC(__backtrace)
ENDPROC(c_backtrace)
#else
stmfd sp!, {r4 - r8, lr} @ Save an extra register so we have a location...
@@ -107,7 +102,6 @@ for_each_frame: tst frame, mask @ Check for address exceptions
mov r1, frame
bl printk
no_frame: ldmfd sp!, {r4 - r8, pc}
-ENDPROC(__backtrace)
ENDPROC(c_backtrace)
.pushsection __ex_table,"a"
diff --git a/arch/arm/lib/div64.S b/arch/arm/lib/div64.S
index faa7748142da..e55c4842c290 100644
--- a/arch/arm/lib/div64.S
+++ b/arch/arm/lib/div64.S
@@ -13,6 +13,7 @@
*/
#include <linux/linkage.h>
+#include <asm/unwind.h>
#ifdef __ARMEB__
#define xh r0
@@ -44,6 +45,7 @@
*/
ENTRY(__do_div64)
+UNWIND(.fnstart)
@ Test for easy paths first.
subs ip, r4, #1
@@ -189,7 +191,12 @@ ENTRY(__do_div64)
moveq yh, xh
moveq xh, #0
moveq pc, lr
+UNWIND(.fnend)
+UNWIND(.fnstart)
+UNWIND(.pad #4)
+UNWIND(.save {lr})
+Ldiv0_64:
@ Division by 0:
str lr, [sp, #-8]!
bl __div0
@@ -200,4 +207,5 @@ ENTRY(__do_div64)
mov xh, #0
ldr pc, [sp], #8
+UNWIND(.fnend)
ENDPROC(__do_div64)
diff --git a/arch/arm/lib/uaccess_with_memcpy.c b/arch/arm/lib/uaccess_with_memcpy.c
index 8b9b13649f81..025f742dd4df 100644
--- a/arch/arm/lib/uaccess_with_memcpy.c
+++ b/arch/arm/lib/uaccess_with_memcpy.c
@@ -17,6 +17,7 @@
#include <linux/sched.h>
#include <linux/hardirq.h> /* for in_atomic() */
#include <linux/gfp.h>
+#include <linux/highmem.h>
#include <asm/current.h>
#include <asm/page.h>
diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
index 3462b815054a..9ab5a3e5f4f1 100644
--- a/arch/arm/mach-at91/Makefile.boot
+++ b/arch/arm/mach-at91/Makefile.boot
@@ -4,15 +4,15 @@
# INITRD_PHYS must be in RAM
ifeq ($(CONFIG_ARCH_AT91CAP9),y)
- zreladdr-y := 0x70008000
+ zreladdr-y += 0x70008000
params_phys-y := 0x70000100
initrd_phys-y := 0x70410000
else ifeq ($(CONFIG_ARCH_AT91SAM9G45),y)
- zreladdr-y := 0x70008000
+ zreladdr-y += 0x70008000
params_phys-y := 0x70000100
initrd_phys-y := 0x70410000
else
- zreladdr-y := 0x20008000
+ zreladdr-y += 0x20008000
params_phys-y := 0x20000100
initrd_phys-y := 0x20410000
endif
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index d522b47e30b5..6c8e3b5f669f 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -157,7 +157,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk),
CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk),
- CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc1_clk),
+ CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
diff --git a/arch/arm/mach-bcmring/Kconfig b/arch/arm/mach-bcmring/Kconfig
index 457b4384913e..9170d16dca50 100644
--- a/arch/arm/mach-bcmring/Kconfig
+++ b/arch/arm/mach-bcmring/Kconfig
@@ -17,5 +17,3 @@ config BCM_ZRELADDR
hex "Compressed ZREL ADDR"
endmenu
-
-# source "drivers/char/bcmring/Kconfig"
diff --git a/arch/arm/mach-bcmring/Makefile.boot b/arch/arm/mach-bcmring/Makefile.boot
index fb53b283bebb..aef2467757fa 100644
--- a/arch/arm/mach-bcmring/Makefile.boot
+++ b/arch/arm/mach-bcmring/Makefile.boot
@@ -1,6 +1,6 @@
# Address where decompressor will be written and eventually executed.
#
# default to SDRAM
-zreladdr-y := $(CONFIG_BCM_ZRELADDR)
+zreladdr-y += $(CONFIG_BCM_ZRELADDR)
params_phys-y := 0x00000800
diff --git a/arch/arm/mach-bcmring/arch.c b/arch/arm/mach-bcmring/arch.c
index a604b9ebb501..31a143592c81 100644
--- a/arch/arm/mach-bcmring/arch.c
+++ b/arch/arm/mach-bcmring/arch.c
@@ -136,8 +136,8 @@ static void __init bcmring_init_machine(void)
*
*****************************************************************************/
-static void __init bcmring_fixup(struct machine_desc *desc,
- struct tag *t, char **cmdline, struct meminfo *mi) {
+static void __init bcmring_fixup(struct tag *t, char **cmdline,
+ struct meminfo *mi) {
#ifdef CONFIG_BLK_DEV_INITRD
printk(KERN_NOTICE "bcmring_fixup\n");
t->hdr.tag = ATAG_CORE;
diff --git a/arch/arm/mach-bcmring/irq.c b/arch/arm/mach-bcmring/irq.c
index c48feaf4e8e9..437fa683bcb2 100644
--- a/arch/arm/mach-bcmring/irq.c
+++ b/arch/arm/mach-bcmring/irq.c
@@ -20,7 +20,6 @@
#include <linux/stddef.h>
#include <linux/list.h>
#include <linux/timer.h>
-#include <linux/version.h>
#include <linux/io.h>
#include <mach/hardware.h>
diff --git a/arch/arm/mach-bcmring/timer.c b/arch/arm/mach-bcmring/timer.c
index 2d415d2a8e68..af9c3d7e2a0c 100644
--- a/arch/arm/mach-bcmring/timer.c
+++ b/arch/arm/mach-bcmring/timer.c
@@ -12,7 +12,6 @@
* consent.
*****************************************************************************/
-#include <linux/version.h>
#include <linux/types.h>
#include <linux/module.h>
#include <csp/tmrHw.h>
diff --git a/arch/arm/mach-clps711x/Makefile.boot b/arch/arm/mach-clps711x/Makefile.boot
index a51fcef64fe0..9398e859b5af 100644
--- a/arch/arm/mach-clps711x/Makefile.boot
+++ b/arch/arm/mach-clps711x/Makefile.boot
@@ -1,5 +1,5 @@
# The standard locations for stuff on CLPS711x type processors
- zreladdr-y := 0xc0028000
+ zreladdr-y += 0xc0028000
params_phys-y := 0xc0000100
# Should probably have some agreement on these...
initrd_phys-$(CONFIG_ARCH_P720T) := 0xc0400000
diff --git a/arch/arm/mach-clps711x/clep7312.c b/arch/arm/mach-clps711x/clep7312.c
index 67b5abb4a60a..0a2e74feb24a 100644
--- a/arch/arm/mach-clps711x/clep7312.c
+++ b/arch/arm/mach-clps711x/clep7312.c
@@ -26,8 +26,7 @@
#include "common.h"
static void __init
-fixup_clep7312(struct machine_desc *desc, struct tag *tags,
- char **cmdline, struct meminfo *mi)
+fixup_clep7312(struct tag *tags, char **cmdline, struct meminfo *mi)
{
mi->nr_banks=1;
mi->bank[0].start = 0xc0000000;
diff --git a/arch/arm/mach-clps711x/edb7211-arch.c b/arch/arm/mach-clps711x/edb7211-arch.c
index 98ca5b2e940d..725a7a54ba42 100644
--- a/arch/arm/mach-clps711x/edb7211-arch.c
+++ b/arch/arm/mach-clps711x/edb7211-arch.c
@@ -37,8 +37,7 @@ static void __init edb7211_reserve(void)
}
static void __init
-fixup_edb7211(struct machine_desc *desc, struct tag *tags,
- char **cmdline, struct meminfo *mi)
+fixup_edb7211(struct tag *tags, char **cmdline, struct meminfo *mi)
{
/*
* Bank start addresses are not present in the information
diff --git a/arch/arm/mach-clps711x/fortunet.c b/arch/arm/mach-clps711x/fortunet.c
index b1cb479e71e9..1947b30f9b8c 100644
--- a/arch/arm/mach-clps711x/fortunet.c
+++ b/arch/arm/mach-clps711x/fortunet.c
@@ -57,8 +57,7 @@ typedef struct tag_IMAGE_PARAMS
#define IMAGE_PARAMS_PHYS 0xC01F0000
static void __init
-fortunet_fixup(struct machine_desc *desc, struct tag *tags,
- char **cmdline, struct meminfo *mi)
+fortunet_fixup(struct tag *tags, char **cmdline, struct meminfo *mi)
{
IMAGE_PARAMS *ip = phys_to_virt(IMAGE_PARAMS_PHYS);
*cmdline = phys_to_virt(ip->command_line);
diff --git a/arch/arm/mach-clps711x/p720t.c b/arch/arm/mach-clps711x/p720t.c
index cefbce0480b9..3f796e0d3284 100644
--- a/arch/arm/mach-clps711x/p720t.c
+++ b/arch/arm/mach-clps711x/p720t.c
@@ -56,8 +56,7 @@ static struct map_desc p720t_io_desc[] __initdata = {
};
static void __init
-fixup_p720t(struct machine_desc *desc, struct tag *tag,
- char **cmdline, struct meminfo *mi)
+fixup_p720t(struct tag *tag, char **cmdline, struct meminfo *mi)
{
/*
* Our bootloader doesn't setup any tags (yet).
diff --git a/arch/arm/mach-cns3xxx/Makefile.boot b/arch/arm/mach-cns3xxx/Makefile.boot
index 777012865220..d079de0b6e3b 100644
--- a/arch/arm/mach-cns3xxx/Makefile.boot
+++ b/arch/arm/mach-cns3xxx/Makefile.boot
@@ -1,3 +1,3 @@
- zreladdr-y := 0x00008000
+ zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00C00000
diff --git a/arch/arm/mach-cns3xxx/include/mach/entry-macro.S b/arch/arm/mach-cns3xxx/include/mach/entry-macro.S
index 6bd83ed90afe..d87bfc397d39 100644
--- a/arch/arm/mach-cns3xxx/include/mach/entry-macro.S
+++ b/arch/arm/mach-cns3xxx/include/mach/entry-macro.S
@@ -8,7 +8,6 @@
* published by the Free Software Foundation.
*/
-#include <mach/hardware.h>
#include <asm/hardware/entry-macro-gic.S>
.macro disable_fiq
diff --git a/arch/arm/mach-cns3xxx/include/mach/system.h b/arch/arm/mach-cns3xxx/include/mach/system.h
index 58bb03ae3cf4..4f16c9b79f78 100644
--- a/arch/arm/mach-cns3xxx/include/mach/system.h
+++ b/arch/arm/mach-cns3xxx/include/mach/system.h
@@ -13,7 +13,6 @@
#include <linux/io.h>
#include <asm/proc-fns.h>
-#include <mach/hardware.h>
static inline void arch_idle(void)
{
diff --git a/arch/arm/mach-cns3xxx/include/mach/uncompress.h b/arch/arm/mach-cns3xxx/include/mach/uncompress.h
index de8ead9b91f7..a91b6058ab4f 100644
--- a/arch/arm/mach-cns3xxx/include/mach/uncompress.h
+++ b/arch/arm/mach-cns3xxx/include/mach/uncompress.h
@@ -8,7 +8,6 @@
*/
#include <asm/mach-types.h>
-#include <mach/hardware.h>
#include <mach/cns3xxx.h>
#define AMBA_UART_DR(base) (*(volatile unsigned char *)((base) + 0x00))
diff --git a/arch/arm/mach-cns3xxx/pcie.c b/arch/arm/mach-cns3xxx/pcie.c
index 06fd25d70aec..0f8fca48a5ed 100644
--- a/arch/arm/mach-cns3xxx/pcie.c
+++ b/arch/arm/mach-cns3xxx/pcie.c
@@ -49,7 +49,7 @@ static struct cns3xxx_pcie *sysdata_to_cnspci(void *sysdata)
return &cns3xxx_pcie[root->domain];
}
-static struct cns3xxx_pcie *pdev_to_cnspci(struct pci_dev *dev)
+static struct cns3xxx_pcie *pdev_to_cnspci(const struct pci_dev *dev)
{
return sysdata_to_cnspci(dev->sysdata);
}
diff --git a/arch/arm/mach-davinci/Makefile.boot b/arch/arm/mach-davinci/Makefile.boot
index db97ef2c6477..04a6c4e67b14 100644
--- a/arch/arm/mach-davinci/Makefile.boot
+++ b/arch/arm/mach-davinci/Makefile.boot
@@ -2,12 +2,12 @@ ifeq ($(CONFIG_ARCH_DAVINCI_DA8XX),y)
ifeq ($(CONFIG_ARCH_DAVINCI_DMx),y)
$(error Cannot enable DaVinci and DA8XX platforms concurrently)
else
- zreladdr-y := 0xc0008000
+ zreladdr-y += 0xc0008000
params_phys-y := 0xc0000100
initrd_phys-y := 0xc0800000
endif
else
- zreladdr-y := 0x80008000
+ zreladdr-y += 0x80008000
params_phys-y := 0x80000100
initrd_phys-y := 0x80800000
endif
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index bd5394537c88..008d51407cd7 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -115,6 +115,32 @@ static struct spi_board_info da850evm_spi_info[] = {
},
};
+#ifdef CONFIG_MTD
+static void da850_evm_m25p80_notify_add(struct mtd_info *mtd)
+{
+ char *mac_addr = davinci_soc_info.emac_pdata->mac_addr;
+ size_t retlen;
+
+ if (!strcmp(mtd->name, "MAC-Address")) {
+ mtd->read(mtd, 0, ETH_ALEN, &retlen, mac_addr);
+ if (retlen == ETH_ALEN)
+ pr_info("Read MAC addr from SPI Flash: %pM\n",
+ mac_addr);
+ }
+}
+
+static struct mtd_notifier da850evm_spi_notifier = {
+ .add = da850_evm_m25p80_notify_add,
+};
+
+static void da850_evm_setup_mac_addr(void)
+{
+ register_mtd_user(&da850evm_spi_notifier);
+}
+#else
+static void da850_evm_setup_mac_addr(void) { }
+#endif
+
static struct mtd_partition da850_evm_norflash_partition[] = {
{
.name = "bootloaders + env",
@@ -1244,6 +1270,8 @@ static __init void da850_evm_init(void)
if (ret)
pr_warning("da850_evm_init: sata registration failed: %d\n",
ret);
+
+ da850_evm_setup_mac_addr();
}
#ifdef CONFIG_SERIAL_8250_CONSOLE
diff --git a/arch/arm/mach-davinci/include/mach/psc.h b/arch/arm/mach-davinci/include/mach/psc.h
index 47fd0bc3d3e7..fa59c097223d 100644
--- a/arch/arm/mach-davinci/include/mach/psc.h
+++ b/arch/arm/mach-davinci/include/mach/psc.h
@@ -243,7 +243,7 @@
#define PSC_STATE_DISABLE 2
#define PSC_STATE_ENABLE 3
-#define MDSTAT_STATE_MASK 0x1f
+#define MDSTAT_STATE_MASK 0x3f
#define MDCTL_FORCE BIT(31)
#ifndef __ASSEMBLER__
diff --git a/arch/arm/mach-davinci/sleep.S b/arch/arm/mach-davinci/sleep.S
index fb5e72b532b0..5f1e045a3ad1 100644
--- a/arch/arm/mach-davinci/sleep.S
+++ b/arch/arm/mach-davinci/sleep.S
@@ -217,7 +217,11 @@ ddr2clk_stop_done:
ENDPROC(davinci_ddr_psc_config)
CACHE_FLUSH:
- .word arm926_flush_kern_cache_all
+#ifdef CONFIG_CPU_V6
+ .word v6_flush_kern_cache_all
+#else
+ .word arm926_flush_kern_cache_all
+#endif
ENTRY(davinci_cpu_suspend_sz)
.word . - davinci_cpu_suspend
diff --git a/arch/arm/mach-dove/Makefile.boot b/arch/arm/mach-dove/Makefile.boot
index 67039c3e0c48..760a0efe7580 100644
--- a/arch/arm/mach-dove/Makefile.boot
+++ b/arch/arm/mach-dove/Makefile.boot
@@ -1,3 +1,3 @@
- zreladdr-y := 0x00008000
+ zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c
index 83dce859886d..a9e0dae86a26 100644
--- a/arch/arm/mach-dove/common.c
+++ b/arch/arm/mach-dove/common.c
@@ -158,7 +158,7 @@ void __init dove_spi0_init(void)
void __init dove_spi1_init(void)
{
- orion_spi_init(DOVE_SPI1_PHYS_BASE, get_tclk());
+ orion_spi_1_init(DOVE_SPI1_PHYS_BASE, get_tclk());
}
/*****************************************************************************
diff --git a/arch/arm/mach-ebsa110/Makefile.boot b/arch/arm/mach-ebsa110/Makefile.boot
index 232126044935..83cf07c38ada 100644
--- a/arch/arm/mach-ebsa110/Makefile.boot
+++ b/arch/arm/mach-ebsa110/Makefile.boot
@@ -1,4 +1,4 @@
- zreladdr-y := 0x00008000
+ zreladdr-y += 0x00008000
params_phys-y := 0x00000400
initrd_phys-y := 0x00800000
diff --git a/arch/arm/mach-ebsa110/include/mach/io.h b/arch/arm/mach-ebsa110/include/mach/io.h
index f68daa632af0..44679db672fb 100644
--- a/arch/arm/mach-ebsa110/include/mach/io.h
+++ b/arch/arm/mach-ebsa110/include/mach/io.h
@@ -13,8 +13,6 @@
#ifndef __ASM_ARM_ARCH_IO_H
#define __ASM_ARM_ARCH_IO_H
-#define IO_SPACE_LIMIT 0xffff
-
u8 __inb8(unsigned int port);
void __outb8(u8 val, unsigned int port);
diff --git a/arch/arm/mach-ep93xx/Makefile.boot b/arch/arm/mach-ep93xx/Makefile.boot
index 0ad33f15c622..d3113a71cb40 100644
--- a/arch/arm/mach-ep93xx/Makefile.boot
+++ b/arch/arm/mach-ep93xx/Makefile.boot
@@ -1,14 +1,14 @@
- zreladdr-$(CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET) := 0x00008000
+ zreladdr-$(CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET) += 0x00008000
params_phys-$(CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET) := 0x00000100
- zreladdr-$(CONFIG_EP93XX_SDCE0_PHYS_OFFSET) := 0xc0008000
+ zreladdr-$(CONFIG_EP93XX_SDCE0_PHYS_OFFSET) += 0xc0008000
params_phys-$(CONFIG_EP93XX_SDCE0_PHYS_OFFSET) := 0xc0000100
- zreladdr-$(CONFIG_EP93XX_SDCE1_PHYS_OFFSET) := 0xd0008000
+ zreladdr-$(CONFIG_EP93XX_SDCE1_PHYS_OFFSET) += 0xd0008000
params_phys-$(CONFIG_EP93XX_SDCE1_PHYS_OFFSET) := 0xd0000100
- zreladdr-$(CONFIG_EP93XX_SDCE2_PHYS_OFFSET) := 0xe0008000
+ zreladdr-$(CONFIG_EP93XX_SDCE2_PHYS_OFFSET) += 0xe0008000
params_phys-$(CONFIG_EP93XX_SDCE2_PHYS_OFFSET) := 0xe0000100
- zreladdr-$(CONFIG_EP93XX_SDCE3_ASYNC_PHYS_OFFSET) := 0xf0008000
+ zreladdr-$(CONFIG_EP93XX_SDCE3_ASYNC_PHYS_OFFSET) += 0xf0008000
params_phys-$(CONFIG_EP93XX_SDCE3_ASYNC_PHYS_OFFSET) := 0xf0000100
diff --git a/arch/arm/mach-ep93xx/include/mach/ts72xx.h b/arch/arm/mach-ep93xx/include/mach/ts72xx.h
index 0eabec62cd9d..f1397a13e76b 100644
--- a/arch/arm/mach-ep93xx/include/mach/ts72xx.h
+++ b/arch/arm/mach-ep93xx/include/mach/ts72xx.h
@@ -6,7 +6,7 @@
* TS72xx memory map:
*
* virt phys size
- * febff000 22000000 4K model number register
+ * febff000 22000000 4K model number register (bits 0-2)
* febfe000 22400000 4K options register
* febfd000 22800000 4K options register #2
* febf9000 10800000 4K TS-5620 RTC index register
@@ -20,6 +20,9 @@
#define TS72XX_MODEL_TS7200 0x00
#define TS72XX_MODEL_TS7250 0x01
#define TS72XX_MODEL_TS7260 0x02
+#define TS72XX_MODEL_TS7300 0x03
+#define TS72XX_MODEL_TS7400 0x04
+#define TS72XX_MODEL_MASK 0x07
#define TS72XX_OPTIONS_PHYS_BASE 0x22400000
@@ -51,19 +54,34 @@
#ifndef __ASSEMBLY__
+static inline int ts72xx_model(void)
+{
+ return __raw_readb(TS72XX_MODEL_VIRT_BASE) & TS72XX_MODEL_MASK;
+}
+
static inline int board_is_ts7200(void)
{
- return __raw_readb(TS72XX_MODEL_VIRT_BASE) == TS72XX_MODEL_TS7200;
+ return ts72xx_model() == TS72XX_MODEL_TS7200;
}
static inline int board_is_ts7250(void)
{
- return __raw_readb(TS72XX_MODEL_VIRT_BASE) == TS72XX_MODEL_TS7250;
+ return ts72xx_model() == TS72XX_MODEL_TS7250;
}
static inline int board_is_ts7260(void)
{
- return __raw_readb(TS72XX_MODEL_VIRT_BASE) == TS72XX_MODEL_TS7260;
+ return ts72xx_model() == TS72XX_MODEL_TS7260;
+}
+
+static inline int board_is_ts7300(void)
+{
+ return ts72xx_model() == TS72XX_MODEL_TS7300;
+}
+
+static inline int board_is_ts7400(void)
+{
+ return ts72xx_model() == TS72XX_MODEL_TS7400;
}
static inline int is_max197_installed(void)
diff --git a/arch/arm/mach-exynos4/Kconfig b/arch/arm/mach-exynos4/Kconfig
index 0c77ab99fa16..fc1f92dfbea8 100644
--- a/arch/arm/mach-exynos4/Kconfig
+++ b/arch/arm/mach-exynos4/Kconfig
@@ -12,6 +12,7 @@ if ARCH_EXYNOS4
config CPU_EXYNOS4210
bool
select S3C_PL330_DMA
+ select ARM_CPU_SUSPEND if PM
help
Enable EXYNOS4210 CPU support
diff --git a/arch/arm/mach-exynos4/Makefile.boot b/arch/arm/mach-exynos4/Makefile.boot
index d65956ffb43d..b9862e22bf10 100644
--- a/arch/arm/mach-exynos4/Makefile.boot
+++ b/arch/arm/mach-exynos4/Makefile.boot
@@ -1,2 +1,2 @@
- zreladdr-y := 0x40008000
+ zreladdr-y += 0x40008000
params_phys-y := 0x40000100
diff --git a/arch/arm/mach-exynos4/clock.c b/arch/arm/mach-exynos4/clock.c
index 851dea018578..86964d2e9e1b 100644
--- a/arch/arm/mach-exynos4/clock.c
+++ b/arch/arm/mach-exynos4/clock.c
@@ -520,7 +520,7 @@ static struct clk init_clocks_off[] = {
.ctrlbit = (1 << 21),
}, {
.name = "ac97",
- .id = -1,
+ .devname = "samsung-ac97",
.enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 27),
}, {
@@ -899,8 +899,7 @@ static struct clksrc_clk clksrcs[] = {
.reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 28, .size = 4 },
}, {
.clk = {
- .name = "sclk_cam",
- .devname = "exynos4-fimc.0",
+ .name = "sclk_cam0",
.enable = exynos4_clksrc_mask_cam_ctrl,
.ctrlbit = (1 << 16),
},
@@ -909,8 +908,7 @@ static struct clksrc_clk clksrcs[] = {
.reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 16, .size = 4 },
}, {
.clk = {
- .name = "sclk_cam",
- .devname = "exynos4-fimc.1",
+ .name = "sclk_cam1",
.enable = exynos4_clksrc_mask_cam_ctrl,
.ctrlbit = (1 << 20),
},
@@ -1160,7 +1158,7 @@ void __init_or_cpufreq exynos4_setup_clocks(void)
vpllsrc = clk_get_rate(&clk_vpllsrc.clk);
vpll = s5p_get_pll46xx(vpllsrc, __raw_readl(S5P_VPLL_CON0),
- __raw_readl(S5P_VPLL_CON1), pll_4650);
+ __raw_readl(S5P_VPLL_CON1), pll_4650c);
clk_fout_apll.ops = &exynos4_fout_apll_ops;
clk_fout_mpll.rate = mpll;
diff --git a/arch/arm/mach-exynos4/cpu.c b/arch/arm/mach-exynos4/cpu.c
index 2d8a40c9e6e5..746d6fc6d397 100644
--- a/arch/arm/mach-exynos4/cpu.c
+++ b/arch/arm/mach-exynos4/cpu.c
@@ -24,12 +24,13 @@
#include <plat/exynos4.h>
#include <plat/adc-core.h>
#include <plat/sdhci.h>
-#include <plat/devs.h>
#include <plat/fb-core.h>
#include <plat/fimc-core.h>
#include <plat/iic-core.h>
+#include <plat/reset.h>
#include <mach/regs-irq.h>
+#include <mach/regs-pmu.h>
extern int combiner_init(unsigned int combiner_nr, void __iomem *base,
unsigned int irq_start);
@@ -128,6 +129,11 @@ static void exynos4_idle(void)
local_irq_enable();
}
+static void exynos4_sw_reset(void)
+{
+ __raw_writel(0x1, S5P_SWRESET);
+}
+
/*
* exynos4_map_io
*
@@ -241,5 +247,8 @@ int __init exynos4_init(void)
/* set idle function */
pm_idle = exynos4_idle;
+ /* set sw_reset function */
+ s5p_reset_hook = exynos4_sw_reset;
+
return sysdev_register(&exynos4_sysdev);
}
diff --git a/arch/arm/mach-exynos4/include/mach/irqs.h b/arch/arm/mach-exynos4/include/mach/irqs.h
index 934d2a493982..f8952f8f3757 100644
--- a/arch/arm/mach-exynos4/include/mach/irqs.h
+++ b/arch/arm/mach-exynos4/include/mach/irqs.h
@@ -80,9 +80,8 @@
#define IRQ_HSMMC3 IRQ_SPI(76)
#define IRQ_DWMCI IRQ_SPI(77)
-#define IRQ_MIPICSI0 IRQ_SPI(78)
-
-#define IRQ_MIPICSI1 IRQ_SPI(80)
+#define IRQ_MIPI_CSIS0 IRQ_SPI(78)
+#define IRQ_MIPI_CSIS1 IRQ_SPI(80)
#define IRQ_ONENAND_AUDI IRQ_SPI(82)
#define IRQ_ROTATOR IRQ_SPI(83)
diff --git a/arch/arm/mach-exynos4/include/mach/regs-pmu.h b/arch/arm/mach-exynos4/include/mach/regs-pmu.h
index fa49bbb8e7b0..cdf9b47c303c 100644
--- a/arch/arm/mach-exynos4/include/mach/regs-pmu.h
+++ b/arch/arm/mach-exynos4/include/mach/regs-pmu.h
@@ -29,6 +29,8 @@
#define S5P_USE_STANDBY_WFE1 (1 << 25)
#define S5P_USE_MASK ((0x3 << 16) | (0x3 << 24))
+#define S5P_SWRESET S5P_PMUREG(0x0400)
+
#define S5P_WAKEUP_STAT S5P_PMUREG(0x0600)
#define S5P_EINT_WAKEUP_MASK S5P_PMUREG(0x0604)
#define S5P_WAKEUP_MASK S5P_PMUREG(0x0608)
diff --git a/arch/arm/mach-exynos4/irq-eint.c b/arch/arm/mach-exynos4/irq-eint.c
index 9d87d2ac7f68..badb8c66fc9b 100644
--- a/arch/arm/mach-exynos4/irq-eint.c
+++ b/arch/arm/mach-exynos4/irq-eint.c
@@ -23,6 +23,8 @@
#include <mach/regs-gpio.h>
+#include <asm/mach/irq.h>
+
static DEFINE_SPINLOCK(eint_lock);
static unsigned int eint0_15_data[16];
@@ -184,8 +186,11 @@ static inline void exynos4_irq_demux_eint(unsigned int start)
static void exynos4_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = irq_get_chip(irq);
+ chained_irq_enter(chip, desc);
exynos4_irq_demux_eint(IRQ_EINT(16));
exynos4_irq_demux_eint(IRQ_EINT(24));
+ chained_irq_exit(chip, desc);
}
static void exynos4_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
@@ -193,6 +198,7 @@ static void exynos4_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
u32 *irq_data = irq_get_handler_data(irq);
struct irq_chip *chip = irq_get_chip(irq);
+ chained_irq_enter(chip, desc);
chip->irq_mask(&desc->irq_data);
if (chip->irq_ack)
@@ -201,6 +207,7 @@ static void exynos4_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
generic_handle_irq(*irq_data);
chip->irq_unmask(&desc->irq_data);
+ chained_irq_exit(chip, desc);
}
int __init exynos4_init_irq_eint(void)
diff --git a/arch/arm/mach-exynos4/mach-universal_c210.c b/arch/arm/mach-exynos4/mach-universal_c210.c
index 0e280d12301e..b3b5d8911004 100644
--- a/arch/arm/mach-exynos4/mach-universal_c210.c
+++ b/arch/arm/mach-exynos4/mach-universal_c210.c
@@ -79,7 +79,7 @@ static struct s3c2410_uartcfg universal_uartcfgs[] __initdata = {
};
static struct regulator_consumer_supply max8952_consumer =
- REGULATOR_SUPPLY("vddarm", NULL);
+ REGULATOR_SUPPLY("vdd_arm", NULL);
static struct max8952_platform_data universal_max8952_pdata __initdata = {
.gpio_vid0 = EXYNOS4_GPX0(3),
@@ -105,7 +105,7 @@ static struct max8952_platform_data universal_max8952_pdata __initdata = {
};
static struct regulator_consumer_supply lp3974_buck1_consumer =
- REGULATOR_SUPPLY("vddint", NULL);
+ REGULATOR_SUPPLY("vdd_int", NULL);
static struct regulator_consumer_supply lp3974_buck2_consumer =
REGULATOR_SUPPLY("vddg3d", NULL);
diff --git a/arch/arm/mach-exynos4/mct.c b/arch/arm/mach-exynos4/mct.c
index 1ae059b7ad7b..ddd86864fb83 100644
--- a/arch/arm/mach-exynos4/mct.c
+++ b/arch/arm/mach-exynos4/mct.c
@@ -132,12 +132,18 @@ static cycle_t exynos4_frc_read(struct clocksource *cs)
return ((cycle_t)hi << 32) | lo;
}
+static void exynos4_frc_resume(struct clocksource *cs)
+{
+ exynos4_mct_frc_start(0, 0);
+}
+
struct clocksource mct_frc = {
.name = "mct-frc",
.rating = 400,
.read = exynos4_frc_read,
.mask = CLOCKSOURCE_MASK(64),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .resume = exynos4_frc_resume,
};
static void __init exynos4_clocksource_init(void)
@@ -389,9 +395,11 @@ static void exynos4_mct_tick_init(struct clock_event_device *evt)
}
/* Setup the local clock events for a CPU */
-void __cpuinit local_timer_setup(struct clock_event_device *evt)
+int __cpuinit local_timer_setup(struct clock_event_device *evt)
{
exynos4_mct_tick_init(evt);
+
+ return 0;
}
int local_timer_ack(void)
diff --git a/arch/arm/mach-exynos4/platsmp.c b/arch/arm/mach-exynos4/platsmp.c
index 7c2282c6ba81..0c90896ad9a0 100644
--- a/arch/arm/mach-exynos4/platsmp.c
+++ b/arch/arm/mach-exynos4/platsmp.c
@@ -106,6 +106,8 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
*/
spin_lock(&boot_lock);
spin_unlock(&boot_lock);
+
+ set_cpu_online(cpu, true);
}
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
@@ -191,12 +193,10 @@ void __init smp_init_cpus(void)
ncores = scu_base ? scu_get_core_count(scu_base) : 1;
/* sanity check */
- if (ncores > NR_CPUS) {
- printk(KERN_WARNING
- "EXYNOS4: no. of cores (%d) greater than configured "
- "maximum of %d - clipping\n",
- ncores, NR_CPUS);
- ncores = NR_CPUS;
+ if (ncores > nr_cpu_ids) {
+ pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
+ ncores, nr_cpu_ids);
+ ncores = nr_cpu_ids;
}
for (i = 0; i < ncores; i++)
diff --git a/arch/arm/mach-exynos4/setup-keypad.c b/arch/arm/mach-exynos4/setup-keypad.c
index 1ee0ebff111f..7862bfb5933d 100644
--- a/arch/arm/mach-exynos4/setup-keypad.c
+++ b/arch/arm/mach-exynos4/setup-keypad.c
@@ -19,15 +19,16 @@ void samsung_keypad_cfg_gpio(unsigned int rows, unsigned int cols)
if (rows > 8) {
/* Set all the necessary GPX2 pins: KP_ROW[0~7] */
- s3c_gpio_cfgrange_nopull(EXYNOS4_GPX2(0), 8, S3C_GPIO_SFN(3));
+ s3c_gpio_cfgall_range(EXYNOS4_GPX2(0), 8, S3C_GPIO_SFN(3),
+ S3C_GPIO_PULL_UP);
/* Set all the necessary GPX3 pins: KP_ROW[8~] */
- s3c_gpio_cfgrange_nopull(EXYNOS4_GPX3(0), (rows - 8),
- S3C_GPIO_SFN(3));
+ s3c_gpio_cfgall_range(EXYNOS4_GPX3(0), (rows - 8),
+ S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
} else {
/* Set all the necessary GPX2 pins: KP_ROW[x] */
- s3c_gpio_cfgrange_nopull(EXYNOS4_GPX2(0), rows,
- S3C_GPIO_SFN(3));
+ s3c_gpio_cfgall_range(EXYNOS4_GPX2(0), rows, S3C_GPIO_SFN(3),
+ S3C_GPIO_PULL_UP);
}
/* Set all the necessary GPX1 pins to special-function 3: KP_COL[x] */
diff --git a/arch/arm/mach-exynos4/setup-usb-phy.c b/arch/arm/mach-exynos4/setup-usb-phy.c
index 0883c1b824b9..39aca045f660 100644
--- a/arch/arm/mach-exynos4/setup-usb-phy.c
+++ b/arch/arm/mach-exynos4/setup-usb-phy.c
@@ -82,7 +82,7 @@ static int exynos4_usb_phy1_init(struct platform_device *pdev)
rstcon &= ~(HOST_LINK_PORT_SWRST_MASK | PHY1_SWRST_MASK);
writel(rstcon, EXYNOS4_RSTCON);
- udelay(50);
+ udelay(80);
clk_disable(otg_clk);
clk_put(otg_clk);
diff --git a/arch/arm/mach-footbridge/Kconfig b/arch/arm/mach-footbridge/Kconfig
index dc26fff22cf0..f643ef819da6 100644
--- a/arch/arm/mach-footbridge/Kconfig
+++ b/arch/arm/mach-footbridge/Kconfig
@@ -4,8 +4,8 @@ menu "Footbridge Implementations"
config ARCH_CATS
bool "CATS"
- select CLKSRC_I8253
select CLKEVT_I8253
+ select CLKSRC_I8253
select FOOTBRIDGE_HOST
select ISA
select ISA_DMA
@@ -61,6 +61,7 @@ config ARCH_EBSA285_HOST
config ARCH_NETWINDER
bool "NetWinder"
+ select CLKEVT_I8253
select CLKSRC_I8253
select FOOTBRIDGE_HOST
select ISA
diff --git a/arch/arm/mach-footbridge/Makefile.boot b/arch/arm/mach-footbridge/Makefile.boot
index c7e75acfe6c9..ff0a4b5b0a82 100644
--- a/arch/arm/mach-footbridge/Makefile.boot
+++ b/arch/arm/mach-footbridge/Makefile.boot
@@ -1,4 +1,4 @@
- zreladdr-y := 0x00008000
+ zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
diff --git a/arch/arm/mach-footbridge/cats-hw.c b/arch/arm/mach-footbridge/cats-hw.c
index 5b1a8db779be..206ff2f39d6c 100644
--- a/arch/arm/mach-footbridge/cats-hw.c
+++ b/arch/arm/mach-footbridge/cats-hw.c
@@ -76,8 +76,7 @@ __initcall(cats_hw_init);
* hard reboots fail on early boards.
*/
static void __init
-fixup_cats(struct machine_desc *desc, struct tag *tags,
- char **cmdline, struct meminfo *mi)
+fixup_cats(struct tag *tags, char **cmdline, struct meminfo *mi)
{
screen_info.orig_video_lines = 25;
screen_info.orig_video_points = 16;
diff --git a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c
index 1331fff51ae2..18c32a5541d9 100644
--- a/arch/arm/mach-footbridge/dc21285.c
+++ b/arch/arm/mach-footbridge/dc21285.c
@@ -18,6 +18,7 @@
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/spinlock.h>
+#include <video/vga.h>
#include <asm/irq.h>
#include <asm/system.h>
diff --git a/arch/arm/mach-footbridge/include/mach/io.h b/arch/arm/mach-footbridge/include/mach/io.h
index 32e4cc397c28..15a70396c27d 100644
--- a/arch/arm/mach-footbridge/include/mach/io.h
+++ b/arch/arm/mach-footbridge/include/mach/io.h
@@ -23,8 +23,6 @@
#define PCIO_SIZE 0x00100000
#define PCIO_BASE MMU_IO(0xff000000, 0x7c000000)
-#define IO_SPACE_LIMIT 0xffff
-
/*
* Translation of various region addresses to virtual addresses
*/
diff --git a/arch/arm/mach-footbridge/netwinder-hw.c b/arch/arm/mach-footbridge/netwinder-hw.c
index 06e514f372d0..4cbc2e65ce3a 100644
--- a/arch/arm/mach-footbridge/netwinder-hw.c
+++ b/arch/arm/mach-footbridge/netwinder-hw.c
@@ -631,8 +631,7 @@ __initcall(nw_hw_init);
* the parameter page.
*/
static void __init
-fixup_netwinder(struct machine_desc *desc, struct tag *tags,
- char **cmdline, struct meminfo *mi)
+fixup_netwinder(struct tag *tags, char **cmdline, struct meminfo *mi)
{
#ifdef CONFIG_ISAPNP
extern int isapnp_disable;
diff --git a/arch/arm/mach-gemini/Makefile.boot b/arch/arm/mach-gemini/Makefile.boot
index 22a52c228d93..683f52b20e3d 100644
--- a/arch/arm/mach-gemini/Makefile.boot
+++ b/arch/arm/mach-gemini/Makefile.boot
@@ -1,9 +1,9 @@
ifeq ($(CONFIG_GEMINI_MEM_SWAP),y)
- zreladdr-y := 0x00008000
+ zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
else
- zreladdr-y := 0x10008000
+ zreladdr-y += 0x10008000
params_phys-y := 0x10000100
initrd_phys-y := 0x10800000
endif
diff --git a/arch/arm/mach-h720x/Makefile.boot b/arch/arm/mach-h720x/Makefile.boot
index 52984017bd91..d875a7094dfe 100644
--- a/arch/arm/mach-h720x/Makefile.boot
+++ b/arch/arm/mach-h720x/Makefile.boot
@@ -1,2 +1,2 @@
- zreladdr-$(CONFIG_ARCH_H720X) := 0x40008000
+ zreladdr-$(CONFIG_ARCH_H720X) += 0x40008000
diff --git a/arch/arm/mach-imx/Makefile.boot b/arch/arm/mach-imx/Makefile.boot
index ebee18b3884c..dbe61201bcd8 100644
--- a/arch/arm/mach-imx/Makefile.boot
+++ b/arch/arm/mach-imx/Makefile.boot
@@ -1,19 +1,19 @@
-zreladdr-$(CONFIG_ARCH_MX1) := 0x08008000
+zreladdr-$(CONFIG_ARCH_MX1) += 0x08008000
params_phys-$(CONFIG_ARCH_MX1) := 0x08000100
initrd_phys-$(CONFIG_ARCH_MX1) := 0x08800000
-zreladdr-$(CONFIG_MACH_MX21) := 0xC0008000
+zreladdr-$(CONFIG_MACH_MX21) += 0xC0008000
params_phys-$(CONFIG_MACH_MX21) := 0xC0000100
initrd_phys-$(CONFIG_MACH_MX21) := 0xC0800000
-zreladdr-$(CONFIG_ARCH_MX25) := 0x80008000
+zreladdr-$(CONFIG_ARCH_MX25) += 0x80008000
params_phys-$(CONFIG_ARCH_MX25) := 0x80000100
initrd_phys-$(CONFIG_ARCH_MX25) := 0x80800000
-zreladdr-$(CONFIG_MACH_MX27) := 0xA0008000
+zreladdr-$(CONFIG_MACH_MX27) += 0xA0008000
params_phys-$(CONFIG_MACH_MX27) := 0xA0000100
initrd_phys-$(CONFIG_MACH_MX27) := 0xA0800000
-zreladdr-$(CONFIG_ARCH_MX3) := 0x80008000
+zreladdr-$(CONFIG_ARCH_MX3) += 0x80008000
params_phys-$(CONFIG_ARCH_MX3) := 0x80000100
initrd_phys-$(CONFIG_ARCH_MX3) := 0x80800000
diff --git a/arch/arm/mach-imx/mach-cpuimx27.c b/arch/arm/mach-imx/mach-cpuimx27.c
index 87887ac5806b..f851fe903687 100644
--- a/arch/arm/mach-imx/mach-cpuimx27.c
+++ b/arch/arm/mach-imx/mach-cpuimx27.c
@@ -310,7 +310,7 @@ static struct sys_timer eukrea_cpuimx27_timer = {
.init = eukrea_cpuimx27_timer_init,
};
-MACHINE_START(CPUIMX27, "EUKREA CPUIMX27")
+MACHINE_START(EUKREA_CPUIMX27, "EUKREA CPUIMX27")
.boot_params = MX27_PHYS_OFFSET + 0x100,
.map_io = mx27_map_io,
.init_early = imx27_init_early,
diff --git a/arch/arm/mach-imx/mach-cpuimx35.c b/arch/arm/mach-imx/mach-cpuimx35.c
index f39a478ba1a6..4bd083ba9af2 100644
--- a/arch/arm/mach-imx/mach-cpuimx35.c
+++ b/arch/arm/mach-imx/mach-cpuimx35.c
@@ -192,7 +192,7 @@ struct sys_timer eukrea_cpuimx35_timer = {
.init = eukrea_cpuimx35_timer_init,
};
-MACHINE_START(EUKREA_CPUIMX35, "Eukrea CPUIMX35")
+MACHINE_START(EUKREA_CPUIMX35SD, "Eukrea CPUIMX35")
/* Maintainer: Eukrea Electromatique */
.boot_params = MX3x_PHYS_OFFSET + 0x100,
.map_io = mx35_map_io,
diff --git a/arch/arm/mach-imx/mach-eukrea_cpuimx25.c b/arch/arm/mach-imx/mach-eukrea_cpuimx25.c
index da36da52969d..2442d5da883d 100644
--- a/arch/arm/mach-imx/mach-eukrea_cpuimx25.c
+++ b/arch/arm/mach-imx/mach-eukrea_cpuimx25.c
@@ -161,7 +161,7 @@ static struct sys_timer eukrea_cpuimx25_timer = {
.init = eukrea_cpuimx25_timer_init,
};
-MACHINE_START(EUKREA_CPUIMX25, "Eukrea CPUIMX25")
+MACHINE_START(EUKREA_CPUIMX25SD, "Eukrea CPUIMX25")
/* Maintainer: Eukrea Electromatique */
.boot_params = MX25_PHYS_OFFSET + 0x100,
.map_io = mx25_map_io,
diff --git a/arch/arm/mach-integrator/Makefile.boot b/arch/arm/mach-integrator/Makefile.boot
index c7e75acfe6c9..ff0a4b5b0a82 100644
--- a/arch/arm/mach-integrator/Makefile.boot
+++ b/arch/arm/mach-integrator/Makefile.boot
@@ -1,4 +1,4 @@
- zreladdr-y := 0x00008000
+ zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c
index 77315b995681..82ebc8d772d3 100644
--- a/arch/arm/mach-integrator/core.c
+++ b/arch/arm/mach-integrator/core.c
@@ -126,6 +126,10 @@ static struct clk_lookup lookups[] = {
{ /* Bus clock */
.con_id = "apb_pclk",
.clk = &dummy_apb_pclk,
+ }, {
+ /* Integrator/AP timer frequency */
+ .dev_id = "ap_timer",
+ .clk = &clk24mhz,
}, { /* UART0 */
.dev_id = "mb:16",
.clk = &uartclk,
diff --git a/arch/arm/mach-integrator/include/mach/io.h b/arch/arm/mach-integrator/include/mach/io.h
index f21bb5493dd9..37beed3fa3ed 100644
--- a/arch/arm/mach-integrator/include/mach/io.h
+++ b/arch/arm/mach-integrator/include/mach/io.h
@@ -20,8 +20,6 @@
#ifndef __ASM_ARM_ARCH_IO_H
#define __ASM_ARM_ARCH_IO_H
-#define IO_SPACE_LIMIT 0xffff
-
/*
* WARNING: this has to mirror definitions in platform.h
*/
diff --git a/arch/arm/mach-integrator/include/mach/platform.h b/arch/arm/mach-integrator/include/mach/platform.h
index 5e6ea5cfea6e..ec467baade09 100644
--- a/arch/arm/mach-integrator/include/mach/platform.h
+++ b/arch/arm/mach-integrator/include/mach/platform.h
@@ -13,9 +13,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-/* DO NOT EDIT!! - this file automatically generated
- * from .s file by awk -f s2h.awk
- */
/**************************************************************************
* * Copyright © ARM Limited 1998. All rights reserved.
* ***********************************************************************/
@@ -399,15 +396,6 @@
#define INTEGRATOR_TIMER1_BASE (INTEGRATOR_CT_BASE + 0x100)
#define INTEGRATOR_TIMER2_BASE (INTEGRATOR_CT_BASE + 0x200)
-#define TICKS_PER_uSEC 24
-
-/*
- * These are useconds NOT ticks.
- *
- */
-#define mSEC_1 1000
-#define mSEC_10 (mSEC_1 * 10)
-
#define INTEGRATOR_CSR_BASE 0x10000000
#define INTEGRATOR_CSR_SIZE 0x10000000
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index 2fbbdd5eac35..f2119908a0b3 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -32,6 +32,8 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/mtd/physmap.h>
+#include <linux/clk.h>
+#include <video/vga.h>
#include <mach/hardware.h>
#include <mach/platform.h>
@@ -154,6 +156,7 @@ static struct map_desc ap_io_desc[] __initdata = {
static void __init ap_map_io(void)
{
iotable_init(ap_io_desc, ARRAY_SIZE(ap_io_desc));
+ vga_base = PCI_MEMORY_VADDR;
}
#define INTEGRATOR_SC_VALID_INT 0x003fffff
@@ -320,35 +323,24 @@ static void __init ap_init(void)
#define TIMER1_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER1_BASE)
#define TIMER2_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER2_BASE)
-/*
- * How long is the timer interval?
- */
-#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10)
-#if TIMER_INTERVAL >= 0x100000
-#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC)
-#elif TIMER_INTERVAL >= 0x10000
-#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC)
-#else
-#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
-#endif
-
static unsigned long timer_reload;
-static void integrator_clocksource_init(u32 khz)
+static void integrator_clocksource_init(unsigned long inrate)
{
void __iomem *base = (void __iomem *)TIMER2_VA_BASE;
- u32 ctrl = TIMER_CTRL_ENABLE;
+ u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
+ unsigned long rate = inrate;
- if (khz >= 1500) {
- khz /= 16;
- ctrl = TIMER_CTRL_DIV16;
+ if (rate >= 1500000) {
+ rate /= 16;
+ ctrl |= TIMER_CTRL_DIV16;
}
- writel(ctrl, base + TIMER_CTRL);
writel(0xffff, base + TIMER_LOAD);
+ writel(ctrl, base + TIMER_CTRL);
clocksource_mmio_init(base + TIMER_VALUE, "timer2",
- khz * 1000, 200, 16, clocksource_mmio_readl_down);
+ rate, 200, 16, clocksource_mmio_readl_down);
}
static void __iomem * const clkevt_base = (void __iomem *)TIMER1_VA_BASE;
@@ -372,15 +364,29 @@ static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_devic
{
u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
- BUG_ON(mode == CLOCK_EVT_MODE_ONESHOT);
+ /* Disable timer */
+ writel(ctrl, clkevt_base + TIMER_CTRL);
- if (mode == CLOCK_EVT_MODE_PERIODIC) {
- writel(ctrl, clkevt_base + TIMER_CTRL);
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ /* Enable the timer and start the periodic tick */
writel(timer_reload, clkevt_base + TIMER_LOAD);
ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
+ writel(ctrl, clkevt_base + TIMER_CTRL);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* Leave the timer disabled, .set_next_event will enable it */
+ ctrl &= ~TIMER_CTRL_PERIODIC;
+ writel(ctrl, clkevt_base + TIMER_CTRL);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_RESUME:
+ default:
+ /* Just leave in disabled state */
+ break;
}
- writel(ctrl, clkevt_base + TIMER_CTRL);
}
static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)
@@ -396,12 +402,10 @@ static int clkevt_set_next_event(unsigned long next, struct clock_event_device *
static struct clock_event_device integrator_clockevent = {
.name = "timer1",
- .shift = 34,
- .features = CLOCK_EVT_FEAT_PERIODIC,
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.set_mode = clkevt_set_mode,
.set_next_event = clkevt_set_next_event,
.rating = 300,
- .cpumask = cpu_all_mask,
};
static struct irqaction integrator_timer_irq = {
@@ -411,29 +415,27 @@ static struct irqaction integrator_timer_irq = {
.dev_id = &integrator_clockevent,
};
-static void integrator_clockevent_init(u32 khz)
+static void integrator_clockevent_init(unsigned long inrate)
{
- struct clock_event_device *evt = &integrator_clockevent;
+ unsigned long rate = inrate;
unsigned int ctrl = 0;
- if (khz * 1000 > 0x100000 * HZ) {
- khz /= 256;
+ /* Calculate and program a divisor */
+ if (rate > 0x100000 * HZ) {
+ rate /= 256;
ctrl |= TIMER_CTRL_DIV256;
- } else if (khz * 1000 > 0x10000 * HZ) {
- khz /= 16;
+ } else if (rate > 0x10000 * HZ) {
+ rate /= 16;
ctrl |= TIMER_CTRL_DIV16;
}
-
- timer_reload = khz * 1000 / HZ;
+ timer_reload = rate / HZ;
writel(ctrl, clkevt_base + TIMER_CTRL);
- evt->irq = IRQ_TIMERINT1;
- evt->mult = div_sc(khz, NSEC_PER_MSEC, evt->shift);
- evt->max_delta_ns = clockevent_delta2ns(0xffff, evt);
- evt->min_delta_ns = clockevent_delta2ns(0xf, evt);
-
setup_irq(IRQ_TIMERINT1, &integrator_timer_irq);
- clockevents_register_device(evt);
+ clockevents_config_and_register(&integrator_clockevent,
+ rate,
+ 1,
+ 0xffffU);
}
/*
@@ -441,14 +443,20 @@ static void integrator_clockevent_init(u32 khz)
*/
static void __init ap_init_timer(void)
{
- u32 khz = TICKS_PER_uSEC * 1000;
+ struct clk *clk;
+ unsigned long rate;
+
+ clk = clk_get_sys("ap_timer", NULL);
+ BUG_ON(IS_ERR(clk));
+ clk_enable(clk);
+ rate = clk_get_rate(clk);
writel(0, TIMER0_VA_BASE + TIMER_CTRL);
writel(0, TIMER1_VA_BASE + TIMER_CTRL);
writel(0, TIMER2_VA_BASE + TIMER_CTRL);
- integrator_clocksource_init(khz);
- integrator_clockevent_init(khz);
+ integrator_clocksource_init(rate);
+ integrator_clockevent_init(rate);
}
static struct sys_timer ap_timer = {
diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c
index dd56bfb351e3..11b86e5b71c2 100644
--- a/arch/arm/mach-integrator/pci_v3.c
+++ b/arch/arm/mach-integrator/pci_v3.c
@@ -27,7 +27,6 @@
#include <linux/spinlock.h>
#include <linux/init.h>
#include <linux/io.h>
-#include <video/vga.h>
#include <mach/hardware.h>
#include <mach/platform.h>
@@ -505,7 +504,6 @@ void __init pci_v3_preinit(void)
pcibios_min_io = 0x6000;
pcibios_min_mem = 0x00100000;
- vga_base = PCI_MEMORY_VADDR;
/*
* Hook in our fault handler for PCI errors
diff --git a/arch/arm/mach-iop13xx/Makefile.boot b/arch/arm/mach-iop13xx/Makefile.boot
index 0b0e19fdfe6c..3a8c38c3189c 100644
--- a/arch/arm/mach-iop13xx/Makefile.boot
+++ b/arch/arm/mach-iop13xx/Makefile.boot
@@ -1,3 +1,3 @@
- zreladdr-y := 0x00008000
+ zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
diff --git a/arch/arm/mach-iop32x/Makefile.boot b/arch/arm/mach-iop32x/Makefile.boot
index 47000dccd61f..0a833b11e38c 100644
--- a/arch/arm/mach-iop32x/Makefile.boot
+++ b/arch/arm/mach-iop32x/Makefile.boot
@@ -1,3 +1,3 @@
- zreladdr-y := 0xa0008000
+ zreladdr-y += 0xa0008000
params_phys-y := 0xa0000100
initrd_phys-y := 0xa0800000
diff --git a/arch/arm/mach-iop33x/Makefile.boot b/arch/arm/mach-iop33x/Makefile.boot
index 67039c3e0c48..760a0efe7580 100644
--- a/arch/arm/mach-iop33x/Makefile.boot
+++ b/arch/arm/mach-iop33x/Makefile.boot
@@ -1,3 +1,3 @@
- zreladdr-y := 0x00008000
+ zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
diff --git a/arch/arm/mach-ixp2000/Makefile.boot b/arch/arm/mach-ixp2000/Makefile.boot
index d84c5807a43d..9c7af91d93da 100644
--- a/arch/arm/mach-ixp2000/Makefile.boot
+++ b/arch/arm/mach-ixp2000/Makefile.boot
@@ -1,3 +1,3 @@
- zreladdr-y := 0x00008000
+ zreladdr-y += 0x00008000
params_phys-y := 0x00000100
diff --git a/arch/arm/mach-ixp23xx/Makefile.boot b/arch/arm/mach-ixp23xx/Makefile.boot
index d5561ad15bad..44fb4a717c3f 100644
--- a/arch/arm/mach-ixp23xx/Makefile.boot
+++ b/arch/arm/mach-ixp23xx/Makefile.boot
@@ -1,2 +1,2 @@
- zreladdr-y := 0x00008000
+ zreladdr-y += 0x00008000
params_phys-y := 0x00000100
diff --git a/arch/arm/mach-ixp4xx/Makefile.boot b/arch/arm/mach-ixp4xx/Makefile.boot
index d84c5807a43d..9c7af91d93da 100644
--- a/arch/arm/mach-ixp4xx/Makefile.boot
+++ b/arch/arm/mach-ixp4xx/Makefile.boot
@@ -1,3 +1,3 @@
- zreladdr-y := 0x00008000
+ zreladdr-y += 0x00008000
params_phys-y := 0x00000100
diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c
index 2131832ee6ba..85245e48099c 100644
--- a/arch/arm/mach-ixp4xx/common-pci.c
+++ b/arch/arm/mach-ixp4xx/common-pci.c
@@ -397,7 +397,8 @@ void __init ixp4xx_pci_preinit(void)
local_write_config(PCI_BASE_ADDRESS_0, 4, PHYS_OFFSET);
local_write_config(PCI_BASE_ADDRESS_1, 4, PHYS_OFFSET + SZ_16M);
local_write_config(PCI_BASE_ADDRESS_2, 4, PHYS_OFFSET + SZ_32M);
- local_write_config(PCI_BASE_ADDRESS_3, 4, PHYS_OFFSET + SZ_48M);
+ local_write_config(PCI_BASE_ADDRESS_3, 4,
+ PHYS_OFFSET + SZ_32M + SZ_16M);
/*
* Enable CSR window at 64 MiB to allow PCI masters
diff --git a/arch/arm/mach-ixp4xx/include/mach/io.h b/arch/arm/mach-ixp4xx/include/mach/io.h
index 57b5410c31f4..ffb9d6afb89f 100644
--- a/arch/arm/mach-ixp4xx/include/mach/io.h
+++ b/arch/arm/mach-ixp4xx/include/mach/io.h
@@ -17,8 +17,6 @@
#include <mach/hardware.h>
-#define IO_SPACE_LIMIT 0x0000ffff
-
extern int (*ixp4xx_pci_read)(u32 addr, u32 cmd, u32* data);
extern int ixp4xx_pci_write(u32 addr, u32 cmd, u32 data);
diff --git a/arch/arm/mach-kirkwood/Makefile.boot b/arch/arm/mach-kirkwood/Makefile.boot
index 67039c3e0c48..760a0efe7580 100644
--- a/arch/arm/mach-kirkwood/Makefile.boot
+++ b/arch/arm/mach-kirkwood/Makefile.boot
@@ -1,3 +1,3 @@
- zreladdr-y := 0x00008000
+ zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
diff --git a/arch/arm/mach-ks8695/Makefile.boot b/arch/arm/mach-ks8695/Makefile.boot
index 48eb2cb3ac77..c9b0bebcf237 100644
--- a/arch/arm/mach-ks8695/Makefile.boot
+++ b/arch/arm/mach-ks8695/Makefile.boot
@@ -3,6 +3,6 @@
# PARAMS_PHYS must be within 4MB of ZRELADDR
# INITRD_PHYS must be in RAM
- zreladdr-y := 0x00008000
+ zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
diff --git a/arch/arm/mach-lpc32xx/Makefile.boot b/arch/arm/mach-lpc32xx/Makefile.boot
index b796b41ebf8f..2cfe0ee635c5 100644
--- a/arch/arm/mach-lpc32xx/Makefile.boot
+++ b/arch/arm/mach-lpc32xx/Makefile.boot
@@ -1,4 +1,4 @@
- zreladdr-y := 0x80008000
+ zreladdr-y += 0x80008000
params_phys-y := 0x80000100
initrd_phys-y := 0x82000000
diff --git a/arch/arm/mach-mmp/Makefile.boot b/arch/arm/mach-mmp/Makefile.boot
index 574a4aa8321a..5edf03e2beed 100644
--- a/arch/arm/mach-mmp/Makefile.boot
+++ b/arch/arm/mach-mmp/Makefile.boot
@@ -1 +1 @@
- zreladdr-y := 0x00008000
+ zreladdr-y += 0x00008000
diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c
index 06b5fa853c93..49c5d6d843d6 100644
--- a/arch/arm/mach-mmp/aspenite.c
+++ b/arch/arm/mach-mmp/aspenite.c
@@ -160,7 +160,7 @@ static struct mtd_partition aspenite_nand_partitions[] = {
}, {
.name = "filesystem",
.offset = MTDPART_OFS_APPEND,
- .size = SZ_48M,
+ .size = SZ_32M + SZ_16M,
.mask_flags = 0,
}
};
diff --git a/arch/arm/mach-mmp/include/mach/pxa168.h b/arch/arm/mach-mmp/include/mach/pxa168.h
index 7f005843a707..7fb568d2845b 100644
--- a/arch/arm/mach-mmp/include/mach/pxa168.h
+++ b/arch/arm/mach-mmp/include/mach/pxa168.h
@@ -35,6 +35,13 @@ extern struct pxa_device_desc pxa168_device_fb;
extern struct pxa_device_desc pxa168_device_keypad;
extern struct pxa_device_desc pxa168_device_eth;
+struct pxa168_usb_pdata {
+ /* If NULL, default phy init routine for PXA168 would be called */
+ int (*phy_init)(void __iomem *usb_phy_reg_base);
+};
+/* pdata can be NULL */
+int __init pxa168_add_usb_host(struct pxa168_usb_pdata *pdata);
+
static inline int pxa168_add_uart(int id)
{
struct pxa_device_desc *d = NULL;
diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c
index 0156f535dae7..b2b280c517dd 100644
--- a/arch/arm/mach-mmp/pxa168.c
+++ b/arch/arm/mach-mmp/pxa168.c
@@ -25,6 +25,9 @@
#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>
#include "common.h"
#include "clock.h"
@@ -83,6 +86,7 @@ static APBC_CLK(keypad, PXA168_KPC, 0, 32000);
static APMU_CLK(nand, NAND, 0x19b, 156000000);
static APMU_CLK(lcd, LCD, 0x7f, 312000000);
static APMU_CLK(eth, ETH, 0x09, 0);
+static APMU_CLK(usb, USB, 0x12, 0);
/* device and clock bindings */
static struct clk_lookup pxa168_clkregs[] = {
@@ -104,6 +108,7 @@ static struct clk_lookup pxa168_clkregs[] = {
INIT_CLKREG(&clk_lcd, "pxa168-fb", NULL),
INIT_CLKREG(&clk_keypad, "pxa27x-keypad", NULL),
INIT_CLKREG(&clk_eth, "pxa168-eth", "MFUCLK"),
+ INIT_CLKREG(&clk_usb, "pxa168-ehci", "PXA168-USBCLK"),
};
static int __init pxa168_init(void)
@@ -169,3 +174,44 @@ PXA168_DEVICE(ssp5, "pxa168-ssp", 4, SSP5, 0xd4021000, 0x40, 60, 61);
PXA168_DEVICE(fb, "pxa168-fb", -1, LCD, 0xd420b000, 0x1c8);
PXA168_DEVICE(keypad, "pxa27x-keypad", -1, KEYPAD, 0xd4012000, 0x4c);
PXA168_DEVICE(eth, "pxa168-eth", -1, MFU, 0xc0800000, 0x0fff);
+
+struct resource pxa168_usb_host_resources[] = {
+ /* USB Host conroller register base */
+ [0] = {
+ .start = 0xd4209000,
+ .end = 0xd4209000 + 0x200,
+ .flags = IORESOURCE_MEM,
+ .name = "pxa168-usb-host",
+ },
+ /* USB PHY register base */
+ [1] = {
+ .start = 0xd4206000,
+ .end = 0xd4206000 + 0xff,
+ .flags = IORESOURCE_MEM,
+ .name = "pxa168-usb-phy",
+ },
+ [2] = {
+ .start = IRQ_PXA168_USB2,
+ .end = IRQ_PXA168_USB2,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 pxa168_usb_host_dmamask = DMA_BIT_MASK(32);
+struct platform_device pxa168_device_usb_host = {
+ .name = "pxa168-ehci",
+ .id = -1,
+ .dev = {
+ .dma_mask = &pxa168_usb_host_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+
+ .num_resources = ARRAY_SIZE(pxa168_usb_host_resources),
+ .resource = pxa168_usb_host_resources,
+};
+
+int __init pxa168_add_usb_host(struct pxa168_usb_pdata *pdata)
+{
+ pxa168_device_usb_host.dev.platform_data = pdata;
+ return platform_device_register(&pxa168_device_usb_host);
+}
diff --git a/arch/arm/mach-mmp/ttc_dkb.c b/arch/arm/mach-mmp/ttc_dkb.c
index 6bd37a27e5fc..176515a76989 100644
--- a/arch/arm/mach-mmp/ttc_dkb.c
+++ b/arch/arm/mach-mmp/ttc_dkb.c
@@ -93,7 +93,7 @@ static struct mtd_partition ttc_dkb_onenand_partitions[] = {
}, {
.name = "filesystem",
.offset = MTDPART_OFS_APPEND,
- .size = SZ_48M,
+ .size = SZ_32M + SZ_16M,
.mask_flags = 0,
}
};
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 24dfbf8c07c4..9b803a578b4d 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -1,3 +1,3 @@
- zreladdr-y := 0x10008000
+ zreladdr-y += 0x10008000
params_phys-y := 0x10000100
initrd_phys-y := 0x10800000
diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c
index 18a3c97bc863..f81ef1f9d46f 100644
--- a/arch/arm/mach-msm/board-halibut.c
+++ b/arch/arm/mach-msm/board-halibut.c
@@ -78,8 +78,8 @@ static void __init halibut_init(void)
platform_add_devices(devices, ARRAY_SIZE(devices));
}
-static void __init halibut_fixup(struct machine_desc *desc, struct tag *tags,
- char **cmdline, struct meminfo *mi)
+static void __init halibut_fixup(struct tag *tags, char **cmdline,
+ struct meminfo *mi)
{
mi->nr_banks=1;
mi->bank[0].start = PHYS_OFFSET;
diff --git a/arch/arm/mach-msm/board-mahimahi.c b/arch/arm/mach-msm/board-mahimahi.c
index 7a9a03eb189c..1df15aa3c66d 100644
--- a/arch/arm/mach-msm/board-mahimahi.c
+++ b/arch/arm/mach-msm/board-mahimahi.c
@@ -53,8 +53,8 @@ static void __init mahimahi_init(void)
platform_add_devices(devices, ARRAY_SIZE(devices));
}
-static void __init mahimahi_fixup(struct machine_desc *desc, struct tag *tags,
- char **cmdline, struct meminfo *mi)
+static void __init mahimahi_fixup(struct tag *tags, char **cmdline,
+ struct meminfo *mi)
{
mi->nr_banks = 2;
mi->bank[0].start = PHYS_OFFSET;
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index b7a84966b711..d1e4cc83b1e6 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -24,6 +24,7 @@
#include <linux/smsc911x.h>
#include <linux/usb/msm_hsusb.h>
#include <linux/clkdev.h>
+#include <linux/memblock.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -42,6 +43,21 @@
extern struct sys_timer msm_timer;
+static void __init msm7x30_fixup(struct machine_desc *desc, struct tag *tag,
+ char **cmdline, struct meminfo *mi)
+{
+ for (; tag->hdr.size; tag = tag_next(tag))
+ if (tag->hdr.tag == ATAG_MEM && tag->u.mem.start == 0x200000) {
+ tag->u.mem.start = 0;
+ tag->u.mem.size += SZ_2M;
+ }
+}
+
+static void __init msm7x30_reserve(void)
+{
+ memblock_remove(0x0, SZ_2M);
+}
+
static int hsusb_phy_init_seq[] = {
0x30, 0x32, /* Enable and set Pre-Emphasis Depth to 20% */
0x02, 0x36, /* Disable CDR Auto Reset feature */
@@ -107,6 +123,8 @@ static void __init msm7x30_map_io(void)
MACHINE_START(MSM7X30_SURF, "QCT MSM7X30 SURF")
.boot_params = PLAT_PHYS_OFFSET + 0x100,
+ .fixup = msm7x30_fixup,
+ .reserve = msm7x30_reserve,
.map_io = msm7x30_map_io,
.init_irq = msm7x30_init_irq,
.init_machine = msm7x30_init,
@@ -115,6 +133,8 @@ MACHINE_END
MACHINE_START(MSM7X30_FFA, "QCT MSM7X30 FFA")
.boot_params = PLAT_PHYS_OFFSET + 0x100,
+ .fixup = msm7x30_fixup,
+ .reserve = msm7x30_reserve,
.map_io = msm7x30_map_io,
.init_irq = msm7x30_init_irq,
.init_machine = msm7x30_init,
@@ -123,6 +143,8 @@ MACHINE_END
MACHINE_START(MSM7X30_FLUID, "QCT MSM7X30 FLUID")
.boot_params = PLAT_PHYS_OFFSET + 0x100,
+ .fixup = msm7x30_fixup,
+ .reserve = msm7x30_reserve,
.map_io = msm7x30_map_io,
.init_irq = msm7x30_init_irq,
.init_machine = msm7x30_init,
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
index 35c7ceeb3f29..b04468e7d00e 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -20,16 +20,34 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/clkdev.h>
+#include <linux/memblock.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/hardware/gic.h>
+#include <asm/setup.h>
#include <mach/board.h>
#include <mach/msm_iomap.h>
#include "devices.h"
+static void __init msm8960_fixup(struct machine_desc *desc, struct tag *tag,
+ char **cmdline, struct meminfo *mi)
+{
+ for (; tag->hdr.size; tag = tag_next(tag))
+ if (tag->hdr.tag == ATAG_MEM &&
+ tag->u.mem.start == 0x40200000) {
+ tag->u.mem.start = 0x40000000;
+ tag->u.mem.size += SZ_2M;
+ }
+}
+
+static void __init msm8960_reserve(void)
+{
+ memblock_remove(0x40000000, SZ_2M);
+}
+
static void __init msm8960_map_io(void)
{
msm_map_msm8960_io();
@@ -76,6 +94,8 @@ static void __init msm8960_rumi3_init(void)
}
MACHINE_START(MSM8960_SIM, "QCT MSM8960 SIMULATOR")
+ .fixup = msm8960_fixup,
+ .reserve = msm8960_reserve,
.map_io = msm8960_map_io,
.init_irq = msm8960_init_irq,
.timer = &msm_timer,
@@ -83,6 +103,8 @@ MACHINE_START(MSM8960_SIM, "QCT MSM8960 SIMULATOR")
MACHINE_END
MACHINE_START(MSM8960_RUMI3, "QCT MSM8960 RUMI3")
+ .fixup = msm8960_fixup,
+ .reserve = msm8960_reserve,
.map_io = msm8960_map_io,
.init_irq = msm8960_init_irq,
.timer = &msm_timer,
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 1163b6fd05d2..9221f54778be 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -20,14 +20,31 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/irq.h>
+#include <linux/memblock.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/hardware/gic.h>
+#include <asm/setup.h>
#include <mach/board.h>
#include <mach/msm_iomap.h>
+static void __init msm8x60_fixup(struct machine_desc *desc, struct tag *tag,
+ char **cmdline, struct meminfo *mi)
+{
+ for (; tag->hdr.size; tag = tag_next(tag))
+ if (tag->hdr.tag == ATAG_MEM &&
+ tag->u.mem.start == 0x40200000) {
+ tag->u.mem.start = 0x40000000;
+ tag->u.mem.size += SZ_2M;
+ }
+}
+
+static void __init msm8x60_reserve(void)
+{
+ memblock_remove(0x40000000, SZ_2M);
+}
static void __init msm8x60_map_io(void)
{
@@ -65,6 +82,8 @@ static void __init msm8x60_init(void)
}
MACHINE_START(MSM8X60_RUMI3, "QCT MSM8X60 RUMI3")
+ .fixup = msm8x60_fixup,
+ .reserve = msm8x60_reserve,
.map_io = msm8x60_map_io,
.init_irq = msm8x60_init_irq,
.init_machine = msm8x60_init,
@@ -72,6 +91,8 @@ MACHINE_START(MSM8X60_RUMI3, "QCT MSM8X60 RUMI3")
MACHINE_END
MACHINE_START(MSM8X60_SURF, "QCT MSM8X60 SURF")
+ .fixup = msm8x60_fixup,
+ .reserve = msm8x60_reserve,
.map_io = msm8x60_map_io,
.init_irq = msm8x60_init_irq,
.init_machine = msm8x60_init,
@@ -79,6 +100,8 @@ MACHINE_START(MSM8X60_SURF, "QCT MSM8X60 SURF")
MACHINE_END
MACHINE_START(MSM8X60_SIM, "QCT MSM8X60 SIMULATOR")
+ .fixup = msm8x60_fixup,
+ .reserve = msm8x60_reserve,
.map_io = msm8x60_map_io,
.init_irq = msm8x60_init_irq,
.init_machine = msm8x60_init,
@@ -86,6 +109,8 @@ MACHINE_START(MSM8X60_SIM, "QCT MSM8X60 SIMULATOR")
MACHINE_END
MACHINE_START(MSM8X60_FFA, "QCT MSM8X60 FFA")
+ .fixup = msm8x60_fixup,
+ .reserve = msm8x60_reserve,
.map_io = msm8x60_map_io,
.init_irq = msm8x60_init_irq,
.init_machine = msm8x60_init,
diff --git a/arch/arm/mach-msm/board-sapphire.c b/arch/arm/mach-msm/board-sapphire.c
index 68f930f07d77..c6e043c896aa 100644
--- a/arch/arm/mach-msm/board-sapphire.c
+++ b/arch/arm/mach-msm/board-sapphire.c
@@ -77,8 +77,8 @@ static struct map_desc sapphire_io_desc[] __initdata = {
}
};
-static void __init sapphire_fixup(struct machine_desc *desc, struct tag *tags,
- char **cmdline, struct meminfo *mi)
+static void __init sapphire_fixup(struct tag *tags, char **cmdline,
+ struct meminfo *mi)
{
int smi_sz = parse_tag_smi((const struct tag *)tags);
diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c
index 814386772c66..7acd2021ada9 100644
--- a/arch/arm/mach-msm/board-trout.c
+++ b/arch/arm/mach-msm/board-trout.c
@@ -48,8 +48,8 @@ static void __init trout_init_irq(void)
msm_init_irq();
}
-static void __init trout_fixup(struct machine_desc *desc, struct tag *tags,
- char **cmdline, struct meminfo *mi)
+static void __init trout_fixup(struct tag *tags, char **cmdline,
+ struct meminfo *mi)
{
mi->nr_banks = 1;
mi->bank[0].start = PHYS_OFFSET;
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 22a537669624..d9145dfc2a3b 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -18,7 +18,7 @@
#include <linux/list.h>
#include <linux/err.h>
#include <linux/spinlock.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
#include <linux/mutex.h>
#include <linux/clk.h>
#include <linux/string.h>
diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h
index f2f8d299ba95..58d5e7eec431 100644
--- a/arch/arm/mach-msm/include/mach/memory.h
+++ b/arch/arm/mach-msm/include/mach/memory.h
@@ -22,11 +22,11 @@
#elif defined(CONFIG_ARCH_QSD8X50)
#define PLAT_PHYS_OFFSET UL(0x20000000)
#elif defined(CONFIG_ARCH_MSM7X30)
-#define PLAT_PHYS_OFFSET UL(0x00200000)
+#define PLAT_PHYS_OFFSET UL(0x00000000)
#elif defined(CONFIG_ARCH_MSM8X60)
-#define PLAT_PHYS_OFFSET UL(0x40200000)
+#define PLAT_PHYS_OFFSET UL(0x40000000)
#elif defined(CONFIG_ARCH_MSM8960)
-#define PLAT_PHYS_OFFSET UL(0x40200000)
+#define PLAT_PHYS_OFFSET UL(0x40000000)
#else
#define PLAT_PHYS_OFFSET UL(0x10000000)
#endif
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 1a1af9e56250..727659520912 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -156,6 +156,12 @@ void __init smp_init_cpus(void)
{
unsigned int i, ncores = get_core_count();
+ if (ncores > nr_cpu_ids) {
+ pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
+ ncores, nr_cpu_ids);
+ ncores = nr_cpu_ids;
+ }
+
for (i = 0; i < ncores; i++)
set_cpu_possible(i, true);
diff --git a/arch/arm/mach-mv78xx0/Makefile.boot b/arch/arm/mach-mv78xx0/Makefile.boot
index 67039c3e0c48..760a0efe7580 100644
--- a/arch/arm/mach-mv78xx0/Makefile.boot
+++ b/arch/arm/mach-mv78xx0/Makefile.boot
@@ -1,3 +1,3 @@
- zreladdr-y := 0x00008000
+ zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
diff --git a/arch/arm/mach-mx5/Makefile.boot b/arch/arm/mach-mx5/Makefile.boot
index e928be1b6757..ca207ca305ec 100644
--- a/arch/arm/mach-mx5/Makefile.boot
+++ b/arch/arm/mach-mx5/Makefile.boot
@@ -1,9 +1,9 @@
- zreladdr-$(CONFIG_ARCH_MX50) := 0x70008000
+ zreladdr-$(CONFIG_ARCH_MX50) += 0x70008000
params_phys-$(CONFIG_ARCH_MX50) := 0x70000100
initrd_phys-$(CONFIG_ARCH_MX50) := 0x70800000
- zreladdr-$(CONFIG_ARCH_MX51) := 0x90008000
+ zreladdr-$(CONFIG_ARCH_MX51) += 0x90008000
params_phys-$(CONFIG_ARCH_MX51) := 0x90000100
initrd_phys-$(CONFIG_ARCH_MX51) := 0x90800000
- zreladdr-$(CONFIG_ARCH_MX53) := 0x70008000
+ zreladdr-$(CONFIG_ARCH_MX53) += 0x70008000
params_phys-$(CONFIG_ARCH_MX53) := 0x70000100
initrd_phys-$(CONFIG_ARCH_MX53) := 0x70800000
diff --git a/arch/arm/mach-mxs/Makefile.boot b/arch/arm/mach-mxs/Makefile.boot
index eb541e0291da..07b11fe6453f 100644
--- a/arch/arm/mach-mxs/Makefile.boot
+++ b/arch/arm/mach-mxs/Makefile.boot
@@ -1 +1 @@
-zreladdr-y := 0x40008000
+zreladdr-y += 0x40008000
diff --git a/arch/arm/mach-netx/Makefile.boot b/arch/arm/mach-netx/Makefile.boot
index b81cf6aff0ac..534a4d27055e 100644
--- a/arch/arm/mach-netx/Makefile.boot
+++ b/arch/arm/mach-netx/Makefile.boot
@@ -1,2 +1,2 @@
- zreladdr-y := 0x80008000
+ zreladdr-y += 0x80008000
diff --git a/arch/arm/mach-nomadik/Makefile.boot b/arch/arm/mach-nomadik/Makefile.boot
index c7e75acfe6c9..ff0a4b5b0a82 100644
--- a/arch/arm/mach-nomadik/Makefile.boot
+++ b/arch/arm/mach-nomadik/Makefile.boot
@@ -1,4 +1,4 @@
- zreladdr-y := 0x00008000
+ zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
diff --git a/arch/arm/mach-nuc93x/Makefile.boot b/arch/arm/mach-nuc93x/Makefile.boot
index a057b546b6e5..6c3d421c2d11 100644
--- a/arch/arm/mach-nuc93x/Makefile.boot
+++ b/arch/arm/mach-nuc93x/Makefile.boot
@@ -1,3 +1,3 @@
-zreladdr-y := 0x00008000
+zreladdr-y += 0x00008000
params_phys-y := 0x00000100
diff --git a/arch/arm/mach-nuc93x/time.c b/arch/arm/mach-nuc93x/time.c
index 2f90f9dc6e30..f9807c029ec5 100644
--- a/arch/arm/mach-nuc93x/time.c
+++ b/arch/arm/mach-nuc93x/time.c
@@ -82,7 +82,7 @@ static void nuc93x_timer_setup(void)
timer0_load = (rate / TICKS_PER_SEC);
__raw_writel(timer0_load, REG_TICR0);
- val |= (PERIOD | COUNTEN | INTEN | PRESCALE);;
+ val |= (PERIOD | COUNTEN | INTEN | PRESCALE);
__raw_writel(val, REG_TCSR0);
}
diff --git a/arch/arm/mach-omap1/Makefile.boot b/arch/arm/mach-omap1/Makefile.boot
index 292d56c5a888..13bda8dbd604 100644
--- a/arch/arm/mach-omap1/Makefile.boot
+++ b/arch/arm/mach-omap1/Makefile.boot
@@ -1,3 +1,3 @@
- zreladdr-y := 0x10008000
+ zreladdr-y += 0x10008000
params_phys-y := 0x10000100
initrd_phys-y := 0x10800000
diff --git a/arch/arm/mach-omap1/pm_bus.c b/arch/arm/mach-omap1/pm_bus.c
index 943072d5a1d5..7868e75ad077 100644
--- a/arch/arm/mach-omap1/pm_bus.c
+++ b/arch/arm/mach-omap1/pm_bus.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/pm_runtime.h>
+#include <linux/pm_clock.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/clk.h>
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 57b66d590c52..89bfb49389f2 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -36,6 +36,7 @@ config ARCH_OMAP3
select ARM_L1_CACHE_SHIFT_6 if !ARCH_OMAP4
select ARCH_HAS_OPP
select PM_OPP if PM
+ select ARM_CPU_SUSPEND if PM
config ARCH_OMAP4
bool "TI OMAP4"
@@ -50,6 +51,7 @@ config ARCH_OMAP4
select ARCH_HAS_OPP
select PM_OPP if PM
select USB_ARCH_HAS_EHCI
+ select ARM_CPU_SUSPEND if PM
comment "OMAP Core Type"
depends on ARCH_OMAP2
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index f34336560437..7317a2b39dd1 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -242,14 +242,11 @@ obj-$(CONFIG_MACH_IGEP0020) += board-igep0020.o \
obj-$(CONFIG_MACH_OMAP3_TOUCHBOOK) += board-omap3touchbook.o \
hsmmc.o
obj-$(CONFIG_MACH_OMAP_4430SDP) += board-4430sdp.o \
- hsmmc.o \
- omap_phy_internal.o
+ hsmmc.o
obj-$(CONFIG_MACH_OMAP4_PANDA) += board-omap4panda.o \
- hsmmc.o \
- omap_phy_internal.o
+ hsmmc.o
-obj-$(CONFIG_MACH_OMAP3517EVM) += board-am3517evm.o \
- omap_phy_internal.o \
+obj-$(CONFIG_MACH_OMAP3517EVM) += board-am3517evm.o
obj-$(CONFIG_MACH_CRANEBOARD) += board-am3517crane.o
@@ -260,6 +257,8 @@ obj-$(CONFIG_MACH_TI8168EVM) += board-ti8168evm.o
usbfs-$(CONFIG_ARCH_OMAP_OTG) := usb-fs.o
obj-y += $(usbfs-m) $(usbfs-y)
obj-y += usb-musb.o
+obj-y += omap_phy_internal.o
+
obj-$(CONFIG_MACH_OMAP2_TUSB6010) += usb-tusb6010.o
obj-y += usb-host.o
diff --git a/arch/arm/mach-omap2/Makefile.boot b/arch/arm/mach-omap2/Makefile.boot
index 565aff7f37a9..b03e562acc60 100644
--- a/arch/arm/mach-omap2/Makefile.boot
+++ b/arch/arm/mach-omap2/Makefile.boot
@@ -1,3 +1,3 @@
- zreladdr-y := 0x80008000
+ zreladdr-y += 0x80008000
params_phys-y := 0x80000100
initrd_phys-y := 0x80800000
diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
index 2028464cf5b9..f79b7d2a8ed4 100644
--- a/arch/arm/mach-omap2/board-2430sdp.c
+++ b/arch/arm/mach-omap2/board-2430sdp.c
@@ -193,7 +193,8 @@ static int __init omap2430_i2c_init(void)
{
omap_register_i2c_bus(1, 100, sdp2430_i2c1_boardinfo,
ARRAY_SIZE(sdp2430_i2c1_boardinfo));
- omap2_pmic_init("twl4030", &sdp2430_twldata);
+ omap_pmic_init(2, 100, "twl4030", INT_24XX_SYS_NIRQ,
+ &sdp2430_twldata);
return 0;
}
diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c
index ffd55b1c4396..b9b844683147 100644
--- a/arch/arm/mach-omap2/clock3xxx_data.c
+++ b/arch/arm/mach-omap2/clock3xxx_data.c
@@ -3078,6 +3078,7 @@ static struct clk gpt12_fck = {
.name = "gpt12_fck",
.ops = &clkops_null,
.parent = &secure_32k_fck,
+ .clkdm_name = "wkup_clkdm",
.recalc = &followparent_recalc,
};
@@ -3085,6 +3086,7 @@ static struct clk wdt1_fck = {
.name = "wdt1_fck",
.ops = &clkops_null,
.parent = &secure_32k_fck,
+ .clkdm_name = "wkup_clkdm",
.recalc = &followparent_recalc,
};
diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c
index 2af0e3f00ce1..c0b6fbda3408 100644
--- a/arch/arm/mach-omap2/clock44xx_data.c
+++ b/arch/arm/mach-omap2/clock44xx_data.c
@@ -3376,10 +3376,18 @@ int __init omap4xxx_clk_init(void)
} else if (cpu_is_omap446x()) {
cpu_mask = RATE_IN_4460;
cpu_clkflg = CK_446X;
+ } else {
+ return 0;
}
clk_init(&omap2_clk_functions);
- omap2_clk_disable_clkdm_control();
+
+ /*
+ * Must stay commented until all OMAP SoC drivers are
+ * converted to runtime PM, or drivers may start crashing
+ *
+ * omap2_clk_disable_clkdm_control();
+ */
for (c = omap44xx_clks; c < omap44xx_clks + ARRAY_SIZE(omap44xx_clks);
c++)
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index ab7db083f97f..8f0890685d7b 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -747,6 +747,7 @@ int clkdm_wakeup(struct clockdomain *clkdm)
spin_lock_irqsave(&clkdm->lock, flags);
clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
ret = arch_clkdm->clkdm_wakeup(clkdm);
+ ret |= pwrdm_state_switch(clkdm->pwrdm.ptr);
spin_unlock_irqrestore(&clkdm->lock, flags);
return ret;
}
@@ -818,6 +819,7 @@ void clkdm_deny_idle(struct clockdomain *clkdm)
spin_lock_irqsave(&clkdm->lock, flags);
clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
arch_clkdm->clkdm_deny_idle(clkdm);
+ pwrdm_state_switch(clkdm->pwrdm.ptr);
spin_unlock_irqrestore(&clkdm->lock, flags);
}
diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
index a9b45c76e1d3..097a42d81e59 100644
--- a/arch/arm/mach-omap2/hsmmc.c
+++ b/arch/arm/mach-omap2/hsmmc.c
@@ -137,8 +137,7 @@ static void omap4_hsmmc1_before_set_reg(struct device *dev, int slot,
*/
reg = omap4_ctrl_pad_readl(control_pbias_offset);
reg &= ~(OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK |
- OMAP4_MMC1_PWRDNZ_MASK |
- OMAP4_USBC1_ICUSB_PWRDNZ_MASK);
+ OMAP4_MMC1_PWRDNZ_MASK);
omap4_ctrl_pad_writel(reg, control_pbias_offset);
}
@@ -156,8 +155,7 @@ static void omap4_hsmmc1_after_set_reg(struct device *dev, int slot,
else
reg |= OMAP4_MMC1_PBIASLITE_VMODE_MASK;
reg |= (OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK |
- OMAP4_MMC1_PWRDNZ_MASK |
- OMAP4_USBC1_ICUSB_PWRDNZ_MASK);
+ OMAP4_MMC1_PWRDNZ_MASK);
omap4_ctrl_pad_writel(reg, control_pbias_offset);
timeout = jiffies + msecs_to_jiffies(5);
@@ -171,16 +169,14 @@ static void omap4_hsmmc1_after_set_reg(struct device *dev, int slot,
if (reg & OMAP4_MMC1_PBIASLITE_VMODE_ERROR_MASK) {
pr_err("Pbias Voltage is not same as LDO\n");
/* Caution : On VMODE_ERROR Power Down MMC IO */
- reg &= ~(OMAP4_MMC1_PWRDNZ_MASK |
- OMAP4_USBC1_ICUSB_PWRDNZ_MASK);
+ reg &= ~(OMAP4_MMC1_PWRDNZ_MASK);
omap4_ctrl_pad_writel(reg, control_pbias_offset);
}
} else {
reg = omap4_ctrl_pad_readl(control_pbias_offset);
reg |= (OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK |
OMAP4_MMC1_PWRDNZ_MASK |
- OMAP4_MMC1_PBIASLITE_VMODE_MASK |
- OMAP4_USBC1_ICUSB_PWRDNZ_MASK);
+ OMAP4_MMC1_PBIASLITE_VMODE_MASK);
omap4_ctrl_pad_writel(reg, control_pbias_offset);
}
}
diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c
index ce65e9329c7b..889464dc7b2d 100644
--- a/arch/arm/mach-omap2/omap-smp.c
+++ b/arch/arm/mach-omap2/omap-smp.c
@@ -109,12 +109,10 @@ void __init smp_init_cpus(void)
ncores = scu_get_core_count(scu_base);
/* sanity check */
- if (ncores > NR_CPUS) {
- printk(KERN_WARNING
- "OMAP4: no. of cores (%d) greater than configured "
- "maximum of %d - clipping\n",
- ncores, NR_CPUS);
- ncores = NR_CPUS;
+ if (ncores > nr_cpu_ids) {
+ pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
+ ncores, nr_cpu_ids);
+ ncores = nr_cpu_ids;
}
for (i = 0; i < ncores; i++)
diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
index 16743c7d6e8e..408193d8e044 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
@@ -192,6 +192,7 @@ static struct omap_hwmod_addr_space omap2430_usbhsotg_addrs[] = {
.pa_end = OMAP243X_HS_BASE + SZ_4K - 1,
.flags = ADDR_TYPE_RT
},
+ { }
};
/* l4_core ->usbhsotg interface */
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index 3feb35911a32..472bf22d5e84 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -130,7 +130,6 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
} else {
hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]);
clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
- pwrdm_wait_transition(pwrdm);
sleep_switch = FORCEWAKEUP_SWITCH;
}
}
@@ -156,7 +155,6 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
return ret;
}
- pwrdm_wait_transition(pwrdm);
pwrdm_state_switch(pwrdm);
err:
return ret;
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 9af08473bf10..ef71fdd40fc4 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -195,28 +195,35 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
/**
* pwrdm_init - set up the powerdomain layer
- * @pwrdm_list: array of struct powerdomain pointers to register
+ * @pwrdms: array of struct powerdomain pointers to register
* @custom_funcs: func pointers for arch specific implementations
*
- * Loop through the array of powerdomains @pwrdm_list, registering all
- * that are available on the current CPU. If pwrdm_list is supplied
- * and not null, all of the referenced powerdomains will be
- * registered. No return value. XXX pwrdm_list is not really a
- * "list"; it is an array. Rename appropriately.
+ * Loop through the array of powerdomains @pwrdms, registering all
+ * that are available on the current CPU. Also, program all
+ * powerdomain target state as ON; this is to prevent domains from
+ * hitting low power states (if bootloader has target states set to
+ * something other than ON) and potentially even losing context while
+ * PM is not fully initialized. The PM late init code can then program
+ * the desired target state for all the power domains. No return
+ * value.
*/
-void pwrdm_init(struct powerdomain **pwrdm_list, struct pwrdm_ops *custom_funcs)
+void pwrdm_init(struct powerdomain **pwrdms, struct pwrdm_ops *custom_funcs)
{
struct powerdomain **p = NULL;
+ struct powerdomain *temp_p;
if (!custom_funcs)
WARN(1, "powerdomain: No custom pwrdm functions registered\n");
else
arch_pwrdm = custom_funcs;
- if (pwrdm_list) {
- for (p = pwrdm_list; *p; p++)
+ if (pwrdms) {
+ for (p = pwrdms; *p; p++)
_pwrdm_register(*p);
}
+
+ list_for_each_entry(temp_p, &pwrdm_list, node)
+ pwrdm_set_next_pwrst(temp_p, PWRDM_POWER_ON);
}
/**
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index 34c01a7de810..f49804f181d4 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -247,7 +247,7 @@ static void sr_stop_vddautocomp(struct omap_sr *sr)
* driver register and sr device intializtion API's. Only one call
* will ultimately succeed.
*
- * Currently this function registers interrrupt handler for a particular SR
+ * Currently this function registers interrupt handler for a particular SR
* if smartreflex class driver is already registered and has
* requested for interrupts and the SR interrupt line in present.
*/
diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c
index a65145b02a55..19e4dac62a8c 100644
--- a/arch/arm/mach-omap2/usb-musb.c
+++ b/arch/arm/mach-omap2/usb-musb.c
@@ -137,9 +137,6 @@ void __init usb_musb_init(struct omap_musb_board_data *musb_board_data)
musb_plat.mode = board_data->mode;
musb_plat.extvbus = board_data->extvbus;
- if (cpu_is_omap44xx())
- omap4430_phy_init(dev);
-
if (cpu_is_omap3517() || cpu_is_omap3505()) {
oh_name = "am35x_otg_hs";
name = "musb-am35x";
diff --git a/arch/arm/mach-orion5x/Makefile.boot b/arch/arm/mach-orion5x/Makefile.boot
index 67039c3e0c48..760a0efe7580 100644
--- a/arch/arm/mach-orion5x/Makefile.boot
+++ b/arch/arm/mach-orion5x/Makefile.boot
@@ -1,3 +1,3 @@
- zreladdr-y := 0x00008000
+ zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c
index 0ab531d047fc..22ace0bf2f92 100644
--- a/arch/arm/mach-orion5x/common.c
+++ b/arch/arm/mach-orion5x/common.c
@@ -308,8 +308,8 @@ void __init orion5x_init(void)
* Many orion-based systems have buggy bootloader implementations.
* This is a common fixup for bogus memory tags.
*/
-void __init tag_fixup_mem32(struct machine_desc *mdesc, struct tag *t,
- char **from, struct meminfo *meminfo)
+void __init tag_fixup_mem32(struct tag *t, char **from,
+ struct meminfo *meminfo)
{
for (; t->hdr.size; t = tag_next(t))
if (t->hdr.tag == ATAG_MEM &&
diff --git a/arch/arm/mach-orion5x/common.h b/arch/arm/mach-orion5x/common.h
index 3e5499dda49a..909489f4d23e 100644
--- a/arch/arm/mach-orion5x/common.h
+++ b/arch/arm/mach-orion5x/common.h
@@ -53,11 +53,9 @@ int orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys);
struct pci_bus *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys);
int orion5x_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin);
-struct machine_desc;
struct meminfo;
struct tag;
-extern void __init tag_fixup_mem32(struct machine_desc *, struct tag *,
- char **, struct meminfo *);
+extern void __init tag_fixup_mem32(struct tag *, char **, struct meminfo *);
#endif
diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c
index a6eddae82a0b..c105556a0ee1 100644
--- a/arch/arm/mach-orion5x/dns323-setup.c
+++ b/arch/arm/mach-orion5x/dns323-setup.c
@@ -77,7 +77,7 @@ static int __init dns323_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
/*
* Check for devices with hard-wired IRQs.
*/
- irq = orion5x_pci_map_irq(const dev, slot, pin);
+ irq = orion5x_pci_map_irq(dev, slot, pin);
if (irq != -1)
return irq;
diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c
index 28b8760ab9fa..bc4a920e26ee 100644
--- a/arch/arm/mach-orion5x/pci.c
+++ b/arch/arm/mach-orion5x/pci.c
@@ -14,6 +14,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/mbus.h>
+#include <video/vga.h>
#include <asm/irq.h>
#include <asm/mach/pci.h>
#include <plat/pcie.h>
diff --git a/arch/arm/mach-pnx4008/Makefile.boot b/arch/arm/mach-pnx4008/Makefile.boot
index 44c7117e20dd..9fa19baa7f2e 100644
--- a/arch/arm/mach-pnx4008/Makefile.boot
+++ b/arch/arm/mach-pnx4008/Makefile.boot
@@ -1,4 +1,4 @@
- zreladdr-y := 0x80008000
+ zreladdr-y += 0x80008000
params_phys-y := 0x80000100
initrd_phys-y := 0x80800000
diff --git a/arch/arm/mach-prima2/Makefile.boot b/arch/arm/mach-prima2/Makefile.boot
index d023db3ae4ff..c77a4883a4ee 100644
--- a/arch/arm/mach-prima2/Makefile.boot
+++ b/arch/arm/mach-prima2/Makefile.boot
@@ -1,3 +1,3 @@
-zreladdr-y := 0x00008000
+zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
diff --git a/arch/arm/mach-prima2/clock.c b/arch/arm/mach-prima2/clock.c
index f9a2aaf63f71..615a4e75ceab 100644
--- a/arch/arm/mach-prima2/clock.c
+++ b/arch/arm/mach-prima2/clock.c
@@ -481,6 +481,7 @@ static void __init sirfsoc_clk_init(void)
static struct of_device_id clkc_ids[] = {
{ .compatible = "sirf,prima2-clkc" },
+ {},
};
void __init sirfsoc_of_clk_init(void)
diff --git a/arch/arm/mach-prima2/irq.c b/arch/arm/mach-prima2/irq.c
index c3404cbb6ff7..7af254d046ba 100644
--- a/arch/arm/mach-prima2/irq.c
+++ b/arch/arm/mach-prima2/irq.c
@@ -51,6 +51,7 @@ static __init void sirfsoc_irq_init(void)
static struct of_device_id intc_ids[] = {
{ .compatible = "sirf,prima2-intc" },
+ {},
};
void __init sirfsoc_of_irq_init(void)
diff --git a/arch/arm/mach-prima2/rstc.c b/arch/arm/mach-prima2/rstc.c
index d074786e83d4..492cfa8d2610 100644
--- a/arch/arm/mach-prima2/rstc.c
+++ b/arch/arm/mach-prima2/rstc.c
@@ -19,6 +19,7 @@ static DEFINE_MUTEX(rstc_lock);
static struct of_device_id rstc_ids[] = {
{ .compatible = "sirf,prima2-rstc" },
+ {},
};
static int __init sirfsoc_of_rstc_init(void)
diff --git a/arch/arm/mach-prima2/timer.c b/arch/arm/mach-prima2/timer.c
index 44027f34a88a..ed7ec48d11da 100644
--- a/arch/arm/mach-prima2/timer.c
+++ b/arch/arm/mach-prima2/timer.c
@@ -190,6 +190,7 @@ static void __init sirfsoc_timer_init(void)
static struct of_device_id timer_ids[] = {
{ .compatible = "sirf,prima2-tick" },
+ {},
};
static void __init sirfsoc_of_timer_map(void)
diff --git a/arch/arm/mach-pxa/Makefile.boot b/arch/arm/mach-pxa/Makefile.boot
index 1ead67178eca..2c1ae92f2106 100644
--- a/arch/arm/mach-pxa/Makefile.boot
+++ b/arch/arm/mach-pxa/Makefile.boot
@@ -1,2 +1,2 @@
- zreladdr-y := 0xa0008000
+ zreladdr-y += 0xa0008000
diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c
index b6a51340270b..d940e8a72270 100644
--- a/arch/arm/mach-pxa/cm-x300.c
+++ b/arch/arm/mach-pxa/cm-x300.c
@@ -839,8 +839,8 @@ static void __init cm_x300_init(void)
cm_x300_init_bl();
}
-static void __init cm_x300_fixup(struct machine_desc *mdesc, struct tag *tags,
- char **cmdline, struct meminfo *mi)
+static void __init cm_x300_fixup(struct tag *tags, char **cmdline,
+ struct meminfo *mi)
{
/* Make sure that mi->bank[0].start = PHYS_ADDR */
for (; tags->hdr.size; tags = tag_next(tags))
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
index 185a37cad254..3e9483b06053 100644
--- a/arch/arm/mach-pxa/corgi.c
+++ b/arch/arm/mach-pxa/corgi.c
@@ -705,8 +705,8 @@ static void __init corgi_init(void)
platform_add_devices(devices, ARRAY_SIZE(devices));
}
-static void __init fixup_corgi(struct machine_desc *desc,
- struct tag *tags, char **cmdline, struct meminfo *mi)
+static void __init fixup_corgi(struct tag *tags, char **cmdline,
+ struct meminfo *mi)
{
sharpsl_save_param();
mi->nr_banks=1;
diff --git a/arch/arm/mach-pxa/eseries.c b/arch/arm/mach-pxa/eseries.c
index b4599ec9d619..e4a1f4dc89ff 100644
--- a/arch/arm/mach-pxa/eseries.c
+++ b/arch/arm/mach-pxa/eseries.c
@@ -41,8 +41,7 @@
#include "clock.h"
/* Only e800 has 128MB RAM */
-void __init eseries_fixup(struct machine_desc *desc,
- struct tag *tags, char **cmdline, struct meminfo *mi)
+void __init eseries_fixup(struct tag *tags, char **cmdline, struct meminfo *mi)
{
mi->nr_banks=1;
mi->bank[0].start = 0xa0000000;
diff --git a/arch/arm/mach-pxa/eseries.h b/arch/arm/mach-pxa/eseries.h
index 5930f5e2a123..be921965e91a 100644
--- a/arch/arm/mach-pxa/eseries.h
+++ b/arch/arm/mach-pxa/eseries.h
@@ -1,5 +1,4 @@
-void __init eseries_fixup(struct machine_desc *desc,
- struct tag *tags, char **cmdline, struct meminfo *mi);
+void __init eseries_fixup(struct tag *tags, char **cmdline, struct meminfo *mi);
extern struct pxa2xx_udc_mach_info e7xx_udc_mach_info;
extern struct pxaficp_platform_data e7xx_ficp_platform_data;
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
index b09e848eb6c6..ca6075717824 100644
--- a/arch/arm/mach-pxa/irq.c
+++ b/arch/arm/mach-pxa/irq.c
@@ -19,6 +19,8 @@
#include <linux/io.h>
#include <linux/irq.h>
+#include <asm/exception.h>
+
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <mach/gpio.h>
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index a113ea9ab4ab..948ce3e729fa 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -454,8 +454,8 @@ static void __init poodle_init(void)
poodle_init_spi();
}
-static void __init fixup_poodle(struct machine_desc *desc,
- struct tag *tags, char **cmdline, struct meminfo *mi)
+static void __init fixup_poodle(struct tag *tags, char **cmdline,
+ struct meminfo *mi)
{
sharpsl_save_param();
mi->nr_banks=1;
diff --git a/arch/arm/mach-pxa/saar.c b/arch/arm/mach-pxa/saar.c
index df4356e8acae..72001ec6e7b5 100644
--- a/arch/arm/mach-pxa/saar.c
+++ b/arch/arm/mach-pxa/saar.c
@@ -540,7 +540,7 @@ static struct mtd_partition saar_onenand_partitions[] = {
}, {
.name = "filesystem",
.offset = MTDPART_OFS_APPEND,
- .size = SZ_48M,
+ .size = SZ_32M + SZ_16M,
.mask_flags = 0,
}
};
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index 438c7b5e451f..d8dec9113aad 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -970,8 +970,8 @@ static void __init spitz_init(void)
spitz_i2c_init();
}
-static void __init spitz_fixup(struct machine_desc *desc,
- struct tag *tags, char **cmdline, struct meminfo *mi)
+static void __init spitz_fixup(struct tag *tags, char **cmdline,
+ struct meminfo *mi)
{
sharpsl_save_param();
mi->nr_banks = 1;
diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
index 9f69a2682693..402b0c96613b 100644
--- a/arch/arm/mach-pxa/tosa.c
+++ b/arch/arm/mach-pxa/tosa.c
@@ -960,8 +960,8 @@ static void __init tosa_init(void)
platform_add_devices(devices, ARRAY_SIZE(devices));
}
-static void __init fixup_tosa(struct machine_desc *desc,
- struct tag *tags, char **cmdline, struct meminfo *mi)
+static void __init fixup_tosa(struct tag *tags, char **cmdline,
+ struct meminfo *mi)
{
sharpsl_save_param();
mi->nr_banks=1;
diff --git a/arch/arm/mach-pxa/xcep.c b/arch/arm/mach-pxa/xcep.c
index acc600f5e72f..937c42845df9 100644
--- a/arch/arm/mach-pxa/xcep.c
+++ b/arch/arm/mach-pxa/xcep.c
@@ -142,8 +142,7 @@ static struct platform_device *devices[] __initdata = {
/* We have to state that there are HWMON devices on the I2C bus on XCEP.
* Drivers for HWMON verify capabilities of the adapter when loading and
- * refuse to attach if the adapter doesn't support HWMON class of devices.
- * See also Documentation/i2c/porting-clients. */
+ * refuse to attach if the adapter doesn't support HWMON class of devices. */
static struct i2c_pxa_platform_data xcep_i2c_platform_data = {
.class = I2C_CLASS_HWMON
};
diff --git a/arch/arm/mach-realview/Makefile.boot b/arch/arm/mach-realview/Makefile.boot
index d97e003d3df4..d2c3d788f688 100644
--- a/arch/arm/mach-realview/Makefile.boot
+++ b/arch/arm/mach-realview/Makefile.boot
@@ -1,9 +1,9 @@
ifeq ($(CONFIG_REALVIEW_HIGH_PHYS_OFFSET),y)
- zreladdr-y := 0x70008000
+ zreladdr-y += 0x70008000
params_phys-y := 0x70000100
initrd_phys-y := 0x70800000
else
- zreladdr-y := 0x00008000
+ zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
endif
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index 5c23450d2d1d..d5ed5d4f77d6 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -517,8 +517,7 @@ void __init realview_timer_init(unsigned int timer_irq)
/*
* Setup the memory banks.
*/
-void realview_fixup(struct machine_desc *mdesc, struct tag *tags, char **from,
- struct meminfo *meminfo)
+void realview_fixup(struct tag *tags, char **from, struct meminfo *meminfo)
{
/*
* Most RealView platforms have 512MB contiguous RAM at 0x70000000.
diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h
index 5c83d1e87a03..47259c89a75e 100644
--- a/arch/arm/mach-realview/core.h
+++ b/arch/arm/mach-realview/core.h
@@ -63,8 +63,8 @@ extern int realview_flash_register(struct resource *res, u32 num);
extern int realview_eth_register(const char *name, struct resource *res);
extern int realview_usb_register(struct resource *res);
extern void realview_init_early(void);
-extern void realview_fixup(struct machine_desc *mdesc, struct tag *tags,
- char **from, struct meminfo *meminfo);
+extern void realview_fixup(struct tag *tags, char **from,
+ struct meminfo *meminfo);
extern void (*realview_reset)(char);
#endif
diff --git a/arch/arm/mach-realview/include/mach/board-pb1176.h b/arch/arm/mach-realview/include/mach/board-pb1176.h
index 002ab5d8c11c..2a15fef94730 100644
--- a/arch/arm/mach-realview/include/mach/board-pb1176.h
+++ b/arch/arm/mach-realview/include/mach/board-pb1176.h
@@ -70,6 +70,7 @@
#define REALVIEW_DC1176_GIC_CPU_BASE 0x10120000 /* GIC CPU interface, on devchip */
#define REALVIEW_DC1176_GIC_DIST_BASE 0x10121000 /* GIC distributor, on devchip */
+#define REALVIEW_DC1176_ROM_BASE 0x10200000 /* 16KiB NRAM preudo-ROM, on devchip */
#define REALVIEW_PB1176_GIC_CPU_BASE 0x10040000 /* GIC CPU interface, on FPGA */
#define REALVIEW_PB1176_GIC_DIST_BASE 0x10041000 /* GIC distributor, on FPGA */
#define REALVIEW_PB1176_L220_BASE 0x10110000 /* L220 registers */
diff --git a/arch/arm/mach-realview/include/mach/system.h b/arch/arm/mach-realview/include/mach/system.h
index a30f2e3ec178..6657ff231161 100644
--- a/arch/arm/mach-realview/include/mach/system.h
+++ b/arch/arm/mach-realview/include/mach/system.h
@@ -44,6 +44,7 @@ static inline void arch_reset(char mode, const char *cmd)
*/
if (realview_reset)
realview_reset(mode);
+ dsb();
}
#endif
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c
index 4ae943bafa92..e83c654a58d0 100644
--- a/arch/arm/mach-realview/platsmp.c
+++ b/arch/arm/mach-realview/platsmp.c
@@ -52,12 +52,10 @@ void __init smp_init_cpus(void)
ncores = scu_base ? scu_get_core_count(scu_base) : 1;
/* sanity check */
- if (ncores > NR_CPUS) {
- printk(KERN_WARNING
- "Realview: no. of cores (%d) greater than configured "
- "maximum of %d - clipping\n",
- ncores, NR_CPUS);
- ncores = NR_CPUS;
+ if (ncores > nr_cpu_ids) {
+ pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
+ ncores, nr_cpu_ids);
+ ncores = nr_cpu_ids;
}
for (i = 0; i < ncores; i++)
diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c
index ad5671acb66a..865d440fcf58 100644
--- a/arch/arm/mach-realview/realview_pb1176.c
+++ b/arch/arm/mach-realview/realview_pb1176.c
@@ -26,6 +26,8 @@
#include <linux/amba/pl061.h>
#include <linux/amba/mmci.h>
#include <linux/amba/pl022.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mtd/partitions.h>
#include <linux/io.h>
#include <mach/hardware.h>
@@ -204,22 +206,48 @@ static struct amba_device *amba_devs[] __initdata = {
* RealView PB1176 platform devices
*/
static struct resource realview_pb1176_flash_resources[] = {
- [0] = {
+ {
.start = REALVIEW_PB1176_FLASH_BASE,
.end = REALVIEW_PB1176_FLASH_BASE + REALVIEW_PB1176_FLASH_SIZE - 1,
.flags = IORESOURCE_MEM,
},
- [1] = {
+#ifdef CONFIG_REALVIEW_PB1176_SECURE_FLASH
+ {
.start = REALVIEW_PB1176_SEC_FLASH_BASE,
.end = REALVIEW_PB1176_SEC_FLASH_BASE + REALVIEW_PB1176_SEC_FLASH_SIZE - 1,
.flags = IORESOURCE_MEM,
},
-};
-#ifdef CONFIG_REALVIEW_PB1176_SECURE_FLASH
-#define PB1176_FLASH_BLOCKS 2
-#else
-#define PB1176_FLASH_BLOCKS 1
#endif
+};
+
+static struct physmap_flash_data pb1176_rom_pdata = {
+ .probe_type = "map_rom",
+ .width = 4,
+ .nr_parts = 0,
+};
+
+static struct resource pb1176_rom_resources[] = {
+ /*
+ * This exposes the PB1176 DevChip ROM as an MTD ROM mapping.
+ * The reference manual states that this is actually a pseudo-ROM
+ * programmed in NVRAM.
+ */
+ {
+ .start = REALVIEW_DC1176_ROM_BASE,
+ .end = REALVIEW_DC1176_ROM_BASE + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device pb1176_rom_device = {
+ .name = "physmap-flash",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(pb1176_rom_resources),
+ .resource = pb1176_rom_resources,
+ .dev = {
+ .platform_data = &pb1176_rom_pdata,
+ },
+};
static struct resource realview_pb1176_smsc911x_resources[] = {
[0] = {
@@ -316,8 +344,7 @@ static void realview_pb1176_reset(char mode)
__raw_writel(REALVIEW_PB1176_SYS_SOFT_RESET, reset_ctrl);
}
-static void realview_pb1176_fixup(struct machine_desc *mdesc,
- struct tag *tags, char **from,
+static void realview_pb1176_fixup(struct tag *tags, char **from,
struct meminfo *meminfo)
{
/*
@@ -338,7 +365,8 @@ static void __init realview_pb1176_init(void)
#endif
realview_flash_register(realview_pb1176_flash_resources,
- PB1176_FLASH_BLOCKS);
+ ARRAY_SIZE(realview_pb1176_flash_resources));
+ platform_device_register(&pb1176_rom_device);
realview_eth_register(NULL, realview_pb1176_smsc911x_resources);
platform_device_register(&realview_i2c_device);
realview_usb_register(realview_pb1176_isp1761_resources);
diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c
index 363b0ab56150..3e1eb2eb8132 100644
--- a/arch/arm/mach-realview/realview_pbx.c
+++ b/arch/arm/mach-realview/realview_pbx.c
@@ -319,8 +319,8 @@ static struct sys_timer realview_pbx_timer = {
.init = realview_pbx_timer_init,
};
-static void realview_pbx_fixup(struct machine_desc *mdesc, struct tag *tags,
- char **from, struct meminfo *meminfo)
+static void realview_pbx_fixup(struct tag *tags, char **from,
+ struct meminfo *meminfo)
{
#ifdef CONFIG_SPARSEMEM
/*
@@ -335,7 +335,7 @@ static void realview_pbx_fixup(struct machine_desc *mdesc, struct tag *tags,
meminfo->bank[2].size = SZ_256M;
meminfo->nr_banks = 3;
#else
- realview_fixup(mdesc, tags, from, meminfo);
+ realview_fixup(tags, from, meminfo);
#endif
}
diff --git a/arch/arm/mach-rpc/Makefile.boot b/arch/arm/mach-rpc/Makefile.boot
index 9c9e7685ec7c..ae2df0d7d037 100644
--- a/arch/arm/mach-rpc/Makefile.boot
+++ b/arch/arm/mach-rpc/Makefile.boot
@@ -1,4 +1,4 @@
- zreladdr-y := 0x10008000
+ zreladdr-y += 0x10008000
params_phys-y := 0x10000100
initrd_phys-y := 0x18000000
diff --git a/arch/arm/mach-rpc/include/mach/hardware.h b/arch/arm/mach-rpc/include/mach/hardware.h
index dde6b3c0e299..050d63c74cc1 100644
--- a/arch/arm/mach-rpc/include/mach/hardware.h
+++ b/arch/arm/mach-rpc/include/mach/hardware.h
@@ -36,7 +36,7 @@
#define EASI_SIZE 0x08000000 /* EASI I/O */
#define EASI_START 0x08000000
-#define EASI_BASE 0xe5000000
+#define EASI_BASE IOMEM(0xe5000000)
#define IO_START 0x03000000 /* I/O */
#define IO_SIZE 0x01000000
@@ -51,21 +51,20 @@
/*
* IO Addresses
*/
-#define VIDC_BASE IOMEM(0xe0400000)
-#define EXPMASK_BASE 0xe0360000
-#define IOMD_BASE IOMEM(0xe0200000)
-#define IOC_BASE IOMEM(0xe0200000)
-#define PCIO_BASE IOMEM(0xe0010000)
-#define FLOPPYDMA_BASE IOMEM(0xe002a000)
+#define ECARD_EASI_BASE (EASI_BASE)
+#define VIDC_BASE (IO_BASE + 0x00400000)
+#define EXPMASK_BASE (IO_BASE + 0x00360000)
+#define ECARD_IOC4_BASE (IO_BASE + 0x00270000)
+#define ECARD_IOC_BASE (IO_BASE + 0x00240000)
+#define IOMD_BASE (IO_BASE + 0x00200000)
+#define IOC_BASE (IO_BASE + 0x00200000)
+#define ECARD_MEMC8_BASE (IO_BASE + 0x0002b000)
+#define FLOPPYDMA_BASE (IO_BASE + 0x0002a000)
+#define PCIO_BASE (IO_BASE + 0x00010000)
+#define ECARD_MEMC_BASE (IO_BASE + 0x00000000)
#define vidc_writel(val) __raw_writel(val, VIDC_BASE)
-#define IO_EC_EASI_BASE 0x81400000
-#define IO_EC_IOC4_BASE 0x8009c000
-#define IO_EC_IOC_BASE 0x80090000
-#define IO_EC_MEMC8_BASE 0x8000ac00
-#define IO_EC_MEMC_BASE 0x80000000
-
#define NETSLOT_BASE 0x0302b000
#define NETSLOT_SIZE 0x00001000
diff --git a/arch/arm/mach-rpc/include/mach/io.h b/arch/arm/mach-rpc/include/mach/io.h
index 20da7f486e51..695f4ed2e11b 100644
--- a/arch/arm/mach-rpc/include/mach/io.h
+++ b/arch/arm/mach-rpc/include/mach/io.h
@@ -15,195 +15,18 @@
#include <mach/hardware.h>
-#define IO_SPACE_LIMIT 0xffffffff
+#define IO_SPACE_LIMIT 0xffff
/*
- * We use two different types of addressing - PC style addresses, and ARM
- * addresses. PC style accesses the PC hardware with the normal PC IO
- * addresses, eg 0x3f8 for serial#1. ARM addresses are 0x80000000+
- * and are translated to the start of IO. Note that all addresses are
- * shifted left!
- */
-#define __PORT_PCIO(x) (!((x) & 0x80000000))
-
-/*
- * Dynamic IO functions.
- */
-static inline void __outb (unsigned int value, unsigned int port)
-{
- unsigned long temp;
- __asm__ __volatile__(
- "tst %2, #0x80000000\n\t"
- "mov %0, %4\n\t"
- "addeq %0, %0, %3\n\t"
- "strb %1, [%0, %2, lsl #2] @ outb"
- : "=&r" (temp)
- : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
- : "cc");
-}
-
-static inline void __outw (unsigned int value, unsigned int port)
-{
- unsigned long temp;
- __asm__ __volatile__(
- "tst %2, #0x80000000\n\t"
- "mov %0, %4\n\t"
- "addeq %0, %0, %3\n\t"
- "str %1, [%0, %2, lsl #2] @ outw"
- : "=&r" (temp)
- : "r" (value|value<<16), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
- : "cc");
-}
-
-static inline void __outl (unsigned int value, unsigned int port)
-{
- unsigned long temp;
- __asm__ __volatile__(
- "tst %2, #0x80000000\n\t"
- "mov %0, %4\n\t"
- "addeq %0, %0, %3\n\t"
- "str %1, [%0, %2, lsl #2] @ outl"
- : "=&r" (temp)
- : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
- : "cc");
-}
-
-#define DECLARE_DYN_IN(sz,fnsuffix,instr) \
-static inline unsigned sz __in##fnsuffix (unsigned int port) \
-{ \
- unsigned long temp, value; \
- __asm__ __volatile__( \
- "tst %2, #0x80000000\n\t" \
- "mov %0, %4\n\t" \
- "addeq %0, %0, %3\n\t" \
- "ldr" instr " %1, [%0, %2, lsl #2] @ in" #fnsuffix \
- : "=&r" (temp), "=r" (value) \
- : "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE) \
- : "cc"); \
- return (unsigned sz)value; \
-}
-
-static inline void __iomem *__deprecated __ioaddr(unsigned int port)
-{
- void __iomem *ret;
- if (__PORT_PCIO(port))
- ret = PCIO_BASE;
- else
- ret = IO_BASE;
- return ret + (port << 2);
-}
-
-#define DECLARE_IO(sz,fnsuffix,instr) \
- DECLARE_DYN_IN(sz,fnsuffix,instr)
-
-DECLARE_IO(char,b,"b")
-DECLARE_IO(short,w,"")
-DECLARE_IO(int,l,"")
-
-#undef DECLARE_IO
-#undef DECLARE_DYN_IN
-
-/*
- * Constant address IO functions
+ * We need PC style IO addressing for:
+ * - floppy (at 0x3f2,0x3f4,0x3f5,0x3f7)
+ * - parport (at 0x278-0x27a, 0x27b-0x27f, 0x778-0x77a)
+ * - 8250 serial (only for compile)
*
- * These have to be macros for the 'J' constraint to work -
- * +/-4096 immediate operand.
+ * These peripherals are found in an area of MMIO which looks very much
+ * like an ISA bus, but with registers at the low byte of each word.
*/
-#define __outbc(value,port) \
-({ \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "strb %0, [%1, %2] @ outbc" \
- : : "r" (value), "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "strb %0, [%1, %2] @ outbc" \
- : : "r" (value), "r" (IO_BASE), "r" ((port) << 2)); \
-})
-
-#define __inbc(port) \
-({ \
- unsigned char result; \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "ldrb %0, [%1, %2] @ inbc" \
- : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "ldrb %0, [%1, %2] @ inbc" \
- : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2)); \
- result; \
-})
-
-#define __outwc(value,port) \
-({ \
- unsigned long __v = value; \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "str %0, [%1, %2] @ outwc" \
- : : "r" (__v|__v<<16), "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "str %0, [%1, %2] @ outwc" \
- : : "r" (__v|__v<<16), "r" (IO_BASE), "r" ((port) << 2)); \
-})
-
-#define __inwc(port) \
-({ \
- unsigned short result; \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "ldr %0, [%1, %2] @ inwc" \
- : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "ldr %0, [%1, %2] @ inwc" \
- : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2)); \
- result & 0xffff; \
-})
-
-#define __outlc(value,port) \
-({ \
- unsigned long __v = value; \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "str %0, [%1, %2] @ outlc" \
- : : "r" (__v), "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "str %0, [%1, %2] @ outlc" \
- : : "r" (__v), "r" (IO_BASE), "r" ((port) << 2)); \
-})
-
-#define __inlc(port) \
-({ \
- unsigned long result; \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "ldr %0, [%1, %2] @ inlc" \
- : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "ldr %0, [%1, %2] @ inlc" \
- : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2)); \
- result; \
-})
-
-#define inb(p) (__builtin_constant_p((p)) ? __inbc(p) : __inb(p))
-#define inw(p) (__builtin_constant_p((p)) ? __inwc(p) : __inw(p))
-#define inl(p) (__builtin_constant_p((p)) ? __inlc(p) : __inl(p))
-#define outb(v,p) (__builtin_constant_p((p)) ? __outbc(v,p) : __outb(v,p))
-#define outw(v,p) (__builtin_constant_p((p)) ? __outwc(v,p) : __outw(v,p))
-#define outl(v,p) (__builtin_constant_p((p)) ? __outlc(v,p) : __outl(v,p))
-
-/* the following macro is deprecated */
-#define ioaddr(port) ((unsigned long)__ioaddr((port)))
-
-#define insb(p,d,l) __raw_readsb(__ioaddr(p),d,l)
-#define insw(p,d,l) __raw_readsw(__ioaddr(p),d,l)
-
-#define outsb(p,d,l) __raw_writesb(__ioaddr(p),d,l)
-#define outsw(p,d,l) __raw_writesw(__ioaddr(p),d,l)
+#define __io(a) (PCIO_BASE + ((a) << 2))
/*
* 1:1 mapping for ioremapped regions.
diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c
index 580b3c73d2c7..1e0e60d04622 100644
--- a/arch/arm/mach-rpc/riscpc.c
+++ b/arch/arm/mach-rpc/riscpc.c
@@ -74,7 +74,7 @@ static struct map_desc rpc_io_desc[] __initdata = {
.length = IO_SIZE ,
.type = MT_DEVICE
}, { /* EASI space */
- .virtual = EASI_BASE,
+ .virtual = (unsigned long)EASI_BASE,
.pfn = __phys_to_pfn(EASI_START),
.length = EASI_SIZE,
.type = MT_DEVICE
diff --git a/arch/arm/mach-s3c2410/Makefile.boot b/arch/arm/mach-s3c2410/Makefile.boot
index 58c1dd7f8e1d..4457605ba04a 100644
--- a/arch/arm/mach-s3c2410/Makefile.boot
+++ b/arch/arm/mach-s3c2410/Makefile.boot
@@ -1,7 +1,7 @@
ifeq ($(CONFIG_PM_H1940),y)
- zreladdr-y := 0x30108000
+ zreladdr-y += 0x30108000
params_phys-y := 0x30100100
else
- zreladdr-y := 0x30008000
+ zreladdr-y += 0x30008000
params_phys-y := 0x30000100
endif
diff --git a/arch/arm/mach-s3c2410/include/mach/io.h b/arch/arm/mach-s3c2410/include/mach/io.h
index 9813dbf2ae4f..118749f37c4c 100644
--- a/arch/arm/mach-s3c2410/include/mach/io.h
+++ b/arch/arm/mach-s3c2410/include/mach/io.h
@@ -199,8 +199,6 @@ DECLARE_IO(int,l,"")
#define outw(v,p) (__builtin_constant_p((p)) ? __outwc(v,p) : __outw(v,p))
#define outl(v,p) (__builtin_constant_p((p)) ? __outlc(v,p) : __outl(v,p))
#define __ioaddr(p) (__builtin_constant_p((p)) ? __ioaddr(p) : __ioaddrc(p))
-/* the following macro is deprecated */
-#define ioaddr(port) __ioaddr((port))
#define insb(p,d,l) __raw_readsb(__ioaddr(p),d,l)
#define insw(p,d,l) __raw_readsw(__ioaddr(p),d,l)
diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c
index f1d3bd8f6f17..343a540d86a9 100644
--- a/arch/arm/mach-s3c2410/s3c2410.c
+++ b/arch/arm/mach-s3c2410/s3c2410.c
@@ -170,7 +170,9 @@ int __init s3c2410_init(void)
{
printk("S3C2410: Initialising architecture\n");
+#ifdef CONFIG_PM
register_syscore_ops(&s3c2410_pm_syscore_ops);
+#endif
register_syscore_ops(&s3c24xx_irq_syscore_ops);
return sysdev_register(&s3c2410_sysdev);
diff --git a/arch/arm/mach-s3c2412/mach-smdk2413.c b/arch/arm/mach-s3c2412/mach-smdk2413.c
index 834cfb61bcfe..3391713e0c92 100644
--- a/arch/arm/mach-s3c2412/mach-smdk2413.c
+++ b/arch/arm/mach-s3c2412/mach-smdk2413.c
@@ -92,8 +92,7 @@ static struct platform_device *smdk2413_devices[] __initdata = {
&s3c_device_usbgadget,
};
-static void __init smdk2413_fixup(struct machine_desc *desc,
- struct tag *tags, char **cmdline,
+static void __init smdk2413_fixup(struct tag *tags, char **cmdline,
struct meminfo *mi)
{
if (tags != phys_to_virt(S3C2410_SDRAM_PA + 0x100)) {
diff --git a/arch/arm/mach-s3c2412/mach-vstms.c b/arch/arm/mach-s3c2412/mach-vstms.c
index 83544ebe20ac..b6ed4573553a 100644
--- a/arch/arm/mach-s3c2412/mach-vstms.c
+++ b/arch/arm/mach-s3c2412/mach-vstms.c
@@ -129,9 +129,8 @@ static struct platform_device *vstms_devices[] __initdata = {
&s3c_device_nand,
};
-static void __init vstms_fixup(struct machine_desc *desc,
- struct tag *tags, char **cmdline,
- struct meminfo *mi)
+static void __init vstms_fixup(struct tag *tags, char **cmdline,
+ struct meminfo *mi)
{
if (tags != phys_to_virt(S3C2410_SDRAM_PA + 0x100)) {
mi->nr_banks=1;
diff --git a/arch/arm/mach-s3c2412/s3c2412.c b/arch/arm/mach-s3c2412/s3c2412.c
index ef0958d3e5c6..57a1e01e4e50 100644
--- a/arch/arm/mach-s3c2412/s3c2412.c
+++ b/arch/arm/mach-s3c2412/s3c2412.c
@@ -245,7 +245,9 @@ int __init s3c2412_init(void)
{
printk("S3C2412: Initialising architecture\n");
+#ifdef CONFIG_PM
register_syscore_ops(&s3c2412_pm_syscore_ops);
+#endif
register_syscore_ops(&s3c24xx_irq_syscore_ops);
return sysdev_register(&s3c2412_sysdev);
diff --git a/arch/arm/mach-s3c2416/s3c2416.c b/arch/arm/mach-s3c2416/s3c2416.c
index 494ce913dc95..20b3fdfb3051 100644
--- a/arch/arm/mach-s3c2416/s3c2416.c
+++ b/arch/arm/mach-s3c2416/s3c2416.c
@@ -97,7 +97,9 @@ int __init s3c2416_init(void)
s3c_fb_setname("s3c2443-fb");
+#ifdef CONFIG_PM
register_syscore_ops(&s3c2416_pm_syscore_ops);
+#endif
register_syscore_ops(&s3c24xx_irq_syscore_ops);
return sysdev_register(&s3c2416_sysdev);
diff --git a/arch/arm/mach-s3c2440/s3c2440.c b/arch/arm/mach-s3c2440/s3c2440.c
index ce99ff72838d..2270d3360216 100644
--- a/arch/arm/mach-s3c2440/s3c2440.c
+++ b/arch/arm/mach-s3c2440/s3c2440.c
@@ -55,7 +55,9 @@ int __init s3c2440_init(void)
/* register suspend/resume handlers */
+#ifdef CONFIG_PM
register_syscore_ops(&s3c2410_pm_syscore_ops);
+#endif
register_syscore_ops(&s3c244x_pm_syscore_ops);
register_syscore_ops(&s3c24xx_irq_syscore_ops);
diff --git a/arch/arm/mach-s3c2440/s3c2442.c b/arch/arm/mach-s3c2440/s3c2442.c
index 9ad99f8016a1..6f2b65e6e068 100644
--- a/arch/arm/mach-s3c2440/s3c2442.c
+++ b/arch/arm/mach-s3c2440/s3c2442.c
@@ -169,7 +169,9 @@ int __init s3c2442_init(void)
{
printk("S3C2442: Initialising architecture\n");
+#ifdef CONFIG_PM
register_syscore_ops(&s3c2410_pm_syscore_ops);
+#endif
register_syscore_ops(&s3c244x_pm_syscore_ops);
register_syscore_ops(&s3c24xx_irq_syscore_ops);
diff --git a/arch/arm/mach-s3c2443/clock.c b/arch/arm/mach-s3c2443/clock.c
index a1a7176675b9..38058af48972 100644
--- a/arch/arm/mach-s3c2443/clock.c
+++ b/arch/arm/mach-s3c2443/clock.c
@@ -128,7 +128,7 @@ static int s3c2443_armclk_setrate(struct clk *clk, unsigned long rate)
unsigned long clkcon0;
clkcon0 = __raw_readl(S3C2443_CLKDIV0);
- clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK;
+ clkcon0 &= ~S3C2443_CLKDIV0_ARMDIV_MASK;
clkcon0 |= val << S3C2443_CLKDIV0_ARMDIV_SHIFT;
__raw_writel(clkcon0, S3C2443_CLKDIV0);
}
diff --git a/arch/arm/mach-s3c64xx/Makefile.boot b/arch/arm/mach-s3c64xx/Makefile.boot
index ba41fdc0a586..c642333af3ed 100644
--- a/arch/arm/mach-s3c64xx/Makefile.boot
+++ b/arch/arm/mach-s3c64xx/Makefile.boot
@@ -1,2 +1,2 @@
- zreladdr-y := 0x50008000
+ zreladdr-y += 0x50008000
params_phys-y := 0x50000100
diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c
index ecbea92bf83b..a9f3183e0290 100644
--- a/arch/arm/mach-s3c64xx/mach-smdk6410.c
+++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c
@@ -262,45 +262,6 @@ static struct samsung_keypad_platdata smdk6410_keypad_data __initdata = {
.cols = 8,
};
-static int smdk6410_backlight_init(struct device *dev)
-{
- int ret;
-
- ret = gpio_request(S3C64XX_GPF(15), "Backlight");
- if (ret) {
- printk(KERN_ERR "failed to request GPF for PWM-OUT1\n");
- return ret;
- }
-
- /* Configure GPIO pin with S3C64XX_GPF15_PWM_TOUT1 */
- s3c_gpio_cfgpin(S3C64XX_GPF(15), S3C_GPIO_SFN(2));
-
- return 0;
-}
-
-static void smdk6410_backlight_exit(struct device *dev)
-{
- s3c_gpio_cfgpin(S3C64XX_GPF(15), S3C_GPIO_OUTPUT);
- gpio_free(S3C64XX_GPF(15));
-}
-
-static struct platform_pwm_backlight_data smdk6410_backlight_data = {
- .pwm_id = 1,
- .max_brightness = 255,
- .dft_brightness = 255,
- .pwm_period_ns = 78770,
- .init = smdk6410_backlight_init,
- .exit = smdk6410_backlight_exit,
-};
-
-static struct platform_device smdk6410_backlight_device = {
- .name = "pwm-backlight",
- .dev = {
- .parent = &s3c_device_timer[1].dev,
- .platform_data = &smdk6410_backlight_data,
- },
-};
-
static struct map_desc smdk6410_iodesc[] = {};
static struct platform_device *smdk6410_devices[] __initdata = {
diff --git a/arch/arm/mach-s3c64xx/pm.c b/arch/arm/mach-s3c64xx/pm.c
index 8bad64370689..055e2858b0dd 100644
--- a/arch/arm/mach-s3c64xx/pm.c
+++ b/arch/arm/mach-s3c64xx/pm.c
@@ -16,6 +16,7 @@
#include <linux/suspend.h>
#include <linux/serial_core.h>
#include <linux/io.h>
+#include <linux/gpio.h>
#include <mach/map.h>
#include <mach/irqs.h>
diff --git a/arch/arm/mach-s5p64x0/Makefile.boot b/arch/arm/mach-s5p64x0/Makefile.boot
index ff90aa13bd67..79ece4055b02 100644
--- a/arch/arm/mach-s5p64x0/Makefile.boot
+++ b/arch/arm/mach-s5p64x0/Makefile.boot
@@ -1,2 +1,2 @@
- zreladdr-y := 0x20008000
+ zreladdr-y += 0x20008000
params_phys-y := 0x20000100
diff --git a/arch/arm/mach-s5p64x0/irq-eint.c b/arch/arm/mach-s5p64x0/irq-eint.c
index 69ed4545112b..fe7380f5c3cd 100644
--- a/arch/arm/mach-s5p64x0/irq-eint.c
+++ b/arch/arm/mach-s5p64x0/irq-eint.c
@@ -129,7 +129,7 @@ static int s5p64x0_alloc_gc(void)
}
ct = gc->chip_types;
- ct->chip.irq_ack = irq_gc_ack;
+ ct->chip.irq_ack = irq_gc_ack_set_bit;
ct->chip.irq_mask = irq_gc_mask_set_bit;
ct->chip.irq_unmask = irq_gc_mask_clr_bit;
ct->chip.irq_set_type = s5p64x0_irq_eint_set_type;
diff --git a/arch/arm/mach-s5pc100/Makefile.boot b/arch/arm/mach-s5pc100/Makefile.boot
index ff90aa13bd67..79ece4055b02 100644
--- a/arch/arm/mach-s5pc100/Makefile.boot
+++ b/arch/arm/mach-s5pc100/Makefile.boot
@@ -1,2 +1,2 @@
- zreladdr-y := 0x20008000
+ zreladdr-y += 0x20008000
params_phys-y := 0x20000100
diff --git a/arch/arm/mach-s5pv210/Makefile.boot b/arch/arm/mach-s5pv210/Makefile.boot
index ff90aa13bd67..79ece4055b02 100644
--- a/arch/arm/mach-s5pv210/Makefile.boot
+++ b/arch/arm/mach-s5pv210/Makefile.boot
@@ -1,2 +1,2 @@
- zreladdr-y := 0x20008000
+ zreladdr-y += 0x20008000
params_phys-y := 0x20000100
diff --git a/arch/arm/mach-s5pv210/clock.c b/arch/arm/mach-s5pv210/clock.c
index 52a8e607bcc2..f5f8fa89679c 100644
--- a/arch/arm/mach-s5pv210/clock.c
+++ b/arch/arm/mach-s5pv210/clock.c
@@ -815,8 +815,7 @@ static struct clksrc_clk clksrcs[] = {
.reg_div = { .reg = S5P_CLK_DIV3, .shift = 20, .size = 4 },
}, {
.clk = {
- .name = "sclk_cam",
- .devname = "s5pv210-fimc.0",
+ .name = "sclk_cam0",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 3),
},
@@ -825,8 +824,7 @@ static struct clksrc_clk clksrcs[] = {
.reg_div = { .reg = S5P_CLK_DIV1, .shift = 12, .size = 4 },
}, {
.clk = {
- .name = "sclk_cam",
- .devname = "s5pv210-fimc.1",
+ .name = "sclk_cam1",
.enable = s5pv210_clk_mask0_ctrl,
.ctrlbit = (1 << 4),
},
diff --git a/arch/arm/mach-s5pv210/pm.c b/arch/arm/mach-s5pv210/pm.c
index 309e388a8a83..f149d278377b 100644
--- a/arch/arm/mach-s5pv210/pm.c
+++ b/arch/arm/mach-s5pv210/pm.c
@@ -88,7 +88,7 @@ static struct sleep_save s5pv210_core_save[] = {
SAVE_ITEM(S3C2410_TCNTO(0)),
};
-void s5pv210_cpu_suspend(unsigned long arg)
+static int s5pv210_cpu_suspend(unsigned long arg)
{
unsigned long tmp;
diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile
index 41252d22e659..00631787e80a 100644
--- a/arch/arm/mach-sa1100/Makefile
+++ b/arch/arm/mach-sa1100/Makefile
@@ -45,7 +45,6 @@ obj-$(CONFIG_SA1100_PLEB) += pleb.o
obj-$(CONFIG_SA1100_SHANNON) += shannon.o
obj-$(CONFIG_SA1100_SIMPAD) += simpad.o
-led-$(CONFIG_SA1100_SIMPAD) += leds-simpad.o
# LEDs support
obj-$(CONFIG_LEDS) += $(led-y)
diff --git a/arch/arm/mach-sa1100/Makefile.boot b/arch/arm/mach-sa1100/Makefile.boot
index a56ad0417cf2..5a616f6e5612 100644
--- a/arch/arm/mach-sa1100/Makefile.boot
+++ b/arch/arm/mach-sa1100/Makefile.boot
@@ -1,6 +1,7 @@
- zreladdr-y := 0xc0008000
ifeq ($(CONFIG_ARCH_SA1100),y)
- zreladdr-$(CONFIG_SA1111) := 0xc0208000
+ zreladdr-$(CONFIG_SA1111) += 0xc0208000
+else
+ zreladdr-y += 0xc0008000
endif
params_phys-y := 0xc0000100
initrd_phys-y := 0xc0800000
diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index 26257df19b63..6290ce28b883 100644
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -301,8 +301,7 @@ static void __init get_assabet_scr(void)
}
static void __init
-fixup_assabet(struct machine_desc *desc, struct tag *tags,
- char **cmdline, struct meminfo *mi)
+fixup_assabet(struct tag *tags, char **cmdline, struct meminfo *mi)
{
/* This must be done before any call to machine_has_neponset() */
map_sa1100_gpio_regs();
diff --git a/arch/arm/mach-sa1100/include/mach/io.h b/arch/arm/mach-sa1100/include/mach/io.h
index d8b43f3dcd2d..dfc27ff08344 100644
--- a/arch/arm/mach-sa1100/include/mach/io.h
+++ b/arch/arm/mach-sa1100/include/mach/io.h
@@ -10,11 +10,9 @@
#ifndef __ASM_ARM_ARCH_IO_H
#define __ASM_ARM_ARCH_IO_H
-#define IO_SPACE_LIMIT 0xffffffff
-
/*
- * We don't actually have real ISA nor PCI buses, but there is so many
- * drivers out there that might just work if we fake them...
+ * __io() is required to be an equivalent mapping to __mem_pci() for
+ * SOC_COMMON to work.
*/
#define __io(a) __typesafe_io(a)
#define __mem_pci(a) (a)
diff --git a/arch/arm/mach-sa1100/include/mach/simpad.h b/arch/arm/mach-sa1100/include/mach/simpad.h
index 9296c4513ce1..db28118103eb 100644
--- a/arch/arm/mach-sa1100/include/mach/simpad.h
+++ b/arch/arm/mach-sa1100/include/mach/simpad.h
@@ -48,32 +48,80 @@
#define GPIO_SMART_CARD GPIO_GPIO10
#define IRQ_GPIO_SMARD_CARD IRQ_GPIO10
-// CS3 Latch is write only, a shadow is necessary
+/*--- ucb1x00 GPIO ---*/
+#define SIMPAD_UCB1X00_GPIO_BASE (GPIO_MAX + 1)
+#define SIMPAD_UCB1X00_GPIO_PROG1 (SIMPAD_UCB1X00_GPIO_BASE)
+#define SIMPAD_UCB1X00_GPIO_PROG2 (SIMPAD_UCB1X00_GPIO_BASE + 1)
+#define SIMPAD_UCB1X00_GPIO_UP (SIMPAD_UCB1X00_GPIO_BASE + 2)
+#define SIMPAD_UCB1X00_GPIO_DOWN (SIMPAD_UCB1X00_GPIO_BASE + 3)
+#define SIMPAD_UCB1X00_GPIO_LEFT (SIMPAD_UCB1X00_GPIO_BASE + 4)
+#define SIMPAD_UCB1X00_GPIO_RIGHT (SIMPAD_UCB1X00_GPIO_BASE + 5)
+#define SIMPAD_UCB1X00_GPIO_6 (SIMPAD_UCB1X00_GPIO_BASE + 6)
+#define SIMPAD_UCB1X00_GPIO_7 (SIMPAD_UCB1X00_GPIO_BASE + 7)
+#define SIMPAD_UCB1X00_GPIO_HEADSET (SIMPAD_UCB1X00_GPIO_BASE + 8)
+#define SIMPAD_UCB1X00_GPIO_SPEAKER (SIMPAD_UCB1X00_GPIO_BASE + 9)
+
+/*--- CS3 Latch ---*/
+#define SIMPAD_CS3_GPIO_BASE (GPIO_MAX + 11)
+#define SIMPAD_CS3_VCC_5V_EN (SIMPAD_CS3_GPIO_BASE)
+#define SIMPAD_CS3_VCC_3V_EN (SIMPAD_CS3_GPIO_BASE + 1)
+#define SIMPAD_CS3_EN1 (SIMPAD_CS3_GPIO_BASE + 2)
+#define SIMPAD_CS3_EN0 (SIMPAD_CS3_GPIO_BASE + 3)
+#define SIMPAD_CS3_DISPLAY_ON (SIMPAD_CS3_GPIO_BASE + 4)
+#define SIMPAD_CS3_PCMCIA_BUFF_DIS (SIMPAD_CS3_GPIO_BASE + 5)
+#define SIMPAD_CS3_MQ_RESET (SIMPAD_CS3_GPIO_BASE + 6)
+#define SIMPAD_CS3_PCMCIA_RESET (SIMPAD_CS3_GPIO_BASE + 7)
+#define SIMPAD_CS3_DECT_POWER_ON (SIMPAD_CS3_GPIO_BASE + 8)
+#define SIMPAD_CS3_IRDA_SD (SIMPAD_CS3_GPIO_BASE + 9)
+#define SIMPAD_CS3_RS232_ON (SIMPAD_CS3_GPIO_BASE + 10)
+#define SIMPAD_CS3_SD_MEDIAQ (SIMPAD_CS3_GPIO_BASE + 11)
+#define SIMPAD_CS3_LED2_ON (SIMPAD_CS3_GPIO_BASE + 12)
+#define SIMPAD_CS3_IRDA_MODE (SIMPAD_CS3_GPIO_BASE + 13)
+#define SIMPAD_CS3_ENABLE_5V (SIMPAD_CS3_GPIO_BASE + 14)
+#define SIMPAD_CS3_RESET_SIMCARD (SIMPAD_CS3_GPIO_BASE + 15)
+
+#define SIMPAD_CS3_PCMCIA_BVD1 (SIMPAD_CS3_GPIO_BASE + 16)
+#define SIMPAD_CS3_PCMCIA_BVD2 (SIMPAD_CS3_GPIO_BASE + 17)
+#define SIMPAD_CS3_PCMCIA_VS1 (SIMPAD_CS3_GPIO_BASE + 18)
+#define SIMPAD_CS3_PCMCIA_VS2 (SIMPAD_CS3_GPIO_BASE + 19)
+#define SIMPAD_CS3_LOCK_IND (SIMPAD_CS3_GPIO_BASE + 20)
+#define SIMPAD_CS3_CHARGING_STATE (SIMPAD_CS3_GPIO_BASE + 21)
+#define SIMPAD_CS3_PCMCIA_SHORT (SIMPAD_CS3_GPIO_BASE + 22)
+#define SIMPAD_CS3_GPIO_23 (SIMPAD_CS3_GPIO_BASE + 23)
-#define CS3BUSTYPE unsigned volatile long
#define CS3_BASE 0xf1000000
-#define VCC_5V_EN 0x0001 // For 5V PCMCIA
-#define VCC_3V_EN 0x0002 // FOR 3.3V PCMCIA
-#define EN1 0x0004 // This is only for EPROM's
-#define EN0 0x0008 // Both should be enable for 3.3V or 5V
-#define DISPLAY_ON 0x0010
-#define PCMCIA_BUFF_DIS 0x0020
-#define MQ_RESET 0x0040
-#define PCMCIA_RESET 0x0080
-#define DECT_POWER_ON 0x0100
-#define IRDA_SD 0x0200 // Shutdown for powersave
-#define RS232_ON 0x0400
-#define SD_MEDIAQ 0x0800 // Shutdown for powersave
-#define LED2_ON 0x1000
-#define IRDA_MODE 0x2000 // Fast/Slow IrDA mode
-#define ENABLE_5V 0x4000 // Enable 5V circuit
-#define RESET_SIMCARD 0x8000
-
-#define RS232_ENABLE 0x0440
-#define PCMCIAMASK 0x402f
-
-
+long simpad_get_cs3_ro(void);
+long simpad_get_cs3_shadow(void);
+void simpad_set_cs3_bit(int value);
+void simpad_clear_cs3_bit(int value);
+
+#define VCC_5V_EN 0x0001 /* For 5V PCMCIA */
+#define VCC_3V_EN 0x0002 /* FOR 3.3V PCMCIA */
+#define EN1 0x0004 /* This is only for EPROM's */
+#define EN0 0x0008 /* Both should be enable for 3.3V or 5V */
+#define DISPLAY_ON 0x0010
+#define PCMCIA_BUFF_DIS 0x0020
+#define MQ_RESET 0x0040
+#define PCMCIA_RESET 0x0080
+#define DECT_POWER_ON 0x0100
+#define IRDA_SD 0x0200 /* Shutdown for powersave */
+#define RS232_ON 0x0400
+#define SD_MEDIAQ 0x0800 /* Shutdown for powersave */
+#define LED2_ON 0x1000
+#define IRDA_MODE 0x2000 /* Fast/Slow IrDA mode */
+#define ENABLE_5V 0x4000 /* Enable 5V circuit */
+#define RESET_SIMCARD 0x8000
+
+#define PCMCIA_BVD1 0x01
+#define PCMCIA_BVD2 0x02
+#define PCMCIA_VS1 0x04
+#define PCMCIA_VS2 0x08
+#define LOCK_IND 0x10
+#define CHARGING_STATE 0x20
+#define PCMCIA_SHORT 0x40
+
+/*--- Battery ---*/
struct simpad_battery {
unsigned char ac_status; /* line connected yes/no */
unsigned char status; /* battery loading yes/no */
diff --git a/arch/arm/mach-sa1100/leds-simpad.c b/arch/arm/mach-sa1100/leds-simpad.c
deleted file mode 100644
index d50f4eeaa12e..000000000000
--- a/arch/arm/mach-sa1100/leds-simpad.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * linux/arch/arm/mach-sa1100/leds-simpad.c
- *
- * Author: Juergen Messerer <juergen.messerer@siemens.ch>
- */
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-#include <asm/system.h>
-#include <mach/simpad.h>
-
-#include "leds.h"
-
-
-#define LED_STATE_ENABLED 1
-#define LED_STATE_CLAIMED 2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-#define LED_GREEN (1)
-#define LED_MASK (1)
-
-extern void set_cs3_bit(int value);
-extern void clear_cs3_bit(int value);
-
-void simpad_leds_event(led_event_t evt)
-{
- switch (evt)
- {
- case led_start:
- hw_led_state = LED_GREEN;
- led_state = LED_STATE_ENABLED;
- break;
-
- case led_stop:
- led_state &= ~LED_STATE_ENABLED;
- break;
-
- case led_claim:
- led_state |= LED_STATE_CLAIMED;
- hw_led_state = LED_GREEN;
- break;
-
- case led_release:
- led_state &= ~LED_STATE_CLAIMED;
- hw_led_state = LED_GREEN;
- break;
-
-#ifdef CONFIG_LEDS_TIMER
- case led_timer:
- if (!(led_state & LED_STATE_CLAIMED))
- hw_led_state ^= LED_GREEN;
- break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
- case led_idle_start:
- break;
-
- case led_idle_end:
- break;
-#endif
-
- case led_halted:
- break;
-
- case led_green_on:
- if (led_state & LED_STATE_CLAIMED)
- hw_led_state |= LED_GREEN;
- break;
-
- case led_green_off:
- if (led_state & LED_STATE_CLAIMED)
- hw_led_state &= ~LED_GREEN;
- break;
-
- case led_amber_on:
- break;
-
- case led_amber_off:
- break;
-
- case led_red_on:
- break;
-
- case led_red_off:
- break;
-
- default:
- break;
- }
-
- if (led_state & LED_STATE_ENABLED)
- set_cs3_bit(LED2_ON);
- else
- clear_cs3_bit(LED2_ON);
-}
-
diff --git a/arch/arm/mach-sa1100/leds.c b/arch/arm/mach-sa1100/leds.c
index bbfe197fb4d6..5fe71a0f1053 100644
--- a/arch/arm/mach-sa1100/leds.c
+++ b/arch/arm/mach-sa1100/leds.c
@@ -42,8 +42,6 @@ sa1100_leds_init(void)
leds_event = adsbitsy_leds_event;
if (machine_is_pt_system3())
leds_event = system3_leds_event;
- if (machine_is_simpad())
- leds_event = simpad_leds_event; /* what about machine registry? including led, apm... -zecke */
leds_event(led_start);
return 0;
diff --git a/arch/arm/mach-sa1100/leds.h b/arch/arm/mach-sa1100/leds.h
index 68cc9f773d6d..776b6020f550 100644
--- a/arch/arm/mach-sa1100/leds.h
+++ b/arch/arm/mach-sa1100/leds.h
@@ -11,4 +11,3 @@ extern void pfs168_leds_event(led_event_t evt);
extern void graphicsmaster_leds_event(led_event_t evt);
extern void adsbitsy_leds_event(led_event_t evt);
extern void system3_leds_event(led_event_t evt);
-extern void simpad_leds_event(led_event_t evt);
diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c
index cfb76077bd25..34659f354bef 100644
--- a/arch/arm/mach-sa1100/simpad.c
+++ b/arch/arm/mach-sa1100/simpad.c
@@ -13,6 +13,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/io.h>
+#include <linux/gpio.h>
#include <asm/irq.h>
#include <mach/hardware.h>
@@ -28,35 +29,92 @@
#include <linux/serial_core.h>
#include <linux/ioport.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/leds.h>
+#include <linux/i2c-gpio.h>
#include "generic.h"
-long cs3_shadow;
+/*
+ * CS3 support
+ */
-long get_cs3_shadow(void)
+static long cs3_shadow;
+static spinlock_t cs3_lock;
+static struct gpio_chip cs3_gpio;
+
+long simpad_get_cs3_ro(void)
+{
+ return readl(CS3_BASE);
+}
+EXPORT_SYMBOL(simpad_get_cs3_ro);
+
+long simpad_get_cs3_shadow(void)
{
return cs3_shadow;
}
+EXPORT_SYMBOL(simpad_get_cs3_shadow);
-void set_cs3(long value)
+static void __simpad_write_cs3(void)
{
- *(CS3BUSTYPE *)(CS3_BASE) = cs3_shadow = value;
+ writel(cs3_shadow, CS3_BASE);
}
-void set_cs3_bit(int value)
+void simpad_set_cs3_bit(int value)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cs3_lock, flags);
cs3_shadow |= value;
- *(CS3BUSTYPE *)(CS3_BASE) = cs3_shadow;
+ __simpad_write_cs3();
+ spin_unlock_irqrestore(&cs3_lock, flags);
}
+EXPORT_SYMBOL(simpad_set_cs3_bit);
-void clear_cs3_bit(int value)
+void simpad_clear_cs3_bit(int value)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cs3_lock, flags);
cs3_shadow &= ~value;
- *(CS3BUSTYPE *)(CS3_BASE) = cs3_shadow;
+ __simpad_write_cs3();
+ spin_unlock_irqrestore(&cs3_lock, flags);
}
+EXPORT_SYMBOL(simpad_clear_cs3_bit);
+
+static void cs3_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ if (offset > 15)
+ return;
+ if (value)
+ simpad_set_cs3_bit(1 << offset);
+ else
+ simpad_clear_cs3_bit(1 << offset);
+};
+
+static int cs3_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ if (offset > 15)
+ return simpad_get_cs3_ro() & (1 << (offset - 16));
+ return simpad_get_cs3_shadow() & (1 << offset);
+};
-EXPORT_SYMBOL(set_cs3_bit);
-EXPORT_SYMBOL(clear_cs3_bit);
+static int cs3_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ if (offset > 15)
+ return 0;
+ return -EINVAL;
+};
+
+static int cs3_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ if (offset > 15)
+ return -EINVAL;
+ cs3_gpio_set(chip, offset, value);
+ return 0;
+};
static struct map_desc simpad_io_desc[] __initdata = {
{ /* MQ200 */
@@ -64,9 +122,9 @@ static struct map_desc simpad_io_desc[] __initdata = {
.pfn = __phys_to_pfn(0x4b800000),
.length = 0x00800000,
.type = MT_DEVICE
- }, { /* Paules CS3, write only */
- .virtual = 0xf1000000,
- .pfn = __phys_to_pfn(0x18000000),
+ }, { /* Simpad CS3 */
+ .virtual = CS3_BASE,
+ .pfn = __phys_to_pfn(SA1100_CS3_PHYS),
.length = 0x00100000,
.type = MT_DEVICE
},
@@ -78,12 +136,12 @@ static void simpad_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
if (port->mapbase == (u_int)&Ser1UTCR0) {
if (state)
{
- clear_cs3_bit(RS232_ON);
- clear_cs3_bit(DECT_POWER_ON);
+ simpad_clear_cs3_bit(RS232_ON);
+ simpad_clear_cs3_bit(DECT_POWER_ON);
}else
{
- set_cs3_bit(RS232_ON);
- set_cs3_bit(DECT_POWER_ON);
+ simpad_set_cs3_bit(RS232_ON);
+ simpad_set_cs3_bit(DECT_POWER_ON);
}
}
}
@@ -132,6 +190,7 @@ static struct resource simpad_flash_resources [] = {
static struct mcp_plat_data simpad_mcp_data = {
.mccr0 = MCCR0_ADM,
.sclk_rate = 11981000,
+ .gpio_base = SIMPAD_UCB1X00_GPIO_BASE,
};
@@ -142,9 +201,10 @@ static void __init simpad_map_io(void)
iotable_init(simpad_io_desc, ARRAY_SIZE(simpad_io_desc));
- set_cs3_bit (EN1 | EN0 | LED2_ON | DISPLAY_ON | RS232_ON |
- ENABLE_5V | RESET_SIMCARD | DECT_POWER_ON);
-
+ /* Initialize CS3 */
+ cs3_shadow = (EN1 | EN0 | LED2_ON | DISPLAY_ON |
+ RS232_ON | ENABLE_5V | RESET_SIMCARD | DECT_POWER_ON);
+ __simpad_write_cs3(); /* Spinlocks not yet initialized */
sa1100_register_uart_fns(&simpad_port_fns);
sa1100_register_uart(0, 3); /* serial interface */
@@ -170,13 +230,14 @@ static void __init simpad_map_io(void)
static void simpad_power_off(void)
{
- local_irq_disable(); // was cli
- set_cs3(0x800); /* only SD_MEDIAQ */
+ local_irq_disable();
+ cs3_shadow = SD_MEDIAQ;
+ __simpad_write_cs3(); /* Bypass spinlock here */
/* disable internal oscillator, float CS lines */
PCFR = (PCFR_OPDE | PCFR_FP | PCFR_FS);
- /* enable wake-up on GPIO0 (Assabet...) */
- PWER = GFER = GRER = 1;
+ /* enable wake-up on GPIO0 */
+ PWER = GFER = GRER = PWER_GPIO0;
/*
* set scratchpad to zero, just in case it is used as a
* restart address by the bootloader.
@@ -192,6 +253,91 @@ static void simpad_power_off(void)
}
+/*
+ * gpio_keys
+*/
+
+static struct gpio_keys_button simpad_button_table[] = {
+ { KEY_POWER, IRQ_GPIO_POWER_BUTTON, 1, "power button" },
+};
+
+static struct gpio_keys_platform_data simpad_keys_data = {
+ .buttons = simpad_button_table,
+ .nbuttons = ARRAY_SIZE(simpad_button_table),
+};
+
+static struct platform_device simpad_keys = {
+ .name = "gpio-keys",
+ .dev = {
+ .platform_data = &simpad_keys_data,
+ },
+};
+
+static struct gpio_keys_button simpad_polled_button_table[] = {
+ { KEY_PROG1, SIMPAD_UCB1X00_GPIO_PROG1, 1, "prog1 button" },
+ { KEY_PROG2, SIMPAD_UCB1X00_GPIO_PROG2, 1, "prog2 button" },
+ { KEY_UP, SIMPAD_UCB1X00_GPIO_UP, 1, "up button" },
+ { KEY_DOWN, SIMPAD_UCB1X00_GPIO_DOWN, 1, "down button" },
+ { KEY_LEFT, SIMPAD_UCB1X00_GPIO_LEFT, 1, "left button" },
+ { KEY_RIGHT, SIMPAD_UCB1X00_GPIO_RIGHT, 1, "right button" },
+};
+
+static struct gpio_keys_platform_data simpad_polled_keys_data = {
+ .buttons = simpad_polled_button_table,
+ .nbuttons = ARRAY_SIZE(simpad_polled_button_table),
+ .poll_interval = 50,
+};
+
+static struct platform_device simpad_polled_keys = {
+ .name = "gpio-keys-polled",
+ .dev = {
+ .platform_data = &simpad_polled_keys_data,
+ },
+};
+
+/*
+ * GPIO LEDs
+ */
+
+static struct gpio_led simpad_leds[] = {
+ {
+ .name = "simpad:power",
+ .gpio = SIMPAD_CS3_LED2_ON,
+ .active_low = 0,
+ .default_trigger = "default-on",
+ },
+};
+
+static struct gpio_led_platform_data simpad_led_data = {
+ .num_leds = ARRAY_SIZE(simpad_leds),
+ .leds = simpad_leds,
+};
+
+static struct platform_device simpad_gpio_leds = {
+ .name = "leds-gpio",
+ .id = 0,
+ .dev = {
+ .platform_data = &simpad_led_data,
+ },
+};
+
+/*
+ * i2c
+ */
+static struct i2c_gpio_platform_data simpad_i2c_data = {
+ .sda_pin = GPIO_GPIO21,
+ .scl_pin = GPIO_GPIO25,
+ .udelay = 10,
+ .timeout = HZ,
+};
+
+static struct platform_device simpad_i2c = {
+ .name = "i2c-gpio",
+ .id = 0,
+ .dev = {
+ .platform_data = &simpad_i2c_data,
+ },
+};
/*
* MediaQ Video Device
@@ -202,7 +348,11 @@ static struct platform_device simpad_mq200fb = {
};
static struct platform_device *devices[] __initdata = {
- &simpad_mq200fb
+ &simpad_keys,
+ &simpad_polled_keys,
+ &simpad_mq200fb,
+ &simpad_gpio_leds,
+ &simpad_i2c,
};
@@ -211,6 +361,19 @@ static int __init simpad_init(void)
{
int ret;
+ spin_lock_init(&cs3_lock);
+
+ cs3_gpio.label = "simpad_cs3";
+ cs3_gpio.base = SIMPAD_CS3_GPIO_BASE;
+ cs3_gpio.ngpio = 24;
+ cs3_gpio.set = cs3_gpio_set;
+ cs3_gpio.get = cs3_gpio_get;
+ cs3_gpio.direction_input = cs3_gpio_direction_input;
+ cs3_gpio.direction_output = cs3_gpio_direction_output;
+ ret = gpiochip_add(&cs3_gpio);
+ if (ret)
+ printk(KERN_WARNING "simpad: Unable to register cs3 GPIO device");
+
pm_power_off = simpad_power_off;
sa11x0_register_mtd(&simpad_flash_data, simpad_flash_resources,
diff --git a/arch/arm/mach-shark/Makefile.boot b/arch/arm/mach-shark/Makefile.boot
index 4320f8b92771..e40e24e4ca34 100644
--- a/arch/arm/mach-shark/Makefile.boot
+++ b/arch/arm/mach-shark/Makefile.boot
@@ -1,2 +1,2 @@
- zreladdr-y := 0x08008000
+ zreladdr-y += 0x08008000
diff --git a/arch/arm/mach-shmobile/Makefile.boot b/arch/arm/mach-shmobile/Makefile.boot
index 1c08ee9de86a..498efd99338d 100644
--- a/arch/arm/mach-shmobile/Makefile.boot
+++ b/arch/arm/mach-shmobile/Makefile.boot
@@ -1,7 +1,7 @@
__ZRELADDR := $(shell /bin/bash -c 'printf "0x%08x" \
$$[$(CONFIG_MEMORY_START) + 0x8000]')
- zreladdr-y := $(__ZRELADDR)
+ zreladdr-y += $(__ZRELADDR)
# Unsupported legacy stuff
#
diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c
index ce5c2513c6ce..cdfdd624d21d 100644
--- a/arch/arm/mach-shmobile/board-ag5evm.c
+++ b/arch/arm/mach-shmobile/board-ag5evm.c
@@ -341,6 +341,7 @@ static struct platform_device mipidsi0_device = {
static struct sh_mobile_sdhi_info sdhi0_info = {
.dma_slave_tx = SHDMA_SLAVE_SDHI0_TX,
.dma_slave_rx = SHDMA_SLAVE_SDHI0_RX,
+ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT,
.tmio_caps = MMC_CAP_SD_HIGHSPEED,
.tmio_ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
};
@@ -382,7 +383,7 @@ void ag5evm_sdhi1_set_pwr(struct platform_device *pdev, int state)
}
static struct sh_mobile_sdhi_info sh_sdhi1_info = {
- .tmio_flags = TMIO_MMC_WRPROTECT_DISABLE,
+ .tmio_flags = TMIO_MMC_WRPROTECT_DISABLE | TMIO_MMC_HAS_IDLE_WAIT,
.tmio_caps = MMC_CAP_NONREMOVABLE | MMC_CAP_SDIO_IRQ,
.tmio_ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
.set_pwr = ag5evm_sdhi1_set_pwr,
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
index 9e0856b2f9e9..7e90d064ebcb 100644
--- a/arch/arm/mach-shmobile/board-ap4evb.c
+++ b/arch/arm/mach-shmobile/board-ap4evb.c
@@ -42,6 +42,7 @@
#include <linux/leds.h>
#include <linux/input/sh_keysc.h>
#include <linux/usb/r8a66597.h>
+#include <linux/pm_clock.h>
#include <media/sh_mobile_ceu.h>
#include <media/sh_mobile_csi2.h>
@@ -1408,10 +1409,16 @@ static void __init ap4evb_init(void)
sh7372_add_device_to_domain(&sh7372_a4lc, &lcdc_device);
sh7372_add_device_to_domain(&sh7372_a4mp, &fsi_device);
+ sh7372_add_device_to_domain(&sh7372_a3sp, &sh_mmcif_device);
+ sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi0_device);
+ sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi1_device);
+ sh7372_add_device_to_domain(&sh7372_a4r, &ceu_device);
+
hdmi_init_pm_clock();
fsi_init_pm_clock();
sh7372_pm_init();
pm_clk_add(&fsi_device.dev, "spu2");
+ pm_clk_add(&lcdc1_device.dev, "hdmi");
}
static void __init ap4evb_timer_init(void)
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index d41c01f83f15..00273dad5bf0 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -39,7 +39,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
-#include <linux/pm_runtime.h>
+#include <linux/pm_clock.h>
#include <linux/smsc911x.h>
#include <linux/sh_intc.h>
#include <linux/tca6416_keypad.h>
@@ -641,6 +641,8 @@ static struct usbhs_private usbhs0_private = {
},
.driver_param = {
.buswait_bwait = 4,
+ .d0_tx_id = SHDMA_SLAVE_USB0_TX,
+ .d1_rx_id = SHDMA_SLAVE_USB0_RX,
},
},
};
@@ -808,8 +810,11 @@ static struct usbhs_private usbhs1_private = {
},
.driver_param = {
.buswait_bwait = 4,
+ .has_otg = 1,
.pipe_type = usbhs1_pipe_cfg,
.pipe_size = ARRAY_SIZE(usbhs1_pipe_cfg),
+ .d0_tx_id = SHDMA_SLAVE_USB1_TX,
+ .d1_rx_id = SHDMA_SLAVE_USB1_RX,
},
},
};
@@ -1584,10 +1589,20 @@ static void __init mackerel_init(void)
sh7372_add_device_to_domain(&sh7372_a4lc, &lcdc_device);
sh7372_add_device_to_domain(&sh7372_a4lc, &hdmi_lcdc_device);
sh7372_add_device_to_domain(&sh7372_a4mp, &fsi_device);
+ sh7372_add_device_to_domain(&sh7372_a3sp, &usbhs0_device);
+ sh7372_add_device_to_domain(&sh7372_a3sp, &usbhs1_device);
+ sh7372_add_device_to_domain(&sh7372_a3sp, &sh_mmcif_device);
+ sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi0_device);
+#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
+ sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi1_device);
+#endif
+ sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi2_device);
+ sh7372_add_device_to_domain(&sh7372_a4r, &ceu_device);
hdmi_init_pm_clock();
sh7372_pm_init();
pm_clk_add(&fsi_device.dev, "spu2");
+ pm_clk_add(&hdmi_lcdc_device.dev, "hdmi");
}
static void __init mackerel_timer_init(void)
diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c
index 6b1619a65dba..66975921e646 100644
--- a/arch/arm/mach-shmobile/clock-sh7372.c
+++ b/arch/arm/mach-shmobile/clock-sh7372.c
@@ -503,16 +503,17 @@ static struct clk *late_main_clks[] = {
&sh7372_fsidivb_clk,
};
-enum { MSTP001,
+enum { MSTP001, MSTP000,
MSTP131, MSTP130,
MSTP129, MSTP128, MSTP127, MSTP126, MSTP125,
MSTP118, MSTP117, MSTP116, MSTP113,
MSTP106, MSTP101, MSTP100,
MSTP223,
- MSTP218, MSTP217, MSTP216,
- MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
- MSTP329, MSTP328, MSTP323, MSTP322, MSTP314, MSTP313, MSTP312,
- MSTP423, MSTP415, MSTP413, MSTP411, MSTP410, MSTP406, MSTP403,
+ MSTP218, MSTP217, MSTP216, MSTP214, MSTP208, MSTP207,
+ MSTP206, MSTP205, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
+ MSTP328, MSTP323, MSTP322, MSTP314, MSTP313, MSTP312,
+ MSTP423, MSTP415, MSTP413, MSTP411, MSTP410, MSTP407, MSTP406,
+ MSTP405, MSTP404, MSTP403, MSTP400,
MSTP_NR };
#define MSTP(_parent, _reg, _bit, _flags) \
@@ -520,6 +521,7 @@ enum { MSTP001,
static struct clk mstp_clks[MSTP_NR] = {
[MSTP001] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR0, 1, 0), /* IIC2 */
+ [MSTP000] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR0, 0, 0), /* MSIOF0 */
[MSTP131] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 31, 0), /* VEU3 */
[MSTP130] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 30, 0), /* VEU2 */
[MSTP129] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 29, 0), /* VEU1 */
@@ -538,14 +540,16 @@ static struct clk mstp_clks[MSTP_NR] = {
[MSTP218] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 18, 0), /* DMAC1 */
[MSTP217] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 17, 0), /* DMAC2 */
[MSTP216] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 16, 0), /* DMAC3 */
+ [MSTP214] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 14, 0), /* USBDMAC */
+ [MSTP208] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 8, 0), /* MSIOF1 */
[MSTP207] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 7, 0), /* SCIFA5 */
[MSTP206] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 6, 0), /* SCIFB */
+ [MSTP205] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 5, 0), /* MSIOF2 */
[MSTP204] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 4, 0), /* SCIFA0 */
[MSTP203] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 3, 0), /* SCIFA1 */
[MSTP202] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 2, 0), /* SCIFA2 */
[MSTP201] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 1, 0), /* SCIFA3 */
[MSTP200] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */
- [MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */
[MSTP328] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR3, 28, 0), /* FSI2 */
[MSTP323] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */
[MSTP322] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 22, 0), /* USB0 */
@@ -557,8 +561,12 @@ static struct clk mstp_clks[MSTP_NR] = {
[MSTP413] = MSTP(&pllc1_div2_clk, SMSTPCR4, 13, 0), /* HDMI */
[MSTP411] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 11, 0), /* IIC3 */
[MSTP410] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 10, 0), /* IIC4 */
+ [MSTP407] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 7, 0), /* USB-DMAC1 */
[MSTP406] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 6, 0), /* USB1 */
+ [MSTP405] = MSTP(&r_clk, SMSTPCR4, 5, 0), /* CMT4 */
+ [MSTP404] = MSTP(&r_clk, SMSTPCR4, 4, 0), /* CMT3 */
[MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */
+ [MSTP400] = MSTP(&r_clk, SMSTPCR4, 0, 0), /* CMT2 */
};
static struct clk_lookup lookups[] = {
@@ -609,6 +617,7 @@ static struct clk_lookup lookups[] = {
/* MSTP32 clocks */
CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* IIC2 */
+ CLKDEV_DEV_ID("spi_sh_msiof.0", &mstp_clks[MSTP000]), /* MSIOF0 */
CLKDEV_DEV_ID("uio_pdrv_genirq.4", &mstp_clks[MSTP131]), /* VEU3 */
CLKDEV_DEV_ID("uio_pdrv_genirq.3", &mstp_clks[MSTP130]), /* VEU2 */
CLKDEV_DEV_ID("uio_pdrv_genirq.2", &mstp_clks[MSTP129]), /* VEU1 */
@@ -629,14 +638,16 @@ static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[MSTP218]), /* DMAC1 */
CLKDEV_DEV_ID("sh-dma-engine.1", &mstp_clks[MSTP217]), /* DMAC2 */
CLKDEV_DEV_ID("sh-dma-engine.2", &mstp_clks[MSTP216]), /* DMAC3 */
+ CLKDEV_DEV_ID("sh-dma-engine.3", &mstp_clks[MSTP214]), /* USB-DMAC0 */
+ CLKDEV_DEV_ID("spi_sh_msiof.1", &mstp_clks[MSTP208]), /* MSIOF1 */
CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), /* SCIFA5 */
CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP206]), /* SCIFB */
+ CLKDEV_DEV_ID("spi_sh_msiof.2", &mstp_clks[MSTP205]), /* MSIOF2 */
CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), /* SCIFA0 */
CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP203]), /* SCIFA1 */
CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP202]), /* SCIFA2 */
CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), /* SCIFA3 */
CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */
- CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */
CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]), /* FSI2 */
CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */
CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USB0 */
@@ -650,11 +661,17 @@ static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("sh-mobile-hdmi", &mstp_clks[MSTP413]), /* HDMI */
CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* IIC3 */
CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* IIC4 */
+ CLKDEV_DEV_ID("sh-dma-engine.4", &mstp_clks[MSTP407]), /* USB-DMAC1 */
CLKDEV_DEV_ID("r8a66597_hcd.1", &mstp_clks[MSTP406]), /* USB1 */
CLKDEV_DEV_ID("r8a66597_udc.1", &mstp_clks[MSTP406]), /* USB1 */
CLKDEV_DEV_ID("renesas_usbhs.1", &mstp_clks[MSTP406]), /* USB1 */
+ CLKDEV_DEV_ID("sh_cmt.4", &mstp_clks[MSTP405]), /* CMT4 */
+ CLKDEV_DEV_ID("sh_cmt.3", &mstp_clks[MSTP404]), /* CMT3 */
CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */
+ CLKDEV_DEV_ID("sh_cmt.2", &mstp_clks[MSTP400]), /* CMT2 */
+ CLKDEV_ICK_ID("hdmi", "sh_mobile_lcdc_fb.1",
+ &div6_reparent_clks[DIV6_HDMI]),
CLKDEV_ICK_ID("ick", "sh-mobile-hdmi", &div6_reparent_clks[DIV6_HDMI]),
CLKDEV_ICK_ID("icka", "sh_fsi2", &div6_reparent_clks[DIV6_FSIA]),
CLKDEV_ICK_ID("ickb", "sh_fsi2", &div6_reparent_clks[DIV6_FSIB]),
diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c
index 6db2ccabc2bf..61a846bb30f2 100644
--- a/arch/arm/mach-shmobile/clock-sh73a0.c
+++ b/arch/arm/mach-shmobile/clock-sh73a0.c
@@ -365,7 +365,7 @@ void __init sh73a0_clock_init(void)
__raw_writel(0x108, SD2CKCR);
/* detect main clock parent */
- switch ((__raw_readl(CKSCR) >> 24) & 0x03) {
+ switch ((__raw_readl(CKSCR) >> 28) & 0x03) {
case 0:
main_clk.parent = &sh73a0_extal1_clk;
break;
diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h
index 06aecb31d9c7..c0cdbf997c91 100644
--- a/arch/arm/mach-shmobile/include/mach/common.h
+++ b/arch/arm/mach-shmobile/include/mach/common.h
@@ -35,8 +35,8 @@ extern void sh7372_add_standard_devices(void);
extern void sh7372_clock_init(void);
extern void sh7372_pinmux_init(void);
extern void sh7372_pm_init(void);
-extern void sh7372_cpu_suspend(void);
-extern void sh7372_cpu_resume(void);
+extern void sh7372_resume_core_standby_a3sm(void);
+extern int sh7372_do_idle_a3sm(unsigned long unused);
extern struct clk sh7372_extal1_clk;
extern struct clk sh7372_extal2_clk;
diff --git a/arch/arm/mach-shmobile/include/mach/sh7372.h b/arch/arm/mach-shmobile/include/mach/sh7372.h
index ce595cee86cd..84532f9629b2 100644
--- a/arch/arm/mach-shmobile/include/mach/sh7372.h
+++ b/arch/arm/mach-shmobile/include/mach/sh7372.h
@@ -459,6 +459,10 @@ enum {
SHDMA_SLAVE_SDHI2_TX,
SHDMA_SLAVE_MMCIF_RX,
SHDMA_SLAVE_MMCIF_TX,
+ SHDMA_SLAVE_USB0_TX,
+ SHDMA_SLAVE_USB0_RX,
+ SHDMA_SLAVE_USB1_TX,
+ SHDMA_SLAVE_USB1_RX,
};
extern struct clk sh7372_extal1_clk;
@@ -475,7 +479,12 @@ struct platform_device;
struct sh7372_pm_domain {
struct generic_pm_domain genpd;
+ struct dev_power_governor *gov;
+ void (*suspend)(void);
+ void (*resume)(void);
unsigned int bit_shift;
+ bool no_debug;
+ bool stay_on;
};
static inline struct sh7372_pm_domain *to_sh7372_pd(struct generic_pm_domain *d)
@@ -487,16 +496,24 @@ static inline struct sh7372_pm_domain *to_sh7372_pd(struct generic_pm_domain *d)
extern struct sh7372_pm_domain sh7372_a4lc;
extern struct sh7372_pm_domain sh7372_a4mp;
extern struct sh7372_pm_domain sh7372_d4;
+extern struct sh7372_pm_domain sh7372_a4r;
extern struct sh7372_pm_domain sh7372_a3rv;
extern struct sh7372_pm_domain sh7372_a3ri;
+extern struct sh7372_pm_domain sh7372_a3sp;
extern struct sh7372_pm_domain sh7372_a3sg;
extern void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd);
extern void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd,
struct platform_device *pdev);
+extern void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd,
+ struct sh7372_pm_domain *sh7372_sd);
#else
#define sh7372_init_pm_domain(pd) do { } while(0)
#define sh7372_add_device_to_domain(pd, pdev) do { } while(0)
+#define sh7372_pm_add_subdomain(pd, sd) do { } while(0)
#endif /* CONFIG_PM */
+extern void sh7372_intcs_suspend(void);
+extern void sh7372_intcs_resume(void);
+
#endif /* __ASM_SH7372_H__ */
diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c
index 3b28743c77eb..29cdc0522d9c 100644
--- a/arch/arm/mach-shmobile/intc-sh7372.c
+++ b/arch/arm/mach-shmobile/intc-sh7372.c
@@ -379,7 +379,7 @@ enum {
/* BBIF2 */
VPU,
TSIF1,
- _3DG_SGX530,
+ /* 3DG */
_2DDMAC,
IIC2_ALI2, IIC2_TACKI2, IIC2_WAITI2, IIC2_DTEI2,
IPMMU_IPMMUR, IPMMU_IPMMUR2,
@@ -436,7 +436,7 @@ static struct intc_vect intcs_vectors[] = {
/* BBIF2 */
INTCS_VECT(VPU, 0x980),
INTCS_VECT(TSIF1, 0x9a0),
- INTCS_VECT(_3DG_SGX530, 0x9e0),
+ /* 3DG */
INTCS_VECT(_2DDMAC, 0xa00),
INTCS_VECT(IIC2_ALI2, 0xa80), INTCS_VECT(IIC2_TACKI2, 0xaa0),
INTCS_VECT(IIC2_WAITI2, 0xac0), INTCS_VECT(IIC2_DTEI2, 0xae0),
@@ -521,7 +521,7 @@ static struct intc_mask_reg intcs_mask_registers[] = {
RTDMAC_1_DEI3, RTDMAC_1_DEI2, RTDMAC_1_DEI1, RTDMAC_1_DEI0 } },
{ 0xffd20198, 0xffd201d8, 8, /* IMR6SA / IMCR6SA */
{ 0, 0, MSIOF, 0,
- _3DG_SGX530, 0, 0, 0 } },
+ 0, 0, 0, 0 } },
{ 0xffd2019c, 0xffd201dc, 8, /* IMR7SA / IMCR7SA */
{ 0, TMU_TUNI2, TMU_TUNI1, TMU_TUNI0,
0, 0, 0, 0 } },
@@ -561,7 +561,6 @@ static struct intc_prio_reg intcs_prio_registers[] = {
TMU_TUNI2, TSIF1 } },
{ 0xffd2001c, 0, 16, 4, /* IPRHS */ { 0, 0, VEU, BEU } },
{ 0xffd20020, 0, 16, 4, /* IPRIS */ { 0, MSIOF, TSIF0, IIC0 } },
- { 0xffd20024, 0, 16, 4, /* IPRJS */ { 0, _3DG_SGX530, 0, 0 } },
{ 0xffd20028, 0, 16, 4, /* IPRKS */ { 0, 0, LMB, 0 } },
{ 0xffd2002c, 0, 16, 4, /* IPRLS */ { IPMMU, 0, 0, 0 } },
{ 0xffd20030, 0, 16, 4, /* IPRMS */ { IIC2, 0, 0, 0 } },
@@ -607,9 +606,16 @@ static void intcs_demux(unsigned int irq, struct irq_desc *desc)
generic_handle_irq(intcs_evt2irq(evtcodeas));
}
+static void __iomem *intcs_ffd2;
+static void __iomem *intcs_ffd5;
+
void __init sh7372_init_irq(void)
{
- void __iomem *intevtsa = ioremap_nocache(0xffd20100, PAGE_SIZE);
+ void __iomem *intevtsa;
+
+ intcs_ffd2 = ioremap_nocache(0xffd20000, PAGE_SIZE);
+ intevtsa = intcs_ffd2 + 0x100;
+ intcs_ffd5 = ioremap_nocache(0xffd50000, PAGE_SIZE);
register_intc_controller(&intca_desc);
register_intc_controller(&intcs_desc);
@@ -618,3 +624,46 @@ void __init sh7372_init_irq(void)
irq_set_handler_data(evt2irq(0xf80), (void *)intevtsa);
irq_set_chained_handler(evt2irq(0xf80), intcs_demux);
}
+
+static unsigned short ffd2[0x200];
+static unsigned short ffd5[0x100];
+
+void sh7372_intcs_suspend(void)
+{
+ int k;
+
+ for (k = 0x00; k <= 0x30; k += 4)
+ ffd2[k] = __raw_readw(intcs_ffd2 + k);
+
+ for (k = 0x80; k <= 0xb0; k += 4)
+ ffd2[k] = __raw_readb(intcs_ffd2 + k);
+
+ for (k = 0x180; k <= 0x188; k += 4)
+ ffd2[k] = __raw_readb(intcs_ffd2 + k);
+
+ for (k = 0x00; k <= 0x3c; k += 4)
+ ffd5[k] = __raw_readw(intcs_ffd5 + k);
+
+ for (k = 0x80; k <= 0x9c; k += 4)
+ ffd5[k] = __raw_readb(intcs_ffd5 + k);
+}
+
+void sh7372_intcs_resume(void)
+{
+ int k;
+
+ for (k = 0x00; k <= 0x30; k += 4)
+ __raw_writew(ffd2[k], intcs_ffd2 + k);
+
+ for (k = 0x80; k <= 0xb0; k += 4)
+ __raw_writeb(ffd2[k], intcs_ffd2 + k);
+
+ for (k = 0x180; k <= 0x188; k += 4)
+ __raw_writeb(ffd2[k], intcs_ffd2 + k);
+
+ for (k = 0x00; k <= 0x3c; k += 4)
+ __raw_writew(ffd5[k], intcs_ffd5 + k);
+
+ for (k = 0x80; k <= 0x9c; k += 4)
+ __raw_writeb(ffd5[k], intcs_ffd5 + k);
+}
diff --git a/arch/arm/mach-shmobile/platsmp.c b/arch/arm/mach-shmobile/platsmp.c
index 66f980625a33..e4e485fa2532 100644
--- a/arch/arm/mach-shmobile/platsmp.c
+++ b/arch/arm/mach-shmobile/platsmp.c
@@ -56,6 +56,12 @@ void __init smp_init_cpus(void)
unsigned int ncores = shmobile_smp_get_core_count();
unsigned int i;
+ if (ncores > nr_cpu_ids) {
+ pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
+ ncores, nr_cpu_ids);
+ ncores = nr_cpu_ids;
+ }
+
for (i = 0; i < ncores; i++)
set_cpu_possible(i, true);
diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c
index 933fb411be0f..79612737c5b2 100644
--- a/arch/arm/mach-shmobile/pm-sh7372.c
+++ b/arch/arm/mach-shmobile/pm-sh7372.c
@@ -15,23 +15,61 @@
#include <linux/list.h>
#include <linux/err.h>
#include <linux/slab.h>
-#include <linux/pm_runtime.h>
+#include <linux/pm_clock.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/bitrev.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/tlbflush.h>
+#include <asm/suspend.h>
#include <mach/common.h>
#include <mach/sh7372.h>
-#define SMFRAM 0xe6a70000
-#define SYSTBCR 0xe6150024
-#define SBAR 0xe6180020
-#define APARMBAREA 0xe6f10020
+/* DBG */
+#define DBGREG1 0xe6100020
+#define DBGREG9 0xe6100040
+/* CPGA */
+#define SYSTBCR 0xe6150024
+#define MSTPSR0 0xe6150030
+#define MSTPSR1 0xe6150038
+#define MSTPSR2 0xe6150040
+#define MSTPSR3 0xe6150048
+#define MSTPSR4 0xe615004c
+#define PLLC01STPCR 0xe61500c8
+
+/* SYSC */
#define SPDCR 0xe6180008
#define SWUCR 0xe6180014
+#define SBAR 0xe6180020
+#define WUPRMSK 0xe6180028
+#define WUPSMSK 0xe618002c
+#define WUPSMSK2 0xe6180048
#define PSTR 0xe6180080
+#define WUPSFAC 0xe6180098
+#define IRQCR 0xe618022c
+#define IRQCR2 0xe6180238
+#define IRQCR3 0xe6180244
+#define IRQCR4 0xe6180248
+#define PDNSEL 0xe6180254
+
+/* INTC */
+#define ICR1A 0xe6900000
+#define ICR2A 0xe6900004
+#define ICR3A 0xe6900008
+#define ICR4A 0xe690000c
+#define INTMSK00A 0xe6900040
+#define INTMSK10A 0xe6900044
+#define INTMSK20A 0xe6900048
+#define INTMSK30A 0xe690004c
+
+/* MFIS */
+#define SMFRAM 0xe6a70000
+
+/* AP-System Core */
+#define APARMBAREA 0xe6f10020
#define PSTR_RETRIES 100
#define PSTR_DELAY_US 10
@@ -43,6 +81,12 @@ static int pd_power_down(struct generic_pm_domain *genpd)
struct sh7372_pm_domain *sh7372_pd = to_sh7372_pd(genpd);
unsigned int mask = 1 << sh7372_pd->bit_shift;
+ if (sh7372_pd->suspend)
+ sh7372_pd->suspend();
+
+ if (sh7372_pd->stay_on)
+ return 0;
+
if (__raw_readl(PSTR) & mask) {
unsigned int retry_count;
@@ -55,8 +99,9 @@ static int pd_power_down(struct generic_pm_domain *genpd)
}
}
- pr_debug("sh7372 power domain down 0x%08x -> PSTR = 0x%08x\n",
- mask, __raw_readl(PSTR));
+ if (!sh7372_pd->no_debug)
+ pr_debug("sh7372 power domain down 0x%08x -> PSTR = 0x%08x\n",
+ mask, __raw_readl(PSTR));
return 0;
}
@@ -68,6 +113,9 @@ static int pd_power_up(struct generic_pm_domain *genpd)
unsigned int retry_count;
int ret = 0;
+ if (sh7372_pd->stay_on)
+ goto out;
+
if (__raw_readl(PSTR) & mask)
goto out;
@@ -84,66 +132,48 @@ static int pd_power_up(struct generic_pm_domain *genpd)
if (__raw_readl(SWUCR) & mask)
ret = -EIO;
+ if (!sh7372_pd->no_debug)
+ pr_debug("sh7372 power domain up 0x%08x -> PSTR = 0x%08x\n",
+ mask, __raw_readl(PSTR));
+
out:
- pr_debug("sh7372 power domain up 0x%08x -> PSTR = 0x%08x\n",
- mask, __raw_readl(PSTR));
+ if (ret == 0 && sh7372_pd->resume)
+ sh7372_pd->resume();
return ret;
}
-static int pd_power_up_a3rv(struct generic_pm_domain *genpd)
+static void sh7372_a4r_suspend(void)
{
- int ret = pd_power_up(genpd);
-
- /* force A4LC on after A3RV has been requested on */
- pm_genpd_poweron(&sh7372_a4lc.genpd);
-
- return ret;
+ sh7372_intcs_suspend();
+ __raw_writel(0x300fffff, WUPRMSK); /* avoid wakeup */
}
-static int pd_power_down_a3rv(struct generic_pm_domain *genpd)
+static bool pd_active_wakeup(struct device *dev)
{
- int ret = pd_power_down(genpd);
-
- /* try to power down A4LC after A3RV is requested off */
- genpd_queue_power_off_work(&sh7372_a4lc.genpd);
-
- return ret;
+ return true;
}
-static int pd_power_down_a4lc(struct generic_pm_domain *genpd)
+static bool sh7372_power_down_forbidden(struct dev_pm_domain *domain)
{
- /* only power down A4LC if A3RV is off */
- if (!(__raw_readl(PSTR) & (1 << sh7372_a3rv.bit_shift)))
- return pd_power_down(genpd);
-
- return -EBUSY;
+ return false;
}
-static bool pd_active_wakeup(struct device *dev)
-{
- return true;
-}
+struct dev_power_governor sh7372_always_on_gov = {
+ .power_down_ok = sh7372_power_down_forbidden,
+};
void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd)
{
struct generic_pm_domain *genpd = &sh7372_pd->genpd;
- pm_genpd_init(genpd, NULL, false);
+ pm_genpd_init(genpd, sh7372_pd->gov, false);
genpd->stop_device = pm_clk_suspend;
genpd->start_device = pm_clk_resume;
+ genpd->dev_irq_safe = true;
genpd->active_wakeup = pd_active_wakeup;
-
- if (sh7372_pd == &sh7372_a4lc) {
- genpd->power_off = pd_power_down_a4lc;
- genpd->power_on = pd_power_up;
- } else if (sh7372_pd == &sh7372_a3rv) {
- genpd->power_off = pd_power_down_a3rv;
- genpd->power_on = pd_power_up_a3rv;
- } else {
- genpd->power_off = pd_power_down;
- genpd->power_on = pd_power_up;
- }
+ genpd->power_off = pd_power_down;
+ genpd->power_on = pd_power_up;
genpd->power_on(&sh7372_pd->genpd);
}
@@ -152,11 +182,15 @@ void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd,
{
struct device *dev = &pdev->dev;
- if (!dev->power.subsys_data) {
- pm_clk_init(dev);
- pm_clk_add(dev, NULL);
- }
pm_genpd_add_device(&sh7372_pd->genpd, dev);
+ if (pm_clk_no_clocks(dev))
+ pm_clk_add(dev, NULL);
+}
+
+void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd,
+ struct sh7372_pm_domain *sh7372_sd)
+{
+ pm_genpd_add_subdomain(&sh7372_pd->genpd, &sh7372_sd->genpd);
}
struct sh7372_pm_domain sh7372_a4lc = {
@@ -171,6 +205,14 @@ struct sh7372_pm_domain sh7372_d4 = {
.bit_shift = 3,
};
+struct sh7372_pm_domain sh7372_a4r = {
+ .bit_shift = 5,
+ .gov = &sh7372_always_on_gov,
+ .suspend = sh7372_a4r_suspend,
+ .resume = sh7372_intcs_resume,
+ .stay_on = true,
+};
+
struct sh7372_pm_domain sh7372_a3rv = {
.bit_shift = 6,
};
@@ -179,39 +221,187 @@ struct sh7372_pm_domain sh7372_a3ri = {
.bit_shift = 8,
};
+struct sh7372_pm_domain sh7372_a3sp = {
+ .bit_shift = 11,
+ .gov = &sh7372_always_on_gov,
+ .no_debug = true,
+};
+
struct sh7372_pm_domain sh7372_a3sg = {
.bit_shift = 13,
};
#endif /* CONFIG_PM */
+#if defined(CONFIG_SUSPEND) || defined(CONFIG_CPU_IDLE)
+static int sh7372_do_idle_core_standby(unsigned long unused)
+{
+ cpu_do_idle(); /* WFI when SYSTBCR == 0x10 -> Core Standby */
+ return 0;
+}
+
static void sh7372_enter_core_standby(void)
{
- void __iomem *smfram = (void __iomem *)SMFRAM;
+ /* set reset vector, translate 4k */
+ __raw_writel(__pa(sh7372_resume_core_standby_a3sm), SBAR);
+ __raw_writel(0, APARMBAREA);
- __raw_writel(0, APARMBAREA); /* translate 4k */
- __raw_writel(__pa(sh7372_cpu_resume), SBAR); /* set reset vector */
- __raw_writel(0x10, SYSTBCR); /* enable core standby */
+ /* enter sleep mode with SYSTBCR to 0x10 */
+ __raw_writel(0x10, SYSTBCR);
+ cpu_suspend(0, sh7372_do_idle_core_standby);
+ __raw_writel(0, SYSTBCR);
- __raw_writel(0, smfram + 0x3c); /* clear page table address */
+ /* disable reset vector translation */
+ __raw_writel(0, SBAR);
+}
+#endif
+
+#ifdef CONFIG_SUSPEND
+static void sh7372_enter_a3sm_common(int pllc0_on)
+{
+ /* set reset vector, translate 4k */
+ __raw_writel(__pa(sh7372_resume_core_standby_a3sm), SBAR);
+ __raw_writel(0, APARMBAREA);
+
+ if (pllc0_on)
+ __raw_writel(0, PLLC01STPCR);
+ else
+ __raw_writel(1 << 28, PLLC01STPCR);
+
+ __raw_writel(0, PDNSEL); /* power-down A3SM only, not A4S */
+ __raw_readl(WUPSFAC); /* read wakeup int. factor before sleep */
+ cpu_suspend(0, sh7372_do_idle_a3sm);
+ __raw_readl(WUPSFAC); /* read wakeup int. factor after wakeup */
+
+ /* disable reset vector translation */
+ __raw_writel(0, SBAR);
+}
+
+static int sh7372_a3sm_valid(unsigned long *mskp, unsigned long *msk2p)
+{
+ unsigned long mstpsr0, mstpsr1, mstpsr2, mstpsr3, mstpsr4;
+ unsigned long msk, msk2;
+
+ /* check active clocks to determine potential wakeup sources */
+
+ mstpsr0 = __raw_readl(MSTPSR0);
+ if ((mstpsr0 & 0x00000003) != 0x00000003) {
+ pr_debug("sh7372 mstpsr0 0x%08lx\n", mstpsr0);
+ return 0;
+ }
+
+ mstpsr1 = __raw_readl(MSTPSR1);
+ if ((mstpsr1 & 0xff079b7f) != 0xff079b7f) {
+ pr_debug("sh7372 mstpsr1 0x%08lx\n", mstpsr1);
+ return 0;
+ }
- sh7372_cpu_suspend();
- cpu_init();
+ mstpsr2 = __raw_readl(MSTPSR2);
+ if ((mstpsr2 & 0x000741ff) != 0x000741ff) {
+ pr_debug("sh7372 mstpsr2 0x%08lx\n", mstpsr2);
+ return 0;
+ }
- /* if page table address is non-NULL then we have been powered down */
- if (__raw_readl(smfram + 0x3c)) {
- __raw_writel(__raw_readl(smfram + 0x40),
- __va(__raw_readl(smfram + 0x3c)));
+ mstpsr3 = __raw_readl(MSTPSR3);
+ if ((mstpsr3 & 0x1a60f010) != 0x1a60f010) {
+ pr_debug("sh7372 mstpsr3 0x%08lx\n", mstpsr3);
+ return 0;
+ }
- flush_tlb_all();
- set_cr(__raw_readl(smfram + 0x38));
+ mstpsr4 = __raw_readl(MSTPSR4);
+ if ((mstpsr4 & 0x00008cf0) != 0x00008cf0) {
+ pr_debug("sh7372 mstpsr4 0x%08lx\n", mstpsr4);
+ return 0;
}
- __raw_writel(0, SYSTBCR); /* disable core standby */
- __raw_writel(0, SBAR); /* disable reset vector translation */
+ msk = 0;
+ msk2 = 0;
+
+ /* make bitmaps of limited number of wakeup sources */
+
+ if ((mstpsr2 & (1 << 23)) == 0) /* SPU2 */
+ msk |= 1 << 31;
+
+ if ((mstpsr2 & (1 << 12)) == 0) /* MFI_MFIM */
+ msk |= 1 << 21;
+
+ if ((mstpsr4 & (1 << 3)) == 0) /* KEYSC */
+ msk |= 1 << 2;
+
+ if ((mstpsr1 & (1 << 24)) == 0) /* CMT0 */
+ msk |= 1 << 1;
+
+ if ((mstpsr3 & (1 << 29)) == 0) /* CMT1 */
+ msk |= 1 << 1;
+
+ if ((mstpsr4 & (1 << 0)) == 0) /* CMT2 */
+ msk |= 1 << 1;
+
+ if ((mstpsr2 & (1 << 13)) == 0) /* MFI_MFIS */
+ msk2 |= 1 << 17;
+
+ *mskp = msk;
+ *msk2p = msk2;
+
+ return 1;
+}
+
+static void sh7372_icr_to_irqcr(unsigned long icr, u16 *irqcr1p, u16 *irqcr2p)
+{
+ u16 tmp, irqcr1, irqcr2;
+ int k;
+
+ irqcr1 = 0;
+ irqcr2 = 0;
+
+ /* convert INTCA ICR register layout to SYSC IRQCR+IRQCR2 */
+ for (k = 0; k <= 7; k++) {
+ tmp = (icr >> ((7 - k) * 4)) & 0xf;
+ irqcr1 |= (tmp & 0x03) << (k * 2);
+ irqcr2 |= (tmp >> 2) << (k * 2);
+ }
+
+ *irqcr1p = irqcr1;
+ *irqcr2p = irqcr2;
+}
+
+static void sh7372_setup_a3sm(unsigned long msk, unsigned long msk2)
+{
+ u16 irqcrx_low, irqcrx_high, irqcry_low, irqcry_high;
+ unsigned long tmp;
+
+ /* read IRQ0A -> IRQ15A mask */
+ tmp = bitrev8(__raw_readb(INTMSK00A));
+ tmp |= bitrev8(__raw_readb(INTMSK10A)) << 8;
+
+ /* setup WUPSMSK from clocks and external IRQ mask */
+ msk = (~msk & 0xc030000f) | (tmp << 4);
+ __raw_writel(msk, WUPSMSK);
+
+ /* propage level/edge trigger for external IRQ 0->15 */
+ sh7372_icr_to_irqcr(__raw_readl(ICR1A), &irqcrx_low, &irqcry_low);
+ sh7372_icr_to_irqcr(__raw_readl(ICR2A), &irqcrx_high, &irqcry_high);
+ __raw_writel((irqcrx_high << 16) | irqcrx_low, IRQCR);
+ __raw_writel((irqcry_high << 16) | irqcry_low, IRQCR2);
+
+ /* read IRQ16A -> IRQ31A mask */
+ tmp = bitrev8(__raw_readb(INTMSK20A));
+ tmp |= bitrev8(__raw_readb(INTMSK30A)) << 8;
+
+ /* setup WUPSMSK2 from clocks and external IRQ mask */
+ msk2 = (~msk2 & 0x00030000) | tmp;
+ __raw_writel(msk2, WUPSMSK2);
+
+ /* propage level/edge trigger for external IRQ 16->31 */
+ sh7372_icr_to_irqcr(__raw_readl(ICR3A), &irqcrx_low, &irqcry_low);
+ sh7372_icr_to_irqcr(__raw_readl(ICR4A), &irqcrx_high, &irqcry_high);
+ __raw_writel((irqcrx_high << 16) | irqcrx_low, IRQCR3);
+ __raw_writel((irqcry_high << 16) | irqcry_low, IRQCR4);
}
+#endif
#ifdef CONFIG_CPU_IDLE
+
static void sh7372_cpuidle_setup(struct cpuidle_device *dev)
{
struct cpuidle_state *state;
@@ -239,9 +429,25 @@ static void sh7372_cpuidle_init(void) {}
#endif
#ifdef CONFIG_SUSPEND
+
static int sh7372_enter_suspend(suspend_state_t suspend_state)
{
- sh7372_enter_core_standby();
+ unsigned long msk, msk2;
+
+ /* check active clocks to determine potential wakeup sources */
+ if (sh7372_a3sm_valid(&msk, &msk2)) {
+
+ /* convert INTC mask and sense to SYSC mask and sense */
+ sh7372_setup_a3sm(msk, msk2);
+
+ /* enter A3SM sleep with PLLC0 off */
+ pr_debug("entering A3SM\n");
+ sh7372_enter_a3sm_common(0);
+ } else {
+ /* default to Core Standby that supports all wakeup sources */
+ pr_debug("entering Core Standby\n");
+ sh7372_enter_core_standby();
+ }
return 0;
}
@@ -253,9 +459,6 @@ static void sh7372_suspend_init(void)
static void sh7372_suspend_init(void) {}
#endif
-#define DBGREG1 0xe6100020
-#define DBGREG9 0xe6100040
-
void __init sh7372_pm_init(void)
{
/* enable DBG hardware block to kick SYSC */
@@ -263,6 +466,9 @@ void __init sh7372_pm_init(void)
__raw_writel(0x0000a501, DBGREG9);
__raw_writel(0x00000000, DBGREG1);
+ /* do not convert A3SM, A3SP, A3SG, A4R power down into A4S */
+ __raw_writel(0, PDNSEL);
+
sh7372_suspend_init();
sh7372_cpuidle_init();
}
diff --git a/arch/arm/mach-shmobile/pm_runtime.c b/arch/arm/mach-shmobile/pm_runtime.c
index 6ec454e1e063..bd5c6a3b8c55 100644
--- a/arch/arm/mach-shmobile/pm_runtime.c
+++ b/arch/arm/mach-shmobile/pm_runtime.c
@@ -15,6 +15,7 @@
#include <linux/io.h>
#include <linux/pm_runtime.h>
#include <linux/pm_domain.h>
+#include <linux/pm_clock.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/sh_clk.h>
diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c
index 79f0413d8725..2380389e6ac5 100644
--- a/arch/arm/mach-shmobile/setup-sh7372.c
+++ b/arch/arm/mach-shmobile/setup-sh7372.c
@@ -30,6 +30,7 @@
#include <linux/sh_dma.h>
#include <linux/sh_intc.h>
#include <linux/sh_timer.h>
+#include <linux/pm_domain.h>
#include <mach/hardware.h>
#include <mach/sh7372.h>
#include <asm/mach-types.h>
@@ -169,35 +170,35 @@ static struct platform_device scif6_device = {
};
/* CMT */
-static struct sh_timer_config cmt10_platform_data = {
- .name = "CMT10",
- .channel_offset = 0x10,
- .timer_bit = 0,
+static struct sh_timer_config cmt2_platform_data = {
+ .name = "CMT2",
+ .channel_offset = 0x40,
+ .timer_bit = 5,
.clockevent_rating = 125,
.clocksource_rating = 125,
};
-static struct resource cmt10_resources[] = {
+static struct resource cmt2_resources[] = {
[0] = {
- .name = "CMT10",
- .start = 0xe6138010,
- .end = 0xe613801b,
+ .name = "CMT2",
+ .start = 0xe6130040,
+ .end = 0xe613004b,
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = evt2irq(0x0b00), /* CMT1_CMT10 */
+ .start = evt2irq(0x0b80), /* CMT2 */
.flags = IORESOURCE_IRQ,
},
};
-static struct platform_device cmt10_device = {
+static struct platform_device cmt2_device = {
.name = "sh_cmt",
- .id = 10,
+ .id = 2,
.dev = {
- .platform_data = &cmt10_platform_data,
+ .platform_data = &cmt2_platform_data,
},
- .resource = cmt10_resources,
- .num_resources = ARRAY_SIZE(cmt10_resources),
+ .resource = cmt2_resources,
+ .num_resources = ARRAY_SIZE(cmt2_resources),
};
/* TMU */
@@ -602,6 +603,150 @@ static struct platform_device dma2_device = {
},
};
+/*
+ * USB-DMAC
+ */
+
+unsigned int usbts_shift[] = {3, 4, 5};
+
+enum {
+ XMIT_SZ_8BYTE = 0,
+ XMIT_SZ_16BYTE = 1,
+ XMIT_SZ_32BYTE = 2,
+};
+
+#define USBTS_INDEX2VAL(i) (((i) & 3) << 6)
+
+static const struct sh_dmae_channel sh7372_usb_dmae_channels[] = {
+ {
+ .offset = 0,
+ }, {
+ .offset = 0x20,
+ },
+};
+
+/* USB DMAC0 */
+static const struct sh_dmae_slave_config sh7372_usb_dmae0_slaves[] = {
+ {
+ .slave_id = SHDMA_SLAVE_USB0_TX,
+ .chcr = USBTS_INDEX2VAL(XMIT_SZ_8BYTE),
+ }, {
+ .slave_id = SHDMA_SLAVE_USB0_RX,
+ .chcr = USBTS_INDEX2VAL(XMIT_SZ_8BYTE),
+ },
+};
+
+static struct sh_dmae_pdata usb_dma0_platform_data = {
+ .slave = sh7372_usb_dmae0_slaves,
+ .slave_num = ARRAY_SIZE(sh7372_usb_dmae0_slaves),
+ .channel = sh7372_usb_dmae_channels,
+ .channel_num = ARRAY_SIZE(sh7372_usb_dmae_channels),
+ .ts_low_shift = 6,
+ .ts_low_mask = 0xc0,
+ .ts_high_shift = 0,
+ .ts_high_mask = 0,
+ .ts_shift = usbts_shift,
+ .ts_shift_num = ARRAY_SIZE(usbts_shift),
+ .dmaor_init = DMAOR_DME,
+ .chcr_offset = 0x14,
+ .chcr_ie_bit = 1 << 5,
+ .dmaor_is_32bit = 1,
+ .needs_tend_set = 1,
+ .no_dmars = 1,
+};
+
+static struct resource sh7372_usb_dmae0_resources[] = {
+ {
+ /* Channel registers and DMAOR */
+ .start = 0xe68a0020,
+ .end = 0xe68a0064 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ /* VCR/SWR/DMICR */
+ .start = 0xe68a0000,
+ .end = 0xe68a0014 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ /* IRQ for channels */
+ .start = evt2irq(0x0a00),
+ .end = evt2irq(0x0a00),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device usb_dma0_device = {
+ .name = "sh-dma-engine",
+ .id = 3,
+ .resource = sh7372_usb_dmae0_resources,
+ .num_resources = ARRAY_SIZE(sh7372_usb_dmae0_resources),
+ .dev = {
+ .platform_data = &usb_dma0_platform_data,
+ },
+};
+
+/* USB DMAC1 */
+static const struct sh_dmae_slave_config sh7372_usb_dmae1_slaves[] = {
+ {
+ .slave_id = SHDMA_SLAVE_USB1_TX,
+ .chcr = USBTS_INDEX2VAL(XMIT_SZ_8BYTE),
+ }, {
+ .slave_id = SHDMA_SLAVE_USB1_RX,
+ .chcr = USBTS_INDEX2VAL(XMIT_SZ_8BYTE),
+ },
+};
+
+static struct sh_dmae_pdata usb_dma1_platform_data = {
+ .slave = sh7372_usb_dmae1_slaves,
+ .slave_num = ARRAY_SIZE(sh7372_usb_dmae1_slaves),
+ .channel = sh7372_usb_dmae_channels,
+ .channel_num = ARRAY_SIZE(sh7372_usb_dmae_channels),
+ .ts_low_shift = 6,
+ .ts_low_mask = 0xc0,
+ .ts_high_shift = 0,
+ .ts_high_mask = 0,
+ .ts_shift = usbts_shift,
+ .ts_shift_num = ARRAY_SIZE(usbts_shift),
+ .dmaor_init = DMAOR_DME,
+ .chcr_offset = 0x14,
+ .chcr_ie_bit = 1 << 5,
+ .dmaor_is_32bit = 1,
+ .needs_tend_set = 1,
+ .no_dmars = 1,
+};
+
+static struct resource sh7372_usb_dmae1_resources[] = {
+ {
+ /* Channel registers and DMAOR */
+ .start = 0xe68c0020,
+ .end = 0xe68c0064 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ /* VCR/SWR/DMICR */
+ .start = 0xe68c0000,
+ .end = 0xe68c0014 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ /* IRQ for channels */
+ .start = evt2irq(0x1d00),
+ .end = evt2irq(0x1d00),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device usb_dma1_device = {
+ .name = "sh-dma-engine",
+ .id = 4,
+ .resource = sh7372_usb_dmae1_resources,
+ .num_resources = ARRAY_SIZE(sh7372_usb_dmae1_resources),
+ .dev = {
+ .platform_data = &usb_dma1_platform_data,
+ },
+};
+
/* VPU */
static struct uio_info vpu_platform_data = {
.name = "VPU5HG",
@@ -818,7 +963,7 @@ static struct platform_device *sh7372_early_devices[] __initdata = {
&scif4_device,
&scif5_device,
&scif6_device,
- &cmt10_device,
+ &cmt2_device,
&tmu00_device,
&tmu01_device,
};
@@ -829,6 +974,8 @@ static struct platform_device *sh7372_late_devices[] __initdata = {
&dma0_device,
&dma1_device,
&dma2_device,
+ &usb_dma0_device,
+ &usb_dma1_device,
&vpu_device,
&veu0_device,
&veu1_device,
@@ -844,9 +991,14 @@ void __init sh7372_add_standard_devices(void)
sh7372_init_pm_domain(&sh7372_a4lc);
sh7372_init_pm_domain(&sh7372_a4mp);
sh7372_init_pm_domain(&sh7372_d4);
+ sh7372_init_pm_domain(&sh7372_a4r);
sh7372_init_pm_domain(&sh7372_a3rv);
sh7372_init_pm_domain(&sh7372_a3ri);
sh7372_init_pm_domain(&sh7372_a3sg);
+ sh7372_init_pm_domain(&sh7372_a3sp);
+
+ sh7372_pm_add_subdomain(&sh7372_a4lc, &sh7372_a3rv);
+ sh7372_pm_add_subdomain(&sh7372_a4r, &sh7372_a4lc);
platform_add_devices(sh7372_early_devices,
ARRAY_SIZE(sh7372_early_devices));
@@ -857,6 +1009,25 @@ void __init sh7372_add_standard_devices(void)
sh7372_add_device_to_domain(&sh7372_a3rv, &vpu_device);
sh7372_add_device_to_domain(&sh7372_a4mp, &spu0_device);
sh7372_add_device_to_domain(&sh7372_a4mp, &spu1_device);
+ sh7372_add_device_to_domain(&sh7372_a3sp, &scif0_device);
+ sh7372_add_device_to_domain(&sh7372_a3sp, &scif1_device);
+ sh7372_add_device_to_domain(&sh7372_a3sp, &scif2_device);
+ sh7372_add_device_to_domain(&sh7372_a3sp, &scif3_device);
+ sh7372_add_device_to_domain(&sh7372_a3sp, &scif4_device);
+ sh7372_add_device_to_domain(&sh7372_a3sp, &scif5_device);
+ sh7372_add_device_to_domain(&sh7372_a3sp, &scif6_device);
+ sh7372_add_device_to_domain(&sh7372_a3sp, &iic1_device);
+ sh7372_add_device_to_domain(&sh7372_a3sp, &dma0_device);
+ sh7372_add_device_to_domain(&sh7372_a3sp, &dma1_device);
+ sh7372_add_device_to_domain(&sh7372_a3sp, &dma2_device);
+ sh7372_add_device_to_domain(&sh7372_a3sp, &usb_dma0_device);
+ sh7372_add_device_to_domain(&sh7372_a3sp, &usb_dma1_device);
+ sh7372_add_device_to_domain(&sh7372_a4r, &iic0_device);
+ sh7372_add_device_to_domain(&sh7372_a4r, &veu0_device);
+ sh7372_add_device_to_domain(&sh7372_a4r, &veu1_device);
+ sh7372_add_device_to_domain(&sh7372_a4r, &veu2_device);
+ sh7372_add_device_to_domain(&sh7372_a4r, &veu3_device);
+ sh7372_add_device_to_domain(&sh7372_a4r, &jpu_device);
}
void __init sh7372_add_early_devices(void)
diff --git a/arch/arm/mach-shmobile/sleep-sh7372.S b/arch/arm/mach-shmobile/sleep-sh7372.S
index d37d3ca4d18f..f3ab3c5810ea 100644
--- a/arch/arm/mach-shmobile/sleep-sh7372.S
+++ b/arch/arm/mach-shmobile/sleep-sh7372.S
@@ -30,58 +30,20 @@
*/
#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/memory.h>
#include <asm/assembler.h>
-#define SMFRAM 0xe6a70000
-
- .align
-kernel_flush:
- .word v7_flush_dcache_all
-
- .align 3
-ENTRY(sh7372_cpu_suspend)
- stmfd sp!, {r0-r12, lr} @ save registers on stack
-
- ldr r8, =SMFRAM
-
- mov r4, sp @ Store sp
- mrs r5, spsr @ Store spsr
- mov r6, lr @ Store lr
- stmia r8!, {r4-r6}
-
- mrc p15, 0, r4, c1, c0, 2 @ Coprocessor access control register
- mrc p15, 0, r5, c2, c0, 0 @ TTBR0
- mrc p15, 0, r6, c2, c0, 1 @ TTBR1
- mrc p15, 0, r7, c2, c0, 2 @ TTBCR
- stmia r8!, {r4-r7}
-
- mrc p15, 0, r4, c3, c0, 0 @ Domain access Control Register
- mrc p15, 0, r5, c10, c2, 0 @ PRRR
- mrc p15, 0, r6, c10, c2, 1 @ NMRR
- stmia r8!,{r4-r6}
-
- mrc p15, 0, r4, c13, c0, 1 @ Context ID
- mrc p15, 0, r5, c13, c0, 2 @ User r/w thread and process ID
- mrc p15, 0, r6, c12, c0, 0 @ Secure or NS vector base address
- mrs r7, cpsr @ Store current cpsr
- stmia r8!, {r4-r7}
-
- mrc p15, 0, r4, c1, c0, 0 @ save control register
- stmia r8!, {r4}
-
- /*
- * jump out to kernel flush routine
- * - reuse that code is better
- * - it executes in a cached space so is faster than refetch per-block
- * - should be faster and will change with kernel
- * - 'might' have to copy address, load and jump to it
- * Flush all data from the L1 data cache before disabling
- * SCTLR.C bit.
- */
- ldr r1, kernel_flush
- mov lr, pc
- bx r1
+#if defined(CONFIG_SUSPEND) || defined(CONFIG_CPU_IDLE)
+ .align 12
+ .text
+ .global sh7372_resume_core_standby_a3sm
+sh7372_resume_core_standby_a3sm:
+ ldr pc, 1f
+1: .long cpu_resume - PAGE_OFFSET + PLAT_PHYS_OFFSET
+ .global sh7372_do_idle_a3sm
+sh7372_do_idle_a3sm:
/*
* Clear the SCTLR.C bit to prevent further data cache
* allocation. Clearing SCTLR.C would make all the data accesses
@@ -92,10 +54,13 @@ ENTRY(sh7372_cpu_suspend)
mcr p15, 0, r0, c1, c0, 0
isb
+ /* disable L2 cache in the aux control register */
+ mrc p15, 0, r10, c1, c0, 1
+ bic r10, r10, #2
+ mcr p15, 0, r10, c1, c0, 1
+
/*
- * Invalidate L1 data cache. Even though only invalidate is
- * necessary exported flush API is used here. Doing clean
- * on already clean cache would be almost NOP.
+ * Invalidate data cache again.
*/
ldr r1, kernel_flush
blx r1
@@ -115,146 +80,16 @@ ENTRY(sh7372_cpu_suspend)
dsb
dmb
-/*
- * ===================================
- * == WFI instruction => Enter idle ==
- * ===================================
- */
- wfi @ wait for interrupt
-
-/*
- * ===================================
- * == Resume path for non-OFF modes ==
- * ===================================
- */
- mrc p15, 0, r0, c1, c0, 0
- tst r0, #(1 << 2) @ Check C bit enabled?
- orreq r0, r0, #(1 << 2) @ Enable the C bit if cleared
- mcreq p15, 0, r0, c1, c0, 0
- isb
-
-/*
- * ===================================
- * == Exit point from non-OFF modes ==
- * ===================================
- */
- ldmfd sp!, {r0-r12, pc} @ restore regs and return
+#define SPDCR 0xe6180008
+#define A3SM (1 << 12)
- .pool
+ /* A3SM power down */
+ ldr r0, =SPDCR
+ ldr r1, =A3SM
+ str r1, [r0]
+1:
+ b 1b
- .align 12
- .text
- .global sh7372_cpu_resume
-sh7372_cpu_resume:
-
- mov r1, #0
- /*
- * Invalidate all instruction caches to PoU
- * and flush branch target cache
- */
- mcr p15, 0, r1, c7, c5, 0
-
- ldr r3, =SMFRAM
-
- ldmia r3!, {r4-r6}
- mov sp, r4 @ Restore sp
- msr spsr_cxsf, r5 @ Restore spsr
- mov lr, r6 @ Restore lr
-
- ldmia r3!, {r4-r7}
- mcr p15, 0, r4, c1, c0, 2 @ Coprocessor access Control Register
- mcr p15, 0, r5, c2, c0, 0 @ TTBR0
- mcr p15, 0, r6, c2, c0, 1 @ TTBR1
- mcr p15, 0, r7, c2, c0, 2 @ TTBCR
-
- ldmia r3!,{r4-r6}
- mcr p15, 0, r4, c3, c0, 0 @ Domain access Control Register
- mcr p15, 0, r5, c10, c2, 0 @ PRRR
- mcr p15, 0, r6, c10, c2, 1 @ NMRR
-
- ldmia r3!,{r4-r7}
- mcr p15, 0, r4, c13, c0, 1 @ Context ID
- mcr p15, 0, r5, c13, c0, 2 @ User r/w thread and process ID
- mrc p15, 0, r6, c12, c0, 0 @ Secure or NS vector base address
- msr cpsr, r7 @ store cpsr
-
- /* Starting to enable MMU here */
- mrc p15, 0, r7, c2, c0, 2 @ Read TTBRControl
- /* Extract N (0:2) bits and decide whether to use TTBR0 or TTBR1 */
- and r7, #0x7
- cmp r7, #0x0
- beq usettbr0
-ttbr_error:
- /*
- * More work needs to be done to support N[0:2] value other than 0
- * So looping here so that the error can be detected
- */
- b ttbr_error
-
- .align
-cache_pred_disable_mask:
- .word 0xFFFFE7FB
-ttbrbit_mask:
- .word 0xFFFFC000
-table_index_mask:
- .word 0xFFF00000
-table_entry:
- .word 0x00000C02
-usettbr0:
-
- mrc p15, 0, r2, c2, c0, 0
- ldr r5, ttbrbit_mask
- and r2, r5
- mov r4, pc
- ldr r5, table_index_mask
- and r4, r5 @ r4 = 31 to 20 bits of pc
- /* Extract the value to be written to table entry */
- ldr r6, table_entry
- /* r6 has the value to be written to table entry */
- add r6, r6, r4
- /* Getting the address of table entry to modify */
- lsr r4, #18
- /* r2 has the location which needs to be modified */
- add r2, r4
- ldr r4, [r2]
- str r6, [r2] /* modify the table entry */
-
- mov r7, r6
- mov r5, r2
- mov r6, r4
- /* r5 = original page table address */
- /* r6 = original page table data */
-
- mov r0, #0
- mcr p15, 0, r0, c7, c5, 4 @ Flush prefetch buffer
- mcr p15, 0, r0, c7, c5, 6 @ Invalidate branch predictor array
- mcr p15, 0, r0, c8, c5, 0 @ Invalidate instruction TLB
- mcr p15, 0, r0, c8, c6, 0 @ Invalidate data TLB
-
- /*
- * Restore control register. This enables the MMU.
- * The caches and prediction are not enabled here, they
- * will be enabled after restoring the MMU table entry.
- */
- ldmia r3!, {r4}
- stmia r3!, {r5} /* save original page table address */
- stmia r3!, {r6} /* save original page table data */
- stmia r3!, {r7} /* save modified page table data */
-
- ldr r2, cache_pred_disable_mask
- and r4, r2
- mcr p15, 0, r4, c1, c0, 0
- dsb
- isb
-
- ldr r0, =restoremmu_on
- bx r0
-
-/*
- * ==============================
- * == Exit point from OFF mode ==
- * ==============================
- */
-restoremmu_on:
-
- ldmfd sp!, {r0-r12, pc} @ restore regs and return
+kernel_flush:
+ .word v7_flush_dcache_all
+#endif
diff --git a/arch/arm/mach-spear3xx/Makefile.boot b/arch/arm/mach-spear3xx/Makefile.boot
index 7a1f3c0eadb8..4674a4c221db 100644
--- a/arch/arm/mach-spear3xx/Makefile.boot
+++ b/arch/arm/mach-spear3xx/Makefile.boot
@@ -1,3 +1,3 @@
-zreladdr-y := 0x00008000
+zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
diff --git a/arch/arm/mach-spear6xx/Makefile.boot b/arch/arm/mach-spear6xx/Makefile.boot
index 7a1f3c0eadb8..4674a4c221db 100644
--- a/arch/arm/mach-spear6xx/Makefile.boot
+++ b/arch/arm/mach-spear6xx/Makefile.boot
@@ -1,3 +1,3 @@
-zreladdr-y := 0x00008000
+zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
diff --git a/arch/arm/mach-tcc8k/Makefile.boot b/arch/arm/mach-tcc8k/Makefile.boot
index f135c9deae10..5e02d4156b04 100644
--- a/arch/arm/mach-tcc8k/Makefile.boot
+++ b/arch/arm/mach-tcc8k/Makefile.boot
@@ -1,3 +1,3 @@
- zreladdr-y := 0x20008000
+ zreladdr-y += 0x20008000
params_phys-y := 0x20000100
initrd_phys-y := 0x20800000
diff --git a/arch/arm/mach-tegra/Makefile.boot b/arch/arm/mach-tegra/Makefile.boot
index 428ad122be03..5e870d29eca1 100644
--- a/arch/arm/mach-tegra/Makefile.boot
+++ b/arch/arm/mach-tegra/Makefile.boot
@@ -1,4 +1,4 @@
-zreladdr-$(CONFIG_ARCH_TEGRA_2x_SOC) := 0x00008000
+zreladdr-$(CONFIG_ARCH_TEGRA_2x_SOC) += 0x00008000
params_phys-$(CONFIG_ARCH_TEGRA_2x_SOC) := 0x00000100
initrd_phys-$(CONFIG_ARCH_TEGRA_2x_SOC) := 0x00800000
diff --git a/arch/arm/mach-tegra/board-harmony.c b/arch/arm/mach-tegra/board-harmony.c
index 846cd7d69e3e..c78ce41cca16 100644
--- a/arch/arm/mach-tegra/board-harmony.c
+++ b/arch/arm/mach-tegra/board-harmony.c
@@ -123,8 +123,8 @@ static struct platform_device *harmony_devices[] __initdata = {
&harmony_audio_device,
};
-static void __init tegra_harmony_fixup(struct machine_desc *desc,
- struct tag *tags, char **cmdline, struct meminfo *mi)
+static void __init tegra_harmony_fixup(struct tag *tags, char **cmdline,
+ struct meminfo *mi)
{
mi->nr_banks = 2;
mi->bank[0].start = PHYS_OFFSET;
diff --git a/arch/arm/mach-tegra/board-paz00.c b/arch/arm/mach-tegra/board-paz00.c
index ea2f79c9879b..5e6bc7719642 100644
--- a/arch/arm/mach-tegra/board-paz00.c
+++ b/arch/arm/mach-tegra/board-paz00.c
@@ -84,8 +84,8 @@ static void paz00_usb_init(void)
platform_device_register(&tegra_ehci3_device);
}
-static void __init tegra_paz00_fixup(struct machine_desc *desc,
- struct tag *tags, char **cmdline, struct meminfo *mi)
+static void __init tegra_paz00_fixup(struct tag *tags, char **cmdline,
+ struct meminfo *mi)
{
mi->nr_banks = 1;
mi->bank[0].start = PHYS_OFFSET;
diff --git a/arch/arm/mach-tegra/board-trimslice.c b/arch/arm/mach-tegra/board-trimslice.c
index 89a6d2adc1de..652c3404d0e2 100644
--- a/arch/arm/mach-tegra/board-trimslice.c
+++ b/arch/arm/mach-tegra/board-trimslice.c
@@ -126,8 +126,8 @@ static void trimslice_usb_init(void)
platform_device_register(&tegra_ehci1_device);
}
-static void __init tegra_trimslice_fixup(struct machine_desc *desc,
- struct tag *tags, char **cmdline, struct meminfo *mi)
+static void __init tegra_trimslice_fixup(struct tag *tags, char **cmdline,
+ struct meminfo *mi)
{
mi->nr_banks = 2;
mi->bank[0].start = PHYS_OFFSET;
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
index 0e1016a827ac..0e0fd4d889bd 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -32,7 +32,6 @@
#include <asm/system.h>
-#include <mach/hardware.h>
#include <mach/clk.h>
/* Frequency table index must be sequential starting at 0 */
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index 0886cbccddee..7d2b5d03c1df 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -114,10 +114,10 @@ void __init smp_init_cpus(void)
{
unsigned int i, ncores = scu_get_core_count(scu_base);
- if (ncores > NR_CPUS) {
- printk(KERN_ERR "Tegra: no. of cores (%u) greater than configured (%u), clipping\n",
- ncores, NR_CPUS);
- ncores = NR_CPUS;
+ if (ncores > nr_cpu_ids) {
+ pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
+ ncores, nr_cpu_ids);
+ ncores = nr_cpu_ids;
}
for (i = 0; i < ncores; i++)
diff --git a/arch/arm/mach-u300/Kconfig b/arch/arm/mach-u300/Kconfig
index 32a7b0f7e9f7..449fd6a8dbd6 100644
--- a/arch/arm/mach-u300/Kconfig
+++ b/arch/arm/mach-u300/Kconfig
@@ -6,6 +6,8 @@ comment "ST-Ericsson Mobile Platform Products"
config MACH_U300
bool "U300"
+ select PINCTRL
+ select PINMUX_U300
comment "ST-Ericsson U300/U330/U335/U365 Feature Selections"
diff --git a/arch/arm/mach-u300/Makefile b/arch/arm/mach-u300/Makefile
index 8fd354aaf0a7..285538124e5e 100644
--- a/arch/arm/mach-u300/Makefile
+++ b/arch/arm/mach-u300/Makefile
@@ -2,7 +2,7 @@
# Makefile for the linux kernel, U300 machine.
#
-obj-y := core.o clock.o timer.o padmux.o
+obj-y := core.o clock.o timer.o
obj-m :=
obj-n :=
obj- :=
diff --git a/arch/arm/mach-u300/Makefile.boot b/arch/arm/mach-u300/Makefile.boot
index 6fbfc6ea2d35..69357affbd77 100644
--- a/arch/arm/mach-u300/Makefile.boot
+++ b/arch/arm/mach-u300/Makefile.boot
@@ -4,10 +4,10 @@
# INITRD_PHYS must be in RAM
ifdef CONFIG_MACH_U300_SINGLE_RAM
- zreladdr-y := 0x28E08000
+ zreladdr-y += 0x28E08000
params_phys-y := 0x28E00100
else
- zreladdr-y := 0x48008000
+ zreladdr-y += 0x48008000
params_phys-y := 0x48000100
endif
diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c
index 399c89f14dfb..2f5929bdeaa2 100644
--- a/arch/arm/mach-u300/core.c
+++ b/arch/arm/mach-u300/core.c
@@ -25,6 +25,8 @@
#include <linux/err.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/fsmc.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinmux.h>
#include <asm/types.h>
#include <asm/setup.h>
@@ -1535,6 +1537,14 @@ static struct coh901318_platform coh901318_platform = {
.max_channels = U300_DMA_CHANNELS,
};
+static struct resource pinmux_resources[] = {
+ {
+ .start = U300_SYSCON_BASE,
+ .end = U300_SYSCON_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
static struct platform_device wdog_device = {
.name = "coh901327_wdog",
.id = -1,
@@ -1630,6 +1640,72 @@ static struct platform_device dma_device = {
},
};
+static struct platform_device pinmux_device = {
+ .name = "pinmux-u300",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(pinmux_resources),
+ .resource = pinmux_resources,
+};
+
+/* Pinmux settings */
+static struct pinmux_map u300_pinmux_map[] = {
+ /* anonymous maps for chip power and EMIFs */
+ PINMUX_MAP_PRIMARY_SYS_HOG("POWER", "power"),
+ PINMUX_MAP_PRIMARY_SYS_HOG("EMIF0", "emif0"),
+ PINMUX_MAP_PRIMARY_SYS_HOG("EMIF1", "emif1"),
+ /* per-device maps for MMC/SD, SPI and UART */
+ PINMUX_MAP_PRIMARY("MMCSD", "mmc0", "mmci"),
+ PINMUX_MAP_PRIMARY("SPI", "spi0", "pl022"),
+ PINMUX_MAP_PRIMARY("UART0", "uart0", "uart0"),
+};
+
+struct u300_mux_hog {
+ const char *name;
+ struct device *dev;
+ struct pinmux *pmx;
+};
+
+static struct u300_mux_hog u300_mux_hogs[] = {
+ {
+ .name = "uart0",
+ .dev = &uart0_device.dev,
+ },
+ {
+ .name = "spi0",
+ .dev = &pl022_device.dev,
+ },
+ {
+ .name = "mmc0",
+ .dev = &mmcsd_device.dev,
+ },
+};
+
+static int __init u300_pinmux_fetch(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(u300_mux_hogs); i++) {
+ struct pinmux *pmx;
+ int ret;
+
+ pmx = pinmux_get(u300_mux_hogs[i].dev, NULL);
+ if (IS_ERR(pmx)) {
+ pr_err("u300: could not get pinmux hog %s\n",
+ u300_mux_hogs[i].name);
+ continue;
+ }
+ ret = pinmux_enable(pmx);
+ if (ret) {
+ pr_err("u300: could enable pinmux hog %s\n",
+ u300_mux_hogs[i].name);
+ continue;
+ }
+ u300_mux_hogs[i].pmx = pmx;
+ }
+ return 0;
+}
+subsys_initcall(u300_pinmux_fetch);
+
/*
* Notice that AMBA devices are initialized before platform devices.
*
@@ -1643,10 +1719,10 @@ static struct platform_device *platform_devs[] __initdata = {
&gpio_device,
&nand_device,
&wdog_device,
- &ave_device
+ &ave_device,
+ &pinmux_device,
};
-
/*
* Interrupts: the U300 platforms have two pl190 ARM PrimeCells connected
* together so some interrupts are connected to the first one and some
@@ -1828,6 +1904,10 @@ void __init u300_init_devices(void)
u300_assign_physmem();
+ /* Initialize pinmuxing */
+ pinmux_register_mappings(u300_pinmux_map,
+ ARRAY_SIZE(u300_pinmux_map));
+
/* Register subdevices on the I2C buses */
u300_i2c_register_board_devices();
diff --git a/arch/arm/mach-u300/include/mach/syscon.h b/arch/arm/mach-u300/include/mach/syscon.h
index 7444f5c7da97..6e84f07a7c6f 100644
--- a/arch/arm/mach-u300/include/mach/syscon.h
+++ b/arch/arm/mach-u300/include/mach/syscon.h
@@ -234,91 +234,6 @@
#define U300_SYSCON_ECCR_EMIF_1_RET_OUT_CLK_EN_N_DISABLE (0x0004)
#define U300_SYSCON_ECCR_EMIF_MEMCLK_RET_EN_N_DISABLE (0x0002)
#define U300_SYSCON_ECCR_EMIF_SDRCLK_RET_EN_N_DISABLE (0x0001)
-/* PAD MUX Control register 1 (LOW) 16bit (R/W) */
-#define U300_SYSCON_PMC1LR (0x007C)
-#define U300_SYSCON_PMC1LR_MASK (0xFFFF)
-#define U300_SYSCON_PMC1LR_CDI_MASK (0xC000)
-#define U300_SYSCON_PMC1LR_CDI_CDI (0x0000)
-#define U300_SYSCON_PMC1LR_CDI_EMIF (0x4000)
-#ifdef CONFIG_MACH_U300_BS335
-#define U300_SYSCON_PMC1LR_CDI_CDI2 (0x8000)
-#define U300_SYSCON_PMC1LR_CDI_WCDMA_APP_GPIO (0xC000)
-#elif CONFIG_MACH_U300_BS365
-#define U300_SYSCON_PMC1LR_CDI_GPIO (0x8000)
-#define U300_SYSCON_PMC1LR_CDI_WCDMA (0xC000)
-#endif
-#define U300_SYSCON_PMC1LR_PDI_MASK (0x3000)
-#define U300_SYSCON_PMC1LR_PDI_PDI (0x0000)
-#define U300_SYSCON_PMC1LR_PDI_EGG (0x1000)
-#define U300_SYSCON_PMC1LR_PDI_WCDMA (0x3000)
-#define U300_SYSCON_PMC1LR_MMCSD_MASK (0x0C00)
-#define U300_SYSCON_PMC1LR_MMCSD_MMCSD (0x0000)
-#define U300_SYSCON_PMC1LR_MMCSD_MSPRO (0x0400)
-#define U300_SYSCON_PMC1LR_MMCSD_DSP (0x0800)
-#define U300_SYSCON_PMC1LR_MMCSD_WCDMA (0x0C00)
-#define U300_SYSCON_PMC1LR_ETM_MASK (0x0300)
-#define U300_SYSCON_PMC1LR_ETM_ACC (0x0000)
-#define U300_SYSCON_PMC1LR_ETM_APP (0x0100)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS2_MASK (0x00C0)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS2_STATIC (0x0000)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS2_NFIF (0x0040)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS2_SDRAM (0x0080)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS2_STATIC_2GB (0x00C0)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS1_MASK (0x0030)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS1_STATIC (0x0000)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS1_NFIF (0x0010)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS1_SDRAM (0x0020)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS1_SEMI (0x0030)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS0_MASK (0x000C)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS0_STATIC (0x0000)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS0_NFIF (0x0004)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS0_SDRAM (0x0008)
-#define U300_SYSCON_PMC1LR_EMIF_1_CS0_SEMI (0x000C)
-#define U300_SYSCON_PMC1LR_EMIF_1_MASK (0x0003)
-#define U300_SYSCON_PMC1LR_EMIF_1_STATIC (0x0000)
-#define U300_SYSCON_PMC1LR_EMIF_1_SDRAM0 (0x0001)
-#define U300_SYSCON_PMC1LR_EMIF_1_SDRAM1 (0x0002)
-#define U300_SYSCON_PMC1LR_EMIF_1 (0x0003)
-/* PAD MUX Control register 2 (HIGH) 16bit (R/W) */
-#define U300_SYSCON_PMC1HR (0x007E)
-#define U300_SYSCON_PMC1HR_MASK (0xFFFF)
-#define U300_SYSCON_PMC1HR_MISC_2_MASK (0xC000)
-#define U300_SYSCON_PMC1HR_MISC_2_APP_GPIO (0x0000)
-#define U300_SYSCON_PMC1HR_MISC_2_MSPRO (0x4000)
-#define U300_SYSCON_PMC1HR_MISC_2_DSP (0x8000)
-#define U300_SYSCON_PMC1HR_MISC_2_AAIF (0xC000)
-#define U300_SYSCON_PMC1HR_APP_GPIO_2_MASK (0x3000)
-#define U300_SYSCON_PMC1HR_APP_GPIO_2_APP_GPIO (0x0000)
-#define U300_SYSCON_PMC1HR_APP_GPIO_2_NFIF (0x1000)
-#define U300_SYSCON_PMC1HR_APP_GPIO_2_DSP (0x2000)
-#define U300_SYSCON_PMC1HR_APP_GPIO_2_AAIF (0x3000)
-#define U300_SYSCON_PMC1HR_APP_GPIO_1_MASK (0x0C00)
-#define U300_SYSCON_PMC1HR_APP_GPIO_1_APP_GPIO (0x0000)
-#define U300_SYSCON_PMC1HR_APP_GPIO_1_MMC (0x0400)
-#define U300_SYSCON_PMC1HR_APP_GPIO_1_DSP (0x0800)
-#define U300_SYSCON_PMC1HR_APP_GPIO_1_AAIF (0x0C00)
-#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_MASK (0x0300)
-#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_APP_GPIO (0x0000)
-#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_SPI (0x0100)
-#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_AAIF (0x0300)
-#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_MASK (0x00C0)
-#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_APP_GPIO (0x0000)
-#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_SPI (0x0040)
-#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_AAIF (0x00C0)
-#define U300_SYSCON_PMC1HR_APP_SPI_2_MASK (0x0030)
-#define U300_SYSCON_PMC1HR_APP_SPI_2_APP_GPIO (0x0000)
-#define U300_SYSCON_PMC1HR_APP_SPI_2_SPI (0x0010)
-#define U300_SYSCON_PMC1HR_APP_SPI_2_DSP (0x0020)
-#define U300_SYSCON_PMC1HR_APP_SPI_2_AAIF (0x0030)
-#define U300_SYSCON_PMC1HR_APP_UART0_2_MASK (0x000C)
-#define U300_SYSCON_PMC1HR_APP_UART0_2_APP_GPIO (0x0000)
-#define U300_SYSCON_PMC1HR_APP_UART0_2_UART0 (0x0004)
-#define U300_SYSCON_PMC1HR_APP_UART0_2_NFIF_CS (0x0008)
-#define U300_SYSCON_PMC1HR_APP_UART0_2_AAIF (0x000C)
-#define U300_SYSCON_PMC1HR_APP_UART0_1_MASK (0x0003)
-#define U300_SYSCON_PMC1HR_APP_UART0_1_APP_GPIO (0x0000)
-#define U300_SYSCON_PMC1HR_APP_UART0_1_UART0 (0x0001)
-#define U300_SYSCON_PMC1HR_APP_UART0_1_AAIF (0x0003)
/* Step one for killing the applications system 16bit (-/W) */
#define U300_SYSCON_KA1R (0x0080)
#define U300_SYSCON_KA1R_MASK (0xFFFF)
@@ -357,57 +272,6 @@
#define U300_SYSCON_PUCR_EMIF_1_16BIT_PU_ENABLE (0x0080)
#define U300_SYSCON_PUCR_EMIF_1_8BIT_PU_ENABLE (0x0040)
#define U300_SYSCON_PUCR_KEY_IN_PU_EN_MASK (0x003F)
-/* Padmux 2 control */
-#define U300_SYSCON_PMC2R (0x100)
-#define U300_SYSCON_PMC2R_APP_MISC_0_MASK (0x00C0)
-#define U300_SYSCON_PMC2R_APP_MISC_0_APP_GPIO (0x0000)
-#define U300_SYSCON_PMC2R_APP_MISC_0_EMIF_SDRAM (0x0040)
-#define U300_SYSCON_PMC2R_APP_MISC_0_MMC (0x0080)
-#define U300_SYSCON_PMC2R_APP_MISC_0_CDI2 (0x00C0)
-#define U300_SYSCON_PMC2R_APP_MISC_1_MASK (0x0300)
-#define U300_SYSCON_PMC2R_APP_MISC_1_APP_GPIO (0x0000)
-#define U300_SYSCON_PMC2R_APP_MISC_1_EMIF_SDRAM (0x0100)
-#define U300_SYSCON_PMC2R_APP_MISC_1_MMC (0x0200)
-#define U300_SYSCON_PMC2R_APP_MISC_1_CDI2 (0x0300)
-#define U300_SYSCON_PMC2R_APP_MISC_2_MASK (0x0C00)
-#define U300_SYSCON_PMC2R_APP_MISC_2_APP_GPIO (0x0000)
-#define U300_SYSCON_PMC2R_APP_MISC_2_EMIF_SDRAM (0x0400)
-#define U300_SYSCON_PMC2R_APP_MISC_2_MMC (0x0800)
-#define U300_SYSCON_PMC2R_APP_MISC_2_CDI2 (0x0C00)
-#define U300_SYSCON_PMC2R_APP_MISC_3_MASK (0x3000)
-#define U300_SYSCON_PMC2R_APP_MISC_3_APP_GPIO (0x0000)
-#define U300_SYSCON_PMC2R_APP_MISC_3_EMIF_SDRAM (0x1000)
-#define U300_SYSCON_PMC2R_APP_MISC_3_MMC (0x2000)
-#define U300_SYSCON_PMC2R_APP_MISC_3_CDI2 (0x3000)
-#define U300_SYSCON_PMC2R_APP_MISC_4_MASK (0xC000)
-#define U300_SYSCON_PMC2R_APP_MISC_4_APP_GPIO (0x0000)
-#define U300_SYSCON_PMC2R_APP_MISC_4_EMIF_SDRAM (0x4000)
-#define U300_SYSCON_PMC2R_APP_MISC_4_MMC (0x8000)
-#define U300_SYSCON_PMC2R_APP_MISC_4_ACC_GPIO (0xC000)
-/* TODO: More SYSCON registers missing */
-#define U300_SYSCON_PMC3R (0x10c)
-#define U300_SYSCON_PMC3R_APP_MISC_11_MASK (0xc000)
-#define U300_SYSCON_PMC3R_APP_MISC_11_SPI (0x4000)
-#define U300_SYSCON_PMC3R_APP_MISC_10_MASK (0x3000)
-#define U300_SYSCON_PMC3R_APP_MISC_10_SPI (0x1000)
-/* TODO: Missing other configs */
-#define U300_SYSCON_PMC4R (0x168)
-#define U300_SYSCON_PMC4R_APP_MISC_12_MASK (0x0003)
-#define U300_SYSCON_PMC4R_APP_MISC_12_APP_GPIO (0x0000)
-#define U300_SYSCON_PMC4R_APP_MISC_13_MASK (0x000C)
-#define U300_SYSCON_PMC4R_APP_MISC_13_CDI (0x0000)
-#define U300_SYSCON_PMC4R_APP_MISC_13_SMIA (0x0004)
-#define U300_SYSCON_PMC4R_APP_MISC_13_SMIA2 (0x0008)
-#define U300_SYSCON_PMC4R_APP_MISC_13_APP_GPIO (0x000C)
-#define U300_SYSCON_PMC4R_APP_MISC_14_MASK (0x0030)
-#define U300_SYSCON_PMC4R_APP_MISC_14_CDI (0x0000)
-#define U300_SYSCON_PMC4R_APP_MISC_14_SMIA (0x0010)
-#define U300_SYSCON_PMC4R_APP_MISC_14_CDI2 (0x0020)
-#define U300_SYSCON_PMC4R_APP_MISC_14_APP_GPIO (0x0030)
-#define U300_SYSCON_PMC4R_APP_MISC_16_MASK (0x0300)
-#define U300_SYSCON_PMC4R_APP_MISC_16_APP_GPIO_13 (0x0000)
-#define U300_SYSCON_PMC4R_APP_MISC_16_APP_UART1_CTS (0x0100)
-#define U300_SYSCON_PMC4R_APP_MISC_16_EMIF_1_STATIC_CS5_N (0x0200)
/* SYS_0_CLK_CONTROL first clock control 16bit (R/W) */
#define U300_SYSCON_S0CCR (0x120)
#define U300_SYSCON_S0CCR_FIELD_MASK (0x43FF)
diff --git a/arch/arm/mach-u300/mmc.c b/arch/arm/mach-u300/mmc.c
index 677ccef5cd32..d5e4a98a9ab8 100644
--- a/arch/arm/mach-u300/mmc.c
+++ b/arch/arm/mach-u300/mmc.c
@@ -21,7 +21,6 @@
#include <mach/dma_channels.h>
#include "mmc.h"
-#include "padmux.h"
static struct mmci_platform_data mmc0_plat_data = {
/*
@@ -45,24 +44,9 @@ static struct mmci_platform_data mmc0_plat_data = {
int __devinit mmc_init(struct amba_device *adev)
{
struct device *mmcsd_device = &adev->dev;
- struct pmx *pmx;
int ret = 0;
mmcsd_device->platform_data = &mmc0_plat_data;
- /*
- * Setup padmuxing for MMC. Since this must always be
- * compiled into the kernel, pmx is never released.
- */
- pmx = pmx_get(mmcsd_device, U300_APP_PMX_MMC_SETTING);
-
- if (IS_ERR(pmx))
- pr_warning("Could not get padmux handle\n");
- else {
- ret = pmx_activate(mmcsd_device, pmx);
- if (IS_ERR_VALUE(ret))
- pr_warning("Could not activate padmuxing\n");
- }
-
return ret;
}
diff --git a/arch/arm/mach-u300/padmux.c b/arch/arm/mach-u300/padmux.c
deleted file mode 100644
index 4c93c6cefd37..000000000000
--- a/arch/arm/mach-u300/padmux.c
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- *
- * arch/arm/mach-u300/padmux.c
- *
- *
- * Copyright (C) 2009 ST-Ericsson AB
- * License terms: GNU General Public License (GPL) version 2
- * U300 PADMUX functions
- * Author: Martin Persson <martin.persson@stericsson.com>
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <linux/io.h>
-#include <linux/mutex.h>
-#include <linux/string.h>
-#include <linux/bug.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <mach/u300-regs.h>
-#include <mach/syscon.h>
-#include "padmux.h"
-
-static DEFINE_MUTEX(pmx_mutex);
-
-const u32 pmx_registers[] = {
- (U300_SYSCON_VBASE + U300_SYSCON_PMC1LR),
- (U300_SYSCON_VBASE + U300_SYSCON_PMC1HR),
- (U300_SYSCON_VBASE + U300_SYSCON_PMC2R),
- (U300_SYSCON_VBASE + U300_SYSCON_PMC3R),
- (U300_SYSCON_VBASE + U300_SYSCON_PMC4R)
-};
-
-/* High level functionality */
-
-/* Lazy dog:
- * onmask = {
- * {"PMC1LR" mask, "PMC1LR" value},
- * {"PMC1HR" mask, "PMC1HR" value},
- * {"PMC2R" mask, "PMC2R" value},
- * {"PMC3R" mask, "PMC3R" value},
- * {"PMC4R" mask, "PMC4R" value}
- * }
- */
-static struct pmx mmc_setting = {
- .setting = U300_APP_PMX_MMC_SETTING,
- .default_on = false,
- .activated = false,
- .name = "MMC",
- .onmask = {
- {U300_SYSCON_PMC1LR_MMCSD_MASK,
- U300_SYSCON_PMC1LR_MMCSD_MMCSD},
- {0, 0},
- {0, 0},
- {0, 0},
- {U300_SYSCON_PMC4R_APP_MISC_12_MASK,
- U300_SYSCON_PMC4R_APP_MISC_12_APP_GPIO}
- },
-};
-
-static struct pmx spi_setting = {
- .setting = U300_APP_PMX_SPI_SETTING,
- .default_on = false,
- .activated = false,
- .name = "SPI",
- .onmask = {{0, 0},
- {U300_SYSCON_PMC1HR_APP_SPI_2_MASK |
- U300_SYSCON_PMC1HR_APP_SPI_CS_1_MASK |
- U300_SYSCON_PMC1HR_APP_SPI_CS_2_MASK,
- U300_SYSCON_PMC1HR_APP_SPI_2_SPI |
- U300_SYSCON_PMC1HR_APP_SPI_CS_1_SPI |
- U300_SYSCON_PMC1HR_APP_SPI_CS_2_SPI},
- {0, 0},
- {0, 0},
- {0, 0}
- },
-};
-
-/* Available padmux settings */
-static struct pmx *pmx_settings[] = {
- &mmc_setting,
- &spi_setting,
-};
-
-static void update_registers(struct pmx *pmx, bool activate)
-{
- u16 regval, val, mask;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(pmx_registers); i++) {
- if (activate)
- val = pmx->onmask[i].val;
- else
- val = 0;
-
- mask = pmx->onmask[i].mask;
- if (mask != 0) {
- regval = readw(pmx_registers[i]);
- regval &= ~mask;
- regval |= val;
- writew(regval, pmx_registers[i]);
- }
- }
-}
-
-struct pmx *pmx_get(struct device *dev, enum pmx_settings setting)
-{
- int i;
- struct pmx *pmx = ERR_PTR(-ENOENT);
-
- if (dev == NULL)
- return ERR_PTR(-EINVAL);
-
- mutex_lock(&pmx_mutex);
- for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
-
- if (setting == pmx_settings[i]->setting) {
-
- if (pmx_settings[i]->dev != NULL) {
- WARN(1, "padmux: required setting "
- "in use by another consumer\n");
- } else {
- pmx = pmx_settings[i];
- pmx->dev = dev;
- dev_dbg(dev, "padmux: setting nr %d is now "
- "bound to %s and ready to use\n",
- setting, dev_name(dev));
- break;
- }
- }
- }
- mutex_unlock(&pmx_mutex);
-
- return pmx;
-}
-EXPORT_SYMBOL(pmx_get);
-
-int pmx_put(struct device *dev, struct pmx *pmx)
-{
- int i;
- int ret = -ENOENT;
-
- if (pmx == NULL || dev == NULL)
- return -EINVAL;
-
- mutex_lock(&pmx_mutex);
- for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
-
- if (pmx->setting == pmx_settings[i]->setting) {
-
- if (dev != pmx->dev) {
- WARN(1, "padmux: cannot release handle as "
- "it is bound to another consumer\n");
- ret = -EINVAL;
- break;
- } else {
- pmx_settings[i]->dev = NULL;
- ret = 0;
- break;
- }
- }
- }
- mutex_unlock(&pmx_mutex);
-
- return ret;
-}
-EXPORT_SYMBOL(pmx_put);
-
-int pmx_activate(struct device *dev, struct pmx *pmx)
-{
- int i, j, ret;
- ret = 0;
-
- if (pmx == NULL || dev == NULL)
- return -EINVAL;
-
- mutex_lock(&pmx_mutex);
-
- /* Make sure the required bits are not used */
- for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
-
- if (pmx_settings[i]->dev == NULL || pmx_settings[i] == pmx)
- continue;
-
- for (j = 0; j < ARRAY_SIZE(pmx_registers); j++) {
-
- if (pmx_settings[i]->onmask[j].mask & pmx->
- onmask[j].mask) {
- /* More than one entry on the same bits */
- WARN(1, "padmux: cannot activate "
- "setting. Bit conflict with "
- "an active setting\n");
-
- ret = -EUSERS;
- goto exit;
- }
- }
- }
- update_registers(pmx, true);
- pmx->activated = true;
- dev_dbg(dev, "padmux: setting nr %d is activated\n",
- pmx->setting);
-
-exit:
- mutex_unlock(&pmx_mutex);
- return ret;
-}
-EXPORT_SYMBOL(pmx_activate);
-
-int pmx_deactivate(struct device *dev, struct pmx *pmx)
-{
- int i;
- int ret = -ENOENT;
-
- if (pmx == NULL || dev == NULL)
- return -EINVAL;
-
- mutex_lock(&pmx_mutex);
- for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
-
- if (pmx_settings[i]->dev == NULL)
- continue;
-
- if (pmx->setting == pmx_settings[i]->setting) {
-
- if (dev != pmx->dev) {
- WARN(1, "padmux: cannot deactivate "
- "pmx setting as it was activated "
- "by another consumer\n");
-
- ret = -EBUSY;
- continue;
- } else {
- update_registers(pmx, false);
- pmx_settings[i]->dev = NULL;
- pmx->activated = false;
- ret = 0;
- dev_dbg(dev, "padmux: setting nr %d is deactivated",
- pmx->setting);
- break;
- }
- }
- }
- mutex_unlock(&pmx_mutex);
-
- return ret;
-}
-EXPORT_SYMBOL(pmx_deactivate);
-
-/*
- * For internal use only. If it is to be exported,
- * it should be reentrant. Notice that pmx_activate
- * (i.e. runtime settings) always override default settings.
- */
-static int pmx_set_default(void)
-{
- /* Used to identify several entries on the same bits */
- u16 modbits[ARRAY_SIZE(pmx_registers)];
-
- int i, j;
-
- memset(modbits, 0, ARRAY_SIZE(pmx_registers) * sizeof(u16));
-
- for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
-
- if (!pmx_settings[i]->default_on)
- continue;
-
- for (j = 0; j < ARRAY_SIZE(pmx_registers); j++) {
-
- /* Make sure there is only one entry on the same bits */
- if (modbits[j] & pmx_settings[i]->onmask[j].mask) {
- BUG();
- return -EUSERS;
- }
- modbits[j] |= pmx_settings[i]->onmask[j].mask;
- }
- update_registers(pmx_settings[i], true);
- }
- return 0;
-}
-
-#if (defined(CONFIG_DEBUG_FS) && defined(CONFIG_U300_DEBUG))
-static int pmx_show(struct seq_file *s, void *data)
-{
- int i;
- seq_printf(s, "-------------------------------------------------\n");
- seq_printf(s, "SETTING BOUND TO DEVICE STATE\n");
- seq_printf(s, "-------------------------------------------------\n");
- mutex_lock(&pmx_mutex);
- for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
- /* Format pmx and device name nicely */
- char cdp[33];
- int chars;
-
- chars = snprintf(&cdp[0], 17, "%s", pmx_settings[i]->name);
- while (chars < 16) {
- cdp[chars] = ' ';
- chars++;
- }
- chars = snprintf(&cdp[16], 17, "%s", pmx_settings[i]->dev ?
- dev_name(pmx_settings[i]->dev) : "N/A");
- while (chars < 16) {
- cdp[chars+16] = ' ';
- chars++;
- }
- cdp[32] = '\0';
-
- seq_printf(s,
- "%s\t%s\n",
- &cdp[0],
- pmx_settings[i]->activated ?
- "ACTIVATED" : "DEACTIVATED"
- );
-
- }
- mutex_unlock(&pmx_mutex);
- return 0;
-}
-
-static int pmx_open(struct inode *inode, struct file *file)
-{
- return single_open(file, pmx_show, NULL);
-}
-
-static const struct file_operations pmx_operations = {
- .owner = THIS_MODULE,
- .open = pmx_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int __init init_pmx_read_debugfs(void)
-{
- /* Expose a simple debugfs interface to view pmx settings */
- (void) debugfs_create_file("padmux", S_IFREG | S_IRUGO,
- NULL, NULL,
- &pmx_operations);
- return 0;
-}
-
-/*
- * This needs to come in after the core_initcall(),
- * because debugfs is not available until
- * the subsystems come up.
- */
-module_init(init_pmx_read_debugfs);
-#endif
-
-static int __init pmx_init(void)
-{
- int ret;
-
- ret = pmx_set_default();
-
- if (IS_ERR_VALUE(ret))
- pr_crit("padmux: default settings could not be set\n");
-
- return 0;
-}
-
-/* Should be initialized before consumers */
-core_initcall(pmx_init);
diff --git a/arch/arm/mach-u300/padmux.h b/arch/arm/mach-u300/padmux.h
deleted file mode 100644
index 6e8b86064097..000000000000
--- a/arch/arm/mach-u300/padmux.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- *
- * arch/arm/mach-u300/padmux.h
- *
- *
- * Copyright (C) 2009 ST-Ericsson AB
- * License terms: GNU General Public License (GPL) version 2
- * U300 PADMUX API
- * Author: Martin Persson <martin.persson@stericsson.com>
- */
-
-#ifndef __MACH_U300_PADMUX_H
-#define __MACH_U300_PADMUX_H
-
-enum pmx_settings {
- U300_APP_PMX_MMC_SETTING,
- U300_APP_PMX_SPI_SETTING
-};
-
-struct pmx_onmask {
- u16 mask; /* Mask bits */
- u16 val; /* Value when active */
-};
-
-struct pmx {
- struct device *dev;
- enum pmx_settings setting;
- char *name;
- bool activated;
- bool default_on;
- struct pmx_onmask onmask[];
-};
-
-struct pmx *pmx_get(struct device *dev, enum pmx_settings setting);
-int pmx_put(struct device *dev, struct pmx *pmx);
-int pmx_activate(struct device *dev, struct pmx *pmx);
-int pmx_deactivate(struct device *dev, struct pmx *pmx);
-
-#endif
diff --git a/arch/arm/mach-u300/spi.c b/arch/arm/mach-u300/spi.c
index 7b597e2b19e2..a1affacfa59c 100644
--- a/arch/arm/mach-u300/spi.c
+++ b/arch/arm/mach-u300/spi.c
@@ -14,8 +14,6 @@
#include <mach/coh901318.h>
#include <mach/dma_channels.h>
-#include "padmux.h"
-
/*
* The following is for the actual devices on the SSP/SPI bus
*/
@@ -95,25 +93,7 @@ static struct pl022_ssp_controller ssp_platform_data = {
void __init u300_spi_init(struct amba_device *adev)
{
- struct pmx *pmx;
-
adev->dev.platform_data = &ssp_platform_data;
- /*
- * Setup padmuxing for SPI. Since this must always be
- * compiled into the kernel, pmx is never released.
- */
- pmx = pmx_get(&adev->dev, U300_APP_PMX_SPI_SETTING);
-
- if (IS_ERR(pmx))
- dev_warn(&adev->dev, "Could not get padmux handle\n");
- else {
- int ret;
-
- ret = pmx_activate(&adev->dev, pmx);
- if (IS_ERR_VALUE(ret))
- dev_warn(&adev->dev, "Could not activate padmuxing\n");
- }
-
}
void __init u300_spi_register_board_devices(void)
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index 4210cb434dbc..a3e0c8692f0d 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -6,6 +6,7 @@ config UX500_SOC_COMMON
select ARM_GIC
select HAS_MTU
select ARM_ERRATA_753970
+ select ARM_ERRATA_754322
menu "Ux500 SoC"
diff --git a/arch/arm/mach-ux500/Makefile.boot b/arch/arm/mach-ux500/Makefile.boot
index c7e75acfe6c9..ff0a4b5b0a82 100644
--- a/arch/arm/mach-ux500/Makefile.boot
+++ b/arch/arm/mach-ux500/Makefile.boot
@@ -1,4 +1,4 @@
- zreladdr-y := 0x00008000
+ zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c
index a33df5f4c27a..eb5199102cfa 100644
--- a/arch/arm/mach-ux500/platsmp.c
+++ b/arch/arm/mach-ux500/platsmp.c
@@ -156,12 +156,10 @@ void __init smp_init_cpus(void)
ncores = scu_base ? scu_get_core_count(scu_base) : 1;
/* sanity check */
- if (ncores > NR_CPUS) {
- printk(KERN_WARNING
- "U8500: no. of cores (%d) greater than configured "
- "maximum of %d - clipping\n",
- ncores, NR_CPUS);
- ncores = NR_CPUS;
+ if (ncores > nr_cpu_ids) {
+ pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
+ ncores, nr_cpu_ids);
+ ncores = nr_cpu_ids;
}
for (i = 0; i < ncores; i++)
diff --git a/arch/arm/mach-versatile/Makefile.boot b/arch/arm/mach-versatile/Makefile.boot
index c7e75acfe6c9..ff0a4b5b0a82 100644
--- a/arch/arm/mach-versatile/Makefile.boot
+++ b/arch/arm/mach-versatile/Makefile.boot
@@ -1,4 +1,4 @@
- zreladdr-y := 0x00008000
+ zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
diff --git a/arch/arm/mach-vexpress/Makefile.boot b/arch/arm/mach-vexpress/Makefile.boot
index 07c2d9c457ec..8630b3d10a4d 100644
--- a/arch/arm/mach-vexpress/Makefile.boot
+++ b/arch/arm/mach-vexpress/Makefile.boot
@@ -1,3 +1,3 @@
- zreladdr-y := 0x60008000
+ zreladdr-y += 0x60008000
params_phys-y := 0x60000100
initrd_phys-y := 0x60800000
diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c
index bfd32f52c2db..2b1e836a76ed 100644
--- a/arch/arm/mach-vexpress/ct-ca9x4.c
+++ b/arch/arm/mach-vexpress/ct-ca9x4.c
@@ -221,6 +221,12 @@ static void ct_ca9x4_init_cpu_map(void)
{
int i, ncores = scu_get_core_count(MMIO_P2V(A9_MPCORE_SCU));
+ if (ncores > nr_cpu_ids) {
+ pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
+ ncores, nr_cpu_ids);
+ ncores = nr_cpu_ids;
+ }
+
for (i = 0; i < ncores; ++i)
set_cpu_possible(i, true);
diff --git a/arch/arm/mach-vexpress/hotplug.c b/arch/arm/mach-vexpress/hotplug.c
index ea4cbfb90a66..3668cf91d2de 100644
--- a/arch/arm/mach-vexpress/hotplug.c
+++ b/arch/arm/mach-vexpress/hotplug.c
@@ -13,6 +13,7 @@
#include <linux/smp.h>
#include <asm/cacheflush.h>
+#include <asm/system.h>
extern volatile int pen_release;
@@ -62,13 +63,7 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
* code will have already disabled interrupts
*/
for (;;) {
- /*
- * here's the WFI
- */
- asm(".word 0xe320f003\n"
- :
- :
- : "memory", "cc");
+ wfi();
if (pen_release == cpu) {
/*
diff --git a/arch/arm/mach-vexpress/include/mach/io.h b/arch/arm/mach-vexpress/include/mach/io.h
index 748bb524ee71..13522d86685e 100644
--- a/arch/arm/mach-vexpress/include/mach/io.h
+++ b/arch/arm/mach-vexpress/include/mach/io.h
@@ -20,8 +20,6 @@
#ifndef __ASM_ARM_ARCH_IO_H
#define __ASM_ARM_ARCH_IO_H
-#define IO_SPACE_LIMIT 0xffffffff
-
#define __io(a) __typesafe_io(a)
#define __mem_pci(a) (a)
diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c
index 9e6b93b1a043..d0d267a8d3f9 100644
--- a/arch/arm/mach-vexpress/v2m.c
+++ b/arch/arm/mach-vexpress/v2m.c
@@ -318,6 +318,10 @@ static struct clk v2m_sp804_clk = {
.rate = 1000000,
};
+static struct clk v2m_ref_clk = {
+ .rate = 32768,
+};
+
static struct clk dummy_apb_pclk;
static struct clk_lookup v2m_lookups[] = {
@@ -348,6 +352,9 @@ static struct clk_lookup v2m_lookups[] = {
}, { /* CLCD */
.dev_id = "mb:clcd",
.clk = &osc1_clk,
+ }, { /* SP805 WDT */
+ .dev_id = "mb:wdt",
+ .clk = &v2m_ref_clk,
}, { /* SP804 timers */
.dev_id = "sp804",
.con_id = "v2m-timer0",
diff --git a/arch/arm/mach-vt8500/Makefile.boot b/arch/arm/mach-vt8500/Makefile.boot
index a8acc4e24902..b79c41cdfdff 100644
--- a/arch/arm/mach-vt8500/Makefile.boot
+++ b/arch/arm/mach-vt8500/Makefile.boot
@@ -1,3 +1,3 @@
- zreladdr-y := 0x00008000
+ zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x01000000
diff --git a/arch/arm/mach-vt8500/include/mach/io.h b/arch/arm/mach-vt8500/include/mach/io.h
index 9077239f78c9..46181eecf273 100644
--- a/arch/arm/mach-vt8500/include/mach/io.h
+++ b/arch/arm/mach-vt8500/include/mach/io.h
@@ -20,8 +20,6 @@
#ifndef __ASM_ARM_ARCH_IO_H
#define __ASM_ARM_ARCH_IO_H
-#define IO_SPACE_LIMIT 0xffff
-
#define __io(a) __typesafe_io((a) + 0xf0000000)
#define __mem_pci(a) (a)
diff --git a/arch/arm/mach-w90x900/Makefile.boot b/arch/arm/mach-w90x900/Makefile.boot
index a057b546b6e5..6c3d421c2d11 100644
--- a/arch/arm/mach-w90x900/Makefile.boot
+++ b/arch/arm/mach-w90x900/Makefile.boot
@@ -1,3 +1,3 @@
-zreladdr-y := 0x00008000
+zreladdr-y += 0x00008000
params_phys-y := 0x00000100
diff --git a/arch/arm/mach-w90x900/cpu.c b/arch/arm/mach-w90x900/cpu.c
index 83c56324a472..0a235e502330 100644
--- a/arch/arm/mach-w90x900/cpu.c
+++ b/arch/arm/mach-w90x900/cpu.c
@@ -60,7 +60,7 @@ static DEFINE_CLK(emc, 7);
static DEFINE_SUBCLK(rmii, 2);
static DEFINE_CLK(usbd, 8);
static DEFINE_CLK(usbh, 9);
-static DEFINE_CLK(g2d, 10);;
+static DEFINE_CLK(g2d, 10);
static DEFINE_CLK(pwm, 18);
static DEFINE_CLK(ps2, 24);
static DEFINE_CLK(kpi, 25);
diff --git a/arch/arm/mach-zynq/Makefile.boot b/arch/arm/mach-zynq/Makefile.boot
index 67039c3e0c48..760a0efe7580 100644
--- a/arch/arm/mach-zynq/Makefile.boot
+++ b/arch/arm/mach-zynq/Makefile.boot
@@ -1,3 +1,3 @@
- zreladdr-y := 0x00008000
+ zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
diff --git a/arch/arm/mm/abort-macro.S b/arch/arm/mm/abort-macro.S
index 52162d59407a..2cbf68ef0e83 100644
--- a/arch/arm/mm/abort-macro.S
+++ b/arch/arm/mm/abort-macro.S
@@ -17,7 +17,7 @@
cmp \tmp, # 0x5600 @ Is it ldrsb?
orreq \tmp, \tmp, #1 << 11 @ Set L-bit if yes
tst \tmp, #1 << 11 @ L = 0 -> write
- orreq \psr, \psr, #1 << 11 @ yes.
+ orreq \fsr, \fsr, #1 << 11 @ yes.
b do_DataAbort
not_thumb:
.endm
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index cfbcf8b95599..c335c76e0d88 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -86,16 +86,6 @@ core_param(alignment, ai_usermode, int, 0600);
#define UM_FIXUP (1 << 1)
#define UM_SIGNAL (1 << 2)
-#ifdef CONFIG_PROC_FS
-static const char *usermode_action[] = {
- "ignored",
- "warn",
- "fixup",
- "fixup+warn",
- "signal",
- "signal+warn"
-};
-
/* Return true if and only if the ARMv6 unaligned access model is in use. */
static bool cpu_is_v6_unaligned(void)
{
@@ -123,6 +113,16 @@ static int safe_usermode(int new_usermode, bool warn)
return new_usermode;
}
+#ifdef CONFIG_PROC_FS
+static const char *usermode_action[] = {
+ "ignored",
+ "warn",
+ "fixup",
+ "fixup+warn",
+ "signal",
+ "signal+warn"
+};
+
static int alignment_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "User:\t\t%lu\n", ai_user);
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 44c086710d2b..3f9b9980478e 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -16,9 +16,12 @@
* 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/err.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
#include <asm/cacheflush.h>
#include <asm/hardware/cache-l2x0.h>
@@ -30,11 +33,19 @@ static DEFINE_SPINLOCK(l2x0_lock);
static uint32_t l2x0_way_mask; /* Bitmask of active ways */
static uint32_t l2x0_size;
+struct l2x0_regs l2x0_saved_regs;
+
+struct l2x0_of_data {
+ void (*setup)(const struct device_node *, __u32 *, __u32 *);
+ void (*save)(void);
+ void (*resume)(void);
+};
+
static inline void cache_wait_way(void __iomem *reg, unsigned long mask)
{
/* wait for cache operation by line or way to complete */
while (readl_relaxed(reg) & mask)
- ;
+ cpu_relax();
}
#ifdef CONFIG_CACHE_PL310
@@ -277,6 +288,25 @@ static void l2x0_disable(void)
spin_unlock_irqrestore(&l2x0_lock, flags);
}
+static void l2x0_unlock(__u32 cache_id)
+{
+ int lockregs;
+ int i;
+
+ if (cache_id == L2X0_CACHE_ID_PART_L310)
+ lockregs = 8;
+ else
+ /* L210 and unknown types */
+ lockregs = 1;
+
+ for (i = 0; i < lockregs; i++) {
+ writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D_BASE +
+ i * L2X0_LOCKDOWN_STRIDE);
+ writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_I_BASE +
+ i * L2X0_LOCKDOWN_STRIDE);
+ }
+}
+
void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
{
__u32 aux;
@@ -328,10 +358,14 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
* accessing the below registers will fault.
*/
if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) {
+ /* Make sure that I&D is not locked down when starting */
+ l2x0_unlock(cache_id);
/* l2x0 controller is disabled */
writel_relaxed(aux, l2x0_base + L2X0_AUX_CTRL);
+ l2x0_saved_regs.aux_ctrl = aux;
+
l2x0_inv_all();
/* enable L2X0 */
@@ -351,3 +385,202 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d B\n",
ways, cache_id, aux, l2x0_size);
}
+
+#ifdef CONFIG_OF
+static void __init l2x0_of_setup(const struct device_node *np,
+ __u32 *aux_val, __u32 *aux_mask)
+{
+ u32 data[2] = { 0, 0 };
+ u32 tag = 0;
+ u32 dirty = 0;
+ u32 val = 0, mask = 0;
+
+ of_property_read_u32(np, "arm,tag-latency", &tag);
+ if (tag) {
+ mask |= L2X0_AUX_CTRL_TAG_LATENCY_MASK;
+ val |= (tag - 1) << L2X0_AUX_CTRL_TAG_LATENCY_SHIFT;
+ }
+
+ of_property_read_u32_array(np, "arm,data-latency",
+ data, ARRAY_SIZE(data));
+ if (data[0] && data[1]) {
+ mask |= L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK |
+ L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK;
+ val |= ((data[0] - 1) << L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT) |
+ ((data[1] - 1) << L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT);
+ }
+
+ of_property_read_u32(np, "arm,dirty-latency", &dirty);
+ if (dirty) {
+ mask |= L2X0_AUX_CTRL_DIRTY_LATENCY_MASK;
+ val |= (dirty - 1) << L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT;
+ }
+
+ *aux_val &= ~mask;
+ *aux_val |= val;
+ *aux_mask &= ~mask;
+}
+
+static void __init pl310_of_setup(const struct device_node *np,
+ __u32 *aux_val, __u32 *aux_mask)
+{
+ u32 data[3] = { 0, 0, 0 };
+ u32 tag[3] = { 0, 0, 0 };
+ u32 filter[2] = { 0, 0 };
+
+ of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag));
+ if (tag[0] && tag[1] && tag[2])
+ writel_relaxed(
+ ((tag[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) |
+ ((tag[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) |
+ ((tag[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT),
+ l2x0_base + L2X0_TAG_LATENCY_CTRL);
+
+ of_property_read_u32_array(np, "arm,data-latency",
+ data, ARRAY_SIZE(data));
+ if (data[0] && data[1] && data[2])
+ writel_relaxed(
+ ((data[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) |
+ ((data[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) |
+ ((data[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT),
+ l2x0_base + L2X0_DATA_LATENCY_CTRL);
+
+ of_property_read_u32_array(np, "arm,filter-ranges",
+ filter, ARRAY_SIZE(filter));
+ if (filter[1]) {
+ writel_relaxed(ALIGN(filter[0] + filter[1], SZ_1M),
+ l2x0_base + L2X0_ADDR_FILTER_END);
+ writel_relaxed((filter[0] & ~(SZ_1M - 1)) | L2X0_ADDR_FILTER_EN,
+ l2x0_base + L2X0_ADDR_FILTER_START);
+ }
+}
+
+static void __init pl310_save(void)
+{
+ u32 l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) &
+ L2X0_CACHE_ID_RTL_MASK;
+
+ l2x0_saved_regs.tag_latency = readl_relaxed(l2x0_base +
+ L2X0_TAG_LATENCY_CTRL);
+ l2x0_saved_regs.data_latency = readl_relaxed(l2x0_base +
+ L2X0_DATA_LATENCY_CTRL);
+ l2x0_saved_regs.filter_end = readl_relaxed(l2x0_base +
+ L2X0_ADDR_FILTER_END);
+ l2x0_saved_regs.filter_start = readl_relaxed(l2x0_base +
+ L2X0_ADDR_FILTER_START);
+
+ if (l2x0_revision >= L2X0_CACHE_ID_RTL_R2P0) {
+ /*
+ * From r2p0, there is Prefetch offset/control register
+ */
+ l2x0_saved_regs.prefetch_ctrl = readl_relaxed(l2x0_base +
+ L2X0_PREFETCH_CTRL);
+ /*
+ * From r3p0, there is Power control register
+ */
+ if (l2x0_revision >= L2X0_CACHE_ID_RTL_R3P0)
+ l2x0_saved_regs.pwr_ctrl = readl_relaxed(l2x0_base +
+ L2X0_POWER_CTRL);
+ }
+}
+
+static void l2x0_resume(void)
+{
+ if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) {
+ /* restore aux ctrl and enable l2 */
+ l2x0_unlock(readl_relaxed(l2x0_base + L2X0_CACHE_ID));
+
+ writel_relaxed(l2x0_saved_regs.aux_ctrl, l2x0_base +
+ L2X0_AUX_CTRL);
+
+ l2x0_inv_all();
+
+ writel_relaxed(1, l2x0_base + L2X0_CTRL);
+ }
+}
+
+static void pl310_resume(void)
+{
+ u32 l2x0_revision;
+
+ if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) {
+ /* restore pl310 setup */
+ writel_relaxed(l2x0_saved_regs.tag_latency,
+ l2x0_base + L2X0_TAG_LATENCY_CTRL);
+ writel_relaxed(l2x0_saved_regs.data_latency,
+ l2x0_base + L2X0_DATA_LATENCY_CTRL);
+ writel_relaxed(l2x0_saved_regs.filter_end,
+ l2x0_base + L2X0_ADDR_FILTER_END);
+ writel_relaxed(l2x0_saved_regs.filter_start,
+ l2x0_base + L2X0_ADDR_FILTER_START);
+
+ l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) &
+ L2X0_CACHE_ID_RTL_MASK;
+
+ if (l2x0_revision >= L2X0_CACHE_ID_RTL_R2P0) {
+ writel_relaxed(l2x0_saved_regs.prefetch_ctrl,
+ l2x0_base + L2X0_PREFETCH_CTRL);
+ if (l2x0_revision >= L2X0_CACHE_ID_RTL_R3P0)
+ writel_relaxed(l2x0_saved_regs.pwr_ctrl,
+ l2x0_base + L2X0_POWER_CTRL);
+ }
+ }
+
+ l2x0_resume();
+}
+
+static const struct l2x0_of_data pl310_data = {
+ pl310_of_setup,
+ pl310_save,
+ pl310_resume,
+};
+
+static const struct l2x0_of_data l2x0_data = {
+ l2x0_of_setup,
+ NULL,
+ l2x0_resume,
+};
+
+static const struct of_device_id l2x0_ids[] __initconst = {
+ { .compatible = "arm,pl310-cache", .data = (void *)&pl310_data },
+ { .compatible = "arm,l220-cache", .data = (void *)&l2x0_data },
+ { .compatible = "arm,l210-cache", .data = (void *)&l2x0_data },
+ {}
+};
+
+int __init l2x0_of_init(__u32 aux_val, __u32 aux_mask)
+{
+ struct device_node *np;
+ struct l2x0_of_data *data;
+ struct resource res;
+
+ np = of_find_matching_node(NULL, l2x0_ids);
+ if (!np)
+ return -ENODEV;
+
+ if (of_address_to_resource(np, 0, &res))
+ return -ENODEV;
+
+ l2x0_base = ioremap(res.start, resource_size(&res));
+ if (!l2x0_base)
+ return -ENOMEM;
+
+ l2x0_saved_regs.phy_base = res.start;
+
+ data = of_match_node(l2x0_ids, np)->data;
+
+ /* L2 configuration can only be changed if the cache is disabled */
+ if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) {
+ if (data->setup)
+ data->setup(np, &aux_val, &aux_mask);
+ }
+
+ if (data->save)
+ data->save();
+
+ l2x0_init(l2x0_base, aux_val, aux_mask);
+
+ outer_cache.resume = data->resume;
+ return 0;
+}
+#endif
diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S
index 3b24bfa3b828..07c4bc8ea0a4 100644
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -174,6 +174,10 @@ ENTRY(v7_coherent_user_range)
dcache_line_size r2, r3
sub r3, r2, #1
bic r12, r0, r3
+#ifdef CONFIG_ARM_ERRATA_764369
+ ALT_SMP(W(dsb))
+ ALT_UP(W(nop))
+#endif
1:
USER( mcr p15, 0, r12, c7, c11, 1 ) @ clean D line to the point of unification
add r12, r12, r2
@@ -223,6 +227,10 @@ ENTRY(v7_flush_kern_dcache_area)
add r1, r0, r1
sub r3, r2, #1
bic r0, r0, r3
+#ifdef CONFIG_ARM_ERRATA_764369
+ ALT_SMP(W(dsb))
+ ALT_UP(W(nop))
+#endif
1:
mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D line / unified line
add r0, r0, r2
@@ -247,6 +255,10 @@ v7_dma_inv_range:
sub r3, r2, #1
tst r0, r3
bic r0, r0, r3
+#ifdef CONFIG_ARM_ERRATA_764369
+ ALT_SMP(W(dsb))
+ ALT_UP(W(nop))
+#endif
mcrne p15, 0, r0, c7, c14, 1 @ clean & invalidate D / U line
tst r1, r3
@@ -270,6 +282,10 @@ v7_dma_clean_range:
dcache_line_size r2, r3
sub r3, r2, #1
bic r0, r0, r3
+#ifdef CONFIG_ARM_ERRATA_764369
+ ALT_SMP(W(dsb))
+ ALT_UP(W(nop))
+#endif
1:
mcr p15, 0, r0, c7, c10, 1 @ clean D / U line
add r0, r0, r2
@@ -288,6 +304,10 @@ ENTRY(v7_dma_flush_range)
dcache_line_size r2, r3
sub r3, r2, #1
bic r0, r0, r3
+#ifdef CONFIG_ARM_ERRATA_764369
+ ALT_SMP(W(dsb))
+ ALT_UP(W(nop))
+#endif
1:
mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D / U line
add r0, r0, r2
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 0a0a1e7c20d2..235eb775fc78 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -123,8 +123,8 @@ static void __dma_free_buffer(struct page *page, size_t size)
#endif
#define CONSISTENT_OFFSET(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT)
-#define CONSISTENT_PTE_INDEX(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PGDIR_SHIFT)
-#define NUM_CONSISTENT_PTES (CONSISTENT_DMA_SIZE >> PGDIR_SHIFT)
+#define CONSISTENT_PTE_INDEX(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PMD_SHIFT)
+#define NUM_CONSISTENT_PTES (CONSISTENT_DMA_SIZE >> PMD_SHIFT)
/*
* These are the page tables (2MB each) covering uncached, DMA consistent allocations
@@ -183,7 +183,7 @@ static int __init consistent_init(void)
}
consistent_pte[i++] = pte;
- base += (1 << PGDIR_SHIFT);
+ base += PMD_SIZE;
} while (base < CONSISTENT_END);
return ret;
@@ -324,6 +324,8 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
if (addr)
*handle = pfn_to_dma(dev, page_to_pfn(page));
+ else
+ __dma_free_buffer(page, size);
return addr;
}
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 3b5ea68acbb8..aa33949fef60 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -20,6 +20,7 @@
#include <linux/highmem.h>
#include <linux/perf_event.h>
+#include <asm/exception.h>
#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 91bca355cd31..f8037ba338ac 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -298,7 +298,7 @@ static void __init arm_bootmem_free(unsigned long min, unsigned long max_low,
#ifdef CONFIG_HAVE_ARCH_PFN_VALID
int pfn_valid(unsigned long pfn)
{
- return memblock_is_memory(pfn << PAGE_SHIFT);
+ return memblock_is_memory(__pfn_to_phys(pfn));
}
EXPORT_SYMBOL(pfn_valid);
#endif
@@ -496,6 +496,13 @@ static void __init free_unused_memmap(struct meminfo *mi)
*/
bank_start = min(bank_start,
ALIGN(prev_bank_end, PAGES_PER_SECTION));
+#else
+ /*
+ * Align down here since the VM subsystem insists that the
+ * memmap entries are valid from the bank start aligned to
+ * MAX_ORDER_NR_PAGES.
+ */
+ bank_start = round_down(bank_start, MAX_ORDER_NR_PAGES);
#endif
/*
* If we had a previous bank, and there is a space
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index ab506272b2d3..bdb248c4f55c 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -289,6 +289,27 @@ __arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
}
EXPORT_SYMBOL(__arm_ioremap);
+/*
+ * Remap an arbitrary physical address space into the kernel virtual
+ * address space as memory. Needed when the kernel wants to execute
+ * code in external memory. This is needed for reprogramming source
+ * clocks that would affect normal memory for example. Please see
+ * CONFIG_GENERIC_ALLOCATOR for allocating external memory.
+ */
+void __iomem *
+__arm_ioremap_exec(unsigned long phys_addr, size_t size, bool cached)
+{
+ unsigned int mtype;
+
+ if (cached)
+ mtype = MT_MEMORY;
+ else
+ mtype = MT_MEMORY_NONCACHED;
+
+ return __arm_ioremap_caller(phys_addr, size, mtype,
+ __builtin_return_address(0));
+}
+
void __iounmap(volatile void __iomem *io_addr)
{
void *addr = (void *)(PAGE_MASK & (unsigned long)io_addr);
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
index 010566799c80..ad7cce3bc431 100644
--- a/arch/arm/mm/mm.h
+++ b/arch/arm/mm/mm.h
@@ -12,8 +12,8 @@ static inline pmd_t *pmd_off_k(unsigned long virt)
struct mem_type {
pteval_t prot_pte;
- unsigned int prot_l1;
- unsigned int prot_sect;
+ pmdval_t prot_l1;
+ pmdval_t prot_sect;
unsigned int domain;
};
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 594d677b92c8..226f1804be12 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -60,7 +60,7 @@ EXPORT_SYMBOL(pgprot_kernel);
struct cachepolicy {
const char policy[16];
unsigned int cr_mask;
- unsigned int pmd;
+ pmdval_t pmd;
pteval_t pte;
};
@@ -288,7 +288,7 @@ static void __init build_mem_type_table(void)
{
struct cachepolicy *cp;
unsigned int cr = get_cr();
- unsigned int user_pgprot, kern_pgprot, vecs_pgprot;
+ pteval_t user_pgprot, kern_pgprot, vecs_pgprot;
int cpu_arch = cpu_architecture();
int i;
@@ -863,14 +863,14 @@ static inline void prepare_page_table(void)
/*
* Clear out all the mappings below the kernel image.
*/
- for (addr = 0; addr < MODULES_VADDR; addr += PGDIR_SIZE)
+ for (addr = 0; addr < MODULES_VADDR; addr += PMD_SIZE)
pmd_clear(pmd_off_k(addr));
#ifdef CONFIG_XIP_KERNEL
/* The XIP kernel is mapped in the module area -- skip over it */
- addr = ((unsigned long)_etext + PGDIR_SIZE - 1) & PGDIR_MASK;
+ addr = ((unsigned long)_etext + PMD_SIZE - 1) & PMD_MASK;
#endif
- for ( ; addr < PAGE_OFFSET; addr += PGDIR_SIZE)
+ for ( ; addr < PAGE_OFFSET; addr += PMD_SIZE)
pmd_clear(pmd_off_k(addr));
/*
@@ -885,10 +885,12 @@ static inline void prepare_page_table(void)
* memory bank, up to the end of the vmalloc region.
*/
for (addr = __phys_to_virt(end);
- addr < VMALLOC_END; addr += PGDIR_SIZE)
+ addr < VMALLOC_END; addr += PMD_SIZE)
pmd_clear(pmd_off_k(addr));
}
+#define SWAPPER_PG_DIR_SIZE (PTRS_PER_PGD * sizeof(pgd_t))
+
/*
* Reserve the special regions of memory
*/
@@ -898,7 +900,7 @@ void __init arm_mm_memblock_reserve(void)
* Reserve the page tables. These are already in use,
* and can only be in node 0.
*/
- memblock_reserve(__pa(swapper_pg_dir), PTRS_PER_PGD * sizeof(pgd_t));
+ memblock_reserve(__pa(swapper_pg_dir), SWAPPER_PG_DIR_SIZE);
#ifdef CONFIG_SA1111
/*
@@ -926,7 +928,7 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
*/
vectors_page = early_alloc(PAGE_SIZE);
- for (addr = VMALLOC_END; addr; addr += PGDIR_SIZE)
+ for (addr = VMALLOC_END; addr; addr += PMD_SIZE)
pmd_clear(pmd_off_k(addr));
/*
diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S
index 92bd102e3982..2e6849b41f66 100644
--- a/arch/arm/mm/proc-arm920.S
+++ b/arch/arm/mm/proc-arm920.S
@@ -379,7 +379,7 @@ ENTRY(cpu_arm920_set_pte_ext)
/* Suspend/resume support: taken from arch/arm/plat-s3c24xx/sleep.S */
.globl cpu_arm920_suspend_size
-.equ cpu_arm920_suspend_size, 4 * 3
+.equ cpu_arm920_suspend_size, 4 * 4
#ifdef CONFIG_PM_SLEEP
ENTRY(cpu_arm920_do_suspend)
stmfd sp!, {r4 - r7, lr}
diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S
index 2bbcf053dffd..cd8f79c3a282 100644
--- a/arch/arm/mm/proc-arm926.S
+++ b/arch/arm/mm/proc-arm926.S
@@ -394,7 +394,7 @@ ENTRY(cpu_arm926_set_pte_ext)
/* Suspend/resume support: taken from arch/arm/plat-s3c24xx/sleep.S */
.globl cpu_arm926_suspend_size
-.equ cpu_arm926_suspend_size, 4 * 3
+.equ cpu_arm926_suspend_size, 4 * 4
#ifdef CONFIG_PM_SLEEP
ENTRY(cpu_arm926_do_suspend)
stmfd sp!, {r4 - r7, lr}
diff --git a/arch/arm/mm/proc-sa1100.S b/arch/arm/mm/proc-sa1100.S
index 07219c2ae114..69e7f2ef7384 100644
--- a/arch/arm/mm/proc-sa1100.S
+++ b/arch/arm/mm/proc-sa1100.S
@@ -182,11 +182,11 @@ ENDPROC(cpu_sa1100_do_suspend)
ENTRY(cpu_sa1100_do_resume)
ldmia r0, {r4 - r7} @ load cp regs
- mov r1, #0
- mcr p15, 0, r1, c8, c7, 0 @ flush I+D TLBs
- mcr p15, 0, r1, c7, c7, 0 @ flush I&D cache
- mcr p15, 0, r1, c9, c0, 0 @ invalidate RB
- mcr p15, 0, r1, c9, c0, 5 @ allow user space to use RB
+ mov ip, #0
+ mcr p15, 0, ip, c8, c7, 0 @ flush I+D TLBs
+ mcr p15, 0, ip, c7, c7, 0 @ flush I&D cache
+ mcr p15, 0, ip, c9, c0, 0 @ invalidate RB
+ mcr p15, 0, ip, c9, c0, 5 @ allow user space to use RB
mcr p15, 0, r4, c3, c0, 0 @ domain ID
mcr p15, 0, r5, c2, c0, 0 @ translation table base addr
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index 219138d2f158..a923aa0fd00d 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -223,6 +223,22 @@ __v6_setup:
mrc p15, 0, r0, c1, c0, 0 @ read control register
bic r0, r0, r5 @ clear bits them
orr r0, r0, r6 @ set them
+#ifdef CONFIG_ARM_ERRATA_364296
+ /*
+ * Workaround for the 364296 ARM1136 r0p2 erratum (possible cache data
+ * corruption with hit-under-miss enabled). The conditional code below
+ * (setting the undocumented bit 31 in the auxiliary control register
+ * and the FI bit in the control register) disables hit-under-miss
+ * without putting the processor into full low interrupt latency mode.
+ */
+ ldr r6, =0x4107b362 @ id for ARM1136 r0p2
+ mrc p15, 0, r5, c0, c0, 0 @ get processor id
+ teq r5, r6 @ check for the faulty core
+ mrceq p15, 0, r5, c1, c0, 1 @ load aux control reg
+ orreq r5, r5, #(1 << 31) @ set the undocumented bit 31
+ mcreq p15, 0, r5, c1, c0, 1 @ write aux control reg
+ orreq r0, r0, #(1 << 21) @ low interrupt latency configuration
+#endif
mov pc, lr @ return to head.S:__ret
/*
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index a30e78542ccf..9591c8e9fb8c 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -66,6 +66,7 @@ ENDPROC(cpu_v7_proc_fin)
ENTRY(cpu_v7_reset)
mrc p15, 0, r1, c1, c0, 0 @ ctrl register
bic r1, r1, #0x1 @ ...............m
+ THUMB( bic r1, r1, #1 << 30 ) @ SCTLR.TE (Thumb exceptions)
mcr p15, 0, r1, c1, c0, 0 @ disable MMU
isb
mov pc, r0
@@ -217,7 +218,7 @@ ENDPROC(cpu_v7_set_pte_ext)
/* Suspend/resume support: derived from arch/arm/mach-s5pv210/sleep.S */
.globl cpu_v7_suspend_size
.equ cpu_v7_suspend_size, 4 * 9
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_ARM_CPU_SUSPEND
ENTRY(cpu_v7_do_suspend)
stmfd sp!, {r4 - r11, lr}
mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID
@@ -247,13 +248,16 @@ ENTRY(cpu_v7_do_resume)
mcr p15, 0, r7, c2, c0, 0 @ TTB 0
mcr p15, 0, r8, c2, c0, 1 @ TTB 1
mcr p15, 0, ip, c2, c0, 2 @ TTB control register
- mcr p15, 0, r10, c1, c0, 1 @ Auxiliary control register
+ mrc p15, 0, r4, c1, c0, 1 @ Read Auxiliary control register
+ teq r4, r10 @ Is it already set?
+ mcrne p15, 0, r10, c1, c0, 1 @ No, so write it
mcr p15, 0, r11, c1, c0, 2 @ Co-processor access control
ldr r4, =PRRR @ PRRR
ldr r5, =NMRR @ NMRR
mcr p15, 0, r4, c10, c2, 0 @ write PRRR
mcr p15, 0, r5, c10, c2, 1 @ write NMRR
isb
+ dsb
mov r0, r9 @ control register
mov r2, r7, lsr #14 @ get TTB0 base
mov r2, r2, lsl #14
diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S
index 28c72a2006a1..755e1bf22681 100644
--- a/arch/arm/mm/proc-xsc3.S
+++ b/arch/arm/mm/proc-xsc3.S
@@ -406,7 +406,7 @@ ENTRY(cpu_xsc3_set_pte_ext)
.align
.globl cpu_xsc3_suspend_size
-.equ cpu_xsc3_suspend_size, 4 * 8
+.equ cpu_xsc3_suspend_size, 4 * 7
#ifdef CONFIG_PM_SLEEP
ENTRY(cpu_xsc3_do_suspend)
stmfd sp!, {r4 - r10, lr}
@@ -418,12 +418,12 @@ ENTRY(cpu_xsc3_do_suspend)
mrc p15, 0, r9, c1, c0, 1 @ auxiliary control reg
mrc p15, 0, r10, c1, c0, 0 @ control reg
bic r4, r4, #2 @ clear frequency change bit
- stmia r0, {r1, r4 - r10} @ store v:p offset + cp regs
+ stmia r0, {r4 - r10} @ store cp regs
ldmia sp!, {r4 - r10, pc}
ENDPROC(cpu_xsc3_do_suspend)
ENTRY(cpu_xsc3_do_resume)
- ldmia r0, {r1, r4 - r10} @ load v:p offset + cp regs
+ ldmia r0, {r4 - r10} @ load cp regs
mov ip, #0
mcr p15, 0, ip, c7, c7, 0 @ invalidate I & D caches, BTB
mcr p15, 0, ip, c7, c10, 4 @ drain write (&fill) buffer
diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig
index a5353fc0793f..4c8fdbcc9467 100644
--- a/arch/arm/plat-mxc/Kconfig
+++ b/arch/arm/plat-mxc/Kconfig
@@ -39,7 +39,7 @@ config ARCH_MX503
select ARCH_MX50_SUPPORTED
select ARCH_MX53_SUPPORTED
help
- This enables support for machines using Freescale's i.MX50 and i.MX51
+ This enables support for machines using Freescale's i.MX50 and i.MX53
processors.
config ARCH_MX51
diff --git a/arch/arm/plat-mxc/devices.c b/arch/arm/plat-mxc/devices.c
index 0d6ed31bdbf2..a34b2ae895f2 100644
--- a/arch/arm/plat-mxc/devices.c
+++ b/arch/arm/plat-mxc/devices.c
@@ -37,59 +37,6 @@ int __init mxc_register_device(struct platform_device *pdev, void *data)
return ret;
}
-struct platform_device *__init imx_add_platform_device_dmamask(
- const char *name, int id,
- const struct resource *res, unsigned int num_resources,
- const void *data, size_t size_data, u64 dmamask)
-{
- int ret = -ENOMEM;
- struct platform_device *pdev;
-
- pdev = platform_device_alloc(name, id);
- if (!pdev)
- goto err;
-
- if (dmamask) {
- /*
- * This memory isn't freed when the device is put,
- * I don't have a nice idea for that though. Conceptually
- * dma_mask in struct device should not be a pointer.
- * See http://thread.gmane.org/gmane.linux.kernel.pci/9081
- */
- pdev->dev.dma_mask =
- kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL);
- if (!pdev->dev.dma_mask)
- /* ret is still -ENOMEM; */
- goto err;
-
- *pdev->dev.dma_mask = dmamask;
- pdev->dev.coherent_dma_mask = dmamask;
- }
-
- if (res) {
- ret = platform_device_add_resources(pdev, res, num_resources);
- if (ret)
- goto err;
- }
-
- if (data) {
- ret = platform_device_add_data(pdev, data, size_data);
- if (ret)
- goto err;
- }
-
- ret = platform_device_add(pdev);
- if (ret) {
-err:
- if (dmamask)
- kfree(pdev->dev.dma_mask);
- platform_device_put(pdev);
- return ERR_PTR(ret);
- }
-
- return pdev;
-}
-
struct device mxc_aips_bus = {
.init_name = "mxc_aips",
.parent = &platform_bus,
diff --git a/arch/arm/plat-mxc/include/mach/devices-common.h b/arch/arm/plat-mxc/include/mach/devices-common.h
index 524538aabc4b..543525d76a60 100644
--- a/arch/arm/plat-mxc/include/mach/devices-common.h
+++ b/arch/arm/plat-mxc/include/mach/devices-common.h
@@ -14,10 +14,22 @@
extern struct device mxc_aips_bus;
extern struct device mxc_ahb_bus;
-struct platform_device *imx_add_platform_device_dmamask(
+static inline struct platform_device *imx_add_platform_device_dmamask(
const char *name, int id,
const struct resource *res, unsigned int num_resources,
- const void *data, size_t size_data, u64 dmamask);
+ const void *data, size_t size_data, u64 dmamask)
+{
+ struct platform_device_info pdevinfo = {
+ .name = name,
+ .id = id,
+ .res = res,
+ .num_res = num_resources,
+ .data = data,
+ .size_data = size_data,
+ .dma_mask = dmamask,
+ };
+ return platform_device_register_full(&pdevinfo);
+}
static inline struct platform_device *imx_add_platform_device(
const char *name, int id,
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index bb8f4a6b3e37..5b605a9eb091 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -14,6 +14,7 @@ config ARCH_OMAP1
select CLKDEV_LOOKUP
select CLKSRC_MMIO
select GENERIC_IRQ_CHIP
+ select HAVE_IDE
help
"Systems based on omap7xx, omap15xx or omap16xx"
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index b6b409744954..02609eee0562 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -615,6 +615,9 @@ static int _od_resume_noirq(struct device *dev)
return pm_generic_resume_noirq(dev);
}
+#else
+#define _od_suspend_noirq NULL
+#define _od_resume_noirq NULL
#endif
static struct dev_pm_domain omap_device_pm_domain = {
@@ -622,7 +625,8 @@ static struct dev_pm_domain omap_device_pm_domain = {
SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume,
_od_runtime_idle)
USE_PLATFORM_PM_SLEEP_OPS
- SET_SYSTEM_SLEEP_PM_OPS(_od_suspend_noirq, _od_resume_noirq)
+ .suspend_noirq = _od_suspend_noirq,
+ .resume_noirq = _od_resume_noirq,
}
};
diff --git a/arch/arm/plat-s5p/clock.c b/arch/arm/plat-s5p/clock.c
index 02af235298e2..5f84a3f13ef9 100644
--- a/arch/arm/plat-s5p/clock.c
+++ b/arch/arm/plat-s5p/clock.c
@@ -192,7 +192,7 @@ unsigned long s5p_spdif_get_rate(struct clk *clk)
if (IS_ERR(pclk))
return -EINVAL;
- rate = pclk->ops->get_rate(clk);
+ rate = pclk->ops->get_rate(pclk);
clk_put(pclk);
return rate;
diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c
index 327ab9f662e8..c65eb791d1bb 100644
--- a/arch/arm/plat-s5p/irq-gpioint.c
+++ b/arch/arm/plat-s5p/irq-gpioint.c
@@ -23,6 +23,8 @@
#include <plat/gpio-core.h>
#include <plat/gpio-cfg.h>
+#include <asm/mach/irq.h>
+
#define GPIO_BASE(chip) (((unsigned long)(chip)->base) & 0xFFFFF000u)
#define CON_OFFSET 0x700
@@ -81,6 +83,9 @@ static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc)
int group, pend_offset, mask_offset;
unsigned int pend, mask;
+ struct irq_chip *chip = irq_get_chip(irq);
+ chained_irq_enter(chip, desc);
+
for (group = 0; group < bank->nr_groups; group++) {
struct s3c_gpio_chip *chip = bank->chips[group];
if (!chip)
@@ -102,23 +107,25 @@ static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc)
pend &= ~BIT(offset);
}
}
+ chained_irq_exit(chip, desc);
}
static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip)
{
static int used_gpioint_groups = 0;
int group = chip->group;
- struct s5p_gpioint_bank *bank = NULL;
+ struct s5p_gpioint_bank *b, *bank = NULL;
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
if (used_gpioint_groups >= S5P_GPIOINT_GROUP_COUNT)
return -ENOMEM;
- list_for_each_entry(bank, &banks, list) {
- if (group >= bank->start &&
- group < bank->start + bank->nr_groups)
+ list_for_each_entry(b, &banks, list) {
+ if (group >= b->start && group < b->start + b->nr_groups) {
+ bank = b;
break;
+ }
}
if (!bank)
return -EINVAL;
@@ -156,9 +163,9 @@ static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip)
ct->chip.irq_mask = irq_gc_mask_set_bit;
ct->chip.irq_unmask = irq_gc_mask_clr_bit;
ct->chip.irq_set_type = s5p_gpioint_set_type,
- ct->regs.ack = PEND_OFFSET + REG_OFFSET(chip->group);
- ct->regs.mask = MASK_OFFSET + REG_OFFSET(chip->group);
- ct->regs.type = CON_OFFSET + REG_OFFSET(chip->group);
+ ct->regs.ack = PEND_OFFSET + REG_OFFSET(group - bank->start);
+ ct->regs.mask = MASK_OFFSET + REG_OFFSET(group - bank->start);
+ ct->regs.type = CON_OFFSET + REG_OFFSET(group - bank->start);
irq_setup_generic_chip(gc, IRQ_MSK(chip->chip.ngpio),
IRQ_GC_INIT_MASK_CACHE,
IRQ_NOREQUEST | IRQ_NOPROBE, 0);
diff --git a/arch/arm/plat-samsung/clock.c b/arch/arm/plat-samsung/clock.c
index 302c42670bd1..3b4451979d1b 100644
--- a/arch/arm/plat-samsung/clock.c
+++ b/arch/arm/plat-samsung/clock.c
@@ -64,6 +64,17 @@ static LIST_HEAD(clocks);
*/
DEFINE_SPINLOCK(clocks_lock);
+/* Global watchdog clock used by arch_wtd_reset() callback */
+struct clk *s3c2410_wdtclk;
+static int __init s3c_wdt_reset_init(void)
+{
+ s3c2410_wdtclk = clk_get(NULL, "watchdog");
+ if (IS_ERR(s3c2410_wdtclk))
+ printk(KERN_WARNING "%s: warning: cannot get watchdog clock\n", __func__);
+ return 0;
+}
+arch_initcall(s3c_wdt_reset_init);
+
/* enable and disable calls for use with the clk struct */
static int clk_null_enable(struct clk *clk, int enable)
diff --git a/arch/arm/plat-samsung/include/plat/backlight.h b/arch/arm/plat-samsung/include/plat/backlight.h
index 51d8da846a62..ad530c78fe8c 100644
--- a/arch/arm/plat-samsung/include/plat/backlight.h
+++ b/arch/arm/plat-samsung/include/plat/backlight.h
@@ -20,7 +20,7 @@ struct samsung_bl_gpio_info {
int func;
};
-extern void samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
+extern void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
struct platform_pwm_backlight_data *bl_data);
#endif /* __ASM_PLAT_BACKLIGHT_H */
diff --git a/arch/arm/plat-samsung/include/plat/clock.h b/arch/arm/plat-samsung/include/plat/clock.h
index 87d5b38a86fb..73c66d4d10fa 100644
--- a/arch/arm/plat-samsung/include/plat/clock.h
+++ b/arch/arm/plat-samsung/include/plat/clock.h
@@ -9,6 +9,9 @@
* published by the Free Software Foundation.
*/
+#ifndef __ASM_PLAT_CLOCK_H
+#define __ASM_PLAT_CLOCK_H __FILE__
+
#include <linux/spinlock.h>
#include <linux/clkdev.h>
@@ -121,3 +124,8 @@ extern int s3c64xx_sclk_ctrl(struct clk *clk, int enable);
extern void s3c_pwmclk_init(void);
+/* Global watchdog clock used by arch_wtd_reset() callback */
+
+extern struct clk *s3c2410_wdtclk;
+
+#endif /* __ASM_PLAT_CLOCK_H */
diff --git a/arch/arm/plat-samsung/include/plat/watchdog-reset.h b/arch/arm/plat-samsung/include/plat/watchdog-reset.h
index 54b762acb5a0..40dbb2b0ae22 100644
--- a/arch/arm/plat-samsung/include/plat/watchdog-reset.h
+++ b/arch/arm/plat-samsung/include/plat/watchdog-reset.h
@@ -10,6 +10,7 @@
* published by the Free Software Foundation.
*/
+#include <plat/clock.h>
#include <plat/regs-watchdog.h>
#include <mach/map.h>
@@ -19,17 +20,12 @@
static inline void arch_wdt_reset(void)
{
- struct clk *wdtclk;
-
printk("arch_reset: attempting watchdog reset\n");
__raw_writel(0, S3C2410_WTCON); /* disable watchdog, to be safe */
- wdtclk = clk_get(NULL, "watchdog");
- if (!IS_ERR(wdtclk)) {
- clk_enable(wdtclk);
- } else
- printk(KERN_WARNING "%s: warning: cannot get watchdog clock\n", __func__);
+ if (s3c2410_wdtclk)
+ clk_enable(s3c2410_wdtclk);
/* put initial values into count and data */
__raw_writel(0x80, S3C2410_WTCNT);
diff --git a/arch/arm/plat-samsung/irq-vic-timer.c b/arch/arm/plat-samsung/irq-vic-timer.c
index f714d060370d..51583cd30164 100644
--- a/arch/arm/plat-samsung/irq-vic-timer.c
+++ b/arch/arm/plat-samsung/irq-vic-timer.c
@@ -22,9 +22,14 @@
#include <plat/irq-vic-timer.h>
#include <plat/regs-timer.h>
+#include <asm/mach/irq.h>
+
static void s3c_irq_demux_vic_timer(unsigned int irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = irq_get_chip(irq);
+ chained_irq_enter(chip, desc);
generic_handle_irq((int)desc->irq_data.handler_data);
+ chained_irq_exit(chip, desc);
}
/* We assume the IRQ_TIMER0..IRQ_TIMER4 range is continuous. */
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index fff68d0d521b..5bdeef969847 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -12,10 +12,9 @@
#
# http://www.arm.linux.org.uk/developer/machines/?action=new
#
-# XXX: This is a cut-down version of the file; it contains only machines that
-# XXX: are in mainline or have been submitted to the machine database within
-# XXX: the last 12 months. If your entry is missing please email rmk at
-# XXX: <linux@arm.linux.org.uk>
+# This is a cut-down version of the file; it contains only machines that
+# are merged into mainline or have been edited in the machine database
+# within the last 12 months. References to machine_is_NAME() do not count!
#
# Last update: Sat May 7 08:48:24 2011
#
@@ -65,6 +64,7 @@ h7201 ARCH_H7201 H7201 161
h7202 ARCH_H7202 H7202 162
iq80321 ARCH_IQ80321 IQ80321 169
ks8695 ARCH_KS8695 KS8695 180
+karo ARCH_KARO KARO 190
smdk2410 ARCH_SMDK2410 SMDK2410 193
ceiva ARCH_CEIVA CEIVA 200
voiceblue MACH_VOICEBLUE VOICEBLUE 218
@@ -188,6 +188,7 @@ omap_2430sdp MACH_OMAP_2430SDP OMAP_2430SDP 900
davinci_evm MACH_DAVINCI_EVM DAVINCI_EVM 901
palmz72 MACH_PALMZ72 PALMZ72 904
nxdb500 MACH_NXDB500 NXDB500 905
+apf9328 MACH_APF9328 APF9328 906
palmt5 MACH_PALMT5 PALMT5 917
palmtc MACH_PALMTC PALMTC 918
omap_apollon MACH_OMAP_APOLLON OMAP_APOLLON 919
@@ -271,10 +272,12 @@ pcm038 MACH_PCM038 PCM038 1551
ts_x09 MACH_TS209 TS209 1565
at91cap9adk MACH_AT91CAP9ADK AT91CAP9ADK 1566
mx31moboard MACH_MX31MOBOARD MX31MOBOARD 1574
+vision_ep9307 MACH_VISION_EP9307 VISION_EP9307 1578
terastation_pro2 MACH_TERASTATION_PRO2 TERASTATION_PRO2 1584
linkstation_pro MACH_LINKSTATION_PRO LINKSTATION_PRO 1585
e350 MACH_E350 E350 1596
ts409 MACH_TS409 TS409 1601
+rsi_ews MACH_RSI_EWS RSI_EWS 1609
cm_x300 MACH_CM_X300 CM_X300 1616
at91sam9g20ek MACH_AT91SAM9G20EK AT91SAM9G20EK 1624
smdk6410 MACH_SMDK6410 SMDK6410 1626
@@ -331,6 +334,7 @@ smdkc100 MACH_SMDKC100 SMDKC100 1826
tavorevb MACH_TAVOREVB TAVOREVB 1827
saar MACH_SAAR SAAR 1828
at91sam9m10g45ek MACH_AT91SAM9M10G45EK AT91SAM9M10G45EK 1830
+usb_a9g20 MACH_USB_A9G20 USB_A9G20 1841
mxlads MACH_MXLADS MXLADS 1851
linkstation_mini MACH_LINKSTATION_MINI LINKSTATION_MINI 1858
afeb9260 MACH_AFEB9260 AFEB9260 1859
@@ -351,7 +355,7 @@ centro MACH_CENTRO CENTRO 1944
nokia_rx51 MACH_NOKIA_RX51 NOKIA_RX51 1955
omap_zoom2 MACH_OMAP_ZOOM2 OMAP_ZOOM2 1967
cpuat9260 MACH_CPUAT9260 CPUAT9260 1973
-eukrea_cpuimx27 MACH_CPUIMX27 CPUIMX27 1975
+eukrea_cpuimx27 MACH_EUKREA_CPUIMX27 EUKREA_CPUIMX27 1975
acs5k MACH_ACS5K ACS5K 1982
snapper_9260 MACH_SNAPPER_9260 SNAPPER_9260 1987
dsm320 MACH_DSM320 DSM320 1988
@@ -369,6 +373,7 @@ pcm043 MACH_PCM043 PCM043 2072
sheevaplug MACH_SHEEVAPLUG SHEEVAPLUG 2097
avengers_lite MACH_AVENGERS_LITE AVENGERS_LITE 2104
mx51_babbage MACH_MX51_BABBAGE MX51_BABBAGE 2125
+tx37 MACH_TX37 TX37 2127
rd78x00_masa MACH_RD78X00_MASA RD78X00_MASA 2135
dm355_leopard MACH_DM355_LEOPARD DM355_LEOPARD 2138
ts219 MACH_TS219 TS219 2139
@@ -379,6 +384,7 @@ omap_4430sdp MACH_OMAP_4430SDP OMAP_4430SDP 2160
magx_zn5 MACH_MAGX_ZN5 MAGX_ZN5 2162
btmavb101 MACH_BTMAVB101 BTMAVB101 2172
btmawb101 MACH_BTMAWB101 BTMAWB101 2173
+tx25 MACH_TX25 TX25 2177
omap3_torpedo MACH_OMAP3_TORPEDO OMAP3_TORPEDO 2178
anw6410 MACH_ANW6410 ANW6410 2183
imx27_visstrim_m10 MACH_IMX27_VISSTRIM_M10 IMX27_VISSTRIM_M10 2187
@@ -423,6 +429,7 @@ raumfeld_rc MACH_RAUMFELD_RC RAUMFELD_RC 2413
raumfeld_connector MACH_RAUMFELD_CONNECTOR RAUMFELD_CONNECTOR 2414
raumfeld_speaker MACH_RAUMFELD_SPEAKER RAUMFELD_SPEAKER 2415
tnetv107x MACH_TNETV107X TNETV107X 2418
+mx51_m2id MACH_MX51_M2ID MX51_M2ID 2428
smdkv210 MACH_SMDKV210 SMDKV210 2456
omap_zoom3 MACH_OMAP_ZOOM3 OMAP_ZOOM3 2464
omap_3630sdp MACH_OMAP_3630SDP OMAP_3630SDP 2465
@@ -433,14 +440,17 @@ omapl138_hawkboard MACH_OMAPL138_HAWKBOARD OMAPL138_HAWKBOARD 2495
ts41x MACH_TS41X TS41X 2502
phy3250 MACH_PHY3250 PHY3250 2511
mini6410 MACH_MINI6410 MINI6410 2520
+tx51 MACH_TX51 TX51 2529
mx28evk MACH_MX28EVK MX28EVK 2531
smartq5 MACH_SMARTQ5 SMARTQ5 2534
davinci_dm6467tevm MACH_DAVINCI_DM6467TEVM DAVINCI_DM6467TEVM 2548
mxt_td60 MACH_MXT_TD60 MXT_TD60 2550
riot_bei2 MACH_RIOT_BEI2 RIOT_BEI2 2576
riot_x37 MACH_RIOT_X37 RIOT_X37 2578
+pca101 MACH_PCA101 PCA101 2595
capc7117 MACH_CAPC7117 CAPC7117 2612
icontrol MACH_ICONTROL ICONTROL 2624
+gplugd MACH_GPLUGD GPLUGD 2625
qsd8x50a_st1_5 MACH_QSD8X50A_ST1_5 QSD8X50A_ST1_5 2627
mx23evk MACH_MX23EVK MX23EVK 2629
ap4evb MACH_AP4EVB AP4EVB 2630
@@ -476,8 +486,8 @@ cns3420vb MACH_CNS3420VB CNS3420VB 2776
omap4_panda MACH_OMAP4_PANDA OMAP4_PANDA 2791
ti8168evm MACH_TI8168EVM TI8168EVM 2800
teton_bga MACH_TETON_BGA TETON_BGA 2816
-eukrea_cpuimx25sd MACH_EUKREA_CPUIMX25 EUKREA_CPUIMX25 2820
-eukrea_cpuimx35sd MACH_EUKREA_CPUIMX35 EUKREA_CPUIMX35 2821
+eukrea_cpuimx25sd MACH_EUKREA_CPUIMX25SD EUKREA_CPUIMX25SD 2820
+eukrea_cpuimx35sd MACH_EUKREA_CPUIMX35SD EUKREA_CPUIMX35SD 2821
eukrea_cpuimx51sd MACH_EUKREA_CPUIMX51SD EUKREA_CPUIMX51SD 2822
eukrea_cpuimx51 MACH_EUKREA_CPUIMX51 EUKREA_CPUIMX51 2823
smdkc210 MACH_SMDKC210 SMDKC210 2838
@@ -1113,3 +1123,5 @@ blissc MACH_BLISSC BLISSC 3491
thales_adc MACH_THALES_ADC THALES_ADC 3492
ubisys_p9d_evp MACH_UBISYS_P9D_EVP UBISYS_P9D_EVP 3493
atdgp318 MACH_ATDGP318 ATDGP318 3494
+smdk4212 MACH_SMDK4212 SMDK4212 3638
+smdk4412 MACH_SMDK4412 SMDK4412 3765
diff --git a/arch/arm/vfp/Makefile b/arch/arm/vfp/Makefile
index 6de73aab0195..a81404c09d5d 100644
--- a/arch/arm/vfp/Makefile
+++ b/arch/arm/vfp/Makefile
@@ -7,7 +7,7 @@
# ccflags-y := -DDEBUG
# asflags-y := -DDEBUG
-KBUILD_AFLAGS :=$(KBUILD_AFLAGS:-msoft-float=-Wa,-mfpu=softvfp+vfp)
+KBUILD_AFLAGS :=$(KBUILD_AFLAGS:-msoft-float=-Wa,-mfpu=softvfp+vfp -mfloat-abi=soft)
LDFLAGS +=--no-warn-mismatch
obj-y += vfp.o
diff --git a/arch/avr32/kernel/syscall_table.S b/arch/avr32/kernel/syscall_table.S
index c7fd394d28a4..6eba53530d1c 100644
--- a/arch/avr32/kernel/syscall_table.S
+++ b/arch/avr32/kernel/syscall_table.S
@@ -158,7 +158,7 @@ sys_call_table:
.long sys_sched_rr_get_interval
.long sys_nanosleep
.long sys_poll
- .long sys_nfsservctl /* 145 */
+ .long sys_ni_syscall /* 145 was nfsservctl */
.long sys_setresgid
.long sys_getresgid
.long sys_prctl
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
index 225d311c9701..e4137297b790 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -1543,7 +1543,7 @@ ENTRY(_sys_call_table)
.long _sys_ni_syscall /* for vm86 */
.long _sys_ni_syscall /* old "query_module" */
.long _sys_ni_syscall /* sys_poll */
- .long _sys_nfsservctl
+ .long _sys_ni_syscall /* old nfsservctl */
.long _sys_setresgid /* setresgid16 */ /* 170 */
.long _sys_getresgid /* getresgid16 */
.long _sys_prctl
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index 17addacb169e..408b055c585f 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -282,8 +282,8 @@ config ETRAX_RTC
Enables drivers for the Real-Time Clock battery-backed chips on
some products. The kernel reads the time when booting, and
the date can be set using ioctl(fd, RTC_SET_TIME, &rt) with rt a
- rtc_time struct (see <file:include/asm-cris/rtc.h>) on the /dev/rtc
- device. You can check the time with cat /proc/rtc, but
+ rtc_time struct (see <file:arch/cris/include/asm/rtc.h>) on the
+ /dev/rtc device. You can check the time with cat /proc/rtc, but
normal time reading should be done using libc function time and
friends.
diff --git a/arch/cris/arch-v10/Kconfig b/arch/cris/arch-v10/Kconfig
index adc164e99339..df9a38b4f18f 100644
--- a/arch/cris/arch-v10/Kconfig
+++ b/arch/cris/arch-v10/Kconfig
@@ -24,8 +24,8 @@ config ETRAX_PA_LEDS
help
The ETRAX network driver is responsible for flashing LED's when
packets arrive and are sent. It uses macros defined in
- <file:include/asm-cris/io.h>, and those macros are defined after what
- YOU choose in this option. The actual bits used are configured
+ <file:arch/cris/include/asm/io.h>, and those macros are defined after
+ what YOU choose in this option. The actual bits used are configured
separately. Select this if the LEDs are on port PA. Some products
put the leds on PB or a memory-mapped latch (CSP0) instead.
@@ -34,8 +34,8 @@ config ETRAX_PB_LEDS
help
The ETRAX network driver is responsible for flashing LED's when
packets arrive and are sent. It uses macros defined in
- <file:include/asm-cris/io.h>, and those macros are defined after what
- YOU choose in this option. The actual bits used are configured
+ <file:arch/cris/include/asm/io.h>, and those macros are defined after
+ what YOU choose in this option. The actual bits used are configured
separately. Select this if the LEDs are on port PB. Some products
put the leds on PA or a memory-mapped latch (CSP0) instead.
@@ -44,8 +44,8 @@ config ETRAX_CSP0_LEDS
help
The ETRAX network driver is responsible for flashing LED's when
packets arrive and are sent. It uses macros defined in
- <file:include/asm-cris/io.h>, and those macros are defined after what
- YOU choose in this option. The actual bits used are configured
+ <file:arch/cris/include/asm/io.h>, and those macros are defined after
+ what YOU choose in this option. The actual bits used are configured
separately. Select this if the LEDs are on a memory-mapped latch
using chip select CSP0, this is mapped at 0x90000000.
Some products put the leds on PA or PB instead.
diff --git a/arch/cris/arch-v10/drivers/Kconfig b/arch/cris/arch-v10/drivers/Kconfig
index 0d7221779923..32d90867a984 100644
--- a/arch/cris/arch-v10/drivers/Kconfig
+++ b/arch/cris/arch-v10/drivers/Kconfig
@@ -4,6 +4,7 @@ config ETRAX_ETHERNET
bool "Ethernet support"
depends on ETRAX_ARCH_V10
select NET_ETHERNET
+ select NET_CORE
select MII
help
This option enables the ETRAX 100LX built-in 10/100Mbit Ethernet
diff --git a/arch/cris/arch-v10/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S
index 1161883eb582..592fbe9dfb62 100644
--- a/arch/cris/arch-v10/kernel/entry.S
+++ b/arch/cris/arch-v10/kernel/entry.S
@@ -771,7 +771,7 @@ sys_call_table:
.long sys_ni_syscall /* sys_vm86 */
.long sys_ni_syscall /* Old sys_query_module */
.long sys_poll
- .long sys_nfsservctl
+ .long sys_ni_syscall /* old nfsservctl */
.long sys_setresgid16 /* 170 */
.long sys_getresgid16
.long sys_prctl
diff --git a/arch/cris/arch-v32/drivers/Kconfig b/arch/cris/arch-v32/drivers/Kconfig
index 41a2732e8b9c..e47e9c3401b0 100644
--- a/arch/cris/arch-v32/drivers/Kconfig
+++ b/arch/cris/arch-v32/drivers/Kconfig
@@ -4,6 +4,7 @@ config ETRAX_ETHERNET
bool "Ethernet support"
depends on ETRAX_ARCH_V32
select NET_ETHERNET
+ select NET_CORE
select MII
help
This option enables the ETRAX FS built-in 10/100Mbit Ethernet
diff --git a/arch/cris/arch-v32/kernel/entry.S b/arch/cris/arch-v32/kernel/entry.S
index 84fed7e91ada..c3ea4694fbaf 100644
--- a/arch/cris/arch-v32/kernel/entry.S
+++ b/arch/cris/arch-v32/kernel/entry.S
@@ -714,7 +714,7 @@ sys_call_table:
.long sys_ni_syscall /* sys_vm86 */
.long sys_ni_syscall /* Old sys_query_module */
.long sys_poll
- .long sys_nfsservctl
+ .long sys_ni_syscall /* Old nfsservctl */
.long sys_setresgid16 /* 170 */
.long sys_getresgid16
.long sys_prctl
diff --git a/arch/cris/arch-v32/lib/nand_init.S b/arch/cris/arch-v32/lib/nand_init.S
deleted file mode 100644
index d671fed451c9..000000000000
--- a/arch/cris/arch-v32/lib/nand_init.S
+++ /dev/null
@@ -1,178 +0,0 @@
-##=============================================================================
-##
-## nand_init.S
-##
-## The bootrom copies data from the NAND flash to the internal RAM but
-## due to a bug/feature we can only trust the 256 first bytes. So this
-## code copies more data from NAND flash to internal RAM. Obvioulsy this
-## code must fit in the first 256 bytes so alter with care.
-##
-## Some notes about the bug/feature for future reference:
-## The bootrom copies the first 127 KB from NAND flash to internal
-## memory. The problem is that it does a bytewise copy. NAND flashes
-## does autoincrement on the address so for a 16-bite device each
-## read/write increases the address by two. So the copy loop in the
-## bootrom will discard every second byte. This is solved by inserting
-## zeroes in every second byte in the first erase block.
-##
-## The bootrom also incorrectly assumes that it can read the flash
-## linear with only one read command but the flash will actually
-## switch between normal area and spare area if you do that so we
-## can't trust more than the first 256 bytes.
-##
-##=============================================================================
-
-#include <arch/hwregs/asm/reg_map_asm.h>
-#include <arch/hwregs/asm/gio_defs_asm.h>
-#include <arch/hwregs/asm/pinmux_defs_asm.h>
-#include <arch/hwregs/asm/bif_core_defs_asm.h>
-#include <arch/hwregs/asm/config_defs_asm.h>
-
-;; There are 8-bit NAND flashes and 16-bit NAND flashes.
-;; We need to treat them slightly different.
-#if CONFIG_ETRAX_FLASH_BUSWIDTH==2
-#define PAGE_SIZE 256
-#else
-#error 2
-#define PAGE_SIZE 512
-#endif
-#define ERASE_BLOCK 16384
-
-;; GPIO pins connected to NAND flash
-#define CE 4
-#define CLE 5
-#define ALE 6
-#define BY 7
-
-;; Address space for NAND flash
-#define NAND_RD_ADDR 0x90000000
-#define NAND_WR_ADDR 0x94000000
-
-#define READ_CMD 0x00
-
-;; Readability macros
-#define CSP_MASK \
- REG_MASK(bif_core, rw_grp3_cfg, gated_csp0) | \
- REG_MASK(bif_core, rw_grp3_cfg, gated_csp1)
-#define CSP_VAL \
- REG_STATE(bif_core, rw_grp3_cfg, gated_csp0, rd) | \
- REG_STATE(bif_core, rw_grp3_cfg, gated_csp1, wr)
-
-;;----------------------------------------------------------------------------
-;; Macros to set/clear GPIO bits
-
-.macro SET x
- or.b (1<<\x),$r9
- move.d $r9, [$r2]
-.endm
-
-.macro CLR x
- and.b ~(1<<\x),$r9
- move.d $r9, [$r2]
-.endm
-
-;;----------------------------------------------------------------------------
-
-nand_boot:
- ;; Check if nand boot was selected
- move.d REG_ADDR(config, regi_config, r_bootsel), $r0
- move.d [$r0], $r0
- and.d REG_MASK(config, r_bootsel, boot_mode), $r0
- cmp.d REG_STATE(config, r_bootsel, boot_mode, nand), $r0
- bne normal_boot ; No NAND boot
- nop
-
-copy_nand_to_ram:
- ;; copy_nand_to_ram
- ;; Arguments
- ;; r10 - destination
- ;; r11 - source offset
- ;; r12 - size
- ;; r13 - Address to jump to after completion
- ;; Note : r10-r12 are clobbered on return
- ;; Registers used:
- ;; r0 - NAND_RD_ADDR
- ;; r1 - NAND_WR_ADDR
- ;; r2 - reg_gio_rw_pa_dout
- ;; r3 - reg_gio_r_pa_din
- ;; r4 - tmp
- ;; r5 - byte counter within a page
- ;; r6 - reg_pinmux_rw_pa
- ;; r7 - reg_gio_rw_pa_oe
- ;; r8 - reg_bif_core_rw_grp3_cfg
- ;; r9 - reg_gio_rw_pa_dout shadow
- move.d 0x90000000, $r0
- move.d 0x94000000, $r1
- move.d REG_ADDR(gio, regi_gio, rw_pa_dout), $r2
- move.d REG_ADDR(gio, regi_gio, r_pa_din), $r3
- move.d REG_ADDR(pinmux, regi_pinmux, rw_pa), $r6
- move.d REG_ADDR(gio, regi_gio, rw_pa_oe), $r7
- move.d REG_ADDR(bif_core, regi_bif_core, rw_grp3_cfg), $r8
-
-#if CONFIG_ETRAX_FLASH_BUSWIDTH==2
- lsrq 1, $r11
-#endif
- ;; Set up GPIO
- move.d [$r2], $r9
- move.d [$r7], $r4
- or.b (1<<ALE) | (1 << CLE) | (1<<CE), $r4
- move.d $r4, [$r7]
-
- ;; Set up bif
- move.d [$r8], $r4
- and.d CSP_MASK, $r4
- or.d CSP_VAL, $r4
- move.d $r4, [$r8]
-
-1: ;; Copy one page
- CLR CE
- SET CLE
- moveq READ_CMD, $r4
- move.b $r4, [$r1]
- moveq 20, $r4
-2: bne 2b
- subq 1, $r4
- CLR CLE
- SET ALE
- clear.w [$r1] ; Column address = 0
- move.d $r11, $r4
- lsrq 8, $r4
- move.b $r4, [$r1] ; Row address
- lsrq 8, $r4
- move.b $r4, [$r1] ; Row address
- moveq 20, $r4
-2: bne 2b
- subq 1, $r4
- CLR ALE
-2: move.d [$r3], $r4
- and.d 1 << BY, $r4
- beq 2b
- movu.w PAGE_SIZE, $r5
-2: ; Copy one byte/word
-#if CONFIG_ETRAX_FLASH_BUSWIDTH==2
- move.w [$r0], $r4
-#else
- move.b [$r0], $r4
-#endif
- subq 1, $r5
- bne 2b
-#if CONFIG_ETRAX_FLASH_BUSWIDTH==2
- move.w $r4, [$r10+]
- subu.w PAGE_SIZE*2, $r12
-#else
- move.b $r4, [$r10+]
- subu.w PAGE_SIZE, $r12
-#endif
- bpl 1b
- addu.w PAGE_SIZE, $r11
-
- ;; End of copy
- jump $r13
- nop
-
- ;; This will warn if the code above is too large. If you consider
- ;; to remove this you don't understand the bug/feature.
- .org 256
- .org ERASE_BLOCK
-
-normal_boot:
diff --git a/arch/cris/include/asm/serial.h b/arch/cris/include/asm/serial.h
new file mode 100644
index 000000000000..af7535a955fb
--- /dev/null
+++ b/arch/cris/include/asm/serial.h
@@ -0,0 +1,9 @@
+#ifndef _ASM_SERIAL_H
+#define _ASM_SERIAL_H
+
+/*
+ * This assumes you have a 1.8432 MHz clock for your UART.
+ */
+#define BASE_BAUD (1843200 / 16)
+
+#endif /* _ASM_SERIAL_H */
diff --git a/arch/frv/kernel/entry.S b/arch/frv/kernel/entry.S
index 017d6d7b784f..5ba23f715ea5 100644
--- a/arch/frv/kernel/entry.S
+++ b/arch/frv/kernel/entry.S
@@ -1358,7 +1358,7 @@ sys_call_table:
.long sys_ni_syscall /* for vm86 */
.long sys_ni_syscall /* Old sys_query_module */
.long sys_poll
- .long sys_nfsservctl
+ .long sys_ni_syscall /* Old nfsservctl */
.long sys_setresgid16 /* 170 */
.long sys_getresgid16
.long sys_prctl
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
index 2b1eee7198c7..d1f377f5d3b6 100644
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -160,7 +160,7 @@ config VT_CONSOLE
config HW_CONSOLE
bool
- depends on VT && !S390 && !UM
+ depends on VT
default y
comment "Unix98 PTY support"
diff --git a/arch/h8300/kernel/syscalls.S b/arch/h8300/kernel/syscalls.S
index f4b2e67bcc34..4be2ea2fbe26 100644
--- a/arch/h8300/kernel/syscalls.S
+++ b/arch/h8300/kernel/syscalls.S
@@ -183,7 +183,7 @@ SYMBOL_NAME_LABEL(sys_call_table)
.long SYMBOL_NAME(sys_ni_syscall) /* for vm86 */
.long SYMBOL_NAME(sys_ni_syscall) /* sys_query_module */
.long SYMBOL_NAME(sys_poll)
- .long SYMBOL_NAME(sys_nfsservctl)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old nfsservctl */
.long SYMBOL_NAME(sys_setresgid16) /* 170 */
.long SYMBOL_NAME(sys_getresgid16)
.long SYMBOL_NAME(sys_prctl)
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
index 80241fe03f50..f5f4ef149aac 100644
--- a/arch/ia64/hp/common/sba_iommu.c
+++ b/arch/ia64/hp/common/sba_iommu.c
@@ -915,7 +915,7 @@ sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
* @dir: R/W or both.
* @attrs: optional dma attributes
*
- * See Documentation/PCI/PCI-DMA-mapping.txt
+ * See Documentation/DMA-API-HOWTO.txt
*/
static dma_addr_t sba_map_page(struct device *dev, struct page *page,
unsigned long poff, size_t size,
@@ -1044,7 +1044,7 @@ sba_mark_clean(struct ioc *ioc, dma_addr_t iova, size_t size)
* @dir: R/W or both.
* @attrs: optional dma attributes
*
- * See Documentation/PCI/PCI-DMA-mapping.txt
+ * See Documentation/DMA-API-HOWTO.txt
*/
static void sba_unmap_page(struct device *dev, dma_addr_t iova, size_t size,
enum dma_data_direction dir, struct dma_attrs *attrs)
@@ -1127,7 +1127,7 @@ void sba_unmap_single_attrs(struct device *dev, dma_addr_t iova, size_t size,
* @size: number of bytes mapped in driver buffer.
* @dma_handle: IOVA of new buffer.
*
- * See Documentation/PCI/PCI-DMA-mapping.txt
+ * See Documentation/DMA-API-HOWTO.txt
*/
static void *
sba_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flags)
@@ -1190,7 +1190,7 @@ sba_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp
* @vaddr: virtual address IOVA of "consistent" buffer.
* @dma_handler: IO virtual address of "consistent" buffer.
*
- * See Documentation/PCI/PCI-DMA-mapping.txt
+ * See Documentation/DMA-API-HOWTO.txt
*/
static void sba_free_coherent (struct device *dev, size_t size, void *vaddr,
dma_addr_t dma_handle)
@@ -1453,7 +1453,7 @@ static void sba_unmap_sg_attrs(struct device *dev, struct scatterlist *sglist,
* @dir: R/W or both.
* @attrs: optional dma attributes
*
- * See Documentation/PCI/PCI-DMA-mapping.txt
+ * See Documentation/DMA-API-HOWTO.txt
*/
static int sba_map_sg_attrs(struct device *dev, struct scatterlist *sglist,
int nents, enum dma_data_direction dir,
@@ -1549,7 +1549,7 @@ static int sba_map_sg_attrs(struct device *dev, struct scatterlist *sglist,
* @dir: R/W or both.
* @attrs: optional dma attributes
*
- * See Documentation/PCI/PCI-DMA-mapping.txt
+ * See Documentation/DMA-API-HOWTO.txt
*/
static void sba_unmap_sg_attrs(struct device *dev, struct scatterlist *sglist,
int nents, enum dma_data_direction dir,
diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c
index 7e81966ce481..47afcc61f6e5 100644
--- a/arch/ia64/hp/sim/simeth.c
+++ b/arch/ia64/hp/sim/simeth.c
@@ -172,7 +172,7 @@ static const struct net_device_ops simeth_netdev_ops = {
.ndo_stop = simeth_close,
.ndo_start_xmit = simeth_tx,
.ndo_get_stats = simeth_get_stats,
- .ndo_set_multicast_list = set_multicast_list, /* not yet used */
+ .ndo_set_rx_mode = set_multicast_list, /* not yet used */
};
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index 97dd2abdeb1a..198c753d1006 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -1614,7 +1614,7 @@ sys_call_table:
data8 sys_sched_get_priority_min
data8 sys_sched_rr_get_interval
data8 sys_nanosleep
- data8 sys_nfsservctl
+ data8 sys_ni_syscall // old nfsservctl
data8 sys_prctl // 1170
data8 sys_getpagesize
data8 sys_mmap2
diff --git a/arch/m32r/kernel/syscall_table.S b/arch/m32r/kernel/syscall_table.S
index 528f2e6ad064..f365c19795ef 100644
--- a/arch/m32r/kernel/syscall_table.S
+++ b/arch/m32r/kernel/syscall_table.S
@@ -168,7 +168,7 @@ ENTRY(sys_call_table)
.long sys_tas /* vm86 syscall holder */
.long sys_ni_syscall /* query_module syscall holder */
.long sys_poll
- .long sys_nfsservctl
+ .long sys_ni_syscall /* was nfsservctl */
.long sys_setresgid /* 170 */
.long sys_getresgid
.long sys_prctl
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 9e8ee9d2b8ca..6c28582fb98f 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -21,6 +21,15 @@ config ARCH_HAS_ILOG2_U32
config ARCH_HAS_ILOG2_U64
bool
+config GENERIC_CLOCKEVENTS
+ bool
+
+config GENERIC_CMOS_UPDATE
+ def_bool !MMU
+
+config GENERIC_GPIO
+ bool
+
config GENERIC_HWEIGHT
bool
default y
@@ -29,10 +38,16 @@ config GENERIC_CALIBRATE_DELAY
bool
default y
+config GENERIC_IOMAP
+ def_bool MMU
+
config TIME_LOW_RES
bool
default y
+config ARCH_USES_GETTIMEOFFSET
+ def_bool MMU
+
config NO_IOPORT
def_bool y
@@ -62,13 +77,31 @@ config MMU
Select if you want MMU-based virtualised addressing space
support by paged memory management. If unsure, say 'Y'.
-menu "Platform dependent setup"
+config MMU_MOTOROLA
+ bool
+
+config MMU_SUN3
+ bool
+ depends on MMU && !MMU_MOTOROLA
+
+menu "Platform setup"
+
+source arch/m68k/Kconfig.cpu
+
+source arch/m68k/Kconfig.machine
+
+source arch/m68k/Kconfig.bus
+
+endmenu
+
+menu "Kernel Features"
-if MMU
-source arch/m68k/Kconfig.mmu
+if COLDFIRE
+source "kernel/Kconfig.preempt"
endif
-if !MMU
-source arch/m68k/Kconfig.nommu
+
+if !MMU || COLDFIRE
+source "kernel/time/Kconfig"
endif
source "mm/Kconfig"
@@ -85,9 +118,9 @@ if !MMU
menu "Power management options"
config PM
- bool "Power Management support"
- help
- Support processor power management modes
+ bool "Power Management support"
+ help
+ Support processor power management modes
endmenu
endif
@@ -96,151 +129,7 @@ source "net/Kconfig"
source "drivers/Kconfig"
-if MMU
-
-menu "Character devices"
-
-config ATARI_MFPSER
- tristate "Atari MFP serial support"
- depends on ATARI
- ---help---
- If you like to use the MFP serial ports ("Modem1", "Serial1") under
- Linux, say Y. The driver equally supports all kinds of MFP serial
- ports and automatically detects whether Serial1 is available.
-
- To compile this driver as a module, choose M here.
-
- Note for Falcon users: You also have an MFP port, it's just not
- wired to the outside... But you could use the port under Linux.
-
-config ATARI_MIDI
- tristate "Atari MIDI serial support"
- depends on ATARI
- help
- If you want to use your Atari's MIDI port in Linux, say Y.
-
- To compile this driver as a module, choose M here.
-
-config ATARI_DSP56K
- tristate "Atari DSP56k support (EXPERIMENTAL)"
- depends on ATARI && EXPERIMENTAL
- help
- If you want to be able to use the DSP56001 in Falcons, say Y. This
- driver is still experimental, and if you don't know what it is, or
- if you don't have this processor, just say N.
-
- To compile this driver as a module, choose M here.
-
-config AMIGA_BUILTIN_SERIAL
- tristate "Amiga builtin serial support"
- depends on AMIGA
- help
- If you want to use your Amiga's built-in serial port in Linux,
- answer Y.
-
- To compile this driver as a module, choose M here.
-
-config MULTIFACE_III_TTY
- tristate "Multiface Card III serial support"
- depends on AMIGA
- help
- If you want to use a Multiface III card's serial port in Linux,
- answer Y.
-
- To compile this driver as a module, choose M here.
-
-config GVPIOEXT
- tristate "GVP IO-Extender support"
- depends on PARPORT=n && ZORRO
- help
- If you want to use a GVP IO-Extender serial card in Linux, say Y.
- Otherwise, say N.
-
-config GVPIOEXT_LP
- tristate "GVP IO-Extender parallel printer support"
- depends on GVPIOEXT
- help
- Say Y to enable driving a printer from the parallel port on your
- GVP IO-Extender card, N otherwise.
-
-config GVPIOEXT_PLIP
- tristate "GVP IO-Extender PLIP support"
- depends on GVPIOEXT
- help
- Say Y to enable doing IP over the parallel port on your GVP
- IO-Extender card, N otherwise.
-
-config MAC_HID
- bool
- depends on INPUT_ADBHID
- default y
-
-config HPDCA
- tristate "HP DCA serial support"
- depends on DIO && SERIAL_8250
- help
- If you want to use the internal "DCA" serial ports on an HP300
- machine, say Y here.
-
-config HPAPCI
- tristate "HP APCI serial support"
- depends on HP300 && SERIAL_8250 && EXPERIMENTAL
- help
- If you want to use the internal "APCI" serial ports on an HP400
- machine, say Y here.
-
-config MVME147_SCC
- bool "SCC support for MVME147 serial ports"
- depends on MVME147 && BROKEN
- help
- This is the driver for the serial ports on the Motorola MVME147
- boards. Everyone using one of these boards should say Y here.
-
-config MVME162_SCC
- bool "SCC support for MVME162 serial ports"
- depends on MVME16x && BROKEN
- help
- This is the driver for the serial ports on the Motorola MVME162 and
- 172 boards. Everyone using one of these boards should say Y here.
-
-config BVME6000_SCC
- bool "SCC support for BVME6000 serial ports"
- depends on BVME6000 && BROKEN
- help
- This is the driver for the serial ports on the BVME4000 and BVME6000
- boards from BVM Ltd. Everyone using one of these boards should say
- Y here.
-
-config DN_SERIAL
- bool "Support for DN serial port (dummy)"
- depends on APOLLO
-
-config SERIAL_CONSOLE
- bool "Support for serial port console"
- depends on (AMIGA || ATARI || SUN3 || SUN3X || VME || APOLLO) && (ATARI_MFPSER=y || ATARI_MIDI=y || AMIGA_BUILTIN_SERIAL=y || GVPIOEXT=y || MULTIFACE_III_TTY=y || SERIAL=y || MVME147_SCC || SERIAL167 || MVME162_SCC || BVME6000_SCC || DN_SERIAL)
- ---help---
- If you say Y here, it will be possible to use a serial port as the
- system console (the system console is the device which receives all
- kernel messages and warnings and which allows logins in single user
- mode). This could be useful if some terminal or printer is connected
- to that serial port.
-
- Even if you say Y here, the currently visible virtual console
- (/dev/tty0) will still be used as the system console by default, but
- you can alter that using a kernel command line option such as
- "console=ttyS1". (Try "man bootparam" or see the documentation of
- your boot loader (lilo or loadlin) about how to pass options to the
- kernel at boot time.)
-
- If you don't have a VGA card installed and you say Y here, the
- kernel will automatically use the first serial line, /dev/ttyS0, as
- system console.
-
- If unsure, say N.
-
-endmenu
-
-endif
+source "arch/m68k/Kconfig.devices"
source "fs/Kconfig"
diff --git a/arch/m68k/Kconfig.bus b/arch/m68k/Kconfig.bus
new file mode 100644
index 000000000000..8294f0c1785e
--- /dev/null
+++ b/arch/m68k/Kconfig.bus
@@ -0,0 +1,55 @@
+if MMU
+
+comment "Bus Support"
+
+config NUBUS
+ bool
+ depends on MAC
+ default y
+
+config ZORRO
+ bool "Amiga Zorro (AutoConfig) bus support"
+ depends on AMIGA
+ help
+ This enables support for the Zorro bus in the Amiga. If you have
+ expansion cards in your Amiga that conform to the Amiga
+ AutoConfig(tm) specification, say Y, otherwise N. Note that even
+ expansion cards that do not fit in the Zorro slots but fit in e.g.
+ the CPU slot may fall in this category, so you have to say Y to let
+ Linux use these.
+
+config AMIGA_PCMCIA
+ bool "Amiga 1200/600 PCMCIA support (EXPERIMENTAL)"
+ depends on AMIGA && EXPERIMENTAL
+ help
+ Include support in the kernel for pcmcia on Amiga 1200 and Amiga
+ 600. If you intend to use pcmcia cards say Y; otherwise say N.
+
+config ISA
+ bool
+ depends on Q40 || AMIGA_PCMCIA
+ default y
+ help
+ Find out whether you have ISA slots on your motherboard. ISA is the
+ name of a bus system, i.e. the way the CPU talks to the other stuff
+ inside your box. Other bus systems are PCI, EISA, MicroChannel
+ (MCA) or VESA. ISA is an older system, now being displaced by PCI;
+ newer boards don't support it. If you have ISA, say Y, otherwise N.
+
+config GENERIC_ISA_DMA
+ def_bool ISA
+
+source "drivers/pci/Kconfig"
+
+source "drivers/zorro/Kconfig"
+
+endif
+
+if !MMU
+
+config ISA_DMA_API
+ def_bool !M5272
+
+source "drivers/pcmcia/Kconfig"
+
+endif
diff --git a/arch/m68k/Kconfig.cpu b/arch/m68k/Kconfig.cpu
new file mode 100644
index 000000000000..e632b2d12106
--- /dev/null
+++ b/arch/m68k/Kconfig.cpu
@@ -0,0 +1,429 @@
+comment "Processor Type"
+
+config M68000
+ bool
+ select CPU_HAS_NO_BITFIELDS
+ help
+ The Freescale (was Motorola) 68000 CPU is the first generation of
+ the well known M68K family of processors. The CPU core as well as
+ being available as a stand alone CPU was also used in many
+ System-On-Chip devices (eg 68328, 68302, etc). It does not contain
+ a paging MMU.
+
+config MCPU32
+ bool
+ select CPU_HAS_NO_BITFIELDS
+ help
+ The Freescale (was then Motorola) CPU32 is a CPU core that is
+ based on the 68020 processor. For the most part it is used in
+ System-On-Chip parts, and does not contain a paging MMU.
+
+config COLDFIRE
+ bool
+ select GENERIC_GPIO
+ select ARCH_REQUIRE_GPIOLIB
+ select CPU_HAS_NO_BITFIELDS
+ help
+ The Freescale ColdFire family of processors is a modern derivitive
+ of the 68000 processor family. They are mainly targeted at embedded
+ applications, and are all System-On-Chip (SOC) devices, as opposed
+ to stand alone CPUs. They implement a subset of the original 68000
+ processor instruction set.
+
+config M68020
+ bool "68020 support"
+ depends on MMU
+ help
+ If you anticipate running this kernel on a computer with a MC68020
+ processor, say Y. Otherwise, say N. Note that the 68020 requires a
+ 68851 MMU (Memory Management Unit) to run Linux/m68k, except on the
+ Sun 3, which provides its own version.
+
+config M68030
+ bool "68030 support"
+ depends on MMU && !MMU_SUN3
+ help
+ If you anticipate running this kernel on a computer with a MC68030
+ processor, say Y. Otherwise, say N. Note that a MC68EC030 will not
+ work, as it does not include an MMU (Memory Management Unit).
+
+config M68040
+ bool "68040 support"
+ depends on MMU && !MMU_SUN3
+ help
+ If you anticipate running this kernel on a computer with a MC68LC040
+ or MC68040 processor, say Y. Otherwise, say N. Note that an
+ MC68EC040 will not work, as it does not include an MMU (Memory
+ Management Unit).
+
+config M68060
+ bool "68060 support"
+ depends on MMU && !MMU_SUN3
+ help
+ If you anticipate running this kernel on a computer with a MC68060
+ processor, say Y. Otherwise, say N.
+
+config M68328
+ bool "MC68328"
+ depends on !MMU
+ select M68000
+ help
+ Motorola 68328 processor support.
+
+config M68EZ328
+ bool "MC68EZ328"
+ depends on !MMU
+ select M68000
+ help
+ Motorola 68EX328 processor support.
+
+config M68VZ328
+ bool "MC68VZ328"
+ depends on !MMU
+ select M68000
+ help
+ Motorola 68VZ328 processor support.
+
+config M68360
+ bool "MC68360"
+ depends on !MMU
+ select MCPU32
+ help
+ Motorola 68360 processor support.
+
+config M5206
+ bool "MCF5206"
+ depends on !MMU
+ select COLDFIRE
+ select COLDFIRE_SW_A7
+ select HAVE_MBAR
+ help
+ Motorola ColdFire 5206 processor support.
+
+config M5206e
+ bool "MCF5206e"
+ depends on !MMU
+ select COLDFIRE
+ select COLDFIRE_SW_A7
+ select HAVE_MBAR
+ help
+ Motorola ColdFire 5206e processor support.
+
+config M520x
+ bool "MCF520x"
+ depends on !MMU
+ select COLDFIRE
+ select GENERIC_CLOCKEVENTS
+ select HAVE_CACHE_SPLIT
+ help
+ Freescale Coldfire 5207/5208 processor support.
+
+config M523x
+ bool "MCF523x"
+ depends on !MMU
+ select COLDFIRE
+ select GENERIC_CLOCKEVENTS
+ select HAVE_CACHE_SPLIT
+ select HAVE_IPSBAR
+ help
+ Freescale Coldfire 5230/1/2/4/5 processor support
+
+config M5249
+ bool "MCF5249"
+ depends on !MMU
+ select COLDFIRE
+ select COLDFIRE_SW_A7
+ select HAVE_MBAR
+ help
+ Motorola ColdFire 5249 processor support.
+
+config M527x
+ bool
+
+config M5271
+ bool "MCF5271"
+ depends on !MMU
+ select COLDFIRE
+ select M527x
+ select HAVE_CACHE_SPLIT
+ select HAVE_IPSBAR
+ select GENERIC_CLOCKEVENTS
+ help
+ Freescale (Motorola) ColdFire 5270/5271 processor support.
+
+config M5272
+ bool "MCF5272"
+ depends on !MMU
+ select COLDFIRE
+ select COLDFIRE_SW_A7
+ select HAVE_MBAR
+ help
+ Motorola ColdFire 5272 processor support.
+
+config M5275
+ bool "MCF5275"
+ depends on !MMU
+ select COLDFIRE
+ select M527x
+ select HAVE_CACHE_SPLIT
+ select HAVE_IPSBAR
+ select GENERIC_CLOCKEVENTS
+ help
+ Freescale (Motorola) ColdFire 5274/5275 processor support.
+
+config M528x
+ bool "MCF528x"
+ depends on !MMU
+ select COLDFIRE
+ select GENERIC_CLOCKEVENTS
+ select HAVE_CACHE_SPLIT
+ select HAVE_IPSBAR
+ help
+ Motorola ColdFire 5280/5282 processor support.
+
+config M5307
+ bool "MCF5307"
+ depends on !MMU
+ select COLDFIRE
+ select COLDFIRE_SW_A7
+ select HAVE_CACHE_CB
+ select HAVE_MBAR
+ help
+ Motorola ColdFire 5307 processor support.
+
+config M532x
+ bool "MCF532x"
+ depends on !MMU
+ select COLDFIRE
+ select HAVE_CACHE_CB
+ help
+ Freescale (Motorola) ColdFire 532x processor support.
+
+config M5407
+ bool "MCF5407"
+ depends on !MMU
+ select COLDFIRE
+ select COLDFIRE_SW_A7
+ select HAVE_CACHE_CB
+ select HAVE_MBAR
+ help
+ Motorola ColdFire 5407 processor support.
+
+config M54xx
+ bool
+
+config M547x
+ bool "MCF547x"
+ depends on !MMU
+ select COLDFIRE
+ select M54xx
+ select HAVE_CACHE_CB
+ select HAVE_MBAR
+ help
+ Freescale ColdFire 5470/5471/5472/5473/5474/5475 processor support.
+
+config M548x
+ bool "MCF548x"
+ depends on !MMU
+ select COLDFIRE
+ select M54xx
+ select HAVE_CACHE_CB
+ select HAVE_MBAR
+ help
+ Freescale ColdFire 5480/5481/5482/5483/5484/5485 processor support.
+
+
+comment "Processor Specific Options"
+
+config M68KFPU_EMU
+ bool "Math emulation support (EXPERIMENTAL)"
+ depends on MMU
+ depends on EXPERIMENTAL
+ help
+ At some point in the future, this will cause floating-point math
+ instructions to be emulated by the kernel on machines that lack a
+ floating-point math coprocessor. Thrill-seekers and chronically
+ sleep-deprived psychotic hacker types can say Y now, everyone else
+ should probably wait a while.
+
+config M68KFPU_EMU_EXTRAPREC
+ bool "Math emulation extra precision"
+ depends on M68KFPU_EMU
+ help
+ The fpu uses normally a few bit more during calculations for
+ correct rounding, the emulator can (often) do the same but this
+ extra calculation can cost quite some time, so you can disable
+ it here. The emulator will then "only" calculate with a 64 bit
+ mantissa and round slightly incorrect, what is more than enough
+ for normal usage.
+
+config M68KFPU_EMU_ONLY
+ bool "Math emulation only kernel"
+ depends on M68KFPU_EMU
+ help
+ This option prevents any floating-point instructions from being
+ compiled into the kernel, thereby the kernel doesn't save any
+ floating point context anymore during task switches, so this
+ kernel will only be usable on machines without a floating-point
+ math coprocessor. This makes the kernel a bit faster as no tests
+ needs to be executed whether a floating-point instruction in the
+ kernel should be executed or not.
+
+config ADVANCED
+ bool "Advanced configuration options"
+ depends on MMU
+ ---help---
+ This gives you access to some advanced options for the CPU. The
+ defaults should be fine for most users, but these options may make
+ it possible for you to improve performance somewhat if you know what
+ you are doing.
+
+ Note that the answer to this question won't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about these options.
+
+ Most users should say N to this question.
+
+config RMW_INSNS
+ bool "Use read-modify-write instructions"
+ depends on ADVANCED
+ ---help---
+ This allows to use certain instructions that work with indivisible
+ read-modify-write bus cycles. While this is faster than the
+ workaround of disabling interrupts, it can conflict with DMA
+ ( = direct memory access) on many Amiga systems, and it is also said
+ to destabilize other machines. It is very likely that this will
+ cause serious problems on any Amiga or Atari Medusa if set. The only
+ configuration where it should work are 68030-based Ataris, where it
+ apparently improves performance. But you've been warned! Unless you
+ really know what you are doing, say N. Try Y only if you're quite
+ adventurous.
+
+config SINGLE_MEMORY_CHUNK
+ bool "Use one physical chunk of memory only" if ADVANCED && !SUN3
+ depends on MMU
+ default y if SUN3
+ select NEED_MULTIPLE_NODES
+ help
+ Ignore all but the first contiguous chunk of physical memory for VM
+ purposes. This will save a few bytes kernel size and may speed up
+ some operations. Say N if not sure.
+
+config ARCH_DISCONTIGMEM_ENABLE
+ def_bool MMU && !SINGLE_MEMORY_CHUNK
+
+config 060_WRITETHROUGH
+ bool "Use write-through caching for 68060 supervisor accesses"
+ depends on ADVANCED && M68060
+ ---help---
+ The 68060 generally uses copyback caching of recently accessed data.
+ Copyback caching means that memory writes will be held in an on-chip
+ cache and only written back to memory some time later. Saying Y
+ here will force supervisor (kernel) accesses to use writethrough
+ caching. Writethrough caching means that data is written to memory
+ straight away, so that cache and memory data always agree.
+ Writethrough caching is less efficient, but is needed for some
+ drivers on 68060 based systems where the 68060 bus snooping signal
+ is hardwired on. The 53c710 SCSI driver is known to suffer from
+ this problem.
+
+config M68K_L2_CACHE
+ bool
+ depends on MAC
+ default y
+
+config NODES_SHIFT
+ int
+ default "3"
+ depends on !SINGLE_MEMORY_CHUNK
+
+config FPU
+ bool
+
+config COLDFIRE_SW_A7
+ bool
+
+config HAVE_CACHE_SPLIT
+ bool
+
+config HAVE_CACHE_CB
+ bool
+
+config HAVE_MBAR
+ bool
+
+config HAVE_IPSBAR
+ bool
+
+config CLOCK_SET
+ bool "Enable setting the CPU clock frequency"
+ depends on COLDFIRE
+ default n
+ help
+ On some CPU's you do not need to know what the core CPU clock
+ frequency is. On these you can disable clock setting. On some
+ traditional 68K parts, and on all ColdFire parts you need to set
+ the appropriate CPU clock frequency. On these devices many of the
+ onboard peripherals derive their timing from the master CPU clock
+ frequency.
+
+config CLOCK_FREQ
+ int "Set the core clock frequency"
+ default "66666666"
+ depends on CLOCK_SET
+ help
+ Define the CPU clock frequency in use. This is the core clock
+ frequency, it may or may not be the same as the external clock
+ crystal fitted to your board. Some processors have an internal
+ PLL and can have their frequency programmed at run time, others
+ use internal dividers. In general the kernel won't setup a PLL
+ if it is fitted (there are some exceptions). This value will be
+ specific to the exact CPU that you are using.
+
+config OLDMASK
+ bool "Old mask 5307 (1H55J) silicon"
+ depends on M5307
+ help
+ Build support for the older revision ColdFire 5307 silicon.
+ Specifically this is the 1H55J mask revision.
+
+if HAVE_CACHE_SPLIT
+choice
+ prompt "Split Cache Configuration"
+ default CACHE_I
+
+config CACHE_I
+ bool "Instruction"
+ help
+ Use all of the ColdFire CPU cache memory as an instruction cache.
+
+config CACHE_D
+ bool "Data"
+ help
+ Use all of the ColdFire CPU cache memory as a data cache.
+
+config CACHE_BOTH
+ bool "Both"
+ help
+ Split the ColdFire CPU cache, and use half as an instruction cache
+ and half as a data cache.
+endchoice
+endif
+
+if HAVE_CACHE_CB
+choice
+ prompt "Data cache mode"
+ default CACHE_WRITETHRU
+
+config CACHE_WRITETHRU
+ bool "Write-through"
+ help
+ The ColdFire CPU cache is set into Write-through mode.
+
+config CACHE_COPYBACK
+ bool "Copy-back"
+ help
+ The ColdFire CPU cache is set into Copy-back mode.
+endchoice
+endif
+
diff --git a/arch/m68k/Kconfig.devices b/arch/m68k/Kconfig.devices
new file mode 100644
index 000000000000..d214034be6a6
--- /dev/null
+++ b/arch/m68k/Kconfig.devices
@@ -0,0 +1,123 @@
+if MMU
+
+config ARCH_MAY_HAVE_PC_FDC
+ bool
+ depends on BROKEN && (Q40 || SUN3X)
+ default y
+
+menu "Platform devices"
+
+config HEARTBEAT
+ bool "Use power LED as a heartbeat" if AMIGA || APOLLO || ATARI || MAC ||Q40
+ default y if !AMIGA && !APOLLO && !ATARI && !MAC && !Q40 && HP300
+ help
+ Use the power-on LED on your machine as a load meter. The exact
+ behavior is platform-dependent, but normally the flash frequency is
+ a hyperbolic function of the 5-minute load average.
+
+# We have a dedicated heartbeat LED. :-)
+config PROC_HARDWARE
+ bool "/proc/hardware support"
+ help
+ Say Y here to support the /proc/hardware file, which gives you
+ access to information about the machine you're running on,
+ including the model, CPU, MMU, clock speed, BogoMIPS rating,
+ and memory size.
+
+endmenu
+
+menu "Character devices"
+
+config ATARI_MFPSER
+ tristate "Atari MFP serial support"
+ depends on ATARI
+ ---help---
+ If you like to use the MFP serial ports ("Modem1", "Serial1") under
+ Linux, say Y. The driver equally supports all kinds of MFP serial
+ ports and automatically detects whether Serial1 is available.
+
+ To compile this driver as a module, choose M here.
+
+ Note for Falcon users: You also have an MFP port, it's just not
+ wired to the outside... But you could use the port under Linux.
+
+config ATARI_MIDI
+ tristate "Atari MIDI serial support"
+ depends on ATARI
+ help
+ If you want to use your Atari's MIDI port in Linux, say Y.
+
+ To compile this driver as a module, choose M here.
+
+config ATARI_DSP56K
+ tristate "Atari DSP56k support (EXPERIMENTAL)"
+ depends on ATARI && EXPERIMENTAL
+ help
+ If you want to be able to use the DSP56001 in Falcons, say Y. This
+ driver is still experimental, and if you don't know what it is, or
+ if you don't have this processor, just say N.
+
+ To compile this driver as a module, choose M here.
+
+config AMIGA_BUILTIN_SERIAL
+ tristate "Amiga builtin serial support"
+ depends on AMIGA
+ help
+ If you want to use your Amiga's built-in serial port in Linux,
+ answer Y.
+
+ To compile this driver as a module, choose M here.
+
+config MULTIFACE_III_TTY
+ tristate "Multiface Card III serial support"
+ depends on AMIGA
+ help
+ If you want to use a Multiface III card's serial port in Linux,
+ answer Y.
+
+ To compile this driver as a module, choose M here.
+
+config HPDCA
+ tristate "HP DCA serial support"
+ depends on DIO && SERIAL_8250
+ help
+ If you want to use the internal "DCA" serial ports on an HP300
+ machine, say Y here.
+
+config HPAPCI
+ tristate "HP APCI serial support"
+ depends on HP300 && SERIAL_8250 && EXPERIMENTAL
+ help
+ If you want to use the internal "APCI" serial ports on an HP400
+ machine, say Y here.
+
+config DN_SERIAL
+ bool "Support for DN serial port (dummy)"
+ depends on APOLLO
+
+config SERIAL_CONSOLE
+ bool "Support for serial port console"
+ depends on (AMIGA || ATARI || SUN3 || SUN3X || VME || APOLLO) && (ATARI_MFPSER=y || ATARI_MIDI=y || AMIGA_BUILTIN_SERIAL=y || MULTIFACE_III_TTY=y || SERIAL=y || SERIAL167 || DN_SERIAL)
+ ---help---
+ If you say Y here, it will be possible to use a serial port as the
+ system console (the system console is the device which receives all
+ kernel messages and warnings and which allows logins in single user
+ mode). This could be useful if some terminal or printer is connected
+ to that serial port.
+
+ Even if you say Y here, the currently visible virtual console
+ (/dev/tty0) will still be used as the system console by default, but
+ you can alter that using a kernel command line option such as
+ "console=ttyS1". (Try "man bootparam" or see the documentation of
+ your boot loader (lilo or loadlin) about how to pass options to the
+ kernel at boot time.)
+
+ If you don't have a VGA card installed and you say Y here, the
+ kernel will automatically use the first serial line, /dev/ttyS0, as
+ system console.
+
+ If unsure, say N.
+
+endmenu
+
+endif
diff --git a/arch/m68k/Kconfig.nommu b/arch/m68k/Kconfig.machine
index ff46383112a4..ef4a26aff780 100644
--- a/arch/m68k/Kconfig.nommu
+++ b/arch/m68k/Kconfig.machine
@@ -1,297 +1,142 @@
-config FPU
- bool
- default n
-
-config GENERIC_GPIO
- bool
- default n
-
-config GENERIC_CMOS_UPDATE
- bool
- default y
-
-config GENERIC_CLOCKEVENTS
- bool
- default n
-
-config M68000
- bool
- select CPU_HAS_NO_BITFIELDS
- help
- The Freescale (was Motorola) 68000 CPU is the first generation of
- the well known M68K family of processors. The CPU core as well as
- being available as a stand alone CPU was also used in many
- System-On-Chip devices (eg 68328, 68302, etc). It does not contain
- a paging MMU.
-
-config MCPU32
- bool
- select CPU_HAS_NO_BITFIELDS
- help
- The Freescale (was then Motorola) CPU32 is a CPU core that is
- based on the 68020 processor. For the most part it is used in
- System-On-Chip parts, and does not contain a paging MMU.
-
-config COLDFIRE
- bool
- select GENERIC_GPIO
- select ARCH_REQUIRE_GPIOLIB
- select CPU_HAS_NO_BITFIELDS
- help
- The Freescale ColdFire family of processors is a modern derivitive
- of the 68000 processor family. They are mainly targeted at embedded
- applications, and are all System-On-Chip (SOC) devices, as opposed
- to stand alone CPUs. They implement a subset of the original 68000
- processor instruction set.
-
-config COLDFIRE_SW_A7
- bool
- default n
-
-config HAVE_CACHE_SPLIT
- bool
-
-config HAVE_CACHE_CB
- bool
-
-config HAVE_MBAR
- bool
-
-config HAVE_IPSBAR
- bool
-
-choice
- prompt "CPU"
- default M68EZ328
-
-config M68328
- bool "MC68328"
- select M68000
- help
- Motorola 68328 processor support.
-
-config M68EZ328
- bool "MC68EZ328"
- select M68000
- help
- Motorola 68EX328 processor support.
-
-config M68VZ328
- bool "MC68VZ328"
- select M68000
- help
- Motorola 68VZ328 processor support.
-
-config M68360
- bool "MC68360"
- select MCPU32
- help
- Motorola 68360 processor support.
-
-config M5206
- bool "MCF5206"
- select COLDFIRE
- select COLDFIRE_SW_A7
- select HAVE_MBAR
- help
- Motorola ColdFire 5206 processor support.
+comment "Machine Types"
+
+config AMIGA
+ bool "Amiga support"
+ depends on MMU
+ select MMU_MOTOROLA if MMU
+ help
+ This option enables support for the Amiga series of computers. If
+ you plan to use this kernel on an Amiga, say Y here and browse the
+ material available in <file:Documentation/m68k>; otherwise say N.
+
+config ATARI
+ bool "Atari support"
+ depends on MMU
+ select MMU_MOTOROLA if MMU
+ help
+ This option enables support for the 68000-based Atari series of
+ computers (including the TT, Falcon and Medusa). If you plan to use
+ this kernel on an Atari, say Y here and browse the material
+ available in <file:Documentation/m68k>; otherwise say N.
+
+config MAC
+ bool "Macintosh support"
+ depends on MMU
+ select MMU_MOTOROLA if MMU
+ help
+ This option enables support for the Apple Macintosh series of
+ computers (yes, there is experimental support now, at least for part
+ of the series).
+
+ Say N unless you're willing to code the remaining necessary support.
+ ;)
+
+config APOLLO
+ bool "Apollo support"
+ depends on MMU
+ select MMU_MOTOROLA if MMU
+ help
+ Say Y here if you want to run Linux on an MC680x0-based Apollo
+ Domain workstation such as the DN3500.
+
+config VME
+ bool "VME (Motorola and BVM) support"
+ depends on MMU
+ select MMU_MOTOROLA if MMU
+ help
+ Say Y here if you want to build a kernel for a 680x0 based VME
+ board. Boards currently supported include Motorola boards MVME147,
+ MVME162, MVME166, MVME167, MVME172, and MVME177. BVME4000 and
+ BVME6000 boards from BVM Ltd are also supported.
+
+config MVME147
+ bool "MVME147 support"
+ depends on MMU
+ depends on VME
+ help
+ Say Y to include support for early Motorola VME boards. This will
+ build a kernel which can run on MVME147 single-board computers. If
+ you select this option you will have to select the appropriate
+ drivers for SCSI, Ethernet and serial ports later on.
+
+config MVME16x
+ bool "MVME162, 166 and 167 support"
+ depends on MMU
+ depends on VME
+ help
+ Say Y to include support for Motorola VME boards. This will build a
+ kernel which can run on MVME162, MVME166, MVME167, MVME172, and
+ MVME177 boards. If you select this option you will have to select
+ the appropriate drivers for SCSI, Ethernet and serial ports later
+ on.
+
+config BVME6000
+ bool "BVME4000 and BVME6000 support"
+ depends on MMU
+ depends on VME
+ help
+ Say Y to include support for VME boards from BVM Ltd. This will
+ build a kernel which can run on BVME4000 and BVME6000 boards. If
+ you select this option you will have to select the appropriate
+ drivers for SCSI, Ethernet and serial ports later on.
+
+config HP300
+ bool "HP9000/300 and HP9000/400 support"
+ depends on MMU
+ select MMU_MOTOROLA if MMU
+ help
+ This option enables support for the HP9000/300 and HP9000/400 series
+ of workstations. Support for these machines is still somewhat
+ experimental. If you plan to try to use the kernel on such a machine
+ say Y here.
+ Everybody else says N.
+
+config SUN3X
+ bool "Sun3x support"
+ depends on MMU
+ select MMU_MOTOROLA if MMU
+ select M68030
+ help
+ This option enables support for the Sun 3x series of workstations.
+ Be warned that this support is very experimental.
+ Note that Sun 3x kernels are not compatible with Sun 3 hardware.
+ General Linux information on the Sun 3x series (now discontinued)
+ is at <http://www.angelfire.com/ca2/tech68k/sun3.html>.
+
+ If you don't want to compile a kernel for a Sun 3x, say N.
+
+config Q40
+ bool "Q40/Q60 support"
+ depends on MMU
+ select MMU_MOTOROLA if MMU
+ help
+ The Q40 is a Motorola 68040-based successor to the Sinclair QL
+ manufactured in Germany. There is an official Q40 home page at
+ <http://www.q40.de/>. This option enables support for the Q40 and
+ Q60. Select your CPU below. For 68LC060 don't forget to enable FPU
+ emulation.
+
+config SUN3
+ bool "Sun3 support"
+ depends on MMU
+ depends on !MMU_MOTOROLA
+ select MMU_SUN3 if MMU
+ select M68020
+ help
+ This option enables support for the Sun 3 series of workstations
+ (3/50, 3/60, 3/1xx, 3/2xx systems). Enabling this option requires
+ that all other hardware types must be disabled, as Sun 3 kernels
+ are incompatible with all other m68k targets (including Sun 3x!).
+
+ If you don't want to compile a kernel exclusively for a Sun 3, say N.
-config M5206e
- bool "MCF5206e"
- select COLDFIRE
- select COLDFIRE_SW_A7
- select HAVE_MBAR
- help
- Motorola ColdFire 5206e processor support.
-
-config M520x
- bool "MCF520x"
- select COLDFIRE
- select GENERIC_CLOCKEVENTS
- select HAVE_CACHE_SPLIT
- help
- Freescale Coldfire 5207/5208 processor support.
-
-config M523x
- bool "MCF523x"
- select COLDFIRE
- select GENERIC_CLOCKEVENTS
- select HAVE_CACHE_SPLIT
- select HAVE_IPSBAR
- help
- Freescale Coldfire 5230/1/2/4/5 processor support
-
-config M5249
- bool "MCF5249"
- select COLDFIRE
- select COLDFIRE_SW_A7
- select HAVE_MBAR
- help
- Motorola ColdFire 5249 processor support.
-
-config M5271
- bool "MCF5271"
- select COLDFIRE
- select HAVE_CACHE_SPLIT
- select HAVE_IPSBAR
- help
- Freescale (Motorola) ColdFire 5270/5271 processor support.
-
-config M5272
- bool "MCF5272"
- select COLDFIRE
- select COLDFIRE_SW_A7
- select HAVE_MBAR
- help
- Motorola ColdFire 5272 processor support.
-
-config M5275
- bool "MCF5275"
- select COLDFIRE
- select HAVE_CACHE_SPLIT
- select HAVE_IPSBAR
- help
- Freescale (Motorola) ColdFire 5274/5275 processor support.
-
-config M528x
- bool "MCF528x"
- select COLDFIRE
- select GENERIC_CLOCKEVENTS
- select HAVE_CACHE_SPLIT
- select HAVE_IPSBAR
- help
- Motorola ColdFire 5280/5282 processor support.
-
-config M5307
- bool "MCF5307"
- select COLDFIRE
- select COLDFIRE_SW_A7
- select HAVE_CACHE_CB
- select HAVE_MBAR
- help
- Motorola ColdFire 5307 processor support.
-
-config M532x
- bool "MCF532x"
- select COLDFIRE
- select HAVE_CACHE_CB
- help
- Freescale (Motorola) ColdFire 532x processor support.
-
-config M5407
- bool "MCF5407"
- select COLDFIRE
- select COLDFIRE_SW_A7
- select HAVE_CACHE_CB
- select HAVE_MBAR
- help
- Motorola ColdFire 5407 processor support.
-
-config M547x
- bool "MCF547x"
- select COLDFIRE
- select HAVE_CACHE_CB
- select HAVE_MBAR
- help
- Freescale ColdFire 5470/5471/5472/5473/5474/5475 processor support.
-
-config M548x
- bool "MCF548x"
- select COLDFIRE
- select HAVE_CACHE_CB
- select HAVE_MBAR
- help
- Freescale ColdFire 5480/5481/5482/5483/5484/5485 processor support.
-
-endchoice
-
-config M527x
- bool
- depends on (M5271 || M5275)
- select GENERIC_CLOCKEVENTS
- default y
-
-config M54xx
+config PILOT
bool
- depends on (M548x || M547x)
- default y
-
-config CLOCK_SET
- bool "Enable setting the CPU clock frequency"
- default n
- help
- On some CPU's you do not need to know what the core CPU clock
- frequency is. On these you can disable clock setting. On some
- traditional 68K parts, and on all ColdFire parts you need to set
- the appropriate CPU clock frequency. On these devices many of the
- onboard peripherals derive their timing from the master CPU clock
- frequency.
-
-config CLOCK_FREQ
- int "Set the core clock frequency"
- default "66666666"
- depends on CLOCK_SET
- help
- Define the CPU clock frequency in use. This is the core clock
- frequency, it may or may not be the same as the external clock
- crystal fitted to your board. Some processors have an internal
- PLL and can have their frequency programmed at run time, others
- use internal dividers. In general the kernel won't setup a PLL
- if it is fitted (there are some exceptions). This value will be
- specific to the exact CPU that you are using.
-
-config OLDMASK
- bool "Old mask 5307 (1H55J) silicon"
- depends on M5307
- help
- Build support for the older revision ColdFire 5307 silicon.
- Specifically this is the 1H55J mask revision.
-
-if HAVE_CACHE_SPLIT
-choice
- prompt "Split Cache Configuration"
- default CACHE_I
-
-config CACHE_I
- bool "Instruction"
- help
- Use all of the ColdFire CPU cache memory as an instruction cache.
-
-config CACHE_D
- bool "Data"
- help
- Use all of the ColdFire CPU cache memory as a data cache.
-
-config CACHE_BOTH
- bool "Both"
- help
- Split the ColdFire CPU cache, and use half as an instruction cache
- and half as a data cache.
-endchoice
-endif
-
-if HAVE_CACHE_CB
-choice
- prompt "Data cache mode"
- default CACHE_WRITETHRU
-
-config CACHE_WRITETHRU
- bool "Write-through"
- help
- The ColdFire CPU cache is set into Write-through mode.
-
-config CACHE_COPYBACK
- bool "Copy-back"
- help
- The ColdFire CPU cache is set into Copy-back mode.
-endchoice
-endif
-
-comment "Platform"
config PILOT3
bool "Pilot 1000/5000, PalmPilot Personal/Pro, or PalmIII support"
depends on M68328
+ select PILOT
help
Support for the Palm Pilot 1000/5000, Personal/Pro and PalmIII.
@@ -302,7 +147,7 @@ config XCOPILOT_BUGS
Support the bugs of Xcopilot.
config UC5272
- bool 'Arcturus Networks uC5272 dimm board support'
+ bool "Arcturus Networks uC5272 dimm board support"
depends on M5272
help
Support for the Arcturus Networks uC5272 dimm board.
@@ -356,15 +201,23 @@ config UCQUICC
help
Support for the Lineo uCquicc board.
+config ARNEWSH
+ bool
+
config ARN5206
bool "Arnewsh 5206 board support"
depends on M5206
+ select ARNEWSH
help
Support for the Arnewsh 5206 board.
+config FREESCALE
+ bool
+
config M5206eC3
bool "Motorola M5206eC3 board support"
depends on M5206e
+ select FREESCALE
help
Support for the Motorola M5206eC3 board.
@@ -377,75 +230,92 @@ config ELITE
config M5208EVB
bool "Freescale M5208EVB board support"
depends on M520x
+ select FREESCALE
help
Support for the Freescale Coldfire M5208EVB.
config M5235EVB
bool "Freescale M5235EVB support"
depends on M523x
+ select FREESCALE
help
Support for the Freescale M5235EVB board.
config M5249C3
bool "Motorola M5249C3 board support"
depends on M5249
+ select FREESCALE
help
Support for the Motorola M5249C3 board.
config M5271EVB
bool "Freescale (Motorola) M5271EVB board support"
depends on M5271
+ select FREESCALE
help
Support for the Freescale (Motorola) M5271EVB board.
config M5275EVB
bool "Freescale (Motorola) M5275EVB board support"
depends on M5275
+ select FREESCALE
help
Support for the Freescale (Motorola) M5275EVB board.
config M5272C3
bool "Motorola M5272C3 board support"
depends on M5272
+ select FREESCALE
help
Support for the Motorola M5272C3 board.
+config senTec
+ bool
+
config COBRA5272
bool "senTec COBRA5272 board support"
depends on M5272
+ select senTec
help
Support for the senTec COBRA5272 board.
+config AVNET
+ bool
+
config AVNET5282
bool "Avnet 5282 board support"
depends on M528x
+ select AVNET
help
- Support for the Avnet 5282 board.
-
+ Support for the Avnet 5282 board.
+
config M5282EVB
bool "Motorola M5282EVB board support"
depends on M528x
+ select FREESCALE
help
Support for the Motorola M5282EVB board.
config COBRA5282
bool "senTec COBRA5282 board support"
depends on M528x
+ select senTec
help
Support for the senTec COBRA5282 board.
-
+
config SOM5282EM
bool "EMAC.Inc SOM5282EM board support"
depends on M528x
+ select EMAC_INC
help
- Support for the EMAC.Inc SOM5282EM module.
-
+ Support for the EMAC.Inc SOM5282EM module.
+
config WILDFIRE
bool "Intec Automation Inc. WildFire board support"
depends on M528x
help
Support for the Intec Automation Inc. WildFire.
-
+
config WILDFIREMOD
bool "Intec Automation Inc. WildFire module support"
depends on M528x
@@ -455,12 +325,14 @@ config WILDFIREMOD
config ARN5307
bool "Arnewsh 5307 board support"
depends on M5307
+ select ARNEWSH
help
Support for the Arnewsh 5307 board.
config M5307C3
bool "Motorola M5307C3 board support"
depends on M5307
+ select FREESCALE
help
Support for the Motorola M5307C3 board.
@@ -473,6 +345,7 @@ config SECUREEDGEMP3
config M5329EVB
bool "Freescale (Motorola) M5329EVB board support"
depends on M532x
+ select FREESCALE
help
Support for the Freescale (Motorola) M5329EVB board.
@@ -485,6 +358,7 @@ config COBRA5329
config M5407C3
bool "Motorola M5407C3 board support"
depends on M5407
+ select FREESCALE
help
Support for the Motorola M5407C3 board.
@@ -524,9 +398,13 @@ config SNAPGEAR
help
Special additional support for SnapGear router boards.
+config SNEHA
+ bool
+
config CPU16B
bool "Sneha Technologies S.L. Sarasvati board support"
depends on M5272
+ select SNEHA
help
Support for the SNEHA CPU16B board.
@@ -536,63 +414,20 @@ config MOD5272
help
Support for the Netburner MOD-5272 board.
+config SAVANT
+ bool
+
config SAVANTrosie1
bool "Savant Rosie1 board support"
depends on M523x
+ select SAVANT
help
Support for the Savant Rosie1 board.
-config ROMFS_FROM_ROM
- bool "ROMFS image not RAM resident"
- depends on (NETtel || SNAPGEAR)
- help
- The ROMfs filesystem will stay resident in the FLASH/ROM, not be
- moved into RAM.
-
-config PILOT
- bool
- default y
- depends on (PILOT3 || PILOT5)
-
-config ARNEWSH
- bool
- default y
- depends on (ARN5206 || ARN5307)
-
-config FREESCALE
- bool
- default y
- depends on (M5206eC3 || M5208EVB || M5235EVB || M5249C3 || M5271EVB || M5272C3 || M5275EVB || M5282EVB || M5307C3 || M5329EVB || M5407C3)
-
-config HW_FEITH
- bool
- default y
- depends on (CLEOPATRA || CANCam || SCALES)
-
-config senTec
- bool
- default y
- depends on (COBRA5272 || COBRA5282)
-
-config EMAC_INC
- bool
- default y
- depends on (SOM5282EM)
-config SNEHA
- bool
- default y
- depends on CPU16B
+if !MMU || COLDFIRE
-config SAVANT
- bool
- default y
- depends on SAVANTrosie1
-
-config AVNET
- bool
- default y
- depends on (AVNET5282)
+comment "Machine Options"
config UBOOT
bool "Support for U-Boot command line parameters"
@@ -673,33 +508,6 @@ config KERNELBASE
a system with the RAM based at address 0, and leaving enough room
for the theoretical maximum number of 256 vectors.
-choice
- prompt "RAM bus width"
- default RAMAUTOBIT
-
-config RAMAUTOBIT
- bool "AUTO"
- help
- Select the physical RAM data bus size. Not needed on most platforms,
- so you can generally choose AUTO.
-
-config RAM8BIT
- bool "8bit"
- help
- Configure RAM bus to be 8 bits wide.
-
-config RAM16BIT
- bool "16bit"
- help
- Configure RAM bus to be 16 bits wide.
-
-config RAM32BIT
- bool "32bit"
- help
- Configure RAM bus to be 32 bits wide.
-
-endchoice
-
comment "ROM configuration"
config ROM
@@ -772,16 +580,4 @@ config ROMKERNEL
endchoice
-if COLDFIRE
-source "kernel/Kconfig.preempt"
endif
-
-source "kernel/time/Kconfig"
-
-config ISA_DMA_API
- bool
- depends on !M5272
- default y
-
-source "drivers/pcmcia/Kconfig"
-
diff --git a/arch/m68k/Kconfig.mmu b/arch/m68k/Kconfig.mmu
deleted file mode 100644
index 13e20bbc4079..000000000000
--- a/arch/m68k/Kconfig.mmu
+++ /dev/null
@@ -1,411 +0,0 @@
-config GENERIC_IOMAP
- bool
- default y
-
-config ARCH_MAY_HAVE_PC_FDC
- bool
- depends on BROKEN && (Q40 || SUN3X)
- default y
-
-config ARCH_USES_GETTIMEOFFSET
- def_bool y
-
-config EISA
- bool
- ---help---
- The Extended Industry Standard Architecture (EISA) bus was
- developed as an open alternative to the IBM MicroChannel bus.
-
- The EISA bus provided some of the features of the IBM MicroChannel
- bus while maintaining backward compatibility with cards made for
- the older ISA bus. The EISA bus saw limited use between 1988 and
- 1995 when it was made obsolete by the PCI bus.
-
- Say Y here if you are building a kernel for an EISA-based machine.
-
- Otherwise, say N.
-
-config MCA
- bool
- help
- MicroChannel Architecture is found in some IBM PS/2 machines and
- laptops. It is a bus system similar to PCI or ISA. See
- <file:Documentation/mca.txt> (and especially the web page given
- there) before attempting to build an MCA bus kernel.
-
-config PCMCIA
- tristate
- ---help---
- Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
- computer. These are credit-card size devices such as network cards,
- modems or hard drives often used with laptops computers. There are
- actually two varieties of these cards: the older 16 bit PCMCIA cards
- and the newer 32 bit CardBus cards. If you want to use CardBus
- cards, you need to say Y here and also to "CardBus support" below.
-
- To use your PC-cards, you will need supporting software from David
- Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
- for location). Please also read the PCMCIA-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as modules, choose M here: the
- modules will be called pcmcia_core and ds.
-
-config AMIGA
- bool "Amiga support"
- select MMU_MOTOROLA if MMU
- help
- This option enables support for the Amiga series of computers. If
- you plan to use this kernel on an Amiga, say Y here and browse the
- material available in <file:Documentation/m68k>; otherwise say N.
-
-config ATARI
- bool "Atari support"
- select MMU_MOTOROLA if MMU
- help
- This option enables support for the 68000-based Atari series of
- computers (including the TT, Falcon and Medusa). If you plan to use
- this kernel on an Atari, say Y here and browse the material
- available in <file:Documentation/m68k>; otherwise say N.
-
-config MAC
- bool "Macintosh support"
- select MMU_MOTOROLA if MMU
- help
- This option enables support for the Apple Macintosh series of
- computers (yes, there is experimental support now, at least for part
- of the series).
-
- Say N unless you're willing to code the remaining necessary support.
- ;)
-
-config NUBUS
- bool
- depends on MAC
- default y
-
-config M68K_L2_CACHE
- bool
- depends on MAC
- default y
-
-config APOLLO
- bool "Apollo support"
- select MMU_MOTOROLA if MMU
- help
- Say Y here if you want to run Linux on an MC680x0-based Apollo
- Domain workstation such as the DN3500.
-
-config VME
- bool "VME (Motorola and BVM) support"
- select MMU_MOTOROLA if MMU
- help
- Say Y here if you want to build a kernel for a 680x0 based VME
- board. Boards currently supported include Motorola boards MVME147,
- MVME162, MVME166, MVME167, MVME172, and MVME177. BVME4000 and
- BVME6000 boards from BVM Ltd are also supported.
-
-config MVME147
- bool "MVME147 support"
- depends on VME
- help
- Say Y to include support for early Motorola VME boards. This will
- build a kernel which can run on MVME147 single-board computers. If
- you select this option you will have to select the appropriate
- drivers for SCSI, Ethernet and serial ports later on.
-
-config MVME16x
- bool "MVME162, 166 and 167 support"
- depends on VME
- help
- Say Y to include support for Motorola VME boards. This will build a
- kernel which can run on MVME162, MVME166, MVME167, MVME172, and
- MVME177 boards. If you select this option you will have to select
- the appropriate drivers for SCSI, Ethernet and serial ports later
- on.
-
-config BVME6000
- bool "BVME4000 and BVME6000 support"
- depends on VME
- help
- Say Y to include support for VME boards from BVM Ltd. This will
- build a kernel which can run on BVME4000 and BVME6000 boards. If
- you select this option you will have to select the appropriate
- drivers for SCSI, Ethernet and serial ports later on.
-
-config HP300
- bool "HP9000/300 and HP9000/400 support"
- select MMU_MOTOROLA if MMU
- help
- This option enables support for the HP9000/300 and HP9000/400 series
- of workstations. Support for these machines is still somewhat
- experimental. If you plan to try to use the kernel on such a machine
- say Y here.
- Everybody else says N.
-
-config DIO
- bool "DIO bus support"
- depends on HP300
- default y
- help
- Say Y here to enable support for the "DIO" expansion bus used in
- HP300 machines. If you are using such a system you almost certainly
- want this.
-
-config SUN3X
- bool "Sun3x support"
- select MMU_MOTOROLA if MMU
- select M68030
- help
- This option enables support for the Sun 3x series of workstations.
- Be warned that this support is very experimental.
- Note that Sun 3x kernels are not compatible with Sun 3 hardware.
- General Linux information on the Sun 3x series (now discontinued)
- is at <http://www.angelfire.com/ca2/tech68k/sun3.html>.
-
- If you don't want to compile a kernel for a Sun 3x, say N.
-
-config Q40
- bool "Q40/Q60 support"
- select MMU_MOTOROLA if MMU
- help
- The Q40 is a Motorola 68040-based successor to the Sinclair QL
- manufactured in Germany. There is an official Q40 home page at
- <http://www.q40.de/>. This option enables support for the Q40 and
- Q60. Select your CPU below. For 68LC060 don't forget to enable FPU
- emulation.
-
-config SUN3
- bool "Sun3 support"
- depends on !MMU_MOTOROLA
- select MMU_SUN3 if MMU
- select M68020
- help
- This option enables support for the Sun 3 series of workstations
- (3/50, 3/60, 3/1xx, 3/2xx systems). Enabling this option requires
- that all other hardware types must be disabled, as Sun 3 kernels
- are incompatible with all other m68k targets (including Sun 3x!).
-
- If you don't want to compile a kernel exclusively for a Sun 3, say N.
-
-config NATFEAT
- bool "ARAnyM emulator support"
- depends on ATARI
- help
- This option enables support for ARAnyM native features, such as
- access to a disk image as /dev/hda.
-
-config NFBLOCK
- tristate "NatFeat block device support"
- depends on BLOCK && NATFEAT
- help
- Say Y to include support for the ARAnyM NatFeat block device
- which allows direct access to the hard drives without using
- the hardware emulation.
-
-config NFCON
- tristate "NatFeat console driver"
- depends on NATFEAT
- help
- Say Y to include support for the ARAnyM NatFeat console driver
- which allows the console output to be redirected to the stderr
- output of ARAnyM.
-
-config NFETH
- tristate "NatFeat Ethernet support"
- depends on NET_ETHERNET && NATFEAT
- help
- Say Y to include support for the ARAnyM NatFeat network device
- which will emulate a regular ethernet device while presenting an
- ethertap device to the host system.
-
-comment "Processor type"
-
-config M68020
- bool "68020 support"
- help
- If you anticipate running this kernel on a computer with a MC68020
- processor, say Y. Otherwise, say N. Note that the 68020 requires a
- 68851 MMU (Memory Management Unit) to run Linux/m68k, except on the
- Sun 3, which provides its own version.
-
-config M68030
- bool "68030 support"
- depends on !MMU_SUN3
- help
- If you anticipate running this kernel on a computer with a MC68030
- processor, say Y. Otherwise, say N. Note that a MC68EC030 will not
- work, as it does not include an MMU (Memory Management Unit).
-
-config M68040
- bool "68040 support"
- depends on !MMU_SUN3
- help
- If you anticipate running this kernel on a computer with a MC68LC040
- or MC68040 processor, say Y. Otherwise, say N. Note that an
- MC68EC040 will not work, as it does not include an MMU (Memory
- Management Unit).
-
-config M68060
- bool "68060 support"
- depends on !MMU_SUN3
- help
- If you anticipate running this kernel on a computer with a MC68060
- processor, say Y. Otherwise, say N.
-
-config MMU_MOTOROLA
- bool
-
-config MMU_SUN3
- bool
- depends on MMU && !MMU_MOTOROLA
-
-config M68KFPU_EMU
- bool "Math emulation support (EXPERIMENTAL)"
- depends on EXPERIMENTAL
- help
- At some point in the future, this will cause floating-point math
- instructions to be emulated by the kernel on machines that lack a
- floating-point math coprocessor. Thrill-seekers and chronically
- sleep-deprived psychotic hacker types can say Y now, everyone else
- should probably wait a while.
-
-config M68KFPU_EMU_EXTRAPREC
- bool "Math emulation extra precision"
- depends on M68KFPU_EMU
- help
- The fpu uses normally a few bit more during calculations for
- correct rounding, the emulator can (often) do the same but this
- extra calculation can cost quite some time, so you can disable
- it here. The emulator will then "only" calculate with a 64 bit
- mantissa and round slightly incorrect, what is more than enough
- for normal usage.
-
-config M68KFPU_EMU_ONLY
- bool "Math emulation only kernel"
- depends on M68KFPU_EMU
- help
- This option prevents any floating-point instructions from being
- compiled into the kernel, thereby the kernel doesn't save any
- floating point context anymore during task switches, so this
- kernel will only be usable on machines without a floating-point
- math coprocessor. This makes the kernel a bit faster as no tests
- needs to be executed whether a floating-point instruction in the
- kernel should be executed or not.
-
-config ADVANCED
- bool "Advanced configuration options"
- ---help---
- This gives you access to some advanced options for the CPU. The
- defaults should be fine for most users, but these options may make
- it possible for you to improve performance somewhat if you know what
- you are doing.
-
- Note that the answer to this question won't directly affect the
- kernel: saying N will just cause the configurator to skip all
- the questions about these options.
-
- Most users should say N to this question.
-
-config RMW_INSNS
- bool "Use read-modify-write instructions"
- depends on ADVANCED
- ---help---
- This allows to use certain instructions that work with indivisible
- read-modify-write bus cycles. While this is faster than the
- workaround of disabling interrupts, it can conflict with DMA
- ( = direct memory access) on many Amiga systems, and it is also said
- to destabilize other machines. It is very likely that this will
- cause serious problems on any Amiga or Atari Medusa if set. The only
- configuration where it should work are 68030-based Ataris, where it
- apparently improves performance. But you've been warned! Unless you
- really know what you are doing, say N. Try Y only if you're quite
- adventurous.
-
-config SINGLE_MEMORY_CHUNK
- bool "Use one physical chunk of memory only" if ADVANCED && !SUN3
- default y if SUN3
- select NEED_MULTIPLE_NODES
- help
- Ignore all but the first contiguous chunk of physical memory for VM
- purposes. This will save a few bytes kernel size and may speed up
- some operations. Say N if not sure.
-
-config 060_WRITETHROUGH
- bool "Use write-through caching for 68060 supervisor accesses"
- depends on ADVANCED && M68060
- ---help---
- The 68060 generally uses copyback caching of recently accessed data.
- Copyback caching means that memory writes will be held in an on-chip
- cache and only written back to memory some time later. Saying Y
- here will force supervisor (kernel) accesses to use writethrough
- caching. Writethrough caching means that data is written to memory
- straight away, so that cache and memory data always agree.
- Writethrough caching is less efficient, but is needed for some
- drivers on 68060 based systems where the 68060 bus snooping signal
- is hardwired on. The 53c710 SCSI driver is known to suffer from
- this problem.
-
-config ARCH_DISCONTIGMEM_ENABLE
- def_bool !SINGLE_MEMORY_CHUNK
-
-config NODES_SHIFT
- int
- default "3"
- depends on !SINGLE_MEMORY_CHUNK
-
-config ZORRO
- bool "Amiga Zorro (AutoConfig) bus support"
- depends on AMIGA
- help
- This enables support for the Zorro bus in the Amiga. If you have
- expansion cards in your Amiga that conform to the Amiga
- AutoConfig(tm) specification, say Y, otherwise N. Note that even
- expansion cards that do not fit in the Zorro slots but fit in e.g.
- the CPU slot may fall in this category, so you have to say Y to let
- Linux use these.
-
-config AMIGA_PCMCIA
- bool "Amiga 1200/600 PCMCIA support (EXPERIMENTAL)"
- depends on AMIGA && EXPERIMENTAL
- help
- Include support in the kernel for pcmcia on Amiga 1200 and Amiga
- 600. If you intend to use pcmcia cards say Y; otherwise say N.
-
-config HEARTBEAT
- bool "Use power LED as a heartbeat" if AMIGA || APOLLO || ATARI || MAC ||Q40
- default y if !AMIGA && !APOLLO && !ATARI && !MAC && !Q40 && HP300
- help
- Use the power-on LED on your machine as a load meter. The exact
- behavior is platform-dependent, but normally the flash frequency is
- a hyperbolic function of the 5-minute load average.
-
-# We have a dedicated heartbeat LED. :-)
-config PROC_HARDWARE
- bool "/proc/hardware support"
- help
- Say Y here to support the /proc/hardware file, which gives you
- access to information about the machine you're running on,
- including the model, CPU, MMU, clock speed, BogoMIPS rating,
- and memory size.
-
-config ISA
- bool
- depends on Q40 || AMIGA_PCMCIA
- default y
- help
- Find out whether you have ISA slots on your motherboard. ISA is the
- name of a bus system, i.e. the way the CPU talks to the other stuff
- inside your box. Other bus systems are PCI, EISA, MicroChannel
- (MCA) or VESA. ISA is an older system, now being displaced by PCI;
- newer boards don't support it. If you have ISA, say Y, otherwise N.
-
-config GENERIC_ISA_DMA
- bool
- depends on Q40 || AMIGA_PCMCIA
- default y
-
-source "drivers/pci/Kconfig"
-
-source "drivers/zorro/Kconfig"
-
diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile
index be46cadd4017..cf318f20c64d 100644
--- a/arch/m68k/Makefile
+++ b/arch/m68k/Makefile
@@ -1,7 +1,171 @@
+#
+# m68k/Makefile
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies. Remember to do have actions
+# for "archclean" and "archdep" for cleaning up and making dependencies for
+# this architecture
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1994 by Hamish Macdonald
+# Copyright (C) 2002,2011 Greg Ungerer <gerg@snapgear.com>
+#
+
KBUILD_DEFCONFIG := multi_defconfig
+#
+# Enable processor type. Ordering of these is important - we want to
+# use the minimum processor type of the range we support. The logic
+# for 680x0 will only allow use of the -m68060 or -m68040 if no other
+# 680x0 type is specified - and no option is specified for 68030 or
+# 68020. The other m68k/ColdFire types always specify some type of
+# compiler cpu type flag.
+#
+ifndef CONFIG_M68040
+cpuflags-$(CONFIG_M68060) := -m68060
+endif
+ifndef CONFIG_M68060
+cpuflags-$(CONFIG_M68040) := -m68040
+endif
+cpuflags-$(CONFIG_M68030) :=
+cpuflags-$(CONFIG_M68020) :=
+cpuflags-$(CONFIG_M68360) := -m68332
+cpuflags-$(CONFIG_M68000) := -m68000
+cpuflags-$(CONFIG_M54xx) := $(call cc-option,-mcpu=5475,-m5200)
+cpuflags-$(CONFIG_M5407) := $(call cc-option,-mcpu=5407,-m5200)
+cpuflags-$(CONFIG_M532x) := $(call cc-option,-mcpu=532x,-m5307)
+cpuflags-$(CONFIG_M5307) := $(call cc-option,-mcpu=5307,-m5200)
+cpuflags-$(CONFIG_M528x) := $(call cc-option,-mcpu=528x,-m5307)
+cpuflags-$(CONFIG_M5275) := $(call cc-option,-mcpu=5275,-m5307)
+cpuflags-$(CONFIG_M5272) := $(call cc-option,-mcpu=5272,-m5307)
+cpuflags-$(CONFIG_M5271) := $(call cc-option,-mcpu=5271,-m5307)
+cpuflags-$(CONFIG_M523x) := $(call cc-option,-mcpu=523x,-m5307)
+cpuflags-$(CONFIG_M5249) := $(call cc-option,-mcpu=5249,-m5200)
+cpuflags-$(CONFIG_M520x) := $(call cc-option,-mcpu=5208,-m5200)
+cpuflags-$(CONFIG_M5206e) := $(call cc-option,-mcpu=5206e,-m5200)
+cpuflags-$(CONFIG_M5206) := $(call cc-option,-mcpu=5206,-m5200)
+
+KBUILD_AFLAGS += $(cpuflags-y)
+KBUILD_CFLAGS += $(cpuflags-y) -pipe
ifdef CONFIG_MMU
-include $(srctree)/arch/m68k/Makefile_mm
+# without -fno-strength-reduce the 53c7xx.c driver fails ;-(
+KBUILD_CFLAGS += -fno-strength-reduce -ffixed-a2
+else
+# we can use a m68k-linux-gcc toolchain with these in place
+KBUILD_CFLAGS += -DUTS_SYSNAME=\"uClinux\"
+KBUILD_CFLAGS += -D__uClinux__
+KBUILD_AFLAGS += -D__uClinux__
+endif
+
+LDFLAGS := -m m68kelf
+KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds
+ifneq ($(SUBARCH),$(ARCH))
+ ifeq ($(CROSS_COMPILE),)
+ CROSS_COMPILE := $(call cc-cross-prefix, \
+ m68k-linux-gnu- m68k-linux- m68k-unknown-linux-gnu-)
+ endif
+endif
+
+ifdef CONFIG_SUN3
+LDFLAGS_vmlinux = -N
+endif
+
+CHECKFLAGS += -D__mc68000__
+
+
+ifdef CONFIG_KGDB
+# If configured for kgdb support, include debugging infos and keep the
+# frame pointer
+KBUILD_CFLAGS := $(subst -fomit-frame-pointer,,$(KBUILD_CFLAGS)) -g
+endif
+
+#
+# Select the assembler head startup code. Order is important. The default
+# head code is first, processor specific selections can override it after.
+#
+head-y := arch/m68k/kernel/head.o
+head-$(CONFIG_SUN3) := arch/m68k/kernel/sun3-head.o
+head-$(CONFIG_M68360) := arch/m68k/platform/68360/head.o
+head-$(CONFIG_M68000) := arch/m68k/platform/68328/head.o
+head-$(CONFIG_COLDFIRE) := arch/m68k/platform/coldfire/head.o
+
+core-y += arch/m68k/kernel/ arch/m68k/mm/
+libs-y += arch/m68k/lib/
+
+core-$(CONFIG_Q40) += arch/m68k/q40/
+core-$(CONFIG_AMIGA) += arch/m68k/amiga/
+core-$(CONFIG_ATARI) += arch/m68k/atari/
+core-$(CONFIG_MAC) += arch/m68k/mac/
+core-$(CONFIG_HP300) += arch/m68k/hp300/
+core-$(CONFIG_APOLLO) += arch/m68k/apollo/
+core-$(CONFIG_MVME147) += arch/m68k/mvme147/
+core-$(CONFIG_MVME16x) += arch/m68k/mvme16x/
+core-$(CONFIG_BVME6000) += arch/m68k/bvme6000/
+core-$(CONFIG_SUN3X) += arch/m68k/sun3x/ arch/m68k/sun3/
+core-$(CONFIG_SUN3) += arch/m68k/sun3/ arch/m68k/sun3/prom/
+core-$(CONFIG_NATFEAT) += arch/m68k/emu/
+core-$(CONFIG_M68040) += arch/m68k/fpsp040/
+core-$(CONFIG_M68060) += arch/m68k/ifpsp060/
+core-$(CONFIG_M68KFPU_EMU) += arch/m68k/math-emu/
+core-$(CONFIG_M68360) += arch/m68k/platform/68360/
+core-$(CONFIG_M68000) += arch/m68k/platform/68328/
+core-$(CONFIG_M68EZ328) += arch/m68k/platform/68EZ328/
+core-$(CONFIG_M68VZ328) += arch/m68k/platform/68VZ328/
+core-$(CONFIG_COLDFIRE) += arch/m68k/platform/coldfire/
+core-$(CONFIG_M5206) += arch/m68k/platform/5206/
+core-$(CONFIG_M5206e) += arch/m68k/platform/5206/
+core-$(CONFIG_M520x) += arch/m68k/platform/520x/
+core-$(CONFIG_M523x) += arch/m68k/platform/523x/
+core-$(CONFIG_M5249) += arch/m68k/platform/5249/
+core-$(CONFIG_M527x) += arch/m68k/platform/527x/
+core-$(CONFIG_M5272) += arch/m68k/platform/5272/
+core-$(CONFIG_M528x) += arch/m68k/platform/528x/
+core-$(CONFIG_M5307) += arch/m68k/platform/5307/
+core-$(CONFIG_M532x) += arch/m68k/platform/532x/
+core-$(CONFIG_M5407) += arch/m68k/platform/5407/
+core-$(CONFIG_M54xx) += arch/m68k/platform/54xx/
+
+
+all: zImage
+
+lilo: vmlinux
+ if [ -f $(INSTALL_PATH)/vmlinux ]; then mv -f $(INSTALL_PATH)/vmlinux $(INSTALL_PATH)/vmlinux.old; fi
+ if [ -f $(INSTALL_PATH)/System.map ]; then mv -f $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
+ cat vmlinux > $(INSTALL_PATH)/vmlinux
+ cp System.map $(INSTALL_PATH)/System.map
+ if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
+
+zImage compressed: vmlinux.gz
+
+vmlinux.gz: vmlinux
+
+ifndef CONFIG_KGDB
+ cp vmlinux vmlinux.tmp
+ $(STRIP) vmlinux.tmp
+ gzip -9c vmlinux.tmp >vmlinux.gz
+ rm vmlinux.tmp
else
-include $(srctree)/arch/m68k/Makefile_no
+ gzip -9c vmlinux >vmlinux.gz
endif
+
+bzImage: vmlinux.bz2
+
+vmlinux.bz2: vmlinux
+
+ifndef CONFIG_KGDB
+ cp vmlinux vmlinux.tmp
+ $(STRIP) vmlinux.tmp
+ bzip2 -1c vmlinux.tmp >vmlinux.bz2
+ rm vmlinux.tmp
+else
+ bzip2 -1c vmlinux >vmlinux.bz2
+endif
+
+archclean:
+ rm -f vmlinux.gz vmlinux.bz2
+
+install:
+ sh $(srctree)/arch/m68k/install.sh $(KERNELRELEASE) vmlinux.gz System.map "$(INSTALL_PATH)"
diff --git a/arch/m68k/Makefile_mm b/arch/m68k/Makefile_mm
deleted file mode 100644
index d449b6d5aecf..000000000000
--- a/arch/m68k/Makefile_mm
+++ /dev/null
@@ -1,121 +0,0 @@
-#
-# m68k/Makefile
-#
-# This file is included by the global makefile so that you can add your own
-# architecture-specific flags and dependencies. Remember to do have actions
-# for "archclean" and "archdep" for cleaning up and making dependencies for
-# this architecture
-#
-# This file is subject to the terms and conditions of the GNU General Public
-# License. See the file "COPYING" in the main directory of this archive
-# for more details.
-#
-# Copyright (C) 1994 by Hamish Macdonald
-#
-
-# override top level makefile
-AS += -m68020
-LDFLAGS := -m m68kelf
-KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds
-ifneq ($(SUBARCH),$(ARCH))
- ifeq ($(CROSS_COMPILE),)
- CROSS_COMPILE := $(call cc-cross-prefix, \
- m68k-linux-gnu- m68k-linux- m68k-unknown-linux-gnu-)
- endif
-endif
-
-ifdef CONFIG_SUN3
-LDFLAGS_vmlinux = -N
-endif
-
-CHECKFLAGS += -D__mc68000__
-
-# without -fno-strength-reduce the 53c7xx.c driver fails ;-(
-KBUILD_CFLAGS += -pipe -fno-strength-reduce -ffixed-a2
-
-# enable processor switch if compiled only for a single cpu
-ifndef CONFIG_M68020
-ifndef CONFIG_M68030
-
-ifndef CONFIG_M68060
-KBUILD_CFLAGS += -m68040
-endif
-
-ifndef CONFIG_M68040
-KBUILD_CFLAGS += -m68060
-endif
-
-endif
-endif
-
-ifdef CONFIG_KGDB
-# If configured for kgdb support, include debugging infos and keep the
-# frame pointer
-KBUILD_CFLAGS := $(subst -fomit-frame-pointer,,$(KBUILD_CFLAGS)) -g
-endif
-
-ifndef CONFIG_SUN3
-head-y := arch/m68k/kernel/head.o
-else
-head-y := arch/m68k/kernel/sun3-head.o
-endif
-
-core-y += arch/m68k/kernel/ arch/m68k/mm/
-libs-y += arch/m68k/lib/
-
-core-$(CONFIG_Q40) += arch/m68k/q40/
-core-$(CONFIG_AMIGA) += arch/m68k/amiga/
-core-$(CONFIG_ATARI) += arch/m68k/atari/
-core-$(CONFIG_MAC) += arch/m68k/mac/
-core-$(CONFIG_HP300) += arch/m68k/hp300/
-core-$(CONFIG_APOLLO) += arch/m68k/apollo/
-core-$(CONFIG_MVME147) += arch/m68k/mvme147/
-core-$(CONFIG_MVME16x) += arch/m68k/mvme16x/
-core-$(CONFIG_BVME6000) += arch/m68k/bvme6000/
-core-$(CONFIG_SUN3X) += arch/m68k/sun3x/ arch/m68k/sun3/
-core-$(CONFIG_SUN3) += arch/m68k/sun3/ arch/m68k/sun3/prom/
-core-$(CONFIG_NATFEAT) += arch/m68k/emu/
-core-$(CONFIG_M68040) += arch/m68k/fpsp040/
-core-$(CONFIG_M68060) += arch/m68k/ifpsp060/
-core-$(CONFIG_M68KFPU_EMU) += arch/m68k/math-emu/
-
-all: zImage
-
-lilo: vmlinux
- if [ -f $(INSTALL_PATH)/vmlinux ]; then mv -f $(INSTALL_PATH)/vmlinux $(INSTALL_PATH)/vmlinux.old; fi
- if [ -f $(INSTALL_PATH)/System.map ]; then mv -f $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
- cat vmlinux > $(INSTALL_PATH)/vmlinux
- cp System.map $(INSTALL_PATH)/System.map
- if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
-
-zImage compressed: vmlinux.gz
-
-vmlinux.gz: vmlinux
-
-ifndef CONFIG_KGDB
- cp vmlinux vmlinux.tmp
- $(STRIP) vmlinux.tmp
- gzip -9c vmlinux.tmp >vmlinux.gz
- rm vmlinux.tmp
-else
- gzip -9c vmlinux >vmlinux.gz
-endif
-
-bzImage: vmlinux.bz2
-
-vmlinux.bz2: vmlinux
-
-ifndef CONFIG_KGDB
- cp vmlinux vmlinux.tmp
- $(STRIP) vmlinux.tmp
- bzip2 -1c vmlinux.tmp >vmlinux.bz2
- rm vmlinux.tmp
-else
- bzip2 -1c vmlinux >vmlinux.bz2
-endif
-
-archclean:
- rm -f vmlinux.gz vmlinux.bz2
-
-install:
- sh $(srctree)/arch/m68k/install.sh $(KERNELRELEASE) vmlinux.gz System.map "$(INSTALL_PATH)"
diff --git a/arch/m68k/Makefile_no b/arch/m68k/Makefile_no
deleted file mode 100644
index 844d3f172264..000000000000
--- a/arch/m68k/Makefile_no
+++ /dev/null
@@ -1,124 +0,0 @@
-#
-# arch/m68k/Makefile
-#
-# This file is subject to the terms and conditions of the GNU General Public
-# License. See the file "COPYING" in the main directory of this archive
-# for more details.
-#
-# (C) Copyright 2002, Greg Ungerer <gerg@snapgear.com>
-#
-
-platform-$(CONFIG_M68328) := 68328
-platform-$(CONFIG_M68EZ328) := 68EZ328
-platform-$(CONFIG_M68VZ328) := 68VZ328
-platform-$(CONFIG_M68360) := 68360
-platform-$(CONFIG_M5206) := 5206
-platform-$(CONFIG_M5206e) := 5206
-platform-$(CONFIG_M520x) := 520x
-platform-$(CONFIG_M523x) := 523x
-platform-$(CONFIG_M5249) := 5249
-platform-$(CONFIG_M527x) := 527x
-platform-$(CONFIG_M5272) := 5272
-platform-$(CONFIG_M528x) := 528x
-platform-$(CONFIG_M5307) := 5307
-platform-$(CONFIG_M532x) := 532x
-platform-$(CONFIG_M5407) := 5407
-platform-$(CONFIG_M54xx) := 54xx
-PLATFORM := $(platform-y)
-
-board-$(CONFIG_PILOT) := pilot
-board-$(CONFIG_UC5272) := UC5272
-board-$(CONFIG_UC5282) := UC5282
-board-$(CONFIG_UCSIMM) := ucsimm
-board-$(CONFIG_UCDIMM) := ucdimm
-board-$(CONFIG_UCQUICC) := uCquicc
-board-$(CONFIG_DRAGEN2) := de2
-board-$(CONFIG_ARNEWSH) := ARNEWSH
-board-$(CONFIG_FREESCALE) := FREESCALE
-board-$(CONFIG_M5235EVB) := M5235EVB
-board-$(CONFIG_M5271EVB) := M5271EVB
-board-$(CONFIG_M5275EVB) := M5275EVB
-board-$(CONFIG_M5282EVB) := M5282EVB
-board-$(CONFIG_ELITE) := eLITE
-board-$(CONFIG_NETtel) := NETtel
-board-$(CONFIG_SECUREEDGEMP3) := MP3
-board-$(CONFIG_CLEOPATRA) := CLEOPATRA
-board-$(CONFIG_senTec) := senTec
-board-$(CONFIG_SNEHA) := SNEHA
-board-$(CONFIG_M5208EVB) := M5208EVB
-board-$(CONFIG_MOD5272) := MOD5272
-board-$(CONFIG_AVNET) := AVNET
-board-$(CONFIG_SAVANT) := SAVANT
-BOARD := $(board-y)
-
-model-$(CONFIG_RAMKERNEL) := ram
-model-$(CONFIG_ROMKERNEL) := rom
-MODEL := $(model-y)
-
-#
-# Some code support is grouped together for a common cpu-subclass (for
-# example all ColdFire cpu's are very similar). Determine the sub-class
-# for the selected cpu. ONLY need to define this for the non-base member
-# of the family.
-#
-cpuclass-$(CONFIG_M5206) := coldfire
-cpuclass-$(CONFIG_M5206e) := coldfire
-cpuclass-$(CONFIG_M520x) := coldfire
-cpuclass-$(CONFIG_M523x) := coldfire
-cpuclass-$(CONFIG_M5249) := coldfire
-cpuclass-$(CONFIG_M527x) := coldfire
-cpuclass-$(CONFIG_M5272) := coldfire
-cpuclass-$(CONFIG_M528x) := coldfire
-cpuclass-$(CONFIG_M5307) := coldfire
-cpuclass-$(CONFIG_M532x) := coldfire
-cpuclass-$(CONFIG_M5407) := coldfire
-cpuclass-$(CONFIG_M54xx) := coldfire
-cpuclass-$(CONFIG_M68328) := 68328
-cpuclass-$(CONFIG_M68EZ328) := 68328
-cpuclass-$(CONFIG_M68VZ328) := 68328
-cpuclass-$(CONFIG_M68360) := 68360
-CPUCLASS := $(cpuclass-y)
-
-ifneq ($(CPUCLASS),$(PLATFORM))
-CLASSDIR := arch/m68k/platform/$(cpuclass-y)/
-endif
-
-export PLATFORM BOARD MODEL CPUCLASS
-
-#
-# Some CFLAG additions based on specific CPU type.
-#
-cflags-$(CONFIG_M5206) := $(call cc-option,-mcpu=5206,-m5200)
-cflags-$(CONFIG_M5206e) := $(call cc-option,-mcpu=5206e,-m5200)
-cflags-$(CONFIG_M520x) := $(call cc-option,-mcpu=5208,-m5200)
-cflags-$(CONFIG_M523x) := $(call cc-option,-mcpu=523x,-m5307)
-cflags-$(CONFIG_M5249) := $(call cc-option,-mcpu=5249,-m5200)
-cflags-$(CONFIG_M5271) := $(call cc-option,-mcpu=5271,-m5307)
-cflags-$(CONFIG_M5272) := $(call cc-option,-mcpu=5272,-m5307)
-cflags-$(CONFIG_M5275) := $(call cc-option,-mcpu=5275,-m5307)
-cflags-$(CONFIG_M528x) := $(call cc-option,-mcpu=528x,-m5307)
-cflags-$(CONFIG_M5307) := $(call cc-option,-mcpu=5307,-m5200)
-cflags-$(CONFIG_M532x) := $(call cc-option,-mcpu=532x,-m5307)
-cflags-$(CONFIG_M5407) := $(call cc-option,-mcpu=5407,-m5200)
-cflags-$(CONFIG_M54xx) := $(call cc-option,-mcpu=5475,-m5200)
-cflags-$(CONFIG_M68328) := -m68000
-cflags-$(CONFIG_M68EZ328) := -m68000
-cflags-$(CONFIG_M68VZ328) := -m68000
-cflags-$(CONFIG_M68360) := -m68332
-
-KBUILD_AFLAGS += $(cflags-y)
-
-KBUILD_CFLAGS += $(cflags-y)
-KBUILD_CFLAGS += -D__linux__
-KBUILD_CFLAGS += -DUTS_SYSNAME=\"uClinux\"
-
-head-y := arch/m68k/platform/$(cpuclass-y)/head.o
-
-core-y += arch/m68k/kernel/ \
- arch/m68k/mm/ \
- $(CLASSDIR) \
- arch/m68k/platform/$(PLATFORM)/
-libs-y += arch/m68k/lib/
-
-archclean:
-
diff --git a/arch/m68k/include/asm/entry.h b/arch/m68k/include/asm/entry.h
index 876eec6f2b52..c3c5a8643e15 100644
--- a/arch/m68k/include/asm/entry.h
+++ b/arch/m68k/include/asm/entry.h
@@ -1,5 +1,254 @@
-#ifdef __uClinux__
-#include "entry_no.h"
+#ifndef __M68K_ENTRY_H
+#define __M68K_ENTRY_H
+
+#include <asm/setup.h>
+#include <asm/page.h>
+#ifdef __ASSEMBLY__
+#include <asm/thread_info.h>
+#endif
+
+/*
+ * Stack layout in 'ret_from_exception':
+ *
+ * This allows access to the syscall arguments in registers d1-d5
+ *
+ * 0(sp) - d1
+ * 4(sp) - d2
+ * 8(sp) - d3
+ * C(sp) - d4
+ * 10(sp) - d5
+ * 14(sp) - a0
+ * 18(sp) - a1
+ * 1C(sp) - a2
+ * 20(sp) - d0
+ * 24(sp) - orig_d0
+ * 28(sp) - stack adjustment
+ * 2C(sp) - [ sr ] [ format & vector ]
+ * 2E(sp) - [ pc-hiword ] [ sr ]
+ * 30(sp) - [ pc-loword ] [ pc-hiword ]
+ * 32(sp) - [ format & vector ] [ pc-loword ]
+ * ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^
+ * M68K COLDFIRE
+ */
+
+/* the following macro is used when enabling interrupts */
+#if defined(MACH_ATARI_ONLY)
+ /* block out HSYNC on the atari */
+#define ALLOWINT (~0x400)
+#define MAX_NOINT_IPL 3
#else
-#include "entry_mm.h"
+ /* portable version */
+#define ALLOWINT (~0x700)
+#define MAX_NOINT_IPL 0
+#endif /* machine compilation types */
+
+#ifdef __ASSEMBLY__
+/*
+ * This defines the normal kernel pt-regs layout.
+ *
+ * regs a3-a6 and d6-d7 are preserved by C code
+ * the kernel doesn't mess with usp unless it needs to
+ */
+#define SWITCH_STACK_SIZE (6*4+4) /* includes return address */
+
+#ifdef CONFIG_COLDFIRE
+#ifdef CONFIG_COLDFIRE_SW_A7
+/*
+ * This is made a little more tricky on older ColdFires. There is no
+ * separate supervisor and user stack pointers. Need to artificially
+ * construct a usp in software... When doing this we need to disable
+ * interrupts, otherwise bad things will happen.
+ */
+.globl sw_usp
+.globl sw_ksp
+
+.macro SAVE_ALL_SYS
+ move #0x2700,%sr /* disable intrs */
+ btst #5,%sp@(2) /* from user? */
+ bnes 6f /* no, skip */
+ movel %sp,sw_usp /* save user sp */
+ addql #8,sw_usp /* remove exception */
+ movel sw_ksp,%sp /* kernel sp */
+ subql #8,%sp /* room for exception */
+ clrl %sp@- /* stkadj */
+ movel %d0,%sp@- /* orig d0 */
+ movel %d0,%sp@- /* d0 */
+ lea %sp@(-32),%sp /* space for 8 regs */
+ moveml %d1-%d5/%a0-%a2,%sp@
+ movel sw_usp,%a0 /* get usp */
+ movel %a0@-,%sp@(PT_OFF_PC) /* copy exception program counter */
+ movel %a0@-,%sp@(PT_OFF_FORMATVEC)/*copy exception format/vector/sr */
+ bra 7f
+ 6:
+ clrl %sp@- /* stkadj */
+ movel %d0,%sp@- /* orig d0 */
+ movel %d0,%sp@- /* d0 */
+ lea %sp@(-32),%sp /* space for 8 regs */
+ moveml %d1-%d5/%a0-%a2,%sp@
+ 7:
+.endm
+
+.macro SAVE_ALL_INT
+ SAVE_ALL_SYS
+ moveq #-1,%d0 /* not system call entry */
+ movel %d0,%sp@(PT_OFF_ORIG_D0)
+.endm
+
+.macro RESTORE_USER
+ move #0x2700,%sr /* disable intrs */
+ movel sw_usp,%a0 /* get usp */
+ movel %sp@(PT_OFF_PC),%a0@- /* copy exception program counter */
+ movel %sp@(PT_OFF_FORMATVEC),%a0@-/*copy exception format/vector/sr */
+ moveml %sp@,%d1-%d5/%a0-%a2
+ lea %sp@(32),%sp /* space for 8 regs */
+ movel %sp@+,%d0
+ addql #4,%sp /* orig d0 */
+ addl %sp@+,%sp /* stkadj */
+ addql #8,%sp /* remove exception */
+ movel %sp,sw_ksp /* save ksp */
+ subql #8,sw_usp /* set exception */
+ movel sw_usp,%sp /* restore usp */
+ rte
+.endm
+
+.macro RDUSP
+ movel sw_usp,%a3
+.endm
+
+.macro WRUSP
+ movel %a3,sw_usp
+.endm
+
+#else /* !CONFIG_COLDFIRE_SW_A7 */
+/*
+ * Modern ColdFire parts have separate supervisor and user stack
+ * pointers. Simple load and restore macros for this case.
+ */
+.macro SAVE_ALL_SYS
+ move #0x2700,%sr /* disable intrs */
+ clrl %sp@- /* stkadj */
+ movel %d0,%sp@- /* orig d0 */
+ movel %d0,%sp@- /* d0 */
+ lea %sp@(-32),%sp /* space for 8 regs */
+ moveml %d1-%d5/%a0-%a2,%sp@
+.endm
+
+.macro SAVE_ALL_INT
+ move #0x2700,%sr /* disable intrs */
+ clrl %sp@- /* stkadj */
+ pea -1:w /* orig d0 */
+ movel %d0,%sp@- /* d0 */
+ lea %sp@(-32),%sp /* space for 8 regs */
+ moveml %d1-%d5/%a0-%a2,%sp@
+.endm
+
+.macro RESTORE_USER
+ moveml %sp@,%d1-%d5/%a0-%a2
+ lea %sp@(32),%sp /* space for 8 regs */
+ movel %sp@+,%d0
+ addql #4,%sp /* orig d0 */
+ addl %sp@+,%sp /* stkadj */
+ rte
+.endm
+
+.macro RDUSP
+ /*move %usp,%a3*/
+ .word 0x4e6b
+.endm
+
+.macro WRUSP
+ /*move %a3,%usp*/
+ .word 0x4e63
+.endm
+
+#endif /* !CONFIG_COLDFIRE_SW_A7 */
+
+.macro SAVE_SWITCH_STACK
+ lea %sp@(-24),%sp /* 6 regs */
+ moveml %a3-%a6/%d6-%d7,%sp@
+.endm
+
+.macro RESTORE_SWITCH_STACK
+ moveml %sp@,%a3-%a6/%d6-%d7
+ lea %sp@(24),%sp /* 6 regs */
+.endm
+
+#else /* !CONFIG_COLDFIRE */
+
+/*
+ * All other types of m68k parts (68000, 680x0, CPU32) have the same
+ * entry and exit code.
+ */
+
+/*
+ * a -1 in the orig_d0 field signifies
+ * that the stack frame is NOT for syscall
+ */
+.macro SAVE_ALL_INT
+ clrl %sp@- /* stk_adj */
+ pea -1:w /* orig d0 */
+ movel %d0,%sp@- /* d0 */
+ moveml %d1-%d5/%a0-%a2,%sp@-
+.endm
+
+.macro SAVE_ALL_SYS
+ clrl %sp@- /* stk_adj */
+ movel %d0,%sp@- /* orig d0 */
+ movel %d0,%sp@- /* d0 */
+ moveml %d1-%d5/%a0-%a2,%sp@-
+.endm
+
+.macro RESTORE_ALL
+ moveml %sp@+,%a0-%a2/%d1-%d5
+ movel %sp@+,%d0
+ addql #4,%sp /* orig d0 */
+ addl %sp@+,%sp /* stk adj */
+ rte
+.endm
+
+
+.macro SAVE_SWITCH_STACK
+ moveml %a3-%a6/%d6-%d7,%sp@-
+.endm
+
+.macro RESTORE_SWITCH_STACK
+ moveml %sp@+,%a3-%a6/%d6-%d7
+.endm
+
+#endif /* !CONFIG_COLDFIRE */
+
+/*
+ * Register %a2 is reserved and set to current task on MMU enabled systems.
+ * Non-MMU systems do not reserve %a2 in this way, and this definition is
+ * not used for them.
+ */
+#define curptr a2
+
+#define GET_CURRENT(tmp) get_current tmp
+.macro get_current reg=%d0
+ movel %sp,\reg
+ andw #-THREAD_SIZE,\reg
+ movel \reg,%curptr
+ movel %curptr@,%curptr
+.endm
+
+#else /* C source */
+
+#define STR(X) STR1(X)
+#define STR1(X) #X
+
+#define SAVE_ALL_INT \
+ "clrl %%sp@-;" /* stk_adj */ \
+ "pea -1:w;" /* orig d0 = -1 */ \
+ "movel %%d0,%%sp@-;" /* d0 */ \
+ "moveml %%d1-%%d5/%%a0-%%a2,%%sp@-"
+
+#define GET_CURRENT(tmp) \
+ "movel %%sp,"#tmp"\n\t" \
+ "andw #-"STR(THREAD_SIZE)","#tmp"\n\t" \
+ "movel "#tmp",%%a2\n\t" \
+ "movel %%a2@,%%a2"
+
#endif
+
+#endif /* __M68K_ENTRY_H */
diff --git a/arch/m68k/include/asm/entry_mm.h b/arch/m68k/include/asm/entry_mm.h
deleted file mode 100644
index 73b8c8fbed9c..000000000000
--- a/arch/m68k/include/asm/entry_mm.h
+++ /dev/null
@@ -1,128 +0,0 @@
-#ifndef __M68K_ENTRY_H
-#define __M68K_ENTRY_H
-
-#include <asm/setup.h>
-#include <asm/page.h>
-#ifdef __ASSEMBLY__
-#include <asm/thread_info.h>
-#endif
-
-/*
- * Stack layout in 'ret_from_exception':
- *
- * This allows access to the syscall arguments in registers d1-d5
- *
- * 0(sp) - d1
- * 4(sp) - d2
- * 8(sp) - d3
- * C(sp) - d4
- * 10(sp) - d5
- * 14(sp) - a0
- * 18(sp) - a1
- * 1C(sp) - a2
- * 20(sp) - d0
- * 24(sp) - orig_d0
- * 28(sp) - stack adjustment
- * 2C(sp) - sr
- * 2E(sp) - pc
- * 32(sp) - format & vector
- */
-
-/*
- * 97/05/14 Andreas: Register %a2 is now set to the current task throughout
- * the whole kernel.
- */
-
-/* the following macro is used when enabling interrupts */
-#if defined(MACH_ATARI_ONLY)
- /* block out HSYNC on the atari */
-#define ALLOWINT (~0x400)
-#define MAX_NOINT_IPL 3
-#else
- /* portable version */
-#define ALLOWINT (~0x700)
-#define MAX_NOINT_IPL 0
-#endif /* machine compilation types */
-
-#ifdef __ASSEMBLY__
-
-#define curptr a2
-
-LFLUSH_I_AND_D = 0x00000808
-
-#define SAVE_ALL_INT save_all_int
-#define SAVE_ALL_SYS save_all_sys
-#define RESTORE_ALL restore_all
-/*
- * This defines the normal kernel pt-regs layout.
- *
- * regs a3-a6 and d6-d7 are preserved by C code
- * the kernel doesn't mess with usp unless it needs to
- */
-
-/*
- * a -1 in the orig_d0 field signifies
- * that the stack frame is NOT for syscall
- */
-.macro save_all_int
- clrl %sp@- | stk_adj
- pea -1:w | orig d0
- movel %d0,%sp@- | d0
- moveml %d1-%d5/%a0-%a1/%curptr,%sp@-
-.endm
-
-.macro save_all_sys
- clrl %sp@- | stk_adj
- movel %d0,%sp@- | orig d0
- movel %d0,%sp@- | d0
- moveml %d1-%d5/%a0-%a1/%curptr,%sp@-
-.endm
-
-.macro restore_all
- moveml %sp@+,%a0-%a1/%curptr/%d1-%d5
- movel %sp@+,%d0
- addql #4,%sp | orig d0
- addl %sp@+,%sp | stk adj
- rte
-.endm
-
-#define SWITCH_STACK_SIZE (6*4+4) /* includes return address */
-
-#define SAVE_SWITCH_STACK save_switch_stack
-#define RESTORE_SWITCH_STACK restore_switch_stack
-#define GET_CURRENT(tmp) get_current tmp
-
-.macro save_switch_stack
- moveml %a3-%a6/%d6-%d7,%sp@-
-.endm
-
-.macro restore_switch_stack
- moveml %sp@+,%a3-%a6/%d6-%d7
-.endm
-
-.macro get_current reg=%d0
- movel %sp,\reg
- andw #-THREAD_SIZE,\reg
- movel \reg,%curptr
- movel %curptr@,%curptr
-.endm
-
-#else /* C source */
-
-#define STR(X) STR1(X)
-#define STR1(X) #X
-
-#define SAVE_ALL_INT \
- "clrl %%sp@-;" /* stk_adj */ \
- "pea -1:w;" /* orig d0 = -1 */ \
- "movel %%d0,%%sp@-;" /* d0 */ \
- "moveml %%d1-%%d5/%%a0-%%a2,%%sp@-"
-#define GET_CURRENT(tmp) \
- "movel %%sp,"#tmp"\n\t" \
- "andw #-"STR(THREAD_SIZE)","#tmp"\n\t" \
- "movel "#tmp",%%a2\n\t" \
- "movel %%a2@,%%a2"
-
-#endif
-
-#endif /* __M68K_ENTRY_H */
diff --git a/arch/m68k/include/asm/entry_no.h b/arch/m68k/include/asm/entry_no.h
deleted file mode 100644
index 68611e3dbb1d..000000000000
--- a/arch/m68k/include/asm/entry_no.h
+++ /dev/null
@@ -1,181 +0,0 @@
-#ifndef __M68KNOMMU_ENTRY_H
-#define __M68KNOMMU_ENTRY_H
-
-#include <asm/setup.h>
-#include <asm/page.h>
-
-/*
- * Stack layout in 'ret_from_exception':
- *
- * This allows access to the syscall arguments in registers d1-d5
- *
- * 0(sp) - d1
- * 4(sp) - d2
- * 8(sp) - d3
- * C(sp) - d4
- * 10(sp) - d5
- * 14(sp) - a0
- * 18(sp) - a1
- * 1C(sp) - a2
- * 20(sp) - d0
- * 24(sp) - orig_d0
- * 28(sp) - stack adjustment
- * 2C(sp) - [ sr ] [ format & vector ]
- * 2E(sp) - [ pc-hiword ] [ sr ]
- * 30(sp) - [ pc-loword ] [ pc-hiword ]
- * 32(sp) - [ format & vector ] [ pc-loword ]
- * ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^
- * M68K COLDFIRE
- */
-
-#define ALLOWINT (~0x700)
-
-#ifdef __ASSEMBLY__
-
-#define SWITCH_STACK_SIZE (6*4+4) /* Includes return address */
-
-/*
- * This defines the normal kernel pt-regs layout.
- *
- * regs are a2-a6 and d6-d7 preserved by C code
- * the kernel doesn't mess with usp unless it needs to
- */
-
-#ifdef CONFIG_COLDFIRE
-#ifdef CONFIG_COLDFIRE_SW_A7
-/*
- * This is made a little more tricky on older ColdFires. There is no
- * separate supervisor and user stack pointers. Need to artificially
- * construct a usp in software... When doing this we need to disable
- * interrupts, otherwise bad things will happen.
- */
-.globl sw_usp
-.globl sw_ksp
-
-.macro SAVE_ALL
- move #0x2700,%sr /* disable intrs */
- btst #5,%sp@(2) /* from user? */
- bnes 6f /* no, skip */
- movel %sp,sw_usp /* save user sp */
- addql #8,sw_usp /* remove exception */
- movel sw_ksp,%sp /* kernel sp */
- subql #8,%sp /* room for exception */
- clrl %sp@- /* stkadj */
- movel %d0,%sp@- /* orig d0 */
- movel %d0,%sp@- /* d0 */
- lea %sp@(-32),%sp /* space for 8 regs */
- moveml %d1-%d5/%a0-%a2,%sp@
- movel sw_usp,%a0 /* get usp */
- movel %a0@-,%sp@(PT_OFF_PC) /* copy exception program counter */
- movel %a0@-,%sp@(PT_OFF_FORMATVEC)/*copy exception format/vector/sr */
- bra 7f
- 6:
- clrl %sp@- /* stkadj */
- movel %d0,%sp@- /* orig d0 */
- movel %d0,%sp@- /* d0 */
- lea %sp@(-32),%sp /* space for 8 regs */
- moveml %d1-%d5/%a0-%a2,%sp@
- 7:
-.endm
-
-.macro RESTORE_USER
- move #0x2700,%sr /* disable intrs */
- movel sw_usp,%a0 /* get usp */
- movel %sp@(PT_OFF_PC),%a0@- /* copy exception program counter */
- movel %sp@(PT_OFF_FORMATVEC),%a0@-/*copy exception format/vector/sr */
- moveml %sp@,%d1-%d5/%a0-%a2
- lea %sp@(32),%sp /* space for 8 regs */
- movel %sp@+,%d0
- addql #4,%sp /* orig d0 */
- addl %sp@+,%sp /* stkadj */
- addql #8,%sp /* remove exception */
- movel %sp,sw_ksp /* save ksp */
- subql #8,sw_usp /* set exception */
- movel sw_usp,%sp /* restore usp */
- rte
-.endm
-
-.macro RDUSP
- movel sw_usp,%a3
-.endm
-
-.macro WRUSP
- movel %a3,sw_usp
-.endm
-
-#else /* !CONFIG_COLDFIRE_SW_A7 */
-/*
- * Modern ColdFire parts have separate supervisor and user stack
- * pointers. Simple load and restore macros for this case.
- */
-.macro SAVE_ALL
- move #0x2700,%sr /* disable intrs */
- clrl %sp@- /* stkadj */
- movel %d0,%sp@- /* orig d0 */
- movel %d0,%sp@- /* d0 */
- lea %sp@(-32),%sp /* space for 8 regs */
- moveml %d1-%d5/%a0-%a2,%sp@
-.endm
-
-.macro RESTORE_USER
- moveml %sp@,%d1-%d5/%a0-%a2
- lea %sp@(32),%sp /* space for 8 regs */
- movel %sp@+,%d0
- addql #4,%sp /* orig d0 */
- addl %sp@+,%sp /* stkadj */
- rte
-.endm
-
-.macro RDUSP
- /*move %usp,%a3*/
- .word 0x4e6b
-.endm
-
-.macro WRUSP
- /*move %a3,%usp*/
- .word 0x4e63
-.endm
-
-#endif /* !CONFIG_COLDFIRE_SW_A7 */
-
-.macro SAVE_SWITCH_STACK
- lea %sp@(-24),%sp /* 6 regs */
- moveml %a3-%a6/%d6-%d7,%sp@
-.endm
-
-.macro RESTORE_SWITCH_STACK
- moveml %sp@,%a3-%a6/%d6-%d7
- lea %sp@(24),%sp /* 6 regs */
-.endm
-
-#else /* !CONFIG_COLDFIRE */
-
-/*
- * Standard 68k interrupt entry and exit macros.
- */
-.macro SAVE_ALL
- clrl %sp@- /* stkadj */
- movel %d0,%sp@- /* orig d0 */
- movel %d0,%sp@- /* d0 */
- moveml %d1-%d5/%a0-%a2,%sp@-
-.endm
-
-.macro RESTORE_ALL
- moveml %sp@+,%a0-%a2/%d1-%d5
- movel %sp@+,%d0
- addql #4,%sp /* orig d0 */
- addl %sp@+,%sp /* stkadj */
- rte
-.endm
-
-.macro SAVE_SWITCH_STACK
- moveml %a3-%a6/%d6-%d7,%sp@-
-.endm
-
-.macro RESTORE_SWITCH_STACK
- moveml %sp@+,%a3-%a6/%d6-%d7
-.endm
-
-#endif /* !COLDFIRE_SW_A7 */
-#endif /* __ASSEMBLY__ */
-#endif /* __M68KNOMMU_ENTRY_H */
diff --git a/arch/m68k/include/asm/m520xsim.h b/arch/m68k/include/asm/m520xsim.h
index b6bf2c518bac..eda62de7e607 100644
--- a/arch/m68k/include/asm/m520xsim.h
+++ b/arch/m68k/include/asm/m520xsim.h
@@ -90,15 +90,13 @@
#define MCFGPIO_PDDR_FECH 0xFC0A4013
#define MCFGPIO_PDDR_FECL 0xFC0A4014
-#define MCFGPIO_PPDSDR_BUSCTL 0xFC0A401A
-#define MCFGPIO_PPDSDR_BE 0xFC0A401B
-#define MCFGPIO_PPDSDR_CS 0xFC0A401C
-#define MCFGPIO_PPDSDR_FECI2C 0xFC0A401D
-#define MCFGPIO_PPDSDR_QSPI 0xFC0A401E
-#define MCFGPIO_PPDSDR_TIMER 0xFC0A401F
-#define MCFGPIO_PPDSDR_UART 0xFC0A4021
-#define MCFGPIO_PPDSDR_FECH 0xFC0A4021
-#define MCFGPIO_PPDSDR_FECL 0xFC0A4022
+#define MCFGPIO_PPDSDR_CS 0xFC0A401A
+#define MCFGPIO_PPDSDR_FECI2C 0xFC0A401B
+#define MCFGPIO_PPDSDR_QSPI 0xFC0A401C
+#define MCFGPIO_PPDSDR_TIMER 0xFC0A401D
+#define MCFGPIO_PPDSDR_UART 0xFC0A401E
+#define MCFGPIO_PPDSDR_FECH 0xFC0A401F
+#define MCFGPIO_PPDSDR_FECL 0xFC0A4020
#define MCFGPIO_PCLRR_BUSCTL 0xFC0A4024
#define MCFGPIO_PCLRR_BE 0xFC0A4025
@@ -113,11 +111,11 @@
/*
* Generic GPIO support
*/
-#define MCFGPIO_PODR MCFGPIO_PODR_BUSCTL
-#define MCFGPIO_PDDR MCFGPIO_PDDR_BUSCTL
-#define MCFGPIO_PPDR MCFGPIO_PPDSDR_BUSCTL
-#define MCFGPIO_SETR MCFGPIO_PPDSDR_BUSCTL
-#define MCFGPIO_CLRR MCFGPIO_PCLRR_BUSCTL
+#define MCFGPIO_PODR MCFGPIO_PODR_CS
+#define MCFGPIO_PDDR MCFGPIO_PDDR_CS
+#define MCFGPIO_PPDR MCFGPIO_PPDSDR_CS
+#define MCFGPIO_SETR MCFGPIO_PPDSDR_CS
+#define MCFGPIO_CLRR MCFGPIO_PCLRR_CS
#define MCFGPIO_PIN_MAX 80
#define MCFGPIO_IRQ_MAX 8
diff --git a/arch/m68k/include/asm/mcfqspi.h b/arch/m68k/include/asm/mcfqspi.h
index 39d90d51111d..7fe631972f1f 100644
--- a/arch/m68k/include/asm/mcfqspi.h
+++ b/arch/m68k/include/asm/mcfqspi.h
@@ -24,9 +24,11 @@
#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
#define MCFQSPI_IOBASE (MCF_IPSBAR + 0x340)
#elif defined(CONFIG_M5249)
-#define MCFQSPI_IOBASE (MCF_MBAR + 0x300)
-#elif defined(CONFIG_M520x) || defined(CONFIG_M532x)
-#define MCFQSPI_IOBASE 0xFC058000
+#define MCFQSPI_IOBASE (MCF_MBAR + 0x300)
+#elif defined(CONFIG_M520x)
+#define MCFQSPI_IOBASE 0xFC05C000
+#elif defined(CONFIG_M532x)
+#define MCFQSPI_IOBASE 0xFC058000
#endif
#define MCFQSPI_IOSIZE 0x40
diff --git a/arch/m68k/include/asm/page_mm.h b/arch/m68k/include/asm/page_mm.h
index 31d5570d6567..89f201434b5a 100644
--- a/arch/m68k/include/asm/page_mm.h
+++ b/arch/m68k/include/asm/page_mm.h
@@ -162,7 +162,7 @@ static inline __attribute_const__ int __virt_to_node_shift(void)
pgdat->node_mem_map + (__pfn - pgdat->node_start_pfn); \
})
#define page_to_pfn(_page) ({ \
- struct page *__p = (_page); \
+ const struct page *__p = (_page); \
struct pglist_data *pgdat; \
pgdat = &pg_data_map[page_to_nid(__p)]; \
((__p) - pgdat->node_mem_map) + pgdat->node_start_pfn; \
diff --git a/arch/m68k/include/asm/page_no.h b/arch/m68k/include/asm/page_no.h
index 90595721185f..a8d1c60eb9ce 100644
--- a/arch/m68k/include/asm/page_no.h
+++ b/arch/m68k/include/asm/page_no.h
@@ -5,6 +5,9 @@
extern unsigned long memory_start;
extern unsigned long memory_end;
+extern unsigned long _rambase;
+extern unsigned long _ramstart;
+extern unsigned long _ramend;
#define get_user_page(vaddr) __get_free_page(GFP_KERNEL)
#define free_user_page(page, addr) free_page(addr)
diff --git a/arch/m68k/include/asm/processor.h b/arch/m68k/include/asm/processor.h
index d8ef53ac03f9..568facf30276 100644
--- a/arch/m68k/include/asm/processor.h
+++ b/arch/m68k/include/asm/processor.h
@@ -135,6 +135,12 @@ do { \
wrusp(_usp); \
} while(0)
+static inline int handle_kernel_fault(struct pt_regs *regs)
+{
+ /* Any fault in kernel is fatal on non-mmu */
+ return 0;
+}
+
#endif
/* Forward declaration, a strange C thing */
diff --git a/arch/m68k/include/asm/sections.h b/arch/m68k/include/asm/sections.h
index d64967ecfec6..5277e52715ec 100644
--- a/arch/m68k/include/asm/sections.h
+++ b/arch/m68k/include/asm/sections.h
@@ -3,4 +3,6 @@
#include <asm-generic/sections.h>
+extern char _sbss[], _ebss[];
+
#endif /* _ASM_M68K_SECTIONS_H */
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile
index c482ebc9dd54..e7f0f2e5ad44 100644
--- a/arch/m68k/kernel/Makefile
+++ b/arch/m68k/kernel/Makefile
@@ -1,5 +1,21 @@
-ifdef CONFIG_MMU
-include arch/m68k/kernel/Makefile_mm
-else
-include arch/m68k/kernel/Makefile_no
+#
+# Makefile for the linux kernel.
+#
+
+extra-$(CONFIG_MMU) := head.o
+extra-$(CONFIG_SUN3) := sun3-head.o
+extra-y += vmlinux.lds
+
+obj-y := entry.o m68k_ksyms.o module.o process.o ptrace.o setup.o signal.o \
+ sys_m68k.o syscalltable.o time.o traps.o
+
+obj-$(CONFIG_MMU) += ints.o devres.o vectors.o
+devres-$(CONFIG_MMU) = ../../../kernel/irq/devres.o
+
+ifndef CONFIG_MMU_SUN3
+obj-y += dma.o
endif
+ifndef CONFIG_MMU
+obj-y += init_task.o irq.o
+endif
+
diff --git a/arch/m68k/kernel/Makefile_mm b/arch/m68k/kernel/Makefile_mm
deleted file mode 100644
index aced67804579..000000000000
--- a/arch/m68k/kernel/Makefile_mm
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-
-ifndef CONFIG_SUN3
- extra-y := head.o
-else
- extra-y := sun3-head.o
-endif
-extra-y += vmlinux.lds
-
-obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o module.o \
- sys_m68k.o time.o setup.o m68k_ksyms.o devres.o syscalltable.o
-
-devres-y = ../../../kernel/irq/devres.o
-
-obj-y$(CONFIG_MMU_SUN3) += dma.o # no, it's not a typo
diff --git a/arch/m68k/kernel/Makefile_no b/arch/m68k/kernel/Makefile_no
deleted file mode 100644
index 37c3fc074c0a..000000000000
--- a/arch/m68k/kernel/Makefile_no
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Makefile for arch/m68knommu/kernel.
-#
-
-extra-y := vmlinux.lds
-
-obj-y += dma.o entry.o init_task.o irq.o m68k_ksyms.o process.o ptrace.o \
- setup.o signal.o syscalltable.o sys_m68k.o time.o traps.o
-
-obj-$(CONFIG_MODULES) += module.o
diff --git a/arch/m68k/kernel/entry_no.S b/arch/m68k/kernel/entry_no.S
index 5f0f6b598b5a..1b4289061a64 100644
--- a/arch/m68k/kernel/entry_no.S
+++ b/arch/m68k/kernel/entry_no.S
@@ -43,7 +43,7 @@
.globl sys_vfork
ENTRY(buserr)
- SAVE_ALL
+ SAVE_ALL_INT
moveq #-1,%d0
movel %d0,%sp@(PT_OFF_ORIG_D0)
movel %sp,%sp@- /* stack frame pointer argument */
@@ -52,7 +52,7 @@ ENTRY(buserr)
jra ret_from_exception
ENTRY(trap)
- SAVE_ALL
+ SAVE_ALL_INT
moveq #-1,%d0
movel %d0,%sp@(PT_OFF_ORIG_D0)
movel %sp,%sp@- /* stack frame pointer argument */
@@ -64,7 +64,7 @@ ENTRY(trap)
.globl dbginterrupt
ENTRY(dbginterrupt)
- SAVE_ALL
+ SAVE_ALL_INT
moveq #-1,%d0
movel %d0,%sp@(PT_OFF_ORIG_D0)
movel %sp,%sp@- /* stack frame pointer argument */
diff --git a/arch/m68k/kernel/setup_no.c b/arch/m68k/kernel/setup_no.c
index 16b2de7f5101..2ed8c0fb1517 100644
--- a/arch/m68k/kernel/setup_no.c
+++ b/arch/m68k/kernel/setup_no.c
@@ -36,6 +36,7 @@
#include <asm/irq.h>
#include <asm/machdep.h>
#include <asm/pgtable.h>
+#include <asm/sections.h>
unsigned long memory_start;
unsigned long memory_end;
@@ -80,9 +81,6 @@ void (*mach_power_off)(void);
#define CPU_INSTR_PER_JIFFY 16
#endif
-extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end;
-extern int _ramstart, _ramend;
-
#if defined(CONFIG_UBOOT)
/*
* parse_uboot_commandline
diff --git a/arch/m68k/kernel/syscalltable.S b/arch/m68k/kernel/syscalltable.S
index 00d1452f9571..c468f2edaa85 100644
--- a/arch/m68k/kernel/syscalltable.S
+++ b/arch/m68k/kernel/syscalltable.S
@@ -189,7 +189,7 @@ ENTRY(sys_call_table)
.long sys_getpagesize
.long sys_ni_syscall /* old "query_module" */
.long sys_poll
- .long sys_nfsservctl
+ .long sys_ni_syscall /* old nfsservctl */
.long sys_setresgid16 /* 170 */
.long sys_getresgid16
.long sys_prctl
diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c
index c98add3f5f0f..89362f2bb56a 100644
--- a/arch/m68k/kernel/traps.c
+++ b/arch/m68k/kernel/traps.c
@@ -1,5 +1,1107 @@
-#ifdef CONFIG_MMU
-#include "traps_mm.c"
+/*
+ * linux/arch/m68k/kernel/traps.c
+ *
+ * Copyright (C) 1993, 1994 by Hamish Macdonald
+ *
+ * 68040 fixes by Michael Rausch
+ * 68040 fixes by Martin Apel
+ * 68040 fixes and writeback by Richard Zidlicky
+ * 68060 fixes by Roman Hodek
+ * 68060 fixes by Jesper Skov
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+/*
+ * Sets up all exception vectors
+ */
+
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/user.h>
+#include <linux/string.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <linux/ptrace.h>
+#include <linux/kallsyms.h>
+
+#include <asm/setup.h>
+#include <asm/fpu.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/traps.h>
+#include <asm/pgalloc.h>
+#include <asm/machdep.h>
+#include <asm/siginfo.h>
+
+
+static const char *vec_names[] = {
+ [VEC_RESETSP] = "RESET SP",
+ [VEC_RESETPC] = "RESET PC",
+ [VEC_BUSERR] = "BUS ERROR",
+ [VEC_ADDRERR] = "ADDRESS ERROR",
+ [VEC_ILLEGAL] = "ILLEGAL INSTRUCTION",
+ [VEC_ZERODIV] = "ZERO DIVIDE",
+ [VEC_CHK] = "CHK",
+ [VEC_TRAP] = "TRAPcc",
+ [VEC_PRIV] = "PRIVILEGE VIOLATION",
+ [VEC_TRACE] = "TRACE",
+ [VEC_LINE10] = "LINE 1010",
+ [VEC_LINE11] = "LINE 1111",
+ [VEC_RESV12] = "UNASSIGNED RESERVED 12",
+ [VEC_COPROC] = "COPROCESSOR PROTOCOL VIOLATION",
+ [VEC_FORMAT] = "FORMAT ERROR",
+ [VEC_UNINT] = "UNINITIALIZED INTERRUPT",
+ [VEC_RESV16] = "UNASSIGNED RESERVED 16",
+ [VEC_RESV17] = "UNASSIGNED RESERVED 17",
+ [VEC_RESV18] = "UNASSIGNED RESERVED 18",
+ [VEC_RESV19] = "UNASSIGNED RESERVED 19",
+ [VEC_RESV20] = "UNASSIGNED RESERVED 20",
+ [VEC_RESV21] = "UNASSIGNED RESERVED 21",
+ [VEC_RESV22] = "UNASSIGNED RESERVED 22",
+ [VEC_RESV23] = "UNASSIGNED RESERVED 23",
+ [VEC_SPUR] = "SPURIOUS INTERRUPT",
+ [VEC_INT1] = "LEVEL 1 INT",
+ [VEC_INT2] = "LEVEL 2 INT",
+ [VEC_INT3] = "LEVEL 3 INT",
+ [VEC_INT4] = "LEVEL 4 INT",
+ [VEC_INT5] = "LEVEL 5 INT",
+ [VEC_INT6] = "LEVEL 6 INT",
+ [VEC_INT7] = "LEVEL 7 INT",
+ [VEC_SYS] = "SYSCALL",
+ [VEC_TRAP1] = "TRAP #1",
+ [VEC_TRAP2] = "TRAP #2",
+ [VEC_TRAP3] = "TRAP #3",
+ [VEC_TRAP4] = "TRAP #4",
+ [VEC_TRAP5] = "TRAP #5",
+ [VEC_TRAP6] = "TRAP #6",
+ [VEC_TRAP7] = "TRAP #7",
+ [VEC_TRAP8] = "TRAP #8",
+ [VEC_TRAP9] = "TRAP #9",
+ [VEC_TRAP10] = "TRAP #10",
+ [VEC_TRAP11] = "TRAP #11",
+ [VEC_TRAP12] = "TRAP #12",
+ [VEC_TRAP13] = "TRAP #13",
+ [VEC_TRAP14] = "TRAP #14",
+ [VEC_TRAP15] = "TRAP #15",
+ [VEC_FPBRUC] = "FPCP BSUN",
+ [VEC_FPIR] = "FPCP INEXACT",
+ [VEC_FPDIVZ] = "FPCP DIV BY 0",
+ [VEC_FPUNDER] = "FPCP UNDERFLOW",
+ [VEC_FPOE] = "FPCP OPERAND ERROR",
+ [VEC_FPOVER] = "FPCP OVERFLOW",
+ [VEC_FPNAN] = "FPCP SNAN",
+ [VEC_FPUNSUP] = "FPCP UNSUPPORTED OPERATION",
+ [VEC_MMUCFG] = "MMU CONFIGURATION ERROR",
+ [VEC_MMUILL] = "MMU ILLEGAL OPERATION ERROR",
+ [VEC_MMUACC] = "MMU ACCESS LEVEL VIOLATION ERROR",
+ [VEC_RESV59] = "UNASSIGNED RESERVED 59",
+ [VEC_UNIMPEA] = "UNASSIGNED RESERVED 60",
+ [VEC_UNIMPII] = "UNASSIGNED RESERVED 61",
+ [VEC_RESV62] = "UNASSIGNED RESERVED 62",
+ [VEC_RESV63] = "UNASSIGNED RESERVED 63",
+};
+
+static const char *space_names[] = {
+ [0] = "Space 0",
+ [USER_DATA] = "User Data",
+ [USER_PROGRAM] = "User Program",
+#ifndef CONFIG_SUN3
+ [3] = "Space 3",
#else
-#include "traps_no.c"
+ [FC_CONTROL] = "Control",
+#endif
+ [4] = "Space 4",
+ [SUPER_DATA] = "Super Data",
+ [SUPER_PROGRAM] = "Super Program",
+ [CPU_SPACE] = "CPU"
+};
+
+void die_if_kernel(char *,struct pt_regs *,int);
+asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
+ unsigned long error_code);
+int send_fault_sig(struct pt_regs *regs);
+
+asmlinkage void trap_c(struct frame *fp);
+
+#if defined (CONFIG_M68060)
+static inline void access_error060 (struct frame *fp)
+{
+ unsigned long fslw = fp->un.fmt4.pc; /* is really FSLW for access error */
+
+#ifdef DEBUG
+ printk("fslw=%#lx, fa=%#lx\n", fslw, fp->un.fmt4.effaddr);
+#endif
+
+ if (fslw & MMU060_BPE) {
+ /* branch prediction error -> clear branch cache */
+ __asm__ __volatile__ ("movec %/cacr,%/d0\n\t"
+ "orl #0x00400000,%/d0\n\t"
+ "movec %/d0,%/cacr"
+ : : : "d0" );
+ /* return if there's no other error */
+ if (!(fslw & MMU060_ERR_BITS) && !(fslw & MMU060_SEE))
+ return;
+ }
+
+ if (fslw & (MMU060_DESC_ERR | MMU060_WP | MMU060_SP)) {
+ unsigned long errorcode;
+ unsigned long addr = fp->un.fmt4.effaddr;
+
+ if (fslw & MMU060_MA)
+ addr = (addr + PAGE_SIZE - 1) & PAGE_MASK;
+
+ errorcode = 1;
+ if (fslw & MMU060_DESC_ERR) {
+ __flush_tlb040_one(addr);
+ errorcode = 0;
+ }
+ if (fslw & MMU060_W)
+ errorcode |= 2;
+#ifdef DEBUG
+ printk("errorcode = %d\n", errorcode );
+#endif
+ do_page_fault(&fp->ptregs, addr, errorcode);
+ } else if (fslw & (MMU060_SEE)){
+ /* Software Emulation Error.
+ * fault during mem_read/mem_write in ifpsp060/os.S
+ */
+ send_fault_sig(&fp->ptregs);
+ } else if (!(fslw & (MMU060_RE|MMU060_WE)) ||
+ send_fault_sig(&fp->ptregs) > 0) {
+ printk("pc=%#lx, fa=%#lx\n", fp->ptregs.pc, fp->un.fmt4.effaddr);
+ printk( "68060 access error, fslw=%lx\n", fslw );
+ trap_c( fp );
+ }
+}
+#endif /* CONFIG_M68060 */
+
+#if defined (CONFIG_M68040)
+static inline unsigned long probe040(int iswrite, unsigned long addr, int wbs)
+{
+ unsigned long mmusr;
+ mm_segment_t old_fs = get_fs();
+
+ set_fs(MAKE_MM_SEG(wbs));
+
+ if (iswrite)
+ asm volatile (".chip 68040; ptestw (%0); .chip 68k" : : "a" (addr));
+ else
+ asm volatile (".chip 68040; ptestr (%0); .chip 68k" : : "a" (addr));
+
+ asm volatile (".chip 68040; movec %%mmusr,%0; .chip 68k" : "=r" (mmusr));
+
+ set_fs(old_fs);
+
+ return mmusr;
+}
+
+static inline int do_040writeback1(unsigned short wbs, unsigned long wba,
+ unsigned long wbd)
+{
+ int res = 0;
+ mm_segment_t old_fs = get_fs();
+
+ /* set_fs can not be moved, otherwise put_user() may oops */
+ set_fs(MAKE_MM_SEG(wbs));
+
+ switch (wbs & WBSIZ_040) {
+ case BA_SIZE_BYTE:
+ res = put_user(wbd & 0xff, (char __user *)wba);
+ break;
+ case BA_SIZE_WORD:
+ res = put_user(wbd & 0xffff, (short __user *)wba);
+ break;
+ case BA_SIZE_LONG:
+ res = put_user(wbd, (int __user *)wba);
+ break;
+ }
+
+ /* set_fs can not be moved, otherwise put_user() may oops */
+ set_fs(old_fs);
+
+
+#ifdef DEBUG
+ printk("do_040writeback1, res=%d\n",res);
+#endif
+
+ return res;
+}
+
+/* after an exception in a writeback the stack frame corresponding
+ * to that exception is discarded, set a few bits in the old frame
+ * to simulate what it should look like
+ */
+static inline void fix_xframe040(struct frame *fp, unsigned long wba, unsigned short wbs)
+{
+ fp->un.fmt7.faddr = wba;
+ fp->un.fmt7.ssw = wbs & 0xff;
+ if (wba != current->thread.faddr)
+ fp->un.fmt7.ssw |= MA_040;
+}
+
+static inline void do_040writebacks(struct frame *fp)
+{
+ int res = 0;
+#if 0
+ if (fp->un.fmt7.wb1s & WBV_040)
+ printk("access_error040: cannot handle 1st writeback. oops.\n");
+#endif
+
+ if ((fp->un.fmt7.wb2s & WBV_040) &&
+ !(fp->un.fmt7.wb2s & WBTT_040)) {
+ res = do_040writeback1(fp->un.fmt7.wb2s, fp->un.fmt7.wb2a,
+ fp->un.fmt7.wb2d);
+ if (res)
+ fix_xframe040(fp, fp->un.fmt7.wb2a, fp->un.fmt7.wb2s);
+ else
+ fp->un.fmt7.wb2s = 0;
+ }
+
+ /* do the 2nd wb only if the first one was successful (except for a kernel wb) */
+ if (fp->un.fmt7.wb3s & WBV_040 && (!res || fp->un.fmt7.wb3s & 4)) {
+ res = do_040writeback1(fp->un.fmt7.wb3s, fp->un.fmt7.wb3a,
+ fp->un.fmt7.wb3d);
+ if (res)
+ {
+ fix_xframe040(fp, fp->un.fmt7.wb3a, fp->un.fmt7.wb3s);
+
+ fp->un.fmt7.wb2s = fp->un.fmt7.wb3s;
+ fp->un.fmt7.wb3s &= (~WBV_040);
+ fp->un.fmt7.wb2a = fp->un.fmt7.wb3a;
+ fp->un.fmt7.wb2d = fp->un.fmt7.wb3d;
+ }
+ else
+ fp->un.fmt7.wb3s = 0;
+ }
+
+ if (res)
+ send_fault_sig(&fp->ptregs);
+}
+
+/*
+ * called from sigreturn(), must ensure userspace code didn't
+ * manipulate exception frame to circumvent protection, then complete
+ * pending writebacks
+ * we just clear TM2 to turn it into a userspace access
+ */
+asmlinkage void berr_040cleanup(struct frame *fp)
+{
+ fp->un.fmt7.wb2s &= ~4;
+ fp->un.fmt7.wb3s &= ~4;
+
+ do_040writebacks(fp);
+}
+
+static inline void access_error040(struct frame *fp)
+{
+ unsigned short ssw = fp->un.fmt7.ssw;
+ unsigned long mmusr;
+
+#ifdef DEBUG
+ printk("ssw=%#x, fa=%#lx\n", ssw, fp->un.fmt7.faddr);
+ printk("wb1s=%#x, wb2s=%#x, wb3s=%#x\n", fp->un.fmt7.wb1s,
+ fp->un.fmt7.wb2s, fp->un.fmt7.wb3s);
+ printk ("wb2a=%lx, wb3a=%lx, wb2d=%lx, wb3d=%lx\n",
+ fp->un.fmt7.wb2a, fp->un.fmt7.wb3a,
+ fp->un.fmt7.wb2d, fp->un.fmt7.wb3d);
+#endif
+
+ if (ssw & ATC_040) {
+ unsigned long addr = fp->un.fmt7.faddr;
+ unsigned long errorcode;
+
+ /*
+ * The MMU status has to be determined AFTER the address
+ * has been corrected if there was a misaligned access (MA).
+ */
+ if (ssw & MA_040)
+ addr = (addr + 7) & -8;
+
+ /* MMU error, get the MMUSR info for this access */
+ mmusr = probe040(!(ssw & RW_040), addr, ssw);
+#ifdef DEBUG
+ printk("mmusr = %lx\n", mmusr);
+#endif
+ errorcode = 1;
+ if (!(mmusr & MMU_R_040)) {
+ /* clear the invalid atc entry */
+ __flush_tlb040_one(addr);
+ errorcode = 0;
+ }
+
+ /* despite what documentation seems to say, RMW
+ * accesses have always both the LK and RW bits set */
+ if (!(ssw & RW_040) || (ssw & LK_040))
+ errorcode |= 2;
+
+ if (do_page_fault(&fp->ptregs, addr, errorcode)) {
+#ifdef DEBUG
+ printk("do_page_fault() !=0\n");
+#endif
+ if (user_mode(&fp->ptregs)){
+ /* delay writebacks after signal delivery */
+#ifdef DEBUG
+ printk(".. was usermode - return\n");
+#endif
+ return;
+ }
+ /* disable writeback into user space from kernel
+ * (if do_page_fault didn't fix the mapping,
+ * the writeback won't do good)
+ */
+disable_wb:
+#ifdef DEBUG
+ printk(".. disabling wb2\n");
+#endif
+ if (fp->un.fmt7.wb2a == fp->un.fmt7.faddr)
+ fp->un.fmt7.wb2s &= ~WBV_040;
+ if (fp->un.fmt7.wb3a == fp->un.fmt7.faddr)
+ fp->un.fmt7.wb3s &= ~WBV_040;
+ }
+ } else {
+ /* In case of a bus error we either kill the process or expect
+ * the kernel to catch the fault, which then is also responsible
+ * for cleaning up the mess.
+ */
+ current->thread.signo = SIGBUS;
+ current->thread.faddr = fp->un.fmt7.faddr;
+ if (send_fault_sig(&fp->ptregs) >= 0)
+ printk("68040 bus error (ssw=%x, faddr=%lx)\n", ssw,
+ fp->un.fmt7.faddr);
+ goto disable_wb;
+ }
+
+ do_040writebacks(fp);
+}
+#endif /* CONFIG_M68040 */
+
+#if defined(CONFIG_SUN3)
+#include <asm/sun3mmu.h>
+
+extern int mmu_emu_handle_fault (unsigned long, int, int);
+
+/* sun3 version of bus_error030 */
+
+static inline void bus_error030 (struct frame *fp)
+{
+ unsigned char buserr_type = sun3_get_buserr ();
+ unsigned long addr, errorcode;
+ unsigned short ssw = fp->un.fmtb.ssw;
+ extern unsigned long _sun3_map_test_start, _sun3_map_test_end;
+
+#ifdef DEBUG
+ if (ssw & (FC | FB))
+ printk ("Instruction fault at %#010lx\n",
+ ssw & FC ?
+ fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2
+ :
+ fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
+ if (ssw & DF)
+ printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
+ ssw & RW ? "read" : "write",
+ fp->un.fmtb.daddr,
+ space_names[ssw & DFC], fp->ptregs.pc);
+#endif
+
+ /*
+ * Check if this page should be demand-mapped. This needs to go before
+ * the testing for a bad kernel-space access (demand-mapping applies
+ * to kernel accesses too).
+ */
+
+ if ((ssw & DF)
+ && (buserr_type & (SUN3_BUSERR_PROTERR | SUN3_BUSERR_INVALID))) {
+ if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 0))
+ return;
+ }
+
+ /* Check for kernel-space pagefault (BAD). */
+ if (fp->ptregs.sr & PS_S) {
+ /* kernel fault must be a data fault to user space */
+ if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) {
+ // try checking the kernel mappings before surrender
+ if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 1))
+ return;
+ /* instruction fault or kernel data fault! */
+ if (ssw & (FC | FB))
+ printk ("Instruction fault at %#010lx\n",
+ fp->ptregs.pc);
+ if (ssw & DF) {
+ /* was this fault incurred testing bus mappings? */
+ if((fp->ptregs.pc >= (unsigned long)&_sun3_map_test_start) &&
+ (fp->ptregs.pc <= (unsigned long)&_sun3_map_test_end)) {
+ send_fault_sig(&fp->ptregs);
+ return;
+ }
+
+ printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
+ ssw & RW ? "read" : "write",
+ fp->un.fmtb.daddr,
+ space_names[ssw & DFC], fp->ptregs.pc);
+ }
+ printk ("BAD KERNEL BUSERR\n");
+
+ die_if_kernel("Oops", &fp->ptregs,0);
+ force_sig(SIGKILL, current);
+ return;
+ }
+ } else {
+ /* user fault */
+ if (!(ssw & (FC | FB)) && !(ssw & DF))
+ /* not an instruction fault or data fault! BAD */
+ panic ("USER BUSERR w/o instruction or data fault");
+ }
+
+
+ /* First handle the data fault, if any. */
+ if (ssw & DF) {
+ addr = fp->un.fmtb.daddr;
+
+// errorcode bit 0: 0 -> no page 1 -> protection fault
+// errorcode bit 1: 0 -> read fault 1 -> write fault
+
+// (buserr_type & SUN3_BUSERR_PROTERR) -> protection fault
+// (buserr_type & SUN3_BUSERR_INVALID) -> invalid page fault
+
+ if (buserr_type & SUN3_BUSERR_PROTERR)
+ errorcode = 0x01;
+ else if (buserr_type & SUN3_BUSERR_INVALID)
+ errorcode = 0x00;
+ else {
+#ifdef DEBUG
+ printk ("*** unexpected busfault type=%#04x\n", buserr_type);
+ printk ("invalid %s access at %#lx from pc %#lx\n",
+ !(ssw & RW) ? "write" : "read", addr,
+ fp->ptregs.pc);
+#endif
+ die_if_kernel ("Oops", &fp->ptregs, buserr_type);
+ force_sig (SIGBUS, current);
+ return;
+ }
+
+//todo: wtf is RM bit? --m
+ if (!(ssw & RW) || ssw & RM)
+ errorcode |= 0x02;
+
+ /* Handle page fault. */
+ do_page_fault (&fp->ptregs, addr, errorcode);
+
+ /* Retry the data fault now. */
+ return;
+ }
+
+ /* Now handle the instruction fault. */
+
+ /* Get the fault address. */
+ if (fp->ptregs.format == 0xA)
+ addr = fp->ptregs.pc + 4;
+ else
+ addr = fp->un.fmtb.baddr;
+ if (ssw & FC)
+ addr -= 2;
+
+ if (buserr_type & SUN3_BUSERR_INVALID) {
+ if (!mmu_emu_handle_fault (fp->un.fmtb.daddr, 1, 0))
+ do_page_fault (&fp->ptregs, addr, 0);
+ } else {
+#ifdef DEBUG
+ printk ("protection fault on insn access (segv).\n");
+#endif
+ force_sig (SIGSEGV, current);
+ }
+}
+#else
+#if defined(CPU_M68020_OR_M68030)
+static inline void bus_error030 (struct frame *fp)
+{
+ volatile unsigned short temp;
+ unsigned short mmusr;
+ unsigned long addr, errorcode;
+ unsigned short ssw = fp->un.fmtb.ssw;
+#ifdef DEBUG
+ unsigned long desc;
+
+ printk ("pid = %x ", current->pid);
+ printk ("SSW=%#06x ", ssw);
+
+ if (ssw & (FC | FB))
+ printk ("Instruction fault at %#010lx\n",
+ ssw & FC ?
+ fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2
+ :
+ fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
+ if (ssw & DF)
+ printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
+ ssw & RW ? "read" : "write",
+ fp->un.fmtb.daddr,
+ space_names[ssw & DFC], fp->ptregs.pc);
+#endif
+
+ /* ++andreas: If a data fault and an instruction fault happen
+ at the same time map in both pages. */
+
+ /* First handle the data fault, if any. */
+ if (ssw & DF) {
+ addr = fp->un.fmtb.daddr;
+
+#ifdef DEBUG
+ asm volatile ("ptestr %3,%2@,#7,%0\n\t"
+ "pmove %%psr,%1@"
+ : "=a&" (desc)
+ : "a" (&temp), "a" (addr), "d" (ssw));
+#else
+ asm volatile ("ptestr %2,%1@,#7\n\t"
+ "pmove %%psr,%0@"
+ : : "a" (&temp), "a" (addr), "d" (ssw));
+#endif
+ mmusr = temp;
+
+#ifdef DEBUG
+ printk("mmusr is %#x for addr %#lx in task %p\n",
+ mmusr, addr, current);
+ printk("descriptor address is %#lx, contents %#lx\n",
+ __va(desc), *(unsigned long *)__va(desc));
+#endif
+
+ errorcode = (mmusr & MMU_I) ? 0 : 1;
+ if (!(ssw & RW) || (ssw & RM))
+ errorcode |= 2;
+
+ if (mmusr & (MMU_I | MMU_WP)) {
+ if (ssw & 4) {
+ printk("Data %s fault at %#010lx in %s (pc=%#lx)\n",
+ ssw & RW ? "read" : "write",
+ fp->un.fmtb.daddr,
+ space_names[ssw & DFC], fp->ptregs.pc);
+ goto buserr;
+ }
+ /* Don't try to do anything further if an exception was
+ handled. */
+ if (do_page_fault (&fp->ptregs, addr, errorcode) < 0)
+ return;
+ } else if (!(mmusr & MMU_I)) {
+ /* probably a 020 cas fault */
+ if (!(ssw & RM) && send_fault_sig(&fp->ptregs) > 0)
+ printk("unexpected bus error (%#x,%#x)\n", ssw, mmusr);
+ } else if (mmusr & (MMU_B|MMU_L|MMU_S)) {
+ printk("invalid %s access at %#lx from pc %#lx\n",
+ !(ssw & RW) ? "write" : "read", addr,
+ fp->ptregs.pc);
+ die_if_kernel("Oops",&fp->ptregs,mmusr);
+ force_sig(SIGSEGV, current);
+ return;
+ } else {
+#if 0
+ static volatile long tlong;
+#endif
+
+ printk("weird %s access at %#lx from pc %#lx (ssw is %#x)\n",
+ !(ssw & RW) ? "write" : "read", addr,
+ fp->ptregs.pc, ssw);
+ asm volatile ("ptestr #1,%1@,#0\n\t"
+ "pmove %%psr,%0@"
+ : /* no outputs */
+ : "a" (&temp), "a" (addr));
+ mmusr = temp;
+
+ printk ("level 0 mmusr is %#x\n", mmusr);
+#if 0
+ asm volatile ("pmove %%tt0,%0@"
+ : /* no outputs */
+ : "a" (&tlong));
+ printk("tt0 is %#lx, ", tlong);
+ asm volatile ("pmove %%tt1,%0@"
+ : /* no outputs */
+ : "a" (&tlong));
+ printk("tt1 is %#lx\n", tlong);
+#endif
+#ifdef DEBUG
+ printk("Unknown SIGSEGV - 1\n");
+#endif
+ die_if_kernel("Oops",&fp->ptregs,mmusr);
+ force_sig(SIGSEGV, current);
+ return;
+ }
+
+ /* setup an ATC entry for the access about to be retried */
+ if (!(ssw & RW) || (ssw & RM))
+ asm volatile ("ploadw %1,%0@" : /* no outputs */
+ : "a" (addr), "d" (ssw));
+ else
+ asm volatile ("ploadr %1,%0@" : /* no outputs */
+ : "a" (addr), "d" (ssw));
+ }
+
+ /* Now handle the instruction fault. */
+
+ if (!(ssw & (FC|FB)))
+ return;
+
+ if (fp->ptregs.sr & PS_S) {
+ printk("Instruction fault at %#010lx\n",
+ fp->ptregs.pc);
+ buserr:
+ printk ("BAD KERNEL BUSERR\n");
+ die_if_kernel("Oops",&fp->ptregs,0);
+ force_sig(SIGKILL, current);
+ return;
+ }
+
+ /* get the fault address */
+ if (fp->ptregs.format == 10)
+ addr = fp->ptregs.pc + 4;
+ else
+ addr = fp->un.fmtb.baddr;
+ if (ssw & FC)
+ addr -= 2;
+
+ if ((ssw & DF) && ((addr ^ fp->un.fmtb.daddr) & PAGE_MASK) == 0)
+ /* Insn fault on same page as data fault. But we
+ should still create the ATC entry. */
+ goto create_atc_entry;
+
+#ifdef DEBUG
+ asm volatile ("ptestr #1,%2@,#7,%0\n\t"
+ "pmove %%psr,%1@"
+ : "=a&" (desc)
+ : "a" (&temp), "a" (addr));
+#else
+ asm volatile ("ptestr #1,%1@,#7\n\t"
+ "pmove %%psr,%0@"
+ : : "a" (&temp), "a" (addr));
+#endif
+ mmusr = temp;
+
+#ifdef DEBUG
+ printk ("mmusr is %#x for addr %#lx in task %p\n",
+ mmusr, addr, current);
+ printk ("descriptor address is %#lx, contents %#lx\n",
+ __va(desc), *(unsigned long *)__va(desc));
+#endif
+
+ if (mmusr & MMU_I)
+ do_page_fault (&fp->ptregs, addr, 0);
+ else if (mmusr & (MMU_B|MMU_L|MMU_S)) {
+ printk ("invalid insn access at %#lx from pc %#lx\n",
+ addr, fp->ptregs.pc);
+#ifdef DEBUG
+ printk("Unknown SIGSEGV - 2\n");
+#endif
+ die_if_kernel("Oops",&fp->ptregs,mmusr);
+ force_sig(SIGSEGV, current);
+ return;
+ }
+
+create_atc_entry:
+ /* setup an ATC entry for the access about to be retried */
+ asm volatile ("ploadr #2,%0@" : /* no outputs */
+ : "a" (addr));
+}
+#endif /* CPU_M68020_OR_M68030 */
+#endif /* !CONFIG_SUN3 */
+
+asmlinkage void buserr_c(struct frame *fp)
+{
+ /* Only set esp0 if coming from user mode */
+ if (user_mode(&fp->ptregs))
+ current->thread.esp0 = (unsigned long) fp;
+
+#ifdef DEBUG
+ printk ("*** Bus Error *** Format is %x\n", fp->ptregs.format);
+#endif
+
+ switch (fp->ptregs.format) {
+#if defined (CONFIG_M68060)
+ case 4: /* 68060 access error */
+ access_error060 (fp);
+ break;
+#endif
+#if defined (CONFIG_M68040)
+ case 0x7: /* 68040 access error */
+ access_error040 (fp);
+ break;
+#endif
+#if defined (CPU_M68020_OR_M68030)
+ case 0xa:
+ case 0xb:
+ bus_error030 (fp);
+ break;
+#endif
+ default:
+ die_if_kernel("bad frame format",&fp->ptregs,0);
+#ifdef DEBUG
+ printk("Unknown SIGSEGV - 4\n");
+#endif
+ force_sig(SIGSEGV, current);
+ }
+}
+
+
+static int kstack_depth_to_print = 48;
+
+void show_trace(unsigned long *stack)
+{
+ unsigned long *endstack;
+ unsigned long addr;
+ int i;
+
+ printk("Call Trace:");
+ addr = (unsigned long)stack + THREAD_SIZE - 1;
+ endstack = (unsigned long *)(addr & -THREAD_SIZE);
+ i = 0;
+ while (stack + 1 <= endstack) {
+ addr = *stack++;
+ /*
+ * If the address is either in the text segment of the
+ * kernel, or in the region which contains vmalloc'ed
+ * memory, it *may* be the address of a calling
+ * routine; if so, print it so that someone tracing
+ * down the cause of the crash will be able to figure
+ * out the call path that was taken.
+ */
+ if (__kernel_text_address(addr)) {
+#ifndef CONFIG_KALLSYMS
+ if (i % 5 == 0)
+ printk("\n ");
+#endif
+ printk(" [<%08lx>] %pS\n", addr, (void *)addr);
+ i++;
+ }
+ }
+ printk("\n");
+}
+
+void show_registers(struct pt_regs *regs)
+{
+ struct frame *fp = (struct frame *)regs;
+ mm_segment_t old_fs = get_fs();
+ u16 c, *cp;
+ unsigned long addr;
+ int i;
+
+ print_modules();
+ printk("PC: [<%08lx>] %pS\n", regs->pc, (void *)regs->pc);
+ printk("SR: %04x SP: %p a2: %08lx\n", regs->sr, regs, regs->a2);
+ printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
+ regs->d0, regs->d1, regs->d2, regs->d3);
+ printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n",
+ regs->d4, regs->d5, regs->a0, regs->a1);
+
+ printk("Process %s (pid: %d, task=%p)\n",
+ current->comm, task_pid_nr(current), current);
+ addr = (unsigned long)&fp->un;
+ printk("Frame format=%X ", regs->format);
+ switch (regs->format) {
+ case 0x2:
+ printk("instr addr=%08lx\n", fp->un.fmt2.iaddr);
+ addr += sizeof(fp->un.fmt2);
+ break;
+ case 0x3:
+ printk("eff addr=%08lx\n", fp->un.fmt3.effaddr);
+ addr += sizeof(fp->un.fmt3);
+ break;
+ case 0x4:
+ printk((CPU_IS_060 ? "fault addr=%08lx fslw=%08lx\n"
+ : "eff addr=%08lx pc=%08lx\n"),
+ fp->un.fmt4.effaddr, fp->un.fmt4.pc);
+ addr += sizeof(fp->un.fmt4);
+ break;
+ case 0x7:
+ printk("eff addr=%08lx ssw=%04x faddr=%08lx\n",
+ fp->un.fmt7.effaddr, fp->un.fmt7.ssw, fp->un.fmt7.faddr);
+ printk("wb 1 stat/addr/data: %04x %08lx %08lx\n",
+ fp->un.fmt7.wb1s, fp->un.fmt7.wb1a, fp->un.fmt7.wb1dpd0);
+ printk("wb 2 stat/addr/data: %04x %08lx %08lx\n",
+ fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d);
+ printk("wb 3 stat/addr/data: %04x %08lx %08lx\n",
+ fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d);
+ printk("push data: %08lx %08lx %08lx %08lx\n",
+ fp->un.fmt7.wb1dpd0, fp->un.fmt7.pd1, fp->un.fmt7.pd2,
+ fp->un.fmt7.pd3);
+ addr += sizeof(fp->un.fmt7);
+ break;
+ case 0x9:
+ printk("instr addr=%08lx\n", fp->un.fmt9.iaddr);
+ addr += sizeof(fp->un.fmt9);
+ break;
+ case 0xa:
+ printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
+ fp->un.fmta.ssw, fp->un.fmta.isc, fp->un.fmta.isb,
+ fp->un.fmta.daddr, fp->un.fmta.dobuf);
+ addr += sizeof(fp->un.fmta);
+ break;
+ case 0xb:
+ printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
+ fp->un.fmtb.ssw, fp->un.fmtb.isc, fp->un.fmtb.isb,
+ fp->un.fmtb.daddr, fp->un.fmtb.dobuf);
+ printk("baddr=%08lx dibuf=%08lx ver=%x\n",
+ fp->un.fmtb.baddr, fp->un.fmtb.dibuf, fp->un.fmtb.ver);
+ addr += sizeof(fp->un.fmtb);
+ break;
+ default:
+ printk("\n");
+ }
+ show_stack(NULL, (unsigned long *)addr);
+
+ printk("Code:");
+ set_fs(KERNEL_DS);
+ cp = (u16 *)regs->pc;
+ for (i = -8; i < 16; i++) {
+ if (get_user(c, cp + i) && i >= 0) {
+ printk(" Bad PC value.");
+ break;
+ }
+ printk(i ? " %04x" : " <%04x>", c);
+ }
+ set_fs(old_fs);
+ printk ("\n");
+}
+
+void show_stack(struct task_struct *task, unsigned long *stack)
+{
+ unsigned long *p;
+ unsigned long *endstack;
+ int i;
+
+ if (!stack) {
+ if (task)
+ stack = (unsigned long *)task->thread.esp0;
+ else
+ stack = (unsigned long *)&stack;
+ }
+ endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) & -THREAD_SIZE);
+
+ printk("Stack from %08lx:", (unsigned long)stack);
+ p = stack;
+ for (i = 0; i < kstack_depth_to_print; i++) {
+ if (p + 1 > endstack)
+ break;
+ if (i % 8 == 0)
+ printk("\n ");
+ printk(" %08lx", *p++);
+ }
+ printk("\n");
+ show_trace(stack);
+}
+
+/*
+ * The architecture-independent backtrace generator
+ */
+void dump_stack(void)
+{
+ unsigned long stack;
+
+ show_trace(&stack);
+}
+
+EXPORT_SYMBOL(dump_stack);
+
+/*
+ * The vector number returned in the frame pointer may also contain
+ * the "fs" (Fault Status) bits on ColdFire. These are in the bottom
+ * 2 bits, and upper 2 bits. So we need to mask out the real vector
+ * number before using it in comparisons. You don't need to do this on
+ * real 68k parts, but it won't hurt either.
+ */
+
+void bad_super_trap (struct frame *fp)
+{
+ int vector = (fp->ptregs.vector >> 2) & 0xff;
+
+ console_verbose();
+ if (vector < ARRAY_SIZE(vec_names))
+ printk ("*** %s *** FORMAT=%X\n",
+ vec_names[vector],
+ fp->ptregs.format);
+ else
+ printk ("*** Exception %d *** FORMAT=%X\n",
+ vector, fp->ptregs.format);
+ if (vector == VEC_ADDRERR && CPU_IS_020_OR_030) {
+ unsigned short ssw = fp->un.fmtb.ssw;
+
+ printk ("SSW=%#06x ", ssw);
+
+ if (ssw & RC)
+ printk ("Pipe stage C instruction fault at %#010lx\n",
+ (fp->ptregs.format) == 0xA ?
+ fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2);
+ if (ssw & RB)
+ printk ("Pipe stage B instruction fault at %#010lx\n",
+ (fp->ptregs.format) == 0xA ?
+ fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
+ if (ssw & DF)
+ printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
+ ssw & RW ? "read" : "write",
+ fp->un.fmtb.daddr, space_names[ssw & DFC],
+ fp->ptregs.pc);
+ }
+ printk ("Current process id is %d\n", task_pid_nr(current));
+ die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
+}
+
+asmlinkage void trap_c(struct frame *fp)
+{
+ int sig;
+ int vector = (fp->ptregs.vector >> 2) & 0xff;
+ siginfo_t info;
+
+ if (fp->ptregs.sr & PS_S) {
+ if (vector == VEC_TRACE) {
+ /* traced a trapping instruction on a 68020/30,
+ * real exception will be executed afterwards.
+ */
+ } else if (!handle_kernel_fault(&fp->ptregs))
+ bad_super_trap(fp);
+ return;
+ }
+
+ /* send the appropriate signal to the user program */
+ switch (vector) {
+ case VEC_ADDRERR:
+ info.si_code = BUS_ADRALN;
+ sig = SIGBUS;
+ break;
+ case VEC_ILLEGAL:
+ case VEC_LINE10:
+ case VEC_LINE11:
+ info.si_code = ILL_ILLOPC;
+ sig = SIGILL;
+ break;
+ case VEC_PRIV:
+ info.si_code = ILL_PRVOPC;
+ sig = SIGILL;
+ break;
+ case VEC_COPROC:
+ info.si_code = ILL_COPROC;
+ sig = SIGILL;
+ break;
+ case VEC_TRAP1:
+ case VEC_TRAP2:
+ case VEC_TRAP3:
+ case VEC_TRAP4:
+ case VEC_TRAP5:
+ case VEC_TRAP6:
+ case VEC_TRAP7:
+ case VEC_TRAP8:
+ case VEC_TRAP9:
+ case VEC_TRAP10:
+ case VEC_TRAP11:
+ case VEC_TRAP12:
+ case VEC_TRAP13:
+ case VEC_TRAP14:
+ info.si_code = ILL_ILLTRP;
+ sig = SIGILL;
+ break;
+ case VEC_FPBRUC:
+ case VEC_FPOE:
+ case VEC_FPNAN:
+ info.si_code = FPE_FLTINV;
+ sig = SIGFPE;
+ break;
+ case VEC_FPIR:
+ info.si_code = FPE_FLTRES;
+ sig = SIGFPE;
+ break;
+ case VEC_FPDIVZ:
+ info.si_code = FPE_FLTDIV;
+ sig = SIGFPE;
+ break;
+ case VEC_FPUNDER:
+ info.si_code = FPE_FLTUND;
+ sig = SIGFPE;
+ break;
+ case VEC_FPOVER:
+ info.si_code = FPE_FLTOVF;
+ sig = SIGFPE;
+ break;
+ case VEC_ZERODIV:
+ info.si_code = FPE_INTDIV;
+ sig = SIGFPE;
+ break;
+ case VEC_CHK:
+ case VEC_TRAP:
+ info.si_code = FPE_INTOVF;
+ sig = SIGFPE;
+ break;
+ case VEC_TRACE: /* ptrace single step */
+ info.si_code = TRAP_TRACE;
+ sig = SIGTRAP;
+ break;
+ case VEC_TRAP15: /* breakpoint */
+ info.si_code = TRAP_BRKPT;
+ sig = SIGTRAP;
+ break;
+ default:
+ info.si_code = ILL_ILLOPC;
+ sig = SIGILL;
+ break;
+ }
+ info.si_signo = sig;
+ info.si_errno = 0;
+ switch (fp->ptregs.format) {
+ default:
+ info.si_addr = (void *) fp->ptregs.pc;
+ break;
+ case 2:
+ info.si_addr = (void *) fp->un.fmt2.iaddr;
+ break;
+ case 7:
+ info.si_addr = (void *) fp->un.fmt7.effaddr;
+ break;
+ case 9:
+ info.si_addr = (void *) fp->un.fmt9.iaddr;
+ break;
+ case 10:
+ info.si_addr = (void *) fp->un.fmta.daddr;
+ break;
+ case 11:
+ info.si_addr = (void *) fp->un.fmtb.daddr;
+ break;
+ }
+ force_sig_info (sig, &info, current);
+}
+
+void die_if_kernel (char *str, struct pt_regs *fp, int nr)
+{
+ if (!(fp->sr & PS_S))
+ return;
+
+ console_verbose();
+ printk("%s: %08x\n",str,nr);
+ show_registers(fp);
+ add_taint(TAINT_DIE);
+ do_exit(SIGSEGV);
+}
+
+asmlinkage void set_esp0(unsigned long ssp)
+{
+ current->thread.esp0 = ssp;
+}
+
+/*
+ * This function is called if an error occur while accessing
+ * user-space from the fpsp040 code.
+ */
+asmlinkage void fpsp040_die(void)
+{
+ do_exit(SIGSEGV);
+}
+
+#ifdef CONFIG_M68KFPU_EMU
+asmlinkage void fpemu_signal(int signal, int code, void *addr)
+{
+ siginfo_t info;
+
+ info.si_signo = signal;
+ info.si_errno = 0;
+ info.si_code = code;
+ info.si_addr = addr;
+ force_sig_info(signal, &info, current);
+}
#endif
diff --git a/arch/m68k/kernel/traps_mm.c b/arch/m68k/kernel/traps_mm.c
deleted file mode 100644
index 4022bbc28878..000000000000
--- a/arch/m68k/kernel/traps_mm.c
+++ /dev/null
@@ -1,1207 +0,0 @@
-/*
- * linux/arch/m68k/kernel/traps.c
- *
- * Copyright (C) 1993, 1994 by Hamish Macdonald
- *
- * 68040 fixes by Michael Rausch
- * 68040 fixes by Martin Apel
- * 68040 fixes and writeback by Richard Zidlicky
- * 68060 fixes by Roman Hodek
- * 68060 fixes by Jesper Skov
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-/*
- * Sets up all exception vectors
- */
-
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/user.h>
-#include <linux/string.h>
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <linux/ptrace.h>
-#include <linux/kallsyms.h>
-
-#include <asm/setup.h>
-#include <asm/fpu.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/traps.h>
-#include <asm/pgalloc.h>
-#include <asm/machdep.h>
-#include <asm/siginfo.h>
-
-/* assembler routines */
-asmlinkage void system_call(void);
-asmlinkage void buserr(void);
-asmlinkage void trap(void);
-asmlinkage void nmihandler(void);
-#ifdef CONFIG_M68KFPU_EMU
-asmlinkage void fpu_emu(void);
-#endif
-
-e_vector vectors[256];
-
-/* nmi handler for the Amiga */
-asm(".text\n"
- __ALIGN_STR "\n"
- "nmihandler: rte");
-
-/*
- * this must be called very early as the kernel might
- * use some instruction that are emulated on the 060
- * and so we're prepared for early probe attempts (e.g. nf_init).
- */
-void __init base_trap_init(void)
-{
- if (MACH_IS_SUN3X) {
- extern e_vector *sun3x_prom_vbr;
-
- __asm__ volatile ("movec %%vbr, %0" : "=r" (sun3x_prom_vbr));
- }
-
- /* setup the exception vector table */
- __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
-
- if (CPU_IS_060) {
- /* set up ISP entry points */
- asmlinkage void unimp_vec(void) asm ("_060_isp_unimp");
-
- vectors[VEC_UNIMPII] = unimp_vec;
- }
-
- vectors[VEC_BUSERR] = buserr;
- vectors[VEC_ILLEGAL] = trap;
- vectors[VEC_SYS] = system_call;
-}
-
-void __init trap_init (void)
-{
- int i;
-
- for (i = VEC_SPUR; i <= VEC_INT7; i++)
- vectors[i] = bad_inthandler;
-
- for (i = 0; i < VEC_USER; i++)
- if (!vectors[i])
- vectors[i] = trap;
-
- for (i = VEC_USER; i < 256; i++)
- vectors[i] = bad_inthandler;
-
-#ifdef CONFIG_M68KFPU_EMU
- if (FPU_IS_EMU)
- vectors[VEC_LINE11] = fpu_emu;
-#endif
-
- if (CPU_IS_040 && !FPU_IS_EMU) {
- /* set up FPSP entry points */
- asmlinkage void dz_vec(void) asm ("dz");
- asmlinkage void inex_vec(void) asm ("inex");
- asmlinkage void ovfl_vec(void) asm ("ovfl");
- asmlinkage void unfl_vec(void) asm ("unfl");
- asmlinkage void snan_vec(void) asm ("snan");
- asmlinkage void operr_vec(void) asm ("operr");
- asmlinkage void bsun_vec(void) asm ("bsun");
- asmlinkage void fline_vec(void) asm ("fline");
- asmlinkage void unsupp_vec(void) asm ("unsupp");
-
- vectors[VEC_FPDIVZ] = dz_vec;
- vectors[VEC_FPIR] = inex_vec;
- vectors[VEC_FPOVER] = ovfl_vec;
- vectors[VEC_FPUNDER] = unfl_vec;
- vectors[VEC_FPNAN] = snan_vec;
- vectors[VEC_FPOE] = operr_vec;
- vectors[VEC_FPBRUC] = bsun_vec;
- vectors[VEC_LINE11] = fline_vec;
- vectors[VEC_FPUNSUP] = unsupp_vec;
- }
-
- if (CPU_IS_060 && !FPU_IS_EMU) {
- /* set up IFPSP entry points */
- asmlinkage void snan_vec6(void) asm ("_060_fpsp_snan");
- asmlinkage void operr_vec6(void) asm ("_060_fpsp_operr");
- asmlinkage void ovfl_vec6(void) asm ("_060_fpsp_ovfl");
- asmlinkage void unfl_vec6(void) asm ("_060_fpsp_unfl");
- asmlinkage void dz_vec6(void) asm ("_060_fpsp_dz");
- asmlinkage void inex_vec6(void) asm ("_060_fpsp_inex");
- asmlinkage void fline_vec6(void) asm ("_060_fpsp_fline");
- asmlinkage void unsupp_vec6(void) asm ("_060_fpsp_unsupp");
- asmlinkage void effadd_vec6(void) asm ("_060_fpsp_effadd");
-
- vectors[VEC_FPNAN] = snan_vec6;
- vectors[VEC_FPOE] = operr_vec6;
- vectors[VEC_FPOVER] = ovfl_vec6;
- vectors[VEC_FPUNDER] = unfl_vec6;
- vectors[VEC_FPDIVZ] = dz_vec6;
- vectors[VEC_FPIR] = inex_vec6;
- vectors[VEC_LINE11] = fline_vec6;
- vectors[VEC_FPUNSUP] = unsupp_vec6;
- vectors[VEC_UNIMPEA] = effadd_vec6;
- }
-
- /* if running on an amiga, make the NMI interrupt do nothing */
- if (MACH_IS_AMIGA) {
- vectors[VEC_INT7] = nmihandler;
- }
-}
-
-
-static const char *vec_names[] = {
- [VEC_RESETSP] = "RESET SP",
- [VEC_RESETPC] = "RESET PC",
- [VEC_BUSERR] = "BUS ERROR",
- [VEC_ADDRERR] = "ADDRESS ERROR",
- [VEC_ILLEGAL] = "ILLEGAL INSTRUCTION",
- [VEC_ZERODIV] = "ZERO DIVIDE",
- [VEC_CHK] = "CHK",
- [VEC_TRAP] = "TRAPcc",
- [VEC_PRIV] = "PRIVILEGE VIOLATION",
- [VEC_TRACE] = "TRACE",
- [VEC_LINE10] = "LINE 1010",
- [VEC_LINE11] = "LINE 1111",
- [VEC_RESV12] = "UNASSIGNED RESERVED 12",
- [VEC_COPROC] = "COPROCESSOR PROTOCOL VIOLATION",
- [VEC_FORMAT] = "FORMAT ERROR",
- [VEC_UNINT] = "UNINITIALIZED INTERRUPT",
- [VEC_RESV16] = "UNASSIGNED RESERVED 16",
- [VEC_RESV17] = "UNASSIGNED RESERVED 17",
- [VEC_RESV18] = "UNASSIGNED RESERVED 18",
- [VEC_RESV19] = "UNASSIGNED RESERVED 19",
- [VEC_RESV20] = "UNASSIGNED RESERVED 20",
- [VEC_RESV21] = "UNASSIGNED RESERVED 21",
- [VEC_RESV22] = "UNASSIGNED RESERVED 22",
- [VEC_RESV23] = "UNASSIGNED RESERVED 23",
- [VEC_SPUR] = "SPURIOUS INTERRUPT",
- [VEC_INT1] = "LEVEL 1 INT",
- [VEC_INT2] = "LEVEL 2 INT",
- [VEC_INT3] = "LEVEL 3 INT",
- [VEC_INT4] = "LEVEL 4 INT",
- [VEC_INT5] = "LEVEL 5 INT",
- [VEC_INT6] = "LEVEL 6 INT",
- [VEC_INT7] = "LEVEL 7 INT",
- [VEC_SYS] = "SYSCALL",
- [VEC_TRAP1] = "TRAP #1",
- [VEC_TRAP2] = "TRAP #2",
- [VEC_TRAP3] = "TRAP #3",
- [VEC_TRAP4] = "TRAP #4",
- [VEC_TRAP5] = "TRAP #5",
- [VEC_TRAP6] = "TRAP #6",
- [VEC_TRAP7] = "TRAP #7",
- [VEC_TRAP8] = "TRAP #8",
- [VEC_TRAP9] = "TRAP #9",
- [VEC_TRAP10] = "TRAP #10",
- [VEC_TRAP11] = "TRAP #11",
- [VEC_TRAP12] = "TRAP #12",
- [VEC_TRAP13] = "TRAP #13",
- [VEC_TRAP14] = "TRAP #14",
- [VEC_TRAP15] = "TRAP #15",
- [VEC_FPBRUC] = "FPCP BSUN",
- [VEC_FPIR] = "FPCP INEXACT",
- [VEC_FPDIVZ] = "FPCP DIV BY 0",
- [VEC_FPUNDER] = "FPCP UNDERFLOW",
- [VEC_FPOE] = "FPCP OPERAND ERROR",
- [VEC_FPOVER] = "FPCP OVERFLOW",
- [VEC_FPNAN] = "FPCP SNAN",
- [VEC_FPUNSUP] = "FPCP UNSUPPORTED OPERATION",
- [VEC_MMUCFG] = "MMU CONFIGURATION ERROR",
- [VEC_MMUILL] = "MMU ILLEGAL OPERATION ERROR",
- [VEC_MMUACC] = "MMU ACCESS LEVEL VIOLATION ERROR",
- [VEC_RESV59] = "UNASSIGNED RESERVED 59",
- [VEC_UNIMPEA] = "UNASSIGNED RESERVED 60",
- [VEC_UNIMPII] = "UNASSIGNED RESERVED 61",
- [VEC_RESV62] = "UNASSIGNED RESERVED 62",
- [VEC_RESV63] = "UNASSIGNED RESERVED 63",
-};
-
-static const char *space_names[] = {
- [0] = "Space 0",
- [USER_DATA] = "User Data",
- [USER_PROGRAM] = "User Program",
-#ifndef CONFIG_SUN3
- [3] = "Space 3",
-#else
- [FC_CONTROL] = "Control",
-#endif
- [4] = "Space 4",
- [SUPER_DATA] = "Super Data",
- [SUPER_PROGRAM] = "Super Program",
- [CPU_SPACE] = "CPU"
-};
-
-void die_if_kernel(char *,struct pt_regs *,int);
-asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
- unsigned long error_code);
-int send_fault_sig(struct pt_regs *regs);
-
-asmlinkage void trap_c(struct frame *fp);
-
-#if defined (CONFIG_M68060)
-static inline void access_error060 (struct frame *fp)
-{
- unsigned long fslw = fp->un.fmt4.pc; /* is really FSLW for access error */
-
-#ifdef DEBUG
- printk("fslw=%#lx, fa=%#lx\n", fslw, fp->un.fmt4.effaddr);
-#endif
-
- if (fslw & MMU060_BPE) {
- /* branch prediction error -> clear branch cache */
- __asm__ __volatile__ ("movec %/cacr,%/d0\n\t"
- "orl #0x00400000,%/d0\n\t"
- "movec %/d0,%/cacr"
- : : : "d0" );
- /* return if there's no other error */
- if (!(fslw & MMU060_ERR_BITS) && !(fslw & MMU060_SEE))
- return;
- }
-
- if (fslw & (MMU060_DESC_ERR | MMU060_WP | MMU060_SP)) {
- unsigned long errorcode;
- unsigned long addr = fp->un.fmt4.effaddr;
-
- if (fslw & MMU060_MA)
- addr = (addr + PAGE_SIZE - 1) & PAGE_MASK;
-
- errorcode = 1;
- if (fslw & MMU060_DESC_ERR) {
- __flush_tlb040_one(addr);
- errorcode = 0;
- }
- if (fslw & MMU060_W)
- errorcode |= 2;
-#ifdef DEBUG
- printk("errorcode = %d\n", errorcode );
-#endif
- do_page_fault(&fp->ptregs, addr, errorcode);
- } else if (fslw & (MMU060_SEE)){
- /* Software Emulation Error.
- * fault during mem_read/mem_write in ifpsp060/os.S
- */
- send_fault_sig(&fp->ptregs);
- } else if (!(fslw & (MMU060_RE|MMU060_WE)) ||
- send_fault_sig(&fp->ptregs) > 0) {
- printk("pc=%#lx, fa=%#lx\n", fp->ptregs.pc, fp->un.fmt4.effaddr);
- printk( "68060 access error, fslw=%lx\n", fslw );
- trap_c( fp );
- }
-}
-#endif /* CONFIG_M68060 */
-
-#if defined (CONFIG_M68040)
-static inline unsigned long probe040(int iswrite, unsigned long addr, int wbs)
-{
- unsigned long mmusr;
- mm_segment_t old_fs = get_fs();
-
- set_fs(MAKE_MM_SEG(wbs));
-
- if (iswrite)
- asm volatile (".chip 68040; ptestw (%0); .chip 68k" : : "a" (addr));
- else
- asm volatile (".chip 68040; ptestr (%0); .chip 68k" : : "a" (addr));
-
- asm volatile (".chip 68040; movec %%mmusr,%0; .chip 68k" : "=r" (mmusr));
-
- set_fs(old_fs);
-
- return mmusr;
-}
-
-static inline int do_040writeback1(unsigned short wbs, unsigned long wba,
- unsigned long wbd)
-{
- int res = 0;
- mm_segment_t old_fs = get_fs();
-
- /* set_fs can not be moved, otherwise put_user() may oops */
- set_fs(MAKE_MM_SEG(wbs));
-
- switch (wbs & WBSIZ_040) {
- case BA_SIZE_BYTE:
- res = put_user(wbd & 0xff, (char __user *)wba);
- break;
- case BA_SIZE_WORD:
- res = put_user(wbd & 0xffff, (short __user *)wba);
- break;
- case BA_SIZE_LONG:
- res = put_user(wbd, (int __user *)wba);
- break;
- }
-
- /* set_fs can not be moved, otherwise put_user() may oops */
- set_fs(old_fs);
-
-
-#ifdef DEBUG
- printk("do_040writeback1, res=%d\n",res);
-#endif
-
- return res;
-}
-
-/* after an exception in a writeback the stack frame corresponding
- * to that exception is discarded, set a few bits in the old frame
- * to simulate what it should look like
- */
-static inline void fix_xframe040(struct frame *fp, unsigned long wba, unsigned short wbs)
-{
- fp->un.fmt7.faddr = wba;
- fp->un.fmt7.ssw = wbs & 0xff;
- if (wba != current->thread.faddr)
- fp->un.fmt7.ssw |= MA_040;
-}
-
-static inline void do_040writebacks(struct frame *fp)
-{
- int res = 0;
-#if 0
- if (fp->un.fmt7.wb1s & WBV_040)
- printk("access_error040: cannot handle 1st writeback. oops.\n");
-#endif
-
- if ((fp->un.fmt7.wb2s & WBV_040) &&
- !(fp->un.fmt7.wb2s & WBTT_040)) {
- res = do_040writeback1(fp->un.fmt7.wb2s, fp->un.fmt7.wb2a,
- fp->un.fmt7.wb2d);
- if (res)
- fix_xframe040(fp, fp->un.fmt7.wb2a, fp->un.fmt7.wb2s);
- else
- fp->un.fmt7.wb2s = 0;
- }
-
- /* do the 2nd wb only if the first one was successful (except for a kernel wb) */
- if (fp->un.fmt7.wb3s & WBV_040 && (!res || fp->un.fmt7.wb3s & 4)) {
- res = do_040writeback1(fp->un.fmt7.wb3s, fp->un.fmt7.wb3a,
- fp->un.fmt7.wb3d);
- if (res)
- {
- fix_xframe040(fp, fp->un.fmt7.wb3a, fp->un.fmt7.wb3s);
-
- fp->un.fmt7.wb2s = fp->un.fmt7.wb3s;
- fp->un.fmt7.wb3s &= (~WBV_040);
- fp->un.fmt7.wb2a = fp->un.fmt7.wb3a;
- fp->un.fmt7.wb2d = fp->un.fmt7.wb3d;
- }
- else
- fp->un.fmt7.wb3s = 0;
- }
-
- if (res)
- send_fault_sig(&fp->ptregs);
-}
-
-/*
- * called from sigreturn(), must ensure userspace code didn't
- * manipulate exception frame to circumvent protection, then complete
- * pending writebacks
- * we just clear TM2 to turn it into a userspace access
- */
-asmlinkage void berr_040cleanup(struct frame *fp)
-{
- fp->un.fmt7.wb2s &= ~4;
- fp->un.fmt7.wb3s &= ~4;
-
- do_040writebacks(fp);
-}
-
-static inline void access_error040(struct frame *fp)
-{
- unsigned short ssw = fp->un.fmt7.ssw;
- unsigned long mmusr;
-
-#ifdef DEBUG
- printk("ssw=%#x, fa=%#lx\n", ssw, fp->un.fmt7.faddr);
- printk("wb1s=%#x, wb2s=%#x, wb3s=%#x\n", fp->un.fmt7.wb1s,
- fp->un.fmt7.wb2s, fp->un.fmt7.wb3s);
- printk ("wb2a=%lx, wb3a=%lx, wb2d=%lx, wb3d=%lx\n",
- fp->un.fmt7.wb2a, fp->un.fmt7.wb3a,
- fp->un.fmt7.wb2d, fp->un.fmt7.wb3d);
-#endif
-
- if (ssw & ATC_040) {
- unsigned long addr = fp->un.fmt7.faddr;
- unsigned long errorcode;
-
- /*
- * The MMU status has to be determined AFTER the address
- * has been corrected if there was a misaligned access (MA).
- */
- if (ssw & MA_040)
- addr = (addr + 7) & -8;
-
- /* MMU error, get the MMUSR info for this access */
- mmusr = probe040(!(ssw & RW_040), addr, ssw);
-#ifdef DEBUG
- printk("mmusr = %lx\n", mmusr);
-#endif
- errorcode = 1;
- if (!(mmusr & MMU_R_040)) {
- /* clear the invalid atc entry */
- __flush_tlb040_one(addr);
- errorcode = 0;
- }
-
- /* despite what documentation seems to say, RMW
- * accesses have always both the LK and RW bits set */
- if (!(ssw & RW_040) || (ssw & LK_040))
- errorcode |= 2;
-
- if (do_page_fault(&fp->ptregs, addr, errorcode)) {
-#ifdef DEBUG
- printk("do_page_fault() !=0\n");
-#endif
- if (user_mode(&fp->ptregs)){
- /* delay writebacks after signal delivery */
-#ifdef DEBUG
- printk(".. was usermode - return\n");
-#endif
- return;
- }
- /* disable writeback into user space from kernel
- * (if do_page_fault didn't fix the mapping,
- * the writeback won't do good)
- */
-disable_wb:
-#ifdef DEBUG
- printk(".. disabling wb2\n");
-#endif
- if (fp->un.fmt7.wb2a == fp->un.fmt7.faddr)
- fp->un.fmt7.wb2s &= ~WBV_040;
- if (fp->un.fmt7.wb3a == fp->un.fmt7.faddr)
- fp->un.fmt7.wb3s &= ~WBV_040;
- }
- } else {
- /* In case of a bus error we either kill the process or expect
- * the kernel to catch the fault, which then is also responsible
- * for cleaning up the mess.
- */
- current->thread.signo = SIGBUS;
- current->thread.faddr = fp->un.fmt7.faddr;
- if (send_fault_sig(&fp->ptregs) >= 0)
- printk("68040 bus error (ssw=%x, faddr=%lx)\n", ssw,
- fp->un.fmt7.faddr);
- goto disable_wb;
- }
-
- do_040writebacks(fp);
-}
-#endif /* CONFIG_M68040 */
-
-#if defined(CONFIG_SUN3)
-#include <asm/sun3mmu.h>
-
-extern int mmu_emu_handle_fault (unsigned long, int, int);
-
-/* sun3 version of bus_error030 */
-
-static inline void bus_error030 (struct frame *fp)
-{
- unsigned char buserr_type = sun3_get_buserr ();
- unsigned long addr, errorcode;
- unsigned short ssw = fp->un.fmtb.ssw;
- extern unsigned long _sun3_map_test_start, _sun3_map_test_end;
-
-#ifdef DEBUG
- if (ssw & (FC | FB))
- printk ("Instruction fault at %#010lx\n",
- ssw & FC ?
- fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2
- :
- fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
- if (ssw & DF)
- printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
- ssw & RW ? "read" : "write",
- fp->un.fmtb.daddr,
- space_names[ssw & DFC], fp->ptregs.pc);
-#endif
-
- /*
- * Check if this page should be demand-mapped. This needs to go before
- * the testing for a bad kernel-space access (demand-mapping applies
- * to kernel accesses too).
- */
-
- if ((ssw & DF)
- && (buserr_type & (SUN3_BUSERR_PROTERR | SUN3_BUSERR_INVALID))) {
- if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 0))
- return;
- }
-
- /* Check for kernel-space pagefault (BAD). */
- if (fp->ptregs.sr & PS_S) {
- /* kernel fault must be a data fault to user space */
- if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) {
- // try checking the kernel mappings before surrender
- if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 1))
- return;
- /* instruction fault or kernel data fault! */
- if (ssw & (FC | FB))
- printk ("Instruction fault at %#010lx\n",
- fp->ptregs.pc);
- if (ssw & DF) {
- /* was this fault incurred testing bus mappings? */
- if((fp->ptregs.pc >= (unsigned long)&_sun3_map_test_start) &&
- (fp->ptregs.pc <= (unsigned long)&_sun3_map_test_end)) {
- send_fault_sig(&fp->ptregs);
- return;
- }
-
- printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
- ssw & RW ? "read" : "write",
- fp->un.fmtb.daddr,
- space_names[ssw & DFC], fp->ptregs.pc);
- }
- printk ("BAD KERNEL BUSERR\n");
-
- die_if_kernel("Oops", &fp->ptregs,0);
- force_sig(SIGKILL, current);
- return;
- }
- } else {
- /* user fault */
- if (!(ssw & (FC | FB)) && !(ssw & DF))
- /* not an instruction fault or data fault! BAD */
- panic ("USER BUSERR w/o instruction or data fault");
- }
-
-
- /* First handle the data fault, if any. */
- if (ssw & DF) {
- addr = fp->un.fmtb.daddr;
-
-// errorcode bit 0: 0 -> no page 1 -> protection fault
-// errorcode bit 1: 0 -> read fault 1 -> write fault
-
-// (buserr_type & SUN3_BUSERR_PROTERR) -> protection fault
-// (buserr_type & SUN3_BUSERR_INVALID) -> invalid page fault
-
- if (buserr_type & SUN3_BUSERR_PROTERR)
- errorcode = 0x01;
- else if (buserr_type & SUN3_BUSERR_INVALID)
- errorcode = 0x00;
- else {
-#ifdef DEBUG
- printk ("*** unexpected busfault type=%#04x\n", buserr_type);
- printk ("invalid %s access at %#lx from pc %#lx\n",
- !(ssw & RW) ? "write" : "read", addr,
- fp->ptregs.pc);
-#endif
- die_if_kernel ("Oops", &fp->ptregs, buserr_type);
- force_sig (SIGBUS, current);
- return;
- }
-
-//todo: wtf is RM bit? --m
- if (!(ssw & RW) || ssw & RM)
- errorcode |= 0x02;
-
- /* Handle page fault. */
- do_page_fault (&fp->ptregs, addr, errorcode);
-
- /* Retry the data fault now. */
- return;
- }
-
- /* Now handle the instruction fault. */
-
- /* Get the fault address. */
- if (fp->ptregs.format == 0xA)
- addr = fp->ptregs.pc + 4;
- else
- addr = fp->un.fmtb.baddr;
- if (ssw & FC)
- addr -= 2;
-
- if (buserr_type & SUN3_BUSERR_INVALID) {
- if (!mmu_emu_handle_fault (fp->un.fmtb.daddr, 1, 0))
- do_page_fault (&fp->ptregs, addr, 0);
- } else {
-#ifdef DEBUG
- printk ("protection fault on insn access (segv).\n");
-#endif
- force_sig (SIGSEGV, current);
- }
-}
-#else
-#if defined(CPU_M68020_OR_M68030)
-static inline void bus_error030 (struct frame *fp)
-{
- volatile unsigned short temp;
- unsigned short mmusr;
- unsigned long addr, errorcode;
- unsigned short ssw = fp->un.fmtb.ssw;
-#ifdef DEBUG
- unsigned long desc;
-
- printk ("pid = %x ", current->pid);
- printk ("SSW=%#06x ", ssw);
-
- if (ssw & (FC | FB))
- printk ("Instruction fault at %#010lx\n",
- ssw & FC ?
- fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2
- :
- fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
- if (ssw & DF)
- printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
- ssw & RW ? "read" : "write",
- fp->un.fmtb.daddr,
- space_names[ssw & DFC], fp->ptregs.pc);
-#endif
-
- /* ++andreas: If a data fault and an instruction fault happen
- at the same time map in both pages. */
-
- /* First handle the data fault, if any. */
- if (ssw & DF) {
- addr = fp->un.fmtb.daddr;
-
-#ifdef DEBUG
- asm volatile ("ptestr %3,%2@,#7,%0\n\t"
- "pmove %%psr,%1@"
- : "=a&" (desc)
- : "a" (&temp), "a" (addr), "d" (ssw));
-#else
- asm volatile ("ptestr %2,%1@,#7\n\t"
- "pmove %%psr,%0@"
- : : "a" (&temp), "a" (addr), "d" (ssw));
-#endif
- mmusr = temp;
-
-#ifdef DEBUG
- printk("mmusr is %#x for addr %#lx in task %p\n",
- mmusr, addr, current);
- printk("descriptor address is %#lx, contents %#lx\n",
- __va(desc), *(unsigned long *)__va(desc));
-#endif
-
- errorcode = (mmusr & MMU_I) ? 0 : 1;
- if (!(ssw & RW) || (ssw & RM))
- errorcode |= 2;
-
- if (mmusr & (MMU_I | MMU_WP)) {
- if (ssw & 4) {
- printk("Data %s fault at %#010lx in %s (pc=%#lx)\n",
- ssw & RW ? "read" : "write",
- fp->un.fmtb.daddr,
- space_names[ssw & DFC], fp->ptregs.pc);
- goto buserr;
- }
- /* Don't try to do anything further if an exception was
- handled. */
- if (do_page_fault (&fp->ptregs, addr, errorcode) < 0)
- return;
- } else if (!(mmusr & MMU_I)) {
- /* probably a 020 cas fault */
- if (!(ssw & RM) && send_fault_sig(&fp->ptregs) > 0)
- printk("unexpected bus error (%#x,%#x)\n", ssw, mmusr);
- } else if (mmusr & (MMU_B|MMU_L|MMU_S)) {
- printk("invalid %s access at %#lx from pc %#lx\n",
- !(ssw & RW) ? "write" : "read", addr,
- fp->ptregs.pc);
- die_if_kernel("Oops",&fp->ptregs,mmusr);
- force_sig(SIGSEGV, current);
- return;
- } else {
-#if 0
- static volatile long tlong;
-#endif
-
- printk("weird %s access at %#lx from pc %#lx (ssw is %#x)\n",
- !(ssw & RW) ? "write" : "read", addr,
- fp->ptregs.pc, ssw);
- asm volatile ("ptestr #1,%1@,#0\n\t"
- "pmove %%psr,%0@"
- : /* no outputs */
- : "a" (&temp), "a" (addr));
- mmusr = temp;
-
- printk ("level 0 mmusr is %#x\n", mmusr);
-#if 0
- asm volatile ("pmove %%tt0,%0@"
- : /* no outputs */
- : "a" (&tlong));
- printk("tt0 is %#lx, ", tlong);
- asm volatile ("pmove %%tt1,%0@"
- : /* no outputs */
- : "a" (&tlong));
- printk("tt1 is %#lx\n", tlong);
-#endif
-#ifdef DEBUG
- printk("Unknown SIGSEGV - 1\n");
-#endif
- die_if_kernel("Oops",&fp->ptregs,mmusr);
- force_sig(SIGSEGV, current);
- return;
- }
-
- /* setup an ATC entry for the access about to be retried */
- if (!(ssw & RW) || (ssw & RM))
- asm volatile ("ploadw %1,%0@" : /* no outputs */
- : "a" (addr), "d" (ssw));
- else
- asm volatile ("ploadr %1,%0@" : /* no outputs */
- : "a" (addr), "d" (ssw));
- }
-
- /* Now handle the instruction fault. */
-
- if (!(ssw & (FC|FB)))
- return;
-
- if (fp->ptregs.sr & PS_S) {
- printk("Instruction fault at %#010lx\n",
- fp->ptregs.pc);
- buserr:
- printk ("BAD KERNEL BUSERR\n");
- die_if_kernel("Oops",&fp->ptregs,0);
- force_sig(SIGKILL, current);
- return;
- }
-
- /* get the fault address */
- if (fp->ptregs.format == 10)
- addr = fp->ptregs.pc + 4;
- else
- addr = fp->un.fmtb.baddr;
- if (ssw & FC)
- addr -= 2;
-
- if ((ssw & DF) && ((addr ^ fp->un.fmtb.daddr) & PAGE_MASK) == 0)
- /* Insn fault on same page as data fault. But we
- should still create the ATC entry. */
- goto create_atc_entry;
-
-#ifdef DEBUG
- asm volatile ("ptestr #1,%2@,#7,%0\n\t"
- "pmove %%psr,%1@"
- : "=a&" (desc)
- : "a" (&temp), "a" (addr));
-#else
- asm volatile ("ptestr #1,%1@,#7\n\t"
- "pmove %%psr,%0@"
- : : "a" (&temp), "a" (addr));
-#endif
- mmusr = temp;
-
-#ifdef DEBUG
- printk ("mmusr is %#x for addr %#lx in task %p\n",
- mmusr, addr, current);
- printk ("descriptor address is %#lx, contents %#lx\n",
- __va(desc), *(unsigned long *)__va(desc));
-#endif
-
- if (mmusr & MMU_I)
- do_page_fault (&fp->ptregs, addr, 0);
- else if (mmusr & (MMU_B|MMU_L|MMU_S)) {
- printk ("invalid insn access at %#lx from pc %#lx\n",
- addr, fp->ptregs.pc);
-#ifdef DEBUG
- printk("Unknown SIGSEGV - 2\n");
-#endif
- die_if_kernel("Oops",&fp->ptregs,mmusr);
- force_sig(SIGSEGV, current);
- return;
- }
-
-create_atc_entry:
- /* setup an ATC entry for the access about to be retried */
- asm volatile ("ploadr #2,%0@" : /* no outputs */
- : "a" (addr));
-}
-#endif /* CPU_M68020_OR_M68030 */
-#endif /* !CONFIG_SUN3 */
-
-asmlinkage void buserr_c(struct frame *fp)
-{
- /* Only set esp0 if coming from user mode */
- if (user_mode(&fp->ptregs))
- current->thread.esp0 = (unsigned long) fp;
-
-#ifdef DEBUG
- printk ("*** Bus Error *** Format is %x\n", fp->ptregs.format);
-#endif
-
- switch (fp->ptregs.format) {
-#if defined (CONFIG_M68060)
- case 4: /* 68060 access error */
- access_error060 (fp);
- break;
-#endif
-#if defined (CONFIG_M68040)
- case 0x7: /* 68040 access error */
- access_error040 (fp);
- break;
-#endif
-#if defined (CPU_M68020_OR_M68030)
- case 0xa:
- case 0xb:
- bus_error030 (fp);
- break;
-#endif
- default:
- die_if_kernel("bad frame format",&fp->ptregs,0);
-#ifdef DEBUG
- printk("Unknown SIGSEGV - 4\n");
-#endif
- force_sig(SIGSEGV, current);
- }
-}
-
-
-static int kstack_depth_to_print = 48;
-
-void show_trace(unsigned long *stack)
-{
- unsigned long *endstack;
- unsigned long addr;
- int i;
-
- printk("Call Trace:");
- addr = (unsigned long)stack + THREAD_SIZE - 1;
- endstack = (unsigned long *)(addr & -THREAD_SIZE);
- i = 0;
- while (stack + 1 <= endstack) {
- addr = *stack++;
- /*
- * If the address is either in the text segment of the
- * kernel, or in the region which contains vmalloc'ed
- * memory, it *may* be the address of a calling
- * routine; if so, print it so that someone tracing
- * down the cause of the crash will be able to figure
- * out the call path that was taken.
- */
- if (__kernel_text_address(addr)) {
-#ifndef CONFIG_KALLSYMS
- if (i % 5 == 0)
- printk("\n ");
-#endif
- printk(" [<%08lx>] %pS\n", addr, (void *)addr);
- i++;
- }
- }
- printk("\n");
-}
-
-void show_registers(struct pt_regs *regs)
-{
- struct frame *fp = (struct frame *)regs;
- mm_segment_t old_fs = get_fs();
- u16 c, *cp;
- unsigned long addr;
- int i;
-
- print_modules();
- printk("PC: [<%08lx>] %pS\n", regs->pc, (void *)regs->pc);
- printk("SR: %04x SP: %p a2: %08lx\n", regs->sr, regs, regs->a2);
- printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
- regs->d0, regs->d1, regs->d2, regs->d3);
- printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n",
- regs->d4, regs->d5, regs->a0, regs->a1);
-
- printk("Process %s (pid: %d, task=%p)\n",
- current->comm, task_pid_nr(current), current);
- addr = (unsigned long)&fp->un;
- printk("Frame format=%X ", regs->format);
- switch (regs->format) {
- case 0x2:
- printk("instr addr=%08lx\n", fp->un.fmt2.iaddr);
- addr += sizeof(fp->un.fmt2);
- break;
- case 0x3:
- printk("eff addr=%08lx\n", fp->un.fmt3.effaddr);
- addr += sizeof(fp->un.fmt3);
- break;
- case 0x4:
- printk((CPU_IS_060 ? "fault addr=%08lx fslw=%08lx\n"
- : "eff addr=%08lx pc=%08lx\n"),
- fp->un.fmt4.effaddr, fp->un.fmt4.pc);
- addr += sizeof(fp->un.fmt4);
- break;
- case 0x7:
- printk("eff addr=%08lx ssw=%04x faddr=%08lx\n",
- fp->un.fmt7.effaddr, fp->un.fmt7.ssw, fp->un.fmt7.faddr);
- printk("wb 1 stat/addr/data: %04x %08lx %08lx\n",
- fp->un.fmt7.wb1s, fp->un.fmt7.wb1a, fp->un.fmt7.wb1dpd0);
- printk("wb 2 stat/addr/data: %04x %08lx %08lx\n",
- fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d);
- printk("wb 3 stat/addr/data: %04x %08lx %08lx\n",
- fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d);
- printk("push data: %08lx %08lx %08lx %08lx\n",
- fp->un.fmt7.wb1dpd0, fp->un.fmt7.pd1, fp->un.fmt7.pd2,
- fp->un.fmt7.pd3);
- addr += sizeof(fp->un.fmt7);
- break;
- case 0x9:
- printk("instr addr=%08lx\n", fp->un.fmt9.iaddr);
- addr += sizeof(fp->un.fmt9);
- break;
- case 0xa:
- printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
- fp->un.fmta.ssw, fp->un.fmta.isc, fp->un.fmta.isb,
- fp->un.fmta.daddr, fp->un.fmta.dobuf);
- addr += sizeof(fp->un.fmta);
- break;
- case 0xb:
- printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
- fp->un.fmtb.ssw, fp->un.fmtb.isc, fp->un.fmtb.isb,
- fp->un.fmtb.daddr, fp->un.fmtb.dobuf);
- printk("baddr=%08lx dibuf=%08lx ver=%x\n",
- fp->un.fmtb.baddr, fp->un.fmtb.dibuf, fp->un.fmtb.ver);
- addr += sizeof(fp->un.fmtb);
- break;
- default:
- printk("\n");
- }
- show_stack(NULL, (unsigned long *)addr);
-
- printk("Code:");
- set_fs(KERNEL_DS);
- cp = (u16 *)regs->pc;
- for (i = -8; i < 16; i++) {
- if (get_user(c, cp + i) && i >= 0) {
- printk(" Bad PC value.");
- break;
- }
- printk(i ? " %04x" : " <%04x>", c);
- }
- set_fs(old_fs);
- printk ("\n");
-}
-
-void show_stack(struct task_struct *task, unsigned long *stack)
-{
- unsigned long *p;
- unsigned long *endstack;
- int i;
-
- if (!stack) {
- if (task)
- stack = (unsigned long *)task->thread.esp0;
- else
- stack = (unsigned long *)&stack;
- }
- endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) & -THREAD_SIZE);
-
- printk("Stack from %08lx:", (unsigned long)stack);
- p = stack;
- for (i = 0; i < kstack_depth_to_print; i++) {
- if (p + 1 > endstack)
- break;
- if (i % 8 == 0)
- printk("\n ");
- printk(" %08lx", *p++);
- }
- printk("\n");
- show_trace(stack);
-}
-
-/*
- * The architecture-independent backtrace generator
- */
-void dump_stack(void)
-{
- unsigned long stack;
-
- show_trace(&stack);
-}
-
-EXPORT_SYMBOL(dump_stack);
-
-void bad_super_trap (struct frame *fp)
-{
- console_verbose();
- if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names))
- printk ("*** %s *** FORMAT=%X\n",
- vec_names[(fp->ptregs.vector) >> 2],
- fp->ptregs.format);
- else
- printk ("*** Exception %d *** FORMAT=%X\n",
- (fp->ptregs.vector) >> 2,
- fp->ptregs.format);
- if (fp->ptregs.vector >> 2 == VEC_ADDRERR && CPU_IS_020_OR_030) {
- unsigned short ssw = fp->un.fmtb.ssw;
-
- printk ("SSW=%#06x ", ssw);
-
- if (ssw & RC)
- printk ("Pipe stage C instruction fault at %#010lx\n",
- (fp->ptregs.format) == 0xA ?
- fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2);
- if (ssw & RB)
- printk ("Pipe stage B instruction fault at %#010lx\n",
- (fp->ptregs.format) == 0xA ?
- fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
- if (ssw & DF)
- printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
- ssw & RW ? "read" : "write",
- fp->un.fmtb.daddr, space_names[ssw & DFC],
- fp->ptregs.pc);
- }
- printk ("Current process id is %d\n", task_pid_nr(current));
- die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
-}
-
-asmlinkage void trap_c(struct frame *fp)
-{
- int sig;
- siginfo_t info;
-
- if (fp->ptregs.sr & PS_S) {
- if (fp->ptregs.vector == VEC_TRACE << 2) {
- /* traced a trapping instruction on a 68020/30,
- * real exception will be executed afterwards.
- */
- } else if (!handle_kernel_fault(&fp->ptregs))
- bad_super_trap(fp);
- return;
- }
-
- /* send the appropriate signal to the user program */
- switch ((fp->ptregs.vector) >> 2) {
- case VEC_ADDRERR:
- info.si_code = BUS_ADRALN;
- sig = SIGBUS;
- break;
- case VEC_ILLEGAL:
- case VEC_LINE10:
- case VEC_LINE11:
- info.si_code = ILL_ILLOPC;
- sig = SIGILL;
- break;
- case VEC_PRIV:
- info.si_code = ILL_PRVOPC;
- sig = SIGILL;
- break;
- case VEC_COPROC:
- info.si_code = ILL_COPROC;
- sig = SIGILL;
- break;
- case VEC_TRAP1:
- case VEC_TRAP2:
- case VEC_TRAP3:
- case VEC_TRAP4:
- case VEC_TRAP5:
- case VEC_TRAP6:
- case VEC_TRAP7:
- case VEC_TRAP8:
- case VEC_TRAP9:
- case VEC_TRAP10:
- case VEC_TRAP11:
- case VEC_TRAP12:
- case VEC_TRAP13:
- case VEC_TRAP14:
- info.si_code = ILL_ILLTRP;
- sig = SIGILL;
- break;
- case VEC_FPBRUC:
- case VEC_FPOE:
- case VEC_FPNAN:
- info.si_code = FPE_FLTINV;
- sig = SIGFPE;
- break;
- case VEC_FPIR:
- info.si_code = FPE_FLTRES;
- sig = SIGFPE;
- break;
- case VEC_FPDIVZ:
- info.si_code = FPE_FLTDIV;
- sig = SIGFPE;
- break;
- case VEC_FPUNDER:
- info.si_code = FPE_FLTUND;
- sig = SIGFPE;
- break;
- case VEC_FPOVER:
- info.si_code = FPE_FLTOVF;
- sig = SIGFPE;
- break;
- case VEC_ZERODIV:
- info.si_code = FPE_INTDIV;
- sig = SIGFPE;
- break;
- case VEC_CHK:
- case VEC_TRAP:
- info.si_code = FPE_INTOVF;
- sig = SIGFPE;
- break;
- case VEC_TRACE: /* ptrace single step */
- info.si_code = TRAP_TRACE;
- sig = SIGTRAP;
- break;
- case VEC_TRAP15: /* breakpoint */
- info.si_code = TRAP_BRKPT;
- sig = SIGTRAP;
- break;
- default:
- info.si_code = ILL_ILLOPC;
- sig = SIGILL;
- break;
- }
- info.si_signo = sig;
- info.si_errno = 0;
- switch (fp->ptregs.format) {
- default:
- info.si_addr = (void *) fp->ptregs.pc;
- break;
- case 2:
- info.si_addr = (void *) fp->un.fmt2.iaddr;
- break;
- case 7:
- info.si_addr = (void *) fp->un.fmt7.effaddr;
- break;
- case 9:
- info.si_addr = (void *) fp->un.fmt9.iaddr;
- break;
- case 10:
- info.si_addr = (void *) fp->un.fmta.daddr;
- break;
- case 11:
- info.si_addr = (void *) fp->un.fmtb.daddr;
- break;
- }
- force_sig_info (sig, &info, current);
-}
-
-void die_if_kernel (char *str, struct pt_regs *fp, int nr)
-{
- if (!(fp->sr & PS_S))
- return;
-
- console_verbose();
- printk("%s: %08x\n",str,nr);
- show_registers(fp);
- add_taint(TAINT_DIE);
- do_exit(SIGSEGV);
-}
-
-/*
- * This function is called if an error occur while accessing
- * user-space from the fpsp040 code.
- */
-asmlinkage void fpsp040_die(void)
-{
- do_exit(SIGSEGV);
-}
-
-#ifdef CONFIG_M68KFPU_EMU
-asmlinkage void fpemu_signal(int signal, int code, void *addr)
-{
- siginfo_t info;
-
- info.si_signo = signal;
- info.si_errno = 0;
- info.si_code = code;
- info.si_addr = addr;
- force_sig_info(signal, &info, current);
-}
-#endif
diff --git a/arch/m68k/kernel/traps_no.c b/arch/m68k/kernel/traps_no.c
deleted file mode 100644
index e67b8c806959..000000000000
--- a/arch/m68k/kernel/traps_no.c
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- * linux/arch/m68knommu/kernel/traps.c
- *
- * Copyright (C) 1993, 1994 by Hamish Macdonald
- *
- * 68040 fixes by Michael Rausch
- * 68040 fixes by Martin Apel
- * 68060 fixes by Roman Hodek
- * 68060 fixes by Jesper Skov
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-/*
- * Sets up all exception vectors
- */
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/user.h>
-#include <linux/string.h>
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <linux/ptrace.h>
-#include <linux/kallsyms.h>
-
-#include <asm/setup.h>
-#include <asm/fpu.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/traps.h>
-#include <asm/pgtable.h>
-#include <asm/machdep.h>
-#include <asm/siginfo.h>
-
-static char const * const vec_names[] = {
- "RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR",
- "ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc",
- "PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111",
- "UNASSIGNED RESERVED 12", "COPROCESSOR PROTOCOL VIOLATION",
- "FORMAT ERROR", "UNINITIALIZED INTERRUPT",
- "UNASSIGNED RESERVED 16", "UNASSIGNED RESERVED 17",
- "UNASSIGNED RESERVED 18", "UNASSIGNED RESERVED 19",
- "UNASSIGNED RESERVED 20", "UNASSIGNED RESERVED 21",
- "UNASSIGNED RESERVED 22", "UNASSIGNED RESERVED 23",
- "SPURIOUS INTERRUPT", "LEVEL 1 INT", "LEVEL 2 INT", "LEVEL 3 INT",
- "LEVEL 4 INT", "LEVEL 5 INT", "LEVEL 6 INT", "LEVEL 7 INT",
- "SYSCALL", "TRAP #1", "TRAP #2", "TRAP #3",
- "TRAP #4", "TRAP #5", "TRAP #6", "TRAP #7",
- "TRAP #8", "TRAP #9", "TRAP #10", "TRAP #11",
- "TRAP #12", "TRAP #13", "TRAP #14", "TRAP #15",
- "FPCP BSUN", "FPCP INEXACT", "FPCP DIV BY 0", "FPCP UNDERFLOW",
- "FPCP OPERAND ERROR", "FPCP OVERFLOW", "FPCP SNAN",
- "FPCP UNSUPPORTED OPERATION",
- "MMU CONFIGURATION ERROR"
-};
-
-void die_if_kernel(char *str, struct pt_regs *fp, int nr)
-{
- if (!(fp->sr & PS_S))
- return;
-
- console_verbose();
- printk(KERN_EMERG "%s: %08x\n",str,nr);
- printk(KERN_EMERG "PC: [<%08lx>]\nSR: %04x SP: %p a2: %08lx\n",
- fp->pc, fp->sr, fp, fp->a2);
- printk(KERN_EMERG "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
- fp->d0, fp->d1, fp->d2, fp->d3);
- printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n",
- fp->d4, fp->d5, fp->a0, fp->a1);
-
- printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n",
- current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
- show_stack(NULL, (unsigned long *)(fp + 1));
- add_taint(TAINT_DIE);
- do_exit(SIGSEGV);
-}
-
-asmlinkage void buserr_c(struct frame *fp)
-{
- /* Only set esp0 if coming from user mode */
- if (user_mode(&fp->ptregs))
- current->thread.esp0 = (unsigned long) fp;
-
-#if defined(DEBUG)
- printk (KERN_DEBUG "*** Bus Error *** Format is %x\n", fp->ptregs.format);
-#endif
-
- die_if_kernel("bad frame format",&fp->ptregs,0);
-#if defined(DEBUG)
- printk(KERN_DEBUG "Unknown SIGSEGV - 4\n");
-#endif
- force_sig(SIGSEGV, current);
-}
-
-static void print_this_address(unsigned long addr, int i)
-{
-#ifdef CONFIG_KALLSYMS
- printk(KERN_EMERG " [%08lx] ", addr);
- print_symbol(KERN_CONT "%s\n", addr);
-#else
- if (i % 5)
- printk(KERN_CONT " [%08lx] ", addr);
- else
- printk(KERN_EMERG " [%08lx] ", addr);
- i++;
-#endif
-}
-
-int kstack_depth_to_print = 48;
-
-static void __show_stack(struct task_struct *task, unsigned long *stack)
-{
- unsigned long *endstack, addr;
-#ifdef CONFIG_FRAME_POINTER
- unsigned long *last_stack;
-#endif
- int i;
-
- if (!stack)
- stack = (unsigned long *)task->thread.ksp;
-
- addr = (unsigned long) stack;
- endstack = (unsigned long *) PAGE_ALIGN(addr);
-
- printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
- for (i = 0; i < kstack_depth_to_print; i++) {
- if (stack + 1 + i > endstack)
- break;
- if (i % 8 == 0)
- printk(KERN_EMERG " ");
- printk(KERN_CONT " %08lx", *(stack + i));
- }
- printk("\n");
- i = 0;
-
-#ifdef CONFIG_FRAME_POINTER
- printk(KERN_EMERG "Call Trace:\n");
-
- last_stack = stack - 1;
- while (stack <= endstack && stack > last_stack) {
-
- addr = *(stack + 1);
- print_this_address(addr, i);
- i++;
-
- last_stack = stack;
- stack = (unsigned long *)*stack;
- }
- printk("\n");
-#else
- printk(KERN_EMERG "Call Trace with CONFIG_FRAME_POINTER disabled:\n");
- while (stack <= endstack) {
- addr = *stack++;
- /*
- * If the address is either in the text segment of the kernel,
- * or in a region which is occupied by a module then it *may*
- * be the address of a calling routine; if so, print it so that
- * someone tracing down the cause of the crash will be able to
- * figure out the call path that was taken.
- */
- if (__kernel_text_address(addr)) {
- print_this_address(addr, i);
- i++;
- }
- }
- printk(KERN_CONT "\n");
-#endif
-}
-
-void bad_super_trap(struct frame *fp)
-{
- int vector = (fp->ptregs.vector >> 2) & 0xff;
-
- console_verbose();
- if (vector < ARRAY_SIZE(vec_names))
- printk (KERN_WARNING "*** %s *** FORMAT=%X\n",
- vec_names[vector],
- fp->ptregs.format);
- else
- printk (KERN_WARNING "*** Exception %d *** FORMAT=%X\n",
- vector,
- fp->ptregs.format);
- printk (KERN_WARNING "Current process id is %d\n", current->pid);
- die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
-}
-
-asmlinkage void trap_c(struct frame *fp)
-{
- int sig;
- int vector = (fp->ptregs.vector >> 2) & 0xff;
- siginfo_t info;
-
- if (fp->ptregs.sr & PS_S) {
- if (vector == VEC_TRACE) {
- /* traced a trapping instruction */
- } else
- bad_super_trap(fp);
- return;
- }
-
- /* send the appropriate signal to the user program */
- switch (vector) {
- case VEC_ADDRERR:
- info.si_code = BUS_ADRALN;
- sig = SIGBUS;
- break;
- case VEC_ILLEGAL:
- case VEC_LINE10:
- case VEC_LINE11:
- info.si_code = ILL_ILLOPC;
- sig = SIGILL;
- break;
- case VEC_PRIV:
- info.si_code = ILL_PRVOPC;
- sig = SIGILL;
- break;
- case VEC_COPROC:
- info.si_code = ILL_COPROC;
- sig = SIGILL;
- break;
- case VEC_TRAP1: /* gdbserver breakpoint */
- fp->ptregs.pc -= 2;
- info.si_code = TRAP_TRACE;
- sig = SIGTRAP;
- break;
- case VEC_TRAP2:
- case VEC_TRAP3:
- case VEC_TRAP4:
- case VEC_TRAP5:
- case VEC_TRAP6:
- case VEC_TRAP7:
- case VEC_TRAP8:
- case VEC_TRAP9:
- case VEC_TRAP10:
- case VEC_TRAP11:
- case VEC_TRAP12:
- case VEC_TRAP13:
- case VEC_TRAP14:
- info.si_code = ILL_ILLTRP;
- sig = SIGILL;
- break;
- case VEC_FPBRUC:
- case VEC_FPOE:
- case VEC_FPNAN:
- info.si_code = FPE_FLTINV;
- sig = SIGFPE;
- break;
- case VEC_FPIR:
- info.si_code = FPE_FLTRES;
- sig = SIGFPE;
- break;
- case VEC_FPDIVZ:
- info.si_code = FPE_FLTDIV;
- sig = SIGFPE;
- break;
- case VEC_FPUNDER:
- info.si_code = FPE_FLTUND;
- sig = SIGFPE;
- break;
- case VEC_FPOVER:
- info.si_code = FPE_FLTOVF;
- sig = SIGFPE;
- break;
- case VEC_ZERODIV:
- info.si_code = FPE_INTDIV;
- sig = SIGFPE;
- break;
- case VEC_CHK:
- case VEC_TRAP:
- info.si_code = FPE_INTOVF;
- sig = SIGFPE;
- break;
- case VEC_TRACE: /* ptrace single step */
- info.si_code = TRAP_TRACE;
- sig = SIGTRAP;
- break;
- case VEC_TRAP15: /* breakpoint */
- info.si_code = TRAP_BRKPT;
- sig = SIGTRAP;
- break;
- default:
- info.si_code = ILL_ILLOPC;
- sig = SIGILL;
- break;
- }
- info.si_signo = sig;
- info.si_errno = 0;
- switch (fp->ptregs.format) {
- default:
- info.si_addr = (void *) fp->ptregs.pc;
- break;
- case 2:
- info.si_addr = (void *) fp->un.fmt2.iaddr;
- break;
- case 7:
- info.si_addr = (void *) fp->un.fmt7.effaddr;
- break;
- case 9:
- info.si_addr = (void *) fp->un.fmt9.iaddr;
- break;
- case 10:
- info.si_addr = (void *) fp->un.fmta.daddr;
- break;
- case 11:
- info.si_addr = (void *) fp->un.fmtb.daddr;
- break;
- }
- force_sig_info (sig, &info, current);
-}
-
-asmlinkage void set_esp0(unsigned long ssp)
-{
- current->thread.esp0 = ssp;
-}
-
-/*
- * The architecture-independent backtrace generator
- */
-void dump_stack(void)
-{
- /*
- * We need frame pointers for this little trick, which works as follows:
- *
- * +------------+ 0x00
- * | Next SP | -> 0x0c
- * +------------+ 0x04
- * | Caller |
- * +------------+ 0x08
- * | Local vars | -> our stack var
- * +------------+ 0x0c
- * | Next SP | -> 0x18, that is what we pass to show_stack()
- * +------------+ 0x10
- * | Caller |
- * +------------+ 0x14
- * | Local vars |
- * +------------+ 0x18
- * | ... |
- * +------------+
- */
-
- unsigned long *stack;
-
- stack = (unsigned long *)&stack;
- stack++;
- __show_stack(current, stack);
-}
-EXPORT_SYMBOL(dump_stack);
-
-void show_stack(struct task_struct *task, unsigned long *stack)
-{
- if (!stack && !task)
- dump_stack();
- else
- __show_stack(task, stack);
-}
diff --git a/arch/m68k/kernel/vectors.c b/arch/m68k/kernel/vectors.c
new file mode 100644
index 000000000000..147b03fbc71e
--- /dev/null
+++ b/arch/m68k/kernel/vectors.c
@@ -0,0 +1,145 @@
+/*
+ * vectors.c
+ *
+ * Copyright (C) 1993, 1994 by Hamish Macdonald
+ *
+ * 68040 fixes by Michael Rausch
+ * 68040 fixes by Martin Apel
+ * 68040 fixes and writeback by Richard Zidlicky
+ * 68060 fixes by Roman Hodek
+ * 68060 fixes by Jesper Skov
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+/*
+ * Sets up all exception vectors
+ */
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <linux/kallsyms.h>
+
+#include <asm/setup.h>
+#include <asm/fpu.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+
+/* assembler routines */
+asmlinkage void system_call(void);
+asmlinkage void buserr(void);
+asmlinkage void trap(void);
+asmlinkage void nmihandler(void);
+#ifdef CONFIG_M68KFPU_EMU
+asmlinkage void fpu_emu(void);
+#endif
+
+e_vector vectors[256];
+
+/* nmi handler for the Amiga */
+asm(".text\n"
+ __ALIGN_STR "\n"
+ "nmihandler: rte");
+
+/*
+ * this must be called very early as the kernel might
+ * use some instruction that are emulated on the 060
+ * and so we're prepared for early probe attempts (e.g. nf_init).
+ */
+void __init base_trap_init(void)
+{
+ if (MACH_IS_SUN3X) {
+ extern e_vector *sun3x_prom_vbr;
+
+ __asm__ volatile ("movec %%vbr, %0" : "=r" (sun3x_prom_vbr));
+ }
+
+ /* setup the exception vector table */
+ __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
+
+ if (CPU_IS_060) {
+ /* set up ISP entry points */
+ asmlinkage void unimp_vec(void) asm ("_060_isp_unimp");
+
+ vectors[VEC_UNIMPII] = unimp_vec;
+ }
+
+ vectors[VEC_BUSERR] = buserr;
+ vectors[VEC_ILLEGAL] = trap;
+ vectors[VEC_SYS] = system_call;
+}
+
+void __init trap_init (void)
+{
+ int i;
+
+ for (i = VEC_SPUR; i <= VEC_INT7; i++)
+ vectors[i] = bad_inthandler;
+
+ for (i = 0; i < VEC_USER; i++)
+ if (!vectors[i])
+ vectors[i] = trap;
+
+ for (i = VEC_USER; i < 256; i++)
+ vectors[i] = bad_inthandler;
+
+#ifdef CONFIG_M68KFPU_EMU
+ if (FPU_IS_EMU)
+ vectors[VEC_LINE11] = fpu_emu;
+#endif
+
+ if (CPU_IS_040 && !FPU_IS_EMU) {
+ /* set up FPSP entry points */
+ asmlinkage void dz_vec(void) asm ("dz");
+ asmlinkage void inex_vec(void) asm ("inex");
+ asmlinkage void ovfl_vec(void) asm ("ovfl");
+ asmlinkage void unfl_vec(void) asm ("unfl");
+ asmlinkage void snan_vec(void) asm ("snan");
+ asmlinkage void operr_vec(void) asm ("operr");
+ asmlinkage void bsun_vec(void) asm ("bsun");
+ asmlinkage void fline_vec(void) asm ("fline");
+ asmlinkage void unsupp_vec(void) asm ("unsupp");
+
+ vectors[VEC_FPDIVZ] = dz_vec;
+ vectors[VEC_FPIR] = inex_vec;
+ vectors[VEC_FPOVER] = ovfl_vec;
+ vectors[VEC_FPUNDER] = unfl_vec;
+ vectors[VEC_FPNAN] = snan_vec;
+ vectors[VEC_FPOE] = operr_vec;
+ vectors[VEC_FPBRUC] = bsun_vec;
+ vectors[VEC_LINE11] = fline_vec;
+ vectors[VEC_FPUNSUP] = unsupp_vec;
+ }
+
+ if (CPU_IS_060 && !FPU_IS_EMU) {
+ /* set up IFPSP entry points */
+ asmlinkage void snan_vec6(void) asm ("_060_fpsp_snan");
+ asmlinkage void operr_vec6(void) asm ("_060_fpsp_operr");
+ asmlinkage void ovfl_vec6(void) asm ("_060_fpsp_ovfl");
+ asmlinkage void unfl_vec6(void) asm ("_060_fpsp_unfl");
+ asmlinkage void dz_vec6(void) asm ("_060_fpsp_dz");
+ asmlinkage void inex_vec6(void) asm ("_060_fpsp_inex");
+ asmlinkage void fline_vec6(void) asm ("_060_fpsp_fline");
+ asmlinkage void unsupp_vec6(void) asm ("_060_fpsp_unsupp");
+ asmlinkage void effadd_vec6(void) asm ("_060_fpsp_effadd");
+
+ vectors[VEC_FPNAN] = snan_vec6;
+ vectors[VEC_FPOE] = operr_vec6;
+ vectors[VEC_FPOVER] = ovfl_vec6;
+ vectors[VEC_FPUNDER] = unfl_vec6;
+ vectors[VEC_FPDIVZ] = dz_vec6;
+ vectors[VEC_FPIR] = inex_vec6;
+ vectors[VEC_LINE11] = fline_vec6;
+ vectors[VEC_FPUNSUP] = unsupp_vec6;
+ vectors[VEC_UNIMPEA] = effadd_vec6;
+ }
+
+ /* if running on an amiga, make the NMI interrupt do nothing */
+ if (MACH_IS_AMIGA) {
+ vectors[VEC_INT7] = nmihandler;
+ }
+}
+
diff --git a/arch/m68k/kernel/vmlinux.lds_no.S b/arch/m68k/kernel/vmlinux.lds_no.S
index 7dc4087a9545..4e2389340837 100644
--- a/arch/m68k/kernel/vmlinux.lds_no.S
+++ b/arch/m68k/kernel/vmlinux.lds_no.S
@@ -77,7 +77,6 @@ SECTIONS {
*(.rodata) *(.rodata.*)
*(__vermagic) /* Kernel version magic */
- *(__markers_strings)
*(.rodata1)
*(.rodata.str1.1)
diff --git a/arch/m68k/lib/memcpy.c b/arch/m68k/lib/memcpy.c
index 064889316974..10ca051d56b8 100644
--- a/arch/m68k/lib/memcpy.c
+++ b/arch/m68k/lib/memcpy.c
@@ -22,6 +22,15 @@ void *memcpy(void *to, const void *from, size_t n)
from = cfrom;
n--;
}
+#if defined(CONFIG_M68000)
+ if ((long)from & 1) {
+ char *cto = to;
+ const char *cfrom = from;
+ for (; n; n--)
+ *cto++ = *cfrom++;
+ return xto;
+ }
+#endif
if (n > 2 && (long)to & 2) {
short *sto = to;
const short *sfrom = from;
diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c
index 900d899f3323..f92190c159b4 100644
--- a/arch/m68k/mac/macints.c
+++ b/arch/m68k/mac/macints.c
@@ -370,7 +370,7 @@ int mac_irq_pending(unsigned int irq)
break;
case 4:
if (psc_present)
- psc_irq_pending(irq);
+ return psc_irq_pending(irq);
break;
}
return 0;
diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c
index e023fc6b37e5..eb915551de69 100644
--- a/arch/m68k/mac/misc.c
+++ b/arch/m68k/mac/misc.c
@@ -304,35 +304,41 @@ static void via_write_pram(int offset, __u8 data)
static long via_read_time(void)
{
union {
- __u8 cdata[4];
- long idata;
+ __u8 cdata[4];
+ long idata;
} result, last_result;
- int ct;
+ int count = 1;
+
+ via_pram_command(0x81, &last_result.cdata[3]);
+ via_pram_command(0x85, &last_result.cdata[2]);
+ via_pram_command(0x89, &last_result.cdata[1]);
+ via_pram_command(0x8D, &last_result.cdata[0]);
/*
* The NetBSD guys say to loop until you get the same reading
* twice in a row.
*/
- ct = 0;
- do {
- if (++ct > 10) {
- printk("via_read_time: couldn't get valid time, "
- "last read = 0x%08lx and 0x%08lx\n",
- last_result.idata, result.idata);
- break;
- }
-
- last_result.idata = result.idata;
- result.idata = 0;
-
+ while (1) {
via_pram_command(0x81, &result.cdata[3]);
via_pram_command(0x85, &result.cdata[2]);
via_pram_command(0x89, &result.cdata[1]);
via_pram_command(0x8D, &result.cdata[0]);
- } while (result.idata != last_result.idata);
- return result.idata - RTC_OFFSET;
+ if (result.idata == last_result.idata)
+ return result.idata - RTC_OFFSET;
+
+ if (++count > 10)
+ break;
+
+ last_result.idata = result.idata;
+ }
+
+ pr_err("via_read_time: failed to read a stable value; "
+ "got 0x%08lx then 0x%08lx\n",
+ last_result.idata, result.idata);
+
+ return 0;
}
/*
diff --git a/arch/m68k/mm/init_no.c b/arch/m68k/mm/init_no.c
index 50cd12cf28d9..1e33d39ca9a0 100644
--- a/arch/m68k/mm/init_no.c
+++ b/arch/m68k/mm/init_no.c
@@ -32,6 +32,7 @@
#include <linux/gfp.h>
#include <asm/setup.h>
+#include <asm/sections.h>
#include <asm/segment.h>
#include <asm/page.h>
#include <asm/pgtable.h>
@@ -44,9 +45,6 @@
*/
void *empty_zero_page;
-extern unsigned long memory_start;
-extern unsigned long memory_end;
-
/*
* paging_init() continues the virtual memory environment setup which
* was begun by the code in arch/head.S.
@@ -78,8 +76,6 @@ void __init mem_init(void)
{
int codek = 0, datak = 0, initk = 0;
unsigned long tmp;
- extern char _etext, _stext, _sdata, _ebss, __init_begin, __init_end;
- extern unsigned int _ramend, _rambase;
unsigned long len = _ramend - _rambase;
unsigned long start_mem = memory_start; /* DAVIDM - these must start at end of kernel */
unsigned long end_mem = memory_end; /* DAVIDM - this must not include kernel stack at top */
@@ -95,9 +91,9 @@ void __init mem_init(void)
/* this will put all memory onto the freelists */
totalram_pages = free_all_bootmem();
- codek = (&_etext - &_stext) >> 10;
- datak = (&_ebss - &_sdata) >> 10;
- initk = (&__init_begin - &__init_end) >> 10;
+ codek = (_etext - _stext) >> 10;
+ datak = (_ebss - _sdata) >> 10;
+ initk = (__init_begin - __init_end) >> 10;
tmp = nr_free_pages() << PAGE_SHIFT;
printk(KERN_INFO "Memory available: %luk/%luk RAM, (%dk kernel code, %dk data)\n",
@@ -129,22 +125,21 @@ void free_initmem(void)
{
#ifdef CONFIG_RAMKERNEL
unsigned long addr;
- extern char __init_begin, __init_end;
/*
* The following code should be cool even if these sections
* are not page aligned.
*/
- addr = PAGE_ALIGN((unsigned long)(&__init_begin));
+ addr = PAGE_ALIGN((unsigned long) __init_begin);
/* next to check that the page we free is not a partial page */
- for (; addr + PAGE_SIZE < (unsigned long)(&__init_end); addr +=PAGE_SIZE) {
+ for (; addr + PAGE_SIZE < ((unsigned long) __init_end); addr += PAGE_SIZE) {
ClearPageReserved(virt_to_page(addr));
init_page_count(virt_to_page(addr));
free_page(addr);
totalram_pages++;
}
pr_notice("Freeing unused kernel memory: %luk freed (0x%x - 0x%x)\n",
- (addr - PAGE_ALIGN((long) &__init_begin)) >> 10,
- (int)(PAGE_ALIGN((unsigned long)(&__init_begin))),
+ (addr - PAGE_ALIGN((unsigned long) __init_begin)) >> 10,
+ (int)(PAGE_ALIGN((unsigned long) __init_begin)),
(int)(addr - PAGE_SIZE));
#endif
}
diff --git a/arch/m68k/platform/520x/config.c b/arch/m68k/platform/520x/config.c
index 621238f1a219..8a98683f1b15 100644
--- a/arch/m68k/platform/520x/config.c
+++ b/arch/m68k/platform/520x/config.c
@@ -91,9 +91,9 @@ static struct resource m520x_qspi_resources[] = {
},
};
-#define MCFQSPI_CS0 62
-#define MCFQSPI_CS1 63
-#define MCFQSPI_CS2 44
+#define MCFQSPI_CS0 46
+#define MCFQSPI_CS1 47
+#define MCFQSPI_CS2 27
static int m520x_cs_setup(struct mcfqspi_cs_control *cs_control)
{
diff --git a/arch/m68k/platform/520x/gpio.c b/arch/m68k/platform/520x/gpio.c
index d757328563d1..9bcc3e4b60c5 100644
--- a/arch/m68k/platform/520x/gpio.c
+++ b/arch/m68k/platform/520x/gpio.c
@@ -38,42 +38,6 @@ static struct mcf_gpio_chip mcf_gpio_chips[] = {
},
{
.gpio_chip = {
- .label = "BUSCTL",
- .request = mcf_gpio_request,
- .free = mcf_gpio_free,
- .direction_input = mcf_gpio_direction_input,
- .direction_output = mcf_gpio_direction_output,
- .get = mcf_gpio_get_value,
- .set = mcf_gpio_set_value_fast,
- .base = 8,
- .ngpio = 4,
- },
- .pddr = (void __iomem *) MCFGPIO_PDDR_BUSCTL,
- .podr = (void __iomem *) MCFGPIO_PODR_BUSCTL,
- .ppdr = (void __iomem *) MCFGPIO_PPDSDR_BUSCTL,
- .setr = (void __iomem *) MCFGPIO_PPDSDR_BUSCTL,
- .clrr = (void __iomem *) MCFGPIO_PCLRR_BUSCTL,
- },
- {
- .gpio_chip = {
- .label = "BE",
- .request = mcf_gpio_request,
- .free = mcf_gpio_free,
- .direction_input = mcf_gpio_direction_input,
- .direction_output = mcf_gpio_direction_output,
- .get = mcf_gpio_get_value,
- .set = mcf_gpio_set_value_fast,
- .base = 16,
- .ngpio = 4,
- },
- .pddr = (void __iomem *) MCFGPIO_PDDR_BE,
- .podr = (void __iomem *) MCFGPIO_PODR_BE,
- .ppdr = (void __iomem *) MCFGPIO_PPDSDR_BE,
- .setr = (void __iomem *) MCFGPIO_PPDSDR_BE,
- .clrr = (void __iomem *) MCFGPIO_PCLRR_BE,
- },
- {
- .gpio_chip = {
.label = "CS",
.request = mcf_gpio_request,
.free = mcf_gpio_free,
@@ -81,7 +45,7 @@ static struct mcf_gpio_chip mcf_gpio_chips[] = {
.direction_output = mcf_gpio_direction_output,
.get = mcf_gpio_get_value,
.set = mcf_gpio_set_value_fast,
- .base = 25,
+ .base = 9,
.ngpio = 3,
},
.pddr = (void __iomem *) MCFGPIO_PDDR_CS,
@@ -99,7 +63,7 @@ static struct mcf_gpio_chip mcf_gpio_chips[] = {
.direction_output = mcf_gpio_direction_output,
.get = mcf_gpio_get_value,
.set = mcf_gpio_set_value_fast,
- .base = 32,
+ .base = 16,
.ngpio = 4,
},
.pddr = (void __iomem *) MCFGPIO_PDDR_FECI2C,
@@ -117,7 +81,7 @@ static struct mcf_gpio_chip mcf_gpio_chips[] = {
.direction_output = mcf_gpio_direction_output,
.get = mcf_gpio_get_value,
.set = mcf_gpio_set_value_fast,
- .base = 40,
+ .base = 24,
.ngpio = 4,
},
.pddr = (void __iomem *) MCFGPIO_PDDR_QSPI,
@@ -135,7 +99,7 @@ static struct mcf_gpio_chip mcf_gpio_chips[] = {
.direction_output = mcf_gpio_direction_output,
.get = mcf_gpio_get_value,
.set = mcf_gpio_set_value_fast,
- .base = 48,
+ .base = 32,
.ngpio = 4,
},
.pddr = (void __iomem *) MCFGPIO_PDDR_TIMER,
@@ -153,7 +117,7 @@ static struct mcf_gpio_chip mcf_gpio_chips[] = {
.direction_output = mcf_gpio_direction_output,
.get = mcf_gpio_get_value,
.set = mcf_gpio_set_value_fast,
- .base = 56,
+ .base = 40,
.ngpio = 8,
},
.pddr = (void __iomem *) MCFGPIO_PDDR_UART,
@@ -171,7 +135,7 @@ static struct mcf_gpio_chip mcf_gpio_chips[] = {
.direction_output = mcf_gpio_direction_output,
.get = mcf_gpio_get_value,
.set = mcf_gpio_set_value_fast,
- .base = 64,
+ .base = 48,
.ngpio = 8,
},
.pddr = (void __iomem *) MCFGPIO_PDDR_FECH,
@@ -189,7 +153,7 @@ static struct mcf_gpio_chip mcf_gpio_chips[] = {
.direction_output = mcf_gpio_direction_output,
.get = mcf_gpio_get_value,
.set = mcf_gpio_set_value_fast,
- .base = 72,
+ .base = 56,
.ngpio = 8,
},
.pddr = (void __iomem *) MCFGPIO_PDDR_FECL,
diff --git a/arch/m68k/platform/68328/Makefile b/arch/m68k/platform/68328/Makefile
index 5e5435552d56..e4dfd8fde068 100644
--- a/arch/m68k/platform/68328/Makefile
+++ b/arch/m68k/platform/68328/Makefile
@@ -2,7 +2,10 @@
# Makefile for arch/m68knommu/platform/68328.
#
-head-y = head-$(MODEL).o
+model-y := ram
+model-$(CONFIG_ROMKERNEL) := rom
+
+head-y = head-$(model-y).o
head-$(CONFIG_PILOT) = head-pilot.o
head-$(CONFIG_DRAGEN2) = head-de2.o
diff --git a/arch/m68k/platform/68328/entry.S b/arch/m68k/platform/68328/entry.S
index 293e1eba9acc..5c39b80ed7de 100644
--- a/arch/m68k/platform/68328/entry.S
+++ b/arch/m68k/platform/68328/entry.S
@@ -67,7 +67,7 @@ ret_from_signal:
jra ret_from_exception
ENTRY(system_call)
- SAVE_ALL
+ SAVE_ALL_SYS
/* save top of frame*/
pea %sp@
@@ -129,7 +129,7 @@ Lsignal_return:
* This is the main interrupt handler, responsible for calling process_int()
*/
inthandler1:
- SAVE_ALL
+ SAVE_ALL_INT
movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
@@ -140,7 +140,7 @@ inthandler1:
bra ret_from_interrupt
inthandler2:
- SAVE_ALL
+ SAVE_ALL_INT
movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
@@ -151,7 +151,7 @@ inthandler2:
bra ret_from_interrupt
inthandler3:
- SAVE_ALL
+ SAVE_ALL_INT
movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
@@ -162,7 +162,7 @@ inthandler3:
bra ret_from_interrupt
inthandler4:
- SAVE_ALL
+ SAVE_ALL_INT
movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
@@ -173,7 +173,7 @@ inthandler4:
bra ret_from_interrupt
inthandler5:
- SAVE_ALL
+ SAVE_ALL_INT
movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
@@ -184,7 +184,7 @@ inthandler5:
bra ret_from_interrupt
inthandler6:
- SAVE_ALL
+ SAVE_ALL_INT
movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
@@ -195,7 +195,7 @@ inthandler6:
bra ret_from_interrupt
inthandler7:
- SAVE_ALL
+ SAVE_ALL_INT
movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
@@ -206,7 +206,7 @@ inthandler7:
bra ret_from_interrupt
inthandler:
- SAVE_ALL
+ SAVE_ALL_INT
movew %sp@(PT_OFF_FORMATVEC), %d0
and #0x3ff, %d0
diff --git a/arch/m68k/platform/68360/Makefile b/arch/m68k/platform/68360/Makefile
index cf5af73a5789..f6f434383049 100644
--- a/arch/m68k/platform/68360/Makefile
+++ b/arch/m68k/platform/68360/Makefile
@@ -1,10 +1,12 @@
#
# Makefile for arch/m68knommu/platform/68360.
#
+model-y := ram
+model-$(CONFIG_ROMKERNEL) := rom
obj-y := config.o commproc.o entry.o ints.o
extra-y := head.o
-$(obj)/head.o: $(obj)/head-$(MODEL).o
- ln -sf head-$(MODEL).o $(obj)/head.o
+$(obj)/head.o: $(obj)/head-$(model-y).o
+ ln -sf head-$(model-y).o $(obj)/head.o
diff --git a/arch/m68k/platform/68360/entry.S b/arch/m68k/platform/68360/entry.S
index abbb89672ea0..aa47d1d49929 100644
--- a/arch/m68k/platform/68360/entry.S
+++ b/arch/m68k/platform/68360/entry.S
@@ -63,7 +63,7 @@ ret_from_signal:
jra ret_from_exception
ENTRY(system_call)
- SAVE_ALL
+ SAVE_ALL_SYS
/* save top of frame*/
pea %sp@
@@ -125,7 +125,7 @@ Lsignal_return:
* This is the main interrupt handler, responsible for calling do_IRQ()
*/
inthandler:
- SAVE_ALL
+ SAVE_ALL_INT
movew %sp@(PT_OFF_FORMATVEC), %d0
and.l #0x3ff, %d0
lsr.l #0x02, %d0
diff --git a/arch/m68k/platform/coldfire/entry.S b/arch/m68k/platform/coldfire/entry.S
index bd27242c2f43..3157461a8d1d 100644
--- a/arch/m68k/platform/coldfire/entry.S
+++ b/arch/m68k/platform/coldfire/entry.S
@@ -61,7 +61,7 @@ enosys:
bra 1f
ENTRY(system_call)
- SAVE_ALL
+ SAVE_ALL_SYS
move #0x2000,%sr /* enable intrs again */
cmpl #NR_syscalls,%d0
@@ -165,9 +165,7 @@ Lsignal_return:
* sources). Calls up to high level code to do all the work.
*/
ENTRY(inthandler)
- SAVE_ALL
- moveq #-1,%d0
- movel %d0,%sp@(PT_OFF_ORIG_D0)
+ SAVE_ALL_INT
movew %sp@(PT_OFF_FORMATVEC),%d0 /* put exception # in d0 */
andl #0x03fc,%d0 /* mask out vector only */
diff --git a/arch/m68k/q40/README b/arch/m68k/q40/README
index b26d5f55e91d..93f4c4cd3c45 100644
--- a/arch/m68k/q40/README
+++ b/arch/m68k/q40/README
@@ -31,7 +31,7 @@ drivers used by the Q40, apart from the very obvious (console etc.):
char/joystick/* # most of this should work, not
# in default config.in
block/q40ide.c # startup for ide
- ide* # see Documentation/ide.txt
+ ide* # see Documentation/ide/ide.txt
floppy.c # normal PC driver, DMA emu in asm/floppy.h
# and arch/m68k/kernel/entry.S
# see drivers/block/README.fd
diff --git a/arch/microblaze/include/asm/dma-mapping.h b/arch/microblaze/include/asm/dma-mapping.h
index 8fbb0ec10233..a569514cf19f 100644
--- a/arch/microblaze/include/asm/dma-mapping.h
+++ b/arch/microblaze/include/asm/dma-mapping.h
@@ -16,7 +16,7 @@
#define _ASM_MICROBLAZE_DMA_MAPPING_H
/*
- * See Documentation/PCI/PCI-DMA-mapping.txt and
+ * See Documentation/DMA-API-HOWTO.txt and
* Documentation/DMA-API.txt for documentation.
*/
diff --git a/arch/microblaze/kernel/syscall_table.S b/arch/microblaze/kernel/syscall_table.S
index d915a122c865..8789daa2a346 100644
--- a/arch/microblaze/kernel/syscall_table.S
+++ b/arch/microblaze/kernel/syscall_table.S
@@ -173,7 +173,7 @@ ENTRY(sys_call_table)
.long sys_ni_syscall /* sys_vm86 */
.long sys_ni_syscall /* Old sys_query_module */
.long sys_poll
- .long sys_nfsservctl
+ .long sys_ni_syscall /* old nfsservctl */
.long sys_setresgid /* 170 */
.long sys_getresgid
.long sys_prctl
diff --git a/arch/microblaze/mm/init.c b/arch/microblaze/mm/init.c
index 213f2d671669..36a133e5ee35 100644
--- a/arch/microblaze/mm/init.c
+++ b/arch/microblaze/mm/init.c
@@ -304,11 +304,11 @@ asmlinkage void __init mmu_init(void)
/* Map in all of RAM starting at CONFIG_KERNEL_START */
mapin_ram();
-#ifdef HIGHMEM_START_BOOL
- ioremap_base = HIGHMEM_START;
+#ifdef CONFIG_HIGHMEM_START_BOOL
+ ioremap_base = CONFIG_HIGHMEM_START;
#else
ioremap_base = 0xfe000000UL; /* for now, could be 0xfffff000 */
-#endif /* CONFIG_HIGHMEM */
+#endif /* CONFIG_HIGHMEM_START_BOOL */
ioremap_bot = ioremap_base;
/* Initialize the context management stuff */
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 177cdaf83564..4cbc6d8de210 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -24,6 +24,7 @@ config MIPS
select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW
select HAVE_ARCH_JUMP_LABEL
+ select IRQ_FORCED_THREADING
menu "Machine selection"
@@ -91,15 +92,8 @@ config BCM47XX
select DMA_NONCOHERENT
select HW_HAS_PCI
select IRQ_CPU
- select SYS_HAS_CPU_MIPS32_R1
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
- select SSB
- select SSB_DRIVER_MIPS
- select SSB_DRIVER_EXTIF
- select SSB_EMBEDDED
- select SSB_B43_PCI_BRIDGE if PCI
- select SSB_PCICORE_HOSTMODE if PCI
select GENERIC_GPIO
select SYS_HAS_EARLY_PRINTK
select CFE
@@ -722,6 +716,7 @@ config CAVIUM_OCTEON_SIMULATOR
select SYS_SUPPORTS_HIGHMEM
select SYS_SUPPORTS_HOTPLUG_CPU
select SYS_HAS_CPU_CAVIUM_OCTEON
+ select HOLES_IN_ZONE
help
The Octeon simulator is software performance model of the Cavium
Octeon Processor. It supports simulating Octeon processors on x86
@@ -744,6 +739,7 @@ config CAVIUM_OCTEON_REFERENCE_BOARD
select ZONE_DMA32
select USB_ARCH_HAS_OHCI
select USB_ARCH_HAS_EHCI
+ select HOLES_IN_ZONE
help
This option supports all of the Octeon reference boards from Cavium
Networks. It builds a kernel that dynamically determines the Octeon
@@ -788,6 +784,7 @@ endchoice
source "arch/mips/alchemy/Kconfig"
source "arch/mips/ath79/Kconfig"
+source "arch/mips/bcm47xx/Kconfig"
source "arch/mips/bcm63xx/Kconfig"
source "arch/mips/jazz/Kconfig"
source "arch/mips/jz4740/Kconfig"
@@ -973,6 +970,9 @@ config ISA_DMA_API
config GENERIC_GPIO
bool
+config HOLES_IN_ZONE
+ bool
+
#
# Endianess selection. Sufficiently obscure so many users don't know what to
# answer,so we try hard to limit the available choices. Also the use of a
diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c
index 3b2c18b14341..f72c48d4804c 100644
--- a/arch/mips/alchemy/common/platform.c
+++ b/arch/mips/alchemy/common/platform.c
@@ -492,7 +492,7 @@ static void __init alchemy_setup_macs(int ctype)
memcpy(au1xxx_eth0_platform_data.mac, ethaddr, 6);
ret = platform_device_register(&au1xxx_eth0_device);
- if (!ret)
+ if (ret)
printk(KERN_INFO "Alchemy: failed to register MAC0\n");
diff --git a/arch/mips/alchemy/common/power.c b/arch/mips/alchemy/common/power.c
index 647e518c90bc..b86324a42601 100644
--- a/arch/mips/alchemy/common/power.c
+++ b/arch/mips/alchemy/common/power.c
@@ -158,15 +158,21 @@ static void restore_core_regs(void)
void au_sleep(void)
{
- int cpuid = alchemy_get_cputype();
- if (cpuid != ALCHEMY_CPU_UNKNOWN) {
- save_core_regs();
- if (cpuid <= ALCHEMY_CPU_AU1500)
- alchemy_sleep_au1000();
- else if (cpuid <= ALCHEMY_CPU_AU1200)
- alchemy_sleep_au1550();
- restore_core_regs();
+ save_core_regs();
+
+ switch (alchemy_get_cputype()) {
+ case ALCHEMY_CPU_AU1000:
+ case ALCHEMY_CPU_AU1500:
+ case ALCHEMY_CPU_AU1100:
+ alchemy_sleep_au1000();
+ break;
+ case ALCHEMY_CPU_AU1550:
+ case ALCHEMY_CPU_AU1200:
+ alchemy_sleep_au1550();
+ break;
}
+
+ restore_core_regs();
}
#endif /* CONFIG_PM */
diff --git a/arch/mips/alchemy/devboards/bcsr.c b/arch/mips/alchemy/devboards/bcsr.c
index 596ad00e7f05..463d2c4d9441 100644
--- a/arch/mips/alchemy/devboards/bcsr.c
+++ b/arch/mips/alchemy/devboards/bcsr.c
@@ -89,8 +89,12 @@ static void bcsr_csc_handler(unsigned int irq, struct irq_desc *d)
{
unsigned short bisr = __raw_readw(bcsr_virt + BCSR_REG_INTSTAT);
+ disable_irq_nosync(irq);
+
for ( ; bisr; bisr &= bisr - 1)
generic_handle_irq(bcsr_csc_base + __ffs(bisr));
+
+ enable_irq(irq);
}
/* NOTE: both the enable and mask bits must be cleared, otherwise the
diff --git a/arch/mips/alchemy/devboards/db1200/setup.c b/arch/mips/alchemy/devboards/db1200/setup.c
index 1dac4f27d334..4a8980027ecf 100644
--- a/arch/mips/alchemy/devboards/db1200/setup.c
+++ b/arch/mips/alchemy/devboards/db1200/setup.c
@@ -23,13 +23,6 @@ void __init board_setup(void)
unsigned long freq0, clksrc, div, pfc;
unsigned short whoami;
- /* Set Config[OD] (disable overlapping bus transaction):
- * This gets rid of a _lot_ of spurious interrupts (especially
- * wrt. IDE); but incurs ~10% performance hit in some
- * cpu-bound applications.
- */
- set_c0_config(1 << 19);
-
bcsr_init(DB1200_BCSR_PHYS_ADDR,
DB1200_BCSR_PHYS_ADDR + DB1200_BCSR_HEXLED_OFS);
diff --git a/arch/mips/ar7/irq.c b/arch/mips/ar7/irq.c
index 03db3daadbd8..88c4babfdb5d 100644
--- a/arch/mips/ar7/irq.c
+++ b/arch/mips/ar7/irq.c
@@ -98,7 +98,8 @@ static struct irq_chip ar7_sec_irq_type = {
static struct irqaction ar7_cascade_action = {
.handler = no_action,
- .name = "AR7 cascade interrupt"
+ .name = "AR7 cascade interrupt",
+ .flags = IRQF_NO_THREAD,
};
static void __init ar7_irq_init(int base)
diff --git a/arch/mips/bcm47xx/Kconfig b/arch/mips/bcm47xx/Kconfig
new file mode 100644
index 000000000000..6210b8d84109
--- /dev/null
+++ b/arch/mips/bcm47xx/Kconfig
@@ -0,0 +1,31 @@
+if BCM47XX
+
+config BCM47XX_SSB
+ bool "SSB Support for Broadcom BCM47XX"
+ select SYS_HAS_CPU_MIPS32_R1
+ select SSB
+ select SSB_DRIVER_MIPS
+ select SSB_DRIVER_EXTIF
+ select SSB_EMBEDDED
+ select SSB_B43_PCI_BRIDGE if PCI
+ select SSB_PCICORE_HOSTMODE if PCI
+ default y
+ help
+ Add support for old Broadcom BCM47xx boards with Sonics Silicon Backplane support.
+
+ This will generate an image with support for SSB and MIPS32 R1 instruction set.
+
+config BCM47XX_BCMA
+ bool "BCMA Support for Broadcom BCM47XX"
+ select SYS_HAS_CPU_MIPS32_R2
+ select BCMA
+ select BCMA_HOST_SOC
+ select BCMA_DRIVER_MIPS
+ select BCMA_DRIVER_PCI_HOSTMODE if PCI
+ default y
+ help
+ Add support for new Broadcom BCM47xx boards with Broadcom specific Advanced Microcontroller Bus.
+
+ This will generate an image with support for BCMA and MIPS32 R2 instruction set.
+
+endif
diff --git a/arch/mips/bcm47xx/Makefile b/arch/mips/bcm47xx/Makefile
index 7465e8a72d9a..4add17349ff9 100644
--- a/arch/mips/bcm47xx/Makefile
+++ b/arch/mips/bcm47xx/Makefile
@@ -3,4 +3,5 @@
# under Linux.
#
-obj-y := gpio.o irq.o nvram.o prom.o serial.o setup.o time.o wgt634u.o
+obj-y += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o
+obj-$(CONFIG_BCM47XX_SSB) += wgt634u.o
diff --git a/arch/mips/bcm47xx/gpio.c b/arch/mips/bcm47xx/gpio.c
index e4a5ee9c9721..57b425fd4d41 100644
--- a/arch/mips/bcm47xx/gpio.c
+++ b/arch/mips/bcm47xx/gpio.c
@@ -20,42 +20,82 @@ static DECLARE_BITMAP(gpio_in_use, BCM47XX_EXTIF_GPIO_LINES);
int gpio_request(unsigned gpio, const char *tag)
{
- if (ssb_chipco_available(&ssb_bcm47xx.chipco) &&
- ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
- return -EINVAL;
+ switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
+ ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
+ return -EINVAL;
- if (ssb_extif_available(&ssb_bcm47xx.extif) &&
- ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
- return -EINVAL;
+ if (ssb_extif_available(&bcm47xx_bus.ssb.extif) &&
+ ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
+ return -EINVAL;
- if (test_and_set_bit(gpio, gpio_in_use))
- return -EBUSY;
+ if (test_and_set_bit(gpio, gpio_in_use))
+ return -EBUSY;
- return 0;
+ return 0;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ if (gpio >= BCM47XX_CHIPCO_GPIO_LINES)
+ return -EINVAL;
+
+ if (test_and_set_bit(gpio, gpio_in_use))
+ return -EBUSY;
+
+ return 0;
+#endif
+ }
+ return -EINVAL;
}
EXPORT_SYMBOL(gpio_request);
void gpio_free(unsigned gpio)
{
- if (ssb_chipco_available(&ssb_bcm47xx.chipco) &&
- ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
- return;
+ switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
+ ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
+ return;
+
+ if (ssb_extif_available(&bcm47xx_bus.ssb.extif) &&
+ ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
+ return;
- if (ssb_extif_available(&ssb_bcm47xx.extif) &&
- ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
+ clear_bit(gpio, gpio_in_use);
return;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ if (gpio >= BCM47XX_CHIPCO_GPIO_LINES)
+ return;
- clear_bit(gpio, gpio_in_use);
+ clear_bit(gpio, gpio_in_use);
+ return;
+#endif
+ }
}
EXPORT_SYMBOL(gpio_free);
int gpio_to_irq(unsigned gpio)
{
- if (ssb_chipco_available(&ssb_bcm47xx.chipco))
- return ssb_mips_irq(ssb_bcm47xx.chipco.dev) + 2;
- else if (ssb_extif_available(&ssb_bcm47xx.extif))
- return ssb_mips_irq(ssb_bcm47xx.extif.dev) + 2;
- else
- return -EINVAL;
+ switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco))
+ return ssb_mips_irq(bcm47xx_bus.ssb.chipco.dev) + 2;
+ else if (ssb_extif_available(&bcm47xx_bus.ssb.extif))
+ return ssb_mips_irq(bcm47xx_bus.ssb.extif.dev) + 2;
+ else
+ return -EINVAL;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ return bcma_core_mips_irq(bcm47xx_bus.bcma.bus.drv_cc.core) + 2;
+#endif
+ }
+ return -EINVAL;
}
EXPORT_SYMBOL_GPL(gpio_to_irq);
diff --git a/arch/mips/bcm47xx/irq.c b/arch/mips/bcm47xx/irq.c
index 325757acd020..8cf3833b2d29 100644
--- a/arch/mips/bcm47xx/irq.c
+++ b/arch/mips/bcm47xx/irq.c
@@ -26,6 +26,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <asm/irq_cpu.h>
+#include <bcm47xx.h>
void plat_irq_dispatch(void)
{
@@ -51,5 +52,16 @@ void plat_irq_dispatch(void)
void __init arch_init_irq(void)
{
+#ifdef CONFIG_BCM47XX_BCMA
+ if (bcm47xx_bus_type == BCM47XX_BUS_TYPE_BCMA) {
+ bcma_write32(bcm47xx_bus.bcma.bus.drv_mips.core,
+ BCMA_MIPS_MIPS74K_INTMASK(5), 1 << 31);
+ /*
+ * the kernel reads the timer irq from some register and thinks
+ * it's #5, but we offset it by 2 and route to #7
+ */
+ cp0_compare_irq = 7;
+ }
+#endif
mips_cpu_irq_init();
}
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index 54db815bc86c..a84e3bb7387f 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -26,14 +26,35 @@ static char nvram_buf[NVRAM_SPACE];
/* Probe for NVRAM header */
static void early_nvram_init(void)
{
- struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
+#ifdef CONFIG_BCM47XX_SSB
+ struct ssb_mipscore *mcore_ssb;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ struct bcma_drv_cc *bcma_cc;
+#endif
struct nvram_header *header;
int i;
- u32 base, lim, off;
+ u32 base = 0;
+ u32 lim = 0;
+ u32 off;
u32 *src, *dst;
- base = mcore->flash_window;
- lim = mcore->flash_window_size;
+ switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ mcore_ssb = &bcm47xx_bus.ssb.mipscore;
+ base = mcore_ssb->flash_window;
+ lim = mcore_ssb->flash_window_size;
+ break;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_cc = &bcm47xx_bus.bcma.bus.drv_cc;
+ base = bcma_cc->pflash.window;
+ lim = bcma_cc->pflash.window_size;
+ break;
+#endif
+ }
off = FLASH_MIN;
while (off <= lim) {
diff --git a/arch/mips/bcm47xx/serial.c b/arch/mips/bcm47xx/serial.c
index 59c11afdb2ab..57981e4fe2bc 100644
--- a/arch/mips/bcm47xx/serial.c
+++ b/arch/mips/bcm47xx/serial.c
@@ -23,10 +23,11 @@ static struct platform_device uart8250_device = {
},
};
-static int __init uart8250_init(void)
+#ifdef CONFIG_BCM47XX_SSB
+static int __init uart8250_init_ssb(void)
{
int i;
- struct ssb_mipscore *mcore = &(ssb_bcm47xx.mipscore);
+ struct ssb_mipscore *mcore = &(bcm47xx_bus.ssb.mipscore);
memset(&uart8250_data, 0, sizeof(uart8250_data));
@@ -44,6 +45,47 @@ static int __init uart8250_init(void)
}
return platform_device_register(&uart8250_device);
}
+#endif
+
+#ifdef CONFIG_BCM47XX_BCMA
+static int __init uart8250_init_bcma(void)
+{
+ int i;
+ struct bcma_drv_cc *cc = &(bcm47xx_bus.bcma.bus.drv_cc);
+
+ memset(&uart8250_data, 0, sizeof(uart8250_data));
+
+ for (i = 0; i < cc->nr_serial_ports; i++) {
+ struct plat_serial8250_port *p = &(uart8250_data[i]);
+ struct bcma_serial_port *bcma_port;
+ bcma_port = &(cc->serial_ports[i]);
+
+ p->mapbase = (unsigned int) bcma_port->regs;
+ p->membase = (void *) bcma_port->regs;
+ p->irq = bcma_port->irq + 2;
+ p->uartclk = bcma_port->baud_base;
+ p->regshift = bcma_port->reg_shift;
+ p->iotype = UPIO_MEM;
+ p->flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+ }
+ return platform_device_register(&uart8250_device);
+}
+#endif
+
+static int __init uart8250_init(void)
+{
+ switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ return uart8250_init_ssb();
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ return uart8250_init_bcma();
+#endif
+ }
+ return -EINVAL;
+}
module_init(uart8250_init);
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index cfae81571ded..17c3d14d7c49 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -29,21 +29,36 @@
#include <linux/types.h>
#include <linux/ssb/ssb.h>
#include <linux/ssb/ssb_embedded.h>
+#include <linux/bcma/bcma_soc.h>
#include <asm/bootinfo.h>
#include <asm/reboot.h>
#include <asm/time.h>
#include <bcm47xx.h>
#include <asm/mach-bcm47xx/nvram.h>
-struct ssb_bus ssb_bcm47xx;
-EXPORT_SYMBOL(ssb_bcm47xx);
+union bcm47xx_bus bcm47xx_bus;
+EXPORT_SYMBOL(bcm47xx_bus);
+
+enum bcm47xx_bus_type bcm47xx_bus_type;
+EXPORT_SYMBOL(bcm47xx_bus_type);
static void bcm47xx_machine_restart(char *command)
{
printk(KERN_ALERT "Please stand by while rebooting the system...\n");
local_irq_disable();
/* Set the watchdog timer to reset immediately */
- ssb_watchdog_timer_set(&ssb_bcm47xx, 1);
+ switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1);
+ break;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 1);
+ break;
+#endif
+ }
while (1)
cpu_relax();
}
@@ -52,11 +67,23 @@ static void bcm47xx_machine_halt(void)
{
/* Disable interrupts and watchdog and spin forever */
local_irq_disable();
- ssb_watchdog_timer_set(&ssb_bcm47xx, 0);
+ switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
+ break;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 0);
+ break;
+#endif
+ }
while (1)
cpu_relax();
}
+#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);
@@ -247,7 +274,7 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus,
return 0;
}
-void __init plat_mem_setup(void)
+static void __init bcm47xx_register_ssb(void)
{
int err;
char buf[100];
@@ -258,12 +285,12 @@ void __init plat_mem_setup(void)
printk(KERN_WARNING "bcm47xx: someone else already registered"
" a ssb SPROM callback handler (err %d)\n", err);
- err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE,
+ err = ssb_bus_ssbbus_register(&(bcm47xx_bus.ssb), SSB_ENUM_BASE,
bcm47xx_get_invariants);
if (err)
panic("Failed to initialize SSB bus (err %d)\n", err);
- mcore = &ssb_bcm47xx.mipscore;
+ mcore = &bcm47xx_bus.ssb.mipscore;
if (nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
if (strstr(buf, "console=ttyS1")) {
struct ssb_serial_port port;
@@ -276,8 +303,57 @@ void __init plat_mem_setup(void)
memcpy(&mcore->serial_ports[1], &port, sizeof(port));
}
}
+}
+#endif
+
+#ifdef CONFIG_BCM47XX_BCMA
+static void __init bcm47xx_register_bcma(void)
+{
+ int err;
+
+ err = bcma_host_soc_register(&bcm47xx_bus.bcma);
+ if (err)
+ panic("Failed to initialize BCMA bus (err %d)\n", err);
+}
+#endif
+
+void __init plat_mem_setup(void)
+{
+ struct cpuinfo_mips *c = &current_cpu_data;
+
+ if (c->cputype == CPU_74K) {
+ printk(KERN_INFO "bcm47xx: using bcma bus\n");
+#ifdef CONFIG_BCM47XX_BCMA
+ bcm47xx_bus_type = BCM47XX_BUS_TYPE_BCMA;
+ bcm47xx_register_bcma();
+#endif
+ } else {
+ printk(KERN_INFO "bcm47xx: using ssb bus\n");
+#ifdef CONFIG_BCM47XX_SSB
+ bcm47xx_bus_type = BCM47XX_BUS_TYPE_SSB;
+ bcm47xx_register_ssb();
+#endif
+ }
_machine_restart = bcm47xx_machine_restart;
_machine_halt = bcm47xx_machine_halt;
pm_power_off = bcm47xx_machine_halt;
}
+
+static int __init bcm47xx_register_bus_complete(void)
+{
+ switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ /* Nothing to do */
+ break;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_bus_register(&bcm47xx_bus.bcma.bus);
+ break;
+#endif
+ }
+ return 0;
+}
+device_initcall(bcm47xx_register_bus_complete);
diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c
index 0c6f47b3fd94..536374dcba78 100644
--- a/arch/mips/bcm47xx/time.c
+++ b/arch/mips/bcm47xx/time.c
@@ -30,7 +30,7 @@
void __init plat_time_init(void)
{
- unsigned long hz;
+ unsigned long hz = 0;
/*
* Use deterministic values for initial counter interrupt
@@ -39,7 +39,19 @@ void __init plat_time_init(void)
write_c0_count(0);
write_c0_compare(0xffff);
- hz = ssb_cpu_clock(&ssb_bcm47xx.mipscore) / 2;
+ switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ hz = ssb_cpu_clock(&bcm47xx_bus.ssb.mipscore) / 2;
+ break;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ hz = bcma_cpu_clock(&bcm47xx_bus.bcma.bus.drv_mips) / 2;
+ break;
+#endif
+ }
+
if (!hz)
hz = 100000000;
diff --git a/arch/mips/bcm47xx/wgt634u.c b/arch/mips/bcm47xx/wgt634u.c
index 74d06965326f..e9f9ec8d443b 100644
--- a/arch/mips/bcm47xx/wgt634u.c
+++ b/arch/mips/bcm47xx/wgt634u.c
@@ -108,7 +108,7 @@ static irqreturn_t gpio_interrupt(int irq, void *ignored)
/* Interrupts are shared, check if the current one is
a GPIO interrupt. */
- if (!ssb_chipco_irq_status(&ssb_bcm47xx.chipco,
+ if (!ssb_chipco_irq_status(&bcm47xx_bus.ssb.chipco,
SSB_CHIPCO_IRQ_GPIO))
return IRQ_NONE;
@@ -132,22 +132,26 @@ static int __init wgt634u_init(void)
* machine. Use the MAC address as an heuristic. Netgear Inc. has
* been allocated ranges 00:09:5b:xx:xx:xx and 00:0f:b5:xx:xx:xx.
*/
+ u8 *et0mac;
- u8 *et0mac = ssb_bcm47xx.sprom.et0mac;
+ if (bcm47xx_bus_type != BCM47XX_BUS_TYPE_SSB)
+ return -ENODEV;
+
+ et0mac = bcm47xx_bus.ssb.sprom.et0mac;
if (et0mac[0] == 0x00 &&
((et0mac[1] == 0x09 && et0mac[2] == 0x5b) ||
(et0mac[1] == 0x0f && et0mac[2] == 0xb5))) {
- struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
+ struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore;
printk(KERN_INFO "WGT634U machine detected.\n");
if (!request_irq(gpio_to_irq(WGT634U_GPIO_RESET),
gpio_interrupt, IRQF_SHARED,
- "WGT634U GPIO", &ssb_bcm47xx.chipco)) {
+ "WGT634U GPIO", &bcm47xx_bus.ssb.chipco)) {
gpio_direction_input(WGT634U_GPIO_RESET);
gpio_intmask(WGT634U_GPIO_RESET, 1);
- ssb_chipco_irq_mask(&ssb_bcm47xx.chipco,
+ ssb_chipco_irq_mask(&bcm47xx_bus.ssb.chipco,
SSB_CHIPCO_IRQ_GPIO,
SSB_CHIPCO_IRQ_GPIO);
}
diff --git a/arch/mips/bcm63xx/irq.c b/arch/mips/bcm63xx/irq.c
index cea6021cb8d7..162e11b4ed75 100644
--- a/arch/mips/bcm63xx/irq.c
+++ b/arch/mips/bcm63xx/irq.c
@@ -222,6 +222,7 @@ static struct irq_chip bcm63xx_external_irq_chip = {
static struct irqaction cpu_ip2_cascade_action = {
.handler = no_action,
.name = "cascade_ip2",
+ .flags = IRQF_NO_THREAD,
};
void __init arch_init_irq(void)
diff --git a/arch/mips/cobalt/irq.c b/arch/mips/cobalt/irq.c
index cb9bf820fe53..965c777d3561 100644
--- a/arch/mips/cobalt/irq.c
+++ b/arch/mips/cobalt/irq.c
@@ -48,6 +48,7 @@ asmlinkage void plat_irq_dispatch(void)
static struct irqaction cascade = {
.handler = no_action,
.name = "cascade",
+ .flags = IRQF_NO_THREAD,
};
void __init arch_init_irq(void)
diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c
index fa45e924be05..f7b7ba6d5c45 100644
--- a/arch/mips/dec/setup.c
+++ b/arch/mips/dec/setup.c
@@ -101,20 +101,24 @@ int cpu_fpu_mask = DEC_CPU_IRQ_MASK(DEC_CPU_INR_FPU);
static struct irqaction ioirq = {
.handler = no_action,
.name = "cascade",
+ .flags = IRQF_NO_THREAD,
};
static struct irqaction fpuirq = {
.handler = no_action,
.name = "fpu",
+ .flags = IRQF_NO_THREAD,
};
static struct irqaction busirq = {
.flags = IRQF_DISABLED,
.name = "bus error",
+ .flags = IRQF_NO_THREAD,
};
static struct irqaction haltirq = {
.handler = dec_intr_halt,
.name = "halt",
+ .flags = IRQF_NO_THREAD,
};
diff --git a/arch/mips/emma/markeins/irq.c b/arch/mips/emma/markeins/irq.c
index 3dbd7a5a6ad3..7798887a1288 100644
--- a/arch/mips/emma/markeins/irq.c
+++ b/arch/mips/emma/markeins/irq.c
@@ -169,7 +169,7 @@ void emma2rh_gpio_irq_init(void)
static struct irqaction irq_cascade = {
.handler = no_action,
- .flags = 0,
+ .flags = IRQF_NO_THREAD,
.name = "cascade",
.dev_id = NULL,
.next = NULL,
diff --git a/arch/mips/include/asm/lasat/lasat.h b/arch/mips/include/asm/lasat/lasat.h
index a1ada1c27c16..e8ff70f80e13 100644
--- a/arch/mips/include/asm/lasat/lasat.h
+++ b/arch/mips/include/asm/lasat/lasat.h
@@ -41,10 +41,8 @@ enum lasat_mtdparts {
/*
* The format of the data record in the EEPROM.
- * See Documentation/LASAT/eeprom.txt for a detailed description
- * of the fields in this struct, and the LASAT Hardware Configuration
- * field specification for a detailed description of the config
- * field.
+ * See the LASAT Hardware Configuration field specification for a detailed
+ * description of the config field.
*/
#include <linux/types.h>
diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
index d008f47a28bd..de95e0723e2b 100644
--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
+++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
@@ -19,7 +19,29 @@
#ifndef __ASM_BCM47XX_H
#define __ASM_BCM47XX_H
-/* SSB bus */
-extern struct ssb_bus ssb_bcm47xx;
+#include <linux/ssb/ssb.h>
+#include <linux/bcma/bcma.h>
+#include <linux/bcma/bcma_soc.h>
+
+enum bcm47xx_bus_type {
+#ifdef CONFIG_BCM47XX_SSB
+ BCM47XX_BUS_TYPE_SSB,
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ BCM47XX_BUS_TYPE_BCMA,
+#endif
+};
+
+union bcm47xx_bus {
+#ifdef CONFIG_BCM47XX_SSB
+ struct ssb_bus ssb;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ struct bcma_soc bcma;
+#endif
+};
+
+extern union bcm47xx_bus bcm47xx_bus;
+extern enum bcm47xx_bus_type bcm47xx_bus_type;
#endif /* __ASM_BCM47XX_H */
diff --git a/arch/mips/include/asm/mach-bcm47xx/gpio.h b/arch/mips/include/asm/mach-bcm47xx/gpio.h
index 98504142124e..76961cabeedf 100644
--- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
+++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
@@ -10,6 +10,7 @@
#define __BCM47XX_GPIO_H
#include <linux/ssb/ssb_embedded.h>
+#include <linux/bcma/bcma.h>
#include <asm/mach-bcm47xx/bcm47xx.h>
#define BCM47XX_EXTIF_GPIO_LINES 5
@@ -21,41 +22,118 @@ extern int gpio_to_irq(unsigned gpio);
static inline int gpio_get_value(unsigned gpio)
{
- return ssb_gpio_in(&ssb_bcm47xx, 1 << gpio);
+ switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ return ssb_gpio_in(&bcm47xx_bus.ssb, 1 << gpio);
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ return bcma_chipco_gpio_in(&bcm47xx_bus.bcma.bus.drv_cc,
+ 1 << gpio);
+#endif
+ }
+ return -EINVAL;
}
static inline void gpio_set_value(unsigned gpio, int value)
{
- ssb_gpio_out(&ssb_bcm47xx, 1 << gpio, value ? 1 << gpio : 0);
+ switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
+ value ? 1 << gpio : 0);
+ return;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_chipco_gpio_out(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
+ value ? 1 << gpio : 0);
+ return;
+#endif
+ }
}
static inline int gpio_direction_input(unsigned gpio)
{
- ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 0);
- return 0;
+ switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 0);
+ return 0;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_chipco_gpio_outen(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
+ 0);
+ return 0;
+#endif
+ }
+ return -EINVAL;
}
static inline int gpio_direction_output(unsigned gpio, int value)
{
- /* first set the gpio out value */
- ssb_gpio_out(&ssb_bcm47xx, 1 << gpio, value ? 1 << gpio : 0);
- /* then set the gpio mode */
- ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 1 << gpio);
- return 0;
+ switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ /* first set the gpio out value */
+ ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
+ value ? 1 << gpio : 0);
+ /* then set the gpio mode */
+ ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 1 << gpio);
+ return 0;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ /* first set the gpio out value */
+ bcma_chipco_gpio_out(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
+ value ? 1 << gpio : 0);
+ /* then set the gpio mode */
+ bcma_chipco_gpio_outen(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
+ 1 << gpio);
+ return 0;
+#endif
+ }
+ return -EINVAL;
}
static inline int gpio_intmask(unsigned gpio, int value)
{
- ssb_gpio_intmask(&ssb_bcm47xx, 1 << gpio,
- value ? 1 << gpio : 0);
- return 0;
+ switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_gpio_intmask(&bcm47xx_bus.ssb, 1 << gpio,
+ value ? 1 << gpio : 0);
+ return 0;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_chipco_gpio_intmask(&bcm47xx_bus.bcma.bus.drv_cc,
+ 1 << gpio, value ? 1 << gpio : 0);
+ return 0;
+#endif
+ }
+ return -EINVAL;
}
static inline int gpio_polarity(unsigned gpio, int value)
{
- ssb_gpio_polarity(&ssb_bcm47xx, 1 << gpio,
- value ? 1 << gpio : 0);
- return 0;
+ switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_gpio_polarity(&bcm47xx_bus.ssb, 1 << gpio,
+ value ? 1 << gpio : 0);
+ return 0;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_chipco_gpio_polarity(&bcm47xx_bus.bcma.bus.drv_cc,
+ 1 << gpio, value ? 1 << gpio : 0);
+ return 0;
+#endif
+ }
+ return -EINVAL;
}
diff --git a/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h b/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h
index 0d5a42b5f47a..a58addb98cfd 100644
--- a/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h
+++ b/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h
@@ -54,7 +54,6 @@
#define cpu_has_mips_r2_exec_hazard 0
#define cpu_has_dsp 0
#define cpu_has_mipsmt 0
-#define cpu_has_userlocal 0
#define cpu_has_vint 0
#define cpu_has_veic 0
#define cpu_hwrena_impl_bits 0xc0000000
diff --git a/arch/mips/include/asm/mach-powertv/dma-coherence.h b/arch/mips/include/asm/mach-powertv/dma-coherence.h
index 62c094085947..35371641575d 100644
--- a/arch/mips/include/asm/mach-powertv/dma-coherence.h
+++ b/arch/mips/include/asm/mach-powertv/dma-coherence.h
@@ -13,7 +13,6 @@
#define __ASM_MACH_POWERTV_DMA_COHERENCE_H
#include <linux/sched.h>
-#include <linux/version.h>
#include <linux/device.h>
#include <asm/mach-powertv/asic.h>
diff --git a/arch/mips/include/asm/stackframe.h b/arch/mips/include/asm/stackframe.h
index b4ba2449444b..cb41af5f3406 100644
--- a/arch/mips/include/asm/stackframe.h
+++ b/arch/mips/include/asm/stackframe.h
@@ -195,9 +195,9 @@
* to cover the pipeline delay.
*/
.set mips32
- mfc0 v1, CP0_TCSTATUS
+ mfc0 k0, CP0_TCSTATUS
.set mips0
- LONG_S v1, PT_TCSTATUS(sp)
+ LONG_S k0, PT_TCSTATUS(sp)
#endif /* CONFIG_MIPS_MT_SMTC */
LONG_S $4, PT_R4(sp)
LONG_S $5, PT_R5(sp)
diff --git a/arch/mips/jz4740/gpio.c b/arch/mips/jz4740/gpio.c
index 73031f7fc827..4397972949fa 100644
--- a/arch/mips/jz4740/gpio.c
+++ b/arch/mips/jz4740/gpio.c
@@ -18,7 +18,7 @@
#include <linux/init.h>
#include <linux/spinlock.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/delay.h>
@@ -86,7 +86,6 @@ struct jz_gpio_chip {
spinlock_t lock;
struct gpio_chip gpio_chip;
- struct sys_device sysdev;
};
static struct jz_gpio_chip jz4740_gpio_chips[];
@@ -459,49 +458,47 @@ static struct jz_gpio_chip jz4740_gpio_chips[] = {
JZ4740_GPIO_CHIP(D),
};
-static inline struct jz_gpio_chip *sysdev_to_chip(struct sys_device *dev)
+static void jz4740_gpio_suspend_chip(struct jz_gpio_chip *chip)
{
- return container_of(dev, struct jz_gpio_chip, sysdev);
+ chip->suspend_mask = readl(chip->base + JZ_REG_GPIO_MASK);
+ writel(~(chip->wakeup), chip->base + JZ_REG_GPIO_MASK_SET);
+ writel(chip->wakeup, chip->base + JZ_REG_GPIO_MASK_CLEAR);
}
-static int jz4740_gpio_suspend(struct sys_device *dev, pm_message_t state)
+static int jz4740_gpio_suspend(void)
{
- struct jz_gpio_chip *chip = sysdev_to_chip(dev);
+ int i;
- chip->suspend_mask = readl(chip->base + JZ_REG_GPIO_MASK);
- writel(~(chip->wakeup), chip->base + JZ_REG_GPIO_MASK_SET);
- writel(chip->wakeup, chip->base + JZ_REG_GPIO_MASK_CLEAR);
+ for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); i++)
+ jz4740_gpio_suspend_chip(&jz4740_gpio_chips[i]);
return 0;
}
-static int jz4740_gpio_resume(struct sys_device *dev)
+static void jz4740_gpio_resume_chip(struct jz_gpio_chip *chip)
{
- struct jz_gpio_chip *chip = sysdev_to_chip(dev);
uint32_t mask = chip->suspend_mask;
writel(~mask, chip->base + JZ_REG_GPIO_MASK_CLEAR);
writel(mask, chip->base + JZ_REG_GPIO_MASK_SET);
+}
- return 0;
+static void jz4740_gpio_resume(void)
+{
+ int i;
+
+ for (i = ARRAY_SIZE(jz4740_gpio_chips) - 1; i >= 0 ; i--)
+ jz4740_gpio_resume_chip(&jz4740_gpio_chips[i]);
}
-static struct sysdev_class jz4740_gpio_sysdev_class = {
- .name = "gpio",
+static struct syscore_ops jz4740_gpio_syscore_ops = {
.suspend = jz4740_gpio_suspend,
.resume = jz4740_gpio_resume,
};
-static int jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id)
+static void jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id)
{
- int ret, irq;
-
- chip->sysdev.id = id;
- chip->sysdev.cls = &jz4740_gpio_sysdev_class;
- ret = sysdev_register(&chip->sysdev);
-
- if (ret)
- return ret;
+ int irq;
spin_lock_init(&chip->lock);
@@ -519,22 +516,17 @@ static int jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id)
irq_set_chip_and_handler(irq, &jz_gpio_irq_chip,
handle_level_irq);
}
-
- return 0;
}
static int __init jz4740_gpio_init(void)
{
unsigned int i;
- int ret;
-
- ret = sysdev_class_register(&jz4740_gpio_sysdev_class);
- if (ret)
- return ret;
for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i)
jz4740_gpio_chip_init(&jz4740_gpio_chips[i], i);
+ register_syscore_ops(&jz4740_gpio_syscore_ops);
+
printk(KERN_INFO "JZ4740 GPIO initialized\n");
return 0;
diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c
index feb8021a305f..6a2d758dd8e9 100644
--- a/arch/mips/kernel/ftrace.c
+++ b/arch/mips/kernel/ftrace.c
@@ -19,6 +19,26 @@
#include <asm-generic/sections.h>
+#if defined(KBUILD_MCOUNT_RA_ADDRESS) && defined(CONFIG_32BIT)
+#define MCOUNT_OFFSET_INSNS 5
+#else
+#define MCOUNT_OFFSET_INSNS 4
+#endif
+
+/*
+ * Check if the address is in kernel space
+ *
+ * Clone core_kernel_text() from kernel/extable.c, but doesn't call
+ * init_kernel_text() for Ftrace doesn't trace functions in init sections.
+ */
+static inline int in_kernel_space(unsigned long ip)
+{
+ if (ip >= (unsigned long)_stext &&
+ ip <= (unsigned long)_etext)
+ return 1;
+ return 0;
+}
+
#ifdef CONFIG_DYNAMIC_FTRACE
#define JAL 0x0c000000 /* jump & link: ip --> ra, jump to target */
@@ -54,20 +74,6 @@ static inline void ftrace_dyn_arch_init_insns(void)
#endif
}
-/*
- * Check if the address is in kernel space
- *
- * Clone core_kernel_text() from kernel/extable.c, but doesn't call
- * init_kernel_text() for Ftrace doesn't trace functions in init sections.
- */
-static inline int in_kernel_space(unsigned long ip)
-{
- if (ip >= (unsigned long)_stext &&
- ip <= (unsigned long)_etext)
- return 1;
- return 0;
-}
-
static int ftrace_modify_code(unsigned long ip, unsigned int new_code)
{
int faulted;
@@ -112,11 +118,6 @@ static int ftrace_modify_code(unsigned long ip, unsigned int new_code)
* 1: offset = 4 instructions
*/
-#if defined(KBUILD_MCOUNT_RA_ADDRESS) && defined(CONFIG_32BIT)
-#define MCOUNT_OFFSET_INSNS 5
-#else
-#define MCOUNT_OFFSET_INSNS 4
-#endif
#define INSN_B_1F (0x10000000 | MCOUNT_OFFSET_INSNS)
int ftrace_make_nop(struct module *mod,
diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c
index 5c74eb797f08..32b397b646ee 100644
--- a/arch/mips/kernel/i8259.c
+++ b/arch/mips/kernel/i8259.c
@@ -229,7 +229,7 @@ static void i8259A_shutdown(void)
*/
if (i8259A_auto_eoi >= 0) {
outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */
- outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-1 */
+ outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */
}
}
@@ -295,6 +295,7 @@ static void init_8259A(int auto_eoi)
static struct irqaction irq2 = {
.handler = no_action,
.name = "cascade",
+ .flags = IRQF_NO_THREAD,
};
static struct resource pic1_io_resource = {
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index 876a75cc376f..922a554cd108 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -349,3 +349,10 @@ SYSCALL_DEFINE6(32_fanotify_mark, int, fanotify_fd, unsigned int, flags,
return sys_fanotify_mark(fanotify_fd, flags, merge_64(a3, a4),
dfd, pathname);
}
+
+SYSCALL_DEFINE6(32_futex, u32 __user *, uaddr, int, op, u32, val,
+ struct compat_timespec __user *, utime, u32 __user *, uaddr2,
+ u32, val3)
+{
+ return compat_sys_futex(uaddr, op, val, utime, uaddr2, val3);
+}
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index e521420a45a5..865bc7a6f5a1 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -424,7 +424,7 @@ einval: li v0, -ENOSYS
sys sys_getresuid 3
sys sys_ni_syscall 0 /* was sys_query_module */
sys sys_poll 3
- sys sys_nfsservctl 3
+ sys sys_ni_syscall 0 /* was nfsservctl */
sys sys_setresgid 3 /* 4190 */
sys sys_getresgid 3
sys sys_prctl 5
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index 85874d6a8a70..fb7334bea731 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -299,7 +299,7 @@ sys_call_table:
PTR sys_ni_syscall /* 5170, was get_kernel_syms */
PTR sys_ni_syscall /* was query_module */
PTR sys_quotactl
- PTR sys_nfsservctl
+ PTR sys_ni_syscall /* was nfsservctl */
PTR sys_ni_syscall /* res. for getpmsg */
PTR sys_ni_syscall /* 5175 for putpmsg */
PTR sys_ni_syscall /* res. for afs_syscall */
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index b85842fc87ae..6de1f598346e 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -294,7 +294,7 @@ EXPORT(sysn32_call_table)
PTR sys_ni_syscall /* 6170, was get_kernel_syms */
PTR sys_ni_syscall /* was query_module */
PTR sys_quotactl
- PTR compat_sys_nfsservctl
+ PTR sys_ni_syscall /* was nfsservctl */
PTR sys_ni_syscall /* res. for getpmsg */
PTR sys_ni_syscall /* 6175 for putpmsg */
PTR sys_ni_syscall /* res. for afs_syscall */
@@ -315,7 +315,7 @@ EXPORT(sysn32_call_table)
PTR sys_fremovexattr
PTR sys_tkill
PTR sys_ni_syscall
- PTR compat_sys_futex
+ PTR sys_32_futex
PTR compat_sys_sched_setaffinity /* 6195 */
PTR compat_sys_sched_getaffinity
PTR sys_cacheflush
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 46c4763edf21..1d813169e453 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -392,7 +392,7 @@ sys_call_table:
PTR sys_getresuid
PTR sys_ni_syscall /* was query_module */
PTR sys_poll
- PTR compat_sys_nfsservctl
+ PTR sys_ni_syscall /* was nfsservctl */
PTR sys_setresgid /* 4190 */
PTR sys_getresgid
PTR sys_prctl
@@ -441,7 +441,7 @@ sys_call_table:
PTR sys_fremovexattr /* 4235 */
PTR sys_tkill
PTR sys_sendfile64
- PTR compat_sys_futex
+ PTR sys_32_futex
PTR compat_sys_sched_setaffinity
PTR compat_sys_sched_getaffinity /* 4240 */
PTR compat_sys_io_setup
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index dbbe0ce48d89..f8524003676a 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -8,6 +8,7 @@
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
*/
#include <linux/cache.h>
+#include <linux/irqflags.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/personality.h>
@@ -658,6 +659,8 @@ static void do_signal(struct pt_regs *regs)
asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
__u32 thread_info_flags)
{
+ local_irq_enable();
+
/* deal with pending signal delivery */
if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
do_signal(regs);
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index b7517e3abc85..cbea618af0b4 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -14,6 +14,7 @@
#include <linux/bug.h>
#include <linux/compiler.h>
#include <linux/init.h>
+#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/sched.h>
@@ -364,21 +365,26 @@ static int regs_to_trapnr(struct pt_regs *regs)
return (regs->cp0_cause >> 2) & 0x1f;
}
-static DEFINE_SPINLOCK(die_lock);
+static DEFINE_RAW_SPINLOCK(die_lock);
void __noreturn die(const char *str, struct pt_regs *regs)
{
static int die_counter;
int sig = SIGSEGV;
#ifdef CONFIG_MIPS_MT_SMTC
- unsigned long dvpret = dvpe();
+ unsigned long dvpret;
#endif /* CONFIG_MIPS_MT_SMTC */
+ oops_enter();
+
if (notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), SIGSEGV) == NOTIFY_STOP)
sig = 0;
console_verbose();
- spin_lock_irq(&die_lock);
+ raw_spin_lock_irq(&die_lock);
+#ifdef CONFIG_MIPS_MT_SMTC
+ dvpret = dvpe();
+#endif /* CONFIG_MIPS_MT_SMTC */
bust_spinlocks(1);
#ifdef CONFIG_MIPS_MT_SMTC
mips_mt_regdump(dvpret);
@@ -387,7 +393,9 @@ void __noreturn die(const char *str, struct pt_regs *regs)
printk("%s[#%d]:\n", str, ++die_counter);
show_registers(regs);
add_taint(TAINT_DIE);
- spin_unlock_irq(&die_lock);
+ raw_spin_unlock_irq(&die_lock);
+
+ oops_exit();
if (in_interrupt())
panic("Fatal exception in interrupt");
diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c
index 2cd50ad0d5c6..3efcb065f78a 100644
--- a/arch/mips/kernel/vpe.c
+++ b/arch/mips/kernel/vpe.c
@@ -192,7 +192,7 @@ static struct tc *get_tc(int index)
}
spin_unlock(&vpecontrol.tc_list_lock);
- return NULL;
+ return res;
}
/* allocate a vpe and associate it with this minor (or index) */
diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c
index fc89795cafdb..f9737bb3c5ab 100644
--- a/arch/mips/lantiq/irq.c
+++ b/arch/mips/lantiq/irq.c
@@ -123,11 +123,10 @@ void ltq_enable_irq(struct irq_data *d)
static unsigned int ltq_startup_eiu_irq(struct irq_data *d)
{
int i;
- int irq_nr = d->irq - INT_NUM_IRQ0;
ltq_enable_irq(d);
for (i = 0; i < MAX_EIU; i++) {
- if (irq_nr == ltq_eiu_irq[i]) {
+ if (d->irq == ltq_eiu_irq[i]) {
/* low level - we should really handle set_type */
ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) |
(0x6 << (i * 4)), LTQ_EIU_EXIN_C);
@@ -147,11 +146,10 @@ static unsigned int ltq_startup_eiu_irq(struct irq_data *d)
static void ltq_shutdown_eiu_irq(struct irq_data *d)
{
int i;
- int irq_nr = d->irq - INT_NUM_IRQ0;
ltq_disable_irq(d);
for (i = 0; i < MAX_EIU; i++) {
- if (irq_nr == ltq_eiu_irq[i]) {
+ if (d->irq == ltq_eiu_irq[i]) {
/* disable */
ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~(1 << i),
LTQ_EIU_EXIN_INEN);
diff --git a/arch/mips/lantiq/xway/ebu.c b/arch/mips/lantiq/xway/ebu.c
index 66eb52fa50a1..033b3184c7a7 100644
--- a/arch/mips/lantiq/xway/ebu.c
+++ b/arch/mips/lantiq/xway/ebu.c
@@ -10,7 +10,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/ioport.h>
#include <lantiq_soc.h>
diff --git a/arch/mips/lantiq/xway/pmu.c b/arch/mips/lantiq/xway/pmu.c
index 9d69f01e352b..39f0d2641cbf 100644
--- a/arch/mips/lantiq/xway/pmu.c
+++ b/arch/mips/lantiq/xway/pmu.c
@@ -8,7 +8,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/ioport.h>
#include <lantiq_soc.h>
diff --git a/arch/mips/lasat/interrupt.c b/arch/mips/lasat/interrupt.c
index de4c165515d7..d608b6ef0edd 100644
--- a/arch/mips/lasat/interrupt.c
+++ b/arch/mips/lasat/interrupt.c
@@ -105,6 +105,7 @@ asmlinkage void plat_irq_dispatch(void)
static struct irqaction cascade = {
.handler = no_action,
.name = "cascade",
+ .flags = IRQF_NO_THREAD,
};
void __init arch_init_irq(void)
diff --git a/arch/mips/loongson/fuloong-2e/irq.c b/arch/mips/loongson/fuloong-2e/irq.c
index d61a04222b87..3cf1fef29f0e 100644
--- a/arch/mips/loongson/fuloong-2e/irq.c
+++ b/arch/mips/loongson/fuloong-2e/irq.c
@@ -42,6 +42,7 @@ asmlinkage void mach_irq_dispatch(unsigned int pending)
static struct irqaction cascade_irqaction = {
.handler = no_action,
.name = "cascade",
+ .flags = IRQF_NO_THREAD,
};
void __init mach_init_irq(void)
diff --git a/arch/mips/loongson/lemote-2f/irq.c b/arch/mips/loongson/lemote-2f/irq.c
index 081db102bb98..14b081841b6b 100644
--- a/arch/mips/loongson/lemote-2f/irq.c
+++ b/arch/mips/loongson/lemote-2f/irq.c
@@ -96,12 +96,13 @@ static irqreturn_t ip6_action(int cpl, void *dev_id)
struct irqaction ip6_irqaction = {
.handler = ip6_action,
.name = "cascade",
- .flags = IRQF_SHARED,
+ .flags = IRQF_SHARED | IRQF_NO_THREAD,
};
struct irqaction cascade_irqaction = {
.handler = no_action,
.name = "cascade",
+ .flags = IRQF_NO_THREAD,
};
void __init mach_init_irq(void)
diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c
index 9ff5d0fac556..302d779d5b0d 100644
--- a/arch/mips/mm/mmap.c
+++ b/arch/mips/mm/mmap.c
@@ -6,6 +6,7 @@
* Copyright (C) 2011 Wind River Systems,
* written by Ralf Baechle <ralf@linux-mips.org>
*/
+#include <linux/compiler.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/mman.h>
@@ -15,12 +16,11 @@
#include <linux/sched.h>
unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */
-
EXPORT_SYMBOL(shm_align_mask);
/* gap between mmap and stack */
#define MIN_GAP (128*1024*1024UL)
-#define MAX_GAP ((TASK_SIZE)/6*5)
+#define MAX_GAP ((TASK_SIZE)/6*5)
static int mmap_is_legacy(void)
{
@@ -57,13 +57,13 @@ static inline unsigned long COLOUR_ALIGN_DOWN(unsigned long addr,
return base - off;
}
-#define COLOUR_ALIGN(addr,pgoff) \
+#define COLOUR_ALIGN(addr, pgoff) \
((((addr) + shm_align_mask) & ~shm_align_mask) + \
(((pgoff) << PAGE_SHIFT) & shm_align_mask))
enum mmap_allocation_direction {UP, DOWN};
-static unsigned long arch_get_unmapped_area_foo(struct file *filp,
+static unsigned long arch_get_unmapped_area_common(struct file *filp,
unsigned long addr0, unsigned long len, unsigned long pgoff,
unsigned long flags, enum mmap_allocation_direction dir)
{
@@ -103,16 +103,16 @@ static unsigned long arch_get_unmapped_area_foo(struct file *filp,
vma = find_vma(mm, addr);
if (TASK_SIZE - len >= addr &&
- (!vma || addr + len <= vma->vm_start))
+ (!vma || addr + len <= vma->vm_start))
return addr;
}
if (dir == UP) {
addr = mm->mmap_base;
- if (do_color_align)
- addr = COLOUR_ALIGN(addr, pgoff);
- else
- addr = PAGE_ALIGN(addr);
+ if (do_color_align)
+ addr = COLOUR_ALIGN(addr, pgoff);
+ else
+ addr = PAGE_ALIGN(addr);
for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
/* At this point: (!vma || addr < vma->vm_end). */
@@ -131,28 +131,30 @@ static unsigned long arch_get_unmapped_area_foo(struct file *filp,
mm->free_area_cache = mm->mmap_base;
}
- /* either no address requested or can't fit in requested address hole */
+ /*
+ * either no address requested, or the mapping can't fit into
+ * the requested address hole
+ */
addr = mm->free_area_cache;
- if (do_color_align) {
- unsigned long base =
- COLOUR_ALIGN_DOWN(addr - len, pgoff);
-
+ if (do_color_align) {
+ unsigned long base =
+ COLOUR_ALIGN_DOWN(addr - len, pgoff);
addr = base + len;
- }
+ }
/* make sure it can fit in the remaining address space */
if (likely(addr > len)) {
vma = find_vma(mm, addr - len);
if (!vma || addr <= vma->vm_start) {
- /* remember the address as a hint for next time */
- return mm->free_area_cache = addr-len;
+ /* cache the address as a hint for next time */
+ return mm->free_area_cache = addr - len;
}
}
if (unlikely(mm->mmap_base < len))
goto bottomup;
- addr = mm->mmap_base-len;
+ addr = mm->mmap_base - len;
if (do_color_align)
addr = COLOUR_ALIGN_DOWN(addr, pgoff);
@@ -163,8 +165,8 @@ static unsigned long arch_get_unmapped_area_foo(struct file *filp,
* return with success:
*/
vma = find_vma(mm, addr);
- if (likely(!vma || addr+len <= vma->vm_start)) {
- /* remember the address as a hint for next time */
+ if (likely(!vma || addr + len <= vma->vm_start)) {
+ /* cache the address as a hint for next time */
return mm->free_area_cache = addr;
}
@@ -173,7 +175,7 @@ static unsigned long arch_get_unmapped_area_foo(struct file *filp,
mm->cached_hole_size = vma->vm_start - addr;
/* try just below the current vma->vm_start */
- addr = vma->vm_start-len;
+ addr = vma->vm_start - len;
if (do_color_align)
addr = COLOUR_ALIGN_DOWN(addr, pgoff);
} while (likely(len < vma->vm_start));
@@ -201,7 +203,7 @@ bottomup:
unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr0,
unsigned long len, unsigned long pgoff, unsigned long flags)
{
- return arch_get_unmapped_area_foo(filp,
+ return arch_get_unmapped_area_common(filp,
addr0, len, pgoff, flags, UP);
}
@@ -213,7 +215,7 @@ unsigned long arch_get_unmapped_area_topdown(struct file *filp,
unsigned long addr0, unsigned long len, unsigned long pgoff,
unsigned long flags)
{
- return arch_get_unmapped_area_foo(filp,
+ return arch_get_unmapped_area_common(filp,
addr0, len, pgoff, flags, DOWN);
}
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index b6e1cff50667..e06370f58ef3 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -1759,14 +1759,13 @@ static void __cpuinit build_r3000_tlb_modify_handler(void)
u32 *p = handle_tlbm;
struct uasm_label *l = labels;
struct uasm_reloc *r = relocs;
- struct work_registers wr;
memset(handle_tlbm, 0, sizeof(handle_tlbm));
memset(labels, 0, sizeof(labels));
memset(relocs, 0, sizeof(relocs));
build_r3000_tlbchange_handler_head(&p, K0, K1);
- build_pte_modifiable(&p, &r, wr.r1, wr.r2, wr.r3, label_nopage_tlbm);
+ build_pte_modifiable(&p, &r, K0, K1, -1, label_nopage_tlbm);
uasm_i_nop(&p); /* load delay */
build_make_write(&p, &r, K0, K1);
build_r3000_pte_reload_tlbwi(&p, K0, K1);
@@ -1963,7 +1962,8 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
uasm_i_andi(&p, wr.r3, wr.r3, 2);
uasm_il_beqz(&p, &r, wr.r3, label_tlbl_goaround2);
}
-
+ if (PM_DEFAULT_MASK == 0)
+ uasm_i_nop(&p);
/*
* We clobbered C0_PAGEMASK, restore it. On the other branch
* it is restored in build_huge_tlb_write_entry.
diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c
index 1d36c511a7a5..d53ff91b277c 100644
--- a/arch/mips/mti-malta/malta-int.c
+++ b/arch/mips/mti-malta/malta-int.c
@@ -350,12 +350,14 @@ unsigned int plat_ipi_resched_int_xlate(unsigned int cpu)
static struct irqaction i8259irq = {
.handler = no_action,
- .name = "XT-PIC cascade"
+ .name = "XT-PIC cascade",
+ .flags = IRQF_NO_THREAD,
};
static struct irqaction corehi_irqaction = {
.handler = no_action,
- .name = "CoreHi"
+ .name = "CoreHi",
+ .flags = IRQF_NO_THREAD,
};
static msc_irqmap_t __initdata msc_irqmap[] = {
diff --git a/arch/mips/netlogic/xlr/Makefile b/arch/mips/netlogic/xlr/Makefile
index 9bd3f731f62e..2dca585dd2f7 100644
--- a/arch/mips/netlogic/xlr/Makefile
+++ b/arch/mips/netlogic/xlr/Makefile
@@ -2,4 +2,4 @@ obj-y += setup.o platform.o irq.o setup.o time.o
obj-$(CONFIG_SMP) += smp.o smpboot.o
obj-$(CONFIG_EARLY_PRINTK) += xlr_console.o
-EXTRA_CFLAGS += -Werror
+ccflags-y += -Werror
diff --git a/arch/mips/pci/pci-bcm47xx.c b/arch/mips/pci/pci-bcm47xx.c
index 455f8e50a007..400535a955d0 100644
--- a/arch/mips/pci/pci-bcm47xx.c
+++ b/arch/mips/pci/pci-bcm47xx.c
@@ -25,6 +25,7 @@
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/ssb/ssb.h>
+#include <bcm47xx.h>
int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
@@ -33,9 +34,13 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
int pcibios_plat_dev_init(struct pci_dev *dev)
{
+#ifdef CONFIG_BCM47XX_SSB
int res;
u8 slot, pin;
+ if (bcm47xx_bus_type != BCM47XX_BUS_TYPE_SSB)
+ return 0;
+
res = ssb_pcibios_plat_dev_init(dev);
if (res < 0) {
printk(KERN_ALERT "PCI: Failed to init device %s\n",
@@ -55,5 +60,6 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
}
dev->irq = res;
+#endif
return 0;
}
diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c
index 603d7493e966..8656388b34bd 100644
--- a/arch/mips/pci/pci-lantiq.c
+++ b/arch/mips/pci/pci-lantiq.c
@@ -171,8 +171,13 @@ static int __devinit ltq_pci_startup(struct ltq_pci_data *conf)
u32 temp_buffer;
/* set clock to 33Mhz */
- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~0xf00000, LTQ_CGU_IFCCR);
- ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | 0x800000, LTQ_CGU_IFCCR);
+ if (ltq_is_ar9()) {
+ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~0x1f00000, LTQ_CGU_IFCCR);
+ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | 0xe00000, LTQ_CGU_IFCCR);
+ } else {
+ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~0xf00000, LTQ_CGU_IFCCR);
+ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | 0x800000, LTQ_CGU_IFCCR);
+ }
/* external or internal clock ? */
if (conf->clock) {
diff --git a/arch/mips/pci/pci-rc32434.c b/arch/mips/pci/pci-rc32434.c
index 764362ce5e40..5f3a69cebad1 100644
--- a/arch/mips/pci/pci-rc32434.c
+++ b/arch/mips/pci/pci-rc32434.c
@@ -215,7 +215,7 @@ static int __init rc32434_pci_init(void)
rc32434_pcibridge_init();
io_map_base = ioremap(rc32434_res_pci_io1.start,
- resource_size(&rcrc32434_res_pci_io1));
+ resource_size(&rc32434_res_pci_io1));
if (!io_map_base)
return -ENOMEM;
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_irq.c b/arch/mips/pmc-sierra/msp71xx/msp_irq.c
index 4531c4a514bc..d3c3d81757a5 100644
--- a/arch/mips/pmc-sierra/msp71xx/msp_irq.c
+++ b/arch/mips/pmc-sierra/msp71xx/msp_irq.c
@@ -108,12 +108,14 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
static struct irqaction cic_cascade_msp = {
.handler = no_action,
- .name = "MSP CIC cascade"
+ .name = "MSP CIC cascade",
+ .flags = IRQF_NO_THREAD,
};
static struct irqaction per_cascade_msp = {
.handler = no_action,
- .name = "MSP PER cascade"
+ .name = "MSP PER cascade",
+ .flags = IRQF_NO_THREAD,
};
void __init arch_init_irq(void)
diff --git a/arch/mips/pnx8550/common/int.c b/arch/mips/pnx8550/common/int.c
index 6b93c81779c1..1ebe22bdadc8 100644
--- a/arch/mips/pnx8550/common/int.c
+++ b/arch/mips/pnx8550/common/int.c
@@ -167,7 +167,7 @@ static struct irq_chip level_irq_type = {
static struct irqaction gic_action = {
.handler = no_action,
- .flags = IRQF_DISABLED,
+ .flags = IRQF_DISABLED | IRQF_NO_THREAD,
.name = "GIC",
};
diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c
index b4d08e4d2ea9..f72c336ea27b 100644
--- a/arch/mips/sgi-ip22/ip22-int.c
+++ b/arch/mips/sgi-ip22/ip22-int.c
@@ -155,32 +155,32 @@ static void __irq_entry indy_buserror_irq(void)
static struct irqaction local0_cascade = {
.handler = no_action,
- .flags = IRQF_DISABLED,
+ .flags = IRQF_DISABLED | IRQF_NO_THREAD,
.name = "local0 cascade",
};
static struct irqaction local1_cascade = {
.handler = no_action,
- .flags = IRQF_DISABLED,
+ .flags = IRQF_DISABLED | IRQF_NO_THREAD,
.name = "local1 cascade",
};
static struct irqaction buserr = {
.handler = no_action,
- .flags = IRQF_DISABLED,
+ .flags = IRQF_DISABLED | IRQF_NO_THREAD,
.name = "Bus Error",
};
static struct irqaction map0_cascade = {
.handler = no_action,
- .flags = IRQF_DISABLED,
+ .flags = IRQF_DISABLED | IRQF_NO_THREAD,
.name = "mapable0 cascade",
};
#ifdef USE_LIO3_IRQ
static struct irqaction map1_cascade = {
.handler = no_action,
- .flags = IRQF_DISABLED,
+ .flags = IRQF_DISABLED | IRQF_NO_THREAD,
.name = "mapable1 cascade",
};
#define SGI_INTERRUPTS SGINT_END
diff --git a/arch/mips/sni/rm200.c b/arch/mips/sni/rm200.c
index a7e5a6d917b1..3ab5b5d25b0a 100644
--- a/arch/mips/sni/rm200.c
+++ b/arch/mips/sni/rm200.c
@@ -359,6 +359,7 @@ void sni_rm200_init_8259A(void)
static struct irqaction sni_rm200_irq2 = {
.handler = no_action,
.name = "cascade",
+ .flags = IRQF_NO_THREAD,
};
static struct resource sni_rm200_pic1_resource = {
diff --git a/arch/mips/txx9/generic/setup_tx4939.c b/arch/mips/txx9/generic/setup_tx4939.c
index e9f95dcde379..ba3cec3155df 100644
--- a/arch/mips/txx9/generic/setup_tx4939.c
+++ b/arch/mips/txx9/generic/setup_tx4939.c
@@ -321,7 +321,7 @@ void __init tx4939_sio_init(unsigned int sclk, unsigned int cts_mask)
static u32 tx4939_get_eth_speed(struct net_device *dev)
{
struct ethtool_cmd cmd;
- if (dev_ethtool_get_settings(dev, &cmd))
+ if (__ethtool_get_settings(dev, &cmd))
return 100; /* default 100Mbps */
return ethtool_cmd_speed(&cmd);
diff --git a/arch/mips/vr41xx/common/irq.c b/arch/mips/vr41xx/common/irq.c
index 70a3b85f3757..fad2bef432cd 100644
--- a/arch/mips/vr41xx/common/irq.c
+++ b/arch/mips/vr41xx/common/irq.c
@@ -34,6 +34,7 @@ static irq_cascade_t irq_cascade[NR_IRQS] __cacheline_aligned;
static struct irqaction cascade_irqaction = {
.handler = no_action,
.name = "cascade",
+ .flags = IRQF_NO_THREAD,
};
int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int))
diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig
index 1f870340ebdd..f093b3a8a4a1 100644
--- a/arch/mn10300/Kconfig
+++ b/arch/mn10300/Kconfig
@@ -195,7 +195,7 @@ config SMP
singleprocessor machines. On a singleprocessor machine, the kernel
will run faster if you say N here.
- See also <file:Documentation/i386/IO-APIC.txt>,
+ See also <file:Documentation/x86/i386/IO-APIC.txt>,
<file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
<http://www.tldp.org/docs.html#howto>.
diff --git a/arch/mn10300/kernel/entry.S b/arch/mn10300/kernel/entry.S
index ae435e1d5669..3e3620d9fc45 100644
--- a/arch/mn10300/kernel/entry.S
+++ b/arch/mn10300/kernel/entry.S
@@ -589,7 +589,7 @@ ENTRY(sys_call_table)
.long sys_ni_syscall /* vm86 */
.long sys_ni_syscall /* Old sys_query_module */
.long sys_poll
- .long sys_nfsservctl
+ .long sys_ni_syscall /* was nfsservctl */
.long sys_setresgid16 /* 170 */
.long sys_getresgid16
.long sys_prctl
diff --git a/arch/mn10300/kernel/irq.c b/arch/mn10300/kernel/irq.c
index 2623d19f4f4c..2381df83bd00 100644
--- a/arch/mn10300/kernel/irq.c
+++ b/arch/mn10300/kernel/irq.c
@@ -260,7 +260,6 @@ void set_intr_level(int irq, u16 level)
/*
* mark an interrupt to be ACK'd after interrupt handlers have been run rather
* than before
- * - see Documentation/mn10300/features.txt
*/
void mn10300_set_lateack_irq_type(int irq)
{
diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
index 4558bafbd1a2..9460e1c266dd 100644
--- a/arch/openrisc/Kconfig
+++ b/arch/openrisc/Kconfig
@@ -1,6 +1,6 @@
#
# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/config-language.txt.
+# see Documentation/kbuild/kconfig-language.txt.
#
config OPENRISC
diff --git a/arch/openrisc/include/asm/dma-mapping.h b/arch/openrisc/include/asm/dma-mapping.h
index 052f877b52a5..b206ba4608b2 100644
--- a/arch/openrisc/include/asm/dma-mapping.h
+++ b/arch/openrisc/include/asm/dma-mapping.h
@@ -18,7 +18,7 @@
#define __ASM_OPENRISC_DMA_MAPPING_H
/*
- * See Documentation/PCI/PCI-DMA-mapping.txt and
+ * See Documentation/DMA-API-HOWTO.txt and
* Documentation/DMA-API.txt for documentation.
*
* This file is written with the intention of eventually moving over
@@ -31,7 +31,6 @@
#define DMA_ERROR_CODE (~(dma_addr_t)0x0)
-int dma_mapping_error(struct device *dev, dma_addr_t dma_addr);
#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
@@ -47,6 +46,12 @@ dma_addr_t or1k_map_page(struct device *dev, struct page *page,
void or1k_unmap_page(struct device *dev, dma_addr_t dma_handle,
size_t size, enum dma_data_direction dir,
struct dma_attrs *attrs);
+int or1k_map_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir,
+ struct dma_attrs *attrs);
+void or1k_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir,
+ struct dma_attrs *attrs);
void or1k_sync_single_for_cpu(struct device *dev,
dma_addr_t dma_handle, size_t size,
enum dma_data_direction dir);
@@ -98,6 +103,51 @@ static inline void dma_unmap_single(struct device *dev, dma_addr_t addr,
debug_dma_unmap_page(dev, addr, size, dir, true);
}
+static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir)
+{
+ int i, ents;
+ struct scatterlist *s;
+
+ for_each_sg(sg, s, nents, i)
+ kmemcheck_mark_initialized(sg_virt(s), s->length);
+ BUG_ON(!valid_dma_direction(dir));
+ ents = or1k_map_sg(dev, sg, nents, dir, NULL);
+ debug_dma_map_sg(dev, sg, nents, ents, dir);
+
+ return ents;
+}
+
+static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir)
+{
+ BUG_ON(!valid_dma_direction(dir));
+ debug_dma_unmap_sg(dev, sg, nents, dir);
+ or1k_unmap_sg(dev, sg, nents, dir, NULL);
+}
+
+static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
+ size_t offset, size_t size,
+ enum dma_data_direction dir)
+{
+ dma_addr_t addr;
+
+ kmemcheck_mark_initialized(page_address(page) + offset, size);
+ BUG_ON(!valid_dma_direction(dir));
+ addr = or1k_map_page(dev, page, offset, size, dir, NULL);
+ debug_dma_map_page(dev, page, offset, size, dir, addr, false);
+
+ return addr;
+}
+
+static inline void dma_unmap_page(struct device *dev, dma_addr_t addr,
+ size_t size, enum dma_data_direction dir)
+{
+ BUG_ON(!valid_dma_direction(dir));
+ or1k_unmap_page(dev, addr, size, dir, NULL);
+ debug_dma_unmap_page(dev, addr, size, dir, true);
+}
+
static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr,
size_t size,
enum dma_data_direction dir)
@@ -119,7 +169,12 @@ static inline void dma_sync_single_for_device(struct device *dev,
static inline int dma_supported(struct device *dev, u64 dma_mask)
{
/* Support 32 bit DMA mask exclusively */
- return dma_mask == 0xffffffffULL;
+ return dma_mask == DMA_BIT_MASK(32);
+}
+
+static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+ return 0;
}
static inline int dma_set_mask(struct device *dev, u64 dma_mask)
diff --git a/arch/openrisc/include/asm/sigcontext.h b/arch/openrisc/include/asm/sigcontext.h
index 54a5c50132e3..b79c2b19afbe 100644
--- a/arch/openrisc/include/asm/sigcontext.h
+++ b/arch/openrisc/include/asm/sigcontext.h
@@ -23,16 +23,11 @@
/* This struct is saved by setup_frame in signal.c, to keep the current
context while a signal handler is executed. It's restored by sys_sigreturn.
-
- To keep things simple, we use pt_regs here even though normally you just
- specify the list of regs to save. Then we can use copy_from_user on the
- entire regs instead of a bunch of get_user's as well...
*/
struct sigcontext {
- struct pt_regs regs; /* needs to be first */
+ struct user_regs_struct regs; /* needs to be first */
unsigned long oldmask;
- unsigned long usp; /* usp before stacking this gunk on it */
};
#endif /* __ASM_OPENRISC_SIGCONTEXT_H */
diff --git a/arch/openrisc/kernel/dma.c b/arch/openrisc/kernel/dma.c
index 968d3ee477e3..f1c8ee2895d0 100644
--- a/arch/openrisc/kernel/dma.c
+++ b/arch/openrisc/kernel/dma.c
@@ -154,6 +154,33 @@ void or1k_unmap_page(struct device *dev, dma_addr_t dma_handle,
/* Nothing special to do here... */
}
+int or1k_map_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct scatterlist *s;
+ int i;
+
+ for_each_sg(sg, s, nents, i) {
+ s->dma_address = or1k_map_page(dev, sg_page(s), s->offset,
+ s->length, dir, NULL);
+ }
+
+ return nents;
+}
+
+void or1k_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct scatterlist *s;
+ int i;
+
+ for_each_sg(sg, s, nents, i) {
+ or1k_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir, NULL);
+ }
+}
+
void or1k_sync_single_for_cpu(struct device *dev,
dma_addr_t dma_handle, size_t size,
enum dma_data_direction dir)
@@ -187,5 +214,4 @@ static int __init dma_init(void)
return 0;
}
-
fs_initcall(dma_init);
diff --git a/arch/openrisc/kernel/signal.c b/arch/openrisc/kernel/signal.c
index 5f759c76834e..95207ab0c99e 100644
--- a/arch/openrisc/kernel/signal.c
+++ b/arch/openrisc/kernel/signal.c
@@ -52,31 +52,25 @@ struct rt_sigframe {
static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
{
unsigned int err = 0;
- unsigned long old_usp;
/* Alwys make any pending restarted system call return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
- /* restore the regs from &sc->regs (same as sc, since regs is first)
+ /*
+ * Restore the regs from &sc->regs.
* (sc is already checked for VERIFY_READ since the sigframe was
* checked in sys_sigreturn previously)
*/
-
- if (__copy_from_user(regs, sc, sizeof(struct pt_regs)))
+ if (__copy_from_user(regs, sc->regs.gpr, 32 * sizeof(unsigned long)))
+ goto badframe;
+ if (__copy_from_user(&regs->pc, &sc->regs.pc, sizeof(unsigned long)))
+ goto badframe;
+ if (__copy_from_user(&regs->sr, &sc->regs.sr, sizeof(unsigned long)))
goto badframe;
/* make sure the SM-bit is cleared so user-mode cannot fool us */
regs->sr &= ~SPR_SR_SM;
- /* restore the old USP as it was before we stacked the sc etc.
- * (we cannot just pop the sigcontext since we aligned the sp and
- * stuff after pushing it)
- */
-
- err |= __get_user(old_usp, &sc->usp);
-
- regs->sp = old_usp;
-
/* TODO: the other ports use regs->orig_XX to disable syscall checks
* after this completes, but we don't use that mechanism. maybe we can
* use it now ?
@@ -137,18 +131,17 @@ static int setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
unsigned long mask)
{
int err = 0;
- unsigned long usp = regs->sp;
- /* copy the regs. they are first in sc so we can use sc directly */
+ /* copy the regs */
- err |= __copy_to_user(sc, regs, sizeof(struct pt_regs));
+ err |= __copy_to_user(sc->regs.gpr, regs, 32 * sizeof(unsigned long));
+ err |= __copy_to_user(&sc->regs.pc, &regs->pc, sizeof(unsigned long));
+ err |= __copy_to_user(&sc->regs.sr, &regs->sr, sizeof(unsigned long));
/* then some other stuff */
err |= __put_user(mask, &sc->oldmask);
- err |= __put_user(usp, &sc->usp);
-
return err;
}
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index e077b0bf56ca..fdfd8be29e95 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -169,9 +169,7 @@ config 64BIT
choice
prompt "Kernel page size"
- default PARISC_PAGE_SIZE_4KB if !64BIT
- default PARISC_PAGE_SIZE_4KB if 64BIT
-# default PARISC_PAGE_SIZE_16KB if 64BIT
+ default PARISC_PAGE_SIZE_4KB
config PARISC_PAGE_SIZE_4KB
bool "4KB"
diff --git a/arch/parisc/include/asm/dma-mapping.h b/arch/parisc/include/asm/dma-mapping.h
index 890531e32fe8..467bbd510eac 100644
--- a/arch/parisc/include/asm/dma-mapping.h
+++ b/arch/parisc/include/asm/dma-mapping.h
@@ -5,7 +5,7 @@
#include <asm/cacheflush.h>
#include <asm/scatterlist.h>
-/* See Documentation/PCI/PCI-DMA-mapping.txt */
+/* See Documentation/DMA-API-HOWTO.txt */
struct hppa_dma_ops {
int (*dma_supported)(struct device *dev, u64 mask);
void *(*alloc_consistent)(struct device *dev, size_t size, dma_addr_t *iova, gfp_t flag);
diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c
index a029f74a3c5c..d047edea2504 100644
--- a/arch/parisc/kernel/pci-dma.c
+++ b/arch/parisc/kernel/pci-dma.c
@@ -2,7 +2,7 @@
** PARISC 1.1 Dynamic DMA mapping support.
** This implementation is for PA-RISC platforms that do not support
** I/O TLBs (aka DMA address translation hardware).
-** See Documentation/PCI/PCI-DMA-mapping.txt for interface definitions.
+** See Documentation/DMA-API-HOWTO.txt for interface definitions.
**
** (c) Copyright 1999,2000 Hewlett-Packard Company
** (c) Copyright 2000 Grant Grundler
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
index e66366fd2abc..3735abd7f8f6 100644
--- a/arch/parisc/kernel/syscall_table.S
+++ b/arch/parisc/kernel/syscall_table.S
@@ -259,7 +259,7 @@
ENTRY_SAME(ni_syscall) /* query_module */
ENTRY_SAME(poll)
/* structs contain pointers and an in_addr... */
- ENTRY_COMP(nfsservctl)
+ ENTRY_SAME(ni_syscall) /* was nfsservctl */
ENTRY_SAME(setresgid) /* 170 */
ENTRY_SAME(getresgid)
ENTRY_SAME(prctl)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 6926b61acfea..47682b67fd36 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -656,6 +656,8 @@ config SBUS
config FSL_SOC
bool
+ select HAVE_CAN_FLEXCAN if NET && CAN
+ select PPC_CLOCK if CAN_FLEXCAN
config FSL_PCI
bool
diff --git a/arch/powerpc/boot/dts/p1010rdb.dts b/arch/powerpc/boot/dts/p1010rdb.dts
index 6b33b73a5ba0..d6c669c888e9 100644
--- a/arch/powerpc/boot/dts/p1010rdb.dts
+++ b/arch/powerpc/boot/dts/p1010rdb.dts
@@ -23,6 +23,8 @@
ethernet2 = &enet2;
pci0 = &pci0;
pci1 = &pci1;
+ can0 = &can0;
+ can1 = &can1;
};
memory {
@@ -169,14 +171,6 @@
};
};
- can0@1c000 {
- fsl,flexcan-clock-source = "platform";
- };
-
- can1@1d000 {
- fsl,flexcan-clock-source = "platform";
- };
-
usb@22000 {
phy_type = "utmi";
};
diff --git a/arch/powerpc/boot/dts/p1010si.dtsi b/arch/powerpc/boot/dts/p1010si.dtsi
index 7f51104f2e36..cabe0a453ae6 100644
--- a/arch/powerpc/boot/dts/p1010si.dtsi
+++ b/arch/powerpc/boot/dts/p1010si.dtsi
@@ -140,20 +140,18 @@
interrupt-parent = <&mpic>;
};
- can0@1c000 {
- compatible = "fsl,flexcan-v1.0";
+ can0: can@1c000 {
+ compatible = "fsl,p1010-flexcan";
reg = <0x1c000 0x1000>;
interrupts = <48 0x2>;
interrupt-parent = <&mpic>;
- fsl,flexcan-clock-divider = <2>;
};
- can1@1d000 {
- compatible = "fsl,flexcan-v1.0";
+ can1: can@1d000 {
+ compatible = "fsl,p1010-flexcan";
reg = <0x1d000 0x1000>;
interrupts = <61 0x2>;
interrupt-parent = <&mpic>;
- fsl,flexcan-clock-divider = <2>;
};
L2: l2-cache-controller@20000 {
diff --git a/arch/powerpc/boot/dts/p1023rds.dts b/arch/powerpc/boot/dts/p1023rds.dts
index bfa96aa8f2ca..d9b776740a67 100644
--- a/arch/powerpc/boot/dts/p1023rds.dts
+++ b/arch/powerpc/boot/dts/p1023rds.dts
@@ -387,7 +387,7 @@
#size-cells = <1>;
compatible = "cfi-flash";
reg = <0x0 0x0 0x02000000>;
- bank-width = <1>;
+ bank-width = <2>;
device-width = <1>;
partition@0 {
label = "ramdisk";
diff --git a/arch/powerpc/configs/40x/acadia_defconfig b/arch/powerpc/configs/40x/acadia_defconfig
index 4182c772340b..ed3bab72a834 100644
--- a/arch/powerpc/configs/40x/acadia_defconfig
+++ b/arch/powerpc/configs/40x/acadia_defconfig
@@ -44,12 +44,13 @@ CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=35000
# CONFIG_MISC_DEVICES is not set
CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_IBM=y
CONFIG_MII=y
-CONFIG_IBM_NEW_EMAC=y
-CONFIG_IBM_NEW_EMAC_RXB=256
-CONFIG_IBM_NEW_EMAC_TXB=256
-CONFIG_IBM_NEW_EMAC_DEBUG=y
+CONFIG_IBM_EMAC=y
+CONFIG_IBM_EMAC_RXB=256
+CONFIG_IBM_EMAC_TXB=256
+CONFIG_IBM_EMAC_DEBUG=y
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
# CONFIG_INPUT is not set
diff --git a/arch/powerpc/configs/40x/ep405_defconfig b/arch/powerpc/configs/40x/ep405_defconfig
index 2dbb293163f5..17582a3420fb 100644
--- a/arch/powerpc/configs/40x/ep405_defconfig
+++ b/arch/powerpc/configs/40x/ep405_defconfig
@@ -42,8 +42,9 @@ CONFIG_PROC_DEVICETREE=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=35000
CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_IBM_NEW_EMAC=y
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_IBM_EMAC=y
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
diff --git a/arch/powerpc/configs/40x/hcu4_defconfig b/arch/powerpc/configs/40x/hcu4_defconfig
index ebeb4accad65..dba263c1d3a2 100644
--- a/arch/powerpc/configs/40x/hcu4_defconfig
+++ b/arch/powerpc/configs/40x/hcu4_defconfig
@@ -43,8 +43,9 @@ CONFIG_PROC_DEVICETREE=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=35000
CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_IBM_NEW_EMAC=y
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_IBM_EMAC=y
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
diff --git a/arch/powerpc/configs/40x/kilauea_defconfig b/arch/powerpc/configs/40x/kilauea_defconfig
index 532ea9d93a15..f2d4be936e08 100644
--- a/arch/powerpc/configs/40x/kilauea_defconfig
+++ b/arch/powerpc/configs/40x/kilauea_defconfig
@@ -51,10 +51,11 @@ CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=35000
# CONFIG_MISC_DEVICES is not set
CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_IBM_NEW_EMAC=y
-CONFIG_IBM_NEW_EMAC_RXB=256
-CONFIG_IBM_NEW_EMAC_TXB=256
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_IBM_EMAC=y
+CONFIG_IBM_EMAC_RXB=256
+CONFIG_IBM_EMAC_TXB=256
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
# CONFIG_INPUT is not set
diff --git a/arch/powerpc/configs/40x/makalu_defconfig b/arch/powerpc/configs/40x/makalu_defconfig
index 3c142ac1b344..42b979355f9b 100644
--- a/arch/powerpc/configs/40x/makalu_defconfig
+++ b/arch/powerpc/configs/40x/makalu_defconfig
@@ -43,10 +43,11 @@ CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=35000
# CONFIG_MISC_DEVICES is not set
CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_IBM_NEW_EMAC=y
-CONFIG_IBM_NEW_EMAC_RXB=256
-CONFIG_IBM_NEW_EMAC_TXB=256
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_IBM_EMAC=y
+CONFIG_IBM_EMAC_RXB=256
+CONFIG_IBM_EMAC_TXB=256
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
# CONFIG_INPUT is not set
diff --git a/arch/powerpc/configs/40x/walnut_defconfig b/arch/powerpc/configs/40x/walnut_defconfig
index ff57d4828ffc..aa1a4cac3708 100644
--- a/arch/powerpc/configs/40x/walnut_defconfig
+++ b/arch/powerpc/configs/40x/walnut_defconfig
@@ -40,8 +40,9 @@ CONFIG_PROC_DEVICETREE=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=35000
CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_IBM_NEW_EMAC=y
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_IBM_EMAC=y
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
diff --git a/arch/powerpc/configs/44x/arches_defconfig b/arch/powerpc/configs/44x/arches_defconfig
index 3ed16d5c909d..329f9a3b892e 100644
--- a/arch/powerpc/configs/44x/arches_defconfig
+++ b/arch/powerpc/configs/44x/arches_defconfig
@@ -44,10 +44,11 @@ CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=35000
# CONFIG_MISC_DEVICES is not set
CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_IBM_NEW_EMAC=y
-CONFIG_IBM_NEW_EMAC_RXB=256
-CONFIG_IBM_NEW_EMAC_TXB=256
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_IBM_EMAC=y
+CONFIG_IBM_EMAC_RXB=256
+CONFIG_IBM_EMAC_TXB=256
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
# CONFIG_INPUT is not set
diff --git a/arch/powerpc/configs/44x/bamboo_defconfig b/arch/powerpc/configs/44x/bamboo_defconfig
index b1b7d2c5c059..cef7d62560c4 100644
--- a/arch/powerpc/configs/44x/bamboo_defconfig
+++ b/arch/powerpc/configs/44x/bamboo_defconfig
@@ -32,8 +32,9 @@ CONFIG_PROC_DEVICETREE=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=35000
CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_IBM_NEW_EMAC=y
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_IBM_EMAC=y
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
diff --git a/arch/powerpc/configs/44x/bluestone_defconfig b/arch/powerpc/configs/44x/bluestone_defconfig
index 30a0a8e08fdd..20c8d26d7fc0 100644
--- a/arch/powerpc/configs/44x/bluestone_defconfig
+++ b/arch/powerpc/configs/44x/bluestone_defconfig
@@ -38,10 +38,11 @@ CONFIG_PROC_DEVICETREE=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=35000
CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_IBM_NEW_EMAC=y
-CONFIG_IBM_NEW_EMAC_RXB=256
-CONFIG_IBM_NEW_EMAC_TXB=256
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_IBM_EMAC=y
+CONFIG_IBM_EMAC_RXB=256
+CONFIG_IBM_EMAC_TXB=256
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_NR_UARTS=2
diff --git a/arch/powerpc/configs/44x/canyonlands_defconfig b/arch/powerpc/configs/44x/canyonlands_defconfig
index a46942aac695..d5be93e6e92d 100644
--- a/arch/powerpc/configs/44x/canyonlands_defconfig
+++ b/arch/powerpc/configs/44x/canyonlands_defconfig
@@ -49,10 +49,11 @@ CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=35000
# CONFIG_MISC_DEVICES is not set
CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_IBM_NEW_EMAC=y
-CONFIG_IBM_NEW_EMAC_RXB=256
-CONFIG_IBM_NEW_EMAC_TXB=256
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_IBM_EMAC=y
+CONFIG_IBM_EMAC_RXB=256
+CONFIG_IBM_EMAC_TXB=256
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
# CONFIG_INPUT is not set
diff --git a/arch/powerpc/configs/44x/ebony_defconfig b/arch/powerpc/configs/44x/ebony_defconfig
index 07d77e51f1ba..f9269fc4ffcc 100644
--- a/arch/powerpc/configs/44x/ebony_defconfig
+++ b/arch/powerpc/configs/44x/ebony_defconfig
@@ -40,8 +40,9 @@ CONFIG_PROC_DEVICETREE=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=35000
CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_IBM_NEW_EMAC=y
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_IBM_EMAC=y
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
diff --git a/arch/powerpc/configs/44x/eiger_defconfig b/arch/powerpc/configs/44x/eiger_defconfig
index 2ce7e9aff09e..9be089038fd7 100644
--- a/arch/powerpc/configs/44x/eiger_defconfig
+++ b/arch/powerpc/configs/44x/eiger_defconfig
@@ -55,10 +55,11 @@ CONFIG_FUSION=y
CONFIG_FUSION_SAS=y
CONFIG_I2O=y
CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_IBM_NEW_EMAC=y
-CONFIG_IBM_NEW_EMAC_RXB=256
-CONFIG_IBM_NEW_EMAC_TXB=256
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_IBM_EMAC=y
+CONFIG_IBM_EMAC_RXB=256
+CONFIG_IBM_EMAC_TXB=256
CONFIG_E1000E=y
# CONFIG_NETDEV_10000 is not set
# CONFIG_INPUT is not set
diff --git a/arch/powerpc/configs/44x/icon_defconfig b/arch/powerpc/configs/44x/icon_defconfig
index 18730ff9de7c..82f73035a7ce 100644
--- a/arch/powerpc/configs/44x/icon_defconfig
+++ b/arch/powerpc/configs/44x/icon_defconfig
@@ -56,8 +56,9 @@ CONFIG_FUSION_SAS=y
CONFIG_FUSION_CTL=y
CONFIG_FUSION_LOGGING=y
CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_IBM_NEW_EMAC=y
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_IBM_EMAC=y
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
# CONFIG_WLAN is not set
diff --git a/arch/powerpc/configs/44x/katmai_defconfig b/arch/powerpc/configs/44x/katmai_defconfig
index 34c09144a699..109562c3c6be 100644
--- a/arch/powerpc/configs/44x/katmai_defconfig
+++ b/arch/powerpc/configs/44x/katmai_defconfig
@@ -42,8 +42,9 @@ CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=35000
CONFIG_MACINTOSH_DRIVERS=y
CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_IBM_NEW_EMAC=y
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_IBM_EMAC=y
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
diff --git a/arch/powerpc/configs/44x/redwood_defconfig b/arch/powerpc/configs/44x/redwood_defconfig
index 01cc2b1a7f9a..48802811da76 100644
--- a/arch/powerpc/configs/44x/redwood_defconfig
+++ b/arch/powerpc/configs/44x/redwood_defconfig
@@ -53,11 +53,12 @@ CONFIG_FUSION=y
CONFIG_FUSION_SAS=y
CONFIG_I2O=y
CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_IBM_NEW_EMAC=y
-CONFIG_IBM_NEW_EMAC_RXB=256
-CONFIG_IBM_NEW_EMAC_TXB=256
-CONFIG_IBM_NEW_EMAC_DEBUG=y
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_IBM_EMAC=y
+CONFIG_IBM_EMAC_RXB=256
+CONFIG_IBM_EMAC_TXB=256
+CONFIG_IBM_EMAC_DEBUG=y
CONFIG_E1000E=y
# CONFIG_NETDEV_10000 is not set
# CONFIG_INPUT is not set
diff --git a/arch/powerpc/configs/44x/sam440ep_defconfig b/arch/powerpc/configs/44x/sam440ep_defconfig
index dfcffede16ad..ca088cd581af 100644
--- a/arch/powerpc/configs/44x/sam440ep_defconfig
+++ b/arch/powerpc/configs/44x/sam440ep_defconfig
@@ -44,8 +44,9 @@ CONFIG_ATA=y
# CONFIG_SATA_PMP is not set
CONFIG_SATA_SIL=y
CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_IBM_NEW_EMAC=y
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_IBM_EMAC=y
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
CONFIG_INPUT_FF_MEMLESS=m
diff --git a/arch/powerpc/configs/44x/sequoia_defconfig b/arch/powerpc/configs/44x/sequoia_defconfig
index 47e399f2892f..b7a653b626db 100644
--- a/arch/powerpc/configs/44x/sequoia_defconfig
+++ b/arch/powerpc/configs/44x/sequoia_defconfig
@@ -46,8 +46,9 @@ CONFIG_PROC_DEVICETREE=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=35000
CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_IBM_NEW_EMAC=y
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_IBM_EMAC=y
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
diff --git a/arch/powerpc/configs/44x/taishan_defconfig b/arch/powerpc/configs/44x/taishan_defconfig
index a6a002ed5681..30de97f158a4 100644
--- a/arch/powerpc/configs/44x/taishan_defconfig
+++ b/arch/powerpc/configs/44x/taishan_defconfig
@@ -40,8 +40,9 @@ CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=35000
CONFIG_MACINTOSH_DRIVERS=y
CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_IBM_NEW_EMAC=y
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_IBM_EMAC=y
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
diff --git a/arch/powerpc/configs/44x/warp_defconfig b/arch/powerpc/configs/44x/warp_defconfig
index abf74dc1f79c..105bc56f4b2b 100644
--- a/arch/powerpc/configs/44x/warp_defconfig
+++ b/arch/powerpc/configs/44x/warp_defconfig
@@ -54,9 +54,10 @@ CONFIG_BLK_DEV_SD=y
CONFIG_SCSI_SPI_ATTRS=y
# CONFIG_SCSI_LOWLEVEL is not set
CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_IBM=y
CONFIG_MII=y
-CONFIG_IBM_NEW_EMAC=y
+CONFIG_IBM_EMAC=y
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
# CONFIG_INPUT is not set
diff --git a/arch/powerpc/configs/85xx/p1023rds_defconfig b/arch/powerpc/configs/85xx/p1023rds_defconfig
index 980ff8f61fd4..3ff5a81c709f 100644
--- a/arch/powerpc/configs/85xx/p1023rds_defconfig
+++ b/arch/powerpc/configs/85xx/p1023rds_defconfig
@@ -171,3 +171,4 @@ CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_SHA512=y
CONFIG_CRYPTO_AES=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_DEV_FSL_CAAM=y
diff --git a/arch/powerpc/configs/corenet32_smp_defconfig b/arch/powerpc/configs/corenet32_smp_defconfig
index 10562a5c65b9..4311d02a3bfd 100644
--- a/arch/powerpc/configs/corenet32_smp_defconfig
+++ b/arch/powerpc/configs/corenet32_smp_defconfig
@@ -185,3 +185,4 @@ CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_SHA512=y
CONFIG_CRYPTO_AES=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_DEV_FSL_CAAM=y
diff --git a/arch/powerpc/configs/corenet64_smp_defconfig b/arch/powerpc/configs/corenet64_smp_defconfig
index d32283555b53..c92c204a204b 100644
--- a/arch/powerpc/configs/corenet64_smp_defconfig
+++ b/arch/powerpc/configs/corenet64_smp_defconfig
@@ -100,5 +100,8 @@ CONFIG_DEBUG_INFO=y
CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_VIRQ_DEBUG=y
CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA512=y
+CONFIG_CRYPTO_AES=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRYPTO_DEV_TALITOS=y
+CONFIG_CRYPTO_DEV_FSL_CAAM=y
diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig
index fcd85d2c72dc..a3467bfb7671 100644
--- a/arch/powerpc/configs/mpc85xx_defconfig
+++ b/arch/powerpc/configs/mpc85xx_defconfig
@@ -139,6 +139,7 @@ CONFIG_SND=y
CONFIG_SND_INTEL8X0=y
# CONFIG_SND_PPC is not set
# CONFIG_SND_USB is not set
+CONFIG_SND_SOC=y
CONFIG_HID_A4TECH=y
CONFIG_HID_APPLE=y
CONFIG_HID_BELKIN=y
diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig
index 908c941fc24c..9693f6ed3da0 100644
--- a/arch/powerpc/configs/mpc85xx_smp_defconfig
+++ b/arch/powerpc/configs/mpc85xx_smp_defconfig
@@ -140,6 +140,7 @@ CONFIG_SND=y
CONFIG_SND_INTEL8X0=y
# CONFIG_SND_PPC is not set
# CONFIG_SND_USB is not set
+CONFIG_SND_SOC=y
CONFIG_HID_A4TECH=y
CONFIG_HID_APPLE=y
CONFIG_HID_BELKIN=y
diff --git a/arch/powerpc/configs/ppc40x_defconfig b/arch/powerpc/configs/ppc40x_defconfig
index bfd634b5ada7..7cb703b948b1 100644
--- a/arch/powerpc/configs/ppc40x_defconfig
+++ b/arch/powerpc/configs/ppc40x_defconfig
@@ -50,8 +50,9 @@ CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=35000
CONFIG_XILINX_SYSACE=m
CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_IBM_NEW_EMAC=y
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_IBM_EMAC=y
# CONFIG_INPUT is not set
CONFIG_SERIO=m
# CONFIG_SERIO_I8042 is not set
diff --git a/arch/powerpc/configs/ppc44x_defconfig b/arch/powerpc/configs/ppc44x_defconfig
index 47133202a625..6cdf1c0d2c8a 100644
--- a/arch/powerpc/configs/ppc44x_defconfig
+++ b/arch/powerpc/configs/ppc44x_defconfig
@@ -63,8 +63,9 @@ CONFIG_BLK_DEV_SD=m
# CONFIG_SCSI_LOWLEVEL is not set
CONFIG_NETDEVICES=y
CONFIG_TUN=m
-CONFIG_NET_ETHERNET=y
-CONFIG_IBM_NEW_EMAC=y
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_IBM_EMAC=y
# CONFIG_INPUT is not set
CONFIG_SERIO=m
# CONFIG_SERIO_I8042 is not set
diff --git a/arch/powerpc/include/asm/qe.h b/arch/powerpc/include/asm/qe.h
index 0947b36e534c..5e0b6d511e14 100644
--- a/arch/powerpc/include/asm/qe.h
+++ b/arch/powerpc/include/asm/qe.h
@@ -196,7 +196,7 @@ static inline int qe_alive_during_sleep(void)
/* Structure that defines QE firmware binary files.
*
- * See Documentation/powerpc/qe-firmware.txt for a description of these
+ * See Documentation/powerpc/qe_firmware.txt for a description of these
* fields.
*/
struct qe_firmware {
diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h
index f6736b7da463..fa0d27a400de 100644
--- a/arch/powerpc/include/asm/systbl.h
+++ b/arch/powerpc/include/asm/systbl.h
@@ -171,7 +171,7 @@ SYSCALL_SPU(setresuid)
SYSCALL_SPU(getresuid)
SYSCALL(ni_syscall)
SYSCALL_SPU(poll)
-COMPAT_SYS(nfsservctl)
+SYSCALL(ni_syscall)
SYSCALL_SPU(setresgid)
SYSCALL_SPU(getresgid)
COMPAT_SYS_SPU(prctl)
diff --git a/arch/powerpc/platforms/40x/Kconfig b/arch/powerpc/platforms/40x/Kconfig
index d733d7ca939c..b5d87067a58b 100644
--- a/arch/powerpc/platforms/40x/Kconfig
+++ b/arch/powerpc/platforms/40x/Kconfig
@@ -130,21 +130,21 @@ config 405GP
bool
select IBM405_ERR77
select IBM405_ERR51
- select IBM_NEW_EMAC_ZMII
+ select IBM_EMAC_ZMII
config 405EP
bool
config 405EX
bool
- select IBM_NEW_EMAC_EMAC4
- select IBM_NEW_EMAC_RGMII
+ select IBM_EMAC_EMAC4
+ select IBM_EMAC_RGMII
config 405EZ
bool
- select IBM_NEW_EMAC_NO_FLOW_CTRL
- select IBM_NEW_EMAC_MAL_CLR_ICINTSTAT
- select IBM_NEW_EMAC_MAL_COMMON_ERR
+ select IBM_EMAC_NO_FLOW_CTRL
+ select IBM_EMAC_MAL_CLR_ICINTSTAT
+ select IBM_EMAC_MAL_COMMON_ERR
config 405GPR
bool
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index e958b6f48ec2..762322ce24a9 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -23,7 +23,7 @@ config BLUESTONE
default n
select PPC44x_SIMPLE
select APM821xx
- select IBM_NEW_EMAC_RGMII
+ select IBM_EMAC_RGMII
help
This option enables support for the APM APM821xx Evaluation board.
@@ -122,8 +122,8 @@ config CANYONLANDS
select PPC4xx_PCI_EXPRESS
select PCI_MSI
select PPC4xx_MSI
- select IBM_NEW_EMAC_RGMII
- select IBM_NEW_EMAC_ZMII
+ select IBM_EMAC_RGMII
+ select IBM_EMAC_ZMII
help
This option enables support for the AMCC PPC460EX evaluation board.
@@ -135,8 +135,8 @@ config GLACIER
select 460EX # Odd since it uses 460GT but the effects are the same
select PCI
select PPC4xx_PCI_EXPRESS
- select IBM_NEW_EMAC_RGMII
- select IBM_NEW_EMAC_ZMII
+ select IBM_EMAC_RGMII
+ select IBM_EMAC_ZMII
help
This option enables support for the AMCC PPC460GT evaluation board.
@@ -161,7 +161,7 @@ config EIGER
select 460SX
select PCI
select PPC4xx_PCI_EXPRESS
- select IBM_NEW_EMAC_RGMII
+ select IBM_EMAC_RGMII
help
This option enables support for the AMCC PPC460SX evaluation board.
@@ -260,59 +260,59 @@ config 440EP
bool
select PPC_FPU
select IBM440EP_ERR42
- select IBM_NEW_EMAC_ZMII
+ select IBM_EMAC_ZMII
select USB_ARCH_HAS_OHCI
config 440EPX
bool
select PPC_FPU
- select IBM_NEW_EMAC_EMAC4
- select IBM_NEW_EMAC_RGMII
- select IBM_NEW_EMAC_ZMII
+ select IBM_EMAC_EMAC4
+ select IBM_EMAC_RGMII
+ select IBM_EMAC_ZMII
config 440GRX
bool
- select IBM_NEW_EMAC_EMAC4
- select IBM_NEW_EMAC_RGMII
- select IBM_NEW_EMAC_ZMII
+ select IBM_EMAC_EMAC4
+ select IBM_EMAC_RGMII
+ select IBM_EMAC_ZMII
config 440GP
bool
- select IBM_NEW_EMAC_ZMII
+ select IBM_EMAC_ZMII
config 440GX
bool
- select IBM_NEW_EMAC_EMAC4
- select IBM_NEW_EMAC_RGMII
- select IBM_NEW_EMAC_ZMII #test only
- select IBM_NEW_EMAC_TAH #test only
+ select IBM_EMAC_EMAC4
+ select IBM_EMAC_RGMII
+ select IBM_EMAC_ZMII #test only
+ select IBM_EMAC_TAH #test only
config 440SP
bool
config 440SPe
bool
- select IBM_NEW_EMAC_EMAC4
+ select IBM_EMAC_EMAC4
config 460EX
bool
select PPC_FPU
- select IBM_NEW_EMAC_EMAC4
- select IBM_NEW_EMAC_TAH
+ select IBM_EMAC_EMAC4
+ select IBM_EMAC_TAH
config 460SX
bool
select PPC_FPU
- select IBM_NEW_EMAC_EMAC4
- select IBM_NEW_EMAC_RGMII
- select IBM_NEW_EMAC_ZMII
- select IBM_NEW_EMAC_TAH
+ select IBM_EMAC_EMAC4
+ select IBM_EMAC_RGMII
+ select IBM_EMAC_ZMII
+ select IBM_EMAC_TAH
config APM821xx
bool
select PPC_FPU
- select IBM_NEW_EMAC_EMAC4
- select IBM_NEW_EMAC_TAH
+ select IBM_EMAC_EMAC4
+ select IBM_EMAC_TAH
# 44x errata/workaround config symbols, selected by the CPU models above
config IBM440EP_ERR42
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index 498534cd5265..12f5932dadc9 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -80,7 +80,7 @@ config P1010_RDB
config P1022_DS
bool "Freescale P1022 DS"
select DEFAULT_UIMAGE
- select CONFIG_PHYS_64BIT # The DTS has 36-bit addresses
+ select PHYS_64BIT # The DTS has 36-bit addresses
select SWIOTLB
help
This option enables support for the Freescale P1022DS reference board.
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
index 67d5009b4e86..2e7ff0c5cf42 100644
--- a/arch/powerpc/platforms/cell/Kconfig
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -17,10 +17,10 @@ config PPC_CELL_NATIVE
select PPC_CELL_COMMON
select MPIC
select PPC_IO_WORKAROUNDS
- select IBM_NEW_EMAC_EMAC4
- select IBM_NEW_EMAC_RGMII
- select IBM_NEW_EMAC_ZMII #test only
- select IBM_NEW_EMAC_TAH #test only
+ select IBM_EMAC_EMAC4
+ select IBM_EMAC_RGMII
+ select IBM_EMAC_ZMII #test only
+ select IBM_EMAC_TAH #test only
default n
config PPC_IBM_CELL_BLADE
diff --git a/arch/powerpc/platforms/embedded6xx/storcenter.c b/arch/powerpc/platforms/embedded6xx/storcenter.c
index 613070e9ddbe..f1eebcae9bf0 100644
--- a/arch/powerpc/platforms/embedded6xx/storcenter.c
+++ b/arch/powerpc/platforms/embedded6xx/storcenter.c
@@ -77,7 +77,7 @@ static void __init storcenter_setup_arch(void)
}
/*
- * Interrupt setup and service. Interrrupts on the turbostation come
+ * Interrupt setup and service. Interrupts on the turbostation come
* from the four PCI slots plus onboard 8241 devices: I2C, DUART.
*/
static void __init storcenter_init_IRQ(void)
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index 5cc83851ad06..31a7d3a7ce25 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -561,6 +561,20 @@ static struct pci_ops u4_pcie_pci_ops =
.write = u4_pcie_write_config,
};
+static void __devinit pmac_pci_fixup_u4_of_node(struct pci_dev *dev)
+{
+ /* Apple's device-tree "hides" the root complex virtual P2P bridge
+ * on U4. However, Linux sees it, causing the PCI <-> OF matching
+ * code to fail to properly match devices below it. This works around
+ * it by setting the node of the bridge to point to the PHB node,
+ * which is not entirely correct but fixes the matching code and
+ * doesn't break anything else. It's also the simplest possible fix.
+ */
+ if (dev->dev.of_node == NULL)
+ dev->dev.of_node = pcibios_get_phb_of_node(dev->bus);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_APPLE, 0x5b, pmac_pci_fixup_u4_of_node);
+
#endif /* CONFIG_PPC64 */
#ifdef CONFIG_PPC32
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
index 2de8551df40f..c65f75aa7ff7 100644
--- a/arch/powerpc/sysdev/fsl_rio.c
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -54,6 +54,7 @@
#define ODSR_CLEAR 0x1c00
#define LTLEECSR_ENABLE_ALL 0xFFC000FC
#define ESCSR_CLEAR 0x07120204
+#define IECSR_CLEAR 0x80000000
#define RIO_PORT1_EDCSR 0x0640
#define RIO_PORT2_EDCSR 0x0680
@@ -1089,11 +1090,11 @@ static void port_error_handler(struct rio_mport *port, int offset)
if (offset == 0) {
out_be32((u32 *)(rio_regs_win + RIO_PORT1_EDCSR), 0);
- out_be32((u32 *)(rio_regs_win + RIO_PORT1_IECSR), 0);
+ out_be32((u32 *)(rio_regs_win + RIO_PORT1_IECSR), IECSR_CLEAR);
out_be32((u32 *)(rio_regs_win + RIO_ESCSR), ESCSR_CLEAR);
} else {
out_be32((u32 *)(rio_regs_win + RIO_PORT2_EDCSR), 0);
- out_be32((u32 *)(rio_regs_win + RIO_PORT2_IECSR), 0);
+ out_be32((u32 *)(rio_regs_win + RIO_PORT2_IECSR), IECSR_CLEAR);
out_be32((u32 *)(rio_regs_win + RIO_PORT2_ESCSR), ESCSR_CLEAR);
}
}
diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c
index 904c6cbaf45b..3363fbc964f8 100644
--- a/arch/powerpc/sysdev/qe_lib/qe.c
+++ b/arch/powerpc/sysdev/qe_lib/qe.c
@@ -382,7 +382,7 @@ static void qe_upload_microcode(const void *base,
/*
* Upload a microcode to the I-RAM at a specific address.
*
- * See Documentation/powerpc/qe-firmware.txt for information on QE microcode
+ * See Documentation/powerpc/qe_firmware.txt for information on QE microcode
* uploading.
*
* Currently, only version 1 is supported, so the 'version' field must be
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index ed5cb5af5281..6b99fc3f9b63 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -91,6 +91,7 @@ config S390
select HAVE_ARCH_MUTEX_CPU_RELAX
select HAVE_ARCH_JUMP_LABEL if !MARCH_G5
select HAVE_RCU_TABLE_FREE if SMP
+ select ARCH_SAVE_PAGE_KEYS if HIBERNATION
select ARCH_INLINE_SPIN_TRYLOCK
select ARCH_INLINE_SPIN_TRYLOCK_BH
select ARCH_INLINE_SPIN_LOCK
diff --git a/arch/s390/hypfs/hypfs_diag.c b/arch/s390/hypfs/hypfs_diag.c
index 6023c6dc1fb7..74c8f5e76ce4 100644
--- a/arch/s390/hypfs/hypfs_diag.c
+++ b/arch/s390/hypfs/hypfs_diag.c
@@ -562,10 +562,9 @@ static int dbfs_d204_create(void **data, void **data_free_ptr, size_t *size)
void *base;
buf_size = PAGE_SIZE * (diag204_buf_pages + 1) + sizeof(d204->hdr);
- base = vmalloc(buf_size);
+ base = vzalloc(buf_size);
if (!base)
return -ENOMEM;
- memset(base, 0, buf_size);
d204 = page_align_ptr(base + sizeof(d204->hdr)) - sizeof(d204->hdr);
rc = diag204_do_store(d204->buf, diag204_buf_pages);
if (rc) {
diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h
index 64b61bf72e93..547f1a6a35d4 100644
--- a/arch/s390/include/asm/elf.h
+++ b/arch/s390/include/asm/elf.h
@@ -188,7 +188,8 @@ extern char elf_platform[];
#define SET_PERSONALITY(ex) \
do { \
if (personality(current->personality) != PER_LINUX32) \
- set_personality(PER_LINUX); \
+ set_personality(PER_LINUX | \
+ (current->personality & ~PER_MASK)); \
if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \
set_thread_flag(TIF_31BIT); \
else \
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 519eb5f187ef..c0cb794bb365 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -658,12 +658,14 @@ static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste)
* struct gmap_struct - guest address space
* @mm: pointer to the parent mm_struct
* @table: pointer to the page directory
+ * @asce: address space control element for gmap page table
* @crst_list: list of all crst tables used in the guest address space
*/
struct gmap {
struct list_head list;
struct mm_struct *mm;
unsigned long *table;
+ unsigned long asce;
struct list_head crst_list;
};
diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h
index 15c97625df8d..21993623da9a 100644
--- a/arch/s390/include/asm/qdio.h
+++ b/arch/s390/include/asm/qdio.h
@@ -123,6 +123,40 @@ struct slibe {
};
/**
+ * struct qaob - queue asynchronous operation block
+ * @res0: reserved parameters
+ * @res1: reserved parameter
+ * @res2: reserved parameter
+ * @res3: reserved parameter
+ * @aorc: asynchronous operation return code
+ * @flags: internal flags
+ * @cbtbs: control block type
+ * @sb_count: number of storage blocks
+ * @sba: storage block element addresses
+ * @dcount: size of storage block elements
+ * @user0: user defineable value
+ * @res4: reserved paramater
+ * @user1: user defineable value
+ * @user2: user defineable value
+ */
+struct qaob {
+ u64 res0[6];
+ u8 res1;
+ u8 res2;
+ u8 res3;
+ u8 aorc;
+ u8 flags;
+ u16 cbtbs;
+ u8 sb_count;
+ u64 sba[QDIO_MAX_ELEMENTS_PER_BUFFER];
+ u16 dcount[QDIO_MAX_ELEMENTS_PER_BUFFER];
+ u64 user0;
+ u64 res4[2];
+ u64 user1;
+ u64 user2;
+} __attribute__ ((packed, aligned(256)));
+
+/**
* struct slib - storage list information block (SLIB)
* @nsliba: next SLIB address (if any)
* @sla: SL address
@@ -225,6 +259,41 @@ struct slsb {
#define CHSC_AC2_DATA_DIV_AVAILABLE 0x0010
#define CHSC_AC2_DATA_DIV_ENABLED 0x0002
+/**
+ * struct qdio_outbuf_state - SBAL related asynchronous operation information
+ * (for communication with upper layer programs)
+ * (only required for use with completion queues)
+ * @flags: flags indicating state of buffer
+ * @aob: pointer to QAOB used for the particular SBAL
+ * @user: pointer to upper layer program's state information related to SBAL
+ * (stored in user1 data of QAOB)
+ */
+struct qdio_outbuf_state {
+ u8 flags;
+ struct qaob *aob;
+ void *user;
+};
+
+#define QDIO_OUTBUF_STATE_FLAG_NONE 0x00
+#define QDIO_OUTBUF_STATE_FLAG_PENDING 0x01
+
+#define CHSC_AC1_INITIATE_INPUTQ 0x80
+
+
+/* qdio adapter-characteristics-1 flag */
+#define AC1_SIGA_INPUT_NEEDED 0x40 /* process input queues */
+#define AC1_SIGA_OUTPUT_NEEDED 0x20 /* process output queues */
+#define AC1_SIGA_SYNC_NEEDED 0x10 /* ask hypervisor to sync */
+#define AC1_AUTOMATIC_SYNC_ON_THININT 0x08 /* set by hypervisor */
+#define AC1_AUTOMATIC_SYNC_ON_OUT_PCI 0x04 /* set by hypervisor */
+#define AC1_SC_QEBSM_AVAILABLE 0x02 /* available for subchannel */
+#define AC1_SC_QEBSM_ENABLED 0x01 /* enabled for subchannel */
+
+#define CHSC_AC2_DATA_DIV_AVAILABLE 0x0010
+#define CHSC_AC2_DATA_DIV_ENABLED 0x0002
+
+#define CHSC_AC3_FORMAT2_CQ_AVAILABLE 0x8000
+
struct qdio_ssqd_desc {
u8 flags;
u8:8;
@@ -243,8 +312,7 @@ struct qdio_ssqd_desc {
u64 sch_token;
u8 mro;
u8 mri;
- u8:8;
- u8 sbalic;
+ u16 qdioac3;
u16:16;
u8:8;
u8 mmwc;
@@ -280,9 +348,11 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int,
* @no_output_qs: number of output queues
* @input_handler: handler to be called for input queues
* @output_handler: handler to be called for output queues
+ * @queue_start_poll: polling handlers (one per input queue or NULL)
* @int_parm: interruption parameter
* @input_sbal_addr_array: address of no_input_qs * 128 pointers
* @output_sbal_addr_array: address of no_output_qs * 128 pointers
+ * @output_sbal_state_array: no_output_qs * 128 state info (for CQ or NULL)
*/
struct qdio_initialize {
struct ccw_device *cdev;
@@ -297,11 +367,12 @@ struct qdio_initialize {
unsigned int no_output_qs;
qdio_handler_t *input_handler;
qdio_handler_t *output_handler;
- void (*queue_start_poll) (struct ccw_device *, int, unsigned long);
+ void (**queue_start_poll) (struct ccw_device *, int, unsigned long);
int scan_threshold;
unsigned long int_parm;
void **input_sbal_addr_array;
void **output_sbal_addr_array;
+ struct qdio_outbuf_state *output_sbal_state_array;
};
#define QDIO_STATE_INACTIVE 0x00000002 /* after qdio_cleanup */
@@ -316,6 +387,7 @@ struct qdio_initialize {
extern int qdio_allocate(struct qdio_initialize *);
extern int qdio_establish(struct qdio_initialize *);
extern int qdio_activate(struct ccw_device *);
+extern void qdio_release_aob(struct qaob *);
extern int do_QDIO(struct ccw_device *, unsigned int, int, unsigned int,
unsigned int);
extern int qdio_start_irq(struct ccw_device *, int);
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index 532fd4322156..2b45591e1582 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -10,6 +10,7 @@
#include <linux/sched.h>
#include <asm/vdso.h>
#include <asm/sigp.h>
+#include <asm/pgtable.h>
/*
* Make sure that the compiler is new enough. We want a compiler that
@@ -126,6 +127,7 @@ int main(void)
DEFINE(__LC_KERNEL_STACK, offsetof(struct _lowcore, kernel_stack));
DEFINE(__LC_ASYNC_STACK, offsetof(struct _lowcore, async_stack));
DEFINE(__LC_PANIC_STACK, offsetof(struct _lowcore, panic_stack));
+ DEFINE(__LC_USER_ASCE, offsetof(struct _lowcore, user_asce));
DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock));
DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock));
DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags));
@@ -151,6 +153,7 @@ int main(void)
DEFINE(__LC_VDSO_PER_CPU, offsetof(struct _lowcore, vdso_per_cpu_data));
DEFINE(__LC_GMAP, offsetof(struct _lowcore, gmap));
DEFINE(__LC_CMF_HPP, offsetof(struct _lowcore, cmf_hpp));
+ DEFINE(__GMAP_ASCE, offsetof(struct gmap, asce));
#endif /* CONFIG_32BIT */
return 0;
}
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index 08ab9aa6a0d5..7526db6bf501 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -665,12 +665,6 @@ ENTRY(sys32_poll_wrapper)
lgfr %r4,%r4 # long
jg sys_poll # branch to system call
-ENTRY(compat_sys_nfsservctl_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # struct compat_nfsctl_arg*
- llgtr %r4,%r4 # union compat_nfsctl_res*
- jg compat_sys_nfsservctl # branch to system call
-
ENTRY(sys32_setresgid16_wrapper)
llgfr %r2,%r2 # __kernel_old_gid_emu31_t
llgfr %r3,%r3 # __kernel_old_gid_emu31_t
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index 068f8465c4ee..f297456dba7a 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -396,17 +396,19 @@ static __init void detect_machine_facilities(void)
static __init void rescue_initrd(void)
{
#ifdef CONFIG_BLK_DEV_INITRD
+ unsigned long min_initrd_addr = (unsigned long) _end + (4UL << 20);
/*
- * Move the initrd right behind the bss section in case it starts
- * within the bss section. So we don't overwrite it when the bss
- * section gets cleared.
+ * Just like in case of IPL from VM reader we make sure there is a
+ * gap of 4MB between end of kernel and start of initrd.
+ * That way we can also be sure that saving an NSS will succeed,
+ * which however only requires different segments.
*/
if (!INITRD_START || !INITRD_SIZE)
return;
- if (INITRD_START >= (unsigned long) __bss_stop)
+ if (INITRD_START >= min_initrd_addr)
return;
- memmove(__bss_stop, (void *) INITRD_START, INITRD_SIZE);
- INITRD_START = (unsigned long) __bss_stop;
+ memmove((void *) min_initrd_addr, (void *) INITRD_START, INITRD_SIZE);
+ INITRD_START = min_initrd_addr;
#endif
}
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 5f729d627cef..713da0760538 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -1076,6 +1076,11 @@ sie_loop:
lg %r14,__LC_THREAD_INFO # pointer thread_info struct
tm __TI_flags+7(%r14),_TIF_EXIT_SIE
jnz sie_exit
+ lg %r14,__LC_GMAP # get gmap pointer
+ ltgr %r14,%r14
+ jz sie_gmap
+ lctlg %c1,%c1,__GMAP_ASCE(%r14) # load primary asce
+sie_gmap:
lg %r14,__SF_EMPTY(%r15) # get control block pointer
SPP __SF_EMPTY(%r15) # set guest id
sie 0(%r14)
@@ -1083,6 +1088,7 @@ sie_done:
SPP __LC_CMF_HPP # set host id
lg %r14,__LC_THREAD_INFO # pointer thread_info struct
sie_exit:
+ lctlg %c1,%c1,__LC_USER_ASCE # load primary asce
ni __TI_flags+6(%r14),255-(_TIF_SIE>>8)
lg %r14,__SF_EMPTY+8(%r15) # load guest register save area
stmg %r0,%r13,0(%r14) # save guest gprs 0-13
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 04361d5a4279..48c710206366 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -1220,7 +1220,7 @@ static int __init reipl_fcp_init(void)
/* sysfs: create fcp kset for mixing attr group and bin attrs */
reipl_fcp_kset = kset_create_and_add(IPL_FCP_STR, NULL,
&reipl_kset->kobj);
- if (!reipl_kset) {
+ if (!reipl_fcp_kset) {
free_page((unsigned long) reipl_block_fcp);
return -ENOMEM;
}
@@ -1618,7 +1618,8 @@ static struct shutdown_action vmcmd_action = {SHUTDOWN_ACTION_VMCMD_STR,
static void stop_run(struct shutdown_trigger *trigger)
{
- if (strcmp(trigger->name, ON_PANIC_STR) == 0)
+ if (strcmp(trigger->name, ON_PANIC_STR) == 0 ||
+ strcmp(trigger->name, ON_RESTART_STR) == 0)
disabled_wait((unsigned long) __builtin_return_address(0));
while (sigp(smp_processor_id(), sigp_stop) == sigp_busy)
cpu_relax();
@@ -1717,7 +1718,7 @@ static void do_panic(void)
/* on restart */
static struct shutdown_trigger on_restart_trigger = {ON_RESTART_STR,
- &reipl_action};
+ &stop_action};
static ssize_t on_restart_show(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
diff --git a/arch/s390/kernel/suspend.c b/arch/s390/kernel/suspend.c
index cf9e5c6d5527..b6f9afed74ec 100644
--- a/arch/s390/kernel/suspend.c
+++ b/arch/s390/kernel/suspend.c
@@ -7,6 +7,7 @@
*/
#include <linux/pfn.h>
+#include <linux/mm.h>
#include <asm/system.h>
/*
@@ -14,6 +15,123 @@
*/
extern const void __nosave_begin, __nosave_end;
+/*
+ * The restore of the saved pages in an hibernation image will set
+ * the change and referenced bits in the storage key for each page.
+ * Overindication of the referenced bits after an hibernation cycle
+ * does not cause any harm but the overindication of the change bits
+ * would cause trouble.
+ * Use the ARCH_SAVE_PAGE_KEYS hooks to save the storage key of each
+ * page to the most significant byte of the associated page frame
+ * number in the hibernation image.
+ */
+
+/*
+ * Key storage is allocated as a linked list of pages.
+ * The size of the keys array is (PAGE_SIZE - sizeof(long))
+ */
+struct page_key_data {
+ struct page_key_data *next;
+ unsigned char data[];
+};
+
+#define PAGE_KEY_DATA_SIZE (PAGE_SIZE - sizeof(struct page_key_data *))
+
+static struct page_key_data *page_key_data;
+static struct page_key_data *page_key_rp, *page_key_wp;
+static unsigned long page_key_rx, page_key_wx;
+
+/*
+ * For each page in the hibernation image one additional byte is
+ * stored in the most significant byte of the page frame number.
+ * On suspend no additional memory is required but on resume the
+ * keys need to be memorized until the page data has been restored.
+ * Only then can the storage keys be set to their old state.
+ */
+unsigned long page_key_additional_pages(unsigned long pages)
+{
+ return DIV_ROUND_UP(pages, PAGE_KEY_DATA_SIZE);
+}
+
+/*
+ * Free page_key_data list of arrays.
+ */
+void page_key_free(void)
+{
+ struct page_key_data *pkd;
+
+ while (page_key_data) {
+ pkd = page_key_data;
+ page_key_data = pkd->next;
+ free_page((unsigned long) pkd);
+ }
+}
+
+/*
+ * Allocate page_key_data list of arrays with enough room to store
+ * one byte for each page in the hibernation image.
+ */
+int page_key_alloc(unsigned long pages)
+{
+ struct page_key_data *pk;
+ unsigned long size;
+
+ size = DIV_ROUND_UP(pages, PAGE_KEY_DATA_SIZE);
+ while (size--) {
+ pk = (struct page_key_data *) get_zeroed_page(GFP_KERNEL);
+ if (!pk) {
+ page_key_free();
+ return -ENOMEM;
+ }
+ pk->next = page_key_data;
+ page_key_data = pk;
+ }
+ page_key_rp = page_key_wp = page_key_data;
+ page_key_rx = page_key_wx = 0;
+ return 0;
+}
+
+/*
+ * Save the storage key into the upper 8 bits of the page frame number.
+ */
+void page_key_read(unsigned long *pfn)
+{
+ unsigned long addr;
+
+ addr = (unsigned long) page_address(pfn_to_page(*pfn));
+ *(unsigned char *) pfn = (unsigned char) page_get_storage_key(addr);
+}
+
+/*
+ * Extract the storage key from the upper 8 bits of the page frame number
+ * and store it in the page_key_data list of arrays.
+ */
+void page_key_memorize(unsigned long *pfn)
+{
+ page_key_wp->data[page_key_wx] = *(unsigned char *) pfn;
+ *(unsigned char *) pfn = 0;
+ if (++page_key_wx < PAGE_KEY_DATA_SIZE)
+ return;
+ page_key_wp = page_key_wp->next;
+ page_key_wx = 0;
+}
+
+/*
+ * Get the next key from the page_key_data list of arrays and set the
+ * storage key of the page referred by @address. If @address refers to
+ * a "safe" page the swsusp_arch_resume code will transfer the storage
+ * key from the buffer page to the original page.
+ */
+void page_key_write(void *address)
+{
+ page_set_storage_key((unsigned long) address,
+ page_key_rp->data[page_key_rx], 0);
+ if (++page_key_rx >= PAGE_KEY_DATA_SIZE)
+ return;
+ page_key_rp = page_key_rp->next;
+ page_key_rx = 0;
+}
+
int pfn_is_nosave(unsigned long pfn)
{
unsigned long nosave_begin_pfn = PFN_DOWN(__pa(&__nosave_begin));
diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S
index 51bcdb50a230..acb78cdee896 100644
--- a/arch/s390/kernel/swsusp_asm64.S
+++ b/arch/s390/kernel/swsusp_asm64.S
@@ -136,11 +136,14 @@ ENTRY(swsusp_arch_resume)
0:
lg %r2,8(%r1)
lg %r4,0(%r1)
+ iske %r0,%r4
lghi %r3,PAGE_SIZE
lghi %r5,PAGE_SIZE
1:
mvcle %r2,%r4,0
jo 1b
+ lg %r2,8(%r1)
+ sske %r0,%r2
lg %r1,16(%r1)
ltgr %r1,%r1
jnz 0b
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index 6ee39ef8fe4a..73eb08c874fb 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -177,7 +177,7 @@ SYSCALL(sys_getresuid16,sys_ni_syscall,sys32_getresuid16_wrapper) /* 165 old get
NI_SYSCALL /* for vm86 */
NI_SYSCALL /* old sys_query_module */
SYSCALL(sys_poll,sys_poll,sys32_poll_wrapper)
-SYSCALL(sys_nfsservctl,sys_nfsservctl,compat_sys_nfsservctl_wrapper)
+NI_SYSCALL /* old nfsservctl */
SYSCALL(sys_setresgid16,sys_ni_syscall,sys32_setresgid16_wrapper) /* 170 old setresgid16 syscall */
SYSCALL(sys_getresgid16,sys_ni_syscall,sys32_getresgid16_wrapper) /* old getresgid16 syscall */
SYSCALL(sys_prctl,sys_prctl,sys32_prctl_wrapper)
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index f17296e4fc89..dc2b580e27bc 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -123,6 +123,7 @@ int kvm_dev_ioctl_check_extension(long ext)
switch (ext) {
case KVM_CAP_S390_PSW:
+ case KVM_CAP_S390_GMAP:
r = 1;
break;
default:
@@ -263,10 +264,12 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
vcpu->arch.guest_fpregs.fpc &= FPC_VALID_MASK;
restore_fp_regs(&vcpu->arch.guest_fpregs);
restore_access_regs(vcpu->arch.guest_acrs);
+ gmap_enable(vcpu->arch.gmap);
}
void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
{
+ gmap_disable(vcpu->arch.gmap);
save_fp_regs(&vcpu->arch.guest_fpregs);
save_access_regs(vcpu->arch.guest_acrs);
restore_fp_regs(&vcpu->arch.host_fpregs);
@@ -461,7 +464,6 @@ static void __vcpu_run(struct kvm_vcpu *vcpu)
local_irq_disable();
kvm_guest_enter();
local_irq_enable();
- gmap_enable(vcpu->arch.gmap);
VCPU_EVENT(vcpu, 6, "entering sie flags %x",
atomic_read(&vcpu->arch.sie_block->cpuflags));
if (sie64a(vcpu->arch.sie_block, vcpu->arch.guest_gprs)) {
@@ -470,7 +472,6 @@ static void __vcpu_run(struct kvm_vcpu *vcpu)
}
VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
vcpu->arch.sie_block->icptcode);
- gmap_disable(vcpu->arch.gmap);
local_irq_disable();
kvm_guest_exit();
local_irq_enable();
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index 4d1f2bce87b3..5d56c2b95b14 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -160,6 +160,8 @@ struct gmap *gmap_alloc(struct mm_struct *mm)
table = (unsigned long *) page_to_phys(page);
crst_table_init(table, _REGION1_ENTRY_EMPTY);
gmap->table = table;
+ gmap->asce = _ASCE_TYPE_REGION1 | _ASCE_TABLE_LENGTH |
+ _ASCE_USER_BITS | __pa(table);
list_add(&gmap->list, &mm->context.gmap_list);
return gmap;
@@ -240,10 +242,6 @@ EXPORT_SYMBOL_GPL(gmap_free);
*/
void gmap_enable(struct gmap *gmap)
{
- /* Load primary space page table origin. */
- S390_lowcore.user_asce = _ASCE_TYPE_REGION1 | _ASCE_TABLE_LENGTH |
- _ASCE_USER_BITS | __pa(gmap->table);
- asm volatile("lctlg 1,1,%0\n" : : "m" (S390_lowcore.user_asce) );
S390_lowcore.gmap = (unsigned long) gmap;
}
EXPORT_SYMBOL_GPL(gmap_enable);
@@ -254,10 +252,6 @@ EXPORT_SYMBOL_GPL(gmap_enable);
*/
void gmap_disable(struct gmap *gmap)
{
- /* Load primary space page table origin. */
- S390_lowcore.user_asce =
- gmap->mm->context.asce_bits | __pa(gmap->mm->pgd);
- asm volatile("lctlg 1,1,%0\n" : : "m" (S390_lowcore.user_asce) );
S390_lowcore.gmap = 0UL;
}
EXPORT_SYMBOL_GPL(gmap_disable);
@@ -309,15 +303,15 @@ int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len)
/* Walk the guest addr space page table */
table = gmap->table + (((to + off) >> 53) & 0x7ff);
if (*table & _REGION_ENTRY_INV)
- return 0;
+ goto out;
table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
table = table + (((to + off) >> 42) & 0x7ff);
if (*table & _REGION_ENTRY_INV)
- return 0;
+ goto out;
table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
table = table + (((to + off) >> 31) & 0x7ff);
if (*table & _REGION_ENTRY_INV)
- return 0;
+ goto out;
table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
table = table + (((to + off) >> 20) & 0x7ff);
@@ -325,6 +319,7 @@ int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len)
flush |= gmap_unlink_segment(gmap, table);
*table = _SEGMENT_ENTRY_INV;
}
+out:
up_read(&gmap->mm->mmap_sem);
if (flush)
gmap_flush_tlb(gmap);
diff --git a/arch/sh/include/asm/ptrace.h b/arch/sh/include/asm/ptrace.h
index b97baf81a87b..2d3679b2447f 100644
--- a/arch/sh/include/asm/ptrace.h
+++ b/arch/sh/include/asm/ptrace.h
@@ -123,7 +123,7 @@ static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
struct perf_event;
struct perf_sample_data;
-extern void ptrace_triggered(struct perf_event *bp, int nmi,
+extern void ptrace_triggered(struct perf_event *bp,
struct perf_sample_data *data, struct pt_regs *regs);
#define task_pt_regs(task) \
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
index e915deafac89..05559295d2ca 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
@@ -15,6 +15,7 @@
#include <linux/serial_sci.h>
#include <linux/io.h>
#include <linux/mm.h>
+#include <linux/dma-mapping.h>
#include <linux/sh_timer.h>
#include <linux/sh_dma.h>
diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c
index 32114e0941ae..db4ecd731a00 100644
--- a/arch/sh/kernel/idle.c
+++ b/arch/sh/kernel/idle.c
@@ -22,7 +22,7 @@
#include <linux/atomic.h>
#include <asm/smp.h>
-static void (*pm_idle)(void);
+void (*pm_idle)(void);
static int hlt_counter;
diff --git a/arch/sh/kernel/syscalls_32.S b/arch/sh/kernel/syscalls_32.S
index 39b051de4c7c..293e39c59c00 100644
--- a/arch/sh/kernel/syscalls_32.S
+++ b/arch/sh/kernel/syscalls_32.S
@@ -185,7 +185,7 @@ ENTRY(sys_call_table)
.long sys_ni_syscall /* vm86 */
.long sys_ni_syscall /* old "query_module" */
.long sys_poll
- .long sys_nfsservctl
+ .long sys_ni_syscall /* was nfsservctl */
.long sys_setresgid16 /* 170 */
.long sys_getresgid16
.long sys_prctl
diff --git a/arch/sh/kernel/syscalls_64.S b/arch/sh/kernel/syscalls_64.S
index 089c4d825d08..ceb34b94afa9 100644
--- a/arch/sh/kernel/syscalls_64.S
+++ b/arch/sh/kernel/syscalls_64.S
@@ -189,7 +189,7 @@ sys_call_table:
.long sys_ni_syscall /* vm86 */
.long sys_ni_syscall /* old "query_module" */
.long sys_poll
- .long sys_nfsservctl
+ .long sys_ni_syscall /* was nfsservctl */
.long sys_setresgid16 /* 170 */
.long sys_getresgid16
.long sys_prctl
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
index d9006f8ffc14..7bbef95c9d1b 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -316,6 +316,35 @@ static int handle_unaligned_ins(insn_size_t instruction, struct pt_regs *regs,
break;
}
break;
+
+ case 9: /* mov.w @(disp,PC),Rn */
+ srcu = (unsigned char __user *)regs->pc;
+ srcu += 4;
+ srcu += (instruction & 0x00FF) << 1;
+ dst = (unsigned char *)rn;
+ *(unsigned long *)dst = 0;
+
+#if !defined(__LITTLE_ENDIAN__)
+ dst += 2;
+#endif
+
+ if (ma->from(dst, srcu, 2))
+ goto fetch_fault;
+ sign_extend(2, dst);
+ ret = 0;
+ break;
+
+ case 0xd: /* mov.l @(disp,PC),Rn */
+ srcu = (unsigned char __user *)(regs->pc & ~0x3);
+ srcu += 4;
+ srcu += (instruction & 0x00FF) << 2;
+ dst = (unsigned char *)rn;
+ *(unsigned long *)dst = 0;
+
+ if (ma->from(dst, srcu, 4))
+ goto fetch_fault;
+ ret = 0;
+ break;
}
return ret;
@@ -466,6 +495,7 @@ int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
case 0x0500: /* mov.w @(disp,Rm),R0 */
goto simple;
case 0x0B00: /* bf lab - no delayslot*/
+ ret = 0;
break;
case 0x0F00: /* bf/s lab */
ret = handle_delayslot(regs, instruction, ma);
@@ -479,6 +509,7 @@ int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
}
break;
case 0x0900: /* bt lab - no delayslot */
+ ret = 0;
break;
case 0x0D00: /* bt/s lab */
ret = handle_delayslot(regs, instruction, ma);
@@ -494,6 +525,9 @@ int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
}
break;
+ case 0x9000: /* mov.w @(disp,Rm),Rn */
+ goto simple;
+
case 0xA000: /* bra label */
ret = handle_delayslot(regs, instruction, ma);
if (ret==0)
@@ -507,6 +541,9 @@ int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
regs->pc += SH_PC_12BIT_OFFSET(instruction);
}
break;
+
+ case 0xD000: /* mov.l @(disp,Rm),Rn */
+ goto simple;
}
return ret;
diff --git a/arch/sparc/include/asm/pgtsrmmu.h b/arch/sparc/include/asm/pgtsrmmu.h
index 1407c07bdade..f6ae2b2b6870 100644
--- a/arch/sparc/include/asm/pgtsrmmu.h
+++ b/arch/sparc/include/asm/pgtsrmmu.h
@@ -280,7 +280,7 @@ static inline unsigned long srmmu_hwprobe(unsigned long vaddr)
return retval;
}
#else
-#define srmmu_hwprobe(addr) (srmmu_swprobe(addr, 0) & SRMMU_PTE_PMASK)
+#define srmmu_hwprobe(addr) srmmu_swprobe(addr, 0)
#endif
static inline int
diff --git a/arch/sparc/include/asm/sigcontext.h b/arch/sparc/include/asm/sigcontext.h
index a1607d180354..69914d748130 100644
--- a/arch/sparc/include/asm/sigcontext.h
+++ b/arch/sparc/include/asm/sigcontext.h
@@ -45,6 +45,19 @@ typedef struct {
int si_mask;
} __siginfo32_t;
+#define __SIGC_MAXWIN 7
+
+typedef struct {
+ unsigned long locals[8];
+ unsigned long ins[8];
+} __siginfo_reg_window;
+
+typedef struct {
+ int wsaved;
+ __siginfo_reg_window reg_window[__SIGC_MAXWIN];
+ unsigned long rwbuf_stkptrs[__SIGC_MAXWIN];
+} __siginfo_rwin_t;
+
#ifdef CONFIG_SPARC64
typedef struct {
unsigned int si_float_regs [64];
@@ -73,6 +86,7 @@ struct sigcontext {
unsigned long ss_size;
} sigc_stack;
unsigned long sigc_mask;
+ __siginfo_rwin_t * sigc_rwin_save;
};
#else
diff --git a/arch/sparc/include/asm/spitfire.h b/arch/sparc/include/asm/spitfire.h
index 55a17c6efeb8..d06a26601753 100644
--- a/arch/sparc/include/asm/spitfire.h
+++ b/arch/sparc/include/asm/spitfire.h
@@ -43,6 +43,8 @@
#define SUN4V_CHIP_NIAGARA1 0x01
#define SUN4V_CHIP_NIAGARA2 0x02
#define SUN4V_CHIP_NIAGARA3 0x03
+#define SUN4V_CHIP_NIAGARA4 0x04
+#define SUN4V_CHIP_NIAGARA5 0x05
#define SUN4V_CHIP_UNKNOWN 0xff
#ifndef __ASSEMBLY__
diff --git a/arch/sparc/include/asm/xor_64.h b/arch/sparc/include/asm/xor_64.h
index 9ed6ff679ab7..ee8edc68423e 100644
--- a/arch/sparc/include/asm/xor_64.h
+++ b/arch/sparc/include/asm/xor_64.h
@@ -66,6 +66,8 @@ static struct xor_block_template xor_block_niagara = {
((tlb_type == hypervisor && \
(sun4v_chip_type == SUN4V_CHIP_NIAGARA1 || \
sun4v_chip_type == SUN4V_CHIP_NIAGARA2 || \
- sun4v_chip_type == SUN4V_CHIP_NIAGARA3)) ? \
+ sun4v_chip_type == SUN4V_CHIP_NIAGARA3 || \
+ sun4v_chip_type == SUN4V_CHIP_NIAGARA4 || \
+ sun4v_chip_type == SUN4V_CHIP_NIAGARA5)) ? \
&xor_block_niagara : \
&xor_block_VIS)
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index b90b4a1d070a..cb85458f89d2 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_SPARC32) += sun4m_irq.o sun4c_irq.o sun4d_irq.o
obj-y += process_$(BITS).o
obj-y += signal_$(BITS).o
+obj-y += sigutil_$(BITS).o
obj-$(CONFIG_SPARC32) += ioport.o
obj-y += setup_$(BITS).o
obj-y += idprom.o
diff --git a/arch/sparc/kernel/cpu.c b/arch/sparc/kernel/cpu.c
index 9810fd881058..ba9b1cec4e6b 100644
--- a/arch/sparc/kernel/cpu.c
+++ b/arch/sparc/kernel/cpu.c
@@ -481,6 +481,18 @@ static void __init sun4v_cpu_probe(void)
sparc_pmu_type = "niagara3";
break;
+ case SUN4V_CHIP_NIAGARA4:
+ sparc_cpu_type = "UltraSparc T4 (Niagara4)";
+ sparc_fpu_type = "UltraSparc T4 integrated FPU";
+ sparc_pmu_type = "niagara4";
+ break;
+
+ case SUN4V_CHIP_NIAGARA5:
+ sparc_cpu_type = "UltraSparc T5 (Niagara5)";
+ sparc_fpu_type = "UltraSparc T5 integrated FPU";
+ sparc_pmu_type = "niagara5";
+ break;
+
default:
printk(KERN_WARNING "CPU: Unknown sun4v cpu type [%s]\n",
prom_cpu_compatible);
diff --git a/arch/sparc/kernel/cpumap.c b/arch/sparc/kernel/cpumap.c
index 4197e8d62d4c..9323eafccb93 100644
--- a/arch/sparc/kernel/cpumap.c
+++ b/arch/sparc/kernel/cpumap.c
@@ -325,6 +325,8 @@ static int iterate_cpu(struct cpuinfo_tree *t, unsigned int root_index)
case SUN4V_CHIP_NIAGARA1:
case SUN4V_CHIP_NIAGARA2:
case SUN4V_CHIP_NIAGARA3:
+ case SUN4V_CHIP_NIAGARA4:
+ case SUN4V_CHIP_NIAGARA5:
rover_inc_table = niagara_iterate_method;
break;
default:
diff --git a/arch/sparc/kernel/head_64.S b/arch/sparc/kernel/head_64.S
index 0eac1b2fc53d..0d810c2f1d00 100644
--- a/arch/sparc/kernel/head_64.S
+++ b/arch/sparc/kernel/head_64.S
@@ -133,7 +133,7 @@ prom_sun4v_name:
prom_niagara_prefix:
.asciz "SUNW,UltraSPARC-T"
prom_sparc_prefix:
- .asciz "SPARC-T"
+ .asciz "SPARC-"
.align 4
prom_root_compatible:
.skip 64
@@ -396,7 +396,7 @@ sun4v_chip_type:
or %g1, %lo(prom_cpu_compatible), %g1
sethi %hi(prom_sparc_prefix), %g7
or %g7, %lo(prom_sparc_prefix), %g7
- mov 7, %g3
+ mov 6, %g3
90: ldub [%g7], %g2
ldub [%g1], %g4
cmp %g2, %g4
@@ -408,10 +408,23 @@ sun4v_chip_type:
sethi %hi(prom_cpu_compatible), %g1
or %g1, %lo(prom_cpu_compatible), %g1
- ldub [%g1 + 7], %g2
+ ldub [%g1 + 6], %g2
+ cmp %g2, 'T'
+ be,pt %xcc, 70f
+ cmp %g2, 'M'
+ bne,pn %xcc, 4f
+ nop
+
+70: ldub [%g1 + 7], %g2
cmp %g2, '3'
be,pt %xcc, 5f
mov SUN4V_CHIP_NIAGARA3, %g4
+ cmp %g2, '4'
+ be,pt %xcc, 5f
+ mov SUN4V_CHIP_NIAGARA4, %g4
+ cmp %g2, '5'
+ be,pt %xcc, 5f
+ mov SUN4V_CHIP_NIAGARA5, %g4
ba,pt %xcc, 4f
nop
@@ -545,6 +558,12 @@ niagara_tlb_fixup:
cmp %g1, SUN4V_CHIP_NIAGARA3
be,pt %xcc, niagara2_patch
nop
+ cmp %g1, SUN4V_CHIP_NIAGARA4
+ be,pt %xcc, niagara2_patch
+ nop
+ cmp %g1, SUN4V_CHIP_NIAGARA5
+ be,pt %xcc, niagara2_patch
+ nop
call generic_patch_copyops
nop
diff --git a/arch/sparc/kernel/irq.h b/arch/sparc/kernel/irq.h
index 100b9c204e78..42851122bbd9 100644
--- a/arch/sparc/kernel/irq.h
+++ b/arch/sparc/kernel/irq.h
@@ -88,7 +88,7 @@ BTFIXUPDEF_CALL(void, set_irq_udt, int)
#define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu)
/* All SUN4D IPIs are sent on this IRQ, may be shared with hard IRQs */
-#define SUN4D_IPI_IRQ 14
+#define SUN4D_IPI_IRQ 13
extern void sun4d_ipi_interrupt(void);
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index 1e94f946570e..8aa0d4408586 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -230,7 +230,8 @@ static void pci_parse_of_addrs(struct platform_device *op,
res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2];
} else if (i == dev->rom_base_reg) {
res = &dev->resource[PCI_ROM_RESOURCE];
- flags |= IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
+ flags |= IORESOURCE_READONLY | IORESOURCE_CACHEABLE
+ | IORESOURCE_SIZEALIGN;
} else {
printk(KERN_ERR "PCI: bad cfg reg num 0x%x\n", i);
continue;
diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c
index c8cc461ff75f..f793742eec2b 100644
--- a/arch/sparc/kernel/process_32.c
+++ b/arch/sparc/kernel/process_32.c
@@ -380,8 +380,7 @@ void flush_thread(void)
#endif
}
- /* Now, this task is no longer a kernel thread. */
- current->thread.current_ds = USER_DS;
+ /* This task is no longer a kernel thread. */
if (current->thread.flags & SPARC_FLAG_KTHREAD) {
current->thread.flags &= ~SPARC_FLAG_KTHREAD;
diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c
index c158a95ec664..d959cd0a4aa4 100644
--- a/arch/sparc/kernel/process_64.c
+++ b/arch/sparc/kernel/process_64.c
@@ -368,9 +368,6 @@ void flush_thread(void)
/* Clear FPU register state. */
t->fpsaved[0] = 0;
-
- if (get_thread_current_ds() != ASI_AIUS)
- set_fs(USER_DS);
}
/* It's a bit more tricky when 64-bit tasks are involved... */
diff --git a/arch/sparc/kernel/setup_32.c b/arch/sparc/kernel/setup_32.c
index d26e1f6c717a..3e3e2914c70b 100644
--- a/arch/sparc/kernel/setup_32.c
+++ b/arch/sparc/kernel/setup_32.c
@@ -137,7 +137,7 @@ static void __init process_switch(char c)
prom_halt();
break;
case 'p':
- /* Just ignore, this behavior is now the default. */
+ prom_early_console.flags &= ~CON_BOOT;
break;
default:
printk("Unknown boot switch (-%c)\n", c);
diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c
index 3e9daea1653d..c965595aa7e9 100644
--- a/arch/sparc/kernel/setup_64.c
+++ b/arch/sparc/kernel/setup_64.c
@@ -106,7 +106,7 @@ static void __init process_switch(char c)
prom_halt();
break;
case 'p':
- /* Just ignore, this behavior is now the default. */
+ prom_early_console.flags &= ~CON_BOOT;
break;
case 'P':
/* Force UltraSPARC-III P-Cache on. */
@@ -425,10 +425,14 @@ static void __init init_sparc64_elf_hwcap(void)
else if (tlb_type == hypervisor) {
if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1 ||
sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
- sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
+ sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
+ sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
+ sun4v_chip_type == SUN4V_CHIP_NIAGARA5)
cap |= HWCAP_SPARC_BLKINIT;
if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
- sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
+ sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
+ sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
+ sun4v_chip_type == SUN4V_CHIP_NIAGARA5)
cap |= HWCAP_SPARC_N2;
}
@@ -440,17 +444,27 @@ static void __init init_sparc64_elf_hwcap(void)
cap |= AV_SPARC_VIS;
if (tlb_type == cheetah || tlb_type == cheetah_plus)
cap |= AV_SPARC_VIS | AV_SPARC_VIS2;
- if (tlb_type == cheetah_plus)
- cap |= AV_SPARC_POPC;
+ if (tlb_type == cheetah_plus) {
+ unsigned long impl, ver;
+
+ __asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver));
+ impl = ((ver >> 32) & 0xffff);
+ if (impl == PANTHER_IMPL)
+ cap |= AV_SPARC_POPC;
+ }
if (tlb_type == hypervisor) {
if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1)
cap |= AV_SPARC_ASI_BLK_INIT;
if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
- sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
+ sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
+ sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
+ sun4v_chip_type == SUN4V_CHIP_NIAGARA5)
cap |= (AV_SPARC_VIS | AV_SPARC_VIS2 |
AV_SPARC_ASI_BLK_INIT |
AV_SPARC_POPC);
- if (sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
+ if (sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
+ sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
+ sun4v_chip_type == SUN4V_CHIP_NIAGARA5)
cap |= (AV_SPARC_VIS3 | AV_SPARC_HPC |
AV_SPARC_FMAF);
}
diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c
index 75fad425e249..2caa556db86d 100644
--- a/arch/sparc/kernel/signal32.c
+++ b/arch/sparc/kernel/signal32.c
@@ -29,6 +29,8 @@
#include <asm/visasm.h>
#include <asm/compat_signal.h>
+#include "sigutil.h"
+
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
/* This magic should be in g_upper[0] for all upper parts
@@ -44,14 +46,14 @@ typedef struct {
struct signal_frame32 {
struct sparc_stackf32 ss;
__siginfo32_t info;
- /* __siginfo_fpu32_t * */ u32 fpu_save;
+ /* __siginfo_fpu_t * */ u32 fpu_save;
unsigned int insns[2];
unsigned int extramask[_COMPAT_NSIG_WORDS - 1];
unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
/* Only valid if (info.si_regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
siginfo_extra_v8plus_t v8plus;
- __siginfo_fpu_t fpu_state;
-};
+ /* __siginfo_rwin_t * */u32 rwin_save;
+} __attribute__((aligned(8)));
typedef struct compat_siginfo{
int si_signo;
@@ -110,18 +112,14 @@ struct rt_signal_frame32 {
compat_siginfo_t info;
struct pt_regs32 regs;
compat_sigset_t mask;
- /* __siginfo_fpu32_t * */ u32 fpu_save;
+ /* __siginfo_fpu_t * */ u32 fpu_save;
unsigned int insns[2];
stack_t32 stack;
unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
/* Only valid if (regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
siginfo_extra_v8plus_t v8plus;
- __siginfo_fpu_t fpu_state;
-};
-
-/* Align macros */
-#define SF_ALIGNEDSZ (((sizeof(struct signal_frame32) + 15) & (~15)))
-#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame32) + 15) & (~15)))
+ /* __siginfo_rwin_t * */u32 rwin_save;
+} __attribute__((aligned(8)));
int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
{
@@ -192,30 +190,13 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
return 0;
}
-static int restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
- unsigned long *fpregs = current_thread_info()->fpregs;
- unsigned long fprs;
- int err;
-
- err = __get_user(fprs, &fpu->si_fprs);
- fprs_write(0);
- regs->tstate &= ~TSTATE_PEF;
- if (fprs & FPRS_DL)
- err |= copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32));
- if (fprs & FPRS_DU)
- err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32));
- err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
- err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
- current_thread_info()->fpsaved[0] |= fprs;
- return err;
-}
-
void do_sigreturn32(struct pt_regs *regs)
{
struct signal_frame32 __user *sf;
+ compat_uptr_t fpu_save;
+ compat_uptr_t rwin_save;
unsigned int psr;
- unsigned pc, npc, fpu_save;
+ unsigned pc, npc;
sigset_t set;
unsigned seta[_COMPAT_NSIG_WORDS];
int err, i;
@@ -273,8 +254,13 @@ void do_sigreturn32(struct pt_regs *regs)
pt_regs_clear_syscall(regs);
err |= __get_user(fpu_save, &sf->fpu_save);
- if (fpu_save)
- err |= restore_fpu_state32(regs, &sf->fpu_state);
+ if (!err && fpu_save)
+ err |= restore_fpu_state(regs, compat_ptr(fpu_save));
+ err |= __get_user(rwin_save, &sf->rwin_save);
+ if (!err && rwin_save) {
+ if (restore_rwin_state(compat_ptr(rwin_save)))
+ goto segv;
+ }
err |= __get_user(seta[0], &sf->info.si_mask);
err |= copy_from_user(seta+1, &sf->extramask,
(_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
@@ -287,10 +273,7 @@ void do_sigreturn32(struct pt_regs *regs)
case 1: set.sig[0] = seta[0] + (((long)seta[1]) << 32);
}
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
return;
segv:
@@ -300,7 +283,9 @@ segv:
asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
{
struct rt_signal_frame32 __user *sf;
- unsigned int psr, pc, npc, fpu_save, u_ss_sp;
+ unsigned int psr, pc, npc, u_ss_sp;
+ compat_uptr_t fpu_save;
+ compat_uptr_t rwin_save;
mm_segment_t old_fs;
sigset_t set;
compat_sigset_t seta;
@@ -359,8 +344,8 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
pt_regs_clear_syscall(regs);
err |= __get_user(fpu_save, &sf->fpu_save);
- if (fpu_save)
- err |= restore_fpu_state32(regs, &sf->fpu_state);
+ if (!err && fpu_save)
+ err |= restore_fpu_state(regs, compat_ptr(fpu_save));
err |= copy_from_user(&seta, &sf->mask, sizeof(compat_sigset_t));
err |= __get_user(u_ss_sp, &sf->stack.ss_sp);
st.ss_sp = compat_ptr(u_ss_sp);
@@ -376,6 +361,12 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
do_sigaltstack((stack_t __user *) &st, NULL, (unsigned long)sf);
set_fs(old_fs);
+ err |= __get_user(rwin_save, &sf->rwin_save);
+ if (!err && rwin_save) {
+ if (restore_rwin_state(compat_ptr(rwin_save)))
+ goto segv;
+ }
+
switch (_NSIG_WORDS) {
case 4: set.sig[3] = seta.sig[6] + (((long)seta.sig[7]) << 32);
case 3: set.sig[2] = seta.sig[4] + (((long)seta.sig[5]) << 32);
@@ -383,10 +374,7 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
case 1: set.sig[0] = seta.sig[0] + (((long)seta.sig[1]) << 32);
}
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
return;
segv:
force_sig(SIGSEGV, current);
@@ -433,26 +421,6 @@ static void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, uns
return (void __user *) sp;
}
-static int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
- unsigned long *fpregs = current_thread_info()->fpregs;
- unsigned long fprs;
- int err = 0;
-
- fprs = current_thread_info()->fpsaved[0];
- if (fprs & FPRS_DL)
- err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
- (sizeof(unsigned int) * 32));
- if (fprs & FPRS_DU)
- err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
- (sizeof(unsigned int) * 32));
- err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
- err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
- err |= __put_user(fprs, &fpu->si_fprs);
-
- return err;
-}
-
/* The I-cache flush instruction only works in the primary ASI, which
* right now is the nucleus, aka. kernel space.
*
@@ -515,18 +483,23 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
int signo, sigset_t *oldset)
{
struct signal_frame32 __user *sf;
+ int i, err, wsaved;
+ void __user *tail;
int sigframe_size;
u32 psr;
- int i, err;
unsigned int seta[_COMPAT_NSIG_WORDS];
/* 1. Make sure everything is clean */
synchronize_user_stack();
save_and_clear_fpu();
- sigframe_size = SF_ALIGNEDSZ;
- if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
- sigframe_size -= sizeof(__siginfo_fpu_t);
+ wsaved = get_thread_wsaved();
+
+ sigframe_size = sizeof(*sf);
+ if (current_thread_info()->fpsaved[0] & FPRS_FEF)
+ sigframe_size += sizeof(__siginfo_fpu_t);
+ if (wsaved)
+ sigframe_size += sizeof(__siginfo_rwin_t);
sf = (struct signal_frame32 __user *)
get_sigframe(&ka->sa, regs, sigframe_size);
@@ -534,8 +507,7 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
if (invalid_frame_pointer(sf, sigframe_size))
goto sigill;
- if (get_thread_wsaved() != 0)
- goto sigill;
+ tail = (sf + 1);
/* 2. Save the current process state */
if (test_thread_flag(TIF_32BIT)) {
@@ -560,11 +532,22 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
&sf->v8plus.asi);
if (psr & PSR_EF) {
- err |= save_fpu_state32(regs, &sf->fpu_state);
- err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
+ __siginfo_fpu_t __user *fp = tail;
+ tail += sizeof(*fp);
+ err |= save_fpu_state(regs, fp);
+ err |= __put_user((u64)fp, &sf->fpu_save);
} else {
err |= __put_user(0, &sf->fpu_save);
}
+ if (wsaved) {
+ __siginfo_rwin_t __user *rwp = tail;
+ tail += sizeof(*rwp);
+ err |= save_rwin_state(wsaved, rwp);
+ err |= __put_user((u64)rwp, &sf->rwin_save);
+ set_thread_wsaved(0);
+ } else {
+ err |= __put_user(0, &sf->rwin_save);
+ }
switch (_NSIG_WORDS) {
case 4: seta[7] = (oldset->sig[3] >> 32);
@@ -580,10 +563,21 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
err |= __copy_to_user(sf->extramask, seta + 1,
(_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
- err |= copy_in_user((u32 __user *)sf,
- (u32 __user *)(regs->u_regs[UREG_FP]),
- sizeof(struct reg_window32));
-
+ if (!wsaved) {
+ err |= copy_in_user((u32 __user *)sf,
+ (u32 __user *)(regs->u_regs[UREG_FP]),
+ sizeof(struct reg_window32));
+ } else {
+ struct reg_window *rp;
+
+ rp = &current_thread_info()->reg_window[wsaved - 1];
+ for (i = 0; i < 8; i++)
+ err |= __put_user(rp->locals[i], &sf->ss.locals[i]);
+ for (i = 0; i < 6; i++)
+ err |= __put_user(rp->ins[i], &sf->ss.ins[i]);
+ err |= __put_user(rp->ins[6], &sf->ss.fp);
+ err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
+ }
if (err)
goto sigsegv;
@@ -613,7 +607,6 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
err |= __put_user(0x91d02010, &sf->insns[1]); /*t 0x10*/
if (err)
goto sigsegv;
-
flush_signal_insns(address);
}
return 0;
@@ -632,18 +625,23 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
siginfo_t *info)
{
struct rt_signal_frame32 __user *sf;
+ int i, err, wsaved;
+ void __user *tail;
int sigframe_size;
u32 psr;
- int i, err;
compat_sigset_t seta;
/* 1. Make sure everything is clean */
synchronize_user_stack();
save_and_clear_fpu();
- sigframe_size = RT_ALIGNEDSZ;
- if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
- sigframe_size -= sizeof(__siginfo_fpu_t);
+ wsaved = get_thread_wsaved();
+
+ sigframe_size = sizeof(*sf);
+ if (current_thread_info()->fpsaved[0] & FPRS_FEF)
+ sigframe_size += sizeof(__siginfo_fpu_t);
+ if (wsaved)
+ sigframe_size += sizeof(__siginfo_rwin_t);
sf = (struct rt_signal_frame32 __user *)
get_sigframe(&ka->sa, regs, sigframe_size);
@@ -651,8 +649,7 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
if (invalid_frame_pointer(sf, sigframe_size))
goto sigill;
- if (get_thread_wsaved() != 0)
- goto sigill;
+ tail = (sf + 1);
/* 2. Save the current process state */
if (test_thread_flag(TIF_32BIT)) {
@@ -677,11 +674,22 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
&sf->v8plus.asi);
if (psr & PSR_EF) {
- err |= save_fpu_state32(regs, &sf->fpu_state);
- err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
+ __siginfo_fpu_t __user *fp = tail;
+ tail += sizeof(*fp);
+ err |= save_fpu_state(regs, fp);
+ err |= __put_user((u64)fp, &sf->fpu_save);
} else {
err |= __put_user(0, &sf->fpu_save);
}
+ if (wsaved) {
+ __siginfo_rwin_t __user *rwp = tail;
+ tail += sizeof(*rwp);
+ err |= save_rwin_state(wsaved, rwp);
+ err |= __put_user((u64)rwp, &sf->rwin_save);
+ set_thread_wsaved(0);
+ } else {
+ err |= __put_user(0, &sf->rwin_save);
+ }
/* Update the siginfo structure. */
err |= copy_siginfo_to_user32(&sf->info, info);
@@ -703,9 +711,21 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
}
err |= __copy_to_user(&sf->mask, &seta, sizeof(compat_sigset_t));
- err |= copy_in_user((u32 __user *)sf,
- (u32 __user *)(regs->u_regs[UREG_FP]),
- sizeof(struct reg_window32));
+ if (!wsaved) {
+ err |= copy_in_user((u32 __user *)sf,
+ (u32 __user *)(regs->u_regs[UREG_FP]),
+ sizeof(struct reg_window32));
+ } else {
+ struct reg_window *rp;
+
+ rp = &current_thread_info()->reg_window[wsaved - 1];
+ for (i = 0; i < 8; i++)
+ err |= __put_user(rp->locals[i], &sf->ss.locals[i]);
+ for (i = 0; i < 6; i++)
+ err |= __put_user(rp->ins[i], &sf->ss.ins[i]);
+ err |= __put_user(rp->ins[6], &sf->ss.fp);
+ err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
+ }
if (err)
goto sigsegv;
@@ -756,6 +776,7 @@ static inline int handle_signal32(unsigned long signr, struct k_sigaction *ka,
siginfo_t *info,
sigset_t *oldset, struct pt_regs *regs)
{
+ sigset_t blocked;
int err;
if (ka->sa.sa_flags & SA_SIGINFO)
@@ -766,12 +787,10 @@ static inline int handle_signal32(unsigned long signr, struct k_sigaction *ka,
if (err)
return err;
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+ sigorsets(&blocked, &current->blocked, &ka->sa.sa_mask);
if (!(ka->sa.sa_flags & SA_NOMASK))
- sigaddset(&current->blocked,signr);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ sigaddset(&blocked, signr);
+ set_current_blocked(&blocked);
tracehook_signal_handler(signr, info, ka, regs, 0);
@@ -855,7 +874,7 @@ void do_signal32(sigset_t *oldset, struct pt_regs * regs,
*/
if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
- sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+ set_current_blocked(&current->saved_sigmask);
}
}
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c
index 5e5c5fd03783..8ce247ac04cc 100644
--- a/arch/sparc/kernel/signal_32.c
+++ b/arch/sparc/kernel/signal_32.c
@@ -26,6 +26,8 @@
#include <asm/pgtable.h>
#include <asm/cacheflush.h> /* flush_sig_insns */
+#include "sigutil.h"
+
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
@@ -39,8 +41,8 @@ struct signal_frame {
unsigned long insns[2] __attribute__ ((aligned (8)));
unsigned int extramask[_NSIG_WORDS - 1];
unsigned int extra_size; /* Should be 0 */
- __siginfo_fpu_t fpu_state;
-};
+ __siginfo_rwin_t __user *rwin_save;
+} __attribute__((aligned(8)));
struct rt_signal_frame {
struct sparc_stackf ss;
@@ -51,8 +53,8 @@ struct rt_signal_frame {
unsigned int insns[2];
stack_t stack;
unsigned int extra_size; /* Should be 0 */
- __siginfo_fpu_t fpu_state;
-};
+ __siginfo_rwin_t __user *rwin_save;
+} __attribute__((aligned(8)));
/* Align macros */
#define SF_ALIGNEDSZ (((sizeof(struct signal_frame) + 7) & (~7)))
@@ -60,12 +62,13 @@ struct rt_signal_frame {
static int _sigpause_common(old_sigset_t set)
{
- set &= _BLOCKABLE;
- spin_lock_irq(&current->sighand->siglock);
+ sigset_t blocked;
+
current->saved_sigmask = current->blocked;
- siginitset(&current->blocked, set);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+
+ set &= _BLOCKABLE;
+ siginitset(&blocked, set);
+ set_current_blocked(&blocked);
current->state = TASK_INTERRUPTIBLE;
schedule();
@@ -79,43 +82,13 @@ asmlinkage int sys_sigsuspend(old_sigset_t set)
return _sigpause_common(set);
}
-static inline int
-restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
- int err;
-#ifdef CONFIG_SMP
- if (test_tsk_thread_flag(current, TIF_USEDFPU))
- regs->psr &= ~PSR_EF;
-#else
- if (current == last_task_used_math) {
- last_task_used_math = NULL;
- regs->psr &= ~PSR_EF;
- }
-#endif
- set_used_math();
- clear_tsk_thread_flag(current, TIF_USEDFPU);
-
- if (!access_ok(VERIFY_READ, fpu, sizeof(*fpu)))
- return -EFAULT;
-
- err = __copy_from_user(&current->thread.float_regs[0], &fpu->si_float_regs[0],
- (sizeof(unsigned long) * 32));
- err |= __get_user(current->thread.fsr, &fpu->si_fsr);
- err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
- if (current->thread.fpqdepth != 0)
- err |= __copy_from_user(&current->thread.fpqueue[0],
- &fpu->si_fpqueue[0],
- ((sizeof(unsigned long) +
- (sizeof(unsigned long *)))*16));
- return err;
-}
-
asmlinkage void do_sigreturn(struct pt_regs *regs)
{
struct signal_frame __user *sf;
unsigned long up_psr, pc, npc;
sigset_t set;
__siginfo_fpu_t __user *fpu_save;
+ __siginfo_rwin_t __user *rwin_save;
int err;
/* Always make any pending restarted system calls return -EINTR */
@@ -150,9 +123,11 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)
pt_regs_clear_syscall(regs);
err |= __get_user(fpu_save, &sf->fpu_save);
-
if (fpu_save)
err |= restore_fpu_state(regs, fpu_save);
+ err |= __get_user(rwin_save, &sf->rwin_save);
+ if (rwin_save)
+ err |= restore_rwin_state(rwin_save);
/* This is pretty much atomic, no amount locking would prevent
* the races which exist anyways.
@@ -165,10 +140,7 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)
goto segv_and_exit;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
return;
segv_and_exit:
@@ -180,6 +152,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
struct rt_signal_frame __user *sf;
unsigned int psr, pc, npc;
__siginfo_fpu_t __user *fpu_save;
+ __siginfo_rwin_t __user *rwin_save;
mm_segment_t old_fs;
sigset_t set;
stack_t st;
@@ -207,8 +180,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
pt_regs_clear_syscall(regs);
err |= __get_user(fpu_save, &sf->fpu_save);
-
- if (fpu_save)
+ if (!err && fpu_save)
err |= restore_fpu_state(regs, fpu_save);
err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
@@ -228,11 +200,14 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
do_sigaltstack((const stack_t __user *) &st, NULL, (unsigned long)sf);
set_fs(old_fs);
+ err |= __get_user(rwin_save, &sf->rwin_save);
+ if (!err && rwin_save) {
+ if (restore_rwin_state(rwin_save))
+ goto segv;
+ }
+
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
return;
segv:
force_sig(SIGSEGV, current);
@@ -280,53 +255,23 @@ static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *re
return (void __user *) sp;
}
-static inline int
-save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
- int err = 0;
-#ifdef CONFIG_SMP
- if (test_tsk_thread_flag(current, TIF_USEDFPU)) {
- put_psr(get_psr() | PSR_EF);
- fpsave(&current->thread.float_regs[0], &current->thread.fsr,
- &current->thread.fpqueue[0], &current->thread.fpqdepth);
- regs->psr &= ~(PSR_EF);
- clear_tsk_thread_flag(current, TIF_USEDFPU);
- }
-#else
- if (current == last_task_used_math) {
- put_psr(get_psr() | PSR_EF);
- fpsave(&current->thread.float_regs[0], &current->thread.fsr,
- &current->thread.fpqueue[0], &current->thread.fpqdepth);
- last_task_used_math = NULL;
- regs->psr &= ~(PSR_EF);
- }
-#endif
- err |= __copy_to_user(&fpu->si_float_regs[0],
- &current->thread.float_regs[0],
- (sizeof(unsigned long) * 32));
- err |= __put_user(current->thread.fsr, &fpu->si_fsr);
- err |= __put_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
- if (current->thread.fpqdepth != 0)
- err |= __copy_to_user(&fpu->si_fpqueue[0],
- &current->thread.fpqueue[0],
- ((sizeof(unsigned long) +
- (sizeof(unsigned long *)))*16));
- clear_used_math();
- return err;
-}
-
static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
int signo, sigset_t *oldset)
{
struct signal_frame __user *sf;
- int sigframe_size, err;
+ int sigframe_size, err, wsaved;
+ void __user *tail;
/* 1. Make sure everything is clean */
synchronize_user_stack();
- sigframe_size = SF_ALIGNEDSZ;
- if (!used_math())
- sigframe_size -= sizeof(__siginfo_fpu_t);
+ wsaved = current_thread_info()->w_saved;
+
+ sigframe_size = sizeof(*sf);
+ if (used_math())
+ sigframe_size += sizeof(__siginfo_fpu_t);
+ if (wsaved)
+ sigframe_size += sizeof(__siginfo_rwin_t);
sf = (struct signal_frame __user *)
get_sigframe(&ka->sa, regs, sigframe_size);
@@ -334,8 +279,7 @@ static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
if (invalid_frame_pointer(sf, sigframe_size))
goto sigill_and_return;
- if (current_thread_info()->w_saved != 0)
- goto sigill_and_return;
+ tail = sf + 1;
/* 2. Save the current process state */
err = __copy_to_user(&sf->info.si_regs, regs, sizeof(struct pt_regs));
@@ -343,17 +287,34 @@ static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
err |= __put_user(0, &sf->extra_size);
if (used_math()) {
- err |= save_fpu_state(regs, &sf->fpu_state);
- err |= __put_user(&sf->fpu_state, &sf->fpu_save);
+ __siginfo_fpu_t __user *fp = tail;
+ tail += sizeof(*fp);
+ err |= save_fpu_state(regs, fp);
+ err |= __put_user(fp, &sf->fpu_save);
} else {
err |= __put_user(0, &sf->fpu_save);
}
+ if (wsaved) {
+ __siginfo_rwin_t __user *rwp = tail;
+ tail += sizeof(*rwp);
+ err |= save_rwin_state(wsaved, rwp);
+ err |= __put_user(rwp, &sf->rwin_save);
+ } else {
+ err |= __put_user(0, &sf->rwin_save);
+ }
err |= __put_user(oldset->sig[0], &sf->info.si_mask);
err |= __copy_to_user(sf->extramask, &oldset->sig[1],
(_NSIG_WORDS - 1) * sizeof(unsigned int));
- err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
- sizeof(struct reg_window32));
+ if (!wsaved) {
+ err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
+ sizeof(struct reg_window32));
+ } else {
+ struct reg_window32 *rp;
+
+ rp = &current_thread_info()->reg_window[wsaved - 1];
+ err |= __copy_to_user(sf, rp, sizeof(struct reg_window32));
+ }
if (err)
goto sigsegv;
@@ -399,21 +360,24 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
int signo, sigset_t *oldset, siginfo_t *info)
{
struct rt_signal_frame __user *sf;
- int sigframe_size;
+ int sigframe_size, wsaved;
+ void __user *tail;
unsigned int psr;
int err;
synchronize_user_stack();
- sigframe_size = RT_ALIGNEDSZ;
- if (!used_math())
- sigframe_size -= sizeof(__siginfo_fpu_t);
+ wsaved = current_thread_info()->w_saved;
+ sigframe_size = sizeof(*sf);
+ if (used_math())
+ sigframe_size += sizeof(__siginfo_fpu_t);
+ if (wsaved)
+ sigframe_size += sizeof(__siginfo_rwin_t);
sf = (struct rt_signal_frame __user *)
get_sigframe(&ka->sa, regs, sigframe_size);
if (invalid_frame_pointer(sf, sigframe_size))
goto sigill;
- if (current_thread_info()->w_saved != 0)
- goto sigill;
+ tail = sf + 1;
err = __put_user(regs->pc, &sf->regs.pc);
err |= __put_user(regs->npc, &sf->regs.npc);
err |= __put_user(regs->y, &sf->regs.y);
@@ -425,11 +389,21 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
err |= __put_user(0, &sf->extra_size);
if (psr & PSR_EF) {
- err |= save_fpu_state(regs, &sf->fpu_state);
- err |= __put_user(&sf->fpu_state, &sf->fpu_save);
+ __siginfo_fpu_t *fp = tail;
+ tail += sizeof(*fp);
+ err |= save_fpu_state(regs, fp);
+ err |= __put_user(fp, &sf->fpu_save);
} else {
err |= __put_user(0, &sf->fpu_save);
}
+ if (wsaved) {
+ __siginfo_rwin_t *rwp = tail;
+ tail += sizeof(*rwp);
+ err |= save_rwin_state(wsaved, rwp);
+ err |= __put_user(rwp, &sf->rwin_save);
+ } else {
+ err |= __put_user(0, &sf->rwin_save);
+ }
err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t));
/* Setup sigaltstack */
@@ -437,8 +411,15 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
- err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
- sizeof(struct reg_window32));
+ if (!wsaved) {
+ err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
+ sizeof(struct reg_window32));
+ } else {
+ struct reg_window32 *rp;
+
+ rp = &current_thread_info()->reg_window[wsaved - 1];
+ err |= __copy_to_user(sf, rp, sizeof(struct reg_window32));
+ }
err |= copy_siginfo_to_user(&sf->info, info);
@@ -484,6 +465,7 @@ static inline int
handle_signal(unsigned long signr, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
{
+ sigset_t blocked;
int err;
if (ka->sa.sa_flags & SA_SIGINFO)
@@ -494,12 +476,10 @@ handle_signal(unsigned long signr, struct k_sigaction *ka,
if (err)
return err;
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+ sigorsets(&blocked, &current->blocked, &ka->sa.sa_mask);
if (!(ka->sa.sa_flags & SA_NOMASK))
- sigaddset(&current->blocked, signr);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ sigaddset(&blocked, signr);
+ set_current_blocked(&blocked);
tracehook_signal_handler(signr, info, ka, regs, 0);
@@ -595,7 +575,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
*/
if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
clear_thread_flag(TIF_RESTORE_SIGMASK);
- sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+ set_current_blocked(&current->saved_sigmask);
}
}
diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c
index 006fe4515886..a2b81598d905 100644
--- a/arch/sparc/kernel/signal_64.c
+++ b/arch/sparc/kernel/signal_64.c
@@ -34,6 +34,7 @@
#include "entry.h"
#include "systbls.h"
+#include "sigutil.h"
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
@@ -69,10 +70,7 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
goto do_sigsegv;
}
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
}
if (test_thread_flag(TIF_32BIT)) {
pc &= 0xffffffff;
@@ -236,17 +234,18 @@ struct rt_signal_frame {
__siginfo_fpu_t __user *fpu_save;
stack_t stack;
sigset_t mask;
- __siginfo_fpu_t fpu_state;
+ __siginfo_rwin_t *rwin_save;
};
static long _sigpause_common(old_sigset_t set)
{
- set &= _BLOCKABLE;
- spin_lock_irq(&current->sighand->siglock);
+ sigset_t blocked;
+
current->saved_sigmask = current->blocked;
- siginitset(&current->blocked, set);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+
+ set &= _BLOCKABLE;
+ siginitset(&blocked, set);
+ set_current_blocked(&blocked);
current->state = TASK_INTERRUPTIBLE;
schedule();
@@ -266,33 +265,12 @@ asmlinkage long sys_sigsuspend(old_sigset_t set)
return _sigpause_common(set);
}
-static inline int
-restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
- unsigned long *fpregs = current_thread_info()->fpregs;
- unsigned long fprs;
- int err;
-
- err = __get_user(fprs, &fpu->si_fprs);
- fprs_write(0);
- regs->tstate &= ~TSTATE_PEF;
- if (fprs & FPRS_DL)
- err |= copy_from_user(fpregs, &fpu->si_float_regs[0],
- (sizeof(unsigned int) * 32));
- if (fprs & FPRS_DU)
- err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32],
- (sizeof(unsigned int) * 32));
- err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
- err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
- current_thread_info()->fpsaved[0] |= fprs;
- return err;
-}
-
void do_rt_sigreturn(struct pt_regs *regs)
{
struct rt_signal_frame __user *sf;
unsigned long tpc, tnpc, tstate;
__siginfo_fpu_t __user *fpu_save;
+ __siginfo_rwin_t __user *rwin_save;
sigset_t set;
int err;
@@ -325,8 +303,8 @@ void do_rt_sigreturn(struct pt_regs *regs)
regs->tstate |= (tstate & (TSTATE_ASI | TSTATE_ICC | TSTATE_XCC));
err |= __get_user(fpu_save, &sf->fpu_save);
- if (fpu_save)
- err |= restore_fpu_state(regs, &sf->fpu_state);
+ if (!err && fpu_save)
+ err |= restore_fpu_state(regs, fpu_save);
err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
err |= do_sigaltstack(&sf->stack, NULL, (unsigned long)sf);
@@ -334,6 +312,12 @@ void do_rt_sigreturn(struct pt_regs *regs)
if (err)
goto segv;
+ err |= __get_user(rwin_save, &sf->rwin_save);
+ if (!err && rwin_save) {
+ if (restore_rwin_state(rwin_save))
+ goto segv;
+ }
+
regs->tpc = tpc;
regs->tnpc = tnpc;
@@ -341,44 +325,20 @@ void do_rt_sigreturn(struct pt_regs *regs)
pt_regs_clear_syscall(regs);
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
return;
segv:
force_sig(SIGSEGV, current);
}
/* Checks if the fp is valid */
-static int invalid_frame_pointer(void __user *fp, int fplen)
+static int invalid_frame_pointer(void __user *fp)
{
if (((unsigned long) fp) & 15)
return 1;
return 0;
}
-static inline int
-save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
- unsigned long *fpregs = current_thread_info()->fpregs;
- unsigned long fprs;
- int err = 0;
-
- fprs = current_thread_info()->fpsaved[0];
- if (fprs & FPRS_DL)
- err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
- (sizeof(unsigned int) * 32));
- if (fprs & FPRS_DU)
- err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
- (sizeof(unsigned int) * 32));
- err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
- err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
- err |= __put_user(fprs, &fpu->si_fprs);
-
- return err;
-}
-
static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, unsigned long framesize)
{
unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS;
@@ -414,34 +374,48 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
int signo, sigset_t *oldset, siginfo_t *info)
{
struct rt_signal_frame __user *sf;
- int sigframe_size, err;
+ int wsaved, err, sf_size;
+ void __user *tail;
/* 1. Make sure everything is clean */
synchronize_user_stack();
save_and_clear_fpu();
- sigframe_size = sizeof(struct rt_signal_frame);
- if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
- sigframe_size -= sizeof(__siginfo_fpu_t);
+ wsaved = get_thread_wsaved();
+ sf_size = sizeof(struct rt_signal_frame);
+ if (current_thread_info()->fpsaved[0] & FPRS_FEF)
+ sf_size += sizeof(__siginfo_fpu_t);
+ if (wsaved)
+ sf_size += sizeof(__siginfo_rwin_t);
sf = (struct rt_signal_frame __user *)
- get_sigframe(ka, regs, sigframe_size);
-
- if (invalid_frame_pointer (sf, sigframe_size))
- goto sigill;
+ get_sigframe(ka, regs, sf_size);
- if (get_thread_wsaved() != 0)
+ if (invalid_frame_pointer (sf))
goto sigill;
+ tail = (sf + 1);
+
/* 2. Save the current process state */
err = copy_to_user(&sf->regs, regs, sizeof (*regs));
if (current_thread_info()->fpsaved[0] & FPRS_FEF) {
- err |= save_fpu_state(regs, &sf->fpu_state);
- err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
+ __siginfo_fpu_t __user *fpu_save = tail;
+ tail += sizeof(__siginfo_fpu_t);
+ err |= save_fpu_state(regs, fpu_save);
+ err |= __put_user((u64)fpu_save, &sf->fpu_save);
} else {
err |= __put_user(0, &sf->fpu_save);
}
+ if (wsaved) {
+ __siginfo_rwin_t __user *rwin_save = tail;
+ tail += sizeof(__siginfo_rwin_t);
+ err |= save_rwin_state(wsaved, rwin_save);
+ err |= __put_user((u64)rwin_save, &sf->rwin_save);
+ set_thread_wsaved(0);
+ } else {
+ err |= __put_user(0, &sf->rwin_save);
+ }
/* Setup sigaltstack */
err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
@@ -450,10 +424,17 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
err |= copy_to_user(&sf->mask, oldset, sizeof(sigset_t));
- err |= copy_in_user((u64 __user *)sf,
- (u64 __user *)(regs->u_regs[UREG_FP]+STACK_BIAS),
- sizeof(struct reg_window));
+ if (!wsaved) {
+ err |= copy_in_user((u64 __user *)sf,
+ (u64 __user *)(regs->u_regs[UREG_FP] +
+ STACK_BIAS),
+ sizeof(struct reg_window));
+ } else {
+ struct reg_window *rp;
+ rp = &current_thread_info()->reg_window[wsaved - 1];
+ err |= copy_to_user(sf, rp, sizeof(struct reg_window));
+ }
if (info)
err |= copy_siginfo_to_user(&sf->info, info);
else {
@@ -498,18 +479,17 @@ static inline int handle_signal(unsigned long signr, struct k_sigaction *ka,
siginfo_t *info,
sigset_t *oldset, struct pt_regs *regs)
{
+ sigset_t blocked;
int err;
err = setup_rt_frame(ka, regs, signr, oldset,
(ka->sa.sa_flags & SA_SIGINFO) ? info : NULL);
if (err)
return err;
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+ sigorsets(&blocked, &current->blocked, &ka->sa.sa_mask);
if (!(ka->sa.sa_flags & SA_NOMASK))
- sigaddset(&current->blocked,signr);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ sigaddset(&blocked, signr);
+ set_current_blocked(&blocked);
tracehook_signal_handler(signr, info, ka, regs, 0);
@@ -615,7 +595,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
*/
if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
- sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+ set_current_blocked(&current->saved_sigmask);
}
}
diff --git a/arch/sparc/kernel/sigutil.h b/arch/sparc/kernel/sigutil.h
new file mode 100644
index 000000000000..d223aa432bb6
--- /dev/null
+++ b/arch/sparc/kernel/sigutil.h
@@ -0,0 +1,9 @@
+#ifndef _SIGUTIL_H
+#define _SIGUTIL_H
+
+int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu);
+int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu);
+int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin);
+int restore_rwin_state(__siginfo_rwin_t __user *rp);
+
+#endif /* _SIGUTIL_H */
diff --git a/arch/sparc/kernel/sigutil_32.c b/arch/sparc/kernel/sigutil_32.c
new file mode 100644
index 000000000000..35c7897b009a
--- /dev/null
+++ b/arch/sparc/kernel/sigutil_32.c
@@ -0,0 +1,120 @@
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/thread_info.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+
+#include <asm/sigcontext.h>
+#include <asm/fpumacro.h>
+#include <asm/ptrace.h>
+
+#include "sigutil.h"
+
+int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
+{
+ int err = 0;
+#ifdef CONFIG_SMP
+ if (test_tsk_thread_flag(current, TIF_USEDFPU)) {
+ put_psr(get_psr() | PSR_EF);
+ fpsave(&current->thread.float_regs[0], &current->thread.fsr,
+ &current->thread.fpqueue[0], &current->thread.fpqdepth);
+ regs->psr &= ~(PSR_EF);
+ clear_tsk_thread_flag(current, TIF_USEDFPU);
+ }
+#else
+ if (current == last_task_used_math) {
+ put_psr(get_psr() | PSR_EF);
+ fpsave(&current->thread.float_regs[0], &current->thread.fsr,
+ &current->thread.fpqueue[0], &current->thread.fpqdepth);
+ last_task_used_math = NULL;
+ regs->psr &= ~(PSR_EF);
+ }
+#endif
+ err |= __copy_to_user(&fpu->si_float_regs[0],
+ &current->thread.float_regs[0],
+ (sizeof(unsigned long) * 32));
+ err |= __put_user(current->thread.fsr, &fpu->si_fsr);
+ err |= __put_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
+ if (current->thread.fpqdepth != 0)
+ err |= __copy_to_user(&fpu->si_fpqueue[0],
+ &current->thread.fpqueue[0],
+ ((sizeof(unsigned long) +
+ (sizeof(unsigned long *)))*16));
+ clear_used_math();
+ return err;
+}
+
+int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
+{
+ int err;
+#ifdef CONFIG_SMP
+ if (test_tsk_thread_flag(current, TIF_USEDFPU))
+ regs->psr &= ~PSR_EF;
+#else
+ if (current == last_task_used_math) {
+ last_task_used_math = NULL;
+ regs->psr &= ~PSR_EF;
+ }
+#endif
+ set_used_math();
+ clear_tsk_thread_flag(current, TIF_USEDFPU);
+
+ if (!access_ok(VERIFY_READ, fpu, sizeof(*fpu)))
+ return -EFAULT;
+
+ err = __copy_from_user(&current->thread.float_regs[0], &fpu->si_float_regs[0],
+ (sizeof(unsigned long) * 32));
+ err |= __get_user(current->thread.fsr, &fpu->si_fsr);
+ err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
+ if (current->thread.fpqdepth != 0)
+ err |= __copy_from_user(&current->thread.fpqueue[0],
+ &fpu->si_fpqueue[0],
+ ((sizeof(unsigned long) +
+ (sizeof(unsigned long *)))*16));
+ return err;
+}
+
+int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin)
+{
+ int i, err = __put_user(wsaved, &rwin->wsaved);
+
+ for (i = 0; i < wsaved; i++) {
+ struct reg_window32 *rp;
+ unsigned long fp;
+
+ rp = &current_thread_info()->reg_window[i];
+ fp = current_thread_info()->rwbuf_stkptrs[i];
+ err |= copy_to_user(&rwin->reg_window[i], rp,
+ sizeof(struct reg_window32));
+ err |= __put_user(fp, &rwin->rwbuf_stkptrs[i]);
+ }
+ return err;
+}
+
+int restore_rwin_state(__siginfo_rwin_t __user *rp)
+{
+ struct thread_info *t = current_thread_info();
+ int i, wsaved, err;
+
+ __get_user(wsaved, &rp->wsaved);
+ if (wsaved > NSWINS)
+ return -EFAULT;
+
+ err = 0;
+ for (i = 0; i < wsaved; i++) {
+ err |= copy_from_user(&t->reg_window[i],
+ &rp->reg_window[i],
+ sizeof(struct reg_window32));
+ err |= __get_user(t->rwbuf_stkptrs[i],
+ &rp->rwbuf_stkptrs[i]);
+ }
+ if (err)
+ return err;
+
+ t->w_saved = wsaved;
+ synchronize_user_stack();
+ if (t->w_saved)
+ return -EFAULT;
+ return 0;
+
+}
diff --git a/arch/sparc/kernel/sigutil_64.c b/arch/sparc/kernel/sigutil_64.c
new file mode 100644
index 000000000000..e7dc508c38eb
--- /dev/null
+++ b/arch/sparc/kernel/sigutil_64.c
@@ -0,0 +1,93 @@
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/thread_info.h>
+#include <linux/uaccess.h>
+
+#include <asm/sigcontext.h>
+#include <asm/fpumacro.h>
+#include <asm/ptrace.h>
+
+#include "sigutil.h"
+
+int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
+{
+ unsigned long *fpregs = current_thread_info()->fpregs;
+ unsigned long fprs;
+ int err = 0;
+
+ fprs = current_thread_info()->fpsaved[0];
+ if (fprs & FPRS_DL)
+ err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
+ (sizeof(unsigned int) * 32));
+ if (fprs & FPRS_DU)
+ err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
+ (sizeof(unsigned int) * 32));
+ err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
+ err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
+ err |= __put_user(fprs, &fpu->si_fprs);
+
+ return err;
+}
+
+int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
+{
+ unsigned long *fpregs = current_thread_info()->fpregs;
+ unsigned long fprs;
+ int err;
+
+ err = __get_user(fprs, &fpu->si_fprs);
+ fprs_write(0);
+ regs->tstate &= ~TSTATE_PEF;
+ if (fprs & FPRS_DL)
+ err |= copy_from_user(fpregs, &fpu->si_float_regs[0],
+ (sizeof(unsigned int) * 32));
+ if (fprs & FPRS_DU)
+ err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32],
+ (sizeof(unsigned int) * 32));
+ err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
+ err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
+ current_thread_info()->fpsaved[0] |= fprs;
+ return err;
+}
+
+int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin)
+{
+ int i, err = __put_user(wsaved, &rwin->wsaved);
+
+ for (i = 0; i < wsaved; i++) {
+ struct reg_window *rp = &current_thread_info()->reg_window[i];
+ unsigned long fp = current_thread_info()->rwbuf_stkptrs[i];
+
+ err |= copy_to_user(&rwin->reg_window[i], rp,
+ sizeof(struct reg_window));
+ err |= __put_user(fp, &rwin->rwbuf_stkptrs[i]);
+ }
+ return err;
+}
+
+int restore_rwin_state(__siginfo_rwin_t __user *rp)
+{
+ struct thread_info *t = current_thread_info();
+ int i, wsaved, err;
+
+ __get_user(wsaved, &rp->wsaved);
+ if (wsaved > NSWINS)
+ return -EFAULT;
+
+ err = 0;
+ for (i = 0; i < wsaved; i++) {
+ err |= copy_from_user(&t->reg_window[i],
+ &rp->reg_window[i],
+ sizeof(struct reg_window));
+ err |= __get_user(t->rwbuf_stkptrs[i],
+ &rp->rwbuf_stkptrs[i]);
+ }
+ if (err)
+ return err;
+
+ set_thread_wsaved(wsaved);
+ synchronize_user_stack();
+ if (get_thread_wsaved())
+ return -EFAULT;
+ return 0;
+}
diff --git a/arch/sparc/kernel/sys32.S b/arch/sparc/kernel/sys32.S
index 44e5faf1ad5f..d97f3eb72e06 100644
--- a/arch/sparc/kernel/sys32.S
+++ b/arch/sparc/kernel/sys32.S
@@ -81,7 +81,6 @@ SIGN2(sys32_fadvise64, compat_sys_fadvise64, %o0, %o4)
SIGN2(sys32_fadvise64_64, compat_sys_fadvise64_64, %o0, %o5)
SIGN2(sys32_bdflush, sys_bdflush, %o0, %o1)
SIGN1(sys32_mlockall, sys_mlockall, %o0)
-SIGN1(sys32_nfsservctl, compat_sys_nfsservctl, %o0)
SIGN1(sys32_clock_nanosleep, compat_sys_clock_nanosleep, %o1)
SIGN1(sys32_timer_settime, compat_sys_timer_settime, %o1)
SIGN1(sys32_io_submit, compat_sys_io_submit, %o1)
diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S
index 6e492d59f6b1..09d8ec454450 100644
--- a/arch/sparc/kernel/systbls_32.S
+++ b/arch/sparc/kernel/systbls_32.S
@@ -67,7 +67,7 @@ sys_call_table:
/*235*/ .long sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
/*240*/ .long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
/*245*/ .long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
-/*250*/ .long sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
+/*250*/ .long sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_ni_syscall
/*255*/ .long sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep
/*260*/ .long sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun
/*265*/ .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy
diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S
index f566518483b5..edbec45d4688 100644
--- a/arch/sparc/kernel/systbls_64.S
+++ b/arch/sparc/kernel/systbls_64.S
@@ -68,7 +68,7 @@ sys_call_table32:
.word compat_sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys32_mlockall
/*240*/ .word sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys32_sched_setscheduler, sys32_sched_getscheduler
.word sys_sched_yield, sys32_sched_get_priority_max, sys32_sched_get_priority_min, sys32_sched_rr_get_interval, compat_sys_nanosleep
-/*250*/ .word sys_mremap, compat_sys_sysctl, sys32_getsid, sys_fdatasync, sys32_nfsservctl
+/*250*/ .word sys_mremap, compat_sys_sysctl, sys32_getsid, sys_fdatasync, sys_nis_syscall
.word sys32_sync_file_range, compat_sys_clock_settime, compat_sys_clock_gettime, compat_sys_clock_getres, sys32_clock_nanosleep
/*260*/ .word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, sys32_timer_settime, compat_sys_timer_gettime, sys_timer_getoverrun
.word sys_timer_delete, compat_sys_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy
@@ -145,7 +145,7 @@ sys_call_table:
.word sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
/*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
-/*250*/ .word sys_64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
+/*250*/ .word sys_64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nis_syscall
.word sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep
/*260*/ .word sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun
.word sys_timer_delete, sys_timer_create, sys_ni_syscall, sys_io_setup, sys_io_destroy
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index 581531dbc8b5..8e073d802139 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -511,6 +511,11 @@ static void __init read_obp_translations(void)
for (i = 0; i < prom_trans_ents; i++)
prom_trans[i].data &= ~0x0003fe0000000000UL;
}
+
+ /* Force execute bit on. */
+ for (i = 0; i < prom_trans_ents; i++)
+ prom_trans[i].data |= (tlb_type == hypervisor ?
+ _PAGE_EXEC_4V : _PAGE_EXEC_4U);
}
static void __init hypervisor_tlb_lock(unsigned long vaddr,
diff --git a/arch/sparc/mm/leon_mm.c b/arch/sparc/mm/leon_mm.c
index e485a6804998..13c2169822a8 100644
--- a/arch/sparc/mm/leon_mm.c
+++ b/arch/sparc/mm/leon_mm.c
@@ -162,7 +162,7 @@ ready:
printk(KERN_INFO "swprobe: padde %x\n", paddr_calc);
if (paddr)
*paddr = paddr_calc;
- return paddrbase;
+ return pte;
}
void leon_flush_icache_all(void)
diff --git a/arch/tile/kernel/intvec_32.S b/arch/tile/kernel/intvec_32.S
index fc94607f0bd5..aecc8ed5f39b 100644
--- a/arch/tile/kernel/intvec_32.S
+++ b/arch/tile/kernel/intvec_32.S
@@ -21,7 +21,7 @@
#include <asm/ptrace.h>
#include <asm/thread_info.h>
#include <asm/irqflags.h>
-#include <linux/atomic.h>
+#include <asm/atomic_32.h>
#include <asm/asm-offsets.h>
#include <hv/hypervisor.h>
#include <arch/abi.h>
diff --git a/arch/tile/lib/atomic_asm_32.S b/arch/tile/lib/atomic_asm_32.S
index 1f75a2a56101..30638042691d 100644
--- a/arch/tile/lib/atomic_asm_32.S
+++ b/arch/tile/lib/atomic_asm_32.S
@@ -70,7 +70,7 @@
*/
#include <linux/linkage.h>
-#include <linux/atomic.h>
+#include <asm/atomic_32.h>
#include <asm/page.h>
#include <asm/processor.h>
diff --git a/arch/um/Kconfig.x86 b/arch/um/Kconfig.x86
index d31ecf346b4e..21bebe63df66 100644
--- a/arch/um/Kconfig.x86
+++ b/arch/um/Kconfig.x86
@@ -10,6 +10,10 @@ config CMPXCHG_LOCAL
bool
default n
+config CMPXCHG_DOUBLE
+ bool
+ default n
+
source "arch/x86/Kconfig.cpu"
endmenu
diff --git a/arch/um/Makefile b/arch/um/Makefile
index fab8121d2b32..c0f712cc7c5f 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -41,7 +41,7 @@ KBUILD_CPPFLAGS += -I$(srctree)/$(ARCH_DIR)/sys-$(SUBARCH)
KBUILD_CFLAGS += $(CFLAGS) $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
$(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap \
-Din6addr_loopback=kernel_in6addr_loopback \
- -Din6addr_any=kernel_in6addr_any
+ -Din6addr_any=kernel_in6addr_any -Dstrrchr=kernel_strrchr
KBUILD_AFLAGS += $(ARCH_INCLUDE)
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index d51c404239a8..364c8a15c4c3 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -399,8 +399,8 @@ int line_setup_irq(int fd, int input, int output, struct line *line, void *data)
* is done under a spinlock. Checking whether the device is in use is
* line->tty->count > 1, also under the spinlock.
*
- * tty->count serves to decide whether the device should be enabled or
- * disabled on the host. If it's equal to 1, then we are doing the
+ * line->count serves to decide whether the device should be enabled or
+ * disabled on the host. If it's equal to 0, then we are doing the
* first open or last close. Otherwise, open and close just return.
*/
@@ -414,16 +414,16 @@ int line_open(struct line *lines, struct tty_struct *tty)
goto out_unlock;
err = 0;
- if (tty->count > 1)
+ if (line->count++)
goto out_unlock;
- spin_unlock(&line->count_lock);
-
+ BUG_ON(tty->driver_data);
tty->driver_data = line;
line->tty = tty;
+ spin_unlock(&line->count_lock);
err = enable_chan(line);
- if (err)
+ if (err) /* line_close() will be called by our caller */
return err;
INIT_DELAYED_WORK(&line->task, line_timer_cb);
@@ -436,7 +436,7 @@ int line_open(struct line *lines, struct tty_struct *tty)
chan_window_size(&line->chan_list, &tty->winsize.ws_row,
&tty->winsize.ws_col);
- return err;
+ return 0;
out_unlock:
spin_unlock(&line->count_lock);
@@ -460,17 +460,16 @@ void line_close(struct tty_struct *tty, struct file * filp)
flush_buffer(line);
spin_lock(&line->count_lock);
- if (!line->valid)
- goto out_unlock;
+ BUG_ON(!line->valid);
- if (tty->count > 1)
+ if (--line->count)
goto out_unlock;
- spin_unlock(&line->count_lock);
-
line->tty = NULL;
tty->driver_data = NULL;
+ spin_unlock(&line->count_lock);
+
if (line->sigio) {
unregister_winch(tty);
line->sigio = 0;
@@ -498,7 +497,7 @@ static int setup_one_line(struct line *lines, int n, char *init, int init_prio,
spin_lock(&line->count_lock);
- if (line->tty != NULL) {
+ if (line->count) {
*error_out = "Device is already open";
goto out;
}
@@ -722,41 +721,53 @@ struct winch {
int pid;
struct tty_struct *tty;
unsigned long stack;
+ struct work_struct work;
};
-static void free_winch(struct winch *winch, int free_irq_ok)
+static void __free_winch(struct work_struct *work)
{
- if (free_irq_ok)
- free_irq(WINCH_IRQ, winch);
-
- list_del(&winch->list);
+ struct winch *winch = container_of(work, struct winch, work);
+ free_irq(WINCH_IRQ, winch);
if (winch->pid != -1)
os_kill_process(winch->pid, 1);
- if (winch->fd != -1)
- os_close_file(winch->fd);
if (winch->stack != 0)
free_stack(winch->stack, 0);
kfree(winch);
}
+static void free_winch(struct winch *winch)
+{
+ int fd = winch->fd;
+ winch->fd = -1;
+ if (fd != -1)
+ os_close_file(fd);
+ list_del(&winch->list);
+ __free_winch(&winch->work);
+}
+
static irqreturn_t winch_interrupt(int irq, void *data)
{
struct winch *winch = data;
struct tty_struct *tty;
struct line *line;
+ int fd = winch->fd;
int err;
char c;
- if (winch->fd != -1) {
- err = generic_read(winch->fd, &c, NULL);
+ if (fd != -1) {
+ err = generic_read(fd, &c, NULL);
if (err < 0) {
if (err != -EAGAIN) {
+ winch->fd = -1;
+ list_del(&winch->list);
+ os_close_file(fd);
printk(KERN_ERR "winch_interrupt : "
"read failed, errno = %d\n", -err);
printk(KERN_ERR "fd %d is losing SIGWINCH "
"support\n", winch->tty_fd);
- free_winch(winch, 0);
+ INIT_WORK(&winch->work, __free_winch);
+ schedule_work(&winch->work);
return IRQ_HANDLED;
}
goto out;
@@ -828,7 +839,7 @@ static void unregister_winch(struct tty_struct *tty)
list_for_each_safe(ele, next, &winch_handlers) {
winch = list_entry(ele, struct winch, list);
if (winch->tty == tty) {
- free_winch(winch, 1);
+ free_winch(winch);
break;
}
}
@@ -844,7 +855,7 @@ static void winch_cleanup(void)
list_for_each_safe(ele, next, &winch_handlers) {
winch = list_entry(ele, struct winch, list);
- free_winch(winch, 1);
+ free_winch(winch);
}
spin_unlock(&winch_handler_lock);
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index 22745b47c829..a492e59883a3 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -368,7 +368,7 @@ static const struct net_device_ops uml_netdev_ops = {
.ndo_open = uml_net_open,
.ndo_stop = uml_net_close,
.ndo_start_xmit = uml_net_start_xmit,
- .ndo_set_multicast_list = uml_net_set_multicast_list,
+ .ndo_set_rx_mode = uml_net_set_multicast_list,
.ndo_tx_timeout = uml_net_tx_timeout,
.ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = uml_net_change_mtu,
diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c
index 8ac7146c237f..2e1de5728604 100644
--- a/arch/um/drivers/xterm.c
+++ b/arch/um/drivers/xterm.c
@@ -123,6 +123,7 @@ static int xterm_open(int input, int output, int primary, void *d,
err = -errno;
printk(UM_KERN_ERR "xterm_open : unlink failed, errno = %d\n",
errno);
+ close(fd);
return err;
}
close(fd);
diff --git a/arch/um/include/asm/ptrace-generic.h b/arch/um/include/asm/ptrace-generic.h
index ae084ad1a3a0..1a7d2757fe05 100644
--- a/arch/um/include/asm/ptrace-generic.h
+++ b/arch/um/include/asm/ptrace-generic.h
@@ -42,10 +42,6 @@ extern long subarch_ptrace(struct task_struct *child, long request,
unsigned long addr, unsigned long data);
extern unsigned long getreg(struct task_struct *child, int regno);
extern int putreg(struct task_struct *child, int regno, unsigned long value);
-extern int get_fpregs(struct user_i387_struct __user *buf,
- struct task_struct *child);
-extern int set_fpregs(struct user_i387_struct __user *buf,
- struct task_struct *child);
extern int arch_copy_tls(struct task_struct *new);
extern void clear_flushed_tls(struct task_struct *task);
diff --git a/arch/um/include/shared/line.h b/arch/um/include/shared/line.h
index 72f4f25af247..63df3ca02ac2 100644
--- a/arch/um/include/shared/line.h
+++ b/arch/um/include/shared/line.h
@@ -33,6 +33,7 @@ struct line_driver {
struct line {
struct tty_struct *tty;
spinlock_t count_lock;
+ unsigned long count;
int valid;
char *init_str;
diff --git a/arch/um/include/shared/registers.h b/arch/um/include/shared/registers.h
index b0b4589e0ebc..f1e0aa56c52a 100644
--- a/arch/um/include/shared/registers.h
+++ b/arch/um/include/shared/registers.h
@@ -16,7 +16,7 @@ extern int restore_fpx_registers(int pid, unsigned long *fp_regs);
extern int save_registers(int pid, struct uml_pt_regs *regs);
extern int restore_registers(int pid, struct uml_pt_regs *regs);
extern int init_registers(int pid);
-extern void get_safe_registers(unsigned long *regs);
+extern void get_safe_registers(unsigned long *regs, unsigned long *fp_regs);
extern unsigned long get_thread_reg(int reg, jmp_buf *buf);
extern int get_fp_registers(int pid, unsigned long *regs);
extern int put_fp_registers(int pid, unsigned long *regs);
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index fab4371184f6..21c1ae7c3d75 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -202,7 +202,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
arch_copy_thread(&current->thread.arch, &p->thread.arch);
}
else {
- get_safe_registers(p->thread.regs.regs.gp);
+ get_safe_registers(p->thread.regs.regs.gp, p->thread.regs.regs.fp);
p->thread.request.u.thread = current->thread.request.u.thread;
handler = new_thread_handler;
}
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c
index 701b672c1122..c9da32b0c707 100644
--- a/arch/um/kernel/ptrace.c
+++ b/arch/um/kernel/ptrace.c
@@ -50,23 +50,11 @@ long arch_ptrace(struct task_struct *child, long request,
void __user *vp = p;
switch (request) {
- /* read word at location addr. */
- case PTRACE_PEEKTEXT:
- case PTRACE_PEEKDATA:
- ret = generic_ptrace_peekdata(child, addr, data);
- break;
-
/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR:
ret = peek_user(child, addr, data);
break;
- /* write the word at location addr. */
- case PTRACE_POKETEXT:
- case PTRACE_POKEDATA:
- ret = generic_ptrace_pokedata(child, addr, data);
- break;
-
/* write the word at location addr in the USER area */
case PTRACE_POKEUSR:
ret = poke_user(child, addr, data);
@@ -107,16 +95,6 @@ long arch_ptrace(struct task_struct *child, long request,
break;
}
#endif
-#ifdef PTRACE_GETFPREGS
- case PTRACE_GETFPREGS: /* Get the child FPU state. */
- ret = get_fpregs(vp, child);
- break;
-#endif
-#ifdef PTRACE_SETFPREGS
- case PTRACE_SETFPREGS: /* Set the child FPU state. */
- ret = set_fpregs(vp, child);
- break;
-#endif
case PTRACE_GET_THREAD_AREA:
ret = ptrace_get_thread_area(child, addr, vp);
break;
@@ -154,12 +132,6 @@ long arch_ptrace(struct task_struct *child, long request,
break;
}
#endif
-#ifdef PTRACE_ARCH_PRCTL
- case PTRACE_ARCH_PRCTL:
- /* XXX Calls ptrace on the host - needs some SMP thinking */
- ret = arch_prctl(child, data, (void __user *) addr);
- break;
-#endif
default:
ret = ptrace_request(child, request, addr, data);
if (ret == -EIO)
diff --git a/arch/um/os-Linux/registers.c b/arch/um/os-Linux/registers.c
index 830fe6a1518a..b866b9e3bef9 100644
--- a/arch/um/os-Linux/registers.c
+++ b/arch/um/os-Linux/registers.c
@@ -8,6 +8,8 @@
#include <string.h>
#include <sys/ptrace.h>
#include "sysdep/ptrace.h"
+#include "sysdep/ptrace_user.h"
+#include "registers.h"
int save_registers(int pid, struct uml_pt_regs *regs)
{
@@ -32,6 +34,7 @@ int restore_registers(int pid, struct uml_pt_regs *regs)
/* This is set once at boot time and not changed thereafter */
static unsigned long exec_regs[MAX_REG_NR];
+static unsigned long exec_fp_regs[FP_SIZE];
int init_registers(int pid)
{
@@ -42,10 +45,14 @@ int init_registers(int pid)
return -errno;
arch_init_registers(pid);
+ get_fp_registers(pid, exec_fp_regs);
return 0;
}
-void get_safe_registers(unsigned long *regs)
+void get_safe_registers(unsigned long *regs, unsigned long *fp_regs)
{
memcpy(regs, exec_regs, sizeof(exec_regs));
+
+ if (fp_regs)
+ memcpy(fp_regs, exec_fp_regs, sizeof(exec_fp_regs));
}
diff --git a/arch/um/os-Linux/skas/mem.c b/arch/um/os-Linux/skas/mem.c
index d261f170d120..e771398be5f3 100644
--- a/arch/um/os-Linux/skas/mem.c
+++ b/arch/um/os-Linux/skas/mem.c
@@ -39,7 +39,7 @@ static unsigned long syscall_regs[MAX_REG_NR];
static int __init init_syscall_regs(void)
{
- get_safe_registers(syscall_regs);
+ get_safe_registers(syscall_regs, NULL);
syscall_regs[REGS_IP_INDEX] = STUB_CODE +
((unsigned long) &batch_syscall_stub -
(unsigned long) &__syscall_stub_start);
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index d6e0a2234b86..dee0e8cf8ad0 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -373,6 +373,9 @@ void userspace(struct uml_pt_regs *regs)
if (ptrace(PTRACE_SETREGS, pid, 0, regs->gp))
fatal_sigsegv();
+ if (put_fp_registers(pid, regs->fp))
+ fatal_sigsegv();
+
/* Now we set local_using_sysemu to be used for one loop */
local_using_sysemu = get_using_sysemu();
@@ -399,6 +402,12 @@ void userspace(struct uml_pt_regs *regs)
fatal_sigsegv();
}
+ if (get_fp_registers(pid, regs->fp)) {
+ printk(UM_KERN_ERR "userspace - get_fp_registers failed, "
+ "errno = %d\n", errno);
+ fatal_sigsegv();
+ }
+
UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */
if (WIFSTOPPED(status)) {
@@ -457,10 +466,11 @@ void userspace(struct uml_pt_regs *regs)
}
static unsigned long thread_regs[MAX_REG_NR];
+static unsigned long thread_fp_regs[FP_SIZE];
static int __init init_thread_regs(void)
{
- get_safe_registers(thread_regs);
+ get_safe_registers(thread_regs, thread_fp_regs);
/* Set parent's instruction pointer to start of clone-stub */
thread_regs[REGS_IP_INDEX] = STUB_CODE +
(unsigned long) stub_clone_handler -
@@ -503,6 +513,13 @@ int copy_context_skas0(unsigned long new_stack, int pid)
return err;
}
+ err = put_fp_registers(pid, thread_fp_regs);
+ if (err < 0) {
+ printk(UM_KERN_ERR "copy_context_skas0 : put_fp_registers "
+ "failed, pid = %d, err = %d\n", pid, err);
+ return err;
+ }
+
/* set a well known return code for detection of child write failure */
child_data->err = 12345678;
diff --git a/arch/um/sys-i386/asm/ptrace.h b/arch/um/sys-i386/asm/ptrace.h
index 0273e4d09af7..5d2a59112537 100644
--- a/arch/um/sys-i386/asm/ptrace.h
+++ b/arch/um/sys-i386/asm/ptrace.h
@@ -42,11 +42,6 @@
*/
struct user_desc;
-extern int get_fpxregs(struct user_fxsr_struct __user *buf,
- struct task_struct *child);
-extern int set_fpxregs(struct user_fxsr_struct __user *buf,
- struct task_struct *tsk);
-
extern int ptrace_get_thread_area(struct task_struct *child, int idx,
struct user_desc __user *user_desc);
diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c
index d23b2d3ea384..3375c2717851 100644
--- a/arch/um/sys-i386/ptrace.c
+++ b/arch/um/sys-i386/ptrace.c
@@ -145,7 +145,7 @@ int peek_user(struct task_struct *child, long addr, long data)
return put_user(tmp, (unsigned long __user *) data);
}
-int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
+static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
{
int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
struct user_i387_struct fpregs;
@@ -161,7 +161,7 @@ int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
return n;
}
-int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
+static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
{
int n, cpu = ((struct thread_info *) child->stack)->cpu;
struct user_i387_struct fpregs;
@@ -174,7 +174,7 @@ int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
(unsigned long *) &fpregs);
}
-int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
+static int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
{
int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
struct user_fxsr_struct fpregs;
@@ -190,7 +190,7 @@ int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
return n;
}
-int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
+static int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
{
int n, cpu = ((struct thread_info *) child->stack)->cpu;
struct user_fxsr_struct fpregs;
@@ -206,5 +206,23 @@ int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
long subarch_ptrace(struct task_struct *child, long request,
unsigned long addr, unsigned long data)
{
- return -EIO;
+ int ret = -EIO;
+ void __user *datap = (void __user *) data;
+ switch (request) {
+ case PTRACE_GETFPREGS: /* Get the child FPU state. */
+ ret = get_fpregs(datap, child);
+ break;
+ case PTRACE_SETFPREGS: /* Set the child FPU state. */
+ ret = set_fpregs(datap, child);
+ break;
+ case PTRACE_GETFPXREGS: /* Get the child FPU state. */
+ ret = get_fpxregs(datap, child);
+ break;
+ case PTRACE_SETFPXREGS: /* Set the child FPU state. */
+ ret = set_fpxregs(datap, child);
+ break;
+ default:
+ ret = -EIO;
+ }
+ return ret;
}
diff --git a/arch/um/sys-i386/shared/sysdep/ptrace.h b/arch/um/sys-i386/shared/sysdep/ptrace.h
index d50e62e07070..c398a5076111 100644
--- a/arch/um/sys-i386/shared/sysdep/ptrace.h
+++ b/arch/um/sys-i386/shared/sysdep/ptrace.h
@@ -53,6 +53,7 @@ extern int sysemu_supported;
struct uml_pt_regs {
unsigned long gp[MAX_REG_NR];
+ unsigned long fp[HOST_FPX_SIZE];
struct faultinfo faultinfo;
long syscall;
int is_user;
diff --git a/arch/um/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c
index f43613643cdb..4005506834fd 100644
--- a/arch/um/sys-x86_64/ptrace.c
+++ b/arch/um/sys-x86_64/ptrace.c
@@ -145,7 +145,7 @@ int is_syscall(unsigned long addr)
return instr == 0x050f;
}
-int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
+static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
{
int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
long fpregs[HOST_FP_SIZE];
@@ -162,7 +162,7 @@ int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
return n;
}
-int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
+static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
{
int n, cpu = ((struct thread_info *) child->stack)->cpu;
long fpregs[HOST_FP_SIZE];
@@ -182,12 +182,16 @@ long subarch_ptrace(struct task_struct *child, long request,
void __user *datap = (void __user *) data;
switch (request) {
- case PTRACE_GETFPXREGS: /* Get the child FPU state. */
+ case PTRACE_GETFPREGS: /* Get the child FPU state. */
ret = get_fpregs(datap, child);
break;
- case PTRACE_SETFPXREGS: /* Set the child FPU state. */
+ case PTRACE_SETFPREGS: /* Set the child FPU state. */
ret = set_fpregs(datap, child);
break;
+ case PTRACE_ARCH_PRCTL:
+ /* XXX Calls ptrace on the host - needs some SMP thinking */
+ ret = arch_prctl(child, data, (void __user *) addr);
+ break;
}
return ret;
diff --git a/arch/um/sys-x86_64/shared/sysdep/ptrace.h b/arch/um/sys-x86_64/shared/sysdep/ptrace.h
index fdba5457947a..8ee8f8e12af1 100644
--- a/arch/um/sys-x86_64/shared/sysdep/ptrace.h
+++ b/arch/um/sys-x86_64/shared/sysdep/ptrace.h
@@ -85,6 +85,7 @@
struct uml_pt_regs {
unsigned long gp[MAX_REG_NR];
+ unsigned long fp[HOST_FP_SIZE];
struct faultinfo faultinfo;
long syscall;
int is_user;
diff --git a/arch/unicore32/include/asm/io.h b/arch/unicore32/include/asm/io.h
index 4bd87f3d13d4..1a5c5a5eb39c 100644
--- a/arch/unicore32/include/asm/io.h
+++ b/arch/unicore32/include/asm/io.h
@@ -32,7 +32,7 @@ extern void __uc32_iounmap(volatile void __iomem *addr);
* ioremap and friends.
*
* ioremap takes a PCI memory address, as specified in
- * Documentation/IO-mapping.txt.
+ * Documentation/io-mapping.txt.
*
*/
#define ioremap(cookie, size) __uc32_ioremap(cookie, size)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 6a47bb22657f..9a4a267a8a55 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -279,7 +279,7 @@ config SMP
Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
Management" code will be disabled if you say Y here.
- See also <file:Documentation/i386/IO-APIC.txt>,
+ See also <file:Documentation/x86/i386/IO-APIC.txt>,
<file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
<http://www.tldp.org/docs.html#howto>.
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index c0f8a5c88910..bf56e1793272 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -139,7 +139,7 @@ config IOMMU_DEBUG
code. When you use it make sure you have a big enough
IOMMU/AGP aperture. Most of the options enabled by this can
be set more finegrained using the iommu= command line
- options. See Documentation/x86_64/boot-options.txt for more
+ options. See Documentation/x86/x86_64/boot-options.txt for more
details.
config IOMMU_STRESS
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index 93e689f4bd86..bdb4d458ec8c 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -129,7 +129,7 @@ start_sys_seg: .word SYSSEG # obsolete and meaningless, but just
type_of_loader: .byte 0 # 0 means ancient bootloader, newer
# bootloaders know to change this.
- # See Documentation/i386/boot.txt for
+ # See Documentation/x86/boot.txt for
# assigned ids
# flags, unused bits must be zero (RFU) bit within loadflags
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index a0e866d233ee..54edb207ff3a 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -672,7 +672,7 @@ ia32_sys_call_table:
.quad sys32_vm86_warning /* vm86 */
.quad quiet_ni_syscall /* query_module */
.quad sys_poll
- .quad compat_sys_nfsservctl
+ .quad quiet_ni_syscall /* old nfsservctl */
.quad sys_setresgid16 /* 170 */
.quad sys_getresgid16
.quad sys_prctl
diff --git a/arch/x86/include/asm/alternative-asm.h b/arch/x86/include/asm/alternative-asm.h
index 4554cc6fb96a..091508b533b4 100644
--- a/arch/x86/include/asm/alternative-asm.h
+++ b/arch/x86/include/asm/alternative-asm.h
@@ -16,7 +16,6 @@
#endif
.macro altinstruction_entry orig alt feature orig_len alt_len
- .align 8
.long \orig - .
.long \alt - .
.word \feature
diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h
index 23fb6d79f209..37ad100a2210 100644
--- a/arch/x86/include/asm/alternative.h
+++ b/arch/x86/include/asm/alternative.h
@@ -48,9 +48,6 @@ struct alt_instr {
u16 cpuid; /* cpuid bit set for replacement */
u8 instrlen; /* length of original instruction */
u8 replacementlen; /* length of new instruction, <= instrlen */
-#ifdef CONFIG_X86_64
- u32 pad2;
-#endif
};
extern void alternative_instructions(void);
@@ -83,7 +80,6 @@ static inline int alternatives_text_reserved(void *start, void *end)
\
"661:\n\t" oldinstr "\n662:\n" \
".section .altinstructions,\"a\"\n" \
- _ASM_ALIGN "\n" \
" .long 661b - .\n" /* label */ \
" .long 663f - .\n" /* new instruction */ \
" .word " __stringify(feature) "\n" /* feature bit */ \
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 4258aac99a6e..88b23a43f340 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -332,7 +332,6 @@ static __always_inline __pure bool __static_cpu_has(u16 bit)
asm goto("1: jmp %l[t_no]\n"
"2:\n"
".section .altinstructions,\"a\"\n"
- _ASM_ALIGN "\n"
" .long 1b - .\n"
" .long 0\n" /* no replacement */
" .word %P0\n" /* feature bit */
@@ -350,7 +349,6 @@ static __always_inline __pure bool __static_cpu_has(u16 bit)
asm volatile("1: movb $0,%0\n"
"2:\n"
".section .altinstructions,\"a\"\n"
- _ASM_ALIGN "\n"
" .long 1b - .\n"
" .long 3f - .\n"
" .word %P1\n" /* feature bit */
diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h
index d4c419f883a0..ed3065fd6314 100644
--- a/arch/x86/include/asm/dma-mapping.h
+++ b/arch/x86/include/asm/dma-mapping.h
@@ -2,7 +2,7 @@
#define _ASM_X86_DMA_MAPPING_H
/*
- * IOMMU interface. See Documentation/PCI/PCI-DMA-mapping.txt and
+ * IOMMU interface. See Documentation/DMA-API-HOWTO.txt and
* Documentation/DMA-API.txt for documentation.
*/
diff --git a/arch/x86/include/asm/pvclock.h b/arch/x86/include/asm/pvclock.h
index a518c0a45044..c59cc97fe6c1 100644
--- a/arch/x86/include/asm/pvclock.h
+++ b/arch/x86/include/asm/pvclock.h
@@ -44,7 +44,7 @@ static inline u64 pvclock_scale_delta(u64 delta, u32 mul_frac, int shift)
: "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
#elif defined(__x86_64__)
__asm__ (
- "mul %[mul_frac] ; shrd $32, %[hi], %[lo]"
+ "mulq %[mul_frac] ; shrd $32, %[hi], %[lo]"
: [lo]"=a"(product),
[hi]"=d"(tmp)
: "0"(delta),
diff --git a/arch/x86/include/asm/unistd_64.h b/arch/x86/include/asm/unistd_64.h
index d92641cc7acc..201040573444 100644
--- a/arch/x86/include/asm/unistd_64.h
+++ b/arch/x86/include/asm/unistd_64.h
@@ -414,7 +414,7 @@ __SYSCALL(__NR_query_module, sys_ni_syscall)
__SYSCALL(__NR_quotactl, sys_quotactl)
#define __NR_nfsservctl 180
-__SYSCALL(__NR_nfsservctl, sys_nfsservctl)
+__SYSCALL(__NR_nfsservctl, sys_ni_syscall)
/* reserved for LiS/STREAMS */
#define __NR_getpmsg 181
diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
index 7ff4669580cf..c34f96c2f7a0 100644
--- a/arch/x86/include/asm/xen/page.h
+++ b/arch/x86/include/asm/xen/page.h
@@ -12,6 +12,7 @@
#include <asm/pgtable.h>
#include <xen/interface/xen.h>
+#include <xen/grant_table.h>
#include <xen/features.h>
/* Xen machine address */
@@ -48,14 +49,11 @@ extern unsigned long set_phys_range_identity(unsigned long pfn_s,
unsigned long pfn_e);
extern int m2p_add_override(unsigned long mfn, struct page *page,
- bool clear_pte);
+ struct gnttab_map_grant_ref *kmap_op);
extern int m2p_remove_override(struct page *page, bool clear_pte);
extern struct page *m2p_find_override(unsigned long mfn);
extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn);
-#ifdef CONFIG_XEN_DEBUG_FS
-extern int p2m_dump_show(struct seq_file *m, void *v);
-#endif
static inline unsigned long pfn_to_mfn(unsigned long pfn)
{
unsigned long mfn;
diff --git a/arch/x86/kernel/amd_gart_64.c b/arch/x86/kernel/amd_gart_64.c
index 8a439d364b94..b1e7c7f7a0af 100644
--- a/arch/x86/kernel/amd_gart_64.c
+++ b/arch/x86/kernel/amd_gart_64.c
@@ -5,7 +5,7 @@
* This allows to use PCI devices that only support 32bit addresses on systems
* with more than 4GB.
*
- * See Documentation/PCI/PCI-DMA-mapping.txt for the interface specification.
+ * See Documentation/DMA-API-HOWTO.txt for the interface specification.
*
* Copyright 2002 Andi Kleen, SuSE Labs.
* Subject to the GNU General Public License v2 only.
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index adc66c3a1fef..34b18594e724 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -207,7 +207,6 @@ static int __cpuinit uv_wakeup_secondary(int phys_apicid, unsigned long start_ri
((start_rip << UVH_IPI_INT_VECTOR_SHFT) >> 12) |
APIC_DM_INIT;
uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
- mdelay(10);
val = (1UL << UVH_IPI_INT_SEND_SHFT) |
(phys_apicid << UVH_IPI_INT_APIC_ID_SHFT) |
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c
index 0371c484bb8a..a46bd383953c 100644
--- a/arch/x86/kernel/apm_32.c
+++ b/arch/x86/kernel/apm_32.c
@@ -249,8 +249,6 @@ extern int (*console_blank_hook)(int);
#define APM_MINOR_DEV 134
/*
- * See Documentation/Config.help for the configuration options.
- *
* Various options can be changed at boot time as follows:
* (We allow underscores for compatibility with the modules code)
* apm=on/off enable/disable APM
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c
index 08119a37e53c..6b96110bb0c3 100644
--- a/arch/x86/kernel/cpu/mtrr/main.c
+++ b/arch/x86/kernel/cpu/mtrr/main.c
@@ -149,7 +149,6 @@ struct set_mtrr_data {
*/
static int mtrr_rendezvous_handler(void *info)
{
-#ifdef CONFIG_SMP
struct set_mtrr_data *data = info;
/*
@@ -171,7 +170,6 @@ static int mtrr_rendezvous_handler(void *info)
} else if (mtrr_aps_delayed_init || !cpu_online(smp_processor_id())) {
mtrr_if->set_all();
}
-#endif
return 0;
}
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 4ee3abf20ed6..cfa62ec090ec 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -1900,6 +1900,9 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
perf_callchain_store(entry, regs->ip);
+ if (!current->mm)
+ return;
+
if (perf_callchain_user32(regs, entry))
return;
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 5c1a91974918..f3f6f5344001 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -54,6 +54,7 @@
#include <asm/ftrace.h>
#include <asm/irq_vectors.h>
#include <asm/cpufeature.h>
+#include <asm/alternative-asm.h>
/* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */
#include <linux/elf-em.h>
@@ -873,12 +874,7 @@ ENTRY(simd_coprocessor_error)
661: pushl_cfi $do_general_protection
662:
.section .altinstructions,"a"
- .balign 4
- .long 661b
- .long 663f
- .word X86_FEATURE_XMM
- .byte 662b-661b
- .byte 664f-663f
+ altinstruction_entry 661b, 663f, X86_FEATURE_XMM, 662b-661b, 664f-663f
.previous
.section .altinstr_replacement,"ax"
663: pushl $do_simd_coprocessor_error
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c
index f1a6244d7d93..794bc95134cd 100644
--- a/arch/x86/kernel/kprobes.c
+++ b/arch/x86/kernel/kprobes.c
@@ -75,8 +75,10 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
/*
* Undefined/reserved opcodes, conditional jump, Opcode Extension
* Groups, and some special opcodes can not boost.
+ * This is non-const to keep gcc from statically optimizing it out, as
+ * variable_test_bit makes gcc think only *(unsigned long*) is used.
*/
-static const u32 twobyte_is_boostable[256 / 32] = {
+static u32 twobyte_is_boostable[256 / 32] = {
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
/* ---------------------------------------------- */
W(0x00, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0) | /* 00 */
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index b49d00da2aed..622872054fbe 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -117,8 +117,8 @@ again:
}
/*
- * See <Documentation/x86_64/boot-options.txt> for the iommu kernel parameter
- * documentation.
+ * See <Documentation/x86/x86_64/boot-options.txt> for the iommu kernel
+ * parameter documentation.
*/
static __init int iommu_setup(char *p)
{
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 7a3b65107a27..2196c703c5e2 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -262,7 +262,7 @@ EXPORT_SYMBOL_GPL(start_thread);
/*
- * switch_to(x,yn) should switch tasks from x to y.
+ * switch_to(x,y) should switch tasks from x to y.
*
* We fsave/fwait so that an exception goes off at the right time
* (as a call from the fsave or fwait in effect) rather than to
diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c
index 3f2ad2640d85..ccdbc16b8941 100644
--- a/arch/x86/kernel/rtc.c
+++ b/arch/x86/kernel/rtc.c
@@ -42,8 +42,11 @@ int mach_set_rtc_mmss(unsigned long nowtime)
{
int real_seconds, real_minutes, cmos_minutes;
unsigned char save_control, save_freq_select;
+ unsigned long flags;
int retval = 0;
+ spin_lock_irqsave(&rtc_lock, flags);
+
/* tell the clock it's being set */
save_control = CMOS_READ(RTC_CONTROL);
CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
@@ -93,12 +96,17 @@ int mach_set_rtc_mmss(unsigned long nowtime)
CMOS_WRITE(save_control, RTC_CONTROL);
CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+ spin_unlock_irqrestore(&rtc_lock, flags);
+
return retval;
}
unsigned long mach_get_cmos_time(void)
{
unsigned int status, year, mon, day, hour, min, sec, century = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rtc_lock, flags);
/*
* If UIP is clear, then we have >= 244 microseconds before
@@ -125,6 +133,8 @@ unsigned long mach_get_cmos_time(void)
status = CMOS_READ(RTC_CONTROL);
WARN_ON_ONCE(RTC_ALWAYS_BCD && (status & RTC_DM_BINARY));
+ spin_unlock_irqrestore(&rtc_lock, flags);
+
if (RTC_ALWAYS_BCD || !(status & RTC_DM_BINARY)) {
sec = bcd2bin(sec);
min = bcd2bin(min);
@@ -169,24 +179,15 @@ EXPORT_SYMBOL(rtc_cmos_write);
int update_persistent_clock(struct timespec now)
{
- unsigned long flags;
- int retval;
-
- spin_lock_irqsave(&rtc_lock, flags);
- retval = x86_platform.set_wallclock(now.tv_sec);
- spin_unlock_irqrestore(&rtc_lock, flags);
-
- return retval;
+ return x86_platform.set_wallclock(now.tv_sec);
}
/* not static: needed by APM */
void read_persistent_clock(struct timespec *ts)
{
- unsigned long retval, flags;
+ unsigned long retval;
- spin_lock_irqsave(&rtc_lock, flags);
retval = x86_platform.get_wallclock();
- spin_unlock_irqrestore(&rtc_lock, flags);
ts->tv_sec = retval;
ts->tv_nsec = 0;
diff --git a/arch/x86/kernel/syscall_table_32.S b/arch/x86/kernel/syscall_table_32.S
index fbb0a045a1a2..bc19be332bc9 100644
--- a/arch/x86/kernel/syscall_table_32.S
+++ b/arch/x86/kernel/syscall_table_32.S
@@ -168,7 +168,7 @@ ENTRY(sys_call_table)
.long ptregs_vm86
.long sys_ni_syscall /* Old sys_query_module */
.long sys_poll
- .long sys_nfsservctl
+ .long sys_ni_syscall /* Old nfsservctl */
.long sys_setresgid16 /* 170 */
.long sys_getresgid16
.long sys_prctl
diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c
index 18ae83dd1cd7..b56c65de384d 100644
--- a/arch/x86/kernel/vsyscall_64.c
+++ b/arch/x86/kernel/vsyscall_64.c
@@ -56,7 +56,7 @@ DEFINE_VVAR(struct vsyscall_gtod_data, vsyscall_gtod_data) =
.lock = __SEQLOCK_UNLOCKED(__vsyscall_gtod_data.lock),
};
-static enum { EMULATE, NATIVE, NONE } vsyscall_mode = EMULATE;
+static enum { EMULATE, NATIVE, NONE } vsyscall_mode = NATIVE;
static int __init vsyscall_setup(char *str)
{
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 6f08bc940fa8..8b4cc5f067de 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -3603,7 +3603,7 @@ done_prefixes:
break;
case Src2CL:
ctxt->src2.bytes = 1;
- ctxt->src2.val = ctxt->regs[VCPU_REGS_RCX] & 0x8;
+ ctxt->src2.val = ctxt->regs[VCPU_REGS_RCX] & 0xff;
break;
case Src2ImmByte:
rc = decode_imm(ctxt, &ctxt->src2, 1, true);
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 1c5b69373a00..8e8da7960dbe 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -400,7 +400,8 @@ static u64 __update_clear_spte_slow(u64 *sptep, u64 spte)
/* xchg acts as a barrier before the setting of the high bits */
orig.spte_low = xchg(&ssptep->spte_low, sspte.spte_low);
- orig.spte_high = ssptep->spte_high = sspte.spte_high;
+ orig.spte_high = ssptep->spte_high;
+ ssptep->spte_high = sspte.spte_high;
count_spte_clear(sptep, spte);
return orig.spte;
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index 30326443ab81..87488b93a65c 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -63,9 +63,8 @@ static void __init find_early_table_space(unsigned long end, int use_pse,
#ifdef CONFIG_X86_32
/* for fixmap */
tables += roundup(__end_of_fixed_addresses * sizeof(pte_t), PAGE_SIZE);
-
- good_end = max_pfn_mapped << PAGE_SHIFT;
#endif
+ good_end = max_pfn_mapped << PAGE_SHIFT;
base = memblock_find_in_range(start, good_end, tables, PAGE_SIZE);
if (base == MEMBLOCK_ERROR)
diff --git a/arch/x86/mm/mmio-mod.c b/arch/x86/mm/mmio-mod.c
index 67421f38a215..de54b9b278a7 100644
--- a/arch/x86/mm/mmio-mod.c
+++ b/arch/x86/mm/mmio-mod.c
@@ -29,7 +29,6 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>
-#include <linux/version.h>
#include <linux/kallsyms.h>
#include <asm/pgtable.h>
#include <linux/mmiotrace.h>
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index c95330267f08..404f21a3ff9e 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -43,6 +43,17 @@ static const struct dmi_system_id pci_use_crs_table[] __initconst = {
DMI_MATCH(DMI_PRODUCT_NAME, "ALiveSATA2-GLAN"),
},
},
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=30552 */
+ /* 2006 AMD HT/VIA system with two host bridges */
+ {
+ .callback = set_use_crs,
+ .ident = "ASUS M2V-MX SE",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "M2V-MX SE"),
+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
+ },
+ },
{}
};
@@ -365,8 +376,13 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
*/
if (bus) {
struct pci_bus *child;
- list_for_each_entry(child, &bus->children, node)
- pcie_bus_configure_settings(child, child->self->pcie_mpss);
+ list_for_each_entry(child, &bus->children, node) {
+ struct pci_dev *self = child->self;
+ if (!self)
+ continue;
+
+ pcie_bus_configure_settings(child, self->pcie_mpss);
+ }
}
if (!bus)
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
index 1017c7bee388..492ade8c978e 100644
--- a/arch/x86/pci/xen.c
+++ b/arch/x86/pci/xen.c
@@ -175,8 +175,10 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
"pcifront-msi-x" :
"pcifront-msi",
DOMID_SELF);
- if (irq < 0)
+ if (irq < 0) {
+ ret = irq;
goto free;
+ }
i++;
}
kfree(v);
@@ -221,8 +223,10 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
if (msg.data != XEN_PIRQ_MSI_DATA ||
xen_irq_from_pirq(pirq) < 0) {
pirq = xen_allocate_pirq_msi(dev, msidesc);
- if (pirq < 0)
+ if (pirq < 0) {
+ irq = -ENODEV;
goto error;
+ }
xen_msi_compose_msg(dev, pirq, &msg);
__write_msi_msg(msidesc, &msg);
dev_dbg(&dev->dev, "xen: msi bound to pirq=%d\n", pirq);
@@ -244,10 +248,12 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
error:
dev_err(&dev->dev,
"Xen PCI frontend has not registered MSI/MSI-X support!\n");
- return -ENODEV;
+ return irq;
}
#ifdef CONFIG_XEN_DOM0
+static bool __read_mostly pci_seg_supported = true;
+
static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{
int ret = 0;
@@ -265,10 +271,11 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
memset(&map_irq, 0, sizeof(map_irq));
map_irq.domid = domid;
- map_irq.type = MAP_PIRQ_TYPE_MSI;
+ map_irq.type = MAP_PIRQ_TYPE_MSI_SEG;
map_irq.index = -1;
map_irq.pirq = -1;
- map_irq.bus = dev->bus->number;
+ map_irq.bus = dev->bus->number |
+ (pci_domain_nr(dev->bus) << 16);
map_irq.devfn = dev->devfn;
if (type == PCI_CAP_ID_MSIX) {
@@ -285,7 +292,20 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
map_irq.entry_nr = msidesc->msi_attrib.entry_nr;
}
- ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
+ ret = -EINVAL;
+ if (pci_seg_supported)
+ ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq,
+ &map_irq);
+ if (ret == -EINVAL && !pci_domain_nr(dev->bus)) {
+ map_irq.type = MAP_PIRQ_TYPE_MSI;
+ map_irq.index = -1;
+ map_irq.pirq = -1;
+ map_irq.bus = dev->bus->number;
+ ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq,
+ &map_irq);
+ if (ret != -EINVAL)
+ pci_seg_supported = false;
+ }
if (ret) {
dev_warn(&dev->dev, "xen map irq failed %d for %d domain\n",
ret, domid);
diff --git a/arch/x86/platform/mrst/mrst.c b/arch/x86/platform/mrst/mrst.c
index b8da1b968998..e6379526675b 100644
--- a/arch/x86/platform/mrst/mrst.c
+++ b/arch/x86/platform/mrst/mrst.c
@@ -681,36 +681,40 @@ static int __init sfi_parse_devs(struct sfi_table_header *table)
pentry = (struct sfi_device_table_entry *)sb->pentry;
for (i = 0; i < num; i++, pentry++) {
- if (pentry->irq != (u8)0xff) { /* native RTE case */
+ int irq = pentry->irq;
+
+ if (irq != (u8)0xff) { /* native RTE case */
/* these SPI2 devices are not exposed to system as PCI
* devices, but they have separate RTE entry in IOAPIC
* so we have to enable them one by one here
*/
- ioapic = mp_find_ioapic(pentry->irq);
+ ioapic = mp_find_ioapic(irq);
irq_attr.ioapic = ioapic;
- irq_attr.ioapic_pin = pentry->irq;
+ irq_attr.ioapic_pin = irq;
irq_attr.trigger = 1;
irq_attr.polarity = 1;
- io_apic_set_pci_routing(NULL, pentry->irq, &irq_attr);
- }
+ io_apic_set_pci_routing(NULL, irq, &irq_attr);
+ } else
+ irq = 0; /* No irq */
+
switch (pentry->type) {
case SFI_DEV_TYPE_IPC:
/* ID as IRQ is a hack that will go away */
- pdev = platform_device_alloc(pentry->name, pentry->irq);
+ pdev = platform_device_alloc(pentry->name, irq);
if (pdev == NULL) {
pr_err("out of memory for SFI platform device '%s'.\n",
pentry->name);
continue;
}
- install_irq_resource(pdev, pentry->irq);
+ install_irq_resource(pdev, irq);
pr_debug("info[%2d]: IPC bus, name = %16.16s, "
- "irq = 0x%2x\n", i, pentry->name, pentry->irq);
+ "irq = 0x%2x\n", i, pentry->name, irq);
sfi_handle_ipc_dev(pdev);
break;
case SFI_DEV_TYPE_SPI:
memset(&spi_info, 0, sizeof(spi_info));
strncpy(spi_info.modalias, pentry->name, SFI_NAME_LEN);
- spi_info.irq = pentry->irq;
+ spi_info.irq = irq;
spi_info.bus_num = pentry->host_num;
spi_info.chip_select = pentry->addr;
spi_info.max_speed_hz = pentry->max_freq;
@@ -727,7 +731,7 @@ static int __init sfi_parse_devs(struct sfi_table_header *table)
memset(&i2c_info, 0, sizeof(i2c_info));
bus = pentry->host_num;
strncpy(i2c_info.type, pentry->name, SFI_NAME_LEN);
- i2c_info.irq = pentry->irq;
+ i2c_info.irq = irq;
i2c_info.addr = pentry->addr;
pr_debug("info[%2d]: I2C bus = %d, name = %16.16s, "
"irq = 0x%2x, addr = 0x%x\n", i, bus,
diff --git a/arch/x86/platform/mrst/vrtc.c b/arch/x86/platform/mrst/vrtc.c
index 73d70d65e76e..6d5dbcdd444a 100644
--- a/arch/x86/platform/mrst/vrtc.c
+++ b/arch/x86/platform/mrst/vrtc.c
@@ -58,8 +58,11 @@ EXPORT_SYMBOL_GPL(vrtc_cmos_write);
unsigned long vrtc_get_time(void)
{
u8 sec, min, hour, mday, mon;
+ unsigned long flags;
u32 year;
+ spin_lock_irqsave(&rtc_lock, flags);
+
while ((vrtc_cmos_read(RTC_FREQ_SELECT) & RTC_UIP))
cpu_relax();
@@ -70,6 +73,8 @@ unsigned long vrtc_get_time(void)
mon = vrtc_cmos_read(RTC_MONTH);
year = vrtc_cmos_read(RTC_YEAR);
+ spin_unlock_irqrestore(&rtc_lock, flags);
+
/* vRTC YEAR reg contains the offset to 1960 */
year += 1960;
@@ -83,8 +88,10 @@ unsigned long vrtc_get_time(void)
int vrtc_set_mmss(unsigned long nowtime)
{
int real_sec, real_min;
+ unsigned long flags;
int vrtc_min;
+ spin_lock_irqsave(&rtc_lock, flags);
vrtc_min = vrtc_cmos_read(RTC_MINUTES);
real_sec = nowtime % 60;
@@ -95,6 +102,8 @@ int vrtc_set_mmss(unsigned long nowtime)
vrtc_cmos_write(real_sec, RTC_SECONDS);
vrtc_cmos_write(real_min, RTC_MINUTES);
+ spin_unlock_irqrestore(&rtc_lock, flags);
+
return 0;
}
diff --git a/arch/x86/platform/olpc/olpc.c b/arch/x86/platform/olpc/olpc.c
index 8b9940e78e2f..7cce722667b8 100644
--- a/arch/x86/platform/olpc/olpc.c
+++ b/arch/x86/platform/olpc/olpc.c
@@ -161,13 +161,13 @@ restart:
if (inbuf && inlen) {
/* write data to EC */
for (i = 0; i < inlen; i++) {
+ pr_devel("olpc-ec: sending cmd arg 0x%x\n", inbuf[i]);
+ outb(inbuf[i], 0x68);
if (wait_on_ibf(0x6c, 0)) {
printk(KERN_ERR "olpc-ec: timeout waiting for"
" EC accept data!\n");
goto err;
}
- pr_devel("olpc-ec: sending cmd arg 0x%x\n", inbuf[i]);
- outb(inbuf[i], 0x68);
}
}
if (outbuf && outlen) {
diff --git a/arch/x86/vdso/vdso32/sysenter.S b/arch/x86/vdso/vdso32/sysenter.S
index e2800affa754..e354bceee0e0 100644
--- a/arch/x86/vdso/vdso32/sysenter.S
+++ b/arch/x86/vdso/vdso32/sysenter.S
@@ -43,7 +43,7 @@ __kernel_vsyscall:
.space 7,0x90
/* 14: System call restart point is here! (SYSENTER_RETURN-2) */
- jmp .Lenter_kernel
+ int $0x80
/* 16: System call normal return point is here! */
VDSO32_SYSENTER_RETURN: /* Symbol used by sysenter.c via vdso32-syms.h */
pop %ebp
diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig
index 5cc821cb2e09..26c731a106af 100644
--- a/arch/x86/xen/Kconfig
+++ b/arch/x86/xen/Kconfig
@@ -25,8 +25,7 @@ config XEN_PRIVILEGED_GUEST
config XEN_PVHVM
def_bool y
- depends on XEN
- depends on X86_LOCAL_APIC
+ depends on XEN && PCI && X86_LOCAL_APIC
config XEN_MAX_DOMAIN_MEMORY
int
@@ -49,11 +48,3 @@ config XEN_DEBUG_FS
help
Enable statistics output and various tuning options in debugfs.
Enabling this option may incur a significant performance overhead.
-
-config XEN_DEBUG
- bool "Enable Xen debug checks"
- depends on XEN
- default n
- help
- Enable various WARN_ON checks in the Xen MMU code.
- Enabling this option WILL incur a significant performance overhead.
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 2d69617950f7..da8afd576a6b 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -251,6 +251,7 @@ static void __init xen_init_cpuid_mask(void)
~((1 << X86_FEATURE_APIC) | /* disable local APIC */
(1 << X86_FEATURE_ACPI)); /* disable ACPI */
ax = 1;
+ cx = 0;
xen_cpuid(&ax, &bx, &cx, &dx);
xsave_mask =
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 20a614275064..87f6673b1207 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -495,41 +495,6 @@ static pte_t xen_make_pte(pteval_t pte)
}
PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte);
-#ifdef CONFIG_XEN_DEBUG
-pte_t xen_make_pte_debug(pteval_t pte)
-{
- phys_addr_t addr = (pte & PTE_PFN_MASK);
- phys_addr_t other_addr;
- bool io_page = false;
- pte_t _pte;
-
- if (pte & _PAGE_IOMAP)
- io_page = true;
-
- _pte = xen_make_pte(pte);
-
- if (!addr)
- return _pte;
-
- if (io_page &&
- (xen_initial_domain() || addr >= ISA_END_ADDRESS)) {
- other_addr = pfn_to_mfn(addr >> PAGE_SHIFT) << PAGE_SHIFT;
- WARN_ONCE(addr != other_addr,
- "0x%lx is using VM_IO, but it is 0x%lx!\n",
- (unsigned long)addr, (unsigned long)other_addr);
- } else {
- pteval_t iomap_set = (_pte.pte & PTE_FLAGS_MASK) & _PAGE_IOMAP;
- other_addr = (_pte.pte & PTE_PFN_MASK);
- WARN_ONCE((addr == other_addr) && (!io_page) && (!iomap_set),
- "0x%lx is missing VM_IO (and wasn't fixed)!\n",
- (unsigned long)addr);
- }
-
- return _pte;
-}
-PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte_debug);
-#endif
-
static pgd_t xen_make_pgd(pgdval_t pgd)
{
pgd = pte_pfn_to_mfn(pgd);
@@ -1721,10 +1686,8 @@ void __init xen_setup_machphys_mapping(void)
machine_to_phys_nr = MACH2PHYS_NR_ENTRIES;
}
#ifdef CONFIG_X86_32
- if ((machine_to_phys_mapping + machine_to_phys_nr)
- < machine_to_phys_mapping)
- machine_to_phys_nr = (unsigned long *)NULL
- - machine_to_phys_mapping;
+ WARN_ON((machine_to_phys_mapping + (machine_to_phys_nr - 1))
+ < machine_to_phys_mapping);
#endif
}
@@ -1994,9 +1957,6 @@ void __init xen_ident_map_ISA(void)
static void __init xen_post_allocator_init(void)
{
-#ifdef CONFIG_XEN_DEBUG
- pv_mmu_ops.make_pte = PV_CALLEE_SAVE(xen_make_pte_debug);
-#endif
pv_mmu_ops.set_pte = xen_set_pte;
pv_mmu_ops.set_pmd = xen_set_pmd;
pv_mmu_ops.set_pud = xen_set_pud;
@@ -2406,17 +2366,3 @@ out:
return err;
}
EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range);
-
-#ifdef CONFIG_XEN_DEBUG_FS
-static int p2m_dump_open(struct inode *inode, struct file *filp)
-{
- return single_open(filp, p2m_dump_show, NULL);
-}
-
-static const struct file_operations p2m_dump_fops = {
- .open = p2m_dump_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-#endif /* CONFIG_XEN_DEBUG_FS */
diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
index 58efeb9d5440..1b267e75158d 100644
--- a/arch/x86/xen/p2m.c
+++ b/arch/x86/xen/p2m.c
@@ -161,7 +161,9 @@
#include <asm/xen/page.h>
#include <asm/xen/hypercall.h>
#include <asm/xen/hypervisor.h>
+#include <xen/grant_table.h>
+#include "multicalls.h"
#include "xen-ops.h"
static void __init m2p_override_init(void);
@@ -676,7 +678,8 @@ static unsigned long mfn_hash(unsigned long mfn)
}
/* Add an MFN override for a particular page */
-int m2p_add_override(unsigned long mfn, struct page *page, bool clear_pte)
+int m2p_add_override(unsigned long mfn, struct page *page,
+ struct gnttab_map_grant_ref *kmap_op)
{
unsigned long flags;
unsigned long pfn;
@@ -692,16 +695,28 @@ int m2p_add_override(unsigned long mfn, struct page *page, bool clear_pte)
"m2p_add_override: pfn %lx not mapped", pfn))
return -EINVAL;
}
-
- page->private = mfn;
+ WARN_ON(PagePrivate(page));
+ SetPagePrivate(page);
+ set_page_private(page, mfn);
page->index = pfn_to_mfn(pfn);
if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn))))
return -ENOMEM;
- if (clear_pte && !PageHighMem(page))
- /* Just zap old mapping for now */
- pte_clear(&init_mm, address, ptep);
+ if (kmap_op != NULL) {
+ if (!PageHighMem(page)) {
+ struct multicall_space mcs =
+ xen_mc_entry(sizeof(*kmap_op));
+
+ MULTI_grant_table_op(mcs.mc,
+ GNTTABOP_map_grant_ref, kmap_op, 1);
+
+ xen_mc_issue(PARAVIRT_LAZY_MMU);
+ }
+ /* let's use dev_bus_addr to record the old mfn instead */
+ kmap_op->dev_bus_addr = page->index;
+ page->index = (unsigned long) kmap_op;
+ }
spin_lock_irqsave(&m2p_override_lock, flags);
list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]);
spin_unlock_irqrestore(&m2p_override_lock, flags);
@@ -735,13 +750,56 @@ int m2p_remove_override(struct page *page, bool clear_pte)
spin_lock_irqsave(&m2p_override_lock, flags);
list_del(&page->lru);
spin_unlock_irqrestore(&m2p_override_lock, flags);
- set_phys_to_machine(pfn, page->index);
+ WARN_ON(!PagePrivate(page));
+ ClearPagePrivate(page);
- if (clear_pte && !PageHighMem(page))
- set_pte_at(&init_mm, address, ptep,
- pfn_pte(pfn, PAGE_KERNEL));
- /* No tlb flush necessary because the caller already
- * left the pte unmapped. */
+ if (clear_pte) {
+ struct gnttab_map_grant_ref *map_op =
+ (struct gnttab_map_grant_ref *) page->index;
+ set_phys_to_machine(pfn, map_op->dev_bus_addr);
+ if (!PageHighMem(page)) {
+ struct multicall_space mcs;
+ struct gnttab_unmap_grant_ref *unmap_op;
+
+ /*
+ * It might be that we queued all the m2p grant table
+ * hypercalls in a multicall, then m2p_remove_override
+ * get called before the multicall has actually been
+ * issued. In this case handle is going to -1 because
+ * it hasn't been modified yet.
+ */
+ if (map_op->handle == -1)
+ xen_mc_flush();
+ /*
+ * Now if map_op->handle is negative it means that the
+ * hypercall actually returned an error.
+ */
+ if (map_op->handle == GNTST_general_error) {
+ printk(KERN_WARNING "m2p_remove_override: "
+ "pfn %lx mfn %lx, failed to modify kernel mappings",
+ pfn, mfn);
+ return -1;
+ }
+
+ mcs = xen_mc_entry(
+ sizeof(struct gnttab_unmap_grant_ref));
+ unmap_op = mcs.args;
+ unmap_op->host_addr = map_op->host_addr;
+ unmap_op->handle = map_op->handle;
+ unmap_op->dev_bus_addr = 0;
+
+ MULTI_grant_table_op(mcs.mc,
+ GNTTABOP_unmap_grant_ref, unmap_op, 1);
+
+ xen_mc_issue(PARAVIRT_LAZY_MMU);
+
+ set_pte_at(&init_mm, address, ptep,
+ pfn_pte(pfn, PAGE_KERNEL));
+ __flush_tlb_single(address);
+ map_op->host_addr = 0;
+ }
+ } else
+ set_phys_to_machine(pfn, page->index);
return 0;
}
@@ -758,7 +816,7 @@ struct page *m2p_find_override(unsigned long mfn)
spin_lock_irqsave(&m2p_override_lock, flags);
list_for_each_entry(p, bucket, lru) {
- if (p->private == mfn) {
+ if (page_private(p) == mfn) {
ret = p;
break;
}
@@ -782,17 +840,21 @@ unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn)
EXPORT_SYMBOL_GPL(m2p_find_override_pfn);
#ifdef CONFIG_XEN_DEBUG_FS
-
-int p2m_dump_show(struct seq_file *m, void *v)
+#include <linux/debugfs.h>
+#include "debugfs.h"
+static int p2m_dump_show(struct seq_file *m, void *v)
{
static const char * const level_name[] = { "top", "middle",
- "entry", "abnormal" };
- static const char * const type_name[] = { "identity", "missing",
- "pfn", "abnormal"};
+ "entry", "abnormal", "error"};
#define TYPE_IDENTITY 0
#define TYPE_MISSING 1
#define TYPE_PFN 2
#define TYPE_UNKNOWN 3
+ static const char * const type_name[] = {
+ [TYPE_IDENTITY] = "identity",
+ [TYPE_MISSING] = "missing",
+ [TYPE_PFN] = "pfn",
+ [TYPE_UNKNOWN] = "abnormal"};
unsigned long pfn, prev_pfn_type = 0, prev_pfn_level = 0;
unsigned int uninitialized_var(prev_level);
unsigned int uninitialized_var(prev_type);
@@ -856,4 +918,32 @@ int p2m_dump_show(struct seq_file *m, void *v)
#undef TYPE_PFN
#undef TYPE_UNKNOWN
}
-#endif
+
+static int p2m_dump_open(struct inode *inode, struct file *filp)
+{
+ return single_open(filp, p2m_dump_show, NULL);
+}
+
+static const struct file_operations p2m_dump_fops = {
+ .open = p2m_dump_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct dentry *d_mmu_debug;
+
+static int __init xen_p2m_debugfs(void)
+{
+ struct dentry *d_xen = xen_init_debugfs();
+
+ if (d_xen == NULL)
+ return -ENOMEM;
+
+ d_mmu_debug = debugfs_create_dir("mmu", d_xen);
+
+ debugfs_create_file("p2m", 0600, d_mmu_debug, NULL, &p2m_dump_fops);
+ return 0;
+}
+fs_initcall(xen_p2m_debugfs);
+#endif /* CONFIG_XEN_DEBUG_FS */
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
index df118a825f39..38d0af4fefec 100644
--- a/arch/x86/xen/setup.c
+++ b/arch/x86/xen/setup.c
@@ -37,7 +37,10 @@ extern void xen_syscall_target(void);
extern void xen_syscall32_target(void);
/* Amount of extra memory space we add to the e820 ranges */
-phys_addr_t xen_extra_mem_start, xen_extra_mem_size;
+struct xen_memory_region xen_extra_mem[XEN_EXTRA_MEM_MAX_REGIONS] __initdata;
+
+/* Number of pages released from the initial allocation. */
+unsigned long xen_released_pages;
/*
* The maximum amount of extra memory compared to the base size. The
@@ -51,48 +54,47 @@ phys_addr_t xen_extra_mem_start, xen_extra_mem_size;
*/
#define EXTRA_MEM_RATIO (10)
-static void __init xen_add_extra_mem(unsigned long pages)
+static void __init xen_add_extra_mem(u64 start, u64 size)
{
unsigned long pfn;
+ int i;
- u64 size = (u64)pages * PAGE_SIZE;
- u64 extra_start = xen_extra_mem_start + xen_extra_mem_size;
-
- if (!pages)
- return;
-
- e820_add_region(extra_start, size, E820_RAM);
- sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
-
- memblock_x86_reserve_range(extra_start, extra_start + size, "XEN EXTRA");
+ for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) {
+ /* Add new region. */
+ if (xen_extra_mem[i].size == 0) {
+ xen_extra_mem[i].start = start;
+ xen_extra_mem[i].size = size;
+ break;
+ }
+ /* Append to existing region. */
+ if (xen_extra_mem[i].start + xen_extra_mem[i].size == start) {
+ xen_extra_mem[i].size += size;
+ break;
+ }
+ }
+ if (i == XEN_EXTRA_MEM_MAX_REGIONS)
+ printk(KERN_WARNING "Warning: not enough extra memory regions\n");
- xen_extra_mem_size += size;
+ memblock_x86_reserve_range(start, start + size, "XEN EXTRA");
- xen_max_p2m_pfn = PFN_DOWN(extra_start + size);
+ xen_max_p2m_pfn = PFN_DOWN(start + size);
- for (pfn = PFN_DOWN(extra_start); pfn <= xen_max_p2m_pfn; pfn++)
+ for (pfn = PFN_DOWN(start); pfn <= xen_max_p2m_pfn; pfn++)
__set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
}
-static unsigned long __init xen_release_chunk(phys_addr_t start_addr,
- phys_addr_t end_addr)
+static unsigned long __init xen_release_chunk(unsigned long start,
+ unsigned long end)
{
struct xen_memory_reservation reservation = {
.address_bits = 0,
.extent_order = 0,
.domid = DOMID_SELF
};
- unsigned long start, end;
unsigned long len = 0;
unsigned long pfn;
int ret;
- start = PFN_UP(start_addr);
- end = PFN_DOWN(end_addr);
-
- if (end <= start)
- return 0;
-
for(pfn = start; pfn < end; pfn++) {
unsigned long mfn = pfn_to_mfn(pfn);
@@ -117,88 +119,92 @@ static unsigned long __init xen_release_chunk(phys_addr_t start_addr,
return len;
}
-static unsigned long __init xen_return_unused_memory(unsigned long max_pfn,
- const struct e820map *e820)
+static unsigned long __init xen_set_identity_and_release(
+ const struct e820entry *list, size_t map_size, unsigned long nr_pages)
{
- phys_addr_t max_addr = PFN_PHYS(max_pfn);
- phys_addr_t last_end = ISA_END_ADDRESS;
+ phys_addr_t start = 0;
unsigned long released = 0;
+ unsigned long identity = 0;
+ const struct e820entry *entry;
int i;
- /* Free any unused memory above the low 1Mbyte. */
- for (i = 0; i < e820->nr_map && last_end < max_addr; i++) {
- phys_addr_t end = e820->map[i].addr;
- end = min(max_addr, end);
+ /*
+ * Combine non-RAM regions and gaps until a RAM region (or the
+ * end of the map) is reached, then set the 1:1 map and
+ * release the pages (if available) in those non-RAM regions.
+ *
+ * The combined non-RAM regions are rounded to a whole number
+ * of pages so any partial pages are accessible via the 1:1
+ * mapping. This is needed for some BIOSes that put (for
+ * example) the DMI tables in a reserved region that begins on
+ * a non-page boundary.
+ */
+ for (i = 0, entry = list; i < map_size; i++, entry++) {
+ phys_addr_t end = entry->addr + entry->size;
+
+ if (entry->type == E820_RAM || i == map_size - 1) {
+ unsigned long start_pfn = PFN_DOWN(start);
+ unsigned long end_pfn = PFN_UP(end);
- if (last_end < end)
- released += xen_release_chunk(last_end, end);
- last_end = max(last_end, e820->map[i].addr + e820->map[i].size);
+ if (entry->type == E820_RAM)
+ end_pfn = PFN_UP(entry->addr);
+
+ if (start_pfn < end_pfn) {
+ if (start_pfn < nr_pages)
+ released += xen_release_chunk(
+ start_pfn, min(end_pfn, nr_pages));
+
+ identity += set_phys_range_identity(
+ start_pfn, end_pfn);
+ }
+ start = end;
+ }
}
- if (last_end < max_addr)
- released += xen_release_chunk(last_end, max_addr);
+ printk(KERN_INFO "Released %lu pages of unused memory\n", released);
+ printk(KERN_INFO "Set %ld page(s) to 1-1 mapping\n", identity);
- printk(KERN_INFO "released %lu pages of unused memory\n", released);
return released;
}
-static unsigned long __init xen_set_identity(const struct e820entry *list,
- ssize_t map_size)
+static unsigned long __init xen_get_max_pages(void)
{
- phys_addr_t last = xen_initial_domain() ? 0 : ISA_END_ADDRESS;
- phys_addr_t start_pci = last;
- const struct e820entry *entry;
- unsigned long identity = 0;
- int i;
-
- for (i = 0, entry = list; i < map_size; i++, entry++) {
- phys_addr_t start = entry->addr;
- phys_addr_t end = start + entry->size;
-
- if (start < last)
- start = last;
-
- if (end <= start)
- continue;
+ unsigned long max_pages = MAX_DOMAIN_PAGES;
+ domid_t domid = DOMID_SELF;
+ int ret;
- /* Skip over the 1MB region. */
- if (last > end)
- continue;
+ ret = HYPERVISOR_memory_op(XENMEM_maximum_reservation, &domid);
+ if (ret > 0)
+ max_pages = ret;
+ return min(max_pages, MAX_DOMAIN_PAGES);
+}
- if ((entry->type == E820_RAM) || (entry->type == E820_UNUSABLE)) {
- if (start > start_pci)
- identity += set_phys_range_identity(
- PFN_UP(start_pci), PFN_DOWN(start));
+static void xen_align_and_add_e820_region(u64 start, u64 size, int type)
+{
+ u64 end = start + size;
- /* Without saving 'last' we would gooble RAM too
- * at the end of the loop. */
- last = end;
- start_pci = end;
- continue;
- }
- start_pci = min(start, start_pci);
- last = end;
+ /* Align RAM regions to page boundaries. */
+ if (type == E820_RAM) {
+ start = PAGE_ALIGN(start);
+ end &= ~((u64)PAGE_SIZE - 1);
}
- if (last > start_pci)
- identity += set_phys_range_identity(
- PFN_UP(start_pci), PFN_DOWN(last));
- return identity;
+
+ e820_add_region(start, end - start, type);
}
+
/**
* machine_specific_memory_setup - Hook for machine specific memory setup.
**/
char * __init xen_memory_setup(void)
{
static struct e820entry map[E820MAX] __initdata;
- static struct e820entry map_raw[E820MAX] __initdata;
unsigned long max_pfn = xen_start_info->nr_pages;
unsigned long long mem_end;
int rc;
struct xen_memory_map memmap;
+ unsigned long max_pages;
unsigned long extra_pages = 0;
- unsigned long extra_limit;
- unsigned long identity_pages = 0;
int i;
int op;
@@ -224,58 +230,65 @@ char * __init xen_memory_setup(void)
}
BUG_ON(rc);
- memcpy(map_raw, map, sizeof(map));
- e820.nr_map = 0;
- xen_extra_mem_start = mem_end;
- for (i = 0; i < memmap.nr_entries; i++) {
- unsigned long long end;
-
- /* Guard against non-page aligned E820 entries. */
- if (map[i].type == E820_RAM)
- map[i].size -= (map[i].size + map[i].addr) % PAGE_SIZE;
-
- end = map[i].addr + map[i].size;
- if (map[i].type == E820_RAM && end > mem_end) {
- /* RAM off the end - may be partially included */
- u64 delta = min(map[i].size, end - mem_end);
-
- map[i].size -= delta;
- end -= delta;
-
- extra_pages += PFN_DOWN(delta);
- /*
- * Set RAM below 4GB that is not for us to be unusable.
- * This prevents "System RAM" address space from being
- * used as potential resource for I/O address (happens
- * when 'allocate_resource' is called).
- */
- if (delta &&
- (xen_initial_domain() && end < 0x100000000ULL))
- e820_add_region(end, delta, E820_UNUSABLE);
+ /* Make sure the Xen-supplied memory map is well-ordered. */
+ sanitize_e820_map(map, memmap.nr_entries, &memmap.nr_entries);
+
+ max_pages = xen_get_max_pages();
+ if (max_pages > max_pfn)
+ extra_pages += max_pages - max_pfn;
+
+ /*
+ * Set P2M for all non-RAM pages and E820 gaps to be identity
+ * type PFNs. Any RAM pages that would be made inaccesible by
+ * this are first released.
+ */
+ xen_released_pages = xen_set_identity_and_release(
+ map, memmap.nr_entries, max_pfn);
+ extra_pages += xen_released_pages;
+
+ /*
+ * Clamp the amount of extra memory to a EXTRA_MEM_RATIO
+ * factor the base size. On non-highmem systems, the base
+ * size is the full initial memory allocation; on highmem it
+ * is limited to the max size of lowmem, so that it doesn't
+ * get completely filled.
+ *
+ * In principle there could be a problem in lowmem systems if
+ * the initial memory is also very large with respect to
+ * lowmem, but we won't try to deal with that here.
+ */
+ extra_pages = min(EXTRA_MEM_RATIO * min(max_pfn, PFN_DOWN(MAXMEM)),
+ extra_pages);
+
+ i = 0;
+ while (i < memmap.nr_entries) {
+ u64 addr = map[i].addr;
+ u64 size = map[i].size;
+ u32 type = map[i].type;
+
+ if (type == E820_RAM) {
+ if (addr < mem_end) {
+ size = min(size, mem_end - addr);
+ } else if (extra_pages) {
+ size = min(size, (u64)extra_pages * PAGE_SIZE);
+ extra_pages -= size / PAGE_SIZE;
+ xen_add_extra_mem(addr, size);
+ } else
+ type = E820_UNUSABLE;
}
- if (map[i].size > 0 && end > xen_extra_mem_start)
- xen_extra_mem_start = end;
+ xen_align_and_add_e820_region(addr, size, type);
- /* Add region if any remains */
- if (map[i].size > 0)
- e820_add_region(map[i].addr, map[i].size, map[i].type);
+ map[i].addr += size;
+ map[i].size -= size;
+ if (map[i].size == 0)
+ i++;
}
- /* Align the balloon area so that max_low_pfn does not get set
- * to be at the _end_ of the PCI gap at the far end (fee01000).
- * Note that xen_extra_mem_start gets set in the loop above to be
- * past the last E820 region. */
- if (xen_initial_domain() && (xen_extra_mem_start < (1ULL<<32)))
- xen_extra_mem_start = (1ULL<<32);
/*
* In domU, the ISA region is normal, usable memory, but we
* reserve ISA memory anyway because too many things poke
* about in there.
- *
- * In Dom0, the host E820 information can leave gaps in the
- * ISA range, which would cause us to release those pages. To
- * avoid this, we unconditionally reserve them here.
*/
e820_add_region(ISA_START_ADDRESS, ISA_END_ADDRESS - ISA_START_ADDRESS,
E820_RESERVED);
@@ -292,36 +305,6 @@ char * __init xen_memory_setup(void)
sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
- extra_pages += xen_return_unused_memory(xen_start_info->nr_pages, &e820);
-
- /*
- * Clamp the amount of extra memory to a EXTRA_MEM_RATIO
- * factor the base size. On non-highmem systems, the base
- * size is the full initial memory allocation; on highmem it
- * is limited to the max size of lowmem, so that it doesn't
- * get completely filled.
- *
- * In principle there could be a problem in lowmem systems if
- * the initial memory is also very large with respect to
- * lowmem, but we won't try to deal with that here.
- */
- extra_limit = min(EXTRA_MEM_RATIO * min(max_pfn, PFN_DOWN(MAXMEM)),
- max_pfn + extra_pages);
-
- if (extra_limit >= max_pfn)
- extra_pages = extra_limit - max_pfn;
- else
- extra_pages = 0;
-
- xen_add_extra_mem(extra_pages);
-
- /*
- * Set P2M for all non-RAM pages and E820 gaps to be identity
- * type PFNs. We supply it with the non-sanitized version
- * of the E820.
- */
- identity_pages = xen_set_identity(map_raw, memmap.nr_entries);
- printk(KERN_INFO "Set %ld page(s) to 1-1 mapping.\n", identity_pages);
return "Xen";
}
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index e79dbb95482b..041d4fe9dfe4 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -32,6 +32,7 @@
#include <xen/page.h>
#include <xen/events.h>
+#include <xen/hvc-console.h>
#include "xen-ops.h"
#include "mmu.h"
@@ -207,6 +208,15 @@ static void __init xen_smp_prepare_cpus(unsigned int max_cpus)
unsigned cpu;
unsigned int i;
+ if (skip_ioapic_setup) {
+ char *m = (max_cpus == 0) ?
+ "The nosmp parameter is incompatible with Xen; " \
+ "use Xen dom0_max_vcpus=1 parameter" :
+ "The noapic parameter is incompatible with Xen";
+
+ xen_raw_printk(m);
+ panic(m);
+ }
xen_init_lock_cpu(0);
smp_store_cpu_info(0);
@@ -522,7 +532,6 @@ static void __init xen_hvm_smp_prepare_cpus(unsigned int max_cpus)
WARN_ON(xen_smp_intr_init(0));
xen_init_lock_cpu(0);
- xen_init_spinlocks();
}
static int __cpuinit xen_hvm_cpu_up(unsigned int cpu)
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
index 5158c505bef9..163b4679556e 100644
--- a/arch/x86/xen/time.c
+++ b/arch/x86/xen/time.c
@@ -168,9 +168,10 @@ cycle_t xen_clocksource_read(void)
struct pvclock_vcpu_time_info *src;
cycle_t ret;
- src = &get_cpu_var(xen_vcpu)->time;
+ preempt_disable_notrace();
+ src = &__get_cpu_var(xen_vcpu)->time;
ret = pvclock_clocksource_read(src);
- put_cpu_var(xen_vcpu);
+ preempt_enable_notrace();
return ret;
}
diff --git a/arch/x86/xen/xen-asm_32.S b/arch/x86/xen/xen-asm_32.S
index 22a2093b5862..b040b0e518ca 100644
--- a/arch/x86/xen/xen-asm_32.S
+++ b/arch/x86/xen/xen-asm_32.S
@@ -113,11 +113,13 @@ xen_iret_start_crit:
/*
* If there's something pending, mask events again so we can
- * jump back into xen_hypervisor_callback
+ * jump back into xen_hypervisor_callback. Otherwise do not
+ * touch XEN_vcpu_info_mask.
*/
- sete XEN_vcpu_info_mask(%eax)
+ jne 1f
+ movb $1, XEN_vcpu_info_mask(%eax)
- popl %eax
+1: popl %eax
/*
* From this point on the registers are restored and the stack
diff --git a/arch/xtensa/include/asm/unistd.h b/arch/xtensa/include/asm/unistd.h
index a6f934f37f1a..798ee6d285a1 100644
--- a/arch/xtensa/include/asm/unistd.h
+++ b/arch/xtensa/include/asm/unistd.h
@@ -455,7 +455,7 @@ __SYSCALL(203, sys_reboot, 3)
#define __NR_quotactl 204
__SYSCALL(204, sys_quotactl, 4)
#define __NR_nfsservctl 205
-__SYSCALL(205, sys_nfsservctl, 3)
+__SYSCALL(205, sys_ni_syscall, 0)
#define __NR__sysctl 206
__SYSCALL(206, sys_sysctl, 1)
#define __NR_bdflush 207
diff --git a/arch/xtensa/platforms/iss/network.c b/arch/xtensa/platforms/iss/network.c
index f717e20d961b..7dde24456427 100644
--- a/arch/xtensa/platforms/iss/network.c
+++ b/arch/xtensa/platforms/iss/network.c
@@ -633,7 +633,7 @@ static const struct net_device_ops iss_netdev_ops = {
.ndo_set_mac_address = iss_net_set_mac,
//.ndo_do_ioctl = iss_net_ioctl,
.ndo_tx_timeout = iss_net_tx_timeout,
- .ndo_set_multicast_list = iss_net_set_multicast_list,
+ .ndo_set_rx_mode = iss_net_set_multicast_list,
};
static int iss_net_configure(int index, char *init)
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index bcaf16ee6ad1..b596e54ddd71 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -785,10 +785,10 @@ static int blkio_policy_parse_and_set(char *buf,
{
char *s[4], *p, *major_s = NULL, *minor_s = NULL;
int ret;
- unsigned long major, minor, temp;
+ unsigned long major, minor;
int i = 0;
dev_t dev;
- u64 bps, iops;
+ u64 temp;
memset(s, 0, sizeof(s));
@@ -826,20 +826,23 @@ static int blkio_policy_parse_and_set(char *buf,
dev = MKDEV(major, minor);
- ret = blkio_check_dev_num(dev);
+ ret = strict_strtoull(s[1], 10, &temp);
if (ret)
- return ret;
+ return -EINVAL;
- newpn->dev = dev;
+ /* For rule removal, do not check for device presence. */
+ if (temp) {
+ ret = blkio_check_dev_num(dev);
+ if (ret)
+ return ret;
+ }
- if (s[1] == NULL)
- return -EINVAL;
+ newpn->dev = dev;
switch (plid) {
case BLKIO_POLICY_PROP:
- ret = strict_strtoul(s[1], 10, &temp);
- if (ret || (temp < BLKIO_WEIGHT_MIN && temp > 0) ||
- temp > BLKIO_WEIGHT_MAX)
+ if ((temp < BLKIO_WEIGHT_MIN && temp > 0) ||
+ temp > BLKIO_WEIGHT_MAX)
return -EINVAL;
newpn->plid = plid;
@@ -850,26 +853,18 @@ static int blkio_policy_parse_and_set(char *buf,
switch(fileid) {
case BLKIO_THROTL_read_bps_device:
case BLKIO_THROTL_write_bps_device:
- ret = strict_strtoull(s[1], 10, &bps);
- if (ret)
- return -EINVAL;
-
newpn->plid = plid;
newpn->fileid = fileid;
- newpn->val.bps = bps;
+ newpn->val.bps = temp;
break;
case BLKIO_THROTL_read_iops_device:
case BLKIO_THROTL_write_iops_device:
- ret = strict_strtoull(s[1], 10, &iops);
- if (ret)
- return -EINVAL;
-
- if (iops > THROTL_IOPS_MAX)
+ if (temp > THROTL_IOPS_MAX)
return -EINVAL;
newpn->plid = plid;
newpn->fileid = fileid;
- newpn->val.iops = (unsigned int)iops;
+ newpn->val.iops = (unsigned int)temp;
break;
}
break;
diff --git a/block/blk-core.c b/block/blk-core.c
index 90e1ffdeb415..d34433ae7917 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -348,9 +348,10 @@ void blk_put_queue(struct request_queue *q)
EXPORT_SYMBOL(blk_put_queue);
/*
- * Note: If a driver supplied the queue lock, it should not zap that lock
- * unexpectedly as some queue cleanup components like elevator_exit() and
- * blk_throtl_exit() need queue lock.
+ * Note: If a driver supplied the queue lock, it is disconnected
+ * by this function. The actual state of the lock doesn't matter
+ * here as the request_queue isn't accessible after this point
+ * (QUEUE_FLAG_DEAD is set) and no other requests will be queued.
*/
void blk_cleanup_queue(struct request_queue *q)
{
@@ -367,10 +368,8 @@ void blk_cleanup_queue(struct request_queue *q)
queue_flag_set_unlocked(QUEUE_FLAG_DEAD, q);
mutex_unlock(&q->sysfs_lock);
- if (q->elevator)
- elevator_exit(q->elevator);
-
- blk_throtl_exit(q);
+ if (q->queue_lock != &q->__queue_lock)
+ q->queue_lock = &q->__queue_lock;
blk_put_queue(q);
}
@@ -1167,7 +1166,7 @@ static bool bio_attempt_front_merge(struct request_queue *q,
* true if merge was successful, otherwise false.
*/
static bool attempt_plug_merge(struct task_struct *tsk, struct request_queue *q,
- struct bio *bio)
+ struct bio *bio, unsigned int *request_count)
{
struct blk_plug *plug;
struct request *rq;
@@ -1176,10 +1175,13 @@ static bool attempt_plug_merge(struct task_struct *tsk, struct request_queue *q,
plug = tsk->plug;
if (!plug)
goto out;
+ *request_count = 0;
list_for_each_entry_reverse(rq, &plug->list, queuelist) {
int el_ret;
+ (*request_count)++;
+
if (rq->q != q)
continue;
@@ -1219,6 +1221,7 @@ static int __make_request(struct request_queue *q, struct bio *bio)
struct blk_plug *plug;
int el_ret, rw_flags, where = ELEVATOR_INSERT_SORT;
struct request *req;
+ unsigned int request_count = 0;
/*
* low level driver can indicate that it wants pages above a
@@ -1237,7 +1240,7 @@ static int __make_request(struct request_queue *q, struct bio *bio)
* Check if we can merge with the plugged list before grabbing
* any locks.
*/
- if (attempt_plug_merge(current, q, bio))
+ if (attempt_plug_merge(current, q, bio, &request_count))
goto out;
spin_lock_irq(q->queue_lock);
@@ -1302,11 +1305,10 @@ get_rq:
if (__rq->q != q)
plug->should_sort = 1;
}
+ if (request_count >= BLK_MAX_REQUEST_COUNT)
+ blk_flush_plug_list(plug, false);
list_add_tail(&req->queuelist, &plug->list);
- plug->count++;
drive_stat_acct(req, 1);
- if (plug->count >= BLK_MAX_REQUEST_COUNT)
- blk_flush_plug_list(plug, false);
} else {
spin_lock_irq(q->queue_lock);
add_acct_request(q, req, where);
@@ -2634,7 +2636,6 @@ void blk_start_plug(struct blk_plug *plug)
INIT_LIST_HEAD(&plug->list);
INIT_LIST_HEAD(&plug->cb_list);
plug->should_sort = 0;
- plug->count = 0;
/*
* If this is a nested plug, don't actually assign it. It will be
@@ -2718,7 +2719,6 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule)
return;
list_splice_init(&plug->list, &list);
- plug->count = 0;
if (plug->should_sort) {
list_sort(NULL, &list, plug_rq_cmp);
diff --git a/block/blk-softirq.c b/block/blk-softirq.c
index 58340d0cb23a..1366a89d8e66 100644
--- a/block/blk-softirq.c
+++ b/block/blk-softirq.c
@@ -115,7 +115,7 @@ void __blk_complete_request(struct request *req)
/*
* Select completion CPU
*/
- if (test_bit(QUEUE_FLAG_SAME_COMP, &q->queue_flags) && req->cpu != -1) {
+ if (req->cpu != -1) {
ccpu = req->cpu;
if (!test_bit(QUEUE_FLAG_SAME_FORCE, &q->queue_flags)) {
ccpu = blk_cpu_to_group(ccpu);
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index 0ee17b5e7fb6..60fda88c57f0 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -258,11 +258,13 @@ queue_rq_affinity_store(struct request_queue *q, const char *page, size_t count)
ret = queue_var_store(&val, page, count);
spin_lock_irq(q->queue_lock);
- if (val) {
+ if (val == 2) {
queue_flag_set(QUEUE_FLAG_SAME_COMP, q);
- if (val == 2)
- queue_flag_set(QUEUE_FLAG_SAME_FORCE, q);
- } else {
+ queue_flag_set(QUEUE_FLAG_SAME_FORCE, q);
+ } else if (val == 1) {
+ queue_flag_set(QUEUE_FLAG_SAME_COMP, q);
+ queue_flag_clear(QUEUE_FLAG_SAME_FORCE, q);
+ } else if (val == 0) {
queue_flag_clear(QUEUE_FLAG_SAME_COMP, q);
queue_flag_clear(QUEUE_FLAG_SAME_FORCE, q);
}
@@ -477,6 +479,11 @@ static void blk_release_queue(struct kobject *kobj)
blk_sync_queue(q);
+ if (q->elevator)
+ elevator_exit(q->elevator);
+
+ blk_throtl_exit(q);
+
if (rl->rq_pool)
mempool_destroy(rl->rq_pool);
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index a33bd4377c61..16ace89613bc 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -130,8 +130,8 @@ struct cfq_queue {
unsigned long slice_end;
long slice_resid;
- /* pending metadata requests */
- int meta_pending;
+ /* pending priority requests */
+ int prio_pending;
/* number of requests that are on the dispatch list or inside driver */
int dispatched;
@@ -684,8 +684,8 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2,
if (rq_is_sync(rq1) != rq_is_sync(rq2))
return rq_is_sync(rq1) ? rq1 : rq2;
- if ((rq1->cmd_flags ^ rq2->cmd_flags) & REQ_META)
- return rq1->cmd_flags & REQ_META ? rq1 : rq2;
+ if ((rq1->cmd_flags ^ rq2->cmd_flags) & REQ_PRIO)
+ return rq1->cmd_flags & REQ_PRIO ? rq1 : rq2;
s1 = blk_rq_pos(rq1);
s2 = blk_rq_pos(rq2);
@@ -1612,9 +1612,9 @@ static void cfq_remove_request(struct request *rq)
cfqq->cfqd->rq_queued--;
cfq_blkiocg_update_io_remove_stats(&(RQ_CFQG(rq))->blkg,
rq_data_dir(rq), rq_is_sync(rq));
- if (rq->cmd_flags & REQ_META) {
- WARN_ON(!cfqq->meta_pending);
- cfqq->meta_pending--;
+ if (rq->cmd_flags & REQ_PRIO) {
+ WARN_ON(!cfqq->prio_pending);
+ cfqq->prio_pending--;
}
}
@@ -3372,7 +3372,7 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
* So both queues are sync. Let the new request get disk time if
* it's a metadata request and the current queue is doing regular IO.
*/
- if ((rq->cmd_flags & REQ_META) && !cfqq->meta_pending)
+ if ((rq->cmd_flags & REQ_PRIO) && !cfqq->prio_pending)
return true;
/*
@@ -3439,8 +3439,8 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
struct cfq_io_context *cic = RQ_CIC(rq);
cfqd->rq_queued++;
- if (rq->cmd_flags & REQ_META)
- cfqq->meta_pending++;
+ if (rq->cmd_flags & REQ_PRIO)
+ cfqq->prio_pending++;
cfq_update_io_thinktime(cfqd, cfqq, cic);
cfq_update_io_seektime(cfqd, cfqq, rq);
diff --git a/crypto/ghash-generic.c b/crypto/ghash-generic.c
index be4425616931..7835b8fc94db 100644
--- a/crypto/ghash-generic.c
+++ b/crypto/ghash-generic.c
@@ -67,6 +67,9 @@ static int ghash_update(struct shash_desc *desc,
struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
u8 *dst = dctx->buffer;
+ if (!ctx->gf128)
+ return -ENOKEY;
+
if (dctx->bytes) {
int n = min(srclen, dctx->bytes);
u8 *pos = dst + (GHASH_BLOCK_SIZE - dctx->bytes);
@@ -119,6 +122,9 @@ static int ghash_final(struct shash_desc *desc, u8 *dst)
struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
u8 *buf = dctx->buffer;
+ if (!ctx->gf128)
+ return -ENOKEY;
+
ghash_flush(ctx, dctx);
memcpy(dst, buf, GHASH_BLOCK_SIZE);
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 95b9e7eefadc..6268167a1bb0 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -56,6 +56,8 @@ source "drivers/pps/Kconfig"
source "drivers/ptp/Kconfig"
+source "drivers/pinctrl/Kconfig"
+
source "drivers/gpio/Kconfig"
source "drivers/w1/Kconfig"
@@ -130,4 +132,6 @@ source "drivers/iommu/Kconfig"
source "drivers/virt/Kconfig"
+source "drivers/devfreq/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 7fa433a7030c..755eaf7a7285 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -5,6 +5,8 @@
# Rewritten to use lists instead of if-statements.
#
+# GPIO must come after pinctrl as gpios may need to mux pins etc
+obj-y += pinctrl/
obj-y += gpio/
obj-$(CONFIG_PCI) += pci/
obj-$(CONFIG_PARISC) += parisc/
@@ -127,3 +129,5 @@ obj-$(CONFIG_IOMMU_SUPPORT) += iommu/
# Virtualization drivers
obj-$(CONFIG_VIRT_DRIVERS) += virt/
+
+obj-$(CONFIG_PM_DEVFREQ) += devfreq/
diff --git a/drivers/acpi/acpica/acconfig.h b/drivers/acpi/acpica/acconfig.h
index bc533dde16c4..f895a244ca7e 100644
--- a/drivers/acpi/acpica/acconfig.h
+++ b/drivers/acpi/acpica/acconfig.h
@@ -121,7 +121,7 @@
/* Maximum sleep allowed via Sleep() operator */
-#define ACPI_MAX_SLEEP 20000 /* Two seconds */
+#define ACPI_MAX_SLEEP 2000 /* Two seconds */
/******************************************************************************
*
diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig
index c34aa51af4ee..e3f47872ec22 100644
--- a/drivers/acpi/apei/Kconfig
+++ b/drivers/acpi/apei/Kconfig
@@ -13,6 +13,7 @@ config ACPI_APEI_GHES
bool "APEI Generic Hardware Error Source"
depends on ACPI_APEI && X86
select ACPI_HED
+ select IRQ_WORK
select LLIST
select GENERIC_ALLOCATOR
help
diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c
index 8041248fce9b..61540360d5ce 100644
--- a/drivers/acpi/apei/apei-base.c
+++ b/drivers/acpi/apei/apei-base.c
@@ -618,7 +618,7 @@ int apei_osc_setup(void)
};
capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
- capbuf[OSC_SUPPORT_TYPE] = 0;
+ capbuf[OSC_SUPPORT_TYPE] = 1;
capbuf[OSC_CONTROL_TYPE] = 0;
if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 431ab11c8c1b..2e69e09ff03e 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -37,7 +37,7 @@
#include <linux/dmi.h>
#include <linux/moduleparam.h>
#include <linux/sched.h> /* need_resched() */
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
#include <linux/clockchips.h>
#include <linux/cpuidle.h>
#include <linux/irqflags.h>
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 3ed80b2ca907..0e46faef1d30 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -390,6 +390,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
},
{
.callback = init_nvs_nosave,
+ .ident = "Sony Vaio VGN-FW21E",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW21E"),
+ },
+ },
+ {
+ .callback = init_nvs_nosave,
.ident = "Sony Vaio VGN-SR11M",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
@@ -444,6 +452,22 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI Premium"),
},
},
+ {
+ .callback = init_nvs_nosave,
+ .ident = "Sony Vaio VGN-SR26GN_P",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR26GN_P"),
+ },
+ },
+ {
+ .callback = init_nvs_nosave,
+ .ident = "Sony Vaio VGN-FW520F",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW520F"),
+ },
+ },
{},
};
#endif /* CONFIG_SUSPEND */
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 93071417315f..956e9accb051 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -1134,8 +1134,9 @@ DPRINTK("doing direct send\n"); /* @@@ well, this doesn't work anyway */
skb_headlen(skb));
else
put_dma(tx->index,eni_dev->dma,&j,(unsigned long)
- skb_shinfo(skb)->frags[i].page + skb_shinfo(skb)->frags[i].page_offset,
- skb_shinfo(skb)->frags[i].size);
+ skb_frag_page(&skb_shinfo(skb)->frags[i]) +
+ skb_shinfo(skb)->frags[i].page_offset,
+ skb_frag_size(&skb_shinfo(skb)->frags[i]));
}
if (skb->len & 3)
put_dma(tx->index,eni_dev->dma,&j,zeroes,4-(skb->len & 3));
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index db06f34419cf..1c052127548c 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -3416,27 +3416,28 @@ init_card(struct atm_dev *dev)
size = sizeof(struct vc_map *) * card->tct_size;
IPRINTK("%s: allocate %d byte for VC map.\n", card->name, size);
- if (NULL == (card->vcs = vmalloc(size))) {
+ card->vcs = vzalloc(size);
+ if (!card->vcs) {
printk("%s: memory allocation failure.\n", card->name);
deinit_card(card);
return -1;
}
- memset(card->vcs, 0, size);
size = sizeof(struct vc_map *) * card->scd_size;
IPRINTK("%s: allocate %d byte for SCD to VC mapping.\n",
card->name, size);
- if (NULL == (card->scd2vc = vmalloc(size))) {
+ card->scd2vc = vzalloc(size);
+ if (!card->scd2vc) {
printk("%s: memory allocation failure.\n", card->name);
deinit_card(card);
return -1;
}
- memset(card->scd2vc, 0, size);
size = sizeof(struct tst_info) * (card->tst_size - 2);
IPRINTK("%s: allocate %d byte for TST to VC mapping.\n",
card->name, size);
- if (NULL == (card->soft_tst = vmalloc(size))) {
+ card->soft_tst = vmalloc(size);
+ if (!card->soft_tst) {
printk("%s: memory allocation failure.\n", card->name);
deinit_card(card);
return -1;
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index cb90f7a3e074..3d0c2b0fed9c 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -818,127 +818,152 @@ static void ia_hw_type(IADEV *iadev) {
}
-static void IaFrontEndIntr(IADEV *iadev) {
- volatile IA_SUNI *suni;
- volatile ia_mb25_t *mb25;
- volatile suni_pm7345_t *suni_pm7345;
-
- if(iadev->phy_type & FE_25MBIT_PHY) {
- mb25 = (ia_mb25_t*)iadev->phy;
- iadev->carrier_detect = Boolean(mb25->mb25_intr_status & MB25_IS_GSB);
- } else if (iadev->phy_type & FE_DS3_PHY) {
- suni_pm7345 = (suni_pm7345_t *)iadev->phy;
- /* clear FRMR interrupts */
- (void) suni_pm7345->suni_ds3_frm_intr_stat;
- iadev->carrier_detect =
- Boolean(!(suni_pm7345->suni_ds3_frm_stat & SUNI_DS3_LOSV));
- } else if (iadev->phy_type & FE_E3_PHY ) {
- suni_pm7345 = (suni_pm7345_t *)iadev->phy;
- (void) suni_pm7345->suni_e3_frm_maint_intr_ind;
- iadev->carrier_detect =
- Boolean(!(suni_pm7345->suni_e3_frm_fram_intr_ind_stat&SUNI_E3_LOS));
- }
- else {
- suni = (IA_SUNI *)iadev->phy;
- (void) suni->suni_rsop_status;
- iadev->carrier_detect = Boolean(!(suni->suni_rsop_status & SUNI_LOSV));
- }
- if (iadev->carrier_detect)
- printk("IA: SUNI carrier detected\n");
- else
- printk("IA: SUNI carrier lost signal\n");
- return;
+static u32 ia_phy_read32(struct iadev_priv *ia, unsigned int reg)
+{
+ return readl(ia->phy + (reg >> 2));
+}
+
+static void ia_phy_write32(struct iadev_priv *ia, unsigned int reg, u32 val)
+{
+ writel(val, ia->phy + (reg >> 2));
+}
+
+static void ia_frontend_intr(struct iadev_priv *iadev)
+{
+ u32 status;
+
+ if (iadev->phy_type & FE_25MBIT_PHY) {
+ status = ia_phy_read32(iadev, MB25_INTR_STATUS);
+ iadev->carrier_detect = (status & MB25_IS_GSB) ? 1 : 0;
+ } else if (iadev->phy_type & FE_DS3_PHY) {
+ ia_phy_read32(iadev, SUNI_DS3_FRM_INTR_STAT);
+ status = ia_phy_read32(iadev, SUNI_DS3_FRM_STAT);
+ iadev->carrier_detect = (status & SUNI_DS3_LOSV) ? 0 : 1;
+ } else if (iadev->phy_type & FE_E3_PHY) {
+ ia_phy_read32(iadev, SUNI_E3_FRM_MAINT_INTR_IND);
+ status = ia_phy_read32(iadev, SUNI_E3_FRM_FRAM_INTR_IND_STAT);
+ iadev->carrier_detect = (status & SUNI_E3_LOS) ? 0 : 1;
+ } else {
+ status = ia_phy_read32(iadev, SUNI_RSOP_STATUS);
+ iadev->carrier_detect = (status & SUNI_LOSV) ? 0 : 1;
+ }
+
+ printk(KERN_INFO "IA: SUNI carrier %s\n",
+ iadev->carrier_detect ? "detected" : "lost signal");
}
-static void ia_mb25_init (IADEV *iadev)
+static void ia_mb25_init(struct iadev_priv *iadev)
{
- volatile ia_mb25_t *mb25 = (ia_mb25_t*)iadev->phy;
#if 0
mb25->mb25_master_ctrl = MB25_MC_DRIC | MB25_MC_DREC | MB25_MC_ENABLED;
#endif
- mb25->mb25_master_ctrl = MB25_MC_DRIC | MB25_MC_DREC;
- mb25->mb25_diag_control = 0;
- /*
- * Initialize carrier detect state
- */
- iadev->carrier_detect = Boolean(mb25->mb25_intr_status & MB25_IS_GSB);
- return;
-}
+ ia_phy_write32(iadev, MB25_MASTER_CTRL, MB25_MC_DRIC | MB25_MC_DREC);
+ ia_phy_write32(iadev, MB25_DIAG_CONTROL, 0);
+
+ iadev->carrier_detect =
+ (ia_phy_read32(iadev, MB25_INTR_STATUS) & MB25_IS_GSB) ? 1 : 0;
+}
-static void ia_suni_pm7345_init (IADEV *iadev)
+struct ia_reg {
+ u16 reg;
+ u16 val;
+};
+
+static void ia_phy_write(struct iadev_priv *iadev,
+ const struct ia_reg *regs, int len)
{
- volatile suni_pm7345_t *suni_pm7345 = (suni_pm7345_t *)iadev->phy;
- if (iadev->phy_type & FE_DS3_PHY)
- {
- iadev->carrier_detect =
- Boolean(!(suni_pm7345->suni_ds3_frm_stat & SUNI_DS3_LOSV));
- suni_pm7345->suni_ds3_frm_intr_enbl = 0x17;
- suni_pm7345->suni_ds3_frm_cfg = 1;
- suni_pm7345->suni_ds3_tran_cfg = 1;
- suni_pm7345->suni_config = 0;
- suni_pm7345->suni_splr_cfg = 0;
- suni_pm7345->suni_splt_cfg = 0;
- }
- else
- {
- iadev->carrier_detect =
- Boolean(!(suni_pm7345->suni_e3_frm_fram_intr_ind_stat & SUNI_E3_LOS));
- suni_pm7345->suni_e3_frm_fram_options = 0x4;
- suni_pm7345->suni_e3_frm_maint_options = 0x20;
- suni_pm7345->suni_e3_frm_fram_intr_enbl = 0x1d;
- suni_pm7345->suni_e3_frm_maint_intr_enbl = 0x30;
- suni_pm7345->suni_e3_tran_stat_diag_options = 0x0;
- suni_pm7345->suni_e3_tran_fram_options = 0x1;
- suni_pm7345->suni_config = SUNI_PM7345_E3ENBL;
- suni_pm7345->suni_splr_cfg = 0x41;
- suni_pm7345->suni_splt_cfg = 0x41;
- }
- /*
- * Enable RSOP loss of signal interrupt.
- */
- suni_pm7345->suni_intr_enbl = 0x28;
-
- /*
- * Clear error counters
- */
- suni_pm7345->suni_id_reset = 0;
-
- /*
- * Clear "PMCTST" in master test register.
- */
- suni_pm7345->suni_master_test = 0;
-
- suni_pm7345->suni_rxcp_ctrl = 0x2c;
- suni_pm7345->suni_rxcp_fctrl = 0x81;
-
- suni_pm7345->suni_rxcp_idle_pat_h1 =
- suni_pm7345->suni_rxcp_idle_pat_h2 =
- suni_pm7345->suni_rxcp_idle_pat_h3 = 0;
- suni_pm7345->suni_rxcp_idle_pat_h4 = 1;
-
- suni_pm7345->suni_rxcp_idle_mask_h1 = 0xff;
- suni_pm7345->suni_rxcp_idle_mask_h2 = 0xff;
- suni_pm7345->suni_rxcp_idle_mask_h3 = 0xff;
- suni_pm7345->suni_rxcp_idle_mask_h4 = 0xfe;
-
- suni_pm7345->suni_rxcp_cell_pat_h1 =
- suni_pm7345->suni_rxcp_cell_pat_h2 =
- suni_pm7345->suni_rxcp_cell_pat_h3 = 0;
- suni_pm7345->suni_rxcp_cell_pat_h4 = 1;
-
- suni_pm7345->suni_rxcp_cell_mask_h1 =
- suni_pm7345->suni_rxcp_cell_mask_h2 =
- suni_pm7345->suni_rxcp_cell_mask_h3 =
- suni_pm7345->suni_rxcp_cell_mask_h4 = 0xff;
-
- suni_pm7345->suni_txcp_ctrl = 0xa4;
- suni_pm7345->suni_txcp_intr_en_sts = 0x10;
- suni_pm7345->suni_txcp_idle_pat_h5 = 0x55;
-
- suni_pm7345->suni_config &= ~(SUNI_PM7345_LLB |
- SUNI_PM7345_CLB |
- SUNI_PM7345_DLB |
- SUNI_PM7345_PLB);
+ while (len--) {
+ ia_phy_write32(iadev, regs->reg, regs->val);
+ regs++;
+ }
+}
+
+static void ia_suni_pm7345_init_ds3(struct iadev_priv *iadev)
+{
+ static const struct ia_reg suni_ds3_init [] = {
+ { SUNI_DS3_FRM_INTR_ENBL, 0x17 },
+ { SUNI_DS3_FRM_CFG, 0x01 },
+ { SUNI_DS3_TRAN_CFG, 0x01 },
+ { SUNI_CONFIG, 0 },
+ { SUNI_SPLR_CFG, 0 },
+ { SUNI_SPLT_CFG, 0 }
+ };
+ u32 status;
+
+ status = ia_phy_read32(iadev, SUNI_DS3_FRM_STAT);
+ iadev->carrier_detect = (status & SUNI_DS3_LOSV) ? 0 : 1;
+
+ ia_phy_write(iadev, suni_ds3_init, ARRAY_SIZE(suni_ds3_init));
+}
+
+static void ia_suni_pm7345_init_e3(struct iadev_priv *iadev)
+{
+ static const struct ia_reg suni_e3_init [] = {
+ { SUNI_E3_FRM_FRAM_OPTIONS, 0x04 },
+ { SUNI_E3_FRM_MAINT_OPTIONS, 0x20 },
+ { SUNI_E3_FRM_FRAM_INTR_ENBL, 0x1d },
+ { SUNI_E3_FRM_MAINT_INTR_ENBL, 0x30 },
+ { SUNI_E3_TRAN_STAT_DIAG_OPTIONS, 0 },
+ { SUNI_E3_TRAN_FRAM_OPTIONS, 0x01 },
+ { SUNI_CONFIG, SUNI_PM7345_E3ENBL },
+ { SUNI_SPLR_CFG, 0x41 },
+ { SUNI_SPLT_CFG, 0x41 }
+ };
+ u32 status;
+
+ status = ia_phy_read32(iadev, SUNI_E3_FRM_FRAM_INTR_IND_STAT);
+ iadev->carrier_detect = (status & SUNI_E3_LOS) ? 0 : 1;
+ ia_phy_write(iadev, suni_e3_init, ARRAY_SIZE(suni_e3_init));
+}
+
+static void ia_suni_pm7345_init(struct iadev_priv *iadev)
+{
+ static const struct ia_reg suni_init [] = {
+ /* Enable RSOP loss of signal interrupt. */
+ { SUNI_INTR_ENBL, 0x28 },
+ /* Clear error counters. */
+ { SUNI_ID_RESET, 0 },
+ /* Clear "PMCTST" in master test register. */
+ { SUNI_MASTER_TEST, 0 },
+
+ { SUNI_RXCP_CTRL, 0x2c },
+ { SUNI_RXCP_FCTRL, 0x81 },
+
+ { SUNI_RXCP_IDLE_PAT_H1, 0 },
+ { SUNI_RXCP_IDLE_PAT_H2, 0 },
+ { SUNI_RXCP_IDLE_PAT_H3, 0 },
+ { SUNI_RXCP_IDLE_PAT_H4, 0x01 },
+
+ { SUNI_RXCP_IDLE_MASK_H1, 0xff },
+ { SUNI_RXCP_IDLE_MASK_H2, 0xff },
+ { SUNI_RXCP_IDLE_MASK_H3, 0xff },
+ { SUNI_RXCP_IDLE_MASK_H4, 0xfe },
+
+ { SUNI_RXCP_CELL_PAT_H1, 0 },
+ { SUNI_RXCP_CELL_PAT_H2, 0 },
+ { SUNI_RXCP_CELL_PAT_H3, 0 },
+ { SUNI_RXCP_CELL_PAT_H4, 0x01 },
+
+ { SUNI_RXCP_CELL_MASK_H1, 0xff },
+ { SUNI_RXCP_CELL_MASK_H2, 0xff },
+ { SUNI_RXCP_CELL_MASK_H3, 0xff },
+ { SUNI_RXCP_CELL_MASK_H4, 0xff },
+
+ { SUNI_TXCP_CTRL, 0xa4 },
+ { SUNI_TXCP_INTR_EN_STS, 0x10 },
+ { SUNI_TXCP_IDLE_PAT_H5, 0x55 }
+ };
+
+ if (iadev->phy_type & FE_DS3_PHY)
+ ia_suni_pm7345_init_ds3(iadev);
+ else
+ ia_suni_pm7345_init_e3(iadev);
+
+ ia_phy_write(iadev, suni_init, ARRAY_SIZE(suni_init));
+
+ ia_phy_write32(iadev, SUNI_CONFIG, ia_phy_read32(iadev, SUNI_CONFIG) &
+ ~(SUNI_PM7345_LLB | SUNI_PM7345_CLB |
+ SUNI_PM7345_DLB | SUNI_PM7345_PLB));
#ifdef __SNMP__
suni_pm7345->suni_rxcp_intr_en_sts |= SUNI_OOCDE;
#endif /* __SNMP__ */
@@ -1425,10 +1450,10 @@ static int rx_init(struct atm_dev *dev)
iadev->dma + IPHASE5575_RX_LIST_ADDR);
IF_INIT(printk("Tx Dle list addr: 0x%p value: 0x%0x\n",
iadev->dma+IPHASE5575_TX_LIST_ADDR,
- *(u32*)(iadev->dma+IPHASE5575_TX_LIST_ADDR));
+ readl(iadev->dma + IPHASE5575_TX_LIST_ADDR));
printk("Rx Dle list addr: 0x%p value: 0x%0x\n",
iadev->dma+IPHASE5575_RX_LIST_ADDR,
- *(u32*)(iadev->dma+IPHASE5575_RX_LIST_ADDR));)
+ readl(iadev->dma + IPHASE5575_RX_LIST_ADDR));)
writew(0xffff, iadev->reass_reg+REASS_MASK_REG);
writew(0, iadev->reass_reg+MODE_REG);
@@ -2208,7 +2233,7 @@ static irqreturn_t ia_int(int irq, void *dev_id)
if (status & STAT_DLERINT)
{
/* Clear this bit by writing a 1 to it. */
- *(u_int *)(iadev->reg+IPHASE5575_BUS_STATUS_REG) = STAT_DLERINT;
+ writel(STAT_DLERINT, iadev->reg + IPHASE5575_BUS_STATUS_REG);
rx_dle_intr(dev);
}
if (status & STAT_SEGINT)
@@ -2219,13 +2244,13 @@ static irqreturn_t ia_int(int irq, void *dev_id)
}
if (status & STAT_DLETINT)
{
- *(u_int *)(iadev->reg+IPHASE5575_BUS_STATUS_REG) = STAT_DLETINT;
+ writel(STAT_DLETINT, iadev->reg + IPHASE5575_BUS_STATUS_REG);
tx_dle_intr(dev);
}
if (status & (STAT_FEINT | STAT_ERRINT | STAT_MARKINT))
{
if (status & STAT_FEINT)
- IaFrontEndIntr(iadev);
+ ia_frontend_intr(iadev);
}
}
return IRQ_RETVAL(handled);
@@ -2556,7 +2581,7 @@ static int __devinit ia_start(struct atm_dev *dev)
goto err_free_rx;
}
/* Get iadev->carrier_detect status */
- IaFrontEndIntr(iadev);
+ ia_frontend_intr(iadev);
}
return 0;
@@ -2827,7 +2852,7 @@ static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg)
case 0xb:
if (!capable(CAP_NET_ADMIN)) return -EPERM;
- IaFrontEndIntr(iadev);
+ ia_frontend_intr(iadev);
break;
case 0xa:
if (!capable(CAP_NET_ADMIN)) return -EPERM;
diff --git a/drivers/atm/iphase.h b/drivers/atm/iphase.h
index 077735e0e04b..6a0955e6d4fc 100644
--- a/drivers/atm/iphase.h
+++ b/drivers/atm/iphase.h
@@ -889,79 +889,71 @@ typedef struct ia_rtn_q {
} IARTN_Q;
#define SUNI_LOSV 0x04
-typedef struct {
- u32 suni_master_reset; /* SUNI Master Reset and Identity */
- u32 suni_master_config; /* SUNI Master Configuration */
- u32 suni_master_intr_stat; /* SUNI Master Interrupt Status */
- u32 suni_reserved1; /* Reserved */
- u32 suni_master_clk_monitor;/* SUNI Master Clock Monitor */
- u32 suni_master_control; /* SUNI Master Clock Monitor */
- u32 suni_reserved2[10]; /* Reserved */
-
- u32 suni_rsop_control; /* RSOP Control/Interrupt Enable */
- u32 suni_rsop_status; /* RSOP Status/Interrupt States */
- u32 suni_rsop_section_bip8l;/* RSOP Section BIP-8 LSB */
- u32 suni_rsop_section_bip8m;/* RSOP Section BIP-8 MSB */
-
- u32 suni_tsop_control; /* TSOP Control */
- u32 suni_tsop_diag; /* TSOP Disgnostics */
- u32 suni_tsop_reserved[2]; /* TSOP Reserved */
-
- u32 suni_rlop_cs; /* RLOP Control/Status */
- u32 suni_rlop_intr; /* RLOP Interrupt Enable/Status */
- u32 suni_rlop_line_bip24l; /* RLOP Line BIP-24 LSB */
- u32 suni_rlop_line_bip24; /* RLOP Line BIP-24 */
- u32 suni_rlop_line_bip24m; /* RLOP Line BIP-24 MSB */
- u32 suni_rlop_line_febel; /* RLOP Line FEBE LSB */
- u32 suni_rlop_line_febe; /* RLOP Line FEBE */
- u32 suni_rlop_line_febem; /* RLOP Line FEBE MSB */
-
- u32 suni_tlop_control; /* TLOP Control */
- u32 suni_tlop_disg; /* TLOP Disgnostics */
- u32 suni_tlop_reserved[14]; /* TLOP Reserved */
-
- u32 suni_rpop_cs; /* RPOP Status/Control */
- u32 suni_rpop_intr; /* RPOP Interrupt/Status */
- u32 suni_rpop_reserved; /* RPOP Reserved */
- u32 suni_rpop_intr_ena; /* RPOP Interrupt Enable */
- u32 suni_rpop_reserved1[3]; /* RPOP Reserved */
- u32 suni_rpop_path_sig; /* RPOP Path Signal Label */
- u32 suni_rpop_bip8l; /* RPOP Path BIP-8 LSB */
- u32 suni_rpop_bip8m; /* RPOP Path BIP-8 MSB */
- u32 suni_rpop_febel; /* RPOP Path FEBE LSB */
- u32 suni_rpop_febem; /* RPOP Path FEBE MSB */
- u32 suni_rpop_reserved2[4]; /* RPOP Reserved */
-
- u32 suni_tpop_cntrl_daig; /* TPOP Control/Disgnostics */
- u32 suni_tpop_pointer_ctrl; /* TPOP Pointer Control */
- u32 suni_tpop_sourcer_ctrl; /* TPOP Source Control */
- u32 suni_tpop_reserved1[2]; /* TPOP Reserved */
- u32 suni_tpop_arb_prtl; /* TPOP Arbitrary Pointer LSB */
- u32 suni_tpop_arb_prtm; /* TPOP Arbitrary Pointer MSB */
- u32 suni_tpop_reserved2; /* TPOP Reserved */
- u32 suni_tpop_path_sig; /* TPOP Path Signal Lable */
- u32 suni_tpop_path_status; /* TPOP Path Status */
- u32 suni_tpop_reserved3[6]; /* TPOP Reserved */
-
- u32 suni_racp_cs; /* RACP Control/Status */
- u32 suni_racp_intr; /* RACP Interrupt Enable/Status */
- u32 suni_racp_hdr_pattern; /* RACP Match Header Pattern */
- u32 suni_racp_hdr_mask; /* RACP Match Header Mask */
- u32 suni_racp_corr_hcs; /* RACP Correctable HCS Error Count */
- u32 suni_racp_uncorr_hcs; /* RACP Uncorrectable HCS Error Count */
- u32 suni_racp_reserved[10]; /* RACP Reserved */
-
- u32 suni_tacp_control; /* TACP Control */
- u32 suni_tacp_idle_hdr_pat; /* TACP Idle Cell Header Pattern */
- u32 suni_tacp_idle_pay_pay; /* TACP Idle Cell Payld Octet Pattern */
- u32 suni_tacp_reserved[5]; /* TACP Reserved */
-
- u32 suni_reserved3[24]; /* Reserved */
-
- u32 suni_master_test; /* SUNI Master Test */
- u32 suni_reserved_test; /* SUNI Reserved for Test */
-} IA_SUNI;
-
+enum ia_suni {
+ SUNI_MASTER_RESET = 0x000, /* SUNI Master Reset and Identity */
+ SUNI_MASTER_CONFIG = 0x004, /* SUNI Master Configuration */
+ SUNI_MASTER_INTR_STAT = 0x008, /* SUNI Master Interrupt Status */
+ SUNI_RESERVED1 = 0x00c, /* Reserved */
+ SUNI_MASTER_CLK_MONITOR = 0x010, /* SUNI Master Clock Monitor */
+ SUNI_MASTER_CONTROL = 0x014, /* SUNI Master Clock Monitor */
+ /* Reserved (10) */
+ SUNI_RSOP_CONTROL = 0x040, /* RSOP Control/Interrupt Enable */
+ SUNI_RSOP_STATUS = 0x044, /* RSOP Status/Interrupt States */
+ SUNI_RSOP_SECTION_BIP8L = 0x048, /* RSOP Section BIP-8 LSB */
+ SUNI_RSOP_SECTION_BIP8M = 0x04c, /* RSOP Section BIP-8 MSB */
+
+ SUNI_TSOP_CONTROL = 0x050, /* TSOP Control */
+ SUNI_TSOP_DIAG = 0x054, /* TSOP Disgnostics */
+ /* Reserved (2) */
+ SUNI_RLOP_CS = 0x060, /* RLOP Control/Status */
+ SUNI_RLOP_INTR = 0x064, /* RLOP Interrupt Enable/Status */
+ SUNI_RLOP_LINE_BIP24L = 0x068, /* RLOP Line BIP-24 LSB */
+ SUNI_RLOP_LINE_BIP24 = 0x06c, /* RLOP Line BIP-24 */
+ SUNI_RLOP_LINE_BIP24M = 0x070, /* RLOP Line BIP-24 MSB */
+ SUNI_RLOP_LINE_FEBEL = 0x074, /* RLOP Line FEBE LSB */
+ SUNI_RLOP_LINE_FEBE = 0x078, /* RLOP Line FEBE */
+ SUNI_RLOP_LINE_FEBEM = 0x07c, /* RLOP Line FEBE MSB */
+
+ SUNI_TLOP_CONTROL = 0x080, /* TLOP Control */
+ SUNI_TLOP_DISG = 0x084, /* TLOP Disgnostics */
+ /* Reserved (14) */
+ SUNI_RPOP_CS = 0x0c0, /* RPOP Status/Control */
+ SUNI_RPOP_INTR = 0x0c4, /* RPOP Interrupt/Status */
+ SUNI_RPOP_RESERVED = 0x0c8, /* RPOP Reserved */
+ SUNI_RPOP_INTR_ENA = 0x0cc, /* RPOP Interrupt Enable */
+ /* Reserved (3) */
+ SUNI_RPOP_PATH_SIG = 0x0dc, /* RPOP Path Signal Label */
+ SUNI_RPOP_BIP8L = 0x0e0, /* RPOP Path BIP-8 LSB */
+ SUNI_RPOP_BIP8M = 0x0e4, /* RPOP Path BIP-8 MSB */
+ SUNI_RPOP_FEBEL = 0x0e8, /* RPOP Path FEBE LSB */
+ SUNI_RPOP_FEBEM = 0x0ec, /* RPOP Path FEBE MSB */
+ /* Reserved (4) */
+ SUNI_TPOP_CNTRL_DAIG = 0x100, /* TPOP Control/Disgnostics */
+ SUNI_TPOP_POINTER_CTRL = 0x104, /* TPOP Pointer Control */
+ SUNI_TPOP_SOURCER_CTRL = 0x108, /* TPOP Source Control */
+ /* Reserved (2) */
+ SUNI_TPOP_ARB_PRTL = 0x114, /* TPOP Arbitrary Pointer LSB */
+ SUNI_TPOP_ARB_PRTM = 0x118, /* TPOP Arbitrary Pointer MSB */
+ SUNI_TPOP_RESERVED2 = 0x11c, /* TPOP Reserved */
+ SUNI_TPOP_PATH_SIG = 0x120, /* TPOP Path Signal Lable */
+ SUNI_TPOP_PATH_STATUS = 0x124, /* TPOP Path Status */
+ /* Reserved (6) */
+ SUNI_RACP_CS = 0x140, /* RACP Control/Status */
+ SUNI_RACP_INTR = 0x144, /* RACP Interrupt Enable/Status */
+ SUNI_RACP_HDR_PATTERN = 0x148, /* RACP Match Header Pattern */
+ SUNI_RACP_HDR_MASK = 0x14c, /* RACP Match Header Mask */
+ SUNI_RACP_CORR_HCS = 0x150, /* RACP Correctable HCS Error Count */
+ SUNI_RACP_UNCORR_HCS = 0x154, /* RACP Uncorrectable HCS Err Count */
+ /* Reserved (10) */
+ SUNI_TACP_CONTROL = 0x180, /* TACP Control */
+ SUNI_TACP_IDLE_HDR_PAT = 0x184, /* TACP Idle Cell Header Pattern */
+ SUNI_TACP_IDLE_PAY_PAY = 0x188, /* TACP Idle Cell Payld Octet Patrn */
+ /* Reserved (5) */
+ /* Reserved (24) */
+ /* FIXME: unused but name conflicts.
+ * SUNI_MASTER_TEST = 0x200, SUNI Master Test */
+ SUNI_RESERVED_TEST = 0x204 /* SUNI Reserved for Test */
+};
typedef struct _SUNI_STATS_
{
@@ -993,13 +985,11 @@ typedef struct _SUNI_STATS_
u32 racp_uchcs_count; // uncorrectable HCS error count
} IA_SUNI_STATS;
-typedef struct iadev_t {
+typedef struct iadev_priv {
/*-----base pointers into (i)chipSAR+ address space */
- u32 __iomem *phy; /* base pointer into phy(SUNI) */
- u32 __iomem *dma; /* base pointer into DMA control
- registers */
- u32 __iomem *reg; /* base pointer to SAR registers
- - Bus Interface Control Regs */
+ u32 __iomem *phy; /* Base pointer into phy (SUNI). */
+ u32 __iomem *dma; /* Base pointer into DMA control registers. */
+ u32 __iomem *reg; /* Base pointer to SAR registers. */
u32 __iomem *seg_reg; /* base pointer to segmentation engine
internal registers */
u32 __iomem *reass_reg; /* base pointer to reassemble engine
@@ -1071,14 +1061,14 @@ typedef struct iadev_t {
#define INPH_IA_VCC(v) ((struct ia_vcc *) (v)->dev_data)
/******************* IDT77105 25MB/s PHY DEFINE *****************************/
-typedef struct {
- u_int mb25_master_ctrl; /* Master control */
- u_int mb25_intr_status; /* Interrupt status */
- u_int mb25_diag_control; /* Diagnostic control */
- u_int mb25_led_hec; /* LED driver and HEC status/control */
- u_int mb25_low_byte_counter; /* Low byte counter */
- u_int mb25_high_byte_counter; /* High byte counter */
-} ia_mb25_t;
+enum ia_mb25 {
+ MB25_MASTER_CTRL = 0x00, /* Master control */
+ MB25_INTR_STATUS = 0x04, /* Interrupt status */
+ MB25_DIAG_CONTROL = 0x08, /* Diagnostic control */
+ MB25_LED_HEC = 0x0c, /* LED driver and HEC status/control */
+ MB25_LOW_BYTE_COUNTER = 0x10,
+ MB25_HIGH_BYTE_COUNTER = 0x14
+};
/*
* Master Control
@@ -1127,122 +1117,121 @@ typedef struct {
#define FE_E3_PHY 0x0090 /* E3 */
/*********************** SUNI_PM7345 PHY DEFINE HERE *********************/
-typedef struct _suni_pm7345_t
-{
- u_int suni_config; /* SUNI Configuration */
- u_int suni_intr_enbl; /* SUNI Interrupt Enable */
- u_int suni_intr_stat; /* SUNI Interrupt Status */
- u_int suni_control; /* SUNI Control */
- u_int suni_id_reset; /* SUNI Reset and Identity */
- u_int suni_data_link_ctrl;
- u_int suni_rboc_conf_intr_enbl;
- u_int suni_rboc_stat;
- u_int suni_ds3_frm_cfg;
- u_int suni_ds3_frm_intr_enbl;
- u_int suni_ds3_frm_intr_stat;
- u_int suni_ds3_frm_stat;
- u_int suni_rfdl_cfg;
- u_int suni_rfdl_enbl_stat;
- u_int suni_rfdl_stat;
- u_int suni_rfdl_data;
- u_int suni_pmon_chng;
- u_int suni_pmon_intr_enbl_stat;
- u_int suni_reserved1[0x13-0x11];
- u_int suni_pmon_lcv_evt_cnt_lsb;
- u_int suni_pmon_lcv_evt_cnt_msb;
- u_int suni_pmon_fbe_evt_cnt_lsb;
- u_int suni_pmon_fbe_evt_cnt_msb;
- u_int suni_pmon_sez_det_cnt_lsb;
- u_int suni_pmon_sez_det_cnt_msb;
- u_int suni_pmon_pe_evt_cnt_lsb;
- u_int suni_pmon_pe_evt_cnt_msb;
- u_int suni_pmon_ppe_evt_cnt_lsb;
- u_int suni_pmon_ppe_evt_cnt_msb;
- u_int suni_pmon_febe_evt_cnt_lsb;
- u_int suni_pmon_febe_evt_cnt_msb;
- u_int suni_ds3_tran_cfg;
- u_int suni_ds3_tran_diag;
- u_int suni_reserved2[0x23-0x21];
- u_int suni_xfdl_cfg;
- u_int suni_xfdl_intr_st;
- u_int suni_xfdl_xmit_data;
- u_int suni_xboc_code;
- u_int suni_splr_cfg;
- u_int suni_splr_intr_en;
- u_int suni_splr_intr_st;
- u_int suni_splr_status;
- u_int suni_splt_cfg;
- u_int suni_splt_cntl;
- u_int suni_splt_diag_g1;
- u_int suni_splt_f1;
- u_int suni_cppm_loc_meters;
- u_int suni_cppm_chng_of_cppm_perf_meter;
- u_int suni_cppm_b1_err_cnt_lsb;
- u_int suni_cppm_b1_err_cnt_msb;
- u_int suni_cppm_framing_err_cnt_lsb;
- u_int suni_cppm_framing_err_cnt_msb;
- u_int suni_cppm_febe_cnt_lsb;
- u_int suni_cppm_febe_cnt_msb;
- u_int suni_cppm_hcs_err_cnt_lsb;
- u_int suni_cppm_hcs_err_cnt_msb;
- u_int suni_cppm_idle_un_cell_cnt_lsb;
- u_int suni_cppm_idle_un_cell_cnt_msb;
- u_int suni_cppm_rcv_cell_cnt_lsb;
- u_int suni_cppm_rcv_cell_cnt_msb;
- u_int suni_cppm_xmit_cell_cnt_lsb;
- u_int suni_cppm_xmit_cell_cnt_msb;
- u_int suni_rxcp_ctrl;
- u_int suni_rxcp_fctrl;
- u_int suni_rxcp_intr_en_sts;
- u_int suni_rxcp_idle_pat_h1;
- u_int suni_rxcp_idle_pat_h2;
- u_int suni_rxcp_idle_pat_h3;
- u_int suni_rxcp_idle_pat_h4;
- u_int suni_rxcp_idle_mask_h1;
- u_int suni_rxcp_idle_mask_h2;
- u_int suni_rxcp_idle_mask_h3;
- u_int suni_rxcp_idle_mask_h4;
- u_int suni_rxcp_cell_pat_h1;
- u_int suni_rxcp_cell_pat_h2;
- u_int suni_rxcp_cell_pat_h3;
- u_int suni_rxcp_cell_pat_h4;
- u_int suni_rxcp_cell_mask_h1;
- u_int suni_rxcp_cell_mask_h2;
- u_int suni_rxcp_cell_mask_h3;
- u_int suni_rxcp_cell_mask_h4;
- u_int suni_rxcp_hcs_cs;
- u_int suni_rxcp_lcd_cnt_threshold;
- u_int suni_reserved3[0x57-0x54];
- u_int suni_txcp_ctrl;
- u_int suni_txcp_intr_en_sts;
- u_int suni_txcp_idle_pat_h1;
- u_int suni_txcp_idle_pat_h2;
- u_int suni_txcp_idle_pat_h3;
- u_int suni_txcp_idle_pat_h4;
- u_int suni_txcp_idle_pat_h5;
- u_int suni_txcp_idle_payload;
- u_int suni_e3_frm_fram_options;
- u_int suni_e3_frm_maint_options;
- u_int suni_e3_frm_fram_intr_enbl;
- u_int suni_e3_frm_fram_intr_ind_stat;
- u_int suni_e3_frm_maint_intr_enbl;
- u_int suni_e3_frm_maint_intr_ind;
- u_int suni_e3_frm_maint_stat;
- u_int suni_reserved4;
- u_int suni_e3_tran_fram_options;
- u_int suni_e3_tran_stat_diag_options;
- u_int suni_e3_tran_bip_8_err_mask;
- u_int suni_e3_tran_maint_adapt_options;
- u_int suni_ttb_ctrl;
- u_int suni_ttb_trail_trace_id_stat;
- u_int suni_ttb_ind_addr;
- u_int suni_ttb_ind_data;
- u_int suni_ttb_exp_payload_type;
- u_int suni_ttb_payload_type_ctrl_stat;
- u_int suni_pad5[0x7f-0x71];
- u_int suni_master_test;
- u_int suni_pad6[0xff-0x80];
-}suni_pm7345_t;
+enum suni_pm7345 {
+ SUNI_CONFIG = 0x000, /* SUNI Configuration */
+ SUNI_INTR_ENBL = 0x004, /* SUNI Interrupt Enable */
+ SUNI_INTR_STAT = 0x008, /* SUNI Interrupt Status */
+ SUNI_CONTROL = 0x00c, /* SUNI Control */
+ SUNI_ID_RESET = 0x010, /* SUNI Reset and Identity */
+ SUNI_DATA_LINK_CTRL = 0x014,
+ SUNI_RBOC_CONF_INTR_ENBL = 0x018,
+ SUNI_RBOC_STAT = 0x01c,
+ SUNI_DS3_FRM_CFG = 0x020,
+ SUNI_DS3_FRM_INTR_ENBL = 0x024,
+ SUNI_DS3_FRM_INTR_STAT = 0x028,
+ SUNI_DS3_FRM_STAT = 0x02c,
+ SUNI_RFDL_CFG = 0x030,
+ SUNI_RFDL_ENBL_STAT = 0x034,
+ SUNI_RFDL_STAT = 0x038,
+ SUNI_RFDL_DATA = 0x03c,
+ SUNI_PMON_CHNG = 0x040,
+ SUNI_PMON_INTR_ENBL_STAT = 0x044,
+ /* SUNI_RESERVED1 (0x13 - 0x11) */
+ SUNI_PMON_LCV_EVT_CNT_LSB = 0x050,
+ SUNI_PMON_LCV_EVT_CNT_MSB = 0x054,
+ SUNI_PMON_FBE_EVT_CNT_LSB = 0x058,
+ SUNI_PMON_FBE_EVT_CNT_MSB = 0x05c,
+ SUNI_PMON_SEZ_DET_CNT_LSB = 0x060,
+ SUNI_PMON_SEZ_DET_CNT_MSB = 0x064,
+ SUNI_PMON_PE_EVT_CNT_LSB = 0x068,
+ SUNI_PMON_PE_EVT_CNT_MSB = 0x06c,
+ SUNI_PMON_PPE_EVT_CNT_LSB = 0x070,
+ SUNI_PMON_PPE_EVT_CNT_MSB = 0x074,
+ SUNI_PMON_FEBE_EVT_CNT_LSB = 0x078,
+ SUNI_PMON_FEBE_EVT_CNT_MSB = 0x07c,
+ SUNI_DS3_TRAN_CFG = 0x080,
+ SUNI_DS3_TRAN_DIAG = 0x084,
+ /* SUNI_RESERVED2 (0x23 - 0x21) */
+ SUNI_XFDL_CFG = 0x090,
+ SUNI_XFDL_INTR_ST = 0x094,
+ SUNI_XFDL_XMIT_DATA = 0x098,
+ SUNI_XBOC_CODE = 0x09c,
+ SUNI_SPLR_CFG = 0x0a0,
+ SUNI_SPLR_INTR_EN = 0x0a4,
+ SUNI_SPLR_INTR_ST = 0x0a8,
+ SUNI_SPLR_STATUS = 0x0ac,
+ SUNI_SPLT_CFG = 0x0b0,
+ SUNI_SPLT_CNTL = 0x0b4,
+ SUNI_SPLT_DIAG_G1 = 0x0b8,
+ SUNI_SPLT_F1 = 0x0bc,
+ SUNI_CPPM_LOC_METERS = 0x0c0,
+ SUNI_CPPM_CHG_OF_CPPM_PERF_METR = 0x0c4,
+ SUNI_CPPM_B1_ERR_CNT_LSB = 0x0c8,
+ SUNI_CPPM_B1_ERR_CNT_MSB = 0x0cc,
+ SUNI_CPPM_FRAMING_ERR_CNT_LSB = 0x0d0,
+ SUNI_CPPM_FRAMING_ERR_CNT_MSB = 0x0d4,
+ SUNI_CPPM_FEBE_CNT_LSB = 0x0d8,
+ SUNI_CPPM_FEBE_CNT_MSB = 0x0dc,
+ SUNI_CPPM_HCS_ERR_CNT_LSB = 0x0e0,
+ SUNI_CPPM_HCS_ERR_CNT_MSB = 0x0e4,
+ SUNI_CPPM_IDLE_UN_CELL_CNT_LSB = 0x0e8,
+ SUNI_CPPM_IDLE_UN_CELL_CNT_MSB = 0x0ec,
+ SUNI_CPPM_RCV_CELL_CNT_LSB = 0x0f0,
+ SUNI_CPPM_RCV_CELL_CNT_MSB = 0x0f4,
+ SUNI_CPPM_XMIT_CELL_CNT_LSB = 0x0f8,
+ SUNI_CPPM_XMIT_CELL_CNT_MSB = 0x0fc,
+ SUNI_RXCP_CTRL = 0x100,
+ SUNI_RXCP_FCTRL = 0x104,
+ SUNI_RXCP_INTR_EN_STS = 0x108,
+ SUNI_RXCP_IDLE_PAT_H1 = 0x10c,
+ SUNI_RXCP_IDLE_PAT_H2 = 0x110,
+ SUNI_RXCP_IDLE_PAT_H3 = 0x114,
+ SUNI_RXCP_IDLE_PAT_H4 = 0x118,
+ SUNI_RXCP_IDLE_MASK_H1 = 0x11c,
+ SUNI_RXCP_IDLE_MASK_H2 = 0x120,
+ SUNI_RXCP_IDLE_MASK_H3 = 0x124,
+ SUNI_RXCP_IDLE_MASK_H4 = 0x128,
+ SUNI_RXCP_CELL_PAT_H1 = 0x12c,
+ SUNI_RXCP_CELL_PAT_H2 = 0x130,
+ SUNI_RXCP_CELL_PAT_H3 = 0x134,
+ SUNI_RXCP_CELL_PAT_H4 = 0x138,
+ SUNI_RXCP_CELL_MASK_H1 = 0x13c,
+ SUNI_RXCP_CELL_MASK_H2 = 0x140,
+ SUNI_RXCP_CELL_MASK_H3 = 0x144,
+ SUNI_RXCP_CELL_MASK_H4 = 0x148,
+ SUNI_RXCP_HCS_CS = 0x14c,
+ SUNI_RXCP_LCD_CNT_THRESHOLD = 0x150,
+ /* SUNI_RESERVED3 (0x57 - 0x54) */
+ SUNI_TXCP_CTRL = 0x160,
+ SUNI_TXCP_INTR_EN_STS = 0x164,
+ SUNI_TXCP_IDLE_PAT_H1 = 0x168,
+ SUNI_TXCP_IDLE_PAT_H2 = 0x16c,
+ SUNI_TXCP_IDLE_PAT_H3 = 0x170,
+ SUNI_TXCP_IDLE_PAT_H4 = 0x174,
+ SUNI_TXCP_IDLE_PAT_H5 = 0x178,
+ SUNI_TXCP_IDLE_PAYLOAD = 0x17c,
+ SUNI_E3_FRM_FRAM_OPTIONS = 0x180,
+ SUNI_E3_FRM_MAINT_OPTIONS = 0x184,
+ SUNI_E3_FRM_FRAM_INTR_ENBL = 0x188,
+ SUNI_E3_FRM_FRAM_INTR_IND_STAT = 0x18c,
+ SUNI_E3_FRM_MAINT_INTR_ENBL = 0x190,
+ SUNI_E3_FRM_MAINT_INTR_IND = 0x194,
+ SUNI_E3_FRM_MAINT_STAT = 0x198,
+ SUNI_RESERVED4 = 0x19c,
+ SUNI_E3_TRAN_FRAM_OPTIONS = 0x1a0,
+ SUNI_E3_TRAN_STAT_DIAG_OPTIONS = 0x1a4,
+ SUNI_E3_TRAN_BIP_8_ERR_MASK = 0x1a8,
+ SUNI_E3_TRAN_MAINT_ADAPT_OPTS = 0x1ac,
+ SUNI_TTB_CTRL = 0x1b0,
+ SUNI_TTB_TRAIL_TRACE_ID_STAT = 0x1b4,
+ SUNI_TTB_IND_ADDR = 0x1b8,
+ SUNI_TTB_IND_DATA = 0x1bc,
+ SUNI_TTB_EXP_PAYLOAD_TYPE = 0x1c0,
+ SUNI_TTB_PAYLOAD_TYPE_CTRL_STAT = 0x1c4,
+ /* SUNI_PAD5 (0x7f - 0x71) */
+ SUNI_MASTER_TEST = 0x200,
+ /* SUNI_PAD6 (0xff - 0x80) */
+};
#define SUNI_PM7345_T suni_pm7345_t
#define SUNI_PM7345 0x20 /* Suni chip type */
diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c
index e828c5487493..f5569699f31c 100644
--- a/drivers/atm/lanai.c
+++ b/drivers/atm/lanai.c
@@ -1457,10 +1457,9 @@ static int __devinit vcc_table_allocate(struct lanai_dev *lanai)
return (lanai->vccs == NULL) ? -ENOMEM : 0;
#else
int bytes = (lanai->num_vci) * sizeof(struct lanai_vcc *);
- lanai->vccs = (struct lanai_vcc **) vmalloc(bytes);
+ lanai->vccs = vzalloc(bytes);
if (unlikely(lanai->vccs == NULL))
return -ENOMEM;
- memset(lanai->vccs, 0, bytes);
return 0;
#endif
}
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 4f1df2e8fd74..b80d91cc8c3a 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -47,6 +47,18 @@ static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr,
return ret;
}
+static const void *class_attr_namespace(struct kobject *kobj,
+ const struct attribute *attr)
+{
+ struct class_attribute *class_attr = to_class_attr(attr);
+ struct subsys_private *cp = to_subsys_private(kobj);
+ const void *ns = NULL;
+
+ if (class_attr->namespace)
+ ns = class_attr->namespace(cp->class, class_attr);
+ return ns;
+}
+
static void class_release(struct kobject *kobj)
{
struct subsys_private *cp = to_subsys_private(kobj);
@@ -72,8 +84,9 @@ static const struct kobj_ns_type_operations *class_child_ns_type(struct kobject
}
static const struct sysfs_ops class_sysfs_ops = {
- .show = class_attr_show,
- .store = class_attr_store,
+ .show = class_attr_show,
+ .store = class_attr_store,
+ .namespace = class_attr_namespace,
};
static struct kobj_type class_ktype = {
diff --git a/drivers/base/core.c b/drivers/base/core.c
index bc8729d603a7..82c865452c70 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1764,8 +1764,8 @@ void device_shutdown(void)
#ifdef CONFIG_PRINTK
-static int __dev_printk(const char *level, const struct device *dev,
- struct va_format *vaf)
+int __dev_printk(const char *level, const struct device *dev,
+ struct va_format *vaf)
{
if (!dev)
return printk("%s(NULL device *): %pV", level, vaf);
@@ -1773,6 +1773,7 @@ static int __dev_printk(const char *level, const struct device *dev,
return printk("%s%s %s: %pV",
level, dev_driver_string(dev), dev_name(dev), vaf);
}
+EXPORT_SYMBOL(__dev_printk);
int dev_printk(const char *level, const struct device *dev,
const char *fmt, ...)
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 6658da743c3a..142e3d600f14 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -147,6 +147,9 @@ probe_failed:
printk(KERN_WARNING
"%s: probe of %s failed with error %d\n",
drv->name, dev_name(dev), ret);
+ } else {
+ pr_debug("%s: probe of %s rejects match %d\n",
+ drv->name, dev_name(dev), ret);
}
/*
* Ignore errors returned by ->probe so that the next driver can try
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index cf7a0c788052..65cd74832450 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -397,6 +397,7 @@ static int remove_nodes(struct device *dev,
static int release_nodes(struct device *dev, struct list_head *first,
struct list_head *end, unsigned long flags)
+ __releases(&dev->devres_lock)
{
LIST_HEAD(todo);
int cnt;
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index 33e1bed68fdd..a4760e095ff5 100644
--- a/drivers/base/devtmpfs.c
+++ b/drivers/base/devtmpfs.c
@@ -376,7 +376,7 @@ int devtmpfs_mount(const char *mntdir)
return err;
}
-static __initdata DECLARE_COMPLETION(setup_done);
+static DECLARE_COMPLETION(setup_done);
static int handle(const char *name, mode_t mode, struct device *dev)
{
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index bbb03e6f7255..06ed6b4e7df5 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -521,11 +521,6 @@ static int _request_firmware(const struct firmware **firmware_p,
if (!firmware_p)
return -EINVAL;
- if (WARN_ON(usermodehelper_is_disabled())) {
- dev_err(device, "firmware: %s will not be loaded\n", name);
- return -EBUSY;
- }
-
*firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
if (!firmware) {
dev_err(device, "%s: kmalloc(struct firmware) failed\n",
@@ -539,6 +534,12 @@ static int _request_firmware(const struct firmware **firmware_p,
return 0;
}
+ if (WARN_ON(usermodehelper_is_disabled())) {
+ dev_err(device, "firmware: %s will not be loaded\n", name);
+ retval = -EBUSY;
+ goto out;
+ }
+
if (uevent)
dev_dbg(device, "firmware: requesting %s\n", name);
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 2840ed4668c1..8272d92d22c0 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -224,13 +224,48 @@ int memory_isolate_notify(unsigned long val, void *v)
}
/*
+ * The probe routines leave the pages reserved, just as the bootmem code does.
+ * Make sure they're still that way.
+ */
+static bool pages_correctly_reserved(unsigned long start_pfn,
+ unsigned long nr_pages)
+{
+ int i, j;
+ struct page *page;
+ unsigned long pfn = start_pfn;
+
+ /*
+ * memmap between sections is not contiguous except with
+ * SPARSEMEM_VMEMMAP. We lookup the page once per section
+ * and assume memmap is contiguous within each section
+ */
+ for (i = 0; i < sections_per_block; i++, pfn += PAGES_PER_SECTION) {
+ if (WARN_ON_ONCE(!pfn_valid(pfn)))
+ return false;
+ page = pfn_to_page(pfn);
+
+ for (j = 0; j < PAGES_PER_SECTION; j++) {
+ if (PageReserved(page + j))
+ continue;
+
+ printk(KERN_WARNING "section number %ld page number %d "
+ "not reserved, was it already online?\n",
+ pfn_to_section_nr(pfn), j);
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/*
* MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is
* OK to have direct references to sparsemem variables in here.
*/
static int
memory_block_action(unsigned long phys_index, unsigned long action)
{
- int i;
unsigned long start_pfn, start_paddr;
unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block;
struct page *first_page;
@@ -238,26 +273,13 @@ memory_block_action(unsigned long phys_index, unsigned long action)
first_page = pfn_to_page(phys_index << PFN_SECTION_SHIFT);
- /*
- * The probe routines leave the pages reserved, just
- * as the bootmem code does. Make sure they're still
- * that way.
- */
- if (action == MEM_ONLINE) {
- for (i = 0; i < nr_pages; i++) {
- if (PageReserved(first_page+i))
- continue;
-
- printk(KERN_WARNING "section number %ld page number %d "
- "not reserved, was it already online?\n",
- phys_index, i);
- return -EBUSY;
- }
- }
-
switch (action) {
case MEM_ONLINE:
start_pfn = page_to_pfn(first_page);
+
+ if (!pages_correctly_reserved(start_pfn, nr_pages))
+ return -EBUSY;
+
ret = online_pages(start_pfn, nr_pages);
break;
case MEM_OFFLINE:
@@ -380,9 +402,13 @@ memory_probe_store(struct class *class, struct class_attribute *attr,
u64 phys_addr;
int nid;
int i, ret;
+ unsigned long pages_per_block = PAGES_PER_SECTION * sections_per_block;
phys_addr = simple_strtoull(buf, NULL, 0);
+ if (phys_addr & ((pages_per_block << PAGE_SHIFT) - 1))
+ return -EINVAL;
+
for (i = 0; i < sections_per_block; i++) {
nid = memory_add_physaddr_to_nid(phys_addr);
ret = add_memory(nid, phys_addr,
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 0cad9c7f6bb5..7a24895543e7 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -33,7 +33,7 @@ EXPORT_SYMBOL_GPL(platform_bus);
/**
* arch_setup_pdev_archdata - Allow manipulation of archdata before its used
- * @dev: platform device
+ * @pdev: platform device
*
* This is called before platform_device_add() such that any pdev_archdata may
* be setup before the platform_notifier is called. So if a user needs to
@@ -375,52 +375,64 @@ void platform_device_unregister(struct platform_device *pdev)
EXPORT_SYMBOL_GPL(platform_device_unregister);
/**
- * platform_device_register_resndata - add a platform-level device with
+ * platform_device_register_full - add a platform-level device with
* resources and platform-specific data
*
- * @parent: parent device for the device we're adding
- * @name: base name of the device we're adding
- * @id: instance id
- * @res: set of resources that needs to be allocated for the device
- * @num: number of resources
- * @data: platform specific data for this platform device
- * @size: size of platform specific data
+ * @pdevinfo: data used to create device
*
* Returns &struct platform_device pointer on success, or ERR_PTR() on error.
*/
-struct platform_device *platform_device_register_resndata(
- struct device *parent,
- const char *name, int id,
- const struct resource *res, unsigned int num,
- const void *data, size_t size)
+struct platform_device *platform_device_register_full(
+ struct platform_device_info *pdevinfo)
{
int ret = -ENOMEM;
struct platform_device *pdev;
- pdev = platform_device_alloc(name, id);
+ pdev = platform_device_alloc(pdevinfo->name, pdevinfo->id);
if (!pdev)
- goto err;
-
- pdev->dev.parent = parent;
+ goto err_alloc;
+
+ pdev->dev.parent = pdevinfo->parent;
+
+ if (pdevinfo->dma_mask) {
+ /*
+ * This memory isn't freed when the device is put,
+ * I don't have a nice idea for that though. Conceptually
+ * dma_mask in struct device should not be a pointer.
+ * See http://thread.gmane.org/gmane.linux.kernel.pci/9081
+ */
+ pdev->dev.dma_mask =
+ kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL);
+ if (!pdev->dev.dma_mask)
+ goto err;
+
+ *pdev->dev.dma_mask = pdevinfo->dma_mask;
+ pdev->dev.coherent_dma_mask = pdevinfo->dma_mask;
+ }
- ret = platform_device_add_resources(pdev, res, num);
+ ret = platform_device_add_resources(pdev,
+ pdevinfo->res, pdevinfo->num_res);
if (ret)
goto err;
- ret = platform_device_add_data(pdev, data, size);
+ ret = platform_device_add_data(pdev,
+ pdevinfo->data, pdevinfo->size_data);
if (ret)
goto err;
ret = platform_device_add(pdev);
if (ret) {
err:
+ kfree(pdev->dev.dma_mask);
+
+err_alloc:
platform_device_put(pdev);
return ERR_PTR(ret);
}
return pdev;
}
-EXPORT_SYMBOL_GPL(platform_device_register_resndata);
+EXPORT_SYMBOL_GPL(platform_device_register_full);
static int platform_drv_probe(struct device *_dev)
{
@@ -614,7 +626,7 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
return rc;
add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX,
- (pdev->id_entry) ? pdev->id_entry->name : pdev->name);
+ pdev->name);
return 0;
}
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 2639ae79a372..81676dd17900 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,4 +1,4 @@
-obj-$(CONFIG_PM) += sysfs.o generic_ops.o
+obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o
obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o
obj-$(CONFIG_PM_RUNTIME) += runtime.o
obj-$(CONFIG_PM_TRACE_RTC) += trace.o
@@ -6,4 +6,4 @@ obj-$(CONFIG_PM_OPP) += opp.o
obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o
obj-$(CONFIG_HAVE_CLK) += clock_ops.o
-ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG \ No newline at end of file
+ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c
index a846b2f95cfb..5f0f85d5c576 100644
--- a/drivers/base/power/clock_ops.c
+++ b/drivers/base/power/clock_ops.c
@@ -10,18 +10,13 @@
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/pm.h>
-#include <linux/pm_runtime.h>
+#include <linux/pm_clock.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/err.h>
#ifdef CONFIG_PM
-struct pm_clk_data {
- struct list_head clock_list;
- struct mutex lock;
-};
-
enum pce_status {
PCE_STATUS_NONE = 0,
PCE_STATUS_ACQUIRED,
@@ -36,9 +31,20 @@ struct pm_clock_entry {
enum pce_status status;
};
-static struct pm_clk_data *__to_pcd(struct device *dev)
+/**
+ * pm_clk_acquire - Acquire a device clock.
+ * @dev: Device whose clock is to be acquired.
+ * @ce: PM clock entry corresponding to the clock.
+ */
+static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce)
{
- return dev ? dev->power.subsys_data : NULL;
+ ce->clk = clk_get(dev, ce->con_id);
+ if (IS_ERR(ce->clk)) {
+ ce->status = PCE_STATUS_ERROR;
+ } else {
+ ce->status = PCE_STATUS_ACQUIRED;
+ dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id);
+ }
}
/**
@@ -51,10 +57,10 @@ static struct pm_clk_data *__to_pcd(struct device *dev)
*/
int pm_clk_add(struct device *dev, const char *con_id)
{
- struct pm_clk_data *pcd = __to_pcd(dev);
+ struct pm_subsys_data *psd = dev_to_psd(dev);
struct pm_clock_entry *ce;
- if (!pcd)
+ if (!psd)
return -EINVAL;
ce = kzalloc(sizeof(*ce), GFP_KERNEL);
@@ -73,26 +79,23 @@ int pm_clk_add(struct device *dev, const char *con_id)
}
}
- mutex_lock(&pcd->lock);
- list_add_tail(&ce->node, &pcd->clock_list);
- mutex_unlock(&pcd->lock);
+ pm_clk_acquire(dev, ce);
+
+ spin_lock_irq(&psd->lock);
+ list_add_tail(&ce->node, &psd->clock_list);
+ spin_unlock_irq(&psd->lock);
return 0;
}
/**
* __pm_clk_remove - Destroy PM clock entry.
* @ce: PM clock entry to destroy.
- *
- * This routine must be called under the mutex protecting the PM list of clocks
- * corresponding the the @ce's device.
*/
static void __pm_clk_remove(struct pm_clock_entry *ce)
{
if (!ce)
return;
- list_del(&ce->node);
-
if (ce->status < PCE_STATUS_ERROR) {
if (ce->status == PCE_STATUS_ENABLED)
clk_disable(ce->clk);
@@ -101,9 +104,7 @@ static void __pm_clk_remove(struct pm_clock_entry *ce)
clk_put(ce->clk);
}
- if (ce->con_id)
- kfree(ce->con_id);
-
+ kfree(ce->con_id);
kfree(ce);
}
@@ -117,50 +118,58 @@ static void __pm_clk_remove(struct pm_clock_entry *ce)
*/
void pm_clk_remove(struct device *dev, const char *con_id)
{
- struct pm_clk_data *pcd = __to_pcd(dev);
+ struct pm_subsys_data *psd = dev_to_psd(dev);
struct pm_clock_entry *ce;
- if (!pcd)
+ if (!psd)
return;
- mutex_lock(&pcd->lock);
+ spin_lock_irq(&psd->lock);
- list_for_each_entry(ce, &pcd->clock_list, node) {
- if (!con_id && !ce->con_id) {
- __pm_clk_remove(ce);
- break;
- } else if (!con_id || !ce->con_id) {
+ list_for_each_entry(ce, &psd->clock_list, node) {
+ if (!con_id && !ce->con_id)
+ goto remove;
+ else if (!con_id || !ce->con_id)
continue;
- } else if (!strcmp(con_id, ce->con_id)) {
- __pm_clk_remove(ce);
- break;
- }
+ else if (!strcmp(con_id, ce->con_id))
+ goto remove;
}
- mutex_unlock(&pcd->lock);
+ spin_unlock_irq(&psd->lock);
+ return;
+
+ remove:
+ list_del(&ce->node);
+ spin_unlock_irq(&psd->lock);
+
+ __pm_clk_remove(ce);
}
/**
* pm_clk_init - Initialize a device's list of power management clocks.
* @dev: Device to initialize the list of PM clocks for.
*
- * Allocate a struct pm_clk_data object, initialize its lock member and
- * make the @dev's power.subsys_data field point to it.
+ * Initialize the lock and clock_list members of the device's pm_subsys_data
+ * object.
*/
-int pm_clk_init(struct device *dev)
+void pm_clk_init(struct device *dev)
{
- struct pm_clk_data *pcd;
-
- pcd = kzalloc(sizeof(*pcd), GFP_KERNEL);
- if (!pcd) {
- dev_err(dev, "Not enough memory for PM clock data.\n");
- return -ENOMEM;
- }
+ struct pm_subsys_data *psd = dev_to_psd(dev);
+ if (psd)
+ INIT_LIST_HEAD(&psd->clock_list);
+}
- INIT_LIST_HEAD(&pcd->clock_list);
- mutex_init(&pcd->lock);
- dev->power.subsys_data = pcd;
- return 0;
+/**
+ * pm_clk_create - Create and initialize a device's list of PM clocks.
+ * @dev: Device to create and initialize the list of PM clocks for.
+ *
+ * Allocate a struct pm_subsys_data object, initialize its lock and clock_list
+ * members and make the @dev's power.subsys_data field point to it.
+ */
+int pm_clk_create(struct device *dev)
+{
+ int ret = dev_pm_get_subsys_data(dev);
+ return ret < 0 ? ret : 0;
}
/**
@@ -168,27 +177,33 @@ int pm_clk_init(struct device *dev)
* @dev: Device to destroy the list of PM clocks for.
*
* Clear the @dev's power.subsys_data field, remove the list of clock entries
- * from the struct pm_clk_data object pointed to by it before and free
+ * from the struct pm_subsys_data object pointed to by it before and free
* that object.
*/
void pm_clk_destroy(struct device *dev)
{
- struct pm_clk_data *pcd = __to_pcd(dev);
+ struct pm_subsys_data *psd = dev_to_psd(dev);
struct pm_clock_entry *ce, *c;
+ struct list_head list;
- if (!pcd)
+ if (!psd)
return;
- dev->power.subsys_data = NULL;
+ INIT_LIST_HEAD(&list);
- mutex_lock(&pcd->lock);
+ spin_lock_irq(&psd->lock);
- list_for_each_entry_safe_reverse(ce, c, &pcd->clock_list, node)
- __pm_clk_remove(ce);
+ list_for_each_entry_safe_reverse(ce, c, &psd->clock_list, node)
+ list_move(&ce->node, &list);
- mutex_unlock(&pcd->lock);
+ spin_unlock_irq(&psd->lock);
- kfree(pcd);
+ dev_pm_put_subsys_data(dev);
+
+ list_for_each_entry_safe_reverse(ce, c, &list, node) {
+ list_del(&ce->node);
+ __pm_clk_remove(ce);
+ }
}
#endif /* CONFIG_PM */
@@ -196,49 +211,30 @@ void pm_clk_destroy(struct device *dev)
#ifdef CONFIG_PM_RUNTIME
/**
- * pm_clk_acquire - Acquire a device clock.
- * @dev: Device whose clock is to be acquired.
- * @con_id: Connection ID of the clock.
- */
-static void pm_clk_acquire(struct device *dev,
- struct pm_clock_entry *ce)
-{
- ce->clk = clk_get(dev, ce->con_id);
- if (IS_ERR(ce->clk)) {
- ce->status = PCE_STATUS_ERROR;
- } else {
- ce->status = PCE_STATUS_ACQUIRED;
- dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id);
- }
-}
-
-/**
* pm_clk_suspend - Disable clocks in a device's PM clock list.
* @dev: Device to disable the clocks for.
*/
int pm_clk_suspend(struct device *dev)
{
- struct pm_clk_data *pcd = __to_pcd(dev);
+ struct pm_subsys_data *psd = dev_to_psd(dev);
struct pm_clock_entry *ce;
+ unsigned long flags;
dev_dbg(dev, "%s()\n", __func__);
- if (!pcd)
+ if (!psd)
return 0;
- mutex_lock(&pcd->lock);
-
- list_for_each_entry_reverse(ce, &pcd->clock_list, node) {
- if (ce->status == PCE_STATUS_NONE)
- pm_clk_acquire(dev, ce);
+ spin_lock_irqsave(&psd->lock, flags);
+ list_for_each_entry_reverse(ce, &psd->clock_list, node) {
if (ce->status < PCE_STATUS_ERROR) {
clk_disable(ce->clk);
ce->status = PCE_STATUS_ACQUIRED;
}
}
- mutex_unlock(&pcd->lock);
+ spin_unlock_irqrestore(&psd->lock, flags);
return 0;
}
@@ -249,27 +245,25 @@ int pm_clk_suspend(struct device *dev)
*/
int pm_clk_resume(struct device *dev)
{
- struct pm_clk_data *pcd = __to_pcd(dev);
+ struct pm_subsys_data *psd = dev_to_psd(dev);
struct pm_clock_entry *ce;
+ unsigned long flags;
dev_dbg(dev, "%s()\n", __func__);
- if (!pcd)
+ if (!psd)
return 0;
- mutex_lock(&pcd->lock);
-
- list_for_each_entry(ce, &pcd->clock_list, node) {
- if (ce->status == PCE_STATUS_NONE)
- pm_clk_acquire(dev, ce);
+ spin_lock_irqsave(&psd->lock, flags);
+ list_for_each_entry(ce, &psd->clock_list, node) {
if (ce->status < PCE_STATUS_ERROR) {
clk_enable(ce->clk);
ce->status = PCE_STATUS_ENABLED;
}
}
- mutex_unlock(&pcd->lock);
+ spin_unlock_irqrestore(&psd->lock, flags);
return 0;
}
@@ -307,7 +301,7 @@ static int pm_clk_notify(struct notifier_block *nb,
if (dev->pm_domain)
break;
- error = pm_clk_init(dev);
+ error = pm_clk_create(dev);
if (error)
break;
@@ -342,21 +336,22 @@ static int pm_clk_notify(struct notifier_block *nb,
*/
int pm_clk_suspend(struct device *dev)
{
- struct pm_clk_data *pcd = __to_pcd(dev);
+ struct pm_subsys_data *psd = dev_to_psd(dev);
struct pm_clock_entry *ce;
+ unsigned long flags;
dev_dbg(dev, "%s()\n", __func__);
/* If there is no driver, the clocks are already disabled. */
- if (!pcd || !dev->driver)
+ if (!psd || !dev->driver)
return 0;
- mutex_lock(&pcd->lock);
+ spin_lock_irqsave(&psd->lock, flags);
- list_for_each_entry_reverse(ce, &pcd->clock_list, node)
+ list_for_each_entry_reverse(ce, &psd->clock_list, node)
clk_disable(ce->clk);
- mutex_unlock(&pcd->lock);
+ spin_unlock_irqrestore(&psd->lock, flags);
return 0;
}
@@ -367,21 +362,22 @@ int pm_clk_suspend(struct device *dev)
*/
int pm_clk_resume(struct device *dev)
{
- struct pm_clk_data *pcd = __to_pcd(dev);
+ struct pm_subsys_data *psd = dev_to_psd(dev);
struct pm_clock_entry *ce;
+ unsigned long flags;
dev_dbg(dev, "%s()\n", __func__);
/* If there is no driver, the clocks should remain disabled. */
- if (!pcd || !dev->driver)
+ if (!psd || !dev->driver)
return 0;
- mutex_lock(&pcd->lock);
+ spin_lock_irqsave(&psd->lock, flags);
- list_for_each_entry(ce, &pcd->clock_list, node)
+ list_for_each_entry(ce, &psd->clock_list, node)
clk_enable(ce->clk);
- mutex_unlock(&pcd->lock);
+ spin_unlock_irqrestore(&psd->lock, flags);
return 0;
}
diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c
new file mode 100644
index 000000000000..29820c396182
--- /dev/null
+++ b/drivers/base/power/common.c
@@ -0,0 +1,86 @@
+/*
+ * drivers/base/power/common.c - Common device power management code.
+ *
+ * Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pm_clock.h>
+
+/**
+ * dev_pm_get_subsys_data - Create or refcount power.subsys_data for device.
+ * @dev: Device to handle.
+ *
+ * If power.subsys_data is NULL, point it to a new object, otherwise increment
+ * its reference counter. Return 1 if a new object has been created, otherwise
+ * return 0 or error code.
+ */
+int dev_pm_get_subsys_data(struct device *dev)
+{
+ struct pm_subsys_data *psd;
+ int ret = 0;
+
+ psd = kzalloc(sizeof(*psd), GFP_KERNEL);
+ if (!psd)
+ return -ENOMEM;
+
+ spin_lock_irq(&dev->power.lock);
+
+ if (dev->power.subsys_data) {
+ dev->power.subsys_data->refcount++;
+ } else {
+ spin_lock_init(&psd->lock);
+ psd->refcount = 1;
+ dev->power.subsys_data = psd;
+ pm_clk_init(dev);
+ psd = NULL;
+ ret = 1;
+ }
+
+ spin_unlock_irq(&dev->power.lock);
+
+ /* kfree() verifies that its argument is nonzero. */
+ kfree(psd);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_get_subsys_data);
+
+/**
+ * dev_pm_put_subsys_data - Drop reference to power.subsys_data.
+ * @dev: Device to handle.
+ *
+ * If the reference counter of power.subsys_data is zero after dropping the
+ * reference, power.subsys_data is removed. Return 1 if that happens or 0
+ * otherwise.
+ */
+int dev_pm_put_subsys_data(struct device *dev)
+{
+ struct pm_subsys_data *psd;
+ int ret = 0;
+
+ spin_lock_irq(&dev->power.lock);
+
+ psd = dev_to_psd(dev);
+ if (!psd) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (--psd->refcount == 0) {
+ dev->power.subsys_data = NULL;
+ kfree(psd);
+ ret = 1;
+ }
+
+ out:
+ spin_unlock_irq(&dev->power.lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_put_subsys_data);
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 1c374579407c..6790cf7eba5a 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -29,10 +29,20 @@ static struct generic_pm_domain *dev_to_genpd(struct device *dev)
return pd_to_genpd(dev->pm_domain);
}
-static void genpd_sd_counter_dec(struct generic_pm_domain *genpd)
+static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd)
{
- if (!WARN_ON(genpd->sd_count == 0))
- genpd->sd_count--;
+ bool ret = false;
+
+ if (!WARN_ON(atomic_read(&genpd->sd_count) == 0))
+ ret = !!atomic_dec_and_test(&genpd->sd_count);
+
+ return ret;
+}
+
+static void genpd_sd_counter_inc(struct generic_pm_domain *genpd)
+{
+ atomic_inc(&genpd->sd_count);
+ smp_mb__after_atomic_inc();
}
static void genpd_acquire_lock(struct generic_pm_domain *genpd)
@@ -71,81 +81,119 @@ static void genpd_set_active(struct generic_pm_domain *genpd)
}
/**
- * pm_genpd_poweron - Restore power to a given PM domain and its parents.
+ * __pm_genpd_poweron - Restore power to a given PM domain and its masters.
* @genpd: PM domain to power up.
*
- * Restore power to @genpd and all of its parents so that it is possible to
+ * Restore power to @genpd and all of its masters so that it is possible to
* resume a device belonging to it.
*/
-int pm_genpd_poweron(struct generic_pm_domain *genpd)
+int __pm_genpd_poweron(struct generic_pm_domain *genpd)
+ __releases(&genpd->lock) __acquires(&genpd->lock)
{
- struct generic_pm_domain *parent = genpd->parent;
+ struct gpd_link *link;
+ DEFINE_WAIT(wait);
int ret = 0;
- start:
- if (parent) {
- genpd_acquire_lock(parent);
- mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING);
- } else {
+ /* If the domain's master is being waited for, we have to wait too. */
+ for (;;) {
+ prepare_to_wait(&genpd->status_wait_queue, &wait,
+ TASK_UNINTERRUPTIBLE);
+ if (genpd->status != GPD_STATE_WAIT_MASTER)
+ break;
+ mutex_unlock(&genpd->lock);
+
+ schedule();
+
mutex_lock(&genpd->lock);
}
+ finish_wait(&genpd->status_wait_queue, &wait);
if (genpd->status == GPD_STATE_ACTIVE
|| (genpd->prepared_count > 0 && genpd->suspend_power_off))
- goto out;
+ return 0;
if (genpd->status != GPD_STATE_POWER_OFF) {
genpd_set_active(genpd);
- goto out;
+ return 0;
}
- if (parent && parent->status != GPD_STATE_ACTIVE) {
+ /*
+ * The list is guaranteed not to change while the loop below is being
+ * executed, unless one of the masters' .power_on() callbacks fiddles
+ * with it.
+ */
+ list_for_each_entry(link, &genpd->slave_links, slave_node) {
+ genpd_sd_counter_inc(link->master);
+ genpd->status = GPD_STATE_WAIT_MASTER;
+
mutex_unlock(&genpd->lock);
- genpd_release_lock(parent);
- ret = pm_genpd_poweron(parent);
- if (ret)
- return ret;
+ ret = pm_genpd_poweron(link->master);
- goto start;
+ mutex_lock(&genpd->lock);
+
+ /*
+ * The "wait for parent" status is guaranteed not to change
+ * while the master is powering on.
+ */
+ genpd->status = GPD_STATE_POWER_OFF;
+ wake_up_all(&genpd->status_wait_queue);
+ if (ret) {
+ genpd_sd_counter_dec(link->master);
+ goto err;
+ }
}
if (genpd->power_on) {
ret = genpd->power_on(genpd);
if (ret)
- goto out;
+ goto err;
}
genpd_set_active(genpd);
- if (parent)
- parent->sd_count++;
- out:
- mutex_unlock(&genpd->lock);
- if (parent)
- genpd_release_lock(parent);
+ return 0;
+
+ err:
+ list_for_each_entry_continue_reverse(link, &genpd->slave_links, slave_node)
+ genpd_sd_counter_dec(link->master);
return ret;
}
+/**
+ * pm_genpd_poweron - Restore power to a given PM domain and its masters.
+ * @genpd: PM domain to power up.
+ */
+int pm_genpd_poweron(struct generic_pm_domain *genpd)
+{
+ int ret;
+
+ mutex_lock(&genpd->lock);
+ ret = __pm_genpd_poweron(genpd);
+ mutex_unlock(&genpd->lock);
+ return ret;
+}
+
#endif /* CONFIG_PM */
#ifdef CONFIG_PM_RUNTIME
/**
* __pm_genpd_save_device - Save the pre-suspend state of a device.
- * @dle: Device list entry of the device to save the state of.
+ * @pdd: Domain data of the device to save the state of.
* @genpd: PM domain the device belongs to.
*/
-static int __pm_genpd_save_device(struct dev_list_entry *dle,
+static int __pm_genpd_save_device(struct pm_domain_data *pdd,
struct generic_pm_domain *genpd)
__releases(&genpd->lock) __acquires(&genpd->lock)
{
- struct device *dev = dle->dev;
+ struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
+ struct device *dev = pdd->dev;
struct device_driver *drv = dev->driver;
int ret = 0;
- if (dle->need_restore)
+ if (gpd_data->need_restore)
return 0;
mutex_unlock(&genpd->lock);
@@ -163,24 +211,25 @@ static int __pm_genpd_save_device(struct dev_list_entry *dle,
mutex_lock(&genpd->lock);
if (!ret)
- dle->need_restore = true;
+ gpd_data->need_restore = true;
return ret;
}
/**
* __pm_genpd_restore_device - Restore the pre-suspend state of a device.
- * @dle: Device list entry of the device to restore the state of.
+ * @pdd: Domain data of the device to restore the state of.
* @genpd: PM domain the device belongs to.
*/
-static void __pm_genpd_restore_device(struct dev_list_entry *dle,
+static void __pm_genpd_restore_device(struct pm_domain_data *pdd,
struct generic_pm_domain *genpd)
__releases(&genpd->lock) __acquires(&genpd->lock)
{
- struct device *dev = dle->dev;
+ struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
+ struct device *dev = pdd->dev;
struct device_driver *drv = dev->driver;
- if (!dle->need_restore)
+ if (!gpd_data->need_restore)
return;
mutex_unlock(&genpd->lock);
@@ -197,7 +246,7 @@ static void __pm_genpd_restore_device(struct dev_list_entry *dle,
mutex_lock(&genpd->lock);
- dle->need_restore = false;
+ gpd_data->need_restore = false;
}
/**
@@ -211,7 +260,8 @@ static void __pm_genpd_restore_device(struct dev_list_entry *dle,
*/
static bool genpd_abort_poweroff(struct generic_pm_domain *genpd)
{
- return genpd->status == GPD_STATE_ACTIVE || genpd->resume_count > 0;
+ return genpd->status == GPD_STATE_WAIT_MASTER
+ || genpd->status == GPD_STATE_ACTIVE || genpd->resume_count > 0;
}
/**
@@ -238,8 +288,8 @@ void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
__releases(&genpd->lock) __acquires(&genpd->lock)
{
- struct generic_pm_domain *parent;
- struct dev_list_entry *dle;
+ struct pm_domain_data *pdd;
+ struct gpd_link *link;
unsigned int not_suspended;
int ret = 0;
@@ -247,19 +297,22 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
/*
* Do not try to power off the domain in the following situations:
* (1) The domain is already in the "power off" state.
- * (2) System suspend is in progress.
+ * (2) The domain is waiting for its master to power up.
* (3) One of the domain's devices is being resumed right now.
+ * (4) System suspend is in progress.
*/
- if (genpd->status == GPD_STATE_POWER_OFF || genpd->prepared_count > 0
- || genpd->resume_count > 0)
+ if (genpd->status == GPD_STATE_POWER_OFF
+ || genpd->status == GPD_STATE_WAIT_MASTER
+ || genpd->resume_count > 0 || genpd->prepared_count > 0)
return 0;
- if (genpd->sd_count > 0)
+ if (atomic_read(&genpd->sd_count) > 0)
return -EBUSY;
not_suspended = 0;
- list_for_each_entry(dle, &genpd->dev_list, node)
- if (dle->dev->driver && !pm_runtime_suspended(dle->dev))
+ list_for_each_entry(pdd, &genpd->dev_list, list_node)
+ if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev)
+ || pdd->dev->power.irq_safe))
not_suspended++;
if (not_suspended > genpd->in_progress)
@@ -282,54 +335,50 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
genpd->status = GPD_STATE_BUSY;
genpd->poweroff_task = current;
- list_for_each_entry_reverse(dle, &genpd->dev_list, node) {
- ret = __pm_genpd_save_device(dle, genpd);
+ list_for_each_entry_reverse(pdd, &genpd->dev_list, list_node) {
+ ret = atomic_read(&genpd->sd_count) == 0 ?
+ __pm_genpd_save_device(pdd, genpd) : -EBUSY;
+
+ if (genpd_abort_poweroff(genpd))
+ goto out;
+
if (ret) {
genpd_set_active(genpd);
goto out;
}
- if (genpd_abort_poweroff(genpd))
- goto out;
-
if (genpd->status == GPD_STATE_REPEAT) {
genpd->poweroff_task = NULL;
goto start;
}
}
- parent = genpd->parent;
- if (parent) {
- mutex_unlock(&genpd->lock);
-
- genpd_acquire_lock(parent);
- mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING);
-
- if (genpd_abort_poweroff(genpd)) {
- genpd_release_lock(parent);
+ if (genpd->power_off) {
+ if (atomic_read(&genpd->sd_count) > 0) {
+ ret = -EBUSY;
goto out;
}
- }
- if (genpd->power_off) {
+ /*
+ * If sd_count > 0 at this point, one of the subdomains hasn't
+ * managed to call pm_genpd_poweron() for the master yet after
+ * incrementing it. In that case pm_genpd_poweron() will wait
+ * for us to drop the lock, so we can call .power_off() and let
+ * the pm_genpd_poweron() restore power for us (this shouldn't
+ * happen very often).
+ */
ret = genpd->power_off(genpd);
if (ret == -EBUSY) {
genpd_set_active(genpd);
- if (parent)
- genpd_release_lock(parent);
-
goto out;
}
}
genpd->status = GPD_STATE_POWER_OFF;
- if (parent) {
- genpd_sd_counter_dec(parent);
- if (parent->sd_count == 0)
- genpd_queue_power_off_work(parent);
-
- genpd_release_lock(parent);
+ list_for_each_entry(link, &genpd->slave_links, slave_node) {
+ genpd_sd_counter_dec(link->master);
+ genpd_queue_power_off_work(link->master);
}
out:
@@ -371,12 +420,21 @@ static int pm_genpd_runtime_suspend(struct device *dev)
if (IS_ERR(genpd))
return -EINVAL;
+ might_sleep_if(!genpd->dev_irq_safe);
+
if (genpd->stop_device) {
int ret = genpd->stop_device(dev);
if (ret)
return ret;
}
+ /*
+ * If power.irq_safe is set, this routine will be run with interrupts
+ * off, so it can't use mutexes.
+ */
+ if (dev->power.irq_safe)
+ return 0;
+
mutex_lock(&genpd->lock);
genpd->in_progress++;
pm_genpd_poweroff(genpd);
@@ -387,24 +445,6 @@ static int pm_genpd_runtime_suspend(struct device *dev)
}
/**
- * __pm_genpd_runtime_resume - Resume a device belonging to I/O PM domain.
- * @dev: Device to resume.
- * @genpd: PM domain the device belongs to.
- */
-static void __pm_genpd_runtime_resume(struct device *dev,
- struct generic_pm_domain *genpd)
-{
- struct dev_list_entry *dle;
-
- list_for_each_entry(dle, &genpd->dev_list, node) {
- if (dle->dev == dev) {
- __pm_genpd_restore_device(dle, genpd);
- break;
- }
- }
-}
-
-/**
* pm_genpd_runtime_resume - Resume a device belonging to I/O PM domain.
* @dev: Device to resume.
*
@@ -424,11 +464,18 @@ static int pm_genpd_runtime_resume(struct device *dev)
if (IS_ERR(genpd))
return -EINVAL;
- ret = pm_genpd_poweron(genpd);
- if (ret)
- return ret;
+ might_sleep_if(!genpd->dev_irq_safe);
+
+ /* If power.irq_safe, the PM domain is never powered off. */
+ if (dev->power.irq_safe)
+ goto out;
mutex_lock(&genpd->lock);
+ ret = __pm_genpd_poweron(genpd);
+ if (ret) {
+ mutex_unlock(&genpd->lock);
+ return ret;
+ }
genpd->status = GPD_STATE_BUSY;
genpd->resume_count++;
for (;;) {
@@ -448,12 +495,13 @@ static int pm_genpd_runtime_resume(struct device *dev)
mutex_lock(&genpd->lock);
}
finish_wait(&genpd->status_wait_queue, &wait);
- __pm_genpd_runtime_resume(dev, genpd);
+ __pm_genpd_restore_device(dev->power.subsys_data->domain_data, genpd);
genpd->resume_count--;
genpd_set_active(genpd);
wake_up_all(&genpd->status_wait_queue);
mutex_unlock(&genpd->lock);
+ out:
if (genpd->start_device)
genpd->start_device(dev);
@@ -478,8 +526,6 @@ void pm_genpd_poweroff_unused(void)
#else
static inline void genpd_power_off_work_fn(struct work_struct *work) {}
-static inline void __pm_genpd_runtime_resume(struct device *dev,
- struct generic_pm_domain *genpd) {}
#define pm_genpd_runtime_suspend NULL
#define pm_genpd_runtime_resume NULL
@@ -489,11 +535,11 @@ static inline void __pm_genpd_runtime_resume(struct device *dev,
#ifdef CONFIG_PM_SLEEP
/**
- * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its parents.
+ * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters.
* @genpd: PM domain to power off, if possible.
*
* Check if the given PM domain can be powered off (during system suspend or
- * hibernation) and do that if so. Also, in that case propagate to its parent.
+ * hibernation) and do that if so. Also, in that case propagate to its masters.
*
* This function is only called in "noirq" stages of system power transitions,
* so it need not acquire locks (all of the "noirq" callbacks are executed
@@ -501,21 +547,23 @@ static inline void __pm_genpd_runtime_resume(struct device *dev,
*/
static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd)
{
- struct generic_pm_domain *parent = genpd->parent;
+ struct gpd_link *link;
if (genpd->status == GPD_STATE_POWER_OFF)
return;
- if (genpd->suspended_count != genpd->device_count || genpd->sd_count > 0)
+ if (genpd->suspended_count != genpd->device_count
+ || atomic_read(&genpd->sd_count) > 0)
return;
if (genpd->power_off)
genpd->power_off(genpd);
genpd->status = GPD_STATE_POWER_OFF;
- if (parent) {
- genpd_sd_counter_dec(parent);
- pm_genpd_sync_poweroff(parent);
+
+ list_for_each_entry(link, &genpd->slave_links, slave_node) {
+ genpd_sd_counter_dec(link->master);
+ pm_genpd_sync_poweroff(link->master);
}
}
@@ -666,7 +714,7 @@ static int pm_genpd_suspend_noirq(struct device *dev)
if (ret)
return ret;
- if (device_may_wakeup(dev)
+ if (dev->power.wakeup_path
&& genpd->active_wakeup && genpd->active_wakeup(dev))
return 0;
@@ -890,7 +938,7 @@ static int pm_genpd_dev_poweroff_noirq(struct device *dev)
if (ret)
return ret;
- if (device_may_wakeup(dev)
+ if (dev->power.wakeup_path
&& genpd->active_wakeup && genpd->active_wakeup(dev))
return 0;
@@ -1034,7 +1082,8 @@ static void pm_genpd_complete(struct device *dev)
*/
int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev)
{
- struct dev_list_entry *dle;
+ struct generic_pm_domain_data *gpd_data;
+ struct pm_domain_data *pdd;
int ret = 0;
dev_dbg(dev, "%s()\n", __func__);
@@ -1054,26 +1103,26 @@ int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev)
goto out;
}
- list_for_each_entry(dle, &genpd->dev_list, node)
- if (dle->dev == dev) {
+ list_for_each_entry(pdd, &genpd->dev_list, list_node)
+ if (pdd->dev == dev) {
ret = -EINVAL;
goto out;
}
- dle = kzalloc(sizeof(*dle), GFP_KERNEL);
- if (!dle) {
+ gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL);
+ if (!gpd_data) {
ret = -ENOMEM;
goto out;
}
- dle->dev = dev;
- dle->need_restore = false;
- list_add_tail(&dle->node, &genpd->dev_list);
genpd->device_count++;
- spin_lock_irq(&dev->power.lock);
dev->pm_domain = &genpd->domain;
- spin_unlock_irq(&dev->power.lock);
+ dev_pm_get_subsys_data(dev);
+ dev->power.subsys_data->domain_data = &gpd_data->base;
+ gpd_data->base.dev = dev;
+ gpd_data->need_restore = false;
+ list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
out:
genpd_release_lock(genpd);
@@ -1089,7 +1138,7 @@ int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev)
int pm_genpd_remove_device(struct generic_pm_domain *genpd,
struct device *dev)
{
- struct dev_list_entry *dle;
+ struct pm_domain_data *pdd;
int ret = -EINVAL;
dev_dbg(dev, "%s()\n", __func__);
@@ -1104,17 +1153,17 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
goto out;
}
- list_for_each_entry(dle, &genpd->dev_list, node) {
- if (dle->dev != dev)
+ list_for_each_entry(pdd, &genpd->dev_list, list_node) {
+ if (pdd->dev != dev)
continue;
- spin_lock_irq(&dev->power.lock);
+ list_del_init(&pdd->list_node);
+ pdd->dev = NULL;
+ dev_pm_put_subsys_data(dev);
dev->pm_domain = NULL;
- spin_unlock_irq(&dev->power.lock);
+ kfree(to_gpd_data(pdd));
genpd->device_count--;
- list_del(&dle->node);
- kfree(dle);
ret = 0;
break;
@@ -1129,48 +1178,55 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
/**
* pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
* @genpd: Master PM domain to add the subdomain to.
- * @new_subdomain: Subdomain to be added.
+ * @subdomain: Subdomain to be added.
*/
int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
- struct generic_pm_domain *new_subdomain)
+ struct generic_pm_domain *subdomain)
{
- struct generic_pm_domain *subdomain;
+ struct gpd_link *link;
int ret = 0;
- if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(new_subdomain))
+ if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
return -EINVAL;
start:
genpd_acquire_lock(genpd);
- mutex_lock_nested(&new_subdomain->lock, SINGLE_DEPTH_NESTING);
+ mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
- if (new_subdomain->status != GPD_STATE_POWER_OFF
- && new_subdomain->status != GPD_STATE_ACTIVE) {
- mutex_unlock(&new_subdomain->lock);
+ if (subdomain->status != GPD_STATE_POWER_OFF
+ && subdomain->status != GPD_STATE_ACTIVE) {
+ mutex_unlock(&subdomain->lock);
genpd_release_lock(genpd);
goto start;
}
if (genpd->status == GPD_STATE_POWER_OFF
- && new_subdomain->status != GPD_STATE_POWER_OFF) {
+ && subdomain->status != GPD_STATE_POWER_OFF) {
ret = -EINVAL;
goto out;
}
- list_for_each_entry(subdomain, &genpd->sd_list, sd_node) {
- if (subdomain == new_subdomain) {
+ list_for_each_entry(link, &genpd->slave_links, slave_node) {
+ if (link->slave == subdomain && link->master == genpd) {
ret = -EINVAL;
goto out;
}
}
- list_add_tail(&new_subdomain->sd_node, &genpd->sd_list);
- new_subdomain->parent = genpd;
+ link = kzalloc(sizeof(*link), GFP_KERNEL);
+ if (!link) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ link->master = genpd;
+ list_add_tail(&link->master_node, &genpd->master_links);
+ link->slave = subdomain;
+ list_add_tail(&link->slave_node, &subdomain->slave_links);
if (subdomain->status != GPD_STATE_POWER_OFF)
- genpd->sd_count++;
+ genpd_sd_counter_inc(genpd);
out:
- mutex_unlock(&new_subdomain->lock);
+ mutex_unlock(&subdomain->lock);
genpd_release_lock(genpd);
return ret;
@@ -1179,22 +1235,22 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
/**
* pm_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain.
* @genpd: Master PM domain to remove the subdomain from.
- * @target: Subdomain to be removed.
+ * @subdomain: Subdomain to be removed.
*/
int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
- struct generic_pm_domain *target)
+ struct generic_pm_domain *subdomain)
{
- struct generic_pm_domain *subdomain;
+ struct gpd_link *link;
int ret = -EINVAL;
- if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(target))
+ if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
return -EINVAL;
start:
genpd_acquire_lock(genpd);
- list_for_each_entry(subdomain, &genpd->sd_list, sd_node) {
- if (subdomain != target)
+ list_for_each_entry(link, &genpd->master_links, master_node) {
+ if (link->slave != subdomain)
continue;
mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
@@ -1206,8 +1262,9 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
goto start;
}
- list_del(&subdomain->sd_node);
- subdomain->parent = NULL;
+ list_del(&link->master_node);
+ list_del(&link->slave_node);
+ kfree(link);
if (subdomain->status != GPD_STATE_POWER_OFF)
genpd_sd_counter_dec(genpd);
@@ -1234,15 +1291,14 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
if (IS_ERR_OR_NULL(genpd))
return;
- INIT_LIST_HEAD(&genpd->sd_node);
- genpd->parent = NULL;
+ INIT_LIST_HEAD(&genpd->master_links);
+ INIT_LIST_HEAD(&genpd->slave_links);
INIT_LIST_HEAD(&genpd->dev_list);
- INIT_LIST_HEAD(&genpd->sd_list);
mutex_init(&genpd->lock);
genpd->gov = gov;
INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn);
genpd->in_progress = 0;
- genpd->sd_count = 0;
+ atomic_set(&genpd->sd_count, 0);
genpd->status = is_off ? GPD_STATE_POWER_OFF : GPD_STATE_ACTIVE;
init_waitqueue_head(&genpd->status_wait_queue);
genpd->poweroff_task = NULL;
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index a85459126bc6..59f8ab235486 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -46,6 +46,7 @@ LIST_HEAD(dpm_prepared_list);
LIST_HEAD(dpm_suspended_list);
LIST_HEAD(dpm_noirq_list);
+struct suspend_stats suspend_stats;
static DEFINE_MUTEX(dpm_list_mtx);
static pm_message_t pm_transition;
@@ -65,6 +66,7 @@ void device_pm_init(struct device *dev)
spin_lock_init(&dev->power.lock);
pm_runtime_init(dev);
INIT_LIST_HEAD(&dev->power.entry);
+ dev->power.power_state = PMSG_INVALID;
}
/**
@@ -96,6 +98,7 @@ void device_pm_add(struct device *dev)
dev_warn(dev, "parent %s should not be sleeping\n",
dev_name(dev->parent));
list_add_tail(&dev->power.entry, &dpm_list);
+ dev_pm_qos_constraints_init(dev);
mutex_unlock(&dpm_list_mtx);
}
@@ -109,6 +112,7 @@ void device_pm_remove(struct device *dev)
dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
complete_all(&dev->power.completion);
mutex_lock(&dpm_list_mtx);
+ dev_pm_qos_constraints_destroy(dev);
list_del_init(&dev->power.entry);
mutex_unlock(&dpm_list_mtx);
device_wakeup_disable(dev);
@@ -464,8 +468,12 @@ void dpm_resume_noirq(pm_message_t state)
mutex_unlock(&dpm_list_mtx);
error = device_resume_noirq(dev, state);
- if (error)
+ if (error) {
+ suspend_stats.failed_resume_noirq++;
+ dpm_save_failed_step(SUSPEND_RESUME_NOIRQ);
+ dpm_save_failed_dev(dev_name(dev));
pm_dev_err(dev, state, " early", error);
+ }
mutex_lock(&dpm_list_mtx);
put_device(dev);
@@ -626,8 +634,12 @@ void dpm_resume(pm_message_t state)
mutex_unlock(&dpm_list_mtx);
error = device_resume(dev, state, false);
- if (error)
+ if (error) {
+ suspend_stats.failed_resume++;
+ dpm_save_failed_step(SUSPEND_RESUME);
+ dpm_save_failed_dev(dev_name(dev));
pm_dev_err(dev, state, "", error);
+ }
mutex_lock(&dpm_list_mtx);
}
@@ -802,6 +814,9 @@ int dpm_suspend_noirq(pm_message_t state)
mutex_lock(&dpm_list_mtx);
if (error) {
pm_dev_err(dev, state, " late", error);
+ suspend_stats.failed_suspend_noirq++;
+ dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ);
+ dpm_save_failed_dev(dev_name(dev));
put_device(dev);
break;
}
@@ -902,7 +917,11 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
}
End:
- dev->power.is_suspended = !error;
+ if (!error) {
+ dev->power.is_suspended = true;
+ if (dev->power.wakeup_path && dev->parent)
+ dev->parent->power.wakeup_path = true;
+ }
device_unlock(dev);
complete_all(&dev->power.completion);
@@ -923,8 +942,10 @@ static void async_suspend(void *data, async_cookie_t cookie)
int error;
error = __device_suspend(dev, pm_transition, true);
- if (error)
+ if (error) {
+ dpm_save_failed_dev(dev_name(dev));
pm_dev_err(dev, pm_transition, " async", error);
+ }
put_device(dev);
}
@@ -967,6 +988,7 @@ int dpm_suspend(pm_message_t state)
mutex_lock(&dpm_list_mtx);
if (error) {
pm_dev_err(dev, state, "", error);
+ dpm_save_failed_dev(dev_name(dev));
put_device(dev);
break;
}
@@ -980,7 +1002,10 @@ int dpm_suspend(pm_message_t state)
async_synchronize_full();
if (!error)
error = async_error;
- if (!error)
+ if (error) {
+ suspend_stats.failed_suspend++;
+ dpm_save_failed_step(SUSPEND_SUSPEND);
+ } else
dpm_show_time(starttime, state, NULL);
return error;
}
@@ -999,6 +1024,8 @@ static int device_prepare(struct device *dev, pm_message_t state)
device_lock(dev);
+ dev->power.wakeup_path = device_may_wakeup(dev);
+
if (dev->pm_domain) {
pm_dev_dbg(dev, state, "preparing power domain ");
if (dev->pm_domain->ops.prepare)
@@ -1088,7 +1115,10 @@ int dpm_suspend_start(pm_message_t state)
int error;
error = dpm_prepare(state);
- if (!error)
+ if (error) {
+ suspend_stats.failed_prepare++;
+ dpm_save_failed_step(SUSPEND_PREPARE);
+ } else
error = dpm_suspend(state);
return error;
}
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index b23de185cb04..434a6c011675 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -73,6 +73,7 @@ struct opp {
* RCU usage: nodes are not modified in the list of device_opp,
* however addition is possible and is secured by dev_opp_list_lock
* @dev: device pointer
+ * @head: notifier head to notify the OPP availability changes.
* @opp_list: list of opps
*
* This is an internal data structure maintaining the link to opps attached to
@@ -83,6 +84,7 @@ struct device_opp {
struct list_head node;
struct device *dev;
+ struct srcu_notifier_head head;
struct list_head opp_list;
};
@@ -404,6 +406,7 @@ int opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
}
dev_opp->dev = dev;
+ srcu_init_notifier_head(&dev_opp->head);
INIT_LIST_HEAD(&dev_opp->opp_list);
/* Secure the device list modification */
@@ -428,6 +431,11 @@ int opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
list_add_rcu(&new_opp->node, head);
mutex_unlock(&dev_opp_list_lock);
+ /*
+ * Notify the changes in the availability of the operable
+ * frequency/voltage list.
+ */
+ srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_ADD, new_opp);
return 0;
}
@@ -504,6 +512,14 @@ static int opp_set_availability(struct device *dev, unsigned long freq,
mutex_unlock(&dev_opp_list_lock);
synchronize_rcu();
+ /* Notify the change of the OPP availability */
+ if (availability_req)
+ srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_ENABLE,
+ new_opp);
+ else
+ srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_DISABLE,
+ new_opp);
+
/* clean up old opp */
new_opp = opp;
goto out;
@@ -643,3 +659,17 @@ void opp_free_cpufreq_table(struct device *dev,
*table = NULL;
}
#endif /* CONFIG_CPU_FREQ */
+
+/**
+ * opp_get_notifier() - find notifier_head of the device with opp
+ * @dev: device pointer used to lookup device OPPs.
+ */
+struct srcu_notifier_head *opp_get_notifier(struct device *dev)
+{
+ struct device_opp *dev_opp = find_device_opp(dev);
+
+ if (IS_ERR(dev_opp))
+ return ERR_PTR(PTR_ERR(dev_opp)); /* matching type */
+
+ return &dev_opp->head;
+}
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index f2a25f18fde7..9bf62323aaf3 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -1,3 +1,5 @@
+#include <linux/pm_qos.h>
+
#ifdef CONFIG_PM_RUNTIME
extern void pm_runtime_init(struct device *dev);
@@ -35,15 +37,21 @@ extern void device_pm_move_last(struct device *);
static inline void device_pm_init(struct device *dev)
{
spin_lock_init(&dev->power.lock);
+ dev->power.power_state = PMSG_INVALID;
pm_runtime_init(dev);
}
+static inline void device_pm_add(struct device *dev)
+{
+ dev_pm_qos_constraints_init(dev);
+}
+
static inline void device_pm_remove(struct device *dev)
{
+ dev_pm_qos_constraints_destroy(dev);
pm_runtime_remove(dev);
}
-static inline void device_pm_add(struct device *dev) {}
static inline void device_pm_move_before(struct device *deva,
struct device *devb) {}
static inline void device_pm_move_after(struct device *deva,
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
new file mode 100644
index 000000000000..91e061417382
--- /dev/null
+++ b/drivers/base/power/qos.c
@@ -0,0 +1,419 @@
+/*
+ * Devices PM QoS constraints management
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *
+ * This module exposes the interface to kernel space for specifying
+ * per-device PM QoS dependencies. It provides infrastructure for registration
+ * of:
+ *
+ * Dependents on a QoS value : register requests
+ * Watchers of QoS value : get notified when target QoS value changes
+ *
+ * This QoS design is best effort based. Dependents register their QoS needs.
+ * Watchers register to keep track of the current QoS needs of the system.
+ * Watchers can register different types of notification callbacks:
+ * . a per-device notification callback using the dev_pm_qos_*_notifier API.
+ * The notification chain data is stored in the per-device constraint
+ * data struct.
+ * . a system-wide notification callback using the dev_pm_qos_*_global_notifier
+ * API. The notification chain data is stored in a static variable.
+ *
+ * Note about the per-device constraint data struct allocation:
+ * . The per-device constraints data struct ptr is tored into the device
+ * dev_pm_info.
+ * . To minimize the data usage by the per-device constraints, the data struct
+ * is only allocated at the first call to dev_pm_qos_add_request.
+ * . The data is later free'd when the device is removed from the system.
+ * . A global mutex protects the constraints users from the data being
+ * allocated and free'd.
+ */
+
+#include <linux/pm_qos.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+
+
+static DEFINE_MUTEX(dev_pm_qos_mtx);
+
+static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers);
+
+/**
+ * dev_pm_qos_read_value - Get PM QoS constraint for a given device.
+ * @dev: Device to get the PM QoS constraint value for.
+ */
+s32 dev_pm_qos_read_value(struct device *dev)
+{
+ struct pm_qos_constraints *c;
+ unsigned long flags;
+ s32 ret = 0;
+
+ spin_lock_irqsave(&dev->power.lock, flags);
+
+ c = dev->power.constraints;
+ if (c)
+ ret = pm_qos_read_value(c);
+
+ spin_unlock_irqrestore(&dev->power.lock, flags);
+
+ return ret;
+}
+
+/*
+ * apply_constraint
+ * @req: constraint request to apply
+ * @action: action to perform add/update/remove, of type enum pm_qos_req_action
+ * @value: defines the qos request
+ *
+ * Internal function to update the constraints list using the PM QoS core
+ * code and if needed call the per-device and the global notification
+ * callbacks
+ */
+static int apply_constraint(struct dev_pm_qos_request *req,
+ enum pm_qos_req_action action, int value)
+{
+ int ret, curr_value;
+
+ ret = pm_qos_update_target(req->dev->power.constraints,
+ &req->node, action, value);
+
+ if (ret) {
+ /* Call the global callbacks if needed */
+ curr_value = pm_qos_read_value(req->dev->power.constraints);
+ blocking_notifier_call_chain(&dev_pm_notifiers,
+ (unsigned long)curr_value,
+ req);
+ }
+
+ return ret;
+}
+
+/*
+ * dev_pm_qos_constraints_allocate
+ * @dev: device to allocate data for
+ *
+ * Called at the first call to add_request, for constraint data allocation
+ * Must be called with the dev_pm_qos_mtx mutex held
+ */
+static int dev_pm_qos_constraints_allocate(struct device *dev)
+{
+ struct pm_qos_constraints *c;
+ struct blocking_notifier_head *n;
+
+ c = kzalloc(sizeof(*c), GFP_KERNEL);
+ if (!c)
+ return -ENOMEM;
+
+ n = kzalloc(sizeof(*n), GFP_KERNEL);
+ if (!n) {
+ kfree(c);
+ return -ENOMEM;
+ }
+ BLOCKING_INIT_NOTIFIER_HEAD(n);
+
+ plist_head_init(&c->list);
+ c->target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
+ c->default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
+ c->type = PM_QOS_MIN;
+ c->notifiers = n;
+
+ spin_lock_irq(&dev->power.lock);
+ dev->power.constraints = c;
+ spin_unlock_irq(&dev->power.lock);
+
+ return 0;
+}
+
+/**
+ * dev_pm_qos_constraints_init - Initalize device's PM QoS constraints pointer.
+ * @dev: target device
+ *
+ * Called from the device PM subsystem during device insertion under
+ * device_pm_lock().
+ */
+void dev_pm_qos_constraints_init(struct device *dev)
+{
+ mutex_lock(&dev_pm_qos_mtx);
+ dev->power.constraints = NULL;
+ dev->power.power_state = PMSG_ON;
+ mutex_unlock(&dev_pm_qos_mtx);
+}
+
+/**
+ * dev_pm_qos_constraints_destroy
+ * @dev: target device
+ *
+ * Called from the device PM subsystem on device removal under device_pm_lock().
+ */
+void dev_pm_qos_constraints_destroy(struct device *dev)
+{
+ struct dev_pm_qos_request *req, *tmp;
+ struct pm_qos_constraints *c;
+
+ mutex_lock(&dev_pm_qos_mtx);
+
+ dev->power.power_state = PMSG_INVALID;
+ c = dev->power.constraints;
+ if (!c)
+ goto out;
+
+ /* Flush the constraints list for the device */
+ plist_for_each_entry_safe(req, tmp, &c->list, node) {
+ /*
+ * Update constraints list and call the notification
+ * callbacks if needed
+ */
+ apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
+ memset(req, 0, sizeof(*req));
+ }
+
+ spin_lock_irq(&dev->power.lock);
+ dev->power.constraints = NULL;
+ spin_unlock_irq(&dev->power.lock);
+
+ kfree(c->notifiers);
+ kfree(c);
+
+ out:
+ mutex_unlock(&dev_pm_qos_mtx);
+}
+
+/**
+ * dev_pm_qos_add_request - inserts new qos request into the list
+ * @dev: target device for the constraint
+ * @req: pointer to a preallocated handle
+ * @value: defines the qos request
+ *
+ * This function inserts a new entry in the device constraints list of
+ * requested qos performance characteristics. It recomputes the aggregate
+ * QoS expectations of parameters and initializes the dev_pm_qos_request
+ * handle. Caller needs to save this handle for later use in updates and
+ * removal.
+ *
+ * Returns 1 if the aggregated constraint value has changed,
+ * 0 if the aggregated constraint value has not changed,
+ * -EINVAL in case of wrong parameters, -ENOMEM if there's not enough memory
+ * to allocate for data structures, -ENODEV if the device has just been removed
+ * from the system.
+ */
+int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
+ s32 value)
+{
+ int ret = 0;
+
+ if (!dev || !req) /*guard against callers passing in null */
+ return -EINVAL;
+
+ if (dev_pm_qos_request_active(req)) {
+ WARN(1, KERN_ERR "dev_pm_qos_add_request() called for already "
+ "added request\n");
+ return -EINVAL;
+ }
+
+ req->dev = dev;
+
+ mutex_lock(&dev_pm_qos_mtx);
+
+ if (!dev->power.constraints) {
+ if (dev->power.power_state.event == PM_EVENT_INVALID) {
+ /* The device has been removed from the system. */
+ req->dev = NULL;
+ ret = -ENODEV;
+ goto out;
+ } else {
+ /*
+ * Allocate the constraints data on the first call to
+ * add_request, i.e. only if the data is not already
+ * allocated and if the device has not been removed.
+ */
+ ret = dev_pm_qos_constraints_allocate(dev);
+ }
+ }
+
+ if (!ret)
+ ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
+
+ out:
+ mutex_unlock(&dev_pm_qos_mtx);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_qos_add_request);
+
+/**
+ * dev_pm_qos_update_request - modifies an existing qos request
+ * @req : handle to list element holding a dev_pm_qos request to use
+ * @new_value: defines the qos request
+ *
+ * Updates an existing dev PM qos request along with updating the
+ * target value.
+ *
+ * Attempts are made to make this code callable on hot code paths.
+ *
+ * Returns 1 if the aggregated constraint value has changed,
+ * 0 if the aggregated constraint value has not changed,
+ * -EINVAL in case of wrong parameters, -ENODEV if the device has been
+ * removed from the system
+ */
+int dev_pm_qos_update_request(struct dev_pm_qos_request *req,
+ s32 new_value)
+{
+ int ret = 0;
+
+ if (!req) /*guard against callers passing in null */
+ return -EINVAL;
+
+ if (!dev_pm_qos_request_active(req)) {
+ WARN(1, KERN_ERR "dev_pm_qos_update_request() called for "
+ "unknown object\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&dev_pm_qos_mtx);
+
+ if (req->dev->power.constraints) {
+ if (new_value != req->node.prio)
+ ret = apply_constraint(req, PM_QOS_UPDATE_REQ,
+ new_value);
+ } else {
+ /* Return if the device has been removed */
+ ret = -ENODEV;
+ }
+
+ mutex_unlock(&dev_pm_qos_mtx);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_qos_update_request);
+
+/**
+ * dev_pm_qos_remove_request - modifies an existing qos request
+ * @req: handle to request list element
+ *
+ * Will remove pm qos request from the list of constraints and
+ * recompute the current target value. Call this on slow code paths.
+ *
+ * Returns 1 if the aggregated constraint value has changed,
+ * 0 if the aggregated constraint value has not changed,
+ * -EINVAL in case of wrong parameters, -ENODEV if the device has been
+ * removed from the system
+ */
+int dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
+{
+ int ret = 0;
+
+ if (!req) /*guard against callers passing in null */
+ return -EINVAL;
+
+ if (!dev_pm_qos_request_active(req)) {
+ WARN(1, KERN_ERR "dev_pm_qos_remove_request() called for "
+ "unknown object\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&dev_pm_qos_mtx);
+
+ if (req->dev->power.constraints) {
+ ret = apply_constraint(req, PM_QOS_REMOVE_REQ,
+ PM_QOS_DEFAULT_VALUE);
+ memset(req, 0, sizeof(*req));
+ } else {
+ /* Return if the device has been removed */
+ ret = -ENODEV;
+ }
+
+ mutex_unlock(&dev_pm_qos_mtx);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
+
+/**
+ * dev_pm_qos_add_notifier - sets notification entry for changes to target value
+ * of per-device PM QoS constraints
+ *
+ * @dev: target device for the constraint
+ * @notifier: notifier block managed by caller.
+ *
+ * Will register the notifier into a notification chain that gets called
+ * upon changes to the target value for the device.
+ */
+int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
+{
+ int retval = 0;
+
+ mutex_lock(&dev_pm_qos_mtx);
+
+ /* Silently return if the constraints object is not present. */
+ if (dev->power.constraints)
+ retval = blocking_notifier_chain_register(
+ dev->power.constraints->notifiers,
+ notifier);
+
+ mutex_unlock(&dev_pm_qos_mtx);
+ return retval;
+}
+EXPORT_SYMBOL_GPL(dev_pm_qos_add_notifier);
+
+/**
+ * dev_pm_qos_remove_notifier - deletes notification for changes to target value
+ * of per-device PM QoS constraints
+ *
+ * @dev: target device for the constraint
+ * @notifier: notifier block to be removed.
+ *
+ * Will remove the notifier from the notification chain that gets called
+ * upon changes to the target value.
+ */
+int dev_pm_qos_remove_notifier(struct device *dev,
+ struct notifier_block *notifier)
+{
+ int retval = 0;
+
+ mutex_lock(&dev_pm_qos_mtx);
+
+ /* Silently return if the constraints object is not present. */
+ if (dev->power.constraints)
+ retval = blocking_notifier_chain_unregister(
+ dev->power.constraints->notifiers,
+ notifier);
+
+ mutex_unlock(&dev_pm_qos_mtx);
+ return retval;
+}
+EXPORT_SYMBOL_GPL(dev_pm_qos_remove_notifier);
+
+/**
+ * dev_pm_qos_add_global_notifier - sets notification entry for changes to
+ * target value of the PM QoS constraints for any device
+ *
+ * @notifier: notifier block managed by caller.
+ *
+ * Will register the notifier into a notification chain that gets called
+ * upon changes to the target value for any device.
+ */
+int dev_pm_qos_add_global_notifier(struct notifier_block *notifier)
+{
+ return blocking_notifier_chain_register(&dev_pm_notifiers, notifier);
+}
+EXPORT_SYMBOL_GPL(dev_pm_qos_add_global_notifier);
+
+/**
+ * dev_pm_qos_remove_global_notifier - deletes notification for changes to
+ * target value of PM QoS constraints for any device
+ *
+ * @notifier: notifier block to be removed.
+ *
+ * Will remove the notifier from the notification chain that gets called
+ * upon changes to the target value for any device.
+ */
+int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier)
+{
+ return blocking_notifier_chain_unregister(&dev_pm_notifiers, notifier);
+}
+EXPORT_SYMBOL_GPL(dev_pm_qos_remove_global_notifier);
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index acb3f83b8079..6bb3aafa85ed 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -9,6 +9,7 @@
#include <linux/sched.h>
#include <linux/pm_runtime.h>
+#include <trace/events/rpm.h>
#include "power.h"
static int rpm_resume(struct device *dev, int rpmflags);
@@ -155,6 +156,31 @@ static int rpm_check_suspend_allowed(struct device *dev)
}
/**
+ * __rpm_callback - Run a given runtime PM callback for a given device.
+ * @cb: Runtime PM callback to run.
+ * @dev: Device to run the callback for.
+ */
+static int __rpm_callback(int (*cb)(struct device *), struct device *dev)
+ __releases(&dev->power.lock) __acquires(&dev->power.lock)
+{
+ int retval;
+
+ if (dev->power.irq_safe)
+ spin_unlock(&dev->power.lock);
+ else
+ spin_unlock_irq(&dev->power.lock);
+
+ retval = cb(dev);
+
+ if (dev->power.irq_safe)
+ spin_lock(&dev->power.lock);
+ else
+ spin_lock_irq(&dev->power.lock);
+
+ return retval;
+}
+
+/**
* rpm_idle - Notify device bus type if the device can be suspended.
* @dev: Device to notify the bus type about.
* @rpmflags: Flag bits.
@@ -171,6 +197,7 @@ static int rpm_idle(struct device *dev, int rpmflags)
int (*callback)(struct device *);
int retval;
+ trace_rpm_idle(dev, rpmflags);
retval = rpm_check_suspend_allowed(dev);
if (retval < 0)
; /* Conditions are wrong. */
@@ -225,24 +252,14 @@ static int rpm_idle(struct device *dev, int rpmflags)
else
callback = NULL;
- if (callback) {
- if (dev->power.irq_safe)
- spin_unlock(&dev->power.lock);
- else
- spin_unlock_irq(&dev->power.lock);
-
- callback(dev);
-
- if (dev->power.irq_safe)
- spin_lock(&dev->power.lock);
- else
- spin_lock_irq(&dev->power.lock);
- }
+ if (callback)
+ __rpm_callback(callback, dev);
dev->power.idle_notification = false;
wake_up_all(&dev->power.wait_queue);
out:
+ trace_rpm_return_int(dev, _THIS_IP_, retval);
return retval;
}
@@ -252,22 +269,14 @@ static int rpm_idle(struct device *dev, int rpmflags)
* @dev: Device to run the callback for.
*/
static int rpm_callback(int (*cb)(struct device *), struct device *dev)
- __releases(&dev->power.lock) __acquires(&dev->power.lock)
{
int retval;
if (!cb)
return -ENOSYS;
- if (dev->power.irq_safe) {
- retval = cb(dev);
- } else {
- spin_unlock_irq(&dev->power.lock);
-
- retval = cb(dev);
+ retval = __rpm_callback(cb, dev);
- spin_lock_irq(&dev->power.lock);
- }
dev->power.runtime_error = retval;
return retval != -EACCES ? retval : -EIO;
}
@@ -277,14 +286,16 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev)
* @dev: Device to suspend.
* @rpmflags: Flag bits.
*
- * Check if the device's runtime PM status allows it to be suspended. If
- * another suspend has been started earlier, either return immediately or wait
- * for it to finish, depending on the RPM_NOWAIT and RPM_ASYNC flags. Cancel a
- * pending idle notification. If the RPM_ASYNC flag is set then queue a
- * suspend request; otherwise run the ->runtime_suspend() callback directly.
- * If a deferred resume was requested while the callback was running then carry
- * it out; otherwise send an idle notification for the device (if the suspend
- * failed) or for its parent (if the suspend succeeded).
+ * Check if the device's runtime PM status allows it to be suspended.
+ * Cancel a pending idle notification, autosuspend or suspend. If
+ * another suspend has been started earlier, either return immediately
+ * or wait for it to finish, depending on the RPM_NOWAIT and RPM_ASYNC
+ * flags. If the RPM_ASYNC flag is set then queue a suspend request;
+ * otherwise run the ->runtime_suspend() callback directly. When
+ * ->runtime_suspend succeeded, if a deferred resume was requested while
+ * the callback was running then carry it out, otherwise send an idle
+ * notification for its parent (if the suspend succeeded and both
+ * ignore_children of parent->power and irq_safe of dev->power are not set).
*
* This function must be called under dev->power.lock with interrupts disabled.
*/
@@ -295,7 +306,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
struct device *parent = NULL;
int retval;
- dev_dbg(dev, "%s flags 0x%x\n", __func__, rpmflags);
+ trace_rpm_suspend(dev, rpmflags);
repeat:
retval = rpm_check_suspend_allowed(dev);
@@ -347,6 +358,15 @@ static int rpm_suspend(struct device *dev, int rpmflags)
goto out;
}
+ if (dev->power.irq_safe) {
+ spin_unlock(&dev->power.lock);
+
+ cpu_relax();
+
+ spin_lock(&dev->power.lock);
+ goto repeat;
+ }
+
/* Wait for the other suspend running in parallel with us. */
for (;;) {
prepare_to_wait(&dev->power.wait_queue, &wait,
@@ -400,15 +420,16 @@ static int rpm_suspend(struct device *dev, int rpmflags)
dev->power.runtime_error = 0;
else
pm_runtime_cancel_pending(dev);
- } else {
+ wake_up_all(&dev->power.wait_queue);
+ goto out;
+ }
no_callback:
- __update_runtime_status(dev, RPM_SUSPENDED);
- pm_runtime_deactivate_timer(dev);
+ __update_runtime_status(dev, RPM_SUSPENDED);
+ pm_runtime_deactivate_timer(dev);
- if (dev->parent) {
- parent = dev->parent;
- atomic_add_unless(&parent->power.child_count, -1, 0);
- }
+ if (dev->parent) {
+ parent = dev->parent;
+ atomic_add_unless(&parent->power.child_count, -1, 0);
}
wake_up_all(&dev->power.wait_queue);
@@ -430,7 +451,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
}
out:
- dev_dbg(dev, "%s returns %d\n", __func__, retval);
+ trace_rpm_return_int(dev, _THIS_IP_, retval);
return retval;
}
@@ -459,7 +480,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
struct device *parent = NULL;
int retval = 0;
- dev_dbg(dev, "%s flags 0x%x\n", __func__, rpmflags);
+ trace_rpm_resume(dev, rpmflags);
repeat:
if (dev->power.runtime_error)
@@ -496,6 +517,15 @@ static int rpm_resume(struct device *dev, int rpmflags)
goto out;
}
+ if (dev->power.irq_safe) {
+ spin_unlock(&dev->power.lock);
+
+ cpu_relax();
+
+ spin_lock(&dev->power.lock);
+ goto repeat;
+ }
+
/* Wait for the operation carried out in parallel with us. */
for (;;) {
prepare_to_wait(&dev->power.wait_queue, &wait,
@@ -615,7 +645,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
spin_lock_irq(&dev->power.lock);
}
- dev_dbg(dev, "%s returns %d\n", __func__, retval);
+ trace_rpm_return_int(dev, _THIS_IP_, retval);
return retval;
}
@@ -732,13 +762,16 @@ EXPORT_SYMBOL_GPL(pm_schedule_suspend);
* return immediately if it is larger than zero. Then carry out an idle
* notification, either synchronous or asynchronous.
*
- * This routine may be called in atomic context if the RPM_ASYNC flag is set.
+ * This routine may be called in atomic context if the RPM_ASYNC flag is set,
+ * or if pm_runtime_irq_safe() has been called.
*/
int __pm_runtime_idle(struct device *dev, int rpmflags)
{
unsigned long flags;
int retval;
+ might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);
+
if (rpmflags & RPM_GET_PUT) {
if (!atomic_dec_and_test(&dev->power.usage_count))
return 0;
@@ -761,13 +794,16 @@ EXPORT_SYMBOL_GPL(__pm_runtime_idle);
* return immediately if it is larger than zero. Then carry out a suspend,
* either synchronous or asynchronous.
*
- * This routine may be called in atomic context if the RPM_ASYNC flag is set.
+ * This routine may be called in atomic context if the RPM_ASYNC flag is set,
+ * or if pm_runtime_irq_safe() has been called.
*/
int __pm_runtime_suspend(struct device *dev, int rpmflags)
{
unsigned long flags;
int retval;
+ might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);
+
if (rpmflags & RPM_GET_PUT) {
if (!atomic_dec_and_test(&dev->power.usage_count))
return 0;
@@ -789,13 +825,16 @@ EXPORT_SYMBOL_GPL(__pm_runtime_suspend);
* If the RPM_GET_PUT flag is set, increment the device's usage count. Then
* carry out a resume, either synchronous or asynchronous.
*
- * This routine may be called in atomic context if the RPM_ASYNC flag is set.
+ * This routine may be called in atomic context if the RPM_ASYNC flag is set,
+ * or if pm_runtime_irq_safe() has been called.
*/
int __pm_runtime_resume(struct device *dev, int rpmflags)
{
unsigned long flags;
int retval;
+ might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);
+
if (rpmflags & RPM_GET_PUT)
atomic_inc(&dev->power.usage_count);
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 84f7c7d5a098..14ee07e9cc43 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -276,7 +276,9 @@ EXPORT_SYMBOL_GPL(device_set_wakeup_capable);
*
* By default, most devices should leave wakeup disabled. The exceptions are
* devices that everyone expects to be wakeup sources: keyboards, power buttons,
- * possibly network interfaces, etc.
+ * possibly network interfaces, etc. Also, devices that don't generate their
+ * own wakeup requests but merely forward requests from one bus to another
+ * (like PCI bridges) should have wakeup enabled by default.
*/
int device_init_wakeup(struct device *dev, bool enable)
{
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig
index fabbf6cc5367..2fc6a66f39a4 100644
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -4,6 +4,8 @@
config REGMAP
default y if (REGMAP_I2C || REGMAP_SPI)
+ select LZO_COMPRESS
+ select LZO_DECOMPRESS
bool
config REGMAP_I2C
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile
index f476f4571295..0573c8a9dacb 100644
--- a/drivers/base/regmap/Makefile
+++ b/drivers/base/regmap/Makefile
@@ -1,3 +1,4 @@
-obj-$(CONFIG_REGMAP) += regmap.o
+obj-$(CONFIG_REGMAP) += regmap.o regcache.o regcache-indexed.o regcache-rbtree.o regcache-lzo.o
+obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
new file mode 100644
index 000000000000..348ff02eb93e
--- /dev/null
+++ b/drivers/base/regmap/internal.h
@@ -0,0 +1,128 @@
+/*
+ * Register map access API internal header
+ *
+ * Copyright 2011 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _REGMAP_INTERNAL_H
+#define _REGMAP_INTERNAL_H
+
+#include <linux/regmap.h>
+#include <linux/fs.h>
+
+struct regmap;
+struct regcache_ops;
+
+struct regmap_format {
+ size_t buf_size;
+ size_t reg_bytes;
+ size_t val_bytes;
+ void (*format_write)(struct regmap *map,
+ unsigned int reg, unsigned int val);
+ void (*format_reg)(void *buf, unsigned int reg);
+ void (*format_val)(void *buf, unsigned int val);
+ unsigned int (*parse_val)(void *buf);
+};
+
+struct regmap {
+ struct mutex lock;
+
+ struct device *dev; /* Device we do I/O on */
+ void *work_buf; /* Scratch buffer used to format I/O */
+ struct regmap_format format; /* Buffer format */
+ const struct regmap_bus *bus;
+
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs;
+#endif
+
+ unsigned int max_register;
+ bool (*writeable_reg)(struct device *dev, unsigned int reg);
+ bool (*readable_reg)(struct device *dev, unsigned int reg);
+ bool (*volatile_reg)(struct device *dev, unsigned int reg);
+ bool (*precious_reg)(struct device *dev, unsigned int reg);
+
+ u8 read_flag_mask;
+ u8 write_flag_mask;
+
+ /* regcache specific members */
+ const struct regcache_ops *cache_ops;
+ enum regcache_type cache_type;
+
+ /* number of bytes in reg_defaults_raw */
+ unsigned int cache_size_raw;
+ /* number of bytes per word in reg_defaults_raw */
+ unsigned int cache_word_size;
+ /* number of entries in reg_defaults */
+ unsigned int num_reg_defaults;
+ /* number of entries in reg_defaults_raw */
+ unsigned int num_reg_defaults_raw;
+
+ /* if set, only the cache is modified not the HW */
+ unsigned int cache_only:1;
+ /* if set, only the HW is modified not the cache */
+ unsigned int cache_bypass:1;
+ /* if set, remember to free reg_defaults_raw */
+ unsigned int cache_free:1;
+
+ struct reg_default *reg_defaults;
+ const void *reg_defaults_raw;
+ void *cache;
+};
+
+struct regcache_ops {
+ const char *name;
+ enum regcache_type type;
+ int (*init)(struct regmap *map);
+ int (*exit)(struct regmap *map);
+ int (*read)(struct regmap *map, unsigned int reg, unsigned int *value);
+ int (*write)(struct regmap *map, unsigned int reg, unsigned int value);
+ int (*sync)(struct regmap *map);
+};
+
+bool regmap_writeable(struct regmap *map, unsigned int reg);
+bool regmap_readable(struct regmap *map, unsigned int reg);
+bool regmap_volatile(struct regmap *map, unsigned int reg);
+bool regmap_precious(struct regmap *map, unsigned int reg);
+
+int _regmap_write(struct regmap *map, unsigned int reg,
+ unsigned int val);
+
+#ifdef CONFIG_DEBUG_FS
+extern void regmap_debugfs_initcall(void);
+extern void regmap_debugfs_init(struct regmap *map);
+extern void regmap_debugfs_exit(struct regmap *map);
+#else
+static inline void regmap_debugfs_initcall(void) { }
+static inline void regmap_debugfs_init(struct regmap *map) { }
+static inline void regmap_debugfs_exit(struct regmap *map) { }
+#endif
+
+/* regcache core declarations */
+int regcache_init(struct regmap *map);
+void regcache_exit(struct regmap *map);
+int regcache_read(struct regmap *map,
+ unsigned int reg, unsigned int *value);
+int regcache_write(struct regmap *map,
+ unsigned int reg, unsigned int value);
+int regcache_sync(struct regmap *map);
+
+unsigned int regcache_get_val(const void *base, unsigned int idx,
+ unsigned int word_size);
+bool regcache_set_val(void *base, unsigned int idx,
+ unsigned int val, unsigned int word_size);
+int regcache_lookup_reg(struct regmap *map, unsigned int reg);
+int regcache_insert_reg(struct regmap *map, unsigned int reg,
+ unsigned int val);
+
+extern struct regcache_ops regcache_indexed_ops;
+extern struct regcache_ops regcache_rbtree_ops;
+extern struct regcache_ops regcache_lzo_ops;
+
+#endif
diff --git a/drivers/base/regmap/regcache-indexed.c b/drivers/base/regmap/regcache-indexed.c
new file mode 100644
index 000000000000..507731ad8ec1
--- /dev/null
+++ b/drivers/base/regmap/regcache-indexed.c
@@ -0,0 +1,64 @@
+/*
+ * Register cache access API - indexed caching support
+ *
+ * Copyright 2011 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/slab.h>
+
+#include "internal.h"
+
+static int regcache_indexed_read(struct regmap *map, unsigned int reg,
+ unsigned int *value)
+{
+ int ret;
+
+ ret = regcache_lookup_reg(map, reg);
+ if (ret >= 0)
+ *value = map->reg_defaults[ret].def;
+
+ return ret;
+}
+
+static int regcache_indexed_write(struct regmap *map, unsigned int reg,
+ unsigned int value)
+{
+ int ret;
+
+ ret = regcache_lookup_reg(map, reg);
+ if (ret < 0)
+ return regcache_insert_reg(map, reg, value);
+ map->reg_defaults[ret].def = value;
+ return 0;
+}
+
+static int regcache_indexed_sync(struct regmap *map)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < map->num_reg_defaults; i++) {
+ ret = _regmap_write(map, map->reg_defaults[i].reg,
+ map->reg_defaults[i].def);
+ if (ret < 0)
+ return ret;
+ dev_dbg(map->dev, "Synced register %#x, value %#x\n",
+ map->reg_defaults[i].reg,
+ map->reg_defaults[i].def);
+ }
+ return 0;
+}
+
+struct regcache_ops regcache_indexed_ops = {
+ .type = REGCACHE_INDEXED,
+ .name = "indexed",
+ .read = regcache_indexed_read,
+ .write = regcache_indexed_write,
+ .sync = regcache_indexed_sync
+};
diff --git a/drivers/base/regmap/regcache-lzo.c b/drivers/base/regmap/regcache-lzo.c
new file mode 100644
index 000000000000..066aeece3626
--- /dev/null
+++ b/drivers/base/regmap/regcache-lzo.c
@@ -0,0 +1,361 @@
+/*
+ * Register cache access API - LZO caching support
+ *
+ * Copyright 2011 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/slab.h>
+#include <linux/lzo.h>
+
+#include "internal.h"
+
+struct regcache_lzo_ctx {
+ void *wmem;
+ void *dst;
+ const void *src;
+ size_t src_len;
+ size_t dst_len;
+ size_t decompressed_size;
+ unsigned long *sync_bmp;
+ int sync_bmp_nbits;
+};
+
+#define LZO_BLOCK_NUM 8
+static int regcache_lzo_block_count(void)
+{
+ return LZO_BLOCK_NUM;
+}
+
+static int regcache_lzo_prepare(struct regcache_lzo_ctx *lzo_ctx)
+{
+ lzo_ctx->wmem = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
+ if (!lzo_ctx->wmem)
+ return -ENOMEM;
+ return 0;
+}
+
+static int regcache_lzo_compress(struct regcache_lzo_ctx *lzo_ctx)
+{
+ size_t compress_size;
+ int ret;
+
+ ret = lzo1x_1_compress(lzo_ctx->src, lzo_ctx->src_len,
+ lzo_ctx->dst, &compress_size, lzo_ctx->wmem);
+ if (ret != LZO_E_OK || compress_size > lzo_ctx->dst_len)
+ return -EINVAL;
+ lzo_ctx->dst_len = compress_size;
+ return 0;
+}
+
+static int regcache_lzo_decompress(struct regcache_lzo_ctx *lzo_ctx)
+{
+ size_t dst_len;
+ int ret;
+
+ dst_len = lzo_ctx->dst_len;
+ ret = lzo1x_decompress_safe(lzo_ctx->src, lzo_ctx->src_len,
+ lzo_ctx->dst, &dst_len);
+ if (ret != LZO_E_OK || dst_len != lzo_ctx->dst_len)
+ return -EINVAL;
+ return 0;
+}
+
+static int regcache_lzo_compress_cache_block(struct regmap *map,
+ struct regcache_lzo_ctx *lzo_ctx)
+{
+ int ret;
+
+ lzo_ctx->dst_len = lzo1x_worst_compress(PAGE_SIZE);
+ lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
+ if (!lzo_ctx->dst) {
+ lzo_ctx->dst_len = 0;
+ return -ENOMEM;
+ }
+
+ ret = regcache_lzo_compress(lzo_ctx);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int regcache_lzo_decompress_cache_block(struct regmap *map,
+ struct regcache_lzo_ctx *lzo_ctx)
+{
+ int ret;
+
+ lzo_ctx->dst_len = lzo_ctx->decompressed_size;
+ lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
+ if (!lzo_ctx->dst) {
+ lzo_ctx->dst_len = 0;
+ return -ENOMEM;
+ }
+
+ ret = regcache_lzo_decompress(lzo_ctx);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static inline int regcache_lzo_get_blkindex(struct regmap *map,
+ unsigned int reg)
+{
+ return (reg * map->cache_word_size) /
+ DIV_ROUND_UP(map->cache_size_raw, regcache_lzo_block_count());
+}
+
+static inline int regcache_lzo_get_blkpos(struct regmap *map,
+ unsigned int reg)
+{
+ return reg % (DIV_ROUND_UP(map->cache_size_raw, regcache_lzo_block_count()) /
+ map->cache_word_size);
+}
+
+static inline int regcache_lzo_get_blksize(struct regmap *map)
+{
+ return DIV_ROUND_UP(map->cache_size_raw, regcache_lzo_block_count());
+}
+
+static int regcache_lzo_init(struct regmap *map)
+{
+ struct regcache_lzo_ctx **lzo_blocks;
+ size_t bmp_size;
+ int ret, i, blksize, blkcount;
+ const char *p, *end;
+ unsigned long *sync_bmp;
+
+ ret = 0;
+
+ blkcount = regcache_lzo_block_count();
+ map->cache = kzalloc(blkcount * sizeof *lzo_blocks,
+ GFP_KERNEL);
+ if (!map->cache)
+ return -ENOMEM;
+ lzo_blocks = map->cache;
+
+ /*
+ * allocate a bitmap to be used when syncing the cache with
+ * the hardware. Each time a register is modified, the corresponding
+ * bit is set in the bitmap, so we know that we have to sync
+ * that register.
+ */
+ bmp_size = map->num_reg_defaults_raw;
+ sync_bmp = kmalloc(BITS_TO_LONGS(bmp_size) * sizeof(long),
+ GFP_KERNEL);
+ if (!sync_bmp) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ bitmap_zero(sync_bmp, bmp_size);
+
+ /* allocate the lzo blocks and initialize them */
+ for (i = 0; i < blkcount; i++) {
+ lzo_blocks[i] = kzalloc(sizeof **lzo_blocks,
+ GFP_KERNEL);
+ if (!lzo_blocks[i]) {
+ kfree(sync_bmp);
+ ret = -ENOMEM;
+ goto err;
+ }
+ lzo_blocks[i]->sync_bmp = sync_bmp;
+ lzo_blocks[i]->sync_bmp_nbits = bmp_size;
+ /* alloc the working space for the compressed block */
+ ret = regcache_lzo_prepare(lzo_blocks[i]);
+ if (ret < 0)
+ goto err;
+ }
+
+ blksize = regcache_lzo_get_blksize(map);
+ p = map->reg_defaults_raw;
+ end = map->reg_defaults_raw + map->cache_size_raw;
+ /* compress the register map and fill the lzo blocks */
+ for (i = 0; i < blkcount; i++, p += blksize) {
+ lzo_blocks[i]->src = p;
+ if (p + blksize > end)
+ lzo_blocks[i]->src_len = end - p;
+ else
+ lzo_blocks[i]->src_len = blksize;
+ ret = regcache_lzo_compress_cache_block(map,
+ lzo_blocks[i]);
+ if (ret < 0)
+ goto err;
+ lzo_blocks[i]->decompressed_size =
+ lzo_blocks[i]->src_len;
+ }
+
+ return 0;
+err:
+ regcache_exit(map);
+ return ret;
+}
+
+static int regcache_lzo_exit(struct regmap *map)
+{
+ struct regcache_lzo_ctx **lzo_blocks;
+ int i, blkcount;
+
+ lzo_blocks = map->cache;
+ if (!lzo_blocks)
+ return 0;
+
+ blkcount = regcache_lzo_block_count();
+ /*
+ * the pointer to the bitmap used for syncing the cache
+ * is shared amongst all lzo_blocks. Ensure it is freed
+ * only once.
+ */
+ if (lzo_blocks[0])
+ kfree(lzo_blocks[0]->sync_bmp);
+ for (i = 0; i < blkcount; i++) {
+ if (lzo_blocks[i]) {
+ kfree(lzo_blocks[i]->wmem);
+ kfree(lzo_blocks[i]->dst);
+ }
+ /* each lzo_block is a pointer returned by kmalloc or NULL */
+ kfree(lzo_blocks[i]);
+ }
+ kfree(lzo_blocks);
+ map->cache = NULL;
+ return 0;
+}
+
+static int regcache_lzo_read(struct regmap *map,
+ unsigned int reg, unsigned int *value)
+{
+ struct regcache_lzo_ctx *lzo_block, **lzo_blocks;
+ int ret, blkindex, blkpos;
+ size_t blksize, tmp_dst_len;
+ void *tmp_dst;
+
+ /* index of the compressed lzo block */
+ blkindex = regcache_lzo_get_blkindex(map, reg);
+ /* register index within the decompressed block */
+ blkpos = regcache_lzo_get_blkpos(map, reg);
+ /* size of the compressed block */
+ blksize = regcache_lzo_get_blksize(map);
+ lzo_blocks = map->cache;
+ lzo_block = lzo_blocks[blkindex];
+
+ /* save the pointer and length of the compressed block */
+ tmp_dst = lzo_block->dst;
+ tmp_dst_len = lzo_block->dst_len;
+
+ /* prepare the source to be the compressed block */
+ lzo_block->src = lzo_block->dst;
+ lzo_block->src_len = lzo_block->dst_len;
+
+ /* decompress the block */
+ ret = regcache_lzo_decompress_cache_block(map, lzo_block);
+ if (ret >= 0)
+ /* fetch the value from the cache */
+ *value = regcache_get_val(lzo_block->dst, blkpos,
+ map->cache_word_size);
+
+ kfree(lzo_block->dst);
+ /* restore the pointer and length of the compressed block */
+ lzo_block->dst = tmp_dst;
+ lzo_block->dst_len = tmp_dst_len;
+
+ return ret;
+}
+
+static int regcache_lzo_write(struct regmap *map,
+ unsigned int reg, unsigned int value)
+{
+ struct regcache_lzo_ctx *lzo_block, **lzo_blocks;
+ int ret, blkindex, blkpos;
+ size_t blksize, tmp_dst_len;
+ void *tmp_dst;
+
+ /* index of the compressed lzo block */
+ blkindex = regcache_lzo_get_blkindex(map, reg);
+ /* register index within the decompressed block */
+ blkpos = regcache_lzo_get_blkpos(map, reg);
+ /* size of the compressed block */
+ blksize = regcache_lzo_get_blksize(map);
+ lzo_blocks = map->cache;
+ lzo_block = lzo_blocks[blkindex];
+
+ /* save the pointer and length of the compressed block */
+ tmp_dst = lzo_block->dst;
+ tmp_dst_len = lzo_block->dst_len;
+
+ /* prepare the source to be the compressed block */
+ lzo_block->src = lzo_block->dst;
+ lzo_block->src_len = lzo_block->dst_len;
+
+ /* decompress the block */
+ ret = regcache_lzo_decompress_cache_block(map, lzo_block);
+ if (ret < 0) {
+ kfree(lzo_block->dst);
+ goto out;
+ }
+
+ /* write the new value to the cache */
+ if (regcache_set_val(lzo_block->dst, blkpos, value,
+ map->cache_word_size)) {
+ kfree(lzo_block->dst);
+ goto out;
+ }
+
+ /* prepare the source to be the decompressed block */
+ lzo_block->src = lzo_block->dst;
+ lzo_block->src_len = lzo_block->dst_len;
+
+ /* compress the block */
+ ret = regcache_lzo_compress_cache_block(map, lzo_block);
+ if (ret < 0) {
+ kfree(lzo_block->dst);
+ kfree(lzo_block->src);
+ goto out;
+ }
+
+ /* set the bit so we know we have to sync this register */
+ set_bit(reg, lzo_block->sync_bmp);
+ kfree(tmp_dst);
+ kfree(lzo_block->src);
+ return 0;
+out:
+ lzo_block->dst = tmp_dst;
+ lzo_block->dst_len = tmp_dst_len;
+ return ret;
+}
+
+static int regcache_lzo_sync(struct regmap *map)
+{
+ struct regcache_lzo_ctx **lzo_blocks;
+ unsigned int val;
+ int i;
+ int ret;
+
+ lzo_blocks = map->cache;
+ for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) {
+ ret = regcache_read(map, i, &val);
+ if (ret)
+ return ret;
+ map->cache_bypass = 1;
+ ret = _regmap_write(map, i, val);
+ map->cache_bypass = 0;
+ if (ret)
+ return ret;
+ dev_dbg(map->dev, "Synced register %#x, value %#x\n",
+ i, val);
+ }
+
+ return 0;
+}
+
+struct regcache_ops regcache_lzo_ops = {
+ .type = REGCACHE_LZO,
+ .name = "lzo",
+ .init = regcache_lzo_init,
+ .exit = regcache_lzo_exit,
+ .read = regcache_lzo_read,
+ .write = regcache_lzo_write,
+ .sync = regcache_lzo_sync
+};
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
new file mode 100644
index 000000000000..e31498499b0f
--- /dev/null
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -0,0 +1,345 @@
+/*
+ * Register cache access API - rbtree caching support
+ *
+ * Copyright 2011 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/slab.h>
+#include <linux/rbtree.h>
+
+#include "internal.h"
+
+static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
+ unsigned int value);
+
+struct regcache_rbtree_node {
+ /* the actual rbtree node holding this block */
+ struct rb_node node;
+ /* base register handled by this block */
+ unsigned int base_reg;
+ /* block of adjacent registers */
+ void *block;
+ /* number of registers available in the block */
+ unsigned int blklen;
+} __attribute__ ((packed));
+
+struct regcache_rbtree_ctx {
+ struct rb_root root;
+ struct regcache_rbtree_node *cached_rbnode;
+};
+
+static inline void regcache_rbtree_get_base_top_reg(
+ struct regcache_rbtree_node *rbnode,
+ unsigned int *base, unsigned int *top)
+{
+ *base = rbnode->base_reg;
+ *top = rbnode->base_reg + rbnode->blklen - 1;
+}
+
+static unsigned int regcache_rbtree_get_register(
+ struct regcache_rbtree_node *rbnode, unsigned int idx,
+ unsigned int word_size)
+{
+ return regcache_get_val(rbnode->block, idx, word_size);
+}
+
+static void regcache_rbtree_set_register(struct regcache_rbtree_node *rbnode,
+ unsigned int idx, unsigned int val,
+ unsigned int word_size)
+{
+ regcache_set_val(rbnode->block, idx, val, word_size);
+}
+
+static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
+ unsigned int reg)
+{
+ struct regcache_rbtree_ctx *rbtree_ctx = map->cache;
+ struct rb_node *node;
+ struct regcache_rbtree_node *rbnode;
+ unsigned int base_reg, top_reg;
+
+ rbnode = rbtree_ctx->cached_rbnode;
+ if (rbnode) {
+ regcache_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
+ if (reg >= base_reg && reg <= top_reg)
+ return rbnode;
+ }
+
+ node = rbtree_ctx->root.rb_node;
+ while (node) {
+ rbnode = container_of(node, struct regcache_rbtree_node, node);
+ regcache_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
+ if (reg >= base_reg && reg <= top_reg) {
+ rbtree_ctx->cached_rbnode = rbnode;
+ return rbnode;
+ } else if (reg > top_reg) {
+ node = node->rb_right;
+ } else if (reg < base_reg) {
+ node = node->rb_left;
+ }
+ }
+
+ return NULL;
+}
+
+static int regcache_rbtree_insert(struct rb_root *root,
+ struct regcache_rbtree_node *rbnode)
+{
+ struct rb_node **new, *parent;
+ struct regcache_rbtree_node *rbnode_tmp;
+ unsigned int base_reg_tmp, top_reg_tmp;
+ unsigned int base_reg;
+
+ parent = NULL;
+ new = &root->rb_node;
+ while (*new) {
+ rbnode_tmp = container_of(*new, struct regcache_rbtree_node,
+ node);
+ /* base and top registers of the current rbnode */
+ regcache_rbtree_get_base_top_reg(rbnode_tmp, &base_reg_tmp,
+ &top_reg_tmp);
+ /* base register of the rbnode to be added */
+ base_reg = rbnode->base_reg;
+ parent = *new;
+ /* if this register has already been inserted, just return */
+ if (base_reg >= base_reg_tmp &&
+ base_reg <= top_reg_tmp)
+ return 0;
+ else if (base_reg > top_reg_tmp)
+ new = &((*new)->rb_right);
+ else if (base_reg < base_reg_tmp)
+ new = &((*new)->rb_left);
+ }
+
+ /* insert the node into the rbtree */
+ rb_link_node(&rbnode->node, parent, new);
+ rb_insert_color(&rbnode->node, root);
+
+ return 1;
+}
+
+static int regcache_rbtree_init(struct regmap *map)
+{
+ struct regcache_rbtree_ctx *rbtree_ctx;
+ int i;
+ int ret;
+
+ map->cache = kmalloc(sizeof *rbtree_ctx, GFP_KERNEL);
+ if (!map->cache)
+ return -ENOMEM;
+
+ rbtree_ctx = map->cache;
+ rbtree_ctx->root = RB_ROOT;
+ rbtree_ctx->cached_rbnode = NULL;
+
+ for (i = 0; i < map->num_reg_defaults; i++) {
+ ret = regcache_rbtree_write(map,
+ map->reg_defaults[i].reg,
+ map->reg_defaults[i].def);
+ if (ret)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ regcache_exit(map);
+ return ret;
+}
+
+static int regcache_rbtree_exit(struct regmap *map)
+{
+ struct rb_node *next;
+ struct regcache_rbtree_ctx *rbtree_ctx;
+ struct regcache_rbtree_node *rbtree_node;
+
+ /* if we've already been called then just return */
+ rbtree_ctx = map->cache;
+ if (!rbtree_ctx)
+ return 0;
+
+ /* free up the rbtree */
+ next = rb_first(&rbtree_ctx->root);
+ while (next) {
+ rbtree_node = rb_entry(next, struct regcache_rbtree_node, node);
+ next = rb_next(&rbtree_node->node);
+ rb_erase(&rbtree_node->node, &rbtree_ctx->root);
+ kfree(rbtree_node->block);
+ kfree(rbtree_node);
+ }
+
+ /* release the resources */
+ kfree(map->cache);
+ map->cache = NULL;
+
+ return 0;
+}
+
+static int regcache_rbtree_read(struct regmap *map,
+ unsigned int reg, unsigned int *value)
+{
+ struct regcache_rbtree_node *rbnode;
+ unsigned int reg_tmp;
+
+ rbnode = regcache_rbtree_lookup(map, reg);
+ if (rbnode) {
+ reg_tmp = reg - rbnode->base_reg;
+ *value = regcache_rbtree_get_register(rbnode, reg_tmp,
+ map->cache_word_size);
+ } else {
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+
+static int regcache_rbtree_insert_to_block(struct regcache_rbtree_node *rbnode,
+ unsigned int pos, unsigned int reg,
+ unsigned int value, unsigned int word_size)
+{
+ u8 *blk;
+
+ blk = krealloc(rbnode->block,
+ (rbnode->blklen + 1) * word_size, GFP_KERNEL);
+ if (!blk)
+ return -ENOMEM;
+
+ /* insert the register value in the correct place in the rbnode block */
+ memmove(blk + (pos + 1) * word_size,
+ blk + pos * word_size,
+ (rbnode->blklen - pos) * word_size);
+
+ /* update the rbnode block, its size and the base register */
+ rbnode->block = blk;
+ rbnode->blklen++;
+ if (!pos)
+ rbnode->base_reg = reg;
+
+ regcache_rbtree_set_register(rbnode, pos, value, word_size);
+ return 0;
+}
+
+static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
+ unsigned int value)
+{
+ struct regcache_rbtree_ctx *rbtree_ctx;
+ struct regcache_rbtree_node *rbnode, *rbnode_tmp;
+ struct rb_node *node;
+ unsigned int val;
+ unsigned int reg_tmp;
+ unsigned int pos;
+ int i;
+ int ret;
+
+ rbtree_ctx = map->cache;
+ /* if we can't locate it in the cached rbnode we'll have
+ * to traverse the rbtree looking for it.
+ */
+ rbnode = regcache_rbtree_lookup(map, reg);
+ if (rbnode) {
+ reg_tmp = reg - rbnode->base_reg;
+ val = regcache_rbtree_get_register(rbnode, reg_tmp,
+ map->cache_word_size);
+ if (val == value)
+ return 0;
+ regcache_rbtree_set_register(rbnode, reg_tmp, value,
+ map->cache_word_size);
+ } else {
+ /* look for an adjacent register to the one we are about to add */
+ for (node = rb_first(&rbtree_ctx->root); node;
+ node = rb_next(node)) {
+ rbnode_tmp = rb_entry(node, struct regcache_rbtree_node, node);
+ for (i = 0; i < rbnode_tmp->blklen; i++) {
+ reg_tmp = rbnode_tmp->base_reg + i;
+ if (abs(reg_tmp - reg) != 1)
+ continue;
+ /* decide where in the block to place our register */
+ if (reg_tmp + 1 == reg)
+ pos = i + 1;
+ else
+ pos = i;
+ ret = regcache_rbtree_insert_to_block(rbnode_tmp, pos,
+ reg, value,
+ map->cache_word_size);
+ if (ret)
+ return ret;
+ rbtree_ctx->cached_rbnode = rbnode_tmp;
+ return 0;
+ }
+ }
+ /* we did not manage to find a place to insert it in an existing
+ * block so create a new rbnode with a single register in its block.
+ * This block will get populated further if any other adjacent
+ * registers get modified in the future.
+ */
+ rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
+ if (!rbnode)
+ return -ENOMEM;
+ rbnode->blklen = 1;
+ rbnode->base_reg = reg;
+ rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size,
+ GFP_KERNEL);
+ if (!rbnode->block) {
+ kfree(rbnode);
+ return -ENOMEM;
+ }
+ regcache_rbtree_set_register(rbnode, 0, value, map->cache_word_size);
+ regcache_rbtree_insert(&rbtree_ctx->root, rbnode);
+ rbtree_ctx->cached_rbnode = rbnode;
+ }
+
+ return 0;
+}
+
+static int regcache_rbtree_sync(struct regmap *map)
+{
+ struct regcache_rbtree_ctx *rbtree_ctx;
+ struct rb_node *node;
+ struct regcache_rbtree_node *rbnode;
+ unsigned int regtmp;
+ unsigned int val;
+ int ret;
+ int i;
+
+ rbtree_ctx = map->cache;
+ for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
+ rbnode = rb_entry(node, struct regcache_rbtree_node, node);
+ for (i = 0; i < rbnode->blklen; i++) {
+ regtmp = rbnode->base_reg + i;
+ val = regcache_rbtree_get_register(rbnode, i,
+ map->cache_word_size);
+
+ /* Is this the hardware default? If so skip. */
+ ret = regcache_lookup_reg(map, i);
+ if (ret > 0 && val == map->reg_defaults[ret].def)
+ continue;
+
+ map->cache_bypass = 1;
+ ret = _regmap_write(map, regtmp, val);
+ map->cache_bypass = 0;
+ if (ret)
+ return ret;
+ dev_dbg(map->dev, "Synced register %#x, value %#x\n",
+ regtmp, val);
+ }
+ }
+
+ return 0;
+}
+
+struct regcache_ops regcache_rbtree_ops = {
+ .type = REGCACHE_RBTREE,
+ .name = "rbtree",
+ .init = regcache_rbtree_init,
+ .exit = regcache_rbtree_exit,
+ .read = regcache_rbtree_read,
+ .write = regcache_rbtree_write,
+ .sync = regcache_rbtree_sync
+};
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
new file mode 100644
index 000000000000..afcfef838263
--- /dev/null
+++ b/drivers/base/regmap/regcache.c
@@ -0,0 +1,401 @@
+/*
+ * Register cache access API
+ *
+ * Copyright 2011 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/slab.h>
+#include <trace/events/regmap.h>
+#include <linux/bsearch.h>
+#include <linux/sort.h>
+
+#include "internal.h"
+
+static const struct regcache_ops *cache_types[] = {
+ &regcache_indexed_ops,
+ &regcache_rbtree_ops,
+ &regcache_lzo_ops,
+};
+
+static int regcache_hw_init(struct regmap *map)
+{
+ int i, j;
+ int ret;
+ int count;
+ unsigned int val;
+ void *tmp_buf;
+
+ if (!map->num_reg_defaults_raw)
+ return -EINVAL;
+
+ if (!map->reg_defaults_raw) {
+ dev_warn(map->dev, "No cache defaults, reading back from HW\n");
+ tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL);
+ if (!tmp_buf)
+ return -EINVAL;
+ ret = regmap_bulk_read(map, 0, tmp_buf,
+ map->num_reg_defaults_raw);
+ if (ret < 0) {
+ kfree(tmp_buf);
+ return ret;
+ }
+ map->reg_defaults_raw = tmp_buf;
+ map->cache_free = 1;
+ }
+
+ /* calculate the size of reg_defaults */
+ for (count = 0, i = 0; i < map->num_reg_defaults_raw; i++) {
+ val = regcache_get_val(map->reg_defaults_raw,
+ i, map->cache_word_size);
+ if (!val)
+ continue;
+ count++;
+ }
+
+ map->reg_defaults = kmalloc(count * sizeof(struct reg_default),
+ GFP_KERNEL);
+ if (!map->reg_defaults)
+ return -ENOMEM;
+
+ /* fill the reg_defaults */
+ map->num_reg_defaults = count;
+ for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) {
+ val = regcache_get_val(map->reg_defaults_raw,
+ i, map->cache_word_size);
+ if (!val)
+ continue;
+ map->reg_defaults[j].reg = i;
+ map->reg_defaults[j].def = val;
+ j++;
+ }
+
+ return 0;
+}
+
+int regcache_init(struct regmap *map)
+{
+ int ret;
+ int i;
+ void *tmp_buf;
+
+ if (map->cache_type == REGCACHE_NONE) {
+ map->cache_bypass = true;
+ return 0;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cache_types); i++)
+ if (cache_types[i]->type == map->cache_type)
+ break;
+
+ if (i == ARRAY_SIZE(cache_types)) {
+ dev_err(map->dev, "Could not match compress type: %d\n",
+ map->cache_type);
+ return -EINVAL;
+ }
+
+ map->cache = NULL;
+ map->cache_ops = cache_types[i];
+
+ if (!map->cache_ops->read ||
+ !map->cache_ops->write ||
+ !map->cache_ops->name)
+ return -EINVAL;
+
+ /* We still need to ensure that the reg_defaults
+ * won't vanish from under us. We'll need to make
+ * a copy of it.
+ */
+ if (map->reg_defaults) {
+ if (!map->num_reg_defaults)
+ return -EINVAL;
+ tmp_buf = kmemdup(map->reg_defaults, map->num_reg_defaults *
+ sizeof(struct reg_default), GFP_KERNEL);
+ if (!tmp_buf)
+ return -ENOMEM;
+ map->reg_defaults = tmp_buf;
+ } else if (map->num_reg_defaults_raw) {
+ /* Some devices such as PMICs don't have cache defaults,
+ * we cope with this by reading back the HW registers and
+ * crafting the cache defaults by hand.
+ */
+ ret = regcache_hw_init(map);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (!map->max_register)
+ map->max_register = map->num_reg_defaults_raw;
+
+ if (map->cache_ops->init) {
+ dev_dbg(map->dev, "Initializing %s cache\n",
+ map->cache_ops->name);
+ return map->cache_ops->init(map);
+ }
+ return 0;
+}
+
+void regcache_exit(struct regmap *map)
+{
+ if (map->cache_type == REGCACHE_NONE)
+ return;
+
+ BUG_ON(!map->cache_ops);
+
+ kfree(map->reg_defaults);
+ if (map->cache_free)
+ kfree(map->reg_defaults_raw);
+
+ if (map->cache_ops->exit) {
+ dev_dbg(map->dev, "Destroying %s cache\n",
+ map->cache_ops->name);
+ map->cache_ops->exit(map);
+ }
+}
+
+/**
+ * regcache_read: Fetch the value of a given register from the cache.
+ *
+ * @map: map to configure.
+ * @reg: The register index.
+ * @value: The value to be returned.
+ *
+ * Return a negative value on failure, 0 on success.
+ */
+int regcache_read(struct regmap *map,
+ unsigned int reg, unsigned int *value)
+{
+ if (map->cache_type == REGCACHE_NONE)
+ return -ENOSYS;
+
+ BUG_ON(!map->cache_ops);
+
+ if (!regmap_readable(map, reg))
+ return -EIO;
+
+ if (!regmap_volatile(map, reg))
+ return map->cache_ops->read(map, reg, value);
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(regcache_read);
+
+/**
+ * regcache_write: Set the value of a given register in the cache.
+ *
+ * @map: map to configure.
+ * @reg: The register index.
+ * @value: The new register value.
+ *
+ * Return a negative value on failure, 0 on success.
+ */
+int regcache_write(struct regmap *map,
+ unsigned int reg, unsigned int value)
+{
+ if (map->cache_type == REGCACHE_NONE)
+ return 0;
+
+ BUG_ON(!map->cache_ops);
+
+ if (!regmap_writeable(map, reg))
+ return -EIO;
+
+ if (!regmap_volatile(map, reg))
+ return map->cache_ops->write(map, reg, value);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(regcache_write);
+
+/**
+ * regcache_sync: Sync the register cache with the hardware.
+ *
+ * @map: map to configure.
+ *
+ * Any registers that should not be synced should be marked as
+ * volatile. In general drivers can choose not to use the provided
+ * syncing functionality if they so require.
+ *
+ * Return a negative value on failure, 0 on success.
+ */
+int regcache_sync(struct regmap *map)
+{
+ int ret = 0;
+ unsigned int val;
+ unsigned int i;
+ const char *name;
+ unsigned int bypass;
+
+ BUG_ON(!map->cache_ops);
+
+ mutex_lock(&map->lock);
+ /* Remember the initial bypass state */
+ bypass = map->cache_bypass;
+ dev_dbg(map->dev, "Syncing %s cache\n",
+ map->cache_ops->name);
+ name = map->cache_ops->name;
+ trace_regcache_sync(map->dev, name, "start");
+ if (map->cache_ops->sync) {
+ ret = map->cache_ops->sync(map);
+ } else {
+ for (i = 0; i < map->num_reg_defaults; i++) {
+ ret = regcache_read(map, i, &val);
+ if (ret < 0)
+ goto out;
+ map->cache_bypass = 1;
+ ret = _regmap_write(map, i, val);
+ map->cache_bypass = 0;
+ if (ret < 0)
+ goto out;
+ dev_dbg(map->dev, "Synced register %#x, value %#x\n",
+ map->reg_defaults[i].reg,
+ map->reg_defaults[i].def);
+ }
+
+ }
+out:
+ trace_regcache_sync(map->dev, name, "stop");
+ /* Restore the bypass state */
+ map->cache_bypass = bypass;
+ mutex_unlock(&map->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regcache_sync);
+
+/**
+ * regcache_cache_only: Put a register map into cache only mode
+ *
+ * @map: map to configure
+ * @cache_only: flag if changes should be written to the hardware
+ *
+ * When a register map is marked as cache only writes to the register
+ * map API will only update the register cache, they will not cause
+ * any hardware changes. This is useful for allowing portions of
+ * drivers to act as though the device were functioning as normal when
+ * it is disabled for power saving reasons.
+ */
+void regcache_cache_only(struct regmap *map, bool enable)
+{
+ mutex_lock(&map->lock);
+ WARN_ON(map->cache_bypass && enable);
+ map->cache_only = enable;
+ mutex_unlock(&map->lock);
+}
+EXPORT_SYMBOL_GPL(regcache_cache_only);
+
+/**
+ * regcache_cache_bypass: Put a register map into cache bypass mode
+ *
+ * @map: map to configure
+ * @cache_bypass: flag if changes should not be written to the hardware
+ *
+ * When a register map is marked with the cache bypass option, writes
+ * to the register map API will only update the hardware and not the
+ * the cache directly. This is useful when syncing the cache back to
+ * the hardware.
+ */
+void regcache_cache_bypass(struct regmap *map, bool enable)
+{
+ mutex_lock(&map->lock);
+ WARN_ON(map->cache_only && enable);
+ map->cache_bypass = enable;
+ mutex_unlock(&map->lock);
+}
+EXPORT_SYMBOL_GPL(regcache_cache_bypass);
+
+bool regcache_set_val(void *base, unsigned int idx,
+ unsigned int val, unsigned int word_size)
+{
+ switch (word_size) {
+ case 1: {
+ u8 *cache = base;
+ if (cache[idx] == val)
+ return true;
+ cache[idx] = val;
+ break;
+ }
+ case 2: {
+ u16 *cache = base;
+ if (cache[idx] == val)
+ return true;
+ cache[idx] = val;
+ break;
+ }
+ default:
+ BUG();
+ }
+ /* unreachable */
+ return false;
+}
+
+unsigned int regcache_get_val(const void *base, unsigned int idx,
+ unsigned int word_size)
+{
+ if (!base)
+ return -EINVAL;
+
+ switch (word_size) {
+ case 1: {
+ const u8 *cache = base;
+ return cache[idx];
+ }
+ case 2: {
+ const u16 *cache = base;
+ return cache[idx];
+ }
+ default:
+ BUG();
+ }
+ /* unreachable */
+ return -1;
+}
+
+static int regcache_default_cmp(const void *a, const void *b)
+{
+ const struct reg_default *_a = a;
+ const struct reg_default *_b = b;
+
+ return _a->reg - _b->reg;
+}
+
+int regcache_lookup_reg(struct regmap *map, unsigned int reg)
+{
+ struct reg_default key;
+ struct reg_default *r;
+
+ key.reg = reg;
+ key.def = 0;
+
+ r = bsearch(&key, map->reg_defaults, map->num_reg_defaults,
+ sizeof(struct reg_default), regcache_default_cmp);
+
+ if (r)
+ return r - map->reg_defaults;
+ else
+ return -ENOENT;
+}
+
+int regcache_insert_reg(struct regmap *map, unsigned int reg,
+ unsigned int val)
+{
+ void *tmp;
+
+ tmp = krealloc(map->reg_defaults,
+ (map->num_reg_defaults + 1) * sizeof(struct reg_default),
+ GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+ map->reg_defaults = tmp;
+ map->num_reg_defaults++;
+ map->reg_defaults[map->num_reg_defaults - 1].reg = reg;
+ map->reg_defaults[map->num_reg_defaults - 1].def = val;
+ sort(map->reg_defaults, map->num_reg_defaults,
+ sizeof(struct reg_default), regcache_default_cmp, NULL);
+ return 0;
+}
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
new file mode 100644
index 000000000000..6f397476e27c
--- /dev/null
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -0,0 +1,209 @@
+/*
+ * Register map access API - debugfs
+ *
+ * Copyright 2011 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#include "internal.h"
+
+static struct dentry *regmap_debugfs_root;
+
+/* Calculate the length of a fixed format */
+static size_t regmap_calc_reg_len(int max_val, char *buf, size_t buf_size)
+{
+ snprintf(buf, buf_size, "%x", max_val);
+ return strlen(buf);
+}
+
+static int regmap_open_file(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ int reg_len, val_len, tot_len;
+ size_t buf_pos = 0;
+ loff_t p = 0;
+ ssize_t ret;
+ int i;
+ struct regmap *map = file->private_data;
+ char *buf;
+ unsigned int val;
+
+ if (*ppos < 0 || !count)
+ return -EINVAL;
+
+ buf = kmalloc(count, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ /* Calculate the length of a fixed format */
+ reg_len = regmap_calc_reg_len(map->max_register, buf, count);
+ val_len = 2 * map->format.val_bytes;
+ tot_len = reg_len + val_len + 3; /* : \n */
+
+ for (i = 0; i < map->max_register + 1; i++) {
+ if (!regmap_readable(map, i))
+ continue;
+
+ if (regmap_precious(map, i))
+ continue;
+
+ /* If we're in the region the user is trying to read */
+ if (p >= *ppos) {
+ /* ...but not beyond it */
+ if (buf_pos >= count - 1 - tot_len)
+ break;
+
+ /* Format the register */
+ snprintf(buf + buf_pos, count - buf_pos, "%.*x: ",
+ reg_len, i);
+ buf_pos += reg_len + 2;
+
+ /* Format the value, write all X if we can't read */
+ ret = regmap_read(map, i, &val);
+ if (ret == 0)
+ snprintf(buf + buf_pos, count - buf_pos,
+ "%.*x", val_len, val);
+ else
+ memset(buf + buf_pos, 'X', val_len);
+ buf_pos += 2 * map->format.val_bytes;
+
+ buf[buf_pos++] = '\n';
+ }
+ p += tot_len;
+ }
+
+ ret = buf_pos;
+
+ if (copy_to_user(user_buf, buf, buf_pos)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ *ppos += buf_pos;
+
+out:
+ kfree(buf);
+ return ret;
+}
+
+static const struct file_operations regmap_map_fops = {
+ .open = regmap_open_file,
+ .read = regmap_map_read_file,
+ .llseek = default_llseek,
+};
+
+static ssize_t regmap_access_read_file(struct file *file,
+ char __user *user_buf, size_t count,
+ loff_t *ppos)
+{
+ int reg_len, tot_len;
+ size_t buf_pos = 0;
+ loff_t p = 0;
+ ssize_t ret;
+ int i;
+ struct regmap *map = file->private_data;
+ char *buf;
+
+ if (*ppos < 0 || !count)
+ return -EINVAL;
+
+ buf = kmalloc(count, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ /* Calculate the length of a fixed format */
+ reg_len = regmap_calc_reg_len(map->max_register, buf, count);
+ tot_len = reg_len + 10; /* ': R W V P\n' */
+
+ for (i = 0; i < map->max_register + 1; i++) {
+ /* Ignore registers which are neither readable nor writable */
+ if (!regmap_readable(map, i) && !regmap_writeable(map, i))
+ continue;
+
+ /* If we're in the region the user is trying to read */
+ if (p >= *ppos) {
+ /* ...but not beyond it */
+ if (buf_pos >= count - 1 - tot_len)
+ break;
+
+ /* Format the register */
+ snprintf(buf + buf_pos, count - buf_pos,
+ "%.*x: %c %c %c %c\n",
+ reg_len, i,
+ regmap_readable(map, i) ? 'y' : 'n',
+ regmap_writeable(map, i) ? 'y' : 'n',
+ regmap_volatile(map, i) ? 'y' : 'n',
+ regmap_precious(map, i) ? 'y' : 'n');
+
+ buf_pos += tot_len;
+ }
+ p += tot_len;
+ }
+
+ ret = buf_pos;
+
+ if (copy_to_user(user_buf, buf, buf_pos)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ *ppos += buf_pos;
+
+out:
+ kfree(buf);
+ return ret;
+}
+
+static const struct file_operations regmap_access_fops = {
+ .open = regmap_open_file,
+ .read = regmap_access_read_file,
+ .llseek = default_llseek,
+};
+
+void regmap_debugfs_init(struct regmap *map)
+{
+ map->debugfs = debugfs_create_dir(dev_name(map->dev),
+ regmap_debugfs_root);
+ if (!map->debugfs) {
+ dev_warn(map->dev, "Failed to create debugfs directory\n");
+ return;
+ }
+
+ if (map->max_register) {
+ debugfs_create_file("registers", 0400, map->debugfs,
+ map, &regmap_map_fops);
+ debugfs_create_file("access", 0400, map->debugfs,
+ map, &regmap_access_fops);
+ }
+}
+
+void regmap_debugfs_exit(struct regmap *map)
+{
+ debugfs_remove_recursive(map->debugfs);
+}
+
+void regmap_debugfs_initcall(void)
+{
+ regmap_debugfs_root = debugfs_create_dir("regmap", NULL);
+ if (!regmap_debugfs_root) {
+ pr_warn("regmap: Failed to create debugfs root\n");
+ return;
+ }
+}
diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c
index c4f7a45cd2c3..38621ec87c05 100644
--- a/drivers/base/regmap/regmap-i2c.c
+++ b/drivers/base/regmap/regmap-i2c.c
@@ -90,11 +90,9 @@ static int regmap_i2c_read(struct device *dev,
}
static struct regmap_bus regmap_i2c = {
- .type = &i2c_bus_type,
.write = regmap_i2c_write,
.gather_write = regmap_i2c_gather_write,
.read = regmap_i2c_read,
- .owner = THIS_MODULE,
};
/**
diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c
index f8396945d6ed..2560658de344 100644
--- a/drivers/base/regmap/regmap-spi.c
+++ b/drivers/base/regmap/regmap-spi.c
@@ -48,11 +48,9 @@ static int regmap_spi_read(struct device *dev,
}
static struct regmap_bus regmap_spi = {
- .type = &spi_bus_type,
.write = regmap_spi_write,
.gather_write = regmap_spi_gather_write,
.read = regmap_spi_read,
- .owner = THIS_MODULE,
.read_flag_mask = 0x80,
};
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 0eef4da1ac61..bf441db1ee90 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -15,29 +15,54 @@
#include <linux/mutex.h>
#include <linux/err.h>
-#include <linux/regmap.h>
-
-struct regmap;
-
-struct regmap_format {
- size_t buf_size;
- size_t reg_bytes;
- size_t val_bytes;
- void (*format_write)(struct regmap *map,
- unsigned int reg, unsigned int val);
- void (*format_reg)(void *buf, unsigned int reg);
- void (*format_val)(void *buf, unsigned int val);
- unsigned int (*parse_val)(void *buf);
-};
-
-struct regmap {
- struct mutex lock;
-
- struct device *dev; /* Device we do I/O on */
- void *work_buf; /* Scratch buffer used to format I/O */
- struct regmap_format format; /* Buffer format */
- const struct regmap_bus *bus;
-};
+#define CREATE_TRACE_POINTS
+#include <trace/events/regmap.h>
+
+#include "internal.h"
+
+bool regmap_writeable(struct regmap *map, unsigned int reg)
+{
+ if (map->max_register && reg > map->max_register)
+ return false;
+
+ if (map->writeable_reg)
+ return map->writeable_reg(map->dev, reg);
+
+ return true;
+}
+
+bool regmap_readable(struct regmap *map, unsigned int reg)
+{
+ if (map->max_register && reg > map->max_register)
+ return false;
+
+ if (map->readable_reg)
+ return map->readable_reg(map->dev, reg);
+
+ return true;
+}
+
+bool regmap_volatile(struct regmap *map, unsigned int reg)
+{
+ if (map->max_register && reg > map->max_register)
+ return false;
+
+ if (map->volatile_reg)
+ return map->volatile_reg(map->dev, reg);
+
+ return true;
+}
+
+bool regmap_precious(struct regmap *map, unsigned int reg)
+{
+ if (map->max_register && reg > map->max_register)
+ return false;
+
+ if (map->precious_reg)
+ return map->precious_reg(map->dev, reg);
+
+ return false;
+}
static void regmap_format_4_12_write(struct regmap *map,
unsigned int reg, unsigned int val)
@@ -116,6 +141,25 @@ struct regmap *regmap_init(struct device *dev,
map->format.val_bytes = config->val_bits / 8;
map->dev = dev;
map->bus = bus;
+ map->max_register = config->max_register;
+ map->writeable_reg = config->writeable_reg;
+ map->readable_reg = config->readable_reg;
+ map->volatile_reg = config->volatile_reg;
+ map->precious_reg = config->precious_reg;
+ map->cache_type = config->cache_type;
+ map->reg_defaults = config->reg_defaults;
+ map->num_reg_defaults = config->num_reg_defaults;
+ map->num_reg_defaults_raw = config->num_reg_defaults_raw;
+ map->reg_defaults_raw = config->reg_defaults_raw;
+ map->cache_size_raw = (config->val_bits / 8) * config->num_reg_defaults_raw;
+ map->cache_word_size = config->val_bits / 8;
+
+ if (config->read_flag_mask || config->write_flag_mask) {
+ map->read_flag_mask = config->read_flag_mask;
+ map->write_flag_mask = config->write_flag_mask;
+ } else {
+ map->read_flag_mask = bus->read_flag_mask;
+ }
switch (config->reg_bits) {
case 4:
@@ -168,13 +212,17 @@ struct regmap *regmap_init(struct device *dev,
map->work_buf = kmalloc(map->format.buf_size, GFP_KERNEL);
if (map->work_buf == NULL) {
ret = -ENOMEM;
- goto err_bus;
+ goto err_map;
}
+ ret = regcache_init(map);
+ if (ret < 0)
+ goto err_map;
+
+ regmap_debugfs_init(map);
+
return map;
-err_bus:
- module_put(map->bus->owner);
err_map:
kfree(map);
err:
@@ -187,8 +235,9 @@ EXPORT_SYMBOL_GPL(regmap_init);
*/
void regmap_exit(struct regmap *map)
{
+ regcache_exit(map);
+ regmap_debugfs_exit(map);
kfree(map->work_buf);
- module_put(map->bus->owner);
kfree(map);
}
EXPORT_SYMBOL_GPL(regmap_exit);
@@ -196,19 +245,38 @@ EXPORT_SYMBOL_GPL(regmap_exit);
static int _regmap_raw_write(struct regmap *map, unsigned int reg,
const void *val, size_t val_len)
{
+ u8 *u8 = map->work_buf;
void *buf;
int ret = -ENOTSUPP;
size_t len;
+ int i;
+
+ /* Check for unwritable registers before we start */
+ if (map->writeable_reg)
+ for (i = 0; i < val_len / map->format.val_bytes; i++)
+ if (!map->writeable_reg(map->dev, reg + i))
+ return -EINVAL;
map->format.format_reg(map->work_buf, reg);
- /* Try to do a gather write if we can */
- if (map->bus->gather_write)
+ u8[0] |= map->write_flag_mask;
+
+ trace_regmap_hw_write_start(map->dev, reg,
+ val_len / map->format.val_bytes);
+
+ /* If we're doing a single register write we can probably just
+ * send the work_buf directly, otherwise try to do a gather
+ * write.
+ */
+ if (val == map->work_buf + map->format.reg_bytes)
+ ret = map->bus->write(map->dev, map->work_buf,
+ map->format.reg_bytes + val_len);
+ else if (map->bus->gather_write)
ret = map->bus->gather_write(map->dev, map->work_buf,
map->format.reg_bytes,
val, val_len);
- /* Otherwise fall back on linearising by hand. */
+ /* If that didn't work fall back on linearising by hand. */
if (ret == -ENOTSUPP) {
len = map->format.reg_bytes + val_len;
buf = kmalloc(len, GFP_KERNEL);
@@ -222,19 +290,39 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
kfree(buf);
}
+ trace_regmap_hw_write_done(map->dev, reg,
+ val_len / map->format.val_bytes);
+
return ret;
}
-static int _regmap_write(struct regmap *map, unsigned int reg,
- unsigned int val)
+int _regmap_write(struct regmap *map, unsigned int reg,
+ unsigned int val)
{
+ int ret;
BUG_ON(!map->format.format_write && !map->format.format_val);
+ if (!map->cache_bypass) {
+ ret = regcache_write(map, reg, val);
+ if (ret != 0)
+ return ret;
+ if (map->cache_only)
+ return 0;
+ }
+
+ trace_regmap_reg_write(map->dev, reg, val);
+
if (map->format.format_write) {
map->format.format_write(map, reg, val);
- return map->bus->write(map->dev, map->work_buf,
- map->format.buf_size);
+ trace_regmap_hw_write_start(map->dev, reg, 1);
+
+ ret = map->bus->write(map->dev, map->work_buf,
+ map->format.buf_size);
+
+ trace_regmap_hw_write_done(map->dev, reg, 1);
+
+ return ret;
} else {
map->format.format_val(map->work_buf + map->format.reg_bytes,
val);
@@ -289,6 +377,8 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
{
int ret;
+ WARN_ON(map->cache_type != REGCACHE_NONE);
+
mutex_lock(&map->lock);
ret = _regmap_raw_write(map, reg, val, val_len);
@@ -308,20 +398,23 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
map->format.format_reg(map->work_buf, reg);
/*
- * Some buses flag reads by setting the high bits in the
+ * Some buses or devices flag reads by setting the high bits in the
* register addresss; since it's always the high bits for all
* current formats we can do this here rather than in
* formatting. This may break if we get interesting formats.
*/
- if (map->bus->read_flag_mask)
- u8[0] |= map->bus->read_flag_mask;
+ u8[0] |= map->read_flag_mask;
+
+ trace_regmap_hw_read_start(map->dev, reg,
+ val_len / map->format.val_bytes);
ret = map->bus->read(map->dev, map->work_buf, map->format.reg_bytes,
val, val_len);
- if (ret != 0)
- return ret;
- return 0;
+ trace_regmap_hw_read_done(map->dev, reg,
+ val_len / map->format.val_bytes);
+
+ return ret;
}
static int _regmap_read(struct regmap *map, unsigned int reg,
@@ -332,9 +425,20 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
if (!map->format.parse_val)
return -EINVAL;
+ if (!map->cache_bypass) {
+ ret = regcache_read(map, reg, val);
+ if (ret == 0)
+ return 0;
+ }
+
+ if (map->cache_only)
+ return -EBUSY;
+
ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes);
- if (ret == 0)
+ if (ret == 0) {
*val = map->format.parse_val(map->work_buf);
+ trace_regmap_reg_read(map->dev, reg, *val);
+ }
return ret;
}
@@ -378,6 +482,14 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
size_t val_len)
{
int ret;
+ int i;
+ bool vol = true;
+
+ for (i = 0; i < val_len / map->format.val_bytes; i++)
+ if (!regmap_volatile(map, reg + i))
+ vol = false;
+
+ WARN_ON(!vol && map->cache_type != REGCACHE_NONE);
mutex_lock(&map->lock);
@@ -405,16 +517,30 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
{
int ret, i;
size_t val_bytes = map->format.val_bytes;
+ bool vol = true;
if (!map->format.parse_val)
return -EINVAL;
- ret = regmap_raw_read(map, reg, val, val_bytes * val_count);
- if (ret != 0)
- return ret;
+ /* Is this a block of volatile registers? */
+ for (i = 0; i < val_count; i++)
+ if (!regmap_volatile(map, reg + i))
+ vol = false;
+
+ if (vol || map->cache_type == REGCACHE_NONE) {
+ ret = regmap_raw_read(map, reg, val, val_bytes * val_count);
+ if (ret != 0)
+ return ret;
- for (i = 0; i < val_count * val_bytes; i += val_bytes)
- map->format.parse_val(val + i);
+ for (i = 0; i < val_count * val_bytes; i += val_bytes)
+ map->format.parse_val(val + i);
+ } else {
+ for (i = 0; i < val_count; i++) {
+ ret = regmap_read(map, reg + i, val + (i * val_bytes));
+ if (ret != 0)
+ return ret;
+ }
+ }
return 0;
}
@@ -453,3 +579,11 @@ out:
return ret;
}
EXPORT_SYMBOL_GPL(regmap_update_bits);
+
+static int __init regmap_initcall(void)
+{
+ regmap_debugfs_initcall();
+
+ return 0;
+}
+postcore_initcall(regmap_initcall);
diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig
index ae0a02e1b808..c1172dafdffa 100644
--- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig
@@ -33,6 +33,19 @@ config BCMA_DRIVER_PCI_HOSTMODE
help
PCI core hostmode operation (external PCI bus).
+config BCMA_HOST_SOC
+ bool
+ depends on BCMA_DRIVER_MIPS
+
+config BCMA_DRIVER_MIPS
+ bool "BCMA Broadcom MIPS core driver"
+ depends on BCMA && MIPS
+ help
+ Driver for the Broadcom MIPS core attached to Broadcom specific
+ Advanced Microcontroller Bus.
+
+ If unsure, say N
+
config BCMA_DEBUG
bool "BCMA debugging"
depends on BCMA
diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile
index a2161cceafb9..82de24e5340c 100644
--- a/drivers/bcma/Makefile
+++ b/drivers/bcma/Makefile
@@ -2,7 +2,9 @@ bcma-y += main.o scan.o core.o sprom.o
bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
bcma-y += driver_pci.o
bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o
+bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o
bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o
+bcma-$(CONFIG_BCMA_HOST_SOC) += host_soc.o
obj-$(CONFIG_BCMA) += bcma.o
ccflags-$(CONFIG_BCMA_DEBUG) := -DDEBUG
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index e02ff21835c9..30a3085d3354 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -15,13 +15,29 @@ struct bcma_bus;
/* main.c */
int bcma_bus_register(struct bcma_bus *bus);
void bcma_bus_unregister(struct bcma_bus *bus);
+int __init bcma_bus_early_register(struct bcma_bus *bus,
+ struct bcma_device *core_cc,
+ struct bcma_device *core_mips);
/* scan.c */
int bcma_bus_scan(struct bcma_bus *bus);
+int __init bcma_bus_scan_early(struct bcma_bus *bus,
+ struct bcma_device_id *match,
+ struct bcma_device *core);
+void bcma_init_bus(struct bcma_bus *bus);
/* sprom.c */
int bcma_sprom_get(struct bcma_bus *bus);
+/* driver_chipcommon.c */
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
+
+/* driver_chipcommon_pmu.c */
+u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
+u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
+
#ifdef CONFIG_BCMA_HOST_PCI
/* host_pci.c */
extern int __init bcma_host_pci_init(void);
diff --git a/drivers/bcma/core.c b/drivers/bcma/core.c
index 4a04a49cc06d..189a97b51be9 100644
--- a/drivers/bcma/core.c
+++ b/drivers/bcma/core.c
@@ -110,6 +110,8 @@ EXPORT_SYMBOL_GPL(bcma_core_pll_ctl);
u32 bcma_core_dma_translation(struct bcma_device *core)
{
switch (core->bus->hosttype) {
+ case BCMA_HOSTTYPE_SOC:
+ return 0;
case BCMA_HOSTTYPE_PCI:
if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64)
return BCMA_DMA_TRANSLATION_DMA64_CMT;
diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c
index 851e05bc948a..47cce9d69630 100644
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
@@ -26,6 +26,9 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
u32 leddc_on = 10;
u32 leddc_off = 90;
+ if (cc->setup_done)
+ return;
+
if (cc->core->id.rev >= 11)
cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
@@ -52,6 +55,8 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
(leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT)));
}
+
+ cc->setup_done = true;
}
/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
@@ -101,3 +106,51 @@ u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value)
{
return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
}
+
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
+{
+ unsigned int irq;
+ u32 baud_base;
+ u32 i;
+ unsigned int ccrev = cc->core->id.rev;
+ struct bcma_serial_port *ports = cc->serial_ports;
+
+ if (ccrev >= 11 && ccrev != 15) {
+ /* Fixed ALP clock */
+ baud_base = bcma_pmu_alp_clock(cc);
+ if (ccrev >= 21) {
+ /* Turn off UART clock before switching clocksource. */
+ bcma_cc_write32(cc, BCMA_CC_CORECTL,
+ bcma_cc_read32(cc, BCMA_CC_CORECTL)
+ & ~BCMA_CC_CORECTL_UARTCLKEN);
+ }
+ /* Set the override bit so we don't divide it */
+ bcma_cc_write32(cc, BCMA_CC_CORECTL,
+ bcma_cc_read32(cc, BCMA_CC_CORECTL)
+ | BCMA_CC_CORECTL_UARTCLK0);
+ if (ccrev >= 21) {
+ /* Re-enable the UART clock. */
+ bcma_cc_write32(cc, BCMA_CC_CORECTL,
+ bcma_cc_read32(cc, BCMA_CC_CORECTL)
+ | BCMA_CC_CORECTL_UARTCLKEN);
+ }
+ } else {
+ pr_err("serial not supported on this device ccrev: 0x%x\n",
+ ccrev);
+ return;
+ }
+
+ irq = bcma_core_mips_irq(cc->core);
+
+ /* Determine the registers of the UARTs */
+ cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);
+ for (i = 0; i < cc->nr_serial_ports; i++) {
+ ports[i].regs = cc->core->io_addr + BCMA_CC_UART0_DATA +
+ (i * 256);
+ ports[i].irq = irq;
+ ports[i].baud_base = baud_base;
+ ports[i].reg_shift = 0;
+ }
+}
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c
index fcc63db0ce75..2968d809d49f 100644
--- a/drivers/bcma/driver_chipcommon_pmu.c
+++ b/drivers/bcma/driver_chipcommon_pmu.c
@@ -11,20 +11,47 @@
#include "bcma_private.h"
#include <linux/bcma/bcma.h>
-static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
- u32 offset, u32 mask, u32 set)
+static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
{
- u32 value;
+ bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
+ bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
+ return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
+}
- bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
+void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
+{
+ bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
+ bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
+ bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
+}
+EXPORT_SYMBOL_GPL(bcma_chipco_pll_write);
+
+void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
+ u32 set)
+{
+ bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
+ bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
+ bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set);
+}
+EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset);
+
+void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
+ u32 offset, u32 mask, u32 set)
+{
bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
- value = bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
- value &= mask;
- value |= set;
- bcma_cc_write32(cc, BCMA_CC_CHIPCTL_DATA, value);
- bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
+ bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set);
+}
+EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset);
+
+void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
+ u32 set)
+{
+ bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset);
+ bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR);
+ bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set);
}
+EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
static void bcma_pmu_pll_init(struct bcma_drv_cc *cc)
{
@@ -83,6 +110,24 @@ void bcma_pmu_swreg_init(struct bcma_drv_cc *cc)
}
}
+/* Disable to allow reading SPROM. Don't know the adventages of enabling it. */
+void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable)
+{
+ struct bcma_bus *bus = cc->core->bus;
+ u32 val;
+
+ val = bcma_cc_read32(cc, BCMA_CC_CHIPCTL);
+ if (enable) {
+ val |= BCMA_CHIPCTL_4331_EXTPA_EN;
+ if (bus->chipinfo.pkg == 9 || bus->chipinfo.pkg == 11)
+ val |= BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
+ } else {
+ val &= ~BCMA_CHIPCTL_4331_EXTPA_EN;
+ val &= ~BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
+ }
+ bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val);
+}
+
void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
{
struct bcma_bus *bus = cc->core->bus;
@@ -92,7 +137,7 @@ void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7);
break;
case 0x4331:
- pr_err("Enabling Ext PA lines not implemented\n");
+ /* BCM4331 workaround is SPROM-related, we put it in sprom.c */
break;
case 43224:
if (bus->chipinfo.rev == 0) {
@@ -136,3 +181,129 @@ void bcma_pmu_init(struct bcma_drv_cc *cc)
bcma_pmu_swreg_init(cc);
bcma_pmu_workarounds(cc);
}
+
+u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
+{
+ struct bcma_bus *bus = cc->core->bus;
+
+ switch (bus->chipinfo.id) {
+ case 0x4716:
+ case 0x4748:
+ case 47162:
+ case 0x4313:
+ case 0x5357:
+ case 0x4749:
+ case 53572:
+ /* always 20Mhz */
+ return 20000 * 1000;
+ case 0x5356:
+ case 0x5300:
+ /* always 25Mhz */
+ return 25000 * 1000;
+ default:
+ pr_warn("No ALP clock specified for %04X device, "
+ "pmu rev. %d, using default %d Hz\n",
+ bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
+ }
+ return BCMA_CC_PMU_ALP_CLOCK;
+}
+
+/* Find the output of the "m" pll divider given pll controls that start with
+ * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
+ */
+static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
+{
+ u32 tmp, div, ndiv, p1, p2, fc;
+ struct bcma_bus *bus = cc->core->bus;
+
+ BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0));
+
+ BUG_ON(!m || m > 4);
+
+ if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) {
+ /* Detect failure in clock setting */
+ tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
+ if (tmp & 0x40000)
+ return 133 * 1000000;
+ }
+
+ tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF);
+ p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT;
+ p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT;
+
+ tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF);
+ div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) &
+ BCMA_CC_PPL_MDIV_MASK;
+
+ tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF);
+ ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;
+
+ /* Do calculation in Mhz */
+ fc = bcma_pmu_alp_clock(cc) / 1000000;
+ fc = (p1 * ndiv * fc) / p2;
+
+ /* Return clock in Hertz */
+ return (fc / div) * 1000000;
+}
+
+/* query bus clock frequency for PMU-enabled chipcommon */
+u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
+{
+ struct bcma_bus *bus = cc->core->bus;
+
+ switch (bus->chipinfo.id) {
+ case 0x4716:
+ case 0x4748:
+ case 47162:
+ return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
+ BCMA_CC_PMU5_MAINPLL_SSB);
+ case 0x5356:
+ return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
+ BCMA_CC_PMU5_MAINPLL_SSB);
+ case 0x5357:
+ case 0x4749:
+ return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
+ BCMA_CC_PMU5_MAINPLL_SSB);
+ case 0x5300:
+ return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0,
+ BCMA_CC_PMU5_MAINPLL_SSB);
+ case 53572:
+ return 75000000;
+ default:
+ pr_warn("No backplane clock specified for %04X device, "
+ "pmu rev. %d, using default %d Hz\n",
+ bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK);
+ }
+ return BCMA_CC_PMU_HT_CLOCK;
+}
+
+/* query cpu clock frequency for PMU-enabled chipcommon */
+u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc)
+{
+ struct bcma_bus *bus = cc->core->bus;
+
+ if (bus->chipinfo.id == 53572)
+ return 300000000;
+
+ if (cc->pmu.rev >= 5) {
+ u32 pll;
+ switch (bus->chipinfo.id) {
+ case 0x5356:
+ pll = BCMA_CC_PMU5356_MAINPLL_PLL0;
+ break;
+ case 0x5357:
+ case 0x4749:
+ pll = BCMA_CC_PMU5357_MAINPLL_PLL0;
+ break;
+ default:
+ pll = BCMA_CC_PMU4716_MAINPLL_PLL0;
+ break;
+ }
+
+ /* TODO: if (bus->chipinfo.id == 0x5300)
+ return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */
+ return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
+ }
+
+ return bcma_pmu_get_clockcontrol(cc);
+}
diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c
new file mode 100644
index 000000000000..c3e9dff4224e
--- /dev/null
+++ b/drivers/bcma/driver_mips.c
@@ -0,0 +1,256 @@
+/*
+ * Broadcom specific AMBA
+ * Broadcom MIPS32 74K core driver
+ *
+ * Copyright 2009, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
+ * Copyright 2010, Bernhard Loos <bernhardloos@googlemail.com>
+ * Copyright 2011, Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+
+#include <linux/bcma/bcma.h>
+
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/time.h>
+
+/* The 47162a0 hangs when reading MIPS DMP registers registers */
+static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
+{
+ return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 &&
+ dev->id.id == BCMA_CORE_MIPS_74K;
+}
+
+/* The 5357b0 hangs when reading USB20H DMP registers */
+static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev)
+{
+ return (dev->bus->chipinfo.id == 0x5357 ||
+ dev->bus->chipinfo.id == 0x4749) &&
+ dev->bus->chipinfo.pkg == 11 &&
+ dev->id.id == BCMA_CORE_USB20_HOST;
+}
+
+static inline u32 mips_read32(struct bcma_drv_mips *mcore,
+ u16 offset)
+{
+ return bcma_read32(mcore->core, offset);
+}
+
+static inline void mips_write32(struct bcma_drv_mips *mcore,
+ u16 offset,
+ u32 value)
+{
+ bcma_write32(mcore->core, offset, value);
+}
+
+static const u32 ipsflag_irq_mask[] = {
+ 0,
+ BCMA_MIPS_IPSFLAG_IRQ1,
+ BCMA_MIPS_IPSFLAG_IRQ2,
+ BCMA_MIPS_IPSFLAG_IRQ3,
+ BCMA_MIPS_IPSFLAG_IRQ4,
+};
+
+static const u32 ipsflag_irq_shift[] = {
+ 0,
+ BCMA_MIPS_IPSFLAG_IRQ1_SHIFT,
+ BCMA_MIPS_IPSFLAG_IRQ2_SHIFT,
+ BCMA_MIPS_IPSFLAG_IRQ3_SHIFT,
+ BCMA_MIPS_IPSFLAG_IRQ4_SHIFT,
+};
+
+static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
+{
+ u32 flag;
+
+ if (bcma_core_mips_bcm47162a0_quirk(dev))
+ return dev->core_index;
+ if (bcma_core_mips_bcm5357b0_quirk(dev))
+ return dev->core_index;
+ flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
+
+ return flag & 0x1F;
+}
+
+/* Get the MIPS IRQ assignment for a specified device.
+ * If unassigned, 0 is returned.
+ */
+unsigned int bcma_core_mips_irq(struct bcma_device *dev)
+{
+ struct bcma_device *mdev = dev->bus->drv_mips.core;
+ u32 irqflag;
+ unsigned int irq;
+
+ irqflag = bcma_core_mips_irqflag(dev);
+
+ for (irq = 1; irq <= 4; irq++)
+ if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
+ (1 << irqflag))
+ return irq;
+
+ return 0;
+}
+EXPORT_SYMBOL(bcma_core_mips_irq);
+
+static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
+{
+ unsigned int oldirq = bcma_core_mips_irq(dev);
+ struct bcma_bus *bus = dev->bus;
+ struct bcma_device *mdev = bus->drv_mips.core;
+ u32 irqflag;
+
+ irqflag = bcma_core_mips_irqflag(dev);
+ BUG_ON(oldirq == 6);
+
+ dev->irq = irq + 2;
+
+ /* clear the old irq */
+ if (oldirq == 0)
+ bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
+ bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
+ ~(1 << irqflag));
+ else
+ bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 0);
+
+ /* assign the new one */
+ if (irq == 0) {
+ bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
+ bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
+ (1 << irqflag));
+ } else {
+ u32 oldirqflag = bcma_read32(mdev,
+ BCMA_MIPS_MIPS74K_INTMASK(irq));
+ if (oldirqflag) {
+ struct bcma_device *core;
+
+ /* backplane irq line is in use, find out who uses
+ * it and set user to irq 0
+ */
+ list_for_each_entry_reverse(core, &bus->cores, list) {
+ if ((1 << bcma_core_mips_irqflag(core)) ==
+ oldirqflag) {
+ bcma_core_mips_set_irq(core, 0);
+ break;
+ }
+ }
+ }
+ bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq),
+ 1 << irqflag);
+ }
+
+ pr_info("set_irq: core 0x%04x, irq %d => %d\n",
+ dev->id.id, oldirq + 2, irq + 2);
+}
+
+static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
+{
+ int i;
+ static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
+ printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
+ for (i = 0; i <= 6; i++)
+ printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
+ printk("\n");
+}
+
+static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
+{
+ struct bcma_device *core;
+
+ list_for_each_entry_reverse(core, &bus->cores, list) {
+ bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
+ }
+}
+
+u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
+{
+ struct bcma_bus *bus = mcore->core->bus;
+
+ if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
+ return bcma_pmu_get_clockcpu(&bus->drv_cc);
+
+ pr_err("No PMU available, need this to get the cpu clock\n");
+ return 0;
+}
+EXPORT_SYMBOL(bcma_cpu_clock);
+
+static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
+{
+ struct bcma_bus *bus = mcore->core->bus;
+
+ switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
+ case BCMA_CC_FLASHT_STSER:
+ case BCMA_CC_FLASHT_ATSER:
+ pr_err("Serial flash not supported.\n");
+ break;
+ case BCMA_CC_FLASHT_PARA:
+ pr_info("found parallel flash.\n");
+ bus->drv_cc.pflash.window = 0x1c000000;
+ bus->drv_cc.pflash.window_size = 0x02000000;
+
+ if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
+ BCMA_CC_FLASH_CFG_DS) == 0)
+ bus->drv_cc.pflash.buswidth = 1;
+ else
+ bus->drv_cc.pflash.buswidth = 2;
+ break;
+ default:
+ pr_err("flash not supported.\n");
+ }
+}
+
+void bcma_core_mips_init(struct bcma_drv_mips *mcore)
+{
+ struct bcma_bus *bus;
+ struct bcma_device *core;
+ bus = mcore->core->bus;
+
+ pr_info("Initializing MIPS core...\n");
+
+ if (!mcore->setup_done)
+ mcore->assigned_irqs = 1;
+
+ /* Assign IRQs to all cores on the bus */
+ list_for_each_entry_reverse(core, &bus->cores, list) {
+ int mips_irq;
+ if (core->irq)
+ continue;
+
+ mips_irq = bcma_core_mips_irq(core);
+ if (mips_irq > 4)
+ core->irq = 0;
+ else
+ core->irq = mips_irq + 2;
+ if (core->irq > 5)
+ continue;
+ switch (core->id.id) {
+ case BCMA_CORE_PCI:
+ case BCMA_CORE_PCIE:
+ case BCMA_CORE_ETHERNET:
+ case BCMA_CORE_ETHERNET_GBIT:
+ case BCMA_CORE_MAC_GBIT:
+ case BCMA_CORE_80211:
+ case BCMA_CORE_USB20_HOST:
+ /* These devices get their own IRQ line if available,
+ * the rest goes on IRQ0
+ */
+ if (mcore->assigned_irqs <= 4)
+ bcma_core_mips_set_irq(core,
+ mcore->assigned_irqs++);
+ break;
+ }
+ }
+ pr_info("IRQ reconfiguration done\n");
+ bcma_core_mips_dump_irq(bus);
+
+ if (mcore->setup_done)
+ return;
+
+ bcma_chipco_serial_init(&bus->drv_cc);
+ bcma_core_mips_flash_detect(mcore);
+ mcore->setup_done = true;
+}
diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c
index 25f3ddf33823..81f3d0a4b856 100644
--- a/drivers/bcma/driver_pci.c
+++ b/drivers/bcma/driver_pci.c
@@ -173,7 +173,7 @@ static bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
return false;
#ifdef CONFIG_SSB_DRIVER_PCICORE
- if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
+ if (bus->sprom.boardflags_lo & SSB_BFL_NOPCI)
return false;
#endif /* CONFIG_SSB_DRIVER_PCICORE */
@@ -189,6 +189,9 @@ static bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
void bcma_core_pci_init(struct bcma_drv_pci *pc)
{
+ if (pc->setup_done)
+ return;
+
if (bcma_core_pci_is_in_hostmode(pc)) {
#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
bcma_core_pci_hostmode_init(pc);
@@ -198,6 +201,8 @@ void bcma_core_pci_init(struct bcma_drv_pci *pc)
} else {
bcma_core_pci_clientmode_init(pc);
}
+
+ pc->setup_done = true;
}
int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
@@ -205,7 +210,14 @@ int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
{
struct pci_dev *pdev = pc->core->bus->host_pci;
u32 coremask, tmp;
- int err;
+ int err = 0;
+
+ if (core->bus->hosttype != BCMA_HOSTTYPE_PCI) {
+ /* This bcma device is not on a PCI host-bus. So the IRQs are
+ * not routed through the PCI core.
+ * So we must not enable routing through the PCI core. */
+ goto out;
+ }
err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
if (err)
diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c
new file mode 100644
index 000000000000..3c381fb8f9c4
--- /dev/null
+++ b/drivers/bcma/host_soc.c
@@ -0,0 +1,183 @@
+/*
+ * Broadcom specific AMBA
+ * System on Chip (SoC) Host
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include "scan.h"
+#include <linux/bcma/bcma.h>
+#include <linux/bcma/bcma_soc.h>
+
+static u8 bcma_host_soc_read8(struct bcma_device *core, u16 offset)
+{
+ return readb(core->io_addr + offset);
+}
+
+static u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset)
+{
+ return readw(core->io_addr + offset);
+}
+
+static u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset)
+{
+ return readl(core->io_addr + offset);
+}
+
+static void bcma_host_soc_write8(struct bcma_device *core, u16 offset,
+ u8 value)
+{
+ writeb(value, core->io_addr + offset);
+}
+
+static void bcma_host_soc_write16(struct bcma_device *core, u16 offset,
+ u16 value)
+{
+ writew(value, core->io_addr + offset);
+}
+
+static void bcma_host_soc_write32(struct bcma_device *core, u16 offset,
+ u32 value)
+{
+ writel(value, core->io_addr + offset);
+}
+
+#ifdef CONFIG_BCMA_BLOCKIO
+static void bcma_host_soc_block_read(struct bcma_device *core, void *buffer,
+ size_t count, u16 offset, u8 reg_width)
+{
+ void __iomem *addr = core->io_addr + offset;
+
+ switch (reg_width) {
+ case sizeof(u8): {
+ u8 *buf = buffer;
+
+ while (count) {
+ *buf = __raw_readb(addr);
+ buf++;
+ count--;
+ }
+ break;
+ }
+ case sizeof(u16): {
+ __le16 *buf = buffer;
+
+ WARN_ON(count & 1);
+ while (count) {
+ *buf = (__force __le16)__raw_readw(addr);
+ buf++;
+ count -= 2;
+ }
+ break;
+ }
+ case sizeof(u32): {
+ __le32 *buf = buffer;
+
+ WARN_ON(count & 3);
+ while (count) {
+ *buf = (__force __le32)__raw_readl(addr);
+ buf++;
+ count -= 4;
+ }
+ break;
+ }
+ default:
+ WARN_ON(1);
+ }
+}
+
+static void bcma_host_soc_block_write(struct bcma_device *core,
+ const void *buffer,
+ size_t count, u16 offset, u8 reg_width)
+{
+ void __iomem *addr = core->io_addr + offset;
+
+ switch (reg_width) {
+ case sizeof(u8): {
+ const u8 *buf = buffer;
+
+ while (count) {
+ __raw_writeb(*buf, addr);
+ buf++;
+ count--;
+ }
+ break;
+ }
+ case sizeof(u16): {
+ const __le16 *buf = buffer;
+
+ WARN_ON(count & 1);
+ while (count) {
+ __raw_writew((__force u16)(*buf), addr);
+ buf++;
+ count -= 2;
+ }
+ break;
+ }
+ case sizeof(u32): {
+ const __le32 *buf = buffer;
+
+ WARN_ON(count & 3);
+ while (count) {
+ __raw_writel((__force u32)(*buf), addr);
+ buf++;
+ count -= 4;
+ }
+ break;
+ }
+ default:
+ WARN_ON(1);
+ }
+}
+#endif /* CONFIG_BCMA_BLOCKIO */
+
+static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset)
+{
+ return readl(core->io_wrap + offset);
+}
+
+static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset,
+ u32 value)
+{
+ writel(value, core->io_wrap + offset);
+}
+
+const struct bcma_host_ops bcma_host_soc_ops = {
+ .read8 = bcma_host_soc_read8,
+ .read16 = bcma_host_soc_read16,
+ .read32 = bcma_host_soc_read32,
+ .write8 = bcma_host_soc_write8,
+ .write16 = bcma_host_soc_write16,
+ .write32 = bcma_host_soc_write32,
+#ifdef CONFIG_BCMA_BLOCKIO
+ .block_read = bcma_host_soc_block_read,
+ .block_write = bcma_host_soc_block_write,
+#endif
+ .aread32 = bcma_host_soc_aread32,
+ .awrite32 = bcma_host_soc_awrite32,
+};
+
+int __init bcma_host_soc_register(struct bcma_soc *soc)
+{
+ struct bcma_bus *bus = &soc->bus;
+ int err;
+
+ /* iomap only first core. We have to read some register on this core
+ * to scan the bus.
+ */
+ bus->mmio = ioremap_nocache(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1);
+ if (!bus->mmio)
+ return -ENOMEM;
+
+ /* Host specific */
+ bus->hosttype = BCMA_HOSTTYPE_SOC;
+ bus->ops = &bcma_host_soc_ops;
+
+ /* Register */
+ err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
+ if (err)
+ iounmap(bus->mmio);
+
+ return err;
+}
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index 873e2e4ac55f..8c09c3e547cd 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -15,6 +15,7 @@ MODULE_LICENSE("GPL");
static int bcma_bus_match(struct device *dev, struct device_driver *drv);
static int bcma_device_probe(struct device *dev);
static int bcma_device_remove(struct device *dev);
+static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env);
static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -49,6 +50,7 @@ static struct bus_type bcma_bus_type = {
.match = bcma_bus_match,
.probe = bcma_device_probe,
.remove = bcma_device_remove,
+ .uevent = bcma_device_uevent,
.dev_attrs = bcma_device_attrs,
};
@@ -66,6 +68,10 @@ static struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid)
static void bcma_release_core_dev(struct device *dev)
{
struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+ if (core->io_addr)
+ iounmap(core->io_addr);
+ if (core->io_wrap)
+ iounmap(core->io_wrap);
kfree(core);
}
@@ -80,6 +86,7 @@ static int bcma_register_cores(struct bcma_bus *bus)
case BCMA_CORE_CHIPCOMMON:
case BCMA_CORE_PCI:
case BCMA_CORE_PCIE:
+ case BCMA_CORE_MIPS_74K:
continue;
}
@@ -93,7 +100,10 @@ static int bcma_register_cores(struct bcma_bus *bus)
core->dma_dev = &bus->host_pci->dev;
core->irq = bus->host_pci->irq;
break;
- case BCMA_HOSTTYPE_NONE:
+ case BCMA_HOSTTYPE_SOC:
+ core->dev.dma_mask = &core->dev.coherent_dma_mask;
+ core->dma_dev = &core->dev;
+ break;
case BCMA_HOSTTYPE_SDIO:
break;
}
@@ -140,6 +150,13 @@ int bcma_bus_register(struct bcma_bus *bus)
bcma_core_chipcommon_init(&bus->drv_cc);
}
+ /* Init MIPS core */
+ core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
+ if (core) {
+ bus->drv_mips.core = core;
+ bcma_core_mips_init(&bus->drv_mips);
+ }
+
/* Init PCIE core */
core = bcma_find_core(bus, BCMA_CORE_PCIE);
if (core) {
@@ -169,6 +186,59 @@ void bcma_bus_unregister(struct bcma_bus *bus)
bcma_unregister_cores(bus);
}
+int __init bcma_bus_early_register(struct bcma_bus *bus,
+ struct bcma_device *core_cc,
+ struct bcma_device *core_mips)
+{
+ int err;
+ struct bcma_device *core;
+ struct bcma_device_id match;
+
+ bcma_init_bus(bus);
+
+ match.manuf = BCMA_MANUF_BCM;
+ match.id = BCMA_CORE_CHIPCOMMON;
+ match.class = BCMA_CL_SIM;
+ match.rev = BCMA_ANY_REV;
+
+ /* Scan for chip common core */
+ err = bcma_bus_scan_early(bus, &match, core_cc);
+ if (err) {
+ pr_err("Failed to scan for common core: %d\n", err);
+ return -1;
+ }
+
+ match.manuf = BCMA_MANUF_MIPS;
+ match.id = BCMA_CORE_MIPS_74K;
+ match.class = BCMA_CL_SIM;
+ match.rev = BCMA_ANY_REV;
+
+ /* Scan for mips core */
+ err = bcma_bus_scan_early(bus, &match, core_mips);
+ if (err) {
+ pr_err("Failed to scan for mips core: %d\n", err);
+ return -1;
+ }
+
+ /* Init CC core */
+ core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
+ if (core) {
+ bus->drv_cc.core = core;
+ bcma_core_chipcommon_init(&bus->drv_cc);
+ }
+
+ /* Init MIPS core */
+ core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
+ if (core) {
+ bus->drv_mips.core = core;
+ bcma_core_mips_init(&bus->drv_mips);
+ }
+
+ pr_info("Early bus registered\n");
+
+ return 0;
+}
+
int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
{
drv->drv.name = drv->name;
@@ -227,6 +297,16 @@ static int bcma_device_remove(struct device *dev)
return 0;
}
+static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+
+ return add_uevent_var(env,
+ "MODALIAS=bcma:m%04Xid%04Xrev%02Xcl%02X",
+ core->id.manuf, core->id.id,
+ core->id.rev, core->id.class);
+}
+
static int __init bcma_modinit(void)
{
int err;
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index 40d7dcce8933..cad994857683 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -200,18 +200,162 @@ static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr,
return addrl;
}
-int bcma_bus_scan(struct bcma_bus *bus)
+static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus,
+ u16 index)
{
- u32 erombase;
- u32 __iomem *eromptr, *eromend;
+ struct bcma_device *core;
+ list_for_each_entry(core, &bus->cores, list) {
+ if (core->core_index == index)
+ return core;
+ }
+ return NULL;
+}
+
+static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
+ struct bcma_device_id *match, int core_num,
+ struct bcma_device *core)
+{
+ s32 tmp;
+ u8 i, j;
s32 cia, cib;
u8 ports[2], wrappers[2];
+ /* get CIs */
+ cia = bcma_erom_get_ci(bus, eromptr);
+ if (cia < 0) {
+ bcma_erom_push_ent(eromptr);
+ if (bcma_erom_is_end(bus, eromptr))
+ return -ESPIPE;
+ return -EILSEQ;
+ }
+ cib = bcma_erom_get_ci(bus, eromptr);
+ if (cib < 0)
+ return -EILSEQ;
+
+ /* parse CIs */
+ core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
+ core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
+ core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
+ ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
+ ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
+ wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
+ wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
+ core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
+
+ if (((core->id.manuf == BCMA_MANUF_ARM) &&
+ (core->id.id == 0xFFF)) ||
+ (ports[1] == 0)) {
+ bcma_erom_skip_component(bus, eromptr);
+ return -ENXIO;
+ }
+
+ /* check if component is a core at all */
+ if (wrappers[0] + wrappers[1] == 0) {
+ /* we could save addrl of the router
+ if (cid == BCMA_CORE_OOB_ROUTER)
+ */
+ bcma_erom_skip_component(bus, eromptr);
+ return -ENXIO;
+ }
+
+ if (bcma_erom_is_bridge(bus, eromptr)) {
+ bcma_erom_skip_component(bus, eromptr);
+ return -ENXIO;
+ }
+
+ if (bcma_find_core_by_index(bus, core_num)) {
+ bcma_erom_skip_component(bus, eromptr);
+ return -ENODEV;
+ }
+
+ if (match && ((match->manuf != BCMA_ANY_MANUF &&
+ match->manuf != core->id.manuf) ||
+ (match->id != BCMA_ANY_ID && match->id != core->id.id) ||
+ (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) ||
+ (match->class != BCMA_ANY_CLASS && match->class != core->id.class)
+ )) {
+ bcma_erom_skip_component(bus, eromptr);
+ return -ENODEV;
+ }
+
+ /* get & parse master ports */
+ for (i = 0; i < ports[0]; i++) {
+ s32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
+ if (mst_port_d < 0)
+ return -EILSEQ;
+ }
+
+ /* get & parse slave ports */
+ for (i = 0; i < ports[1]; i++) {
+ for (j = 0; ; j++) {
+ tmp = bcma_erom_get_addr_desc(bus, eromptr,
+ SCAN_ADDR_TYPE_SLAVE, i);
+ if (tmp < 0) {
+ /* no more entries for port _i_ */
+ /* pr_debug("erom: slave port %d "
+ * "has %d descriptors\n", i, j); */
+ break;
+ } else {
+ if (i == 0 && j == 0)
+ core->addr = tmp;
+ }
+ }
+ }
+
+ /* get & parse master wrappers */
+ for (i = 0; i < wrappers[0]; i++) {
+ for (j = 0; ; j++) {
+ tmp = bcma_erom_get_addr_desc(bus, eromptr,
+ SCAN_ADDR_TYPE_MWRAP, i);
+ if (tmp < 0) {
+ /* no more entries for port _i_ */
+ /* pr_debug("erom: master wrapper %d "
+ * "has %d descriptors\n", i, j); */
+ break;
+ } else {
+ if (i == 0 && j == 0)
+ core->wrap = tmp;
+ }
+ }
+ }
+
+ /* get & parse slave wrappers */
+ for (i = 0; i < wrappers[1]; i++) {
+ u8 hack = (ports[1] == 1) ? 0 : 1;
+ for (j = 0; ; j++) {
+ tmp = bcma_erom_get_addr_desc(bus, eromptr,
+ SCAN_ADDR_TYPE_SWRAP, i + hack);
+ if (tmp < 0) {
+ /* no more entries for port _i_ */
+ /* pr_debug("erom: master wrapper %d "
+ * has %d descriptors\n", i, j); */
+ break;
+ } else {
+ if (wrappers[0] == 0 && !i && !j)
+ core->wrap = tmp;
+ }
+ }
+ }
+ if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
+ core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE);
+ if (!core->io_addr)
+ return -ENOMEM;
+ core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE);
+ if (!core->io_wrap) {
+ iounmap(core->io_addr);
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+void bcma_init_bus(struct bcma_bus *bus)
+{
s32 tmp;
- u8 i, j;
- int err;
+ if (bus->init_done)
+ return;
INIT_LIST_HEAD(&bus->cores);
bus->nr_cores = 0;
@@ -222,9 +366,27 @@ int bcma_bus_scan(struct bcma_bus *bus)
bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
+ bus->init_done = true;
+}
+
+int bcma_bus_scan(struct bcma_bus *bus)
+{
+ u32 erombase;
+ u32 __iomem *eromptr, *eromend;
+
+ int err, core_num = 0;
+
+ bcma_init_bus(bus);
erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
- eromptr = bus->mmio;
+ if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
+ eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
+ if (!eromptr)
+ return -ENOMEM;
+ } else {
+ eromptr = bus->mmio;
+ }
+
eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
bcma_scan_switch_core(bus, erombase);
@@ -236,125 +398,89 @@ int bcma_bus_scan(struct bcma_bus *bus)
INIT_LIST_HEAD(&core->list);
core->bus = bus;
- /* get CIs */
- cia = bcma_erom_get_ci(bus, &eromptr);
- if (cia < 0) {
- bcma_erom_push_ent(&eromptr);
- if (bcma_erom_is_end(bus, &eromptr))
- break;
- err= -EILSEQ;
- goto out;
- }
- cib = bcma_erom_get_ci(bus, &eromptr);
- if (cib < 0) {
- err= -EILSEQ;
- goto out;
- }
-
- /* parse CIs */
- core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
- core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
- core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
- ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
- ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
- wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
- wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
- core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
-
- if (((core->id.manuf == BCMA_MANUF_ARM) &&
- (core->id.id == 0xFFF)) ||
- (ports[1] == 0)) {
- bcma_erom_skip_component(bus, &eromptr);
+ err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core);
+ if (err == -ENODEV) {
+ core_num++;
continue;
- }
-
- /* check if component is a core at all */
- if (wrappers[0] + wrappers[1] == 0) {
- /* we could save addrl of the router
- if (cid == BCMA_CORE_OOB_ROUTER)
- */
- bcma_erom_skip_component(bus, &eromptr);
+ } else if (err == -ENXIO)
continue;
- }
+ else if (err == -ESPIPE)
+ break;
+ else if (err < 0)
+ return err;
- if (bcma_erom_is_bridge(bus, &eromptr)) {
- bcma_erom_skip_component(bus, &eromptr);
- continue;
- }
+ core->core_index = core_num++;
+ bus->nr_cores++;
- /* get & parse master ports */
- for (i = 0; i < ports[0]; i++) {
- u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr);
- if (mst_port_d < 0) {
- err= -EILSEQ;
- goto out;
- }
- }
+ pr_info("Core %d found: %s "
+ "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
+ core->core_index, bcma_device_name(&core->id),
+ core->id.manuf, core->id.id, core->id.rev,
+ core->id.class);
- /* get & parse slave ports */
- for (i = 0; i < ports[1]; i++) {
- for (j = 0; ; j++) {
- tmp = bcma_erom_get_addr_desc(bus, &eromptr,
- SCAN_ADDR_TYPE_SLAVE, i);
- if (tmp < 0) {
- /* no more entries for port _i_ */
- /* pr_debug("erom: slave port %d "
- * "has %d descriptors\n", i, j); */
- break;
- } else {
- if (i == 0 && j == 0)
- core->addr = tmp;
- }
- }
- }
+ list_add(&core->list, &bus->cores);
+ }
- /* get & parse master wrappers */
- for (i = 0; i < wrappers[0]; i++) {
- for (j = 0; ; j++) {
- tmp = bcma_erom_get_addr_desc(bus, &eromptr,
- SCAN_ADDR_TYPE_MWRAP, i);
- if (tmp < 0) {
- /* no more entries for port _i_ */
- /* pr_debug("erom: master wrapper %d "
- * "has %d descriptors\n", i, j); */
- break;
- } else {
- if (i == 0 && j == 0)
- core->wrap = tmp;
- }
- }
- }
+ if (bus->hosttype == BCMA_HOSTTYPE_SOC)
+ iounmap(eromptr);
- /* get & parse slave wrappers */
- for (i = 0; i < wrappers[1]; i++) {
- u8 hack = (ports[1] == 1) ? 0 : 1;
- for (j = 0; ; j++) {
- tmp = bcma_erom_get_addr_desc(bus, &eromptr,
- SCAN_ADDR_TYPE_SWRAP, i + hack);
- if (tmp < 0) {
- /* no more entries for port _i_ */
- /* pr_debug("erom: master wrapper %d "
- * has %d descriptors\n", i, j); */
- break;
- } else {
- if (wrappers[0] == 0 && !i && !j)
- core->wrap = tmp;
- }
- }
- }
+ return 0;
+}
+
+int __init bcma_bus_scan_early(struct bcma_bus *bus,
+ struct bcma_device_id *match,
+ struct bcma_device *core)
+{
+ u32 erombase;
+ u32 __iomem *eromptr, *eromend;
+
+ int err = -ENODEV;
+ int core_num = 0;
+
+ erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
+ if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
+ eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
+ if (!eromptr)
+ return -ENOMEM;
+ } else {
+ eromptr = bus->mmio;
+ }
+
+ eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
+
+ bcma_scan_switch_core(bus, erombase);
+
+ while (eromptr < eromend) {
+ memset(core, 0, sizeof(*core));
+ INIT_LIST_HEAD(&core->list);
+ core->bus = bus;
+ err = bcma_get_next_core(bus, &eromptr, match, core_num, core);
+ if (err == -ENODEV) {
+ core_num++;
+ continue;
+ } else if (err == -ENXIO)
+ continue;
+ else if (err == -ESPIPE)
+ break;
+ else if (err < 0)
+ return err;
+
+ core->core_index = core_num++;
+ bus->nr_cores++;
pr_info("Core %d found: %s "
"(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
- bus->nr_cores, bcma_device_name(&core->id),
+ core->core_index, bcma_device_name(&core->id),
core->id.manuf, core->id.id, core->id.rev,
core->id.class);
- core->core_index = bus->nr_cores++;
list_add(&core->list, &bus->cores);
- continue;
-out:
- return err;
+ err = 0;
+ break;
}
- return 0;
+ if (bus->hosttype == BCMA_HOSTTYPE_SOC)
+ iounmap(eromptr);
+
+ return err;
}
diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c
index 8b5b7856abe3..d7292390d236 100644
--- a/drivers/bcma/sprom.c
+++ b/drivers/bcma/sprom.c
@@ -133,6 +133,15 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
*(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
}
+
+ bus->sprom.board_rev = sprom[SPOFF(SSB_SPROM8_BOARDREV)];
+
+ bus->sprom.boardflags_lo = sprom[SPOFF(SSB_SPROM8_BFLLO)];
+ bus->sprom.boardflags_hi = sprom[SPOFF(SSB_SPROM8_BFLHI)];
+ bus->sprom.boardflags2_lo = sprom[SPOFF(SSB_SPROM8_BFL2LO)];
+ bus->sprom.boardflags2_hi = sprom[SPOFF(SSB_SPROM8_BFL2HI)];
+
+ bus->sprom.country_code = sprom[SPOFF(SSB_SPROM8_CCODE)];
}
int bcma_sprom_get(struct bcma_bus *bus)
@@ -152,6 +161,9 @@ int bcma_sprom_get(struct bcma_bus *bus)
if (!sprom)
return -ENOMEM;
+ 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 */
@@ -159,6 +171,9 @@ int bcma_sprom_get(struct bcma_bus *bus)
BCMA_CC_SPROM_PCIE6;
bcma_sprom_read(bus, offset, sprom);
+ if (bus->chipinfo.id == 0x4331)
+ bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
+
err = bcma_sprom_valid(sprom);
if (err)
goto out;
diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c
index 7b976296b564..912f585a760f 100644
--- a/drivers/block/drbd/drbd_bitmap.c
+++ b/drivers/block/drbd/drbd_bitmap.c
@@ -378,15 +378,14 @@ static struct page **bm_realloc_pages(struct drbd_bitmap *b, unsigned long want)
* thread. As we have no disk yet, we are not in the IO path,
* not even the IO path of the peer. */
bytes = sizeof(struct page *)*want;
- new_pages = kmalloc(bytes, GFP_KERNEL);
+ new_pages = kzalloc(bytes, GFP_KERNEL);
if (!new_pages) {
- new_pages = vmalloc(bytes);
+ new_pages = vzalloc(bytes);
if (!new_pages)
return NULL;
vmalloced = 1;
}
- memset(new_pages, 0, bytes);
if (want >= have) {
for (i = 0; i < have; i++)
new_pages[i] = old_pages[i];
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index ef2ceed3be4b..1706d60b8c99 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -28,7 +28,6 @@
#include <linux/compiler.h>
#include <linux/types.h>
-#include <linux/version.h>
#include <linux/list.h>
#include <linux/sched.h>
#include <linux/bitops.h>
@@ -928,7 +927,7 @@ struct drbd_md {
#define NL_INT64(pn,pr,member) __u64 member;
#define NL_BIT(pn,pr,member) unsigned member:1;
#define NL_STRING(pn,pr,member,len) unsigned char member[len]; int member ## _len;
-#include "linux/drbd_nl.h"
+#include <linux/drbd_nl.h>
struct drbd_backing_dev {
struct block_device *backing_bdev;
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index 0feab261e295..af2a25049bce 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -94,7 +94,7 @@ static int name ## _from_tags(struct drbd_conf *mdev, \
arg->member ## _len = dlen; \
memcpy(arg->member, tags, min_t(size_t, dlen, len)); \
break;
-#include "linux/drbd_nl.h"
+#include <linux/drbd_nl.h>
/* Generate the struct to tag_list functions */
#define NL_PACKET(name, number, fields) \
@@ -129,7 +129,7 @@ name ## _to_tags(struct drbd_conf *mdev, \
put_unaligned(arg->member ## _len, tags++); \
memcpy(tags, arg->member, arg->member ## _len); \
tags = (unsigned short *)((char *)tags + arg->member ## _len);
-#include "linux/drbd_nl.h"
+#include <linux/drbd_nl.h>
void drbd_bcast_ev_helper(struct drbd_conf *mdev, char *helper_name);
void drbd_nl_send_reply(struct cn_msg *, int);
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 98de8f418676..9955a53733b2 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -4250,7 +4250,7 @@ static int __init floppy_init(void)
use_virtual_dma = can_use_virtual_dma & 1;
fdc_state[0].address = FDC1;
if (fdc_state[0].address == -1) {
- del_timer(&fd_timeout);
+ del_timer_sync(&fd_timeout);
err = -ENODEV;
goto out_unreg_region;
}
@@ -4261,7 +4261,7 @@ static int __init floppy_init(void)
fdc = 0; /* reset fdc in case of unexpected interrupt */
err = floppy_grab_irq_and_dma();
if (err) {
- del_timer(&fd_timeout);
+ del_timer_sync(&fd_timeout);
err = -EBUSY;
goto out_unreg_region;
}
@@ -4318,7 +4318,7 @@ static int __init floppy_init(void)
user_reset_fdc(-1, FD_RESET_ALWAYS, false);
}
fdc = 0;
- del_timer(&fd_timeout);
+ del_timer_sync(&fd_timeout);
current_drive = 0;
initialized = true;
if (have_no_fdc) {
@@ -4368,7 +4368,7 @@ out_unreg_blkdev:
unregister_blkdev(FLOPPY_MAJOR, "fd");
out_put_disk:
while (dr--) {
- del_timer(&motor_off_timer[dr]);
+ del_timer_sync(&motor_off_timer[dr]);
if (disks[dr]->queue)
blk_cleanup_queue(disks[dr]->queue);
put_disk(disks[dr]);
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 15f65b5f3fc7..fe3c3249cec4 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -192,7 +192,7 @@ static ssize_t rbd_snap_add(struct device *dev,
const char *buf,
size_t count);
static void __rbd_remove_snap_dev(struct rbd_device *rbd_dev,
- struct rbd_snap *snap);;
+ struct rbd_snap *snap);
static struct rbd_device *dev_to_rbd(struct device *dev)
diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c
index 2330a9ad5e95..1540792b1e54 100644
--- a/drivers/block/xen-blkback/blkback.c
+++ b/drivers/block/xen-blkback/blkback.c
@@ -396,7 +396,7 @@ static int xen_blkbk_map(struct blkif_request *req,
continue;
ret = m2p_add_override(PFN_DOWN(map[i].dev_bus_addr),
- blkbk->pending_page(pending_req, i), false);
+ blkbk->pending_page(pending_req, i), NULL);
if (ret) {
pr_alert(DRV_PFX "Failed to install M2P override for %lx (ret: %d)\n",
(unsigned long)map[i].dev_bus_addr, ret);
diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h
index 9e40b283a468..c4bd34063ecc 100644
--- a/drivers/block/xen-blkback/common.h
+++ b/drivers/block/xen-blkback/common.h
@@ -27,7 +27,6 @@
#ifndef __XEN_BLKIF__BACKEND__COMMON_H__
#define __XEN_BLKIF__BACKEND__COMMON_H__
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
@@ -46,7 +45,7 @@
#define DRV_PFX "xen-blkback:"
#define DPRINTK(fmt, args...) \
- pr_debug(DRV_PFX "(%s:%d) " fmt ".\n", \
+ pr_debug(DRV_PFX "(%s:%d) " fmt ".\n", \
__func__, __LINE__, ##args)
diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c
index 3f129b45451a..5fd2010f7d2b 100644
--- a/drivers/block/xen-blkback/xenbus.c
+++ b/drivers/block/xen-blkback/xenbus.c
@@ -590,7 +590,7 @@ static void frontend_changed(struct xenbus_device *dev,
/*
* Enforce precondition before potential leak point.
- * blkif_disconnect() is idempotent.
+ * xen_blkif_disconnect() is idempotent.
*/
xen_blkif_disconnect(be->blkif);
@@ -601,17 +601,17 @@ static void frontend_changed(struct xenbus_device *dev,
break;
case XenbusStateClosing:
- xen_blkif_disconnect(be->blkif);
xenbus_switch_state(dev, XenbusStateClosing);
break;
case XenbusStateClosed:
+ xen_blkif_disconnect(be->blkif);
xenbus_switch_state(dev, XenbusStateClosed);
if (xenbus_dev_is_online(dev))
break;
/* fall through if not online */
case XenbusStateUnknown:
- /* implies blkif_disconnect() via blkback_remove() */
+ /* implies xen_blkif_disconnect() via xen_blkbk_remove() */
device_unregister(&dev->dev);
break;
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index a5854735bb2e..db7cb8111fbe 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -63,6 +63,7 @@ static struct usb_device_id ath3k_table[] = {
/* Atheros AR3011 with sflash firmware*/
{ USB_DEVICE(0x0CF3, 0x3002) },
{ USB_DEVICE(0x13d3, 0x3304) },
+ { USB_DEVICE(0x0930, 0x0215) },
/* Atheros AR9285 Malbec with sflash firmware */
{ USB_DEVICE(0x03F0, 0x311D) },
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index 7f521d4ac657..c827d737ccee 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -81,7 +81,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8787 = {
.io_port_2 = 0x7a,
};
-static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = {
+static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
.helper = "sd8688_helper.bin",
.firmware = "sd8688.bin",
.reg = &btmrvl_reg_8688,
@@ -98,7 +98,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
static const struct sdio_device_id btmrvl_sdio_ids[] = {
/* Marvell SD8688 Bluetooth device */
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105),
- .driver_data = (unsigned long) &btmrvl_sdio_sd6888 },
+ .driver_data = (unsigned long) &btmrvl_sdio_sd8688 },
/* Marvell SD8787 Bluetooth device */
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A),
.driver_data = (unsigned long) &btmrvl_sdio_sd8787 },
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 91d13a9e8c65..f9b726091ad0 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -60,6 +60,9 @@ static struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
+ /* Broadcom SoftSailing reporting vendor specific */
+ { USB_DEVICE(0x05ac, 0x21e1) },
+
/* Apple MacBookPro 7,1 */
{ USB_DEVICE(0x05ac, 0x8213) },
@@ -72,9 +75,15 @@ static struct usb_device_id btusb_table[] = {
/* Apple MacBookAir3,1, MacBookAir3,2 */
{ USB_DEVICE(0x05ac, 0x821b) },
+ /* Apple MacBookAir4,1 */
+ { USB_DEVICE(0x05ac, 0x821f) },
+
/* Apple MacBookPro8,2 */
{ USB_DEVICE(0x05ac, 0x821a) },
+ /* Apple MacMini5,1 */
+ { USB_DEVICE(0x05ac, 0x8281) },
+
/* AVM BlueFRITZ! USB v2.0 */
{ USB_DEVICE(0x057c, 0x3800) },
@@ -106,6 +115,7 @@ static struct usb_device_id blacklist_table[] = {
/* Atheros 3011 with sflash firmware */
{ USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
{ USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE },
+ { USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE },
/* Atheros AR9285 Malbec with sflash firmware */
{ USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
@@ -256,7 +266,9 @@ static void btusb_intr_complete(struct urb *urb)
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
- if (err != -EPERM)
+ /* -EPERM: urb is being killed;
+ * -ENODEV: device got disconnected */
+ if (err != -EPERM && err != -ENODEV)
BT_ERR("%s urb %p failed to resubmit (%d)",
hdev->name, urb, -err);
usb_unanchor_urb(urb);
@@ -341,7 +353,9 @@ static void btusb_bulk_complete(struct urb *urb)
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
- if (err != -EPERM)
+ /* -EPERM: urb is being killed;
+ * -ENODEV: device got disconnected */
+ if (err != -EPERM && err != -ENODEV)
BT_ERR("%s urb %p failed to resubmit (%d)",
hdev->name, urb, -err);
usb_unanchor_urb(urb);
@@ -431,7 +445,9 @@ static void btusb_isoc_complete(struct urb *urb)
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
- if (err != -EPERM)
+ /* -EPERM: urb is being killed;
+ * -ENODEV: device got disconnected */
+ if (err != -EPERM && err != -ENODEV)
BT_ERR("%s urb %p failed to resubmit (%d)",
hdev->name, urb, -err);
usb_unanchor_urb(urb);
@@ -695,8 +711,7 @@ static int btusb_send_frame(struct sk_buff *skb)
break;
case HCI_ACLDATA_PKT:
- if (!data->bulk_tx_ep || (hdev->conn_hash.acl_num < 1 &&
- hdev->conn_hash.le_num < 1))
+ if (!data->bulk_tx_ep)
return -ENODEV;
urb = usb_alloc_urb(0, GFP_ATOMIC);
@@ -1103,7 +1118,7 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
return 0;
spin_lock_irq(&data->txlock);
- if (!((message.event & PM_EVENT_AUTO) && data->tx_in_flight)) {
+ if (!(PMSG_IS_AUTO(message) && data->tx_in_flight)) {
set_bit(BTUSB_SUSPENDING, &data->flags);
spin_unlock_irq(&data->txlock);
} else {
diff --git a/drivers/bluetooth/btwilink.c b/drivers/bluetooth/btwilink.c
index 65d27aff553a..04d353f58d71 100644
--- a/drivers/bluetooth/btwilink.c
+++ b/drivers/bluetooth/btwilink.c
@@ -125,6 +125,13 @@ static long st_receive(void *priv_data, struct sk_buff *skb)
/* protocol structure registered with shared transport */
static struct st_proto_s ti_st_proto[MAX_BT_CHNL_IDS] = {
{
+ .chnl_id = HCI_EVENT_PKT, /* HCI Events */
+ .hdr_len = sizeof(struct hci_event_hdr),
+ .offset_len_in_hdr = offsetof(struct hci_event_hdr, plen),
+ .len_size = 1, /* sizeof(plen) in struct hci_event_hdr */
+ .reserve = 8,
+ },
+ {
.chnl_id = HCI_ACLDATA_PKT, /* ACL */
.hdr_len = sizeof(struct hci_acl_hdr),
.offset_len_in_hdr = offsetof(struct hci_acl_hdr, dlen),
@@ -138,13 +145,6 @@ static struct st_proto_s ti_st_proto[MAX_BT_CHNL_IDS] = {
.len_size = 1, /* sizeof(dlen) in struct hci_sco_hdr */
.reserve = 8,
},
- {
- .chnl_id = HCI_EVENT_PKT, /* HCI Events */
- .hdr_len = sizeof(struct hci_event_hdr),
- .offset_len_in_hdr = offsetof(struct hci_event_hdr, plen),
- .len_size = 1, /* sizeof(plen) in struct hci_event_hdr */
- .reserve = 8,
- },
};
/* Called from HCI core to initialize the device */
@@ -240,7 +240,7 @@ static int ti_st_close(struct hci_dev *hdev)
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
return 0;
- for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
+ for (i = MAX_BT_CHNL_IDS-1; i >= 0; i--) {
err = st_unregister(&ti_st_proto[i]);
if (err)
BT_ERR("st_unregister(%d) failed with error %d",
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
index f27d0d0816d3..4b71647782d0 100644
--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -171,7 +171,7 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
}
got_gatt = 1;
- bridge->key_list = vmalloc(PAGE_SIZE * 4);
+ bridge->key_list = vzalloc(PAGE_SIZE * 4);
if (bridge->key_list == NULL) {
dev_err(&bridge->dev->dev,
"can't allocate memory for key lists\n");
@@ -181,7 +181,6 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
got_keylist = 1;
/* FIXME vmalloc'd memory not guaranteed contiguous */
- memset(bridge->key_list, 0, PAGE_SIZE * 4);
if (bridge->driver->configure()) {
dev_err(&bridge->dev->dev, "error configuring host chipset\n");
diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c
index a7346ab97a3c..f4837a893dfa 100644
--- a/drivers/char/apm-emulation.c
+++ b/drivers/char/apm-emulation.c
@@ -40,10 +40,7 @@
#define APM_MINOR_DEV 134
/*
- * See Documentation/Config.help for the configuration options.
- *
- * Various options can be changed at boot time as follows:
- * (We allow underscores for compatibility with the modules code)
+ * One option can be changed at boot time as follows:
* apm=on/off enable/disable APM
*/
@@ -300,17 +297,13 @@ apm_ioctl(struct file *filp, u_int cmd, u_long arg)
/*
* Wait for the suspend/resume to complete. If there
* are pending acknowledges, we wait here for them.
+ * wait_event_freezable() is interruptible and pending
+ * signal can cause busy looping. We aren't doing
+ * anything critical, chill a bit on each iteration.
*/
- freezer_do_not_count();
-
- wait_event(apm_suspend_waitqueue,
- as->suspend_state == SUSPEND_DONE);
-
- /*
- * Since we are waiting until the suspend is done, the
- * try_to_freeze() in freezer_count() will not trigger
- */
- freezer_count();
+ while (wait_event_freezable(apm_suspend_waitqueue,
+ as->suspend_state == SUSPEND_DONE))
+ msleep(10);
break;
case SUSPEND_ACKTO:
as->suspend_result = -ETIMEDOUT;
diff --git a/drivers/char/msm_smd_pkt.c b/drivers/char/msm_smd_pkt.c
index b6f8a65c9960..8eca55deb3a3 100644
--- a/drivers/char/msm_smd_pkt.c
+++ b/drivers/char/msm_smd_pkt.c
@@ -379,9 +379,8 @@ static int __init smd_pkt_init(void)
for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) {
smd_pkt_devp[i] = kzalloc(sizeof(struct smd_pkt_dev),
GFP_KERNEL);
- if (IS_ERR(smd_pkt_devp[i])) {
- r = PTR_ERR(smd_pkt_devp[i]);
- pr_err("kmalloc() failed %d\n", r);
+ if (!smd_pkt_devp[i]) {
+ pr_err("kmalloc() failed\n");
goto clean_cdevs;
}
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index b33e8ea314ed..b6de2c047145 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -324,13 +324,12 @@ static int __init raw_init(void)
max_raw_minors = MAX_RAW_MINORS;
}
- raw_devices = vmalloc(sizeof(struct raw_device_data) * max_raw_minors);
+ raw_devices = vzalloc(sizeof(struct raw_device_data) * max_raw_minors);
if (!raw_devices) {
printk(KERN_ERR "Not enough memory for raw device structures\n");
ret = -ENOMEM;
goto error;
}
- memset(raw_devices, 0, sizeof(struct raw_device_data) * max_raw_minors);
ret = register_chrdev_region(dev, max_raw_minors, "raw");
if (ret)
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index dfa8b3062fda..ccd124ab7ca7 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -80,6 +80,7 @@
#include <linux/bcd.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
+#include <linux/ratelimit.h>
#include <asm/current.h>
#include <asm/system.h>
@@ -1195,10 +1196,8 @@ static void rtc_dropped_irq(unsigned long data)
spin_unlock_irq(&rtc_lock);
- if (printk_ratelimit()) {
- printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n",
- freq);
- }
+ printk_ratelimited(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n",
+ freq);
/* Now we have new data */
wake_up_interruptible(&rtc_wait);
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index f6595aba4f0f..fa567f1158c2 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -43,6 +43,7 @@ config TCG_NSC
config TCG_ATMEL
tristate "Atmel TPM Interface"
+ depends on PPC64 || HAS_IOPORT
---help---
If you have a TPM security chip from Atmel say Yes and it
will be accessible from within Linux. To compile this driver
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index caf8012ef47c..361a1dff8f77 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -383,6 +383,9 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
u32 count, ordinal;
unsigned long stop;
+ if (bufsiz > TPM_BUFSIZE)
+ bufsiz = TPM_BUFSIZE;
+
count = be32_to_cpu(*((__be32 *) (buf + 2)));
ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
if (count == 0)
@@ -963,6 +966,9 @@ ssize_t tpm_show_durations(struct device *dev, struct device_attribute *attr,
{
struct tpm_chip *chip = dev_get_drvdata(dev);
+ if (chip->vendor.duration[TPM_LONG] == 0)
+ return 0;
+
return sprintf(buf, "%d %d %d [%s]\n",
jiffies_to_usecs(chip->vendor.duration[TPM_SHORT]),
jiffies_to_usecs(chip->vendor.duration[TPM_MEDIUM]),
@@ -1102,6 +1108,7 @@ ssize_t tpm_read(struct file *file, char __user *buf,
{
struct tpm_chip *chip = file->private_data;
ssize_t ret_size;
+ int rc;
del_singleshot_timer_sync(&chip->user_read_timer);
flush_work_sync(&chip->work);
@@ -1112,8 +1119,11 @@ ssize_t tpm_read(struct file *file, char __user *buf,
ret_size = size;
mutex_lock(&chip->buffer_mutex);
- if (copy_to_user(buf, chip->data_buffer, ret_size))
+ rc = copy_to_user(buf, chip->data_buffer, ret_size);
+ memset(chip->data_buffer, 0, ret_size);
+ if (rc)
ret_size = -EFAULT;
+
mutex_unlock(&chip->buffer_mutex);
}
diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c
index 82facc9104c7..4d2464871ada 100644
--- a/drivers/char/tpm/tpm_nsc.c
+++ b/drivers/char/tpm/tpm_nsc.c
@@ -396,8 +396,6 @@ static void __exit cleanup_nsc(void)
if (pdev) {
tpm_nsc_remove(&pdev->dev);
platform_device_unregister(pdev);
- kfree(pdev);
- pdev = NULL;
}
platform_driver_unregister(&nsc_drv);
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index dc7c033ef587..32a77becc098 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -26,6 +26,7 @@
#include <linux/clk.h>
#include <linux/irq.h>
#include <linux/err.h>
+#include <linux/delay.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/sh_timer.h>
@@ -150,13 +151,13 @@ static void sh_cmt_start_stop_ch(struct sh_cmt_priv *p, int start)
static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)
{
- int ret;
+ int k, ret;
/* enable clock */
ret = clk_enable(p->clk);
if (ret) {
dev_err(&p->pdev->dev, "cannot enable clock\n");
- return ret;
+ goto err0;
}
/* make sure channel is disabled */
@@ -174,9 +175,38 @@ static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)
sh_cmt_write(p, CMCOR, 0xffffffff);
sh_cmt_write(p, CMCNT, 0);
+ /*
+ * According to the sh73a0 user's manual, as CMCNT can be operated
+ * only by the RCLK (Pseudo 32 KHz), there's one restriction on
+ * modifying CMCNT register; two RCLK cycles are necessary before
+ * this register is either read or any modification of the value
+ * it holds is reflected in the LSI's actual operation.
+ *
+ * While at it, we're supposed to clear out the CMCNT as of this
+ * moment, so make sure it's processed properly here. This will
+ * take RCLKx2 at maximum.
+ */
+ for (k = 0; k < 100; k++) {
+ if (!sh_cmt_read(p, CMCNT))
+ break;
+ udelay(1);
+ }
+
+ if (sh_cmt_read(p, CMCNT)) {
+ dev_err(&p->pdev->dev, "cannot clear CMCNT\n");
+ ret = -ETIMEDOUT;
+ goto err1;
+ }
+
/* enable channel */
sh_cmt_start_stop_ch(p, 1);
return 0;
+ err1:
+ /* stop clock */
+ clk_disable(p->clk);
+
+ err0:
+ return ret;
}
static void sh_cmt_disable(struct sh_cmt_priv *p)
diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
index e55814bc0d06..77e1e6cd66ce 100644
--- a/drivers/connector/cn_proc.c
+++ b/drivers/connector/cn_proc.c
@@ -205,6 +205,32 @@ void proc_ptrace_connector(struct task_struct *task, int ptrace_id)
cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
}
+void proc_comm_connector(struct task_struct *task)
+{
+ struct cn_msg *msg;
+ struct proc_event *ev;
+ struct timespec ts;
+ __u8 buffer[CN_PROC_MSG_SIZE];
+
+ if (atomic_read(&proc_event_num_listeners) < 1)
+ return;
+
+ msg = (struct cn_msg *)buffer;
+ ev = (struct proc_event *)msg->data;
+ get_seq(&msg->seq, &ev->cpu);
+ ktime_get_ts(&ts); /* get high res monotonic timestamp */
+ put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
+ ev->what = PROC_EVENT_COMM;
+ ev->event_data.comm.process_pid = task->pid;
+ ev->event_data.comm.process_tgid = task->tgid;
+ get_task_comm(ev->event_data.comm.comm, task);
+
+ memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
+ msg->ack = 0; /* not used */
+ msg->len = sizeof(*ev);
+ cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+}
+
void proc_exit_connector(struct task_struct *task)
{
struct cn_msg *msg;
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 891360edecdd..629b3ec698e2 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -725,7 +725,7 @@ static int __init cpufreq_gov_dbs_init(void)
dbs_tuners_ins.down_differential =
MICRO_FREQUENCY_DOWN_DIFFERENTIAL;
/*
- * In no_hz/micro accounting case we set the minimum frequency
+ * In nohz/micro accounting case we set the minimum frequency
* not depending on HZ, but fixed (very low). The deferred
* timer might skip some samples if idle/sleeping as needed.
*/
diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c
index 7b0603eb0129..cdc02ac8f41a 100644
--- a/drivers/cpufreq/pcc-cpufreq.c
+++ b/drivers/cpufreq/pcc-cpufreq.c
@@ -261,6 +261,9 @@ static int pcc_get_offset(int cpu)
pr = per_cpu(processors, cpu);
pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu);
+ if (!pr)
+ return -ENODEV;
+
status = acpi_evaluate_object(pr->handle, "PCCP", NULL, &buffer);
if (ACPI_FAILURE(status))
return -ENODEV;
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index d4c542372886..0df014110097 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -12,7 +12,7 @@
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/notifier.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
#include <linux/cpu.h>
#include <linux/cpuidle.h>
#include <linux/ktime.h>
diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c
index 12c98900dcf8..f62fde21e962 100644
--- a/drivers/cpuidle/governors/ladder.c
+++ b/drivers/cpuidle/governors/ladder.c
@@ -14,7 +14,7 @@
#include <linux/kernel.h>
#include <linux/cpuidle.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
#include <linux/moduleparam.h>
#include <linux/jiffies.h>
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index c47f3d09c1ee..3600f1955e48 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -12,7 +12,7 @@
#include <linux/kernel.h>
#include <linux/cpuidle.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
#include <linux/time.h>
#include <linux/ktime.h>
#include <linux/hrtimer.h>
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
new file mode 100644
index 000000000000..643b055ed3cd
--- /dev/null
+++ b/drivers/devfreq/Kconfig
@@ -0,0 +1,75 @@
+config ARCH_HAS_DEVFREQ
+ bool
+ depends on ARCH_HAS_OPP
+ help
+ Denotes that the architecture supports DEVFREQ. If the architecture
+ supports multiple OPP entries per device and the frequency of the
+ devices with OPPs may be altered dynamically, the architecture
+ supports DEVFREQ.
+
+menuconfig PM_DEVFREQ
+ bool "Generic Dynamic Voltage and Frequency Scaling (DVFS) support"
+ depends on PM_OPP && ARCH_HAS_DEVFREQ
+ help
+ With OPP support, a device may have a list of frequencies and
+ voltages available. DEVFREQ, a generic DVFS framework can be
+ registered for a device with OPP support in order to let the
+ governor provided to DEVFREQ choose an operating frequency
+ based on the OPP's list and the policy given with DEVFREQ.
+
+ Each device may have its own governor and policy. DEVFREQ can
+ reevaluate the device state periodically and/or based on the
+ OPP list changes (each frequency/voltage pair in OPP may be
+ disabled or enabled).
+
+ Like some CPUs with CPUFREQ, a device may have multiple clocks.
+ However, because the clock frequencies of a single device are
+ determined by the single device's state, an instance of DEVFREQ
+ is attached to a single device and returns a "representative"
+ clock frequency from the OPP of the device, which is also attached
+ to a device by 1-to-1. The device registering DEVFREQ takes the
+ responsiblity to "interpret" the frequency listed in OPP and
+ to set its every clock accordingly with the "target" callback
+ given to DEVFREQ.
+
+if PM_DEVFREQ
+
+comment "DEVFREQ Governors"
+
+config DEVFREQ_GOV_SIMPLE_ONDEMAND
+ bool "Simple Ondemand"
+ help
+ Chooses frequency based on the recent load on the device. Works
+ similar as ONDEMAND governor of CPUFREQ does. A device with
+ Simple-Ondemand should be able to provide busy/total counter
+ values that imply the usage rate. A device may provide tuned
+ values to the governor with data field at devfreq_add_device().
+
+config DEVFREQ_GOV_PERFORMANCE
+ bool "Performance"
+ help
+ Sets the frequency at the maximum available frequency.
+ This governor always returns UINT_MAX as frequency so that
+ the DEVFREQ framework returns the highest frequency available
+ at any time.
+
+config DEVFREQ_GOV_POWERSAVE
+ bool "Powersave"
+ help
+ Sets the frequency at the minimum available frequency.
+ This governor always returns 0 as frequency so that
+ the DEVFREQ framework returns the lowest frequency available
+ at any time.
+
+config DEVFREQ_GOV_USERSPACE
+ bool "Userspace"
+ help
+ Sets the frequency at the user specified one.
+ This governor returns the user configured frequency if there
+ has been an input to /sys/devices/.../power/devfreq_set_freq.
+ Otherwise, the governor does not change the frequnecy
+ given at the initialization.
+
+comment "DEVFREQ Drivers"
+
+endif # PM_DEVFREQ
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
new file mode 100644
index 000000000000..4564a89e970a
--- /dev/null
+++ b/drivers/devfreq/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_PM_DEVFREQ) += devfreq.o
+obj-$(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND) += governor_simpleondemand.o
+obj-$(CONFIG_DEVFREQ_GOV_PERFORMANCE) += governor_performance.o
+obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE) += governor_powersave.o
+obj-$(CONFIG_DEVFREQ_GOV_USERSPACE) += governor_userspace.o
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
new file mode 100644
index 000000000000..5d15b812377b
--- /dev/null
+++ b/drivers/devfreq/devfreq.c
@@ -0,0 +1,601 @@
+/*
+ * devfreq: Generic Dynamic Voltage and Frequency Scaling (DVFS) Framework
+ * for Non-CPU Devices.
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/opp.h>
+#include <linux/devfreq.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/printk.h>
+#include <linux/hrtimer.h>
+#include "governor.h"
+
+struct class *devfreq_class;
+
+/*
+ * devfreq_work periodically monitors every registered device.
+ * The minimum polling interval is one jiffy. The polling interval is
+ * determined by the minimum polling period among all polling devfreq
+ * devices. The resolution of polling interval is one jiffy.
+ */
+static bool polling;
+static struct workqueue_struct *devfreq_wq;
+static struct delayed_work devfreq_work;
+
+/* wait removing if this is to be removed */
+static struct devfreq *wait_remove_device;
+
+/* The list of all device-devfreq */
+static LIST_HEAD(devfreq_list);
+static DEFINE_MUTEX(devfreq_list_lock);
+
+/**
+ * find_device_devfreq() - find devfreq struct using device pointer
+ * @dev: device pointer used to lookup device devfreq.
+ *
+ * Search the list of device devfreqs and return the matched device's
+ * devfreq info. devfreq_list_lock should be held by the caller.
+ */
+static struct devfreq *find_device_devfreq(struct device *dev)
+{
+ struct devfreq *tmp_devfreq;
+
+ if (unlikely(IS_ERR_OR_NULL(dev))) {
+ pr_err("DEVFREQ: %s: Invalid parameters\n", __func__);
+ return ERR_PTR(-EINVAL);
+ }
+ WARN(!mutex_is_locked(&devfreq_list_lock),
+ "devfreq_list_lock must be locked.");
+
+ list_for_each_entry(tmp_devfreq, &devfreq_list, node) {
+ if (tmp_devfreq->dev.parent == dev)
+ return tmp_devfreq;
+ }
+
+ return ERR_PTR(-ENODEV);
+}
+
+/**
+ * update_devfreq() - Reevaluate the device and configure frequency.
+ * @devfreq: the devfreq instance.
+ *
+ * Note: Lock devfreq->lock before calling update_devfreq
+ * This function is exported for governors.
+ */
+int update_devfreq(struct devfreq *devfreq)
+{
+ unsigned long freq;
+ int err = 0;
+
+ if (!mutex_is_locked(&devfreq->lock)) {
+ WARN(true, "devfreq->lock must be locked by the caller.\n");
+ return -EINVAL;
+ }
+
+ /* Reevaluate the proper frequency */
+ err = devfreq->governor->get_target_freq(devfreq, &freq);
+ if (err)
+ return err;
+
+ err = devfreq->profile->target(devfreq->dev.parent, &freq);
+ if (err)
+ return err;
+
+ devfreq->previous_freq = freq;
+ return err;
+}
+
+/**
+ * devfreq_notifier_call() - Notify that the device frequency requirements
+ * has been changed out of devfreq framework.
+ * @nb the notifier_block (supposed to be devfreq->nb)
+ * @type not used
+ * @devp not used
+ *
+ * Called by a notifier that uses devfreq->nb.
+ */
+static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
+ void *devp)
+{
+ struct devfreq *devfreq = container_of(nb, struct devfreq, nb);
+ int ret;
+
+ mutex_lock(&devfreq->lock);
+ ret = update_devfreq(devfreq);
+ mutex_unlock(&devfreq->lock);
+
+ return ret;
+}
+
+/**
+ * _remove_devfreq() - Remove devfreq from the device.
+ * @devfreq: the devfreq struct
+ * @skip: skip calling device_unregister().
+ *
+ * Note that the caller should lock devfreq->lock before calling
+ * this. _remove_devfreq() will unlock it and free devfreq
+ * internally. devfreq_list_lock should be locked by the caller
+ * as well (not relased at return)
+ *
+ * Lock usage:
+ * devfreq->lock: locked before call.
+ * unlocked at return (and freed)
+ * devfreq_list_lock: locked before call.
+ * kept locked at return.
+ * if devfreq is centrally polled.
+ *
+ * Freed memory:
+ * devfreq
+ */
+static void _remove_devfreq(struct devfreq *devfreq, bool skip)
+{
+ if (!mutex_is_locked(&devfreq->lock)) {
+ WARN(true, "devfreq->lock must be locked by the caller.\n");
+ return;
+ }
+ if (!devfreq->governor->no_central_polling &&
+ !mutex_is_locked(&devfreq_list_lock)) {
+ WARN(true, "devfreq_list_lock must be locked by the caller.\n");
+ return;
+ }
+
+ if (devfreq->being_removed)
+ return;
+
+ devfreq->being_removed = true;
+
+ if (devfreq->profile->exit)
+ devfreq->profile->exit(devfreq->dev.parent);
+
+ if (devfreq->governor->exit)
+ devfreq->governor->exit(devfreq);
+
+ if (!skip && get_device(&devfreq->dev)) {
+ device_unregister(&devfreq->dev);
+ put_device(&devfreq->dev);
+ }
+
+ if (!devfreq->governor->no_central_polling)
+ list_del(&devfreq->node);
+
+ mutex_unlock(&devfreq->lock);
+ mutex_destroy(&devfreq->lock);
+
+ kfree(devfreq);
+}
+
+/**
+ * devfreq_dev_release() - Callback for struct device to release the device.
+ * @dev: the devfreq device
+ *
+ * This calls _remove_devfreq() if _remove_devfreq() is not called.
+ * Note that devfreq_dev_release() could be called by _remove_devfreq() as
+ * well as by others unregistering the device.
+ */
+static void devfreq_dev_release(struct device *dev)
+{
+ struct devfreq *devfreq = to_devfreq(dev);
+ bool central_polling = !devfreq->governor->no_central_polling;
+
+ /*
+ * If devfreq_dev_release() was called by device_unregister() of
+ * _remove_devfreq(), we cannot mutex_lock(&devfreq->lock) and
+ * being_removed is already set. This also partially checks the case
+ * where devfreq_dev_release() is called from a thread other than
+ * the one called _remove_devfreq(); however, this case is
+ * dealt completely with another following being_removed check.
+ *
+ * Because being_removed is never being
+ * unset, we do not need to worry about race conditions on
+ * being_removed.
+ */
+ if (devfreq->being_removed)
+ return;
+
+ if (central_polling)
+ mutex_lock(&devfreq_list_lock);
+
+ mutex_lock(&devfreq->lock);
+
+ /*
+ * Check being_removed flag again for the case where
+ * devfreq_dev_release() was called in a thread other than the one
+ * possibly called _remove_devfreq().
+ */
+ if (devfreq->being_removed) {
+ mutex_unlock(&devfreq->lock);
+ goto out;
+ }
+
+ /* devfreq->lock is unlocked and removed in _removed_devfreq() */
+ _remove_devfreq(devfreq, true);
+
+out:
+ if (central_polling)
+ mutex_unlock(&devfreq_list_lock);
+}
+
+/**
+ * devfreq_monitor() - Periodically poll devfreq objects.
+ * @work: the work struct used to run devfreq_monitor periodically.
+ *
+ */
+static void devfreq_monitor(struct work_struct *work)
+{
+ static unsigned long last_polled_at;
+ struct devfreq *devfreq, *tmp;
+ int error;
+ unsigned long jiffies_passed;
+ unsigned long next_jiffies = ULONG_MAX, now = jiffies;
+ struct device *dev;
+
+ /* Initially last_polled_at = 0, polling every device at bootup */
+ jiffies_passed = now - last_polled_at;
+ last_polled_at = now;
+ if (jiffies_passed == 0)
+ jiffies_passed = 1;
+
+ mutex_lock(&devfreq_list_lock);
+ list_for_each_entry_safe(devfreq, tmp, &devfreq_list, node) {
+ mutex_lock(&devfreq->lock);
+ dev = devfreq->dev.parent;
+
+ /* Do not remove tmp for a while */
+ wait_remove_device = tmp;
+
+ if (devfreq->governor->no_central_polling ||
+ devfreq->next_polling == 0) {
+ mutex_unlock(&devfreq->lock);
+ continue;
+ }
+ mutex_unlock(&devfreq_list_lock);
+
+ /*
+ * Reduce more next_polling if devfreq_wq took an extra
+ * delay. (i.e., CPU has been idled.)
+ */
+ if (devfreq->next_polling <= jiffies_passed) {
+ error = update_devfreq(devfreq);
+
+ /* Remove a devfreq with an error. */
+ if (error && error != -EAGAIN) {
+
+ dev_err(dev, "Due to update_devfreq error(%d), devfreq(%s) is removed from the device\n",
+ error, devfreq->governor->name);
+
+ /*
+ * Unlock devfreq before locking the list
+ * in order to avoid deadlock with
+ * find_device_devfreq or others
+ */
+ mutex_unlock(&devfreq->lock);
+ mutex_lock(&devfreq_list_lock);
+ /* Check if devfreq is already removed */
+ if (IS_ERR(find_device_devfreq(dev)))
+ continue;
+ mutex_lock(&devfreq->lock);
+ /* This unlocks devfreq->lock and free it */
+ _remove_devfreq(devfreq, false);
+ continue;
+ }
+ devfreq->next_polling = devfreq->polling_jiffies;
+ } else {
+ devfreq->next_polling -= jiffies_passed;
+ }
+
+ if (devfreq->next_polling)
+ next_jiffies = (next_jiffies > devfreq->next_polling) ?
+ devfreq->next_polling : next_jiffies;
+
+ mutex_unlock(&devfreq->lock);
+ mutex_lock(&devfreq_list_lock);
+ }
+ wait_remove_device = NULL;
+ mutex_unlock(&devfreq_list_lock);
+
+ if (next_jiffies > 0 && next_jiffies < ULONG_MAX) {
+ polling = true;
+ queue_delayed_work(devfreq_wq, &devfreq_work, next_jiffies);
+ } else {
+ polling = false;
+ }
+}
+
+/**
+ * devfreq_add_device() - Add devfreq feature to the device
+ * @dev: the device to add devfreq feature.
+ * @profile: device-specific profile to run devfreq.
+ * @governor: the policy to choose frequency.
+ * @data: private data for the governor. The devfreq framework does not
+ * touch this value.
+ */
+struct devfreq *devfreq_add_device(struct device *dev,
+ struct devfreq_dev_profile *profile,
+ const struct devfreq_governor *governor,
+ void *data)
+{
+ struct devfreq *devfreq;
+ int err = 0;
+
+ if (!dev || !profile || !governor) {
+ dev_err(dev, "%s: Invalid parameters.\n", __func__);
+ return ERR_PTR(-EINVAL);
+ }
+
+
+ if (!governor->no_central_polling) {
+ mutex_lock(&devfreq_list_lock);
+ devfreq = find_device_devfreq(dev);
+ mutex_unlock(&devfreq_list_lock);
+ if (!IS_ERR(devfreq)) {
+ dev_err(dev, "%s: Unable to create devfreq for the device. It already has one.\n", __func__);
+ err = -EINVAL;
+ goto out;
+ }
+ }
+
+ devfreq = kzalloc(sizeof(struct devfreq), GFP_KERNEL);
+ if (!devfreq) {
+ dev_err(dev, "%s: Unable to create devfreq for the device\n",
+ __func__);
+ err = -ENOMEM;
+ goto out;
+ }
+
+ mutex_init(&devfreq->lock);
+ mutex_lock(&devfreq->lock);
+ devfreq->dev.parent = dev;
+ devfreq->dev.class = devfreq_class;
+ devfreq->dev.release = devfreq_dev_release;
+ devfreq->profile = profile;
+ devfreq->governor = governor;
+ devfreq->previous_freq = profile->initial_freq;
+ devfreq->data = data;
+ devfreq->next_polling = devfreq->polling_jiffies
+ = msecs_to_jiffies(devfreq->profile->polling_ms);
+ devfreq->nb.notifier_call = devfreq_notifier_call;
+
+ dev_set_name(&devfreq->dev, dev_name(dev));
+ err = device_register(&devfreq->dev);
+ if (err) {
+ put_device(&devfreq->dev);
+ goto err_dev;
+ }
+
+ if (governor->init)
+ err = governor->init(devfreq);
+ if (err)
+ goto err_init;
+
+ mutex_unlock(&devfreq->lock);
+
+ if (governor->no_central_polling)
+ goto out;
+
+ mutex_lock(&devfreq_list_lock);
+
+ list_add(&devfreq->node, &devfreq_list);
+
+ if (devfreq_wq && devfreq->next_polling && !polling) {
+ polling = true;
+ queue_delayed_work(devfreq_wq, &devfreq_work,
+ devfreq->next_polling);
+ }
+ mutex_unlock(&devfreq_list_lock);
+ goto out;
+err_init:
+ device_unregister(&devfreq->dev);
+err_dev:
+ mutex_unlock(&devfreq->lock);
+ kfree(devfreq);
+out:
+ if (err)
+ return ERR_PTR(err);
+ else
+ return devfreq;
+}
+
+/**
+ * devfreq_remove_device() - Remove devfreq feature from a device.
+ * @devfreq the devfreq instance to be removed
+ */
+int devfreq_remove_device(struct devfreq *devfreq)
+{
+ if (!devfreq)
+ return -EINVAL;
+
+ if (!devfreq->governor->no_central_polling) {
+ mutex_lock(&devfreq_list_lock);
+ while (wait_remove_device == devfreq) {
+ mutex_unlock(&devfreq_list_lock);
+ schedule();
+ mutex_lock(&devfreq_list_lock);
+ }
+ }
+
+ mutex_lock(&devfreq->lock);
+ _remove_devfreq(devfreq, false); /* it unlocks devfreq->lock */
+
+ if (!devfreq->governor->no_central_polling)
+ mutex_unlock(&devfreq_list_lock);
+
+ return 0;
+}
+
+static ssize_t show_governor(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s\n", to_devfreq(dev)->governor->name);
+}
+
+static ssize_t show_freq(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%lu\n", to_devfreq(dev)->previous_freq);
+}
+
+static ssize_t show_polling_interval(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", to_devfreq(dev)->profile->polling_ms);
+}
+
+static ssize_t store_polling_interval(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct devfreq *df = to_devfreq(dev);
+ unsigned int value;
+ int ret;
+
+ ret = sscanf(buf, "%u", &value);
+ if (ret != 1)
+ goto out;
+
+ mutex_lock(&df->lock);
+ df->profile->polling_ms = value;
+ df->next_polling = df->polling_jiffies
+ = msecs_to_jiffies(value);
+ mutex_unlock(&df->lock);
+
+ ret = count;
+
+ if (df->governor->no_central_polling)
+ goto out;
+
+ mutex_lock(&devfreq_list_lock);
+ if (df->next_polling > 0 && !polling) {
+ polling = true;
+ queue_delayed_work(devfreq_wq, &devfreq_work,
+ df->next_polling);
+ }
+ mutex_unlock(&devfreq_list_lock);
+out:
+ return ret;
+}
+
+static ssize_t show_central_polling(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n",
+ !to_devfreq(dev)->governor->no_central_polling);
+}
+
+static struct device_attribute devfreq_attrs[] = {
+ __ATTR(governor, S_IRUGO, show_governor, NULL),
+ __ATTR(cur_freq, S_IRUGO, show_freq, NULL),
+ __ATTR(central_polling, S_IRUGO, show_central_polling, NULL),
+ __ATTR(polling_interval, S_IRUGO | S_IWUSR, show_polling_interval,
+ store_polling_interval),
+ { },
+};
+
+/**
+ * devfreq_start_polling() - Initialize data structure for devfreq framework and
+ * start polling registered devfreq devices.
+ */
+static int __init devfreq_start_polling(void)
+{
+ mutex_lock(&devfreq_list_lock);
+ polling = false;
+ devfreq_wq = create_freezable_workqueue("devfreq_wq");
+ INIT_DELAYED_WORK_DEFERRABLE(&devfreq_work, devfreq_monitor);
+ mutex_unlock(&devfreq_list_lock);
+
+ devfreq_monitor(&devfreq_work.work);
+ return 0;
+}
+late_initcall(devfreq_start_polling);
+
+static int __init devfreq_init(void)
+{
+ devfreq_class = class_create(THIS_MODULE, "devfreq");
+ if (IS_ERR(devfreq_class)) {
+ pr_err("%s: couldn't create class\n", __FILE__);
+ return PTR_ERR(devfreq_class);
+ }
+ devfreq_class->dev_attrs = devfreq_attrs;
+ return 0;
+}
+subsys_initcall(devfreq_init);
+
+static void __exit devfreq_exit(void)
+{
+ class_destroy(devfreq_class);
+}
+module_exit(devfreq_exit);
+
+/*
+ * The followings are helper functions for devfreq user device drivers with
+ * OPP framework.
+ */
+
+/**
+ * devfreq_recommended_opp() - Helper function to get proper OPP for the
+ * freq value given to target callback.
+ * @dev The devfreq user device. (parent of devfreq)
+ * @freq The frequency given to target function
+ *
+ */
+struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq)
+{
+ struct opp *opp = opp_find_freq_ceil(dev, freq);
+
+ if (opp == ERR_PTR(-ENODEV))
+ opp = opp_find_freq_floor(dev, freq);
+ return opp;
+}
+
+/**
+ * devfreq_register_opp_notifier() - Helper function to get devfreq notified
+ * for any changes in the OPP availability
+ * changes
+ * @dev The devfreq user device. (parent of devfreq)
+ * @devfreq The devfreq object.
+ */
+int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq)
+{
+ struct srcu_notifier_head *nh = opp_get_notifier(dev);
+
+ if (IS_ERR(nh))
+ return PTR_ERR(nh);
+ return srcu_notifier_chain_register(nh, &devfreq->nb);
+}
+
+/**
+ * devfreq_unregister_opp_notifier() - Helper function to stop getting devfreq
+ * notified for any changes in the OPP
+ * availability changes anymore.
+ * @dev The devfreq user device. (parent of devfreq)
+ * @devfreq The devfreq object.
+ *
+ * At exit() callback of devfreq_dev_profile, this must be included if
+ * devfreq_recommended_opp is used.
+ */
+int devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq)
+{
+ struct srcu_notifier_head *nh = opp_get_notifier(dev);
+
+ if (IS_ERR(nh))
+ return PTR_ERR(nh);
+ return srcu_notifier_chain_unregister(nh, &devfreq->nb);
+}
+
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_DESCRIPTION("devfreq class support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/devfreq/governor.h b/drivers/devfreq/governor.h
new file mode 100644
index 000000000000..ea7f13c58ded
--- /dev/null
+++ b/drivers/devfreq/governor.h
@@ -0,0 +1,24 @@
+/*
+ * governor.h - internal header for devfreq governors.
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This header is for devfreq governors in drivers/devfreq/
+ */
+
+#ifndef _GOVERNOR_H
+#define _GOVERNOR_H
+
+#include <linux/devfreq.h>
+
+#define to_devfreq(DEV) container_of((DEV), struct devfreq, dev)
+
+/* Caution: devfreq->lock must be locked before calling update_devfreq */
+extern int update_devfreq(struct devfreq *devfreq);
+
+#endif /* _GOVERNOR_H */
diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c
new file mode 100644
index 000000000000..c0596b291761
--- /dev/null
+++ b/drivers/devfreq/governor_performance.c
@@ -0,0 +1,29 @@
+/*
+ * linux/drivers/devfreq/governor_performance.c
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/devfreq.h>
+
+static int devfreq_performance_func(struct devfreq *df,
+ unsigned long *freq)
+{
+ /*
+ * target callback should be able to get floor value as
+ * said in devfreq.h
+ */
+ *freq = UINT_MAX;
+ return 0;
+}
+
+const struct devfreq_governor devfreq_performance = {
+ .name = "performance",
+ .get_target_freq = devfreq_performance_func,
+ .no_central_polling = true,
+};
diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c
new file mode 100644
index 000000000000..2483a85a266f
--- /dev/null
+++ b/drivers/devfreq/governor_powersave.c
@@ -0,0 +1,29 @@
+/*
+ * linux/drivers/devfreq/governor_powersave.c
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/devfreq.h>
+
+static int devfreq_powersave_func(struct devfreq *df,
+ unsigned long *freq)
+{
+ /*
+ * target callback should be able to get ceiling value as
+ * said in devfreq.h
+ */
+ *freq = 0;
+ return 0;
+}
+
+const struct devfreq_governor devfreq_powersave = {
+ .name = "powersave",
+ .get_target_freq = devfreq_powersave_func,
+ .no_central_polling = true,
+};
diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c
new file mode 100644
index 000000000000..efad8dcf9028
--- /dev/null
+++ b/drivers/devfreq/governor_simpleondemand.c
@@ -0,0 +1,88 @@
+/*
+ * linux/drivers/devfreq/governor_simpleondemand.c
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/errno.h>
+#include <linux/devfreq.h>
+#include <linux/math64.h>
+
+/* Default constants for DevFreq-Simple-Ondemand (DFSO) */
+#define DFSO_UPTHRESHOLD (90)
+#define DFSO_DOWNDIFFERENCTIAL (5)
+static int devfreq_simple_ondemand_func(struct devfreq *df,
+ unsigned long *freq)
+{
+ struct devfreq_dev_status stat;
+ int err = df->profile->get_dev_status(df->dev.parent, &stat);
+ unsigned long long a, b;
+ unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD;
+ unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL;
+ struct devfreq_simple_ondemand_data *data = df->data;
+
+ if (err)
+ return err;
+
+ if (data) {
+ if (data->upthreshold)
+ dfso_upthreshold = data->upthreshold;
+ if (data->downdifferential)
+ dfso_downdifferential = data->downdifferential;
+ }
+ if (dfso_upthreshold > 100 ||
+ dfso_upthreshold < dfso_downdifferential)
+ return -EINVAL;
+
+ /* Assume MAX if it is going to be divided by zero */
+ if (stat.total_time == 0) {
+ *freq = UINT_MAX;
+ return 0;
+ }
+
+ /* Prevent overflow */
+ if (stat.busy_time >= (1 << 24) || stat.total_time >= (1 << 24)) {
+ stat.busy_time >>= 7;
+ stat.total_time >>= 7;
+ }
+
+ /* Set MAX if it's busy enough */
+ if (stat.busy_time * 100 >
+ stat.total_time * dfso_upthreshold) {
+ *freq = UINT_MAX;
+ return 0;
+ }
+
+ /* Set MAX if we do not know the initial frequency */
+ if (stat.current_frequency == 0) {
+ *freq = UINT_MAX;
+ return 0;
+ }
+
+ /* Keep the current frequency */
+ if (stat.busy_time * 100 >
+ stat.total_time * (dfso_upthreshold - dfso_downdifferential)) {
+ *freq = stat.current_frequency;
+ return 0;
+ }
+
+ /* Set the desired frequency based on the load */
+ a = stat.busy_time;
+ a *= stat.current_frequency;
+ b = div_u64(a, stat.total_time);
+ b *= 100;
+ b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2));
+ *freq = (unsigned long) b;
+
+ return 0;
+}
+
+const struct devfreq_governor devfreq_simple_ondemand = {
+ .name = "simple_ondemand",
+ .get_target_freq = devfreq_simple_ondemand_func,
+};
diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c
new file mode 100644
index 000000000000..4f8b563da782
--- /dev/null
+++ b/drivers/devfreq/governor_userspace.c
@@ -0,0 +1,116 @@
+/*
+ * linux/drivers/devfreq/governor_simpleondemand.c
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/devfreq.h>
+#include <linux/pm.h>
+#include <linux/mutex.h>
+#include "governor.h"
+
+struct userspace_data {
+ unsigned long user_frequency;
+ bool valid;
+};
+
+static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq)
+{
+ struct userspace_data *data = df->data;
+
+ if (!data->valid)
+ *freq = df->previous_freq; /* No user freq specified yet */
+ else
+ *freq = data->user_frequency;
+ return 0;
+}
+
+static ssize_t store_freq(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct devfreq *devfreq = to_devfreq(dev);
+ struct userspace_data *data;
+ unsigned long wanted;
+ int err = 0;
+
+
+ mutex_lock(&devfreq->lock);
+ data = devfreq->data;
+
+ sscanf(buf, "%lu", &wanted);
+ data->user_frequency = wanted;
+ data->valid = true;
+ err = update_devfreq(devfreq);
+ if (err == 0)
+ err = count;
+ mutex_unlock(&devfreq->lock);
+ return err;
+}
+
+static ssize_t show_freq(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct devfreq *devfreq = to_devfreq(dev);
+ struct userspace_data *data;
+ int err = 0;
+
+ mutex_lock(&devfreq->lock);
+ data = devfreq->data;
+
+ if (data->valid)
+ err = sprintf(buf, "%lu\n", data->user_frequency);
+ else
+ err = sprintf(buf, "undefined\n");
+ mutex_unlock(&devfreq->lock);
+ return err;
+}
+
+static DEVICE_ATTR(set_freq, 0644, show_freq, store_freq);
+static struct attribute *dev_entries[] = {
+ &dev_attr_set_freq.attr,
+ NULL,
+};
+static struct attribute_group dev_attr_group = {
+ .name = "userspace",
+ .attrs = dev_entries,
+};
+
+static int userspace_init(struct devfreq *devfreq)
+{
+ int err = 0;
+ struct userspace_data *data = kzalloc(sizeof(struct userspace_data),
+ GFP_KERNEL);
+
+ if (!data) {
+ err = -ENOMEM;
+ goto out;
+ }
+ data->valid = false;
+ devfreq->data = data;
+
+ err = sysfs_create_group(&devfreq->dev.kobj, &dev_attr_group);
+out:
+ return err;
+}
+
+static void userspace_exit(struct devfreq *devfreq)
+{
+ sysfs_remove_group(&devfreq->dev.kobj, &dev_attr_group);
+ kfree(devfreq->data);
+ devfreq->data = NULL;
+}
+
+const struct devfreq_governor devfreq_userspace = {
+ .name = "userspace",
+ .get_target_freq = devfreq_userspace_func,
+ .init = userspace_init,
+ .exit = userspace_exit,
+ .no_central_polling = true,
+};
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index cd3a7c726bf8..467e4dcb20a0 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -174,8 +174,10 @@ struct d40_base;
* @tasklet: Tasklet that gets scheduled from interrupt context to complete a
* transfer and call client callback.
* @client: Cliented owned descriptor list.
+ * @pending_queue: Submitted jobs, to be issued by issue_pending()
* @active: Active descriptor.
* @queue: Queued jobs.
+ * @prepare_queue: Prepared jobs.
* @dma_cfg: The client configuration of this dma channel.
* @configured: whether the dma_cfg configuration is valid
* @base: Pointer to the device instance struct.
@@ -203,6 +205,7 @@ struct d40_chan {
struct list_head pending_queue;
struct list_head active;
struct list_head queue;
+ struct list_head prepare_queue;
struct stedma40_chan_cfg dma_cfg;
bool configured;
struct d40_base *base;
@@ -477,7 +480,6 @@ static struct d40_desc *d40_desc_get(struct d40_chan *d40c)
list_for_each_entry_safe(d, _d, &d40c->client, node)
if (async_tx_test_ack(&d->txd)) {
- d40_pool_lli_free(d40c, d);
d40_desc_remove(d);
desc = d;
memset(desc, 0, sizeof(*desc));
@@ -644,8 +646,11 @@ static struct d40_desc *d40_first_active_get(struct d40_chan *d40c)
return d;
}
+/* remove desc from current queue and add it to the pending_queue */
static void d40_desc_queue(struct d40_chan *d40c, struct d40_desc *desc)
{
+ d40_desc_remove(desc);
+ desc->is_in_client_list = false;
list_add_tail(&desc->node, &d40c->pending_queue);
}
@@ -803,6 +808,7 @@ done:
static void d40_term_all(struct d40_chan *d40c)
{
struct d40_desc *d40d;
+ struct d40_desc *_d;
/* Release active descriptors */
while ((d40d = d40_first_active_get(d40c))) {
@@ -822,6 +828,21 @@ static void d40_term_all(struct d40_chan *d40c)
d40_desc_free(d40c, d40d);
}
+ /* Release client owned descriptors */
+ if (!list_empty(&d40c->client))
+ list_for_each_entry_safe(d40d, _d, &d40c->client, node) {
+ d40_desc_remove(d40d);
+ d40_desc_free(d40c, d40d);
+ }
+
+ /* Release descriptors in prepare queue */
+ if (!list_empty(&d40c->prepare_queue))
+ list_for_each_entry_safe(d40d, _d,
+ &d40c->prepare_queue, node) {
+ d40_desc_remove(d40d);
+ d40_desc_free(d40c, d40d);
+ }
+
d40c->pending_tx = 0;
d40c->busy = false;
}
@@ -1208,7 +1229,6 @@ static void dma_tasklet(unsigned long data)
if (!d40d->cyclic) {
if (async_tx_test_ack(&d40d->txd)) {
- d40_pool_lli_free(d40c, d40d);
d40_desc_remove(d40d);
d40_desc_free(d40c, d40d);
} else {
@@ -1595,21 +1615,10 @@ static int d40_free_dma(struct d40_chan *d40c)
u32 event;
struct d40_phy_res *phy = d40c->phy_chan;
bool is_src;
- struct d40_desc *d;
- struct d40_desc *_d;
-
/* Terminate all queued and active transfers */
d40_term_all(d40c);
- /* Release client owned descriptors */
- if (!list_empty(&d40c->client))
- list_for_each_entry_safe(d, _d, &d40c->client, node) {
- d40_pool_lli_free(d40c, d);
- d40_desc_remove(d);
- d40_desc_free(d40c, d);
- }
-
if (phy == NULL) {
chan_err(d40c, "phy == null\n");
return -EINVAL;
@@ -1911,6 +1920,12 @@ d40_prep_sg(struct dma_chan *dchan, struct scatterlist *sg_src,
goto err;
}
+ /*
+ * add descriptor to the prepare queue in order to be able
+ * to free them later in terminate_all
+ */
+ list_add_tail(&desc->node, &chan->prepare_queue);
+
spin_unlock_irqrestore(&chan->lock, flags);
return &desc->txd;
@@ -2400,6 +2415,7 @@ static void __init d40_chan_init(struct d40_base *base, struct dma_device *dma,
INIT_LIST_HEAD(&d40c->queue);
INIT_LIST_HEAD(&d40c->pending_queue);
INIT_LIST_HEAD(&d40c->client);
+ INIT_LIST_HEAD(&d40c->prepare_queue);
tasklet_init(&d40c->tasklet, dma_tasklet,
(unsigned long) d40c);
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 57cd3a406edf..fd7170a9ad2c 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -290,6 +290,9 @@ static const struct {
{PCI_VENDOR_ID_NEC, PCI_ANY_ID, PCI_ANY_ID,
QUIRK_CYCLE_TIMER},
+ {PCI_VENDOR_ID_O2, PCI_ANY_ID, PCI_ANY_ID,
+ QUIRK_NO_MSI},
+
{PCI_VENDOR_ID_RICOH, PCI_ANY_ID, PCI_ANY_ID,
QUIRK_CYCLE_TIMER},
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c
index 41841a3e3f99..17cef864506a 100644
--- a/drivers/firewire/sbp2.c
+++ b/drivers/firewire/sbp2.c
@@ -1198,6 +1198,10 @@ static int sbp2_remove(struct device *dev)
{
struct fw_unit *unit = fw_unit(dev);
struct sbp2_target *tgt = dev_get_drvdata(&unit->device);
+ struct sbp2_logical_unit *lu;
+
+ list_for_each_entry(lu, &tgt->lu_list, link)
+ cancel_delayed_work_sync(&lu->work);
sbp2_target_put(tgt);
return 0;
diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c
index 68810fd1a59d..aa83de9db1b9 100644
--- a/drivers/firmware/google/gsmi.c
+++ b/drivers/firmware/google/gsmi.c
@@ -420,7 +420,7 @@ static efi_status_t gsmi_get_next_variable(unsigned long *name_size,
static efi_status_t gsmi_set_variable(efi_char16_t *name,
efi_guid_t *vendor,
- unsigned long attr,
+ u32 attr,
unsigned long data_size,
void *data)
{
diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c
index 231714def4d2..4e24436b0f82 100644
--- a/drivers/gpio/gpio-generic.c
+++ b/drivers/gpio/gpio-generic.c
@@ -351,7 +351,7 @@ static int bgpio_setup_direction(struct bgpio_chip *bgc,
return 0;
}
-int __devexit bgpio_remove(struct bgpio_chip *bgc)
+int bgpio_remove(struct bgpio_chip *bgc)
{
int err = gpiochip_remove(&bgc->gc);
@@ -361,15 +361,10 @@ int __devexit bgpio_remove(struct bgpio_chip *bgc)
}
EXPORT_SYMBOL_GPL(bgpio_remove);
-int __devinit bgpio_init(struct bgpio_chip *bgc,
- struct device *dev,
- unsigned long sz,
- void __iomem *dat,
- void __iomem *set,
- void __iomem *clr,
- void __iomem *dirout,
- void __iomem *dirin,
- bool big_endian)
+int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
+ unsigned long sz, void __iomem *dat, void __iomem *set,
+ void __iomem *clr, void __iomem *dirout, void __iomem *dirin,
+ bool big_endian)
{
int ret;
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 0599854e2217..118ec12d2d5f 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -34,8 +34,8 @@ struct gpio_bank {
u16 irq;
u16 virtual_irq_start;
int method;
-#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS)
u32 suspend_wakeup;
+#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS)
u32 saved_wakeup;
#endif
u32 non_wakeup_gpios;
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index c43b8ff626a7..0550dcb85814 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -577,6 +577,7 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, int *invert)
void
pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, int *invert)
{
+ *gpio_base = -1;
}
#endif
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 82db18506662..fe738f05309b 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -499,6 +499,7 @@ void drm_connector_cleanup(struct drm_connector *connector)
mutex_lock(&dev->mode_config.mutex);
drm_mode_object_put(dev, &connector->base);
list_del(&connector->head);
+ dev->mode_config.num_connector--;
mutex_unlock(&dev->mode_config.mutex);
}
EXPORT_SYMBOL(drm_connector_cleanup);
@@ -529,6 +530,7 @@ void drm_encoder_cleanup(struct drm_encoder *encoder)
mutex_lock(&dev->mode_config.mutex);
drm_mode_object_put(dev, &encoder->base);
list_del(&encoder->head);
+ dev->mode_config.num_encoder--;
mutex_unlock(&dev->mode_config.mutex);
}
EXPORT_SYMBOL(drm_encoder_cleanup);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 802b61ac3139..f7c6854eb4dd 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -256,7 +256,6 @@ int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed,
{
printk(KERN_ERR "panic occurred, switching back to text console\n");
return drm_fb_helper_force_kernel_mode();
- return 0;
}
EXPORT_SYMBOL(drm_fb_helper_panic);
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index ce045a8cf82c..f07e4252b708 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -67,11 +67,11 @@ module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600);
MODULE_PARM_DESC(i915_enable_rc6,
"Enable power-saving render C-state 6 (default: true)");
-unsigned int i915_enable_fbc __read_mostly = 1;
+unsigned int i915_enable_fbc __read_mostly = -1;
module_param_named(i915_enable_fbc, i915_enable_fbc, int, 0600);
MODULE_PARM_DESC(i915_enable_fbc,
"Enable frame buffer compression for power savings "
- "(default: false)");
+ "(default: -1 (use per-chip default))");
unsigned int i915_lvds_downclock __read_mostly = 0;
module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index ee1d701317f7..04411ad2e779 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -878,7 +878,7 @@ static void assert_panel_unlocked(struct drm_i915_private *dev_priv,
int pp_reg, lvds_reg;
u32 val;
enum pipe panel_pipe = PIPE_A;
- bool locked = locked;
+ bool locked = true;
if (HAS_PCH_SPLIT(dev_priv->dev)) {
pp_reg = PCH_PP_CONTROL;
@@ -1799,6 +1799,7 @@ static void intel_update_fbc(struct drm_device *dev)
struct drm_framebuffer *fb;
struct intel_framebuffer *intel_fb;
struct drm_i915_gem_object *obj;
+ int enable_fbc;
DRM_DEBUG_KMS("\n");
@@ -1839,8 +1840,15 @@ static void intel_update_fbc(struct drm_device *dev)
intel_fb = to_intel_framebuffer(fb);
obj = intel_fb->obj;
- if (!i915_enable_fbc) {
- DRM_DEBUG_KMS("fbc disabled per module param (default off)\n");
+ enable_fbc = i915_enable_fbc;
+ if (enable_fbc < 0) {
+ DRM_DEBUG_KMS("fbc set to per-chip default\n");
+ enable_fbc = 1;
+ if (INTEL_INFO(dev)->gen <= 5)
+ enable_fbc = 0;
+ }
+ if (!enable_fbc) {
+ DRM_DEBUG_KMS("fbc disabled per module param\n");
dev_priv->no_fbc_reason = FBC_MODULE_PARAM;
goto out_disable;
}
@@ -4687,13 +4695,13 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
bpc = 6; /* min is 18bpp */
break;
case 24:
- bpc = min((unsigned int)8, display_bpc);
+ bpc = 8;
break;
case 30:
- bpc = min((unsigned int)10, display_bpc);
+ bpc = 10;
break;
case 48:
- bpc = min((unsigned int)12, display_bpc);
+ bpc = 12;
break;
default:
DRM_DEBUG("unsupported depth, assuming 24 bits\n");
@@ -4701,10 +4709,12 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
break;
}
+ display_bpc = min(display_bpc, bpc);
+
DRM_DEBUG_DRIVER("setting pipe bpc to %d (max display bpc %d)\n",
bpc, display_bpc);
- *pipe_bpp = bpc * 3;
+ *pipe_bpp = display_bpc * 3;
return display_bpc != bpc;
}
@@ -7238,8 +7248,6 @@ static void intel_setup_outputs(struct drm_device *dev)
intel_encoder_clones(dev, encoder->clone_mask);
}
- intel_panel_setup_backlight(dev);
-
/* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(dev);
}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 0b2ee9d39980..fe1099d8817e 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -337,9 +337,6 @@ extern void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
struct drm_connector *connector,
struct intel_load_detect_pipe *old);
-extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB);
-extern int intel_sdvo_supports_hotplug(struct drm_connector *connector);
-extern void intel_sdvo_set_hotplug(struct drm_connector *connector, int enable);
extern void intelfb_restore(void);
extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
u16 blue, int regno);
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 30fe554d8936..6348c499616f 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -92,6 +92,11 @@ struct intel_sdvo {
*/
uint16_t attached_output;
+ /*
+ * Hotplug activation bits for this device
+ */
+ uint8_t hotplug_active[2];
+
/**
* This is used to select the color range of RBG outputs in HDMI mode.
* It is only valid when using TMDS encoding and 8 bit per color mode.
@@ -1208,74 +1213,20 @@ static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct in
return true;
}
-/* No use! */
-#if 0
-struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB)
-{
- struct drm_connector *connector = NULL;
- struct intel_sdvo *iout = NULL;
- struct intel_sdvo *sdvo;
-
- /* find the sdvo connector */
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- iout = to_intel_sdvo(connector);
-
- if (iout->type != INTEL_OUTPUT_SDVO)
- continue;
-
- sdvo = iout->dev_priv;
-
- if (sdvo->sdvo_reg == SDVOB && sdvoB)
- return connector;
-
- if (sdvo->sdvo_reg == SDVOC && !sdvoB)
- return connector;
-
- }
-
- return NULL;
-}
-
-int intel_sdvo_supports_hotplug(struct drm_connector *connector)
+static int intel_sdvo_supports_hotplug(struct intel_sdvo *intel_sdvo)
{
u8 response[2];
- u8 status;
- struct intel_sdvo *intel_sdvo;
- DRM_DEBUG_KMS("\n");
-
- if (!connector)
- return 0;
-
- intel_sdvo = to_intel_sdvo(connector);
return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT,
&response, 2) && response[0];
}
-void intel_sdvo_set_hotplug(struct drm_connector *connector, int on)
+static void intel_sdvo_enable_hotplug(struct intel_encoder *encoder)
{
- u8 response[2];
- u8 status;
- struct intel_sdvo *intel_sdvo = to_intel_sdvo(connector);
-
- intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0);
- intel_sdvo_read_response(intel_sdvo, &response, 2);
-
- if (on) {
- intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0);
- status = intel_sdvo_read_response(intel_sdvo, &response, 2);
-
- intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2);
- } else {
- response[0] = 0;
- response[1] = 0;
- intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2);
- }
+ struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
- intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0);
- intel_sdvo_read_response(intel_sdvo, &response, 2);
+ intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &intel_sdvo->hotplug_active, 2);
}
-#endif
static bool
intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo)
@@ -2045,6 +1996,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
{
struct drm_encoder *encoder = &intel_sdvo->base.base;
struct drm_connector *connector;
+ struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
struct intel_connector *intel_connector;
struct intel_sdvo_connector *intel_sdvo_connector;
@@ -2062,7 +2014,17 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
intel_connector = &intel_sdvo_connector->base;
connector = &intel_connector->base;
- connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
+ if (intel_sdvo_supports_hotplug(intel_sdvo) & (1 << device)) {
+ connector->polled = DRM_CONNECTOR_POLL_HPD;
+ intel_sdvo->hotplug_active[0] |= 1 << device;
+ /* Some SDVO devices have one-shot hotplug interrupts.
+ * Ensure that they get re-enabled when an interrupt happens.
+ */
+ intel_encoder->hot_plug = intel_sdvo_enable_hotplug;
+ intel_sdvo_enable_hotplug(intel_encoder);
+ }
+ else
+ connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
connector->connector_type = DRM_MODE_CONNECTOR_DVID;
@@ -2569,6 +2531,14 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
goto err;
+ /* Set up hotplug command - note paranoia about contents of reply.
+ * We assume that the hardware is in a sane state, and only touch
+ * the bits we think we understand.
+ */
+ intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG,
+ &intel_sdvo->hotplug_active, 2);
+ intel_sdvo->hotplug_active[0] &= ~0x3;
+
if (intel_sdvo_output_setup(intel_sdvo,
intel_sdvo->caps.output_flags) != true) {
DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n",
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index 8d02d875376d..c919cfc8f2fd 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -530,7 +530,8 @@ nouveau_fence_channel_init(struct nouveau_channel *chan)
nouveau_gpuobj_ref(NULL, &obj);
if (ret)
return ret;
- } else {
+ } else
+ if (USE_SEMA(dev)) {
/* map fence bo into channel's vm */
ret = nouveau_bo_vma_add(dev_priv->fence.bo, chan->vm,
&chan->fence.vma);
diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
index c444cadbf849..2706cb3d871a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
@@ -37,8 +37,11 @@ nouveau_sgdma_populate(struct ttm_backend *be, unsigned long num_pages,
return -ENOMEM;
nvbe->ttm_alloced = kmalloc(sizeof(bool) * num_pages, GFP_KERNEL);
- if (!nvbe->ttm_alloced)
+ if (!nvbe->ttm_alloced) {
+ kfree(nvbe->pages);
+ nvbe->pages = NULL;
return -ENOMEM;
+ }
nvbe->nr_pages = 0;
while (num_pages--) {
@@ -126,7 +129,7 @@ nv04_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++, pte++) {
nv_wo32(gpuobj, (pte * 4) + 0, offset_l | 3);
- dma_offset += NV_CTXDMA_PAGE_SIZE;
+ offset_l += NV_CTXDMA_PAGE_SIZE;
}
}
diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c
index 118261d4927a..5e45398a9e2d 100644
--- a/drivers/gpu/drm/nouveau/nv04_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv04_crtc.c
@@ -781,11 +781,20 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
struct drm_device *dev = crtc->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv04_crtc_reg *regp = &dev_priv->mode_reg.crtc_reg[nv_crtc->index];
- struct drm_framebuffer *drm_fb = nv_crtc->base.fb;
- struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
+ struct drm_framebuffer *drm_fb;
+ struct nouveau_framebuffer *fb;
int arb_burst, arb_lwm;
int ret;
+ NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
+
+ /* no fb bound */
+ if (!atomic && !crtc->fb) {
+ NV_DEBUG_KMS(dev, "No FB bound\n");
+ return 0;
+ }
+
+
/* If atomic, we want to switch to the fb we were passed, so
* now we update pointers to do that. (We don't pin; just
* assume we're already pinned and update the base address.)
@@ -794,6 +803,8 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
drm_fb = passed_fb;
fb = nouveau_framebuffer(passed_fb);
} else {
+ drm_fb = crtc->fb;
+ fb = nouveau_framebuffer(crtc->fb);
/* If not atomic, we can go ahead and pin, and unpin the
* old fb we were passed.
*/
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
index 46ad59ea2185..5d989073ba6e 100644
--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
@@ -519,12 +519,18 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
struct drm_device *dev = nv_crtc->base.dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *evo = nv50_display(dev)->master;
- struct drm_framebuffer *drm_fb = nv_crtc->base.fb;
- struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
+ struct drm_framebuffer *drm_fb;
+ struct nouveau_framebuffer *fb;
int ret;
NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
+ /* no fb bound */
+ if (!atomic && !crtc->fb) {
+ NV_DEBUG_KMS(dev, "No FB bound\n");
+ return 0;
+ }
+
/* If atomic, we want to switch to the fb we were passed, so
* now we update pointers to do that. (We don't pin; just
* assume we're already pinned and update the base address.)
@@ -533,6 +539,8 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
drm_fb = passed_fb;
fb = nouveau_framebuffer(passed_fb);
} else {
+ drm_fb = crtc->fb;
+ fb = nouveau_framebuffer(crtc->fb);
/* If not atomic, we can go ahead and pin, and unpin the
* old fb we were passed.
*/
diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c
index e88c64417a8a..14cc88aaf3a7 100644
--- a/drivers/gpu/drm/radeon/atom.c
+++ b/drivers/gpu/drm/radeon/atom.c
@@ -277,7 +277,12 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
case ATOM_ARG_FB:
idx = U8(*ptr);
(*ptr)++;
- val = gctx->scratch[((gctx->fb_base + idx) / 4)];
+ if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) {
+ DRM_ERROR("ATOM: fb read beyond scratch region: %d vs. %d\n",
+ gctx->fb_base + (idx * 4), gctx->scratch_size_bytes);
+ val = 0;
+ } else
+ val = gctx->scratch[(gctx->fb_base / 4) + idx];
if (print)
DEBUG("FB[0x%02X]", idx);
break;
@@ -531,7 +536,11 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
case ATOM_ARG_FB:
idx = U8(*ptr);
(*ptr)++;
- gctx->scratch[((gctx->fb_base + idx) / 4)] = val;
+ if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) {
+ DRM_ERROR("ATOM: fb write beyond scratch region: %d vs. %d\n",
+ gctx->fb_base + (idx * 4), gctx->scratch_size_bytes);
+ } else
+ gctx->scratch[(gctx->fb_base / 4) + idx] = val;
DEBUG("FB[0x%02X]", idx);
break;
case ATOM_ARG_PLL:
@@ -1370,11 +1379,13 @@ int atom_allocate_fb_scratch(struct atom_context *ctx)
usage_bytes = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb * 1024;
}
+ ctx->scratch_size_bytes = 0;
if (usage_bytes == 0)
usage_bytes = 20 * 1024;
/* allocate some scratch memory */
ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL);
if (!ctx->scratch)
return -ENOMEM;
+ ctx->scratch_size_bytes = usage_bytes;
return 0;
}
diff --git a/drivers/gpu/drm/radeon/atom.h b/drivers/gpu/drm/radeon/atom.h
index a589a55b223e..93cfe2086ba0 100644
--- a/drivers/gpu/drm/radeon/atom.h
+++ b/drivers/gpu/drm/radeon/atom.h
@@ -137,6 +137,7 @@ struct atom_context {
int cs_equal, cs_above;
int io_mode;
uint32_t *scratch;
+ int scratch_size_bytes;
};
extern int atom_debug;
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index c742944d3805..a515b2a09d85 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -466,7 +466,7 @@ static void atombios_crtc_program_ss(struct drm_crtc *crtc,
return;
}
args.v2.ucEnable = enable;
- if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK))
+ if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK) || ASIC_IS_DCE41(rdev))
args.v2.ucEnable = ATOM_DISABLE;
} else if (ASIC_IS_DCE3(rdev)) {
args.v1.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c
index 7ad43c6b1db7..79e8ebc05307 100644
--- a/drivers/gpu/drm/radeon/atombios_dp.c
+++ b/drivers/gpu/drm/radeon/atombios_dp.c
@@ -115,6 +115,7 @@ static int radeon_dp_aux_native_write(struct radeon_connector *radeon_connector,
u8 msg[20];
int msg_bytes = send_bytes + 4;
u8 ack;
+ unsigned retry;
if (send_bytes > 16)
return -1;
@@ -125,20 +126,22 @@ static int radeon_dp_aux_native_write(struct radeon_connector *radeon_connector,
msg[3] = (msg_bytes << 4) | (send_bytes - 1);
memcpy(&msg[4], send, send_bytes);
- while (1) {
+ for (retry = 0; retry < 4; retry++) {
ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,
msg, msg_bytes, NULL, 0, delay, &ack);
- if (ret < 0)
+ if (ret == -EBUSY)
+ continue;
+ else if (ret < 0)
return ret;
if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
- break;
+ return send_bytes;
else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
udelay(400);
else
return -EIO;
}
- return send_bytes;
+ return -EIO;
}
static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector,
@@ -149,26 +152,31 @@ static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector,
int msg_bytes = 4;
u8 ack;
int ret;
+ unsigned retry;
msg[0] = address;
msg[1] = address >> 8;
msg[2] = AUX_NATIVE_READ << 4;
msg[3] = (msg_bytes << 4) | (recv_bytes - 1);
- while (1) {
+ for (retry = 0; retry < 4; retry++) {
ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,
msg, msg_bytes, recv, recv_bytes, delay, &ack);
- if (ret == 0)
- return -EPROTO;
- if (ret < 0)
+ if (ret == -EBUSY)
+ continue;
+ else if (ret < 0)
return ret;
if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
return ret;
else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
udelay(400);
+ else if (ret == 0)
+ return -EPROTO;
else
return -EIO;
}
+
+ return -EIO;
}
static void radeon_write_dpcd_reg(struct radeon_connector *radeon_connector,
@@ -232,7 +240,9 @@ int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
for (retry = 0; retry < 4; retry++) {
ret = radeon_process_aux_ch(auxch,
msg, msg_bytes, reply, reply_bytes, 0, &ack);
- if (ret < 0) {
+ if (ret == -EBUSY)
+ continue;
+ else if (ret < 0) {
DRM_DEBUG_KMS("aux_ch failed %d\n", ret);
return ret;
}
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index fb5fa0898868..c4ffa14fb2f4 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -41,6 +41,31 @@ static void evergreen_gpu_init(struct radeon_device *rdev);
void evergreen_fini(struct radeon_device *rdev);
static void evergreen_pcie_gen2_enable(struct radeon_device *rdev);
+void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev)
+{
+ u16 ctl, v;
+ int cap, err;
+
+ cap = pci_pcie_cap(rdev->pdev);
+ if (!cap)
+ return;
+
+ err = pci_read_config_word(rdev->pdev, cap + PCI_EXP_DEVCTL, &ctl);
+ if (err)
+ return;
+
+ v = (ctl & PCI_EXP_DEVCTL_READRQ) >> 12;
+
+ /* if bios or OS sets MAX_READ_REQUEST_SIZE to an invalid value, fix it
+ * to avoid hangs or perfomance issues
+ */
+ if ((v == 0) || (v == 6) || (v == 7)) {
+ ctl &= ~PCI_EXP_DEVCTL_READRQ;
+ ctl |= (2 << 12);
+ pci_write_config_word(rdev->pdev, cap + PCI_EXP_DEVCTL, ctl);
+ }
+}
+
void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc)
{
/* enable the pflip int */
@@ -1357,6 +1382,7 @@ int evergreen_cp_resume(struct radeon_device *rdev)
SOFT_RESET_PA |
SOFT_RESET_SH |
SOFT_RESET_VGT |
+ SOFT_RESET_SPI |
SOFT_RESET_SX));
RREG32(GRBM_SOFT_RESET);
mdelay(15);
@@ -1378,7 +1404,8 @@ int evergreen_cp_resume(struct radeon_device *rdev)
/* Initialize the ring buffer's read and write pointers */
WREG32(CP_RB_CNTL, tmp | RB_RPTR_WR_ENA);
WREG32(CP_RB_RPTR_WR, 0);
- WREG32(CP_RB_WPTR, 0);
+ rdev->cp.wptr = 0;
+ WREG32(CP_RB_WPTR, rdev->cp.wptr);
/* set the wb address wether it's enabled or not */
WREG32(CP_RB_RPTR_ADDR,
@@ -1400,7 +1427,6 @@ int evergreen_cp_resume(struct radeon_device *rdev)
WREG32(CP_DEBUG, (1 << 27) | (1 << 28));
rdev->cp.rptr = RREG32(CP_RB_RPTR);
- rdev->cp.wptr = RREG32(CP_RB_WPTR);
evergreen_cp_start(rdev);
rdev->cp.ready = true;
@@ -1564,48 +1590,6 @@ static u32 evergreen_get_tile_pipe_to_backend_map(struct radeon_device *rdev,
return backend_map;
}
-static void evergreen_program_channel_remap(struct radeon_device *rdev)
-{
- u32 tcp_chan_steer_lo, tcp_chan_steer_hi, mc_shared_chremap, tmp;
-
- tmp = RREG32(MC_SHARED_CHMAP);
- switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
- case 0:
- case 1:
- case 2:
- case 3:
- default:
- /* default mapping */
- mc_shared_chremap = 0x00fac688;
- break;
- }
-
- switch (rdev->family) {
- case CHIP_HEMLOCK:
- case CHIP_CYPRESS:
- case CHIP_BARTS:
- tcp_chan_steer_lo = 0x54763210;
- tcp_chan_steer_hi = 0x0000ba98;
- break;
- case CHIP_JUNIPER:
- case CHIP_REDWOOD:
- case CHIP_CEDAR:
- case CHIP_PALM:
- case CHIP_SUMO:
- case CHIP_SUMO2:
- case CHIP_TURKS:
- case CHIP_CAICOS:
- default:
- tcp_chan_steer_lo = 0x76543210;
- tcp_chan_steer_hi = 0x0000ba98;
- break;
- }
-
- WREG32(TCP_CHAN_STEER_LO, tcp_chan_steer_lo);
- WREG32(TCP_CHAN_STEER_HI, tcp_chan_steer_hi);
- WREG32(MC_SHARED_CHREMAP, mc_shared_chremap);
-}
-
static void evergreen_gpu_init(struct radeon_device *rdev)
{
u32 cc_rb_backend_disable = 0;
@@ -1862,6 +1846,8 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff));
+ evergreen_fix_pci_max_read_req_size(rdev);
+
cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & ~2;
cc_gc_shader_pipe_config |=
@@ -2050,8 +2036,6 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
WREG32(DMIF_ADDR_CONFIG, gb_addr_config);
WREG32(HDP_ADDR_CONFIG, gb_addr_config);
- evergreen_program_channel_remap(rdev);
-
num_shader_engines = ((RREG32(GB_ADDR_CONFIG) & NUM_SHADER_ENGINES(3)) >> 12) + 1;
grbm_gfx_index = INSTANCE_BROADCAST_WRITES;
@@ -3143,21 +3127,23 @@ int evergreen_suspend(struct radeon_device *rdev)
}
int evergreen_copy_blit(struct radeon_device *rdev,
- uint64_t src_offset, uint64_t dst_offset,
- unsigned num_pages, struct radeon_fence *fence)
+ uint64_t src_offset,
+ uint64_t dst_offset,
+ unsigned num_gpu_pages,
+ struct radeon_fence *fence)
{
int r;
mutex_lock(&rdev->r600_blit.mutex);
rdev->r600_blit.vb_ib = NULL;
- r = evergreen_blit_prepare_copy(rdev, num_pages * RADEON_GPU_PAGE_SIZE);
+ r = evergreen_blit_prepare_copy(rdev, num_gpu_pages * RADEON_GPU_PAGE_SIZE);
if (r) {
if (rdev->r600_blit.vb_ib)
radeon_ib_free(rdev, &rdev->r600_blit.vb_ib);
mutex_unlock(&rdev->r600_blit.mutex);
return r;
}
- evergreen_kms_blit_copy(rdev, src_offset, dst_offset, num_pages * RADEON_GPU_PAGE_SIZE);
+ evergreen_kms_blit_copy(rdev, src_offset, dst_offset, num_gpu_pages * RADEON_GPU_PAGE_SIZE);
evergreen_blit_done_copy(rdev, fence);
mutex_unlock(&rdev->r600_blit.mutex);
return 0;
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index 44c4750f4518..8c79ca97753d 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -39,6 +39,7 @@ extern int evergreen_mc_wait_for_idle(struct radeon_device *rdev);
extern void evergreen_mc_program(struct radeon_device *rdev);
extern void evergreen_irq_suspend(struct radeon_device *rdev);
extern int evergreen_mc_init(struct radeon_device *rdev);
+extern void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev);
#define EVERGREEN_PFP_UCODE_SIZE 1120
#define EVERGREEN_PM4_UCODE_SIZE 1376
@@ -568,36 +569,6 @@ static u32 cayman_get_tile_pipe_to_backend_map(struct radeon_device *rdev,
return backend_map;
}
-static void cayman_program_channel_remap(struct radeon_device *rdev)
-{
- u32 tcp_chan_steer_lo, tcp_chan_steer_hi, mc_shared_chremap, tmp;
-
- tmp = RREG32(MC_SHARED_CHMAP);
- switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
- case 0:
- case 1:
- case 2:
- case 3:
- default:
- /* default mapping */
- mc_shared_chremap = 0x00fac688;
- break;
- }
-
- switch (rdev->family) {
- case CHIP_CAYMAN:
- default:
- //tcp_chan_steer_lo = 0x54763210
- tcp_chan_steer_lo = 0x76543210;
- tcp_chan_steer_hi = 0x0000ba98;
- break;
- }
-
- WREG32(TCP_CHAN_STEER_LO, tcp_chan_steer_lo);
- WREG32(TCP_CHAN_STEER_HI, tcp_chan_steer_hi);
- WREG32(MC_SHARED_CHREMAP, mc_shared_chremap);
-}
-
static u32 cayman_get_disable_mask_per_asic(struct radeon_device *rdev,
u32 disable_mask_per_se,
u32 max_disable_mask_per_se,
@@ -669,6 +640,8 @@ static void cayman_gpu_init(struct radeon_device *rdev)
WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff));
+ evergreen_fix_pci_max_read_req_size(rdev);
+
mc_shared_chmap = RREG32(MC_SHARED_CHMAP);
mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG);
@@ -839,8 +812,6 @@ static void cayman_gpu_init(struct radeon_device *rdev)
WREG32(DMIF_ADDR_CONFIG, gb_addr_config);
WREG32(HDP_ADDR_CONFIG, gb_addr_config);
- cayman_program_channel_remap(rdev);
-
/* primary versions */
WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable);
WREG32(CC_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable);
@@ -1159,6 +1130,7 @@ int cayman_cp_resume(struct radeon_device *rdev)
SOFT_RESET_PA |
SOFT_RESET_SH |
SOFT_RESET_VGT |
+ SOFT_RESET_SPI |
SOFT_RESET_SX));
RREG32(GRBM_SOFT_RESET);
mdelay(15);
@@ -1183,7 +1155,8 @@ int cayman_cp_resume(struct radeon_device *rdev)
/* Initialize the ring buffer's read and write pointers */
WREG32(CP_RB0_CNTL, tmp | RB_RPTR_WR_ENA);
- WREG32(CP_RB0_WPTR, 0);
+ rdev->cp.wptr = 0;
+ WREG32(CP_RB0_WPTR, rdev->cp.wptr);
/* set the wb address wether it's enabled or not */
WREG32(CP_RB0_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC);
@@ -1203,7 +1176,6 @@ int cayman_cp_resume(struct radeon_device *rdev)
WREG32(CP_RB0_BASE, rdev->cp.gpu_addr >> 8);
rdev->cp.rptr = RREG32(CP_RB0_RPTR);
- rdev->cp.wptr = RREG32(CP_RB0_WPTR);
/* ring1 - compute only */
/* Set ring buffer size */
@@ -1216,7 +1188,8 @@ int cayman_cp_resume(struct radeon_device *rdev)
/* Initialize the ring buffer's read and write pointers */
WREG32(CP_RB1_CNTL, tmp | RB_RPTR_WR_ENA);
- WREG32(CP_RB1_WPTR, 0);
+ rdev->cp1.wptr = 0;
+ WREG32(CP_RB1_WPTR, rdev->cp1.wptr);
/* set the wb address wether it's enabled or not */
WREG32(CP_RB1_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP1_RPTR_OFFSET) & 0xFFFFFFFC);
@@ -1228,7 +1201,6 @@ int cayman_cp_resume(struct radeon_device *rdev)
WREG32(CP_RB1_BASE, rdev->cp1.gpu_addr >> 8);
rdev->cp1.rptr = RREG32(CP_RB1_RPTR);
- rdev->cp1.wptr = RREG32(CP_RB1_WPTR);
/* ring2 - compute only */
/* Set ring buffer size */
@@ -1241,7 +1213,8 @@ int cayman_cp_resume(struct radeon_device *rdev)
/* Initialize the ring buffer's read and write pointers */
WREG32(CP_RB2_CNTL, tmp | RB_RPTR_WR_ENA);
- WREG32(CP_RB2_WPTR, 0);
+ rdev->cp2.wptr = 0;
+ WREG32(CP_RB2_WPTR, rdev->cp2.wptr);
/* set the wb address wether it's enabled or not */
WREG32(CP_RB2_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP2_RPTR_OFFSET) & 0xFFFFFFFC);
@@ -1253,7 +1226,6 @@ int cayman_cp_resume(struct radeon_device *rdev)
WREG32(CP_RB2_BASE, rdev->cp2.gpu_addr >> 8);
rdev->cp2.rptr = RREG32(CP_RB2_RPTR);
- rdev->cp2.wptr = RREG32(CP_RB2_WPTR);
/* start the rings */
cayman_cp_start(rdev);
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index f2204cb1ccdf..7fcdbbbf2979 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -721,11 +721,11 @@ void r100_fence_ring_emit(struct radeon_device *rdev,
int r100_copy_blit(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
- unsigned num_pages,
+ unsigned num_gpu_pages,
struct radeon_fence *fence)
{
uint32_t cur_pages;
- uint32_t stride_bytes = PAGE_SIZE;
+ uint32_t stride_bytes = RADEON_GPU_PAGE_SIZE;
uint32_t pitch;
uint32_t stride_pixels;
unsigned ndw;
@@ -737,7 +737,7 @@ int r100_copy_blit(struct radeon_device *rdev,
/* radeon pitch is /64 */
pitch = stride_bytes / 64;
stride_pixels = stride_bytes / 4;
- num_loops = DIV_ROUND_UP(num_pages, 8191);
+ num_loops = DIV_ROUND_UP(num_gpu_pages, 8191);
/* Ask for enough room for blit + flush + fence */
ndw = 64 + (10 * num_loops);
@@ -746,12 +746,12 @@ int r100_copy_blit(struct radeon_device *rdev,
DRM_ERROR("radeon: moving bo (%d) asking for %u dw.\n", r, ndw);
return -EINVAL;
}
- while (num_pages > 0) {
- cur_pages = num_pages;
+ while (num_gpu_pages > 0) {
+ cur_pages = num_gpu_pages;
if (cur_pages > 8191) {
cur_pages = 8191;
}
- num_pages -= cur_pages;
+ num_gpu_pages -= cur_pages;
/* pages are in Y direction - height
page width in X direction - width */
@@ -773,8 +773,8 @@ int r100_copy_blit(struct radeon_device *rdev,
radeon_ring_write(rdev, (0x1fff) | (0x1fff << 16));
radeon_ring_write(rdev, 0);
radeon_ring_write(rdev, (0x1fff) | (0x1fff << 16));
- radeon_ring_write(rdev, num_pages);
- radeon_ring_write(rdev, num_pages);
+ radeon_ring_write(rdev, num_gpu_pages);
+ radeon_ring_write(rdev, num_gpu_pages);
radeon_ring_write(rdev, cur_pages | (stride_pixels << 16));
}
radeon_ring_write(rdev, PACKET0(RADEON_DSTCACHE_CTLSTAT, 0));
@@ -990,7 +990,8 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size)
/* Force read & write ptr to 0 */
WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA | RADEON_RB_NO_UPDATE);
WREG32(RADEON_CP_RB_RPTR_WR, 0);
- WREG32(RADEON_CP_RB_WPTR, 0);
+ rdev->cp.wptr = 0;
+ WREG32(RADEON_CP_RB_WPTR, rdev->cp.wptr);
/* set the wb address whether it's enabled or not */
WREG32(R_00070C_CP_RB_RPTR_ADDR,
@@ -1007,9 +1008,6 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size)
WREG32(RADEON_CP_RB_CNTL, tmp);
udelay(10);
rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR);
- rdev->cp.wptr = RREG32(RADEON_CP_RB_WPTR);
- /* protect against crazy HW on resume */
- rdev->cp.wptr &= rdev->cp.ptr_mask;
/* Set cp mode to bus mastering & enable cp*/
WREG32(RADEON_CP_CSQ_MODE,
REG_SET(RADEON_INDIRECT2_START, indirect2_start) |
diff --git a/drivers/gpu/drm/radeon/r200.c b/drivers/gpu/drm/radeon/r200.c
index f24058300413..a1f3ba063c2d 100644
--- a/drivers/gpu/drm/radeon/r200.c
+++ b/drivers/gpu/drm/radeon/r200.c
@@ -84,7 +84,7 @@ static int r200_get_vtx_size_0(uint32_t vtx_fmt_0)
int r200_copy_dma(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
- unsigned num_pages,
+ unsigned num_gpu_pages,
struct radeon_fence *fence)
{
uint32_t size;
@@ -93,7 +93,7 @@ int r200_copy_dma(struct radeon_device *rdev,
int r = 0;
/* radeon pitch is /64 */
- size = num_pages << PAGE_SHIFT;
+ size = num_gpu_pages << RADEON_GPU_PAGE_SHIFT;
num_loops = DIV_ROUND_UP(size, 0x1FFFFF);
r = radeon_ring_lock(rdev, num_loops * 4 + 64);
if (r) {
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index aa5571b73aa0..720dd99163f8 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -2209,7 +2209,8 @@ int r600_cp_resume(struct radeon_device *rdev)
/* Initialize the ring buffer's read and write pointers */
WREG32(CP_RB_CNTL, tmp | RB_RPTR_WR_ENA);
WREG32(CP_RB_RPTR_WR, 0);
- WREG32(CP_RB_WPTR, 0);
+ rdev->cp.wptr = 0;
+ WREG32(CP_RB_WPTR, rdev->cp.wptr);
/* set the wb address whether it's enabled or not */
WREG32(CP_RB_RPTR_ADDR,
@@ -2231,7 +2232,6 @@ int r600_cp_resume(struct radeon_device *rdev)
WREG32(CP_DEBUG, (1 << 27) | (1 << 28));
rdev->cp.rptr = RREG32(CP_RB_RPTR);
- rdev->cp.wptr = RREG32(CP_RB_WPTR);
r600_cp_start(rdev);
rdev->cp.ready = true;
@@ -2353,21 +2353,23 @@ void r600_fence_ring_emit(struct radeon_device *rdev,
}
int r600_copy_blit(struct radeon_device *rdev,
- uint64_t src_offset, uint64_t dst_offset,
- unsigned num_pages, struct radeon_fence *fence)
+ uint64_t src_offset,
+ uint64_t dst_offset,
+ unsigned num_gpu_pages,
+ struct radeon_fence *fence)
{
int r;
mutex_lock(&rdev->r600_blit.mutex);
rdev->r600_blit.vb_ib = NULL;
- r = r600_blit_prepare_copy(rdev, num_pages * RADEON_GPU_PAGE_SIZE);
+ r = r600_blit_prepare_copy(rdev, num_gpu_pages * RADEON_GPU_PAGE_SIZE);
if (r) {
if (rdev->r600_blit.vb_ib)
radeon_ib_free(rdev, &rdev->r600_blit.vb_ib);
mutex_unlock(&rdev->r600_blit.mutex);
return r;
}
- r600_kms_blit_copy(rdev, src_offset, dst_offset, num_pages * RADEON_GPU_PAGE_SIZE);
+ r600_kms_blit_copy(rdev, src_offset, dst_offset, num_gpu_pages * RADEON_GPU_PAGE_SIZE);
r600_blit_done_copy(rdev, fence);
mutex_unlock(&rdev->r600_blit.mutex);
return 0;
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 32807baf55e2..c1e056b35b29 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -322,6 +322,7 @@ union radeon_gart_table {
#define RADEON_GPU_PAGE_SIZE 4096
#define RADEON_GPU_PAGE_MASK (RADEON_GPU_PAGE_SIZE - 1)
+#define RADEON_GPU_PAGE_SHIFT 12
struct radeon_gart {
dma_addr_t table_addr;
@@ -914,17 +915,17 @@ struct radeon_asic {
int (*copy_blit)(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
- unsigned num_pages,
+ unsigned num_gpu_pages,
struct radeon_fence *fence);
int (*copy_dma)(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
- unsigned num_pages,
+ unsigned num_gpu_pages,
struct radeon_fence *fence);
int (*copy)(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
- unsigned num_pages,
+ unsigned num_gpu_pages,
struct radeon_fence *fence);
uint32_t (*get_engine_clock)(struct radeon_device *rdev);
void (*set_engine_clock)(struct radeon_device *rdev, uint32_t eng_clock);
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 3d7a0d7c6a9a..3dedaa07aac1 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -75,7 +75,7 @@ uint32_t r100_pll_rreg(struct radeon_device *rdev, uint32_t reg);
int r100_copy_blit(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
- unsigned num_pages,
+ unsigned num_gpu_pages,
struct radeon_fence *fence);
int r100_set_surface_reg(struct radeon_device *rdev, int reg,
uint32_t tiling_flags, uint32_t pitch,
@@ -143,7 +143,7 @@ extern void r100_post_page_flip(struct radeon_device *rdev, int crtc);
extern int r200_copy_dma(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
- unsigned num_pages,
+ unsigned num_gpu_pages,
struct radeon_fence *fence);
void r200_set_safe_registers(struct radeon_device *rdev);
@@ -311,7 +311,7 @@ void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
int r600_ring_test(struct radeon_device *rdev);
int r600_copy_blit(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
- unsigned num_pages, struct radeon_fence *fence);
+ unsigned num_gpu_pages, struct radeon_fence *fence);
void r600_hpd_init(struct radeon_device *rdev);
void r600_hpd_fini(struct radeon_device *rdev);
bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd);
@@ -403,7 +403,7 @@ void evergreen_bandwidth_update(struct radeon_device *rdev);
void evergreen_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
int evergreen_copy_blit(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
- unsigned num_pages, struct radeon_fence *fence);
+ unsigned num_gpu_pages, struct radeon_fence *fence);
void evergreen_hpd_init(struct radeon_device *rdev);
void evergreen_hpd_fini(struct radeon_device *rdev);
bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd);
diff --git a/drivers/gpu/drm/radeon/radeon_clocks.c b/drivers/gpu/drm/radeon/radeon_clocks.c
index dcd0863e31ae..b6e18c8db9f5 100644
--- a/drivers/gpu/drm/radeon/radeon_clocks.c
+++ b/drivers/gpu/drm/radeon/radeon_clocks.c
@@ -219,6 +219,9 @@ void radeon_get_clock_info(struct drm_device *dev)
} else {
DRM_INFO("Using generic clock info\n");
+ /* may need to be per card */
+ rdev->clock.max_pixel_clock = 35000;
+
if (rdev->flags & RADEON_IS_IGP) {
p1pll->reference_freq = 1432;
p2pll->reference_freq = 1432;
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
index e0138b674aca..63675241c7ff 100644
--- a/drivers/gpu/drm/radeon/radeon_combios.c
+++ b/drivers/gpu/drm/radeon/radeon_combios.c
@@ -3298,6 +3298,14 @@ void radeon_combios_asic_init(struct drm_device *dev)
rdev->pdev->subsystem_device == 0x30a4)
return;
+ /* quirk for rs4xx Compaq Presario V5245EU laptop to make it resume
+ * - it hangs on resume inside the dynclk 1 table.
+ */
+ if (rdev->family == CHIP_RS480 &&
+ rdev->pdev->subsystem_vendor == 0x103c &&
+ rdev->pdev->subsystem_device == 0x30ae)
+ return;
+
/* DYN CLK 1 */
table = combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE);
if (table)
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 7f65940f918f..449c3d8c6836 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -68,11 +68,11 @@ void radeon_connector_hotplug(struct drm_connector *connector)
if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
int saved_dpms = connector->dpms;
- if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd) &&
- radeon_dp_needs_link_train(radeon_connector))
- drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
- else
+ /* Only turn off the display it it's physically disconnected */
+ if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+ else if (radeon_dp_needs_link_train(radeon_connector))
+ drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
connector->dpms = saved_dpms;
}
}
@@ -466,6 +466,16 @@ static bool radeon_connector_needs_extended_probe(struct radeon_device *dev,
(supported_device == ATOM_DEVICE_DFP2_SUPPORT))
return true;
}
+ /* TOSHIBA Satellite L300D with ATI Mobility Radeon x1100
+ * (RS690M) sends data to i2c bus for a HDMI connector that
+ * is not implemented */
+ if ((dev->pdev->device == 0x791f) &&
+ (dev->pdev->subsystem_vendor == 0x1179) &&
+ (dev->pdev->subsystem_device == 0xff68)) {
+ if ((connector_type == DRM_MODE_CONNECTOR_HDMIA) &&
+ (supported_device == ATOM_DEVICE_DFP2_SUPPORT))
+ return true;
+ }
/* Default: no EDID header probe required for DDC probing */
return false;
@@ -1287,12 +1297,24 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
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_is_dp_bridge(connector)) {
- if (encoder)
- radeon_atom_ext_encoder_setup_ddc(encoder);
+ } else if (radeon_connector_encoder_is_dp_bridge(connector)) {
+ /* DP bridges are always DP */
+ radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
+ /* get the DPCD from the bridge */
+ radeon_dp_getdpcd(radeon_connector);
+
+ if (encoder) {
+ /* setup ddc on the bridge */
+ radeon_atom_ext_encoder_setup_ddc(encoder);
+ if (radeon_ddc_probe(radeon_connector,
+ radeon_connector->requires_extended_probe)) /* try DDC */
+ ret = connector_status_connected;
+ else if (radeon_connector->dac_load_detect) { /* try load detection */
+ struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
+ ret = encoder_funcs->detect(encoder, connector);
+ }
}
+ } else {
radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
ret = connector_status_connected;
@@ -1308,16 +1330,6 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
ret = connector_status_connected;
}
}
-
- if ((ret == connector_status_disconnected) &&
- radeon_connector->dac_load_detect) {
- struct drm_encoder *encoder = radeon_best_single_encoder(connector);
- struct drm_encoder_helper_funcs *encoder_funcs;
- if (encoder) {
- encoder_funcs = encoder->helper_private;
- ret = encoder_funcs->detect(encoder, connector);
- }
- }
}
radeon_connector_update_scratch_regs(connector, ret);
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c
index 3189a7efb2e9..fde25c0d65a0 100644
--- a/drivers/gpu/drm/radeon/radeon_cursor.c
+++ b/drivers/gpu/drm/radeon/radeon_cursor.c
@@ -208,23 +208,25 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
int xorigin = 0, yorigin = 0;
int w = radeon_crtc->cursor_width;
- if (x < 0)
- xorigin = -x + 1;
- if (y < 0)
- yorigin = -y + 1;
- if (xorigin >= CURSOR_WIDTH)
- xorigin = CURSOR_WIDTH - 1;
- if (yorigin >= CURSOR_HEIGHT)
- yorigin = CURSOR_HEIGHT - 1;
-
if (ASIC_IS_AVIVO(rdev)) {
- int i = 0;
- struct drm_crtc *crtc_p;
-
/* avivo cursor are offset into the total surface */
x += crtc->x;
y += crtc->y;
- DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
+ }
+ DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
+
+ if (x < 0) {
+ xorigin = min(-x, CURSOR_WIDTH - 1);
+ x = 0;
+ }
+ if (y < 0) {
+ yorigin = min(-y, CURSOR_HEIGHT - 1);
+ y = 0;
+ }
+
+ if (ASIC_IS_AVIVO(rdev)) {
+ int i = 0;
+ struct drm_crtc *crtc_p;
/* avivo cursor image can't end on 128 pixel boundary or
* go past the end of the frame if both crtcs are enabled
@@ -253,16 +255,12 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
radeon_lock_cursor(crtc, true);
if (ASIC_IS_DCE4(rdev)) {
- WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset,
- ((xorigin ? 0 : x) << 16) |
- (yorigin ? 0 : y));
+ WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset,
((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
} else if (ASIC_IS_AVIVO(rdev)) {
- WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset,
- ((xorigin ? 0 : x) << 16) |
- (yorigin ? 0 : y));
+ WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
@@ -276,8 +274,8 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
| yorigin));
WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset,
(RADEON_CUR_LOCK
- | ((xorigin ? 0 : x) << 16)
- | (yorigin ? 0 : y)));
+ | (x << 16)
+ | y));
/* offset is from DISP(2)_BASE_ADDRESS */
WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset +
(yorigin * 256)));
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index a3b011b49465..b51e15725c6e 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -301,6 +301,8 @@ void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64
mc->mc_vram_size = mc->aper_size;
}
mc->vram_end = mc->vram_start + mc->mc_vram_size - 1;
+ if (radeon_vram_limit && radeon_vram_limit < mc->real_vram_size)
+ mc->real_vram_size = radeon_vram_limit;
dev_info(rdev->dev, "VRAM: %lluM 0x%016llX - 0x%016llX (%lluM used)\n",
mc->mc_vram_size >> 20, mc->vram_start,
mc->vram_end, mc->real_vram_size >> 20);
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 1a858944e4f3..6adb3e58affd 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -473,8 +473,8 @@ pflip_cleanup:
spin_lock_irqsave(&dev->event_lock, flags);
radeon_crtc->unpin_work = NULL;
unlock_free:
- drm_gem_object_unreference_unlocked(old_radeon_fb->obj);
spin_unlock_irqrestore(&dev->event_lock, flags);
+ drm_gem_object_unreference_unlocked(old_radeon_fb->obj);
radeon_fence_unref(&work->fence);
kfree(work);
@@ -707,16 +707,21 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
radeon_router_select_ddc_port(radeon_connector);
if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
- (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) {
+ (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP) ||
+ radeon_connector_encoder_is_dp_bridge(&radeon_connector->base)) {
struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
+
if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT ||
dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && dig->dp_i2c_bus)
- radeon_connector->edid = drm_get_edid(&radeon_connector->base, &dig->dp_i2c_bus->adapter);
- }
- if (!radeon_connector->ddc_bus)
- return -1;
- if (!radeon_connector->edid) {
- radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
+ radeon_connector->edid = drm_get_edid(&radeon_connector->base,
+ &dig->dp_i2c_bus->adapter);
+ else if (radeon_connector->ddc_bus && !radeon_connector->edid)
+ radeon_connector->edid = drm_get_edid(&radeon_connector->base,
+ &radeon_connector->ddc_bus->adapter);
+ } else {
+ if (radeon_connector->ddc_bus && !radeon_connector->edid)
+ radeon_connector->edid = drm_get_edid(&radeon_connector->base,
+ &radeon_connector->ddc_bus->adapter);
}
if (!radeon_connector->edid) {
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c
index 319d85d7e759..eb3f6dc6df83 100644
--- a/drivers/gpu/drm/radeon/radeon_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_encoders.c
@@ -1507,7 +1507,14 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
switch (mode) {
case DRM_MODE_DPMS_ON:
args.ucAction = ATOM_ENABLE;
- atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+ /* workaround for DVOOutputControl on some RS690 systems */
+ if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DDI) {
+ u32 reg = RREG32(RADEON_BIOS_3_SCRATCH);
+ WREG32(RADEON_BIOS_3_SCRATCH, reg & ~ATOM_S3_DFP2I_ACTIVE);
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+ WREG32(RADEON_BIOS_3_SCRATCH, reg);
+ } else
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
args.ucAction = ATOM_LCD_BLON;
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
@@ -1631,7 +1638,17 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
break;
case 2:
args.v2.ucCRTC = radeon_crtc->crtc_id;
- args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder);
+ if (radeon_encoder_is_dp_bridge(encoder)) {
+ struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+
+ if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
+ args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS;
+ else if (connector->connector_type == DRM_MODE_CONNECTOR_VGA)
+ args.v2.ucEncodeMode = ATOM_ENCODER_MODE_CRT;
+ else
+ args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder);
+ } else
+ args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder);
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
@@ -1748,9 +1765,17 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
/* DCE4/5 */
if (ASIC_IS_DCE4(rdev)) {
dig = radeon_encoder->enc_priv;
- if (ASIC_IS_DCE41(rdev))
- return radeon_crtc->crtc_id;
- else {
+ if (ASIC_IS_DCE41(rdev)) {
+ /* ontario follows DCE4 */
+ if (rdev->family == CHIP_PALM) {
+ if (dig->linkb)
+ return 1;
+ else
+ return 0;
+ } else
+ /* llano follows DCE3.2 */
+ return radeon_crtc->crtc_id;
+ } else {
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
if (dig->linkb)
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c
index 7fd4e3e5ad5f..3475a09f946b 100644
--- a/drivers/gpu/drm/radeon/radeon_fence.c
+++ b/drivers/gpu/drm/radeon/radeon_fence.c
@@ -48,7 +48,7 @@ static void radeon_fence_write(struct radeon_device *rdev, u32 seq)
scratch_index = R600_WB_EVENT_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base;
else
scratch_index = RADEON_WB_SCRATCH_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base;
- rdev->wb.wb[scratch_index/4] = cpu_to_le32(seq);;
+ rdev->wb.wb[scratch_index/4] = cpu_to_le32(seq);
} else
WREG32(rdev->fence_drv.scratch_reg, seq);
}
diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c
index dee4a0c1b4b2..602fa3541c45 100644
--- a/drivers/gpu/drm/radeon/radeon_test.c
+++ b/drivers/gpu/drm/radeon/radeon_test.c
@@ -40,10 +40,14 @@ void radeon_test_moves(struct radeon_device *rdev)
size = 1024 * 1024;
/* Number of tests =
- * (Total GTT - IB pool - writeback page - ring buffer) / test size
+ * (Total GTT - IB pool - writeback page - ring buffers) / test size
*/
- n = ((u32)(rdev->mc.gtt_size - RADEON_IB_POOL_SIZE*64*1024 - RADEON_GPU_PAGE_SIZE -
- rdev->cp.ring_size)) / size;
+ n = rdev->mc.gtt_size - RADEON_IB_POOL_SIZE*64*1024 - rdev->cp.ring_size;
+ if (rdev->wb.wb_obj)
+ n -= RADEON_GPU_PAGE_SIZE;
+ if (rdev->ih.ring_obj)
+ n -= rdev->ih.ring_size;
+ n /= size;
gtt_obj = kzalloc(n * sizeof(*gtt_obj), GFP_KERNEL);
if (!gtt_obj) {
@@ -132,9 +136,15 @@ void radeon_test_moves(struct radeon_device *rdev)
gtt_start++, vram_start++) {
if (*vram_start != gtt_start) {
DRM_ERROR("Incorrect GTT->VRAM copy %d: Got 0x%p, "
- "expected 0x%p (GTT map 0x%p-0x%p)\n",
- i, *vram_start, gtt_start, gtt_map,
- gtt_end);
+ "expected 0x%p (GTT/VRAM offset "
+ "0x%16llx/0x%16llx)\n",
+ i, *vram_start, gtt_start,
+ (unsigned long long)
+ (gtt_addr - rdev->mc.gtt_start +
+ (void*)gtt_start - gtt_map),
+ (unsigned long long)
+ (vram_addr - rdev->mc.vram_start +
+ (void*)gtt_start - gtt_map));
radeon_bo_kunmap(vram_obj);
goto out_cleanup;
}
@@ -175,9 +185,15 @@ void radeon_test_moves(struct radeon_device *rdev)
gtt_start++, vram_start++) {
if (*gtt_start != vram_start) {
DRM_ERROR("Incorrect VRAM->GTT copy %d: Got 0x%p, "
- "expected 0x%p (VRAM map 0x%p-0x%p)\n",
- i, *gtt_start, vram_start, vram_map,
- vram_end);
+ "expected 0x%p (VRAM/GTT offset "
+ "0x%16llx/0x%16llx)\n",
+ i, *gtt_start, vram_start,
+ (unsigned long long)
+ (vram_addr - rdev->mc.vram_start +
+ (void*)vram_start - vram_map),
+ (unsigned long long)
+ (gtt_addr - rdev->mc.gtt_start +
+ (void*)vram_start - vram_map));
radeon_bo_kunmap(gtt_obj[i]);
goto out_cleanup;
}
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index 60125ddba1e9..0b5468bfaf54 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -277,7 +277,12 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,
DRM_ERROR("Trying to move memory with CP turned off.\n");
return -EINVAL;
}
- r = radeon_copy(rdev, old_start, new_start, new_mem->num_pages, fence);
+
+ BUILD_BUG_ON((PAGE_SIZE % RADEON_GPU_PAGE_SIZE) != 0);
+
+ r = radeon_copy(rdev, old_start, new_start,
+ new_mem->num_pages * (PAGE_SIZE / RADEON_GPU_PAGE_SIZE), /* GPU pages */
+ fence);
/* FIXME: handle copy error */
r = ttm_bo_move_accel_cleanup(bo, (void *)fence, NULL,
evict, no_wait_reserve, no_wait_gpu, new_mem);
@@ -450,6 +455,29 @@ static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_
return -EINVAL;
mem->bus.base = rdev->mc.aper_base;
mem->bus.is_iomem = true;
+#ifdef __alpha__
+ /*
+ * Alpha: use bus.addr to hold the ioremap() return,
+ * so we can modify bus.base below.
+ */
+ if (mem->placement & TTM_PL_FLAG_WC)
+ mem->bus.addr =
+ ioremap_wc(mem->bus.base + mem->bus.offset,
+ mem->bus.size);
+ else
+ mem->bus.addr =
+ ioremap_nocache(mem->bus.base + mem->bus.offset,
+ mem->bus.size);
+
+ /*
+ * Alpha: Use just the bus offset plus
+ * the hose/domain memory base for bus.base.
+ * It then can be used to build PTEs for VRAM
+ * access, as done in ttm_bo_vm_fault().
+ */
+ mem->bus.base = (mem->bus.base & 0x0ffffffffUL) +
+ rdev->ddev->hose->dense_mem_base;
+#endif
break;
default:
return -EINVAL;
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 4720d000d440..b13c2eedc321 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -536,55 +536,6 @@ static u32 r700_get_tile_pipe_to_backend_map(struct radeon_device *rdev,
return backend_map;
}
-static void rv770_program_channel_remap(struct radeon_device *rdev)
-{
- u32 tcp_chan_steer, mc_shared_chremap, tmp;
- bool force_no_swizzle;
-
- switch (rdev->family) {
- case CHIP_RV770:
- case CHIP_RV730:
- force_no_swizzle = false;
- break;
- case CHIP_RV710:
- case CHIP_RV740:
- default:
- force_no_swizzle = true;
- break;
- }
-
- tmp = RREG32(MC_SHARED_CHMAP);
- switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
- case 0:
- case 1:
- default:
- /* default mapping */
- mc_shared_chremap = 0x00fac688;
- break;
- case 2:
- case 3:
- if (force_no_swizzle)
- mc_shared_chremap = 0x00fac688;
- else
- mc_shared_chremap = 0x00bbc298;
- break;
- }
-
- if (rdev->family == CHIP_RV740)
- tcp_chan_steer = 0x00ef2a60;
- else
- tcp_chan_steer = 0x00fac688;
-
- /* RV770 CE has special chremap setup */
- if (rdev->pdev->device == 0x944e) {
- tcp_chan_steer = 0x00b08b08;
- mc_shared_chremap = 0x00b08b08;
- }
-
- WREG32(TCP_CHAN_STEER, tcp_chan_steer);
- WREG32(MC_SHARED_CHREMAP, mc_shared_chremap);
-}
-
static void rv770_gpu_init(struct radeon_device *rdev)
{
int i, j, num_qd_pipes;
@@ -785,8 +736,6 @@ static void rv770_gpu_init(struct radeon_device *rdev)
WREG32(DCP_TILING_CONFIG, (gb_tiling_config & 0xffff));
WREG32(HDP_TILING_CONFIG, (gb_tiling_config & 0xffff));
- rv770_program_channel_remap(rdev);
-
WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable);
WREG32(CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
WREG32(GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 56619f64b6bf..ef06194c5aa6 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -353,8 +353,10 @@ static int ttm_bo_add_ttm(struct ttm_buffer_object *bo, bool zero_alloc)
ret = ttm_tt_set_user(bo->ttm, current,
bo->buffer_start, bo->num_pages);
- if (unlikely(ret != 0))
+ if (unlikely(ret != 0)) {
ttm_tt_destroy(bo->ttm);
+ bo->ttm = NULL;
+ }
break;
default:
printk(KERN_ERR TTM_PFX "Illegal buffer object type\n");
@@ -390,10 +392,13 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
* Create and bind a ttm if required.
*/
- if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED) && (bo->ttm == NULL)) {
- ret = ttm_bo_add_ttm(bo, false);
- if (ret)
- goto out_err;
+ if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) {
+ if (bo->ttm == NULL) {
+ bool zero = !(old_man->flags & TTM_MEMTYPE_FLAG_FIXED);
+ ret = ttm_bo_add_ttm(bo, zero);
+ if (ret)
+ goto out_err;
+ }
ret = ttm_tt_set_placement_caching(bo->ttm, mem->placement);
if (ret)
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index 77dbf408c0d0..082fcaea583f 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -321,7 +321,7 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
struct ttm_mem_type_manager *man = &bdev->man[new_mem->mem_type];
struct ttm_tt *ttm = bo->ttm;
struct ttm_mem_reg *old_mem = &bo->mem;
- struct ttm_mem_reg old_copy;
+ struct ttm_mem_reg old_copy = *old_mem;
void *old_iomap;
void *new_iomap;
int ret;
@@ -635,13 +635,13 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
if (ret)
return ret;
- ttm_bo_free_old_node(bo);
if ((man->flags & TTM_MEMTYPE_FLAG_FIXED) &&
(bo->ttm != NULL)) {
ttm_tt_unbind(bo->ttm);
ttm_tt_destroy(bo->ttm);
bo->ttm = NULL;
}
+ ttm_bo_free_old_node(bo);
} else {
/**
* This should help pipeline ordinary buffer moves.
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 306b15f39c9c..22a4a051f221 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -69,7 +69,7 @@ config HID_ACRUX
Say Y here if you want to enable support for ACRUX game controllers.
config HID_ACRUX_FF
- tristate "ACRUX force feedback support"
+ bool "ACRUX force feedback support"
depends on HID_ACRUX
select INPUT_FF_MEMLESS
---help---
@@ -245,6 +245,15 @@ config HID_LOGITECH
---help---
Support for Logitech devices that are not fully compliant with HID standard.
+config HID_LOGITECH_DJ
+ tristate "Logitech Unifying receivers full support"
+ depends on HID_LOGITECH
+ default m
+ ---help---
+ Say Y if you want support for Logitech Unifying receivers and devices.
+ Unifying receivers are capable of pairing up to 6 Logitech compliant
+ devices to the same receiver.
+
config LOGITECH_FF
bool "Logitech force feedback support"
depends on HID_LOGITECH
@@ -278,13 +287,21 @@ config LOGIG940_FF
Say Y here if you want to enable force feedback support for Logitech
Flight System G940 devices.
-config LOGIWII_FF
- bool "Logitech Speed Force Wireless force feedback support"
+config LOGIWHEELS_FF
+ bool "Logitech wheels configuration and force feedback support"
depends on HID_LOGITECH
select INPUT_FF_MEMLESS
+ default LOGITECH_FF
help
- Say Y here if you want to enable force feedback support for Logitech
- Speed Force Wireless (Wii) devices.
+ Say Y here if you want to enable force feedback and range setting
+ support for following Logitech wheels:
+ - Logitech Driving Force
+ - Logitech Driving Force Pro
+ - Logitech Driving Force GT
+ - Logitech G25
+ - Logitech G27
+ - Logitech MOMO/MOMO 2
+ - Logitech Formula Force EX
config HID_MAGICMOUSE
tristate "Apple MagicMouse multi-touch support"
@@ -328,6 +345,7 @@ config HID_MULTITOUCH
- Hanvon dual touch panels
- Ilitek dual touch panels
- IrTouch Infrared USB panels
+ - LG Display panels (Dell ST2220Tc)
- Lumio CrystalTouch panels
- MosArt dual-touch panels
- PenMount dual touch panels
@@ -441,6 +459,13 @@ config HID_PICOLCD_LEDS
---help---
Provide access to PicoLCD's GPO pins via leds class.
+config HID_PRIMAX
+ tristate "Primax non-fully HID-compliant devices"
+ depends on USB_HID
+ ---help---
+ Support for Primax devices that are not fully compliant with the
+ HID standard.
+
config HID_QUANTA
tristate "Quanta Optical Touch panels"
depends on USB_HID
@@ -539,7 +564,11 @@ config HID_SMARTJOYPLUS
tristate "SmartJoy PLUS PS2/USB adapter support"
depends on USB_HID
---help---
- Support for SmartJoy PLUS PS2/USB adapter.
+ Support for SmartJoy PLUS PS2/USB adapter, Super Dual Box,
+ Super Joy Box 3 Pro, Super Dual Box Pro, and Super Joy Box 5 Pro.
+
+ Note that DDR (Dance Dance Revolution) mode is not supported, nor
+ is pressure sensitive buttons on the pro models.
config SMARTJOYPLUS_FF
bool "SmartJoy PLUS PS2/USB adapter force feedback support"
@@ -589,6 +618,8 @@ config HID_WACOM_POWER_SUPPLY
config HID_WIIMOTE
tristate "Nintendo Wii Remote support"
depends on BT_HIDP
+ depends on LEDS_CLASS
+ select POWER_SUPPLY
---help---
Support for the Nintendo Wii Remote bluetooth device.
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 0a0a38e9fd28..1e0d2a638b28 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -21,7 +21,7 @@ endif
ifdef CONFIG_LOGIG940_FF
hid-logitech-y += hid-lg3ff.o
endif
-ifdef CONFIG_LOGIWII_FF
+ifdef CONFIG_LOGIWHEELS_FF
hid-logitech-y += hid-lg4ff.o
endif
@@ -43,6 +43,7 @@ obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o
obj-$(CONFIG_HID_KYE) += hid-kye.o
obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o
obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o
+obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o
obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o
obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o
obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o
@@ -54,6 +55,7 @@ obj-$(CONFIG_HID_QUANTA) += hid-quanta.o
obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o
obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o
+obj-$(CONFIG_HID_PRIMAX) += hid-primax.o
obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o
obj-$(CONFIG_HID_ROCCAT_COMMON) += hid-roccat-common.o
obj-$(CONFIG_HID_ROCCAT_ARVO) += hid-roccat-arvo.o
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index b85744fe8464..9bc7b03269df 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -183,6 +183,9 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI &&
hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS)
table = macbookair_fn_keys;
+ else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI &&
+ hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING6_JIS)
+ table = macbookair_fn_keys;
else if (hid->product < 0x21d || hid->product >= 0x300)
table = powerbook_fn_keys;
else
@@ -444,6 +447,12 @@ static const struct hid_device_id apple_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
APPLE_RDESC_JIS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI),
+ .driver_data = APPLE_HAS_FN },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO),
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_JIS),
+ .driver_data = APPLE_HAS_FN },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO),
@@ -487,6 +496,18 @@ static const struct hid_device_id apple_devices[] = {
.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS),
.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI),
+ .driver_data = APPLE_HAS_FN },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO),
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS),
+ .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI),
+ .driver_data = APPLE_HAS_FN },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO),
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS),
+ .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
diff --git a/drivers/hid/hid-axff.c b/drivers/hid/hid-axff.c
index 121514149e0b..3bdb4500f95e 100644
--- a/drivers/hid/hid-axff.c
+++ b/drivers/hid/hid-axff.c
@@ -6,7 +6,7 @@
* Xbox 360 controller.
*
* 1a34:0802 "ACRUX USB GAMEPAD 8116"
- * - tested with a EXEQ EQ-PCU-02090 game controller.
+ * - tested with an EXEQ EQ-PCU-02090 game controller.
*
* Copyright (c) 2010 Sergei Kolzun <x0r@dv-life.ru>
*/
@@ -45,7 +45,10 @@ static int axff_play(struct input_dev *dev, void *data, struct ff_effect *effect
{
struct hid_device *hid = input_get_drvdata(dev);
struct axff_device *axff = data;
+ struct hid_report *report = axff->report;
+ int field_count = 0;
int left, right;
+ int i, j;
left = effect->u.rumble.strong_magnitude;
right = effect->u.rumble.weak_magnitude;
@@ -55,10 +58,14 @@ static int axff_play(struct input_dev *dev, void *data, struct ff_effect *effect
left = left * 0xff / 0xffff;
right = right * 0xff / 0xffff;
- axff->report->field[0]->value[0] = left;
- axff->report->field[1]->value[0] = right;
- axff->report->field[2]->value[0] = left;
- axff->report->field[3]->value[0] = right;
+ for (i = 0; i < report->maxfield; i++) {
+ for (j = 0; j < report->field[i]->report_count; j++) {
+ report->field[i]->value[j] =
+ field_count % 2 ? right : left;
+ field_count++;
+ }
+ }
+
dbg_hid("running with 0x%02x 0x%02x", left, right);
usbhid_submit_report(hid, axff->report, USB_DIR_OUT);
@@ -72,6 +79,8 @@ static int axff_init(struct hid_device *hid)
struct hid_input *hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
struct list_head *report_list =&hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct input_dev *dev = hidinput->input;
+ int field_count = 0;
+ int i, j;
int error;
if (list_empty(report_list)) {
@@ -80,9 +89,16 @@ static int axff_init(struct hid_device *hid)
}
report = list_first_entry(report_list, struct hid_report, list);
+ for (i = 0; i < report->maxfield; i++) {
+ for (j = 0; j < report->field[i]->report_count; j++) {
+ report->field[i]->value[j] = 0x00;
+ field_count++;
+ }
+ }
- if (report->maxfield < 4) {
- hid_err(hid, "no fields in the report: %d\n", report->maxfield);
+ if (field_count < 4) {
+ hid_err(hid, "not enough fields in the report: %d\n",
+ field_count);
return -ENODEV;
}
@@ -97,13 +113,9 @@ static int axff_init(struct hid_device *hid)
goto err_free_mem;
axff->report = report;
- axff->report->field[0]->value[0] = 0x00;
- axff->report->field[1]->value[0] = 0x00;
- axff->report->field[2]->value[0] = 0x00;
- axff->report->field[3]->value[0] = 0x00;
usbhid_submit_report(hid, axff->report, USB_DIR_OUT);
- hid_info(hid, "Force Feedback for ACRUX game controllers by Sergei Kolzun<x0r@dv-life.ru>\n");
+ hid_info(hid, "Force Feedback for ACRUX game controllers by Sergei Kolzun <x0r@dv-life.ru>\n");
return 0;
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 1a5cf0c9cfca..91adcc5bad28 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -29,6 +29,7 @@
#include <linux/wait.h>
#include <linux/vmalloc.h>
#include <linux/sched.h>
+#include <linux/semaphore.h>
#include <linux/hid.h>
#include <linux/hiddev.h>
@@ -1085,16 +1086,25 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
struct hid_report *report;
char *buf;
unsigned int i;
- int ret;
+ int ret = 0;
- if (!hid || !hid->driver)
+ if (!hid)
return -ENODEV;
+
+ if (down_trylock(&hid->driver_lock))
+ return -EBUSY;
+
+ if (!hid->driver) {
+ ret = -ENODEV;
+ goto unlock;
+ }
report_enum = hid->report_enum + type;
hdrv = hid->driver;
if (!size) {
dbg_hid("empty report\n");
- return -1;
+ ret = -1;
+ goto unlock;
}
buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC);
@@ -1118,18 +1128,24 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
nomem:
report = hid_get_report(report_enum, data);
- if (!report)
- return -1;
+ if (!report) {
+ ret = -1;
+ goto unlock;
+ }
if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) {
ret = hdrv->raw_event(hid, report, data, size);
- if (ret != 0)
- return ret < 0 ? ret : 0;
+ if (ret != 0) {
+ ret = ret < 0 ? ret : 0;
+ goto unlock;
+ }
}
hid_report_raw_event(hid, type, data, size, interrupt);
- return 0;
+unlock:
+ up(&hid->driver_lock);
+ return ret;
}
EXPORT_SYMBOL_GPL(hid_input_report);
@@ -1212,6 +1228,12 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
if ((connect_mask & HID_CONNECT_HIDINPUT) && !hidinput_connect(hdev,
connect_mask & HID_CONNECT_HIDINPUT_FORCE))
hdev->claimed |= HID_CLAIMED_INPUT;
+ if (hdev->quirks & HID_QUIRK_MULTITOUCH) {
+ /* this device should be handled by hid-multitouch, skip it */
+ hdev->quirks &= ~HID_QUIRK_MULTITOUCH;
+ return -ENODEV;
+ }
+
if ((connect_mask & HID_CONNECT_HIDDEV) && hdev->hiddev_connect &&
!hdev->hiddev_connect(hdev,
connect_mask & HID_CONNECT_HIDDEV_FORCE))
@@ -1340,6 +1362,15 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
@@ -1388,6 +1419,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HANVON, USB_DEVICE_ID_HANVON_MULTITOUCH) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6650) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ILITEK, USB_DEVICE_ID_ILITEK_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
@@ -1396,6 +1428,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LG, USB_DEVICE_ID_LG_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
@@ -1417,8 +1450,11 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) },
@@ -1458,6 +1494,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_PCI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
@@ -1498,6 +1535,10 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_3_PRO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_DUAL_BOX_PRO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_5_PRO) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) },
@@ -1617,10 +1658,15 @@ static int hid_device_probe(struct device *dev)
const struct hid_device_id *id;
int ret = 0;
+ if (down_interruptible(&hdev->driver_lock))
+ return -EINTR;
+
if (!hdev->driver) {
id = hid_match_device(hdev, hdrv);
- if (id == NULL)
- return -ENODEV;
+ if (id == NULL) {
+ ret = -ENODEV;
+ goto unlock;
+ }
hdev->driver = hdrv;
if (hdrv->probe) {
@@ -1633,14 +1679,20 @@ static int hid_device_probe(struct device *dev)
if (ret)
hdev->driver = NULL;
}
+unlock:
+ up(&hdev->driver_lock);
return ret;
}
static int hid_device_remove(struct device *dev)
{
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
- struct hid_driver *hdrv = hdev->driver;
+ struct hid_driver *hdrv;
+
+ if (down_interruptible(&hdev->driver_lock))
+ return -EINTR;
+ hdrv = hdev->driver;
if (hdrv) {
if (hdrv->remove)
hdrv->remove(hdev);
@@ -1649,6 +1701,7 @@ static int hid_device_remove(struct device *dev)
hdev->driver = NULL;
}
+ up(&hdev->driver_lock);
return 0;
}
@@ -1889,6 +1942,12 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ }
@@ -1996,6 +2055,7 @@ struct hid_device *hid_allocate_device(void)
init_waitqueue_head(&hdev->debug_wait);
INIT_LIST_HEAD(&hdev->debug_list);
+ sema_init(&hdev->driver_lock, 1);
return hdev;
err:
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index bae48745bb42..9a243ca96e6d 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -450,6 +450,11 @@ void hid_dump_field(struct hid_field *field, int n, struct seq_file *f) {
seq_printf(f, "Logical(");
hid_resolv_usage(field->logical, f); seq_printf(f, ")\n");
}
+ if (field->application) {
+ tab(n, f);
+ seq_printf(f, "Application(");
+ hid_resolv_usage(field->application, f); seq_printf(f, ")\n");
+ }
tab(n, f); seq_printf(f, "Usage(%d)\n", field->maxusage);
for (j = 0; j < field->maxusage; j++) {
tab(n+2, f); hid_resolv_usage(field->usage[j].hid, f); seq_printf(f, "\n");
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index db63ccf21cc8..1680e99b4816 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -109,6 +109,15 @@
#define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI 0x0245
#define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO 0x0246
#define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS 0x0247
+#define USB_DEVICE_ID_APPLE_ALU_REVB_ANSI 0x024f
+#define USB_DEVICE_ID_APPLE_ALU_REVB_ISO 0x0250
+#define USB_DEVICE_ID_APPLE_ALU_REVB_JIS 0x0251
+#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI 0x0249
+#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO 0x024a
+#define USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS 0x024b
+#define USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI 0x024c
+#define USB_DEVICE_ID_APPLE_WELLSPRING6_ISO 0x024d
+#define USB_DEVICE_ID_APPLE_WELLSPRING6_JIS 0x024e
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI 0x0239
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO 0x023a
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b
@@ -274,6 +283,7 @@
#define USB_DEVICE_ID_PENPOWER 0x00f4
#define USB_VENDOR_ID_GREENASIA 0x0e8f
+#define USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD 0x3013
#define USB_VENDOR_ID_GRETAGMACBETH 0x0971
#define USB_DEVICE_ID_GRETAGMACBETH_HUEY 0x2005
@@ -347,6 +357,9 @@
#define USB_DEVICE_ID_UGCI_FLYING 0x0020
#define USB_DEVICE_ID_UGCI_FIGHTING 0x0030
+#define USB_VENDOR_ID_IDEACOM 0x1cb6
+#define USB_DEVICE_ID_IDEACOM_IDC6650 0x6650
+
#define USB_VENDOR_ID_ILITEK 0x222a
#define USB_DEVICE_ID_ILITEK_MULTITOUCH 0x0001
@@ -419,6 +432,9 @@
#define USB_DEVICE_ID_LD_HYBRID 0x2090
#define USB_DEVICE_ID_LD_HEATCONTROL 0x20A0
+#define USB_VENDOR_ID_LG 0x1fd2
+#define USB_DEVICE_ID_LG_MULTITOUCH 0x0064
+
#define USB_VENDOR_ID_LOGITECH 0x046d
#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
#define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110
@@ -436,6 +452,7 @@
#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295
#define USB_DEVICE_ID_LOGITECH_DFP_WHEEL 0xc298
#define USB_DEVICE_ID_LOGITECH_G25_WHEEL 0xc299
+#define USB_DEVICE_ID_LOGITECH_DFGT_WHEEL 0xc29a
#define USB_DEVICE_ID_LOGITECH_G27_WHEEL 0xc29b
#define USB_DEVICE_ID_LOGITECH_WII_WHEEL 0xc29c
#define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a
@@ -443,6 +460,8 @@
#define USB_DEVICE_ID_S510_RECEIVER_2 0xc517
#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512
#define USB_DEVICE_ID_MX3000_RECEIVER 0xc513
+#define USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER 0xc52b
+#define USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2 0xc532
#define USB_DEVICE_ID_SPACETRAVELLER 0xc623
#define USB_DEVICE_ID_SPACENAVIGATOR 0xc626
#define USB_DEVICE_ID_DINOVO_DESKTOP 0xc704
@@ -576,6 +595,9 @@
#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE 0x0600
+#define USB_VENDOR_ID_SIGMA_MICRO 0x1c4f
+#define USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD 0x0002
+
#define USB_VENDOR_ID_SKYCABLE 0x1223
#define USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER 0x3F07
@@ -671,6 +693,9 @@
#define USB_VENDOR_ID_WISEGROUP_LTD 0x6666
#define USB_VENDOR_ID_WISEGROUP_LTD2 0x6677
#define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802
+#define USB_DEVICE_ID_SUPER_JOY_BOX_3_PRO 0x8801
+#define USB_DEVICE_ID_SUPER_DUAL_BOX_PRO 0x8802
+#define USB_DEVICE_ID_SUPER_JOY_BOX_5_PRO 0x8804
#define USB_VENDOR_ID_X_TENSIONS 0x1ae7
#define USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE 0x9001
@@ -686,4 +711,7 @@
#define USB_VENDOR_ID_ZYDACRON 0x13EC
#define USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL 0x0006
+#define USB_VENDOR_ID_PRIMAX 0x0461
+#define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05
+
#endif
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 6559e2e3364e..f333139d1a48 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -474,6 +474,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
map_key_clear(BTN_STYLUS2);
break;
+ case 0x51: /* ContactID */
+ device->quirks |= HID_QUIRK_MULTITOUCH;
+ goto unknown;
+
default: goto unknown;
}
break;
@@ -978,6 +982,13 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
}
}
+ if (hid->quirks & HID_QUIRK_MULTITOUCH) {
+ /* generic hid does not know how to handle multitouch devices */
+ if (hidinput)
+ goto out_cleanup;
+ goto out_unwind;
+ }
+
if (hidinput && input_register_device(hidinput->input))
goto out_cleanup;
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index a7f916e8fc32..e7a7bd1eb34a 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -363,7 +363,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_free;
}
- if (quirks & (LG_FF | LG_FF2 | LG_FF3))
+ if (quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
connect_mask &= ~HID_CONNECT_FF;
ret = hid_hw_start(hdev, connect_mask);
@@ -372,7 +372,8 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_free;
}
- if (quirks & LG_FF4) {
+ /* Setup wireless link with Logitech Wii wheel */
+ if(hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
unsigned char buf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
@@ -405,6 +406,15 @@ err_free:
return ret;
}
+static void lg_remove(struct hid_device *hdev)
+{
+ unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+ if(quirks & LG_FF4)
+ lg4ff_deinit(hdev);
+
+ hid_hw_stop(hdev);
+}
+
static const struct hid_device_id lg_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
.driver_data = LG_RDESC | LG_WIRELESS },
@@ -431,7 +441,7 @@ static const struct hid_device_id lg_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
.driver_data = LG_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
- .driver_data = LG_NOGET | LG_FF },
+ .driver_data = LG_NOGET | LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
.driver_data = LG_FF2 },
@@ -444,15 +454,17 @@ static const struct hid_device_id lg_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
.driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
- .driver_data = LG_FF },
+ .driver_data = LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
- .driver_data = LG_FF },
+ .driver_data = LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
- .driver_data = LG_FF },
+ .driver_data = LG_FF4 },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL),
+ .driver_data = LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
- .driver_data = LG_FF },
+ .driver_data = LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
- .driver_data = LG_NOGET | LG_FF },
+ .driver_data = LG_NOGET | LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
.driver_data = LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ),
@@ -478,6 +490,7 @@ static struct hid_driver lg_driver = {
.input_mapped = lg_input_mapped,
.event = lg_event,
.probe = lg_probe,
+ .remove = lg_remove,
};
static int __init lg_init(void)
diff --git a/drivers/hid/hid-lg.h b/drivers/hid/hid-lg.h
index b0100ba2ae0b..4b097286dc78 100644
--- a/drivers/hid/hid-lg.h
+++ b/drivers/hid/hid-lg.h
@@ -19,10 +19,12 @@ int lg3ff_init(struct hid_device *hdev);
static inline int lg3ff_init(struct hid_device *hdev) { return -1; }
#endif
-#ifdef CONFIG_LOGIWII_FF
+#ifdef CONFIG_LOGIWHEELS_FF
int lg4ff_init(struct hid_device *hdev);
+int lg4ff_deinit(struct hid_device *hdev);
#else
static inline int lg4ff_init(struct hid_device *hdev) { return -1; }
+static inline int lg4ff_deinit(struct hid_device *hdev) { return -1; }
#endif
#endif
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index fa550c8e1d1b..103f30d93f76 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -29,19 +29,108 @@
#include "usbhid/usbhid.h"
#include "hid-lg.h"
+#include "hid-ids.h"
-struct lg4ff_device {
- struct hid_report *report;
+#define DFGT_REV_MAJ 0x13
+#define DFGT_REV_MIN 0x22
+#define DFP_REV_MAJ 0x11
+#define DFP_REV_MIN 0x06
+#define FFEX_REV_MAJ 0x21
+#define FFEX_REV_MIN 0x00
+#define G25_REV_MAJ 0x12
+#define G25_REV_MIN 0x22
+#define G27_REV_MAJ 0x12
+#define G27_REV_MIN 0x38
+
+#define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
+
+static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
+static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range);
+static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+
+static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IRWXO, lg4ff_range_show, lg4ff_range_store);
+
+static bool list_inited;
+
+struct lg4ff_device_entry {
+ char *device_id; /* Use name in respective kobject structure's address as the ID */
+ __u16 range;
+ __u16 min_range;
+ __u16 max_range;
+ __u8 leds;
+ struct list_head list;
+ void (*set_range)(struct hid_device *hid, u16 range);
};
-static const signed short ff4_wheel_ac[] = {
+static struct lg4ff_device_entry device_list;
+
+static const signed short lg4ff_wheel_effects[] = {
FF_CONSTANT,
FF_AUTOCENTER,
-1
};
-static int hid_lg4ff_play(struct input_dev *dev, void *data,
- struct ff_effect *effect)
+struct lg4ff_wheel {
+ const __u32 product_id;
+ const signed short *ff_effects;
+ const __u16 min_range;
+ const __u16 max_range;
+ void (*set_range)(struct hid_device *hid, u16 range);
+};
+
+static const struct lg4ff_wheel lg4ff_devices[] = {
+ {USB_DEVICE_ID_LOGITECH_WHEEL, lg4ff_wheel_effects, 40, 270, NULL},
+ {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL, lg4ff_wheel_effects, 40, 270, NULL},
+ {USB_DEVICE_ID_LOGITECH_DFP_WHEEL, lg4ff_wheel_effects, 40, 900, hid_lg4ff_set_range_dfp},
+ {USB_DEVICE_ID_LOGITECH_G25_WHEEL, lg4ff_wheel_effects, 40, 900, hid_lg4ff_set_range_g25},
+ {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL, lg4ff_wheel_effects, 40, 900, hid_lg4ff_set_range_g25},
+ {USB_DEVICE_ID_LOGITECH_G27_WHEEL, lg4ff_wheel_effects, 40, 900, hid_lg4ff_set_range_g25},
+ {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2, lg4ff_wheel_effects, 40, 270, NULL},
+ {USB_DEVICE_ID_LOGITECH_WII_WHEEL, lg4ff_wheel_effects, 40, 270, NULL}
+};
+
+struct lg4ff_native_cmd {
+ const __u8 cmd_num; /* Number of commands to send */
+ const __u8 cmd[];
+};
+
+struct lg4ff_usb_revision {
+ const __u16 rev_maj;
+ const __u16 rev_min;
+ const struct lg4ff_native_cmd *command;
+};
+
+static const struct lg4ff_native_cmd native_dfp = {
+ 1,
+ {0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+
+static const struct lg4ff_native_cmd native_dfgt = {
+ 2,
+ {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1st command */
+ 0xf8, 0x09, 0x03, 0x01, 0x00, 0x00, 0x00} /* 2nd command */
+};
+
+static const struct lg4ff_native_cmd native_g25 = {
+ 1,
+ {0xf8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+
+static const struct lg4ff_native_cmd native_g27 = {
+ 2,
+ {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1st command */
+ 0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00} /* 2nd command */
+};
+
+static const struct lg4ff_usb_revision lg4ff_revs[] = {
+ {DFGT_REV_MAJ, DFGT_REV_MIN, &native_dfgt}, /* Driving Force GT */
+ {DFP_REV_MAJ, DFP_REV_MIN, &native_dfp}, /* Driving Force Pro */
+ {G25_REV_MAJ, G25_REV_MIN, &native_g25}, /* G25 */
+ {G27_REV_MAJ, G27_REV_MIN, &native_g27}, /* G27 */
+};
+
+static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
{
struct hid_device *hid = input_get_drvdata(dev);
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
@@ -55,13 +144,12 @@ static int hid_lg4ff_play(struct input_dev *dev, void *data,
x = effect->u.ramp.start_level + 0x80; /* 0x80 is no force */
CLAMP(x);
report->field[0]->value[0] = 0x11; /* Slot 1 */
- report->field[0]->value[1] = 0x10;
+ report->field[0]->value[1] = 0x08;
report->field[0]->value[2] = x;
- report->field[0]->value[3] = 0x00;
+ report->field[0]->value[3] = 0x80;
report->field[0]->value[4] = 0x00;
- report->field[0]->value[5] = 0x08;
+ report->field[0]->value[5] = 0x00;
report->field[0]->value[6] = 0x00;
- dbg_hid("Autocenter, x=0x%02X\n", x);
usbhid_submit_report(hid, report, USB_DIR_OUT);
break;
@@ -69,24 +157,184 @@ static int hid_lg4ff_play(struct input_dev *dev, void *data,
return 0;
}
-static void hid_lg4ff_set_autocenter(struct input_dev *dev, u16 magnitude)
+/* Sends default autocentering command compatible with
+ * all wheels except Formula Force EX */
+static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude)
{
struct hid_device *hid = input_get_drvdata(dev);
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
- __s32 *value = report->field[0]->value;
- *value++ = 0xfe;
- *value++ = 0x0d;
- *value++ = 0x07;
- *value++ = 0x07;
- *value++ = (magnitude >> 8) & 0xff;
- *value++ = 0x00;
- *value = 0x00;
+ report->field[0]->value[0] = 0xfe;
+ report->field[0]->value[1] = 0x0d;
+ report->field[0]->value[2] = magnitude >> 13;
+ report->field[0]->value[3] = magnitude >> 13;
+ report->field[0]->value[4] = magnitude >> 8;
+ report->field[0]->value[5] = 0x00;
+ report->field[0]->value[6] = 0x00;
+
+ usbhid_submit_report(hid, report, USB_DIR_OUT);
+}
+
+/* Sends autocentering command compatible with Formula Force EX */
+static void hid_lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude)
+{
+ struct hid_device *hid = input_get_drvdata(dev);
+ struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+ magnitude = magnitude * 90 / 65535;
+
+
+ report->field[0]->value[0] = 0xfe;
+ report->field[0]->value[1] = 0x03;
+ report->field[0]->value[2] = magnitude >> 14;
+ report->field[0]->value[3] = magnitude >> 14;
+ report->field[0]->value[4] = magnitude;
+ report->field[0]->value[5] = 0x00;
+ report->field[0]->value[6] = 0x00;
+
+ usbhid_submit_report(hid, report, USB_DIR_OUT);
+}
+
+/* Sends command to set range compatible with G25/G27/Driving Force GT */
+static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range)
+{
+ struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+ dbg_hid("G25/G27/DFGT: setting range to %u\n", range);
+
+ report->field[0]->value[0] = 0xf8;
+ report->field[0]->value[1] = 0x81;
+ report->field[0]->value[2] = range & 0x00ff;
+ report->field[0]->value[3] = (range & 0xff00) >> 8;
+ report->field[0]->value[4] = 0x00;
+ report->field[0]->value[5] = 0x00;
+ report->field[0]->value[6] = 0x00;
+
+ usbhid_submit_report(hid, report, USB_DIR_OUT);
+}
+
+/* Sends commands to set range compatible with Driving Force Pro wheel */
+static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range)
+{
+ struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+ int start_left, start_right, full_range;
+ dbg_hid("Driving Force Pro: setting range to %u\n", range);
+
+ /* Prepare "coarse" limit command */
+ report->field[0]->value[0] = 0xf8;
+ report->field[0]->value[1] = 0x00; /* Set later */
+ report->field[0]->value[2] = 0x00;
+ report->field[0]->value[3] = 0x00;
+ report->field[0]->value[4] = 0x00;
+ report->field[0]->value[5] = 0x00;
+ report->field[0]->value[6] = 0x00;
+
+ if (range > 200) {
+ report->field[0]->value[1] = 0x03;
+ full_range = 900;
+ } else {
+ report->field[0]->value[1] = 0x02;
+ full_range = 200;
+ }
+ usbhid_submit_report(hid, report, USB_DIR_OUT);
+
+ /* Prepare "fine" limit command */
+ report->field[0]->value[0] = 0x81;
+ report->field[0]->value[1] = 0x0b;
+ report->field[0]->value[2] = 0x00;
+ report->field[0]->value[3] = 0x00;
+ report->field[0]->value[4] = 0x00;
+ report->field[0]->value[5] = 0x00;
+ report->field[0]->value[6] = 0x00;
+
+ if (range == 200 || range == 900) { /* Do not apply any fine limit */
+ usbhid_submit_report(hid, report, USB_DIR_OUT);
+ return;
+ }
+
+ /* Construct fine limit command */
+ start_left = (((full_range - range + 1) * 2047) / full_range);
+ start_right = 0xfff - start_left;
+
+ report->field[0]->value[2] = start_left >> 4;
+ report->field[0]->value[3] = start_right >> 4;
+ report->field[0]->value[4] = 0xff;
+ report->field[0]->value[5] = (start_right & 0xe) << 4 | (start_left & 0xe);
+ report->field[0]->value[6] = 0xff;
usbhid_submit_report(hid, report, USB_DIR_OUT);
}
+static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_native_cmd *cmd)
+{
+ struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+ __u8 i, j;
+
+ j = 0;
+ while (j < 7*cmd->cmd_num) {
+ for (i = 0; i < 7; i++)
+ report->field[0]->value[i] = cmd->cmd[j++];
+
+ usbhid_submit_report(hid, report, USB_DIR_OUT);
+ }
+}
+
+/* Read current range and display it in terminal */
+static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct lg4ff_device_entry *uninitialized_var(entry);
+ struct list_head *h;
+ struct hid_device *hid = to_hid_device(dev);
+ size_t count;
+
+ list_for_each(h, &device_list.list) {
+ entry = list_entry(h, struct lg4ff_device_entry, list);
+ if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0)
+ break;
+ }
+ if (h == &device_list.list) {
+ dbg_hid("Device not found!");
+ return 0;
+ }
+
+ count = scnprintf(buf, PAGE_SIZE, "%u\n", entry->range);
+ return count;
+}
+
+/* Set range to user specified value, call appropriate function
+ * according to the type of the wheel */
+static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct lg4ff_device_entry *uninitialized_var(entry);
+ struct list_head *h;
+ struct hid_device *hid = to_hid_device(dev);
+ __u16 range = simple_strtoul(buf, NULL, 10);
+
+ list_for_each(h, &device_list.list) {
+ entry = list_entry(h, struct lg4ff_device_entry, list);
+ if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0)
+ break;
+ }
+ if (h == &device_list.list) {
+ dbg_hid("Device not found!");
+ return count;
+ }
+
+ if (range == 0)
+ range = entry->max_range;
+
+ /* Check if the wheel supports range setting
+ * and that the range is within limits for the wheel */
+ if (entry->set_range != NULL && range >= entry->min_range && range <= entry->max_range) {
+ entry->set_range(hid, range);
+ entry->range = range;
+ }
+
+ return count;
+}
int lg4ff_init(struct hid_device *hid)
{
@@ -95,9 +343,10 @@ int lg4ff_init(struct hid_device *hid)
struct input_dev *dev = hidinput->input;
struct hid_report *report;
struct hid_field *field;
- const signed short *ff_bits = ff4_wheel_ac;
- int error;
- int i;
+ struct lg4ff_device_entry *entry;
+ struct usb_device_descriptor *udesc;
+ int error, i, j;
+ __u16 bcdDevice, rev_maj, rev_min;
/* Find the report to use */
if (list_empty(report_list)) {
@@ -118,18 +367,122 @@ int lg4ff_init(struct hid_device *hid)
return -1;
}
- for (i = 0; ff_bits[i] >= 0; i++)
- set_bit(ff_bits[i], dev->ffbit);
+ /* Check what wheel has been connected */
+ for (i = 0; i < ARRAY_SIZE(lg4ff_devices); i++) {
+ if (hid->product == lg4ff_devices[i].product_id) {
+ dbg_hid("Found compatible device, product ID %04X\n", lg4ff_devices[i].product_id);
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(lg4ff_devices)) {
+ hid_err(hid, "Device is not supported by lg4ff driver. If you think it should be, consider reporting a bug to"
+ "LKML, Simon Wood <simon@mungewell.org> or Michal Maly <madcatxster@gmail.com>\n");
+ return -1;
+ }
+
+ /* Attempt to switch wheel to native mode when applicable */
+ udesc = &(hid_to_usb_dev(hid)->descriptor);
+ if (!udesc) {
+ hid_err(hid, "NULL USB device descriptor\n");
+ return -1;
+ }
+ bcdDevice = le16_to_cpu(udesc->bcdDevice);
+ rev_maj = bcdDevice >> 8;
+ rev_min = bcdDevice & 0xff;
+
+ if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_WHEEL) {
+ dbg_hid("Generic wheel detected, can it do native?\n");
+ dbg_hid("USB revision: %2x.%02x\n", rev_maj, rev_min);
+
+ for (j = 0; j < ARRAY_SIZE(lg4ff_revs); j++) {
+ if (lg4ff_revs[j].rev_maj == rev_maj && lg4ff_revs[j].rev_min == rev_min) {
+ hid_lg4ff_switch_native(hid, lg4ff_revs[j].command);
+ hid_info(hid, "Switched to native mode\n");
+ }
+ }
+ }
+
+ /* Set supported force feedback capabilities */
+ for (j = 0; lg4ff_devices[i].ff_effects[j] >= 0; j++)
+ set_bit(lg4ff_devices[i].ff_effects[j], dev->ffbit);
error = input_ff_create_memless(dev, NULL, hid_lg4ff_play);
if (error)
return error;
- if (test_bit(FF_AUTOCENTER, dev->ffbit))
- dev->ff->set_autocenter = hid_lg4ff_set_autocenter;
+ /* Check if autocentering is available and
+ * set the centering force to zero by default */
+ if (test_bit(FF_AUTOCENTER, dev->ffbit)) {
+ if(rev_maj == FFEX_REV_MAJ && rev_min == FFEX_REV_MIN) /* Formula Force EX expects different autocentering command */
+ dev->ff->set_autocenter = hid_lg4ff_set_autocenter_ffex;
+ else
+ dev->ff->set_autocenter = hid_lg4ff_set_autocenter_default;
+
+ dev->ff->set_autocenter(dev, 0);
+ }
+
+ /* Initialize device_list if this is the first device to handle by lg4ff */
+ if (!list_inited) {
+ INIT_LIST_HEAD(&device_list.list);
+ list_inited = 1;
+ }
+
+ /* Add the device to device_list */
+ entry = (struct lg4ff_device_entry *)kzalloc(sizeof(struct lg4ff_device_entry), GFP_KERNEL);
+ if (!entry) {
+ hid_err(hid, "Cannot add device, insufficient memory.\n");
+ return -ENOMEM;
+ }
+ entry->device_id = kstrdup((&hid->dev)->kobj.name, GFP_KERNEL);
+ if (!entry->device_id) {
+ hid_err(hid, "Cannot set device_id, insufficient memory.\n");
+ kfree(entry);
+ return -ENOMEM;
+ }
+ entry->min_range = lg4ff_devices[i].min_range;
+ entry->max_range = lg4ff_devices[i].max_range;
+ entry->set_range = lg4ff_devices[i].set_range;
+ list_add(&entry->list, &device_list.list);
+
+ /* Create sysfs interface */
+ error = device_create_file(&hid->dev, &dev_attr_range);
+ if (error)
+ return error;
+ dbg_hid("sysfs interface created\n");
+
+ /* Set the maximum range to start with */
+ entry->range = entry->max_range;
+ if (entry->set_range != NULL)
+ entry->set_range(hid, entry->range);
hid_info(hid, "Force feedback for Logitech Speed Force Wireless by Simon Wood <simon@mungewell.org>\n");
return 0;
}
+int lg4ff_deinit(struct hid_device *hid)
+{
+ bool found = 0;
+ struct lg4ff_device_entry *entry;
+ struct list_head *h, *g;
+ list_for_each_safe(h, g, &device_list.list) {
+ entry = list_entry(h, struct lg4ff_device_entry, list);
+ if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0) {
+ list_del(h);
+ kfree(entry->device_id);
+ kfree(entry);
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ dbg_hid("Device entry not found!\n");
+ return -1;
+ }
+
+ device_remove_file(&hid->dev, &dev_attr_range);
+ dbg_hid("Device successfully unregistered\n");
+ return 0;
+}
diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c
index 088f85049290..27bc54f92f44 100644
--- a/drivers/hid/hid-lgff.c
+++ b/drivers/hid/hid-lgff.c
@@ -58,12 +58,6 @@ static const signed short ff_joystick_ac[] = {
-1
};
-static const signed short ff_wheel[] = {
- FF_CONSTANT,
- FF_AUTOCENTER,
- -1
-};
-
static const struct dev_type devices[] = {
{ 0x046d, 0xc211, ff_rumble },
{ 0x046d, 0xc219, ff_rumble },
@@ -71,14 +65,7 @@ static const struct dev_type devices[] = {
{ 0x046d, 0xc286, ff_joystick_ac },
{ 0x046d, 0xc287, ff_joystick_ac },
{ 0x046d, 0xc293, ff_joystick },
- { 0x046d, 0xc294, ff_wheel },
- { 0x046d, 0xc298, ff_wheel },
- { 0x046d, 0xc299, ff_wheel },
- { 0x046d, 0xc29b, ff_wheel },
{ 0x046d, 0xc295, ff_joystick },
- { 0x046d, 0xc298, ff_wheel },
- { 0x046d, 0xc299, ff_wheel },
- { 0x046d, 0xca03, ff_wheel },
};
static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
new file mode 100644
index 000000000000..38b12e45780c
--- /dev/null
+++ b/drivers/hid/hid-logitech-dj.c
@@ -0,0 +1,922 @@
+/*
+ * HID driver for Logitech Unifying receivers
+ *
+ * Copyright (c) 2011 Logitech
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
+#include "hid-ids.h"
+#include "hid-logitech-dj.h"
+
+/* Keyboard descriptor (1) */
+static const char kbd_descriptor[] = {
+ 0x05, 0x01, /* USAGE_PAGE (generic Desktop) */
+ 0x09, 0x06, /* USAGE (Keyboard) */
+ 0xA1, 0x01, /* COLLECTION (Application) */
+ 0x85, 0x01, /* REPORT_ID (1) */
+ 0x95, 0x08, /* REPORT_COUNT (8) */
+ 0x75, 0x01, /* REPORT_SIZE (1) */
+ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
+ 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
+ 0x05, 0x07, /* USAGE_PAGE (Keyboard) */
+ 0x19, 0xE0, /* USAGE_MINIMUM (Left Control) */
+ 0x29, 0xE7, /* USAGE_MAXIMUM (Right GUI) */
+ 0x81, 0x02, /* INPUT (Data,Var,Abs) */
+ 0x95, 0x05, /* REPORT COUNT (5) */
+ 0x05, 0x08, /* USAGE PAGE (LED page) */
+ 0x19, 0x01, /* USAGE MINIMUM (1) */
+ 0x29, 0x05, /* USAGE MAXIMUM (5) */
+ 0x91, 0x02, /* OUTPUT (Data, Variable, Absolute) */
+ 0x95, 0x01, /* REPORT COUNT (1) */
+ 0x75, 0x03, /* REPORT SIZE (3) */
+ 0x91, 0x01, /* OUTPUT (Constant) */
+ 0x95, 0x06, /* REPORT_COUNT (6) */
+ 0x75, 0x08, /* REPORT_SIZE (8) */
+ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
+ 0x26, 0xFF, 0x00, /* LOGICAL_MAXIMUM (255) */
+ 0x05, 0x07, /* USAGE_PAGE (Keyboard) */
+ 0x19, 0x00, /* USAGE_MINIMUM (no event) */
+ 0x2A, 0xFF, 0x00, /* USAGE_MAXIMUM (reserved) */
+ 0x81, 0x00, /* INPUT (Data,Ary,Abs) */
+ 0xC0
+};
+
+/* Mouse descriptor (2) */
+static const char mse_descriptor[] = {
+ 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
+ 0x09, 0x02, /* USAGE (Mouse) */
+ 0xA1, 0x01, /* COLLECTION (Application) */
+ 0x85, 0x02, /* REPORT_ID = 2 */
+ 0x09, 0x01, /* USAGE (pointer) */
+ 0xA1, 0x00, /* COLLECTION (physical) */
+ 0x05, 0x09, /* USAGE_PAGE (buttons) */
+ 0x19, 0x01, /* USAGE_MIN (1) */
+ 0x29, 0x10, /* USAGE_MAX (16) */
+ 0x15, 0x00, /* LOGICAL_MIN (0) */
+ 0x25, 0x01, /* LOGICAL_MAX (1) */
+ 0x95, 0x10, /* REPORT_COUNT (16) */
+ 0x75, 0x01, /* REPORT_SIZE (1) */
+ 0x81, 0x02, /* INPUT (data var abs) */
+ 0x05, 0x01, /* USAGE_PAGE (generic desktop) */
+ 0x16, 0x01, 0xF8, /* LOGICAL_MIN (-2047) */
+ 0x26, 0xFF, 0x07, /* LOGICAL_MAX (2047) */
+ 0x75, 0x0C, /* REPORT_SIZE (12) */
+ 0x95, 0x02, /* REPORT_COUNT (2) */
+ 0x09, 0x30, /* USAGE (X) */
+ 0x09, 0x31, /* USAGE (Y) */
+ 0x81, 0x06, /* INPUT */
+ 0x15, 0x81, /* LOGICAL_MIN (-127) */
+ 0x25, 0x7F, /* LOGICAL_MAX (127) */
+ 0x75, 0x08, /* REPORT_SIZE (8) */
+ 0x95, 0x01, /* REPORT_COUNT (1) */
+ 0x09, 0x38, /* USAGE (wheel) */
+ 0x81, 0x06, /* INPUT */
+ 0x05, 0x0C, /* USAGE_PAGE(consumer) */
+ 0x0A, 0x38, 0x02, /* USAGE(AC Pan) */
+ 0x95, 0x01, /* REPORT_COUNT (1) */
+ 0x81, 0x06, /* INPUT */
+ 0xC0, /* END_COLLECTION */
+ 0xC0, /* END_COLLECTION */
+};
+
+/* Consumer Control descriptor (3) */
+static const char consumer_descriptor[] = {
+ 0x05, 0x0C, /* USAGE_PAGE (Consumer Devices) */
+ 0x09, 0x01, /* USAGE (Consumer Control) */
+ 0xA1, 0x01, /* COLLECTION (Application) */
+ 0x85, 0x03, /* REPORT_ID = 3 */
+ 0x75, 0x10, /* REPORT_SIZE (16) */
+ 0x95, 0x02, /* REPORT_COUNT (2) */
+ 0x15, 0x01, /* LOGICAL_MIN (1) */
+ 0x26, 0x8C, 0x02, /* LOGICAL_MAX (652) */
+ 0x19, 0x01, /* USAGE_MIN (1) */
+ 0x2A, 0x8C, 0x02, /* USAGE_MAX (652) */
+ 0x81, 0x00, /* INPUT (Data Ary Abs) */
+ 0xC0, /* END_COLLECTION */
+}; /* */
+
+/* System control descriptor (4) */
+static const char syscontrol_descriptor[] = {
+ 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
+ 0x09, 0x80, /* USAGE (System Control) */
+ 0xA1, 0x01, /* COLLECTION (Application) */
+ 0x85, 0x04, /* REPORT_ID = 4 */
+ 0x75, 0x02, /* REPORT_SIZE (2) */
+ 0x95, 0x01, /* REPORT_COUNT (1) */
+ 0x15, 0x01, /* LOGICAL_MIN (1) */
+ 0x25, 0x03, /* LOGICAL_MAX (3) */
+ 0x09, 0x82, /* USAGE (System Sleep) */
+ 0x09, 0x81, /* USAGE (System Power Down) */
+ 0x09, 0x83, /* USAGE (System Wake Up) */
+ 0x81, 0x60, /* INPUT (Data Ary Abs NPrf Null) */
+ 0x75, 0x06, /* REPORT_SIZE (6) */
+ 0x81, 0x03, /* INPUT (Cnst Var Abs) */
+ 0xC0, /* END_COLLECTION */
+};
+
+/* Media descriptor (8) */
+static const char media_descriptor[] = {
+ 0x06, 0xbc, 0xff, /* Usage Page 0xffbc */
+ 0x09, 0x88, /* Usage 0x0088 */
+ 0xa1, 0x01, /* BeginCollection */
+ 0x85, 0x08, /* Report ID 8 */
+ 0x19, 0x01, /* Usage Min 0x0001 */
+ 0x29, 0xff, /* Usage Max 0x00ff */
+ 0x15, 0x01, /* Logical Min 1 */
+ 0x26, 0xff, 0x00, /* Logical Max 255 */
+ 0x75, 0x08, /* Report Size 8 */
+ 0x95, 0x01, /* Report Count 1 */
+ 0x81, 0x00, /* Input */
+ 0xc0, /* EndCollection */
+}; /* */
+
+/* Maximum size of all defined hid reports in bytes (including report id) */
+#define MAX_REPORT_SIZE 8
+
+/* Number of possible hid report types that can be created by this driver.
+ *
+ * Right now, RF report types have the same report types (or report id's)
+ * than the hid report created from those RF reports. In the future
+ * this doesnt have to be true.
+ *
+ * For instance, RF report type 0x01 which has a size of 8 bytes, corresponds
+ * to hid report id 0x01, this is standard keyboard. Same thing applies to mice
+ * reports and consumer control, etc. If a new RF report is created, it doesn't
+ * has to have the same report id as its corresponding hid report, so an
+ * translation may have to take place for future report types.
+ */
+#define NUMBER_OF_HID_REPORTS 32
+static const u8 hid_reportid_size_map[NUMBER_OF_HID_REPORTS] = {
+ [1] = 8, /* Standard keyboard */
+ [2] = 8, /* Standard mouse */
+ [3] = 5, /* Consumer control */
+ [4] = 2, /* System control */
+ [8] = 2, /* Media Center */
+};
+
+
+#define LOGITECH_DJ_INTERFACE_NUMBER 0x02
+
+static struct hid_ll_driver logi_dj_ll_driver;
+
+static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
+ size_t count,
+ unsigned char report_type);
+
+static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev,
+ struct dj_report *dj_report)
+{
+ /* Called in delayed work context */
+ struct dj_device *dj_dev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&djrcv_dev->lock, flags);
+ dj_dev = djrcv_dev->paired_dj_devices[dj_report->device_index];
+ djrcv_dev->paired_dj_devices[dj_report->device_index] = NULL;
+ spin_unlock_irqrestore(&djrcv_dev->lock, flags);
+
+ if (dj_dev != NULL) {
+ hid_destroy_device(dj_dev->hdev);
+ kfree(dj_dev);
+ } else {
+ dev_err(&djrcv_dev->hdev->dev, "%s: can't destroy a NULL device\n",
+ __func__);
+ }
+}
+
+static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
+ struct dj_report *dj_report)
+{
+ /* Called in delayed work context */
+ struct hid_device *djrcv_hdev = djrcv_dev->hdev;
+ struct usb_interface *intf = to_usb_interface(djrcv_hdev->dev.parent);
+ struct usb_device *usbdev = interface_to_usbdev(intf);
+ struct hid_device *dj_hiddev;
+ struct dj_device *dj_dev;
+
+ /* Device index goes from 1 to 6, we need 3 bytes to store the
+ * semicolon, the index, and a null terminator
+ */
+ unsigned char tmpstr[3];
+
+ if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] &
+ SPFUNCTION_DEVICE_LIST_EMPTY) {
+ dbg_hid("%s: device list is empty\n", __func__);
+ return;
+ }
+
+ if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) ||
+ (dj_report->device_index > DJ_DEVICE_INDEX_MAX)) {
+ dev_err(&djrcv_hdev->dev, "%s: invalid device index:%d\n",
+ __func__, dj_report->device_index);
+ return;
+ }
+
+ dj_hiddev = hid_allocate_device();
+ if (IS_ERR(dj_hiddev)) {
+ dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n",
+ __func__);
+ return;
+ }
+
+ dj_hiddev->ll_driver = &logi_dj_ll_driver;
+ dj_hiddev->hid_output_raw_report = logi_dj_output_hidraw_report;
+
+ dj_hiddev->dev.parent = &djrcv_hdev->dev;
+ dj_hiddev->bus = BUS_USB;
+ dj_hiddev->vendor = le16_to_cpu(usbdev->descriptor.idVendor);
+ dj_hiddev->product = le16_to_cpu(usbdev->descriptor.idProduct);
+ snprintf(dj_hiddev->name, sizeof(dj_hiddev->name),
+ "Logitech Unifying Device. Wireless PID:%02x%02x",
+ dj_report->report_params[DEVICE_PAIRED_PARAM_EQUAD_ID_MSB],
+ dj_report->report_params[DEVICE_PAIRED_PARAM_EQUAD_ID_LSB]);
+
+ usb_make_path(usbdev, dj_hiddev->phys, sizeof(dj_hiddev->phys));
+ snprintf(tmpstr, sizeof(tmpstr), ":%d", dj_report->device_index);
+ strlcat(dj_hiddev->phys, tmpstr, sizeof(dj_hiddev->phys));
+
+ dj_dev = kzalloc(sizeof(struct dj_device), GFP_KERNEL);
+
+ if (!dj_dev) {
+ dev_err(&djrcv_hdev->dev, "%s: failed allocating dj_device\n",
+ __func__);
+ goto dj_device_allocate_fail;
+ }
+
+ dj_dev->reports_supported = le32_to_cpu(
+ dj_report->report_params[DEVICE_PAIRED_RF_REPORT_TYPE]);
+ dj_dev->hdev = dj_hiddev;
+ dj_dev->dj_receiver_dev = djrcv_dev;
+ dj_dev->device_index = dj_report->device_index;
+ dj_hiddev->driver_data = dj_dev;
+
+ djrcv_dev->paired_dj_devices[dj_report->device_index] = dj_dev;
+
+ if (hid_add_device(dj_hiddev)) {
+ dev_err(&djrcv_hdev->dev, "%s: failed adding dj_device\n",
+ __func__);
+ goto hid_add_device_fail;
+ }
+
+ return;
+
+hid_add_device_fail:
+ djrcv_dev->paired_dj_devices[dj_report->device_index] = NULL;
+ kfree(dj_dev);
+dj_device_allocate_fail:
+ hid_destroy_device(dj_hiddev);
+}
+
+static void delayedwork_callback(struct work_struct *work)
+{
+ struct dj_receiver_dev *djrcv_dev =
+ container_of(work, struct dj_receiver_dev, work);
+
+ struct dj_report dj_report;
+ unsigned long flags;
+ int count;
+
+ dbg_hid("%s\n", __func__);
+
+ spin_lock_irqsave(&djrcv_dev->lock, flags);
+
+ count = kfifo_out(&djrcv_dev->notif_fifo, &dj_report,
+ sizeof(struct dj_report));
+
+ if (count != sizeof(struct dj_report)) {
+ dev_err(&djrcv_dev->hdev->dev, "%s: workitem triggered without "
+ "notifications available\n", __func__);
+ spin_unlock_irqrestore(&djrcv_dev->lock, flags);
+ return;
+ }
+
+ if (!kfifo_is_empty(&djrcv_dev->notif_fifo)) {
+ if (schedule_work(&djrcv_dev->work) == 0) {
+ dbg_hid("%s: did not schedule the work item, was "
+ "already queued\n", __func__);
+ }
+ }
+
+ spin_unlock_irqrestore(&djrcv_dev->lock, flags);
+
+ switch (dj_report.report_type) {
+ case REPORT_TYPE_NOTIF_DEVICE_PAIRED:
+ logi_dj_recv_add_djhid_device(djrcv_dev, &dj_report);
+ break;
+ case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED:
+ logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report);
+ break;
+ default:
+ dbg_hid("%s: unexpected report type\n", __func__);
+ }
+}
+
+static void logi_dj_recv_queue_notification(struct dj_receiver_dev *djrcv_dev,
+ struct dj_report *dj_report)
+{
+ /* We are called from atomic context (tasklet && djrcv->lock held) */
+
+ kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
+
+ if (schedule_work(&djrcv_dev->work) == 0) {
+ dbg_hid("%s: did not schedule the work item, was already "
+ "queued\n", __func__);
+ }
+}
+
+static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev,
+ struct dj_report *dj_report)
+{
+ /* We are called from atomic context (tasklet && djrcv->lock held) */
+ unsigned int i;
+ u8 reportbuffer[MAX_REPORT_SIZE];
+ struct dj_device *djdev;
+
+ djdev = djrcv_dev->paired_dj_devices[dj_report->device_index];
+
+ if (!djdev) {
+ dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
+ " is NULL, index %d\n", dj_report->device_index);
+ return;
+ }
+
+ memset(reportbuffer, 0, sizeof(reportbuffer));
+
+ for (i = 0; i < NUMBER_OF_HID_REPORTS; i++) {
+ if (djdev->reports_supported & (1 << i)) {
+ reportbuffer[0] = i;
+ if (hid_input_report(djdev->hdev,
+ HID_INPUT_REPORT,
+ reportbuffer,
+ hid_reportid_size_map[i], 1)) {
+ dbg_hid("hid_input_report error sending null "
+ "report\n");
+ }
+ }
+ }
+}
+
+static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev,
+ struct dj_report *dj_report)
+{
+ /* We are called from atomic context (tasklet && djrcv->lock held) */
+ struct dj_device *dj_device;
+
+ dj_device = djrcv_dev->paired_dj_devices[dj_report->device_index];
+
+ if (dj_device == NULL) {
+ dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
+ " is NULL, index %d\n", dj_report->device_index);
+ return;
+ }
+
+ if ((dj_report->report_type > ARRAY_SIZE(hid_reportid_size_map) - 1) ||
+ (hid_reportid_size_map[dj_report->report_type] == 0)) {
+ dbg_hid("invalid report type:%x\n", dj_report->report_type);
+ return;
+ }
+
+ if (hid_input_report(dj_device->hdev,
+ HID_INPUT_REPORT, &dj_report->report_type,
+ hid_reportid_size_map[dj_report->report_type], 1)) {
+ dbg_hid("hid_input_report error\n");
+ }
+}
+
+
+static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
+ struct dj_report *dj_report)
+{
+ struct hid_device *hdev = djrcv_dev->hdev;
+ int sent_bytes;
+
+ if (!hdev->hid_output_raw_report) {
+ dev_err(&hdev->dev, "%s:"
+ "hid_output_raw_report is null\n", __func__);
+ return -ENODEV;
+ }
+
+ sent_bytes = hdev->hid_output_raw_report(hdev, (u8 *) dj_report,
+ sizeof(struct dj_report),
+ HID_OUTPUT_REPORT);
+
+ return (sent_bytes < 0) ? sent_bytes : 0;
+}
+
+static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
+{
+ struct dj_report dj_report;
+
+ memset(&dj_report, 0, sizeof(dj_report));
+ dj_report.report_id = REPORT_ID_DJ_SHORT;
+ dj_report.device_index = 0xFF;
+ dj_report.report_type = REPORT_TYPE_CMD_GET_PAIRED_DEVICES;
+ return logi_dj_recv_send_report(djrcv_dev, &dj_report);
+}
+
+static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
+ unsigned timeout)
+{
+ struct dj_report dj_report;
+
+ memset(&dj_report, 0, sizeof(dj_report));
+ dj_report.report_id = REPORT_ID_DJ_SHORT;
+ dj_report.device_index = 0xFF;
+ dj_report.report_type = REPORT_TYPE_CMD_SWITCH;
+ dj_report.report_params[CMD_SWITCH_PARAM_DEVBITFIELD] = 0x1F;
+ dj_report.report_params[CMD_SWITCH_PARAM_TIMEOUT_SECONDS] = (u8)timeout;
+ return logi_dj_recv_send_report(djrcv_dev, &dj_report);
+}
+
+
+static int logi_dj_ll_open(struct hid_device *hid)
+{
+ dbg_hid("%s:%s\n", __func__, hid->phys);
+ return 0;
+
+}
+
+static void logi_dj_ll_close(struct hid_device *hid)
+{
+ dbg_hid("%s:%s\n", __func__, hid->phys);
+}
+
+static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
+ size_t count,
+ unsigned char report_type)
+{
+ /* Called by hid raw to send data */
+ dbg_hid("%s\n", __func__);
+
+ return 0;
+}
+
+static int logi_dj_ll_parse(struct hid_device *hid)
+{
+ struct dj_device *djdev = hid->driver_data;
+ int retval;
+
+ dbg_hid("%s\n", __func__);
+
+ djdev->hdev->version = 0x0111;
+ djdev->hdev->country = 0x00;
+
+ if (djdev->reports_supported & STD_KEYBOARD) {
+ dbg_hid("%s: sending a kbd descriptor, reports_supported: %x\n",
+ __func__, djdev->reports_supported);
+ retval = hid_parse_report(hid,
+ (u8 *) kbd_descriptor,
+ sizeof(kbd_descriptor));
+ if (retval) {
+ dbg_hid("%s: sending a kbd descriptor, hid_parse failed"
+ " error: %d\n", __func__, retval);
+ return retval;
+ }
+ }
+
+ if (djdev->reports_supported & STD_MOUSE) {
+ dbg_hid("%s: sending a mouse descriptor, reports_supported: "
+ "%x\n", __func__, djdev->reports_supported);
+ retval = hid_parse_report(hid,
+ (u8 *) mse_descriptor,
+ sizeof(mse_descriptor));
+ if (retval) {
+ dbg_hid("%s: sending a mouse descriptor, hid_parse "
+ "failed error: %d\n", __func__, retval);
+ return retval;
+ }
+ }
+
+ if (djdev->reports_supported & MULTIMEDIA) {
+ dbg_hid("%s: sending a multimedia report descriptor: %x\n",
+ __func__, djdev->reports_supported);
+ retval = hid_parse_report(hid,
+ (u8 *) consumer_descriptor,
+ sizeof(consumer_descriptor));
+ if (retval) {
+ dbg_hid("%s: sending a consumer_descriptor, hid_parse "
+ "failed error: %d\n", __func__, retval);
+ return retval;
+ }
+ }
+
+ if (djdev->reports_supported & POWER_KEYS) {
+ dbg_hid("%s: sending a power keys report descriptor: %x\n",
+ __func__, djdev->reports_supported);
+ retval = hid_parse_report(hid,
+ (u8 *) syscontrol_descriptor,
+ sizeof(syscontrol_descriptor));
+ if (retval) {
+ dbg_hid("%s: sending a syscontrol_descriptor, "
+ "hid_parse failed error: %d\n",
+ __func__, retval);
+ return retval;
+ }
+ }
+
+ if (djdev->reports_supported & MEDIA_CENTER) {
+ dbg_hid("%s: sending a media center report descriptor: %x\n",
+ __func__, djdev->reports_supported);
+ retval = hid_parse_report(hid,
+ (u8 *) media_descriptor,
+ sizeof(media_descriptor));
+ if (retval) {
+ dbg_hid("%s: sending a media_descriptor, hid_parse "
+ "failed error: %d\n", __func__, retval);
+ return retval;
+ }
+ }
+
+ if (djdev->reports_supported & KBD_LEDS) {
+ dbg_hid("%s: need to send kbd leds report descriptor: %x\n",
+ __func__, djdev->reports_supported);
+ }
+
+ return 0;
+}
+
+static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type,
+ unsigned int code, int value)
+{
+ /* Sent by the input layer to handle leds and Force Feedback */
+ struct hid_device *dj_hiddev = input_get_drvdata(dev);
+ struct dj_device *dj_dev = dj_hiddev->driver_data;
+
+ struct dj_receiver_dev *djrcv_dev =
+ dev_get_drvdata(dj_hiddev->dev.parent);
+ struct hid_device *dj_rcv_hiddev = djrcv_dev->hdev;
+ struct hid_report_enum *output_report_enum;
+
+ struct hid_field *field;
+ struct hid_report *report;
+ unsigned char data[8];
+ int offset;
+
+ dbg_hid("%s: %s, type:%d | code:%d | value:%d\n",
+ __func__, dev->phys, type, code, value);
+
+ if (type != EV_LED)
+ return -1;
+
+ offset = hidinput_find_field(dj_hiddev, type, code, &field);
+
+ if (offset == -1) {
+ dev_warn(&dev->dev, "event field not found\n");
+ return -1;
+ }
+ hid_set_field(field, offset, value);
+ hid_output_report(field->report, &data[0]);
+
+ output_report_enum = &dj_rcv_hiddev->report_enum[HID_OUTPUT_REPORT];
+ report = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT];
+ hid_set_field(report->field[0], 0, dj_dev->device_index);
+ hid_set_field(report->field[0], 1, REPORT_TYPE_LEDS);
+ hid_set_field(report->field[0], 2, data[1]);
+
+ usbhid_submit_report(dj_rcv_hiddev, report, USB_DIR_OUT);
+
+ return 0;
+
+}
+
+static int logi_dj_ll_start(struct hid_device *hid)
+{
+ dbg_hid("%s\n", __func__);
+ return 0;
+}
+
+static void logi_dj_ll_stop(struct hid_device *hid)
+{
+ dbg_hid("%s\n", __func__);
+}
+
+
+static struct hid_ll_driver logi_dj_ll_driver = {
+ .parse = logi_dj_ll_parse,
+ .start = logi_dj_ll_start,
+ .stop = logi_dj_ll_stop,
+ .open = logi_dj_ll_open,
+ .close = logi_dj_ll_close,
+ .hidinput_input_event = logi_dj_ll_input_event,
+};
+
+
+static int logi_dj_raw_event(struct hid_device *hdev,
+ struct hid_report *report, u8 *data,
+ int size)
+{
+ struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
+ struct dj_report *dj_report = (struct dj_report *) data;
+ unsigned long flags;
+ bool report_processed = false;
+
+ dbg_hid("%s, size:%d\n", __func__, size);
+
+ /* Here we receive all data coming from iface 2, there are 4 cases:
+ *
+ * 1) Data should continue its normal processing i.e. data does not
+ * come from the DJ collection, in which case we do nothing and
+ * return 0, so hid-core can continue normal processing (will forward
+ * to associated hidraw device)
+ *
+ * 2) Data is from DJ collection, and is intended for this driver i. e.
+ * data contains arrival, departure, etc notifications, in which case
+ * we queue them for delayed processing by the work queue. We return 1
+ * to hid-core as no further processing is required from it.
+ *
+ * 3) Data is from DJ collection, and informs a connection change,
+ * if the change means rf link loss, then we must send a null report
+ * to the upper layer to discard potentially pressed keys that may be
+ * repeated forever by the input layer. Return 1 to hid-core as no
+ * further processing is required.
+ *
+ * 4) Data is from DJ collection and is an actual input event from
+ * a paired DJ device in which case we forward it to the correct hid
+ * device (via hid_input_report() ) and return 1 so hid-core does not do
+ * anything else with it.
+ */
+
+ spin_lock_irqsave(&djrcv_dev->lock, flags);
+ if (dj_report->report_id == REPORT_ID_DJ_SHORT) {
+ switch (dj_report->report_type) {
+ case REPORT_TYPE_NOTIF_DEVICE_PAIRED:
+ case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED:
+ logi_dj_recv_queue_notification(djrcv_dev, dj_report);
+ break;
+ case REPORT_TYPE_NOTIF_CONNECTION_STATUS:
+ if (dj_report->report_params[CONNECTION_STATUS_PARAM_STATUS] ==
+ STATUS_LINKLOSS) {
+ logi_dj_recv_forward_null_report(djrcv_dev, dj_report);
+ }
+ break;
+ default:
+ logi_dj_recv_forward_report(djrcv_dev, dj_report);
+ }
+ report_processed = true;
+ }
+ spin_unlock_irqrestore(&djrcv_dev->lock, flags);
+
+ return report_processed;
+}
+
+static int logi_dj_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct dj_receiver_dev *djrcv_dev;
+ int retval;
+
+ if (is_dj_device((struct dj_device *)hdev->driver_data))
+ return -ENODEV;
+
+ dbg_hid("%s called for ifnum %d\n", __func__,
+ intf->cur_altsetting->desc.bInterfaceNumber);
+
+ /* Ignore interfaces 0 and 1, they will not carry any data, dont create
+ * any hid_device for them */
+ if (intf->cur_altsetting->desc.bInterfaceNumber !=
+ LOGITECH_DJ_INTERFACE_NUMBER) {
+ dbg_hid("%s: ignoring ifnum %d\n", __func__,
+ intf->cur_altsetting->desc.bInterfaceNumber);
+ return -ENODEV;
+ }
+
+ /* Treat interface 2 */
+
+ djrcv_dev = kzalloc(sizeof(struct dj_receiver_dev), GFP_KERNEL);
+ if (!djrcv_dev) {
+ dev_err(&hdev->dev,
+ "%s:failed allocating dj_receiver_dev\n", __func__);
+ return -ENOMEM;
+ }
+ djrcv_dev->hdev = hdev;
+ INIT_WORK(&djrcv_dev->work, delayedwork_callback);
+ spin_lock_init(&djrcv_dev->lock);
+ if (kfifo_alloc(&djrcv_dev->notif_fifo,
+ DJ_MAX_NUMBER_NOTIFICATIONS * sizeof(struct dj_report),
+ GFP_KERNEL)) {
+ dev_err(&hdev->dev,
+ "%s:failed allocating notif_fifo\n", __func__);
+ kfree(djrcv_dev);
+ return -ENOMEM;
+ }
+ hid_set_drvdata(hdev, djrcv_dev);
+
+ /* Call to usbhid to fetch the HID descriptors of interface 2 and
+ * subsequently call to the hid/hid-core to parse the fetched
+ * descriptors, this will in turn create the hidraw and hiddev nodes
+ * for interface 2 of the receiver */
+ retval = hid_parse(hdev);
+ if (retval) {
+ dev_err(&hdev->dev,
+ "%s:parse of interface 2 failed\n", __func__);
+ goto hid_parse_fail;
+ }
+
+ /* Starts the usb device and connects to upper interfaces hiddev and
+ * hidraw */
+ retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (retval) {
+ dev_err(&hdev->dev,
+ "%s:hid_hw_start returned error\n", __func__);
+ goto hid_hw_start_fail;
+ }
+
+ retval = logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0);
+ if (retval < 0) {
+ dev_err(&hdev->dev,
+ "%s:logi_dj_recv_switch_to_dj_mode returned error:%d\n",
+ __func__, retval);
+ goto switch_to_dj_mode_fail;
+ }
+
+ /* This is enabling the polling urb on the IN endpoint */
+ retval = hdev->ll_driver->open(hdev);
+ if (retval < 0) {
+ dev_err(&hdev->dev, "%s:hdev->ll_driver->open returned "
+ "error:%d\n", __func__, retval);
+ goto llopen_failed;
+ }
+
+ retval = logi_dj_recv_query_paired_devices(djrcv_dev);
+ if (retval < 0) {
+ dev_err(&hdev->dev, "%s:logi_dj_recv_query_paired_devices "
+ "error:%d\n", __func__, retval);
+ goto logi_dj_recv_query_paired_devices_failed;
+ }
+
+ return retval;
+
+logi_dj_recv_query_paired_devices_failed:
+ hdev->ll_driver->close(hdev);
+
+llopen_failed:
+switch_to_dj_mode_fail:
+ hid_hw_stop(hdev);
+
+hid_hw_start_fail:
+hid_parse_fail:
+ kfifo_free(&djrcv_dev->notif_fifo);
+ kfree(djrcv_dev);
+ hid_set_drvdata(hdev, NULL);
+ return retval;
+
+}
+
+#ifdef CONFIG_PM
+static int logi_dj_reset_resume(struct hid_device *hdev)
+{
+ int retval;
+ struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
+
+ retval = logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0);
+ if (retval < 0) {
+ dev_err(&hdev->dev,
+ "%s:logi_dj_recv_switch_to_dj_mode returned error:%d\n",
+ __func__, retval);
+ }
+
+ return 0;
+}
+#endif
+
+static void logi_dj_remove(struct hid_device *hdev)
+{
+ struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
+ struct dj_device *dj_dev;
+ int i;
+
+ dbg_hid("%s\n", __func__);
+
+ cancel_work_sync(&djrcv_dev->work);
+
+ hdev->ll_driver->close(hdev);
+ hid_hw_stop(hdev);
+
+ /* I suppose that at this point the only context that can access
+ * the djrecv_data is this thread as the work item is guaranteed to
+ * have finished and no more raw_event callbacks should arrive after
+ * the remove callback was triggered so no locks are put around the
+ * code below */
+ for (i = 0; i < (DJ_MAX_PAIRED_DEVICES + DJ_DEVICE_INDEX_MIN); i++) {
+ dj_dev = djrcv_dev->paired_dj_devices[i];
+ if (dj_dev != NULL) {
+ hid_destroy_device(dj_dev->hdev);
+ kfree(dj_dev);
+ djrcv_dev->paired_dj_devices[i] = NULL;
+ }
+ }
+
+ kfifo_free(&djrcv_dev->notif_fifo);
+ kfree(djrcv_dev);
+ hid_set_drvdata(hdev, NULL);
+}
+
+static int logi_djdevice_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ int ret;
+ struct dj_device *dj_dev = hdev->driver_data;
+
+ if (!is_dj_device(dj_dev))
+ return -ENODEV;
+
+ ret = hid_parse(hdev);
+ if (!ret)
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+
+ return ret;
+}
+
+static const struct hid_device_id logi_dj_receivers[] = {
+ {HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
+ USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER)},
+ {HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
+ USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2)},
+ {}
+};
+
+MODULE_DEVICE_TABLE(hid, logi_dj_receivers);
+
+static struct hid_driver logi_djreceiver_driver = {
+ .name = "logitech-djreceiver",
+ .id_table = logi_dj_receivers,
+ .probe = logi_dj_probe,
+ .remove = logi_dj_remove,
+ .raw_event = logi_dj_raw_event,
+#ifdef CONFIG_PM
+ .reset_resume = logi_dj_reset_resume,
+#endif
+};
+
+
+static const struct hid_device_id logi_dj_devices[] = {
+ {HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
+ USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER)},
+ {HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
+ USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2)},
+ {}
+};
+
+static struct hid_driver logi_djdevice_driver = {
+ .name = "logitech-djdevice",
+ .id_table = logi_dj_devices,
+ .probe = logi_djdevice_probe,
+};
+
+
+static int __init logi_dj_init(void)
+{
+ int retval;
+
+ dbg_hid("Logitech-DJ:%s\n", __func__);
+
+ retval = hid_register_driver(&logi_djreceiver_driver);
+ if (retval)
+ return retval;
+
+ retval = hid_register_driver(&logi_djdevice_driver);
+ if (retval)
+ hid_unregister_driver(&logi_djreceiver_driver);
+
+ return retval;
+
+}
+
+static void __exit logi_dj_exit(void)
+{
+ dbg_hid("Logitech-DJ:%s\n", __func__);
+
+ hid_unregister_driver(&logi_djdevice_driver);
+ hid_unregister_driver(&logi_djreceiver_driver);
+
+}
+
+module_init(logi_dj_init);
+module_exit(logi_dj_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Logitech");
+MODULE_AUTHOR("Nestor Lopez Casado");
+MODULE_AUTHOR("nlopezcasad@logitech.com");
diff --git a/drivers/hid/hid-logitech-dj.h b/drivers/hid/hid-logitech-dj.h
new file mode 100644
index 000000000000..fd28a5e0ca3b
--- /dev/null
+++ b/drivers/hid/hid-logitech-dj.h
@@ -0,0 +1,123 @@
+#ifndef __HID_LOGITECH_DJ_H
+#define __HID_LOGITECH_DJ_H
+
+/*
+ * HID driver for Logitech Unifying receivers
+ *
+ * Copyright (c) 2011 Logitech
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kfifo.h>
+
+#define DJ_MAX_PAIRED_DEVICES 6
+#define DJ_MAX_NUMBER_NOTIFICATIONS 8
+#define DJ_DEVICE_INDEX_MIN 1
+#define DJ_DEVICE_INDEX_MAX 6
+
+#define DJREPORT_SHORT_LENGTH 15
+#define DJREPORT_LONG_LENGTH 32
+
+#define REPORT_ID_DJ_SHORT 0x20
+#define REPORT_ID_DJ_LONG 0x21
+
+#define REPORT_TYPE_RFREPORT_FIRST 0x01
+#define REPORT_TYPE_RFREPORT_LAST 0x1F
+
+/* Command Switch to DJ mode */
+#define REPORT_TYPE_CMD_SWITCH 0x80
+#define CMD_SWITCH_PARAM_DEVBITFIELD 0x00
+#define CMD_SWITCH_PARAM_TIMEOUT_SECONDS 0x01
+#define TIMEOUT_NO_KEEPALIVE 0x00
+
+/* Command to Get the list of Paired devices */
+#define REPORT_TYPE_CMD_GET_PAIRED_DEVICES 0x81
+
+/* Device Paired Notification */
+#define REPORT_TYPE_NOTIF_DEVICE_PAIRED 0x41
+#define SPFUNCTION_MORE_NOTIF_EXPECTED 0x01
+#define SPFUNCTION_DEVICE_LIST_EMPTY 0x02
+#define DEVICE_PAIRED_PARAM_SPFUNCTION 0x00
+#define DEVICE_PAIRED_PARAM_EQUAD_ID_LSB 0x01
+#define DEVICE_PAIRED_PARAM_EQUAD_ID_MSB 0x02
+#define DEVICE_PAIRED_RF_REPORT_TYPE 0x03
+
+/* Device Un-Paired Notification */
+#define REPORT_TYPE_NOTIF_DEVICE_UNPAIRED 0x40
+
+
+/* Connection Status Notification */
+#define REPORT_TYPE_NOTIF_CONNECTION_STATUS 0x42
+#define CONNECTION_STATUS_PARAM_STATUS 0x00
+#define STATUS_LINKLOSS 0x01
+
+/* Error Notification */
+#define REPORT_TYPE_NOTIF_ERROR 0x7F
+#define NOTIF_ERROR_PARAM_ETYPE 0x00
+#define ETYPE_KEEPALIVE_TIMEOUT 0x01
+
+/* supported DJ HID && RF report types */
+#define REPORT_TYPE_KEYBOARD 0x01
+#define REPORT_TYPE_MOUSE 0x02
+#define REPORT_TYPE_CONSUMER_CONTROL 0x03
+#define REPORT_TYPE_SYSTEM_CONTROL 0x04
+#define REPORT_TYPE_MEDIA_CENTER 0x08
+#define REPORT_TYPE_LEDS 0x0E
+
+/* RF Report types bitfield */
+#define STD_KEYBOARD 0x00000002
+#define STD_MOUSE 0x00000004
+#define MULTIMEDIA 0x00000008
+#define POWER_KEYS 0x00000010
+#define MEDIA_CENTER 0x00000100
+#define KBD_LEDS 0x00004000
+
+struct dj_report {
+ u8 report_id;
+ u8 device_index;
+ u8 report_type;
+ u8 report_params[DJREPORT_SHORT_LENGTH - 3];
+};
+
+struct dj_receiver_dev {
+ struct hid_device *hdev;
+ struct dj_device *paired_dj_devices[DJ_MAX_PAIRED_DEVICES +
+ DJ_DEVICE_INDEX_MIN];
+ struct work_struct work;
+ struct kfifo notif_fifo;
+ spinlock_t lock;
+};
+
+struct dj_device {
+ struct hid_device *hdev;
+ struct dj_receiver_dev *dj_receiver_dev;
+ u32 reports_supported;
+ u8 device_index;
+};
+
+/**
+ * is_dj_device - know if the given dj_device is not the receiver.
+ * @dj_dev: the dj device to test
+ *
+ * This macro tests if a struct dj_device pointer is a device created
+ * by the bus enumarator.
+ */
+#define is_dj_device(dj_dev) \
+ (&(dj_dev)->dj_receiver_dev->hdev->dev == (dj_dev)->hdev->dev.parent)
+
+#endif
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index 0ec91c18a421..2ab71758e2e2 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -81,6 +81,28 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie
#define NO_TOUCHES -1
#define SINGLE_TOUCH_UP -2
+/* Touch surface information. Dimension is in hundredths of a mm, min and max
+ * are in units. */
+#define MOUSE_DIMENSION_X (float)9056
+#define MOUSE_MIN_X -1100
+#define MOUSE_MAX_X 1258
+#define MOUSE_RES_X ((MOUSE_MAX_X - MOUSE_MIN_X) / (MOUSE_DIMENSION_X / 100))
+#define MOUSE_DIMENSION_Y (float)5152
+#define MOUSE_MIN_Y -1589
+#define MOUSE_MAX_Y 2047
+#define MOUSE_RES_Y ((MOUSE_MAX_Y - MOUSE_MIN_Y) / (MOUSE_DIMENSION_Y / 100))
+
+#define TRACKPAD_DIMENSION_X (float)13000
+#define TRACKPAD_MIN_X -2909
+#define TRACKPAD_MAX_X 3167
+#define TRACKPAD_RES_X \
+ ((TRACKPAD_MAX_X - TRACKPAD_MIN_X) / (TRACKPAD_DIMENSION_X / 100))
+#define TRACKPAD_DIMENSION_Y (float)11000
+#define TRACKPAD_MIN_Y -2456
+#define TRACKPAD_MAX_Y 2565
+#define TRACKPAD_RES_Y \
+ ((TRACKPAD_MAX_Y - TRACKPAD_MIN_Y) / (TRACKPAD_DIMENSION_Y / 100))
+
/**
* struct magicmouse_sc - Tracks Magic Mouse-specific data.
* @input: Input device through which we report events.
@@ -383,6 +405,13 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h
__set_bit(REL_HWHEEL, input->relbit);
}
} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
+ /* input->keybit is initialized with incorrect button info
+ * for Magic Trackpad. There really is only one physical
+ * button (BTN_LEFT == BTN_MOUSE). Make sure we don't
+ * advertise buttons that don't exist...
+ */
+ __clear_bit(BTN_RIGHT, input->keybit);
+ __clear_bit(BTN_MIDDLE, input->keybit);
__set_bit(BTN_MOUSE, input->keybit);
__set_bit(BTN_TOOL_FINGER, input->keybit);
__set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
@@ -406,17 +435,31 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h
* inverse of the reported Y.
*/
if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
- input_set_abs_params(input, ABS_MT_POSITION_X, -1100,
- 1358, 4, 0);
- input_set_abs_params(input, ABS_MT_POSITION_Y, -1589,
- 2047, 4, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_X,
+ MOUSE_MIN_X, MOUSE_MAX_X, 4, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_Y,
+ MOUSE_MIN_Y, MOUSE_MAX_Y, 4, 0);
+
+ input_abs_set_res(input, ABS_MT_POSITION_X,
+ MOUSE_RES_X);
+ input_abs_set_res(input, ABS_MT_POSITION_Y,
+ MOUSE_RES_Y);
} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
- input_set_abs_params(input, ABS_X, -2909, 3167, 4, 0);
- input_set_abs_params(input, ABS_Y, -2456, 2565, 4, 0);
- input_set_abs_params(input, ABS_MT_POSITION_X, -2909,
- 3167, 4, 0);
- input_set_abs_params(input, ABS_MT_POSITION_Y, -2456,
- 2565, 4, 0);
+ input_set_abs_params(input, ABS_X, TRACKPAD_MIN_X,
+ TRACKPAD_MAX_X, 4, 0);
+ input_set_abs_params(input, ABS_Y, TRACKPAD_MIN_Y,
+ TRACKPAD_MAX_Y, 4, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_X,
+ TRACKPAD_MIN_X, TRACKPAD_MAX_X, 4, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_Y,
+ TRACKPAD_MIN_Y, TRACKPAD_MAX_Y, 4, 0);
+
+ input_abs_set_res(input, ABS_X, TRACKPAD_RES_X);
+ input_abs_set_res(input, ABS_Y, TRACKPAD_RES_Y);
+ input_abs_set_res(input, ABS_MT_POSITION_X,
+ TRACKPAD_RES_X);
+ input_abs_set_res(input, ABS_MT_POSITION_Y,
+ TRACKPAD_RES_Y);
}
input_set_events_per_packet(input, 60);
@@ -501,9 +544,17 @@ static int magicmouse_probe(struct hid_device *hdev,
}
report->size = 6;
+ /*
+ * Some devices repond with 'invalid report id' when feature
+ * report switching it into multitouch mode is sent to it.
+ *
+ * This results in -EIO from the _raw low-level transport callback,
+ * but there seems to be no other way of switching the mode.
+ * Thus the super-ugly hacky success check below.
+ */
ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature),
HID_FEATURE_REPORT);
- if (ret != sizeof(feature)) {
+ if (ret != -EIO && ret != sizeof(feature)) {
hid_err(hdev, "unable to request touch data (%d)\n", ret);
goto err_stop_hw;
}
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 58d0e7aaf088..fa5d7a1ffa9e 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -47,10 +47,11 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_SLOT_IS_CONTACTID (1 << 1)
#define MT_QUIRK_CYPRESS (1 << 2)
#define MT_QUIRK_SLOT_IS_CONTACTNUMBER (1 << 3)
-#define MT_QUIRK_VALID_IS_INRANGE (1 << 4)
-#define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 5)
-#define MT_QUIRK_EGALAX_XYZ_FIXUP (1 << 6)
-#define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 7)
+#define MT_QUIRK_ALWAYS_VALID (1 << 4)
+#define MT_QUIRK_VALID_IS_INRANGE (1 << 5)
+#define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 6)
+#define MT_QUIRK_EGALAX_XYZ_FIXUP (1 << 7)
+#define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 8)
struct mt_slot {
__s32 x, y, p, w, h;
@@ -86,11 +87,12 @@ struct mt_class {
/* classes of device behavior */
#define MT_CLS_DEFAULT 0x0001
-#define MT_CLS_CONFIDENCE 0x0002
-#define MT_CLS_CONFIDENCE_MINUS_ONE 0x0003
-#define MT_CLS_DUAL_INRANGE_CONTACTID 0x0004
-#define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0005
-#define MT_CLS_DUAL_NSMU_CONTACTID 0x0006
+#define MT_CLS_SERIAL 0x0002
+#define MT_CLS_CONFIDENCE 0x0003
+#define MT_CLS_CONFIDENCE_MINUS_ONE 0x0004
+#define MT_CLS_DUAL_INRANGE_CONTACTID 0x0005
+#define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0006
+#define MT_CLS_DUAL_NSMU_CONTACTID 0x0007
/* vendor specific classes */
#define MT_CLS_3M 0x0101
@@ -134,6 +136,8 @@ static int find_slot_from_contactid(struct mt_device *td)
struct mt_class mt_classes[] = {
{ .name = MT_CLS_DEFAULT,
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP },
+ { .name = MT_CLS_SERIAL,
+ .quirks = MT_QUIRK_ALWAYS_VALID},
{ .name = MT_CLS_CONFIDENCE,
.quirks = MT_QUIRK_VALID_IS_CONFIDENCE },
{ .name = MT_CLS_CONFIDENCE_MINUS_ONE,
@@ -213,6 +217,16 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct mt_class *cls = td->mtclass;
__s32 quirks = cls->quirks;
+ /* Only map fields from TouchScreen or TouchPad collections.
+ * We need to ignore fields that belong to other collections
+ * such as Mouse that might have the same GenericDesktop usages. */
+ if (field->application == HID_DG_TOUCHSCREEN)
+ set_bit(INPUT_PROP_DIRECT, hi->input->propbit);
+ else if (field->application == HID_DG_TOUCHPAD)
+ set_bit(INPUT_PROP_POINTER, hi->input->propbit);
+ else
+ return 0;
+
switch (usage->hid & HID_USAGE_PAGE) {
case HID_UP_GENDESK:
@@ -277,6 +291,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
td->last_slot_field = usage->hid;
td->last_field_index = field->index;
td->last_mt_collection = usage->collection_index;
+ hdev->quirks &= ~HID_QUIRK_MULTITOUCH;
return 1;
case HID_DG_WIDTH:
hid_map_usage(hi, usage, bit, max,
@@ -435,7 +450,9 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
if (hid->claimed & HID_CLAIMED_INPUT && td->slots) {
switch (usage->hid) {
case HID_DG_INRANGE:
- if (quirks & MT_QUIRK_VALID_IS_INRANGE)
+ if (quirks & MT_QUIRK_ALWAYS_VALID)
+ td->curvalid = true;
+ else if (quirks & MT_QUIRK_VALID_IS_INRANGE)
td->curvalid = value;
break;
case HID_DG_TIPSWITCH:
@@ -513,12 +530,44 @@ static void mt_set_input_mode(struct hid_device *hdev)
}
}
+/* a list of devices for which there is a specialized multitouch driver */
+static const struct hid_device_id mt_have_special_driver[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, 0x0001) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, 0x0006) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
+ USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
+ USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
+ { }
+};
+
+static bool mt_match_one_id(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ return id->bus == hdev->bus &&
+ (id->vendor == HID_ANY_ID || id->vendor == hdev->vendor) &&
+ (id->product == HID_ANY_ID || id->product == hdev->product);
+}
+
+static const struct hid_device_id *mt_match_id(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ for (; id->bus; id++)
+ if (mt_match_one_id(hdev, id))
+ return id;
+
+ return NULL;
+}
+
static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret, i;
struct mt_device *td;
struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */
+ if (mt_match_id(hdev, mt_have_special_driver))
+ return -ENODEV;
+
for (i = 0; mt_classes[i].name ; i++) {
if (id->driver_data == mt_classes[i].name) {
mtclass = &(mt_classes[i]);
@@ -526,10 +575,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
}
}
- /* This allows the driver to correctly support devices
- * that emit events over several HID messages.
- */
- hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
td = kzalloc(sizeof(struct mt_device), GFP_KERNEL);
if (!td) {
@@ -545,10 +590,16 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (ret != 0)
goto fail;
+ hdev->quirks |= HID_QUIRK_MULTITOUCH;
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret)
goto fail;
+ /* This allows the driver to correctly support devices
+ * that emit events over several HID messages.
+ */
+ hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
+
td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot),
GFP_KERNEL);
if (!td->slots) {
@@ -662,6 +713,11 @@ static const struct hid_device_id mt_devices[] = {
HID_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH,
USB_DEVICE_ID_GOODTOUCH_000f) },
+ /* Ideacom panel */
+ { .driver_data = MT_CLS_SERIAL,
+ HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM,
+ USB_DEVICE_ID_IDEACOM_IDC6650) },
+
/* Ilitek dual touch panel */
{ .driver_data = MT_CLS_DEFAULT,
HID_USB_DEVICE(USB_VENDOR_ID_ILITEK,
@@ -672,6 +728,11 @@ static const struct hid_device_id mt_devices[] = {
HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS,
USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
+ /* LG Display panels */
+ { .driver_data = MT_CLS_DEFAULT,
+ HID_USB_DEVICE(USB_VENDOR_ID_LG,
+ USB_DEVICE_ID_LG_MULTITOUCH) },
+
/* Lumio panels */
{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
HID_USB_DEVICE(USB_VENDOR_ID_LUMIO,
@@ -732,6 +793,10 @@ static const struct hid_device_id mt_devices[] = {
HID_USB_DEVICE(USB_VENDOR_ID_XAT,
USB_DEVICE_ID_XAT_CSR) },
+ /* Rest of the world */
+ { .driver_data = MT_CLS_DEFAULT,
+ HID_USB_DEVICE(HID_ANY_ID, HID_ANY_ID) },
+
{ }
};
MODULE_DEVICE_TABLE(hid, mt_devices);
diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c
index 9d8710f8bc79..1782693819f3 100644
--- a/drivers/hid/hid-picolcd.c
+++ b/drivers/hid/hid-picolcd.c
@@ -2409,7 +2409,7 @@ static int picolcd_raw_event(struct hid_device *hdev,
#ifdef CONFIG_PM
static int picolcd_suspend(struct hid_device *hdev, pm_message_t message)
{
- if (message.event & PM_EVENT_AUTO)
+ if (PMSG_IS_AUTO(message))
return 0;
picolcd_suspend_backlight(hid_get_drvdata(hdev));
diff --git a/drivers/hid/hid-primax.c b/drivers/hid/hid-primax.c
new file mode 100644
index 000000000000..4d3c60d88318
--- /dev/null
+++ b/drivers/hid/hid-primax.c
@@ -0,0 +1,117 @@
+/*
+ * HID driver for primax and similar keyboards with in-band modifiers
+ *
+ * Copyright 2011 Google Inc. All Rights Reserved
+ *
+ * Author:
+ * Terry Lambert <tlambert@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static int px_raw_event(struct hid_device *hid, struct hid_report *report,
+ u8 *data, int size)
+{
+ int idx = size;
+
+ switch (report->id) {
+ case 0: /* keyboard input */
+ /*
+ * Convert in-band modifier key values into out of band
+ * modifier bits and pull the key strokes from the report.
+ * Thus a report data set which looked like:
+ *
+ * [00][00][E0][30][00][00][00][00]
+ * (no modifier bits + "Left Shift" key + "1" key)
+ *
+ * Would be converted to:
+ *
+ * [01][00][00][30][00][00][00][00]
+ * (Left Shift modifier bit + "1" key)
+ *
+ * As long as it's in the size range, the upper level
+ * drivers don't particularly care if there are in-band
+ * 0-valued keys, so they don't stop parsing.
+ */
+ while (--idx > 1) {
+ if (data[idx] < 0xE0 || data[idx] > 0xE7)
+ continue;
+ data[0] |= (1 << (data[idx] - 0xE0));
+ data[idx] = 0;
+ }
+ hid_report_raw_event(hid, HID_INPUT_REPORT, data, size, 0);
+ return 1;
+
+ default: /* unknown report */
+ /* Unknown report type; pass upstream */
+ hid_info(hid, "unknown report type %d\n", report->id);
+ break;
+ }
+
+ return 0;
+}
+
+static int px_probe(struct hid_device *hid, const struct hid_device_id *id)
+{
+ int ret;
+
+ ret = hid_parse(hid);
+ if (ret) {
+ hid_err(hid, "parse failed\n");
+ goto fail;
+ }
+
+ ret = hid_hw_start(hid, HID_CONNECT_DEFAULT);
+ if (ret)
+ hid_err(hid, "hw start failed\n");
+
+fail:
+ return ret;
+}
+
+static void px_remove(struct hid_device *hid)
+{
+ hid_hw_stop(hid);
+}
+
+static const struct hid_device_id px_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, px_devices);
+
+static struct hid_driver px_driver = {
+ .name = "primax",
+ .id_table = px_devices,
+ .raw_event = px_raw_event,
+ .probe = px_probe,
+ .remove = px_remove,
+};
+
+static int __init px_init(void)
+{
+ return hid_register_driver(&px_driver);
+}
+
+static void __exit px_exit(void)
+{
+ hid_unregister_driver(&px_driver);
+}
+
+module_init(px_init);
+module_exit(px_exit);
+MODULE_AUTHOR("Terry Lambert <tlambert@google.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c
index 158b389d0fb7..f779009104eb 100644
--- a/drivers/hid/hid-prodikeys.c
+++ b/drivers/hid/hid-prodikeys.c
@@ -816,7 +816,7 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (pm == NULL) {
hid_err(hdev, "can't alloc descriptor\n");
ret = -ENOMEM;
- goto err_free;
+ goto err_free_pk;
}
pm->pk = pk;
@@ -849,10 +849,10 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
err_stop:
hid_hw_stop(hdev);
err_free:
- if (pm != NULL)
- kfree(pm);
-
+ kfree(pm);
+err_free_pk:
kfree(pk);
+
return ret;
}
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
index 2b8f3a31ffb3..e2072afb34bb 100644
--- a/drivers/hid/hid-roccat-kone.c
+++ b/drivers/hid/hid-roccat-kone.c
@@ -37,6 +37,21 @@
static uint profile_numbers[5] = {0, 1, 2, 3, 4};
+static void kone_profile_activated(struct kone_device *kone, uint new_profile)
+{
+ kone->actual_profile = new_profile;
+ kone->actual_dpi = kone->profiles[new_profile - 1].startup_dpi;
+}
+
+static void kone_profile_report(struct kone_device *kone, uint new_profile)
+{
+ struct kone_roccat_report roccat_report;
+ roccat_report.event = kone_mouse_event_switch_profile;
+ roccat_report.value = new_profile;
+ roccat_report.key = 0;
+ roccat_report_event(kone->chrdev_minor, (uint8_t *)&roccat_report);
+}
+
static int kone_receive(struct usb_device *usb_dev, uint usb_command,
void *data, uint size)
{
@@ -283,7 +298,7 @@ static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj,
container_of(kobj, struct device, kobj)->parent->parent;
struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
- int retval = 0, difference;
+ int retval = 0, difference, old_profile;
/* I need to get my data in one piece */
if (off != 0 || count != sizeof(struct kone_settings))
@@ -294,21 +309,20 @@ static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj,
if (difference) {
retval = kone_set_settings(usb_dev,
(struct kone_settings const *)buf);
- if (!retval)
- memcpy(&kone->settings, buf,
- sizeof(struct kone_settings));
- }
- mutex_unlock(&kone->kone_lock);
+ if (retval) {
+ mutex_unlock(&kone->kone_lock);
+ return retval;
+ }
- if (retval)
- return retval;
+ old_profile = kone->settings.startup_profile;
+ memcpy(&kone->settings, buf, sizeof(struct kone_settings));
- /*
- * If we get here, treat settings as okay and update actual values
- * according to startup_profile
- */
- kone->actual_profile = kone->settings.startup_profile;
- kone->actual_dpi = kone->profiles[kone->actual_profile - 1].startup_dpi;
+ kone_profile_activated(kone, kone->settings.startup_profile);
+
+ if (kone->settings.startup_profile != old_profile)
+ kone_profile_report(kone, kone->settings.startup_profile);
+ }
+ mutex_unlock(&kone->kone_lock);
return sizeof(struct kone_settings);
}
@@ -501,6 +515,8 @@ static ssize_t kone_sysfs_set_tcu(struct device *dev,
goto exit_no_settings;
goto exit_unlock;
}
+ /* calibration resets profile */
+ kone_profile_activated(kone, kone->settings.startup_profile);
}
retval = size;
@@ -544,16 +560,16 @@ static ssize_t kone_sysfs_set_startup_profile(struct device *dev,
kone_set_settings_checksum(&kone->settings);
retval = kone_set_settings(usb_dev, &kone->settings);
-
- mutex_unlock(&kone->kone_lock);
-
- if (retval)
+ if (retval) {
+ mutex_unlock(&kone->kone_lock);
return retval;
+ }
/* changing the startup profile immediately activates this profile */
- kone->actual_profile = new_startup_profile;
- kone->actual_dpi = kone->profiles[kone->actual_profile - 1].startup_dpi;
+ kone_profile_activated(kone, new_startup_profile);
+ kone_profile_report(kone, new_startup_profile);
+ mutex_unlock(&kone->kone_lock);
return size;
}
@@ -665,8 +681,7 @@ static int kone_init_kone_device_struct(struct usb_device *usb_dev,
if (retval)
return retval;
- kone->actual_profile = kone->settings.startup_profile;
- kone->actual_dpi = kone->profiles[kone->actual_profile].startup_dpi;
+ kone_profile_activated(kone, kone->settings.startup_profile);
return 0;
}
@@ -776,10 +791,10 @@ static void kone_keep_values_up_to_date(struct kone_device *kone,
{
switch (event->event) {
case kone_mouse_event_switch_profile:
+ kone->actual_dpi = kone->profiles[event->value - 1].
+ startup_dpi;
case kone_mouse_event_osd_profile:
kone->actual_profile = event->value;
- kone->actual_dpi = kone->profiles[kone->actual_profile - 1].
- startup_dpi;
break;
case kone_mouse_event_switch_dpi:
case kone_mouse_event_osd_dpi:
diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c
index 1f8336e3f584..112d934132c8 100644
--- a/drivers/hid/hid-roccat-kovaplus.c
+++ b/drivers/hid/hid-roccat-kovaplus.c
@@ -323,6 +323,7 @@ static ssize_t kovaplus_sysfs_set_actual_profile(struct device *dev,
struct usb_device *usb_dev;
unsigned long profile;
int retval;
+ struct kovaplus_roccat_report roccat_report;
dev = dev->parent->parent;
kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
@@ -337,10 +338,22 @@ static ssize_t kovaplus_sysfs_set_actual_profile(struct device *dev,
mutex_lock(&kovaplus->kovaplus_lock);
retval = kovaplus_set_actual_profile(usb_dev, profile);
+ if (retval) {
+ mutex_unlock(&kovaplus->kovaplus_lock);
+ return retval;
+ }
+
kovaplus_profile_activated(kovaplus, profile);
+
+ roccat_report.type = KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_1;
+ roccat_report.profile = profile + 1;
+ roccat_report.button = 0;
+ roccat_report.data1 = profile + 1;
+ roccat_report.data2 = 0;
+ roccat_report_event(kovaplus->chrdev_minor,
+ (uint8_t const *)&roccat_report);
+
mutex_unlock(&kovaplus->kovaplus_lock);
- if (retval)
- return retval;
return size;
}
diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c
index 8140776bd8c5..df05c1b1064f 100644
--- a/drivers/hid/hid-roccat-pyra.c
+++ b/drivers/hid/hid-roccat-pyra.c
@@ -298,6 +298,7 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp,
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0;
int difference;
+ struct pyra_roccat_report roccat_report;
if (off != 0 || count != sizeof(struct pyra_settings))
return -EINVAL;
@@ -307,17 +308,23 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp,
if (difference) {
retval = pyra_set_settings(usb_dev,
(struct pyra_settings const *)buf);
- if (!retval)
- memcpy(&pyra->settings, buf,
- sizeof(struct pyra_settings));
- }
- mutex_unlock(&pyra->pyra_lock);
+ if (retval) {
+ mutex_unlock(&pyra->pyra_lock);
+ return retval;
+ }
- if (retval)
- return retval;
+ memcpy(&pyra->settings, buf,
+ sizeof(struct pyra_settings));
- profile_activated(pyra, pyra->settings.startup_profile);
+ profile_activated(pyra, pyra->settings.startup_profile);
+ roccat_report.type = PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2;
+ roccat_report.value = pyra->settings.startup_profile + 1;
+ roccat_report.key = 0;
+ roccat_report_event(pyra->chrdev_minor,
+ (uint8_t const *)&roccat_report);
+ }
+ mutex_unlock(&pyra->pyra_lock);
return sizeof(struct pyra_settings);
}
diff --git a/drivers/hid/hid-sjoy.c b/drivers/hid/hid-sjoy.c
index 16f7cafc9695..670da9109f86 100644
--- a/drivers/hid/hid-sjoy.c
+++ b/drivers/hid/hid-sjoy.c
@@ -65,8 +65,7 @@ static int sjoyff_init(struct hid_device *hid)
{
struct sjoyff_device *sjoyff;
struct hid_report *report;
- struct hid_input *hidinput = list_entry(hid->inputs.next,
- struct hid_input, list);
+ struct hid_input *hidinput;
struct list_head *report_list =
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct list_head *report_ptr = report_list;
@@ -78,43 +77,45 @@ static int sjoyff_init(struct hid_device *hid)
return -ENODEV;
}
- report_ptr = report_ptr->next;
+ list_for_each_entry(hidinput, &hid->inputs, list) {
+ report_ptr = report_ptr->next;
- if (report_ptr == report_list) {
- hid_err(hid, "required output report is missing\n");
- return -ENODEV;
- }
+ if (report_ptr == report_list) {
+ hid_err(hid, "required output report is missing\n");
+ return -ENODEV;
+ }
- report = list_entry(report_ptr, struct hid_report, list);
- if (report->maxfield < 1) {
- hid_err(hid, "no fields in the report\n");
- return -ENODEV;
- }
+ report = list_entry(report_ptr, struct hid_report, list);
+ if (report->maxfield < 1) {
+ hid_err(hid, "no fields in the report\n");
+ return -ENODEV;
+ }
- if (report->field[0]->report_count < 3) {
- hid_err(hid, "not enough values in the field\n");
- return -ENODEV;
- }
+ if (report->field[0]->report_count < 3) {
+ hid_err(hid, "not enough values in the field\n");
+ return -ENODEV;
+ }
- sjoyff = kzalloc(sizeof(struct sjoyff_device), GFP_KERNEL);
- if (!sjoyff)
- return -ENOMEM;
+ sjoyff = kzalloc(sizeof(struct sjoyff_device), GFP_KERNEL);
+ if (!sjoyff)
+ return -ENOMEM;
- dev = hidinput->input;
+ dev = hidinput->input;
- set_bit(FF_RUMBLE, dev->ffbit);
+ set_bit(FF_RUMBLE, dev->ffbit);
- error = input_ff_create_memless(dev, sjoyff, hid_sjoyff_play);
- if (error) {
- kfree(sjoyff);
- return error;
- }
+ error = input_ff_create_memless(dev, sjoyff, hid_sjoyff_play);
+ if (error) {
+ kfree(sjoyff);
+ return error;
+ }
- sjoyff->report = report;
- sjoyff->report->field[0]->value[0] = 0x01;
- sjoyff->report->field[0]->value[1] = 0x00;
- sjoyff->report->field[0]->value[2] = 0x00;
- usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT);
+ sjoyff->report = report;
+ sjoyff->report->field[0]->value[0] = 0x01;
+ sjoyff->report->field[0]->value[1] = 0x00;
+ sjoyff->report->field[0]->value[2] = 0x00;
+ usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT);
+ }
hid_info(hid, "Force feedback for SmartJoy PLUS PS2/USB adapter\n");
@@ -131,6 +132,8 @@ static int sjoy_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
+ hdev->quirks |= id->driver_data;
+
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "parse failed\n");
@@ -151,7 +154,17 @@ err:
}
static const struct hid_device_id sjoy_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_3_PRO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_DUAL_BOX_PRO),
+ .driver_data = HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET |
+ HID_QUIRK_SKIP_OUTPUT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_5_PRO),
+ .driver_data = HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET |
+ HID_QUIRK_SKIP_OUTPUT_REPORTS },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD),
+ .driver_data = HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET |
+ HID_QUIRK_SKIP_OUTPUT_REPORTS },
{ }
};
MODULE_DEVICE_TABLE(hid, sjoy_devices);
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
index 06888323828c..17bb88f782b6 100644
--- a/drivers/hid/hid-wacom.c
+++ b/drivers/hid/hid-wacom.c
@@ -304,11 +304,51 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
return 1;
}
+static int wacom_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage, unsigned long **bit,
+ int *max)
+{
+ struct input_dev *input = hi->input;
+
+ __set_bit(INPUT_PROP_POINTER, input->propbit);
+
+ /* Basics */
+ input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
+
+ __set_bit(REL_WHEEL, input->relbit);
+
+ __set_bit(BTN_TOOL_PEN, input->keybit);
+ __set_bit(BTN_TOUCH, input->keybit);
+ __set_bit(BTN_STYLUS, input->keybit);
+ __set_bit(BTN_STYLUS2, input->keybit);
+ __set_bit(BTN_LEFT, input->keybit);
+ __set_bit(BTN_RIGHT, input->keybit);
+ __set_bit(BTN_MIDDLE, input->keybit);
+
+ /* Pad */
+ input->evbit[0] |= BIT(EV_MSC);
+
+ __set_bit(MSC_SERIAL, input->mscbit);
+
+ __set_bit(BTN_0, input->keybit);
+ __set_bit(BTN_1, input->keybit);
+ __set_bit(BTN_TOOL_FINGER, input->keybit);
+
+ /* Distance, rubber and mouse */
+ __set_bit(BTN_TOOL_RUBBER, input->keybit);
+ __set_bit(BTN_TOOL_MOUSE, input->keybit);
+
+ input_set_abs_params(input, ABS_X, 0, 16704, 4, 0);
+ input_set_abs_params(input, ABS_Y, 0, 12064, 4, 0);
+ input_set_abs_params(input, ABS_PRESSURE, 0, 511, 0, 0);
+ input_set_abs_params(input, ABS_DISTANCE, 0, 32, 0, 0);
+
+ return 0;
+}
+
static int wacom_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
- struct hid_input *hidinput;
- struct input_dev *input;
struct wacom_data *wdata;
int ret;
@@ -353,11 +393,7 @@ static int wacom_probe(struct hid_device *hdev,
if (ret) {
hid_warn(hdev, "can't create sysfs battery attribute, err: %d\n",
ret);
- /*
- * battery attribute is not critical for the tablet, but if it
- * failed then there is no need to create ac attribute
- */
- goto move_on;
+ goto err_battery;
}
wdata->ac.properties = wacom_ac_props;
@@ -371,51 +407,18 @@ static int wacom_probe(struct hid_device *hdev,
if (ret) {
hid_warn(hdev,
"can't create ac battery attribute, err: %d\n", ret);
- /*
- * ac attribute is not critical for the tablet, but if it
- * failed then we don't want to battery attribute to exist
- */
- power_supply_unregister(&wdata->battery);
+ goto err_ac;
}
-
-move_on:
#endif
- hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
- input = hidinput->input;
-
- /* Basics */
- input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
-
- __set_bit(REL_WHEEL, input->relbit);
-
- __set_bit(BTN_TOOL_PEN, input->keybit);
- __set_bit(BTN_TOUCH, input->keybit);
- __set_bit(BTN_STYLUS, input->keybit);
- __set_bit(BTN_STYLUS2, input->keybit);
- __set_bit(BTN_LEFT, input->keybit);
- __set_bit(BTN_RIGHT, input->keybit);
- __set_bit(BTN_MIDDLE, input->keybit);
-
- /* Pad */
- input->evbit[0] |= BIT(EV_MSC);
-
- __set_bit(MSC_SERIAL, input->mscbit);
-
- __set_bit(BTN_0, input->keybit);
- __set_bit(BTN_1, input->keybit);
- __set_bit(BTN_TOOL_FINGER, input->keybit);
-
- /* Distance, rubber and mouse */
- __set_bit(BTN_TOOL_RUBBER, input->keybit);
- __set_bit(BTN_TOOL_MOUSE, input->keybit);
-
- input_set_abs_params(input, ABS_X, 0, 16704, 4, 0);
- input_set_abs_params(input, ABS_Y, 0, 12064, 4, 0);
- input_set_abs_params(input, ABS_PRESSURE, 0, 511, 0, 0);
- input_set_abs_params(input, ABS_DISTANCE, 0, 32, 0, 0);
-
return 0;
+#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
+err_ac:
+ power_supply_unregister(&wdata->battery);
+err_battery:
+ device_remove_file(&hdev->dev, &dev_attr_speed);
+ hid_hw_stop(hdev);
+#endif
err_free:
kfree(wdata);
return ret;
@@ -426,6 +429,7 @@ static void wacom_remove(struct hid_device *hdev)
#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
struct wacom_data *wdata = hid_get_drvdata(hdev);
#endif
+ device_remove_file(&hdev->dev, &dev_attr_speed);
hid_hw_stop(hdev);
#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
@@ -448,6 +452,7 @@ static struct hid_driver wacom_driver = {
.probe = wacom_probe,
.remove = wacom_remove,
.raw_event = wacom_raw_event,
+ .input_mapped = wacom_input_mapped,
};
static int __init wacom_init(void)
diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index a594383ce03d..76739c07fa3c 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -10,15 +10,18 @@
* any later version.
*/
-#include <linux/atomic.h>
+#include <linux/completion.h>
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/input.h>
+#include <linux/leds.h>
#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/power_supply.h>
#include <linux/spinlock.h>
#include "hid-ids.h"
-#define WIIMOTE_VERSION "0.1"
+#define WIIMOTE_VERSION "0.2"
#define WIIMOTE_NAME "Nintendo Wii Remote"
#define WIIMOTE_BUFSIZE 32
@@ -30,12 +33,26 @@ struct wiimote_buf {
struct wiimote_state {
spinlock_t lock;
__u8 flags;
+ __u8 accel_split[2];
+
+ /* synchronous cmd requests */
+ struct mutex sync;
+ struct completion ready;
+ int cmd;
+ __u32 opt;
+
+ /* results of synchronous requests */
+ __u8 cmd_battery;
+ __u8 cmd_err;
};
struct wiimote_data {
- atomic_t ready;
struct hid_device *hdev;
struct input_dev *input;
+ struct led_classdev *leds[4];
+ struct input_dev *accel;
+ struct input_dev *ir;
+ struct power_supply battery;
spinlock_t qlock;
__u8 head;
@@ -46,16 +63,47 @@ struct wiimote_data {
struct wiimote_state state;
};
-#define WIIPROTO_FLAG_LED1 0x01
-#define WIIPROTO_FLAG_LED2 0x02
-#define WIIPROTO_FLAG_LED3 0x04
-#define WIIPROTO_FLAG_LED4 0x08
+#define WIIPROTO_FLAG_LED1 0x01
+#define WIIPROTO_FLAG_LED2 0x02
+#define WIIPROTO_FLAG_LED3 0x04
+#define WIIPROTO_FLAG_LED4 0x08
+#define WIIPROTO_FLAG_RUMBLE 0x10
+#define WIIPROTO_FLAG_ACCEL 0x20
+#define WIIPROTO_FLAG_IR_BASIC 0x40
+#define WIIPROTO_FLAG_IR_EXT 0x80
+#define WIIPROTO_FLAG_IR_FULL 0xc0 /* IR_BASIC | IR_EXT */
#define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \
WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4)
+#define WIIPROTO_FLAGS_IR (WIIPROTO_FLAG_IR_BASIC | WIIPROTO_FLAG_IR_EXT | \
+ WIIPROTO_FLAG_IR_FULL)
+
+/* return flag for led \num */
+#define WIIPROTO_FLAG_LED(num) (WIIPROTO_FLAG_LED1 << (num - 1))
enum wiiproto_reqs {
+ WIIPROTO_REQ_NULL = 0x0,
+ WIIPROTO_REQ_RUMBLE = 0x10,
WIIPROTO_REQ_LED = 0x11,
+ WIIPROTO_REQ_DRM = 0x12,
+ WIIPROTO_REQ_IR1 = 0x13,
+ WIIPROTO_REQ_SREQ = 0x15,
+ WIIPROTO_REQ_WMEM = 0x16,
+ WIIPROTO_REQ_RMEM = 0x17,
+ WIIPROTO_REQ_IR2 = 0x1a,
+ WIIPROTO_REQ_STATUS = 0x20,
+ WIIPROTO_REQ_DATA = 0x21,
+ WIIPROTO_REQ_RETURN = 0x22,
WIIPROTO_REQ_DRM_K = 0x30,
+ WIIPROTO_REQ_DRM_KA = 0x31,
+ WIIPROTO_REQ_DRM_KE = 0x32,
+ WIIPROTO_REQ_DRM_KAI = 0x33,
+ WIIPROTO_REQ_DRM_KEE = 0x34,
+ WIIPROTO_REQ_DRM_KAE = 0x35,
+ WIIPROTO_REQ_DRM_KIE = 0x36,
+ WIIPROTO_REQ_DRM_KAIE = 0x37,
+ WIIPROTO_REQ_DRM_E = 0x3d,
+ WIIPROTO_REQ_DRM_SKAI1 = 0x3e,
+ WIIPROTO_REQ_DRM_SKAI2 = 0x3f,
};
enum wiiproto_keys {
@@ -87,8 +135,55 @@ static __u16 wiiproto_keymap[] = {
BTN_MODE, /* WIIPROTO_KEY_HOME */
};
-#define dev_to_wii(pdev) hid_get_drvdata(container_of(pdev, struct hid_device, \
- dev))
+static enum power_supply_property wiimote_battery_props[] = {
+ POWER_SUPPLY_PROP_CAPACITY
+};
+
+/* requires the state.lock spinlock to be held */
+static inline bool wiimote_cmd_pending(struct wiimote_data *wdata, int cmd,
+ __u32 opt)
+{
+ return wdata->state.cmd == cmd && wdata->state.opt == opt;
+}
+
+/* requires the state.lock spinlock to be held */
+static inline void wiimote_cmd_complete(struct wiimote_data *wdata)
+{
+ wdata->state.cmd = WIIPROTO_REQ_NULL;
+ complete(&wdata->state.ready);
+}
+
+static inline int wiimote_cmd_acquire(struct wiimote_data *wdata)
+{
+ return mutex_lock_interruptible(&wdata->state.sync) ? -ERESTARTSYS : 0;
+}
+
+/* requires the state.lock spinlock to be held */
+static inline void wiimote_cmd_set(struct wiimote_data *wdata, int cmd,
+ __u32 opt)
+{
+ INIT_COMPLETION(wdata->state.ready);
+ wdata->state.cmd = cmd;
+ wdata->state.opt = opt;
+}
+
+static inline void wiimote_cmd_release(struct wiimote_data *wdata)
+{
+ mutex_unlock(&wdata->state.sync);
+}
+
+static inline int wiimote_cmd_wait(struct wiimote_data *wdata)
+{
+ int ret;
+
+ ret = wait_for_completion_interruptible_timeout(&wdata->state.ready, HZ);
+ if (ret < 0)
+ return -ERESTARTSYS;
+ else if (ret == 0)
+ return -EIO;
+ else
+ return 0;
+}
static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
size_t count)
@@ -168,6 +263,39 @@ static void wiimote_queue(struct wiimote_data *wdata, const __u8 *buffer,
spin_unlock_irqrestore(&wdata->qlock, flags);
}
+/*
+ * This sets the rumble bit on the given output report if rumble is
+ * currently enabled.
+ * \cmd1 must point to the second byte in the output report => &cmd[1]
+ * This must be called on nearly every output report before passing it
+ * into the output queue!
+ */
+static inline void wiiproto_keep_rumble(struct wiimote_data *wdata, __u8 *cmd1)
+{
+ if (wdata->state.flags & WIIPROTO_FLAG_RUMBLE)
+ *cmd1 |= 0x01;
+}
+
+static void wiiproto_req_rumble(struct wiimote_data *wdata, __u8 rumble)
+{
+ __u8 cmd[2];
+
+ rumble = !!rumble;
+ if (rumble == !!(wdata->state.flags & WIIPROTO_FLAG_RUMBLE))
+ return;
+
+ if (rumble)
+ wdata->state.flags |= WIIPROTO_FLAG_RUMBLE;
+ else
+ wdata->state.flags &= ~WIIPROTO_FLAG_RUMBLE;
+
+ cmd[0] = WIIPROTO_REQ_RUMBLE;
+ cmd[1] = 0;
+
+ wiiproto_keep_rumble(wdata, &cmd[1]);
+ wiimote_queue(wdata, cmd, sizeof(cmd));
+}
+
static void wiiproto_req_leds(struct wiimote_data *wdata, int leds)
{
__u8 cmd[2];
@@ -189,71 +317,439 @@ static void wiiproto_req_leds(struct wiimote_data *wdata, int leds)
if (leds & WIIPROTO_FLAG_LED4)
cmd[1] |= 0x80;
+ wiiproto_keep_rumble(wdata, &cmd[1]);
+ wiimote_queue(wdata, cmd, sizeof(cmd));
+}
+
+/*
+ * Check what peripherals of the wiimote are currently
+ * active and select a proper DRM that supports all of
+ * the requested data inputs.
+ */
+static __u8 select_drm(struct wiimote_data *wdata)
+{
+ __u8 ir = wdata->state.flags & WIIPROTO_FLAGS_IR;
+
+ if (ir == WIIPROTO_FLAG_IR_BASIC) {
+ if (wdata->state.flags & WIIPROTO_FLAG_ACCEL)
+ return WIIPROTO_REQ_DRM_KAIE;
+ else
+ return WIIPROTO_REQ_DRM_KIE;
+ } else if (ir == WIIPROTO_FLAG_IR_EXT) {
+ return WIIPROTO_REQ_DRM_KAI;
+ } else if (ir == WIIPROTO_FLAG_IR_FULL) {
+ return WIIPROTO_REQ_DRM_SKAI1;
+ } else {
+ if (wdata->state.flags & WIIPROTO_FLAG_ACCEL)
+ return WIIPROTO_REQ_DRM_KA;
+ else
+ return WIIPROTO_REQ_DRM_K;
+ }
+}
+
+static void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm)
+{
+ __u8 cmd[3];
+
+ if (drm == WIIPROTO_REQ_NULL)
+ drm = select_drm(wdata);
+
+ cmd[0] = WIIPROTO_REQ_DRM;
+ cmd[1] = 0;
+ cmd[2] = drm;
+
+ wiiproto_keep_rumble(wdata, &cmd[1]);
+ wiimote_queue(wdata, cmd, sizeof(cmd));
+}
+
+static void wiiproto_req_status(struct wiimote_data *wdata)
+{
+ __u8 cmd[2];
+
+ cmd[0] = WIIPROTO_REQ_SREQ;
+ cmd[1] = 0;
+
+ wiiproto_keep_rumble(wdata, &cmd[1]);
+ wiimote_queue(wdata, cmd, sizeof(cmd));
+}
+
+static void wiiproto_req_accel(struct wiimote_data *wdata, __u8 accel)
+{
+ accel = !!accel;
+ if (accel == !!(wdata->state.flags & WIIPROTO_FLAG_ACCEL))
+ return;
+
+ if (accel)
+ wdata->state.flags |= WIIPROTO_FLAG_ACCEL;
+ else
+ wdata->state.flags &= ~WIIPROTO_FLAG_ACCEL;
+
+ wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+}
+
+static void wiiproto_req_ir1(struct wiimote_data *wdata, __u8 flags)
+{
+ __u8 cmd[2];
+
+ cmd[0] = WIIPROTO_REQ_IR1;
+ cmd[1] = flags;
+
+ wiiproto_keep_rumble(wdata, &cmd[1]);
+ wiimote_queue(wdata, cmd, sizeof(cmd));
+}
+
+static void wiiproto_req_ir2(struct wiimote_data *wdata, __u8 flags)
+{
+ __u8 cmd[2];
+
+ cmd[0] = WIIPROTO_REQ_IR2;
+ cmd[1] = flags;
+
+ wiiproto_keep_rumble(wdata, &cmd[1]);
+ wiimote_queue(wdata, cmd, sizeof(cmd));
+}
+
+#define wiiproto_req_wreg(wdata, os, buf, sz) \
+ wiiproto_req_wmem((wdata), false, (os), (buf), (sz))
+
+#define wiiproto_req_weeprom(wdata, os, buf, sz) \
+ wiiproto_req_wmem((wdata), true, (os), (buf), (sz))
+
+static void wiiproto_req_wmem(struct wiimote_data *wdata, bool eeprom,
+ __u32 offset, const __u8 *buf, __u8 size)
+{
+ __u8 cmd[22];
+
+ if (size > 16 || size == 0) {
+ hid_warn(wdata->hdev, "Invalid length %d wmem request\n", size);
+ return;
+ }
+
+ memset(cmd, 0, sizeof(cmd));
+ cmd[0] = WIIPROTO_REQ_WMEM;
+ cmd[2] = (offset >> 16) & 0xff;
+ cmd[3] = (offset >> 8) & 0xff;
+ cmd[4] = offset & 0xff;
+ cmd[5] = size;
+ memcpy(&cmd[6], buf, size);
+
+ if (!eeprom)
+ cmd[1] |= 0x04;
+
+ wiiproto_keep_rumble(wdata, &cmd[1]);
wiimote_queue(wdata, cmd, sizeof(cmd));
}
-#define wiifs_led_show_set(num) \
-static ssize_t wiifs_led_show_##num(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct wiimote_data *wdata = dev_to_wii(dev); \
- unsigned long flags; \
- int state; \
- \
- if (!atomic_read(&wdata->ready)) \
- return -EBUSY; \
- \
- spin_lock_irqsave(&wdata->state.lock, flags); \
- state = !!(wdata->state.flags & WIIPROTO_FLAG_LED##num); \
- spin_unlock_irqrestore(&wdata->state.lock, flags); \
- \
- return sprintf(buf, "%d\n", state); \
-} \
-static ssize_t wiifs_led_set_##num(struct device *dev, \
- struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- struct wiimote_data *wdata = dev_to_wii(dev); \
- int tmp = simple_strtoul(buf, NULL, 10); \
- unsigned long flags; \
- __u8 state; \
- \
- if (!atomic_read(&wdata->ready)) \
- return -EBUSY; \
- \
- spin_lock_irqsave(&wdata->state.lock, flags); \
- \
- state = wdata->state.flags; \
- \
- if (tmp) \
- wiiproto_req_leds(wdata, state | WIIPROTO_FLAG_LED##num);\
- else \
- wiiproto_req_leds(wdata, state & ~WIIPROTO_FLAG_LED##num);\
- \
- spin_unlock_irqrestore(&wdata->state.lock, flags); \
- \
- return count; \
-} \
-static DEVICE_ATTR(led##num, S_IRUGO | S_IWUSR, wiifs_led_show_##num, \
- wiifs_led_set_##num)
-
-wiifs_led_show_set(1);
-wiifs_led_show_set(2);
-wiifs_led_show_set(3);
-wiifs_led_show_set(4);
-
-static int wiimote_input_event(struct input_dev *dev, unsigned int type,
- unsigned int code, int value)
+/* requries the cmd-mutex to be held */
+static int wiimote_cmd_write(struct wiimote_data *wdata, __u32 offset,
+ const __u8 *wmem, __u8 size)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wiimote_cmd_set(wdata, WIIPROTO_REQ_WMEM, 0);
+ wiiproto_req_wreg(wdata, offset, wmem, size);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ ret = wiimote_cmd_wait(wdata);
+ if (!ret && wdata->state.cmd_err)
+ ret = -EIO;
+
+ return ret;
+}
+
+static int wiimote_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct wiimote_data *wdata = container_of(psy,
+ struct wiimote_data, battery);
+ int ret = 0, state;
+ unsigned long flags;
+
+ ret = wiimote_cmd_acquire(wdata);
+ if (ret)
+ return ret;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wiimote_cmd_set(wdata, WIIPROTO_REQ_SREQ, 0);
+ wiiproto_req_status(wdata);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ ret = wiimote_cmd_wait(wdata);
+ state = wdata->state.cmd_battery;
+ wiimote_cmd_release(wdata);
+
+ if (ret)
+ return ret;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = state * 100 / 255;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int wiimote_init_ir(struct wiimote_data *wdata, __u16 mode)
+{
+ int ret;
+ unsigned long flags;
+ __u8 format = 0;
+ static const __u8 data_enable[] = { 0x01 };
+ static const __u8 data_sens1[] = { 0x02, 0x00, 0x00, 0x71, 0x01,
+ 0x00, 0xaa, 0x00, 0x64 };
+ static const __u8 data_sens2[] = { 0x63, 0x03 };
+ static const __u8 data_fin[] = { 0x08 };
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+
+ if (mode == (wdata->state.flags & WIIPROTO_FLAGS_IR)) {
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+ return 0;
+ }
+
+ if (mode == 0) {
+ wdata->state.flags &= ~WIIPROTO_FLAGS_IR;
+ wiiproto_req_ir1(wdata, 0);
+ wiiproto_req_ir2(wdata, 0);
+ wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+ return 0;
+ }
+
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ ret = wiimote_cmd_acquire(wdata);
+ if (ret)
+ return ret;
+
+ /* send PIXEL CLOCK ENABLE cmd first */
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wiimote_cmd_set(wdata, WIIPROTO_REQ_IR1, 0);
+ wiiproto_req_ir1(wdata, 0x06);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ ret = wiimote_cmd_wait(wdata);
+ if (ret)
+ goto unlock;
+ if (wdata->state.cmd_err) {
+ ret = -EIO;
+ goto unlock;
+ }
+
+ /* enable IR LOGIC */
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wiimote_cmd_set(wdata, WIIPROTO_REQ_IR2, 0);
+ wiiproto_req_ir2(wdata, 0x06);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ ret = wiimote_cmd_wait(wdata);
+ if (ret)
+ goto unlock;
+ if (wdata->state.cmd_err) {
+ ret = -EIO;
+ goto unlock;
+ }
+
+ /* enable IR cam but do not make it send data, yet */
+ ret = wiimote_cmd_write(wdata, 0xb00030, data_enable,
+ sizeof(data_enable));
+ if (ret)
+ goto unlock;
+
+ /* write first sensitivity block */
+ ret = wiimote_cmd_write(wdata, 0xb00000, data_sens1,
+ sizeof(data_sens1));
+ if (ret)
+ goto unlock;
+
+ /* write second sensitivity block */
+ ret = wiimote_cmd_write(wdata, 0xb0001a, data_sens2,
+ sizeof(data_sens2));
+ if (ret)
+ goto unlock;
+
+ /* put IR cam into desired state */
+ switch (mode) {
+ case WIIPROTO_FLAG_IR_FULL:
+ format = 5;
+ break;
+ case WIIPROTO_FLAG_IR_EXT:
+ format = 3;
+ break;
+ case WIIPROTO_FLAG_IR_BASIC:
+ format = 1;
+ break;
+ }
+ ret = wiimote_cmd_write(wdata, 0xb00033, &format, sizeof(format));
+ if (ret)
+ goto unlock;
+
+ /* make IR cam send data */
+ ret = wiimote_cmd_write(wdata, 0xb00030, data_fin, sizeof(data_fin));
+ if (ret)
+ goto unlock;
+
+ /* request new DRM mode compatible to IR mode */
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wdata->state.flags &= ~WIIPROTO_FLAGS_IR;
+ wdata->state.flags |= mode & WIIPROTO_FLAGS_IR;
+ wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+unlock:
+ wiimote_cmd_release(wdata);
+ return ret;
+}
+
+static enum led_brightness wiimote_leds_get(struct led_classdev *led_dev)
+{
+ struct wiimote_data *wdata;
+ struct device *dev = led_dev->dev->parent;
+ int i;
+ unsigned long flags;
+ bool value = false;
+
+ wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
+
+ for (i = 0; i < 4; ++i) {
+ if (wdata->leds[i] == led_dev) {
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ value = wdata->state.flags & WIIPROTO_FLAG_LED(i + 1);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+ break;
+ }
+ }
+
+ return value ? LED_FULL : LED_OFF;
+}
+
+static void wiimote_leds_set(struct led_classdev *led_dev,
+ enum led_brightness value)
+{
+ struct wiimote_data *wdata;
+ struct device *dev = led_dev->dev->parent;
+ int i;
+ unsigned long flags;
+ __u8 state, flag;
+
+ wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
+
+ for (i = 0; i < 4; ++i) {
+ if (wdata->leds[i] == led_dev) {
+ flag = WIIPROTO_FLAG_LED(i + 1);
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ state = wdata->state.flags;
+ if (value == LED_OFF)
+ wiiproto_req_leds(wdata, state & ~flag);
+ else
+ wiiproto_req_leds(wdata, state | flag);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+ break;
+ }
+ }
+}
+
+static int wiimote_ff_play(struct input_dev *dev, void *data,
+ struct ff_effect *eff)
{
struct wiimote_data *wdata = input_get_drvdata(dev);
+ __u8 value;
+ unsigned long flags;
+
+ /*
+ * The wiimote supports only a single rumble motor so if any magnitude
+ * is set to non-zero then we start the rumble motor. If both are set to
+ * zero, we stop the rumble motor.
+ */
- if (!atomic_read(&wdata->ready))
- return -EBUSY;
- /* smp_rmb: Make sure wdata->xy is available when wdata->ready is 1 */
- smp_rmb();
+ if (eff->u.rumble.strong_magnitude || eff->u.rumble.weak_magnitude)
+ value = 1;
+ else
+ value = 0;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wiiproto_req_rumble(wdata, value);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
return 0;
}
+static int wiimote_input_open(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+
+ return hid_hw_open(wdata->hdev);
+}
+
+static void wiimote_input_close(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+
+ hid_hw_close(wdata->hdev);
+}
+
+static int wiimote_accel_open(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+ int ret;
+ unsigned long flags;
+
+ ret = hid_hw_open(wdata->hdev);
+ if (ret)
+ return ret;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wiiproto_req_accel(wdata, true);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ return 0;
+}
+
+static void wiimote_accel_close(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wiiproto_req_accel(wdata, false);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ hid_hw_close(wdata->hdev);
+}
+
+static int wiimote_ir_open(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+ int ret;
+
+ ret = hid_hw_open(wdata->hdev);
+ if (ret)
+ return ret;
+
+ ret = wiimote_init_ir(wdata, WIIPROTO_FLAG_IR_BASIC);
+ if (ret) {
+ hid_hw_close(wdata->hdev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void wiimote_ir_close(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+
+ wiimote_init_ir(wdata, 0);
+ hid_hw_close(wdata->hdev);
+}
+
static void handler_keys(struct wiimote_data *wdata, const __u8 *payload)
{
input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_LEFT],
@@ -281,6 +777,210 @@ static void handler_keys(struct wiimote_data *wdata, const __u8 *payload)
input_sync(wdata->input);
}
+static void handler_accel(struct wiimote_data *wdata, const __u8 *payload)
+{
+ __u16 x, y, z;
+
+ if (!(wdata->state.flags & WIIPROTO_FLAG_ACCEL))
+ return;
+
+ /*
+ * payload is: BB BB XX YY ZZ
+ * Accelerometer data is encoded into 3 10bit values. XX, YY and ZZ
+ * contain the upper 8 bits of each value. The lower 2 bits are
+ * contained in the buttons data BB BB.
+ * Bits 6 and 7 of the first buttons byte BB is the lower 2 bits of the
+ * X accel value. Bit 5 of the second buttons byte is the 2nd bit of Y
+ * accel value and bit 6 is the second bit of the Z value.
+ * The first bit of Y and Z values is not available and always set to 0.
+ * 0x200 is returned on no movement.
+ */
+
+ x = payload[2] << 2;
+ y = payload[3] << 2;
+ z = payload[4] << 2;
+
+ x |= (payload[0] >> 5) & 0x3;
+ y |= (payload[1] >> 4) & 0x2;
+ z |= (payload[1] >> 5) & 0x2;
+
+ input_report_abs(wdata->accel, ABS_RX, x - 0x200);
+ input_report_abs(wdata->accel, ABS_RY, y - 0x200);
+ input_report_abs(wdata->accel, ABS_RZ, z - 0x200);
+ input_sync(wdata->accel);
+}
+
+#define ir_to_input0(wdata, ir, packed) __ir_to_input((wdata), (ir), (packed), \
+ ABS_HAT0X, ABS_HAT0Y)
+#define ir_to_input1(wdata, ir, packed) __ir_to_input((wdata), (ir), (packed), \
+ ABS_HAT1X, ABS_HAT1Y)
+#define ir_to_input2(wdata, ir, packed) __ir_to_input((wdata), (ir), (packed), \
+ ABS_HAT2X, ABS_HAT2Y)
+#define ir_to_input3(wdata, ir, packed) __ir_to_input((wdata), (ir), (packed), \
+ ABS_HAT3X, ABS_HAT3Y)
+
+static void __ir_to_input(struct wiimote_data *wdata, const __u8 *ir,
+ bool packed, __u8 xid, __u8 yid)
+{
+ __u16 x, y;
+
+ if (!(wdata->state.flags & WIIPROTO_FLAGS_IR))
+ return;
+
+ /*
+ * Basic IR data is encoded into 3 bytes. The first two bytes are the
+ * upper 8 bit of the X/Y data, the 3rd byte contains the lower 2 bits
+ * of both.
+ * If data is packed, then the 3rd byte is put first and slightly
+ * reordered. This allows to interleave packed and non-packed data to
+ * have two IR sets in 5 bytes instead of 6.
+ * The resulting 10bit X/Y values are passed to the ABS_HATXY input dev.
+ */
+
+ if (packed) {
+ x = ir[1] << 2;
+ y = ir[2] << 2;
+
+ x |= ir[0] & 0x3;
+ y |= (ir[0] >> 2) & 0x3;
+ } else {
+ x = ir[0] << 2;
+ y = ir[1] << 2;
+
+ x |= (ir[2] >> 4) & 0x3;
+ y |= (ir[2] >> 6) & 0x3;
+ }
+
+ input_report_abs(wdata->ir, xid, x);
+ input_report_abs(wdata->ir, yid, y);
+}
+
+static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
+{
+ handler_keys(wdata, payload);
+
+ /* on status reports the drm is reset so we need to resend the drm */
+ wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+
+ if (wiimote_cmd_pending(wdata, WIIPROTO_REQ_SREQ, 0)) {
+ wdata->state.cmd_battery = payload[5];
+ wiimote_cmd_complete(wdata);
+ }
+}
+
+static void handler_data(struct wiimote_data *wdata, const __u8 *payload)
+{
+ handler_keys(wdata, payload);
+}
+
+static void handler_return(struct wiimote_data *wdata, const __u8 *payload)
+{
+ __u8 err = payload[3];
+ __u8 cmd = payload[2];
+
+ handler_keys(wdata, payload);
+
+ if (wiimote_cmd_pending(wdata, cmd, 0)) {
+ wdata->state.cmd_err = err;
+ wiimote_cmd_complete(wdata);
+ } else if (err) {
+ hid_warn(wdata->hdev, "Remote error %hhu on req %hhu\n", err,
+ cmd);
+ }
+}
+
+static void handler_drm_KA(struct wiimote_data *wdata, const __u8 *payload)
+{
+ handler_keys(wdata, payload);
+ handler_accel(wdata, payload);
+}
+
+static void handler_drm_KE(struct wiimote_data *wdata, const __u8 *payload)
+{
+ handler_keys(wdata, payload);
+}
+
+static void handler_drm_KAI(struct wiimote_data *wdata, const __u8 *payload)
+{
+ handler_keys(wdata, payload);
+ handler_accel(wdata, payload);
+ ir_to_input0(wdata, &payload[5], false);
+ ir_to_input1(wdata, &payload[8], false);
+ ir_to_input2(wdata, &payload[11], false);
+ ir_to_input3(wdata, &payload[14], false);
+ input_sync(wdata->ir);
+}
+
+static void handler_drm_KEE(struct wiimote_data *wdata, const __u8 *payload)
+{
+ handler_keys(wdata, payload);
+}
+
+static void handler_drm_KIE(struct wiimote_data *wdata, const __u8 *payload)
+{
+ handler_keys(wdata, payload);
+ ir_to_input0(wdata, &payload[2], false);
+ ir_to_input1(wdata, &payload[4], true);
+ ir_to_input2(wdata, &payload[7], false);
+ ir_to_input3(wdata, &payload[9], true);
+ input_sync(wdata->ir);
+}
+
+static void handler_drm_KAE(struct wiimote_data *wdata, const __u8 *payload)
+{
+ handler_keys(wdata, payload);
+ handler_accel(wdata, payload);
+}
+
+static void handler_drm_KAIE(struct wiimote_data *wdata, const __u8 *payload)
+{
+ handler_keys(wdata, payload);
+ handler_accel(wdata, payload);
+ ir_to_input0(wdata, &payload[5], false);
+ ir_to_input1(wdata, &payload[7], true);
+ ir_to_input2(wdata, &payload[10], false);
+ ir_to_input3(wdata, &payload[12], true);
+ input_sync(wdata->ir);
+}
+
+static void handler_drm_E(struct wiimote_data *wdata, const __u8 *payload)
+{
+}
+
+static void handler_drm_SKAI1(struct wiimote_data *wdata, const __u8 *payload)
+{
+ handler_keys(wdata, payload);
+
+ wdata->state.accel_split[0] = payload[2];
+ wdata->state.accel_split[1] = (payload[0] >> 1) & (0x10 | 0x20);
+ wdata->state.accel_split[1] |= (payload[1] << 1) & (0x40 | 0x80);
+
+ ir_to_input0(wdata, &payload[3], false);
+ ir_to_input1(wdata, &payload[12], false);
+ input_sync(wdata->ir);
+}
+
+static void handler_drm_SKAI2(struct wiimote_data *wdata, const __u8 *payload)
+{
+ __u8 buf[5];
+
+ handler_keys(wdata, payload);
+
+ wdata->state.accel_split[1] |= (payload[0] >> 5) & (0x01 | 0x02);
+ wdata->state.accel_split[1] |= (payload[1] >> 3) & (0x04 | 0x08);
+
+ buf[0] = 0;
+ buf[1] = 0;
+ buf[2] = wdata->state.accel_split[0];
+ buf[3] = payload[2];
+ buf[4] = wdata->state.accel_split[1];
+ handler_accel(wdata, buf);
+
+ ir_to_input2(wdata, &payload[3], false);
+ ir_to_input3(wdata, &payload[12], false);
+ input_sync(wdata->ir);
+}
+
struct wiiproto_handler {
__u8 id;
size_t size;
@@ -288,7 +988,20 @@ struct wiiproto_handler {
};
static struct wiiproto_handler handlers[] = {
+ { .id = WIIPROTO_REQ_STATUS, .size = 6, .func = handler_status },
+ { .id = WIIPROTO_REQ_DATA, .size = 21, .func = handler_data },
+ { .id = WIIPROTO_REQ_RETURN, .size = 4, .func = handler_return },
{ .id = WIIPROTO_REQ_DRM_K, .size = 2, .func = handler_keys },
+ { .id = WIIPROTO_REQ_DRM_KA, .size = 5, .func = handler_drm_KA },
+ { .id = WIIPROTO_REQ_DRM_KE, .size = 10, .func = handler_drm_KE },
+ { .id = WIIPROTO_REQ_DRM_KAI, .size = 17, .func = handler_drm_KAI },
+ { .id = WIIPROTO_REQ_DRM_KEE, .size = 21, .func = handler_drm_KEE },
+ { .id = WIIPROTO_REQ_DRM_KAE, .size = 21, .func = handler_drm_KAE },
+ { .id = WIIPROTO_REQ_DRM_KIE, .size = 21, .func = handler_drm_KIE },
+ { .id = WIIPROTO_REQ_DRM_KAIE, .size = 21, .func = handler_drm_KAIE },
+ { .id = WIIPROTO_REQ_DRM_E, .size = 21, .func = handler_drm_E },
+ { .id = WIIPROTO_REQ_DRM_SKAI1, .size = 21, .func = handler_drm_SKAI1 },
+ { .id = WIIPROTO_REQ_DRM_SKAI2, .size = 21, .func = handler_drm_SKAI2 },
{ .id = 0 }
};
@@ -299,11 +1012,7 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
struct wiiproto_handler *h;
int i;
unsigned long flags;
-
- if (!atomic_read(&wdata->ready))
- return -EBUSY;
- /* smp_rmb: Make sure wdata->xy is available when wdata->ready is 1 */
- smp_rmb();
+ bool handled = false;
if (size < 1)
return -EINVAL;
@@ -312,15 +1021,73 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
for (i = 0; handlers[i].id; ++i) {
h = &handlers[i];
- if (h->id == raw_data[0] && h->size < size)
+ if (h->id == raw_data[0] && h->size < size) {
h->func(wdata, &raw_data[1]);
+ handled = true;
+ }
}
+ if (!handled)
+ hid_warn(hdev, "Unhandled report %hhu size %d\n", raw_data[0],
+ size);
+
spin_unlock_irqrestore(&wdata->state.lock, flags);
return 0;
}
+static void wiimote_leds_destroy(struct wiimote_data *wdata)
+{
+ int i;
+ struct led_classdev *led;
+
+ for (i = 0; i < 4; ++i) {
+ if (wdata->leds[i]) {
+ led = wdata->leds[i];
+ wdata->leds[i] = NULL;
+ led_classdev_unregister(led);
+ kfree(led);
+ }
+ }
+}
+
+static int wiimote_leds_create(struct wiimote_data *wdata)
+{
+ int i, ret;
+ struct device *dev = &wdata->hdev->dev;
+ size_t namesz = strlen(dev_name(dev)) + 9;
+ struct led_classdev *led;
+ char *name;
+
+ for (i = 0; i < 4; ++i) {
+ led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL);
+ if (!led) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ name = (void*)&led[1];
+ snprintf(name, namesz, "%s:blue:p%d", dev_name(dev), i);
+ led->name = name;
+ led->brightness = 0;
+ led->max_brightness = 1;
+ led->brightness_get = wiimote_leds_get;
+ led->brightness_set = wiimote_leds_set;
+
+ ret = led_classdev_register(dev, led);
+ if (ret) {
+ kfree(led);
+ goto err;
+ }
+ wdata->leds[i] = led;
+ }
+
+ return 0;
+
+err:
+ wiimote_leds_destroy(wdata);
+ return ret;
+}
+
static struct wiimote_data *wiimote_create(struct hid_device *hdev)
{
struct wiimote_data *wdata;
@@ -331,16 +1098,15 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
return NULL;
wdata->input = input_allocate_device();
- if (!wdata->input) {
- kfree(wdata);
- return NULL;
- }
+ if (!wdata->input)
+ goto err;
wdata->hdev = hdev;
hid_set_drvdata(hdev, wdata);
input_set_drvdata(wdata->input, wdata);
- wdata->input->event = wiimote_input_event;
+ wdata->input->open = wiimote_input_open;
+ wdata->input->close = wiimote_input_close;
wdata->input->dev.parent = &wdata->hdev->dev;
wdata->input->id.bustype = wdata->hdev->bus;
wdata->input->id.vendor = wdata->hdev->vendor;
@@ -352,16 +1118,93 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
for (i = 0; i < WIIPROTO_KEY_COUNT; ++i)
set_bit(wiiproto_keymap[i], wdata->input->keybit);
+ set_bit(FF_RUMBLE, wdata->input->ffbit);
+ if (input_ff_create_memless(wdata->input, NULL, wiimote_ff_play))
+ goto err_input;
+
+ wdata->accel = input_allocate_device();
+ if (!wdata->accel)
+ goto err_input;
+
+ input_set_drvdata(wdata->accel, wdata);
+ wdata->accel->open = wiimote_accel_open;
+ wdata->accel->close = wiimote_accel_close;
+ wdata->accel->dev.parent = &wdata->hdev->dev;
+ wdata->accel->id.bustype = wdata->hdev->bus;
+ wdata->accel->id.vendor = wdata->hdev->vendor;
+ wdata->accel->id.product = wdata->hdev->product;
+ wdata->accel->id.version = wdata->hdev->version;
+ wdata->accel->name = WIIMOTE_NAME " Accelerometer";
+
+ set_bit(EV_ABS, wdata->accel->evbit);
+ set_bit(ABS_RX, wdata->accel->absbit);
+ set_bit(ABS_RY, wdata->accel->absbit);
+ set_bit(ABS_RZ, wdata->accel->absbit);
+ input_set_abs_params(wdata->accel, ABS_RX, -500, 500, 2, 4);
+ input_set_abs_params(wdata->accel, ABS_RY, -500, 500, 2, 4);
+ input_set_abs_params(wdata->accel, ABS_RZ, -500, 500, 2, 4);
+
+ wdata->ir = input_allocate_device();
+ if (!wdata->ir)
+ goto err_ir;
+
+ input_set_drvdata(wdata->ir, wdata);
+ wdata->ir->open = wiimote_ir_open;
+ wdata->ir->close = wiimote_ir_close;
+ wdata->ir->dev.parent = &wdata->hdev->dev;
+ wdata->ir->id.bustype = wdata->hdev->bus;
+ wdata->ir->id.vendor = wdata->hdev->vendor;
+ wdata->ir->id.product = wdata->hdev->product;
+ wdata->ir->id.version = wdata->hdev->version;
+ wdata->ir->name = WIIMOTE_NAME " IR";
+
+ set_bit(EV_ABS, wdata->ir->evbit);
+ set_bit(ABS_HAT0X, wdata->ir->absbit);
+ set_bit(ABS_HAT0Y, wdata->ir->absbit);
+ set_bit(ABS_HAT1X, wdata->ir->absbit);
+ set_bit(ABS_HAT1Y, wdata->ir->absbit);
+ set_bit(ABS_HAT2X, wdata->ir->absbit);
+ set_bit(ABS_HAT2Y, wdata->ir->absbit);
+ set_bit(ABS_HAT3X, wdata->ir->absbit);
+ set_bit(ABS_HAT3Y, wdata->ir->absbit);
+ input_set_abs_params(wdata->ir, ABS_HAT0X, 0, 1023, 2, 4);
+ input_set_abs_params(wdata->ir, ABS_HAT0Y, 0, 767, 2, 4);
+ input_set_abs_params(wdata->ir, ABS_HAT1X, 0, 1023, 2, 4);
+ input_set_abs_params(wdata->ir, ABS_HAT1Y, 0, 767, 2, 4);
+ input_set_abs_params(wdata->ir, ABS_HAT2X, 0, 1023, 2, 4);
+ input_set_abs_params(wdata->ir, ABS_HAT2Y, 0, 767, 2, 4);
+ input_set_abs_params(wdata->ir, ABS_HAT3X, 0, 1023, 2, 4);
+ input_set_abs_params(wdata->ir, ABS_HAT3Y, 0, 767, 2, 4);
+
spin_lock_init(&wdata->qlock);
INIT_WORK(&wdata->worker, wiimote_worker);
spin_lock_init(&wdata->state.lock);
+ init_completion(&wdata->state.ready);
+ mutex_init(&wdata->state.sync);
return wdata;
+
+err_ir:
+ input_free_device(wdata->accel);
+err_input:
+ input_free_device(wdata->input);
+err:
+ kfree(wdata);
+ return NULL;
}
static void wiimote_destroy(struct wiimote_data *wdata)
{
+ wiimote_leds_destroy(wdata);
+
+ power_supply_unregister(&wdata->battery);
+ input_unregister_device(wdata->accel);
+ input_unregister_device(wdata->ir);
+ input_unregister_device(wdata->input);
+ cancel_work_sync(&wdata->worker);
+ hid_hw_stop(wdata->hdev);
+
kfree(wdata);
}
@@ -377,19 +1220,6 @@ static int wiimote_hid_probe(struct hid_device *hdev,
return -ENOMEM;
}
- ret = device_create_file(&hdev->dev, &dev_attr_led1);
- if (ret)
- goto err;
- ret = device_create_file(&hdev->dev, &dev_attr_led2);
- if (ret)
- goto err;
- ret = device_create_file(&hdev->dev, &dev_attr_led3);
- if (ret)
- goto err;
- ret = device_create_file(&hdev->dev, &dev_attr_led4);
- if (ret)
- goto err;
-
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "HID parse failed\n");
@@ -402,15 +1232,41 @@ static int wiimote_hid_probe(struct hid_device *hdev,
goto err;
}
- ret = input_register_device(wdata->input);
+ ret = input_register_device(wdata->accel);
if (ret) {
hid_err(hdev, "Cannot register input device\n");
goto err_stop;
}
- /* smp_wmb: Write wdata->xy first before wdata->ready is set to 1 */
- smp_wmb();
- atomic_set(&wdata->ready, 1);
+ ret = input_register_device(wdata->ir);
+ if (ret) {
+ hid_err(hdev, "Cannot register input device\n");
+ goto err_ir;
+ }
+
+ ret = input_register_device(wdata->input);
+ if (ret) {
+ hid_err(hdev, "Cannot register input device\n");
+ goto err_input;
+ }
+
+ wdata->battery.properties = wiimote_battery_props;
+ wdata->battery.num_properties = ARRAY_SIZE(wiimote_battery_props);
+ wdata->battery.get_property = wiimote_battery_get_property;
+ wdata->battery.name = "wiimote_battery";
+ wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+ wdata->battery.use_for_apm = 0;
+
+ ret = power_supply_register(&wdata->hdev->dev, &wdata->battery);
+ if (ret) {
+ hid_err(hdev, "Cannot register battery device\n");
+ goto err_battery;
+ }
+
+ ret = wiimote_leds_create(wdata);
+ if (ret)
+ goto err_free;
+
hid_info(hdev, "New device registered\n");
/* by default set led1 after device initialization */
@@ -420,15 +1276,26 @@ static int wiimote_hid_probe(struct hid_device *hdev,
return 0;
+err_free:
+ wiimote_destroy(wdata);
+ return ret;
+
+err_battery:
+ input_unregister_device(wdata->input);
+ wdata->input = NULL;
+err_input:
+ input_unregister_device(wdata->ir);
+ wdata->ir = NULL;
+err_ir:
+ input_unregister_device(wdata->accel);
+ wdata->accel = NULL;
err_stop:
hid_hw_stop(hdev);
err:
+ input_free_device(wdata->ir);
+ input_free_device(wdata->accel);
input_free_device(wdata->input);
- device_remove_file(&hdev->dev, &dev_attr_led1);
- device_remove_file(&hdev->dev, &dev_attr_led2);
- device_remove_file(&hdev->dev, &dev_attr_led3);
- device_remove_file(&hdev->dev, &dev_attr_led4);
- wiimote_destroy(wdata);
+ kfree(wdata);
return ret;
}
@@ -437,16 +1304,6 @@ static void wiimote_hid_remove(struct hid_device *hdev)
struct wiimote_data *wdata = hid_get_drvdata(hdev);
hid_info(hdev, "Device removed\n");
-
- device_remove_file(&hdev->dev, &dev_attr_led1);
- device_remove_file(&hdev->dev, &dev_attr_led2);
- device_remove_file(&hdev->dev, &dev_attr_led3);
- device_remove_file(&hdev->dev, &dev_attr_led4);
-
- hid_hw_stop(hdev);
- input_unregister_device(wdata->input);
-
- cancel_work_sync(&wdata->worker);
wiimote_destroy(wdata);
}
diff --git a/drivers/hid/hid-zydacron.c b/drivers/hid/hid-zydacron.c
index e90371508fd2..1ad85f2257b4 100644
--- a/drivers/hid/hid-zydacron.c
+++ b/drivers/hid/hid-zydacron.c
@@ -201,9 +201,7 @@ static void zc_remove(struct hid_device *hdev)
struct zc_device *zc = hid_get_drvdata(hdev);
hid_hw_stop(hdev);
-
- if (NULL != zc)
- kfree(zc);
+ kfree(zc);
}
static const struct hid_device_id zc_devices[] = {
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index c79578b5a788..cf7d6d58e79f 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -259,7 +259,6 @@ static int hidraw_open(struct inode *inode, struct file *file)
mutex_lock(&minors_lock);
if (!hidraw_table[minor]) {
- kfree(list);
err = -ENODEV;
goto out_unlock;
}
@@ -272,8 +271,10 @@ static int hidraw_open(struct inode *inode, struct file *file)
dev = hidraw_table[minor];
if (!dev->open++) {
err = hid_hw_power(dev->hid, PM_HINT_FULLON);
- if (err < 0)
+ if (err < 0) {
+ dev->open--;
goto out_unlock;
+ }
err = hid_hw_open(dev->hid);
if (err < 0) {
@@ -285,6 +286,8 @@ static int hidraw_open(struct inode *inode, struct file *file)
out_unlock:
mutex_unlock(&minors_lock);
out:
+ if (err < 0)
+ kfree(list);
return err;
}
@@ -510,13 +513,12 @@ void hidraw_disconnect(struct hid_device *hid)
{
struct hidraw *hidraw = hid->hidraw;
+ mutex_lock(&minors_lock);
hidraw->exist = 0;
device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
- mutex_lock(&minors_lock);
hidraw_table[hidraw->minor] = NULL;
- mutex_unlock(&minors_lock);
if (hidraw->open) {
hid_hw_close(hid);
@@ -524,6 +526,7 @@ void hidraw_disconnect(struct hid_device *hid)
} else {
kfree(hidraw);
}
+ mutex_unlock(&minors_lock);
}
EXPORT_SYMBOL_GPL(hidraw_disconnect);
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index ad978f5748d3..b403fcef0b86 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -1270,7 +1270,7 @@ static void hid_cancel_delayed_stuff(struct usbhid_device *usbhid)
static void hid_cease_io(struct usbhid_device *usbhid)
{
- del_timer(&usbhid->io_retry);
+ del_timer_sync(&usbhid->io_retry);
usb_kill_urb(usbhid->urbin);
usb_kill_urb(usbhid->urbctrl);
usb_kill_urb(usbhid->urbout);
@@ -1332,7 +1332,7 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
struct usbhid_device *usbhid = hid->driver_data;
int status;
- if (message.event & PM_EVENT_AUTO) {
+ if (PMSG_IS_AUTO(message)) {
spin_lock_irq(&usbhid->lock); /* Sync with error handler */
if (!test_bit(HID_RESET_PENDING, &usbhid->iofl)
&& !test_bit(HID_CLEAR_HALT, &usbhid->iofl)
@@ -1367,7 +1367,7 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
return -EIO;
}
- if (!ignoreled && (message.event & PM_EVENT_AUTO)) {
+ if (!ignoreled && PMSG_IS_AUTO(message)) {
spin_lock_irq(&usbhid->lock);
if (test_bit(HID_LED_ON, &usbhid->iofl)) {
spin_unlock_irq(&usbhid->lock);
@@ -1380,8 +1380,7 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
hid_cancel_delayed_stuff(usbhid);
hid_cease_io(usbhid);
- if ((message.event & PM_EVENT_AUTO) &&
- test_bit(HID_KEYS_PRESSED, &usbhid->iofl)) {
+ if (PMSG_IS_AUTO(message) && test_bit(HID_KEYS_PRESSED, &usbhid->iofl)) {
/* lost race against keypresses */
status = hid_start_in(hid);
if (status < 0)
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 621959d5cc42..4ea464151c3b 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -47,6 +47,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL },
{ USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_GREENASIA, USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
{ 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 },
@@ -79,16 +80,15 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH, HID_QUIRK_MULTI_INPUT },
- { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
- { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_PI_ENGINEERING, USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL, HID_QUIRK_HIDINPUT_FORCE },
{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_SIGMA_MICRO, USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD, HID_QUIRK_NO_INIT_REPORTS },
{ 0, 0 }
};
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index 7c1188b53c3e..4ef02b269a71 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -641,6 +641,8 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct usb_device *dev = hid_to_usb_dev(hid);
struct usbhid_device *usbhid = hid->driver_data;
+ memset(&dinfo, 0, sizeof(dinfo));
+
dinfo.bustype = BUS_USB;
dinfo.busnum = dev->bus->busnum;
dinfo.devnum = dev->devnum;
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 0b62c3c6b7ce..9b347acf1559 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -68,6 +68,16 @@ config SENSORS_ABITUGURU3
This driver can also be built as a module. If so, the module
will be called abituguru3.
+config SENSORS_AD7314
+ tristate "Analog Devices AD7314 and compatibles"
+ depends on SPI && EXPERIMENTAL
+ help
+ If you say yes here you get support for the Analog Devices
+ AD7314, ADT7301 and ADT7302 temperature sensors.
+
+ This driver can also be built as a module. If so, the module
+ will be called ad7314.
+
config SENSORS_AD7414
tristate "Analog Devices AD7414"
depends on I2C && EXPERIMENTAL
@@ -303,6 +313,16 @@ config SENSORS_DS1621
This driver can also be built as a module. If so, the module
will be called ds1621.
+config SENSORS_EXYNOS4_TMU
+ tristate "Temperature sensor on Samsung EXYNOS4"
+ depends on EXYNOS4_DEV_TMU
+ help
+ If you say yes here you get support for TMU (Thermal Managment
+ Unit) on SAMSUNG EXYNOS4 series of SoC.
+
+ This driver can also be built as a module. If so, the module
+ will be called exynos4-tmu.
+
config SENSORS_I5K_AMB
tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets"
depends on PCI && EXPERIMENTAL
@@ -531,6 +551,7 @@ config SENSORS_LM75
If you say yes here you get support for one common type of
temperature sensor chip, with models including:
+ - Analog Devices ADT75
- Dallas Semiconductor DS75 and DS1775
- Maxim MAX6625 and MAX6626
- Microchip MCP980x
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 3c9ccefea791..8251ce8cd035 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_SENSORS_W83791D) += w83791d.o
obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o
obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
+obj-$(CONFIG_SENSORS_AD7314) += ad7314.o
obj-$(CONFIG_SENSORS_AD7414) += ad7414.o
obj-$(CONFIG_SENSORS_AD7418) += ad7418.o
obj-$(CONFIG_SENSORS_ADCXX) += adcxx.o
@@ -47,6 +48,7 @@ obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o
obj-$(CONFIG_SENSORS_EMC2103) += emc2103.o
obj-$(CONFIG_SENSORS_EMC6W201) += emc6w201.o
+obj-$(CONFIG_SENSORS_EXYNOS4_TMU) += exynos4_tmu.o
obj-$(CONFIG_SENSORS_F71805F) += f71805f.o
obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o
obj-$(CONFIG_SENSORS_F75375S) += f75375s.o
diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c
new file mode 100644
index 000000000000..318e38e85376
--- /dev/null
+++ b/drivers/hwmon/ad7314.c
@@ -0,0 +1,186 @@
+/*
+ * AD7314 digital temperature sensor driver for AD7314, ADT7301 and ADT7302
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ *
+ * Conversion to hwmon from IIO done by Jonathan Cameron <jic23@cam.ac.uk>
+ */
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+/*
+ * AD7314 power mode
+ */
+#define AD7314_PD 0x2000
+
+/*
+ * AD7314 temperature masks
+ */
+#define AD7314_TEMP_SIGN 0x200
+#define AD7314_TEMP_MASK 0x7FE0
+#define AD7314_TEMP_OFFSET 5
+
+/*
+ * ADT7301 and ADT7302 temperature masks
+ */
+#define ADT7301_TEMP_SIGN 0x2000
+#define ADT7301_TEMP_MASK 0x3FFF
+
+enum ad7314_variant {
+ adt7301,
+ adt7302,
+ ad7314,
+};
+
+struct ad7314_data {
+ struct spi_device *spi_dev;
+ struct device *hwmon_dev;
+ u16 rx ____cacheline_aligned;
+};
+
+static int ad7314_spi_read(struct ad7314_data *chip, s16 *data)
+{
+ int ret;
+
+ ret = spi_read(chip->spi_dev, (u8 *)&chip->rx, sizeof(chip->rx));
+ if (ret < 0) {
+ dev_err(&chip->spi_dev->dev, "SPI read error\n");
+ return ret;
+ }
+
+ *data = be16_to_cpu(chip->rx);
+
+ return ret;
+}
+
+static ssize_t ad7314_show_temperature(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ad7314_data *chip = dev_get_drvdata(dev);
+ s16 data;
+ int ret;
+
+ ret = ad7314_spi_read(chip, &data);
+ if (ret < 0)
+ return ret;
+ switch (spi_get_device_id(chip->spi_dev)->driver_data) {
+ case ad7314:
+ data = (data & AD7314_TEMP_MASK) >> AD7314_TEMP_OFFSET;
+ data = (data << 6) >> 6;
+
+ return sprintf(buf, "%d\n", 250 * data);
+ case adt7301:
+ case adt7302:
+ /*
+ * Documented as a 13 bit twos complement register
+ * with a sign bit - which is a 14 bit 2's complement
+ * register. 1lsb - 31.25 milli degrees centigrade
+ */
+ data &= ADT7301_TEMP_MASK;
+ data = (data << 2) >> 2;
+
+ return sprintf(buf, "%d\n",
+ DIV_ROUND_CLOSEST(data * 3125, 100));
+ default:
+ return -EINVAL;
+ }
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
+ ad7314_show_temperature, NULL, 0);
+
+static struct attribute *ad7314_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad7314_group = {
+ .attrs = ad7314_attributes,
+};
+
+static int __devinit ad7314_probe(struct spi_device *spi_dev)
+{
+ int ret;
+ struct ad7314_data *chip;
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (chip == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ dev_set_drvdata(&spi_dev->dev, chip);
+
+ ret = sysfs_create_group(&spi_dev->dev.kobj, &ad7314_group);
+ if (ret < 0)
+ goto error_free_chip;
+ chip->hwmon_dev = hwmon_device_register(&spi_dev->dev);
+ if (IS_ERR(chip->hwmon_dev)) {
+ ret = PTR_ERR(chip->hwmon_dev);
+ goto error_remove_group;
+ }
+
+ return 0;
+error_remove_group:
+ sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
+error_free_chip:
+ kfree(chip);
+error_ret:
+ return ret;
+}
+
+static int __devexit ad7314_remove(struct spi_device *spi_dev)
+{
+ struct ad7314_data *chip = dev_get_drvdata(&spi_dev->dev);
+
+ hwmon_device_unregister(chip->hwmon_dev);
+ sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
+ kfree(chip);
+
+ return 0;
+}
+
+static const struct spi_device_id ad7314_id[] = {
+ { "adt7301", adt7301 },
+ { "adt7302", adt7302 },
+ { "ad7314", ad7314 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ad7314_id);
+
+static struct spi_driver ad7314_driver = {
+ .driver = {
+ .name = "ad7314",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad7314_probe,
+ .remove = __devexit_p(ad7314_remove),
+ .id_table = ad7314_id,
+};
+
+static __init int ad7314_init(void)
+{
+ return spi_register_driver(&ad7314_driver);
+}
+module_init(ad7314_init);
+
+static __exit void ad7314_exit(void)
+{
+ spi_unregister_driver(&ad7314_driver);
+}
+module_exit(ad7314_exit);
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital"
+ " temperature sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 59d83e83da7f..932383786642 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -36,17 +36,25 @@
#include <linux/cpu.h>
#include <linux/pci.h>
#include <linux/smp.h>
+#include <linux/moduleparam.h>
#include <asm/msr.h>
#include <asm/processor.h>
#define DRVNAME "coretemp"
+/*
+ * force_tjmax only matters when TjMax can't be read from the CPU itself.
+ * When set, it replaces the driver's suboptimal heuristic.
+ */
+static int force_tjmax;
+module_param_named(tjmax, force_tjmax, int, 0444);
+MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius");
+
#define BASE_SYSFS_ATTR_NO 2 /* Sysfs Base attr no for coretemp */
#define NUM_REAL_CORES 16 /* Number of Real cores per cpu */
#define CORETEMP_NAME_LENGTH 17 /* String Length of attrs */
#define MAX_CORE_ATTRS 4 /* Maximum no of basic attrs */
-#define MAX_THRESH_ATTRS 3 /* Maximum no of Threshold attrs */
-#define TOTAL_ATTRS (MAX_CORE_ATTRS + MAX_THRESH_ATTRS)
+#define TOTAL_ATTRS (MAX_CORE_ATTRS + 1)
#define MAX_CORE_DATA (NUM_REAL_CORES + BASE_SYSFS_ATTR_NO)
#ifdef CONFIG_SMP
@@ -69,8 +77,6 @@
* This value is passed as "id" field to rdmsr/wrmsr functions.
* @status_reg: One of IA32_THERM_STATUS or IA32_PACKAGE_THERM_STATUS,
* from where the temperature values should be read.
- * @intrpt_reg: One of IA32_THERM_INTERRUPT or IA32_PACKAGE_THERM_INTERRUPT,
- * from where the thresholds are read.
* @attr_size: Total number of pre-core attrs displayed in the sysfs.
* @is_pkg_data: If this is 1, the temp_data holds pkgtemp data.
* Otherwise, temp_data holds coretemp data.
@@ -79,13 +85,11 @@
struct temp_data {
int temp;
int ttarget;
- int tmin;
int tjmax;
unsigned long last_updated;
unsigned int cpu;
u32 cpu_core_id;
u32 status_reg;
- u32 intrpt_reg;
int attr_size;
bool is_pkg_data;
bool valid;
@@ -143,19 +147,6 @@ static ssize_t show_crit_alarm(struct device *dev,
return sprintf(buf, "%d\n", (eax >> 5) & 1);
}
-static ssize_t show_max_alarm(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- u32 eax, edx;
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct platform_data *pdata = dev_get_drvdata(dev);
- struct temp_data *tdata = pdata->core_data[attr->index];
-
- rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx);
-
- return sprintf(buf, "%d\n", !!(eax & THERM_STATUS_THRESHOLD1));
-}
-
static ssize_t show_tjmax(struct device *dev,
struct device_attribute *devattr, char *buf)
{
@@ -174,83 +165,6 @@ static ssize_t show_ttarget(struct device *dev,
return sprintf(buf, "%d\n", pdata->core_data[attr->index]->ttarget);
}
-static ssize_t store_ttarget(struct device *dev,
- struct device_attribute *devattr,
- const char *buf, size_t count)
-{
- struct platform_data *pdata = dev_get_drvdata(dev);
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct temp_data *tdata = pdata->core_data[attr->index];
- u32 eax, edx;
- unsigned long val;
- int diff;
-
- if (strict_strtoul(buf, 10, &val))
- return -EINVAL;
-
- /*
- * THERM_MASK_THRESHOLD1 is 7 bits wide. Values are entered in terms
- * of milli degree celsius. Hence don't accept val > (127 * 1000)
- */
- if (val > tdata->tjmax || val > 127000)
- return -EINVAL;
-
- diff = (tdata->tjmax - val) / 1000;
-
- mutex_lock(&tdata->update_lock);
- rdmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, &eax, &edx);
- eax = (eax & ~THERM_MASK_THRESHOLD1) |
- (diff << THERM_SHIFT_THRESHOLD1);
- wrmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, eax, edx);
- tdata->ttarget = val;
- mutex_unlock(&tdata->update_lock);
-
- return count;
-}
-
-static ssize_t show_tmin(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct platform_data *pdata = dev_get_drvdata(dev);
-
- return sprintf(buf, "%d\n", pdata->core_data[attr->index]->tmin);
-}
-
-static ssize_t store_tmin(struct device *dev,
- struct device_attribute *devattr,
- const char *buf, size_t count)
-{
- struct platform_data *pdata = dev_get_drvdata(dev);
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct temp_data *tdata = pdata->core_data[attr->index];
- u32 eax, edx;
- unsigned long val;
- int diff;
-
- if (strict_strtoul(buf, 10, &val))
- return -EINVAL;
-
- /*
- * THERM_MASK_THRESHOLD0 is 7 bits wide. Values are entered in terms
- * of milli degree celsius. Hence don't accept val > (127 * 1000)
- */
- if (val > tdata->tjmax || val > 127000)
- return -EINVAL;
-
- diff = (tdata->tjmax - val) / 1000;
-
- mutex_lock(&tdata->update_lock);
- rdmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, &eax, &edx);
- eax = (eax & ~THERM_MASK_THRESHOLD0) |
- (diff << THERM_SHIFT_THRESHOLD0);
- wrmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, eax, edx);
- tdata->tmin = val;
- mutex_unlock(&tdata->update_lock);
-
- return count;
-}
-
static ssize_t show_temp(struct device *dev,
struct device_attribute *devattr, char *buf)
{
@@ -374,7 +288,6 @@ static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
{
- /* The 100C is default for both mobile and non mobile CPUs */
int err;
u32 eax, edx;
u32 val;
@@ -385,7 +298,8 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
*/
err = rdmsr_safe_on_cpu(id, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
if (err) {
- dev_warn(dev, "Unable to read TjMax from CPU.\n");
+ if (c->x86_model > 0xe && c->x86_model != 0x1c)
+ dev_warn(dev, "Unable to read TjMax from CPU %u\n", id);
} else {
val = (eax >> 16) & 0xff;
/*
@@ -393,11 +307,17 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
* will be used
*/
if (val) {
- dev_info(dev, "TjMax is %d C.\n", val);
+ dev_dbg(dev, "TjMax is %d degrees C\n", val);
return val * 1000;
}
}
+ if (force_tjmax) {
+ dev_notice(dev, "TjMax forced to %d degrees C by user\n",
+ force_tjmax);
+ return force_tjmax * 1000;
+ }
+
/*
* An assumption is made for early CPUs and unreadable MSR.
* NOTE: the calculated value may not be correct.
@@ -414,21 +334,6 @@ static void __devinit get_ucode_rev_on_cpu(void *edx)
rdmsr(MSR_IA32_UCODE_REV, eax, *(u32 *)edx);
}
-static int get_pkg_tjmax(unsigned int cpu, struct device *dev)
-{
- int err;
- u32 eax, edx, val;
-
- err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
- if (!err) {
- val = (eax >> 16) & 0xff;
- if (val)
- return val * 1000;
- }
- dev_warn(dev, "Unable to read Pkg-TjMax from CPU:%u\n", cpu);
- return 100000; /* Default TjMax: 100 degree celsius */
-}
-
static int create_name_attr(struct platform_data *pdata, struct device *dev)
{
sysfs_attr_init(&pdata->name_attr.attr);
@@ -442,19 +347,14 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev,
int attr_no)
{
int err, i;
- static ssize_t (*rd_ptr[TOTAL_ATTRS]) (struct device *dev,
+ static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev,
struct device_attribute *devattr, char *buf) = {
show_label, show_crit_alarm, show_temp, show_tjmax,
- show_max_alarm, show_ttarget, show_tmin };
- static ssize_t (*rw_ptr[TOTAL_ATTRS]) (struct device *dev,
- struct device_attribute *devattr, const char *buf,
- size_t count) = { NULL, NULL, NULL, NULL, NULL,
- store_ttarget, store_tmin };
- static const char *names[TOTAL_ATTRS] = {
+ show_ttarget };
+ static const char *const names[TOTAL_ATTRS] = {
"temp%d_label", "temp%d_crit_alarm",
"temp%d_input", "temp%d_crit",
- "temp%d_max_alarm", "temp%d_max",
- "temp%d_max_hyst" };
+ "temp%d_max" };
for (i = 0; i < tdata->attr_size; i++) {
snprintf(tdata->attr_name[i], CORETEMP_NAME_LENGTH, names[i],
@@ -462,10 +362,6 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev,
sysfs_attr_init(&tdata->sd_attrs[i].dev_attr.attr);
tdata->sd_attrs[i].dev_attr.attr.name = tdata->attr_name[i];
tdata->sd_attrs[i].dev_attr.attr.mode = S_IRUGO;
- if (rw_ptr[i]) {
- tdata->sd_attrs[i].dev_attr.attr.mode |= S_IWUSR;
- tdata->sd_attrs[i].dev_attr.store = rw_ptr[i];
- }
tdata->sd_attrs[i].dev_attr.show = rd_ptr[i];
tdata->sd_attrs[i].index = attr_no;
err = device_create_file(dev, &tdata->sd_attrs[i].dev_attr);
@@ -481,9 +377,9 @@ exit_free:
}
-static int __devinit chk_ucode_version(struct platform_device *pdev)
+static int __cpuinit chk_ucode_version(unsigned int cpu)
{
- struct cpuinfo_x86 *c = &cpu_data(pdev->id);
+ struct cpuinfo_x86 *c = &cpu_data(cpu);
int err;
u32 edx;
@@ -494,17 +390,15 @@ static int __devinit chk_ucode_version(struct platform_device *pdev)
*/
if (c->x86_model == 0xe && c->x86_mask < 0xc) {
/* check for microcode update */
- err = smp_call_function_single(pdev->id, get_ucode_rev_on_cpu,
+ err = smp_call_function_single(cpu, get_ucode_rev_on_cpu,
&edx, 1);
if (err) {
- dev_err(&pdev->dev,
- "Cannot determine microcode revision of "
- "CPU#%u (%d)!\n", pdev->id, err);
+ pr_err("Cannot determine microcode revision of "
+ "CPU#%u (%d)!\n", cpu, err);
return -ENODEV;
} else if (edx < 0x39) {
- dev_err(&pdev->dev,
- "Errata AE18 not fixed, update BIOS or "
- "microcode of the CPU!\n");
+ pr_err("Errata AE18 not fixed, update BIOS or "
+ "microcode of the CPU!\n");
return -ENODEV;
}
}
@@ -538,8 +432,6 @@ static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag)
tdata->status_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_STATUS :
MSR_IA32_THERM_STATUS;
- tdata->intrpt_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_INTERRUPT :
- MSR_IA32_THERM_INTERRUPT;
tdata->is_pkg_data = pkg_flag;
tdata->cpu = cpu;
tdata->cpu_core_id = TO_CORE_ID(cpu);
@@ -548,11 +440,11 @@ static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag)
return tdata;
}
-static int create_core_data(struct platform_data *pdata,
- struct platform_device *pdev,
+static int create_core_data(struct platform_device *pdev,
unsigned int cpu, int pkg_flag)
{
struct temp_data *tdata;
+ struct platform_data *pdata = platform_get_drvdata(pdev);
struct cpuinfo_x86 *c = &cpu_data(cpu);
u32 eax, edx;
int err, attr_no;
@@ -588,20 +480,21 @@ static int create_core_data(struct platform_data *pdata,
goto exit_free;
/* We can access status register. Get Critical Temperature */
- if (pkg_flag)
- tdata->tjmax = get_pkg_tjmax(pdev->id, &pdev->dev);
- else
- tdata->tjmax = get_tjmax(c, cpu, &pdev->dev);
+ tdata->tjmax = get_tjmax(c, cpu, &pdev->dev);
/*
- * Test if we can access the intrpt register. If so, increase the
- * 'size' enough to have ttarget/tmin/max_alarm interfaces.
- * Initialize ttarget with bits 16:22 of MSR_IA32_THERM_INTERRUPT
+ * Read the still undocumented bits 8:15 of IA32_TEMPERATURE_TARGET.
+ * The target temperature is available on older CPUs but not in this
+ * register. Atoms don't have the register at all.
*/
- err = rdmsr_safe_on_cpu(cpu, tdata->intrpt_reg, &eax, &edx);
- if (!err) {
- tdata->attr_size += MAX_THRESH_ATTRS;
- tdata->ttarget = tdata->tjmax - ((eax >> 16) & 0x7f) * 1000;
+ if (c->x86_model > 0xe && c->x86_model != 0x1c) {
+ err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET,
+ &eax, &edx);
+ if (!err) {
+ tdata->ttarget
+ = tdata->tjmax - ((eax >> 8) & 0xff) * 1000;
+ tdata->attr_size++;
+ }
}
pdata->core_data[attr_no] = tdata;
@@ -613,22 +506,20 @@ static int create_core_data(struct platform_data *pdata,
return 0;
exit_free:
+ pdata->core_data[attr_no] = NULL;
kfree(tdata);
return err;
}
static void coretemp_add_core(unsigned int cpu, int pkg_flag)
{
- struct platform_data *pdata;
struct platform_device *pdev = coretemp_get_pdev(cpu);
int err;
if (!pdev)
return;
- pdata = platform_get_drvdata(pdev);
-
- err = create_core_data(pdata, pdev, cpu, pkg_flag);
+ err = create_core_data(pdev, cpu, pkg_flag);
if (err)
dev_err(&pdev->dev, "Adding Core %u failed\n", cpu);
}
@@ -652,11 +543,6 @@ static int __devinit coretemp_probe(struct platform_device *pdev)
struct platform_data *pdata;
int err;
- /* Check the microcode version of the CPU */
- err = chk_ucode_version(pdev);
- if (err)
- return err;
-
/* Initialize the per-package data structures */
pdata = kzalloc(sizeof(struct platform_data), GFP_KERNEL);
if (!pdata)
@@ -666,7 +552,7 @@ static int __devinit coretemp_probe(struct platform_device *pdev)
if (err)
goto exit_free;
- pdata->phys_proc_id = TO_PHYS_ID(pdev->id);
+ pdata->phys_proc_id = pdev->id;
platform_set_drvdata(pdev, pdata);
pdata->hwmon_dev = hwmon_device_register(&pdev->dev);
@@ -718,7 +604,7 @@ static int __cpuinit coretemp_device_add(unsigned int cpu)
mutex_lock(&pdev_list_mutex);
- pdev = platform_device_alloc(DRVNAME, cpu);
+ pdev = platform_device_alloc(DRVNAME, TO_PHYS_ID(cpu));
if (!pdev) {
err = -ENOMEM;
pr_err("Device allocation failed\n");
@@ -738,7 +624,7 @@ static int __cpuinit coretemp_device_add(unsigned int cpu)
}
pdev_entry->pdev = pdev;
- pdev_entry->phys_proc_id = TO_PHYS_ID(cpu);
+ pdev_entry->phys_proc_id = pdev->id;
list_add_tail(&pdev_entry->list, &pdev_list);
mutex_unlock(&pdev_list_mutex);
@@ -799,6 +685,10 @@ static void __cpuinit get_core_online(unsigned int cpu)
return;
if (!pdev) {
+ /* Check the microcode version of the CPU */
+ if (chk_ucode_version(cpu))
+ return;
+
/*
* Alright, we have DTS support.
* We are bringing the _first_ core in this pkg
diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c
index 257957c69d92..4f7c3fc40a89 100644
--- a/drivers/hwmon/ds620.c
+++ b/drivers/hwmon/ds620.c
@@ -72,7 +72,7 @@ struct ds620_data {
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
- u16 temp[3]; /* Register values, word */
+ s16 temp[3]; /* Register values, word */
};
/*
diff --git a/drivers/hwmon/exynos4_tmu.c b/drivers/hwmon/exynos4_tmu.c
new file mode 100644
index 000000000000..faa0884f61f6
--- /dev/null
+++ b/drivers/hwmon/exynos4_tmu.c
@@ -0,0 +1,524 @@
+/*
+ * exynos4_tmu.c - Samsung EXYNOS4 TMU (Thermal Management Unit)
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * Donggeun Kim <dg77.kim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/workqueue.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#include <linux/platform_data/exynos4_tmu.h>
+
+#define EXYNOS4_TMU_REG_TRIMINFO 0x0
+#define EXYNOS4_TMU_REG_CONTROL 0x20
+#define EXYNOS4_TMU_REG_STATUS 0x28
+#define EXYNOS4_TMU_REG_CURRENT_TEMP 0x40
+#define EXYNOS4_TMU_REG_THRESHOLD_TEMP 0x44
+#define EXYNOS4_TMU_REG_TRIG_LEVEL0 0x50
+#define EXYNOS4_TMU_REG_TRIG_LEVEL1 0x54
+#define EXYNOS4_TMU_REG_TRIG_LEVEL2 0x58
+#define EXYNOS4_TMU_REG_TRIG_LEVEL3 0x5C
+#define EXYNOS4_TMU_REG_PAST_TEMP0 0x60
+#define EXYNOS4_TMU_REG_PAST_TEMP1 0x64
+#define EXYNOS4_TMU_REG_PAST_TEMP2 0x68
+#define EXYNOS4_TMU_REG_PAST_TEMP3 0x6C
+#define EXYNOS4_TMU_REG_INTEN 0x70
+#define EXYNOS4_TMU_REG_INTSTAT 0x74
+#define EXYNOS4_TMU_REG_INTCLEAR 0x78
+
+#define EXYNOS4_TMU_GAIN_SHIFT 8
+#define EXYNOS4_TMU_REF_VOLTAGE_SHIFT 24
+
+#define EXYNOS4_TMU_TRIM_TEMP_MASK 0xff
+#define EXYNOS4_TMU_CORE_ON 3
+#define EXYNOS4_TMU_CORE_OFF 2
+#define EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET 50
+#define EXYNOS4_TMU_TRIG_LEVEL0_MASK 0x1
+#define EXYNOS4_TMU_TRIG_LEVEL1_MASK 0x10
+#define EXYNOS4_TMU_TRIG_LEVEL2_MASK 0x100
+#define EXYNOS4_TMU_TRIG_LEVEL3_MASK 0x1000
+#define EXYNOS4_TMU_INTCLEAR_VAL 0x1111
+
+struct exynos4_tmu_data {
+ struct exynos4_tmu_platform_data *pdata;
+ struct device *hwmon_dev;
+ struct resource *mem;
+ void __iomem *base;
+ int irq;
+ struct work_struct irq_work;
+ struct mutex lock;
+ struct clk *clk;
+ u8 temp_error1, temp_error2;
+};
+
+/*
+ * TMU treats temperature as a mapped temperature code.
+ * The temperature is converted differently depending on the calibration type.
+ */
+static int temp_to_code(struct exynos4_tmu_data *data, u8 temp)
+{
+ struct exynos4_tmu_platform_data *pdata = data->pdata;
+ int temp_code;
+
+ /* temp should range between 25 and 125 */
+ if (temp < 25 || temp > 125) {
+ temp_code = -EINVAL;
+ goto out;
+ }
+
+ switch (pdata->cal_type) {
+ case TYPE_TWO_POINT_TRIMMING:
+ temp_code = (temp - 25) *
+ (data->temp_error2 - data->temp_error1) /
+ (85 - 25) + data->temp_error1;
+ break;
+ case TYPE_ONE_POINT_TRIMMING:
+ temp_code = temp + data->temp_error1 - 25;
+ break;
+ default:
+ temp_code = temp + EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET;
+ break;
+ }
+out:
+ return temp_code;
+}
+
+/*
+ * Calculate a temperature value from a temperature code.
+ * The unit of the temperature is degree Celsius.
+ */
+static int code_to_temp(struct exynos4_tmu_data *data, u8 temp_code)
+{
+ struct exynos4_tmu_platform_data *pdata = data->pdata;
+ int temp;
+
+ /* temp_code should range between 75 and 175 */
+ if (temp_code < 75 || temp_code > 175) {
+ temp = -ENODATA;
+ goto out;
+ }
+
+ switch (pdata->cal_type) {
+ case TYPE_TWO_POINT_TRIMMING:
+ temp = (temp_code - data->temp_error1) * (85 - 25) /
+ (data->temp_error2 - data->temp_error1) + 25;
+ break;
+ case TYPE_ONE_POINT_TRIMMING:
+ temp = temp_code - data->temp_error1 + 25;
+ break;
+ default:
+ temp = temp_code - EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET;
+ break;
+ }
+out:
+ return temp;
+}
+
+static int exynos4_tmu_initialize(struct platform_device *pdev)
+{
+ struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
+ struct exynos4_tmu_platform_data *pdata = data->pdata;
+ unsigned int status, trim_info;
+ int ret = 0, threshold_code;
+
+ mutex_lock(&data->lock);
+ clk_enable(data->clk);
+
+ status = readb(data->base + EXYNOS4_TMU_REG_STATUS);
+ if (!status) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* Save trimming info in order to perform calibration */
+ trim_info = readl(data->base + EXYNOS4_TMU_REG_TRIMINFO);
+ data->temp_error1 = trim_info & EXYNOS4_TMU_TRIM_TEMP_MASK;
+ data->temp_error2 = ((trim_info >> 8) & EXYNOS4_TMU_TRIM_TEMP_MASK);
+
+ /* Write temperature code for threshold */
+ threshold_code = temp_to_code(data, pdata->threshold);
+ if (threshold_code < 0) {
+ ret = threshold_code;
+ goto out;
+ }
+ writeb(threshold_code,
+ data->base + EXYNOS4_TMU_REG_THRESHOLD_TEMP);
+
+ writeb(pdata->trigger_levels[0],
+ data->base + EXYNOS4_TMU_REG_TRIG_LEVEL0);
+ writeb(pdata->trigger_levels[1],
+ data->base + EXYNOS4_TMU_REG_TRIG_LEVEL1);
+ writeb(pdata->trigger_levels[2],
+ data->base + EXYNOS4_TMU_REG_TRIG_LEVEL2);
+ writeb(pdata->trigger_levels[3],
+ data->base + EXYNOS4_TMU_REG_TRIG_LEVEL3);
+
+ writel(EXYNOS4_TMU_INTCLEAR_VAL,
+ data->base + EXYNOS4_TMU_REG_INTCLEAR);
+out:
+ clk_disable(data->clk);
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+
+static void exynos4_tmu_control(struct platform_device *pdev, bool on)
+{
+ struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
+ struct exynos4_tmu_platform_data *pdata = data->pdata;
+ unsigned int con, interrupt_en;
+
+ mutex_lock(&data->lock);
+ clk_enable(data->clk);
+
+ con = pdata->reference_voltage << EXYNOS4_TMU_REF_VOLTAGE_SHIFT |
+ pdata->gain << EXYNOS4_TMU_GAIN_SHIFT;
+ if (on) {
+ con |= EXYNOS4_TMU_CORE_ON;
+ interrupt_en = pdata->trigger_level3_en << 12 |
+ pdata->trigger_level2_en << 8 |
+ pdata->trigger_level1_en << 4 |
+ pdata->trigger_level0_en;
+ } else {
+ con |= EXYNOS4_TMU_CORE_OFF;
+ interrupt_en = 0; /* Disable all interrupts */
+ }
+ writel(interrupt_en, data->base + EXYNOS4_TMU_REG_INTEN);
+ writel(con, data->base + EXYNOS4_TMU_REG_CONTROL);
+
+ clk_disable(data->clk);
+ mutex_unlock(&data->lock);
+}
+
+static int exynos4_tmu_read(struct exynos4_tmu_data *data)
+{
+ u8 temp_code;
+ int temp;
+
+ mutex_lock(&data->lock);
+ clk_enable(data->clk);
+
+ temp_code = readb(data->base + EXYNOS4_TMU_REG_CURRENT_TEMP);
+ temp = code_to_temp(data, temp_code);
+
+ clk_disable(data->clk);
+ mutex_unlock(&data->lock);
+
+ return temp;
+}
+
+static void exynos4_tmu_work(struct work_struct *work)
+{
+ struct exynos4_tmu_data *data = container_of(work,
+ struct exynos4_tmu_data, irq_work);
+
+ mutex_lock(&data->lock);
+ clk_enable(data->clk);
+
+ writel(EXYNOS4_TMU_INTCLEAR_VAL, data->base + EXYNOS4_TMU_REG_INTCLEAR);
+
+ kobject_uevent(&data->hwmon_dev->kobj, KOBJ_CHANGE);
+
+ enable_irq(data->irq);
+
+ clk_disable(data->clk);
+ mutex_unlock(&data->lock);
+}
+
+static irqreturn_t exynos4_tmu_irq(int irq, void *id)
+{
+ struct exynos4_tmu_data *data = id;
+
+ disable_irq_nosync(irq);
+ schedule_work(&data->irq_work);
+
+ return IRQ_HANDLED;
+}
+
+static ssize_t exynos4_tmu_show_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "exynos4-tmu\n");
+}
+
+static ssize_t exynos4_tmu_show_temp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct exynos4_tmu_data *data = dev_get_drvdata(dev);
+ int ret;
+
+ ret = exynos4_tmu_read(data);
+ if (ret < 0)
+ return ret;
+
+ /* convert from degree Celsius to millidegree Celsius */
+ return sprintf(buf, "%d\n", ret * 1000);
+}
+
+static ssize_t exynos4_tmu_show_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct exynos4_tmu_data *data = dev_get_drvdata(dev);
+ struct exynos4_tmu_platform_data *pdata = data->pdata;
+ int temp;
+ unsigned int trigger_level;
+
+ temp = exynos4_tmu_read(data);
+ if (temp < 0)
+ return temp;
+
+ trigger_level = pdata->threshold + pdata->trigger_levels[attr->index];
+
+ return sprintf(buf, "%d\n", !!(temp > trigger_level));
+}
+
+static ssize_t exynos4_tmu_show_level(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct exynos4_tmu_data *data = dev_get_drvdata(dev);
+ struct exynos4_tmu_platform_data *pdata = data->pdata;
+ unsigned int temp = pdata->threshold +
+ pdata->trigger_levels[attr->index];
+
+ return sprintf(buf, "%u\n", temp * 1000);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, exynos4_tmu_show_name, NULL);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, exynos4_tmu_show_temp, NULL, 0);
+
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO,
+ exynos4_tmu_show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO,
+ exynos4_tmu_show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp1_emergency_alarm, S_IRUGO,
+ exynos4_tmu_show_alarm, NULL, 3);
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, exynos4_tmu_show_level, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, exynos4_tmu_show_level, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp1_emergency, S_IRUGO,
+ exynos4_tmu_show_level, NULL, 3);
+
+static struct attribute *exynos4_tmu_attributes[] = {
+ &dev_attr_name.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_emergency_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_emergency.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group exynos4_tmu_attr_group = {
+ .attrs = exynos4_tmu_attributes,
+};
+
+static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
+{
+ struct exynos4_tmu_data *data;
+ struct exynos4_tmu_platform_data *pdata = pdev->dev.platform_data;
+ int ret;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform init data supplied.\n");
+ return -ENODEV;
+ }
+
+ data = kzalloc(sizeof(struct exynos4_tmu_data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&pdev->dev, "Failed to allocate driver structure\n");
+ return -ENOMEM;
+ }
+
+ data->irq = platform_get_irq(pdev, 0);
+ if (data->irq < 0) {
+ ret = data->irq;
+ dev_err(&pdev->dev, "Failed to get platform irq\n");
+ goto err_free;
+ }
+
+ INIT_WORK(&data->irq_work, exynos4_tmu_work);
+
+ data->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!data->mem) {
+ ret = -ENOENT;
+ dev_err(&pdev->dev, "Failed to get platform resource\n");
+ goto err_free;
+ }
+
+ data->mem = request_mem_region(data->mem->start,
+ resource_size(data->mem), pdev->name);
+ if (!data->mem) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "Failed to request memory region\n");
+ goto err_free;
+ }
+
+ data->base = ioremap(data->mem->start, resource_size(data->mem));
+ if (!data->base) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "Failed to ioremap memory\n");
+ goto err_mem_region;
+ }
+
+ ret = request_irq(data->irq, exynos4_tmu_irq,
+ IRQF_TRIGGER_RISING,
+ "exynos4-tmu", data);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
+ goto err_io_remap;
+ }
+
+ data->clk = clk_get(NULL, "tmu_apbif");
+ if (IS_ERR(data->clk)) {
+ ret = PTR_ERR(data->clk);
+ dev_err(&pdev->dev, "Failed to get clock\n");
+ goto err_irq;
+ }
+
+ data->pdata = pdata;
+ platform_set_drvdata(pdev, data);
+ mutex_init(&data->lock);
+
+ ret = exynos4_tmu_initialize(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to initialize TMU\n");
+ goto err_clk;
+ }
+
+ ret = sysfs_create_group(&pdev->dev.kobj, &exynos4_tmu_attr_group);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to create sysfs group\n");
+ goto err_clk;
+ }
+
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ ret = PTR_ERR(data->hwmon_dev);
+ dev_err(&pdev->dev, "Failed to register hwmon device\n");
+ goto err_create_group;
+ }
+
+ exynos4_tmu_control(pdev, true);
+
+ return 0;
+
+err_create_group:
+ sysfs_remove_group(&pdev->dev.kobj, &exynos4_tmu_attr_group);
+err_clk:
+ platform_set_drvdata(pdev, NULL);
+ clk_put(data->clk);
+err_irq:
+ free_irq(data->irq, data);
+err_io_remap:
+ iounmap(data->base);
+err_mem_region:
+ release_mem_region(data->mem->start, resource_size(data->mem));
+err_free:
+ kfree(data);
+
+ return ret;
+}
+
+static int __devexit exynos4_tmu_remove(struct platform_device *pdev)
+{
+ struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
+
+ exynos4_tmu_control(pdev, false);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&pdev->dev.kobj, &exynos4_tmu_attr_group);
+
+ clk_put(data->clk);
+
+ free_irq(data->irq, data);
+
+ iounmap(data->base);
+ release_mem_region(data->mem->start, resource_size(data->mem));
+
+ platform_set_drvdata(pdev, NULL);
+
+ kfree(data);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int exynos4_tmu_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ exynos4_tmu_control(pdev, false);
+
+ return 0;
+}
+
+static int exynos4_tmu_resume(struct platform_device *pdev)
+{
+ exynos4_tmu_initialize(pdev);
+ exynos4_tmu_control(pdev, true);
+
+ return 0;
+}
+#else
+#define exynos4_tmu_suspend NULL
+#define exynos4_tmu_resume NULL
+#endif
+
+static struct platform_driver exynos4_tmu_driver = {
+ .driver = {
+ .name = "exynos4-tmu",
+ .owner = THIS_MODULE,
+ },
+ .probe = exynos4_tmu_probe,
+ .remove = __devexit_p(exynos4_tmu_remove),
+ .suspend = exynos4_tmu_suspend,
+ .resume = exynos4_tmu_resume,
+};
+
+static int __init exynos4_tmu_driver_init(void)
+{
+ return platform_driver_register(&exynos4_tmu_driver);
+}
+module_init(exynos4_tmu_driver_init);
+
+static void __exit exynos4_tmu_driver_exit(void)
+{
+ platform_driver_unregister(&exynos4_tmu_driver);
+}
+module_exit(exynos4_tmu_driver_exit);
+
+MODULE_DESCRIPTION("EXYNOS4 TMU Driver");
+MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:exynos4-tmu");
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
index 2d96ed2bf8ed..59dd881c71d8 100644
--- a/drivers/hwmon/f71882fg.c
+++ b/drivers/hwmon/f71882fg.c
@@ -605,7 +605,7 @@ static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
/* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
standard models */
-static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
+static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[3][7] = { {
SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
show_pwm_auto_point_channel,
store_pwm_auto_point_channel, 0, 0),
@@ -627,7 +627,7 @@ static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
0, 0),
SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
show_pwm_auto_point_temp_hyst, NULL, 3, 0),
-
+}, {
SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
show_pwm_auto_point_channel,
store_pwm_auto_point_channel, 0, 1),
@@ -649,7 +649,7 @@ static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
0, 1),
SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
show_pwm_auto_point_temp_hyst, NULL, 3, 1),
-
+}, {
SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
show_pwm_auto_point_channel,
store_pwm_auto_point_channel, 0, 2),
@@ -671,12 +671,12 @@ static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
0, 2),
SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
show_pwm_auto_point_temp_hyst, NULL, 3, 2),
-};
+} };
/* PWM attr for the f71808e/f71869, almost identical to the f71862fg, but the
pwm setting when the temperature is above the pwmX_auto_point1_temp can be
programmed instead of being hardcoded to 0xff */
-static struct sensor_device_attribute_2 f71869_auto_pwm_attr[] = {
+static struct sensor_device_attribute_2 f71869_auto_pwm_attr[3][8] = { {
SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
show_pwm_auto_point_channel,
store_pwm_auto_point_channel, 0, 0),
@@ -701,7 +701,7 @@ static struct sensor_device_attribute_2 f71869_auto_pwm_attr[] = {
0, 0),
SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
show_pwm_auto_point_temp_hyst, NULL, 3, 0),
-
+}, {
SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
show_pwm_auto_point_channel,
store_pwm_auto_point_channel, 0, 1),
@@ -726,7 +726,7 @@ static struct sensor_device_attribute_2 f71869_auto_pwm_attr[] = {
0, 1),
SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
show_pwm_auto_point_temp_hyst, NULL, 3, 1),
-
+}, {
SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
show_pwm_auto_point_channel,
store_pwm_auto_point_channel, 0, 2),
@@ -751,7 +751,7 @@ static struct sensor_device_attribute_2 f71869_auto_pwm_attr[] = {
0, 2),
SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
show_pwm_auto_point_temp_hyst, NULL, 3, 2),
-};
+} };
/* PWM attr for the standard models */
static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { {
@@ -928,7 +928,7 @@ static struct sensor_device_attribute_2 f8000_fan_attr[] = {
/* PWM attr for the f8000, zones mapped to temp instead of to pwm!
Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
-static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = {
+static struct sensor_device_attribute_2 f8000_auto_pwm_attr[3][14] = { {
SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
show_pwm_auto_point_channel,
store_pwm_auto_point_channel, 0, 0),
@@ -969,7 +969,7 @@ static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = {
show_pwm_auto_point_temp_hyst, NULL, 2, 2),
SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
show_pwm_auto_point_temp_hyst, NULL, 3, 2),
-
+}, {
SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
show_pwm_auto_point_channel,
store_pwm_auto_point_channel, 0, 1),
@@ -1010,7 +1010,7 @@ static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = {
show_pwm_auto_point_temp_hyst, NULL, 2, 0),
SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
show_pwm_auto_point_temp_hyst, NULL, 3, 0),
-
+}, {
SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
show_pwm_auto_point_channel,
store_pwm_auto_point_channel, 0, 2),
@@ -1051,7 +1051,7 @@ static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = {
show_pwm_auto_point_temp_hyst, NULL, 2, 1),
SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
show_pwm_auto_point_temp_hyst, NULL, 3, 1),
-};
+} };
/* Super I/O functions */
static inline int superio_inb(int base, int reg)
@@ -2154,6 +2154,104 @@ static void f71882fg_remove_sysfs_files(struct platform_device *pdev,
device_remove_file(&pdev->dev, &attr[i].dev_attr);
}
+static int __devinit f71882fg_create_fan_sysfs_files(
+ struct platform_device *pdev, int idx)
+{
+ struct f71882fg_data *data = platform_get_drvdata(pdev);
+ int err;
+
+ /* Sanity check the pwm setting */
+ err = 0;
+ switch (data->type) {
+ case f71858fg:
+ if (((data->pwm_enable >> (idx * 2)) & 3) == 3)
+ err = 1;
+ break;
+ case f71862fg:
+ if (((data->pwm_enable >> (idx * 2)) & 1) != 1)
+ err = 1;
+ break;
+ case f8000:
+ if (idx == 2)
+ err = data->pwm_enable & 0x20;
+ break;
+ default:
+ break;
+ }
+ if (err) {
+ dev_err(&pdev->dev,
+ "Invalid (reserved) pwm settings: 0x%02x, "
+ "skipping fan %d\n",
+ (data->pwm_enable >> (idx * 2)) & 3, idx + 1);
+ return 0; /* This is a non fatal condition */
+ }
+
+ err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[idx][0],
+ ARRAY_SIZE(fxxxx_fan_attr[0]));
+ if (err)
+ return err;
+
+ if (f71882fg_fan_has_beep[data->type]) {
+ err = f71882fg_create_sysfs_files(pdev,
+ &fxxxx_fan_beep_attr[idx],
+ 1);
+ if (err)
+ return err;
+ }
+
+ dev_info(&pdev->dev, "Fan: %d is in %s mode\n", idx + 1,
+ (data->pwm_enable & (1 << (2 * idx))) ? "duty-cycle" : "RPM");
+
+ /* Check for unsupported auto pwm settings */
+ switch (data->type) {
+ case f71808e:
+ case f71808a:
+ case f71869:
+ case f71869a:
+ case f71889fg:
+ case f71889ed:
+ case f71889a:
+ data->pwm_auto_point_mapping[idx] =
+ f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(idx));
+ if ((data->pwm_auto_point_mapping[idx] & 0x80) ||
+ (data->pwm_auto_point_mapping[idx] & 3) == 0) {
+ dev_warn(&pdev->dev,
+ "Auto pwm controlled by raw digital "
+ "data, disabling pwm auto_point "
+ "sysfs attributes for fan %d\n", idx + 1);
+ return 0; /* This is a non fatal condition */
+ }
+ break;
+ default:
+ break;
+ }
+
+ switch (data->type) {
+ case f71862fg:
+ err = f71882fg_create_sysfs_files(pdev,
+ &f71862fg_auto_pwm_attr[idx][0],
+ ARRAY_SIZE(f71862fg_auto_pwm_attr[0]));
+ break;
+ case f71808e:
+ case f71869:
+ err = f71882fg_create_sysfs_files(pdev,
+ &f71869_auto_pwm_attr[idx][0],
+ ARRAY_SIZE(f71869_auto_pwm_attr[0]));
+ break;
+ case f8000:
+ err = f71882fg_create_sysfs_files(pdev,
+ &f8000_auto_pwm_attr[idx][0],
+ ARRAY_SIZE(f8000_auto_pwm_attr[0]));
+ break;
+ default:
+ err = f71882fg_create_sysfs_files(pdev,
+ &fxxxx_auto_pwm_attr[idx][0],
+ ARRAY_SIZE(fxxxx_auto_pwm_attr[0]));
+ }
+
+ return err;
+}
+
static int __devinit f71882fg_probe(struct platform_device *pdev)
{
struct f71882fg_data *data;
@@ -2272,117 +2370,29 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
data->pwm_enable =
f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
- /* Sanity check the pwm settings */
- switch (data->type) {
- case f71858fg:
- err = 0;
- for (i = 0; i < nr_fans; i++)
- if (((data->pwm_enable >> (i * 2)) & 3) == 3)
- err = 1;
- break;
- case f71862fg:
- err = (data->pwm_enable & 0x15) != 0x15;
- break;
- case f8000:
- err = data->pwm_enable & 0x20;
- break;
- default:
- err = 0;
- break;
- }
- if (err) {
- dev_err(&pdev->dev,
- "Invalid (reserved) pwm settings: 0x%02x\n",
- (unsigned int)data->pwm_enable);
- err = -ENODEV;
- goto exit_unregister_sysfs;
- }
-
- err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
- ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
- if (err)
- goto exit_unregister_sysfs;
-
- if (f71882fg_fan_has_beep[data->type]) {
- err = f71882fg_create_sysfs_files(pdev,
- fxxxx_fan_beep_attr, nr_fans);
+ for (i = 0; i < nr_fans; i++) {
+ err = f71882fg_create_fan_sysfs_files(pdev, i);
if (err)
goto exit_unregister_sysfs;
}
- switch (data->type) {
- case f71808e:
- case f71808a:
- case f71869:
- case f71869a:
- case f71889fg:
- case f71889ed:
- case f71889a:
- for (i = 0; i < nr_fans; i++) {
- data->pwm_auto_point_mapping[i] =
- f71882fg_read8(data,
- F71882FG_REG_POINT_MAPPING(i));
- if ((data->pwm_auto_point_mapping[i] & 0x80) ||
- (data->pwm_auto_point_mapping[i] & 3) == 0)
- break;
- }
- if (i != nr_fans) {
- dev_warn(&pdev->dev,
- "Auto pwm controlled by raw digital "
- "data, disabling pwm auto_point "
- "sysfs attributes\n");
- goto no_pwm_auto_point;
- }
- break;
- default:
- break;
- }
-
+ /* Some types have 1 extra fan with limited functionality */
switch (data->type) {
case f71808a:
err = f71882fg_create_sysfs_files(pdev,
- &fxxxx_auto_pwm_attr[0][0],
- ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
- if (err)
- goto exit_unregister_sysfs;
- err = f71882fg_create_sysfs_files(pdev,
f71808a_fan3_attr,
ARRAY_SIZE(f71808a_fan3_attr));
break;
- case f71862fg:
- err = f71882fg_create_sysfs_files(pdev,
- f71862fg_auto_pwm_attr,
- ARRAY_SIZE(f71862fg_auto_pwm_attr));
- break;
- case f71808e:
- case f71869:
- err = f71882fg_create_sysfs_files(pdev,
- f71869_auto_pwm_attr,
- ARRAY_SIZE(f71869_auto_pwm_attr));
- break;
case f8000:
err = f71882fg_create_sysfs_files(pdev,
f8000_fan_attr,
ARRAY_SIZE(f8000_fan_attr));
- if (err)
- goto exit_unregister_sysfs;
- err = f71882fg_create_sysfs_files(pdev,
- f8000_auto_pwm_attr,
- ARRAY_SIZE(f8000_auto_pwm_attr));
break;
default:
- err = f71882fg_create_sysfs_files(pdev,
- &fxxxx_auto_pwm_attr[0][0],
- ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
+ break;
}
if (err)
goto exit_unregister_sysfs;
-
-no_pwm_auto_point:
- for (i = 0; i < nr_fans; i++)
- dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
- (data->pwm_enable & (1 << 2 * i)) ?
- "duty-cycle" : "RPM");
}
data->hwmon_dev = hwmon_device_register(&pdev->dev);
@@ -2476,22 +2486,23 @@ static int f71882fg_remove(struct platform_device *pdev)
break;
case f71862fg:
f71882fg_remove_sysfs_files(pdev,
- f71862fg_auto_pwm_attr,
- ARRAY_SIZE(f71862fg_auto_pwm_attr));
+ &f71862fg_auto_pwm_attr[0][0],
+ ARRAY_SIZE(f71862fg_auto_pwm_attr[0]) *
+ nr_fans);
break;
case f71808e:
case f71869:
f71882fg_remove_sysfs_files(pdev,
- f71869_auto_pwm_attr,
- ARRAY_SIZE(f71869_auto_pwm_attr));
+ &f71869_auto_pwm_attr[0][0],
+ ARRAY_SIZE(f71869_auto_pwm_attr[0]) * nr_fans);
break;
case f8000:
f71882fg_remove_sysfs_files(pdev,
f8000_fan_attr,
ARRAY_SIZE(f8000_fan_attr));
f71882fg_remove_sysfs_files(pdev,
- f8000_auto_pwm_attr,
- ARRAY_SIZE(f8000_auto_pwm_attr));
+ &f8000_auto_pwm_attr[0][0],
+ ARRAY_SIZE(f8000_auto_pwm_attr[0]) * nr_fans);
break;
default:
f71882fg_remove_sysfs_files(pdev,
diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c
index c4c40be0edbf..d22f241b6a67 100644
--- a/drivers/hwmon/i5k_amb.c
+++ b/drivers/hwmon/i5k_amb.c
@@ -114,7 +114,6 @@ struct i5k_amb_data {
void __iomem *amb_mmio;
struct i5k_device_attribute *attrs;
unsigned int num_attrs;
- unsigned long chipset_id;
};
static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
@@ -444,8 +443,6 @@ static int __devinit i5k_find_amb_registers(struct i5k_amb_data *data,
goto out;
}
- data->chipset_id = devid;
-
res = 0;
out:
pci_dev_put(pcidev);
@@ -478,23 +475,13 @@ out:
return res;
}
-static unsigned long i5k_channel_pci_id(struct i5k_amb_data *data,
- unsigned long channel)
-{
- switch (data->chipset_id) {
- case PCI_DEVICE_ID_INTEL_5000_ERR:
- return PCI_DEVICE_ID_INTEL_5000_FBD0 + channel;
- case PCI_DEVICE_ID_INTEL_5400_ERR:
- return PCI_DEVICE_ID_INTEL_5400_FBD0 + channel;
- default:
- BUG();
- }
-}
-
-static unsigned long chipset_ids[] = {
- PCI_DEVICE_ID_INTEL_5000_ERR,
- PCI_DEVICE_ID_INTEL_5400_ERR,
- 0
+static struct {
+ unsigned long err;
+ unsigned long fbd0;
+} chipset_ids[] __devinitdata = {
+ { PCI_DEVICE_ID_INTEL_5000_ERR, PCI_DEVICE_ID_INTEL_5000_FBD0 },
+ { PCI_DEVICE_ID_INTEL_5400_ERR, PCI_DEVICE_ID_INTEL_5400_FBD0 },
+ { 0, 0 }
};
#ifdef MODULE
@@ -510,8 +497,7 @@ static int __devinit i5k_amb_probe(struct platform_device *pdev)
{
struct i5k_amb_data *data;
struct resource *reso;
- int i;
- int res = -ENODEV;
+ int i, res;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
@@ -520,22 +506,22 @@ static int __devinit i5k_amb_probe(struct platform_device *pdev)
/* Figure out where the AMB registers live */
i = 0;
do {
- res = i5k_find_amb_registers(data, chipset_ids[i]);
+ res = i5k_find_amb_registers(data, chipset_ids[i].err);
+ if (res == 0)
+ break;
i++;
- } while (res && chipset_ids[i]);
+ } while (chipset_ids[i].err);
if (res)
goto err;
/* Copy the DIMM presence map for the first two channels */
- res = i5k_channel_probe(&data->amb_present[0],
- i5k_channel_pci_id(data, 0));
+ res = i5k_channel_probe(&data->amb_present[0], chipset_ids[i].fbd0);
if (res)
goto err;
/* Copy the DIMM presence map for the optional second two channels */
- i5k_channel_probe(&data->amb_present[2],
- i5k_channel_pci_id(data, 1));
+ i5k_channel_probe(&data->amb_present[2], chipset_ids[i].fbd0 + 1);
/* Set up resource regions */
reso = request_mem_region(data->amb_base, data->amb_len, DRVNAME);
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index ef902d5d06ab..90126a2a1e44 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -35,6 +35,7 @@
*/
enum lm75_type { /* keep sorted in alphabetical order */
+ adt75,
ds1775,
ds75,
lm75,
@@ -213,6 +214,7 @@ static int lm75_remove(struct i2c_client *client)
}
static const struct i2c_device_id lm75_ids[] = {
+ { "adt75", adt75, },
{ "ds1775", ds1775, },
{ "ds75", ds75, },
{ "lm75", lm75, },
@@ -247,19 +249,30 @@ static int lm75_detect(struct i2c_client *new_client,
I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV;
- /* Now, we do the remaining detection. There is no identification-
- dedicated register so we have to rely on several tricks:
- unused bits, registers cycling over 8-address boundaries,
- addresses 0x04-0x07 returning the last read value.
- The cycling+unused addresses combination is not tested,
- since it would significantly slow the detection down and would
- hardly add any value.
-
- The National Semiconductor LM75A is different than earlier
- LM75s. It has an ID byte of 0xaX (where X is the chip
- revision, with 1 being the only revision in existence) in
- register 7, and unused registers return 0xff rather than the
- last read value. */
+ /*
+ * Now, we do the remaining detection. There is no identification-
+ * dedicated register so we have to rely on several tricks:
+ * unused bits, registers cycling over 8-address boundaries,
+ * addresses 0x04-0x07 returning the last read value.
+ * The cycling+unused addresses combination is not tested,
+ * since it would significantly slow the detection down and would
+ * hardly add any value.
+ *
+ * The National Semiconductor LM75A is different than earlier
+ * LM75s. It has an ID byte of 0xaX (where X is the chip
+ * revision, with 1 being the only revision in existence) in
+ * register 7, and unused registers return 0xff rather than the
+ * last read value.
+ *
+ * Note that this function only detects the original National
+ * Semiconductor LM75 and the LM75A. Clones from other vendors
+ * aren't detected, on purpose, because they are typically never
+ * found on PC hardware. They are found on embedded designs where
+ * they can be instantiated explicitly so detection is not needed.
+ * The absence of identification registers on all these clones
+ * would make their exhaustive detection very difficult and weak,
+ * and odds are that the driver would bind to unsupported devices.
+ */
/* Unused bits */
conf = i2c_smbus_read_byte_data(new_client, 1);
diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c
index d94a24fdf4ba..dd2d7b9620c2 100644
--- a/drivers/hwmon/max16065.c
+++ b/drivers/hwmon/max16065.c
@@ -124,7 +124,7 @@ static inline int MV_TO_LIMIT(int mv, int range)
static inline int ADC_TO_CURR(int adc, int gain)
{
- return adc * 1400000 / gain * 255;
+ return adc * 1400000 / (gain * 255);
}
/*
diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
index d7926f4336b5..eab11615dced 100644
--- a/drivers/hwmon/ntc_thermistor.c
+++ b/drivers/hwmon/ntc_thermistor.c
@@ -211,8 +211,7 @@ static int lookup_comp(struct ntc_data *data,
if (data->comp[mid].ohm <= ohm) {
*i_low = mid;
*i_high = mid - 1;
- }
- if (data->comp[mid].ohm > ohm) {
+ } else {
*i_low = mid + 1;
*i_high = mid;
}
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index c9237b9dcff2..4b26f51920ba 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -20,17 +20,18 @@ config SENSORS_PMBUS
help
If you say yes here you get hardware monitoring support for generic
PMBus devices, including but not limited to ADP4000, BMR450, BMR451,
- BMR453, BMR454, LTC2978, NCP4200, and NCP4208.
+ BMR453, BMR454, NCP4200, and NCP4208.
This driver can also be built as a module. If so, the module will
be called pmbus.
config SENSORS_ADM1275
- tristate "Analog Devices ADM1275"
+ tristate "Analog Devices ADM1275 and compatibles"
default n
help
If you say yes here you get hardware monitoring support for Analog
- Devices ADM1275 Hot-Swap Controller and Digital Power Monitor.
+ Devices ADM1275 and ADM1276 Hot-Swap Controller and Digital Power
+ Monitor.
This driver can also be built as a module. If so, the module will
be called adm1275.
@@ -45,6 +46,16 @@ config SENSORS_LM25066
This driver can also be built as a module. If so, the module will
be called lm25066.
+config SENSORS_LTC2978
+ tristate "Linear Technologies LTC2978 and LTC3880"
+ default n
+ help
+ If you say yes here you get hardware monitoring support for Linear
+ Technology LTC2978 and LTC3880.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc2978.
+
config SENSORS_MAX16064
tristate "Maxim MAX16064"
default n
@@ -97,4 +108,15 @@ config SENSORS_UCD9200
This driver can also be built as a module. If so, the module will
be called ucd9200.
+config SENSORS_ZL6100
+ tristate "Intersil ZL6100 and compatibles"
+ default n
+ help
+ If you say yes here you get hardware monitoring support for Intersil
+ ZL2004, ZL2006, ZL2008, ZL2105, ZL2106, ZL6100, and ZL6105 Digital
+ DC/DC Controllers.
+
+ This driver can also be built as a module. If so, the module will
+ be called zl6100.
+
endif # PMBUS
diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile
index 623eedb1ed9a..789376c85dbb 100644
--- a/drivers/hwmon/pmbus/Makefile
+++ b/drivers/hwmon/pmbus/Makefile
@@ -6,8 +6,10 @@ obj-$(CONFIG_PMBUS) += pmbus_core.o
obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o
obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o
obj-$(CONFIG_SENSORS_LM25066) += lm25066.o
+obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o
obj-$(CONFIG_SENSORS_MAX16064) += max16064.o
obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
obj-$(CONFIG_SENSORS_MAX8688) += max8688.o
obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o
obj-$(CONFIG_SENSORS_UCD9200) += ucd9200.o
+obj-$(CONFIG_SENSORS_ZL6100) += zl6100.o
diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c
index c936e2782309..980a4d9d5028 100644
--- a/drivers/hwmon/pmbus/adm1275.c
+++ b/drivers/hwmon/pmbus/adm1275.c
@@ -23,6 +23,8 @@
#include <linux/i2c.h>
#include "pmbus.h"
+enum chips { adm1275, adm1276 };
+
#define ADM1275_PEAK_IOUT 0xd0
#define ADM1275_PEAK_VIN 0xd1
#define ADM1275_PEAK_VOUT 0xd2
@@ -31,14 +33,47 @@
#define ADM1275_VIN_VOUT_SELECT (1 << 6)
#define ADM1275_VRANGE (1 << 5)
+#define ADM1275_IOUT_WARN2_LIMIT 0xd7
+#define ADM1275_DEVICE_CONFIG 0xd8
+
+#define ADM1275_IOUT_WARN2_SELECT (1 << 4)
+
+#define ADM1276_PEAK_PIN 0xda
+
+#define ADM1275_MFR_STATUS_IOUT_WARN2 (1 << 0)
+
+struct adm1275_data {
+ int id;
+ bool have_oc_fault;
+ struct pmbus_driver_info info;
+};
+
+#define to_adm1275_data(x) container_of(x, struct adm1275_data, info)
+
static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
{
- int ret;
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ const struct adm1275_data *data = to_adm1275_data(info);
+ int ret = 0;
if (page)
- return -EINVAL;
+ return -ENXIO;
switch (reg) {
+ case PMBUS_IOUT_UC_FAULT_LIMIT:
+ if (data->have_oc_fault) {
+ ret = -ENXIO;
+ break;
+ }
+ ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT);
+ break;
+ case PMBUS_IOUT_OC_FAULT_LIMIT:
+ if (!data->have_oc_fault) {
+ ret = -ENXIO;
+ break;
+ }
+ ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT);
+ break;
case PMBUS_VIRT_READ_IOUT_MAX:
ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_IOUT);
break;
@@ -48,10 +83,20 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
case PMBUS_VIRT_READ_VIN_MAX:
ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN);
break;
+ case PMBUS_VIRT_READ_PIN_MAX:
+ if (data->id != adm1276) {
+ ret = -ENXIO;
+ break;
+ }
+ ret = pmbus_read_word_data(client, 0, ADM1276_PEAK_PIN);
+ break;
case PMBUS_VIRT_RESET_IOUT_HISTORY:
case PMBUS_VIRT_RESET_VOUT_HISTORY:
case PMBUS_VIRT_RESET_VIN_HISTORY:
- ret = 0;
+ break;
+ case PMBUS_VIRT_RESET_PIN_HISTORY:
+ if (data->id != adm1276)
+ ret = -ENXIO;
break;
default:
ret = -ENODATA;
@@ -66,9 +111,14 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
int ret;
if (page)
- return -EINVAL;
+ return -ENXIO;
switch (reg) {
+ case PMBUS_IOUT_UC_FAULT_LIMIT:
+ case PMBUS_IOUT_OC_FAULT_LIMIT:
+ ret = pmbus_write_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT,
+ word);
+ break;
case PMBUS_VIRT_RESET_IOUT_HISTORY:
ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_IOUT, 0);
break;
@@ -78,6 +128,41 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
case PMBUS_VIRT_RESET_VIN_HISTORY:
ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VIN, 0);
break;
+ case PMBUS_VIRT_RESET_PIN_HISTORY:
+ ret = pmbus_write_word_data(client, 0, ADM1276_PEAK_PIN, 0);
+ break;
+ default:
+ ret = -ENODATA;
+ break;
+ }
+ return ret;
+}
+
+static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ const struct adm1275_data *data = to_adm1275_data(info);
+ int mfr_status, ret;
+
+ if (page > 0)
+ return -ENXIO;
+
+ switch (reg) {
+ case PMBUS_STATUS_IOUT:
+ ret = pmbus_read_byte_data(client, page, PMBUS_STATUS_IOUT);
+ if (ret < 0)
+ break;
+ mfr_status = pmbus_read_byte_data(client, page,
+ PMBUS_STATUS_MFR_SPECIFIC);
+ if (mfr_status < 0) {
+ ret = mfr_status;
+ break;
+ }
+ if (mfr_status & ADM1275_MFR_STATUS_IOUT_WARN2) {
+ ret |= data->have_oc_fault ?
+ PB_IOUT_OC_FAULT : PB_IOUT_UC_FAULT;
+ }
+ break;
default:
ret = -ENODATA;
break;
@@ -88,16 +173,17 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
static int adm1275_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- int config;
+ int config, device_config;
int ret;
struct pmbus_driver_info *info;
+ struct adm1275_data *data;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_BYTE_DATA))
return -ENODEV;
- info = kzalloc(sizeof(struct pmbus_driver_info), GFP_KERNEL);
- if (!info)
+ data = kzalloc(sizeof(struct adm1275_data), GFP_KERNEL);
+ if (!data)
return -ENOMEM;
config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);
@@ -106,6 +192,15 @@ static int adm1275_probe(struct i2c_client *client,
goto err_mem;
}
+ device_config = i2c_smbus_read_byte_data(client, ADM1275_DEVICE_CONFIG);
+ if (device_config < 0) {
+ ret = device_config;
+ goto err_mem;
+ }
+
+ data->id = id->driver_data;
+ info = &data->info;
+
info->pages = 1;
info->format[PSC_VOLTAGE_IN] = direct;
info->format[PSC_VOLTAGE_OUT] = direct;
@@ -116,6 +211,7 @@ static int adm1275_probe(struct i2c_client *client,
info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
info->read_word_data = adm1275_read_word_data;
+ info->read_byte_data = adm1275_read_byte_data;
info->write_word_data = adm1275_write_word_data;
if (config & ADM1275_VRANGE) {
@@ -134,10 +230,36 @@ static int adm1275_probe(struct i2c_client *client,
info->R[PSC_VOLTAGE_OUT] = -1;
}
- if (config & ADM1275_VIN_VOUT_SELECT)
- info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
- else
- info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT;
+ if (device_config & ADM1275_IOUT_WARN2_SELECT)
+ data->have_oc_fault = true;
+
+ switch (id->driver_data) {
+ case adm1275:
+ if (config & ADM1275_VIN_VOUT_SELECT)
+ info->func[0] |=
+ PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
+ else
+ info->func[0] |=
+ PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT;
+ break;
+ case adm1276:
+ info->format[PSC_POWER] = direct;
+ info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN
+ | PMBUS_HAVE_STATUS_INPUT;
+ if (config & ADM1275_VIN_VOUT_SELECT)
+ info->func[0] |=
+ PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
+ if (config & ADM1275_VRANGE) {
+ info->m[PSC_POWER] = 6043;
+ info->b[PSC_POWER] = 0;
+ info->R[PSC_POWER] = -2;
+ } else {
+ info->m[PSC_POWER] = 2115;
+ info->b[PSC_POWER] = 0;
+ info->R[PSC_POWER] = -1;
+ }
+ break;
+ }
ret = pmbus_do_probe(client, id, info);
if (ret)
@@ -145,22 +267,23 @@ static int adm1275_probe(struct i2c_client *client,
return 0;
err_mem:
- kfree(info);
+ kfree(data);
return ret;
}
static int adm1275_remove(struct i2c_client *client)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
- int ret;
+ const struct adm1275_data *data = to_adm1275_data(info);
- ret = pmbus_do_remove(client);
- kfree(info);
- return ret;
+ pmbus_do_remove(client);
+ kfree(data);
+ return 0;
}
static const struct i2c_device_id adm1275_id[] = {
- {"adm1275", 0},
+ { "adm1275", adm1275 },
+ { "adm1276", adm1276 },
{ }
};
MODULE_DEVICE_TABLE(i2c, adm1275_id);
@@ -185,7 +308,7 @@ static void __exit adm1275_exit(void)
}
MODULE_AUTHOR("Guenter Roeck");
-MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275");
+MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275 and compatibles");
MODULE_LICENSE("GPL");
module_init(adm1275_init);
module_exit(adm1275_exit);
diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c
index ac254fba551b..84a37f0c8db6 100644
--- a/drivers/hwmon/pmbus/lm25066.c
+++ b/drivers/hwmon/pmbus/lm25066.c
@@ -57,7 +57,7 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
int ret;
if (page > 1)
- return -EINVAL;
+ return -ENXIO;
/* Map READ_VAUX into READ_VOUT register on page 1 */
if (page == 1) {
@@ -85,7 +85,7 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
break;
default:
/* No other valid registers on page 1 */
- ret = -EINVAL;
+ ret = -ENXIO;
break;
}
goto done;
@@ -138,7 +138,7 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,
int ret;
if (page > 1)
- return -EINVAL;
+ return -ENXIO;
switch (reg) {
case PMBUS_IIN_OC_WARN_LIMIT:
@@ -164,10 +164,10 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,
static int lm25066_write_byte(struct i2c_client *client, int page, u8 value)
{
if (page > 1)
- return -EINVAL;
+ return -ENXIO;
- if (page == 0)
- return pmbus_write_byte(client, 0, value);
+ if (page <= 0)
+ return pmbus_write_byte(client, page, value);
return 0;
}
@@ -309,11 +309,10 @@ static int lm25066_remove(struct i2c_client *client)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
const struct lm25066_data *data = to_lm25066_data(info);
- int ret;
- ret = pmbus_do_remove(client);
+ pmbus_do_remove(client);
kfree(data);
- return ret;
+ return 0;
}
static const struct i2c_device_id lm25066_id[] = {
diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c
new file mode 100644
index 000000000000..820fff48910b
--- /dev/null
+++ b/drivers/hwmon/pmbus/ltc2978.c
@@ -0,0 +1,408 @@
+/*
+ * Hardware monitoring driver for LTC2978 and LTC3880
+ *
+ * Copyright (c) 2011 Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include "pmbus.h"
+
+enum chips { ltc2978, ltc3880 };
+
+/* LTC2978 and LTC3880 */
+#define LTC2978_MFR_VOUT_PEAK 0xdd
+#define LTC2978_MFR_VIN_PEAK 0xde
+#define LTC2978_MFR_TEMPERATURE_PEAK 0xdf
+#define LTC2978_MFR_SPECIAL_ID 0xe7
+
+/* LTC2978 only */
+#define LTC2978_MFR_VOUT_MIN 0xfb
+#define LTC2978_MFR_VIN_MIN 0xfc
+#define LTC2978_MFR_TEMPERATURE_MIN 0xfd
+
+/* LTC3880 only */
+#define LTC3880_MFR_IOUT_PEAK 0xd7
+#define LTC3880_MFR_CLEAR_PEAKS 0xe3
+#define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4
+
+#define LTC2978_ID_REV1 0x0121
+#define LTC2978_ID_REV2 0x0122
+#define LTC3880_ID 0x4000
+#define LTC3880_ID_MASK 0xff00
+
+/*
+ * LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which
+ * happens pretty much each time chip data is updated. Raw peak data therefore
+ * does not provide much value. To be able to provide useful peak data, keep an
+ * internal cache of measured peak data, which is only cleared if an explicit
+ * "clear peak" command is executed for the sensor in question.
+ */
+struct ltc2978_data {
+ enum chips id;
+ int vin_min, vin_max;
+ int temp_min, temp_max;
+ int vout_min[8], vout_max[8];
+ int iout_max[2];
+ int temp2_max[2];
+ struct pmbus_driver_info info;
+};
+
+#define to_ltc2978_data(x) container_of(x, struct ltc2978_data, info)
+
+static inline int lin11_to_val(int data)
+{
+ s16 e = ((s16)data) >> 11;
+ s32 m = (((s16)(data << 5)) >> 5);
+
+ /*
+ * mantissa is 10 bit + sign, exponent adds up to 15 bit.
+ * Add 6 bit to exponent for maximum accuracy (10 + 15 + 6 = 31).
+ */
+ e += 6;
+ return (e < 0 ? m >> -e : m << e);
+}
+
+static int ltc2978_read_word_data_common(struct i2c_client *client, int page,
+ int reg)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct ltc2978_data *data = to_ltc2978_data(info);
+ int ret;
+
+ switch (reg) {
+ case PMBUS_VIRT_READ_VIN_MAX:
+ ret = pmbus_read_word_data(client, page, LTC2978_MFR_VIN_PEAK);
+ if (ret >= 0) {
+ if (lin11_to_val(ret) > lin11_to_val(data->vin_max))
+ data->vin_max = ret;
+ ret = data->vin_max;
+ }
+ break;
+ case PMBUS_VIRT_READ_VOUT_MAX:
+ ret = pmbus_read_word_data(client, page, LTC2978_MFR_VOUT_PEAK);
+ if (ret >= 0) {
+ /*
+ * VOUT is 16 bit unsigned with fixed exponent,
+ * so we can compare it directly
+ */
+ if (ret > data->vout_max[page])
+ data->vout_max[page] = ret;
+ ret = data->vout_max[page];
+ }
+ break;
+ case PMBUS_VIRT_READ_TEMP_MAX:
+ ret = pmbus_read_word_data(client, page,
+ LTC2978_MFR_TEMPERATURE_PEAK);
+ if (ret >= 0) {
+ if (lin11_to_val(ret) > lin11_to_val(data->temp_max))
+ data->temp_max = ret;
+ ret = data->temp_max;
+ }
+ break;
+ case PMBUS_VIRT_RESET_VOUT_HISTORY:
+ case PMBUS_VIRT_RESET_VIN_HISTORY:
+ case PMBUS_VIRT_RESET_TEMP_HISTORY:
+ ret = 0;
+ break;
+ default:
+ ret = -ENODATA;
+ break;
+ }
+ return ret;
+}
+
+static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct ltc2978_data *data = to_ltc2978_data(info);
+ int ret;
+
+ switch (reg) {
+ case PMBUS_VIRT_READ_VIN_MIN:
+ ret = pmbus_read_word_data(client, page, LTC2978_MFR_VIN_MIN);
+ if (ret >= 0) {
+ if (lin11_to_val(ret) < lin11_to_val(data->vin_min))
+ data->vin_min = ret;
+ ret = data->vin_min;
+ }
+ break;
+ case PMBUS_VIRT_READ_VOUT_MIN:
+ ret = pmbus_read_word_data(client, page, LTC2978_MFR_VOUT_MIN);
+ if (ret >= 0) {
+ /*
+ * VOUT_MIN is known to not be supported on some lots
+ * of LTC2978 revision 1, and will return the maximum
+ * possible voltage if read. If VOUT_MAX is valid and
+ * lower than the reading of VOUT_MIN, use it instead.
+ */
+ if (data->vout_max[page] && ret > data->vout_max[page])
+ ret = data->vout_max[page];
+ if (ret < data->vout_min[page])
+ data->vout_min[page] = ret;
+ ret = data->vout_min[page];
+ }
+ break;
+ case PMBUS_VIRT_READ_TEMP_MIN:
+ ret = pmbus_read_word_data(client, page,
+ LTC2978_MFR_TEMPERATURE_MIN);
+ if (ret >= 0) {
+ if (lin11_to_val(ret)
+ < lin11_to_val(data->temp_min))
+ data->temp_min = ret;
+ ret = data->temp_min;
+ }
+ break;
+ case PMBUS_VIRT_READ_IOUT_MAX:
+ case PMBUS_VIRT_RESET_IOUT_HISTORY:
+ case PMBUS_VIRT_READ_TEMP2_MAX:
+ case PMBUS_VIRT_RESET_TEMP2_HISTORY:
+ ret = -ENXIO;
+ break;
+ default:
+ ret = ltc2978_read_word_data_common(client, page, reg);
+ break;
+ }
+ return ret;
+}
+
+static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct ltc2978_data *data = to_ltc2978_data(info);
+ int ret;
+
+ switch (reg) {
+ case PMBUS_VIRT_READ_IOUT_MAX:
+ ret = pmbus_read_word_data(client, page, LTC3880_MFR_IOUT_PEAK);
+ if (ret >= 0) {
+ if (lin11_to_val(ret)
+ > lin11_to_val(data->iout_max[page]))
+ data->iout_max[page] = ret;
+ ret = data->iout_max[page];
+ }
+ break;
+ case PMBUS_VIRT_READ_TEMP2_MAX:
+ ret = pmbus_read_word_data(client, page,
+ LTC3880_MFR_TEMPERATURE2_PEAK);
+ if (ret >= 0) {
+ if (lin11_to_val(ret)
+ > lin11_to_val(data->temp2_max[page]))
+ data->temp2_max[page] = ret;
+ ret = data->temp2_max[page];
+ }
+ break;
+ case PMBUS_VIRT_READ_VIN_MIN:
+ case PMBUS_VIRT_READ_VOUT_MIN:
+ case PMBUS_VIRT_READ_TEMP_MIN:
+ ret = -ENXIO;
+ break;
+ case PMBUS_VIRT_RESET_IOUT_HISTORY:
+ case PMBUS_VIRT_RESET_TEMP2_HISTORY:
+ ret = 0;
+ break;
+ default:
+ ret = ltc2978_read_word_data_common(client, page, reg);
+ break;
+ }
+ return ret;
+}
+
+static int ltc2978_clear_peaks(struct i2c_client *client, int page,
+ enum chips id)
+{
+ int ret;
+
+ if (id == ltc2978)
+ ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
+ else
+ ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS);
+
+ return ret;
+}
+
+static int ltc2978_write_word_data(struct i2c_client *client, int page,
+ int reg, u16 word)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct ltc2978_data *data = to_ltc2978_data(info);
+ int ret;
+
+ switch (reg) {
+ case PMBUS_VIRT_RESET_IOUT_HISTORY:
+ data->iout_max[page] = 0x7fff;
+ ret = ltc2978_clear_peaks(client, page, data->id);
+ break;
+ case PMBUS_VIRT_RESET_TEMP2_HISTORY:
+ data->temp2_max[page] = 0x7fff;
+ ret = ltc2978_clear_peaks(client, page, data->id);
+ break;
+ case PMBUS_VIRT_RESET_VOUT_HISTORY:
+ data->vout_min[page] = 0xffff;
+ data->vout_max[page] = 0;
+ ret = ltc2978_clear_peaks(client, page, data->id);
+ break;
+ case PMBUS_VIRT_RESET_VIN_HISTORY:
+ data->vin_min = 0x7bff;
+ data->vin_max = 0;
+ ret = ltc2978_clear_peaks(client, page, data->id);
+ break;
+ case PMBUS_VIRT_RESET_TEMP_HISTORY:
+ data->temp_min = 0x7bff;
+ data->temp_max = 0x7fff;
+ ret = ltc2978_clear_peaks(client, page, data->id);
+ break;
+ default:
+ ret = -ENODATA;
+ break;
+ }
+ return ret;
+}
+
+static const struct i2c_device_id ltc2978_id[] = {
+ {"ltc2978", ltc2978},
+ {"ltc3880", ltc3880},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, ltc2978_id);
+
+static int ltc2978_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int chip_id, ret, i;
+ struct ltc2978_data *data;
+ struct pmbus_driver_info *info;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_WORD_DATA))
+ return -ENODEV;
+
+ data = kzalloc(sizeof(struct ltc2978_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ chip_id = i2c_smbus_read_word_data(client, LTC2978_MFR_SPECIAL_ID);
+ if (chip_id < 0) {
+ ret = chip_id;
+ goto err_mem;
+ }
+
+ if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) {
+ data->id = ltc2978;
+ } else if ((chip_id & LTC3880_ID_MASK) == LTC3880_ID) {
+ data->id = ltc3880;
+ } else {
+ dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
+ ret = -ENODEV;
+ goto err_mem;
+ }
+ if (data->id != id->driver_data)
+ dev_warn(&client->dev,
+ "Device mismatch: Configured %s, detected %s\n",
+ id->name,
+ ltc2978_id[data->id].name);
+
+ info = &data->info;
+ info->write_word_data = ltc2978_write_word_data;
+
+ data->vout_min[0] = 0xffff;
+ data->vin_min = 0x7bff;
+ data->temp_min = 0x7bff;
+ data->temp_max = 0x7fff;
+
+ switch (id->driver_data) {
+ case ltc2978:
+ info->read_word_data = ltc2978_read_word_data;
+ info->pages = 8;
+ info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
+ | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+ | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
+ for (i = 1; i < 8; i++) {
+ info->func[i] = PMBUS_HAVE_VOUT
+ | PMBUS_HAVE_STATUS_VOUT;
+ data->vout_min[i] = 0xffff;
+ }
+ break;
+ case ltc3880:
+ info->read_word_data = ltc3880_read_word_data;
+ info->pages = 2;
+ info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
+ | PMBUS_HAVE_STATUS_INPUT
+ | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
+ | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
+ | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
+ info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
+ | PMBUS_HAVE_POUT
+ | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
+ data->vout_min[1] = 0xffff;
+ break;
+ default:
+ ret = -ENODEV;
+ goto err_mem;
+ }
+
+ ret = pmbus_do_probe(client, id, info);
+ if (ret)
+ goto err_mem;
+ return 0;
+
+err_mem:
+ kfree(data);
+ return ret;
+}
+
+static int ltc2978_remove(struct i2c_client *client)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ const struct ltc2978_data *data = to_ltc2978_data(info);
+
+ pmbus_do_remove(client);
+ kfree(data);
+ return 0;
+}
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ltc2978_driver = {
+ .driver = {
+ .name = "ltc2978",
+ },
+ .probe = ltc2978_probe,
+ .remove = ltc2978_remove,
+ .id_table = ltc2978_id,
+};
+
+static int __init ltc2978_init(void)
+{
+ return i2c_add_driver(&ltc2978_driver);
+}
+
+static void __exit ltc2978_exit(void)
+{
+ i2c_del_driver(&ltc2978_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for LTC2978 and LTC3880");
+MODULE_LICENSE("GPL");
+module_init(ltc2978_init);
+module_exit(ltc2978_exit);
diff --git a/drivers/hwmon/pmbus/max16064.c b/drivers/hwmon/pmbus/max16064.c
index e50b296e8db4..1d77cf4d2d44 100644
--- a/drivers/hwmon/pmbus/max16064.c
+++ b/drivers/hwmon/pmbus/max16064.c
@@ -105,7 +105,8 @@ static int max16064_probe(struct i2c_client *client,
static int max16064_remove(struct i2c_client *client)
{
- return pmbus_do_remove(client);
+ pmbus_do_remove(client);
+ return 0;
}
static const struct i2c_device_id max16064_id[] = {
diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c
index fda621d2e458..beaf5a8d9c45 100644
--- a/drivers/hwmon/pmbus/max34440.c
+++ b/drivers/hwmon/pmbus/max34440.c
@@ -93,12 +93,14 @@ static int max34440_write_word_data(struct i2c_client *client, int page,
static int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
{
- int ret;
+ int ret = 0;
int mfg_status;
- ret = pmbus_set_page(client, page);
- if (ret < 0)
- return ret;
+ if (page >= 0) {
+ ret = pmbus_set_page(client, page);
+ if (ret < 0)
+ return ret;
+ }
switch (reg) {
case PMBUS_STATUS_IOUT:
@@ -224,7 +226,8 @@ static int max34440_probe(struct i2c_client *client,
static int max34440_remove(struct i2c_client *client)
{
- return pmbus_do_remove(client);
+ pmbus_do_remove(client);
+ return 0;
}
static const struct i2c_device_id max34440_id[] = {
diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c
index c3e72f1a3cfb..e2b74bb399ba 100644
--- a/drivers/hwmon/pmbus/max8688.c
+++ b/drivers/hwmon/pmbus/max8688.c
@@ -45,7 +45,7 @@ static int max8688_read_word_data(struct i2c_client *client, int page, int reg)
int ret;
if (page)
- return -EINVAL;
+ return -ENXIO;
switch (reg) {
case PMBUS_VIRT_READ_VOUT_MAX:
@@ -101,8 +101,8 @@ static int max8688_read_byte_data(struct i2c_client *client, int page, int reg)
int ret = 0;
int mfg_status;
- if (page)
- return -EINVAL;
+ if (page > 0)
+ return -ENXIO;
switch (reg) {
case PMBUS_STATUS_VOUT:
@@ -182,7 +182,8 @@ static int max8688_probe(struct i2c_client *client,
static int max8688_remove(struct i2c_client *client)
{
- return pmbus_do_remove(client);
+ pmbus_do_remove(client);
+ return 0;
}
static const struct i2c_device_id max8688_id[] = {
diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c
index 73de9f1f3194..995e873197e3 100644
--- a/drivers/hwmon/pmbus/pmbus.c
+++ b/drivers/hwmon/pmbus/pmbus.c
@@ -187,13 +187,12 @@ out:
static int pmbus_remove(struct i2c_client *client)
{
- int ret;
const struct pmbus_driver_info *info;
info = pmbus_get_driver_info(client);
- ret = pmbus_do_remove(client);
+ pmbus_do_remove(client);
kfree(info);
- return ret;
+ return 0;
}
/*
@@ -205,10 +204,13 @@ static const struct i2c_device_id pmbus_id[] = {
{"bmr451", 1},
{"bmr453", 1},
{"bmr454", 1},
- {"ltc2978", 8},
{"ncp4200", 1},
{"ncp4208", 1},
+ {"pdt003", 1},
+ {"pdt006", 1},
+ {"pdt012", 1},
{"pmbus", 0},
+ {"udt020", 1},
{}
};
diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
index a6ae20ffef6b..5d31d1c2c0f5 100644
--- a/drivers/hwmon/pmbus/pmbus.h
+++ b/drivers/hwmon/pmbus/pmbus.h
@@ -134,8 +134,16 @@
* Semantics:
* Virtual registers are all word size.
* READ registers are read-only; writes are either ignored or return an error.
- * RESET registers are read/write. Reading returns zero (used for detection),
- * writing any value causes the associated history to be reset.
+ * RESET registers are read/write. Reading reset registers returns zero
+ * (used for detection), writing any value causes the associated history to be
+ * reset.
+ * Virtual registers have to be handled in device specific driver code. Chip
+ * driver code returns non-negative register values if a virtual register is
+ * supported, or a negative error code if not. The chip driver may return
+ * -ENODATA or any other error code in this case, though an error code other
+ * than -ENODATA is handled more efficiently and thus preferred. Either case,
+ * the calling PMBus core code will abort if the chip driver returns an error
+ * code when reading or writing virtual registers.
*/
#define PMBUS_VIRT_BASE 0x100
#define PMBUS_VIRT_READ_TEMP_MIN (PMBUS_VIRT_BASE + 0)
@@ -160,6 +168,9 @@
#define PMBUS_VIRT_READ_IOUT_MIN (PMBUS_VIRT_BASE + 19)
#define PMBUS_VIRT_READ_IOUT_MAX (PMBUS_VIRT_BASE + 20)
#define PMBUS_VIRT_RESET_IOUT_HISTORY (PMBUS_VIRT_BASE + 21)
+#define PMBUS_VIRT_READ_TEMP2_MIN (PMBUS_VIRT_BASE + 22)
+#define PMBUS_VIRT_READ_TEMP2_MAX (PMBUS_VIRT_BASE + 23)
+#define PMBUS_VIRT_RESET_TEMP2_HISTORY (PMBUS_VIRT_BASE + 24)
/*
* CAPABILITY
@@ -320,6 +331,12 @@ struct pmbus_driver_info {
* The following functions map manufacturing specific register values
* to PMBus standard register values. Specify only if mapping is
* necessary.
+ * Functions return the register value (read) or zero (write) if
+ * successful. A return value of -ENODATA indicates that there is no
+ * manufacturer specific register, but that a standard PMBus register
+ * may exist. Any other negative return value indicates that the
+ * register does not exist, and that no attempt should be made to read
+ * the standard register.
*/
int (*read_byte_data)(struct i2c_client *client, int page, int reg);
int (*read_word_data)(struct i2c_client *client, int page, int reg);
@@ -347,7 +364,7 @@ bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg);
bool pmbus_check_word_register(struct i2c_client *client, int page, int reg);
int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
struct pmbus_driver_info *info);
-int pmbus_do_remove(struct i2c_client *client);
+void pmbus_do_remove(struct i2c_client *client);
const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client
*client);
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index a561c3a0e916..00460d8d8423 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -160,7 +160,7 @@ int pmbus_set_page(struct i2c_client *client, u8 page)
rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
newpage = i2c_smbus_read_byte_data(client, PMBUS_PAGE);
if (newpage != page)
- rv = -EINVAL;
+ rv = -EIO;
else
data->currpage = page;
}
@@ -229,7 +229,7 @@ static int _pmbus_write_word_data(struct i2c_client *client, int page, int reg,
return status;
}
if (reg >= PMBUS_VIRT_BASE)
- return -EINVAL;
+ return -ENXIO;
return pmbus_write_word_data(client, page, reg, word);
}
@@ -261,7 +261,7 @@ static int _pmbus_read_word_data(struct i2c_client *client, int page, int reg)
return status;
}
if (reg >= PMBUS_VIRT_BASE)
- return -EINVAL;
+ return -ENXIO;
return pmbus_read_word_data(client, page, reg);
}
@@ -316,11 +316,11 @@ static int pmbus_check_status_cml(struct i2c_client *client)
{
int status, status2;
- status = pmbus_read_byte_data(client, -1, PMBUS_STATUS_BYTE);
+ status = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_BYTE);
if (status < 0 || (status & PB_STATUS_CML)) {
- status2 = pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML);
+ status2 = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML);
if (status2 < 0 || (status2 & PB_CML_FAULT_INVALID_COMMAND))
- return -EINVAL;
+ return -EIO;
}
return 0;
}
@@ -371,8 +371,8 @@ static struct pmbus_data *pmbus_update_device(struct device *dev)
for (i = 0; i < info->pages; i++)
data->status[PB_STATUS_BASE + i]
- = pmbus_read_byte_data(client, i,
- PMBUS_STATUS_BYTE);
+ = _pmbus_read_byte_data(client, i,
+ PMBUS_STATUS_BYTE);
for (i = 0; i < info->pages; i++) {
if (!(info->func[i] & PMBUS_HAVE_STATUS_VOUT))
continue;
@@ -445,13 +445,8 @@ static long pmbus_reg2data_linear(struct pmbus_data *data,
exponent = data->exponent;
mantissa = (u16) sensor->data;
} else { /* LINEAR11 */
- exponent = (sensor->data >> 11) & 0x001f;
- mantissa = sensor->data & 0x07ff;
-
- if (exponent > 0x0f)
- exponent |= 0xffe0; /* sign extend exponent */
- if (mantissa > 0x03ff)
- mantissa |= 0xfffff800; /* sign extend mantissa */
+ exponent = ((s16)sensor->data) >> 11;
+ mantissa = ((s16)((sensor->data & 0x7ff) << 5)) >> 5;
}
val = mantissa;
@@ -978,6 +973,8 @@ static void pmbus_find_max_attr(struct i2c_client *client,
struct pmbus_limit_attr {
u16 reg; /* Limit register */
bool update; /* True if register needs updates */
+ bool low; /* True if low limit; for limits with compare
+ functions only */
const char *attr; /* Attribute name */
const char *alarm; /* Alarm attribute name */
u32 sbit; /* Alarm attribute status bit */
@@ -1029,7 +1026,8 @@ static bool pmbus_add_limit_attrs(struct i2c_client *client,
if (attr->compare) {
pmbus_add_boolean_cmp(data, name,
l->alarm, index,
- cbase, cindex,
+ l->low ? cindex : cbase,
+ l->low ? cbase : cindex,
attr->sbase + page, l->sbit);
} else {
pmbus_add_boolean_reg(data, name,
@@ -1366,11 +1364,13 @@ static const struct pmbus_sensor_attr power_attributes[] = {
static const struct pmbus_limit_attr temp_limit_attrs[] = {
{
.reg = PMBUS_UT_WARN_LIMIT,
+ .low = true,
.attr = "min",
.alarm = "min_alarm",
.sbit = PB_TEMP_UT_WARNING,
}, {
.reg = PMBUS_UT_FAULT_LIMIT,
+ .low = true,
.attr = "lcrit",
.alarm = "lcrit_alarm",
.sbit = PB_TEMP_UT_FAULT,
@@ -1396,14 +1396,51 @@ static const struct pmbus_limit_attr temp_limit_attrs[] = {
}
};
-static const struct pmbus_limit_attr temp_limit_attrs23[] = {
+static const struct pmbus_limit_attr temp_limit_attrs2[] = {
+ {
+ .reg = PMBUS_UT_WARN_LIMIT,
+ .low = true,
+ .attr = "min",
+ .alarm = "min_alarm",
+ .sbit = PB_TEMP_UT_WARNING,
+ }, {
+ .reg = PMBUS_UT_FAULT_LIMIT,
+ .low = true,
+ .attr = "lcrit",
+ .alarm = "lcrit_alarm",
+ .sbit = PB_TEMP_UT_FAULT,
+ }, {
+ .reg = PMBUS_OT_WARN_LIMIT,
+ .attr = "max",
+ .alarm = "max_alarm",
+ .sbit = PB_TEMP_OT_WARNING,
+ }, {
+ .reg = PMBUS_OT_FAULT_LIMIT,
+ .attr = "crit",
+ .alarm = "crit_alarm",
+ .sbit = PB_TEMP_OT_FAULT,
+ }, {
+ .reg = PMBUS_VIRT_READ_TEMP2_MIN,
+ .attr = "lowest",
+ }, {
+ .reg = PMBUS_VIRT_READ_TEMP2_MAX,
+ .attr = "highest",
+ }, {
+ .reg = PMBUS_VIRT_RESET_TEMP2_HISTORY,
+ .attr = "reset_history",
+ }
+};
+
+static const struct pmbus_limit_attr temp_limit_attrs3[] = {
{
.reg = PMBUS_UT_WARN_LIMIT,
+ .low = true,
.attr = "min",
.alarm = "min_alarm",
.sbit = PB_TEMP_UT_WARNING,
}, {
.reg = PMBUS_UT_FAULT_LIMIT,
+ .low = true,
.attr = "lcrit",
.alarm = "lcrit_alarm",
.sbit = PB_TEMP_UT_FAULT,
@@ -1443,8 +1480,8 @@ static const struct pmbus_sensor_attr temp_attributes[] = {
.sfunc = PMBUS_HAVE_STATUS_TEMP,
.sbase = PB_STATUS_TEMP_BASE,
.gbit = PB_STATUS_TEMPERATURE,
- .limit = temp_limit_attrs23,
- .nlimit = ARRAY_SIZE(temp_limit_attrs23),
+ .limit = temp_limit_attrs2,
+ .nlimit = ARRAY_SIZE(temp_limit_attrs2),
}, {
.reg = PMBUS_READ_TEMPERATURE_3,
.class = PSC_TEMPERATURE,
@@ -1455,8 +1492,8 @@ static const struct pmbus_sensor_attr temp_attributes[] = {
.sfunc = PMBUS_HAVE_STATUS_TEMP,
.sbase = PB_STATUS_TEMP_BASE,
.gbit = PB_STATUS_TEMPERATURE,
- .limit = temp_limit_attrs23,
- .nlimit = ARRAY_SIZE(temp_limit_attrs23),
+ .limit = temp_limit_attrs3,
+ .nlimit = ARRAY_SIZE(temp_limit_attrs3),
}
};
@@ -1586,10 +1623,10 @@ static void pmbus_find_attributes(struct i2c_client *client,
static int pmbus_identify_common(struct i2c_client *client,
struct pmbus_data *data)
{
- int vout_mode = -1, exponent;
+ int vout_mode = -1;
if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE))
- vout_mode = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
+ vout_mode = _pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
if (vout_mode >= 0 && vout_mode != 0xff) {
/*
* Not all chips support the VOUT_MODE command,
@@ -1600,11 +1637,7 @@ static int pmbus_identify_common(struct i2c_client *client,
if (data->info->format[PSC_VOLTAGE_OUT] != linear)
return -ENODEV;
- exponent = vout_mode & 0x1f;
- /* and sign-extend it */
- if (exponent & 0x10)
- exponent |= ~0x1f;
- data->exponent = exponent;
+ data->exponent = ((s8)(vout_mode << 3)) >> 3;
break;
case 1: /* VID mode */
if (data->info->format[PSC_VOLTAGE_OUT] != vid)
@@ -1675,7 +1708,7 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
if (info->pages <= 0 || info->pages > PMBUS_PAGES) {
dev_err(&client->dev, "Bad number of PMBus pages: %d\n",
info->pages);
- ret = -EINVAL;
+ ret = -ENODEV;
goto out_data;
}
@@ -1757,7 +1790,7 @@ out_data:
}
EXPORT_SYMBOL_GPL(pmbus_do_probe);
-int pmbus_do_remove(struct i2c_client *client)
+void pmbus_do_remove(struct i2c_client *client)
{
struct pmbus_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
@@ -1767,7 +1800,6 @@ int pmbus_do_remove(struct i2c_client *client)
kfree(data->booleans);
kfree(data->sensors);
kfree(data);
- return 0;
}
EXPORT_SYMBOL_GPL(pmbus_do_remove);
diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c
index ace1c7319734..4ff6cf289f85 100644
--- a/drivers/hwmon/pmbus/ucd9000.c
+++ b/drivers/hwmon/pmbus/ucd9000.c
@@ -74,8 +74,8 @@ static int ucd9000_read_byte_data(struct i2c_client *client, int page, int reg)
switch (reg) {
case PMBUS_FAN_CONFIG_12:
- if (page)
- return -EINVAL;
+ if (page > 0)
+ return -ENXIO;
ret = ucd9000_get_fan_config(client, 0);
if (ret < 0)
@@ -88,8 +88,8 @@ static int ucd9000_read_byte_data(struct i2c_client *client, int page, int reg)
ret = fan_config;
break;
case PMBUS_FAN_CONFIG_34:
- if (page)
- return -EINVAL;
+ if (page > 0)
+ return -ENXIO;
ret = ucd9000_get_fan_config(client, 2);
if (ret < 0)
@@ -141,13 +141,11 @@ static int ucd9000_probe(struct i2c_client *client,
block_buffer[ret] = '\0';
dev_info(&client->dev, "Device ID %s\n", block_buffer);
- mid = NULL;
- for (i = 0; i < ARRAY_SIZE(ucd9000_id); i++) {
- mid = &ucd9000_id[i];
+ for (mid = ucd9000_id; mid->name[0]; mid++) {
if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
break;
}
- if (!mid || !strlen(mid->name)) {
+ if (!mid->name[0]) {
dev_err(&client->dev, "Unsupported device\n");
return -ENODEV;
}
@@ -241,13 +239,12 @@ out:
static int ucd9000_remove(struct i2c_client *client)
{
- int ret;
struct ucd9000_data *data;
data = to_ucd9000_data(pmbus_get_driver_info(client));
- ret = pmbus_do_remove(client);
+ pmbus_do_remove(client);
kfree(data);
- return ret;
+ return 0;
}
diff --git a/drivers/hwmon/pmbus/ucd9200.c b/drivers/hwmon/pmbus/ucd9200.c
index ffcc1cf3609d..6e1c1a80ab85 100644
--- a/drivers/hwmon/pmbus/ucd9200.c
+++ b/drivers/hwmon/pmbus/ucd9200.c
@@ -68,13 +68,11 @@ static int ucd9200_probe(struct i2c_client *client,
block_buffer[ret] = '\0';
dev_info(&client->dev, "Device ID %s\n", block_buffer);
- mid = NULL;
- for (i = 0; i < ARRAY_SIZE(ucd9200_id); i++) {
- mid = &ucd9200_id[i];
+ for (mid = ucd9200_id; mid->name[0]; mid++) {
if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
break;
}
- if (!mid || !strlen(mid->name)) {
+ if (!mid->name[0]) {
dev_err(&client->dev, "Unsupported device\n");
return -ENODEV;
}
@@ -173,13 +171,12 @@ out:
static int ucd9200_remove(struct i2c_client *client)
{
- int ret;
const struct pmbus_driver_info *info;
info = pmbus_get_driver_info(client);
- ret = pmbus_do_remove(client);
+ pmbus_do_remove(client);
kfree(info);
- return ret;
+ return 0;
}
diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c
new file mode 100644
index 000000000000..2bc980006f83
--- /dev/null
+++ b/drivers/hwmon/pmbus/zl6100.c
@@ -0,0 +1,256 @@
+/*
+ * Hardware monitoring driver for ZL6100 and compatibles
+ *
+ * Copyright (c) 2011 Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/ktime.h>
+#include <linux/delay.h>
+#include "pmbus.h"
+
+enum chips { zl2004, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105 };
+
+struct zl6100_data {
+ int id;
+ ktime_t access; /* chip access time */
+ struct pmbus_driver_info info;
+};
+
+#define to_zl6100_data(x) container_of(x, struct zl6100_data, info)
+
+#define ZL6100_DEVICE_ID 0xe4
+
+#define ZL6100_WAIT_TIME 1000 /* uS */
+
+static ushort delay = ZL6100_WAIT_TIME;
+module_param(delay, ushort, 0644);
+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) {
+ s64 delta = ktime_us_delta(ktime_get(), data->access);
+ if (delta < delay)
+ udelay(delay - delta);
+ }
+}
+
+static int zl6100_read_word_data(struct i2c_client *client, int page, int reg)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct zl6100_data *data = to_zl6100_data(info);
+ int ret;
+
+ if (page || reg >= PMBUS_VIRT_BASE)
+ return -ENXIO;
+
+ zl6100_wait(data);
+ ret = pmbus_read_word_data(client, page, reg);
+ data->access = ktime_get();
+
+ return ret;
+}
+
+static int zl6100_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct zl6100_data *data = to_zl6100_data(info);
+ int ret;
+
+ if (page > 0)
+ return -ENXIO;
+
+ zl6100_wait(data);
+ ret = pmbus_read_byte_data(client, page, reg);
+ data->access = ktime_get();
+
+ return ret;
+}
+
+static int zl6100_write_word_data(struct i2c_client *client, int page, int reg,
+ u16 word)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct zl6100_data *data = to_zl6100_data(info);
+ int ret;
+
+ if (page || reg >= PMBUS_VIRT_BASE)
+ return -ENXIO;
+
+ zl6100_wait(data);
+ ret = pmbus_write_word_data(client, page, reg, word);
+ data->access = ktime_get();
+
+ return ret;
+}
+
+static int zl6100_write_byte(struct i2c_client *client, int page, u8 value)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct zl6100_data *data = to_zl6100_data(info);
+ int ret;
+
+ if (page > 0)
+ return -ENXIO;
+
+ zl6100_wait(data);
+ ret = pmbus_write_byte(client, page, value);
+ data->access = ktime_get();
+
+ return ret;
+}
+
+static const struct i2c_device_id zl6100_id[] = {
+ {"zl2004", zl2004},
+ {"zl2006", zl2006},
+ {"zl2008", zl2008},
+ {"zl2105", zl2105},
+ {"zl2106", zl2106},
+ {"zl6100", zl6100},
+ {"zl6105", zl6105},
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, zl6100_id);
+
+static int zl6100_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret;
+ struct zl6100_data *data;
+ struct pmbus_driver_info *info;
+ u8 device_id[I2C_SMBUS_BLOCK_MAX + 1];
+ const struct i2c_device_id *mid;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_BYTE_DATA
+ | I2C_FUNC_SMBUS_READ_BLOCK_DATA))
+ return -ENODEV;
+
+ ret = i2c_smbus_read_block_data(client, ZL6100_DEVICE_ID,
+ device_id);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to read device ID\n");
+ return ret;
+ }
+ device_id[ret] = '\0';
+ dev_info(&client->dev, "Device ID %s\n", device_id);
+
+ mid = NULL;
+ for (mid = zl6100_id; mid->name[0]; mid++) {
+ if (!strncasecmp(mid->name, device_id, strlen(mid->name)))
+ break;
+ }
+ if (!mid->name[0]) {
+ dev_err(&client->dev, "Unsupported device\n");
+ return -ENODEV;
+ }
+ if (id->driver_data != mid->driver_data)
+ dev_notice(&client->dev,
+ "Device mismatch: Configured %s, detected %s\n",
+ id->name, mid->name);
+
+ data = kzalloc(sizeof(struct zl6100_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->id = mid->driver_data;
+
+ /*
+ * ZL2008, ZL2105, and ZL6100 are known to require a wait time
+ * between I2C accesses. ZL2004 and ZL6105 are known to be safe.
+ *
+ * Only clear the wait time for chips known to be safe. The wait time
+ * can be cleared later for additional chips if tests show that it
+ * is not needed (in other words, better be safe than sorry).
+ */
+ if (data->id == zl2004 || data->id == zl6105)
+ delay = 0;
+
+ /*
+ * Since there was a direct I2C device access above, wait before
+ * accessing the chip again.
+ * Set the timestamp, wait, then set it again. This should provide
+ * enough buffer time to be safe.
+ */
+ data->access = ktime_get();
+ zl6100_wait(data);
+ data->access = ktime_get();
+
+ info = &data->info;
+
+ info->pages = 1;
+ info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
+ | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
+ | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
+
+ info->read_word_data = zl6100_read_word_data;
+ info->read_byte_data = zl6100_read_byte_data;
+ info->write_word_data = zl6100_write_word_data;
+ info->write_byte = zl6100_write_byte;
+
+ ret = pmbus_do_probe(client, mid, info);
+ if (ret)
+ goto err_mem;
+ return 0;
+
+err_mem:
+ kfree(data);
+ return ret;
+}
+
+static int zl6100_remove(struct i2c_client *client)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ const struct zl6100_data *data = to_zl6100_data(info);
+
+ pmbus_do_remove(client);
+ kfree(data);
+ return 0;
+}
+
+static struct i2c_driver zl6100_driver = {
+ .driver = {
+ .name = "zl6100",
+ },
+ .probe = zl6100_probe,
+ .remove = zl6100_remove,
+ .id_table = zl6100_id,
+};
+
+static int __init zl6100_init(void)
+{
+ return i2c_add_driver(&zl6100_driver);
+}
+
+static void __exit zl6100_exit(void)
+{
+ i2c_del_driver(&zl6100_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for ZL6100 and compatibles");
+MODULE_LICENSE("GPL");
+module_init(zl6100_init);
+module_exit(zl6100_exit);
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index f2b377c56a3a..98aab4bea342 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -197,6 +197,9 @@ static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252, 0 };
#define W83627EHF_REG_ALARM2 0x45A
#define W83627EHF_REG_ALARM3 0x45B
+#define W83627EHF_REG_CASEOPEN_DET 0x42 /* SMI STATUS #2 */
+#define W83627EHF_REG_CASEOPEN_CLR 0x46 /* SMI MASK #3 */
+
/* SmartFan registers */
#define W83627EHF_REG_FAN_STEPUP_TIME 0x0f
#define W83627EHF_REG_FAN_STEPDOWN_TIME 0x0e
@@ -316,7 +319,7 @@ static const char *const nct6776_temp_label[] = {
#define NUM_REG_TEMP ARRAY_SIZE(NCT6775_REG_TEMP)
-static inline int is_word_sized(u16 reg)
+static int is_word_sized(u16 reg)
{
return ((((reg & 0xff00) == 0x100
|| (reg & 0xff00) == 0x200)
@@ -385,22 +388,6 @@ div_from_reg(u8 reg)
return 1 << reg;
}
-static inline int
-temp_from_reg(u16 reg, s16 regval)
-{
- if (is_word_sized(reg))
- return LM75_TEMP_FROM_REG(regval);
- return regval * 1000;
-}
-
-static inline u16
-temp_to_reg(u16 reg, long temp)
-{
- if (is_word_sized(reg))
- return LM75_TEMP_TO_REG(temp);
- return DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, -127000, 128000), 1000);
-}
-
/* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */
static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 };
@@ -468,6 +455,7 @@ struct w83627ehf_data {
s16 temp_max[9];
s16 temp_max_hyst[9];
u32 alarms;
+ u8 caseopen;
u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
u8 pwm_enable[4]; /* 1->manual
@@ -556,6 +544,26 @@ static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg,
return 0;
}
+/* We left-align 8-bit temperature values to make the code simpler */
+static u16 w83627ehf_read_temp(struct w83627ehf_data *data, u16 reg)
+{
+ u16 res;
+
+ res = w83627ehf_read_value(data, reg);
+ if (!is_word_sized(reg))
+ res <<= 8;
+
+ return res;
+}
+
+static int w83627ehf_write_temp(struct w83627ehf_data *data, u16 reg,
+ u16 value)
+{
+ if (!is_word_sized(reg))
+ value >>= 8;
+ return w83627ehf_write_value(data, reg, value);
+}
+
/* This function assumes that the caller holds data->update_lock */
static void nct6775_write_fan_div(struct w83627ehf_data *data, int nr)
{
@@ -770,6 +778,9 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
/* Measured voltages and limits */
for (i = 0; i < data->in_num; i++) {
+ if ((i == 6) && data->in6_skip)
+ continue;
+
data->in[i] = w83627ehf_read_value(data,
W83627EHF_REG_IN(i));
data->in_min[i] = w83627ehf_read_value(data,
@@ -854,15 +865,15 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
for (i = 0; i < NUM_REG_TEMP; i++) {
if (!(data->have_temp & (1 << i)))
continue;
- data->temp[i] = w83627ehf_read_value(data,
+ data->temp[i] = w83627ehf_read_temp(data,
data->reg_temp[i]);
if (data->reg_temp_over[i])
data->temp_max[i]
- = w83627ehf_read_value(data,
+ = w83627ehf_read_temp(data,
data->reg_temp_over[i]);
if (data->reg_temp_hyst[i])
data->temp_max_hyst[i]
- = w83627ehf_read_value(data,
+ = w83627ehf_read_temp(data,
data->reg_temp_hyst[i]);
}
@@ -873,6 +884,9 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
(w83627ehf_read_value(data,
W83627EHF_REG_ALARM3) << 16);
+ data->caseopen = w83627ehf_read_value(data,
+ W83627EHF_REG_CASEOPEN_DET);
+
data->last_updated = jiffies;
data->valid = 1;
}
@@ -1155,8 +1169,7 @@ show_##reg(struct device *dev, struct device_attribute *attr, \
struct sensor_device_attribute *sensor_attr = \
to_sensor_dev_attr(attr); \
int nr = sensor_attr->index; \
- return sprintf(buf, "%d\n", \
- temp_from_reg(data->addr[nr], data->reg[nr])); \
+ return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->reg[nr])); \
}
show_temp_reg(reg_temp, temp);
show_temp_reg(reg_temp_over, temp_max);
@@ -1177,9 +1190,8 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
if (err < 0) \
return err; \
mutex_lock(&data->update_lock); \
- data->reg[nr] = temp_to_reg(data->addr[nr], val); \
- w83627ehf_write_value(data, data->addr[nr], \
- data->reg[nr]); \
+ data->reg[nr] = LM75_TEMP_TO_REG(val); \
+ w83627ehf_write_temp(data, data->addr[nr], data->reg[nr]); \
mutex_unlock(&data->update_lock); \
return count; \
}
@@ -1654,6 +1666,48 @@ show_vid(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+/* Case open detection */
+
+static ssize_t
+show_caseopen(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w83627ehf_data *data = w83627ehf_update_device(dev);
+
+ return sprintf(buf, "%d\n",
+ !!(data->caseopen & to_sensor_dev_attr_2(attr)->index));
+}
+
+static ssize_t
+clear_caseopen(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct w83627ehf_data *data = dev_get_drvdata(dev);
+ unsigned long val;
+ u16 reg, mask;
+
+ if (strict_strtoul(buf, 10, &val) || val != 0)
+ return -EINVAL;
+
+ mask = to_sensor_dev_attr_2(attr)->nr;
+
+ mutex_lock(&data->update_lock);
+ reg = w83627ehf_read_value(data, W83627EHF_REG_CASEOPEN_CLR);
+ w83627ehf_write_value(data, W83627EHF_REG_CASEOPEN_CLR, reg | mask);
+ w83627ehf_write_value(data, W83627EHF_REG_CASEOPEN_CLR, reg & ~mask);
+ data->valid = 0; /* Force cache refresh */
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static struct sensor_device_attribute_2 sda_caseopen[] = {
+ SENSOR_ATTR_2(intrusion0_alarm, S_IWUSR | S_IRUGO, show_caseopen,
+ clear_caseopen, 0x80, 0x10),
+ SENSOR_ATTR_2(intrusion1_alarm, S_IWUSR | S_IRUGO, show_caseopen,
+ clear_caseopen, 0x40, 0x40),
+};
+
/*
* Driver and device management
*/
@@ -1710,12 +1764,16 @@ static void w83627ehf_device_remove_files(struct device *dev)
device_remove_file(dev, &sda_temp_type[i].dev_attr);
}
+ device_remove_file(dev, &sda_caseopen[0].dev_attr);
+ device_remove_file(dev, &sda_caseopen[1].dev_attr);
+
device_remove_file(dev, &dev_attr_name);
device_remove_file(dev, &dev_attr_cpu0_vid);
}
/* Get the monitoring functions started */
-static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
+static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data,
+ enum kinds kind)
{
int i;
u8 tmp, diode;
@@ -1746,10 +1804,16 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);
/* Get thermal sensor types */
- diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
+ switch (kind) {
+ case w83627ehf:
+ diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
+ break;
+ default:
+ diode = 0x70;
+ }
for (i = 0; i < 3; i++) {
if ((tmp & (0x02 << i)))
- data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 2;
+ data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 3;
else
data->temp_type[i] = 4; /* thermistor */
}
@@ -1781,13 +1845,78 @@ static void w82627ehf_swap_tempreg(struct w83627ehf_data *data,
data->reg_temp_config[r2] = tmp;
}
+static void __devinit
+w83627ehf_check_fan_inputs(const struct w83627ehf_sio_data *sio_data,
+ struct w83627ehf_data *data)
+{
+ int fan3pin, fan4pin, fan4min, fan5pin, regval;
+
+ superio_enter(sio_data->sioreg);
+
+ /* fan4 and fan5 share some pins with the GPIO and serial flash */
+ if (sio_data->kind == nct6775) {
+ /* On NCT6775, fan4 shares pins with the fdc interface */
+ fan3pin = 1;
+ fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80);
+ fan4min = 0;
+ fan5pin = 0;
+ } else if (sio_data->kind == nct6776) {
+ fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40);
+ fan4pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x01);
+ fan5pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x02);
+ fan4min = fan4pin;
+ } else if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
+ fan3pin = 1;
+ fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
+ fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
+ fan4min = fan4pin;
+ } else {
+ fan3pin = 1;
+ fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
+ fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
+ fan4min = fan4pin;
+ }
+
+ superio_exit(sio_data->sioreg);
+
+ data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */
+ data->has_fan |= (fan3pin << 2);
+ data->has_fan_min |= (fan3pin << 2);
+
+ if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
+ /*
+ * NCT6775F and NCT6776F don't have the W83627EHF_REG_FANDIV1
+ * register
+ */
+ data->has_fan |= (fan4pin << 3) | (fan5pin << 4);
+ data->has_fan_min |= (fan4min << 3) | (fan5pin << 4);
+ } else {
+ /*
+ * It looks like fan4 and fan5 pins can be alternatively used
+ * as fan on/off switches, but fan5 control is write only :/
+ * We assume that if the serial interface is disabled, designers
+ * connected fan5 as input unless they are emitting log 1, which
+ * is not the default.
+ */
+ regval = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
+ if ((regval & (1 << 2)) && fan4pin) {
+ data->has_fan |= (1 << 3);
+ data->has_fan_min |= (1 << 3);
+ }
+ if (!(regval & (1 << 1)) && fan5pin) {
+ data->has_fan |= (1 << 4);
+ data->has_fan_min |= (1 << 4);
+ }
+ }
+}
+
static int __devinit w83627ehf_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct w83627ehf_sio_data *sio_data = dev->platform_data;
struct w83627ehf_data *data;
struct resource *res;
- u8 fan3pin, fan4pin, fan4min, fan5pin, en_vrm10;
+ u8 en_vrm10;
int i, err = 0;
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
@@ -2016,7 +2145,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
}
/* Initialize the chip */
- w83627ehf_init_device(data);
+ w83627ehf_init_device(data, sio_data->kind);
data->vrm = vid_which_vrm();
superio_enter(sio_data->sioreg);
@@ -2072,30 +2201,6 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
}
}
- /* fan4 and fan5 share some pins with the GPIO and serial flash */
- if (sio_data->kind == nct6775) {
- /* On NCT6775, fan4 shares pins with the fdc interface */
- fan3pin = 1;
- fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80);
- fan4min = 0;
- fan5pin = 0;
- } else if (sio_data->kind == nct6776) {
- fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40);
- fan4pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x01);
- fan5pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x02);
- fan4min = fan4pin;
- } else if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
- fan3pin = 1;
- fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
- fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
- fan4min = fan4pin;
- } else {
- fan3pin = 1;
- fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
- fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
- fan4min = fan4pin;
- }
-
if (fan_debounce &&
(sio_data->kind == nct6775 || sio_data->kind == nct6776)) {
u8 tmp;
@@ -2113,34 +2218,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
superio_exit(sio_data->sioreg);
- /* It looks like fan4 and fan5 pins can be alternatively used
- as fan on/off switches, but fan5 control is write only :/
- We assume that if the serial interface is disabled, designers
- connected fan5 as input unless they are emitting log 1, which
- is not the default. */
-
- data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */
-
- data->has_fan |= (fan3pin << 2);
- data->has_fan_min |= (fan3pin << 2);
-
- /*
- * NCT6775F and NCT6776F don't have the W83627EHF_REG_FANDIV1 register
- */
- if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
- data->has_fan |= (fan4pin << 3) | (fan5pin << 4);
- data->has_fan_min |= (fan4min << 3) | (fan5pin << 4);
- } else {
- i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
- if ((i & (1 << 2)) && fan4pin) {
- data->has_fan |= (1 << 3);
- data->has_fan_min |= (1 << 3);
- }
- if (!(i & (1 << 1)) && fan5pin) {
- data->has_fan |= (1 << 4);
- data->has_fan_min |= (1 << 4);
- }
- }
+ w83627ehf_check_fan_inputs(sio_data, data);
/* Read fan clock dividers immediately */
w83627ehf_update_fan_div_common(dev, data);
@@ -2261,6 +2339,16 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
goto exit_remove;
}
+ err = device_create_file(dev, &sda_caseopen[0].dev_attr);
+ if (err)
+ goto exit_remove;
+
+ if (sio_data->kind == nct6776) {
+ err = device_create_file(dev, &sda_caseopen[1].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+
err = device_create_file(dev, &dev_attr_name);
if (err)
goto exit_remove;
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
index 17cf1ab95521..8c2844e5691c 100644
--- a/drivers/hwmon/w83791d.c
+++ b/drivers/hwmon/w83791d.c
@@ -329,8 +329,8 @@ static int w83791d_detect(struct i2c_client *client,
struct i2c_board_info *info);
static int w83791d_remove(struct i2c_client *client);
-static int w83791d_read(struct i2c_client *client, u8 register);
-static int w83791d_write(struct i2c_client *client, u8 register, u8 value);
+static int w83791d_read(struct i2c_client *client, u8 reg);
+static int w83791d_write(struct i2c_client *client, u8 reg, u8 value);
static struct w83791d_data *w83791d_update_device(struct device *dev);
#ifdef DEBUG
diff --git a/drivers/i2c/busses/i2c-designware.c b/drivers/i2c/busses/i2c-designware.c
index b7a51c43b185..1b42b50b5992 100644
--- a/drivers/i2c/busses/i2c-designware.c
+++ b/drivers/i2c/busses/i2c-designware.c
@@ -390,7 +390,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
int tx_limit, rx_limit;
u32 addr = msgs[dev->msg_write_idx].addr;
u32 buf_len = dev->tx_buf_len;
- u8 *buf = dev->tx_buf;;
+ u8 *buf = dev->tx_buf;
intr_mask = DW_IC_INTR_DEFAULT_MASK;
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index 0c731ca69f15..b228e09c5d05 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -146,6 +146,7 @@ struct i2c_nmk_client {
* @stop: stop condition
* @xfer_complete: acknowledge completion for a I2C message
* @result: controller propogated result
+ * @regulator: pointer to i2c regulator
* @busy: Busy doing transfer
*/
struct nmk_i2c_dev {
@@ -417,12 +418,12 @@ static int read_i2c(struct nmk_i2c_dev *dev)
writel(readl(dev->virtbase + I2C_IMSCR) | irq_mask,
dev->virtbase + I2C_IMSCR);
- timeout = wait_for_completion_interruptible_timeout(
+ timeout = wait_for_completion_timeout(
&dev->xfer_complete, dev->adap.timeout);
if (timeout < 0) {
dev_err(&dev->pdev->dev,
- "wait_for_completion_interruptible_timeout"
+ "wait_for_completion_timeout"
"returned %d waiting for event\n", timeout);
status = timeout;
}
@@ -504,12 +505,12 @@ static int write_i2c(struct nmk_i2c_dev *dev)
writel(readl(dev->virtbase + I2C_IMSCR) | irq_mask,
dev->virtbase + I2C_IMSCR);
- timeout = wait_for_completion_interruptible_timeout(
+ timeout = wait_for_completion_timeout(
&dev->xfer_complete, dev->adap.timeout);
if (timeout < 0) {
dev_err(&dev->pdev->dev,
- "wait_for_completion_interruptible_timeout"
+ "wait_for_completion_timeout "
"returned %d waiting for event\n", timeout);
status = timeout;
}
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 1a766cf74f6b..2dfb63176856 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -1139,41 +1139,12 @@ omap_i2c_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_SUSPEND
-static int omap_i2c_suspend(struct device *dev)
-{
- if (!pm_runtime_suspended(dev))
- if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend)
- dev->bus->pm->runtime_suspend(dev);
-
- return 0;
-}
-
-static int omap_i2c_resume(struct device *dev)
-{
- if (!pm_runtime_suspended(dev))
- if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume)
- dev->bus->pm->runtime_resume(dev);
-
- return 0;
-}
-
-static struct dev_pm_ops omap_i2c_pm_ops = {
- .suspend = omap_i2c_suspend,
- .resume = omap_i2c_resume,
-};
-#define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops)
-#else
-#define OMAP_I2C_PM_OPS NULL
-#endif
-
static struct platform_driver omap_i2c_driver = {
.probe = omap_i2c_probe,
.remove = omap_i2c_remove,
.driver = {
.name = "omap_i2c",
.owner = THIS_MODULE,
- .pm = OMAP_I2C_PM_OPS,
},
};
diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c
index 6659d269b841..b73da6cd6f91 100644
--- a/drivers/i2c/busses/i2c-pxa-pci.c
+++ b/drivers/i2c/busses/i2c-pxa-pci.c
@@ -109,12 +109,15 @@ static int __devinit ce4100_i2c_probe(struct pci_dev *dev,
return -EINVAL;
}
sds = kzalloc(sizeof(*sds), GFP_KERNEL);
- if (!sds)
+ if (!sds) {
+ ret = -ENOMEM;
goto err_mem;
+ }
for (i = 0; i < ARRAY_SIZE(sds->pdev); i++) {
sds->pdev[i] = add_i2c_device(dev, i);
if (IS_ERR(sds->pdev[i])) {
+ ret = PTR_ERR(sds->pdev[i]);
while (--i >= 0)
platform_device_unregister(sds->pdev[i]);
goto err_dev_add;
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 2440b7411978..3c94c4a81a55 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -270,14 +270,30 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
/* Rounds down to not include partial word at the end of buf */
words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD;
- if (words_to_transfer > tx_fifo_avail)
- words_to_transfer = tx_fifo_avail;
- i2c_writesl(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer);
-
- buf += words_to_transfer * BYTES_PER_FIFO_WORD;
- buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD;
- tx_fifo_avail -= words_to_transfer;
+ /* It's very common to have < 4 bytes, so optimize that case. */
+ if (words_to_transfer) {
+ if (words_to_transfer > tx_fifo_avail)
+ words_to_transfer = tx_fifo_avail;
+
+ /*
+ * Update state before writing to FIFO. If this casues us
+ * to finish writing all bytes (AKA buf_remaining goes to 0) we
+ * have a potential for an interrupt (PACKET_XFER_COMPLETE is
+ * not maskable). We need to make sure that the isr sees
+ * buf_remaining as 0 and doesn't call us back re-entrantly.
+ */
+ buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD;
+ tx_fifo_avail -= words_to_transfer;
+ i2c_dev->msg_buf_remaining = buf_remaining;
+ i2c_dev->msg_buf = buf +
+ words_to_transfer * BYTES_PER_FIFO_WORD;
+ barrier();
+
+ i2c_writesl(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer);
+
+ buf += words_to_transfer * BYTES_PER_FIFO_WORD;
+ }
/*
* If there is a partial word at the end of buf, handle it manually to
@@ -287,14 +303,15 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
if (tx_fifo_avail > 0 && buf_remaining > 0) {
BUG_ON(buf_remaining > 3);
memcpy(&val, buf, buf_remaining);
+
+ /* Again update before writing to FIFO to make sure isr sees. */
+ i2c_dev->msg_buf_remaining = 0;
+ i2c_dev->msg_buf = NULL;
+ barrier();
+
i2c_writel(i2c_dev, val, I2C_TX_FIFO);
- buf_remaining = 0;
- tx_fifo_avail--;
}
- BUG_ON(tx_fifo_avail > 0 && buf_remaining > 0);
- i2c_dev->msg_buf_remaining = buf_remaining;
- i2c_dev->msg_buf = buf;
return 0;
}
@@ -411,9 +428,10 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
tegra_i2c_mask_irq(i2c_dev, I2C_INT_TX_FIFO_DATA_REQ);
}
- if ((status & I2C_INT_PACKET_XFER_COMPLETE) &&
- !i2c_dev->msg_buf_remaining)
+ if (status & I2C_INT_PACKET_XFER_COMPLETE) {
+ BUG_ON(i2c_dev->msg_buf_remaining);
complete(&i2c_dev->msg_complete);
+ }
i2c_writel(i2c_dev, status, I2C_INT_STATUS);
if (i2c_dev->is_dvc)
@@ -531,7 +549,7 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
static u32 tegra_i2c_func(struct i2c_adapter *adap)
{
- return I2C_FUNC_I2C;
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
static const struct i2c_algorithm tegra_i2c_algo = {
@@ -719,6 +737,17 @@ static int tegra_i2c_resume(struct platform_device *pdev)
}
#endif
+#if defined(CONFIG_OF)
+/* Match table for of_platform binding */
+static const struct of_device_id tegra_i2c_of_match[] __devinitconst = {
+ { .compatible = "nvidia,tegra20-i2c", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, tegra_i2c_of_match);
+#else
+#define tegra_i2c_of_match NULL
+#endif
+
static struct platform_driver tegra_i2c_driver = {
.probe = tegra_i2c_probe,
.remove = tegra_i2c_remove,
@@ -729,6 +758,7 @@ static struct platform_driver tegra_i2c_driver = {
.driver = {
.name = "tegra-i2c",
.owner = THIS_MODULE,
+ .of_match_table = tegra_i2c_of_match,
},
};
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 9827c5e686cb..76b6d98bd295 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -327,7 +327,7 @@ config BLK_DEV_OPTI621
select BLK_DEV_IDEPCI
help
This is a driver for the OPTi 82C621 EIDE controller.
- Please read the comments at the top of <file:drivers/ide/pci/opti621.c>.
+ Please read the comments at the top of <file:drivers/ide/opti621.c>.
config BLK_DEV_RZ1000
tristate "RZ1000 chipset bugfix/support"
@@ -365,7 +365,7 @@ config BLK_DEV_ALI15X3
normal dual channel support.
Please read the comments at the top of
- <file:drivers/ide/pci/alim15x3.c>.
+ <file:drivers/ide/alim15x3.c>.
If unsure, say N.
@@ -528,7 +528,7 @@ config BLK_DEV_NS87415
This driver adds detection and support for the NS87415 chip
(used mainly on SPARC64 and PA-RISC machines).
- Please read the comments at the top of <file:drivers/ide/pci/ns87415.c>.
+ Please read the comments at the top of <file:drivers/ide/ns87415.c>.
config BLK_DEV_PDC202XX_OLD
tristate "PROMISE PDC202{46|62|65|67} support"
@@ -547,7 +547,7 @@ config BLK_DEV_PDC202XX_OLD
for more than one card.
Please read the comments at the top of
- <file:drivers/ide/pci/pdc202xx_old.c>.
+ <file:drivers/ide/pdc202xx_old.c>.
If unsure, say N.
@@ -593,7 +593,7 @@ config BLK_DEV_SIS5513
ATA100: SiS635, SiS645, SiS650, SiS730, SiS735, SiS740,
SiS745, SiS750
- Please read the comments at the top of <file:drivers/ide/pci/sis5513.c>.
+ Please read the comments at the top of <file:drivers/ide/sis5513.c>.
config BLK_DEV_SL82C105
tristate "Winbond SL82c105 support"
@@ -616,7 +616,7 @@ config BLK_DEV_SLC90E66
look-a-like to the PIIX4 it should be a nice addition.
Please read the comments at the top of
- <file:drivers/ide/pci/slc90e66.c>.
+ <file:drivers/ide/slc90e66.c>.
config BLK_DEV_TRM290
tristate "Tekram TRM290 chipset support"
@@ -625,7 +625,7 @@ config BLK_DEV_TRM290
This driver adds support for bus master DMA transfers
using the Tekram TRM290 PCI IDE chip. Volunteers are
needed for further tweaking and development.
- Please read the comments at the top of <file:drivers/ide/pci/trm290.c>.
+ Please read the comments at the top of <file:drivers/ide/trm290.c>.
config BLK_DEV_VIA82CXXX
tristate "VIA82CXXX chipset support"
@@ -681,7 +681,7 @@ config BLK_DEV_IDE_AU1XXX
select IDE_XFER_MODE
choice
prompt "IDE Mode for AMD Alchemy Au1200"
- default CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA
+ default BLK_DEV_IDE_AU1XXX_PIO_DBDMA
depends on SOC_AU1200 && BLK_DEV_IDE_AU1XXX
config BLK_DEV_IDE_AU1XXX_PIO_DBDMA
@@ -836,7 +836,7 @@ config BLK_DEV_ALI14XX
of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
I/O speeds to be set as well.
See the files <file:Documentation/ide/ide.txt> and
- <file:drivers/ide/legacy/ali14xx.c> for more info.
+ <file:drivers/ide/ali14xx.c> for more info.
config BLK_DEV_DTC2278
tristate "DTC-2278 support"
@@ -847,7 +847,7 @@ config BLK_DEV_DTC2278
boot parameter. It enables support for the secondary IDE interface
of the DTC-2278 card, and permits faster I/O speeds to be set as
well. See the <file:Documentation/ide/ide.txt> and
- <file:drivers/ide/legacy/dtc2278.c> files for more info.
+ <file:drivers/ide/dtc2278.c> files for more info.
config BLK_DEV_HT6560B
tristate "Holtek HT6560B support"
@@ -858,7 +858,7 @@ config BLK_DEV_HT6560B
boot parameter. It enables support for the secondary IDE interface
of the Holtek card, and permits faster I/O speeds to be set as well.
See the <file:Documentation/ide/ide.txt> and
- <file:drivers/ide/legacy/ht6560b.c> files for more info.
+ <file:drivers/ide/ht6560b.c> files for more info.
config BLK_DEV_QD65XX
tristate "QDI QD65xx support"
@@ -867,7 +867,7 @@ config BLK_DEV_QD65XX
help
This driver is enabled at runtime using the "qd65xx.probe" kernel
boot parameter. It permits faster I/O speeds to be set. See the
- <file:Documentation/ide/ide.txt> and <file:drivers/ide/legacy/qd65xx.c>
+ <file:Documentation/ide/ide.txt> and <file:drivers/ide/qd65xx.c>
for more info.
config BLK_DEV_UMC8672
@@ -879,7 +879,7 @@ config BLK_DEV_UMC8672
boot parameter. It enables support for the secondary IDE interface
of the UMC-8672, and permits faster I/O speeds to be set as well.
See the files <file:Documentation/ide/ide.txt> and
- <file:drivers/ide/legacy/umc8672.c> for more info.
+ <file:drivers/ide/umc8672.c> for more info.
endif
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 274798068a54..16f69be820c7 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -435,7 +435,12 @@ static int idedisk_prep_fn(struct request_queue *q, struct request *rq)
if (!(rq->cmd_flags & REQ_FLUSH))
return BLKPREP_OK;
- cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
+ if (rq->special) {
+ cmd = rq->special;
+ memset(cmd, 0, sizeof(*cmd));
+ } else {
+ cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
+ }
/* FIXME: map struct ide_taskfile on rq->cmd[] */
BUG_ON(cmd == NULL);
diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c
index 444470a28de2..5ce7b9e8bff6 100644
--- a/drivers/infiniband/hw/amso1100/c2.c
+++ b/drivers/infiniband/hw/amso1100/c2.c
@@ -800,13 +800,10 @@ static int c2_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
/* Loop thru additional data fragments and queue them */
if (skb_shinfo(skb)->nr_frags) {
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- maplen = frag->size;
- mapaddr =
- pci_map_page(c2dev->pcidev, frag->page,
- frag->page_offset, maplen,
- PCI_DMA_TODEVICE);
-
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ maplen = skb_frag_size(frag);
+ mapaddr = skb_frag_dma_map(&c2dev->pcidev->dev, frag,
+ 0, maplen, DMA_TO_DEVICE);
elem = elem->next;
elem->skb = NULL;
elem->mapaddr = mapaddr;
diff --git a/drivers/infiniband/hw/cxgb3/Makefile b/drivers/infiniband/hw/cxgb3/Makefile
index 621619c794e5..2761364185af 100644
--- a/drivers/infiniband/hw/cxgb3/Makefile
+++ b/drivers/infiniband/hw/cxgb3/Makefile
@@ -1,4 +1,4 @@
-ccflags-y := -Idrivers/net/cxgb3
+ccflags-y := -Idrivers/net/ethernet/chelsio/cxgb3
obj-$(CONFIG_INFINIBAND_CXGB3) += iw_cxgb3.o
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index 17bf9d95463c..6cd642aaa4de 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -287,7 +287,7 @@ void __free_ep(struct kref *kref)
if (test_bit(RELEASE_RESOURCES, &ep->com.flags)) {
cxgb3_remove_tid(ep->com.tdev, (void *)ep, ep->hwtid);
dst_release(ep->dst);
- l2t_release(L2DATA(ep->com.tdev), ep->l2t);
+ l2t_release(ep->com.tdev, ep->l2t);
}
kfree(ep);
}
@@ -1178,7 +1178,7 @@ static int act_open_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
release_tid(ep->com.tdev, GET_TID(rpl), NULL);
cxgb3_free_atid(ep->com.tdev, ep->atid);
dst_release(ep->dst);
- l2t_release(L2DATA(ep->com.tdev), ep->l2t);
+ l2t_release(ep->com.tdev, ep->l2t);
put_ep(&ep->com);
return CPL_RET_BUF_DONE;
}
@@ -1377,7 +1377,7 @@ static int pass_accept_req(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
if (!child_ep) {
printk(KERN_ERR MOD "%s - failed to allocate ep entry!\n",
__func__);
- l2t_release(L2DATA(tdev), l2t);
+ l2t_release(tdev, l2t);
dst_release(dst);
goto reject;
}
@@ -1956,7 +1956,7 @@ int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
if (!err)
goto out;
- l2t_release(L2DATA(h->rdev.t3cdev_p), ep->l2t);
+ l2t_release(h->rdev.t3cdev_p, ep->l2t);
fail4:
dst_release(ep->dst);
fail3:
@@ -2127,7 +2127,7 @@ int iwch_ep_redirect(void *ctx, struct dst_entry *old, struct dst_entry *new,
PDBG("%s ep %p redirect to dst %p l2t %p\n", __func__, ep, new,
l2t);
dst_hold(new);
- l2t_release(L2DATA(ep->com.tdev), ep->l2t);
+ l2t_release(ep->com.tdev, ep->l2t);
ep->l2t = l2t;
dst_release(old);
ep->dst = new;
diff --git a/drivers/infiniband/hw/cxgb4/Makefile b/drivers/infiniband/hw/cxgb4/Makefile
index cd20b1342aec..46b878ca2c3b 100644
--- a/drivers/infiniband/hw/cxgb4/Makefile
+++ b/drivers/infiniband/hw/cxgb4/Makefile
@@ -1,4 +1,4 @@
-ccflags-y := -Idrivers/net/cxgb4
+ccflags-y := -Idrivers/net/ethernet/chelsio/cxgb4
obj-$(CONFIG_INFINIBAND_CXGB4) += iw_cxgb4.o
diff --git a/drivers/infiniband/hw/mlx4/Kconfig b/drivers/infiniband/hw/mlx4/Kconfig
index bd995b2b50d8..24ab11a9ad1e 100644
--- a/drivers/infiniband/hw/mlx4/Kconfig
+++ b/drivers/infiniband/hw/mlx4/Kconfig
@@ -1,6 +1,7 @@
config MLX4_INFINIBAND
tristate "Mellanox ConnectX HCA support"
- depends on NETDEVICES && NETDEV_10000 && PCI
+ depends on NETDEVICES && ETHERNET && PCI
+ select NET_VENDOR_MELLANOX
select MLX4_CORE
---help---
This driver provides low-level InfiniBand support for
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index 9d7ffebff213..47b2ee4c01e2 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -441,13 +441,13 @@ static int nes_nic_send(struct sk_buff *skb, struct net_device *netdev)
nesnic->tx_skb[nesnic->sq_head] = skb;
for (skb_fragment_index = 0; skb_fragment_index < skb_shinfo(skb)->nr_frags;
skb_fragment_index++) {
- bus_address = pci_map_page( nesdev->pcidev,
- skb_shinfo(skb)->frags[skb_fragment_index].page,
- skb_shinfo(skb)->frags[skb_fragment_index].page_offset,
- skb_shinfo(skb)->frags[skb_fragment_index].size,
- PCI_DMA_TODEVICE);
+ skb_frag_t *frag =
+ &skb_shinfo(skb)->frags[skb_fragment_index];
+ bus_address = skb_frag_dma_map(&nesdev->pcidev->dev,
+ frag, 0, skb_frag_size(frag),
+ DMA_TO_DEVICE);
wqe_fragment_length[wqe_fragment_index] =
- cpu_to_le16(skb_shinfo(skb)->frags[skb_fragment_index].size);
+ cpu_to_le16(skb_frag_size(&skb_shinfo(skb)->frags[skb_fragment_index]));
set_wqe_64bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_FRAG0_LOW_IDX+(2*wqe_fragment_index),
bus_address);
wqe_fragment_index++;
@@ -561,11 +561,12 @@ tso_sq_no_longer_full:
/* Map all the buffers */
for (tso_frag_count=0; tso_frag_count < skb_shinfo(skb)->nr_frags;
tso_frag_count++) {
- tso_bus_address[tso_frag_count] = pci_map_page( nesdev->pcidev,
- skb_shinfo(skb)->frags[tso_frag_count].page,
- skb_shinfo(skb)->frags[tso_frag_count].page_offset,
- skb_shinfo(skb)->frags[tso_frag_count].size,
- PCI_DMA_TODEVICE);
+ skb_frag_t *frag =
+ &skb_shinfo(skb)->frags[tso_frag_count];
+ tso_bus_address[tso_frag_count] =
+ skb_frag_dma_map(&nesdev->pcidev->dev,
+ frag, 0, skb_frag_size(frag),
+ DMA_TO_DEVICE);
}
tso_frag_index = 0;
@@ -636,11 +637,11 @@ tso_sq_no_longer_full:
}
while (wqe_fragment_index < 5) {
wqe_fragment_length[wqe_fragment_index] =
- cpu_to_le16(skb_shinfo(skb)->frags[tso_frag_index].size);
+ cpu_to_le16(skb_frag_size(&skb_shinfo(skb)->frags[tso_frag_index]));
set_wqe_64bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_FRAG0_LOW_IDX+(2*wqe_fragment_index),
(u64)tso_bus_address[tso_frag_index]);
wqe_fragment_index++;
- tso_wqe_length += skb_shinfo(skb)->frags[tso_frag_index++].size;
+ tso_wqe_length += skb_frag_size(&skb_shinfo(skb)->frags[tso_frag_index++]);
if (wqe_fragment_index < 5)
wqe_fragment_length[wqe_fragment_index] = 0;
if (tso_frag_index == tso_frag_count)
@@ -1638,7 +1639,7 @@ static const struct net_device_ops nes_netdev_ops = {
.ndo_get_stats = nes_netdev_get_stats,
.ndo_tx_timeout = nes_netdev_tx_timeout,
.ndo_set_mac_address = nes_netdev_set_mac_address,
- .ndo_set_multicast_list = nes_netdev_set_multicast_list,
+ .ndo_set_rx_mode = nes_netdev_set_multicast_list,
.ndo_change_mtu = nes_netdev_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_fix_features = nes_fix_features,
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 39913a065f99..c74548a586ea 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -169,7 +169,7 @@ static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev,
goto partial_error;
skb_fill_page_desc(skb, i, page, 0, PAGE_SIZE);
- mapping[i + 1] = ib_dma_map_page(priv->ca, skb_shinfo(skb)->frags[i].page,
+ mapping[i + 1] = ib_dma_map_page(priv->ca, page,
0, PAGE_SIZE, DMA_FROM_DEVICE);
if (unlikely(ib_dma_mapping_error(priv->ca, mapping[i + 1])))
goto partial_error;
@@ -537,12 +537,13 @@ static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space,
if (length == 0) {
/* don't need this page */
- skb_fill_page_desc(toskb, i, frag->page, 0, PAGE_SIZE);
+ skb_fill_page_desc(toskb, i, skb_frag_page(frag),
+ 0, PAGE_SIZE);
--skb_shinfo(skb)->nr_frags;
} else {
size = min(length, (unsigned) PAGE_SIZE);
- frag->size = size;
+ skb_frag_size_set(frag, size);
skb->data_len += size;
skb->truesize += size;
skb->len += size;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 81ae61d68a22..2b060f45bec3 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -117,7 +117,7 @@ static void ipoib_ud_skb_put_frags(struct ipoib_dev_priv *priv,
size = length - IPOIB_UD_HEAD_SIZE;
- frag->size = size;
+ skb_frag_size_set(frag, size);
skb->data_len += size;
skb->truesize += size;
} else
@@ -182,7 +182,7 @@ static struct sk_buff *ipoib_alloc_rx_skb(struct net_device *dev, int id)
goto partial_error;
skb_fill_page_desc(skb, 0, page, 0, PAGE_SIZE);
mapping[1] =
- ib_dma_map_page(priv->ca, skb_shinfo(skb)->frags[0].page,
+ ib_dma_map_page(priv->ca, page,
0, PAGE_SIZE, DMA_FROM_DEVICE);
if (unlikely(ib_dma_mapping_error(priv->ca, mapping[1])))
goto partial_error;
@@ -322,9 +322,10 @@ static int ipoib_dma_map_tx(struct ib_device *ca,
off = 0;
for (i = 0; i < skb_shinfo(skb)->nr_frags; ++i) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- mapping[i + off] = ib_dma_map_page(ca, frag->page,
- frag->page_offset, frag->size,
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ mapping[i + off] = ib_dma_map_page(ca,
+ skb_frag_page(frag),
+ frag->page_offset, skb_frag_size(frag),
DMA_TO_DEVICE);
if (unlikely(ib_dma_mapping_error(ca, mapping[i + off])))
goto partial_error;
@@ -333,8 +334,9 @@ static int ipoib_dma_map_tx(struct ib_device *ca,
partial_error:
for (; i > 0; --i) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1];
- ib_dma_unmap_page(ca, mapping[i - !off], frag->size, DMA_TO_DEVICE);
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1];
+
+ ib_dma_unmap_page(ca, mapping[i - !off], skb_frag_size(frag), DMA_TO_DEVICE);
}
if (off)
@@ -358,8 +360,9 @@ static void ipoib_dma_unmap_tx(struct ib_device *ca,
off = 0;
for (i = 0; i < skb_shinfo(skb)->nr_frags; ++i) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- ib_dma_unmap_page(ca, mapping[i + off], frag->size,
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+ ib_dma_unmap_page(ca, mapping[i + off], skb_frag_size(frag),
DMA_TO_DEVICE);
}
}
@@ -509,7 +512,7 @@ static inline int post_send(struct ipoib_dev_priv *priv,
for (i = 0; i < nr_frags; ++i) {
priv->tx_sge[i + off].addr = mapping[i + off];
- priv->tx_sge[i + off].length = frags[i].size;
+ priv->tx_sge[i + off].length = skb_frag_size(&frags[i]);
}
priv->tx_wr.num_sge = nr_frags + off;
priv->tx_wr.wr_id = wr_id;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index fe89c4660d55..7567b6000230 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -998,7 +998,7 @@ static const struct net_device_ops ipoib_netdev_ops = {
.ndo_fix_features = ipoib_fix_features,
.ndo_start_xmit = ipoib_start_xmit,
.ndo_tx_timeout = ipoib_timeout,
- .ndo_set_multicast_list = ipoib_set_mcast_list,
+ .ndo_set_rx_mode = ipoib_set_mcast_list,
.ndo_neigh_setup = ipoib_neigh_setup_dev,
};
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index 9882971827e6..358cd7ee905b 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -139,7 +139,7 @@ struct analog_port {
#include <linux/i8253.h>
#define GET_TIME(x) do { if (cpu_has_tsc) rdtscl(x); else x = get_time_pit(); } while (0)
-#define DELTA(x,y) (cpu_has_tsc ? ((y) - (x)) : ((x) - (y) + ((x) < (y) ? CLOCK_TICK_RATE / HZ : 0)))
+#define DELTA(x,y) (cpu_has_tsc ? ((y) - (x)) : ((x) - (y) + ((x) < (y) ? PIT_TICK_RATE / HZ : 0)))
#define TIME_NAME (cpu_has_tsc?"TSC":"PIT")
static unsigned int get_time_pit(void)
{
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
index 7b404e5443ed..e34eeb8ae371 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -668,4 +668,3 @@ module_exit(adp5588_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("ADP5588/87 Keypad driver");
-MODULE_ALIAS("platform:adp5588-keys");
diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c
index c8242dd190d0..aa17e024d803 100644
--- a/drivers/input/keyboard/ep93xx_keypad.c
+++ b/drivers/input/keyboard/ep93xx_keypad.c
@@ -20,6 +20,7 @@
* flag.
*/
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
index f270447ba951..a5a77915c650 100644
--- a/drivers/input/keyboard/tegra-kbc.c
+++ b/drivers/input/keyboard/tegra-kbc.c
@@ -702,7 +702,7 @@ err_iounmap:
err_free_mem_region:
release_mem_region(res->start, resource_size(res));
err_free_mem:
- input_free_device(kbc->idev);
+ input_free_device(input_dev);
kfree(kbc);
return err;
diff --git a/drivers/input/misc/ad714x-i2c.c b/drivers/input/misc/ad714x-i2c.c
index e21deb1baa8a..025417d74ca2 100644
--- a/drivers/input/misc/ad714x-i2c.c
+++ b/drivers/input/misc/ad714x-i2c.c
@@ -1,7 +1,7 @@
/*
* AD714X CapTouch Programmable Controller driver (I2C bus)
*
- * Copyright 2009 Analog Devices Inc.
+ * Copyright 2009-2011 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
@@ -27,54 +27,49 @@ static int ad714x_i2c_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(ad714x_i2c_pm, ad714x_i2c_suspend, ad714x_i2c_resume);
-static int ad714x_i2c_write(struct device *dev, unsigned short reg,
- unsigned short data)
+static int ad714x_i2c_write(struct ad714x_chip *chip,
+ unsigned short reg, unsigned short data)
{
- struct i2c_client *client = to_i2c_client(dev);
- int ret = 0;
- u8 *_reg = (u8 *)&reg;
- u8 *_data = (u8 *)&data;
-
- u8 tx[4] = {
- _reg[1],
- _reg[0],
- _data[1],
- _data[0]
- };
-
- ret = i2c_master_send(client, tx, 4);
- if (ret < 0)
- dev_err(&client->dev, "I2C write error\n");
-
- return ret;
+ struct i2c_client *client = to_i2c_client(chip->dev);
+ int error;
+
+ chip->xfer_buf[0] = cpu_to_be16(reg);
+ chip->xfer_buf[1] = cpu_to_be16(data);
+
+ error = i2c_master_send(client, (u8 *)chip->xfer_buf,
+ 2 * sizeof(*chip->xfer_buf));
+ if (unlikely(error < 0)) {
+ dev_err(&client->dev, "I2C write error: %d\n", error);
+ return error;
+ }
+
+ return 0;
}
-static int ad714x_i2c_read(struct device *dev, unsigned short reg,
- unsigned short *data)
+static int ad714x_i2c_read(struct ad714x_chip *chip,
+ unsigned short reg, unsigned short *data, size_t len)
{
- struct i2c_client *client = to_i2c_client(dev);
- int ret = 0;
- u8 *_reg = (u8 *)&reg;
- u8 *_data = (u8 *)data;
-
- u8 tx[2] = {
- _reg[1],
- _reg[0]
- };
- u8 rx[2];
-
- ret = i2c_master_send(client, tx, 2);
- if (ret >= 0)
- ret = i2c_master_recv(client, rx, 2);
-
- if (unlikely(ret < 0)) {
- dev_err(&client->dev, "I2C read error\n");
- } else {
- _data[0] = rx[1];
- _data[1] = rx[0];
+ struct i2c_client *client = to_i2c_client(chip->dev);
+ int i;
+ int error;
+
+ chip->xfer_buf[0] = cpu_to_be16(reg);
+
+ error = i2c_master_send(client, (u8 *)chip->xfer_buf,
+ sizeof(*chip->xfer_buf));
+ if (error >= 0)
+ error = i2c_master_recv(client, (u8 *)chip->xfer_buf,
+ len * sizeof(*chip->xfer_buf));
+
+ if (unlikely(error < 0)) {
+ dev_err(&client->dev, "I2C read error: %d\n", error);
+ return error;
}
- return ret;
+ for (i = 0; i < len; i++)
+ data[i] = be16_to_cpu(chip->xfer_buf[i]);
+
+ return 0;
}
static int __devinit ad714x_i2c_probe(struct i2c_client *client,
diff --git a/drivers/input/misc/ad714x-spi.c b/drivers/input/misc/ad714x-spi.c
index 4120dd549305..875b50811361 100644
--- a/drivers/input/misc/ad714x-spi.c
+++ b/drivers/input/misc/ad714x-spi.c
@@ -1,12 +1,12 @@
/*
* AD714X CapTouch Programmable Controller driver (SPI bus)
*
- * Copyright 2009 Analog Devices Inc.
+ * Copyright 2009-2011 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
-#include <linux/input.h> /* BUS_I2C */
+#include <linux/input.h> /* BUS_SPI */
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/pm.h>
@@ -30,30 +30,68 @@ static int ad714x_spi_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(ad714x_spi_pm, ad714x_spi_suspend, ad714x_spi_resume);
-static int ad714x_spi_read(struct device *dev, unsigned short reg,
- unsigned short *data)
+static int ad714x_spi_read(struct ad714x_chip *chip,
+ unsigned short reg, unsigned short *data, size_t len)
{
- struct spi_device *spi = to_spi_device(dev);
- unsigned short tx = AD714x_SPI_CMD_PREFIX | AD714x_SPI_READ | reg;
+ struct spi_device *spi = to_spi_device(chip->dev);
+ struct spi_message message;
+ struct spi_transfer xfer[2];
+ int i;
+ int error;
+
+ spi_message_init(&message);
+ memset(xfer, 0, sizeof(xfer));
+
+ chip->xfer_buf[0] = cpu_to_be16(AD714x_SPI_CMD_PREFIX |
+ AD714x_SPI_READ | reg);
+ xfer[0].tx_buf = &chip->xfer_buf[0];
+ xfer[0].len = sizeof(chip->xfer_buf[0]);
+ spi_message_add_tail(&xfer[0], &message);
+
+ xfer[1].rx_buf = &chip->xfer_buf[1];
+ xfer[1].len = sizeof(chip->xfer_buf[1]) * len;
+ spi_message_add_tail(&xfer[1], &message);
+
+ error = spi_sync(spi, &message);
+ if (unlikely(error)) {
+ dev_err(chip->dev, "SPI read error: %d\n", error);
+ return error;
+ }
+
+ for (i = 0; i < len; i++)
+ data[i] = be16_to_cpu(chip->xfer_buf[i + 1]);
- return spi_write_then_read(spi, (u8 *)&tx, 2, (u8 *)data, 2);
+ return 0;
}
-static int ad714x_spi_write(struct device *dev, unsigned short reg,
- unsigned short data)
+static int ad714x_spi_write(struct ad714x_chip *chip,
+ unsigned short reg, unsigned short data)
{
- struct spi_device *spi = to_spi_device(dev);
- unsigned short tx[2] = {
- AD714x_SPI_CMD_PREFIX | reg,
- data
- };
+ struct spi_device *spi = to_spi_device(chip->dev);
+ int error;
+
+ chip->xfer_buf[0] = cpu_to_be16(AD714x_SPI_CMD_PREFIX | reg);
+ chip->xfer_buf[1] = cpu_to_be16(data);
+
+ error = spi_write(spi, (u8 *)chip->xfer_buf,
+ 2 * sizeof(*chip->xfer_buf));
+ if (unlikely(error)) {
+ dev_err(chip->dev, "SPI write error: %d\n", error);
+ return error;
+ }
- return spi_write(spi, (u8 *)tx, 4);
+ return 0;
}
static int __devinit ad714x_spi_probe(struct spi_device *spi)
{
struct ad714x_chip *chip;
+ int err;
+
+ spi->bits_per_word = 8;
+ err = spi_setup(spi);
+ if (err < 0)
+ return err;
chip = ad714x_probe(&spi->dev, BUS_SPI, spi->irq,
ad714x_spi_read, ad714x_spi_write);
diff --git a/drivers/input/misc/ad714x.c b/drivers/input/misc/ad714x.c
index c3a62c42cd28..ca42c7d2a3c7 100644
--- a/drivers/input/misc/ad714x.c
+++ b/drivers/input/misc/ad714x.c
@@ -1,7 +1,7 @@
/*
* AD714X CapTouch Programmable Controller driver supporting AD7142/3/7/8/7A
*
- * Copyright 2009 Analog Devices Inc.
+ * Copyright 2009-2011 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
@@ -59,7 +59,6 @@
#define STAGE11_AMBIENT 0x27D
#define PER_STAGE_REG_NUM 36
-#define STAGE_NUM 12
#define STAGE_CFGREG_NUM 8
#define SYS_CFGREG_NUM 8
@@ -124,27 +123,6 @@ struct ad714x_driver_data {
* information to integrate all things which will be private data
* of spi/i2c device
*/
-struct ad714x_chip {
- unsigned short h_state;
- unsigned short l_state;
- unsigned short c_state;
- unsigned short adc_reg[STAGE_NUM];
- unsigned short amb_reg[STAGE_NUM];
- unsigned short sensor_val[STAGE_NUM];
-
- struct ad714x_platform_data *hw;
- struct ad714x_driver_data *sw;
-
- int irq;
- struct device *dev;
- ad714x_read_t read;
- ad714x_write_t write;
-
- struct mutex mutex;
-
- unsigned product;
- unsigned version;
-};
static void ad714x_use_com_int(struct ad714x_chip *ad714x,
int start_stage, int end_stage)
@@ -154,13 +132,13 @@ static void ad714x_use_com_int(struct ad714x_chip *ad714x,
mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);
- ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data);
+ ad714x->read(ad714x, STG_COM_INT_EN_REG, &data, 1);
data |= 1 << end_stage;
- ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data);
+ ad714x->write(ad714x, STG_COM_INT_EN_REG, data);
- ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data);
+ ad714x->read(ad714x, STG_HIGH_INT_EN_REG, &data, 1);
data &= ~mask;
- ad714x->write(ad714x->dev, STG_HIGH_INT_EN_REG, data);
+ ad714x->write(ad714x, STG_HIGH_INT_EN_REG, data);
}
static void ad714x_use_thr_int(struct ad714x_chip *ad714x,
@@ -171,13 +149,13 @@ static void ad714x_use_thr_int(struct ad714x_chip *ad714x,
mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);
- ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data);
+ ad714x->read(ad714x, STG_COM_INT_EN_REG, &data, 1);
data &= ~(1 << end_stage);
- ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data);
+ ad714x->write(ad714x, STG_COM_INT_EN_REG, data);
- ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data);
+ ad714x->read(ad714x, STG_HIGH_INT_EN_REG, &data, 1);
data |= mask;
- ad714x->write(ad714x->dev, STG_HIGH_INT_EN_REG, data);
+ ad714x->write(ad714x, STG_HIGH_INT_EN_REG, data);
}
static int ad714x_cal_highest_stage(struct ad714x_chip *ad714x,
@@ -273,15 +251,16 @@ static void ad714x_slider_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
int i;
+ ad714x->read(ad714x, CDC_RESULT_S0 + hw->start_stage,
+ &ad714x->adc_reg[hw->start_stage],
+ hw->end_stage - hw->start_stage + 1);
+
for (i = hw->start_stage; i <= hw->end_stage; i++) {
- ad714x->read(ad714x->dev, CDC_RESULT_S0 + i,
- &ad714x->adc_reg[i]);
- ad714x->read(ad714x->dev,
- STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
- &ad714x->amb_reg[i]);
-
- ad714x->sensor_val[i] = abs(ad714x->adc_reg[i] -
- ad714x->amb_reg[i]);
+ ad714x->read(ad714x, STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
+ &ad714x->amb_reg[i], 1);
+
+ ad714x->sensor_val[i] =
+ abs(ad714x->adc_reg[i] - ad714x->amb_reg[i]);
}
}
@@ -444,15 +423,16 @@ static void ad714x_wheel_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
int i;
+ ad714x->read(ad714x, CDC_RESULT_S0 + hw->start_stage,
+ &ad714x->adc_reg[hw->start_stage],
+ hw->end_stage - hw->start_stage + 1);
+
for (i = hw->start_stage; i <= hw->end_stage; i++) {
- ad714x->read(ad714x->dev, CDC_RESULT_S0 + i,
- &ad714x->adc_reg[i]);
- ad714x->read(ad714x->dev,
- STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
- &ad714x->amb_reg[i]);
+ ad714x->read(ad714x, STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
+ &ad714x->amb_reg[i], 1);
if (ad714x->adc_reg[i] > ad714x->amb_reg[i])
- ad714x->sensor_val[i] = ad714x->adc_reg[i] -
- ad714x->amb_reg[i];
+ ad714x->sensor_val[i] =
+ ad714x->adc_reg[i] - ad714x->amb_reg[i];
else
ad714x->sensor_val[i] = 0;
}
@@ -597,15 +577,16 @@ static void touchpad_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
int i;
+ ad714x->read(ad714x, CDC_RESULT_S0 + hw->x_start_stage,
+ &ad714x->adc_reg[hw->x_start_stage],
+ hw->x_end_stage - hw->x_start_stage + 1);
+
for (i = hw->x_start_stage; i <= hw->x_end_stage; i++) {
- ad714x->read(ad714x->dev, CDC_RESULT_S0 + i,
- &ad714x->adc_reg[i]);
- ad714x->read(ad714x->dev,
- STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
- &ad714x->amb_reg[i]);
+ ad714x->read(ad714x, STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
+ &ad714x->amb_reg[i], 1);
if (ad714x->adc_reg[i] > ad714x->amb_reg[i])
- ad714x->sensor_val[i] = ad714x->adc_reg[i] -
- ad714x->amb_reg[i];
+ ad714x->sensor_val[i] =
+ ad714x->adc_reg[i] - ad714x->amb_reg[i];
else
ad714x->sensor_val[i] = 0;
}
@@ -891,7 +872,7 @@ static int ad714x_hw_detect(struct ad714x_chip *ad714x)
{
unsigned short data;
- ad714x->read(ad714x->dev, AD714X_PARTID_REG, &data);
+ ad714x->read(ad714x, AD714X_PARTID_REG, &data, 1);
switch (data & 0xFFF0) {
case AD7142_PARTID:
ad714x->product = 0x7142;
@@ -940,23 +921,20 @@ static void ad714x_hw_init(struct ad714x_chip *ad714x)
for (i = 0; i < STAGE_NUM; i++) {
reg_base = AD714X_STAGECFG_REG + i * STAGE_CFGREG_NUM;
for (j = 0; j < STAGE_CFGREG_NUM; j++)
- ad714x->write(ad714x->dev, reg_base + j,
+ ad714x->write(ad714x, reg_base + j,
ad714x->hw->stage_cfg_reg[i][j]);
}
for (i = 0; i < SYS_CFGREG_NUM; i++)
- ad714x->write(ad714x->dev, AD714X_SYSCFG_REG + i,
+ ad714x->write(ad714x, AD714X_SYSCFG_REG + i,
ad714x->hw->sys_cfg_reg[i]);
for (i = 0; i < SYS_CFGREG_NUM; i++)
- ad714x->read(ad714x->dev, AD714X_SYSCFG_REG + i,
- &data);
+ ad714x->read(ad714x, AD714X_SYSCFG_REG + i, &data, 1);
- ad714x->write(ad714x->dev, AD714X_STG_CAL_EN_REG, 0xFFF);
+ ad714x->write(ad714x, AD714X_STG_CAL_EN_REG, 0xFFF);
/* clear all interrupts */
- ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &data);
- ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &data);
- ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &data);
+ ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3);
}
static irqreturn_t ad714x_interrupt_thread(int irq, void *data)
@@ -966,9 +944,7 @@ static irqreturn_t ad714x_interrupt_thread(int irq, void *data)
mutex_lock(&ad714x->mutex);
- ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &ad714x->l_state);
- ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &ad714x->h_state);
- ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &ad714x->c_state);
+ ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3);
for (i = 0; i < ad714x->hw->button_num; i++)
ad714x_button_state_machine(ad714x, i);
@@ -1245,7 +1221,7 @@ int ad714x_disable(struct ad714x_chip *ad714x)
mutex_lock(&ad714x->mutex);
data = ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL] | 0x3;
- ad714x->write(ad714x->dev, AD714X_PWR_CTRL, data);
+ ad714x->write(ad714x, AD714X_PWR_CTRL, data);
mutex_unlock(&ad714x->mutex);
@@ -1255,24 +1231,20 @@ EXPORT_SYMBOL(ad714x_disable);
int ad714x_enable(struct ad714x_chip *ad714x)
{
- unsigned short data;
-
dev_dbg(ad714x->dev, "%s enter\n", __func__);
mutex_lock(&ad714x->mutex);
/* resume to non-shutdown mode */
- ad714x->write(ad714x->dev, AD714X_PWR_CTRL,
+ ad714x->write(ad714x, AD714X_PWR_CTRL,
ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL]);
/* make sure the interrupt output line is not low level after resume,
* otherwise we will get no chance to enter falling-edge irq again
*/
- ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &data);
- ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &data);
- ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &data);
+ ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3);
mutex_unlock(&ad714x->mutex);
diff --git a/drivers/input/misc/ad714x.h b/drivers/input/misc/ad714x.h
index 45c54fb13f07..3c85455aa66d 100644
--- a/drivers/input/misc/ad714x.h
+++ b/drivers/input/misc/ad714x.h
@@ -1,7 +1,7 @@
/*
* AD714X CapTouch Programmable Controller driver (bus interfaces)
*
- * Copyright 2009 Analog Devices Inc.
+ * Copyright 2009-2011 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
@@ -11,11 +11,40 @@
#include <linux/types.h>
+#define STAGE_NUM 12
+
struct device;
+struct ad714x_platform_data;
+struct ad714x_driver_data;
struct ad714x_chip;
-typedef int (*ad714x_read_t)(struct device *, unsigned short, unsigned short *);
-typedef int (*ad714x_write_t)(struct device *, unsigned short, unsigned short);
+typedef int (*ad714x_read_t)(struct ad714x_chip *, unsigned short, unsigned short *, size_t);
+typedef int (*ad714x_write_t)(struct ad714x_chip *, unsigned short, unsigned short);
+
+struct ad714x_chip {
+ unsigned short l_state;
+ unsigned short h_state;
+ unsigned short c_state;
+ unsigned short adc_reg[STAGE_NUM];
+ unsigned short amb_reg[STAGE_NUM];
+ unsigned short sensor_val[STAGE_NUM];
+
+ struct ad714x_platform_data *hw;
+ struct ad714x_driver_data *sw;
+
+ int irq;
+ struct device *dev;
+ ad714x_read_t read;
+ ad714x_write_t write;
+
+ struct mutex mutex;
+
+ unsigned product;
+ unsigned version;
+
+ __be16 xfer_buf[16] ____cacheline_aligned;
+
+};
int ad714x_disable(struct ad714x_chip *ad714x);
int ad714x_enable(struct ad714x_chip *ad714x);
diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c
index b09c7d127219..ab860511f016 100644
--- a/drivers/input/misc/cm109.c
+++ b/drivers/input/misc/cm109.c
@@ -475,7 +475,7 @@ static void cm109_toggle_buzzer_sync(struct cm109_dev *dev, int on)
le16_to_cpu(dev->ctl_req->wIndex),
dev->ctl_data,
USB_PKT_LEN, USB_CTRL_SET_TIMEOUT);
- if (error && error != EINTR)
+ if (error < 0 && error != -EINTR)
err("%s: usb_control_msg() failed %d", __func__, error);
}
diff --git a/drivers/input/misc/mma8450.c b/drivers/input/misc/mma8450.c
index 6c76cf792991..0794778295fc 100644
--- a/drivers/input/misc/mma8450.c
+++ b/drivers/input/misc/mma8450.c
@@ -234,7 +234,7 @@ static const struct of_device_id mma8450_dt_ids[] = {
{ .compatible = "fsl,mma8450", },
{ /* sentinel */ }
};
-MODULE_DEVICE_TABLE(i2c, mma8450_dt_ids);
+MODULE_DEVICE_TABLE(of, mma8450_dt_ids);
static struct i2c_driver mma8450_driver = {
.driver = {
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index b95fac15b2ea..f71dc728da58 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -282,7 +282,7 @@ err_free_irq:
err_pm_set_suspended:
pm_runtime_set_suspended(&client->dev);
err_free_mem:
- input_unregister_device(idev);
+ input_free_device(idev);
kfree(sensor);
return error;
}
diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c
index 2c8b84dd9dac..2be21694fac1 100644
--- a/drivers/input/misc/rotary_encoder.c
+++ b/drivers/input/misc/rotary_encoder.c
@@ -7,7 +7,7 @@
* state machine code inspired by code from Tim Ruetz
*
* A generic driver for rotary encoders connected to GPIO lines.
- * See file:Documentation/input/rotary_encoder.txt for more information
+ * See file:Documentation/input/rotary-encoder.txt for more information
*
* 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
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index 3126983c004a..5ec617e28f7e 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -67,6 +67,18 @@
#define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI 0x0245
#define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO 0x0246
#define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS 0x0247
+/* MacbookAir4,1 (unibody, July 2011) */
+#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI 0x0249
+#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO 0x024a
+#define USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS 0x024b
+/* MacbookAir4,2 (unibody, July 2011) */
+#define USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI 0x024c
+#define USB_DEVICE_ID_APPLE_WELLSPRING6_ISO 0x024d
+#define USB_DEVICE_ID_APPLE_WELLSPRING6_JIS 0x024e
+/* Macbook8,2 (unibody) */
+#define USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI 0x0252
+#define USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO 0x0253
+#define USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS 0x0254
#define BCM5974_DEVICE(prod) { \
.match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \
@@ -104,6 +116,18 @@ static const struct usb_device_id bcm5974_table[] = {
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_ISO),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_JIS),
+ /* MacbookAir4,1 */
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS),
+ /* MacbookAir4,2 */
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6_ISO),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6_JIS),
+ /* MacbookPro8,2 */
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS),
/* Terminating entry */
{}
};
@@ -294,6 +318,42 @@ static const struct bcm5974_config bcm5974_config_table[] = {
{ DIM_X, DIM_X / SN_COORD, -4415, 5050 },
{ DIM_Y, DIM_Y / SN_COORD, -55, 6680 }
},
+ {
+ USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI,
+ USB_DEVICE_ID_APPLE_WELLSPRING6_ISO,
+ USB_DEVICE_ID_APPLE_WELLSPRING6_JIS,
+ HAS_INTEGRATED_BUTTON,
+ 0x84, sizeof(struct bt_data),
+ 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+ { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
+ { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
+ { DIM_X, DIM_X / SN_COORD, -4620, 5140 },
+ { DIM_Y, DIM_Y / SN_COORD, -150, 6600 }
+ },
+ {
+ USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI,
+ USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO,
+ USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS,
+ HAS_INTEGRATED_BUTTON,
+ 0x84, sizeof(struct bt_data),
+ 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+ { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
+ { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
+ { DIM_X, DIM_X / SN_COORD, -4750, 5280 },
+ { DIM_Y, DIM_Y / SN_COORD, -150, 6730 }
+ },
+ {
+ USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI,
+ USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO,
+ USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS,
+ HAS_INTEGRATED_BUTTON,
+ 0x84, sizeof(struct bt_data),
+ 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+ { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
+ { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
+ { DIM_X, DIM_X / SN_COORD, -4620, 5140 },
+ { DIM_Y, DIM_Y / SN_COORD, -150, 6600 }
+ },
{}
};
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index 449c0a46dbac..958b4eb6369d 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -49,6 +49,7 @@ struct hid_descriptor {
#define USB_REQ_GET_REPORT 0x01
#define USB_REQ_SET_REPORT 0x09
#define WAC_HID_FEATURE_REPORT 0x03
+#define WAC_MSG_RETRIES 5
static int usb_get_report(struct usb_interface *intf, unsigned char type,
unsigned char id, void *buf, int size)
@@ -165,7 +166,7 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
report,
hid_desc->wDescriptorLength,
5000); /* 5 secs */
- } while (result < 0 && limit++ < 5);
+ } while (result < 0 && limit++ < WAC_MSG_RETRIES);
/* No need to parse the Descriptor. It isn't an error though */
if (result < 0)
@@ -228,13 +229,6 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
get_unaligned_le16(&report[i + 3]);
i += 4;
}
- } else if (usage == WCM_DIGITIZER) {
- /* max pressure isn't reported
- features->pressure_max = (unsigned short)
- (report[i+4] << 8 | report[i + 3]);
- */
- features->pressure_max = 255;
- i += 4;
}
break;
@@ -290,13 +284,6 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
pen = 1;
i++;
break;
-
- case HID_USAGE_UNDEFINED:
- if (usage == WCM_DESKTOP && finger) /* capacity */
- features->pressure_max =
- get_unaligned_le16(&report[i + 3]);
- i += 4;
- break;
}
break;
@@ -319,24 +306,26 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
int limit = 0, report_id = 2;
int error = -ENOMEM;
- rep_data = kmalloc(2, GFP_KERNEL);
+ rep_data = kmalloc(4, GFP_KERNEL);
if (!rep_data)
return error;
- /* ask to report tablet data if it is 2FGT Tablet PC or
+ /* ask to report tablet data if it is MT Tablet PC or
* not a Tablet PC */
if (features->type == TABLETPC2FG) {
do {
rep_data[0] = 3;
rep_data[1] = 4;
+ rep_data[2] = 0;
+ rep_data[3] = 0;
report_id = 3;
error = usb_set_report(intf, WAC_HID_FEATURE_REPORT,
- report_id, rep_data, 2);
+ report_id, rep_data, 4);
if (error >= 0)
error = usb_get_report(intf,
WAC_HID_FEATURE_REPORT, report_id,
- rep_data, 3);
- } while ((error < 0 || rep_data[1] != 4) && limit++ < 5);
+ rep_data, 4);
+ } while ((error < 0 || rep_data[1] != 4) && limit++ < WAC_MSG_RETRIES);
} else if (features->type != TABLETPC) {
do {
rep_data[0] = 2;
@@ -347,7 +336,7 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
error = usb_get_report(intf,
WAC_HID_FEATURE_REPORT, report_id,
rep_data, 2);
- } while ((error < 0 || rep_data[1] != 2) && limit++ < 5);
+ } while ((error < 0 || rep_data[1] != 2) && limit++ < WAC_MSG_RETRIES);
}
kfree(rep_data);
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 03ebcc8b24b5..9dea71849f40 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -800,25 +800,26 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
int i;
for (i = 0; i < 2; i++) {
- int p = data[9 * i + 2];
- bool touch = p && !wacom->shared->stylus_in_proximity;
+ int offset = (data[1] & 0x80) ? (8 * i) : (9 * i);
+ bool touch = data[offset + 3] & 0x80;
- input_mt_slot(input, i);
- input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
/*
* Touch events need to be disabled while stylus is
* in proximity because user's hand is resting on touchpad
* and sending unwanted events. User expects tablet buttons
* to continue working though.
*/
+ touch = touch && !wacom->shared->stylus_in_proximity;
+
+ input_mt_slot(input, i);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
if (touch) {
- int x = get_unaligned_be16(&data[9 * i + 3]) & 0x7ff;
- int y = get_unaligned_be16(&data[9 * i + 5]) & 0x7ff;
+ int x = get_unaligned_be16(&data[offset + 3]) & 0x7ff;
+ int y = get_unaligned_be16(&data[offset + 5]) & 0x7ff;
if (features->quirks & WACOM_QUIRK_BBTOUCH_LOWRES) {
x <<= 5;
y <<= 5;
}
- input_report_abs(input, ABS_MT_PRESSURE, p);
input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y);
}
@@ -1056,10 +1057,11 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
features->x_fuzz, 0);
input_set_abs_params(input_dev, ABS_Y, 0, features->y_max,
features->y_fuzz, 0);
- input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max,
- features->pressure_fuzz, 0);
if (features->device_type == BTN_TOOL_PEN) {
+ input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max,
+ features->pressure_fuzz, 0);
+
/* penabled devices have fixed resolution for each model */
input_abs_set_res(input_dev, ABS_X, features->x_resolution);
input_abs_set_res(input_dev, ABS_Y, features->y_resolution);
@@ -1098,6 +1100,8 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
__set_bit(BTN_STYLUS, input_dev->keybit);
__set_bit(BTN_STYLUS2, input_dev->keybit);
+
+ __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
break;
case WACOM_21UX2:
@@ -1120,12 +1124,12 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
for (i = 0; i < 8; i++)
__set_bit(BTN_0 + i, input_dev->keybit);
- if (wacom_wac->features.type != WACOM_21UX2) {
- input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
- input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
- }
-
+ input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
+ input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+
+ __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+
wacom_setup_cintiq(wacom_wac);
break;
@@ -1150,6 +1154,8 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
/* fall through */
case INTUOS:
+ __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+
wacom_setup_intuos(wacom_wac);
break;
@@ -1165,6 +1171,8 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
wacom_setup_intuos(wacom_wac);
+
+ __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
break;
case TABLETPC2FG:
@@ -1183,26 +1191,40 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
case TABLETPC:
__clear_bit(ABS_MISC, input_dev->absbit);
+ __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+
if (features->device_type != BTN_TOOL_PEN)
break; /* no need to process stylus stuff */
/* fall through */
case PL:
- case PTU:
case DTU:
__set_bit(BTN_TOOL_PEN, input_dev->keybit);
+ __set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
__set_bit(BTN_STYLUS, input_dev->keybit);
__set_bit(BTN_STYLUS2, input_dev->keybit);
+
+ __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+ break;
+
+ case PTU:
+ __set_bit(BTN_STYLUS2, input_dev->keybit);
/* fall through */
case PENPARTNER:
+ __set_bit(BTN_TOOL_PEN, input_dev->keybit);
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
+ __set_bit(BTN_STYLUS, input_dev->keybit);
+
+ __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
break;
case BAMBOO_PT:
__clear_bit(ABS_MISC, input_dev->absbit);
+ __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+
if (features->device_type == BTN_TOOL_DOUBLETAP) {
__set_bit(BTN_LEFT, input_dev->keybit);
__set_bit(BTN_FORWARD, input_dev->keybit);
@@ -1460,6 +1482,9 @@ static const struct wacom_features wacom_features_0xD3 =
static const struct wacom_features wacom_features_0xD4 =
{ "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0xD5 =
+ { "Wacom Bamboo Pen 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023,
+ 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xD6 =
{ "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -1564,6 +1589,7 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0xD2) },
{ USB_DEVICE_WACOM(0xD3) },
{ USB_DEVICE_WACOM(0xD4) },
+ { USB_DEVICE_WACOM(0xD5) },
{ USB_DEVICE_WACOM(0xD6) },
{ USB_DEVICE_WACOM(0xD7) },
{ USB_DEVICE_WACOM(0xD8) },
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index ae00604a6a81..f5d66859f232 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -244,6 +244,7 @@ struct mxt_finger {
int x;
int y;
int area;
+ int pressure;
};
/* Each client has this additional data */
@@ -536,6 +537,8 @@ static void mxt_input_report(struct mxt_data *data, int single_id)
finger[id].x);
input_report_abs(input_dev, ABS_MT_POSITION_Y,
finger[id].y);
+ input_report_abs(input_dev, ABS_MT_PRESSURE,
+ finger[id].pressure);
} else {
finger[id].status = 0;
}
@@ -546,6 +549,8 @@ static void mxt_input_report(struct mxt_data *data, int single_id)
if (status != MXT_RELEASE) {
input_report_abs(input_dev, ABS_X, finger[single_id].x);
input_report_abs(input_dev, ABS_Y, finger[single_id].y);
+ input_report_abs(input_dev,
+ ABS_PRESSURE, finger[single_id].pressure);
}
input_sync(input_dev);
@@ -560,6 +565,7 @@ static void mxt_input_touchevent(struct mxt_data *data,
int x;
int y;
int area;
+ int pressure;
/* Check the touch is present on the screen */
if (!(status & MXT_DETECT)) {
@@ -584,6 +590,7 @@ static void mxt_input_touchevent(struct mxt_data *data,
y = y >> 2;
area = message->message[4];
+ pressure = message->message[5];
dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id,
status & MXT_MOVE ? "moved" : "pressed",
@@ -594,6 +601,7 @@ static void mxt_input_touchevent(struct mxt_data *data,
finger[id].x = x;
finger[id].y = y;
finger[id].area = area;
+ finger[id].pressure = pressure;
mxt_input_report(data, id);
}
@@ -1116,6 +1124,8 @@ static int __devinit mxt_probe(struct i2c_client *client,
0, data->max_x, 0, 0);
input_set_abs_params(input_dev, ABS_Y,
0, data->max_y, 0, 0);
+ input_set_abs_params(input_dev, ABS_PRESSURE,
+ 0, 255, 0, 0);
/* For multi touch */
input_mt_init_slots(input_dev, MXT_MAX_FINGER);
@@ -1125,6 +1135,8 @@ static int __devinit mxt_probe(struct i2c_client *client,
0, data->max_x, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
0, data->max_y, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_PRESSURE,
+ 0, 255, 0, 0);
input_set_drvdata(input_dev, data);
i2c_set_clientdata(client, data);
diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c
index 4f2713d92791..4627fe55b401 100644
--- a/drivers/input/touchscreen/max11801_ts.c
+++ b/drivers/input/touchscreen/max11801_ts.c
@@ -9,7 +9,8 @@
*
* 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.
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
*/
/*
diff --git a/drivers/input/touchscreen/tnetv107x-ts.c b/drivers/input/touchscreen/tnetv107x-ts.c
index 089b0a0f3d8c..0e8f63e5b36f 100644
--- a/drivers/input/touchscreen/tnetv107x-ts.c
+++ b/drivers/input/touchscreen/tnetv107x-ts.c
@@ -13,6 +13,7 @@
* GNU General Public License for more details.
*/
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/errno.h>
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c
index c14412ef4648..9941d39df43d 100644
--- a/drivers/input/touchscreen/wacom_w8001.c
+++ b/drivers/input/touchscreen/wacom_w8001.c
@@ -383,6 +383,8 @@ static int w8001_setup(struct w8001 *w8001)
dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
strlcat(w8001->name, "Wacom Serial", sizeof(w8001->name));
+ __set_bit(INPUT_PROP_DIRECT, dev->propbit);
+
/* penabled? */
error = w8001_command(w8001, W8001_CMD_QUERY, true);
if (!error) {
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index a14f8dc23462..0e4227f457af 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -605,7 +605,9 @@ static void build_inv_all(struct iommu_cmd *cmd)
* Writes the command to the IOMMUs command buffer and informs the
* hardware about the new command.
*/
-static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd)
+static int iommu_queue_command_sync(struct amd_iommu *iommu,
+ struct iommu_cmd *cmd,
+ bool sync)
{
u32 left, tail, head, next_tail;
unsigned long flags;
@@ -639,13 +641,18 @@ again:
copy_cmd_to_buffer(iommu, cmd, tail);
/* We need to sync now to make sure all commands are processed */
- iommu->need_sync = true;
+ iommu->need_sync = sync;
spin_unlock_irqrestore(&iommu->lock, flags);
return 0;
}
+static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd)
+{
+ return iommu_queue_command_sync(iommu, cmd, true);
+}
+
/*
* This function queues a completion wait command into the command
* buffer of an IOMMU
@@ -661,7 +668,7 @@ static int iommu_completion_wait(struct amd_iommu *iommu)
build_completion_wait(&cmd, (u64)&sem);
- ret = iommu_queue_command(iommu, &cmd);
+ ret = iommu_queue_command_sync(iommu, &cmd, false);
if (ret)
return ret;
@@ -840,14 +847,9 @@ static void domain_flush_complete(struct protection_domain *domain)
static void domain_flush_devices(struct protection_domain *domain)
{
struct iommu_dev_data *dev_data;
- unsigned long flags;
-
- spin_lock_irqsave(&domain->lock, flags);
list_for_each_entry(dev_data, &domain->dev_list, list)
device_flush_dte(dev_data);
-
- spin_unlock_irqrestore(&domain->lock, flags);
}
/****************************************************************************
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 3dc9befa5aec..6dcc7e2d54de 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -1388,7 +1388,7 @@ int dmar_set_interrupt(struct intel_iommu *iommu)
return ret;
}
- ret = request_irq(irq, dmar_fault, 0, iommu->name, iommu);
+ ret = request_irq(irq, dmar_fault, IRQF_NO_THREAD, iommu->name, iommu);
if (ret)
printk(KERN_ERR "IOMMU: can't request irq\n");
return ret;
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index c621c98c99da..a88f3cbb100b 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -306,6 +306,11 @@ static inline bool dma_pte_present(struct dma_pte *pte)
return (pte->val & 3) != 0;
}
+static inline bool dma_pte_superpage(struct dma_pte *pte)
+{
+ return (pte->val & (1 << 7));
+}
+
static inline int first_pte_in_page(struct dma_pte *pte)
{
return !((unsigned long)pte & ~VTD_PAGE_MASK);
@@ -404,6 +409,9 @@ static int dmar_forcedac;
static int intel_iommu_strict;
static int intel_iommu_superpage = 1;
+int intel_iommu_gfx_mapped;
+EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped);
+
#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
static DEFINE_SPINLOCK(device_domain_lock);
static LIST_HEAD(device_domain_list);
@@ -577,17 +585,18 @@ static void domain_update_iommu_snooping(struct dmar_domain *domain)
static void domain_update_iommu_superpage(struct dmar_domain *domain)
{
- int i, mask = 0xf;
+ struct dmar_drhd_unit *drhd;
+ struct intel_iommu *iommu = NULL;
+ int mask = 0xf;
if (!intel_iommu_superpage) {
domain->iommu_superpage = 0;
return;
}
- domain->iommu_superpage = 4; /* 1TiB */
-
- for_each_set_bit(i, &domain->iommu_bmp, g_num_of_iommus) {
- mask |= cap_super_page_val(g_iommus[i]->cap);
+ /* set iommu_superpage to the smallest common denominator */
+ for_each_active_iommu(iommu, drhd) {
+ mask &= cap_super_page_val(iommu->cap);
if (!mask) {
break;
}
@@ -730,29 +739,23 @@ out:
}
static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
- unsigned long pfn, int large_level)
+ unsigned long pfn, int target_level)
{
int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
struct dma_pte *parent, *pte = NULL;
int level = agaw_to_level(domain->agaw);
- int offset, target_level;
+ int offset;
BUG_ON(!domain->pgd);
BUG_ON(addr_width < BITS_PER_LONG && pfn >> addr_width);
parent = domain->pgd;
- /* Search pte */
- if (!large_level)
- target_level = 1;
- else
- target_level = large_level;
-
while (level > 0) {
void *tmp_page;
offset = pfn_level_offset(pfn, level);
pte = &parent[offset];
- if (!large_level && (pte->val & DMA_PTE_LARGE_PAGE))
+ if (!target_level && (dma_pte_superpage(pte) || !dma_pte_present(pte)))
break;
if (level == target_level)
break;
@@ -816,13 +819,14 @@ static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
}
/* clear last level pte, a tlb flush should be followed */
-static void dma_pte_clear_range(struct dmar_domain *domain,
+static int dma_pte_clear_range(struct dmar_domain *domain,
unsigned long start_pfn,
unsigned long last_pfn)
{
int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
unsigned int large_page = 1;
struct dma_pte *first_pte, *pte;
+ int order;
BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
@@ -846,6 +850,9 @@ static void dma_pte_clear_range(struct dmar_domain *domain,
(void *)pte - (void *)first_pte);
} while (start_pfn && start_pfn <= last_pfn);
+
+ order = (large_page - 1) * 9;
+ return order;
}
/* free page table pages. last level pte should already be cleared */
@@ -3226,9 +3233,6 @@ static void __init init_no_remapping_devices(void)
}
}
- if (dmar_map_gfx)
- return;
-
for_each_drhd_unit(drhd) {
int i;
if (drhd->ignored || drhd->include_all)
@@ -3236,18 +3240,23 @@ static void __init init_no_remapping_devices(void)
for (i = 0; i < drhd->devices_cnt; i++)
if (drhd->devices[i] &&
- !IS_GFX_DEVICE(drhd->devices[i]))
+ !IS_GFX_DEVICE(drhd->devices[i]))
break;
if (i < drhd->devices_cnt)
continue;
- /* bypass IOMMU if it is just for gfx devices */
- drhd->ignored = 1;
- for (i = 0; i < drhd->devices_cnt; i++) {
- if (!drhd->devices[i])
- continue;
- drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
+ /* This IOMMU has *only* gfx devices. Either bypass it or
+ set the gfx_mapped flag, as appropriate */
+ if (dmar_map_gfx) {
+ intel_iommu_gfx_mapped = 1;
+ } else {
+ drhd->ignored = 1;
+ for (i = 0; i < drhd->devices_cnt; i++) {
+ if (!drhd->devices[i])
+ continue;
+ drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
+ }
}
}
}
@@ -3568,6 +3577,8 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain,
found = 1;
}
+ spin_unlock_irqrestore(&device_domain_lock, flags);
+
if (found == 0) {
unsigned long tmp_flags;
spin_lock_irqsave(&domain->iommu_lock, tmp_flags);
@@ -3584,8 +3595,6 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain,
spin_unlock_irqrestore(&iommu->lock, tmp_flags);
}
}
-
- spin_unlock_irqrestore(&device_domain_lock, flags);
}
static void vm_domain_remove_all_dev_info(struct dmar_domain *domain)
@@ -3739,6 +3748,7 @@ static int intel_iommu_domain_init(struct iommu_domain *domain)
vm_domain_exit(dmar_domain);
return -ENOMEM;
}
+ domain_update_iommu_cap(dmar_domain);
domain->priv = dmar_domain;
return 0;
@@ -3864,14 +3874,15 @@ static int intel_iommu_unmap(struct iommu_domain *domain,
{
struct dmar_domain *dmar_domain = domain->priv;
size_t size = PAGE_SIZE << gfp_order;
+ int order;
- dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
+ order = dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
(iova + size - 1) >> VTD_PAGE_SHIFT);
if (dmar_domain->max_addr == iova + size)
dmar_domain->max_addr = iova;
- return gfp_order;
+ return order;
}
static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
@@ -3950,7 +3961,11 @@ static void __devinit quirk_calpella_no_shadow_gtt(struct pci_dev *dev)
if (!(ggc & GGC_MEMORY_VT_ENABLED)) {
printk(KERN_INFO "DMAR: BIOS has allocated no shadow GTT; disabling IOMMU for graphics\n");
dmar_map_gfx = 0;
- }
+ } else if (dmar_map_gfx) {
+ /* we have to ensure the gfx device is idle before we flush */
+ printk(KERN_INFO "DMAR: Disabling batched IOTLB flush on Ironlake\n");
+ intel_iommu_strict = 1;
+ }
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0040, quirk_calpella_no_shadow_gtt);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_gtt);
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index 6ed82add6ffa..6ddb795e31c5 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -2308,11 +2308,11 @@ static int __init isdn_init(void)
int i;
char tmprev[50];
- if (!(dev = vmalloc(sizeof(isdn_dev)))) {
+ dev = vzalloc(sizeof(isdn_dev));
+ if (!dev) {
printk(KERN_WARNING "isdn: Could not allocate device-struct.\n");
return -EIO;
}
- memset((char *) dev, 0, sizeof(isdn_dev));
init_timer(&dev->timer);
dev->timer.function = isdn_timer_funct;
spin_lock_init(&dev->lock);
diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c
index 2877291a9ed8..0c41553ce684 100644
--- a/drivers/isdn/mISDN/dsp_core.c
+++ b/drivers/isdn/mISDN/dsp_core.c
@@ -1052,12 +1052,11 @@ dspcreate(struct channel_req *crq)
if (crq->protocol != ISDN_P_B_L2DSP
&& crq->protocol != ISDN_P_B_L2DSPHDLC)
return -EPROTONOSUPPORT;
- ndsp = vmalloc(sizeof(struct dsp));
+ ndsp = vzalloc(sizeof(struct dsp));
if (!ndsp) {
printk(KERN_ERR "%s: vmalloc struct dsp failed\n", __func__);
return -ENOMEM;
}
- memset(ndsp, 0, sizeof(struct dsp));
if (dsp_debug & DEBUG_DSP_CTRL)
printk(KERN_DEBUG "%s: creating new dsp instance\n", __func__);
diff --git a/drivers/isdn/mISDN/l1oip_codec.c b/drivers/isdn/mISDN/l1oip_codec.c
index bbfd1b863ed3..5a89972624d8 100644
--- a/drivers/isdn/mISDN/l1oip_codec.c
+++ b/drivers/isdn/mISDN/l1oip_codec.c
@@ -330,14 +330,12 @@ l1oip_4bit_alloc(int ulaw)
return 0;
/* alloc conversion tables */
- table_com = vmalloc(65536);
- table_dec = vmalloc(512);
+ table_com = vzalloc(65536);
+ table_dec = vzalloc(512);
if (!table_com || !table_dec) {
l1oip_4bit_free();
return -ENOMEM;
}
- memset(table_com, 0, 65536);
- memset(table_dec, 0, 512);
/* generate compression table */
i1 = 0;
while (i1 < 256) {
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index b591e726a6fa..807c875f1c2e 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -400,7 +400,7 @@ config LEDS_TRIGGER_TIMER
This allows LEDs to be controlled by a programmable timer
via sysfs. Some LED hardware can be programmed to start
blinking the LED without any further software interaction.
- For more details read Documentation/leds-class.txt.
+ For more details read Documentation/leds/leds-class.txt.
If unsure, say Y.
diff --git a/drivers/leds/leds-ams-delta.c b/drivers/leds/leds-ams-delta.c
index b9826032450b..8c00937bf7e7 100644
--- a/drivers/leds/leds-ams-delta.c
+++ b/drivers/leds/leds-ams-delta.c
@@ -8,6 +8,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c
index 3ebe3824662d..ea2185531f82 100644
--- a/drivers/leds/leds-bd2802.c
+++ b/drivers/leds/leds-bd2802.c
@@ -662,6 +662,11 @@ failed_unregister_led1_R:
static void bd2802_unregister_led_classdev(struct bd2802_led *led)
{
cancel_work_sync(&led->work);
+ led_classdev_unregister(&led->cdev_led2b);
+ led_classdev_unregister(&led->cdev_led2g);
+ led_classdev_unregister(&led->cdev_led2r);
+ led_classdev_unregister(&led->cdev_led1b);
+ led_classdev_unregister(&led->cdev_led1g);
led_classdev_unregister(&led->cdev_led1r);
}
diff --git a/drivers/leds/leds-hp6xx.c b/drivers/leds/leds-hp6xx.c
index e4ce1fd46338..bcfbd3a60eab 100644
--- a/drivers/leds/leds-hp6xx.c
+++ b/drivers/leds/leds-hp6xx.c
@@ -10,6 +10,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
index d87c9d02f786..328c64c0841c 100644
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -41,6 +41,7 @@ static ssize_t led_delay_on_store(struct device *dev,
if (count == size) {
led_blink_set(led_cdev, &state, &led_cdev->blink_delay_off);
+ led_cdev->blink_delay_on = state;
ret = count;
}
@@ -69,6 +70,7 @@ static ssize_t led_delay_off_store(struct device *dev,
if (count == size) {
led_blink_set(led_cdev, &led_cdev->blink_delay_on, &state);
+ led_cdev->blink_delay_off = state;
ret = count;
}
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 49da55c1528a..8c2a000cf3f5 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -1698,6 +1698,8 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
}
ti->num_flush_requests = 1;
+ ti->discard_zeroes_data_unsupported = 1;
+
return 0;
bad:
diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c
index 89f73ca22cfa..f84c08029b21 100644
--- a/drivers/md/dm-flakey.c
+++ b/drivers/md/dm-flakey.c
@@ -81,8 +81,10 @@ static int parse_features(struct dm_arg_set *as, struct flakey_c *fc,
* corrupt_bio_byte <Nth_byte> <direction> <value> <bio_flags>
*/
if (!strcasecmp(arg_name, "corrupt_bio_byte")) {
- if (!argc)
+ if (!argc) {
ti->error = "Feature corrupt_bio_byte requires parameters";
+ return -EINVAL;
+ }
r = dm_read_arg(_args + 1, as, &fc->corrupt_bio_byte, &ti->error);
if (r)
diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c
index f82147029636..32ac70861d66 100644
--- a/drivers/md/dm-kcopyd.c
+++ b/drivers/md/dm-kcopyd.c
@@ -628,6 +628,7 @@ void *dm_kcopyd_prepare_callback(struct dm_kcopyd_client *kc,
job->kc = kc;
job->fn = fn;
job->context = context;
+ job->master_job = job;
atomic_inc(&kc->nr_jobs);
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index a002dd85db1e..86df8b2cf927 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -449,7 +449,7 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
rs->ti->error = "write_mostly option is only valid for RAID1";
return -EINVAL;
}
- if (value > rs->md.raid_disks) {
+ if (value >= rs->md.raid_disks) {
rs->ti->error = "Invalid write_mostly drive index given";
return -EINVAL;
}
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 986b8754bb08..bc04518e9d8b 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -1238,14 +1238,15 @@ static void dm_table_set_integrity(struct dm_table *t)
return;
template_disk = dm_table_get_integrity_disk(t, true);
- if (!template_disk &&
- blk_integrity_is_initialized(dm_disk(t->md))) {
+ if (template_disk)
+ blk_integrity_register(dm_disk(t->md),
+ blk_get_integrity(template_disk));
+ else if (blk_integrity_is_initialized(dm_disk(t->md)))
DMWARN("%s: device no longer has a valid integrity profile",
dm_device_name(t->md));
- return;
- }
- blk_integrity_register(dm_disk(t->md),
- blk_get_integrity(template_disk));
+ else
+ DMWARN("%s: unable to establish an integrity profile",
+ dm_device_name(t->md));
}
static int device_flush_capable(struct dm_target *ti, struct dm_dev *dev,
@@ -1282,6 +1283,22 @@ static bool dm_table_supports_flush(struct dm_table *t, unsigned flush)
return 0;
}
+static bool dm_table_discard_zeroes_data(struct dm_table *t)
+{
+ struct dm_target *ti;
+ unsigned i = 0;
+
+ /* Ensure that all targets supports discard_zeroes_data. */
+ while (i < dm_table_get_num_targets(t)) {
+ ti = dm_table_get_target(t, i++);
+
+ if (ti->discard_zeroes_data_unsupported)
+ return 0;
+ }
+
+ return 1;
+}
+
void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
struct queue_limits *limits)
{
@@ -1304,6 +1321,9 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
}
blk_queue_flush(q, flush);
+ if (!dm_table_discard_zeroes_data(t))
+ q->limits.discard_zeroes_data = 0;
+
dm_table_set_integrity(t);
/*
diff --git a/drivers/md/linear.h b/drivers/md/linear.h
index 0ce29b61605a..2f2da05b2ce9 100644
--- a/drivers/md/linear.h
+++ b/drivers/md/linear.h
@@ -10,9 +10,9 @@ typedef struct dev_info dev_info_t;
struct linear_private_data
{
+ struct rcu_head rcu;
sector_t array_sectors;
dev_info_t disks[0];
- struct rcu_head rcu;
};
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 8e221a20f5d9..5c95ccb59500 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -61,6 +61,11 @@
static void autostart_arrays(int part);
#endif
+/* pers_list is a list of registered personalities protected
+ * by pers_lock.
+ * pers_lock does extra service to protect accesses to
+ * mddev->thread when the mutex cannot be held.
+ */
static LIST_HEAD(pers_list);
static DEFINE_SPINLOCK(pers_lock);
@@ -739,7 +744,12 @@ static void mddev_unlock(mddev_t * mddev)
} else
mutex_unlock(&mddev->reconfig_mutex);
+ /* was we've dropped the mutex we need a spinlock to
+ * make sur the thread doesn't disappear
+ */
+ spin_lock(&pers_lock);
md_wakeup_thread(mddev->thread);
+ spin_unlock(&pers_lock);
}
static mdk_rdev_t * find_rdev_nr(mddev_t *mddev, int nr)
@@ -848,7 +858,7 @@ void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
bio->bi_end_io = super_written;
atomic_inc(&mddev->pending_writes);
- submit_bio(REQ_WRITE | REQ_SYNC | REQ_FLUSH | REQ_FUA, bio);
+ submit_bio(WRITE_FLUSH_FUA, bio);
}
void md_super_wait(mddev_t *mddev)
@@ -1138,8 +1148,11 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version
ret = 0;
}
rdev->sectors = rdev->sb_start;
+ /* Limit to 4TB as metadata cannot record more than that */
+ if (rdev->sectors >= (2ULL << 32))
+ rdev->sectors = (2ULL << 32) - 2;
- if (rdev->sectors < sb->size * 2 && sb->level > 1)
+ if (rdev->sectors < ((sector_t)sb->size) * 2 && sb->level >= 1)
/* "this cannot possibly happen" ... */
ret = -EINVAL;
@@ -1173,7 +1186,7 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
mddev->clevel[0] = 0;
mddev->layout = sb->layout;
mddev->raid_disks = sb->raid_disks;
- mddev->dev_sectors = sb->size * 2;
+ mddev->dev_sectors = ((sector_t)sb->size) * 2;
mddev->events = ev1;
mddev->bitmap_info.offset = 0;
mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
@@ -1415,6 +1428,11 @@ super_90_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors)
rdev->sb_start = calc_dev_sboffset(rdev);
if (!num_sectors || num_sectors > rdev->sb_start)
num_sectors = rdev->sb_start;
+ /* Limit to 4TB as metadata cannot record more than that.
+ * 4TB == 2^32 KB, or 2*2^32 sectors.
+ */
+ if (num_sectors >= (2ULL << 32))
+ num_sectors = (2ULL << 32) - 2;
md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size,
rdev->sb_page);
md_super_wait(rdev->mddev);
@@ -1738,6 +1756,11 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
sb->level = cpu_to_le32(mddev->level);
sb->layout = cpu_to_le32(mddev->layout);
+ if (test_bit(WriteMostly, &rdev->flags))
+ sb->devflags |= WriteMostly1;
+ else
+ sb->devflags &= ~WriteMostly1;
+
if (mddev->bitmap && mddev->bitmap_info.file == NULL) {
sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_info.offset);
sb->feature_map = cpu_to_le32(MD_FEATURE_BITMAP_OFFSET);
@@ -2561,7 +2584,10 @@ state_store(mdk_rdev_t *rdev, const char *buf, size_t len)
int err = -EINVAL;
if (cmd_match(buf, "faulty") && rdev->mddev->pers) {
md_error(rdev->mddev, rdev);
- err = 0;
+ if (test_bit(Faulty, &rdev->flags))
+ err = 0;
+ else
+ err = -EBUSY;
} else if (cmd_match(buf, "remove")) {
if (rdev->raid_disk >= 0)
err = -EBUSY;
@@ -2584,7 +2610,7 @@ state_store(mdk_rdev_t *rdev, const char *buf, size_t len)
err = 0;
} else if (cmd_match(buf, "-blocked")) {
if (!test_bit(Faulty, &rdev->flags) &&
- test_bit(BlockedBadBlocks, &rdev->flags)) {
+ rdev->badblocks.unacked_exist) {
/* metadata handler doesn't understand badblocks,
* so we need to fail the device
*/
@@ -5983,6 +6009,8 @@ static int set_disk_faulty(mddev_t *mddev, dev_t dev)
return -ENODEV;
md_error(mddev, rdev);
+ if (!test_bit(Faulty, &rdev->flags))
+ return -EBUSY;
return 0;
}
@@ -6411,11 +6439,18 @@ mdk_thread_t *md_register_thread(void (*run) (mddev_t *), mddev_t *mddev,
return thread;
}
-void md_unregister_thread(mdk_thread_t *thread)
+void md_unregister_thread(mdk_thread_t **threadp)
{
+ mdk_thread_t *thread = *threadp;
if (!thread)
return;
dprintk("interrupting MD-thread pid %d\n", task_pid_nr(thread->tsk));
+ /* Locking ensures that mddev_unlock does not wake_up a
+ * non-existent thread
+ */
+ spin_lock(&pers_lock);
+ *threadp = NULL;
+ spin_unlock(&pers_lock);
kthread_stop(thread->tsk);
kfree(thread);
@@ -7322,8 +7357,7 @@ static void reap_sync_thread(mddev_t *mddev)
mdk_rdev_t *rdev;
/* resync has finished, collect result */
- md_unregister_thread(mddev->sync_thread);
- mddev->sync_thread = NULL;
+ md_unregister_thread(&mddev->sync_thread);
if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery) &&
!test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
/* success...*/
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 1e586bb4452e..0a309dc29b45 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -560,7 +560,7 @@ extern int register_md_personality(struct mdk_personality *p);
extern int unregister_md_personality(struct mdk_personality *p);
extern mdk_thread_t * md_register_thread(void (*run) (mddev_t *mddev),
mddev_t *mddev, const char *name);
-extern void md_unregister_thread(mdk_thread_t *thread);
+extern void md_unregister_thread(mdk_thread_t **threadp);
extern void md_wakeup_thread(mdk_thread_t *thread);
extern void md_check_recovery(mddev_t *mddev);
extern void md_write_start(mddev_t *mddev, struct bio *bi);
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 3535c23af288..d5b5fb300171 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -514,8 +514,7 @@ static int multipath_stop (mddev_t *mddev)
{
multipath_conf_t *conf = mddev->private;
- md_unregister_thread(mddev->thread);
- mddev->thread = NULL;
+ md_unregister_thread(&mddev->thread);
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
mempool_destroy(conf->pool);
kfree(conf->multipaths);
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 32323f0afd89..d9587dffe533 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1099,12 +1099,11 @@ read_again:
bio_list_add(&conf->pending_bio_list, mbio);
spin_unlock_irqrestore(&conf->device_lock, flags);
}
- r1_bio_write_done(r1_bio);
-
- /* In case raid1d snuck in to freeze_array */
- wake_up(&conf->wait_barrier);
-
+ /* Mustn't call r1_bio_write_done before this next test,
+ * as it could result in the bio being freed.
+ */
if (sectors_handled < (bio->bi_size >> 9)) {
+ r1_bio_write_done(r1_bio);
/* We need another r1_bio. It has already been counted
* in bio->bi_phys_segments
*/
@@ -1117,6 +1116,11 @@ read_again:
goto retry_write;
}
+ r1_bio_write_done(r1_bio);
+
+ /* In case raid1d snuck in to freeze_array */
+ wake_up(&conf->wait_barrier);
+
if (do_sync || !bitmap || !plugged)
md_wakeup_thread(mddev->thread);
@@ -2558,8 +2562,7 @@ static int stop(mddev_t *mddev)
raise_barrier(conf);
lower_barrier(conf);
- md_unregister_thread(mddev->thread);
- mddev->thread = NULL;
+ md_unregister_thread(&mddev->thread);
if (conf->r1bio_pool)
mempool_destroy(conf->r1bio_pool);
kfree(conf->mirrors);
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 8b29cd4f01c8..0cd9672cf9cb 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -337,6 +337,21 @@ static void close_write(r10bio_t *r10_bio)
md_write_end(r10_bio->mddev);
}
+static void one_write_done(r10bio_t *r10_bio)
+{
+ if (atomic_dec_and_test(&r10_bio->remaining)) {
+ if (test_bit(R10BIO_WriteError, &r10_bio->state))
+ reschedule_retry(r10_bio);
+ else {
+ close_write(r10_bio);
+ if (test_bit(R10BIO_MadeGood, &r10_bio->state))
+ reschedule_retry(r10_bio);
+ else
+ raid_end_bio_io(r10_bio);
+ }
+ }
+}
+
static void raid10_end_write_request(struct bio *bio, int error)
{
int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
@@ -387,17 +402,7 @@ static void raid10_end_write_request(struct bio *bio, int error)
* Let's see if all mirrored write operations have finished
* already.
*/
- if (atomic_dec_and_test(&r10_bio->remaining)) {
- if (test_bit(R10BIO_WriteError, &r10_bio->state))
- reschedule_retry(r10_bio);
- else {
- close_write(r10_bio);
- if (test_bit(R10BIO_MadeGood, &r10_bio->state))
- reschedule_retry(r10_bio);
- else
- raid_end_bio_io(r10_bio);
- }
- }
+ one_write_done(r10_bio);
if (dec_rdev)
rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev);
}
@@ -1127,20 +1132,12 @@ retry_write:
spin_unlock_irqrestore(&conf->device_lock, flags);
}
- if (atomic_dec_and_test(&r10_bio->remaining)) {
- /* This matches the end of raid10_end_write_request() */
- bitmap_endwrite(r10_bio->mddev->bitmap, r10_bio->sector,
- r10_bio->sectors,
- !test_bit(R10BIO_Degraded, &r10_bio->state),
- 0);
- md_write_end(mddev);
- raid_end_bio_io(r10_bio);
- }
-
- /* In case raid10d snuck in to freeze_array */
- wake_up(&conf->wait_barrier);
+ /* Don't remove the bias on 'remaining' (one_write_done) until
+ * after checking if we need to go around again.
+ */
if (sectors_handled < (bio->bi_size >> 9)) {
+ one_write_done(r10_bio);
/* We need another r10_bio. It has already been counted
* in bio->bi_phys_segments.
*/
@@ -1154,6 +1151,10 @@ retry_write:
r10_bio->state = 0;
goto retry_write;
}
+ one_write_done(r10_bio);
+
+ /* In case raid10d snuck in to freeze_array */
+ wake_up(&conf->wait_barrier);
if (do_sync || !mddev->bitmap || !plugged)
md_wakeup_thread(mddev->thread);
@@ -2954,7 +2955,7 @@ static int run(mddev_t *mddev)
return 0;
out_free_conf:
- md_unregister_thread(mddev->thread);
+ md_unregister_thread(&mddev->thread);
if (conf->r10bio_pool)
mempool_destroy(conf->r10bio_pool);
safe_put_page(conf->tmppage);
@@ -2972,8 +2973,7 @@ static int stop(mddev_t *mddev)
raise_barrier(conf, 0);
lower_barrier(conf);
- md_unregister_thread(mddev->thread);
- mddev->thread = NULL;
+ md_unregister_thread(&mddev->thread);
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
if (conf->r10bio_pool)
mempool_destroy(conf->r10bio_pool);
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index dbae459fb02d..ac5e8b57e50f 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -3336,7 +3336,7 @@ static void handle_stripe(struct stripe_head *sh)
finish:
/* wait for this device to become unblocked */
- if (unlikely(s.blocked_rdev))
+ if (conf->mddev->external && unlikely(s.blocked_rdev))
md_wait_for_blocked_rdev(s.blocked_rdev, conf->mddev);
if (s.handle_bad_blocks)
@@ -4941,8 +4941,7 @@ static int run(mddev_t *mddev)
return 0;
abort:
- md_unregister_thread(mddev->thread);
- mddev->thread = NULL;
+ md_unregister_thread(&mddev->thread);
if (conf) {
print_raid5_conf(conf);
free_conf(conf);
@@ -4956,8 +4955,7 @@ static int stop(mddev_t *mddev)
{
raid5_conf_t *conf = mddev->private;
- md_unregister_thread(mddev->thread);
- mddev->thread = NULL;
+ md_unregister_thread(&mddev->thread);
if (mddev->queue)
mddev->queue->backing_dev_info.congested_fn = NULL;
free_conf(conf);
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 51752a9ef7a4..93d9869e0f15 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -1230,7 +1230,7 @@ static const struct net_device_ops dvb_netdev_ops = {
.ndo_open = dvb_net_open,
.ndo_stop = dvb_net_stop,
.ndo_start_xmit = dvb_net_tx,
- .ndo_set_multicast_list = dvb_net_set_multicast_list,
+ .ndo_set_rx_mode = dvb_net_set_multicast_list,
.ndo_set_mac_address = dvb_net_set_mac,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/media/dvb/dvb-usb/af9005-remote.c b/drivers/media/dvb/dvb-usb/af9005-remote.c
index c3bc64ed405c..7e3961d0db6b 100644
--- a/drivers/media/dvb/dvb-usb/af9005-remote.c
+++ b/drivers/media/dvb/dvb-usb/af9005-remote.c
@@ -21,7 +21,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * see Documentation/dvb/REDME.dvb-usb for more information
+ * see Documentation/dvb/README.dvb-usb for more information
*/
#include "af9005.h"
/* debug */
diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c
index 51f6439dcfd5..0351c0e52dd2 100644
--- a/drivers/media/dvb/dvb-usb/af9005.c
+++ b/drivers/media/dvb/dvb-usb/af9005.c
@@ -19,7 +19,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * see Documentation/dvb/REDME.dvb-usb for more information
+ * see Documentation/dvb/README.dvb-usb for more information
*/
#include "af9005.h"
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
index 3db89e3cb0bb..536c16c943bd 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -224,26 +224,8 @@ static struct dvb_usb_device_properties vp7045_properties;
static int vp7045_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- struct dvb_usb_device *d;
- int ret = dvb_usb_device_init(intf, &vp7045_properties,
- THIS_MODULE, &d, adapter_nr);
- if (ret)
- return ret;
-
- d->priv = kmalloc(20, GFP_KERNEL);
- if (!d->priv) {
- dvb_usb_device_exit(intf);
- return -ENOMEM;
- }
-
- return ret;
-}
-
-static void vp7045_usb_disconnect(struct usb_interface *intf)
-{
- struct dvb_usb_device *d = usb_get_intfdata(intf);
- kfree(d->priv);
- dvb_usb_device_exit(intf);
+ return dvb_usb_device_init(intf, &vp7045_properties,
+ THIS_MODULE, NULL, adapter_nr);
}
static struct usb_device_id vp7045_usb_table [] = {
@@ -258,7 +240,7 @@ MODULE_DEVICE_TABLE(usb, vp7045_usb_table);
static struct dvb_usb_device_properties vp7045_properties = {
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-vp7045-01.fw",
- .size_of_priv = sizeof(u8 *),
+ .size_of_priv = 20,
.num_adapters = 1,
.adapter = {
@@ -305,7 +287,7 @@ static struct dvb_usb_device_properties vp7045_properties = {
static struct usb_driver vp7045_usb_driver = {
.name = "dvb_usb_vp7045",
.probe = vp7045_usb_probe,
- .disconnect = vp7045_usb_disconnect,
+ .disconnect = dvb_usb_device_exit,
.id_table = vp7045_usb_table,
};
diff --git a/drivers/media/dvb/frontends/dib3000.h b/drivers/media/dvb/frontends/dib3000.h
index ba917359fa65..404f63a6f26b 100644
--- a/drivers/media/dvb/frontends/dib3000.h
+++ b/drivers/media/dvb/frontends/dib3000.h
@@ -17,7 +17,7 @@
* Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
* sources, on which this driver (and the dvb-dibusb) are based.
*
- * see Documentation/dvb/README.dibusb for more information
+ * see Documentation/dvb/README.dvb-usb for more information
*
*/
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c
index e80c59796368..437904cbf3e6 100644
--- a/drivers/media/dvb/frontends/dib3000mb.c
+++ b/drivers/media/dvb/frontends/dib3000mb.c
@@ -17,7 +17,7 @@
* Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
* sources, on which this driver (and the dvb-dibusb) are based.
*
- * see Documentation/dvb/README.dibusb for more information
+ * see Documentation/dvb/README.dvb-usb for more information
*
*/
diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c
index 8c0e19276970..ec1d52f38904 100644
--- a/drivers/media/radio/wl128x/fmdrv_v4l2.c
+++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c
@@ -402,7 +402,7 @@ static int fm_v4l2_vidioc_s_hw_freq_seek(struct file *file, void *priv,
static int fm_v4l2_vidioc_g_modulator(struct file *file, void *priv,
struct v4l2_modulator *mod)
{
- struct fmdev *fmdev = video_drvdata(file);;
+ struct fmdev *fmdev = video_drvdata(file);
if (mod->index != 0)
return -EINVAL;
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index eae05b500476..144f3f55d765 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -618,7 +618,6 @@ static void nvt_dump_rx_buf(struct nvt_dev *nvt)
static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
{
DEFINE_IR_RAW_EVENT(rawir);
- unsigned int count;
u32 carrier;
u8 sample;
int i;
@@ -631,65 +630,38 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
if (nvt->carrier_detect_enabled)
carrier = nvt_rx_carrier_detect(nvt);
- count = nvt->pkts;
- nvt_dbg_verbose("Processing buffer of len %d", count);
+ nvt_dbg_verbose("Processing buffer of len %d", nvt->pkts);
init_ir_raw_event(&rawir);
- for (i = 0; i < count; i++) {
- nvt->pkts--;
+ for (i = 0; i < nvt->pkts; i++) {
sample = nvt->buf[i];
rawir.pulse = ((sample & BUF_PULSE_BIT) != 0);
rawir.duration = US_TO_NS((sample & BUF_LEN_MASK)
* SAMPLE_PERIOD);
- if ((sample & BUF_LEN_MASK) == BUF_LEN_MASK) {
- if (nvt->rawir.pulse == rawir.pulse)
- nvt->rawir.duration += rawir.duration;
- else {
- nvt->rawir.duration = rawir.duration;
- nvt->rawir.pulse = rawir.pulse;
- }
- continue;
- }
-
- rawir.duration += nvt->rawir.duration;
+ nvt_dbg("Storing %s with duration %d",
+ rawir.pulse ? "pulse" : "space", rawir.duration);
- init_ir_raw_event(&nvt->rawir);
- nvt->rawir.duration = 0;
- nvt->rawir.pulse = rawir.pulse;
-
- if (sample == BUF_PULSE_BIT)
- rawir.pulse = false;
-
- if (rawir.duration) {
- nvt_dbg("Storing %s with duration %d",
- rawir.pulse ? "pulse" : "space",
- rawir.duration);
-
- ir_raw_event_store_with_filter(nvt->rdev, &rawir);
- }
+ ir_raw_event_store_with_filter(nvt->rdev, &rawir);
/*
* BUF_PULSE_BIT indicates end of IR data, BUF_REPEAT_BYTE
* indicates end of IR signal, but new data incoming. In both
* cases, it means we're ready to call ir_raw_event_handle
*/
- if ((sample == BUF_PULSE_BIT) && nvt->pkts) {
+ if ((sample == BUF_PULSE_BIT) && (i + 1 < nvt->pkts)) {
nvt_dbg("Calling ir_raw_event_handle (signal end)\n");
ir_raw_event_handle(nvt->rdev);
}
}
+ nvt->pkts = 0;
+
nvt_dbg("Calling ir_raw_event_handle (buffer empty)\n");
ir_raw_event_handle(nvt->rdev);
- if (nvt->pkts) {
- nvt_dbg("Odd, pkts should be 0 now... (its %u)", nvt->pkts);
- nvt->pkts = 0;
- }
-
nvt_dbg_verbose("%s done", __func__);
}
@@ -1048,7 +1020,6 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
spin_lock_init(&nvt->nvt_lock);
spin_lock_init(&nvt->tx.lock);
- init_ir_raw_event(&nvt->rawir);
ret = -EBUSY;
/* now claim resources */
diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h
index 1241fc89a36c..0d5e0872a2ea 100644
--- a/drivers/media/rc/nuvoton-cir.h
+++ b/drivers/media/rc/nuvoton-cir.h
@@ -67,7 +67,6 @@ static int debug;
struct nvt_dev {
struct pnp_dev *pdev;
struct rc_dev *rdev;
- struct ir_raw_event rawir;
spinlock_t nvt_lock;
diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h
index 05fe6bdbe062..b63fdfaac49e 100644
--- a/drivers/media/video/cx18/cx18-mailbox.h
+++ b/drivers/media/video/cx18/cx18-mailbox.h
@@ -69,7 +69,7 @@ struct cx18_mailbox {
/* Each command can have up to 6 arguments */
u32 args[MAX_MB_ARGUMENTS];
/* The return code can be one of the codes in the file cx23418.h. If the
- command is completed successfuly, the error will be ERR_SYS_SUCCESS.
+ command is completed successfully, the error will be ERR_SYS_SUCCESS.
If it is pending, the code is ERR_SYS_PENDING. If it failed, the error
code would indicate the task from which the error originated and will
be one of the errors in cx23418.h. In that case, the following
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c
index 0800433b2092..18305c89083c 100644
--- a/drivers/media/video/gspca/ov519.c
+++ b/drivers/media/video/gspca/ov519.c
@@ -2858,7 +2858,6 @@ static void ov7xx0_configure(struct sd *sd)
case 0x60:
PDEBUG(D_PROBE, "Sensor is a OV7660");
sd->sensor = SEN_OV7660;
- sd->invert_led = 0;
break;
default:
PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low);
@@ -3337,7 +3336,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
case BRIDGE_OV519:
cam->cam_mode = ov519_vga_mode;
cam->nmodes = ARRAY_SIZE(ov519_vga_mode);
- sd->invert_led = !sd->invert_led;
break;
case BRIDGE_OVFX2:
cam->cam_mode = ov519_vga_mode;
@@ -5005,24 +5003,24 @@ static const struct sd_desc sd_desc = {
/* -- module initialisation -- */
static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x4003), .driver_info = BRIDGE_W9968CF },
- {USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 },
- {USB_DEVICE(0x041e, 0x405f),
+ {USB_DEVICE(0x041e, 0x4052),
.driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
+ {USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x041e, 0x4060), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x041e, 0x4061), .driver_info = BRIDGE_OV519 },
- {USB_DEVICE(0x041e, 0x4064),
- .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
+ {USB_DEVICE(0x041e, 0x4064), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x041e, 0x4067), .driver_info = BRIDGE_OV519 },
- {USB_DEVICE(0x041e, 0x4068),
+ {USB_DEVICE(0x041e, 0x4068), .driver_info = BRIDGE_OV519 },
+ {USB_DEVICE(0x045e, 0x028c),
.driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
- {USB_DEVICE(0x045e, 0x028c), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x054c, 0x0154), .driver_info = BRIDGE_OV519 },
- {USB_DEVICE(0x054c, 0x0155),
- .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
+ {USB_DEVICE(0x054c, 0x0155), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x05a9, 0x0511), .driver_info = BRIDGE_OV511 },
{USB_DEVICE(0x05a9, 0x0518), .driver_info = BRIDGE_OV518 },
- {USB_DEVICE(0x05a9, 0x0519), .driver_info = BRIDGE_OV519 },
- {USB_DEVICE(0x05a9, 0x0530), .driver_info = BRIDGE_OV519 },
+ {USB_DEVICE(0x05a9, 0x0519),
+ .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
+ {USB_DEVICE(0x05a9, 0x0530),
+ .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
{USB_DEVICE(0x05a9, 0x2800), .driver_info = BRIDGE_OVFX2 },
{USB_DEVICE(0x05a9, 0x4519), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x05a9, 0x8519), .driver_info = BRIDGE_OV519 },
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index 81b8a600783b..c477ad11f103 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -2386,7 +2386,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0x01, 0x22);
msleep(100);
reg01 = SCL_SEL_OD | S_PDN_INV;
- reg17 &= MCK_SIZE_MASK;
+ reg17 &= ~MCK_SIZE_MASK;
reg17 |= 0x04; /* clock / 4 */
break;
}
@@ -2532,6 +2532,10 @@ static int sd_start(struct gspca_dev *gspca_dev)
if (!mode) { /* if 640x480 */
reg17 &= ~MCK_SIZE_MASK;
reg17 |= 0x04; /* clock / 4 */
+ } else {
+ reg01 &= ~SYS_SEL_48M; /* clk 24Mz */
+ reg17 &= ~MCK_SIZE_MASK;
+ reg17 |= 0x02; /* clock / 2 */
}
break;
case SENSOR_OV7630:
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c
index b5ef36222440..b3a5ecdb33ac 100644
--- a/drivers/media/video/omap/omap_vout.c
+++ b/drivers/media/video/omap/omap_vout.c
@@ -2194,19 +2194,6 @@ static int __init omap_vout_probe(struct platform_device *pdev)
"'%s' Display already enabled\n",
def_display->name);
}
- /* set the update mode */
- if (def_display->caps &
- OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
- if (dssdrv->enable_te)
- dssdrv->enable_te(def_display, 0);
- if (dssdrv->set_update_mode)
- dssdrv->set_update_mode(def_display,
- OMAP_DSS_UPDATE_MANUAL);
- } else {
- if (dssdrv->set_update_mode)
- dssdrv->set_update_mode(def_display,
- OMAP_DSS_UPDATE_AUTO);
- }
}
}
diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c
index 9d3459de04b2..80796eb0c53e 100644
--- a/drivers/media/video/omap3isp/ispccdc.c
+++ b/drivers/media/video/omap3isp/ispccdc.c
@@ -31,6 +31,7 @@
#include <linux/dma-mapping.h>
#include <linux/mm.h>
#include <linux/sched.h>
+#include <linux/slab.h>
#include <media/v4l2-event.h>
#include "isp.h"
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
index e9a0e94b9995..8c70e64444e7 100644
--- a/drivers/media/video/pwc/pwc-v4l.c
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -338,7 +338,7 @@ int pwc_init_controls(struct pwc_device *pdev)
if (pdev->restore_factory)
pdev->restore_factory->flags = V4L2_CTRL_FLAG_UPDATE;
- if (!pdev->features & FEATURE_MOTOR_PANTILT)
+ if (!(pdev->features & FEATURE_MOTOR_PANTILT))
return hdl->error;
/* Motor pan / tilt / reset */
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index d29f9c2d0854..e4100b1f68df 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -1961,7 +1961,7 @@ static int __uvc_resume(struct usb_interface *intf, int reset)
list_for_each_entry(stream, &dev->streams, list) {
if (stream->intf == intf)
- return uvc_video_resume(stream);
+ return uvc_video_resume(stream, reset);
}
uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB interface "
diff --git a/drivers/media/video/uvc/uvc_entity.c b/drivers/media/video/uvc/uvc_entity.c
index 48fea373c25a..29e239911d0e 100644
--- a/drivers/media/video/uvc/uvc_entity.c
+++ b/drivers/media/video/uvc/uvc_entity.c
@@ -49,7 +49,7 @@ static int uvc_mc_register_entity(struct uvc_video_chain *chain,
if (remote == NULL)
return -EINVAL;
- source = (UVC_ENTITY_TYPE(remote) != UVC_TT_STREAMING)
+ source = (UVC_ENTITY_TYPE(remote) == UVC_TT_STREAMING)
? (remote->vdev ? &remote->vdev->entity : NULL)
: &remote->subdev.entity;
if (source == NULL)
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index 8244167c8915..ffd1158628b6 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -1104,10 +1104,18 @@ int uvc_video_suspend(struct uvc_streaming *stream)
* buffers, making sure userspace applications are notified of the problem
* instead of waiting forever.
*/
-int uvc_video_resume(struct uvc_streaming *stream)
+int uvc_video_resume(struct uvc_streaming *stream, int reset)
{
int ret;
+ /* If the bus has been reset on resume, set the alternate setting to 0.
+ * This should be the default value, but some devices crash or otherwise
+ * misbehave if they don't receive a SET_INTERFACE request before any
+ * other video control request.
+ */
+ if (reset)
+ usb_set_interface(stream->dev->udev, stream->intfnum, 0);
+
stream->frozen = 0;
ret = uvc_commit_video(stream, &stream->ctrl);
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index df32a43ca86a..cbdd49bf8b67 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -638,7 +638,7 @@ extern void uvc_mc_cleanup_entity(struct uvc_entity *entity);
/* Video */
extern int uvc_video_init(struct uvc_streaming *stream);
extern int uvc_video_suspend(struct uvc_streaming *stream);
-extern int uvc_video_resume(struct uvc_streaming *stream);
+extern int uvc_video_resume(struct uvc_streaming *stream, int reset);
extern int uvc_video_enable(struct uvc_streaming *stream, int enable);
extern int uvc_probe_video(struct uvc_streaming *stream,
struct uvc_streaming_control *probe);
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 06f14008b346..a5c9ed128b97 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -173,6 +173,17 @@ static void v4l2_device_release(struct device *cd)
media_device_unregister_entity(&vdev->entity);
#endif
+ /* Do not call v4l2_device_put if there is no release callback set.
+ * Drivers that have no v4l2_device release callback might free the
+ * v4l2_dev instance in the video_device release callback below, so we
+ * must perform this check here.
+ *
+ * TODO: In the long run all drivers that use v4l2_device should use the
+ * v4l2_device release callback. This check will then be unnecessary.
+ */
+ if (v4l2_dev && v4l2_dev->release == NULL)
+ v4l2_dev = NULL;
+
/* Release video_device and perform other
cleanups as needed. */
vdev->release(vdev);
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
index c72856c41434..e6a2c3b302d4 100644
--- a/drivers/media/video/v4l2-device.c
+++ b/drivers/media/video/v4l2-device.c
@@ -38,6 +38,7 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
mutex_init(&v4l2_dev->ioctl_lock);
v4l2_prio_init(&v4l2_dev->prio);
kref_init(&v4l2_dev->ref);
+ get_device(dev);
v4l2_dev->dev = dev;
if (dev == NULL) {
/* If dev == NULL, then name must be filled in by the caller */
@@ -93,6 +94,7 @@ void v4l2_device_disconnect(struct v4l2_device *v4l2_dev)
if (dev_get_drvdata(v4l2_dev->dev) == v4l2_dev)
dev_set_drvdata(v4l2_dev->dev, NULL);
+ put_device(v4l2_dev->dev);
v4l2_dev->dev = NULL;
}
EXPORT_SYMBOL_GPL(v4l2_device_disconnect);
diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c
index 85d3048c1d67..cbf13d09b4ac 100644
--- a/drivers/media/video/via-camera.c
+++ b/drivers/media/video/via-camera.c
@@ -21,7 +21,7 @@
#include <media/videobuf-dma-sg.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
#include <linux/via-core.h>
#include <linux/via-gpio.h>
#include <linux/via_i2c.h>
@@ -69,7 +69,7 @@ struct via_camera {
struct mutex lock;
enum viacam_opstate opstate;
unsigned long flags;
- struct pm_qos_request_list qos_request;
+ struct pm_qos_request qos_request;
/*
* GPIO info for power/reset management
*/
@@ -1332,6 +1332,8 @@ static __devinit bool viacam_serial_is_enabled(void)
struct pci_bus *pbus = pci_find_bus(0, 0);
u8 cbyte;
+ if (!pbus)
+ return false;
pci_bus_read_config_byte(pbus, VIACAM_SERIAL_DEVFN,
VIACAM_SERIAL_CREG, &cbyte);
if ((cbyte & VIACAM_SERIAL_BIT) == 0)
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 21574bdf485f..a67adcbd0fa1 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -404,6 +404,7 @@ config MFD_WM831X_I2C
bool "Support Wolfson Microelectronics WM831x/2x PMICs with I2C"
select MFD_CORE
select MFD_WM831X
+ select REGMAP_I2C
depends on I2C=y && GENERIC_HARDIRQS
help
Support for the Wolfson Microelecronics WM831x and WM832x PMICs
@@ -415,6 +416,7 @@ config MFD_WM831X_SPI
bool "Support Wolfson Microelectronics WM831x/2x PMICs with SPI"
select MFD_CORE
select MFD_WM831X
+ select REGMAP_SPI
depends on SPI_MASTER && GENERIC_HARDIRQS
help
Support for the Wolfson Microelecronics WM831x and WM832x PMICs
@@ -488,6 +490,7 @@ config MFD_WM8350_I2C
config MFD_WM8994
bool "Support Wolfson Microelectronics WM8994"
select MFD_CORE
+ select REGMAP_I2C
depends on I2C=y && GENERIC_HARDIRQS
help
The WM8994 is a highly integrated hi-fi CODEC designed for
diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c
index 21131c7b0f1e..563654c9b19e 100644
--- a/drivers/mfd/jz4740-adc.c
+++ b/drivers/mfd/jz4740-adc.c
@@ -273,7 +273,7 @@ static int __devinit jz4740_adc_probe(struct platform_device *pdev)
ct->regs.ack = JZ_REG_ADC_STATUS;
ct->chip.irq_mask = irq_gc_mask_set_bit;
ct->chip.irq_unmask = irq_gc_mask_clr_bit;
- ct->chip.irq_ack = irq_gc_ack;
+ ct->chip.irq_ack = irq_gc_ack_set_bit;
irq_setup_generic_chip(gc, IRQ_MSK(5), 0, 0, IRQ_NOPROBE | IRQ_LEVEL);
diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c
index 5d1fca0277ef..f83103b8970d 100644
--- a/drivers/mfd/max8997.c
+++ b/drivers/mfd/max8997.c
@@ -135,10 +135,13 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
max8997->dev = &i2c->dev;
max8997->i2c = i2c;
max8997->type = id->driver_data;
+ max8997->irq = i2c->irq;
if (!pdata)
goto err;
+ max8997->irq_base = pdata->irq_base;
+ max8997->ono = pdata->ono;
max8997->wakeup = pdata->wakeup;
mutex_init(&max8997->iolock);
@@ -152,6 +155,8 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
pm_runtime_set_active(max8997->dev);
+ max8997_irq_init(max8997);
+
mfd_add_devices(max8997->dev, -1, max8997_devs,
ARRAY_SIZE(max8997_devs),
NULL, 0);
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 29601e7d606d..86e14583a082 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -17,6 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -676,7 +677,6 @@ static void usbhs_omap_tll_init(struct device *dev, u8 tll_channel_count)
| OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF
| OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE);
- reg |= (1 << (i + 1));
} else
continue;
diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c
index 2bfad5c86cc7..a56be931551c 100644
--- a/drivers/mfd/tps65910-irq.c
+++ b/drivers/mfd/tps65910-irq.c
@@ -178,8 +178,10 @@ int tps65910_irq_init(struct tps65910 *tps65910, int irq,
switch (tps65910_chip_id(tps65910)) {
case TPS65910:
tps65910->irq_num = TPS65910_NUM_IRQ;
+ break;
case TPS65911:
tps65910->irq_num = TPS65911_NUM_IRQ;
+ break;
}
/* Register with genirq */
diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c
index b5d598c3aa71..7cbf2aa9e64f 100644
--- a/drivers/mfd/twl4030-madc.c
+++ b/drivers/mfd/twl4030-madc.c
@@ -510,8 +510,9 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req)
u8 ch_msb, ch_lsb;
int ret;
- if (!req)
+ if (!req || !twl4030_madc)
return -EINVAL;
+
mutex_lock(&twl4030_madc->lock);
if (req->method < TWL4030_MADC_RT || req->method > TWL4030_MADC_SW2) {
ret = -EINVAL;
@@ -706,6 +707,8 @@ static int __devinit twl4030_madc_probe(struct platform_device *pdev)
if (!madc)
return -ENOMEM;
+ madc->dev = &pdev->dev;
+
/*
* Phoenix provides 2 interrupt lines. The first one is connected to
* the OMAP. The other one can be connected to the other processor such
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index 282e76ab678f..0a2b8d41a702 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -18,12 +18,14 @@
#include <linux/delay.h>
#include <linux/mfd/core.h>
#include <linux/slab.h>
+#include <linux/err.h>
#include <linux/mfd/wm831x/core.h>
#include <linux/mfd/wm831x/pdata.h>
#include <linux/mfd/wm831x/irq.h>
#include <linux/mfd/wm831x/auxadc.h>
#include <linux/mfd/wm831x/otp.h>
+#include <linux/mfd/wm831x/pmu.h>
#include <linux/mfd/wm831x/regulator.h>
/* Current settings - values are 2*2^(reg_val/4) microamps. These are
@@ -160,27 +162,350 @@ int wm831x_reg_unlock(struct wm831x *wm831x)
}
EXPORT_SYMBOL_GPL(wm831x_reg_unlock);
-static int wm831x_read(struct wm831x *wm831x, unsigned short reg,
- int bytes, void *dest)
+static bool wm831x_reg_readable(struct device *dev, unsigned int reg)
{
- int ret, i;
- u16 *buf = dest;
-
- BUG_ON(bytes % 2);
- BUG_ON(bytes <= 0);
+ switch (reg) {
+ case WM831X_RESET_ID:
+ case WM831X_REVISION:
+ case WM831X_PARENT_ID:
+ case WM831X_SYSVDD_CONTROL:
+ case WM831X_THERMAL_MONITORING:
+ case WM831X_POWER_STATE:
+ case WM831X_WATCHDOG:
+ case WM831X_ON_PIN_CONTROL:
+ case WM831X_RESET_CONTROL:
+ case WM831X_CONTROL_INTERFACE:
+ case WM831X_SECURITY_KEY:
+ case WM831X_SOFTWARE_SCRATCH:
+ case WM831X_OTP_CONTROL:
+ case WM831X_GPIO_LEVEL:
+ case WM831X_SYSTEM_STATUS:
+ case WM831X_ON_SOURCE:
+ case WM831X_OFF_SOURCE:
+ case WM831X_SYSTEM_INTERRUPTS:
+ case WM831X_INTERRUPT_STATUS_1:
+ case WM831X_INTERRUPT_STATUS_2:
+ case WM831X_INTERRUPT_STATUS_3:
+ case WM831X_INTERRUPT_STATUS_4:
+ case WM831X_INTERRUPT_STATUS_5:
+ case WM831X_IRQ_CONFIG:
+ case WM831X_SYSTEM_INTERRUPTS_MASK:
+ case WM831X_INTERRUPT_STATUS_1_MASK:
+ case WM831X_INTERRUPT_STATUS_2_MASK:
+ case WM831X_INTERRUPT_STATUS_3_MASK:
+ case WM831X_INTERRUPT_STATUS_4_MASK:
+ case WM831X_INTERRUPT_STATUS_5_MASK:
+ case WM831X_RTC_WRITE_COUNTER:
+ case WM831X_RTC_TIME_1:
+ case WM831X_RTC_TIME_2:
+ case WM831X_RTC_ALARM_1:
+ case WM831X_RTC_ALARM_2:
+ case WM831X_RTC_CONTROL:
+ case WM831X_RTC_TRIM:
+ case WM831X_TOUCH_CONTROL_1:
+ case WM831X_TOUCH_CONTROL_2:
+ case WM831X_TOUCH_DATA_X:
+ case WM831X_TOUCH_DATA_Y:
+ case WM831X_TOUCH_DATA_Z:
+ case WM831X_AUXADC_DATA:
+ case WM831X_AUXADC_CONTROL:
+ case WM831X_AUXADC_SOURCE:
+ case WM831X_COMPARATOR_CONTROL:
+ case WM831X_COMPARATOR_1:
+ case WM831X_COMPARATOR_2:
+ case WM831X_COMPARATOR_3:
+ case WM831X_COMPARATOR_4:
+ case WM831X_GPIO1_CONTROL:
+ case WM831X_GPIO2_CONTROL:
+ case WM831X_GPIO3_CONTROL:
+ case WM831X_GPIO4_CONTROL:
+ case WM831X_GPIO5_CONTROL:
+ case WM831X_GPIO6_CONTROL:
+ case WM831X_GPIO7_CONTROL:
+ case WM831X_GPIO8_CONTROL:
+ case WM831X_GPIO9_CONTROL:
+ case WM831X_GPIO10_CONTROL:
+ case WM831X_GPIO11_CONTROL:
+ case WM831X_GPIO12_CONTROL:
+ case WM831X_GPIO13_CONTROL:
+ case WM831X_GPIO14_CONTROL:
+ case WM831X_GPIO15_CONTROL:
+ case WM831X_GPIO16_CONTROL:
+ case WM831X_CHARGER_CONTROL_1:
+ case WM831X_CHARGER_CONTROL_2:
+ case WM831X_CHARGER_STATUS:
+ case WM831X_BACKUP_CHARGER_CONTROL:
+ case WM831X_STATUS_LED_1:
+ case WM831X_STATUS_LED_2:
+ case WM831X_CURRENT_SINK_1:
+ case WM831X_CURRENT_SINK_2:
+ case WM831X_DCDC_ENABLE:
+ case WM831X_LDO_ENABLE:
+ case WM831X_DCDC_STATUS:
+ case WM831X_LDO_STATUS:
+ case WM831X_DCDC_UV_STATUS:
+ case WM831X_LDO_UV_STATUS:
+ case WM831X_DC1_CONTROL_1:
+ case WM831X_DC1_CONTROL_2:
+ case WM831X_DC1_ON_CONFIG:
+ case WM831X_DC1_SLEEP_CONTROL:
+ case WM831X_DC1_DVS_CONTROL:
+ case WM831X_DC2_CONTROL_1:
+ case WM831X_DC2_CONTROL_2:
+ case WM831X_DC2_ON_CONFIG:
+ case WM831X_DC2_SLEEP_CONTROL:
+ case WM831X_DC2_DVS_CONTROL:
+ case WM831X_DC3_CONTROL_1:
+ case WM831X_DC3_CONTROL_2:
+ case WM831X_DC3_ON_CONFIG:
+ case WM831X_DC3_SLEEP_CONTROL:
+ case WM831X_DC4_CONTROL:
+ case WM831X_DC4_SLEEP_CONTROL:
+ case WM831X_EPE1_CONTROL:
+ case WM831X_EPE2_CONTROL:
+ case WM831X_LDO1_CONTROL:
+ case WM831X_LDO1_ON_CONTROL:
+ case WM831X_LDO1_SLEEP_CONTROL:
+ case WM831X_LDO2_CONTROL:
+ case WM831X_LDO2_ON_CONTROL:
+ case WM831X_LDO2_SLEEP_CONTROL:
+ case WM831X_LDO3_CONTROL:
+ case WM831X_LDO3_ON_CONTROL:
+ case WM831X_LDO3_SLEEP_CONTROL:
+ case WM831X_LDO4_CONTROL:
+ case WM831X_LDO4_ON_CONTROL:
+ case WM831X_LDO4_SLEEP_CONTROL:
+ case WM831X_LDO5_CONTROL:
+ case WM831X_LDO5_ON_CONTROL:
+ case WM831X_LDO5_SLEEP_CONTROL:
+ case WM831X_LDO6_CONTROL:
+ case WM831X_LDO6_ON_CONTROL:
+ case WM831X_LDO6_SLEEP_CONTROL:
+ case WM831X_LDO7_CONTROL:
+ case WM831X_LDO7_ON_CONTROL:
+ case WM831X_LDO7_SLEEP_CONTROL:
+ case WM831X_LDO8_CONTROL:
+ case WM831X_LDO8_ON_CONTROL:
+ case WM831X_LDO8_SLEEP_CONTROL:
+ case WM831X_LDO9_CONTROL:
+ case WM831X_LDO9_ON_CONTROL:
+ case WM831X_LDO9_SLEEP_CONTROL:
+ case WM831X_LDO10_CONTROL:
+ case WM831X_LDO10_ON_CONTROL:
+ case WM831X_LDO10_SLEEP_CONTROL:
+ case WM831X_LDO11_ON_CONTROL:
+ case WM831X_LDO11_SLEEP_CONTROL:
+ case WM831X_POWER_GOOD_SOURCE_1:
+ case WM831X_POWER_GOOD_SOURCE_2:
+ case WM831X_CLOCK_CONTROL_1:
+ case WM831X_CLOCK_CONTROL_2:
+ case WM831X_FLL_CONTROL_1:
+ case WM831X_FLL_CONTROL_2:
+ case WM831X_FLL_CONTROL_3:
+ case WM831X_FLL_CONTROL_4:
+ case WM831X_FLL_CONTROL_5:
+ case WM831X_UNIQUE_ID_1:
+ case WM831X_UNIQUE_ID_2:
+ case WM831X_UNIQUE_ID_3:
+ case WM831X_UNIQUE_ID_4:
+ case WM831X_UNIQUE_ID_5:
+ case WM831X_UNIQUE_ID_6:
+ case WM831X_UNIQUE_ID_7:
+ case WM831X_UNIQUE_ID_8:
+ case WM831X_FACTORY_OTP_ID:
+ case WM831X_FACTORY_OTP_1:
+ case WM831X_FACTORY_OTP_2:
+ case WM831X_FACTORY_OTP_3:
+ case WM831X_FACTORY_OTP_4:
+ case WM831X_FACTORY_OTP_5:
+ case WM831X_CUSTOMER_OTP_ID:
+ case WM831X_DC1_OTP_CONTROL:
+ case WM831X_DC2_OTP_CONTROL:
+ case WM831X_DC3_OTP_CONTROL:
+ case WM831X_LDO1_2_OTP_CONTROL:
+ case WM831X_LDO3_4_OTP_CONTROL:
+ case WM831X_LDO5_6_OTP_CONTROL:
+ case WM831X_LDO7_8_OTP_CONTROL:
+ case WM831X_LDO9_10_OTP_CONTROL:
+ case WM831X_LDO11_EPE_CONTROL:
+ case WM831X_GPIO1_OTP_CONTROL:
+ case WM831X_GPIO2_OTP_CONTROL:
+ case WM831X_GPIO3_OTP_CONTROL:
+ case WM831X_GPIO4_OTP_CONTROL:
+ case WM831X_GPIO5_OTP_CONTROL:
+ case WM831X_GPIO6_OTP_CONTROL:
+ case WM831X_DBE_CHECK_DATA:
+ return true;
+ default:
+ return false;
+ }
+}
- ret = wm831x->read_dev(wm831x, reg, bytes, dest);
- if (ret < 0)
- return ret;
+static bool wm831x_reg_writeable(struct device *dev, unsigned int reg)
+{
+ struct wm831x *wm831x = dev_get_drvdata(dev);
- for (i = 0; i < bytes / 2; i++) {
- buf[i] = be16_to_cpu(buf[i]);
+ if (wm831x_reg_locked(wm831x, reg))
+ return false;
- dev_vdbg(wm831x->dev, "Read %04x from R%d(0x%x)\n",
- buf[i], reg + i, reg + i);
+ switch (reg) {
+ case WM831X_SYSVDD_CONTROL:
+ case WM831X_THERMAL_MONITORING:
+ case WM831X_POWER_STATE:
+ case WM831X_WATCHDOG:
+ case WM831X_ON_PIN_CONTROL:
+ case WM831X_RESET_CONTROL:
+ case WM831X_CONTROL_INTERFACE:
+ case WM831X_SECURITY_KEY:
+ case WM831X_SOFTWARE_SCRATCH:
+ case WM831X_OTP_CONTROL:
+ case WM831X_GPIO_LEVEL:
+ case WM831X_INTERRUPT_STATUS_1:
+ case WM831X_INTERRUPT_STATUS_2:
+ case WM831X_INTERRUPT_STATUS_3:
+ case WM831X_INTERRUPT_STATUS_4:
+ case WM831X_INTERRUPT_STATUS_5:
+ case WM831X_IRQ_CONFIG:
+ case WM831X_SYSTEM_INTERRUPTS_MASK:
+ case WM831X_INTERRUPT_STATUS_1_MASK:
+ case WM831X_INTERRUPT_STATUS_2_MASK:
+ case WM831X_INTERRUPT_STATUS_3_MASK:
+ case WM831X_INTERRUPT_STATUS_4_MASK:
+ case WM831X_INTERRUPT_STATUS_5_MASK:
+ case WM831X_RTC_TIME_1:
+ case WM831X_RTC_TIME_2:
+ case WM831X_RTC_ALARM_1:
+ case WM831X_RTC_ALARM_2:
+ case WM831X_RTC_CONTROL:
+ case WM831X_RTC_TRIM:
+ case WM831X_TOUCH_CONTROL_1:
+ case WM831X_TOUCH_CONTROL_2:
+ case WM831X_AUXADC_CONTROL:
+ case WM831X_AUXADC_SOURCE:
+ case WM831X_COMPARATOR_CONTROL:
+ case WM831X_COMPARATOR_1:
+ case WM831X_COMPARATOR_2:
+ case WM831X_COMPARATOR_3:
+ case WM831X_COMPARATOR_4:
+ case WM831X_GPIO1_CONTROL:
+ case WM831X_GPIO2_CONTROL:
+ case WM831X_GPIO3_CONTROL:
+ case WM831X_GPIO4_CONTROL:
+ case WM831X_GPIO5_CONTROL:
+ case WM831X_GPIO6_CONTROL:
+ case WM831X_GPIO7_CONTROL:
+ case WM831X_GPIO8_CONTROL:
+ case WM831X_GPIO9_CONTROL:
+ case WM831X_GPIO10_CONTROL:
+ case WM831X_GPIO11_CONTROL:
+ case WM831X_GPIO12_CONTROL:
+ case WM831X_GPIO13_CONTROL:
+ case WM831X_GPIO14_CONTROL:
+ case WM831X_GPIO15_CONTROL:
+ case WM831X_GPIO16_CONTROL:
+ case WM831X_CHARGER_CONTROL_1:
+ case WM831X_CHARGER_CONTROL_2:
+ case WM831X_CHARGER_STATUS:
+ case WM831X_BACKUP_CHARGER_CONTROL:
+ case WM831X_STATUS_LED_1:
+ case WM831X_STATUS_LED_2:
+ case WM831X_CURRENT_SINK_1:
+ case WM831X_CURRENT_SINK_2:
+ case WM831X_DCDC_ENABLE:
+ case WM831X_LDO_ENABLE:
+ case WM831X_DC1_CONTROL_1:
+ case WM831X_DC1_CONTROL_2:
+ case WM831X_DC1_ON_CONFIG:
+ case WM831X_DC1_SLEEP_CONTROL:
+ case WM831X_DC1_DVS_CONTROL:
+ case WM831X_DC2_CONTROL_1:
+ case WM831X_DC2_CONTROL_2:
+ case WM831X_DC2_ON_CONFIG:
+ case WM831X_DC2_SLEEP_CONTROL:
+ case WM831X_DC2_DVS_CONTROL:
+ case WM831X_DC3_CONTROL_1:
+ case WM831X_DC3_CONTROL_2:
+ case WM831X_DC3_ON_CONFIG:
+ case WM831X_DC3_SLEEP_CONTROL:
+ case WM831X_DC4_CONTROL:
+ case WM831X_DC4_SLEEP_CONTROL:
+ case WM831X_EPE1_CONTROL:
+ case WM831X_EPE2_CONTROL:
+ case WM831X_LDO1_CONTROL:
+ case WM831X_LDO1_ON_CONTROL:
+ case WM831X_LDO1_SLEEP_CONTROL:
+ case WM831X_LDO2_CONTROL:
+ case WM831X_LDO2_ON_CONTROL:
+ case WM831X_LDO2_SLEEP_CONTROL:
+ case WM831X_LDO3_CONTROL:
+ case WM831X_LDO3_ON_CONTROL:
+ case WM831X_LDO3_SLEEP_CONTROL:
+ case WM831X_LDO4_CONTROL:
+ case WM831X_LDO4_ON_CONTROL:
+ case WM831X_LDO4_SLEEP_CONTROL:
+ case WM831X_LDO5_CONTROL:
+ case WM831X_LDO5_ON_CONTROL:
+ case WM831X_LDO5_SLEEP_CONTROL:
+ case WM831X_LDO6_CONTROL:
+ case WM831X_LDO6_ON_CONTROL:
+ case WM831X_LDO6_SLEEP_CONTROL:
+ case WM831X_LDO7_CONTROL:
+ case WM831X_LDO7_ON_CONTROL:
+ case WM831X_LDO7_SLEEP_CONTROL:
+ case WM831X_LDO8_CONTROL:
+ case WM831X_LDO8_ON_CONTROL:
+ case WM831X_LDO8_SLEEP_CONTROL:
+ case WM831X_LDO9_CONTROL:
+ case WM831X_LDO9_ON_CONTROL:
+ case WM831X_LDO9_SLEEP_CONTROL:
+ case WM831X_LDO10_CONTROL:
+ case WM831X_LDO10_ON_CONTROL:
+ case WM831X_LDO10_SLEEP_CONTROL:
+ case WM831X_LDO11_ON_CONTROL:
+ case WM831X_LDO11_SLEEP_CONTROL:
+ case WM831X_POWER_GOOD_SOURCE_1:
+ case WM831X_POWER_GOOD_SOURCE_2:
+ case WM831X_CLOCK_CONTROL_1:
+ case WM831X_CLOCK_CONTROL_2:
+ case WM831X_FLL_CONTROL_1:
+ case WM831X_FLL_CONTROL_2:
+ case WM831X_FLL_CONTROL_3:
+ case WM831X_FLL_CONTROL_4:
+ case WM831X_FLL_CONTROL_5:
+ return true;
+ default:
+ return false;
}
+}
- return 0;
+static bool wm831x_reg_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WM831X_SYSTEM_STATUS:
+ case WM831X_ON_SOURCE:
+ case WM831X_OFF_SOURCE:
+ case WM831X_GPIO_LEVEL:
+ case WM831X_SYSTEM_INTERRUPTS:
+ case WM831X_INTERRUPT_STATUS_1:
+ case WM831X_INTERRUPT_STATUS_2:
+ case WM831X_INTERRUPT_STATUS_3:
+ case WM831X_INTERRUPT_STATUS_4:
+ case WM831X_INTERRUPT_STATUS_5:
+ case WM831X_RTC_TIME_1:
+ case WM831X_RTC_TIME_2:
+ case WM831X_TOUCH_DATA_X:
+ case WM831X_TOUCH_DATA_Y:
+ case WM831X_TOUCH_DATA_Z:
+ case WM831X_AUXADC_DATA:
+ case WM831X_CHARGER_STATUS:
+ case WM831X_DCDC_STATUS:
+ case WM831X_LDO_STATUS:
+ case WM831X_DCDC_UV_STATUS:
+ case WM831X_LDO_UV_STATUS:
+ return true;
+ default:
+ return false;
+ }
}
/**
@@ -191,14 +516,10 @@ static int wm831x_read(struct wm831x *wm831x, unsigned short reg,
*/
int wm831x_reg_read(struct wm831x *wm831x, unsigned short reg)
{
- unsigned short val;
+ unsigned int val;
int ret;
- mutex_lock(&wm831x->io_lock);
-
- ret = wm831x_read(wm831x, reg, 2, &val);
-
- mutex_unlock(&wm831x->io_lock);
+ ret = regmap_read(wm831x->regmap, reg, &val);
if (ret < 0)
return ret;
@@ -218,15 +539,7 @@ EXPORT_SYMBOL_GPL(wm831x_reg_read);
int wm831x_bulk_read(struct wm831x *wm831x, unsigned short reg,
int count, u16 *buf)
{
- int ret;
-
- mutex_lock(&wm831x->io_lock);
-
- ret = wm831x_read(wm831x, reg, count * 2, buf);
-
- mutex_unlock(&wm831x->io_lock);
-
- return ret;
+ return regmap_bulk_read(wm831x->regmap, reg, buf, count);
}
EXPORT_SYMBOL_GPL(wm831x_bulk_read);
@@ -234,7 +547,7 @@ static int wm831x_write(struct wm831x *wm831x, unsigned short reg,
int bytes, void *src)
{
u16 *buf = src;
- int i;
+ int i, ret;
BUG_ON(bytes % 2);
BUG_ON(bytes <= 0);
@@ -245,11 +558,10 @@ static int wm831x_write(struct wm831x *wm831x, unsigned short reg,
dev_vdbg(wm831x->dev, "Write %04x to R%d(0x%x)\n",
buf[i], reg + i, reg + i);
-
- buf[i] = cpu_to_be16(buf[i]);
+ ret = regmap_write(wm831x->regmap, reg + i, buf[i]);
}
- return wm831x->write_dev(wm831x, reg, bytes, src);
+ return 0;
}
/**
@@ -286,20 +598,14 @@ int wm831x_set_bits(struct wm831x *wm831x, unsigned short reg,
unsigned short mask, unsigned short val)
{
int ret;
- u16 r;
mutex_lock(&wm831x->io_lock);
- ret = wm831x_read(wm831x, reg, 2, &r);
- if (ret < 0)
- goto out;
-
- r &= ~mask;
- r |= val & mask;
-
- ret = wm831x_write(wm831x, reg, 2, &r);
+ if (!wm831x_reg_locked(wm831x, reg))
+ ret = regmap_update_bits(wm831x->regmap, reg, mask, val);
+ else
+ ret = -EPERM;
-out:
mutex_unlock(&wm831x->io_lock);
return ret;
@@ -1292,6 +1598,19 @@ static struct mfd_cell backlight_devs[] = {
},
};
+struct regmap_config wm831x_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 16,
+
+ .cache_type = REGCACHE_RBTREE,
+
+ .max_register = WM831X_DBE_CHECK_DATA,
+ .readable_reg = wm831x_reg_readable,
+ .writeable_reg = wm831x_reg_writeable,
+ .volatile_reg = wm831x_reg_volatile,
+};
+EXPORT_SYMBOL_GPL(wm831x_regmap_config);
+
/*
* Instantiate the generic non-control parts of the device.
*/
@@ -1305,11 +1624,12 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
mutex_init(&wm831x->io_lock);
mutex_init(&wm831x->key_lock);
dev_set_drvdata(wm831x->dev, wm831x);
+ wm831x->soft_shutdown = pdata->soft_shutdown;
ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID);
if (ret < 0) {
dev_err(wm831x->dev, "Failed to read parent ID: %d\n", ret);
- goto err;
+ goto err_regmap;
}
switch (ret) {
case 0x6204:
@@ -1318,20 +1638,20 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
default:
dev_err(wm831x->dev, "Device is not a WM831x: ID %x\n", ret);
ret = -EINVAL;
- goto err;
+ goto err_regmap;
}
ret = wm831x_reg_read(wm831x, WM831X_REVISION);
if (ret < 0) {
dev_err(wm831x->dev, "Failed to read revision: %d\n", ret);
- goto err;
+ goto err_regmap;
}
rev = (ret & WM831X_PARENT_REV_MASK) >> WM831X_PARENT_REV_SHIFT;
ret = wm831x_reg_read(wm831x, WM831X_RESET_ID);
if (ret < 0) {
dev_err(wm831x->dev, "Failed to read device ID: %d\n", ret);
- goto err;
+ goto err_regmap;
}
/* Some engineering samples do not have the ID set, rely on
@@ -1406,7 +1726,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
default:
dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret);
ret = -EINVAL;
- goto err;
+ goto err_regmap;
}
/* This will need revisiting in future but is OK for all
@@ -1420,7 +1740,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
ret = wm831x_reg_read(wm831x, WM831X_SECURITY_KEY);
if (ret < 0) {
dev_err(wm831x->dev, "Failed to read security key: %d\n", ret);
- goto err;
+ goto err_regmap;
}
if (ret != 0) {
dev_warn(wm831x->dev, "Security key had non-zero value %x\n",
@@ -1433,7 +1753,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
ret = pdata->pre_init(wm831x);
if (ret != 0) {
dev_err(wm831x->dev, "pre_init() failed: %d\n", ret);
- goto err;
+ goto err_regmap;
}
}
@@ -1456,7 +1776,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
ret = wm831x_irq_init(wm831x, irq);
if (ret != 0)
- goto err;
+ goto err_regmap;
wm831x_auxadc_init(wm831x);
@@ -1552,8 +1872,9 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
err_irq:
wm831x_irq_exit(wm831x);
-err:
+err_regmap:
mfd_remove_devices(wm831x->dev);
+ regmap_exit(wm831x->regmap);
kfree(wm831x);
return ret;
}
@@ -1565,6 +1886,7 @@ void wm831x_device_exit(struct wm831x *wm831x)
if (wm831x->irq_base)
free_irq(wm831x->irq_base + WM831X_IRQ_AUXADC_DATA, wm831x);
wm831x_irq_exit(wm831x);
+ regmap_exit(wm831x->regmap);
kfree(wm831x);
}
@@ -1604,6 +1926,15 @@ int wm831x_device_suspend(struct wm831x *wm831x)
return 0;
}
+void wm831x_device_shutdown(struct wm831x *wm831x)
+{
+ if (wm831x->soft_shutdown) {
+ dev_info(wm831x->dev, "Initiating shutdown...\n");
+ wm831x_set_bits(wm831x, WM831X_POWER_STATE, WM831X_CHIP_ON, 0);
+ }
+}
+EXPORT_SYMBOL_GPL(wm831x_device_shutdown);
+
MODULE_DESCRIPTION("Core support for the WM831X AudioPlus PMIC");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mark Brown");
diff --git a/drivers/mfd/wm831x-i2c.c b/drivers/mfd/wm831x-i2c.c
index a06cbc739716..ac8da1d439da 100644
--- a/drivers/mfd/wm831x-i2c.c
+++ b/drivers/mfd/wm831x-i2c.c
@@ -18,67 +18,17 @@
#include <linux/delay.h>
#include <linux/mfd/core.h>
#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/regmap.h>
#include <linux/mfd/wm831x/core.h>
#include <linux/mfd/wm831x/pdata.h>
-static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg,
- int bytes, void *dest)
-{
- struct i2c_client *i2c = wm831x->control_data;
- int ret;
- u16 r = cpu_to_be16(reg);
-
- ret = i2c_master_send(i2c, (unsigned char *)&r, 2);
- if (ret < 0)
- return ret;
- if (ret != 2)
- return -EIO;
-
- ret = i2c_master_recv(i2c, dest, bytes);
- if (ret < 0)
- return ret;
- if (ret != bytes)
- return -EIO;
- return 0;
-}
-
-/* Currently we allocate the write buffer on the stack; this is OK for
- * small writes - if we need to do large writes this will need to be
- * revised.
- */
-static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg,
- int bytes, void *src)
-{
- struct i2c_client *i2c = wm831x->control_data;
- struct i2c_msg xfer[2];
- int ret;
-
- reg = cpu_to_be16(reg);
-
- xfer[0].addr = i2c->addr;
- xfer[0].flags = 0;
- xfer[0].len = 2;
- xfer[0].buf = (char *)&reg;
-
- xfer[1].addr = i2c->addr;
- xfer[1].flags = I2C_M_NOSTART;
- xfer[1].len = bytes;
- xfer[1].buf = (char *)src;
-
- ret = i2c_transfer(i2c->adapter, xfer, 2);
- if (ret < 0)
- return ret;
- if (ret != 2)
- return -EIO;
-
- return 0;
-}
-
static int wm831x_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm831x *wm831x;
+ int ret;
wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
if (wm831x == NULL)
@@ -86,9 +36,15 @@ static int wm831x_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, wm831x);
wm831x->dev = &i2c->dev;
- wm831x->control_data = i2c;
- wm831x->read_dev = wm831x_i2c_read_device;
- wm831x->write_dev = wm831x_i2c_write_device;
+
+ wm831x->regmap = regmap_init_i2c(i2c, &wm831x_regmap_config);
+ if (IS_ERR(wm831x->regmap)) {
+ ret = PTR_ERR(wm831x->regmap);
+ dev_err(wm831x->dev, "Failed to allocate register map: %d\n",
+ ret);
+ kfree(wm831x);
+ return ret;
+ }
return wm831x_device_init(wm831x, id->driver_data, i2c->irq);
}
@@ -109,6 +65,13 @@ static int wm831x_i2c_suspend(struct device *dev)
return wm831x_device_suspend(wm831x);
}
+static void wm831x_i2c_shutdown(struct i2c_client *i2c)
+{
+ struct wm831x *wm831x = i2c_get_clientdata(i2c);
+
+ wm831x_device_shutdown(wm831x);
+}
+
static const struct i2c_device_id wm831x_i2c_id[] = {
{ "wm8310", WM8310 },
{ "wm8311", WM8311 },
@@ -133,6 +96,7 @@ static struct i2c_driver wm831x_i2c_driver = {
},
.probe = wm831x_i2c_probe,
.remove = wm831x_i2c_remove,
+ .shutdown = wm831x_i2c_shutdown,
.id_table = wm831x_i2c_id,
};
diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c
index eed8e4f7a5a1..8d6a9a969dbc 100644
--- a/drivers/mfd/wm831x-spi.c
+++ b/drivers/mfd/wm831x-spi.c
@@ -16,78 +16,19 @@
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
#include <linux/mfd/wm831x/core.h>
-static int wm831x_spi_read_device(struct wm831x *wm831x, unsigned short reg,
- int bytes, void *dest)
-{
- u16 tx_val;
- u16 *d = dest;
- int r, ret;
-
- /* Go register at a time */
- for (r = reg; r < reg + (bytes / 2); r++) {
- tx_val = r | 0x8000;
-
- ret = spi_write_then_read(wm831x->control_data,
- (u8 *)&tx_val, 2, (u8 *)d, 2);
- if (ret != 0)
- return ret;
-
- *d = be16_to_cpu(*d);
-
- d++;
- }
-
- return 0;
-}
-
-static int wm831x_spi_write_device(struct wm831x *wm831x, unsigned short reg,
- int bytes, void *src)
-{
- struct spi_device *spi = wm831x->control_data;
- u16 *s = src;
- u16 data[2];
- int ret, r;
-
- /* Go register at a time */
- for (r = reg; r < reg + (bytes / 2); r++) {
- data[0] = r;
- data[1] = *s++;
-
- ret = spi_write(spi, (char *)&data, sizeof(data));
- if (ret != 0)
- return ret;
- }
-
- return 0;
-}
-
static int __devinit wm831x_spi_probe(struct spi_device *spi)
{
+ const struct spi_device_id *id = spi_get_device_id(spi);
struct wm831x *wm831x;
enum wm831x_parent type;
+ int ret;
- /* Currently SPI support for ID tables is unmerged, we're faking it */
- if (strcmp(spi->modalias, "wm8310") == 0)
- type = WM8310;
- else if (strcmp(spi->modalias, "wm8311") == 0)
- type = WM8311;
- else if (strcmp(spi->modalias, "wm8312") == 0)
- type = WM8312;
- else if (strcmp(spi->modalias, "wm8320") == 0)
- type = WM8320;
- else if (strcmp(spi->modalias, "wm8321") == 0)
- type = WM8321;
- else if (strcmp(spi->modalias, "wm8325") == 0)
- type = WM8325;
- else if (strcmp(spi->modalias, "wm8326") == 0)
- type = WM8326;
- else {
- dev_err(&spi->dev, "Unknown device type\n");
- return -EINVAL;
- }
+ type = (enum wm831x_parent)id->driver_data;
wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
if (wm831x == NULL)
@@ -98,9 +39,15 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi)
dev_set_drvdata(&spi->dev, wm831x);
wm831x->dev = &spi->dev;
- wm831x->control_data = spi;
- wm831x->read_dev = wm831x_spi_read_device;
- wm831x->write_dev = wm831x_spi_write_device;
+
+ wm831x->regmap = regmap_init_spi(spi, &wm831x_regmap_config);
+ if (IS_ERR(wm831x->regmap)) {
+ ret = PTR_ERR(wm831x->regmap);
+ dev_err(wm831x->dev, "Failed to allocate register map: %d\n",
+ ret);
+ kfree(wm831x);
+ return ret;
+ }
return wm831x_device_init(wm831x, type, spi->irq);
}
@@ -121,119 +68,50 @@ static int wm831x_spi_suspend(struct device *dev)
return wm831x_device_suspend(wm831x);
}
+static void wm831x_spi_shutdown(struct spi_device *spi)
+{
+ struct wm831x *wm831x = dev_get_drvdata(&spi->dev);
+
+ wm831x_device_shutdown(wm831x);
+}
+
static const struct dev_pm_ops wm831x_spi_pm = {
.freeze = wm831x_spi_suspend,
.suspend = wm831x_spi_suspend,
};
-static struct spi_driver wm8310_spi_driver = {
- .driver = {
- .name = "wm8310",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- .pm = &wm831x_spi_pm,
- },
- .probe = wm831x_spi_probe,
- .remove = __devexit_p(wm831x_spi_remove),
+static const struct spi_device_id wm831x_spi_ids[] = {
+ { "wm8310", WM8310 },
+ { "wm8311", WM8311 },
+ { "wm8312", WM8312 },
+ { "wm8320", WM8320 },
+ { "wm8321", WM8321 },
+ { "wm8325", WM8325 },
+ { "wm8326", WM8326 },
+ { },
};
+MODULE_DEVICE_TABLE(spi, wm831x_spi_id);
-static struct spi_driver wm8311_spi_driver = {
+static struct spi_driver wm831x_spi_driver = {
.driver = {
- .name = "wm8311",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- .pm = &wm831x_spi_pm,
- },
- .probe = wm831x_spi_probe,
- .remove = __devexit_p(wm831x_spi_remove),
-};
-
-static struct spi_driver wm8312_spi_driver = {
- .driver = {
- .name = "wm8312",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- .pm = &wm831x_spi_pm,
- },
- .probe = wm831x_spi_probe,
- .remove = __devexit_p(wm831x_spi_remove),
-};
-
-static struct spi_driver wm8320_spi_driver = {
- .driver = {
- .name = "wm8320",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- .pm = &wm831x_spi_pm,
- },
- .probe = wm831x_spi_probe,
- .remove = __devexit_p(wm831x_spi_remove),
-};
-
-static struct spi_driver wm8321_spi_driver = {
- .driver = {
- .name = "wm8321",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- .pm = &wm831x_spi_pm,
- },
- .probe = wm831x_spi_probe,
- .remove = __devexit_p(wm831x_spi_remove),
-};
-
-static struct spi_driver wm8325_spi_driver = {
- .driver = {
- .name = "wm8325",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- .pm = &wm831x_spi_pm,
- },
- .probe = wm831x_spi_probe,
- .remove = __devexit_p(wm831x_spi_remove),
-};
-
-static struct spi_driver wm8326_spi_driver = {
- .driver = {
- .name = "wm8326",
+ .name = "wm831x",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
.pm = &wm831x_spi_pm,
},
+ .id_table = wm831x_spi_ids,
.probe = wm831x_spi_probe,
.remove = __devexit_p(wm831x_spi_remove),
+ .shutdown = wm831x_spi_shutdown,
};
static int __init wm831x_spi_init(void)
{
int ret;
- ret = spi_register_driver(&wm8310_spi_driver);
- if (ret != 0)
- pr_err("Failed to register WM8310 SPI driver: %d\n", ret);
-
- ret = spi_register_driver(&wm8311_spi_driver);
- if (ret != 0)
- pr_err("Failed to register WM8311 SPI driver: %d\n", ret);
-
- ret = spi_register_driver(&wm8312_spi_driver);
- if (ret != 0)
- pr_err("Failed to register WM8312 SPI driver: %d\n", ret);
-
- ret = spi_register_driver(&wm8320_spi_driver);
- if (ret != 0)
- pr_err("Failed to register WM8320 SPI driver: %d\n", ret);
-
- ret = spi_register_driver(&wm8321_spi_driver);
- if (ret != 0)
- pr_err("Failed to register WM8321 SPI driver: %d\n", ret);
-
- ret = spi_register_driver(&wm8325_spi_driver);
- if (ret != 0)
- pr_err("Failed to register WM8325 SPI driver: %d\n", ret);
-
- ret = spi_register_driver(&wm8326_spi_driver);
+ ret = spi_register_driver(&wm831x_spi_driver);
if (ret != 0)
- pr_err("Failed to register WM8326 SPI driver: %d\n", ret);
+ pr_err("Failed to register WM831x SPI driver: %d\n", ret);
return 0;
}
@@ -241,13 +119,7 @@ subsys_initcall(wm831x_spi_init);
static void __exit wm831x_spi_exit(void)
{
- spi_unregister_driver(&wm8326_spi_driver);
- spi_unregister_driver(&wm8325_spi_driver);
- spi_unregister_driver(&wm8321_spi_driver);
- spi_unregister_driver(&wm8320_spi_driver);
- spi_unregister_driver(&wm8312_spi_driver);
- spi_unregister_driver(&wm8311_spi_driver);
- spi_unregister_driver(&wm8310_spi_driver);
+ spi_unregister_driver(&wm831x_spi_driver);
}
module_exit(wm831x_spi_exit);
diff --git a/drivers/mfd/wm8350-gpio.c b/drivers/mfd/wm8350-gpio.c
index ebf99bef392f..d584f6b4d6e2 100644
--- a/drivers/mfd/wm8350-gpio.c
+++ b/drivers/mfd/wm8350-gpio.c
@@ -37,7 +37,7 @@ static int gpio_set_dir(struct wm8350 *wm8350, int gpio, int dir)
return ret;
}
-static int gpio_set_debounce(struct wm8350 *wm8350, int gpio, int db)
+static int wm8350_gpio_set_debounce(struct wm8350 *wm8350, int gpio, int db)
{
if (db == WM8350_GPIO_DEBOUNCE_ON)
return wm8350_set_bits(wm8350, WM8350_GPIO_DEBOUNCE,
@@ -210,7 +210,7 @@ int wm8350_gpio_config(struct wm8350 *wm8350, int gpio, int dir, int func,
goto err;
if (gpio_set_polarity(wm8350, gpio, pol))
goto err;
- if (gpio_set_debounce(wm8350, gpio, debounce))
+ if (wm8350_gpio_set_debounce(wm8350, gpio, debounce))
goto err;
if (gpio_set_dir(wm8350, gpio, dir))
goto err;
diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c
index 597f82edacaa..e06ba9440cdb 100644
--- a/drivers/mfd/wm8400-core.c
+++ b/drivers/mfd/wm8400-core.c
@@ -13,11 +13,13 @@
*/
#include <linux/bug.h>
+#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/mfd/core.h>
#include <linux/mfd/wm8400-private.h>
#include <linux/mfd/wm8400-audio.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
static struct {
@@ -123,14 +125,9 @@ static int wm8400_read(struct wm8400 *wm8400, u8 reg, int num_regs, u16 *dest)
/* If there are any volatile reads then read back the entire block */
for (i = reg; i < reg + num_regs; i++)
if (reg_data[i].vol) {
- ret = wm8400->read_dev(wm8400->io_data, reg,
- num_regs, dest);
- if (ret != 0)
- return ret;
- for (i = 0; i < num_regs; i++)
- dest[i] = be16_to_cpu(dest[i]);
-
- return 0;
+ ret = regmap_bulk_read(wm8400->regmap, reg, dest,
+ num_regs);
+ return ret;
}
/* Otherwise use the cache */
@@ -149,14 +146,11 @@ static int wm8400_write(struct wm8400 *wm8400, u8 reg, int num_regs,
for (i = 0; i < num_regs; i++) {
BUG_ON(!reg_data[reg + i].writable);
wm8400->reg_cache[reg + i] = src[i];
- src[i] = cpu_to_be16(src[i]);
+ ret = regmap_write(wm8400->regmap, reg, src[i]);
+ if (ret != 0)
+ return ret;
}
- /* Do the actual I/O */
- ret = wm8400->write_dev(wm8400->io_data, reg, num_regs, src);
- if (ret != 0)
- return -EIO;
-
return 0;
}
@@ -270,14 +264,14 @@ static int wm8400_init(struct wm8400 *wm8400,
dev_set_drvdata(wm8400->dev, wm8400);
/* Check that this is actually a WM8400 */
- ret = wm8400->read_dev(wm8400->io_data, WM8400_RESET_ID, 1, &reg);
+ ret = regmap_read(wm8400->regmap, WM8400_RESET_ID, &i);
if (ret != 0) {
dev_err(wm8400->dev, "Chip ID register read failed\n");
return -EIO;
}
- if (be16_to_cpu(reg) != reg_data[WM8400_RESET_ID].default_val) {
+ if (i != reg_data[WM8400_RESET_ID].default_val) {
dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n",
- be16_to_cpu(reg));
+ reg);
return -ENODEV;
}
@@ -285,9 +279,8 @@ static int wm8400_init(struct wm8400 *wm8400,
* is a PMIC we can't reset it safely so initialise the register
* cache from the hardware.
*/
- ret = wm8400->read_dev(wm8400->io_data, 0,
- ARRAY_SIZE(wm8400->reg_cache),
- wm8400->reg_cache);
+ ret = regmap_raw_read(wm8400->regmap, 0, wm8400->reg_cache,
+ ARRAY_SIZE(wm8400->reg_cache));
if (ret != 0) {
dev_err(wm8400->dev, "Register cache read failed\n");
return -EIO;
@@ -337,60 +330,13 @@ static void wm8400_release(struct wm8400 *wm8400)
mfd_remove_devices(wm8400->dev);
}
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-static int wm8400_i2c_read(void *io_data, char reg, int count, u16 *dest)
-{
- struct i2c_client *i2c = io_data;
- struct i2c_msg xfer[2];
- int ret;
-
- /* Write register */
- xfer[0].addr = i2c->addr;
- xfer[0].flags = 0;
- xfer[0].len = 1;
- xfer[0].buf = &reg;
-
- /* Read data */
- xfer[1].addr = i2c->addr;
- xfer[1].flags = I2C_M_RD;
- xfer[1].len = count * sizeof(u16);
- xfer[1].buf = (u8 *)dest;
-
- ret = i2c_transfer(i2c->adapter, xfer, 2);
- if (ret == 2)
- ret = 0;
- else if (ret >= 0)
- ret = -EIO;
-
- return ret;
-}
-
-static int wm8400_i2c_write(void *io_data, char reg, int count, const u16 *src)
-{
- struct i2c_client *i2c = io_data;
- u8 *msg;
- int ret;
-
- /* We add 1 byte for device register - ideally I2C would gather. */
- msg = kmalloc((count * sizeof(u16)) + 1, GFP_KERNEL);
- if (msg == NULL)
- return -ENOMEM;
-
- msg[0] = reg;
- memcpy(&msg[1], src, count * sizeof(u16));
-
- ret = i2c_master_send(i2c, msg, (count * sizeof(u16)) + 1);
-
- if (ret == (count * 2) + 1)
- ret = 0;
- else if (ret >= 0)
- ret = -EIO;
-
- kfree(msg);
-
- return ret;
-}
+static const struct regmap_config wm8400_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .max_register = WM8400_REGISTER_COUNT - 1,
+};
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static int wm8400_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -403,18 +349,23 @@ static int wm8400_i2c_probe(struct i2c_client *i2c,
goto err;
}
- wm8400->io_data = i2c;
- wm8400->read_dev = wm8400_i2c_read;
- wm8400->write_dev = wm8400_i2c_write;
+ wm8400->regmap = regmap_init_i2c(i2c, &wm8400_regmap_config);
+ if (IS_ERR(wm8400->regmap)) {
+ ret = PTR_ERR(wm8400->regmap);
+ goto struct_err;
+ }
+
wm8400->dev = &i2c->dev;
i2c_set_clientdata(i2c, wm8400);
ret = wm8400_init(wm8400, i2c->dev.platform_data);
if (ret != 0)
- goto struct_err;
+ goto map_err;
return 0;
+map_err:
+ regmap_exit(wm8400->regmap);
struct_err:
kfree(wm8400);
err:
@@ -426,6 +377,7 @@ static int wm8400_i2c_remove(struct i2c_client *i2c)
struct wm8400 *wm8400 = i2c_get_clientdata(i2c);
wm8400_release(wm8400);
+ regmap_exit(wm8400->regmap);
kfree(wm8400);
return 0;
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index 96479c9b1728..bfde4e8ec638 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -16,9 +16,11 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
+#include <linux/err.h>
#include <linux/delay.h>
#include <linux/mfd/core.h>
#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/machine.h>
@@ -29,22 +31,7 @@
static int wm8994_read(struct wm8994 *wm8994, unsigned short reg,
int bytes, void *dest)
{
- int ret, i;
- u16 *buf = dest;
-
- BUG_ON(bytes % 2);
- BUG_ON(bytes <= 0);
-
- ret = wm8994->read_dev(wm8994, reg, bytes, dest);
- if (ret < 0)
- return ret;
-
- for (i = 0; i < bytes / 2; i++) {
- dev_vdbg(wm8994->dev, "Read %04x from R%d(0x%x)\n",
- be16_to_cpu(buf[i]), reg + i, reg + i);
- }
-
- return 0;
+ return regmap_raw_read(wm8994->regmap, reg, dest, bytes);
}
/**
@@ -55,19 +42,15 @@ static int wm8994_read(struct wm8994 *wm8994, unsigned short reg,
*/
int wm8994_reg_read(struct wm8994 *wm8994, unsigned short reg)
{
- unsigned short val;
+ unsigned int val;
int ret;
- mutex_lock(&wm8994->io_lock);
-
- ret = wm8994_read(wm8994, reg, 2, &val);
-
- mutex_unlock(&wm8994->io_lock);
+ ret = regmap_read(wm8994->regmap, reg, &val);
if (ret < 0)
return ret;
else
- return be16_to_cpu(val);
+ return val;
}
EXPORT_SYMBOL_GPL(wm8994_reg_read);
@@ -82,33 +65,13 @@ EXPORT_SYMBOL_GPL(wm8994_reg_read);
int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg,
int count, u16 *buf)
{
- int ret;
-
- mutex_lock(&wm8994->io_lock);
-
- ret = wm8994_read(wm8994, reg, count * 2, buf);
-
- mutex_unlock(&wm8994->io_lock);
-
- return ret;
+ return regmap_bulk_read(wm8994->regmap, reg, buf, count);
}
-EXPORT_SYMBOL_GPL(wm8994_bulk_read);
static int wm8994_write(struct wm8994 *wm8994, unsigned short reg,
int bytes, const void *src)
{
- const u16 *buf = src;
- int i;
-
- BUG_ON(bytes % 2);
- BUG_ON(bytes <= 0);
-
- for (i = 0; i < bytes / 2; i++) {
- dev_vdbg(wm8994->dev, "Write %04x to R%d(0x%x)\n",
- be16_to_cpu(buf[i]), reg + i, reg + i);
- }
-
- return wm8994->write_dev(wm8994, reg, bytes, src);
+ return regmap_raw_write(wm8994->regmap, reg, src, bytes);
}
/**
@@ -121,17 +84,7 @@ static int wm8994_write(struct wm8994 *wm8994, unsigned short reg,
int wm8994_reg_write(struct wm8994 *wm8994, unsigned short reg,
unsigned short val)
{
- int ret;
-
- val = cpu_to_be16(val);
-
- mutex_lock(&wm8994->io_lock);
-
- ret = wm8994_write(wm8994, reg, 2, &val);
-
- mutex_unlock(&wm8994->io_lock);
-
- return ret;
+ return regmap_write(wm8994->regmap, reg, val);
}
EXPORT_SYMBOL_GPL(wm8994_reg_write);
@@ -146,15 +99,7 @@ EXPORT_SYMBOL_GPL(wm8994_reg_write);
int wm8994_bulk_write(struct wm8994 *wm8994, unsigned short reg,
int count, const u16 *buf)
{
- int ret;
-
- mutex_lock(&wm8994->io_lock);
-
- ret = wm8994_write(wm8994, reg, count * 2, buf);
-
- mutex_unlock(&wm8994->io_lock);
-
- return ret;
+ return regmap_raw_write(wm8994->regmap, reg, buf, count * sizeof(u16));
}
EXPORT_SYMBOL_GPL(wm8994_bulk_write);
@@ -169,28 +114,7 @@ EXPORT_SYMBOL_GPL(wm8994_bulk_write);
int wm8994_set_bits(struct wm8994 *wm8994, unsigned short reg,
unsigned short mask, unsigned short val)
{
- int ret;
- u16 r;
-
- mutex_lock(&wm8994->io_lock);
-
- ret = wm8994_read(wm8994, reg, 2, &r);
- if (ret < 0)
- goto out;
-
- r = be16_to_cpu(r);
-
- r &= ~mask;
- r |= val;
-
- r = cpu_to_be16(r);
-
- ret = wm8994_write(wm8994, reg, 2, &r);
-
-out:
- mutex_unlock(&wm8994->io_lock);
-
- return ret;
+ return regmap_update_bits(wm8994->regmap, reg, mask, val);
}
EXPORT_SYMBOL_GPL(wm8994_set_bits);
@@ -378,6 +302,11 @@ static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo)
}
#endif
+static struct regmap_config wm8994_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 16,
+};
+
/*
* Instantiate the generic non-control parts of the device.
*/
@@ -387,7 +316,6 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
const char *devname;
int ret, i;
- mutex_init(&wm8994->io_lock);
dev_set_drvdata(wm8994->dev, wm8994);
/* Add the on-chip regulators first for bootstrapping */
@@ -397,7 +325,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
NULL, 0);
if (ret != 0) {
dev_err(wm8994->dev, "Failed to add children: %d\n", ret);
- goto err;
+ goto err_regmap;
}
switch (wm8994->type) {
@@ -409,7 +337,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
break;
default:
BUG();
- goto err;
+ goto err_regmap;
}
wm8994->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
@@ -417,7 +345,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
GFP_KERNEL);
if (!wm8994->supplies) {
ret = -ENOMEM;
- goto err;
+ goto err_regmap;
}
switch (wm8994->type) {
@@ -431,7 +359,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
break;
default:
BUG();
- goto err;
+ goto err_regmap;
}
ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies,
@@ -554,7 +482,8 @@ err_get:
regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
err_supplies:
kfree(wm8994->supplies);
-err:
+err_regmap:
+ regmap_exit(wm8994->regmap);
mfd_remove_devices(wm8994->dev);
kfree(wm8994);
return ret;
@@ -569,62 +498,15 @@ static void wm8994_device_exit(struct wm8994 *wm8994)
wm8994->supplies);
regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
kfree(wm8994->supplies);
+ regmap_exit(wm8994->regmap);
kfree(wm8994);
}
-static int wm8994_i2c_read_device(struct wm8994 *wm8994, unsigned short reg,
- int bytes, void *dest)
-{
- struct i2c_client *i2c = wm8994->control_data;
- int ret;
- u16 r = cpu_to_be16(reg);
-
- ret = i2c_master_send(i2c, (unsigned char *)&r, 2);
- if (ret < 0)
- return ret;
- if (ret != 2)
- return -EIO;
-
- ret = i2c_master_recv(i2c, dest, bytes);
- if (ret < 0)
- return ret;
- if (ret != bytes)
- return -EIO;
- return 0;
-}
-
-static int wm8994_i2c_write_device(struct wm8994 *wm8994, unsigned short reg,
- int bytes, const void *src)
-{
- struct i2c_client *i2c = wm8994->control_data;
- struct i2c_msg xfer[2];
- int ret;
-
- reg = cpu_to_be16(reg);
-
- xfer[0].addr = i2c->addr;
- xfer[0].flags = 0;
- xfer[0].len = 2;
- xfer[0].buf = (char *)&reg;
-
- xfer[1].addr = i2c->addr;
- xfer[1].flags = I2C_M_NOSTART;
- xfer[1].len = bytes;
- xfer[1].buf = (char *)src;
-
- ret = i2c_transfer(i2c->adapter, xfer, 2);
- if (ret < 0)
- return ret;
- if (ret != 2)
- return -EIO;
-
- return 0;
-}
-
static int wm8994_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8994 *wm8994;
+ int ret;
wm8994 = kzalloc(sizeof(struct wm8994), GFP_KERNEL);
if (wm8994 == NULL)
@@ -632,12 +514,18 @@ static int wm8994_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, wm8994);
wm8994->dev = &i2c->dev;
- wm8994->control_data = i2c;
- wm8994->read_dev = wm8994_i2c_read_device;
- wm8994->write_dev = wm8994_i2c_write_device;
wm8994->irq = i2c->irq;
wm8994->type = id->driver_data;
+ wm8994->regmap = regmap_init_i2c(i2c, &wm8994_regmap_config);
+ if (IS_ERR(wm8994->regmap)) {
+ ret = PTR_ERR(wm8994->regmap);
+ dev_err(wm8994->dev, "Failed to allocate register map: %d\n",
+ ret);
+ kfree(wm8994);
+ return ret;
+ }
+
return wm8994_device_init(wm8994, i2c->irq);
}
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 0a4d86c6c4a4..2d6423c2d193 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -146,6 +146,7 @@ config PHANTOM
config INTEL_MID_PTI
tristate "Parallel Trace Interface for MIPI P1149.7 cJTAG standard"
+ depends on PCI
default n
help
The PTI (Parallel Trace Interface) driver directs
diff --git a/drivers/misc/ab8500-pwm.c b/drivers/misc/ab8500-pwm.c
index 54e3d05b63cc..35903154ca2e 100644
--- a/drivers/misc/ab8500-pwm.c
+++ b/drivers/misc/ab8500-pwm.c
@@ -164,5 +164,5 @@ subsys_initcall(ab8500_pwm_init);
module_exit(ab8500_pwm_exit);
MODULE_AUTHOR("Arun MURTHY <arun.murthy@stericsson.com>");
MODULE_DESCRIPTION("AB8500 Pulse Width Modulation Driver");
-MODULE_ALIAS("AB8500 PWM driver");
+MODULE_ALIAS("platform:ab8500-pwm");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/fsa9480.c b/drivers/misc/fsa9480.c
index 5325a7e70dcf..27dc0d21aafa 100644
--- a/drivers/misc/fsa9480.c
+++ b/drivers/misc/fsa9480.c
@@ -455,7 +455,7 @@ static int __devinit fsa9480_probe(struct i2c_client *client,
fail2:
if (client->irq)
- free_irq(client->irq, NULL);
+ free_irq(client->irq, usbsw);
fail1:
i2c_set_clientdata(client, NULL);
kfree(usbsw);
@@ -466,7 +466,7 @@ static int __devexit fsa9480_remove(struct i2c_client *client)
{
struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client);
if (client->irq)
- free_irq(client->irq, NULL);
+ free_irq(client->irq, usbsw);
i2c_set_clientdata(client, NULL);
sysfs_remove_group(&client->dev.kobj, &fsa9480_group);
diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c
index b928bc14e97b..8b51cd62d067 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d.c
@@ -375,12 +375,14 @@ void lis3lv02d_poweron(struct lis3lv02d *lis3)
* both have been read. So the value read will always be correct.
* Set BOOT bit to refresh factory tuning values.
*/
- lis3->read(lis3, CTRL_REG2, &reg);
- if (lis3->whoami == WAI_12B)
- reg |= CTRL2_BDU | CTRL2_BOOT;
- else
- reg |= CTRL2_BOOT_8B;
- lis3->write(lis3, CTRL_REG2, reg);
+ if (lis3->pdata) {
+ lis3->read(lis3, CTRL_REG2, &reg);
+ if (lis3->whoami == WAI_12B)
+ reg |= CTRL2_BDU | CTRL2_BOOT;
+ else
+ reg |= CTRL2_BOOT_8B;
+ lis3->write(lis3, CTRL_REG2, reg);
+ }
/* LIS3 power on delay is quite long */
msleep(lis3->pwron_delay / lis3lv02d_get_odr());
diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c
index 0fd7e77bee29..dee33addcaeb 100644
--- a/drivers/misc/pch_phub.c
+++ b/drivers/misc/pch_phub.c
@@ -90,6 +90,7 @@
#define PCH_PHUB_INTPIN_REG_WPERMIT_REG3 0x002C
#define PCH_PHUB_INT_REDUCE_CONTROL_REG_BASE 0x0040
#define CLKCFG_REG_OFFSET 0x500
+#define FUNCSEL_REG_OFFSET 0x508
#define PCH_PHUB_OROM_SIZE 15360
@@ -108,6 +109,7 @@
* @intpin_reg_wpermit_reg3: INTPIN_REG_WPERMIT register 3 val
* @int_reduce_control_reg: INT_REDUCE_CONTROL registers val
* @clkcfg_reg: CLK CFG register val
+ * @funcsel_reg: Function select register value
* @pch_phub_base_address: Register base address
* @pch_phub_extrom_base_address: external rom base address
* @pch_mac_start_address: MAC address area start address
@@ -128,6 +130,7 @@ struct pch_phub_reg {
u32 intpin_reg_wpermit_reg3;
u32 int_reduce_control_reg[MAX_NUM_INT_REDUCE_CONTROL_REG];
u32 clkcfg_reg;
+ u32 funcsel_reg;
void __iomem *pch_phub_base_address;
void __iomem *pch_phub_extrom_base_address;
u32 pch_mac_start_address;
@@ -211,6 +214,8 @@ static void pch_phub_save_reg_conf(struct pci_dev *pdev)
__func__, i, chip->int_reduce_control_reg[i]);
}
chip->clkcfg_reg = ioread32(p + CLKCFG_REG_OFFSET);
+ if ((chip->ioh_type == 2) || (chip->ioh_type == 4))
+ chip->funcsel_reg = ioread32(p + FUNCSEL_REG_OFFSET);
}
/* pch_phub_restore_reg_conf - restore register configuration */
@@ -271,6 +276,8 @@ static void pch_phub_restore_reg_conf(struct pci_dev *pdev)
}
iowrite32(chip->clkcfg_reg, p + CLKCFG_REG_OFFSET);
+ if ((chip->ioh_type == 2) || (chip->ioh_type == 4))
+ iowrite32(chip->funcsel_reg, p + FUNCSEL_REG_OFFSET);
}
/**
@@ -594,8 +601,7 @@ static ssize_t show_pch_mac(struct device *dev, struct device_attribute *attr,
pch_phub_read_gbe_mac_addr(chip, mac);
- return sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ return sprintf(buf, "%pM\n", mac);
}
static ssize_t store_pch_mac(struct device *dev, struct device_attribute *attr,
diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c
index 8653bd0b1a33..0b56e3f43573 100644
--- a/drivers/misc/pti.c
+++ b/drivers/misc/pti.c
@@ -33,6 +33,8 @@
#include <linux/mutex.h>
#include <linux/miscdevice.h>
#include <linux/pti.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
#define DRIVERNAME "pti"
#define PCINAME "pciPTI"
@@ -163,6 +165,11 @@ static void pti_write_to_aperture(struct pti_masterchannel *mc,
static void pti_control_frame_built_and_sent(struct pti_masterchannel *mc,
const char *thread_name)
{
+ /*
+ * Since we access the comm member in current's task_struct, we only
+ * need to be as large as what 'comm' in that structure is.
+ */
+ char comm[TASK_COMM_LEN];
struct pti_masterchannel mccontrol = {.master = CONTROL_ID,
.channel = 0};
const char *thread_name_p;
@@ -170,13 +177,6 @@ static void pti_control_frame_built_and_sent(struct pti_masterchannel *mc,
u8 control_frame[CONTROL_FRAME_LEN];
if (!thread_name) {
- /*
- * Since we access the comm member in current's task_struct,
- * we only need to be as large as what 'comm' in that
- * structure is.
- */
- char comm[TASK_COMM_LEN];
-
if (!in_interrupt())
get_task_comm(comm, current);
else
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index 54c91ffe4a91..ba168a7d54d4 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -338,6 +338,12 @@ void st_int_recv(void *disc_data,
/* Unknow packet? */
default:
type = *ptr;
+ if (st_gdata->list[type] == NULL) {
+ pr_err("chip/interface misbehavior dropping"
+ " frame starting with 0x%02x", type);
+ goto done;
+
+ }
st_gdata->rx_skb = alloc_skb(
st_gdata->list[type]->max_frame_size,
GFP_ATOMIC);
@@ -354,6 +360,7 @@ void st_int_recv(void *disc_data,
ptr++;
count--;
}
+done:
spin_unlock_irqrestore(&st_gdata->lock, flags);
pr_debug("done %s", __func__);
return;
@@ -717,9 +724,10 @@ static void st_tty_close(struct tty_struct *tty)
*/
spin_lock_irqsave(&st_gdata->lock, flags);
for (i = ST_BT; i < ST_MAX_CHANNELS; i++) {
- if (st_gdata->list[i] != NULL)
+ if (st_gdata->is_registered[i] == true)
pr_err("%d not un-registered", i);
st_gdata->list[i] = NULL;
+ st_gdata->is_registered[i] = false;
}
st_gdata->protos_registered = 0;
spin_unlock_irqrestore(&st_gdata->lock, flags);
diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c
index 38fd2f04c07e..3a3580566dfc 100644
--- a/drivers/misc/ti-st/st_kim.c
+++ b/drivers/misc/ti-st/st_kim.c
@@ -68,6 +68,7 @@ void validate_firmware_response(struct kim_data_s *kim_gdata)
if (unlikely(skb->data[5] != 0)) {
pr_err("no proper response during fw download");
pr_err("data6 %x", skb->data[5]);
+ kfree_skb(skb);
return; /* keep waiting for the proper response */
}
/* becos of all the script being downloaded */
@@ -210,6 +211,7 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name)
pr_err(" waiting for ver info- timed out ");
return -ETIMEDOUT;
}
+ INIT_COMPLETION(kim_gdata->kim_rcvd);
version =
MAKEWORD(kim_gdata->resp_buffer[13],
@@ -298,6 +300,7 @@ static long download_firmware(struct kim_data_s *kim_gdata)
switch (((struct bts_action *)ptr)->type) {
case ACTION_SEND_COMMAND: /* action send */
+ pr_debug("S");
action_ptr = &(((struct bts_action *)ptr)->data[0]);
if (unlikely
(((struct hci_command *)action_ptr)->opcode ==
@@ -335,6 +338,10 @@ static long download_firmware(struct kim_data_s *kim_gdata)
release_firmware(kim_gdata->fw_entry);
return -ETIMEDOUT;
}
+ /* reinit completion before sending for the
+ * relevant wait
+ */
+ INIT_COMPLETION(kim_gdata->kim_rcvd);
/*
* Free space found in uart buffer, call st_int_write
@@ -361,6 +368,7 @@ static long download_firmware(struct kim_data_s *kim_gdata)
}
break;
case ACTION_WAIT_EVENT: /* wait */
+ pr_debug("W");
if (!wait_for_completion_timeout
(&kim_gdata->kim_rcvd,
msecs_to_jiffies(CMD_RESP_TIME))) {
@@ -434,11 +442,17 @@ long st_kim_start(void *kim_data)
{
long err = 0;
long retry = POR_RETRY_COUNT;
+ struct ti_st_plat_data *pdata;
struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data;
pr_info(" %s", __func__);
+ pdata = kim_gdata->kim_pdev->dev.platform_data;
do {
+ /* platform specific enabling code here */
+ if (pdata->chip_enable)
+ pdata->chip_enable(kim_gdata);
+
/* Configure BT nShutdown to HIGH state */
gpio_set_value(kim_gdata->nshutdown, GPIO_LOW);
mdelay(5); /* FIXME: a proper toggle */
@@ -460,6 +474,12 @@ long st_kim_start(void *kim_data)
pr_info("ldisc_install = 0");
sysfs_notify(&kim_gdata->kim_pdev->dev.kobj,
NULL, "install");
+ /* the following wait is never going to be completed,
+ * since the ldisc was never installed, hence serving
+ * as a mdelay of LDISC_TIME msecs */
+ err = wait_for_completion_timeout
+ (&kim_gdata->ldisc_installed,
+ msecs_to_jiffies(LDISC_TIME));
err = -ETIMEDOUT;
continue;
} else {
@@ -472,6 +492,13 @@ long st_kim_start(void *kim_data)
pr_info("ldisc_install = 0");
sysfs_notify(&kim_gdata->kim_pdev->dev.kobj,
NULL, "install");
+ /* this wait might be completed, though in the
+ * tty_close() since the ldisc is already
+ * installed */
+ err = wait_for_completion_timeout
+ (&kim_gdata->ldisc_installed,
+ msecs_to_jiffies(LDISC_TIME));
+ err = -EINVAL;
continue;
} else { /* on success don't retry */
break;
@@ -489,6 +516,8 @@ long st_kim_stop(void *kim_data)
{
long err = 0;
struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data;
+ struct ti_st_plat_data *pdata =
+ kim_gdata->kim_pdev->dev.platform_data;
INIT_COMPLETION(kim_gdata->ldisc_installed);
@@ -515,6 +544,10 @@ long st_kim_stop(void *kim_data)
gpio_set_value(kim_gdata->nshutdown, GPIO_HIGH);
mdelay(1);
gpio_set_value(kim_gdata->nshutdown, GPIO_LOW);
+
+ /* platform specific disable */
+ if (pdata->chip_disable)
+ pdata->chip_disable(kim_gdata);
return err;
}
diff --git a/drivers/misc/ti-st/st_ll.c b/drivers/misc/ti-st/st_ll.c
index 3f2495138855..1ff460a8e9c7 100644
--- a/drivers/misc/ti-st/st_ll.c
+++ b/drivers/misc/ti-st/st_ll.c
@@ -22,6 +22,7 @@
#define pr_fmt(fmt) "(stll) :" fmt
#include <linux/skbuff.h>
#include <linux/module.h>
+#include <linux/platform_device.h>
#include <linux/ti_wilink_st.h>
/**********************************************************************/
@@ -37,6 +38,9 @@ static void send_ll_cmd(struct st_data_s *st_data,
static void ll_device_want_to_sleep(struct st_data_s *st_data)
{
+ struct kim_data_s *kim_data;
+ struct ti_st_plat_data *pdata;
+
pr_debug("%s", __func__);
/* sanity check */
if (st_data->ll_state != ST_LL_AWAKE)
@@ -46,10 +50,19 @@ static void ll_device_want_to_sleep(struct st_data_s *st_data)
send_ll_cmd(st_data, LL_SLEEP_ACK);
/* update state */
st_data->ll_state = ST_LL_ASLEEP;
+
+ /* communicate to platform about chip asleep */
+ kim_data = st_data->kim_data;
+ pdata = kim_data->kim_pdev->dev.platform_data;
+ if (pdata->chip_asleep)
+ pdata->chip_asleep(NULL);
}
static void ll_device_want_to_wakeup(struct st_data_s *st_data)
{
+ struct kim_data_s *kim_data;
+ struct ti_st_plat_data *pdata;
+
/* diff actions in diff states */
switch (st_data->ll_state) {
case ST_LL_ASLEEP:
@@ -70,6 +83,12 @@ static void ll_device_want_to_wakeup(struct st_data_s *st_data)
}
/* update state */
st_data->ll_state = ST_LL_AWAKE;
+
+ /* communicate to platform about chip wakeup */
+ kim_data = st_data->kim_data;
+ pdata = kim_data->kim_pdev->dev.platform_data;
+ if (pdata->chip_asleep)
+ pdata->chip_awake(NULL);
}
/**********************************************************************/
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 1ff5486213fb..4c1a648d00fc 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -926,6 +926,9 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
/*
* Reliable writes are used to implement Forced Unit Access and
* REQ_META accesses, and are supported only on MMCs.
+ *
+ * XXX: this really needs a good explanation of why REQ_META
+ * is treated special.
*/
bool do_rel_wr = ((req->cmd_flags & REQ_FUA) ||
(req->cmd_flags & REQ_META)) &&
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 91a0a7460ebb..b27b94078c21 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -133,7 +133,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
if (mrq->done)
mrq->done(mrq);
- mmc_host_clk_gate(host);
+ mmc_host_clk_release(host);
}
}
@@ -192,7 +192,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mrq->stop->mrq = mrq;
}
}
- mmc_host_clk_ungate(host);
+ mmc_host_clk_hold(host);
led_trigger_event(host->led, LED_FULL);
host->ops->request(host, mrq);
}
@@ -728,15 +728,17 @@ static inline void mmc_set_ios(struct mmc_host *host)
*/
void mmc_set_chip_select(struct mmc_host *host, int mode)
{
+ mmc_host_clk_hold(host);
host->ios.chip_select = mode;
mmc_set_ios(host);
+ mmc_host_clk_release(host);
}
/*
* Sets the host clock to the highest possible frequency that
* is below "hz".
*/
-void mmc_set_clock(struct mmc_host *host, unsigned int hz)
+static void __mmc_set_clock(struct mmc_host *host, unsigned int hz)
{
WARN_ON(hz < host->f_min);
@@ -747,6 +749,13 @@ void mmc_set_clock(struct mmc_host *host, unsigned int hz)
mmc_set_ios(host);
}
+void mmc_set_clock(struct mmc_host *host, unsigned int hz)
+{
+ mmc_host_clk_hold(host);
+ __mmc_set_clock(host, hz);
+ mmc_host_clk_release(host);
+}
+
#ifdef CONFIG_MMC_CLKGATE
/*
* This gates the clock by setting it to 0 Hz.
@@ -779,7 +788,7 @@ void mmc_ungate_clock(struct mmc_host *host)
if (host->clk_old) {
BUG_ON(host->ios.clock);
/* This call will also set host->clk_gated to false */
- mmc_set_clock(host, host->clk_old);
+ __mmc_set_clock(host, host->clk_old);
}
}
@@ -807,8 +816,10 @@ void mmc_set_ungated(struct mmc_host *host)
*/
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
{
+ mmc_host_clk_hold(host);
host->ios.bus_mode = mode;
mmc_set_ios(host);
+ mmc_host_clk_release(host);
}
/*
@@ -816,8 +827,10 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
*/
void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
{
+ mmc_host_clk_hold(host);
host->ios.bus_width = width;
mmc_set_ios(host);
+ mmc_host_clk_release(host);
}
/**
@@ -1015,8 +1028,10 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
ocr &= 3 << bit;
+ mmc_host_clk_hold(host);
host->ios.vdd = bit;
mmc_set_ios(host);
+ mmc_host_clk_release(host);
} else {
pr_warning("%s: host doesn't support card's voltages\n",
mmc_hostname(host));
@@ -1063,8 +1078,10 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11
*/
void mmc_set_timing(struct mmc_host *host, unsigned int timing)
{
+ mmc_host_clk_hold(host);
host->ios.timing = timing;
mmc_set_ios(host);
+ mmc_host_clk_release(host);
}
/*
@@ -1072,8 +1089,10 @@ void mmc_set_timing(struct mmc_host *host, unsigned int timing)
*/
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
{
+ mmc_host_clk_hold(host);
host->ios.drv_type = drv_type;
mmc_set_ios(host);
+ mmc_host_clk_release(host);
}
/*
@@ -1091,6 +1110,8 @@ static void mmc_power_up(struct mmc_host *host)
{
int bit;
+ mmc_host_clk_hold(host);
+
/* If ocr is set, we use it */
if (host->ocr)
bit = ffs(host->ocr) - 1;
@@ -1126,10 +1147,14 @@ static void mmc_power_up(struct mmc_host *host)
* time required to reach a stable voltage.
*/
mmc_delay(10);
+
+ mmc_host_clk_release(host);
}
static void mmc_power_off(struct mmc_host *host)
{
+ mmc_host_clk_hold(host);
+
host->ios.clock = 0;
host->ios.vdd = 0;
@@ -1147,6 +1172,8 @@ static void mmc_power_off(struct mmc_host *host)
host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ios.timing = MMC_TIMING_LEGACY;
mmc_set_ios(host);
+
+ mmc_host_clk_release(host);
}
/*
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index b29d3e8fd3a2..793d0a0dad8d 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -119,14 +119,14 @@ static void mmc_host_clk_gate_work(struct work_struct *work)
}
/**
- * mmc_host_clk_ungate - ungate hardware MCI clocks
+ * mmc_host_clk_hold - ungate hardware MCI clocks
* @host: host to ungate.
*
* Makes sure the host ios.clock is restored to a non-zero value
* past this call. Increase clock reference count and ungate clock
* if we're the first user.
*/
-void mmc_host_clk_ungate(struct mmc_host *host)
+void mmc_host_clk_hold(struct mmc_host *host)
{
unsigned long flags;
@@ -164,14 +164,14 @@ static bool mmc_host_may_gate_card(struct mmc_card *card)
}
/**
- * mmc_host_clk_gate - gate off hardware MCI clocks
+ * mmc_host_clk_release - gate off hardware MCI clocks
* @host: host to gate.
*
* Calls the host driver with ios.clock set to zero as often as possible
* in order to gate off hardware MCI clocks. Decrease clock reference
* count and schedule disabling of clock.
*/
-void mmc_host_clk_gate(struct mmc_host *host)
+void mmc_host_clk_release(struct mmc_host *host)
{
unsigned long flags;
@@ -179,7 +179,7 @@ void mmc_host_clk_gate(struct mmc_host *host)
host->clk_requests--;
if (mmc_host_may_gate_card(host->card) &&
!host->clk_requests)
- schedule_work(&host->clk_gate_work);
+ queue_work(system_nrt_wq, &host->clk_gate_work);
spin_unlock_irqrestore(&host->clk_lock, flags);
}
@@ -231,7 +231,7 @@ static inline void mmc_host_clk_exit(struct mmc_host *host)
if (cancel_work_sync(&host->clk_gate_work))
mmc_host_clk_gate_delayed(host);
if (host->clk_gated)
- mmc_host_clk_ungate(host);
+ mmc_host_clk_hold(host);
/* There should be only one user now */
WARN_ON(host->clk_requests > 1);
}
diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h
index de199f911928..fb8a5cd2e4a1 100644
--- a/drivers/mmc/core/host.h
+++ b/drivers/mmc/core/host.h
@@ -16,16 +16,16 @@ int mmc_register_host_class(void);
void mmc_unregister_host_class(void);
#ifdef CONFIG_MMC_CLKGATE
-void mmc_host_clk_ungate(struct mmc_host *host);
-void mmc_host_clk_gate(struct mmc_host *host);
+void mmc_host_clk_hold(struct mmc_host *host);
+void mmc_host_clk_release(struct mmc_host *host);
unsigned int mmc_host_clk_rate(struct mmc_host *host);
#else
-static inline void mmc_host_clk_ungate(struct mmc_host *host)
+static inline void mmc_host_clk_hold(struct mmc_host *host)
{
}
-static inline void mmc_host_clk_gate(struct mmc_host *host)
+static inline void mmc_host_clk_release(struct mmc_host *host)
{
}
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 633975ff2bb3..0370e03e3142 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -469,56 +469,75 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status)
return 0;
}
-static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
+static void sd_update_bus_speed_mode(struct mmc_card *card)
{
- unsigned int bus_speed = 0, timing = 0;
- int err;
-
/*
* If the host doesn't support any of the UHS-I modes, fallback on
* default speed.
*/
if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50)))
- return 0;
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))) {
+ card->sd_bus_speed = 0;
+ return;
+ }
if ((card->host->caps & MMC_CAP_UHS_SDR104) &&
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) {
- bus_speed = UHS_SDR104_BUS_SPEED;
- timing = MMC_TIMING_UHS_SDR104;
- card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
+ card->sd_bus_speed = UHS_SDR104_BUS_SPEED;
} else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
- bus_speed = UHS_DDR50_BUS_SPEED;
- timing = MMC_TIMING_UHS_DDR50;
- card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
+ card->sd_bus_speed = UHS_DDR50_BUS_SPEED;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
SD_MODE_UHS_SDR50)) {
- bus_speed = UHS_SDR50_BUS_SPEED;
- timing = MMC_TIMING_UHS_SDR50;
- card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
+ card->sd_bus_speed = UHS_SDR50_BUS_SPEED;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
- bus_speed = UHS_SDR25_BUS_SPEED;
- timing = MMC_TIMING_UHS_SDR25;
- card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
+ card->sd_bus_speed = UHS_SDR25_BUS_SPEED;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
SD_MODE_UHS_SDR12)) {
- bus_speed = UHS_SDR12_BUS_SPEED;
- timing = MMC_TIMING_UHS_SDR12;
- card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
+ card->sd_bus_speed = UHS_SDR12_BUS_SPEED;
+ }
+}
+
+static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
+{
+ int err;
+ unsigned int timing = 0;
+
+ switch (card->sd_bus_speed) {
+ case UHS_SDR104_BUS_SPEED:
+ timing = MMC_TIMING_UHS_SDR104;
+ card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
+ break;
+ case UHS_DDR50_BUS_SPEED:
+ timing = MMC_TIMING_UHS_DDR50;
+ card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
+ break;
+ case UHS_SDR50_BUS_SPEED:
+ timing = MMC_TIMING_UHS_SDR50;
+ card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
+ break;
+ case UHS_SDR25_BUS_SPEED:
+ timing = MMC_TIMING_UHS_SDR25;
+ card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
+ break;
+ case UHS_SDR12_BUS_SPEED:
+ timing = MMC_TIMING_UHS_SDR12;
+ card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
+ break;
+ default:
+ return 0;
}
- card->sd_bus_speed = bus_speed;
- err = mmc_sd_switch(card, 1, 0, bus_speed, status);
+ err = mmc_sd_switch(card, 1, 0, card->sd_bus_speed, status);
if (err)
return err;
- if ((status[16] & 0xF) != bus_speed)
+ if ((status[16] & 0xF) != card->sd_bus_speed)
printk(KERN_WARNING "%s: Problem setting bus speed mode!\n",
mmc_hostname(card->host));
else {
@@ -618,18 +637,24 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
}
+ /*
+ * Select the bus speed mode depending on host
+ * and card capability.
+ */
+ sd_update_bus_speed_mode(card);
+
/* Set the driver strength for the card */
err = sd_select_driver_type(card, status);
if (err)
goto out;
- /* Set bus speed mode of the card */
- err = sd_set_bus_speed_mode(card, status);
+ /* Set current limit for the card */
+ err = sd_set_current_limit(card, status);
if (err)
goto out;
- /* Set current limit for the card */
- err = sd_set_current_limit(card, status);
+ /* Set bus speed mode of the card */
+ err = sd_set_bus_speed_mode(card, status);
if (err)
goto out;
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 0e9780f5a4a9..4dc0028086a3 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -16,6 +16,7 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/gpio.h>
+#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index 2bd7bf4fece7..fe886d6c474a 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -302,6 +302,8 @@ static int sdhci_s3c_platform_8bit_width(struct sdhci_host *host, int width)
ctrl &= ~SDHCI_CTRL_8BITBUS;
break;
default:
+ ctrl &= ~SDHCI_CTRL_4BITBUS;
+ ctrl &= ~SDHCI_CTRL_8BITBUS;
break;
}
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index 774f6439d7ce..0c4a672f5db6 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -120,11 +120,11 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
mmc_data->hclk = clk_get_rate(priv->clk);
mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
mmc_data->get_cd = sh_mobile_sdhi_get_cd;
- if (mmc_data->flags & TMIO_MMC_HAS_IDLE_WAIT)
- mmc_data->write16_hook = sh_mobile_sdhi_write16_hook;
mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED;
if (p) {
mmc_data->flags = p->tmio_flags;
+ if (mmc_data->flags & TMIO_MMC_HAS_IDLE_WAIT)
+ mmc_data->write16_hook = sh_mobile_sdhi_write16_hook;
mmc_data->ocr_mask = p->tmio_ocr_mask;
mmc_data->capabilities |= p->tmio_caps;
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 4be8373d43e5..66b616ebe536 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -142,7 +142,7 @@ config MTD_OF_PARTS
help
This provides a partition parsing function which derives
the partition map from the children of the flash node,
- as described in Documentation/powerpc/booting-without-of.txt.
+ as described in Documentation/devicetree/booting-without-of.txt.
config MTD_AR7_PARTS
tristate "TI AR7 partitioning support"
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index 65b5b76cc379..64fbb0021825 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -181,7 +181,7 @@ static inline int ubi_dbg_is_erase_failure(const struct ubi_device *ubi)
#define ubi_dbg_msg(fmt, ...) do { \
if (0) \
- pr_debug(fmt "\n", ##__VA_ARGS__); \
+ printk(KERN_DEBUG fmt "\n", ##__VA_ARGS__); \
} while (0)
#define dbg_msg(fmt, ...) ubi_dbg_msg(fmt, ##__VA_ARGS__)
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 8d0314dbd946..583f66cd5bbd 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2,9 +2,6 @@
# Network device configuration
#
-config HAVE_NET_MACB
- bool
-
menuconfig NETDEVICES
default y if UML
depends on NET
@@ -28,18 +25,32 @@ menuconfig NETDEVICES
# that for each of the symbols.
if NETDEVICES
-config IFB
- tristate "Intermediate Functional Block support"
- depends on NET_CLS_ACT
+config NET_CORE
+ default y
+ bool "Network core driver support"
---help---
- This is an intermediate driver that allows sharing of
- resources.
+ You can say N here if you do not intend to use any of the
+ networking core drivers (i.e. VLAN, bridging, bonding, etc.)
+
+if NET_CORE
+
+config BONDING
+ tristate "Bonding driver support"
+ depends on INET
+ depends on IPV6 || IPV6=n
+ ---help---
+ Say 'Y' or 'M' if you wish to be able to 'bond' multiple Ethernet
+ Channels together. This is called 'Etherchannel' by Cisco,
+ 'Trunking' by Sun, 802.3ad by the IEEE, and 'Bonding' in Linux.
+
+ The driver supports multiple bonding modes to allow for both high
+ performance and high availability operation.
+
+ Refer to <file:Documentation/networking/bonding.txt> for more
+ information.
+
To compile this driver as a module, choose M here: the module
- will be called ifb. If you want to use more than one ifb
- device at a time, you need to compile this driver as a module.
- Instead of 'ifb', the devices will then be called 'ifb0',
- 'ifb1' etc.
- Look at the iproute2 documentation directory for usage etc
+ will be called bonding.
config DUMMY
tristate "Dummy net driver support"
@@ -60,23 +71,59 @@ config DUMMY
Instead of 'dummy', the devices will then be called 'dummy0',
'dummy1' etc.
-config BONDING
- tristate "Bonding driver support"
- depends on INET
- depends on IPV6 || IPV6=n
+config EQUALIZER
+ tristate "EQL (serial line load balancing) support"
---help---
- Say 'Y' or 'M' if you wish to be able to 'bond' multiple Ethernet
- Channels together. This is called 'Etherchannel' by Cisco,
- 'Trunking' by Sun, 802.3ad by the IEEE, and 'Bonding' in Linux.
+ If you have two serial connections to some other computer (this
+ usually requires two modems and two telephone lines) and you use
+ SLIP (the protocol for sending Internet traffic over telephone
+ lines) or PPP (a better SLIP) on them, you can make them behave like
+ one double speed connection using this driver. Naturally, this has
+ to be supported at the other end as well, either with a similar EQL
+ Linux driver or with a Livingston Portmaster 2e.
- The driver supports multiple bonding modes to allow for both high
- performance and high availability operation.
+ Say Y if you want this and read
+ <file:Documentation/networking/eql.txt>. You may also want to read
+ section 6.2 of the NET-3-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
- Refer to <file:Documentation/networking/bonding.txt> for more
- information.
+ To compile this driver as a module, choose M here: the module
+ will be called eql. If unsure, say N.
+
+config NET_FC
+ bool "Fibre Channel driver support"
+ depends on SCSI && PCI
+ help
+ Fibre Channel is a high speed serial protocol mainly used to connect
+ large storage devices to the computer; it is compatible with and
+ intended to replace SCSI.
+
+ If you intend to use Fibre Channel, you need to have a Fibre channel
+ adaptor card in your computer; say Y here and to the driver for your
+ adaptor below. You also should have said Y to "SCSI support" and
+ "SCSI generic support".
+
+config MII
+ tristate "Generic Media Independent Interface device support"
+ help
+ Most ethernet controllers have MII transceiver either as an external
+ or internal device. It is safe to say Y or M here even if your
+ ethernet card lacks MII.
+source "drivers/ieee802154/Kconfig"
+
+config IFB
+ tristate "Intermediate Functional Block support"
+ depends on NET_CLS_ACT
+ ---help---
+ This is an intermediate driver that allows sharing of
+ resources.
To compile this driver as a module, choose M here: the module
- will be called bonding.
+ will be called ifb. If you want to use more than one ifb
+ device at a time, you need to compile this driver as a module.
+ Instead of 'ifb', the devices will then be called 'ifb0',
+ 'ifb1' etc.
+ Look at the iproute2 documentation directory for usage etc
config MACVLAN
tristate "MAC-VLAN support (EXPERIMENTAL)"
@@ -105,24 +152,46 @@ config MACVTAP
To compile this driver as a module, choose M here: the module
will be called macvtap.
-config EQUALIZER
- tristate "EQL (serial line load balancing) support"
+config NETCONSOLE
+ tristate "Network console logging support"
---help---
- If you have two serial connections to some other computer (this
- usually requires two modems and two telephone lines) and you use
- SLIP (the protocol for sending Internet traffic over telephone
- lines) or PPP (a better SLIP) on them, you can make them behave like
- one double speed connection using this driver. Naturally, this has
- to be supported at the other end as well, either with a similar EQL
- Linux driver or with a Livingston Portmaster 2e.
+ If you want to log kernel messages over the network, enable this.
+ See <file:Documentation/networking/netconsole.txt> for details.
- Say Y if you want this and read
- <file:Documentation/networking/eql.txt>. You may also want to read
- section 6.2 of the NET-3-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+config NETCONSOLE_DYNAMIC
+ bool "Dynamic reconfiguration of logging targets"
+ depends on NETCONSOLE && SYSFS && CONFIGFS_FS && \
+ !(NETCONSOLE=y && CONFIGFS_FS=m)
+ help
+ This option enables the ability to dynamically reconfigure target
+ parameters (interface, IP addresses, port numbers, MAC addresses)
+ at runtime through a userspace interface exported using configfs.
+ See <file:Documentation/networking/netconsole.txt> for details.
- To compile this driver as a module, choose M here: the module
- will be called eql. If unsure, say N.
+config NETPOLL
+ def_bool NETCONSOLE
+
+config NETPOLL_TRAP
+ bool "Netpoll traffic trapping"
+ default n
+ depends on NETPOLL
+
+config NET_POLL_CONTROLLER
+ def_bool NETPOLL
+
+config RIONET
+ tristate "RapidIO Ethernet over messaging driver support"
+ depends on RAPIDIO
+
+config RIONET_TX_SIZE
+ int "Number of outbound queue entries"
+ depends on RIONET
+ default "128"
+
+config RIONET_RX_SIZE
+ int "Number of inbound queue entries"
+ depends on RIONET
+ default "128"
config TUN
tristate "Universal TUN/TAP device driver support"
@@ -154,6 +223,28 @@ config VETH
When one end receives the packet it appears on its pair and vice
versa.
+config VIRTIO_NET
+ tristate "Virtio network driver (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && VIRTIO
+ ---help---
+ This is the virtual network driver for virtio. It can be used with
+ lguest or QEMU based VMMs (like KVM or Xen). Say Y or M.
+
+endif # NET_CORE
+
+config SUNGEM_PHY
+ tristate
+
+source "drivers/net/arcnet/Kconfig"
+
+source "drivers/atm/Kconfig"
+
+source "drivers/net/caif/Kconfig"
+
+source "drivers/net/ethernet/Kconfig"
+
+source "drivers/net/fddi/Kconfig"
+
config NET_SB1000
tristate "General Instruments Surfboard 1000"
depends on PNP
@@ -178,2790 +269,26 @@ config NET_SB1000
If you don't have this card, of course say N.
-source "drivers/net/arcnet/Kconfig"
-
-config MII
- tristate "Generic Media Independent Interface device support"
- help
- Most ethernet controllers have MII transceiver either as an external
- or internal device. It is safe to say Y or M here even if your
- ethernet card lacks MII.
-
source "drivers/net/phy/Kconfig"
-#
-# Ethernet
-#
+source "drivers/net/plip/Kconfig"
-menuconfig NET_ETHERNET
- bool "Ethernet (10 or 100Mbit)"
- depends on !UML
- ---help---
- Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common
- type of Local Area Network (LAN) in universities and companies.
-
- Common varieties of Ethernet are: 10BASE-2 or Thinnet (10 Mbps over
- coaxial cable, linking computers in a chain), 10BASE-T or twisted
- pair (10 Mbps over twisted pair cable, linking computers to central
- hubs), 10BASE-F (10 Mbps over optical fiber links, using hubs),
- 100BASE-TX (100 Mbps over two twisted pair cables, using hubs),
- 100BASE-T4 (100 Mbps over 4 standard voice-grade twisted pair
- cables, using hubs), 100BASE-FX (100 Mbps over optical fiber links)
- [the 100BASE varieties are also known as Fast Ethernet], and Gigabit
- Ethernet (1 Gbps over optical fiber or short copper links).
-
- If your Linux machine will be connected to an Ethernet and you have
- an Ethernet network interface card (NIC) installed in your computer,
- say Y here and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. You will then also have
- to say Y to the driver for your particular NIC.
-
- Note that the answer to this question won't directly affect the
- kernel: saying N will just cause the configurator to skip all
- the questions about Ethernet network cards. If unsure, say N.
-
-if NET_ETHERNET
-
-config MACB
- tristate "Atmel MACB support"
- depends on HAVE_NET_MACB
- select PHYLIB
- help
- The Atmel MACB ethernet interface is found on many AT32 and AT91
- parts. Say Y to include support for the MACB chip.
+source "drivers/net/ppp/Kconfig"
- To compile this driver as a module, choose M here: the module
- will be called macb.
+source "drivers/net/slip/Kconfig"
-source "drivers/net/arm/Kconfig"
-
-config AX88796
- tristate "ASIX AX88796 NE2000 clone support"
- depends on ARM || MIPS || SUPERH
- select PHYLIB
- select MDIO_BITBANG
- help
- AX88796 driver, using platform bus to provide
- chip detection and resources
-
-config AX88796_93CX6
- bool "ASIX AX88796 external 93CX6 eeprom support"
- depends on AX88796
- select EEPROM_93CX6
- help
- Select this if your platform comes with an external 93CX6 eeprom.
-
-config MACE
- tristate "MACE (Power Mac ethernet) support"
- depends on PPC_PMAC && PPC32
- select CRC32
- help
- Power Macintoshes and clones with Ethernet built-in on the
- motherboard will usually use a MACE (Medium Access Control for
- Ethernet) interface. Say Y to include support for the MACE chip.
-
- To compile this driver as a module, choose M here: the module
- will be called mace.
-
-config MACE_AAUI_PORT
- bool "Use AAUI port instead of TP by default"
- depends on MACE
- help
- Some Apple machines (notably the Apple Network Server) which use the
- MACE ethernet chip have an Apple AUI port (small 15-pin connector),
- instead of an 8-pin RJ45 connector for twisted-pair ethernet. Say
- Y here if you have such a machine. If unsure, say N.
- The driver will default to AAUI on ANS anyway, and if you use it as
- a module, you can provide the port_aaui=0|1 to force the driver.
-
-config BMAC
- tristate "BMAC (G3 ethernet) support"
- depends on PPC_PMAC && PPC32
- select CRC32
- help
- Say Y for support of BMAC Ethernet interfaces. These are used on G3
- computers.
-
- To compile this driver as a module, choose M here: the module
- will be called bmac.
-
-config ARIADNE
- tristate "Ariadne support"
- depends on ZORRO
- help
- If you have a Village Tronic Ariadne Ethernet adapter, say Y.
- Otherwise, say N.
-
- To compile this driver as a module, choose M here: the module
- will be called ariadne.
-
-config A2065
- tristate "A2065 support"
- depends on ZORRO
- select CRC32
- help
- If you have a Commodore A2065 Ethernet adapter, say Y. Otherwise,
- say N.
-
- To compile this driver as a module, choose M here: the module
- will be called a2065.
-
-config HYDRA
- tristate "Hydra support"
- depends on ZORRO
- select CRC32
- help
- If you have a Hydra Ethernet adapter, say Y. Otherwise, say N.
-
- To compile this driver as a module, choose M here: the module
- will be called hydra.
-
-config ZORRO8390
- tristate "Zorro NS8390-based Ethernet support"
- depends on ZORRO
- select CRC32
- help
- This driver is for Zorro Ethernet cards using an NS8390-compatible
- chipset, like the Village Tronic Ariadne II and the Individual
- Computers X-Surf Ethernet cards. If you have such a card, say Y.
- Otherwise, say N.
-
- To compile this driver as a module, choose M here: the module
- will be called zorro8390.
-
-config APNE
- tristate "PCMCIA NE2000 support"
- depends on AMIGA_PCMCIA
- select CRC32
- help
- If you have a PCMCIA NE2000 compatible adapter, say Y. Otherwise,
- say N.
-
- To compile this driver as a module, choose M here: the module
- will be called apne.
-
-config MAC8390
- bool "Macintosh NS 8390 based ethernet cards"
- depends on MAC
- select CRC32
- help
- If you want to include a driver to support Nubus or LC-PDS
- Ethernet cards using an NS8390 chipset or its equivalent, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
-config MAC89x0
- tristate "Macintosh CS89x0 based ethernet cards"
- depends on MAC
- ---help---
- Support for CS89x0 chipset based Ethernet cards. If you have a
- Nubus or LC-PDS network (Ethernet) card of this type, say Y and
- read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. This module will
- be called mac89x0.
-
-config MACSONIC
- tristate "Macintosh SONIC based ethernet (onboard, NuBus, LC, CS)"
- depends on MAC
- ---help---
- Support for NatSemi SONIC based Ethernet devices. This includes
- the onboard Ethernet in many Quadras as well as some LC-PDS,
- a few Nubus and all known Comm Slot Ethernet cards. If you have
- one of these say Y and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. This module will
- be called macsonic.
-
-config MACMACE
- bool "Macintosh (AV) onboard MACE ethernet"
- depends on MAC
- select CRC32
- help
- Support for the onboard AMD 79C940 MACE Ethernet controller used in
- the 660AV and 840AV Macintosh. If you have one of these Macintoshes
- say Y and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
-config MVME147_NET
- tristate "MVME147 (Lance) Ethernet support"
- depends on MVME147
- select CRC32
- help
- Support for the on-board Ethernet interface on the Motorola MVME147
- single-board computer. Say Y here to include the
- driver for this chip in your kernel.
- To compile this driver as a module, choose M here.
-
-config MVME16x_NET
- tristate "MVME16x Ethernet support"
- depends on MVME16x
- help
- This is the driver for the Ethernet interface on the Motorola
- MVME162, 166, 167, 172 and 177 boards. Say Y here to include the
- driver for this chip in your kernel.
- To compile this driver as a module, choose M here.
-
-config BVME6000_NET
- tristate "BVME6000 Ethernet support"
- depends on BVME6000
- help
- This is the driver for the Ethernet interface on BVME4000 and
- BVME6000 VME boards. Say Y here to include the driver for this chip
- in your kernel.
- To compile this driver as a module, choose M here.
-
-config ATARILANCE
- tristate "Atari Lance support"
- depends on ATARI
- help
- Say Y to include support for several Atari Ethernet adapters based
- on the AMD Lance chipset: RieblCard (with or without battery), or
- PAMCard VME (also the version by Rhotron, with different addresses).
-
-config SUN3LANCE
- tristate "Sun3/Sun3x on-board LANCE support"
- depends on SUN3 || SUN3X
- help
- Most Sun3 and Sun3x motherboards (including the 3/50, 3/60 and 3/80)
- featured an AMD Lance 10Mbit Ethernet controller on board; say Y
- here to compile in the Linux driver for this and enable Ethernet.
- General Linux information on the Sun 3 and 3x series (now
- discontinued) is at
- <http://www.angelfire.com/ca2/tech68k/sun3.html>.
-
- If you're not building a kernel for a Sun 3, say N.
-
-config SUN3_82586
- bool "Sun3 on-board Intel 82586 support"
- depends on SUN3
- help
- This driver enables support for the on-board Intel 82586 based
- Ethernet adapter found on Sun 3/1xx and 3/2xx motherboards. Note
- that this driver does not support 82586-based adapters on additional
- VME boards.
-
-config HPLANCE
- bool "HP on-board LANCE support"
- depends on DIO
- select CRC32
- help
- If you want to use the builtin "LANCE" Ethernet controller on an
- HP300 machine, say Y here.
-
-config LASI_82596
- tristate "Lasi ethernet"
- depends on GSC
- help
- Say Y here to support the builtin Intel 82596 ethernet controller
- found in Hewlett-Packard PA-RISC machines with 10Mbit ethernet.
-
-config SNI_82596
- tristate "SNI RM ethernet"
- depends on NET_ETHERNET && SNI_RM
- help
- Say Y here to support the on-board Intel 82596 ethernet controller
- built into SNI RM machines.
-
-config KORINA
- tristate "Korina (IDT RC32434) Ethernet support"
- depends on NET_ETHERNET && MIKROTIK_RB532
- help
- If you have a Mikrotik RouterBoard 500 or IDT RC32434
- based system say Y. Otherwise say N.
-
-config MIPS_JAZZ_SONIC
- tristate "MIPS JAZZ onboard SONIC Ethernet support"
- depends on MACH_JAZZ
- help
- This is the driver for the onboard card of MIPS Magnum 4000,
- Acer PICA, Olivetti M700-10 and a few other identical OEM systems.
-
-config XTENSA_XT2000_SONIC
- tristate "Xtensa XT2000 onboard SONIC Ethernet support"
- depends on XTENSA_PLATFORM_XT2000
- help
- This is the driver for the onboard card of the Xtensa XT2000 board.
-
-config MIPS_AU1X00_ENET
- tristate "MIPS AU1000 Ethernet support"
- depends on MIPS_ALCHEMY
- select PHYLIB
- select CRC32
- help
- If you have an Alchemy Semi AU1X00 based system
- say Y. Otherwise, say N.
-
-config SGI_IOC3_ETH
- bool "SGI IOC3 Ethernet"
- depends on PCI && SGI_IP27
- select CRC32
- select MII
- help
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
-config MIPS_SIM_NET
- tristate "MIPS simulator Network device"
- depends on MIPS_SIM
- help
- The MIPSNET device is a simple Ethernet network device which is
- emulated by the MIPS Simulator.
- If you are not using a MIPSsim or are unsure, say N.
-
-config SGI_O2MACE_ETH
- tristate "SGI O2 MACE Fast Ethernet support"
- depends on SGI_IP32=y
-
-config STNIC
- tristate "National DP83902AV support"
- depends on SUPERH
- select CRC32
- help
- Support for cards based on the National Semiconductor DP83902AV
- ST-NIC Serial Network Interface Controller for Twisted Pair. This
- is a 10Mbit/sec Ethernet controller. Product overview and specs at
- <http://www.national.com/pf/DP/DP83902A.html>.
-
- If unsure, say N.
-
-config SH_ETH
- tristate "Renesas SuperH Ethernet support"
- depends on SUPERH && \
- (CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712 || \
- CPU_SUBTYPE_SH7763 || CPU_SUBTYPE_SH7619 || \
- CPU_SUBTYPE_SH7724 || CPU_SUBTYPE_SH7757)
- select CRC32
- select MII
- select MDIO_BITBANG
- select PHYLIB
- help
- Renesas SuperH Ethernet device driver.
- This driver supporting CPUs are:
- - SH7710, SH7712, SH7763, SH7619, SH7724, and SH7757.
-
-config SUNLANCE
- tristate "Sun LANCE support"
- depends on SBUS
- select CRC32
- help
- This driver supports the "le" interface present on all 32-bit Sparc
- systems, on some older Ultra systems and as an Sbus option. These
- cards are based on the AMD Lance chipset, which is better known
- via the NE2100 cards.
-
- To compile this driver as a module, choose M here: the module
- will be called sunlance.
-
-config HAPPYMEAL
- tristate "Sun Happy Meal 10/100baseT support"
- depends on SBUS || PCI
- select CRC32
- help
- This driver supports the "hme" interface present on most Ultra
- systems and as an option on older Sbus systems. This driver supports
- both PCI and Sbus devices. This driver also supports the "qfe" quad
- 100baseT device available in both PCI and Sbus configurations.
-
- To compile this driver as a module, choose M here: the module
- will be called sunhme.
-
-config SUNBMAC
- tristate "Sun BigMAC 10/100baseT support (EXPERIMENTAL)"
- depends on SBUS && EXPERIMENTAL
- select CRC32
- help
- This driver supports the "be" interface available as an Sbus option.
- This is Sun's older 100baseT Ethernet device.
-
- To compile this driver as a module, choose M here: the module
- will be called sunbmac.
-
-config SUNQE
- tristate "Sun QuadEthernet support"
- depends on SBUS
- select CRC32
- help
- This driver supports the "qe" 10baseT Ethernet device, available as
- an Sbus option. Note that this is not the same as Quad FastEthernet
- "qfe" which is supported by the Happy Meal driver instead.
-
- To compile this driver as a module, choose M here: the module
- will be called sunqe.
-
-config SUNGEM
- tristate "Sun GEM support"
- depends on PCI
- select CRC32
- help
- Support for the Sun GEM chip, aka Sun GigabitEthernet/P 2.0. See also
- <http://www.sun.com/products-n-solutions/hardware/docs/pdf/806-3985-10.pdf>.
-
-config CASSINI
- tristate "Sun Cassini support"
- depends on PCI
- select CRC32
- help
- Support for the Sun Cassini chip, aka Sun GigaSwift Ethernet. See also
- <http://www.sun.com/products-n-solutions/hardware/docs/pdf/817-4341-10.pdf>
-
-config SUNVNET
- tristate "Sun Virtual Network support"
- depends on SUN_LDOMS
- help
- Support for virtual network devices under Sun Logical Domains.
-
-config NET_VENDOR_3COM
- bool "3COM cards"
- depends on ISA || EISA || MCA || PCI
- help
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- Note that the answer to this question doesn't directly affect the
- kernel: saying N will just cause the configurator to skip all
- the questions about 3COM cards. If you say Y, you will be asked for
- your specific card in the following questions.
-
-config EL1
- tristate "3c501 \"EtherLink\" support"
- depends on NET_VENDOR_3COM && ISA
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. Also, consider buying a
- new card, since the 3c501 is slow, broken, and obsolete: you will
- have problems. Some people suggest to ping ("man ping") a nearby
- machine every minute ("man cron") when using this card.
-
- To compile this driver as a module, choose M here. The module
- will be called 3c501.
-
-config EL2
- tristate "3c503 \"EtherLink II\" support"
- depends on NET_VENDOR_3COM && ISA
- select CRC32
- help
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called 3c503.
-
-config ELPLUS
- tristate "3c505 \"EtherLink Plus\" support"
- depends on NET_VENDOR_3COM && ISA && ISA_DMA_API
- ---help---
- Information about this network (Ethernet) card can be found in
- <file:Documentation/networking/3c505.txt>. If you have a card of
- this type, say Y and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called 3c505.
-
-config EL16
- tristate "3c507 \"EtherLink 16\" support (EXPERIMENTAL)"
- depends on NET_VENDOR_3COM && ISA && EXPERIMENTAL
- help
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called 3c507.
-
-config EL3
- tristate "3c509/3c529 (MCA)/3c579 \"EtherLink III\" support"
- depends on NET_VENDOR_3COM && (ISA || EISA || MCA)
- ---help---
- If you have a network (Ethernet) card belonging to the 3Com
- EtherLinkIII series, say Y and read the Ethernet-HOWTO, available
- from <http://www.tldp.org/docs.html#howto>.
-
- If your card is not working you may need to use the DOS
- setup disk to disable Plug & Play mode, and to select the default
- media type.
-
- To compile this driver as a module, choose M here. The module
- will be called 3c509.
-
-config 3C515
- tristate "3c515 ISA \"Fast EtherLink\""
- depends on NET_VENDOR_3COM && (ISA || EISA) && ISA_DMA_API
- help
- If you have a 3Com ISA EtherLink XL "Corkscrew" 3c515 Fast Ethernet
- network card, say Y and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called 3c515.
-
-config ELMC
- tristate "3c523 \"EtherLink/MC\" support"
- depends on NET_VENDOR_3COM && MCA_LEGACY
- help
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called 3c523.
-
-config ELMC_II
- tristate "3c527 \"EtherLink/MC 32\" support (EXPERIMENTAL)"
- depends on NET_VENDOR_3COM && MCA && MCA_LEGACY
- help
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called 3c527.
-
-config VORTEX
- tristate "3c590/3c900 series (592/595/597) \"Vortex/Boomerang\" support"
- depends on NET_VENDOR_3COM && (PCI || EISA)
- select MII
- ---help---
- This option enables driver support for a large number of 10Mbps and
- 10/100Mbps EISA, PCI and PCMCIA 3Com network cards:
-
- "Vortex" (Fast EtherLink 3c590/3c592/3c595/3c597) EISA and PCI
- "Boomerang" (EtherLink XL 3c900 or 3c905) PCI
- "Cyclone" (3c540/3c900/3c905/3c980/3c575/3c656) PCI and Cardbus
- "Tornado" (3c905) PCI
- "Hurricane" (3c555/3cSOHO) PCI
-
- If you have such a card, say Y and read the Ethernet-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>. More
- specific information is in
- <file:Documentation/networking/vortex.txt> and in the comments at
- the beginning of <file:drivers/net/3c59x.c>.
-
- To compile this support as a module, choose M here.
-
-config TYPHOON
- tristate "3cr990 series \"Typhoon\" support"
- depends on NET_VENDOR_3COM && PCI
- select CRC32
- ---help---
- This option enables driver support for the 3cr990 series of cards:
-
- 3C990-TX, 3CR990-TX-95, 3CR990-TX-97, 3CR990-FX-95, 3CR990-FX-97,
- 3CR990SVR, 3CR990SVR95, 3CR990SVR97, 3CR990-FX-95 Server,
- 3CR990-FX-97 Server, 3C990B-TX-M, 3C990BSVR
-
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called typhoon.
-
-config LANCE
- tristate "AMD LANCE and PCnet (AT1500 and NE2100) support"
- depends on ISA && ISA_DMA_API
- help
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. Some LinkSys cards are
- of this type.
-
- To compile this driver as a module, choose M here: the module
- will be called lance. This is recommended.
-
-config NET_VENDOR_SMC
- bool "Western Digital/SMC cards"
- depends on ISA || MCA || EISA || MAC
- help
- If you have a network (Ethernet) card belonging to this class, say Y
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- Note that the answer to this question doesn't directly affect the
- kernel: saying N will just cause the configurator to skip all
- the questions about Western Digital cards. If you say Y, you will be
- asked for your specific card in the following questions.
-
-config WD80x3
- tristate "WD80*3 support"
- depends on NET_VENDOR_SMC && ISA
- select CRC32
- help
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called wd.
-
-config ULTRAMCA
- tristate "SMC Ultra MCA support"
- depends on NET_VENDOR_SMC && MCA
- select CRC32
- help
- If you have a network (Ethernet) card of this type and are running
- an MCA based system (PS/2), say Y and read the Ethernet-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called smc-mca.
-
-config ULTRA
- tristate "SMC Ultra support"
- depends on NET_VENDOR_SMC && ISA
- select CRC32
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- Important: There have been many reports that, with some motherboards
- mixing an SMC Ultra and an Adaptec AHA154x SCSI card (or compatible,
- such as some BusLogic models) causes corruption problems with many
- operating systems. The Linux smc-ultra driver has a work-around for
- this but keep it in mind if you have such a SCSI card and have
- problems.
-
- To compile this driver as a module, choose M here. The module
- will be called smc-ultra.
-
-config ULTRA32
- tristate "SMC Ultra32 EISA support"
- depends on NET_VENDOR_SMC && EISA
- select CRC32
- help
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called smc-ultra32.
-
-config BFIN_MAC
- tristate "Blackfin on-chip MAC support"
- depends on NET_ETHERNET && (BF516 || BF518 || BF526 || BF527 || BF536 || BF537)
- select CRC32
- select MII
- select PHYLIB
- select BFIN_MAC_USE_L1 if DMA_UNCACHED_NONE
- help
- This is the driver for Blackfin on-chip mac device. Say Y if you want it
- compiled into the kernel. This driver is also available as a module
- ( = code which can be inserted in and removed from the running kernel
- whenever you want). The module will be called bfin_mac.
-
-config BFIN_MAC_USE_L1
- bool "Use L1 memory for rx/tx packets"
- depends on BFIN_MAC && (BF527 || BF537)
- default y
- help
- To get maximum network performance, you should use L1 memory as rx/tx buffers.
- Say N here if you want to reserve L1 memory for other uses.
-
-config BFIN_TX_DESC_NUM
- int "Number of transmit buffer packets"
- depends on BFIN_MAC
- range 6 10 if BFIN_MAC_USE_L1
- range 10 100
- default "10"
- help
- Set the number of buffer packets used in driver.
-
-config BFIN_RX_DESC_NUM
- int "Number of receive buffer packets"
- depends on BFIN_MAC
- range 20 100 if BFIN_MAC_USE_L1
- range 20 800
- default "20"
- help
- Set the number of buffer packets used in driver.
-
-config BFIN_MAC_USE_HWSTAMP
- bool "Use IEEE 1588 hwstamp"
- depends on BFIN_MAC && BF518
- default y
- help
- To support the IEEE 1588 Precision Time Protocol (PTP), select y here
-
-config SMC9194
- tristate "SMC 9194 support"
- depends on NET_VENDOR_SMC && (ISA || MAC && BROKEN)
- select CRC32
- ---help---
- This is support for the SMC9xxx based Ethernet cards. Choose this
- option if you have a DELL laptop with the docking station, or
- another SMC9192/9194 based chipset. Say Y if you want it compiled
- into the kernel, and read the file
- <file:Documentation/networking/smc9.txt> and the Ethernet-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called smc9194.
-
-config SMC91X
- tristate "SMC 91C9x/91C1xxx support"
- select CRC32
- select MII
- depends on ARM || M32R || SUPERH || \
- MIPS || BLACKFIN || MN10300 || COLDFIRE
- help
- This is a driver for SMC's 91x series of Ethernet chipsets,
- including the SMC91C94 and the SMC91C111. Say Y if you want it
- compiled into the kernel, and read the file
- <file:Documentation/networking/smc9.txt> and the Ethernet-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called smc91x. If you want to compile it as a
- module, say M here and read <file:Documentation/kbuild/modules.txt>.
-
-config PXA168_ETH
- tristate "Marvell pxa168 ethernet support"
- depends on CPU_PXA168
- select PHYLIB
- help
- This driver supports the pxa168 Ethernet ports.
-
- To compile this driver as a module, choose M here. The module
- will be called pxa168_eth.
-
-config NET_NETX
- tristate "NetX Ethernet support"
- select MII
- depends on ARCH_NETX
- help
- This is support for the Hilscher netX builtin Ethernet ports
-
- To compile this driver as a module, choose M here. The module
- will be called netx-eth.
-
-config TI_DAVINCI_EMAC
- tristate "TI DaVinci EMAC Support"
- depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 )
- select TI_DAVINCI_MDIO
- select TI_DAVINCI_CPDMA
- select PHYLIB
- help
- This driver supports TI's DaVinci Ethernet .
-
- To compile this driver as a module, choose M here: the module
- will be called davinci_emac_driver. This is recommended.
-
-config TI_DAVINCI_MDIO
- tristate "TI DaVinci MDIO Support"
- depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 )
- select PHYLIB
- help
- This driver supports TI's DaVinci MDIO module.
-
- To compile this driver as a module, choose M here: the module
- will be called davinci_mdio. This is recommended.
-
-config TI_DAVINCI_CPDMA
- tristate "TI DaVinci CPDMA Support"
- depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 )
- help
- This driver supports TI's DaVinci CPDMA dma engine.
-
- To compile this driver as a module, choose M here: the module
- will be called davinci_cpdma. This is recommended.
-
-config DM9000
- tristate "DM9000 support"
- depends on ARM || BLACKFIN || MIPS
- select CRC32
- select MII
- ---help---
- Support for DM9000 chipset.
-
- To compile this driver as a module, choose M here. The module
- will be called dm9000.
-
-config DM9000_DEBUGLEVEL
- int "DM9000 maximum debug level"
- depends on DM9000
- default 4
- help
- The maximum level of debugging code compiled into the DM9000
- driver.
-
-config DM9000_FORCE_SIMPLE_PHY_POLL
- bool "Force simple NSR based PHY polling"
- depends on DM9000
- ---help---
- This configuration forces the DM9000 to use the NSR's LinkStatus
- bit to determine if the link is up or down instead of the more
- costly MII PHY reads. Note, this will not work if the chip is
- operating with an external PHY.
-
-config ENC28J60
- tristate "ENC28J60 support"
- depends on EXPERIMENTAL && SPI && NET_ETHERNET
- select CRC32
- ---help---
- Support for the Microchip EN28J60 ethernet chip.
-
- To compile this driver as a module, choose M here. The module will be
- called enc28j60.
-
-config ENC28J60_WRITEVERIFY
- bool "Enable write verify"
- depends on ENC28J60
- ---help---
- Enable the verify after the buffer write useful for debugging purpose.
- If unsure, say N.
-
-config ETHOC
- tristate "OpenCores 10/100 Mbps Ethernet MAC support"
- depends on NET_ETHERNET && HAS_IOMEM && HAS_DMA
- select MII
- select PHYLIB
- select CRC32
- select BITREVERSE
- help
- Say Y here if you want to use the OpenCores 10/100 Mbps Ethernet MAC.
-
-config GRETH
- tristate "Aeroflex Gaisler GRETH Ethernet MAC support"
- depends on SPARC
- select PHYLIB
- select CRC32
- help
- Say Y here if you want to use the Aeroflex Gaisler GRETH Ethernet MAC.
-
-config SMC911X
- tristate "SMSC LAN911[5678] support"
- select CRC32
- select MII
- depends on ARM || SUPERH || MN10300
- help
- This is a driver for SMSC's LAN911x series of Ethernet chipsets
- including the new LAN9115, LAN9116, LAN9117, and LAN9118.
- Say Y if you want it compiled into the kernel,
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- This driver is also available as a module. The module will be
- called smc911x. If you want to compile it as a module, say M
- here and read <file:Documentation/kbuild/modules.txt>
-
-config SMSC911X
- tristate "SMSC LAN911x/LAN921x families embedded ethernet support"
- depends on ARM || SUPERH || BLACKFIN || MIPS || MN10300
- select CRC32
- select MII
- select PHYLIB
- ---help---
- Say Y here if you want support for SMSC LAN911x and LAN921x families
- of ethernet controllers.
-
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
- will be called smsc911x.
-
-config SMSC911X_ARCH_HOOKS
- def_bool n
- depends on SMSC911X
- help
- If the arch enables this, it allows the arch to implement various
- hooks for more comprehensive interrupt control and also to override
- the source of the MAC address.
-
-config NET_VENDOR_RACAL
- bool "Racal-Interlan (Micom) NI cards"
- depends on ISA
- help
- If you have a network (Ethernet) card belonging to this class, such
- as the NI5010, NI5210 or NI6210, say Y and read the Ethernet-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>.
-
- Note that the answer to this question doesn't directly affect the
- kernel: saying N will just cause the configurator to skip all
- the questions about NI cards. If you say Y, you will be asked for
- your specific card in the following questions.
-
-config NI5010
- tristate "NI5010 support (EXPERIMENTAL)"
- depends on NET_VENDOR_RACAL && ISA && EXPERIMENTAL && BROKEN_ON_SMP
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. Note that this is still
- experimental code.
-
- To compile this driver as a module, choose M here. The module
- will be called ni5010.
-
-config NI52
- tristate "NI5210 support"
- depends on NET_VENDOR_RACAL && ISA
- help
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called ni52.
-
-config NI65
- tristate "NI6510 support"
- depends on NET_VENDOR_RACAL && ISA && ISA_DMA_API
- help
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called ni65.
-
-config DNET
- tristate "Dave ethernet support (DNET)"
- depends on NET_ETHERNET && HAS_IOMEM
- select PHYLIB
- help
- The Dave ethernet interface (DNET) is found on Qong Board FPGA.
- Say Y to include support for the DNET chip.
-
- To compile this driver as a module, choose M here: the module
- will be called dnet.
-
-source "drivers/net/tulip/Kconfig"
-
-config AT1700
- tristate "AT1700/1720 support (EXPERIMENTAL)"
- depends on (ISA || MCA_LEGACY) && EXPERIMENTAL
- select CRC32
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called at1700.
-
-config DEPCA
- tristate "DEPCA, DE10x, DE200, DE201, DE202, DE422 support"
- depends on ISA || EISA || MCA
- select CRC32
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto> as well as
- <file:drivers/net/depca.c>.
-
- To compile this driver as a module, choose M here. The module
- will be called depca.
-
-config HP100
- tristate "HP 10/100VG PCLAN (ISA, EISA, PCI) support"
- depends on ISA || EISA || PCI
- help
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called hp100.
-
-config NET_ISA
- bool "Other ISA cards"
- depends on ISA
- ---help---
- If your network (Ethernet) card hasn't been mentioned yet and its
- bus system (that's the way the cards talks to the other components
- of your computer) is ISA (as opposed to EISA, VLB or PCI), say Y.
- Make sure you know the name of your card. Read the Ethernet-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>.
-
- If unsure, say Y.
-
- Note that the answer to this question doesn't directly affect the
- kernel: saying N will just cause the configurator to skip all
- the remaining ISA network card questions. If you say Y, you will be
- asked for your specific card in the following questions.
-
-config E2100
- tristate "Cabletron E21xx support"
- depends on NET_ISA
- select CRC32
- help
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called e2100.
-
-config EWRK3
- tristate "EtherWORKS 3 (DE203, DE204, DE205) support"
- depends on NET_ISA
- select CRC32
- ---help---
- This driver supports the DE203, DE204 and DE205 network (Ethernet)
- cards. If this is for you, say Y and read
- <file:Documentation/networking/ewrk3.txt> in the kernel source as
- well as the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called ewrk3.
-
-config EEXPRESS
- tristate "EtherExpress 16 support"
- depends on NET_ISA
- ---help---
- If you have an EtherExpress16 network (Ethernet) card, say Y and
- read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. Note that the Intel
- EtherExpress16 card used to be regarded as a very poor choice
- because the driver was very unreliable. We now have a new driver
- that should do better.
-
- To compile this driver as a module, choose M here. The module
- will be called eexpress.
-
-config EEXPRESS_PRO
- tristate "EtherExpressPro support/EtherExpress 10 (i82595) support"
- depends on NET_ISA
- ---help---
- If you have a network (Ethernet) card of this type, say Y. This
- driver supports Intel i82595{FX,TX} based boards. Note however
- that the EtherExpress PRO/100 Ethernet card has its own separate
- driver. Please read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called eepro.
-
-config HPLAN_PLUS
- tristate "HP PCLAN+ (27247B and 27252A) support"
- depends on NET_ISA
- select CRC32
- help
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called hp-plus.
-
-config HPLAN
- tristate "HP PCLAN (27245 and other 27xxx series) support"
- depends on NET_ISA
- select CRC32
- help
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called hp.
-
-config LP486E
- tristate "LP486E on board Ethernet"
- depends on NET_ISA
- help
- Say Y here to support the 82596-based on-board Ethernet controller
- for the Panther motherboard, which is one of the two shipped in the
- Intel Professional Workstation.
-
-config ETH16I
- tristate "ICL EtherTeam 16i/32 support"
- depends on NET_ISA
- help
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called eth16i.
-
-config NE2000
- tristate "NE2000/NE1000 support"
- depends on NET_ISA || (Q40 && m) || M32R || MACH_TX49XX
- select CRC32
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. Many Ethernet cards
- without a specific driver are compatible with NE2000.
-
- If you have a PCI NE2000 card however, say N here and Y to "PCI
- NE2000 and clone support" under "EISA, VLB, PCI and on board
- controllers" below. If you have a NE2000 card and are running on
- an MCA system (a bus system used on some IBM PS/2 computers and
- laptops), say N here and Y to "NE/2 (ne2000 MCA version) support",
- below.
-
- To compile this driver as a module, choose M here. The module
- will be called ne.
-
-config ZNET
- tristate "Zenith Z-Note support (EXPERIMENTAL)"
- depends on NET_ISA && EXPERIMENTAL && ISA_DMA_API
- help
- The Zenith Z-Note notebook computer has a built-in network
- (Ethernet) card, and this is the Linux driver for it. Note that the
- IBM Thinkpad 300 is compatible with the Z-Note and is also supported
- by this driver. Read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
-config SEEQ8005
- tristate "SEEQ8005 support (EXPERIMENTAL)"
- depends on NET_ISA && EXPERIMENTAL
- help
- This is a driver for the SEEQ 8005 network (Ethernet) card. If this
- is for you, read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called seeq8005.
-
-config NE2_MCA
- tristate "NE/2 (ne2000 MCA version) support"
- depends on MCA_LEGACY
- select CRC32
- help
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called ne2.
-
-config IBMLANA
- tristate "IBM LAN Adapter/A support"
- depends on MCA
- ---help---
- This is a Micro Channel Ethernet adapter. You need to set
- CONFIG_MCA to use this driver. It is both available as an in-kernel
- driver and as a module.
-
- To compile this driver as a module, choose M here. The only
- currently supported card is the IBM LAN Adapter/A for Ethernet. It
- will both support 16K and 32K memory windows, however a 32K window
- gives a better security against packet losses. Usage of multiple
- boards with this driver should be possible, but has not been tested
- up to now due to lack of hardware.
-
-config IBMVETH
- tristate "IBM LAN Virtual Ethernet support"
- depends on PPC_PSERIES
- ---help---
- This driver supports virtual ethernet adapters on newer IBM iSeries
- and pSeries systems.
-
- To compile this driver as a module, choose M here. The module will
- be called ibmveth.
-
-source "drivers/net/ibm_newemac/Kconfig"
-
-config NET_PCI
- bool "EISA, VLB, PCI and on board controllers"
- depends on ISA || EISA || PCI
- help
- This is another class of network cards which attach directly to the
- bus. If you have one of those, say Y and read the Ethernet-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>.
-
- Note that the answer to this question doesn't directly affect the
- kernel: saying N will just cause the configurator to skip all
- the questions about this class of network cards. If you say Y, you
- will be asked for your specific card in the following questions. If
- you are unsure, say Y.
-
-config PCNET32
- tristate "AMD PCnet32 PCI support"
- depends on NET_PCI && PCI
- select CRC32
- select MII
- help
- If you have a PCnet32 or PCnetPCI based network (Ethernet) card,
- answer Y here and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called pcnet32.
-
-config AMD8111_ETH
- tristate "AMD 8111 (new PCI lance) support"
- depends on NET_PCI && PCI
- select CRC32
- select MII
- help
- If you have an AMD 8111-based PCI lance ethernet card,
- answer Y here and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called amd8111e.
-
-config ADAPTEC_STARFIRE
- tristate "Adaptec Starfire/DuraLAN support"
- depends on NET_PCI && PCI
- select CRC32
- select MII
- help
- Say Y here if you have an Adaptec Starfire (or DuraLAN) PCI network
- adapter. The DuraLAN chip is used on the 64 bit PCI boards from
- Adaptec e.g. the ANA-6922A. The older 32 bit boards use the tulip
- driver.
-
- To compile this driver as a module, choose M here: the module
- will be called starfire. This is recommended.
-
-config AC3200
- tristate "Ansel Communications EISA 3200 support (EXPERIMENTAL)"
- depends on NET_PCI && (ISA || EISA) && EXPERIMENTAL
- select CRC32
- help
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called ac3200.
-
-config KSZ884X_PCI
- tristate "Micrel KSZ8841/2 PCI"
- depends on NET_PCI && PCI
- select MII
- select CRC32
- help
- This PCI driver is for Micrel KSZ8841/KSZ8842 PCI Ethernet chip.
-
- To compile this driver as a module, choose M here. The module
- will be called ksz884x.
-
-config APRICOT
- tristate "Apricot Xen-II on board Ethernet"
- depends on NET_PCI && ISA
- help
- If you have a network (Ethernet) controller of this type, say Y and
- read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called apricot.
-
-config B44
- tristate "Broadcom 440x/47xx ethernet support"
- depends on SSB_POSSIBLE && HAS_DMA
- select SSB
- select MII
- help
- If you have a network (Ethernet) controller of this type, say Y
- or M and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called b44.
-
-# Auto-select SSB PCI-HOST support, if possible
-config B44_PCI_AUTOSELECT
- bool
- depends on B44 && SSB_PCIHOST_POSSIBLE
- select SSB_PCIHOST
- default y
-
-# Auto-select SSB PCICORE driver, if possible
-config B44_PCICORE_AUTOSELECT
- bool
- depends on B44 && SSB_DRIVER_PCICORE_POSSIBLE
- select SSB_DRIVER_PCICORE
- default y
-
-config B44_PCI
- bool
- depends on B44_PCI_AUTOSELECT && B44_PCICORE_AUTOSELECT
- default y
-
-config FORCEDETH
- tristate "nForce Ethernet support"
- depends on NET_PCI && PCI
- help
- If you have a network (Ethernet) controller of this type, say Y and
- read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called forcedeth.
-
-config CS89x0
- tristate "CS89x0 support"
- depends on NET_ETHERNET && (ISA || EISA || MACH_IXDP2351 \
- || ARCH_IXDP2X01 || MACH_MX31ADS || MACH_QQ2440)
- ---help---
- Support for CS89x0 chipset based Ethernet cards. If you have a
- network (Ethernet) card of this type, say Y and read the
- Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto> as well as
- <file:Documentation/networking/cs89x0.txt>.
-
- To compile this driver as a module, choose M here. The module
- will be called cs89x0.
-
-config CS89x0_NONISA_IRQ
- def_bool y
- depends on CS89x0 != n
- depends on MACH_IXDP2351 || ARCH_IXDP2X01 || MACH_MX31ADS || MACH_QQ2440
-
-config TC35815
- tristate "TOSHIBA TC35815 Ethernet support"
- depends on NET_PCI && PCI && MIPS
- select PHYLIB
-
-config E100
- tristate "Intel(R) PRO/100+ support"
- depends on NET_PCI && PCI
- select MII
- ---help---
- This driver supports Intel(R) PRO/100 family of adapters.
- To verify that your adapter is supported, find the board ID number
- on the adapter. Look for a label that has a barcode and a number
- in the format 123456-001 (six digits hyphen three digits).
-
- Use the above information and the Adapter & Driver ID Guide at:
-
- <http://support.intel.com/support/network/adapter/pro100/21397.htm>
-
- to identify the adapter.
-
- For the latest Intel PRO/100 network driver for Linux, see:
-
- <http://www.intel.com/p/en_US/support/highlights/network/pro100plus>
-
- More specific information on configuring the driver is in
- <file:Documentation/networking/e100.txt>.
-
- To compile this driver as a module, choose M here. The module
- will be called e100.
-
-config LNE390
- tristate "Mylex EISA LNE390A/B support (EXPERIMENTAL)"
- depends on NET_PCI && EISA && EXPERIMENTAL
- select CRC32
- help
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called lne390.
-
-config FEALNX
- tristate "Myson MTD-8xx PCI Ethernet support"
- depends on NET_PCI && PCI
- select CRC32
- select MII
- help
- Say Y here to support the Myson MTD-800 family of PCI-based Ethernet
- cards. <http://www.myson.com.tw/>
-
-config NATSEMI
- tristate "National Semiconductor DP8381x series PCI Ethernet support"
- depends on NET_PCI && PCI
- select CRC32
- help
- This driver is for the National Semiconductor DP83810 series,
- which is used in cards from PureData, NetGear, Linksys
- and others, including the 83815 chip.
- More specific information and updates are available from
- <http://www.scyld.com/network/natsemi.html>.
-
-config NE2K_PCI
- tristate "PCI NE2000 and clones support (see help)"
- depends on NET_PCI && PCI
- select CRC32
- ---help---
- This driver is for NE2000 compatible PCI cards. It will not work
- with ISA NE2000 cards (they have their own driver, "NE2000/NE1000
- support" below). If you have a PCI NE2000 network (Ethernet) card,
- say Y and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- This driver also works for the following NE2000 clone cards:
- RealTek RTL-8029 Winbond 89C940 Compex RL2000 KTI ET32P2
- NetVin NV5000SC Via 86C926 SureCom NE34 Winbond
- Holtek HT80232 Holtek HT80229
-
- To compile this driver as a module, choose M here. The module
- will be called ne2k-pci.
-
-config NE3210
- tristate "Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)"
- depends on NET_PCI && EISA && EXPERIMENTAL
- select CRC32
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. Note that this driver
- will NOT WORK for NE3200 cards as they are completely different.
-
- To compile this driver as a module, choose M here. The module
- will be called ne3210.
-
-config ES3210
- tristate "Racal-Interlan EISA ES3210 support (EXPERIMENTAL)"
- depends on NET_PCI && EISA && EXPERIMENTAL
- select CRC32
- help
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called es3210.
-
-config 8139CP
- tristate "RealTek RTL-8139 C+ PCI Fast Ethernet Adapter support (EXPERIMENTAL)"
- depends on NET_PCI && PCI && EXPERIMENTAL
- select CRC32
- select MII
- help
- This is a driver for the Fast Ethernet PCI network cards based on
- the RTL8139C+ chips. If you have one of those, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here: the module
- will be called 8139cp. This is recommended.
-
-config 8139TOO
- tristate "RealTek RTL-8129/8130/8139 PCI Fast Ethernet Adapter support"
- depends on NET_PCI && PCI
- select CRC32
- select MII
- ---help---
- This is a driver for the Fast Ethernet PCI network cards based on
- the RTL 8129/8130/8139 chips. If you have one of those, say Y and
- read the Ethernet-HOWTO <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here: the module
- will be called 8139too. This is recommended.
-
-config 8139TOO_PIO
- bool "Use PIO instead of MMIO"
- default y
- depends on 8139TOO
- help
- This instructs the driver to use programmed I/O ports (PIO) instead
- of PCI shared memory (MMIO). This can possibly solve some problems
- in case your mainboard has memory consistency issues. If unsure,
- say N.
-
-config 8139TOO_TUNE_TWISTER
- bool "Support for uncommon RTL-8139 rev. K (automatic channel equalization)"
- depends on 8139TOO
- help
- This implements a function which might come in handy in case you
- are using low quality on long cabling. It is required for RealTek
- RTL-8139 revision K boards, and totally unused otherwise. It tries
- to match the transceiver to the cable characteristics. This is
- experimental since hardly documented by the manufacturer.
- If unsure, say Y.
-
-config 8139TOO_8129
- bool "Support for older RTL-8129/8130 boards"
- depends on 8139TOO
- help
- This enables support for the older and uncommon RTL-8129 and
- RTL-8130 chips, which support MII via an external transceiver,
- instead of an internal one. Disabling this option will save some
- memory by making the code size smaller. If unsure, say Y.
-
-config 8139_OLD_RX_RESET
- bool "Use older RX-reset method"
- depends on 8139TOO
- help
- The 8139too driver was recently updated to contain a more rapid
- reset sequence, in the face of severe receive errors. This "new"
- RX-reset method should be adequate for all boards. But if you
- experience problems, you can enable this option to restore the
- old RX-reset behavior. If unsure, say N.
-
-config R6040
- tristate "RDC R6040 Fast Ethernet Adapter support"
- depends on NET_PCI && PCI
- select CRC32
- select MII
- select PHYLIB
- help
- This is a driver for the R6040 Fast Ethernet MACs found in the
- the RDC R-321x System-on-chips.
-
- To compile this driver as a module, choose M here: the module
- will be called r6040. This is recommended.
-
-config SIS900
- tristate "SiS 900/7016 PCI Fast Ethernet Adapter support"
- depends on NET_PCI && PCI
- select CRC32
- select MII
- ---help---
- This is a driver for the Fast Ethernet PCI network cards based on
- the SiS 900 and SiS 7016 chips. The SiS 900 core is also embedded in
- SiS 630 and SiS 540 chipsets.
-
- This driver also supports AMD 79C901 HomePNA so that you can use
- your phone line as a network cable.
-
- To compile this driver as a module, choose M here: the module
- will be called sis900. This is recommended.
-
-config EPIC100
- tristate "SMC EtherPower II"
- depends on NET_PCI && PCI
- select CRC32
- select MII
- help
- This driver is for the SMC EtherPower II 9432 PCI Ethernet NIC,
- which is based on the SMC83c17x (EPIC/100).
- More specific information and updates are available from
- <http://www.scyld.com/network/epic100.html>.
-
-config SMSC9420
- tristate "SMSC LAN9420 PCI ethernet adapter support"
- depends on NET_PCI && PCI
- select CRC32
- select PHYLIB
- select SMSC_PHY
- help
- This is a driver for SMSC's LAN9420 PCI ethernet adapter.
- Say Y if you want it compiled into the kernel,
- and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- This driver is also available as a module. The module will be
- called smsc9420. If you want to compile it as a module, say M
- here and read <file:Documentation/kbuild/modules.txt>
-
-config SUNDANCE
- tristate "Sundance Alta support"
- depends on NET_PCI && PCI
- select CRC32
- select MII
- help
- This driver is for the Sundance "Alta" chip.
- More specific information and updates are available from
- <http://www.scyld.com/network/sundance.html>.
-
-config SUNDANCE_MMIO
- bool "Use MMIO instead of PIO"
- depends on SUNDANCE
- help
- Enable memory-mapped I/O for interaction with Sundance NIC registers.
- Do NOT enable this by default, PIO (enabled when MMIO is disabled)
- is known to solve bugs on certain chips.
-
- If unsure, say N.
-
-config TLAN
- tristate "TI ThunderLAN support"
- depends on NET_PCI && (PCI || EISA)
- ---help---
- If you have a PCI Ethernet network card based on the ThunderLAN chip
- which is supported by this driver, say Y and read the
- Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- Devices currently supported by this driver are Compaq Netelligent,
- Compaq NetFlex and Olicom cards. Please read the file
- <file:Documentation/networking/tlan.txt> for more details.
-
- To compile this driver as a module, choose M here. The module
- will be called tlan.
-
- Please email feedback to <torben.mathiasen@compaq.com>.
-
-config KS8842
- tristate "Micrel KSZ8841/42 with generic bus interface"
- depends on HAS_IOMEM && DMA_ENGINE
- help
- This platform driver is for KSZ8841(1-port) / KS8842(2-port)
- ethernet switch chip (managed, VLAN, QoS) from Micrel or
- Timberdale(FPGA).
-
-config KS8851
- tristate "Micrel KS8851 SPI"
- depends on SPI
- select MII
- select CRC32
- help
- SPI driver for Micrel KS8851 SPI attached network chip.
-
-config KS8851_MLL
- tristate "Micrel KS8851 MLL"
- depends on HAS_IOMEM
- select MII
- help
- This platform driver is for Micrel KS8851 Address/data bus
- multiplexed network chip.
-
-config VIA_RHINE
- tristate "VIA Rhine support"
- depends on NET_PCI && PCI
- select CRC32
- select MII
- help
- If you have a VIA "Rhine" based network card (Rhine-I (VT86C100A),
- Rhine-II (VT6102), or Rhine-III (VT6105)), say Y here. Rhine-type
- Ethernet functions can also be found integrated on South Bridges
- (e.g. VT8235).
-
- To compile this driver as a module, choose M here. The module
- will be called via-rhine.
-
-config VIA_RHINE_MMIO
- bool "Use MMIO instead of PIO"
- depends on VIA_RHINE
- help
- This instructs the driver to use PCI shared memory (MMIO) instead of
- programmed I/O ports (PIO). Enabling this gives an improvement in
- processing time in parts of the driver.
-
- If unsure, say Y.
-
-config SC92031
- tristate "Silan SC92031 PCI Fast Ethernet Adapter driver (EXPERIMENTAL)"
- depends on NET_PCI && PCI && EXPERIMENTAL
- select CRC32
- ---help---
- This is a driver for the Fast Ethernet PCI network cards based on
- the Silan SC92031 chip (sometimes also called Rsltek 8139D). If you
- have one of these, say Y here.
-
- To compile this driver as a module, choose M here: the module
- will be called sc92031. This is recommended.
-
-config CPMAC
- tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)"
- depends on NET_ETHERNET && EXPERIMENTAL && AR7
- select PHYLIB
- help
- TI AR7 CPMAC Ethernet support
-
-config NET_POCKET
- bool "Pocket and portable adapters"
- depends on PARPORT
- ---help---
- Cute little network (Ethernet) devices which attach to the parallel
- port ("pocket adapters"), commonly used with laptops. If you have
- one of those, say Y and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- If you want to plug a network (or some other) card into the PCMCIA
- (or PC-card) slot of your laptop instead (PCMCIA is the standard for
- credit card size extension cards used by all modern laptops), you
- need the pcmcia-cs package (location contained in the file
- <file:Documentation/Changes>) and you can say N here.
-
- Laptop users should read the Linux Laptop home page at
- <http://www.linux-on-laptops.com/> or
- Tuxmobil - Linux on Mobile Computers at <http://www.tuxmobil.org/>.
-
- Note that the answer to this question doesn't directly affect the
- kernel: saying N will just cause the configurator to skip all
- the questions about this class of network devices. If you say Y, you
- will be asked for your specific device in the following questions.
-
-config ATP
- tristate "AT-LAN-TEC/RealTek pocket adapter support"
- depends on NET_POCKET && PARPORT && X86
- select CRC32
- ---help---
- This is a network (Ethernet) device which attaches to your parallel
- port. Read <file:drivers/net/atp.c> as well as the Ethernet-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>, if you
- want to use this. If you intend to use this driver, you should have
- said N to the "Parallel printer support", because the two drivers
- don't like each other.
-
- To compile this driver as a module, choose M here: the module
- will be called atp.
-
-config DE600
- tristate "D-Link DE600 pocket adapter support"
- depends on NET_POCKET && PARPORT
- ---help---
- This is a network (Ethernet) device which attaches to your parallel
- port. Read <file:Documentation/networking/DLINK.txt> as well as the
- Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>, if you want to use
- this. It is possible to have several devices share a single parallel
- port and it is safe to compile the corresponding drivers into the
- kernel.
-
- To compile this driver as a module, choose M here: the module
- will be called de600.
-
-config DE620
- tristate "D-Link DE620 pocket adapter support"
- depends on NET_POCKET && PARPORT
- ---help---
- This is a network (Ethernet) device which attaches to your parallel
- port. Read <file:Documentation/networking/DLINK.txt> as well as the
- Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>, if you want to use
- this. It is possible to have several devices share a single parallel
- port and it is safe to compile the corresponding drivers into the
- kernel.
-
- To compile this driver as a module, choose M here: the module
- will be called de620.
-
-config SGISEEQ
- tristate "SGI Seeq ethernet controller support"
- depends on SGI_HAS_SEEQ
- help
- Say Y here if you have an Seeq based Ethernet network card. This is
- used in many Silicon Graphics machines.
-
-config DECLANCE
- tristate "DEC LANCE ethernet controller support"
- depends on MACH_DECSTATION
- select CRC32
- help
- This driver is for the series of Ethernet controllers produced by
- DEC (now Compaq) based on the AMD Lance chipset, including the
- DEPCA series. (This chipset is better known via the NE2100 cards.)
-
-config FEC
- bool "FEC ethernet controller (of ColdFire and some i.MX CPUs)"
- depends on M523x || M527x || M5272 || M528x || M520x || M532x || \
- IMX_HAVE_PLATFORM_FEC || MXS_HAVE_PLATFORM_FEC
- default IMX_HAVE_PLATFORM_FEC || MXS_HAVE_PLATFORM_FEC if ARM
- select PHYLIB
- help
- Say Y here if you want to use the built-in 10/100 Fast ethernet
- controller on some Motorola ColdFire and Freescale i.MX processors.
-
-config FEC_MPC52xx
- tristate "MPC52xx FEC driver"
- depends on PPC_MPC52xx && PPC_BESTCOMM
- select CRC32
- select PHYLIB
- select PPC_BESTCOMM_FEC
- ---help---
- This option enables support for the MPC5200's on-chip
- Fast Ethernet Controller
- If compiled as module, it will be called fec_mpc52xx.
-
-config FEC_MPC52xx_MDIO
- bool "MPC52xx FEC MDIO bus driver"
- depends on FEC_MPC52xx
- default y
- ---help---
- The MPC5200's FEC can connect to the Ethernet either with
- an external MII PHY chip or 10 Mbps 7-wire interface
- (Motorola? industry standard).
- If your board uses an external PHY connected to FEC, enable this.
- If not sure, enable.
- If compiled as module, it will be called fec_mpc52xx_phy.
-
-config NE_H8300
- tristate "NE2000 compatible support for H8/300"
- depends on H8300
- help
- Say Y here if you want to use the NE2000 compatible
- controller on the Renesas H8/300 processor.
-
-config ATL2
- tristate "Atheros L2 Fast Ethernet support"
- depends on PCI
- select CRC32
- select MII
- help
- This driver supports the Atheros L2 fast ethernet adapter.
-
- To compile this driver as a module, choose M here. The module
- will be called atl2.
-
-config XILINX_EMACLITE
- tristate "Xilinx 10/100 Ethernet Lite support"
- depends on PPC32 || MICROBLAZE
- select PHYLIB
- help
- This driver supports the 10/100 Ethernet Lite from Xilinx.
-
-config BCM63XX_ENET
- tristate "Broadcom 63xx internal mac support"
- depends on BCM63XX
- select MII
- select PHYLIB
- help
- This driver supports the ethernet MACs in the Broadcom 63xx
- MIPS chipset family (BCM63XX).
-
-config FTMAC100
- tristate "Faraday FTMAC100 10/100 Ethernet support"
- depends on ARM
- select MII
- help
- This driver supports the FTMAC100 10/100 Ethernet controller
- from Faraday. It is used on Faraday A320, Andes AG101 and some
- other ARM/NDS32 SoC's.
-
-config LANTIQ_ETOP
- tristate "Lantiq SoC ETOP driver"
- depends on SOC_TYPE_XWAY
- help
- Support for the MII0 inside the Lantiq SoC
-
-
-source "drivers/net/fs_enet/Kconfig"
-
-source "drivers/net/octeon/Kconfig"
-
-endif # NET_ETHERNET
-
-#
-# Gigabit Ethernet
-#
-
-menuconfig NETDEV_1000
- bool "Ethernet (1000 Mbit)"
- depends on !UML
- default y
- ---help---
- Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common
- type of Local Area Network (LAN) in universities and companies.
-
- Say Y here to get to see options for Gigabit Ethernet drivers.
- This option alone does not add any kernel code.
- Note that drivers supporting both 100 and 1000 MBit may be listed
- under "Ethernet (10 or 100MBit)" instead.
-
- If you say N, all options in this submenu will be skipped and disabled.
-
-if NETDEV_1000
-
-config ACENIC
- tristate "Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support"
- depends on PCI
- ---help---
- Say Y here if you have an Alteon AceNIC, 3Com 3C985(B), NetGear
- GA620, SGI Gigabit or Farallon PN9000-SX PCI Gigabit Ethernet
- adapter. The driver allows for using the Jumbo Frame option (9000
- bytes/frame) however it requires that your switches can handle this
- as well. To enable Jumbo Frames, add `mtu 9000' to your ifconfig
- line.
-
- To compile this driver as a module, choose M here: the
- module will be called acenic.
-
-config ACENIC_OMIT_TIGON_I
- bool "Omit support for old Tigon I based AceNICs"
- depends on ACENIC
- help
- Say Y here if you only have Tigon II based AceNICs and want to leave
- out support for the older Tigon I based cards which are no longer
- being sold (ie. the original Alteon AceNIC and 3Com 3C985 (non B
- version)). This will reduce the size of the driver object by
- app. 100KB. If you are not sure whether your card is a Tigon I or a
- Tigon II, say N here.
-
- The safe and default value for this is N.
-
-config DL2K
- tristate "DL2000/TC902x-based Gigabit Ethernet support"
- depends on PCI
- select CRC32
- help
- This driver supports DL2000/TC902x-based Gigabit ethernet cards,
- which includes
- D-Link DGE-550T Gigabit Ethernet Adapter.
- D-Link DL2000-based Gigabit Ethernet Adapter.
- Sundance/Tamarack TC902x Gigabit Ethernet Adapter.
-
- To compile this driver as a module, choose M here: the
- module will be called dl2k.
-
-config E1000
- tristate "Intel(R) PRO/1000 Gigabit Ethernet support"
- depends on PCI
- ---help---
- This driver supports Intel(R) PRO/1000 gigabit ethernet family of
- adapters. For more information on how to identify your adapter, go
- to the Adapter & Driver ID Guide at:
-
- <http://support.intel.com/support/network/adapter/pro100/21397.htm>
-
- For general information and support, go to the Intel support
- website at:
-
- <http://support.intel.com>
-
- More specific information on configuring the driver is in
- <file:Documentation/networking/e1000.txt>.
-
- To compile this driver as a module, choose M here. The module
- will be called e1000.
-
-config E1000E
- tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support"
- depends on PCI && (!SPARC32 || BROKEN)
- select CRC32
- ---help---
- This driver supports the PCI-Express Intel(R) PRO/1000 gigabit
- ethernet family of adapters. For PCI or PCI-X e1000 adapters,
- use the regular e1000 driver For more information on how to
- identify your adapter, go to the Adapter & Driver ID Guide at:
-
- <http://support.intel.com/support/network/adapter/pro100/21397.htm>
-
- For general information and support, go to the Intel support
- website at:
-
- <http://support.intel.com>
-
- To compile this driver as a module, choose M here. The module
- will be called e1000e.
-
-config IP1000
- tristate "IP1000 Gigabit Ethernet support"
- depends on PCI && EXPERIMENTAL
- select MII
- ---help---
- This driver supports IP1000 gigabit Ethernet cards.
-
- To compile this driver as a module, choose M here: the module
- will be called ipg. This is recommended.
-
-config IGB
- tristate "Intel(R) 82575/82576 PCI-Express Gigabit Ethernet support"
- depends on PCI
- ---help---
- This driver supports Intel(R) 82575/82576 gigabit ethernet family of
- adapters. For more information on how to identify your adapter, go
- to the Adapter & Driver ID Guide at:
-
- <http://support.intel.com/support/network/adapter/pro100/21397.htm>
-
- For general information and support, go to the Intel support
- website at:
-
- <http://support.intel.com>
-
- More specific information on configuring the driver is in
- <file:Documentation/networking/e1000.txt>.
-
- To compile this driver as a module, choose M here. The module
- will be called igb.
-
-config IGB_DCA
- bool "Direct Cache Access (DCA) Support"
- default y
- depends on IGB && DCA && !(IGB=y && DCA=m)
- ---help---
- Say Y here if you want to use Direct Cache Access (DCA) in the
- driver. DCA is a method for warming the CPU cache before data
- is used, with the intent of lessening the impact of cache misses.
-
-config IGBVF
- tristate "Intel(R) 82576 Virtual Function Ethernet support"
- depends on PCI
- ---help---
- This driver supports Intel(R) 82576 virtual functions. For more
- information on how to identify your adapter, go to the Adapter &
- Driver ID Guide at:
-
- <http://support.intel.com/support/network/adapter/pro100/21397.htm>
-
- For general information and support, go to the Intel support
- website at:
-
- <http://support.intel.com>
-
- More specific information on configuring the driver is in
- <file:Documentation/networking/e1000.txt>.
-
- To compile this driver as a module, choose M here. The module
- will be called igbvf.
-
-source "drivers/net/ixp2000/Kconfig"
-
-config NS83820
- tristate "National Semiconductor DP83820 support"
- depends on PCI
- help
- This is a driver for the National Semiconductor DP83820 series
- of gigabit ethernet MACs. Cards using this chipset include
- the D-Link DGE-500T, PureData's PDP8023Z-TG, SMC's SMC9462TX,
- SOHO-GA2000T, SOHO-GA2500T. The driver supports the use of
- zero copy.
-
-config HAMACHI
- tristate "Packet Engines Hamachi GNIC-II support"
- depends on PCI
- select MII
- help
- If you have a Gigabit Ethernet card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module will be
- called hamachi.
-
-config YELLOWFIN
- tristate "Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL
- select CRC32
- ---help---
- Say Y here if you have a Packet Engines G-NIC PCI Gigabit Ethernet
- adapter or the SYM53C885 Ethernet controller. The Gigabit adapter is
- used by the Beowulf Linux cluster project. See
- <http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html> for more
- information about this driver in particular and Beowulf in general.
-
- To compile this driver as a module, choose M here: the module
- will be called yellowfin. This is recommended.
-
-config R8169
- tristate "Realtek 8169 gigabit ethernet support"
- depends on PCI
- select FW_LOADER
- select CRC32
- select MII
- ---help---
- Say Y here if you have a Realtek 8169 PCI Gigabit Ethernet adapter.
-
- To compile this driver as a module, choose M here: the module
- will be called r8169. This is recommended.
-
-config SB1250_MAC
- tristate "SB1250 Gigabit Ethernet support"
- depends on SIBYTE_SB1xxx_SOC
- select PHYLIB
- ---help---
- This driver supports Gigabit Ethernet interfaces based on the
- Broadcom SiByte family of System-On-a-Chip parts. They include
- the BCM1120, BCM1125, BCM1125H, BCM1250, BCM1255, BCM1280, BCM1455
- and BCM1480 chips.
-
- To compile this driver as a module, choose M here: the module
- will be called sb1250-mac.
-
-config SIS190
- tristate "SiS190/SiS191 gigabit ethernet support"
- depends on PCI
- select CRC32
- select MII
- ---help---
- Say Y here if you have a SiS 190 PCI Fast Ethernet adapter or
- a SiS 191 PCI Gigabit Ethernet adapter. Both are expected to
- appear in lan on motherboard designs which are based on SiS 965
- and SiS 966 south bridge.
-
- To compile this driver as a module, choose M here: the module
- will be called sis190. This is recommended.
-
-config SKGE
- tristate "Marvell Yukon Gigabit Ethernet support"
- depends on PCI
- select CRC32
- ---help---
- This driver support the Marvell Yukon or SysKonnect SK-98xx/SK-95xx
- and related Gigabit Ethernet adapters. It is a new smaller driver
- with better performance and more complete ethtool support.
-
- It does not support the link failover and network management
- features that "portable" vendor supplied sk98lin driver does.
-
- This driver supports adapters based on the original Yukon chipset:
- Marvell 88E8001, Belkin F5D5005, CNet GigaCard, DLink DGE-530T,
- Linksys EG1032/EG1064, 3Com 3C940/3C940B, SysKonnect SK-9871/9872.
-
- It does not support the newer Yukon2 chipset: a separate driver,
- sky2, is provided for these adapters.
-
- To compile this driver as a module, choose M here: the module
- will be called skge. This is recommended.
-
-config SKGE_DEBUG
- bool "Debugging interface"
- depends on SKGE && DEBUG_FS
- help
- This option adds the ability to dump driver state for debugging.
- The file /sys/kernel/debug/skge/ethX displays the state of the internal
- transmit and receive rings.
-
- If unsure, say N.
-
-config SKGE_GENESIS
- bool "Support for older SysKonnect Genesis boards"
- depends on SKGE
- help
- This enables support for the older and uncommon SysKonnect Genesis
- chips, which support MII via an external transceiver, instead of
- an internal one. Disabling this option will save some memory
- by making code smaller. If unsure say Y.
-
-config SKY2
- tristate "Marvell Yukon 2 support"
- depends on PCI
- select CRC32
- ---help---
- This driver supports Gigabit Ethernet adapters based on the
- Marvell Yukon 2 chipset:
- Marvell 88E8021/88E8022/88E8035/88E8036/88E8038/88E8050/88E8052/
- 88E8053/88E8055/88E8061/88E8062, SysKonnect SK-9E21D/SK-9S21
-
- There is companion driver for the older Marvell Yukon and
- SysKonnect Genesis based adapters: skge.
-
- To compile this driver as a module, choose M here: the module
- will be called sky2. This is recommended.
-
-config SKY2_DEBUG
- bool "Debugging interface"
- depends on SKY2 && DEBUG_FS
- help
- This option adds the ability to dump driver state for debugging.
- The file /sys/kernel/debug/sky2/ethX displays the state of the internal
- transmit and receive rings.
-
- If unsure, say N.
-
-config VIA_VELOCITY
- tristate "VIA Velocity support"
- depends on PCI
- select CRC32
- select CRC_CCITT
- select MII
- help
- If you have a VIA "Velocity" based network card say Y here.
-
- To compile this driver as a module, choose M here. The module
- will be called via-velocity.
-
-config TIGON3
- tristate "Broadcom Tigon3 support"
- depends on PCI
- select PHYLIB
- help
- This driver supports Broadcom Tigon3 based gigabit Ethernet cards.
-
- To compile this driver as a module, choose M here: the module
- will be called tg3. This is recommended.
-
-config BNX2
- tristate "Broadcom NetXtremeII support"
- depends on PCI
- select CRC32
- select FW_LOADER
- help
- This driver supports Broadcom NetXtremeII gigabit Ethernet cards.
-
- To compile this driver as a module, choose M here: the module
- will be called bnx2. This is recommended.
-
-config CNIC
- tristate "Broadcom CNIC support"
- depends on PCI
- select BNX2
- select UIO
- help
- This driver supports offload features of Broadcom NetXtremeII
- gigabit Ethernet cards.
-
- To compile this driver as a module, choose M here: the module
- will be called cnic. This is recommended.
-
-config SPIDER_NET
- tristate "Spider Gigabit Ethernet driver"
- depends on PCI && (PPC_IBM_CELL_BLADE || PPC_CELLEB)
- select FW_LOADER
- help
- This driver supports the Gigabit Ethernet chips present on the
- Cell Processor-Based Blades from IBM.
-
-config TSI108_ETH
- tristate "Tundra TSI108 gigabit Ethernet support"
- depends on TSI108_BRIDGE
- help
- This driver supports Tundra TSI108 gigabit Ethernet ports.
- To compile this driver as a module, choose M here: the module
- will be called tsi108_eth.
-
-config GELIC_NET
- tristate "PS3 Gigabit Ethernet driver"
- depends on PPC_PS3
- select PS3_SYS_MANAGER
- help
- This driver supports the network device on the PS3 game
- console. This driver has built-in support for Ethernet.
-
- To compile this driver as a module, choose M here: the
- module will be called ps3_gelic.
-
-config GELIC_WIRELESS
- bool "PS3 Wireless support"
- depends on WLAN
- depends on GELIC_NET
- select WIRELESS_EXT
- help
- This option adds the support for the wireless feature of PS3.
- If you have the wireless-less model of PS3 or have no plan to
- use wireless feature, disabling this option saves memory. As
- the driver automatically distinguishes the models, you can
- safely enable this option even if you have a wireless-less model.
-
-config FSL_PQ_MDIO
- tristate "Freescale PQ MDIO"
- depends on FSL_SOC
- select PHYLIB
- help
- This driver supports the MDIO bus used by the gianfar and UCC drivers.
-
-config GIANFAR
- tristate "Gianfar Ethernet"
- depends on FSL_SOC
- select FSL_PQ_MDIO
- select PHYLIB
- select CRC32
- help
- This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx,
- and MPC86xx family of chips, and the FEC on the 8540.
-
-config UCC_GETH
- tristate "Freescale QE Gigabit Ethernet"
- depends on QUICC_ENGINE
- select FSL_PQ_MDIO
- select PHYLIB
- help
- This driver supports the Gigabit Ethernet mode of the QUICC Engine,
- which is available on some Freescale SOCs.
-
-config UGETH_TX_ON_DEMAND
- bool "Transmit on Demand support"
- depends on UCC_GETH
-
-config MV643XX_ETH
- tristate "Marvell Discovery (643XX) and Orion ethernet support"
- depends on (MV64X60 || PPC32 || PLAT_ORION) && INET
- select INET_LRO
- select PHYLIB
- help
- This driver supports the gigabit ethernet MACs in the
- Marvell Discovery PPC/MIPS chipset family (MV643XX) and
- in the Marvell Orion ARM SoC family.
-
- Some boards that use the Discovery chipset are the Momenco
- Ocelot C and Jaguar ATX and Pegasos II.
-
-config XILINX_LL_TEMAC
- tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver"
- depends on PPC || MICROBLAZE
- select PHYLIB
- help
- This driver supports the Xilinx 10/100/1000 LocalLink TEMAC
- core used in Xilinx Spartan and Virtex FPGAs
-
-config QLA3XXX
- tristate "QLogic QLA3XXX Network Driver Support"
- depends on PCI
- help
- This driver supports QLogic ISP3XXX gigabit Ethernet cards.
-
- To compile this driver as a module, choose M here: the module
- will be called qla3xxx.
-
-config ATL1
- tristate "Atheros/Attansic L1 Gigabit Ethernet support"
- depends on PCI
- select CRC32
- select MII
- help
- This driver supports the Atheros/Attansic L1 gigabit ethernet
- adapter.
-
- To compile this driver as a module, choose M here. The module
- will be called atl1.
-
-config ATL1E
- tristate "Atheros L1E Gigabit Ethernet support (EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL
- select CRC32
- select MII
- help
- This driver supports the Atheros L1E gigabit ethernet adapter.
-
- To compile this driver as a module, choose M here. The module
- will be called atl1e.
-
-config ATL1C
- tristate "Atheros L1C Gigabit Ethernet support (EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL
- select CRC32
- select MII
- help
- This driver supports the Atheros L1C gigabit ethernet adapter.
-
- To compile this driver as a module, choose M here. The module
- will be called atl1c.
-
-config JME
- tristate "JMicron(R) PCI-Express Gigabit Ethernet support"
- depends on PCI
- select CRC32
- select MII
- ---help---
- This driver supports the PCI-Express gigabit ethernet adapters
- based on JMicron JMC250 chipset.
-
- To compile this driver as a module, choose M here. The module
- will be called jme.
-
-config S6GMAC
- tristate "S6105 GMAC ethernet support"
- depends on XTENSA_VARIANT_S6000
- select PHYLIB
- help
- This driver supports the on chip ethernet device on the
- S6105 xtensa processor.
-
- To compile this driver as a module, choose M here. The module
- will be called s6gmac.
-
-source "drivers/net/stmmac/Kconfig"
-
-config PCH_GBE
- tristate "Intel EG20T PCH / OKI SEMICONDUCTOR ML7223 IOH GbE"
- depends on PCI
- select MII
- ---help---
- This is a gigabit ethernet driver for EG20T PCH.
- EG20T PCH is the platform controller hub that is used in Intel's
- general embedded platform.
- EG20T PCH has Gigabit Ethernet interface.
- Using this interface, it is able to access system devices connected
- to Gigabit Ethernet.
- This driver enables Gigabit Ethernet function.
-
- This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
- Output Hub), ML7223.
- ML7223 IOH is for MP(Media Phone) use.
- ML7223 is companion chip for Intel Atom E6xx series.
- ML7223 is completely compatible for Intel EG20T PCH.
-
-config FTGMAC100
- tristate "Faraday FTGMAC100 Gigabit Ethernet support"
- depends on ARM
- select PHYLIB
- help
- This driver supports the FTGMAC100 Gigabit Ethernet controller
- from Faraday. It is used on Faraday A369, Andes AG102 and some
- other ARM/NDS32 SoC's.
-
-endif # NETDEV_1000
-
-#
-# 10 Gigabit Ethernet
-#
-
-menuconfig NETDEV_10000
- bool "Ethernet (10000 Mbit)"
- depends on !UML
- default y
- ---help---
- Say Y here to get to see options for 10 Gigabit Ethernet drivers.
- This option alone does not add any kernel code.
-
- If you say N, all options in this submenu will be skipped and disabled.
-
-if NETDEV_10000
-
-config MDIO
- tristate
-
-config CHELSIO_T1
- tristate "Chelsio 10Gb Ethernet support"
- depends on PCI
- select CRC32
- select MDIO
- help
- This driver supports Chelsio gigabit and 10-gigabit
- Ethernet cards. More information about adapter features and
- performance tuning is in <file:Documentation/networking/cxgb.txt>.
-
- For general information about Chelsio and our products, visit
- our website at <http://www.chelsio.com>.
-
- For customer support, please visit our customer support page at
- <http://www.chelsio.com/support.html>.
-
- Please send feedback to <linux-bugs@chelsio.com>.
-
- To compile this driver as a module, choose M here: the module
- will be called cxgb.
-
-config CHELSIO_T1_1G
- bool "Chelsio gigabit Ethernet support"
- depends on CHELSIO_T1
- help
- Enables support for Chelsio's gigabit Ethernet PCI cards. If you
- are using only 10G cards say 'N' here.
-
-config CHELSIO_T3
- tristate "Chelsio Communications T3 10Gb Ethernet support"
- depends on PCI && INET
- select FW_LOADER
- select MDIO
- help
- This driver supports Chelsio T3-based gigabit and 10Gb Ethernet
- adapters.
-
- For general information about Chelsio and our products, visit
- our website at <http://www.chelsio.com>.
-
- For customer support, please visit our customer support page at
- <http://www.chelsio.com/support.html>.
-
- Please send feedback to <linux-bugs@chelsio.com>.
-
- To compile this driver as a module, choose M here: the module
- will be called cxgb3.
-
-config CHELSIO_T4
- tristate "Chelsio Communications T4 Ethernet support"
- depends on PCI
- select FW_LOADER
- select MDIO
- help
- This driver supports Chelsio T4-based gigabit and 10Gb Ethernet
- adapters.
-
- For general information about Chelsio and our products, visit
- our website at <http://www.chelsio.com>.
-
- For customer support, please visit our customer support page at
- <http://www.chelsio.com/support.html>.
-
- Please send feedback to <linux-bugs@chelsio.com>.
-
- To compile this driver as a module choose M here; the module
- will be called cxgb4.
-
-config CHELSIO_T4VF
- tristate "Chelsio Communications T4 Virtual Function Ethernet support"
- depends on PCI
- help
- This driver supports Chelsio T4-based gigabit and 10Gb Ethernet
- adapters with PCI-E SR-IOV Virtual Functions.
-
- For general information about Chelsio and our products, visit
- our website at <http://www.chelsio.com>.
-
- For customer support, please visit our customer support page at
- <http://www.chelsio.com/support.html>.
-
- Please send feedback to <linux-bugs@chelsio.com>.
-
- To compile this driver as a module choose M here; the module
- will be called cxgb4vf.
-
-config EHEA
- tristate "eHEA Ethernet support"
- depends on IBMEBUS && INET && SPARSEMEM
- select INET_LRO
- ---help---
- This driver supports the IBM pSeries eHEA ethernet adapter.
-
- To compile the driver as a module, choose M here. The module
- will be called ehea.
-
-config ENIC
- tristate "Cisco VIC Ethernet NIC Support"
- depends on PCI && INET
- help
- This enables the support for the Cisco VIC Ethernet card.
-
-config IXGBE
- tristate "Intel(R) 10GbE PCI Express adapters support"
- depends on PCI && INET
- select MDIO
- ---help---
- This driver supports Intel(R) 10GbE PCI Express family of
- adapters. For more information on how to identify your adapter, go
- to the Adapter & Driver ID Guide at:
-
- <http://support.intel.com/support/network/adapter/pro100/21397.htm>
-
- For general information and support, go to the Intel support
- website at:
-
- <http://support.intel.com>
-
- To compile this driver as a module, choose M here. The module
- will be called ixgbe.
-
-config IXGBE_DCA
- bool "Direct Cache Access (DCA) Support"
- default y
- depends on IXGBE && DCA && !(IXGBE=y && DCA=m)
- ---help---
- Say Y here if you want to use Direct Cache Access (DCA) in the
- driver. DCA is a method for warming the CPU cache before data
- is used, with the intent of lessening the impact of cache misses.
-
-config IXGBE_DCB
- bool "Data Center Bridging (DCB) Support"
- default n
- depends on IXGBE && DCB
- ---help---
- Say Y here if you want to use Data Center Bridging (DCB) in the
- driver.
-
- If unsure, say N.
-
-config IXGBEVF
- tristate "Intel(R) 82599 Virtual Function Ethernet support"
- depends on PCI_MSI
- ---help---
- This driver supports Intel(R) 82599 virtual functions. For more
- information on how to identify your adapter, go to the Adapter &
- Driver ID Guide at:
-
- <http://support.intel.com/support/network/sb/CS-008441.htm>
-
- For general information and support, go to the Intel support
- website at:
-
- <http://support.intel.com>
-
- More specific information on configuring the driver is in
- <file:Documentation/networking/ixgbevf.txt>.
-
- To compile this driver as a module, choose M here. The module
- will be called ixgbevf. MSI-X interrupt support is required
- for this driver to work correctly.
-
-config IXGB
- tristate "Intel(R) PRO/10GbE support"
- depends on PCI
- ---help---
- This driver supports Intel(R) PRO/10GbE family of adapters for
- PCI-X type cards. For PCI-E type cards, use the "ixgbe" driver
- instead. For more information on how to identify your adapter, go
- to the Adapter & Driver ID Guide at:
-
- <http://support.intel.com/support/network/adapter/pro100/21397.htm>
-
- For general information and support, go to the Intel support
- website at:
-
- <http://support.intel.com>
-
- More specific information on configuring the driver is in
- <file:Documentation/networking/ixgb.txt>.
-
- To compile this driver as a module, choose M here. The module
- will be called ixgb.
-
-config S2IO
- tristate "Exar Xframe 10Gb Ethernet Adapter"
- depends on PCI
- ---help---
- This driver supports Exar Corp's Xframe Series 10Gb Ethernet Adapters.
-
- More specific information on configuring the driver is in
- <file:Documentation/networking/s2io.txt>.
-
- To compile this driver as a module, choose M here. The module
- will be called s2io.
-
-config VXGE
- tristate "Exar X3100 Series 10GbE PCIe Server Adapter"
- depends on PCI && INET
- ---help---
- This driver supports Exar Corp's X3100 Series 10 GbE PCIe
- I/O Virtualized Server Adapter.
-
- More specific information on configuring the driver is in
- <file:Documentation/networking/vxge.txt>.
-
- To compile this driver as a module, choose M here. The module
- will be called vxge.
-
-config VXGE_DEBUG_TRACE_ALL
- bool "Enabling All Debug trace statments in driver"
- default n
- depends on VXGE
- ---help---
- Say Y here if you want to enabling all the debug trace statements in
- the vxge driver. By default only few debug trace statements are
- enabled.
-
-config MYRI10GE
- tristate "Myricom Myri-10G Ethernet support"
- depends on PCI && INET
- select FW_LOADER
- select CRC32
- select INET_LRO
- ---help---
- This driver supports Myricom Myri-10G Dual Protocol interface in
- Ethernet mode. If the eeprom on your board is not recent enough,
- you will need a newer firmware image.
- You may get this image or more information, at:
-
- <http://www.myri.com/scs/download-Myri10GE.html>
-
- To compile this driver as a module, choose M here. The module
- will be called myri10ge.
-
-config MYRI10GE_DCA
- bool "Direct Cache Access (DCA) Support"
- default y
- depends on MYRI10GE && DCA && !(MYRI10GE=y && DCA=m)
- ---help---
- Say Y here if you want to use Direct Cache Access (DCA) in the
- driver. DCA is a method for warming the CPU cache before data
- is used, with the intent of lessening the impact of cache misses.
-
-config NETXEN_NIC
- tristate "NetXen Multi port (1/10) Gigabit Ethernet NIC"
- depends on PCI
- select FW_LOADER
- help
- This enables the support for NetXen's Gigabit Ethernet card.
-
-config NIU
- tristate "Sun Neptune 10Gbit Ethernet support"
- depends on PCI
- select CRC32
- help
- This enables support for cards based upon Sun's
- Neptune chipset.
-
-config PASEMI_MAC
- tristate "PA Semi 1/10Gbit MAC"
- depends on PPC_PASEMI && PCI && INET
- select PHYLIB
- select INET_LRO
- help
- This driver supports the on-chip 1/10Gbit Ethernet controller on
- PA Semi's PWRficient line of chips.
-
-config MLX4_EN
- tristate "Mellanox Technologies 10Gbit Ethernet support"
- depends on PCI && INET
- select MLX4_CORE
- select INET_LRO
- help
- This driver supports Mellanox Technologies ConnectX Ethernet
- devices.
-
-config MLX4_CORE
- tristate
- depends on PCI
- default n
-
-config MLX4_DEBUG
- bool "Verbose debugging output" if (MLX4_CORE && EXPERT)
- depends on MLX4_CORE
- default y
- ---help---
- This option causes debugging code to be compiled into the
- mlx4_core driver. The output can be turned on via the
- debug_level module parameter (which can also be set after
- the driver is loaded through sysfs).
-
-config TEHUTI
- tristate "Tehuti Networks 10G Ethernet"
- depends on PCI
- help
- Tehuti Networks 10G Ethernet NIC
-
-config BNX2X
- tristate "Broadcom NetXtremeII 10Gb support"
- depends on PCI
- select FW_LOADER
- select ZLIB_INFLATE
- select LIBCRC32C
- select MDIO
- help
- This driver supports Broadcom NetXtremeII 10 gigabit Ethernet cards.
- To compile this driver as a module, choose M here: the module
- will be called bnx2x. This is recommended.
-
-config QLCNIC
- tristate "QLOGIC QLCNIC 1/10Gb Converged Ethernet NIC Support"
- depends on PCI
- select FW_LOADER
- help
- This driver supports QLogic QLE8240 and QLE8242 Converged Ethernet
- devices.
-
-config QLGE
- tristate "QLogic QLGE 10Gb Ethernet Driver Support"
- depends on PCI
- help
- This driver supports QLogic ISP8XXX 10Gb Ethernet cards.
-
- To compile this driver as a module, choose M here: the module
- will be called qlge.
-
-config BNA
- tristate "Brocade 1010/1020 10Gb Ethernet Driver support"
- depends on PCI
- ---help---
- This driver supports Brocade 1010/1020 10Gb CEE capable Ethernet
- cards.
- To compile this driver as a module, choose M here: the module
- will be called bna.
-
- For general information and support, go to the Brocade support
- website at:
-
- <http://support.brocade.com>
-
-source "drivers/net/sfc/Kconfig"
-
-source "drivers/net/benet/Kconfig"
-
-endif # NETDEV_10000
+source "drivers/s390/net/Kconfig"
source "drivers/net/tokenring/Kconfig"
+source "drivers/net/usb/Kconfig"
+
source "drivers/net/wireless/Kconfig"
source "drivers/net/wimax/Kconfig"
-source "drivers/net/usb/Kconfig"
-
-source "drivers/net/pcmcia/Kconfig"
-
source "drivers/net/wan/Kconfig"
-source "drivers/atm/Kconfig"
-
-source "drivers/ieee802154/Kconfig"
-
-source "drivers/s390/net/Kconfig"
-
-source "drivers/net/caif/Kconfig"
-
-config TILE_NET
- tristate "Tilera GBE/XGBE network driver support"
- depends on TILE
- default y
- select CRC32
- help
- This is a standard Linux network device driver for the
- on-chip Tilera Gigabit Ethernet and XAUI interfaces.
-
- To compile this driver as a module, choose M here: the module
- will be called tile_net.
-
config XEN_NETDEV_FRONTEND
tristate "Xen network device frontend driver"
depends on XEN
@@ -3001,448 +328,6 @@ config XEN_NETDEV_BACKEND
compile this driver as a module, chose M here: the module
will be called xen-netback.
-config ISERIES_VETH
- tristate "iSeries Virtual Ethernet driver support"
- depends on PPC_ISERIES
-
-config RIONET
- tristate "RapidIO Ethernet over messaging driver support"
- depends on RAPIDIO
-
-config RIONET_TX_SIZE
- int "Number of outbound queue entries"
- depends on RIONET
- default "128"
-
-config RIONET_RX_SIZE
- int "Number of inbound queue entries"
- depends on RIONET
- default "128"
-
-config FDDI
- tristate "FDDI driver support"
- depends on (PCI || EISA || TC)
- help
- Fiber Distributed Data Interface is a high speed local area network
- design; essentially a replacement for high speed Ethernet. FDDI can
- run over copper or fiber. If you are connected to such a network and
- want a driver for the FDDI card in your computer, say Y here (and
- then also Y to the driver for your FDDI card, below). Most people
- will say N.
-
-config DEFXX
- tristate "Digital DEFTA/DEFEA/DEFPA adapter support"
- depends on FDDI && (PCI || EISA || TC)
- ---help---
- This is support for the DIGITAL series of TURBOchannel (DEFTA),
- EISA (DEFEA) and PCI (DEFPA) controllers which can connect you
- to a local FDDI network.
-
- To compile this driver as a module, choose M here: the module
- will be called defxx. If unsure, say N.
-
-config DEFXX_MMIO
- bool
- prompt "Use MMIO instead of PIO" if PCI || EISA
- depends on DEFXX
- default n if PCI || EISA
- default y
- ---help---
- This instructs the driver to use EISA or PCI memory-mapped I/O
- (MMIO) as appropriate instead of programmed I/O ports (PIO).
- Enabling this gives an improvement in processing time in parts
- of the driver, but it may cause problems with EISA (DEFEA)
- adapters. TURBOchannel does not have the concept of I/O ports,
- so MMIO is always used for these (DEFTA) adapters.
-
- If unsure, say N.
-
-config SKFP
- tristate "SysKonnect FDDI PCI support"
- depends on FDDI && PCI
- select BITREVERSE
- ---help---
- Say Y here if you have a SysKonnect FDDI PCI adapter.
- The following adapters are supported by this driver:
- - SK-5521 (SK-NET FDDI-UP)
- - SK-5522 (SK-NET FDDI-UP DAS)
- - SK-5541 (SK-NET FDDI-FP)
- - SK-5543 (SK-NET FDDI-LP)
- - SK-5544 (SK-NET FDDI-LP DAS)
- - SK-5821 (SK-NET FDDI-UP64)
- - SK-5822 (SK-NET FDDI-UP64 DAS)
- - SK-5841 (SK-NET FDDI-FP64)
- - SK-5843 (SK-NET FDDI-LP64)
- - SK-5844 (SK-NET FDDI-LP64 DAS)
- - Netelligent 100 FDDI DAS Fibre SC
- - Netelligent 100 FDDI SAS Fibre SC
- - Netelligent 100 FDDI DAS UTP
- - Netelligent 100 FDDI SAS UTP
- - Netelligent 100 FDDI SAS Fibre MIC
-
- Read <file:Documentation/networking/skfp.txt> for information about
- the driver.
-
- Questions concerning this driver can be addressed to:
- <linux@syskonnect.de>
-
- To compile this driver as a module, choose M here: the module
- will be called skfp. This is recommended.
-
-config HIPPI
- bool "HIPPI driver support (EXPERIMENTAL)"
- depends on EXPERIMENTAL && INET && PCI
- help
- HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and
- 1600Mbit/sec dual-simplex switched or point-to-point network. HIPPI
- can run over copper (25m) or fiber (300m on multi-mode or 10km on
- single-mode). HIPPI networks are commonly used for clusters and to
- connect to super computers. If you are connected to a HIPPI network
- and have a HIPPI network card in your computer that you want to use
- under Linux, say Y here (you must also remember to enable the driver
- for your HIPPI card below). Most people will say N here.
-
-config ROADRUNNER
- tristate "Essential RoadRunner HIPPI PCI adapter support (EXPERIMENTAL)"
- depends on HIPPI && PCI
- help
- Say Y here if this is your PCI HIPPI network card.
-
- To compile this driver as a module, choose M here: the module
- will be called rrunner. If unsure, say N.
-
-config ROADRUNNER_LARGE_RINGS
- bool "Use large TX/RX rings (EXPERIMENTAL)"
- depends on ROADRUNNER
- help
- If you say Y here, the RoadRunner driver will preallocate up to 2 MB
- of additional memory to allow for fastest operation, both for
- transmitting and receiving. This memory cannot be used by any other
- kernel code or by user space programs. Say Y here only if you have
- the memory.
-
-config PLIP
- tristate "PLIP (parallel port) support"
- depends on PARPORT
- ---help---
- PLIP (Parallel Line Internet Protocol) is used to create a
- reasonably fast mini network consisting of two (or, rarely, more)
- local machines. A PLIP link from a Linux box is a popular means to
- install a Linux distribution on a machine which doesn't have a
- CD-ROM drive (a minimal system has to be transferred with floppies
- first). The kernels on both machines need to have this PLIP option
- enabled for this to work.
-
- The PLIP driver has two modes, mode 0 and mode 1. The parallel
- ports (the connectors at the computers with 25 holes) are connected
- with "null printer" or "Turbo Laplink" cables which can transmit 4
- bits at a time (mode 0) or with special PLIP cables, to be used on
- bidirectional parallel ports only, which can transmit 8 bits at a
- time (mode 1); you can find the wiring of these cables in
- <file:Documentation/networking/PLIP.txt>. The cables can be up to
- 15m long. Mode 0 works also if one of the machines runs DOS/Windows
- and has some PLIP software installed, e.g. the Crynwr PLIP packet
- driver (<http://oak.oakland.edu/simtel.net/msdos/pktdrvr-pre.html>)
- and winsock or NCSA's telnet.
-
- If you want to use PLIP, say Y and read the PLIP mini-HOWTO as well
- as the NET-3-HOWTO, both available from
- <http://www.tldp.org/docs.html#howto>. Note that the PLIP
- protocol has been changed and this PLIP driver won't work together
- with the PLIP support in Linux versions 1.0.x. This option enlarges
- your kernel by about 8 KB.
-
- To compile this driver as a module, choose M here. The module
- will be called plip. If unsure, say Y or M, in case you buy
- a laptop later.
-
-config PPP
- tristate "PPP (point-to-point protocol) support"
- select SLHC
- ---help---
- PPP (Point to Point Protocol) is a newer and better SLIP. It serves
- the same purpose: sending Internet traffic over telephone (and other
- serial) lines. Ask your access provider if they support it, because
- otherwise you can't use it; most Internet access providers these
- days support PPP rather than SLIP.
-
- To use PPP, you need an additional program called pppd as described
- in the PPP-HOWTO, available at
- <http://www.tldp.org/docs.html#howto>. Make sure that you have
- the version of pppd recommended in <file:Documentation/Changes>.
- The PPP option enlarges your kernel by about 16 KB.
-
- There are actually two versions of PPP: the traditional PPP for
- asynchronous lines, such as regular analog phone lines, and
- synchronous PPP which can be used over digital ISDN lines for
- example. If you want to use PPP over phone lines or other
- asynchronous serial lines, you need to say Y (or M) here and also to
- the next option, "PPP support for async serial ports". For PPP over
- synchronous lines, you should say Y (or M) here and to "Support
- synchronous PPP", below.
-
- If you said Y to "Version information on all symbols" above, then
- you cannot compile the PPP driver into the kernel; you can then only
- compile it as a module. To compile this driver as a module, choose M
- here. The module will be called ppp_generic.
-
-config PPP_MULTILINK
- bool "PPP multilink support (EXPERIMENTAL)"
- depends on PPP && EXPERIMENTAL
- help
- PPP multilink is a protocol (defined in RFC 1990) which allows you
- to combine several (logical or physical) lines into one logical PPP
- connection, so that you can utilize your full bandwidth.
-
- This has to be supported at the other end as well and you need a
- version of the pppd daemon which understands the multilink protocol.
-
- If unsure, say N.
-
-config PPP_FILTER
- bool "PPP filtering"
- depends on PPP
- help
- Say Y here if you want to be able to filter the packets passing over
- PPP interfaces. This allows you to control which packets count as
- activity (i.e. which packets will reset the idle timer or bring up
- a demand-dialed link) and which packets are to be dropped entirely.
- You need to say Y here if you wish to use the pass-filter and
- active-filter options to pppd.
-
- If unsure, say N.
-
-config PPP_ASYNC
- tristate "PPP support for async serial ports"
- depends on PPP
- select CRC_CCITT
- ---help---
- Say Y (or M) here if you want to be able to use PPP over standard
- asynchronous serial ports, such as COM1 or COM2 on a PC. If you use
- a modem (not a synchronous or ISDN modem) to contact your ISP, you
- need this option.
-
- To compile this driver as a module, choose M here.
-
- If unsure, say Y.
-
-config PPP_SYNC_TTY
- tristate "PPP support for sync tty ports"
- depends on PPP
- help
- Say Y (or M) here if you want to be able to use PPP over synchronous
- (HDLC) tty devices, such as the SyncLink adapter. These devices
- are often used for high-speed leased lines like T1/E1.
-
- To compile this driver as a module, choose M here.
-
-config PPP_DEFLATE
- tristate "PPP Deflate compression"
- depends on PPP
- select ZLIB_INFLATE
- select ZLIB_DEFLATE
- ---help---
- Support for the Deflate compression method for PPP, which uses the
- Deflate algorithm (the same algorithm that gzip uses) to compress
- each PPP packet before it is sent over the wire. The machine at the
- other end of the PPP link (usually your ISP) has to support the
- Deflate compression method as well for this to be useful. Even if
- they don't support it, it is safe to say Y here.
-
- To compile this driver as a module, choose M here.
-
-config PPP_BSDCOMP
- tristate "PPP BSD-Compress compression"
- depends on PPP
- ---help---
- Support for the BSD-Compress compression method for PPP, which uses
- the LZW compression method to compress each PPP packet before it is
- sent over the wire. The machine at the other end of the PPP link
- (usually your ISP) has to support the BSD-Compress compression
- method as well for this to be useful. Even if they don't support it,
- it is safe to say Y here.
-
- The PPP Deflate compression method ("PPP Deflate compression",
- above) is preferable to BSD-Compress, because it compresses better
- and is patent-free.
-
- Note that the BSD compression code will always be compiled as a
- module; it is called bsd_comp and will show up in the directory
- modules once you have said "make modules". If unsure, say N.
-
-config PPP_MPPE
- tristate "PPP MPPE compression (encryption) (EXPERIMENTAL)"
- depends on PPP && EXPERIMENTAL
- select CRYPTO
- select CRYPTO_SHA1
- select CRYPTO_ARC4
- select CRYPTO_ECB
- ---help---
- Support for the MPPE Encryption protocol, as employed by the
- Microsoft Point-to-Point Tunneling Protocol.
-
- See http://pptpclient.sourceforge.net/ for information on
- configuring PPTP clients and servers to utilize this method.
-
-config PPPOE
- tristate "PPP over Ethernet (EXPERIMENTAL)"
- depends on EXPERIMENTAL && PPP
- help
- Support for PPP over Ethernet.
-
- This driver requires the latest version of pppd from the CVS
- repository at cvs.samba.org. Alternatively, see the
- RoaringPenguin package (<http://www.roaringpenguin.com/pppoe>)
- which contains instruction on how to use this driver (under
- the heading "Kernel mode PPPoE").
-
-config PPTP
- tristate "PPP over IPv4 (PPTP) (EXPERIMENTAL)"
- depends on EXPERIMENTAL && PPP && NET_IPGRE_DEMUX
- help
- Support for PPP over IPv4.(Point-to-Point Tunneling Protocol)
-
- This driver requires pppd plugin to work in client mode or
- modified pptpd (poptop) to work in server mode.
- See http://accel-pptp.sourceforge.net/ for information how to
- utilize this module.
-
-config PPPOATM
- tristate "PPP over ATM"
- depends on ATM && PPP
- help
- Support PPP (Point to Point Protocol) encapsulated in ATM frames.
- This implementation does not yet comply with section 8 of RFC2364,
- which can lead to bad results if the ATM peer loses state and
- changes its encapsulation unilaterally.
-
-config PPPOL2TP
- tristate "PPP over L2TP (EXPERIMENTAL)"
- depends on EXPERIMENTAL && L2TP && PPP
- help
- Support for PPP-over-L2TP socket family. L2TP is a protocol
- used by ISPs and enterprises to tunnel PPP traffic over UDP
- tunnels. L2TP is replacing PPTP for VPN uses.
-
-config SLIP
- tristate "SLIP (serial line) support"
- ---help---
- Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to
- connect to your Internet service provider or to connect to some
- other local Unix box or if you want to configure your Linux box as a
- Slip/CSlip server for other people to dial in. SLIP (Serial Line
- Internet Protocol) is a protocol used to send Internet traffic over
- serial connections such as telephone lines or null modem cables;
- nowadays, the protocol PPP is more commonly used for this same
- purpose.
-
- Normally, your access provider has to support SLIP in order for you
- to be able to use it, but there is now a SLIP emulator called SLiRP
- around (available from
- <ftp://ibiblio.org/pub/Linux/system/network/serial/>) which
- allows you to use SLIP over a regular dial up shell connection. If
- you plan to use SLiRP, make sure to say Y to CSLIP, below. The
- NET-3-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>, explains how to
- configure SLIP. Note that you don't need this option if you just
- want to run term (term is a program which gives you almost full
- Internet connectivity if you have a regular dial up shell account on
- some Internet connected Unix computer. Read
- <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>). SLIP
- support will enlarge your kernel by about 4 KB. If unsure, say N.
-
- To compile this driver as a module, choose M here. The module
- will be called slip.
-
-config SLIP_COMPRESSED
- bool "CSLIP compressed headers"
- depends on SLIP
- select SLHC
- ---help---
- This protocol is faster than SLIP because it uses compression on the
- TCP/IP headers (not on the data itself), but it has to be supported
- on both ends. Ask your access provider if you are not sure and
- answer Y, just in case. You will still be able to use plain SLIP. If
- you plan to use SLiRP, the SLIP emulator (available from
- <ftp://ibiblio.org/pub/Linux/system/network/serial/>) which
- allows you to use SLIP over a regular dial up shell connection, you
- definitely want to say Y here. The NET-3-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>, explains how to configure
- CSLIP. This won't enlarge your kernel.
-
-config SLHC
- tristate
- help
- This option enables Van Jacobsen serial line header compression
- routines.
-
-config SLIP_SMART
- bool "Keepalive and linefill"
- depends on SLIP
- help
- Adds additional capabilities to the SLIP driver to support the
- RELCOM line fill and keepalive monitoring. Ideal on poor quality
- analogue lines.
-
-config SLIP_MODE_SLIP6
- bool "Six bit SLIP encapsulation"
- depends on SLIP
- help
- Just occasionally you may need to run IP over hostile serial
- networks that don't pass all control characters or are only seven
- bit. Saying Y here adds an extra mode you can use with SLIP:
- "slip6". In this mode, SLIP will only send normal ASCII symbols over
- the serial device. Naturally, this has to be supported at the other
- end of the link as well. It's good enough, for example, to run IP
- over the async ports of a Camtec JNT Pad. If unsure, say N.
-
-config NET_FC
- bool "Fibre Channel driver support"
- depends on SCSI && PCI
- help
- Fibre Channel is a high speed serial protocol mainly used to connect
- large storage devices to the computer; it is compatible with and
- intended to replace SCSI.
-
- If you intend to use Fibre Channel, you need to have a Fibre channel
- adaptor card in your computer; say Y here and to the driver for your
- adaptor below. You also should have said Y to "SCSI support" and
- "SCSI generic support".
-
-config NETCONSOLE
- tristate "Network console logging support"
- ---help---
- If you want to log kernel messages over the network, enable this.
- See <file:Documentation/networking/netconsole.txt> for details.
-
-config NETCONSOLE_DYNAMIC
- bool "Dynamic reconfiguration of logging targets"
- depends on NETCONSOLE && SYSFS && CONFIGFS_FS && \
- !(NETCONSOLE=y && CONFIGFS_FS=m)
- help
- This option enables the ability to dynamically reconfigure target
- parameters (interface, IP addresses, port numbers, MAC addresses)
- at runtime through a userspace interface exported using configfs.
- See <file:Documentation/networking/netconsole.txt> for details.
-
-config NETPOLL
- def_bool NETCONSOLE
-
-config NETPOLL_TRAP
- bool "Netpoll traffic trapping"
- default n
- depends on NETPOLL
-
-config NET_POLL_CONTROLLER
- def_bool NETPOLL
-
-config VIRTIO_NET
- tristate "Virtio network driver (EXPERIMENTAL)"
- depends on EXPERIMENTAL && VIRTIO
- ---help---
- This is the virtual network driver for virtio. It can be used with
- lguest or QEMU based VMMs (like KVM or Xen). Say Y or M.
-
config VMXNET3
tristate "VMware VMXNET3 ethernet driver"
depends on PCI && INET
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index e1eca2ab505e..fa877cd2b139 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -1,278 +1,61 @@
#
-# Makefile for the Linux network (ethercard) device drivers.
+# Makefile for the Linux network device drivers.
#
-obj-$(CONFIG_MII) += mii.o
-obj-$(CONFIG_MDIO) += mdio.o
-obj-$(CONFIG_PHYLIB) += phy/
-
-obj-$(CONFIG_TI_DAVINCI_EMAC) += davinci_emac.o
-obj-$(CONFIG_TI_DAVINCI_MDIO) += davinci_mdio.o
-obj-$(CONFIG_TI_DAVINCI_CPDMA) += davinci_cpdma.o
-
-obj-$(CONFIG_E1000) += e1000/
-obj-$(CONFIG_E1000E) += e1000e/
-obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac/
-obj-$(CONFIG_IGB) += igb/
-obj-$(CONFIG_IGBVF) += igbvf/
-obj-$(CONFIG_IXGBE) += ixgbe/
-obj-$(CONFIG_IXGBEVF) += ixgbevf/
-obj-$(CONFIG_IXGB) += ixgb/
-obj-$(CONFIG_IP1000) += ipg.o
-obj-$(CONFIG_CHELSIO_T1) += chelsio/
-obj-$(CONFIG_CHELSIO_T3) += cxgb3/
-obj-$(CONFIG_CHELSIO_T4) += cxgb4/
-obj-$(CONFIG_CHELSIO_T4VF) += cxgb4vf/
-obj-$(CONFIG_EHEA) += ehea/
-obj-$(CONFIG_CAN) += can/
-obj-$(CONFIG_BONDING) += bonding/
-obj-$(CONFIG_ATL1) += atlx/
-obj-$(CONFIG_ATL2) += atlx/
-obj-$(CONFIG_ATL1E) += atl1e/
-obj-$(CONFIG_ATL1C) += atl1c/
-obj-$(CONFIG_GIANFAR) += gianfar_driver.o
-obj-$(CONFIG_PTP_1588_CLOCK_GIANFAR) += gianfar_ptp.o
-obj-$(CONFIG_TEHUTI) += tehuti.o
-obj-$(CONFIG_ENIC) += enic/
-obj-$(CONFIG_JME) += jme.o
-obj-$(CONFIG_BE2NET) += benet/
-obj-$(CONFIG_VMXNET3) += vmxnet3/
-obj-$(CONFIG_BNA) += bna/
-
-gianfar_driver-objs := gianfar.o \
- gianfar_ethtool.o \
- gianfar_sysfs.o
-
-obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o
-ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o
-
-obj-$(CONFIG_FSL_PQ_MDIO) += fsl_pq_mdio.o
-
-#
-# link order important here
#
-obj-$(CONFIG_PLIP) += plip.o
-
-obj-$(CONFIG_ROADRUNNER) += rrunner.o
-
-obj-$(CONFIG_HAPPYMEAL) += sunhme.o
-obj-$(CONFIG_SUNLANCE) += sunlance.o
-obj-$(CONFIG_SUNQE) += sunqe.o
-obj-$(CONFIG_SUNBMAC) += sunbmac.o
-obj-$(CONFIG_SUNGEM) += sungem.o sungem_phy.o
-obj-$(CONFIG_CASSINI) += cassini.o
-obj-$(CONFIG_SUNVNET) += sunvnet.o
-
-obj-$(CONFIG_MACE) += mace.o
-obj-$(CONFIG_BMAC) += bmac.o
-
-obj-$(CONFIG_VORTEX) += 3c59x.o
-obj-$(CONFIG_TYPHOON) += typhoon.o
-obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
-obj-$(CONFIG_PCNET32) += pcnet32.o
-obj-$(CONFIG_E100) += e100.o
-obj-$(CONFIG_TLAN) += tlan.o
-obj-$(CONFIG_EPIC100) += epic100.o
-obj-$(CONFIG_SMSC9420) += smsc9420.o
-obj-$(CONFIG_SIS190) += sis190.o
-obj-$(CONFIG_SIS900) += sis900.o
-obj-$(CONFIG_R6040) += r6040.o
-obj-$(CONFIG_YELLOWFIN) += yellowfin.o
-obj-$(CONFIG_ACENIC) += acenic.o
-obj-$(CONFIG_ISERIES_VETH) += iseries_veth.o
-obj-$(CONFIG_NATSEMI) += natsemi.o
-obj-$(CONFIG_NS83820) += ns83820.o
-obj-$(CONFIG_STNIC) += stnic.o 8390.o
-obj-$(CONFIG_FEALNX) += fealnx.o
-obj-$(CONFIG_TIGON3) += tg3.o
-obj-$(CONFIG_BNX2) += bnx2.o
-obj-$(CONFIG_CNIC) += cnic.o
-obj-$(CONFIG_BNX2X) += bnx2x/
-spidernet-y += spider_net.o spider_net_ethtool.o
-obj-$(CONFIG_SPIDER_NET) += spidernet.o sungem_phy.o
-obj-$(CONFIG_GELIC_NET) += ps3_gelic.o
-gelic_wireless-$(CONFIG_GELIC_WIRELESS) += ps3_gelic_wireless.o
-ps3_gelic-objs += ps3_gelic_net.o $(gelic_wireless-y)
-obj-$(CONFIG_TC35815) += tc35815.o
-obj-$(CONFIG_SKGE) += skge.o
-obj-$(CONFIG_SKY2) += sky2.o
-obj-$(CONFIG_SKFP) += skfp/
-obj-$(CONFIG_KS8842) += ks8842.o
-obj-$(CONFIG_KS8851) += ks8851.o
-obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o
-obj-$(CONFIG_KSZ884X_PCI) += ksz884x.o
-obj-$(CONFIG_VIA_RHINE) += via-rhine.o
-obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o
-obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
-obj-$(CONFIG_RIONET) += rionet.o
-obj-$(CONFIG_SH_ETH) += sh_eth.o
-obj-$(CONFIG_STMMAC_ETH) += stmmac/
-
+# Networking Core Drivers
#
-# end link order section
-#
-
-obj-$(CONFIG_SUNDANCE) += sundance.o
-obj-$(CONFIG_HAMACHI) += hamachi.o
-obj-$(CONFIG_NET) += Space.o loopback.o
-obj-$(CONFIG_SEEQ8005) += seeq8005.o
-obj-$(CONFIG_NET_SB1000) += sb1000.o
-obj-$(CONFIG_MAC8390) += mac8390.o
-obj-$(CONFIG_APNE) += apne.o 8390.o
-obj-$(CONFIG_PCMCIA_PCNET) += 8390.o
-obj-$(CONFIG_HP100) += hp100.o
-obj-$(CONFIG_SMC9194) += smc9194.o
-obj-$(CONFIG_FEC) += fec.o
-obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
-ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
- obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o
-endif
-obj-$(CONFIG_WD80x3) += wd.o 8390.o
-obj-$(CONFIG_EL2) += 3c503.o 8390p.o
-obj-$(CONFIG_NE2000) += ne.o 8390p.o
-obj-$(CONFIG_NE2_MCA) += ne2.o 8390p.o
-obj-$(CONFIG_HPLAN) += hp.o 8390p.o
-obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390p.o
-obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o
-obj-$(CONFIG_ULTRAMCA) += smc-mca.o 8390.o
-obj-$(CONFIG_ULTRA32) += smc-ultra32.o 8390.o
-obj-$(CONFIG_E2100) += e2100.o 8390.o
-obj-$(CONFIG_ES3210) += es3210.o 8390.o
-obj-$(CONFIG_LNE390) += lne390.o 8390.o
-obj-$(CONFIG_NE3210) += ne3210.o 8390.o
-obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o
-obj-$(CONFIG_B44) += b44.o
-obj-$(CONFIG_FORCEDETH) += forcedeth.o
-obj-$(CONFIG_NE_H8300) += ne-h8300.o
-obj-$(CONFIG_AX88796) += ax88796.o
-obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o
-obj-$(CONFIG_FTGMAC100) += ftgmac100.o
-obj-$(CONFIG_FTMAC100) += ftmac100.o
-
-obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o
-obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o
-ll_temac-objs := ll_temac_main.o ll_temac_mdio.o
-obj-$(CONFIG_XILINX_LL_TEMAC) += ll_temac.o
-obj-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o
-obj-$(CONFIG_QLA3XXX) += qla3xxx.o
-obj-$(CONFIG_QLCNIC) += qlcnic/
-obj-$(CONFIG_QLGE) += qlge/
-
-obj-$(CONFIG_PPP) += ppp_generic.o
-obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
-obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o
-obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o
-obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o
-obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o
-obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
-obj-$(CONFIG_PPPOL2TP) += pppox.o
-obj-$(CONFIG_PPTP) += pppox.o pptp.o
-
-obj-$(CONFIG_SLIP) += slip.o
-obj-$(CONFIG_SLHC) += slhc.o
-
-obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o
-obj-$(CONFIG_XEN_NETDEV_BACKEND) += xen-netback/
-
+obj-$(CONFIG_BONDING) += bonding/
obj-$(CONFIG_DUMMY) += dummy.o
+obj-$(CONFIG_EQUALIZER) += eql.o
obj-$(CONFIG_IFB) += ifb.o
obj-$(CONFIG_MACVLAN) += macvlan.o
obj-$(CONFIG_MACVTAP) += macvtap.o
-obj-$(CONFIG_DE600) += de600.o
-obj-$(CONFIG_DE620) += de620.o
-obj-$(CONFIG_LANCE) += lance.o
-obj-$(CONFIG_SUN3_82586) += sun3_82586.o
-obj-$(CONFIG_SUN3LANCE) += sun3lance.o
-obj-$(CONFIG_DEFXX) += defxx.o
-obj-$(CONFIG_SGISEEQ) += sgiseeq.o
-obj-$(CONFIG_SGI_O2MACE_ETH) += meth.o
-obj-$(CONFIG_AT1700) += at1700.o
-obj-$(CONFIG_EL1) += 3c501.o
-obj-$(CONFIG_EL16) += 3c507.o
-obj-$(CONFIG_ELMC) += 3c523.o
-obj-$(CONFIG_IBMLANA) += ibmlana.o
-obj-$(CONFIG_ELMC_II) += 3c527.o
-obj-$(CONFIG_EL3) += 3c509.o
-obj-$(CONFIG_3C515) += 3c515.o
-obj-$(CONFIG_EEXPRESS) += eexpress.o
-obj-$(CONFIG_EEXPRESS_PRO) += eepro.o
-obj-$(CONFIG_8139CP) += 8139cp.o
-obj-$(CONFIG_8139TOO) += 8139too.o
-obj-$(CONFIG_ZNET) += znet.o
-obj-$(CONFIG_CPMAC) += cpmac.o
-obj-$(CONFIG_DEPCA) += depca.o
-obj-$(CONFIG_EWRK3) += ewrk3.o
-obj-$(CONFIG_ATP) += atp.o
-obj-$(CONFIG_NI5010) += ni5010.o
-obj-$(CONFIG_NI52) += ni52.o
-obj-$(CONFIG_NI65) += ni65.o
-obj-$(CONFIG_ELPLUS) += 3c505.o
-obj-$(CONFIG_AC3200) += ac3200.o 8390.o
-obj-$(CONFIG_APRICOT) += 82596.o
-obj-$(CONFIG_LASI_82596) += lasi_82596.o
-obj-$(CONFIG_SNI_82596) += sni_82596.o
-obj-$(CONFIG_MVME16x_NET) += 82596.o
-obj-$(CONFIG_BVME6000_NET) += 82596.o
-obj-$(CONFIG_SC92031) += sc92031.o
-
-# This is also a 82596 and should probably be merged
-obj-$(CONFIG_LP486E) += lp486e.o
-
-obj-$(CONFIG_ETH16I) += eth16i.o
-obj-$(CONFIG_ZORRO8390) += zorro8390.o
-obj-$(CONFIG_HPLANCE) += hplance.o 7990.o
-obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o
-obj-$(CONFIG_EQUALIZER) += eql.o
-obj-$(CONFIG_KORINA) += korina.o
-obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o
-obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
-obj-$(CONFIG_MIPS_SIM_NET) += mipsnet.o
-obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o
-obj-$(CONFIG_DECLANCE) += declance.o
-obj-$(CONFIG_ATARILANCE) += atarilance.o
-obj-$(CONFIG_A2065) += a2065.o
-obj-$(CONFIG_HYDRA) += hydra.o
-obj-$(CONFIG_ARIADNE) += ariadne.o
-obj-$(CONFIG_CS89x0) += cs89x0.o
-obj-$(CONFIG_MACSONIC) += macsonic.o
-obj-$(CONFIG_MACMACE) += macmace.o
-obj-$(CONFIG_MAC89x0) += mac89x0.o
+obj-$(CONFIG_MII) += mii.o
+obj-$(CONFIG_MDIO) += mdio.o
+obj-$(CONFIG_NET) += Space.o loopback.o
+obj-$(CONFIG_NETCONSOLE) += netconsole.o
+obj-$(CONFIG_PHYLIB) += phy/
+obj-$(CONFIG_RIONET) += rionet.o
obj-$(CONFIG_TUN) += tun.o
obj-$(CONFIG_VETH) += veth.o
-obj-$(CONFIG_NET_NETX) += netx-eth.o
-obj-$(CONFIG_DL2K) += dl2k.o
-obj-$(CONFIG_R8169) += r8169.o
-obj-$(CONFIG_AMD8111_ETH) += amd8111e.o
-obj-$(CONFIG_IBMVETH) += ibmveth.o
-obj-$(CONFIG_S2IO) += s2io.o
-obj-$(CONFIG_VXGE) += vxge/
-obj-$(CONFIG_MYRI10GE) += myri10ge/
-obj-$(CONFIG_SMC91X) += smc91x.o
-obj-$(CONFIG_SMC911X) += smc911x.o
-obj-$(CONFIG_SMSC911X) += smsc911x.o
-obj-$(CONFIG_PXA168_ETH) += pxa168_eth.o
-obj-$(CONFIG_BFIN_MAC) += bfin_mac.o
-obj-$(CONFIG_DM9000) += dm9000.o
-obj-$(CONFIG_PASEMI_MAC) += pasemi_mac_driver.o
-pasemi_mac_driver-objs := pasemi_mac.o pasemi_mac_ethtool.o
-obj-$(CONFIG_MLX4_CORE) += mlx4/
-obj-$(CONFIG_ENC28J60) += enc28j60.o
-obj-$(CONFIG_ETHOC) += ethoc.o
-obj-$(CONFIG_GRETH) += greth.o
-obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o
-
-obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o
-
-obj-$(CONFIG_DNET) += dnet.o
-obj-$(CONFIG_MACB) += macb.o
-obj-$(CONFIG_S6GMAC) += s6gmac.o
+obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
-obj-$(CONFIG_ARM) += arm/
+#
+# Networking Drivers
+#
+obj-$(CONFIG_ARCNET) += arcnet/
obj-$(CONFIG_DEV_APPLETALK) += appletalk/
+obj-$(CONFIG_CAIF) += caif/
+obj-$(CONFIG_CAN) += can/
+obj-$(CONFIG_ETRAX_ETHERNET) += cris/
+obj-$(CONFIG_ETHERNET) += ethernet/
+obj-$(CONFIG_FDDI) += fddi/
+obj-$(CONFIG_HIPPI) += hippi/
+obj-$(CONFIG_HAMRADIO) += hamradio/
+obj-$(CONFIG_IRDA) += irda/
+obj-$(CONFIG_PLIP) += plip/
+obj-$(CONFIG_PPP) += ppp/
+obj-$(CONFIG_PPP_ASYNC) += ppp/
+obj-$(CONFIG_PPP_BSDCOMP) += ppp/
+obj-$(CONFIG_PPP_DEFLATE) += ppp/
+obj-$(CONFIG_PPP_MPPE) += ppp/
+obj-$(CONFIG_PPP_SYNC_TTY) += ppp/
+obj-$(CONFIG_PPPOE) += ppp/
+obj-$(CONFIG_PPPOL2TP) += ppp/
+obj-$(CONFIG_PPTP) += ppp/
+obj-$(CONFIG_SLIP) += slip/
+obj-$(CONFIG_SLHC) += slip/
+obj-$(CONFIG_NET_SB1000) += sb1000.o
+obj-$(CONFIG_SUNGEM_PHY) += sungem_phy.o
obj-$(CONFIG_TR) += tokenring/
obj-$(CONFIG_WAN) += wan/
-obj-$(CONFIG_ARCNET) += arcnet/
-obj-$(CONFIG_NET_PCMCIA) += pcmcia/
+obj-$(CONFIG_WLAN) += wireless/
+obj-$(CONFIG_WIMAX) += wimax/
+
+obj-$(CONFIG_VMXNET3) += vmxnet3/
+obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o
+obj-$(CONFIG_XEN_NETDEV_BACKEND) += xen-netback/
obj-$(CONFIG_USB_CATC) += usb/
obj-$(CONFIG_USB_KAWETH) += usb/
@@ -283,26 +66,3 @@ obj-$(CONFIG_USB_USBNET) += usb/
obj-$(CONFIG_USB_ZD1201) += usb/
obj-$(CONFIG_USB_IPHETH) += usb/
obj-$(CONFIG_USB_CDC_PHONET) += usb/
-
-obj-$(CONFIG_WLAN) += wireless/
-obj-$(CONFIG_NET_TULIP) += tulip/
-obj-$(CONFIG_HAMRADIO) += hamradio/
-obj-$(CONFIG_IRDA) += irda/
-obj-$(CONFIG_ETRAX_ETHERNET) += cris/
-obj-$(CONFIG_ENP2611_MSF_NET) += ixp2000/
-
-obj-$(CONFIG_NETCONSOLE) += netconsole.o
-
-obj-$(CONFIG_FS_ENET) += fs_enet/
-
-obj-$(CONFIG_NETXEN_NIC) += netxen/
-obj-$(CONFIG_NIU) += niu.o
-obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
-obj-$(CONFIG_SFC) += sfc/
-
-obj-$(CONFIG_WIMAX) += wimax/
-obj-$(CONFIG_CAIF) += caif/
-
-obj-$(CONFIG_OCTEON_MGMT_ETHERNET) += octeon/
-obj-$(CONFIG_PCH_GBE) += pch_gbe/
-obj-$(CONFIG_TILE_NET) += tile/
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index 748c9f526e71..9abd4eb86dc1 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -264,7 +264,7 @@ static const struct net_device_ops cops_netdev_ops = {
.ndo_start_xmit = cops_send_packet,
.ndo_tx_timeout = cops_timeout,
.ndo_do_ioctl = cops_ioctl,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
};
/*
diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
index 34ffb5422628..6057b30417a2 100644
--- a/drivers/net/appletalk/ltpc.c
+++ b/drivers/net/appletalk/ltpc.c
@@ -1014,7 +1014,7 @@ static int __init ltpc_probe_dma(int base, int dma)
static const struct net_device_ops ltpc_netdev = {
.ndo_start_xmit = ltpc_xmit,
.ndo_do_ioctl = ltpc_ioctl,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
};
struct net_device * __init ltpc_probe(void)
diff --git a/drivers/net/arcnet/Kconfig b/drivers/net/arcnet/Kconfig
index 3b2f7f115464..a73d9dc80ff6 100644
--- a/drivers/net/arcnet/Kconfig
+++ b/drivers/net/arcnet/Kconfig
@@ -3,8 +3,8 @@
#
menuconfig ARCNET
- depends on NETDEVICES && (ISA || PCI)
- tristate "ARCnet support"
+ depends on NETDEVICES && (ISA || PCI || PCMCIA)
+ bool "ARCnet support"
---help---
If you have a network card of this type, say Y and check out the
(arguably) beautiful poetry in
@@ -123,4 +123,14 @@ config ARCNET_COM20020_PCI
tristate "Support for COM20020 on PCI"
depends on ARCNET_COM20020 && PCI
+config ARCNET_COM20020_CS
+ tristate "COM20020 ARCnet PCMCIA support"
+ depends on ARCNET_COM20020 && PCMCIA
+ help
+ Say Y here if you intend to attach this type of ARCnet PCMCIA card
+ to your computer.
+
+ To compile this driver as a module, choose M here: the module will be
+ called com20020_cs. If unsure, say N.
+
endif # ARCNET
diff --git a/drivers/net/arcnet/Makefile b/drivers/net/arcnet/Makefile
index 5861af543d42..5ce8ee63e435 100644
--- a/drivers/net/arcnet/Makefile
+++ b/drivers/net/arcnet/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_ARCNET_RIM_I) += arc-rimi.o
obj-$(CONFIG_ARCNET_COM20020) += com20020.o
obj-$(CONFIG_ARCNET_COM20020_ISA) += com20020-isa.o
obj-$(CONFIG_ARCNET_COM20020_PCI) += com20020-pci.o
+obj-$(CONFIG_ARCNET_COM20020_CS) += com20020_cs.o
diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c
index 7bfb91f32857..7b96c5f47e8d 100644
--- a/drivers/net/arcnet/com20020.c
+++ b/drivers/net/arcnet/com20020.c
@@ -154,7 +154,7 @@ const struct net_device_ops com20020_netdev_ops = {
.ndo_stop = arcnet_close,
.ndo_start_xmit = arcnet_send_packet,
.ndo_tx_timeout = arcnet_timeout,
- .ndo_set_multicast_list = com20020_set_mc_list,
+ .ndo_set_rx_mode = com20020_set_mc_list,
};
/* Set up the struct net_device associated with this card. Called after
diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/arcnet/com20020_cs.c
index 980e65c14936..980e65c14936 100644
--- a/drivers/net/pcmcia/com20020_cs.c
+++ b/drivers/net/arcnet/com20020_cs.c
diff --git a/drivers/net/arm/Kconfig b/drivers/net/arm/Kconfig
deleted file mode 100644
index 39e1c0d39476..000000000000
--- a/drivers/net/arm/Kconfig
+++ /dev/null
@@ -1,74 +0,0 @@
-#
-# Acorn Network device configuration
-# These are for Acorn's Expansion card network interfaces
-#
-config ARM_AM79C961A
- bool "ARM EBSA110 AM79C961A support"
- depends on ARM && ARCH_EBSA110
- select CRC32
- help
- If you wish to compile a kernel for the EBSA-110, then you should
- always answer Y to this.
-
-config ARM_ETHER1
- tristate "Acorn Ether1 support"
- depends on ARM && ARCH_ACORN
- help
- If you have an Acorn system with one of these (AKA25) network cards,
- you should say Y to this option if you wish to use it with Linux.
-
-config ARM_ETHER3
- tristate "Acorn/ANT Ether3 support"
- depends on ARM && ARCH_ACORN
- help
- If you have an Acorn system with one of these network cards, you
- should say Y to this option if you wish to use it with Linux.
-
-config ARM_ETHERH
- tristate "I-cubed EtherH/ANT EtherM support"
- depends on ARM && ARCH_ACORN
- select CRC32
- help
- If you have an Acorn system with one of these network cards, you
- should say Y to this option if you wish to use it with Linux.
-
-config ARM_AT91_ETHER
- tristate "AT91RM9200 Ethernet support"
- depends on ARM && ARCH_AT91RM9200
- select MII
- help
- If you wish to compile a kernel for the AT91RM9200 and enable
- ethernet support, then you should always answer Y to this.
-
-config ARM_KS8695_ETHER
- tristate "KS8695 Ethernet support"
- depends on ARM && ARCH_KS8695
- select MII
- help
- If you wish to compile a kernel for the KS8695 and want to
- use the internal ethernet then you should answer Y to this.
-
-config EP93XX_ETH
- tristate "EP93xx Ethernet support"
- depends on ARM && ARCH_EP93XX
- select MII
- help
- This is a driver for the ethernet hardware included in EP93xx CPUs.
- Say Y if you are building a kernel for EP93xx based devices.
-
-config IXP4XX_ETH
- tristate "Intel IXP4xx Ethernet support"
- depends on ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR
- select PHYLIB
- help
- Say Y here if you want to use built-in Ethernet ports
- on IXP4xx processor.
-
-config W90P910_ETH
- tristate "Nuvoton w90p910 Ethernet support"
- depends on ARM && ARCH_W90X900
- select PHYLIB
- select MII
- help
- Say Y here if you want to use built-in Ethernet ports
- on w90p910 processor.
diff --git a/drivers/net/arm/Makefile b/drivers/net/arm/Makefile
deleted file mode 100644
index 303171f589e6..000000000000
--- a/drivers/net/arm/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-# File: drivers/net/arm/Makefile
-#
-# Makefile for the ARM network device drivers
-#
-
-obj-$(CONFIG_ARM_AM79C961A) += am79c961a.o
-obj-$(CONFIG_ARM_ETHERH) += etherh.o
-obj-$(CONFIG_ARM_ETHER3) += ether3.o
-obj-$(CONFIG_ARM_ETHER1) += ether1.o
-obj-$(CONFIG_ARM_AT91_ETHER) += at91_ether.o
-obj-$(CONFIG_ARM_KS8695_ETHER) += ks8695net.o
-obj-$(CONFIG_EP93XX_ETH) += ep93xx_eth.o
-obj-$(CONFIG_IXP4XX_ETH) += ixp4xx_eth.o
-obj-$(CONFIG_W90P910_ETH) += w90p910_ether.o
diff --git a/drivers/net/benet/Kconfig b/drivers/net/benet/Kconfig
deleted file mode 100644
index 1a41a49bb619..000000000000
--- a/drivers/net/benet/Kconfig
+++ /dev/null
@@ -1,6 +0,0 @@
-config BE2NET
- tristate "ServerEngines' 10Gbps NIC - BladeEngine"
- depends on PCI && INET
- help
- This driver implements the NIC functionality for ServerEngines'
- 10Gbps network adapter - BladeEngine.
diff --git a/drivers/net/bna/bfa_ioc_ct.c b/drivers/net/bna/bfa_ioc_ct.c
deleted file mode 100644
index 87aecdf22cf9..000000000000
--- a/drivers/net/bna/bfa_ioc_ct.c
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * Linux network driver for Brocade Converged Network Adapter.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License (GPL) Version 2 as
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- */
-/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
- * All rights reserved
- * www.brocade.com
- */
-
-#include "bfa_ioc.h"
-#include "cna.h"
-#include "bfi.h"
-#include "bfi_ctreg.h"
-#include "bfa_defs.h"
-
-#define bfa_ioc_ct_sync_pos(__ioc) \
- ((u32) (1 << bfa_ioc_pcifn(__ioc)))
-#define BFA_IOC_SYNC_REQD_SH 16
-#define bfa_ioc_ct_get_sync_ackd(__val) (__val & 0x0000ffff)
-#define bfa_ioc_ct_clear_sync_ackd(__val) (__val & 0xffff0000)
-#define bfa_ioc_ct_get_sync_reqd(__val) (__val >> BFA_IOC_SYNC_REQD_SH)
-#define bfa_ioc_ct_sync_reqd_pos(__ioc) \
- (bfa_ioc_ct_sync_pos(__ioc) << BFA_IOC_SYNC_REQD_SH)
-
-/*
- * forward declarations
- */
-static bool bfa_ioc_ct_firmware_lock(struct bfa_ioc *ioc);
-static void bfa_ioc_ct_firmware_unlock(struct bfa_ioc *ioc);
-static void bfa_ioc_ct_reg_init(struct bfa_ioc *ioc);
-static void bfa_ioc_ct_map_port(struct bfa_ioc *ioc);
-static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc *ioc, bool msix);
-static void bfa_ioc_ct_notify_fail(struct bfa_ioc *ioc);
-static void bfa_ioc_ct_ownership_reset(struct bfa_ioc *ioc);
-static bool bfa_ioc_ct_sync_start(struct bfa_ioc *ioc);
-static void bfa_ioc_ct_sync_join(struct bfa_ioc *ioc);
-static void bfa_ioc_ct_sync_leave(struct bfa_ioc *ioc);
-static void bfa_ioc_ct_sync_ack(struct bfa_ioc *ioc);
-static bool bfa_ioc_ct_sync_complete(struct bfa_ioc *ioc);
-static enum bfa_status bfa_ioc_ct_pll_init(void __iomem *rb, bool fcmode);
-
-static struct bfa_ioc_hwif nw_hwif_ct;
-
-/**
- * Called from bfa_ioc_attach() to map asic specific calls.
- */
-void
-bfa_nw_ioc_set_ct_hwif(struct bfa_ioc *ioc)
-{
- nw_hwif_ct.ioc_pll_init = bfa_ioc_ct_pll_init;
- nw_hwif_ct.ioc_firmware_lock = bfa_ioc_ct_firmware_lock;
- nw_hwif_ct.ioc_firmware_unlock = bfa_ioc_ct_firmware_unlock;
- nw_hwif_ct.ioc_reg_init = bfa_ioc_ct_reg_init;
- nw_hwif_ct.ioc_map_port = bfa_ioc_ct_map_port;
- nw_hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set;
- nw_hwif_ct.ioc_notify_fail = bfa_ioc_ct_notify_fail;
- nw_hwif_ct.ioc_ownership_reset = bfa_ioc_ct_ownership_reset;
- nw_hwif_ct.ioc_sync_start = bfa_ioc_ct_sync_start;
- nw_hwif_ct.ioc_sync_join = bfa_ioc_ct_sync_join;
- nw_hwif_ct.ioc_sync_leave = bfa_ioc_ct_sync_leave;
- nw_hwif_ct.ioc_sync_ack = bfa_ioc_ct_sync_ack;
- nw_hwif_ct.ioc_sync_complete = bfa_ioc_ct_sync_complete;
-
- ioc->ioc_hwif = &nw_hwif_ct;
-}
-
-/**
- * Return true if firmware of current driver matches the running firmware.
- */
-static bool
-bfa_ioc_ct_firmware_lock(struct bfa_ioc *ioc)
-{
- enum bfi_ioc_state ioc_fwstate;
- u32 usecnt;
- struct bfi_ioc_image_hdr fwhdr;
-
- /**
- * Firmware match check is relevant only for CNA.
- */
- if (!ioc->cna)
- return true;
-
- /**
- * If bios boot (flash based) -- do not increment usage count
- */
- if (bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) <
- BFA_IOC_FWIMG_MINSZ)
- return true;
-
- bfa_nw_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
- usecnt = readl(ioc->ioc_regs.ioc_usage_reg);
-
- /**
- * If usage count is 0, always return TRUE.
- */
- if (usecnt == 0) {
- writel(1, ioc->ioc_regs.ioc_usage_reg);
- bfa_nw_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
- writel(0, ioc->ioc_regs.ioc_fail_sync);
- return true;
- }
-
- ioc_fwstate = readl(ioc->ioc_regs.ioc_fwstate);
-
- /**
- * Use count cannot be non-zero and chip in uninitialized state.
- */
- BUG_ON(!(ioc_fwstate != BFI_IOC_UNINIT));
-
- /**
- * Check if another driver with a different firmware is active
- */
- bfa_nw_ioc_fwver_get(ioc, &fwhdr);
- if (!bfa_nw_ioc_fwver_cmp(ioc, &fwhdr)) {
- bfa_nw_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
- return false;
- }
-
- /**
- * Same firmware version. Increment the reference count.
- */
- usecnt++;
- writel(usecnt, ioc->ioc_regs.ioc_usage_reg);
- bfa_nw_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
- return true;
-}
-
-static void
-bfa_ioc_ct_firmware_unlock(struct bfa_ioc *ioc)
-{
- u32 usecnt;
-
- /**
- * Firmware lock is relevant only for CNA.
- */
- if (!ioc->cna)
- return;
-
- /**
- * If bios boot (flash based) -- do not decrement usage count
- */
- if (bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) <
- BFA_IOC_FWIMG_MINSZ)
- return;
-
- /**
- * decrement usage count
- */
- bfa_nw_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
- usecnt = readl(ioc->ioc_regs.ioc_usage_reg);
- BUG_ON(!(usecnt > 0));
-
- usecnt--;
- writel(usecnt, ioc->ioc_regs.ioc_usage_reg);
-
- bfa_nw_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
-}
-
-/**
- * Notify other functions on HB failure.
- */
-static void
-bfa_ioc_ct_notify_fail(struct bfa_ioc *ioc)
-{
- if (ioc->cna) {
- writel(__FW_INIT_HALT_P, ioc->ioc_regs.ll_halt);
- writel(__FW_INIT_HALT_P, ioc->ioc_regs.alt_ll_halt);
- /* Wait for halt to take effect */
- readl(ioc->ioc_regs.ll_halt);
- readl(ioc->ioc_regs.alt_ll_halt);
- } else {
- writel(__PSS_ERR_STATUS_SET, ioc->ioc_regs.err_set);
- readl(ioc->ioc_regs.err_set);
- }
-}
-
-/**
- * Host to LPU mailbox message addresses
- */
-static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = {
- { HOSTFN0_LPU_MBOX0_0, LPU_HOSTFN0_MBOX0_0, HOST_PAGE_NUM_FN0 },
- { HOSTFN1_LPU_MBOX0_8, LPU_HOSTFN1_MBOX0_8, HOST_PAGE_NUM_FN1 },
- { HOSTFN2_LPU_MBOX0_0, LPU_HOSTFN2_MBOX0_0, HOST_PAGE_NUM_FN2 },
- { HOSTFN3_LPU_MBOX0_8, LPU_HOSTFN3_MBOX0_8, HOST_PAGE_NUM_FN3 }
-};
-
-/**
- * Host <-> LPU mailbox command/status registers - port 0
- */
-static struct { u32 hfn, lpu; } iocreg_mbcmd_p0[] = {
- { HOSTFN0_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN0_MBOX0_CMD_STAT },
- { HOSTFN1_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN1_MBOX0_CMD_STAT },
- { HOSTFN2_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN2_MBOX0_CMD_STAT },
- { HOSTFN3_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN3_MBOX0_CMD_STAT }
-};
-
-/**
- * Host <-> LPU mailbox command/status registers - port 1
- */
-static struct { u32 hfn, lpu; } iocreg_mbcmd_p1[] = {
- { HOSTFN0_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN0_MBOX0_CMD_STAT },
- { HOSTFN1_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN1_MBOX0_CMD_STAT },
- { HOSTFN2_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN2_MBOX0_CMD_STAT },
- { HOSTFN3_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN3_MBOX0_CMD_STAT }
-};
-
-static void
-bfa_ioc_ct_reg_init(struct bfa_ioc *ioc)
-{
- void __iomem *rb;
- int pcifn = bfa_ioc_pcifn(ioc);
-
- rb = bfa_ioc_bar0(ioc);
-
- ioc->ioc_regs.hfn_mbox = rb + iocreg_fnreg[pcifn].hfn_mbox;
- ioc->ioc_regs.lpu_mbox = rb + iocreg_fnreg[pcifn].lpu_mbox;
- ioc->ioc_regs.host_page_num_fn = rb + iocreg_fnreg[pcifn].hfn_pgn;
-
- if (ioc->port_id == 0) {
- ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG;
- ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG;
- ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC1_STATE_REG;
- ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].hfn;
- ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].lpu;
- ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0;
- ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P1;
- } else {
- ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG);
- ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG);
- ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC0_STATE_REG;
- ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].hfn;
- ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].lpu;
- ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1;
- ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P0;
- }
-
- /*
- * PSS control registers
- */
- ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG);
- ioc->ioc_regs.pss_err_status_reg = (rb + PSS_ERR_STATUS_REG);
- ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_425_CTL_REG);
- ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_312_CTL_REG);
-
- /*
- * IOC semaphore registers and serialization
- */
- ioc->ioc_regs.ioc_sem_reg = (rb + HOST_SEM0_REG);
- ioc->ioc_regs.ioc_usage_sem_reg = (rb + HOST_SEM1_REG);
- ioc->ioc_regs.ioc_init_sem_reg = (rb + HOST_SEM2_REG);
- ioc->ioc_regs.ioc_usage_reg = (rb + BFA_FW_USE_COUNT);
- ioc->ioc_regs.ioc_fail_sync = (rb + BFA_IOC_FAIL_SYNC);
-
- /**
- * sram memory access
- */
- ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START);
- ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CT;
-
- /*
- * err set reg : for notification of hb failure in fcmode
- */
- ioc->ioc_regs.err_set = (rb + ERR_SET_REG);
-}
-
-/**
- * Initialize IOC to port mapping.
- */
-
-#define FNC_PERS_FN_SHIFT(__fn) ((__fn) * 8)
-static void
-bfa_ioc_ct_map_port(struct bfa_ioc *ioc)
-{
- void __iomem *rb = ioc->pcidev.pci_bar_kva;
- u32 r32;
-
- /**
- * For catapult, base port id on personality register and IOC type
- */
- r32 = readl(rb + FNC_PERS_REG);
- r32 >>= FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc));
- ioc->port_id = (r32 & __F0_PORT_MAP_MK) >> __F0_PORT_MAP_SH;
-
-}
-
-/**
- * Set interrupt mode for a function: INTX or MSIX
- */
-static void
-bfa_ioc_ct_isr_mode_set(struct bfa_ioc *ioc, bool msix)
-{
- void __iomem *rb = ioc->pcidev.pci_bar_kva;
- u32 r32, mode;
-
- r32 = readl(rb + FNC_PERS_REG);
-
- mode = (r32 >> FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc))) &
- __F0_INTX_STATUS;
-
- /**
- * If already in desired mode, do not change anything
- */
- if (!msix && mode)
- return;
-
- if (msix)
- mode = __F0_INTX_STATUS_MSIX;
- else
- mode = __F0_INTX_STATUS_INTA;
-
- r32 &= ~(__F0_INTX_STATUS << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc)));
- r32 |= (mode << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc)));
-
- writel(r32, rb + FNC_PERS_REG);
-}
-
-/**
- * Cleanup hw semaphore and usecnt registers
- */
-static void
-bfa_ioc_ct_ownership_reset(struct bfa_ioc *ioc)
-{
- if (ioc->cna) {
- bfa_nw_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
- writel(0, ioc->ioc_regs.ioc_usage_reg);
- bfa_nw_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
- }
-
- /*
- * Read the hw sem reg to make sure that it is locked
- * before we clear it. If it is not locked, writing 1
- * will lock it instead of clearing it.
- */
- readl(ioc->ioc_regs.ioc_sem_reg);
- bfa_nw_ioc_hw_sem_release(ioc);
-}
-
-/**
- * Synchronized IOC failure processing routines
- */
-static bool
-bfa_ioc_ct_sync_start(struct bfa_ioc *ioc)
-{
- u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync);
- u32 sync_reqd = bfa_ioc_ct_get_sync_reqd(r32);
-
- /*
- * Driver load time. If the sync required bit for this PCI fn
- * is set, it is due to an unclean exit by the driver for this
- * PCI fn in the previous incarnation. Whoever comes here first
- * should clean it up, no matter which PCI fn.
- */
-
- if (sync_reqd & bfa_ioc_ct_sync_pos(ioc)) {
- writel(0, ioc->ioc_regs.ioc_fail_sync);
- writel(1, ioc->ioc_regs.ioc_usage_reg);
- writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate);
- writel(BFI_IOC_UNINIT, ioc->ioc_regs.alt_ioc_fwstate);
- return true;
- }
-
- return bfa_ioc_ct_sync_complete(ioc);
-}
-/**
- * Synchronized IOC failure processing routines
- */
-static void
-bfa_ioc_ct_sync_join(struct bfa_ioc *ioc)
-{
- u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync);
- u32 sync_pos = bfa_ioc_ct_sync_reqd_pos(ioc);
-
- writel((r32 | sync_pos), ioc->ioc_regs.ioc_fail_sync);
-}
-
-static void
-bfa_ioc_ct_sync_leave(struct bfa_ioc *ioc)
-{
- u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync);
- u32 sync_msk = bfa_ioc_ct_sync_reqd_pos(ioc) |
- bfa_ioc_ct_sync_pos(ioc);
-
- writel((r32 & ~sync_msk), ioc->ioc_regs.ioc_fail_sync);
-}
-
-static void
-bfa_ioc_ct_sync_ack(struct bfa_ioc *ioc)
-{
- u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync);
-
- writel((r32 | bfa_ioc_ct_sync_pos(ioc)), ioc->ioc_regs.ioc_fail_sync);
-}
-
-static bool
-bfa_ioc_ct_sync_complete(struct bfa_ioc *ioc)
-{
- u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync);
- u32 sync_reqd = bfa_ioc_ct_get_sync_reqd(r32);
- u32 sync_ackd = bfa_ioc_ct_get_sync_ackd(r32);
- u32 tmp_ackd;
-
- if (sync_ackd == 0)
- return true;
-
- /**
- * The check below is to see whether any other PCI fn
- * has reinitialized the ASIC (reset sync_ackd bits)
- * and failed again while this IOC was waiting for hw
- * semaphore (in bfa_iocpf_sm_semwait()).
- */
- tmp_ackd = sync_ackd;
- if ((sync_reqd & bfa_ioc_ct_sync_pos(ioc)) &&
- !(sync_ackd & bfa_ioc_ct_sync_pos(ioc)))
- sync_ackd |= bfa_ioc_ct_sync_pos(ioc);
-
- if (sync_reqd == sync_ackd) {
- writel(bfa_ioc_ct_clear_sync_ackd(r32),
- ioc->ioc_regs.ioc_fail_sync);
- writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
- writel(BFI_IOC_FAIL, ioc->ioc_regs.alt_ioc_fwstate);
- return true;
- }
-
- /**
- * If another PCI fn reinitialized and failed again while
- * this IOC was waiting for hw sem, the sync_ackd bit for
- * this IOC need to be set again to allow reinitialization.
- */
- if (tmp_ackd != sync_ackd)
- writel((r32 | sync_ackd), ioc->ioc_regs.ioc_fail_sync);
-
- return false;
-}
-
-static enum bfa_status
-bfa_ioc_ct_pll_init(void __iomem *rb, bool fcmode)
-{
- u32 pll_sclk, pll_fclk, r32;
-
- pll_sclk = __APP_PLL_312_LRESETN | __APP_PLL_312_ENARST |
- __APP_PLL_312_RSEL200500 | __APP_PLL_312_P0_1(3U) |
- __APP_PLL_312_JITLMT0_1(3U) |
- __APP_PLL_312_CNTLMT0_1(1U);
- pll_fclk = __APP_PLL_425_LRESETN | __APP_PLL_425_ENARST |
- __APP_PLL_425_RSEL200500 | __APP_PLL_425_P0_1(3U) |
- __APP_PLL_425_JITLMT0_1(3U) |
- __APP_PLL_425_CNTLMT0_1(1U);
- if (fcmode) {
- writel(0, (rb + OP_MODE));
- writel(__APP_EMS_CMLCKSEL |
- __APP_EMS_REFCKBUFEN2 |
- __APP_EMS_CHANNEL_SEL,
- (rb + ETH_MAC_SER_REG));
- } else {
- writel(__GLOBAL_FCOE_MODE, (rb + OP_MODE));
- writel(__APP_EMS_REFCKBUFEN1,
- (rb + ETH_MAC_SER_REG));
- }
- writel(BFI_IOC_UNINIT, (rb + BFA_IOC0_STATE_REG));
- writel(BFI_IOC_UNINIT, (rb + BFA_IOC1_STATE_REG));
- writel(0xffffffffU, (rb + HOSTFN0_INT_MSK));
- writel(0xffffffffU, (rb + HOSTFN1_INT_MSK));
- writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS));
- writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS));
- writel(0xffffffffU, (rb + HOSTFN0_INT_MSK));
- writel(0xffffffffU, (rb + HOSTFN1_INT_MSK));
- writel(pll_sclk |
- __APP_PLL_312_LOGIC_SOFT_RESET,
- rb + APP_PLL_312_CTL_REG);
- writel(pll_fclk |
- __APP_PLL_425_LOGIC_SOFT_RESET,
- rb + APP_PLL_425_CTL_REG);
- writel(pll_sclk |
- __APP_PLL_312_LOGIC_SOFT_RESET | __APP_PLL_312_ENABLE,
- rb + APP_PLL_312_CTL_REG);
- writel(pll_fclk |
- __APP_PLL_425_LOGIC_SOFT_RESET | __APP_PLL_425_ENABLE,
- rb + APP_PLL_425_CTL_REG);
- readl(rb + HOSTFN0_INT_MSK);
- udelay(2000);
- writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS));
- writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS));
- writel(pll_sclk |
- __APP_PLL_312_ENABLE,
- rb + APP_PLL_312_CTL_REG);
- writel(pll_fclk |
- __APP_PLL_425_ENABLE,
- rb + APP_PLL_425_CTL_REG);
- if (!fcmode) {
- writel(__PMM_1T_RESET_P, (rb + PMM_1T_RESET_REG_P0));
- writel(__PMM_1T_RESET_P, (rb + PMM_1T_RESET_REG_P1));
- }
- r32 = readl((rb + PSS_CTL_REG));
- r32 &= ~__PSS_LMEM_RESET;
- writel(r32, (rb + PSS_CTL_REG));
- udelay(1000);
- if (!fcmode) {
- writel(0, (rb + PMM_1T_RESET_REG_P0));
- writel(0, (rb + PMM_1T_RESET_REG_P1));
- }
-
- writel(__EDRAM_BISTR_START, (rb + MBIST_CTL_REG));
- udelay(1000);
- r32 = readl((rb + MBIST_STAT_REG));
- writel(0, (rb + MBIST_CTL_REG));
- return BFA_STATUS_OK;
-}
diff --git a/drivers/net/bna/bfi_ctreg.h b/drivers/net/bna/bfi_ctreg.h
deleted file mode 100644
index 5130d7918660..000000000000
--- a/drivers/net/bna/bfi_ctreg.h
+++ /dev/null
@@ -1,646 +0,0 @@
-/*
- * Linux network driver for Brocade Converged Network Adapter.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License (GPL) Version 2 as
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- */
-/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
- * All rights reserved
- * www.brocade.com
- */
-
-/*
- * bfi_ctreg.h catapult host block register definitions
- *
- * !!! Do not edit. Auto generated. !!!
- */
-
-#ifndef __BFI_CTREG_H__
-#define __BFI_CTREG_H__
-
-#define HOSTFN0_LPU_MBOX0_0 0x00019200
-#define HOSTFN1_LPU_MBOX0_8 0x00019260
-#define LPU_HOSTFN0_MBOX0_0 0x00019280
-#define LPU_HOSTFN1_MBOX0_8 0x000192e0
-#define HOSTFN2_LPU_MBOX0_0 0x00019400
-#define HOSTFN3_LPU_MBOX0_8 0x00019460
-#define LPU_HOSTFN2_MBOX0_0 0x00019480
-#define LPU_HOSTFN3_MBOX0_8 0x000194e0
-#define HOSTFN0_INT_STATUS 0x00014000
-#define __HOSTFN0_HALT_OCCURRED 0x01000000
-#define __HOSTFN0_INT_STATUS_LVL_MK 0x00f00000
-#define __HOSTFN0_INT_STATUS_LVL_SH 20
-#define __HOSTFN0_INT_STATUS_LVL(_v) ((_v) << __HOSTFN0_INT_STATUS_LVL_SH)
-#define __HOSTFN0_INT_STATUS_P_MK 0x000f0000
-#define __HOSTFN0_INT_STATUS_P_SH 16
-#define __HOSTFN0_INT_STATUS_P(_v) ((_v) << __HOSTFN0_INT_STATUS_P_SH)
-#define __HOSTFN0_INT_STATUS_F 0x0000ffff
-#define HOSTFN0_INT_MSK 0x00014004
-#define HOST_PAGE_NUM_FN0 0x00014008
-#define __HOST_PAGE_NUM_FN 0x000001ff
-#define HOST_MSIX_ERR_INDEX_FN0 0x0001400c
-#define __MSIX_ERR_INDEX_FN 0x000001ff
-#define HOSTFN1_INT_STATUS 0x00014100
-#define __HOSTFN1_HALT_OCCURRED 0x01000000
-#define __HOSTFN1_INT_STATUS_LVL_MK 0x00f00000
-#define __HOSTFN1_INT_STATUS_LVL_SH 20
-#define __HOSTFN1_INT_STATUS_LVL(_v) ((_v) << __HOSTFN1_INT_STATUS_LVL_SH)
-#define __HOSTFN1_INT_STATUS_P_MK 0x000f0000
-#define __HOSTFN1_INT_STATUS_P_SH 16
-#define __HOSTFN1_INT_STATUS_P(_v) ((_v) << __HOSTFN1_INT_STATUS_P_SH)
-#define __HOSTFN1_INT_STATUS_F 0x0000ffff
-#define HOSTFN1_INT_MSK 0x00014104
-#define HOST_PAGE_NUM_FN1 0x00014108
-#define HOST_MSIX_ERR_INDEX_FN1 0x0001410c
-#define APP_PLL_425_CTL_REG 0x00014204
-#define __P_425_PLL_LOCK 0x80000000
-#define __APP_PLL_425_SRAM_USE_100MHZ 0x00100000
-#define __APP_PLL_425_RESET_TIMER_MK 0x000e0000
-#define __APP_PLL_425_RESET_TIMER_SH 17
-#define __APP_PLL_425_RESET_TIMER(_v) ((_v) << __APP_PLL_425_RESET_TIMER_SH)
-#define __APP_PLL_425_LOGIC_SOFT_RESET 0x00010000
-#define __APP_PLL_425_CNTLMT0_1_MK 0x0000c000
-#define __APP_PLL_425_CNTLMT0_1_SH 14
-#define __APP_PLL_425_CNTLMT0_1(_v) ((_v) << __APP_PLL_425_CNTLMT0_1_SH)
-#define __APP_PLL_425_JITLMT0_1_MK 0x00003000
-#define __APP_PLL_425_JITLMT0_1_SH 12
-#define __APP_PLL_425_JITLMT0_1(_v) ((_v) << __APP_PLL_425_JITLMT0_1_SH)
-#define __APP_PLL_425_HREF 0x00000800
-#define __APP_PLL_425_HDIV 0x00000400
-#define __APP_PLL_425_P0_1_MK 0x00000300
-#define __APP_PLL_425_P0_1_SH 8
-#define __APP_PLL_425_P0_1(_v) ((_v) << __APP_PLL_425_P0_1_SH)
-#define __APP_PLL_425_Z0_2_MK 0x000000e0
-#define __APP_PLL_425_Z0_2_SH 5
-#define __APP_PLL_425_Z0_2(_v) ((_v) << __APP_PLL_425_Z0_2_SH)
-#define __APP_PLL_425_RSEL200500 0x00000010
-#define __APP_PLL_425_ENARST 0x00000008
-#define __APP_PLL_425_BYPASS 0x00000004
-#define __APP_PLL_425_LRESETN 0x00000002
-#define __APP_PLL_425_ENABLE 0x00000001
-#define APP_PLL_312_CTL_REG 0x00014208
-#define __P_312_PLL_LOCK 0x80000000
-#define __ENABLE_MAC_AHB_1 0x00800000
-#define __ENABLE_MAC_AHB_0 0x00400000
-#define __ENABLE_MAC_1 0x00200000
-#define __ENABLE_MAC_0 0x00100000
-#define __APP_PLL_312_RESET_TIMER_MK 0x000e0000
-#define __APP_PLL_312_RESET_TIMER_SH 17
-#define __APP_PLL_312_RESET_TIMER(_v) ((_v) << __APP_PLL_312_RESET_TIMER_SH)
-#define __APP_PLL_312_LOGIC_SOFT_RESET 0x00010000
-#define __APP_PLL_312_CNTLMT0_1_MK 0x0000c000
-#define __APP_PLL_312_CNTLMT0_1_SH 14
-#define __APP_PLL_312_CNTLMT0_1(_v) ((_v) << __APP_PLL_312_CNTLMT0_1_SH)
-#define __APP_PLL_312_JITLMT0_1_MK 0x00003000
-#define __APP_PLL_312_JITLMT0_1_SH 12
-#define __APP_PLL_312_JITLMT0_1(_v) ((_v) << __APP_PLL_312_JITLMT0_1_SH)
-#define __APP_PLL_312_HREF 0x00000800
-#define __APP_PLL_312_HDIV 0x00000400
-#define __APP_PLL_312_P0_1_MK 0x00000300
-#define __APP_PLL_312_P0_1_SH 8
-#define __APP_PLL_312_P0_1(_v) ((_v) << __APP_PLL_312_P0_1_SH)
-#define __APP_PLL_312_Z0_2_MK 0x000000e0
-#define __APP_PLL_312_Z0_2_SH 5
-#define __APP_PLL_312_Z0_2(_v) ((_v) << __APP_PLL_312_Z0_2_SH)
-#define __APP_PLL_312_RSEL200500 0x00000010
-#define __APP_PLL_312_ENARST 0x00000008
-#define __APP_PLL_312_BYPASS 0x00000004
-#define __APP_PLL_312_LRESETN 0x00000002
-#define __APP_PLL_312_ENABLE 0x00000001
-#define MBIST_CTL_REG 0x00014220
-#define __EDRAM_BISTR_START 0x00000004
-#define __MBIST_RESET 0x00000002
-#define __MBIST_START 0x00000001
-#define MBIST_STAT_REG 0x00014224
-#define __EDRAM_BISTR_STATUS 0x00000008
-#define __EDRAM_BISTR_DONE 0x00000004
-#define __MEM_BIT_STATUS 0x00000002
-#define __MBIST_DONE 0x00000001
-#define HOST_SEM0_REG 0x00014230
-#define __HOST_SEMAPHORE 0x00000001
-#define HOST_SEM1_REG 0x00014234
-#define HOST_SEM2_REG 0x00014238
-#define HOST_SEM3_REG 0x0001423c
-#define HOST_SEM0_INFO_REG 0x00014240
-#define HOST_SEM1_INFO_REG 0x00014244
-#define HOST_SEM2_INFO_REG 0x00014248
-#define HOST_SEM3_INFO_REG 0x0001424c
-#define ETH_MAC_SER_REG 0x00014288
-#define __APP_EMS_CKBUFAMPIN 0x00000020
-#define __APP_EMS_REFCLKSEL 0x00000010
-#define __APP_EMS_CMLCKSEL 0x00000008
-#define __APP_EMS_REFCKBUFEN2 0x00000004
-#define __APP_EMS_REFCKBUFEN1 0x00000002
-#define __APP_EMS_CHANNEL_SEL 0x00000001
-#define HOSTFN2_INT_STATUS 0x00014300
-#define __HOSTFN2_HALT_OCCURRED 0x01000000
-#define __HOSTFN2_INT_STATUS_LVL_MK 0x00f00000
-#define __HOSTFN2_INT_STATUS_LVL_SH 20
-#define __HOSTFN2_INT_STATUS_LVL(_v) ((_v) << __HOSTFN2_INT_STATUS_LVL_SH)
-#define __HOSTFN2_INT_STATUS_P_MK 0x000f0000
-#define __HOSTFN2_INT_STATUS_P_SH 16
-#define __HOSTFN2_INT_STATUS_P(_v) ((_v) << __HOSTFN2_INT_STATUS_P_SH)
-#define __HOSTFN2_INT_STATUS_F 0x0000ffff
-#define HOSTFN2_INT_MSK 0x00014304
-#define HOST_PAGE_NUM_FN2 0x00014308
-#define HOST_MSIX_ERR_INDEX_FN2 0x0001430c
-#define HOSTFN3_INT_STATUS 0x00014400
-#define __HALT_OCCURRED 0x01000000
-#define __HOSTFN3_INT_STATUS_LVL_MK 0x00f00000
-#define __HOSTFN3_INT_STATUS_LVL_SH 20
-#define __HOSTFN3_INT_STATUS_LVL(_v) ((_v) << __HOSTFN3_INT_STATUS_LVL_SH)
-#define __HOSTFN3_INT_STATUS_P_MK 0x000f0000
-#define __HOSTFN3_INT_STATUS_P_SH 16
-#define __HOSTFN3_INT_STATUS_P(_v) ((_v) << __HOSTFN3_INT_STATUS_P_SH)
-#define __HOSTFN3_INT_STATUS_F 0x0000ffff
-#define HOSTFN3_INT_MSK 0x00014404
-#define HOST_PAGE_NUM_FN3 0x00014408
-#define HOST_MSIX_ERR_INDEX_FN3 0x0001440c
-#define FNC_ID_REG 0x00014600
-#define __FUNCTION_NUMBER 0x00000007
-#define FNC_PERS_REG 0x00014604
-#define __F3_FUNCTION_ACTIVE 0x80000000
-#define __F3_FUNCTION_MODE 0x40000000
-#define __F3_PORT_MAP_MK 0x30000000
-#define __F3_PORT_MAP_SH 28
-#define __F3_PORT_MAP(_v) ((_v) << __F3_PORT_MAP_SH)
-#define __F3_VM_MODE 0x08000000
-#define __F3_INTX_STATUS_MK 0x07000000
-#define __F3_INTX_STATUS_SH 24
-#define __F3_INTX_STATUS(_v) ((_v) << __F3_INTX_STATUS_SH)
-#define __F2_FUNCTION_ACTIVE 0x00800000
-#define __F2_FUNCTION_MODE 0x00400000
-#define __F2_PORT_MAP_MK 0x00300000
-#define __F2_PORT_MAP_SH 20
-#define __F2_PORT_MAP(_v) ((_v) << __F2_PORT_MAP_SH)
-#define __F2_VM_MODE 0x00080000
-#define __F2_INTX_STATUS_MK 0x00070000
-#define __F2_INTX_STATUS_SH 16
-#define __F2_INTX_STATUS(_v) ((_v) << __F2_INTX_STATUS_SH)
-#define __F1_FUNCTION_ACTIVE 0x00008000
-#define __F1_FUNCTION_MODE 0x00004000
-#define __F1_PORT_MAP_MK 0x00003000
-#define __F1_PORT_MAP_SH 12
-#define __F1_PORT_MAP(_v) ((_v) << __F1_PORT_MAP_SH)
-#define __F1_VM_MODE 0x00000800
-#define __F1_INTX_STATUS_MK 0x00000700
-#define __F1_INTX_STATUS_SH 8
-#define __F1_INTX_STATUS(_v) ((_v) << __F1_INTX_STATUS_SH)
-#define __F0_FUNCTION_ACTIVE 0x00000080
-#define __F0_FUNCTION_MODE 0x00000040
-#define __F0_PORT_MAP_MK 0x00000030
-#define __F0_PORT_MAP_SH 4
-#define __F0_PORT_MAP(_v) ((_v) << __F0_PORT_MAP_SH)
-#define __F0_VM_MODE 0x00000008
-#define __F0_INTX_STATUS 0x00000007
-enum {
- __F0_INTX_STATUS_MSIX = 0x0,
- __F0_INTX_STATUS_INTA = 0x1,
- __F0_INTX_STATUS_INTB = 0x2,
- __F0_INTX_STATUS_INTC = 0x3,
- __F0_INTX_STATUS_INTD = 0x4,
-};
-#define OP_MODE 0x0001460c
-#define __APP_ETH_CLK_LOWSPEED 0x00000004
-#define __GLOBAL_CORECLK_HALFSPEED 0x00000002
-#define __GLOBAL_FCOE_MODE 0x00000001
-#define HOST_SEM4_REG 0x00014610
-#define HOST_SEM5_REG 0x00014614
-#define HOST_SEM6_REG 0x00014618
-#define HOST_SEM7_REG 0x0001461c
-#define HOST_SEM4_INFO_REG 0x00014620
-#define HOST_SEM5_INFO_REG 0x00014624
-#define HOST_SEM6_INFO_REG 0x00014628
-#define HOST_SEM7_INFO_REG 0x0001462c
-#define HOSTFN0_LPU0_MBOX0_CMD_STAT 0x00019000
-#define __HOSTFN0_LPU0_MBOX0_INFO_MK 0xfffffffe
-#define __HOSTFN0_LPU0_MBOX0_INFO_SH 1
-#define __HOSTFN0_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN0_LPU0_MBOX0_INFO_SH)
-#define __HOSTFN0_LPU0_MBOX0_CMD_STATUS 0x00000001
-#define HOSTFN0_LPU1_MBOX0_CMD_STAT 0x00019004
-#define __HOSTFN0_LPU1_MBOX0_INFO_MK 0xfffffffe
-#define __HOSTFN0_LPU1_MBOX0_INFO_SH 1
-#define __HOSTFN0_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN0_LPU1_MBOX0_INFO_SH)
-#define __HOSTFN0_LPU1_MBOX0_CMD_STATUS 0x00000001
-#define LPU0_HOSTFN0_MBOX0_CMD_STAT 0x00019008
-#define __LPU0_HOSTFN0_MBOX0_INFO_MK 0xfffffffe
-#define __LPU0_HOSTFN0_MBOX0_INFO_SH 1
-#define __LPU0_HOSTFN0_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN0_MBOX0_INFO_SH)
-#define __LPU0_HOSTFN0_MBOX0_CMD_STATUS 0x00000001
-#define LPU1_HOSTFN0_MBOX0_CMD_STAT 0x0001900c
-#define __LPU1_HOSTFN0_MBOX0_INFO_MK 0xfffffffe
-#define __LPU1_HOSTFN0_MBOX0_INFO_SH 1
-#define __LPU1_HOSTFN0_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN0_MBOX0_INFO_SH)
-#define __LPU1_HOSTFN0_MBOX0_CMD_STATUS 0x00000001
-#define HOSTFN1_LPU0_MBOX0_CMD_STAT 0x00019010
-#define __HOSTFN1_LPU0_MBOX0_INFO_MK 0xfffffffe
-#define __HOSTFN1_LPU0_MBOX0_INFO_SH 1
-#define __HOSTFN1_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN1_LPU0_MBOX0_INFO_SH)
-#define __HOSTFN1_LPU0_MBOX0_CMD_STATUS 0x00000001
-#define HOSTFN1_LPU1_MBOX0_CMD_STAT 0x00019014
-#define __HOSTFN1_LPU1_MBOX0_INFO_MK 0xfffffffe
-#define __HOSTFN1_LPU1_MBOX0_INFO_SH 1
-#define __HOSTFN1_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN1_LPU1_MBOX0_INFO_SH)
-#define __HOSTFN1_LPU1_MBOX0_CMD_STATUS 0x00000001
-#define LPU0_HOSTFN1_MBOX0_CMD_STAT 0x00019018
-#define __LPU0_HOSTFN1_MBOX0_INFO_MK 0xfffffffe
-#define __LPU0_HOSTFN1_MBOX0_INFO_SH 1
-#define __LPU0_HOSTFN1_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN1_MBOX0_INFO_SH)
-#define __LPU0_HOSTFN1_MBOX0_CMD_STATUS 0x00000001
-#define LPU1_HOSTFN1_MBOX0_CMD_STAT 0x0001901c
-#define __LPU1_HOSTFN1_MBOX0_INFO_MK 0xfffffffe
-#define __LPU1_HOSTFN1_MBOX0_INFO_SH 1
-#define __LPU1_HOSTFN1_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN1_MBOX0_INFO_SH)
-#define __LPU1_HOSTFN1_MBOX0_CMD_STATUS 0x00000001
-#define HOSTFN2_LPU0_MBOX0_CMD_STAT 0x00019150
-#define __HOSTFN2_LPU0_MBOX0_INFO_MK 0xfffffffe
-#define __HOSTFN2_LPU0_MBOX0_INFO_SH 1
-#define __HOSTFN2_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN2_LPU0_MBOX0_INFO_SH)
-#define __HOSTFN2_LPU0_MBOX0_CMD_STATUS 0x00000001
-#define HOSTFN2_LPU1_MBOX0_CMD_STAT 0x00019154
-#define __HOSTFN2_LPU1_MBOX0_INFO_MK 0xfffffffe
-#define __HOSTFN2_LPU1_MBOX0_INFO_SH 1
-#define __HOSTFN2_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN2_LPU1_MBOX0_INFO_SH)
-#define __HOSTFN2_LPU1_MBOX0BOX0_CMD_STATUS 0x00000001
-#define LPU0_HOSTFN2_MBOX0_CMD_STAT 0x00019158
-#define __LPU0_HOSTFN2_MBOX0_INFO_MK 0xfffffffe
-#define __LPU0_HOSTFN2_MBOX0_INFO_SH 1
-#define __LPU0_HOSTFN2_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN2_MBOX0_INFO_SH)
-#define __LPU0_HOSTFN2_MBOX0_CMD_STATUS 0x00000001
-#define LPU1_HOSTFN2_MBOX0_CMD_STAT 0x0001915c
-#define __LPU1_HOSTFN2_MBOX0_INFO_MK 0xfffffffe
-#define __LPU1_HOSTFN2_MBOX0_INFO_SH 1
-#define __LPU1_HOSTFN2_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN2_MBOX0_INFO_SH)
-#define __LPU1_HOSTFN2_MBOX0_CMD_STATUS 0x00000001
-#define HOSTFN3_LPU0_MBOX0_CMD_STAT 0x00019160
-#define __HOSTFN3_LPU0_MBOX0_INFO_MK 0xfffffffe
-#define __HOSTFN3_LPU0_MBOX0_INFO_SH 1
-#define __HOSTFN3_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN3_LPU0_MBOX0_INFO_SH)
-#define __HOSTFN3_LPU0_MBOX0_CMD_STATUS 0x00000001
-#define HOSTFN3_LPU1_MBOX0_CMD_STAT 0x00019164
-#define __HOSTFN3_LPU1_MBOX0_INFO_MK 0xfffffffe
-#define __HOSTFN3_LPU1_MBOX0_INFO_SH 1
-#define __HOSTFN3_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN3_LPU1_MBOX0_INFO_SH)
-#define __HOSTFN3_LPU1_MBOX0_CMD_STATUS 0x00000001
-#define LPU0_HOSTFN3_MBOX0_CMD_STAT 0x00019168
-#define __LPU0_HOSTFN3_MBOX0_INFO_MK 0xfffffffe
-#define __LPU0_HOSTFN3_MBOX0_INFO_SH 1
-#define __LPU0_HOSTFN3_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN3_MBOX0_INFO_SH)
-#define __LPU0_HOSTFN3_MBOX0_CMD_STATUS 0x00000001
-#define LPU1_HOSTFN3_MBOX0_CMD_STAT 0x0001916c
-#define __LPU1_HOSTFN3_MBOX0_INFO_MK 0xfffffffe
-#define __LPU1_HOSTFN3_MBOX0_INFO_SH 1
-#define __LPU1_HOSTFN3_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN3_MBOX0_INFO_SH)
-#define __LPU1_HOSTFN3_MBOX0_CMD_STATUS 0x00000001
-#define FW_INIT_HALT_P0 0x000191ac
-#define __FW_INIT_HALT_P 0x00000001
-#define FW_INIT_HALT_P1 0x000191bc
-#define CPE_PI_PTR_Q0 0x00038000
-#define __CPE_PI_UNUSED_MK 0xffff0000
-#define __CPE_PI_UNUSED_SH 16
-#define __CPE_PI_UNUSED(_v) ((_v) << __CPE_PI_UNUSED_SH)
-#define __CPE_PI_PTR 0x0000ffff
-#define CPE_PI_PTR_Q1 0x00038040
-#define CPE_CI_PTR_Q0 0x00038004
-#define __CPE_CI_UNUSED_MK 0xffff0000
-#define __CPE_CI_UNUSED_SH 16
-#define __CPE_CI_UNUSED(_v) ((_v) << __CPE_CI_UNUSED_SH)
-#define __CPE_CI_PTR 0x0000ffff
-#define CPE_CI_PTR_Q1 0x00038044
-#define CPE_DEPTH_Q0 0x00038008
-#define __CPE_DEPTH_UNUSED_MK 0xf8000000
-#define __CPE_DEPTH_UNUSED_SH 27
-#define __CPE_DEPTH_UNUSED(_v) ((_v) << __CPE_DEPTH_UNUSED_SH)
-#define __CPE_MSIX_VEC_INDEX_MK 0x07ff0000
-#define __CPE_MSIX_VEC_INDEX_SH 16
-#define __CPE_MSIX_VEC_INDEX(_v) ((_v) << __CPE_MSIX_VEC_INDEX_SH)
-#define __CPE_DEPTH 0x0000ffff
-#define CPE_DEPTH_Q1 0x00038048
-#define CPE_QCTRL_Q0 0x0003800c
-#define __CPE_CTRL_UNUSED30_MK 0xfc000000
-#define __CPE_CTRL_UNUSED30_SH 26
-#define __CPE_CTRL_UNUSED30(_v) ((_v) << __CPE_CTRL_UNUSED30_SH)
-#define __CPE_FUNC_INT_CTRL_MK 0x03000000
-#define __CPE_FUNC_INT_CTRL_SH 24
-#define __CPE_FUNC_INT_CTRL(_v) ((_v) << __CPE_FUNC_INT_CTRL_SH)
-enum {
- __CPE_FUNC_INT_CTRL_DISABLE = 0x0,
- __CPE_FUNC_INT_CTRL_F2NF = 0x1,
- __CPE_FUNC_INT_CTRL_3QUART = 0x2,
- __CPE_FUNC_INT_CTRL_HALF = 0x3,
-};
-#define __CPE_CTRL_UNUSED20_MK 0x00f00000
-#define __CPE_CTRL_UNUSED20_SH 20
-#define __CPE_CTRL_UNUSED20(_v) ((_v) << __CPE_CTRL_UNUSED20_SH)
-#define __CPE_SCI_TH_MK 0x000f0000
-#define __CPE_SCI_TH_SH 16
-#define __CPE_SCI_TH(_v) ((_v) << __CPE_SCI_TH_SH)
-#define __CPE_CTRL_UNUSED10_MK 0x0000c000
-#define __CPE_CTRL_UNUSED10_SH 14
-#define __CPE_CTRL_UNUSED10(_v) ((_v) << __CPE_CTRL_UNUSED10_SH)
-#define __CPE_ACK_PENDING 0x00002000
-#define __CPE_CTRL_UNUSED40_MK 0x00001c00
-#define __CPE_CTRL_UNUSED40_SH 10
-#define __CPE_CTRL_UNUSED40(_v) ((_v) << __CPE_CTRL_UNUSED40_SH)
-#define __CPE_PCIEID_MK 0x00000300
-#define __CPE_PCIEID_SH 8
-#define __CPE_PCIEID(_v) ((_v) << __CPE_PCIEID_SH)
-#define __CPE_CTRL_UNUSED00_MK 0x000000fe
-#define __CPE_CTRL_UNUSED00_SH 1
-#define __CPE_CTRL_UNUSED00(_v) ((_v) << __CPE_CTRL_UNUSED00_SH)
-#define __CPE_ESIZE 0x00000001
-#define CPE_QCTRL_Q1 0x0003804c
-#define __CPE_CTRL_UNUSED31_MK 0xfc000000
-#define __CPE_CTRL_UNUSED31_SH 26
-#define __CPE_CTRL_UNUSED31(_v) ((_v) << __CPE_CTRL_UNUSED31_SH)
-#define __CPE_CTRL_UNUSED21_MK 0x00f00000
-#define __CPE_CTRL_UNUSED21_SH 20
-#define __CPE_CTRL_UNUSED21(_v) ((_v) << __CPE_CTRL_UNUSED21_SH)
-#define __CPE_CTRL_UNUSED11_MK 0x0000c000
-#define __CPE_CTRL_UNUSED11_SH 14
-#define __CPE_CTRL_UNUSED11(_v) ((_v) << __CPE_CTRL_UNUSED11_SH)
-#define __CPE_CTRL_UNUSED41_MK 0x00001c00
-#define __CPE_CTRL_UNUSED41_SH 10
-#define __CPE_CTRL_UNUSED41(_v) ((_v) << __CPE_CTRL_UNUSED41_SH)
-#define __CPE_CTRL_UNUSED01_MK 0x000000fe
-#define __CPE_CTRL_UNUSED01_SH 1
-#define __CPE_CTRL_UNUSED01(_v) ((_v) << __CPE_CTRL_UNUSED01_SH)
-#define RME_PI_PTR_Q0 0x00038020
-#define __LATENCY_TIME_STAMP_MK 0xffff0000
-#define __LATENCY_TIME_STAMP_SH 16
-#define __LATENCY_TIME_STAMP(_v) ((_v) << __LATENCY_TIME_STAMP_SH)
-#define __RME_PI_PTR 0x0000ffff
-#define RME_PI_PTR_Q1 0x00038060
-#define RME_CI_PTR_Q0 0x00038024
-#define __DELAY_TIME_STAMP_MK 0xffff0000
-#define __DELAY_TIME_STAMP_SH 16
-#define __DELAY_TIME_STAMP(_v) ((_v) << __DELAY_TIME_STAMP_SH)
-#define __RME_CI_PTR 0x0000ffff
-#define RME_CI_PTR_Q1 0x00038064
-#define RME_DEPTH_Q0 0x00038028
-#define __RME_DEPTH_UNUSED_MK 0xf8000000
-#define __RME_DEPTH_UNUSED_SH 27
-#define __RME_DEPTH_UNUSED(_v) ((_v) << __RME_DEPTH_UNUSED_SH)
-#define __RME_MSIX_VEC_INDEX_MK 0x07ff0000
-#define __RME_MSIX_VEC_INDEX_SH 16
-#define __RME_MSIX_VEC_INDEX(_v) ((_v) << __RME_MSIX_VEC_INDEX_SH)
-#define __RME_DEPTH 0x0000ffff
-#define RME_DEPTH_Q1 0x00038068
-#define RME_QCTRL_Q0 0x0003802c
-#define __RME_INT_LATENCY_TIMER_MK 0xff000000
-#define __RME_INT_LATENCY_TIMER_SH 24
-#define __RME_INT_LATENCY_TIMER(_v) ((_v) << __RME_INT_LATENCY_TIMER_SH)
-#define __RME_INT_DELAY_TIMER_MK 0x00ff0000
-#define __RME_INT_DELAY_TIMER_SH 16
-#define __RME_INT_DELAY_TIMER(_v) ((_v) << __RME_INT_DELAY_TIMER_SH)
-#define __RME_INT_DELAY_DISABLE 0x00008000
-#define __RME_DLY_DELAY_DISABLE 0x00004000
-#define __RME_ACK_PENDING 0x00002000
-#define __RME_FULL_INTERRUPT_DISABLE 0x00001000
-#define __RME_CTRL_UNUSED10_MK 0x00000c00
-#define __RME_CTRL_UNUSED10_SH 10
-#define __RME_CTRL_UNUSED10(_v) ((_v) << __RME_CTRL_UNUSED10_SH)
-#define __RME_PCIEID_MK 0x00000300
-#define __RME_PCIEID_SH 8
-#define __RME_PCIEID(_v) ((_v) << __RME_PCIEID_SH)
-#define __RME_CTRL_UNUSED00_MK 0x000000fe
-#define __RME_CTRL_UNUSED00_SH 1
-#define __RME_CTRL_UNUSED00(_v) ((_v) << __RME_CTRL_UNUSED00_SH)
-#define __RME_ESIZE 0x00000001
-#define RME_QCTRL_Q1 0x0003806c
-#define __RME_CTRL_UNUSED11_MK 0x00000c00
-#define __RME_CTRL_UNUSED11_SH 10
-#define __RME_CTRL_UNUSED11(_v) ((_v) << __RME_CTRL_UNUSED11_SH)
-#define __RME_CTRL_UNUSED01_MK 0x000000fe
-#define __RME_CTRL_UNUSED01_SH 1
-#define __RME_CTRL_UNUSED01(_v) ((_v) << __RME_CTRL_UNUSED01_SH)
-#define PSS_CTL_REG 0x00018800
-#define __PSS_I2C_CLK_DIV_MK 0x007f0000
-#define __PSS_I2C_CLK_DIV_SH 16
-#define __PSS_I2C_CLK_DIV(_v) ((_v) << __PSS_I2C_CLK_DIV_SH)
-#define __PSS_LMEM_INIT_DONE 0x00001000
-#define __PSS_LMEM_RESET 0x00000200
-#define __PSS_LMEM_INIT_EN 0x00000100
-#define __PSS_LPU1_RESET 0x00000002
-#define __PSS_LPU0_RESET 0x00000001
-#define PSS_ERR_STATUS_REG 0x00018810
-#define __PSS_LPU1_TCM_READ_ERR 0x00200000
-#define __PSS_LPU0_TCM_READ_ERR 0x00100000
-#define __PSS_LMEM5_CORR_ERR 0x00080000
-#define __PSS_LMEM4_CORR_ERR 0x00040000
-#define __PSS_LMEM3_CORR_ERR 0x00020000
-#define __PSS_LMEM2_CORR_ERR 0x00010000
-#define __PSS_LMEM1_CORR_ERR 0x00008000
-#define __PSS_LMEM0_CORR_ERR 0x00004000
-#define __PSS_LMEM5_UNCORR_ERR 0x00002000
-#define __PSS_LMEM4_UNCORR_ERR 0x00001000
-#define __PSS_LMEM3_UNCORR_ERR 0x00000800
-#define __PSS_LMEM2_UNCORR_ERR 0x00000400
-#define __PSS_LMEM1_UNCORR_ERR 0x00000200
-#define __PSS_LMEM0_UNCORR_ERR 0x00000100
-#define __PSS_BAL_PERR 0x00000080
-#define __PSS_DIP_IF_ERR 0x00000040
-#define __PSS_IOH_IF_ERR 0x00000020
-#define __PSS_TDS_IF_ERR 0x00000010
-#define __PSS_RDS_IF_ERR 0x00000008
-#define __PSS_SGM_IF_ERR 0x00000004
-#define __PSS_LPU1_RAM_ERR 0x00000002
-#define __PSS_LPU0_RAM_ERR 0x00000001
-#define ERR_SET_REG 0x00018818
-#define __PSS_ERR_STATUS_SET 0x003fffff
-#define PMM_1T_RESET_REG_P0 0x0002381c
-#define __PMM_1T_RESET_P 0x00000001
-#define PMM_1T_RESET_REG_P1 0x00023c1c
-#define HQM_QSET0_RXQ_DRBL_P0 0x00038000
-#define __RXQ0_ADD_VECTORS_P 0x80000000
-#define __RXQ0_STOP_P 0x40000000
-#define __RXQ0_PRD_PTR_P 0x0000ffff
-#define HQM_QSET1_RXQ_DRBL_P0 0x00038080
-#define __RXQ1_ADD_VECTORS_P 0x80000000
-#define __RXQ1_STOP_P 0x40000000
-#define __RXQ1_PRD_PTR_P 0x0000ffff
-#define HQM_QSET0_RXQ_DRBL_P1 0x0003c000
-#define HQM_QSET1_RXQ_DRBL_P1 0x0003c080
-#define HQM_QSET0_TXQ_DRBL_P0 0x00038020
-#define __TXQ0_ADD_VECTORS_P 0x80000000
-#define __TXQ0_STOP_P 0x40000000
-#define __TXQ0_PRD_PTR_P 0x0000ffff
-#define HQM_QSET1_TXQ_DRBL_P0 0x000380a0
-#define __TXQ1_ADD_VECTORS_P 0x80000000
-#define __TXQ1_STOP_P 0x40000000
-#define __TXQ1_PRD_PTR_P 0x0000ffff
-#define HQM_QSET0_TXQ_DRBL_P1 0x0003c020
-#define HQM_QSET1_TXQ_DRBL_P1 0x0003c0a0
-#define HQM_QSET0_IB_DRBL_1_P0 0x00038040
-#define __IB1_0_ACK_P 0x80000000
-#define __IB1_0_DISABLE_P 0x40000000
-#define __IB1_0_COALESCING_CFG_P_MK 0x00ff0000
-#define __IB1_0_COALESCING_CFG_P_SH 16
-#define __IB1_0_COALESCING_CFG_P(_v) ((_v) << __IB1_0_COALESCING_CFG_P_SH)
-#define __IB1_0_NUM_OF_ACKED_EVENTS_P 0x0000ffff
-#define HQM_QSET1_IB_DRBL_1_P0 0x000380c0
-#define __IB1_1_ACK_P 0x80000000
-#define __IB1_1_DISABLE_P 0x40000000
-#define __IB1_1_COALESCING_CFG_P_MK 0x00ff0000
-#define __IB1_1_COALESCING_CFG_P_SH 16
-#define __IB1_1_COALESCING_CFG_P(_v) ((_v) << __IB1_1_COALESCING_CFG_P_SH)
-#define __IB1_1_NUM_OF_ACKED_EVENTS_P 0x0000ffff
-#define HQM_QSET0_IB_DRBL_1_P1 0x0003c040
-#define HQM_QSET1_IB_DRBL_1_P1 0x0003c0c0
-#define HQM_QSET0_IB_DRBL_2_P0 0x00038060
-#define __IB2_0_ACK_P 0x80000000
-#define __IB2_0_DISABLE_P 0x40000000
-#define __IB2_0_COALESCING_CFG_P_MK 0x00ff0000
-#define __IB2_0_COALESCING_CFG_P_SH 16
-#define __IB2_0_COALESCING_CFG_P(_v) ((_v) << __IB2_0_COALESCING_CFG_P_SH)
-#define __IB2_0_NUM_OF_ACKED_EVENTS_P 0x0000ffff
-#define HQM_QSET1_IB_DRBL_2_P0 0x000380e0
-#define __IB2_1_ACK_P 0x80000000
-#define __IB2_1_DISABLE_P 0x40000000
-#define __IB2_1_COALESCING_CFG_P_MK 0x00ff0000
-#define __IB2_1_COALESCING_CFG_P_SH 16
-#define __IB2_1_COALESCING_CFG_P(_v) ((_v) << __IB2_1_COALESCING_CFG_P_SH)
-#define __IB2_1_NUM_OF_ACKED_EVENTS_P 0x0000ffff
-#define HQM_QSET0_IB_DRBL_2_P1 0x0003c060
-#define HQM_QSET1_IB_DRBL_2_P1 0x0003c0e0
-
-/*
- * These definitions are either in error/missing in spec. Its auto-generated
- * from hard coded values in regparse.pl.
- */
-#define __EMPHPOST_AT_4G_MK_FIX 0x0000001c
-#define __EMPHPOST_AT_4G_SH_FIX 0x00000002
-#define __EMPHPRE_AT_4G_FIX 0x00000003
-#define __SFP_TXRATE_EN_FIX 0x00000100
-#define __SFP_RXRATE_EN_FIX 0x00000080
-
-/*
- * These register definitions are auto-generated from hard coded values
- * in regparse.pl.
- */
-
-/*
- * These register mapping definitions are auto-generated from mapping tables
- * in regparse.pl.
- */
-#define BFA_IOC0_HBEAT_REG HOST_SEM0_INFO_REG
-#define BFA_IOC0_STATE_REG HOST_SEM1_INFO_REG
-#define BFA_IOC1_HBEAT_REG HOST_SEM2_INFO_REG
-#define BFA_IOC1_STATE_REG HOST_SEM3_INFO_REG
-#define BFA_FW_USE_COUNT HOST_SEM4_INFO_REG
-#define BFA_IOC_FAIL_SYNC HOST_SEM5_INFO_REG
-
-#define CPE_DEPTH_Q(__n) \
- (CPE_DEPTH_Q0 + (__n) * (CPE_DEPTH_Q1 - CPE_DEPTH_Q0))
-#define CPE_QCTRL_Q(__n) \
- (CPE_QCTRL_Q0 + (__n) * (CPE_QCTRL_Q1 - CPE_QCTRL_Q0))
-#define CPE_PI_PTR_Q(__n) \
- (CPE_PI_PTR_Q0 + (__n) * (CPE_PI_PTR_Q1 - CPE_PI_PTR_Q0))
-#define CPE_CI_PTR_Q(__n) \
- (CPE_CI_PTR_Q0 + (__n) * (CPE_CI_PTR_Q1 - CPE_CI_PTR_Q0))
-#define RME_DEPTH_Q(__n) \
- (RME_DEPTH_Q0 + (__n) * (RME_DEPTH_Q1 - RME_DEPTH_Q0))
-#define RME_QCTRL_Q(__n) \
- (RME_QCTRL_Q0 + (__n) * (RME_QCTRL_Q1 - RME_QCTRL_Q0))
-#define RME_PI_PTR_Q(__n) \
- (RME_PI_PTR_Q0 + (__n) * (RME_PI_PTR_Q1 - RME_PI_PTR_Q0))
-#define RME_CI_PTR_Q(__n) \
- (RME_CI_PTR_Q0 + (__n) * (RME_CI_PTR_Q1 - RME_CI_PTR_Q0))
-#define HQM_QSET_RXQ_DRBL_P0(__n) \
- (HQM_QSET0_RXQ_DRBL_P0 + (__n) * \
- (HQM_QSET1_RXQ_DRBL_P0 - HQM_QSET0_RXQ_DRBL_P0))
-#define HQM_QSET_TXQ_DRBL_P0(__n) \
- (HQM_QSET0_TXQ_DRBL_P0 + (__n) * \
- (HQM_QSET1_TXQ_DRBL_P0 - HQM_QSET0_TXQ_DRBL_P0))
-#define HQM_QSET_IB_DRBL_1_P0(__n) \
- (HQM_QSET0_IB_DRBL_1_P0 + (__n) * \
- (HQM_QSET1_IB_DRBL_1_P0 - HQM_QSET0_IB_DRBL_1_P0))
-#define HQM_QSET_IB_DRBL_2_P0(__n) \
- (HQM_QSET0_IB_DRBL_2_P0 + (__n) * \
- (HQM_QSET1_IB_DRBL_2_P0 - HQM_QSET0_IB_DRBL_2_P0))
-#define HQM_QSET_RXQ_DRBL_P1(__n) \
- (HQM_QSET0_RXQ_DRBL_P1 + (__n) * \
- (HQM_QSET1_RXQ_DRBL_P1 - HQM_QSET0_RXQ_DRBL_P1))
-#define HQM_QSET_TXQ_DRBL_P1(__n) \
- (HQM_QSET0_TXQ_DRBL_P1 + (__n) * \
- (HQM_QSET1_TXQ_DRBL_P1 - HQM_QSET0_TXQ_DRBL_P1))
-#define HQM_QSET_IB_DRBL_1_P1(__n) \
- (HQM_QSET0_IB_DRBL_1_P1 + (__n) * \
- (HQM_QSET1_IB_DRBL_1_P1 - HQM_QSET0_IB_DRBL_1_P1))
-#define HQM_QSET_IB_DRBL_2_P1(__n) \
- (HQM_QSET0_IB_DRBL_2_P1 + (__n) * \
- (HQM_QSET1_IB_DRBL_2_P1 - HQM_QSET0_IB_DRBL_2_P1))
-
-#define CPE_Q_NUM(__fn, __q) (((__fn) << 2) + (__q))
-#define RME_Q_NUM(__fn, __q) (((__fn) << 2) + (__q))
-#define CPE_Q_MASK(__q) ((__q) & 0x3)
-#define RME_Q_MASK(__q) ((__q) & 0x3)
-
-/*
- * PCI MSI-X vector defines
- */
-enum {
- BFA_MSIX_CPE_Q0 = 0,
- BFA_MSIX_CPE_Q1 = 1,
- BFA_MSIX_CPE_Q2 = 2,
- BFA_MSIX_CPE_Q3 = 3,
- BFA_MSIX_RME_Q0 = 4,
- BFA_MSIX_RME_Q1 = 5,
- BFA_MSIX_RME_Q2 = 6,
- BFA_MSIX_RME_Q3 = 7,
- BFA_MSIX_LPU_ERR = 8,
- BFA_MSIX_CT_MAX = 9,
-};
-
-/*
- * And corresponding host interrupt status bit field defines
- */
-#define __HFN_INT_CPE_Q0 0x00000001U
-#define __HFN_INT_CPE_Q1 0x00000002U
-#define __HFN_INT_CPE_Q2 0x00000004U
-#define __HFN_INT_CPE_Q3 0x00000008U
-#define __HFN_INT_CPE_Q4 0x00000010U
-#define __HFN_INT_CPE_Q5 0x00000020U
-#define __HFN_INT_CPE_Q6 0x00000040U
-#define __HFN_INT_CPE_Q7 0x00000080U
-#define __HFN_INT_RME_Q0 0x00000100U
-#define __HFN_INT_RME_Q1 0x00000200U
-#define __HFN_INT_RME_Q2 0x00000400U
-#define __HFN_INT_RME_Q3 0x00000800U
-#define __HFN_INT_RME_Q4 0x00001000U
-#define __HFN_INT_RME_Q5 0x00002000U
-#define __HFN_INT_RME_Q6 0x00004000U
-#define __HFN_INT_RME_Q7 0x00008000U
-#define __HFN_INT_ERR_EMC 0x00010000U
-#define __HFN_INT_ERR_LPU0 0x00020000U
-#define __HFN_INT_ERR_LPU1 0x00040000U
-#define __HFN_INT_ERR_PSS 0x00080000U
-#define __HFN_INT_MBOX_LPU0 0x00100000U
-#define __HFN_INT_MBOX_LPU1 0x00200000U
-#define __HFN_INT_MBOX1_LPU0 0x00400000U
-#define __HFN_INT_MBOX1_LPU1 0x00800000U
-#define __HFN_INT_LL_HALT 0x01000000U
-#define __HFN_INT_CPE_MASK 0x000000ffU
-#define __HFN_INT_RME_MASK 0x0000ff00U
-
-/*
- * catapult memory map.
- */
-#define LL_PGN_HQM0 0x0096
-#define LL_PGN_HQM1 0x0097
-#define PSS_SMEM_PAGE_START 0x8000
-#define PSS_SMEM_PGNUM(_pg0, _ma) ((_pg0) + ((_ma) >> 15))
-#define PSS_SMEM_PGOFF(_ma) ((_ma) & 0x7fff)
-
-/*
- * End of catapult memory map
- */
-
-#endif /* __BFI_CTREG_H__ */
diff --git a/drivers/net/bna/bfi_ll.h b/drivers/net/bna/bfi_ll.h
deleted file mode 100644
index bee4d054066a..000000000000
--- a/drivers/net/bna/bfi_ll.h
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * Linux network driver for Brocade Converged Network Adapter.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License (GPL) Version 2 as
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- */
-/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
- * All rights reserved
- * www.brocade.com
- */
-#ifndef __BFI_LL_H__
-#define __BFI_LL_H__
-
-#include "bfi.h"
-
-#pragma pack(1)
-
-/**
- * @brief
- * "enums" for all LL mailbox messages other than IOC
- */
-enum {
- BFI_LL_H2I_MAC_UCAST_SET_REQ = 1,
- BFI_LL_H2I_MAC_UCAST_ADD_REQ = 2,
- BFI_LL_H2I_MAC_UCAST_DEL_REQ = 3,
-
- BFI_LL_H2I_MAC_MCAST_ADD_REQ = 4,
- BFI_LL_H2I_MAC_MCAST_DEL_REQ = 5,
- BFI_LL_H2I_MAC_MCAST_FILTER_REQ = 6,
- BFI_LL_H2I_MAC_MCAST_DEL_ALL_REQ = 7,
-
- BFI_LL_H2I_PORT_ADMIN_REQ = 8,
- BFI_LL_H2I_STATS_GET_REQ = 9,
- BFI_LL_H2I_STATS_CLEAR_REQ = 10,
-
- BFI_LL_H2I_RXF_PROMISCUOUS_SET_REQ = 11,
- BFI_LL_H2I_RXF_DEFAULT_SET_REQ = 12,
-
- BFI_LL_H2I_TXQ_STOP_REQ = 13,
- BFI_LL_H2I_RXQ_STOP_REQ = 14,
-
- BFI_LL_H2I_DIAG_LOOPBACK_REQ = 15,
-
- BFI_LL_H2I_SET_PAUSE_REQ = 16,
- BFI_LL_H2I_MTU_INFO_REQ = 17,
-
- BFI_LL_H2I_RX_REQ = 18,
-} ;
-
-enum {
- BFI_LL_I2H_MAC_UCAST_SET_RSP = BFA_I2HM(1),
- BFI_LL_I2H_MAC_UCAST_ADD_RSP = BFA_I2HM(2),
- BFI_LL_I2H_MAC_UCAST_DEL_RSP = BFA_I2HM(3),
-
- BFI_LL_I2H_MAC_MCAST_ADD_RSP = BFA_I2HM(4),
- BFI_LL_I2H_MAC_MCAST_DEL_RSP = BFA_I2HM(5),
- BFI_LL_I2H_MAC_MCAST_FILTER_RSP = BFA_I2HM(6),
- BFI_LL_I2H_MAC_MCAST_DEL_ALL_RSP = BFA_I2HM(7),
-
- BFI_LL_I2H_PORT_ADMIN_RSP = BFA_I2HM(8),
- BFI_LL_I2H_STATS_GET_RSP = BFA_I2HM(9),
- BFI_LL_I2H_STATS_CLEAR_RSP = BFA_I2HM(10),
-
- BFI_LL_I2H_RXF_PROMISCUOUS_SET_RSP = BFA_I2HM(11),
- BFI_LL_I2H_RXF_DEFAULT_SET_RSP = BFA_I2HM(12),
-
- BFI_LL_I2H_TXQ_STOP_RSP = BFA_I2HM(13),
- BFI_LL_I2H_RXQ_STOP_RSP = BFA_I2HM(14),
-
- BFI_LL_I2H_DIAG_LOOPBACK_RSP = BFA_I2HM(15),
-
- BFI_LL_I2H_SET_PAUSE_RSP = BFA_I2HM(16),
-
- BFI_LL_I2H_MTU_INFO_RSP = BFA_I2HM(17),
- BFI_LL_I2H_RX_RSP = BFA_I2HM(18),
-
- BFI_LL_I2H_LINK_DOWN_AEN = BFA_I2HM(19),
- BFI_LL_I2H_LINK_UP_AEN = BFA_I2HM(20),
-
- BFI_LL_I2H_PORT_ENABLE_AEN = BFA_I2HM(21),
- BFI_LL_I2H_PORT_DISABLE_AEN = BFA_I2HM(22),
-} ;
-
-/**
- * @brief bfi_ll_mac_addr_req is used by:
- * BFI_LL_H2I_MAC_UCAST_SET_REQ
- * BFI_LL_H2I_MAC_UCAST_ADD_REQ
- * BFI_LL_H2I_MAC_UCAST_DEL_REQ
- * BFI_LL_H2I_MAC_MCAST_ADD_REQ
- * BFI_LL_H2I_MAC_MCAST_DEL_REQ
- */
-struct bfi_ll_mac_addr_req {
- struct bfi_mhdr mh; /*!< common msg header */
- u8 rxf_id;
- u8 rsvd1[3];
- mac_t mac_addr;
- u8 rsvd2[2];
-};
-
-/**
- * @brief bfi_ll_mcast_filter_req is used by:
- * BFI_LL_H2I_MAC_MCAST_FILTER_REQ
- */
-struct bfi_ll_mcast_filter_req {
- struct bfi_mhdr mh; /*!< common msg header */
- u8 rxf_id;
- u8 enable;
- u8 rsvd[2];
-};
-
-/**
- * @brief bfi_ll_mcast_del_all is used by:
- * BFI_LL_H2I_MAC_MCAST_DEL_ALL_REQ
- */
-struct bfi_ll_mcast_del_all_req {
- struct bfi_mhdr mh; /*!< common msg header */
- u8 rxf_id;
- u8 rsvd[3];
-};
-
-/**
- * @brief bfi_ll_q_stop_req is used by:
- * BFI_LL_H2I_TXQ_STOP_REQ
- * BFI_LL_H2I_RXQ_STOP_REQ
- */
-struct bfi_ll_q_stop_req {
- struct bfi_mhdr mh; /*!< common msg header */
- u32 q_id_mask[2]; /* !< bit-mask for queue ids */
-};
-
-/**
- * @brief bfi_ll_stats_req is used by:
- * BFI_LL_I2H_STATS_GET_REQ
- * BFI_LL_I2H_STATS_CLEAR_REQ
- */
-struct bfi_ll_stats_req {
- struct bfi_mhdr mh; /*!< common msg header */
- u16 stats_mask; /* !< bit-mask for non-function statistics */
- u8 rsvd[2];
- u32 rxf_id_mask[2]; /* !< bit-mask for RxF Statistics */
- u32 txf_id_mask[2]; /* !< bit-mask for TxF Statistics */
- union bfi_addr_u host_buffer; /* !< where statistics are returned */
-};
-
-/**
- * @brief defines for "stats_mask" above.
- */
-#define BFI_LL_STATS_MAC (1 << 0) /* !< MAC Statistics */
-#define BFI_LL_STATS_BPC (1 << 1) /* !< Pause Stats from BPC */
-#define BFI_LL_STATS_RAD (1 << 2) /* !< Rx Admission Statistics */
-#define BFI_LL_STATS_RX_FC (1 << 3) /* !< Rx FC Stats from RxA */
-#define BFI_LL_STATS_TX_FC (1 << 4) /* !< Tx FC Stats from TxA */
-
-#define BFI_LL_STATS_ALL 0x1f
-
-/**
- * @brief bfi_ll_port_admin_req
- */
-struct bfi_ll_port_admin_req {
- struct bfi_mhdr mh; /*!< common msg header */
- u8 up;
- u8 rsvd[3];
-};
-
-/**
- * @brief bfi_ll_rxf_req is used by:
- * BFI_LL_H2I_RXF_PROMISCUOUS_SET_REQ
- * BFI_LL_H2I_RXF_DEFAULT_SET_REQ
- */
-struct bfi_ll_rxf_req {
- struct bfi_mhdr mh; /*!< common msg header */
- u8 rxf_id;
- u8 enable;
- u8 rsvd[2];
-};
-
-/**
- * @brief bfi_ll_rxf_multi_req is used by:
- * BFI_LL_H2I_RX_REQ
- */
-struct bfi_ll_rxf_multi_req {
- struct bfi_mhdr mh; /*!< common msg header */
- u32 rxf_id_mask[2];
- u8 enable;
- u8 rsvd[3];
-};
-
-/**
- * @brief enum for Loopback opmodes
- */
-enum {
- BFI_LL_DIAG_LB_OPMODE_EXT = 0,
- BFI_LL_DIAG_LB_OPMODE_CBL = 1,
-};
-
-/**
- * @brief bfi_ll_set_pause_req is used by:
- * BFI_LL_H2I_SET_PAUSE_REQ
- */
-struct bfi_ll_set_pause_req {
- struct bfi_mhdr mh;
- u8 tx_pause; /* 1 = enable, 0 = disable */
- u8 rx_pause; /* 1 = enable, 0 = disable */
- u8 rsvd[2];
-};
-
-/**
- * @brief bfi_ll_mtu_info_req is used by:
- * BFI_LL_H2I_MTU_INFO_REQ
- */
-struct bfi_ll_mtu_info_req {
- struct bfi_mhdr mh;
- u16 mtu;
- u8 rsvd[2];
-};
-
-/**
- * @brief
- * Response header format used by all responses
- * For both responses and asynchronous notifications
- */
-struct bfi_ll_rsp {
- struct bfi_mhdr mh; /*!< common msg header */
- u8 error;
- u8 rsvd[3];
-};
-
-/**
- * @brief bfi_ll_cee_aen is used by:
- * BFI_LL_I2H_LINK_DOWN_AEN
- * BFI_LL_I2H_LINK_UP_AEN
- */
-struct bfi_ll_aen {
- struct bfi_mhdr mh; /*!< common msg header */
- u32 reason;
- u8 cee_linkup;
- u8 prio_map; /*!< LL priority bit-map */
- u8 rsvd[2];
-};
-
-/**
- * @brief
- * The following error codes can be returned
- * by the mbox commands
- */
-enum {
- BFI_LL_CMD_OK = 0,
- BFI_LL_CMD_FAIL = 1,
- BFI_LL_CMD_DUP_ENTRY = 2, /* !< Duplicate entry in CAM */
- BFI_LL_CMD_CAM_FULL = 3, /* !< CAM is full */
- BFI_LL_CMD_NOT_OWNER = 4, /* !< Not permitted, b'cos not owner */
- BFI_LL_CMD_NOT_EXEC = 5, /* !< Was not sent to f/w at all */
- BFI_LL_CMD_WAITING = 6, /* !< Waiting for completion (VMware) */
- BFI_LL_CMD_PORT_DISABLED = 7, /* !< port in disabled state */
-} ;
-
-/* Statistics */
-#define BFI_LL_TXF_ID_MAX 64
-#define BFI_LL_RXF_ID_MAX 64
-
-/* TxF Frame Statistics */
-struct bfi_ll_stats_txf {
- u64 ucast_octets;
- u64 ucast;
- u64 ucast_vlan;
-
- u64 mcast_octets;
- u64 mcast;
- u64 mcast_vlan;
-
- u64 bcast_octets;
- u64 bcast;
- u64 bcast_vlan;
-
- u64 errors;
- u64 filter_vlan; /* frames filtered due to VLAN */
- u64 filter_mac_sa; /* frames filtered due to SA check */
-};
-
-/* RxF Frame Statistics */
-struct bfi_ll_stats_rxf {
- u64 ucast_octets;
- u64 ucast;
- u64 ucast_vlan;
-
- u64 mcast_octets;
- u64 mcast;
- u64 mcast_vlan;
-
- u64 bcast_octets;
- u64 bcast;
- u64 bcast_vlan;
- u64 frame_drops;
-};
-
-/* FC Tx Frame Statistics */
-struct bfi_ll_stats_fc_tx {
- u64 txf_ucast_octets;
- u64 txf_ucast;
- u64 txf_ucast_vlan;
-
- u64 txf_mcast_octets;
- u64 txf_mcast;
- u64 txf_mcast_vlan;
-
- u64 txf_bcast_octets;
- u64 txf_bcast;
- u64 txf_bcast_vlan;
-
- u64 txf_parity_errors;
- u64 txf_timeout;
- u64 txf_fid_parity_errors;
-};
-
-/* FC Rx Frame Statistics */
-struct bfi_ll_stats_fc_rx {
- u64 rxf_ucast_octets;
- u64 rxf_ucast;
- u64 rxf_ucast_vlan;
-
- u64 rxf_mcast_octets;
- u64 rxf_mcast;
- u64 rxf_mcast_vlan;
-
- u64 rxf_bcast_octets;
- u64 rxf_bcast;
- u64 rxf_bcast_vlan;
-};
-
-/* RAD Frame Statistics */
-struct bfi_ll_stats_rad {
- u64 rx_frames;
- u64 rx_octets;
- u64 rx_vlan_frames;
-
- u64 rx_ucast;
- u64 rx_ucast_octets;
- u64 rx_ucast_vlan;
-
- u64 rx_mcast;
- u64 rx_mcast_octets;
- u64 rx_mcast_vlan;
-
- u64 rx_bcast;
- u64 rx_bcast_octets;
- u64 rx_bcast_vlan;
-
- u64 rx_drops;
-};
-
-/* BPC Tx Registers */
-struct bfi_ll_stats_bpc {
- /* transmit stats */
- u64 tx_pause[8];
- u64 tx_zero_pause[8]; /*!< Pause cancellation */
- /*!<Pause initiation rather than retention */
- u64 tx_first_pause[8];
-
- /* receive stats */
- u64 rx_pause[8];
- u64 rx_zero_pause[8]; /*!< Pause cancellation */
- /*!<Pause initiation rather than retention */
- u64 rx_first_pause[8];
-};
-
-/* MAC Rx Statistics */
-struct bfi_ll_stats_mac {
- u64 frame_64; /* both rx and tx counter */
- u64 frame_65_127; /* both rx and tx counter */
- u64 frame_128_255; /* both rx and tx counter */
- u64 frame_256_511; /* both rx and tx counter */
- u64 frame_512_1023; /* both rx and tx counter */
- u64 frame_1024_1518; /* both rx and tx counter */
- u64 frame_1519_1522; /* both rx and tx counter */
-
- /* receive stats */
- u64 rx_bytes;
- u64 rx_packets;
- u64 rx_fcs_error;
- u64 rx_multicast;
- u64 rx_broadcast;
- u64 rx_control_frames;
- u64 rx_pause;
- u64 rx_unknown_opcode;
- u64 rx_alignment_error;
- u64 rx_frame_length_error;
- u64 rx_code_error;
- u64 rx_carrier_sense_error;
- u64 rx_undersize;
- u64 rx_oversize;
- u64 rx_fragments;
- u64 rx_jabber;
- u64 rx_drop;
-
- /* transmit stats */
- u64 tx_bytes;
- u64 tx_packets;
- u64 tx_multicast;
- u64 tx_broadcast;
- u64 tx_pause;
- u64 tx_deferral;
- u64 tx_excessive_deferral;
- u64 tx_single_collision;
- u64 tx_muliple_collision;
- u64 tx_late_collision;
- u64 tx_excessive_collision;
- u64 tx_total_collision;
- u64 tx_pause_honored;
- u64 tx_drop;
- u64 tx_jabber;
- u64 tx_fcs_error;
- u64 tx_control_frame;
- u64 tx_oversize;
- u64 tx_undersize;
- u64 tx_fragments;
-};
-
-/* Complete statistics */
-struct bfi_ll_stats {
- struct bfi_ll_stats_mac mac_stats;
- struct bfi_ll_stats_bpc bpc_stats;
- struct bfi_ll_stats_rad rad_stats;
- struct bfi_ll_stats_fc_rx fc_rx_stats;
- struct bfi_ll_stats_fc_tx fc_tx_stats;
- struct bfi_ll_stats_rxf rxf_stats[BFI_LL_RXF_ID_MAX];
- struct bfi_ll_stats_txf txf_stats[BFI_LL_TXF_ID_MAX];
-};
-
-#pragma pack()
-
-#endif /* __BFI_LL_H__ */
diff --git a/drivers/net/bna/bna_ctrl.c b/drivers/net/bna/bna_ctrl.c
deleted file mode 100644
index cb2594c564dc..000000000000
--- a/drivers/net/bna/bna_ctrl.c
+++ /dev/null
@@ -1,3076 +0,0 @@
-/*
- * Linux network driver for Brocade Converged Network Adapter.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License (GPL) Version 2 as
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- */
-/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
- * All rights reserved
- * www.brocade.com
- */
-#include "bna.h"
-#include "bfa_cs.h"
-
-static void bna_device_cb_port_stopped(void *arg, enum bna_cb_status status);
-
-static void
-bna_port_cb_link_up(struct bna_port *port, struct bfi_ll_aen *aen,
- int status)
-{
- int i;
- u8 prio_map;
-
- port->llport.link_status = BNA_LINK_UP;
- if (aen->cee_linkup)
- port->llport.link_status = BNA_CEE_UP;
-
- /* Compute the priority */
- prio_map = aen->prio_map;
- if (prio_map) {
- for (i = 0; i < 8; i++) {
- if ((prio_map >> i) & 0x1)
- break;
- }
- port->priority = i;
- } else
- port->priority = 0;
-
- /* Dispatch events */
- bna_tx_mod_cee_link_status(&port->bna->tx_mod, aen->cee_linkup);
- bna_tx_mod_prio_changed(&port->bna->tx_mod, port->priority);
- port->link_cbfn(port->bna->bnad, port->llport.link_status);
-}
-
-static void
-bna_port_cb_link_down(struct bna_port *port, int status)
-{
- port->llport.link_status = BNA_LINK_DOWN;
-
- /* Dispatch events */
- bna_tx_mod_cee_link_status(&port->bna->tx_mod, BNA_LINK_DOWN);
- port->link_cbfn(port->bna->bnad, BNA_LINK_DOWN);
-}
-
-static inline int
-llport_can_be_up(struct bna_llport *llport)
-{
- int ready = 0;
- if (llport->type == BNA_PORT_T_REGULAR)
- ready = ((llport->flags & BNA_LLPORT_F_ADMIN_UP) &&
- (llport->flags & BNA_LLPORT_F_RX_STARTED) &&
- (llport->flags & BNA_LLPORT_F_PORT_ENABLED));
- else
- ready = ((llport->flags & BNA_LLPORT_F_ADMIN_UP) &&
- (llport->flags & BNA_LLPORT_F_RX_STARTED) &&
- !(llport->flags & BNA_LLPORT_F_PORT_ENABLED));
- return ready;
-}
-
-#define llport_is_up llport_can_be_up
-
-enum bna_llport_event {
- LLPORT_E_START = 1,
- LLPORT_E_STOP = 2,
- LLPORT_E_FAIL = 3,
- LLPORT_E_UP = 4,
- LLPORT_E_DOWN = 5,
- LLPORT_E_FWRESP_UP_OK = 6,
- LLPORT_E_FWRESP_UP_FAIL = 7,
- LLPORT_E_FWRESP_DOWN = 8
-};
-
-static void
-bna_llport_cb_port_enabled(struct bna_llport *llport)
-{
- llport->flags |= BNA_LLPORT_F_PORT_ENABLED;
-
- if (llport_can_be_up(llport))
- bfa_fsm_send_event(llport, LLPORT_E_UP);
-}
-
-static void
-bna_llport_cb_port_disabled(struct bna_llport *llport)
-{
- int llport_up = llport_is_up(llport);
-
- llport->flags &= ~BNA_LLPORT_F_PORT_ENABLED;
-
- if (llport_up)
- bfa_fsm_send_event(llport, LLPORT_E_DOWN);
-}
-
-/**
- * MBOX
- */
-static int
-bna_is_aen(u8 msg_id)
-{
- switch (msg_id) {
- case BFI_LL_I2H_LINK_DOWN_AEN:
- case BFI_LL_I2H_LINK_UP_AEN:
- case BFI_LL_I2H_PORT_ENABLE_AEN:
- case BFI_LL_I2H_PORT_DISABLE_AEN:
- return 1;
-
- default:
- return 0;
- }
-}
-
-static void
-bna_mbox_aen_callback(struct bna *bna, struct bfi_mbmsg *msg)
-{
- struct bfi_ll_aen *aen = (struct bfi_ll_aen *)(msg);
-
- switch (aen->mh.msg_id) {
- case BFI_LL_I2H_LINK_UP_AEN:
- bna_port_cb_link_up(&bna->port, aen, aen->reason);
- break;
- case BFI_LL_I2H_LINK_DOWN_AEN:
- bna_port_cb_link_down(&bna->port, aen->reason);
- break;
- case BFI_LL_I2H_PORT_ENABLE_AEN:
- bna_llport_cb_port_enabled(&bna->port.llport);
- break;
- case BFI_LL_I2H_PORT_DISABLE_AEN:
- bna_llport_cb_port_disabled(&bna->port.llport);
- break;
- default:
- break;
- }
-}
-
-static void
-bna_ll_isr(void *llarg, struct bfi_mbmsg *msg)
-{
- struct bna *bna = (struct bna *)(llarg);
- struct bfi_ll_rsp *mb_rsp = (struct bfi_ll_rsp *)(msg);
- struct bfi_mhdr *cmd_h, *rsp_h;
- struct bna_mbox_qe *mb_qe = NULL;
- int to_post = 0;
- u8 aen = 0;
- char message[BNA_MESSAGE_SIZE];
-
- aen = bna_is_aen(mb_rsp->mh.msg_id);
-
- if (!aen) {
- mb_qe = bfa_q_first(&bna->mbox_mod.posted_q);
- cmd_h = (struct bfi_mhdr *)(&mb_qe->cmd.msg[0]);
- rsp_h = (struct bfi_mhdr *)(&mb_rsp->mh);
-
- if ((BFA_I2HM(cmd_h->msg_id) == rsp_h->msg_id) &&
- (cmd_h->mtag.i2htok == rsp_h->mtag.i2htok)) {
- /* Remove the request from posted_q, update state */
- list_del(&mb_qe->qe);
- bna->mbox_mod.msg_pending--;
- if (list_empty(&bna->mbox_mod.posted_q))
- bna->mbox_mod.state = BNA_MBOX_FREE;
- else
- to_post = 1;
-
- /* Dispatch the cbfn */
- if (mb_qe->cbfn)
- mb_qe->cbfn(mb_qe->cbarg, mb_rsp->error);
-
- /* Post the next entry, if needed */
- if (to_post) {
- mb_qe = bfa_q_first(&bna->mbox_mod.posted_q);
- bfa_nw_ioc_mbox_queue(&bna->device.ioc,
- &mb_qe->cmd);
- }
- } else {
- snprintf(message, BNA_MESSAGE_SIZE,
- "No matching rsp for [%d:%d:%d]\n",
- mb_rsp->mh.msg_class, mb_rsp->mh.msg_id,
- mb_rsp->mh.mtag.i2htok);
- pr_info("%s", message);
- }
-
- } else
- bna_mbox_aen_callback(bna, msg);
-}
-
-static void
-bna_err_handler(struct bna *bna, u32 intr_status)
-{
- u32 init_halt;
-
- if (intr_status & __HALT_STATUS_BITS) {
- init_halt = readl(bna->device.ioc.ioc_regs.ll_halt);
- init_halt &= ~__FW_INIT_HALT_P;
- writel(init_halt, bna->device.ioc.ioc_regs.ll_halt);
- }
-
- bfa_nw_ioc_error_isr(&bna->device.ioc);
-}
-
-void
-bna_mbox_handler(struct bna *bna, u32 intr_status)
-{
- if (BNA_IS_ERR_INTR(intr_status)) {
- bna_err_handler(bna, intr_status);
- return;
- }
- if (BNA_IS_MBOX_INTR(intr_status))
- bfa_nw_ioc_mbox_isr(&bna->device.ioc);
-}
-
-void
-bna_mbox_send(struct bna *bna, struct bna_mbox_qe *mbox_qe)
-{
- struct bfi_mhdr *mh;
-
- mh = (struct bfi_mhdr *)(&mbox_qe->cmd.msg[0]);
-
- mh->mtag.i2htok = htons(bna->mbox_mod.msg_ctr);
- bna->mbox_mod.msg_ctr++;
- bna->mbox_mod.msg_pending++;
- if (bna->mbox_mod.state == BNA_MBOX_FREE) {
- list_add_tail(&mbox_qe->qe, &bna->mbox_mod.posted_q);
- bfa_nw_ioc_mbox_queue(&bna->device.ioc, &mbox_qe->cmd);
- bna->mbox_mod.state = BNA_MBOX_POSTED;
- } else {
- list_add_tail(&mbox_qe->qe, &bna->mbox_mod.posted_q);
- }
-}
-
-static void
-bna_mbox_flush_q(struct bna *bna, struct list_head *q)
-{
- struct bna_mbox_qe *mb_qe = NULL;
- struct list_head *mb_q;
- void (*cbfn)(void *arg, int status);
- void *cbarg;
-
- mb_q = &bna->mbox_mod.posted_q;
-
- while (!list_empty(mb_q)) {
- bfa_q_deq(mb_q, &mb_qe);
- cbfn = mb_qe->cbfn;
- cbarg = mb_qe->cbarg;
- bfa_q_qe_init(mb_qe);
- bna->mbox_mod.msg_pending--;
-
- if (cbfn)
- cbfn(cbarg, BNA_CB_NOT_EXEC);
- }
-
- bna->mbox_mod.state = BNA_MBOX_FREE;
-}
-
-static void
-bna_mbox_mod_start(struct bna_mbox_mod *mbox_mod)
-{
-}
-
-static void
-bna_mbox_mod_stop(struct bna_mbox_mod *mbox_mod)
-{
- bna_mbox_flush_q(mbox_mod->bna, &mbox_mod->posted_q);
-}
-
-static void
-bna_mbox_mod_init(struct bna_mbox_mod *mbox_mod, struct bna *bna)
-{
- bfa_nw_ioc_mbox_regisr(&bna->device.ioc, BFI_MC_LL, bna_ll_isr, bna);
- mbox_mod->state = BNA_MBOX_FREE;
- mbox_mod->msg_ctr = mbox_mod->msg_pending = 0;
- INIT_LIST_HEAD(&mbox_mod->posted_q);
- mbox_mod->bna = bna;
-}
-
-static void
-bna_mbox_mod_uninit(struct bna_mbox_mod *mbox_mod)
-{
- mbox_mod->bna = NULL;
-}
-
-/**
- * LLPORT
- */
-#define call_llport_stop_cbfn(llport, status)\
-do {\
- if ((llport)->stop_cbfn)\
- (llport)->stop_cbfn(&(llport)->bna->port, status);\
- (llport)->stop_cbfn = NULL;\
-} while (0)
-
-static void bna_fw_llport_up(struct bna_llport *llport);
-static void bna_fw_cb_llport_up(void *arg, int status);
-static void bna_fw_llport_down(struct bna_llport *llport);
-static void bna_fw_cb_llport_down(void *arg, int status);
-static void bna_llport_start(struct bna_llport *llport);
-static void bna_llport_stop(struct bna_llport *llport);
-static void bna_llport_fail(struct bna_llport *llport);
-
-enum bna_llport_state {
- BNA_LLPORT_STOPPED = 1,
- BNA_LLPORT_DOWN = 2,
- BNA_LLPORT_UP_RESP_WAIT = 3,
- BNA_LLPORT_DOWN_RESP_WAIT = 4,
- BNA_LLPORT_UP = 5,
- BNA_LLPORT_LAST_RESP_WAIT = 6
-};
-
-bfa_fsm_state_decl(bna_llport, stopped, struct bna_llport,
- enum bna_llport_event);
-bfa_fsm_state_decl(bna_llport, down, struct bna_llport,
- enum bna_llport_event);
-bfa_fsm_state_decl(bna_llport, up_resp_wait, struct bna_llport,
- enum bna_llport_event);
-bfa_fsm_state_decl(bna_llport, down_resp_wait, struct bna_llport,
- enum bna_llport_event);
-bfa_fsm_state_decl(bna_llport, up, struct bna_llport,
- enum bna_llport_event);
-bfa_fsm_state_decl(bna_llport, last_resp_wait, struct bna_llport,
- enum bna_llport_event);
-
-static struct bfa_sm_table llport_sm_table[] = {
- {BFA_SM(bna_llport_sm_stopped), BNA_LLPORT_STOPPED},
- {BFA_SM(bna_llport_sm_down), BNA_LLPORT_DOWN},
- {BFA_SM(bna_llport_sm_up_resp_wait), BNA_LLPORT_UP_RESP_WAIT},
- {BFA_SM(bna_llport_sm_down_resp_wait), BNA_LLPORT_DOWN_RESP_WAIT},
- {BFA_SM(bna_llport_sm_up), BNA_LLPORT_UP},
- {BFA_SM(bna_llport_sm_last_resp_wait), BNA_LLPORT_LAST_RESP_WAIT}
-};
-
-static void
-bna_llport_sm_stopped_entry(struct bna_llport *llport)
-{
- llport->bna->port.link_cbfn((llport)->bna->bnad, BNA_LINK_DOWN);
- call_llport_stop_cbfn(llport, BNA_CB_SUCCESS);
-}
-
-static void
-bna_llport_sm_stopped(struct bna_llport *llport,
- enum bna_llport_event event)
-{
- switch (event) {
- case LLPORT_E_START:
- bfa_fsm_set_state(llport, bna_llport_sm_down);
- break;
-
- case LLPORT_E_STOP:
- call_llport_stop_cbfn(llport, BNA_CB_SUCCESS);
- break;
-
- case LLPORT_E_FAIL:
- break;
-
- case LLPORT_E_DOWN:
- /* This event is received due to Rx objects failing */
- /* No-op */
- break;
-
- case LLPORT_E_FWRESP_UP_OK:
- case LLPORT_E_FWRESP_DOWN:
- /**
- * These events are received due to flushing of mbox when
- * device fails
- */
- /* No-op */
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_llport_sm_down_entry(struct bna_llport *llport)
-{
- bnad_cb_port_link_status((llport)->bna->bnad, BNA_LINK_DOWN);
-}
-
-static void
-bna_llport_sm_down(struct bna_llport *llport,
- enum bna_llport_event event)
-{
- switch (event) {
- case LLPORT_E_STOP:
- bfa_fsm_set_state(llport, bna_llport_sm_stopped);
- break;
-
- case LLPORT_E_FAIL:
- bfa_fsm_set_state(llport, bna_llport_sm_stopped);
- break;
-
- case LLPORT_E_UP:
- bfa_fsm_set_state(llport, bna_llport_sm_up_resp_wait);
- bna_fw_llport_up(llport);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_llport_sm_up_resp_wait_entry(struct bna_llport *llport)
-{
- BUG_ON(!llport_can_be_up(llport));
- /**
- * NOTE: Do not call bna_fw_llport_up() here. That will over step
- * mbox due to down_resp_wait -> up_resp_wait transition on event
- * LLPORT_E_UP
- */
-}
-
-static void
-bna_llport_sm_up_resp_wait(struct bna_llport *llport,
- enum bna_llport_event event)
-{
- switch (event) {
- case LLPORT_E_STOP:
- bfa_fsm_set_state(llport, bna_llport_sm_last_resp_wait);
- break;
-
- case LLPORT_E_FAIL:
- bfa_fsm_set_state(llport, bna_llport_sm_stopped);
- break;
-
- case LLPORT_E_DOWN:
- bfa_fsm_set_state(llport, bna_llport_sm_down_resp_wait);
- break;
-
- case LLPORT_E_FWRESP_UP_OK:
- bfa_fsm_set_state(llport, bna_llport_sm_up);
- break;
-
- case LLPORT_E_FWRESP_UP_FAIL:
- bfa_fsm_set_state(llport, bna_llport_sm_down);
- break;
-
- case LLPORT_E_FWRESP_DOWN:
- /* down_resp_wait -> up_resp_wait transition on LLPORT_E_UP */
- bna_fw_llport_up(llport);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_llport_sm_down_resp_wait_entry(struct bna_llport *llport)
-{
- /**
- * NOTE: Do not call bna_fw_llport_down() here. That will over step
- * mbox due to up_resp_wait -> down_resp_wait transition on event
- * LLPORT_E_DOWN
- */
-}
-
-static void
-bna_llport_sm_down_resp_wait(struct bna_llport *llport,
- enum bna_llport_event event)
-{
- switch (event) {
- case LLPORT_E_STOP:
- bfa_fsm_set_state(llport, bna_llport_sm_last_resp_wait);
- break;
-
- case LLPORT_E_FAIL:
- bfa_fsm_set_state(llport, bna_llport_sm_stopped);
- break;
-
- case LLPORT_E_UP:
- bfa_fsm_set_state(llport, bna_llport_sm_up_resp_wait);
- break;
-
- case LLPORT_E_FWRESP_UP_OK:
- /* up_resp_wait->down_resp_wait transition on LLPORT_E_DOWN */
- bna_fw_llport_down(llport);
- break;
-
- case LLPORT_E_FWRESP_UP_FAIL:
- case LLPORT_E_FWRESP_DOWN:
- bfa_fsm_set_state(llport, bna_llport_sm_down);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_llport_sm_up_entry(struct bna_llport *llport)
-{
-}
-
-static void
-bna_llport_sm_up(struct bna_llport *llport,
- enum bna_llport_event event)
-{
- switch (event) {
- case LLPORT_E_STOP:
- bfa_fsm_set_state(llport, bna_llport_sm_last_resp_wait);
- bna_fw_llport_down(llport);
- break;
-
- case LLPORT_E_FAIL:
- bfa_fsm_set_state(llport, bna_llport_sm_stopped);
- break;
-
- case LLPORT_E_DOWN:
- bfa_fsm_set_state(llport, bna_llport_sm_down_resp_wait);
- bna_fw_llport_down(llport);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_llport_sm_last_resp_wait_entry(struct bna_llport *llport)
-{
-}
-
-static void
-bna_llport_sm_last_resp_wait(struct bna_llport *llport,
- enum bna_llport_event event)
-{
- switch (event) {
- case LLPORT_E_FAIL:
- bfa_fsm_set_state(llport, bna_llport_sm_stopped);
- break;
-
- case LLPORT_E_DOWN:
- /**
- * This event is received due to Rx objects stopping in
- * parallel to llport
- */
- /* No-op */
- break;
-
- case LLPORT_E_FWRESP_UP_OK:
- /* up_resp_wait->last_resp_wait transition on LLPORT_T_STOP */
- bna_fw_llport_down(llport);
- break;
-
- case LLPORT_E_FWRESP_UP_FAIL:
- case LLPORT_E_FWRESP_DOWN:
- bfa_fsm_set_state(llport, bna_llport_sm_stopped);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_fw_llport_admin_up(struct bna_llport *llport)
-{
- struct bfi_ll_port_admin_req ll_req;
-
- memset(&ll_req, 0, sizeof(ll_req));
- ll_req.mh.msg_class = BFI_MC_LL;
- ll_req.mh.msg_id = BFI_LL_H2I_PORT_ADMIN_REQ;
- ll_req.mh.mtag.h2i.lpu_id = 0;
-
- ll_req.up = BNA_STATUS_T_ENABLED;
-
- bna_mbox_qe_fill(&llport->mbox_qe, &ll_req, sizeof(ll_req),
- bna_fw_cb_llport_up, llport);
-
- bna_mbox_send(llport->bna, &llport->mbox_qe);
-}
-
-static void
-bna_fw_llport_up(struct bna_llport *llport)
-{
- if (llport->type == BNA_PORT_T_REGULAR)
- bna_fw_llport_admin_up(llport);
-}
-
-static void
-bna_fw_cb_llport_up(void *arg, int status)
-{
- struct bna_llport *llport = (struct bna_llport *)arg;
-
- bfa_q_qe_init(&llport->mbox_qe.qe);
- if (status == BFI_LL_CMD_FAIL) {
- if (llport->type == BNA_PORT_T_REGULAR)
- llport->flags &= ~BNA_LLPORT_F_PORT_ENABLED;
- else
- llport->flags &= ~BNA_LLPORT_F_ADMIN_UP;
- bfa_fsm_send_event(llport, LLPORT_E_FWRESP_UP_FAIL);
- } else
- bfa_fsm_send_event(llport, LLPORT_E_FWRESP_UP_OK);
-}
-
-static void
-bna_fw_llport_admin_down(struct bna_llport *llport)
-{
- struct bfi_ll_port_admin_req ll_req;
-
- memset(&ll_req, 0, sizeof(ll_req));
- ll_req.mh.msg_class = BFI_MC_LL;
- ll_req.mh.msg_id = BFI_LL_H2I_PORT_ADMIN_REQ;
- ll_req.mh.mtag.h2i.lpu_id = 0;
-
- ll_req.up = BNA_STATUS_T_DISABLED;
-
- bna_mbox_qe_fill(&llport->mbox_qe, &ll_req, sizeof(ll_req),
- bna_fw_cb_llport_down, llport);
-
- bna_mbox_send(llport->bna, &llport->mbox_qe);
-}
-
-static void
-bna_fw_llport_down(struct bna_llport *llport)
-{
- if (llport->type == BNA_PORT_T_REGULAR)
- bna_fw_llport_admin_down(llport);
-}
-
-static void
-bna_fw_cb_llport_down(void *arg, int status)
-{
- struct bna_llport *llport = (struct bna_llport *)arg;
-
- bfa_q_qe_init(&llport->mbox_qe.qe);
- bfa_fsm_send_event(llport, LLPORT_E_FWRESP_DOWN);
-}
-
-static void
-bna_port_cb_llport_stopped(struct bna_port *port,
- enum bna_cb_status status)
-{
- bfa_wc_down(&port->chld_stop_wc);
-}
-
-static void
-bna_llport_init(struct bna_llport *llport, struct bna *bna)
-{
- llport->flags |= BNA_LLPORT_F_ADMIN_UP;
- llport->flags |= BNA_LLPORT_F_PORT_ENABLED;
- llport->type = BNA_PORT_T_REGULAR;
- llport->bna = bna;
-
- llport->link_status = BNA_LINK_DOWN;
-
- llport->rx_started_count = 0;
-
- llport->stop_cbfn = NULL;
-
- bfa_q_qe_init(&llport->mbox_qe.qe);
-
- bfa_fsm_set_state(llport, bna_llport_sm_stopped);
-}
-
-static void
-bna_llport_uninit(struct bna_llport *llport)
-{
- llport->flags &= ~BNA_LLPORT_F_ADMIN_UP;
- llport->flags &= ~BNA_LLPORT_F_PORT_ENABLED;
-
- llport->bna = NULL;
-}
-
-static void
-bna_llport_start(struct bna_llport *llport)
-{
- bfa_fsm_send_event(llport, LLPORT_E_START);
-}
-
-static void
-bna_llport_stop(struct bna_llport *llport)
-{
- llport->stop_cbfn = bna_port_cb_llport_stopped;
-
- bfa_fsm_send_event(llport, LLPORT_E_STOP);
-}
-
-static void
-bna_llport_fail(struct bna_llport *llport)
-{
- /* Reset the physical port status to enabled */
- llport->flags |= BNA_LLPORT_F_PORT_ENABLED;
- bfa_fsm_send_event(llport, LLPORT_E_FAIL);
-}
-
-static int
-bna_llport_state_get(struct bna_llport *llport)
-{
- return bfa_sm_to_state(llport_sm_table, llport->fsm);
-}
-
-void
-bna_llport_rx_started(struct bna_llport *llport)
-{
- llport->rx_started_count++;
-
- if (llport->rx_started_count == 1) {
-
- llport->flags |= BNA_LLPORT_F_RX_STARTED;
-
- if (llport_can_be_up(llport))
- bfa_fsm_send_event(llport, LLPORT_E_UP);
- }
-}
-
-void
-bna_llport_rx_stopped(struct bna_llport *llport)
-{
- int llport_up = llport_is_up(llport);
-
- llport->rx_started_count--;
-
- if (llport->rx_started_count == 0) {
-
- llport->flags &= ~BNA_LLPORT_F_RX_STARTED;
-
- if (llport_up)
- bfa_fsm_send_event(llport, LLPORT_E_DOWN);
- }
-}
-
-/**
- * PORT
- */
-#define bna_port_chld_start(port)\
-do {\
- enum bna_tx_type tx_type = ((port)->type == BNA_PORT_T_REGULAR) ?\
- BNA_TX_T_REGULAR : BNA_TX_T_LOOPBACK;\
- enum bna_rx_type rx_type = ((port)->type == BNA_PORT_T_REGULAR) ?\
- BNA_RX_T_REGULAR : BNA_RX_T_LOOPBACK;\
- bna_llport_start(&(port)->llport);\
- bna_tx_mod_start(&(port)->bna->tx_mod, tx_type);\
- bna_rx_mod_start(&(port)->bna->rx_mod, rx_type);\
-} while (0)
-
-#define bna_port_chld_stop(port)\
-do {\
- enum bna_tx_type tx_type = ((port)->type == BNA_PORT_T_REGULAR) ?\
- BNA_TX_T_REGULAR : BNA_TX_T_LOOPBACK;\
- enum bna_rx_type rx_type = ((port)->type == BNA_PORT_T_REGULAR) ?\
- BNA_RX_T_REGULAR : BNA_RX_T_LOOPBACK;\
- bfa_wc_up(&(port)->chld_stop_wc);\
- bfa_wc_up(&(port)->chld_stop_wc);\
- bfa_wc_up(&(port)->chld_stop_wc);\
- bna_llport_stop(&(port)->llport);\
- bna_tx_mod_stop(&(port)->bna->tx_mod, tx_type);\
- bna_rx_mod_stop(&(port)->bna->rx_mod, rx_type);\
-} while (0)
-
-#define bna_port_chld_fail(port)\
-do {\
- bna_llport_fail(&(port)->llport);\
- bna_tx_mod_fail(&(port)->bna->tx_mod);\
- bna_rx_mod_fail(&(port)->bna->rx_mod);\
-} while (0)
-
-#define bna_port_rx_start(port)\
-do {\
- enum bna_rx_type rx_type = ((port)->type == BNA_PORT_T_REGULAR) ?\
- BNA_RX_T_REGULAR : BNA_RX_T_LOOPBACK;\
- bna_rx_mod_start(&(port)->bna->rx_mod, rx_type);\
-} while (0)
-
-#define bna_port_rx_stop(port)\
-do {\
- enum bna_rx_type rx_type = ((port)->type == BNA_PORT_T_REGULAR) ?\
- BNA_RX_T_REGULAR : BNA_RX_T_LOOPBACK;\
- bfa_wc_up(&(port)->chld_stop_wc);\
- bna_rx_mod_stop(&(port)->bna->rx_mod, rx_type);\
-} while (0)
-
-#define call_port_stop_cbfn(port, status)\
-do {\
- if ((port)->stop_cbfn)\
- (port)->stop_cbfn((port)->stop_cbarg, status);\
- (port)->stop_cbfn = NULL;\
- (port)->stop_cbarg = NULL;\
-} while (0)
-
-#define call_port_pause_cbfn(port, status)\
-do {\
- if ((port)->pause_cbfn)\
- (port)->pause_cbfn((port)->bna->bnad, status);\
- (port)->pause_cbfn = NULL;\
-} while (0)
-
-#define call_port_mtu_cbfn(port, status)\
-do {\
- if ((port)->mtu_cbfn)\
- (port)->mtu_cbfn((port)->bna->bnad, status);\
- (port)->mtu_cbfn = NULL;\
-} while (0)
-
-static void bna_fw_pause_set(struct bna_port *port);
-static void bna_fw_cb_pause_set(void *arg, int status);
-static void bna_fw_mtu_set(struct bna_port *port);
-static void bna_fw_cb_mtu_set(void *arg, int status);
-
-enum bna_port_event {
- PORT_E_START = 1,
- PORT_E_STOP = 2,
- PORT_E_FAIL = 3,
- PORT_E_PAUSE_CFG = 4,
- PORT_E_MTU_CFG = 5,
- PORT_E_CHLD_STOPPED = 6,
- PORT_E_FWRESP_PAUSE = 7,
- PORT_E_FWRESP_MTU = 8
-};
-
-enum bna_port_state {
- BNA_PORT_STOPPED = 1,
- BNA_PORT_MTU_INIT_WAIT = 2,
- BNA_PORT_PAUSE_INIT_WAIT = 3,
- BNA_PORT_LAST_RESP_WAIT = 4,
- BNA_PORT_STARTED = 5,
- BNA_PORT_PAUSE_CFG_WAIT = 6,
- BNA_PORT_RX_STOP_WAIT = 7,
- BNA_PORT_MTU_CFG_WAIT = 8,
- BNA_PORT_CHLD_STOP_WAIT = 9
-};
-
-bfa_fsm_state_decl(bna_port, stopped, struct bna_port,
- enum bna_port_event);
-bfa_fsm_state_decl(bna_port, mtu_init_wait, struct bna_port,
- enum bna_port_event);
-bfa_fsm_state_decl(bna_port, pause_init_wait, struct bna_port,
- enum bna_port_event);
-bfa_fsm_state_decl(bna_port, last_resp_wait, struct bna_port,
- enum bna_port_event);
-bfa_fsm_state_decl(bna_port, started, struct bna_port,
- enum bna_port_event);
-bfa_fsm_state_decl(bna_port, pause_cfg_wait, struct bna_port,
- enum bna_port_event);
-bfa_fsm_state_decl(bna_port, rx_stop_wait, struct bna_port,
- enum bna_port_event);
-bfa_fsm_state_decl(bna_port, mtu_cfg_wait, struct bna_port,
- enum bna_port_event);
-bfa_fsm_state_decl(bna_port, chld_stop_wait, struct bna_port,
- enum bna_port_event);
-
-static struct bfa_sm_table port_sm_table[] = {
- {BFA_SM(bna_port_sm_stopped), BNA_PORT_STOPPED},
- {BFA_SM(bna_port_sm_mtu_init_wait), BNA_PORT_MTU_INIT_WAIT},
- {BFA_SM(bna_port_sm_pause_init_wait), BNA_PORT_PAUSE_INIT_WAIT},
- {BFA_SM(bna_port_sm_last_resp_wait), BNA_PORT_LAST_RESP_WAIT},
- {BFA_SM(bna_port_sm_started), BNA_PORT_STARTED},
- {BFA_SM(bna_port_sm_pause_cfg_wait), BNA_PORT_PAUSE_CFG_WAIT},
- {BFA_SM(bna_port_sm_rx_stop_wait), BNA_PORT_RX_STOP_WAIT},
- {BFA_SM(bna_port_sm_mtu_cfg_wait), BNA_PORT_MTU_CFG_WAIT},
- {BFA_SM(bna_port_sm_chld_stop_wait), BNA_PORT_CHLD_STOP_WAIT}
-};
-
-static void
-bna_port_sm_stopped_entry(struct bna_port *port)
-{
- call_port_pause_cbfn(port, BNA_CB_SUCCESS);
- call_port_mtu_cbfn(port, BNA_CB_SUCCESS);
- call_port_stop_cbfn(port, BNA_CB_SUCCESS);
-}
-
-static void
-bna_port_sm_stopped(struct bna_port *port, enum bna_port_event event)
-{
- switch (event) {
- case PORT_E_START:
- bfa_fsm_set_state(port, bna_port_sm_mtu_init_wait);
- break;
-
- case PORT_E_STOP:
- call_port_stop_cbfn(port, BNA_CB_SUCCESS);
- break;
-
- case PORT_E_FAIL:
- /* No-op */
- break;
-
- case PORT_E_PAUSE_CFG:
- call_port_pause_cbfn(port, BNA_CB_SUCCESS);
- break;
-
- case PORT_E_MTU_CFG:
- call_port_mtu_cbfn(port, BNA_CB_SUCCESS);
- break;
-
- case PORT_E_CHLD_STOPPED:
- /**
- * This event is received due to LLPort, Tx and Rx objects
- * failing
- */
- /* No-op */
- break;
-
- case PORT_E_FWRESP_PAUSE:
- case PORT_E_FWRESP_MTU:
- /**
- * These events are received due to flushing of mbox when
- * device fails
- */
- /* No-op */
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_port_sm_mtu_init_wait_entry(struct bna_port *port)
-{
- bna_fw_mtu_set(port);
-}
-
-static void
-bna_port_sm_mtu_init_wait(struct bna_port *port, enum bna_port_event event)
-{
- switch (event) {
- case PORT_E_STOP:
- bfa_fsm_set_state(port, bna_port_sm_last_resp_wait);
- break;
-
- case PORT_E_FAIL:
- bfa_fsm_set_state(port, bna_port_sm_stopped);
- break;
-
- case PORT_E_PAUSE_CFG:
- /* No-op */
- break;
-
- case PORT_E_MTU_CFG:
- port->flags |= BNA_PORT_F_MTU_CHANGED;
- break;
-
- case PORT_E_FWRESP_MTU:
- if (port->flags & BNA_PORT_F_MTU_CHANGED) {
- port->flags &= ~BNA_PORT_F_MTU_CHANGED;
- bna_fw_mtu_set(port);
- } else {
- bfa_fsm_set_state(port, bna_port_sm_pause_init_wait);
- }
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_port_sm_pause_init_wait_entry(struct bna_port *port)
-{
- bna_fw_pause_set(port);
-}
-
-static void
-bna_port_sm_pause_init_wait(struct bna_port *port,
- enum bna_port_event event)
-{
- switch (event) {
- case PORT_E_STOP:
- bfa_fsm_set_state(port, bna_port_sm_last_resp_wait);
- break;
-
- case PORT_E_FAIL:
- bfa_fsm_set_state(port, bna_port_sm_stopped);
- break;
-
- case PORT_E_PAUSE_CFG:
- port->flags |= BNA_PORT_F_PAUSE_CHANGED;
- break;
-
- case PORT_E_MTU_CFG:
- port->flags |= BNA_PORT_F_MTU_CHANGED;
- break;
-
- case PORT_E_FWRESP_PAUSE:
- if (port->flags & BNA_PORT_F_PAUSE_CHANGED) {
- port->flags &= ~BNA_PORT_F_PAUSE_CHANGED;
- bna_fw_pause_set(port);
- } else if (port->flags & BNA_PORT_F_MTU_CHANGED) {
- port->flags &= ~BNA_PORT_F_MTU_CHANGED;
- bfa_fsm_set_state(port, bna_port_sm_mtu_init_wait);
- } else {
- bfa_fsm_set_state(port, bna_port_sm_started);
- bna_port_chld_start(port);
- }
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_port_sm_last_resp_wait_entry(struct bna_port *port)
-{
-}
-
-static void
-bna_port_sm_last_resp_wait(struct bna_port *port,
- enum bna_port_event event)
-{
- switch (event) {
- case PORT_E_FAIL:
- case PORT_E_FWRESP_PAUSE:
- case PORT_E_FWRESP_MTU:
- bfa_fsm_set_state(port, bna_port_sm_stopped);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_port_sm_started_entry(struct bna_port *port)
-{
- /**
- * NOTE: Do not call bna_port_chld_start() here, since it will be
- * inadvertently called during pause_cfg_wait->started transition
- * as well
- */
- call_port_pause_cbfn(port, BNA_CB_SUCCESS);
- call_port_mtu_cbfn(port, BNA_CB_SUCCESS);
-}
-
-static void
-bna_port_sm_started(struct bna_port *port,
- enum bna_port_event event)
-{
- switch (event) {
- case PORT_E_STOP:
- bfa_fsm_set_state(port, bna_port_sm_chld_stop_wait);
- break;
-
- case PORT_E_FAIL:
- bfa_fsm_set_state(port, bna_port_sm_stopped);
- bna_port_chld_fail(port);
- break;
-
- case PORT_E_PAUSE_CFG:
- bfa_fsm_set_state(port, bna_port_sm_pause_cfg_wait);
- break;
-
- case PORT_E_MTU_CFG:
- bfa_fsm_set_state(port, bna_port_sm_rx_stop_wait);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_port_sm_pause_cfg_wait_entry(struct bna_port *port)
-{
- bna_fw_pause_set(port);
-}
-
-static void
-bna_port_sm_pause_cfg_wait(struct bna_port *port,
- enum bna_port_event event)
-{
- switch (event) {
- case PORT_E_FAIL:
- bfa_fsm_set_state(port, bna_port_sm_stopped);
- bna_port_chld_fail(port);
- break;
-
- case PORT_E_FWRESP_PAUSE:
- bfa_fsm_set_state(port, bna_port_sm_started);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_port_sm_rx_stop_wait_entry(struct bna_port *port)
-{
- bna_port_rx_stop(port);
-}
-
-static void
-bna_port_sm_rx_stop_wait(struct bna_port *port,
- enum bna_port_event event)
-{
- switch (event) {
- case PORT_E_FAIL:
- bfa_fsm_set_state(port, bna_port_sm_stopped);
- bna_port_chld_fail(port);
- break;
-
- case PORT_E_CHLD_STOPPED:
- bfa_fsm_set_state(port, bna_port_sm_mtu_cfg_wait);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_port_sm_mtu_cfg_wait_entry(struct bna_port *port)
-{
- bna_fw_mtu_set(port);
-}
-
-static void
-bna_port_sm_mtu_cfg_wait(struct bna_port *port, enum bna_port_event event)
-{
- switch (event) {
- case PORT_E_FAIL:
- bfa_fsm_set_state(port, bna_port_sm_stopped);
- bna_port_chld_fail(port);
- break;
-
- case PORT_E_FWRESP_MTU:
- bfa_fsm_set_state(port, bna_port_sm_started);
- bna_port_rx_start(port);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_port_sm_chld_stop_wait_entry(struct bna_port *port)
-{
- bna_port_chld_stop(port);
-}
-
-static void
-bna_port_sm_chld_stop_wait(struct bna_port *port,
- enum bna_port_event event)
-{
- switch (event) {
- case PORT_E_FAIL:
- bfa_fsm_set_state(port, bna_port_sm_stopped);
- bna_port_chld_fail(port);
- break;
-
- case PORT_E_CHLD_STOPPED:
- bfa_fsm_set_state(port, bna_port_sm_stopped);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_fw_pause_set(struct bna_port *port)
-{
- struct bfi_ll_set_pause_req ll_req;
-
- memset(&ll_req, 0, sizeof(ll_req));
- ll_req.mh.msg_class = BFI_MC_LL;
- ll_req.mh.msg_id = BFI_LL_H2I_SET_PAUSE_REQ;
- ll_req.mh.mtag.h2i.lpu_id = 0;
-
- ll_req.tx_pause = port->pause_config.tx_pause;
- ll_req.rx_pause = port->pause_config.rx_pause;
-
- bna_mbox_qe_fill(&port->mbox_qe, &ll_req, sizeof(ll_req),
- bna_fw_cb_pause_set, port);
-
- bna_mbox_send(port->bna, &port->mbox_qe);
-}
-
-static void
-bna_fw_cb_pause_set(void *arg, int status)
-{
- struct bna_port *port = (struct bna_port *)arg;
-
- bfa_q_qe_init(&port->mbox_qe.qe);
- bfa_fsm_send_event(port, PORT_E_FWRESP_PAUSE);
-}
-
-void
-bna_fw_mtu_set(struct bna_port *port)
-{
- struct bfi_ll_mtu_info_req ll_req;
-
- bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_MTU_INFO_REQ, 0);
- ll_req.mtu = htons((u16)port->mtu);
-
- bna_mbox_qe_fill(&port->mbox_qe, &ll_req, sizeof(ll_req),
- bna_fw_cb_mtu_set, port);
- bna_mbox_send(port->bna, &port->mbox_qe);
-}
-
-void
-bna_fw_cb_mtu_set(void *arg, int status)
-{
- struct bna_port *port = (struct bna_port *)arg;
-
- bfa_q_qe_init(&port->mbox_qe.qe);
- bfa_fsm_send_event(port, PORT_E_FWRESP_MTU);
-}
-
-static void
-bna_port_cb_chld_stopped(void *arg)
-{
- struct bna_port *port = (struct bna_port *)arg;
-
- bfa_fsm_send_event(port, PORT_E_CHLD_STOPPED);
-}
-
-static void
-bna_port_init(struct bna_port *port, struct bna *bna)
-{
- port->bna = bna;
- port->flags = 0;
- port->mtu = 0;
- port->type = BNA_PORT_T_REGULAR;
-
- port->link_cbfn = bnad_cb_port_link_status;
-
- port->chld_stop_wc.wc_resume = bna_port_cb_chld_stopped;
- port->chld_stop_wc.wc_cbarg = port;
- port->chld_stop_wc.wc_count = 0;
-
- port->stop_cbfn = NULL;
- port->stop_cbarg = NULL;
-
- port->pause_cbfn = NULL;
-
- port->mtu_cbfn = NULL;
-
- bfa_q_qe_init(&port->mbox_qe.qe);
-
- bfa_fsm_set_state(port, bna_port_sm_stopped);
-
- bna_llport_init(&port->llport, bna);
-}
-
-static void
-bna_port_uninit(struct bna_port *port)
-{
- bna_llport_uninit(&port->llport);
-
- port->flags = 0;
-
- port->bna = NULL;
-}
-
-static int
-bna_port_state_get(struct bna_port *port)
-{
- return bfa_sm_to_state(port_sm_table, port->fsm);
-}
-
-static void
-bna_port_start(struct bna_port *port)
-{
- port->flags |= BNA_PORT_F_DEVICE_READY;
- if (port->flags & BNA_PORT_F_ENABLED)
- bfa_fsm_send_event(port, PORT_E_START);
-}
-
-static void
-bna_port_stop(struct bna_port *port)
-{
- port->stop_cbfn = bna_device_cb_port_stopped;
- port->stop_cbarg = &port->bna->device;
-
- port->flags &= ~BNA_PORT_F_DEVICE_READY;
- bfa_fsm_send_event(port, PORT_E_STOP);
-}
-
-static void
-bna_port_fail(struct bna_port *port)
-{
- port->flags &= ~BNA_PORT_F_DEVICE_READY;
- bfa_fsm_send_event(port, PORT_E_FAIL);
-}
-
-void
-bna_port_cb_tx_stopped(struct bna_port *port, enum bna_cb_status status)
-{
- bfa_wc_down(&port->chld_stop_wc);
-}
-
-void
-bna_port_cb_rx_stopped(struct bna_port *port, enum bna_cb_status status)
-{
- bfa_wc_down(&port->chld_stop_wc);
-}
-
-int
-bna_port_mtu_get(struct bna_port *port)
-{
- return port->mtu;
-}
-
-void
-bna_port_enable(struct bna_port *port)
-{
- if (port->fsm != (bfa_sm_t)bna_port_sm_stopped)
- return;
-
- port->flags |= BNA_PORT_F_ENABLED;
-
- if (port->flags & BNA_PORT_F_DEVICE_READY)
- bfa_fsm_send_event(port, PORT_E_START);
-}
-
-void
-bna_port_disable(struct bna_port *port, enum bna_cleanup_type type,
- void (*cbfn)(void *, enum bna_cb_status))
-{
- if (type == BNA_SOFT_CLEANUP) {
- (*cbfn)(port->bna->bnad, BNA_CB_SUCCESS);
- return;
- }
-
- port->stop_cbfn = cbfn;
- port->stop_cbarg = port->bna->bnad;
-
- port->flags &= ~BNA_PORT_F_ENABLED;
-
- bfa_fsm_send_event(port, PORT_E_STOP);
-}
-
-void
-bna_port_pause_config(struct bna_port *port,
- struct bna_pause_config *pause_config,
- void (*cbfn)(struct bnad *, enum bna_cb_status))
-{
- port->pause_config = *pause_config;
-
- port->pause_cbfn = cbfn;
-
- bfa_fsm_send_event(port, PORT_E_PAUSE_CFG);
-}
-
-void
-bna_port_mtu_set(struct bna_port *port, int mtu,
- void (*cbfn)(struct bnad *, enum bna_cb_status))
-{
- port->mtu = mtu;
-
- port->mtu_cbfn = cbfn;
-
- bfa_fsm_send_event(port, PORT_E_MTU_CFG);
-}
-
-void
-bna_port_mac_get(struct bna_port *port, mac_t *mac)
-{
- *mac = bfa_nw_ioc_get_mac(&port->bna->device.ioc);
-}
-
-/**
- * DEVICE
- */
-#define enable_mbox_intr(_device)\
-do {\
- u32 intr_status;\
- bna_intr_status_get((_device)->bna, intr_status);\
- bnad_cb_device_enable_mbox_intr((_device)->bna->bnad);\
- bna_mbox_intr_enable((_device)->bna);\
-} while (0)
-
-#define disable_mbox_intr(_device)\
-do {\
- bna_mbox_intr_disable((_device)->bna);\
- bnad_cb_device_disable_mbox_intr((_device)->bna->bnad);\
-} while (0)
-
-static const struct bna_chip_regs_offset reg_offset[] =
-{{HOST_PAGE_NUM_FN0, HOSTFN0_INT_STATUS,
- HOSTFN0_INT_MASK, HOST_MSIX_ERR_INDEX_FN0},
-{HOST_PAGE_NUM_FN1, HOSTFN1_INT_STATUS,
- HOSTFN1_INT_MASK, HOST_MSIX_ERR_INDEX_FN1},
-{HOST_PAGE_NUM_FN2, HOSTFN2_INT_STATUS,
- HOSTFN2_INT_MASK, HOST_MSIX_ERR_INDEX_FN2},
-{HOST_PAGE_NUM_FN3, HOSTFN3_INT_STATUS,
- HOSTFN3_INT_MASK, HOST_MSIX_ERR_INDEX_FN3},
-};
-
-enum bna_device_event {
- DEVICE_E_ENABLE = 1,
- DEVICE_E_DISABLE = 2,
- DEVICE_E_IOC_READY = 3,
- DEVICE_E_IOC_FAILED = 4,
- DEVICE_E_IOC_DISABLED = 5,
- DEVICE_E_IOC_RESET = 6,
- DEVICE_E_PORT_STOPPED = 7,
-};
-
-enum bna_device_state {
- BNA_DEVICE_STOPPED = 1,
- BNA_DEVICE_IOC_READY_WAIT = 2,
- BNA_DEVICE_READY = 3,
- BNA_DEVICE_PORT_STOP_WAIT = 4,
- BNA_DEVICE_IOC_DISABLE_WAIT = 5,
- BNA_DEVICE_FAILED = 6
-};
-
-bfa_fsm_state_decl(bna_device, stopped, struct bna_device,
- enum bna_device_event);
-bfa_fsm_state_decl(bna_device, ioc_ready_wait, struct bna_device,
- enum bna_device_event);
-bfa_fsm_state_decl(bna_device, ready, struct bna_device,
- enum bna_device_event);
-bfa_fsm_state_decl(bna_device, port_stop_wait, struct bna_device,
- enum bna_device_event);
-bfa_fsm_state_decl(bna_device, ioc_disable_wait, struct bna_device,
- enum bna_device_event);
-bfa_fsm_state_decl(bna_device, failed, struct bna_device,
- enum bna_device_event);
-
-static struct bfa_sm_table device_sm_table[] = {
- {BFA_SM(bna_device_sm_stopped), BNA_DEVICE_STOPPED},
- {BFA_SM(bna_device_sm_ioc_ready_wait), BNA_DEVICE_IOC_READY_WAIT},
- {BFA_SM(bna_device_sm_ready), BNA_DEVICE_READY},
- {BFA_SM(bna_device_sm_port_stop_wait), BNA_DEVICE_PORT_STOP_WAIT},
- {BFA_SM(bna_device_sm_ioc_disable_wait), BNA_DEVICE_IOC_DISABLE_WAIT},
- {BFA_SM(bna_device_sm_failed), BNA_DEVICE_FAILED},
-};
-
-static void
-bna_device_sm_stopped_entry(struct bna_device *device)
-{
- if (device->stop_cbfn)
- device->stop_cbfn(device->stop_cbarg, BNA_CB_SUCCESS);
-
- device->stop_cbfn = NULL;
- device->stop_cbarg = NULL;
-}
-
-static void
-bna_device_sm_stopped(struct bna_device *device,
- enum bna_device_event event)
-{
- switch (event) {
- case DEVICE_E_ENABLE:
- if (device->intr_type == BNA_INTR_T_MSIX)
- bna_mbox_msix_idx_set(device);
- bfa_nw_ioc_enable(&device->ioc);
- bfa_fsm_set_state(device, bna_device_sm_ioc_ready_wait);
- break;
-
- case DEVICE_E_DISABLE:
- bfa_fsm_set_state(device, bna_device_sm_stopped);
- break;
-
- case DEVICE_E_IOC_RESET:
- enable_mbox_intr(device);
- break;
-
- case DEVICE_E_IOC_FAILED:
- bfa_fsm_set_state(device, bna_device_sm_failed);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_device_sm_ioc_ready_wait_entry(struct bna_device *device)
-{
- /**
- * Do not call bfa_ioc_enable() here. It must be called in the
- * previous state due to failed -> ioc_ready_wait transition.
- */
-}
-
-static void
-bna_device_sm_ioc_ready_wait(struct bna_device *device,
- enum bna_device_event event)
-{
- switch (event) {
- case DEVICE_E_DISABLE:
- if (device->ready_cbfn)
- device->ready_cbfn(device->ready_cbarg,
- BNA_CB_INTERRUPT);
- device->ready_cbfn = NULL;
- device->ready_cbarg = NULL;
- bfa_fsm_set_state(device, bna_device_sm_ioc_disable_wait);
- break;
-
- case DEVICE_E_IOC_READY:
- bfa_fsm_set_state(device, bna_device_sm_ready);
- break;
-
- case DEVICE_E_IOC_FAILED:
- bfa_fsm_set_state(device, bna_device_sm_failed);
- break;
-
- case DEVICE_E_IOC_RESET:
- enable_mbox_intr(device);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_device_sm_ready_entry(struct bna_device *device)
-{
- bna_mbox_mod_start(&device->bna->mbox_mod);
- bna_port_start(&device->bna->port);
-
- if (device->ready_cbfn)
- device->ready_cbfn(device->ready_cbarg,
- BNA_CB_SUCCESS);
- device->ready_cbfn = NULL;
- device->ready_cbarg = NULL;
-}
-
-static void
-bna_device_sm_ready(struct bna_device *device, enum bna_device_event event)
-{
- switch (event) {
- case DEVICE_E_DISABLE:
- bfa_fsm_set_state(device, bna_device_sm_port_stop_wait);
- break;
-
- case DEVICE_E_IOC_FAILED:
- bfa_fsm_set_state(device, bna_device_sm_failed);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_device_sm_port_stop_wait_entry(struct bna_device *device)
-{
- bna_port_stop(&device->bna->port);
-}
-
-static void
-bna_device_sm_port_stop_wait(struct bna_device *device,
- enum bna_device_event event)
-{
- switch (event) {
- case DEVICE_E_PORT_STOPPED:
- bna_mbox_mod_stop(&device->bna->mbox_mod);
- bfa_fsm_set_state(device, bna_device_sm_ioc_disable_wait);
- break;
-
- case DEVICE_E_IOC_FAILED:
- disable_mbox_intr(device);
- bna_port_fail(&device->bna->port);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_device_sm_ioc_disable_wait_entry(struct bna_device *device)
-{
- bfa_nw_ioc_disable(&device->ioc);
-}
-
-static void
-bna_device_sm_ioc_disable_wait(struct bna_device *device,
- enum bna_device_event event)
-{
- switch (event) {
- case DEVICE_E_IOC_DISABLED:
- disable_mbox_intr(device);
- bfa_fsm_set_state(device, bna_device_sm_stopped);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_device_sm_failed_entry(struct bna_device *device)
-{
- disable_mbox_intr(device);
- bna_port_fail(&device->bna->port);
- bna_mbox_mod_stop(&device->bna->mbox_mod);
-
- if (device->ready_cbfn)
- device->ready_cbfn(device->ready_cbarg,
- BNA_CB_FAIL);
- device->ready_cbfn = NULL;
- device->ready_cbarg = NULL;
-}
-
-static void
-bna_device_sm_failed(struct bna_device *device,
- enum bna_device_event event)
-{
- switch (event) {
- case DEVICE_E_DISABLE:
- bfa_fsm_set_state(device, bna_device_sm_ioc_disable_wait);
- break;
-
- case DEVICE_E_IOC_RESET:
- enable_mbox_intr(device);
- bfa_fsm_set_state(device, bna_device_sm_ioc_ready_wait);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-/* IOC callback functions */
-
-static void
-bna_device_cb_iocll_ready(void *dev, enum bfa_status error)
-{
- struct bna_device *device = (struct bna_device *)dev;
-
- if (error)
- bfa_fsm_send_event(device, DEVICE_E_IOC_FAILED);
- else
- bfa_fsm_send_event(device, DEVICE_E_IOC_READY);
-}
-
-static void
-bna_device_cb_iocll_disabled(void *dev)
-{
- struct bna_device *device = (struct bna_device *)dev;
-
- bfa_fsm_send_event(device, DEVICE_E_IOC_DISABLED);
-}
-
-static void
-bna_device_cb_iocll_failed(void *dev)
-{
- struct bna_device *device = (struct bna_device *)dev;
-
- bfa_fsm_send_event(device, DEVICE_E_IOC_FAILED);
-}
-
-static void
-bna_device_cb_iocll_reset(void *dev)
-{
- struct bna_device *device = (struct bna_device *)dev;
-
- bfa_fsm_send_event(device, DEVICE_E_IOC_RESET);
-}
-
-static struct bfa_ioc_cbfn bfa_iocll_cbfn = {
- bna_device_cb_iocll_ready,
- bna_device_cb_iocll_disabled,
- bna_device_cb_iocll_failed,
- bna_device_cb_iocll_reset
-};
-
-/* device */
-static void
-bna_adv_device_init(struct bna_device *device, struct bna *bna,
- struct bna_res_info *res_info)
-{
- u8 *kva;
- u64 dma;
-
- device->bna = bna;
-
- kva = res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.mdl[0].kva;
-
- /**
- * Attach common modules (Diag, SFP, CEE, Port) and claim respective
- * DMA memory.
- */
- BNA_GET_DMA_ADDR(
- &res_info[BNA_RES_MEM_T_COM].res_u.mem_info.mdl[0].dma, dma);
- kva = res_info[BNA_RES_MEM_T_COM].res_u.mem_info.mdl[0].kva;
-
- bfa_nw_cee_attach(&bna->cee, &device->ioc, bna);
- bfa_nw_cee_mem_claim(&bna->cee, kva, dma);
- kva += bfa_nw_cee_meminfo();
- dma += bfa_nw_cee_meminfo();
-
-}
-
-static void
-bna_device_init(struct bna_device *device, struct bna *bna,
- struct bna_res_info *res_info)
-{
- u64 dma;
-
- device->bna = bna;
-
- /**
- * Attach IOC and claim:
- * 1. DMA memory for IOC attributes
- * 2. Kernel memory for FW trace
- */
- bfa_nw_ioc_attach(&device->ioc, device, &bfa_iocll_cbfn);
- bfa_nw_ioc_pci_init(&device->ioc, &bna->pcidev, BFI_MC_LL);
-
- BNA_GET_DMA_ADDR(
- &res_info[BNA_RES_MEM_T_ATTR].res_u.mem_info.mdl[0].dma, dma);
- bfa_nw_ioc_mem_claim(&device->ioc,
- res_info[BNA_RES_MEM_T_ATTR].res_u.mem_info.mdl[0].kva,
- dma);
-
- bna_adv_device_init(device, bna, res_info);
- /*
- * Initialize mbox_mod only after IOC, so that mbox handler
- * registration goes through
- */
- device->intr_type =
- res_info[BNA_RES_INTR_T_MBOX].res_u.intr_info.intr_type;
- device->vector =
- res_info[BNA_RES_INTR_T_MBOX].res_u.intr_info.idl[0].vector;
- bna_mbox_mod_init(&bna->mbox_mod, bna);
-
- device->ready_cbfn = device->stop_cbfn = NULL;
- device->ready_cbarg = device->stop_cbarg = NULL;
-
- bfa_fsm_set_state(device, bna_device_sm_stopped);
-}
-
-static void
-bna_device_uninit(struct bna_device *device)
-{
- bna_mbox_mod_uninit(&device->bna->mbox_mod);
-
- bfa_nw_ioc_detach(&device->ioc);
-
- device->bna = NULL;
-}
-
-static void
-bna_device_cb_port_stopped(void *arg, enum bna_cb_status status)
-{
- struct bna_device *device = (struct bna_device *)arg;
-
- bfa_fsm_send_event(device, DEVICE_E_PORT_STOPPED);
-}
-
-static int
-bna_device_status_get(struct bna_device *device)
-{
- return device->fsm == (bfa_fsm_t)bna_device_sm_ready;
-}
-
-void
-bna_device_enable(struct bna_device *device)
-{
- if (device->fsm != (bfa_fsm_t)bna_device_sm_stopped) {
- bnad_cb_device_enabled(device->bna->bnad, BNA_CB_BUSY);
- return;
- }
-
- device->ready_cbfn = bnad_cb_device_enabled;
- device->ready_cbarg = device->bna->bnad;
-
- bfa_fsm_send_event(device, DEVICE_E_ENABLE);
-}
-
-void
-bna_device_disable(struct bna_device *device, enum bna_cleanup_type type)
-{
- if (type == BNA_SOFT_CLEANUP) {
- bnad_cb_device_disabled(device->bna->bnad, BNA_CB_SUCCESS);
- return;
- }
-
- device->stop_cbfn = bnad_cb_device_disabled;
- device->stop_cbarg = device->bna->bnad;
-
- bfa_fsm_send_event(device, DEVICE_E_DISABLE);
-}
-
-static int
-bna_device_state_get(struct bna_device *device)
-{
- return bfa_sm_to_state(device_sm_table, device->fsm);
-}
-
-const u32 bna_napi_dim_vector[BNA_LOAD_T_MAX][BNA_BIAS_T_MAX] = {
- {12, 12},
- {6, 10},
- {5, 10},
- {4, 8},
- {3, 6},
- {3, 6},
- {2, 4},
- {1, 2},
-};
-
-/* utils */
-
-static void
-bna_adv_res_req(struct bna_res_info *res_info)
-{
- /* DMA memory for COMMON_MODULE */
- res_info[BNA_RES_MEM_T_COM].res_type = BNA_RES_T_MEM;
- res_info[BNA_RES_MEM_T_COM].res_u.mem_info.mem_type = BNA_MEM_T_DMA;
- res_info[BNA_RES_MEM_T_COM].res_u.mem_info.num = 1;
- res_info[BNA_RES_MEM_T_COM].res_u.mem_info.len = ALIGN(
- bfa_nw_cee_meminfo(), PAGE_SIZE);
-
- /* Virtual memory for retreiving fw_trc */
- res_info[BNA_RES_MEM_T_FWTRC].res_type = BNA_RES_T_MEM;
- res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.mem_type = BNA_MEM_T_KVA;
- res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.num = 0;
- res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.len = 0;
-
- /* DMA memory for retreiving stats */
- res_info[BNA_RES_MEM_T_STATS].res_type = BNA_RES_T_MEM;
- res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.mem_type = BNA_MEM_T_DMA;
- res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.num = 1;
- res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.len =
- ALIGN(BFI_HW_STATS_SIZE, PAGE_SIZE);
-
- /* Virtual memory for soft stats */
- res_info[BNA_RES_MEM_T_SWSTATS].res_type = BNA_RES_T_MEM;
- res_info[BNA_RES_MEM_T_SWSTATS].res_u.mem_info.mem_type = BNA_MEM_T_KVA;
- res_info[BNA_RES_MEM_T_SWSTATS].res_u.mem_info.num = 1;
- res_info[BNA_RES_MEM_T_SWSTATS].res_u.mem_info.len =
- sizeof(struct bna_sw_stats);
-}
-
-static void
-bna_sw_stats_get(struct bna *bna, struct bna_sw_stats *sw_stats)
-{
- struct bna_tx *tx;
- struct bna_txq *txq;
- struct bna_rx *rx;
- struct bna_rxp *rxp;
- struct list_head *qe;
- struct list_head *txq_qe;
- struct list_head *rxp_qe;
- struct list_head *mac_qe;
- int i;
-
- sw_stats->device_state = bna_device_state_get(&bna->device);
- sw_stats->port_state = bna_port_state_get(&bna->port);
- sw_stats->port_flags = bna->port.flags;
- sw_stats->llport_state = bna_llport_state_get(&bna->port.llport);
- sw_stats->priority = bna->port.priority;
-
- i = 0;
- list_for_each(qe, &bna->tx_mod.tx_active_q) {
- tx = (struct bna_tx *)qe;
- sw_stats->tx_stats[i].tx_state = bna_tx_state_get(tx);
- sw_stats->tx_stats[i].tx_flags = tx->flags;
-
- sw_stats->tx_stats[i].num_txqs = 0;
- sw_stats->tx_stats[i].txq_bmap[0] = 0;
- sw_stats->tx_stats[i].txq_bmap[1] = 0;
- list_for_each(txq_qe, &tx->txq_q) {
- txq = (struct bna_txq *)txq_qe;
- if (txq->txq_id < 32)
- sw_stats->tx_stats[i].txq_bmap[0] |=
- ((u32)1 << txq->txq_id);
- else
- sw_stats->tx_stats[i].txq_bmap[1] |=
- ((u32)
- 1 << (txq->txq_id - 32));
- sw_stats->tx_stats[i].num_txqs++;
- }
-
- sw_stats->tx_stats[i].txf_id = tx->txf.txf_id;
-
- i++;
- }
- sw_stats->num_active_tx = i;
-
- i = 0;
- list_for_each(qe, &bna->rx_mod.rx_active_q) {
- rx = (struct bna_rx *)qe;
- sw_stats->rx_stats[i].rx_state = bna_rx_state_get(rx);
- sw_stats->rx_stats[i].rx_flags = rx->rx_flags;
-
- sw_stats->rx_stats[i].num_rxps = 0;
- sw_stats->rx_stats[i].num_rxqs = 0;
- sw_stats->rx_stats[i].rxq_bmap[0] = 0;
- sw_stats->rx_stats[i].rxq_bmap[1] = 0;
- sw_stats->rx_stats[i].cq_bmap[0] = 0;
- sw_stats->rx_stats[i].cq_bmap[1] = 0;
- list_for_each(rxp_qe, &rx->rxp_q) {
- rxp = (struct bna_rxp *)rxp_qe;
-
- sw_stats->rx_stats[i].num_rxqs += 1;
-
- if (rxp->type == BNA_RXP_SINGLE) {
- if (rxp->rxq.single.only->rxq_id < 32) {
- sw_stats->rx_stats[i].rxq_bmap[0] |=
- ((u32)1 <<
- rxp->rxq.single.only->rxq_id);
- } else {
- sw_stats->rx_stats[i].rxq_bmap[1] |=
- ((u32)1 <<
- (rxp->rxq.single.only->rxq_id - 32));
- }
- } else {
- if (rxp->rxq.slr.large->rxq_id < 32) {
- sw_stats->rx_stats[i].rxq_bmap[0] |=
- ((u32)1 <<
- rxp->rxq.slr.large->rxq_id);
- } else {
- sw_stats->rx_stats[i].rxq_bmap[1] |=
- ((u32)1 <<
- (rxp->rxq.slr.large->rxq_id - 32));
- }
-
- if (rxp->rxq.slr.small->rxq_id < 32) {
- sw_stats->rx_stats[i].rxq_bmap[0] |=
- ((u32)1 <<
- rxp->rxq.slr.small->rxq_id);
- } else {
- sw_stats->rx_stats[i].rxq_bmap[1] |=
- ((u32)1 <<
- (rxp->rxq.slr.small->rxq_id - 32));
- }
- sw_stats->rx_stats[i].num_rxqs += 1;
- }
-
- if (rxp->cq.cq_id < 32)
- sw_stats->rx_stats[i].cq_bmap[0] |=
- (1 << rxp->cq.cq_id);
- else
- sw_stats->rx_stats[i].cq_bmap[1] |=
- (1 << (rxp->cq.cq_id - 32));
-
- sw_stats->rx_stats[i].num_rxps++;
- }
-
- sw_stats->rx_stats[i].rxf_id = rx->rxf.rxf_id;
- sw_stats->rx_stats[i].rxf_state = bna_rxf_state_get(&rx->rxf);
- sw_stats->rx_stats[i].rxf_oper_state = rx->rxf.rxf_oper_state;
-
- sw_stats->rx_stats[i].num_active_ucast = 0;
- if (rx->rxf.ucast_active_mac)
- sw_stats->rx_stats[i].num_active_ucast++;
- list_for_each(mac_qe, &rx->rxf.ucast_active_q)
- sw_stats->rx_stats[i].num_active_ucast++;
-
- sw_stats->rx_stats[i].num_active_mcast = 0;
- list_for_each(mac_qe, &rx->rxf.mcast_active_q)
- sw_stats->rx_stats[i].num_active_mcast++;
-
- sw_stats->rx_stats[i].rxmode_active = rx->rxf.rxmode_active;
- sw_stats->rx_stats[i].vlan_filter_status =
- rx->rxf.vlan_filter_status;
- memcpy(sw_stats->rx_stats[i].vlan_filter_table,
- rx->rxf.vlan_filter_table,
- sizeof(u32) * ((BFI_MAX_VLAN + 1) / 32));
-
- sw_stats->rx_stats[i].rss_status = rx->rxf.rss_status;
- sw_stats->rx_stats[i].hds_status = rx->rxf.hds_status;
-
- i++;
- }
- sw_stats->num_active_rx = i;
-}
-
-static void
-bna_fw_cb_stats_get(void *arg, int status)
-{
- struct bna *bna = (struct bna *)arg;
- u64 *p_stats;
- int i, count;
- int rxf_count, txf_count;
- u64 rxf_bmap, txf_bmap;
-
- bfa_q_qe_init(&bna->mbox_qe.qe);
-
- if (status == 0) {
- p_stats = (u64 *)bna->stats.hw_stats;
- count = sizeof(struct bfi_ll_stats) / sizeof(u64);
- for (i = 0; i < count; i++)
- p_stats[i] = cpu_to_be64(p_stats[i]);
-
- rxf_count = 0;
- rxf_bmap = (u64)bna->stats.rxf_bmap[0] |
- ((u64)bna->stats.rxf_bmap[1] << 32);
- for (i = 0; i < BFI_LL_RXF_ID_MAX; i++)
- if (rxf_bmap & ((u64)1 << i))
- rxf_count++;
-
- txf_count = 0;
- txf_bmap = (u64)bna->stats.txf_bmap[0] |
- ((u64)bna->stats.txf_bmap[1] << 32);
- for (i = 0; i < BFI_LL_TXF_ID_MAX; i++)
- if (txf_bmap & ((u64)1 << i))
- txf_count++;
-
- p_stats = (u64 *)&bna->stats.hw_stats->rxf_stats[0] +
- ((rxf_count * sizeof(struct bfi_ll_stats_rxf) +
- txf_count * sizeof(struct bfi_ll_stats_txf))/
- sizeof(u64));
-
- /* Populate the TXF stats from the firmware DMAed copy */
- for (i = (BFI_LL_TXF_ID_MAX - 1); i >= 0; i--)
- if (txf_bmap & ((u64)1 << i)) {
- p_stats -= sizeof(struct bfi_ll_stats_txf)/
- sizeof(u64);
- memcpy(&bna->stats.hw_stats->txf_stats[i],
- p_stats,
- sizeof(struct bfi_ll_stats_txf));
- }
-
- /* Populate the RXF stats from the firmware DMAed copy */
- for (i = (BFI_LL_RXF_ID_MAX - 1); i >= 0; i--)
- if (rxf_bmap & ((u64)1 << i)) {
- p_stats -= sizeof(struct bfi_ll_stats_rxf)/
- sizeof(u64);
- memcpy(&bna->stats.hw_stats->rxf_stats[i],
- p_stats,
- sizeof(struct bfi_ll_stats_rxf));
- }
-
- bna_sw_stats_get(bna, bna->stats.sw_stats);
- bnad_cb_stats_get(bna->bnad, BNA_CB_SUCCESS, &bna->stats);
- } else
- bnad_cb_stats_get(bna->bnad, BNA_CB_FAIL, &bna->stats);
-}
-
-static void
-bna_fw_stats_get(struct bna *bna)
-{
- struct bfi_ll_stats_req ll_req;
-
- bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_STATS_GET_REQ, 0);
- ll_req.stats_mask = htons(BFI_LL_STATS_ALL);
-
- ll_req.rxf_id_mask[0] = htonl(bna->rx_mod.rxf_bmap[0]);
- ll_req.rxf_id_mask[1] = htonl(bna->rx_mod.rxf_bmap[1]);
- ll_req.txf_id_mask[0] = htonl(bna->tx_mod.txf_bmap[0]);
- ll_req.txf_id_mask[1] = htonl(bna->tx_mod.txf_bmap[1]);
-
- ll_req.host_buffer.a32.addr_hi = bna->hw_stats_dma.msb;
- ll_req.host_buffer.a32.addr_lo = bna->hw_stats_dma.lsb;
-
- bna_mbox_qe_fill(&bna->mbox_qe, &ll_req, sizeof(ll_req),
- bna_fw_cb_stats_get, bna);
- bna_mbox_send(bna, &bna->mbox_qe);
-
- bna->stats.rxf_bmap[0] = bna->rx_mod.rxf_bmap[0];
- bna->stats.rxf_bmap[1] = bna->rx_mod.rxf_bmap[1];
- bna->stats.txf_bmap[0] = bna->tx_mod.txf_bmap[0];
- bna->stats.txf_bmap[1] = bna->tx_mod.txf_bmap[1];
-}
-
-void
-bna_stats_get(struct bna *bna)
-{
- if (bna_device_status_get(&bna->device))
- bna_fw_stats_get(bna);
- else
- bnad_cb_stats_get(bna->bnad, BNA_CB_FAIL, &bna->stats);
-}
-
-/* IB */
-static void
-bna_ib_coalescing_timeo_set(struct bna_ib *ib, u8 coalescing_timeo)
-{
- ib->ib_config.coalescing_timeo = coalescing_timeo;
-
- if (ib->start_count)
- ib->door_bell.doorbell_ack = BNA_DOORBELL_IB_INT_ACK(
- (u32)ib->ib_config.coalescing_timeo, 0);
-}
-
-/* RxF */
-void
-bna_rxf_adv_init(struct bna_rxf *rxf,
- struct bna_rx *rx,
- struct bna_rx_config *q_config)
-{
- switch (q_config->rxp_type) {
- case BNA_RXP_SINGLE:
- /* No-op */
- break;
- case BNA_RXP_SLR:
- rxf->ctrl_flags |= BNA_RXF_CF_SM_LG_RXQ;
- break;
- case BNA_RXP_HDS:
- rxf->hds_cfg.hdr_type = q_config->hds_config.hdr_type;
- rxf->hds_cfg.header_size =
- q_config->hds_config.header_size;
- rxf->forced_offset = 0;
- break;
- default:
- break;
- }
-
- if (q_config->rss_status == BNA_STATUS_T_ENABLED) {
- rxf->ctrl_flags |= BNA_RXF_CF_RSS_ENABLE;
- rxf->rss_cfg.hash_type = q_config->rss_config.hash_type;
- rxf->rss_cfg.hash_mask = q_config->rss_config.hash_mask;
- memcpy(&rxf->rss_cfg.toeplitz_hash_key[0],
- &q_config->rss_config.toeplitz_hash_key[0],
- sizeof(rxf->rss_cfg.toeplitz_hash_key));
- }
-}
-
-static void
-rxf_fltr_mbox_cmd(struct bna_rxf *rxf, u8 cmd, enum bna_status status)
-{
- struct bfi_ll_rxf_req req;
-
- bfi_h2i_set(req.mh, BFI_MC_LL, cmd, 0);
-
- req.rxf_id = rxf->rxf_id;
- req.enable = status;
-
- bna_mbox_qe_fill(&rxf->mbox_qe, &req, sizeof(req),
- rxf_cb_cam_fltr_mbox_cmd, rxf);
-
- bna_mbox_send(rxf->rx->bna, &rxf->mbox_qe);
-}
-
-int
-rxf_process_packet_filter_ucast(struct bna_rxf *rxf)
-{
- struct bna_mac *mac = NULL;
- struct list_head *qe;
-
- /* Add additional MAC entries */
- if (!list_empty(&rxf->ucast_pending_add_q)) {
- bfa_q_deq(&rxf->ucast_pending_add_q, &qe);
- bfa_q_qe_init(qe);
- mac = (struct bna_mac *)qe;
- rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_UCAST_ADD_REQ, mac);
- list_add_tail(&mac->qe, &rxf->ucast_active_q);
- return 1;
- }
-
- /* Delete MAC addresses previousely added */
- if (!list_empty(&rxf->ucast_pending_del_q)) {
- bfa_q_deq(&rxf->ucast_pending_del_q, &qe);
- bfa_q_qe_init(qe);
- mac = (struct bna_mac *)qe;
- rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_UCAST_DEL_REQ, mac);
- bna_ucam_mod_mac_put(&rxf->rx->bna->ucam_mod, mac);
- return 1;
- }
-
- return 0;
-}
-
-int
-rxf_process_packet_filter_promisc(struct bna_rxf *rxf)
-{
- struct bna *bna = rxf->rx->bna;
-
- /* Enable/disable promiscuous mode */
- if (is_promisc_enable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask)) {
- /* move promisc configuration from pending -> active */
- promisc_inactive(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- rxf->rxmode_active |= BNA_RXMODE_PROMISC;
-
- /* Disable VLAN filter to allow all VLANs */
- __rxf_vlan_filter_set(rxf, BNA_STATUS_T_DISABLED);
- rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_PROMISCUOUS_SET_REQ,
- BNA_STATUS_T_ENABLED);
- return 1;
- } else if (is_promisc_disable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask)) {
- /* move promisc configuration from pending -> active */
- promisc_inactive(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- rxf->rxmode_active &= ~BNA_RXMODE_PROMISC;
- bna->rxf_promisc_id = BFI_MAX_RXF;
-
- /* Revert VLAN filter */
- __rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
- rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_PROMISCUOUS_SET_REQ,
- BNA_STATUS_T_DISABLED);
- return 1;
- }
-
- return 0;
-}
-
-int
-rxf_process_packet_filter_allmulti(struct bna_rxf *rxf)
-{
- /* Enable/disable allmulti mode */
- if (is_allmulti_enable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask)) {
- /* move allmulti configuration from pending -> active */
- allmulti_inactive(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- rxf->rxmode_active |= BNA_RXMODE_ALLMULTI;
-
- rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_FILTER_REQ,
- BNA_STATUS_T_ENABLED);
- return 1;
- } else if (is_allmulti_disable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask)) {
- /* move allmulti configuration from pending -> active */
- allmulti_inactive(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- rxf->rxmode_active &= ~BNA_RXMODE_ALLMULTI;
-
- rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_FILTER_REQ,
- BNA_STATUS_T_DISABLED);
- return 1;
- }
-
- return 0;
-}
-
-int
-rxf_clear_packet_filter_ucast(struct bna_rxf *rxf)
-{
- struct bna_mac *mac = NULL;
- struct list_head *qe;
-
- /* 1. delete pending ucast entries */
- if (!list_empty(&rxf->ucast_pending_del_q)) {
- bfa_q_deq(&rxf->ucast_pending_del_q, &qe);
- bfa_q_qe_init(qe);
- mac = (struct bna_mac *)qe;
- rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_UCAST_DEL_REQ, mac);
- bna_ucam_mod_mac_put(&rxf->rx->bna->ucam_mod, mac);
- return 1;
- }
-
- /* 2. clear active ucast entries; move them to pending_add_q */
- if (!list_empty(&rxf->ucast_active_q)) {
- bfa_q_deq(&rxf->ucast_active_q, &qe);
- bfa_q_qe_init(qe);
- mac = (struct bna_mac *)qe;
- rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_UCAST_DEL_REQ, mac);
- list_add_tail(&mac->qe, &rxf->ucast_pending_add_q);
- return 1;
- }
-
- return 0;
-}
-
-int
-rxf_clear_packet_filter_promisc(struct bna_rxf *rxf)
-{
- struct bna *bna = rxf->rx->bna;
-
- /* 6. Execute pending promisc mode disable command */
- if (is_promisc_disable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask)) {
- /* move promisc configuration from pending -> active */
- promisc_inactive(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- rxf->rxmode_active &= ~BNA_RXMODE_PROMISC;
- bna->rxf_promisc_id = BFI_MAX_RXF;
-
- /* Revert VLAN filter */
- __rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
- rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_PROMISCUOUS_SET_REQ,
- BNA_STATUS_T_DISABLED);
- return 1;
- }
-
- /* 7. Clear active promisc mode; move it to pending enable */
- if (rxf->rxmode_active & BNA_RXMODE_PROMISC) {
- /* move promisc configuration from active -> pending */
- promisc_enable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- rxf->rxmode_active &= ~BNA_RXMODE_PROMISC;
-
- /* Revert VLAN filter */
- __rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
- rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_PROMISCUOUS_SET_REQ,
- BNA_STATUS_T_DISABLED);
- return 1;
- }
-
- return 0;
-}
-
-int
-rxf_clear_packet_filter_allmulti(struct bna_rxf *rxf)
-{
- /* 10. Execute pending allmulti mode disable command */
- if (is_allmulti_disable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask)) {
- /* move allmulti configuration from pending -> active */
- allmulti_inactive(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- rxf->rxmode_active &= ~BNA_RXMODE_ALLMULTI;
- rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_FILTER_REQ,
- BNA_STATUS_T_DISABLED);
- return 1;
- }
-
- /* 11. Clear active allmulti mode; move it to pending enable */
- if (rxf->rxmode_active & BNA_RXMODE_ALLMULTI) {
- /* move allmulti configuration from active -> pending */
- allmulti_enable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- rxf->rxmode_active &= ~BNA_RXMODE_ALLMULTI;
- rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_FILTER_REQ,
- BNA_STATUS_T_DISABLED);
- return 1;
- }
-
- return 0;
-}
-
-void
-rxf_reset_packet_filter_ucast(struct bna_rxf *rxf)
-{
- struct list_head *qe;
- struct bna_mac *mac;
-
- /* 1. Move active ucast entries to pending_add_q */
- while (!list_empty(&rxf->ucast_active_q)) {
- bfa_q_deq(&rxf->ucast_active_q, &qe);
- bfa_q_qe_init(qe);
- list_add_tail(qe, &rxf->ucast_pending_add_q);
- }
-
- /* 2. Throw away delete pending ucast entries */
- while (!list_empty(&rxf->ucast_pending_del_q)) {
- bfa_q_deq(&rxf->ucast_pending_del_q, &qe);
- bfa_q_qe_init(qe);
- mac = (struct bna_mac *)qe;
- bna_ucam_mod_mac_put(&rxf->rx->bna->ucam_mod, mac);
- }
-}
-
-void
-rxf_reset_packet_filter_promisc(struct bna_rxf *rxf)
-{
- struct bna *bna = rxf->rx->bna;
-
- /* 6. Clear pending promisc mode disable */
- if (is_promisc_disable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask)) {
- promisc_inactive(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- rxf->rxmode_active &= ~BNA_RXMODE_PROMISC;
- bna->rxf_promisc_id = BFI_MAX_RXF;
- }
-
- /* 7. Move promisc mode config from active -> pending */
- if (rxf->rxmode_active & BNA_RXMODE_PROMISC) {
- promisc_enable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- rxf->rxmode_active &= ~BNA_RXMODE_PROMISC;
- }
-
-}
-
-void
-rxf_reset_packet_filter_allmulti(struct bna_rxf *rxf)
-{
- /* 10. Clear pending allmulti mode disable */
- if (is_allmulti_disable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask)) {
- allmulti_inactive(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- rxf->rxmode_active &= ~BNA_RXMODE_ALLMULTI;
- }
-
- /* 11. Move allmulti mode config from active -> pending */
- if (rxf->rxmode_active & BNA_RXMODE_ALLMULTI) {
- allmulti_enable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- rxf->rxmode_active &= ~BNA_RXMODE_ALLMULTI;
- }
-}
-
-/**
- * Should only be called by bna_rxf_mode_set.
- * Helps deciding if h/w configuration is needed or not.
- * Returns:
- * 0 = no h/w change
- * 1 = need h/w change
- */
-static int
-rxf_promisc_enable(struct bna_rxf *rxf)
-{
- struct bna *bna = rxf->rx->bna;
- int ret = 0;
-
- /* There can not be any pending disable command */
-
- /* Do nothing if pending enable or already enabled */
- if (is_promisc_enable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask) ||
- (rxf->rxmode_active & BNA_RXMODE_PROMISC)) {
- /* Schedule enable */
- } else {
- /* Promisc mode should not be active in the system */
- promisc_enable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- bna->rxf_promisc_id = rxf->rxf_id;
- ret = 1;
- }
-
- return ret;
-}
-
-/**
- * Should only be called by bna_rxf_mode_set.
- * Helps deciding if h/w configuration is needed or not.
- * Returns:
- * 0 = no h/w change
- * 1 = need h/w change
- */
-static int
-rxf_promisc_disable(struct bna_rxf *rxf)
-{
- struct bna *bna = rxf->rx->bna;
- int ret = 0;
-
- /* There can not be any pending disable */
-
- /* Turn off pending enable command , if any */
- if (is_promisc_enable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask)) {
- /* Promisc mode should not be active */
- /* system promisc state should be pending */
- promisc_inactive(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- /* Remove the promisc state from the system */
- bna->rxf_promisc_id = BFI_MAX_RXF;
-
- /* Schedule disable */
- } else if (rxf->rxmode_active & BNA_RXMODE_PROMISC) {
- /* Promisc mode should be active in the system */
- promisc_disable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- ret = 1;
-
- /* Do nothing if already disabled */
- } else {
- }
-
- return ret;
-}
-
-/**
- * Should only be called by bna_rxf_mode_set.
- * Helps deciding if h/w configuration is needed or not.
- * Returns:
- * 0 = no h/w change
- * 1 = need h/w change
- */
-static int
-rxf_allmulti_enable(struct bna_rxf *rxf)
-{
- int ret = 0;
-
- /* There can not be any pending disable command */
-
- /* Do nothing if pending enable or already enabled */
- if (is_allmulti_enable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask) ||
- (rxf->rxmode_active & BNA_RXMODE_ALLMULTI)) {
- /* Schedule enable */
- } else {
- allmulti_enable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- ret = 1;
- }
-
- return ret;
-}
-
-/**
- * Should only be called by bna_rxf_mode_set.
- * Helps deciding if h/w configuration is needed or not.
- * Returns:
- * 0 = no h/w change
- * 1 = need h/w change
- */
-static int
-rxf_allmulti_disable(struct bna_rxf *rxf)
-{
- int ret = 0;
-
- /* There can not be any pending disable */
-
- /* Turn off pending enable command , if any */
- if (is_allmulti_enable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask)) {
- /* Allmulti mode should not be active */
- allmulti_inactive(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
-
- /* Schedule disable */
- } else if (rxf->rxmode_active & BNA_RXMODE_ALLMULTI) {
- allmulti_disable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- ret = 1;
- }
-
- return ret;
-}
-
-/* RxF <- bnad */
-enum bna_cb_status
-bna_rx_mode_set(struct bna_rx *rx, enum bna_rxmode new_mode,
- enum bna_rxmode bitmask,
- void (*cbfn)(struct bnad *, struct bna_rx *,
- enum bna_cb_status))
-{
- struct bna_rxf *rxf = &rx->rxf;
- int need_hw_config = 0;
-
- /* Process the commands */
-
- if (is_promisc_enable(new_mode, bitmask)) {
- /* If promisc mode is already enabled elsewhere in the system */
- if ((rx->bna->rxf_promisc_id != BFI_MAX_RXF) &&
- (rx->bna->rxf_promisc_id != rxf->rxf_id))
- goto err_return;
- if (rxf_promisc_enable(rxf))
- need_hw_config = 1;
- } else if (is_promisc_disable(new_mode, bitmask)) {
- if (rxf_promisc_disable(rxf))
- need_hw_config = 1;
- }
-
- if (is_allmulti_enable(new_mode, bitmask)) {
- if (rxf_allmulti_enable(rxf))
- need_hw_config = 1;
- } else if (is_allmulti_disable(new_mode, bitmask)) {
- if (rxf_allmulti_disable(rxf))
- need_hw_config = 1;
- }
-
- /* Trigger h/w if needed */
-
- if (need_hw_config) {
- rxf->cam_fltr_cbfn = cbfn;
- rxf->cam_fltr_cbarg = rx->bna->bnad;
- bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
- } else if (cbfn)
- (*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
-
- return BNA_CB_SUCCESS;
-
-err_return:
- return BNA_CB_FAIL;
-}
-
-void
-/* RxF <- bnad */
-bna_rx_vlanfilter_enable(struct bna_rx *rx)
-{
- struct bna_rxf *rxf = &rx->rxf;
-
- if (rxf->vlan_filter_status == BNA_STATUS_T_DISABLED) {
- rxf->rxf_flags |= BNA_RXF_FL_VLAN_CONFIG_PENDING;
- rxf->vlan_filter_status = BNA_STATUS_T_ENABLED;
- bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
- }
-}
-
-/* Rx */
-
-/* Rx <- bnad */
-void
-bna_rx_coalescing_timeo_set(struct bna_rx *rx, int coalescing_timeo)
-{
- struct bna_rxp *rxp;
- struct list_head *qe;
-
- list_for_each(qe, &rx->rxp_q) {
- rxp = (struct bna_rxp *)qe;
- rxp->cq.ccb->rx_coalescing_timeo = coalescing_timeo;
- bna_ib_coalescing_timeo_set(rxp->cq.ib, coalescing_timeo);
- }
-}
-
-/* Rx <- bnad */
-void
-bna_rx_dim_reconfig(struct bna *bna, const u32 vector[][BNA_BIAS_T_MAX])
-{
- int i, j;
-
- for (i = 0; i < BNA_LOAD_T_MAX; i++)
- for (j = 0; j < BNA_BIAS_T_MAX; j++)
- bna->rx_mod.dim_vector[i][j] = vector[i][j];
-}
-
-/* Rx <- bnad */
-void
-bna_rx_dim_update(struct bna_ccb *ccb)
-{
- struct bna *bna = ccb->cq->rx->bna;
- u32 load, bias;
- u32 pkt_rt, small_rt, large_rt;
- u8 coalescing_timeo;
-
- if ((ccb->pkt_rate.small_pkt_cnt == 0) &&
- (ccb->pkt_rate.large_pkt_cnt == 0))
- return;
-
- /* Arrive at preconfigured coalescing timeo value based on pkt rate */
-
- small_rt = ccb->pkt_rate.small_pkt_cnt;
- large_rt = ccb->pkt_rate.large_pkt_cnt;
-
- pkt_rt = small_rt + large_rt;
-
- if (pkt_rt < BNA_PKT_RATE_10K)
- load = BNA_LOAD_T_LOW_4;
- else if (pkt_rt < BNA_PKT_RATE_20K)
- load = BNA_LOAD_T_LOW_3;
- else if (pkt_rt < BNA_PKT_RATE_30K)
- load = BNA_LOAD_T_LOW_2;
- else if (pkt_rt < BNA_PKT_RATE_40K)
- load = BNA_LOAD_T_LOW_1;
- else if (pkt_rt < BNA_PKT_RATE_50K)
- load = BNA_LOAD_T_HIGH_1;
- else if (pkt_rt < BNA_PKT_RATE_60K)
- load = BNA_LOAD_T_HIGH_2;
- else if (pkt_rt < BNA_PKT_RATE_80K)
- load = BNA_LOAD_T_HIGH_3;
- else
- load = BNA_LOAD_T_HIGH_4;
-
- if (small_rt > (large_rt << 1))
- bias = 0;
- else
- bias = 1;
-
- ccb->pkt_rate.small_pkt_cnt = 0;
- ccb->pkt_rate.large_pkt_cnt = 0;
-
- coalescing_timeo = bna->rx_mod.dim_vector[load][bias];
- ccb->rx_coalescing_timeo = coalescing_timeo;
-
- /* Set it to IB */
- bna_ib_coalescing_timeo_set(ccb->cq->ib, coalescing_timeo);
-}
-
-/* Tx */
-/* TX <- bnad */
-void
-bna_tx_coalescing_timeo_set(struct bna_tx *tx, int coalescing_timeo)
-{
- struct bna_txq *txq;
- struct list_head *qe;
-
- list_for_each(qe, &tx->txq_q) {
- txq = (struct bna_txq *)qe;
- bna_ib_coalescing_timeo_set(txq->ib, coalescing_timeo);
- }
-}
-
-/*
- * Private data
- */
-
-struct bna_ritseg_pool_cfg {
- u32 pool_size;
- u32 pool_entry_size;
-};
-init_ritseg_pool(ritseg_pool_cfg);
-
-/*
- * Private functions
- */
-static void
-bna_ucam_mod_init(struct bna_ucam_mod *ucam_mod, struct bna *bna,
- struct bna_res_info *res_info)
-{
- int i;
-
- ucam_mod->ucmac = (struct bna_mac *)
- res_info[BNA_RES_MEM_T_UCMAC_ARRAY].res_u.mem_info.mdl[0].kva;
-
- INIT_LIST_HEAD(&ucam_mod->free_q);
- for (i = 0; i < BFI_MAX_UCMAC; i++) {
- bfa_q_qe_init(&ucam_mod->ucmac[i].qe);
- list_add_tail(&ucam_mod->ucmac[i].qe, &ucam_mod->free_q);
- }
-
- ucam_mod->bna = bna;
-}
-
-static void
-bna_ucam_mod_uninit(struct bna_ucam_mod *ucam_mod)
-{
- struct list_head *qe;
- int i = 0;
-
- list_for_each(qe, &ucam_mod->free_q)
- i++;
-
- ucam_mod->bna = NULL;
-}
-
-static void
-bna_mcam_mod_init(struct bna_mcam_mod *mcam_mod, struct bna *bna,
- struct bna_res_info *res_info)
-{
- int i;
-
- mcam_mod->mcmac = (struct bna_mac *)
- res_info[BNA_RES_MEM_T_MCMAC_ARRAY].res_u.mem_info.mdl[0].kva;
-
- INIT_LIST_HEAD(&mcam_mod->free_q);
- for (i = 0; i < BFI_MAX_MCMAC; i++) {
- bfa_q_qe_init(&mcam_mod->mcmac[i].qe);
- list_add_tail(&mcam_mod->mcmac[i].qe, &mcam_mod->free_q);
- }
-
- mcam_mod->bna = bna;
-}
-
-static void
-bna_mcam_mod_uninit(struct bna_mcam_mod *mcam_mod)
-{
- struct list_head *qe;
- int i = 0;
-
- list_for_each(qe, &mcam_mod->free_q)
- i++;
-
- mcam_mod->bna = NULL;
-}
-
-static void
-bna_rit_mod_init(struct bna_rit_mod *rit_mod,
- struct bna_res_info *res_info)
-{
- int i;
- int j;
- int count;
- int offset;
-
- rit_mod->rit = (struct bna_rit_entry *)
- res_info[BNA_RES_MEM_T_RIT_ENTRY].res_u.mem_info.mdl[0].kva;
- rit_mod->rit_segment = (struct bna_rit_segment *)
- res_info[BNA_RES_MEM_T_RIT_SEGMENT].res_u.mem_info.mdl[0].kva;
-
- count = 0;
- offset = 0;
- for (i = 0; i < BFI_RIT_SEG_TOTAL_POOLS; i++) {
- INIT_LIST_HEAD(&rit_mod->rit_seg_pool[i]);
- for (j = 0; j < ritseg_pool_cfg[i].pool_size; j++) {
- bfa_q_qe_init(&rit_mod->rit_segment[count].qe);
- rit_mod->rit_segment[count].max_rit_size =
- ritseg_pool_cfg[i].pool_entry_size;
- rit_mod->rit_segment[count].rit_offset = offset;
- rit_mod->rit_segment[count].rit =
- &rit_mod->rit[offset];
- list_add_tail(&rit_mod->rit_segment[count].qe,
- &rit_mod->rit_seg_pool[i]);
- count++;
- offset += ritseg_pool_cfg[i].pool_entry_size;
- }
- }
-}
-
-/*
- * Public functions
- */
-
-/* Called during probe(), before calling bna_init() */
-void
-bna_res_req(struct bna_res_info *res_info)
-{
- bna_adv_res_req(res_info);
-
- /* DMA memory for retrieving IOC attributes */
- res_info[BNA_RES_MEM_T_ATTR].res_type = BNA_RES_T_MEM;
- res_info[BNA_RES_MEM_T_ATTR].res_u.mem_info.mem_type = BNA_MEM_T_DMA;
- res_info[BNA_RES_MEM_T_ATTR].res_u.mem_info.num = 1;
- res_info[BNA_RES_MEM_T_ATTR].res_u.mem_info.len =
- ALIGN(bfa_nw_ioc_meminfo(), PAGE_SIZE);
-
- /* DMA memory for index segment of an IB */
- res_info[BNA_RES_MEM_T_IBIDX].res_type = BNA_RES_T_MEM;
- res_info[BNA_RES_MEM_T_IBIDX].res_u.mem_info.mem_type = BNA_MEM_T_DMA;
- res_info[BNA_RES_MEM_T_IBIDX].res_u.mem_info.len =
- BFI_IBIDX_SIZE * BFI_IBIDX_MAX_SEGSIZE;
- res_info[BNA_RES_MEM_T_IBIDX].res_u.mem_info.num = BFI_MAX_IB;
-
- /* Virtual memory for IB objects - stored by IB module */
- res_info[BNA_RES_MEM_T_IB_ARRAY].res_type = BNA_RES_T_MEM;
- res_info[BNA_RES_MEM_T_IB_ARRAY].res_u.mem_info.mem_type =
- BNA_MEM_T_KVA;
- res_info[BNA_RES_MEM_T_IB_ARRAY].res_u.mem_info.num = 1;
- res_info[BNA_RES_MEM_T_IB_ARRAY].res_u.mem_info.len =
- BFI_MAX_IB * sizeof(struct bna_ib);
-
- /* Virtual memory for intr objects - stored by IB module */
- res_info[BNA_RES_MEM_T_INTR_ARRAY].res_type = BNA_RES_T_MEM;
- res_info[BNA_RES_MEM_T_INTR_ARRAY].res_u.mem_info.mem_type =
- BNA_MEM_T_KVA;
- res_info[BNA_RES_MEM_T_INTR_ARRAY].res_u.mem_info.num = 1;
- res_info[BNA_RES_MEM_T_INTR_ARRAY].res_u.mem_info.len =
- BFI_MAX_IB * sizeof(struct bna_intr);
-
- /* Virtual memory for idx_seg objects - stored by IB module */
- res_info[BNA_RES_MEM_T_IDXSEG_ARRAY].res_type = BNA_RES_T_MEM;
- res_info[BNA_RES_MEM_T_IDXSEG_ARRAY].res_u.mem_info.mem_type =
- BNA_MEM_T_KVA;
- res_info[BNA_RES_MEM_T_IDXSEG_ARRAY].res_u.mem_info.num = 1;
- res_info[BNA_RES_MEM_T_IDXSEG_ARRAY].res_u.mem_info.len =
- BFI_IBIDX_TOTAL_SEGS * sizeof(struct bna_ibidx_seg);
-
- /* Virtual memory for Tx objects - stored by Tx module */
- res_info[BNA_RES_MEM_T_TX_ARRAY].res_type = BNA_RES_T_MEM;
- res_info[BNA_RES_MEM_T_TX_ARRAY].res_u.mem_info.mem_type =
- BNA_MEM_T_KVA;
- res_info[BNA_RES_MEM_T_TX_ARRAY].res_u.mem_info.num = 1;
- res_info[BNA_RES_MEM_T_TX_ARRAY].res_u.mem_info.len =
- BFI_MAX_TXQ * sizeof(struct bna_tx);
-
- /* Virtual memory for TxQ - stored by Tx module */
- res_info[BNA_RES_MEM_T_TXQ_ARRAY].res_type = BNA_RES_T_MEM;
- res_info[BNA_RES_MEM_T_TXQ_ARRAY].res_u.mem_info.mem_type =
- BNA_MEM_T_KVA;
- res_info[BNA_RES_MEM_T_TXQ_ARRAY].res_u.mem_info.num = 1;
- res_info[BNA_RES_MEM_T_TXQ_ARRAY].res_u.mem_info.len =
- BFI_MAX_TXQ * sizeof(struct bna_txq);
-
- /* Virtual memory for Rx objects - stored by Rx module */
- res_info[BNA_RES_MEM_T_RX_ARRAY].res_type = BNA_RES_T_MEM;
- res_info[BNA_RES_MEM_T_RX_ARRAY].res_u.mem_info.mem_type =
- BNA_MEM_T_KVA;
- res_info[BNA_RES_MEM_T_RX_ARRAY].res_u.mem_info.num = 1;
- res_info[BNA_RES_MEM_T_RX_ARRAY].res_u.mem_info.len =
- BFI_MAX_RXQ * sizeof(struct bna_rx);
-
- /* Virtual memory for RxPath - stored by Rx module */
- res_info[BNA_RES_MEM_T_RXP_ARRAY].res_type = BNA_RES_T_MEM;
- res_info[BNA_RES_MEM_T_RXP_ARRAY].res_u.mem_info.mem_type =
- BNA_MEM_T_KVA;
- res_info[BNA_RES_MEM_T_RXP_ARRAY].res_u.mem_info.num = 1;
- res_info[BNA_RES_MEM_T_RXP_ARRAY].res_u.mem_info.len =
- BFI_MAX_RXQ * sizeof(struct bna_rxp);
-
- /* Virtual memory for RxQ - stored by Rx module */
- res_info[BNA_RES_MEM_T_RXQ_ARRAY].res_type = BNA_RES_T_MEM;
- res_info[BNA_RES_MEM_T_RXQ_ARRAY].res_u.mem_info.mem_type =
- BNA_MEM_T_KVA;
- res_info[BNA_RES_MEM_T_RXQ_ARRAY].res_u.mem_info.num = 1;
- res_info[BNA_RES_MEM_T_RXQ_ARRAY].res_u.mem_info.len =
- BFI_MAX_RXQ * sizeof(struct bna_rxq);
-
- /* Virtual memory for Unicast MAC address - stored by ucam module */
- res_info[BNA_RES_MEM_T_UCMAC_ARRAY].res_type = BNA_RES_T_MEM;
- res_info[BNA_RES_MEM_T_UCMAC_ARRAY].res_u.mem_info.mem_type =
- BNA_MEM_T_KVA;
- res_info[BNA_RES_MEM_T_UCMAC_ARRAY].res_u.mem_info.num = 1;
- res_info[BNA_RES_MEM_T_UCMAC_ARRAY].res_u.mem_info.len =
- BFI_MAX_UCMAC * sizeof(struct bna_mac);
-
- /* Virtual memory for Multicast MAC address - stored by mcam module */
- res_info[BNA_RES_MEM_T_MCMAC_ARRAY].res_type = BNA_RES_T_MEM;
- res_info[BNA_RES_MEM_T_MCMAC_ARRAY].res_u.mem_info.mem_type =
- BNA_MEM_T_KVA;
- res_info[BNA_RES_MEM_T_MCMAC_ARRAY].res_u.mem_info.num = 1;
- res_info[BNA_RES_MEM_T_MCMAC_ARRAY].res_u.mem_info.len =
- BFI_MAX_MCMAC * sizeof(struct bna_mac);
-
- /* Virtual memory for RIT entries */
- res_info[BNA_RES_MEM_T_RIT_ENTRY].res_type = BNA_RES_T_MEM;
- res_info[BNA_RES_MEM_T_RIT_ENTRY].res_u.mem_info.mem_type =
- BNA_MEM_T_KVA;
- res_info[BNA_RES_MEM_T_RIT_ENTRY].res_u.mem_info.num = 1;
- res_info[BNA_RES_MEM_T_RIT_ENTRY].res_u.mem_info.len =
- BFI_MAX_RIT_SIZE * sizeof(struct bna_rit_entry);
-
- /* Virtual memory for RIT segment table */
- res_info[BNA_RES_MEM_T_RIT_SEGMENT].res_type = BNA_RES_T_MEM;
- res_info[BNA_RES_MEM_T_RIT_SEGMENT].res_u.mem_info.mem_type =
- BNA_MEM_T_KVA;
- res_info[BNA_RES_MEM_T_RIT_SEGMENT].res_u.mem_info.num = 1;
- res_info[BNA_RES_MEM_T_RIT_SEGMENT].res_u.mem_info.len =
- BFI_RIT_TOTAL_SEGS * sizeof(struct bna_rit_segment);
-
- /* Interrupt resource for mailbox interrupt */
- res_info[BNA_RES_INTR_T_MBOX].res_type = BNA_RES_T_INTR;
- res_info[BNA_RES_INTR_T_MBOX].res_u.intr_info.intr_type =
- BNA_INTR_T_MSIX;
- res_info[BNA_RES_INTR_T_MBOX].res_u.intr_info.num = 1;
-}
-
-/* Called during probe() */
-void
-bna_init(struct bna *bna, struct bnad *bnad, struct bfa_pcidev *pcidev,
- struct bna_res_info *res_info)
-{
- bna->bnad = bnad;
- bna->pcidev = *pcidev;
-
- bna->stats.hw_stats = (struct bfi_ll_stats *)
- res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.mdl[0].kva;
- bna->hw_stats_dma.msb =
- res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.mdl[0].dma.msb;
- bna->hw_stats_dma.lsb =
- res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.mdl[0].dma.lsb;
- bna->stats.sw_stats = (struct bna_sw_stats *)
- res_info[BNA_RES_MEM_T_SWSTATS].res_u.mem_info.mdl[0].kva;
-
- bna->regs.page_addr = bna->pcidev.pci_bar_kva +
- reg_offset[bna->pcidev.pci_func].page_addr;
- bna->regs.fn_int_status = bna->pcidev.pci_bar_kva +
- reg_offset[bna->pcidev.pci_func].fn_int_status;
- bna->regs.fn_int_mask = bna->pcidev.pci_bar_kva +
- reg_offset[bna->pcidev.pci_func].fn_int_mask;
-
- if (bna->pcidev.pci_func < 3)
- bna->port_num = 0;
- else
- bna->port_num = 1;
-
- /* Also initializes diag, cee, sfp, phy_port and mbox_mod */
- bna_device_init(&bna->device, bna, res_info);
-
- bna_port_init(&bna->port, bna);
-
- bna_tx_mod_init(&bna->tx_mod, bna, res_info);
-
- bna_rx_mod_init(&bna->rx_mod, bna, res_info);
-
- bna_ib_mod_init(&bna->ib_mod, bna, res_info);
-
- bna_rit_mod_init(&bna->rit_mod, res_info);
-
- bna_ucam_mod_init(&bna->ucam_mod, bna, res_info);
-
- bna_mcam_mod_init(&bna->mcam_mod, bna, res_info);
-
- bna->rxf_promisc_id = BFI_MAX_RXF;
-
- /* Mbox q element for posting stat request to f/w */
- bfa_q_qe_init(&bna->mbox_qe.qe);
-}
-
-void
-bna_uninit(struct bna *bna)
-{
- bna_mcam_mod_uninit(&bna->mcam_mod);
-
- bna_ucam_mod_uninit(&bna->ucam_mod);
-
- bna_ib_mod_uninit(&bna->ib_mod);
-
- bna_rx_mod_uninit(&bna->rx_mod);
-
- bna_tx_mod_uninit(&bna->tx_mod);
-
- bna_port_uninit(&bna->port);
-
- bna_device_uninit(&bna->device);
-
- bna->bnad = NULL;
-}
-
-struct bna_mac *
-bna_ucam_mod_mac_get(struct bna_ucam_mod *ucam_mod)
-{
- struct list_head *qe;
-
- if (list_empty(&ucam_mod->free_q))
- return NULL;
-
- bfa_q_deq(&ucam_mod->free_q, &qe);
-
- return (struct bna_mac *)qe;
-}
-
-void
-bna_ucam_mod_mac_put(struct bna_ucam_mod *ucam_mod, struct bna_mac *mac)
-{
- list_add_tail(&mac->qe, &ucam_mod->free_q);
-}
-
-struct bna_mac *
-bna_mcam_mod_mac_get(struct bna_mcam_mod *mcam_mod)
-{
- struct list_head *qe;
-
- if (list_empty(&mcam_mod->free_q))
- return NULL;
-
- bfa_q_deq(&mcam_mod->free_q, &qe);
-
- return (struct bna_mac *)qe;
-}
-
-void
-bna_mcam_mod_mac_put(struct bna_mcam_mod *mcam_mod, struct bna_mac *mac)
-{
- list_add_tail(&mac->qe, &mcam_mod->free_q);
-}
-
-/**
- * Note: This should be called in the same locking context as the call to
- * bna_rit_mod_seg_get()
- */
-int
-bna_rit_mod_can_satisfy(struct bna_rit_mod *rit_mod, int seg_size)
-{
- int i;
-
- /* Select the pool for seg_size */
- for (i = 0; i < BFI_RIT_SEG_TOTAL_POOLS; i++) {
- if (seg_size <= ritseg_pool_cfg[i].pool_entry_size)
- break;
- }
-
- if (i == BFI_RIT_SEG_TOTAL_POOLS)
- return 0;
-
- if (list_empty(&rit_mod->rit_seg_pool[i]))
- return 0;
-
- return 1;
-}
-
-struct bna_rit_segment *
-bna_rit_mod_seg_get(struct bna_rit_mod *rit_mod, int seg_size)
-{
- struct bna_rit_segment *seg;
- struct list_head *qe;
- int i;
-
- /* Select the pool for seg_size */
- for (i = 0; i < BFI_RIT_SEG_TOTAL_POOLS; i++) {
- if (seg_size <= ritseg_pool_cfg[i].pool_entry_size)
- break;
- }
-
- if (i == BFI_RIT_SEG_TOTAL_POOLS)
- return NULL;
-
- if (list_empty(&rit_mod->rit_seg_pool[i]))
- return NULL;
-
- bfa_q_deq(&rit_mod->rit_seg_pool[i], &qe);
- seg = (struct bna_rit_segment *)qe;
- bfa_q_qe_init(&seg->qe);
- seg->rit_size = seg_size;
-
- return seg;
-}
-
-void
-bna_rit_mod_seg_put(struct bna_rit_mod *rit_mod,
- struct bna_rit_segment *seg)
-{
- int i;
-
- /* Select the pool for seg->max_rit_size */
- for (i = 0; i < BFI_RIT_SEG_TOTAL_POOLS; i++) {
- if (seg->max_rit_size == ritseg_pool_cfg[i].pool_entry_size)
- break;
- }
-
- seg->rit_size = 0;
- list_add_tail(&seg->qe, &rit_mod->rit_seg_pool[i]);
-}
diff --git a/drivers/net/bna/bna_hw.h b/drivers/net/bna/bna_hw.h
deleted file mode 100644
index cad233da843a..000000000000
--- a/drivers/net/bna/bna_hw.h
+++ /dev/null
@@ -1,1490 +0,0 @@
-/*
- * Linux network driver for Brocade Converged Network Adapter.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License (GPL) Version 2 as
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- */
-/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
- * All rights reserved
- * www.brocade.com
- *
- * File for interrupt macros and functions
- */
-
-#ifndef __BNA_HW_H__
-#define __BNA_HW_H__
-
-#include "bfi_ctreg.h"
-
-/**
- *
- * SW imposed limits
- *
- */
-
-#ifndef BNA_BIOS_BUILD
-
-#define BFI_MAX_TXQ 64
-#define BFI_MAX_RXQ 64
-#define BFI_MAX_RXF 64
-#define BFI_MAX_IB 128
-#define BFI_MAX_RIT_SIZE 256
-#define BFI_RSS_RIT_SIZE 64
-#define BFI_NONRSS_RIT_SIZE 1
-#define BFI_MAX_UCMAC 256
-#define BFI_MAX_MCMAC 512
-#define BFI_IBIDX_SIZE 4
-#define BFI_MAX_VLAN 4095
-
-/**
- * There are 2 free IB index pools:
- * pool1: 120 segments of 1 index each
- * pool8: 1 segment of 8 indexes
- */
-#define BFI_IBIDX_POOL1_SIZE 116
-#define BFI_IBIDX_POOL1_ENTRY_SIZE 1
-#define BFI_IBIDX_POOL2_SIZE 2
-#define BFI_IBIDX_POOL2_ENTRY_SIZE 2
-#define BFI_IBIDX_POOL8_SIZE 1
-#define BFI_IBIDX_POOL8_ENTRY_SIZE 8
-#define BFI_IBIDX_TOTAL_POOLS 3
-#define BFI_IBIDX_TOTAL_SEGS 119 /* (POOL1 + POOL2 + POOL8)_SIZE */
-#define BFI_IBIDX_MAX_SEGSIZE 8
-#define init_ibidx_pool(name) \
-static struct bna_ibidx_pool name[BFI_IBIDX_TOTAL_POOLS] = \
-{ \
- { BFI_IBIDX_POOL1_SIZE, BFI_IBIDX_POOL1_ENTRY_SIZE }, \
- { BFI_IBIDX_POOL2_SIZE, BFI_IBIDX_POOL2_ENTRY_SIZE }, \
- { BFI_IBIDX_POOL8_SIZE, BFI_IBIDX_POOL8_ENTRY_SIZE } \
-}
-
-/**
- * There are 2 free RIT segment pools:
- * Pool1: 192 segments of 1 RIT entry each
- * Pool2: 1 segment of 64 RIT entry
- */
-#define BFI_RIT_SEG_POOL1_SIZE 192
-#define BFI_RIT_SEG_POOL1_ENTRY_SIZE 1
-#define BFI_RIT_SEG_POOLRSS_SIZE 1
-#define BFI_RIT_SEG_POOLRSS_ENTRY_SIZE 64
-#define BFI_RIT_SEG_TOTAL_POOLS 2
-#define BFI_RIT_TOTAL_SEGS 193 /* POOL1_SIZE + POOLRSS_SIZE */
-#define init_ritseg_pool(name) \
-static struct bna_ritseg_pool_cfg name[BFI_RIT_SEG_TOTAL_POOLS] = \
-{ \
- { BFI_RIT_SEG_POOL1_SIZE, BFI_RIT_SEG_POOL1_ENTRY_SIZE }, \
- { BFI_RIT_SEG_POOLRSS_SIZE, BFI_RIT_SEG_POOLRSS_ENTRY_SIZE } \
-}
-
-#else /* BNA_BIOS_BUILD */
-
-#define BFI_MAX_TXQ 1
-#define BFI_MAX_RXQ 1
-#define BFI_MAX_RXF 1
-#define BFI_MAX_IB 2
-#define BFI_MAX_RIT_SIZE 2
-#define BFI_RSS_RIT_SIZE 64
-#define BFI_NONRSS_RIT_SIZE 1
-#define BFI_MAX_UCMAC 1
-#define BFI_MAX_MCMAC 8
-#define BFI_IBIDX_SIZE 4
-#define BFI_MAX_VLAN 4095
-/* There is one free pool: 2 segments of 1 index each */
-#define BFI_IBIDX_POOL1_SIZE 2
-#define BFI_IBIDX_POOL1_ENTRY_SIZE 1
-#define BFI_IBIDX_TOTAL_POOLS 1
-#define BFI_IBIDX_TOTAL_SEGS 2 /* POOL1_SIZE */
-#define BFI_IBIDX_MAX_SEGSIZE 1
-#define init_ibidx_pool(name) \
-static struct bna_ibidx_pool name[BFI_IBIDX_TOTAL_POOLS] = \
-{ \
- { BFI_IBIDX_POOL1_SIZE, BFI_IBIDX_POOL1_ENTRY_SIZE } \
-}
-
-#define BFI_RIT_SEG_POOL1_SIZE 1
-#define BFI_RIT_SEG_POOL1_ENTRY_SIZE 1
-#define BFI_RIT_SEG_TOTAL_POOLS 1
-#define BFI_RIT_TOTAL_SEGS 1 /* POOL1_SIZE */
-#define init_ritseg_pool(name) \
-static struct bna_ritseg_pool_cfg name[BFI_RIT_SEG_TOTAL_POOLS] = \
-{ \
- { BFI_RIT_SEG_POOL1_SIZE, BFI_RIT_SEG_POOL1_ENTRY_SIZE } \
-}
-
-#endif /* BNA_BIOS_BUILD */
-
-#define BFI_RSS_HASH_KEY_LEN 10
-
-#define BFI_COALESCING_TIMER_UNIT 5 /* 5us */
-#define BFI_MAX_COALESCING_TIMEO 0xFF /* in 5us units */
-#define BFI_MAX_INTERPKT_COUNT 0xFF
-#define BFI_MAX_INTERPKT_TIMEO 0xF /* in 0.5us units */
-#define BFI_TX_COALESCING_TIMEO 20 /* 20 * 5 = 100us */
-#define BFI_TX_INTERPKT_COUNT 32
-#define BFI_RX_COALESCING_TIMEO 12 /* 12 * 5 = 60us */
-#define BFI_RX_INTERPKT_COUNT 6 /* Pkt Cnt = 6 */
-#define BFI_RX_INTERPKT_TIMEO 3 /* 3 * 0.5 = 1.5us */
-
-#define BFI_TXQ_WI_SIZE 64 /* bytes */
-#define BFI_RXQ_WI_SIZE 8 /* bytes */
-#define BFI_CQ_WI_SIZE 16 /* bytes */
-#define BFI_TX_MAX_WRR_QUOTA 0xFFF
-
-#define BFI_TX_MAX_VECTORS_PER_WI 4
-#define BFI_TX_MAX_VECTORS_PER_PKT 0xFF
-#define BFI_TX_MAX_DATA_PER_VECTOR 0xFFFF
-#define BFI_TX_MAX_DATA_PER_PKT 0xFFFFFF
-
-/* Small Q buffer size */
-#define BFI_SMALL_RXBUF_SIZE 128
-
-/* Defined separately since BFA_FLASH_DMA_BUF_SZ is in bfa_flash.c */
-#define BFI_FLASH_DMA_BUF_SZ 0x010000 /* 64K DMA */
-#define BFI_HW_STATS_SIZE 0x4000 /* 16K DMA */
-
-/**
- *
- * HW register offsets, macros
- *
- */
-
-/* DMA Block Register Host Window Start Address */
-#define DMA_BLK_REG_ADDR 0x00013000
-
-/* DMA Block Internal Registers */
-#define DMA_CTRL_REG0 (DMA_BLK_REG_ADDR + 0x000)
-#define DMA_CTRL_REG1 (DMA_BLK_REG_ADDR + 0x004)
-#define DMA_ERR_INT_STATUS (DMA_BLK_REG_ADDR + 0x008)
-#define DMA_ERR_INT_ENABLE (DMA_BLK_REG_ADDR + 0x00c)
-#define DMA_ERR_INT_STATUS_SET (DMA_BLK_REG_ADDR + 0x010)
-
-/* APP Block Register Address Offset from BAR0 */
-#define APP_BLK_REG_ADDR 0x00014000
-
-/* Host Function Interrupt Mask Registers */
-#define HOSTFN0_INT_MASK (APP_BLK_REG_ADDR + 0x004)
-#define HOSTFN1_INT_MASK (APP_BLK_REG_ADDR + 0x104)
-#define HOSTFN2_INT_MASK (APP_BLK_REG_ADDR + 0x304)
-#define HOSTFN3_INT_MASK (APP_BLK_REG_ADDR + 0x404)
-
-/**
- * Host Function PCIe Error Registers
- * Duplicates "Correctable" & "Uncorrectable"
- * registers in PCIe Config space.
- */
-#define FN0_PCIE_ERR_REG (APP_BLK_REG_ADDR + 0x014)
-#define FN1_PCIE_ERR_REG (APP_BLK_REG_ADDR + 0x114)
-#define FN2_PCIE_ERR_REG (APP_BLK_REG_ADDR + 0x314)
-#define FN3_PCIE_ERR_REG (APP_BLK_REG_ADDR + 0x414)
-
-/* Host Function Error Type Status Registers */
-#define FN0_ERR_TYPE_STATUS_REG (APP_BLK_REG_ADDR + 0x018)
-#define FN1_ERR_TYPE_STATUS_REG (APP_BLK_REG_ADDR + 0x118)
-#define FN2_ERR_TYPE_STATUS_REG (APP_BLK_REG_ADDR + 0x318)
-#define FN3_ERR_TYPE_STATUS_REG (APP_BLK_REG_ADDR + 0x418)
-
-/* Host Function Error Type Mask Registers */
-#define FN0_ERR_TYPE_MSK_STATUS_REG (APP_BLK_REG_ADDR + 0x01c)
-#define FN1_ERR_TYPE_MSK_STATUS_REG (APP_BLK_REG_ADDR + 0x11c)
-#define FN2_ERR_TYPE_MSK_STATUS_REG (APP_BLK_REG_ADDR + 0x31c)
-#define FN3_ERR_TYPE_MSK_STATUS_REG (APP_BLK_REG_ADDR + 0x41c)
-
-/* Catapult Host Semaphore Status Registers (App block) */
-#define HOST_SEM_STS0_REG (APP_BLK_REG_ADDR + 0x630)
-#define HOST_SEM_STS1_REG (APP_BLK_REG_ADDR + 0x634)
-#define HOST_SEM_STS2_REG (APP_BLK_REG_ADDR + 0x638)
-#define HOST_SEM_STS3_REG (APP_BLK_REG_ADDR + 0x63c)
-#define HOST_SEM_STS4_REG (APP_BLK_REG_ADDR + 0x640)
-#define HOST_SEM_STS5_REG (APP_BLK_REG_ADDR + 0x644)
-#define HOST_SEM_STS6_REG (APP_BLK_REG_ADDR + 0x648)
-#define HOST_SEM_STS7_REG (APP_BLK_REG_ADDR + 0x64c)
-
-/* PCIe Misc Register */
-#define PCIE_MISC_REG (APP_BLK_REG_ADDR + 0x200)
-
-/* Temp Sensor Control Registers */
-#define TEMPSENSE_CNTL_REG (APP_BLK_REG_ADDR + 0x250)
-#define TEMPSENSE_STAT_REG (APP_BLK_REG_ADDR + 0x254)
-
-/* APP Block local error registers */
-#define APP_LOCAL_ERR_STAT (APP_BLK_REG_ADDR + 0x258)
-#define APP_LOCAL_ERR_MSK (APP_BLK_REG_ADDR + 0x25c)
-
-/* PCIe Link Error registers */
-#define PCIE_LNK_ERR_STAT (APP_BLK_REG_ADDR + 0x260)
-#define PCIE_LNK_ERR_MSK (APP_BLK_REG_ADDR + 0x264)
-
-/**
- * FCoE/FIP Ethertype Register
- * 31:16 -- Chip wide value for FIP type
- * 15:0 -- Chip wide value for FCoE type
- */
-#define FCOE_FIP_ETH_TYPE (APP_BLK_REG_ADDR + 0x280)
-
-/**
- * Reserved Ethertype Register
- * 31:16 -- Reserved
- * 15:0 -- Other ethertype
- */
-#define RESV_ETH_TYPE (APP_BLK_REG_ADDR + 0x284)
-
-/**
- * Host Command Status Registers
- * Each set consists of 3 registers :
- * clear, set, cmd
- * 16 such register sets in all
- * See catapult_spec.pdf for detailed functionality
- * Put each type in a single macro accessed by _num ?
- */
-#define HOST_CMDSTS0_CLR_REG (APP_BLK_REG_ADDR + 0x500)
-#define HOST_CMDSTS0_SET_REG (APP_BLK_REG_ADDR + 0x504)
-#define HOST_CMDSTS0_REG (APP_BLK_REG_ADDR + 0x508)
-#define HOST_CMDSTS1_CLR_REG (APP_BLK_REG_ADDR + 0x510)
-#define HOST_CMDSTS1_SET_REG (APP_BLK_REG_ADDR + 0x514)
-#define HOST_CMDSTS1_REG (APP_BLK_REG_ADDR + 0x518)
-#define HOST_CMDSTS2_CLR_REG (APP_BLK_REG_ADDR + 0x520)
-#define HOST_CMDSTS2_SET_REG (APP_BLK_REG_ADDR + 0x524)
-#define HOST_CMDSTS2_REG (APP_BLK_REG_ADDR + 0x528)
-#define HOST_CMDSTS3_CLR_REG (APP_BLK_REG_ADDR + 0x530)
-#define HOST_CMDSTS3_SET_REG (APP_BLK_REG_ADDR + 0x534)
-#define HOST_CMDSTS3_REG (APP_BLK_REG_ADDR + 0x538)
-#define HOST_CMDSTS4_CLR_REG (APP_BLK_REG_ADDR + 0x540)
-#define HOST_CMDSTS4_SET_REG (APP_BLK_REG_ADDR + 0x544)
-#define HOST_CMDSTS4_REG (APP_BLK_REG_ADDR + 0x548)
-#define HOST_CMDSTS5_CLR_REG (APP_BLK_REG_ADDR + 0x550)
-#define HOST_CMDSTS5_SET_REG (APP_BLK_REG_ADDR + 0x554)
-#define HOST_CMDSTS5_REG (APP_BLK_REG_ADDR + 0x558)
-#define HOST_CMDSTS6_CLR_REG (APP_BLK_REG_ADDR + 0x560)
-#define HOST_CMDSTS6_SET_REG (APP_BLK_REG_ADDR + 0x564)
-#define HOST_CMDSTS6_REG (APP_BLK_REG_ADDR + 0x568)
-#define HOST_CMDSTS7_CLR_REG (APP_BLK_REG_ADDR + 0x570)
-#define HOST_CMDSTS7_SET_REG (APP_BLK_REG_ADDR + 0x574)
-#define HOST_CMDSTS7_REG (APP_BLK_REG_ADDR + 0x578)
-#define HOST_CMDSTS8_CLR_REG (APP_BLK_REG_ADDR + 0x580)
-#define HOST_CMDSTS8_SET_REG (APP_BLK_REG_ADDR + 0x584)
-#define HOST_CMDSTS8_REG (APP_BLK_REG_ADDR + 0x588)
-#define HOST_CMDSTS9_CLR_REG (APP_BLK_REG_ADDR + 0x590)
-#define HOST_CMDSTS9_SET_REG (APP_BLK_REG_ADDR + 0x594)
-#define HOST_CMDSTS9_REG (APP_BLK_REG_ADDR + 0x598)
-#define HOST_CMDSTS10_CLR_REG (APP_BLK_REG_ADDR + 0x5A0)
-#define HOST_CMDSTS10_SET_REG (APP_BLK_REG_ADDR + 0x5A4)
-#define HOST_CMDSTS10_REG (APP_BLK_REG_ADDR + 0x5A8)
-#define HOST_CMDSTS11_CLR_REG (APP_BLK_REG_ADDR + 0x5B0)
-#define HOST_CMDSTS11_SET_REG (APP_BLK_REG_ADDR + 0x5B4)
-#define HOST_CMDSTS11_REG (APP_BLK_REG_ADDR + 0x5B8)
-#define HOST_CMDSTS12_CLR_REG (APP_BLK_REG_ADDR + 0x5C0)
-#define HOST_CMDSTS12_SET_REG (APP_BLK_REG_ADDR + 0x5C4)
-#define HOST_CMDSTS12_REG (APP_BLK_REG_ADDR + 0x5C8)
-#define HOST_CMDSTS13_CLR_REG (APP_BLK_REG_ADDR + 0x5D0)
-#define HOST_CMDSTS13_SET_REG (APP_BLK_REG_ADDR + 0x5D4)
-#define HOST_CMDSTS13_REG (APP_BLK_REG_ADDR + 0x5D8)
-#define HOST_CMDSTS14_CLR_REG (APP_BLK_REG_ADDR + 0x5E0)
-#define HOST_CMDSTS14_SET_REG (APP_BLK_REG_ADDR + 0x5E4)
-#define HOST_CMDSTS14_REG (APP_BLK_REG_ADDR + 0x5E8)
-#define HOST_CMDSTS15_CLR_REG (APP_BLK_REG_ADDR + 0x5F0)
-#define HOST_CMDSTS15_SET_REG (APP_BLK_REG_ADDR + 0x5F4)
-#define HOST_CMDSTS15_REG (APP_BLK_REG_ADDR + 0x5F8)
-
-/**
- * LPU0 Block Register Address Offset from BAR0
- * Range 0x18000 - 0x18033
- */
-#define LPU0_BLK_REG_ADDR 0x00018000
-
-/**
- * LPU0 Registers
- * Should they be directly used from host,
- * except for diagnostics ?
- * CTL_REG : Control register
- * CMD_REG : Triggers exec. of cmd. in
- * Mailbox memory
- */
-#define LPU0_MBOX_CTL_REG (LPU0_BLK_REG_ADDR + 0x000)
-#define LPU0_MBOX_CMD_REG (LPU0_BLK_REG_ADDR + 0x004)
-#define LPU0_MBOX_LINK_0REG (LPU0_BLK_REG_ADDR + 0x008)
-#define LPU1_MBOX_LINK_0REG (LPU0_BLK_REG_ADDR + 0x00c)
-#define LPU0_MBOX_STATUS_0REG (LPU0_BLK_REG_ADDR + 0x010)
-#define LPU1_MBOX_STATUS_0REG (LPU0_BLK_REG_ADDR + 0x014)
-#define LPU0_ERR_STATUS_REG (LPU0_BLK_REG_ADDR + 0x018)
-#define LPU0_ERR_SET_REG (LPU0_BLK_REG_ADDR + 0x020)
-
-/**
- * LPU1 Block Register Address Offset from BAR0
- * Range 0x18400 - 0x18433
- */
-#define LPU1_BLK_REG_ADDR 0x00018400
-
-/**
- * LPU1 Registers
- * Same as LPU0 registers above
- */
-#define LPU1_MBOX_CTL_REG (LPU1_BLK_REG_ADDR + 0x000)
-#define LPU1_MBOX_CMD_REG (LPU1_BLK_REG_ADDR + 0x004)
-#define LPU0_MBOX_LINK_1REG (LPU1_BLK_REG_ADDR + 0x008)
-#define LPU1_MBOX_LINK_1REG (LPU1_BLK_REG_ADDR + 0x00c)
-#define LPU0_MBOX_STATUS_1REG (LPU1_BLK_REG_ADDR + 0x010)
-#define LPU1_MBOX_STATUS_1REG (LPU1_BLK_REG_ADDR + 0x014)
-#define LPU1_ERR_STATUS_REG (LPU1_BLK_REG_ADDR + 0x018)
-#define LPU1_ERR_SET_REG (LPU1_BLK_REG_ADDR + 0x020)
-
-/**
- * PSS Block Register Address Offset from BAR0
- * Range 0x18800 - 0x188DB
- */
-#define PSS_BLK_REG_ADDR 0x00018800
-
-/**
- * PSS Registers
- * For details, see catapult_spec.pdf
- * ERR_STATUS_REG : Indicates error in PSS module
- * RAM_ERR_STATUS_REG : Indicates RAM module that detected error
- */
-#define ERR_STATUS_SET (PSS_BLK_REG_ADDR + 0x018)
-#define PSS_RAM_ERR_STATUS_REG (PSS_BLK_REG_ADDR + 0x01C)
-
-/**
- * PSS Semaphore Lock Registers, total 16
- * First read when unlocked returns 0,
- * and is set to 1, atomically.
- * Subsequent reads returns 1.
- * To clear set the value to 0.
- * Range : 0x20 to 0x5c
- */
-#define PSS_SEM_LOCK_REG(_num) \
- (PSS_BLK_REG_ADDR + 0x020 + ((_num) << 2))
-
-/**
- * PSS Semaphore Status Registers,
- * corresponding to the lock registers above
- */
-#define PSS_SEM_STATUS_REG(_num) \
- (PSS_BLK_REG_ADDR + 0x060 + ((_num) << 2))
-
-/**
- * Catapult CPQ Registers
- * Defines for Mailbox Registers
- * Used to send mailbox commands to firmware from
- * host. The data part is written to the MBox
- * memory, registers are used to indicate that
- * a commnad is resident in memory.
- *
- * Note : LPU0<->LPU1 mailboxes are not listed here
- */
-#define CPQ_BLK_REG_ADDR 0x00019000
-
-#define HOSTFN0_LPU0_MBOX1_CMD_STAT (CPQ_BLK_REG_ADDR + 0x130)
-#define HOSTFN0_LPU1_MBOX1_CMD_STAT (CPQ_BLK_REG_ADDR + 0x134)
-#define LPU0_HOSTFN0_MBOX1_CMD_STAT (CPQ_BLK_REG_ADDR + 0x138)
-#define LPU1_HOSTFN0_MBOX1_CMD_STAT (CPQ_BLK_REG_ADDR + 0x13C)
-
-#define HOSTFN1_LPU0_MBOX1_CMD_STAT (CPQ_BLK_REG_ADDR + 0x140)
-#define HOSTFN1_LPU1_MBOX1_CMD_STAT (CPQ_BLK_REG_ADDR + 0x144)
-#define LPU0_HOSTFN1_MBOX1_CMD_STAT (CPQ_BLK_REG_ADDR + 0x148)
-#define LPU1_HOSTFN1_MBOX1_CMD_STAT (CPQ_BLK_REG_ADDR + 0x14C)
-
-#define HOSTFN2_LPU0_MBOX1_CMD_STAT (CPQ_BLK_REG_ADDR + 0x170)
-#define HOSTFN2_LPU1_MBOX1_CMD_STAT (CPQ_BLK_REG_ADDR + 0x174)
-#define LPU0_HOSTFN2_MBOX1_CMD_STAT (CPQ_BLK_REG_ADDR + 0x178)
-#define LPU1_HOSTFN2_MBOX1_CMD_STAT (CPQ_BLK_REG_ADDR + 0x17C)
-
-#define HOSTFN3_LPU0_MBOX1_CMD_STAT (CPQ_BLK_REG_ADDR + 0x180)
-#define HOSTFN3_LPU1_MBOX1_CMD_STAT (CPQ_BLK_REG_ADDR + 0x184)
-#define LPU0_HOSTFN3_MBOX1_CMD_STAT (CPQ_BLK_REG_ADDR + 0x188)
-#define LPU1_HOSTFN3_MBOX1_CMD_STAT (CPQ_BLK_REG_ADDR + 0x18C)
-
-/* Host Function Force Parity Error Registers */
-#define HOSTFN0_LPU_FORCE_PERR (CPQ_BLK_REG_ADDR + 0x120)
-#define HOSTFN1_LPU_FORCE_PERR (CPQ_BLK_REG_ADDR + 0x124)
-#define HOSTFN2_LPU_FORCE_PERR (CPQ_BLK_REG_ADDR + 0x128)
-#define HOSTFN3_LPU_FORCE_PERR (CPQ_BLK_REG_ADDR + 0x12C)
-
-/* LL Port[0|1] Halt Mask Registers */
-#define LL_HALT_MSK_P0 (CPQ_BLK_REG_ADDR + 0x1A0)
-#define LL_HALT_MSK_P1 (CPQ_BLK_REG_ADDR + 0x1B0)
-
-/* LL Port[0|1] Error Mask Registers */
-#define LL_ERR_MSK_P0 (CPQ_BLK_REG_ADDR + 0x1D0)
-#define LL_ERR_MSK_P1 (CPQ_BLK_REG_ADDR + 0x1D4)
-
-/* EMC FLI (Flash Controller) Block Register Address Offset from BAR0 */
-#define FLI_BLK_REG_ADDR 0x0001D000
-
-/* EMC FLI Registers */
-#define FLI_CMD_REG (FLI_BLK_REG_ADDR + 0x000)
-#define FLI_ADDR_REG (FLI_BLK_REG_ADDR + 0x004)
-#define FLI_CTL_REG (FLI_BLK_REG_ADDR + 0x008)
-#define FLI_WRDATA_REG (FLI_BLK_REG_ADDR + 0x00C)
-#define FLI_RDDATA_REG (FLI_BLK_REG_ADDR + 0x010)
-#define FLI_DEV_STATUS_REG (FLI_BLK_REG_ADDR + 0x014)
-#define FLI_SIG_WD_REG (FLI_BLK_REG_ADDR + 0x018)
-
-/**
- * RO register
- * 31:16 -- Vendor Id
- * 15:0 -- Device Id
- */
-#define FLI_DEV_VENDOR_REG (FLI_BLK_REG_ADDR + 0x01C)
-#define FLI_ERR_STATUS_REG (FLI_BLK_REG_ADDR + 0x020)
-
-/**
- * RAD (RxAdm) Block Register Address Offset from BAR0
- * RAD0 Range : 0x20000 - 0x203FF
- * RAD1 Range : 0x20400 - 0x207FF
- */
-#define RAD0_BLK_REG_ADDR 0x00020000
-#define RAD1_BLK_REG_ADDR 0x00020400
-
-/* RAD0 Registers */
-#define RAD0_CTL_REG (RAD0_BLK_REG_ADDR + 0x000)
-#define RAD0_PE_PARM_REG (RAD0_BLK_REG_ADDR + 0x004)
-#define RAD0_BCN_REG (RAD0_BLK_REG_ADDR + 0x008)
-
-/* Default function ID register */
-#define RAD0_DEFAULT_REG (RAD0_BLK_REG_ADDR + 0x00C)
-
-/* Default promiscuous ID register */
-#define RAD0_PROMISC_REG (RAD0_BLK_REG_ADDR + 0x010)
-
-#define RAD0_BCNQ_REG (RAD0_BLK_REG_ADDR + 0x014)
-
-/*
- * This register selects 1 of 8 PM Q's using
- * VLAN pri, for non-BCN packets without a VLAN tag
- */
-#define RAD0_DEFAULTQ_REG (RAD0_BLK_REG_ADDR + 0x018)
-
-#define RAD0_ERR_STS (RAD0_BLK_REG_ADDR + 0x01C)
-#define RAD0_SET_ERR_STS (RAD0_BLK_REG_ADDR + 0x020)
-#define RAD0_ERR_INT_EN (RAD0_BLK_REG_ADDR + 0x024)
-#define RAD0_FIRST_ERR (RAD0_BLK_REG_ADDR + 0x028)
-#define RAD0_FORCE_ERR (RAD0_BLK_REG_ADDR + 0x02C)
-
-#define RAD0_IF_RCVD (RAD0_BLK_REG_ADDR + 0x030)
-#define RAD0_IF_RCVD_OCTETS_HIGH (RAD0_BLK_REG_ADDR + 0x034)
-#define RAD0_IF_RCVD_OCTETS_LOW (RAD0_BLK_REG_ADDR + 0x038)
-#define RAD0_IF_RCVD_VLAN (RAD0_BLK_REG_ADDR + 0x03C)
-#define RAD0_IF_RCVD_UCAST (RAD0_BLK_REG_ADDR + 0x040)
-#define RAD0_IF_RCVD_UCAST_OCTETS_HIGH (RAD0_BLK_REG_ADDR + 0x044)
-#define RAD0_IF_RCVD_UCAST_OCTETS_LOW (RAD0_BLK_REG_ADDR + 0x048)
-#define RAD0_IF_RCVD_UCAST_VLAN (RAD0_BLK_REG_ADDR + 0x04C)
-#define RAD0_IF_RCVD_MCAST (RAD0_BLK_REG_ADDR + 0x050)
-#define RAD0_IF_RCVD_MCAST_OCTETS_HIGH (RAD0_BLK_REG_ADDR + 0x054)
-#define RAD0_IF_RCVD_MCAST_OCTETS_LOW (RAD0_BLK_REG_ADDR + 0x058)
-#define RAD0_IF_RCVD_MCAST_VLAN (RAD0_BLK_REG_ADDR + 0x05C)
-#define RAD0_IF_RCVD_BCAST (RAD0_BLK_REG_ADDR + 0x060)
-#define RAD0_IF_RCVD_BCAST_OCTETS_HIGH (RAD0_BLK_REG_ADDR + 0x064)
-#define RAD0_IF_RCVD_BCAST_OCTETS_LOW (RAD0_BLK_REG_ADDR + 0x068)
-#define RAD0_IF_RCVD_BCAST_VLAN (RAD0_BLK_REG_ADDR + 0x06C)
-#define RAD0_DROPPED_FRAMES (RAD0_BLK_REG_ADDR + 0x070)
-
-#define RAD0_MAC_MAN_1H (RAD0_BLK_REG_ADDR + 0x080)
-#define RAD0_MAC_MAN_1L (RAD0_BLK_REG_ADDR + 0x084)
-#define RAD0_MAC_MAN_2H (RAD0_BLK_REG_ADDR + 0x088)
-#define RAD0_MAC_MAN_2L (RAD0_BLK_REG_ADDR + 0x08C)
-#define RAD0_MAC_MAN_3H (RAD0_BLK_REG_ADDR + 0x090)
-#define RAD0_MAC_MAN_3L (RAD0_BLK_REG_ADDR + 0x094)
-#define RAD0_MAC_MAN_4H (RAD0_BLK_REG_ADDR + 0x098)
-#define RAD0_MAC_MAN_4L (RAD0_BLK_REG_ADDR + 0x09C)
-
-#define RAD0_LAST4_IP (RAD0_BLK_REG_ADDR + 0x100)
-
-/* RAD1 Registers */
-#define RAD1_CTL_REG (RAD1_BLK_REG_ADDR + 0x000)
-#define RAD1_PE_PARM_REG (RAD1_BLK_REG_ADDR + 0x004)
-#define RAD1_BCN_REG (RAD1_BLK_REG_ADDR + 0x008)
-
-/* Default function ID register */
-#define RAD1_DEFAULT_REG (RAD1_BLK_REG_ADDR + 0x00C)
-
-/* Promiscuous function ID register */
-#define RAD1_PROMISC_REG (RAD1_BLK_REG_ADDR + 0x010)
-
-#define RAD1_BCNQ_REG (RAD1_BLK_REG_ADDR + 0x014)
-
-/*
- * This register selects 1 of 8 PM Q's using
- * VLAN pri, for non-BCN packets without a VLAN tag
- */
-#define RAD1_DEFAULTQ_REG (RAD1_BLK_REG_ADDR + 0x018)
-
-#define RAD1_ERR_STS (RAD1_BLK_REG_ADDR + 0x01C)
-#define RAD1_SET_ERR_STS (RAD1_BLK_REG_ADDR + 0x020)
-#define RAD1_ERR_INT_EN (RAD1_BLK_REG_ADDR + 0x024)
-
-/**
- * TXA Block Register Address Offset from BAR0
- * TXA0 Range : 0x21000 - 0x213FF
- * TXA1 Range : 0x21400 - 0x217FF
- */
-#define TXA0_BLK_REG_ADDR 0x00021000
-#define TXA1_BLK_REG_ADDR 0x00021400
-
-/* TXA Registers */
-#define TXA0_CTRL_REG (TXA0_BLK_REG_ADDR + 0x000)
-#define TXA1_CTRL_REG (TXA1_BLK_REG_ADDR + 0x000)
-
-/**
- * TSO Sequence # Registers (RO)
- * Total 8 (for 8 queues)
- * Holds the last seq.# for TSO frames
- * See catapult_spec.pdf for more details
- */
-#define TXA0_TSO_TCP_SEQ_REG(_num) \
- (TXA0_BLK_REG_ADDR + 0x020 + ((_num) << 2))
-
-#define TXA1_TSO_TCP_SEQ_REG(_num) \
- (TXA1_BLK_REG_ADDR + 0x020 + ((_num) << 2))
-
-/**
- * TSO IP ID # Registers (RO)
- * Total 8 (for 8 queues)
- * Holds the last IP ID for TSO frames
- * See catapult_spec.pdf for more details
- */
-#define TXA0_TSO_IP_INFO_REG(_num) \
- (TXA0_BLK_REG_ADDR + 0x040 + ((_num) << 2))
-
-#define TXA1_TSO_IP_INFO_REG(_num) \
- (TXA1_BLK_REG_ADDR + 0x040 + ((_num) << 2))
-
-/**
- * RXA Block Register Address Offset from BAR0
- * RXA0 Range : 0x21800 - 0x21BFF
- * RXA1 Range : 0x21C00 - 0x21FFF
- */
-#define RXA0_BLK_REG_ADDR 0x00021800
-#define RXA1_BLK_REG_ADDR 0x00021C00
-
-/* RXA Registers */
-#define RXA0_CTL_REG (RXA0_BLK_REG_ADDR + 0x040)
-#define RXA1_CTL_REG (RXA1_BLK_REG_ADDR + 0x040)
-
-/**
- * PPLB Block Register Address Offset from BAR0
- * PPLB0 Range : 0x22000 - 0x223FF
- * PPLB1 Range : 0x22400 - 0x227FF
- */
-#define PLB0_BLK_REG_ADDR 0x00022000
-#define PLB1_BLK_REG_ADDR 0x00022400
-
-/**
- * PLB Registers
- * Holds RL timer used time stamps in RLT tagged frames
- */
-#define PLB0_ECM_TIMER_REG (PLB0_BLK_REG_ADDR + 0x05C)
-#define PLB1_ECM_TIMER_REG (PLB1_BLK_REG_ADDR + 0x05C)
-
-/* Controls the rate-limiter on each of the priority class */
-#define PLB0_RL_CTL (PLB0_BLK_REG_ADDR + 0x060)
-#define PLB1_RL_CTL (PLB1_BLK_REG_ADDR + 0x060)
-
-/**
- * Max byte register, total 8, 0-7
- * see catapult_spec.pdf for details
- */
-#define PLB0_RL_MAX_BC(_num) \
- (PLB0_BLK_REG_ADDR + 0x064 + ((_num) << 2))
-#define PLB1_RL_MAX_BC(_num) \
- (PLB1_BLK_REG_ADDR + 0x064 + ((_num) << 2))
-
-/**
- * RL Time Unit Register for priority 0-7
- * 4 bits per priority
- * (2^rl_unit)*1us is the actual time period
- */
-#define PLB0_RL_TU_PRIO (PLB0_BLK_REG_ADDR + 0x084)
-#define PLB1_RL_TU_PRIO (PLB1_BLK_REG_ADDR + 0x084)
-
-/**
- * RL byte count register,
- * bytes transmitted in (rl_unit*1)us time period
- * 1 per priority, 8 in all, 0-7.
- */
-#define PLB0_RL_BYTE_CNT(_num) \
- (PLB0_BLK_REG_ADDR + 0x088 + ((_num) << 2))
-#define PLB1_RL_BYTE_CNT(_num) \
- (PLB1_BLK_REG_ADDR + 0x088 + ((_num) << 2))
-
-/**
- * RL Min factor register
- * 2 bits per priority,
- * 4 factors possible: 1, 0.5, 0.25, 0
- * 2'b00 - 0; 2'b01 - 0.25; 2'b10 - 0.5; 2'b11 - 1
- */
-#define PLB0_RL_MIN_REG (PLB0_BLK_REG_ADDR + 0x0A8)
-#define PLB1_RL_MIN_REG (PLB1_BLK_REG_ADDR + 0x0A8)
-
-/**
- * RL Max factor register
- * 2 bits per priority,
- * 4 factors possible: 1, 0.5, 0.25, 0
- * 2'b00 - 0; 2'b01 - 0.25; 2'b10 - 0.5; 2'b11 - 1
- */
-#define PLB0_RL_MAX_REG (PLB0_BLK_REG_ADDR + 0x0AC)
-#define PLB1_RL_MAX_REG (PLB1_BLK_REG_ADDR + 0x0AC)
-
-/* MAC SERDES Address Paging register */
-#define PLB0_EMS_ADD_REG (PLB0_BLK_REG_ADDR + 0xD0)
-#define PLB1_EMS_ADD_REG (PLB1_BLK_REG_ADDR + 0xD0)
-
-/* LL EMS Registers */
-#define LL_EMS0_BLK_REG_ADDR 0x00026800
-#define LL_EMS1_BLK_REG_ADDR 0x00026C00
-
-/**
- * BPC Block Register Address Offset from BAR0
- * BPC0 Range : 0x23000 - 0x233FF
- * BPC1 Range : 0x23400 - 0x237FF
- */
-#define BPC0_BLK_REG_ADDR 0x00023000
-#define BPC1_BLK_REG_ADDR 0x00023400
-
-/**
- * PMM Block Register Address Offset from BAR0
- * PMM0 Range : 0x23800 - 0x23BFF
- * PMM1 Range : 0x23C00 - 0x23FFF
- */
-#define PMM0_BLK_REG_ADDR 0x00023800
-#define PMM1_BLK_REG_ADDR 0x00023C00
-
-/**
- * HQM Block Register Address Offset from BAR0
- * HQM0 Range : 0x24000 - 0x243FF
- * HQM1 Range : 0x24400 - 0x247FF
- */
-#define HQM0_BLK_REG_ADDR 0x00024000
-#define HQM1_BLK_REG_ADDR 0x00024400
-
-/**
- * HQM Control Register
- * Controls some aspects of IB
- * See catapult_spec.pdf for details
- */
-#define HQM0_CTL_REG (HQM0_BLK_REG_ADDR + 0x000)
-#define HQM1_CTL_REG (HQM1_BLK_REG_ADDR + 0x000)
-
-/**
- * HQM Stop Q Semaphore Registers.
- * Only one Queue resource can be stopped at
- * any given time. This register controls access
- * to the single stop Q resource.
- * See catapult_spec.pdf for details
- */
-#define HQM0_RXQ_STOP_SEM (HQM0_BLK_REG_ADDR + 0x028)
-#define HQM0_TXQ_STOP_SEM (HQM0_BLK_REG_ADDR + 0x02C)
-#define HQM1_RXQ_STOP_SEM (HQM1_BLK_REG_ADDR + 0x028)
-#define HQM1_TXQ_STOP_SEM (HQM1_BLK_REG_ADDR + 0x02C)
-
-/**
- * LUT Block Register Address Offset from BAR0
- * LUT0 Range : 0x25800 - 0x25BFF
- * LUT1 Range : 0x25C00 - 0x25FFF
- */
-#define LUT0_BLK_REG_ADDR 0x00025800
-#define LUT1_BLK_REG_ADDR 0x00025C00
-
-/**
- * LUT Registers
- * See catapult_spec.pdf for details
- */
-#define LUT0_ERR_STS (LUT0_BLK_REG_ADDR + 0x000)
-#define LUT1_ERR_STS (LUT1_BLK_REG_ADDR + 0x000)
-#define LUT0_SET_ERR_STS (LUT0_BLK_REG_ADDR + 0x004)
-#define LUT1_SET_ERR_STS (LUT1_BLK_REG_ADDR + 0x004)
-
-/**
- * TRC (Debug/Trace) Register Offset from BAR0
- * Range : 0x26000 -- 0x263FFF
- */
-#define TRC_BLK_REG_ADDR 0x00026000
-
-/**
- * TRC Registers
- * See catapult_spec.pdf for details of each
- */
-#define TRC_CTL_REG (TRC_BLK_REG_ADDR + 0x000)
-#define TRC_MODS_REG (TRC_BLK_REG_ADDR + 0x004)
-#define TRC_TRGC_REG (TRC_BLK_REG_ADDR + 0x008)
-#define TRC_CNT1_REG (TRC_BLK_REG_ADDR + 0x010)
-#define TRC_CNT2_REG (TRC_BLK_REG_ADDR + 0x014)
-#define TRC_NXTS_REG (TRC_BLK_REG_ADDR + 0x018)
-#define TRC_DIRR_REG (TRC_BLK_REG_ADDR + 0x01C)
-
-/**
- * TRC Trigger match filters, total 10
- * Determines the trigger condition
- */
-#define TRC_TRGM_REG(_num) \
- (TRC_BLK_REG_ADDR + 0x040 + ((_num) << 2))
-
-/**
- * TRC Next State filters, total 10
- * Determines the next state conditions
- */
-#define TRC_NXTM_REG(_num) \
- (TRC_BLK_REG_ADDR + 0x080 + ((_num) << 2))
-
-/**
- * TRC Store Match filters, total 10
- * Determines the store conditions
- */
-#define TRC_STRM_REG(_num) \
- (TRC_BLK_REG_ADDR + 0x0C0 + ((_num) << 2))
-
-/* DOORBELLS ACCESS */
-
-/**
- * Catapult doorbells
- * Each doorbell-queue set has
- * 1 RxQ, 1 TxQ, 2 IBs in that order
- * Size of each entry in 32 bytes, even though only 1 word
- * is used. For Non-VM case each doorbell-q set is
- * separated by 128 bytes, for VM case it is separated
- * by 4K bytes
- * Non VM case Range : 0x38000 - 0x39FFF
- * VM case Range : 0x100000 - 0x11FFFF
- * The range applies to both HQMs
- */
-#define HQM_DOORBELL_BLK_BASE_ADDR 0x00038000
-#define HQM_DOORBELL_VM_BLK_BASE_ADDR 0x00100000
-
-/* MEMORY ACCESS */
-
-/**
- * Catapult H/W Block Memory Access Address
- * To the host a memory space of 32K (page) is visible
- * at a time. The address range is from 0x08000 to 0x0FFFF
- */
-#define HW_BLK_HOST_MEM_ADDR 0x08000
-
-/**
- * Catapult LUT Memory Access Page Numbers
- * Range : LUT0 0xa0-0xa1
- * LUT1 0xa2-0xa3
- */
-#define LUT0_MEM_BLK_BASE_PG_NUM 0x000000A0
-#define LUT1_MEM_BLK_BASE_PG_NUM 0x000000A2
-
-/**
- * Catapult RxFn Database Memory Block Base Offset
- *
- * The Rx function database exists in LUT block.
- * In PCIe space this is accessible as a 256x32
- * bit block. Each entry in this database is 4
- * (4 byte) words. Max. entries is 64.
- * Address of an entry corresponding to a function
- * = base_addr + (function_no. * 16)
- */
-#define RX_FNDB_RAM_BASE_OFFSET 0x0000B400
-
-/**
- * Catapult TxFn Database Memory Block Base Offset Address
- *
- * The Tx function database exists in LUT block.
- * In PCIe space this is accessible as a 64x32
- * bit block. Each entry in this database is 1
- * (4 byte) word. Max. entries is 64.
- * Address of an entry corresponding to a function
- * = base_addr + (function_no. * 4)
- */
-#define TX_FNDB_RAM_BASE_OFFSET 0x0000B800
-
-/**
- * Catapult Unicast CAM Base Offset Address
- *
- * Exists in LUT memory space.
- * Shared by both the LL & FCoE driver.
- * Size is 256x48 bits; mapped to PCIe space
- * 512x32 bit blocks. For each address, bits
- * are written in the order : [47:32] and then
- * [31:0].
- */
-#define UCAST_CAM_BASE_OFFSET 0x0000A800
-
-/**
- * Catapult Unicast RAM Base Offset Address
- *
- * Exists in LUT memory space.
- * Shared by both the LL & FCoE driver.
- * Size is 256x9 bits.
- */
-#define UCAST_RAM_BASE_OFFSET 0x0000B000
-
-/**
- * Catapult Mulicast CAM Base Offset Address
- *
- * Exists in LUT memory space.
- * Shared by both the LL & FCoE driver.
- * Size is 256x48 bits; mapped to PCIe space
- * 512x32 bit blocks. For each address, bits
- * are written in the order : [47:32] and then
- * [31:0].
- */
-#define MCAST_CAM_BASE_OFFSET 0x0000A000
-
-/**
- * Catapult VLAN RAM Base Offset Address
- *
- * Exists in LUT memory space.
- * Size is 4096x66 bits; mapped to PCIe space as
- * 8192x32 bit blocks.
- * All the 4K entries are within the address range
- * 0x0000 to 0x8000, so in the first LUT page.
- */
-#define VLAN_RAM_BASE_OFFSET 0x00000000
-
-/**
- * Catapult Tx Stats RAM Base Offset Address
- *
- * Exists in LUT memory space.
- * Size is 1024x33 bits;
- * Each Tx function has 64 bytes of space
- */
-#define TX_STATS_RAM_BASE_OFFSET 0x00009000
-
-/**
- * Catapult Rx Stats RAM Base Offset Address
- *
- * Exists in LUT memory space.
- * Size is 1024x33 bits;
- * Each Rx function has 64 bytes of space
- */
-#define RX_STATS_RAM_BASE_OFFSET 0x00008000
-
-/* Catapult RXA Memory Access Page Numbers */
-#define RXA0_MEM_BLK_BASE_PG_NUM 0x0000008C
-#define RXA1_MEM_BLK_BASE_PG_NUM 0x0000008D
-
-/**
- * Catapult Multicast Vector Table Base Offset Address
- *
- * Exists in RxA memory space.
- * Organized as 512x65 bit block.
- * However for each entry 16 bytes allocated (power of 2)
- * Total size 512*16 bytes.
- * There are two logical divisions, 256 entries each :
- * a) Entries 0x00 to 0xff (256) -- Approx. MVT
- * Offset 0x000 to 0xFFF
- * b) Entries 0x100 to 0x1ff (256) -- Exact MVT
- * Offsets 0x1000 to 0x1FFF
- */
-#define MCAST_APPROX_MVT_BASE_OFFSET 0x00000000
-#define MCAST_EXACT_MVT_BASE_OFFSET 0x00001000
-
-/**
- * Catapult RxQ Translate Table (RIT) Base Offset Address
- *
- * Exists in RxA memory space
- * Total no. of entries 64
- * Each entry is 1 (4 byte) word.
- * 31:12 -- Reserved
- * 11:0 -- Two 6 bit RxQ Ids
- */
-#define FUNCTION_TO_RXQ_TRANSLATE 0x00002000
-
-/* Catapult RxAdm (RAD) Memory Access Page Numbers */
-#define RAD0_MEM_BLK_BASE_PG_NUM 0x00000086
-#define RAD1_MEM_BLK_BASE_PG_NUM 0x00000087
-
-/**
- * Catapult RSS Table Base Offset Address
- *
- * Exists in RAD memory space.
- * Each entry is 352 bits, but aligned on
- * 64 byte (512 bit) boundary. Accessed
- * 4 byte words, the whole entry can be
- * broken into 11 word accesses.
- */
-#define RSS_TABLE_BASE_OFFSET 0x00000800
-
-/**
- * Catapult CPQ Block Page Number
- * This value is written to the page number registers
- * to access the memory associated with the mailboxes.
- */
-#define CPQ_BLK_PG_NUM 0x00000005
-
-/**
- * Clarification :
- * LL functions are 2 & 3; can HostFn0/HostFn1
- * <-> LPU0/LPU1 memories be used ?
- */
-/**
- * Catapult HostFn0/HostFn1 to LPU0/LPU1 Mbox memory
- * Per catapult_spec.pdf, the offset of the mbox
- * memory is in the register space at an offset of 0x200
- */
-#define CPQ_BLK_REG_MBOX_ADDR (CPQ_BLK_REG_ADDR + 0x200)
-
-#define HOSTFN_LPU_MBOX (CPQ_BLK_REG_MBOX_ADDR + 0x000)
-
-/* Catapult LPU0/LPU1 to HostFn0/HostFn1 Mbox memory */
-#define LPU_HOSTFN_MBOX (CPQ_BLK_REG_MBOX_ADDR + 0x080)
-
-/**
- * Catapult HQM Block Page Number
- * This is written to the page number register for
- * the appropriate function to access the memory
- * associated with HQM
- */
-#define HQM0_BLK_PG_NUM 0x00000096
-#define HQM1_BLK_PG_NUM 0x00000097
-
-/**
- * Note that TxQ and RxQ entries are interlaced
- * the HQM memory, i.e RXQ0, TXQ0, RXQ1, TXQ1.. etc.
- */
-
-#define HQM_RXTX_Q_RAM_BASE_OFFSET 0x00004000
-
-/**
- * CQ Memory
- * Exists in HQM Memory space
- * Each entry is 16 (4 byte) words of which
- * only 12 words are used for configuration
- * Total 64 entries per HQM memory space
- */
-#define HQM_CQ_RAM_BASE_OFFSET 0x00006000
-
-/**
- * Interrupt Block (IB) Memory
- * Exists in HQM Memory space
- * Each entry is 8 (4 byte) words of which
- * only 5 words are used for configuration
- * Total 128 entries per HQM memory space
- */
-#define HQM_IB_RAM_BASE_OFFSET 0x00001000
-
-/**
- * Index Table (IT) Memory
- * Exists in HQM Memory space
- * Each entry is 1 (4 byte) word which
- * is used for configuration
- * Total 128 entries per HQM memory space
- */
-#define HQM_INDX_TBL_RAM_BASE_OFFSET 0x00002000
-
-/**
- * PSS Block Memory Page Number
- * This is written to the appropriate page number
- * register to access the CPU memory.
- * Also known as the PSS secondary memory (SMEM).
- * Range : 0x180 to 0x1CF
- * See catapult_spec.pdf for details
- */
-#define PSS_BLK_PG_NUM 0x00000180
-
-/**
- * Offsets of different instances of PSS SMEM
- * 2.5M of continuous 1T memory space : 2 blocks
- * of 1M each (32 pages each, page=32KB) and 4 smaller
- * blocks of 128K each (4 pages each, page=32KB)
- * PSS_LMEM_INST0 is used for firmware download
- */
-#define PSS_LMEM_INST0 0x00000000
-#define PSS_LMEM_INST1 0x00100000
-#define PSS_LMEM_INST2 0x00200000
-#define PSS_LMEM_INST3 0x00220000
-#define PSS_LMEM_INST4 0x00240000
-#define PSS_LMEM_INST5 0x00260000
-
-#define BNA_PCI_REG_CT_ADDRSZ (0x40000)
-
-#define BNA_GET_PAGE_NUM(_base_page, _offset) \
- ((_base_page) + ((_offset) >> 15))
-
-#define BNA_GET_PAGE_OFFSET(_offset) \
- ((_offset) & 0x7fff)
-
-#define BNA_GET_MEM_BASE_ADDR(_bar0, _base_offset) \
- ((_bar0) + HW_BLK_HOST_MEM_ADDR \
- + BNA_GET_PAGE_OFFSET((_base_offset)))
-
-#define BNA_GET_VLAN_MEM_ENTRY_ADDR(_bar0, _fn_id, _vlan_id)\
- (_bar0 + (HW_BLK_HOST_MEM_ADDR) \
- + (BNA_GET_PAGE_OFFSET(VLAN_RAM_BASE_OFFSET)) \
- + (((_fn_id) & 0x3f) << 9) \
- + (((_vlan_id) & 0xfe0) >> 3))
-
-/**
- *
- * Interrupt related bits, flags and macros
- *
- */
-
-#define __LPU02HOST_MBOX0_STATUS_BITS 0x00100000
-#define __LPU12HOST_MBOX0_STATUS_BITS 0x00200000
-#define __LPU02HOST_MBOX1_STATUS_BITS 0x00400000
-#define __LPU12HOST_MBOX1_STATUS_BITS 0x00800000
-
-#define __LPU02HOST_MBOX0_MASK_BITS 0x00100000
-#define __LPU12HOST_MBOX0_MASK_BITS 0x00200000
-#define __LPU02HOST_MBOX1_MASK_BITS 0x00400000
-#define __LPU12HOST_MBOX1_MASK_BITS 0x00800000
-
-#define __LPU2HOST_MBOX_MASK_BITS \
- (__LPU02HOST_MBOX0_MASK_BITS | __LPU02HOST_MBOX1_MASK_BITS | \
- __LPU12HOST_MBOX0_MASK_BITS | __LPU12HOST_MBOX1_MASK_BITS)
-
-#define __LPU2HOST_IB_STATUS_BITS 0x0000ffff
-
-#define BNA_IS_LPU0_MBOX_INTR(_intr_status) \
- ((_intr_status) & (__LPU02HOST_MBOX0_STATUS_BITS | \
- __LPU02HOST_MBOX1_STATUS_BITS))
-
-#define BNA_IS_LPU1_MBOX_INTR(_intr_status) \
- ((_intr_status) & (__LPU12HOST_MBOX0_STATUS_BITS | \
- __LPU12HOST_MBOX1_STATUS_BITS))
-
-#define BNA_IS_MBOX_INTR(_intr_status) \
- ((_intr_status) & \
- (__LPU02HOST_MBOX0_STATUS_BITS | \
- __LPU02HOST_MBOX1_STATUS_BITS | \
- __LPU12HOST_MBOX0_STATUS_BITS | \
- __LPU12HOST_MBOX1_STATUS_BITS))
-
-#define __EMC_ERROR_STATUS_BITS 0x00010000
-#define __LPU0_ERROR_STATUS_BITS 0x00020000
-#define __LPU1_ERROR_STATUS_BITS 0x00040000
-#define __PSS_ERROR_STATUS_BITS 0x00080000
-
-#define __HALT_STATUS_BITS 0x01000000
-
-#define __EMC_ERROR_MASK_BITS 0x00010000
-#define __LPU0_ERROR_MASK_BITS 0x00020000
-#define __LPU1_ERROR_MASK_BITS 0x00040000
-#define __PSS_ERROR_MASK_BITS 0x00080000
-
-#define __HALT_MASK_BITS 0x01000000
-
-#define __ERROR_MASK_BITS \
- (__EMC_ERROR_MASK_BITS | __LPU0_ERROR_MASK_BITS | \
- __LPU1_ERROR_MASK_BITS | __PSS_ERROR_MASK_BITS | \
- __HALT_MASK_BITS)
-
-#define BNA_IS_ERR_INTR(_intr_status) \
- ((_intr_status) & \
- (__EMC_ERROR_STATUS_BITS | \
- __LPU0_ERROR_STATUS_BITS | \
- __LPU1_ERROR_STATUS_BITS | \
- __PSS_ERROR_STATUS_BITS | \
- __HALT_STATUS_BITS))
-
-#define BNA_IS_MBOX_ERR_INTR(_intr_status) \
- (BNA_IS_MBOX_INTR((_intr_status)) | \
- BNA_IS_ERR_INTR((_intr_status)))
-
-#define BNA_IS_INTX_DATA_INTR(_intr_status) \
- ((_intr_status) & __LPU2HOST_IB_STATUS_BITS)
-
-#define BNA_INTR_STATUS_MBOX_CLR(_intr_status) \
-do { \
- (_intr_status) &= ~(__LPU02HOST_MBOX0_STATUS_BITS | \
- __LPU02HOST_MBOX1_STATUS_BITS | \
- __LPU12HOST_MBOX0_STATUS_BITS | \
- __LPU12HOST_MBOX1_STATUS_BITS); \
-} while (0)
-
-#define BNA_INTR_STATUS_ERR_CLR(_intr_status) \
-do { \
- (_intr_status) &= ~(__EMC_ERROR_STATUS_BITS | \
- __LPU0_ERROR_STATUS_BITS | \
- __LPU1_ERROR_STATUS_BITS | \
- __PSS_ERROR_STATUS_BITS | \
- __HALT_STATUS_BITS); \
-} while (0)
-
-#define bna_intx_disable(_bna, _cur_mask) \
-{ \
- (_cur_mask) = readl((_bna)->regs.fn_int_mask);\
- writel(0xffffffff, (_bna)->regs.fn_int_mask);\
-}
-
-#define bna_intx_enable(bna, new_mask) \
- writel((new_mask), (bna)->regs.fn_int_mask)
-
-#define bna_mbox_intr_disable(bna) \
- writel((readl((bna)->regs.fn_int_mask) | \
- (__LPU2HOST_MBOX_MASK_BITS | __ERROR_MASK_BITS)), \
- (bna)->regs.fn_int_mask)
-
-#define bna_mbox_intr_enable(bna) \
- writel((readl((bna)->regs.fn_int_mask) & \
- ~(__LPU2HOST_MBOX_MASK_BITS | __ERROR_MASK_BITS)), \
- (bna)->regs.fn_int_mask)
-
-#define bna_intr_status_get(_bna, _status) \
-{ \
- (_status) = readl((_bna)->regs.fn_int_status); \
- if ((_status)) { \
- writel((_status) & ~(__LPU02HOST_MBOX0_STATUS_BITS |\
- __LPU02HOST_MBOX1_STATUS_BITS |\
- __LPU12HOST_MBOX0_STATUS_BITS |\
- __LPU12HOST_MBOX1_STATUS_BITS), \
- (_bna)->regs.fn_int_status);\
- } \
-}
-
-#define bna_intr_status_get_no_clr(_bna, _status) \
- (_status) = readl((_bna)->regs.fn_int_status)
-
-#define bna_intr_mask_get(bna, mask) \
- (*mask) = readl((bna)->regs.fn_int_mask)
-
-#define bna_intr_ack(bna, intr_bmap) \
- writel((intr_bmap), (bna)->regs.fn_int_status)
-
-#define bna_ib_intx_disable(bna, ib_id) \
- writel(readl((bna)->regs.fn_int_mask) | \
- (1 << (ib_id)), \
- (bna)->regs.fn_int_mask)
-
-#define bna_ib_intx_enable(bna, ib_id) \
- writel(readl((bna)->regs.fn_int_mask) & \
- ~(1 << (ib_id)), \
- (bna)->regs.fn_int_mask)
-
-#define bna_mbox_msix_idx_set(_device) \
-do {\
- writel(((_device)->vector & 0x000001FF), \
- (_device)->bna->pcidev.pci_bar_kva + \
- reg_offset[(_device)->bna->pcidev.pci_func].msix_idx);\
-} while (0)
-
-/**
- *
- * TxQ, RxQ, CQ related bits, offsets, macros
- *
- */
-
-#define BNA_Q_IDLE_STATE 0x00008001
-
-#define BNA_GET_DOORBELL_BASE_ADDR(_bar0) \
- ((_bar0) + HQM_DOORBELL_BLK_BASE_ADDR)
-
-#define BNA_GET_DOORBELL_ENTRY_OFFSET(_entry) \
- ((HQM_DOORBELL_BLK_BASE_ADDR) \
- + (_entry << 7))
-
-#define BNA_DOORBELL_IB_INT_ACK(_timeout, _events) \
- (0x80000000 | ((_timeout) << 16) | (_events))
-
-#define BNA_DOORBELL_IB_INT_DISABLE (0x40000000)
-
-/* TxQ Entry Opcodes */
-#define BNA_TXQ_WI_SEND (0x402) /* Single Frame Transmission */
-#define BNA_TXQ_WI_SEND_LSO (0x403) /* Multi-Frame Transmission */
-#define BNA_TXQ_WI_EXTENSION (0x104) /* Extension WI */
-
-/* TxQ Entry Control Flags */
-#define BNA_TXQ_WI_CF_FCOE_CRC (1 << 8)
-#define BNA_TXQ_WI_CF_IPID_MODE (1 << 5)
-#define BNA_TXQ_WI_CF_INS_PRIO (1 << 4)
-#define BNA_TXQ_WI_CF_INS_VLAN (1 << 3)
-#define BNA_TXQ_WI_CF_UDP_CKSUM (1 << 2)
-#define BNA_TXQ_WI_CF_TCP_CKSUM (1 << 1)
-#define BNA_TXQ_WI_CF_IP_CKSUM (1 << 0)
-
-#define BNA_TXQ_WI_L4_HDR_N_OFFSET(_hdr_size, _offset) \
- (((_hdr_size) << 10) | ((_offset) & 0x3FF))
-
-/*
- * Completion Q defines
- */
-/* CQ Entry Flags */
-#define BNA_CQ_EF_MAC_ERROR (1 << 0)
-#define BNA_CQ_EF_FCS_ERROR (1 << 1)
-#define BNA_CQ_EF_TOO_LONG (1 << 2)
-#define BNA_CQ_EF_FC_CRC_OK (1 << 3)
-
-#define BNA_CQ_EF_RSVD1 (1 << 4)
-#define BNA_CQ_EF_L4_CKSUM_OK (1 << 5)
-#define BNA_CQ_EF_L3_CKSUM_OK (1 << 6)
-#define BNA_CQ_EF_HDS_HEADER (1 << 7)
-
-#define BNA_CQ_EF_UDP (1 << 8)
-#define BNA_CQ_EF_TCP (1 << 9)
-#define BNA_CQ_EF_IP_OPTIONS (1 << 10)
-#define BNA_CQ_EF_IPV6 (1 << 11)
-
-#define BNA_CQ_EF_IPV4 (1 << 12)
-#define BNA_CQ_EF_VLAN (1 << 13)
-#define BNA_CQ_EF_RSS (1 << 14)
-#define BNA_CQ_EF_RSVD2 (1 << 15)
-
-#define BNA_CQ_EF_MCAST_MATCH (1 << 16)
-#define BNA_CQ_EF_MCAST (1 << 17)
-#define BNA_CQ_EF_BCAST (1 << 18)
-#define BNA_CQ_EF_REMOTE (1 << 19)
-
-#define BNA_CQ_EF_LOCAL (1 << 20)
-
-/**
- *
- * Data structures
- *
- */
-
-enum txf_flags {
- BFI_TXF_CF_ENABLE = 1 << 0,
- BFI_TXF_CF_VLAN_FILTER = 1 << 8,
- BFI_TXF_CF_VLAN_ADMIT = 1 << 9,
- BFI_TXF_CF_VLAN_INSERT = 1 << 10,
- BFI_TXF_CF_RSVD1 = 1 << 11,
- BFI_TXF_CF_MAC_SA_CHECK = 1 << 12,
- BFI_TXF_CF_VLAN_WI_BASED = 1 << 13,
- BFI_TXF_CF_VSWITCH_MCAST = 1 << 14,
- BFI_TXF_CF_VSWITCH_UCAST = 1 << 15,
- BFI_TXF_CF_RSVD2 = 0x7F << 1
-};
-
-enum ib_flags {
- BFI_IB_CF_MASTER_ENABLE = (1 << 0),
- BFI_IB_CF_MSIX_MODE = (1 << 1),
- BFI_IB_CF_COALESCING_MODE = (1 << 2),
- BFI_IB_CF_INTER_PKT_ENABLE = (1 << 3),
- BFI_IB_CF_INT_ENABLE = (1 << 4),
- BFI_IB_CF_INTER_PKT_DMA = (1 << 5),
- BFI_IB_CF_ACK_PENDING = (1 << 6),
- BFI_IB_CF_RESERVED1 = (1 << 7)
-};
-
-enum rss_hash_type {
- BFI_RSS_T_V4_TCP = (1 << 11),
- BFI_RSS_T_V4_IP = (1 << 10),
- BFI_RSS_T_V6_TCP = (1 << 9),
- BFI_RSS_T_V6_IP = (1 << 8)
-};
-enum hds_header_type {
- BNA_HDS_T_V4_TCP = (1 << 11),
- BNA_HDS_T_V4_UDP = (1 << 10),
- BNA_HDS_T_V6_TCP = (1 << 9),
- BNA_HDS_T_V6_UDP = (1 << 8),
- BNA_HDS_FORCED = (1 << 7),
-};
-enum rxf_flags {
- BNA_RXF_CF_SM_LG_RXQ = (1 << 15),
- BNA_RXF_CF_DEFAULT_VLAN = (1 << 14),
- BNA_RXF_CF_DEFAULT_FUNCTION_ENABLE = (1 << 13),
- BNA_RXF_CF_VLAN_STRIP = (1 << 12),
- BNA_RXF_CF_RSS_ENABLE = (1 << 8)
-};
-struct bna_chip_regs_offset {
- u32 page_addr;
- u32 fn_int_status;
- u32 fn_int_mask;
- u32 msix_idx;
-};
-
-struct bna_chip_regs {
- void __iomem *page_addr;
- void __iomem *fn_int_status;
- void __iomem *fn_int_mask;
-};
-
-struct bna_txq_mem {
- u32 pg_tbl_addr_lo;
- u32 pg_tbl_addr_hi;
- u32 cur_q_entry_lo;
- u32 cur_q_entry_hi;
- u32 reserved1;
- u32 reserved2;
- u32 pg_cnt_n_prd_ptr; /* 31:16->total page count */
- /* 15:0 ->producer pointer (index?) */
- u32 entry_n_pg_size; /* 31:16->entry size */
- /* 15:0 ->page size */
- u32 int_blk_n_cns_ptr; /* 31:24->Int Blk Id; */
- /* 23:16->Int Blk Offset */
- /* 15:0 ->consumer pointer(index?) */
- u32 cns_ptr2_n_q_state; /* 31:16->cons. ptr 2; 15:0-> Q state */
- u32 nxt_qid_n_fid_n_pri; /* 17:10->next */
- /* QId;9:3->FID;2:0->Priority */
- u32 wvc_n_cquota_n_rquota; /* 31:24->WI Vector Count; */
- /* 23:12->Cfg Quota; */
- /* 11:0 ->Run Quota */
- u32 reserved3[4];
-};
-
-struct bna_rxq_mem {
- u32 pg_tbl_addr_lo;
- u32 pg_tbl_addr_hi;
- u32 cur_q_entry_lo;
- u32 cur_q_entry_hi;
- u32 reserved1;
- u32 reserved2;
- u32 pg_cnt_n_prd_ptr; /* 31:16->total page count */
- /* 15:0 ->producer pointer (index?) */
- u32 entry_n_pg_size; /* 31:16->entry size */
- /* 15:0 ->page size */
- u32 sg_n_cq_n_cns_ptr; /* 31:28->reserved; 27:24->sg count */
- /* 23:16->CQ; */
- /* 15:0->consumer pointer(index?) */
- u32 buf_sz_n_q_state; /* 31:16->buffer size; 15:0-> Q state */
- u32 next_qid; /* 17:10->next QId */
- u32 reserved3;
- u32 reserved4[4];
-};
-
-struct bna_rxtx_q_mem {
- struct bna_rxq_mem rxq;
- struct bna_txq_mem txq;
-};
-
-struct bna_cq_mem {
- u32 pg_tbl_addr_lo;
- u32 pg_tbl_addr_hi;
- u32 cur_q_entry_lo;
- u32 cur_q_entry_hi;
-
- u32 reserved1;
- u32 reserved2;
- u32 pg_cnt_n_prd_ptr; /* 31:16->total page count */
- /* 15:0 ->producer pointer (index?) */
- u32 entry_n_pg_size; /* 31:16->entry size */
- /* 15:0 ->page size */
- u32 int_blk_n_cns_ptr; /* 31:24->Int Blk Id; */
- /* 23:16->Int Blk Offset */
- /* 15:0 ->consumer pointer(index?) */
- u32 q_state; /* 31:16->reserved; 15:0-> Q state */
- u32 reserved3[2];
- u32 reserved4[4];
-};
-
-struct bna_ib_blk_mem {
- u32 host_addr_lo;
- u32 host_addr_hi;
- u32 clsc_n_ctrl_n_msix; /* 31:24->coalescing; */
- /* 23:16->coalescing cfg; */
- /* 15:8 ->control; */
- /* 7:0 ->msix; */
- u32 ipkt_n_ent_n_idxof;
- u32 ipkt_cnt_cfg_n_unacked;
-
- u32 reserved[3];
-};
-
-struct bna_idx_tbl_mem {
- u32 idx; /* !< 31:16->res;15:0->idx; */
-};
-
-struct bna_doorbell_qset {
- u32 rxq[0x20 >> 2];
- u32 txq[0x20 >> 2];
- u32 ib0[0x20 >> 2];
- u32 ib1[0x20 >> 2];
-};
-
-struct bna_rx_fndb_ram {
- u32 rss_prop;
- u32 size_routing_props;
- u32 rit_hds_mcastq;
- u32 control_flags;
-};
-
-struct bna_tx_fndb_ram {
- u32 vlan_n_ctrl_flags;
-};
-
-/**
- * @brief
- * Structure which maps to RxFn Indirection Table (RIT)
- * Size : 1 word
- * See catapult_spec.pdf, RxA for details
- */
-struct bna_rit_mem {
- u32 rxq_ids; /* !< 31:12->res;11:0->two 6 bit RxQ Ids */
-};
-
-/**
- * @brief
- * Structure which maps to RSS Table entry
- * Size : 16 words
- * See catapult_spec.pdf, RAD for details
- */
-struct bna_rss_mem {
- /*
- * 31:12-> res
- * 11:8 -> protocol type
- * 7:0 -> hash index
- */
- u32 type_n_hash;
- u32 hash_key[10]; /* !< 40 byte Toeplitz hash key */
- u32 reserved[5];
-};
-
-/* TxQ Vector (a.k.a. Tx-Buffer Descriptor) */
-struct bna_dma_addr {
- u32 msb;
- u32 lsb;
-};
-
-struct bna_txq_wi_vector {
- u16 reserved;
- u16 length; /* Only 14 LSB are valid */
- struct bna_dma_addr host_addr; /* Tx-Buf DMA addr */
-};
-
-typedef u16 bna_txq_wi_opcode_t;
-
-typedef u16 bna_txq_wi_ctrl_flag_t;
-
-/**
- * TxQ Entry Structure
- *
- * BEWARE: Load values into this structure with correct endianess.
- */
-struct bna_txq_entry {
- union {
- struct {
- u8 reserved;
- u8 num_vectors; /* number of vectors present */
- bna_txq_wi_opcode_t opcode; /* Either */
- /* BNA_TXQ_WI_SEND or */
- /* BNA_TXQ_WI_SEND_LSO */
- bna_txq_wi_ctrl_flag_t flags; /* OR of all the flags */
- u16 l4_hdr_size_n_offset;
- u16 vlan_tag;
- u16 lso_mss; /* Only 14 LSB are valid */
- u32 frame_length; /* Only 24 LSB are valid */
- } wi;
-
- struct {
- u16 reserved;
- bna_txq_wi_opcode_t opcode; /* Must be */
- /* BNA_TXQ_WI_EXTENSION */
- u32 reserved2[3]; /* Place holder for */
- /* removed vector (12 bytes) */
- } wi_ext;
- } hdr;
- struct bna_txq_wi_vector vector[4];
-};
-#define wi_hdr hdr.wi
-#define wi_ext_hdr hdr.wi_ext
-
-/* RxQ Entry Structure */
-struct bna_rxq_entry { /* Rx-Buffer */
- struct bna_dma_addr host_addr; /* Rx-Buffer DMA address */
-};
-
-typedef u32 bna_cq_e_flag_t;
-
-/* CQ Entry Structure */
-struct bna_cq_entry {
- bna_cq_e_flag_t flags;
- u16 vlan_tag;
- u16 length;
- u32 rss_hash;
- u8 valid;
- u8 reserved1;
- u8 reserved2;
- u8 rxq_id;
-};
-
-#endif /* __BNA_HW_H__ */
diff --git a/drivers/net/bna/bna_txrx.c b/drivers/net/bna/bna_txrx.c
deleted file mode 100644
index f0983c832447..000000000000
--- a/drivers/net/bna/bna_txrx.c
+++ /dev/null
@@ -1,4185 +0,0 @@
-/*
- * Linux network driver for Brocade Converged Network Adapter.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License (GPL) Version 2 as
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- */
-/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
- * All rights reserved
- * www.brocade.com
- */
-#include "bna.h"
-#include "bfa_cs.h"
-#include "bfi.h"
-
-/**
- * IB
- */
-#define bna_ib_find_free_ibidx(_mask, _pos)\
-do {\
- (_pos) = 0;\
- while (((_pos) < (BFI_IBIDX_MAX_SEGSIZE)) &&\
- ((1 << (_pos)) & (_mask)))\
- (_pos)++;\
-} while (0)
-
-#define bna_ib_count_ibidx(_mask, _count)\
-do {\
- int pos = 0;\
- (_count) = 0;\
- while (pos < (BFI_IBIDX_MAX_SEGSIZE)) {\
- if ((1 << pos) & (_mask))\
- (_count) = pos + 1;\
- pos++;\
- } \
-} while (0)
-
-#define bna_ib_select_segpool(_count, _q_idx)\
-do {\
- int i;\
- (_q_idx) = -1;\
- for (i = 0; i < BFI_IBIDX_TOTAL_POOLS; i++) {\
- if ((_count <= ibidx_pool[i].pool_entry_size)) {\
- (_q_idx) = i;\
- break;\
- } \
- } \
-} while (0)
-
-struct bna_ibidx_pool {
- int pool_size;
- int pool_entry_size;
-};
-init_ibidx_pool(ibidx_pool);
-
-static struct bna_intr *
-bna_intr_get(struct bna_ib_mod *ib_mod, enum bna_intr_type intr_type,
- int vector)
-{
- struct bna_intr *intr;
- struct list_head *qe;
-
- list_for_each(qe, &ib_mod->intr_active_q) {
- intr = (struct bna_intr *)qe;
-
- if ((intr->intr_type == intr_type) &&
- (intr->vector == vector)) {
- intr->ref_count++;
- return intr;
- }
- }
-
- if (list_empty(&ib_mod->intr_free_q))
- return NULL;
-
- bfa_q_deq(&ib_mod->intr_free_q, &intr);
- bfa_q_qe_init(&intr->qe);
-
- intr->ref_count = 1;
- intr->intr_type = intr_type;
- intr->vector = vector;
-
- list_add_tail(&intr->qe, &ib_mod->intr_active_q);
-
- return intr;
-}
-
-static void
-bna_intr_put(struct bna_ib_mod *ib_mod,
- struct bna_intr *intr)
-{
- intr->ref_count--;
-
- if (intr->ref_count == 0) {
- intr->ib = NULL;
- list_del(&intr->qe);
- bfa_q_qe_init(&intr->qe);
- list_add_tail(&intr->qe, &ib_mod->intr_free_q);
- }
-}
-
-void
-bna_ib_mod_init(struct bna_ib_mod *ib_mod, struct bna *bna,
- struct bna_res_info *res_info)
-{
- int i;
- int j;
- int count;
- u8 offset;
- struct bna_doorbell_qset *qset;
- unsigned long off;
-
- ib_mod->bna = bna;
-
- ib_mod->ib = (struct bna_ib *)
- res_info[BNA_RES_MEM_T_IB_ARRAY].res_u.mem_info.mdl[0].kva;
- ib_mod->intr = (struct bna_intr *)
- res_info[BNA_RES_MEM_T_INTR_ARRAY].res_u.mem_info.mdl[0].kva;
- ib_mod->idx_seg = (struct bna_ibidx_seg *)
- res_info[BNA_RES_MEM_T_IDXSEG_ARRAY].res_u.mem_info.mdl[0].kva;
-
- INIT_LIST_HEAD(&ib_mod->ib_free_q);
- INIT_LIST_HEAD(&ib_mod->intr_free_q);
- INIT_LIST_HEAD(&ib_mod->intr_active_q);
-
- for (i = 0; i < BFI_IBIDX_TOTAL_POOLS; i++)
- INIT_LIST_HEAD(&ib_mod->ibidx_seg_pool[i]);
-
- for (i = 0; i < BFI_MAX_IB; i++) {
- ib_mod->ib[i].ib_id = i;
-
- ib_mod->ib[i].ib_seg_host_addr_kva =
- res_info[BNA_RES_MEM_T_IBIDX].res_u.mem_info.mdl[i].kva;
- ib_mod->ib[i].ib_seg_host_addr.lsb =
- res_info[BNA_RES_MEM_T_IBIDX].res_u.mem_info.mdl[i].dma.lsb;
- ib_mod->ib[i].ib_seg_host_addr.msb =
- res_info[BNA_RES_MEM_T_IBIDX].res_u.mem_info.mdl[i].dma.msb;
-
- qset = (struct bna_doorbell_qset *)0;
- off = (unsigned long)(&qset[i >> 1].ib0[(i & 0x1)
- * (0x20 >> 2)]);
- ib_mod->ib[i].door_bell.doorbell_addr = off +
- BNA_GET_DOORBELL_BASE_ADDR(bna->pcidev.pci_bar_kva);
-
- bfa_q_qe_init(&ib_mod->ib[i].qe);
- list_add_tail(&ib_mod->ib[i].qe, &ib_mod->ib_free_q);
-
- bfa_q_qe_init(&ib_mod->intr[i].qe);
- list_add_tail(&ib_mod->intr[i].qe, &ib_mod->intr_free_q);
- }
-
- count = 0;
- offset = 0;
- for (i = 0; i < BFI_IBIDX_TOTAL_POOLS; i++) {
- for (j = 0; j < ibidx_pool[i].pool_size; j++) {
- bfa_q_qe_init(&ib_mod->idx_seg[count]);
- ib_mod->idx_seg[count].ib_seg_size =
- ibidx_pool[i].pool_entry_size;
- ib_mod->idx_seg[count].ib_idx_tbl_offset = offset;
- list_add_tail(&ib_mod->idx_seg[count].qe,
- &ib_mod->ibidx_seg_pool[i]);
- count++;
- offset += ibidx_pool[i].pool_entry_size;
- }
- }
-}
-
-void
-bna_ib_mod_uninit(struct bna_ib_mod *ib_mod)
-{
- int i;
- int j;
- struct list_head *qe;
-
- i = 0;
- list_for_each(qe, &ib_mod->ib_free_q)
- i++;
-
- i = 0;
- list_for_each(qe, &ib_mod->intr_free_q)
- i++;
-
- for (i = 0; i < BFI_IBIDX_TOTAL_POOLS; i++) {
- j = 0;
- list_for_each(qe, &ib_mod->ibidx_seg_pool[i])
- j++;
- }
-
- ib_mod->bna = NULL;
-}
-
-static struct bna_ib *
-bna_ib_get(struct bna_ib_mod *ib_mod,
- enum bna_intr_type intr_type,
- int vector)
-{
- struct bna_ib *ib;
- struct bna_intr *intr;
-
- if (intr_type == BNA_INTR_T_INTX)
- vector = (1 << vector);
-
- intr = bna_intr_get(ib_mod, intr_type, vector);
- if (intr == NULL)
- return NULL;
-
- if (intr->ib) {
- if (intr->ib->ref_count == BFI_IBIDX_MAX_SEGSIZE) {
- bna_intr_put(ib_mod, intr);
- return NULL;
- }
- intr->ib->ref_count++;
- return intr->ib;
- }
-
- if (list_empty(&ib_mod->ib_free_q)) {
- bna_intr_put(ib_mod, intr);
- return NULL;
- }
-
- bfa_q_deq(&ib_mod->ib_free_q, &ib);
- bfa_q_qe_init(&ib->qe);
-
- ib->ref_count = 1;
- ib->start_count = 0;
- ib->idx_mask = 0;
-
- ib->intr = intr;
- ib->idx_seg = NULL;
- intr->ib = ib;
-
- ib->bna = ib_mod->bna;
-
- return ib;
-}
-
-static void
-bna_ib_put(struct bna_ib_mod *ib_mod, struct bna_ib *ib)
-{
- bna_intr_put(ib_mod, ib->intr);
-
- ib->ref_count--;
-
- if (ib->ref_count == 0) {
- ib->intr = NULL;
- ib->bna = NULL;
- list_add_tail(&ib->qe, &ib_mod->ib_free_q);
- }
-}
-
-/* Returns index offset - starting from 0 */
-static int
-bna_ib_reserve_idx(struct bna_ib *ib)
-{
- struct bna_ib_mod *ib_mod = &ib->bna->ib_mod;
- struct bna_ibidx_seg *idx_seg;
- int idx;
- int num_idx;
- int q_idx;
-
- /* Find the first free index position */
- bna_ib_find_free_ibidx(ib->idx_mask, idx);
- if (idx == BFI_IBIDX_MAX_SEGSIZE)
- return -1;
-
- /*
- * Calculate the total number of indexes held by this IB,
- * including the index newly reserved above.
- */
- bna_ib_count_ibidx((ib->idx_mask | (1 << idx)), num_idx);
-
- /* See if there is a free space in the index segment held by this IB */
- if (ib->idx_seg && (num_idx <= ib->idx_seg->ib_seg_size)) {
- ib->idx_mask |= (1 << idx);
- return idx;
- }
-
- if (ib->start_count)
- return -1;
-
- /* Allocate a new segment */
- bna_ib_select_segpool(num_idx, q_idx);
- while (1) {
- if (q_idx == BFI_IBIDX_TOTAL_POOLS)
- return -1;
- if (!list_empty(&ib_mod->ibidx_seg_pool[q_idx]))
- break;
- q_idx++;
- }
- bfa_q_deq(&ib_mod->ibidx_seg_pool[q_idx], &idx_seg);
- bfa_q_qe_init(&idx_seg->qe);
-
- /* Free the old segment */
- if (ib->idx_seg) {
- bna_ib_select_segpool(ib->idx_seg->ib_seg_size, q_idx);
- list_add_tail(&ib->idx_seg->qe, &ib_mod->ibidx_seg_pool[q_idx]);
- }
-
- ib->idx_seg = idx_seg;
-
- ib->idx_mask |= (1 << idx);
-
- return idx;
-}
-
-static void
-bna_ib_release_idx(struct bna_ib *ib, int idx)
-{
- struct bna_ib_mod *ib_mod = &ib->bna->ib_mod;
- struct bna_ibidx_seg *idx_seg;
- int num_idx;
- int cur_q_idx;
- int new_q_idx;
-
- ib->idx_mask &= ~(1 << idx);
-
- if (ib->start_count)
- return;
-
- bna_ib_count_ibidx(ib->idx_mask, num_idx);
-
- /*
- * Free the segment, if there are no more indexes in the segment
- * held by this IB
- */
- if (!num_idx) {
- bna_ib_select_segpool(ib->idx_seg->ib_seg_size, cur_q_idx);
- list_add_tail(&ib->idx_seg->qe,
- &ib_mod->ibidx_seg_pool[cur_q_idx]);
- ib->idx_seg = NULL;
- return;
- }
-
- /* See if we can move to a smaller segment */
- bna_ib_select_segpool(num_idx, new_q_idx);
- bna_ib_select_segpool(ib->idx_seg->ib_seg_size, cur_q_idx);
- while (new_q_idx < cur_q_idx) {
- if (!list_empty(&ib_mod->ibidx_seg_pool[new_q_idx]))
- break;
- new_q_idx++;
- }
- if (new_q_idx < cur_q_idx) {
- /* Select the new smaller segment */
- bfa_q_deq(&ib_mod->ibidx_seg_pool[new_q_idx], &idx_seg);
- bfa_q_qe_init(&idx_seg->qe);
- /* Free the old segment */
- list_add_tail(&ib->idx_seg->qe,
- &ib_mod->ibidx_seg_pool[cur_q_idx]);
- ib->idx_seg = idx_seg;
- }
-}
-
-static int
-bna_ib_config(struct bna_ib *ib, struct bna_ib_config *ib_config)
-{
- if (ib->start_count)
- return -1;
-
- ib->ib_config.coalescing_timeo = ib_config->coalescing_timeo;
- ib->ib_config.interpkt_timeo = ib_config->interpkt_timeo;
- ib->ib_config.interpkt_count = ib_config->interpkt_count;
- ib->ib_config.ctrl_flags = ib_config->ctrl_flags;
-
- ib->ib_config.ctrl_flags |= BFI_IB_CF_MASTER_ENABLE;
- if (ib->intr->intr_type == BNA_INTR_T_MSIX)
- ib->ib_config.ctrl_flags |= BFI_IB_CF_MSIX_MODE;
-
- return 0;
-}
-
-static void
-bna_ib_start(struct bna_ib *ib)
-{
- struct bna_ib_blk_mem ib_cfg;
- struct bna_ib_blk_mem *ib_mem;
- u32 pg_num;
- u32 intx_mask;
- int i;
- void __iomem *base_addr;
- unsigned long off;
-
- ib->start_count++;
-
- if (ib->start_count > 1)
- return;
-
- ib_cfg.host_addr_lo = (u32)(ib->ib_seg_host_addr.lsb);
- ib_cfg.host_addr_hi = (u32)(ib->ib_seg_host_addr.msb);
-
- ib_cfg.clsc_n_ctrl_n_msix = (((u32)
- ib->ib_config.coalescing_timeo << 16) |
- ((u32)ib->ib_config.ctrl_flags << 8) |
- (ib->intr->vector));
- ib_cfg.ipkt_n_ent_n_idxof =
- ((u32)
- (ib->ib_config.interpkt_timeo & 0xf) << 16) |
- ((u32)ib->idx_seg->ib_seg_size << 8) |
- (ib->idx_seg->ib_idx_tbl_offset);
- ib_cfg.ipkt_cnt_cfg_n_unacked = ((u32)
- ib->ib_config.interpkt_count << 24);
-
- pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + ib->bna->port_num,
- HQM_IB_RAM_BASE_OFFSET);
- writel(pg_num, ib->bna->regs.page_addr);
-
- base_addr = BNA_GET_MEM_BASE_ADDR(ib->bna->pcidev.pci_bar_kva,
- HQM_IB_RAM_BASE_OFFSET);
-
- ib_mem = (struct bna_ib_blk_mem *)0;
- off = (unsigned long)&ib_mem[ib->ib_id].host_addr_lo;
- writel(htonl(ib_cfg.host_addr_lo), base_addr + off);
-
- off = (unsigned long)&ib_mem[ib->ib_id].host_addr_hi;
- writel(htonl(ib_cfg.host_addr_hi), base_addr + off);
-
- off = (unsigned long)&ib_mem[ib->ib_id].clsc_n_ctrl_n_msix;
- writel(ib_cfg.clsc_n_ctrl_n_msix, base_addr + off);
-
- off = (unsigned long)&ib_mem[ib->ib_id].ipkt_n_ent_n_idxof;
- writel(ib_cfg.ipkt_n_ent_n_idxof, base_addr + off);
-
- off = (unsigned long)&ib_mem[ib->ib_id].ipkt_cnt_cfg_n_unacked;
- writel(ib_cfg.ipkt_cnt_cfg_n_unacked, base_addr + off);
-
- ib->door_bell.doorbell_ack = BNA_DOORBELL_IB_INT_ACK(
- (u32)ib->ib_config.coalescing_timeo, 0);
-
- pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + ib->bna->port_num,
- HQM_INDX_TBL_RAM_BASE_OFFSET);
- writel(pg_num, ib->bna->regs.page_addr);
-
- base_addr = BNA_GET_MEM_BASE_ADDR(ib->bna->pcidev.pci_bar_kva,
- HQM_INDX_TBL_RAM_BASE_OFFSET);
- for (i = 0; i < ib->idx_seg->ib_seg_size; i++) {
- off = (unsigned long)
- ((ib->idx_seg->ib_idx_tbl_offset + i) * BFI_IBIDX_SIZE);
- writel(0, base_addr + off);
- }
-
- if (ib->intr->intr_type == BNA_INTR_T_INTX) {
- bna_intx_disable(ib->bna, intx_mask);
- intx_mask &= ~(ib->intr->vector);
- bna_intx_enable(ib->bna, intx_mask);
- }
-}
-
-static void
-bna_ib_stop(struct bna_ib *ib)
-{
- u32 intx_mask;
-
- ib->start_count--;
-
- if (ib->start_count == 0) {
- writel(BNA_DOORBELL_IB_INT_DISABLE,
- ib->door_bell.doorbell_addr);
- if (ib->intr->intr_type == BNA_INTR_T_INTX) {
- bna_intx_disable(ib->bna, intx_mask);
- intx_mask |= (ib->intr->vector);
- bna_intx_enable(ib->bna, intx_mask);
- }
- }
-}
-
-static void
-bna_ib_fail(struct bna_ib *ib)
-{
- ib->start_count = 0;
-}
-
-/**
- * RXF
- */
-static void rxf_enable(struct bna_rxf *rxf);
-static void rxf_disable(struct bna_rxf *rxf);
-static void __rxf_config_set(struct bna_rxf *rxf);
-static void __rxf_rit_set(struct bna_rxf *rxf);
-static void __bna_rxf_stat_clr(struct bna_rxf *rxf);
-static int rxf_process_packet_filter(struct bna_rxf *rxf);
-static int rxf_clear_packet_filter(struct bna_rxf *rxf);
-static void rxf_reset_packet_filter(struct bna_rxf *rxf);
-static void rxf_cb_enabled(void *arg, int status);
-static void rxf_cb_disabled(void *arg, int status);
-static void bna_rxf_cb_stats_cleared(void *arg, int status);
-static void __rxf_enable(struct bna_rxf *rxf);
-static void __rxf_disable(struct bna_rxf *rxf);
-
-bfa_fsm_state_decl(bna_rxf, stopped, struct bna_rxf,
- enum bna_rxf_event);
-bfa_fsm_state_decl(bna_rxf, start_wait, struct bna_rxf,
- enum bna_rxf_event);
-bfa_fsm_state_decl(bna_rxf, cam_fltr_mod_wait, struct bna_rxf,
- enum bna_rxf_event);
-bfa_fsm_state_decl(bna_rxf, started, struct bna_rxf,
- enum bna_rxf_event);
-bfa_fsm_state_decl(bna_rxf, cam_fltr_clr_wait, struct bna_rxf,
- enum bna_rxf_event);
-bfa_fsm_state_decl(bna_rxf, stop_wait, struct bna_rxf,
- enum bna_rxf_event);
-bfa_fsm_state_decl(bna_rxf, pause_wait, struct bna_rxf,
- enum bna_rxf_event);
-bfa_fsm_state_decl(bna_rxf, resume_wait, struct bna_rxf,
- enum bna_rxf_event);
-bfa_fsm_state_decl(bna_rxf, stat_clr_wait, struct bna_rxf,
- enum bna_rxf_event);
-
-static struct bfa_sm_table rxf_sm_table[] = {
- {BFA_SM(bna_rxf_sm_stopped), BNA_RXF_STOPPED},
- {BFA_SM(bna_rxf_sm_start_wait), BNA_RXF_START_WAIT},
- {BFA_SM(bna_rxf_sm_cam_fltr_mod_wait), BNA_RXF_CAM_FLTR_MOD_WAIT},
- {BFA_SM(bna_rxf_sm_started), BNA_RXF_STARTED},
- {BFA_SM(bna_rxf_sm_cam_fltr_clr_wait), BNA_RXF_CAM_FLTR_CLR_WAIT},
- {BFA_SM(bna_rxf_sm_stop_wait), BNA_RXF_STOP_WAIT},
- {BFA_SM(bna_rxf_sm_pause_wait), BNA_RXF_PAUSE_WAIT},
- {BFA_SM(bna_rxf_sm_resume_wait), BNA_RXF_RESUME_WAIT},
- {BFA_SM(bna_rxf_sm_stat_clr_wait), BNA_RXF_STAT_CLR_WAIT}
-};
-
-static void
-bna_rxf_sm_stopped_entry(struct bna_rxf *rxf)
-{
- call_rxf_stop_cbfn(rxf, BNA_CB_SUCCESS);
-}
-
-static void
-bna_rxf_sm_stopped(struct bna_rxf *rxf, enum bna_rxf_event event)
-{
- switch (event) {
- case RXF_E_START:
- bfa_fsm_set_state(rxf, bna_rxf_sm_start_wait);
- break;
-
- case RXF_E_STOP:
- bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
- break;
-
- case RXF_E_FAIL:
- /* No-op */
- break;
-
- case RXF_E_CAM_FLTR_MOD:
- call_rxf_cam_fltr_cbfn(rxf, BNA_CB_SUCCESS);
- break;
-
- case RXF_E_STARTED:
- case RXF_E_STOPPED:
- case RXF_E_CAM_FLTR_RESP:
- /**
- * These events are received due to flushing of mbox
- * when device fails
- */
- /* No-op */
- break;
-
- case RXF_E_PAUSE:
- rxf->rxf_oper_state = BNA_RXF_OPER_STATE_PAUSED;
- call_rxf_pause_cbfn(rxf, BNA_CB_SUCCESS);
- break;
-
- case RXF_E_RESUME:
- rxf->rxf_oper_state = BNA_RXF_OPER_STATE_RUNNING;
- call_rxf_resume_cbfn(rxf, BNA_CB_SUCCESS);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_rxf_sm_start_wait_entry(struct bna_rxf *rxf)
-{
- __rxf_config_set(rxf);
- __rxf_rit_set(rxf);
- rxf_enable(rxf);
-}
-
-static void
-bna_rxf_sm_start_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
-{
- switch (event) {
- case RXF_E_STOP:
- /**
- * STOP is originated from bnad. When this happens,
- * it can not be waiting for filter update
- */
- call_rxf_start_cbfn(rxf, BNA_CB_INTERRUPT);
- bfa_fsm_set_state(rxf, bna_rxf_sm_stop_wait);
- break;
-
- case RXF_E_FAIL:
- call_rxf_cam_fltr_cbfn(rxf, BNA_CB_SUCCESS);
- call_rxf_start_cbfn(rxf, BNA_CB_FAIL);
- bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
- break;
-
- case RXF_E_CAM_FLTR_MOD:
- /* No-op */
- break;
-
- case RXF_E_STARTED:
- /**
- * Force rxf_process_filter() to go through initial
- * config
- */
- if ((rxf->ucast_active_mac != NULL) &&
- (rxf->ucast_pending_set == 0))
- rxf->ucast_pending_set = 1;
-
- if (rxf->rss_status == BNA_STATUS_T_ENABLED)
- rxf->rxf_flags |= BNA_RXF_FL_RSS_CONFIG_PENDING;
-
- rxf->rxf_flags |= BNA_RXF_FL_VLAN_CONFIG_PENDING;
-
- bfa_fsm_set_state(rxf, bna_rxf_sm_cam_fltr_mod_wait);
- break;
-
- case RXF_E_PAUSE:
- case RXF_E_RESUME:
- rxf->rxf_flags |= BNA_RXF_FL_OPERSTATE_CHANGED;
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_rxf_sm_cam_fltr_mod_wait_entry(struct bna_rxf *rxf)
-{
- if (!rxf_process_packet_filter(rxf)) {
- /* No more pending CAM entries to update */
- bfa_fsm_set_state(rxf, bna_rxf_sm_started);
- }
-}
-
-static void
-bna_rxf_sm_cam_fltr_mod_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
-{
- switch (event) {
- case RXF_E_STOP:
- /**
- * STOP is originated from bnad. When this happens,
- * it can not be waiting for filter update
- */
- call_rxf_start_cbfn(rxf, BNA_CB_INTERRUPT);
- bfa_fsm_set_state(rxf, bna_rxf_sm_cam_fltr_clr_wait);
- break;
-
- case RXF_E_FAIL:
- rxf_reset_packet_filter(rxf);
- call_rxf_cam_fltr_cbfn(rxf, BNA_CB_SUCCESS);
- call_rxf_start_cbfn(rxf, BNA_CB_FAIL);
- bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
- break;
-
- case RXF_E_CAM_FLTR_MOD:
- /* No-op */
- break;
-
- case RXF_E_CAM_FLTR_RESP:
- if (!rxf_process_packet_filter(rxf)) {
- /* No more pending CAM entries to update */
- call_rxf_cam_fltr_cbfn(rxf, BNA_CB_SUCCESS);
- bfa_fsm_set_state(rxf, bna_rxf_sm_started);
- }
- break;
-
- case RXF_E_PAUSE:
- case RXF_E_RESUME:
- rxf->rxf_flags |= BNA_RXF_FL_OPERSTATE_CHANGED;
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_rxf_sm_started_entry(struct bna_rxf *rxf)
-{
- call_rxf_start_cbfn(rxf, BNA_CB_SUCCESS);
-
- if (rxf->rxf_flags & BNA_RXF_FL_OPERSTATE_CHANGED) {
- if (rxf->rxf_oper_state == BNA_RXF_OPER_STATE_PAUSED)
- bfa_fsm_send_event(rxf, RXF_E_PAUSE);
- else
- bfa_fsm_send_event(rxf, RXF_E_RESUME);
- }
-
-}
-
-static void
-bna_rxf_sm_started(struct bna_rxf *rxf, enum bna_rxf_event event)
-{
- switch (event) {
- case RXF_E_STOP:
- bfa_fsm_set_state(rxf, bna_rxf_sm_cam_fltr_clr_wait);
- /* Hack to get FSM start clearing CAM entries */
- bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_RESP);
- break;
-
- case RXF_E_FAIL:
- rxf_reset_packet_filter(rxf);
- bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
- break;
-
- case RXF_E_CAM_FLTR_MOD:
- bfa_fsm_set_state(rxf, bna_rxf_sm_cam_fltr_mod_wait);
- break;
-
- case RXF_E_PAUSE:
- bfa_fsm_set_state(rxf, bna_rxf_sm_pause_wait);
- break;
-
- case RXF_E_RESUME:
- bfa_fsm_set_state(rxf, bna_rxf_sm_resume_wait);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_rxf_sm_cam_fltr_clr_wait_entry(struct bna_rxf *rxf)
-{
- /**
- * Note: Do not add rxf_clear_packet_filter here.
- * It will overstep mbox when this transition happens:
- * cam_fltr_mod_wait -> cam_fltr_clr_wait on RXF_E_STOP event
- */
-}
-
-static void
-bna_rxf_sm_cam_fltr_clr_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
-{
- switch (event) {
- case RXF_E_FAIL:
- /**
- * FSM was in the process of stopping, initiated by
- * bnad. When this happens, no one can be waiting for
- * start or filter update
- */
- rxf_reset_packet_filter(rxf);
- bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
- break;
-
- case RXF_E_CAM_FLTR_RESP:
- if (!rxf_clear_packet_filter(rxf)) {
- /* No more pending CAM entries to clear */
- bfa_fsm_set_state(rxf, bna_rxf_sm_stop_wait);
- rxf_disable(rxf);
- }
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_rxf_sm_stop_wait_entry(struct bna_rxf *rxf)
-{
- /**
- * NOTE: Do not add rxf_disable here.
- * It will overstep mbox when this transition happens:
- * start_wait -> stop_wait on RXF_E_STOP event
- */
-}
-
-static void
-bna_rxf_sm_stop_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
-{
- switch (event) {
- case RXF_E_FAIL:
- /**
- * FSM was in the process of stopping, initiated by
- * bnad. When this happens, no one can be waiting for
- * start or filter update
- */
- bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
- break;
-
- case RXF_E_STARTED:
- /**
- * This event is received due to abrupt transition from
- * bna_rxf_sm_start_wait state on receiving
- * RXF_E_STOP event
- */
- rxf_disable(rxf);
- break;
-
- case RXF_E_STOPPED:
- /**
- * FSM was in the process of stopping, initiated by
- * bnad. When this happens, no one can be waiting for
- * start or filter update
- */
- bfa_fsm_set_state(rxf, bna_rxf_sm_stat_clr_wait);
- break;
-
- case RXF_E_PAUSE:
- rxf->rxf_oper_state = BNA_RXF_OPER_STATE_PAUSED;
- break;
-
- case RXF_E_RESUME:
- rxf->rxf_oper_state = BNA_RXF_OPER_STATE_RUNNING;
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_rxf_sm_pause_wait_entry(struct bna_rxf *rxf)
-{
- rxf->rxf_flags &=
- ~(BNA_RXF_FL_OPERSTATE_CHANGED | BNA_RXF_FL_RXF_ENABLED);
- __rxf_disable(rxf);
-}
-
-static void
-bna_rxf_sm_pause_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
-{
- switch (event) {
- case RXF_E_FAIL:
- /**
- * FSM was in the process of disabling rxf, initiated by
- * bnad.
- */
- call_rxf_pause_cbfn(rxf, BNA_CB_FAIL);
- bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
- break;
-
- case RXF_E_STOPPED:
- rxf->rxf_oper_state = BNA_RXF_OPER_STATE_PAUSED;
- call_rxf_pause_cbfn(rxf, BNA_CB_SUCCESS);
- bfa_fsm_set_state(rxf, bna_rxf_sm_started);
- break;
-
- /*
- * Since PAUSE/RESUME can only be sent by bnad, we don't expect
- * any other event during these states
- */
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_rxf_sm_resume_wait_entry(struct bna_rxf *rxf)
-{
- rxf->rxf_flags &= ~(BNA_RXF_FL_OPERSTATE_CHANGED);
- rxf->rxf_flags |= BNA_RXF_FL_RXF_ENABLED;
- __rxf_enable(rxf);
-}
-
-static void
-bna_rxf_sm_resume_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
-{
- switch (event) {
- case RXF_E_FAIL:
- /**
- * FSM was in the process of disabling rxf, initiated by
- * bnad.
- */
- call_rxf_resume_cbfn(rxf, BNA_CB_FAIL);
- bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
- break;
-
- case RXF_E_STARTED:
- rxf->rxf_oper_state = BNA_RXF_OPER_STATE_RUNNING;
- call_rxf_resume_cbfn(rxf, BNA_CB_SUCCESS);
- bfa_fsm_set_state(rxf, bna_rxf_sm_started);
- break;
-
- /*
- * Since PAUSE/RESUME can only be sent by bnad, we don't expect
- * any other event during these states
- */
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_rxf_sm_stat_clr_wait_entry(struct bna_rxf *rxf)
-{
- __bna_rxf_stat_clr(rxf);
-}
-
-static void
-bna_rxf_sm_stat_clr_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
-{
- switch (event) {
- case RXF_E_FAIL:
- case RXF_E_STAT_CLEARED:
- bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-__rxf_enable(struct bna_rxf *rxf)
-{
- struct bfi_ll_rxf_multi_req ll_req;
- u32 bm[2] = {0, 0};
-
- if (rxf->rxf_id < 32)
- bm[0] = 1 << rxf->rxf_id;
- else
- bm[1] = 1 << (rxf->rxf_id - 32);
-
- bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_RX_REQ, 0);
- ll_req.rxf_id_mask[0] = htonl(bm[0]);
- ll_req.rxf_id_mask[1] = htonl(bm[1]);
- ll_req.enable = 1;
-
- bna_mbox_qe_fill(&rxf->mbox_qe, &ll_req, sizeof(ll_req),
- rxf_cb_enabled, rxf);
-
- bna_mbox_send(rxf->rx->bna, &rxf->mbox_qe);
-}
-
-static void
-__rxf_disable(struct bna_rxf *rxf)
-{
- struct bfi_ll_rxf_multi_req ll_req;
- u32 bm[2] = {0, 0};
-
- if (rxf->rxf_id < 32)
- bm[0] = 1 << rxf->rxf_id;
- else
- bm[1] = 1 << (rxf->rxf_id - 32);
-
- bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_RX_REQ, 0);
- ll_req.rxf_id_mask[0] = htonl(bm[0]);
- ll_req.rxf_id_mask[1] = htonl(bm[1]);
- ll_req.enable = 0;
-
- bna_mbox_qe_fill(&rxf->mbox_qe, &ll_req, sizeof(ll_req),
- rxf_cb_disabled, rxf);
-
- bna_mbox_send(rxf->rx->bna, &rxf->mbox_qe);
-}
-
-static void
-__rxf_config_set(struct bna_rxf *rxf)
-{
- u32 i;
- struct bna_rss_mem *rss_mem;
- struct bna_rx_fndb_ram *rx_fndb_ram;
- struct bna *bna = rxf->rx->bna;
- void __iomem *base_addr;
- unsigned long off;
-
- base_addr = BNA_GET_MEM_BASE_ADDR(bna->pcidev.pci_bar_kva,
- RSS_TABLE_BASE_OFFSET);
-
- rss_mem = (struct bna_rss_mem *)0;
-
- /* Configure RSS if required */
- if (rxf->ctrl_flags & BNA_RXF_CF_RSS_ENABLE) {
- /* configure RSS Table */
- writel(BNA_GET_PAGE_NUM(RAD0_MEM_BLK_BASE_PG_NUM +
- bna->port_num, RSS_TABLE_BASE_OFFSET),
- bna->regs.page_addr);
-
- /* temporarily disable RSS, while hash value is written */
- off = (unsigned long)&rss_mem[0].type_n_hash;
- writel(0, base_addr + off);
-
- for (i = 0; i < BFI_RSS_HASH_KEY_LEN; i++) {
- off = (unsigned long)
- &rss_mem[0].hash_key[(BFI_RSS_HASH_KEY_LEN - 1) - i];
- writel(htonl(rxf->rss_cfg.toeplitz_hash_key[i]),
- base_addr + off);
- }
-
- off = (unsigned long)&rss_mem[0].type_n_hash;
- writel(rxf->rss_cfg.hash_type | rxf->rss_cfg.hash_mask,
- base_addr + off);
- }
-
- /* Configure RxF */
- writel(BNA_GET_PAGE_NUM(
- LUT0_MEM_BLK_BASE_PG_NUM + (bna->port_num * 2),
- RX_FNDB_RAM_BASE_OFFSET),
- bna->regs.page_addr);
-
- base_addr = BNA_GET_MEM_BASE_ADDR(bna->pcidev.pci_bar_kva,
- RX_FNDB_RAM_BASE_OFFSET);
-
- rx_fndb_ram = (struct bna_rx_fndb_ram *)0;
-
- /* We always use RSS table 0 */
- off = (unsigned long)&rx_fndb_ram[rxf->rxf_id].rss_prop;
- writel(rxf->ctrl_flags & BNA_RXF_CF_RSS_ENABLE,
- base_addr + off);
-
- /* small large buffer enable/disable */
- off = (unsigned long)&rx_fndb_ram[rxf->rxf_id].size_routing_props;
- writel((rxf->ctrl_flags & BNA_RXF_CF_SM_LG_RXQ) | 0x80,
- base_addr + off);
-
- /* RIT offset, HDS forced offset, multicast RxQ Id */
- off = (unsigned long)&rx_fndb_ram[rxf->rxf_id].rit_hds_mcastq;
- writel((rxf->rit_segment->rit_offset << 16) |
- (rxf->forced_offset << 8) |
- (rxf->hds_cfg.hdr_type & BNA_HDS_FORCED) | rxf->mcast_rxq_id,
- base_addr + off);
-
- /*
- * default vlan tag, default function enable, strip vlan bytes,
- * HDS type, header size
- */
-
- off = (unsigned long)&rx_fndb_ram[rxf->rxf_id].control_flags;
- writel(((u32)rxf->default_vlan_tag << 16) |
- (rxf->ctrl_flags &
- (BNA_RXF_CF_DEFAULT_VLAN |
- BNA_RXF_CF_DEFAULT_FUNCTION_ENABLE |
- BNA_RXF_CF_VLAN_STRIP)) |
- (rxf->hds_cfg.hdr_type & ~BNA_HDS_FORCED) |
- rxf->hds_cfg.header_size,
- base_addr + off);
-}
-
-void
-__rxf_vlan_filter_set(struct bna_rxf *rxf, enum bna_status status)
-{
- struct bna *bna = rxf->rx->bna;
- int i;
-
- writel(BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
- (bna->port_num * 2), VLAN_RAM_BASE_OFFSET),
- bna->regs.page_addr);
-
- if (status == BNA_STATUS_T_ENABLED) {
- /* enable VLAN filtering on this function */
- for (i = 0; i <= BFI_MAX_VLAN / 32; i++) {
- writel(rxf->vlan_filter_table[i],
- BNA_GET_VLAN_MEM_ENTRY_ADDR
- (bna->pcidev.pci_bar_kva, rxf->rxf_id,
- i * 32));
- }
- } else {
- /* disable VLAN filtering on this function */
- for (i = 0; i <= BFI_MAX_VLAN / 32; i++) {
- writel(0xffffffff,
- BNA_GET_VLAN_MEM_ENTRY_ADDR
- (bna->pcidev.pci_bar_kva, rxf->rxf_id,
- i * 32));
- }
- }
-}
-
-static void
-__rxf_rit_set(struct bna_rxf *rxf)
-{
- struct bna *bna = rxf->rx->bna;
- struct bna_rit_mem *rit_mem;
- int i;
- void __iomem *base_addr;
- unsigned long off;
-
- base_addr = BNA_GET_MEM_BASE_ADDR(bna->pcidev.pci_bar_kva,
- FUNCTION_TO_RXQ_TRANSLATE);
-
- rit_mem = (struct bna_rit_mem *)0;
-
- writel(BNA_GET_PAGE_NUM(RXA0_MEM_BLK_BASE_PG_NUM + bna->port_num,
- FUNCTION_TO_RXQ_TRANSLATE),
- bna->regs.page_addr);
-
- for (i = 0; i < rxf->rit_segment->rit_size; i++) {
- off = (unsigned long)&rit_mem[i + rxf->rit_segment->rit_offset];
- writel(rxf->rit_segment->rit[i].large_rxq_id << 6 |
- rxf->rit_segment->rit[i].small_rxq_id,
- base_addr + off);
- }
-}
-
-static void
-__bna_rxf_stat_clr(struct bna_rxf *rxf)
-{
- struct bfi_ll_stats_req ll_req;
- u32 bm[2] = {0, 0};
-
- if (rxf->rxf_id < 32)
- bm[0] = 1 << rxf->rxf_id;
- else
- bm[1] = 1 << (rxf->rxf_id - 32);
-
- bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_STATS_CLEAR_REQ, 0);
- ll_req.stats_mask = 0;
- ll_req.txf_id_mask[0] = 0;
- ll_req.txf_id_mask[1] = 0;
-
- ll_req.rxf_id_mask[0] = htonl(bm[0]);
- ll_req.rxf_id_mask[1] = htonl(bm[1]);
-
- bna_mbox_qe_fill(&rxf->mbox_qe, &ll_req, sizeof(ll_req),
- bna_rxf_cb_stats_cleared, rxf);
- bna_mbox_send(rxf->rx->bna, &rxf->mbox_qe);
-}
-
-static void
-rxf_enable(struct bna_rxf *rxf)
-{
- if (rxf->rxf_oper_state == BNA_RXF_OPER_STATE_PAUSED)
- bfa_fsm_send_event(rxf, RXF_E_STARTED);
- else {
- rxf->rxf_flags |= BNA_RXF_FL_RXF_ENABLED;
- __rxf_enable(rxf);
- }
-}
-
-static void
-rxf_cb_enabled(void *arg, int status)
-{
- struct bna_rxf *rxf = (struct bna_rxf *)arg;
-
- bfa_q_qe_init(&rxf->mbox_qe.qe);
- bfa_fsm_send_event(rxf, RXF_E_STARTED);
-}
-
-static void
-rxf_disable(struct bna_rxf *rxf)
-{
- if (rxf->rxf_oper_state == BNA_RXF_OPER_STATE_PAUSED)
- bfa_fsm_send_event(rxf, RXF_E_STOPPED);
- else
- rxf->rxf_flags &= ~BNA_RXF_FL_RXF_ENABLED;
- __rxf_disable(rxf);
-}
-
-static void
-rxf_cb_disabled(void *arg, int status)
-{
- struct bna_rxf *rxf = (struct bna_rxf *)arg;
-
- bfa_q_qe_init(&rxf->mbox_qe.qe);
- bfa_fsm_send_event(rxf, RXF_E_STOPPED);
-}
-
-void
-rxf_cb_cam_fltr_mbox_cmd(void *arg, int status)
-{
- struct bna_rxf *rxf = (struct bna_rxf *)arg;
-
- bfa_q_qe_init(&rxf->mbox_qe.qe);
-
- bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_RESP);
-}
-
-static void
-bna_rxf_cb_stats_cleared(void *arg, int status)
-{
- struct bna_rxf *rxf = (struct bna_rxf *)arg;
-
- bfa_q_qe_init(&rxf->mbox_qe.qe);
- bfa_fsm_send_event(rxf, RXF_E_STAT_CLEARED);
-}
-
-void
-rxf_cam_mbox_cmd(struct bna_rxf *rxf, u8 cmd,
- const struct bna_mac *mac_addr)
-{
- struct bfi_ll_mac_addr_req req;
-
- bfi_h2i_set(req.mh, BFI_MC_LL, cmd, 0);
-
- req.rxf_id = rxf->rxf_id;
- memcpy(&req.mac_addr, (void *)&mac_addr->addr, ETH_ALEN);
-
- bna_mbox_qe_fill(&rxf->mbox_qe, &req, sizeof(req),
- rxf_cb_cam_fltr_mbox_cmd, rxf);
-
- bna_mbox_send(rxf->rx->bna, &rxf->mbox_qe);
-}
-
-static int
-rxf_process_packet_filter_mcast(struct bna_rxf *rxf)
-{
- struct bna_mac *mac = NULL;
- struct list_head *qe;
-
- /* Add multicast entries */
- if (!list_empty(&rxf->mcast_pending_add_q)) {
- bfa_q_deq(&rxf->mcast_pending_add_q, &qe);
- bfa_q_qe_init(qe);
- mac = (struct bna_mac *)qe;
- rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_ADD_REQ, mac);
- list_add_tail(&mac->qe, &rxf->mcast_active_q);
- return 1;
- }
-
- /* Delete multicast entries previousely added */
- if (!list_empty(&rxf->mcast_pending_del_q)) {
- bfa_q_deq(&rxf->mcast_pending_del_q, &qe);
- bfa_q_qe_init(qe);
- mac = (struct bna_mac *)qe;
- rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_DEL_REQ, mac);
- bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
- return 1;
- }
-
- return 0;
-}
-
-static int
-rxf_process_packet_filter_vlan(struct bna_rxf *rxf)
-{
- /* Apply the VLAN filter */
- if (rxf->rxf_flags & BNA_RXF_FL_VLAN_CONFIG_PENDING) {
- rxf->rxf_flags &= ~BNA_RXF_FL_VLAN_CONFIG_PENDING;
- if (!(rxf->rxmode_active & BNA_RXMODE_PROMISC))
- __rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
- }
-
- /* Apply RSS configuration */
- if (rxf->rxf_flags & BNA_RXF_FL_RSS_CONFIG_PENDING) {
- rxf->rxf_flags &= ~BNA_RXF_FL_RSS_CONFIG_PENDING;
- if (rxf->rss_status == BNA_STATUS_T_DISABLED) {
- /* RSS is being disabled */
- rxf->ctrl_flags &= ~BNA_RXF_CF_RSS_ENABLE;
- __rxf_rit_set(rxf);
- __rxf_config_set(rxf);
- } else {
- /* RSS is being enabled or reconfigured */
- rxf->ctrl_flags |= BNA_RXF_CF_RSS_ENABLE;
- __rxf_rit_set(rxf);
- __rxf_config_set(rxf);
- }
- }
-
- return 0;
-}
-
-/**
- * Processes pending ucast, mcast entry addition/deletion and issues mailbox
- * command. Also processes pending filter configuration - promiscuous mode,
- * default mode, allmutli mode and issues mailbox command or directly applies
- * to h/w
- */
-static int
-rxf_process_packet_filter(struct bna_rxf *rxf)
-{
- /* Set the default MAC first */
- if (rxf->ucast_pending_set > 0) {
- rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_UCAST_SET_REQ,
- rxf->ucast_active_mac);
- rxf->ucast_pending_set--;
- return 1;
- }
-
- if (rxf_process_packet_filter_ucast(rxf))
- return 1;
-
- if (rxf_process_packet_filter_mcast(rxf))
- return 1;
-
- if (rxf_process_packet_filter_promisc(rxf))
- return 1;
-
- if (rxf_process_packet_filter_allmulti(rxf))
- return 1;
-
- if (rxf_process_packet_filter_vlan(rxf))
- return 1;
-
- return 0;
-}
-
-static int
-rxf_clear_packet_filter_mcast(struct bna_rxf *rxf)
-{
- struct bna_mac *mac = NULL;
- struct list_head *qe;
-
- /* 3. delete pending mcast entries */
- if (!list_empty(&rxf->mcast_pending_del_q)) {
- bfa_q_deq(&rxf->mcast_pending_del_q, &qe);
- bfa_q_qe_init(qe);
- mac = (struct bna_mac *)qe;
- rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_DEL_REQ, mac);
- bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
- return 1;
- }
-
- /* 4. clear active mcast entries; move them to pending_add_q */
- if (!list_empty(&rxf->mcast_active_q)) {
- bfa_q_deq(&rxf->mcast_active_q, &qe);
- bfa_q_qe_init(qe);
- mac = (struct bna_mac *)qe;
- rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_DEL_REQ, mac);
- list_add_tail(&mac->qe, &rxf->mcast_pending_add_q);
- return 1;
- }
-
- return 0;
-}
-
-/**
- * In the rxf stop path, processes pending ucast/mcast delete queue and issues
- * the mailbox command. Moves the active ucast/mcast entries to pending add q,
- * so that they are added to CAM again in the rxf start path. Moves the current
- * filter settings - promiscuous, default, allmutli - to pending filter
- * configuration
- */
-static int
-rxf_clear_packet_filter(struct bna_rxf *rxf)
-{
- if (rxf_clear_packet_filter_ucast(rxf))
- return 1;
-
- if (rxf_clear_packet_filter_mcast(rxf))
- return 1;
-
- /* 5. clear active default MAC in the CAM */
- if (rxf->ucast_pending_set > 0)
- rxf->ucast_pending_set = 0;
-
- if (rxf_clear_packet_filter_promisc(rxf))
- return 1;
-
- if (rxf_clear_packet_filter_allmulti(rxf))
- return 1;
-
- return 0;
-}
-
-static void
-rxf_reset_packet_filter_mcast(struct bna_rxf *rxf)
-{
- struct list_head *qe;
- struct bna_mac *mac;
-
- /* 3. Move active mcast entries to pending_add_q */
- while (!list_empty(&rxf->mcast_active_q)) {
- bfa_q_deq(&rxf->mcast_active_q, &qe);
- bfa_q_qe_init(qe);
- list_add_tail(qe, &rxf->mcast_pending_add_q);
- }
-
- /* 4. Throw away delete pending mcast entries */
- while (!list_empty(&rxf->mcast_pending_del_q)) {
- bfa_q_deq(&rxf->mcast_pending_del_q, &qe);
- bfa_q_qe_init(qe);
- mac = (struct bna_mac *)qe;
- bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
- }
-}
-
-/**
- * In the rxf fail path, throws away the ucast/mcast entries pending for
- * deletion, moves all active ucast/mcast entries to pending queue so that
- * they are added back to CAM in the rxf start path. Also moves the current
- * filter configuration to pending filter configuration.
- */
-static void
-rxf_reset_packet_filter(struct bna_rxf *rxf)
-{
- rxf_reset_packet_filter_ucast(rxf);
-
- rxf_reset_packet_filter_mcast(rxf);
-
- /* 5. Turn off ucast set flag */
- rxf->ucast_pending_set = 0;
-
- rxf_reset_packet_filter_promisc(rxf);
-
- rxf_reset_packet_filter_allmulti(rxf);
-}
-
-static void
-bna_rxf_init(struct bna_rxf *rxf,
- struct bna_rx *rx,
- struct bna_rx_config *q_config)
-{
- struct list_head *qe;
- struct bna_rxp *rxp;
-
- /* rxf_id is initialized during rx_mod init */
- rxf->rx = rx;
-
- INIT_LIST_HEAD(&rxf->ucast_pending_add_q);
- INIT_LIST_HEAD(&rxf->ucast_pending_del_q);
- rxf->ucast_pending_set = 0;
- INIT_LIST_HEAD(&rxf->ucast_active_q);
- rxf->ucast_active_mac = NULL;
-
- INIT_LIST_HEAD(&rxf->mcast_pending_add_q);
- INIT_LIST_HEAD(&rxf->mcast_pending_del_q);
- INIT_LIST_HEAD(&rxf->mcast_active_q);
-
- bfa_q_qe_init(&rxf->mbox_qe.qe);
-
- if (q_config->vlan_strip_status == BNA_STATUS_T_ENABLED)
- rxf->ctrl_flags |= BNA_RXF_CF_VLAN_STRIP;
-
- rxf->rxf_oper_state = (q_config->paused) ?
- BNA_RXF_OPER_STATE_PAUSED : BNA_RXF_OPER_STATE_RUNNING;
-
- bna_rxf_adv_init(rxf, rx, q_config);
-
- rxf->rit_segment = bna_rit_mod_seg_get(&rxf->rx->bna->rit_mod,
- q_config->num_paths);
-
- list_for_each(qe, &rx->rxp_q) {
- rxp = (struct bna_rxp *)qe;
- if (q_config->rxp_type == BNA_RXP_SINGLE)
- rxf->mcast_rxq_id = rxp->rxq.single.only->rxq_id;
- else
- rxf->mcast_rxq_id = rxp->rxq.slr.large->rxq_id;
- break;
- }
-
- rxf->vlan_filter_status = BNA_STATUS_T_DISABLED;
- memset(rxf->vlan_filter_table, 0,
- (sizeof(u32) * ((BFI_MAX_VLAN + 1) / 32)));
-
- /* Set up VLAN 0 for pure priority tagged packets */
- rxf->vlan_filter_table[0] |= 1;
-
- bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
-}
-
-static void
-bna_rxf_uninit(struct bna_rxf *rxf)
-{
- struct bna *bna = rxf->rx->bna;
- struct bna_mac *mac;
-
- bna_rit_mod_seg_put(&rxf->rx->bna->rit_mod, rxf->rit_segment);
- rxf->rit_segment = NULL;
-
- rxf->ucast_pending_set = 0;
-
- while (!list_empty(&rxf->ucast_pending_add_q)) {
- bfa_q_deq(&rxf->ucast_pending_add_q, &mac);
- bfa_q_qe_init(&mac->qe);
- bna_ucam_mod_mac_put(&rxf->rx->bna->ucam_mod, mac);
- }
-
- if (rxf->ucast_active_mac) {
- bfa_q_qe_init(&rxf->ucast_active_mac->qe);
- bna_ucam_mod_mac_put(&rxf->rx->bna->ucam_mod,
- rxf->ucast_active_mac);
- rxf->ucast_active_mac = NULL;
- }
-
- while (!list_empty(&rxf->mcast_pending_add_q)) {
- bfa_q_deq(&rxf->mcast_pending_add_q, &mac);
- bfa_q_qe_init(&mac->qe);
- bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
- }
-
- /* Turn off pending promisc mode */
- if (is_promisc_enable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask)) {
- /* system promisc state should be pending */
- BUG_ON(!(bna->rxf_promisc_id == rxf->rxf_id));
- promisc_inactive(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- bna->rxf_promisc_id = BFI_MAX_RXF;
- }
- /* Promisc mode should not be active */
- BUG_ON(rxf->rxmode_active & BNA_RXMODE_PROMISC);
-
- /* Turn off pending all-multi mode */
- if (is_allmulti_enable(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask)) {
- allmulti_inactive(rxf->rxmode_pending,
- rxf->rxmode_pending_bitmask);
- }
- /* Allmulti mode should not be active */
- BUG_ON(rxf->rxmode_active & BNA_RXMODE_ALLMULTI);
-
- rxf->rx = NULL;
-}
-
-static void
-bna_rx_cb_rxf_started(struct bna_rx *rx, enum bna_cb_status status)
-{
- bfa_fsm_send_event(rx, RX_E_RXF_STARTED);
- if (rx->rxf.rxf_id < 32)
- rx->bna->rx_mod.rxf_bmap[0] |= ((u32)1 << rx->rxf.rxf_id);
- else
- rx->bna->rx_mod.rxf_bmap[1] |= ((u32)
- 1 << (rx->rxf.rxf_id - 32));
-}
-
-static void
-bna_rxf_start(struct bna_rxf *rxf)
-{
- rxf->start_cbfn = bna_rx_cb_rxf_started;
- rxf->start_cbarg = rxf->rx;
- rxf->rxf_flags &= ~BNA_RXF_FL_FAILED;
- bfa_fsm_send_event(rxf, RXF_E_START);
-}
-
-static void
-bna_rx_cb_rxf_stopped(struct bna_rx *rx, enum bna_cb_status status)
-{
- bfa_fsm_send_event(rx, RX_E_RXF_STOPPED);
- if (rx->rxf.rxf_id < 32)
- rx->bna->rx_mod.rxf_bmap[0] &= ~(u32)1 << rx->rxf.rxf_id;
- else
- rx->bna->rx_mod.rxf_bmap[1] &= ~(u32)
- 1 << (rx->rxf.rxf_id - 32);
-}
-
-static void
-bna_rxf_stop(struct bna_rxf *rxf)
-{
- rxf->stop_cbfn = bna_rx_cb_rxf_stopped;
- rxf->stop_cbarg = rxf->rx;
- bfa_fsm_send_event(rxf, RXF_E_STOP);
-}
-
-static void
-bna_rxf_fail(struct bna_rxf *rxf)
-{
- rxf->rxf_flags |= BNA_RXF_FL_FAILED;
- bfa_fsm_send_event(rxf, RXF_E_FAIL);
-}
-
-int
-bna_rxf_state_get(struct bna_rxf *rxf)
-{
- return bfa_sm_to_state(rxf_sm_table, rxf->fsm);
-}
-
-enum bna_cb_status
-bna_rx_ucast_set(struct bna_rx *rx, u8 *ucmac,
- void (*cbfn)(struct bnad *, struct bna_rx *,
- enum bna_cb_status))
-{
- struct bna_rxf *rxf = &rx->rxf;
-
- if (rxf->ucast_active_mac == NULL) {
- rxf->ucast_active_mac =
- bna_ucam_mod_mac_get(&rxf->rx->bna->ucam_mod);
- if (rxf->ucast_active_mac == NULL)
- return BNA_CB_UCAST_CAM_FULL;
- bfa_q_qe_init(&rxf->ucast_active_mac->qe);
- }
-
- memcpy(rxf->ucast_active_mac->addr, ucmac, ETH_ALEN);
- rxf->ucast_pending_set++;
- rxf->cam_fltr_cbfn = cbfn;
- rxf->cam_fltr_cbarg = rx->bna->bnad;
-
- bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
-
- return BNA_CB_SUCCESS;
-}
-
-enum bna_cb_status
-bna_rx_mcast_add(struct bna_rx *rx, u8 *addr,
- void (*cbfn)(struct bnad *, struct bna_rx *,
- enum bna_cb_status))
-{
- struct bna_rxf *rxf = &rx->rxf;
- struct list_head *qe;
- struct bna_mac *mac;
-
- /* Check if already added */
- list_for_each(qe, &rxf->mcast_active_q) {
- mac = (struct bna_mac *)qe;
- if (BNA_MAC_IS_EQUAL(mac->addr, addr)) {
- if (cbfn)
- (*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
- return BNA_CB_SUCCESS;
- }
- }
-
- /* Check if pending addition */
- list_for_each(qe, &rxf->mcast_pending_add_q) {
- mac = (struct bna_mac *)qe;
- if (BNA_MAC_IS_EQUAL(mac->addr, addr)) {
- if (cbfn)
- (*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
- return BNA_CB_SUCCESS;
- }
- }
-
- mac = bna_mcam_mod_mac_get(&rxf->rx->bna->mcam_mod);
- if (mac == NULL)
- return BNA_CB_MCAST_LIST_FULL;
- bfa_q_qe_init(&mac->qe);
- memcpy(mac->addr, addr, ETH_ALEN);
- list_add_tail(&mac->qe, &rxf->mcast_pending_add_q);
-
- rxf->cam_fltr_cbfn = cbfn;
- rxf->cam_fltr_cbarg = rx->bna->bnad;
-
- bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
-
- return BNA_CB_SUCCESS;
-}
-
-enum bna_cb_status
-bna_rx_mcast_listset(struct bna_rx *rx, int count, u8 *mclist,
- void (*cbfn)(struct bnad *, struct bna_rx *,
- enum bna_cb_status))
-{
- struct bna_rxf *rxf = &rx->rxf;
- struct list_head list_head;
- struct list_head *qe;
- u8 *mcaddr;
- struct bna_mac *mac;
- struct bna_mac *mac1;
- int skip;
- int delete;
- int need_hw_config = 0;
- int i;
-
- /* Allocate nodes */
- INIT_LIST_HEAD(&list_head);
- for (i = 0, mcaddr = mclist; i < count; i++) {
- mac = bna_mcam_mod_mac_get(&rxf->rx->bna->mcam_mod);
- if (mac == NULL)
- goto err_return;
- bfa_q_qe_init(&mac->qe);
- memcpy(mac->addr, mcaddr, ETH_ALEN);
- list_add_tail(&mac->qe, &list_head);
-
- mcaddr += ETH_ALEN;
- }
-
- /* Schedule for addition */
- while (!list_empty(&list_head)) {
- bfa_q_deq(&list_head, &qe);
- mac = (struct bna_mac *)qe;
- bfa_q_qe_init(&mac->qe);
-
- skip = 0;
-
- /* Skip if already added */
- list_for_each(qe, &rxf->mcast_active_q) {
- mac1 = (struct bna_mac *)qe;
- if (BNA_MAC_IS_EQUAL(mac1->addr, mac->addr)) {
- bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod,
- mac);
- skip = 1;
- break;
- }
- }
-
- if (skip)
- continue;
-
- /* Skip if pending addition */
- list_for_each(qe, &rxf->mcast_pending_add_q) {
- mac1 = (struct bna_mac *)qe;
- if (BNA_MAC_IS_EQUAL(mac1->addr, mac->addr)) {
- bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod,
- mac);
- skip = 1;
- break;
- }
- }
-
- if (skip)
- continue;
-
- need_hw_config = 1;
- list_add_tail(&mac->qe, &rxf->mcast_pending_add_q);
- }
-
- /**
- * Delete the entries that are in the pending_add_q but not
- * in the new list
- */
- while (!list_empty(&rxf->mcast_pending_add_q)) {
- bfa_q_deq(&rxf->mcast_pending_add_q, &qe);
- mac = (struct bna_mac *)qe;
- bfa_q_qe_init(&mac->qe);
- for (i = 0, mcaddr = mclist, delete = 1; i < count; i++) {
- if (BNA_MAC_IS_EQUAL(mcaddr, mac->addr)) {
- delete = 0;
- break;
- }
- mcaddr += ETH_ALEN;
- }
- if (delete)
- bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
- else
- list_add_tail(&mac->qe, &list_head);
- }
- while (!list_empty(&list_head)) {
- bfa_q_deq(&list_head, &qe);
- mac = (struct bna_mac *)qe;
- bfa_q_qe_init(&mac->qe);
- list_add_tail(&mac->qe, &rxf->mcast_pending_add_q);
- }
-
- /**
- * Schedule entries for deletion that are in the active_q but not
- * in the new list
- */
- while (!list_empty(&rxf->mcast_active_q)) {
- bfa_q_deq(&rxf->mcast_active_q, &qe);
- mac = (struct bna_mac *)qe;
- bfa_q_qe_init(&mac->qe);
- for (i = 0, mcaddr = mclist, delete = 1; i < count; i++) {
- if (BNA_MAC_IS_EQUAL(mcaddr, mac->addr)) {
- delete = 0;
- break;
- }
- mcaddr += ETH_ALEN;
- }
- if (delete) {
- list_add_tail(&mac->qe, &rxf->mcast_pending_del_q);
- need_hw_config = 1;
- } else {
- list_add_tail(&mac->qe, &list_head);
- }
- }
- while (!list_empty(&list_head)) {
- bfa_q_deq(&list_head, &qe);
- mac = (struct bna_mac *)qe;
- bfa_q_qe_init(&mac->qe);
- list_add_tail(&mac->qe, &rxf->mcast_active_q);
- }
-
- if (need_hw_config) {
- rxf->cam_fltr_cbfn = cbfn;
- rxf->cam_fltr_cbarg = rx->bna->bnad;
- bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
- } else if (cbfn)
- (*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
-
- return BNA_CB_SUCCESS;
-
-err_return:
- while (!list_empty(&list_head)) {
- bfa_q_deq(&list_head, &qe);
- mac = (struct bna_mac *)qe;
- bfa_q_qe_init(&mac->qe);
- bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
- }
-
- return BNA_CB_MCAST_LIST_FULL;
-}
-
-void
-bna_rx_vlan_add(struct bna_rx *rx, int vlan_id)
-{
- struct bna_rxf *rxf = &rx->rxf;
- int index = (vlan_id >> 5);
- int bit = (1 << (vlan_id & 0x1F));
-
- rxf->vlan_filter_table[index] |= bit;
- if (rxf->vlan_filter_status == BNA_STATUS_T_ENABLED) {
- rxf->rxf_flags |= BNA_RXF_FL_VLAN_CONFIG_PENDING;
- bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
- }
-}
-
-void
-bna_rx_vlan_del(struct bna_rx *rx, int vlan_id)
-{
- struct bna_rxf *rxf = &rx->rxf;
- int index = (vlan_id >> 5);
- int bit = (1 << (vlan_id & 0x1F));
-
- rxf->vlan_filter_table[index] &= ~bit;
- if (rxf->vlan_filter_status == BNA_STATUS_T_ENABLED) {
- rxf->rxf_flags |= BNA_RXF_FL_VLAN_CONFIG_PENDING;
- bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
- }
-}
-
-/**
- * RX
- */
-#define RXQ_RCB_INIT(q, rxp, qdepth, bna, _id, unmapq_mem) do { \
- struct bna_doorbell_qset *_qset; \
- unsigned long off; \
- (q)->rcb->producer_index = (q)->rcb->consumer_index = 0; \
- (q)->rcb->q_depth = (qdepth); \
- (q)->rcb->unmap_q = unmapq_mem; \
- (q)->rcb->rxq = (q); \
- (q)->rcb->cq = &(rxp)->cq; \
- (q)->rcb->bnad = (bna)->bnad; \
- _qset = (struct bna_doorbell_qset *)0; \
- off = (unsigned long)&_qset[(q)->rxq_id].rxq[0]; \
- (q)->rcb->q_dbell = off + \
- BNA_GET_DOORBELL_BASE_ADDR((bna)->pcidev.pci_bar_kva); \
- (q)->rcb->id = _id; \
-} while (0)
-
-#define BNA_GET_RXQS(qcfg) (((qcfg)->rxp_type == BNA_RXP_SINGLE) ? \
- (qcfg)->num_paths : ((qcfg)->num_paths * 2))
-
-#define SIZE_TO_PAGES(size) (((size) >> PAGE_SHIFT) + ((((size) &\
- (PAGE_SIZE - 1)) + (PAGE_SIZE - 1)) >> PAGE_SHIFT))
-
-#define call_rx_stop_callback(rx, status) \
- if ((rx)->stop_cbfn) { \
- (*(rx)->stop_cbfn)((rx)->stop_cbarg, rx, (status)); \
- (rx)->stop_cbfn = NULL; \
- (rx)->stop_cbarg = NULL; \
- }
-
-/*
- * Since rx_enable is synchronous callback, there is no start_cbfn required.
- * Instead, we'll call bnad_rx_post(rxp) so that bnad can post the buffers
- * for each rxpath.
- */
-
-#define call_rx_disable_cbfn(rx, status) \
- if ((rx)->disable_cbfn) { \
- (*(rx)->disable_cbfn)((rx)->disable_cbarg, \
- status); \
- (rx)->disable_cbfn = NULL; \
- (rx)->disable_cbarg = NULL; \
- } \
-
-#define rxqs_reqd(type, num_rxqs) \
- (((type) == BNA_RXP_SINGLE) ? (num_rxqs) : ((num_rxqs) * 2))
-
-#define rx_ib_fail(rx) \
-do { \
- struct bna_rxp *rxp; \
- struct list_head *qe; \
- list_for_each(qe, &(rx)->rxp_q) { \
- rxp = (struct bna_rxp *)qe; \
- bna_ib_fail(rxp->cq.ib); \
- } \
-} while (0)
-
-static void __bna_multi_rxq_stop(struct bna_rxp *, u32 *);
-static void __bna_rxq_start(struct bna_rxq *rxq);
-static void __bna_cq_start(struct bna_cq *cq);
-static void bna_rit_create(struct bna_rx *rx);
-static void bna_rx_cb_multi_rxq_stopped(void *arg, int status);
-static void bna_rx_cb_rxq_stopped_all(void *arg);
-
-bfa_fsm_state_decl(bna_rx, stopped,
- struct bna_rx, enum bna_rx_event);
-bfa_fsm_state_decl(bna_rx, rxf_start_wait,
- struct bna_rx, enum bna_rx_event);
-bfa_fsm_state_decl(bna_rx, started,
- struct bna_rx, enum bna_rx_event);
-bfa_fsm_state_decl(bna_rx, rxf_stop_wait,
- struct bna_rx, enum bna_rx_event);
-bfa_fsm_state_decl(bna_rx, rxq_stop_wait,
- struct bna_rx, enum bna_rx_event);
-
-static const struct bfa_sm_table rx_sm_table[] = {
- {BFA_SM(bna_rx_sm_stopped), BNA_RX_STOPPED},
- {BFA_SM(bna_rx_sm_rxf_start_wait), BNA_RX_RXF_START_WAIT},
- {BFA_SM(bna_rx_sm_started), BNA_RX_STARTED},
- {BFA_SM(bna_rx_sm_rxf_stop_wait), BNA_RX_RXF_STOP_WAIT},
- {BFA_SM(bna_rx_sm_rxq_stop_wait), BNA_RX_RXQ_STOP_WAIT},
-};
-
-static void bna_rx_sm_stopped_entry(struct bna_rx *rx)
-{
- struct bna_rxp *rxp;
- struct list_head *qe_rxp;
-
- list_for_each(qe_rxp, &rx->rxp_q) {
- rxp = (struct bna_rxp *)qe_rxp;
- rx->rx_cleanup_cbfn(rx->bna->bnad, rxp->cq.ccb);
- }
-
- call_rx_stop_callback(rx, BNA_CB_SUCCESS);
-}
-
-static void bna_rx_sm_stopped(struct bna_rx *rx,
- enum bna_rx_event event)
-{
- switch (event) {
- case RX_E_START:
- bfa_fsm_set_state(rx, bna_rx_sm_rxf_start_wait);
- break;
- case RX_E_STOP:
- call_rx_stop_callback(rx, BNA_CB_SUCCESS);
- break;
- case RX_E_FAIL:
- /* no-op */
- break;
- default:
- bfa_sm_fault(event);
- break;
- }
-
-}
-
-static void bna_rx_sm_rxf_start_wait_entry(struct bna_rx *rx)
-{
- struct bna_rxp *rxp;
- struct list_head *qe_rxp;
- struct bna_rxq *q0 = NULL, *q1 = NULL;
-
- /* Setup the RIT */
- bna_rit_create(rx);
-
- list_for_each(qe_rxp, &rx->rxp_q) {
- rxp = (struct bna_rxp *)qe_rxp;
- bna_ib_start(rxp->cq.ib);
- GET_RXQS(rxp, q0, q1);
- q0->buffer_size = bna_port_mtu_get(&rx->bna->port);
- __bna_rxq_start(q0);
- rx->rx_post_cbfn(rx->bna->bnad, q0->rcb);
- if (q1) {
- __bna_rxq_start(q1);
- rx->rx_post_cbfn(rx->bna->bnad, q1->rcb);
- }
- __bna_cq_start(&rxp->cq);
- }
-
- bna_rxf_start(&rx->rxf);
-}
-
-static void bna_rx_sm_rxf_start_wait(struct bna_rx *rx,
- enum bna_rx_event event)
-{
- switch (event) {
- case RX_E_STOP:
- bfa_fsm_set_state(rx, bna_rx_sm_rxf_stop_wait);
- break;
- case RX_E_FAIL:
- bfa_fsm_set_state(rx, bna_rx_sm_stopped);
- rx_ib_fail(rx);
- bna_rxf_fail(&rx->rxf);
- break;
- case RX_E_RXF_STARTED:
- bfa_fsm_set_state(rx, bna_rx_sm_started);
- break;
- default:
- bfa_sm_fault(event);
- break;
- }
-}
-
-void
-bna_rx_sm_started_entry(struct bna_rx *rx)
-{
- struct bna_rxp *rxp;
- struct list_head *qe_rxp;
-
- /* Start IB */
- list_for_each(qe_rxp, &rx->rxp_q) {
- rxp = (struct bna_rxp *)qe_rxp;
- bna_ib_ack(&rxp->cq.ib->door_bell, 0);
- }
-
- bna_llport_rx_started(&rx->bna->port.llport);
-}
-
-void
-bna_rx_sm_started(struct bna_rx *rx, enum bna_rx_event event)
-{
- switch (event) {
- case RX_E_FAIL:
- bna_llport_rx_stopped(&rx->bna->port.llport);
- bfa_fsm_set_state(rx, bna_rx_sm_stopped);
- rx_ib_fail(rx);
- bna_rxf_fail(&rx->rxf);
- break;
- case RX_E_STOP:
- bna_llport_rx_stopped(&rx->bna->port.llport);
- bfa_fsm_set_state(rx, bna_rx_sm_rxf_stop_wait);
- break;
- default:
- bfa_sm_fault(event);
- break;
- }
-}
-
-void
-bna_rx_sm_rxf_stop_wait_entry(struct bna_rx *rx)
-{
- bna_rxf_stop(&rx->rxf);
-}
-
-void
-bna_rx_sm_rxf_stop_wait(struct bna_rx *rx, enum bna_rx_event event)
-{
- switch (event) {
- case RX_E_RXF_STOPPED:
- bfa_fsm_set_state(rx, bna_rx_sm_rxq_stop_wait);
- break;
- case RX_E_RXF_STARTED:
- /**
- * RxF was in the process of starting up when
- * RXF_E_STOP was issued. Ignore this event
- */
- break;
- case RX_E_FAIL:
- bfa_fsm_set_state(rx, bna_rx_sm_stopped);
- rx_ib_fail(rx);
- bna_rxf_fail(&rx->rxf);
- break;
- default:
- bfa_sm_fault(event);
- break;
- }
-
-}
-
-void
-bna_rx_sm_rxq_stop_wait_entry(struct bna_rx *rx)
-{
- struct bna_rxp *rxp = NULL;
- struct bna_rxq *q0 = NULL;
- struct bna_rxq *q1 = NULL;
- struct list_head *qe;
- u32 rxq_mask[2] = {0, 0};
-
- /* Only one call to multi-rxq-stop for all RXPs in this RX */
- bfa_wc_up(&rx->rxq_stop_wc);
- list_for_each(qe, &rx->rxp_q) {
- rxp = (struct bna_rxp *)qe;
- GET_RXQS(rxp, q0, q1);
- if (q0->rxq_id < 32)
- rxq_mask[0] |= ((u32)1 << q0->rxq_id);
- else
- rxq_mask[1] |= ((u32)1 << (q0->rxq_id - 32));
- if (q1) {
- if (q1->rxq_id < 32)
- rxq_mask[0] |= ((u32)1 << q1->rxq_id);
- else
- rxq_mask[1] |= ((u32)
- 1 << (q1->rxq_id - 32));
- }
- }
-
- __bna_multi_rxq_stop(rxp, rxq_mask);
-}
-
-void
-bna_rx_sm_rxq_stop_wait(struct bna_rx *rx, enum bna_rx_event event)
-{
- struct bna_rxp *rxp = NULL;
- struct list_head *qe;
-
- switch (event) {
- case RX_E_RXQ_STOPPED:
- list_for_each(qe, &rx->rxp_q) {
- rxp = (struct bna_rxp *)qe;
- bna_ib_stop(rxp->cq.ib);
- }
- /* Fall through */
- case RX_E_FAIL:
- bfa_fsm_set_state(rx, bna_rx_sm_stopped);
- break;
- default:
- bfa_sm_fault(event);
- break;
- }
-}
-
-void
-__bna_multi_rxq_stop(struct bna_rxp *rxp, u32 * rxq_id_mask)
-{
- struct bfi_ll_q_stop_req ll_req;
-
- bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_RXQ_STOP_REQ, 0);
- ll_req.q_id_mask[0] = htonl(rxq_id_mask[0]);
- ll_req.q_id_mask[1] = htonl(rxq_id_mask[1]);
- bna_mbox_qe_fill(&rxp->mbox_qe, &ll_req, sizeof(ll_req),
- bna_rx_cb_multi_rxq_stopped, rxp);
- bna_mbox_send(rxp->rx->bna, &rxp->mbox_qe);
-}
-
-void
-__bna_rxq_start(struct bna_rxq *rxq)
-{
- struct bna_rxtx_q_mem *q_mem;
- struct bna_rxq_mem rxq_cfg, *rxq_mem;
- struct bna_dma_addr cur_q_addr;
- /* struct bna_doorbell_qset *qset; */
- struct bna_qpt *qpt;
- u32 pg_num;
- struct bna *bna = rxq->rx->bna;
- void __iomem *base_addr;
- unsigned long off;
-
- qpt = &rxq->qpt;
- cur_q_addr = *((struct bna_dma_addr *)(qpt->kv_qpt_ptr));
-
- rxq_cfg.pg_tbl_addr_lo = qpt->hw_qpt_ptr.lsb;
- rxq_cfg.pg_tbl_addr_hi = qpt->hw_qpt_ptr.msb;
- rxq_cfg.cur_q_entry_lo = cur_q_addr.lsb;
- rxq_cfg.cur_q_entry_hi = cur_q_addr.msb;
-
- rxq_cfg.pg_cnt_n_prd_ptr = ((u32)qpt->page_count << 16) | 0x0;
- rxq_cfg.entry_n_pg_size = ((u32)(BFI_RXQ_WI_SIZE >> 2) << 16) |
- (qpt->page_size >> 2);
- rxq_cfg.sg_n_cq_n_cns_ptr =
- ((u32)(rxq->rxp->cq.cq_id & 0xff) << 16) | 0x0;
- rxq_cfg.buf_sz_n_q_state = ((u32)rxq->buffer_size << 16) |
- BNA_Q_IDLE_STATE;
- rxq_cfg.next_qid = 0x0 | (0x3 << 8);
-
- /* Write the page number register */
- pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + bna->port_num,
- HQM_RXTX_Q_RAM_BASE_OFFSET);
- writel(pg_num, bna->regs.page_addr);
-
- /* Write to h/w */
- base_addr = BNA_GET_MEM_BASE_ADDR(bna->pcidev.pci_bar_kva,
- HQM_RXTX_Q_RAM_BASE_OFFSET);
-
- q_mem = (struct bna_rxtx_q_mem *)0;
- rxq_mem = &q_mem[rxq->rxq_id].rxq;
-
- off = (unsigned long)&rxq_mem->pg_tbl_addr_lo;
- writel(htonl(rxq_cfg.pg_tbl_addr_lo), base_addr + off);
-
- off = (unsigned long)&rxq_mem->pg_tbl_addr_hi;
- writel(htonl(rxq_cfg.pg_tbl_addr_hi), base_addr + off);
-
- off = (unsigned long)&rxq_mem->cur_q_entry_lo;
- writel(htonl(rxq_cfg.cur_q_entry_lo), base_addr + off);
-
- off = (unsigned long)&rxq_mem->cur_q_entry_hi;
- writel(htonl(rxq_cfg.cur_q_entry_hi), base_addr + off);
-
- off = (unsigned long)&rxq_mem->pg_cnt_n_prd_ptr;
- writel(rxq_cfg.pg_cnt_n_prd_ptr, base_addr + off);
-
- off = (unsigned long)&rxq_mem->entry_n_pg_size;
- writel(rxq_cfg.entry_n_pg_size, base_addr + off);
-
- off = (unsigned long)&rxq_mem->sg_n_cq_n_cns_ptr;
- writel(rxq_cfg.sg_n_cq_n_cns_ptr, base_addr + off);
-
- off = (unsigned long)&rxq_mem->buf_sz_n_q_state;
- writel(rxq_cfg.buf_sz_n_q_state, base_addr + off);
-
- off = (unsigned long)&rxq_mem->next_qid;
- writel(rxq_cfg.next_qid, base_addr + off);
-
- rxq->rcb->producer_index = 0;
- rxq->rcb->consumer_index = 0;
-}
-
-void
-__bna_cq_start(struct bna_cq *cq)
-{
- struct bna_cq_mem cq_cfg, *cq_mem;
- const struct bna_qpt *qpt;
- struct bna_dma_addr cur_q_addr;
- u32 pg_num;
- struct bna *bna = cq->rx->bna;
- void __iomem *base_addr;
- unsigned long off;
-
- qpt = &cq->qpt;
- cur_q_addr = *((struct bna_dma_addr *)(qpt->kv_qpt_ptr));
-
- /*
- * Fill out structure, to be subsequently written
- * to hardware
- */
- cq_cfg.pg_tbl_addr_lo = qpt->hw_qpt_ptr.lsb;
- cq_cfg.pg_tbl_addr_hi = qpt->hw_qpt_ptr.msb;
- cq_cfg.cur_q_entry_lo = cur_q_addr.lsb;
- cq_cfg.cur_q_entry_hi = cur_q_addr.msb;
-
- cq_cfg.pg_cnt_n_prd_ptr = (qpt->page_count << 16) | 0x0;
- cq_cfg.entry_n_pg_size =
- ((u32)(BFI_CQ_WI_SIZE >> 2) << 16) | (qpt->page_size >> 2);
- cq_cfg.int_blk_n_cns_ptr = ((((u32)cq->ib_seg_offset) << 24) |
- ((u32)(cq->ib->ib_id & 0xff) << 16) | 0x0);
- cq_cfg.q_state = BNA_Q_IDLE_STATE;
-
- /* Write the page number register */
- pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + bna->port_num,
- HQM_CQ_RAM_BASE_OFFSET);
-
- writel(pg_num, bna->regs.page_addr);
-
- /* H/W write */
- base_addr = BNA_GET_MEM_BASE_ADDR(bna->pcidev.pci_bar_kva,
- HQM_CQ_RAM_BASE_OFFSET);
-
- cq_mem = (struct bna_cq_mem *)0;
-
- off = (unsigned long)&cq_mem[cq->cq_id].pg_tbl_addr_lo;
- writel(htonl(cq_cfg.pg_tbl_addr_lo), base_addr + off);
-
- off = (unsigned long)&cq_mem[cq->cq_id].pg_tbl_addr_hi;
- writel(htonl(cq_cfg.pg_tbl_addr_hi), base_addr + off);
-
- off = (unsigned long)&cq_mem[cq->cq_id].cur_q_entry_lo;
- writel(htonl(cq_cfg.cur_q_entry_lo), base_addr + off);
-
- off = (unsigned long)&cq_mem[cq->cq_id].cur_q_entry_hi;
- writel(htonl(cq_cfg.cur_q_entry_hi), base_addr + off);
-
- off = (unsigned long)&cq_mem[cq->cq_id].pg_cnt_n_prd_ptr;
- writel(cq_cfg.pg_cnt_n_prd_ptr, base_addr + off);
-
- off = (unsigned long)&cq_mem[cq->cq_id].entry_n_pg_size;
- writel(cq_cfg.entry_n_pg_size, base_addr + off);
-
- off = (unsigned long)&cq_mem[cq->cq_id].int_blk_n_cns_ptr;
- writel(cq_cfg.int_blk_n_cns_ptr, base_addr + off);
-
- off = (unsigned long)&cq_mem[cq->cq_id].q_state;
- writel(cq_cfg.q_state, base_addr + off);
-
- cq->ccb->producer_index = 0;
- *(cq->ccb->hw_producer_index) = 0;
-}
-
-void
-bna_rit_create(struct bna_rx *rx)
-{
- struct list_head *qe_rxp;
- struct bna_rxp *rxp;
- struct bna_rxq *q0 = NULL;
- struct bna_rxq *q1 = NULL;
- int offset;
-
- offset = 0;
- list_for_each(qe_rxp, &rx->rxp_q) {
- rxp = (struct bna_rxp *)qe_rxp;
- GET_RXQS(rxp, q0, q1);
- rx->rxf.rit_segment->rit[offset].large_rxq_id = q0->rxq_id;
- rx->rxf.rit_segment->rit[offset].small_rxq_id =
- (q1 ? q1->rxq_id : 0);
- offset++;
- }
-}
-
-static int
-_rx_can_satisfy(struct bna_rx_mod *rx_mod,
- struct bna_rx_config *rx_cfg)
-{
- if ((rx_mod->rx_free_count == 0) ||
- (rx_mod->rxp_free_count == 0) ||
- (rx_mod->rxq_free_count == 0))
- return 0;
-
- if (rx_cfg->rxp_type == BNA_RXP_SINGLE) {
- if ((rx_mod->rxp_free_count < rx_cfg->num_paths) ||
- (rx_mod->rxq_free_count < rx_cfg->num_paths))
- return 0;
- } else {
- if ((rx_mod->rxp_free_count < rx_cfg->num_paths) ||
- (rx_mod->rxq_free_count < (2 * rx_cfg->num_paths)))
- return 0;
- }
-
- if (!bna_rit_mod_can_satisfy(&rx_mod->bna->rit_mod, rx_cfg->num_paths))
- return 0;
-
- return 1;
-}
-
-static struct bna_rxq *
-_get_free_rxq(struct bna_rx_mod *rx_mod)
-{
- struct bna_rxq *rxq = NULL;
- struct list_head *qe = NULL;
-
- bfa_q_deq(&rx_mod->rxq_free_q, &qe);
- if (qe) {
- rx_mod->rxq_free_count--;
- rxq = (struct bna_rxq *)qe;
- }
- return rxq;
-}
-
-static void
-_put_free_rxq(struct bna_rx_mod *rx_mod, struct bna_rxq *rxq)
-{
- bfa_q_qe_init(&rxq->qe);
- list_add_tail(&rxq->qe, &rx_mod->rxq_free_q);
- rx_mod->rxq_free_count++;
-}
-
-static struct bna_rxp *
-_get_free_rxp(struct bna_rx_mod *rx_mod)
-{
- struct list_head *qe = NULL;
- struct bna_rxp *rxp = NULL;
-
- bfa_q_deq(&rx_mod->rxp_free_q, &qe);
- if (qe) {
- rx_mod->rxp_free_count--;
-
- rxp = (struct bna_rxp *)qe;
- }
-
- return rxp;
-}
-
-static void
-_put_free_rxp(struct bna_rx_mod *rx_mod, struct bna_rxp *rxp)
-{
- bfa_q_qe_init(&rxp->qe);
- list_add_tail(&rxp->qe, &rx_mod->rxp_free_q);
- rx_mod->rxp_free_count++;
-}
-
-static struct bna_rx *
-_get_free_rx(struct bna_rx_mod *rx_mod)
-{
- struct list_head *qe = NULL;
- struct bna_rx *rx = NULL;
-
- bfa_q_deq(&rx_mod->rx_free_q, &qe);
- if (qe) {
- rx_mod->rx_free_count--;
-
- rx = (struct bna_rx *)qe;
- bfa_q_qe_init(qe);
- list_add_tail(&rx->qe, &rx_mod->rx_active_q);
- }
-
- return rx;
-}
-
-static void
-_put_free_rx(struct bna_rx_mod *rx_mod, struct bna_rx *rx)
-{
- bfa_q_qe_init(&rx->qe);
- list_add_tail(&rx->qe, &rx_mod->rx_free_q);
- rx_mod->rx_free_count++;
-}
-
-static void
-_rx_init(struct bna_rx *rx, struct bna *bna)
-{
- rx->bna = bna;
- rx->rx_flags = 0;
-
- INIT_LIST_HEAD(&rx->rxp_q);
-
- rx->rxq_stop_wc.wc_resume = bna_rx_cb_rxq_stopped_all;
- rx->rxq_stop_wc.wc_cbarg = rx;
- rx->rxq_stop_wc.wc_count = 0;
-
- rx->stop_cbfn = NULL;
- rx->stop_cbarg = NULL;
-}
-
-static void
-_rxp_add_rxqs(struct bna_rxp *rxp,
- struct bna_rxq *q0,
- struct bna_rxq *q1)
-{
- switch (rxp->type) {
- case BNA_RXP_SINGLE:
- rxp->rxq.single.only = q0;
- rxp->rxq.single.reserved = NULL;
- break;
- case BNA_RXP_SLR:
- rxp->rxq.slr.large = q0;
- rxp->rxq.slr.small = q1;
- break;
- case BNA_RXP_HDS:
- rxp->rxq.hds.data = q0;
- rxp->rxq.hds.hdr = q1;
- break;
- default:
- break;
- }
-}
-
-static void
-_rxq_qpt_init(struct bna_rxq *rxq,
- struct bna_rxp *rxp,
- u32 page_count,
- u32 page_size,
- struct bna_mem_descr *qpt_mem,
- struct bna_mem_descr *swqpt_mem,
- struct bna_mem_descr *page_mem)
-{
- int i;
-
- rxq->qpt.hw_qpt_ptr.lsb = qpt_mem->dma.lsb;
- rxq->qpt.hw_qpt_ptr.msb = qpt_mem->dma.msb;
- rxq->qpt.kv_qpt_ptr = qpt_mem->kva;
- rxq->qpt.page_count = page_count;
- rxq->qpt.page_size = page_size;
-
- rxq->rcb->sw_qpt = (void **) swqpt_mem->kva;
-
- for (i = 0; i < rxq->qpt.page_count; i++) {
- rxq->rcb->sw_qpt[i] = page_mem[i].kva;
- ((struct bna_dma_addr *)rxq->qpt.kv_qpt_ptr)[i].lsb =
- page_mem[i].dma.lsb;
- ((struct bna_dma_addr *)rxq->qpt.kv_qpt_ptr)[i].msb =
- page_mem[i].dma.msb;
-
- }
-}
-
-static void
-_rxp_cqpt_setup(struct bna_rxp *rxp,
- u32 page_count,
- u32 page_size,
- struct bna_mem_descr *qpt_mem,
- struct bna_mem_descr *swqpt_mem,
- struct bna_mem_descr *page_mem)
-{
- int i;
-
- rxp->cq.qpt.hw_qpt_ptr.lsb = qpt_mem->dma.lsb;
- rxp->cq.qpt.hw_qpt_ptr.msb = qpt_mem->dma.msb;
- rxp->cq.qpt.kv_qpt_ptr = qpt_mem->kva;
- rxp->cq.qpt.page_count = page_count;
- rxp->cq.qpt.page_size = page_size;
-
- rxp->cq.ccb->sw_qpt = (void **) swqpt_mem->kva;
-
- for (i = 0; i < rxp->cq.qpt.page_count; i++) {
- rxp->cq.ccb->sw_qpt[i] = page_mem[i].kva;
-
- ((struct bna_dma_addr *)rxp->cq.qpt.kv_qpt_ptr)[i].lsb =
- page_mem[i].dma.lsb;
- ((struct bna_dma_addr *)rxp->cq.qpt.kv_qpt_ptr)[i].msb =
- page_mem[i].dma.msb;
-
- }
-}
-
-static void
-_rx_add_rxp(struct bna_rx *rx, struct bna_rxp *rxp)
-{
- list_add_tail(&rxp->qe, &rx->rxp_q);
-}
-
-static void
-_init_rxmod_queues(struct bna_rx_mod *rx_mod)
-{
- INIT_LIST_HEAD(&rx_mod->rx_free_q);
- INIT_LIST_HEAD(&rx_mod->rxq_free_q);
- INIT_LIST_HEAD(&rx_mod->rxp_free_q);
- INIT_LIST_HEAD(&rx_mod->rx_active_q);
-
- rx_mod->rx_free_count = 0;
- rx_mod->rxq_free_count = 0;
- rx_mod->rxp_free_count = 0;
-}
-
-static void
-_rx_ctor(struct bna_rx *rx, int id)
-{
- bfa_q_qe_init(&rx->qe);
- INIT_LIST_HEAD(&rx->rxp_q);
- rx->bna = NULL;
-
- rx->rxf.rxf_id = id;
-
- /* FIXME: mbox_qe ctor()?? */
- bfa_q_qe_init(&rx->mbox_qe.qe);
-
- rx->stop_cbfn = NULL;
- rx->stop_cbarg = NULL;
-}
-
-void
-bna_rx_cb_multi_rxq_stopped(void *arg, int status)
-{
- struct bna_rxp *rxp = (struct bna_rxp *)arg;
-
- bfa_wc_down(&rxp->rx->rxq_stop_wc);
-}
-
-void
-bna_rx_cb_rxq_stopped_all(void *arg)
-{
- struct bna_rx *rx = (struct bna_rx *)arg;
-
- bfa_fsm_send_event(rx, RX_E_RXQ_STOPPED);
-}
-
-static void
-bna_rx_mod_cb_rx_stopped(void *arg, struct bna_rx *rx,
- enum bna_cb_status status)
-{
- struct bna_rx_mod *rx_mod = (struct bna_rx_mod *)arg;
-
- bfa_wc_down(&rx_mod->rx_stop_wc);
-}
-
-static void
-bna_rx_mod_cb_rx_stopped_all(void *arg)
-{
- struct bna_rx_mod *rx_mod = (struct bna_rx_mod *)arg;
-
- if (rx_mod->stop_cbfn)
- rx_mod->stop_cbfn(&rx_mod->bna->port, BNA_CB_SUCCESS);
- rx_mod->stop_cbfn = NULL;
-}
-
-static void
-bna_rx_start(struct bna_rx *rx)
-{
- rx->rx_flags |= BNA_RX_F_PORT_ENABLED;
- if (rx->rx_flags & BNA_RX_F_ENABLE)
- bfa_fsm_send_event(rx, RX_E_START);
-}
-
-static void
-bna_rx_stop(struct bna_rx *rx)
-{
- rx->rx_flags &= ~BNA_RX_F_PORT_ENABLED;
- if (rx->fsm == (bfa_fsm_t) bna_rx_sm_stopped)
- bna_rx_mod_cb_rx_stopped(&rx->bna->rx_mod, rx, BNA_CB_SUCCESS);
- else {
- rx->stop_cbfn = bna_rx_mod_cb_rx_stopped;
- rx->stop_cbarg = &rx->bna->rx_mod;
- bfa_fsm_send_event(rx, RX_E_STOP);
- }
-}
-
-static void
-bna_rx_fail(struct bna_rx *rx)
-{
- /* Indicate port is not enabled, and failed */
- rx->rx_flags &= ~BNA_RX_F_PORT_ENABLED;
- rx->rx_flags |= BNA_RX_F_PORT_FAILED;
- bfa_fsm_send_event(rx, RX_E_FAIL);
-}
-
-void
-bna_rx_mod_start(struct bna_rx_mod *rx_mod, enum bna_rx_type type)
-{
- struct bna_rx *rx;
- struct list_head *qe;
-
- rx_mod->flags |= BNA_RX_MOD_F_PORT_STARTED;
- if (type == BNA_RX_T_LOOPBACK)
- rx_mod->flags |= BNA_RX_MOD_F_PORT_LOOPBACK;
-
- list_for_each(qe, &rx_mod->rx_active_q) {
- rx = (struct bna_rx *)qe;
- if (rx->type == type)
- bna_rx_start(rx);
- }
-}
-
-void
-bna_rx_mod_stop(struct bna_rx_mod *rx_mod, enum bna_rx_type type)
-{
- struct bna_rx *rx;
- struct list_head *qe;
-
- rx_mod->flags &= ~BNA_RX_MOD_F_PORT_STARTED;
- rx_mod->flags &= ~BNA_RX_MOD_F_PORT_LOOPBACK;
-
- rx_mod->stop_cbfn = bna_port_cb_rx_stopped;
-
- /**
- * Before calling bna_rx_stop(), increment rx_stop_wc as many times
- * as we are going to call bna_rx_stop
- */
- list_for_each(qe, &rx_mod->rx_active_q) {
- rx = (struct bna_rx *)qe;
- if (rx->type == type)
- bfa_wc_up(&rx_mod->rx_stop_wc);
- }
-
- if (rx_mod->rx_stop_wc.wc_count == 0) {
- rx_mod->stop_cbfn(&rx_mod->bna->port, BNA_CB_SUCCESS);
- rx_mod->stop_cbfn = NULL;
- return;
- }
-
- list_for_each(qe, &rx_mod->rx_active_q) {
- rx = (struct bna_rx *)qe;
- if (rx->type == type)
- bna_rx_stop(rx);
- }
-}
-
-void
-bna_rx_mod_fail(struct bna_rx_mod *rx_mod)
-{
- struct bna_rx *rx;
- struct list_head *qe;
-
- rx_mod->flags &= ~BNA_RX_MOD_F_PORT_STARTED;
- rx_mod->flags &= ~BNA_RX_MOD_F_PORT_LOOPBACK;
-
- list_for_each(qe, &rx_mod->rx_active_q) {
- rx = (struct bna_rx *)qe;
- bna_rx_fail(rx);
- }
-}
-
-void bna_rx_mod_init(struct bna_rx_mod *rx_mod, struct bna *bna,
- struct bna_res_info *res_info)
-{
- int index;
- struct bna_rx *rx_ptr;
- struct bna_rxp *rxp_ptr;
- struct bna_rxq *rxq_ptr;
-
- rx_mod->bna = bna;
- rx_mod->flags = 0;
-
- rx_mod->rx = (struct bna_rx *)
- res_info[BNA_RES_MEM_T_RX_ARRAY].res_u.mem_info.mdl[0].kva;
- rx_mod->rxp = (struct bna_rxp *)
- res_info[BNA_RES_MEM_T_RXP_ARRAY].res_u.mem_info.mdl[0].kva;
- rx_mod->rxq = (struct bna_rxq *)
- res_info[BNA_RES_MEM_T_RXQ_ARRAY].res_u.mem_info.mdl[0].kva;
-
- /* Initialize the queues */
- _init_rxmod_queues(rx_mod);
-
- /* Build RX queues */
- for (index = 0; index < BFI_MAX_RXQ; index++) {
- rx_ptr = &rx_mod->rx[index];
- _rx_ctor(rx_ptr, index);
- list_add_tail(&rx_ptr->qe, &rx_mod->rx_free_q);
- rx_mod->rx_free_count++;
- }
-
- /* build RX-path queue */
- for (index = 0; index < BFI_MAX_RXQ; index++) {
- rxp_ptr = &rx_mod->rxp[index];
- rxp_ptr->cq.cq_id = index;
- bfa_q_qe_init(&rxp_ptr->qe);
- list_add_tail(&rxp_ptr->qe, &rx_mod->rxp_free_q);
- rx_mod->rxp_free_count++;
- }
-
- /* build RXQ queue */
- for (index = 0; index < BFI_MAX_RXQ; index++) {
- rxq_ptr = &rx_mod->rxq[index];
- rxq_ptr->rxq_id = index;
-
- bfa_q_qe_init(&rxq_ptr->qe);
- list_add_tail(&rxq_ptr->qe, &rx_mod->rxq_free_q);
- rx_mod->rxq_free_count++;
- }
-
- rx_mod->rx_stop_wc.wc_resume = bna_rx_mod_cb_rx_stopped_all;
- rx_mod->rx_stop_wc.wc_cbarg = rx_mod;
- rx_mod->rx_stop_wc.wc_count = 0;
-}
-
-void
-bna_rx_mod_uninit(struct bna_rx_mod *rx_mod)
-{
- struct list_head *qe;
- int i;
-
- i = 0;
- list_for_each(qe, &rx_mod->rx_free_q)
- i++;
-
- i = 0;
- list_for_each(qe, &rx_mod->rxp_free_q)
- i++;
-
- i = 0;
- list_for_each(qe, &rx_mod->rxq_free_q)
- i++;
-
- rx_mod->bna = NULL;
-}
-
-int
-bna_rx_state_get(struct bna_rx *rx)
-{
- return bfa_sm_to_state(rx_sm_table, rx->fsm);
-}
-
-void
-bna_rx_res_req(struct bna_rx_config *q_cfg, struct bna_res_info *res_info)
-{
- u32 cq_size, hq_size, dq_size;
- u32 cpage_count, hpage_count, dpage_count;
- struct bna_mem_info *mem_info;
- u32 cq_depth;
- u32 hq_depth;
- u32 dq_depth;
-
- dq_depth = q_cfg->q_depth;
- hq_depth = ((q_cfg->rxp_type == BNA_RXP_SINGLE) ? 0 : q_cfg->q_depth);
- cq_depth = dq_depth + hq_depth;
-
- BNA_TO_POWER_OF_2_HIGH(cq_depth);
- cq_size = cq_depth * BFI_CQ_WI_SIZE;
- cq_size = ALIGN(cq_size, PAGE_SIZE);
- cpage_count = SIZE_TO_PAGES(cq_size);
-
- BNA_TO_POWER_OF_2_HIGH(dq_depth);
- dq_size = dq_depth * BFI_RXQ_WI_SIZE;
- dq_size = ALIGN(dq_size, PAGE_SIZE);
- dpage_count = SIZE_TO_PAGES(dq_size);
-
- if (BNA_RXP_SINGLE != q_cfg->rxp_type) {
- BNA_TO_POWER_OF_2_HIGH(hq_depth);
- hq_size = hq_depth * BFI_RXQ_WI_SIZE;
- hq_size = ALIGN(hq_size, PAGE_SIZE);
- hpage_count = SIZE_TO_PAGES(hq_size);
- } else {
- hpage_count = 0;
- }
-
- /* CCB structures */
- res_info[BNA_RX_RES_MEM_T_CCB].res_type = BNA_RES_T_MEM;
- mem_info = &res_info[BNA_RX_RES_MEM_T_CCB].res_u.mem_info;
- mem_info->mem_type = BNA_MEM_T_KVA;
- mem_info->len = sizeof(struct bna_ccb);
- mem_info->num = q_cfg->num_paths;
-
- /* RCB structures */
- res_info[BNA_RX_RES_MEM_T_RCB].res_type = BNA_RES_T_MEM;
- mem_info = &res_info[BNA_RX_RES_MEM_T_RCB].res_u.mem_info;
- mem_info->mem_type = BNA_MEM_T_KVA;
- mem_info->len = sizeof(struct bna_rcb);
- mem_info->num = BNA_GET_RXQS(q_cfg);
-
- /* Completion QPT */
- res_info[BNA_RX_RES_MEM_T_CQPT].res_type = BNA_RES_T_MEM;
- mem_info = &res_info[BNA_RX_RES_MEM_T_CQPT].res_u.mem_info;
- mem_info->mem_type = BNA_MEM_T_DMA;
- mem_info->len = cpage_count * sizeof(struct bna_dma_addr);
- mem_info->num = q_cfg->num_paths;
-
- /* Completion s/w QPT */
- res_info[BNA_RX_RES_MEM_T_CSWQPT].res_type = BNA_RES_T_MEM;
- mem_info = &res_info[BNA_RX_RES_MEM_T_CSWQPT].res_u.mem_info;
- mem_info->mem_type = BNA_MEM_T_KVA;
- mem_info->len = cpage_count * sizeof(void *);
- mem_info->num = q_cfg->num_paths;
-
- /* Completion QPT pages */
- res_info[BNA_RX_RES_MEM_T_CQPT_PAGE].res_type = BNA_RES_T_MEM;
- mem_info = &res_info[BNA_RX_RES_MEM_T_CQPT_PAGE].res_u.mem_info;
- mem_info->mem_type = BNA_MEM_T_DMA;
- mem_info->len = PAGE_SIZE;
- mem_info->num = cpage_count * q_cfg->num_paths;
-
- /* Data QPTs */
- res_info[BNA_RX_RES_MEM_T_DQPT].res_type = BNA_RES_T_MEM;
- mem_info = &res_info[BNA_RX_RES_MEM_T_DQPT].res_u.mem_info;
- mem_info->mem_type = BNA_MEM_T_DMA;
- mem_info->len = dpage_count * sizeof(struct bna_dma_addr);
- mem_info->num = q_cfg->num_paths;
-
- /* Data s/w QPTs */
- res_info[BNA_RX_RES_MEM_T_DSWQPT].res_type = BNA_RES_T_MEM;
- mem_info = &res_info[BNA_RX_RES_MEM_T_DSWQPT].res_u.mem_info;
- mem_info->mem_type = BNA_MEM_T_KVA;
- mem_info->len = dpage_count * sizeof(void *);
- mem_info->num = q_cfg->num_paths;
-
- /* Data QPT pages */
- res_info[BNA_RX_RES_MEM_T_DPAGE].res_type = BNA_RES_T_MEM;
- mem_info = &res_info[BNA_RX_RES_MEM_T_DPAGE].res_u.mem_info;
- mem_info->mem_type = BNA_MEM_T_DMA;
- mem_info->len = PAGE_SIZE;
- mem_info->num = dpage_count * q_cfg->num_paths;
-
- /* Hdr QPTs */
- res_info[BNA_RX_RES_MEM_T_HQPT].res_type = BNA_RES_T_MEM;
- mem_info = &res_info[BNA_RX_RES_MEM_T_HQPT].res_u.mem_info;
- mem_info->mem_type = BNA_MEM_T_DMA;
- mem_info->len = hpage_count * sizeof(struct bna_dma_addr);
- mem_info->num = (hpage_count ? q_cfg->num_paths : 0);
-
- /* Hdr s/w QPTs */
- res_info[BNA_RX_RES_MEM_T_HSWQPT].res_type = BNA_RES_T_MEM;
- mem_info = &res_info[BNA_RX_RES_MEM_T_HSWQPT].res_u.mem_info;
- mem_info->mem_type = BNA_MEM_T_KVA;
- mem_info->len = hpage_count * sizeof(void *);
- mem_info->num = (hpage_count ? q_cfg->num_paths : 0);
-
- /* Hdr QPT pages */
- res_info[BNA_RX_RES_MEM_T_HPAGE].res_type = BNA_RES_T_MEM;
- mem_info = &res_info[BNA_RX_RES_MEM_T_HPAGE].res_u.mem_info;
- mem_info->mem_type = BNA_MEM_T_DMA;
- mem_info->len = (hpage_count ? PAGE_SIZE : 0);
- mem_info->num = (hpage_count ? (hpage_count * q_cfg->num_paths) : 0);
-
- /* RX Interrupts */
- res_info[BNA_RX_RES_T_INTR].res_type = BNA_RES_T_INTR;
- res_info[BNA_RX_RES_T_INTR].res_u.intr_info.intr_type = BNA_INTR_T_MSIX;
- res_info[BNA_RX_RES_T_INTR].res_u.intr_info.num = q_cfg->num_paths;
-}
-
-struct bna_rx *
-bna_rx_create(struct bna *bna, struct bnad *bnad,
- struct bna_rx_config *rx_cfg,
- struct bna_rx_event_cbfn *rx_cbfn,
- struct bna_res_info *res_info,
- void *priv)
-{
- struct bna_rx_mod *rx_mod = &bna->rx_mod;
- struct bna_rx *rx;
- struct bna_rxp *rxp;
- struct bna_rxq *q0;
- struct bna_rxq *q1;
- struct bna_intr_info *intr_info;
- u32 page_count;
- struct bna_mem_descr *ccb_mem;
- struct bna_mem_descr *rcb_mem;
- struct bna_mem_descr *unmapq_mem;
- struct bna_mem_descr *cqpt_mem;
- struct bna_mem_descr *cswqpt_mem;
- struct bna_mem_descr *cpage_mem;
- struct bna_mem_descr *hqpt_mem; /* Header/Small Q qpt */
- struct bna_mem_descr *dqpt_mem; /* Data/Large Q qpt */
- struct bna_mem_descr *hsqpt_mem; /* s/w qpt for hdr */
- struct bna_mem_descr *dsqpt_mem; /* s/w qpt for data */
- struct bna_mem_descr *hpage_mem; /* hdr page mem */
- struct bna_mem_descr *dpage_mem; /* data page mem */
- int i, cpage_idx = 0, dpage_idx = 0, hpage_idx = 0;
- int dpage_count, hpage_count, rcb_idx;
- struct bna_ib_config ibcfg;
- /* Fail if we don't have enough RXPs, RXQs */
- if (!_rx_can_satisfy(rx_mod, rx_cfg))
- return NULL;
-
- /* Initialize resource pointers */
- intr_info = &res_info[BNA_RX_RES_T_INTR].res_u.intr_info;
- ccb_mem = &res_info[BNA_RX_RES_MEM_T_CCB].res_u.mem_info.mdl[0];
- rcb_mem = &res_info[BNA_RX_RES_MEM_T_RCB].res_u.mem_info.mdl[0];
- unmapq_mem = &res_info[BNA_RX_RES_MEM_T_UNMAPQ].res_u.mem_info.mdl[0];
- cqpt_mem = &res_info[BNA_RX_RES_MEM_T_CQPT].res_u.mem_info.mdl[0];
- cswqpt_mem = &res_info[BNA_RX_RES_MEM_T_CSWQPT].res_u.mem_info.mdl[0];
- cpage_mem = &res_info[BNA_RX_RES_MEM_T_CQPT_PAGE].res_u.mem_info.mdl[0];
- hqpt_mem = &res_info[BNA_RX_RES_MEM_T_HQPT].res_u.mem_info.mdl[0];
- dqpt_mem = &res_info[BNA_RX_RES_MEM_T_DQPT].res_u.mem_info.mdl[0];
- hsqpt_mem = &res_info[BNA_RX_RES_MEM_T_HSWQPT].res_u.mem_info.mdl[0];
- dsqpt_mem = &res_info[BNA_RX_RES_MEM_T_DSWQPT].res_u.mem_info.mdl[0];
- hpage_mem = &res_info[BNA_RX_RES_MEM_T_HPAGE].res_u.mem_info.mdl[0];
- dpage_mem = &res_info[BNA_RX_RES_MEM_T_DPAGE].res_u.mem_info.mdl[0];
-
- /* Compute q depth & page count */
- page_count = res_info[BNA_RX_RES_MEM_T_CQPT_PAGE].res_u.mem_info.num /
- rx_cfg->num_paths;
-
- dpage_count = res_info[BNA_RX_RES_MEM_T_DPAGE].res_u.mem_info.num /
- rx_cfg->num_paths;
-
- hpage_count = res_info[BNA_RX_RES_MEM_T_HPAGE].res_u.mem_info.num /
- rx_cfg->num_paths;
- /* Get RX pointer */
- rx = _get_free_rx(rx_mod);
- _rx_init(rx, bna);
- rx->priv = priv;
- rx->type = rx_cfg->rx_type;
-
- rx->rcb_setup_cbfn = rx_cbfn->rcb_setup_cbfn;
- rx->rcb_destroy_cbfn = rx_cbfn->rcb_destroy_cbfn;
- rx->ccb_setup_cbfn = rx_cbfn->ccb_setup_cbfn;
- rx->ccb_destroy_cbfn = rx_cbfn->ccb_destroy_cbfn;
- /* Following callbacks are mandatory */
- rx->rx_cleanup_cbfn = rx_cbfn->rx_cleanup_cbfn;
- rx->rx_post_cbfn = rx_cbfn->rx_post_cbfn;
-
- if (rx->bna->rx_mod.flags & BNA_RX_MOD_F_PORT_STARTED) {
- switch (rx->type) {
- case BNA_RX_T_REGULAR:
- if (!(rx->bna->rx_mod.flags &
- BNA_RX_MOD_F_PORT_LOOPBACK))
- rx->rx_flags |= BNA_RX_F_PORT_ENABLED;
- break;
- case BNA_RX_T_LOOPBACK:
- if (rx->bna->rx_mod.flags & BNA_RX_MOD_F_PORT_LOOPBACK)
- rx->rx_flags |= BNA_RX_F_PORT_ENABLED;
- break;
- }
- }
-
- for (i = 0, rcb_idx = 0; i < rx_cfg->num_paths; i++) {
- rxp = _get_free_rxp(rx_mod);
- rxp->type = rx_cfg->rxp_type;
- rxp->rx = rx;
- rxp->cq.rx = rx;
-
- /* Get required RXQs, and queue them to rx-path */
- q0 = _get_free_rxq(rx_mod);
- if (BNA_RXP_SINGLE == rx_cfg->rxp_type)
- q1 = NULL;
- else
- q1 = _get_free_rxq(rx_mod);
-
- /* Initialize IB */
- if (1 == intr_info->num) {
- rxp->cq.ib = bna_ib_get(&bna->ib_mod,
- intr_info->intr_type,
- intr_info->idl[0].vector);
- rxp->vector = intr_info->idl[0].vector;
- } else {
- rxp->cq.ib = bna_ib_get(&bna->ib_mod,
- intr_info->intr_type,
- intr_info->idl[i].vector);
-
- /* Map the MSI-x vector used for this RXP */
- rxp->vector = intr_info->idl[i].vector;
- }
-
- rxp->cq.ib_seg_offset = bna_ib_reserve_idx(rxp->cq.ib);
-
- ibcfg.coalescing_timeo = BFI_RX_COALESCING_TIMEO;
- ibcfg.interpkt_count = BFI_RX_INTERPKT_COUNT;
- ibcfg.interpkt_timeo = BFI_RX_INTERPKT_TIMEO;
- ibcfg.ctrl_flags = BFI_IB_CF_INT_ENABLE;
-
- bna_ib_config(rxp->cq.ib, &ibcfg);
-
- /* Link rxqs to rxp */
- _rxp_add_rxqs(rxp, q0, q1);
-
- /* Link rxp to rx */
- _rx_add_rxp(rx, rxp);
-
- q0->rx = rx;
- q0->rxp = rxp;
-
- /* Initialize RCB for the large / data q */
- q0->rcb = (struct bna_rcb *) rcb_mem[rcb_idx].kva;
- RXQ_RCB_INIT(q0, rxp, rx_cfg->q_depth, bna, 0,
- (void *)unmapq_mem[rcb_idx].kva);
- rcb_idx++;
- (q0)->rx_packets = (q0)->rx_bytes = 0;
- (q0)->rx_packets_with_error = (q0)->rxbuf_alloc_failed = 0;
-
- /* Initialize RXQs */
- _rxq_qpt_init(q0, rxp, dpage_count, PAGE_SIZE,
- &dqpt_mem[i], &dsqpt_mem[i], &dpage_mem[dpage_idx]);
- q0->rcb->page_idx = dpage_idx;
- q0->rcb->page_count = dpage_count;
- dpage_idx += dpage_count;
-
- /* Call bnad to complete rcb setup */
- if (rx->rcb_setup_cbfn)
- rx->rcb_setup_cbfn(bnad, q0->rcb);
-
- if (q1) {
- q1->rx = rx;
- q1->rxp = rxp;
-
- q1->rcb = (struct bna_rcb *) rcb_mem[rcb_idx].kva;
- RXQ_RCB_INIT(q1, rxp, rx_cfg->q_depth, bna, 1,
- (void *)unmapq_mem[rcb_idx].kva);
- rcb_idx++;
- (q1)->buffer_size = (rx_cfg)->small_buff_size;
- (q1)->rx_packets = (q1)->rx_bytes = 0;
- (q1)->rx_packets_with_error =
- (q1)->rxbuf_alloc_failed = 0;
-
- _rxq_qpt_init(q1, rxp, hpage_count, PAGE_SIZE,
- &hqpt_mem[i], &hsqpt_mem[i],
- &hpage_mem[hpage_idx]);
- q1->rcb->page_idx = hpage_idx;
- q1->rcb->page_count = hpage_count;
- hpage_idx += hpage_count;
-
- /* Call bnad to complete rcb setup */
- if (rx->rcb_setup_cbfn)
- rx->rcb_setup_cbfn(bnad, q1->rcb);
- }
- /* Setup RXP::CQ */
- rxp->cq.ccb = (struct bna_ccb *) ccb_mem[i].kva;
- _rxp_cqpt_setup(rxp, page_count, PAGE_SIZE,
- &cqpt_mem[i], &cswqpt_mem[i], &cpage_mem[cpage_idx]);
- rxp->cq.ccb->page_idx = cpage_idx;
- rxp->cq.ccb->page_count = page_count;
- cpage_idx += page_count;
-
- rxp->cq.ccb->pkt_rate.small_pkt_cnt = 0;
- rxp->cq.ccb->pkt_rate.large_pkt_cnt = 0;
-
- rxp->cq.ccb->producer_index = 0;
- rxp->cq.ccb->q_depth = rx_cfg->q_depth +
- ((rx_cfg->rxp_type == BNA_RXP_SINGLE) ?
- 0 : rx_cfg->q_depth);
- rxp->cq.ccb->i_dbell = &rxp->cq.ib->door_bell;
- rxp->cq.ccb->rcb[0] = q0->rcb;
- if (q1)
- rxp->cq.ccb->rcb[1] = q1->rcb;
- rxp->cq.ccb->cq = &rxp->cq;
- rxp->cq.ccb->bnad = bna->bnad;
- rxp->cq.ccb->hw_producer_index =
- ((volatile u32 *)rxp->cq.ib->ib_seg_host_addr_kva +
- (rxp->cq.ib_seg_offset * BFI_IBIDX_SIZE));
- *(rxp->cq.ccb->hw_producer_index) = 0;
- rxp->cq.ccb->intr_type = intr_info->intr_type;
- rxp->cq.ccb->intr_vector = (intr_info->num == 1) ?
- intr_info->idl[0].vector :
- intr_info->idl[i].vector;
- rxp->cq.ccb->rx_coalescing_timeo =
- rxp->cq.ib->ib_config.coalescing_timeo;
- rxp->cq.ccb->id = i;
-
- /* Call bnad to complete CCB setup */
- if (rx->ccb_setup_cbfn)
- rx->ccb_setup_cbfn(bnad, rxp->cq.ccb);
-
- } /* for each rx-path */
-
- bna_rxf_init(&rx->rxf, rx, rx_cfg);
-
- bfa_fsm_set_state(rx, bna_rx_sm_stopped);
-
- return rx;
-}
-
-void
-bna_rx_destroy(struct bna_rx *rx)
-{
- struct bna_rx_mod *rx_mod = &rx->bna->rx_mod;
- struct bna_ib_mod *ib_mod = &rx->bna->ib_mod;
- struct bna_rxq *q0 = NULL;
- struct bna_rxq *q1 = NULL;
- struct bna_rxp *rxp;
- struct list_head *qe;
-
- bna_rxf_uninit(&rx->rxf);
-
- while (!list_empty(&rx->rxp_q)) {
- bfa_q_deq(&rx->rxp_q, &rxp);
- GET_RXQS(rxp, q0, q1);
- /* Callback to bnad for destroying RCB */
- if (rx->rcb_destroy_cbfn)
- rx->rcb_destroy_cbfn(rx->bna->bnad, q0->rcb);
- q0->rcb = NULL;
- q0->rxp = NULL;
- q0->rx = NULL;
- _put_free_rxq(rx_mod, q0);
- if (q1) {
- /* Callback to bnad for destroying RCB */
- if (rx->rcb_destroy_cbfn)
- rx->rcb_destroy_cbfn(rx->bna->bnad, q1->rcb);
- q1->rcb = NULL;
- q1->rxp = NULL;
- q1->rx = NULL;
- _put_free_rxq(rx_mod, q1);
- }
- rxp->rxq.slr.large = NULL;
- rxp->rxq.slr.small = NULL;
- if (rxp->cq.ib) {
- if (rxp->cq.ib_seg_offset != 0xff)
- bna_ib_release_idx(rxp->cq.ib,
- rxp->cq.ib_seg_offset);
- bna_ib_put(ib_mod, rxp->cq.ib);
- rxp->cq.ib = NULL;
- }
- /* Callback to bnad for destroying CCB */
- if (rx->ccb_destroy_cbfn)
- rx->ccb_destroy_cbfn(rx->bna->bnad, rxp->cq.ccb);
- rxp->cq.ccb = NULL;
- rxp->rx = NULL;
- _put_free_rxp(rx_mod, rxp);
- }
-
- list_for_each(qe, &rx_mod->rx_active_q) {
- if (qe == &rx->qe) {
- list_del(&rx->qe);
- bfa_q_qe_init(&rx->qe);
- break;
- }
- }
-
- rx->bna = NULL;
- rx->priv = NULL;
- _put_free_rx(rx_mod, rx);
-}
-
-void
-bna_rx_enable(struct bna_rx *rx)
-{
- if (rx->fsm != (bfa_sm_t)bna_rx_sm_stopped)
- return;
-
- rx->rx_flags |= BNA_RX_F_ENABLE;
- if (rx->rx_flags & BNA_RX_F_PORT_ENABLED)
- bfa_fsm_send_event(rx, RX_E_START);
-}
-
-void
-bna_rx_disable(struct bna_rx *rx, enum bna_cleanup_type type,
- void (*cbfn)(void *, struct bna_rx *,
- enum bna_cb_status))
-{
- if (type == BNA_SOFT_CLEANUP) {
- /* h/w should not be accessed. Treat we're stopped */
- (*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
- } else {
- rx->stop_cbfn = cbfn;
- rx->stop_cbarg = rx->bna->bnad;
-
- rx->rx_flags &= ~BNA_RX_F_ENABLE;
-
- bfa_fsm_send_event(rx, RX_E_STOP);
- }
-}
-
-/**
- * TX
- */
-#define call_tx_stop_cbfn(tx, status)\
-do {\
- if ((tx)->stop_cbfn)\
- (tx)->stop_cbfn((tx)->stop_cbarg, (tx), status);\
- (tx)->stop_cbfn = NULL;\
- (tx)->stop_cbarg = NULL;\
-} while (0)
-
-#define call_tx_prio_change_cbfn(tx, status)\
-do {\
- if ((tx)->prio_change_cbfn)\
- (tx)->prio_change_cbfn((tx)->bna->bnad, (tx), status);\
- (tx)->prio_change_cbfn = NULL;\
-} while (0)
-
-static void bna_tx_mod_cb_tx_stopped(void *tx_mod, struct bna_tx *tx,
- enum bna_cb_status status);
-static void bna_tx_cb_txq_stopped(void *arg, int status);
-static void bna_tx_cb_stats_cleared(void *arg, int status);
-static void __bna_tx_stop(struct bna_tx *tx);
-static void __bna_tx_start(struct bna_tx *tx);
-static void __bna_txf_stat_clr(struct bna_tx *tx);
-
-enum bna_tx_event {
- TX_E_START = 1,
- TX_E_STOP = 2,
- TX_E_FAIL = 3,
- TX_E_TXQ_STOPPED = 4,
- TX_E_PRIO_CHANGE = 5,
- TX_E_STAT_CLEARED = 6,
-};
-
-enum bna_tx_state {
- BNA_TX_STOPPED = 1,
- BNA_TX_STARTED = 2,
- BNA_TX_TXQ_STOP_WAIT = 3,
- BNA_TX_PRIO_STOP_WAIT = 4,
- BNA_TX_STAT_CLR_WAIT = 5,
-};
-
-bfa_fsm_state_decl(bna_tx, stopped, struct bna_tx,
- enum bna_tx_event);
-bfa_fsm_state_decl(bna_tx, started, struct bna_tx,
- enum bna_tx_event);
-bfa_fsm_state_decl(bna_tx, txq_stop_wait, struct bna_tx,
- enum bna_tx_event);
-bfa_fsm_state_decl(bna_tx, prio_stop_wait, struct bna_tx,
- enum bna_tx_event);
-bfa_fsm_state_decl(bna_tx, stat_clr_wait, struct bna_tx,
- enum bna_tx_event);
-
-static struct bfa_sm_table tx_sm_table[] = {
- {BFA_SM(bna_tx_sm_stopped), BNA_TX_STOPPED},
- {BFA_SM(bna_tx_sm_started), BNA_TX_STARTED},
- {BFA_SM(bna_tx_sm_txq_stop_wait), BNA_TX_TXQ_STOP_WAIT},
- {BFA_SM(bna_tx_sm_prio_stop_wait), BNA_TX_PRIO_STOP_WAIT},
- {BFA_SM(bna_tx_sm_stat_clr_wait), BNA_TX_STAT_CLR_WAIT},
-};
-
-static void
-bna_tx_sm_stopped_entry(struct bna_tx *tx)
-{
- struct bna_txq *txq;
- struct list_head *qe;
-
- list_for_each(qe, &tx->txq_q) {
- txq = (struct bna_txq *)qe;
- (tx->tx_cleanup_cbfn)(tx->bna->bnad, txq->tcb);
- }
-
- call_tx_stop_cbfn(tx, BNA_CB_SUCCESS);
-}
-
-static void
-bna_tx_sm_stopped(struct bna_tx *tx, enum bna_tx_event event)
-{
- switch (event) {
- case TX_E_START:
- bfa_fsm_set_state(tx, bna_tx_sm_started);
- break;
-
- case TX_E_STOP:
- bfa_fsm_set_state(tx, bna_tx_sm_stopped);
- break;
-
- case TX_E_FAIL:
- /* No-op */
- break;
-
- case TX_E_PRIO_CHANGE:
- call_tx_prio_change_cbfn(tx, BNA_CB_SUCCESS);
- break;
-
- case TX_E_TXQ_STOPPED:
- /**
- * This event is received due to flushing of mbox when
- * device fails
- */
- /* No-op */
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_tx_sm_started_entry(struct bna_tx *tx)
-{
- struct bna_txq *txq;
- struct list_head *qe;
-
- __bna_tx_start(tx);
-
- /* Start IB */
- list_for_each(qe, &tx->txq_q) {
- txq = (struct bna_txq *)qe;
- bna_ib_ack(&txq->ib->door_bell, 0);
- }
-}
-
-static void
-bna_tx_sm_started(struct bna_tx *tx, enum bna_tx_event event)
-{
- struct bna_txq *txq;
- struct list_head *qe;
-
- switch (event) {
- case TX_E_STOP:
- bfa_fsm_set_state(tx, bna_tx_sm_txq_stop_wait);
- __bna_tx_stop(tx);
- break;
-
- case TX_E_FAIL:
- list_for_each(qe, &tx->txq_q) {
- txq = (struct bna_txq *)qe;
- bna_ib_fail(txq->ib);
- (tx->tx_stall_cbfn)(tx->bna->bnad, txq->tcb);
- }
- bfa_fsm_set_state(tx, bna_tx_sm_stopped);
- break;
-
- case TX_E_PRIO_CHANGE:
- bfa_fsm_set_state(tx, bna_tx_sm_prio_stop_wait);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_tx_sm_txq_stop_wait_entry(struct bna_tx *tx)
-{
-}
-
-static void
-bna_tx_sm_txq_stop_wait(struct bna_tx *tx, enum bna_tx_event event)
-{
- struct bna_txq *txq;
- struct list_head *qe;
-
- switch (event) {
- case TX_E_FAIL:
- bfa_fsm_set_state(tx, bna_tx_sm_stopped);
- break;
-
- case TX_E_TXQ_STOPPED:
- list_for_each(qe, &tx->txq_q) {
- txq = (struct bna_txq *)qe;
- bna_ib_stop(txq->ib);
- }
- bfa_fsm_set_state(tx, bna_tx_sm_stat_clr_wait);
- break;
-
- case TX_E_PRIO_CHANGE:
- /* No-op */
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_tx_sm_prio_stop_wait_entry(struct bna_tx *tx)
-{
- __bna_tx_stop(tx);
-}
-
-static void
-bna_tx_sm_prio_stop_wait(struct bna_tx *tx, enum bna_tx_event event)
-{
- struct bna_txq *txq;
- struct list_head *qe;
-
- switch (event) {
- case TX_E_STOP:
- bfa_fsm_set_state(tx, bna_tx_sm_txq_stop_wait);
- break;
-
- case TX_E_FAIL:
- call_tx_prio_change_cbfn(tx, BNA_CB_FAIL);
- bfa_fsm_set_state(tx, bna_tx_sm_stopped);
- break;
-
- case TX_E_TXQ_STOPPED:
- list_for_each(qe, &tx->txq_q) {
- txq = (struct bna_txq *)qe;
- bna_ib_stop(txq->ib);
- (tx->tx_cleanup_cbfn)(tx->bna->bnad, txq->tcb);
- }
- call_tx_prio_change_cbfn(tx, BNA_CB_SUCCESS);
- bfa_fsm_set_state(tx, bna_tx_sm_started);
- break;
-
- case TX_E_PRIO_CHANGE:
- /* No-op */
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-bna_tx_sm_stat_clr_wait_entry(struct bna_tx *tx)
-{
- __bna_txf_stat_clr(tx);
-}
-
-static void
-bna_tx_sm_stat_clr_wait(struct bna_tx *tx, enum bna_tx_event event)
-{
- switch (event) {
- case TX_E_FAIL:
- case TX_E_STAT_CLEARED:
- bfa_fsm_set_state(tx, bna_tx_sm_stopped);
- break;
-
- default:
- bfa_sm_fault(event);
- }
-}
-
-static void
-__bna_txq_start(struct bna_tx *tx, struct bna_txq *txq)
-{
- struct bna_rxtx_q_mem *q_mem;
- struct bna_txq_mem txq_cfg;
- struct bna_txq_mem *txq_mem;
- struct bna_dma_addr cur_q_addr;
- u32 pg_num;
- void __iomem *base_addr;
- unsigned long off;
-
- /* Fill out structure, to be subsequently written to hardware */
- txq_cfg.pg_tbl_addr_lo = txq->qpt.hw_qpt_ptr.lsb;
- txq_cfg.pg_tbl_addr_hi = txq->qpt.hw_qpt_ptr.msb;
- cur_q_addr = *((struct bna_dma_addr *)(txq->qpt.kv_qpt_ptr));
- txq_cfg.cur_q_entry_lo = cur_q_addr.lsb;
- txq_cfg.cur_q_entry_hi = cur_q_addr.msb;
-
- txq_cfg.pg_cnt_n_prd_ptr = (txq->qpt.page_count << 16) | 0x0;
-
- txq_cfg.entry_n_pg_size = ((u32)(BFI_TXQ_WI_SIZE >> 2) << 16) |
- (txq->qpt.page_size >> 2);
- txq_cfg.int_blk_n_cns_ptr = ((((u32)txq->ib_seg_offset) << 24) |
- ((u32)(txq->ib->ib_id & 0xff) << 16) | 0x0);
-
- txq_cfg.cns_ptr2_n_q_state = BNA_Q_IDLE_STATE;
- txq_cfg.nxt_qid_n_fid_n_pri = (((tx->txf.txf_id & 0x3f) << 3) |
- (txq->priority & 0x7));
- txq_cfg.wvc_n_cquota_n_rquota =
- ((((u32)BFI_TX_MAX_WRR_QUOTA & 0xfff) << 12) |
- (BFI_TX_MAX_WRR_QUOTA & 0xfff));
-
- /* Setup the page and write to H/W */
-
- pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + tx->bna->port_num,
- HQM_RXTX_Q_RAM_BASE_OFFSET);
- writel(pg_num, tx->bna->regs.page_addr);
-
- base_addr = BNA_GET_MEM_BASE_ADDR(tx->bna->pcidev.pci_bar_kva,
- HQM_RXTX_Q_RAM_BASE_OFFSET);
- q_mem = (struct bna_rxtx_q_mem *)0;
- txq_mem = &q_mem[txq->txq_id].txq;
-
- /*
- * The following 4 lines, is a hack b'cos the H/W needs to read
- * these DMA addresses as little endian
- */
-
- off = (unsigned long)&txq_mem->pg_tbl_addr_lo;
- writel(htonl(txq_cfg.pg_tbl_addr_lo), base_addr + off);
-
- off = (unsigned long)&txq_mem->pg_tbl_addr_hi;
- writel(htonl(txq_cfg.pg_tbl_addr_hi), base_addr + off);
-
- off = (unsigned long)&txq_mem->cur_q_entry_lo;
- writel(htonl(txq_cfg.cur_q_entry_lo), base_addr + off);
-
- off = (unsigned long)&txq_mem->cur_q_entry_hi;
- writel(htonl(txq_cfg.cur_q_entry_hi), base_addr + off);
-
- off = (unsigned long)&txq_mem->pg_cnt_n_prd_ptr;
- writel(txq_cfg.pg_cnt_n_prd_ptr, base_addr + off);
-
- off = (unsigned long)&txq_mem->entry_n_pg_size;
- writel(txq_cfg.entry_n_pg_size, base_addr + off);
-
- off = (unsigned long)&txq_mem->int_blk_n_cns_ptr;
- writel(txq_cfg.int_blk_n_cns_ptr, base_addr + off);
-
- off = (unsigned long)&txq_mem->cns_ptr2_n_q_state;
- writel(txq_cfg.cns_ptr2_n_q_state, base_addr + off);
-
- off = (unsigned long)&txq_mem->nxt_qid_n_fid_n_pri;
- writel(txq_cfg.nxt_qid_n_fid_n_pri, base_addr + off);
-
- off = (unsigned long)&txq_mem->wvc_n_cquota_n_rquota;
- writel(txq_cfg.wvc_n_cquota_n_rquota, base_addr + off);
-
- txq->tcb->producer_index = 0;
- txq->tcb->consumer_index = 0;
- *(txq->tcb->hw_consumer_index) = 0;
-
-}
-
-static void
-__bna_txq_stop(struct bna_tx *tx, struct bna_txq *txq)
-{
- struct bfi_ll_q_stop_req ll_req;
- u32 bit_mask[2] = {0, 0};
- if (txq->txq_id < 32)
- bit_mask[0] = (u32)1 << txq->txq_id;
- else
- bit_mask[1] = (u32)1 << (txq->txq_id - 32);
-
- memset(&ll_req, 0, sizeof(ll_req));
- ll_req.mh.msg_class = BFI_MC_LL;
- ll_req.mh.msg_id = BFI_LL_H2I_TXQ_STOP_REQ;
- ll_req.mh.mtag.h2i.lpu_id = 0;
- ll_req.q_id_mask[0] = htonl(bit_mask[0]);
- ll_req.q_id_mask[1] = htonl(bit_mask[1]);
-
- bna_mbox_qe_fill(&tx->mbox_qe, &ll_req, sizeof(ll_req),
- bna_tx_cb_txq_stopped, tx);
-
- bna_mbox_send(tx->bna, &tx->mbox_qe);
-}
-
-static void
-__bna_txf_start(struct bna_tx *tx)
-{
- struct bna_tx_fndb_ram *tx_fndb;
- struct bna_txf *txf = &tx->txf;
- void __iomem *base_addr;
- unsigned long off;
-
- writel(BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
- (tx->bna->port_num * 2), TX_FNDB_RAM_BASE_OFFSET),
- tx->bna->regs.page_addr);
-
- base_addr = BNA_GET_MEM_BASE_ADDR(tx->bna->pcidev.pci_bar_kva,
- TX_FNDB_RAM_BASE_OFFSET);
-
- tx_fndb = (struct bna_tx_fndb_ram *)0;
- off = (unsigned long)&tx_fndb[txf->txf_id].vlan_n_ctrl_flags;
-
- writel(((u32)txf->vlan << 16) | txf->ctrl_flags,
- base_addr + off);
-
- if (tx->txf.txf_id < 32)
- tx->bna->tx_mod.txf_bmap[0] |= ((u32)1 << tx->txf.txf_id);
- else
- tx->bna->tx_mod.txf_bmap[1] |= ((u32)
- 1 << (tx->txf.txf_id - 32));
-}
-
-static void
-__bna_txf_stop(struct bna_tx *tx)
-{
- struct bna_tx_fndb_ram *tx_fndb;
- u32 page_num;
- u32 ctl_flags;
- struct bna_txf *txf = &tx->txf;
- void __iomem *base_addr;
- unsigned long off;
-
- /* retrieve the running txf_flags & turn off enable bit */
- page_num = BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
- (tx->bna->port_num * 2), TX_FNDB_RAM_BASE_OFFSET);
- writel(page_num, tx->bna->regs.page_addr);
-
- base_addr = BNA_GET_MEM_BASE_ADDR(tx->bna->pcidev.pci_bar_kva,
- TX_FNDB_RAM_BASE_OFFSET);
- tx_fndb = (struct bna_tx_fndb_ram *)0;
- off = (unsigned long)&tx_fndb[txf->txf_id].vlan_n_ctrl_flags;
-
- ctl_flags = readl(base_addr + off);
- ctl_flags &= ~BFI_TXF_CF_ENABLE;
-
- writel(ctl_flags, base_addr + off);
-
- if (tx->txf.txf_id < 32)
- tx->bna->tx_mod.txf_bmap[0] &= ~((u32)1 << tx->txf.txf_id);
- else
- tx->bna->tx_mod.txf_bmap[0] &= ~((u32)
- 1 << (tx->txf.txf_id - 32));
-}
-
-static void
-__bna_txf_stat_clr(struct bna_tx *tx)
-{
- struct bfi_ll_stats_req ll_req;
- u32 txf_bmap[2] = {0, 0};
- if (tx->txf.txf_id < 32)
- txf_bmap[0] = ((u32)1 << tx->txf.txf_id);
- else
- txf_bmap[1] = ((u32)1 << (tx->txf.txf_id - 32));
- bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_STATS_CLEAR_REQ, 0);
- ll_req.stats_mask = 0;
- ll_req.rxf_id_mask[0] = 0;
- ll_req.rxf_id_mask[1] = 0;
- ll_req.txf_id_mask[0] = htonl(txf_bmap[0]);
- ll_req.txf_id_mask[1] = htonl(txf_bmap[1]);
-
- bna_mbox_qe_fill(&tx->mbox_qe, &ll_req, sizeof(ll_req),
- bna_tx_cb_stats_cleared, tx);
- bna_mbox_send(tx->bna, &tx->mbox_qe);
-}
-
-static void
-__bna_tx_start(struct bna_tx *tx)
-{
- struct bna_txq *txq;
- struct list_head *qe;
-
- list_for_each(qe, &tx->txq_q) {
- txq = (struct bna_txq *)qe;
- bna_ib_start(txq->ib);
- __bna_txq_start(tx, txq);
- }
-
- __bna_txf_start(tx);
-
- list_for_each(qe, &tx->txq_q) {
- txq = (struct bna_txq *)qe;
- txq->tcb->priority = txq->priority;
- (tx->tx_resume_cbfn)(tx->bna->bnad, txq->tcb);
- }
-}
-
-static void
-__bna_tx_stop(struct bna_tx *tx)
-{
- struct bna_txq *txq;
- struct list_head *qe;
-
- list_for_each(qe, &tx->txq_q) {
- txq = (struct bna_txq *)qe;
- (tx->tx_stall_cbfn)(tx->bna->bnad, txq->tcb);
- }
-
- __bna_txf_stop(tx);
-
- list_for_each(qe, &tx->txq_q) {
- txq = (struct bna_txq *)qe;
- bfa_wc_up(&tx->txq_stop_wc);
- }
-
- list_for_each(qe, &tx->txq_q) {
- txq = (struct bna_txq *)qe;
- __bna_txq_stop(tx, txq);
- }
-}
-
-static void
-bna_txq_qpt_setup(struct bna_txq *txq, int page_count, int page_size,
- struct bna_mem_descr *qpt_mem,
- struct bna_mem_descr *swqpt_mem,
- struct bna_mem_descr *page_mem)
-{
- int i;
-
- txq->qpt.hw_qpt_ptr.lsb = qpt_mem->dma.lsb;
- txq->qpt.hw_qpt_ptr.msb = qpt_mem->dma.msb;
- txq->qpt.kv_qpt_ptr = qpt_mem->kva;
- txq->qpt.page_count = page_count;
- txq->qpt.page_size = page_size;
-
- txq->tcb->sw_qpt = (void **) swqpt_mem->kva;
-
- for (i = 0; i < page_count; i++) {
- txq->tcb->sw_qpt[i] = page_mem[i].kva;
-
- ((struct bna_dma_addr *)txq->qpt.kv_qpt_ptr)[i].lsb =
- page_mem[i].dma.lsb;
- ((struct bna_dma_addr *)txq->qpt.kv_qpt_ptr)[i].msb =
- page_mem[i].dma.msb;
-
- }
-}
-
-static void
-bna_tx_free(struct bna_tx *tx)
-{
- struct bna_tx_mod *tx_mod = &tx->bna->tx_mod;
- struct bna_txq *txq;
- struct bna_ib_mod *ib_mod = &tx->bna->ib_mod;
- struct list_head *qe;
-
- while (!list_empty(&tx->txq_q)) {
- bfa_q_deq(&tx->txq_q, &txq);
- bfa_q_qe_init(&txq->qe);
- if (txq->ib) {
- if (txq->ib_seg_offset != -1)
- bna_ib_release_idx(txq->ib,
- txq->ib_seg_offset);
- bna_ib_put(ib_mod, txq->ib);
- txq->ib = NULL;
- }
- txq->tcb = NULL;
- txq->tx = NULL;
- list_add_tail(&txq->qe, &tx_mod->txq_free_q);
- }
-
- list_for_each(qe, &tx_mod->tx_active_q) {
- if (qe == &tx->qe) {
- list_del(&tx->qe);
- bfa_q_qe_init(&tx->qe);
- break;
- }
- }
-
- tx->bna = NULL;
- tx->priv = NULL;
- list_add_tail(&tx->qe, &tx_mod->tx_free_q);
-}
-
-static void
-bna_tx_cb_txq_stopped(void *arg, int status)
-{
- struct bna_tx *tx = (struct bna_tx *)arg;
-
- bfa_q_qe_init(&tx->mbox_qe.qe);
- bfa_wc_down(&tx->txq_stop_wc);
-}
-
-static void
-bna_tx_cb_txq_stopped_all(void *arg)
-{
- struct bna_tx *tx = (struct bna_tx *)arg;
-
- bfa_fsm_send_event(tx, TX_E_TXQ_STOPPED);
-}
-
-static void
-bna_tx_cb_stats_cleared(void *arg, int status)
-{
- struct bna_tx *tx = (struct bna_tx *)arg;
-
- bfa_q_qe_init(&tx->mbox_qe.qe);
-
- bfa_fsm_send_event(tx, TX_E_STAT_CLEARED);
-}
-
-static void
-bna_tx_start(struct bna_tx *tx)
-{
- tx->flags |= BNA_TX_F_PORT_STARTED;
- if (tx->flags & BNA_TX_F_ENABLED)
- bfa_fsm_send_event(tx, TX_E_START);
-}
-
-static void
-bna_tx_stop(struct bna_tx *tx)
-{
- tx->stop_cbfn = bna_tx_mod_cb_tx_stopped;
- tx->stop_cbarg = &tx->bna->tx_mod;
-
- tx->flags &= ~BNA_TX_F_PORT_STARTED;
- bfa_fsm_send_event(tx, TX_E_STOP);
-}
-
-static void
-bna_tx_fail(struct bna_tx *tx)
-{
- tx->flags &= ~BNA_TX_F_PORT_STARTED;
- bfa_fsm_send_event(tx, TX_E_FAIL);
-}
-
-static void
-bna_tx_prio_changed(struct bna_tx *tx, int prio)
-{
- struct bna_txq *txq;
- struct list_head *qe;
-
- list_for_each(qe, &tx->txq_q) {
- txq = (struct bna_txq *)qe;
- txq->priority = prio;
- }
-
- bfa_fsm_send_event(tx, TX_E_PRIO_CHANGE);
-}
-
-static void
-bna_tx_cee_link_status(struct bna_tx *tx, int cee_link)
-{
- if (cee_link)
- tx->flags |= BNA_TX_F_PRIO_LOCK;
- else
- tx->flags &= ~BNA_TX_F_PRIO_LOCK;
-}
-
-static void
-bna_tx_mod_cb_tx_stopped(void *arg, struct bna_tx *tx,
- enum bna_cb_status status)
-{
- struct bna_tx_mod *tx_mod = (struct bna_tx_mod *)arg;
-
- bfa_wc_down(&tx_mod->tx_stop_wc);
-}
-
-static void
-bna_tx_mod_cb_tx_stopped_all(void *arg)
-{
- struct bna_tx_mod *tx_mod = (struct bna_tx_mod *)arg;
-
- if (tx_mod->stop_cbfn)
- tx_mod->stop_cbfn(&tx_mod->bna->port, BNA_CB_SUCCESS);
- tx_mod->stop_cbfn = NULL;
-}
-
-void
-bna_tx_res_req(int num_txq, int txq_depth, struct bna_res_info *res_info)
-{
- u32 q_size;
- u32 page_count;
- struct bna_mem_info *mem_info;
-
- res_info[BNA_TX_RES_MEM_T_TCB].res_type = BNA_RES_T_MEM;
- mem_info = &res_info[BNA_TX_RES_MEM_T_TCB].res_u.mem_info;
- mem_info->mem_type = BNA_MEM_T_KVA;
- mem_info->len = sizeof(struct bna_tcb);
- mem_info->num = num_txq;
-
- q_size = txq_depth * BFI_TXQ_WI_SIZE;
- q_size = ALIGN(q_size, PAGE_SIZE);
- page_count = q_size >> PAGE_SHIFT;
-
- res_info[BNA_TX_RES_MEM_T_QPT].res_type = BNA_RES_T_MEM;
- mem_info = &res_info[BNA_TX_RES_MEM_T_QPT].res_u.mem_info;
- mem_info->mem_type = BNA_MEM_T_DMA;
- mem_info->len = page_count * sizeof(struct bna_dma_addr);
- mem_info->num = num_txq;
-
- res_info[BNA_TX_RES_MEM_T_SWQPT].res_type = BNA_RES_T_MEM;
- mem_info = &res_info[BNA_TX_RES_MEM_T_SWQPT].res_u.mem_info;
- mem_info->mem_type = BNA_MEM_T_KVA;
- mem_info->len = page_count * sizeof(void *);
- mem_info->num = num_txq;
-
- res_info[BNA_TX_RES_MEM_T_PAGE].res_type = BNA_RES_T_MEM;
- mem_info = &res_info[BNA_TX_RES_MEM_T_PAGE].res_u.mem_info;
- mem_info->mem_type = BNA_MEM_T_DMA;
- mem_info->len = PAGE_SIZE;
- mem_info->num = num_txq * page_count;
-
- res_info[BNA_TX_RES_INTR_T_TXCMPL].res_type = BNA_RES_T_INTR;
- res_info[BNA_TX_RES_INTR_T_TXCMPL].res_u.intr_info.intr_type =
- BNA_INTR_T_MSIX;
- res_info[BNA_TX_RES_INTR_T_TXCMPL].res_u.intr_info.num = num_txq;
-}
-
-struct bna_tx *
-bna_tx_create(struct bna *bna, struct bnad *bnad,
- struct bna_tx_config *tx_cfg,
- struct bna_tx_event_cbfn *tx_cbfn,
- struct bna_res_info *res_info, void *priv)
-{
- struct bna_intr_info *intr_info;
- struct bna_tx_mod *tx_mod = &bna->tx_mod;
- struct bna_tx *tx;
- struct bna_txq *txq;
- struct list_head *qe;
- struct bna_ib_mod *ib_mod = &bna->ib_mod;
- struct bna_doorbell_qset *qset;
- struct bna_ib_config ib_config;
- int page_count;
- int page_size;
- int page_idx;
- int i;
- unsigned long off;
-
- intr_info = &res_info[BNA_TX_RES_INTR_T_TXCMPL].res_u.intr_info;
- page_count = (res_info[BNA_TX_RES_MEM_T_PAGE].res_u.mem_info.num) /
- tx_cfg->num_txq;
- page_size = res_info[BNA_TX_RES_MEM_T_PAGE].res_u.mem_info.len;
-
- /**
- * Get resources
- */
-
- if ((intr_info->num != 1) && (intr_info->num != tx_cfg->num_txq))
- return NULL;
-
- /* Tx */
-
- if (list_empty(&tx_mod->tx_free_q))
- return NULL;
- bfa_q_deq(&tx_mod->tx_free_q, &tx);
- bfa_q_qe_init(&tx->qe);
-
- /* TxQs */
-
- INIT_LIST_HEAD(&tx->txq_q);
- for (i = 0; i < tx_cfg->num_txq; i++) {
- if (list_empty(&tx_mod->txq_free_q))
- goto err_return;
-
- bfa_q_deq(&tx_mod->txq_free_q, &txq);
- bfa_q_qe_init(&txq->qe);
- list_add_tail(&txq->qe, &tx->txq_q);
- txq->ib = NULL;
- txq->ib_seg_offset = -1;
- txq->tx = tx;
- }
-
- /* IBs */
- i = 0;
- list_for_each(qe, &tx->txq_q) {
- txq = (struct bna_txq *)qe;
-
- if (intr_info->num == 1)
- txq->ib = bna_ib_get(ib_mod, intr_info->intr_type,
- intr_info->idl[0].vector);
- else
- txq->ib = bna_ib_get(ib_mod, intr_info->intr_type,
- intr_info->idl[i].vector);
-
- if (txq->ib == NULL)
- goto err_return;
-
- txq->ib_seg_offset = bna_ib_reserve_idx(txq->ib);
- if (txq->ib_seg_offset == -1)
- goto err_return;
-
- i++;
- }
-
- /*
- * Initialize
- */
-
- /* Tx */
-
- tx->tcb_setup_cbfn = tx_cbfn->tcb_setup_cbfn;
- tx->tcb_destroy_cbfn = tx_cbfn->tcb_destroy_cbfn;
- /* Following callbacks are mandatory */
- tx->tx_stall_cbfn = tx_cbfn->tx_stall_cbfn;
- tx->tx_resume_cbfn = tx_cbfn->tx_resume_cbfn;
- tx->tx_cleanup_cbfn = tx_cbfn->tx_cleanup_cbfn;
-
- list_add_tail(&tx->qe, &tx_mod->tx_active_q);
- tx->bna = bna;
- tx->priv = priv;
- tx->txq_stop_wc.wc_resume = bna_tx_cb_txq_stopped_all;
- tx->txq_stop_wc.wc_cbarg = tx;
- tx->txq_stop_wc.wc_count = 0;
-
- tx->type = tx_cfg->tx_type;
-
- tx->flags = 0;
- if (tx->bna->tx_mod.flags & BNA_TX_MOD_F_PORT_STARTED) {
- switch (tx->type) {
- case BNA_TX_T_REGULAR:
- if (!(tx->bna->tx_mod.flags &
- BNA_TX_MOD_F_PORT_LOOPBACK))
- tx->flags |= BNA_TX_F_PORT_STARTED;
- break;
- case BNA_TX_T_LOOPBACK:
- if (tx->bna->tx_mod.flags & BNA_TX_MOD_F_PORT_LOOPBACK)
- tx->flags |= BNA_TX_F_PORT_STARTED;
- break;
- }
- }
- if (tx->bna->tx_mod.cee_link)
- tx->flags |= BNA_TX_F_PRIO_LOCK;
-
- /* TxQ */
-
- i = 0;
- page_idx = 0;
- list_for_each(qe, &tx->txq_q) {
- txq = (struct bna_txq *)qe;
- txq->priority = tx_mod->priority;
- txq->tcb = (struct bna_tcb *)
- res_info[BNA_TX_RES_MEM_T_TCB].res_u.mem_info.mdl[i].kva;
- txq->tx_packets = 0;
- txq->tx_bytes = 0;
-
- /* IB */
-
- ib_config.coalescing_timeo = BFI_TX_COALESCING_TIMEO;
- ib_config.interpkt_timeo = 0; /* Not used */
- ib_config.interpkt_count = BFI_TX_INTERPKT_COUNT;
- ib_config.ctrl_flags = (BFI_IB_CF_INTER_PKT_DMA |
- BFI_IB_CF_INT_ENABLE |
- BFI_IB_CF_COALESCING_MODE);
- bna_ib_config(txq->ib, &ib_config);
-
- /* TCB */
-
- txq->tcb->producer_index = 0;
- txq->tcb->consumer_index = 0;
- txq->tcb->hw_consumer_index = (volatile u32 *)
- ((volatile u8 *)txq->ib->ib_seg_host_addr_kva +
- (txq->ib_seg_offset * BFI_IBIDX_SIZE));
- *(txq->tcb->hw_consumer_index) = 0;
- txq->tcb->q_depth = tx_cfg->txq_depth;
- txq->tcb->unmap_q = (void *)
- res_info[BNA_TX_RES_MEM_T_UNMAPQ].res_u.mem_info.mdl[i].kva;
- qset = (struct bna_doorbell_qset *)0;
- off = (unsigned long)&qset[txq->txq_id].txq[0];
- txq->tcb->q_dbell = off +
- BNA_GET_DOORBELL_BASE_ADDR(bna->pcidev.pci_bar_kva);
- txq->tcb->i_dbell = &txq->ib->door_bell;
- txq->tcb->intr_type = intr_info->intr_type;
- txq->tcb->intr_vector = (intr_info->num == 1) ?
- intr_info->idl[0].vector :
- intr_info->idl[i].vector;
- txq->tcb->txq = txq;
- txq->tcb->bnad = bnad;
- txq->tcb->id = i;
-
- /* QPT, SWQPT, Pages */
- bna_txq_qpt_setup(txq, page_count, page_size,
- &res_info[BNA_TX_RES_MEM_T_QPT].res_u.mem_info.mdl[i],
- &res_info[BNA_TX_RES_MEM_T_SWQPT].res_u.mem_info.mdl[i],
- &res_info[BNA_TX_RES_MEM_T_PAGE].
- res_u.mem_info.mdl[page_idx]);
- txq->tcb->page_idx = page_idx;
- txq->tcb->page_count = page_count;
- page_idx += page_count;
-
- /* Callback to bnad for setting up TCB */
- if (tx->tcb_setup_cbfn)
- (tx->tcb_setup_cbfn)(bna->bnad, txq->tcb);
-
- i++;
- }
-
- /* TxF */
-
- tx->txf.ctrl_flags = BFI_TXF_CF_ENABLE | BFI_TXF_CF_VLAN_WI_BASED;
- tx->txf.vlan = 0;
-
- /* Mbox element */
- bfa_q_qe_init(&tx->mbox_qe.qe);
-
- bfa_fsm_set_state(tx, bna_tx_sm_stopped);
-
- return tx;
-
-err_return:
- bna_tx_free(tx);
- return NULL;
-}
-
-void
-bna_tx_destroy(struct bna_tx *tx)
-{
- /* Callback to bnad for destroying TCB */
- if (tx->tcb_destroy_cbfn) {
- struct bna_txq *txq;
- struct list_head *qe;
-
- list_for_each(qe, &tx->txq_q) {
- txq = (struct bna_txq *)qe;
- (tx->tcb_destroy_cbfn)(tx->bna->bnad, txq->tcb);
- }
- }
-
- bna_tx_free(tx);
-}
-
-void
-bna_tx_enable(struct bna_tx *tx)
-{
- if (tx->fsm != (bfa_sm_t)bna_tx_sm_stopped)
- return;
-
- tx->flags |= BNA_TX_F_ENABLED;
-
- if (tx->flags & BNA_TX_F_PORT_STARTED)
- bfa_fsm_send_event(tx, TX_E_START);
-}
-
-void
-bna_tx_disable(struct bna_tx *tx, enum bna_cleanup_type type,
- void (*cbfn)(void *, struct bna_tx *, enum bna_cb_status))
-{
- if (type == BNA_SOFT_CLEANUP) {
- (*cbfn)(tx->bna->bnad, tx, BNA_CB_SUCCESS);
- return;
- }
-
- tx->stop_cbfn = cbfn;
- tx->stop_cbarg = tx->bna->bnad;
-
- tx->flags &= ~BNA_TX_F_ENABLED;
-
- bfa_fsm_send_event(tx, TX_E_STOP);
-}
-
-int
-bna_tx_state_get(struct bna_tx *tx)
-{
- return bfa_sm_to_state(tx_sm_table, tx->fsm);
-}
-
-void
-bna_tx_mod_init(struct bna_tx_mod *tx_mod, struct bna *bna,
- struct bna_res_info *res_info)
-{
- int i;
-
- tx_mod->bna = bna;
- tx_mod->flags = 0;
-
- tx_mod->tx = (struct bna_tx *)
- res_info[BNA_RES_MEM_T_TX_ARRAY].res_u.mem_info.mdl[0].kva;
- tx_mod->txq = (struct bna_txq *)
- res_info[BNA_RES_MEM_T_TXQ_ARRAY].res_u.mem_info.mdl[0].kva;
-
- INIT_LIST_HEAD(&tx_mod->tx_free_q);
- INIT_LIST_HEAD(&tx_mod->tx_active_q);
-
- INIT_LIST_HEAD(&tx_mod->txq_free_q);
-
- for (i = 0; i < BFI_MAX_TXQ; i++) {
- tx_mod->tx[i].txf.txf_id = i;
- bfa_q_qe_init(&tx_mod->tx[i].qe);
- list_add_tail(&tx_mod->tx[i].qe, &tx_mod->tx_free_q);
-
- tx_mod->txq[i].txq_id = i;
- bfa_q_qe_init(&tx_mod->txq[i].qe);
- list_add_tail(&tx_mod->txq[i].qe, &tx_mod->txq_free_q);
- }
-
- tx_mod->tx_stop_wc.wc_resume = bna_tx_mod_cb_tx_stopped_all;
- tx_mod->tx_stop_wc.wc_cbarg = tx_mod;
- tx_mod->tx_stop_wc.wc_count = 0;
-}
-
-void
-bna_tx_mod_uninit(struct bna_tx_mod *tx_mod)
-{
- struct list_head *qe;
- int i;
-
- i = 0;
- list_for_each(qe, &tx_mod->tx_free_q)
- i++;
-
- i = 0;
- list_for_each(qe, &tx_mod->txq_free_q)
- i++;
-
- tx_mod->bna = NULL;
-}
-
-void
-bna_tx_mod_start(struct bna_tx_mod *tx_mod, enum bna_tx_type type)
-{
- struct bna_tx *tx;
- struct list_head *qe;
-
- tx_mod->flags |= BNA_TX_MOD_F_PORT_STARTED;
- if (type == BNA_TX_T_LOOPBACK)
- tx_mod->flags |= BNA_TX_MOD_F_PORT_LOOPBACK;
-
- list_for_each(qe, &tx_mod->tx_active_q) {
- tx = (struct bna_tx *)qe;
- if (tx->type == type)
- bna_tx_start(tx);
- }
-}
-
-void
-bna_tx_mod_stop(struct bna_tx_mod *tx_mod, enum bna_tx_type type)
-{
- struct bna_tx *tx;
- struct list_head *qe;
-
- tx_mod->flags &= ~BNA_TX_MOD_F_PORT_STARTED;
- tx_mod->flags &= ~BNA_TX_MOD_F_PORT_LOOPBACK;
-
- tx_mod->stop_cbfn = bna_port_cb_tx_stopped;
-
- /**
- * Before calling bna_tx_stop(), increment tx_stop_wc as many times
- * as we are going to call bna_tx_stop
- */
- list_for_each(qe, &tx_mod->tx_active_q) {
- tx = (struct bna_tx *)qe;
- if (tx->type == type)
- bfa_wc_up(&tx_mod->tx_stop_wc);
- }
-
- if (tx_mod->tx_stop_wc.wc_count == 0) {
- tx_mod->stop_cbfn(&tx_mod->bna->port, BNA_CB_SUCCESS);
- tx_mod->stop_cbfn = NULL;
- return;
- }
-
- list_for_each(qe, &tx_mod->tx_active_q) {
- tx = (struct bna_tx *)qe;
- if (tx->type == type)
- bna_tx_stop(tx);
- }
-}
-
-void
-bna_tx_mod_fail(struct bna_tx_mod *tx_mod)
-{
- struct bna_tx *tx;
- struct list_head *qe;
-
- tx_mod->flags &= ~BNA_TX_MOD_F_PORT_STARTED;
- tx_mod->flags &= ~BNA_TX_MOD_F_PORT_LOOPBACK;
-
- list_for_each(qe, &tx_mod->tx_active_q) {
- tx = (struct bna_tx *)qe;
- bna_tx_fail(tx);
- }
-}
-
-void
-bna_tx_mod_prio_changed(struct bna_tx_mod *tx_mod, int prio)
-{
- struct bna_tx *tx;
- struct list_head *qe;
-
- if (prio != tx_mod->priority) {
- tx_mod->priority = prio;
-
- list_for_each(qe, &tx_mod->tx_active_q) {
- tx = (struct bna_tx *)qe;
- bna_tx_prio_changed(tx, prio);
- }
- }
-}
-
-void
-bna_tx_mod_cee_link_status(struct bna_tx_mod *tx_mod, int cee_link)
-{
- struct bna_tx *tx;
- struct list_head *qe;
-
- tx_mod->cee_link = cee_link;
-
- list_for_each(qe, &tx_mod->tx_active_q) {
- tx = (struct bna_tx *)qe;
- bna_tx_cee_link_status(tx, cee_link);
- }
-}
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index a047eb973e3b..b33c099d65a4 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -1135,13 +1135,6 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
__record_pdu(lacpdu, port);
port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(port->actor_oper_port_state & AD_STATE_LACP_TIMEOUT));
port->actor_oper_port_state &= ~AD_STATE_EXPIRED;
- // verify that if the aggregator is enabled, the port is enabled too.
- //(because if the link goes down for a short time, the 802.3ad will not
- // catch it, and the port will continue to be disabled)
- if (port->aggregator
- && port->aggregator->is_active
- && !__port_is_enabled(port))
- __enable_port(port);
break;
default: //to silence the compiler
break;
@@ -2168,7 +2161,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
}
re_arm:
- queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks);
+ if (!bond->kill_timers)
+ queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks);
out:
read_unlock(&bond->lock);
}
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 7f8b20a34ee3..d4fbd2e62616 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -1440,7 +1440,8 @@ void bond_alb_monitor(struct work_struct *work)
}
re_arm:
- queue_delayed_work(bond->wq, &bond->alb_work, alb_delta_in_ticks);
+ if (!bond->kill_timers)
+ queue_delayed_work(bond->wq, &bond->alb_work, alb_delta_in_ticks);
out:
read_unlock(&bond->lock);
}
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 38a83acd502e..71efff323941 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -557,7 +557,7 @@ down:
static int bond_update_speed_duplex(struct slave *slave)
{
struct net_device *slave_dev = slave->dev;
- struct ethtool_cmd etool = { .cmd = ETHTOOL_GSET };
+ struct ethtool_cmd ecmd;
u32 slave_speed;
int res;
@@ -565,18 +565,15 @@ static int bond_update_speed_duplex(struct slave *slave)
slave->speed = SPEED_100;
slave->duplex = DUPLEX_FULL;
- if (!slave_dev->ethtool_ops || !slave_dev->ethtool_ops->get_settings)
- return -1;
-
- res = slave_dev->ethtool_ops->get_settings(slave_dev, &etool);
+ res = __ethtool_get_settings(slave_dev, &ecmd);
if (res < 0)
return -1;
- slave_speed = ethtool_cmd_speed(&etool);
+ slave_speed = ethtool_cmd_speed(&ecmd);
if (slave_speed == 0 || slave_speed == ((__u32) -1))
return -1;
- switch (etool.duplex) {
+ switch (ecmd.duplex) {
case DUPLEX_FULL:
case DUPLEX_HALF:
break;
@@ -585,7 +582,7 @@ static int bond_update_speed_duplex(struct slave *slave)
}
slave->speed = slave_speed;
- slave->duplex = etool.duplex;
+ slave->duplex = ecmd.duplex;
return 0;
}
@@ -777,6 +774,9 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
read_lock(&bond->lock);
+ if (bond->kill_timers)
+ goto out;
+
/* rejoin all groups on bond device */
__bond_resend_igmp_join_requests(bond->dev);
@@ -790,9 +790,9 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
__bond_resend_igmp_join_requests(vlan_dev);
}
- if (--bond->igmp_retrans > 0)
+ if ((--bond->igmp_retrans > 0) && !bond->kill_timers)
queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5);
-
+out:
read_unlock(&bond->lock);
}
@@ -1432,6 +1432,8 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
struct sk_buff *skb = *pskb;
struct slave *slave;
struct bonding *bond;
+ void (*recv_probe)(struct sk_buff *, struct bonding *,
+ struct slave *);
skb = skb_share_check(skb, GFP_ATOMIC);
if (unlikely(!skb))
@@ -1445,11 +1447,12 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
if (bond->params.arp_interval)
slave->dev->last_rx = jiffies;
- if (bond->recv_probe) {
+ recv_probe = ACCESS_ONCE(bond->recv_probe);
+ if (recv_probe) {
struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
if (likely(nskb)) {
- bond->recv_probe(nskb, bond, slave);
+ recv_probe(nskb, bond, slave);
dev_kfree_skb(nskb);
}
}
@@ -2538,7 +2541,7 @@ void bond_mii_monitor(struct work_struct *work)
}
re_arm:
- if (bond->params.miimon)
+ if (bond->params.miimon && !bond->kill_timers)
queue_delayed_work(bond->wq, &bond->mii_work,
msecs_to_jiffies(bond->params.miimon));
out:
@@ -2886,7 +2889,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
}
re_arm:
- if (bond->params.arp_interval)
+ if (bond->params.arp_interval && !bond->kill_timers)
queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
out:
read_unlock(&bond->lock);
@@ -3154,7 +3157,7 @@ void bond_activebackup_arp_mon(struct work_struct *work)
bond_ab_arp_probe(bond);
re_arm:
- if (bond->params.arp_interval)
+ if (bond->params.arp_interval && !bond->kill_timers)
queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
out:
read_unlock(&bond->lock);
@@ -3419,9 +3422,27 @@ static int bond_xmit_hash_policy_l2(struct sk_buff *skb, int count)
static int bond_open(struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
+ struct slave *slave;
+ int i;
bond->kill_timers = 0;
+ /* reset slave->backup and slave->inactive */
+ read_lock(&bond->lock);
+ if (bond->slave_cnt > 0) {
+ read_lock(&bond->curr_slave_lock);
+ bond_for_each_slave(bond, slave, i) {
+ if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP)
+ && (slave != bond->curr_active_slave)) {
+ bond_set_slave_inactive_flags(slave);
+ } else {
+ bond_set_slave_active_flags(slave);
+ }
+ }
+ read_unlock(&bond->curr_slave_lock);
+ }
+ read_unlock(&bond->lock);
+
INIT_DELAYED_WORK(&bond->mcast_work, bond_resend_igmp_join_requests_delayed);
if (bond_is_lb(bond)) {
@@ -3686,44 +3707,27 @@ static bool bond_addr_in_mc_list(unsigned char *addr,
return false;
}
-static void bond_set_multicast_list(struct net_device *bond_dev)
+static void bond_change_rx_flags(struct net_device *bond_dev, int change)
{
struct bonding *bond = netdev_priv(bond_dev);
- struct netdev_hw_addr *ha;
- bool found;
- /*
- * Do promisc before checking multicast_mode
- */
- if ((bond_dev->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC))
- /*
- * FIXME: Need to handle the error when one of the multi-slaves
- * encounters error.
- */
- bond_set_promiscuity(bond, 1);
-
-
- if (!(bond_dev->flags & IFF_PROMISC) && (bond->flags & IFF_PROMISC))
- bond_set_promiscuity(bond, -1);
+ if (change & IFF_PROMISC)
+ bond_set_promiscuity(bond,
+ bond_dev->flags & IFF_PROMISC ? 1 : -1);
+ if (change & IFF_ALLMULTI)
+ bond_set_allmulti(bond,
+ bond_dev->flags & IFF_ALLMULTI ? 1 : -1);
+}
- /* set allmulti flag to slaves */
- if ((bond_dev->flags & IFF_ALLMULTI) && !(bond->flags & IFF_ALLMULTI))
- /*
- * FIXME: Need to handle the error when one of the multi-slaves
- * encounters error.
- */
- bond_set_allmulti(bond, 1);
-
-
- if (!(bond_dev->flags & IFF_ALLMULTI) && (bond->flags & IFF_ALLMULTI))
- bond_set_allmulti(bond, -1);
-
+static void bond_set_multicast_list(struct net_device *bond_dev)
+{
+ struct bonding *bond = netdev_priv(bond_dev);
+ struct netdev_hw_addr *ha;
+ bool found;
read_lock(&bond->lock);
- bond->flags = bond_dev->flags;
-
/* looking for addresses to add to slaves' mc list */
netdev_for_each_mc_addr(ha, bond_dev) {
found = bond_addr_in_mc_list(ha->addr, &bond->mc_list,
@@ -4282,7 +4286,8 @@ static const struct net_device_ops bond_netdev_ops = {
.ndo_select_queue = bond_select_queue,
.ndo_get_stats64 = bond_get_stats,
.ndo_do_ioctl = bond_do_ioctl,
- .ndo_set_multicast_list = bond_set_multicast_list,
+ .ndo_change_rx_flags = bond_change_rx_flags,
+ .ndo_set_rx_mode = bond_set_multicast_list,
.ndo_change_mtu = bond_change_mtu,
.ndo_set_mac_address = bond_set_mac_address,
.ndo_neigh_setup = bond_neigh_setup,
@@ -4828,11 +4833,20 @@ static int bond_validate(struct nlattr *tb[], struct nlattr *data[])
return 0;
}
+static int bond_get_tx_queues(struct net *net, struct nlattr *tb[],
+ unsigned int *num_queues,
+ unsigned int *real_num_queues)
+{
+ *num_queues = tx_queues;
+ return 0;
+}
+
static struct rtnl_link_ops bond_link_ops __read_mostly = {
.kind = "bond",
.priv_size = sizeof(struct bonding),
.setup = bond_setup,
.validate = bond_validate,
+ .get_tx_queues = bond_get_tx_queues,
};
/* Create a new bond based on the specified name and bonding parameters.
@@ -4877,6 +4891,7 @@ static int __net_init bond_net_init(struct net *net)
INIT_LIST_HEAD(&bn->dev_list);
bond_create_proc_dir(bn);
+ bond_create_sysfs(bn);
return 0;
}
@@ -4885,6 +4900,7 @@ static void __net_exit bond_net_exit(struct net *net)
{
struct bond_net *bn = net_generic(net, bond_net_id);
+ bond_destroy_sysfs(bn);
bond_destroy_proc_dir(bn);
}
@@ -4922,10 +4938,6 @@ static int __init bonding_init(void)
goto err;
}
- res = bond_create_sysfs();
- if (res)
- goto err;
-
register_netdevice_notifier(&bond_netdev_notifier);
register_inetaddr_notifier(&bond_inetaddr_notifier);
out:
@@ -4943,7 +4955,6 @@ static void __exit bonding_exit(void)
unregister_netdevice_notifier(&bond_netdev_notifier);
unregister_inetaddr_notifier(&bond_inetaddr_notifier);
- bond_destroy_sysfs();
bond_destroy_debugfs();
rtnl_link_unregister(&bond_link_ops);
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 2dfb4bf90087..5a20804fdece 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -55,8 +55,8 @@ static ssize_t bonding_show_bonds(struct class *cls,
struct class_attribute *attr,
char *buf)
{
- struct net *net = current->nsproxy->net_ns;
- struct bond_net *bn = net_generic(net, bond_net_id);
+ struct bond_net *bn =
+ container_of(attr, struct bond_net, class_attr_bonding_masters);
int res = 0;
struct bonding *bond;
@@ -79,9 +79,8 @@ static ssize_t bonding_show_bonds(struct class *cls,
return res;
}
-static struct net_device *bond_get_by_name(struct net *net, const char *ifname)
+static struct net_device *bond_get_by_name(struct bond_net *bn, const char *ifname)
{
- struct bond_net *bn = net_generic(net, bond_net_id);
struct bonding *bond;
list_for_each_entry(bond, &bn->dev_list, bond_list) {
@@ -103,7 +102,8 @@ static ssize_t bonding_store_bonds(struct class *cls,
struct class_attribute *attr,
const char *buffer, size_t count)
{
- struct net *net = current->nsproxy->net_ns;
+ struct bond_net *bn =
+ container_of(attr, struct bond_net, class_attr_bonding_masters);
char command[IFNAMSIZ + 1] = {0, };
char *ifname;
int rv, res = count;
@@ -116,7 +116,7 @@ static ssize_t bonding_store_bonds(struct class *cls,
if (command[0] == '+') {
pr_info("%s is being created...\n", ifname);
- rv = bond_create(net, ifname);
+ rv = bond_create(bn->net, ifname);
if (rv) {
if (rv == -EEXIST)
pr_info("%s already exists.\n", ifname);
@@ -128,7 +128,7 @@ static ssize_t bonding_store_bonds(struct class *cls,
struct net_device *bond_dev;
rtnl_lock();
- bond_dev = bond_get_by_name(net, ifname);
+ bond_dev = bond_get_by_name(bn, ifname);
if (bond_dev) {
pr_info("%s is being deleted...\n", ifname);
unregister_netdevice(bond_dev);
@@ -150,9 +150,24 @@ err_no_cmd:
return -EPERM;
}
+static const void *bonding_namespace(struct class *cls,
+ const struct class_attribute *attr)
+{
+ const struct bond_net *bn =
+ container_of(attr, struct bond_net, class_attr_bonding_masters);
+ return bn->net;
+}
+
/* class attribute for bond_masters file. This ends up in /sys/class/net */
-static CLASS_ATTR(bonding_masters, S_IWUSR | S_IRUGO,
- bonding_show_bonds, bonding_store_bonds);
+static const struct class_attribute class_attr_bonding_masters = {
+ .attr = {
+ .name = "bonding_masters",
+ .mode = S_IWUSR | S_IRUGO,
+ },
+ .show = bonding_show_bonds,
+ .store = bonding_store_bonds,
+ .namespace = bonding_namespace,
+};
int bond_create_slave_symlinks(struct net_device *master,
struct net_device *slave)
@@ -1655,11 +1670,14 @@ static struct attribute_group bonding_group = {
* Initialize sysfs. This sets up the bonding_masters file in
* /sys/class/net.
*/
-int bond_create_sysfs(void)
+int bond_create_sysfs(struct bond_net *bn)
{
int ret;
- ret = netdev_class_create_file(&class_attr_bonding_masters);
+ bn->class_attr_bonding_masters = class_attr_bonding_masters;
+ sysfs_attr_init(&bn->class_attr_bonding_masters.attr);
+
+ ret = netdev_class_create_file(&bn->class_attr_bonding_masters);
/*
* Permit multiple loads of the module by ignoring failures to
* create the bonding_masters sysfs file. Bonding devices
@@ -1673,7 +1691,7 @@ int bond_create_sysfs(void)
*/
if (ret == -EEXIST) {
/* Is someone being kinky and naming a device bonding_master? */
- if (__dev_get_by_name(&init_net,
+ if (__dev_get_by_name(bn->net,
class_attr_bonding_masters.attr.name))
pr_err("network device named %s already exists in sysfs",
class_attr_bonding_masters.attr.name);
@@ -1687,9 +1705,9 @@ int bond_create_sysfs(void)
/*
* Remove /sys/class/net/bonding_masters.
*/
-void bond_destroy_sysfs(void)
+void bond_destroy_sysfs(struct bond_net *bn)
{
- netdev_class_remove_file(&class_attr_bonding_masters);
+ netdev_class_remove_file(&bn->class_attr_bonding_masters);
}
/*
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 43526a2d275c..82fec5fc75d7 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -234,7 +234,6 @@ struct bonding {
struct netdev_hw_addr_list mc_list;
int (*xmit_hash_policy)(struct sk_buff *, int);
__be32 master_ip;
- u16 flags;
u16 rr_tx_counter;
struct ad_bond_info ad_info;
struct alb_bond_info alb_info;
@@ -380,11 +379,13 @@ static inline bool bond_is_slave_inactive(struct slave *slave)
return slave->inactive;
}
+struct bond_net;
+
struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr);
int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev);
int bond_create(struct net *net, const char *name);
-int bond_create_sysfs(void);
-void bond_destroy_sysfs(void);
+int bond_create_sysfs(struct bond_net *net);
+void bond_destroy_sysfs(struct bond_net *net);
void bond_prepare_sysfs_group(struct bonding *bond);
int bond_create_slave_symlinks(struct net_device *master, struct net_device *slave);
void bond_destroy_slave_symlinks(struct net_device *master, struct net_device *slave);
@@ -410,6 +411,7 @@ struct bond_net {
#ifdef CONFIG_PROC_FS
struct proc_dir_entry * proc_dir;
#endif
+ struct class_attribute class_attr_bonding_masters;
};
#ifdef CONFIG_PROC_FS
diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c
index b41c2fced0a7..073352517adc 100644
--- a/drivers/net/caif/caif_hsi.c
+++ b/drivers/net/caif/caif_hsi.c
@@ -18,6 +18,7 @@
#include <linux/sched.h>
#include <linux/if_arp.h>
#include <linux/timer.h>
+#include <linux/rtnetlink.h>
#include <net/caif/caif_layer.h>
#include <net/caif/caif_hsi.h>
@@ -29,6 +30,10 @@ MODULE_DESCRIPTION("CAIF HSI driver");
#define PAD_POW2(x, pow) ((((x)&((pow)-1)) == 0) ? 0 :\
(((pow)-((x)&((pow)-1)))))
+static int inactivity_timeout = 1000;
+module_param(inactivity_timeout, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(inactivity_timeout, "Inactivity timeout on HSI, ms.");
+
/*
* HSI padding options.
* Warning: must be a base of 2 (& operation used) and can not be zero !
@@ -98,7 +103,8 @@ static void cfhsi_abort_tx(struct cfhsi *cfhsi)
}
cfhsi->tx_state = CFHSI_TX_STATE_IDLE;
if (!test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
- mod_timer(&cfhsi->timer, jiffies + CFHSI_INACTIVITY_TOUT);
+ mod_timer(&cfhsi->timer,
+ jiffies + cfhsi->inactivity_timeout);
spin_unlock_bh(&cfhsi->lock);
}
@@ -145,7 +151,7 @@ static int cfhsi_flush_fifo(struct cfhsi *cfhsi)
}
ret = 5 * HZ;
- wait_event_interruptible_timeout(cfhsi->flush_fifo_wait,
+ ret = wait_event_interruptible_timeout(cfhsi->flush_fifo_wait,
!test_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits), ret);
if (ret < 0) {
@@ -178,6 +184,9 @@ static int cfhsi_tx_frm(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
if (!skb)
return 0;
+ /* Clear offset. */
+ desc->offset = 0;
+
/* Check if we can embed a CAIF frame. */
if (skb->len < CFHSI_MAX_EMB_FRM_SZ) {
struct caif_payload_info *info;
@@ -206,9 +215,7 @@ static int cfhsi_tx_frm(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
consume_skb(skb);
skb = NULL;
}
- } else
- /* Clear offset. */
- desc->offset = 0;
+ }
/* Create payload CAIF frames. */
pfrm = desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ;
@@ -271,16 +278,13 @@ static int cfhsi_tx_frm(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
return CFHSI_DESC_SZ + pld_len;
}
-static void cfhsi_tx_done_work(struct work_struct *work)
+static void cfhsi_tx_done(struct cfhsi *cfhsi)
{
- struct cfhsi *cfhsi = NULL;
struct cfhsi_desc *desc = NULL;
int len = 0;
int res;
- cfhsi = container_of(work, struct cfhsi, tx_done_work);
- dev_dbg(&cfhsi->ndev->dev, "%s.\n",
- __func__);
+ dev_dbg(&cfhsi->ndev->dev, "%s.\n", __func__);
if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
return;
@@ -303,14 +307,22 @@ static void cfhsi_tx_done_work(struct work_struct *work)
spin_unlock_bh(&cfhsi->lock);
/* Create HSI frame. */
- len = cfhsi_tx_frm(desc, cfhsi);
- if (!len) {
- cfhsi->tx_state = CFHSI_TX_STATE_IDLE;
- /* Start inactivity timer. */
- mod_timer(&cfhsi->timer,
- jiffies + CFHSI_INACTIVITY_TOUT);
- break;
- }
+ do {
+ len = cfhsi_tx_frm(desc, cfhsi);
+ if (!len) {
+ spin_lock_bh(&cfhsi->lock);
+ if (unlikely(skb_peek(&cfhsi->qhead))) {
+ spin_unlock_bh(&cfhsi->lock);
+ continue;
+ }
+ cfhsi->tx_state = CFHSI_TX_STATE_IDLE;
+ /* Start inactivity timer. */
+ mod_timer(&cfhsi->timer,
+ jiffies + cfhsi->inactivity_timeout);
+ spin_unlock_bh(&cfhsi->lock);
+ goto done;
+ }
+ } while (!len);
/* Set up new transfer. */
res = cfhsi->dev->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->dev);
@@ -319,6 +331,9 @@ static void cfhsi_tx_done_work(struct work_struct *work)
__func__, res);
}
} while (res < 0);
+
+done:
+ return;
}
static void cfhsi_tx_done_cb(struct cfhsi_drv *drv)
@@ -331,8 +346,7 @@ static void cfhsi_tx_done_cb(struct cfhsi_drv *drv)
if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
return;
-
- queue_work(cfhsi->wq, &cfhsi->tx_done_work);
+ cfhsi_tx_done(cfhsi);
}
static int cfhsi_rx_desc(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
@@ -346,14 +360,14 @@ static int cfhsi_rx_desc(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
(desc->offset > CFHSI_MAX_EMB_FRM_SZ)) {
dev_err(&cfhsi->ndev->dev, "%s: Invalid descriptor.\n",
__func__);
- return 0;
+ return -EPROTO;
}
/* Check for embedded CAIF frame. */
if (desc->offset) {
struct sk_buff *skb;
u8 *dst = NULL;
- int len = 0, retries = 0;
+ int len = 0;
pfrm = ((u8 *)desc) + desc->offset;
/* Remove offset padding. */
@@ -364,26 +378,19 @@ static int cfhsi_rx_desc(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
len |= ((*(pfrm+1)) << 8) & 0xFF00;
len += 2; /* Add FCS fields. */
+ /* Sanity check length of CAIF frame. */
+ if (unlikely(len > CFHSI_MAX_CAIF_FRAME_SZ)) {
+ dev_err(&cfhsi->ndev->dev, "%s: Invalid length.\n",
+ __func__);
+ return -EPROTO;
+ }
/* Allocate SKB (OK even in IRQ context). */
- skb = alloc_skb(len + 1, GFP_KERNEL);
- while (!skb) {
- retries++;
- schedule_timeout(1);
- skb = alloc_skb(len + 1, GFP_KERNEL);
- if (skb) {
- printk(KERN_WARNING "%s: slept for %u "
- "before getting memory\n",
- __func__, retries);
- break;
- }
- if (retries > HZ) {
- printk(KERN_ERR "%s: slept for 1HZ and "
- "did not get memory\n",
- __func__);
- cfhsi->ndev->stats.rx_dropped++;
- goto drop_frame;
- }
+ skb = alloc_skb(len + 1, GFP_ATOMIC);
+ if (!skb) {
+ dev_err(&cfhsi->ndev->dev, "%s: Out of memory !\n",
+ __func__);
+ return -ENOMEM;
}
caif_assert(skb != NULL);
@@ -409,7 +416,6 @@ static int cfhsi_rx_desc(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
cfhsi->ndev->stats.rx_bytes += len;
}
-drop_frame:
/* Calculate transfer length. */
plen = desc->cffrm_len;
while (nfrms < CFHSI_MAX_PKTS && *plen) {
@@ -422,13 +428,12 @@ drop_frame:
if (desc->header & CFHSI_PIGGY_DESC)
xfer_sz += CFHSI_DESC_SZ;
- if (xfer_sz % 4) {
+ if ((xfer_sz % 4) || (xfer_sz > (CFHSI_BUF_SZ_RX - CFHSI_DESC_SZ))) {
dev_err(&cfhsi->ndev->dev,
"%s: Invalid payload len: %d, ignored.\n",
__func__, xfer_sz);
- xfer_sz = 0;
+ return -EPROTO;
}
-
return xfer_sz;
}
@@ -444,23 +449,27 @@ static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
(desc->offset > CFHSI_MAX_EMB_FRM_SZ))) {
dev_err(&cfhsi->ndev->dev, "%s: Invalid descriptor.\n",
__func__);
- return -EINVAL;
+ return -EPROTO;
}
/* Set frame pointer to start of payload. */
pfrm = desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ;
plen = desc->cffrm_len;
+
+ /* Skip already processed frames. */
+ while (nfrms < cfhsi->rx_state.nfrms) {
+ pfrm += *plen;
+ rx_sz += *plen;
+ plen++;
+ nfrms++;
+ }
+
+ /* Parse payload. */
while (nfrms < CFHSI_MAX_PKTS && *plen) {
struct sk_buff *skb;
u8 *dst = NULL;
u8 *pcffrm = NULL;
- int len = 0, retries = 0;
-
- if (WARN_ON(desc->cffrm_len[nfrms] > CFHSI_MAX_PAYLOAD_SZ)) {
- dev_err(&cfhsi->ndev->dev, "%s: Invalid payload.\n",
- __func__);
- return -EINVAL;
- }
+ int len = 0;
/* CAIF frame starts after head padding. */
pcffrm = pfrm + *pfrm + 1;
@@ -470,25 +479,20 @@ static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
len |= ((*(pcffrm + 1)) << 8) & 0xFF00;
len += 2; /* Add FCS fields. */
+ /* Sanity check length of CAIF frames. */
+ if (unlikely(len > CFHSI_MAX_CAIF_FRAME_SZ)) {
+ dev_err(&cfhsi->ndev->dev, "%s: Invalid length.\n",
+ __func__);
+ return -EPROTO;
+ }
+
/* Allocate SKB (OK even in IRQ context). */
- skb = alloc_skb(len + 1, GFP_KERNEL);
- while (!skb) {
- retries++;
- schedule_timeout(1);
- skb = alloc_skb(len + 1, GFP_KERNEL);
- if (skb) {
- printk(KERN_WARNING "%s: slept for %u "
- "before getting memory\n",
- __func__, retries);
- break;
- }
- if (retries > HZ) {
- printk(KERN_ERR "%s: slept for 1HZ "
- "and did not get memory\n",
- __func__);
- cfhsi->ndev->stats.rx_dropped++;
- goto drop_frame;
- }
+ skb = alloc_skb(len + 1, GFP_ATOMIC);
+ if (!skb) {
+ dev_err(&cfhsi->ndev->dev, "%s: Out of memory !\n",
+ __func__);
+ cfhsi->rx_state.nfrms = nfrms;
+ return -ENOMEM;
}
caif_assert(skb != NULL);
@@ -512,7 +516,6 @@ static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
cfhsi->ndev->stats.rx_packets++;
cfhsi->ndev->stats.rx_bytes += len;
-drop_frame:
pfrm += *plen;
rx_sz += *plen;
plen++;
@@ -522,40 +525,56 @@ drop_frame:
return rx_sz;
}
-static void cfhsi_rx_done_work(struct work_struct *work)
+static void cfhsi_rx_done(struct cfhsi *cfhsi)
{
int res;
int desc_pld_len = 0;
- struct cfhsi *cfhsi = NULL;
struct cfhsi_desc *desc = NULL;
- cfhsi = container_of(work, struct cfhsi, rx_done_work);
desc = (struct cfhsi_desc *)cfhsi->rx_buf;
- dev_dbg(&cfhsi->ndev->dev, "%s: Kick timer if pending.\n",
- __func__);
+ dev_dbg(&cfhsi->ndev->dev, "%s\n", __func__);
if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
return;
/* Update inactivity timer if pending. */
- mod_timer_pending(&cfhsi->timer, jiffies + CFHSI_INACTIVITY_TOUT);
+ spin_lock_bh(&cfhsi->lock);
+ mod_timer_pending(&cfhsi->timer,
+ jiffies + cfhsi->inactivity_timeout);
+ spin_unlock_bh(&cfhsi->lock);
- if (cfhsi->rx_state == CFHSI_RX_STATE_DESC) {
+ if (cfhsi->rx_state.state == CFHSI_RX_STATE_DESC) {
desc_pld_len = cfhsi_rx_desc(desc, cfhsi);
+ if (desc_pld_len == -ENOMEM)
+ goto restart;
+ if (desc_pld_len == -EPROTO)
+ goto out_of_sync;
} else {
int pld_len;
- pld_len = cfhsi_rx_pld(desc, cfhsi);
+ if (!cfhsi->rx_state.piggy_desc) {
+ pld_len = cfhsi_rx_pld(desc, cfhsi);
+ if (pld_len == -ENOMEM)
+ goto restart;
+ if (pld_len == -EPROTO)
+ goto out_of_sync;
+ cfhsi->rx_state.pld_len = pld_len;
+ } else {
+ pld_len = cfhsi->rx_state.pld_len;
+ }
if ((pld_len > 0) && (desc->header & CFHSI_PIGGY_DESC)) {
struct cfhsi_desc *piggy_desc;
piggy_desc = (struct cfhsi_desc *)
(desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ +
pld_len);
+ cfhsi->rx_state.piggy_desc = true;
/* Extract piggy-backed descriptor. */
desc_pld_len = cfhsi_rx_desc(piggy_desc, cfhsi);
+ if (desc_pld_len == -ENOMEM)
+ goto restart;
/*
* Copy needed information from the piggy-backed
@@ -563,19 +582,22 @@ static void cfhsi_rx_done_work(struct work_struct *work)
*/
memcpy((u8 *)desc, (u8 *)piggy_desc,
CFHSI_DESC_SHORT_SZ);
+
+ if (desc_pld_len == -EPROTO)
+ goto out_of_sync;
}
}
+ memset(&cfhsi->rx_state, 0, sizeof(cfhsi->rx_state));
if (desc_pld_len) {
- cfhsi->rx_state = CFHSI_RX_STATE_PAYLOAD;
+ cfhsi->rx_state.state = CFHSI_RX_STATE_PAYLOAD;
cfhsi->rx_ptr = cfhsi->rx_buf + CFHSI_DESC_SZ;
cfhsi->rx_len = desc_pld_len;
} else {
- cfhsi->rx_state = CFHSI_RX_STATE_DESC;
+ cfhsi->rx_state.state = CFHSI_RX_STATE_DESC;
cfhsi->rx_ptr = cfhsi->rx_buf;
cfhsi->rx_len = CFHSI_DESC_SZ;
}
- clear_bit(CFHSI_PENDING_RX, &cfhsi->bits);
if (test_bit(CFHSI_AWAKE, &cfhsi->bits)) {
/* Set up new transfer. */
@@ -590,6 +612,33 @@ static void cfhsi_rx_done_work(struct work_struct *work)
cfhsi->ndev->stats.rx_dropped++;
}
}
+ return;
+
+restart:
+ if (++cfhsi->rx_state.retries > CFHSI_MAX_RX_RETRIES) {
+ dev_err(&cfhsi->ndev->dev, "%s: No memory available "
+ "in %d iterations.\n",
+ __func__, CFHSI_MAX_RX_RETRIES);
+ BUG();
+ }
+ mod_timer(&cfhsi->rx_slowpath_timer, jiffies + 1);
+ return;
+
+out_of_sync:
+ dev_err(&cfhsi->ndev->dev, "%s: Out of sync.\n", __func__);
+ print_hex_dump_bytes("--> ", DUMP_PREFIX_NONE,
+ cfhsi->rx_buf, CFHSI_DESC_SZ);
+ schedule_work(&cfhsi->out_of_sync_work);
+}
+
+static void cfhsi_rx_slowpath(unsigned long arg)
+{
+ struct cfhsi *cfhsi = (struct cfhsi *)arg;
+
+ dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+ __func__);
+
+ cfhsi_rx_done(cfhsi);
}
static void cfhsi_rx_done_cb(struct cfhsi_drv *drv)
@@ -603,12 +652,10 @@ static void cfhsi_rx_done_cb(struct cfhsi_drv *drv)
if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
return;
- set_bit(CFHSI_PENDING_RX, &cfhsi->bits);
-
if (test_and_clear_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits))
wake_up_interruptible(&cfhsi->flush_fifo_wait);
else
- queue_work(cfhsi->wq, &cfhsi->rx_done_work);
+ cfhsi_rx_done(cfhsi);
}
static void cfhsi_wake_up(struct work_struct *work)
@@ -627,6 +674,7 @@ static void cfhsi_wake_up(struct work_struct *work)
/* It happenes when wakeup is requested by
* both ends at the same time. */
clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
+ clear_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits);
return;
}
@@ -637,25 +685,53 @@ static void cfhsi_wake_up(struct work_struct *work)
__func__);
/* Wait for acknowledge. */
- ret = CFHSI_WAKEUP_TOUT;
- wait_event_interruptible_timeout(cfhsi->wake_up_wait,
- test_bit(CFHSI_WAKE_UP_ACK,
+ ret = CFHSI_WAKE_TOUT;
+ ret = wait_event_interruptible_timeout(cfhsi->wake_up_wait,
+ test_and_clear_bit(CFHSI_WAKE_UP_ACK,
&cfhsi->bits), ret);
if (unlikely(ret < 0)) {
/* Interrupted by signal. */
- dev_info(&cfhsi->ndev->dev, "%s: Signalled: %ld.\n",
+ dev_err(&cfhsi->ndev->dev, "%s: Signalled: %ld.\n",
__func__, ret);
+
clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
cfhsi->dev->cfhsi_wake_down(cfhsi->dev);
return;
} else if (!ret) {
+ bool ca_wake = false;
+ size_t fifo_occupancy = 0;
+
/* Wakeup timeout */
dev_err(&cfhsi->ndev->dev, "%s: Timeout.\n",
__func__);
+
+ /* Check FIFO to check if modem has sent something. */
+ WARN_ON(cfhsi->dev->cfhsi_fifo_occupancy(cfhsi->dev,
+ &fifo_occupancy));
+
+ dev_err(&cfhsi->ndev->dev, "%s: Bytes in FIFO: %u.\n",
+ __func__, (unsigned) fifo_occupancy);
+
+ /* Check if we misssed the interrupt. */
+ WARN_ON(cfhsi->dev->cfhsi_get_peer_wake(cfhsi->dev,
+ &ca_wake));
+
+ if (ca_wake) {
+ dev_err(&cfhsi->ndev->dev, "%s: CA Wake missed !.\n",
+ __func__);
+
+ /* Clear the CFHSI_WAKE_UP_ACK bit to prevent race. */
+ clear_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits);
+
+ /* Continue execution. */
+ goto wake_ack;
+ }
+
clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
cfhsi->dev->cfhsi_wake_down(cfhsi->dev);
return;
}
+wake_ack:
dev_dbg(&cfhsi->ndev->dev, "%s: Woken.\n",
__func__);
@@ -664,16 +740,11 @@ static void cfhsi_wake_up(struct work_struct *work)
clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
/* Resume read operation. */
- if (!test_bit(CFHSI_PENDING_RX, &cfhsi->bits)) {
- dev_dbg(&cfhsi->ndev->dev, "%s: Start RX.\n",
- __func__);
- res = cfhsi->dev->cfhsi_rx(cfhsi->rx_ptr,
- cfhsi->rx_len, cfhsi->dev);
- if (WARN_ON(res < 0)) {
- dev_err(&cfhsi->ndev->dev, "%s: RX error %d.\n",
- __func__, res);
- }
- }
+ dev_dbg(&cfhsi->ndev->dev, "%s: Start RX.\n", __func__);
+ res = cfhsi->dev->cfhsi_rx(cfhsi->rx_ptr, cfhsi->rx_len, cfhsi->dev);
+
+ if (WARN_ON(res < 0))
+ dev_err(&cfhsi->ndev->dev, "%s: RX err %d.\n", __func__, res);
/* Clear power up acknowledment. */
clear_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits);
@@ -686,7 +757,7 @@ static void cfhsi_wake_up(struct work_struct *work)
__func__);
/* Start inactivity timer. */
mod_timer(&cfhsi->timer,
- jiffies + CFHSI_INACTIVITY_TOUT);
+ jiffies + cfhsi->inactivity_timeout);
spin_unlock_bh(&cfhsi->lock);
return;
}
@@ -712,79 +783,81 @@ static void cfhsi_wake_up(struct work_struct *work)
"%s: Failed to create HSI frame: %d.\n",
__func__, len);
}
-
}
static void cfhsi_wake_down(struct work_struct *work)
{
long ret;
struct cfhsi *cfhsi = NULL;
- size_t fifo_occupancy;
+ size_t fifo_occupancy = 0;
+ int retry = CFHSI_WAKE_TOUT;
cfhsi = container_of(work, struct cfhsi, wake_down_work);
- dev_dbg(&cfhsi->ndev->dev, "%s.\n",
- __func__);
+ dev_dbg(&cfhsi->ndev->dev, "%s.\n", __func__);
if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
return;
- /* Check if there is something in FIFO. */
- if (WARN_ON(cfhsi->dev->cfhsi_fifo_occupancy(cfhsi->dev,
- &fifo_occupancy)))
- fifo_occupancy = 0;
-
- if (fifo_occupancy) {
- dev_dbg(&cfhsi->ndev->dev,
- "%s: %u words in RX FIFO, restart timer.\n",
- __func__, (unsigned) fifo_occupancy);
- spin_lock_bh(&cfhsi->lock);
- mod_timer(&cfhsi->timer,
- jiffies + CFHSI_INACTIVITY_TOUT);
- spin_unlock_bh(&cfhsi->lock);
- return;
- }
-
- /* Cancel pending RX requests */
- cfhsi->dev->cfhsi_rx_cancel(cfhsi->dev);
-
/* Deactivate wake line. */
cfhsi->dev->cfhsi_wake_down(cfhsi->dev);
/* Wait for acknowledge. */
- ret = CFHSI_WAKEUP_TOUT;
+ ret = CFHSI_WAKE_TOUT;
ret = wait_event_interruptible_timeout(cfhsi->wake_down_wait,
- test_bit(CFHSI_WAKE_DOWN_ACK,
- &cfhsi->bits),
- ret);
+ test_and_clear_bit(CFHSI_WAKE_DOWN_ACK,
+ &cfhsi->bits), ret);
if (ret < 0) {
/* Interrupted by signal. */
- dev_info(&cfhsi->ndev->dev, "%s: Signalled: %ld.\n",
+ dev_err(&cfhsi->ndev->dev, "%s: Signalled: %ld.\n",
__func__, ret);
return;
} else if (!ret) {
+ bool ca_wake = true;
+
/* Timeout */
- dev_err(&cfhsi->ndev->dev, "%s: Timeout.\n",
- __func__);
+ dev_err(&cfhsi->ndev->dev, "%s: Timeout.\n", __func__);
+
+ /* Check if we misssed the interrupt. */
+ WARN_ON(cfhsi->dev->cfhsi_get_peer_wake(cfhsi->dev,
+ &ca_wake));
+ if (!ca_wake)
+ dev_err(&cfhsi->ndev->dev, "%s: CA Wake missed !.\n",
+ __func__);
}
- /* Clear power down acknowledment. */
- clear_bit(CFHSI_WAKE_DOWN_ACK, &cfhsi->bits);
+ /* Check FIFO occupancy. */
+ while (retry) {
+ WARN_ON(cfhsi->dev->cfhsi_fifo_occupancy(cfhsi->dev,
+ &fifo_occupancy));
+
+ if (!fifo_occupancy)
+ break;
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1);
+ retry--;
+ }
+
+ if (!retry)
+ dev_err(&cfhsi->ndev->dev, "%s: FIFO Timeout.\n", __func__);
+
+ /* Clear AWAKE condition. */
clear_bit(CFHSI_AWAKE, &cfhsi->bits);
- /* Check if there is something in FIFO. */
- if (WARN_ON(cfhsi->dev->cfhsi_fifo_occupancy(cfhsi->dev,
- &fifo_occupancy)))
- fifo_occupancy = 0;
+ /* Cancel pending RX requests. */
+ cfhsi->dev->cfhsi_rx_cancel(cfhsi->dev);
- if (fifo_occupancy) {
- dev_dbg(&cfhsi->ndev->dev,
- "%s: %u words in RX FIFO, wakeup forced.\n",
- __func__, (unsigned) fifo_occupancy);
- if (!test_and_set_bit(CFHSI_WAKE_UP, &cfhsi->bits))
- queue_work(cfhsi->wq, &cfhsi->wake_up_work);
- } else
- dev_dbg(&cfhsi->ndev->dev, "%s: Done.\n",
- __func__);
+}
+
+static void cfhsi_out_of_sync(struct work_struct *work)
+{
+ struct cfhsi *cfhsi = NULL;
+
+ cfhsi = container_of(work, struct cfhsi, out_of_sync_work);
+
+ rtnl_lock();
+ dev_close(cfhsi->ndev);
+ rtnl_unlock();
}
static void cfhsi_wake_up_cb(struct cfhsi_drv *drv)
@@ -854,17 +927,15 @@ static int cfhsi_xmit(struct sk_buff *skb, struct net_device *dev)
start_xfer = 1;
}
- spin_unlock_bh(&cfhsi->lock);
-
- if (!start_xfer)
+ if (!start_xfer) {
+ spin_unlock_bh(&cfhsi->lock);
return 0;
+ }
/* Delete inactivity timer if started. */
-#ifdef CONFIG_SMP
timer_active = del_timer_sync(&cfhsi->timer);
-#else
- timer_active = del_timer(&cfhsi->timer);
-#endif /* CONFIG_SMP */
+
+ spin_unlock_bh(&cfhsi->lock);
if (timer_active) {
struct cfhsi_desc *desc = (struct cfhsi_desc *)cfhsi->tx_buf;
@@ -937,11 +1008,8 @@ int cfhsi_probe(struct platform_device *pdev)
int res;
ndev = alloc_netdev(sizeof(struct cfhsi), "cfhsi%d", cfhsi_setup);
- if (!ndev) {
- dev_err(&pdev->dev, "%s: alloc_netdev failed.\n",
- __func__);
+ if (!ndev)
return -ENODEV;
- }
cfhsi = netdev_priv(ndev);
cfhsi->ndev = ndev;
@@ -949,7 +1017,7 @@ int cfhsi_probe(struct platform_device *pdev)
/* Initialize state vaiables. */
cfhsi->tx_state = CFHSI_TX_STATE_IDLE;
- cfhsi->rx_state = CFHSI_RX_STATE_DESC;
+ cfhsi->rx_state.state = CFHSI_RX_STATE_DESC;
/* Set flow info */
cfhsi->flow_off_sent = 0;
@@ -969,8 +1037,6 @@ int cfhsi_probe(struct platform_device *pdev)
*/
cfhsi->tx_buf = kzalloc(CFHSI_BUF_SZ_TX, GFP_KERNEL);
if (!cfhsi->tx_buf) {
- dev_err(&ndev->dev, "%s: Failed to allocate TX buffer.\n",
- __func__);
res = -ENODEV;
goto err_alloc_tx;
}
@@ -981,13 +1047,23 @@ int cfhsi_probe(struct platform_device *pdev)
*/
cfhsi->rx_buf = kzalloc(CFHSI_BUF_SZ_RX, GFP_KERNEL);
if (!cfhsi->rx_buf) {
- dev_err(&ndev->dev, "%s: Failed to allocate RX buffer.\n",
- __func__);
res = -ENODEV;
goto err_alloc_rx;
}
- /* Initialize receive variables. */
+ /* Pre-calculate inactivity timeout. */
+ if (inactivity_timeout != -1) {
+ cfhsi->inactivity_timeout =
+ inactivity_timeout * HZ / 1000;
+ if (!cfhsi->inactivity_timeout)
+ cfhsi->inactivity_timeout = 1;
+ else if (cfhsi->inactivity_timeout > NEXT_TIMER_MAX_DELTA)
+ cfhsi->inactivity_timeout = NEXT_TIMER_MAX_DELTA;
+ } else {
+ cfhsi->inactivity_timeout = NEXT_TIMER_MAX_DELTA;
+ }
+
+ /* Initialize recieve vaiables. */
cfhsi->rx_ptr = cfhsi->rx_buf;
cfhsi->rx_len = CFHSI_DESC_SZ;
@@ -997,19 +1073,19 @@ int cfhsi_probe(struct platform_device *pdev)
/* Set up the driver. */
cfhsi->drv.tx_done_cb = cfhsi_tx_done_cb;
cfhsi->drv.rx_done_cb = cfhsi_rx_done_cb;
+ cfhsi->drv.wake_up_cb = cfhsi_wake_up_cb;
+ cfhsi->drv.wake_down_cb = cfhsi_wake_down_cb;
/* Initialize the work queues. */
INIT_WORK(&cfhsi->wake_up_work, cfhsi_wake_up);
INIT_WORK(&cfhsi->wake_down_work, cfhsi_wake_down);
- INIT_WORK(&cfhsi->rx_done_work, cfhsi_rx_done_work);
- INIT_WORK(&cfhsi->tx_done_work, cfhsi_tx_done_work);
+ INIT_WORK(&cfhsi->out_of_sync_work, cfhsi_out_of_sync);
/* Clear all bit fields. */
clear_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits);
clear_bit(CFHSI_WAKE_DOWN_ACK, &cfhsi->bits);
clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
clear_bit(CFHSI_AWAKE, &cfhsi->bits);
- clear_bit(CFHSI_PENDING_RX, &cfhsi->bits);
/* Create work thread. */
cfhsi->wq = create_singlethread_workqueue(pdev->name);
@@ -1029,6 +1105,10 @@ int cfhsi_probe(struct platform_device *pdev)
init_timer(&cfhsi->timer);
cfhsi->timer.data = (unsigned long)cfhsi;
cfhsi->timer.function = cfhsi_inactivity_tout;
+ /* Setup the slowpath RX timer. */
+ init_timer(&cfhsi->rx_slowpath_timer);
+ cfhsi->rx_slowpath_timer.data = (unsigned long)cfhsi;
+ cfhsi->rx_slowpath_timer.function = cfhsi_rx_slowpath;
/* Add CAIF HSI device to list. */
spin_lock(&cfhsi_list_lock);
@@ -1052,9 +1132,6 @@ int cfhsi_probe(struct platform_device *pdev)
goto err_net_reg;
}
- cfhsi->drv.wake_up_cb = cfhsi_wake_up_cb;
- cfhsi->drv.wake_down_cb = cfhsi_wake_down_cb;
-
/* Register network device. */
res = register_netdev(ndev);
if (res) {
@@ -1081,7 +1158,7 @@ int cfhsi_probe(struct platform_device *pdev)
return res;
}
-static void cfhsi_shutdown(struct cfhsi *cfhsi, bool remove_platform_dev)
+static void cfhsi_shutdown(struct cfhsi *cfhsi)
{
u8 *tx_buf, *rx_buf;
@@ -1091,28 +1168,17 @@ static void cfhsi_shutdown(struct cfhsi *cfhsi, bool remove_platform_dev)
/* going to shutdown driver */
set_bit(CFHSI_SHUTDOWN, &cfhsi->bits);
- if (remove_platform_dev) {
- /* Flush workqueue */
- flush_workqueue(cfhsi->wq);
-
- /* Notify device. */
- platform_device_unregister(cfhsi->pdev);
- }
-
/* Flush workqueue */
flush_workqueue(cfhsi->wq);
- /* Delete timer if pending */
-#ifdef CONFIG_SMP
+ /* Delete timers if pending */
del_timer_sync(&cfhsi->timer);
-#else
- del_timer(&cfhsi->timer);
-#endif /* CONFIG_SMP */
+ del_timer_sync(&cfhsi->rx_slowpath_timer);
/* Cancel pending RX request (if any) */
cfhsi->dev->cfhsi_rx_cancel(cfhsi->dev);
- /* Flush again and destroy workqueue */
+ /* Destroy workqueue */
destroy_workqueue(cfhsi->wq);
/* Store bufferes: will be freed later. */
@@ -1151,7 +1217,7 @@ int cfhsi_remove(struct platform_device *pdev)
spin_unlock(&cfhsi_list_lock);
/* Shutdown driver. */
- cfhsi_shutdown(cfhsi, false);
+ cfhsi_shutdown(cfhsi);
return 0;
}
@@ -1184,7 +1250,7 @@ static void __exit cfhsi_exit_module(void)
spin_unlock(&cfhsi_list_lock);
/* Shutdown driver. */
- cfhsi_shutdown(cfhsi, true);
+ cfhsi_shutdown(cfhsi);
spin_lock(&cfhsi_list_lock);
}
diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c
index 0f8defc73307..05e791f46aef 100644
--- a/drivers/net/caif/caif_spi.c
+++ b/drivers/net/caif/caif_spi.c
@@ -664,8 +664,6 @@ int cfspi_spi_probe(struct platform_device *pdev)
/* Allocate DMA buffers. */
cfspi->xfer.va_tx = dma_alloc(&cfspi->xfer.pa_tx);
if (!cfspi->xfer.va_tx) {
- printk(KERN_WARNING
- "CFSPI: failed to allocate dma TX buffer.\n");
res = -ENODEV;
goto err_dma_alloc_tx;
}
@@ -673,8 +671,6 @@ int cfspi_spi_probe(struct platform_device *pdev)
cfspi->xfer.va_rx = dma_alloc(&cfspi->xfer.pa_rx);
if (!cfspi->xfer.va_rx) {
- printk(KERN_WARNING
- "CFSPI: failed to allocate dma TX buffer.\n");
res = -ENODEV;
goto err_dma_alloc_rx;
}
diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
index 121ede663e20..044ea0647b04 100644
--- a/drivers/net/can/at91_can.c
+++ b/drivers/net/can/at91_can.c
@@ -8,8 +8,6 @@
* Public License ("GPL") version 2 as distributed in the 'COPYING'
* file from the main directory of the linux kernel source.
*
- * Send feedback to <socketcan-users@lists.berlios.de>
- *
*
* Your platform definition file should specify something like:
*
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c
index 9bf1116e5b5e..25695bde0549 100644
--- a/drivers/net/can/dev.c
+++ b/drivers/net/can/dev.c
@@ -150,7 +150,19 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
bt->prop_seg = tseg1 / 2;
bt->phase_seg1 = tseg1 - bt->prop_seg;
bt->phase_seg2 = tseg2;
- bt->sjw = 1;
+
+ /* check for sjw user settings */
+ if (!bt->sjw || !btc->sjw_max)
+ bt->sjw = 1;
+ else {
+ /* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
+ if (bt->sjw > btc->sjw_max)
+ bt->sjw = btc->sjw_max;
+ /* bt->sjw must not be higher than tseg2 */
+ if (tseg2 < bt->sjw)
+ bt->sjw = tseg2;
+ }
+
bt->brp = best_brp;
/* real bit-rate */
bt->bitrate = priv->clock.freq / (bt->brp * (tseg1 + tseg2 + 1));
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index 17678117ed69..e02337953f41 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -33,10 +33,9 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
-#include <mach/clock.h>
-
#define DRV_NAME "flexcan"
/* 8 for RX fifo and 2 error handling */
@@ -192,6 +191,31 @@ static struct can_bittiming_const flexcan_bittiming_const = {
};
/*
+ * Abstract off the read/write for arm versus ppc.
+ */
+#if defined(__BIG_ENDIAN)
+static inline u32 flexcan_read(void __iomem *addr)
+{
+ return in_be32(addr);
+}
+
+static inline void flexcan_write(u32 val, void __iomem *addr)
+{
+ out_be32(addr, val);
+}
+#else
+static inline u32 flexcan_read(void __iomem *addr)
+{
+ return readl(addr);
+}
+
+static inline void flexcan_write(u32 val, void __iomem *addr)
+{
+ writel(val, addr);
+}
+#endif
+
+/*
* Swtich transceiver on or off
*/
static void flexcan_transceiver_switch(const struct flexcan_priv *priv, int on)
@@ -212,9 +236,9 @@ static inline void flexcan_chip_enable(struct flexcan_priv *priv)
struct flexcan_regs __iomem *regs = priv->base;
u32 reg;
- reg = readl(&regs->mcr);
+ reg = flexcan_read(&regs->mcr);
reg &= ~FLEXCAN_MCR_MDIS;
- writel(reg, &regs->mcr);
+ flexcan_write(reg, &regs->mcr);
udelay(10);
}
@@ -224,9 +248,9 @@ static inline void flexcan_chip_disable(struct flexcan_priv *priv)
struct flexcan_regs __iomem *regs = priv->base;
u32 reg;
- reg = readl(&regs->mcr);
+ reg = flexcan_read(&regs->mcr);
reg |= FLEXCAN_MCR_MDIS;
- writel(reg, &regs->mcr);
+ flexcan_write(reg, &regs->mcr);
}
static int flexcan_get_berr_counter(const struct net_device *dev,
@@ -234,7 +258,7 @@ static int flexcan_get_berr_counter(const struct net_device *dev,
{
const struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->base;
- u32 reg = readl(&regs->ecr);
+ u32 reg = flexcan_read(&regs->ecr);
bec->txerr = (reg >> 0) & 0xff;
bec->rxerr = (reg >> 8) & 0xff;
@@ -268,15 +292,15 @@ static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (cf->can_dlc > 0) {
u32 data = be32_to_cpup((__be32 *)&cf->data[0]);
- writel(data, &regs->cantxfg[FLEXCAN_TX_BUF_ID].data[0]);
+ flexcan_write(data, &regs->cantxfg[FLEXCAN_TX_BUF_ID].data[0]);
}
if (cf->can_dlc > 3) {
u32 data = be32_to_cpup((__be32 *)&cf->data[4]);
- writel(data, &regs->cantxfg[FLEXCAN_TX_BUF_ID].data[1]);
+ flexcan_write(data, &regs->cantxfg[FLEXCAN_TX_BUF_ID].data[1]);
}
- writel(can_id, &regs->cantxfg[FLEXCAN_TX_BUF_ID].can_id);
- writel(ctrl, &regs->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl);
+ flexcan_write(can_id, &regs->cantxfg[FLEXCAN_TX_BUF_ID].can_id);
+ flexcan_write(ctrl, &regs->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl);
kfree_skb(skb);
@@ -464,8 +488,8 @@ static void flexcan_read_fifo(const struct net_device *dev,
struct flexcan_mb __iomem *mb = &regs->cantxfg[0];
u32 reg_ctrl, reg_id;
- reg_ctrl = readl(&mb->can_ctrl);
- reg_id = readl(&mb->can_id);
+ reg_ctrl = flexcan_read(&mb->can_ctrl);
+ reg_id = flexcan_read(&mb->can_id);
if (reg_ctrl & FLEXCAN_MB_CNT_IDE)
cf->can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG;
else
@@ -475,12 +499,12 @@ static void flexcan_read_fifo(const struct net_device *dev,
cf->can_id |= CAN_RTR_FLAG;
cf->can_dlc = get_can_dlc((reg_ctrl >> 16) & 0xf);
- *(__be32 *)(cf->data + 0) = cpu_to_be32(readl(&mb->data[0]));
- *(__be32 *)(cf->data + 4) = cpu_to_be32(readl(&mb->data[1]));
+ *(__be32 *)(cf->data + 0) = cpu_to_be32(flexcan_read(&mb->data[0]));
+ *(__be32 *)(cf->data + 4) = cpu_to_be32(flexcan_read(&mb->data[1]));
/* mark as read */
- writel(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, &regs->iflag1);
- readl(&regs->timer);
+ flexcan_write(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, &regs->iflag1);
+ flexcan_read(&regs->timer);
}
static int flexcan_read_frame(struct net_device *dev)
@@ -516,17 +540,17 @@ static int flexcan_poll(struct napi_struct *napi, int quota)
* The error bits are cleared on read,
* use saved value from irq handler.
*/
- reg_esr = readl(&regs->esr) | priv->reg_esr;
+ reg_esr = flexcan_read(&regs->esr) | priv->reg_esr;
/* handle state changes */
work_done += flexcan_poll_state(dev, reg_esr);
/* handle RX-FIFO */
- reg_iflag1 = readl(&regs->iflag1);
+ reg_iflag1 = flexcan_read(&regs->iflag1);
while (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE &&
work_done < quota) {
work_done += flexcan_read_frame(dev);
- reg_iflag1 = readl(&regs->iflag1);
+ reg_iflag1 = flexcan_read(&regs->iflag1);
}
/* report bus errors */
@@ -536,8 +560,8 @@ static int flexcan_poll(struct napi_struct *napi, int quota)
if (work_done < quota) {
napi_complete(napi);
/* enable IRQs */
- writel(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
- writel(priv->reg_ctrl_default, &regs->ctrl);
+ flexcan_write(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
+ flexcan_write(priv->reg_ctrl_default, &regs->ctrl);
}
return work_done;
@@ -551,9 +575,9 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
struct flexcan_regs __iomem *regs = priv->base;
u32 reg_iflag1, reg_esr;
- reg_iflag1 = readl(&regs->iflag1);
- reg_esr = readl(&regs->esr);
- writel(FLEXCAN_ESR_ERR_INT, &regs->esr); /* ACK err IRQ */
+ reg_iflag1 = flexcan_read(&regs->iflag1);
+ reg_esr = flexcan_read(&regs->esr);
+ flexcan_write(FLEXCAN_ESR_ERR_INT, &regs->esr); /* ACK err IRQ */
/*
* schedule NAPI in case of:
@@ -569,16 +593,16 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
* save them for later use.
*/
priv->reg_esr = reg_esr & FLEXCAN_ESR_ERR_BUS;
- writel(FLEXCAN_IFLAG_DEFAULT & ~FLEXCAN_IFLAG_RX_FIFO_AVAILABLE,
- &regs->imask1);
- writel(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
+ flexcan_write(FLEXCAN_IFLAG_DEFAULT &
+ ~FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, &regs->imask1);
+ flexcan_write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
&regs->ctrl);
napi_schedule(&priv->napi);
}
/* FIFO overflow */
if (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_OVERFLOW) {
- writel(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW, &regs->iflag1);
+ flexcan_write(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW, &regs->iflag1);
dev->stats.rx_over_errors++;
dev->stats.rx_errors++;
}
@@ -587,7 +611,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
if (reg_iflag1 & (1 << FLEXCAN_TX_BUF_ID)) {
/* tx_bytes is incremented in flexcan_start_xmit */
stats->tx_packets++;
- writel((1 << FLEXCAN_TX_BUF_ID), &regs->iflag1);
+ flexcan_write((1 << FLEXCAN_TX_BUF_ID), &regs->iflag1);
netif_wake_queue(dev);
}
@@ -601,7 +625,7 @@ static void flexcan_set_bittiming(struct net_device *dev)
struct flexcan_regs __iomem *regs = priv->base;
u32 reg;
- reg = readl(&regs->ctrl);
+ reg = flexcan_read(&regs->ctrl);
reg &= ~(FLEXCAN_CTRL_PRESDIV(0xff) |
FLEXCAN_CTRL_RJW(0x3) |
FLEXCAN_CTRL_PSEG1(0x7) |
@@ -625,11 +649,11 @@ static void flexcan_set_bittiming(struct net_device *dev)
reg |= FLEXCAN_CTRL_SMP;
dev_info(dev->dev.parent, "writing ctrl=0x%08x\n", reg);
- writel(reg, &regs->ctrl);
+ flexcan_write(reg, &regs->ctrl);
/* print chip status */
dev_dbg(dev->dev.parent, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__,
- readl(&regs->mcr), readl(&regs->ctrl));
+ flexcan_read(&regs->mcr), flexcan_read(&regs->ctrl));
}
/*
@@ -650,10 +674,10 @@ static int flexcan_chip_start(struct net_device *dev)
flexcan_chip_enable(priv);
/* soft reset */
- writel(FLEXCAN_MCR_SOFTRST, &regs->mcr);
+ flexcan_write(FLEXCAN_MCR_SOFTRST, &regs->mcr);
udelay(10);
- reg_mcr = readl(&regs->mcr);
+ reg_mcr = flexcan_read(&regs->mcr);
if (reg_mcr & FLEXCAN_MCR_SOFTRST) {
dev_err(dev->dev.parent,
"Failed to softreset can module (mcr=0x%08x)\n",
@@ -675,12 +699,12 @@ static int flexcan_chip_start(struct net_device *dev)
* choose format C
*
*/
- reg_mcr = readl(&regs->mcr);
+ reg_mcr = flexcan_read(&regs->mcr);
reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_FEN | FLEXCAN_MCR_HALT |
FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN |
FLEXCAN_MCR_IDAM_C;
dev_dbg(dev->dev.parent, "%s: writing mcr=0x%08x", __func__, reg_mcr);
- writel(reg_mcr, &regs->mcr);
+ flexcan_write(reg_mcr, &regs->mcr);
/*
* CTRL
@@ -698,7 +722,7 @@ static int flexcan_chip_start(struct net_device *dev)
* (FLEXCAN_CTRL_ERR_MSK), too. Otherwise we don't get any
* warning or bus passive interrupts.
*/
- reg_ctrl = readl(&regs->ctrl);
+ reg_ctrl = flexcan_read(&regs->ctrl);
reg_ctrl &= ~FLEXCAN_CTRL_TSYN;
reg_ctrl |= FLEXCAN_CTRL_BOFF_REC | FLEXCAN_CTRL_LBUF |
FLEXCAN_CTRL_ERR_STATE | FLEXCAN_CTRL_ERR_MSK;
@@ -706,38 +730,39 @@ static int flexcan_chip_start(struct net_device *dev)
/* save for later use */
priv->reg_ctrl_default = reg_ctrl;
dev_dbg(dev->dev.parent, "%s: writing ctrl=0x%08x", __func__, reg_ctrl);
- writel(reg_ctrl, &regs->ctrl);
+ flexcan_write(reg_ctrl, &regs->ctrl);
for (i = 0; i < ARRAY_SIZE(regs->cantxfg); i++) {
- writel(0, &regs->cantxfg[i].can_ctrl);
- writel(0, &regs->cantxfg[i].can_id);
- writel(0, &regs->cantxfg[i].data[0]);
- writel(0, &regs->cantxfg[i].data[1]);
+ flexcan_write(0, &regs->cantxfg[i].can_ctrl);
+ flexcan_write(0, &regs->cantxfg[i].can_id);
+ flexcan_write(0, &regs->cantxfg[i].data[0]);
+ flexcan_write(0, &regs->cantxfg[i].data[1]);
/* put MB into rx queue */
- writel(FLEXCAN_MB_CNT_CODE(0x4), &regs->cantxfg[i].can_ctrl);
+ flexcan_write(FLEXCAN_MB_CNT_CODE(0x4),
+ &regs->cantxfg[i].can_ctrl);
}
/* acceptance mask/acceptance code (accept everything) */
- writel(0x0, &regs->rxgmask);
- writel(0x0, &regs->rx14mask);
- writel(0x0, &regs->rx15mask);
+ flexcan_write(0x0, &regs->rxgmask);
+ flexcan_write(0x0, &regs->rx14mask);
+ flexcan_write(0x0, &regs->rx15mask);
flexcan_transceiver_switch(priv, 1);
/* synchronize with the can bus */
- reg_mcr = readl(&regs->mcr);
+ reg_mcr = flexcan_read(&regs->mcr);
reg_mcr &= ~FLEXCAN_MCR_HALT;
- writel(reg_mcr, &regs->mcr);
+ flexcan_write(reg_mcr, &regs->mcr);
priv->can.state = CAN_STATE_ERROR_ACTIVE;
/* enable FIFO interrupts */
- writel(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
+ flexcan_write(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
/* print chip status */
dev_dbg(dev->dev.parent, "%s: reading mcr=0x%08x ctrl=0x%08x\n",
- __func__, readl(&regs->mcr), readl(&regs->ctrl));
+ __func__, flexcan_read(&regs->mcr), flexcan_read(&regs->ctrl));
return 0;
@@ -759,12 +784,12 @@ static void flexcan_chip_stop(struct net_device *dev)
u32 reg;
/* Disable all interrupts */
- writel(0, &regs->imask1);
+ flexcan_write(0, &regs->imask1);
/* Disable + halt module */
- reg = readl(&regs->mcr);
+ reg = flexcan_read(&regs->mcr);
reg |= FLEXCAN_MCR_MDIS | FLEXCAN_MCR_HALT;
- writel(reg, &regs->mcr);
+ flexcan_write(reg, &regs->mcr);
flexcan_transceiver_switch(priv, 0);
priv->can.state = CAN_STATE_STOPPED;
@@ -856,24 +881,24 @@ static int __devinit register_flexcandev(struct net_device *dev)
/* select "bus clock", chip must be disabled */
flexcan_chip_disable(priv);
- reg = readl(&regs->ctrl);
+ reg = flexcan_read(&regs->ctrl);
reg |= FLEXCAN_CTRL_CLK_SRC;
- writel(reg, &regs->ctrl);
+ flexcan_write(reg, &regs->ctrl);
flexcan_chip_enable(priv);
/* set freeze, halt and activate FIFO, restrict register access */
- reg = readl(&regs->mcr);
+ reg = flexcan_read(&regs->mcr);
reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
FLEXCAN_MCR_FEN | FLEXCAN_MCR_SUPV;
- writel(reg, &regs->mcr);
+ flexcan_write(reg, &regs->mcr);
/*
* Currently we only support newer versions of this core
* featuring a RX FIFO. Older cores found on some Coldfire
* derivates are not yet supported.
*/
- reg = readl(&regs->mcr);
+ reg = flexcan_read(&regs->mcr);
if (!(reg & FLEXCAN_MCR_FEN)) {
dev_err(dev->dev.parent,
"Could not enable RX FIFO, unsupported core\n");
@@ -901,16 +926,29 @@ static int __devinit flexcan_probe(struct platform_device *pdev)
struct net_device *dev;
struct flexcan_priv *priv;
struct resource *mem;
- struct clk *clk;
+ struct clk *clk = NULL;
void __iomem *base;
resource_size_t mem_size;
int err, irq;
+ u32 clock_freq = 0;
+
+ if (pdev->dev.of_node) {
+ const u32 *clock_freq_p;
- clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(clk)) {
- dev_err(&pdev->dev, "no clock defined\n");
- err = PTR_ERR(clk);
- goto failed_clock;
+ clock_freq_p = of_get_property(pdev->dev.of_node,
+ "clock-frequency", NULL);
+ if (clock_freq_p)
+ clock_freq = *clock_freq_p;
+ }
+
+ if (!clock_freq) {
+ clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "no clock defined\n");
+ err = PTR_ERR(clk);
+ goto failed_clock;
+ }
+ clock_freq = clk_get_rate(clk);
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -943,7 +981,7 @@ static int __devinit flexcan_probe(struct platform_device *pdev)
dev->flags |= IFF_ECHO; /* we support local echo in hardware */
priv = netdev_priv(dev);
- priv->can.clock.freq = clk_get_rate(clk);
+ priv->can.clock.freq = clock_freq;
priv->can.bittiming_const = &flexcan_bittiming_const;
priv->can.do_set_mode = flexcan_set_mode;
priv->can.do_get_berr_counter = flexcan_get_berr_counter;
@@ -978,7 +1016,8 @@ static int __devinit flexcan_probe(struct platform_device *pdev)
failed_map:
release_mem_region(mem->start, mem_size);
failed_get:
- clk_put(clk);
+ if (clk)
+ clk_put(clk);
failed_clock:
return err;
}
@@ -996,15 +1035,27 @@ static int __devexit flexcan_remove(struct platform_device *pdev)
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(mem->start, resource_size(mem));
- clk_put(priv->clk);
+ if (priv->clk)
+ clk_put(priv->clk);
free_candev(dev);
return 0;
}
+static struct of_device_id flexcan_of_match[] = {
+ {
+ .compatible = "fsl,p1010-flexcan",
+ },
+ {},
+};
+
static struct platform_driver flexcan_driver = {
- .driver.name = DRV_NAME,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = flexcan_of_match,
+ },
.probe = flexcan_probe,
.remove = __devexit_p(flexcan_remove),
};
diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c
index 92feac68b66e..ec4a3119e2c9 100644
--- a/drivers/net/can/mscan/mscan.c
+++ b/drivers/net/can/mscan/mscan.c
@@ -62,7 +62,7 @@ static enum can_state state_map[] = {
static int mscan_set_mode(struct net_device *dev, u8 mode)
{
struct mscan_priv *priv = netdev_priv(dev);
- struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ struct mscan_regs __iomem *regs = priv->reg_base;
int ret = 0;
int i;
u8 canctl1;
@@ -138,7 +138,7 @@ static int mscan_set_mode(struct net_device *dev, u8 mode)
static int mscan_start(struct net_device *dev)
{
struct mscan_priv *priv = netdev_priv(dev);
- struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ struct mscan_regs __iomem *regs = priv->reg_base;
u8 canrflg;
int err;
@@ -178,7 +178,7 @@ static int mscan_restart(struct net_device *dev)
struct mscan_priv *priv = netdev_priv(dev);
if (priv->type == MSCAN_TYPE_MPC5121) {
- struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ struct mscan_regs __iomem *regs = priv->reg_base;
priv->can.state = CAN_STATE_ERROR_ACTIVE;
WARN(!(in_8(&regs->canmisc) & MSCAN_BOHOLD),
@@ -199,7 +199,7 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct can_frame *frame = (struct can_frame *)skb->data;
struct mscan_priv *priv = netdev_priv(dev);
- struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ struct mscan_regs __iomem *regs = priv->reg_base;
int i, rtr, buf_id;
u32 can_id;
@@ -261,11 +261,13 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)
void __iomem *data = &regs->tx.dsr1_0;
u16 *payload = (u16 *)frame->data;
- /* It is safe to write into dsr[dlc+1] */
- for (i = 0; i < (frame->can_dlc + 1) / 2; i++) {
+ for (i = 0; i < frame->can_dlc / 2; i++) {
out_be16(data, *payload++);
data += 2 + _MSCAN_RESERVED_DSR_SIZE;
}
+ /* write remaining byte if necessary */
+ if (frame->can_dlc & 1)
+ out_8(data, frame->data[frame->can_dlc - 1]);
}
out_8(&regs->tx.dlr, frame->can_dlc);
@@ -305,7 +307,7 @@ static enum can_state check_set_state(struct net_device *dev, u8 canrflg)
static void mscan_get_rx_frame(struct net_device *dev, struct can_frame *frame)
{
struct mscan_priv *priv = netdev_priv(dev);
- struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ struct mscan_regs __iomem *regs = priv->reg_base;
u32 can_id;
int i;
@@ -330,10 +332,13 @@ static void mscan_get_rx_frame(struct net_device *dev, struct can_frame *frame)
void __iomem *data = &regs->rx.dsr1_0;
u16 *payload = (u16 *)frame->data;
- for (i = 0; i < (frame->can_dlc + 1) / 2; i++) {
+ for (i = 0; i < frame->can_dlc / 2; i++) {
*payload++ = in_be16(data);
data += 2 + _MSCAN_RESERVED_DSR_SIZE;
}
+ /* read remaining byte if necessary */
+ if (frame->can_dlc & 1)
+ frame->data[frame->can_dlc - 1] = in_8(data);
}
out_8(&regs->canrflg, MSCAN_RXF);
@@ -343,7 +348,7 @@ static void mscan_get_err_frame(struct net_device *dev, struct can_frame *frame,
u8 canrflg)
{
struct mscan_priv *priv = netdev_priv(dev);
- struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ struct mscan_regs __iomem *regs = priv->reg_base;
struct net_device_stats *stats = &dev->stats;
enum can_state old_state;
@@ -406,7 +411,7 @@ static int mscan_rx_poll(struct napi_struct *napi, int quota)
{
struct mscan_priv *priv = container_of(napi, struct mscan_priv, napi);
struct net_device *dev = napi->dev;
- struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ struct mscan_regs __iomem *regs = priv->reg_base;
struct net_device_stats *stats = &dev->stats;
int npackets = 0;
int ret = 1;
@@ -453,7 +458,7 @@ static irqreturn_t mscan_isr(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
struct mscan_priv *priv = netdev_priv(dev);
- struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ struct mscan_regs __iomem *regs = priv->reg_base;
struct net_device_stats *stats = &dev->stats;
u8 cantier, cantflg, canrflg;
irqreturn_t ret = IRQ_NONE;
@@ -537,7 +542,7 @@ static int mscan_do_set_mode(struct net_device *dev, enum can_mode mode)
static int mscan_do_set_bittiming(struct net_device *dev)
{
struct mscan_priv *priv = netdev_priv(dev);
- struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ struct mscan_regs __iomem *regs = priv->reg_base;
struct can_bittiming *bt = &priv->can.bittiming;
u8 btr0, btr1;
@@ -559,7 +564,7 @@ static int mscan_open(struct net_device *dev)
{
int ret;
struct mscan_priv *priv = netdev_priv(dev);
- struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ struct mscan_regs __iomem *regs = priv->reg_base;
/* common open */
ret = open_candev(dev);
@@ -598,7 +603,7 @@ exit_napi_disable:
static int mscan_close(struct net_device *dev)
{
struct mscan_priv *priv = netdev_priv(dev);
- struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ struct mscan_regs __iomem *regs = priv->reg_base;
netif_stop_queue(dev);
napi_disable(&priv->napi);
@@ -622,7 +627,7 @@ static const struct net_device_ops mscan_netdev_ops = {
int register_mscandev(struct net_device *dev, int mscan_clksrc)
{
struct mscan_priv *priv = netdev_priv(dev);
- struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ struct mscan_regs __iomem *regs = priv->reg_base;
u8 ctl1;
ctl1 = in_8(&regs->canctl1);
@@ -659,7 +664,7 @@ int register_mscandev(struct net_device *dev, int mscan_clksrc)
void unregister_mscandev(struct net_device *dev)
{
struct mscan_priv *priv = netdev_priv(dev);
- struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ struct mscan_regs __iomem *regs = priv->reg_base;
mscan_set_mode(dev, MSCAN_INIT_MODE);
clrbits8(&regs->canctl1, MSCAN_CANE);
unregister_candev(dev);
diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig
index 6fdc031daaae..fe9e64d476eb 100644
--- a/drivers/net/can/sja1000/Kconfig
+++ b/drivers/net/can/sja1000/Kconfig
@@ -29,6 +29,13 @@ config CAN_SJA1000_OF_PLATFORM
OpenFirmware bindings, e.g. if you have a PowerPC based system
you may want to enable this option.
+config CAN_EMS_PCMCIA
+ tristate "EMS CPC-CARD Card"
+ depends on PCMCIA
+ ---help---
+ This driver is for the one or two channel CPC-CARD cards from
+ EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
+
config CAN_EMS_PCI
tristate "EMS CPC-PCI, CPC-PCIe and CPC-104P Card"
depends on PCI
@@ -37,6 +44,13 @@ config CAN_EMS_PCI
CPC-PCIe and CPC-104P cards from EMS Dr. Thomas Wuensche
(http://www.ems-wuensche.de).
+config CAN_PEAK_PCI
+ tristate "PEAK PCAN PCI/PCIe Cards"
+ depends on PCI
+ ---help---
+ This driver is for the PCAN PCI/PCIe cards (1, 2, 3 or 4 channels)
+ from PEAK Systems (http://www.peak-system.com).
+
config CAN_KVASER_PCI
tristate "Kvaser PCIcanx and Kvaser PCIcan PCI Cards"
depends on PCI
diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile
index 2c591eb321c7..0604f240c8b1 100644
--- a/drivers/net/can/sja1000/Makefile
+++ b/drivers/net/can/sja1000/Makefile
@@ -6,8 +6,10 @@ obj-$(CONFIG_CAN_SJA1000) += sja1000.o
obj-$(CONFIG_CAN_SJA1000_ISA) += sja1000_isa.o
obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o
obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o
+obj-$(CONFIG_CAN_EMS_PCMCIA) += ems_pcmcia.o
obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o
obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o
+obj-$(CONFIG_CAN_PEAK_PCI) += peak_pci.o
obj-$(CONFIG_CAN_PLX_PCI) += plx_pci.o
obj-$(CONFIG_CAN_TSCAN1) += tscan1.o
diff --git a/drivers/net/can/sja1000/ems_pcmcia.c b/drivers/net/can/sja1000/ems_pcmcia.c
new file mode 100644
index 000000000000..075a5457a190
--- /dev/null
+++ b/drivers/net/can/sja1000/ems_pcmcia.c
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2008 Sebastian Haas (initial chardev implementation)
+ * Copyright (C) 2010 Markus Plessing <plessing@ems-wuensche.com>
+ * Rework for mainline by Oliver Hartkopp <socketcan@hartkopp.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include "sja1000.h"
+
+#define DRV_NAME "ems_pcmcia"
+
+MODULE_AUTHOR("Markus Plessing <plessing@ems-wuensche.com>");
+MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-CARD cards");
+MODULE_SUPPORTED_DEVICE("EMS CPC-CARD CAN card");
+MODULE_LICENSE("GPL v2");
+
+#define EMS_PCMCIA_MAX_CHAN 2
+
+struct ems_pcmcia_card {
+ int channels;
+ struct pcmcia_device *pcmcia_dev;
+ struct net_device *net_dev[EMS_PCMCIA_MAX_CHAN];
+ void __iomem *base_addr;
+};
+
+#define EMS_PCMCIA_CAN_CLOCK (16000000 / 2)
+
+/*
+ * The board configuration is probably following:
+ * RX1 is connected to ground.
+ * TX1 is not connected.
+ * CLKO is not connected.
+ * Setting the OCR register to 0xDA is a good idea.
+ * This means normal output mode , push-pull and the correct polarity.
+ */
+#define EMS_PCMCIA_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
+
+/*
+ * In the CDR register, you should set CBP to 1.
+ * You will probably also want to set the clock divider value to 7
+ * (meaning direct oscillator output) because the second SJA1000 chip
+ * is driven by the first one CLKOUT output.
+ */
+#define EMS_PCMCIA_CDR (CDR_CBP | CDR_CLKOUT_MASK)
+#define EMS_PCMCIA_MEM_SIZE 4096 /* Size of the remapped io-memory */
+#define EMS_PCMCIA_CAN_BASE_OFFSET 0x100 /* Offset where controllers starts */
+#define EMS_PCMCIA_CAN_CTRL_SIZE 0x80 /* Memory size for each controller */
+
+#define EMS_CMD_RESET 0x00 /* Perform a reset of the card */
+#define EMS_CMD_MAP 0x03 /* Map CAN controllers into card' memory */
+#define EMS_CMD_UMAP 0x02 /* Unmap CAN controllers from card' memory */
+
+static struct pcmcia_device_id ems_pcmcia_tbl[] = {
+ PCMCIA_DEVICE_PROD_ID123("EMS_T_W", "CPC-Card", "V2.0", 0xeab1ea23,
+ 0xa338573f, 0xe4575800),
+ PCMCIA_DEVICE_NULL,
+};
+
+MODULE_DEVICE_TABLE(pcmcia, ems_pcmcia_tbl);
+
+static u8 ems_pcmcia_read_reg(const struct sja1000_priv *priv, int port)
+{
+ return readb(priv->reg_base + port);
+}
+
+static void ems_pcmcia_write_reg(const struct sja1000_priv *priv, int port,
+ u8 val)
+{
+ writeb(val, priv->reg_base + port);
+}
+
+static irqreturn_t ems_pcmcia_interrupt(int irq, void *dev_id)
+{
+ struct ems_pcmcia_card *card = dev_id;
+ struct net_device *dev;
+ irqreturn_t retval = IRQ_NONE;
+ int i, again;
+
+ /* Card not present */
+ if (readw(card->base_addr) != 0xAA55)
+ return IRQ_HANDLED;
+
+ do {
+ again = 0;
+
+ /* Check interrupt for each channel */
+ for (i = 0; i < card->channels; i++) {
+ dev = card->net_dev[i];
+ if (!dev)
+ continue;
+
+ if (sja1000_interrupt(irq, dev) == IRQ_HANDLED)
+ again = 1;
+ }
+ /* At least one channel handled the interrupt */
+ if (again)
+ retval = IRQ_HANDLED;
+
+ } while (again);
+
+ return retval;
+}
+
+/*
+ * Check if a CAN controller is present at the specified location
+ * by trying to set 'em into the PeliCAN mode
+ */
+static inline int ems_pcmcia_check_chan(struct sja1000_priv *priv)
+{
+ /* Make sure SJA1000 is in reset mode */
+ ems_pcmcia_write_reg(priv, REG_MOD, 1);
+ ems_pcmcia_write_reg(priv, REG_CDR, CDR_PELICAN);
+
+ /* read reset-values */
+ if (ems_pcmcia_read_reg(priv, REG_CDR) == CDR_PELICAN)
+ return 1;
+
+ return 0;
+}
+
+static void ems_pcmcia_del_card(struct pcmcia_device *pdev)
+{
+ struct ems_pcmcia_card *card = pdev->priv;
+ struct net_device *dev;
+ int i;
+
+ free_irq(pdev->irq, card);
+
+ for (i = 0; i < card->channels; i++) {
+ dev = card->net_dev[i];
+ if (!dev)
+ continue;
+
+ printk(KERN_INFO "%s: removing %s on channel #%d\n",
+ DRV_NAME, dev->name, i);
+ unregister_sja1000dev(dev);
+ free_sja1000dev(dev);
+ }
+
+ writeb(EMS_CMD_UMAP, card->base_addr);
+ iounmap(card->base_addr);
+ kfree(card);
+
+ pdev->priv = NULL;
+}
+
+/*
+ * Probe PCI device for EMS CAN signature and register each available
+ * CAN channel to SJA1000 Socket-CAN subsystem.
+ */
+static int __devinit ems_pcmcia_add_card(struct pcmcia_device *pdev,
+ unsigned long base)
+{
+ struct sja1000_priv *priv;
+ struct net_device *dev;
+ struct ems_pcmcia_card *card;
+ int err, i;
+
+ /* Allocating card structures to hold addresses, ... */
+ card = kzalloc(sizeof(struct ems_pcmcia_card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ pdev->priv = card;
+ card->channels = 0;
+
+ card->base_addr = ioremap(base, EMS_PCMCIA_MEM_SIZE);
+ if (!card->base_addr) {
+ err = -ENOMEM;
+ goto failure_cleanup;
+ }
+
+ /* Check for unique EMS CAN signature */
+ if (readw(card->base_addr) != 0xAA55) {
+ err = -ENODEV;
+ goto failure_cleanup;
+ }
+
+ /* Request board reset */
+ writeb(EMS_CMD_RESET, card->base_addr);
+
+ /* Make sure CAN controllers are mapped into card's memory space */
+ writeb(EMS_CMD_MAP, card->base_addr);
+
+ /* Detect available channels */
+ for (i = 0; i < EMS_PCMCIA_MAX_CHAN; i++) {
+ dev = alloc_sja1000dev(0);
+ if (!dev) {
+ err = -ENOMEM;
+ goto failure_cleanup;
+ }
+
+ card->net_dev[i] = dev;
+ priv = netdev_priv(dev);
+ priv->priv = card;
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ priv->irq_flags = IRQF_SHARED;
+ dev->irq = pdev->irq;
+ priv->reg_base = card->base_addr + EMS_PCMCIA_CAN_BASE_OFFSET +
+ (i * EMS_PCMCIA_CAN_CTRL_SIZE);
+
+ /* Check if channel is present */
+ if (ems_pcmcia_check_chan(priv)) {
+ priv->read_reg = ems_pcmcia_read_reg;
+ priv->write_reg = ems_pcmcia_write_reg;
+ priv->can.clock.freq = EMS_PCMCIA_CAN_CLOCK;
+ priv->ocr = EMS_PCMCIA_OCR;
+ priv->cdr = EMS_PCMCIA_CDR;
+ priv->flags |= SJA1000_CUSTOM_IRQ_HANDLER;
+
+ /* Register SJA1000 device */
+ err = register_sja1000dev(dev);
+ if (err) {
+ free_sja1000dev(dev);
+ goto failure_cleanup;
+ }
+
+ card->channels++;
+
+ printk(KERN_INFO "%s: registered %s on channel "
+ "#%d at 0x%p, irq %d\n", DRV_NAME, dev->name,
+ i, priv->reg_base, dev->irq);
+ } else
+ free_sja1000dev(dev);
+ }
+
+ err = request_irq(dev->irq, &ems_pcmcia_interrupt, IRQF_SHARED,
+ DRV_NAME, card);
+ if (!err)
+ return 0;
+
+failure_cleanup:
+ ems_pcmcia_del_card(pdev);
+ return err;
+}
+
+/*
+ * Setup PCMCIA socket and probe for EMS CPC-CARD
+ */
+static int __devinit ems_pcmcia_probe(struct pcmcia_device *dev)
+{
+ int csval;
+
+ /* General socket configuration */
+ dev->config_flags |= CONF_ENABLE_IRQ;
+ dev->config_index = 1;
+ dev->config_regs = PRESENT_OPTION;
+
+ /* The io structure describes IO port mapping */
+ dev->resource[0]->end = 16;
+ dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+ dev->resource[1]->end = 16;
+ dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_16;
+ dev->io_lines = 5;
+
+ /* Allocate a memory window */
+ dev->resource[2]->flags =
+ (WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE);
+ dev->resource[2]->start = dev->resource[2]->end = 0;
+
+ csval = pcmcia_request_window(dev, dev->resource[2], 0);
+ if (csval) {
+ dev_err(&dev->dev, "pcmcia_request_window failed (err=%d)\n",
+ csval);
+ return 0;
+ }
+
+ csval = pcmcia_map_mem_page(dev, dev->resource[2], dev->config_base);
+ if (csval) {
+ dev_err(&dev->dev, "pcmcia_map_mem_page failed (err=%d)\n",
+ csval);
+ return 0;
+ }
+
+ csval = pcmcia_enable_device(dev);
+ if (csval) {
+ dev_err(&dev->dev, "pcmcia_enable_device failed (err=%d)\n",
+ csval);
+ return 0;
+ }
+
+ ems_pcmcia_add_card(dev, dev->resource[2]->start);
+ return 0;
+}
+
+/*
+ * Release claimed resources
+ */
+static void ems_pcmcia_remove(struct pcmcia_device *dev)
+{
+ ems_pcmcia_del_card(dev);
+ pcmcia_disable_device(dev);
+}
+
+static struct pcmcia_driver ems_pcmcia_driver = {
+ .name = DRV_NAME,
+ .probe = ems_pcmcia_probe,
+ .remove = ems_pcmcia_remove,
+ .id_table = ems_pcmcia_tbl,
+};
+
+static int __init ems_pcmcia_init(void)
+{
+ return pcmcia_register_driver(&ems_pcmcia_driver);
+}
+module_init(ems_pcmcia_init);
+
+static void __exit ems_pcmcia_exit(void)
+{
+ pcmcia_unregister_driver(&ems_pcmcia_driver);
+}
+module_exit(ems_pcmcia_exit);
diff --git a/drivers/net/can/sja1000/peak_pci.c b/drivers/net/can/sja1000/peak_pci.c
new file mode 100644
index 000000000000..905bce0b3a43
--- /dev/null
+++ b/drivers/net/can/sja1000/peak_pci.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2007, 2011 Wolfgang Grandegger <wg@grandegger.com>
+ *
+ * Derived from the PCAN project file driver/src/pcan_pci.c:
+ *
+ * Copyright (C) 2001-2006 PEAK System-Technik GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+
+#include "sja1000.h"
+
+MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
+MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCI/PCIe cards");
+MODULE_SUPPORTED_DEVICE("PEAK PCAN PCI/PCIe CAN card");
+MODULE_LICENSE("GPL v2");
+
+#define DRV_NAME "peak_pci"
+
+struct peak_pci_chan {
+ void __iomem *cfg_base; /* Common for all channels */
+ struct net_device *next_dev; /* Chain of network devices */
+ u16 icr_mask; /* Interrupt mask for fast ack */
+};
+
+#define PEAK_PCI_CAN_CLOCK (16000000 / 2)
+
+#define PEAK_PCI_CDR (CDR_CBP | CDR_CLKOUT_MASK)
+#define PEAK_PCI_OCR OCR_TX0_PUSHPULL
+
+/*
+ * Important PITA registers
+ */
+#define PITA_ICR 0x00 /* Interrupt control register */
+#define PITA_GPIOICR 0x18 /* GPIO interface control register */
+#define PITA_MISC 0x1C /* Miscellaneous register */
+
+#define PEAK_PCI_CFG_SIZE 0x1000 /* Size of the config PCI bar */
+#define PEAK_PCI_CHAN_SIZE 0x0400 /* Size used by the channel */
+
+#define PEAK_PCI_VENDOR_ID 0x001C /* The PCI device and vendor IDs */
+#define PEAK_PCI_DEVICE_ID 0x0001 /* for PCI/PCIe slot cards */
+
+static const u16 peak_pci_icr_masks[] = {0x02, 0x01, 0x40, 0x80};
+
+static DEFINE_PCI_DEVICE_TABLE(peak_pci_tbl) = {
+ {PEAK_PCI_VENDOR_ID, PEAK_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, peak_pci_tbl);
+
+static u8 peak_pci_read_reg(const struct sja1000_priv *priv, int port)
+{
+ return readb(priv->reg_base + (port << 2));
+}
+
+static void peak_pci_write_reg(const struct sja1000_priv *priv,
+ int port, u8 val)
+{
+ writeb(val, priv->reg_base + (port << 2));
+}
+
+static void peak_pci_post_irq(const struct sja1000_priv *priv)
+{
+ struct peak_pci_chan *chan = priv->priv;
+ u16 icr;
+
+ /* Select and clear in PITA stored interrupt */
+ icr = readw(chan->cfg_base + PITA_ICR);
+ if (icr & chan->icr_mask)
+ writew(chan->icr_mask, chan->cfg_base + PITA_ICR);
+}
+
+static int __devinit peak_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct sja1000_priv *priv;
+ struct peak_pci_chan *chan;
+ struct net_device *dev, *dev0 = NULL;
+ void __iomem *cfg_base, *reg_base;
+ u16 sub_sys_id, icr;
+ int i, err, channels;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+
+ err = pci_request_regions(pdev, DRV_NAME);
+ if (err)
+ goto failure_disable_pci;
+
+ err = pci_read_config_word(pdev, 0x2e, &sub_sys_id);
+ if (err)
+ goto failure_release_regions;
+
+ dev_dbg(&pdev->dev, "probing device %04x:%04x:%04x\n",
+ pdev->vendor, pdev->device, sub_sys_id);
+
+ err = pci_write_config_word(pdev, 0x44, 0);
+ if (err)
+ goto failure_release_regions;
+
+ if (sub_sys_id >= 12)
+ channels = 4;
+ else if (sub_sys_id >= 10)
+ channels = 3;
+ else if (sub_sys_id >= 4)
+ channels = 2;
+ else
+ channels = 1;
+
+ cfg_base = pci_iomap(pdev, 0, PEAK_PCI_CFG_SIZE);
+ if (!cfg_base) {
+ dev_err(&pdev->dev, "failed to map PCI resource #0\n");
+ goto failure_release_regions;
+ }
+
+ reg_base = pci_iomap(pdev, 1, PEAK_PCI_CHAN_SIZE * channels);
+ if (!reg_base) {
+ dev_err(&pdev->dev, "failed to map PCI resource #1\n");
+ goto failure_unmap_cfg_base;
+ }
+
+ /* Set GPIO control register */
+ writew(0x0005, cfg_base + PITA_GPIOICR + 2);
+ /* Enable all channels of this card */
+ writeb(0x00, cfg_base + PITA_GPIOICR);
+ /* Toggle reset */
+ writeb(0x05, cfg_base + PITA_MISC + 3);
+ mdelay(5);
+ /* Leave parport mux mode */
+ writeb(0x04, cfg_base + PITA_MISC + 3);
+
+ icr = readw(cfg_base + PITA_ICR + 2);
+
+ for (i = 0; i < channels; i++) {
+ dev = alloc_sja1000dev(sizeof(struct peak_pci_chan));
+ if (!dev) {
+ err = -ENOMEM;
+ goto failure_remove_channels;
+ }
+
+ priv = netdev_priv(dev);
+ chan = priv->priv;
+
+ chan->cfg_base = cfg_base;
+ priv->reg_base = reg_base + i * PEAK_PCI_CHAN_SIZE;
+
+ priv->read_reg = peak_pci_read_reg;
+ priv->write_reg = peak_pci_write_reg;
+ priv->post_irq = peak_pci_post_irq;
+
+ priv->can.clock.freq = PEAK_PCI_CAN_CLOCK;
+ priv->ocr = PEAK_PCI_OCR;
+ priv->cdr = PEAK_PCI_CDR;
+ /* Neither a slave nor a single device distributes the clock */
+ if (channels == 1 || i > 0)
+ priv->cdr |= CDR_CLK_OFF;
+
+ /* Setup interrupt handling */
+ priv->irq_flags = IRQF_SHARED;
+ dev->irq = pdev->irq;
+
+ chan->icr_mask = peak_pci_icr_masks[i];
+ icr |= chan->icr_mask;
+
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ err = register_sja1000dev(dev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to register device\n");
+ free_sja1000dev(dev);
+ goto failure_remove_channels;
+ }
+
+ /* Create chain of SJA1000 devices */
+ if (i == 0)
+ dev0 = dev;
+ else
+ chan->next_dev = dev;
+
+ dev_info(&pdev->dev,
+ "%s at reg_base=0x%p cfg_base=0x%p irq=%d\n",
+ dev->name, priv->reg_base, chan->cfg_base, dev->irq);
+ }
+
+ pci_set_drvdata(pdev, dev0);
+
+ /* Enable interrupts */
+ writew(icr, cfg_base + PITA_ICR + 2);
+
+ return 0;
+
+failure_remove_channels:
+ /* Disable interrupts */
+ writew(0x0, cfg_base + PITA_ICR + 2);
+
+ for (dev = dev0; dev; dev = chan->next_dev) {
+ unregister_sja1000dev(dev);
+ free_sja1000dev(dev);
+ priv = netdev_priv(dev);
+ chan = priv->priv;
+ dev = chan->next_dev;
+ }
+
+ pci_iounmap(pdev, reg_base);
+
+failure_unmap_cfg_base:
+ pci_iounmap(pdev, cfg_base);
+
+failure_release_regions:
+ pci_release_regions(pdev);
+
+failure_disable_pci:
+ pci_disable_device(pdev);
+
+ return err;
+}
+
+static void __devexit peak_pci_remove(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev); /* First device */
+ struct sja1000_priv *priv = netdev_priv(dev);
+ struct peak_pci_chan *chan = priv->priv;
+ void __iomem *cfg_base = chan->cfg_base;
+ void __iomem *reg_base = priv->reg_base;
+
+ /* Disable interrupts */
+ writew(0x0, cfg_base + PITA_ICR + 2);
+
+ /* Loop over all registered devices */
+ while (1) {
+ dev_info(&pdev->dev, "removing device %s\n", dev->name);
+ unregister_sja1000dev(dev);
+ free_sja1000dev(dev);
+ dev = chan->next_dev;
+ if (!dev)
+ break;
+ priv = netdev_priv(dev);
+ chan = priv->priv;
+ }
+
+ pci_iounmap(pdev, reg_base);
+ pci_iounmap(pdev, cfg_base);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+
+ pci_set_drvdata(pdev, NULL);
+}
+
+static struct pci_driver peak_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = peak_pci_tbl,
+ .probe = peak_pci_probe,
+ .remove = __devexit_p(peak_pci_remove),
+};
+
+static int __init peak_pci_init(void)
+{
+ return pci_register_driver(&peak_pci_driver);
+}
+module_init(peak_pci_init);
+
+static void __exit peak_pci_exit(void)
+{
+ pci_unregister_driver(&peak_pci_driver);
+}
+module_exit(peak_pci_exit);
diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c
index 231385b8e08f..c7f3d4ea1167 100644
--- a/drivers/net/can/sja1000/plx_pci.c
+++ b/drivers/net/can/sja1000/plx_pci.c
@@ -408,7 +408,7 @@ static void plx_pci_del_card(struct pci_dev *pdev)
struct sja1000_priv *priv;
int i = 0;
- for (i = 0; i < card->channels; i++) {
+ for (i = 0; i < PLX_PCI_MAX_CHAN; i++) {
dev = card->net_dev[i];
if (!dev)
continue;
@@ -536,7 +536,6 @@ static int __devinit plx_pci_add_card(struct pci_dev *pdev,
if (err) {
dev_err(&pdev->dev, "Registering device failed "
"(err=%d)\n", err);
- free_sja1000dev(dev);
goto failure_cleanup;
}
@@ -549,6 +548,7 @@ static int __devinit plx_pci_add_card(struct pci_dev *pdev,
dev_err(&pdev->dev, "Channel #%d not detected\n",
i + 1);
free_sja1000dev(dev);
+ card->net_dev[i] = NULL;
}
}
diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c
index f501bba1fc6f..04a3f1b756a8 100644
--- a/drivers/net/can/sja1000/sja1000.c
+++ b/drivers/net/can/sja1000/sja1000.c
@@ -40,8 +40,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
- * Send feedback to <socketcan-users@lists.berlios.de>
- *
*/
#include <linux/module.h>
diff --git a/drivers/net/can/sja1000/sja1000.h b/drivers/net/can/sja1000/sja1000.h
index 78bd4ecac140..23fff06875f5 100644
--- a/drivers/net/can/sja1000/sja1000.h
+++ b/drivers/net/can/sja1000/sja1000.h
@@ -40,8 +40,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
- * Send feedback to <socketcan-users@lists.berlios.de>
- *
*/
#ifndef SJA1000_DEV_H
diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c
index cee6ba2b8b58..c3dd9d09be57 100644
--- a/drivers/net/can/sja1000/sja1000_of_platform.c
+++ b/drivers/net/can/sja1000/sja1000_of_platform.c
@@ -29,7 +29,7 @@
* nxp,external-clock-frequency = <16000000>;
* };
*
- * See "Documentation/powerpc/dts-bindings/can/sja1000.txt" for further
+ * See "Documentation/devicetree/bindings/net/can/sja1000.txt" for further
* information.
*/
diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c
index 4b70b7e8bdeb..a979b006f459 100644
--- a/drivers/net/can/slcan.c
+++ b/drivers/net/can/slcan.c
@@ -35,8 +35,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
- * Send feedback to <socketcan-users@lists.berlios.de>
- *
*/
#include <linux/module.h>
diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
index f7bbde9eb2cb..2adc294f512a 100644
--- a/drivers/net/can/ti_hecc.c
+++ b/drivers/net/can/ti_hecc.c
@@ -46,6 +46,7 @@
#include <linux/skbuff.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/io.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
@@ -503,9 +504,9 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev)
spin_unlock_irqrestore(&priv->mbx_lock, flags);
/* Prepare mailbox for transmission */
+ data = cf->can_dlc | (get_tx_head_prio(priv) << 8);
if (cf->can_id & CAN_RTR_FLAG) /* Remote transmission request */
data |= HECC_CANMCF_RTR;
- data |= get_tx_head_prio(priv) << 8;
hecc_write_mbx(priv, mbxno, HECC_CANMCF, data);
if (cf->can_id & CAN_EFF_FLAG) /* Extended frame format */
@@ -923,6 +924,7 @@ static int ti_hecc_probe(struct platform_device *pdev)
priv->can.do_get_state = ti_hecc_get_state;
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
+ spin_lock_init(&priv->mbx_lock);
ndev->irq = irq->start;
ndev->flags |= IFF_ECHO;
platform_set_drvdata(pdev, ndev);
diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
index a30b8f480f61..f93e2d6fc88c 100644
--- a/drivers/net/can/vcan.c
+++ b/drivers/net/can/vcan.c
@@ -37,8 +37,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
- * Send feedback to <socketcan-users@lists.berlios.de>
- *
*/
#include <linux/module.h>
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index e66aceb57cef..7cb2785e209d 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -261,7 +261,7 @@ static const struct net_device_ops e100_netdev_ops = {
.ndo_start_xmit = e100_send_packet,
.ndo_tx_timeout = e100_tx_timeout,
.ndo_get_stats = e100_get_stats,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_do_ioctl = e100_ioctl,
.ndo_set_mac_address = e100_set_mac_address,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index 39cf9b9bd673..a7c5e8831e8c 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -116,7 +116,7 @@ static const struct net_device_ops dummy_netdev_ops = {
.ndo_init = dummy_dev_init,
.ndo_start_xmit = dummy_xmit,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_set_mac_address = dummy_set_address,
.ndo_get_stats64 = dummy_get_stats64,
};
diff --git a/drivers/net/3c501.c b/drivers/net/ethernet/3com/3c501.c
index 5420f6de27df..68da81d476f3 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/ethernet/3com/3c501.c
@@ -201,7 +201,7 @@ static const struct net_device_ops el_netdev_ops = {
.ndo_stop = el1_close,
.ndo_start_xmit = el_start_xmit,
.ndo_tx_timeout = el_timeout,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/3c501.h b/drivers/net/ethernet/3com/3c501.h
index 183fd55f03cb..183fd55f03cb 100644
--- a/drivers/net/3c501.h
+++ b/drivers/net/ethernet/3com/3c501.h
diff --git a/drivers/net/3c509.c b/drivers/net/ethernet/3com/3c509.c
index 44b28b2d7003..92053e6fc980 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/ethernet/3com/3c509.c
@@ -545,7 +545,7 @@ static const struct net_device_ops netdev_ops = {
.ndo_stop = el3_close,
.ndo_start_xmit = el3_start_xmit,
.ndo_get_stats = el3_get_stats,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_tx_timeout = el3_tx_timeout,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/3c515.c b/drivers/net/ethernet/3com/3c515.c
index d2bb4b254c57..f67a5d3a200c 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/ethernet/3com/3c515.c
@@ -569,7 +569,7 @@ static const struct net_device_ops netdev_ops = {
.ndo_start_xmit = corkscrew_start_xmit,
.ndo_tx_timeout = corkscrew_timeout,
.ndo_get_stats = corkscrew_get_stats,
- .ndo_set_multicast_list = set_rx_mode,
+ .ndo_set_rx_mode = set_rx_mode,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/ethernet/3com/3c574_cs.c
index 34c5e1cbf65d..9c01bc9235b3 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/ethernet/3com/3c574_cs.c
@@ -255,7 +255,7 @@ static const struct net_device_ops el3_netdev_ops = {
.ndo_tx_timeout = el3_tx_timeout,
.ndo_get_stats = el3_get_stats,
.ndo_do_ioctl = el3_ioctl,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/ethernet/3com/3c589_cs.c
index 4a1a35809807..972f80ecc510 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/ethernet/3com/3c589_cs.c
@@ -184,7 +184,7 @@ static const struct net_device_ops el3_netdev_ops = {
.ndo_tx_timeout = el3_tx_timeout,
.ndo_set_config = el3_config,
.ndo_get_stats = el3_get_stats,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/3c59x.c b/drivers/net/ethernet/3com/3c59x.c
index 8cc22568ebd3..b42c06baba89 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/ethernet/3com/3c59x.c
@@ -1055,7 +1055,7 @@ static const struct net_device_ops boomrang_netdev_ops = {
#ifdef CONFIG_PCI
.ndo_do_ioctl = vortex_ioctl,
#endif
- .ndo_set_multicast_list = set_rx_mode,
+ .ndo_set_rx_mode = set_rx_mode,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
@@ -1073,7 +1073,7 @@ static const struct net_device_ops vortex_netdev_ops = {
#ifdef CONFIG_PCI
.ndo_do_ioctl = vortex_ioctl,
#endif
- .ndo_set_multicast_list = set_rx_mode,
+ .ndo_set_rx_mode = set_rx_mode,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
@@ -2179,14 +2179,15 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
vp->tx_ring[entry].frag[i+1].addr =
- cpu_to_le32(pci_map_single(VORTEX_PCI(vp),
- (void*)page_address(frag->page) + frag->page_offset,
- frag->size, PCI_DMA_TODEVICE));
+ cpu_to_le32(pci_map_single(
+ VORTEX_PCI(vp),
+ (void *)skb_frag_address(frag),
+ skb_frag_size(frag), PCI_DMA_TODEVICE));
if (i == skb_shinfo(skb)->nr_frags-1)
- vp->tx_ring[entry].frag[i+1].length = cpu_to_le32(frag->size|LAST_FRAG);
+ vp->tx_ring[entry].frag[i+1].length = cpu_to_le32(skb_frag_size(frag)|LAST_FRAG);
else
- vp->tx_ring[entry].frag[i+1].length = cpu_to_le32(frag->size);
+ vp->tx_ring[entry].frag[i+1].length = cpu_to_le32(skb_frag_size(frag));
}
}
#else
diff --git a/drivers/net/ethernet/3com/Kconfig b/drivers/net/ethernet/3com/Kconfig
new file mode 100644
index 000000000000..a8bb30cf512d
--- /dev/null
+++ b/drivers/net/ethernet/3com/Kconfig
@@ -0,0 +1,122 @@
+#
+# 3Com Ethernet device configuration
+#
+
+config NET_VENDOR_3COM
+ bool "3Com devices"
+ default y
+ depends on ISA || EISA || MCA || PCI || PCMCIA
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about 3Com cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_3COM
+
+config EL1
+ tristate "3c501 \"EtherLink\" support"
+ depends on ISA
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>. Also, consider buying a
+ new card, since the 3c501 is slow, broken, and obsolete: you will
+ have problems. Some people suggest to ping ("man ping") a nearby
+ machine every minute ("man cron") when using this card.
+
+ To compile this driver as a module, choose M here. The module
+ will be called 3c501.
+
+config EL3
+ tristate "3c509/3c529 (MCA)/3c579 \"EtherLink III\" support"
+ depends on (ISA || EISA || MCA)
+ ---help---
+ If you have a network (Ethernet) card belonging to the 3Com
+ EtherLinkIII series, say Y and read the Ethernet-HOWTO, available
+ from <http://www.tldp.org/docs.html#howto>.
+
+ If your card is not working you may need to use the DOS
+ setup disk to disable Plug & Play mode, and to select the default
+ media type.
+
+ To compile this driver as a module, choose M here. The module
+ will be called 3c509.
+
+config 3C515
+ tristate "3c515 ISA \"Fast EtherLink\""
+ depends on (ISA || EISA) && ISA_DMA_API
+ ---help---
+ If you have a 3Com ISA EtherLink XL "Corkscrew" 3c515 Fast Ethernet
+ network card, say Y and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called 3c515.
+
+config PCMCIA_3C574
+ tristate "3Com 3c574 PCMCIA support"
+ depends on PCMCIA
+ ---help---
+ Say Y here if you intend to attach a 3Com 3c574 or compatible PCMCIA
+ (PC-card) Fast Ethernet card to your computer.
+
+ To compile this driver as a module, choose M here: the module will be
+ called 3c574_cs. If unsure, say N.
+
+config PCMCIA_3C589
+ tristate "3Com 3c589 PCMCIA support"
+ depends on PCMCIA
+ ---help---
+ Say Y here if you intend to attach a 3Com 3c589 or compatible PCMCIA
+ (PC-card) Ethernet card to your computer.
+
+ To compile this driver as a module, choose M here: the module will be
+ called 3c589_cs. If unsure, say N.
+
+config VORTEX
+ tristate "3c590/3c900 series (592/595/597) \"Vortex/Boomerang\" support"
+ depends on (PCI || EISA)
+ select NET_CORE
+ select MII
+ ---help---
+ This option enables driver support for a large number of 10Mbps and
+ 10/100Mbps EISA, PCI and PCMCIA 3Com network cards:
+
+ "Vortex" (Fast EtherLink 3c590/3c592/3c595/3c597) EISA and PCI
+ "Boomerang" (EtherLink XL 3c900 or 3c905) PCI
+ "Cyclone" (3c540/3c900/3c905/3c980/3c575/3c656) PCI and Cardbus
+ "Tornado" (3c905) PCI
+ "Hurricane" (3c555/3cSOHO) PCI
+
+ If you have such a card, say Y and read the Ethernet-HOWTO,
+ available from <http://www.tldp.org/docs.html#howto>. More
+ specific information is in
+ <file:Documentation/networking/vortex.txt> and in the comments at
+ the beginning of <file:drivers/net/3c59x.c>.
+
+ To compile this support as a module, choose M here.
+
+config TYPHOON
+ tristate "3cr990 series \"Typhoon\" support"
+ depends on PCI
+ select CRC32
+ ---help---
+ This option enables driver support for the 3cr990 series of cards:
+
+ 3C990-TX, 3CR990-TX-95, 3CR990-TX-97, 3CR990-FX-95, 3CR990-FX-97,
+ 3CR990SVR, 3CR990SVR95, 3CR990SVR97, 3CR990-FX-95 Server,
+ 3CR990-FX-97 Server, 3C990B-TX-M, 3C990BSVR
+
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called typhoon.
+
+endif # NET_VENDOR_3COM
diff --git a/drivers/net/ethernet/3com/Makefile b/drivers/net/ethernet/3com/Makefile
new file mode 100644
index 000000000000..1e5382a30ead
--- /dev/null
+++ b/drivers/net/ethernet/3com/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the 3Com Ethernet device drivers
+#
+
+obj-$(CONFIG_EL1) += 3c501.o
+obj-$(CONFIG_EL3) += 3c509.o
+obj-$(CONFIG_3C515) += 3c515.o
+obj-$(CONFIG_PCMCIA_3C589) += 3c589_cs.o
+obj-$(CONFIG_PCMCIA_3C574) += 3c574_cs.o
+obj-$(CONFIG_VORTEX) += 3c59x.o
+obj-$(CONFIG_TYPHOON) += typhoon.o
diff --git a/drivers/net/typhoon.c b/drivers/net/ethernet/3com/typhoon.c
index 1d5091a1e49a..20ea07508ac7 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/ethernet/3com/typhoon.c
@@ -810,17 +810,16 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev)
txd->frag.addrHi = 0;
first_txd->numDesc++;
- for(i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
void *frag_addr;
txd = (struct tx_desc *) (txRing->ringBase +
txRing->lastWrite);
typhoon_inc_tx_index(&txRing->lastWrite, 1);
- len = frag->size;
- frag_addr = (void *) page_address(frag->page) +
- frag->page_offset;
+ len = skb_frag_size(frag);
+ frag_addr = skb_frag_address(frag);
skb_dma = pci_map_single(tp->tx_pdev, frag_addr, len,
PCI_DMA_TODEVICE);
txd->flags = TYPHOON_FRAG_DESC | TYPHOON_DESC_VALID;
@@ -1149,13 +1148,9 @@ static void
typhoon_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
{
ering->rx_max_pending = RXENT_ENTRIES;
- ering->rx_mini_max_pending = 0;
- ering->rx_jumbo_max_pending = 0;
ering->tx_max_pending = TXLO_ENTRIES - 1;
ering->rx_pending = RXENT_ENTRIES;
- ering->rx_mini_pending = 0;
- ering->rx_jumbo_pending = 0;
ering->tx_pending = TXLO_ENTRIES - 1;
}
@@ -2266,7 +2261,7 @@ static const struct net_device_ops typhoon_netdev_ops = {
.ndo_open = typhoon_open,
.ndo_stop = typhoon_close,
.ndo_start_xmit = typhoon_start_tx,
- .ndo_set_multicast_list = typhoon_set_rx_mode,
+ .ndo_set_rx_mode = typhoon_set_rx_mode,
.ndo_tx_timeout = typhoon_tx_timeout,
.ndo_get_stats = typhoon_get_stats,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/typhoon.h b/drivers/net/ethernet/3com/typhoon.h
index 88187fc84aa3..88187fc84aa3 100644
--- a/drivers/net/typhoon.h
+++ b/drivers/net/ethernet/3com/typhoon.h
diff --git a/drivers/net/3c503.c b/drivers/net/ethernet/8390/3c503.c
index 84e68f1b9adf..fbab1367505f 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/ethernet/8390/3c503.c
@@ -176,7 +176,7 @@ static const struct net_device_ops el2_netdev_ops = {
.ndo_start_xmit = eip_start_xmit,
.ndo_tx_timeout = eip_tx_timeout,
.ndo_get_stats = eip_get_stats,
- .ndo_set_multicast_list = eip_set_multicast_list,
+ .ndo_set_rx_mode = eip_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/3c503.h b/drivers/net/ethernet/8390/3c503.h
index e2367b82a2ec..e2367b82a2ec 100644
--- a/drivers/net/3c503.h
+++ b/drivers/net/ethernet/8390/3c503.h
diff --git a/drivers/net/8390.c b/drivers/net/ethernet/8390/8390.c
index 7c7518be1756..5db1f55abef4 100644
--- a/drivers/net/8390.c
+++ b/drivers/net/ethernet/8390/8390.c
@@ -61,7 +61,7 @@ const struct net_device_ops ei_netdev_ops = {
.ndo_start_xmit = ei_start_xmit,
.ndo_tx_timeout = ei_tx_timeout,
.ndo_get_stats = ei_get_stats,
- .ndo_set_multicast_list = ei_set_multicast_list,
+ .ndo_set_rx_mode = ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/8390.h b/drivers/net/ethernet/8390/8390.h
index 58a12e4c78f9..58a12e4c78f9 100644
--- a/drivers/net/8390.h
+++ b/drivers/net/ethernet/8390/8390.h
diff --git a/drivers/net/8390p.c b/drivers/net/ethernet/8390/8390p.c
index a2a64ea0b691..e8fc2e87e840 100644
--- a/drivers/net/8390p.c
+++ b/drivers/net/ethernet/8390/8390p.c
@@ -66,7 +66,7 @@ const struct net_device_ops eip_netdev_ops = {
.ndo_start_xmit = eip_start_xmit,
.ndo_tx_timeout = eip_tx_timeout,
.ndo_get_stats = eip_get_stats,
- .ndo_set_multicast_list = eip_set_multicast_list,
+ .ndo_set_rx_mode = eip_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig
new file mode 100644
index 000000000000..e04ade444247
--- /dev/null
+++ b/drivers/net/ethernet/8390/Kconfig
@@ -0,0 +1,337 @@
+#
+# 8390 device configuration
+#
+
+config NET_VENDOR_8390
+ bool "National Semi-conductor 8390 devices"
+ default y
+ depends on NET_VENDOR_NATSEMI && (AMIGA_PCMCIA || PCI || SUPERH || \
+ ISA || MCA || EISA || MAC || M32R || MACH_TX49XX || \
+ MCA_LEGACY || H8300 || ARM || MIPS || ZORRO || PCMCIA || \
+ EXPERIMENTAL)
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Western Digital cards. If you say Y, you will be
+ asked for your specific card in the following questions.
+
+if NET_VENDOR_8390
+
+config EL2
+ tristate "3c503 \"EtherLink II\" support"
+ depends on ISA
+ select CRC32
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called 3c503.
+
+config AC3200
+ tristate "Ansel Communications EISA 3200 support (EXPERIMENTAL)"
+ depends on PCI && (ISA || EISA) && EXPERIMENTAL
+ select CRC32
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called ac3200.
+
+config PCMCIA_AXNET
+ tristate "Asix AX88190 PCMCIA support"
+ depends on PCMCIA
+ ---help---
+ Say Y here if you intend to attach an Asix AX88190-based PCMCIA
+ (PC-card) Fast Ethernet card to your computer. These cards are
+ nearly NE2000 compatible but need a separate driver due to a few
+ misfeatures.
+
+ To compile this driver as a module, choose M here: the module will be
+ called axnet_cs. If unsure, say N.
+
+config AX88796
+ tristate "ASIX AX88796 NE2000 clone support"
+ depends on (ARM || MIPS || SUPERH)
+ select PHYLIB
+ select MDIO_BITBANG
+ ---help---
+ AX88796 driver, using platform bus to provide
+ chip detection and resources
+
+config AX88796_93CX6
+ bool "ASIX AX88796 external 93CX6 eeprom support"
+ depends on AX88796
+ select EEPROM_93CX6
+ ---help---
+ Select this if your platform comes with an external 93CX6 eeprom.
+
+config E2100
+ tristate "Cabletron E21xx support"
+ depends on ISA
+ select CRC32
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called e2100.
+
+config ES3210
+ tristate "Racal-Interlan EISA ES3210 support (EXPERIMENTAL)"
+ depends on PCI && EISA && EXPERIMENTAL
+ select CRC32
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called es3210.
+
+config HPLAN_PLUS
+ tristate "HP PCLAN+ (27247B and 27252A) support"
+ depends on ISA
+ select CRC32
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called hp-plus.
+
+config HPLAN
+ tristate "HP PCLAN (27245 and other 27xxx series) support"
+ depends on ISA
+ select CRC32
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called hp.
+
+config HYDRA
+ tristate "Hydra support"
+ depends on ZORRO
+ select CRC32
+ ---help---
+ If you have a Hydra Ethernet adapter, say Y. Otherwise, say N.
+
+ To compile this driver as a module, choose M here: the module
+ will be called hydra.
+
+config ARM_ETHERH
+ tristate "I-cubed EtherH/ANT EtherM support"
+ depends on ARM && ARCH_ACORN
+ select CRC32
+ ---help---
+ If you have an Acorn system with one of these network cards, you
+ should say Y to this option if you wish to use it with Linux.
+
+config LNE390
+ tristate "Mylex EISA LNE390A/B support (EXPERIMENTAL)"
+ depends on PCI && EISA && EXPERIMENTAL
+ select CRC32
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called lne390.
+
+config MAC8390
+ bool "Macintosh NS 8390 based ethernet cards"
+ depends on MAC
+ select CRC32
+ ---help---
+ If you want to include a driver to support Nubus or LC-PDS
+ Ethernet cards using an NS8390 chipset or its equivalent, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+config NE2000
+ tristate "NE2000/NE1000 support"
+ depends on (ISA || (Q40 && m) || M32R || MACH_TX49XX)
+ select CRC32
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>. Many Ethernet cards
+ without a specific driver are compatible with NE2000.
+
+ If you have a PCI NE2000 card however, say N here and Y to "PCI
+ NE2000 and clone support" under "EISA, VLB, PCI and on board
+ controllers" below. If you have a NE2000 card and are running on
+ an MCA system (a bus system used on some IBM PS/2 computers and
+ laptops), say N here and Y to "NE/2 (ne2000 MCA version) support",
+ below.
+
+ To compile this driver as a module, choose M here. The module
+ will be called ne.
+
+config NE2_MCA
+ tristate "NE/2 (ne2000 MCA version) support"
+ depends on MCA_LEGACY
+ select CRC32
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called ne2.
+
+config NE2K_PCI
+ tristate "PCI NE2000 and clones support (see help)"
+ depends on PCI
+ select CRC32
+ ---help---
+ This driver is for NE2000 compatible PCI cards. It will not work
+ with ISA NE2000 cards (they have their own driver, "NE2000/NE1000
+ support" below). If you have a PCI NE2000 network (Ethernet) card,
+ say Y and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ This driver also works for the following NE2000 clone cards:
+ RealTek RTL-8029 Winbond 89C940 Compex RL2000 KTI ET32P2
+ NetVin NV5000SC Via 86C926 SureCom NE34 Winbond
+ Holtek HT80232 Holtek HT80229
+
+ To compile this driver as a module, choose M here. The module
+ will be called ne2k-pci.
+
+config APNE
+ tristate "PCMCIA NE2000 support"
+ depends on AMIGA_PCMCIA
+ select CRC32
+ ---help---
+ If you have a PCMCIA NE2000 compatible adapter, say Y. Otherwise,
+ say N.
+
+ To compile this driver as a module, choose M here: the module
+ will be called apne.
+
+config NE3210
+ tristate "Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)"
+ depends on PCI && EISA && EXPERIMENTAL
+ select CRC32
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>. Note that this driver
+ will NOT WORK for NE3200 cards as they are completely different.
+
+ To compile this driver as a module, choose M here. The module
+ will be called ne3210.
+
+config PCMCIA_PCNET
+ tristate "NE2000 compatible PCMCIA support"
+ depends on PCMCIA
+ select CRC32
+ ---help---
+ Say Y here if you intend to attach an NE2000 compatible PCMCIA
+ (PC-card) Ethernet or Fast Ethernet card to your computer.
+
+ To compile this driver as a module, choose M here: the module will be
+ called pcnet_cs. If unsure, say N.
+
+config NE_H8300
+ tristate "NE2000 compatible support for H8/300"
+ depends on H8300
+ ---help---
+ Say Y here if you want to use the NE2000 compatible
+ controller on the Renesas H8/300 processor.
+
+config STNIC
+ tristate "National DP83902AV support"
+ depends on SUPERH
+ select CRC32
+ ---help---
+ Support for cards based on the National Semiconductor DP83902AV
+ ST-NIC Serial Network Interface Controller for Twisted Pair. This
+ is a 10Mbit/sec Ethernet controller. Product overview and specs at
+ <http://www.national.com/pf/DP/DP83902A.html>.
+
+ If unsure, say N.
+
+config ULTRAMCA
+ tristate "SMC Ultra MCA support"
+ depends on MCA
+ select CRC32
+ ---help---
+ If you have a network (Ethernet) card of this type and are running
+ an MCA based system (PS/2), say Y and read the Ethernet-HOWTO,
+ available from <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called smc-mca.
+
+config ULTRA
+ tristate "SMC Ultra support"
+ depends on ISA
+ select CRC32
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Important: There have been many reports that, with some motherboards
+ mixing an SMC Ultra and an Adaptec AHA154x SCSI card (or compatible,
+ such as some BusLogic models) causes corruption problems with many
+ operating systems. The Linux smc-ultra driver has a work-around for
+ this but keep it in mind if you have such a SCSI card and have
+ problems.
+
+ To compile this driver as a module, choose M here. The module
+ will be called smc-ultra.
+
+config ULTRA32
+ tristate "SMC Ultra32 EISA support"
+ depends on EISA
+ select CRC32
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called smc-ultra32.
+
+config WD80x3
+ tristate "WD80*3 support"
+ depends on ISA
+ select CRC32
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called wd.
+
+config ZORRO8390
+ tristate "Zorro NS8390-based Ethernet support"
+ depends on ZORRO
+ select CRC32
+ ---help---
+ This driver is for Zorro Ethernet cards using an NS8390-compatible
+ chipset, like the Village Tronic Ariadne II and the Individual
+ Computers X-Surf Ethernet cards. If you have such a card, say Y.
+ Otherwise, say N.
+
+ To compile this driver as a module, choose M here: the module
+ will be called zorro8390.
+
+endif # NET_VENDOR_8390
diff --git a/drivers/net/ethernet/8390/Makefile b/drivers/net/ethernet/8390/Makefile
new file mode 100644
index 000000000000..3337d7fb4344
--- /dev/null
+++ b/drivers/net/ethernet/8390/Makefile
@@ -0,0 +1,29 @@
+#
+# Makefile for the 8390 network device drivers.
+#
+
+obj-$(CONFIG_MAC8390) += mac8390.o
+obj-$(CONFIG_AC3200) += ac3200.o 8390.o
+obj-$(CONFIG_APNE) += apne.o 8390.o
+obj-$(CONFIG_ARM_ETHERH) += etherh.o
+obj-$(CONFIG_AX88796) += ax88796.o
+obj-$(CONFIG_E2100) += e2100.o 8390.o
+obj-$(CONFIG_EL2) += 3c503.o 8390p.o
+obj-$(CONFIG_ES3210) += es3210.o 8390.o
+obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390p.o
+obj-$(CONFIG_HPLAN) += hp.o 8390p.o
+obj-$(CONFIG_HYDRA) += hydra.o 8390.o
+obj-$(CONFIG_LNE390) += lne390.o 8390.o
+obj-$(CONFIG_NE2000) += ne.o 8390p.o
+obj-$(CONFIG_NE2_MCA) += ne2.o 8390p.o
+obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
+obj-$(CONFIG_NE3210) += ne3210.o 8390.o
+obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o
+obj-$(CONFIG_PCMCIA_AXNET) += axnet_cs.o 8390.o
+obj-$(CONFIG_PCMCIA_PCNET) += pcnet_cs.o 8390.o
+obj-$(CONFIG_STNIC) += stnic.o 8390.o
+obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o
+obj-$(CONFIG_ULTRA32) += smc-ultra32.o 8390.o
+obj-$(CONFIG_ULTRAMCA) += smc-mca.o 8390.o
+obj-$(CONFIG_WD80x3) += wd.o 8390.o
+obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o
diff --git a/drivers/net/ac3200.c b/drivers/net/ethernet/8390/ac3200.c
index f07b2e980fbc..5337dd0a59b0 100644
--- a/drivers/net/ac3200.c
+++ b/drivers/net/ethernet/8390/ac3200.c
@@ -151,7 +151,7 @@ static const struct net_device_ops ac_netdev_ops = {
.ndo_start_xmit = ei_start_xmit,
.ndo_tx_timeout = ei_tx_timeout,
.ndo_get_stats = ei_get_stats,
- .ndo_set_multicast_list = ei_set_multicast_list,
+ .ndo_set_rx_mode = ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/apne.c b/drivers/net/ethernet/8390/apne.c
index 547737340cbb..547737340cbb 100644
--- a/drivers/net/apne.c
+++ b/drivers/net/ethernet/8390/apne.c
diff --git a/drivers/net/ax88796.c b/drivers/net/ethernet/8390/ax88796.c
index e7cb8c8b9776..e9f8432f55b4 100644
--- a/drivers/net/ax88796.c
+++ b/drivers/net/ethernet/8390/ax88796.c
@@ -543,7 +543,7 @@ static const struct net_device_ops ax_netdev_ops = {
.ndo_start_xmit = ax_ei_start_xmit,
.ndo_tx_timeout = ax_ei_tx_timeout,
.ndo_get_stats = ax_ei_get_stats,
- .ndo_set_multicast_list = ax_ei_set_multicast_list,
+ .ndo_set_rx_mode = ax_ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/ethernet/8390/axnet_cs.c
index 9953db711969..bba51cdc74a1 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/ethernet/8390/axnet_cs.c
@@ -38,7 +38,7 @@
#include <linux/etherdevice.h>
#include <linux/crc32.h>
#include <linux/mii.h>
-#include "../8390.h"
+#include "8390.h"
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
@@ -134,7 +134,7 @@ static const struct net_device_ops axnet_netdev_ops = {
.ndo_start_xmit = axnet_start_xmit,
.ndo_tx_timeout = axnet_tx_timeout,
.ndo_get_stats = get_stats,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/e2100.c b/drivers/net/ethernet/8390/e2100.c
index d50a9998ae77..d16dc53c1813 100644
--- a/drivers/net/e2100.c
+++ b/drivers/net/ethernet/8390/e2100.c
@@ -168,7 +168,7 @@ static const struct net_device_ops e21_netdev_ops = {
.ndo_start_xmit = ei_start_xmit,
.ndo_tx_timeout = ei_tx_timeout,
.ndo_get_stats = ei_get_stats,
- .ndo_set_multicast_list = ei_set_multicast_list,
+ .ndo_set_rx_mode = ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/es3210.c b/drivers/net/ethernet/8390/es3210.c
index 7a09575ecff0..7a09575ecff0 100644
--- a/drivers/net/es3210.c
+++ b/drivers/net/ethernet/8390/es3210.c
diff --git a/drivers/net/arm/etherh.c b/drivers/net/ethernet/8390/etherh.c
index 03e217a868d4..48c4948750d1 100644
--- a/drivers/net/arm/etherh.c
+++ b/drivers/net/ethernet/8390/etherh.c
@@ -65,7 +65,7 @@
static char version[] __initdata =
"EtherH/EtherM Driver (c) 2002-2004 Russell King " DRV_VERSION "\n";
-#include "../lib8390.c"
+#include "lib8390.c"
static unsigned int net_debug = NET_DEBUG;
@@ -644,7 +644,7 @@ static const struct net_device_ops etherh_netdev_ops = {
.ndo_start_xmit = __ei_start_xmit,
.ndo_tx_timeout = __ei_tx_timeout,
.ndo_get_stats = __ei_get_stats,
- .ndo_set_multicast_list = __ei_set_multicast_list,
+ .ndo_set_rx_mode = __ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/hp-plus.c b/drivers/net/ethernet/8390/hp-plus.c
index 29917363ebfb..eeac843dcd2d 100644
--- a/drivers/net/hp-plus.c
+++ b/drivers/net/ethernet/8390/hp-plus.c
@@ -165,7 +165,7 @@ static const struct net_device_ops hpp_netdev_ops = {
.ndo_start_xmit = eip_start_xmit,
.ndo_tx_timeout = eip_tx_timeout,
.ndo_get_stats = eip_get_stats,
- .ndo_set_multicast_list = eip_set_multicast_list,
+ .ndo_set_rx_mode = eip_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/hp.c b/drivers/net/ethernet/8390/hp.c
index 18564d4a7c04..18564d4a7c04 100644
--- a/drivers/net/hp.c
+++ b/drivers/net/ethernet/8390/hp.c
diff --git a/drivers/net/hydra.c b/drivers/net/ethernet/8390/hydra.c
index 1cd481c04202..3dac937a67c4 100644
--- a/drivers/net/hydra.c
+++ b/drivers/net/ethernet/8390/hydra.c
@@ -101,7 +101,7 @@ static const struct net_device_ops hydra_netdev_ops = {
.ndo_start_xmit = __ei_start_xmit,
.ndo_tx_timeout = __ei_tx_timeout,
.ndo_get_stats = __ei_get_stats,
- .ndo_set_multicast_list = __ei_set_multicast_list,
+ .ndo_set_rx_mode = __ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/lib8390.c b/drivers/net/ethernet/8390/lib8390.c
index 05ae21435bfd..05ae21435bfd 100644
--- a/drivers/net/lib8390.c
+++ b/drivers/net/ethernet/8390/lib8390.c
diff --git a/drivers/net/lne390.c b/drivers/net/ethernet/8390/lne390.c
index f9888d20177b..f9888d20177b 100644
--- a/drivers/net/lne390.c
+++ b/drivers/net/ethernet/8390/lne390.c
diff --git a/drivers/net/mac8390.c b/drivers/net/ethernet/8390/mac8390.c
index f84f5e6ededb..af5d9822cad9 100644
--- a/drivers/net/mac8390.c
+++ b/drivers/net/ethernet/8390/mac8390.c
@@ -494,7 +494,7 @@ static const struct net_device_ops mac8390_netdev_ops = {
.ndo_start_xmit = __ei_start_xmit,
.ndo_tx_timeout = __ei_tx_timeout,
.ndo_get_stats = __ei_get_stats,
- .ndo_set_multicast_list = __ei_set_multicast_list,
+ .ndo_set_rx_mode = __ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/ne-h8300.c b/drivers/net/ethernet/8390/ne-h8300.c
index 7298a34bc795..cd36a6a5f408 100644
--- a/drivers/net/ne-h8300.c
+++ b/drivers/net/ethernet/8390/ne-h8300.c
@@ -200,7 +200,7 @@ static const struct net_device_ops ne_netdev_ops = {
.ndo_start_xmit = __ei_start_xmit,
.ndo_tx_timeout = __ei_tx_timeout,
.ndo_get_stats = __ei_get_stats,
- .ndo_set_multicast_list = __ei_set_multicast_list,
+ .ndo_set_rx_mode = __ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/ne.c b/drivers/net/ethernet/8390/ne.c
index 1063093b3afc..1063093b3afc 100644
--- a/drivers/net/ne.c
+++ b/drivers/net/ethernet/8390/ne.c
diff --git a/drivers/net/ne2.c b/drivers/net/ethernet/8390/ne2.c
index 70cdc6996342..70cdc6996342 100644
--- a/drivers/net/ne2.c
+++ b/drivers/net/ethernet/8390/ne2.c
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ethernet/8390/ne2k-pci.c
index 3c333cb5d34e..39923425ba25 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ethernet/8390/ne2k-pci.c
@@ -207,7 +207,7 @@ static const struct net_device_ops ne2k_netdev_ops = {
.ndo_start_xmit = ei_start_xmit,
.ndo_tx_timeout = ei_tx_timeout,
.ndo_get_stats = ei_get_stats,
- .ndo_set_multicast_list = ei_set_multicast_list,
+ .ndo_set_rx_mode = ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/ne3210.c b/drivers/net/ethernet/8390/ne3210.c
index 243ed2aee88e..243ed2aee88e 100644
--- a/drivers/net/ne3210.c
+++ b/drivers/net/ethernet/8390/ne3210.c
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/ethernet/8390/pcnet_cs.c
index b4fd7c3ed077..053b2551a72d 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/ethernet/8390/pcnet_cs.c
@@ -41,7 +41,7 @@
#include <linux/log2.h>
#include <linux/etherdevice.h>
#include <linux/mii.h>
-#include "../8390.h"
+#include "8390.h"
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
@@ -227,7 +227,7 @@ static const struct net_device_ops pcnet_netdev_ops = {
.ndo_start_xmit = ei_start_xmit,
.ndo_get_stats = ei_get_stats,
.ndo_do_ioctl = ei_ioctl,
- .ndo_set_multicast_list = ei_set_multicast_list,
+ .ndo_set_rx_mode = ei_set_multicast_list,
.ndo_tx_timeout = ei_tx_timeout,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/smc-mca.c b/drivers/net/ethernet/8390/smc-mca.c
index 34934fb23b97..77efec44fea0 100644
--- a/drivers/net/smc-mca.c
+++ b/drivers/net/ethernet/8390/smc-mca.c
@@ -191,7 +191,7 @@ static const struct net_device_ops ultramca_netdev_ops = {
.ndo_start_xmit = ei_start_xmit,
.ndo_tx_timeout = ei_tx_timeout,
.ndo_get_stats = ei_get_stats,
- .ndo_set_multicast_list = ei_set_multicast_list,
+ .ndo_set_rx_mode = ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/smc-ultra.c b/drivers/net/ethernet/8390/smc-ultra.c
index ba44ede29198..1cc306a83ff7 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/ethernet/8390/smc-ultra.c
@@ -192,7 +192,7 @@ static const struct net_device_ops ultra_netdev_ops = {
.ndo_start_xmit = ei_start_xmit,
.ndo_tx_timeout = ei_tx_timeout,
.ndo_get_stats = ei_get_stats,
- .ndo_set_multicast_list = ei_set_multicast_list,
+ .ndo_set_rx_mode = ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/smc-ultra32.c b/drivers/net/ethernet/8390/smc-ultra32.c
index e459c3b2510a..bb87053eb3da 100644
--- a/drivers/net/smc-ultra32.c
+++ b/drivers/net/ethernet/8390/smc-ultra32.c
@@ -160,7 +160,7 @@ static const struct net_device_ops ultra32_netdev_ops = {
.ndo_start_xmit = ei_start_xmit,
.ndo_tx_timeout = ei_tx_timeout,
.ndo_get_stats = ei_get_stats,
- .ndo_set_multicast_list = ei_set_multicast_list,
+ .ndo_set_rx_mode = ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/stnic.c b/drivers/net/ethernet/8390/stnic.c
index d85f0a84bc7b..d85f0a84bc7b 100644
--- a/drivers/net/stnic.c
+++ b/drivers/net/ethernet/8390/stnic.c
diff --git a/drivers/net/wd.c b/drivers/net/ethernet/8390/wd.c
index 8831a3393ecf..c175fadb597b 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/ethernet/8390/wd.c
@@ -153,7 +153,7 @@ static const struct net_device_ops wd_netdev_ops = {
.ndo_start_xmit = ei_start_xmit,
.ndo_tx_timeout = ei_tx_timeout,
.ndo_get_stats = ei_get_stats,
- .ndo_set_multicast_list = ei_set_multicast_list,
+ .ndo_set_rx_mode = ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/zorro8390.c b/drivers/net/ethernet/8390/zorro8390.c
index 15e7751a273c..3aa9fe9999b5 100644
--- a/drivers/net/zorro8390.c
+++ b/drivers/net/ethernet/8390/zorro8390.c
@@ -278,7 +278,7 @@ static const struct net_device_ops zorro8390_netdev_ops = {
.ndo_start_xmit = __ei_start_xmit,
.ndo_tx_timeout = __ei_tx_timeout,
.ndo_get_stats = __ei_get_stats,
- .ndo_set_multicast_list = __ei_set_multicast_list,
+ .ndo_set_rx_mode = __ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
new file mode 100644
index 000000000000..6dff5a0e733f
--- /dev/null
+++ b/drivers/net/ethernet/Kconfig
@@ -0,0 +1,177 @@
+#
+# Ethernet LAN device configuration
+#
+
+menuconfig ETHERNET
+ bool "Ethernet driver support"
+ depends on NET
+ default y
+ ---help---
+ This section contains all the Ethernet device drivers.
+
+if ETHERNET
+
+config MDIO
+ tristate
+
+config SUNGEM_PHY
+ tristate
+
+source "drivers/net/ethernet/3com/Kconfig"
+source "drivers/net/ethernet/adaptec/Kconfig"
+source "drivers/net/ethernet/aeroflex/Kconfig"
+source "drivers/net/ethernet/alteon/Kconfig"
+source "drivers/net/ethernet/amd/Kconfig"
+source "drivers/net/ethernet/apple/Kconfig"
+source "drivers/net/ethernet/atheros/Kconfig"
+source "drivers/net/ethernet/cadence/Kconfig"
+source "drivers/net/ethernet/adi/Kconfig"
+source "drivers/net/ethernet/broadcom/Kconfig"
+source "drivers/net/ethernet/brocade/Kconfig"
+source "drivers/net/ethernet/chelsio/Kconfig"
+source "drivers/net/ethernet/cirrus/Kconfig"
+source "drivers/net/ethernet/cisco/Kconfig"
+source "drivers/net/ethernet/davicom/Kconfig"
+
+config DNET
+ tristate "Dave ethernet support (DNET)"
+ depends on HAS_IOMEM
+ select PHYLIB
+ ---help---
+ The Dave ethernet interface (DNET) is found on Qong Board FPGA.
+ Say Y to include support for the DNET chip.
+
+ To compile this driver as a module, choose M here: the module
+ will be called dnet.
+
+source "drivers/net/ethernet/dec/Kconfig"
+source "drivers/net/ethernet/dlink/Kconfig"
+source "drivers/net/ethernet/emulex/Kconfig"
+source "drivers/net/ethernet/neterion/Kconfig"
+source "drivers/net/ethernet/faraday/Kconfig"
+source "drivers/net/ethernet/freescale/Kconfig"
+source "drivers/net/ethernet/fujitsu/Kconfig"
+source "drivers/net/ethernet/hp/Kconfig"
+source "drivers/net/ethernet/ibm/Kconfig"
+source "drivers/net/ethernet/intel/Kconfig"
+source "drivers/net/ethernet/i825xx/Kconfig"
+source "drivers/net/ethernet/xscale/Kconfig"
+source "drivers/net/ethernet/icplus/Kconfig"
+
+config JME
+ tristate "JMicron(R) PCI-Express Gigabit Ethernet support"
+ depends on PCI
+ select CRC32
+ select NET_CORE
+ select MII
+ ---help---
+ This driver supports the PCI-Express gigabit ethernet adapters
+ based on JMicron JMC250 chipset.
+
+ To compile this driver as a module, choose M here. The module
+ will be called jme.
+
+config KORINA
+ tristate "Korina (IDT RC32434) Ethernet support"
+ depends on MIKROTIK_RB532
+ ---help---
+ If you have a Mikrotik RouterBoard 500 or IDT RC32434
+ based system say Y. Otherwise say N.
+
+config LANTIQ_ETOP
+ tristate "Lantiq SoC ETOP driver"
+ depends on SOC_TYPE_XWAY
+ ---help---
+ Support for the MII0 inside the Lantiq SoC
+
+source "drivers/net/ethernet/marvell/Kconfig"
+source "drivers/net/ethernet/mellanox/Kconfig"
+source "drivers/net/ethernet/micrel/Kconfig"
+source "drivers/net/ethernet/microchip/Kconfig"
+
+config MIPS_SIM_NET
+ tristate "MIPS simulator Network device"
+ depends on MIPS_SIM
+ ---help---
+ The MIPSNET device is a simple Ethernet network device which is
+ emulated by the MIPS Simulator.
+ If you are not using a MIPSsim or are unsure, say N.
+
+source "drivers/net/ethernet/myricom/Kconfig"
+
+config FEALNX
+ tristate "Myson MTD-8xx PCI Ethernet support"
+ depends on PCI
+ select CRC32
+ select NET_CORE
+ select MII
+ ---help---
+ Say Y here to support the Myson MTD-800 family of PCI-based Ethernet
+ cards. <http://www.myson.com.tw/>
+
+source "drivers/net/ethernet/natsemi/Kconfig"
+source "drivers/net/ethernet/8390/Kconfig"
+
+config NET_NETX
+ tristate "NetX Ethernet support"
+ select NET_CORE
+ select MII
+ depends on ARCH_NETX
+ ---help---
+ This is support for the Hilscher netX builtin Ethernet ports
+
+ To compile this driver as a module, choose M here. The module
+ will be called netx-eth.
+
+source "drivers/net/ethernet/nuvoton/Kconfig"
+source "drivers/net/ethernet/nvidia/Kconfig"
+source "drivers/net/ethernet/octeon/Kconfig"
+source "drivers/net/ethernet/oki-semi/Kconfig"
+
+config ETHOC
+ tristate "OpenCores 10/100 Mbps Ethernet MAC support"
+ depends on HAS_IOMEM && HAS_DMA
+ select NET_CORE
+ select MII
+ select PHYLIB
+ select CRC32
+ select BITREVERSE
+ ---help---
+ Say Y here if you want to use the OpenCores 10/100 Mbps Ethernet MAC.
+
+source "drivers/net/ethernet/packetengines/Kconfig"
+source "drivers/net/ethernet/pasemi/Kconfig"
+source "drivers/net/ethernet/qlogic/Kconfig"
+source "drivers/net/ethernet/racal/Kconfig"
+source "drivers/net/ethernet/realtek/Kconfig"
+source "drivers/net/ethernet/renesas/Kconfig"
+source "drivers/net/ethernet/rdc/Kconfig"
+
+config S6GMAC
+ tristate "S6105 GMAC ethernet support"
+ depends on XTENSA_VARIANT_S6000
+ select PHYLIB
+ ---help---
+ This driver supports the on chip ethernet device on the
+ S6105 xtensa processor.
+
+ To compile this driver as a module, choose M here. The module
+ will be called s6gmac.
+
+source "drivers/net/ethernet/seeq/Kconfig"
+source "drivers/net/ethernet/sis/Kconfig"
+source "drivers/net/ethernet/sfc/Kconfig"
+source "drivers/net/ethernet/sgi/Kconfig"
+source "drivers/net/ethernet/smsc/Kconfig"
+source "drivers/net/ethernet/stmicro/Kconfig"
+source "drivers/net/ethernet/sun/Kconfig"
+source "drivers/net/ethernet/tehuti/Kconfig"
+source "drivers/net/ethernet/ti/Kconfig"
+source "drivers/net/ethernet/tile/Kconfig"
+source "drivers/net/ethernet/toshiba/Kconfig"
+source "drivers/net/ethernet/tundra/Kconfig"
+source "drivers/net/ethernet/via/Kconfig"
+source "drivers/net/ethernet/xilinx/Kconfig"
+source "drivers/net/ethernet/xircom/Kconfig"
+
+endif # ETHERNET
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
new file mode 100644
index 000000000000..c53ad3afc991
--- /dev/null
+++ b/drivers/net/ethernet/Makefile
@@ -0,0 +1,74 @@
+#
+# Makefile for the Linux network Ethernet device drivers.
+#
+
+obj-$(CONFIG_NET_VENDOR_3COM) += 3com/
+obj-$(CONFIG_NET_VENDOR_8390) += 8390/
+obj-$(CONFIG_NET_VENDOR_ADAPTEC) += adaptec/
+obj-$(CONFIG_GRETH) += aeroflex/
+obj-$(CONFIG_NET_VENDOR_ALTEON) += alteon/
+obj-$(CONFIG_NET_VENDOR_AMD) += amd/
+obj-$(CONFIG_NET_VENDOR_APPLE) += apple/
+obj-$(CONFIG_NET_VENDOR_ATHEROS) += atheros/
+obj-$(CONFIG_NET_ATMEL) += cadence/
+obj-$(CONFIG_NET_BFIN) += adi/
+obj-$(CONFIG_NET_VENDOR_BROADCOM) += broadcom/
+obj-$(CONFIG_NET_VENDOR_BROCADE) += brocade/
+obj-$(CONFIG_NET_VENDOR_CHELSIO) += chelsio/
+obj-$(CONFIG_NET_VENDOR_CIRRUS) += cirrus/
+obj-$(CONFIG_NET_VENDOR_CISCO) += cisco/
+obj-$(CONFIG_DM9000) += davicom/
+obj-$(CONFIG_DNET) += dnet.o
+obj-$(CONFIG_NET_VENDOR_DEC) += dec/
+obj-$(CONFIG_NET_VENDOR_DLINK) += dlink/
+obj-$(CONFIG_NET_VENDOR_EMULEX) += emulex/
+obj-$(CONFIG_NET_VENDOR_EXAR) += neterion/
+obj-$(CONFIG_NET_VENDOR_FARADAY) += faraday/
+obj-$(CONFIG_NET_VENDOR_FREESCALE) += freescale/
+obj-$(CONFIG_NET_VENDOR_FUJITSU) += fujitsu/
+obj-$(CONFIG_NET_VENDOR_HP) += hp/
+obj-$(CONFIG_NET_VENDOR_IBM) += ibm/
+obj-$(CONFIG_NET_VENDOR_INTEL) += intel/
+obj-$(CONFIG_NET_VENDOR_I825XX) += i825xx/
+obj-$(CONFIG_NET_VENDOR_XSCALE) += xscale/
+obj-$(CONFIG_IP1000) += icplus/
+obj-$(CONFIG_JME) += jme.o
+obj-$(CONFIG_KORINA) += korina.o
+obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o
+obj-$(CONFIG_NET_VENDOR_MARVELL) += marvell/
+obj-$(CONFIG_NET_VENDOR_MELLANOX) += mellanox/
+obj-$(CONFIG_NET_VENDOR_MICREL) += micrel/
+obj-$(CONFIG_NET_VENDOR_MICROCHIP) += microchip/
+obj-$(CONFIG_MIPS_SIM_NET) += mipsnet.o
+obj-$(CONFIG_NET_VENDOR_MYRI) += myricom/
+obj-$(CONFIG_FEALNX) += fealnx.o
+obj-$(CONFIG_NET_VENDOR_NATSEMI) += natsemi/
+obj-$(CONFIG_NET_NETX) += netx-eth.o
+obj-$(CONFIG_NET_VENDOR_NUVOTON) += nuvoton/
+obj-$(CONFIG_NET_VENDOR_NVIDIA) += nvidia/
+obj-$(CONFIG_OCTEON_MGMT_ETHERNET) += octeon/
+obj-$(CONFIG_NET_VENDOR_OKI) += oki-semi/
+obj-$(CONFIG_ETHOC) += ethoc.o
+obj-$(CONFIG_NET_PACKET_ENGINE) += packetengines/
+obj-$(CONFIG_NET_VENDOR_PASEMI) += pasemi/
+obj-$(CONFIG_NET_VENDOR_QLOGIC) += qlogic/
+obj-$(CONFIG_NET_VENDOR_RACAL) += racal/
+obj-$(CONFIG_NET_VENDOR_REALTEK) += realtek/
+obj-$(CONFIG_SH_ETH) += renesas/
+obj-$(CONFIG_NET_VENDOR_RDC) += rdc/
+obj-$(CONFIG_S6GMAC) += s6gmac.o
+obj-$(CONFIG_NET_VENDOR_SEEQ) += seeq/
+obj-$(CONFIG_NET_VENDOR_SIS) += sis/
+obj-$(CONFIG_SFC) += sfc/
+obj-$(CONFIG_NET_VENDOR_SGI) += sgi/
+obj-$(CONFIG_NET_VENDOR_SMSC) += smsc/
+obj-$(CONFIG_NET_VENDOR_STMICRO) += stmicro/
+obj-$(CONFIG_NET_VENDOR_SUN) += sun/
+obj-$(CONFIG_NET_VENDOR_TEHUTI) += tehuti/
+obj-$(CONFIG_NET_VENDOR_TI) += ti/
+obj-$(CONFIG_TILE_NET) += tile/
+obj-$(CONFIG_NET_VENDOR_TOSHIBA) += toshiba/
+obj-$(CONFIG_NET_VENDOR_TUNDRA) += tundra/
+obj-$(CONFIG_NET_VENDOR_VIA) += via/
+obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/
+obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/
diff --git a/drivers/net/ethernet/adaptec/Kconfig b/drivers/net/ethernet/adaptec/Kconfig
new file mode 100644
index 000000000000..0bff571b1bb3
--- /dev/null
+++ b/drivers/net/ethernet/adaptec/Kconfig
@@ -0,0 +1,36 @@
+#
+# Adaptec network device configuration
+#
+
+config NET_VENDOR_ADAPTEC
+ bool "Adaptec devices"
+ default y
+ depends on PCI
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Adaptec cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_ADAPTEC
+
+config ADAPTEC_STARFIRE
+ tristate "Adaptec Starfire/DuraLAN support"
+ depends on PCI
+ select CRC32
+ select NET_CORE
+ select MII
+ ---help---
+ Say Y here if you have an Adaptec Starfire (or DuraLAN) PCI network
+ adapter. The DuraLAN chip is used on the 64 bit PCI boards from
+ Adaptec e.g. the ANA-6922A. The older 32 bit boards use the tulip
+ driver.
+
+ To compile this driver as a module, choose M here: the module
+ will be called starfire. This is recommended.
+
+endif # NET_VENDOR_ADAPTEC
diff --git a/drivers/net/ethernet/adaptec/Makefile b/drivers/net/ethernet/adaptec/Makefile
new file mode 100644
index 000000000000..6c07b758ac0a
--- /dev/null
+++ b/drivers/net/ethernet/adaptec/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Adaptec network device drivers.
+#
+
+obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
diff --git a/drivers/net/starfire.c b/drivers/net/ethernet/adaptec/starfire.c
index 7ae1f990a98e..6d9f6911000f 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/ethernet/adaptec/starfire.c
@@ -639,7 +639,7 @@ static const struct net_device_ops netdev_ops = {
.ndo_start_xmit = start_tx,
.ndo_tx_timeout = tx_timeout,
.ndo_get_stats = get_stats,
- .ndo_set_multicast_list = &set_rx_mode,
+ .ndo_set_rx_mode = set_rx_mode,
.ndo_do_ioctl = netdev_ioctl,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
@@ -1256,10 +1256,13 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
np->tx_info[entry].mapping =
pci_map_single(np->pci_dev, skb->data, skb_first_frag_len(skb), PCI_DMA_TODEVICE);
} else {
- skb_frag_t *this_frag = &skb_shinfo(skb)->frags[i - 1];
- status |= this_frag->size;
+ const skb_frag_t *this_frag = &skb_shinfo(skb)->frags[i - 1];
+ status |= skb_frag_size(this_frag);
np->tx_info[entry].mapping =
- pci_map_single(np->pci_dev, page_address(this_frag->page) + this_frag->page_offset, this_frag->size, PCI_DMA_TODEVICE);
+ pci_map_single(np->pci_dev,
+ skb_frag_address(this_frag),
+ skb_frag_size(this_frag),
+ PCI_DMA_TODEVICE);
}
np->tx_ring[entry].addr = cpu_to_dma(np->tx_info[entry].mapping);
@@ -1375,7 +1378,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
pci_unmap_single(np->pci_dev,
np->tx_info[entry].mapping,
- skb_shinfo(skb)->frags[i].size,
+ skb_frag_size(&skb_shinfo(skb)->frags[i]),
PCI_DMA_TODEVICE);
np->dirty_tx++;
entry++;
diff --git a/drivers/net/ethernet/adi/Kconfig b/drivers/net/ethernet/adi/Kconfig
new file mode 100644
index 000000000000..49a30d37ae4a
--- /dev/null
+++ b/drivers/net/ethernet/adi/Kconfig
@@ -0,0 +1,69 @@
+#
+# Blackfin device configuration
+#
+
+config NET_BFIN
+ bool "Blackfin devices"
+ depends on BF516 || BF518 || BF526 || BF527 || BF536 || BF537
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y.
+ Make sure you know the name of your card. Read the Ethernet-HOWTO,
+ available from <http://www.tldp.org/docs.html#howto>.
+
+ If unsure, say Y.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the remaining Blackfin card questions. If you say Y, you will be
+ asked for your specific card in the following questions.
+
+if NET_BFIN
+
+config BFIN_MAC
+ tristate "Blackfin on-chip MAC support"
+ depends on (BF516 || BF518 || BF526 || BF527 || BF536 || BF537)
+ select CRC32
+ select NET_CORE
+ select MII
+ select PHYLIB
+ select BFIN_MAC_USE_L1 if DMA_UNCACHED_NONE
+ ---help---
+ This is the driver for Blackfin on-chip mac device. Say Y if you want
+ it compiled into the kernel. This driver is also available as a
+ module ( = code which can be inserted in and removed from the running
+ kernel whenever you want). The module will be called bfin_mac.
+
+config BFIN_MAC_USE_L1
+ bool "Use L1 memory for rx/tx packets"
+ depends on BFIN_MAC && (BF527 || BF537)
+ default y
+ ---help---
+ To get maximum network performance, you should use L1 memory as rx/tx
+ buffers. Say N here if you want to reserve L1 memory for other uses.
+
+config BFIN_TX_DESC_NUM
+ int "Number of transmit buffer packets"
+ depends on BFIN_MAC
+ range 6 10 if BFIN_MAC_USE_L1
+ range 10 100
+ default "10"
+ ---help---
+ Set the number of buffer packets used in driver.
+
+config BFIN_RX_DESC_NUM
+ int "Number of receive buffer packets"
+ depends on BFIN_MAC
+ range 20 100 if BFIN_MAC_USE_L1
+ range 20 800
+ default "20"
+ ---help---
+ Set the number of buffer packets used in driver.
+
+config BFIN_MAC_USE_HWSTAMP
+ bool "Use IEEE 1588 hwstamp"
+ depends on BFIN_MAC && BF518
+ default y
+ ---help---
+ To support the IEEE 1588 Precision Time Protocol (PTP), select y here
+
+endif # NET_BFIN
diff --git a/drivers/net/ethernet/adi/Makefile b/drivers/net/ethernet/adi/Makefile
new file mode 100644
index 000000000000..b1fbe195d0e8
--- /dev/null
+++ b/drivers/net/ethernet/adi/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Blackfin device drivers.
+#
+
+obj-$(CONFIG_BFIN_MAC) += bfin_mac.o
diff --git a/drivers/net/bfin_mac.c b/drivers/net/ethernet/adi/bfin_mac.c
index 6c019e148546..b6d69c91db96 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/ethernet/adi/bfin_mac.c
@@ -1449,7 +1449,7 @@ static const struct net_device_ops bfin_mac_netdev_ops = {
.ndo_start_xmit = bfin_mac_hard_start_xmit,
.ndo_set_mac_address = bfin_mac_set_mac_address,
.ndo_tx_timeout = bfin_mac_timeout,
- .ndo_set_multicast_list = bfin_mac_set_multicast_list,
+ .ndo_set_rx_mode = bfin_mac_set_multicast_list,
.ndo_do_ioctl = bfin_mac_ioctl,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/bfin_mac.h b/drivers/net/ethernet/adi/bfin_mac.h
index f8559ac9a403..f8559ac9a403 100644
--- a/drivers/net/bfin_mac.h
+++ b/drivers/net/ethernet/adi/bfin_mac.h
diff --git a/drivers/net/ethernet/aeroflex/Kconfig b/drivers/net/ethernet/aeroflex/Kconfig
new file mode 100644
index 000000000000..4f4a8d78fd54
--- /dev/null
+++ b/drivers/net/ethernet/aeroflex/Kconfig
@@ -0,0 +1,11 @@
+#
+# Aeroflex Gaisler network device configuration
+#
+
+config GRETH
+ tristate "Aeroflex Gaisler GRETH Ethernet MAC support"
+ depends on SPARC
+ select PHYLIB
+ select CRC32
+ ---help---
+ Say Y here if you want to use the Aeroflex Gaisler GRETH Ethernet MAC.
diff --git a/drivers/net/ethernet/aeroflex/Makefile b/drivers/net/ethernet/aeroflex/Makefile
new file mode 100644
index 000000000000..6e62a679282f
--- /dev/null
+++ b/drivers/net/ethernet/aeroflex/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Aeroflex Gaisler network device drivers.
+#
+
+obj-$(CONFIG_GRETH) += greth.o
diff --git a/drivers/net/greth.c b/drivers/net/ethernet/aeroflex/greth.c
index 16ce45c11934..442fefa4f2ca 100644
--- a/drivers/net/greth.c
+++ b/drivers/net/ethernet/aeroflex/greth.c
@@ -113,9 +113,8 @@ static void greth_print_tx_packet(struct sk_buff *skb)
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
print_hex_dump(KERN_DEBUG, "TX: ", DUMP_PREFIX_OFFSET, 16, 1,
- phys_to_virt(page_to_phys(skb_shinfo(skb)->frags[i].page)) +
- skb_shinfo(skb)->frags[i].page_offset,
- length, true);
+ skb_frag_address(&skb_shinfo(skb)->frags[i]),
+ skb_shinfo(skb)->frags[i].size, true);
}
}
@@ -199,7 +198,7 @@ static void greth_clean_rings(struct greth_private *greth)
dma_unmap_page(greth->dev,
greth_read_bd(&tx_bdp->addr),
- frag->size,
+ skb_frag_size(frag),
DMA_TO_DEVICE);
greth->tx_last = NEXT_TX(greth->tx_last);
@@ -428,6 +427,7 @@ greth_start_xmit(struct sk_buff *skb, struct net_device *dev)
dma_sync_single_for_device(greth->dev, dma_addr, skb->len, DMA_TO_DEVICE);
status = GRETH_BD_EN | GRETH_BD_IE | (skb->len & GRETH_BD_LEN);
+ greth->tx_bufs_length[greth->tx_next] = skb->len & GRETH_BD_LEN;
/* Wrap around descriptor ring */
if (greth->tx_next == GRETH_TXBD_NUM_MASK) {
@@ -490,7 +490,8 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
if (nr_frags != 0)
status = GRETH_TXBD_MORE;
- status |= GRETH_TXBD_CSALL;
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ status |= GRETH_TXBD_CSALL;
status |= skb_headlen(skb) & GRETH_BD_LEN;
if (greth->tx_next == GRETH_TXBD_NUM_MASK)
status |= GRETH_BD_WR;
@@ -513,8 +514,10 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
greth->tx_skbuff[curr_tx] = NULL;
bdp = greth->tx_bd_base + curr_tx;
- status = GRETH_TXBD_CSALL | GRETH_BD_EN;
- status |= frag->size & GRETH_BD_LEN;
+ status = GRETH_BD_EN;
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ status |= GRETH_TXBD_CSALL;
+ status |= skb_frag_size(frag) & GRETH_BD_LEN;
/* Wrap around descriptor ring */
if (curr_tx == GRETH_TXBD_NUM_MASK)
@@ -528,11 +531,8 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
greth_write_bd(&bdp->stat, status);
- dma_addr = dma_map_page(greth->dev,
- frag->page,
- frag->page_offset,
- frag->size,
- DMA_TO_DEVICE);
+ dma_addr = skb_frag_dma_map(greth->dev, frag, 0, skb_frag_size(frag),
+ DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(greth->dev, dma_addr)))
goto frag_map_error;
@@ -641,6 +641,7 @@ static void greth_clean_tx(struct net_device *dev)
dev->stats.tx_fifo_errors++;
}
dev->stats.tx_packets++;
+ dev->stats.tx_bytes += greth->tx_bufs_length[greth->tx_last];
greth->tx_last = NEXT_TX(greth->tx_last);
greth->tx_free++;
}
@@ -695,6 +696,7 @@ static void greth_clean_tx_gbit(struct net_device *dev)
greth->tx_skbuff[greth->tx_last] = NULL;
greth_update_tx_stats(dev, stat);
+ dev->stats.tx_bytes += skb->len;
bdp = greth->tx_bd_base + greth->tx_last;
@@ -711,7 +713,7 @@ static void greth_clean_tx_gbit(struct net_device *dev)
dma_unmap_page(greth->dev,
greth_read_bd(&bdp->addr),
- frag->size,
+ skb_frag_size(frag),
DMA_TO_DEVICE);
greth->tx_last = NEXT_TX(greth->tx_last);
@@ -796,6 +798,7 @@ static int greth_rx(struct net_device *dev, int limit)
memcpy(skb_put(skb, pkt_len), phys_to_virt(dma_addr), pkt_len);
skb->protocol = eth_type_trans(skb, dev);
+ dev->stats.rx_bytes += pkt_len;
dev->stats.rx_packets++;
netif_receive_skb(skb);
}
@@ -910,6 +913,7 @@ static int greth_rx_gbit(struct net_device *dev, int limit)
skb->protocol = eth_type_trans(skb, dev);
dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
netif_receive_skb(skb);
greth->rx_skbuff[greth->rx_cur] = newskb;
@@ -1539,7 +1543,7 @@ static int __devinit greth_of_probe(struct platform_device *ofdev)
}
if (greth->multicast) {
- greth_netdev_ops.ndo_set_multicast_list = greth_set_multicast_list;
+ greth_netdev_ops.ndo_set_rx_mode = greth_set_multicast_list;
dev->flags |= IFF_MULTICAST;
} else {
dev->flags &= ~IFF_MULTICAST;
diff --git a/drivers/net/greth.h b/drivers/net/ethernet/aeroflex/greth.h
index 9a0040dee4da..232a622a85b7 100644
--- a/drivers/net/greth.h
+++ b/drivers/net/ethernet/aeroflex/greth.h
@@ -103,6 +103,7 @@ struct greth_private {
unsigned char *tx_bufs[GRETH_TXBD_NUM];
unsigned char *rx_bufs[GRETH_RXBD_NUM];
+ u16 tx_bufs_length[GRETH_TXBD_NUM];
u16 tx_next;
u16 tx_last;
diff --git a/drivers/net/ethernet/alteon/Kconfig b/drivers/net/ethernet/alteon/Kconfig
new file mode 100644
index 000000000000..799a85282070
--- /dev/null
+++ b/drivers/net/ethernet/alteon/Kconfig
@@ -0,0 +1,48 @@
+#
+# Alteon network device configuration
+#
+
+config NET_VENDOR_ALTEON
+ bool "Alteon devices"
+ default y
+ depends on PCI
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Alteon cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_ALTEON
+
+config ACENIC
+ tristate "Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support"
+ depends on PCI
+ ---help---
+ Say Y here if you have an Alteon AceNIC, 3Com 3C985(B), NetGear
+ GA620, SGI Gigabit or Farallon PN9000-SX PCI Gigabit Ethernet
+ adapter. The driver allows for using the Jumbo Frame option (9000
+ bytes/frame) however it requires that your switches can handle this
+ as well. To enable Jumbo Frames, add `mtu 9000' to your ifconfig
+ line.
+
+ To compile this driver as a module, choose M here: the
+ module will be called acenic.
+
+config ACENIC_OMIT_TIGON_I
+ bool "Omit support for old Tigon I based AceNICs"
+ depends on ACENIC
+ ---help---
+ Say Y here if you only have Tigon II based AceNICs and want to leave
+ out support for the older Tigon I based cards which are no longer
+ being sold (ie. the original Alteon AceNIC and 3Com 3C985 (non B
+ version)). This will reduce the size of the driver object by
+ app. 100KB. If you are not sure whether your card is a Tigon I or a
+ Tigon II, say N here.
+
+ The safe and default value for this is N.
+
+endif # NET_VENDOR_ALTEON
diff --git a/drivers/net/ethernet/alteon/Makefile b/drivers/net/ethernet/alteon/Makefile
new file mode 100644
index 000000000000..a2ca173f2a50
--- /dev/null
+++ b/drivers/net/ethernet/alteon/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Alteon network device drivers.
+#
+
+obj-$(CONFIG_ACENIC) += acenic.o
diff --git a/drivers/net/acenic.c b/drivers/net/ethernet/alteon/acenic.c
index 31798f5f5d06..f872748ab4e6 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/ethernet/alteon/acenic.c
@@ -449,7 +449,7 @@ static const struct net_device_ops ace_netdev_ops = {
.ndo_tx_timeout = ace_watchdog,
.ndo_get_stats = ace_get_stats,
.ndo_start_xmit = ace_start_xmit,
- .ndo_set_multicast_list = ace_set_multicast_list,
+ .ndo_set_rx_mode = ace_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = ace_set_mac_addr,
.ndo_change_mtu = ace_change_mtu,
@@ -2478,18 +2478,18 @@ restart:
idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap);
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
struct tx_ring_info *info;
- len += frag->size;
+ len += skb_frag_size(frag);
info = ap->skb->tx_skbuff + idx;
desc = ap->tx_ring + idx;
- mapping = pci_map_page(ap->pdev, frag->page,
- frag->page_offset, frag->size,
- PCI_DMA_TODEVICE);
+ mapping = skb_frag_dma_map(&ap->pdev->dev, frag, 0,
+ skb_frag_size(frag),
+ DMA_TO_DEVICE);
- flagsize = (frag->size << 16);
+ flagsize = skb_frag_size(frag) << 16;
if (skb->ip_summed == CHECKSUM_PARTIAL)
flagsize |= BD_FLG_TCP_UDP_SUM;
idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap);
@@ -2508,7 +2508,7 @@ restart:
info->skb = NULL;
}
dma_unmap_addr_set(info, mapping, mapping);
- dma_unmap_len_set(info, maplen, frag->size);
+ dma_unmap_len_set(info, maplen, skb_frag_size(frag));
ace_load_tx_bd(ap, desc, mapping, flagsize, vlan_tag);
}
}
diff --git a/drivers/net/acenic.h b/drivers/net/ethernet/alteon/acenic.h
index 51c486cfbb8c..51c486cfbb8c 100644
--- a/drivers/net/acenic.h
+++ b/drivers/net/ethernet/alteon/acenic.h
diff --git a/drivers/net/7990.c b/drivers/net/ethernet/amd/7990.c
index 60b35fb5f524..60b35fb5f524 100644
--- a/drivers/net/7990.c
+++ b/drivers/net/ethernet/amd/7990.c
diff --git a/drivers/net/7990.h b/drivers/net/ethernet/amd/7990.h
index 0a5837b96421..0a5837b96421 100644
--- a/drivers/net/7990.h
+++ b/drivers/net/ethernet/amd/7990.h
diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig
new file mode 100644
index 000000000000..238b537b68fe
--- /dev/null
+++ b/drivers/net/ethernet/amd/Kconfig
@@ -0,0 +1,195 @@
+#
+# AMD network device configuration
+#
+
+config NET_VENDOR_AMD
+ bool "AMD devices"
+ default y
+ depends on DIO || MACH_DECSTATION || MVME147 || ATARI || SUN3 || \
+ SUN3X || SBUS || PCI || ZORRO || (ISA && ISA_DMA_API) || \
+ (ARM && ARCH_EBSA110) || ISA || EISA || MCA || PCMCIA
+ ---help---
+ If you have a network (Ethernet) chipset belonging to this class,
+ say Y.
+
+ Note that the answer to this question does not directly affect
+ the kernel: saying N will just case the configurator to skip all
+ the questions regarding AMD chipsets. If you say Y, you will be asked
+ for your specific chipset/driver in the following questions.
+
+if NET_VENDOR_AMD
+
+config A2065
+ tristate "A2065 support"
+ depends on ZORRO
+ select CRC32
+ ---help---
+ If you have a Commodore A2065 Ethernet adapter, say Y. Otherwise,
+ say N.
+
+ To compile this driver as a module, choose M here: the module
+ will be called a2065.
+
+config AMD8111_ETH
+ tristate "AMD 8111 (new PCI LANCE) support"
+ depends on PCI
+ select CRC32
+ select NET_CORE
+ select MII
+ ---help---
+ If you have an AMD 8111-based PCI LANCE ethernet card,
+ answer Y here and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called amd8111e.
+
+config LANCE
+ tristate "AMD LANCE and PCnet (AT1500 and NE2100) support"
+ depends on ISA && ISA_DMA_API
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>. Some LinkSys cards are
+ of this type.
+
+ To compile this driver as a module, choose M here: the module
+ will be called lance. This is recommended.
+
+config PCNET32
+ tristate "AMD PCnet32 PCI support"
+ depends on PCI
+ select CRC32
+ select NET_CORE
+ select MII
+ ---help---
+ If you have a PCnet32 or PCnetPCI based network (Ethernet) card,
+ answer Y here and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called pcnet32.
+
+config ARIADNE
+ tristate "Ariadne support"
+ depends on ZORRO
+ ---help---
+ If you have a Village Tronic Ariadne Ethernet adapter, say Y.
+ Otherwise, say N.
+
+ To compile this driver as a module, choose M here: the module
+ will be called ariadne.
+
+config ARM_AM79C961A
+ bool "ARM EBSA110 AM79C961A support"
+ depends on ARM && ARCH_EBSA110
+ select CRC32
+ ---help---
+ If you wish to compile a kernel for the EBSA-110, then you should
+ always answer Y to this.
+
+config ATARILANCE
+ tristate "Atari LANCE support"
+ depends on ATARI
+ ---help---
+ Say Y to include support for several Atari Ethernet adapters based
+ on the AMD LANCE chipset: RieblCard (with or without battery), or
+ PAMCard VME (also the version by Rhotron, with different addresses).
+
+config DECLANCE
+ tristate "DEC LANCE ethernet controller support"
+ depends on MACH_DECSTATION
+ select CRC32
+ ---help---
+ This driver is for the series of Ethernet controllers produced by
+ DEC (now Compaq) based on the AMD LANCE chipset, including the
+ DEPCA series. (This chipset is better known via the NE2100 cards.)
+
+config DEPCA
+ tristate "DEPCA, DE10x, DE200, DE201, DE202, DE422 support"
+ depends on (ISA || EISA || MCA)
+ select CRC32
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto> as well as
+ <file:drivers/net/depca.c>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called depca.
+
+config HPLANCE
+ bool "HP on-board LANCE support"
+ depends on DIO
+ select CRC32
+ ---help---
+ If you want to use the builtin "LANCE" Ethernet controller on an
+ HP300 machine, say Y here.
+
+config MIPS_AU1X00_ENET
+ tristate "MIPS AU1000 Ethernet support"
+ depends on MIPS_ALCHEMY
+ select PHYLIB
+ select CRC32
+ ---help---
+ If you have an Alchemy Semi AU1X00 based system
+ say Y. Otherwise, say N.
+
+config MVME147_NET
+ tristate "MVME147 (LANCE) Ethernet support"
+ depends on MVME147
+ select CRC32
+ ---help---
+ Support for the on-board Ethernet interface on the Motorola MVME147
+ single-board computer. Say Y here to include the
+ driver for this chip in your kernel.
+ To compile this driver as a module, choose M here.
+
+config PCMCIA_NMCLAN
+ tristate "New Media PCMCIA support"
+ depends on PCMCIA
+ help
+ Say Y here if you intend to attach a New Media Ethernet or LiveWire
+ PCMCIA (PC-card) Ethernet card to your computer.
+
+ To compile this driver as a module, choose M here: the module will be
+ called nmclan_cs. If unsure, say N.
+
+config NI65
+ tristate "NI6510 support"
+ depends on ISA && ISA_DMA_API
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called ni65.
+
+config SUN3LANCE
+ tristate "Sun3/Sun3x on-board LANCE support"
+ depends on (SUN3 || SUN3X)
+ ---help---
+ Most Sun3 and Sun3x motherboards (including the 3/50, 3/60 and 3/80)
+ featured an AMD LANCE 10Mbit Ethernet controller on board; say Y
+ here to compile in the Linux driver for this and enable Ethernet.
+ General Linux information on the Sun 3 and 3x series (now
+ discontinued) is at
+ <http://www.angelfire.com/ca2/tech68k/sun3.html>.
+
+ If you're not building a kernel for a Sun 3, say N.
+
+config SUNLANCE
+ tristate "Sun LANCE support"
+ depends on SBUS
+ select CRC32
+ ---help---
+ This driver supports the "le" interface present on all 32-bit Sparc
+ systems, on some older Ultra systems and as an Sbus option. These
+ cards are based on the AMD LANCE chipset, which is better known
+ via the NE2100 cards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called sunlance.
+
+endif # NET_VENDOR_AMD
diff --git a/drivers/net/ethernet/amd/Makefile b/drivers/net/ethernet/amd/Makefile
new file mode 100644
index 000000000000..175caa5328c9
--- /dev/null
+++ b/drivers/net/ethernet/amd/Makefile
@@ -0,0 +1,20 @@
+#
+# Makefile for the AMD network device drivers.
+#
+
+obj-$(CONFIG_A2065) += a2065.o
+obj-$(CONFIG_AMD8111_ETH) += amd8111e.o
+obj-$(CONFIG_ARM_AM79C961A) += am79c961a.o
+obj-$(CONFIG_ARIADNE) += ariadne.o
+obj-$(CONFIG_ATARILANCE) += atarilance.o
+obj-$(CONFIG_DECLANCE) += declance.o
+obj-$(CONFIG_DEPCA) += depca.o
+obj-$(CONFIG_HPLANCE) += hplance.o 7990.o
+obj-$(CONFIG_LANCE) += lance.o
+obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
+obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o
+obj-$(CONFIG_PCMCIA_NMCLAN) += nmclan_cs.o
+obj-$(CONFIG_NI65) += ni65.o
+obj-$(CONFIG_PCNET32) += pcnet32.o
+obj-$(CONFIG_SUN3LANCE) += sun3lance.o
+obj-$(CONFIG_SUNLANCE) += sunlance.o
diff --git a/drivers/net/a2065.c b/drivers/net/ethernet/amd/a2065.c
index e1e1b07d9b8d..825e5d4ef4c3 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/ethernet/amd/a2065.c
@@ -664,7 +664,7 @@ static const struct net_device_ops lance_netdev_ops = {
.ndo_stop = lance_close,
.ndo_start_xmit = lance_start_xmit,
.ndo_tx_timeout = lance_tx_timeout,
- .ndo_set_multicast_list = lance_set_multicast,
+ .ndo_set_rx_mode = lance_set_multicast,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/a2065.h b/drivers/net/ethernet/amd/a2065.h
index 5117759d4e9c..5117759d4e9c 100644
--- a/drivers/net/a2065.h
+++ b/drivers/net/ethernet/amd/a2065.h
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/ethernet/amd/am79c961a.c
index 52fe21e1e2cd..7d5ded80d2d7 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/ethernet/amd/am79c961a.c
@@ -308,8 +308,11 @@ static void am79c961_timer(unsigned long data)
struct net_device *dev = (struct net_device *)data;
struct dev_priv *priv = netdev_priv(dev);
unsigned int lnkstat, carrier;
+ unsigned long flags;
+ spin_lock_irqsave(&priv->chip_lock, flags);
lnkstat = read_ireg(dev->base_addr, ISALED0) & ISALED0_LNKST;
+ spin_unlock_irqrestore(&priv->chip_lock, flags);
carrier = netif_carrier_ok(dev);
if (lnkstat && !carrier) {
@@ -659,7 +662,7 @@ static const struct net_device_ops am79c961_netdev_ops = {
.ndo_open = am79c961_open,
.ndo_stop = am79c961_close,
.ndo_start_xmit = am79c961_sendpacket,
- .ndo_set_multicast_list = am79c961_setmulticastlist,
+ .ndo_set_rx_mode = am79c961_setmulticastlist,
.ndo_tx_timeout = am79c961_timeout,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/arm/am79c961a.h b/drivers/net/ethernet/amd/am79c961a.h
index fd634d32756b..fd634d32756b 100644
--- a/drivers/net/arm/am79c961a.h
+++ b/drivers/net/ethernet/amd/am79c961a.h
diff --git a/drivers/net/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c
index 78002ef9c0e5..a9745f4ddbfe 100644
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/ethernet/amd/amd8111e.c
@@ -1798,7 +1798,7 @@ static const struct net_device_ops amd8111e_netdev_ops = {
.ndo_start_xmit = amd8111e_start_xmit,
.ndo_tx_timeout = amd8111e_tx_timeout,
.ndo_get_stats = amd8111e_get_stats,
- .ndo_set_multicast_list = amd8111e_set_multicast_list,
+ .ndo_set_rx_mode = amd8111e_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = amd8111e_set_mac_address,
.ndo_do_ioctl = amd8111e_ioctl,
diff --git a/drivers/net/amd8111e.h b/drivers/net/ethernet/amd/amd8111e.h
index 2ff2e7a12dd0..2ff2e7a12dd0 100644
--- a/drivers/net/amd8111e.h
+++ b/drivers/net/ethernet/amd/amd8111e.h
diff --git a/drivers/net/ariadne.c b/drivers/net/ethernet/amd/ariadne.c
index 7ed78f402042..eb18e1fe65c8 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ethernet/amd/ariadne.c
@@ -704,7 +704,7 @@ static const struct net_device_ops ariadne_netdev_ops = {
.ndo_start_xmit = ariadne_start_xmit,
.ndo_tx_timeout = ariadne_tx_timeout,
.ndo_get_stats = ariadne_get_stats,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/ariadne.h b/drivers/net/ethernet/amd/ariadne.h
index 727be5cdd1ea..727be5cdd1ea 100644
--- a/drivers/net/ariadne.h
+++ b/drivers/net/ethernet/amd/ariadne.h
diff --git a/drivers/net/atarilance.c b/drivers/net/ethernet/amd/atarilance.c
index 1264d781b554..15bfa28d6c53 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/ethernet/amd/atarilance.c
@@ -456,7 +456,7 @@ static const struct net_device_ops lance_netdev_ops = {
.ndo_open = lance_open,
.ndo_stop = lance_close,
.ndo_start_xmit = lance_start_xmit,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_set_mac_address = lance_set_mac_address,
.ndo_tx_timeout = lance_tx_timeout,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c
index b9debcfb61a0..82386677bb8c 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/ethernet/amd/au1000_eth.c
@@ -1010,7 +1010,7 @@ static const struct net_device_ops au1000_netdev_ops = {
.ndo_open = au1000_open,
.ndo_stop = au1000_close,
.ndo_start_xmit = au1000_tx,
- .ndo_set_multicast_list = au1000_multicast_list,
+ .ndo_set_rx_mode = au1000_multicast_list,
.ndo_do_ioctl = au1000_ioctl,
.ndo_tx_timeout = au1000_tx_timeout,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/au1000_eth.h b/drivers/net/ethernet/amd/au1000_eth.h
index 6229c774552c..6229c774552c 100644
--- a/drivers/net/au1000_eth.h
+++ b/drivers/net/ethernet/amd/au1000_eth.h
diff --git a/drivers/net/declance.c b/drivers/net/ethernet/amd/declance.c
index d5598f6584a3..73f8d4fa682d 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/ethernet/amd/declance.c
@@ -1015,7 +1015,7 @@ static const struct net_device_ops lance_netdev_ops = {
.ndo_stop = lance_close,
.ndo_start_xmit = lance_start_xmit,
.ndo_tx_timeout = lance_tx_timeout,
- .ndo_set_multicast_list = lance_set_multicast,
+ .ndo_set_rx_mode = lance_set_multicast,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/depca.c b/drivers/net/ethernet/amd/depca.c
index f2015a851977..681970c07f22 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/ethernet/amd/depca.c
@@ -572,7 +572,7 @@ static const struct net_device_ops depca_netdev_ops = {
.ndo_open = depca_open,
.ndo_start_xmit = depca_start_xmit,
.ndo_stop = depca_close,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_do_ioctl = depca_ioctl,
.ndo_tx_timeout = depca_tx_timeout,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/depca.h b/drivers/net/ethernet/amd/depca.h
index ee42648dbde6..cdcfe4252c16 100644
--- a/drivers/net/depca.h
+++ b/drivers/net/ethernet/amd/depca.h
@@ -157,8 +157,6 @@
*/
#include <linux/sockios.h>
-#define DEPCAIOCTL SIOCDEVPRIVATE
-
struct depca_ioctl {
unsigned short cmd; /* Command to run */
unsigned short len; /* Length of the data buffer */
diff --git a/drivers/net/hplance.c b/drivers/net/ethernet/amd/hplance.c
index a900d5bf2948..86aa0d546a5b 100644
--- a/drivers/net/hplance.c
+++ b/drivers/net/ethernet/amd/hplance.c
@@ -74,7 +74,7 @@ static const struct net_device_ops hplance_netdev_ops = {
.ndo_open = hplance_open,
.ndo_stop = hplance_close,
.ndo_start_xmit = lance_start_xmit,
- .ndo_set_multicast_list = lance_set_multicast,
+ .ndo_set_rx_mode = lance_set_multicast,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/hplance.h b/drivers/net/ethernet/amd/hplance.h
index 04aee9e0376a..04aee9e0376a 100644
--- a/drivers/net/hplance.h
+++ b/drivers/net/ethernet/amd/hplance.h
diff --git a/drivers/net/lance.c b/drivers/net/ethernet/amd/lance.c
index 02336edce748..a6e2e840884e 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/ethernet/amd/lance.c
@@ -459,7 +459,7 @@ static const struct net_device_ops lance_netdev_ops = {
.ndo_start_xmit = lance_start_xmit,
.ndo_stop = lance_close,
.ndo_get_stats = lance_get_stats,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_tx_timeout = lance_tx_timeout,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/mvme147.c b/drivers/net/ethernet/amd/mvme147.c
index 3a7ad840d5b5..56bc47a94186 100644
--- a/drivers/net/mvme147.c
+++ b/drivers/net/ethernet/amd/mvme147.c
@@ -61,7 +61,7 @@ static const struct net_device_ops lance_netdev_ops = {
.ndo_open = m147lance_open,
.ndo_stop = m147lance_close,
.ndo_start_xmit = lance_start_xmit,
- .ndo_set_multicast_list = lance_set_multicast,
+ .ndo_set_rx_mode = lance_set_multicast,
.ndo_tx_timeout = lance_tx_timeout,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/ni65.c b/drivers/net/ethernet/amd/ni65.c
index c75ae85eb918..6e6aa7213aab 100644
--- a/drivers/net/ni65.c
+++ b/drivers/net/ethernet/amd/ni65.c
@@ -406,7 +406,7 @@ static const struct net_device_ops ni65_netdev_ops = {
.ndo_stop = ni65_close,
.ndo_start_xmit = ni65_send_packet,
.ndo_tx_timeout = ni65_timeout,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/ni65.h b/drivers/net/ethernet/amd/ni65.h
index e6217e35edf0..e6217e35edf0 100644
--- a/drivers/net/ni65.h
+++ b/drivers/net/ethernet/amd/ni65.h
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/ethernet/amd/nmclan_cs.c
index 9d70b6595220..3accd5d21b08 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/ethernet/amd/nmclan_cs.c
@@ -430,7 +430,7 @@ static const struct net_device_ops mace_netdev_ops = {
.ndo_tx_timeout = mace_tx_timeout,
.ndo_set_config = mace_config,
.ndo_get_stats = mace_get_stats,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c
index 80b6f36a8074..f92bc6e34828 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/ethernet/amd/pcnet32.c
@@ -270,7 +270,7 @@ struct pcnet32_private {
struct sk_buff **rx_skbuff;
dma_addr_t *tx_dma_addr;
dma_addr_t *rx_dma_addr;
- struct pcnet32_access a;
+ const struct pcnet32_access *a;
spinlock_t lock; /* Guard lock */
unsigned int cur_rx, cur_tx; /* The next free ring entry */
unsigned int rx_ring_size; /* current rx ring size */
@@ -379,7 +379,7 @@ static int pcnet32_wio_check(unsigned long addr)
return inw(addr + PCNET32_WIO_RAP) == 88;
}
-static struct pcnet32_access pcnet32_wio = {
+static const struct pcnet32_access pcnet32_wio = {
.read_csr = pcnet32_wio_read_csr,
.write_csr = pcnet32_wio_write_csr,
.read_bcr = pcnet32_wio_read_bcr,
@@ -434,7 +434,7 @@ static int pcnet32_dwio_check(unsigned long addr)
return (inl(addr + PCNET32_DWIO_RAP) & 0xffff) == 88;
}
-static struct pcnet32_access pcnet32_dwio = {
+static const struct pcnet32_access pcnet32_dwio = {
.read_csr = pcnet32_dwio_read_csr,
.write_csr = pcnet32_dwio_write_csr,
.read_bcr = pcnet32_dwio_read_bcr,
@@ -460,9 +460,9 @@ static void pcnet32_netif_start(struct net_device *dev)
u16 val;
netif_wake_queue(dev);
- val = lp->a.read_csr(ioaddr, CSR3);
+ val = lp->a->read_csr(ioaddr, CSR3);
val &= 0x00ff;
- lp->a.write_csr(ioaddr, CSR3, val);
+ lp->a->write_csr(ioaddr, CSR3, val);
napi_enable(&lp->napi);
}
@@ -730,7 +730,7 @@ static u32 pcnet32_get_link(struct net_device *dev)
r = mii_link_ok(&lp->mii_if);
} else if (lp->chip_version >= PCNET32_79C970A) {
ulong ioaddr = dev->base_addr; /* card base I/O address */
- r = (lp->a.read_bcr(ioaddr, 4) != 0xc0);
+ r = (lp->a->read_bcr(ioaddr, 4) != 0xc0);
} else { /* can not detect link on really old chips */
r = 1;
}
@@ -792,7 +792,7 @@ static int pcnet32_set_ringparam(struct net_device *dev,
pcnet32_netif_stop(dev);
spin_lock_irqsave(&lp->lock, flags);
- lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */
+ lp->a->write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */
size = min(ering->tx_pending, (unsigned int)TX_MAX_RING_SIZE);
@@ -868,7 +868,7 @@ static void pcnet32_ethtool_test(struct net_device *dev,
static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
{
struct pcnet32_private *lp = netdev_priv(dev);
- struct pcnet32_access *a = &lp->a; /* access to registers */
+ const struct pcnet32_access *a = lp->a; /* access to registers */
ulong ioaddr = dev->base_addr; /* card base I/O address */
struct sk_buff *skb; /* sk buff */
int x, i; /* counters */
@@ -888,21 +888,21 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
pcnet32_netif_stop(dev);
spin_lock_irqsave(&lp->lock, flags);
- lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */
+ lp->a->write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */
numbuffs = min(numbuffs, (int)min(lp->rx_ring_size, lp->tx_ring_size));
/* Reset the PCNET32 */
- lp->a.reset(ioaddr);
- lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */
+ lp->a->reset(ioaddr);
+ lp->a->write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */
/* switch pcnet32 to 32bit mode */
- lp->a.write_bcr(ioaddr, 20, 2);
+ lp->a->write_bcr(ioaddr, 20, 2);
/* purge & init rings but don't actually restart */
pcnet32_restart(dev, 0x0000);
- lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* Set STOP bit */
+ lp->a->write_csr(ioaddr, CSR0, CSR0_STOP); /* Set STOP bit */
/* Initialize Transmit buffers. */
size = data_len + 15;
@@ -947,10 +947,10 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
/* set int loopback in CSR15 */
x = a->read_csr(ioaddr, CSR15) & 0xfffc;
- lp->a.write_csr(ioaddr, CSR15, x | 0x0044);
+ lp->a->write_csr(ioaddr, CSR15, x | 0x0044);
teststatus = cpu_to_le16(0x8000);
- lp->a.write_csr(ioaddr, CSR0, CSR0_START); /* Set STRT bit */
+ lp->a->write_csr(ioaddr, CSR0, CSR0_START); /* Set STRT bit */
/* Check status of descriptors */
for (x = 0; x < numbuffs; x++) {
@@ -969,7 +969,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
}
}
- lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* Set STOP bit */
+ lp->a->write_csr(ioaddr, CSR0, CSR0_STOP); /* Set STOP bit */
wmb();
if (netif_msg_hw(lp) && netif_msg_pktdata(lp)) {
netdev_printk(KERN_DEBUG, dev, "RX loopback packets:\n");
@@ -1015,7 +1015,7 @@ clean_up:
pcnet32_restart(dev, CSR0_NORMAL);
} else {
pcnet32_purge_rx_ring(dev);
- lp->a.write_bcr(ioaddr, 20, 4); /* return to 16bit mode */
+ lp->a->write_bcr(ioaddr, 20, 4); /* return to 16bit mode */
}
spin_unlock_irqrestore(&lp->lock, flags);
@@ -1026,7 +1026,7 @@ static int pcnet32_set_phys_id(struct net_device *dev,
enum ethtool_phys_id_state state)
{
struct pcnet32_private *lp = netdev_priv(dev);
- struct pcnet32_access *a = &lp->a;
+ const struct pcnet32_access *a = lp->a;
ulong ioaddr = dev->base_addr;
unsigned long flags;
int i;
@@ -1067,7 +1067,7 @@ static int pcnet32_suspend(struct net_device *dev, unsigned long *flags,
{
int csr5;
struct pcnet32_private *lp = netdev_priv(dev);
- struct pcnet32_access *a = &lp->a;
+ const struct pcnet32_access *a = lp->a;
ulong ioaddr = dev->base_addr;
int ticks;
@@ -1324,8 +1324,8 @@ static int pcnet32_poll(struct napi_struct *napi, int budget)
spin_lock_irqsave(&lp->lock, flags);
if (pcnet32_tx(dev)) {
/* reset the chip to clear the error condition, then restart */
- lp->a.reset(ioaddr);
- lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */
+ lp->a->reset(ioaddr);
+ lp->a->write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */
pcnet32_restart(dev, CSR0_START);
netif_wake_queue(dev);
}
@@ -1337,12 +1337,12 @@ static int pcnet32_poll(struct napi_struct *napi, int budget)
__napi_complete(napi);
/* clear interrupt masks */
- val = lp->a.read_csr(ioaddr, CSR3);
+ val = lp->a->read_csr(ioaddr, CSR3);
val &= 0x00ff;
- lp->a.write_csr(ioaddr, CSR3, val);
+ lp->a->write_csr(ioaddr, CSR3, val);
/* Set interrupt enable. */
- lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN);
+ lp->a->write_csr(ioaddr, CSR0, CSR0_INTEN);
spin_unlock_irqrestore(&lp->lock, flags);
}
@@ -1365,7 +1365,7 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
int i, csr0;
u16 *buff = ptr;
struct pcnet32_private *lp = netdev_priv(dev);
- struct pcnet32_access *a = &lp->a;
+ const struct pcnet32_access *a = lp->a;
ulong ioaddr = dev->base_addr;
unsigned long flags;
@@ -1401,9 +1401,9 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
for (j = 0; j < PCNET32_MAX_PHYS; j++) {
if (lp->phymask & (1 << j)) {
for (i = 0; i < PCNET32_REGS_PER_PHY; i++) {
- lp->a.write_bcr(ioaddr, 33,
+ lp->a->write_bcr(ioaddr, 33,
(j << 5) | i);
- *buff++ = lp->a.read_bcr(ioaddr, 34);
+ *buff++ = lp->a->read_bcr(ioaddr, 34);
}
}
}
@@ -1505,7 +1505,7 @@ static const struct net_device_ops pcnet32_netdev_ops = {
.ndo_start_xmit = pcnet32_start_xmit,
.ndo_tx_timeout = pcnet32_tx_timeout,
.ndo_get_stats = pcnet32_get_stats,
- .ndo_set_multicast_list = pcnet32_set_multicast_list,
+ .ndo_set_rx_mode = pcnet32_set_multicast_list,
.ndo_do_ioctl = pcnet32_ioctl,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
@@ -1528,7 +1528,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
int chip_version;
char *chipname;
struct net_device *dev;
- struct pcnet32_access *a = NULL;
+ const struct pcnet32_access *a = NULL;
u8 promaddr[6];
int ret = -ENODEV;
@@ -1785,7 +1785,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
((cards_found >= MAX_UNITS) || full_duplex[cards_found]))
lp->options |= PCNET32_PORT_FD;
- lp->a = *a;
+ lp->a = a;
/* prior to register_netdev, dev->name is not yet correct */
if (pcnet32_alloc_ring(dev, pci_name(lp->pci_dev))) {
@@ -1844,7 +1844,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
if (lp->mii) {
/* lp->phycount and lp->phymask are set to 0 by memset above */
- lp->mii_if.phy_id = ((lp->a.read_bcr(ioaddr, 33)) >> 5) & 0x1f;
+ lp->mii_if.phy_id = ((lp->a->read_bcr(ioaddr, 33)) >> 5) & 0x1f;
/* scan for PHYs */
for (i = 0; i < PCNET32_MAX_PHYS; i++) {
unsigned short id1, id2;
@@ -1864,7 +1864,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
pr_info("Found PHY %04x:%04x at address %d\n",
id1, id2, i);
}
- lp->a.write_bcr(ioaddr, 33, (lp->mii_if.phy_id) << 5);
+ lp->a->write_bcr(ioaddr, 33, (lp->mii_if.phy_id) << 5);
if (lp->phycount > 1)
lp->options |= PCNET32_PORT_MII;
}
@@ -2020,10 +2020,10 @@ static int pcnet32_open(struct net_device *dev)
}
/* Reset the PCNET32 */
- lp->a.reset(ioaddr);
+ lp->a->reset(ioaddr);
/* switch pcnet32 to 32bit mode */
- lp->a.write_bcr(ioaddr, 20, 2);
+ lp->a->write_bcr(ioaddr, 20, 2);
netif_printk(lp, ifup, KERN_DEBUG, dev,
"%s() irq %d tx/rx rings %#x/%#x init %#x\n",
@@ -2032,14 +2032,14 @@ static int pcnet32_open(struct net_device *dev)
(u32) (lp->init_dma_addr));
/* set/reset autoselect bit */
- val = lp->a.read_bcr(ioaddr, 2) & ~2;
+ val = lp->a->read_bcr(ioaddr, 2) & ~2;
if (lp->options & PCNET32_PORT_ASEL)
val |= 2;
- lp->a.write_bcr(ioaddr, 2, val);
+ lp->a->write_bcr(ioaddr, 2, val);
/* handle full duplex setting */
if (lp->mii_if.full_duplex) {
- val = lp->a.read_bcr(ioaddr, 9) & ~3;
+ val = lp->a->read_bcr(ioaddr, 9) & ~3;
if (lp->options & PCNET32_PORT_FD) {
val |= 1;
if (lp->options == (PCNET32_PORT_FD | PCNET32_PORT_AUI))
@@ -2049,14 +2049,14 @@ static int pcnet32_open(struct net_device *dev)
if (lp->chip_version == 0x2627)
val |= 3;
}
- lp->a.write_bcr(ioaddr, 9, val);
+ lp->a->write_bcr(ioaddr, 9, val);
}
/* set/reset GPSI bit in test register */
- val = lp->a.read_csr(ioaddr, 124) & ~0x10;
+ val = lp->a->read_csr(ioaddr, 124) & ~0x10;
if ((lp->options & PCNET32_PORT_PORTSEL) == PCNET32_PORT_GPSI)
val |= 0x10;
- lp->a.write_csr(ioaddr, 124, val);
+ lp->a->write_csr(ioaddr, 124, val);
/* Allied Telesyn AT 2700/2701 FX are 100Mbit only and do not negotiate */
if (pdev && pdev->subsystem_vendor == PCI_VENDOR_ID_AT &&
@@ -2075,24 +2075,24 @@ static int pcnet32_open(struct net_device *dev)
* duplex, and/or enable auto negotiation, and clear DANAS
*/
if (lp->mii && !(lp->options & PCNET32_PORT_ASEL)) {
- lp->a.write_bcr(ioaddr, 32,
- lp->a.read_bcr(ioaddr, 32) | 0x0080);
+ lp->a->write_bcr(ioaddr, 32,
+ lp->a->read_bcr(ioaddr, 32) | 0x0080);
/* disable Auto Negotiation, set 10Mpbs, HD */
- val = lp->a.read_bcr(ioaddr, 32) & ~0xb8;
+ val = lp->a->read_bcr(ioaddr, 32) & ~0xb8;
if (lp->options & PCNET32_PORT_FD)
val |= 0x10;
if (lp->options & PCNET32_PORT_100)
val |= 0x08;
- lp->a.write_bcr(ioaddr, 32, val);
+ lp->a->write_bcr(ioaddr, 32, val);
} else {
if (lp->options & PCNET32_PORT_ASEL) {
- lp->a.write_bcr(ioaddr, 32,
- lp->a.read_bcr(ioaddr,
+ lp->a->write_bcr(ioaddr, 32,
+ lp->a->read_bcr(ioaddr,
32) | 0x0080);
/* enable auto negotiate, setup, disable fd */
- val = lp->a.read_bcr(ioaddr, 32) & ~0x98;
+ val = lp->a->read_bcr(ioaddr, 32) & ~0x98;
val |= 0x20;
- lp->a.write_bcr(ioaddr, 32, val);
+ lp->a->write_bcr(ioaddr, 32, val);
}
}
} else {
@@ -2105,10 +2105,10 @@ static int pcnet32_open(struct net_device *dev)
* There is really no good other way to handle multiple PHYs
* other than turning off all automatics
*/
- val = lp->a.read_bcr(ioaddr, 2);
- lp->a.write_bcr(ioaddr, 2, val & ~2);
- val = lp->a.read_bcr(ioaddr, 32);
- lp->a.write_bcr(ioaddr, 32, val & ~(1 << 7)); /* stop MII manager */
+ val = lp->a->read_bcr(ioaddr, 2);
+ lp->a->write_bcr(ioaddr, 2, val & ~2);
+ val = lp->a->read_bcr(ioaddr, 32);
+ lp->a->write_bcr(ioaddr, 32, val & ~(1 << 7)); /* stop MII manager */
if (!(lp->options & PCNET32_PORT_ASEL)) {
/* setup ecmd */
@@ -2118,7 +2118,7 @@ static int pcnet32_open(struct net_device *dev)
ethtool_cmd_speed_set(&ecmd,
(lp->options & PCNET32_PORT_100) ?
SPEED_100 : SPEED_10);
- bcr9 = lp->a.read_bcr(ioaddr, 9);
+ bcr9 = lp->a->read_bcr(ioaddr, 9);
if (lp->options & PCNET32_PORT_FD) {
ecmd.duplex = DUPLEX_FULL;
@@ -2127,7 +2127,7 @@ static int pcnet32_open(struct net_device *dev)
ecmd.duplex = DUPLEX_HALF;
bcr9 |= ~(1 << 0);
}
- lp->a.write_bcr(ioaddr, 9, bcr9);
+ lp->a->write_bcr(ioaddr, 9, bcr9);
}
for (i = 0; i < PCNET32_MAX_PHYS; i++) {
@@ -2158,9 +2158,9 @@ static int pcnet32_open(struct net_device *dev)
#ifdef DO_DXSUFLO
if (lp->dxsuflo) { /* Disable transmit stop on underflow */
- val = lp->a.read_csr(ioaddr, CSR3);
+ val = lp->a->read_csr(ioaddr, CSR3);
val |= 0x40;
- lp->a.write_csr(ioaddr, CSR3, val);
+ lp->a->write_csr(ioaddr, CSR3, val);
}
#endif
@@ -2176,11 +2176,11 @@ static int pcnet32_open(struct net_device *dev)
napi_enable(&lp->napi);
/* Re-initialize the PCNET32, and start it when done. */
- lp->a.write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff));
- lp->a.write_csr(ioaddr, 2, (lp->init_dma_addr >> 16));
+ lp->a->write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff));
+ lp->a->write_csr(ioaddr, 2, (lp->init_dma_addr >> 16));
- lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */
- lp->a.write_csr(ioaddr, CSR0, CSR0_INIT);
+ lp->a->write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */
+ lp->a->write_csr(ioaddr, CSR0, CSR0_INIT);
netif_start_queue(dev);
@@ -2192,19 +2192,19 @@ static int pcnet32_open(struct net_device *dev)
i = 0;
while (i++ < 100)
- if (lp->a.read_csr(ioaddr, CSR0) & CSR0_IDON)
+ if (lp->a->read_csr(ioaddr, CSR0) & CSR0_IDON)
break;
/*
* We used to clear the InitDone bit, 0x0100, here but Mark Stockton
* reports that doing so triggers a bug in the '974.
*/
- lp->a.write_csr(ioaddr, CSR0, CSR0_NORMAL);
+ lp->a->write_csr(ioaddr, CSR0, CSR0_NORMAL);
netif_printk(lp, ifup, KERN_DEBUG, dev,
"pcnet32 open after %d ticks, init block %#x csr0 %4.4x\n",
i,
(u32) (lp->init_dma_addr),
- lp->a.read_csr(ioaddr, CSR0));
+ lp->a->read_csr(ioaddr, CSR0));
spin_unlock_irqrestore(&lp->lock, flags);
@@ -2218,7 +2218,7 @@ err_free_ring:
* Switch back to 16bit mode to avoid problems with dumb
* DOS packet driver after a warm reboot
*/
- lp->a.write_bcr(ioaddr, 20, 4);
+ lp->a->write_bcr(ioaddr, 20, 4);
err_free_irq:
spin_unlock_irqrestore(&lp->lock, flags);
@@ -2323,7 +2323,7 @@ static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits)
/* wait for stop */
for (i = 0; i < 100; i++)
- if (lp->a.read_csr(ioaddr, CSR0) & CSR0_STOP)
+ if (lp->a->read_csr(ioaddr, CSR0) & CSR0_STOP)
break;
if (i >= 100)
@@ -2335,13 +2335,13 @@ static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits)
return;
/* ReInit Ring */
- lp->a.write_csr(ioaddr, CSR0, CSR0_INIT);
+ lp->a->write_csr(ioaddr, CSR0, CSR0_INIT);
i = 0;
while (i++ < 1000)
- if (lp->a.read_csr(ioaddr, CSR0) & CSR0_IDON)
+ if (lp->a->read_csr(ioaddr, CSR0) & CSR0_IDON)
break;
- lp->a.write_csr(ioaddr, CSR0, csr0_bits);
+ lp->a->write_csr(ioaddr, CSR0, csr0_bits);
}
static void pcnet32_tx_timeout(struct net_device *dev)
@@ -2353,8 +2353,8 @@ static void pcnet32_tx_timeout(struct net_device *dev)
/* Transmitter timeout, serious problems. */
if (pcnet32_debug & NETIF_MSG_DRV)
pr_err("%s: transmit timed out, status %4.4x, resetting\n",
- dev->name, lp->a.read_csr(ioaddr, CSR0));
- lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);
+ dev->name, lp->a->read_csr(ioaddr, CSR0));
+ lp->a->write_csr(ioaddr, CSR0, CSR0_STOP);
dev->stats.tx_errors++;
if (netif_msg_tx_err(lp)) {
int i;
@@ -2397,7 +2397,7 @@ static netdev_tx_t pcnet32_start_xmit(struct sk_buff *skb,
netif_printk(lp, tx_queued, KERN_DEBUG, dev,
"%s() called, csr0 %4.4x\n",
- __func__, lp->a.read_csr(ioaddr, CSR0));
+ __func__, lp->a->read_csr(ioaddr, CSR0));
/* Default status -- will not enable Successful-TxDone
* interrupt when that option is available to us.
@@ -2427,7 +2427,7 @@ static netdev_tx_t pcnet32_start_xmit(struct sk_buff *skb,
dev->stats.tx_bytes += skb->len;
/* Trigger an immediate send poll. */
- lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN | CSR0_TXPOLL);
+ lp->a->write_csr(ioaddr, CSR0, CSR0_INTEN | CSR0_TXPOLL);
if (lp->tx_ring[(entry + 1) & lp->tx_mod_mask].base != 0) {
lp->tx_full = 1;
@@ -2452,16 +2452,16 @@ pcnet32_interrupt(int irq, void *dev_id)
spin_lock(&lp->lock);
- csr0 = lp->a.read_csr(ioaddr, CSR0);
+ csr0 = lp->a->read_csr(ioaddr, CSR0);
while ((csr0 & 0x8f00) && --boguscnt >= 0) {
if (csr0 == 0xffff)
break; /* PCMCIA remove happened */
/* Acknowledge all of the current interrupt sources ASAP. */
- lp->a.write_csr(ioaddr, CSR0, csr0 & ~0x004f);
+ lp->a->write_csr(ioaddr, CSR0, csr0 & ~0x004f);
netif_printk(lp, intr, KERN_DEBUG, dev,
"interrupt csr0=%#2.2x new csr=%#2.2x\n",
- csr0, lp->a.read_csr(ioaddr, CSR0));
+ csr0, lp->a->read_csr(ioaddr, CSR0));
/* Log misc errors. */
if (csr0 & 0x4000)
@@ -2488,19 +2488,19 @@ pcnet32_interrupt(int irq, void *dev_id)
if (napi_schedule_prep(&lp->napi)) {
u16 val;
/* set interrupt masks */
- val = lp->a.read_csr(ioaddr, CSR3);
+ val = lp->a->read_csr(ioaddr, CSR3);
val |= 0x5f00;
- lp->a.write_csr(ioaddr, CSR3, val);
+ lp->a->write_csr(ioaddr, CSR3, val);
__napi_schedule(&lp->napi);
break;
}
- csr0 = lp->a.read_csr(ioaddr, CSR0);
+ csr0 = lp->a->read_csr(ioaddr, CSR0);
}
netif_printk(lp, intr, KERN_DEBUG, dev,
"exiting interrupt, csr0=%#4.4x\n",
- lp->a.read_csr(ioaddr, CSR0));
+ lp->a->read_csr(ioaddr, CSR0));
spin_unlock(&lp->lock);
@@ -2520,20 +2520,20 @@ static int pcnet32_close(struct net_device *dev)
spin_lock_irqsave(&lp->lock, flags);
- dev->stats.rx_missed_errors = lp->a.read_csr(ioaddr, 112);
+ dev->stats.rx_missed_errors = lp->a->read_csr(ioaddr, 112);
netif_printk(lp, ifdown, KERN_DEBUG, dev,
"Shutting down ethercard, status was %2.2x\n",
- lp->a.read_csr(ioaddr, CSR0));
+ lp->a->read_csr(ioaddr, CSR0));
/* We stop the PCNET32 here -- it occasionally polls memory if we don't. */
- lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);
+ lp->a->write_csr(ioaddr, CSR0, CSR0_STOP);
/*
* Switch back to 16bit mode to avoid problems with dumb
* DOS packet driver after a warm reboot
*/
- lp->a.write_bcr(ioaddr, 20, 4);
+ lp->a->write_bcr(ioaddr, 20, 4);
spin_unlock_irqrestore(&lp->lock, flags);
@@ -2556,7 +2556,7 @@ static struct net_device_stats *pcnet32_get_stats(struct net_device *dev)
unsigned long flags;
spin_lock_irqsave(&lp->lock, flags);
- dev->stats.rx_missed_errors = lp->a.read_csr(ioaddr, 112);
+ dev->stats.rx_missed_errors = lp->a->read_csr(ioaddr, 112);
spin_unlock_irqrestore(&lp->lock, flags);
return &dev->stats;
@@ -2577,10 +2577,10 @@ static void pcnet32_load_multicast(struct net_device *dev)
if (dev->flags & IFF_ALLMULTI) {
ib->filter[0] = cpu_to_le32(~0U);
ib->filter[1] = cpu_to_le32(~0U);
- lp->a.write_csr(ioaddr, PCNET32_MC_FILTER, 0xffff);
- lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+1, 0xffff);
- lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+2, 0xffff);
- lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+3, 0xffff);
+ lp->a->write_csr(ioaddr, PCNET32_MC_FILTER, 0xffff);
+ lp->a->write_csr(ioaddr, PCNET32_MC_FILTER+1, 0xffff);
+ lp->a->write_csr(ioaddr, PCNET32_MC_FILTER+2, 0xffff);
+ lp->a->write_csr(ioaddr, PCNET32_MC_FILTER+3, 0xffff);
return;
}
/* clear the multicast filter */
@@ -2594,7 +2594,7 @@ static void pcnet32_load_multicast(struct net_device *dev)
mcast_table[crc >> 4] |= cpu_to_le16(1 << (crc & 0xf));
}
for (i = 0; i < 4; i++)
- lp->a.write_csr(ioaddr, PCNET32_MC_FILTER + i,
+ lp->a->write_csr(ioaddr, PCNET32_MC_FILTER + i,
le16_to_cpu(mcast_table[i]));
}
@@ -2609,28 +2609,28 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
spin_lock_irqsave(&lp->lock, flags);
suspended = pcnet32_suspend(dev, &flags, 0);
- csr15 = lp->a.read_csr(ioaddr, CSR15);
+ csr15 = lp->a->read_csr(ioaddr, CSR15);
if (dev->flags & IFF_PROMISC) {
/* Log any net taps. */
netif_info(lp, hw, dev, "Promiscuous mode enabled\n");
lp->init_block->mode =
cpu_to_le16(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) <<
7);
- lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000);
+ lp->a->write_csr(ioaddr, CSR15, csr15 | 0x8000);
} else {
lp->init_block->mode =
cpu_to_le16((lp->options & PCNET32_PORT_PORTSEL) << 7);
- lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff);
+ lp->a->write_csr(ioaddr, CSR15, csr15 & 0x7fff);
pcnet32_load_multicast(dev);
}
if (suspended) {
int csr5;
/* clear SUSPEND (SPND) - CSR5 bit 0 */
- csr5 = lp->a.read_csr(ioaddr, CSR5);
- lp->a.write_csr(ioaddr, CSR5, csr5 & (~CSR5_SUSPEND));
+ csr5 = lp->a->read_csr(ioaddr, CSR5);
+ lp->a->write_csr(ioaddr, CSR5, csr5 & (~CSR5_SUSPEND));
} else {
- lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);
+ lp->a->write_csr(ioaddr, CSR0, CSR0_STOP);
pcnet32_restart(dev, CSR0_NORMAL);
netif_wake_queue(dev);
}
@@ -2648,8 +2648,8 @@ static int mdio_read(struct net_device *dev, int phy_id, int reg_num)
if (!lp->mii)
return 0;
- lp->a.write_bcr(ioaddr, 33, ((phy_id & 0x1f) << 5) | (reg_num & 0x1f));
- val_out = lp->a.read_bcr(ioaddr, 34);
+ lp->a->write_bcr(ioaddr, 33, ((phy_id & 0x1f) << 5) | (reg_num & 0x1f));
+ val_out = lp->a->read_bcr(ioaddr, 34);
return val_out;
}
@@ -2663,8 +2663,8 @@ static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val)
if (!lp->mii)
return;
- lp->a.write_bcr(ioaddr, 33, ((phy_id & 0x1f) << 5) | (reg_num & 0x1f));
- lp->a.write_bcr(ioaddr, 34, val);
+ lp->a->write_bcr(ioaddr, 33, ((phy_id & 0x1f) << 5) | (reg_num & 0x1f));
+ lp->a->write_bcr(ioaddr, 34, val);
}
static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
@@ -2741,7 +2741,7 @@ static void pcnet32_check_media(struct net_device *dev, int verbose)
curr_link = mii_link_ok(&lp->mii_if);
} else {
ulong ioaddr = dev->base_addr; /* card base I/O address */
- curr_link = (lp->a.read_bcr(ioaddr, 4) != 0xc0);
+ curr_link = (lp->a->read_bcr(ioaddr, 4) != 0xc0);
}
if (!curr_link) {
if (prev_link || verbose) {
@@ -2764,13 +2764,13 @@ static void pcnet32_check_media(struct net_device *dev, int verbose)
(ecmd.duplex == DUPLEX_FULL)
? "full" : "half");
}
- bcr9 = lp->a.read_bcr(dev->base_addr, 9);
+ bcr9 = lp->a->read_bcr(dev->base_addr, 9);
if ((bcr9 & (1 << 0)) != lp->mii_if.full_duplex) {
if (lp->mii_if.full_duplex)
bcr9 |= (1 << 0);
else
bcr9 &= ~(1 << 0);
- lp->a.write_bcr(dev->base_addr, 9, bcr9);
+ lp->a->write_bcr(dev->base_addr, 9, bcr9);
}
} else {
netif_info(lp, link, dev, "link up\n");
diff --git a/drivers/net/sun3lance.c b/drivers/net/ethernet/amd/sun3lance.c
index 7d9ec23aabf6..080b71fcc683 100644
--- a/drivers/net/sun3lance.c
+++ b/drivers/net/ethernet/amd/sun3lance.c
@@ -297,7 +297,7 @@ static const struct net_device_ops lance_netdev_ops = {
.ndo_open = lance_open,
.ndo_stop = lance_close,
.ndo_start_xmit = lance_start_xmit,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_set_mac_address = NULL,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/sunlance.c b/drivers/net/ethernet/amd/sunlance.c
index 06f2d4382dc4..8fda457f94cf 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/ethernet/amd/sunlance.c
@@ -1298,7 +1298,7 @@ static const struct net_device_ops sparc_lance_ops = {
.ndo_open = lance_open,
.ndo_stop = lance_close,
.ndo_start_xmit = lance_start_xmit,
- .ndo_set_multicast_list = lance_set_multicast,
+ .ndo_set_rx_mode = lance_set_multicast,
.ndo_tx_timeout = lance_tx_timeout,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/ethernet/apple/Kconfig b/drivers/net/ethernet/apple/Kconfig
new file mode 100644
index 000000000000..a759d5483ab9
--- /dev/null
+++ b/drivers/net/ethernet/apple/Kconfig
@@ -0,0 +1,77 @@
+#
+# Apple device configuration
+#
+
+config NET_VENDOR_APPLE
+ bool "Apple devices"
+ default y
+ depends on (PPC_PMAC && PPC32) || MAC
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about IBM devices. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_APPLE
+
+config MACE
+ tristate "MACE (Power Mac ethernet) support"
+ depends on PPC_PMAC && PPC32
+ select CRC32
+ ---help---
+ Power Macintoshes and clones with Ethernet built-in on the
+ motherboard will usually use a MACE (Medium Access Control for
+ Ethernet) interface. Say Y to include support for the MACE chip.
+
+ To compile this driver as a module, choose M here: the module
+ will be called mace.
+
+config MACE_AAUI_PORT
+ bool "Use AAUI port instead of TP by default"
+ depends on MACE
+ ---help---
+ Some Apple machines (notably the Apple Network Server) which use the
+ MACE ethernet chip have an Apple AUI port (small 15-pin connector),
+ instead of an 8-pin RJ45 connector for twisted-pair ethernet. Say
+ Y here if you have such a machine. If unsure, say N.
+ The driver will default to AAUI on ANS anyway, and if you use it as
+ a module, you can provide the port_aaui=0|1 to force the driver.
+
+config BMAC
+ tristate "BMAC (G3 ethernet) support"
+ depends on PPC_PMAC && PPC32
+ select CRC32
+ ---help---
+ Say Y for support of BMAC Ethernet interfaces. These are used on G3
+ computers.
+
+ To compile this driver as a module, choose M here: the module
+ will be called bmac.
+
+config MAC89x0
+ tristate "Macintosh CS89x0 based ethernet cards"
+ depends on MAC
+ ---help---
+ Support for CS89x0 chipset based Ethernet cards. If you have a
+ Nubus or LC-PDS network (Ethernet) card of this type, say Y and
+ read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. This module will
+ be called mac89x0.
+
+config MACMACE
+ bool "Macintosh (AV) onboard MACE ethernet"
+ depends on MAC
+ select CRC32
+ ---help---
+ Support for the onboard AMD 79C940 MACE Ethernet controller used in
+ the 660AV and 840AV Macintosh. If you have one of these Macintoshes
+ say Y and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+endif # NET_VENDOR_APPLE
diff --git a/drivers/net/ethernet/apple/Makefile b/drivers/net/ethernet/apple/Makefile
new file mode 100644
index 000000000000..0d3a5919c95b
--- /dev/null
+++ b/drivers/net/ethernet/apple/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the Apple network device drivers.
+#
+
+obj-$(CONFIG_MACE) += mace.o
+obj-$(CONFIG_BMAC) += bmac.o
+obj-$(CONFIG_MAC89x0) += mac89x0.o
+obj-$(CONFIG_MACMACE) += macmace.o
diff --git a/drivers/net/bmac.c b/drivers/net/ethernet/apple/bmac.c
index 45e45e8d3d66..d070b229dbf7 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/ethernet/apple/bmac.c
@@ -1237,7 +1237,7 @@ static const struct net_device_ops bmac_netdev_ops = {
.ndo_open = bmac_open,
.ndo_stop = bmac_close,
.ndo_start_xmit = bmac_output,
- .ndo_set_multicast_list = bmac_set_multicast,
+ .ndo_set_rx_mode = bmac_set_multicast,
.ndo_set_mac_address = bmac_set_address,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/bmac.h b/drivers/net/ethernet/apple/bmac.h
index a1d19d867ba5..a1d19d867ba5 100644
--- a/drivers/net/bmac.h
+++ b/drivers/net/ethernet/apple/bmac.h
diff --git a/drivers/net/mac89x0.c b/drivers/net/ethernet/apple/mac89x0.c
index 669b317974a8..83781f316d1f 100644
--- a/drivers/net/mac89x0.c
+++ b/drivers/net/ethernet/apple/mac89x0.c
@@ -170,7 +170,7 @@ static const struct net_device_ops mac89x0_netdev_ops = {
.ndo_stop = net_close,
.ndo_start_xmit = net_send_packet,
.ndo_get_stats = net_get_stats,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_set_mac_address = set_mac_address,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/mace.c b/drivers/net/ethernet/apple/mace.c
index 2074e9724ba3..bec87bd9195c 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/ethernet/apple/mace.c
@@ -100,7 +100,7 @@ static const struct net_device_ops mace_netdev_ops = {
.ndo_open = mace_open,
.ndo_stop = mace_close,
.ndo_start_xmit = mace_xmit_start,
- .ndo_set_multicast_list = mace_set_multicast,
+ .ndo_set_rx_mode = mace_set_multicast,
.ndo_set_mac_address = mace_set_address,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/mace.h b/drivers/net/ethernet/apple/mace.h
index 30b7ec0cedb5..30b7ec0cedb5 100644
--- a/drivers/net/mace.h
+++ b/drivers/net/ethernet/apple/mace.h
diff --git a/drivers/net/macmace.c b/drivers/net/ethernet/apple/macmace.c
index 4286e67f9634..7cf81bbffe0e 100644
--- a/drivers/net/macmace.c
+++ b/drivers/net/ethernet/apple/macmace.c
@@ -31,9 +31,8 @@
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/gfp.h>
+#include <linux/interrupt.h>
#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/macintosh.h>
#include <asm/macints.h>
#include <asm/mac_psc.h>
#include <asm/page.h>
@@ -185,7 +184,7 @@ static const struct net_device_ops mace_netdev_ops = {
.ndo_stop = mace_close,
.ndo_start_xmit = mace_xmit_start,
.ndo_tx_timeout = mace_tx_timeout,
- .ndo_set_multicast_list = mace_set_multicast,
+ .ndo_set_rx_mode = mace_set_multicast,
.ndo_set_mac_address = mace_set_address,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
@@ -203,14 +202,8 @@ static int __devinit mace_probe(struct platform_device *pdev)
unsigned char *addr;
struct net_device *dev;
unsigned char checksum = 0;
- static int found = 0;
int err;
- if (found || macintosh_config->ether_type != MAC_ETHER_MACE)
- return -ENODEV;
-
- found = 1; /* prevent 'finding' one on every device probe */
-
dev = alloc_etherdev(PRIV_BYTES);
if (!dev)
return -ENOMEM;
diff --git a/drivers/net/ethernet/atheros/Kconfig b/drivers/net/ethernet/atheros/Kconfig
new file mode 100644
index 000000000000..1ed886d421f8
--- /dev/null
+++ b/drivers/net/ethernet/atheros/Kconfig
@@ -0,0 +1,70 @@
+#
+# Atheros device configuration
+#
+
+config NET_VENDOR_ATHEROS
+ bool "Atheros devices"
+ default y
+ depends on PCI
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Atheros devices. If you say Y, you will be asked
+ for your specific card in the following questions.
+
+if NET_VENDOR_ATHEROS
+
+config ATL2
+ tristate "Atheros L2 Fast Ethernet support"
+ depends on PCI
+ select CRC32
+ select NET_CORE
+ select MII
+ ---help---
+ This driver supports the Atheros L2 fast ethernet adapter.
+
+ To compile this driver as a module, choose M here. The module
+ will be called atl2.
+
+config ATL1
+ tristate "Atheros/Attansic L1 Gigabit Ethernet support"
+ depends on PCI
+ select CRC32
+ select NET_CORE
+ select MII
+ ---help---
+ This driver supports the Atheros/Attansic L1 gigabit ethernet
+ adapter.
+
+ To compile this driver as a module, choose M here. The module
+ will be called atl1.
+
+config ATL1E
+ tristate "Atheros L1E Gigabit Ethernet support (EXPERIMENTAL)"
+ depends on PCI && EXPERIMENTAL
+ select CRC32
+ select NET_CORE
+ select MII
+ ---help---
+ This driver supports the Atheros L1E gigabit ethernet adapter.
+
+ To compile this driver as a module, choose M here. The module
+ will be called atl1e.
+
+config ATL1C
+ tristate "Atheros L1C Gigabit Ethernet support (EXPERIMENTAL)"
+ depends on PCI && EXPERIMENTAL
+ select CRC32
+ select NET_CORE
+ select MII
+ ---help---
+ This driver supports the Atheros L1C gigabit ethernet adapter.
+
+ To compile this driver as a module, choose M here. The module
+ will be called atl1c.
+
+endif # NET_VENDOR_ATHEROS
diff --git a/drivers/net/ethernet/atheros/Makefile b/drivers/net/ethernet/atheros/Makefile
new file mode 100644
index 000000000000..e7e76fb576ff
--- /dev/null
+++ b/drivers/net/ethernet/atheros/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the Atheros network device drivers.
+#
+
+obj-$(CONFIG_ATL1) += atlx/
+obj-$(CONFIG_ATL2) += atlx/
+obj-$(CONFIG_ATL1E) += atl1e/
+obj-$(CONFIG_ATL1C) += atl1c/
diff --git a/drivers/net/atl1c/Makefile b/drivers/net/ethernet/atheros/atl1c/Makefile
index c37d966952ee..c37d966952ee 100644
--- a/drivers/net/atl1c/Makefile
+++ b/drivers/net/ethernet/atheros/atl1c/Makefile
diff --git a/drivers/net/atl1c/atl1c.h b/drivers/net/ethernet/atheros/atl1c/atl1c.h
index ca70e16b6e2c..ca70e16b6e2c 100644
--- a/drivers/net/atl1c/atl1c.h
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c.h
diff --git a/drivers/net/atl1c/atl1c_ethtool.c b/drivers/net/ethernet/atheros/atl1c/atl1c_ethtool.c
index 7be884d0aaf6..7be884d0aaf6 100644
--- a/drivers/net/atl1c/atl1c_ethtool.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_ethtool.c
diff --git a/drivers/net/atl1c/atl1c_hw.c b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
index 23f2ab0f2fa8..23f2ab0f2fa8 100644
--- a/drivers/net/atl1c/atl1c_hw.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
diff --git a/drivers/net/atl1c/atl1c_hw.h b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h
index 655fc6c4a8a4..655fc6c4a8a4 100644
--- a/drivers/net/atl1c/atl1c_hw.h
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h
diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index 972244218408..02c7ed8d9eca 100644
--- a/drivers/net/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -2179,12 +2179,11 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter,
memcpy(use_tpd, tpd, sizeof(struct atl1c_tpd_desc));
buffer_info = atl1c_get_tx_buffer(adapter, use_tpd);
- buffer_info->length = frag->size;
- buffer_info->dma =
- pci_map_page(adapter->pdev, frag->page,
- frag->page_offset,
- buffer_info->length,
- PCI_DMA_TODEVICE);
+ buffer_info->length = skb_frag_size(frag);
+ buffer_info->dma = skb_frag_dma_map(&adapter->pdev->dev,
+ frag, 0,
+ buffer_info->length,
+ DMA_TO_DEVICE);
ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY);
ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_PAGE,
ATL1C_PCIMAP_TODEVICE);
@@ -2600,7 +2599,7 @@ static const struct net_device_ops atl1c_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_start_xmit = atl1c_xmit_frame,
.ndo_set_mac_address = atl1c_set_mac_addr,
- .ndo_set_multicast_list = atl1c_set_multi,
+ .ndo_set_rx_mode = atl1c_set_multi,
.ndo_change_mtu = atl1c_change_mtu,
.ndo_fix_features = atl1c_fix_features,
.ndo_set_features = atl1c_set_features,
diff --git a/drivers/net/atl1e/Makefile b/drivers/net/ethernet/atheros/atl1e/Makefile
index bc11be824e76..bc11be824e76 100644
--- a/drivers/net/atl1e/Makefile
+++ b/drivers/net/ethernet/atheros/atl1e/Makefile
diff --git a/drivers/net/atl1e/atl1e.h b/drivers/net/ethernet/atheros/atl1e/atl1e.h
index 829b5ad71d0d..829b5ad71d0d 100644
--- a/drivers/net/atl1e/atl1e.h
+++ b/drivers/net/ethernet/atheros/atl1e/atl1e.h
diff --git a/drivers/net/atl1e/atl1e_ethtool.c b/drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c
index 6269438d365f..6269438d365f 100644
--- a/drivers/net/atl1e/atl1e_ethtool.c
+++ b/drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c
diff --git a/drivers/net/atl1e/atl1e_hw.c b/drivers/net/ethernet/atheros/atl1e/atl1e_hw.c
index 923063d2e5bb..923063d2e5bb 100644
--- a/drivers/net/atl1e/atl1e_hw.c
+++ b/drivers/net/ethernet/atheros/atl1e/atl1e_hw.c
diff --git a/drivers/net/atl1e/atl1e_hw.h b/drivers/net/ethernet/atheros/atl1e/atl1e_hw.h
index 74df16aef793..74df16aef793 100644
--- a/drivers/net/atl1e/atl1e_hw.h
+++ b/drivers/net/ethernet/atheros/atl1e/atl1e_hw.h
diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
index d8d411998fa3..95483bcac1d0 100644
--- a/drivers/net/atl1e/atl1e_main.c
+++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
@@ -1593,7 +1593,7 @@ static u16 atl1e_cal_tdp_req(const struct sk_buff *skb)
u16 proto_hdr_len = 0;
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- fg_size = skb_shinfo(skb)->frags[i].size;
+ fg_size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
tpd_req += ((fg_size + MAX_TX_BUF_LEN - 1) >> MAX_TX_BUF_SHIFT);
}
@@ -1744,12 +1744,12 @@ static void atl1e_tx_map(struct atl1e_adapter *adapter,
}
for (f = 0; f < nr_frags; f++) {
- struct skb_frag_struct *frag;
+ const struct skb_frag_struct *frag;
u16 i;
u16 seg_num;
frag = &skb_shinfo(skb)->frags[f];
- buf_len = frag->size;
+ buf_len = skb_frag_size(frag);
seg_num = (buf_len + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN;
for (i = 0; i < seg_num; i++) {
@@ -1765,12 +1765,11 @@ static void atl1e_tx_map(struct atl1e_adapter *adapter,
MAX_TX_BUF_LEN : buf_len;
buf_len -= tx_buffer->length;
- tx_buffer->dma =
- pci_map_page(adapter->pdev, frag->page,
- frag->page_offset +
- (i * MAX_TX_BUF_LEN),
- tx_buffer->length,
- PCI_DMA_TODEVICE);
+ tx_buffer->dma = skb_frag_dma_map(&adapter->pdev->dev,
+ frag,
+ (i * MAX_TX_BUF_LEN),
+ tx_buffer->length,
+ DMA_TO_DEVICE);
ATL1E_SET_PCIMAP_TYPE(tx_buffer, ATL1E_TX_PCIMAP_PAGE);
use_tpd->buffer_addr = cpu_to_le64(tx_buffer->dma);
use_tpd->word2 = (use_tpd->word2 & (~TPD_BUFLEN_MASK)) |
@@ -2212,7 +2211,7 @@ static const struct net_device_ops atl1e_netdev_ops = {
.ndo_stop = atl1e_close,
.ndo_start_xmit = atl1e_xmit_frame,
.ndo_get_stats = atl1e_get_stats,
- .ndo_set_multicast_list = atl1e_set_multi,
+ .ndo_set_rx_mode = atl1e_set_multi,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = atl1e_set_mac_addr,
.ndo_fix_features = atl1e_fix_features,
diff --git a/drivers/net/atl1e/atl1e_param.c b/drivers/net/ethernet/atheros/atl1e/atl1e_param.c
index 0ce60b6e7ef0..0ce60b6e7ef0 100644
--- a/drivers/net/atl1e/atl1e_param.c
+++ b/drivers/net/ethernet/atheros/atl1e/atl1e_param.c
diff --git a/drivers/net/atlx/Makefile b/drivers/net/ethernet/atheros/atlx/Makefile
index e4f6022ca552..e4f6022ca552 100644
--- a/drivers/net/atlx/Makefile
+++ b/drivers/net/ethernet/atheros/atlx/Makefile
diff --git a/drivers/net/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c
index 97e6954304ea..33a4e35f5ee8 100644
--- a/drivers/net/atlx/atl1.c
+++ b/drivers/net/ethernet/atheros/atlx/atl1.c
@@ -858,7 +858,7 @@ static s32 atl1_init_hw(struct atl1_hw *hw)
atl1_init_flash_opcode(hw);
if (!hw->phy_configured) {
- /* enable GPHY LinkChange Interrrupt */
+ /* enable GPHY LinkChange Interrupt */
ret_val = atl1_write_phy_reg(hw, 18, 0xC00);
if (ret_val)
return ret_val;
@@ -2267,11 +2267,11 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
}
for (f = 0; f < nr_frags; f++) {
- struct skb_frag_struct *frag;
+ const struct skb_frag_struct *frag;
u16 i, nseg;
frag = &skb_shinfo(skb)->frags[f];
- buf_len = frag->size;
+ buf_len = skb_frag_size(frag);
nseg = (buf_len + ATL1_MAX_TX_BUF_LEN - 1) /
ATL1_MAX_TX_BUF_LEN;
@@ -2283,10 +2283,9 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
buffer_info->length = (buf_len > ATL1_MAX_TX_BUF_LEN) ?
ATL1_MAX_TX_BUF_LEN : buf_len;
buf_len -= buffer_info->length;
- buffer_info->dma = pci_map_page(adapter->pdev,
- frag->page,
- frag->page_offset + (i * ATL1_MAX_TX_BUF_LEN),
- buffer_info->length, PCI_DMA_TODEVICE);
+ buffer_info->dma = skb_frag_dma_map(&adapter->pdev->dev,
+ frag, i * ATL1_MAX_TX_BUF_LEN,
+ buffer_info->length, DMA_TO_DEVICE);
if (++next_to_use == tpd_ring->count)
next_to_use = 0;
@@ -2357,7 +2356,6 @@ static netdev_tx_t atl1_xmit_frame(struct sk_buff *skb,
int count = 1;
int ret_val;
struct tx_packet_desc *ptpd;
- u16 frag_size;
u16 vlan_tag;
unsigned int nr_frags = 0;
unsigned int mss = 0;
@@ -2373,10 +2371,9 @@ static netdev_tx_t atl1_xmit_frame(struct sk_buff *skb,
nr_frags = skb_shinfo(skb)->nr_frags;
for (f = 0; f < nr_frags; f++) {
- frag_size = skb_shinfo(skb)->frags[f].size;
- if (frag_size)
- count += (frag_size + ATL1_MAX_TX_BUF_LEN - 1) /
- ATL1_MAX_TX_BUF_LEN;
+ unsigned int f_size = skb_frag_size(&skb_shinfo(skb)->frags[f]);
+ count += (f_size + ATL1_MAX_TX_BUF_LEN - 1) /
+ ATL1_MAX_TX_BUF_LEN;
}
mss = skb_shinfo(skb)->gso_size;
@@ -2869,7 +2866,7 @@ static const struct net_device_ops atl1_netdev_ops = {
.ndo_open = atl1_open,
.ndo_stop = atl1_close,
.ndo_start_xmit = atl1_xmit_frame,
- .ndo_set_multicast_list = atlx_set_multi,
+ .ndo_set_rx_mode = atlx_set_multi,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = atl1_set_mac,
.ndo_change_mtu = atl1_change_mtu,
@@ -3474,12 +3471,8 @@ static void atl1_get_ringparam(struct net_device *netdev,
ring->rx_max_pending = ATL1_MAX_RFD;
ring->tx_max_pending = ATL1_MAX_TPD;
- ring->rx_mini_max_pending = 0;
- ring->rx_jumbo_max_pending = 0;
ring->rx_pending = rxdr->count;
ring->tx_pending = txdr->count;
- ring->rx_mini_pending = 0;
- ring->rx_jumbo_pending = 0;
}
static int atl1_set_ringparam(struct net_device *netdev,
diff --git a/drivers/net/atlx/atl1.h b/drivers/net/ethernet/atheros/atlx/atl1.h
index 109d6da8be97..109d6da8be97 100644
--- a/drivers/net/atlx/atl1.h
+++ b/drivers/net/ethernet/atheros/atlx/atl1.h
diff --git a/drivers/net/atlx/atl2.c b/drivers/net/ethernet/atheros/atlx/atl2.c
index d4f7dda39721..1feae5928a4b 100644
--- a/drivers/net/atlx/atl2.c
+++ b/drivers/net/ethernet/atheros/atlx/atl2.c
@@ -1325,7 +1325,7 @@ static const struct net_device_ops atl2_netdev_ops = {
.ndo_open = atl2_open,
.ndo_stop = atl2_close,
.ndo_start_xmit = atl2_xmit_frame,
- .ndo_set_multicast_list = atl2_set_multi,
+ .ndo_set_rx_mode = atl2_set_multi,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = atl2_set_mac,
.ndo_change_mtu = atl2_change_mtu,
diff --git a/drivers/net/atlx/atl2.h b/drivers/net/ethernet/atheros/atlx/atl2.h
index bf9016ebdd9b..bf9016ebdd9b 100644
--- a/drivers/net/atlx/atl2.h
+++ b/drivers/net/ethernet/atheros/atlx/atl2.h
diff --git a/drivers/net/atlx/atlx.c b/drivers/net/ethernet/atheros/atlx/atlx.c
index aabcf4b5745a..aabcf4b5745a 100644
--- a/drivers/net/atlx/atlx.c
+++ b/drivers/net/ethernet/atheros/atlx/atlx.c
diff --git a/drivers/net/atlx/atlx.h b/drivers/net/ethernet/atheros/atlx/atlx.h
index 14054b75aa62..14054b75aa62 100644
--- a/drivers/net/atlx/atlx.h
+++ b/drivers/net/ethernet/atheros/atlx/atlx.h
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
new file mode 100644
index 000000000000..f15e72e81ac4
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -0,0 +1,122 @@
+#
+# Broadcom device configuration
+#
+
+config NET_VENDOR_BROADCOM
+ bool "Broadcom devices"
+ default y
+ depends on (SSB_POSSIBLE && HAS_DMA) || PCI || BCM63XX || \
+ SIBYTE_SB1xxx_SOC
+ ---help---
+ If you have a network (Ethernet) chipset belonging to this class,
+ say Y.
+
+ Note that the answer to this question does not directly affect
+ the kernel: saying N will just case the configurator to skip all
+ the questions regarding AMD chipsets. If you say Y, you will be asked
+ for your specific chipset/driver in the following questions.
+
+if NET_VENDOR_BROADCOM
+
+config B44
+ tristate "Broadcom 440x/47xx ethernet support"
+ depends on SSB_POSSIBLE && HAS_DMA
+ select SSB
+ select NET_CORE
+ select MII
+ ---help---
+ If you have a network (Ethernet) controller of this type, say Y
+ or M and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called b44.
+
+# Auto-select SSB PCI-HOST support, if possible
+config B44_PCI_AUTOSELECT
+ bool
+ depends on B44 && SSB_PCIHOST_POSSIBLE
+ select SSB_PCIHOST
+ default y
+
+# Auto-select SSB PCICORE driver, if possible
+config B44_PCICORE_AUTOSELECT
+ bool
+ depends on B44 && SSB_DRIVER_PCICORE_POSSIBLE
+ select SSB_DRIVER_PCICORE
+ default y
+
+config B44_PCI
+ bool
+ depends on B44_PCI_AUTOSELECT && B44_PCICORE_AUTOSELECT
+ default y
+
+config BCM63XX_ENET
+ tristate "Broadcom 63xx internal mac support"
+ depends on BCM63XX
+ select NET_CORE
+ select MII
+ select PHYLIB
+ help
+ This driver supports the ethernet MACs in the Broadcom 63xx
+ MIPS chipset family (BCM63XX).
+
+config BNX2
+ tristate "Broadcom NetXtremeII support"
+ depends on PCI
+ select CRC32
+ select FW_LOADER
+ ---help---
+ This driver supports Broadcom NetXtremeII gigabit Ethernet cards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called bnx2. This is recommended.
+
+config CNIC
+ tristate "Broadcom CNIC support"
+ depends on PCI
+ select BNX2
+ select UIO
+ ---help---
+ This driver supports offload features of Broadcom NetXtremeII
+ gigabit Ethernet cards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called cnic. This is recommended.
+
+config SB1250_MAC
+ tristate "SB1250 Gigabit Ethernet support"
+ depends on SIBYTE_SB1xxx_SOC
+ select PHYLIB
+ ---help---
+ This driver supports Gigabit Ethernet interfaces based on the
+ Broadcom SiByte family of System-On-a-Chip parts. They include
+ the BCM1120, BCM1125, BCM1125H, BCM1250, BCM1255, BCM1280, BCM1455
+ and BCM1480 chips.
+
+ To compile this driver as a module, choose M here: the module
+ will be called sb1250-mac.
+
+config TIGON3
+ tristate "Broadcom Tigon3 support"
+ depends on PCI
+ select PHYLIB
+ ---help---
+ This driver supports Broadcom Tigon3 based gigabit Ethernet cards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called tg3. This is recommended.
+
+config BNX2X
+ tristate "Broadcom NetXtremeII 10Gb support"
+ depends on PCI
+ select FW_LOADER
+ select ZLIB_INFLATE
+ select LIBCRC32C
+ select MDIO
+ ---help---
+ This driver supports Broadcom NetXtremeII 10 gigabit Ethernet cards.
+ To compile this driver as a module, choose M here: the module
+ will be called bnx2x. This is recommended.
+
+endif # NET_VENDOR_BROADCOM
diff --git a/drivers/net/ethernet/broadcom/Makefile b/drivers/net/ethernet/broadcom/Makefile
new file mode 100644
index 000000000000..b7896051d54e
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the Broadcom network device drivers.
+#
+
+obj-$(CONFIG_B44) += b44.o
+obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o
+obj-$(CONFIG_BNX2) += bnx2.o
+obj-$(CONFIG_CNIC) += cnic.o
+obj-$(CONFIG_BNX2X) += bnx2x/
+obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o
+obj-$(CONFIG_TIGON3) += tg3.o
diff --git a/drivers/net/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 41ea84e3f69c..4cf835dbc122 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -2114,7 +2114,7 @@ static const struct net_device_ops b44_netdev_ops = {
.ndo_stop = b44_close,
.ndo_start_xmit = b44_start_xmit,
.ndo_get_stats = b44_get_stats,
- .ndo_set_multicast_list = b44_set_rx_mode,
+ .ndo_set_rx_mode = b44_set_rx_mode,
.ndo_set_mac_address = b44_set_mac_addr,
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = b44_ioctl,
diff --git a/drivers/net/b44.h b/drivers/net/ethernet/broadcom/b44.h
index e1905a49279f..e1905a49279f 100644
--- a/drivers/net/b44.h
+++ b/drivers/net/ethernet/broadcom/b44.h
diff --git a/drivers/net/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
index 1d9b9858067c..a11a8ad94226 100644
--- a/drivers/net/bcm63xx_enet.c
+++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
@@ -1398,8 +1398,6 @@ static void bcm_enet_get_ringparam(struct net_device *dev,
/* rx/tx ring is actually only limited by memory */
ering->rx_max_pending = 8192;
ering->tx_max_pending = 8192;
- ering->rx_mini_max_pending = 0;
- ering->rx_jumbo_max_pending = 0;
ering->rx_pending = priv->rx_ring_size;
ering->tx_pending = priv->tx_ring_size;
}
@@ -1603,7 +1601,7 @@ static const struct net_device_ops bcm_enet_ops = {
.ndo_stop = bcm_enet_stop,
.ndo_start_xmit = bcm_enet_start_xmit,
.ndo_set_mac_address = bcm_enet_set_mac_address,
- .ndo_set_multicast_list = bcm_enet_set_multicast_list,
+ .ndo_set_rx_mode = bcm_enet_set_multicast_list,
.ndo_do_ioctl = bcm_enet_ioctl,
.ndo_change_mtu = bcm_enet_change_mtu,
#ifdef CONFIG_NET_POLL_CONTROLLER
diff --git a/drivers/net/bcm63xx_enet.h b/drivers/net/ethernet/broadcom/bcm63xx_enet.h
index 0e3048b788c2..0e3048b788c2 100644
--- a/drivers/net/bcm63xx_enet.h
+++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.h
diff --git a/drivers/net/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c
index 4b2b57018a02..965c7235804d 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/ethernet/broadcom/bnx2.c
@@ -36,6 +36,7 @@
#include <linux/time.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
+#include <linux/if.h>
#include <linux/if_vlan.h>
#include <net/ip.h>
#include <net/tcp.h>
@@ -2870,7 +2871,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
dma_unmap_addr(
&txr->tx_buf_ring[TX_RING_IDX(sw_cons)],
mapping),
- skb_shinfo(skb)->frags[i].size,
+ skb_frag_size(&skb_shinfo(skb)->frags[i]),
PCI_DMA_TODEVICE);
}
@@ -2929,8 +2930,8 @@ bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
shinfo = skb_shinfo(skb);
shinfo->nr_frags--;
- page = shinfo->frags[shinfo->nr_frags].page;
- shinfo->frags[shinfo->nr_frags].page = NULL;
+ page = skb_frag_page(&shinfo->frags[shinfo->nr_frags]);
+ __skb_frag_set_page(&shinfo->frags[shinfo->nr_frags], NULL);
cons_rx_pg->page = page;
dev_kfree_skb(skb);
@@ -3048,9 +3049,8 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
} else {
skb_frag_t *frag =
&skb_shinfo(skb)->frags[i - 1];
- frag->size -= tail;
+ skb_frag_size_sub(frag, tail);
skb->data_len -= tail;
- skb->truesize -= tail;
}
return 0;
}
@@ -3082,7 +3082,7 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
frag_size -= frag_len;
skb->data_len += frag_len;
- skb->truesize += frag_len;
+ skb->truesize += PAGE_SIZE;
skb->len += frag_len;
pg_prod = NEXT_RX_BD(pg_prod);
@@ -3622,7 +3622,7 @@ bnx2_set_rx_mode(struct net_device *dev)
spin_unlock_bh(&bp->phy_lock);
}
-static int __devinit
+static int
check_fw_section(const struct firmware *fw,
const struct bnx2_fw_file_section *section,
u32 alignment, bool non_empty)
@@ -3638,7 +3638,7 @@ check_fw_section(const struct firmware *fw,
return 0;
}
-static int __devinit
+static int
check_mips_fw_entry(const struct firmware *fw,
const struct bnx2_mips_fw_file_entry *entry)
{
@@ -3649,8 +3649,16 @@ check_mips_fw_entry(const struct firmware *fw,
return 0;
}
-static int __devinit
-bnx2_request_firmware(struct bnx2 *bp)
+static void bnx2_release_firmware(struct bnx2 *bp)
+{
+ if (bp->rv2p_firmware) {
+ release_firmware(bp->mips_firmware);
+ release_firmware(bp->rv2p_firmware);
+ bp->rv2p_firmware = NULL;
+ }
+}
+
+static int bnx2_request_uncached_firmware(struct bnx2 *bp)
{
const char *mips_fw_file, *rv2p_fw_file;
const struct bnx2_mips_fw_file *mips_fw;
@@ -3672,13 +3680,13 @@ bnx2_request_firmware(struct bnx2 *bp)
rc = request_firmware(&bp->mips_firmware, mips_fw_file, &bp->pdev->dev);
if (rc) {
pr_err("Can't load firmware file \"%s\"\n", mips_fw_file);
- return rc;
+ goto out;
}
rc = request_firmware(&bp->rv2p_firmware, rv2p_fw_file, &bp->pdev->dev);
if (rc) {
pr_err("Can't load firmware file \"%s\"\n", rv2p_fw_file);
- return rc;
+ goto err_release_mips_firmware;
}
mips_fw = (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
rv2p_fw = (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
@@ -3689,16 +3697,30 @@ bnx2_request_firmware(struct bnx2 *bp)
check_mips_fw_entry(bp->mips_firmware, &mips_fw->tpat) ||
check_mips_fw_entry(bp->mips_firmware, &mips_fw->txp)) {
pr_err("Firmware file \"%s\" is invalid\n", mips_fw_file);
- return -EINVAL;
+ rc = -EINVAL;
+ goto err_release_firmware;
}
if (bp->rv2p_firmware->size < sizeof(*rv2p_fw) ||
check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc1.rv2p, 8, true) ||
check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc2.rv2p, 8, true)) {
pr_err("Firmware file \"%s\" is invalid\n", rv2p_fw_file);
- return -EINVAL;
+ rc = -EINVAL;
+ goto err_release_firmware;
}
+out:
+ return rc;
- return 0;
+err_release_firmware:
+ release_firmware(bp->rv2p_firmware);
+ bp->rv2p_firmware = NULL;
+err_release_mips_firmware:
+ release_firmware(bp->mips_firmware);
+ goto out;
+}
+
+static int bnx2_request_firmware(struct bnx2 *bp)
+{
+ return bp->rv2p_firmware ? 0 : bnx2_request_uncached_firmware(bp);
}
static u32
@@ -5373,7 +5395,7 @@ bnx2_free_tx_skbs(struct bnx2 *bp)
tx_buf = &txr->tx_buf_ring[TX_RING_IDX(j)];
dma_unmap_page(&bp->pdev->dev,
dma_unmap_addr(tx_buf, mapping),
- skb_shinfo(skb)->frags[k].size,
+ skb_frag_size(&skb_shinfo(skb)->frags[k]),
PCI_DMA_TODEVICE);
}
dev_kfree_skb(skb);
@@ -6266,6 +6288,10 @@ bnx2_open(struct net_device *dev)
struct bnx2 *bp = netdev_priv(dev);
int rc;
+ rc = bnx2_request_firmware(bp);
+ if (rc < 0)
+ goto out;
+
netif_carrier_off(dev);
bnx2_set_power_state(bp, PCI_D0);
@@ -6326,8 +6352,8 @@ bnx2_open(struct net_device *dev)
netdev_info(dev, "using MSIX\n");
netif_tx_start_all_queues(dev);
-
- return 0;
+out:
+ return rc;
open_err:
bnx2_napi_disable(bp);
@@ -6335,7 +6361,8 @@ open_err:
bnx2_free_irq(bp);
bnx2_free_mem(bp);
bnx2_del_napi(bp);
- return rc;
+ bnx2_release_firmware(bp);
+ goto out;
}
static void
@@ -6503,15 +6530,15 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
tx_buf->is_gso = skb_is_gso(skb);
for (i = 0; i < last_frag; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
prod = NEXT_TX_BD(prod);
ring_prod = TX_RING_IDX(prod);
txbd = &txr->tx_desc_ring[ring_prod];
- len = frag->size;
- mapping = dma_map_page(&bp->pdev->dev, frag->page, frag->page_offset,
- len, PCI_DMA_TODEVICE);
+ len = skb_frag_size(frag);
+ mapping = skb_frag_dma_map(&bp->pdev->dev, frag, 0, len,
+ DMA_TO_DEVICE);
if (dma_mapping_error(&bp->pdev->dev, mapping))
goto dma_error;
dma_unmap_addr_set(&txr->tx_buf_ring[ring_prod], mapping,
@@ -6567,7 +6594,7 @@ dma_error:
ring_prod = TX_RING_IDX(prod);
tx_buf = &txr->tx_buf_ring[ring_prod];
dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
- skb_shinfo(skb)->frags[i].size,
+ skb_frag_size(&skb_shinfo(skb)->frags[i]),
PCI_DMA_TODEVICE);
}
@@ -7127,11 +7154,9 @@ bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
struct bnx2 *bp = netdev_priv(dev);
ering->rx_max_pending = MAX_TOTAL_RX_DESC_CNT;
- ering->rx_mini_max_pending = 0;
ering->rx_jumbo_max_pending = MAX_TOTAL_RX_PG_DESC_CNT;
ering->rx_pending = bp->rx_ring_size;
- ering->rx_mini_pending = 0;
ering->rx_jumbo_pending = bp->rx_pg_ring_size;
ering->tx_max_pending = MAX_TX_DESC_CNT;
@@ -8353,10 +8378,6 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_drvdata(pdev, dev);
- rc = bnx2_request_firmware(bp);
- if (rc)
- goto error;
-
memcpy(dev->dev_addr, bp->mac_addr, 6);
memcpy(dev->perm_addr, bp->mac_addr, 6);
@@ -8370,6 +8391,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->vlan_features = dev->hw_features;
dev->hw_features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
dev->features |= dev->hw_features;
+ dev->priv_flags |= IFF_UNICAST_FLT;
if ((rc = register_netdev(dev))) {
dev_err(&pdev->dev, "Cannot register net device\n");
@@ -8387,11 +8409,6 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;
error:
- if (bp->mips_firmware)
- release_firmware(bp->mips_firmware);
- if (bp->rv2p_firmware)
- release_firmware(bp->rv2p_firmware);
-
if (bp->regview)
iounmap(bp->regview);
pci_release_regions(pdev);
@@ -8412,11 +8429,6 @@ bnx2_remove_one(struct pci_dev *pdev)
del_timer_sync(&bp->timer);
cancel_work_sync(&bp->reset_task);
- if (bp->mips_firmware)
- release_firmware(bp->mips_firmware);
- if (bp->rv2p_firmware)
- release_firmware(bp->rv2p_firmware);
-
if (bp->regview)
iounmap(bp->regview);
@@ -8427,6 +8439,8 @@ bnx2_remove_one(struct pci_dev *pdev)
bp->flags &= ~BNX2_FLAG_AER_ENABLED;
}
+ bnx2_release_firmware(bp);
+
free_netdev(dev);
pci_release_regions(pdev);
diff --git a/drivers/net/bnx2.h b/drivers/net/ethernet/broadcom/bnx2.h
index fc50d4267df8..99d31a7d6aaa 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/ethernet/broadcom/bnx2.h
@@ -5617,7 +5617,7 @@ struct l2_fhdr {
#define BNX2_TXP_CPU_STATE_FIO_ABORT_HALTED (1L<<8)
#define BNX2_TXP_CPU_STATE_SOFT_HALTED (1L<<10)
#define BNX2_TXP_CPU_STATE_SPAD_UNDERFLOW (1L<<11)
-#define BNX2_TXP_CPU_STATE_INTERRRUPT (1L<<12)
+#define BNX2_TXP_CPU_STATE_INTERRUPT (1L<<12)
#define BNX2_TXP_CPU_STATE_DATA_ACCESS_STALL (1L<<14)
#define BNX2_TXP_CPU_STATE_INST_FETCH_STALL (1L<<15)
#define BNX2_TXP_CPU_STATE_BLOCKED_READ (1L<<31)
@@ -5712,7 +5712,7 @@ struct l2_fhdr {
#define BNX2_TPAT_CPU_STATE_FIO_ABORT_HALTED (1L<<8)
#define BNX2_TPAT_CPU_STATE_SOFT_HALTED (1L<<10)
#define BNX2_TPAT_CPU_STATE_SPAD_UNDERFLOW (1L<<11)
-#define BNX2_TPAT_CPU_STATE_INTERRRUPT (1L<<12)
+#define BNX2_TPAT_CPU_STATE_INTERRUPT (1L<<12)
#define BNX2_TPAT_CPU_STATE_DATA_ACCESS_STALL (1L<<14)
#define BNX2_TPAT_CPU_STATE_INST_FETCH_STALL (1L<<15)
#define BNX2_TPAT_CPU_STATE_BLOCKED_READ (1L<<31)
@@ -5807,7 +5807,7 @@ struct l2_fhdr {
#define BNX2_RXP_CPU_STATE_FIO_ABORT_HALTED (1L<<8)
#define BNX2_RXP_CPU_STATE_SOFT_HALTED (1L<<10)
#define BNX2_RXP_CPU_STATE_SPAD_UNDERFLOW (1L<<11)
-#define BNX2_RXP_CPU_STATE_INTERRRUPT (1L<<12)
+#define BNX2_RXP_CPU_STATE_INTERRUPT (1L<<12)
#define BNX2_RXP_CPU_STATE_DATA_ACCESS_STALL (1L<<14)
#define BNX2_RXP_CPU_STATE_INST_FETCH_STALL (1L<<15)
#define BNX2_RXP_CPU_STATE_BLOCKED_READ (1L<<31)
@@ -5953,7 +5953,7 @@ struct l2_fhdr {
#define BNX2_COM_CPU_STATE_FIO_ABORT_HALTED (1L<<8)
#define BNX2_COM_CPU_STATE_SOFT_HALTED (1L<<10)
#define BNX2_COM_CPU_STATE_SPAD_UNDERFLOW (1L<<11)
-#define BNX2_COM_CPU_STATE_INTERRRUPT (1L<<12)
+#define BNX2_COM_CPU_STATE_INTERRUPT (1L<<12)
#define BNX2_COM_CPU_STATE_DATA_ACCESS_STALL (1L<<14)
#define BNX2_COM_CPU_STATE_INST_FETCH_STALL (1L<<15)
#define BNX2_COM_CPU_STATE_BLOCKED_READ (1L<<31)
@@ -6119,7 +6119,7 @@ struct l2_fhdr {
#define BNX2_CP_CPU_STATE_FIO_ABORT_HALTED (1L<<8)
#define BNX2_CP_CPU_STATE_SOFT_HALTED (1L<<10)
#define BNX2_CP_CPU_STATE_SPAD_UNDERFLOW (1L<<11)
-#define BNX2_CP_CPU_STATE_INTERRRUPT (1L<<12)
+#define BNX2_CP_CPU_STATE_INTERRUPT (1L<<12)
#define BNX2_CP_CPU_STATE_DATA_ACCESS_STALL (1L<<14)
#define BNX2_CP_CPU_STATE_INST_FETCH_STALL (1L<<15)
#define BNX2_CP_CPU_STATE_BLOCKED_READ (1L<<31)
@@ -6291,7 +6291,7 @@ struct l2_fhdr {
#define BNX2_MCP_CPU_STATE_FIO_ABORT_HALTED (1L<<8)
#define BNX2_MCP_CPU_STATE_SOFT_HALTED (1L<<10)
#define BNX2_MCP_CPU_STATE_SPAD_UNDERFLOW (1L<<11)
-#define BNX2_MCP_CPU_STATE_INTERRRUPT (1L<<12)
+#define BNX2_MCP_CPU_STATE_INTERRUPT (1L<<12)
#define BNX2_MCP_CPU_STATE_DATA_ACCESS_STALL (1L<<14)
#define BNX2_MCP_CPU_STATE_INST_FETCH_STALL (1L<<15)
#define BNX2_MCP_CPU_STATE_BLOCKED_READ (1L<<31)
diff --git a/drivers/net/bnx2_fw.h b/drivers/net/ethernet/broadcom/bnx2_fw.h
index 940eb91f209d..940eb91f209d 100644
--- a/drivers/net/bnx2_fw.h
+++ b/drivers/net/ethernet/broadcom/bnx2_fw.h
diff --git a/drivers/net/bnx2x/Makefile b/drivers/net/ethernet/broadcom/bnx2x/Makefile
index 48fbdd48f88f..48fbdd48f88f 100644
--- a/drivers/net/bnx2x/Makefile
+++ b/drivers/net/ethernet/broadcom/bnx2x/Makefile
diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
index c423504a755f..627a5807836d 100644
--- a/drivers/net/bnx2x/bnx2x.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -66,73 +66,68 @@
#define BNX2X_MSG_SP 0x100000 /* was: NETIF_MSG_INTR */
#define BNX2X_MSG_FP 0x200000 /* was: NETIF_MSG_INTR */
-#define DP_LEVEL KERN_NOTICE /* was: KERN_DEBUG */
-
/* regular debug print */
-#define DP(__mask, __fmt, __args...) \
+#define DP(__mask, fmt, ...) \
do { \
if (bp->msg_enable & (__mask)) \
- printk(DP_LEVEL "[%s:%d(%s)]" __fmt, \
- __func__, __LINE__, \
- bp->dev ? (bp->dev->name) : "?", \
- ##__args); \
+ pr_notice("[%s:%d(%s)]" fmt, \
+ __func__, __LINE__, \
+ bp->dev ? (bp->dev->name) : "?", \
+ ##__VA_ARGS__); \
} while (0)
-#define DP_CONT(__mask, __fmt, __args...) \
+#define DP_CONT(__mask, fmt, ...) \
do { \
if (bp->msg_enable & (__mask)) \
- pr_cont(__fmt, ##__args); \
+ pr_cont(fmt, ##__VA_ARGS__); \
} while (0)
/* errors debug print */
-#define BNX2X_DBG_ERR(__fmt, __args...) \
+#define BNX2X_DBG_ERR(fmt, ...) \
do { \
if (netif_msg_probe(bp)) \
- pr_err("[%s:%d(%s)]" __fmt, \
+ pr_err("[%s:%d(%s)]" fmt, \
__func__, __LINE__, \
bp->dev ? (bp->dev->name) : "?", \
- ##__args); \
+ ##__VA_ARGS__); \
} while (0)
/* for errors (never masked) */
-#define BNX2X_ERR(__fmt, __args...) \
+#define BNX2X_ERR(fmt, ...) \
do { \
- pr_err("[%s:%d(%s)]" __fmt, \
+ pr_err("[%s:%d(%s)]" fmt, \
__func__, __LINE__, \
bp->dev ? (bp->dev->name) : "?", \
- ##__args); \
- } while (0)
+ ##__VA_ARGS__); \
+} while (0)
-#define BNX2X_ERROR(__fmt, __args...) do { \
- pr_err("[%s:%d]" __fmt, __func__, __LINE__, ##__args); \
- } while (0)
+#define BNX2X_ERROR(fmt, ...) \
+ pr_err("[%s:%d]" fmt, __func__, __LINE__, ##__VA_ARGS__)
/* before we have a dev->name use dev_info() */
-#define BNX2X_DEV_INFO(__fmt, __args...) \
+#define BNX2X_DEV_INFO(fmt, ...) \
do { \
if (netif_msg_probe(bp)) \
- dev_info(&bp->pdev->dev, __fmt, ##__args); \
+ dev_info(&bp->pdev->dev, fmt, ##__VA_ARGS__); \
} while (0)
-#define BNX2X_MAC_FMT "%pM"
-#define BNX2X_MAC_PRN_LIST(mac) (mac)
-
-
#ifdef BNX2X_STOP_ON_ERROR
void bnx2x_int_disable(struct bnx2x *bp);
-#define bnx2x_panic() do { \
- bp->panic = 1; \
- BNX2X_ERR("driver assert\n"); \
- bnx2x_int_disable(bp); \
- bnx2x_panic_dump(bp); \
- } while (0)
+#define bnx2x_panic() \
+do { \
+ bp->panic = 1; \
+ BNX2X_ERR("driver assert\n"); \
+ bnx2x_int_disable(bp); \
+ bnx2x_panic_dump(bp); \
+} while (0)
#else
-#define bnx2x_panic() do { \
- bp->panic = 1; \
- BNX2X_ERR("driver assert\n"); \
- bnx2x_panic_dump(bp); \
- } while (0)
+#define bnx2x_panic() \
+do { \
+ bp->panic = 1; \
+ BNX2X_ERR("driver assert\n"); \
+ bnx2x_panic_dump(bp); \
+} while (0)
#endif
#define bnx2x_mc_addr(ha) ((ha)->addr)
@@ -239,13 +234,19 @@ void bnx2x_int_disable(struct bnx2x *bp);
* FUNC_N_CLID_X = N * NUM_SPECIAL_CLIENTS + FUNC_0_CLID_X
*
*/
-/* iSCSI L2 */
-#define BNX2X_ISCSI_ETH_CL_ID_IDX 1
-#define BNX2X_ISCSI_ETH_CID 49
+enum {
+ BNX2X_ISCSI_ETH_CL_ID_IDX,
+ BNX2X_FCOE_ETH_CL_ID_IDX,
+ BNX2X_MAX_CNIC_ETH_CL_ID_IDX,
+};
-/* FCoE L2 */
-#define BNX2X_FCOE_ETH_CL_ID_IDX 2
-#define BNX2X_FCOE_ETH_CID 50
+#define BNX2X_CNIC_START_ETH_CID 48
+enum {
+ /* iSCSI L2 */
+ BNX2X_ISCSI_ETH_CID = BNX2X_CNIC_START_ETH_CID,
+ /* FCoE L2 */
+ BNX2X_FCOE_ETH_CID,
+};
/** Additional rings budgeting */
#ifdef BCM_CNIC
@@ -315,6 +316,14 @@ union db_prod {
u32 raw;
};
+/* dropless fc FW/HW related params */
+#define BRB_SIZE(bp) (CHIP_IS_E3(bp) ? 1024 : 512)
+#define MAX_AGG_QS(bp) (CHIP_IS_E1(bp) ? \
+ ETH_MAX_AGGREGATION_QUEUES_E1 :\
+ ETH_MAX_AGGREGATION_QUEUES_E1H_E2)
+#define FW_DROP_LEVEL(bp) (3 + MAX_SPQ_PENDING + MAX_AGG_QS(bp))
+#define FW_PREFETCH_CNT 16
+#define DROPLESS_FC_HEADROOM 100
/* MC hsi */
#define BCM_PAGE_SHIFT 12
@@ -331,15 +340,35 @@ union db_prod {
/* SGE ring related macros */
#define NUM_RX_SGE_PAGES 2
#define RX_SGE_CNT (BCM_PAGE_SIZE / sizeof(struct eth_rx_sge))
-#define MAX_RX_SGE_CNT (RX_SGE_CNT - 2)
+#define NEXT_PAGE_SGE_DESC_CNT 2
+#define MAX_RX_SGE_CNT (RX_SGE_CNT - NEXT_PAGE_SGE_DESC_CNT)
/* RX_SGE_CNT is promised to be a power of 2 */
#define RX_SGE_MASK (RX_SGE_CNT - 1)
#define NUM_RX_SGE (RX_SGE_CNT * NUM_RX_SGE_PAGES)
#define MAX_RX_SGE (NUM_RX_SGE - 1)
#define NEXT_SGE_IDX(x) ((((x) & RX_SGE_MASK) == \
- (MAX_RX_SGE_CNT - 1)) ? (x) + 3 : (x) + 1)
+ (MAX_RX_SGE_CNT - 1)) ? \
+ (x) + 1 + NEXT_PAGE_SGE_DESC_CNT : \
+ (x) + 1)
#define RX_SGE(x) ((x) & MAX_RX_SGE)
+/*
+ * Number of required SGEs is the sum of two:
+ * 1. Number of possible opened aggregations (next packet for
+ * these aggregations will probably consume SGE immidiatelly)
+ * 2. Rest of BRB blocks divided by 2 (block will consume new SGE only
+ * after placement on BD for new TPA aggregation)
+ *
+ * Takes into account NEXT_PAGE_SGE_DESC_CNT "next" elements on each page
+ */
+#define NUM_SGE_REQ (MAX_AGG_QS(bp) + \
+ (BRB_SIZE(bp) - MAX_AGG_QS(bp)) / 2)
+#define NUM_SGE_PG_REQ ((NUM_SGE_REQ + MAX_RX_SGE_CNT - 1) / \
+ MAX_RX_SGE_CNT)
+#define SGE_TH_LO(bp) (NUM_SGE_REQ + \
+ NUM_SGE_PG_REQ * NEXT_PAGE_SGE_DESC_CNT)
+#define SGE_TH_HI(bp) (SGE_TH_LO(bp) + DROPLESS_FC_HEADROOM)
+
/* Manipulate a bit vector defined as an array of u64 */
/* Number of bits in one sge_mask array element */
@@ -551,24 +580,43 @@ struct bnx2x_fastpath {
#define NUM_TX_RINGS 16
#define TX_DESC_CNT (BCM_PAGE_SIZE / sizeof(union eth_tx_bd_types))
-#define MAX_TX_DESC_CNT (TX_DESC_CNT - 1)
+#define NEXT_PAGE_TX_DESC_CNT 1
+#define MAX_TX_DESC_CNT (TX_DESC_CNT - NEXT_PAGE_TX_DESC_CNT)
#define NUM_TX_BD (TX_DESC_CNT * NUM_TX_RINGS)
#define MAX_TX_BD (NUM_TX_BD - 1)
#define MAX_TX_AVAIL (MAX_TX_DESC_CNT * NUM_TX_RINGS - 2)
#define NEXT_TX_IDX(x) ((((x) & MAX_TX_DESC_CNT) == \
- (MAX_TX_DESC_CNT - 1)) ? (x) + 2 : (x) + 1)
+ (MAX_TX_DESC_CNT - 1)) ? \
+ (x) + 1 + NEXT_PAGE_TX_DESC_CNT : \
+ (x) + 1)
#define TX_BD(x) ((x) & MAX_TX_BD)
#define TX_BD_POFF(x) ((x) & MAX_TX_DESC_CNT)
/* The RX BD ring is special, each bd is 8 bytes but the last one is 16 */
#define NUM_RX_RINGS 8
#define RX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_rx_bd))
-#define MAX_RX_DESC_CNT (RX_DESC_CNT - 2)
+#define NEXT_PAGE_RX_DESC_CNT 2
+#define MAX_RX_DESC_CNT (RX_DESC_CNT - NEXT_PAGE_RX_DESC_CNT)
#define RX_DESC_MASK (RX_DESC_CNT - 1)
#define NUM_RX_BD (RX_DESC_CNT * NUM_RX_RINGS)
#define MAX_RX_BD (NUM_RX_BD - 1)
#define MAX_RX_AVAIL (MAX_RX_DESC_CNT * NUM_RX_RINGS - 2)
-#define MIN_RX_AVAIL 128
+
+/* dropless fc calculations for BDs
+ *
+ * Number of BDs should as number of buffers in BRB:
+ * Low threshold takes into account NEXT_PAGE_RX_DESC_CNT
+ * "next" elements on each page
+ */
+#define NUM_BD_REQ BRB_SIZE(bp)
+#define NUM_BD_PG_REQ ((NUM_BD_REQ + MAX_RX_DESC_CNT - 1) / \
+ MAX_RX_DESC_CNT)
+#define BD_TH_LO(bp) (NUM_BD_REQ + \
+ NUM_BD_PG_REQ * NEXT_PAGE_RX_DESC_CNT + \
+ FW_DROP_LEVEL(bp))
+#define BD_TH_HI(bp) (BD_TH_LO(bp) + DROPLESS_FC_HEADROOM)
+
+#define MIN_RX_AVAIL ((bp)->dropless_fc ? BD_TH_HI(bp) + 128 : 128)
#define MIN_RX_SIZE_TPA_HW (CHIP_IS_E1(bp) ? \
ETH_MIN_RX_CQES_WITH_TPA_E1 : \
@@ -579,7 +627,9 @@ struct bnx2x_fastpath {
MIN_RX_AVAIL))
#define NEXT_RX_IDX(x) ((((x) & RX_DESC_MASK) == \
- (MAX_RX_DESC_CNT - 1)) ? (x) + 3 : (x) + 1)
+ (MAX_RX_DESC_CNT - 1)) ? \
+ (x) + 1 + NEXT_PAGE_RX_DESC_CNT : \
+ (x) + 1)
#define RX_BD(x) ((x) & MAX_RX_BD)
/*
@@ -589,14 +639,31 @@ struct bnx2x_fastpath {
#define CQE_BD_REL (sizeof(union eth_rx_cqe) / sizeof(struct eth_rx_bd))
#define NUM_RCQ_RINGS (NUM_RX_RINGS * CQE_BD_REL)
#define RCQ_DESC_CNT (BCM_PAGE_SIZE / sizeof(union eth_rx_cqe))
-#define MAX_RCQ_DESC_CNT (RCQ_DESC_CNT - 1)
+#define NEXT_PAGE_RCQ_DESC_CNT 1
+#define MAX_RCQ_DESC_CNT (RCQ_DESC_CNT - NEXT_PAGE_RCQ_DESC_CNT)
#define NUM_RCQ_BD (RCQ_DESC_CNT * NUM_RCQ_RINGS)
#define MAX_RCQ_BD (NUM_RCQ_BD - 1)
#define MAX_RCQ_AVAIL (MAX_RCQ_DESC_CNT * NUM_RCQ_RINGS - 2)
#define NEXT_RCQ_IDX(x) ((((x) & MAX_RCQ_DESC_CNT) == \
- (MAX_RCQ_DESC_CNT - 1)) ? (x) + 2 : (x) + 1)
+ (MAX_RCQ_DESC_CNT - 1)) ? \
+ (x) + 1 + NEXT_PAGE_RCQ_DESC_CNT : \
+ (x) + 1)
#define RCQ_BD(x) ((x) & MAX_RCQ_BD)
+/* dropless fc calculations for RCQs
+ *
+ * Number of RCQs should be as number of buffers in BRB:
+ * Low threshold takes into account NEXT_PAGE_RCQ_DESC_CNT
+ * "next" elements on each page
+ */
+#define NUM_RCQ_REQ BRB_SIZE(bp)
+#define NUM_RCQ_PG_REQ ((NUM_BD_REQ + MAX_RCQ_DESC_CNT - 1) / \
+ MAX_RCQ_DESC_CNT)
+#define RCQ_TH_LO(bp) (NUM_RCQ_REQ + \
+ NUM_RCQ_PG_REQ * NEXT_PAGE_RCQ_DESC_CNT + \
+ FW_DROP_LEVEL(bp))
+#define RCQ_TH_HI(bp) (RCQ_TH_LO(bp) + DROPLESS_FC_HEADROOM)
+
/* This is needed for determining of last_max */
#define SUB_S16(a, b) (s16)((s16)(a) - (s16)(b))
@@ -685,24 +752,17 @@ struct bnx2x_fastpath {
#define FP_CSB_FUNC_OFF \
offsetof(struct cstorm_status_block_c, func)
-#define HC_INDEX_TOE_RX_CQ_CONS 0 /* Formerly Ustorm TOE CQ index */
- /* (HC_INDEX_U_TOE_RX_CQ_CONS) */
-#define HC_INDEX_ETH_RX_CQ_CONS 1 /* Formerly Ustorm ETH CQ index */
- /* (HC_INDEX_U_ETH_RX_CQ_CONS) */
-#define HC_INDEX_ETH_RX_BD_CONS 2 /* Formerly Ustorm ETH BD index */
- /* (HC_INDEX_U_ETH_RX_BD_CONS) */
-
-#define HC_INDEX_TOE_TX_CQ_CONS 4 /* Formerly Cstorm TOE CQ index */
- /* (HC_INDEX_C_TOE_TX_CQ_CONS) */
-#define HC_INDEX_ETH_TX_CQ_CONS_COS0 5 /* Formerly Cstorm ETH CQ index */
- /* (HC_INDEX_C_ETH_TX_CQ_CONS) */
-#define HC_INDEX_ETH_TX_CQ_CONS_COS1 6 /* Formerly Cstorm ETH CQ index */
- /* (HC_INDEX_C_ETH_TX_CQ_CONS) */
-#define HC_INDEX_ETH_TX_CQ_CONS_COS2 7 /* Formerly Cstorm ETH CQ index */
- /* (HC_INDEX_C_ETH_TX_CQ_CONS) */
+#define HC_INDEX_ETH_RX_CQ_CONS 1
-#define HC_INDEX_ETH_FIRST_TX_CQ_CONS HC_INDEX_ETH_TX_CQ_CONS_COS0
+#define HC_INDEX_OOO_TX_CQ_CONS 4
+#define HC_INDEX_ETH_TX_CQ_CONS_COS0 5
+
+#define HC_INDEX_ETH_TX_CQ_CONS_COS1 6
+
+#define HC_INDEX_ETH_TX_CQ_CONS_COS2 7
+
+#define HC_INDEX_ETH_FIRST_TX_CQ_CONS HC_INDEX_ETH_TX_CQ_CONS_COS0
#define BNX2X_RX_SB_INDEX \
(&fp->sb_index_values[HC_INDEX_ETH_RX_CQ_CONS])
@@ -1100,11 +1160,12 @@ struct bnx2x {
#define BP_PORT(bp) (bp->pfid & 1)
#define BP_FUNC(bp) (bp->pfid)
#define BP_ABS_FUNC(bp) (bp->pf_num)
-#define BP_E1HVN(bp) (bp->pfid >> 1)
-#define BP_VN(bp) (BP_E1HVN(bp)) /*remove when approved*/
-#define BP_L_ID(bp) (BP_E1HVN(bp) << 2)
-#define BP_FW_MB_IDX(bp) (BP_PORT(bp) +\
- BP_VN(bp) * ((CHIP_IS_E1x(bp) || (CHIP_MODE_IS_4_PORT(bp))) ? 2 : 1))
+#define BP_VN(bp) ((bp)->pfid >> 1)
+#define BP_MAX_VN_NUM(bp) (CHIP_MODE_IS_4_PORT(bp) ? 2 : 4)
+#define BP_L_ID(bp) (BP_VN(bp) << 2)
+#define BP_FW_MB_IDX_VN(bp, vn) (BP_PORT(bp) +\
+ (vn) * ((CHIP_IS_E1x(bp) || (CHIP_MODE_IS_4_PORT(bp))) ? 2 : 1))
+#define BP_FW_MB_IDX(bp) BP_FW_MB_IDX_VN(bp, BP_VN(bp))
struct net_device *dev;
struct pci_dev *pdev;
@@ -1767,7 +1828,7 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
#define MAX_DMAE_C_PER_PORT 8
#define INIT_DMAE_C(bp) (BP_PORT(bp) * MAX_DMAE_C_PER_PORT + \
- BP_E1HVN(bp))
+ BP_VN(bp))
#define PMF_DMAE_C(bp) (BP_PORT(bp) * MAX_DMAE_C_PER_PORT + \
E1HVN_MAX)
@@ -1793,7 +1854,7 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
/* must be used on a CID before placing it on a HW ring */
#define HW_CID(bp, x) ((BP_PORT(bp) << 23) | \
- (BP_E1HVN(bp) << BNX2X_SWCID_SHIFT) | \
+ (BP_VN(bp) << BNX2X_SWCID_SHIFT) | \
(x))
#define SP_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_spe))
diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index 37e5790681ad..580b44edb066 100644
--- a/drivers/net/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -15,6 +15,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/etherdevice.h>
#include <linux/if_vlan.h>
#include <linux/interrupt.h>
@@ -452,7 +454,7 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
skb_fill_page_desc(skb, j, old_rx_pg.page, 0, frag_len);
skb->data_len += frag_len;
- skb->truesize += frag_len;
+ skb->truesize += SGE_PAGE_SIZE * PAGES_PER_SGE;
skb->len += frag_len;
frag_size -= frag_len;
@@ -954,15 +956,16 @@ void __bnx2x_link_report(struct bnx2x *bp)
netdev_err(bp->dev, "NIC Link is Down\n");
return;
} else {
+ const char *duplex;
+ const char *flow;
+
netif_carrier_on(bp->dev);
- netdev_info(bp->dev, "NIC Link is Up, ");
- pr_cont("%d Mbps ", cur_data.line_speed);
if (test_and_clear_bit(BNX2X_LINK_REPORT_FD,
&cur_data.link_report_flags))
- pr_cont("full duplex");
+ duplex = "full";
else
- pr_cont("half duplex");
+ duplex = "half";
/* Handle the FC at the end so that only these flags would be
* possibly set. This way we may easily check if there is no FC
@@ -971,24 +974,25 @@ void __bnx2x_link_report(struct bnx2x *bp)
if (cur_data.link_report_flags) {
if (test_bit(BNX2X_LINK_REPORT_RX_FC_ON,
&cur_data.link_report_flags)) {
- pr_cont(", receive ");
if (test_bit(BNX2X_LINK_REPORT_TX_FC_ON,
&cur_data.link_report_flags))
- pr_cont("& transmit ");
+ flow = "ON - receive & transmit";
+ else
+ flow = "ON - receive";
} else {
- pr_cont(", transmit ");
+ flow = "ON - transmit";
}
- pr_cont("flow control ON");
+ } else {
+ flow = "none";
}
- pr_cont("\n");
+ netdev_info(bp->dev, "NIC Link is Up, %d Mbps %s duplex, Flow control: %s\n",
+ cur_data.line_speed, duplex, flow);
}
}
void bnx2x_init_rx_rings(struct bnx2x *bp)
{
int func = BP_FUNC(bp);
- int max_agg_queues = CHIP_IS_E1(bp) ? ETH_MAX_AGGREGATION_QUEUES_E1 :
- ETH_MAX_AGGREGATION_QUEUES_E1H_E2;
u16 ring_prod;
int i, j;
@@ -1001,7 +1005,7 @@ void bnx2x_init_rx_rings(struct bnx2x *bp)
if (!fp->disable_tpa) {
/* Fill the per-aggregtion pool */
- for (i = 0; i < max_agg_queues; i++) {
+ for (i = 0; i < MAX_AGG_QS(bp); i++) {
struct bnx2x_agg_info *tpa_info =
&fp->tpa_info[i];
struct sw_rx_bd *first_buf =
@@ -1041,7 +1045,7 @@ void bnx2x_init_rx_rings(struct bnx2x *bp)
bnx2x_free_rx_sge_range(bp, fp,
ring_prod);
bnx2x_free_tpa_pool(bp, fp,
- max_agg_queues);
+ MAX_AGG_QS(bp));
fp->disable_tpa = 1;
ring_prod = 0;
break;
@@ -1137,9 +1141,7 @@ static void bnx2x_free_rx_skbs(struct bnx2x *bp)
bnx2x_free_rx_bds(fp);
if (!fp->disable_tpa)
- bnx2x_free_tpa_pool(bp, fp, CHIP_IS_E1(bp) ?
- ETH_MAX_AGGREGATION_QUEUES_E1 :
- ETH_MAX_AGGREGATION_QUEUES_E1H_E2);
+ bnx2x_free_tpa_pool(bp, fp, MAX_AGG_QS(bp));
}
}
@@ -2361,7 +2363,7 @@ static int bnx2x_pkt_req_lin(struct bnx2x *bp, struct sk_buff *skb,
/* Calculate the first sum - it's special */
for (frag_idx = 0; frag_idx < wnd_size - 1; frag_idx++)
wnd_sum +=
- skb_shinfo(skb)->frags[frag_idx].size;
+ skb_frag_size(&skb_shinfo(skb)->frags[frag_idx]);
/* If there was data on linear skb data - check it */
if (first_bd_sz > 0) {
@@ -2377,14 +2379,14 @@ static int bnx2x_pkt_req_lin(struct bnx2x *bp, struct sk_buff *skb,
check all windows */
for (wnd_idx = 0; wnd_idx <= num_wnds; wnd_idx++) {
wnd_sum +=
- skb_shinfo(skb)->frags[wnd_idx + wnd_size - 1].size;
+ skb_frag_size(&skb_shinfo(skb)->frags[wnd_idx + wnd_size - 1]);
if (unlikely(wnd_sum < lso_mss)) {
to_copy = 1;
break;
}
wnd_sum -=
- skb_shinfo(skb)->frags[wnd_idx].size;
+ skb_frag_size(&skb_shinfo(skb)->frags[wnd_idx]);
}
} else {
/* in non-LSO too fragmented packet should always
@@ -2605,7 +2607,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
#endif
/* enable this debug print to view the transmission queue being used
- DP(BNX2X_MSG_FP, "indices: txq %d, fp %d, txdata %d",
+ DP(BNX2X_MSG_FP, "indices: txq %d, fp %d, txdata %d\n",
txq_index, fp_index, txdata_index); */
/* locate the fastpath and the txdata */
@@ -2614,7 +2616,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* enable this debug print to view the tranmission details
DP(BNX2X_MSG_FP,"transmitting packet cid %d fp index %d txdata_index %d"
- " tx_data ptr %p fp pointer %p",
+ " tx_data ptr %p fp pointer %p\n",
txdata->cid, fp_index, txdata_index, txdata, fp); */
if (unlikely(bnx2x_tx_avail(bp, txdata) <
@@ -2794,9 +2796,8 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- mapping = dma_map_page(&bp->pdev->dev, frag->page,
- frag->page_offset, frag->size,
- DMA_TO_DEVICE);
+ mapping = skb_frag_dma_map(&bp->pdev->dev, frag, 0,
+ skb_frag_size(frag), DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
DP(NETIF_MSG_TX_QUEUED, "Unable to map page - "
@@ -2820,8 +2821,8 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
tx_data_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
tx_data_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
- tx_data_bd->nbytes = cpu_to_le16(frag->size);
- le16_add_cpu(&pkt_size, frag->size);
+ tx_data_bd->nbytes = cpu_to_le16(skb_frag_size(frag));
+ le16_add_cpu(&pkt_size, skb_frag_size(frag));
nbd++;
DP(NETIF_MSG_TX_QUEUED,
@@ -2931,14 +2932,14 @@ int bnx2x_setup_tc(struct net_device *dev, u8 num_tc)
/* requested to support too many traffic classes */
if (num_tc > bp->max_cos) {
DP(NETIF_MSG_TX_ERR, "support for too many traffic classes"
- " requested: %d. max supported is %d",
+ " requested: %d. max supported is %d\n",
num_tc, bp->max_cos);
return -EINVAL;
}
/* declare amount of supported traffic classes */
if (netdev_set_num_tc(dev, num_tc)) {
- DP(NETIF_MSG_TX_ERR, "failed to declare %d traffic classes",
+ DP(NETIF_MSG_TX_ERR, "failed to declare %d traffic classes\n",
num_tc);
return -EINVAL;
}
@@ -2946,7 +2947,7 @@ int bnx2x_setup_tc(struct net_device *dev, u8 num_tc)
/* configure priority to traffic class mapping */
for (prio = 0; prio < BNX2X_MAX_PRIORITY; prio++) {
netdev_set_prio_tc_map(dev, prio, bp->prio_to_cos[prio]);
- DP(BNX2X_MSG_SP, "mapping priority %d to tc %d",
+ DP(BNX2X_MSG_SP, "mapping priority %d to tc %d\n",
prio, bp->prio_to_cos[prio]);
}
@@ -2955,10 +2956,10 @@ int bnx2x_setup_tc(struct net_device *dev, u8 num_tc)
This can be used for ets or pfc, and save the effort of setting
up a multio class queue disc or negotiating DCBX with a switch
netdev_set_prio_tc_map(dev, 0, 0);
- DP(BNX2X_MSG_SP, "mapping priority %d to tc %d", 0, 0);
+ DP(BNX2X_MSG_SP, "mapping priority %d to tc %d\n", 0, 0);
for (prio = 1; prio < 16; prio++) {
netdev_set_prio_tc_map(dev, prio, 1);
- DP(BNX2X_MSG_SP, "mapping priority %d to tc %d", prio, 1);
+ DP(BNX2X_MSG_SP, "mapping priority %d to tc %d\n", prio, 1);
} */
/* configure traffic class to transmission queue mapping */
@@ -2966,7 +2967,7 @@ int bnx2x_setup_tc(struct net_device *dev, u8 num_tc)
count = BNX2X_NUM_ETH_QUEUES(bp);
offset = cos * MAX_TXQS_PER_COS;
netdev_set_tc_queue(dev, cos, count, offset);
- DP(BNX2X_MSG_SP, "mapping tc %d to offset %d count %d",
+ DP(BNX2X_MSG_SP, "mapping tc %d to offset %d count %d\n",
cos, offset, count);
}
@@ -3054,7 +3055,7 @@ static void bnx2x_free_fp_mem_at(struct bnx2x *bp, int fp_index)
struct bnx2x_fp_txdata *txdata = &fp->txdata[cos];
DP(BNX2X_MSG_SP,
- "freeing tx memory of fp %d cos %d cid %d",
+ "freeing tx memory of fp %d cos %d cid %d\n",
fp_index, cos, txdata->cid);
BNX2X_FREE(txdata->tx_buf_ring);
@@ -3095,15 +3096,20 @@ static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index)
struct bnx2x_fastpath *fp = &bp->fp[index];
int ring_size = 0;
u8 cos;
+ int rx_ring_size = 0;
/* if rx_ring_size specified - use it */
- int rx_ring_size = bp->rx_ring_size ? bp->rx_ring_size :
- MAX_RX_AVAIL/BNX2X_NUM_RX_QUEUES(bp);
+ if (!bp->rx_ring_size) {
- /* allocate at least number of buffers required by FW */
- rx_ring_size = max_t(int, bp->disable_tpa ? MIN_RX_SIZE_NONTPA :
- MIN_RX_SIZE_TPA,
- rx_ring_size);
+ rx_ring_size = MAX_RX_AVAIL/BNX2X_NUM_RX_QUEUES(bp);
+
+ /* allocate at least number of buffers required by FW */
+ rx_ring_size = max_t(int, bp->disable_tpa ? MIN_RX_SIZE_NONTPA :
+ MIN_RX_SIZE_TPA, rx_ring_size);
+
+ bp->rx_ring_size = rx_ring_size;
+ } else
+ rx_ring_size = bp->rx_ring_size;
/* Common */
sb = &bnx2x_fp(bp, index, status_blk);
@@ -3136,7 +3142,7 @@ static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index)
struct bnx2x_fp_txdata *txdata = &fp->txdata[cos];
DP(BNX2X_MSG_SP, "allocating tx memory of "
- "fp %d cos %d",
+ "fp %d cos %d\n",
index, cos);
BNX2X_ALLOC(txdata->tx_buf_ring,
@@ -3386,7 +3392,7 @@ int bnx2x_change_mtu(struct net_device *dev, int new_mtu)
struct bnx2x *bp = netdev_priv(dev);
if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
- printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+ pr_err("Handling parity error recovery. Try again later\n");
return -EAGAIN;
}
@@ -3512,7 +3518,7 @@ int bnx2x_resume(struct pci_dev *pdev)
bp = netdev_priv(dev);
if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
- printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+ pr_err("Handling parity error recovery. Try again later\n");
return -EAGAIN;
}
diff --git a/drivers/net/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
index 223bfeebc597..283d663da180 100644
--- a/drivers/net/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -522,7 +522,7 @@ void bnx2x_free_mem_bp(struct bnx2x *bp);
*/
int bnx2x_change_mtu(struct net_device *dev, int new_mtu);
-#if defined(BCM_CNIC) && (defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE))
+#if defined(NETDEV_FCOE_WWNN) && defined(BCM_CNIC)
/**
* bnx2x_fcoe_get_wwn - return the requested WWN value for this port
*
@@ -1289,7 +1289,7 @@ static inline void bnx2x_init_txdata(struct bnx2x *bp,
txdata->txq_index = txq_index;
txdata->tx_cons_sb = tx_cons_sb;
- DP(BNX2X_MSG_SP, "created tx data cid %d, txq %d",
+ DP(BNX2X_MSG_SP, "created tx data cid %d, txq %d\n",
txdata->cid, txdata->txq_index);
}
@@ -1297,7 +1297,7 @@ static inline void bnx2x_init_txdata(struct bnx2x *bp,
static inline u8 bnx2x_cnic_eth_cl_id(struct bnx2x *bp, u8 cl_idx)
{
return bp->cnic_base_cl_id + cl_idx +
- (bp->pf_num >> 1) * NON_ETH_CONTEXT_USE;
+ (bp->pf_num >> 1) * BNX2X_MAX_CNIC_ETH_CL_ID_IDX;
}
static inline u8 bnx2x_cnic_fw_sb_id(struct bnx2x *bp)
@@ -1333,7 +1333,7 @@ static inline void bnx2x_init_fcoe_fp(struct bnx2x *bp)
bnx2x_init_txdata(bp, &bnx2x_fcoe(bp, txdata[0]),
fp->cid, FCOE_TXQ_IDX(bp), BNX2X_FCOE_L2_TX_INDEX);
- DP(BNX2X_MSG_SP, "created fcoe tx data (fp index %d)", fp->index);
+ DP(BNX2X_MSG_SP, "created fcoe tx data (fp index %d)\n", fp->index);
/* qZone id equals to FW (per path) client id */
bnx2x_fcoe(bp, cl_qzone_id) = bnx2x_fp_qzone_id(fp);
@@ -1481,8 +1481,8 @@ static inline u16 bnx2x_extract_max_cfg(struct bnx2x *bp, u32 mf_cfg)
u16 max_cfg = (mf_cfg & FUNC_MF_CFG_MAX_BW_MASK) >>
FUNC_MF_CFG_MAX_BW_SHIFT;
if (!max_cfg) {
- BNX2X_ERR("Illegal configuration detected for Max BW - "
- "using 100 instead\n");
+ DP(NETIF_MSG_LINK,
+ "Max BW configured to 0 - using 100 instead\n");
max_cfg = 100;
}
return max_cfg;
diff --git a/drivers/net/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
index a1e004a82f7a..51bd7485ab18 100644
--- a/drivers/net/bnx2x/bnx2x_dcb.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
@@ -16,6 +16,9 @@
* Written by: Dmitry Kravkov
*
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/netdevice.h>
#include <linux/types.h>
#include <linux/errno.h>
@@ -350,7 +353,7 @@ static void bnx2x_dcbx_map_nw(struct bnx2x *bp)
if (cos_params[i].pri_bitmask & nw_prio) {
/* extend the bitmask with unmapped */
DP(NETIF_MSG_LINK,
- "cos %d extended with 0x%08x", i, unmapped);
+ "cos %d extended with 0x%08x\n", i, unmapped);
cos_params[i].pri_bitmask |= unmapped;
break;
}
@@ -2120,6 +2123,7 @@ static u8 bnx2x_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap)
break;
case DCB_CAP_ATTR_DCBX:
*cap = BNX2X_DCBX_CAPS;
+ break;
default:
rval = -EINVAL;
break;
diff --git a/drivers/net/bnx2x/bnx2x_dcb.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h
index 2c6a3bca6f28..2c6a3bca6f28 100644
--- a/drivers/net/bnx2x/bnx2x_dcb.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h
diff --git a/drivers/net/bnx2x/bnx2x_dump.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
index b983825d0ee9..b983825d0ee9 100644
--- a/drivers/net/bnx2x/bnx2x_dump.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
index 221863059dae..1a6e37ce730c 100644
--- a/drivers/net/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
@@ -14,6 +14,9 @@
* Statistics and Link management by Yitchak Gertner
*
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/ethtool.h>
#include <linux/netdevice.h>
#include <linux/types.h>
@@ -239,9 +242,9 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->maxrxpkt = 0;
DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n"
- DP_LEVEL " supported 0x%x advertising 0x%x speed %u\n"
- DP_LEVEL " duplex %d port %d phy_address %d transceiver %d\n"
- DP_LEVEL " autoneg %d maxtxpkt %d maxrxpkt %d\n",
+ " supported 0x%x advertising 0x%x speed %u\n"
+ " duplex %d port %d phy_address %d transceiver %d\n"
+ " autoneg %d maxtxpkt %d maxrxpkt %d\n",
cmd->cmd, cmd->supported, cmd->advertising,
ethtool_cmd_speed(cmd),
cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver,
@@ -363,13 +366,50 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
}
/* advertise the requested speed and duplex if supported */
- cmd->advertising &= bp->port.supported[cfg_idx];
+ if (cmd->advertising & ~(bp->port.supported[cfg_idx])) {
+ DP(NETIF_MSG_LINK, "Advertisement parameters "
+ "are not supported\n");
+ return -EINVAL;
+ }
bp->link_params.req_line_speed[cfg_idx] = SPEED_AUTO_NEG;
- bp->link_params.req_duplex[cfg_idx] = DUPLEX_FULL;
- bp->port.advertising[cfg_idx] |= (ADVERTISED_Autoneg |
+ bp->link_params.req_duplex[cfg_idx] = cmd->duplex;
+ bp->port.advertising[cfg_idx] = (ADVERTISED_Autoneg |
cmd->advertising);
+ if (cmd->advertising) {
+ bp->link_params.speed_cap_mask[cfg_idx] = 0;
+ if (cmd->advertising & ADVERTISED_10baseT_Half) {
+ bp->link_params.speed_cap_mask[cfg_idx] |=
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF;
+ }
+ if (cmd->advertising & ADVERTISED_10baseT_Full)
+ bp->link_params.speed_cap_mask[cfg_idx] |=
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL;
+
+ if (cmd->advertising & ADVERTISED_100baseT_Full)
+ bp->link_params.speed_cap_mask[cfg_idx] |=
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL;
+
+ if (cmd->advertising & ADVERTISED_100baseT_Half) {
+ bp->link_params.speed_cap_mask[cfg_idx] |=
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF;
+ }
+ if (cmd->advertising & ADVERTISED_1000baseT_Half) {
+ bp->link_params.speed_cap_mask[cfg_idx] |=
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_1G;
+ }
+ if (cmd->advertising & (ADVERTISED_1000baseT_Full |
+ ADVERTISED_1000baseKX_Full))
+ bp->link_params.speed_cap_mask[cfg_idx] |=
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_1G;
+
+ if (cmd->advertising & (ADVERTISED_10000baseT_Full |
+ ADVERTISED_10000baseKX4_Full |
+ ADVERTISED_10000baseKR_Full))
+ bp->link_params.speed_cap_mask[cfg_idx] |=
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_10G;
+ }
} else { /* forced speed */
/* advertise the requested speed and duplex if supported */
switch (speed) {
@@ -482,7 +522,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
}
DP(NETIF_MSG_LINK, "req_line_speed %d\n"
- DP_LEVEL " req_duplex %d advertising 0x%x\n",
+ " req_duplex %d advertising 0x%x\n",
bp->link_params.req_line_speed[cfg_idx],
bp->link_params.req_duplex[cfg_idx],
bp->port.advertising[cfg_idx]);
@@ -1028,7 +1068,7 @@ static int bnx2x_get_eeprom(struct net_device *dev,
return -EAGAIN;
DP(BNX2X_MSG_NVM, "ethtool_eeprom: cmd %d\n"
- DP_LEVEL " magic 0x%x offset 0x%x (%d) len 0x%x (%d)\n",
+ " magic 0x%x offset 0x%x (%d) len 0x%x (%d)\n",
eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset,
eeprom->len, eeprom->len);
@@ -1199,7 +1239,7 @@ static int bnx2x_set_eeprom(struct net_device *dev,
return -EAGAIN;
DP(BNX2X_MSG_NVM, "ethtool_eeprom: cmd %d\n"
- DP_LEVEL " magic 0x%x offset 0x%x (%d) len 0x%x (%d)\n",
+ " magic 0x%x offset 0x%x (%d) len 0x%x (%d)\n",
eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset,
eeprom->len, eeprom->len);
@@ -1304,19 +1344,11 @@ static void bnx2x_get_ringparam(struct net_device *dev,
struct bnx2x *bp = netdev_priv(dev);
ering->rx_max_pending = MAX_RX_AVAIL;
- ering->rx_mini_max_pending = 0;
- ering->rx_jumbo_max_pending = 0;
if (bp->rx_ring_size)
ering->rx_pending = bp->rx_ring_size;
else
- if (bp->state == BNX2X_STATE_OPEN && bp->num_queues)
- ering->rx_pending = MAX_RX_AVAIL/bp->num_queues;
- else
- ering->rx_pending = MAX_RX_AVAIL;
-
- ering->rx_mini_pending = 0;
- ering->rx_jumbo_pending = 0;
+ ering->rx_pending = MAX_RX_AVAIL;
ering->tx_max_pending = MAX_TX_AVAIL;
ering->tx_pending = bp->tx_ring_size;
@@ -1328,7 +1360,7 @@ static int bnx2x_set_ringparam(struct net_device *dev,
struct bnx2x *bp = netdev_priv(dev);
if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
- printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+ pr_err("Handling parity error recovery. Try again later\n");
return -EAGAIN;
}
@@ -1359,7 +1391,7 @@ static void bnx2x_get_pauseparam(struct net_device *dev,
BNX2X_FLOW_CTRL_TX);
DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n"
- DP_LEVEL " autoneg %d rx_pause %d tx_pause %d\n",
+ " autoneg %d rx_pause %d tx_pause %d\n",
epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause);
}
@@ -1372,7 +1404,7 @@ static int bnx2x_set_pauseparam(struct net_device *dev,
return 0;
DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n"
- DP_LEVEL " autoneg %d rx_pause %d tx_pause %d\n",
+ " autoneg %d rx_pause %d tx_pause %d\n",
epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause);
bp->link_params.req_flow_ctrl[cfg_idx] = BNX2X_FLOW_CTRL_AUTO;
@@ -1970,7 +2002,7 @@ static void bnx2x_self_test(struct net_device *dev,
struct bnx2x *bp = netdev_priv(dev);
u8 is_serdes;
if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
- printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+ pr_err("Handling parity error recovery. Try again later\n");
etest->flags |= ETH_TEST_FL_FAILED;
return;
}
@@ -2238,7 +2270,7 @@ static int bnx2x_set_phys_id(struct net_device *dev,
}
static int bnx2x_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
- void *rules __always_unused)
+ u32 *rules __always_unused)
{
struct bnx2x *bp = netdev_priv(dev);
diff --git a/drivers/net/bnx2x/bnx2x_fw_defs.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
index 998652a1b858..998652a1b858 100644
--- a/drivers/net/bnx2x/bnx2x_fw_defs.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
diff --git a/drivers/net/bnx2x/bnx2x_fw_file_hdr.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h
index f4a07fbaed05..f4a07fbaed05 100644
--- a/drivers/net/bnx2x/bnx2x_fw_file_hdr.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h
diff --git a/drivers/net/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
index dc24de40e336..e44b858ff12f 100644
--- a/drivers/net/bnx2x/bnx2x_hsi.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
@@ -704,6 +704,7 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */
#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM84833 0x00000d00
#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM54618SE 0x00000e00
#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8722 0x00000f00
+ #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM54616 0x00001000
#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_FAILURE 0x0000fd00
#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_NOT_CONN 0x0000ff00
@@ -759,6 +760,7 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833 0x00000d00
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE 0x00000e00
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722 0x00000f00
+ #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54616 0x00001000
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT_WC 0x0000fc00
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE 0x0000fd00
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN 0x0000ff00
diff --git a/drivers/net/bnx2x/bnx2x_init.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h
index 4d748e77d1ac..4d748e77d1ac 100644
--- a/drivers/net/bnx2x/bnx2x_init.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h
diff --git a/drivers/net/bnx2x/bnx2x_init_ops.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h
index 7ec1724753ad..7ec1724753ad 100644
--- a/drivers/net/bnx2x/bnx2x_init_ops.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h
diff --git a/drivers/net/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
index d45b1555a602..818723c9e678 100644
--- a/drivers/net/bnx2x/bnx2x_link.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
@@ -694,8 +694,8 @@ static int bnx2x_ets_e3b0_disabled(const struct link_params *params,
struct bnx2x *bp = params->bp;
if (!CHIP_IS_E3B0(bp)) {
- DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_disabled the chip isn't E3B0"
- "\n");
+ DP(NETIF_MSG_LINK,
+ "bnx2x_ets_e3b0_disabled the chip isn't E3B0\n");
return -EINVAL;
}
@@ -778,9 +778,9 @@ static int bnx2x_ets_e3b0_set_cos_bw(struct bnx2x *bp,
{
u32 nig_reg_adress_crd_weight = 0;
u32 pbf_reg_adress_crd_weight = 0;
- /* Calculate and set BW for this COS*/
- const u32 cos_bw_nig = (bw * min_w_val_nig) / total_bw;
- const u32 cos_bw_pbf = (bw * min_w_val_pbf) / total_bw;
+ /* Calculate and set BW for this COS - use 1 instead of 0 for BW */
+ const u32 cos_bw_nig = ((bw ? bw : 1) * min_w_val_nig) / total_bw;
+ const u32 cos_bw_pbf = ((bw ? bw : 1) * min_w_val_pbf) / total_bw;
switch (cos_entry) {
case 0:
@@ -852,26 +852,20 @@ static int bnx2x_ets_e3b0_get_total_bw(
/* Calculate total BW requested */
for (cos_idx = 0; cos_idx < ets_params->num_of_cos; cos_idx++) {
if (bnx2x_cos_state_bw == ets_params->cos[cos_idx].state) {
-
- if (0 == ets_params->cos[cos_idx].params.bw_params.bw) {
- DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config BW"
- "was set to 0\n");
- return -EINVAL;
+ *total_bw +=
+ ets_params->cos[cos_idx].params.bw_params.bw;
}
- *total_bw +=
- ets_params->cos[cos_idx].params.bw_params.bw;
- }
}
- /*Check taotl BW is valid */
+ /* Check total BW is valid */
if ((100 != *total_bw) || (0 == *total_bw)) {
if (0 == *total_bw) {
- DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config toatl BW"
- "shouldn't be 0\n");
+ DP(NETIF_MSG_LINK,
+ "bnx2x_ets_E3B0_config toatl BW shouldn't be 0\n");
return -EINVAL;
}
- DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config toatl BW should be"
- "100\n");
+ DP(NETIF_MSG_LINK,
+ "bnx2x_ets_E3B0_config toatl BW should be 100\n");
/**
* We can handle a case whre the BW isn't 100 this can happen
* if the TC are joined.
@@ -908,13 +902,13 @@ static int bnx2x_ets_e3b0_sp_pri_to_cos_set(const struct link_params *params,
if (DCBX_INVALID_COS != sp_pri_to_cos[pri]) {
DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_sp_pri_to_cos_set invalid "
- "parameter There can't be two COS's with"
+ "parameter There can't be two COS's with "
"the same strict pri\n");
return -EINVAL;
}
if (pri > max_num_of_cos) {
- DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_sp_pri_to_cos_set invalid"
+ DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_sp_pri_to_cos_set invalid "
"parameter Illegal strict priority\n");
return -EINVAL;
}
@@ -1090,8 +1084,8 @@ int bnx2x_ets_e3b0_config(const struct link_params *params,
u8 cos_entry = 0;
if (!CHIP_IS_E3B0(bp)) {
- DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_disabled the chip isn't E3B0"
- "\n");
+ DP(NETIF_MSG_LINK,
+ "bnx2x_ets_e3b0_disabled the chip isn't E3B0\n");
return -EINVAL;
}
@@ -1108,8 +1102,8 @@ int bnx2x_ets_e3b0_config(const struct link_params *params,
bnx2x_status = bnx2x_ets_e3b0_get_total_bw(params, ets_params,
&total_bw);
if (0 != bnx2x_status) {
- DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config get_total_bw failed "
- "\n");
+ DP(NETIF_MSG_LINK,
+ "bnx2x_ets_E3B0_config get_total_bw failed\n");
return -EINVAL;
}
@@ -1144,13 +1138,13 @@ int bnx2x_ets_e3b0_config(const struct link_params *params,
cos_entry);
} else {
- DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_config cos state not"
- " valid\n");
+ DP(NETIF_MSG_LINK,
+ "bnx2x_ets_e3b0_config cos state not valid\n");
return -EINVAL;
}
if (0 != bnx2x_status) {
- DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_config set cos bw "
- "failed\n");
+ DP(NETIF_MSG_LINK,
+ "bnx2x_ets_e3b0_config set cos bw failed\n");
return bnx2x_status;
}
}
@@ -1160,8 +1154,8 @@ int bnx2x_ets_e3b0_config(const struct link_params *params,
sp_pri_to_cos);
if (0 != bnx2x_status) {
- DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config set_pri_cli_reg "
- "failed\n");
+ DP(NETIF_MSG_LINK,
+ "bnx2x_ets_E3B0_config set_pri_cli_reg failed\n");
return bnx2x_status;
}
@@ -1618,8 +1612,8 @@ static void bnx2x_xmac_init(struct bnx2x *bp, u32 max_speed)
if (is_port4mode && (REG_RD(bp, MISC_REG_RESET_REG_2) &
MISC_REGISTERS_RESET_REG_2_XMAC)) {
- DP(NETIF_MSG_LINK, "XMAC already out of reset"
- " in 4-port mode\n");
+ DP(NETIF_MSG_LINK,
+ "XMAC already out of reset in 4-port mode\n");
return;
}
@@ -1642,13 +1636,13 @@ static void bnx2x_xmac_init(struct bnx2x *bp, u32 max_speed)
/* Set the number of ports on the system side to 1 */
REG_WR(bp, MISC_REG_XMAC_CORE_PORT_MODE, 0);
if (max_speed == SPEED_10000) {
- DP(NETIF_MSG_LINK, "Init XMAC to 10G x 1"
- " port per path\n");
+ DP(NETIF_MSG_LINK,
+ "Init XMAC to 10G x 1 port per path\n");
/* Set the number of ports on the Warp Core to 10G */
REG_WR(bp, MISC_REG_XMAC_PHY_PORT_MODE, 3);
} else {
- DP(NETIF_MSG_LINK, "Init XMAC to 20G x 2 ports"
- " per path\n");
+ DP(NETIF_MSG_LINK,
+ "Init XMAC to 20G x 2 ports per path\n");
/* Set the number of ports on the Warp Core to 20G */
REG_WR(bp, MISC_REG_XMAC_PHY_PORT_MODE, 1);
}
@@ -1726,7 +1720,7 @@ static int bnx2x_xmac_enable(struct link_params *params,
/* Check loopback mode */
if (lb)
- val |= XMAC_CTRL_REG_CORE_LOCAL_LPBK;
+ val |= XMAC_CTRL_REG_LINE_LOCAL_LPBK;
REG_WR(bp, xmac_base + XMAC_REG_CTRL, val);
bnx2x_set_xumac_nig(params,
((vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) != 0), 1);
@@ -3630,6 +3624,12 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1, val16);
+ /* Advertised and set FEC (Forward Error Correction) */
+ bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+ MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT2,
+ (MDIO_WC_REG_AN_IEEE1BLK_AN_ADV2_FEC_ABILITY |
+ MDIO_WC_REG_AN_IEEE1BLK_AN_ADV2_FEC_REQ));
+
/* Enable CL37 BAM */
if (REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region, dev_info.
@@ -3959,8 +3959,8 @@ static void bnx2x_warpcore_set_sgmii_speed(struct bnx2x_phy *phy,
val16 |= 0x0040;
break;
default:
- DP(NETIF_MSG_LINK, "Speed not supported: 0x%x"
- "\n", phy->req_line_speed);
+ DP(NETIF_MSG_LINK,
+ "Speed not supported: 0x%x\n", phy->req_line_speed);
return;
}
@@ -4092,9 +4092,9 @@ static int bnx2x_get_mod_abs_int_cfg(struct bnx2x *bp,
*/
if ((cfg_pin < PIN_CFG_GPIO0_P0) ||
(cfg_pin > PIN_CFG_GPIO3_P1)) {
- DP(NETIF_MSG_LINK, "ERROR: Invalid cfg pin %x for "
- "module detect indication\n",
- cfg_pin);
+ DP(NETIF_MSG_LINK,
+ "ERROR: Invalid cfg pin %x for module detect indication\n",
+ cfg_pin);
return -EINVAL;
}
@@ -4222,8 +4222,9 @@ static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy,
break;
default:
- DP(NETIF_MSG_LINK, "Unsupported Serdes Net Interface "
- "0x%x\n", serdes_net_if);
+ DP(NETIF_MSG_LINK,
+ "Unsupported Serdes Net Interface 0x%x\n",
+ serdes_net_if);
return;
}
}
@@ -5924,7 +5925,7 @@ int bnx2x_set_led(struct link_params *params,
(tmp | EMAC_LED_OVERRIDE));
/*
* return here without enabling traffic
- * LED blink andsetting rate in ON mode.
+ * LED blink and setting rate in ON mode.
* In oper mode, enabling LED blink
* and setting rate is needed.
*/
@@ -5936,7 +5937,11 @@ int bnx2x_set_led(struct link_params *params,
* This is a work-around for HW issue found when link
* is up in CL73
*/
- REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
+ if ((!CHIP_IS_E3(bp)) ||
+ (CHIP_IS_E3(bp) &&
+ mode == LED_MODE_ON))
+ REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
+
if (CHIP_IS_E1x(bp) ||
CHIP_IS_E2(bp) ||
(mode == LED_MODE_ON))
@@ -6127,8 +6132,8 @@ static int bnx2x_link_initialize(struct link_params *params,
if (phy_index == EXT_PHY2 &&
(bnx2x_phy_selection(params) ==
PORT_HW_CFG_PHY_SELECTION_FIRST_PHY)) {
- DP(NETIF_MSG_LINK, "Not initializing"
- " second phy\n");
+ DP(NETIF_MSG_LINK,
+ "Not initializing second phy\n");
continue;
}
params->phy[phy_index].config_init(
@@ -6447,8 +6452,8 @@ int bnx2x_link_update(struct link_params *params, struct link_vars *vars)
*/
if (active_external_phy == EXT_PHY1) {
if (params->phy[EXT_PHY2].phy_specific_func) {
- DP(NETIF_MSG_LINK, "Disabling TX on"
- " EXT_PHY2\n");
+ DP(NETIF_MSG_LINK,
+ "Disabling TX on EXT_PHY2\n");
params->phy[EXT_PHY2].phy_specific_func(
&params->phy[EXT_PHY2],
params, DISABLE_TX);
@@ -7341,8 +7346,8 @@ static int bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
u16 val = 0;
u16 i;
if (byte_cnt > 16) {
- DP(NETIF_MSG_LINK, "Reading from eeprom is"
- " is limited to 0xf\n");
+ DP(NETIF_MSG_LINK,
+ "Reading from eeprom is limited to 0xf\n");
return -EINVAL;
}
/* Set the read command byte count */
@@ -7413,8 +7418,8 @@ static int bnx2x_warpcore_read_sfp_module_eeprom(struct bnx2x_phy *phy,
" addr %d, cnt %d\n",
addr, byte_cnt);*/
if (byte_cnt > 16) {
- DP(NETIF_MSG_LINK, "Reading from eeprom is"
- " is limited to 16 bytes\n");
+ DP(NETIF_MSG_LINK,
+ "Reading from eeprom is limited to 16 bytes\n");
return -EINVAL;
}
@@ -7443,8 +7448,8 @@ static int bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
u16 val, i;
if (byte_cnt > 16) {
- DP(NETIF_MSG_LINK, "Reading from eeprom is"
- " is limited to 0xf\n");
+ DP(NETIF_MSG_LINK,
+ "Reading from eeprom is limited to 0xf\n");
return -EINVAL;
}
@@ -7591,13 +7596,14 @@ static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
check_limiting_mode = 1;
} else if (copper_module_type &
SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
- DP(NETIF_MSG_LINK, "Passive Copper"
- " cable detected\n");
+ DP(NETIF_MSG_LINK,
+ "Passive Copper cable detected\n");
*edc_mode =
EDC_MODE_PASSIVE_DAC;
} else {
- DP(NETIF_MSG_LINK, "Unknown copper-cable-"
- "type 0x%x !!!\n", copper_module_type);
+ DP(NETIF_MSG_LINK,
+ "Unknown copper-cable-type 0x%x !!!\n",
+ copper_module_type);
return -EINVAL;
}
break;
@@ -7635,8 +7641,8 @@ static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
SFP_EEPROM_OPTIONS_ADDR,
SFP_EEPROM_OPTIONS_SIZE,
options) != 0) {
- DP(NETIF_MSG_LINK, "Failed to read Option"
- " field from module EEPROM\n");
+ DP(NETIF_MSG_LINK,
+ "Failed to read Option field from module EEPROM\n");
return -EINVAL;
}
if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
@@ -7677,15 +7683,15 @@ static int bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY) {
/* Use first phy request only in case of non-dual media*/
if (DUAL_MEDIA(params)) {
- DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
- "verification\n");
+ DP(NETIF_MSG_LINK,
+ "FW does not support OPT MDL verification\n");
return -EINVAL;
}
cmd = DRV_MSG_CODE_VRFY_FIRST_PHY_OPT_MDL;
} else {
/* No support in OPT MDL detection */
- DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
- "verification\n");
+ DP(NETIF_MSG_LINK,
+ "FW does not support OPT MDL verification\n");
return -EINVAL;
}
@@ -7736,8 +7742,9 @@ static int bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
for (timeout = 0; timeout < 60; timeout++) {
if (bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, &val)
== 0) {
- DP(NETIF_MSG_LINK, "SFP+ module initialization "
- "took %d ms\n", timeout * 5);
+ DP(NETIF_MSG_LINK,
+ "SFP+ module initialization took %d ms\n",
+ timeout * 5);
return 0;
}
msleep(5);
@@ -8506,8 +8513,8 @@ static int bnx2x_8726_config_init(struct bnx2x_phy *phy,
/* Set TX PreEmphasis if needed */
if ((params->feature_config_flags &
FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
- DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
- "TX_CTRL2 0x%x\n",
+ DP(NETIF_MSG_LINK,
+ "Setting TX_CTRL1 0x%x, TX_CTRL2 0x%x\n",
phy->tx_preemphasis[0],
phy->tx_preemphasis[1]);
bnx2x_cl45_write(bp, phy,
@@ -8788,8 +8795,8 @@ static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
if (mod_abs & (1<<8)) {
/* Module is absent */
- DP(NETIF_MSG_LINK, "MOD_ABS indication "
- "show module is absent\n");
+ DP(NETIF_MSG_LINK,
+ "MOD_ABS indication show module is absent\n");
phy->media_type = ETH_PHY_NOT_PRESENT;
/*
* 1. Set mod_abs to detect next module
@@ -8816,8 +8823,8 @@ static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
} else {
/* Module is present */
- DP(NETIF_MSG_LINK, "MOD_ABS indication "
- "show module is present\n");
+ DP(NETIF_MSG_LINK,
+ "MOD_ABS indication show module is present\n");
/*
* First disable transmitter, and if the module is ok, the
* module_detection will enable it
@@ -8908,8 +8915,9 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
if ((val1 & (1<<8)) == 0) {
if (!CHIP_IS_E1x(bp))
oc_port = BP_PATH(bp) + (params->port << 1);
- DP(NETIF_MSG_LINK, "8727 Power fault has been detected"
- " on port %d\n", oc_port);
+ DP(NETIF_MSG_LINK,
+ "8727 Power fault has been detected on port %d\n",
+ oc_port);
netdev_err(bp->dev, "Error: Power fault on Port %d has"
" been detected and the power to "
"that SFP+ module has been removed"
@@ -9690,8 +9698,8 @@ static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
&legacy_status);
- DP(NETIF_MSG_LINK, "Legacy speed status"
- " = 0x%x\n", legacy_status);
+ DP(NETIF_MSG_LINK, "Legacy speed status = 0x%x\n",
+ legacy_status);
link_up = ((legacy_status & (1<<11)) == (1<<11));
if (link_up) {
legacy_speed = (legacy_status & (3<<9));
@@ -9709,9 +9717,10 @@ static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
else
vars->duplex = DUPLEX_HALF;
- DP(NETIF_MSG_LINK, "Link is up in %dMbps,"
- " is_duplex_full= %d\n", vars->line_speed,
- (vars->duplex == DUPLEX_FULL));
+ DP(NETIF_MSG_LINK,
+ "Link is up in %dMbps, is_duplex_full= %d\n",
+ vars->line_speed,
+ (vars->duplex == DUPLEX_FULL));
/* Check legacy speed AN resolution */
bnx2x_cl45_read(bp, phy,
MDIO_AN_DEVAD,
@@ -10286,9 +10295,10 @@ static u8 bnx2x_54618se_read_status(struct bnx2x_phy *phy,
} else /* Should not happen */
vars->line_speed = 0;
- DP(NETIF_MSG_LINK, "Link is up in %dMbps,"
- " is_duplex_full= %d\n", vars->line_speed,
- (vars->duplex == DUPLEX_FULL));
+ DP(NETIF_MSG_LINK,
+ "Link is up in %dMbps, is_duplex_full= %d\n",
+ vars->line_speed,
+ (vars->duplex == DUPLEX_FULL));
/* Check legacy speed AN resolution */
bnx2x_cl22_read(bp, phy,
@@ -10638,8 +10648,7 @@ static struct bnx2x_phy phy_warpcore = {
.type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
.addr = 0xff,
.def_md_devad = 0,
- .flags = (FLAGS_HW_LOCK_REQUIRED |
- FLAGS_TX_ERROR_CHECK),
+ .flags = FLAGS_HW_LOCK_REQUIRED,
.rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.mdio_ctrl = 0,
@@ -10765,8 +10774,7 @@ static struct bnx2x_phy phy_8706 = {
.type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706,
.addr = 0xff,
.def_md_devad = 0,
- .flags = (FLAGS_INIT_XGXS_FIRST |
- FLAGS_TX_ERROR_CHECK),
+ .flags = FLAGS_INIT_XGXS_FIRST,
.rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.mdio_ctrl = 0,
@@ -10797,8 +10805,7 @@ static struct bnx2x_phy phy_8726 = {
.addr = 0xff,
.def_md_devad = 0,
.flags = (FLAGS_HW_LOCK_REQUIRED |
- FLAGS_INIT_XGXS_FIRST |
- FLAGS_TX_ERROR_CHECK),
+ FLAGS_INIT_XGXS_FIRST),
.rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.mdio_ctrl = 0,
@@ -10829,8 +10836,7 @@ static struct bnx2x_phy phy_8727 = {
.type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
.addr = 0xff,
.def_md_devad = 0,
- .flags = (FLAGS_FAN_FAILURE_DET_REQ |
- FLAGS_TX_ERROR_CHECK),
+ .flags = FLAGS_FAN_FAILURE_DET_REQ,
.rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.mdio_ctrl = 0,
@@ -11236,6 +11242,7 @@ static int bnx2x_populate_ext_phy(struct bnx2x *bp,
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833:
*phy = phy_84833;
break;
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54616:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE:
*phy = phy_54618se;
break;
@@ -11336,8 +11343,9 @@ static void bnx2x_phy_def_cfg(struct link_params *params,
dev_info.
port_hw_config[params->port].speed_capability_mask));
}
- DP(NETIF_MSG_LINK, "Default config phy idx %x cfg 0x%x speed_cap_mask"
- " 0x%x\n", phy_index, link_config, phy->speed_cap_mask);
+ DP(NETIF_MSG_LINK,
+ "Default config phy idx %x cfg 0x%x speed_cap_mask 0x%x\n",
+ phy_index, link_config, phy->speed_cap_mask);
phy->req_duplex = DUPLEX_FULL;
switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) {
diff --git a/drivers/net/bnx2x/bnx2x_link.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
index c12db6da213e..c12db6da213e 100644
--- a/drivers/net/bnx2x/bnx2x_link.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index f74582a22c68..6486ab8c8fc8 100644
--- a/drivers/net/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -15,6 +15,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -37,6 +39,7 @@
#include <linux/time.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
+#include <linux/if.h>
#include <linux/if_vlan.h>
#include <net/ip.h>
#include <net/ipv6.h>
@@ -350,17 +353,15 @@ static void bnx2x_dp_dmae(struct bnx2x *bp, struct dmae_command *dmae,
default:
if (src_type == DMAE_CMD_SRC_PCI)
DP(msglvl, "DMAE: opcode 0x%08x\n"
- DP_LEVEL "src_addr [%x:%08x] len [%d * 4] "
- "dst_addr [none]\n"
- DP_LEVEL "comp_addr [%x:%08x] comp_val 0x%08x\n",
+ "src_addr [%x:%08x] len [%d * 4] dst_addr [none]\n"
+ "comp_addr [%x:%08x] comp_val 0x%08x\n",
dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
dmae->len, dmae->comp_addr_hi, dmae->comp_addr_lo,
dmae->comp_val);
else
DP(msglvl, "DMAE: opcode 0x%08x\n"
- DP_LEVEL "src_addr [%08x] len [%d * 4] "
- "dst_addr [none]\n"
- DP_LEVEL "comp_addr [%x:%08x] comp_val 0x%08x\n",
+ "src_addr [%08x] len [%d * 4] dst_addr [none]\n"
+ "comp_addr [%x:%08x] comp_val 0x%08x\n",
dmae->opcode, dmae->src_addr_lo >> 2,
dmae->len, dmae->comp_addr_hi, dmae->comp_addr_lo,
dmae->comp_val);
@@ -407,8 +408,8 @@ u32 bnx2x_dmae_opcode(struct bnx2x *bp, u8 src_type, u8 dst_type,
opcode |= (DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET);
opcode |= (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0);
- opcode |= ((BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT) |
- (BP_E1HVN(bp) << DMAE_COMMAND_DST_VN_SHIFT));
+ opcode |= ((BP_VN(bp) << DMAE_CMD_E1HVN_SHIFT) |
+ (BP_VN(bp) << DMAE_COMMAND_DST_VN_SHIFT));
opcode |= (DMAE_COM_SET_ERR << DMAE_COMMAND_ERR_POLICY_SHIFT);
#ifdef __BIG_ENDIAN
@@ -789,18 +790,15 @@ void bnx2x_panic_dump(struct bnx2x *bp)
BNX2X_ERR(" def (");
for (i = 0; i < HC_SP_SB_MAX_INDICES; i++)
pr_cont("0x%x%s",
- bp->def_status_blk->sp_sb.index_values[i],
- (i == HC_SP_SB_MAX_INDICES - 1) ? ") " : " ");
+ bp->def_status_blk->sp_sb.index_values[i],
+ (i == HC_SP_SB_MAX_INDICES - 1) ? ") " : " ");
for (i = 0; i < sizeof(struct hc_sp_status_block_data)/sizeof(u32); i++)
*((u32 *)&sp_sb_data + i) = REG_RD(bp, BAR_CSTRORM_INTMEM +
CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(func) +
i*sizeof(u32));
- pr_cont("igu_sb_id(0x%x) igu_seg_id(0x%x) "
- "pf_id(0x%x) vnic_id(0x%x) "
- "vf_id(0x%x) vf_valid (0x%x) "
- "state(0x%x)\n",
+ pr_cont("igu_sb_id(0x%x) igu_seg_id(0x%x) pf_id(0x%x) vnic_id(0x%x) vf_id(0x%x) vf_valid (0x%x) state(0x%x)\n",
sp_sb_data.igu_sb_id,
sp_sb_data.igu_seg_id,
sp_sb_data.p_func.pf_id,
@@ -1419,7 +1417,7 @@ static void bnx2x_hc_int_enable(struct bnx2x *bp)
if (!CHIP_IS_E1(bp)) {
/* init leading/trailing edge */
if (IS_MF(bp)) {
- val = (0xee0f | (1 << (BP_E1HVN(bp) + 4)));
+ val = (0xee0f | (1 << (BP_VN(bp) + 4)));
if (bp->port.pmf)
/* enable nig and gpio3 attention */
val |= 0x1100;
@@ -1471,7 +1469,7 @@ static void bnx2x_igu_int_enable(struct bnx2x *bp)
/* init leading/trailing edge */
if (IS_MF(bp)) {
- val = (0xee0f | (1 << (BP_E1HVN(bp) + 4)));
+ val = (0xee0f | (1 << (BP_VN(bp) + 4)));
if (bp->port.pmf)
/* enable nig and gpio3 attention */
val |= 0x1100;
@@ -2287,7 +2285,7 @@ static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp)
int vn;
bp->vn_weight_sum = 0;
- for (vn = VN_0; vn < E1HVN_MAX; vn++) {
+ for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++) {
u32 vn_cfg = bp->mf_config[vn];
u32 vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >>
FUNC_MF_CFG_MIN_BW_SHIFT) * 100;
@@ -2320,12 +2318,18 @@ static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp)
CMNG_FLAGS_PER_PORT_FAIRNESS_VN;
}
+/* returns func by VN for current port */
+static inline int func_by_vn(struct bnx2x *bp, int vn)
+{
+ return 2 * vn + BP_PORT(bp);
+}
+
static void bnx2x_init_vn_minmax(struct bnx2x *bp, int vn)
{
struct rate_shaping_vars_per_vn m_rs_vn;
struct fairness_vars_per_vn m_fair_vn;
u32 vn_cfg = bp->mf_config[vn];
- int func = 2*vn + BP_PORT(bp);
+ int func = func_by_vn(bp, vn);
u16 vn_min_rate, vn_max_rate;
int i;
@@ -2422,7 +2426,7 @@ void bnx2x_read_mf_cfg(struct bnx2x *bp)
*
* and there are 2 functions per port
*/
- for (vn = VN_0; vn < E1HVN_MAX; vn++) {
+ for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++) {
int /*abs*/func = n * (2 * vn + BP_PORT(bp)) + BP_PATH(bp);
if (func >= E1H_FUNC_MAX)
@@ -2454,7 +2458,7 @@ static void bnx2x_cmng_fns_init(struct bnx2x *bp, u8 read_cfg, u8 cmng_type)
/* calculate and set min-max rate for each vn */
if (bp->port.pmf)
- for (vn = VN_0; vn < E1HVN_MAX; vn++)
+ for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++)
bnx2x_init_vn_minmax(bp, vn);
/* always enable rate shaping and fairness */
@@ -2473,16 +2477,15 @@ static void bnx2x_cmng_fns_init(struct bnx2x *bp, u8 read_cfg, u8 cmng_type)
static inline void bnx2x_link_sync_notify(struct bnx2x *bp)
{
- int port = BP_PORT(bp);
int func;
int vn;
/* Set the attention towards other drivers on the same port */
- for (vn = VN_0; vn < E1HVN_MAX; vn++) {
- if (vn == BP_E1HVN(bp))
+ for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++) {
+ if (vn == BP_VN(bp))
continue;
- func = ((vn << 1) | port);
+ func = func_by_vn(bp, vn);
REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 +
(LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1);
}
@@ -2577,7 +2580,7 @@ static void bnx2x_pmf_update(struct bnx2x *bp)
bnx2x_dcbx_pmf_update(bp);
/* enable nig attention */
- val = (0xff0f | (1 << (BP_E1HVN(bp) + 4)));
+ val = (0xff0f | (1 << (BP_VN(bp) + 4)));
if (bp->common.int_block == INT_BLOCK_HC) {
REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val);
REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val);
@@ -2756,8 +2759,14 @@ static void bnx2x_pf_rx_q_prep(struct bnx2x *bp,
u16 tpa_agg_size = 0;
if (!fp->disable_tpa) {
- pause->sge_th_hi = 250;
- pause->sge_th_lo = 150;
+ pause->sge_th_lo = SGE_TH_LO(bp);
+ pause->sge_th_hi = SGE_TH_HI(bp);
+
+ /* validate SGE ring has enough to cross high threshold */
+ WARN_ON(bp->dropless_fc &&
+ pause->sge_th_hi + FW_PREFETCH_CNT >
+ MAX_RX_SGE_CNT * NUM_RX_SGE_PAGES);
+
tpa_agg_size = min_t(u32,
(min_t(u32, 8, MAX_SKB_FRAGS) *
SGE_PAGE_SIZE * PAGES_PER_SGE), 0xffff);
@@ -2771,10 +2780,21 @@ static void bnx2x_pf_rx_q_prep(struct bnx2x *bp,
/* pause - not for e1 */
if (!CHIP_IS_E1(bp)) {
- pause->bd_th_hi = 350;
- pause->bd_th_lo = 250;
- pause->rcq_th_hi = 350;
- pause->rcq_th_lo = 250;
+ pause->bd_th_lo = BD_TH_LO(bp);
+ pause->bd_th_hi = BD_TH_HI(bp);
+
+ pause->rcq_th_lo = RCQ_TH_LO(bp);
+ pause->rcq_th_hi = RCQ_TH_HI(bp);
+ /*
+ * validate that rings have enough entries to cross
+ * high thresholds
+ */
+ WARN_ON(bp->dropless_fc &&
+ pause->bd_th_hi + FW_PREFETCH_CNT >
+ bp->rx_ring_size);
+ WARN_ON(bp->dropless_fc &&
+ pause->rcq_th_hi + FW_PREFETCH_CNT >
+ NUM_RCQ_RINGS * MAX_RCQ_DESC_CNT);
pause->pri_map = 1;
}
@@ -2802,9 +2822,7 @@ static void bnx2x_pf_rx_q_prep(struct bnx2x *bp,
* For PF Clients it should be the maximum avaliable number.
* VF driver(s) may want to define it to a smaller value.
*/
- rxq_init->max_tpa_queues =
- (CHIP_IS_E1(bp) ? ETH_MAX_AGGREGATION_QUEUES_E1 :
- ETH_MAX_AGGREGATION_QUEUES_E1H_E2);
+ rxq_init->max_tpa_queues = MAX_AGG_QS(bp);
rxq_init->cache_line_log = BNX2X_RX_ALIGN_SHIFT;
rxq_init->fw_sb_id = fp->fw_sb_id;
@@ -3721,9 +3739,7 @@ static inline void bnx2x_clear_load_cnt(struct bnx2x *bp)
static inline void _print_next_block(int idx, const char *blk)
{
- if (idx)
- pr_cont(", ");
- pr_cont("%s", blk);
+ pr_cont("%s%s", idx ? ", " : "", blk);
}
static inline int bnx2x_check_blocks_with_parity0(u32 sig, int par_num,
@@ -4337,8 +4353,6 @@ static inline void bnx2x_handle_classification_eqe(struct bnx2x *bp,
vlan_mac_obj = &bp->fp[cid].mac_obj;
break;
- vlan_mac_obj = &bp->fp[cid].mac_obj;
-
case BNX2X_FILTER_MCAST_PENDING:
/* This is only relevant for 57710 where multicast MACs are
* configured as unicast MACs using the same ramrod.
@@ -4388,7 +4402,7 @@ static inline void bnx2x_handle_rx_mode_eqe(struct bnx2x *bp)
static inline struct bnx2x_queue_sp_obj *bnx2x_cid_to_q_obj(
struct bnx2x *bp, u32 cid)
{
- DP(BNX2X_MSG_SP, "retrieving fp from cid %d", cid);
+ DP(BNX2X_MSG_SP, "retrieving fp from cid %d\n", cid);
#ifdef BCM_CNIC
if (cid == BNX2X_FCOE_ETH_CID)
return &bnx2x_fcoe(bp, q_obj);
@@ -4808,6 +4822,37 @@ void bnx2x_setup_ndsb_state_machine(struct hc_status_block_sm *hc_sm,
hc_sm->time_to_expire = 0xFFFFFFFF;
}
+
+/* allocates state machine ids. */
+static inline
+void bnx2x_map_sb_state_machines(struct hc_index_data *index_data)
+{
+ /* zero out state machine indices */
+ /* rx indices */
+ index_data[HC_INDEX_ETH_RX_CQ_CONS].flags &= ~HC_INDEX_DATA_SM_ID;
+
+ /* tx indices */
+ index_data[HC_INDEX_OOO_TX_CQ_CONS].flags &= ~HC_INDEX_DATA_SM_ID;
+ index_data[HC_INDEX_ETH_TX_CQ_CONS_COS0].flags &= ~HC_INDEX_DATA_SM_ID;
+ index_data[HC_INDEX_ETH_TX_CQ_CONS_COS1].flags &= ~HC_INDEX_DATA_SM_ID;
+ index_data[HC_INDEX_ETH_TX_CQ_CONS_COS2].flags &= ~HC_INDEX_DATA_SM_ID;
+
+ /* map indices */
+ /* rx indices */
+ index_data[HC_INDEX_ETH_RX_CQ_CONS].flags |=
+ SM_RX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
+
+ /* tx indices */
+ index_data[HC_INDEX_OOO_TX_CQ_CONS].flags |=
+ SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
+ index_data[HC_INDEX_ETH_TX_CQ_CONS_COS0].flags |=
+ SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
+ index_data[HC_INDEX_ETH_TX_CQ_CONS_COS1].flags |=
+ SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
+ index_data[HC_INDEX_ETH_TX_CQ_CONS_COS2].flags |=
+ SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
+}
+
static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
u8 vf_valid, int fw_sb_id, int igu_sb_id)
{
@@ -4839,6 +4884,7 @@ static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
hc_sm_p = sb_data_e2.common.state_machine;
sb_data_p = (u32 *)&sb_data_e2;
data_size = sizeof(struct hc_status_block_data_e2)/sizeof(u32);
+ bnx2x_map_sb_state_machines(sb_data_e2.index_data);
} else {
memset(&sb_data_e1x, 0,
sizeof(struct hc_status_block_data_e1x));
@@ -4853,6 +4899,7 @@ static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
hc_sm_p = sb_data_e1x.common.state_machine;
sb_data_p = (u32 *)&sb_data_e1x;
data_size = sizeof(struct hc_status_block_data_e1x)/sizeof(u32);
+ bnx2x_map_sb_state_machines(sb_data_e1x.index_data);
}
bnx2x_setup_ndsb_state_machine(&hc_sm_p[SM_RX_ID],
@@ -4890,7 +4937,7 @@ static void bnx2x_init_def_sb(struct bnx2x *bp)
int igu_seg_id;
int port = BP_PORT(bp);
int func = BP_FUNC(bp);
- int reg_offset;
+ int reg_offset, reg_offset_en5;
u64 section;
int index;
struct hc_sp_status_block_data sp_sb_data;
@@ -4913,6 +4960,8 @@ static void bnx2x_init_def_sb(struct bnx2x *bp)
reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
+ reg_offset_en5 = (port ? MISC_REG_AEU_ENABLE5_FUNC_1_OUT_0 :
+ MISC_REG_AEU_ENABLE5_FUNC_0_OUT_0);
for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) {
int sindex;
/* take care of sig[0]..sig[4] */
@@ -4927,7 +4976,7 @@ static void bnx2x_init_def_sb(struct bnx2x *bp)
* and not 16 between the different groups
*/
bp->attn_group[index].sig[4] = REG_RD(bp,
- reg_offset + 0x10 + 0x4*index);
+ reg_offset_en5 + 0x4*index);
else
bp->attn_group[index].sig[4] = 0;
}
@@ -5802,7 +5851,7 @@ static int bnx2x_init_hw_common(struct bnx2x *bp)
* take the UNDI lock to protect undi_unload flow from accessing
* registers while we're resetting the chip
*/
- bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
+ bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
bnx2x_reset_common(bp);
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0xffffffff);
@@ -5814,7 +5863,7 @@ static int bnx2x_init_hw_common(struct bnx2x *bp)
}
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, val);
- bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
+ bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
bnx2x_init_block(bp, BLOCK_MISC, PHASE_COMMON);
@@ -6671,12 +6720,16 @@ static int bnx2x_init_hw_func(struct bnx2x *bp)
if (CHIP_MODE_IS_4_PORT(bp))
dsb_idx = BP_FUNC(bp);
else
- dsb_idx = BP_E1HVN(bp);
+ dsb_idx = BP_VN(bp);
prod_offset = (CHIP_INT_MODE_IS_BC(bp) ?
IGU_BC_BASE_DSB_PROD + dsb_idx :
IGU_NORM_BASE_DSB_PROD + dsb_idx);
+ /*
+ * igu prods come in chunks of E1HVN_MAX (4) -
+ * does not matters what is the current chip mode
+ */
for (i = 0; i < (num_segs * E1HVN_MAX);
i += E1HVN_MAX) {
addr = IGU_REG_PROD_CONS_MEMORY +
@@ -7184,7 +7237,7 @@ static inline void bnx2x_pf_q_prep_init(struct bnx2x *bp,
/* set maximum number of COSs supported by this queue */
init_params->max_cos = fp->max_cos;
- DP(BNX2X_MSG_SP, "fp: %d setting queue params max cos to: %d",
+ DP(BNX2X_MSG_SP, "fp: %d setting queue params max cos to: %d\n",
fp->index, init_params->max_cos);
/* set the context pointers queue object */
@@ -7217,7 +7270,7 @@ int bnx2x_setup_tx_only(struct bnx2x *bp, struct bnx2x_fastpath *fp,
DP(BNX2X_MSG_SP, "preparing to send tx-only ramrod for connection:"
"cos %d, primary cid %d, cid %d, "
- "client id %d, sp-client id %d, flags %lx",
+ "client id %d, sp-client id %d, flags %lx\n",
tx_index, q_params->q_obj->cids[FIRST_TX_COS_INDEX],
q_params->q_obj->cids[tx_index], q_params->q_obj->cl_id,
tx_only_params->gen_params.spcl_id, tx_only_params->flags);
@@ -7249,7 +7302,7 @@ int bnx2x_setup_queue(struct bnx2x *bp, struct bnx2x_fastpath *fp,
int rc;
u8 tx_index;
- DP(BNX2X_MSG_SP, "setting up queue %d", fp->index);
+ DP(BNX2X_MSG_SP, "setting up queue %d\n", fp->index);
/* reset IGU state skip FCoE L2 queue */
if (!IS_FCOE_FP(fp))
@@ -7273,7 +7326,7 @@ int bnx2x_setup_queue(struct bnx2x *bp, struct bnx2x_fastpath *fp,
return rc;
}
- DP(BNX2X_MSG_SP, "init complete");
+ DP(BNX2X_MSG_SP, "init complete\n");
/* Now move the Queue to the SETUP state... */
@@ -7327,7 +7380,7 @@ static int bnx2x_stop_queue(struct bnx2x *bp, int index)
struct bnx2x_queue_state_params q_params = {0};
int rc, tx_index;
- DP(BNX2X_MSG_SP, "stopping queue %d cid %d", index, fp->cid);
+ DP(BNX2X_MSG_SP, "stopping queue %d cid %d\n", index, fp->cid);
q_params.q_obj = &fp->q_obj;
/* We want to wait for completion in this context */
@@ -7342,7 +7395,7 @@ static int bnx2x_stop_queue(struct bnx2x *bp, int index)
/* ascertain this is a normal queue*/
txdata = &fp->txdata[tx_index];
- DP(BNX2X_MSG_SP, "stopping tx-only queue %d",
+ DP(BNX2X_MSG_SP, "stopping tx-only queue %d\n",
txdata->txq_index);
/* send halt terminate on tx-only connection */
@@ -7568,9 +7621,12 @@ u32 bnx2x_send_unload_req(struct bnx2x *bp, int unload_mode)
u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
u8 *mac_addr = bp->dev->dev_addr;
u32 val;
+ u16 pmc;
+
/* The mac address is written to entries 1-4 to
- preserve entry 0 which is used by the PMF */
- u8 entry = (BP_E1HVN(bp) + 1)*8;
+ * preserve entry 0 which is used by the PMF
+ */
+ u8 entry = (BP_VN(bp) + 1)*8;
val = (mac_addr[0] << 8) | mac_addr[1];
EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + entry, val);
@@ -7579,6 +7635,11 @@ u32 bnx2x_send_unload_req(struct bnx2x *bp, int unload_mode)
(mac_addr[4] << 8) | mac_addr[5];
EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + entry + 4, val);
+ /* Enable the PME and clear the status */
+ pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmc);
+ pmc |= PCI_PM_CTRL_PME_ENABLE | PCI_PM_CTRL_PME_STATUS;
+ pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, pmc);
+
reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_EN;
} else
@@ -8546,10 +8607,12 @@ static void __devinit bnx2x_undi_unload(struct bnx2x *bp)
/* Check if there is any driver already loaded */
val = REG_RD(bp, MISC_REG_UNPREPARED);
if (val == 0x1) {
- /* Check if it is the UNDI driver
+
+ bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
+ /*
+ * Check if it is the UNDI driver
* UNDI driver initializes CID offset for normal bell to 0x7
*/
- bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
val = REG_RD(bp, DORQ_REG_NORM_CID_OFST);
if (val == 0x7) {
u32 reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
@@ -8587,9 +8650,6 @@ static void __devinit bnx2x_undi_unload(struct bnx2x *bp)
bnx2x_fw_command(bp, reset_code, 0);
}
- /* now it's safe to release the lock */
- bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
-
bnx2x_undi_int_disable(bp);
port = BP_PORT(bp);
@@ -8639,8 +8699,10 @@ static void __devinit bnx2x_undi_unload(struct bnx2x *bp)
bp->fw_seq =
(SHMEM_RD(bp, func_mb[bp->pf_num].drv_mb_header) &
DRV_MSG_SEQ_NUMBER_MASK);
- } else
- bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
+ }
+
+ /* now it's safe to release the lock */
+ bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
}
}
@@ -8777,13 +8839,13 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
static void __devinit bnx2x_get_igu_cam_info(struct bnx2x *bp)
{
int pfid = BP_FUNC(bp);
- int vn = BP_E1HVN(bp);
int igu_sb_id;
u32 val;
u8 fid, igu_sb_cnt = 0;
bp->igu_base_sb = 0xff;
if (CHIP_INT_MODE_IS_BC(bp)) {
+ int vn = BP_VN(bp);
igu_sb_cnt = bp->igu_sb_cnt;
bp->igu_base_sb = (CHIP_MODE_IS_4_PORT(bp) ? pfid : vn) *
FP_SB_MAX_E1x;
@@ -9323,9 +9385,8 @@ static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp)
val = MF_CFG_RD(bp, func_ext_config[func].
iscsi_mac_addr_lower);
bnx2x_set_mac_buf(iscsi_mac, val, val2);
- BNX2X_DEV_INFO("Read iSCSI MAC: "
- BNX2X_MAC_FMT"\n",
- BNX2X_MAC_PRN_LIST(iscsi_mac));
+ BNX2X_DEV_INFO("Read iSCSI MAC: %pM\n",
+ iscsi_mac);
} else
bp->flags |= NO_ISCSI_OOO_FLAG | NO_ISCSI_FLAG;
@@ -9335,9 +9396,8 @@ static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp)
val = MF_CFG_RD(bp, func_ext_config[func].
fcoe_mac_addr_lower);
bnx2x_set_mac_buf(fip_mac, val, val2);
- BNX2X_DEV_INFO("Read FCoE L2 MAC to "
- BNX2X_MAC_FMT"\n",
- BNX2X_MAC_PRN_LIST(fip_mac));
+ BNX2X_DEV_INFO("Read FCoE L2 MAC to %pM\n",
+ fip_mac);
} else
bp->flags |= NO_FCOE_FLAG;
@@ -9392,9 +9452,9 @@ static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp)
if (!is_valid_ether_addr(bp->dev->dev_addr))
dev_err(&bp->pdev->dev,
"bad Ethernet MAC address configuration: "
- BNX2X_MAC_FMT", change it manually before bringing up "
+ "%pM, change it manually before bringing up "
"the appropriate network interface\n",
- BNX2X_MAC_PRN_LIST(bp->dev->dev_addr));
+ bp->dev->dev_addr);
}
static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
@@ -9416,6 +9476,10 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
bp->igu_base_sb = 0;
} else {
bp->common.int_block = INT_BLOCK_IGU;
+
+ /* do not allow device reset during IGU info preocessing */
+ bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
+
val = REG_RD(bp, IGU_REG_BLOCK_CONFIGURATION);
if (val & IGU_BLOCK_CONFIGURATION_REG_BACKWARD_COMP_EN) {
@@ -9447,6 +9511,7 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
bnx2x_get_igu_cam_info(bp);
+ bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
}
/*
@@ -9473,7 +9538,7 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
bp->mf_ov = 0;
bp->mf_mode = 0;
- vn = BP_E1HVN(bp);
+ vn = BP_VN(bp);
if (!CHIP_IS_E1(bp) && !BP_NOMCP(bp)) {
BNX2X_DEV_INFO("shmem2base 0x%x, size %d, mfcfg offset %d\n",
@@ -9593,13 +9658,6 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
/* port info */
bnx2x_get_port_hwinfo(bp);
- if (!BP_NOMCP(bp)) {
- bp->fw_seq =
- (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
- DRV_MSG_SEQ_NUMBER_MASK);
- BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
- }
-
/* Get MAC addresses */
bnx2x_get_mac_hwinfo(bp);
@@ -9765,6 +9823,14 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
if (!BP_NOMCP(bp))
bnx2x_undi_unload(bp);
+ /* init fw_seq after undi_unload! */
+ if (!BP_NOMCP(bp)) {
+ bp->fw_seq =
+ (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
+ DRV_MSG_SEQ_NUMBER_MASK);
+ BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
+ }
+
if (CHIP_REV_IS_FPGA(bp))
dev_err(&bp->pdev->dev, "FPGA detected\n");
@@ -10259,17 +10325,21 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
/* clean indirect addresses */
pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
PCICFG_VENDOR_ID_OFFSET);
- /* Clean the following indirect addresses for all functions since it
+ /*
+ * Clean the following indirect addresses for all functions since it
* is not used by the driver.
*/
REG_WR(bp, PXP2_REG_PGL_ADDR_88_F0, 0);
REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F0, 0);
REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0, 0);
REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0, 0);
- REG_WR(bp, PXP2_REG_PGL_ADDR_88_F1, 0);
- REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F1, 0);
- REG_WR(bp, PXP2_REG_PGL_ADDR_90_F1, 0);
- REG_WR(bp, PXP2_REG_PGL_ADDR_94_F1, 0);
+
+ if (CHIP_IS_E1x(bp)) {
+ REG_WR(bp, PXP2_REG_PGL_ADDR_88_F1, 0);
+ REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F1, 0);
+ REG_WR(bp, PXP2_REG_PGL_ADDR_90_F1, 0);
+ REG_WR(bp, PXP2_REG_PGL_ADDR_94_F1, 0);
+ }
/*
* Enable internal target-read (in case we are probed after PF FLR).
@@ -10288,9 +10358,11 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
dev->netdev_ops = &bnx2x_netdev_ops;
bnx2x_set_ethtool_ops(dev);
+ dev->priv_flags |= IFF_UNICAST_FLT;
+
dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
- NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 |
- NETIF_F_RXCSUM | NETIF_F_LRO | NETIF_F_HW_VLAN_TX;
+ NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_LRO |
+ NETIF_F_RXCSUM | NETIF_F_RXHASH | NETIF_F_HW_VLAN_TX;
dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_HIGHDMA;
@@ -10721,7 +10793,7 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
return rc;
}
- DP(NETIF_MSG_DRV, "max_non_def_sbs %d", max_non_def_sbs);
+ DP(NETIF_MSG_DRV, "max_non_def_sbs %d\n", max_non_def_sbs);
rc = bnx2x_init_bp(bp);
if (rc)
@@ -10776,15 +10848,14 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
bnx2x_get_pcie_width_speed(bp, &pcie_width, &pcie_speed);
- netdev_info(dev, "%s (%c%d) PCI-E x%d %s found at mem %lx,"
- " IRQ %d, ", board_info[ent->driver_data].name,
- (CHIP_REV(bp) >> 12) + 'A', (CHIP_METAL(bp) >> 4),
- pcie_width,
- ((!CHIP_IS_E2(bp) && pcie_speed == 2) ||
- (CHIP_IS_E2(bp) && pcie_speed == 1)) ?
- "5GHz (Gen2)" : "2.5GHz",
- dev->base_addr, bp->pdev->irq);
- pr_cont("node addr %pM\n", dev->dev_addr);
+ netdev_info(dev, "%s (%c%d) PCI-E x%d %s found at mem %lx, IRQ %d, node addr %pM\n",
+ board_info[ent->driver_data].name,
+ (CHIP_REV(bp) >> 12) + 'A', (CHIP_METAL(bp) >> 4),
+ pcie_width,
+ ((!CHIP_IS_E2(bp) && pcie_speed == 2) ||
+ (CHIP_IS_E2(bp) && pcie_speed == 1)) ?
+ "5GHz (Gen2)" : "2.5GHz",
+ dev->base_addr, bp->pdev->irq, dev->dev_addr);
return 0;
diff --git a/drivers/net/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
index 40266c14e6dc..fc7bd0f23c0b 100644
--- a/drivers/net/bnx2x/bnx2x_reg.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
@@ -1384,6 +1384,18 @@
Latched ump_tx_parity; [31] MCP Latched scpad_parity; */
#define MISC_REG_AEU_ENABLE4_PXP_0 0xa108
#define MISC_REG_AEU_ENABLE4_PXP_1 0xa1a8
+/* [RW 32] fifth 32b for enabling the output for function 0 output0. Mapped
+ * as follows: [0] PGLUE config_space; [1] PGLUE misc_flr; [2] PGLUE B RBC
+ * attention [3] PGLUE B RBC parity; [4] ATC attention; [5] ATC parity; [6]
+ * mstat0 attention; [7] mstat0 parity; [8] mstat1 attention; [9] mstat1
+ * parity; [31-10] Reserved; */
+#define MISC_REG_AEU_ENABLE5_FUNC_0_OUT_0 0xa688
+/* [RW 32] Fifth 32b for enabling the output for function 1 output0. Mapped
+ * as follows: [0] PGLUE config_space; [1] PGLUE misc_flr; [2] PGLUE B RBC
+ * attention [3] PGLUE B RBC parity; [4] ATC attention; [5] ATC parity; [6]
+ * mstat0 attention; [7] mstat0 parity; [8] mstat1 attention; [9] mstat1
+ * parity; [31-10] Reserved; */
+#define MISC_REG_AEU_ENABLE5_FUNC_1_OUT_0 0xa6b0
/* [RW 1] set/clr general attention 0; this will set/clr bit 94 in the aeu
128 bit vector */
#define MISC_REG_AEU_GENERAL_ATTN_0 0xa000
@@ -5320,7 +5332,7 @@
#define XCM_REG_XX_OVFL_EVNT_ID 0x20058
#define XMAC_CLEAR_RX_LSS_STATUS_REG_CLEAR_LOCAL_FAULT_STATUS (0x1<<0)
#define XMAC_CLEAR_RX_LSS_STATUS_REG_CLEAR_REMOTE_FAULT_STATUS (0x1<<1)
-#define XMAC_CTRL_REG_CORE_LOCAL_LPBK (0x1<<3)
+#define XMAC_CTRL_REG_LINE_LOCAL_LPBK (0x1<<2)
#define XMAC_CTRL_REG_RX_EN (0x1<<1)
#define XMAC_CTRL_REG_SOFT_RESET (0x1<<6)
#define XMAC_CTRL_REG_TX_EN (0x1<<0)
@@ -5766,7 +5778,7 @@
#define HW_LOCK_RESOURCE_RECOVERY_LEADER_0 8
#define HW_LOCK_RESOURCE_RECOVERY_LEADER_1 9
#define HW_LOCK_RESOURCE_SPIO 2
-#define HW_LOCK_RESOURCE_UNDI 5
+#define HW_LOCK_RESOURCE_RESET 5
#define AEU_INPUTS_ATTN_BITS_ATC_HW_INTERRUPT (0x1<<4)
#define AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR (0x1<<5)
#define AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR (0x1<<18)
@@ -6853,6 +6865,9 @@ Theotherbitsarereservedandshouldbezero*/
#define MDIO_WC_REG_IEEE0BLK_AUTONEGNP 0x7
#define MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT0 0x10
#define MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1 0x11
+#define MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT2 0x12
+#define MDIO_WC_REG_AN_IEEE1BLK_AN_ADV2_FEC_ABILITY 0x4000
+#define MDIO_WC_REG_AN_IEEE1BLK_AN_ADV2_FEC_REQ 0x8000
#define MDIO_WC_REG_PMD_IEEE9BLK_TENGBASE_KR_PMD_CONTROL_REGISTER_150 0x96
#define MDIO_WC_REG_XGXSBLK0_XGXSCONTROL 0x8000
#define MDIO_WC_REG_XGXSBLK0_MISCCONTROL1 0x800e
diff --git a/drivers/net/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
index df52f110c6c5..0440425c83d6 100644
--- a/drivers/net/bnx2x/bnx2x_sp.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
@@ -16,6 +16,9 @@
* Written by: Vladislav Zolotarov
*
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/crc32.h>
#include <linux/netdevice.h>
@@ -707,9 +710,8 @@ static void bnx2x_set_one_mac_e2(struct bnx2x *bp,
bnx2x_vlan_mac_set_cmd_hdr_e2(bp, o, add, CLASSIFY_RULE_OPCODE_MAC,
&rule_entry->mac.header);
- DP(BNX2X_MSG_SP, "About to %s MAC "BNX2X_MAC_FMT" for "
- "Queue %d\n", (add ? "add" : "delete"),
- BNX2X_MAC_PRN_LIST(mac), raw->cl_id);
+ DP(BNX2X_MSG_SP, "About to %s MAC %pM for Queue %d\n",
+ add ? "add" : "delete", mac, raw->cl_id);
/* Set a MAC itself */
bnx2x_set_fw_mac_addr(&rule_entry->mac.mac_msb,
@@ -801,9 +803,9 @@ static inline void bnx2x_vlan_mac_set_rdata_e1x(struct bnx2x *bp,
bnx2x_vlan_mac_set_cfg_entry_e1x(bp, o, add, opcode, mac, vlan_id,
cfg_entry);
- DP(BNX2X_MSG_SP, "%s MAC "BNX2X_MAC_FMT" CLID %d CAM offset %d\n",
- (add ? "setting" : "clearing"),
- BNX2X_MAC_PRN_LIST(mac), raw->cl_id, cam_offset);
+ DP(BNX2X_MSG_SP, "%s MAC %pM CLID %d CAM offset %d\n",
+ add ? "setting" : "clearing",
+ mac, raw->cl_id, cam_offset);
}
/**
@@ -2579,9 +2581,8 @@ static inline void bnx2x_mcast_hdl_pending_add_e2(struct bnx2x *bp,
cnt++;
- DP(BNX2X_MSG_SP, "About to configure "BNX2X_MAC_FMT
- " mcast MAC\n",
- BNX2X_MAC_PRN_LIST(pmac_pos->mac));
+ DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n",
+ pmac_pos->mac);
list_del(&pmac_pos->link);
@@ -2702,9 +2703,8 @@ static inline void bnx2x_mcast_hdl_add(struct bnx2x *bp,
cnt++;
- DP(BNX2X_MSG_SP, "About to configure "BNX2X_MAC_FMT
- " mcast MAC\n",
- BNX2X_MAC_PRN_LIST(mlist_pos->mac));
+ DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n",
+ mlist_pos->mac);
}
*line_idx = cnt;
@@ -2998,9 +2998,8 @@ static inline void bnx2x_mcast_hdl_add_e1h(struct bnx2x *bp,
bit = bnx2x_mcast_bin_from_mac(mlist_pos->mac);
BNX2X_57711_SET_MC_FILTER(mc_filter, bit);
- DP(BNX2X_MSG_SP, "About to configure "
- BNX2X_MAC_FMT" mcast MAC, bin %d\n",
- BNX2X_MAC_PRN_LIST(mlist_pos->mac), bit);
+ DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC, bin %d\n",
+ mlist_pos->mac, bit);
/* bookkeeping... */
BIT_VEC64_SET_BIT(o->registry.aprox_match.vec,
@@ -3049,8 +3048,8 @@ static int bnx2x_mcast_setup_e1h(struct bnx2x *bp,
break;
case BNX2X_MCAST_CMD_DEL:
- DP(BNX2X_MSG_SP, "Invalidating multicast "
- "MACs configuration\n");
+ DP(BNX2X_MSG_SP,
+ "Invalidating multicast MACs configuration\n");
/* clear the registry */
memset(o->registry.aprox_match.vec, 0,
@@ -3233,9 +3232,8 @@ static inline int bnx2x_mcast_handle_restore_cmd_e1(
i++;
- DP(BNX2X_MSG_SP, "About to configure "BNX2X_MAC_FMT
- " mcast MAC\n",
- BNX2X_MAC_PRN_LIST(cfg_data.mac));
+ DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n",
+ cfg_data.mac);
}
*rdata_idx = i;
@@ -3270,9 +3268,8 @@ static inline int bnx2x_mcast_handle_pending_cmds_e1(
cnt++;
- DP(BNX2X_MSG_SP, "About to configure "BNX2X_MAC_FMT
- " mcast MAC\n",
- BNX2X_MAC_PRN_LIST(pmac_pos->mac));
+ DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n",
+ pmac_pos->mac);
}
break;
@@ -3357,9 +3354,8 @@ static inline int bnx2x_mcast_refresh_registry_e1(struct bnx2x *bp,
&data->config_table[i].middle_mac_addr,
&data->config_table[i].lsb_mac_addr,
elem->mac);
- DP(BNX2X_MSG_SP, "Adding registry entry for ["
- BNX2X_MAC_FMT"]\n",
- BNX2X_MAC_PRN_LIST(elem->mac));
+ DP(BNX2X_MSG_SP, "Adding registry entry for [%pM]\n",
+ elem->mac);
list_add_tail(&elem->link,
&o->registry.exact_match.macs);
}
@@ -4246,7 +4242,7 @@ static int bnx2x_queue_comp_cmd(struct bnx2x *bp,
o->cids[BNX2X_PRIMARY_CID_INDEX], o->next_state);
if (o->next_tx_only) /* print num tx-only if any exist */
- DP(BNX2X_MSG_SP, "primary cid %d: num tx-only cons %d",
+ DP(BNX2X_MSG_SP, "primary cid %d: num tx-only cons %d\n",
o->cids[BNX2X_PRIMARY_CID_INDEX], o->next_tx_only);
o->state = o->next_state;
@@ -4308,7 +4304,7 @@ static void bnx2x_q_fill_init_general_data(struct bnx2x *bp,
test_bit(BNX2X_Q_FLG_FCOE, flags) ?
LLFC_TRAFFIC_TYPE_FCOE : LLFC_TRAFFIC_TYPE_NW;
- DP(BNX2X_MSG_SP, "flags: active %d, cos %d, stats en %d",
+ DP(BNX2X_MSG_SP, "flags: active %d, cos %d, stats en %d\n",
gen_data->activate_flg, gen_data->cos, gen_data->statistics_en_flg);
}
@@ -4461,7 +4457,7 @@ static void bnx2x_q_fill_setup_tx_only(struct bnx2x *bp,
&data->tx,
&cmd_params->params.tx_only.flags);
- DP(BNX2X_MSG_SP, "cid %d, tx bd page lo %x hi %x",cmd_params->q_obj->cids[0],
+ DP(BNX2X_MSG_SP, "cid %d, tx bd page lo %x hi %x\n",cmd_params->q_obj->cids[0],
data->tx.tx_bd_page_base.lo, data->tx.tx_bd_page_base.hi);
}
@@ -4508,9 +4504,9 @@ static inline int bnx2x_q_init(struct bnx2x *bp,
/* Set CDU context validation values */
for (cos = 0; cos < o->max_cos; cos++) {
- DP(BNX2X_MSG_SP, "setting context validation. cid %d, cos %d",
+ DP(BNX2X_MSG_SP, "setting context validation. cid %d, cos %d\n",
o->cids[cos], cos);
- DP(BNX2X_MSG_SP, "context pointer %p", init->cxts[cos]);
+ DP(BNX2X_MSG_SP, "context pointer %p\n", init->cxts[cos]);
bnx2x_set_ctx_validation(bp, init->cxts[cos], o->cids[cos]);
}
@@ -4599,7 +4595,7 @@ static inline int bnx2x_q_send_setup_tx_only(struct bnx2x *bp,
return -EINVAL;
}
- DP(BNX2X_MSG_SP, "parameters received: cos: %d sp-id: %d",
+ DP(BNX2X_MSG_SP, "parameters received: cos: %d sp-id: %d\n",
tx_only_params->gen_params.cos,
tx_only_params->gen_params.spcl_id);
@@ -4610,7 +4606,7 @@ static inline int bnx2x_q_send_setup_tx_only(struct bnx2x *bp,
bnx2x_q_fill_setup_tx_only(bp, params, rdata);
DP(BNX2X_MSG_SP, "sending tx-only ramrod: cid %d, client-id %d,"
- "sp-client id %d, cos %d",
+ "sp-client id %d, cos %d\n",
o->cids[cid_index],
rdata->general.client_id,
rdata->general.sp_client_id, rdata->general.cos);
@@ -5167,8 +5163,9 @@ static inline int bnx2x_func_state_change_comp(struct bnx2x *bp,
return -EINVAL;
}
- DP(BNX2X_MSG_SP, "Completing command %d for func %d, setting state to "
- "%d\n", cmd, BP_FUNC(bp), o->next_state);
+ DP(BNX2X_MSG_SP,
+ "Completing command %d for func %d, setting state to %d\n",
+ cmd, BP_FUNC(bp), o->next_state);
o->state = o->next_state;
o->next_state = BNX2X_F_STATE_MAX;
diff --git a/drivers/net/bnx2x/bnx2x_sp.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
index 9a517c2e9f1b..9a517c2e9f1b 100644
--- a/drivers/net/bnx2x/bnx2x_sp.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
diff --git a/drivers/net/bnx2x/bnx2x_stats.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
index 771f6803b238..02ac6a771bf9 100644
--- a/drivers/net/bnx2x/bnx2x_stats.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
@@ -14,6 +14,9 @@
* Statistics and Link management by Yitchak Gertner
*
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include "bnx2x_stats.h"
#include "bnx2x_cmn.h"
@@ -710,7 +713,8 @@ static int bnx2x_hw_stats_update(struct bnx2x *bp)
break;
case MAC_TYPE_NONE: /* unreached */
- BNX2X_ERR("stats updated by DMAE but no MAC active\n");
+ DP(BNX2X_MSG_STATS,
+ "stats updated by DMAE but no MAC active\n");
return -1;
default: /* unreached */
@@ -1194,14 +1198,13 @@ static void bnx2x_stats_update(struct bnx2x *bp)
struct bnx2x_fastpath *fp = &bp->fp[i];
struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
- printk(KERN_DEBUG "%s: rx usage(%4u) *rx_cons_sb(%u)"
- " rx pkt(%lu) rx calls(%lu %lu)\n",
- fp->name, (le16_to_cpu(*fp->rx_cons_sb) -
- fp->rx_comp_cons),
- le16_to_cpu(*fp->rx_cons_sb),
- bnx2x_hilo(&qstats->
- total_unicast_packets_received_hi),
- fp->rx_calls, fp->rx_pkt);
+ pr_debug("%s: rx usage(%4u) *rx_cons_sb(%u) rx pkt(%lu) rx calls(%lu %lu)\n",
+ fp->name, (le16_to_cpu(*fp->rx_cons_sb) -
+ fp->rx_comp_cons),
+ le16_to_cpu(*fp->rx_cons_sb),
+ bnx2x_hilo(&qstats->
+ total_unicast_packets_received_hi),
+ fp->rx_calls, fp->rx_pkt);
}
for_each_eth_queue(bp, i) {
@@ -1210,27 +1213,25 @@ static void bnx2x_stats_update(struct bnx2x *bp)
struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
struct netdev_queue *txq;
- printk(KERN_DEBUG "%s: tx pkt(%lu) (Xoff events %u)",
- fp->name, bnx2x_hilo(
- &qstats->total_unicast_packets_transmitted_hi),
- qstats->driver_xoff);
+ pr_debug("%s: tx pkt(%lu) (Xoff events %u)",
+ fp->name,
+ bnx2x_hilo(
+ &qstats->total_unicast_packets_transmitted_hi),
+ qstats->driver_xoff);
for_each_cos_in_tx_queue(fp, cos) {
txdata = &fp->txdata[cos];
txq = netdev_get_tx_queue(bp->dev,
FP_COS_TO_TXQ(fp, cos));
- printk(KERN_DEBUG "%d: tx avail(%4u)"
- " *tx_cons_sb(%u)"
- " tx calls (%lu)"
- " %s\n",
- cos,
- bnx2x_tx_avail(bp, txdata),
- le16_to_cpu(*txdata->tx_cons_sb),
- txdata->tx_pkt,
- (netif_tx_queue_stopped(txq) ?
- "Xoff" : "Xon")
- );
+ pr_debug("%d: tx avail(%4u) *tx_cons_sb(%u) tx calls (%lu) %s\n",
+ cos,
+ bnx2x_tx_avail(bp, txdata),
+ le16_to_cpu(*txdata->tx_cons_sb),
+ txdata->tx_pkt,
+ (netif_tx_queue_stopped(txq) ?
+ "Xoff" : "Xon")
+ );
}
}
}
@@ -1391,7 +1392,7 @@ static void bnx2x_port_stats_base_init(struct bnx2x *bp)
static void bnx2x_func_stats_base_init(struct bnx2x *bp)
{
- int vn, vn_max = IS_MF(bp) ? E1HVN_MAX : E1VN_MAX;
+ int vn, vn_max = IS_MF(bp) ? BP_MAX_VN_NUM(bp) : E1VN_MAX;
u32 func_stx;
/* sanity */
@@ -1404,7 +1405,7 @@ static void bnx2x_func_stats_base_init(struct bnx2x *bp)
func_stx = bp->func_stx;
for (vn = VN_0; vn < vn_max; vn++) {
- int mb_idx = CHIP_IS_E1x(bp) ? 2*vn + BP_PORT(bp) : vn;
+ int mb_idx = BP_FW_MB_IDX_VN(bp, vn);
bp->func_stx = SHMEM_RD(bp, func_mb[mb_idx].fw_mb_param);
bnx2x_func_stats_init(bp);
diff --git a/drivers/net/bnx2x/bnx2x_stats.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
index 5d8ce2f6afef..5d8ce2f6afef 100644
--- a/drivers/net/bnx2x/bnx2x_stats.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
diff --git a/drivers/net/cnic.c b/drivers/net/ethernet/broadcom/cnic.c
index 94a2e541006d..6f10c6939834 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/ethernet/broadcom/cnic.c
@@ -45,8 +45,8 @@
#include "bnx2x/bnx2x_reg.h"
#include "bnx2x/bnx2x_fw_defs.h"
#include "bnx2x/bnx2x_hsi.h"
-#include "../scsi/bnx2i/57xx_iscsi_constants.h"
-#include "../scsi/bnx2i/57xx_iscsi_hsi.h"
+#include "../../../scsi/bnx2i/57xx_iscsi_constants.h"
+#include "../../../scsi/bnx2i/57xx_iscsi_hsi.h"
#include "cnic.h"
#include "cnic_defs.h"
@@ -1177,7 +1177,7 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
cp->fcoe_start_cid = start_cid + MAX_ISCSI_TBL_SZ;
if (BNX2X_CHIP_IS_E2_PLUS(cp->chip_id)) {
- cp->max_cid_space += BNX2X_FCOE_NUM_CONNECTIONS;
+ cp->max_cid_space += dev->max_fcoe_conn;
cp->fcoe_init_cid = ethdev->fcoe_init_cid;
if (!cp->fcoe_init_cid)
cp->fcoe_init_cid = 0x10;
@@ -1875,12 +1875,12 @@ static int cnic_bnx2x_destroy_ramrod(struct cnic_dev *dev, u32 l5_cid)
hw_cid, NONE_CONNECTION_TYPE, &l5_data);
if (ret == 0) {
- wait_event(ctx->waitq, ctx->wait_cond);
+ wait_event_timeout(ctx->waitq, ctx->wait_cond, CNIC_RAMROD_TMO);
if (unlikely(test_bit(CTX_FL_CID_ERROR, &ctx->ctx_flags)))
return -EBUSY;
}
- return ret;
+ return 0;
}
static int cnic_bnx2x_iscsi_destroy(struct cnic_dev *dev, struct kwqe *kwqe)
@@ -2280,7 +2280,7 @@ static int cnic_bnx2x_fcoe_ofld1(struct cnic_dev *dev, struct kwqe *wqes[],
*work = 4;
l5_cid = req1->fcoe_conn_id;
- if (l5_cid >= BNX2X_FCOE_NUM_CONNECTIONS)
+ if (l5_cid >= dev->max_fcoe_conn)
goto err_reply;
l5_cid += BNX2X_FCOE_L5_CID_BASE;
@@ -2384,7 +2384,7 @@ static int cnic_bnx2x_fcoe_disable(struct cnic_dev *dev, struct kwqe *kwqe)
req = (struct fcoe_kwqe_conn_enable_disable *) kwqe;
cid = req->context_id;
l5_cid = req->conn_id;
- if (l5_cid >= BNX2X_FCOE_NUM_CONNECTIONS)
+ if (l5_cid >= dev->max_fcoe_conn)
return -EINVAL;
l5_cid += BNX2X_FCOE_L5_CID_BASE;
@@ -2418,7 +2418,7 @@ static int cnic_bnx2x_fcoe_destroy(struct cnic_dev *dev, struct kwqe *kwqe)
req = (struct fcoe_kwqe_conn_destroy *) kwqe;
cid = req->context_id;
l5_cid = req->conn_id;
- if (l5_cid >= BNX2X_FCOE_NUM_CONNECTIONS)
+ if (l5_cid >= dev->max_fcoe_conn)
return -EINVAL;
l5_cid += BNX2X_FCOE_L5_CID_BASE;
@@ -2428,17 +2428,20 @@ static int cnic_bnx2x_fcoe_destroy(struct cnic_dev *dev, struct kwqe *kwqe)
init_waitqueue_head(&ctx->waitq);
ctx->wait_cond = 0;
+ memset(&kcqe, 0, sizeof(kcqe));
+ kcqe.completion_status = FCOE_KCQE_COMPLETION_STATUS_ERROR;
memset(&l5_data, 0, sizeof(l5_data));
ret = cnic_submit_kwqe_16(dev, FCOE_RAMROD_CMD_ID_TERMINATE_CONN, cid,
FCOE_CONNECTION_TYPE, &l5_data);
if (ret == 0) {
- wait_event(ctx->waitq, ctx->wait_cond);
- set_bit(CTX_FL_DELETE_WAIT, &ctx->ctx_flags);
- queue_delayed_work(cnic_wq, &cp->delete_task,
- msecs_to_jiffies(2000));
+ wait_event_timeout(ctx->waitq, ctx->wait_cond, CNIC_RAMROD_TMO);
+ if (ctx->wait_cond)
+ kcqe.completion_status = 0;
}
- memset(&kcqe, 0, sizeof(kcqe));
+ set_bit(CTX_FL_DELETE_WAIT, &ctx->ctx_flags);
+ queue_delayed_work(cnic_wq, &cp->delete_task, msecs_to_jiffies(2000));
+
kcqe.op_code = FCOE_KCQE_OPCODE_DESTROY_CONN;
kcqe.fcoe_conn_id = req->conn_id;
kcqe.fcoe_conn_context_id = cid;
@@ -4850,8 +4853,7 @@ static int cnic_start_bnx2x_hw(struct cnic_dev *dev)
return -ENOMEM;
if (BNX2X_CHIP_IS_E2_PLUS(cp->chip_id)) {
- ret = cnic_init_id_tbl(&cp->fcoe_cid_tbl,
- BNX2X_FCOE_NUM_CONNECTIONS,
+ ret = cnic_init_id_tbl(&cp->fcoe_cid_tbl, dev->max_fcoe_conn,
cp->fcoe_start_cid, 0);
if (ret)
@@ -5292,6 +5294,9 @@ static struct cnic_dev *init_bnx2x_cnic(struct net_device *dev)
!(ethdev->drv_state & CNIC_DRV_STATE_NO_FCOE))
cdev->max_fcoe_conn = ethdev->max_fcoe_conn;
+ if (cdev->max_fcoe_conn > BNX2X_FCOE_NUM_CONNECTIONS)
+ cdev->max_fcoe_conn = BNX2X_FCOE_NUM_CONNECTIONS;
+
memcpy(cdev->mac_addr, ethdev->iscsi_mac, 6);
cp->cnic_ops = &cnic_bnx2x_ops;
diff --git a/drivers/net/cnic.h b/drivers/net/ethernet/broadcom/cnic.h
index 7a2928f82d40..30328097f516 100644
--- a/drivers/net/cnic.h
+++ b/drivers/net/ethernet/broadcom/cnic.h
@@ -373,7 +373,7 @@ struct bnx2x_bd_chain_next {
#define BNX2X_ISCSI_PBL_NOT_CACHED 0xff
#define BNX2X_ISCSI_PDU_HEADER_NOT_CACHED 0xff
-#define BNX2X_FCOE_NUM_CONNECTIONS 128
+#define BNX2X_FCOE_NUM_CONNECTIONS 1024
#define BNX2X_FCOE_L5_CID_BASE MAX_ISCSI_TBL_SZ
@@ -474,5 +474,7 @@ struct bnx2x_bd_chain_next {
MAX_STAT_COUNTER_ID_E1))
#endif
+#define CNIC_RAMROD_TMO (HZ / 4)
+
#endif
diff --git a/drivers/net/cnic_defs.h b/drivers/net/ethernet/broadcom/cnic_defs.h
index e47d21076767..239de898f071 100644
--- a/drivers/net/cnic_defs.h
+++ b/drivers/net/ethernet/broadcom/cnic_defs.h
@@ -67,6 +67,7 @@
#define FCOE_KWQE_OPCODE_DESTROY (10)
#define FCOE_KWQE_OPCODE_STAT (11)
+#define FCOE_KCQE_COMPLETION_STATUS_ERROR (0x1)
#define FCOE_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE (0x3)
/* KCQ (kernel completion queue) response op codes */
diff --git a/drivers/net/cnic_if.h b/drivers/net/ethernet/broadcom/cnic_if.h
index 79443e0dbf96..79443e0dbf96 100644
--- a/drivers/net/cnic_if.h
+++ b/drivers/net/ethernet/broadcom/cnic_if.h
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/ethernet/broadcom/sb1250-mac.c
index ea65f7ec360a..0a1d7f279fc8 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/ethernet/broadcom/sb1250-mac.c
@@ -2176,7 +2176,7 @@ static const struct net_device_ops sbmac_netdev_ops = {
.ndo_open = sbmac_open,
.ndo_stop = sbmac_close,
.ndo_start_xmit = sbmac_start_tx,
- .ndo_set_multicast_list = sbmac_set_rx_mode,
+ .ndo_set_rx_mode = sbmac_set_rx_mode,
.ndo_tx_timeout = sbmac_tx_timeout,
.ndo_do_ioctl = sbmac_mii_ioctl,
.ndo_change_mtu = sb1250_change_mtu,
diff --git a/drivers/net/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index dc3fbf61910b..161cbbb4814a 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -89,12 +89,15 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
#define DRV_MODULE_NAME "tg3"
#define TG3_MAJ_NUM 3
-#define TG3_MIN_NUM 119
+#define TG3_MIN_NUM 120
#define DRV_MODULE_VERSION \
__stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM)
-#define DRV_MODULE_RELDATE "May 18, 2011"
+#define DRV_MODULE_RELDATE "August 18, 2011"
+
+#define RESET_KIND_SHUTDOWN 0
+#define RESET_KIND_INIT 1
+#define RESET_KIND_SUSPEND 2
-#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
#define TG3_DEF_TX_MODE 0
#define TG3_DEF_MSG_ENABLE \
@@ -188,6 +191,12 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
#define TG3_RX_COPY_THRESH(tp) ((tp)->rx_copy_thresh)
#endif
+#if (NET_IP_ALIGN != 0)
+#define TG3_RX_OFFSET(tp) ((tp)->rx_offset)
+#else
+#define TG3_RX_OFFSET(tp) 0
+#endif
+
/* minimum number of free TX descriptors required to wake up TX process */
#define TG3_TX_WAKEUP_THRESH(tnapi) ((tnapi)->tx_pending / 4)
#define TG3_TX_BD_DMA_MAX 4096
@@ -391,12 +400,14 @@ static const struct {
static const struct {
const char string[ETH_GSTRING_LEN];
} ethtool_test_keys[] = {
- { "nvram test (online) " },
- { "link test (online) " },
- { "register test (offline)" },
- { "memory test (offline)" },
- { "loopback test (offline)" },
- { "interrupt test (offline)" },
+ { "nvram test (online) " },
+ { "link test (online) " },
+ { "register test (offline)" },
+ { "memory test (offline)" },
+ { "mac loopback test (offline)" },
+ { "phy loopback test (offline)" },
+ { "ext loopback test (offline)" },
+ { "interrupt test (offline)" },
};
#define TG3_NUM_TEST ARRAY_SIZE(ethtool_test_keys)
@@ -717,6 +728,103 @@ static void tg3_ape_unlock(struct tg3 *tp, int locknum)
tg3_ape_write32(tp, gnt + 4 * locknum, bit);
}
+static void tg3_ape_send_event(struct tg3 *tp, u32 event)
+{
+ int i;
+ u32 apedata;
+
+ /* NCSI does not support APE events */
+ if (tg3_flag(tp, APE_HAS_NCSI))
+ return;
+
+ apedata = tg3_ape_read32(tp, TG3_APE_SEG_SIG);
+ if (apedata != APE_SEG_SIG_MAGIC)
+ return;
+
+ apedata = tg3_ape_read32(tp, TG3_APE_FW_STATUS);
+ if (!(apedata & APE_FW_STATUS_READY))
+ return;
+
+ /* Wait for up to 1 millisecond for APE to service previous event. */
+ for (i = 0; i < 10; i++) {
+ if (tg3_ape_lock(tp, TG3_APE_LOCK_MEM))
+ return;
+
+ apedata = tg3_ape_read32(tp, TG3_APE_EVENT_STATUS);
+
+ if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
+ tg3_ape_write32(tp, TG3_APE_EVENT_STATUS,
+ event | APE_EVENT_STATUS_EVENT_PENDING);
+
+ tg3_ape_unlock(tp, TG3_APE_LOCK_MEM);
+
+ if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
+ break;
+
+ udelay(100);
+ }
+
+ if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
+ tg3_ape_write32(tp, TG3_APE_EVENT, APE_EVENT_1);
+}
+
+static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
+{
+ u32 event;
+ u32 apedata;
+
+ if (!tg3_flag(tp, ENABLE_APE))
+ return;
+
+ switch (kind) {
+ case RESET_KIND_INIT:
+ tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG,
+ APE_HOST_SEG_SIG_MAGIC);
+ tg3_ape_write32(tp, TG3_APE_HOST_SEG_LEN,
+ APE_HOST_SEG_LEN_MAGIC);
+ apedata = tg3_ape_read32(tp, TG3_APE_HOST_INIT_COUNT);
+ tg3_ape_write32(tp, TG3_APE_HOST_INIT_COUNT, ++apedata);
+ tg3_ape_write32(tp, TG3_APE_HOST_DRIVER_ID,
+ APE_HOST_DRIVER_ID_MAGIC(TG3_MAJ_NUM, TG3_MIN_NUM));
+ tg3_ape_write32(tp, TG3_APE_HOST_BEHAVIOR,
+ APE_HOST_BEHAV_NO_PHYLOCK);
+ tg3_ape_write32(tp, TG3_APE_HOST_DRVR_STATE,
+ TG3_APE_HOST_DRVR_STATE_START);
+
+ event = APE_EVENT_STATUS_STATE_START;
+ break;
+ case RESET_KIND_SHUTDOWN:
+ /* With the interface we are currently using,
+ * APE does not track driver state. Wiping
+ * out the HOST SEGMENT SIGNATURE forces
+ * the APE to assume OS absent status.
+ */
+ tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG, 0x0);
+
+ if (device_may_wakeup(&tp->pdev->dev) &&
+ tg3_flag(tp, WOL_ENABLE)) {
+ tg3_ape_write32(tp, TG3_APE_HOST_WOL_SPEED,
+ TG3_APE_HOST_WOL_SPEED_AUTO);
+ apedata = TG3_APE_HOST_DRVR_STATE_WOL;
+ } else
+ apedata = TG3_APE_HOST_DRVR_STATE_UNLOAD;
+
+ tg3_ape_write32(tp, TG3_APE_HOST_DRVR_STATE, apedata);
+
+ event = APE_EVENT_STATUS_STATE_UNLOAD;
+ break;
+ case RESET_KIND_SUSPEND:
+ event = APE_EVENT_STATUS_STATE_SUSPEND;
+ break;
+ default:
+ return;
+ }
+
+ event |= APE_EVENT_STATUS_DRIVER_EVNT | APE_EVENT_STATUS_STATE_CHNGE;
+
+ tg3_ape_send_event(tp, event);
+}
+
static void tg3_disable_ints(struct tg3 *tp)
{
int i;
@@ -1389,6 +1497,149 @@ static void tg3_ump_link_report(struct tg3 *tp)
tg3_generate_fw_event(tp);
}
+/* tp->lock is held. */
+static void tg3_stop_fw(struct tg3 *tp)
+{
+ if (tg3_flag(tp, ENABLE_ASF) && !tg3_flag(tp, ENABLE_APE)) {
+ /* Wait for RX cpu to ACK the previous event. */
+ tg3_wait_for_event_ack(tp);
+
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_PAUSE_FW);
+
+ tg3_generate_fw_event(tp);
+
+ /* Wait for RX cpu to ACK this event. */
+ tg3_wait_for_event_ack(tp);
+ }
+}
+
+/* tp->lock is held. */
+static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
+{
+ tg3_write_mem(tp, NIC_SRAM_FIRMWARE_MBOX,
+ NIC_SRAM_FIRMWARE_MBOX_MAGIC1);
+
+ if (tg3_flag(tp, ASF_NEW_HANDSHAKE)) {
+ switch (kind) {
+ case RESET_KIND_INIT:
+ tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
+ DRV_STATE_START);
+ break;
+
+ case RESET_KIND_SHUTDOWN:
+ tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
+ DRV_STATE_UNLOAD);
+ break;
+
+ case RESET_KIND_SUSPEND:
+ tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
+ DRV_STATE_SUSPEND);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (kind == RESET_KIND_INIT ||
+ kind == RESET_KIND_SUSPEND)
+ tg3_ape_driver_state_change(tp, kind);
+}
+
+/* tp->lock is held. */
+static void tg3_write_sig_post_reset(struct tg3 *tp, int kind)
+{
+ if (tg3_flag(tp, ASF_NEW_HANDSHAKE)) {
+ switch (kind) {
+ case RESET_KIND_INIT:
+ tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
+ DRV_STATE_START_DONE);
+ break;
+
+ case RESET_KIND_SHUTDOWN:
+ tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
+ DRV_STATE_UNLOAD_DONE);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (kind == RESET_KIND_SHUTDOWN)
+ tg3_ape_driver_state_change(tp, kind);
+}
+
+/* tp->lock is held. */
+static void tg3_write_sig_legacy(struct tg3 *tp, int kind)
+{
+ if (tg3_flag(tp, ENABLE_ASF)) {
+ switch (kind) {
+ case RESET_KIND_INIT:
+ tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
+ DRV_STATE_START);
+ break;
+
+ case RESET_KIND_SHUTDOWN:
+ tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
+ DRV_STATE_UNLOAD);
+ break;
+
+ case RESET_KIND_SUSPEND:
+ tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
+ DRV_STATE_SUSPEND);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+static int tg3_poll_fw(struct tg3 *tp)
+{
+ int i;
+ u32 val;
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ /* Wait up to 20ms for init done. */
+ for (i = 0; i < 200; i++) {
+ if (tr32(VCPU_STATUS) & VCPU_STATUS_INIT_DONE)
+ return 0;
+ udelay(100);
+ }
+ return -ENODEV;
+ }
+
+ /* Wait for firmware initialization to complete. */
+ for (i = 0; i < 100000; i++) {
+ tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
+ if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
+ break;
+ udelay(10);
+ }
+
+ /* Chip might not be fitted with firmware. Some Sun onboard
+ * parts are configured like that. So don't signal the timeout
+ * of the above loop as an error, but do report the lack of
+ * running firmware once.
+ */
+ if (i >= 100000 && !tg3_flag(tp, NO_FWARE_REPORTED)) {
+ tg3_flag_set(tp, NO_FWARE_REPORTED);
+
+ netdev_info(tp->dev, "No firmware running\n");
+ }
+
+ if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0) {
+ /* The 57765 A0 needs a little more
+ * time to do some important work.
+ */
+ mdelay(10);
+ }
+
+ return 0;
+}
+
static void tg3_link_report(struct tg3 *tp)
{
if (!netif_carrier_ok(tp->dev)) {
@@ -1680,6 +1931,36 @@ static void tg3_phy_fini(struct tg3 *tp)
}
}
+static int tg3_phy_set_extloopbk(struct tg3 *tp)
+{
+ int err;
+ u32 val;
+
+ if (tp->phy_flags & TG3_PHYFLG_IS_FET)
+ return 0;
+
+ if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5401) {
+ /* Cannot do read-modify-write on 5401 */
+ err = tg3_phy_auxctl_write(tp,
+ MII_TG3_AUXCTL_SHDWSEL_AUXCTL,
+ MII_TG3_AUXCTL_ACTL_EXTLOOPBK |
+ 0x4c20);
+ goto done;
+ }
+
+ err = tg3_phy_auxctl_read(tp,
+ MII_TG3_AUXCTL_SHDWSEL_AUXCTL, &val);
+ if (err)
+ return err;
+
+ val |= MII_TG3_AUXCTL_ACTL_EXTLOOPBK;
+ err = tg3_phy_auxctl_write(tp,
+ MII_TG3_AUXCTL_SHDWSEL_AUXCTL, val);
+
+done:
+ return err;
+}
+
static void tg3_phy_fet_toggle_apd(struct tg3 *tp, bool enable)
{
u32 phytest;
@@ -2450,12 +2731,6 @@ static int tg3_5700_link_polarity(struct tg3 *tp, u32 speed)
}
static int tg3_setup_phy(struct tg3 *, int);
-
-#define RESET_KIND_SHUTDOWN 0
-#define RESET_KIND_INIT 1
-#define RESET_KIND_SUSPEND 2
-
-static void tg3_write_sig_post_reset(struct tg3 *, int);
static int tg3_halt_cpu(struct tg3 *, u32);
static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power)
@@ -2724,6 +2999,228 @@ static int tg3_nvram_read_be32(struct tg3 *tp, u32 offset, __be32 *val)
return res;
}
+#define RX_CPU_SCRATCH_BASE 0x30000
+#define RX_CPU_SCRATCH_SIZE 0x04000
+#define TX_CPU_SCRATCH_BASE 0x34000
+#define TX_CPU_SCRATCH_SIZE 0x04000
+
+/* tp->lock is held. */
+static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
+{
+ int i;
+
+ BUG_ON(offset == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS));
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ u32 val = tr32(GRC_VCPU_EXT_CTRL);
+
+ tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_HALT_CPU);
+ return 0;
+ }
+ if (offset == RX_CPU_BASE) {
+ for (i = 0; i < 10000; i++) {
+ tw32(offset + CPU_STATE, 0xffffffff);
+ tw32(offset + CPU_MODE, CPU_MODE_HALT);
+ if (tr32(offset + CPU_MODE) & CPU_MODE_HALT)
+ break;
+ }
+
+ tw32(offset + CPU_STATE, 0xffffffff);
+ tw32_f(offset + CPU_MODE, CPU_MODE_HALT);
+ udelay(10);
+ } else {
+ for (i = 0; i < 10000; i++) {
+ tw32(offset + CPU_STATE, 0xffffffff);
+ tw32(offset + CPU_MODE, CPU_MODE_HALT);
+ if (tr32(offset + CPU_MODE) & CPU_MODE_HALT)
+ break;
+ }
+ }
+
+ if (i >= 10000) {
+ netdev_err(tp->dev, "%s timed out, %s CPU\n",
+ __func__, offset == RX_CPU_BASE ? "RX" : "TX");
+ return -ENODEV;
+ }
+
+ /* Clear firmware's nvram arbitration. */
+ if (tg3_flag(tp, NVRAM))
+ tw32(NVRAM_SWARB, SWARB_REQ_CLR0);
+ return 0;
+}
+
+struct fw_info {
+ unsigned int fw_base;
+ unsigned int fw_len;
+ const __be32 *fw_data;
+};
+
+/* tp->lock is held. */
+static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base,
+ u32 cpu_scratch_base, int cpu_scratch_size,
+ struct fw_info *info)
+{
+ int err, lock_err, i;
+ void (*write_op)(struct tg3 *, u32, u32);
+
+ if (cpu_base == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS)) {
+ netdev_err(tp->dev,
+ "%s: Trying to load TX cpu firmware which is 5705\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (tg3_flag(tp, 5705_PLUS))
+ write_op = tg3_write_mem;
+ else
+ write_op = tg3_write_indirect_reg32;
+
+ /* It is possible that bootcode is still loading at this point.
+ * Get the nvram lock first before halting the cpu.
+ */
+ lock_err = tg3_nvram_lock(tp);
+ err = tg3_halt_cpu(tp, cpu_base);
+ if (!lock_err)
+ tg3_nvram_unlock(tp);
+ if (err)
+ goto out;
+
+ for (i = 0; i < cpu_scratch_size; i += sizeof(u32))
+ write_op(tp, cpu_scratch_base + i, 0);
+ tw32(cpu_base + CPU_STATE, 0xffffffff);
+ tw32(cpu_base + CPU_MODE, tr32(cpu_base+CPU_MODE)|CPU_MODE_HALT);
+ for (i = 0; i < (info->fw_len / sizeof(u32)); i++)
+ write_op(tp, (cpu_scratch_base +
+ (info->fw_base & 0xffff) +
+ (i * sizeof(u32))),
+ be32_to_cpu(info->fw_data[i]));
+
+ err = 0;
+
+out:
+ return err;
+}
+
+/* tp->lock is held. */
+static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
+{
+ struct fw_info info;
+ const __be32 *fw_data;
+ int err, i;
+
+ fw_data = (void *)tp->fw->data;
+
+ /* Firmware blob starts with version numbers, followed by
+ start address and length. We are setting complete length.
+ length = end_address_of_bss - start_address_of_text.
+ Remainder is the blob to be loaded contiguously
+ from start address. */
+
+ info.fw_base = be32_to_cpu(fw_data[1]);
+ info.fw_len = tp->fw->size - 12;
+ info.fw_data = &fw_data[3];
+
+ err = tg3_load_firmware_cpu(tp, RX_CPU_BASE,
+ RX_CPU_SCRATCH_BASE, RX_CPU_SCRATCH_SIZE,
+ &info);
+ if (err)
+ return err;
+
+ err = tg3_load_firmware_cpu(tp, TX_CPU_BASE,
+ TX_CPU_SCRATCH_BASE, TX_CPU_SCRATCH_SIZE,
+ &info);
+ if (err)
+ return err;
+
+ /* Now startup only the RX cpu. */
+ tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
+ tw32_f(RX_CPU_BASE + CPU_PC, info.fw_base);
+
+ for (i = 0; i < 5; i++) {
+ if (tr32(RX_CPU_BASE + CPU_PC) == info.fw_base)
+ break;
+ tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
+ tw32(RX_CPU_BASE + CPU_MODE, CPU_MODE_HALT);
+ tw32_f(RX_CPU_BASE + CPU_PC, info.fw_base);
+ udelay(1000);
+ }
+ if (i >= 5) {
+ netdev_err(tp->dev, "%s fails to set RX CPU PC, is %08x "
+ "should be %08x\n", __func__,
+ tr32(RX_CPU_BASE + CPU_PC), info.fw_base);
+ return -ENODEV;
+ }
+ tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
+ tw32_f(RX_CPU_BASE + CPU_MODE, 0x00000000);
+
+ return 0;
+}
+
+/* tp->lock is held. */
+static int tg3_load_tso_firmware(struct tg3 *tp)
+{
+ struct fw_info info;
+ const __be32 *fw_data;
+ unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size;
+ int err, i;
+
+ if (tg3_flag(tp, HW_TSO_1) ||
+ tg3_flag(tp, HW_TSO_2) ||
+ tg3_flag(tp, HW_TSO_3))
+ return 0;
+
+ fw_data = (void *)tp->fw->data;
+
+ /* Firmware blob starts with version numbers, followed by
+ start address and length. We are setting complete length.
+ length = end_address_of_bss - start_address_of_text.
+ Remainder is the blob to be loaded contiguously
+ from start address. */
+
+ info.fw_base = be32_to_cpu(fw_data[1]);
+ cpu_scratch_size = tp->fw_len;
+ info.fw_len = tp->fw->size - 12;
+ info.fw_data = &fw_data[3];
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+ cpu_base = RX_CPU_BASE;
+ cpu_scratch_base = NIC_SRAM_MBUF_POOL_BASE5705;
+ } else {
+ cpu_base = TX_CPU_BASE;
+ cpu_scratch_base = TX_CPU_SCRATCH_BASE;
+ cpu_scratch_size = TX_CPU_SCRATCH_SIZE;
+ }
+
+ err = tg3_load_firmware_cpu(tp, cpu_base,
+ cpu_scratch_base, cpu_scratch_size,
+ &info);
+ if (err)
+ return err;
+
+ /* Now startup the cpu. */
+ tw32(cpu_base + CPU_STATE, 0xffffffff);
+ tw32_f(cpu_base + CPU_PC, info.fw_base);
+
+ for (i = 0; i < 5; i++) {
+ if (tr32(cpu_base + CPU_PC) == info.fw_base)
+ break;
+ tw32(cpu_base + CPU_STATE, 0xffffffff);
+ tw32(cpu_base + CPU_MODE, CPU_MODE_HALT);
+ tw32_f(cpu_base + CPU_PC, info.fw_base);
+ udelay(1000);
+ }
+ if (i >= 5) {
+ netdev_err(tp->dev,
+ "%s fails to set CPU PC, is %08x should be %08x\n",
+ __func__, tr32(cpu_base + CPU_PC), info.fw_base);
+ return -ENODEV;
+ }
+ tw32(cpu_base + CPU_STATE, 0xffffffff);
+ tw32_f(cpu_base + CPU_MODE, 0x00000000);
+ return 0;
+}
+
+
/* tp->lock is held. */
static void __tg3_set_mac_addr(struct tg3 *tp, int skip_mac_1)
{
@@ -3303,8 +3800,9 @@ static int tg3_copper_is_advertising_all(struct tg3 *tp, u32 mask)
if (tg3_readphy(tp, MII_ADVERTISE, &adv_reg))
return 0;
- if ((adv_reg & all_mask) != all_mask)
+ if ((adv_reg & ADVERTISE_ALL) != all_mask)
return 0;
+
if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) {
u32 tg3_ctrl;
@@ -3317,9 +3815,11 @@ static int tg3_copper_is_advertising_all(struct tg3 *tp, u32 mask)
if (tg3_readphy(tp, MII_CTRL1000, &tg3_ctrl))
return 0;
- if ((tg3_ctrl & all_mask) != all_mask)
+ tg3_ctrl &= (ADVERTISE_1000HALF | ADVERTISE_1000FULL);
+ if (tg3_ctrl != all_mask)
return 0;
}
+
return 1;
}
@@ -3620,8 +4120,8 @@ relink:
newlnkctl = oldlnkctl | PCI_EXP_LNKCTL_CLKREQ_EN;
if (newlnkctl != oldlnkctl)
pci_write_config_word(tp->pdev,
- pci_pcie_cap(tp->pdev) + PCI_EXP_LNKCTL,
- newlnkctl);
+ pci_pcie_cap(tp->pdev) +
+ PCI_EXP_LNKCTL, newlnkctl);
}
if (current_link_up != netif_carrier_ok(tp->dev)) {
@@ -4856,7 +5356,7 @@ static void tg3_tx(struct tg3_napi *tnapi)
pci_unmap_page(tp->pdev,
dma_unmap_addr(ri, mapping),
- skb_shinfo(skb)->frags[i].size,
+ skb_frag_size(&skb_shinfo(skb)->frags[i]),
PCI_DMA_TODEVICE);
while (ri->fragmented) {
@@ -4951,11 +5451,11 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, struct tg3_rx_prodring_set *tpr,
* Callers depend upon this behavior and assume that
* we leave everything unchanged if we fail.
*/
- skb = netdev_alloc_skb(tp->dev, skb_size + tp->rx_offset);
+ skb = netdev_alloc_skb(tp->dev, skb_size + TG3_RX_OFFSET(tp));
if (skb == NULL)
return -ENOMEM;
- skb_reserve(skb, tp->rx_offset);
+ skb_reserve(skb, TG3_RX_OFFSET(tp));
mapping = pci_map_single(tp->pdev, skb->data, skb_size,
PCI_DMA_FROMDEVICE);
@@ -5673,7 +6173,7 @@ static irqreturn_t tg3_msi(int irq, void *dev_id)
* NIC to stop sending us irqs, engaging "in-intr-handler"
* event coalescing.
*/
- tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
+ tw32_mailbox(tnapi->int_mbox, 0x00000001);
if (likely(!tg3_irq_sync(tp)))
napi_schedule(&tnapi->napi);
@@ -6010,14 +6510,14 @@ static void tg3_tx_skb_unmap(struct tg3_napi *tnapi, u32 entry, int last)
}
for (i = 0; i < last; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
entry = NEXT_TX(entry);
txb = &tnapi->tx_buffers[entry];
pci_unmap_page(tnapi->tp->pdev,
dma_unmap_addr(txb, mapping),
- frag->size, PCI_DMA_TODEVICE);
+ skb_frag_size(frag), PCI_DMA_TODEVICE);
while (txb->fragmented) {
txb->fragmented = false;
@@ -6029,12 +6529,12 @@ static void tg3_tx_skb_unmap(struct tg3_napi *tnapi, u32 entry, int last)
/* Workaround 4GB and 40-bit hardware DMA bugs. */
static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi,
- struct sk_buff *skb,
+ struct sk_buff **pskb,
u32 *entry, u32 *budget,
u32 base_flags, u32 mss, u32 vlan)
{
struct tg3 *tp = tnapi->tp;
- struct sk_buff *new_skb;
+ struct sk_buff *new_skb, *skb = *pskb;
dma_addr_t new_addr = 0;
int ret = 0;
@@ -6076,7 +6576,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi,
}
dev_kfree_skb(skb);
-
+ *pskb = new_skb;
return ret;
}
@@ -6171,10 +6671,8 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
u32 tcp_opt_len, hdr_len;
if (skb_header_cloned(skb) &&
- pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
- dev_kfree_skb(skb);
- goto out_unlock;
- }
+ pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ goto drop;
iph = ip_hdr(skb);
tcp_opt_len = tcp_optlen(skb);
@@ -6234,24 +6732,21 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
}
-#ifdef BCM_KERNEL_SUPPORTS_8021Q
+ if (tg3_flag(tp, USE_JUMBO_BDFLAG) &&
+ !mss && skb->len > VLAN_ETH_FRAME_LEN)
+ base_flags |= TXD_FLAG_JMB_PKT;
+
if (vlan_tx_tag_present(skb)) {
base_flags |= TXD_FLAG_VLAN;
vlan = vlan_tx_tag_get(skb);
}
-#endif
-
- if (tg3_flag(tp, USE_JUMBO_BDFLAG) &&
- !mss && skb->len > VLAN_ETH_FRAME_LEN)
- base_flags |= TXD_FLAG_JMB_PKT;
len = skb_headlen(skb);
mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(tp->pdev, mapping)) {
- dev_kfree_skb(skb);
- goto out_unlock;
- }
+ if (pci_dma_mapping_error(tp->pdev, mapping))
+ goto drop;
+
tnapi->tx_buffers[entry].skb = skb;
dma_unmap_addr_set(&tnapi->tx_buffers[entry], mapping, mapping);
@@ -6279,16 +6774,14 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
for (i = 0; i <= last; i++) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- len = frag->size;
- mapping = pci_map_page(tp->pdev,
- frag->page,
- frag->page_offset,
- len, PCI_DMA_TODEVICE);
+ len = skb_frag_size(frag);
+ mapping = skb_frag_dma_map(&tp->pdev->dev, frag, 0,
+ len, DMA_TO_DEVICE);
tnapi->tx_buffers[entry].skb = NULL;
dma_unmap_addr_set(&tnapi->tx_buffers[entry], mapping,
mapping);
- if (pci_dma_mapping_error(tp->pdev, mapping))
+ if (dma_mapping_error(&tp->pdev->dev, mapping))
goto dma_error;
if (tg3_tx_frag_set(tnapi, &entry, &budget, mapping,
@@ -6307,9 +6800,9 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
entry = tnapi->tx_prod;
budget = tg3_tx_avail(tnapi);
- if (tigon3_dma_hwbug_workaround(tnapi, skb, &entry, &budget,
+ if (tigon3_dma_hwbug_workaround(tnapi, &skb, &entry, &budget,
base_flags, mss, vlan))
- goto out_unlock;
+ goto drop_nofree;
}
skb_tx_timestamp(skb);
@@ -6331,18 +6824,140 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_tx_wake_queue(txq);
}
-out_unlock:
mmiowb();
-
return NETDEV_TX_OK;
dma_error:
tg3_tx_skb_unmap(tnapi, tnapi->tx_prod, i);
- dev_kfree_skb(skb);
tnapi->tx_buffers[tnapi->tx_prod].skb = NULL;
+drop:
+ dev_kfree_skb(skb);
+drop_nofree:
+ tp->tx_dropped++;
return NETDEV_TX_OK;
}
+static void tg3_mac_loopback(struct tg3 *tp, bool enable)
+{
+ if (enable) {
+ tp->mac_mode &= ~(MAC_MODE_HALF_DUPLEX |
+ MAC_MODE_PORT_MODE_MASK);
+
+ tp->mac_mode |= MAC_MODE_PORT_INT_LPBACK;
+
+ if (!tg3_flag(tp, 5705_PLUS))
+ tp->mac_mode |= MAC_MODE_LINK_POLARITY;
+
+ if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
+ tp->mac_mode |= MAC_MODE_PORT_MODE_MII;
+ else
+ tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
+ } else {
+ tp->mac_mode &= ~MAC_MODE_PORT_INT_LPBACK;
+
+ if (tg3_flag(tp, 5705_PLUS) ||
+ (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700)
+ tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
+ }
+
+ tw32(MAC_MODE, tp->mac_mode);
+ udelay(40);
+}
+
+static int tg3_phy_lpbk_set(struct tg3 *tp, u32 speed, bool extlpbk)
+{
+ u32 val, bmcr, mac_mode, ptest = 0;
+
+ tg3_phy_toggle_apd(tp, false);
+ tg3_phy_toggle_automdix(tp, 0);
+
+ if (extlpbk && tg3_phy_set_extloopbk(tp))
+ return -EIO;
+
+ bmcr = BMCR_FULLDPLX;
+ switch (speed) {
+ case SPEED_10:
+ break;
+ case SPEED_100:
+ bmcr |= BMCR_SPEED100;
+ break;
+ case SPEED_1000:
+ default:
+ if (tp->phy_flags & TG3_PHYFLG_IS_FET) {
+ speed = SPEED_100;
+ bmcr |= BMCR_SPEED100;
+ } else {
+ speed = SPEED_1000;
+ bmcr |= BMCR_SPEED1000;
+ }
+ }
+
+ if (extlpbk) {
+ if (!(tp->phy_flags & TG3_PHYFLG_IS_FET)) {
+ tg3_readphy(tp, MII_CTRL1000, &val);
+ val |= CTL1000_AS_MASTER |
+ CTL1000_ENABLE_MASTER;
+ tg3_writephy(tp, MII_CTRL1000, val);
+ } else {
+ ptest = MII_TG3_FET_PTEST_TRIM_SEL |
+ MII_TG3_FET_PTEST_TRIM_2;
+ tg3_writephy(tp, MII_TG3_FET_PTEST, ptest);
+ }
+ } else
+ bmcr |= BMCR_LOOPBACK;
+
+ tg3_writephy(tp, MII_BMCR, bmcr);
+
+ /* The write needs to be flushed for the FETs */
+ if (tp->phy_flags & TG3_PHYFLG_IS_FET)
+ tg3_readphy(tp, MII_BMCR, &bmcr);
+
+ udelay(40);
+
+ if ((tp->phy_flags & TG3_PHYFLG_IS_FET) &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
+ tg3_writephy(tp, MII_TG3_FET_PTEST, ptest |
+ MII_TG3_FET_PTEST_FRC_TX_LINK |
+ MII_TG3_FET_PTEST_FRC_TX_LOCK);
+
+ /* The write needs to be flushed for the AC131 */
+ tg3_readphy(tp, MII_TG3_FET_PTEST, &val);
+ }
+
+ /* Reset to prevent losing 1st rx packet intermittently */
+ if ((tp->phy_flags & TG3_PHYFLG_MII_SERDES) &&
+ tg3_flag(tp, 5780_CLASS)) {
+ tw32_f(MAC_RX_MODE, RX_MODE_RESET);
+ udelay(10);
+ tw32_f(MAC_RX_MODE, tp->rx_mode);
+ }
+
+ mac_mode = tp->mac_mode &
+ ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX);
+ if (speed == SPEED_1000)
+ mac_mode |= MAC_MODE_PORT_MODE_GMII;
+ else
+ mac_mode |= MAC_MODE_PORT_MODE_MII;
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) {
+ u32 masked_phy_id = tp->phy_id & TG3_PHY_ID_MASK;
+
+ if (masked_phy_id == TG3_PHY_ID_BCM5401)
+ mac_mode &= ~MAC_MODE_LINK_POLARITY;
+ else if (masked_phy_id == TG3_PHY_ID_BCM5411)
+ mac_mode |= MAC_MODE_LINK_POLARITY;
+
+ tg3_writephy(tp, MII_TG3_EXT_CTRL,
+ MII_TG3_EXT_CTRL_LNK3_LED_MODE);
+ }
+
+ tw32(MAC_MODE, mac_mode);
+ udelay(40);
+
+ return 0;
+}
+
static void tg3_set_loopback(struct net_device *dev, u32 features)
{
struct tg3 *tp = netdev_priv(dev);
@@ -6351,16 +6966,8 @@ static void tg3_set_loopback(struct net_device *dev, u32 features)
if (tp->mac_mode & MAC_MODE_PORT_INT_LPBACK)
return;
- /*
- * Clear MAC_MODE_HALF_DUPLEX or you won't get packets back in
- * loopback mode if Half-Duplex mode was negotiated earlier.
- */
- tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX;
-
- /* Enable internal MAC loopback mode */
- tp->mac_mode |= MAC_MODE_PORT_INT_LPBACK;
spin_lock_bh(&tp->lock);
- tw32(MAC_MODE, tp->mac_mode);
+ tg3_mac_loopback(tp, true);
netif_carrier_on(tp->dev);
spin_unlock_bh(&tp->lock);
netdev_info(dev, "Internal MAC loopback mode enabled.\n");
@@ -6368,10 +6975,8 @@ static void tg3_set_loopback(struct net_device *dev, u32 features)
if (!(tp->mac_mode & MAC_MODE_PORT_INT_LPBACK))
return;
- /* Disable internal MAC loopback mode */
- tp->mac_mode &= ~MAC_MODE_PORT_INT_LPBACK;
spin_lock_bh(&tp->lock);
- tw32(MAC_MODE, tp->mac_mode);
+ tg3_mac_loopback(tp, false);
/* Force link status check */
tg3_setup_phy(tp, 1);
spin_unlock_bh(&tp->lock);
@@ -6981,230 +7586,6 @@ static int tg3_abort_hw(struct tg3 *tp, int silent)
return err;
}
-static void tg3_ape_send_event(struct tg3 *tp, u32 event)
-{
- int i;
- u32 apedata;
-
- /* NCSI does not support APE events */
- if (tg3_flag(tp, APE_HAS_NCSI))
- return;
-
- apedata = tg3_ape_read32(tp, TG3_APE_SEG_SIG);
- if (apedata != APE_SEG_SIG_MAGIC)
- return;
-
- apedata = tg3_ape_read32(tp, TG3_APE_FW_STATUS);
- if (!(apedata & APE_FW_STATUS_READY))
- return;
-
- /* Wait for up to 1 millisecond for APE to service previous event. */
- for (i = 0; i < 10; i++) {
- if (tg3_ape_lock(tp, TG3_APE_LOCK_MEM))
- return;
-
- apedata = tg3_ape_read32(tp, TG3_APE_EVENT_STATUS);
-
- if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
- tg3_ape_write32(tp, TG3_APE_EVENT_STATUS,
- event | APE_EVENT_STATUS_EVENT_PENDING);
-
- tg3_ape_unlock(tp, TG3_APE_LOCK_MEM);
-
- if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
- break;
-
- udelay(100);
- }
-
- if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
- tg3_ape_write32(tp, TG3_APE_EVENT, APE_EVENT_1);
-}
-
-static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
-{
- u32 event;
- u32 apedata;
-
- if (!tg3_flag(tp, ENABLE_APE))
- return;
-
- switch (kind) {
- case RESET_KIND_INIT:
- tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG,
- APE_HOST_SEG_SIG_MAGIC);
- tg3_ape_write32(tp, TG3_APE_HOST_SEG_LEN,
- APE_HOST_SEG_LEN_MAGIC);
- apedata = tg3_ape_read32(tp, TG3_APE_HOST_INIT_COUNT);
- tg3_ape_write32(tp, TG3_APE_HOST_INIT_COUNT, ++apedata);
- tg3_ape_write32(tp, TG3_APE_HOST_DRIVER_ID,
- APE_HOST_DRIVER_ID_MAGIC(TG3_MAJ_NUM, TG3_MIN_NUM));
- tg3_ape_write32(tp, TG3_APE_HOST_BEHAVIOR,
- APE_HOST_BEHAV_NO_PHYLOCK);
- tg3_ape_write32(tp, TG3_APE_HOST_DRVR_STATE,
- TG3_APE_HOST_DRVR_STATE_START);
-
- event = APE_EVENT_STATUS_STATE_START;
- break;
- case RESET_KIND_SHUTDOWN:
- /* With the interface we are currently using,
- * APE does not track driver state. Wiping
- * out the HOST SEGMENT SIGNATURE forces
- * the APE to assume OS absent status.
- */
- tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG, 0x0);
-
- if (device_may_wakeup(&tp->pdev->dev) &&
- tg3_flag(tp, WOL_ENABLE)) {
- tg3_ape_write32(tp, TG3_APE_HOST_WOL_SPEED,
- TG3_APE_HOST_WOL_SPEED_AUTO);
- apedata = TG3_APE_HOST_DRVR_STATE_WOL;
- } else
- apedata = TG3_APE_HOST_DRVR_STATE_UNLOAD;
-
- tg3_ape_write32(tp, TG3_APE_HOST_DRVR_STATE, apedata);
-
- event = APE_EVENT_STATUS_STATE_UNLOAD;
- break;
- case RESET_KIND_SUSPEND:
- event = APE_EVENT_STATUS_STATE_SUSPEND;
- break;
- default:
- return;
- }
-
- event |= APE_EVENT_STATUS_DRIVER_EVNT | APE_EVENT_STATUS_STATE_CHNGE;
-
- tg3_ape_send_event(tp, event);
-}
-
-/* tp->lock is held. */
-static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
-{
- tg3_write_mem(tp, NIC_SRAM_FIRMWARE_MBOX,
- NIC_SRAM_FIRMWARE_MBOX_MAGIC1);
-
- if (tg3_flag(tp, ASF_NEW_HANDSHAKE)) {
- switch (kind) {
- case RESET_KIND_INIT:
- tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
- DRV_STATE_START);
- break;
-
- case RESET_KIND_SHUTDOWN:
- tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
- DRV_STATE_UNLOAD);
- break;
-
- case RESET_KIND_SUSPEND:
- tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
- DRV_STATE_SUSPEND);
- break;
-
- default:
- break;
- }
- }
-
- if (kind == RESET_KIND_INIT ||
- kind == RESET_KIND_SUSPEND)
- tg3_ape_driver_state_change(tp, kind);
-}
-
-/* tp->lock is held. */
-static void tg3_write_sig_post_reset(struct tg3 *tp, int kind)
-{
- if (tg3_flag(tp, ASF_NEW_HANDSHAKE)) {
- switch (kind) {
- case RESET_KIND_INIT:
- tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
- DRV_STATE_START_DONE);
- break;
-
- case RESET_KIND_SHUTDOWN:
- tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
- DRV_STATE_UNLOAD_DONE);
- break;
-
- default:
- break;
- }
- }
-
- if (kind == RESET_KIND_SHUTDOWN)
- tg3_ape_driver_state_change(tp, kind);
-}
-
-/* tp->lock is held. */
-static void tg3_write_sig_legacy(struct tg3 *tp, int kind)
-{
- if (tg3_flag(tp, ENABLE_ASF)) {
- switch (kind) {
- case RESET_KIND_INIT:
- tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
- DRV_STATE_START);
- break;
-
- case RESET_KIND_SHUTDOWN:
- tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
- DRV_STATE_UNLOAD);
- break;
-
- case RESET_KIND_SUSPEND:
- tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
- DRV_STATE_SUSPEND);
- break;
-
- default:
- break;
- }
- }
-}
-
-static int tg3_poll_fw(struct tg3 *tp)
-{
- int i;
- u32 val;
-
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
- /* Wait up to 20ms for init done. */
- for (i = 0; i < 200; i++) {
- if (tr32(VCPU_STATUS) & VCPU_STATUS_INIT_DONE)
- return 0;
- udelay(100);
- }
- return -ENODEV;
- }
-
- /* Wait for firmware initialization to complete. */
- for (i = 0; i < 100000; i++) {
- tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
- if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
- break;
- udelay(10);
- }
-
- /* Chip might not be fitted with firmware. Some Sun onboard
- * parts are configured like that. So don't signal the timeout
- * of the above loop as an error, but do report the lack of
- * running firmware once.
- */
- if (i >= 100000 && !tg3_flag(tp, NO_FWARE_REPORTED)) {
- tg3_flag_set(tp, NO_FWARE_REPORTED);
-
- netdev_info(tp->dev, "No firmware running\n");
- }
-
- if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0) {
- /* The 57765 A0 needs a little more
- * time to do some important work.
- */
- mdelay(10);
- }
-
- return 0;
-}
-
/* Save PCI command register before chip reset */
static void tg3_save_pci_state(struct tg3 *tp)
{
@@ -7276,8 +7657,6 @@ static void tg3_restore_pci_state(struct tg3 *tp)
}
}
-static void tg3_stop_fw(struct tg3 *);
-
/* tp->lock is held. */
static int tg3_chip_reset(struct tg3 *tp)
{
@@ -7525,22 +7904,6 @@ static int tg3_chip_reset(struct tg3 *tp)
}
/* tp->lock is held. */
-static void tg3_stop_fw(struct tg3 *tp)
-{
- if (tg3_flag(tp, ENABLE_ASF) && !tg3_flag(tp, ENABLE_APE)) {
- /* Wait for RX cpu to ACK the previous event. */
- tg3_wait_for_event_ack(tp);
-
- tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_PAUSE_FW);
-
- tg3_generate_fw_event(tp);
-
- /* Wait for RX cpu to ACK this event. */
- tg3_wait_for_event_ack(tp);
- }
-}
-
-/* tp->lock is held. */
static int tg3_halt(struct tg3 *tp, int kind, int silent)
{
int err;
@@ -7563,227 +7926,6 @@ static int tg3_halt(struct tg3 *tp, int kind, int silent)
return 0;
}
-#define RX_CPU_SCRATCH_BASE 0x30000
-#define RX_CPU_SCRATCH_SIZE 0x04000
-#define TX_CPU_SCRATCH_BASE 0x34000
-#define TX_CPU_SCRATCH_SIZE 0x04000
-
-/* tp->lock is held. */
-static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
-{
- int i;
-
- BUG_ON(offset == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS));
-
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
- u32 val = tr32(GRC_VCPU_EXT_CTRL);
-
- tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_HALT_CPU);
- return 0;
- }
- if (offset == RX_CPU_BASE) {
- for (i = 0; i < 10000; i++) {
- tw32(offset + CPU_STATE, 0xffffffff);
- tw32(offset + CPU_MODE, CPU_MODE_HALT);
- if (tr32(offset + CPU_MODE) & CPU_MODE_HALT)
- break;
- }
-
- tw32(offset + CPU_STATE, 0xffffffff);
- tw32_f(offset + CPU_MODE, CPU_MODE_HALT);
- udelay(10);
- } else {
- for (i = 0; i < 10000; i++) {
- tw32(offset + CPU_STATE, 0xffffffff);
- tw32(offset + CPU_MODE, CPU_MODE_HALT);
- if (tr32(offset + CPU_MODE) & CPU_MODE_HALT)
- break;
- }
- }
-
- if (i >= 10000) {
- netdev_err(tp->dev, "%s timed out, %s CPU\n",
- __func__, offset == RX_CPU_BASE ? "RX" : "TX");
- return -ENODEV;
- }
-
- /* Clear firmware's nvram arbitration. */
- if (tg3_flag(tp, NVRAM))
- tw32(NVRAM_SWARB, SWARB_REQ_CLR0);
- return 0;
-}
-
-struct fw_info {
- unsigned int fw_base;
- unsigned int fw_len;
- const __be32 *fw_data;
-};
-
-/* tp->lock is held. */
-static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_base,
- int cpu_scratch_size, struct fw_info *info)
-{
- int err, lock_err, i;
- void (*write_op)(struct tg3 *, u32, u32);
-
- if (cpu_base == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS)) {
- netdev_err(tp->dev,
- "%s: Trying to load TX cpu firmware which is 5705\n",
- __func__);
- return -EINVAL;
- }
-
- if (tg3_flag(tp, 5705_PLUS))
- write_op = tg3_write_mem;
- else
- write_op = tg3_write_indirect_reg32;
-
- /* It is possible that bootcode is still loading at this point.
- * Get the nvram lock first before halting the cpu.
- */
- lock_err = tg3_nvram_lock(tp);
- err = tg3_halt_cpu(tp, cpu_base);
- if (!lock_err)
- tg3_nvram_unlock(tp);
- if (err)
- goto out;
-
- for (i = 0; i < cpu_scratch_size; i += sizeof(u32))
- write_op(tp, cpu_scratch_base + i, 0);
- tw32(cpu_base + CPU_STATE, 0xffffffff);
- tw32(cpu_base + CPU_MODE, tr32(cpu_base+CPU_MODE)|CPU_MODE_HALT);
- for (i = 0; i < (info->fw_len / sizeof(u32)); i++)
- write_op(tp, (cpu_scratch_base +
- (info->fw_base & 0xffff) +
- (i * sizeof(u32))),
- be32_to_cpu(info->fw_data[i]));
-
- err = 0;
-
-out:
- return err;
-}
-
-/* tp->lock is held. */
-static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
-{
- struct fw_info info;
- const __be32 *fw_data;
- int err, i;
-
- fw_data = (void *)tp->fw->data;
-
- /* Firmware blob starts with version numbers, followed by
- start address and length. We are setting complete length.
- length = end_address_of_bss - start_address_of_text.
- Remainder is the blob to be loaded contiguously
- from start address. */
-
- info.fw_base = be32_to_cpu(fw_data[1]);
- info.fw_len = tp->fw->size - 12;
- info.fw_data = &fw_data[3];
-
- err = tg3_load_firmware_cpu(tp, RX_CPU_BASE,
- RX_CPU_SCRATCH_BASE, RX_CPU_SCRATCH_SIZE,
- &info);
- if (err)
- return err;
-
- err = tg3_load_firmware_cpu(tp, TX_CPU_BASE,
- TX_CPU_SCRATCH_BASE, TX_CPU_SCRATCH_SIZE,
- &info);
- if (err)
- return err;
-
- /* Now startup only the RX cpu. */
- tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
- tw32_f(RX_CPU_BASE + CPU_PC, info.fw_base);
-
- for (i = 0; i < 5; i++) {
- if (tr32(RX_CPU_BASE + CPU_PC) == info.fw_base)
- break;
- tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
- tw32(RX_CPU_BASE + CPU_MODE, CPU_MODE_HALT);
- tw32_f(RX_CPU_BASE + CPU_PC, info.fw_base);
- udelay(1000);
- }
- if (i >= 5) {
- netdev_err(tp->dev, "%s fails to set RX CPU PC, is %08x "
- "should be %08x\n", __func__,
- tr32(RX_CPU_BASE + CPU_PC), info.fw_base);
- return -ENODEV;
- }
- tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
- tw32_f(RX_CPU_BASE + CPU_MODE, 0x00000000);
-
- return 0;
-}
-
-/* tp->lock is held. */
-static int tg3_load_tso_firmware(struct tg3 *tp)
-{
- struct fw_info info;
- const __be32 *fw_data;
- unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size;
- int err, i;
-
- if (tg3_flag(tp, HW_TSO_1) ||
- tg3_flag(tp, HW_TSO_2) ||
- tg3_flag(tp, HW_TSO_3))
- return 0;
-
- fw_data = (void *)tp->fw->data;
-
- /* Firmware blob starts with version numbers, followed by
- start address and length. We are setting complete length.
- length = end_address_of_bss - start_address_of_text.
- Remainder is the blob to be loaded contiguously
- from start address. */
-
- info.fw_base = be32_to_cpu(fw_data[1]);
- cpu_scratch_size = tp->fw_len;
- info.fw_len = tp->fw->size - 12;
- info.fw_data = &fw_data[3];
-
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
- cpu_base = RX_CPU_BASE;
- cpu_scratch_base = NIC_SRAM_MBUF_POOL_BASE5705;
- } else {
- cpu_base = TX_CPU_BASE;
- cpu_scratch_base = TX_CPU_SCRATCH_BASE;
- cpu_scratch_size = TX_CPU_SCRATCH_SIZE;
- }
-
- err = tg3_load_firmware_cpu(tp, cpu_base,
- cpu_scratch_base, cpu_scratch_size,
- &info);
- if (err)
- return err;
-
- /* Now startup the cpu. */
- tw32(cpu_base + CPU_STATE, 0xffffffff);
- tw32_f(cpu_base + CPU_PC, info.fw_base);
-
- for (i = 0; i < 5; i++) {
- if (tr32(cpu_base + CPU_PC) == info.fw_base)
- break;
- tw32(cpu_base + CPU_STATE, 0xffffffff);
- tw32(cpu_base + CPU_MODE, CPU_MODE_HALT);
- tw32_f(cpu_base + CPU_PC, info.fw_base);
- udelay(1000);
- }
- if (i >= 5) {
- netdev_err(tp->dev,
- "%s fails to set CPU PC, is %08x should be %08x\n",
- __func__, tr32(cpu_base + CPU_PC), info.fw_base);
- return -ENODEV;
- }
- tw32(cpu_base + CPU_STATE, 0xffffffff);
- tw32_f(cpu_base + CPU_MODE, 0x00000000);
- return 0;
-}
-
-
static int tg3_set_mac_addr(struct net_device *dev, void *p)
{
struct tg3 *tp = netdev_priv(dev);
@@ -7963,7 +8105,7 @@ static void tg3_rings_reset(struct tg3 *tp)
tw32_mailbox(tp->napi[i].prodmbox, 0);
tw32_rx_mbox(tp->napi[i].consmbox, 0);
tw32_mailbox_f(tp->napi[i].int_mbox, 1);
- tp->napi[0].chk_msi_cnt = 0;
+ tp->napi[i].chk_msi_cnt = 0;
tp->napi[i].last_rx_cons = 0;
tp->napi[i].last_tx_cons = 0;
}
@@ -8659,6 +8801,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
if (tg3_flag(tp, USING_MSIX) && tp->irq_cnt > 1) {
val = tr32(MSGINT_MODE);
val |= MSGINT_MODE_MULTIVEC_EN | MSGINT_MODE_ENABLE;
+ if (!tg3_flag(tp, 1SHOT_MSI))
+ val |= MSGINT_MODE_ONE_SHOT_DISABLE;
tw32(MSGINT_MODE, val);
}
@@ -9043,8 +9187,7 @@ static void tg3_chk_missed_msi(struct tg3 *tp)
tnapi->chk_msi_cnt++;
return;
}
- tw32_mailbox(tnapi->int_mbox,
- tnapi->last_tag << 24);
+ tg3_msi(0, tnapi);
}
}
tnapi->chk_msi_cnt = 0;
@@ -9275,7 +9418,7 @@ static int tg3_test_interrupt(struct tg3 *tp)
if (intr_ok) {
/* Reenable MSI one shot mode. */
- if (tg3_flag(tp, 57765_PLUS)) {
+ if (tg3_flag(tp, 57765_PLUS) && tg3_flag(tp, 1SHOT_MSI)) {
val = tr32(MSGINT_MODE) & ~MSGINT_MODE_ONE_SHOT_DISABLE;
tw32(MSGINT_MODE, val);
}
@@ -9453,6 +9596,8 @@ static void tg3_ints_init(struct tg3 *tp)
u32 msi_mode = tr32(MSGINT_MODE);
if (tg3_flag(tp, USING_MSIX) && tp->irq_cnt > 1)
msi_mode |= MSGINT_MODE_MULTIVEC_EN;
+ if (!tg3_flag(tp, 1SHOT_MSI))
+ msi_mode |= MSGINT_MODE_ONE_SHOT_DISABLE;
tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE);
}
defcfg:
@@ -9862,6 +10007,7 @@ static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev,
get_stat64(&hw_stats->rx_discards);
stats->rx_dropped = tp->rx_dropped;
+ stats->tx_dropped = tp->tx_dropped;
return stats;
}
@@ -10367,7 +10513,6 @@ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam *
struct tg3 *tp = netdev_priv(dev);
ering->rx_max_pending = tp->rx_std_ring_mask;
- ering->rx_mini_max_pending = 0;
if (tg3_flag(tp, JUMBO_RING_ENABLE))
ering->rx_jumbo_max_pending = tp->rx_jmb_ring_mask;
else
@@ -10376,7 +10521,6 @@ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam *
ering->tx_max_pending = TG3_TX_RING_SIZE - 1;
ering->rx_pending = tp->rx_pending;
- ering->rx_mini_pending = 0;
if (tg3_flag(tp, JUMBO_RING_ENABLE))
ering->rx_jumbo_pending = tp->rx_jumbo_pending;
else
@@ -11219,10 +11363,6 @@ static int tg3_test_memory(struct tg3 *tp)
return err;
}
-#define TG3_MAC_LOOPBACK 0
-#define TG3_PHY_LOOPBACK 1
-#define TG3_TSO_LOOPBACK 2
-
#define TG3_TSO_MSS 500
#define TG3_TSO_IP_HDR_LEN 20
@@ -11246,9 +11386,9 @@ static const u8 tg3_tso_header[] = {
0x11, 0x11, 0x11, 0x11,
};
-static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode)
+static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, bool tso_loopback)
{
- u32 mac_mode, rx_start_idx, rx_idx, tx_idx, opaque_key;
+ u32 rx_start_idx, rx_idx, tx_idx, opaque_key;
u32 base_flags = 0, mss = 0, desc_idx, coal_now, data_off, val;
u32 budget;
struct sk_buff *skb, *rx_skb;
@@ -11269,76 +11409,6 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode)
}
coal_now = tnapi->coal_now | rnapi->coal_now;
- if (loopback_mode == TG3_MAC_LOOPBACK) {
- /* HW errata - mac loopback fails in some cases on 5780.
- * Normal traffic and PHY loopback are not affected by
- * errata. Also, the MAC loopback test is deprecated for
- * all newer ASIC revisions.
- */
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 ||
- tg3_flag(tp, CPMU_PRESENT))
- return 0;
-
- mac_mode = tp->mac_mode &
- ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX);
- mac_mode |= MAC_MODE_PORT_INT_LPBACK;
- if (!tg3_flag(tp, 5705_PLUS))
- mac_mode |= MAC_MODE_LINK_POLARITY;
- if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
- mac_mode |= MAC_MODE_PORT_MODE_MII;
- else
- mac_mode |= MAC_MODE_PORT_MODE_GMII;
- tw32(MAC_MODE, mac_mode);
- } else {
- if (tp->phy_flags & TG3_PHYFLG_IS_FET) {
- tg3_phy_fet_toggle_apd(tp, false);
- val = BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED100;
- } else
- val = BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED1000;
-
- tg3_phy_toggle_automdix(tp, 0);
-
- tg3_writephy(tp, MII_BMCR, val);
- udelay(40);
-
- mac_mode = tp->mac_mode &
- ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX);
- if (tp->phy_flags & TG3_PHYFLG_IS_FET) {
- tg3_writephy(tp, MII_TG3_FET_PTEST,
- MII_TG3_FET_PTEST_FRC_TX_LINK |
- MII_TG3_FET_PTEST_FRC_TX_LOCK);
- /* The write needs to be flushed for the AC131 */
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
- tg3_readphy(tp, MII_TG3_FET_PTEST, &val);
- mac_mode |= MAC_MODE_PORT_MODE_MII;
- } else
- mac_mode |= MAC_MODE_PORT_MODE_GMII;
-
- /* reset to prevent losing 1st rx packet intermittently */
- if (tp->phy_flags & TG3_PHYFLG_MII_SERDES) {
- tw32_f(MAC_RX_MODE, RX_MODE_RESET);
- udelay(10);
- tw32_f(MAC_RX_MODE, tp->rx_mode);
- }
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) {
- u32 masked_phy_id = tp->phy_id & TG3_PHY_ID_MASK;
- if (masked_phy_id == TG3_PHY_ID_BCM5401)
- mac_mode &= ~MAC_MODE_LINK_POLARITY;
- else if (masked_phy_id == TG3_PHY_ID_BCM5411)
- mac_mode |= MAC_MODE_LINK_POLARITY;
- tg3_writephy(tp, MII_TG3_EXT_CTRL,
- MII_TG3_EXT_CTRL_LNK3_LED_MODE);
- }
- tw32(MAC_MODE, mac_mode);
-
- /* Wait for link */
- for (i = 0; i < 100; i++) {
- if (tr32(MAC_TX_STATUS) & TX_STATUS_LINK_UP)
- break;
- mdelay(1);
- }
- }
-
err = -EIO;
tx_len = pktsz;
@@ -11352,7 +11422,7 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode)
tw32(MAC_RX_MTU_SIZE, tx_len + ETH_FCS_LEN);
- if (loopback_mode == TG3_TSO_LOOPBACK) {
+ if (tso_loopback) {
struct iphdr *iph = (struct iphdr *)&tx_data[ETH_HLEN];
u32 hdr_len = TG3_TSO_IP_HDR_LEN + TG3_TSO_TCP_HDR_LEN +
@@ -11472,7 +11542,7 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode)
rx_len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT)
- ETH_FCS_LEN;
- if (loopback_mode != TG3_TSO_LOOPBACK) {
+ if (!tso_loopback) {
if (rx_len != tx_len)
goto out;
@@ -11519,25 +11589,33 @@ out:
#define TG3_STD_LOOPBACK_FAILED 1
#define TG3_JMB_LOOPBACK_FAILED 2
#define TG3_TSO_LOOPBACK_FAILED 4
+#define TG3_LOOPBACK_FAILED \
+ (TG3_STD_LOOPBACK_FAILED | \
+ TG3_JMB_LOOPBACK_FAILED | \
+ TG3_TSO_LOOPBACK_FAILED)
-#define TG3_MAC_LOOPBACK_SHIFT 0
-#define TG3_PHY_LOOPBACK_SHIFT 4
-#define TG3_LOOPBACK_FAILED 0x00000077
-
-static int tg3_test_loopback(struct tg3 *tp)
+static int tg3_test_loopback(struct tg3 *tp, u64 *data, bool do_extlpbk)
{
- int err = 0;
- u32 eee_cap, cpmuctrl = 0;
-
- if (!netif_running(tp->dev))
- return TG3_LOOPBACK_FAILED;
+ int err = -EIO;
+ u32 eee_cap;
eee_cap = tp->phy_flags & TG3_PHYFLG_EEE_CAP;
tp->phy_flags &= ~TG3_PHYFLG_EEE_CAP;
+ if (!netif_running(tp->dev)) {
+ data[0] = TG3_LOOPBACK_FAILED;
+ data[1] = TG3_LOOPBACK_FAILED;
+ if (do_extlpbk)
+ data[2] = TG3_LOOPBACK_FAILED;
+ goto done;
+ }
+
err = tg3_reset_hw(tp, 1);
if (err) {
- err = TG3_LOOPBACK_FAILED;
+ data[0] = TG3_LOOPBACK_FAILED;
+ data[1] = TG3_LOOPBACK_FAILED;
+ if (do_extlpbk)
+ data[2] = TG3_LOOPBACK_FAILED;
goto done;
}
@@ -11550,68 +11628,72 @@ static int tg3_test_loopback(struct tg3 *tp)
tw32(i, 0x0);
}
- /* Turn off gphy autopowerdown. */
- if (tp->phy_flags & TG3_PHYFLG_ENABLE_APD)
- tg3_phy_toggle_apd(tp, false);
+ /* HW errata - mac loopback fails in some cases on 5780.
+ * Normal traffic and PHY loopback are not affected by
+ * errata. Also, the MAC loopback test is deprecated for
+ * all newer ASIC revisions.
+ */
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5780 &&
+ !tg3_flag(tp, CPMU_PRESENT)) {
+ tg3_mac_loopback(tp, true);
+
+ if (tg3_run_loopback(tp, ETH_FRAME_LEN, false))
+ data[0] |= TG3_STD_LOOPBACK_FAILED;
+
+ if (tg3_flag(tp, JUMBO_RING_ENABLE) &&
+ tg3_run_loopback(tp, 9000 + ETH_HLEN, false))
+ data[0] |= TG3_JMB_LOOPBACK_FAILED;
- if (tg3_flag(tp, CPMU_PRESENT)) {
+ tg3_mac_loopback(tp, false);
+ }
+
+ if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) &&
+ !tg3_flag(tp, USE_PHYLIB)) {
int i;
- u32 status;
- tw32(TG3_CPMU_MUTEX_REQ, CPMU_MUTEX_REQ_DRIVER);
+ tg3_phy_lpbk_set(tp, 0, false);
- /* Wait for up to 40 microseconds to acquire lock. */
- for (i = 0; i < 4; i++) {
- status = tr32(TG3_CPMU_MUTEX_GNT);
- if (status == CPMU_MUTEX_GNT_DRIVER)
+ /* Wait for link */
+ for (i = 0; i < 100; i++) {
+ if (tr32(MAC_TX_STATUS) & TX_STATUS_LINK_UP)
break;
- udelay(10);
- }
-
- if (status != CPMU_MUTEX_GNT_DRIVER) {
- err = TG3_LOOPBACK_FAILED;
- goto done;
+ mdelay(1);
}
- /* Turn off link-based power management. */
- cpmuctrl = tr32(TG3_CPMU_CTRL);
- tw32(TG3_CPMU_CTRL,
- cpmuctrl & ~(CPMU_CTRL_LINK_SPEED_MODE |
- CPMU_CTRL_LINK_AWARE_MODE));
- }
+ if (tg3_run_loopback(tp, ETH_FRAME_LEN, false))
+ data[1] |= TG3_STD_LOOPBACK_FAILED;
+ if (tg3_flag(tp, TSO_CAPABLE) &&
+ tg3_run_loopback(tp, ETH_FRAME_LEN, true))
+ data[1] |= TG3_TSO_LOOPBACK_FAILED;
+ if (tg3_flag(tp, JUMBO_RING_ENABLE) &&
+ tg3_run_loopback(tp, 9000 + ETH_HLEN, false))
+ data[1] |= TG3_JMB_LOOPBACK_FAILED;
- if (tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_MAC_LOOPBACK))
- err |= TG3_STD_LOOPBACK_FAILED << TG3_MAC_LOOPBACK_SHIFT;
+ if (do_extlpbk) {
+ tg3_phy_lpbk_set(tp, 0, true);
- if (tg3_flag(tp, JUMBO_RING_ENABLE) &&
- tg3_run_loopback(tp, 9000 + ETH_HLEN, TG3_MAC_LOOPBACK))
- err |= TG3_JMB_LOOPBACK_FAILED << TG3_MAC_LOOPBACK_SHIFT;
+ /* All link indications report up, but the hardware
+ * isn't really ready for about 20 msec. Double it
+ * to be sure.
+ */
+ mdelay(40);
- if (tg3_flag(tp, CPMU_PRESENT)) {
- tw32(TG3_CPMU_CTRL, cpmuctrl);
+ if (tg3_run_loopback(tp, ETH_FRAME_LEN, false))
+ data[2] |= TG3_STD_LOOPBACK_FAILED;
+ if (tg3_flag(tp, TSO_CAPABLE) &&
+ tg3_run_loopback(tp, ETH_FRAME_LEN, true))
+ data[2] |= TG3_TSO_LOOPBACK_FAILED;
+ if (tg3_flag(tp, JUMBO_RING_ENABLE) &&
+ tg3_run_loopback(tp, 9000 + ETH_HLEN, false))
+ data[2] |= TG3_JMB_LOOPBACK_FAILED;
+ }
- /* Release the mutex */
- tw32(TG3_CPMU_MUTEX_GNT, CPMU_MUTEX_GNT_DRIVER);
+ /* Re-enable gphy autopowerdown. */
+ if (tp->phy_flags & TG3_PHYFLG_ENABLE_APD)
+ tg3_phy_toggle_apd(tp, true);
}
- if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) &&
- !tg3_flag(tp, USE_PHYLIB)) {
- if (tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_PHY_LOOPBACK))
- err |= TG3_STD_LOOPBACK_FAILED <<
- TG3_PHY_LOOPBACK_SHIFT;
- if (tg3_flag(tp, TSO_CAPABLE) &&
- tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_TSO_LOOPBACK))
- err |= TG3_TSO_LOOPBACK_FAILED <<
- TG3_PHY_LOOPBACK_SHIFT;
- if (tg3_flag(tp, JUMBO_RING_ENABLE) &&
- tg3_run_loopback(tp, 9000 + ETH_HLEN, TG3_PHY_LOOPBACK))
- err |= TG3_JMB_LOOPBACK_FAILED <<
- TG3_PHY_LOOPBACK_SHIFT;
- }
-
- /* Re-enable gphy autopowerdown. */
- if (tp->phy_flags & TG3_PHYFLG_ENABLE_APD)
- tg3_phy_toggle_apd(tp, true);
+ err = (data[0] | data[1] | data[2]) ? -EIO : 0;
done:
tp->phy_flags |= eee_cap;
@@ -11623,6 +11705,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
u64 *data)
{
struct tg3 *tp = netdev_priv(dev);
+ bool doextlpbk = etest->flags & ETH_TEST_FL_EXTERNAL_LB;
if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) &&
tg3_power_up(tp)) {
@@ -11637,7 +11720,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
etest->flags |= ETH_TEST_FL_FAILED;
data[0] = 1;
}
- if (tg3_test_link(tp) != 0) {
+ if (!doextlpbk && tg3_test_link(tp)) {
etest->flags |= ETH_TEST_FL_FAILED;
data[1] = 1;
}
@@ -11667,18 +11750,23 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
etest->flags |= ETH_TEST_FL_FAILED;
data[2] = 1;
}
+
if (tg3_test_memory(tp) != 0) {
etest->flags |= ETH_TEST_FL_FAILED;
data[3] = 1;
}
- if ((data[4] = tg3_test_loopback(tp)) != 0)
+
+ if (doextlpbk)
+ etest->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
+
+ if (tg3_test_loopback(tp, &data[4], doextlpbk))
etest->flags |= ETH_TEST_FL_FAILED;
tg3_full_unlock(tp);
if (tg3_test_interrupt(tp) != 0) {
etest->flags |= ETH_TEST_FL_FAILED;
- data[5] = 1;
+ data[7] = 1;
}
tg3_full_lock(tp, 0);
@@ -13987,7 +14075,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
/* BCM5785 devices are effectively PCIe devices, and should
* follow PCIe codepaths, but do not have a PCIe capabilities
* section.
- */
+ */
tg3_flag_set(tp, PCI_EXPRESS);
} else if (!tg3_flag(tp, 5705_PLUS) ||
tg3_flag(tp, 5780_CLASS)) {
@@ -14368,7 +14456,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (tg3_flag(tp, ENABLE_APE))
tp->mac_mode = MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN;
else
- tp->mac_mode = TG3_DEF_MAC_MODE;
+ tp->mac_mode = 0;
/* these are limited to 10/100 only */
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 &&
@@ -15177,7 +15265,7 @@ static const struct net_device_ops tg3_netdev_ops = {
.ndo_start_xmit = tg3_start_xmit,
.ndo_get_stats64 = tg3_get_stats64,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = tg3_set_rx_mode,
+ .ndo_set_rx_mode = tg3_set_rx_mode,
.ndo_set_mac_address = tg3_set_mac_addr,
.ndo_do_ioctl = tg3_ioctl,
.ndo_tx_timeout = tg3_tx_timeout,
@@ -15447,7 +15535,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
tnapi->tx_pending = TG3_DEF_TX_RING_PENDING;
tnapi->int_mbox = intmbx;
- if (i < 4)
+ if (i <= 4)
intmbx += 0x8;
else
intmbx += 0x4;
@@ -15579,7 +15667,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
cancel_work_sync(&tp->reset_task);
- if (!tg3_flag(tp, USE_PHYLIB)) {
+ if (tg3_flag(tp, USE_PHYLIB)) {
tg3_phy_fini(tp);
tg3_mdio_fini(tp);
}
diff --git a/drivers/net/tg3.h b/drivers/net/ethernet/broadcom/tg3.h
index 2ea456dd5880..f32f288134c7 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/ethernet/broadcom/tg3.h
@@ -2197,6 +2197,7 @@
#define MII_TG3_AUXCTL_ACTL_TX_6DB 0x0400
#define MII_TG3_AUXCTL_ACTL_SMDSP_ENA 0x0800
#define MII_TG3_AUXCTL_ACTL_EXTPKTLEN 0x4000
+#define MII_TG3_AUXCTL_ACTL_EXTLOOPBK 0x8000
#define MII_TG3_AUXCTL_SHDWSEL_PWRCTL 0x0002
#define MII_TG3_AUXCTL_PCTL_WOL_EN 0x0008
@@ -2262,6 +2263,8 @@
/* Fast Ethernet Tranceiver definitions */
#define MII_TG3_FET_PTEST 0x17
+#define MII_TG3_FET_PTEST_TRIM_SEL 0x0010
+#define MII_TG3_FET_PTEST_TRIM_2 0x0002
#define MII_TG3_FET_PTEST_FRC_TX_LINK 0x1000
#define MII_TG3_FET_PTEST_FRC_TX_LOCK 0x0800
@@ -2987,6 +2990,7 @@ struct tg3 {
/* begin "everything else" cacheline(s) section */
unsigned long rx_dropped;
+ unsigned long tx_dropped;
struct rtnl_link_stats64 net_stats_prev;
struct tg3_ethtool_stats estats;
struct tg3_ethtool_stats estats_prev;
diff --git a/drivers/net/ethernet/brocade/Kconfig b/drivers/net/ethernet/brocade/Kconfig
new file mode 100644
index 000000000000..264155778857
--- /dev/null
+++ b/drivers/net/ethernet/brocade/Kconfig
@@ -0,0 +1,23 @@
+#
+# Brocade device configuration
+#
+
+config NET_VENDOR_BROCADE
+ bool "Brocade devices"
+ default y
+ depends on PCI
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Brocade cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_BROCADE
+
+source "drivers/net/ethernet/brocade/bna/Kconfig"
+
+endif # NET_VENDOR_BROCADE
diff --git a/drivers/net/ethernet/brocade/Makefile b/drivers/net/ethernet/brocade/Makefile
new file mode 100644
index 000000000000..b58238d2df6a
--- /dev/null
+++ b/drivers/net/ethernet/brocade/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Brocade device drivers.
+#
+
+obj-$(CONFIG_BNA) += bna/
diff --git a/drivers/net/ethernet/brocade/bna/Kconfig b/drivers/net/ethernet/brocade/bna/Kconfig
new file mode 100644
index 000000000000..dc2eb526fbf7
--- /dev/null
+++ b/drivers/net/ethernet/brocade/bna/Kconfig
@@ -0,0 +1,17 @@
+#
+# Brocade network device configuration
+#
+
+config BNA
+ tristate "Brocade 1010/1020 10Gb Ethernet Driver support"
+ depends on PCI
+ ---help---
+ This driver supports Brocade 1010/1020 10Gb CEE capable Ethernet
+ cards.
+ To compile this driver as a module, choose M here: the module
+ will be called bna.
+
+ For general information and support, go to the Brocade support
+ website at:
+
+ <http://support.brocade.com>
diff --git a/drivers/net/bna/Makefile b/drivers/net/ethernet/brocade/bna/Makefile
index a5d604de7fea..74d3abca1960 100644
--- a/drivers/net/bna/Makefile
+++ b/drivers/net/ethernet/brocade/bna/Makefile
@@ -5,7 +5,8 @@
obj-$(CONFIG_BNA) += bna.o
-bna-objs := bnad.o bnad_ethtool.o bna_ctrl.o bna_txrx.o
-bna-objs += bfa_ioc.o bfa_ioc_ct.o bfa_cee.o cna_fwimg.o
+bna-objs := bnad.o bnad_ethtool.o bna_enet.o bna_tx_rx.o
+bna-objs += bfa_msgq.o bfa_ioc.o bfa_ioc_ct.o bfa_cee.o
+bna-objs += cna_fwimg.o
EXTRA_CFLAGS := -Idrivers/net/bna
diff --git a/drivers/net/bna/bfa_cee.c b/drivers/net/ethernet/brocade/bna/bfa_cee.c
index 39e5ab9fde59..8e627186507c 100644
--- a/drivers/net/bna/bfa_cee.c
+++ b/drivers/net/ethernet/brocade/bna/bfa_cee.c
@@ -16,15 +16,10 @@
* www.brocade.com
*/
-#include "bfa_defs_cna.h"
-#include "cna.h"
#include "bfa_cee.h"
#include "bfi_cna.h"
#include "bfa_ioc.h"
-#define bfa_ioc_portid(__ioc) ((__ioc)->port_id)
-#define bfa_lpuid(__arg) bfa_ioc_portid(&(__arg)->ioc)
-
static void bfa_cee_format_lldp_cfg(struct bfa_cee_lldp_cfg *lldp_cfg);
static void bfa_cee_format_cee_cfg(void *buffer);
diff --git a/drivers/net/bna/bfa_cee.h b/drivers/net/ethernet/brocade/bna/bfa_cee.h
index 58d54e98d595..58d54e98d595 100644
--- a/drivers/net/bna/bfa_cee.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_cee.h
diff --git a/drivers/net/bna/bfa_cs.h b/drivers/net/ethernet/brocade/bna/bfa_cs.h
index 3da1a946ccdd..3da1a946ccdd 100644
--- a/drivers/net/bna/bfa_cs.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_cs.h
diff --git a/drivers/net/bna/bfa_defs.h b/drivers/net/ethernet/brocade/bna/bfa_defs.h
index b080b3698f48..2f12d68021d5 100644
--- a/drivers/net/bna/bfa_defs.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_defs.h
@@ -124,6 +124,7 @@ enum bfa_ioc_state {
BFA_IOC_DISABLED = 10, /*!< IOC is disabled */
BFA_IOC_FWMISMATCH = 11, /*!< IOC f/w different from drivers */
BFA_IOC_ENABLING = 12, /*!< IOC is being enabled */
+ BFA_IOC_HWFAIL = 13, /*!< PCI mapping doesn't exist */
};
/**
@@ -179,8 +180,20 @@ struct bfa_ioc_attr {
struct bfa_adapter_attr adapter_attr; /*!< HBA attributes */
struct bfa_ioc_driver_attr driver_attr; /*!< driver attr */
struct bfa_ioc_pci_attr pci_attr;
- u8 port_id; /*!< port number */
- u8 rsvd[7]; /*!< 64bit align */
+ u8 port_id; /*!< port number */
+ u8 port_mode; /*!< enum bfa_mode */
+ u8 cap_bm; /*!< capability */
+ u8 port_mode_cfg; /*!< enum bfa_mode */
+ u8 rsvd[4]; /*!< 64bit align */
+};
+
+/**
+ * Adapter capability mask definition
+ */
+enum {
+ BFA_CM_HBA = 0x01,
+ BFA_CM_CNA = 0x02,
+ BFA_CM_NIC = 0x04,
};
/**
@@ -228,8 +241,18 @@ struct bfa_mfg_block {
mac_t mfg_mac; /*!< mac address */
u8 num_mac; /*!< number of mac addresses */
u8 rsv2;
- u32 mfg_type; /*!< card type */
- u8 rsv3[108];
+ u32 card_type; /*!< card type */
+ char cap_nic; /*!< capability nic */
+ char cap_cna; /*!< capability cna */
+ char cap_hba; /*!< capability hba */
+ char cap_fc16g; /*!< capability fc 16g */
+ char cap_sriov; /*!< capability sriov */
+ char cap_mezz; /*!< capability mezz */
+ u8 rsv3;
+ u8 mfg_nports; /*!< number of ports */
+ char media[8]; /*!< xfi/xaui */
+ char initial_mode[8];/*!< initial mode: hba/cna/nic */
+ u8 rsv4[84];
u8 md5_chksum[BFA_MFG_CHKSUM_SIZE]; /*!< md5 checksum */
};
@@ -239,8 +262,35 @@ struct bfa_mfg_block {
* ---------------------- pci definitions ------------
*/
-#define bfa_asic_id_ct(devid) \
- ((devid) == PCI_DEVICE_ID_BROCADE_CT || \
- (devid) == PCI_DEVICE_ID_BROCADE_CT_FC)
+/*
+ * PCI device ID information
+ */
+enum {
+ BFA_PCI_DEVICE_ID_CT2 = 0x22,
+};
+
+#define bfa_asic_id_ct(device) \
+ ((device) == PCI_DEVICE_ID_BROCADE_CT || \
+ (device) == PCI_DEVICE_ID_BROCADE_CT_FC)
+#define bfa_asic_id_ct2(device) \
+ ((device) == BFA_PCI_DEVICE_ID_CT2)
+#define bfa_asic_id_ctc(device) \
+ (bfa_asic_id_ct(device) || bfa_asic_id_ct2(device))
+
+/**
+ * PCI sub-system device and vendor ID information
+ */
+enum {
+ BFA_PCI_FCOE_SSDEVICE_ID = 0x14,
+ BFA_PCI_CT2_SSID_FCoE = 0x22,
+ BFA_PCI_CT2_SSID_ETH = 0x23,
+ BFA_PCI_CT2_SSID_FC = 0x24,
+};
+
+enum bfa_mode {
+ BFA_MODE_HBA = 1,
+ BFA_MODE_CNA = 2,
+ BFA_MODE_NIC = 3
+};
#endif /* __BFA_DEFS_H__ */
diff --git a/drivers/net/bna/bfa_defs_cna.h b/drivers/net/ethernet/brocade/bna/bfa_defs_cna.h
index 7e0a9187bdd5..8ab33ee2c2bc 100644
--- a/drivers/net/bna/bfa_defs_cna.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_defs_cna.h
@@ -15,7 +15,6 @@
* All rights reserved
* www.brocade.com
*/
-
#ifndef __BFA_DEFS_CNA_H__
#define __BFA_DEFS_CNA_H__
@@ -55,6 +54,9 @@ struct bfa_port_fc_stats {
u64 bad_os_count; /*!< Invalid ordered sets */
u64 err_enc_out; /*!< Encoding err nonframe_8b10b */
u64 err_enc; /*!< Encoding err frame_8b10b */
+ u64 bbsc_frames_lost; /*!< Credit Recovery-Frames Lost */
+ u64 bbsc_credits_lost; /*!< Credit Recovery-Credits Lost */
+ u64 bbsc_link_resets; /*!< Credit Recovery-Link Resets */
};
/**
@@ -100,6 +102,10 @@ struct bfa_port_eth_stats {
u64 rx_fcoe_zero_pause; /*!< Rx FCoE zero pause */
u64 tx_fcoe_pause; /*!< Tx FCoE pause */
u64 tx_fcoe_zero_pause; /*!< Tx FCoE zero pause */
+ u64 rx_iscsi_pause; /*!< Rx iSCSI pause */
+ u64 rx_iscsi_zero_pause; /*!< Rx iSCSI zero pause */
+ u64 tx_iscsi_pause; /*!< Tx iSCSI pause */
+ u64 tx_iscsi_zero_pause; /*!< Tx iSCSI zero pause */
};
/**
diff --git a/drivers/net/bna/bfa_defs_mfg_comm.h b/drivers/net/ethernet/brocade/bna/bfa_defs_mfg_comm.h
index 885ef3afdd4e..6681fe87c1e1 100644
--- a/drivers/net/bna/bfa_defs_mfg_comm.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_defs_mfg_comm.h
@@ -18,12 +18,12 @@
#ifndef __BFA_DEFS_MFG_COMM_H__
#define __BFA_DEFS_MFG_COMM_H__
-#include "cna.h"
+#include "bfa_defs.h"
/**
* Manufacturing block version
*/
-#define BFA_MFG_VERSION 2
+#define BFA_MFG_VERSION 3
#define BFA_MFG_VERSION_UNINIT 0xFF
/**
@@ -60,20 +60,17 @@ enum {
BFA_MFG_TYPE_ASTRA = 807, /*!< Astra mezz card */
BFA_MFG_TYPE_LIGHTNING_P0 = 902, /*!< Lightning mezz card - old */
BFA_MFG_TYPE_LIGHTNING = 1741, /*!< Lightning mezz card */
+ BFA_MFG_TYPE_PROWLER_F = 1560, /*!< Prowler FC only cards */
+ BFA_MFG_TYPE_PROWLER_N = 1410, /*!< Prowler NIC only cards */
+ BFA_MFG_TYPE_PROWLER_C = 1710, /*!< Prowler CNA only cards */
+ BFA_MFG_TYPE_PROWLER_D = 1860, /*!< Prowler Dual cards */
+ BFA_MFG_TYPE_CHINOOK = 1867, /*!< Chinook cards */
BFA_MFG_TYPE_INVALID = 0, /*!< Invalid card type */
};
#pragma pack(1)
/**
- * Check if 1-port card
- */
-#define bfa_mfg_is_1port(type) (( \
- (type) == BFA_MFG_TYPE_FC8P1 || \
- (type) == BFA_MFG_TYPE_FC4P1 || \
- (type) == BFA_MFG_TYPE_CNA10P1))
-
-/**
* Check if Mezz card
*/
#define bfa_mfg_is_mezz(type) (( \
@@ -81,56 +78,8 @@ enum {
(type) == BFA_MFG_TYPE_WANCHESE || \
(type) == BFA_MFG_TYPE_ASTRA || \
(type) == BFA_MFG_TYPE_LIGHTNING_P0 || \
- (type) == BFA_MFG_TYPE_LIGHTNING))
-
-/**
- * Check if card type valid
- */
-#define bfa_mfg_is_card_type_valid(type) (( \
- (type) == BFA_MFG_TYPE_FC8P2 || \
- (type) == BFA_MFG_TYPE_FC8P1 || \
- (type) == BFA_MFG_TYPE_FC4P2 || \
- (type) == BFA_MFG_TYPE_FC4P1 || \
- (type) == BFA_MFG_TYPE_CNA10P2 || \
- (type) == BFA_MFG_TYPE_CNA10P1 || \
- bfa_mfg_is_mezz(type)))
-
-#define bfa_mfg_adapter_prop_init_flash(card_type, prop) \
-do { \
- switch ((card_type)) { \
- case BFA_MFG_TYPE_FC8P2: \
- case BFA_MFG_TYPE_JAYHAWK: \
- case BFA_MFG_TYPE_ASTRA: \
- (prop) = BFI_ADAPTER_SETP(NPORTS, 2) | \
- BFI_ADAPTER_SETP(SPEED, 8); \
- break; \
- case BFA_MFG_TYPE_FC8P1: \
- (prop) = BFI_ADAPTER_SETP(NPORTS, 1) | \
- BFI_ADAPTER_SETP(SPEED, 8); \
- break; \
- case BFA_MFG_TYPE_FC4P2: \
- (prop) = BFI_ADAPTER_SETP(NPORTS, 2) | \
- BFI_ADAPTER_SETP(SPEED, 4); \
- break; \
- case BFA_MFG_TYPE_FC4P1: \
- (prop) = BFI_ADAPTER_SETP(NPORTS, 1) | \
- BFI_ADAPTER_SETP(SPEED, 4); \
- break; \
- case BFA_MFG_TYPE_CNA10P2: \
- case BFA_MFG_TYPE_WANCHESE: \
- case BFA_MFG_TYPE_LIGHTNING_P0: \
- case BFA_MFG_TYPE_LIGHTNING: \
- (prop) = BFI_ADAPTER_SETP(NPORTS, 2); \
- (prop) |= BFI_ADAPTER_SETP(SPEED, 10); \
- break; \
- case BFA_MFG_TYPE_CNA10P1: \
- (prop) = BFI_ADAPTER_SETP(NPORTS, 1); \
- (prop) |= BFI_ADAPTER_SETP(SPEED, 10); \
- break; \
- default: \
- (prop) = BFI_ADAPTER_UNSUPP; \
- } \
-} while (0)
+ (type) == BFA_MFG_TYPE_LIGHTNING || \
+ (type) == BFA_MFG_TYPE_CHINOOK))
enum {
CB_GPIO_TTV = (1), /*!< TTV debug capable cards */
diff --git a/drivers/net/bna/bfa_defs_status.h b/drivers/net/ethernet/brocade/bna/bfa_defs_status.h
index 7c5fe6c2e80e..7c5fe6c2e80e 100644
--- a/drivers/net/bna/bfa_defs_status.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_defs_status.h
diff --git a/drivers/net/bna/bfa_ioc.c b/drivers/net/ethernet/brocade/bna/bfa_ioc.c
index 126b0aac9f94..b0307a00a109 100644
--- a/drivers/net/bna/bfa_ioc.c
+++ b/drivers/net/ethernet/brocade/bna/bfa_ioc.c
@@ -17,9 +17,7 @@
*/
#include "bfa_ioc.h"
-#include "cna.h"
-#include "bfi.h"
-#include "bfi_ctreg.h"
+#include "bfi_reg.h"
#include "bfa_defs.h"
/**
@@ -62,6 +60,7 @@ static void bfa_ioc_hw_sem_init(struct bfa_ioc *ioc);
static void bfa_ioc_hw_sem_get(struct bfa_ioc *ioc);
static void bfa_ioc_hw_sem_get_cancel(struct bfa_ioc *ioc);
static void bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force);
+static void bfa_ioc_poll_fwinit(struct bfa_ioc *ioc);
static void bfa_ioc_send_enable(struct bfa_ioc *ioc);
static void bfa_ioc_send_disable(struct bfa_ioc *ioc);
static void bfa_ioc_send_getattr(struct bfa_ioc *ioc);
@@ -78,8 +77,8 @@ static void bfa_ioc_lpu_stop(struct bfa_ioc *ioc);
static void bfa_ioc_fail_notify(struct bfa_ioc *ioc);
static void bfa_ioc_pf_enabled(struct bfa_ioc *ioc);
static void bfa_ioc_pf_disabled(struct bfa_ioc *ioc);
-static void bfa_ioc_pf_initfailed(struct bfa_ioc *ioc);
static void bfa_ioc_pf_failed(struct bfa_ioc *ioc);
+static void bfa_ioc_pf_hwfailed(struct bfa_ioc *ioc);
static void bfa_ioc_pf_fwmismatch(struct bfa_ioc *ioc);
static void bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type,
u32 boot_param);
@@ -108,11 +107,11 @@ enum ioc_event {
IOC_E_ENABLED = 5, /*!< f/w enabled */
IOC_E_FWRSP_GETATTR = 6, /*!< IOC get attribute response */
IOC_E_DISABLED = 7, /*!< f/w disabled */
- IOC_E_INITFAILED = 8, /*!< failure notice by iocpf sm */
- IOC_E_PFFAILED = 9, /*!< failure notice by iocpf sm */
- IOC_E_HBFAIL = 10, /*!< heartbeat failure */
- IOC_E_HWERROR = 11, /*!< hardware error interrupt */
- IOC_E_TIMEOUT = 12, /*!< timeout */
+ IOC_E_PFFAILED = 8, /*!< failure notice by iocpf sm */
+ IOC_E_HBFAIL = 9, /*!< heartbeat failure */
+ IOC_E_HWERROR = 10, /*!< hardware error interrupt */
+ IOC_E_TIMEOUT = 11, /*!< timeout */
+ IOC_E_HWFAILED = 12, /*!< PCI mapping failure notice */
};
bfa_fsm_state_decl(bfa_ioc, uninit, struct bfa_ioc, enum ioc_event);
@@ -124,6 +123,7 @@ bfa_fsm_state_decl(bfa_ioc, fail_retry, struct bfa_ioc, enum ioc_event);
bfa_fsm_state_decl(bfa_ioc, fail, struct bfa_ioc, enum ioc_event);
bfa_fsm_state_decl(bfa_ioc, disabling, struct bfa_ioc, enum ioc_event);
bfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, hwfail, struct bfa_ioc, enum ioc_event);
static struct bfa_sm_table ioc_sm_table[] = {
{BFA_SM(bfa_ioc_sm_uninit), BFA_IOC_UNINIT},
@@ -135,12 +135,9 @@ static struct bfa_sm_table ioc_sm_table[] = {
{BFA_SM(bfa_ioc_sm_fail), BFA_IOC_FAIL},
{BFA_SM(bfa_ioc_sm_disabling), BFA_IOC_DISABLING},
{BFA_SM(bfa_ioc_sm_disabled), BFA_IOC_DISABLED},
+ {BFA_SM(bfa_ioc_sm_hwfail), BFA_IOC_HWFAIL},
};
-/**
- * IOCPF state machine definitions/declarations
- */
-
/*
* Forward declareations for iocpf state machine
*/
@@ -166,6 +163,7 @@ enum iocpf_event {
IOCPF_E_GETATTRFAIL = 9, /*!< init fail notice by ioc sm */
IOCPF_E_SEMLOCKED = 10, /*!< h/w semaphore is locked */
IOCPF_E_TIMEOUT = 11, /*!< f/w response timeout */
+ IOCPF_E_SEM_ERROR = 12, /*!< h/w sem mapping error */
};
/**
@@ -300,11 +298,16 @@ bfa_ioc_sm_enabling(struct bfa_ioc *ioc, enum ioc_event event)
/* !!! fall through !!! */
case IOC_E_HWERROR:
ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
if (event != IOC_E_PFFAILED)
bfa_iocpf_initfail(ioc);
break;
+ case IOC_E_HWFAILED:
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail);
+ break;
+
case IOC_E_DISABLE:
bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
break;
@@ -343,6 +346,7 @@ bfa_ioc_sm_getattr(struct bfa_ioc *ioc, enum ioc_event event)
case IOC_E_FWRSP_GETATTR:
del_timer(&ioc->ioc_timer);
bfa_ioc_check_attr_wwns(ioc);
+ bfa_ioc_hb_monitor(ioc);
bfa_fsm_set_state(ioc, bfa_ioc_sm_op);
break;
@@ -352,7 +356,7 @@ bfa_ioc_sm_getattr(struct bfa_ioc *ioc, enum ioc_event event)
/* fall through */
case IOC_E_TIMEOUT:
ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
- bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
if (event != IOC_E_PFFAILED)
bfa_iocpf_getattrfail(ioc);
break;
@@ -374,7 +378,7 @@ static void
bfa_ioc_sm_op_entry(struct bfa_ioc *ioc)
{
ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK);
- bfa_ioc_hb_monitor(ioc);
+ bfa_ioc_event_notify(ioc, BFA_IOC_E_ENABLED);
}
static void
@@ -394,12 +398,13 @@ bfa_ioc_sm_op(struct bfa_ioc *ioc, enum ioc_event event)
bfa_ioc_hb_stop(ioc);
/* !!! fall through !!! */
case IOC_E_HBFAIL:
- bfa_ioc_fail_notify(ioc);
if (ioc->iocpf.auto_recover)
bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry);
else
bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
+ bfa_ioc_fail_notify(ioc);
+
if (event != IOC_E_PFFAILED)
bfa_iocpf_fail(ioc);
break;
@@ -416,7 +421,7 @@ bfa_ioc_sm_disabling_entry(struct bfa_ioc *ioc)
}
/**
- * IOC is being desabled
+ * IOC is being disabled
*/
static void
bfa_ioc_sm_disabling(struct bfa_ioc *ioc, enum ioc_event event)
@@ -435,13 +440,18 @@ bfa_ioc_sm_disabling(struct bfa_ioc *ioc, enum ioc_event event)
bfa_iocpf_fail(ioc);
break;
+ case IOC_E_HWFAILED:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail);
+ bfa_ioc_disable_comp(ioc);
+ break;
+
default:
bfa_sm_fault(event);
}
}
/**
- * IOC desable completion entry.
+ * IOC disable completion entry.
*/
static void
bfa_ioc_sm_disabled_entry(struct bfa_ioc *ioc)
@@ -493,12 +503,14 @@ bfa_ioc_sm_fail_retry(struct bfa_ioc *ioc, enum ioc_event event)
* Initialization retry failed.
*/
ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
if (event != IOC_E_PFFAILED)
bfa_iocpf_initfail(ioc);
break;
- case IOC_E_INITFAILED:
- bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
+ case IOC_E_HWFAILED:
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail);
break;
case IOC_E_ENABLE:
@@ -552,6 +564,36 @@ bfa_ioc_sm_fail(struct bfa_ioc *ioc, enum ioc_event event)
}
}
+static void
+bfa_ioc_sm_hwfail_entry(struct bfa_ioc *ioc)
+{
+}
+
+/**
+ * IOC failure.
+ */
+static void
+bfa_ioc_sm_hwfail(struct bfa_ioc *ioc, enum ioc_event event)
+{
+ switch (event) {
+
+ case IOC_E_ENABLE:
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ break;
+
+ case IOC_E_DISABLE:
+ ioc->cbfn->disable_cbfn(ioc->bfa);
+ break;
+
+ case IOC_E_DETACH:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
/**
* IOCPF State Machine
*/
@@ -562,7 +604,7 @@ bfa_ioc_sm_fail(struct bfa_ioc *ioc, enum ioc_event event)
static void
bfa_iocpf_sm_reset_entry(struct bfa_iocpf *iocpf)
{
- iocpf->retry_count = 0;
+ iocpf->fw_mismatch_notified = false;
iocpf->auto_recover = bfa_nw_auto_recover;
}
@@ -607,7 +649,6 @@ bfa_iocpf_sm_fwcheck(struct bfa_iocpf *iocpf, enum iocpf_event event)
case IOCPF_E_SEMLOCKED:
if (bfa_ioc_firmware_lock(ioc)) {
if (bfa_ioc_sync_start(ioc)) {
- iocpf->retry_count = 0;
bfa_ioc_sync_join(ioc);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
} else {
@@ -622,6 +663,11 @@ bfa_iocpf_sm_fwcheck(struct bfa_iocpf *iocpf, enum iocpf_event event)
}
break;
+ case IOCPF_E_SEM_ERROR:
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
+ bfa_ioc_pf_hwfailed(ioc);
+ break;
+
case IOCPF_E_DISABLE:
bfa_ioc_hw_sem_get_cancel(ioc);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
@@ -645,10 +691,10 @@ static void
bfa_iocpf_sm_mismatch_entry(struct bfa_iocpf *iocpf)
{
/* Call only the first time sm enters fwmismatch state. */
- if (iocpf->retry_count == 0)
+ if (iocpf->fw_mismatch_notified == false)
bfa_ioc_pf_fwmismatch(iocpf->ioc);
- iocpf->retry_count++;
+ iocpf->fw_mismatch_notified = true;
mod_timer(&(iocpf->ioc)->iocpf_timer, jiffies +
msecs_to_jiffies(BFA_IOC_TOV));
}
@@ -711,6 +757,11 @@ bfa_iocpf_sm_semwait(struct bfa_iocpf *iocpf, enum iocpf_event event)
}
break;
+ case IOCPF_E_SEM_ERROR:
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
+ bfa_ioc_pf_hwfailed(ioc);
+ break;
+
case IOCPF_E_DISABLE:
bfa_ioc_hw_sem_get_cancel(ioc);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
@@ -724,9 +775,8 @@ bfa_iocpf_sm_semwait(struct bfa_iocpf *iocpf, enum iocpf_event event)
static void
bfa_iocpf_sm_hwinit_entry(struct bfa_iocpf *iocpf)
{
- mod_timer(&(iocpf->ioc)->iocpf_timer, jiffies +
- msecs_to_jiffies(BFA_IOC_TOV));
- bfa_ioc_reset(iocpf->ioc, 0);
+ iocpf->poll_time = 0;
+ bfa_ioc_reset(iocpf->ioc, false);
}
/**
@@ -740,19 +790,11 @@ bfa_iocpf_sm_hwinit(struct bfa_iocpf *iocpf, enum iocpf_event event)
switch (event) {
case IOCPF_E_FWREADY:
- del_timer(&ioc->iocpf_timer);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_enabling);
break;
- case IOCPF_E_INITFAIL:
- del_timer(&ioc->iocpf_timer);
- /*
- * !!! fall through !!!
- */
-
case IOCPF_E_TIMEOUT:
bfa_nw_ioc_hw_sem_release(ioc);
- if (event == IOCPF_E_TIMEOUT)
bfa_ioc_pf_failed(ioc);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);
break;
@@ -774,6 +816,10 @@ bfa_iocpf_sm_enabling_entry(struct bfa_iocpf *iocpf)
{
mod_timer(&(iocpf->ioc)->iocpf_timer, jiffies +
msecs_to_jiffies(BFA_IOC_TOV));
+ /**
+ * Enable Interrupts before sending fw IOC ENABLE cmd.
+ */
+ iocpf->ioc->cbfn->reset_cbfn(iocpf->ioc->bfa);
bfa_ioc_send_enable(iocpf->ioc);
}
@@ -811,21 +857,11 @@ bfa_iocpf_sm_enabling(struct bfa_iocpf *iocpf, enum iocpf_event event)
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling);
break;
- case IOCPF_E_FWREADY:
- bfa_ioc_send_enable(ioc);
- break;
-
default:
bfa_sm_fault(event);
}
}
-static bool
-bfa_nw_ioc_is_operational(struct bfa_ioc *ioc)
-{
- return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_op);
-}
-
static void
bfa_iocpf_sm_ready_entry(struct bfa_iocpf *iocpf)
{
@@ -835,8 +871,6 @@ bfa_iocpf_sm_ready_entry(struct bfa_iocpf *iocpf)
static void
bfa_iocpf_sm_ready(struct bfa_iocpf *iocpf, enum iocpf_event event)
{
- struct bfa_ioc *ioc = iocpf->ioc;
-
switch (event) {
case IOCPF_E_DISABLE:
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling);
@@ -850,14 +884,6 @@ bfa_iocpf_sm_ready(struct bfa_iocpf *iocpf, enum iocpf_event event)
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail_sync);
break;
- case IOCPF_E_FWREADY:
- bfa_ioc_pf_failed(ioc);
- if (bfa_nw_ioc_is_operational(ioc))
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail_sync);
- else
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);
- break;
-
default:
bfa_sm_fault(event);
}
@@ -881,7 +907,6 @@ bfa_iocpf_sm_disabling(struct bfa_iocpf *iocpf, enum iocpf_event event)
switch (event) {
case IOCPF_E_FWRSP_DISABLE:
- case IOCPF_E_FWREADY:
del_timer(&ioc->iocpf_timer);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
break;
@@ -926,6 +951,11 @@ bfa_iocpf_sm_disabling_sync(struct bfa_iocpf *iocpf, enum iocpf_event event)
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
break;
+ case IOCPF_E_SEM_ERROR:
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
+ bfa_ioc_pf_hwfailed(ioc);
+ break;
+
case IOCPF_E_FAIL:
break;
@@ -951,7 +981,6 @@ bfa_iocpf_sm_disabled(struct bfa_iocpf *iocpf, enum iocpf_event event)
switch (event) {
case IOCPF_E_ENABLE:
- iocpf->retry_count = 0;
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait);
break;
@@ -982,20 +1011,15 @@ bfa_iocpf_sm_initfail_sync(struct bfa_iocpf *iocpf, enum iocpf_event event)
switch (event) {
case IOCPF_E_SEMLOCKED:
bfa_ioc_notify_fail(ioc);
- bfa_ioc_sync_ack(ioc);
- iocpf->retry_count++;
- if (iocpf->retry_count >= BFA_IOC_HWINIT_MAX) {
- bfa_ioc_sync_leave(ioc);
- bfa_nw_ioc_hw_sem_release(ioc);
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail);
- } else {
- if (bfa_ioc_sync_complete(ioc))
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
- else {
- bfa_nw_ioc_hw_sem_release(ioc);
- bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait);
- }
- }
+ bfa_ioc_sync_leave(ioc);
+ writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
+ bfa_nw_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail);
+ break;
+
+ case IOCPF_E_SEM_ERROR:
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
+ bfa_ioc_pf_hwfailed(ioc);
break;
case IOCPF_E_DISABLE:
@@ -1020,7 +1044,6 @@ bfa_iocpf_sm_initfail_sync(struct bfa_iocpf *iocpf, enum iocpf_event event)
static void
bfa_iocpf_sm_initfail_entry(struct bfa_iocpf *iocpf)
{
- bfa_ioc_pf_initfailed(iocpf->ioc);
}
/**
@@ -1071,11 +1094,11 @@ bfa_iocpf_sm_fail_sync(struct bfa_iocpf *iocpf, enum iocpf_event event)
switch (event) {
case IOCPF_E_SEMLOCKED:
- iocpf->retry_count = 0;
bfa_ioc_sync_ack(ioc);
bfa_ioc_notify_fail(ioc);
if (!iocpf->auto_recover) {
bfa_ioc_sync_leave(ioc);
+ writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
bfa_nw_ioc_hw_sem_release(ioc);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
} else {
@@ -1088,6 +1111,11 @@ bfa_iocpf_sm_fail_sync(struct bfa_iocpf *iocpf, enum iocpf_event event)
}
break;
+ case IOCPF_E_SEM_ERROR:
+ bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
+ bfa_ioc_pf_hwfailed(ioc);
+ break;
+
case IOCPF_E_DISABLE:
bfa_ioc_hw_sem_get_cancel(ioc);
bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
@@ -1158,22 +1186,22 @@ bfa_nw_ioc_sem_get(void __iomem *sem_reg)
r32 = readl(sem_reg);
- while (r32 && (cnt < BFA_SEM_SPINCNT)) {
+ while ((r32 & 1) && (cnt < BFA_SEM_SPINCNT)) {
cnt++;
udelay(2);
r32 = readl(sem_reg);
}
- if (r32 == 0)
+ if (!(r32 & 1))
return true;
- BUG_ON(!(cnt < BFA_SEM_SPINCNT));
return false;
}
void
bfa_nw_ioc_sem_release(void __iomem *sem_reg)
{
+ readl(sem_reg);
writel(1, sem_reg);
}
@@ -1210,7 +1238,11 @@ bfa_ioc_hw_sem_get(struct bfa_ioc *ioc)
* will return 1. Semaphore is released by writing 1 to the register
*/
r32 = readl(ioc->ioc_regs.ioc_sem_reg);
- if (r32 == 0) {
+ if (r32 == ~0) {
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_SEM_ERROR);
+ return;
+ }
+ if (!(r32 & 1)) {
bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_SEMLOCKED);
return;
}
@@ -1331,7 +1363,7 @@ bfa_nw_ioc_fwver_cmp(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr)
int i;
drv_fwhdr = (struct bfi_ioc_image_hdr *)
- bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), 0);
+ bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0);
for (i = 0; i < BFI_IOC_MD5SUM_SZ; i++) {
if (fwhdr->md5sum[i] != drv_fwhdr->md5sum[i])
@@ -1352,12 +1384,12 @@ bfa_ioc_fwver_valid(struct bfa_ioc *ioc, u32 boot_env)
bfa_nw_ioc_fwver_get(ioc, &fwhdr);
drv_fwhdr = (struct bfi_ioc_image_hdr *)
- bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), 0);
+ bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0);
if (fwhdr.signature != drv_fwhdr->signature)
return false;
- if (swab32(fwhdr.param) != boot_env)
+ if (swab32(fwhdr.bootenv) != boot_env)
return false;
return bfa_nw_ioc_fwver_cmp(ioc, &fwhdr);
@@ -1388,11 +1420,11 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force)
ioc_fwstate = readl(ioc->ioc_regs.ioc_fwstate);
- boot_env = BFI_BOOT_LOADER_OS;
-
if (force)
ioc_fwstate = BFI_IOC_UNINIT;
+ boot_env = BFI_FWBOOT_ENV_OS;
+
/**
* check if firmware is valid
*/
@@ -1400,7 +1432,8 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force)
false : bfa_ioc_fwver_valid(ioc, boot_env);
if (!fwvalid) {
- bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, boot_env);
+ bfa_ioc_boot(ioc, BFI_FWBOOT_TYPE_NORMAL, boot_env);
+ bfa_ioc_poll_fwinit(ioc);
return;
}
@@ -1409,7 +1442,7 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force)
* just wait for an initialization completion interrupt.
*/
if (ioc_fwstate == BFI_IOC_INITING) {
- ioc->cbfn->reset_cbfn(ioc->bfa);
+ bfa_ioc_poll_fwinit(ioc);
return;
}
@@ -1423,7 +1456,6 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force)
* be flushed. Otherwise MSI-X interrupts are not delivered.
*/
bfa_ioc_msgflush(ioc);
- ioc->cbfn->reset_cbfn(ioc->bfa);
bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FWREADY);
return;
}
@@ -1431,7 +1463,8 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force)
/**
* Initialize the h/w for any other states.
*/
- bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, boot_env);
+ bfa_ioc_boot(ioc, BFI_FWBOOT_TYPE_NORMAL, boot_env);
+ bfa_ioc_poll_fwinit(ioc);
}
void
@@ -1475,7 +1508,7 @@ bfa_ioc_send_enable(struct bfa_ioc *ioc)
bfi_h2i_set(enable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_ENABLE_REQ,
bfa_ioc_portid(ioc));
- enable_req.ioc_class = ioc->ioc_mc;
+ enable_req.clscode = htons(ioc->clscode);
do_gettimeofday(&tv);
enable_req.tv_sec = ntohl(tv.tv_sec);
bfa_ioc_mbox_send(ioc, &enable_req, sizeof(struct bfi_ioc_ctrl_req));
@@ -1548,22 +1581,23 @@ bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type,
u32 loff = 0;
u32 chunkno = 0;
u32 i;
+ u32 asicmode;
/**
* Initialize LMEM first before code download
*/
bfa_ioc_lmem_init(ioc);
- fwimg = bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), chunkno);
+ fwimg = bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), chunkno);
pgnum = bfa_ioc_smem_pgnum(ioc, loff);
writel(pgnum, ioc->ioc_regs.host_page_num_fn);
- for (i = 0; i < bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)); i++) {
+ for (i = 0; i < bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc)); i++) {
if (BFA_IOC_FLASH_CHUNK_NO(i) != chunkno) {
chunkno = BFA_IOC_FLASH_CHUNK_NO(i);
- fwimg = bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc),
+ fwimg = bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc),
BFA_IOC_FLASH_CHUNK_ADDR(chunkno));
}
@@ -1590,12 +1624,16 @@ bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type,
ioc->ioc_regs.host_page_num_fn);
/*
- * Set boot type and boot param at the end.
+ * Set boot type, env and device mode at the end.
*/
+ asicmode = BFI_FWBOOT_DEVMODE(ioc->asic_gen, ioc->asic_mode,
+ ioc->port0_mode, ioc->port1_mode);
+ writel(asicmode, ((ioc->ioc_regs.smem_page_start)
+ + BFI_FWBOOT_DEVMODE_OFF));
writel(boot_type, ((ioc->ioc_regs.smem_page_start)
- + (BFI_BOOT_TYPE_OFF)));
+ + (BFI_FWBOOT_TYPE_OFF)));
writel(boot_env, ((ioc->ioc_regs.smem_page_start)
- + (BFI_BOOT_LOADER_OFF)));
+ + (BFI_FWBOOT_ENV_OFF)));
}
static void
@@ -1605,6 +1643,20 @@ bfa_ioc_reset(struct bfa_ioc *ioc, bool force)
}
/**
+ * BFA ioc enable reply by firmware
+ */
+static void
+bfa_ioc_enable_reply(struct bfa_ioc *ioc, enum bfa_mode port_mode,
+ u8 cap_bm)
+{
+ struct bfa_iocpf *iocpf = &ioc->iocpf;
+
+ ioc->port_mode = ioc->port_mode_cfg = port_mode;
+ ioc->ad_cap_bm = cap_bm;
+ bfa_fsm_send_event(iocpf, IOCPF_E_FWRSP_ENABLE);
+}
+
+/**
* @brief
* Update BFA configuration from firmware configuration.
*/
@@ -1644,7 +1696,9 @@ bfa_ioc_mbox_poll(struct bfa_ioc *ioc)
{
struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
struct bfa_mbox_cmd *cmd;
- u32 stat;
+ bfa_mbox_cmd_cbfn_t cbfn;
+ void *cbarg;
+ u32 stat;
/**
* If no command pending, do nothing
@@ -1664,6 +1718,16 @@ bfa_ioc_mbox_poll(struct bfa_ioc *ioc)
*/
bfa_q_deq(&mod->cmd_q, &cmd);
bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
+
+ /**
+ * Give a callback to the client, indicating that the command is sent
+ */
+ if (cmd->cbfn) {
+ cbfn = cmd->cbfn;
+ cbarg = cmd->cbarg;
+ cmd->cbfn = NULL;
+ cbfn(cbarg);
+ }
}
/**
@@ -1689,6 +1753,9 @@ bfa_ioc_fail_notify(struct bfa_ioc *ioc)
bfa_ioc_event_notify(ioc, BFA_IOC_E_FAILED);
}
+/**
+ * IOCPF to IOC interface
+ */
static void
bfa_ioc_pf_enabled(struct bfa_ioc *ioc)
{
@@ -1702,15 +1769,15 @@ bfa_ioc_pf_disabled(struct bfa_ioc *ioc)
}
static void
-bfa_ioc_pf_initfailed(struct bfa_ioc *ioc)
+bfa_ioc_pf_failed(struct bfa_ioc *ioc)
{
- bfa_fsm_send_event(ioc, IOC_E_INITFAILED);
+ bfa_fsm_send_event(ioc, IOC_E_PFFAILED);
}
static void
-bfa_ioc_pf_failed(struct bfa_ioc *ioc)
+bfa_ioc_pf_hwfailed(struct bfa_ioc *ioc)
{
- bfa_fsm_send_event(ioc, IOC_E_PFFAILED);
+ bfa_fsm_send_event(ioc, IOC_E_HWFAILED);
}
static void
@@ -1749,10 +1816,9 @@ bfa_ioc_pll_init(struct bfa_ioc *ioc)
* as the entry vector.
*/
static void
-bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_env)
+bfa_ioc_boot(struct bfa_ioc *ioc, enum bfi_fwboot_type boot_type,
+ u32 boot_env)
{
- void __iomem *rb;
-
bfa_ioc_stats(ioc, ioc_boots);
if (bfa_ioc_pll_init(ioc) != BFA_STATUS_OK)
@@ -1761,22 +1827,16 @@ bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_env)
/**
* Initialize IOC state of all functions on a chip reset.
*/
- rb = ioc->pcidev.pci_bar_kva;
- if (boot_type == BFI_BOOT_TYPE_MEMTEST) {
- writel(BFI_IOC_MEMTEST, (rb + BFA_IOC0_STATE_REG));
- writel(BFI_IOC_MEMTEST, (rb + BFA_IOC1_STATE_REG));
+ if (boot_type == BFI_FWBOOT_TYPE_MEMTEST) {
+ writel(BFI_IOC_MEMTEST, ioc->ioc_regs.ioc_fwstate);
+ writel(BFI_IOC_MEMTEST, ioc->ioc_regs.alt_ioc_fwstate);
} else {
- writel(BFI_IOC_INITING, (rb + BFA_IOC0_STATE_REG));
- writel(BFI_IOC_INITING, (rb + BFA_IOC1_STATE_REG));
+ writel(BFI_IOC_INITING, ioc->ioc_regs.ioc_fwstate);
+ writel(BFI_IOC_INITING, ioc->ioc_regs.alt_ioc_fwstate);
}
bfa_ioc_msgflush(ioc);
bfa_ioc_download_fw(ioc, boot_type, boot_env);
-
- /**
- * Enable interrupts just before starting LPU
- */
- ioc->cbfn->reset_cbfn(ioc->bfa);
bfa_ioc_lpu_start(ioc);
}
@@ -1789,13 +1849,17 @@ bfa_nw_ioc_auto_recover(bool auto_recover)
bfa_nw_auto_recover = auto_recover;
}
-static void
+static bool
bfa_ioc_msgget(struct bfa_ioc *ioc, void *mbmsg)
{
u32 *msgp = mbmsg;
u32 r32;
int i;
+ r32 = readl(ioc->ioc_regs.lpu_mbox_cmd);
+ if ((r32 & 1) == 0)
+ return false;
+
/**
* read the MBOX msg
*/
@@ -1811,6 +1875,8 @@ bfa_ioc_msgget(struct bfa_ioc *ioc, void *mbmsg)
*/
writel(1, ioc->ioc_regs.lpu_mbox_cmd);
readl(ioc->ioc_regs.lpu_mbox_cmd);
+
+ return true;
}
static void
@@ -1827,12 +1893,10 @@ bfa_ioc_isr(struct bfa_ioc *ioc, struct bfi_mbmsg *m)
case BFI_IOC_I2H_HBEAT:
break;
- case BFI_IOC_I2H_READY_EVENT:
- bfa_fsm_send_event(iocpf, IOCPF_E_FWREADY);
- break;
-
case BFI_IOC_I2H_ENABLE_REPLY:
- bfa_fsm_send_event(iocpf, IOCPF_E_FWRSP_ENABLE);
+ bfa_ioc_enable_reply(ioc,
+ (enum bfa_mode)msg->fw_event.port_mode,
+ msg->fw_event.cap_bm);
break;
case BFI_IOC_I2H_DISABLE_REPLY:
@@ -1878,6 +1942,9 @@ void
bfa_nw_ioc_detach(struct bfa_ioc *ioc)
{
bfa_fsm_send_event(ioc, IOC_E_DETACH);
+
+ /* Done with detach, empty the notify_q. */
+ INIT_LIST_HEAD(&ioc->notify_q);
}
/**
@@ -1887,14 +1954,63 @@ bfa_nw_ioc_detach(struct bfa_ioc *ioc)
*/
void
bfa_nw_ioc_pci_init(struct bfa_ioc *ioc, struct bfa_pcidev *pcidev,
- enum bfi_mclass mc)
+ enum bfi_pcifn_class clscode)
{
- ioc->ioc_mc = mc;
+ ioc->clscode = clscode;
ioc->pcidev = *pcidev;
- ioc->ctdev = bfa_asic_id_ct(ioc->pcidev.device_id);
- ioc->cna = ioc->ctdev && !ioc->fcmode;
- bfa_nw_ioc_set_ct_hwif(ioc);
+ /**
+ * Initialize IOC and device personality
+ */
+ ioc->port0_mode = ioc->port1_mode = BFI_PORT_MODE_FC;
+ ioc->asic_mode = BFI_ASIC_MODE_FC;
+
+ switch (pcidev->device_id) {
+ case PCI_DEVICE_ID_BROCADE_CT:
+ ioc->asic_gen = BFI_ASIC_GEN_CT;
+ ioc->port0_mode = ioc->port1_mode = BFI_PORT_MODE_ETH;
+ ioc->asic_mode = BFI_ASIC_MODE_ETH;
+ ioc->port_mode = ioc->port_mode_cfg = BFA_MODE_CNA;
+ ioc->ad_cap_bm = BFA_CM_CNA;
+ break;
+
+ case BFA_PCI_DEVICE_ID_CT2:
+ ioc->asic_gen = BFI_ASIC_GEN_CT2;
+ if (clscode == BFI_PCIFN_CLASS_FC &&
+ pcidev->ssid == BFA_PCI_CT2_SSID_FC) {
+ ioc->asic_mode = BFI_ASIC_MODE_FC16;
+ ioc->fcmode = true;
+ ioc->port_mode = ioc->port_mode_cfg = BFA_MODE_HBA;
+ ioc->ad_cap_bm = BFA_CM_HBA;
+ } else {
+ ioc->port0_mode = ioc->port1_mode = BFI_PORT_MODE_ETH;
+ ioc->asic_mode = BFI_ASIC_MODE_ETH;
+ if (pcidev->ssid == BFA_PCI_CT2_SSID_FCoE) {
+ ioc->port_mode =
+ ioc->port_mode_cfg = BFA_MODE_CNA;
+ ioc->ad_cap_bm = BFA_CM_CNA;
+ } else {
+ ioc->port_mode =
+ ioc->port_mode_cfg = BFA_MODE_NIC;
+ ioc->ad_cap_bm = BFA_CM_NIC;
+ }
+ }
+ break;
+
+ default:
+ BUG_ON(1);
+ }
+
+ /**
+ * Set asic specific interfaces.
+ */
+ if (ioc->asic_gen == BFI_ASIC_GEN_CT)
+ bfa_nw_ioc_set_ct_hwif(ioc);
+ else {
+ WARN_ON(ioc->asic_gen != BFI_ASIC_GEN_CT2);
+ bfa_nw_ioc_set_ct2_hwif(ioc);
+ bfa_nw_ioc_ct2_poweron(ioc);
+ }
bfa_ioc_map_port(ioc);
bfa_ioc_reg_init(ioc);
@@ -1968,18 +2084,22 @@ bfa_nw_ioc_mbox_regisr(struct bfa_ioc *ioc, enum bfi_mclass mc,
* @param[in] ioc IOC instance
* @param[i] cmd Mailbox command
*/
-void
-bfa_nw_ioc_mbox_queue(struct bfa_ioc *ioc, struct bfa_mbox_cmd *cmd)
+bool
+bfa_nw_ioc_mbox_queue(struct bfa_ioc *ioc, struct bfa_mbox_cmd *cmd,
+ bfa_mbox_cmd_cbfn_t cbfn, void *cbarg)
{
struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
u32 stat;
+ cmd->cbfn = cbfn;
+ cmd->cbarg = cbarg;
+
/**
* If a previous command is pending, queue new command
*/
if (!list_empty(&mod->cmd_q)) {
list_add_tail(&cmd->qe, &mod->cmd_q);
- return;
+ return true;
}
/**
@@ -1988,7 +2108,7 @@ bfa_nw_ioc_mbox_queue(struct bfa_ioc *ioc, struct bfa_mbox_cmd *cmd)
stat = readl(ioc->ioc_regs.hfn_mbox_cmd);
if (stat) {
list_add_tail(&cmd->qe, &mod->cmd_q);
- return;
+ return true;
}
/**
@@ -1996,7 +2116,7 @@ bfa_nw_ioc_mbox_queue(struct bfa_ioc *ioc, struct bfa_mbox_cmd *cmd)
*/
bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
- return;
+ return false;
}
/**
@@ -2009,21 +2129,28 @@ bfa_nw_ioc_mbox_isr(struct bfa_ioc *ioc)
struct bfi_mbmsg m;
int mc;
- bfa_ioc_msgget(ioc, &m);
+ if (bfa_ioc_msgget(ioc, &m)) {
+ /**
+ * Treat IOC message class as special.
+ */
+ mc = m.mh.msg_class;
+ if (mc == BFI_MC_IOC) {
+ bfa_ioc_isr(ioc, &m);
+ return;
+ }
- /**
- * Treat IOC message class as special.
- */
- mc = m.mh.msg_class;
- if (mc == BFI_MC_IOC) {
- bfa_ioc_isr(ioc, &m);
- return;
+ if ((mc >= BFI_MC_MAX) || (mod->mbhdlr[mc].cbfn == NULL))
+ return;
+
+ mod->mbhdlr[mc].cbfn(mod->mbhdlr[mc].cbarg, &m);
}
- if ((mc >= BFI_MC_MAX) || (mod->mbhdlr[mc].cbfn == NULL))
- return;
+ bfa_ioc_lpu_read_stat(ioc);
- mod->mbhdlr[mc].cbfn(mod->mbhdlr[mc].cbarg, &m);
+ /**
+ * Try to send pending mailbox commands
+ */
+ bfa_ioc_mbox_poll(ioc);
}
void
@@ -2095,24 +2222,18 @@ bfa_ioc_get_adapter_attr(struct bfa_ioc *ioc,
ad_attr->asic_rev = ioc_attr->asic_rev;
bfa_ioc_get_pci_chip_rev(ioc, ad_attr->hw_ver);
-
- ad_attr->cna_capable = ioc->cna;
- ad_attr->trunk_capable = (ad_attr->nports > 1) && !ioc->cna;
}
static enum bfa_ioc_type
bfa_ioc_get_type(struct bfa_ioc *ioc)
{
- if (!ioc->ctdev || ioc->fcmode)
- return BFA_IOC_TYPE_FC;
- else if (ioc->ioc_mc == BFI_MC_IOCFC)
- return BFA_IOC_TYPE_FCoE;
- else if (ioc->ioc_mc == BFI_MC_LL)
- return BFA_IOC_TYPE_LL;
- else {
- BUG_ON(!(ioc->ioc_mc == BFI_MC_LL));
+ if (ioc->clscode == BFI_PCIFN_CLASS_ETH)
return BFA_IOC_TYPE_LL;
- }
+
+ BUG_ON(!(ioc->clscode == BFI_PCIFN_CLASS_FC));
+
+ return (ioc->attr->port_mode == BFI_PORT_MODE_FC)
+ ? BFA_IOC_TYPE_FC : BFA_IOC_TYPE_FCoE;
}
static void
@@ -2171,9 +2292,6 @@ bfa_ioc_get_adapter_model(struct bfa_ioc *ioc, char *model)
ioc_attr = ioc->attr;
- /**
- * model name
- */
snprintf(model, BFA_ADAPTER_MODEL_NAME_LEN, "%s-%u",
BFA_MFG_NAME, ioc_attr->card_type);
}
@@ -2224,6 +2342,10 @@ bfa_nw_ioc_get_attr(struct bfa_ioc *ioc, struct bfa_ioc_attr *ioc_attr)
ioc_attr->state = bfa_ioc_get_state(ioc);
ioc_attr->port_id = ioc->port_id;
+ ioc_attr->port_mode = ioc->port_mode;
+
+ ioc_attr->port_mode_cfg = ioc->port_mode_cfg;
+ ioc_attr->cap_bm = ioc->ad_cap_bm;
ioc_attr->ioc_type = bfa_ioc_get_type(ioc);
@@ -2313,8 +2435,14 @@ void
bfa_nw_iocpf_timeout(void *ioc_arg)
{
struct bfa_ioc *ioc = (struct bfa_ioc *) ioc_arg;
+ enum bfa_iocpf_state iocpf_st;
+
+ iocpf_st = bfa_sm_to_state(iocpf_sm_table, ioc->iocpf.fsm);
- bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_TIMEOUT);
+ if (iocpf_st == BFA_IOCPF_HWINIT)
+ bfa_ioc_poll_fwinit(ioc);
+ else
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_TIMEOUT);
}
void
@@ -2324,3 +2452,22 @@ bfa_nw_iocpf_sem_timeout(void *ioc_arg)
bfa_ioc_hw_sem_get(ioc);
}
+
+static void
+bfa_ioc_poll_fwinit(struct bfa_ioc *ioc)
+{
+ u32 fwstate = readl(ioc->ioc_regs.ioc_fwstate);
+
+ if (fwstate == BFI_IOC_DISABLED) {
+ bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FWREADY);
+ return;
+ }
+
+ if (ioc->iocpf.poll_time >= BFA_IOC_TOV) {
+ bfa_nw_iocpf_timeout(ioc);
+ } else {
+ ioc->iocpf.poll_time += BFA_IOC_POLL_TOV;
+ mod_timer(&ioc->iocpf_timer, jiffies +
+ msecs_to_jiffies(BFA_IOC_POLL_TOV));
+ }
+}
diff --git a/drivers/net/bna/bfa_ioc.h b/drivers/net/ethernet/brocade/bna/bfa_ioc.h
index bda866ba6e90..ca158d1eaef3 100644
--- a/drivers/net/bna/bfa_ioc.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_ioc.h
@@ -26,7 +26,7 @@
#define BFA_IOC_TOV 3000 /* msecs */
#define BFA_IOC_HWSEM_TOV 500 /* msecs */
#define BFA_IOC_HB_TOV 500 /* msecs */
-#define BFA_IOC_HWINIT_MAX 5
+#define BFA_IOC_POLL_TOV 200 /* msecs */
/**
* PCI device information required by IOC
@@ -35,6 +35,7 @@ struct bfa_pcidev {
int pci_slot;
u8 pci_func;
u16 device_id;
+ u16 ssid;
void __iomem *pci_bar_kva;
};
@@ -72,6 +73,7 @@ struct bfa_ioc_regs {
void __iomem *hfn_mbox;
void __iomem *lpu_mbox_cmd;
void __iomem *lpu_mbox;
+ void __iomem *lpu_read_stat;
void __iomem *pss_ctl_reg;
void __iomem *pss_err_status_reg;
void __iomem *app_pll_fast_ctl_reg;
@@ -150,16 +152,7 @@ struct bfa_ioc_notify {
};
/**
- * Heartbeat failure notification queue element.
- */
-struct bfa_ioc_hbfail_notify {
- struct list_head qe;
- bfa_ioc_hbfail_cbfn_t cbfn;
- void *cbarg;
-};
-
-/**
- * Initialize a heartbeat failure notification structure
+ * Initialize a IOC event notification structure
*/
#define bfa_ioc_notify_init(__notify, __cbfn, __cbarg) do { \
(__notify)->cbfn = (__cbfn); \
@@ -169,8 +162,9 @@ struct bfa_ioc_hbfail_notify {
struct bfa_iocpf {
bfa_fsm_t fsm;
struct bfa_ioc *ioc;
- u32 retry_count;
+ bool fw_mismatch_notified;
bool auto_recover;
+ u32 poll_time;
};
struct bfa_ioc {
@@ -186,12 +180,10 @@ struct bfa_ioc {
void *dbg_fwsave;
int dbg_fwsave_len;
bool dbg_fwsave_once;
- enum bfi_mclass ioc_mc;
+ enum bfi_pcifn_class clscode;
struct bfa_ioc_regs ioc_regs;
struct bfa_ioc_drv_stats stats;
bool fcmode;
- bool ctdev;
- bool cna;
bool pllinit;
bool stats_busy; /*!< outstanding stats */
u8 port_id;
@@ -200,12 +192,20 @@ struct bfa_ioc {
struct bfi_ioc_attr *attr;
struct bfa_ioc_cbfn *cbfn;
struct bfa_ioc_mbox_mod mbox_mod;
- struct bfa_ioc_hwif *ioc_hwif;
+ const struct bfa_ioc_hwif *ioc_hwif;
struct bfa_iocpf iocpf;
+ enum bfi_asic_gen asic_gen;
+ enum bfi_asic_mode asic_mode;
+ enum bfi_port_mode port0_mode;
+ enum bfi_port_mode port1_mode;
+ enum bfa_mode port_mode;
+ u8 ad_cap_bm; /*!< adapter cap bit mask */
+ u8 port_mode_cfg; /*!< config port mode */
};
struct bfa_ioc_hwif {
- enum bfa_status (*ioc_pll_init) (void __iomem *rb, bool fcmode);
+ enum bfa_status (*ioc_pll_init) (void __iomem *rb,
+ enum bfi_asic_mode m);
bool (*ioc_firmware_lock) (struct bfa_ioc *ioc);
void (*ioc_firmware_unlock) (struct bfa_ioc *ioc);
void (*ioc_reg_init) (struct bfa_ioc *ioc);
@@ -219,12 +219,14 @@ struct bfa_ioc_hwif {
void (*ioc_sync_leave) (struct bfa_ioc *ioc);
void (*ioc_sync_ack) (struct bfa_ioc *ioc);
bool (*ioc_sync_complete) (struct bfa_ioc *ioc);
+ bool (*ioc_lpu_read_stat) (struct bfa_ioc *ioc);
};
#define bfa_ioc_pcifn(__ioc) ((__ioc)->pcidev.pci_func)
#define bfa_ioc_devid(__ioc) ((__ioc)->pcidev.device_id)
#define bfa_ioc_bar0(__ioc) ((__ioc)->pcidev.pci_bar_kva)
#define bfa_ioc_portid(__ioc) ((__ioc)->port_id)
+#define bfa_ioc_asic_gen(__ioc) ((__ioc)->asic_gen)
#define bfa_ioc_fetch_stats(__ioc, __stats) \
(((__stats)->drv_stats) = (__ioc)->stats)
#define bfa_ioc_clr_stats(__ioc) \
@@ -240,12 +242,9 @@ struct bfa_ioc_hwif {
#define bfa_ioc_stats_hb_count(_ioc, _hb_count) \
((_ioc)->stats.hb_count = (_hb_count))
#define BFA_IOC_FWIMG_MINSZ (16 * 1024)
-#define BFA_IOC_FWIMG_TYPE(__ioc) \
- (((__ioc)->ctdev) ? \
- (((__ioc)->fcmode) ? BFI_IMAGE_CT_FC : BFI_IMAGE_CT_CNA) : \
- BFI_IMAGE_CB_FC)
#define BFA_IOC_FW_SMEM_SIZE(__ioc) \
- (((__ioc)->ctdev) ? BFI_SMEM_CT_SIZE : BFI_SMEM_CB_SIZE)
+ ((bfa_ioc_asic_gen(__ioc) == BFI_ASIC_GEN_CB) \
+ ? BFI_SMEM_CB_SIZE : BFI_SMEM_CT_SIZE)
#define BFA_IOC_FLASH_CHUNK_NO(off) (off / BFI_FLASH_CHUNK_SZ_WORDS)
#define BFA_IOC_FLASH_OFFSET_IN_CHUNK(off) (off % BFI_FLASH_CHUNK_SZ_WORDS)
#define BFA_IOC_FLASH_CHUNK_ADDR(chunkno) (chunkno * BFI_FLASH_CHUNK_SZ_WORDS)
@@ -253,7 +252,9 @@ struct bfa_ioc_hwif {
/**
* IOC mailbox interface
*/
-void bfa_nw_ioc_mbox_queue(struct bfa_ioc *ioc, struct bfa_mbox_cmd *cmd);
+bool bfa_nw_ioc_mbox_queue(struct bfa_ioc *ioc,
+ struct bfa_mbox_cmd *cmd,
+ bfa_mbox_cmd_cbfn_t cbfn, void *cbarg);
void bfa_nw_ioc_mbox_isr(struct bfa_ioc *ioc);
void bfa_nw_ioc_mbox_regisr(struct bfa_ioc *ioc, enum bfi_mclass mc,
bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg);
@@ -264,21 +265,30 @@ void bfa_nw_ioc_mbox_regisr(struct bfa_ioc *ioc, enum bfi_mclass mc,
#define bfa_ioc_pll_init_asic(__ioc) \
((__ioc)->ioc_hwif->ioc_pll_init((__ioc)->pcidev.pci_bar_kva, \
- (__ioc)->fcmode))
+ (__ioc)->asic_mode))
-#define bfa_ioc_isr_mode_set(__ioc, __msix) \
- ((__ioc)->ioc_hwif->ioc_isr_mode_set(__ioc, __msix))
+#define bfa_ioc_isr_mode_set(__ioc, __msix) do { \
+ if ((__ioc)->ioc_hwif->ioc_isr_mode_set) \
+ ((__ioc)->ioc_hwif->ioc_isr_mode_set(__ioc, __msix)); \
+} while (0)
#define bfa_ioc_ownership_reset(__ioc) \
((__ioc)->ioc_hwif->ioc_ownership_reset(__ioc))
+#define bfa_ioc_lpu_read_stat(__ioc) do { \
+ if ((__ioc)->ioc_hwif->ioc_lpu_read_stat) \
+ ((__ioc)->ioc_hwif->ioc_lpu_read_stat(__ioc)); \
+} while (0)
+
void bfa_nw_ioc_set_ct_hwif(struct bfa_ioc *ioc);
+void bfa_nw_ioc_set_ct2_hwif(struct bfa_ioc *ioc);
+void bfa_nw_ioc_ct2_poweron(struct bfa_ioc *ioc);
void bfa_nw_ioc_attach(struct bfa_ioc *ioc, void *bfa,
struct bfa_ioc_cbfn *cbfn);
void bfa_nw_ioc_auto_recover(bool auto_recover);
void bfa_nw_ioc_detach(struct bfa_ioc *ioc);
void bfa_nw_ioc_pci_init(struct bfa_ioc *ioc, struct bfa_pcidev *pcidev,
- enum bfi_mclass mc);
+ enum bfi_pcifn_class clscode);
u32 bfa_nw_ioc_meminfo(void);
void bfa_nw_ioc_mem_claim(struct bfa_ioc *ioc, u8 *dm_kva, u64 dm_pa);
void bfa_nw_ioc_enable(struct bfa_ioc *ioc);
@@ -309,7 +319,7 @@ void bfa_nw_iocpf_sem_timeout(void *ioc);
/*
* F/W Image Size & Chunk
*/
-u32 *bfa_cb_image_get_chunk(int type, u32 off);
-u32 bfa_cb_image_get_size(int type);
+u32 *bfa_cb_image_get_chunk(enum bfi_asic_gen asic_gen, u32 off);
+u32 bfa_cb_image_get_size(enum bfi_asic_gen asic_gen);
#endif /* __BFA_IOC_H__ */
diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc_ct.c b/drivers/net/ethernet/brocade/bna/bfa_ioc_ct.c
new file mode 100644
index 000000000000..348479bbfa3a
--- /dev/null
+++ b/drivers/net/ethernet/brocade/bna/bfa_ioc_ct.c
@@ -0,0 +1,878 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#include "bfa_ioc.h"
+#include "cna.h"
+#include "bfi.h"
+#include "bfi_reg.h"
+#include "bfa_defs.h"
+
+#define bfa_ioc_ct_sync_pos(__ioc) \
+ ((u32) (1 << bfa_ioc_pcifn(__ioc)))
+#define BFA_IOC_SYNC_REQD_SH 16
+#define bfa_ioc_ct_get_sync_ackd(__val) (__val & 0x0000ffff)
+#define bfa_ioc_ct_clear_sync_ackd(__val) (__val & 0xffff0000)
+#define bfa_ioc_ct_get_sync_reqd(__val) (__val >> BFA_IOC_SYNC_REQD_SH)
+#define bfa_ioc_ct_sync_reqd_pos(__ioc) \
+ (bfa_ioc_ct_sync_pos(__ioc) << BFA_IOC_SYNC_REQD_SH)
+
+/*
+ * forward declarations
+ */
+static bool bfa_ioc_ct_firmware_lock(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_firmware_unlock(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_reg_init(struct bfa_ioc *ioc);
+static void bfa_ioc_ct2_reg_init(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_map_port(struct bfa_ioc *ioc);
+static void bfa_ioc_ct2_map_port(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc *ioc, bool msix);
+static void bfa_ioc_ct_notify_fail(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_ownership_reset(struct bfa_ioc *ioc);
+static bool bfa_ioc_ct_sync_start(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_sync_join(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_sync_leave(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_sync_ack(struct bfa_ioc *ioc);
+static bool bfa_ioc_ct_sync_complete(struct bfa_ioc *ioc);
+static enum bfa_status bfa_ioc_ct_pll_init(void __iomem *rb,
+ enum bfi_asic_mode asic_mode);
+static enum bfa_status bfa_ioc_ct2_pll_init(void __iomem *rb,
+ enum bfi_asic_mode asic_mode);
+static bool bfa_ioc_ct2_lpu_read_stat(struct bfa_ioc *ioc);
+
+static const struct bfa_ioc_hwif nw_hwif_ct = {
+ .ioc_pll_init = bfa_ioc_ct_pll_init,
+ .ioc_firmware_lock = bfa_ioc_ct_firmware_lock,
+ .ioc_firmware_unlock = bfa_ioc_ct_firmware_unlock,
+ .ioc_reg_init = bfa_ioc_ct_reg_init,
+ .ioc_map_port = bfa_ioc_ct_map_port,
+ .ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set,
+ .ioc_notify_fail = bfa_ioc_ct_notify_fail,
+ .ioc_ownership_reset = bfa_ioc_ct_ownership_reset,
+ .ioc_sync_start = bfa_ioc_ct_sync_start,
+ .ioc_sync_join = bfa_ioc_ct_sync_join,
+ .ioc_sync_leave = bfa_ioc_ct_sync_leave,
+ .ioc_sync_ack = bfa_ioc_ct_sync_ack,
+ .ioc_sync_complete = bfa_ioc_ct_sync_complete,
+};
+
+static const struct bfa_ioc_hwif nw_hwif_ct2 = {
+ .ioc_pll_init = bfa_ioc_ct2_pll_init,
+ .ioc_firmware_lock = bfa_ioc_ct_firmware_lock,
+ .ioc_firmware_unlock = bfa_ioc_ct_firmware_unlock,
+ .ioc_reg_init = bfa_ioc_ct2_reg_init,
+ .ioc_map_port = bfa_ioc_ct2_map_port,
+ .ioc_lpu_read_stat = bfa_ioc_ct2_lpu_read_stat,
+ .ioc_isr_mode_set = NULL,
+ .ioc_notify_fail = bfa_ioc_ct_notify_fail,
+ .ioc_ownership_reset = bfa_ioc_ct_ownership_reset,
+ .ioc_sync_start = bfa_ioc_ct_sync_start,
+ .ioc_sync_join = bfa_ioc_ct_sync_join,
+ .ioc_sync_leave = bfa_ioc_ct_sync_leave,
+ .ioc_sync_ack = bfa_ioc_ct_sync_ack,
+ .ioc_sync_complete = bfa_ioc_ct_sync_complete,
+};
+
+/**
+ * Called from bfa_ioc_attach() to map asic specific calls.
+ */
+void
+bfa_nw_ioc_set_ct_hwif(struct bfa_ioc *ioc)
+{
+ ioc->ioc_hwif = &nw_hwif_ct;
+}
+
+void
+bfa_nw_ioc_set_ct2_hwif(struct bfa_ioc *ioc)
+{
+ ioc->ioc_hwif = &nw_hwif_ct2;
+}
+
+/**
+ * Return true if firmware of current driver matches the running firmware.
+ */
+static bool
+bfa_ioc_ct_firmware_lock(struct bfa_ioc *ioc)
+{
+ enum bfi_ioc_state ioc_fwstate;
+ u32 usecnt;
+ struct bfi_ioc_image_hdr fwhdr;
+
+ /**
+ * If bios boot (flash based) -- do not increment usage count
+ */
+ if (bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc)) <
+ BFA_IOC_FWIMG_MINSZ)
+ return true;
+
+ bfa_nw_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
+ usecnt = readl(ioc->ioc_regs.ioc_usage_reg);
+
+ /**
+ * If usage count is 0, always return TRUE.
+ */
+ if (usecnt == 0) {
+ writel(1, ioc->ioc_regs.ioc_usage_reg);
+ bfa_nw_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+ writel(0, ioc->ioc_regs.ioc_fail_sync);
+ return true;
+ }
+
+ ioc_fwstate = readl(ioc->ioc_regs.ioc_fwstate);
+
+ /**
+ * Use count cannot be non-zero and chip in uninitialized state.
+ */
+ BUG_ON(!(ioc_fwstate != BFI_IOC_UNINIT));
+
+ /**
+ * Check if another driver with a different firmware is active
+ */
+ bfa_nw_ioc_fwver_get(ioc, &fwhdr);
+ if (!bfa_nw_ioc_fwver_cmp(ioc, &fwhdr)) {
+ bfa_nw_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+ return false;
+ }
+
+ /**
+ * Same firmware version. Increment the reference count.
+ */
+ usecnt++;
+ writel(usecnt, ioc->ioc_regs.ioc_usage_reg);
+ bfa_nw_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+ return true;
+}
+
+static void
+bfa_ioc_ct_firmware_unlock(struct bfa_ioc *ioc)
+{
+ u32 usecnt;
+
+ /**
+ * If bios boot (flash based) -- do not decrement usage count
+ */
+ if (bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc)) <
+ BFA_IOC_FWIMG_MINSZ)
+ return;
+
+ /**
+ * decrement usage count
+ */
+ bfa_nw_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
+ usecnt = readl(ioc->ioc_regs.ioc_usage_reg);
+ BUG_ON(!(usecnt > 0));
+
+ usecnt--;
+ writel(usecnt, ioc->ioc_regs.ioc_usage_reg);
+
+ bfa_nw_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+}
+
+/**
+ * Notify other functions on HB failure.
+ */
+static void
+bfa_ioc_ct_notify_fail(struct bfa_ioc *ioc)
+{
+ writel(__FW_INIT_HALT_P, ioc->ioc_regs.ll_halt);
+ writel(__FW_INIT_HALT_P, ioc->ioc_regs.alt_ll_halt);
+ /* Wait for halt to take effect */
+ readl(ioc->ioc_regs.ll_halt);
+ readl(ioc->ioc_regs.alt_ll_halt);
+}
+
+/**
+ * Host to LPU mailbox message addresses
+ */
+static const struct {
+ u32 hfn_mbox;
+ u32 lpu_mbox;
+ u32 hfn_pgn;
+} ct_fnreg[] = {
+ { HOSTFN0_LPU_MBOX0_0, LPU_HOSTFN0_MBOX0_0, HOST_PAGE_NUM_FN0 },
+ { HOSTFN1_LPU_MBOX0_8, LPU_HOSTFN1_MBOX0_8, HOST_PAGE_NUM_FN1 },
+ { HOSTFN2_LPU_MBOX0_0, LPU_HOSTFN2_MBOX0_0, HOST_PAGE_NUM_FN2 },
+ { HOSTFN3_LPU_MBOX0_8, LPU_HOSTFN3_MBOX0_8, HOST_PAGE_NUM_FN3 }
+};
+
+/**
+ * Host <-> LPU mailbox command/status registers - port 0
+ */
+static const struct {
+ u32 hfn;
+ u32 lpu;
+} ct_p0reg[] = {
+ { HOSTFN0_LPU0_CMD_STAT, LPU0_HOSTFN0_CMD_STAT },
+ { HOSTFN1_LPU0_CMD_STAT, LPU0_HOSTFN1_CMD_STAT },
+ { HOSTFN2_LPU0_CMD_STAT, LPU0_HOSTFN2_CMD_STAT },
+ { HOSTFN3_LPU0_CMD_STAT, LPU0_HOSTFN3_CMD_STAT }
+};
+
+/**
+ * Host <-> LPU mailbox command/status registers - port 1
+ */
+static const struct {
+ u32 hfn;
+ u32 lpu;
+} ct_p1reg[] = {
+ { HOSTFN0_LPU1_CMD_STAT, LPU1_HOSTFN0_CMD_STAT },
+ { HOSTFN1_LPU1_CMD_STAT, LPU1_HOSTFN1_CMD_STAT },
+ { HOSTFN2_LPU1_CMD_STAT, LPU1_HOSTFN2_CMD_STAT },
+ { HOSTFN3_LPU1_CMD_STAT, LPU1_HOSTFN3_CMD_STAT }
+};
+
+static const struct {
+ u32 hfn_mbox;
+ u32 lpu_mbox;
+ u32 hfn_pgn;
+ u32 hfn;
+ u32 lpu;
+ u32 lpu_read;
+} ct2_reg[] = {
+ { CT2_HOSTFN_LPU0_MBOX0, CT2_LPU0_HOSTFN_MBOX0, CT2_HOSTFN_PAGE_NUM,
+ CT2_HOSTFN_LPU0_CMD_STAT, CT2_LPU0_HOSTFN_CMD_STAT,
+ CT2_HOSTFN_LPU0_READ_STAT},
+ { CT2_HOSTFN_LPU1_MBOX0, CT2_LPU1_HOSTFN_MBOX0, CT2_HOSTFN_PAGE_NUM,
+ CT2_HOSTFN_LPU1_CMD_STAT, CT2_LPU1_HOSTFN_CMD_STAT,
+ CT2_HOSTFN_LPU1_READ_STAT},
+};
+
+static void
+bfa_ioc_ct_reg_init(struct bfa_ioc *ioc)
+{
+ void __iomem *rb;
+ int pcifn = bfa_ioc_pcifn(ioc);
+
+ rb = bfa_ioc_bar0(ioc);
+
+ ioc->ioc_regs.hfn_mbox = rb + ct_fnreg[pcifn].hfn_mbox;
+ ioc->ioc_regs.lpu_mbox = rb + ct_fnreg[pcifn].lpu_mbox;
+ ioc->ioc_regs.host_page_num_fn = rb + ct_fnreg[pcifn].hfn_pgn;
+
+ if (ioc->port_id == 0) {
+ ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG;
+ ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG;
+ ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC1_STATE_REG;
+ ioc->ioc_regs.hfn_mbox_cmd = rb + ct_p0reg[pcifn].hfn;
+ ioc->ioc_regs.lpu_mbox_cmd = rb + ct_p0reg[pcifn].lpu;
+ ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0;
+ ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P1;
+ } else {
+ ioc->ioc_regs.heartbeat = rb + BFA_IOC1_HBEAT_REG;
+ ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC1_STATE_REG;
+ ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC0_STATE_REG;
+ ioc->ioc_regs.hfn_mbox_cmd = rb + ct_p1reg[pcifn].hfn;
+ ioc->ioc_regs.lpu_mbox_cmd = rb + ct_p1reg[pcifn].lpu;
+ ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1;
+ ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P0;
+ }
+
+ /*
+ * PSS control registers
+ */
+ ioc->ioc_regs.pss_ctl_reg = rb + PSS_CTL_REG;
+ ioc->ioc_regs.pss_err_status_reg = rb + PSS_ERR_STATUS_REG;
+ ioc->ioc_regs.app_pll_fast_ctl_reg = rb + APP_PLL_LCLK_CTL_REG;
+ ioc->ioc_regs.app_pll_slow_ctl_reg = rb + APP_PLL_SCLK_CTL_REG;
+
+ /*
+ * IOC semaphore registers and serialization
+ */
+ ioc->ioc_regs.ioc_sem_reg = rb + HOST_SEM0_REG;
+ ioc->ioc_regs.ioc_usage_sem_reg = rb + HOST_SEM1_REG;
+ ioc->ioc_regs.ioc_init_sem_reg = rb + HOST_SEM2_REG;
+ ioc->ioc_regs.ioc_usage_reg = rb + BFA_FW_USE_COUNT;
+ ioc->ioc_regs.ioc_fail_sync = rb + BFA_IOC_FAIL_SYNC;
+
+ /**
+ * sram memory access
+ */
+ ioc->ioc_regs.smem_page_start = rb + PSS_SMEM_PAGE_START;
+ ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CT;
+
+ /*
+ * err set reg : for notification of hb failure in fcmode
+ */
+ ioc->ioc_regs.err_set = (rb + ERR_SET_REG);
+}
+
+static void
+bfa_ioc_ct2_reg_init(struct bfa_ioc *ioc)
+{
+ void __iomem *rb;
+ int port = bfa_ioc_portid(ioc);
+
+ rb = bfa_ioc_bar0(ioc);
+
+ ioc->ioc_regs.hfn_mbox = rb + ct2_reg[port].hfn_mbox;
+ ioc->ioc_regs.lpu_mbox = rb + ct2_reg[port].lpu_mbox;
+ ioc->ioc_regs.host_page_num_fn = rb + ct2_reg[port].hfn_pgn;
+ ioc->ioc_regs.hfn_mbox_cmd = rb + ct2_reg[port].hfn;
+ ioc->ioc_regs.lpu_mbox_cmd = rb + ct2_reg[port].lpu;
+ ioc->ioc_regs.lpu_read_stat = rb + ct2_reg[port].lpu_read;
+
+ if (port == 0) {
+ ioc->ioc_regs.heartbeat = rb + CT2_BFA_IOC0_HBEAT_REG;
+ ioc->ioc_regs.ioc_fwstate = rb + CT2_BFA_IOC0_STATE_REG;
+ ioc->ioc_regs.alt_ioc_fwstate = rb + CT2_BFA_IOC1_STATE_REG;
+ ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0;
+ ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P1;
+ } else {
+ ioc->ioc_regs.heartbeat = rb + CT2_BFA_IOC1_HBEAT_REG;
+ ioc->ioc_regs.ioc_fwstate = rb + CT2_BFA_IOC1_STATE_REG;
+ ioc->ioc_regs.alt_ioc_fwstate = rb + CT2_BFA_IOC0_STATE_REG;
+ ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1;
+ ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P0;
+ }
+
+ /*
+ * PSS control registers
+ */
+ ioc->ioc_regs.pss_ctl_reg = rb + PSS_CTL_REG;
+ ioc->ioc_regs.pss_err_status_reg = rb + PSS_ERR_STATUS_REG;
+ ioc->ioc_regs.app_pll_fast_ctl_reg = rb + CT2_APP_PLL_LCLK_CTL_REG;
+ ioc->ioc_regs.app_pll_slow_ctl_reg = rb + CT2_APP_PLL_SCLK_CTL_REG;
+
+ /*
+ * IOC semaphore registers and serialization
+ */
+ ioc->ioc_regs.ioc_sem_reg = rb + CT2_HOST_SEM0_REG;
+ ioc->ioc_regs.ioc_usage_sem_reg = rb + CT2_HOST_SEM1_REG;
+ ioc->ioc_regs.ioc_init_sem_reg = rb + CT2_HOST_SEM2_REG;
+ ioc->ioc_regs.ioc_usage_reg = rb + CT2_BFA_FW_USE_COUNT;
+ ioc->ioc_regs.ioc_fail_sync = rb + CT2_BFA_IOC_FAIL_SYNC;
+
+ /**
+ * sram memory access
+ */
+ ioc->ioc_regs.smem_page_start = rb + PSS_SMEM_PAGE_START;
+ ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CT;
+
+ /*
+ * err set reg : for notification of hb failure in fcmode
+ */
+ ioc->ioc_regs.err_set = rb + ERR_SET_REG;
+}
+
+/**
+ * Initialize IOC to port mapping.
+ */
+
+#define FNC_PERS_FN_SHIFT(__fn) ((__fn) * 8)
+static void
+bfa_ioc_ct_map_port(struct bfa_ioc *ioc)
+{
+ void __iomem *rb = ioc->pcidev.pci_bar_kva;
+ u32 r32;
+
+ /**
+ * For catapult, base port id on personality register and IOC type
+ */
+ r32 = readl(rb + FNC_PERS_REG);
+ r32 >>= FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc));
+ ioc->port_id = (r32 & __F0_PORT_MAP_MK) >> __F0_PORT_MAP_SH;
+
+}
+
+static void
+bfa_ioc_ct2_map_port(struct bfa_ioc *ioc)
+{
+ void __iomem *rb = ioc->pcidev.pci_bar_kva;
+ u32 r32;
+
+ r32 = readl(rb + CT2_HOSTFN_PERSONALITY0);
+ ioc->port_id = ((r32 & __FC_LL_PORT_MAP__MK) >> __FC_LL_PORT_MAP__SH);
+}
+
+/**
+ * Set interrupt mode for a function: INTX or MSIX
+ */
+static void
+bfa_ioc_ct_isr_mode_set(struct bfa_ioc *ioc, bool msix)
+{
+ void __iomem *rb = ioc->pcidev.pci_bar_kva;
+ u32 r32, mode;
+
+ r32 = readl(rb + FNC_PERS_REG);
+
+ mode = (r32 >> FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc))) &
+ __F0_INTX_STATUS;
+
+ /**
+ * If already in desired mode, do not change anything
+ */
+ if ((!msix && mode) || (msix && !mode))
+ return;
+
+ if (msix)
+ mode = __F0_INTX_STATUS_MSIX;
+ else
+ mode = __F0_INTX_STATUS_INTA;
+
+ r32 &= ~(__F0_INTX_STATUS << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc)));
+ r32 |= (mode << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc)));
+
+ writel(r32, rb + FNC_PERS_REG);
+}
+
+static bool
+bfa_ioc_ct2_lpu_read_stat(struct bfa_ioc *ioc)
+{
+ u32 r32;
+
+ r32 = readl(ioc->ioc_regs.lpu_read_stat);
+ if (r32) {
+ writel(1, ioc->ioc_regs.lpu_read_stat);
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * MSI-X resource allocation for 1860 with no asic block
+ */
+#define HOSTFN_MSIX_DEFAULT 64
+#define HOSTFN_MSIX_VT_INDEX_MBOX_ERR 0x30138
+#define HOSTFN_MSIX_VT_OFST_NUMVT 0x3013c
+#define __MSIX_VT_NUMVT__MK 0x003ff800
+#define __MSIX_VT_NUMVT__SH 11
+#define __MSIX_VT_NUMVT_(_v) ((_v) << __MSIX_VT_NUMVT__SH)
+#define __MSIX_VT_OFST_ 0x000007ff
+void
+bfa_nw_ioc_ct2_poweron(struct bfa_ioc *ioc)
+{
+ void __iomem *rb = ioc->pcidev.pci_bar_kva;
+ u32 r32;
+
+ r32 = readl(rb + HOSTFN_MSIX_VT_OFST_NUMVT);
+ if (r32 & __MSIX_VT_NUMVT__MK) {
+ writel(r32 & __MSIX_VT_OFST_,
+ rb + HOSTFN_MSIX_VT_INDEX_MBOX_ERR);
+ return;
+ }
+
+ writel(__MSIX_VT_NUMVT_(HOSTFN_MSIX_DEFAULT - 1) |
+ HOSTFN_MSIX_DEFAULT * bfa_ioc_pcifn(ioc),
+ rb + HOSTFN_MSIX_VT_OFST_NUMVT);
+ writel(HOSTFN_MSIX_DEFAULT * bfa_ioc_pcifn(ioc),
+ rb + HOSTFN_MSIX_VT_INDEX_MBOX_ERR);
+}
+
+/**
+ * Cleanup hw semaphore and usecnt registers
+ */
+static void
+bfa_ioc_ct_ownership_reset(struct bfa_ioc *ioc)
+{
+ bfa_nw_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
+ writel(0, ioc->ioc_regs.ioc_usage_reg);
+ bfa_nw_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+
+ /*
+ * Read the hw sem reg to make sure that it is locked
+ * before we clear it. If it is not locked, writing 1
+ * will lock it instead of clearing it.
+ */
+ readl(ioc->ioc_regs.ioc_sem_reg);
+ bfa_nw_ioc_hw_sem_release(ioc);
+}
+
+/**
+ * Synchronized IOC failure processing routines
+ */
+static bool
+bfa_ioc_ct_sync_start(struct bfa_ioc *ioc)
+{
+ u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+ u32 sync_reqd = bfa_ioc_ct_get_sync_reqd(r32);
+
+ /*
+ * Driver load time. If the sync required bit for this PCI fn
+ * is set, it is due to an unclean exit by the driver for this
+ * PCI fn in the previous incarnation. Whoever comes here first
+ * should clean it up, no matter which PCI fn.
+ */
+
+ if (sync_reqd & bfa_ioc_ct_sync_pos(ioc)) {
+ writel(0, ioc->ioc_regs.ioc_fail_sync);
+ writel(1, ioc->ioc_regs.ioc_usage_reg);
+ writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate);
+ writel(BFI_IOC_UNINIT, ioc->ioc_regs.alt_ioc_fwstate);
+ return true;
+ }
+
+ return bfa_ioc_ct_sync_complete(ioc);
+}
+/**
+ * Synchronized IOC failure processing routines
+ */
+static void
+bfa_ioc_ct_sync_join(struct bfa_ioc *ioc)
+{
+ u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+ u32 sync_pos = bfa_ioc_ct_sync_reqd_pos(ioc);
+
+ writel((r32 | sync_pos), ioc->ioc_regs.ioc_fail_sync);
+}
+
+static void
+bfa_ioc_ct_sync_leave(struct bfa_ioc *ioc)
+{
+ u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+ u32 sync_msk = bfa_ioc_ct_sync_reqd_pos(ioc) |
+ bfa_ioc_ct_sync_pos(ioc);
+
+ writel((r32 & ~sync_msk), ioc->ioc_regs.ioc_fail_sync);
+}
+
+static void
+bfa_ioc_ct_sync_ack(struct bfa_ioc *ioc)
+{
+ u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+
+ writel((r32 | bfa_ioc_ct_sync_pos(ioc)), ioc->ioc_regs.ioc_fail_sync);
+}
+
+static bool
+bfa_ioc_ct_sync_complete(struct bfa_ioc *ioc)
+{
+ u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+ u32 sync_reqd = bfa_ioc_ct_get_sync_reqd(r32);
+ u32 sync_ackd = bfa_ioc_ct_get_sync_ackd(r32);
+ u32 tmp_ackd;
+
+ if (sync_ackd == 0)
+ return true;
+
+ /**
+ * The check below is to see whether any other PCI fn
+ * has reinitialized the ASIC (reset sync_ackd bits)
+ * and failed again while this IOC was waiting for hw
+ * semaphore (in bfa_iocpf_sm_semwait()).
+ */
+ tmp_ackd = sync_ackd;
+ if ((sync_reqd & bfa_ioc_ct_sync_pos(ioc)) &&
+ !(sync_ackd & bfa_ioc_ct_sync_pos(ioc)))
+ sync_ackd |= bfa_ioc_ct_sync_pos(ioc);
+
+ if (sync_reqd == sync_ackd) {
+ writel(bfa_ioc_ct_clear_sync_ackd(r32),
+ ioc->ioc_regs.ioc_fail_sync);
+ writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
+ writel(BFI_IOC_FAIL, ioc->ioc_regs.alt_ioc_fwstate);
+ return true;
+ }
+
+ /**
+ * If another PCI fn reinitialized and failed again while
+ * this IOC was waiting for hw sem, the sync_ackd bit for
+ * this IOC need to be set again to allow reinitialization.
+ */
+ if (tmp_ackd != sync_ackd)
+ writel((r32 | sync_ackd), ioc->ioc_regs.ioc_fail_sync);
+
+ return false;
+}
+
+static enum bfa_status
+bfa_ioc_ct_pll_init(void __iomem *rb, enum bfi_asic_mode asic_mode)
+{
+ u32 pll_sclk, pll_fclk, r32;
+ bool fcmode = (asic_mode == BFI_ASIC_MODE_FC);
+
+ pll_sclk = __APP_PLL_SCLK_LRESETN | __APP_PLL_SCLK_ENARST |
+ __APP_PLL_SCLK_RSEL200500 | __APP_PLL_SCLK_P0_1(3U) |
+ __APP_PLL_SCLK_JITLMT0_1(3U) |
+ __APP_PLL_SCLK_CNTLMT0_1(1U);
+ pll_fclk = __APP_PLL_LCLK_LRESETN | __APP_PLL_LCLK_ENARST |
+ __APP_PLL_LCLK_RSEL200500 | __APP_PLL_LCLK_P0_1(3U) |
+ __APP_PLL_LCLK_JITLMT0_1(3U) |
+ __APP_PLL_LCLK_CNTLMT0_1(1U);
+
+ if (fcmode) {
+ writel(0, (rb + OP_MODE));
+ writel(__APP_EMS_CMLCKSEL |
+ __APP_EMS_REFCKBUFEN2 |
+ __APP_EMS_CHANNEL_SEL,
+ (rb + ETH_MAC_SER_REG));
+ } else {
+ writel(__GLOBAL_FCOE_MODE, (rb + OP_MODE));
+ writel(__APP_EMS_REFCKBUFEN1,
+ (rb + ETH_MAC_SER_REG));
+ }
+ writel(BFI_IOC_UNINIT, (rb + BFA_IOC0_STATE_REG));
+ writel(BFI_IOC_UNINIT, (rb + BFA_IOC1_STATE_REG));
+ writel(0xffffffffU, (rb + HOSTFN0_INT_MSK));
+ writel(0xffffffffU, (rb + HOSTFN1_INT_MSK));
+ writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS));
+ writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS));
+ writel(0xffffffffU, (rb + HOSTFN0_INT_MSK));
+ writel(0xffffffffU, (rb + HOSTFN1_INT_MSK));
+ writel(pll_sclk |
+ __APP_PLL_SCLK_LOGIC_SOFT_RESET,
+ rb + APP_PLL_SCLK_CTL_REG);
+ writel(pll_fclk |
+ __APP_PLL_LCLK_LOGIC_SOFT_RESET,
+ rb + APP_PLL_LCLK_CTL_REG);
+ writel(pll_sclk |
+ __APP_PLL_SCLK_LOGIC_SOFT_RESET | __APP_PLL_SCLK_ENABLE,
+ rb + APP_PLL_SCLK_CTL_REG);
+ writel(pll_fclk |
+ __APP_PLL_LCLK_LOGIC_SOFT_RESET | __APP_PLL_LCLK_ENABLE,
+ rb + APP_PLL_LCLK_CTL_REG);
+ readl(rb + HOSTFN0_INT_MSK);
+ udelay(2000);
+ writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS));
+ writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS));
+ writel(pll_sclk |
+ __APP_PLL_SCLK_ENABLE,
+ rb + APP_PLL_SCLK_CTL_REG);
+ writel(pll_fclk |
+ __APP_PLL_LCLK_ENABLE,
+ rb + APP_PLL_LCLK_CTL_REG);
+
+ if (!fcmode) {
+ writel(__PMM_1T_RESET_P, (rb + PMM_1T_RESET_REG_P0));
+ writel(__PMM_1T_RESET_P, (rb + PMM_1T_RESET_REG_P1));
+ }
+ r32 = readl((rb + PSS_CTL_REG));
+ r32 &= ~__PSS_LMEM_RESET;
+ writel(r32, (rb + PSS_CTL_REG));
+ udelay(1000);
+ if (!fcmode) {
+ writel(0, (rb + PMM_1T_RESET_REG_P0));
+ writel(0, (rb + PMM_1T_RESET_REG_P1));
+ }
+
+ writel(__EDRAM_BISTR_START, (rb + MBIST_CTL_REG));
+ udelay(1000);
+ r32 = readl((rb + MBIST_STAT_REG));
+ writel(0, (rb + MBIST_CTL_REG));
+ return BFA_STATUS_OK;
+}
+
+static void
+bfa_ioc_ct2_sclk_init(void __iomem *rb)
+{
+ u32 r32;
+
+ /*
+ * put s_clk PLL and PLL FSM in reset
+ */
+ r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG));
+ r32 &= ~(__APP_PLL_SCLK_ENABLE | __APP_PLL_SCLK_LRESETN);
+ r32 |= (__APP_PLL_SCLK_ENARST | __APP_PLL_SCLK_BYPASS |
+ __APP_PLL_SCLK_LOGIC_SOFT_RESET);
+ writel(r32, (rb + CT2_APP_PLL_SCLK_CTL_REG));
+
+ /*
+ * Ignore mode and program for the max clock (which is FC16)
+ * Firmware/NFC will do the PLL init appropiately
+ */
+ r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG));
+ r32 &= ~(__APP_PLL_SCLK_REFCLK_SEL | __APP_PLL_SCLK_CLK_DIV2);
+ writel(r32, (rb + CT2_APP_PLL_SCLK_CTL_REG));
+
+ /*
+ * while doing PLL init dont clock gate ethernet subsystem
+ */
+ r32 = readl((rb + CT2_CHIP_MISC_PRG));
+ writel((r32 | __ETH_CLK_ENABLE_PORT0),
+ (rb + CT2_CHIP_MISC_PRG));
+
+ r32 = readl((rb + CT2_PCIE_MISC_REG));
+ writel((r32 | __ETH_CLK_ENABLE_PORT1),
+ (rb + CT2_PCIE_MISC_REG));
+
+ /*
+ * set sclk value
+ */
+ r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG));
+ r32 &= (__P_SCLK_PLL_LOCK | __APP_PLL_SCLK_REFCLK_SEL |
+ __APP_PLL_SCLK_CLK_DIV2);
+ writel(r32 | 0x1061731b, (rb + CT2_APP_PLL_SCLK_CTL_REG));
+
+ /*
+ * poll for s_clk lock or delay 1ms
+ */
+ udelay(1000);
+
+ /*
+ * Dont do clock gating for ethernet subsystem, firmware/NFC will
+ * do this appropriately
+ */
+}
+
+static void
+bfa_ioc_ct2_lclk_init(void __iomem *rb)
+{
+ u32 r32;
+
+ /*
+ * put l_clk PLL and PLL FSM in reset
+ */
+ r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG));
+ r32 &= ~(__APP_PLL_LCLK_ENABLE | __APP_PLL_LCLK_LRESETN);
+ r32 |= (__APP_PLL_LCLK_ENARST | __APP_PLL_LCLK_BYPASS |
+ __APP_PLL_LCLK_LOGIC_SOFT_RESET);
+ writel(r32, (rb + CT2_APP_PLL_LCLK_CTL_REG));
+
+ /*
+ * set LPU speed (set for FC16 which will work for other modes)
+ */
+ r32 = readl((rb + CT2_CHIP_MISC_PRG));
+ writel(r32, (rb + CT2_CHIP_MISC_PRG));
+
+ /*
+ * set LPU half speed (set for FC16 which will work for other modes)
+ */
+ r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG));
+ writel(r32, (rb + CT2_APP_PLL_LCLK_CTL_REG));
+
+ /*
+ * set lclk for mode (set for FC16)
+ */
+ r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG));
+ r32 &= (__P_LCLK_PLL_LOCK | __APP_LPUCLK_HALFSPEED);
+ r32 |= 0x20c1731b;
+ writel(r32, (rb + CT2_APP_PLL_LCLK_CTL_REG));
+
+ /*
+ * poll for s_clk lock or delay 1ms
+ */
+ udelay(1000);
+}
+
+static void
+bfa_ioc_ct2_mem_init(void __iomem *rb)
+{
+ u32 r32;
+
+ r32 = readl((rb + PSS_CTL_REG));
+ r32 &= ~__PSS_LMEM_RESET;
+ writel(r32, (rb + PSS_CTL_REG));
+ udelay(1000);
+
+ writel(__EDRAM_BISTR_START, (rb + CT2_MBIST_CTL_REG));
+ udelay(1000);
+ writel(0, (rb + CT2_MBIST_CTL_REG));
+}
+
+static void
+bfa_ioc_ct2_mac_reset(void __iomem *rb)
+{
+ volatile u32 r32;
+
+ bfa_ioc_ct2_sclk_init(rb);
+ bfa_ioc_ct2_lclk_init(rb);
+
+ /*
+ * release soft reset on s_clk & l_clk
+ */
+ r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG));
+ writel((r32 & ~__APP_PLL_SCLK_LOGIC_SOFT_RESET),
+ (rb + CT2_APP_PLL_SCLK_CTL_REG));
+
+ /*
+ * release soft reset on s_clk & l_clk
+ */
+ r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG));
+ writel((r32 & ~__APP_PLL_LCLK_LOGIC_SOFT_RESET),
+ (rb + CT2_APP_PLL_LCLK_CTL_REG));
+
+ /* put port0, port1 MAC & AHB in reset */
+ writel((__CSI_MAC_RESET | __CSI_MAC_AHB_RESET),
+ (rb + CT2_CSI_MAC_CONTROL_REG(0)));
+ writel((__CSI_MAC_RESET | __CSI_MAC_AHB_RESET),
+ (rb + CT2_CSI_MAC_CONTROL_REG(1)));
+}
+
+#define CT2_NFC_MAX_DELAY 1000
+static enum bfa_status
+bfa_ioc_ct2_pll_init(void __iomem *rb, enum bfi_asic_mode asic_mode)
+{
+ volatile u32 wgn, r32;
+ int i;
+
+ /*
+ * Initialize PLL if not already done by NFC
+ */
+ wgn = readl(rb + CT2_WGN_STATUS);
+ if (!(wgn & __GLBL_PF_VF_CFG_RDY)) {
+ writel(__HALT_NFC_CONTROLLER, (rb + CT2_NFC_CSR_SET_REG));
+ for (i = 0; i < CT2_NFC_MAX_DELAY; i++) {
+ r32 = readl(rb + CT2_NFC_CSR_SET_REG);
+ if (r32 & __NFC_CONTROLLER_HALTED)
+ break;
+ udelay(1000);
+ }
+ }
+
+ /*
+ * Mask the interrupts and clear any
+ * pending interrupts left by BIOS/EFI
+ */
+
+ writel(1, (rb + CT2_LPU0_HOSTFN_MBOX0_MSK));
+ writel(1, (rb + CT2_LPU1_HOSTFN_MBOX0_MSK));
+
+ r32 = readl((rb + CT2_LPU0_HOSTFN_CMD_STAT));
+ if (r32 == 1) {
+ writel(1, (rb + CT2_LPU0_HOSTFN_CMD_STAT));
+ readl((rb + CT2_LPU0_HOSTFN_CMD_STAT));
+ }
+ r32 = readl((rb + CT2_LPU1_HOSTFN_CMD_STAT));
+ if (r32 == 1) {
+ writel(1, (rb + CT2_LPU1_HOSTFN_CMD_STAT));
+ readl((rb + CT2_LPU1_HOSTFN_CMD_STAT));
+ }
+
+ bfa_ioc_ct2_mac_reset(rb);
+ bfa_ioc_ct2_sclk_init(rb);
+ bfa_ioc_ct2_lclk_init(rb);
+
+ /*
+ * release soft reset on s_clk & l_clk
+ */
+ r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG));
+ writel((r32 & ~__APP_PLL_SCLK_LOGIC_SOFT_RESET),
+ (rb + CT2_APP_PLL_SCLK_CTL_REG));
+
+ /*
+ * release soft reset on s_clk & l_clk
+ */
+ r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG));
+ writel(r32 & ~__APP_PLL_LCLK_LOGIC_SOFT_RESET,
+ (rb + CT2_APP_PLL_LCLK_CTL_REG));
+
+ /*
+ * Announce flash device presence, if flash was corrupted.
+ */
+ if (wgn == (__WGN_READY | __GLBL_PF_VF_CFG_RDY)) {
+ r32 = readl((rb + PSS_GPIO_OUT_REG));
+ writel((r32 & ~1), (rb + PSS_GPIO_OUT_REG));
+ r32 = readl((rb + PSS_GPIO_OE_REG));
+ writel((r32 | 1), (rb + PSS_GPIO_OE_REG));
+ }
+
+ bfa_ioc_ct2_mem_init(rb);
+
+ writel(BFI_IOC_UNINIT, (rb + CT2_BFA_IOC0_STATE_REG));
+ writel(BFI_IOC_UNINIT, (rb + CT2_BFA_IOC1_STATE_REG));
+ return BFA_STATUS_OK;
+}
diff --git a/drivers/net/ethernet/brocade/bna/bfa_msgq.c b/drivers/net/ethernet/brocade/bna/bfa_msgq.c
new file mode 100644
index 000000000000..dd36427f4752
--- /dev/null
+++ b/drivers/net/ethernet/brocade/bna/bfa_msgq.c
@@ -0,0 +1,669 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2005-2011 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+/**
+ * @file bfa_msgq.c MSGQ module source file.
+ */
+
+#include "bfi.h"
+#include "bfa_msgq.h"
+#include "bfa_ioc.h"
+
+#define call_cmdq_ent_cbfn(_cmdq_ent, _status) \
+{ \
+ bfa_msgq_cmdcbfn_t cbfn; \
+ void *cbarg; \
+ cbfn = (_cmdq_ent)->cbfn; \
+ cbarg = (_cmdq_ent)->cbarg; \
+ (_cmdq_ent)->cbfn = NULL; \
+ (_cmdq_ent)->cbarg = NULL; \
+ if (cbfn) { \
+ cbfn(cbarg, (_status)); \
+ } \
+}
+
+static void bfa_msgq_cmdq_dbell(struct bfa_msgq_cmdq *cmdq);
+static void bfa_msgq_cmdq_copy_rsp(struct bfa_msgq_cmdq *cmdq);
+
+enum cmdq_event {
+ CMDQ_E_START = 1,
+ CMDQ_E_STOP = 2,
+ CMDQ_E_FAIL = 3,
+ CMDQ_E_POST = 4,
+ CMDQ_E_INIT_RESP = 5,
+ CMDQ_E_DB_READY = 6,
+};
+
+bfa_fsm_state_decl(cmdq, stopped, struct bfa_msgq_cmdq, enum cmdq_event);
+bfa_fsm_state_decl(cmdq, init_wait, struct bfa_msgq_cmdq, enum cmdq_event);
+bfa_fsm_state_decl(cmdq, ready, struct bfa_msgq_cmdq, enum cmdq_event);
+bfa_fsm_state_decl(cmdq, dbell_wait, struct bfa_msgq_cmdq,
+ enum cmdq_event);
+
+static void
+cmdq_sm_stopped_entry(struct bfa_msgq_cmdq *cmdq)
+{
+ struct bfa_msgq_cmd_entry *cmdq_ent;
+
+ cmdq->producer_index = 0;
+ cmdq->consumer_index = 0;
+ cmdq->flags = 0;
+ cmdq->token = 0;
+ cmdq->offset = 0;
+ cmdq->bytes_to_copy = 0;
+ while (!list_empty(&cmdq->pending_q)) {
+ bfa_q_deq(&cmdq->pending_q, &cmdq_ent);
+ bfa_q_qe_init(&cmdq_ent->qe);
+ call_cmdq_ent_cbfn(cmdq_ent, BFA_STATUS_FAILED);
+ }
+}
+
+static void
+cmdq_sm_stopped(struct bfa_msgq_cmdq *cmdq, enum cmdq_event event)
+{
+ switch (event) {
+ case CMDQ_E_START:
+ bfa_fsm_set_state(cmdq, cmdq_sm_init_wait);
+ break;
+
+ case CMDQ_E_STOP:
+ case CMDQ_E_FAIL:
+ /* No-op */
+ break;
+
+ case CMDQ_E_POST:
+ cmdq->flags |= BFA_MSGQ_CMDQ_F_DB_UPDATE;
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+cmdq_sm_init_wait_entry(struct bfa_msgq_cmdq *cmdq)
+{
+ bfa_wc_down(&cmdq->msgq->init_wc);
+}
+
+static void
+cmdq_sm_init_wait(struct bfa_msgq_cmdq *cmdq, enum cmdq_event event)
+{
+ switch (event) {
+ case CMDQ_E_STOP:
+ case CMDQ_E_FAIL:
+ bfa_fsm_set_state(cmdq, cmdq_sm_stopped);
+ break;
+
+ case CMDQ_E_POST:
+ cmdq->flags |= BFA_MSGQ_CMDQ_F_DB_UPDATE;
+ break;
+
+ case CMDQ_E_INIT_RESP:
+ if (cmdq->flags & BFA_MSGQ_CMDQ_F_DB_UPDATE) {
+ cmdq->flags &= ~BFA_MSGQ_CMDQ_F_DB_UPDATE;
+ bfa_fsm_set_state(cmdq, cmdq_sm_dbell_wait);
+ } else
+ bfa_fsm_set_state(cmdq, cmdq_sm_ready);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+cmdq_sm_ready_entry(struct bfa_msgq_cmdq *cmdq)
+{
+}
+
+static void
+cmdq_sm_ready(struct bfa_msgq_cmdq *cmdq, enum cmdq_event event)
+{
+ switch (event) {
+ case CMDQ_E_STOP:
+ case CMDQ_E_FAIL:
+ bfa_fsm_set_state(cmdq, cmdq_sm_stopped);
+ break;
+
+ case CMDQ_E_POST:
+ bfa_fsm_set_state(cmdq, cmdq_sm_dbell_wait);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+cmdq_sm_dbell_wait_entry(struct bfa_msgq_cmdq *cmdq)
+{
+ bfa_msgq_cmdq_dbell(cmdq);
+}
+
+static void
+cmdq_sm_dbell_wait(struct bfa_msgq_cmdq *cmdq, enum cmdq_event event)
+{
+ switch (event) {
+ case CMDQ_E_STOP:
+ case CMDQ_E_FAIL:
+ bfa_fsm_set_state(cmdq, cmdq_sm_stopped);
+ break;
+
+ case CMDQ_E_POST:
+ cmdq->flags |= BFA_MSGQ_CMDQ_F_DB_UPDATE;
+ break;
+
+ case CMDQ_E_DB_READY:
+ if (cmdq->flags & BFA_MSGQ_CMDQ_F_DB_UPDATE) {
+ cmdq->flags &= ~BFA_MSGQ_CMDQ_F_DB_UPDATE;
+ bfa_fsm_set_state(cmdq, cmdq_sm_dbell_wait);
+ } else
+ bfa_fsm_set_state(cmdq, cmdq_sm_ready);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bfa_msgq_cmdq_dbell_ready(void *arg)
+{
+ struct bfa_msgq_cmdq *cmdq = (struct bfa_msgq_cmdq *)arg;
+ bfa_fsm_send_event(cmdq, CMDQ_E_DB_READY);
+}
+
+static void
+bfa_msgq_cmdq_dbell(struct bfa_msgq_cmdq *cmdq)
+{
+ struct bfi_msgq_h2i_db *dbell =
+ (struct bfi_msgq_h2i_db *)(&cmdq->dbell_mb.msg[0]);
+
+ memset(dbell, 0, sizeof(struct bfi_msgq_h2i_db));
+ bfi_h2i_set(dbell->mh, BFI_MC_MSGQ, BFI_MSGQ_H2I_DOORBELL_PI, 0);
+ dbell->mh.mtag.i2htok = 0;
+ dbell->idx.cmdq_pi = htons(cmdq->producer_index);
+
+ if (!bfa_nw_ioc_mbox_queue(cmdq->msgq->ioc, &cmdq->dbell_mb,
+ bfa_msgq_cmdq_dbell_ready, cmdq)) {
+ bfa_msgq_cmdq_dbell_ready(cmdq);
+ }
+}
+
+static void
+__cmd_copy(struct bfa_msgq_cmdq *cmdq, struct bfa_msgq_cmd_entry *cmd)
+{
+ size_t len = cmd->msg_size;
+ int num_entries = 0;
+ size_t to_copy;
+ u8 *src, *dst;
+
+ src = (u8 *)cmd->msg_hdr;
+ dst = (u8 *)cmdq->addr.kva;
+ dst += (cmdq->producer_index * BFI_MSGQ_CMD_ENTRY_SIZE);
+
+ while (len) {
+ to_copy = (len < BFI_MSGQ_CMD_ENTRY_SIZE) ?
+ len : BFI_MSGQ_CMD_ENTRY_SIZE;
+ memcpy(dst, src, to_copy);
+ len -= to_copy;
+ src += BFI_MSGQ_CMD_ENTRY_SIZE;
+ BFA_MSGQ_INDX_ADD(cmdq->producer_index, 1, cmdq->depth);
+ dst = (u8 *)cmdq->addr.kva;
+ dst += (cmdq->producer_index * BFI_MSGQ_CMD_ENTRY_SIZE);
+ num_entries++;
+ }
+
+}
+
+static void
+bfa_msgq_cmdq_ci_update(struct bfa_msgq_cmdq *cmdq, struct bfi_mbmsg *mb)
+{
+ struct bfi_msgq_i2h_db *dbell = (struct bfi_msgq_i2h_db *)mb;
+ struct bfa_msgq_cmd_entry *cmd;
+ int posted = 0;
+
+ cmdq->consumer_index = ntohs(dbell->idx.cmdq_ci);
+
+ /* Walk through pending list to see if the command can be posted */
+ while (!list_empty(&cmdq->pending_q)) {
+ cmd =
+ (struct bfa_msgq_cmd_entry *)bfa_q_first(&cmdq->pending_q);
+ if (ntohs(cmd->msg_hdr->num_entries) <=
+ BFA_MSGQ_FREE_CNT(cmdq)) {
+ list_del(&cmd->qe);
+ __cmd_copy(cmdq, cmd);
+ posted = 1;
+ call_cmdq_ent_cbfn(cmd, BFA_STATUS_OK);
+ } else {
+ break;
+ }
+ }
+
+ if (posted)
+ bfa_fsm_send_event(cmdq, CMDQ_E_POST);
+}
+
+static void
+bfa_msgq_cmdq_copy_next(void *arg)
+{
+ struct bfa_msgq_cmdq *cmdq = (struct bfa_msgq_cmdq *)arg;
+
+ if (cmdq->bytes_to_copy)
+ bfa_msgq_cmdq_copy_rsp(cmdq);
+}
+
+static void
+bfa_msgq_cmdq_copy_req(struct bfa_msgq_cmdq *cmdq, struct bfi_mbmsg *mb)
+{
+ struct bfi_msgq_i2h_cmdq_copy_req *req =
+ (struct bfi_msgq_i2h_cmdq_copy_req *)mb;
+
+ cmdq->token = 0;
+ cmdq->offset = ntohs(req->offset);
+ cmdq->bytes_to_copy = ntohs(req->len);
+ bfa_msgq_cmdq_copy_rsp(cmdq);
+}
+
+static void
+bfa_msgq_cmdq_copy_rsp(struct bfa_msgq_cmdq *cmdq)
+{
+ struct bfi_msgq_h2i_cmdq_copy_rsp *rsp =
+ (struct bfi_msgq_h2i_cmdq_copy_rsp *)&cmdq->copy_mb.msg[0];
+ int copied;
+ u8 *addr = (u8 *)cmdq->addr.kva;
+
+ memset(rsp, 0, sizeof(struct bfi_msgq_h2i_cmdq_copy_rsp));
+ bfi_h2i_set(rsp->mh, BFI_MC_MSGQ, BFI_MSGQ_H2I_CMDQ_COPY_RSP, 0);
+ rsp->mh.mtag.i2htok = htons(cmdq->token);
+ copied = (cmdq->bytes_to_copy >= BFI_CMD_COPY_SZ) ? BFI_CMD_COPY_SZ :
+ cmdq->bytes_to_copy;
+ addr += cmdq->offset;
+ memcpy(rsp->data, addr, copied);
+
+ cmdq->token++;
+ cmdq->offset += copied;
+ cmdq->bytes_to_copy -= copied;
+
+ if (!bfa_nw_ioc_mbox_queue(cmdq->msgq->ioc, &cmdq->copy_mb,
+ bfa_msgq_cmdq_copy_next, cmdq)) {
+ bfa_msgq_cmdq_copy_next(cmdq);
+ }
+}
+
+static void
+bfa_msgq_cmdq_attach(struct bfa_msgq_cmdq *cmdq, struct bfa_msgq *msgq)
+{
+ cmdq->depth = BFA_MSGQ_CMDQ_NUM_ENTRY;
+ INIT_LIST_HEAD(&cmdq->pending_q);
+ cmdq->msgq = msgq;
+ bfa_fsm_set_state(cmdq, cmdq_sm_stopped);
+}
+
+static void bfa_msgq_rspq_dbell(struct bfa_msgq_rspq *rspq);
+
+enum rspq_event {
+ RSPQ_E_START = 1,
+ RSPQ_E_STOP = 2,
+ RSPQ_E_FAIL = 3,
+ RSPQ_E_RESP = 4,
+ RSPQ_E_INIT_RESP = 5,
+ RSPQ_E_DB_READY = 6,
+};
+
+bfa_fsm_state_decl(rspq, stopped, struct bfa_msgq_rspq, enum rspq_event);
+bfa_fsm_state_decl(rspq, init_wait, struct bfa_msgq_rspq,
+ enum rspq_event);
+bfa_fsm_state_decl(rspq, ready, struct bfa_msgq_rspq, enum rspq_event);
+bfa_fsm_state_decl(rspq, dbell_wait, struct bfa_msgq_rspq,
+ enum rspq_event);
+
+static void
+rspq_sm_stopped_entry(struct bfa_msgq_rspq *rspq)
+{
+ rspq->producer_index = 0;
+ rspq->consumer_index = 0;
+ rspq->flags = 0;
+}
+
+static void
+rspq_sm_stopped(struct bfa_msgq_rspq *rspq, enum rspq_event event)
+{
+ switch (event) {
+ case RSPQ_E_START:
+ bfa_fsm_set_state(rspq, rspq_sm_init_wait);
+ break;
+
+ case RSPQ_E_STOP:
+ case RSPQ_E_FAIL:
+ /* No-op */
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+rspq_sm_init_wait_entry(struct bfa_msgq_rspq *rspq)
+{
+ bfa_wc_down(&rspq->msgq->init_wc);
+}
+
+static void
+rspq_sm_init_wait(struct bfa_msgq_rspq *rspq, enum rspq_event event)
+{
+ switch (event) {
+ case RSPQ_E_FAIL:
+ case RSPQ_E_STOP:
+ bfa_fsm_set_state(rspq, rspq_sm_stopped);
+ break;
+
+ case RSPQ_E_INIT_RESP:
+ bfa_fsm_set_state(rspq, rspq_sm_ready);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+rspq_sm_ready_entry(struct bfa_msgq_rspq *rspq)
+{
+}
+
+static void
+rspq_sm_ready(struct bfa_msgq_rspq *rspq, enum rspq_event event)
+{
+ switch (event) {
+ case RSPQ_E_STOP:
+ case RSPQ_E_FAIL:
+ bfa_fsm_set_state(rspq, rspq_sm_stopped);
+ break;
+
+ case RSPQ_E_RESP:
+ bfa_fsm_set_state(rspq, rspq_sm_dbell_wait);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+rspq_sm_dbell_wait_entry(struct bfa_msgq_rspq *rspq)
+{
+ if (!bfa_nw_ioc_is_disabled(rspq->msgq->ioc))
+ bfa_msgq_rspq_dbell(rspq);
+}
+
+static void
+rspq_sm_dbell_wait(struct bfa_msgq_rspq *rspq, enum rspq_event event)
+{
+ switch (event) {
+ case RSPQ_E_STOP:
+ case RSPQ_E_FAIL:
+ bfa_fsm_set_state(rspq, rspq_sm_stopped);
+ break;
+
+ case RSPQ_E_RESP:
+ rspq->flags |= BFA_MSGQ_RSPQ_F_DB_UPDATE;
+ break;
+
+ case RSPQ_E_DB_READY:
+ if (rspq->flags & BFA_MSGQ_RSPQ_F_DB_UPDATE) {
+ rspq->flags &= ~BFA_MSGQ_RSPQ_F_DB_UPDATE;
+ bfa_fsm_set_state(rspq, rspq_sm_dbell_wait);
+ } else
+ bfa_fsm_set_state(rspq, rspq_sm_ready);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bfa_msgq_rspq_dbell_ready(void *arg)
+{
+ struct bfa_msgq_rspq *rspq = (struct bfa_msgq_rspq *)arg;
+ bfa_fsm_send_event(rspq, RSPQ_E_DB_READY);
+}
+
+static void
+bfa_msgq_rspq_dbell(struct bfa_msgq_rspq *rspq)
+{
+ struct bfi_msgq_h2i_db *dbell =
+ (struct bfi_msgq_h2i_db *)(&rspq->dbell_mb.msg[0]);
+
+ memset(dbell, 0, sizeof(struct bfi_msgq_h2i_db));
+ bfi_h2i_set(dbell->mh, BFI_MC_MSGQ, BFI_MSGQ_H2I_DOORBELL_CI, 0);
+ dbell->mh.mtag.i2htok = 0;
+ dbell->idx.rspq_ci = htons(rspq->consumer_index);
+
+ if (!bfa_nw_ioc_mbox_queue(rspq->msgq->ioc, &rspq->dbell_mb,
+ bfa_msgq_rspq_dbell_ready, rspq)) {
+ bfa_msgq_rspq_dbell_ready(rspq);
+ }
+}
+
+static void
+bfa_msgq_rspq_pi_update(struct bfa_msgq_rspq *rspq, struct bfi_mbmsg *mb)
+{
+ struct bfi_msgq_i2h_db *dbell = (struct bfi_msgq_i2h_db *)mb;
+ struct bfi_msgq_mhdr *msghdr;
+ int num_entries;
+ int mc;
+ u8 *rspq_qe;
+
+ rspq->producer_index = ntohs(dbell->idx.rspq_pi);
+
+ while (rspq->consumer_index != rspq->producer_index) {
+ rspq_qe = (u8 *)rspq->addr.kva;
+ rspq_qe += (rspq->consumer_index * BFI_MSGQ_RSP_ENTRY_SIZE);
+ msghdr = (struct bfi_msgq_mhdr *)rspq_qe;
+
+ mc = msghdr->msg_class;
+ num_entries = ntohs(msghdr->num_entries);
+
+ if ((mc >= BFI_MC_MAX) || (rspq->rsphdlr[mc].cbfn == NULL))
+ break;
+
+ (rspq->rsphdlr[mc].cbfn)(rspq->rsphdlr[mc].cbarg, msghdr);
+
+ BFA_MSGQ_INDX_ADD(rspq->consumer_index, num_entries,
+ rspq->depth);
+ }
+
+ bfa_fsm_send_event(rspq, RSPQ_E_RESP);
+}
+
+static void
+bfa_msgq_rspq_attach(struct bfa_msgq_rspq *rspq, struct bfa_msgq *msgq)
+{
+ rspq->depth = BFA_MSGQ_RSPQ_NUM_ENTRY;
+ rspq->msgq = msgq;
+ bfa_fsm_set_state(rspq, rspq_sm_stopped);
+}
+
+static void
+bfa_msgq_init_rsp(struct bfa_msgq *msgq,
+ struct bfi_mbmsg *mb)
+{
+ bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_INIT_RESP);
+ bfa_fsm_send_event(&msgq->rspq, RSPQ_E_INIT_RESP);
+}
+
+static void
+bfa_msgq_init(void *arg)
+{
+ struct bfa_msgq *msgq = (struct bfa_msgq *)arg;
+ struct bfi_msgq_cfg_req *msgq_cfg =
+ (struct bfi_msgq_cfg_req *)&msgq->init_mb.msg[0];
+
+ memset(msgq_cfg, 0, sizeof(struct bfi_msgq_cfg_req));
+ bfi_h2i_set(msgq_cfg->mh, BFI_MC_MSGQ, BFI_MSGQ_H2I_INIT_REQ, 0);
+ msgq_cfg->mh.mtag.i2htok = 0;
+
+ bfa_dma_be_addr_set(msgq_cfg->cmdq.addr, msgq->cmdq.addr.pa);
+ msgq_cfg->cmdq.q_depth = htons(msgq->cmdq.depth);
+ bfa_dma_be_addr_set(msgq_cfg->rspq.addr, msgq->rspq.addr.pa);
+ msgq_cfg->rspq.q_depth = htons(msgq->rspq.depth);
+
+ bfa_nw_ioc_mbox_queue(msgq->ioc, &msgq->init_mb, NULL, NULL);
+}
+
+static void
+bfa_msgq_isr(void *cbarg, struct bfi_mbmsg *msg)
+{
+ struct bfa_msgq *msgq = (struct bfa_msgq *)cbarg;
+
+ switch (msg->mh.msg_id) {
+ case BFI_MSGQ_I2H_INIT_RSP:
+ bfa_msgq_init_rsp(msgq, msg);
+ break;
+
+ case BFI_MSGQ_I2H_DOORBELL_PI:
+ bfa_msgq_rspq_pi_update(&msgq->rspq, msg);
+ break;
+
+ case BFI_MSGQ_I2H_DOORBELL_CI:
+ bfa_msgq_cmdq_ci_update(&msgq->cmdq, msg);
+ break;
+
+ case BFI_MSGQ_I2H_CMDQ_COPY_REQ:
+ bfa_msgq_cmdq_copy_req(&msgq->cmdq, msg);
+ break;
+
+ default:
+ BUG_ON(1);
+ }
+}
+
+static void
+bfa_msgq_notify(void *cbarg, enum bfa_ioc_event event)
+{
+ struct bfa_msgq *msgq = (struct bfa_msgq *)cbarg;
+
+ switch (event) {
+ case BFA_IOC_E_ENABLED:
+ bfa_wc_init(&msgq->init_wc, bfa_msgq_init, msgq);
+ bfa_wc_up(&msgq->init_wc);
+ bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_START);
+ bfa_wc_up(&msgq->init_wc);
+ bfa_fsm_send_event(&msgq->rspq, RSPQ_E_START);
+ bfa_wc_wait(&msgq->init_wc);
+ break;
+
+ case BFA_IOC_E_DISABLED:
+ bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_STOP);
+ bfa_fsm_send_event(&msgq->rspq, RSPQ_E_STOP);
+ break;
+
+ case BFA_IOC_E_FAILED:
+ bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_FAIL);
+ bfa_fsm_send_event(&msgq->rspq, RSPQ_E_FAIL);
+ break;
+
+ default:
+ break;
+ }
+}
+
+u32
+bfa_msgq_meminfo(void)
+{
+ return roundup(BFA_MSGQ_CMDQ_SIZE, BFA_DMA_ALIGN_SZ) +
+ roundup(BFA_MSGQ_RSPQ_SIZE, BFA_DMA_ALIGN_SZ);
+}
+
+void
+bfa_msgq_memclaim(struct bfa_msgq *msgq, u8 *kva, u64 pa)
+{
+ msgq->cmdq.addr.kva = kva;
+ msgq->cmdq.addr.pa = pa;
+
+ kva += roundup(BFA_MSGQ_CMDQ_SIZE, BFA_DMA_ALIGN_SZ);
+ pa += roundup(BFA_MSGQ_CMDQ_SIZE, BFA_DMA_ALIGN_SZ);
+
+ msgq->rspq.addr.kva = kva;
+ msgq->rspq.addr.pa = pa;
+}
+
+void
+bfa_msgq_attach(struct bfa_msgq *msgq, struct bfa_ioc *ioc)
+{
+ msgq->ioc = ioc;
+
+ bfa_msgq_cmdq_attach(&msgq->cmdq, msgq);
+ bfa_msgq_rspq_attach(&msgq->rspq, msgq);
+
+ bfa_nw_ioc_mbox_regisr(msgq->ioc, BFI_MC_MSGQ, bfa_msgq_isr, msgq);
+ bfa_q_qe_init(&msgq->ioc_notify);
+ bfa_ioc_notify_init(&msgq->ioc_notify, bfa_msgq_notify, msgq);
+ bfa_nw_ioc_notify_register(msgq->ioc, &msgq->ioc_notify);
+}
+
+void
+bfa_msgq_regisr(struct bfa_msgq *msgq, enum bfi_mclass mc,
+ bfa_msgq_mcfunc_t cbfn, void *cbarg)
+{
+ msgq->rspq.rsphdlr[mc].cbfn = cbfn;
+ msgq->rspq.rsphdlr[mc].cbarg = cbarg;
+}
+
+void
+bfa_msgq_cmd_post(struct bfa_msgq *msgq, struct bfa_msgq_cmd_entry *cmd)
+{
+ if (ntohs(cmd->msg_hdr->num_entries) <=
+ BFA_MSGQ_FREE_CNT(&msgq->cmdq)) {
+ __cmd_copy(&msgq->cmdq, cmd);
+ call_cmdq_ent_cbfn(cmd, BFA_STATUS_OK);
+ bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_POST);
+ } else {
+ list_add_tail(&cmd->qe, &msgq->cmdq.pending_q);
+ }
+}
+
+void
+bfa_msgq_rsp_copy(struct bfa_msgq *msgq, u8 *buf, size_t buf_len)
+{
+ struct bfa_msgq_rspq *rspq = &msgq->rspq;
+ size_t len = buf_len;
+ size_t to_copy;
+ int ci;
+ u8 *src, *dst;
+
+ ci = rspq->consumer_index;
+ src = (u8 *)rspq->addr.kva;
+ src += (ci * BFI_MSGQ_RSP_ENTRY_SIZE);
+ dst = buf;
+
+ while (len) {
+ to_copy = (len < BFI_MSGQ_RSP_ENTRY_SIZE) ?
+ len : BFI_MSGQ_RSP_ENTRY_SIZE;
+ memcpy(dst, src, to_copy);
+ len -= to_copy;
+ dst += BFI_MSGQ_RSP_ENTRY_SIZE;
+ BFA_MSGQ_INDX_ADD(ci, 1, rspq->depth);
+ src = (u8 *)rspq->addr.kva;
+ src += (ci * BFI_MSGQ_RSP_ENTRY_SIZE);
+ }
+}
diff --git a/drivers/net/ethernet/brocade/bna/bfa_msgq.h b/drivers/net/ethernet/brocade/bna/bfa_msgq.h
new file mode 100644
index 000000000000..a6a565a366dc
--- /dev/null
+++ b/drivers/net/ethernet/brocade/bna/bfa_msgq.h
@@ -0,0 +1,130 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2005-2011 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#ifndef __BFA_MSGQ_H__
+#define __BFA_MSGQ_H__
+
+#include "bfa_defs.h"
+#include "bfi.h"
+#include "bfa_ioc.h"
+#include "bfa_cs.h"
+
+#define BFA_MSGQ_FREE_CNT(_q) \
+ (((_q)->consumer_index - (_q)->producer_index - 1) & ((_q)->depth - 1))
+
+#define BFA_MSGQ_INDX_ADD(_q_indx, _qe_num, _q_depth) \
+ ((_q_indx) = (((_q_indx) + (_qe_num)) & ((_q_depth) - 1)))
+
+#define BFA_MSGQ_CMDQ_NUM_ENTRY 128
+#define BFA_MSGQ_CMDQ_SIZE \
+ (BFI_MSGQ_CMD_ENTRY_SIZE * BFA_MSGQ_CMDQ_NUM_ENTRY)
+
+#define BFA_MSGQ_RSPQ_NUM_ENTRY 128
+#define BFA_MSGQ_RSPQ_SIZE \
+ (BFI_MSGQ_RSP_ENTRY_SIZE * BFA_MSGQ_RSPQ_NUM_ENTRY)
+
+#define bfa_msgq_cmd_set(_cmd, _cbfn, _cbarg, _msg_size, _msg_hdr) \
+do { \
+ (_cmd)->cbfn = (_cbfn); \
+ (_cmd)->cbarg = (_cbarg); \
+ (_cmd)->msg_size = (_msg_size); \
+ (_cmd)->msg_hdr = (_msg_hdr); \
+} while (0)
+
+struct bfa_msgq;
+
+typedef void (*bfa_msgq_cmdcbfn_t)(void *cbarg, enum bfa_status status);
+
+struct bfa_msgq_cmd_entry {
+ struct list_head qe;
+ bfa_msgq_cmdcbfn_t cbfn;
+ void *cbarg;
+ size_t msg_size;
+ struct bfi_msgq_mhdr *msg_hdr;
+};
+
+enum bfa_msgq_cmdq_flags {
+ BFA_MSGQ_CMDQ_F_DB_UPDATE = 1,
+};
+
+struct bfa_msgq_cmdq {
+ bfa_fsm_t fsm;
+ enum bfa_msgq_cmdq_flags flags;
+
+ u16 producer_index;
+ u16 consumer_index;
+ u16 depth; /* FW Q depth is 16 bits */
+ struct bfa_dma addr;
+ struct bfa_mbox_cmd dbell_mb;
+
+ u16 token;
+ int offset;
+ int bytes_to_copy;
+ struct bfa_mbox_cmd copy_mb;
+
+ struct list_head pending_q; /* pending command queue */
+
+ struct bfa_msgq *msgq;
+};
+
+enum bfa_msgq_rspq_flags {
+ BFA_MSGQ_RSPQ_F_DB_UPDATE = 1,
+};
+
+typedef void (*bfa_msgq_mcfunc_t)(void *cbarg, struct bfi_msgq_mhdr *mhdr);
+
+struct bfa_msgq_rspq {
+ bfa_fsm_t fsm;
+ enum bfa_msgq_rspq_flags flags;
+
+ u16 producer_index;
+ u16 consumer_index;
+ u16 depth; /* FW Q depth is 16 bits */
+ struct bfa_dma addr;
+ struct bfa_mbox_cmd dbell_mb;
+
+ int nmclass;
+ struct {
+ bfa_msgq_mcfunc_t cbfn;
+ void *cbarg;
+ } rsphdlr[BFI_MC_MAX];
+
+ struct bfa_msgq *msgq;
+};
+
+struct bfa_msgq {
+ struct bfa_msgq_cmdq cmdq;
+ struct bfa_msgq_rspq rspq;
+
+ struct bfa_wc init_wc;
+ struct bfa_mbox_cmd init_mb;
+
+ struct bfa_ioc_notify ioc_notify;
+ struct bfa_ioc *ioc;
+};
+
+u32 bfa_msgq_meminfo(void);
+void bfa_msgq_memclaim(struct bfa_msgq *msgq, u8 *kva, u64 pa);
+void bfa_msgq_attach(struct bfa_msgq *msgq, struct bfa_ioc *ioc);
+void bfa_msgq_regisr(struct bfa_msgq *msgq, enum bfi_mclass mc,
+ bfa_msgq_mcfunc_t cbfn, void *cbarg);
+void bfa_msgq_cmd_post(struct bfa_msgq *msgq,
+ struct bfa_msgq_cmd_entry *cmd);
+void bfa_msgq_rsp_copy(struct bfa_msgq *msgq, u8 *buf, size_t buf_len);
+
+#endif
diff --git a/drivers/net/bna/bfi.h b/drivers/net/ethernet/brocade/bna/bfi.h
index 088211c2724f..7a1393aabd43 100644
--- a/drivers/net/bna/bfi.h
+++ b/drivers/net/ethernet/brocade/bna/bfi.h
@@ -15,7 +15,6 @@
* All rights reserved
* www.brocade.com
*/
-
#ifndef __BFI_H__
#define __BFI_H__
@@ -28,12 +27,6 @@
*/
#define BFI_FLASH_CHUNK_SZ 256 /*!< Flash chunk size */
#define BFI_FLASH_CHUNK_SZ_WORDS (BFI_FLASH_CHUNK_SZ/sizeof(u32))
-enum {
- BFI_IMAGE_CB_FC,
- BFI_IMAGE_CT_FC,
- BFI_IMAGE_CT_CNA,
- BFI_IMAGE_MAX,
-};
/**
* Msg header common to all msgs
@@ -43,17 +36,21 @@ struct bfi_mhdr {
u8 msg_id; /*!< msg opcode with in the class */
union {
struct {
- u8 rsvd;
- u8 lpu_id; /*!< msg destination */
+ u8 qid;
+ u8 fn_lpu; /*!< msg destination */
} h2i;
u16 i2htok; /*!< token in msgs to host */
} mtag;
};
-#define bfi_h2i_set(_mh, _mc, _op, _lpuid) do { \
+#define bfi_fn_lpu(__fn, __lpu) ((__fn) << 1 | (__lpu))
+#define bfi_mhdr_2_fn(_mh) ((_mh)->mtag.h2i.fn_lpu >> 1)
+#define bfi_mhdr_2_qid(_mh) ((_mh)->mtag.h2i.qid)
+
+#define bfi_h2i_set(_mh, _mc, _op, _fn_lpu) do { \
(_mh).msg_class = (_mc); \
(_mh).msg_id = (_op); \
- (_mh).mtag.h2i.lpu_id = (_lpuid); \
+ (_mh).mtag.h2i.fn_lpu = (_fn_lpu); \
} while (0)
#define bfi_i2h_set(_mh, _mc, _op, _i2htok) do { \
@@ -76,20 +73,6 @@ struct bfi_mhdr {
****************************************************************************
*/
-#define BFI_SGE_INLINE 1
-#define BFI_SGE_INLINE_MAX (BFI_SGE_INLINE + 1)
-
-/**
- * SG Flags
- */
-enum {
- BFI_SGE_DATA = 0, /*!< data address, not last */
- BFI_SGE_DATA_CPL = 1, /*!< data addr, last in current page */
- BFI_SGE_DATA_LAST = 3, /*!< data address, last */
- BFI_SGE_LINK = 2, /*!< link address */
- BFI_SGE_PGDLEN = 2, /*!< cumulative data length for page */
-};
-
/**
* DMA addresses
*/
@@ -100,33 +83,6 @@ union bfi_addr_u {
} a32;
};
-/**
- * Scatter Gather Element
- */
-struct bfi_sge {
-#ifdef __BIGENDIAN
- u32 flags:2,
- rsvd:2,
- sg_len:28;
-#else
- u32 sg_len:28,
- rsvd:2,
- flags:2;
-#endif
- union bfi_addr_u sga;
-};
-
-/**
- * Scatter Gather Page
- */
-#define BFI_SGPG_DATA_SGES 7
-#define BFI_SGPG_SGES_MAX (BFI_SGPG_DATA_SGES + 1)
-#define BFI_SGPG_RSVD_WD_LEN 8
-struct bfi_sgpg {
- struct bfi_sge sges[BFI_SGPG_SGES_MAX];
- u32 rsvd[BFI_SGPG_RSVD_WD_LEN];
-};
-
/*
* Large Message structure - 128 Bytes size Msgs
*/
@@ -134,11 +90,6 @@ struct bfi_sgpg {
#define BFI_LMSG_PL_WSZ \
((BFI_LMSG_SZ - sizeof(struct bfi_mhdr)) / 4)
-struct bfi_msg {
- struct bfi_mhdr mhdr;
- u32 pl[BFI_LMSG_PL_WSZ];
-};
-
/**
* Mailbox message structure
*/
@@ -149,6 +100,14 @@ struct bfi_mbmsg {
};
/**
+ * Supported PCI function class codes (personality)
+ */
+enum bfi_pcifn_class {
+ BFI_PCIFN_CLASS_FC = 0x0c04,
+ BFI_PCIFN_CLASS_ETH = 0x0200,
+};
+
+/**
* Message Classes
*/
enum bfi_mclass {
@@ -176,24 +135,21 @@ enum bfi_mclass {
BFI_MC_SFP = 22, /*!< SFP module */
BFI_MC_MSGQ = 23, /*!< MSGQ */
BFI_MC_ENET = 24, /*!< ENET commands/responses */
- BFI_MC_MAX = 32
+ BFI_MC_PHY = 25, /*!< External PHY message class */
+ BFI_MC_NBOOT = 26, /*!< Network Boot */
+ BFI_MC_TIO_READ = 27, /*!< read IO (Target mode) */
+ BFI_MC_TIO_WRITE = 28, /*!< write IO (Target mode) */
+ BFI_MC_TIO_DATA_XFERED = 29, /*!< ds transferred (target mode) */
+ BFI_MC_TIO_IO = 30, /*!< IO (Target mode) */
+ BFI_MC_TIO = 31, /*!< IO (target mode) */
+ BFI_MC_MFG = 32, /*!< MFG/ASIC block commands */
+ BFI_MC_EDMA = 33, /*!< EDMA copy commands */
+ BFI_MC_MAX = 34
};
-#define BFI_IOC_MAX_CQS 4
-#define BFI_IOC_MAX_CQS_ASIC 8
#define BFI_IOC_MSGLEN_MAX 32 /* 32 bytes */
-#define BFI_BOOT_TYPE_OFF 8
-#define BFI_BOOT_LOADER_OFF 12
-
-#define BFI_BOOT_TYPE_NORMAL 0
-#define BFI_BOOT_TYPE_FLASH 1
-#define BFI_BOOT_TYPE_MEMTEST 2
-
-#define BFI_BOOT_LOADER_OS 0
-
-#define BFI_BOOT_MEMTEST_RES_ADDR 0x900
-#define BFI_BOOT_MEMTEST_RES_SIG 0xA0A1A2A3
+#define BFI_FWBOOT_ENV_OS 0
/**
*----------------------------------------------------------------------
@@ -201,6 +157,22 @@ enum bfi_mclass {
*----------------------------------------------------------------------
*/
+/**
+ * Different asic generations
+ */
+enum bfi_asic_gen {
+ BFI_ASIC_GEN_CB = 1,
+ BFI_ASIC_GEN_CT = 2,
+ BFI_ASIC_GEN_CT2 = 3,
+};
+
+enum bfi_asic_mode {
+ BFI_ASIC_MODE_FC = 1, /* FC upto 8G speed */
+ BFI_ASIC_MODE_FC16 = 2, /* FC upto 16G speed */
+ BFI_ASIC_MODE_ETH = 3, /* Ethernet ports */
+ BFI_ASIC_MODE_COMBO = 4, /* FC 16G and Ethernet 10G port */
+};
+
enum bfi_ioc_h2i_msgs {
BFI_IOC_H2I_ENABLE_REQ = 1,
BFI_IOC_H2I_DISABLE_REQ = 2,
@@ -213,8 +185,7 @@ enum bfi_ioc_i2h_msgs {
BFI_IOC_I2H_ENABLE_REPLY = BFA_I2HM(1),
BFI_IOC_I2H_DISABLE_REPLY = BFA_I2HM(2),
BFI_IOC_I2H_GETATTR_REPLY = BFA_I2HM(3),
- BFI_IOC_I2H_READY_EVENT = BFA_I2HM(4),
- BFI_IOC_I2H_HBEAT = BFA_I2HM(5),
+ BFI_IOC_I2H_HBEAT = BFA_I2HM(4),
};
/**
@@ -229,7 +200,8 @@ struct bfi_ioc_attr {
u64 mfg_pwwn; /*!< Mfg port wwn */
u64 mfg_nwwn; /*!< Mfg node wwn */
mac_t mfg_mac; /*!< Mfg mac */
- u16 rsvd_a;
+ u8 port_mode; /* enum bfi_port_mode */
+ u8 rsvd_a;
u64 pwwn;
u64 nwwn;
mac_t mac; /*!< PBC or Mfg mac */
@@ -282,26 +254,34 @@ struct bfi_ioc_getattr_reply {
#define BFI_IOC_MD5SUM_SZ 4
struct bfi_ioc_image_hdr {
u32 signature; /*!< constant signature */
- u32 rsvd_a;
+ u8 asic_gen; /*!< asic generation */
+ u8 asic_mode;
+ u8 port0_mode; /*!< device mode for port 0 */
+ u8 port1_mode; /*!< device mode for port 1 */
u32 exec; /*!< exec vector */
- u32 param; /*!< parameters */
+ u32 bootenv; /*!< firmware boot env */
u32 rsvd_b[4];
u32 md5sum[BFI_IOC_MD5SUM_SZ];
};
+#define BFI_FWBOOT_DEVMODE_OFF 4
+#define BFI_FWBOOT_TYPE_OFF 8
+#define BFI_FWBOOT_ENV_OFF 12
+#define BFI_FWBOOT_DEVMODE(__asic_gen, __asic_mode, __p0_mode, __p1_mode) \
+ (((u32)(__asic_gen)) << 24 | \
+ ((u32)(__asic_mode)) << 16 | \
+ ((u32)(__p0_mode)) << 8 | \
+ ((u32)(__p1_mode)))
+
enum bfi_fwboot_type {
BFI_FWBOOT_TYPE_NORMAL = 0,
BFI_FWBOOT_TYPE_FLASH = 1,
BFI_FWBOOT_TYPE_MEMTEST = 2,
};
-/**
- * BFI_IOC_I2H_READY_EVENT message
- */
-struct bfi_ioc_rdy_event {
- struct bfi_mhdr mh; /*!< common msg header */
- u8 init_status; /*!< init event status */
- u8 rsvd[3];
+enum bfi_port_mode {
+ BFI_PORT_MODE_FC = 1,
+ BFI_PORT_MODE_ETH = 2,
};
struct bfi_ioc_hbeat {
@@ -360,8 +340,8 @@ enum {
*/
struct bfi_ioc_ctrl_req {
struct bfi_mhdr mh;
- u8 ioc_class;
- u8 rsvd[3];
+ u16 clscode;
+ u16 rsvd;
u32 tv_sec;
};
@@ -369,9 +349,11 @@ struct bfi_ioc_ctrl_req {
* BFI_IOC_I2H_ENABLE_REPLY & BFI_IOC_I2H_DISABLE_REPLY messages
*/
struct bfi_ioc_ctrl_reply {
- struct bfi_mhdr mh; /*!< Common msg header */
+ struct bfi_mhdr mh; /*!< Common msg header */
u8 status; /*!< enable/disable status */
- u8 rsvd[3];
+ u8 port_mode; /*!< enum bfa_mode */
+ u8 cap_bm; /*!< capability bit mask */
+ u8 rsvd;
};
#define BFI_IOC_MSGSZ 8
@@ -391,10 +373,109 @@ union bfi_ioc_h2i_msg_u {
*/
union bfi_ioc_i2h_msg_u {
struct bfi_mhdr mh;
- struct bfi_ioc_rdy_event rdy_event;
+ struct bfi_ioc_ctrl_reply fw_event;
u32 mboxmsg[BFI_IOC_MSGSZ];
};
+/**
+ *----------------------------------------------------------------------
+ * MSGQ
+ *----------------------------------------------------------------------
+ */
+
+enum bfi_msgq_h2i_msgs {
+ BFI_MSGQ_H2I_INIT_REQ = 1,
+ BFI_MSGQ_H2I_DOORBELL_PI = 2,
+ BFI_MSGQ_H2I_DOORBELL_CI = 3,
+ BFI_MSGQ_H2I_CMDQ_COPY_RSP = 4,
+};
+
+enum bfi_msgq_i2h_msgs {
+ BFI_MSGQ_I2H_INIT_RSP = BFA_I2HM(BFI_MSGQ_H2I_INIT_REQ),
+ BFI_MSGQ_I2H_DOORBELL_PI = BFA_I2HM(BFI_MSGQ_H2I_DOORBELL_PI),
+ BFI_MSGQ_I2H_DOORBELL_CI = BFA_I2HM(BFI_MSGQ_H2I_DOORBELL_CI),
+ BFI_MSGQ_I2H_CMDQ_COPY_REQ = BFA_I2HM(BFI_MSGQ_H2I_CMDQ_COPY_RSP),
+};
+
+/* Messages(commands/responsed/AENS will have the following header */
+struct bfi_msgq_mhdr {
+ u8 msg_class;
+ u8 msg_id;
+ u16 msg_token;
+ u16 num_entries;
+ u8 enet_id;
+ u8 rsvd[1];
+};
+
+#define bfi_msgq_mhdr_set(_mh, _mc, _mid, _tok, _enet_id) do { \
+ (_mh).msg_class = (_mc); \
+ (_mh).msg_id = (_mid); \
+ (_mh).msg_token = (_tok); \
+ (_mh).enet_id = (_enet_id); \
+} while (0)
+
+/*
+ * Mailbox for messaging interface
+ */
+#define BFI_MSGQ_CMD_ENTRY_SIZE (64) /* TBD */
+#define BFI_MSGQ_RSP_ENTRY_SIZE (64) /* TBD */
+
+#define bfi_msgq_num_cmd_entries(_size) \
+ (((_size) + BFI_MSGQ_CMD_ENTRY_SIZE - 1) / BFI_MSGQ_CMD_ENTRY_SIZE)
+
+struct bfi_msgq {
+ union bfi_addr_u addr;
+ u16 q_depth; /* Total num of entries in the queue */
+ u8 rsvd[2];
+};
+
+/* BFI_ENET_MSGQ_CFG_REQ TBD init or cfg? */
+struct bfi_msgq_cfg_req {
+ struct bfi_mhdr mh;
+ struct bfi_msgq cmdq;
+ struct bfi_msgq rspq;
+};
+
+/* BFI_ENET_MSGQ_CFG_RSP */
+struct bfi_msgq_cfg_rsp {
+ struct bfi_mhdr mh;
+ u8 cmd_status;
+ u8 rsvd[3];
+};
+
+/* BFI_MSGQ_H2I_DOORBELL */
+struct bfi_msgq_h2i_db {
+ struct bfi_mhdr mh;
+ union {
+ u16 cmdq_pi;
+ u16 rspq_ci;
+ } idx;
+};
+
+/* BFI_MSGQ_I2H_DOORBELL */
+struct bfi_msgq_i2h_db {
+ struct bfi_mhdr mh;
+ union {
+ u16 rspq_pi;
+ u16 cmdq_ci;
+ } idx;
+};
+
+#define BFI_CMD_COPY_SZ 28
+
+/* BFI_MSGQ_H2I_CMD_COPY_RSP */
+struct bfi_msgq_h2i_cmdq_copy_rsp {
+ struct bfi_mhdr mh;
+ u8 data[BFI_CMD_COPY_SZ];
+};
+
+/* BFI_MSGQ_I2H_CMD_COPY_REQ */
+struct bfi_msgq_i2h_cmdq_copy_req {
+ struct bfi_mhdr mh;
+ u16 offset;
+ u16 len;
+};
+
#pragma pack()
#endif /* __BFI_H__ */
diff --git a/drivers/net/bna/bfi_cna.h b/drivers/net/ethernet/brocade/bna/bfi_cna.h
index 4eecabea397b..4eecabea397b 100644
--- a/drivers/net/bna/bfi_cna.h
+++ b/drivers/net/ethernet/brocade/bna/bfi_cna.h
diff --git a/drivers/net/ethernet/brocade/bna/bfi_enet.h b/drivers/net/ethernet/brocade/bna/bfi_enet.h
new file mode 100644
index 000000000000..a90f1cf46b41
--- /dev/null
+++ b/drivers/net/ethernet/brocade/bna/bfi_enet.h
@@ -0,0 +1,901 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2005-2011 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+/**
+ * @file bfi_enet.h BNA Hardware and Firmware Interface
+ */
+
+/**
+ * Skipping statistics collection to avoid clutter.
+ * Command is no longer needed:
+ * MTU
+ * TxQ Stop
+ * RxQ Stop
+ * RxF Enable/Disable
+ *
+ * HDS-off request is dynamic
+ * keep structures as multiple of 32-bit fields for alignment.
+ * All values must be written in big-endian.
+ */
+#ifndef __BFI_ENET_H__
+#define __BFI_ENET_H__
+
+#include "bfa_defs.h"
+#include "bfi.h"
+
+#pragma pack(1)
+
+#define BFI_ENET_CFG_MAX 32 /* Max resources per PF */
+
+#define BFI_ENET_TXQ_PRIO_MAX 8
+#define BFI_ENET_RX_QSET_MAX 16
+#define BFI_ENET_TXQ_WI_VECT_MAX 4
+
+#define BFI_ENET_VLAN_ID_MAX 4096
+#define BFI_ENET_VLAN_BLOCK_SIZE 512 /* in bits */
+#define BFI_ENET_VLAN_BLOCKS_MAX \
+ (BFI_ENET_VLAN_ID_MAX / BFI_ENET_VLAN_BLOCK_SIZE)
+#define BFI_ENET_VLAN_WORD_SIZE 32 /* in bits */
+#define BFI_ENET_VLAN_WORDS_MAX \
+ (BFI_ENET_VLAN_BLOCK_SIZE / BFI_ENET_VLAN_WORD_SIZE)
+
+#define BFI_ENET_RSS_RIT_MAX 64 /* entries */
+#define BFI_ENET_RSS_KEY_LEN 10 /* 32-bit words */
+
+union bfi_addr_be_u {
+ struct {
+ u32 addr_hi; /* Most Significant 32-bits */
+ u32 addr_lo; /* Least Significant 32-Bits */
+ } a32;
+};
+
+/**
+ * T X Q U E U E D E F I N E S
+ */
+/* TxQ Vector (a.k.a. Tx-Buffer Descriptor) */
+/* TxQ Entry Opcodes */
+#define BFI_ENET_TXQ_WI_SEND (0x402) /* Single Frame Transmission */
+#define BFI_ENET_TXQ_WI_SEND_LSO (0x403) /* Multi-Frame Transmission */
+#define BFI_ENET_TXQ_WI_EXTENSION (0x104) /* Extension WI */
+
+/* TxQ Entry Control Flags */
+#define BFI_ENET_TXQ_WI_CF_FCOE_CRC (1 << 8)
+#define BFI_ENET_TXQ_WI_CF_IPID_MODE (1 << 5)
+#define BFI_ENET_TXQ_WI_CF_INS_PRIO (1 << 4)
+#define BFI_ENET_TXQ_WI_CF_INS_VLAN (1 << 3)
+#define BFI_ENET_TXQ_WI_CF_UDP_CKSUM (1 << 2)
+#define BFI_ENET_TXQ_WI_CF_TCP_CKSUM (1 << 1)
+#define BFI_ENET_TXQ_WI_CF_IP_CKSUM (1 << 0)
+
+struct bfi_enet_txq_wi_base {
+ u8 reserved;
+ u8 num_vectors; /* number of vectors present */
+ u16 opcode;
+ /* BFI_ENET_TXQ_WI_SEND or BFI_ENET_TXQ_WI_SEND_LSO */
+ u16 flags; /* OR of all the flags */
+ u16 l4_hdr_size_n_offset;
+ u16 vlan_tag;
+ u16 lso_mss; /* Only 14 LSB are valid */
+ u32 frame_length; /* Only 24 LSB are valid */
+};
+
+struct bfi_enet_txq_wi_ext {
+ u16 reserved;
+ u16 opcode; /* BFI_ENET_TXQ_WI_EXTENSION */
+ u32 reserved2[3];
+};
+
+struct bfi_enet_txq_wi_vector { /* Tx Buffer Descriptor */
+ u16 reserved;
+ u16 length; /* Only 14 LSB are valid */
+ union bfi_addr_be_u addr;
+};
+
+/**
+ * TxQ Entry Structure
+ *
+ */
+struct bfi_enet_txq_entry {
+ union {
+ struct bfi_enet_txq_wi_base base;
+ struct bfi_enet_txq_wi_ext ext;
+ } wi;
+ struct bfi_enet_txq_wi_vector vector[BFI_ENET_TXQ_WI_VECT_MAX];
+};
+
+#define wi_hdr wi.base
+#define wi_ext_hdr wi.ext
+
+#define BFI_ENET_TXQ_WI_L4_HDR_N_OFFSET(_hdr_size, _offset) \
+ (((_hdr_size) << 10) | ((_offset) & 0x3FF))
+
+/**
+ * R X Q U E U E D E F I N E S
+ */
+struct bfi_enet_rxq_entry {
+ union bfi_addr_be_u rx_buffer;
+};
+
+/**
+ * R X C O M P L E T I O N Q U E U E D E F I N E S
+ */
+/* CQ Entry Flags */
+#define BFI_ENET_CQ_EF_MAC_ERROR (1 << 0)
+#define BFI_ENET_CQ_EF_FCS_ERROR (1 << 1)
+#define BFI_ENET_CQ_EF_TOO_LONG (1 << 2)
+#define BFI_ENET_CQ_EF_FC_CRC_OK (1 << 3)
+
+#define BFI_ENET_CQ_EF_RSVD1 (1 << 4)
+#define BFI_ENET_CQ_EF_L4_CKSUM_OK (1 << 5)
+#define BFI_ENET_CQ_EF_L3_CKSUM_OK (1 << 6)
+#define BFI_ENET_CQ_EF_HDS_HEADER (1 << 7)
+
+#define BFI_ENET_CQ_EF_UDP (1 << 8)
+#define BFI_ENET_CQ_EF_TCP (1 << 9)
+#define BFI_ENET_CQ_EF_IP_OPTIONS (1 << 10)
+#define BFI_ENET_CQ_EF_IPV6 (1 << 11)
+
+#define BFI_ENET_CQ_EF_IPV4 (1 << 12)
+#define BFI_ENET_CQ_EF_VLAN (1 << 13)
+#define BFI_ENET_CQ_EF_RSS (1 << 14)
+#define BFI_ENET_CQ_EF_RSVD2 (1 << 15)
+
+#define BFI_ENET_CQ_EF_MCAST_MATCH (1 << 16)
+#define BFI_ENET_CQ_EF_MCAST (1 << 17)
+#define BFI_ENET_CQ_EF_BCAST (1 << 18)
+#define BFI_ENET_CQ_EF_REMOTE (1 << 19)
+
+#define BFI_ENET_CQ_EF_LOCAL (1 << 20)
+
+/* CQ Entry Structure */
+struct bfi_enet_cq_entry {
+ u32 flags;
+ u16 vlan_tag;
+ u16 length;
+ u32 rss_hash;
+ u8 valid;
+ u8 reserved1;
+ u8 reserved2;
+ u8 rxq_id;
+};
+
+/**
+ * E N E T C O N T R O L P A T H C O M M A N D S
+ */
+struct bfi_enet_q {
+ union bfi_addr_u pg_tbl;
+ union bfi_addr_u first_entry;
+ u16 pages; /* # of pages */
+ u16 page_sz;
+};
+
+struct bfi_enet_txq {
+ struct bfi_enet_q q;
+ u8 priority;
+ u8 rsvd[3];
+};
+
+struct bfi_enet_rxq {
+ struct bfi_enet_q q;
+ u16 rx_buffer_size;
+ u16 rsvd;
+};
+
+struct bfi_enet_cq {
+ struct bfi_enet_q q;
+};
+
+struct bfi_enet_ib_cfg {
+ u8 int_pkt_dma;
+ u8 int_enabled;
+ u8 int_pkt_enabled;
+ u8 continuous_coalescing;
+ u8 msix;
+ u8 rsvd[3];
+ u32 coalescing_timeout;
+ u32 inter_pkt_timeout;
+ u8 inter_pkt_count;
+ u8 rsvd1[3];
+};
+
+struct bfi_enet_ib {
+ union bfi_addr_u index_addr;
+ union {
+ u16 msix_index;
+ u16 intx_bitmask;
+ } intr;
+ u16 rsvd;
+};
+
+/**
+ * ENET command messages
+ */
+enum bfi_enet_h2i_msgs {
+ /* Rx Commands */
+ BFI_ENET_H2I_RX_CFG_SET_REQ = 1,
+ BFI_ENET_H2I_RX_CFG_CLR_REQ = 2,
+
+ BFI_ENET_H2I_RIT_CFG_REQ = 3,
+ BFI_ENET_H2I_RSS_CFG_REQ = 4,
+ BFI_ENET_H2I_RSS_ENABLE_REQ = 5,
+ BFI_ENET_H2I_RX_PROMISCUOUS_REQ = 6,
+ BFI_ENET_H2I_RX_DEFAULT_REQ = 7,
+
+ BFI_ENET_H2I_MAC_UCAST_SET_REQ = 8,
+ BFI_ENET_H2I_MAC_UCAST_CLR_REQ = 9,
+ BFI_ENET_H2I_MAC_UCAST_ADD_REQ = 10,
+ BFI_ENET_H2I_MAC_UCAST_DEL_REQ = 11,
+
+ BFI_ENET_H2I_MAC_MCAST_ADD_REQ = 12,
+ BFI_ENET_H2I_MAC_MCAST_DEL_REQ = 13,
+ BFI_ENET_H2I_MAC_MCAST_FILTER_REQ = 14,
+
+ BFI_ENET_H2I_RX_VLAN_SET_REQ = 15,
+ BFI_ENET_H2I_RX_VLAN_STRIP_ENABLE_REQ = 16,
+
+ /* Tx Commands */
+ BFI_ENET_H2I_TX_CFG_SET_REQ = 17,
+ BFI_ENET_H2I_TX_CFG_CLR_REQ = 18,
+
+ /* Port Commands */
+ BFI_ENET_H2I_PORT_ADMIN_UP_REQ = 19,
+ BFI_ENET_H2I_SET_PAUSE_REQ = 20,
+ BFI_ENET_H2I_DIAG_LOOPBACK_REQ = 21,
+
+ /* Get Attributes Command */
+ BFI_ENET_H2I_GET_ATTR_REQ = 22,
+
+ /* Statistics Commands */
+ BFI_ENET_H2I_STATS_GET_REQ = 23,
+ BFI_ENET_H2I_STATS_CLR_REQ = 24,
+
+ BFI_ENET_H2I_WOL_MAGIC_REQ = 25,
+ BFI_ENET_H2I_WOL_FRAME_REQ = 26,
+
+ BFI_ENET_H2I_MAX = 27,
+};
+
+enum bfi_enet_i2h_msgs {
+ /* Rx Responses */
+ BFI_ENET_I2H_RX_CFG_SET_RSP =
+ BFA_I2HM(BFI_ENET_H2I_RX_CFG_SET_REQ),
+ BFI_ENET_I2H_RX_CFG_CLR_RSP =
+ BFA_I2HM(BFI_ENET_H2I_RX_CFG_CLR_REQ),
+
+ BFI_ENET_I2H_RIT_CFG_RSP =
+ BFA_I2HM(BFI_ENET_H2I_RIT_CFG_REQ),
+ BFI_ENET_I2H_RSS_CFG_RSP =
+ BFA_I2HM(BFI_ENET_H2I_RSS_CFG_REQ),
+ BFI_ENET_I2H_RSS_ENABLE_RSP =
+ BFA_I2HM(BFI_ENET_H2I_RSS_ENABLE_REQ),
+ BFI_ENET_I2H_RX_PROMISCUOUS_RSP =
+ BFA_I2HM(BFI_ENET_H2I_RX_PROMISCUOUS_REQ),
+ BFI_ENET_I2H_RX_DEFAULT_RSP =
+ BFA_I2HM(BFI_ENET_H2I_RX_DEFAULT_REQ),
+
+ BFI_ENET_I2H_MAC_UCAST_SET_RSP =
+ BFA_I2HM(BFI_ENET_H2I_MAC_UCAST_SET_REQ),
+ BFI_ENET_I2H_MAC_UCAST_CLR_RSP =
+ BFA_I2HM(BFI_ENET_H2I_MAC_UCAST_CLR_REQ),
+ BFI_ENET_I2H_MAC_UCAST_ADD_RSP =
+ BFA_I2HM(BFI_ENET_H2I_MAC_UCAST_ADD_REQ),
+ BFI_ENET_I2H_MAC_UCAST_DEL_RSP =
+ BFA_I2HM(BFI_ENET_H2I_MAC_UCAST_DEL_REQ),
+
+ BFI_ENET_I2H_MAC_MCAST_ADD_RSP =
+ BFA_I2HM(BFI_ENET_H2I_MAC_MCAST_ADD_REQ),
+ BFI_ENET_I2H_MAC_MCAST_DEL_RSP =
+ BFA_I2HM(BFI_ENET_H2I_MAC_MCAST_DEL_REQ),
+ BFI_ENET_I2H_MAC_MCAST_FILTER_RSP =
+ BFA_I2HM(BFI_ENET_H2I_MAC_MCAST_FILTER_REQ),
+
+ BFI_ENET_I2H_RX_VLAN_SET_RSP =
+ BFA_I2HM(BFI_ENET_H2I_RX_VLAN_SET_REQ),
+
+ BFI_ENET_I2H_RX_VLAN_STRIP_ENABLE_RSP =
+ BFA_I2HM(BFI_ENET_H2I_RX_VLAN_STRIP_ENABLE_REQ),
+
+ /* Tx Responses */
+ BFI_ENET_I2H_TX_CFG_SET_RSP =
+ BFA_I2HM(BFI_ENET_H2I_TX_CFG_SET_REQ),
+ BFI_ENET_I2H_TX_CFG_CLR_RSP =
+ BFA_I2HM(BFI_ENET_H2I_TX_CFG_CLR_REQ),
+
+ /* Port Responses */
+ BFI_ENET_I2H_PORT_ADMIN_RSP =
+ BFA_I2HM(BFI_ENET_H2I_PORT_ADMIN_UP_REQ),
+
+ BFI_ENET_I2H_SET_PAUSE_RSP =
+ BFA_I2HM(BFI_ENET_H2I_SET_PAUSE_REQ),
+ BFI_ENET_I2H_DIAG_LOOPBACK_RSP =
+ BFA_I2HM(BFI_ENET_H2I_DIAG_LOOPBACK_REQ),
+
+ /* Attributes Response */
+ BFI_ENET_I2H_GET_ATTR_RSP =
+ BFA_I2HM(BFI_ENET_H2I_GET_ATTR_REQ),
+
+ /* Statistics Responses */
+ BFI_ENET_I2H_STATS_GET_RSP =
+ BFA_I2HM(BFI_ENET_H2I_STATS_GET_REQ),
+ BFI_ENET_I2H_STATS_CLR_RSP =
+ BFA_I2HM(BFI_ENET_H2I_STATS_CLR_REQ),
+
+ BFI_ENET_I2H_WOL_MAGIC_RSP =
+ BFA_I2HM(BFI_ENET_H2I_WOL_MAGIC_REQ),
+ BFI_ENET_I2H_WOL_FRAME_RSP =
+ BFA_I2HM(BFI_ENET_H2I_WOL_FRAME_REQ),
+
+ /* AENs */
+ BFI_ENET_I2H_LINK_DOWN_AEN = BFA_I2HM(BFI_ENET_H2I_MAX),
+ BFI_ENET_I2H_LINK_UP_AEN = BFA_I2HM(BFI_ENET_H2I_MAX + 1),
+
+ BFI_ENET_I2H_PORT_ENABLE_AEN = BFA_I2HM(BFI_ENET_H2I_MAX + 2),
+ BFI_ENET_I2H_PORT_DISABLE_AEN = BFA_I2HM(BFI_ENET_H2I_MAX + 3),
+
+ BFI_ENET_I2H_BW_UPDATE_AEN = BFA_I2HM(BFI_ENET_H2I_MAX + 4),
+};
+
+/**
+ * The following error codes can be returned by the enet commands
+ */
+enum bfi_enet_err {
+ BFI_ENET_CMD_OK = 0,
+ BFI_ENET_CMD_FAIL = 1,
+ BFI_ENET_CMD_DUP_ENTRY = 2, /* !< Duplicate entry in CAM */
+ BFI_ENET_CMD_CAM_FULL = 3, /* !< CAM is full */
+ BFI_ENET_CMD_NOT_OWNER = 4, /* !< Not permitted, b'cos not owner */
+ BFI_ENET_CMD_NOT_EXEC = 5, /* !< Was not sent to f/w at all */
+ BFI_ENET_CMD_WAITING = 6, /* !< Waiting for completion */
+ BFI_ENET_CMD_PORT_DISABLED = 7, /* !< port in disabled state */
+};
+
+/**
+ * Generic Request
+ *
+ * bfi_enet_req is used by:
+ * BFI_ENET_H2I_RX_CFG_CLR_REQ
+ * BFI_ENET_H2I_TX_CFG_CLR_REQ
+ */
+struct bfi_enet_req {
+ struct bfi_msgq_mhdr mh;
+};
+
+/**
+ * Enable/Disable Request
+ *
+ * bfi_enet_enable_req is used by:
+ * BFI_ENET_H2I_RSS_ENABLE_REQ (enet_id must be zero)
+ * BFI_ENET_H2I_RX_PROMISCUOUS_REQ (enet_id must be zero)
+ * BFI_ENET_H2I_RX_DEFAULT_REQ (enet_id must be zero)
+ * BFI_ENET_H2I_RX_MAC_MCAST_FILTER_REQ
+ * BFI_ENET_H2I_PORT_ADMIN_UP_REQ (enet_id must be zero)
+ */
+struct bfi_enet_enable_req {
+ struct bfi_msgq_mhdr mh;
+ u8 enable; /* 1 = enable; 0 = disable */
+ u8 rsvd[3];
+};
+
+/**
+ * Generic Response
+ */
+struct bfi_enet_rsp {
+ struct bfi_msgq_mhdr mh;
+ u8 error; /*!< if error see cmd_offset */
+ u8 rsvd;
+ u16 cmd_offset; /*!< offset to invalid parameter */
+};
+
+/**
+ * GLOBAL CONFIGURATION
+ */
+
+/**
+ * bfi_enet_attr_req is used by:
+ * BFI_ENET_H2I_GET_ATTR_REQ
+ */
+struct bfi_enet_attr_req {
+ struct bfi_msgq_mhdr mh;
+};
+
+/**
+ * bfi_enet_attr_rsp is used by:
+ * BFI_ENET_I2H_GET_ATTR_RSP
+ */
+struct bfi_enet_attr_rsp {
+ struct bfi_msgq_mhdr mh;
+ u8 error; /*!< if error see cmd_offset */
+ u8 rsvd;
+ u16 cmd_offset; /*!< offset to invalid parameter */
+ u32 max_cfg;
+ u32 max_ucmac;
+ u32 rit_size;
+};
+
+/**
+ * Tx Configuration
+ *
+ * bfi_enet_tx_cfg is used by:
+ * BFI_ENET_H2I_TX_CFG_SET_REQ
+ */
+enum bfi_enet_tx_vlan_mode {
+ BFI_ENET_TX_VLAN_NOP = 0,
+ BFI_ENET_TX_VLAN_INS = 1,
+ BFI_ENET_TX_VLAN_WI = 2,
+};
+
+struct bfi_enet_tx_cfg {
+ u8 vlan_mode; /*!< processing mode */
+ u8 rsvd;
+ u16 vlan_id;
+ u8 admit_tagged_frame;
+ u8 apply_vlan_filter;
+ u8 add_to_vswitch;
+ u8 rsvd1[1];
+};
+
+struct bfi_enet_tx_cfg_req {
+ struct bfi_msgq_mhdr mh;
+ u8 num_queues; /* # of Tx Queues */
+ u8 rsvd[3];
+
+ struct {
+ struct bfi_enet_txq q;
+ struct bfi_enet_ib ib;
+ } q_cfg[BFI_ENET_TXQ_PRIO_MAX];
+
+ struct bfi_enet_ib_cfg ib_cfg;
+
+ struct bfi_enet_tx_cfg tx_cfg;
+};
+
+struct bfi_enet_tx_cfg_rsp {
+ struct bfi_msgq_mhdr mh;
+ u8 error;
+ u8 hw_id; /* For debugging */
+ u8 rsvd[2];
+ struct {
+ u32 q_dbell; /* PCI base address offset */
+ u32 i_dbell; /* PCI base address offset */
+ u8 hw_qid; /* For debugging */
+ u8 rsvd[3];
+ } q_handles[BFI_ENET_TXQ_PRIO_MAX];
+};
+
+/**
+ * Rx Configuration
+ *
+ * bfi_enet_rx_cfg is used by:
+ * BFI_ENET_H2I_RX_CFG_SET_REQ
+ */
+enum bfi_enet_rxq_type {
+ BFI_ENET_RXQ_SINGLE = 1,
+ BFI_ENET_RXQ_LARGE_SMALL = 2,
+ BFI_ENET_RXQ_HDS = 3,
+ BFI_ENET_RXQ_HDS_OPT_BASED = 4,
+};
+
+enum bfi_enet_hds_type {
+ BFI_ENET_HDS_FORCED = 0x01,
+ BFI_ENET_HDS_IPV6_UDP = 0x02,
+ BFI_ENET_HDS_IPV6_TCP = 0x04,
+ BFI_ENET_HDS_IPV4_TCP = 0x08,
+ BFI_ENET_HDS_IPV4_UDP = 0x10,
+};
+
+struct bfi_enet_rx_cfg {
+ u8 rxq_type;
+ u8 rsvd[3];
+
+ struct {
+ u8 max_header_size;
+ u8 force_offset;
+ u8 type;
+ u8 rsvd1;
+ } hds;
+
+ u8 multi_buffer;
+ u8 strip_vlan;
+ u8 drop_untagged;
+ u8 rsvd2;
+};
+
+/*
+ * Multicast frames are received on the ql of q-set index zero.
+ * On the completion queue. RxQ ID = even is for large/data buffer queues
+ * and RxQ ID = odd is for small/header buffer queues.
+ */
+struct bfi_enet_rx_cfg_req {
+ struct bfi_msgq_mhdr mh;
+ u8 num_queue_sets; /* # of Rx Queue Sets */
+ u8 rsvd[3];
+
+ struct {
+ struct bfi_enet_rxq ql; /* large/data/single buffers */
+ struct bfi_enet_rxq qs; /* small/header buffers */
+ struct bfi_enet_cq cq;
+ struct bfi_enet_ib ib;
+ } q_cfg[BFI_ENET_RX_QSET_MAX];
+
+ struct bfi_enet_ib_cfg ib_cfg;
+
+ struct bfi_enet_rx_cfg rx_cfg;
+};
+
+struct bfi_enet_rx_cfg_rsp {
+ struct bfi_msgq_mhdr mh;
+ u8 error;
+ u8 hw_id; /* For debugging */
+ u8 rsvd[2];
+ struct {
+ u32 ql_dbell; /* PCI base address offset */
+ u32 qs_dbell; /* PCI base address offset */
+ u32 i_dbell; /* PCI base address offset */
+ u8 hw_lqid; /* For debugging */
+ u8 hw_sqid; /* For debugging */
+ u8 hw_cqid; /* For debugging */
+ u8 rsvd;
+ } q_handles[BFI_ENET_RX_QSET_MAX];
+};
+
+/**
+ * RIT
+ *
+ * bfi_enet_rit_req is used by:
+ * BFI_ENET_H2I_RIT_CFG_REQ
+ */
+struct bfi_enet_rit_req {
+ struct bfi_msgq_mhdr mh;
+ u16 size; /* number of table-entries used */
+ u8 rsvd[2];
+ u8 table[BFI_ENET_RSS_RIT_MAX];
+};
+
+/**
+ * RSS
+ *
+ * bfi_enet_rss_cfg_req is used by:
+ * BFI_ENET_H2I_RSS_CFG_REQ
+ */
+enum bfi_enet_rss_type {
+ BFI_ENET_RSS_IPV6 = 0x01,
+ BFI_ENET_RSS_IPV6_TCP = 0x02,
+ BFI_ENET_RSS_IPV4 = 0x04,
+ BFI_ENET_RSS_IPV4_TCP = 0x08
+};
+
+struct bfi_enet_rss_cfg {
+ u8 type;
+ u8 mask;
+ u8 rsvd[2];
+ u32 key[BFI_ENET_RSS_KEY_LEN];
+};
+
+struct bfi_enet_rss_cfg_req {
+ struct bfi_msgq_mhdr mh;
+ struct bfi_enet_rss_cfg cfg;
+};
+
+/**
+ * MAC Unicast
+ *
+ * bfi_enet_rx_vlan_req is used by:
+ * BFI_ENET_H2I_MAC_UCAST_SET_REQ
+ * BFI_ENET_H2I_MAC_UCAST_CLR_REQ
+ * BFI_ENET_H2I_MAC_UCAST_ADD_REQ
+ * BFI_ENET_H2I_MAC_UCAST_DEL_REQ
+ */
+struct bfi_enet_ucast_req {
+ struct bfi_msgq_mhdr mh;
+ mac_t mac_addr;
+ u8 rsvd[2];
+};
+
+/**
+ * MAC Unicast + VLAN
+ */
+struct bfi_enet_mac_n_vlan_req {
+ struct bfi_msgq_mhdr mh;
+ u16 vlan_id;
+ mac_t mac_addr;
+};
+
+/**
+ * MAC Multicast
+ *
+ * bfi_enet_mac_mfilter_add_req is used by:
+ * BFI_ENET_H2I_MAC_MCAST_ADD_REQ
+ */
+struct bfi_enet_mcast_add_req {
+ struct bfi_msgq_mhdr mh;
+ mac_t mac_addr;
+ u8 rsvd[2];
+};
+
+/**
+ * bfi_enet_mac_mfilter_add_rsp is used by:
+ * BFI_ENET_I2H_MAC_MCAST_ADD_RSP
+ */
+struct bfi_enet_mcast_add_rsp {
+ struct bfi_msgq_mhdr mh;
+ u8 error;
+ u8 rsvd;
+ u16 cmd_offset;
+ u16 handle;
+ u8 rsvd1[2];
+};
+
+/**
+ * bfi_enet_mac_mfilter_del_req is used by:
+ * BFI_ENET_H2I_MAC_MCAST_DEL_REQ
+ */
+struct bfi_enet_mcast_del_req {
+ struct bfi_msgq_mhdr mh;
+ u16 handle;
+ u8 rsvd[2];
+};
+
+/**
+ * VLAN
+ *
+ * bfi_enet_rx_vlan_req is used by:
+ * BFI_ENET_H2I_RX_VLAN_SET_REQ
+ */
+struct bfi_enet_rx_vlan_req {
+ struct bfi_msgq_mhdr mh;
+ u8 block_idx;
+ u8 rsvd[3];
+ u32 bit_mask[BFI_ENET_VLAN_WORDS_MAX];
+};
+
+/**
+ * PAUSE
+ *
+ * bfi_enet_set_pause_req is used by:
+ * BFI_ENET_H2I_SET_PAUSE_REQ
+ */
+struct bfi_enet_set_pause_req {
+ struct bfi_msgq_mhdr mh;
+ u8 rsvd[2];
+ u8 tx_pause; /* 1 = enable; 0 = disable */
+ u8 rx_pause; /* 1 = enable; 0 = disable */
+};
+
+/**
+ * DIAGNOSTICS
+ *
+ * bfi_enet_diag_lb_req is used by:
+ * BFI_ENET_H2I_DIAG_LOOPBACK
+ */
+struct bfi_enet_diag_lb_req {
+ struct bfi_msgq_mhdr mh;
+ u8 rsvd[2];
+ u8 mode; /* cable or Serdes */
+ u8 enable; /* 1 = enable; 0 = disable */
+};
+
+/**
+ * enum for Loopback opmodes
+ */
+enum {
+ BFI_ENET_DIAG_LB_OPMODE_EXT = 0,
+ BFI_ENET_DIAG_LB_OPMODE_CBL = 1,
+};
+
+/**
+ * STATISTICS
+ *
+ * bfi_enet_stats_req is used by:
+ * BFI_ENET_H2I_STATS_GET_REQ
+ * BFI_ENET_I2H_STATS_CLR_REQ
+ */
+struct bfi_enet_stats_req {
+ struct bfi_msgq_mhdr mh;
+ u16 stats_mask;
+ u8 rsvd[2];
+ u32 rx_enet_mask;
+ u32 tx_enet_mask;
+ union bfi_addr_u host_buffer;
+};
+
+/**
+ * defines for "stats_mask" above.
+ */
+#define BFI_ENET_STATS_MAC (1 << 0) /* !< MAC Statistics */
+#define BFI_ENET_STATS_BPC (1 << 1) /* !< Pause Stats from BPC */
+#define BFI_ENET_STATS_RAD (1 << 2) /* !< Rx Admission Statistics */
+#define BFI_ENET_STATS_RX_FC (1 << 3) /* !< Rx FC Stats from RxA */
+#define BFI_ENET_STATS_TX_FC (1 << 4) /* !< Tx FC Stats from TxA */
+
+#define BFI_ENET_STATS_ALL 0x1f
+
+/* TxF Frame Statistics */
+struct bfi_enet_stats_txf {
+ u64 ucast_octets;
+ u64 ucast;
+ u64 ucast_vlan;
+
+ u64 mcast_octets;
+ u64 mcast;
+ u64 mcast_vlan;
+
+ u64 bcast_octets;
+ u64 bcast;
+ u64 bcast_vlan;
+
+ u64 errors;
+ u64 filter_vlan; /* frames filtered due to VLAN */
+ u64 filter_mac_sa; /* frames filtered due to SA check */
+};
+
+/* RxF Frame Statistics */
+struct bfi_enet_stats_rxf {
+ u64 ucast_octets;
+ u64 ucast;
+ u64 ucast_vlan;
+
+ u64 mcast_octets;
+ u64 mcast;
+ u64 mcast_vlan;
+
+ u64 bcast_octets;
+ u64 bcast;
+ u64 bcast_vlan;
+ u64 frame_drops;
+};
+
+/* FC Tx Frame Statistics */
+struct bfi_enet_stats_fc_tx {
+ u64 txf_ucast_octets;
+ u64 txf_ucast;
+ u64 txf_ucast_vlan;
+
+ u64 txf_mcast_octets;
+ u64 txf_mcast;
+ u64 txf_mcast_vlan;
+
+ u64 txf_bcast_octets;
+ u64 txf_bcast;
+ u64 txf_bcast_vlan;
+
+ u64 txf_parity_errors;
+ u64 txf_timeout;
+ u64 txf_fid_parity_errors;
+};
+
+/* FC Rx Frame Statistics */
+struct bfi_enet_stats_fc_rx {
+ u64 rxf_ucast_octets;
+ u64 rxf_ucast;
+ u64 rxf_ucast_vlan;
+
+ u64 rxf_mcast_octets;
+ u64 rxf_mcast;
+ u64 rxf_mcast_vlan;
+
+ u64 rxf_bcast_octets;
+ u64 rxf_bcast;
+ u64 rxf_bcast_vlan;
+};
+
+/* RAD Frame Statistics */
+struct bfi_enet_stats_rad {
+ u64 rx_frames;
+ u64 rx_octets;
+ u64 rx_vlan_frames;
+
+ u64 rx_ucast;
+ u64 rx_ucast_octets;
+ u64 rx_ucast_vlan;
+
+ u64 rx_mcast;
+ u64 rx_mcast_octets;
+ u64 rx_mcast_vlan;
+
+ u64 rx_bcast;
+ u64 rx_bcast_octets;
+ u64 rx_bcast_vlan;
+
+ u64 rx_drops;
+};
+
+/* BPC Tx Registers */
+struct bfi_enet_stats_bpc {
+ /* transmit stats */
+ u64 tx_pause[8];
+ u64 tx_zero_pause[8]; /*!< Pause cancellation */
+ /*!<Pause initiation rather than retention */
+ u64 tx_first_pause[8];
+
+ /* receive stats */
+ u64 rx_pause[8];
+ u64 rx_zero_pause[8]; /*!< Pause cancellation */
+ /*!<Pause initiation rather than retention */
+ u64 rx_first_pause[8];
+};
+
+/* MAC Rx Statistics */
+struct bfi_enet_stats_mac {
+ u64 frame_64; /* both rx and tx counter */
+ u64 frame_65_127; /* both rx and tx counter */
+ u64 frame_128_255; /* both rx and tx counter */
+ u64 frame_256_511; /* both rx and tx counter */
+ u64 frame_512_1023; /* both rx and tx counter */
+ u64 frame_1024_1518; /* both rx and tx counter */
+ u64 frame_1519_1522; /* both rx and tx counter */
+
+ /* receive stats */
+ u64 rx_bytes;
+ u64 rx_packets;
+ u64 rx_fcs_error;
+ u64 rx_multicast;
+ u64 rx_broadcast;
+ u64 rx_control_frames;
+ u64 rx_pause;
+ u64 rx_unknown_opcode;
+ u64 rx_alignment_error;
+ u64 rx_frame_length_error;
+ u64 rx_code_error;
+ u64 rx_carrier_sense_error;
+ u64 rx_undersize;
+ u64 rx_oversize;
+ u64 rx_fragments;
+ u64 rx_jabber;
+ u64 rx_drop;
+
+ /* transmit stats */
+ u64 tx_bytes;
+ u64 tx_packets;
+ u64 tx_multicast;
+ u64 tx_broadcast;
+ u64 tx_pause;
+ u64 tx_deferral;
+ u64 tx_excessive_deferral;
+ u64 tx_single_collision;
+ u64 tx_muliple_collision;
+ u64 tx_late_collision;
+ u64 tx_excessive_collision;
+ u64 tx_total_collision;
+ u64 tx_pause_honored;
+ u64 tx_drop;
+ u64 tx_jabber;
+ u64 tx_fcs_error;
+ u64 tx_control_frame;
+ u64 tx_oversize;
+ u64 tx_undersize;
+ u64 tx_fragments;
+};
+
+/**
+ * Complete statistics, DMAed from fw to host followed by
+ * BFI_ENET_I2H_STATS_GET_RSP
+ */
+struct bfi_enet_stats {
+ struct bfi_enet_stats_mac mac_stats;
+ struct bfi_enet_stats_bpc bpc_stats;
+ struct bfi_enet_stats_rad rad_stats;
+ struct bfi_enet_stats_rad rlb_stats;
+ struct bfi_enet_stats_fc_rx fc_rx_stats;
+ struct bfi_enet_stats_fc_tx fc_tx_stats;
+ struct bfi_enet_stats_rxf rxf_stats[BFI_ENET_CFG_MAX];
+ struct bfi_enet_stats_txf txf_stats[BFI_ENET_CFG_MAX];
+};
+
+#pragma pack()
+
+#endif /* __BFI_ENET_H__ */
diff --git a/drivers/net/ethernet/brocade/bna/bfi_reg.h b/drivers/net/ethernet/brocade/bna/bfi_reg.h
new file mode 100644
index 000000000000..efacff3ab51d
--- /dev/null
+++ b/drivers/net/ethernet/brocade/bna/bfi_reg.h
@@ -0,0 +1,452 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2005-2011 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+/*
+ * bfi_reg.h ASIC register defines for all Brocade adapter ASICs
+ */
+
+#ifndef __BFI_REG_H__
+#define __BFI_REG_H__
+
+#define HOSTFN0_INT_STATUS 0x00014000 /* cb/ct */
+#define HOSTFN1_INT_STATUS 0x00014100 /* cb/ct */
+#define HOSTFN2_INT_STATUS 0x00014300 /* ct */
+#define HOSTFN3_INT_STATUS 0x00014400 /* ct */
+#define HOSTFN0_INT_MSK 0x00014004 /* cb/ct */
+#define HOSTFN1_INT_MSK 0x00014104 /* cb/ct */
+#define HOSTFN2_INT_MSK 0x00014304 /* ct */
+#define HOSTFN3_INT_MSK 0x00014404 /* ct */
+
+#define HOST_PAGE_NUM_FN0 0x00014008 /* cb/ct */
+#define HOST_PAGE_NUM_FN1 0x00014108 /* cb/ct */
+#define HOST_PAGE_NUM_FN2 0x00014308 /* ct */
+#define HOST_PAGE_NUM_FN3 0x00014408 /* ct */
+
+#define APP_PLL_LCLK_CTL_REG 0x00014204 /* cb/ct */
+#define __P_LCLK_PLL_LOCK 0x80000000
+#define __APP_PLL_LCLK_SRAM_USE_100MHZ 0x00100000
+#define __APP_PLL_LCLK_RESET_TIMER_MK 0x000e0000
+#define __APP_PLL_LCLK_RESET_TIMER_SH 17
+#define __APP_PLL_LCLK_RESET_TIMER(_v) ((_v) << __APP_PLL_LCLK_RESET_TIMER_SH)
+#define __APP_PLL_LCLK_LOGIC_SOFT_RESET 0x00010000
+#define __APP_PLL_LCLK_CNTLMT0_1_MK 0x0000c000
+#define __APP_PLL_LCLK_CNTLMT0_1_SH 14
+#define __APP_PLL_LCLK_CNTLMT0_1(_v) ((_v) << __APP_PLL_LCLK_CNTLMT0_1_SH)
+#define __APP_PLL_LCLK_JITLMT0_1_MK 0x00003000
+#define __APP_PLL_LCLK_JITLMT0_1_SH 12
+#define __APP_PLL_LCLK_JITLMT0_1(_v) ((_v) << __APP_PLL_LCLK_JITLMT0_1_SH)
+#define __APP_PLL_LCLK_HREF 0x00000800
+#define __APP_PLL_LCLK_HDIV 0x00000400
+#define __APP_PLL_LCLK_P0_1_MK 0x00000300
+#define __APP_PLL_LCLK_P0_1_SH 8
+#define __APP_PLL_LCLK_P0_1(_v) ((_v) << __APP_PLL_LCLK_P0_1_SH)
+#define __APP_PLL_LCLK_Z0_2_MK 0x000000e0
+#define __APP_PLL_LCLK_Z0_2_SH 5
+#define __APP_PLL_LCLK_Z0_2(_v) ((_v) << __APP_PLL_LCLK_Z0_2_SH)
+#define __APP_PLL_LCLK_RSEL200500 0x00000010
+#define __APP_PLL_LCLK_ENARST 0x00000008
+#define __APP_PLL_LCLK_BYPASS 0x00000004
+#define __APP_PLL_LCLK_LRESETN 0x00000002
+#define __APP_PLL_LCLK_ENABLE 0x00000001
+#define APP_PLL_SCLK_CTL_REG 0x00014208 /* cb/ct */
+#define __P_SCLK_PLL_LOCK 0x80000000
+#define __APP_PLL_SCLK_RESET_TIMER_MK 0x000e0000
+#define __APP_PLL_SCLK_RESET_TIMER_SH 17
+#define __APP_PLL_SCLK_RESET_TIMER(_v) ((_v) << __APP_PLL_SCLK_RESET_TIMER_SH)
+#define __APP_PLL_SCLK_LOGIC_SOFT_RESET 0x00010000
+#define __APP_PLL_SCLK_CNTLMT0_1_MK 0x0000c000
+#define __APP_PLL_SCLK_CNTLMT0_1_SH 14
+#define __APP_PLL_SCLK_CNTLMT0_1(_v) ((_v) << __APP_PLL_SCLK_CNTLMT0_1_SH)
+#define __APP_PLL_SCLK_JITLMT0_1_MK 0x00003000
+#define __APP_PLL_SCLK_JITLMT0_1_SH 12
+#define __APP_PLL_SCLK_JITLMT0_1(_v) ((_v) << __APP_PLL_SCLK_JITLMT0_1_SH)
+#define __APP_PLL_SCLK_HREF 0x00000800
+#define __APP_PLL_SCLK_HDIV 0x00000400
+#define __APP_PLL_SCLK_P0_1_MK 0x00000300
+#define __APP_PLL_SCLK_P0_1_SH 8
+#define __APP_PLL_SCLK_P0_1(_v) ((_v) << __APP_PLL_SCLK_P0_1_SH)
+#define __APP_PLL_SCLK_Z0_2_MK 0x000000e0
+#define __APP_PLL_SCLK_Z0_2_SH 5
+#define __APP_PLL_SCLK_Z0_2(_v) ((_v) << __APP_PLL_SCLK_Z0_2_SH)
+#define __APP_PLL_SCLK_RSEL200500 0x00000010
+#define __APP_PLL_SCLK_ENARST 0x00000008
+#define __APP_PLL_SCLK_BYPASS 0x00000004
+#define __APP_PLL_SCLK_LRESETN 0x00000002
+#define __APP_PLL_SCLK_ENABLE 0x00000001
+#define __ENABLE_MAC_AHB_1 0x00800000 /* ct */
+#define __ENABLE_MAC_AHB_0 0x00400000 /* ct */
+#define __ENABLE_MAC_1 0x00200000 /* ct */
+#define __ENABLE_MAC_0 0x00100000 /* ct */
+
+#define HOST_SEM0_REG 0x00014230 /* cb/ct */
+#define HOST_SEM1_REG 0x00014234 /* cb/ct */
+#define HOST_SEM2_REG 0x00014238 /* cb/ct */
+#define HOST_SEM3_REG 0x0001423c /* cb/ct */
+#define HOST_SEM4_REG 0x00014610 /* cb/ct */
+#define HOST_SEM5_REG 0x00014614 /* cb/ct */
+#define HOST_SEM6_REG 0x00014618 /* cb/ct */
+#define HOST_SEM7_REG 0x0001461c /* cb/ct */
+#define HOST_SEM0_INFO_REG 0x00014240 /* cb/ct */
+#define HOST_SEM1_INFO_REG 0x00014244 /* cb/ct */
+#define HOST_SEM2_INFO_REG 0x00014248 /* cb/ct */
+#define HOST_SEM3_INFO_REG 0x0001424c /* cb/ct */
+#define HOST_SEM4_INFO_REG 0x00014620 /* cb/ct */
+#define HOST_SEM5_INFO_REG 0x00014624 /* cb/ct */
+#define HOST_SEM6_INFO_REG 0x00014628 /* cb/ct */
+#define HOST_SEM7_INFO_REG 0x0001462c /* cb/ct */
+
+#define HOSTFN0_LPU0_CMD_STAT 0x00019000 /* cb/ct */
+#define HOSTFN0_LPU1_CMD_STAT 0x00019004 /* cb/ct */
+#define HOSTFN1_LPU0_CMD_STAT 0x00019010 /* cb/ct */
+#define HOSTFN1_LPU1_CMD_STAT 0x00019014 /* cb/ct */
+#define HOSTFN2_LPU0_CMD_STAT 0x00019150 /* ct */
+#define HOSTFN2_LPU1_CMD_STAT 0x00019154 /* ct */
+#define HOSTFN3_LPU0_CMD_STAT 0x00019160 /* ct */
+#define HOSTFN3_LPU1_CMD_STAT 0x00019164 /* ct */
+#define LPU0_HOSTFN0_CMD_STAT 0x00019008 /* cb/ct */
+#define LPU1_HOSTFN0_CMD_STAT 0x0001900c /* cb/ct */
+#define LPU0_HOSTFN1_CMD_STAT 0x00019018 /* cb/ct */
+#define LPU1_HOSTFN1_CMD_STAT 0x0001901c /* cb/ct */
+#define LPU0_HOSTFN2_CMD_STAT 0x00019158 /* ct */
+#define LPU1_HOSTFN2_CMD_STAT 0x0001915c /* ct */
+#define LPU0_HOSTFN3_CMD_STAT 0x00019168 /* ct */
+#define LPU1_HOSTFN3_CMD_STAT 0x0001916c /* ct */
+
+#define PSS_CTL_REG 0x00018800 /* cb/ct */
+#define __PSS_I2C_CLK_DIV_MK 0x007f0000
+#define __PSS_I2C_CLK_DIV_SH 16
+#define __PSS_I2C_CLK_DIV(_v) ((_v) << __PSS_I2C_CLK_DIV_SH)
+#define __PSS_LMEM_INIT_DONE 0x00001000
+#define __PSS_LMEM_RESET 0x00000200
+#define __PSS_LMEM_INIT_EN 0x00000100
+#define __PSS_LPU1_RESET 0x00000002
+#define __PSS_LPU0_RESET 0x00000001
+#define PSS_ERR_STATUS_REG 0x00018810 /* cb/ct */
+#define ERR_SET_REG 0x00018818 /* cb/ct */
+#define PSS_GPIO_OUT_REG 0x000188c0 /* cb/ct */
+#define __PSS_GPIO_OUT_REG 0x00000fff
+#define PSS_GPIO_OE_REG 0x000188c8 /* cb/ct */
+#define __PSS_GPIO_OE_REG 0x000000ff
+
+#define HOSTFN0_LPU_MBOX0_0 0x00019200 /* cb/ct */
+#define HOSTFN1_LPU_MBOX0_8 0x00019260 /* cb/ct */
+#define LPU_HOSTFN0_MBOX0_0 0x00019280 /* cb/ct */
+#define LPU_HOSTFN1_MBOX0_8 0x000192e0 /* cb/ct */
+#define HOSTFN2_LPU_MBOX0_0 0x00019400 /* ct */
+#define HOSTFN3_LPU_MBOX0_8 0x00019460 /* ct */
+#define LPU_HOSTFN2_MBOX0_0 0x00019480 /* ct */
+#define LPU_HOSTFN3_MBOX0_8 0x000194e0 /* ct */
+
+#define HOST_MSIX_ERR_INDEX_FN0 0x0001400c /* ct */
+#define HOST_MSIX_ERR_INDEX_FN1 0x0001410c /* ct */
+#define HOST_MSIX_ERR_INDEX_FN2 0x0001430c /* ct */
+#define HOST_MSIX_ERR_INDEX_FN3 0x0001440c /* ct */
+
+#define MBIST_CTL_REG 0x00014220 /* ct */
+#define __EDRAM_BISTR_START 0x00000004
+#define MBIST_STAT_REG 0x00014224 /* ct */
+#define ETH_MAC_SER_REG 0x00014288 /* ct */
+#define __APP_EMS_CKBUFAMPIN 0x00000020
+#define __APP_EMS_REFCLKSEL 0x00000010
+#define __APP_EMS_CMLCKSEL 0x00000008
+#define __APP_EMS_REFCKBUFEN2 0x00000004
+#define __APP_EMS_REFCKBUFEN1 0x00000002
+#define __APP_EMS_CHANNEL_SEL 0x00000001
+#define FNC_PERS_REG 0x00014604 /* ct */
+#define __F3_FUNCTION_ACTIVE 0x80000000
+#define __F3_FUNCTION_MODE 0x40000000
+#define __F3_PORT_MAP_MK 0x30000000
+#define __F3_PORT_MAP_SH 28
+#define __F3_PORT_MAP(_v) ((_v) << __F3_PORT_MAP_SH)
+#define __F3_VM_MODE 0x08000000
+#define __F3_INTX_STATUS_MK 0x07000000
+#define __F3_INTX_STATUS_SH 24
+#define __F3_INTX_STATUS(_v) ((_v) << __F3_INTX_STATUS_SH)
+#define __F2_FUNCTION_ACTIVE 0x00800000
+#define __F2_FUNCTION_MODE 0x00400000
+#define __F2_PORT_MAP_MK 0x00300000
+#define __F2_PORT_MAP_SH 20
+#define __F2_PORT_MAP(_v) ((_v) << __F2_PORT_MAP_SH)
+#define __F2_VM_MODE 0x00080000
+#define __F2_INTX_STATUS_MK 0x00070000
+#define __F2_INTX_STATUS_SH 16
+#define __F2_INTX_STATUS(_v) ((_v) << __F2_INTX_STATUS_SH)
+#define __F1_FUNCTION_ACTIVE 0x00008000
+#define __F1_FUNCTION_MODE 0x00004000
+#define __F1_PORT_MAP_MK 0x00003000
+#define __F1_PORT_MAP_SH 12
+#define __F1_PORT_MAP(_v) ((_v) << __F1_PORT_MAP_SH)
+#define __F1_VM_MODE 0x00000800
+#define __F1_INTX_STATUS_MK 0x00000700
+#define __F1_INTX_STATUS_SH 8
+#define __F1_INTX_STATUS(_v) ((_v) << __F1_INTX_STATUS_SH)
+#define __F0_FUNCTION_ACTIVE 0x00000080
+#define __F0_FUNCTION_MODE 0x00000040
+#define __F0_PORT_MAP_MK 0x00000030
+#define __F0_PORT_MAP_SH 4
+#define __F0_PORT_MAP(_v) ((_v) << __F0_PORT_MAP_SH)
+#define __F0_VM_MODE 0x00000008
+#define __F0_INTX_STATUS 0x00000007
+enum {
+ __F0_INTX_STATUS_MSIX = 0x0,
+ __F0_INTX_STATUS_INTA = 0x1,
+ __F0_INTX_STATUS_INTB = 0x2,
+ __F0_INTX_STATUS_INTC = 0x3,
+ __F0_INTX_STATUS_INTD = 0x4,
+};
+
+#define OP_MODE 0x0001460c
+#define __APP_ETH_CLK_LOWSPEED 0x00000004
+#define __GLOBAL_CORECLK_HALFSPEED 0x00000002
+#define __GLOBAL_FCOE_MODE 0x00000001
+#define FW_INIT_HALT_P0 0x000191ac
+#define __FW_INIT_HALT_P 0x00000001
+#define FW_INIT_HALT_P1 0x000191bc
+#define PMM_1T_RESET_REG_P0 0x0002381c
+#define __PMM_1T_RESET_P 0x00000001
+#define PMM_1T_RESET_REG_P1 0x00023c1c
+
+/**
+ * Brocade 1860 Adapter specific defines
+ */
+#define CT2_PCI_CPQ_BASE 0x00030000
+#define CT2_PCI_APP_BASE 0x00030100
+#define CT2_PCI_ETH_BASE 0x00030400
+
+/*
+ * APP block registers
+ */
+#define CT2_HOSTFN_INT_STATUS (CT2_PCI_APP_BASE + 0x00)
+#define CT2_HOSTFN_INTR_MASK (CT2_PCI_APP_BASE + 0x04)
+#define CT2_HOSTFN_PERSONALITY0 (CT2_PCI_APP_BASE + 0x08)
+#define __PME_STATUS_ 0x00200000
+#define __PF_VF_BAR_SIZE_MODE__MK 0x00180000
+#define __PF_VF_BAR_SIZE_MODE__SH 19
+#define __PF_VF_BAR_SIZE_MODE_(_v) ((_v) << __PF_VF_BAR_SIZE_MODE__SH)
+#define __FC_LL_PORT_MAP__MK 0x00060000
+#define __FC_LL_PORT_MAP__SH 17
+#define __FC_LL_PORT_MAP_(_v) ((_v) << __FC_LL_PORT_MAP__SH)
+#define __PF_VF_ACTIVE_ 0x00010000
+#define __PF_VF_CFG_RDY_ 0x00008000
+#define __PF_VF_ENABLE_ 0x00004000
+#define __PF_DRIVER_ACTIVE_ 0x00002000
+#define __PF_PME_SEND_ENABLE_ 0x00001000
+#define __PF_EXROM_OFFSET__MK 0x00000ff0
+#define __PF_EXROM_OFFSET__SH 4
+#define __PF_EXROM_OFFSET_(_v) ((_v) << __PF_EXROM_OFFSET__SH)
+#define __FC_LL_MODE_ 0x00000008
+#define __PF_INTX_PIN_ 0x00000007
+#define CT2_HOSTFN_PERSONALITY1 (CT2_PCI_APP_BASE + 0x0C)
+#define __PF_NUM_QUEUES1__MK 0xff000000
+#define __PF_NUM_QUEUES1__SH 24
+#define __PF_NUM_QUEUES1_(_v) ((_v) << __PF_NUM_QUEUES1__SH)
+#define __PF_VF_QUE_OFFSET1__MK 0x00ff0000
+#define __PF_VF_QUE_OFFSET1__SH 16
+#define __PF_VF_QUE_OFFSET1_(_v) ((_v) << __PF_VF_QUE_OFFSET1__SH)
+#define __PF_VF_NUM_QUEUES__MK 0x0000ff00
+#define __PF_VF_NUM_QUEUES__SH 8
+#define __PF_VF_NUM_QUEUES_(_v) ((_v) << __PF_VF_NUM_QUEUES__SH)
+#define __PF_VF_QUE_OFFSET_ 0x000000ff
+#define CT2_HOSTFN_PAGE_NUM (CT2_PCI_APP_BASE + 0x18)
+#define CT2_HOSTFN_MSIX_VT_INDEX_MBOX_ERR (CT2_PCI_APP_BASE + 0x38)
+
+/*
+ * Brocade 1860 adapter CPQ block registers
+ */
+#define CT2_HOSTFN_LPU0_MBOX0 (CT2_PCI_CPQ_BASE + 0x00)
+#define CT2_HOSTFN_LPU1_MBOX0 (CT2_PCI_CPQ_BASE + 0x20)
+#define CT2_LPU0_HOSTFN_MBOX0 (CT2_PCI_CPQ_BASE + 0x40)
+#define CT2_LPU1_HOSTFN_MBOX0 (CT2_PCI_CPQ_BASE + 0x60)
+#define CT2_HOSTFN_LPU0_CMD_STAT (CT2_PCI_CPQ_BASE + 0x80)
+#define CT2_HOSTFN_LPU1_CMD_STAT (CT2_PCI_CPQ_BASE + 0x84)
+#define CT2_LPU0_HOSTFN_CMD_STAT (CT2_PCI_CPQ_BASE + 0x88)
+#define CT2_LPU1_HOSTFN_CMD_STAT (CT2_PCI_CPQ_BASE + 0x8c)
+#define CT2_HOSTFN_LPU0_READ_STAT (CT2_PCI_CPQ_BASE + 0x90)
+#define CT2_HOSTFN_LPU1_READ_STAT (CT2_PCI_CPQ_BASE + 0x94)
+#define CT2_LPU0_HOSTFN_MBOX0_MSK (CT2_PCI_CPQ_BASE + 0x98)
+#define CT2_LPU1_HOSTFN_MBOX0_MSK (CT2_PCI_CPQ_BASE + 0x9C)
+#define CT2_HOST_SEM0_REG 0x000148f0
+#define CT2_HOST_SEM1_REG 0x000148f4
+#define CT2_HOST_SEM2_REG 0x000148f8
+#define CT2_HOST_SEM3_REG 0x000148fc
+#define CT2_HOST_SEM4_REG 0x00014900
+#define CT2_HOST_SEM5_REG 0x00014904
+#define CT2_HOST_SEM6_REG 0x00014908
+#define CT2_HOST_SEM7_REG 0x0001490c
+#define CT2_HOST_SEM0_INFO_REG 0x000148b0
+#define CT2_HOST_SEM1_INFO_REG 0x000148b4
+#define CT2_HOST_SEM2_INFO_REG 0x000148b8
+#define CT2_HOST_SEM3_INFO_REG 0x000148bc
+#define CT2_HOST_SEM4_INFO_REG 0x000148c0
+#define CT2_HOST_SEM5_INFO_REG 0x000148c4
+#define CT2_HOST_SEM6_INFO_REG 0x000148c8
+#define CT2_HOST_SEM7_INFO_REG 0x000148cc
+
+#define CT2_APP_PLL_LCLK_CTL_REG 0x00014808
+#define __APP_LPUCLK_HALFSPEED 0x40000000
+#define __APP_PLL_LCLK_LOAD 0x20000000
+#define __APP_PLL_LCLK_FBCNT_MK 0x1fe00000
+#define __APP_PLL_LCLK_FBCNT_SH 21
+#define __APP_PLL_LCLK_FBCNT(_v) ((_v) << __APP_PLL_SCLK_FBCNT_SH)
+enum {
+ __APP_PLL_LCLK_FBCNT_425_MHZ = 6,
+ __APP_PLL_LCLK_FBCNT_468_MHZ = 4,
+};
+#define __APP_PLL_LCLK_EXTFB 0x00000800
+#define __APP_PLL_LCLK_ENOUTS 0x00000400
+#define __APP_PLL_LCLK_RATE 0x00000010
+#define CT2_APP_PLL_SCLK_CTL_REG 0x0001480c
+#define __P_SCLK_PLL_LOCK 0x80000000
+#define __APP_PLL_SCLK_REFCLK_SEL 0x40000000
+#define __APP_PLL_SCLK_CLK_DIV2 0x20000000
+#define __APP_PLL_SCLK_LOAD 0x10000000
+#define __APP_PLL_SCLK_FBCNT_MK 0x0ff00000
+#define __APP_PLL_SCLK_FBCNT_SH 20
+#define __APP_PLL_SCLK_FBCNT(_v) ((_v) << __APP_PLL_SCLK_FBCNT_SH)
+enum {
+ __APP_PLL_SCLK_FBCNT_NORM = 6,
+ __APP_PLL_SCLK_FBCNT_10G_FC = 10,
+};
+#define __APP_PLL_SCLK_EXTFB 0x00000800
+#define __APP_PLL_SCLK_ENOUTS 0x00000400
+#define __APP_PLL_SCLK_RATE 0x00000010
+#define CT2_PCIE_MISC_REG 0x00014804
+#define __ETH_CLK_ENABLE_PORT1 0x00000010
+#define CT2_CHIP_MISC_PRG 0x000148a4
+#define __ETH_CLK_ENABLE_PORT0 0x00004000
+#define __APP_LPU_SPEED 0x00000002
+#define CT2_MBIST_STAT_REG 0x00014818
+#define CT2_MBIST_CTL_REG 0x0001481c
+#define CT2_PMM_1T_CONTROL_REG_P0 0x0002381c
+#define __PMM_1T_PNDB_P 0x00000002
+#define CT2_PMM_1T_CONTROL_REG_P1 0x00023c1c
+#define CT2_WGN_STATUS 0x00014990
+#define __A2T_AHB_LOAD 0x00000800
+#define __WGN_READY 0x00000400
+#define __GLBL_PF_VF_CFG_RDY 0x00000200
+#define CT2_NFC_CSR_SET_REG 0x00027424
+#define __HALT_NFC_CONTROLLER 0x00000002
+#define __NFC_CONTROLLER_HALTED 0x00001000
+
+#define CT2_CSI_MAC0_CONTROL_REG 0x000270d0
+#define __CSI_MAC_RESET 0x00000010
+#define __CSI_MAC_AHB_RESET 0x00000008
+#define CT2_CSI_MAC1_CONTROL_REG 0x000270d4
+#define CT2_CSI_MAC_CONTROL_REG(__n) \
+ (CT2_CSI_MAC0_CONTROL_REG + \
+ (__n) * (CT2_CSI_MAC1_CONTROL_REG - CT2_CSI_MAC0_CONTROL_REG))
+
+/*
+ * Name semaphore registers based on usage
+ */
+#define BFA_IOC0_HBEAT_REG HOST_SEM0_INFO_REG
+#define BFA_IOC0_STATE_REG HOST_SEM1_INFO_REG
+#define BFA_IOC1_HBEAT_REG HOST_SEM2_INFO_REG
+#define BFA_IOC1_STATE_REG HOST_SEM3_INFO_REG
+#define BFA_FW_USE_COUNT HOST_SEM4_INFO_REG
+#define BFA_IOC_FAIL_SYNC HOST_SEM5_INFO_REG
+
+/*
+ * CT2 semaphore register locations changed
+ */
+#define CT2_BFA_IOC0_HBEAT_REG CT2_HOST_SEM0_INFO_REG
+#define CT2_BFA_IOC0_STATE_REG CT2_HOST_SEM1_INFO_REG
+#define CT2_BFA_IOC1_HBEAT_REG CT2_HOST_SEM2_INFO_REG
+#define CT2_BFA_IOC1_STATE_REG CT2_HOST_SEM3_INFO_REG
+#define CT2_BFA_FW_USE_COUNT CT2_HOST_SEM4_INFO_REG
+#define CT2_BFA_IOC_FAIL_SYNC CT2_HOST_SEM5_INFO_REG
+
+#define CPE_Q_NUM(__fn, __q) (((__fn) << 2) + (__q))
+#define RME_Q_NUM(__fn, __q) (((__fn) << 2) + (__q))
+
+/*
+ * And corresponding host interrupt status bit field defines
+ */
+#define __HFN_INT_CPE_Q0 0x00000001U
+#define __HFN_INT_CPE_Q1 0x00000002U
+#define __HFN_INT_CPE_Q2 0x00000004U
+#define __HFN_INT_CPE_Q3 0x00000008U
+#define __HFN_INT_CPE_Q4 0x00000010U
+#define __HFN_INT_CPE_Q5 0x00000020U
+#define __HFN_INT_CPE_Q6 0x00000040U
+#define __HFN_INT_CPE_Q7 0x00000080U
+#define __HFN_INT_RME_Q0 0x00000100U
+#define __HFN_INT_RME_Q1 0x00000200U
+#define __HFN_INT_RME_Q2 0x00000400U
+#define __HFN_INT_RME_Q3 0x00000800U
+#define __HFN_INT_RME_Q4 0x00001000U
+#define __HFN_INT_RME_Q5 0x00002000U
+#define __HFN_INT_RME_Q6 0x00004000U
+#define __HFN_INT_RME_Q7 0x00008000U
+#define __HFN_INT_ERR_EMC 0x00010000U
+#define __HFN_INT_ERR_LPU0 0x00020000U
+#define __HFN_INT_ERR_LPU1 0x00040000U
+#define __HFN_INT_ERR_PSS 0x00080000U
+#define __HFN_INT_MBOX_LPU0 0x00100000U
+#define __HFN_INT_MBOX_LPU1 0x00200000U
+#define __HFN_INT_MBOX1_LPU0 0x00400000U
+#define __HFN_INT_MBOX1_LPU1 0x00800000U
+#define __HFN_INT_LL_HALT 0x01000000U
+#define __HFN_INT_CPE_MASK 0x000000ffU
+#define __HFN_INT_RME_MASK 0x0000ff00U
+#define __HFN_INT_ERR_MASK \
+ (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 | __HFN_INT_ERR_LPU1 | \
+ __HFN_INT_ERR_PSS | __HFN_INT_LL_HALT)
+#define __HFN_INT_FN0_MASK \
+ (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 | __HFN_INT_CPE_Q2 | \
+ __HFN_INT_CPE_Q3 | __HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 | \
+ __HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 | __HFN_INT_MBOX_LPU0)
+#define __HFN_INT_FN1_MASK \
+ (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 | __HFN_INT_CPE_Q6 | \
+ __HFN_INT_CPE_Q7 | __HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 | \
+ __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 | __HFN_INT_MBOX_LPU1)
+
+/*
+ * Host interrupt status defines for 1860
+ */
+#define __HFN_INT_MBOX_LPU0_CT2 0x00010000U
+#define __HFN_INT_MBOX_LPU1_CT2 0x00020000U
+#define __HFN_INT_ERR_PSS_CT2 0x00040000U
+#define __HFN_INT_ERR_LPU0_CT2 0x00080000U
+#define __HFN_INT_ERR_LPU1_CT2 0x00100000U
+#define __HFN_INT_CPQ_HALT_CT2 0x00200000U
+#define __HFN_INT_ERR_WGN_CT2 0x00400000U
+#define __HFN_INT_ERR_LEHRX_CT2 0x00800000U
+#define __HFN_INT_ERR_LEHTX_CT2 0x01000000U
+#define __HFN_INT_ERR_MASK_CT2 \
+ (__HFN_INT_ERR_PSS_CT2 | __HFN_INT_ERR_LPU0_CT2 | \
+ __HFN_INT_ERR_LPU1_CT2 | __HFN_INT_CPQ_HALT_CT2 | \
+ __HFN_INT_ERR_WGN_CT2 | __HFN_INT_ERR_LEHRX_CT2 | \
+ __HFN_INT_ERR_LEHTX_CT2)
+#define __HFN_INT_FN0_MASK_CT2 \
+ (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 | __HFN_INT_CPE_Q2 | \
+ __HFN_INT_CPE_Q3 | __HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 | \
+ __HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 | __HFN_INT_MBOX_LPU0_CT2)
+#define __HFN_INT_FN1_MASK_CT2 \
+ (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 | __HFN_INT_CPE_Q6 | \
+ __HFN_INT_CPE_Q7 | __HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 | \
+ __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 | __HFN_INT_MBOX_LPU1_CT2)
+
+/*
+ * asic memory map.
+ */
+#define PSS_SMEM_PAGE_START 0x8000
+#define PSS_SMEM_PGNUM(_pg0, _ma) ((_pg0) + ((_ma) >> 15))
+#define PSS_SMEM_PGOFF(_ma) ((_ma) & 0x7fff)
+
+#endif /* __BFI_REG_H__ */
diff --git a/drivers/net/bna/bna.h b/drivers/net/ethernet/brocade/bna/bna.h
index 21e9155d6e56..4d7a5de08e12 100644
--- a/drivers/net/bna/bna.h
+++ b/drivers/net/ethernet/brocade/bna/bna.h
@@ -10,13 +10,17 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
+/*
+ * Copyright (c) 2005-2011 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
#ifndef __BNA_H__
#define __BNA_H__
-#include "bfa_cs.h"
+#include "bfa_defs.h"
#include "bfa_ioc.h"
-#include "cna.h"
-#include "bfi_ll.h"
+#include "bfi_enet.h"
#include "bna_types.h"
extern const u32 bna_napi_dim_vector[][BNA_BIAS_T_MAX];
@@ -32,15 +36,7 @@ extern const u32 bna_napi_dim_vector[][BNA_BIAS_T_MAX];
/* Log string size */
#define BNA_MESSAGE_SIZE 256
-/* MBOX API for PORT, TX, RX */
-#define bna_mbox_qe_fill(_qe, _cmd, _cmd_len, _cbfn, _cbarg) \
-do { \
- memcpy(&((_qe)->cmd.msg[0]), (_cmd), (_cmd_len)); \
- (_qe)->cbfn = (_cbfn); \
- (_qe)->cbarg = (_cbarg); \
-} while (0)
-
-#define bna_is_small_rxq(rcb) ((rcb)->id == 1)
+#define bna_is_small_rxq(_id) ((_id) & 0x1)
#define BNA_MAC_IS_EQUAL(_mac1, _mac2) \
(!memcmp((_mac1), (_mac2), sizeof(mac_t)))
@@ -177,32 +173,6 @@ do { \
#define BNA_Q_IN_USE_COUNT(_q_ptr) \
(BNA_QE_IN_USE_CNT(&(_q_ptr)->q, (_q_ptr)->q.q_depth))
-/* These macros build the data portion of the TxQ/RxQ doorbell */
-#define BNA_DOORBELL_Q_PRD_IDX(_pi) (0x80000000 | (_pi))
-#define BNA_DOORBELL_Q_STOP (0x40000000)
-
-/* These macros build the data portion of the IB doorbell */
-#define BNA_DOORBELL_IB_INT_ACK(_timeout, _events) \
- (0x80000000 | ((_timeout) << 16) | (_events))
-#define BNA_DOORBELL_IB_INT_DISABLE (0x40000000)
-
-/* Set the coalescing timer for the given ib */
-#define bna_ib_coalescing_timer_set(_i_dbell, _cls_timer) \
- ((_i_dbell)->doorbell_ack = BNA_DOORBELL_IB_INT_ACK((_cls_timer), 0));
-
-/* Acks 'events' # of events for a given ib */
-#define bna_ib_ack(_i_dbell, _events) \
- (writel(((_i_dbell)->doorbell_ack | (_events)), \
- (_i_dbell)->doorbell_addr));
-
-#define bna_txq_prod_indx_doorbell(_tcb) \
- (writel(BNA_DOORBELL_Q_PRD_IDX((_tcb)->producer_index), \
- (_tcb)->q_dbell));
-
-#define bna_rxq_prod_indx_doorbell(_rcb) \
- (writel(BNA_DOORBELL_Q_PRD_IDX((_rcb)->producer_index), \
- (_rcb)->q_dbell));
-
#define BNA_LARGE_PKT_SIZE 1000
#define BNA_UPDATE_PKT_CNT(_pkt, _len) \
@@ -214,38 +184,59 @@ do { \
} \
} while (0)
-#define call_rxf_stop_cbfn(rxf, status) \
+#define call_rxf_stop_cbfn(rxf) \
+do { \
if ((rxf)->stop_cbfn) { \
- (*(rxf)->stop_cbfn)((rxf)->stop_cbarg, (status)); \
+ void (*cbfn)(struct bna_rx *); \
+ struct bna_rx *cbarg; \
+ cbfn = (rxf)->stop_cbfn; \
+ cbarg = (rxf)->stop_cbarg; \
(rxf)->stop_cbfn = NULL; \
(rxf)->stop_cbarg = NULL; \
- }
+ cbfn(cbarg); \
+ } \
+} while (0)
-#define call_rxf_start_cbfn(rxf, status) \
+#define call_rxf_start_cbfn(rxf) \
+do { \
if ((rxf)->start_cbfn) { \
- (*(rxf)->start_cbfn)((rxf)->start_cbarg, (status)); \
+ void (*cbfn)(struct bna_rx *); \
+ struct bna_rx *cbarg; \
+ cbfn = (rxf)->start_cbfn; \
+ cbarg = (rxf)->start_cbarg; \
(rxf)->start_cbfn = NULL; \
(rxf)->start_cbarg = NULL; \
- }
+ cbfn(cbarg); \
+ } \
+} while (0)
-#define call_rxf_cam_fltr_cbfn(rxf, status) \
+#define call_rxf_cam_fltr_cbfn(rxf) \
+do { \
if ((rxf)->cam_fltr_cbfn) { \
- (*(rxf)->cam_fltr_cbfn)((rxf)->cam_fltr_cbarg, rxf->rx, \
- (status)); \
+ void (*cbfn)(struct bnad *, struct bna_rx *); \
+ struct bnad *cbarg; \
+ cbfn = (rxf)->cam_fltr_cbfn; \
+ cbarg = (rxf)->cam_fltr_cbarg; \
(rxf)->cam_fltr_cbfn = NULL; \
(rxf)->cam_fltr_cbarg = NULL; \
- }
+ cbfn(cbarg, rxf->rx); \
+ } \
+} while (0)
-#define call_rxf_pause_cbfn(rxf, status) \
+#define call_rxf_pause_cbfn(rxf) \
+do { \
if ((rxf)->oper_state_cbfn) { \
- (*(rxf)->oper_state_cbfn)((rxf)->oper_state_cbarg, rxf->rx,\
- (status)); \
- (rxf)->rxf_flags &= ~BNA_RXF_FL_OPERSTATE_CHANGED; \
+ void (*cbfn)(struct bnad *, struct bna_rx *); \
+ struct bnad *cbarg; \
+ cbfn = (rxf)->oper_state_cbfn; \
+ cbarg = (rxf)->oper_state_cbarg; \
(rxf)->oper_state_cbfn = NULL; \
(rxf)->oper_state_cbarg = NULL; \
- }
+ cbfn(cbarg, rxf->rx); \
+ } \
+} while (0)
-#define call_rxf_resume_cbfn(rxf, status) call_rxf_pause_cbfn(rxf, status)
+#define call_rxf_resume_cbfn(rxf) call_rxf_pause_cbfn(rxf)
#define is_xxx_enable(mode, bitmask, xxx) ((bitmask & xxx) && (mode & xxx))
@@ -331,6 +322,61 @@ do { \
} \
} while (0)
+#define bna_tx_rid_mask(_bna) ((_bna)->tx_mod.rid_mask)
+
+#define bna_rx_rid_mask(_bna) ((_bna)->rx_mod.rid_mask)
+
+#define bna_tx_from_rid(_bna, _rid, _tx) \
+do { \
+ struct bna_tx_mod *__tx_mod = &(_bna)->tx_mod; \
+ struct bna_tx *__tx; \
+ struct list_head *qe; \
+ _tx = NULL; \
+ list_for_each(qe, &__tx_mod->tx_active_q) { \
+ __tx = (struct bna_tx *)qe; \
+ if (__tx->rid == (_rid)) { \
+ (_tx) = __tx; \
+ break; \
+ } \
+ } \
+} while (0)
+
+#define bna_rx_from_rid(_bna, _rid, _rx) \
+do { \
+ struct bna_rx_mod *__rx_mod = &(_bna)->rx_mod; \
+ struct bna_rx *__rx; \
+ struct list_head *qe; \
+ _rx = NULL; \
+ list_for_each(qe, &__rx_mod->rx_active_q) { \
+ __rx = (struct bna_rx *)qe; \
+ if (__rx->rid == (_rid)) { \
+ (_rx) = __rx; \
+ break; \
+ } \
+ } \
+} while (0)
+
+/**
+ *
+ * Inline functions
+ *
+ */
+
+static inline struct bna_mac *bna_mac_find(struct list_head *q, u8 *addr)
+{
+ struct bna_mac *mac = NULL;
+ struct list_head *qe;
+ list_for_each(qe, q) {
+ if (BNA_MAC_IS_EQUAL(((struct bna_mac *)qe)->addr, addr)) {
+ mac = (struct bna_mac *)qe;
+ break;
+ }
+ }
+ return mac;
+}
+
+#define bna_attr(_bna) (&(_bna)->ioceth.attr)
+
/**
*
* Function prototypes
@@ -341,17 +387,20 @@ do { \
* BNA
*/
+/* FW response handlers */
+void bna_bfi_stats_clr_rsp(struct bna *bna, struct bfi_msgq_mhdr *msghdr);
+
/* APIs for BNAD */
void bna_res_req(struct bna_res_info *res_info);
+void bna_mod_res_req(struct bna *bna, struct bna_res_info *res_info);
void bna_init(struct bna *bna, struct bnad *bnad,
struct bfa_pcidev *pcidev,
struct bna_res_info *res_info);
+void bna_mod_init(struct bna *bna, struct bna_res_info *res_info);
void bna_uninit(struct bna *bna);
-void bna_stats_get(struct bna *bna);
-void bna_get_perm_mac(struct bna *bna, u8 *mac);
-
-/* APIs for Rx */
-int bna_rit_mod_can_satisfy(struct bna_rit_mod *rit_mod, int seg_size);
+int bna_num_txq_set(struct bna *bna, int num_txq);
+int bna_num_rxp_set(struct bna *bna, int num_rxp);
+void bna_hw_stats_get(struct bna *bna);
/* APIs for RxF */
struct bna_mac *bna_ucam_mod_mac_get(struct bna_ucam_mod *ucam_mod);
@@ -360,127 +409,78 @@ void bna_ucam_mod_mac_put(struct bna_ucam_mod *ucam_mod,
struct bna_mac *bna_mcam_mod_mac_get(struct bna_mcam_mod *mcam_mod);
void bna_mcam_mod_mac_put(struct bna_mcam_mod *mcam_mod,
struct bna_mac *mac);
-struct bna_rit_segment *
-bna_rit_mod_seg_get(struct bna_rit_mod *rit_mod, int seg_size);
-void bna_rit_mod_seg_put(struct bna_rit_mod *rit_mod,
- struct bna_rit_segment *seg);
-
-/**
- * DEVICE
- */
-
-/* APIs for BNAD */
-void bna_device_enable(struct bna_device *device);
-void bna_device_disable(struct bna_device *device,
- enum bna_cleanup_type type);
+struct bna_mcam_handle *bna_mcam_mod_handle_get(struct bna_mcam_mod *mod);
+void bna_mcam_mod_handle_put(struct bna_mcam_mod *mcam_mod,
+ struct bna_mcam_handle *handle);
/**
* MBOX
*/
-/* APIs for PORT, TX, RX */
-void bna_mbox_handler(struct bna *bna, u32 intr_status);
-void bna_mbox_send(struct bna *bna, struct bna_mbox_qe *mbox_qe);
-
-/**
- * PORT
- */
-
-/* API for RX */
-int bna_port_mtu_get(struct bna_port *port);
-void bna_llport_rx_started(struct bna_llport *llport);
-void bna_llport_rx_stopped(struct bna_llport *llport);
-
/* API for BNAD */
-void bna_port_enable(struct bna_port *port);
-void bna_port_disable(struct bna_port *port, enum bna_cleanup_type type,
- void (*cbfn)(void *, enum bna_cb_status));
-void bna_port_pause_config(struct bna_port *port,
- struct bna_pause_config *pause_config,
- void (*cbfn)(struct bnad *, enum bna_cb_status));
-void bna_port_mtu_set(struct bna_port *port, int mtu,
- void (*cbfn)(struct bnad *, enum bna_cb_status));
-void bna_port_mac_get(struct bna_port *port, mac_t *mac);
-
-/* Callbacks for TX, RX */
-void bna_port_cb_tx_stopped(struct bna_port *port,
- enum bna_cb_status status);
-void bna_port_cb_rx_stopped(struct bna_port *port,
- enum bna_cb_status status);
+void bna_mbox_handler(struct bna *bna, u32 intr_status);
/**
- * IB
+ * ETHPORT
*/
-/* APIs for BNA */
-void bna_ib_mod_init(struct bna_ib_mod *ib_mod, struct bna *bna,
- struct bna_res_info *res_info);
-void bna_ib_mod_uninit(struct bna_ib_mod *ib_mod);
+/* Callbacks for RX */
+void bna_ethport_cb_rx_started(struct bna_ethport *ethport);
+void bna_ethport_cb_rx_stopped(struct bna_ethport *ethport);
/**
* TX MODULE AND TX
*/
+/* FW response handelrs */
+void bna_bfi_tx_enet_start_rsp(struct bna_tx *tx,
+ struct bfi_msgq_mhdr *msghdr);
+void bna_bfi_tx_enet_stop_rsp(struct bna_tx *tx,
+ struct bfi_msgq_mhdr *msghdr);
+void bna_bfi_bw_update_aen(struct bna_tx_mod *tx_mod);
/* APIs for BNA */
void bna_tx_mod_init(struct bna_tx_mod *tx_mod, struct bna *bna,
struct bna_res_info *res_info);
void bna_tx_mod_uninit(struct bna_tx_mod *tx_mod);
-int bna_tx_state_get(struct bna_tx *tx);
-/* APIs for PORT */
+/* APIs for ENET */
void bna_tx_mod_start(struct bna_tx_mod *tx_mod, enum bna_tx_type type);
void bna_tx_mod_stop(struct bna_tx_mod *tx_mod, enum bna_tx_type type);
void bna_tx_mod_fail(struct bna_tx_mod *tx_mod);
-void bna_tx_mod_prio_changed(struct bna_tx_mod *tx_mod, int prio);
-void bna_tx_mod_cee_link_status(struct bna_tx_mod *tx_mod, int cee_link);
/* APIs for BNAD */
void bna_tx_res_req(int num_txq, int txq_depth,
struct bna_res_info *res_info);
struct bna_tx *bna_tx_create(struct bna *bna, struct bnad *bnad,
struct bna_tx_config *tx_cfg,
- struct bna_tx_event_cbfn *tx_cbfn,
+ const struct bna_tx_event_cbfn *tx_cbfn,
struct bna_res_info *res_info, void *priv);
void bna_tx_destroy(struct bna_tx *tx);
void bna_tx_enable(struct bna_tx *tx);
void bna_tx_disable(struct bna_tx *tx, enum bna_cleanup_type type,
- void (*cbfn)(void *, struct bna_tx *,
- enum bna_cb_status));
+ void (*cbfn)(void *, struct bna_tx *));
+void bna_tx_cleanup_complete(struct bna_tx *tx);
void bna_tx_coalescing_timeo_set(struct bna_tx *tx, int coalescing_timeo);
/**
* RX MODULE, RX, RXF
*/
-/* Internal APIs */
-void rxf_cb_cam_fltr_mbox_cmd(void *arg, int status);
-void rxf_cam_mbox_cmd(struct bna_rxf *rxf, u8 cmd,
- const struct bna_mac *mac_addr);
-void __rxf_vlan_filter_set(struct bna_rxf *rxf, enum bna_status status);
-void bna_rxf_adv_init(struct bna_rxf *rxf,
- struct bna_rx *rx,
- struct bna_rx_config *q_config);
-int rxf_process_packet_filter_ucast(struct bna_rxf *rxf);
-int rxf_process_packet_filter_promisc(struct bna_rxf *rxf);
-int rxf_process_packet_filter_default(struct bna_rxf *rxf);
-int rxf_process_packet_filter_allmulti(struct bna_rxf *rxf);
-int rxf_clear_packet_filter_ucast(struct bna_rxf *rxf);
-int rxf_clear_packet_filter_promisc(struct bna_rxf *rxf);
-int rxf_clear_packet_filter_default(struct bna_rxf *rxf);
-int rxf_clear_packet_filter_allmulti(struct bna_rxf *rxf);
-void rxf_reset_packet_filter_ucast(struct bna_rxf *rxf);
-void rxf_reset_packet_filter_promisc(struct bna_rxf *rxf);
-void rxf_reset_packet_filter_default(struct bna_rxf *rxf);
-void rxf_reset_packet_filter_allmulti(struct bna_rxf *rxf);
+/* FW response handlers */
+void bna_bfi_rx_enet_start_rsp(struct bna_rx *rx,
+ struct bfi_msgq_mhdr *msghdr);
+void bna_bfi_rx_enet_stop_rsp(struct bna_rx *rx,
+ struct bfi_msgq_mhdr *msghdr);
+void bna_bfi_rxf_cfg_rsp(struct bna_rxf *rxf, struct bfi_msgq_mhdr *msghdr);
+void bna_bfi_rxf_mcast_add_rsp(struct bna_rxf *rxf,
+ struct bfi_msgq_mhdr *msghdr);
/* APIs for BNA */
void bna_rx_mod_init(struct bna_rx_mod *rx_mod, struct bna *bna,
struct bna_res_info *res_info);
void bna_rx_mod_uninit(struct bna_rx_mod *rx_mod);
-int bna_rx_state_get(struct bna_rx *rx);
-int bna_rxf_state_get(struct bna_rxf *rxf);
-/* APIs for PORT */
+/* APIs for ENET */
void bna_rx_mod_start(struct bna_rx_mod *rx_mod, enum bna_rx_type type);
void bna_rx_mod_stop(struct bna_rx_mod *rx_mod, enum bna_rx_type type);
void bna_rx_mod_fail(struct bna_rx_mod *rx_mod);
@@ -490,59 +490,86 @@ void bna_rx_res_req(struct bna_rx_config *rx_config,
struct bna_res_info *res_info);
struct bna_rx *bna_rx_create(struct bna *bna, struct bnad *bnad,
struct bna_rx_config *rx_cfg,
- struct bna_rx_event_cbfn *rx_cbfn,
+ const struct bna_rx_event_cbfn *rx_cbfn,
struct bna_res_info *res_info, void *priv);
void bna_rx_destroy(struct bna_rx *rx);
void bna_rx_enable(struct bna_rx *rx);
void bna_rx_disable(struct bna_rx *rx, enum bna_cleanup_type type,
- void (*cbfn)(void *, struct bna_rx *,
- enum bna_cb_status));
+ void (*cbfn)(void *, struct bna_rx *));
+void bna_rx_cleanup_complete(struct bna_rx *rx);
void bna_rx_coalescing_timeo_set(struct bna_rx *rx, int coalescing_timeo);
void bna_rx_dim_reconfig(struct bna *bna, const u32 vector[][BNA_BIAS_T_MAX]);
void bna_rx_dim_update(struct bna_ccb *ccb);
enum bna_cb_status
bna_rx_ucast_set(struct bna_rx *rx, u8 *ucmac,
- void (*cbfn)(struct bnad *, struct bna_rx *,
- enum bna_cb_status));
+ void (*cbfn)(struct bnad *, struct bna_rx *));
+enum bna_cb_status
+bna_rx_ucast_add(struct bna_rx *rx, u8* ucmac,
+ void (*cbfn)(struct bnad *, struct bna_rx *));
+enum bna_cb_status
+bna_rx_ucast_del(struct bna_rx *rx, u8 *ucmac,
+ void (*cbfn)(struct bnad *, struct bna_rx *));
enum bna_cb_status
bna_rx_mcast_add(struct bna_rx *rx, u8 *mcmac,
- void (*cbfn)(struct bnad *, struct bna_rx *,
- enum bna_cb_status));
+ void (*cbfn)(struct bnad *, struct bna_rx *));
enum bna_cb_status
bna_rx_mcast_listset(struct bna_rx *rx, int count, u8 *mcmac,
- void (*cbfn)(struct bnad *, struct bna_rx *,
- enum bna_cb_status));
+ void (*cbfn)(struct bnad *, struct bna_rx *));
enum bna_cb_status
bna_rx_mode_set(struct bna_rx *rx, enum bna_rxmode rxmode,
enum bna_rxmode bitmask,
- void (*cbfn)(struct bnad *, struct bna_rx *,
- enum bna_cb_status));
+ void (*cbfn)(struct bnad *, struct bna_rx *));
void bna_rx_vlan_add(struct bna_rx *rx, int vlan_id);
void bna_rx_vlan_del(struct bna_rx *rx, int vlan_id);
void bna_rx_vlanfilter_enable(struct bna_rx *rx);
-void bna_rx_hds_enable(struct bna_rx *rx, struct bna_rxf_hds *hds_config,
- void (*cbfn)(struct bnad *, struct bna_rx *,
- enum bna_cb_status));
-void bna_rx_hds_disable(struct bna_rx *rx,
- void (*cbfn)(struct bnad *, struct bna_rx *,
- enum bna_cb_status));
+/**
+ * ENET
+ */
+
+/* API for RX */
+int bna_enet_mtu_get(struct bna_enet *enet);
+
+/* Callbacks for TX, RX */
+void bna_enet_cb_tx_stopped(struct bna_enet *enet);
+void bna_enet_cb_rx_stopped(struct bna_enet *enet);
+
+/* API for BNAD */
+void bna_enet_enable(struct bna_enet *enet);
+void bna_enet_disable(struct bna_enet *enet, enum bna_cleanup_type type,
+ void (*cbfn)(void *));
+void bna_enet_pause_config(struct bna_enet *enet,
+ struct bna_pause_config *pause_config,
+ void (*cbfn)(struct bnad *));
+void bna_enet_mtu_set(struct bna_enet *enet, int mtu,
+ void (*cbfn)(struct bnad *));
+void bna_enet_perm_mac_get(struct bna_enet *enet, mac_t *mac);
+
+/**
+ * IOCETH
+ */
+
+/* APIs for BNAD */
+void bna_ioceth_enable(struct bna_ioceth *ioceth);
+void bna_ioceth_disable(struct bna_ioceth *ioceth,
+ enum bna_cleanup_type type);
/**
* BNAD
*/
+/* Callbacks for ENET */
+void bnad_cb_ethport_link_status(struct bnad *bnad,
+ enum bna_link_status status);
+
+/* Callbacks for IOCETH */
+void bnad_cb_ioceth_ready(struct bnad *bnad);
+void bnad_cb_ioceth_failed(struct bnad *bnad);
+void bnad_cb_ioceth_disabled(struct bnad *bnad);
+void bnad_cb_mbox_intr_enable(struct bnad *bnad);
+void bnad_cb_mbox_intr_disable(struct bnad *bnad);
+
/* Callbacks for BNA */
void bnad_cb_stats_get(struct bnad *bnad, enum bna_cb_status status,
struct bna_stats *stats);
-/* Callbacks for DEVICE */
-void bnad_cb_device_enabled(struct bnad *bnad, enum bna_cb_status status);
-void bnad_cb_device_disabled(struct bnad *bnad, enum bna_cb_status status);
-void bnad_cb_device_enable_mbox_intr(struct bnad *bnad);
-void bnad_cb_device_disable_mbox_intr(struct bnad *bnad);
-
-/* Callbacks for port */
-void bnad_cb_port_link_status(struct bnad *bnad,
- enum bna_link_status status);
-
#endif /* __BNA_H__ */
diff --git a/drivers/net/ethernet/brocade/bna/bna_enet.c b/drivers/net/ethernet/brocade/bna/bna_enet.c
new file mode 100644
index 000000000000..26f5c5abfd1f
--- /dev/null
+++ b/drivers/net/ethernet/brocade/bna/bna_enet.c
@@ -0,0 +1,2144 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2005-2011 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+#include "bna.h"
+
+static inline int
+ethport_can_be_up(struct bna_ethport *ethport)
+{
+ int ready = 0;
+ if (ethport->bna->enet.type == BNA_ENET_T_REGULAR)
+ ready = ((ethport->flags & BNA_ETHPORT_F_ADMIN_UP) &&
+ (ethport->flags & BNA_ETHPORT_F_RX_STARTED) &&
+ (ethport->flags & BNA_ETHPORT_F_PORT_ENABLED));
+ else
+ ready = ((ethport->flags & BNA_ETHPORT_F_ADMIN_UP) &&
+ (ethport->flags & BNA_ETHPORT_F_RX_STARTED) &&
+ !(ethport->flags & BNA_ETHPORT_F_PORT_ENABLED));
+ return ready;
+}
+
+#define ethport_is_up ethport_can_be_up
+
+enum bna_ethport_event {
+ ETHPORT_E_START = 1,
+ ETHPORT_E_STOP = 2,
+ ETHPORT_E_FAIL = 3,
+ ETHPORT_E_UP = 4,
+ ETHPORT_E_DOWN = 5,
+ ETHPORT_E_FWRESP_UP_OK = 6,
+ ETHPORT_E_FWRESP_DOWN = 7,
+ ETHPORT_E_FWRESP_UP_FAIL = 8,
+};
+
+enum bna_enet_event {
+ ENET_E_START = 1,
+ ENET_E_STOP = 2,
+ ENET_E_FAIL = 3,
+ ENET_E_PAUSE_CFG = 4,
+ ENET_E_MTU_CFG = 5,
+ ENET_E_FWRESP_PAUSE = 6,
+ ENET_E_CHLD_STOPPED = 7,
+};
+
+enum bna_ioceth_event {
+ IOCETH_E_ENABLE = 1,
+ IOCETH_E_DISABLE = 2,
+ IOCETH_E_IOC_RESET = 3,
+ IOCETH_E_IOC_FAILED = 4,
+ IOCETH_E_IOC_READY = 5,
+ IOCETH_E_ENET_ATTR_RESP = 6,
+ IOCETH_E_ENET_STOPPED = 7,
+ IOCETH_E_IOC_DISABLED = 8,
+};
+
+#define bna_stats_copy(_name, _type) \
+do { \
+ count = sizeof(struct bfi_enet_stats_ ## _type) / sizeof(u64); \
+ stats_src = (u64 *)&bna->stats.hw_stats_kva->_name ## _stats; \
+ stats_dst = (u64 *)&bna->stats.hw_stats._name ## _stats; \
+ for (i = 0; i < count; i++) \
+ stats_dst[i] = be64_to_cpu(stats_src[i]); \
+} while (0) \
+
+/*
+ * FW response handlers
+ */
+
+static void
+bna_bfi_ethport_enable_aen(struct bna_ethport *ethport,
+ struct bfi_msgq_mhdr *msghdr)
+{
+ ethport->flags |= BNA_ETHPORT_F_PORT_ENABLED;
+
+ if (ethport_can_be_up(ethport))
+ bfa_fsm_send_event(ethport, ETHPORT_E_UP);
+}
+
+static void
+bna_bfi_ethport_disable_aen(struct bna_ethport *ethport,
+ struct bfi_msgq_mhdr *msghdr)
+{
+ int ethport_up = ethport_is_up(ethport);
+
+ ethport->flags &= ~BNA_ETHPORT_F_PORT_ENABLED;
+
+ if (ethport_up)
+ bfa_fsm_send_event(ethport, ETHPORT_E_DOWN);
+}
+
+static void
+bna_bfi_ethport_admin_rsp(struct bna_ethport *ethport,
+ struct bfi_msgq_mhdr *msghdr)
+{
+ struct bfi_enet_enable_req *admin_req =
+ &ethport->bfi_enet_cmd.admin_req;
+ struct bfi_enet_rsp *rsp = (struct bfi_enet_rsp *)msghdr;
+
+ switch (admin_req->enable) {
+ case BNA_STATUS_T_ENABLED:
+ if (rsp->error == BFI_ENET_CMD_OK)
+ bfa_fsm_send_event(ethport, ETHPORT_E_FWRESP_UP_OK);
+ else {
+ ethport->flags &= ~BNA_ETHPORT_F_PORT_ENABLED;
+ bfa_fsm_send_event(ethport, ETHPORT_E_FWRESP_UP_FAIL);
+ }
+ break;
+
+ case BNA_STATUS_T_DISABLED:
+ bfa_fsm_send_event(ethport, ETHPORT_E_FWRESP_DOWN);
+ ethport->link_status = BNA_LINK_DOWN;
+ ethport->link_cbfn(ethport->bna->bnad, BNA_LINK_DOWN);
+ break;
+ }
+}
+
+static void
+bna_bfi_ethport_lpbk_rsp(struct bna_ethport *ethport,
+ struct bfi_msgq_mhdr *msghdr)
+{
+ struct bfi_enet_diag_lb_req *diag_lb_req =
+ &ethport->bfi_enet_cmd.lpbk_req;
+ struct bfi_enet_rsp *rsp = (struct bfi_enet_rsp *)msghdr;
+
+ switch (diag_lb_req->enable) {
+ case BNA_STATUS_T_ENABLED:
+ if (rsp->error == BFI_ENET_CMD_OK)
+ bfa_fsm_send_event(ethport, ETHPORT_E_FWRESP_UP_OK);
+ else {
+ ethport->flags &= ~BNA_ETHPORT_F_ADMIN_UP;
+ bfa_fsm_send_event(ethport, ETHPORT_E_FWRESP_UP_FAIL);
+ }
+ break;
+
+ case BNA_STATUS_T_DISABLED:
+ bfa_fsm_send_event(ethport, ETHPORT_E_FWRESP_DOWN);
+ break;
+ }
+}
+
+static void
+bna_bfi_pause_set_rsp(struct bna_enet *enet, struct bfi_msgq_mhdr *msghdr)
+{
+ bfa_fsm_send_event(enet, ENET_E_FWRESP_PAUSE);
+}
+
+static void
+bna_bfi_attr_get_rsp(struct bna_ioceth *ioceth,
+ struct bfi_msgq_mhdr *msghdr)
+{
+ struct bfi_enet_attr_rsp *rsp = (struct bfi_enet_attr_rsp *)msghdr;
+
+ /**
+ * Store only if not set earlier, since BNAD can override the HW
+ * attributes
+ */
+ if (!ioceth->attr.fw_query_complete) {
+ ioceth->attr.num_txq = ntohl(rsp->max_cfg);
+ ioceth->attr.num_rxp = ntohl(rsp->max_cfg);
+ ioceth->attr.num_ucmac = ntohl(rsp->max_ucmac);
+ ioceth->attr.num_mcmac = BFI_ENET_MAX_MCAM;
+ ioceth->attr.max_rit_size = ntohl(rsp->rit_size);
+ ioceth->attr.fw_query_complete = true;
+ }
+
+ bfa_fsm_send_event(ioceth, IOCETH_E_ENET_ATTR_RESP);
+}
+
+static void
+bna_bfi_stats_get_rsp(struct bna *bna, struct bfi_msgq_mhdr *msghdr)
+{
+ struct bfi_enet_stats_req *stats_req = &bna->stats_mod.stats_get;
+ u64 *stats_src;
+ u64 *stats_dst;
+ u32 tx_enet_mask = ntohl(stats_req->tx_enet_mask);
+ u32 rx_enet_mask = ntohl(stats_req->rx_enet_mask);
+ int count;
+ int i;
+
+ bna_stats_copy(mac, mac);
+ bna_stats_copy(bpc, bpc);
+ bna_stats_copy(rad, rad);
+ bna_stats_copy(rlb, rad);
+ bna_stats_copy(fc_rx, fc_rx);
+ bna_stats_copy(fc_tx, fc_tx);
+
+ stats_src = (u64 *)&(bna->stats.hw_stats_kva->rxf_stats[0]);
+
+ /* Copy Rxf stats to SW area, scatter them while copying */
+ for (i = 0; i < BFI_ENET_CFG_MAX; i++) {
+ stats_dst = (u64 *)&(bna->stats.hw_stats.rxf_stats[i]);
+ memset(stats_dst, 0, sizeof(struct bfi_enet_stats_rxf));
+ if (rx_enet_mask & ((u32)(1 << i))) {
+ int k;
+ count = sizeof(struct bfi_enet_stats_rxf) /
+ sizeof(u64);
+ for (k = 0; k < count; k++) {
+ stats_dst[k] = be64_to_cpu(*stats_src);
+ stats_src++;
+ }
+ }
+ }
+
+ /* Copy Txf stats to SW area, scatter them while copying */
+ for (i = 0; i < BFI_ENET_CFG_MAX; i++) {
+ stats_dst = (u64 *)&(bna->stats.hw_stats.txf_stats[i]);
+ memset(stats_dst, 0, sizeof(struct bfi_enet_stats_txf));
+ if (tx_enet_mask & ((u32)(1 << i))) {
+ int k;
+ count = sizeof(struct bfi_enet_stats_txf) /
+ sizeof(u64);
+ for (k = 0; k < count; k++) {
+ stats_dst[k] = be64_to_cpu(*stats_src);
+ stats_src++;
+ }
+ }
+ }
+
+ bna->stats_mod.stats_get_busy = false;
+ bnad_cb_stats_get(bna->bnad, BNA_CB_SUCCESS, &bna->stats);
+}
+
+static void
+bna_bfi_ethport_linkup_aen(struct bna_ethport *ethport,
+ struct bfi_msgq_mhdr *msghdr)
+{
+ ethport->link_status = BNA_LINK_UP;
+
+ /* Dispatch events */
+ ethport->link_cbfn(ethport->bna->bnad, ethport->link_status);
+}
+
+static void
+bna_bfi_ethport_linkdown_aen(struct bna_ethport *ethport,
+ struct bfi_msgq_mhdr *msghdr)
+{
+ ethport->link_status = BNA_LINK_DOWN;
+
+ /* Dispatch events */
+ ethport->link_cbfn(ethport->bna->bnad, BNA_LINK_DOWN);
+}
+
+static void
+bna_err_handler(struct bna *bna, u32 intr_status)
+{
+ if (BNA_IS_HALT_INTR(bna, intr_status))
+ bna_halt_clear(bna);
+
+ bfa_nw_ioc_error_isr(&bna->ioceth.ioc);
+}
+
+void
+bna_mbox_handler(struct bna *bna, u32 intr_status)
+{
+ if (BNA_IS_ERR_INTR(bna, intr_status)) {
+ bna_err_handler(bna, intr_status);
+ return;
+ }
+ if (BNA_IS_MBOX_INTR(bna, intr_status))
+ bfa_nw_ioc_mbox_isr(&bna->ioceth.ioc);
+}
+
+static void
+bna_msgq_rsp_handler(void *arg, struct bfi_msgq_mhdr *msghdr)
+{
+ struct bna *bna = (struct bna *)arg;
+ struct bna_tx *tx;
+ struct bna_rx *rx;
+
+ switch (msghdr->msg_id) {
+ case BFI_ENET_I2H_RX_CFG_SET_RSP:
+ bna_rx_from_rid(bna, msghdr->enet_id, rx);
+ if (rx)
+ bna_bfi_rx_enet_start_rsp(rx, msghdr);
+ break;
+
+ case BFI_ENET_I2H_RX_CFG_CLR_RSP:
+ bna_rx_from_rid(bna, msghdr->enet_id, rx);
+ if (rx)
+ bna_bfi_rx_enet_stop_rsp(rx, msghdr);
+ break;
+
+ case BFI_ENET_I2H_RIT_CFG_RSP:
+ case BFI_ENET_I2H_RSS_CFG_RSP:
+ case BFI_ENET_I2H_RSS_ENABLE_RSP:
+ case BFI_ENET_I2H_RX_PROMISCUOUS_RSP:
+ case BFI_ENET_I2H_RX_DEFAULT_RSP:
+ case BFI_ENET_I2H_MAC_UCAST_SET_RSP:
+ case BFI_ENET_I2H_MAC_UCAST_CLR_RSP:
+ case BFI_ENET_I2H_MAC_UCAST_ADD_RSP:
+ case BFI_ENET_I2H_MAC_UCAST_DEL_RSP:
+ case BFI_ENET_I2H_MAC_MCAST_DEL_RSP:
+ case BFI_ENET_I2H_MAC_MCAST_FILTER_RSP:
+ case BFI_ENET_I2H_RX_VLAN_SET_RSP:
+ case BFI_ENET_I2H_RX_VLAN_STRIP_ENABLE_RSP:
+ bna_rx_from_rid(bna, msghdr->enet_id, rx);
+ if (rx)
+ bna_bfi_rxf_cfg_rsp(&rx->rxf, msghdr);
+ break;
+
+ case BFI_ENET_I2H_MAC_MCAST_ADD_RSP:
+ bna_rx_from_rid(bna, msghdr->enet_id, rx);
+ if (rx)
+ bna_bfi_rxf_mcast_add_rsp(&rx->rxf, msghdr);
+ break;
+
+ case BFI_ENET_I2H_TX_CFG_SET_RSP:
+ bna_tx_from_rid(bna, msghdr->enet_id, tx);
+ if (tx)
+ bna_bfi_tx_enet_start_rsp(tx, msghdr);
+ break;
+
+ case BFI_ENET_I2H_TX_CFG_CLR_RSP:
+ bna_tx_from_rid(bna, msghdr->enet_id, tx);
+ if (tx)
+ bna_bfi_tx_enet_stop_rsp(tx, msghdr);
+ break;
+
+ case BFI_ENET_I2H_PORT_ADMIN_RSP:
+ bna_bfi_ethport_admin_rsp(&bna->ethport, msghdr);
+ break;
+
+ case BFI_ENET_I2H_DIAG_LOOPBACK_RSP:
+ bna_bfi_ethport_lpbk_rsp(&bna->ethport, msghdr);
+ break;
+
+ case BFI_ENET_I2H_SET_PAUSE_RSP:
+ bna_bfi_pause_set_rsp(&bna->enet, msghdr);
+ break;
+
+ case BFI_ENET_I2H_GET_ATTR_RSP:
+ bna_bfi_attr_get_rsp(&bna->ioceth, msghdr);
+ break;
+
+ case BFI_ENET_I2H_STATS_GET_RSP:
+ bna_bfi_stats_get_rsp(bna, msghdr);
+ break;
+
+ case BFI_ENET_I2H_STATS_CLR_RSP:
+ /* No-op */
+ break;
+
+ case BFI_ENET_I2H_LINK_UP_AEN:
+ bna_bfi_ethport_linkup_aen(&bna->ethport, msghdr);
+ break;
+
+ case BFI_ENET_I2H_LINK_DOWN_AEN:
+ bna_bfi_ethport_linkdown_aen(&bna->ethport, msghdr);
+ break;
+
+ case BFI_ENET_I2H_PORT_ENABLE_AEN:
+ bna_bfi_ethport_enable_aen(&bna->ethport, msghdr);
+ break;
+
+ case BFI_ENET_I2H_PORT_DISABLE_AEN:
+ bna_bfi_ethport_disable_aen(&bna->ethport, msghdr);
+ break;
+
+ case BFI_ENET_I2H_BW_UPDATE_AEN:
+ bna_bfi_bw_update_aen(&bna->tx_mod);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ * ETHPORT
+ */
+#define call_ethport_stop_cbfn(_ethport) \
+do { \
+ if ((_ethport)->stop_cbfn) { \
+ void (*cbfn)(struct bna_enet *); \
+ cbfn = (_ethport)->stop_cbfn; \
+ (_ethport)->stop_cbfn = NULL; \
+ cbfn(&(_ethport)->bna->enet); \
+ } \
+} while (0)
+
+#define call_ethport_adminup_cbfn(ethport, status) \
+do { \
+ if ((ethport)->adminup_cbfn) { \
+ void (*cbfn)(struct bnad *, enum bna_cb_status); \
+ cbfn = (ethport)->adminup_cbfn; \
+ (ethport)->adminup_cbfn = NULL; \
+ cbfn((ethport)->bna->bnad, status); \
+ } \
+} while (0)
+
+static void
+bna_bfi_ethport_admin_up(struct bna_ethport *ethport)
+{
+ struct bfi_enet_enable_req *admin_up_req =
+ &ethport->bfi_enet_cmd.admin_req;
+
+ bfi_msgq_mhdr_set(admin_up_req->mh, BFI_MC_ENET,
+ BFI_ENET_H2I_PORT_ADMIN_UP_REQ, 0, 0);
+ admin_up_req->mh.num_entries = htons(
+ bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_enable_req)));
+ admin_up_req->enable = BNA_STATUS_T_ENABLED;
+
+ bfa_msgq_cmd_set(&ethport->msgq_cmd, NULL, NULL,
+ sizeof(struct bfi_enet_enable_req), &admin_up_req->mh);
+ bfa_msgq_cmd_post(&ethport->bna->msgq, &ethport->msgq_cmd);
+}
+
+static void
+bna_bfi_ethport_admin_down(struct bna_ethport *ethport)
+{
+ struct bfi_enet_enable_req *admin_down_req =
+ &ethport->bfi_enet_cmd.admin_req;
+
+ bfi_msgq_mhdr_set(admin_down_req->mh, BFI_MC_ENET,
+ BFI_ENET_H2I_PORT_ADMIN_UP_REQ, 0, 0);
+ admin_down_req->mh.num_entries = htons(
+ bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_enable_req)));
+ admin_down_req->enable = BNA_STATUS_T_DISABLED;
+
+ bfa_msgq_cmd_set(&ethport->msgq_cmd, NULL, NULL,
+ sizeof(struct bfi_enet_enable_req), &admin_down_req->mh);
+ bfa_msgq_cmd_post(&ethport->bna->msgq, &ethport->msgq_cmd);
+}
+
+static void
+bna_bfi_ethport_lpbk_up(struct bna_ethport *ethport)
+{
+ struct bfi_enet_diag_lb_req *lpbk_up_req =
+ &ethport->bfi_enet_cmd.lpbk_req;
+
+ bfi_msgq_mhdr_set(lpbk_up_req->mh, BFI_MC_ENET,
+ BFI_ENET_H2I_DIAG_LOOPBACK_REQ, 0, 0);
+ lpbk_up_req->mh.num_entries = htons(
+ bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_diag_lb_req)));
+ lpbk_up_req->mode = (ethport->bna->enet.type ==
+ BNA_ENET_T_LOOPBACK_INTERNAL) ?
+ BFI_ENET_DIAG_LB_OPMODE_EXT :
+ BFI_ENET_DIAG_LB_OPMODE_CBL;
+ lpbk_up_req->enable = BNA_STATUS_T_ENABLED;
+
+ bfa_msgq_cmd_set(&ethport->msgq_cmd, NULL, NULL,
+ sizeof(struct bfi_enet_diag_lb_req), &lpbk_up_req->mh);
+ bfa_msgq_cmd_post(&ethport->bna->msgq, &ethport->msgq_cmd);
+}
+
+static void
+bna_bfi_ethport_lpbk_down(struct bna_ethport *ethport)
+{
+ struct bfi_enet_diag_lb_req *lpbk_down_req =
+ &ethport->bfi_enet_cmd.lpbk_req;
+
+ bfi_msgq_mhdr_set(lpbk_down_req->mh, BFI_MC_ENET,
+ BFI_ENET_H2I_DIAG_LOOPBACK_REQ, 0, 0);
+ lpbk_down_req->mh.num_entries = htons(
+ bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_diag_lb_req)));
+ lpbk_down_req->enable = BNA_STATUS_T_DISABLED;
+
+ bfa_msgq_cmd_set(&ethport->msgq_cmd, NULL, NULL,
+ sizeof(struct bfi_enet_diag_lb_req), &lpbk_down_req->mh);
+ bfa_msgq_cmd_post(&ethport->bna->msgq, &ethport->msgq_cmd);
+}
+
+static void
+bna_bfi_ethport_up(struct bna_ethport *ethport)
+{
+ if (ethport->bna->enet.type == BNA_ENET_T_REGULAR)
+ bna_bfi_ethport_admin_up(ethport);
+ else
+ bna_bfi_ethport_lpbk_up(ethport);
+}
+
+static void
+bna_bfi_ethport_down(struct bna_ethport *ethport)
+{
+ if (ethport->bna->enet.type == BNA_ENET_T_REGULAR)
+ bna_bfi_ethport_admin_down(ethport);
+ else
+ bna_bfi_ethport_lpbk_down(ethport);
+}
+
+bfa_fsm_state_decl(bna_ethport, stopped, struct bna_ethport,
+ enum bna_ethport_event);
+bfa_fsm_state_decl(bna_ethport, down, struct bna_ethport,
+ enum bna_ethport_event);
+bfa_fsm_state_decl(bna_ethport, up_resp_wait, struct bna_ethport,
+ enum bna_ethport_event);
+bfa_fsm_state_decl(bna_ethport, down_resp_wait, struct bna_ethport,
+ enum bna_ethport_event);
+bfa_fsm_state_decl(bna_ethport, up, struct bna_ethport,
+ enum bna_ethport_event);
+bfa_fsm_state_decl(bna_ethport, last_resp_wait, struct bna_ethport,
+ enum bna_ethport_event);
+
+static void
+bna_ethport_sm_stopped_entry(struct bna_ethport *ethport)
+{
+ call_ethport_stop_cbfn(ethport);
+}
+
+static void
+bna_ethport_sm_stopped(struct bna_ethport *ethport,
+ enum bna_ethport_event event)
+{
+ switch (event) {
+ case ETHPORT_E_START:
+ bfa_fsm_set_state(ethport, bna_ethport_sm_down);
+ break;
+
+ case ETHPORT_E_STOP:
+ call_ethport_stop_cbfn(ethport);
+ break;
+
+ case ETHPORT_E_FAIL:
+ /* No-op */
+ break;
+
+ case ETHPORT_E_DOWN:
+ /* This event is received due to Rx objects failing */
+ /* No-op */
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_ethport_sm_down_entry(struct bna_ethport *ethport)
+{
+}
+
+static void
+bna_ethport_sm_down(struct bna_ethport *ethport,
+ enum bna_ethport_event event)
+{
+ switch (event) {
+ case ETHPORT_E_STOP:
+ bfa_fsm_set_state(ethport, bna_ethport_sm_stopped);
+ break;
+
+ case ETHPORT_E_FAIL:
+ bfa_fsm_set_state(ethport, bna_ethport_sm_stopped);
+ break;
+
+ case ETHPORT_E_UP:
+ bfa_fsm_set_state(ethport, bna_ethport_sm_up_resp_wait);
+ bna_bfi_ethport_up(ethport);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_ethport_sm_up_resp_wait_entry(struct bna_ethport *ethport)
+{
+}
+
+static void
+bna_ethport_sm_up_resp_wait(struct bna_ethport *ethport,
+ enum bna_ethport_event event)
+{
+ switch (event) {
+ case ETHPORT_E_STOP:
+ bfa_fsm_set_state(ethport, bna_ethport_sm_last_resp_wait);
+ break;
+
+ case ETHPORT_E_FAIL:
+ call_ethport_adminup_cbfn(ethport, BNA_CB_FAIL);
+ bfa_fsm_set_state(ethport, bna_ethport_sm_stopped);
+ break;
+
+ case ETHPORT_E_DOWN:
+ call_ethport_adminup_cbfn(ethport, BNA_CB_INTERRUPT);
+ bfa_fsm_set_state(ethport, bna_ethport_sm_down_resp_wait);
+ break;
+
+ case ETHPORT_E_FWRESP_UP_OK:
+ call_ethport_adminup_cbfn(ethport, BNA_CB_SUCCESS);
+ bfa_fsm_set_state(ethport, bna_ethport_sm_up);
+ break;
+
+ case ETHPORT_E_FWRESP_UP_FAIL:
+ call_ethport_adminup_cbfn(ethport, BNA_CB_FAIL);
+ bfa_fsm_set_state(ethport, bna_ethport_sm_down);
+ break;
+
+ case ETHPORT_E_FWRESP_DOWN:
+ /* down_resp_wait -> up_resp_wait transition on ETHPORT_E_UP */
+ bna_bfi_ethport_up(ethport);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_ethport_sm_down_resp_wait_entry(struct bna_ethport *ethport)
+{
+ /**
+ * NOTE: Do not call bna_bfi_ethport_down() here. That will over step
+ * mbox due to up_resp_wait -> down_resp_wait transition on event
+ * ETHPORT_E_DOWN
+ */
+}
+
+static void
+bna_ethport_sm_down_resp_wait(struct bna_ethport *ethport,
+ enum bna_ethport_event event)
+{
+ switch (event) {
+ case ETHPORT_E_STOP:
+ bfa_fsm_set_state(ethport, bna_ethport_sm_last_resp_wait);
+ break;
+
+ case ETHPORT_E_FAIL:
+ bfa_fsm_set_state(ethport, bna_ethport_sm_stopped);
+ break;
+
+ case ETHPORT_E_UP:
+ bfa_fsm_set_state(ethport, bna_ethport_sm_up_resp_wait);
+ break;
+
+ case ETHPORT_E_FWRESP_UP_OK:
+ /* up_resp_wait->down_resp_wait transition on ETHPORT_E_DOWN */
+ bna_bfi_ethport_down(ethport);
+ break;
+
+ case ETHPORT_E_FWRESP_UP_FAIL:
+ case ETHPORT_E_FWRESP_DOWN:
+ bfa_fsm_set_state(ethport, bna_ethport_sm_down);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_ethport_sm_up_entry(struct bna_ethport *ethport)
+{
+}
+
+static void
+bna_ethport_sm_up(struct bna_ethport *ethport,
+ enum bna_ethport_event event)
+{
+ switch (event) {
+ case ETHPORT_E_STOP:
+ bfa_fsm_set_state(ethport, bna_ethport_sm_last_resp_wait);
+ bna_bfi_ethport_down(ethport);
+ break;
+
+ case ETHPORT_E_FAIL:
+ bfa_fsm_set_state(ethport, bna_ethport_sm_stopped);
+ break;
+
+ case ETHPORT_E_DOWN:
+ bfa_fsm_set_state(ethport, bna_ethport_sm_down_resp_wait);
+ bna_bfi_ethport_down(ethport);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_ethport_sm_last_resp_wait_entry(struct bna_ethport *ethport)
+{
+}
+
+static void
+bna_ethport_sm_last_resp_wait(struct bna_ethport *ethport,
+ enum bna_ethport_event event)
+{
+ switch (event) {
+ case ETHPORT_E_FAIL:
+ bfa_fsm_set_state(ethport, bna_ethport_sm_stopped);
+ break;
+
+ case ETHPORT_E_DOWN:
+ /**
+ * This event is received due to Rx objects stopping in
+ * parallel to ethport
+ */
+ /* No-op */
+ break;
+
+ case ETHPORT_E_FWRESP_UP_OK:
+ /* up_resp_wait->last_resp_wait transition on ETHPORT_T_STOP */
+ bna_bfi_ethport_down(ethport);
+ break;
+
+ case ETHPORT_E_FWRESP_UP_FAIL:
+ case ETHPORT_E_FWRESP_DOWN:
+ bfa_fsm_set_state(ethport, bna_ethport_sm_stopped);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_ethport_init(struct bna_ethport *ethport, struct bna *bna)
+{
+ ethport->flags |= (BNA_ETHPORT_F_ADMIN_UP | BNA_ETHPORT_F_PORT_ENABLED);
+ ethport->bna = bna;
+
+ ethport->link_status = BNA_LINK_DOWN;
+ ethport->link_cbfn = bnad_cb_ethport_link_status;
+
+ ethport->rx_started_count = 0;
+
+ ethport->stop_cbfn = NULL;
+ ethport->adminup_cbfn = NULL;
+
+ bfa_fsm_set_state(ethport, bna_ethport_sm_stopped);
+}
+
+static void
+bna_ethport_uninit(struct bna_ethport *ethport)
+{
+ ethport->flags &= ~BNA_ETHPORT_F_ADMIN_UP;
+ ethport->flags &= ~BNA_ETHPORT_F_PORT_ENABLED;
+
+ ethport->bna = NULL;
+}
+
+static void
+bna_ethport_start(struct bna_ethport *ethport)
+{
+ bfa_fsm_send_event(ethport, ETHPORT_E_START);
+}
+
+static void
+bna_enet_cb_ethport_stopped(struct bna_enet *enet)
+{
+ bfa_wc_down(&enet->chld_stop_wc);
+}
+
+static void
+bna_ethport_stop(struct bna_ethport *ethport)
+{
+ ethport->stop_cbfn = bna_enet_cb_ethport_stopped;
+ bfa_fsm_send_event(ethport, ETHPORT_E_STOP);
+}
+
+static void
+bna_ethport_fail(struct bna_ethport *ethport)
+{
+ /* Reset the physical port status to enabled */
+ ethport->flags |= BNA_ETHPORT_F_PORT_ENABLED;
+
+ if (ethport->link_status != BNA_LINK_DOWN) {
+ ethport->link_status = BNA_LINK_DOWN;
+ ethport->link_cbfn(ethport->bna->bnad, BNA_LINK_DOWN);
+ }
+ bfa_fsm_send_event(ethport, ETHPORT_E_FAIL);
+}
+
+/* Should be called only when ethport is disabled */
+void
+bna_ethport_cb_rx_started(struct bna_ethport *ethport)
+{
+ ethport->rx_started_count++;
+
+ if (ethport->rx_started_count == 1) {
+ ethport->flags |= BNA_ETHPORT_F_RX_STARTED;
+
+ if (ethport_can_be_up(ethport))
+ bfa_fsm_send_event(ethport, ETHPORT_E_UP);
+ }
+}
+
+void
+bna_ethport_cb_rx_stopped(struct bna_ethport *ethport)
+{
+ int ethport_up = ethport_is_up(ethport);
+
+ ethport->rx_started_count--;
+
+ if (ethport->rx_started_count == 0) {
+ ethport->flags &= ~BNA_ETHPORT_F_RX_STARTED;
+
+ if (ethport_up)
+ bfa_fsm_send_event(ethport, ETHPORT_E_DOWN);
+ }
+}
+
+/**
+ * ENET
+ */
+#define bna_enet_chld_start(enet) \
+do { \
+ enum bna_tx_type tx_type = \
+ ((enet)->type == BNA_ENET_T_REGULAR) ? \
+ BNA_TX_T_REGULAR : BNA_TX_T_LOOPBACK; \
+ enum bna_rx_type rx_type = \
+ ((enet)->type == BNA_ENET_T_REGULAR) ? \
+ BNA_RX_T_REGULAR : BNA_RX_T_LOOPBACK; \
+ bna_ethport_start(&(enet)->bna->ethport); \
+ bna_tx_mod_start(&(enet)->bna->tx_mod, tx_type); \
+ bna_rx_mod_start(&(enet)->bna->rx_mod, rx_type); \
+} while (0)
+
+#define bna_enet_chld_stop(enet) \
+do { \
+ enum bna_tx_type tx_type = \
+ ((enet)->type == BNA_ENET_T_REGULAR) ? \
+ BNA_TX_T_REGULAR : BNA_TX_T_LOOPBACK; \
+ enum bna_rx_type rx_type = \
+ ((enet)->type == BNA_ENET_T_REGULAR) ? \
+ BNA_RX_T_REGULAR : BNA_RX_T_LOOPBACK; \
+ bfa_wc_init(&(enet)->chld_stop_wc, bna_enet_cb_chld_stopped, (enet));\
+ bfa_wc_up(&(enet)->chld_stop_wc); \
+ bna_ethport_stop(&(enet)->bna->ethport); \
+ bfa_wc_up(&(enet)->chld_stop_wc); \
+ bna_tx_mod_stop(&(enet)->bna->tx_mod, tx_type); \
+ bfa_wc_up(&(enet)->chld_stop_wc); \
+ bna_rx_mod_stop(&(enet)->bna->rx_mod, rx_type); \
+ bfa_wc_wait(&(enet)->chld_stop_wc); \
+} while (0)
+
+#define bna_enet_chld_fail(enet) \
+do { \
+ bna_ethport_fail(&(enet)->bna->ethport); \
+ bna_tx_mod_fail(&(enet)->bna->tx_mod); \
+ bna_rx_mod_fail(&(enet)->bna->rx_mod); \
+} while (0)
+
+#define bna_enet_rx_start(enet) \
+do { \
+ enum bna_rx_type rx_type = \
+ ((enet)->type == BNA_ENET_T_REGULAR) ? \
+ BNA_RX_T_REGULAR : BNA_RX_T_LOOPBACK; \
+ bna_rx_mod_start(&(enet)->bna->rx_mod, rx_type); \
+} while (0)
+
+#define bna_enet_rx_stop(enet) \
+do { \
+ enum bna_rx_type rx_type = \
+ ((enet)->type == BNA_ENET_T_REGULAR) ? \
+ BNA_RX_T_REGULAR : BNA_RX_T_LOOPBACK; \
+ bfa_wc_init(&(enet)->chld_stop_wc, bna_enet_cb_chld_stopped, (enet));\
+ bfa_wc_up(&(enet)->chld_stop_wc); \
+ bna_rx_mod_stop(&(enet)->bna->rx_mod, rx_type); \
+ bfa_wc_wait(&(enet)->chld_stop_wc); \
+} while (0)
+
+#define call_enet_stop_cbfn(enet) \
+do { \
+ if ((enet)->stop_cbfn) { \
+ void (*cbfn)(void *); \
+ void *cbarg; \
+ cbfn = (enet)->stop_cbfn; \
+ cbarg = (enet)->stop_cbarg; \
+ (enet)->stop_cbfn = NULL; \
+ (enet)->stop_cbarg = NULL; \
+ cbfn(cbarg); \
+ } \
+} while (0)
+
+#define call_enet_pause_cbfn(enet) \
+do { \
+ if ((enet)->pause_cbfn) { \
+ void (*cbfn)(struct bnad *); \
+ cbfn = (enet)->pause_cbfn; \
+ (enet)->pause_cbfn = NULL; \
+ cbfn((enet)->bna->bnad); \
+ } \
+} while (0)
+
+#define call_enet_mtu_cbfn(enet) \
+do { \
+ if ((enet)->mtu_cbfn) { \
+ void (*cbfn)(struct bnad *); \
+ cbfn = (enet)->mtu_cbfn; \
+ (enet)->mtu_cbfn = NULL; \
+ cbfn((enet)->bna->bnad); \
+ } \
+} while (0)
+
+static void bna_enet_cb_chld_stopped(void *arg);
+static void bna_bfi_pause_set(struct bna_enet *enet);
+
+bfa_fsm_state_decl(bna_enet, stopped, struct bna_enet,
+ enum bna_enet_event);
+bfa_fsm_state_decl(bna_enet, pause_init_wait, struct bna_enet,
+ enum bna_enet_event);
+bfa_fsm_state_decl(bna_enet, last_resp_wait, struct bna_enet,
+ enum bna_enet_event);
+bfa_fsm_state_decl(bna_enet, started, struct bna_enet,
+ enum bna_enet_event);
+bfa_fsm_state_decl(bna_enet, cfg_wait, struct bna_enet,
+ enum bna_enet_event);
+bfa_fsm_state_decl(bna_enet, cfg_stop_wait, struct bna_enet,
+ enum bna_enet_event);
+bfa_fsm_state_decl(bna_enet, chld_stop_wait, struct bna_enet,
+ enum bna_enet_event);
+
+static void
+bna_enet_sm_stopped_entry(struct bna_enet *enet)
+{
+ call_enet_pause_cbfn(enet);
+ call_enet_mtu_cbfn(enet);
+ call_enet_stop_cbfn(enet);
+}
+
+static void
+bna_enet_sm_stopped(struct bna_enet *enet, enum bna_enet_event event)
+{
+ switch (event) {
+ case ENET_E_START:
+ bfa_fsm_set_state(enet, bna_enet_sm_pause_init_wait);
+ break;
+
+ case ENET_E_STOP:
+ call_enet_stop_cbfn(enet);
+ break;
+
+ case ENET_E_FAIL:
+ /* No-op */
+ break;
+
+ case ENET_E_PAUSE_CFG:
+ call_enet_pause_cbfn(enet);
+ break;
+
+ case ENET_E_MTU_CFG:
+ call_enet_mtu_cbfn(enet);
+ break;
+
+ case ENET_E_CHLD_STOPPED:
+ /**
+ * This event is received due to Ethport, Tx and Rx objects
+ * failing
+ */
+ /* No-op */
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_enet_sm_pause_init_wait_entry(struct bna_enet *enet)
+{
+ bna_bfi_pause_set(enet);
+}
+
+static void
+bna_enet_sm_pause_init_wait(struct bna_enet *enet,
+ enum bna_enet_event event)
+{
+ switch (event) {
+ case ENET_E_STOP:
+ enet->flags &= ~BNA_ENET_F_PAUSE_CHANGED;
+ bfa_fsm_set_state(enet, bna_enet_sm_last_resp_wait);
+ break;
+
+ case ENET_E_FAIL:
+ enet->flags &= ~BNA_ENET_F_PAUSE_CHANGED;
+ bfa_fsm_set_state(enet, bna_enet_sm_stopped);
+ break;
+
+ case ENET_E_PAUSE_CFG:
+ enet->flags |= BNA_ENET_F_PAUSE_CHANGED;
+ break;
+
+ case ENET_E_MTU_CFG:
+ /* No-op */
+ break;
+
+ case ENET_E_FWRESP_PAUSE:
+ if (enet->flags & BNA_ENET_F_PAUSE_CHANGED) {
+ enet->flags &= ~BNA_ENET_F_PAUSE_CHANGED;
+ bna_bfi_pause_set(enet);
+ } else {
+ bfa_fsm_set_state(enet, bna_enet_sm_started);
+ bna_enet_chld_start(enet);
+ }
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_enet_sm_last_resp_wait_entry(struct bna_enet *enet)
+{
+ enet->flags &= ~BNA_ENET_F_PAUSE_CHANGED;
+}
+
+static void
+bna_enet_sm_last_resp_wait(struct bna_enet *enet,
+ enum bna_enet_event event)
+{
+ switch (event) {
+ case ENET_E_FAIL:
+ case ENET_E_FWRESP_PAUSE:
+ bfa_fsm_set_state(enet, bna_enet_sm_stopped);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_enet_sm_started_entry(struct bna_enet *enet)
+{
+ /**
+ * NOTE: Do not call bna_enet_chld_start() here, since it will be
+ * inadvertently called during cfg_wait->started transition as well
+ */
+ call_enet_pause_cbfn(enet);
+ call_enet_mtu_cbfn(enet);
+}
+
+static void
+bna_enet_sm_started(struct bna_enet *enet,
+ enum bna_enet_event event)
+{
+ switch (event) {
+ case ENET_E_STOP:
+ bfa_fsm_set_state(enet, bna_enet_sm_chld_stop_wait);
+ break;
+
+ case ENET_E_FAIL:
+ bfa_fsm_set_state(enet, bna_enet_sm_stopped);
+ bna_enet_chld_fail(enet);
+ break;
+
+ case ENET_E_PAUSE_CFG:
+ bfa_fsm_set_state(enet, bna_enet_sm_cfg_wait);
+ bna_bfi_pause_set(enet);
+ break;
+
+ case ENET_E_MTU_CFG:
+ bfa_fsm_set_state(enet, bna_enet_sm_cfg_wait);
+ bna_enet_rx_stop(enet);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_enet_sm_cfg_wait_entry(struct bna_enet *enet)
+{
+}
+
+static void
+bna_enet_sm_cfg_wait(struct bna_enet *enet,
+ enum bna_enet_event event)
+{
+ switch (event) {
+ case ENET_E_STOP:
+ enet->flags &= ~BNA_ENET_F_PAUSE_CHANGED;
+ enet->flags &= ~BNA_ENET_F_MTU_CHANGED;
+ bfa_fsm_set_state(enet, bna_enet_sm_cfg_stop_wait);
+ break;
+
+ case ENET_E_FAIL:
+ enet->flags &= ~BNA_ENET_F_PAUSE_CHANGED;
+ enet->flags &= ~BNA_ENET_F_MTU_CHANGED;
+ bfa_fsm_set_state(enet, bna_enet_sm_stopped);
+ bna_enet_chld_fail(enet);
+ break;
+
+ case ENET_E_PAUSE_CFG:
+ enet->flags |= BNA_ENET_F_PAUSE_CHANGED;
+ break;
+
+ case ENET_E_MTU_CFG:
+ enet->flags |= BNA_ENET_F_MTU_CHANGED;
+ break;
+
+ case ENET_E_CHLD_STOPPED:
+ bna_enet_rx_start(enet);
+ /* Fall through */
+ case ENET_E_FWRESP_PAUSE:
+ if (enet->flags & BNA_ENET_F_PAUSE_CHANGED) {
+ enet->flags &= ~BNA_ENET_F_PAUSE_CHANGED;
+ bna_bfi_pause_set(enet);
+ } else if (enet->flags & BNA_ENET_F_MTU_CHANGED) {
+ enet->flags &= ~BNA_ENET_F_MTU_CHANGED;
+ bna_enet_rx_stop(enet);
+ } else {
+ bfa_fsm_set_state(enet, bna_enet_sm_started);
+ }
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_enet_sm_cfg_stop_wait_entry(struct bna_enet *enet)
+{
+ enet->flags &= ~BNA_ENET_F_PAUSE_CHANGED;
+ enet->flags &= ~BNA_ENET_F_MTU_CHANGED;
+}
+
+static void
+bna_enet_sm_cfg_stop_wait(struct bna_enet *enet,
+ enum bna_enet_event event)
+{
+ switch (event) {
+ case ENET_E_FAIL:
+ bfa_fsm_set_state(enet, bna_enet_sm_stopped);
+ bna_enet_chld_fail(enet);
+ break;
+
+ case ENET_E_FWRESP_PAUSE:
+ case ENET_E_CHLD_STOPPED:
+ bfa_fsm_set_state(enet, bna_enet_sm_chld_stop_wait);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_enet_sm_chld_stop_wait_entry(struct bna_enet *enet)
+{
+ bna_enet_chld_stop(enet);
+}
+
+static void
+bna_enet_sm_chld_stop_wait(struct bna_enet *enet,
+ enum bna_enet_event event)
+{
+ switch (event) {
+ case ENET_E_FAIL:
+ bfa_fsm_set_state(enet, bna_enet_sm_stopped);
+ bna_enet_chld_fail(enet);
+ break;
+
+ case ENET_E_CHLD_STOPPED:
+ bfa_fsm_set_state(enet, bna_enet_sm_stopped);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_bfi_pause_set(struct bna_enet *enet)
+{
+ struct bfi_enet_set_pause_req *pause_req = &enet->pause_req;
+
+ bfi_msgq_mhdr_set(pause_req->mh, BFI_MC_ENET,
+ BFI_ENET_H2I_SET_PAUSE_REQ, 0, 0);
+ pause_req->mh.num_entries = htons(
+ bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_set_pause_req)));
+ pause_req->tx_pause = enet->pause_config.tx_pause;
+ pause_req->rx_pause = enet->pause_config.rx_pause;
+
+ bfa_msgq_cmd_set(&enet->msgq_cmd, NULL, NULL,
+ sizeof(struct bfi_enet_set_pause_req), &pause_req->mh);
+ bfa_msgq_cmd_post(&enet->bna->msgq, &enet->msgq_cmd);
+}
+
+static void
+bna_enet_cb_chld_stopped(void *arg)
+{
+ struct bna_enet *enet = (struct bna_enet *)arg;
+
+ bfa_fsm_send_event(enet, ENET_E_CHLD_STOPPED);
+}
+
+static void
+bna_enet_init(struct bna_enet *enet, struct bna *bna)
+{
+ enet->bna = bna;
+ enet->flags = 0;
+ enet->mtu = 0;
+ enet->type = BNA_ENET_T_REGULAR;
+
+ enet->stop_cbfn = NULL;
+ enet->stop_cbarg = NULL;
+
+ enet->pause_cbfn = NULL;
+
+ enet->mtu_cbfn = NULL;
+
+ bfa_fsm_set_state(enet, bna_enet_sm_stopped);
+}
+
+static void
+bna_enet_uninit(struct bna_enet *enet)
+{
+ enet->flags = 0;
+
+ enet->bna = NULL;
+}
+
+static void
+bna_enet_start(struct bna_enet *enet)
+{
+ enet->flags |= BNA_ENET_F_IOCETH_READY;
+ if (enet->flags & BNA_ENET_F_ENABLED)
+ bfa_fsm_send_event(enet, ENET_E_START);
+}
+
+static void
+bna_ioceth_cb_enet_stopped(void *arg)
+{
+ struct bna_ioceth *ioceth = (struct bna_ioceth *)arg;
+
+ bfa_fsm_send_event(ioceth, IOCETH_E_ENET_STOPPED);
+}
+
+static void
+bna_enet_stop(struct bna_enet *enet)
+{
+ enet->stop_cbfn = bna_ioceth_cb_enet_stopped;
+ enet->stop_cbarg = &enet->bna->ioceth;
+
+ enet->flags &= ~BNA_ENET_F_IOCETH_READY;
+ bfa_fsm_send_event(enet, ENET_E_STOP);
+}
+
+static void
+bna_enet_fail(struct bna_enet *enet)
+{
+ enet->flags &= ~BNA_ENET_F_IOCETH_READY;
+ bfa_fsm_send_event(enet, ENET_E_FAIL);
+}
+
+void
+bna_enet_cb_tx_stopped(struct bna_enet *enet)
+{
+ bfa_wc_down(&enet->chld_stop_wc);
+}
+
+void
+bna_enet_cb_rx_stopped(struct bna_enet *enet)
+{
+ bfa_wc_down(&enet->chld_stop_wc);
+}
+
+int
+bna_enet_mtu_get(struct bna_enet *enet)
+{
+ return enet->mtu;
+}
+
+void
+bna_enet_enable(struct bna_enet *enet)
+{
+ if (enet->fsm != (bfa_sm_t)bna_enet_sm_stopped)
+ return;
+
+ enet->flags |= BNA_ENET_F_ENABLED;
+
+ if (enet->flags & BNA_ENET_F_IOCETH_READY)
+ bfa_fsm_send_event(enet, ENET_E_START);
+}
+
+void
+bna_enet_disable(struct bna_enet *enet, enum bna_cleanup_type type,
+ void (*cbfn)(void *))
+{
+ if (type == BNA_SOFT_CLEANUP) {
+ (*cbfn)(enet->bna->bnad);
+ return;
+ }
+
+ enet->stop_cbfn = cbfn;
+ enet->stop_cbarg = enet->bna->bnad;
+
+ enet->flags &= ~BNA_ENET_F_ENABLED;
+
+ bfa_fsm_send_event(enet, ENET_E_STOP);
+}
+
+void
+bna_enet_pause_config(struct bna_enet *enet,
+ struct bna_pause_config *pause_config,
+ void (*cbfn)(struct bnad *))
+{
+ enet->pause_config = *pause_config;
+
+ enet->pause_cbfn = cbfn;
+
+ bfa_fsm_send_event(enet, ENET_E_PAUSE_CFG);
+}
+
+void
+bna_enet_mtu_set(struct bna_enet *enet, int mtu,
+ void (*cbfn)(struct bnad *))
+{
+ enet->mtu = mtu;
+
+ enet->mtu_cbfn = cbfn;
+
+ bfa_fsm_send_event(enet, ENET_E_MTU_CFG);
+}
+
+void
+bna_enet_perm_mac_get(struct bna_enet *enet, mac_t *mac)
+{
+ *mac = bfa_nw_ioc_get_mac(&enet->bna->ioceth.ioc);
+}
+
+/**
+ * IOCETH
+ */
+#define enable_mbox_intr(_ioceth) \
+do { \
+ u32 intr_status; \
+ bna_intr_status_get((_ioceth)->bna, intr_status); \
+ bnad_cb_mbox_intr_enable((_ioceth)->bna->bnad); \
+ bna_mbox_intr_enable((_ioceth)->bna); \
+} while (0)
+
+#define disable_mbox_intr(_ioceth) \
+do { \
+ bna_mbox_intr_disable((_ioceth)->bna); \
+ bnad_cb_mbox_intr_disable((_ioceth)->bna->bnad); \
+} while (0)
+
+#define call_ioceth_stop_cbfn(_ioceth) \
+do { \
+ if ((_ioceth)->stop_cbfn) { \
+ void (*cbfn)(struct bnad *); \
+ struct bnad *cbarg; \
+ cbfn = (_ioceth)->stop_cbfn; \
+ cbarg = (_ioceth)->stop_cbarg; \
+ (_ioceth)->stop_cbfn = NULL; \
+ (_ioceth)->stop_cbarg = NULL; \
+ cbfn(cbarg); \
+ } \
+} while (0)
+
+#define bna_stats_mod_uninit(_stats_mod) \
+do { \
+} while (0)
+
+#define bna_stats_mod_start(_stats_mod) \
+do { \
+ (_stats_mod)->ioc_ready = true; \
+} while (0)
+
+#define bna_stats_mod_stop(_stats_mod) \
+do { \
+ (_stats_mod)->ioc_ready = false; \
+} while (0)
+
+#define bna_stats_mod_fail(_stats_mod) \
+do { \
+ (_stats_mod)->ioc_ready = false; \
+ (_stats_mod)->stats_get_busy = false; \
+ (_stats_mod)->stats_clr_busy = false; \
+} while (0)
+
+static void bna_bfi_attr_get(struct bna_ioceth *ioceth);
+
+bfa_fsm_state_decl(bna_ioceth, stopped, struct bna_ioceth,
+ enum bna_ioceth_event);
+bfa_fsm_state_decl(bna_ioceth, ioc_ready_wait, struct bna_ioceth,
+ enum bna_ioceth_event);
+bfa_fsm_state_decl(bna_ioceth, enet_attr_wait, struct bna_ioceth,
+ enum bna_ioceth_event);
+bfa_fsm_state_decl(bna_ioceth, ready, struct bna_ioceth,
+ enum bna_ioceth_event);
+bfa_fsm_state_decl(bna_ioceth, last_resp_wait, struct bna_ioceth,
+ enum bna_ioceth_event);
+bfa_fsm_state_decl(bna_ioceth, enet_stop_wait, struct bna_ioceth,
+ enum bna_ioceth_event);
+bfa_fsm_state_decl(bna_ioceth, ioc_disable_wait, struct bna_ioceth,
+ enum bna_ioceth_event);
+bfa_fsm_state_decl(bna_ioceth, failed, struct bna_ioceth,
+ enum bna_ioceth_event);
+
+static void
+bna_ioceth_sm_stopped_entry(struct bna_ioceth *ioceth)
+{
+ call_ioceth_stop_cbfn(ioceth);
+}
+
+static void
+bna_ioceth_sm_stopped(struct bna_ioceth *ioceth,
+ enum bna_ioceth_event event)
+{
+ switch (event) {
+ case IOCETH_E_ENABLE:
+ bfa_fsm_set_state(ioceth, bna_ioceth_sm_ioc_ready_wait);
+ bfa_nw_ioc_enable(&ioceth->ioc);
+ break;
+
+ case IOCETH_E_DISABLE:
+ bfa_fsm_set_state(ioceth, bna_ioceth_sm_stopped);
+ break;
+
+ case IOCETH_E_IOC_RESET:
+ enable_mbox_intr(ioceth);
+ break;
+
+ case IOCETH_E_IOC_FAILED:
+ disable_mbox_intr(ioceth);
+ bfa_fsm_set_state(ioceth, bna_ioceth_sm_failed);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_ioceth_sm_ioc_ready_wait_entry(struct bna_ioceth *ioceth)
+{
+ /**
+ * Do not call bfa_nw_ioc_enable() here. It must be called in the
+ * previous state due to failed -> ioc_ready_wait transition.
+ */
+}
+
+static void
+bna_ioceth_sm_ioc_ready_wait(struct bna_ioceth *ioceth,
+ enum bna_ioceth_event event)
+{
+ switch (event) {
+ case IOCETH_E_DISABLE:
+ bfa_fsm_set_state(ioceth, bna_ioceth_sm_ioc_disable_wait);
+ bfa_nw_ioc_disable(&ioceth->ioc);
+ break;
+
+ case IOCETH_E_IOC_RESET:
+ enable_mbox_intr(ioceth);
+ break;
+
+ case IOCETH_E_IOC_FAILED:
+ disable_mbox_intr(ioceth);
+ bfa_fsm_set_state(ioceth, bna_ioceth_sm_failed);
+ break;
+
+ case IOCETH_E_IOC_READY:
+ bfa_fsm_set_state(ioceth, bna_ioceth_sm_enet_attr_wait);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_ioceth_sm_enet_attr_wait_entry(struct bna_ioceth *ioceth)
+{
+ bna_bfi_attr_get(ioceth);
+}
+
+static void
+bna_ioceth_sm_enet_attr_wait(struct bna_ioceth *ioceth,
+ enum bna_ioceth_event event)
+{
+ switch (event) {
+ case IOCETH_E_DISABLE:
+ bfa_fsm_set_state(ioceth, bna_ioceth_sm_last_resp_wait);
+ break;
+
+ case IOCETH_E_IOC_FAILED:
+ disable_mbox_intr(ioceth);
+ bfa_fsm_set_state(ioceth, bna_ioceth_sm_failed);
+ break;
+
+ case IOCETH_E_ENET_ATTR_RESP:
+ bfa_fsm_set_state(ioceth, bna_ioceth_sm_ready);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_ioceth_sm_ready_entry(struct bna_ioceth *ioceth)
+{
+ bna_enet_start(&ioceth->bna->enet);
+ bna_stats_mod_start(&ioceth->bna->stats_mod);
+ bnad_cb_ioceth_ready(ioceth->bna->bnad);
+}
+
+static void
+bna_ioceth_sm_ready(struct bna_ioceth *ioceth, enum bna_ioceth_event event)
+{
+ switch (event) {
+ case IOCETH_E_DISABLE:
+ bfa_fsm_set_state(ioceth, bna_ioceth_sm_enet_stop_wait);
+ break;
+
+ case IOCETH_E_IOC_FAILED:
+ disable_mbox_intr(ioceth);
+ bna_enet_fail(&ioceth->bna->enet);
+ bna_stats_mod_fail(&ioceth->bna->stats_mod);
+ bfa_fsm_set_state(ioceth, bna_ioceth_sm_failed);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_ioceth_sm_last_resp_wait_entry(struct bna_ioceth *ioceth)
+{
+}
+
+static void
+bna_ioceth_sm_last_resp_wait(struct bna_ioceth *ioceth,
+ enum bna_ioceth_event event)
+{
+ switch (event) {
+ case IOCETH_E_IOC_FAILED:
+ bfa_fsm_set_state(ioceth, bna_ioceth_sm_ioc_disable_wait);
+ disable_mbox_intr(ioceth);
+ bfa_nw_ioc_disable(&ioceth->ioc);
+ break;
+
+ case IOCETH_E_ENET_ATTR_RESP:
+ bfa_fsm_set_state(ioceth, bna_ioceth_sm_ioc_disable_wait);
+ bfa_nw_ioc_disable(&ioceth->ioc);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_ioceth_sm_enet_stop_wait_entry(struct bna_ioceth *ioceth)
+{
+ bna_stats_mod_stop(&ioceth->bna->stats_mod);
+ bna_enet_stop(&ioceth->bna->enet);
+}
+
+static void
+bna_ioceth_sm_enet_stop_wait(struct bna_ioceth *ioceth,
+ enum bna_ioceth_event event)
+{
+ switch (event) {
+ case IOCETH_E_IOC_FAILED:
+ bfa_fsm_set_state(ioceth, bna_ioceth_sm_ioc_disable_wait);
+ disable_mbox_intr(ioceth);
+ bna_enet_fail(&ioceth->bna->enet);
+ bna_stats_mod_fail(&ioceth->bna->stats_mod);
+ bfa_nw_ioc_disable(&ioceth->ioc);
+ break;
+
+ case IOCETH_E_ENET_STOPPED:
+ bfa_fsm_set_state(ioceth, bna_ioceth_sm_ioc_disable_wait);
+ bfa_nw_ioc_disable(&ioceth->ioc);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_ioceth_sm_ioc_disable_wait_entry(struct bna_ioceth *ioceth)
+{
+}
+
+static void
+bna_ioceth_sm_ioc_disable_wait(struct bna_ioceth *ioceth,
+ enum bna_ioceth_event event)
+{
+ switch (event) {
+ case IOCETH_E_IOC_DISABLED:
+ disable_mbox_intr(ioceth);
+ bfa_fsm_set_state(ioceth, bna_ioceth_sm_stopped);
+ break;
+
+ case IOCETH_E_ENET_STOPPED:
+ /* This event is received due to enet failing */
+ /* No-op */
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_ioceth_sm_failed_entry(struct bna_ioceth *ioceth)
+{
+ bnad_cb_ioceth_failed(ioceth->bna->bnad);
+}
+
+static void
+bna_ioceth_sm_failed(struct bna_ioceth *ioceth,
+ enum bna_ioceth_event event)
+{
+ switch (event) {
+ case IOCETH_E_DISABLE:
+ bfa_fsm_set_state(ioceth, bna_ioceth_sm_ioc_disable_wait);
+ bfa_nw_ioc_disable(&ioceth->ioc);
+ break;
+
+ case IOCETH_E_IOC_RESET:
+ enable_mbox_intr(ioceth);
+ bfa_fsm_set_state(ioceth, bna_ioceth_sm_ioc_ready_wait);
+ break;
+
+ case IOCETH_E_IOC_FAILED:
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_bfi_attr_get(struct bna_ioceth *ioceth)
+{
+ struct bfi_enet_attr_req *attr_req = &ioceth->attr_req;
+
+ bfi_msgq_mhdr_set(attr_req->mh, BFI_MC_ENET,
+ BFI_ENET_H2I_GET_ATTR_REQ, 0, 0);
+ attr_req->mh.num_entries = htons(
+ bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_attr_req)));
+ bfa_msgq_cmd_set(&ioceth->msgq_cmd, NULL, NULL,
+ sizeof(struct bfi_enet_attr_req), &attr_req->mh);
+ bfa_msgq_cmd_post(&ioceth->bna->msgq, &ioceth->msgq_cmd);
+}
+
+/* IOC callback functions */
+
+static void
+bna_cb_ioceth_enable(void *arg, enum bfa_status error)
+{
+ struct bna_ioceth *ioceth = (struct bna_ioceth *)arg;
+
+ if (error)
+ bfa_fsm_send_event(ioceth, IOCETH_E_IOC_FAILED);
+ else
+ bfa_fsm_send_event(ioceth, IOCETH_E_IOC_READY);
+}
+
+static void
+bna_cb_ioceth_disable(void *arg)
+{
+ struct bna_ioceth *ioceth = (struct bna_ioceth *)arg;
+
+ bfa_fsm_send_event(ioceth, IOCETH_E_IOC_DISABLED);
+}
+
+static void
+bna_cb_ioceth_hbfail(void *arg)
+{
+ struct bna_ioceth *ioceth = (struct bna_ioceth *)arg;
+
+ bfa_fsm_send_event(ioceth, IOCETH_E_IOC_FAILED);
+}
+
+static void
+bna_cb_ioceth_reset(void *arg)
+{
+ struct bna_ioceth *ioceth = (struct bna_ioceth *)arg;
+
+ bfa_fsm_send_event(ioceth, IOCETH_E_IOC_RESET);
+}
+
+static struct bfa_ioc_cbfn bna_ioceth_cbfn = {
+ bna_cb_ioceth_enable,
+ bna_cb_ioceth_disable,
+ bna_cb_ioceth_hbfail,
+ bna_cb_ioceth_reset
+};
+
+static void bna_attr_init(struct bna_ioceth *ioceth)
+{
+ ioceth->attr.num_txq = BFI_ENET_DEF_TXQ;
+ ioceth->attr.num_rxp = BFI_ENET_DEF_RXP;
+ ioceth->attr.num_ucmac = BFI_ENET_DEF_UCAM;
+ ioceth->attr.num_mcmac = BFI_ENET_MAX_MCAM;
+ ioceth->attr.max_rit_size = BFI_ENET_DEF_RITSZ;
+ ioceth->attr.fw_query_complete = false;
+}
+
+static void
+bna_ioceth_init(struct bna_ioceth *ioceth, struct bna *bna,
+ struct bna_res_info *res_info)
+{
+ u64 dma;
+ u8 *kva;
+
+ ioceth->bna = bna;
+
+ /**
+ * Attach IOC and claim:
+ * 1. DMA memory for IOC attributes
+ * 2. Kernel memory for FW trace
+ */
+ bfa_nw_ioc_attach(&ioceth->ioc, ioceth, &bna_ioceth_cbfn);
+ bfa_nw_ioc_pci_init(&ioceth->ioc, &bna->pcidev, BFI_PCIFN_CLASS_ETH);
+
+ BNA_GET_DMA_ADDR(
+ &res_info[BNA_RES_MEM_T_ATTR].res_u.mem_info.mdl[0].dma, dma);
+ kva = res_info[BNA_RES_MEM_T_ATTR].res_u.mem_info.mdl[0].kva;
+ bfa_nw_ioc_mem_claim(&ioceth->ioc, kva, dma);
+
+ kva = res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.mdl[0].kva;
+
+ /**
+ * Attach common modules (Diag, SFP, CEE, Port) and claim respective
+ * DMA memory.
+ */
+ BNA_GET_DMA_ADDR(
+ &res_info[BNA_RES_MEM_T_COM].res_u.mem_info.mdl[0].dma, dma);
+ kva = res_info[BNA_RES_MEM_T_COM].res_u.mem_info.mdl[0].kva;
+ bfa_nw_cee_attach(&bna->cee, &ioceth->ioc, bna);
+ bfa_nw_cee_mem_claim(&bna->cee, kva, dma);
+ kva += bfa_nw_cee_meminfo();
+ dma += bfa_nw_cee_meminfo();
+
+ bfa_msgq_attach(&bna->msgq, &ioceth->ioc);
+ bfa_msgq_memclaim(&bna->msgq, kva, dma);
+ bfa_msgq_regisr(&bna->msgq, BFI_MC_ENET, bna_msgq_rsp_handler, bna);
+ kva += bfa_msgq_meminfo();
+ dma += bfa_msgq_meminfo();
+
+ ioceth->stop_cbfn = NULL;
+ ioceth->stop_cbarg = NULL;
+
+ bna_attr_init(ioceth);
+
+ bfa_fsm_set_state(ioceth, bna_ioceth_sm_stopped);
+}
+
+static void
+bna_ioceth_uninit(struct bna_ioceth *ioceth)
+{
+ bfa_nw_ioc_detach(&ioceth->ioc);
+
+ ioceth->bna = NULL;
+}
+
+void
+bna_ioceth_enable(struct bna_ioceth *ioceth)
+{
+ if (ioceth->fsm == (bfa_fsm_t)bna_ioceth_sm_ready) {
+ bnad_cb_ioceth_ready(ioceth->bna->bnad);
+ return;
+ }
+
+ if (ioceth->fsm == (bfa_fsm_t)bna_ioceth_sm_stopped)
+ bfa_fsm_send_event(ioceth, IOCETH_E_ENABLE);
+}
+
+void
+bna_ioceth_disable(struct bna_ioceth *ioceth, enum bna_cleanup_type type)
+{
+ if (type == BNA_SOFT_CLEANUP) {
+ bnad_cb_ioceth_disabled(ioceth->bna->bnad);
+ return;
+ }
+
+ ioceth->stop_cbfn = bnad_cb_ioceth_disabled;
+ ioceth->stop_cbarg = ioceth->bna->bnad;
+
+ bfa_fsm_send_event(ioceth, IOCETH_E_DISABLE);
+}
+
+static void
+bna_ucam_mod_init(struct bna_ucam_mod *ucam_mod, struct bna *bna,
+ struct bna_res_info *res_info)
+{
+ int i;
+
+ ucam_mod->ucmac = (struct bna_mac *)
+ res_info[BNA_MOD_RES_MEM_T_UCMAC_ARRAY].res_u.mem_info.mdl[0].kva;
+
+ INIT_LIST_HEAD(&ucam_mod->free_q);
+ for (i = 0; i < bna->ioceth.attr.num_ucmac; i++) {
+ bfa_q_qe_init(&ucam_mod->ucmac[i].qe);
+ list_add_tail(&ucam_mod->ucmac[i].qe, &ucam_mod->free_q);
+ }
+
+ ucam_mod->bna = bna;
+}
+
+static void
+bna_ucam_mod_uninit(struct bna_ucam_mod *ucam_mod)
+{
+ struct list_head *qe;
+ int i = 0;
+
+ list_for_each(qe, &ucam_mod->free_q)
+ i++;
+
+ ucam_mod->bna = NULL;
+}
+
+static void
+bna_mcam_mod_init(struct bna_mcam_mod *mcam_mod, struct bna *bna,
+ struct bna_res_info *res_info)
+{
+ int i;
+
+ mcam_mod->mcmac = (struct bna_mac *)
+ res_info[BNA_MOD_RES_MEM_T_MCMAC_ARRAY].res_u.mem_info.mdl[0].kva;
+
+ INIT_LIST_HEAD(&mcam_mod->free_q);
+ for (i = 0; i < bna->ioceth.attr.num_mcmac; i++) {
+ bfa_q_qe_init(&mcam_mod->mcmac[i].qe);
+ list_add_tail(&mcam_mod->mcmac[i].qe, &mcam_mod->free_q);
+ }
+
+ mcam_mod->mchandle = (struct bna_mcam_handle *)
+ res_info[BNA_MOD_RES_MEM_T_MCHANDLE_ARRAY].res_u.mem_info.mdl[0].kva;
+
+ INIT_LIST_HEAD(&mcam_mod->free_handle_q);
+ for (i = 0; i < bna->ioceth.attr.num_mcmac; i++) {
+ bfa_q_qe_init(&mcam_mod->mchandle[i].qe);
+ list_add_tail(&mcam_mod->mchandle[i].qe,
+ &mcam_mod->free_handle_q);
+ }
+
+ mcam_mod->bna = bna;
+}
+
+static void
+bna_mcam_mod_uninit(struct bna_mcam_mod *mcam_mod)
+{
+ struct list_head *qe;
+ int i;
+
+ i = 0;
+ list_for_each(qe, &mcam_mod->free_q) i++;
+
+ i = 0;
+ list_for_each(qe, &mcam_mod->free_handle_q) i++;
+
+ mcam_mod->bna = NULL;
+}
+
+static void
+bna_bfi_stats_get(struct bna *bna)
+{
+ struct bfi_enet_stats_req *stats_req = &bna->stats_mod.stats_get;
+
+ bna->stats_mod.stats_get_busy = true;
+
+ bfi_msgq_mhdr_set(stats_req->mh, BFI_MC_ENET,
+ BFI_ENET_H2I_STATS_GET_REQ, 0, 0);
+ stats_req->mh.num_entries = htons(
+ bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_stats_req)));
+ stats_req->stats_mask = htons(BFI_ENET_STATS_ALL);
+ stats_req->tx_enet_mask = htonl(bna->tx_mod.rid_mask);
+ stats_req->rx_enet_mask = htonl(bna->rx_mod.rid_mask);
+ stats_req->host_buffer.a32.addr_hi = bna->stats.hw_stats_dma.msb;
+ stats_req->host_buffer.a32.addr_lo = bna->stats.hw_stats_dma.lsb;
+
+ bfa_msgq_cmd_set(&bna->stats_mod.stats_get_cmd, NULL, NULL,
+ sizeof(struct bfi_enet_stats_req), &stats_req->mh);
+ bfa_msgq_cmd_post(&bna->msgq, &bna->stats_mod.stats_get_cmd);
+}
+
+void
+bna_res_req(struct bna_res_info *res_info)
+{
+ /* DMA memory for COMMON_MODULE */
+ res_info[BNA_RES_MEM_T_COM].res_type = BNA_RES_T_MEM;
+ res_info[BNA_RES_MEM_T_COM].res_u.mem_info.mem_type = BNA_MEM_T_DMA;
+ res_info[BNA_RES_MEM_T_COM].res_u.mem_info.num = 1;
+ res_info[BNA_RES_MEM_T_COM].res_u.mem_info.len = ALIGN(
+ (bfa_nw_cee_meminfo() +
+ bfa_msgq_meminfo()), PAGE_SIZE);
+
+ /* DMA memory for retrieving IOC attributes */
+ res_info[BNA_RES_MEM_T_ATTR].res_type = BNA_RES_T_MEM;
+ res_info[BNA_RES_MEM_T_ATTR].res_u.mem_info.mem_type = BNA_MEM_T_DMA;
+ res_info[BNA_RES_MEM_T_ATTR].res_u.mem_info.num = 1;
+ res_info[BNA_RES_MEM_T_ATTR].res_u.mem_info.len =
+ ALIGN(bfa_nw_ioc_meminfo(), PAGE_SIZE);
+
+ /* Virtual memory for retreiving fw_trc */
+ res_info[BNA_RES_MEM_T_FWTRC].res_type = BNA_RES_T_MEM;
+ res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.mem_type = BNA_MEM_T_KVA;
+ res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.num = 0;
+ res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.len = 0;
+
+ /* DMA memory for retreiving stats */
+ res_info[BNA_RES_MEM_T_STATS].res_type = BNA_RES_T_MEM;
+ res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.mem_type = BNA_MEM_T_DMA;
+ res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.num = 1;
+ res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.len =
+ ALIGN(sizeof(struct bfi_enet_stats),
+ PAGE_SIZE);
+}
+
+void
+bna_mod_res_req(struct bna *bna, struct bna_res_info *res_info)
+{
+ struct bna_attr *attr = &bna->ioceth.attr;
+
+ /* Virtual memory for Tx objects - stored by Tx module */
+ res_info[BNA_MOD_RES_MEM_T_TX_ARRAY].res_type = BNA_RES_T_MEM;
+ res_info[BNA_MOD_RES_MEM_T_TX_ARRAY].res_u.mem_info.mem_type =
+ BNA_MEM_T_KVA;
+ res_info[BNA_MOD_RES_MEM_T_TX_ARRAY].res_u.mem_info.num = 1;
+ res_info[BNA_MOD_RES_MEM_T_TX_ARRAY].res_u.mem_info.len =
+ attr->num_txq * sizeof(struct bna_tx);
+
+ /* Virtual memory for TxQ - stored by Tx module */
+ res_info[BNA_MOD_RES_MEM_T_TXQ_ARRAY].res_type = BNA_RES_T_MEM;
+ res_info[BNA_MOD_RES_MEM_T_TXQ_ARRAY].res_u.mem_info.mem_type =
+ BNA_MEM_T_KVA;
+ res_info[BNA_MOD_RES_MEM_T_TXQ_ARRAY].res_u.mem_info.num = 1;
+ res_info[BNA_MOD_RES_MEM_T_TXQ_ARRAY].res_u.mem_info.len =
+ attr->num_txq * sizeof(struct bna_txq);
+
+ /* Virtual memory for Rx objects - stored by Rx module */
+ res_info[BNA_MOD_RES_MEM_T_RX_ARRAY].res_type = BNA_RES_T_MEM;
+ res_info[BNA_MOD_RES_MEM_T_RX_ARRAY].res_u.mem_info.mem_type =
+ BNA_MEM_T_KVA;
+ res_info[BNA_MOD_RES_MEM_T_RX_ARRAY].res_u.mem_info.num = 1;
+ res_info[BNA_MOD_RES_MEM_T_RX_ARRAY].res_u.mem_info.len =
+ attr->num_rxp * sizeof(struct bna_rx);
+
+ /* Virtual memory for RxPath - stored by Rx module */
+ res_info[BNA_MOD_RES_MEM_T_RXP_ARRAY].res_type = BNA_RES_T_MEM;
+ res_info[BNA_MOD_RES_MEM_T_RXP_ARRAY].res_u.mem_info.mem_type =
+ BNA_MEM_T_KVA;
+ res_info[BNA_MOD_RES_MEM_T_RXP_ARRAY].res_u.mem_info.num = 1;
+ res_info[BNA_MOD_RES_MEM_T_RXP_ARRAY].res_u.mem_info.len =
+ attr->num_rxp * sizeof(struct bna_rxp);
+
+ /* Virtual memory for RxQ - stored by Rx module */
+ res_info[BNA_MOD_RES_MEM_T_RXQ_ARRAY].res_type = BNA_RES_T_MEM;
+ res_info[BNA_MOD_RES_MEM_T_RXQ_ARRAY].res_u.mem_info.mem_type =
+ BNA_MEM_T_KVA;
+ res_info[BNA_MOD_RES_MEM_T_RXQ_ARRAY].res_u.mem_info.num = 1;
+ res_info[BNA_MOD_RES_MEM_T_RXQ_ARRAY].res_u.mem_info.len =
+ (attr->num_rxp * 2) * sizeof(struct bna_rxq);
+
+ /* Virtual memory for Unicast MAC address - stored by ucam module */
+ res_info[BNA_MOD_RES_MEM_T_UCMAC_ARRAY].res_type = BNA_RES_T_MEM;
+ res_info[BNA_MOD_RES_MEM_T_UCMAC_ARRAY].res_u.mem_info.mem_type =
+ BNA_MEM_T_KVA;
+ res_info[BNA_MOD_RES_MEM_T_UCMAC_ARRAY].res_u.mem_info.num = 1;
+ res_info[BNA_MOD_RES_MEM_T_UCMAC_ARRAY].res_u.mem_info.len =
+ attr->num_ucmac * sizeof(struct bna_mac);
+
+ /* Virtual memory for Multicast MAC address - stored by mcam module */
+ res_info[BNA_MOD_RES_MEM_T_MCMAC_ARRAY].res_type = BNA_RES_T_MEM;
+ res_info[BNA_MOD_RES_MEM_T_MCMAC_ARRAY].res_u.mem_info.mem_type =
+ BNA_MEM_T_KVA;
+ res_info[BNA_MOD_RES_MEM_T_MCMAC_ARRAY].res_u.mem_info.num = 1;
+ res_info[BNA_MOD_RES_MEM_T_MCMAC_ARRAY].res_u.mem_info.len =
+ attr->num_mcmac * sizeof(struct bna_mac);
+
+ /* Virtual memory for Multicast handle - stored by mcam module */
+ res_info[BNA_MOD_RES_MEM_T_MCHANDLE_ARRAY].res_type = BNA_RES_T_MEM;
+ res_info[BNA_MOD_RES_MEM_T_MCHANDLE_ARRAY].res_u.mem_info.mem_type =
+ BNA_MEM_T_KVA;
+ res_info[BNA_MOD_RES_MEM_T_MCHANDLE_ARRAY].res_u.mem_info.num = 1;
+ res_info[BNA_MOD_RES_MEM_T_MCHANDLE_ARRAY].res_u.mem_info.len =
+ attr->num_mcmac * sizeof(struct bna_mcam_handle);
+}
+
+void
+bna_init(struct bna *bna, struct bnad *bnad,
+ struct bfa_pcidev *pcidev, struct bna_res_info *res_info)
+{
+ bna->bnad = bnad;
+ bna->pcidev = *pcidev;
+
+ bna->stats.hw_stats_kva = (struct bfi_enet_stats *)
+ res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.mdl[0].kva;
+ bna->stats.hw_stats_dma.msb =
+ res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.mdl[0].dma.msb;
+ bna->stats.hw_stats_dma.lsb =
+ res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.mdl[0].dma.lsb;
+
+ bna_reg_addr_init(bna, &bna->pcidev);
+
+ /* Also initializes diag, cee, sfp, phy_port, msgq */
+ bna_ioceth_init(&bna->ioceth, bna, res_info);
+
+ bna_enet_init(&bna->enet, bna);
+ bna_ethport_init(&bna->ethport, bna);
+}
+
+void
+bna_mod_init(struct bna *bna, struct bna_res_info *res_info)
+{
+ bna_tx_mod_init(&bna->tx_mod, bna, res_info);
+
+ bna_rx_mod_init(&bna->rx_mod, bna, res_info);
+
+ bna_ucam_mod_init(&bna->ucam_mod, bna, res_info);
+
+ bna_mcam_mod_init(&bna->mcam_mod, bna, res_info);
+
+ bna->default_mode_rid = BFI_INVALID_RID;
+ bna->promisc_rid = BFI_INVALID_RID;
+
+ bna->mod_flags |= BNA_MOD_F_INIT_DONE;
+}
+
+void
+bna_uninit(struct bna *bna)
+{
+ if (bna->mod_flags & BNA_MOD_F_INIT_DONE) {
+ bna_mcam_mod_uninit(&bna->mcam_mod);
+ bna_ucam_mod_uninit(&bna->ucam_mod);
+ bna_rx_mod_uninit(&bna->rx_mod);
+ bna_tx_mod_uninit(&bna->tx_mod);
+ bna->mod_flags &= ~BNA_MOD_F_INIT_DONE;
+ }
+
+ bna_stats_mod_uninit(&bna->stats_mod);
+ bna_ethport_uninit(&bna->ethport);
+ bna_enet_uninit(&bna->enet);
+
+ bna_ioceth_uninit(&bna->ioceth);
+
+ bna->bnad = NULL;
+}
+
+int
+bna_num_txq_set(struct bna *bna, int num_txq)
+{
+ if (bna->ioceth.attr.fw_query_complete &&
+ (num_txq <= bna->ioceth.attr.num_txq)) {
+ bna->ioceth.attr.num_txq = num_txq;
+ return BNA_CB_SUCCESS;
+ }
+
+ return BNA_CB_FAIL;
+}
+
+int
+bna_num_rxp_set(struct bna *bna, int num_rxp)
+{
+ if (bna->ioceth.attr.fw_query_complete &&
+ (num_rxp <= bna->ioceth.attr.num_rxp)) {
+ bna->ioceth.attr.num_rxp = num_rxp;
+ return BNA_CB_SUCCESS;
+ }
+
+ return BNA_CB_FAIL;
+}
+
+struct bna_mac *
+bna_ucam_mod_mac_get(struct bna_ucam_mod *ucam_mod)
+{
+ struct list_head *qe;
+
+ if (list_empty(&ucam_mod->free_q))
+ return NULL;
+
+ bfa_q_deq(&ucam_mod->free_q, &qe);
+
+ return (struct bna_mac *)qe;
+}
+
+void
+bna_ucam_mod_mac_put(struct bna_ucam_mod *ucam_mod, struct bna_mac *mac)
+{
+ list_add_tail(&mac->qe, &ucam_mod->free_q);
+}
+
+struct bna_mac *
+bna_mcam_mod_mac_get(struct bna_mcam_mod *mcam_mod)
+{
+ struct list_head *qe;
+
+ if (list_empty(&mcam_mod->free_q))
+ return NULL;
+
+ bfa_q_deq(&mcam_mod->free_q, &qe);
+
+ return (struct bna_mac *)qe;
+}
+
+void
+bna_mcam_mod_mac_put(struct bna_mcam_mod *mcam_mod, struct bna_mac *mac)
+{
+ list_add_tail(&mac->qe, &mcam_mod->free_q);
+}
+
+struct bna_mcam_handle *
+bna_mcam_mod_handle_get(struct bna_mcam_mod *mcam_mod)
+{
+ struct list_head *qe;
+
+ if (list_empty(&mcam_mod->free_handle_q))
+ return NULL;
+
+ bfa_q_deq(&mcam_mod->free_handle_q, &qe);
+
+ return (struct bna_mcam_handle *)qe;
+}
+
+void
+bna_mcam_mod_handle_put(struct bna_mcam_mod *mcam_mod,
+ struct bna_mcam_handle *handle)
+{
+ list_add_tail(&handle->qe, &mcam_mod->free_handle_q);
+}
+
+void
+bna_hw_stats_get(struct bna *bna)
+{
+ if (!bna->stats_mod.ioc_ready) {
+ bnad_cb_stats_get(bna->bnad, BNA_CB_FAIL, &bna->stats);
+ return;
+ }
+ if (bna->stats_mod.stats_get_busy) {
+ bnad_cb_stats_get(bna->bnad, BNA_CB_BUSY, &bna->stats);
+ return;
+ }
+
+ bna_bfi_stats_get(bna);
+}
diff --git a/drivers/net/ethernet/brocade/bna/bna_hw_defs.h b/drivers/net/ethernet/brocade/bna/bna_hw_defs.h
new file mode 100644
index 000000000000..4c6aab2a9534
--- /dev/null
+++ b/drivers/net/ethernet/brocade/bna/bna_hw_defs.h
@@ -0,0 +1,422 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2005-2011 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+/**
+ * File for interrupt macros and functions
+ */
+
+#ifndef __BNA_HW_DEFS_H__
+#define __BNA_HW_DEFS_H__
+
+#include "bfi_reg.h"
+
+/**
+ *
+ * SW imposed limits
+ *
+ */
+#define BFI_ENET_DEF_TXQ 1
+#define BFI_ENET_DEF_RXP 1
+#define BFI_ENET_DEF_UCAM 1
+#define BFI_ENET_DEF_RITSZ 1
+
+#define BFI_ENET_MAX_MCAM 256
+
+#define BFI_INVALID_RID -1
+
+#define BFI_IBIDX_SIZE 4
+
+#define BFI_VLAN_WORD_SHIFT 5 /* 32 bits */
+#define BFI_VLAN_WORD_MASK 0x1F
+#define BFI_VLAN_BLOCK_SHIFT 9 /* 512 bits */
+#define BFI_VLAN_BMASK_ALL 0xFF
+
+#define BFI_COALESCING_TIMER_UNIT 5 /* 5us */
+#define BFI_MAX_COALESCING_TIMEO 0xFF /* in 5us units */
+#define BFI_MAX_INTERPKT_COUNT 0xFF
+#define BFI_MAX_INTERPKT_TIMEO 0xF /* in 0.5us units */
+#define BFI_TX_COALESCING_TIMEO 20 /* 20 * 5 = 100us */
+#define BFI_TX_INTERPKT_COUNT 32
+#define BFI_RX_COALESCING_TIMEO 12 /* 12 * 5 = 60us */
+#define BFI_RX_INTERPKT_COUNT 6 /* Pkt Cnt = 6 */
+#define BFI_RX_INTERPKT_TIMEO 3 /* 3 * 0.5 = 1.5us */
+
+#define BFI_TXQ_WI_SIZE 64 /* bytes */
+#define BFI_RXQ_WI_SIZE 8 /* bytes */
+#define BFI_CQ_WI_SIZE 16 /* bytes */
+#define BFI_TX_MAX_WRR_QUOTA 0xFFF
+
+#define BFI_TX_MAX_VECTORS_PER_WI 4
+#define BFI_TX_MAX_VECTORS_PER_PKT 0xFF
+#define BFI_TX_MAX_DATA_PER_VECTOR 0xFFFF
+#define BFI_TX_MAX_DATA_PER_PKT 0xFFFFFF
+
+/* Small Q buffer size */
+#define BFI_SMALL_RXBUF_SIZE 128
+
+#define BFI_TX_MAX_PRIO 8
+#define BFI_TX_PRIO_MAP_ALL 0xFF
+
+/*
+ *
+ * Register definitions and macros
+ *
+ */
+
+#define BNA_PCI_REG_CT_ADDRSZ (0x40000)
+
+#define ct_reg_addr_init(_bna, _pcidev) \
+{ \
+ struct bna_reg_offset reg_offset[] = \
+ {{HOSTFN0_INT_STATUS, HOSTFN0_INT_MSK}, \
+ {HOSTFN1_INT_STATUS, HOSTFN1_INT_MSK}, \
+ {HOSTFN2_INT_STATUS, HOSTFN2_INT_MSK}, \
+ {HOSTFN3_INT_STATUS, HOSTFN3_INT_MSK} }; \
+ \
+ (_bna)->regs.fn_int_status = (_pcidev)->pci_bar_kva + \
+ reg_offset[(_pcidev)->pci_func].fn_int_status;\
+ (_bna)->regs.fn_int_mask = (_pcidev)->pci_bar_kva + \
+ reg_offset[(_pcidev)->pci_func].fn_int_mask;\
+}
+
+#define ct_bit_defn_init(_bna, _pcidev) \
+{ \
+ (_bna)->bits.mbox_status_bits = (__HFN_INT_MBOX_LPU0 | \
+ __HFN_INT_MBOX_LPU1); \
+ (_bna)->bits.mbox_mask_bits = (__HFN_INT_MBOX_LPU0 | \
+ __HFN_INT_MBOX_LPU1); \
+ (_bna)->bits.error_status_bits = (__HFN_INT_ERR_MASK); \
+ (_bna)->bits.error_mask_bits = (__HFN_INT_ERR_MASK); \
+ (_bna)->bits.halt_status_bits = __HFN_INT_LL_HALT; \
+ (_bna)->bits.halt_mask_bits = __HFN_INT_LL_HALT; \
+}
+
+#define ct2_reg_addr_init(_bna, _pcidev) \
+{ \
+ (_bna)->regs.fn_int_status = (_pcidev)->pci_bar_kva + \
+ CT2_HOSTFN_INT_STATUS; \
+ (_bna)->regs.fn_int_mask = (_pcidev)->pci_bar_kva + \
+ CT2_HOSTFN_INTR_MASK; \
+}
+
+#define ct2_bit_defn_init(_bna, _pcidev) \
+{ \
+ (_bna)->bits.mbox_status_bits = (__HFN_INT_MBOX_LPU0_CT2 | \
+ __HFN_INT_MBOX_LPU1_CT2); \
+ (_bna)->bits.mbox_mask_bits = (__HFN_INT_MBOX_LPU0_CT2 | \
+ __HFN_INT_MBOX_LPU1_CT2); \
+ (_bna)->bits.error_status_bits = (__HFN_INT_ERR_MASK_CT2); \
+ (_bna)->bits.error_mask_bits = (__HFN_INT_ERR_MASK_CT2); \
+ (_bna)->bits.halt_status_bits = __HFN_INT_CPQ_HALT_CT2; \
+ (_bna)->bits.halt_mask_bits = __HFN_INT_CPQ_HALT_CT2; \
+}
+
+#define bna_reg_addr_init(_bna, _pcidev) \
+{ \
+ switch ((_pcidev)->device_id) { \
+ case PCI_DEVICE_ID_BROCADE_CT: \
+ ct_reg_addr_init((_bna), (_pcidev)); \
+ ct_bit_defn_init((_bna), (_pcidev)); \
+ break; \
+ case BFA_PCI_DEVICE_ID_CT2: \
+ ct2_reg_addr_init((_bna), (_pcidev)); \
+ ct2_bit_defn_init((_bna), (_pcidev)); \
+ break; \
+ } \
+}
+
+#define bna_port_id_get(_bna) ((_bna)->ioceth.ioc.port_id)
+/**
+ *
+ * Interrupt related bits, flags and macros
+ *
+ */
+
+#define IB_STATUS_BITS 0x0000ffff
+
+#define BNA_IS_MBOX_INTR(_bna, _intr_status) \
+ ((_intr_status) & (_bna)->bits.mbox_status_bits)
+
+#define BNA_IS_HALT_INTR(_bna, _intr_status) \
+ ((_intr_status) & (_bna)->bits.halt_status_bits)
+
+#define BNA_IS_ERR_INTR(_bna, _intr_status) \
+ ((_intr_status) & (_bna)->bits.error_status_bits)
+
+#define BNA_IS_MBOX_ERR_INTR(_bna, _intr_status) \
+ (BNA_IS_MBOX_INTR(_bna, _intr_status) | \
+ BNA_IS_ERR_INTR(_bna, _intr_status))
+
+#define BNA_IS_INTX_DATA_INTR(_intr_status) \
+ ((_intr_status) & IB_STATUS_BITS)
+
+#define bna_halt_clear(_bna) \
+do { \
+ u32 init_halt; \
+ init_halt = readl((_bna)->ioceth.ioc.ioc_regs.ll_halt); \
+ init_halt &= ~__FW_INIT_HALT_P; \
+ writel(init_halt, (_bna)->ioceth.ioc.ioc_regs.ll_halt); \
+ init_halt = readl((_bna)->ioceth.ioc.ioc_regs.ll_halt); \
+} while (0)
+
+#define bna_intx_disable(_bna, _cur_mask) \
+{ \
+ (_cur_mask) = readl((_bna)->regs.fn_int_mask); \
+ writel(0xffffffff, (_bna)->regs.fn_int_mask); \
+}
+
+#define bna_intx_enable(bna, new_mask) \
+ writel((new_mask), (bna)->regs.fn_int_mask)
+#define bna_mbox_intr_disable(bna) \
+do { \
+ u32 mask; \
+ mask = readl((bna)->regs.fn_int_mask); \
+ writel((mask | (bna)->bits.mbox_mask_bits | \
+ (bna)->bits.error_mask_bits), (bna)->regs.fn_int_mask); \
+ mask = readl((bna)->regs.fn_int_mask); \
+} while (0)
+
+#define bna_mbox_intr_enable(bna) \
+do { \
+ u32 mask; \
+ mask = readl((bna)->regs.fn_int_mask); \
+ writel((mask & ~((bna)->bits.mbox_mask_bits | \
+ (bna)->bits.error_mask_bits)), (bna)->regs.fn_int_mask);\
+ mask = readl((bna)->regs.fn_int_mask); \
+} while (0)
+
+#define bna_intr_status_get(_bna, _status) \
+{ \
+ (_status) = readl((_bna)->regs.fn_int_status); \
+ if (_status) { \
+ writel(((_status) & ~(_bna)->bits.mbox_status_bits), \
+ (_bna)->regs.fn_int_status); \
+ } \
+}
+
+/*
+ * MAX ACK EVENTS : No. of acks that can be accumulated in driver,
+ * before acking to h/w. The no. of bits is 16 in the doorbell register,
+ * however we keep this limited to 15 bits.
+ * This is because around the edge of 64K boundary (16 bits), one
+ * single poll can make the accumulated ACK counter cross the 64K boundary,
+ * causing problems, when we try to ack with a value greater than 64K.
+ * 15 bits (32K) should be large enough to accumulate, anyways, and the max.
+ * acked events to h/w can be (32K + max poll weight) (currently 64).
+ */
+#define BNA_IB_MAX_ACK_EVENTS (1 << 15)
+
+/* These macros build the data portion of the TxQ/RxQ doorbell */
+#define BNA_DOORBELL_Q_PRD_IDX(_pi) (0x80000000 | (_pi))
+#define BNA_DOORBELL_Q_STOP (0x40000000)
+
+/* These macros build the data portion of the IB doorbell */
+#define BNA_DOORBELL_IB_INT_ACK(_timeout, _events) \
+ (0x80000000 | ((_timeout) << 16) | (_events))
+#define BNA_DOORBELL_IB_INT_DISABLE (0x40000000)
+
+/* Set the coalescing timer for the given ib */
+#define bna_ib_coalescing_timer_set(_i_dbell, _cls_timer) \
+ ((_i_dbell)->doorbell_ack = BNA_DOORBELL_IB_INT_ACK((_cls_timer), 0));
+
+/* Acks 'events' # of events for a given ib while disabling interrupts */
+#define bna_ib_ack_disable_irq(_i_dbell, _events) \
+ (writel(BNA_DOORBELL_IB_INT_ACK(0, (_events)), \
+ (_i_dbell)->doorbell_addr));
+
+/* Acks 'events' # of events for a given ib */
+#define bna_ib_ack(_i_dbell, _events) \
+ (writel(((_i_dbell)->doorbell_ack | (_events)), \
+ (_i_dbell)->doorbell_addr));
+
+#define bna_ib_start(_bna, _ib, _is_regular) \
+{ \
+ u32 intx_mask; \
+ struct bna_ib *ib = _ib; \
+ if ((ib->intr_type == BNA_INTR_T_INTX)) { \
+ bna_intx_disable((_bna), intx_mask); \
+ intx_mask &= ~(ib->intr_vector); \
+ bna_intx_enable((_bna), intx_mask); \
+ } \
+ bna_ib_coalescing_timer_set(&ib->door_bell, \
+ ib->coalescing_timeo); \
+ if (_is_regular) \
+ bna_ib_ack(&ib->door_bell, 0); \
+}
+
+#define bna_ib_stop(_bna, _ib) \
+{ \
+ u32 intx_mask; \
+ struct bna_ib *ib = _ib; \
+ writel(BNA_DOORBELL_IB_INT_DISABLE, \
+ ib->door_bell.doorbell_addr); \
+ if (ib->intr_type == BNA_INTR_T_INTX) { \
+ bna_intx_disable((_bna), intx_mask); \
+ intx_mask |= ib->intr_vector; \
+ bna_intx_enable((_bna), intx_mask); \
+ } \
+}
+
+#define bna_txq_prod_indx_doorbell(_tcb) \
+ (writel(BNA_DOORBELL_Q_PRD_IDX((_tcb)->producer_index), \
+ (_tcb)->q_dbell));
+
+#define bna_rxq_prod_indx_doorbell(_rcb) \
+ (writel(BNA_DOORBELL_Q_PRD_IDX((_rcb)->producer_index), \
+ (_rcb)->q_dbell));
+
+/**
+ *
+ * TxQ, RxQ, CQ related bits, offsets, macros
+ *
+ */
+
+/* TxQ Entry Opcodes */
+#define BNA_TXQ_WI_SEND (0x402) /* Single Frame Transmission */
+#define BNA_TXQ_WI_SEND_LSO (0x403) /* Multi-Frame Transmission */
+#define BNA_TXQ_WI_EXTENSION (0x104) /* Extension WI */
+
+/* TxQ Entry Control Flags */
+#define BNA_TXQ_WI_CF_FCOE_CRC (1 << 8)
+#define BNA_TXQ_WI_CF_IPID_MODE (1 << 5)
+#define BNA_TXQ_WI_CF_INS_PRIO (1 << 4)
+#define BNA_TXQ_WI_CF_INS_VLAN (1 << 3)
+#define BNA_TXQ_WI_CF_UDP_CKSUM (1 << 2)
+#define BNA_TXQ_WI_CF_TCP_CKSUM (1 << 1)
+#define BNA_TXQ_WI_CF_IP_CKSUM (1 << 0)
+
+#define BNA_TXQ_WI_L4_HDR_N_OFFSET(_hdr_size, _offset) \
+ (((_hdr_size) << 10) | ((_offset) & 0x3FF))
+
+/*
+ * Completion Q defines
+ */
+/* CQ Entry Flags */
+#define BNA_CQ_EF_MAC_ERROR (1 << 0)
+#define BNA_CQ_EF_FCS_ERROR (1 << 1)
+#define BNA_CQ_EF_TOO_LONG (1 << 2)
+#define BNA_CQ_EF_FC_CRC_OK (1 << 3)
+
+#define BNA_CQ_EF_RSVD1 (1 << 4)
+#define BNA_CQ_EF_L4_CKSUM_OK (1 << 5)
+#define BNA_CQ_EF_L3_CKSUM_OK (1 << 6)
+#define BNA_CQ_EF_HDS_HEADER (1 << 7)
+
+#define BNA_CQ_EF_UDP (1 << 8)
+#define BNA_CQ_EF_TCP (1 << 9)
+#define BNA_CQ_EF_IP_OPTIONS (1 << 10)
+#define BNA_CQ_EF_IPV6 (1 << 11)
+
+#define BNA_CQ_EF_IPV4 (1 << 12)
+#define BNA_CQ_EF_VLAN (1 << 13)
+#define BNA_CQ_EF_RSS (1 << 14)
+#define BNA_CQ_EF_RSVD2 (1 << 15)
+
+#define BNA_CQ_EF_MCAST_MATCH (1 << 16)
+#define BNA_CQ_EF_MCAST (1 << 17)
+#define BNA_CQ_EF_BCAST (1 << 18)
+#define BNA_CQ_EF_REMOTE (1 << 19)
+
+#define BNA_CQ_EF_LOCAL (1 << 20)
+
+/**
+ *
+ * Data structures
+ *
+ */
+
+struct bna_reg_offset {
+ u32 fn_int_status;
+ u32 fn_int_mask;
+};
+
+struct bna_bit_defn {
+ u32 mbox_status_bits;
+ u32 mbox_mask_bits;
+ u32 error_status_bits;
+ u32 error_mask_bits;
+ u32 halt_status_bits;
+ u32 halt_mask_bits;
+};
+
+struct bna_reg {
+ void __iomem *fn_int_status;
+ void __iomem *fn_int_mask;
+};
+
+/* TxQ Vector (a.k.a. Tx-Buffer Descriptor) */
+struct bna_dma_addr {
+ u32 msb;
+ u32 lsb;
+};
+
+struct bna_txq_wi_vector {
+ u16 reserved;
+ u16 length; /* Only 14 LSB are valid */
+ struct bna_dma_addr host_addr; /* Tx-Buf DMA addr */
+};
+
+/**
+ * TxQ Entry Structure
+ *
+ * BEWARE: Load values into this structure with correct endianess.
+ */
+struct bna_txq_entry {
+ union {
+ struct {
+ u8 reserved;
+ u8 num_vectors; /* number of vectors present */
+ u16 opcode; /* Either */
+ /* BNA_TXQ_WI_SEND or */
+ /* BNA_TXQ_WI_SEND_LSO */
+ u16 flags; /* OR of all the flags */
+ u16 l4_hdr_size_n_offset;
+ u16 vlan_tag;
+ u16 lso_mss; /* Only 14 LSB are valid */
+ u32 frame_length; /* Only 24 LSB are valid */
+ } wi;
+
+ struct {
+ u16 reserved;
+ u16 opcode; /* Must be */
+ /* BNA_TXQ_WI_EXTENSION */
+ u32 reserved2[3]; /* Place holder for */
+ /* removed vector (12 bytes) */
+ } wi_ext;
+ } hdr;
+ struct bna_txq_wi_vector vector[4];
+};
+
+/* RxQ Entry Structure */
+struct bna_rxq_entry { /* Rx-Buffer */
+ struct bna_dma_addr host_addr; /* Rx-Buffer DMA address */
+};
+
+/* CQ Entry Structure */
+struct bna_cq_entry {
+ u32 flags;
+ u16 vlan_tag;
+ u16 length;
+ u32 rss_hash;
+ u8 valid;
+ u8 reserved1;
+ u8 reserved2;
+ u8 rxq_id;
+};
+
+#endif /* __BNA_HW_DEFS_H__ */
diff --git a/drivers/net/ethernet/brocade/bna/bna_tx_rx.c b/drivers/net/ethernet/brocade/bna/bna_tx_rx.c
new file mode 100644
index 000000000000..276fcb589f4b
--- /dev/null
+++ b/drivers/net/ethernet/brocade/bna/bna_tx_rx.c
@@ -0,0 +1,3798 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2005-2011 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+#include "bna.h"
+#include "bfi.h"
+
+/**
+ * IB
+ */
+static void
+bna_ib_coalescing_timeo_set(struct bna_ib *ib, u8 coalescing_timeo)
+{
+ ib->coalescing_timeo = coalescing_timeo;
+ ib->door_bell.doorbell_ack = BNA_DOORBELL_IB_INT_ACK(
+ (u32)ib->coalescing_timeo, 0);
+}
+
+/**
+ * RXF
+ */
+
+#define bna_rxf_vlan_cfg_soft_reset(rxf) \
+do { \
+ (rxf)->vlan_pending_bitmask = (u8)BFI_VLAN_BMASK_ALL; \
+ (rxf)->vlan_strip_pending = true; \
+} while (0)
+
+#define bna_rxf_rss_cfg_soft_reset(rxf) \
+do { \
+ if ((rxf)->rss_status == BNA_STATUS_T_ENABLED) \
+ (rxf)->rss_pending = (BNA_RSS_F_RIT_PENDING | \
+ BNA_RSS_F_CFG_PENDING | \
+ BNA_RSS_F_STATUS_PENDING); \
+} while (0)
+
+static int bna_rxf_cfg_apply(struct bna_rxf *rxf);
+static void bna_rxf_cfg_reset(struct bna_rxf *rxf);
+static int bna_rxf_fltr_clear(struct bna_rxf *rxf);
+static int bna_rxf_ucast_cfg_apply(struct bna_rxf *rxf);
+static int bna_rxf_promisc_cfg_apply(struct bna_rxf *rxf);
+static int bna_rxf_allmulti_cfg_apply(struct bna_rxf *rxf);
+static int bna_rxf_vlan_strip_cfg_apply(struct bna_rxf *rxf);
+static int bna_rxf_ucast_cfg_reset(struct bna_rxf *rxf,
+ enum bna_cleanup_type cleanup);
+static int bna_rxf_promisc_cfg_reset(struct bna_rxf *rxf,
+ enum bna_cleanup_type cleanup);
+static int bna_rxf_allmulti_cfg_reset(struct bna_rxf *rxf,
+ enum bna_cleanup_type cleanup);
+
+bfa_fsm_state_decl(bna_rxf, stopped, struct bna_rxf,
+ enum bna_rxf_event);
+bfa_fsm_state_decl(bna_rxf, paused, struct bna_rxf,
+ enum bna_rxf_event);
+bfa_fsm_state_decl(bna_rxf, cfg_wait, struct bna_rxf,
+ enum bna_rxf_event);
+bfa_fsm_state_decl(bna_rxf, started, struct bna_rxf,
+ enum bna_rxf_event);
+bfa_fsm_state_decl(bna_rxf, fltr_clr_wait, struct bna_rxf,
+ enum bna_rxf_event);
+bfa_fsm_state_decl(bna_rxf, last_resp_wait, struct bna_rxf,
+ enum bna_rxf_event);
+
+static void
+bna_rxf_sm_stopped_entry(struct bna_rxf *rxf)
+{
+ call_rxf_stop_cbfn(rxf);
+}
+
+static void
+bna_rxf_sm_stopped(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+ switch (event) {
+ case RXF_E_START:
+ if (rxf->flags & BNA_RXF_F_PAUSED) {
+ bfa_fsm_set_state(rxf, bna_rxf_sm_paused);
+ call_rxf_start_cbfn(rxf);
+ } else
+ bfa_fsm_set_state(rxf, bna_rxf_sm_cfg_wait);
+ break;
+
+ case RXF_E_STOP:
+ call_rxf_stop_cbfn(rxf);
+ break;
+
+ case RXF_E_FAIL:
+ /* No-op */
+ break;
+
+ case RXF_E_CONFIG:
+ call_rxf_cam_fltr_cbfn(rxf);
+ break;
+
+ case RXF_E_PAUSE:
+ rxf->flags |= BNA_RXF_F_PAUSED;
+ call_rxf_pause_cbfn(rxf);
+ break;
+
+ case RXF_E_RESUME:
+ rxf->flags &= ~BNA_RXF_F_PAUSED;
+ call_rxf_resume_cbfn(rxf);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_rxf_sm_paused_entry(struct bna_rxf *rxf)
+{
+ call_rxf_pause_cbfn(rxf);
+}
+
+static void
+bna_rxf_sm_paused(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+ switch (event) {
+ case RXF_E_STOP:
+ case RXF_E_FAIL:
+ bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+ break;
+
+ case RXF_E_CONFIG:
+ call_rxf_cam_fltr_cbfn(rxf);
+ break;
+
+ case RXF_E_RESUME:
+ rxf->flags &= ~BNA_RXF_F_PAUSED;
+ bfa_fsm_set_state(rxf, bna_rxf_sm_cfg_wait);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_rxf_sm_cfg_wait_entry(struct bna_rxf *rxf)
+{
+ if (!bna_rxf_cfg_apply(rxf)) {
+ /* No more pending config updates */
+ bfa_fsm_set_state(rxf, bna_rxf_sm_started);
+ }
+}
+
+static void
+bna_rxf_sm_cfg_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+ switch (event) {
+ case RXF_E_STOP:
+ bfa_fsm_set_state(rxf, bna_rxf_sm_last_resp_wait);
+ break;
+
+ case RXF_E_FAIL:
+ bna_rxf_cfg_reset(rxf);
+ call_rxf_start_cbfn(rxf);
+ call_rxf_cam_fltr_cbfn(rxf);
+ call_rxf_resume_cbfn(rxf);
+ bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+ break;
+
+ case RXF_E_CONFIG:
+ /* No-op */
+ break;
+
+ case RXF_E_PAUSE:
+ rxf->flags |= BNA_RXF_F_PAUSED;
+ call_rxf_start_cbfn(rxf);
+ bfa_fsm_set_state(rxf, bna_rxf_sm_fltr_clr_wait);
+ break;
+
+ case RXF_E_FW_RESP:
+ if (!bna_rxf_cfg_apply(rxf)) {
+ /* No more pending config updates */
+ bfa_fsm_set_state(rxf, bna_rxf_sm_started);
+ }
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_rxf_sm_started_entry(struct bna_rxf *rxf)
+{
+ call_rxf_start_cbfn(rxf);
+ call_rxf_cam_fltr_cbfn(rxf);
+ call_rxf_resume_cbfn(rxf);
+}
+
+static void
+bna_rxf_sm_started(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+ switch (event) {
+ case RXF_E_STOP:
+ case RXF_E_FAIL:
+ bna_rxf_cfg_reset(rxf);
+ bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+ break;
+
+ case RXF_E_CONFIG:
+ bfa_fsm_set_state(rxf, bna_rxf_sm_cfg_wait);
+ break;
+
+ case RXF_E_PAUSE:
+ rxf->flags |= BNA_RXF_F_PAUSED;
+ if (!bna_rxf_fltr_clear(rxf))
+ bfa_fsm_set_state(rxf, bna_rxf_sm_paused);
+ else
+ bfa_fsm_set_state(rxf, bna_rxf_sm_fltr_clr_wait);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_rxf_sm_fltr_clr_wait_entry(struct bna_rxf *rxf)
+{
+}
+
+static void
+bna_rxf_sm_fltr_clr_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+ switch (event) {
+ case RXF_E_FAIL:
+ bna_rxf_cfg_reset(rxf);
+ call_rxf_pause_cbfn(rxf);
+ bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+ break;
+
+ case RXF_E_FW_RESP:
+ if (!bna_rxf_fltr_clear(rxf)) {
+ /* No more pending CAM entries to clear */
+ bfa_fsm_set_state(rxf, bna_rxf_sm_paused);
+ }
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_rxf_sm_last_resp_wait_entry(struct bna_rxf *rxf)
+{
+}
+
+static void
+bna_rxf_sm_last_resp_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+ switch (event) {
+ case RXF_E_FAIL:
+ case RXF_E_FW_RESP:
+ bna_rxf_cfg_reset(rxf);
+ bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_bfi_ucast_req(struct bna_rxf *rxf, struct bna_mac *mac,
+ enum bfi_enet_h2i_msgs req_type)
+{
+ struct bfi_enet_ucast_req *req = &rxf->bfi_enet_cmd.ucast_req;
+
+ bfi_msgq_mhdr_set(req->mh, BFI_MC_ENET, req_type, 0, rxf->rx->rid);
+ req->mh.num_entries = htons(
+ bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_ucast_req)));
+ memcpy(&req->mac_addr, &mac->addr, sizeof(mac_t));
+ bfa_msgq_cmd_set(&rxf->msgq_cmd, NULL, NULL,
+ sizeof(struct bfi_enet_ucast_req), &req->mh);
+ bfa_msgq_cmd_post(&rxf->rx->bna->msgq, &rxf->msgq_cmd);
+}
+
+static void
+bna_bfi_mcast_add_req(struct bna_rxf *rxf, struct bna_mac *mac)
+{
+ struct bfi_enet_mcast_add_req *req =
+ &rxf->bfi_enet_cmd.mcast_add_req;
+
+ bfi_msgq_mhdr_set(req->mh, BFI_MC_ENET, BFI_ENET_H2I_MAC_MCAST_ADD_REQ,
+ 0, rxf->rx->rid);
+ req->mh.num_entries = htons(
+ bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_mcast_add_req)));
+ memcpy(&req->mac_addr, &mac->addr, sizeof(mac_t));
+ bfa_msgq_cmd_set(&rxf->msgq_cmd, NULL, NULL,
+ sizeof(struct bfi_enet_mcast_add_req), &req->mh);
+ bfa_msgq_cmd_post(&rxf->rx->bna->msgq, &rxf->msgq_cmd);
+}
+
+static void
+bna_bfi_mcast_del_req(struct bna_rxf *rxf, u16 handle)
+{
+ struct bfi_enet_mcast_del_req *req =
+ &rxf->bfi_enet_cmd.mcast_del_req;
+
+ bfi_msgq_mhdr_set(req->mh, BFI_MC_ENET, BFI_ENET_H2I_MAC_MCAST_DEL_REQ,
+ 0, rxf->rx->rid);
+ req->mh.num_entries = htons(
+ bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_mcast_del_req)));
+ req->handle = htons(handle);
+ bfa_msgq_cmd_set(&rxf->msgq_cmd, NULL, NULL,
+ sizeof(struct bfi_enet_mcast_del_req), &req->mh);
+ bfa_msgq_cmd_post(&rxf->rx->bna->msgq, &rxf->msgq_cmd);
+}
+
+static void
+bna_bfi_mcast_filter_req(struct bna_rxf *rxf, enum bna_status status)
+{
+ struct bfi_enet_enable_req *req = &rxf->bfi_enet_cmd.req;
+
+ bfi_msgq_mhdr_set(req->mh, BFI_MC_ENET,
+ BFI_ENET_H2I_MAC_MCAST_FILTER_REQ, 0, rxf->rx->rid);
+ req->mh.num_entries = htons(
+ bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_enable_req)));
+ req->enable = status;
+ bfa_msgq_cmd_set(&rxf->msgq_cmd, NULL, NULL,
+ sizeof(struct bfi_enet_enable_req), &req->mh);
+ bfa_msgq_cmd_post(&rxf->rx->bna->msgq, &rxf->msgq_cmd);
+}
+
+static void
+bna_bfi_rx_promisc_req(struct bna_rxf *rxf, enum bna_status status)
+{
+ struct bfi_enet_enable_req *req = &rxf->bfi_enet_cmd.req;
+
+ bfi_msgq_mhdr_set(req->mh, BFI_MC_ENET,
+ BFI_ENET_H2I_RX_PROMISCUOUS_REQ, 0, rxf->rx->rid);
+ req->mh.num_entries = htons(
+ bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_enable_req)));
+ req->enable = status;
+ bfa_msgq_cmd_set(&rxf->msgq_cmd, NULL, NULL,
+ sizeof(struct bfi_enet_enable_req), &req->mh);
+ bfa_msgq_cmd_post(&rxf->rx->bna->msgq, &rxf->msgq_cmd);
+}
+
+static void
+bna_bfi_rx_vlan_filter_set(struct bna_rxf *rxf, u8 block_idx)
+{
+ struct bfi_enet_rx_vlan_req *req = &rxf->bfi_enet_cmd.vlan_req;
+ int i;
+ int j;
+
+ bfi_msgq_mhdr_set(req->mh, BFI_MC_ENET,
+ BFI_ENET_H2I_RX_VLAN_SET_REQ, 0, rxf->rx->rid);
+ req->mh.num_entries = htons(
+ bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_rx_vlan_req)));
+ req->block_idx = block_idx;
+ for (i = 0; i < (BFI_ENET_VLAN_BLOCK_SIZE / 32); i++) {
+ j = (block_idx * (BFI_ENET_VLAN_BLOCK_SIZE / 32)) + i;
+ if (rxf->vlan_filter_status == BNA_STATUS_T_ENABLED)
+ req->bit_mask[i] =
+ htonl(rxf->vlan_filter_table[j]);
+ else
+ req->bit_mask[i] = 0xFFFFFFFF;
+ }
+ bfa_msgq_cmd_set(&rxf->msgq_cmd, NULL, NULL,
+ sizeof(struct bfi_enet_rx_vlan_req), &req->mh);
+ bfa_msgq_cmd_post(&rxf->rx->bna->msgq, &rxf->msgq_cmd);
+}
+
+static void
+bna_bfi_vlan_strip_enable(struct bna_rxf *rxf)
+{
+ struct bfi_enet_enable_req *req = &rxf->bfi_enet_cmd.req;
+
+ bfi_msgq_mhdr_set(req->mh, BFI_MC_ENET,
+ BFI_ENET_H2I_RX_VLAN_STRIP_ENABLE_REQ, 0, rxf->rx->rid);
+ req->mh.num_entries = htons(
+ bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_enable_req)));
+ req->enable = rxf->vlan_strip_status;
+ bfa_msgq_cmd_set(&rxf->msgq_cmd, NULL, NULL,
+ sizeof(struct bfi_enet_enable_req), &req->mh);
+ bfa_msgq_cmd_post(&rxf->rx->bna->msgq, &rxf->msgq_cmd);
+}
+
+static void
+bna_bfi_rit_cfg(struct bna_rxf *rxf)
+{
+ struct bfi_enet_rit_req *req = &rxf->bfi_enet_cmd.rit_req;
+
+ bfi_msgq_mhdr_set(req->mh, BFI_MC_ENET,
+ BFI_ENET_H2I_RIT_CFG_REQ, 0, rxf->rx->rid);
+ req->mh.num_entries = htons(
+ bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_rit_req)));
+ req->size = htons(rxf->rit_size);
+ memcpy(&req->table[0], rxf->rit, rxf->rit_size);
+ bfa_msgq_cmd_set(&rxf->msgq_cmd, NULL, NULL,
+ sizeof(struct bfi_enet_rit_req), &req->mh);
+ bfa_msgq_cmd_post(&rxf->rx->bna->msgq, &rxf->msgq_cmd);
+}
+
+static void
+bna_bfi_rss_cfg(struct bna_rxf *rxf)
+{
+ struct bfi_enet_rss_cfg_req *req = &rxf->bfi_enet_cmd.rss_req;
+ int i;
+
+ bfi_msgq_mhdr_set(req->mh, BFI_MC_ENET,
+ BFI_ENET_H2I_RSS_CFG_REQ, 0, rxf->rx->rid);
+ req->mh.num_entries = htons(
+ bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_rss_cfg_req)));
+ req->cfg.type = rxf->rss_cfg.hash_type;
+ req->cfg.mask = rxf->rss_cfg.hash_mask;
+ for (i = 0; i < BFI_ENET_RSS_KEY_LEN; i++)
+ req->cfg.key[i] =
+ htonl(rxf->rss_cfg.toeplitz_hash_key[i]);
+ bfa_msgq_cmd_set(&rxf->msgq_cmd, NULL, NULL,
+ sizeof(struct bfi_enet_rss_cfg_req), &req->mh);
+ bfa_msgq_cmd_post(&rxf->rx->bna->msgq, &rxf->msgq_cmd);
+}
+
+static void
+bna_bfi_rss_enable(struct bna_rxf *rxf)
+{
+ struct bfi_enet_enable_req *req = &rxf->bfi_enet_cmd.req;
+
+ bfi_msgq_mhdr_set(req->mh, BFI_MC_ENET,
+ BFI_ENET_H2I_RSS_ENABLE_REQ, 0, rxf->rx->rid);
+ req->mh.num_entries = htons(
+ bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_enable_req)));
+ req->enable = rxf->rss_status;
+ bfa_msgq_cmd_set(&rxf->msgq_cmd, NULL, NULL,
+ sizeof(struct bfi_enet_enable_req), &req->mh);
+ bfa_msgq_cmd_post(&rxf->rx->bna->msgq, &rxf->msgq_cmd);
+}
+
+/* This function gets the multicast MAC that has already been added to CAM */
+static struct bna_mac *
+bna_rxf_mcmac_get(struct bna_rxf *rxf, u8 *mac_addr)
+{
+ struct bna_mac *mac;
+ struct list_head *qe;
+
+ list_for_each(qe, &rxf->mcast_active_q) {
+ mac = (struct bna_mac *)qe;
+ if (BNA_MAC_IS_EQUAL(&mac->addr, mac_addr))
+ return mac;
+ }
+
+ list_for_each(qe, &rxf->mcast_pending_del_q) {
+ mac = (struct bna_mac *)qe;
+ if (BNA_MAC_IS_EQUAL(&mac->addr, mac_addr))
+ return mac;
+ }
+
+ return NULL;
+}
+
+static struct bna_mcam_handle *
+bna_rxf_mchandle_get(struct bna_rxf *rxf, int handle)
+{
+ struct bna_mcam_handle *mchandle;
+ struct list_head *qe;
+
+ list_for_each(qe, &rxf->mcast_handle_q) {
+ mchandle = (struct bna_mcam_handle *)qe;
+ if (mchandle->handle == handle)
+ return mchandle;
+ }
+
+ return NULL;
+}
+
+static void
+bna_rxf_mchandle_attach(struct bna_rxf *rxf, u8 *mac_addr, int handle)
+{
+ struct bna_mac *mcmac;
+ struct bna_mcam_handle *mchandle;
+
+ mcmac = bna_rxf_mcmac_get(rxf, mac_addr);
+ mchandle = bna_rxf_mchandle_get(rxf, handle);
+ if (mchandle == NULL) {
+ mchandle = bna_mcam_mod_handle_get(&rxf->rx->bna->mcam_mod);
+ mchandle->handle = handle;
+ mchandle->refcnt = 0;
+ list_add_tail(&mchandle->qe, &rxf->mcast_handle_q);
+ }
+ mchandle->refcnt++;
+ mcmac->handle = mchandle;
+}
+
+static int
+bna_rxf_mcast_del(struct bna_rxf *rxf, struct bna_mac *mac,
+ enum bna_cleanup_type cleanup)
+{
+ struct bna_mcam_handle *mchandle;
+ int ret = 0;
+
+ mchandle = mac->handle;
+ if (mchandle == NULL)
+ return ret;
+
+ mchandle->refcnt--;
+ if (mchandle->refcnt == 0) {
+ if (cleanup == BNA_HARD_CLEANUP) {
+ bna_bfi_mcast_del_req(rxf, mchandle->handle);
+ ret = 1;
+ }
+ list_del(&mchandle->qe);
+ bfa_q_qe_init(&mchandle->qe);
+ bna_mcam_mod_handle_put(&rxf->rx->bna->mcam_mod, mchandle);
+ }
+ mac->handle = NULL;
+
+ return ret;
+}
+
+static int
+bna_rxf_mcast_cfg_apply(struct bna_rxf *rxf)
+{
+ struct bna_mac *mac = NULL;
+ struct list_head *qe;
+ int ret;
+
+ /* Delete multicast entries previousely added */
+ while (!list_empty(&rxf->mcast_pending_del_q)) {
+ bfa_q_deq(&rxf->mcast_pending_del_q, &qe);
+ bfa_q_qe_init(qe);
+ mac = (struct bna_mac *)qe;
+ ret = bna_rxf_mcast_del(rxf, mac, BNA_HARD_CLEANUP);
+ bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
+ if (ret)
+ return ret;
+ }
+
+ /* Add multicast entries */
+ if (!list_empty(&rxf->mcast_pending_add_q)) {
+ bfa_q_deq(&rxf->mcast_pending_add_q, &qe);
+ bfa_q_qe_init(qe);
+ mac = (struct bna_mac *)qe;
+ list_add_tail(&mac->qe, &rxf->mcast_active_q);
+ bna_bfi_mcast_add_req(rxf, mac);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+bna_rxf_vlan_cfg_apply(struct bna_rxf *rxf)
+{
+ u8 vlan_pending_bitmask;
+ int block_idx = 0;
+
+ if (rxf->vlan_pending_bitmask) {
+ vlan_pending_bitmask = rxf->vlan_pending_bitmask;
+ while (!(vlan_pending_bitmask & 0x1)) {
+ block_idx++;
+ vlan_pending_bitmask >>= 1;
+ }
+ rxf->vlan_pending_bitmask &= ~(1 << block_idx);
+ bna_bfi_rx_vlan_filter_set(rxf, block_idx);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+bna_rxf_mcast_cfg_reset(struct bna_rxf *rxf, enum bna_cleanup_type cleanup)
+{
+ struct list_head *qe;
+ struct bna_mac *mac;
+ int ret;
+
+ /* Throw away delete pending mcast entries */
+ while (!list_empty(&rxf->mcast_pending_del_q)) {
+ bfa_q_deq(&rxf->mcast_pending_del_q, &qe);
+ bfa_q_qe_init(qe);
+ mac = (struct bna_mac *)qe;
+ ret = bna_rxf_mcast_del(rxf, mac, cleanup);
+ bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
+ if (ret)
+ return ret;
+ }
+
+ /* Move active mcast entries to pending_add_q */
+ while (!list_empty(&rxf->mcast_active_q)) {
+ bfa_q_deq(&rxf->mcast_active_q, &qe);
+ bfa_q_qe_init(qe);
+ list_add_tail(qe, &rxf->mcast_pending_add_q);
+ mac = (struct bna_mac *)qe;
+ if (bna_rxf_mcast_del(rxf, mac, cleanup))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+bna_rxf_rss_cfg_apply(struct bna_rxf *rxf)
+{
+ if (rxf->rss_pending) {
+ if (rxf->rss_pending & BNA_RSS_F_RIT_PENDING) {
+ rxf->rss_pending &= ~BNA_RSS_F_RIT_PENDING;
+ bna_bfi_rit_cfg(rxf);
+ return 1;
+ }
+
+ if (rxf->rss_pending & BNA_RSS_F_CFG_PENDING) {
+ rxf->rss_pending &= ~BNA_RSS_F_CFG_PENDING;
+ bna_bfi_rss_cfg(rxf);
+ return 1;
+ }
+
+ if (rxf->rss_pending & BNA_RSS_F_STATUS_PENDING) {
+ rxf->rss_pending &= ~BNA_RSS_F_STATUS_PENDING;
+ bna_bfi_rss_enable(rxf);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+bna_rxf_cfg_apply(struct bna_rxf *rxf)
+{
+ if (bna_rxf_ucast_cfg_apply(rxf))
+ return 1;
+
+ if (bna_rxf_mcast_cfg_apply(rxf))
+ return 1;
+
+ if (bna_rxf_promisc_cfg_apply(rxf))
+ return 1;
+
+ if (bna_rxf_allmulti_cfg_apply(rxf))
+ return 1;
+
+ if (bna_rxf_vlan_cfg_apply(rxf))
+ return 1;
+
+ if (bna_rxf_vlan_strip_cfg_apply(rxf))
+ return 1;
+
+ if (bna_rxf_rss_cfg_apply(rxf))
+ return 1;
+
+ return 0;
+}
+
+/* Only software reset */
+static int
+bna_rxf_fltr_clear(struct bna_rxf *rxf)
+{
+ if (bna_rxf_ucast_cfg_reset(rxf, BNA_HARD_CLEANUP))
+ return 1;
+
+ if (bna_rxf_mcast_cfg_reset(rxf, BNA_HARD_CLEANUP))
+ return 1;
+
+ if (bna_rxf_promisc_cfg_reset(rxf, BNA_HARD_CLEANUP))
+ return 1;
+
+ if (bna_rxf_allmulti_cfg_reset(rxf, BNA_HARD_CLEANUP))
+ return 1;
+
+ return 0;
+}
+
+static void
+bna_rxf_cfg_reset(struct bna_rxf *rxf)
+{
+ bna_rxf_ucast_cfg_reset(rxf, BNA_SOFT_CLEANUP);
+ bna_rxf_mcast_cfg_reset(rxf, BNA_SOFT_CLEANUP);
+ bna_rxf_promisc_cfg_reset(rxf, BNA_SOFT_CLEANUP);
+ bna_rxf_allmulti_cfg_reset(rxf, BNA_SOFT_CLEANUP);
+ bna_rxf_vlan_cfg_soft_reset(rxf);
+ bna_rxf_rss_cfg_soft_reset(rxf);
+}
+
+static void
+bna_rit_init(struct bna_rxf *rxf, int rit_size)
+{
+ struct bna_rx *rx = rxf->rx;
+ struct bna_rxp *rxp;
+ struct list_head *qe;
+ int offset = 0;
+
+ rxf->rit_size = rit_size;
+ list_for_each(qe, &rx->rxp_q) {
+ rxp = (struct bna_rxp *)qe;
+ rxf->rit[offset] = rxp->cq.ccb->id;
+ offset++;
+ }
+
+}
+
+void
+bna_bfi_rxf_cfg_rsp(struct bna_rxf *rxf, struct bfi_msgq_mhdr *msghdr)
+{
+ bfa_fsm_send_event(rxf, RXF_E_FW_RESP);
+}
+
+void
+bna_bfi_rxf_mcast_add_rsp(struct bna_rxf *rxf,
+ struct bfi_msgq_mhdr *msghdr)
+{
+ struct bfi_enet_mcast_add_req *req =
+ &rxf->bfi_enet_cmd.mcast_add_req;
+ struct bfi_enet_mcast_add_rsp *rsp =
+ (struct bfi_enet_mcast_add_rsp *)msghdr;
+
+ bna_rxf_mchandle_attach(rxf, (u8 *)&req->mac_addr,
+ ntohs(rsp->handle));
+ bfa_fsm_send_event(rxf, RXF_E_FW_RESP);
+}
+
+static void
+bna_rxf_init(struct bna_rxf *rxf,
+ struct bna_rx *rx,
+ struct bna_rx_config *q_config,
+ struct bna_res_info *res_info)
+{
+ rxf->rx = rx;
+
+ INIT_LIST_HEAD(&rxf->ucast_pending_add_q);
+ INIT_LIST_HEAD(&rxf->ucast_pending_del_q);
+ rxf->ucast_pending_set = 0;
+ rxf->ucast_active_set = 0;
+ INIT_LIST_HEAD(&rxf->ucast_active_q);
+ rxf->ucast_pending_mac = NULL;
+
+ INIT_LIST_HEAD(&rxf->mcast_pending_add_q);
+ INIT_LIST_HEAD(&rxf->mcast_pending_del_q);
+ INIT_LIST_HEAD(&rxf->mcast_active_q);
+ INIT_LIST_HEAD(&rxf->mcast_handle_q);
+
+ if (q_config->paused)
+ rxf->flags |= BNA_RXF_F_PAUSED;
+
+ rxf->rit = (u8 *)
+ res_info[BNA_RX_RES_MEM_T_RIT].res_u.mem_info.mdl[0].kva;
+ bna_rit_init(rxf, q_config->num_paths);
+
+ rxf->rss_status = q_config->rss_status;
+ if (rxf->rss_status == BNA_STATUS_T_ENABLED) {
+ rxf->rss_cfg = q_config->rss_config;
+ rxf->rss_pending |= BNA_RSS_F_CFG_PENDING;
+ rxf->rss_pending |= BNA_RSS_F_RIT_PENDING;
+ rxf->rss_pending |= BNA_RSS_F_STATUS_PENDING;
+ }
+
+ rxf->vlan_filter_status = BNA_STATUS_T_DISABLED;
+ memset(rxf->vlan_filter_table, 0,
+ (sizeof(u32) * (BFI_ENET_VLAN_ID_MAX / 32)));
+ rxf->vlan_filter_table[0] |= 1; /* for pure priority tagged frames */
+ rxf->vlan_pending_bitmask = (u8)BFI_VLAN_BMASK_ALL;
+
+ rxf->vlan_strip_status = q_config->vlan_strip_status;
+
+ bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+}
+
+static void
+bna_rxf_uninit(struct bna_rxf *rxf)
+{
+ struct bna_mac *mac;
+
+ rxf->ucast_pending_set = 0;
+ rxf->ucast_active_set = 0;
+
+ while (!list_empty(&rxf->ucast_pending_add_q)) {
+ bfa_q_deq(&rxf->ucast_pending_add_q, &mac);
+ bfa_q_qe_init(&mac->qe);
+ bna_ucam_mod_mac_put(&rxf->rx->bna->ucam_mod, mac);
+ }
+
+ if (rxf->ucast_pending_mac) {
+ bfa_q_qe_init(&rxf->ucast_pending_mac->qe);
+ bna_ucam_mod_mac_put(&rxf->rx->bna->ucam_mod,
+ rxf->ucast_pending_mac);
+ rxf->ucast_pending_mac = NULL;
+ }
+
+ while (!list_empty(&rxf->mcast_pending_add_q)) {
+ bfa_q_deq(&rxf->mcast_pending_add_q, &mac);
+ bfa_q_qe_init(&mac->qe);
+ bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
+ }
+
+ rxf->rxmode_pending = 0;
+ rxf->rxmode_pending_bitmask = 0;
+ if (rxf->rx->bna->promisc_rid == rxf->rx->rid)
+ rxf->rx->bna->promisc_rid = BFI_INVALID_RID;
+ if (rxf->rx->bna->default_mode_rid == rxf->rx->rid)
+ rxf->rx->bna->default_mode_rid = BFI_INVALID_RID;
+
+ rxf->rss_pending = 0;
+ rxf->vlan_strip_pending = false;
+
+ rxf->flags = 0;
+
+ rxf->rx = NULL;
+}
+
+static void
+bna_rx_cb_rxf_started(struct bna_rx *rx)
+{
+ bfa_fsm_send_event(rx, RX_E_RXF_STARTED);
+}
+
+static void
+bna_rxf_start(struct bna_rxf *rxf)
+{
+ rxf->start_cbfn = bna_rx_cb_rxf_started;
+ rxf->start_cbarg = rxf->rx;
+ bfa_fsm_send_event(rxf, RXF_E_START);
+}
+
+static void
+bna_rx_cb_rxf_stopped(struct bna_rx *rx)
+{
+ bfa_fsm_send_event(rx, RX_E_RXF_STOPPED);
+}
+
+static void
+bna_rxf_stop(struct bna_rxf *rxf)
+{
+ rxf->stop_cbfn = bna_rx_cb_rxf_stopped;
+ rxf->stop_cbarg = rxf->rx;
+ bfa_fsm_send_event(rxf, RXF_E_STOP);
+}
+
+static void
+bna_rxf_fail(struct bna_rxf *rxf)
+{
+ bfa_fsm_send_event(rxf, RXF_E_FAIL);
+}
+
+enum bna_cb_status
+bna_rx_ucast_set(struct bna_rx *rx, u8 *ucmac,
+ void (*cbfn)(struct bnad *, struct bna_rx *))
+{
+ struct bna_rxf *rxf = &rx->rxf;
+
+ if (rxf->ucast_pending_mac == NULL) {
+ rxf->ucast_pending_mac =
+ bna_ucam_mod_mac_get(&rxf->rx->bna->ucam_mod);
+ if (rxf->ucast_pending_mac == NULL)
+ return BNA_CB_UCAST_CAM_FULL;
+ bfa_q_qe_init(&rxf->ucast_pending_mac->qe);
+ }
+
+ memcpy(rxf->ucast_pending_mac->addr, ucmac, ETH_ALEN);
+ rxf->ucast_pending_set = 1;
+ rxf->cam_fltr_cbfn = cbfn;
+ rxf->cam_fltr_cbarg = rx->bna->bnad;
+
+ bfa_fsm_send_event(rxf, RXF_E_CONFIG);
+
+ return BNA_CB_SUCCESS;
+}
+
+enum bna_cb_status
+bna_rx_mcast_add(struct bna_rx *rx, u8 *addr,
+ void (*cbfn)(struct bnad *, struct bna_rx *))
+{
+ struct bna_rxf *rxf = &rx->rxf;
+ struct bna_mac *mac;
+
+ /* Check if already added or pending addition */
+ if (bna_mac_find(&rxf->mcast_active_q, addr) ||
+ bna_mac_find(&rxf->mcast_pending_add_q, addr)) {
+ if (cbfn)
+ cbfn(rx->bna->bnad, rx);
+ return BNA_CB_SUCCESS;
+ }
+
+ mac = bna_mcam_mod_mac_get(&rxf->rx->bna->mcam_mod);
+ if (mac == NULL)
+ return BNA_CB_MCAST_LIST_FULL;
+ bfa_q_qe_init(&mac->qe);
+ memcpy(mac->addr, addr, ETH_ALEN);
+ list_add_tail(&mac->qe, &rxf->mcast_pending_add_q);
+
+ rxf->cam_fltr_cbfn = cbfn;
+ rxf->cam_fltr_cbarg = rx->bna->bnad;
+
+ bfa_fsm_send_event(rxf, RXF_E_CONFIG);
+
+ return BNA_CB_SUCCESS;
+}
+
+enum bna_cb_status
+bna_rx_mcast_listset(struct bna_rx *rx, int count, u8 *mclist,
+ void (*cbfn)(struct bnad *, struct bna_rx *))
+{
+ struct bna_rxf *rxf = &rx->rxf;
+ struct list_head list_head;
+ struct list_head *qe;
+ u8 *mcaddr;
+ struct bna_mac *mac;
+ int i;
+
+ /* Allocate nodes */
+ INIT_LIST_HEAD(&list_head);
+ for (i = 0, mcaddr = mclist; i < count; i++) {
+ mac = bna_mcam_mod_mac_get(&rxf->rx->bna->mcam_mod);
+ if (mac == NULL)
+ goto err_return;
+ bfa_q_qe_init(&mac->qe);
+ memcpy(mac->addr, mcaddr, ETH_ALEN);
+ list_add_tail(&mac->qe, &list_head);
+
+ mcaddr += ETH_ALEN;
+ }
+
+ /* Purge the pending_add_q */
+ while (!list_empty(&rxf->mcast_pending_add_q)) {
+ bfa_q_deq(&rxf->mcast_pending_add_q, &qe);
+ bfa_q_qe_init(qe);
+ mac = (struct bna_mac *)qe;
+ bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
+ }
+
+ /* Schedule active_q entries for deletion */
+ while (!list_empty(&rxf->mcast_active_q)) {
+ bfa_q_deq(&rxf->mcast_active_q, &qe);
+ mac = (struct bna_mac *)qe;
+ bfa_q_qe_init(&mac->qe);
+ list_add_tail(&mac->qe, &rxf->mcast_pending_del_q);
+ }
+
+ /* Add the new entries */
+ while (!list_empty(&list_head)) {
+ bfa_q_deq(&list_head, &qe);
+ mac = (struct bna_mac *)qe;
+ bfa_q_qe_init(&mac->qe);
+ list_add_tail(&mac->qe, &rxf->mcast_pending_add_q);
+ }
+
+ rxf->cam_fltr_cbfn = cbfn;
+ rxf->cam_fltr_cbarg = rx->bna->bnad;
+ bfa_fsm_send_event(rxf, RXF_E_CONFIG);
+
+ return BNA_CB_SUCCESS;
+
+err_return:
+ while (!list_empty(&list_head)) {
+ bfa_q_deq(&list_head, &qe);
+ mac = (struct bna_mac *)qe;
+ bfa_q_qe_init(&mac->qe);
+ bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
+ }
+
+ return BNA_CB_MCAST_LIST_FULL;
+}
+
+void
+bna_rx_vlan_add(struct bna_rx *rx, int vlan_id)
+{
+ struct bna_rxf *rxf = &rx->rxf;
+ int index = (vlan_id >> BFI_VLAN_WORD_SHIFT);
+ int bit = (1 << (vlan_id & BFI_VLAN_WORD_MASK));
+ int group_id = (vlan_id >> BFI_VLAN_BLOCK_SHIFT);
+
+ rxf->vlan_filter_table[index] |= bit;
+ if (rxf->vlan_filter_status == BNA_STATUS_T_ENABLED) {
+ rxf->vlan_pending_bitmask |= (1 << group_id);
+ bfa_fsm_send_event(rxf, RXF_E_CONFIG);
+ }
+}
+
+void
+bna_rx_vlan_del(struct bna_rx *rx, int vlan_id)
+{
+ struct bna_rxf *rxf = &rx->rxf;
+ int index = (vlan_id >> BFI_VLAN_WORD_SHIFT);
+ int bit = (1 << (vlan_id & BFI_VLAN_WORD_MASK));
+ int group_id = (vlan_id >> BFI_VLAN_BLOCK_SHIFT);
+
+ rxf->vlan_filter_table[index] &= ~bit;
+ if (rxf->vlan_filter_status == BNA_STATUS_T_ENABLED) {
+ rxf->vlan_pending_bitmask |= (1 << group_id);
+ bfa_fsm_send_event(rxf, RXF_E_CONFIG);
+ }
+}
+
+static int
+bna_rxf_ucast_cfg_apply(struct bna_rxf *rxf)
+{
+ struct bna_mac *mac = NULL;
+ struct list_head *qe;
+
+ /* Delete MAC addresses previousely added */
+ if (!list_empty(&rxf->ucast_pending_del_q)) {
+ bfa_q_deq(&rxf->ucast_pending_del_q, &qe);
+ bfa_q_qe_init(qe);
+ mac = (struct bna_mac *)qe;
+ bna_bfi_ucast_req(rxf, mac, BFI_ENET_H2I_MAC_UCAST_DEL_REQ);
+ bna_ucam_mod_mac_put(&rxf->rx->bna->ucam_mod, mac);
+ return 1;
+ }
+
+ /* Set default unicast MAC */
+ if (rxf->ucast_pending_set) {
+ rxf->ucast_pending_set = 0;
+ memcpy(rxf->ucast_active_mac.addr,
+ rxf->ucast_pending_mac->addr, ETH_ALEN);
+ rxf->ucast_active_set = 1;
+ bna_bfi_ucast_req(rxf, &rxf->ucast_active_mac,
+ BFI_ENET_H2I_MAC_UCAST_SET_REQ);
+ return 1;
+ }
+
+ /* Add additional MAC entries */
+ if (!list_empty(&rxf->ucast_pending_add_q)) {
+ bfa_q_deq(&rxf->ucast_pending_add_q, &qe);
+ bfa_q_qe_init(qe);
+ mac = (struct bna_mac *)qe;
+ list_add_tail(&mac->qe, &rxf->ucast_active_q);
+ bna_bfi_ucast_req(rxf, mac, BFI_ENET_H2I_MAC_UCAST_ADD_REQ);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+bna_rxf_ucast_cfg_reset(struct bna_rxf *rxf, enum bna_cleanup_type cleanup)
+{
+ struct list_head *qe;
+ struct bna_mac *mac;
+
+ /* Throw away delete pending ucast entries */
+ while (!list_empty(&rxf->ucast_pending_del_q)) {
+ bfa_q_deq(&rxf->ucast_pending_del_q, &qe);
+ bfa_q_qe_init(qe);
+ mac = (struct bna_mac *)qe;
+ if (cleanup == BNA_SOFT_CLEANUP)
+ bna_ucam_mod_mac_put(&rxf->rx->bna->ucam_mod, mac);
+ else {
+ bna_bfi_ucast_req(rxf, mac,
+ BFI_ENET_H2I_MAC_UCAST_DEL_REQ);
+ bna_ucam_mod_mac_put(&rxf->rx->bna->ucam_mod, mac);
+ return 1;
+ }
+ }
+
+ /* Move active ucast entries to pending_add_q */
+ while (!list_empty(&rxf->ucast_active_q)) {
+ bfa_q_deq(&rxf->ucast_active_q, &qe);
+ bfa_q_qe_init(qe);
+ list_add_tail(qe, &rxf->ucast_pending_add_q);
+ if (cleanup == BNA_HARD_CLEANUP) {
+ mac = (struct bna_mac *)qe;
+ bna_bfi_ucast_req(rxf, mac,
+ BFI_ENET_H2I_MAC_UCAST_DEL_REQ);
+ return 1;
+ }
+ }
+
+ if (rxf->ucast_active_set) {
+ rxf->ucast_pending_set = 1;
+ rxf->ucast_active_set = 0;
+ if (cleanup == BNA_HARD_CLEANUP) {
+ bna_bfi_ucast_req(rxf, &rxf->ucast_active_mac,
+ BFI_ENET_H2I_MAC_UCAST_CLR_REQ);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+bna_rxf_promisc_cfg_apply(struct bna_rxf *rxf)
+{
+ struct bna *bna = rxf->rx->bna;
+
+ /* Enable/disable promiscuous mode */
+ if (is_promisc_enable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask)) {
+ /* move promisc configuration from pending -> active */
+ promisc_inactive(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ rxf->rxmode_active |= BNA_RXMODE_PROMISC;
+ bna_bfi_rx_promisc_req(rxf, BNA_STATUS_T_ENABLED);
+ return 1;
+ } else if (is_promisc_disable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask)) {
+ /* move promisc configuration from pending -> active */
+ promisc_inactive(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ rxf->rxmode_active &= ~BNA_RXMODE_PROMISC;
+ bna->promisc_rid = BFI_INVALID_RID;
+ bna_bfi_rx_promisc_req(rxf, BNA_STATUS_T_DISABLED);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+bna_rxf_promisc_cfg_reset(struct bna_rxf *rxf, enum bna_cleanup_type cleanup)
+{
+ struct bna *bna = rxf->rx->bna;
+
+ /* Clear pending promisc mode disable */
+ if (is_promisc_disable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask)) {
+ promisc_inactive(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ rxf->rxmode_active &= ~BNA_RXMODE_PROMISC;
+ bna->promisc_rid = BFI_INVALID_RID;
+ if (cleanup == BNA_HARD_CLEANUP) {
+ bna_bfi_rx_promisc_req(rxf, BNA_STATUS_T_DISABLED);
+ return 1;
+ }
+ }
+
+ /* Move promisc mode config from active -> pending */
+ if (rxf->rxmode_active & BNA_RXMODE_PROMISC) {
+ promisc_enable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ rxf->rxmode_active &= ~BNA_RXMODE_PROMISC;
+ if (cleanup == BNA_HARD_CLEANUP) {
+ bna_bfi_rx_promisc_req(rxf, BNA_STATUS_T_DISABLED);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+bna_rxf_allmulti_cfg_apply(struct bna_rxf *rxf)
+{
+ /* Enable/disable allmulti mode */
+ if (is_allmulti_enable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask)) {
+ /* move allmulti configuration from pending -> active */
+ allmulti_inactive(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ rxf->rxmode_active |= BNA_RXMODE_ALLMULTI;
+ bna_bfi_mcast_filter_req(rxf, BNA_STATUS_T_DISABLED);
+ return 1;
+ } else if (is_allmulti_disable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask)) {
+ /* move allmulti configuration from pending -> active */
+ allmulti_inactive(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ rxf->rxmode_active &= ~BNA_RXMODE_ALLMULTI;
+ bna_bfi_mcast_filter_req(rxf, BNA_STATUS_T_ENABLED);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+bna_rxf_allmulti_cfg_reset(struct bna_rxf *rxf, enum bna_cleanup_type cleanup)
+{
+ /* Clear pending allmulti mode disable */
+ if (is_allmulti_disable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask)) {
+ allmulti_inactive(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ rxf->rxmode_active &= ~BNA_RXMODE_ALLMULTI;
+ if (cleanup == BNA_HARD_CLEANUP) {
+ bna_bfi_mcast_filter_req(rxf, BNA_STATUS_T_ENABLED);
+ return 1;
+ }
+ }
+
+ /* Move allmulti mode config from active -> pending */
+ if (rxf->rxmode_active & BNA_RXMODE_ALLMULTI) {
+ allmulti_enable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ rxf->rxmode_active &= ~BNA_RXMODE_ALLMULTI;
+ if (cleanup == BNA_HARD_CLEANUP) {
+ bna_bfi_mcast_filter_req(rxf, BNA_STATUS_T_ENABLED);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+bna_rxf_promisc_enable(struct bna_rxf *rxf)
+{
+ struct bna *bna = rxf->rx->bna;
+ int ret = 0;
+
+ if (is_promisc_enable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask) ||
+ (rxf->rxmode_active & BNA_RXMODE_PROMISC)) {
+ /* Do nothing if pending enable or already enabled */
+ } else if (is_promisc_disable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask)) {
+ /* Turn off pending disable command */
+ promisc_inactive(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ } else {
+ /* Schedule enable */
+ promisc_enable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ bna->promisc_rid = rxf->rx->rid;
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static int
+bna_rxf_promisc_disable(struct bna_rxf *rxf)
+{
+ struct bna *bna = rxf->rx->bna;
+ int ret = 0;
+
+ if (is_promisc_disable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask) ||
+ (!(rxf->rxmode_active & BNA_RXMODE_PROMISC))) {
+ /* Do nothing if pending disable or already disabled */
+ } else if (is_promisc_enable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask)) {
+ /* Turn off pending enable command */
+ promisc_inactive(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ bna->promisc_rid = BFI_INVALID_RID;
+ } else if (rxf->rxmode_active & BNA_RXMODE_PROMISC) {
+ /* Schedule disable */
+ promisc_disable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static int
+bna_rxf_allmulti_enable(struct bna_rxf *rxf)
+{
+ int ret = 0;
+
+ if (is_allmulti_enable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask) ||
+ (rxf->rxmode_active & BNA_RXMODE_ALLMULTI)) {
+ /* Do nothing if pending enable or already enabled */
+ } else if (is_allmulti_disable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask)) {
+ /* Turn off pending disable command */
+ allmulti_inactive(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ } else {
+ /* Schedule enable */
+ allmulti_enable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static int
+bna_rxf_allmulti_disable(struct bna_rxf *rxf)
+{
+ int ret = 0;
+
+ if (is_allmulti_disable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask) ||
+ (!(rxf->rxmode_active & BNA_RXMODE_ALLMULTI))) {
+ /* Do nothing if pending disable or already disabled */
+ } else if (is_allmulti_enable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask)) {
+ /* Turn off pending enable command */
+ allmulti_inactive(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ } else if (rxf->rxmode_active & BNA_RXMODE_ALLMULTI) {
+ /* Schedule disable */
+ allmulti_disable(rxf->rxmode_pending,
+ rxf->rxmode_pending_bitmask);
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static int
+bna_rxf_vlan_strip_cfg_apply(struct bna_rxf *rxf)
+{
+ if (rxf->vlan_strip_pending) {
+ rxf->vlan_strip_pending = false;
+ bna_bfi_vlan_strip_enable(rxf);
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * RX
+ */
+
+#define BNA_GET_RXQS(qcfg) (((qcfg)->rxp_type == BNA_RXP_SINGLE) ? \
+ (qcfg)->num_paths : ((qcfg)->num_paths * 2))
+
+#define SIZE_TO_PAGES(size) (((size) >> PAGE_SHIFT) + ((((size) &\
+ (PAGE_SIZE - 1)) + (PAGE_SIZE - 1)) >> PAGE_SHIFT))
+
+#define call_rx_stop_cbfn(rx) \
+do { \
+ if ((rx)->stop_cbfn) { \
+ void (*cbfn)(void *, struct bna_rx *); \
+ void *cbarg; \
+ cbfn = (rx)->stop_cbfn; \
+ cbarg = (rx)->stop_cbarg; \
+ (rx)->stop_cbfn = NULL; \
+ (rx)->stop_cbarg = NULL; \
+ cbfn(cbarg, rx); \
+ } \
+} while (0)
+
+#define call_rx_stall_cbfn(rx) \
+do { \
+ if ((rx)->rx_stall_cbfn) \
+ (rx)->rx_stall_cbfn((rx)->bna->bnad, (rx)); \
+} while (0)
+
+#define bfi_enet_datapath_q_init(bfi_q, bna_qpt) \
+do { \
+ struct bna_dma_addr cur_q_addr = \
+ *((struct bna_dma_addr *)((bna_qpt)->kv_qpt_ptr)); \
+ (bfi_q)->pg_tbl.a32.addr_lo = (bna_qpt)->hw_qpt_ptr.lsb; \
+ (bfi_q)->pg_tbl.a32.addr_hi = (bna_qpt)->hw_qpt_ptr.msb; \
+ (bfi_q)->first_entry.a32.addr_lo = cur_q_addr.lsb; \
+ (bfi_q)->first_entry.a32.addr_hi = cur_q_addr.msb; \
+ (bfi_q)->pages = htons((u16)(bna_qpt)->page_count); \
+ (bfi_q)->page_sz = htons((u16)(bna_qpt)->page_size);\
+} while (0)
+
+static void bna_bfi_rx_enet_start(struct bna_rx *rx);
+static void bna_rx_enet_stop(struct bna_rx *rx);
+static void bna_rx_mod_cb_rx_stopped(void *arg, struct bna_rx *rx);
+
+bfa_fsm_state_decl(bna_rx, stopped,
+ struct bna_rx, enum bna_rx_event);
+bfa_fsm_state_decl(bna_rx, start_wait,
+ struct bna_rx, enum bna_rx_event);
+bfa_fsm_state_decl(bna_rx, rxf_start_wait,
+ struct bna_rx, enum bna_rx_event);
+bfa_fsm_state_decl(bna_rx, started,
+ struct bna_rx, enum bna_rx_event);
+bfa_fsm_state_decl(bna_rx, rxf_stop_wait,
+ struct bna_rx, enum bna_rx_event);
+bfa_fsm_state_decl(bna_rx, stop_wait,
+ struct bna_rx, enum bna_rx_event);
+bfa_fsm_state_decl(bna_rx, cleanup_wait,
+ struct bna_rx, enum bna_rx_event);
+bfa_fsm_state_decl(bna_rx, failed,
+ struct bna_rx, enum bna_rx_event);
+bfa_fsm_state_decl(bna_rx, quiesce_wait,
+ struct bna_rx, enum bna_rx_event);
+
+static void bna_rx_sm_stopped_entry(struct bna_rx *rx)
+{
+ call_rx_stop_cbfn(rx);
+}
+
+static void bna_rx_sm_stopped(struct bna_rx *rx,
+ enum bna_rx_event event)
+{
+ switch (event) {
+ case RX_E_START:
+ bfa_fsm_set_state(rx, bna_rx_sm_start_wait);
+ break;
+
+ case RX_E_STOP:
+ call_rx_stop_cbfn(rx);
+ break;
+
+ case RX_E_FAIL:
+ /* no-op */
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ break;
+ }
+}
+
+static void bna_rx_sm_start_wait_entry(struct bna_rx *rx)
+{
+ bna_bfi_rx_enet_start(rx);
+}
+
+void
+bna_rx_sm_stop_wait_entry(struct bna_rx *rx)
+{
+}
+
+static void
+bna_rx_sm_stop_wait(struct bna_rx *rx, enum bna_rx_event event)
+{
+ switch (event) {
+ case RX_E_FAIL:
+ case RX_E_STOPPED:
+ bfa_fsm_set_state(rx, bna_rx_sm_cleanup_wait);
+ rx->rx_cleanup_cbfn(rx->bna->bnad, rx);
+ break;
+
+ case RX_E_STARTED:
+ bna_rx_enet_stop(rx);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ break;
+ }
+}
+
+static void bna_rx_sm_start_wait(struct bna_rx *rx,
+ enum bna_rx_event event)
+{
+ switch (event) {
+ case RX_E_STOP:
+ bfa_fsm_set_state(rx, bna_rx_sm_stop_wait);
+ break;
+
+ case RX_E_FAIL:
+ bfa_fsm_set_state(rx, bna_rx_sm_stopped);
+ break;
+
+ case RX_E_STARTED:
+ bfa_fsm_set_state(rx, bna_rx_sm_rxf_start_wait);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ break;
+ }
+}
+
+static void bna_rx_sm_rxf_start_wait_entry(struct bna_rx *rx)
+{
+ rx->rx_post_cbfn(rx->bna->bnad, rx);
+ bna_rxf_start(&rx->rxf);
+}
+
+void
+bna_rx_sm_rxf_stop_wait_entry(struct bna_rx *rx)
+{
+}
+
+static void
+bna_rx_sm_rxf_stop_wait(struct bna_rx *rx, enum bna_rx_event event)
+{
+ switch (event) {
+ case RX_E_FAIL:
+ bfa_fsm_set_state(rx, bna_rx_sm_cleanup_wait);
+ bna_rxf_fail(&rx->rxf);
+ call_rx_stall_cbfn(rx);
+ rx->rx_cleanup_cbfn(rx->bna->bnad, rx);
+ break;
+
+ case RX_E_RXF_STARTED:
+ bna_rxf_stop(&rx->rxf);
+ break;
+
+ case RX_E_RXF_STOPPED:
+ bfa_fsm_set_state(rx, bna_rx_sm_stop_wait);
+ call_rx_stall_cbfn(rx);
+ bna_rx_enet_stop(rx);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ break;
+ }
+
+}
+
+void
+bna_rx_sm_started_entry(struct bna_rx *rx)
+{
+ struct bna_rxp *rxp;
+ struct list_head *qe_rxp;
+ int is_regular = (rx->type == BNA_RX_T_REGULAR);
+
+ /* Start IB */
+ list_for_each(qe_rxp, &rx->rxp_q) {
+ rxp = (struct bna_rxp *)qe_rxp;
+ bna_ib_start(rx->bna, &rxp->cq.ib, is_regular);
+ }
+
+ bna_ethport_cb_rx_started(&rx->bna->ethport);
+}
+
+static void
+bna_rx_sm_started(struct bna_rx *rx, enum bna_rx_event event)
+{
+ switch (event) {
+ case RX_E_STOP:
+ bfa_fsm_set_state(rx, bna_rx_sm_rxf_stop_wait);
+ bna_ethport_cb_rx_stopped(&rx->bna->ethport);
+ bna_rxf_stop(&rx->rxf);
+ break;
+
+ case RX_E_FAIL:
+ bfa_fsm_set_state(rx, bna_rx_sm_failed);
+ bna_ethport_cb_rx_stopped(&rx->bna->ethport);
+ bna_rxf_fail(&rx->rxf);
+ call_rx_stall_cbfn(rx);
+ rx->rx_cleanup_cbfn(rx->bna->bnad, rx);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ break;
+ }
+}
+
+static void bna_rx_sm_rxf_start_wait(struct bna_rx *rx,
+ enum bna_rx_event event)
+{
+ switch (event) {
+ case RX_E_STOP:
+ bfa_fsm_set_state(rx, bna_rx_sm_rxf_stop_wait);
+ break;
+
+ case RX_E_FAIL:
+ bfa_fsm_set_state(rx, bna_rx_sm_failed);
+ bna_rxf_fail(&rx->rxf);
+ call_rx_stall_cbfn(rx);
+ rx->rx_cleanup_cbfn(rx->bna->bnad, rx);
+ break;
+
+ case RX_E_RXF_STARTED:
+ bfa_fsm_set_state(rx, bna_rx_sm_started);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ break;
+ }
+}
+
+void
+bna_rx_sm_cleanup_wait_entry(struct bna_rx *rx)
+{
+}
+
+void
+bna_rx_sm_cleanup_wait(struct bna_rx *rx, enum bna_rx_event event)
+{
+ switch (event) {
+ case RX_E_FAIL:
+ case RX_E_RXF_STOPPED:
+ /* No-op */
+ break;
+
+ case RX_E_CLEANUP_DONE:
+ bfa_fsm_set_state(rx, bna_rx_sm_stopped);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ break;
+ }
+}
+
+static void
+bna_rx_sm_failed_entry(struct bna_rx *rx)
+{
+}
+
+static void
+bna_rx_sm_failed(struct bna_rx *rx, enum bna_rx_event event)
+{
+ switch (event) {
+ case RX_E_START:
+ bfa_fsm_set_state(rx, bna_rx_sm_quiesce_wait);
+ break;
+
+ case RX_E_STOP:
+ bfa_fsm_set_state(rx, bna_rx_sm_cleanup_wait);
+ break;
+
+ case RX_E_FAIL:
+ case RX_E_RXF_STARTED:
+ case RX_E_RXF_STOPPED:
+ /* No-op */
+ break;
+
+ case RX_E_CLEANUP_DONE:
+ bfa_fsm_set_state(rx, bna_rx_sm_stopped);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ break;
+} }
+
+static void
+bna_rx_sm_quiesce_wait_entry(struct bna_rx *rx)
+{
+}
+
+static void
+bna_rx_sm_quiesce_wait(struct bna_rx *rx, enum bna_rx_event event)
+{
+ switch (event) {
+ case RX_E_STOP:
+ bfa_fsm_set_state(rx, bna_rx_sm_cleanup_wait);
+ break;
+
+ case RX_E_FAIL:
+ bfa_fsm_set_state(rx, bna_rx_sm_failed);
+ break;
+
+ case RX_E_CLEANUP_DONE:
+ bfa_fsm_set_state(rx, bna_rx_sm_start_wait);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ break;
+ }
+}
+
+static void
+bna_bfi_rx_enet_start(struct bna_rx *rx)
+{
+ struct bfi_enet_rx_cfg_req *cfg_req = &rx->bfi_enet_cmd.cfg_req;
+ struct bna_rxp *rxp = NULL;
+ struct bna_rxq *q0 = NULL, *q1 = NULL;
+ struct list_head *rxp_qe;
+ int i;
+
+ bfi_msgq_mhdr_set(cfg_req->mh, BFI_MC_ENET,
+ BFI_ENET_H2I_RX_CFG_SET_REQ, 0, rx->rid);
+ cfg_req->mh.num_entries = htons(
+ bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_rx_cfg_req)));
+
+ cfg_req->num_queue_sets = rx->num_paths;
+ for (i = 0, rxp_qe = bfa_q_first(&rx->rxp_q);
+ i < rx->num_paths;
+ i++, rxp_qe = bfa_q_next(rxp_qe)) {
+ rxp = (struct bna_rxp *)rxp_qe;
+
+ GET_RXQS(rxp, q0, q1);
+ switch (rxp->type) {
+ case BNA_RXP_SLR:
+ case BNA_RXP_HDS:
+ /* Small RxQ */
+ bfi_enet_datapath_q_init(&cfg_req->q_cfg[i].qs.q,
+ &q1->qpt);
+ cfg_req->q_cfg[i].qs.rx_buffer_size =
+ htons((u16)q1->buffer_size);
+ /* Fall through */
+
+ case BNA_RXP_SINGLE:
+ /* Large/Single RxQ */
+ bfi_enet_datapath_q_init(&cfg_req->q_cfg[i].ql.q,
+ &q0->qpt);
+ q0->buffer_size =
+ bna_enet_mtu_get(&rx->bna->enet);
+ cfg_req->q_cfg[i].ql.rx_buffer_size =
+ htons((u16)q0->buffer_size);
+ break;
+
+ default:
+ BUG_ON(1);
+ }
+
+ bfi_enet_datapath_q_init(&cfg_req->q_cfg[i].cq.q,
+ &rxp->cq.qpt);
+
+ cfg_req->q_cfg[i].ib.index_addr.a32.addr_lo =
+ rxp->cq.ib.ib_seg_host_addr.lsb;
+ cfg_req->q_cfg[i].ib.index_addr.a32.addr_hi =
+ rxp->cq.ib.ib_seg_host_addr.msb;
+ cfg_req->q_cfg[i].ib.intr.msix_index =
+ htons((u16)rxp->cq.ib.intr_vector);
+ }
+
+ cfg_req->ib_cfg.int_pkt_dma = BNA_STATUS_T_DISABLED;
+ cfg_req->ib_cfg.int_enabled = BNA_STATUS_T_ENABLED;
+ cfg_req->ib_cfg.int_pkt_enabled = BNA_STATUS_T_DISABLED;
+ cfg_req->ib_cfg.continuous_coalescing = BNA_STATUS_T_DISABLED;
+ cfg_req->ib_cfg.msix = (rxp->cq.ib.intr_type == BNA_INTR_T_MSIX)
+ ? BNA_STATUS_T_ENABLED :
+ BNA_STATUS_T_DISABLED;
+ cfg_req->ib_cfg.coalescing_timeout =
+ htonl((u32)rxp->cq.ib.coalescing_timeo);
+ cfg_req->ib_cfg.inter_pkt_timeout =
+ htonl((u32)rxp->cq.ib.interpkt_timeo);
+ cfg_req->ib_cfg.inter_pkt_count = (u8)rxp->cq.ib.interpkt_count;
+
+ switch (rxp->type) {
+ case BNA_RXP_SLR:
+ cfg_req->rx_cfg.rxq_type = BFI_ENET_RXQ_LARGE_SMALL;
+ break;
+
+ case BNA_RXP_HDS:
+ cfg_req->rx_cfg.rxq_type = BFI_ENET_RXQ_HDS;
+ cfg_req->rx_cfg.hds.type = rx->hds_cfg.hdr_type;
+ cfg_req->rx_cfg.hds.force_offset = rx->hds_cfg.forced_offset;
+ cfg_req->rx_cfg.hds.max_header_size = rx->hds_cfg.forced_offset;
+ break;
+
+ case BNA_RXP_SINGLE:
+ cfg_req->rx_cfg.rxq_type = BFI_ENET_RXQ_SINGLE;
+ break;
+
+ default:
+ BUG_ON(1);
+ }
+ cfg_req->rx_cfg.strip_vlan = rx->rxf.vlan_strip_status;
+
+ bfa_msgq_cmd_set(&rx->msgq_cmd, NULL, NULL,
+ sizeof(struct bfi_enet_rx_cfg_req), &cfg_req->mh);
+ bfa_msgq_cmd_post(&rx->bna->msgq, &rx->msgq_cmd);
+}
+
+static void
+bna_bfi_rx_enet_stop(struct bna_rx *rx)
+{
+ struct bfi_enet_req *req = &rx->bfi_enet_cmd.req;
+
+ bfi_msgq_mhdr_set(req->mh, BFI_MC_ENET,
+ BFI_ENET_H2I_RX_CFG_CLR_REQ, 0, rx->rid);
+ req->mh.num_entries = htons(
+ bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_req)));
+ bfa_msgq_cmd_set(&rx->msgq_cmd, NULL, NULL, sizeof(struct bfi_enet_req),
+ &req->mh);
+ bfa_msgq_cmd_post(&rx->bna->msgq, &rx->msgq_cmd);
+}
+
+static void
+bna_rx_enet_stop(struct bna_rx *rx)
+{
+ struct bna_rxp *rxp;
+ struct list_head *qe_rxp;
+
+ /* Stop IB */
+ list_for_each(qe_rxp, &rx->rxp_q) {
+ rxp = (struct bna_rxp *)qe_rxp;
+ bna_ib_stop(rx->bna, &rxp->cq.ib);
+ }
+
+ bna_bfi_rx_enet_stop(rx);
+}
+
+static int
+bna_rx_res_check(struct bna_rx_mod *rx_mod, struct bna_rx_config *rx_cfg)
+{
+ if ((rx_mod->rx_free_count == 0) ||
+ (rx_mod->rxp_free_count == 0) ||
+ (rx_mod->rxq_free_count == 0))
+ return 0;
+
+ if (rx_cfg->rxp_type == BNA_RXP_SINGLE) {
+ if ((rx_mod->rxp_free_count < rx_cfg->num_paths) ||
+ (rx_mod->rxq_free_count < rx_cfg->num_paths))
+ return 0;
+ } else {
+ if ((rx_mod->rxp_free_count < rx_cfg->num_paths) ||
+ (rx_mod->rxq_free_count < (2 * rx_cfg->num_paths)))
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct bna_rxq *
+bna_rxq_get(struct bna_rx_mod *rx_mod)
+{
+ struct bna_rxq *rxq = NULL;
+ struct list_head *qe = NULL;
+
+ bfa_q_deq(&rx_mod->rxq_free_q, &qe);
+ rx_mod->rxq_free_count--;
+ rxq = (struct bna_rxq *)qe;
+ bfa_q_qe_init(&rxq->qe);
+
+ return rxq;
+}
+
+static void
+bna_rxq_put(struct bna_rx_mod *rx_mod, struct bna_rxq *rxq)
+{
+ bfa_q_qe_init(&rxq->qe);
+ list_add_tail(&rxq->qe, &rx_mod->rxq_free_q);
+ rx_mod->rxq_free_count++;
+}
+
+static struct bna_rxp *
+bna_rxp_get(struct bna_rx_mod *rx_mod)
+{
+ struct list_head *qe = NULL;
+ struct bna_rxp *rxp = NULL;
+
+ bfa_q_deq(&rx_mod->rxp_free_q, &qe);
+ rx_mod->rxp_free_count--;
+ rxp = (struct bna_rxp *)qe;
+ bfa_q_qe_init(&rxp->qe);
+
+ return rxp;
+}
+
+static void
+bna_rxp_put(struct bna_rx_mod *rx_mod, struct bna_rxp *rxp)
+{
+ bfa_q_qe_init(&rxp->qe);
+ list_add_tail(&rxp->qe, &rx_mod->rxp_free_q);
+ rx_mod->rxp_free_count++;
+}
+
+static struct bna_rx *
+bna_rx_get(struct bna_rx_mod *rx_mod, enum bna_rx_type type)
+{
+ struct list_head *qe = NULL;
+ struct bna_rx *rx = NULL;
+
+ if (type == BNA_RX_T_REGULAR) {
+ bfa_q_deq(&rx_mod->rx_free_q, &qe);
+ } else
+ bfa_q_deq_tail(&rx_mod->rx_free_q, &qe);
+
+ rx_mod->rx_free_count--;
+ rx = (struct bna_rx *)qe;
+ bfa_q_qe_init(&rx->qe);
+ list_add_tail(&rx->qe, &rx_mod->rx_active_q);
+ rx->type = type;
+
+ return rx;
+}
+
+static void
+bna_rx_put(struct bna_rx_mod *rx_mod, struct bna_rx *rx)
+{
+ struct list_head *prev_qe = NULL;
+ struct list_head *qe;
+
+ bfa_q_qe_init(&rx->qe);
+
+ list_for_each(qe, &rx_mod->rx_free_q) {
+ if (((struct bna_rx *)qe)->rid < rx->rid)
+ prev_qe = qe;
+ else
+ break;
+ }
+
+ if (prev_qe == NULL) {
+ /* This is the first entry */
+ bfa_q_enq_head(&rx_mod->rx_free_q, &rx->qe);
+ } else if (bfa_q_next(prev_qe) == &rx_mod->rx_free_q) {
+ /* This is the last entry */
+ list_add_tail(&rx->qe, &rx_mod->rx_free_q);
+ } else {
+ /* Somewhere in the middle */
+ bfa_q_next(&rx->qe) = bfa_q_next(prev_qe);
+ bfa_q_prev(&rx->qe) = prev_qe;
+ bfa_q_next(prev_qe) = &rx->qe;
+ bfa_q_prev(bfa_q_next(&rx->qe)) = &rx->qe;
+ }
+
+ rx_mod->rx_free_count++;
+}
+
+static void
+bna_rxp_add_rxqs(struct bna_rxp *rxp, struct bna_rxq *q0,
+ struct bna_rxq *q1)
+{
+ switch (rxp->type) {
+ case BNA_RXP_SINGLE:
+ rxp->rxq.single.only = q0;
+ rxp->rxq.single.reserved = NULL;
+ break;
+ case BNA_RXP_SLR:
+ rxp->rxq.slr.large = q0;
+ rxp->rxq.slr.small = q1;
+ break;
+ case BNA_RXP_HDS:
+ rxp->rxq.hds.data = q0;
+ rxp->rxq.hds.hdr = q1;
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+bna_rxq_qpt_setup(struct bna_rxq *rxq,
+ struct bna_rxp *rxp,
+ u32 page_count,
+ u32 page_size,
+ struct bna_mem_descr *qpt_mem,
+ struct bna_mem_descr *swqpt_mem,
+ struct bna_mem_descr *page_mem)
+{
+ int i;
+
+ rxq->qpt.hw_qpt_ptr.lsb = qpt_mem->dma.lsb;
+ rxq->qpt.hw_qpt_ptr.msb = qpt_mem->dma.msb;
+ rxq->qpt.kv_qpt_ptr = qpt_mem->kva;
+ rxq->qpt.page_count = page_count;
+ rxq->qpt.page_size = page_size;
+
+ rxq->rcb->sw_qpt = (void **) swqpt_mem->kva;
+
+ for (i = 0; i < rxq->qpt.page_count; i++) {
+ rxq->rcb->sw_qpt[i] = page_mem[i].kva;
+ ((struct bna_dma_addr *)rxq->qpt.kv_qpt_ptr)[i].lsb =
+ page_mem[i].dma.lsb;
+ ((struct bna_dma_addr *)rxq->qpt.kv_qpt_ptr)[i].msb =
+ page_mem[i].dma.msb;
+ }
+}
+
+static void
+bna_rxp_cqpt_setup(struct bna_rxp *rxp,
+ u32 page_count,
+ u32 page_size,
+ struct bna_mem_descr *qpt_mem,
+ struct bna_mem_descr *swqpt_mem,
+ struct bna_mem_descr *page_mem)
+{
+ int i;
+
+ rxp->cq.qpt.hw_qpt_ptr.lsb = qpt_mem->dma.lsb;
+ rxp->cq.qpt.hw_qpt_ptr.msb = qpt_mem->dma.msb;
+ rxp->cq.qpt.kv_qpt_ptr = qpt_mem->kva;
+ rxp->cq.qpt.page_count = page_count;
+ rxp->cq.qpt.page_size = page_size;
+
+ rxp->cq.ccb->sw_qpt = (void **) swqpt_mem->kva;
+
+ for (i = 0; i < rxp->cq.qpt.page_count; i++) {
+ rxp->cq.ccb->sw_qpt[i] = page_mem[i].kva;
+
+ ((struct bna_dma_addr *)rxp->cq.qpt.kv_qpt_ptr)[i].lsb =
+ page_mem[i].dma.lsb;
+ ((struct bna_dma_addr *)rxp->cq.qpt.kv_qpt_ptr)[i].msb =
+ page_mem[i].dma.msb;
+ }
+}
+
+static void
+bna_rx_mod_cb_rx_stopped(void *arg, struct bna_rx *rx)
+{
+ struct bna_rx_mod *rx_mod = (struct bna_rx_mod *)arg;
+
+ bfa_wc_down(&rx_mod->rx_stop_wc);
+}
+
+static void
+bna_rx_mod_cb_rx_stopped_all(void *arg)
+{
+ struct bna_rx_mod *rx_mod = (struct bna_rx_mod *)arg;
+
+ if (rx_mod->stop_cbfn)
+ rx_mod->stop_cbfn(&rx_mod->bna->enet);
+ rx_mod->stop_cbfn = NULL;
+}
+
+static void
+bna_rx_start(struct bna_rx *rx)
+{
+ rx->rx_flags |= BNA_RX_F_ENET_STARTED;
+ if (rx->rx_flags & BNA_RX_F_ENABLED)
+ bfa_fsm_send_event(rx, RX_E_START);
+}
+
+static void
+bna_rx_stop(struct bna_rx *rx)
+{
+ rx->rx_flags &= ~BNA_RX_F_ENET_STARTED;
+ if (rx->fsm == (bfa_fsm_t) bna_rx_sm_stopped)
+ bna_rx_mod_cb_rx_stopped(&rx->bna->rx_mod, rx);
+ else {
+ rx->stop_cbfn = bna_rx_mod_cb_rx_stopped;
+ rx->stop_cbarg = &rx->bna->rx_mod;
+ bfa_fsm_send_event(rx, RX_E_STOP);
+ }
+}
+
+static void
+bna_rx_fail(struct bna_rx *rx)
+{
+ /* Indicate Enet is not enabled, and failed */
+ rx->rx_flags &= ~BNA_RX_F_ENET_STARTED;
+ bfa_fsm_send_event(rx, RX_E_FAIL);
+}
+
+void
+bna_rx_mod_start(struct bna_rx_mod *rx_mod, enum bna_rx_type type)
+{
+ struct bna_rx *rx;
+ struct list_head *qe;
+
+ rx_mod->flags |= BNA_RX_MOD_F_ENET_STARTED;
+ if (type == BNA_RX_T_LOOPBACK)
+ rx_mod->flags |= BNA_RX_MOD_F_ENET_LOOPBACK;
+
+ list_for_each(qe, &rx_mod->rx_active_q) {
+ rx = (struct bna_rx *)qe;
+ if (rx->type == type)
+ bna_rx_start(rx);
+ }
+}
+
+void
+bna_rx_mod_stop(struct bna_rx_mod *rx_mod, enum bna_rx_type type)
+{
+ struct bna_rx *rx;
+ struct list_head *qe;
+
+ rx_mod->flags &= ~BNA_RX_MOD_F_ENET_STARTED;
+ rx_mod->flags &= ~BNA_RX_MOD_F_ENET_LOOPBACK;
+
+ rx_mod->stop_cbfn = bna_enet_cb_rx_stopped;
+
+ bfa_wc_init(&rx_mod->rx_stop_wc, bna_rx_mod_cb_rx_stopped_all, rx_mod);
+
+ list_for_each(qe, &rx_mod->rx_active_q) {
+ rx = (struct bna_rx *)qe;
+ if (rx->type == type) {
+ bfa_wc_up(&rx_mod->rx_stop_wc);
+ bna_rx_stop(rx);
+ }
+ }
+
+ bfa_wc_wait(&rx_mod->rx_stop_wc);
+}
+
+void
+bna_rx_mod_fail(struct bna_rx_mod *rx_mod)
+{
+ struct bna_rx *rx;
+ struct list_head *qe;
+
+ rx_mod->flags &= ~BNA_RX_MOD_F_ENET_STARTED;
+ rx_mod->flags &= ~BNA_RX_MOD_F_ENET_LOOPBACK;
+
+ list_for_each(qe, &rx_mod->rx_active_q) {
+ rx = (struct bna_rx *)qe;
+ bna_rx_fail(rx);
+ }
+}
+
+void bna_rx_mod_init(struct bna_rx_mod *rx_mod, struct bna *bna,
+ struct bna_res_info *res_info)
+{
+ int index;
+ struct bna_rx *rx_ptr;
+ struct bna_rxp *rxp_ptr;
+ struct bna_rxq *rxq_ptr;
+
+ rx_mod->bna = bna;
+ rx_mod->flags = 0;
+
+ rx_mod->rx = (struct bna_rx *)
+ res_info[BNA_MOD_RES_MEM_T_RX_ARRAY].res_u.mem_info.mdl[0].kva;
+ rx_mod->rxp = (struct bna_rxp *)
+ res_info[BNA_MOD_RES_MEM_T_RXP_ARRAY].res_u.mem_info.mdl[0].kva;
+ rx_mod->rxq = (struct bna_rxq *)
+ res_info[BNA_MOD_RES_MEM_T_RXQ_ARRAY].res_u.mem_info.mdl[0].kva;
+
+ /* Initialize the queues */
+ INIT_LIST_HEAD(&rx_mod->rx_free_q);
+ rx_mod->rx_free_count = 0;
+ INIT_LIST_HEAD(&rx_mod->rxq_free_q);
+ rx_mod->rxq_free_count = 0;
+ INIT_LIST_HEAD(&rx_mod->rxp_free_q);
+ rx_mod->rxp_free_count = 0;
+ INIT_LIST_HEAD(&rx_mod->rx_active_q);
+
+ /* Build RX queues */
+ for (index = 0; index < bna->ioceth.attr.num_rxp; index++) {
+ rx_ptr = &rx_mod->rx[index];
+
+ bfa_q_qe_init(&rx_ptr->qe);
+ INIT_LIST_HEAD(&rx_ptr->rxp_q);
+ rx_ptr->bna = NULL;
+ rx_ptr->rid = index;
+ rx_ptr->stop_cbfn = NULL;
+ rx_ptr->stop_cbarg = NULL;
+
+ list_add_tail(&rx_ptr->qe, &rx_mod->rx_free_q);
+ rx_mod->rx_free_count++;
+ }
+
+ /* build RX-path queue */
+ for (index = 0; index < bna->ioceth.attr.num_rxp; index++) {
+ rxp_ptr = &rx_mod->rxp[index];
+ bfa_q_qe_init(&rxp_ptr->qe);
+ list_add_tail(&rxp_ptr->qe, &rx_mod->rxp_free_q);
+ rx_mod->rxp_free_count++;
+ }
+
+ /* build RXQ queue */
+ for (index = 0; index < (bna->ioceth.attr.num_rxp * 2); index++) {
+ rxq_ptr = &rx_mod->rxq[index];
+ bfa_q_qe_init(&rxq_ptr->qe);
+ list_add_tail(&rxq_ptr->qe, &rx_mod->rxq_free_q);
+ rx_mod->rxq_free_count++;
+ }
+}
+
+void
+bna_rx_mod_uninit(struct bna_rx_mod *rx_mod)
+{
+ struct list_head *qe;
+ int i;
+
+ i = 0;
+ list_for_each(qe, &rx_mod->rx_free_q)
+ i++;
+
+ i = 0;
+ list_for_each(qe, &rx_mod->rxp_free_q)
+ i++;
+
+ i = 0;
+ list_for_each(qe, &rx_mod->rxq_free_q)
+ i++;
+
+ rx_mod->bna = NULL;
+}
+
+void
+bna_bfi_rx_enet_start_rsp(struct bna_rx *rx, struct bfi_msgq_mhdr *msghdr)
+{
+ struct bfi_enet_rx_cfg_rsp *cfg_rsp = &rx->bfi_enet_cmd.cfg_rsp;
+ struct bna_rxp *rxp = NULL;
+ struct bna_rxq *q0 = NULL, *q1 = NULL;
+ struct list_head *rxp_qe;
+ int i;
+
+ bfa_msgq_rsp_copy(&rx->bna->msgq, (u8 *)cfg_rsp,
+ sizeof(struct bfi_enet_rx_cfg_rsp));
+
+ rx->hw_id = cfg_rsp->hw_id;
+
+ for (i = 0, rxp_qe = bfa_q_first(&rx->rxp_q);
+ i < rx->num_paths;
+ i++, rxp_qe = bfa_q_next(rxp_qe)) {
+ rxp = (struct bna_rxp *)rxp_qe;
+ GET_RXQS(rxp, q0, q1);
+
+ /* Setup doorbells */
+ rxp->cq.ccb->i_dbell->doorbell_addr =
+ rx->bna->pcidev.pci_bar_kva
+ + ntohl(cfg_rsp->q_handles[i].i_dbell);
+ rxp->hw_id = cfg_rsp->q_handles[i].hw_cqid;
+ q0->rcb->q_dbell =
+ rx->bna->pcidev.pci_bar_kva
+ + ntohl(cfg_rsp->q_handles[i].ql_dbell);
+ q0->hw_id = cfg_rsp->q_handles[i].hw_lqid;
+ if (q1) {
+ q1->rcb->q_dbell =
+ rx->bna->pcidev.pci_bar_kva
+ + ntohl(cfg_rsp->q_handles[i].qs_dbell);
+ q1->hw_id = cfg_rsp->q_handles[i].hw_sqid;
+ }
+
+ /* Initialize producer/consumer indexes */
+ (*rxp->cq.ccb->hw_producer_index) = 0;
+ rxp->cq.ccb->producer_index = 0;
+ q0->rcb->producer_index = q0->rcb->consumer_index = 0;
+ if (q1)
+ q1->rcb->producer_index = q1->rcb->consumer_index = 0;
+ }
+
+ bfa_fsm_send_event(rx, RX_E_STARTED);
+}
+
+void
+bna_bfi_rx_enet_stop_rsp(struct bna_rx *rx, struct bfi_msgq_mhdr *msghdr)
+{
+ bfa_fsm_send_event(rx, RX_E_STOPPED);
+}
+
+void
+bna_rx_res_req(struct bna_rx_config *q_cfg, struct bna_res_info *res_info)
+{
+ u32 cq_size, hq_size, dq_size;
+ u32 cpage_count, hpage_count, dpage_count;
+ struct bna_mem_info *mem_info;
+ u32 cq_depth;
+ u32 hq_depth;
+ u32 dq_depth;
+
+ dq_depth = q_cfg->q_depth;
+ hq_depth = ((q_cfg->rxp_type == BNA_RXP_SINGLE) ? 0 : q_cfg->q_depth);
+ cq_depth = dq_depth + hq_depth;
+
+ BNA_TO_POWER_OF_2_HIGH(cq_depth);
+ cq_size = cq_depth * BFI_CQ_WI_SIZE;
+ cq_size = ALIGN(cq_size, PAGE_SIZE);
+ cpage_count = SIZE_TO_PAGES(cq_size);
+
+ BNA_TO_POWER_OF_2_HIGH(dq_depth);
+ dq_size = dq_depth * BFI_RXQ_WI_SIZE;
+ dq_size = ALIGN(dq_size, PAGE_SIZE);
+ dpage_count = SIZE_TO_PAGES(dq_size);
+
+ if (BNA_RXP_SINGLE != q_cfg->rxp_type) {
+ BNA_TO_POWER_OF_2_HIGH(hq_depth);
+ hq_size = hq_depth * BFI_RXQ_WI_SIZE;
+ hq_size = ALIGN(hq_size, PAGE_SIZE);
+ hpage_count = SIZE_TO_PAGES(hq_size);
+ } else
+ hpage_count = 0;
+
+ res_info[BNA_RX_RES_MEM_T_CCB].res_type = BNA_RES_T_MEM;
+ mem_info = &res_info[BNA_RX_RES_MEM_T_CCB].res_u.mem_info;
+ mem_info->mem_type = BNA_MEM_T_KVA;
+ mem_info->len = sizeof(struct bna_ccb);
+ mem_info->num = q_cfg->num_paths;
+
+ res_info[BNA_RX_RES_MEM_T_RCB].res_type = BNA_RES_T_MEM;
+ mem_info = &res_info[BNA_RX_RES_MEM_T_RCB].res_u.mem_info;
+ mem_info->mem_type = BNA_MEM_T_KVA;
+ mem_info->len = sizeof(struct bna_rcb);
+ mem_info->num = BNA_GET_RXQS(q_cfg);
+
+ res_info[BNA_RX_RES_MEM_T_CQPT].res_type = BNA_RES_T_MEM;
+ mem_info = &res_info[BNA_RX_RES_MEM_T_CQPT].res_u.mem_info;
+ mem_info->mem_type = BNA_MEM_T_DMA;
+ mem_info->len = cpage_count * sizeof(struct bna_dma_addr);
+ mem_info->num = q_cfg->num_paths;
+
+ res_info[BNA_RX_RES_MEM_T_CSWQPT].res_type = BNA_RES_T_MEM;
+ mem_info = &res_info[BNA_RX_RES_MEM_T_CSWQPT].res_u.mem_info;
+ mem_info->mem_type = BNA_MEM_T_KVA;
+ mem_info->len = cpage_count * sizeof(void *);
+ mem_info->num = q_cfg->num_paths;
+
+ res_info[BNA_RX_RES_MEM_T_CQPT_PAGE].res_type = BNA_RES_T_MEM;
+ mem_info = &res_info[BNA_RX_RES_MEM_T_CQPT_PAGE].res_u.mem_info;
+ mem_info->mem_type = BNA_MEM_T_DMA;
+ mem_info->len = PAGE_SIZE;
+ mem_info->num = cpage_count * q_cfg->num_paths;
+
+ res_info[BNA_RX_RES_MEM_T_DQPT].res_type = BNA_RES_T_MEM;
+ mem_info = &res_info[BNA_RX_RES_MEM_T_DQPT].res_u.mem_info;
+ mem_info->mem_type = BNA_MEM_T_DMA;
+ mem_info->len = dpage_count * sizeof(struct bna_dma_addr);
+ mem_info->num = q_cfg->num_paths;
+
+ res_info[BNA_RX_RES_MEM_T_DSWQPT].res_type = BNA_RES_T_MEM;
+ mem_info = &res_info[BNA_RX_RES_MEM_T_DSWQPT].res_u.mem_info;
+ mem_info->mem_type = BNA_MEM_T_KVA;
+ mem_info->len = dpage_count * sizeof(void *);
+ mem_info->num = q_cfg->num_paths;
+
+ res_info[BNA_RX_RES_MEM_T_DPAGE].res_type = BNA_RES_T_MEM;
+ mem_info = &res_info[BNA_RX_RES_MEM_T_DPAGE].res_u.mem_info;
+ mem_info->mem_type = BNA_MEM_T_DMA;
+ mem_info->len = PAGE_SIZE;
+ mem_info->num = dpage_count * q_cfg->num_paths;
+
+ res_info[BNA_RX_RES_MEM_T_HQPT].res_type = BNA_RES_T_MEM;
+ mem_info = &res_info[BNA_RX_RES_MEM_T_HQPT].res_u.mem_info;
+ mem_info->mem_type = BNA_MEM_T_DMA;
+ mem_info->len = hpage_count * sizeof(struct bna_dma_addr);
+ mem_info->num = (hpage_count ? q_cfg->num_paths : 0);
+
+ res_info[BNA_RX_RES_MEM_T_HSWQPT].res_type = BNA_RES_T_MEM;
+ mem_info = &res_info[BNA_RX_RES_MEM_T_HSWQPT].res_u.mem_info;
+ mem_info->mem_type = BNA_MEM_T_KVA;
+ mem_info->len = hpage_count * sizeof(void *);
+ mem_info->num = (hpage_count ? q_cfg->num_paths : 0);
+
+ res_info[BNA_RX_RES_MEM_T_HPAGE].res_type = BNA_RES_T_MEM;
+ mem_info = &res_info[BNA_RX_RES_MEM_T_HPAGE].res_u.mem_info;
+ mem_info->mem_type = BNA_MEM_T_DMA;
+ mem_info->len = (hpage_count ? PAGE_SIZE : 0);
+ mem_info->num = (hpage_count ? (hpage_count * q_cfg->num_paths) : 0);
+
+ res_info[BNA_RX_RES_MEM_T_IBIDX].res_type = BNA_RES_T_MEM;
+ mem_info = &res_info[BNA_RX_RES_MEM_T_IBIDX].res_u.mem_info;
+ mem_info->mem_type = BNA_MEM_T_DMA;
+ mem_info->len = BFI_IBIDX_SIZE;
+ mem_info->num = q_cfg->num_paths;
+
+ res_info[BNA_RX_RES_MEM_T_RIT].res_type = BNA_RES_T_MEM;
+ mem_info = &res_info[BNA_RX_RES_MEM_T_RIT].res_u.mem_info;
+ mem_info->mem_type = BNA_MEM_T_KVA;
+ mem_info->len = BFI_ENET_RSS_RIT_MAX;
+ mem_info->num = 1;
+
+ res_info[BNA_RX_RES_T_INTR].res_type = BNA_RES_T_INTR;
+ res_info[BNA_RX_RES_T_INTR].res_u.intr_info.intr_type = BNA_INTR_T_MSIX;
+ res_info[BNA_RX_RES_T_INTR].res_u.intr_info.num = q_cfg->num_paths;
+}
+
+struct bna_rx *
+bna_rx_create(struct bna *bna, struct bnad *bnad,
+ struct bna_rx_config *rx_cfg,
+ const struct bna_rx_event_cbfn *rx_cbfn,
+ struct bna_res_info *res_info,
+ void *priv)
+{
+ struct bna_rx_mod *rx_mod = &bna->rx_mod;
+ struct bna_rx *rx;
+ struct bna_rxp *rxp;
+ struct bna_rxq *q0;
+ struct bna_rxq *q1;
+ struct bna_intr_info *intr_info;
+ u32 page_count;
+ struct bna_mem_descr *ccb_mem;
+ struct bna_mem_descr *rcb_mem;
+ struct bna_mem_descr *unmapq_mem;
+ struct bna_mem_descr *cqpt_mem;
+ struct bna_mem_descr *cswqpt_mem;
+ struct bna_mem_descr *cpage_mem;
+ struct bna_mem_descr *hqpt_mem;
+ struct bna_mem_descr *dqpt_mem;
+ struct bna_mem_descr *hsqpt_mem;
+ struct bna_mem_descr *dsqpt_mem;
+ struct bna_mem_descr *hpage_mem;
+ struct bna_mem_descr *dpage_mem;
+ int i, cpage_idx = 0, dpage_idx = 0, hpage_idx = 0;
+ int dpage_count, hpage_count, rcb_idx;
+
+ if (!bna_rx_res_check(rx_mod, rx_cfg))
+ return NULL;
+
+ intr_info = &res_info[BNA_RX_RES_T_INTR].res_u.intr_info;
+ ccb_mem = &res_info[BNA_RX_RES_MEM_T_CCB].res_u.mem_info.mdl[0];
+ rcb_mem = &res_info[BNA_RX_RES_MEM_T_RCB].res_u.mem_info.mdl[0];
+ unmapq_mem = &res_info[BNA_RX_RES_MEM_T_UNMAPQ].res_u.mem_info.mdl[0];
+ cqpt_mem = &res_info[BNA_RX_RES_MEM_T_CQPT].res_u.mem_info.mdl[0];
+ cswqpt_mem = &res_info[BNA_RX_RES_MEM_T_CSWQPT].res_u.mem_info.mdl[0];
+ cpage_mem = &res_info[BNA_RX_RES_MEM_T_CQPT_PAGE].res_u.mem_info.mdl[0];
+ hqpt_mem = &res_info[BNA_RX_RES_MEM_T_HQPT].res_u.mem_info.mdl[0];
+ dqpt_mem = &res_info[BNA_RX_RES_MEM_T_DQPT].res_u.mem_info.mdl[0];
+ hsqpt_mem = &res_info[BNA_RX_RES_MEM_T_HSWQPT].res_u.mem_info.mdl[0];
+ dsqpt_mem = &res_info[BNA_RX_RES_MEM_T_DSWQPT].res_u.mem_info.mdl[0];
+ hpage_mem = &res_info[BNA_RX_RES_MEM_T_HPAGE].res_u.mem_info.mdl[0];
+ dpage_mem = &res_info[BNA_RX_RES_MEM_T_DPAGE].res_u.mem_info.mdl[0];
+
+ page_count = res_info[BNA_RX_RES_MEM_T_CQPT_PAGE].res_u.mem_info.num /
+ rx_cfg->num_paths;
+
+ dpage_count = res_info[BNA_RX_RES_MEM_T_DPAGE].res_u.mem_info.num /
+ rx_cfg->num_paths;
+
+ hpage_count = res_info[BNA_RX_RES_MEM_T_HPAGE].res_u.mem_info.num /
+ rx_cfg->num_paths;
+
+ rx = bna_rx_get(rx_mod, rx_cfg->rx_type);
+ rx->bna = bna;
+ rx->rx_flags = 0;
+ INIT_LIST_HEAD(&rx->rxp_q);
+ rx->stop_cbfn = NULL;
+ rx->stop_cbarg = NULL;
+ rx->priv = priv;
+
+ rx->rcb_setup_cbfn = rx_cbfn->rcb_setup_cbfn;
+ rx->rcb_destroy_cbfn = rx_cbfn->rcb_destroy_cbfn;
+ rx->ccb_setup_cbfn = rx_cbfn->ccb_setup_cbfn;
+ rx->ccb_destroy_cbfn = rx_cbfn->ccb_destroy_cbfn;
+ rx->rx_stall_cbfn = rx_cbfn->rx_stall_cbfn;
+ /* Following callbacks are mandatory */
+ rx->rx_cleanup_cbfn = rx_cbfn->rx_cleanup_cbfn;
+ rx->rx_post_cbfn = rx_cbfn->rx_post_cbfn;
+
+ if (rx->bna->rx_mod.flags & BNA_RX_MOD_F_ENET_STARTED) {
+ switch (rx->type) {
+ case BNA_RX_T_REGULAR:
+ if (!(rx->bna->rx_mod.flags &
+ BNA_RX_MOD_F_ENET_LOOPBACK))
+ rx->rx_flags |= BNA_RX_F_ENET_STARTED;
+ break;
+ case BNA_RX_T_LOOPBACK:
+ if (rx->bna->rx_mod.flags & BNA_RX_MOD_F_ENET_LOOPBACK)
+ rx->rx_flags |= BNA_RX_F_ENET_STARTED;
+ break;
+ }
+ }
+
+ rx->num_paths = rx_cfg->num_paths;
+ for (i = 0, rcb_idx = 0; i < rx->num_paths; i++) {
+ rxp = bna_rxp_get(rx_mod);
+ list_add_tail(&rxp->qe, &rx->rxp_q);
+ rxp->type = rx_cfg->rxp_type;
+ rxp->rx = rx;
+ rxp->cq.rx = rx;
+
+ q0 = bna_rxq_get(rx_mod);
+ if (BNA_RXP_SINGLE == rx_cfg->rxp_type)
+ q1 = NULL;
+ else
+ q1 = bna_rxq_get(rx_mod);
+
+ if (1 == intr_info->num)
+ rxp->vector = intr_info->idl[0].vector;
+ else
+ rxp->vector = intr_info->idl[i].vector;
+
+ /* Setup IB */
+
+ rxp->cq.ib.ib_seg_host_addr.lsb =
+ res_info[BNA_RX_RES_MEM_T_IBIDX].res_u.mem_info.mdl[i].dma.lsb;
+ rxp->cq.ib.ib_seg_host_addr.msb =
+ res_info[BNA_RX_RES_MEM_T_IBIDX].res_u.mem_info.mdl[i].dma.msb;
+ rxp->cq.ib.ib_seg_host_addr_kva =
+ res_info[BNA_RX_RES_MEM_T_IBIDX].res_u.mem_info.mdl[i].kva;
+ rxp->cq.ib.intr_type = intr_info->intr_type;
+ if (intr_info->intr_type == BNA_INTR_T_MSIX)
+ rxp->cq.ib.intr_vector = rxp->vector;
+ else
+ rxp->cq.ib.intr_vector = (1 << rxp->vector);
+ rxp->cq.ib.coalescing_timeo = rx_cfg->coalescing_timeo;
+ rxp->cq.ib.interpkt_count = BFI_RX_INTERPKT_COUNT;
+ rxp->cq.ib.interpkt_timeo = BFI_RX_INTERPKT_TIMEO;
+
+ bna_rxp_add_rxqs(rxp, q0, q1);
+
+ /* Setup large Q */
+
+ q0->rx = rx;
+ q0->rxp = rxp;
+
+ q0->rcb = (struct bna_rcb *) rcb_mem[rcb_idx].kva;
+ q0->rcb->unmap_q = (void *)unmapq_mem[rcb_idx].kva;
+ rcb_idx++;
+ q0->rcb->q_depth = rx_cfg->q_depth;
+ q0->rcb->rxq = q0;
+ q0->rcb->bnad = bna->bnad;
+ q0->rcb->id = 0;
+ q0->rx_packets = q0->rx_bytes = 0;
+ q0->rx_packets_with_error = q0->rxbuf_alloc_failed = 0;
+
+ bna_rxq_qpt_setup(q0, rxp, dpage_count, PAGE_SIZE,
+ &dqpt_mem[i], &dsqpt_mem[i], &dpage_mem[dpage_idx]);
+ q0->rcb->page_idx = dpage_idx;
+ q0->rcb->page_count = dpage_count;
+ dpage_idx += dpage_count;
+
+ if (rx->rcb_setup_cbfn)
+ rx->rcb_setup_cbfn(bnad, q0->rcb);
+
+ /* Setup small Q */
+
+ if (q1) {
+ q1->rx = rx;
+ q1->rxp = rxp;
+
+ q1->rcb = (struct bna_rcb *) rcb_mem[rcb_idx].kva;
+ q1->rcb->unmap_q = (void *)unmapq_mem[rcb_idx].kva;
+ rcb_idx++;
+ q1->rcb->q_depth = rx_cfg->q_depth;
+ q1->rcb->rxq = q1;
+ q1->rcb->bnad = bna->bnad;
+ q1->rcb->id = 1;
+ q1->buffer_size = (rx_cfg->rxp_type == BNA_RXP_HDS) ?
+ rx_cfg->hds_config.forced_offset
+ : rx_cfg->small_buff_size;
+ q1->rx_packets = q1->rx_bytes = 0;
+ q1->rx_packets_with_error = q1->rxbuf_alloc_failed = 0;
+
+ bna_rxq_qpt_setup(q1, rxp, hpage_count, PAGE_SIZE,
+ &hqpt_mem[i], &hsqpt_mem[i],
+ &hpage_mem[hpage_idx]);
+ q1->rcb->page_idx = hpage_idx;
+ q1->rcb->page_count = hpage_count;
+ hpage_idx += hpage_count;
+
+ if (rx->rcb_setup_cbfn)
+ rx->rcb_setup_cbfn(bnad, q1->rcb);
+ }
+
+ /* Setup CQ */
+
+ rxp->cq.ccb = (struct bna_ccb *) ccb_mem[i].kva;
+ rxp->cq.ccb->q_depth = rx_cfg->q_depth +
+ ((rx_cfg->rxp_type == BNA_RXP_SINGLE) ?
+ 0 : rx_cfg->q_depth);
+ rxp->cq.ccb->cq = &rxp->cq;
+ rxp->cq.ccb->rcb[0] = q0->rcb;
+ q0->rcb->ccb = rxp->cq.ccb;
+ if (q1) {
+ rxp->cq.ccb->rcb[1] = q1->rcb;
+ q1->rcb->ccb = rxp->cq.ccb;
+ }
+ rxp->cq.ccb->hw_producer_index =
+ (u32 *)rxp->cq.ib.ib_seg_host_addr_kva;
+ rxp->cq.ccb->i_dbell = &rxp->cq.ib.door_bell;
+ rxp->cq.ccb->intr_type = rxp->cq.ib.intr_type;
+ rxp->cq.ccb->intr_vector = rxp->cq.ib.intr_vector;
+ rxp->cq.ccb->rx_coalescing_timeo =
+ rxp->cq.ib.coalescing_timeo;
+ rxp->cq.ccb->pkt_rate.small_pkt_cnt = 0;
+ rxp->cq.ccb->pkt_rate.large_pkt_cnt = 0;
+ rxp->cq.ccb->bnad = bna->bnad;
+ rxp->cq.ccb->id = i;
+
+ bna_rxp_cqpt_setup(rxp, page_count, PAGE_SIZE,
+ &cqpt_mem[i], &cswqpt_mem[i], &cpage_mem[cpage_idx]);
+ rxp->cq.ccb->page_idx = cpage_idx;
+ rxp->cq.ccb->page_count = page_count;
+ cpage_idx += page_count;
+
+ if (rx->ccb_setup_cbfn)
+ rx->ccb_setup_cbfn(bnad, rxp->cq.ccb);
+ }
+
+ rx->hds_cfg = rx_cfg->hds_config;
+
+ bna_rxf_init(&rx->rxf, rx, rx_cfg, res_info);
+
+ bfa_fsm_set_state(rx, bna_rx_sm_stopped);
+
+ rx_mod->rid_mask |= (1 << rx->rid);
+
+ return rx;
+}
+
+void
+bna_rx_destroy(struct bna_rx *rx)
+{
+ struct bna_rx_mod *rx_mod = &rx->bna->rx_mod;
+ struct bna_rxq *q0 = NULL;
+ struct bna_rxq *q1 = NULL;
+ struct bna_rxp *rxp;
+ struct list_head *qe;
+
+ bna_rxf_uninit(&rx->rxf);
+
+ while (!list_empty(&rx->rxp_q)) {
+ bfa_q_deq(&rx->rxp_q, &rxp);
+ GET_RXQS(rxp, q0, q1);
+ if (rx->rcb_destroy_cbfn)
+ rx->rcb_destroy_cbfn(rx->bna->bnad, q0->rcb);
+ q0->rcb = NULL;
+ q0->rxp = NULL;
+ q0->rx = NULL;
+ bna_rxq_put(rx_mod, q0);
+
+ if (q1) {
+ if (rx->rcb_destroy_cbfn)
+ rx->rcb_destroy_cbfn(rx->bna->bnad, q1->rcb);
+ q1->rcb = NULL;
+ q1->rxp = NULL;
+ q1->rx = NULL;
+ bna_rxq_put(rx_mod, q1);
+ }
+ rxp->rxq.slr.large = NULL;
+ rxp->rxq.slr.small = NULL;
+
+ if (rx->ccb_destroy_cbfn)
+ rx->ccb_destroy_cbfn(rx->bna->bnad, rxp->cq.ccb);
+ rxp->cq.ccb = NULL;
+ rxp->rx = NULL;
+ bna_rxp_put(rx_mod, rxp);
+ }
+
+ list_for_each(qe, &rx_mod->rx_active_q) {
+ if (qe == &rx->qe) {
+ list_del(&rx->qe);
+ bfa_q_qe_init(&rx->qe);
+ break;
+ }
+ }
+
+ rx_mod->rid_mask &= ~(1 << rx->rid);
+
+ rx->bna = NULL;
+ rx->priv = NULL;
+ bna_rx_put(rx_mod, rx);
+}
+
+void
+bna_rx_enable(struct bna_rx *rx)
+{
+ if (rx->fsm != (bfa_sm_t)bna_rx_sm_stopped)
+ return;
+
+ rx->rx_flags |= BNA_RX_F_ENABLED;
+ if (rx->rx_flags & BNA_RX_F_ENET_STARTED)
+ bfa_fsm_send_event(rx, RX_E_START);
+}
+
+void
+bna_rx_disable(struct bna_rx *rx, enum bna_cleanup_type type,
+ void (*cbfn)(void *, struct bna_rx *))
+{
+ if (type == BNA_SOFT_CLEANUP) {
+ /* h/w should not be accessed. Treat we're stopped */
+ (*cbfn)(rx->bna->bnad, rx);
+ } else {
+ rx->stop_cbfn = cbfn;
+ rx->stop_cbarg = rx->bna->bnad;
+
+ rx->rx_flags &= ~BNA_RX_F_ENABLED;
+
+ bfa_fsm_send_event(rx, RX_E_STOP);
+ }
+}
+
+void
+bna_rx_cleanup_complete(struct bna_rx *rx)
+{
+ bfa_fsm_send_event(rx, RX_E_CLEANUP_DONE);
+}
+
+enum bna_cb_status
+bna_rx_mode_set(struct bna_rx *rx, enum bna_rxmode new_mode,
+ enum bna_rxmode bitmask,
+ void (*cbfn)(struct bnad *, struct bna_rx *))
+{
+ struct bna_rxf *rxf = &rx->rxf;
+ int need_hw_config = 0;
+
+ /* Error checks */
+
+ if (is_promisc_enable(new_mode, bitmask)) {
+ /* If promisc mode is already enabled elsewhere in the system */
+ if ((rx->bna->promisc_rid != BFI_INVALID_RID) &&
+ (rx->bna->promisc_rid != rxf->rx->rid))
+ goto err_return;
+
+ /* If default mode is already enabled in the system */
+ if (rx->bna->default_mode_rid != BFI_INVALID_RID)
+ goto err_return;
+
+ /* Trying to enable promiscuous and default mode together */
+ if (is_default_enable(new_mode, bitmask))
+ goto err_return;
+ }
+
+ if (is_default_enable(new_mode, bitmask)) {
+ /* If default mode is already enabled elsewhere in the system */
+ if ((rx->bna->default_mode_rid != BFI_INVALID_RID) &&
+ (rx->bna->default_mode_rid != rxf->rx->rid)) {
+ goto err_return;
+ }
+
+ /* If promiscuous mode is already enabled in the system */
+ if (rx->bna->promisc_rid != BFI_INVALID_RID)
+ goto err_return;
+ }
+
+ /* Process the commands */
+
+ if (is_promisc_enable(new_mode, bitmask)) {
+ if (bna_rxf_promisc_enable(rxf))
+ need_hw_config = 1;
+ } else if (is_promisc_disable(new_mode, bitmask)) {
+ if (bna_rxf_promisc_disable(rxf))
+ need_hw_config = 1;
+ }
+
+ if (is_allmulti_enable(new_mode, bitmask)) {
+ if (bna_rxf_allmulti_enable(rxf))
+ need_hw_config = 1;
+ } else if (is_allmulti_disable(new_mode, bitmask)) {
+ if (bna_rxf_allmulti_disable(rxf))
+ need_hw_config = 1;
+ }
+
+ /* Trigger h/w if needed */
+
+ if (need_hw_config) {
+ rxf->cam_fltr_cbfn = cbfn;
+ rxf->cam_fltr_cbarg = rx->bna->bnad;
+ bfa_fsm_send_event(rxf, RXF_E_CONFIG);
+ } else if (cbfn)
+ (*cbfn)(rx->bna->bnad, rx);
+
+ return BNA_CB_SUCCESS;
+
+err_return:
+ return BNA_CB_FAIL;
+}
+
+void
+bna_rx_vlanfilter_enable(struct bna_rx *rx)
+{
+ struct bna_rxf *rxf = &rx->rxf;
+
+ if (rxf->vlan_filter_status == BNA_STATUS_T_DISABLED) {
+ rxf->vlan_filter_status = BNA_STATUS_T_ENABLED;
+ rxf->vlan_pending_bitmask = (u8)BFI_VLAN_BMASK_ALL;
+ bfa_fsm_send_event(rxf, RXF_E_CONFIG);
+ }
+}
+
+void
+bna_rx_coalescing_timeo_set(struct bna_rx *rx, int coalescing_timeo)
+{
+ struct bna_rxp *rxp;
+ struct list_head *qe;
+
+ list_for_each(qe, &rx->rxp_q) {
+ rxp = (struct bna_rxp *)qe;
+ rxp->cq.ccb->rx_coalescing_timeo = coalescing_timeo;
+ bna_ib_coalescing_timeo_set(&rxp->cq.ib, coalescing_timeo);
+ }
+}
+
+void
+bna_rx_dim_reconfig(struct bna *bna, const u32 vector[][BNA_BIAS_T_MAX])
+{
+ int i, j;
+
+ for (i = 0; i < BNA_LOAD_T_MAX; i++)
+ for (j = 0; j < BNA_BIAS_T_MAX; j++)
+ bna->rx_mod.dim_vector[i][j] = vector[i][j];
+}
+
+void
+bna_rx_dim_update(struct bna_ccb *ccb)
+{
+ struct bna *bna = ccb->cq->rx->bna;
+ u32 load, bias;
+ u32 pkt_rt, small_rt, large_rt;
+ u8 coalescing_timeo;
+
+ if ((ccb->pkt_rate.small_pkt_cnt == 0) &&
+ (ccb->pkt_rate.large_pkt_cnt == 0))
+ return;
+
+ /* Arrive at preconfigured coalescing timeo value based on pkt rate */
+
+ small_rt = ccb->pkt_rate.small_pkt_cnt;
+ large_rt = ccb->pkt_rate.large_pkt_cnt;
+
+ pkt_rt = small_rt + large_rt;
+
+ if (pkt_rt < BNA_PKT_RATE_10K)
+ load = BNA_LOAD_T_LOW_4;
+ else if (pkt_rt < BNA_PKT_RATE_20K)
+ load = BNA_LOAD_T_LOW_3;
+ else if (pkt_rt < BNA_PKT_RATE_30K)
+ load = BNA_LOAD_T_LOW_2;
+ else if (pkt_rt < BNA_PKT_RATE_40K)
+ load = BNA_LOAD_T_LOW_1;
+ else if (pkt_rt < BNA_PKT_RATE_50K)
+ load = BNA_LOAD_T_HIGH_1;
+ else if (pkt_rt < BNA_PKT_RATE_60K)
+ load = BNA_LOAD_T_HIGH_2;
+ else if (pkt_rt < BNA_PKT_RATE_80K)
+ load = BNA_LOAD_T_HIGH_3;
+ else
+ load = BNA_LOAD_T_HIGH_4;
+
+ if (small_rt > (large_rt << 1))
+ bias = 0;
+ else
+ bias = 1;
+
+ ccb->pkt_rate.small_pkt_cnt = 0;
+ ccb->pkt_rate.large_pkt_cnt = 0;
+
+ coalescing_timeo = bna->rx_mod.dim_vector[load][bias];
+ ccb->rx_coalescing_timeo = coalescing_timeo;
+
+ /* Set it to IB */
+ bna_ib_coalescing_timeo_set(&ccb->cq->ib, coalescing_timeo);
+}
+
+const u32 bna_napi_dim_vector[BNA_LOAD_T_MAX][BNA_BIAS_T_MAX] = {
+ {12, 12},
+ {6, 10},
+ {5, 10},
+ {4, 8},
+ {3, 6},
+ {3, 6},
+ {2, 4},
+ {1, 2},
+};
+
+/**
+ * TX
+ */
+#define call_tx_stop_cbfn(tx) \
+do { \
+ if ((tx)->stop_cbfn) { \
+ void (*cbfn)(void *, struct bna_tx *); \
+ void *cbarg; \
+ cbfn = (tx)->stop_cbfn; \
+ cbarg = (tx)->stop_cbarg; \
+ (tx)->stop_cbfn = NULL; \
+ (tx)->stop_cbarg = NULL; \
+ cbfn(cbarg, (tx)); \
+ } \
+} while (0)
+
+#define call_tx_prio_change_cbfn(tx) \
+do { \
+ if ((tx)->prio_change_cbfn) { \
+ void (*cbfn)(struct bnad *, struct bna_tx *); \
+ cbfn = (tx)->prio_change_cbfn; \
+ (tx)->prio_change_cbfn = NULL; \
+ cbfn((tx)->bna->bnad, (tx)); \
+ } \
+} while (0)
+
+static void bna_tx_mod_cb_tx_stopped(void *tx_mod, struct bna_tx *tx);
+static void bna_bfi_tx_enet_start(struct bna_tx *tx);
+static void bna_tx_enet_stop(struct bna_tx *tx);
+
+enum bna_tx_event {
+ TX_E_START = 1,
+ TX_E_STOP = 2,
+ TX_E_FAIL = 3,
+ TX_E_STARTED = 4,
+ TX_E_STOPPED = 5,
+ TX_E_PRIO_CHANGE = 6,
+ TX_E_CLEANUP_DONE = 7,
+ TX_E_BW_UPDATE = 8,
+};
+
+bfa_fsm_state_decl(bna_tx, stopped, struct bna_tx, enum bna_tx_event);
+bfa_fsm_state_decl(bna_tx, start_wait, struct bna_tx, enum bna_tx_event);
+bfa_fsm_state_decl(bna_tx, started, struct bna_tx, enum bna_tx_event);
+bfa_fsm_state_decl(bna_tx, stop_wait, struct bna_tx, enum bna_tx_event);
+bfa_fsm_state_decl(bna_tx, cleanup_wait, struct bna_tx,
+ enum bna_tx_event);
+bfa_fsm_state_decl(bna_tx, prio_stop_wait, struct bna_tx,
+ enum bna_tx_event);
+bfa_fsm_state_decl(bna_tx, prio_cleanup_wait, struct bna_tx,
+ enum bna_tx_event);
+bfa_fsm_state_decl(bna_tx, failed, struct bna_tx, enum bna_tx_event);
+bfa_fsm_state_decl(bna_tx, quiesce_wait, struct bna_tx,
+ enum bna_tx_event);
+
+static void
+bna_tx_sm_stopped_entry(struct bna_tx *tx)
+{
+ call_tx_stop_cbfn(tx);
+}
+
+static void
+bna_tx_sm_stopped(struct bna_tx *tx, enum bna_tx_event event)
+{
+ switch (event) {
+ case TX_E_START:
+ bfa_fsm_set_state(tx, bna_tx_sm_start_wait);
+ break;
+
+ case TX_E_STOP:
+ call_tx_stop_cbfn(tx);
+ break;
+
+ case TX_E_FAIL:
+ /* No-op */
+ break;
+
+ case TX_E_PRIO_CHANGE:
+ call_tx_prio_change_cbfn(tx);
+ break;
+
+ case TX_E_BW_UPDATE:
+ /* No-op */
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_tx_sm_start_wait_entry(struct bna_tx *tx)
+{
+ bna_bfi_tx_enet_start(tx);
+}
+
+static void
+bna_tx_sm_start_wait(struct bna_tx *tx, enum bna_tx_event event)
+{
+ switch (event) {
+ case TX_E_STOP:
+ tx->flags &= ~(BNA_TX_F_PRIO_CHANGED | BNA_TX_F_BW_UPDATED);
+ bfa_fsm_set_state(tx, bna_tx_sm_stop_wait);
+ break;
+
+ case TX_E_FAIL:
+ tx->flags &= ~(BNA_TX_F_PRIO_CHANGED | BNA_TX_F_BW_UPDATED);
+ bfa_fsm_set_state(tx, bna_tx_sm_stopped);
+ break;
+
+ case TX_E_STARTED:
+ if (tx->flags & (BNA_TX_F_PRIO_CHANGED | BNA_TX_F_BW_UPDATED)) {
+ tx->flags &= ~(BNA_TX_F_PRIO_CHANGED |
+ BNA_TX_F_BW_UPDATED);
+ bfa_fsm_set_state(tx, bna_tx_sm_prio_stop_wait);
+ } else
+ bfa_fsm_set_state(tx, bna_tx_sm_started);
+ break;
+
+ case TX_E_PRIO_CHANGE:
+ tx->flags |= BNA_TX_F_PRIO_CHANGED;
+ break;
+
+ case TX_E_BW_UPDATE:
+ tx->flags |= BNA_TX_F_BW_UPDATED;
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_tx_sm_started_entry(struct bna_tx *tx)
+{
+ struct bna_txq *txq;
+ struct list_head *qe;
+ int is_regular = (tx->type == BNA_TX_T_REGULAR);
+
+ list_for_each(qe, &tx->txq_q) {
+ txq = (struct bna_txq *)qe;
+ txq->tcb->priority = txq->priority;
+ /* Start IB */
+ bna_ib_start(tx->bna, &txq->ib, is_regular);
+ }
+ tx->tx_resume_cbfn(tx->bna->bnad, tx);
+}
+
+static void
+bna_tx_sm_started(struct bna_tx *tx, enum bna_tx_event event)
+{
+ switch (event) {
+ case TX_E_STOP:
+ bfa_fsm_set_state(tx, bna_tx_sm_stop_wait);
+ tx->tx_stall_cbfn(tx->bna->bnad, tx);
+ bna_tx_enet_stop(tx);
+ break;
+
+ case TX_E_FAIL:
+ bfa_fsm_set_state(tx, bna_tx_sm_failed);
+ tx->tx_stall_cbfn(tx->bna->bnad, tx);
+ tx->tx_cleanup_cbfn(tx->bna->bnad, tx);
+ break;
+
+ case TX_E_PRIO_CHANGE:
+ case TX_E_BW_UPDATE:
+ bfa_fsm_set_state(tx, bna_tx_sm_prio_stop_wait);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_tx_sm_stop_wait_entry(struct bna_tx *tx)
+{
+}
+
+static void
+bna_tx_sm_stop_wait(struct bna_tx *tx, enum bna_tx_event event)
+{
+ switch (event) {
+ case TX_E_FAIL:
+ case TX_E_STOPPED:
+ bfa_fsm_set_state(tx, bna_tx_sm_cleanup_wait);
+ tx->tx_cleanup_cbfn(tx->bna->bnad, tx);
+ break;
+
+ case TX_E_STARTED:
+ /**
+ * We are here due to start_wait -> stop_wait transition on
+ * TX_E_STOP event
+ */
+ bna_tx_enet_stop(tx);
+ break;
+
+ case TX_E_PRIO_CHANGE:
+ case TX_E_BW_UPDATE:
+ /* No-op */
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_tx_sm_cleanup_wait_entry(struct bna_tx *tx)
+{
+}
+
+static void
+bna_tx_sm_cleanup_wait(struct bna_tx *tx, enum bna_tx_event event)
+{
+ switch (event) {
+ case TX_E_FAIL:
+ case TX_E_PRIO_CHANGE:
+ case TX_E_BW_UPDATE:
+ /* No-op */
+ break;
+
+ case TX_E_CLEANUP_DONE:
+ bfa_fsm_set_state(tx, bna_tx_sm_stopped);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_tx_sm_prio_stop_wait_entry(struct bna_tx *tx)
+{
+ tx->tx_stall_cbfn(tx->bna->bnad, tx);
+ bna_tx_enet_stop(tx);
+}
+
+static void
+bna_tx_sm_prio_stop_wait(struct bna_tx *tx, enum bna_tx_event event)
+{
+ switch (event) {
+ case TX_E_STOP:
+ bfa_fsm_set_state(tx, bna_tx_sm_stop_wait);
+ break;
+
+ case TX_E_FAIL:
+ bfa_fsm_set_state(tx, bna_tx_sm_failed);
+ call_tx_prio_change_cbfn(tx);
+ tx->tx_cleanup_cbfn(tx->bna->bnad, tx);
+ break;
+
+ case TX_E_STOPPED:
+ bfa_fsm_set_state(tx, bna_tx_sm_prio_cleanup_wait);
+ break;
+
+ case TX_E_PRIO_CHANGE:
+ case TX_E_BW_UPDATE:
+ /* No-op */
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_tx_sm_prio_cleanup_wait_entry(struct bna_tx *tx)
+{
+ call_tx_prio_change_cbfn(tx);
+ tx->tx_cleanup_cbfn(tx->bna->bnad, tx);
+}
+
+static void
+bna_tx_sm_prio_cleanup_wait(struct bna_tx *tx, enum bna_tx_event event)
+{
+ switch (event) {
+ case TX_E_STOP:
+ bfa_fsm_set_state(tx, bna_tx_sm_cleanup_wait);
+ break;
+
+ case TX_E_FAIL:
+ bfa_fsm_set_state(tx, bna_tx_sm_failed);
+ break;
+
+ case TX_E_PRIO_CHANGE:
+ case TX_E_BW_UPDATE:
+ /* No-op */
+ break;
+
+ case TX_E_CLEANUP_DONE:
+ bfa_fsm_set_state(tx, bna_tx_sm_start_wait);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_tx_sm_failed_entry(struct bna_tx *tx)
+{
+}
+
+static void
+bna_tx_sm_failed(struct bna_tx *tx, enum bna_tx_event event)
+{
+ switch (event) {
+ case TX_E_START:
+ bfa_fsm_set_state(tx, bna_tx_sm_quiesce_wait);
+ break;
+
+ case TX_E_STOP:
+ bfa_fsm_set_state(tx, bna_tx_sm_cleanup_wait);
+ break;
+
+ case TX_E_FAIL:
+ /* No-op */
+ break;
+
+ case TX_E_CLEANUP_DONE:
+ bfa_fsm_set_state(tx, bna_tx_sm_stopped);
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_tx_sm_quiesce_wait_entry(struct bna_tx *tx)
+{
+}
+
+static void
+bna_tx_sm_quiesce_wait(struct bna_tx *tx, enum bna_tx_event event)
+{
+ switch (event) {
+ case TX_E_STOP:
+ bfa_fsm_set_state(tx, bna_tx_sm_cleanup_wait);
+ break;
+
+ case TX_E_FAIL:
+ bfa_fsm_set_state(tx, bna_tx_sm_failed);
+ break;
+
+ case TX_E_CLEANUP_DONE:
+ bfa_fsm_set_state(tx, bna_tx_sm_start_wait);
+ break;
+
+ case TX_E_BW_UPDATE:
+ /* No-op */
+ break;
+
+ default:
+ bfa_sm_fault(event);
+ }
+}
+
+static void
+bna_bfi_tx_enet_start(struct bna_tx *tx)
+{
+ struct bfi_enet_tx_cfg_req *cfg_req = &tx->bfi_enet_cmd.cfg_req;
+ struct bna_txq *txq = NULL;
+ struct list_head *qe;
+ int i;
+
+ bfi_msgq_mhdr_set(cfg_req->mh, BFI_MC_ENET,
+ BFI_ENET_H2I_TX_CFG_SET_REQ, 0, tx->rid);
+ cfg_req->mh.num_entries = htons(
+ bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_tx_cfg_req)));
+
+ cfg_req->num_queues = tx->num_txq;
+ for (i = 0, qe = bfa_q_first(&tx->txq_q);
+ i < tx->num_txq;
+ i++, qe = bfa_q_next(qe)) {
+ txq = (struct bna_txq *)qe;
+
+ bfi_enet_datapath_q_init(&cfg_req->q_cfg[i].q.q, &txq->qpt);
+ cfg_req->q_cfg[i].q.priority = txq->priority;
+
+ cfg_req->q_cfg[i].ib.index_addr.a32.addr_lo =
+ txq->ib.ib_seg_host_addr.lsb;
+ cfg_req->q_cfg[i].ib.index_addr.a32.addr_hi =
+ txq->ib.ib_seg_host_addr.msb;
+ cfg_req->q_cfg[i].ib.intr.msix_index =
+ htons((u16)txq->ib.intr_vector);
+ }
+
+ cfg_req->ib_cfg.int_pkt_dma = BNA_STATUS_T_ENABLED;
+ cfg_req->ib_cfg.int_enabled = BNA_STATUS_T_ENABLED;
+ cfg_req->ib_cfg.int_pkt_enabled = BNA_STATUS_T_DISABLED;
+ cfg_req->ib_cfg.continuous_coalescing = BNA_STATUS_T_ENABLED;
+ cfg_req->ib_cfg.msix = (txq->ib.intr_type == BNA_INTR_T_MSIX)
+ ? BNA_STATUS_T_ENABLED : BNA_STATUS_T_DISABLED;
+ cfg_req->ib_cfg.coalescing_timeout =
+ htonl((u32)txq->ib.coalescing_timeo);
+ cfg_req->ib_cfg.inter_pkt_timeout =
+ htonl((u32)txq->ib.interpkt_timeo);
+ cfg_req->ib_cfg.inter_pkt_count = (u8)txq->ib.interpkt_count;
+
+ cfg_req->tx_cfg.vlan_mode = BFI_ENET_TX_VLAN_WI;
+ cfg_req->tx_cfg.vlan_id = htons((u16)tx->txf_vlan_id);
+ cfg_req->tx_cfg.admit_tagged_frame = BNA_STATUS_T_DISABLED;
+ cfg_req->tx_cfg.apply_vlan_filter = BNA_STATUS_T_DISABLED;
+
+ bfa_msgq_cmd_set(&tx->msgq_cmd, NULL, NULL,
+ sizeof(struct bfi_enet_tx_cfg_req), &cfg_req->mh);
+ bfa_msgq_cmd_post(&tx->bna->msgq, &tx->msgq_cmd);
+}
+
+static void
+bna_bfi_tx_enet_stop(struct bna_tx *tx)
+{
+ struct bfi_enet_req *req = &tx->bfi_enet_cmd.req;
+
+ bfi_msgq_mhdr_set(req->mh, BFI_MC_ENET,
+ BFI_ENET_H2I_TX_CFG_CLR_REQ, 0, tx->rid);
+ req->mh.num_entries = htons(
+ bfi_msgq_num_cmd_entries(sizeof(struct bfi_enet_req)));
+ bfa_msgq_cmd_set(&tx->msgq_cmd, NULL, NULL, sizeof(struct bfi_enet_req),
+ &req->mh);
+ bfa_msgq_cmd_post(&tx->bna->msgq, &tx->msgq_cmd);
+}
+
+static void
+bna_tx_enet_stop(struct bna_tx *tx)
+{
+ struct bna_txq *txq;
+ struct list_head *qe;
+
+ /* Stop IB */
+ list_for_each(qe, &tx->txq_q) {
+ txq = (struct bna_txq *)qe;
+ bna_ib_stop(tx->bna, &txq->ib);
+ }
+
+ bna_bfi_tx_enet_stop(tx);
+}
+
+static void
+bna_txq_qpt_setup(struct bna_txq *txq, int page_count, int page_size,
+ struct bna_mem_descr *qpt_mem,
+ struct bna_mem_descr *swqpt_mem,
+ struct bna_mem_descr *page_mem)
+{
+ int i;
+
+ txq->qpt.hw_qpt_ptr.lsb = qpt_mem->dma.lsb;
+ txq->qpt.hw_qpt_ptr.msb = qpt_mem->dma.msb;
+ txq->qpt.kv_qpt_ptr = qpt_mem->kva;
+ txq->qpt.page_count = page_count;
+ txq->qpt.page_size = page_size;
+
+ txq->tcb->sw_qpt = (void **) swqpt_mem->kva;
+
+ for (i = 0; i < page_count; i++) {
+ txq->tcb->sw_qpt[i] = page_mem[i].kva;
+
+ ((struct bna_dma_addr *)txq->qpt.kv_qpt_ptr)[i].lsb =
+ page_mem[i].dma.lsb;
+ ((struct bna_dma_addr *)txq->qpt.kv_qpt_ptr)[i].msb =
+ page_mem[i].dma.msb;
+ }
+}
+
+static struct bna_tx *
+bna_tx_get(struct bna_tx_mod *tx_mod, enum bna_tx_type type)
+{
+ struct list_head *qe = NULL;
+ struct bna_tx *tx = NULL;
+
+ if (list_empty(&tx_mod->tx_free_q))
+ return NULL;
+ if (type == BNA_TX_T_REGULAR) {
+ bfa_q_deq(&tx_mod->tx_free_q, &qe);
+ } else {
+ bfa_q_deq_tail(&tx_mod->tx_free_q, &qe);
+ }
+ tx = (struct bna_tx *)qe;
+ bfa_q_qe_init(&tx->qe);
+ tx->type = type;
+
+ return tx;
+}
+
+static void
+bna_tx_free(struct bna_tx *tx)
+{
+ struct bna_tx_mod *tx_mod = &tx->bna->tx_mod;
+ struct bna_txq *txq;
+ struct list_head *prev_qe;
+ struct list_head *qe;
+
+ while (!list_empty(&tx->txq_q)) {
+ bfa_q_deq(&tx->txq_q, &txq);
+ bfa_q_qe_init(&txq->qe);
+ txq->tcb = NULL;
+ txq->tx = NULL;
+ list_add_tail(&txq->qe, &tx_mod->txq_free_q);
+ }
+
+ list_for_each(qe, &tx_mod->tx_active_q) {
+ if (qe == &tx->qe) {
+ list_del(&tx->qe);
+ bfa_q_qe_init(&tx->qe);
+ break;
+ }
+ }
+
+ tx->bna = NULL;
+ tx->priv = NULL;
+
+ prev_qe = NULL;
+ list_for_each(qe, &tx_mod->tx_free_q) {
+ if (((struct bna_tx *)qe)->rid < tx->rid)
+ prev_qe = qe;
+ else {
+ break;
+ }
+ }
+
+ if (prev_qe == NULL) {
+ /* This is the first entry */
+ bfa_q_enq_head(&tx_mod->tx_free_q, &tx->qe);
+ } else if (bfa_q_next(prev_qe) == &tx_mod->tx_free_q) {
+ /* This is the last entry */
+ list_add_tail(&tx->qe, &tx_mod->tx_free_q);
+ } else {
+ /* Somewhere in the middle */
+ bfa_q_next(&tx->qe) = bfa_q_next(prev_qe);
+ bfa_q_prev(&tx->qe) = prev_qe;
+ bfa_q_next(prev_qe) = &tx->qe;
+ bfa_q_prev(bfa_q_next(&tx->qe)) = &tx->qe;
+ }
+}
+
+static void
+bna_tx_start(struct bna_tx *tx)
+{
+ tx->flags |= BNA_TX_F_ENET_STARTED;
+ if (tx->flags & BNA_TX_F_ENABLED)
+ bfa_fsm_send_event(tx, TX_E_START);
+}
+
+static void
+bna_tx_stop(struct bna_tx *tx)
+{
+ tx->stop_cbfn = bna_tx_mod_cb_tx_stopped;
+ tx->stop_cbarg = &tx->bna->tx_mod;
+
+ tx->flags &= ~BNA_TX_F_ENET_STARTED;
+ bfa_fsm_send_event(tx, TX_E_STOP);
+}
+
+static void
+bna_tx_fail(struct bna_tx *tx)
+{
+ tx->flags &= ~BNA_TX_F_ENET_STARTED;
+ bfa_fsm_send_event(tx, TX_E_FAIL);
+}
+
+void
+bna_bfi_tx_enet_start_rsp(struct bna_tx *tx, struct bfi_msgq_mhdr *msghdr)
+{
+ struct bfi_enet_tx_cfg_rsp *cfg_rsp = &tx->bfi_enet_cmd.cfg_rsp;
+ struct bna_txq *txq = NULL;
+ struct list_head *qe;
+ int i;
+
+ bfa_msgq_rsp_copy(&tx->bna->msgq, (u8 *)cfg_rsp,
+ sizeof(struct bfi_enet_tx_cfg_rsp));
+
+ tx->hw_id = cfg_rsp->hw_id;
+
+ for (i = 0, qe = bfa_q_first(&tx->txq_q);
+ i < tx->num_txq; i++, qe = bfa_q_next(qe)) {
+ txq = (struct bna_txq *)qe;
+
+ /* Setup doorbells */
+ txq->tcb->i_dbell->doorbell_addr =
+ tx->bna->pcidev.pci_bar_kva
+ + ntohl(cfg_rsp->q_handles[i].i_dbell);
+ txq->tcb->q_dbell =
+ tx->bna->pcidev.pci_bar_kva
+ + ntohl(cfg_rsp->q_handles[i].q_dbell);
+ txq->hw_id = cfg_rsp->q_handles[i].hw_qid;
+
+ /* Initialize producer/consumer indexes */
+ (*txq->tcb->hw_consumer_index) = 0;
+ txq->tcb->producer_index = txq->tcb->consumer_index = 0;
+ }
+
+ bfa_fsm_send_event(tx, TX_E_STARTED);
+}
+
+void
+bna_bfi_tx_enet_stop_rsp(struct bna_tx *tx, struct bfi_msgq_mhdr *msghdr)
+{
+ bfa_fsm_send_event(tx, TX_E_STOPPED);
+}
+
+void
+bna_bfi_bw_update_aen(struct bna_tx_mod *tx_mod)
+{
+ struct bna_tx *tx;
+ struct list_head *qe;
+
+ list_for_each(qe, &tx_mod->tx_active_q) {
+ tx = (struct bna_tx *)qe;
+ bfa_fsm_send_event(tx, TX_E_BW_UPDATE);
+ }
+}
+
+void
+bna_tx_res_req(int num_txq, int txq_depth, struct bna_res_info *res_info)
+{
+ u32 q_size;
+ u32 page_count;
+ struct bna_mem_info *mem_info;
+
+ res_info[BNA_TX_RES_MEM_T_TCB].res_type = BNA_RES_T_MEM;
+ mem_info = &res_info[BNA_TX_RES_MEM_T_TCB].res_u.mem_info;
+ mem_info->mem_type = BNA_MEM_T_KVA;
+ mem_info->len = sizeof(struct bna_tcb);
+ mem_info->num = num_txq;
+
+ q_size = txq_depth * BFI_TXQ_WI_SIZE;
+ q_size = ALIGN(q_size, PAGE_SIZE);
+ page_count = q_size >> PAGE_SHIFT;
+
+ res_info[BNA_TX_RES_MEM_T_QPT].res_type = BNA_RES_T_MEM;
+ mem_info = &res_info[BNA_TX_RES_MEM_T_QPT].res_u.mem_info;
+ mem_info->mem_type = BNA_MEM_T_DMA;
+ mem_info->len = page_count * sizeof(struct bna_dma_addr);
+ mem_info->num = num_txq;
+
+ res_info[BNA_TX_RES_MEM_T_SWQPT].res_type = BNA_RES_T_MEM;
+ mem_info = &res_info[BNA_TX_RES_MEM_T_SWQPT].res_u.mem_info;
+ mem_info->mem_type = BNA_MEM_T_KVA;
+ mem_info->len = page_count * sizeof(void *);
+ mem_info->num = num_txq;
+
+ res_info[BNA_TX_RES_MEM_T_PAGE].res_type = BNA_RES_T_MEM;
+ mem_info = &res_info[BNA_TX_RES_MEM_T_PAGE].res_u.mem_info;
+ mem_info->mem_type = BNA_MEM_T_DMA;
+ mem_info->len = PAGE_SIZE;
+ mem_info->num = num_txq * page_count;
+
+ res_info[BNA_TX_RES_MEM_T_IBIDX].res_type = BNA_RES_T_MEM;
+ mem_info = &res_info[BNA_TX_RES_MEM_T_IBIDX].res_u.mem_info;
+ mem_info->mem_type = BNA_MEM_T_DMA;
+ mem_info->len = BFI_IBIDX_SIZE;
+ mem_info->num = num_txq;
+
+ res_info[BNA_TX_RES_INTR_T_TXCMPL].res_type = BNA_RES_T_INTR;
+ res_info[BNA_TX_RES_INTR_T_TXCMPL].res_u.intr_info.intr_type =
+ BNA_INTR_T_MSIX;
+ res_info[BNA_TX_RES_INTR_T_TXCMPL].res_u.intr_info.num = num_txq;
+}
+
+struct bna_tx *
+bna_tx_create(struct bna *bna, struct bnad *bnad,
+ struct bna_tx_config *tx_cfg,
+ const struct bna_tx_event_cbfn *tx_cbfn,
+ struct bna_res_info *res_info, void *priv)
+{
+ struct bna_intr_info *intr_info;
+ struct bna_tx_mod *tx_mod = &bna->tx_mod;
+ struct bna_tx *tx;
+ struct bna_txq *txq;
+ struct list_head *qe;
+ int page_count;
+ int page_size;
+ int page_idx;
+ int i;
+
+ intr_info = &res_info[BNA_TX_RES_INTR_T_TXCMPL].res_u.intr_info;
+ page_count = (res_info[BNA_TX_RES_MEM_T_PAGE].res_u.mem_info.num) /
+ tx_cfg->num_txq;
+ page_size = res_info[BNA_TX_RES_MEM_T_PAGE].res_u.mem_info.len;
+
+ /**
+ * Get resources
+ */
+
+ if ((intr_info->num != 1) && (intr_info->num != tx_cfg->num_txq))
+ return NULL;
+
+ /* Tx */
+
+ tx = bna_tx_get(tx_mod, tx_cfg->tx_type);
+ if (!tx)
+ return NULL;
+ tx->bna = bna;
+ tx->priv = priv;
+
+ /* TxQs */
+
+ INIT_LIST_HEAD(&tx->txq_q);
+ for (i = 0; i < tx_cfg->num_txq; i++) {
+ if (list_empty(&tx_mod->txq_free_q))
+ goto err_return;
+
+ bfa_q_deq(&tx_mod->txq_free_q, &txq);
+ bfa_q_qe_init(&txq->qe);
+ list_add_tail(&txq->qe, &tx->txq_q);
+ txq->tx = tx;
+ }
+
+ /*
+ * Initialize
+ */
+
+ /* Tx */
+
+ tx->tcb_setup_cbfn = tx_cbfn->tcb_setup_cbfn;
+ tx->tcb_destroy_cbfn = tx_cbfn->tcb_destroy_cbfn;
+ /* Following callbacks are mandatory */
+ tx->tx_stall_cbfn = tx_cbfn->tx_stall_cbfn;
+ tx->tx_resume_cbfn = tx_cbfn->tx_resume_cbfn;
+ tx->tx_cleanup_cbfn = tx_cbfn->tx_cleanup_cbfn;
+
+ list_add_tail(&tx->qe, &tx_mod->tx_active_q);
+
+ tx->num_txq = tx_cfg->num_txq;
+
+ tx->flags = 0;
+ if (tx->bna->tx_mod.flags & BNA_TX_MOD_F_ENET_STARTED) {
+ switch (tx->type) {
+ case BNA_TX_T_REGULAR:
+ if (!(tx->bna->tx_mod.flags &
+ BNA_TX_MOD_F_ENET_LOOPBACK))
+ tx->flags |= BNA_TX_F_ENET_STARTED;
+ break;
+ case BNA_TX_T_LOOPBACK:
+ if (tx->bna->tx_mod.flags & BNA_TX_MOD_F_ENET_LOOPBACK)
+ tx->flags |= BNA_TX_F_ENET_STARTED;
+ break;
+ }
+ }
+
+ /* TxQ */
+
+ i = 0;
+ page_idx = 0;
+ list_for_each(qe, &tx->txq_q) {
+ txq = (struct bna_txq *)qe;
+ txq->tcb = (struct bna_tcb *)
+ res_info[BNA_TX_RES_MEM_T_TCB].res_u.mem_info.mdl[i].kva;
+ txq->tx_packets = 0;
+ txq->tx_bytes = 0;
+
+ /* IB */
+ txq->ib.ib_seg_host_addr.lsb =
+ res_info[BNA_TX_RES_MEM_T_IBIDX].res_u.mem_info.mdl[i].dma.lsb;
+ txq->ib.ib_seg_host_addr.msb =
+ res_info[BNA_TX_RES_MEM_T_IBIDX].res_u.mem_info.mdl[i].dma.msb;
+ txq->ib.ib_seg_host_addr_kva =
+ res_info[BNA_TX_RES_MEM_T_IBIDX].res_u.mem_info.mdl[i].kva;
+ txq->ib.intr_type = intr_info->intr_type;
+ txq->ib.intr_vector = (intr_info->num == 1) ?
+ intr_info->idl[0].vector :
+ intr_info->idl[i].vector;
+ if (intr_info->intr_type == BNA_INTR_T_INTX)
+ txq->ib.intr_vector = (1 << txq->ib.intr_vector);
+ txq->ib.coalescing_timeo = tx_cfg->coalescing_timeo;
+ txq->ib.interpkt_timeo = 0; /* Not used */
+ txq->ib.interpkt_count = BFI_TX_INTERPKT_COUNT;
+
+ /* TCB */
+
+ txq->tcb->q_depth = tx_cfg->txq_depth;
+ txq->tcb->unmap_q = (void *)
+ res_info[BNA_TX_RES_MEM_T_UNMAPQ].res_u.mem_info.mdl[i].kva;
+ txq->tcb->hw_consumer_index =
+ (u32 *)txq->ib.ib_seg_host_addr_kva;
+ txq->tcb->i_dbell = &txq->ib.door_bell;
+ txq->tcb->intr_type = txq->ib.intr_type;
+ txq->tcb->intr_vector = txq->ib.intr_vector;
+ txq->tcb->txq = txq;
+ txq->tcb->bnad = bnad;
+ txq->tcb->id = i;
+
+ /* QPT, SWQPT, Pages */
+ bna_txq_qpt_setup(txq, page_count, page_size,
+ &res_info[BNA_TX_RES_MEM_T_QPT].res_u.mem_info.mdl[i],
+ &res_info[BNA_TX_RES_MEM_T_SWQPT].res_u.mem_info.mdl[i],
+ &res_info[BNA_TX_RES_MEM_T_PAGE].
+ res_u.mem_info.mdl[page_idx]);
+ txq->tcb->page_idx = page_idx;
+ txq->tcb->page_count = page_count;
+ page_idx += page_count;
+
+ /* Callback to bnad for setting up TCB */
+ if (tx->tcb_setup_cbfn)
+ (tx->tcb_setup_cbfn)(bna->bnad, txq->tcb);
+
+ if (tx_cfg->num_txq == BFI_TX_MAX_PRIO)
+ txq->priority = txq->tcb->id;
+ else
+ txq->priority = tx_mod->default_prio;
+
+ i++;
+ }
+
+ tx->txf_vlan_id = 0;
+
+ bfa_fsm_set_state(tx, bna_tx_sm_stopped);
+
+ tx_mod->rid_mask |= (1 << tx->rid);
+
+ return tx;
+
+err_return:
+ bna_tx_free(tx);
+ return NULL;
+}
+
+void
+bna_tx_destroy(struct bna_tx *tx)
+{
+ struct bna_txq *txq;
+ struct list_head *qe;
+
+ list_for_each(qe, &tx->txq_q) {
+ txq = (struct bna_txq *)qe;
+ if (tx->tcb_destroy_cbfn)
+ (tx->tcb_destroy_cbfn)(tx->bna->bnad, txq->tcb);
+ }
+
+ tx->bna->tx_mod.rid_mask &= ~(1 << tx->rid);
+ bna_tx_free(tx);
+}
+
+void
+bna_tx_enable(struct bna_tx *tx)
+{
+ if (tx->fsm != (bfa_sm_t)bna_tx_sm_stopped)
+ return;
+
+ tx->flags |= BNA_TX_F_ENABLED;
+
+ if (tx->flags & BNA_TX_F_ENET_STARTED)
+ bfa_fsm_send_event(tx, TX_E_START);
+}
+
+void
+bna_tx_disable(struct bna_tx *tx, enum bna_cleanup_type type,
+ void (*cbfn)(void *, struct bna_tx *))
+{
+ if (type == BNA_SOFT_CLEANUP) {
+ (*cbfn)(tx->bna->bnad, tx);
+ return;
+ }
+
+ tx->stop_cbfn = cbfn;
+ tx->stop_cbarg = tx->bna->bnad;
+
+ tx->flags &= ~BNA_TX_F_ENABLED;
+
+ bfa_fsm_send_event(tx, TX_E_STOP);
+}
+
+void
+bna_tx_cleanup_complete(struct bna_tx *tx)
+{
+ bfa_fsm_send_event(tx, TX_E_CLEANUP_DONE);
+}
+
+static void
+bna_tx_mod_cb_tx_stopped(void *arg, struct bna_tx *tx)
+{
+ struct bna_tx_mod *tx_mod = (struct bna_tx_mod *)arg;
+
+ bfa_wc_down(&tx_mod->tx_stop_wc);
+}
+
+static void
+bna_tx_mod_cb_tx_stopped_all(void *arg)
+{
+ struct bna_tx_mod *tx_mod = (struct bna_tx_mod *)arg;
+
+ if (tx_mod->stop_cbfn)
+ tx_mod->stop_cbfn(&tx_mod->bna->enet);
+ tx_mod->stop_cbfn = NULL;
+}
+
+void
+bna_tx_mod_init(struct bna_tx_mod *tx_mod, struct bna *bna,
+ struct bna_res_info *res_info)
+{
+ int i;
+
+ tx_mod->bna = bna;
+ tx_mod->flags = 0;
+
+ tx_mod->tx = (struct bna_tx *)
+ res_info[BNA_MOD_RES_MEM_T_TX_ARRAY].res_u.mem_info.mdl[0].kva;
+ tx_mod->txq = (struct bna_txq *)
+ res_info[BNA_MOD_RES_MEM_T_TXQ_ARRAY].res_u.mem_info.mdl[0].kva;
+
+ INIT_LIST_HEAD(&tx_mod->tx_free_q);
+ INIT_LIST_HEAD(&tx_mod->tx_active_q);
+
+ INIT_LIST_HEAD(&tx_mod->txq_free_q);
+
+ for (i = 0; i < bna->ioceth.attr.num_txq; i++) {
+ tx_mod->tx[i].rid = i;
+ bfa_q_qe_init(&tx_mod->tx[i].qe);
+ list_add_tail(&tx_mod->tx[i].qe, &tx_mod->tx_free_q);
+ bfa_q_qe_init(&tx_mod->txq[i].qe);
+ list_add_tail(&tx_mod->txq[i].qe, &tx_mod->txq_free_q);
+ }
+
+ tx_mod->prio_map = BFI_TX_PRIO_MAP_ALL;
+ tx_mod->default_prio = 0;
+ tx_mod->iscsi_over_cee = BNA_STATUS_T_DISABLED;
+ tx_mod->iscsi_prio = -1;
+}
+
+void
+bna_tx_mod_uninit(struct bna_tx_mod *tx_mod)
+{
+ struct list_head *qe;
+ int i;
+
+ i = 0;
+ list_for_each(qe, &tx_mod->tx_free_q)
+ i++;
+
+ i = 0;
+ list_for_each(qe, &tx_mod->txq_free_q)
+ i++;
+
+ tx_mod->bna = NULL;
+}
+
+void
+bna_tx_mod_start(struct bna_tx_mod *tx_mod, enum bna_tx_type type)
+{
+ struct bna_tx *tx;
+ struct list_head *qe;
+
+ tx_mod->flags |= BNA_TX_MOD_F_ENET_STARTED;
+ if (type == BNA_TX_T_LOOPBACK)
+ tx_mod->flags |= BNA_TX_MOD_F_ENET_LOOPBACK;
+
+ list_for_each(qe, &tx_mod->tx_active_q) {
+ tx = (struct bna_tx *)qe;
+ if (tx->type == type)
+ bna_tx_start(tx);
+ }
+}
+
+void
+bna_tx_mod_stop(struct bna_tx_mod *tx_mod, enum bna_tx_type type)
+{
+ struct bna_tx *tx;
+ struct list_head *qe;
+
+ tx_mod->flags &= ~BNA_TX_MOD_F_ENET_STARTED;
+ tx_mod->flags &= ~BNA_TX_MOD_F_ENET_LOOPBACK;
+
+ tx_mod->stop_cbfn = bna_enet_cb_tx_stopped;
+
+ bfa_wc_init(&tx_mod->tx_stop_wc, bna_tx_mod_cb_tx_stopped_all, tx_mod);
+
+ list_for_each(qe, &tx_mod->tx_active_q) {
+ tx = (struct bna_tx *)qe;
+ if (tx->type == type) {
+ bfa_wc_up(&tx_mod->tx_stop_wc);
+ bna_tx_stop(tx);
+ }
+ }
+
+ bfa_wc_wait(&tx_mod->tx_stop_wc);
+}
+
+void
+bna_tx_mod_fail(struct bna_tx_mod *tx_mod)
+{
+ struct bna_tx *tx;
+ struct list_head *qe;
+
+ tx_mod->flags &= ~BNA_TX_MOD_F_ENET_STARTED;
+ tx_mod->flags &= ~BNA_TX_MOD_F_ENET_LOOPBACK;
+
+ list_for_each(qe, &tx_mod->tx_active_q) {
+ tx = (struct bna_tx *)qe;
+ bna_tx_fail(tx);
+ }
+}
+
+void
+bna_tx_coalescing_timeo_set(struct bna_tx *tx, int coalescing_timeo)
+{
+ struct bna_txq *txq;
+ struct list_head *qe;
+
+ list_for_each(qe, &tx->txq_q) {
+ txq = (struct bna_txq *)qe;
+ bna_ib_coalescing_timeo_set(&txq->ib, coalescing_timeo);
+ }
+}
diff --git a/drivers/net/bna/bna_types.h b/drivers/net/ethernet/brocade/bna/bna_types.h
index 2f89cb235248..d090fbfb12fa 100644
--- a/drivers/net/bna/bna_types.h
+++ b/drivers/net/ethernet/brocade/bna/bna_types.h
@@ -19,8 +19,9 @@
#define __BNA_TYPES_H__
#include "cna.h"
-#include "bna_hw.h"
+#include "bna_hw_defs.h"
#include "bfa_cee.h"
+#include "bfa_msgq.h"
/**
*
@@ -28,13 +29,14 @@
*
*/
+struct bna_mcam_handle;
struct bna_txq;
struct bna_tx;
struct bna_rxq;
struct bna_cq;
struct bna_rx;
struct bna_rxf;
-struct bna_port;
+struct bna_enet;
struct bna;
struct bnad;
@@ -86,31 +88,29 @@ enum bna_res_req_type {
BNA_RES_MEM_T_ATTR = 1,
BNA_RES_MEM_T_FWTRC = 2,
BNA_RES_MEM_T_STATS = 3,
- BNA_RES_MEM_T_SWSTATS = 4,
- BNA_RES_MEM_T_IBIDX = 5,
- BNA_RES_MEM_T_IB_ARRAY = 6,
- BNA_RES_MEM_T_INTR_ARRAY = 7,
- BNA_RES_MEM_T_IDXSEG_ARRAY = 8,
- BNA_RES_MEM_T_TX_ARRAY = 9,
- BNA_RES_MEM_T_TXQ_ARRAY = 10,
- BNA_RES_MEM_T_RX_ARRAY = 11,
- BNA_RES_MEM_T_RXP_ARRAY = 12,
- BNA_RES_MEM_T_RXQ_ARRAY = 13,
- BNA_RES_MEM_T_UCMAC_ARRAY = 14,
- BNA_RES_MEM_T_MCMAC_ARRAY = 15,
- BNA_RES_MEM_T_RIT_ENTRY = 16,
- BNA_RES_MEM_T_RIT_SEGMENT = 17,
- BNA_RES_INTR_T_MBOX = 18,
BNA_RES_T_MAX
};
+enum bna_mod_res_req_type {
+ BNA_MOD_RES_MEM_T_TX_ARRAY = 0,
+ BNA_MOD_RES_MEM_T_TXQ_ARRAY = 1,
+ BNA_MOD_RES_MEM_T_RX_ARRAY = 2,
+ BNA_MOD_RES_MEM_T_RXP_ARRAY = 3,
+ BNA_MOD_RES_MEM_T_RXQ_ARRAY = 4,
+ BNA_MOD_RES_MEM_T_UCMAC_ARRAY = 5,
+ BNA_MOD_RES_MEM_T_MCMAC_ARRAY = 6,
+ BNA_MOD_RES_MEM_T_MCHANDLE_ARRAY = 7,
+ BNA_MOD_RES_T_MAX
+};
+
enum bna_tx_res_req_type {
BNA_TX_RES_MEM_T_TCB = 0,
BNA_TX_RES_MEM_T_UNMAPQ = 1,
BNA_TX_RES_MEM_T_QPT = 2,
BNA_TX_RES_MEM_T_SWQPT = 3,
BNA_TX_RES_MEM_T_PAGE = 4,
- BNA_TX_RES_INTR_T_TXCMPL = 5,
+ BNA_TX_RES_MEM_T_IBIDX = 5,
+ BNA_TX_RES_INTR_T_TXCMPL = 6,
BNA_TX_RES_T_MAX,
};
@@ -127,13 +127,10 @@ enum bna_rx_mem_type {
BNA_RX_RES_MEM_T_DSWQPT = 9, /* RX s/w QPT */
BNA_RX_RES_MEM_T_DPAGE = 10, /* RX s/w QPT */
BNA_RX_RES_MEM_T_HPAGE = 11, /* RX s/w QPT */
- BNA_RX_RES_T_INTR = 12, /* Rx interrupts */
- BNA_RX_RES_T_MAX = 13
-};
-
-enum bna_mbox_state {
- BNA_MBOX_FREE = 0,
- BNA_MBOX_POSTED = 1
+ BNA_RX_RES_MEM_T_IBIDX = 12,
+ BNA_RX_RES_MEM_T_RIT = 13,
+ BNA_RX_RES_T_INTR = 14, /* Rx interrupts */
+ BNA_RX_RES_T_MAX = 15
};
enum bna_tx_type {
@@ -142,14 +139,15 @@ enum bna_tx_type {
};
enum bna_tx_flags {
- BNA_TX_F_PORT_STARTED = 1,
+ BNA_TX_F_ENET_STARTED = 1,
BNA_TX_F_ENABLED = 2,
- BNA_TX_F_PRIO_LOCK = 4,
+ BNA_TX_F_PRIO_CHANGED = 4,
+ BNA_TX_F_BW_UPDATED = 8,
};
enum bna_tx_mod_flags {
- BNA_TX_MOD_F_PORT_STARTED = 1,
- BNA_TX_MOD_F_PORT_LOOPBACK = 2,
+ BNA_TX_MOD_F_ENET_STARTED = 1,
+ BNA_TX_MOD_F_ENET_LOOPBACK = 2,
};
enum bna_rx_type {
@@ -165,80 +163,49 @@ enum bna_rxp_type {
enum bna_rxmode {
BNA_RXMODE_PROMISC = 1,
- BNA_RXMODE_ALLMULTI = 2
+ BNA_RXMODE_DEFAULT = 2,
+ BNA_RXMODE_ALLMULTI = 4
};
enum bna_rx_event {
RX_E_START = 1,
RX_E_STOP = 2,
RX_E_FAIL = 3,
- RX_E_RXF_STARTED = 4,
- RX_E_RXF_STOPPED = 5,
- RX_E_RXQ_STOPPED = 6,
-};
-
-enum bna_rx_state {
- BNA_RX_STOPPED = 1,
- BNA_RX_RXF_START_WAIT = 2,
- BNA_RX_STARTED = 3,
- BNA_RX_RXF_STOP_WAIT = 4,
- BNA_RX_RXQ_STOP_WAIT = 5,
+ RX_E_STARTED = 4,
+ RX_E_STOPPED = 5,
+ RX_E_RXF_STARTED = 6,
+ RX_E_RXF_STOPPED = 7,
+ RX_E_CLEANUP_DONE = 8,
};
enum bna_rx_flags {
- BNA_RX_F_ENABLE = 0x01, /* bnad enabled rxf */
- BNA_RX_F_PORT_ENABLED = 0x02, /* Port object is enabled */
- BNA_RX_F_PORT_FAILED = 0x04, /* Port in failed state */
+ BNA_RX_F_ENET_STARTED = 1,
+ BNA_RX_F_ENABLED = 2,
};
enum bna_rx_mod_flags {
- BNA_RX_MOD_F_PORT_STARTED = 1,
- BNA_RX_MOD_F_PORT_LOOPBACK = 2,
-};
-
-enum bna_rxf_oper_state {
- BNA_RXF_OPER_STATE_RUNNING = 0x01, /* rxf operational */
- BNA_RXF_OPER_STATE_PAUSED = 0x02, /* rxf in PAUSED state */
+ BNA_RX_MOD_F_ENET_STARTED = 1,
+ BNA_RX_MOD_F_ENET_LOOPBACK = 2,
};
enum bna_rxf_flags {
- BNA_RXF_FL_STOP_PENDING = 0x01,
- BNA_RXF_FL_FAILED = 0x02,
- BNA_RXF_FL_RSS_CONFIG_PENDING = 0x04,
- BNA_RXF_FL_OPERSTATE_CHANGED = 0x08,
- BNA_RXF_FL_RXF_ENABLED = 0x10,
- BNA_RXF_FL_VLAN_CONFIG_PENDING = 0x20,
+ BNA_RXF_F_PAUSED = 1,
};
enum bna_rxf_event {
RXF_E_START = 1,
RXF_E_STOP = 2,
RXF_E_FAIL = 3,
- RXF_E_CAM_FLTR_MOD = 4,
- RXF_E_STARTED = 5,
- RXF_E_STOPPED = 6,
- RXF_E_CAM_FLTR_RESP = 7,
- RXF_E_PAUSE = 8,
- RXF_E_RESUME = 9,
- RXF_E_STAT_CLEARED = 10,
-};
-
-enum bna_rxf_state {
- BNA_RXF_STOPPED = 1,
- BNA_RXF_START_WAIT = 2,
- BNA_RXF_CAM_FLTR_MOD_WAIT = 3,
- BNA_RXF_STARTED = 4,
- BNA_RXF_CAM_FLTR_CLR_WAIT = 5,
- BNA_RXF_STOP_WAIT = 6,
- BNA_RXF_PAUSE_WAIT = 7,
- BNA_RXF_RESUME_WAIT = 8,
- BNA_RXF_STAT_CLR_WAIT = 9,
+ RXF_E_CONFIG = 4,
+ RXF_E_PAUSE = 5,
+ RXF_E_RESUME = 6,
+ RXF_E_FW_RESP = 7,
};
-enum bna_port_type {
- BNA_PORT_T_REGULAR = 0,
- BNA_PORT_T_LOOPBACK_INTERNAL = 1,
- BNA_PORT_T_LOOPBACK_EXTERNAL = 2,
+enum bna_enet_type {
+ BNA_ENET_T_REGULAR = 0,
+ BNA_ENET_T_LOOPBACK_INTERNAL = 1,
+ BNA_ENET_T_LOOPBACK_EXTERNAL = 2,
};
enum bna_link_status {
@@ -247,17 +214,27 @@ enum bna_link_status {
BNA_CEE_UP = 2
};
-enum bna_llport_flags {
- BNA_LLPORT_F_ADMIN_UP = 1,
- BNA_LLPORT_F_PORT_ENABLED = 2,
- BNA_LLPORT_F_RX_STARTED = 4
+enum bna_ethport_flags {
+ BNA_ETHPORT_F_ADMIN_UP = 1,
+ BNA_ETHPORT_F_PORT_ENABLED = 2,
+ BNA_ETHPORT_F_RX_STARTED = 4,
};
-enum bna_port_flags {
- BNA_PORT_F_DEVICE_READY = 1,
- BNA_PORT_F_ENABLED = 2,
- BNA_PORT_F_PAUSE_CHANGED = 4,
- BNA_PORT_F_MTU_CHANGED = 8
+enum bna_enet_flags {
+ BNA_ENET_F_IOCETH_READY = 1,
+ BNA_ENET_F_ENABLED = 2,
+ BNA_ENET_F_PAUSE_CHANGED = 4,
+ BNA_ENET_F_MTU_CHANGED = 8
+};
+
+enum bna_rss_flags {
+ BNA_RSS_F_RIT_PENDING = 1,
+ BNA_RSS_F_CFG_PENDING = 2,
+ BNA_RSS_F_STATUS_PENDING = 4,
+};
+
+enum bna_mod_flags {
+ BNA_MOD_F_INIT_DONE = 1,
};
enum bna_pkt_rates {
@@ -289,10 +266,17 @@ enum bna_dim_bias_types {
BNA_BIAS_T_MAX = 2
};
+#define BNA_MAX_NAME_SIZE 64
+struct bna_ident {
+ int id;
+ char name[BNA_MAX_NAME_SIZE];
+};
+
struct bna_mac {
/* This should be the first one */
struct list_head qe;
u8 addr[ETH_ALEN];
+ struct bna_mcam_handle *handle;
};
struct bna_mem_descr {
@@ -338,23 +322,30 @@ struct bna_qpt {
u32 page_size;
};
+struct bna_attr {
+ bool fw_query_complete;
+ int num_txq;
+ int num_rxp;
+ int num_ucmac;
+ int num_mcmac;
+ int max_rit_size;
+};
+
/**
*
- * Device
+ * IOCEth
*
*/
-struct bna_device {
+struct bna_ioceth {
bfa_fsm_t fsm;
struct bfa_ioc ioc;
- enum bna_intr_type intr_type;
- int vector;
+ struct bna_attr attr;
+ struct bfa_msgq_cmd_entry msgq_cmd;
+ struct bfi_enet_attr_req attr_req;
- void (*ready_cbfn)(struct bnad *bnad, enum bna_cb_status status);
- struct bnad *ready_cbarg;
-
- void (*stop_cbfn)(struct bnad *bnad, enum bna_cb_status status);
+ void (*stop_cbfn)(struct bnad *bnad);
struct bnad *stop_cbarg;
struct bna *bna;
@@ -362,32 +353,7 @@ struct bna_device {
/**
*
- * Mail box
- *
- */
-
-struct bna_mbox_qe {
- /* This should be the first one */
- struct list_head qe;
-
- struct bfa_mbox_cmd cmd;
- u32 cmd_len;
- /* Callback for port, tx, rx, rxf */
- void (*cbfn)(void *arg, int status);
- void *cbarg;
-};
-
-struct bna_mbox_mod {
- enum bna_mbox_state state;
- struct list_head posted_q;
- u32 msg_pending;
- u32 msg_ctr;
- struct bna *bna;
-};
-
-/**
- *
- * Port
+ * Enet
*
*/
@@ -397,50 +363,58 @@ struct bna_pause_config {
enum bna_status rx_pause;
};
-struct bna_llport {
+struct bna_enet {
bfa_fsm_t fsm;
- enum bna_llport_flags flags;
+ enum bna_enet_flags flags;
- enum bna_port_type type;
+ enum bna_enet_type type;
- enum bna_link_status link_status;
+ struct bna_pause_config pause_config;
+ int mtu;
- int rx_started_count;
+ /* Callback for bna_enet_disable(), enet_stop() */
+ void (*stop_cbfn)(void *);
+ void *stop_cbarg;
+
+ /* Callback for bna_enet_pause_config() */
+ void (*pause_cbfn)(struct bnad *);
+
+ /* Callback for bna_enet_mtu_set() */
+ void (*mtu_cbfn)(struct bnad *);
- void (*stop_cbfn)(struct bna_port *, enum bna_cb_status);
+ struct bfa_wc chld_stop_wc;
- struct bna_mbox_qe mbox_qe;
+ struct bfa_msgq_cmd_entry msgq_cmd;
+ struct bfi_enet_set_pause_req pause_req;
struct bna *bna;
};
-struct bna_port {
- bfa_fsm_t fsm;
- enum bna_port_flags flags;
-
- enum bna_port_type type;
+/**
+ *
+ * Ethport
+ *
+ */
- struct bna_llport llport;
+struct bna_ethport {
+ bfa_fsm_t fsm;
+ enum bna_ethport_flags flags;
- struct bna_pause_config pause_config;
- u8 priority;
- int mtu;
+ enum bna_link_status link_status;
- /* Callback for bna_port_disable(), port_stop() */
- void (*stop_cbfn)(void *, enum bna_cb_status);
- void *stop_cbarg;
+ int rx_started_count;
- /* Callback for bna_port_pause_config() */
- void (*pause_cbfn)(struct bnad *, enum bna_cb_status);
+ void (*stop_cbfn)(struct bna_enet *);
- /* Callback for bna_port_mtu_set() */
- void (*mtu_cbfn)(struct bnad *, enum bna_cb_status);
+ void (*adminup_cbfn)(struct bnad *, enum bna_cb_status);
void (*link_cbfn)(struct bnad *, enum bna_link_status);
- struct bfa_wc chld_stop_wc;
-
- struct bna_mbox_qe mbox_qe;
+ struct bfa_msgq_cmd_entry msgq_cmd;
+ union {
+ struct bfi_enet_enable_req admin_req;
+ struct bfi_enet_diag_lb_req lpbk_req;
+ } bfi_enet_cmd;
struct bna *bna;
};
@@ -451,82 +425,26 @@ struct bna_port {
*
*/
-/* IB index segment structure */
-struct bna_ibidx_seg {
- /* This should be the first one */
- struct list_head qe;
-
- u8 ib_seg_size;
- u8 ib_idx_tbl_offset;
-};
-
-/* Interrupt structure */
-struct bna_intr {
- /* This should be the first one */
- struct list_head qe;
- int ref_count;
-
- enum bna_intr_type intr_type;
- int vector;
-
- struct bna_ib *ib;
-};
-
/* Doorbell structure */
struct bna_ib_dbell {
void *__iomem doorbell_addr;
u32 doorbell_ack;
};
-/* Interrupt timer configuration */
-struct bna_ib_config {
- u8 coalescing_timeo; /* Unit is 5usec. */
-
- int interpkt_count;
- int interpkt_timeo;
-
- enum ib_flags ctrl_flags;
-};
-
/* IB structure */
struct bna_ib {
- /* This should be the first one */
- struct list_head qe;
-
- int ib_id;
-
- int ref_count;
- int start_count;
-
struct bna_dma_addr ib_seg_host_addr;
void *ib_seg_host_addr_kva;
- u32 idx_mask; /* Size >= BNA_IBIDX_MAX_SEGSIZE */
-
- struct bna_ibidx_seg *idx_seg;
struct bna_ib_dbell door_bell;
- struct bna_intr *intr;
-
- struct bna_ib_config ib_config;
-
- struct bna *bna;
-};
-
-/* IB module - keeps track of IBs and interrupts */
-struct bna_ib_mod {
- struct bna_ib *ib; /* BFI_MAX_IB entries */
- struct bna_intr *intr; /* BFI_MAX_IB entries */
- struct bna_ibidx_seg *idx_seg; /* BNA_IBIDX_TOTAL_SEGS */
-
- struct list_head ib_free_q;
-
- struct list_head ibidx_seg_pool[BFI_IBIDX_TOTAL_POOLS];
+ enum bna_intr_type intr_type;
+ int intr_vector;
- struct list_head intr_free_q;
- struct list_head intr_active_q;
+ u8 coalescing_timeo; /* Unit is 5usec. */
- struct bna *bna;
+ int interpkt_count;
+ int interpkt_timeo;
};
/**
@@ -552,6 +470,7 @@ struct bna_tcb {
/* Control path */
struct bna_txq *txq;
struct bnad *bnad;
+ void *priv; /* BNAD's cookie */
enum bna_intr_type intr_type;
int intr_vector;
u8 priority; /* Current priority */
@@ -565,68 +484,66 @@ struct bna_txq {
/* This should be the first one */
struct list_head qe;
- int txq_id;
-
u8 priority;
struct bna_qpt qpt;
struct bna_tcb *tcb;
- struct bna_ib *ib;
- int ib_seg_offset;
+ struct bna_ib ib;
struct bna_tx *tx;
+ int hw_id;
+
u64 tx_packets;
u64 tx_bytes;
};
-/* TxF structure (hardware Tx Function) */
-struct bna_txf {
- int txf_id;
- enum txf_flags ctrl_flags;
- u16 vlan;
-};
-
/* Tx object */
struct bna_tx {
/* This should be the first one */
struct list_head qe;
+ int rid;
+ int hw_id;
bfa_fsm_t fsm;
enum bna_tx_flags flags;
enum bna_tx_type type;
+ int num_txq;
struct list_head txq_q;
- struct bna_txf txf;
+ u16 txf_vlan_id;
/* Tx event handlers */
void (*tcb_setup_cbfn)(struct bnad *, struct bna_tcb *);
void (*tcb_destroy_cbfn)(struct bnad *, struct bna_tcb *);
- void (*tx_stall_cbfn)(struct bnad *, struct bna_tcb *);
- void (*tx_resume_cbfn)(struct bnad *, struct bna_tcb *);
- void (*tx_cleanup_cbfn)(struct bnad *, struct bna_tcb *);
+ void (*tx_stall_cbfn)(struct bnad *, struct bna_tx *);
+ void (*tx_resume_cbfn)(struct bnad *, struct bna_tx *);
+ void (*tx_cleanup_cbfn)(struct bnad *, struct bna_tx *);
/* callback for bna_tx_disable(), bna_tx_stop() */
- void (*stop_cbfn)(void *arg, struct bna_tx *tx,
- enum bna_cb_status status);
+ void (*stop_cbfn)(void *arg, struct bna_tx *tx);
void *stop_cbarg;
/* callback for bna_tx_prio_set() */
- void (*prio_change_cbfn)(struct bnad *bnad, struct bna_tx *tx,
- enum bna_cb_status status);
-
- struct bfa_wc txq_stop_wc;
+ void (*prio_change_cbfn)(struct bnad *bnad, struct bna_tx *tx);
- struct bna_mbox_qe mbox_qe;
+ struct bfa_msgq_cmd_entry msgq_cmd;
+ union {
+ struct bfi_enet_tx_cfg_req cfg_req;
+ struct bfi_enet_req req;
+ struct bfi_enet_tx_cfg_rsp cfg_rsp;
+ } bfi_enet_cmd;
struct bna *bna;
void *priv; /* bnad's cookie */
};
+/* Tx object configuration used during creation */
struct bna_tx_config {
int num_txq;
int txq_depth;
+ int coalescing_timeo;
enum bna_tx_type tx_type;
};
@@ -635,9 +552,9 @@ struct bna_tx_event_cbfn {
void (*tcb_setup_cbfn)(struct bnad *, struct bna_tcb *);
void (*tcb_destroy_cbfn)(struct bnad *, struct bna_tcb *);
/* Mandatory */
- void (*tx_stall_cbfn)(struct bnad *, struct bna_tcb *);
- void (*tx_resume_cbfn)(struct bnad *, struct bna_tcb *);
- void (*tx_cleanup_cbfn)(struct bnad *, struct bna_tcb *);
+ void (*tx_stall_cbfn)(struct bnad *, struct bna_tx *);
+ void (*tx_resume_cbfn)(struct bnad *, struct bna_tx *);
+ void (*tx_cleanup_cbfn)(struct bnad *, struct bna_tx *);
};
/* Tx module - keeps track of free, active tx objects */
@@ -651,57 +568,25 @@ struct bna_tx_mod {
struct list_head txq_free_q;
/* callback for bna_tx_mod_stop() */
- void (*stop_cbfn)(struct bna_port *port,
- enum bna_cb_status status);
+ void (*stop_cbfn)(struct bna_enet *enet);
struct bfa_wc tx_stop_wc;
enum bna_tx_mod_flags flags;
- int priority;
- int cee_link;
+ u8 prio_map;
+ int default_prio;
+ int iscsi_over_cee;
+ int iscsi_prio;
+ int prio_reconfigured;
- u32 txf_bmap[2];
+ u32 rid_mask;
struct bna *bna;
};
/**
*
- * Receive Indirection Table
- *
- */
-
-/* One row of RIT table */
-struct bna_rit_entry {
- u8 large_rxq_id; /* used for either large or data buffers */
- u8 small_rxq_id; /* used for either small or header buffers */
-};
-
-/* RIT segment */
-struct bna_rit_segment {
- struct list_head qe;
-
- u32 rit_offset;
- u32 rit_size;
- /**
- * max_rit_size: Varies per RIT segment depending on how RIT is
- * partitioned
- */
- u32 max_rit_size;
-
- struct bna_rit_entry *rit;
-};
-
-struct bna_rit_mod {
- struct bna_rit_entry *rit;
- struct bna_rit_segment *rit_segment;
-
- struct list_head rit_seg_pool[BFI_RIT_SEG_TOTAL_POOLS];
-};
-
-/**
- *
* Rx object
*
*/
@@ -719,8 +604,9 @@ struct bna_rcb {
int page_count;
/* Control path */
struct bna_rxq *rxq;
- struct bna_cq *cq;
+ struct bna_ccb *ccb;
struct bnad *bnad;
+ void *priv; /* BNAD's cookie */
unsigned long flags;
int id;
};
@@ -728,7 +614,6 @@ struct bna_rcb {
/* RxQ structure - QPT, configuration */
struct bna_rxq {
struct list_head qe;
- int rxq_id;
int buffer_size;
int q_depth;
@@ -739,6 +624,8 @@ struct bna_rxq {
struct bna_rxp *rxp;
struct bna_rx *rx;
+ int hw_id;
+
u64 rx_packets;
u64 rx_bytes;
u64 rx_packets_with_error;
@@ -784,6 +671,7 @@ struct bna_ccb {
/* Control path */
struct bna_cq *cq;
struct bnad *bnad;
+ void *priv; /* BNAD's cookie */
enum bna_intr_type intr_type;
int intr_vector;
u8 rx_coalescing_timeo; /* For NAPI */
@@ -793,46 +681,43 @@ struct bna_ccb {
/* CQ QPT, configuration */
struct bna_cq {
- int cq_id;
-
struct bna_qpt qpt;
struct bna_ccb *ccb;
- struct bna_ib *ib;
- u8 ib_seg_offset;
+ struct bna_ib ib;
struct bna_rx *rx;
};
struct bna_rss_config {
- enum rss_hash_type hash_type;
+ enum bfi_enet_rss_type hash_type;
u8 hash_mask;
- u32 toeplitz_hash_key[BFI_RSS_HASH_KEY_LEN];
+ u32 toeplitz_hash_key[BFI_ENET_RSS_KEY_LEN];
};
struct bna_hds_config {
- enum hds_header_type hdr_type;
- int header_size;
+ enum bfi_enet_hds_type hdr_type;
+ int forced_offset;
};
-/* This structure is used during RX creation */
+/* Rx object configuration used during creation */
struct bna_rx_config {
enum bna_rx_type rx_type;
int num_paths;
enum bna_rxp_type rxp_type;
int paused;
int q_depth;
+ int coalescing_timeo;
/*
* Small/Large (or Header/Data) buffer size to be configured
* for SLR and HDS queue type. Large buffer size comes from
- * port->mtu.
+ * enet->mtu.
*/
int small_buff_size;
enum bna_status rss_status;
struct bna_rss_config rss_config;
- enum bna_status hds_status;
struct bna_hds_config hds_config;
enum bna_status vlan_strip_status;
@@ -851,51 +736,35 @@ struct bna_rxp {
/* MSI-x vector number for configuring RSS */
int vector;
-
- struct bna_mbox_qe mbox_qe;
-};
-
-/* HDS configuration structure */
-struct bna_rxf_hds {
- enum hds_header_type hdr_type;
- int header_size;
-};
-
-/* RSS configuration structure */
-struct bna_rxf_rss {
- enum rss_hash_type hash_type;
- u8 hash_mask;
- u32 toeplitz_hash_key[BFI_RSS_HASH_KEY_LEN];
+ int hw_id;
};
/* RxF structure (hardware Rx Function) */
struct bna_rxf {
bfa_fsm_t fsm;
- int rxf_id;
- enum rxf_flags ctrl_flags;
- u16 default_vlan_tag;
- enum bna_rxf_oper_state rxf_oper_state;
- enum bna_status hds_status;
- struct bna_rxf_hds hds_cfg;
- enum bna_status rss_status;
- struct bna_rxf_rss rss_cfg;
- struct bna_rit_segment *rit_segment;
- struct bna_rx *rx;
- u32 forced_offset;
- struct bna_mbox_qe mbox_qe;
- int mcast_rxq_id;
+ enum bna_rxf_flags flags;
+
+ struct bfa_msgq_cmd_entry msgq_cmd;
+ union {
+ struct bfi_enet_enable_req req;
+ struct bfi_enet_rss_cfg_req rss_req;
+ struct bfi_enet_rit_req rit_req;
+ struct bfi_enet_rx_vlan_req vlan_req;
+ struct bfi_enet_mcast_add_req mcast_add_req;
+ struct bfi_enet_mcast_del_req mcast_del_req;
+ struct bfi_enet_ucast_req ucast_req;
+ } bfi_enet_cmd;
/* callback for bna_rxf_start() */
- void (*start_cbfn) (struct bna_rx *rx, enum bna_cb_status status);
+ void (*start_cbfn) (struct bna_rx *rx);
struct bna_rx *start_cbarg;
/* callback for bna_rxf_stop() */
- void (*stop_cbfn) (struct bna_rx *rx, enum bna_cb_status status);
+ void (*stop_cbfn) (struct bna_rx *rx);
struct bna_rx *stop_cbarg;
- /* callback for bna_rxf_receive_enable() / bna_rxf_receive_disable() */
- void (*oper_state_cbfn) (struct bnad *bnad, struct bna_rx *rx,
- enum bna_cb_status status);
+ /* callback for bna_rx_receive_pause() / bna_rx_receive_resume() */
+ void (*oper_state_cbfn) (struct bnad *bnad, struct bna_rx *rx);
struct bnad *oper_state_cbarg;
/**
@@ -905,25 +774,25 @@ struct bna_rxf {
* bna_rxf_{ucast/mcast}_del(),
* bna_rxf_mode_set()
*/
- void (*cam_fltr_cbfn)(struct bnad *bnad, struct bna_rx *rx,
- enum bna_cb_status status);
+ void (*cam_fltr_cbfn)(struct bnad *bnad, struct bna_rx *rx);
struct bnad *cam_fltr_cbarg;
- enum bna_rxf_flags rxf_flags;
-
/* List of unicast addresses yet to be applied to h/w */
struct list_head ucast_pending_add_q;
struct list_head ucast_pending_del_q;
+ struct bna_mac *ucast_pending_mac;
int ucast_pending_set;
/* ucast addresses applied to the h/w */
struct list_head ucast_active_q;
- struct bna_mac *ucast_active_mac;
+ struct bna_mac ucast_active_mac;
+ int ucast_active_set;
/* List of multicast addresses yet to be applied to h/w */
struct list_head mcast_pending_add_q;
struct list_head mcast_pending_del_q;
/* multicast addresses applied to the h/w */
struct list_head mcast_active_q;
+ struct list_head mcast_handle_q;
/* Rx modes yet to be applied to h/w */
enum bna_rxmode rxmode_pending;
@@ -931,41 +800,59 @@ struct bna_rxf {
/* Rx modes applied to h/w */
enum bna_rxmode rxmode_active;
+ u8 vlan_pending_bitmask;
enum bna_status vlan_filter_status;
- u32 vlan_filter_table[(BFI_MAX_VLAN + 1) / 32];
+ u32 vlan_filter_table[(BFI_ENET_VLAN_ID_MAX) / 32];
+ bool vlan_strip_pending;
+ enum bna_status vlan_strip_status;
+
+ enum bna_rss_flags rss_pending;
+ enum bna_status rss_status;
+ struct bna_rss_config rss_cfg;
+ u8 *rit;
+ int rit_size;
+
+ struct bna_rx *rx;
};
/* Rx object */
struct bna_rx {
/* This should be the first one */
struct list_head qe;
+ int rid;
+ int hw_id;
bfa_fsm_t fsm;
enum bna_rx_type type;
- /* list-head for RX path objects */
+ int num_paths;
struct list_head rxp_q;
+ struct bna_hds_config hds_cfg;
+
struct bna_rxf rxf;
enum bna_rx_flags rx_flags;
- struct bna_mbox_qe mbox_qe;
-
- struct bfa_wc rxq_stop_wc;
+ struct bfa_msgq_cmd_entry msgq_cmd;
+ union {
+ struct bfi_enet_rx_cfg_req cfg_req;
+ struct bfi_enet_req req;
+ struct bfi_enet_rx_cfg_rsp cfg_rsp;
+ } bfi_enet_cmd;
/* Rx event handlers */
void (*rcb_setup_cbfn)(struct bnad *, struct bna_rcb *);
void (*rcb_destroy_cbfn)(struct bnad *, struct bna_rcb *);
void (*ccb_setup_cbfn)(struct bnad *, struct bna_ccb *);
void (*ccb_destroy_cbfn)(struct bnad *, struct bna_ccb *);
- void (*rx_cleanup_cbfn)(struct bnad *, struct bna_ccb *);
- void (*rx_post_cbfn)(struct bnad *, struct bna_rcb *);
+ void (*rx_stall_cbfn)(struct bnad *, struct bna_rx *);
+ void (*rx_cleanup_cbfn)(struct bnad *, struct bna_rx *);
+ void (*rx_post_cbfn)(struct bnad *, struct bna_rx *);
/* callback for bna_rx_disable(), bna_rx_stop() */
- void (*stop_cbfn)(void *arg, struct bna_rx *rx,
- enum bna_cb_status status);
+ void (*stop_cbfn)(void *arg, struct bna_rx *rx);
void *stop_cbarg;
struct bna *bna;
@@ -978,9 +865,10 @@ struct bna_rx_event_cbfn {
void (*rcb_destroy_cbfn)(struct bnad *, struct bna_rcb *);
void (*ccb_setup_cbfn)(struct bnad *, struct bna_ccb *);
void (*ccb_destroy_cbfn)(struct bnad *, struct bna_ccb *);
+ void (*rx_stall_cbfn)(struct bnad *, struct bna_rx *);
/* Mandatory */
- void (*rx_cleanup_cbfn)(struct bnad *, struct bna_ccb *);
- void (*rx_post_cbfn)(struct bnad *, struct bna_rcb *);
+ void (*rx_cleanup_cbfn)(struct bnad *, struct bna_rx *);
+ void (*rx_post_cbfn)(struct bnad *, struct bna_rx *);
};
/* Rx module - keeps track of free, active rx objects */
@@ -1003,12 +891,11 @@ struct bna_rx_mod {
enum bna_rx_mod_flags flags;
/* callback for bna_rx_mod_stop() */
- void (*stop_cbfn)(struct bna_port *port,
- enum bna_cb_status status);
+ void (*stop_cbfn)(struct bna_enet *enet);
struct bfa_wc rx_stop_wc;
u32 dim_vector[BNA_LOAD_T_MAX][BNA_BIAS_T_MAX];
- u32 rxf_bmap[2];
+ u32 rid_mask;
};
/**
@@ -1024,9 +911,18 @@ struct bna_ucam_mod {
struct bna *bna;
};
+struct bna_mcam_handle {
+ /* This should be the first one */
+ struct list_head qe;
+ int handle;
+ int refcnt;
+};
+
struct bna_mcam_mod {
struct bna_mac *mcmac; /* BFI_MAX_MCMAC entries */
+ struct bna_mcam_handle *mchandle; /* BFI_MAX_MCMAC entries */
struct list_head free_q;
+ struct list_head free_handle_q;
struct bna *bna;
};
@@ -1037,50 +933,20 @@ struct bna_mcam_mod {
*
*/
-struct bna_tx_stats {
- int tx_state;
- int tx_flags;
- int num_txqs;
- u32 txq_bmap[2];
- int txf_id;
-};
-
-struct bna_rx_stats {
- int rx_state;
- int rx_flags;
- int num_rxps;
- int num_rxqs;
- u32 rxq_bmap[2];
- u32 cq_bmap[2];
- int rxf_id;
- int rxf_state;
- int rxf_oper_state;
- int num_active_ucast;
- int num_active_mcast;
- int rxmode_active;
- int vlan_filter_status;
- u32 vlan_filter_table[(BFI_MAX_VLAN + 1) / 32];
- int rss_status;
- int hds_status;
-};
-
-struct bna_sw_stats {
- int device_state;
- int port_state;
- int port_flags;
- int llport_state;
- int priority;
- int num_active_tx;
- int num_active_rx;
- struct bna_tx_stats tx_stats[BFI_MAX_TXQ];
- struct bna_rx_stats rx_stats[BFI_MAX_RXQ];
+struct bna_stats {
+ struct bna_dma_addr hw_stats_dma;
+ struct bfi_enet_stats *hw_stats_kva;
+ struct bfi_enet_stats hw_stats;
};
-struct bna_stats {
- u32 txf_bmap[2];
- u32 rxf_bmap[2];
- struct bfi_ll_stats *hw_stats;
- struct bna_sw_stats *sw_stats;
+struct bna_stats_mod {
+ bool ioc_ready;
+ bool stats_get_busy;
+ bool stats_clr_busy;
+ struct bfa_msgq_cmd_entry stats_get_cmd;
+ struct bfa_msgq_cmd_entry stats_clr_cmd;
+ struct bfi_enet_stats_req stats_get;
+ struct bfi_enet_stats_req stats_clr;
};
/**
@@ -1090,38 +956,32 @@ struct bna_stats {
*/
struct bna {
+ struct bna_ident ident;
struct bfa_pcidev pcidev;
- int port_num;
-
- struct bna_chip_regs regs;
+ struct bna_reg regs;
+ struct bna_bit_defn bits;
- struct bna_dma_addr hw_stats_dma;
struct bna_stats stats;
- struct bna_device device;
+ struct bna_ioceth ioceth;
struct bfa_cee cee;
+ struct bfa_msgq msgq;
- struct bna_mbox_mod mbox_mod;
-
- struct bna_port port;
+ struct bna_ethport ethport;
+ struct bna_enet enet;
+ struct bna_stats_mod stats_mod;
struct bna_tx_mod tx_mod;
-
struct bna_rx_mod rx_mod;
-
- struct bna_ib_mod ib_mod;
-
struct bna_ucam_mod ucam_mod;
struct bna_mcam_mod mcam_mod;
- struct bna_rit_mod rit_mod;
+ enum bna_mod_flags mod_flags;
- int rxf_promisc_id;
-
- struct bna_mbox_qe mbox_qe;
+ int default_mode_rid;
+ int promisc_rid;
struct bnad *bnad;
};
-
#endif /* __BNA_TYPES_H__ */
diff --git a/drivers/net/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c
index 8e35b2596f93..5d7872ecff52 100644
--- a/drivers/net/bna/bnad.c
+++ b/drivers/net/ethernet/brocade/bna/bnad.c
@@ -102,6 +102,28 @@ bnad_cq_cmpl_init(struct bnad *bnad, struct bna_ccb *ccb)
}
}
+static u32
+bnad_pci_unmap_skb(struct device *pdev, struct bnad_skb_unmap *array,
+ u32 index, u32 depth, struct sk_buff *skb, u32 frag)
+{
+ int j;
+ array[index].skb = NULL;
+
+ dma_unmap_single(pdev, dma_unmap_addr(&array[index], dma_addr),
+ skb_headlen(skb), DMA_TO_DEVICE);
+ dma_unmap_addr_set(&array[index], dma_addr, 0);
+ BNA_QE_INDX_ADD(index, 1, depth);
+
+ for (j = 0; j < frag; j++) {
+ dma_unmap_page(pdev, dma_unmap_addr(&array[index], dma_addr),
+ skb_frag_size(&skb_shinfo(skb)->frags[j]), DMA_TO_DEVICE);
+ dma_unmap_addr_set(&array[index], dma_addr, 0);
+ BNA_QE_INDX_ADD(index, 1, depth);
+ }
+
+ return index;
+}
+
/*
* Frees all pending Tx Bufs
* At this point no activity is expected on the Q,
@@ -115,39 +137,20 @@ bnad_free_all_txbufs(struct bnad *bnad,
struct bnad_unmap_q *unmap_q = tcb->unmap_q;
struct bnad_skb_unmap *unmap_array;
struct sk_buff *skb = NULL;
- int i;
+ int q;
unmap_array = unmap_q->unmap_array;
- unmap_cons = 0;
- while (unmap_cons < unmap_q->q_depth) {
- skb = unmap_array[unmap_cons].skb;
- if (!skb) {
- unmap_cons++;
+ for (q = 0; q < unmap_q->q_depth; q++) {
+ skb = unmap_array[q].skb;
+ if (!skb)
continue;
- }
- unmap_array[unmap_cons].skb = NULL;
- dma_unmap_single(&bnad->pcidev->dev,
- dma_unmap_addr(&unmap_array[unmap_cons],
- dma_addr), skb_headlen(skb),
- DMA_TO_DEVICE);
-
- dma_unmap_addr_set(&unmap_array[unmap_cons], dma_addr, 0);
- if (++unmap_cons >= unmap_q->q_depth)
- break;
+ unmap_cons = q;
+ unmap_cons = bnad_pci_unmap_skb(&bnad->pcidev->dev, unmap_array,
+ unmap_cons, unmap_q->q_depth, skb,
+ skb_shinfo(skb)->nr_frags);
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- dma_unmap_page(&bnad->pcidev->dev,
- dma_unmap_addr(&unmap_array[unmap_cons],
- dma_addr),
- skb_shinfo(skb)->frags[i].size,
- DMA_TO_DEVICE);
- dma_unmap_addr_set(&unmap_array[unmap_cons], dma_addr,
- 0);
- if (++unmap_cons >= unmap_q->q_depth)
- break;
- }
dev_kfree_skb_any(skb);
}
}
@@ -164,12 +167,11 @@ static u32
bnad_free_txbufs(struct bnad *bnad,
struct bna_tcb *tcb)
{
- u32 sent_packets = 0, sent_bytes = 0;
- u16 wis, unmap_cons, updated_hw_cons;
+ u32 unmap_cons, sent_packets = 0, sent_bytes = 0;
+ u16 wis, updated_hw_cons;
struct bnad_unmap_q *unmap_q = tcb->unmap_q;
struct bnad_skb_unmap *unmap_array;
struct sk_buff *skb;
- int i;
/*
* Just return if TX is stopped. This check is useful
@@ -195,32 +197,14 @@ bnad_free_txbufs(struct bnad *bnad,
while (wis) {
skb = unmap_array[unmap_cons].skb;
- unmap_array[unmap_cons].skb = NULL;
-
sent_packets++;
sent_bytes += skb->len;
wis -= BNA_TXQ_WI_NEEDED(1 + skb_shinfo(skb)->nr_frags);
- dma_unmap_single(&bnad->pcidev->dev,
- dma_unmap_addr(&unmap_array[unmap_cons],
- dma_addr), skb_headlen(skb),
- DMA_TO_DEVICE);
- dma_unmap_addr_set(&unmap_array[unmap_cons], dma_addr, 0);
- BNA_QE_INDX_ADD(unmap_cons, 1, unmap_q->q_depth);
-
- prefetch(&unmap_array[unmap_cons + 1]);
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- prefetch(&unmap_array[unmap_cons + 1]);
-
- dma_unmap_page(&bnad->pcidev->dev,
- dma_unmap_addr(&unmap_array[unmap_cons],
- dma_addr),
- skb_shinfo(skb)->frags[i].size,
- DMA_TO_DEVICE);
- dma_unmap_addr_set(&unmap_array[unmap_cons], dma_addr,
- 0);
- BNA_QE_INDX_ADD(unmap_cons, 1, unmap_q->q_depth);
- }
+ unmap_cons = bnad_pci_unmap_skb(&bnad->pcidev->dev, unmap_array,
+ unmap_cons, unmap_q->q_depth, skb,
+ skb_shinfo(skb)->nr_frags);
+
dev_kfree_skb_any(skb);
}
@@ -383,14 +367,14 @@ bnad_alloc_n_post_rxbufs(struct bnad *bnad, struct bna_rcb *rcb)
BNA_RXQ_QPGE_PTR_GET(unmap_prod, rcb->sw_qpt, rxent, wi_range);
while (to_alloc--) {
- if (!wi_range) {
+ if (!wi_range)
BNA_RXQ_QPGE_PTR_GET(unmap_prod, rcb->sw_qpt, rxent,
wi_range);
- }
skb = netdev_alloc_skb_ip_align(bnad->netdev,
rcb->rxq->buffer_size);
if (unlikely(!skb)) {
BNAD_UPDATE_CTR(bnad, rxbuf_alloc_failed);
+ rcb->rxq->rxbuf_alloc_failed++;
goto finishing;
}
unmap_array[unmap_prod].skb = skb;
@@ -412,7 +396,7 @@ finishing:
unmap_q->producer_index = unmap_prod;
rcb->producer_index = unmap_prod;
smp_mb();
- if (likely(test_bit(BNAD_RXQ_STARTED, &rcb->flags)))
+ if (likely(test_bit(BNAD_RXQ_POST_OK, &rcb->flags)))
bna_rxq_prod_indx_doorbell(rcb);
}
}
@@ -441,11 +425,15 @@ bnad_poll_cq(struct bnad *bnad, struct bna_ccb *ccb, int budget)
struct bnad_skb_unmap *unmap_array;
struct sk_buff *skb;
u32 flags, unmap_cons;
- u32 qid0 = ccb->rcb[0]->rxq->rxq_id;
struct bna_pkt_rate *pkt_rt = &ccb->pkt_rate;
+ struct bnad_rx_ctrl *rx_ctrl = (struct bnad_rx_ctrl *)(ccb->ctrl);
+
+ set_bit(BNAD_FP_IN_RX_PATH, &rx_ctrl->flags);
- if (!test_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags))
+ if (!test_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags)) {
+ clear_bit(BNAD_FP_IN_RX_PATH, &rx_ctrl->flags);
return 0;
+ }
prefetch(bnad->netdev);
BNA_CQ_QPGE_PTR_GET(ccb->producer_index, ccb->sw_qpt, cmpl,
@@ -455,10 +443,10 @@ bnad_poll_cq(struct bnad *bnad, struct bna_ccb *ccb, int budget)
packets++;
BNA_UPDATE_PKT_CNT(pkt_rt, ntohs(cmpl->length));
- if (qid0 == cmpl->rxq_id)
- rcb = ccb->rcb[0];
- else
+ if (bna_is_small_rxq(cmpl->rxq_id))
rcb = ccb->rcb[1];
+ else
+ rcb = ccb->rcb[0];
unmap_q = rcb->unmap_q;
unmap_array = unmap_q->unmap_array;
@@ -518,12 +506,9 @@ bnad_poll_cq(struct bnad *bnad, struct bna_ccb *ccb, int budget)
if (flags & BNA_CQ_EF_VLAN)
__vlan_hwaccel_put_tag(skb, ntohs(cmpl->vlan_tag));
- if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
- struct bnad_rx_ctrl *rx_ctrl;
-
- rx_ctrl = (struct bnad_rx_ctrl *) ccb->ctrl;
+ if (skb->ip_summed == CHECKSUM_UNNECESSARY)
napi_gro_receive(&rx_ctrl->napi, skb);
- } else {
+ else {
netif_receive_skb(skb);
}
@@ -534,39 +519,16 @@ next:
BNA_QE_INDX_ADD(ccb->producer_index, wis, ccb->q_depth);
- if (likely(ccb)) {
- if (likely(test_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags)))
- bna_ib_ack(ccb->i_dbell, packets);
- bnad_refill_rxq(bnad, ccb->rcb[0]);
- if (ccb->rcb[1])
- bnad_refill_rxq(bnad, ccb->rcb[1]);
- } else {
- if (likely(test_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags)))
- bna_ib_ack(ccb->i_dbell, 0);
- }
-
- return packets;
-}
+ if (likely(test_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags)))
+ bna_ib_ack_disable_irq(ccb->i_dbell, packets);
-static void
-bnad_disable_rx_irq(struct bnad *bnad, struct bna_ccb *ccb)
-{
- if (unlikely(!test_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags)))
- return;
+ bnad_refill_rxq(bnad, ccb->rcb[0]);
+ if (ccb->rcb[1])
+ bnad_refill_rxq(bnad, ccb->rcb[1]);
- bna_ib_coalescing_timer_set(ccb->i_dbell, 0);
- bna_ib_ack(ccb->i_dbell, 0);
-}
+ clear_bit(BNAD_FP_IN_RX_PATH, &rx_ctrl->flags);
-static void
-bnad_enable_rx_irq(struct bnad *bnad, struct bna_ccb *ccb)
-{
- unsigned long flags;
-
- /* Because of polling context */
- spin_lock_irqsave(&bnad->bna_lock, flags);
- bnad_enable_rx_irq_unsafe(ccb);
- spin_unlock_irqrestore(&bnad->bna_lock, flags);
+ return packets;
}
static void
@@ -576,10 +538,9 @@ bnad_netif_rx_schedule_poll(struct bnad *bnad, struct bna_ccb *ccb)
struct napi_struct *napi = &rx_ctrl->napi;
if (likely(napi_schedule_prep(napi))) {
- bnad_disable_rx_irq(bnad, ccb);
__napi_schedule(napi);
+ rx_ctrl->rx_schedule++;
}
- BNAD_UPDATE_CTR(bnad, netif_rx_schedule);
}
/* MSIX Rx Path Handler */
@@ -587,9 +548,11 @@ static irqreturn_t
bnad_msix_rx(int irq, void *data)
{
struct bna_ccb *ccb = (struct bna_ccb *)data;
- struct bnad *bnad = ccb->bnad;
- bnad_netif_rx_schedule_poll(bnad, ccb);
+ if (ccb) {
+ ((struct bnad_rx_ctrl *)(ccb->ctrl))->rx_intr_ctr++;
+ bnad_netif_rx_schedule_poll(ccb->bnad, ccb);
+ }
return IRQ_HANDLED;
}
@@ -604,14 +567,15 @@ bnad_msix_mbox_handler(int irq, void *data)
unsigned long flags;
struct bnad *bnad = (struct bnad *)data;
- if (unlikely(test_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags)))
- return IRQ_HANDLED;
-
spin_lock_irqsave(&bnad->bna_lock, flags);
+ if (unlikely(test_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags))) {
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+ return IRQ_HANDLED;
+ }
bna_intr_status_get(&bnad->bna, intr_status);
- if (BNA_IS_MBOX_ERR_INTR(intr_status))
+ if (BNA_IS_MBOX_ERR_INTR(&bnad->bna, intr_status))
bna_mbox_handler(&bnad->bna, intr_status);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
@@ -628,18 +592,22 @@ bnad_isr(int irq, void *data)
struct bnad *bnad = (struct bnad *)data;
struct bnad_rx_info *rx_info;
struct bnad_rx_ctrl *rx_ctrl;
+ struct bna_tcb *tcb = NULL;
- if (unlikely(test_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags)))
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ if (unlikely(test_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags))) {
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
return IRQ_NONE;
+ }
bna_intr_status_get(&bnad->bna, intr_status);
- if (unlikely(!intr_status))
+ if (unlikely(!intr_status)) {
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
return IRQ_NONE;
+ }
- spin_lock_irqsave(&bnad->bna_lock, flags);
-
- if (BNA_IS_MBOX_ERR_INTR(intr_status))
+ if (BNA_IS_MBOX_ERR_INTR(&bnad->bna, intr_status))
bna_mbox_handler(&bnad->bna, intr_status);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
@@ -650,8 +618,11 @@ bnad_isr(int irq, void *data)
/* Process data interrupts */
/* Tx processing */
for (i = 0; i < bnad->num_tx; i++) {
- for (j = 0; j < bnad->num_txq_per_tx; j++)
- bnad_tx(bnad, bnad->tx_info[i].tcb[j]);
+ for (j = 0; j < bnad->num_txq_per_tx; j++) {
+ tcb = bnad->tx_info[i].tcb[j];
+ if (tcb && test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))
+ bnad_tx(bnad, bnad->tx_info[i].tcb[j]);
+ }
}
/* Rx processing */
for (i = 0; i < bnad->num_rx; i++) {
@@ -706,43 +677,49 @@ bnad_set_netdev_perm_addr(struct bnad *bnad)
/* Callbacks */
void
-bnad_cb_device_enable_mbox_intr(struct bnad *bnad)
+bnad_cb_mbox_intr_enable(struct bnad *bnad)
{
bnad_enable_mbox_irq(bnad);
}
void
-bnad_cb_device_disable_mbox_intr(struct bnad *bnad)
+bnad_cb_mbox_intr_disable(struct bnad *bnad)
{
bnad_disable_mbox_irq(bnad);
}
void
-bnad_cb_device_enabled(struct bnad *bnad, enum bna_cb_status status)
+bnad_cb_ioceth_ready(struct bnad *bnad)
{
+ bnad->bnad_completions.ioc_comp_status = BNA_CB_SUCCESS;
complete(&bnad->bnad_completions.ioc_comp);
- bnad->bnad_completions.ioc_comp_status = status;
}
void
-bnad_cb_device_disabled(struct bnad *bnad, enum bna_cb_status status)
+bnad_cb_ioceth_failed(struct bnad *bnad)
{
+ bnad->bnad_completions.ioc_comp_status = BNA_CB_FAIL;
+ complete(&bnad->bnad_completions.ioc_comp);
+}
+
+void
+bnad_cb_ioceth_disabled(struct bnad *bnad)
+{
+ bnad->bnad_completions.ioc_comp_status = BNA_CB_SUCCESS;
complete(&bnad->bnad_completions.ioc_comp);
- bnad->bnad_completions.ioc_comp_status = status;
}
static void
-bnad_cb_port_disabled(void *arg, enum bna_cb_status status)
+bnad_cb_enet_disabled(void *arg)
{
struct bnad *bnad = (struct bnad *)arg;
- complete(&bnad->bnad_completions.port_comp);
-
netif_carrier_off(bnad->netdev);
+ complete(&bnad->bnad_completions.enet_comp);
}
void
-bnad_cb_port_link_status(struct bnad *bnad,
+bnad_cb_ethport_link_status(struct bnad *bnad,
enum bna_link_status link_status)
{
bool link_up = 0;
@@ -750,34 +727,60 @@ bnad_cb_port_link_status(struct bnad *bnad,
link_up = (link_status == BNA_LINK_UP) || (link_status == BNA_CEE_UP);
if (link_status == BNA_CEE_UP) {
+ if (!test_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags))
+ BNAD_UPDATE_CTR(bnad, cee_toggle);
set_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags);
- BNAD_UPDATE_CTR(bnad, cee_up);
- } else
+ } else {
+ if (test_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags))
+ BNAD_UPDATE_CTR(bnad, cee_toggle);
clear_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags);
+ }
if (link_up) {
if (!netif_carrier_ok(bnad->netdev)) {
- struct bna_tcb *tcb = bnad->tx_info[0].tcb[0];
- if (!tcb)
- return;
- pr_warn("bna: %s link up\n",
+ uint tx_id, tcb_id;
+ printk(KERN_WARNING "bna: %s link up\n",
bnad->netdev->name);
netif_carrier_on(bnad->netdev);
BNAD_UPDATE_CTR(bnad, link_toggle);
- if (test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)) {
- /* Force an immediate Transmit Schedule */
- pr_info("bna: %s TX_STARTED\n",
- bnad->netdev->name);
- netif_wake_queue(bnad->netdev);
- BNAD_UPDATE_CTR(bnad, netif_queue_wakeup);
- } else {
- netif_stop_queue(bnad->netdev);
- BNAD_UPDATE_CTR(bnad, netif_queue_stop);
+ for (tx_id = 0; tx_id < bnad->num_tx; tx_id++) {
+ for (tcb_id = 0; tcb_id < bnad->num_txq_per_tx;
+ tcb_id++) {
+ struct bna_tcb *tcb =
+ bnad->tx_info[tx_id].tcb[tcb_id];
+ u32 txq_id;
+ if (!tcb)
+ continue;
+
+ txq_id = tcb->id;
+
+ if (test_bit(BNAD_TXQ_TX_STARTED,
+ &tcb->flags)) {
+ /*
+ * Force an immediate
+ * Transmit Schedule */
+ printk(KERN_INFO "bna: %s %d "
+ "TXQ_STARTED\n",
+ bnad->netdev->name,
+ txq_id);
+ netif_wake_subqueue(
+ bnad->netdev,
+ txq_id);
+ BNAD_UPDATE_CTR(bnad,
+ netif_queue_wakeup);
+ } else {
+ netif_stop_subqueue(
+ bnad->netdev,
+ txq_id);
+ BNAD_UPDATE_CTR(bnad,
+ netif_queue_stop);
+ }
+ }
}
}
} else {
if (netif_carrier_ok(bnad->netdev)) {
- pr_warn("bna: %s link down\n",
+ printk(KERN_WARNING "bna: %s link down\n",
bnad->netdev->name);
netif_carrier_off(bnad->netdev);
BNAD_UPDATE_CTR(bnad, link_toggle);
@@ -786,8 +789,7 @@ bnad_cb_port_link_status(struct bnad *bnad,
}
static void
-bnad_cb_tx_disabled(void *arg, struct bna_tx *tx,
- enum bna_cb_status status)
+bnad_cb_tx_disabled(void *arg, struct bna_tx *tx)
{
struct bnad *bnad = (struct bnad *)arg;
@@ -864,108 +866,188 @@ bnad_cb_ccb_destroy(struct bnad *bnad, struct bna_ccb *ccb)
}
static void
-bnad_cb_tx_stall(struct bnad *bnad, struct bna_tcb *tcb)
+bnad_cb_tx_stall(struct bnad *bnad, struct bna_tx *tx)
{
struct bnad_tx_info *tx_info =
- (struct bnad_tx_info *)tcb->txq->tx->priv;
-
- if (tx_info != &bnad->tx_info[0])
- return;
+ (struct bnad_tx_info *)tx->priv;
+ struct bna_tcb *tcb;
+ u32 txq_id;
+ int i;
- clear_bit(BNAD_TXQ_TX_STARTED, &tcb->flags);
- netif_stop_queue(bnad->netdev);
- pr_info("bna: %s TX_STOPPED\n", bnad->netdev->name);
+ for (i = 0; i < BNAD_MAX_TXQ_PER_TX; i++) {
+ tcb = tx_info->tcb[i];
+ if (!tcb)
+ continue;
+ txq_id = tcb->id;
+ clear_bit(BNAD_TXQ_TX_STARTED, &tcb->flags);
+ netif_stop_subqueue(bnad->netdev, txq_id);
+ printk(KERN_INFO "bna: %s %d TXQ_STOPPED\n",
+ bnad->netdev->name, txq_id);
+ }
}
static void
-bnad_cb_tx_resume(struct bnad *bnad, struct bna_tcb *tcb)
+bnad_cb_tx_resume(struct bnad *bnad, struct bna_tx *tx)
{
- struct bnad_unmap_q *unmap_q = tcb->unmap_q;
+ struct bnad_tx_info *tx_info = (struct bnad_tx_info *)tx->priv;
+ struct bna_tcb *tcb;
+ struct bnad_unmap_q *unmap_q;
+ u32 txq_id;
+ int i;
- if (test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))
- return;
+ for (i = 0; i < BNAD_MAX_TXQ_PER_TX; i++) {
+ tcb = tx_info->tcb[i];
+ if (!tcb)
+ continue;
+ txq_id = tcb->id;
- clear_bit(BNAD_RF_TX_SHUTDOWN_DELAYED, &bnad->run_flags);
+ unmap_q = tcb->unmap_q;
- while (test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags))
- cpu_relax();
+ if (test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))
+ continue;
- bnad_free_all_txbufs(bnad, tcb);
+ while (test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags))
+ cpu_relax();
- unmap_q->producer_index = 0;
- unmap_q->consumer_index = 0;
+ bnad_free_all_txbufs(bnad, tcb);
- smp_mb__before_clear_bit();
- clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
+ unmap_q->producer_index = 0;
+ unmap_q->consumer_index = 0;
+
+ smp_mb__before_clear_bit();
+ clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
+
+ set_bit(BNAD_TXQ_TX_STARTED, &tcb->flags);
+
+ if (netif_carrier_ok(bnad->netdev)) {
+ printk(KERN_INFO "bna: %s %d TXQ_STARTED\n",
+ bnad->netdev->name, txq_id);
+ netif_wake_subqueue(bnad->netdev, txq_id);
+ BNAD_UPDATE_CTR(bnad, netif_queue_wakeup);
+ }
+ }
/*
- * Workaround for first device enable failure & we
+ * Workaround for first ioceth enable failure & we
* get a 0 MAC address. We try to get the MAC address
* again here.
*/
if (is_zero_ether_addr(&bnad->perm_addr.mac[0])) {
- bna_port_mac_get(&bnad->bna.port, &bnad->perm_addr);
+ bna_enet_perm_mac_get(&bnad->bna.enet, &bnad->perm_addr);
bnad_set_netdev_perm_addr(bnad);
}
+}
- set_bit(BNAD_TXQ_TX_STARTED, &tcb->flags);
+static void
+bnad_cb_tx_cleanup(struct bnad *bnad, struct bna_tx *tx)
+{
+ struct bnad_tx_info *tx_info = (struct bnad_tx_info *)tx->priv;
+ struct bna_tcb *tcb;
+ int i;
- if (netif_carrier_ok(bnad->netdev)) {
- pr_info("bna: %s TX_STARTED\n", bnad->netdev->name);
- netif_wake_queue(bnad->netdev);
- BNAD_UPDATE_CTR(bnad, netif_queue_wakeup);
+ for (i = 0; i < BNAD_MAX_TXQ_PER_TX; i++) {
+ tcb = tx_info->tcb[i];
+ if (!tcb)
+ continue;
}
+
+ mdelay(BNAD_TXRX_SYNC_MDELAY);
+ bna_tx_cleanup_complete(tx);
}
static void
-bnad_cb_tx_cleanup(struct bnad *bnad, struct bna_tcb *tcb)
+bnad_cb_rx_stall(struct bnad *bnad, struct bna_rx *rx)
{
- /* Delay only once for the whole Tx Path Shutdown */
- if (!test_and_set_bit(BNAD_RF_TX_SHUTDOWN_DELAYED, &bnad->run_flags))
- mdelay(BNAD_TXRX_SYNC_MDELAY);
+ struct bnad_rx_info *rx_info = (struct bnad_rx_info *)rx->priv;
+ struct bna_ccb *ccb;
+ struct bnad_rx_ctrl *rx_ctrl;
+ int i;
+
+ for (i = 0; i < BNAD_MAX_RXP_PER_RX; i++) {
+ rx_ctrl = &rx_info->rx_ctrl[i];
+ ccb = rx_ctrl->ccb;
+ if (!ccb)
+ continue;
+
+ clear_bit(BNAD_RXQ_POST_OK, &ccb->rcb[0]->flags);
+
+ if (ccb->rcb[1])
+ clear_bit(BNAD_RXQ_POST_OK, &ccb->rcb[1]->flags);
+ }
}
static void
-bnad_cb_rx_cleanup(struct bnad *bnad,
- struct bna_ccb *ccb)
+bnad_cb_rx_cleanup(struct bnad *bnad, struct bna_rx *rx)
{
- clear_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags);
+ struct bnad_rx_info *rx_info = (struct bnad_rx_info *)rx->priv;
+ struct bna_ccb *ccb;
+ struct bnad_rx_ctrl *rx_ctrl;
+ int i;
- if (ccb->rcb[1])
- clear_bit(BNAD_RXQ_STARTED, &ccb->rcb[1]->flags);
+ mdelay(BNAD_TXRX_SYNC_MDELAY);
+
+ for (i = 0; i < BNAD_MAX_RXP_PER_RX; i++) {
+ rx_ctrl = &rx_info->rx_ctrl[i];
+ ccb = rx_ctrl->ccb;
+ if (!ccb)
+ continue;
+
+ clear_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags);
+
+ if (ccb->rcb[1])
+ clear_bit(BNAD_RXQ_STARTED, &ccb->rcb[1]->flags);
- if (!test_and_set_bit(BNAD_RF_RX_SHUTDOWN_DELAYED, &bnad->run_flags))
- mdelay(BNAD_TXRX_SYNC_MDELAY);
+ while (test_bit(BNAD_FP_IN_RX_PATH, &rx_ctrl->flags))
+ cpu_relax();
+ }
+
+ bna_rx_cleanup_complete(rx);
}
static void
-bnad_cb_rx_post(struct bnad *bnad, struct bna_rcb *rcb)
+bnad_cb_rx_post(struct bnad *bnad, struct bna_rx *rx)
{
- struct bnad_unmap_q *unmap_q = rcb->unmap_q;
-
- clear_bit(BNAD_RF_RX_SHUTDOWN_DELAYED, &bnad->run_flags);
-
- if (rcb == rcb->cq->ccb->rcb[0])
- bnad_cq_cmpl_init(bnad, rcb->cq->ccb);
+ struct bnad_rx_info *rx_info = (struct bnad_rx_info *)rx->priv;
+ struct bna_ccb *ccb;
+ struct bna_rcb *rcb;
+ struct bnad_rx_ctrl *rx_ctrl;
+ struct bnad_unmap_q *unmap_q;
+ int i;
+ int j;
- bnad_free_all_rxbufs(bnad, rcb);
+ for (i = 0; i < BNAD_MAX_RXP_PER_RX; i++) {
+ rx_ctrl = &rx_info->rx_ctrl[i];
+ ccb = rx_ctrl->ccb;
+ if (!ccb)
+ continue;
- set_bit(BNAD_RXQ_STARTED, &rcb->flags);
+ bnad_cq_cmpl_init(bnad, ccb);
- /* Now allocate & post buffers for this RCB */
- /* !!Allocation in callback context */
- if (!test_and_set_bit(BNAD_RXQ_REFILL, &rcb->flags)) {
- if (BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth)
- >> BNAD_RXQ_REFILL_THRESHOLD_SHIFT)
- bnad_alloc_n_post_rxbufs(bnad, rcb);
- smp_mb__before_clear_bit();
- clear_bit(BNAD_RXQ_REFILL, &rcb->flags);
+ for (j = 0; j < BNAD_MAX_RXQ_PER_RXP; j++) {
+ rcb = ccb->rcb[j];
+ if (!rcb)
+ continue;
+ bnad_free_all_rxbufs(bnad, rcb);
+
+ set_bit(BNAD_RXQ_STARTED, &rcb->flags);
+ set_bit(BNAD_RXQ_POST_OK, &rcb->flags);
+ unmap_q = rcb->unmap_q;
+
+ /* Now allocate & post buffers for this RCB */
+ /* !!Allocation in callback context */
+ if (!test_and_set_bit(BNAD_RXQ_REFILL, &rcb->flags)) {
+ if (BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth)
+ >> BNAD_RXQ_REFILL_THRESHOLD_SHIFT)
+ bnad_alloc_n_post_rxbufs(bnad, rcb);
+ smp_mb__before_clear_bit();
+ clear_bit(BNAD_RXQ_REFILL, &rcb->flags);
+ }
+ }
}
}
static void
-bnad_cb_rx_disabled(void *arg, struct bna_rx *rx,
- enum bna_cb_status status)
+bnad_cb_rx_disabled(void *arg, struct bna_rx *rx)
{
struct bnad *bnad = (struct bnad *)arg;
@@ -973,10 +1055,9 @@ bnad_cb_rx_disabled(void *arg, struct bna_rx *rx,
}
static void
-bnad_cb_rx_mcast_add(struct bnad *bnad, struct bna_rx *rx,
- enum bna_cb_status status)
+bnad_cb_rx_mcast_add(struct bnad *bnad, struct bna_rx *rx)
{
- bnad->bnad_completions.mcast_comp_status = status;
+ bnad->bnad_completions.mcast_comp_status = BNA_CB_SUCCESS;
complete(&bnad->bnad_completions.mcast_comp);
}
@@ -995,6 +1076,13 @@ bnad_cb_stats_get(struct bnad *bnad, enum bna_cb_status status,
jiffies + msecs_to_jiffies(BNAD_STATS_TIMER_FREQ));
}
+static void
+bnad_cb_enet_mtu_set(struct bnad *bnad)
+{
+ bnad->bnad_completions.mtu_comp_status = BNA_CB_SUCCESS;
+ complete(&bnad->bnad_completions.mtu_comp);
+}
+
/* Resource allocation, free functions */
static void
@@ -1073,23 +1161,17 @@ err_return:
/* Free IRQ for Mailbox */
static void
-bnad_mbox_irq_free(struct bnad *bnad,
- struct bna_intr_info *intr_info)
+bnad_mbox_irq_free(struct bnad *bnad)
{
int irq;
unsigned long flags;
- if (intr_info->idl == NULL)
- return;
-
spin_lock_irqsave(&bnad->bna_lock, flags);
bnad_disable_mbox_irq(bnad);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
irq = BNAD_GET_MBOX_IRQ(bnad);
free_irq(irq, bnad);
-
- kfree(intr_info->idl);
}
/*
@@ -1098,32 +1180,22 @@ bnad_mbox_irq_free(struct bnad *bnad,
* from bna
*/
static int
-bnad_mbox_irq_alloc(struct bnad *bnad,
- struct bna_intr_info *intr_info)
+bnad_mbox_irq_alloc(struct bnad *bnad)
{
int err = 0;
unsigned long irq_flags, flags;
u32 irq;
irq_handler_t irq_handler;
- /* Mbox should use only 1 vector */
-
- intr_info->idl = kzalloc(sizeof(*(intr_info->idl)), GFP_KERNEL);
- if (!intr_info->idl)
- return -ENOMEM;
-
spin_lock_irqsave(&bnad->bna_lock, flags);
if (bnad->cfg_flags & BNAD_CF_MSIX) {
irq_handler = (irq_handler_t)bnad_msix_mbox_handler;
irq = bnad->msix_table[BNAD_MAILBOX_MSIX_INDEX].vector;
irq_flags = 0;
- intr_info->intr_type = BNA_INTR_T_MSIX;
- intr_info->idl[0].vector = BNAD_MAILBOX_MSIX_INDEX;
} else {
irq_handler = (irq_handler_t)bnad_isr;
irq = bnad->pcidev->irq;
irq_flags = IRQF_SHARED;
- intr_info->intr_type = BNA_INTR_T_INTX;
}
spin_unlock_irqrestore(&bnad->bna_lock, flags);
@@ -1140,11 +1212,6 @@ bnad_mbox_irq_alloc(struct bnad *bnad,
err = request_irq(irq, irq_handler, irq_flags,
bnad->mbox_irq_name, bnad);
- if (err) {
- kfree(intr_info->idl);
- intr_info->idl = NULL;
- }
-
return err;
}
@@ -1158,7 +1225,7 @@ bnad_txrx_irq_free(struct bnad *bnad, struct bna_intr_info *intr_info)
/* Allocates Interrupt Descriptor List for MSIX/INT-X vectors */
static int
bnad_txrx_irq_alloc(struct bnad *bnad, enum bnad_intr_source src,
- uint txrx_id, struct bna_intr_info *intr_info)
+ u32 txrx_id, struct bna_intr_info *intr_info)
{
int i, vector_start = 0;
u32 cfg_flags;
@@ -1241,7 +1308,7 @@ bnad_tx_msix_unregister(struct bnad *bnad, struct bnad_tx_info *tx_info,
*/
static int
bnad_tx_msix_register(struct bnad *bnad, struct bnad_tx_info *tx_info,
- uint tx_id, int num_txqs)
+ u32 tx_id, int num_txqs)
{
int i;
int err;
@@ -1294,7 +1361,7 @@ bnad_rx_msix_unregister(struct bnad *bnad, struct bnad_rx_info *rx_info,
*/
static int
bnad_rx_msix_register(struct bnad *bnad, struct bnad_rx_info *rx_info,
- uint rx_id, int num_rxps)
+ u32 rx_id, int num_rxps)
{
int i;
int err;
@@ -1338,7 +1405,7 @@ bnad_tx_res_free(struct bnad *bnad, struct bna_res_info *res_info)
/* Allocates memory and interrupt resources for Tx object */
static int
bnad_tx_res_alloc(struct bnad *bnad, struct bna_res_info *res_info,
- uint tx_id)
+ u32 tx_id)
{
int i, err = 0;
@@ -1407,7 +1474,7 @@ bnad_ioc_timeout(unsigned long data)
unsigned long flags;
spin_lock_irqsave(&bnad->bna_lock, flags);
- bfa_nw_ioc_timeout((void *) &bnad->bna.device.ioc);
+ bfa_nw_ioc_timeout((void *) &bnad->bna.ioceth.ioc);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
}
@@ -1418,7 +1485,7 @@ bnad_ioc_hb_check(unsigned long data)
unsigned long flags;
spin_lock_irqsave(&bnad->bna_lock, flags);
- bfa_nw_ioc_hb_check((void *) &bnad->bna.device.ioc);
+ bfa_nw_ioc_hb_check((void *) &bnad->bna.ioceth.ioc);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
}
@@ -1429,7 +1496,7 @@ bnad_iocpf_timeout(unsigned long data)
unsigned long flags;
spin_lock_irqsave(&bnad->bna_lock, flags);
- bfa_nw_iocpf_timeout((void *) &bnad->bna.device.ioc);
+ bfa_nw_iocpf_timeout((void *) &bnad->bna.ioceth.ioc);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
}
@@ -1440,7 +1507,7 @@ bnad_iocpf_sem_timeout(unsigned long data)
unsigned long flags;
spin_lock_irqsave(&bnad->bna_lock, flags);
- bfa_nw_iocpf_sem_timeout((void *) &bnad->bna.device.ioc);
+ bfa_nw_iocpf_sem_timeout((void *) &bnad->bna.ioceth.ioc);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
}
@@ -1499,7 +1566,7 @@ bnad_stats_timeout(unsigned long data)
return;
spin_lock_irqsave(&bnad->bna_lock, flags);
- bna_stats_get(&bnad->bna);
+ bna_hw_stats_get(&bnad->bna);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
}
@@ -1577,32 +1644,32 @@ bnad_napi_poll_rx(struct napi_struct *napi, int budget)
{
struct bnad_rx_ctrl *rx_ctrl =
container_of(napi, struct bnad_rx_ctrl, napi);
- struct bna_ccb *ccb;
- struct bnad *bnad;
+ struct bnad *bnad = rx_ctrl->bnad;
int rcvd = 0;
- ccb = rx_ctrl->ccb;
-
- bnad = ccb->bnad;
+ rx_ctrl->rx_poll_ctr++;
if (!netif_carrier_ok(bnad->netdev))
goto poll_exit;
- rcvd = bnad_poll_cq(bnad, ccb, budget);
- if (rcvd == budget)
+ rcvd = bnad_poll_cq(bnad, rx_ctrl->ccb, budget);
+ if (rcvd >= budget)
return rcvd;
poll_exit:
- napi_complete((napi));
+ napi_complete(napi);
- BNAD_UPDATE_CTR(bnad, netif_rx_complete);
+ rx_ctrl->rx_complete++;
+
+ if (rx_ctrl->ccb)
+ bnad_enable_rx_irq_unsafe(rx_ctrl->ccb);
- bnad_enable_rx_irq(bnad, ccb);
return rcvd;
}
+#define BNAD_NAPI_POLL_QUOTA 64
static void
-bnad_napi_enable(struct bnad *bnad, u32 rx_id)
+bnad_napi_init(struct bnad *bnad, u32 rx_id)
{
struct bnad_rx_ctrl *rx_ctrl;
int i;
@@ -1610,9 +1677,20 @@ bnad_napi_enable(struct bnad *bnad, u32 rx_id)
/* Initialize & enable NAPI */
for (i = 0; i < bnad->num_rxp_per_rx; i++) {
rx_ctrl = &bnad->rx_info[rx_id].rx_ctrl[i];
-
netif_napi_add(bnad->netdev, &rx_ctrl->napi,
- bnad_napi_poll_rx, 64);
+ bnad_napi_poll_rx, BNAD_NAPI_POLL_QUOTA);
+ }
+}
+
+static void
+bnad_napi_enable(struct bnad *bnad, u32 rx_id)
+{
+ struct bnad_rx_ctrl *rx_ctrl;
+ int i;
+
+ /* Initialize & enable NAPI */
+ for (i = 0; i < bnad->num_rxp_per_rx; i++) {
+ rx_ctrl = &bnad->rx_info[rx_id].rx_ctrl[i];
napi_enable(&rx_ctrl->napi);
}
@@ -1632,7 +1710,7 @@ bnad_napi_disable(struct bnad *bnad, u32 rx_id)
/* Should be held with conf_lock held */
void
-bnad_cleanup_tx(struct bnad *bnad, uint tx_id)
+bnad_cleanup_tx(struct bnad *bnad, u32 tx_id)
{
struct bnad_tx_info *tx_info = &bnad->tx_info[tx_id];
struct bna_res_info *res_info = &bnad->tx_res_info[tx_id].res_info[0];
@@ -1651,21 +1729,22 @@ bnad_cleanup_tx(struct bnad *bnad, uint tx_id)
bnad_tx_msix_unregister(bnad, tx_info,
bnad->num_txq_per_tx);
+ if (0 == tx_id)
+ tasklet_kill(&bnad->tx_free_tasklet);
+
spin_lock_irqsave(&bnad->bna_lock, flags);
bna_tx_destroy(tx_info->tx);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
tx_info->tx = NULL;
-
- if (0 == tx_id)
- tasklet_kill(&bnad->tx_free_tasklet);
+ tx_info->tx_id = 0;
bnad_tx_res_free(bnad, res_info);
}
/* Should be held with conf_lock held */
int
-bnad_setup_tx(struct bnad *bnad, uint tx_id)
+bnad_setup_tx(struct bnad *bnad, u32 tx_id)
{
int err;
struct bnad_tx_info *tx_info = &bnad->tx_info[tx_id];
@@ -1673,21 +1752,24 @@ bnad_setup_tx(struct bnad *bnad, uint tx_id)
struct bna_intr_info *intr_info =
&res_info[BNA_TX_RES_INTR_T_TXCMPL].res_u.intr_info;
struct bna_tx_config *tx_config = &bnad->tx_config[tx_id];
- struct bna_tx_event_cbfn tx_cbfn;
+ static const struct bna_tx_event_cbfn tx_cbfn = {
+ .tcb_setup_cbfn = bnad_cb_tcb_setup,
+ .tcb_destroy_cbfn = bnad_cb_tcb_destroy,
+ .tx_stall_cbfn = bnad_cb_tx_stall,
+ .tx_resume_cbfn = bnad_cb_tx_resume,
+ .tx_cleanup_cbfn = bnad_cb_tx_cleanup,
+ };
+
struct bna_tx *tx;
unsigned long flags;
+ tx_info->tx_id = tx_id;
+
/* Initialize the Tx object configuration */
tx_config->num_txq = bnad->num_txq_per_tx;
tx_config->txq_depth = bnad->txq_depth;
tx_config->tx_type = BNA_TX_T_REGULAR;
-
- /* Initialize the tx event handlers */
- tx_cbfn.tcb_setup_cbfn = bnad_cb_tcb_setup;
- tx_cbfn.tcb_destroy_cbfn = bnad_cb_tcb_destroy;
- tx_cbfn.tx_stall_cbfn = bnad_cb_tx_stall;
- tx_cbfn.tx_resume_cbfn = bnad_cb_tx_resume;
- tx_cbfn.tx_cleanup_cbfn = bnad_cb_tx_cleanup;
+ tx_config->coalescing_timeo = bnad->tx_coalescing_timeo;
/* Get BNA's resource requirement for one tx object */
spin_lock_irqsave(&bnad->bna_lock, flags);
@@ -1741,14 +1823,15 @@ bnad_init_rx_config(struct bnad *bnad, struct bna_rx_config *rx_config)
{
rx_config->rx_type = BNA_RX_T_REGULAR;
rx_config->num_paths = bnad->num_rxp_per_rx;
+ rx_config->coalescing_timeo = bnad->rx_coalescing_timeo;
if (bnad->num_rxp_per_rx > 1) {
rx_config->rss_status = BNA_STATUS_T_ENABLED;
rx_config->rss_config.hash_type =
- (BFI_RSS_T_V4_TCP |
- BFI_RSS_T_V6_TCP |
- BFI_RSS_T_V4_IP |
- BFI_RSS_T_V6_IP);
+ (BFI_ENET_RSS_IPV6 |
+ BFI_ENET_RSS_IPV6_TCP |
+ BFI_ENET_RSS_IPV4 |
+ BFI_ENET_RSS_IPV4_TCP);
rx_config->rss_config.hash_mask =
bnad->num_rxp_per_rx - 1;
get_random_bytes(rx_config->rss_config.toeplitz_hash_key,
@@ -1766,31 +1849,41 @@ bnad_init_rx_config(struct bnad *bnad, struct bna_rx_config *rx_config)
rx_config->vlan_strip_status = BNA_STATUS_T_ENABLED;
}
+static void
+bnad_rx_ctrl_init(struct bnad *bnad, u32 rx_id)
+{
+ struct bnad_rx_info *rx_info = &bnad->rx_info[rx_id];
+ int i;
+
+ for (i = 0; i < bnad->num_rxp_per_rx; i++)
+ rx_info->rx_ctrl[i].bnad = bnad;
+}
+
/* Called with mutex_lock(&bnad->conf_mutex) held */
void
-bnad_cleanup_rx(struct bnad *bnad, uint rx_id)
+bnad_cleanup_rx(struct bnad *bnad, u32 rx_id)
{
struct bnad_rx_info *rx_info = &bnad->rx_info[rx_id];
struct bna_rx_config *rx_config = &bnad->rx_config[rx_id];
struct bna_res_info *res_info = &bnad->rx_res_info[rx_id].res_info[0];
unsigned long flags;
- int dim_timer_del = 0;
+ int to_del = 0;
if (!rx_info->rx)
return;
if (0 == rx_id) {
spin_lock_irqsave(&bnad->bna_lock, flags);
- dim_timer_del = bnad_dim_timer_running(bnad);
- if (dim_timer_del)
+ if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED &&
+ test_bit(BNAD_RF_DIM_TIMER_RUNNING, &bnad->run_flags)) {
clear_bit(BNAD_RF_DIM_TIMER_RUNNING, &bnad->run_flags);
+ to_del = 1;
+ }
spin_unlock_irqrestore(&bnad->bna_lock, flags);
- if (dim_timer_del)
+ if (to_del)
del_timer_sync(&bnad->dim_timer);
}
- bnad_napi_disable(bnad, rx_id);
-
init_completion(&bnad->bnad_completions.rx_comp);
spin_lock_irqsave(&bnad->bna_lock, flags);
bna_rx_disable(rx_info->rx, BNA_HARD_CLEANUP, bnad_cb_rx_disabled);
@@ -1800,18 +1893,21 @@ bnad_cleanup_rx(struct bnad *bnad, uint rx_id)
if (rx_info->rx_ctrl[0].ccb->intr_type == BNA_INTR_T_MSIX)
bnad_rx_msix_unregister(bnad, rx_info, rx_config->num_paths);
+ bnad_napi_disable(bnad, rx_id);
+
spin_lock_irqsave(&bnad->bna_lock, flags);
bna_rx_destroy(rx_info->rx);
- spin_unlock_irqrestore(&bnad->bna_lock, flags);
rx_info->rx = NULL;
+ rx_info->rx_id = 0;
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
bnad_rx_res_free(bnad, res_info);
}
/* Called with mutex_lock(&bnad->conf_mutex) held */
int
-bnad_setup_rx(struct bnad *bnad, uint rx_id)
+bnad_setup_rx(struct bnad *bnad, u32 rx_id)
{
int err;
struct bnad_rx_info *rx_info = &bnad->rx_info[rx_id];
@@ -1819,21 +1915,23 @@ bnad_setup_rx(struct bnad *bnad, uint rx_id)
struct bna_intr_info *intr_info =
&res_info[BNA_RX_RES_T_INTR].res_u.intr_info;
struct bna_rx_config *rx_config = &bnad->rx_config[rx_id];
- struct bna_rx_event_cbfn rx_cbfn;
+ static const struct bna_rx_event_cbfn rx_cbfn = {
+ .rcb_setup_cbfn = bnad_cb_rcb_setup,
+ .rcb_destroy_cbfn = bnad_cb_rcb_destroy,
+ .ccb_setup_cbfn = bnad_cb_ccb_setup,
+ .ccb_destroy_cbfn = bnad_cb_ccb_destroy,
+ .rx_stall_cbfn = bnad_cb_rx_stall,
+ .rx_cleanup_cbfn = bnad_cb_rx_cleanup,
+ .rx_post_cbfn = bnad_cb_rx_post,
+ };
struct bna_rx *rx;
unsigned long flags;
+ rx_info->rx_id = rx_id;
+
/* Initialize the Rx object configuration */
bnad_init_rx_config(bnad, rx_config);
- /* Initialize the Rx event handlers */
- rx_cbfn.rcb_setup_cbfn = bnad_cb_rcb_setup;
- rx_cbfn.rcb_destroy_cbfn = bnad_cb_rcb_destroy;
- rx_cbfn.ccb_setup_cbfn = bnad_cb_ccb_setup;
- rx_cbfn.ccb_destroy_cbfn = bnad_cb_ccb_destroy;
- rx_cbfn.rx_cleanup_cbfn = bnad_cb_rx_cleanup;
- rx_cbfn.rx_post_cbfn = bnad_cb_rx_post;
-
/* Get BNA's resource requirement for one Rx object */
spin_lock_irqsave(&bnad->bna_lock, flags);
bna_rx_res_req(rx_config, res_info);
@@ -1851,14 +1949,25 @@ bnad_setup_rx(struct bnad *bnad, uint rx_id)
if (err)
return err;
+ bnad_rx_ctrl_init(bnad, rx_id);
+
/* Ask BNA to create one Rx object, supplying required resources */
spin_lock_irqsave(&bnad->bna_lock, flags);
rx = bna_rx_create(&bnad->bna, bnad, rx_config, &rx_cbfn, res_info,
rx_info);
- spin_unlock_irqrestore(&bnad->bna_lock, flags);
- if (!rx)
+ if (!rx) {
+ err = -ENOMEM;
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
goto err_return;
+ }
rx_info->rx = rx;
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ /*
+ * Init NAPI, so that state is set to NAPI_STATE_SCHED,
+ * so that IRQ handler cannot schedule NAPI at this point.
+ */
+ bnad_napi_init(bnad, rx_id);
/* Register ISR for the Rx object */
if (intr_info->intr_type == BNA_INTR_T_MSIX) {
@@ -1868,9 +1977,6 @@ bnad_setup_rx(struct bnad *bnad, uint rx_id)
goto err_return;
}
- /* Enable NAPI */
- bnad_napi_enable(bnad, rx_id);
-
spin_lock_irqsave(&bnad->bna_lock, flags);
if (0 == rx_id) {
/* Set up Dynamic Interrupt Moderation Vector */
@@ -1887,6 +1993,9 @@ bnad_setup_rx(struct bnad *bnad, uint rx_id)
bna_rx_enable(rx);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
+ /* Enable scheduling of NAPI */
+ bnad_napi_enable(bnad, rx_id);
+
return 0;
err_return:
@@ -1926,7 +2035,7 @@ bnad_rx_coalescing_timeo_set(struct bnad *bnad)
/*
* Called with bnad->bna_lock held
*/
-static int
+int
bnad_mac_addr_set_locked(struct bnad *bnad, u8 *mac_addr)
{
int ret;
@@ -1946,7 +2055,7 @@ bnad_mac_addr_set_locked(struct bnad *bnad, u8 *mac_addr)
}
/* Should be called with conf_lock held */
-static int
+int
bnad_enable_default_bcast(struct bnad *bnad)
{
struct bnad_rx_info *rx_info = &bnad->rx_info[0];
@@ -1971,15 +2080,13 @@ bnad_enable_default_bcast(struct bnad *bnad)
return 0;
}
-/* Called with bnad_conf_lock() held */
-static void
+/* Called with mutex_lock(&bnad->conf_mutex) held */
+void
bnad_restore_vlans(struct bnad *bnad, u32 rx_id)
{
u16 vid;
unsigned long flags;
- BUG_ON(!(VLAN_N_VID == (BFI_MAX_VLAN + 1)));
-
for_each_set_bit(vid, bnad->active_vlans, VLAN_N_VID) {
spin_lock_irqsave(&bnad->bna_lock, flags);
bna_rx_vlan_add(bnad->rx_info[rx_id].rx, vid);
@@ -2031,11 +2138,11 @@ bnad_netdev_qstats_fill(struct bnad *bnad, struct rtnl_link_stats64 *stats)
void
bnad_netdev_hwstats_fill(struct bnad *bnad, struct rtnl_link_stats64 *stats)
{
- struct bfi_ll_stats_mac *mac_stats;
- u64 bmap;
+ struct bfi_enet_stats_mac *mac_stats;
+ u32 bmap;
int i;
- mac_stats = &bnad->stats.bna_stats->hw_stats->mac_stats;
+ mac_stats = &bnad->stats.bna_stats->hw_stats.mac_stats;
stats->rx_errors =
mac_stats->rx_fcs_error + mac_stats->rx_alignment_error +
mac_stats->rx_frame_length_error + mac_stats->rx_code_error +
@@ -2054,13 +2161,12 @@ bnad_netdev_hwstats_fill(struct bnad *bnad, struct rtnl_link_stats64 *stats)
stats->rx_crc_errors = mac_stats->rx_fcs_error;
stats->rx_frame_errors = mac_stats->rx_alignment_error;
/* recv'r fifo overrun */
- bmap = (u64)bnad->stats.bna_stats->rxf_bmap[0] |
- ((u64)bnad->stats.bna_stats->rxf_bmap[1] << 32);
- for (i = 0; bmap && (i < BFI_LL_RXF_ID_MAX); i++) {
+ bmap = bna_rx_rid_mask(&bnad->bna);
+ for (i = 0; bmap; i++) {
if (bmap & 1) {
stats->rx_fifo_errors +=
bnad->stats.bna_stats->
- hw_stats->rxf_stats[i].frame_drops;
+ hw_stats.rxf_stats[i].frame_drops;
break;
}
bmap >>= 1;
@@ -2089,9 +2195,6 @@ bnad_tso_prepare(struct bnad *bnad, struct sk_buff *skb)
{
int err;
- /* SKB_GSO_TCPV4 and SKB_GSO_TCPV6 is defined since 2.6.18. */
- BUG_ON(!(skb_shinfo(skb)->gso_type == SKB_GSO_TCPV4 ||
- skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6));
if (skb_header_cloned(skb)) {
err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
if (err) {
@@ -2118,7 +2221,6 @@ bnad_tso_prepare(struct bnad *bnad, struct sk_buff *skb)
} else {
struct ipv6hdr *ipv6h = ipv6_hdr(skb);
- BUG_ON(!(skb->protocol == htons(ETH_P_IPV6)));
ipv6h->payload_len = 0;
tcp_hdr(skb)->check =
~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, 0,
@@ -2140,7 +2242,7 @@ bnad_q_num_init(struct bnad *bnad)
int rxps;
rxps = min((uint)num_online_cpus(),
- (uint)(BNAD_MAX_RXS * BNAD_MAX_RXPS_PER_RX));
+ (uint)(BNAD_MAX_RX * BNAD_MAX_RXP_PER_RX));
if (!(bnad->cfg_flags & BNAD_CF_MSIX))
rxps = 1; /* INTx */
@@ -2158,7 +2260,7 @@ bnad_q_num_init(struct bnad *bnad)
* Called with bnad->bna_lock held b'cos of cfg_flags access
*/
static void
-bnad_q_num_adjust(struct bnad *bnad, int msix_vectors)
+bnad_q_num_adjust(struct bnad *bnad, int msix_vectors, int temp)
{
bnad->num_txq_per_tx = 1;
if ((msix_vectors >= (bnad->num_tx * bnad->num_txq_per_tx) +
@@ -2171,76 +2273,72 @@ bnad_q_num_adjust(struct bnad *bnad, int msix_vectors)
bnad->num_rxp_per_rx = 1;
}
-/* Enable / disable device */
-static void
-bnad_device_disable(struct bnad *bnad)
+/* Enable / disable ioceth */
+static int
+bnad_ioceth_disable(struct bnad *bnad)
{
unsigned long flags;
-
- init_completion(&bnad->bnad_completions.ioc_comp);
+ int err = 0;
spin_lock_irqsave(&bnad->bna_lock, flags);
- bna_device_disable(&bnad->bna.device, BNA_HARD_CLEANUP);
+ init_completion(&bnad->bnad_completions.ioc_comp);
+ bna_ioceth_disable(&bnad->bna.ioceth, BNA_HARD_CLEANUP);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
- wait_for_completion(&bnad->bnad_completions.ioc_comp);
+ wait_for_completion_timeout(&bnad->bnad_completions.ioc_comp,
+ msecs_to_jiffies(BNAD_IOCETH_TIMEOUT));
+
+ err = bnad->bnad_completions.ioc_comp_status;
+ return err;
}
static int
-bnad_device_enable(struct bnad *bnad)
+bnad_ioceth_enable(struct bnad *bnad)
{
int err = 0;
unsigned long flags;
- init_completion(&bnad->bnad_completions.ioc_comp);
-
spin_lock_irqsave(&bnad->bna_lock, flags);
- bna_device_enable(&bnad->bna.device);
+ init_completion(&bnad->bnad_completions.ioc_comp);
+ bnad->bnad_completions.ioc_comp_status = BNA_CB_WAITING;
+ bna_ioceth_enable(&bnad->bna.ioceth);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
- wait_for_completion(&bnad->bnad_completions.ioc_comp);
+ wait_for_completion_timeout(&bnad->bnad_completions.ioc_comp,
+ msecs_to_jiffies(BNAD_IOCETH_TIMEOUT));
- if (bnad->bnad_completions.ioc_comp_status)
- err = bnad->bnad_completions.ioc_comp_status;
+ err = bnad->bnad_completions.ioc_comp_status;
return err;
}
/* Free BNA resources */
static void
-bnad_res_free(struct bnad *bnad)
+bnad_res_free(struct bnad *bnad, struct bna_res_info *res_info,
+ u32 res_val_max)
{
int i;
- struct bna_res_info *res_info = &bnad->res_info[0];
- for (i = 0; i < BNA_RES_T_MAX; i++) {
- if (res_info[i].res_type == BNA_RES_T_MEM)
- bnad_mem_free(bnad, &res_info[i].res_u.mem_info);
- else
- bnad_mbox_irq_free(bnad, &res_info[i].res_u.intr_info);
- }
+ for (i = 0; i < res_val_max; i++)
+ bnad_mem_free(bnad, &res_info[i].res_u.mem_info);
}
/* Allocates memory and interrupt resources for BNA */
static int
-bnad_res_alloc(struct bnad *bnad)
+bnad_res_alloc(struct bnad *bnad, struct bna_res_info *res_info,
+ u32 res_val_max)
{
int i, err;
- struct bna_res_info *res_info = &bnad->res_info[0];
- for (i = 0; i < BNA_RES_T_MAX; i++) {
- if (res_info[i].res_type == BNA_RES_T_MEM)
- err = bnad_mem_alloc(bnad, &res_info[i].res_u.mem_info);
- else
- err = bnad_mbox_irq_alloc(bnad,
- &res_info[i].res_u.intr_info);
+ for (i = 0; i < res_val_max; i++) {
+ err = bnad_mem_alloc(bnad, &res_info[i].res_u.mem_info);
if (err)
goto err_return;
}
return 0;
err_return:
- bnad_res_free(bnad);
+ bnad_res_free(bnad, res_info, res_val_max);
return err;
}
@@ -2273,17 +2371,21 @@ bnad_enable_msix(struct bnad *bnad)
ret = pci_enable_msix(bnad->pcidev, bnad->msix_table, bnad->msix_num);
if (ret > 0) {
/* Not enough MSI-X vectors. */
+ pr_warn("BNA: %d MSI-X vectors allocated < %d requested\n",
+ ret, bnad->msix_num);
spin_lock_irqsave(&bnad->bna_lock, flags);
/* ret = #of vectors that we got */
- bnad_q_num_adjust(bnad, ret);
+ bnad_q_num_adjust(bnad, (ret - BNAD_MAILBOX_MSIX_VECTORS) / 2,
+ (ret - BNAD_MAILBOX_MSIX_VECTORS) / 2);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
- bnad->msix_num = (bnad->num_tx * bnad->num_txq_per_tx)
- + (bnad->num_rx
- * bnad->num_rxp_per_rx) +
+ bnad->msix_num = BNAD_NUM_TXQ + BNAD_NUM_RXP +
BNAD_MAILBOX_MSIX_VECTORS;
+ if (bnad->msix_num > ret)
+ goto intx_mode;
+
/* Try once more with adjusted numbers */
/* If this fails, fall back to INTx */
ret = pci_enable_msix(bnad->pcidev, bnad->msix_table,
@@ -2293,9 +2395,13 @@ bnad_enable_msix(struct bnad *bnad)
} else if (ret < 0)
goto intx_mode;
+
+ pci_intx(bnad->pcidev, 0);
+
return;
intx_mode:
+ pr_warn("BNA: MSI-X enable failed - operating in INTx mode\n");
kfree(bnad->msix_table);
bnad->msix_table = NULL;
@@ -2351,12 +2457,12 @@ bnad_open(struct net_device *netdev)
pause_config.tx_pause = 0;
pause_config.rx_pause = 0;
- mtu = ETH_HLEN + bnad->netdev->mtu + ETH_FCS_LEN;
+ mtu = ETH_HLEN + VLAN_HLEN + bnad->netdev->mtu + ETH_FCS_LEN;
spin_lock_irqsave(&bnad->bna_lock, flags);
- bna_port_mtu_set(&bnad->bna.port, mtu, NULL);
- bna_port_pause_config(&bnad->bna.port, &pause_config, NULL);
- bna_port_enable(&bnad->bna.port);
+ bna_enet_mtu_set(&bnad->bna.enet, mtu, NULL);
+ bna_enet_pause_config(&bnad->bna.enet, &pause_config, NULL);
+ bna_enet_enable(&bnad->bna.enet);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
/* Enable broadcast */
@@ -2396,14 +2502,14 @@ bnad_stop(struct net_device *netdev)
/* Stop the stats timer */
bnad_stats_timer_stop(bnad);
- init_completion(&bnad->bnad_completions.port_comp);
+ init_completion(&bnad->bnad_completions.enet_comp);
spin_lock_irqsave(&bnad->bna_lock, flags);
- bna_port_disable(&bnad->bna.port, BNA_HARD_CLEANUP,
- bnad_cb_port_disabled);
+ bna_enet_disable(&bnad->bna.enet, BNA_HARD_CLEANUP,
+ bnad_cb_enet_disabled);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
- wait_for_completion(&bnad->bnad_completions.port_comp);
+ wait_for_completion(&bnad->bnad_completions.enet_comp);
bnad_cleanup_tx(bnad, 0);
bnad_cleanup_rx(bnad, 0);
@@ -2425,51 +2531,57 @@ static netdev_tx_t
bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct bnad *bnad = netdev_priv(netdev);
+ u32 txq_id = 0;
+ struct bna_tcb *tcb = bnad->tx_info[0].tcb[txq_id];
u16 txq_prod, vlan_tag = 0;
u32 unmap_prod, wis, wis_used, wi_range;
u32 vectors, vect_id, i, acked;
- u32 tx_id;
int err;
+ unsigned int len;
+ u32 gso_size;
- struct bnad_tx_info *tx_info;
- struct bna_tcb *tcb;
- struct bnad_unmap_q *unmap_q;
+ struct bnad_unmap_q *unmap_q = tcb->unmap_q;
dma_addr_t dma_addr;
struct bna_txq_entry *txqent;
- bna_txq_wi_ctrl_flag_t flags;
+ u16 flags;
- if (unlikely
- (skb->len <= ETH_HLEN || skb->len > BFI_TX_MAX_DATA_PER_PKT)) {
+ if (unlikely(skb->len <= ETH_HLEN)) {
dev_kfree_skb(skb);
+ BNAD_UPDATE_CTR(bnad, tx_skb_too_short);
+ return NETDEV_TX_OK;
+ }
+ if (unlikely(skb_headlen(skb) > BFI_TX_MAX_DATA_PER_VECTOR)) {
+ dev_kfree_skb(skb);
+ BNAD_UPDATE_CTR(bnad, tx_skb_headlen_too_long);
+ return NETDEV_TX_OK;
+ }
+ if (unlikely(skb_headlen(skb) == 0)) {
+ dev_kfree_skb(skb);
+ BNAD_UPDATE_CTR(bnad, tx_skb_headlen_zero);
return NETDEV_TX_OK;
}
-
- tx_id = 0;
-
- tx_info = &bnad->tx_info[tx_id];
- tcb = tx_info->tcb[tx_id];
- unmap_q = tcb->unmap_q;
/*
* Takes care of the Tx that is scheduled between clearing the flag
- * and the netif_stop_queue() call.
+ * and the netif_tx_stop_all_queues() call.
*/
if (unlikely(!test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))) {
dev_kfree_skb(skb);
+ BNAD_UPDATE_CTR(bnad, tx_skb_stopping);
return NETDEV_TX_OK;
}
vectors = 1 + skb_shinfo(skb)->nr_frags;
- if (vectors > BFI_TX_MAX_VECTORS_PER_PKT) {
+ if (unlikely(vectors > BFI_TX_MAX_VECTORS_PER_PKT)) {
dev_kfree_skb(skb);
+ BNAD_UPDATE_CTR(bnad, tx_skb_max_vectors);
return NETDEV_TX_OK;
}
wis = BNA_TXQ_WI_NEEDED(vectors); /* 4 vectors per work item */
acked = 0;
- if (unlikely
- (wis > BNA_QE_FREE_CNT(tcb, tcb->q_depth) ||
- vectors > BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth))) {
+ if (unlikely(wis > BNA_QE_FREE_CNT(tcb, tcb->q_depth) ||
+ vectors > BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth))) {
if ((u16) (*tcb->hw_consumer_index) !=
tcb->consumer_index &&
!test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags)) {
@@ -2501,18 +2613,12 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
}
unmap_prod = unmap_q->producer_index;
- wis_used = 1;
- vect_id = 0;
flags = 0;
txq_prod = tcb->producer_index;
BNA_TXQ_QPGE_PTR_GET(txq_prod, tcb->sw_qpt, txqent, wi_range);
- BUG_ON(!(wi_range <= tcb->q_depth));
txqent->hdr.wi.reserved = 0;
txqent->hdr.wi.num_vectors = vectors;
- txqent->hdr.wi.opcode =
- htons((skb_is_gso(skb) ? BNA_TXQ_WI_SEND_LSO :
- BNA_TXQ_WI_SEND));
if (vlan_tx_tag_present(skb)) {
vlan_tag = (u16) vlan_tx_tag_get(skb);
@@ -2527,62 +2633,93 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
txqent->hdr.wi.vlan_tag = htons(vlan_tag);
if (skb_is_gso(skb)) {
+ gso_size = skb_shinfo(skb)->gso_size;
+
+ if (unlikely(gso_size > netdev->mtu)) {
+ dev_kfree_skb(skb);
+ BNAD_UPDATE_CTR(bnad, tx_skb_mss_too_long);
+ return NETDEV_TX_OK;
+ }
+ if (unlikely((gso_size + skb_transport_offset(skb) +
+ tcp_hdrlen(skb)) >= skb->len)) {
+ txqent->hdr.wi.opcode =
+ __constant_htons(BNA_TXQ_WI_SEND);
+ txqent->hdr.wi.lso_mss = 0;
+ BNAD_UPDATE_CTR(bnad, tx_skb_tso_too_short);
+ } else {
+ txqent->hdr.wi.opcode =
+ __constant_htons(BNA_TXQ_WI_SEND_LSO);
+ txqent->hdr.wi.lso_mss = htons(gso_size);
+ }
+
err = bnad_tso_prepare(bnad, skb);
- if (err) {
+ if (unlikely(err)) {
dev_kfree_skb(skb);
+ BNAD_UPDATE_CTR(bnad, tx_skb_tso_prepare);
return NETDEV_TX_OK;
}
- txqent->hdr.wi.lso_mss = htons(skb_is_gso(skb));
flags |= (BNA_TXQ_WI_CF_IP_CKSUM | BNA_TXQ_WI_CF_TCP_CKSUM);
txqent->hdr.wi.l4_hdr_size_n_offset =
htons(BNA_TXQ_WI_L4_HDR_N_OFFSET
(tcp_hdrlen(skb) >> 2,
skb_transport_offset(skb)));
- } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
- u8 proto = 0;
-
+ } else {
+ txqent->hdr.wi.opcode = __constant_htons(BNA_TXQ_WI_SEND);
txqent->hdr.wi.lso_mss = 0;
- if (skb->protocol == htons(ETH_P_IP))
- proto = ip_hdr(skb)->protocol;
- else if (skb->protocol == htons(ETH_P_IPV6)) {
- /* nexthdr may not be TCP immediately. */
- proto = ipv6_hdr(skb)->nexthdr;
+ if (unlikely(skb->len > (netdev->mtu + ETH_HLEN))) {
+ dev_kfree_skb(skb);
+ BNAD_UPDATE_CTR(bnad, tx_skb_non_tso_too_long);
+ return NETDEV_TX_OK;
}
- if (proto == IPPROTO_TCP) {
- flags |= BNA_TXQ_WI_CF_TCP_CKSUM;
- txqent->hdr.wi.l4_hdr_size_n_offset =
- htons(BNA_TXQ_WI_L4_HDR_N_OFFSET
- (0, skb_transport_offset(skb)));
- BNAD_UPDATE_CTR(bnad, tcpcsum_offload);
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ u8 proto = 0;
- BUG_ON(!(skb_headlen(skb) >=
- skb_transport_offset(skb) + tcp_hdrlen(skb)));
-
- } else if (proto == IPPROTO_UDP) {
- flags |= BNA_TXQ_WI_CF_UDP_CKSUM;
- txqent->hdr.wi.l4_hdr_size_n_offset =
- htons(BNA_TXQ_WI_L4_HDR_N_OFFSET
- (0, skb_transport_offset(skb)));
-
- BNAD_UPDATE_CTR(bnad, udpcsum_offload);
+ if (skb->protocol == __constant_htons(ETH_P_IP))
+ proto = ip_hdr(skb)->protocol;
+ else if (skb->protocol ==
+ __constant_htons(ETH_P_IPV6)) {
+ /* nexthdr may not be TCP immediately. */
+ proto = ipv6_hdr(skb)->nexthdr;
+ }
+ if (proto == IPPROTO_TCP) {
+ flags |= BNA_TXQ_WI_CF_TCP_CKSUM;
+ txqent->hdr.wi.l4_hdr_size_n_offset =
+ htons(BNA_TXQ_WI_L4_HDR_N_OFFSET
+ (0, skb_transport_offset(skb)));
+
+ BNAD_UPDATE_CTR(bnad, tcpcsum_offload);
+
+ if (unlikely(skb_headlen(skb) <
+ skb_transport_offset(skb) + tcp_hdrlen(skb))) {
+ dev_kfree_skb(skb);
+ BNAD_UPDATE_CTR(bnad, tx_skb_tcp_hdr);
+ return NETDEV_TX_OK;
+ }
- BUG_ON(!(skb_headlen(skb) >=
- skb_transport_offset(skb) +
- sizeof(struct udphdr)));
- } else {
- err = skb_checksum_help(skb);
- BNAD_UPDATE_CTR(bnad, csum_help);
- if (err) {
+ } else if (proto == IPPROTO_UDP) {
+ flags |= BNA_TXQ_WI_CF_UDP_CKSUM;
+ txqent->hdr.wi.l4_hdr_size_n_offset =
+ htons(BNA_TXQ_WI_L4_HDR_N_OFFSET
+ (0, skb_transport_offset(skb)));
+
+ BNAD_UPDATE_CTR(bnad, udpcsum_offload);
+ if (unlikely(skb_headlen(skb) <
+ skb_transport_offset(skb) +
+ sizeof(struct udphdr))) {
+ dev_kfree_skb(skb);
+ BNAD_UPDATE_CTR(bnad, tx_skb_udp_hdr);
+ return NETDEV_TX_OK;
+ }
+ } else {
dev_kfree_skb(skb);
- BNAD_UPDATE_CTR(bnad, csum_help_err);
+ BNAD_UPDATE_CTR(bnad, tx_skb_csum_err);
return NETDEV_TX_OK;
}
+ } else {
+ txqent->hdr.wi.l4_hdr_size_n_offset = 0;
}
- } else {
- txqent->hdr.wi.lso_mss = 0;
- txqent->hdr.wi.l4_hdr_size_n_offset = 0;
}
txqent->hdr.wi.flags = htons(flags);
@@ -2590,19 +2727,36 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
txqent->hdr.wi.frame_length = htonl(skb->len);
unmap_q->unmap_array[unmap_prod].skb = skb;
- BUG_ON(!(skb_headlen(skb) <= BFI_TX_MAX_DATA_PER_VECTOR));
- txqent->vector[vect_id].length = htons(skb_headlen(skb));
+ len = skb_headlen(skb);
+ txqent->vector[0].length = htons(len);
dma_addr = dma_map_single(&bnad->pcidev->dev, skb->data,
skb_headlen(skb), DMA_TO_DEVICE);
dma_unmap_addr_set(&unmap_q->unmap_array[unmap_prod], dma_addr,
dma_addr);
- BNA_SET_DMA_ADDR(dma_addr, &txqent->vector[vect_id].host_addr);
+ BNA_SET_DMA_ADDR(dma_addr, &txqent->vector[0].host_addr);
BNA_QE_INDX_ADD(unmap_prod, 1, unmap_q->q_depth);
+ vect_id = 0;
+ wis_used = 1;
+
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
- u32 size = frag->size;
+ const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
+ u16 size = skb_frag_size(frag);
+
+ if (unlikely(size == 0)) {
+ unmap_prod = unmap_q->producer_index;
+
+ unmap_prod = bnad_pci_unmap_skb(&bnad->pcidev->dev,
+ unmap_q->unmap_array,
+ unmap_prod, unmap_q->q_depth, skb,
+ i);
+ dev_kfree_skb(skb);
+ BNAD_UPDATE_CTR(bnad, tx_skb_frag_zero);
+ return NETDEV_TX_OK;
+ }
+
+ len += size;
if (++vect_id == BFI_TX_MAX_VECTORS_PER_WI) {
vect_id = 0;
@@ -2614,22 +2768,34 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
wis_used = 0;
BNA_TXQ_QPGE_PTR_GET(txq_prod, tcb->sw_qpt,
txqent, wi_range);
- BUG_ON(!(wi_range <= tcb->q_depth));
}
wis_used++;
- txqent->hdr.wi_ext.opcode = htons(BNA_TXQ_WI_EXTENSION);
+ txqent->hdr.wi_ext.opcode =
+ __constant_htons(BNA_TXQ_WI_EXTENSION);
}
BUG_ON(!(size <= BFI_TX_MAX_DATA_PER_VECTOR));
txqent->vector[vect_id].length = htons(size);
- dma_addr = dma_map_page(&bnad->pcidev->dev, frag->page,
- frag->page_offset, size, DMA_TO_DEVICE);
+ dma_addr = skb_frag_dma_map(&bnad->pcidev->dev, frag,
+ 0, size, DMA_TO_DEVICE);
dma_unmap_addr_set(&unmap_q->unmap_array[unmap_prod], dma_addr,
dma_addr);
BNA_SET_DMA_ADDR(dma_addr, &txqent->vector[vect_id].host_addr);
BNA_QE_INDX_ADD(unmap_prod, 1, unmap_q->q_depth);
}
+ if (unlikely(len != skb->len)) {
+ unmap_prod = unmap_q->producer_index;
+
+ unmap_prod = bnad_pci_unmap_skb(&bnad->pcidev->dev,
+ unmap_q->unmap_array, unmap_prod,
+ unmap_q->q_depth, skb,
+ skb_shinfo(skb)->nr_frags);
+ dev_kfree_skb(skb);
+ BNAD_UPDATE_CTR(bnad, tx_skb_len_mismatch);
+ return NETDEV_TX_OK;
+ }
+
unmap_q->producer_index = unmap_prod;
BNA_QE_INDX_ADD(txq_prod, wis_used, tcb->q_depth);
tcb->producer_index = txq_prod;
@@ -2640,6 +2806,7 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
return NETDEV_TX_OK;
bna_txq_prod_indx_doorbell(tcb);
+ smp_mb();
if ((u16) (*tcb->hw_consumer_index) != tcb->consumer_index)
tasklet_schedule(&bnad->tx_free_tasklet);
@@ -2667,7 +2834,7 @@ bnad_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats)
return stats;
}
-static void
+void
bnad_set_rx_mode(struct net_device *netdev)
{
struct bnad *bnad = netdev_priv(netdev);
@@ -2706,6 +2873,9 @@ bnad_set_rx_mode(struct net_device *netdev)
}
}
+ if (bnad->rx_info[0].rx == NULL)
+ goto unlock;
+
bna_rx_mode_set(bnad->rx_info[0].rx, new_mask, valid_mask, NULL);
if (!netdev_mc_empty(netdev)) {
@@ -2760,11 +2930,25 @@ bnad_set_mac_address(struct net_device *netdev, void *mac_addr)
}
static int
-bnad_change_mtu(struct net_device *netdev, int new_mtu)
+bnad_mtu_set(struct bnad *bnad, int mtu)
{
- int mtu, err = 0;
unsigned long flags;
+ init_completion(&bnad->bnad_completions.mtu_comp);
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bna_enet_mtu_set(&bnad->bna.enet, mtu, bnad_cb_enet_mtu_set);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ wait_for_completion(&bnad->bnad_completions.mtu_comp);
+
+ return bnad->bnad_completions.mtu_comp_status;
+}
+
+static int
+bnad_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ int err, mtu = netdev->mtu;
struct bnad *bnad = netdev_priv(netdev);
if (new_mtu + ETH_HLEN < ETH_ZLEN || new_mtu > BNAD_JUMBO_MTU)
@@ -2774,11 +2958,10 @@ bnad_change_mtu(struct net_device *netdev, int new_mtu)
netdev->mtu = new_mtu;
- mtu = ETH_HLEN + new_mtu + ETH_FCS_LEN;
-
- spin_lock_irqsave(&bnad->bna_lock, flags);
- bna_port_mtu_set(&bnad->bna.port, mtu, NULL);
- spin_unlock_irqrestore(&bnad->bna_lock, flags);
+ mtu = ETH_HLEN + VLAN_HLEN + new_mtu + ETH_FCS_LEN;
+ err = bnad_mtu_set(bnad, mtu);
+ if (err)
+ err = -EBUSY;
mutex_unlock(&bnad->conf_mutex);
return err;
@@ -2839,18 +3022,21 @@ bnad_netpoll(struct net_device *netdev)
bnad_isr(bnad->pcidev->irq, netdev);
bna_intx_enable(&bnad->bna, curr_mask);
} else {
+ /*
+ * Tx processing may happen in sending context, so no need
+ * to explicitly process completions here
+ */
+
+ /* Rx processing */
for (i = 0; i < bnad->num_rx; i++) {
rx_info = &bnad->rx_info[i];
if (!rx_info->rx)
continue;
for (j = 0; j < bnad->num_rxp_per_rx; j++) {
rx_ctrl = &rx_info->rx_ctrl[j];
- if (rx_ctrl->ccb) {
- bnad_disable_rx_irq(bnad,
- rx_ctrl->ccb);
+ if (rx_ctrl->ccb)
bnad_netif_rx_schedule_poll(bnad,
rx_ctrl->ccb);
- }
}
}
}
@@ -2863,7 +3049,6 @@ static const struct net_device_ops bnad_netdev_ops = {
.ndo_start_xmit = bnad_start_xmit,
.ndo_get_stats64 = bnad_get_stats64,
.ndo_set_rx_mode = bnad_set_rx_mode,
- .ndo_set_multicast_list = bnad_set_rx_mode,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = bnad_set_mac_address,
.ndo_change_mtu = bnad_change_mtu,
@@ -2968,7 +3153,7 @@ bnad_uninit(struct bnad *bnad)
/*
* Initialize locks
- a) Per device mutes used for serializing configuration
+ a) Per ioceth mutes used for serializing configuration
changes from OS interface
b) spin lock used to protect bna state machine
*/
@@ -3033,7 +3218,7 @@ static int __devinit
bnad_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *pcidev_id)
{
- bool using_dac = false;
+ bool using_dac;
int err;
struct bnad *bnad;
struct bna *bna;
@@ -3058,12 +3243,15 @@ bnad_pci_probe(struct pci_dev *pdev,
*/
netdev = alloc_etherdev(sizeof(struct bnad));
if (!netdev) {
- dev_err(&pdev->dev, "alloc_etherdev failed\n");
+ dev_err(&pdev->dev, "netdev allocation failed\n");
err = -ENOMEM;
return err;
}
bnad = netdev_priv(netdev);
+ bnad_lock_init(bnad);
+
+ mutex_lock(&bnad->conf_mutex);
/*
* PCI initialization
* Output : using_dac = 1 for 64 bit DMA
@@ -3071,9 +3259,8 @@ bnad_pci_probe(struct pci_dev *pdev,
*/
err = bnad_pci_init(bnad, pdev, &using_dac);
if (err)
- goto free_netdev;
+ goto unlock_mutex;
- bnad_lock_init(bnad);
/*
* Initialize bnad structure
* Setup relation between pci_dev & netdev
@@ -3082,21 +3269,22 @@ bnad_pci_probe(struct pci_dev *pdev,
err = bnad_init(bnad, pdev, netdev);
if (err)
goto pci_uninit;
+
/* Initialize netdev structure, set up ethtool ops */
bnad_netdev_init(bnad, using_dac);
/* Set link to down state */
netif_carrier_off(netdev);
- bnad_enable_msix(bnad);
-
/* Get resource requirement form bna */
+ spin_lock_irqsave(&bnad->bna_lock, flags);
bna_res_req(&bnad->res_info[0]);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
/* Allocate resources from bna */
- err = bnad_res_alloc(bnad);
+ err = bnad_res_alloc(bnad, &bnad->res_info[0], BNA_RES_T_MAX);
if (err)
- goto free_netdev;
+ goto drv_uninit;
bna = &bnad->bna;
@@ -3106,38 +3294,74 @@ bnad_pci_probe(struct pci_dev *pdev,
pcidev_info.device_id = bnad->pcidev->device;
pcidev_info.pci_bar_kva = bnad->bar0;
- mutex_lock(&bnad->conf_mutex);
-
spin_lock_irqsave(&bnad->bna_lock, flags);
bna_init(bna, bnad, &pcidev_info, &bnad->res_info[0]);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
bnad->stats.bna_stats = &bna->stats;
+ bnad_enable_msix(bnad);
+ err = bnad_mbox_irq_alloc(bnad);
+ if (err)
+ goto res_free;
+
+
/* Set up timers */
- setup_timer(&bnad->bna.device.ioc.ioc_timer, bnad_ioc_timeout,
+ setup_timer(&bnad->bna.ioceth.ioc.ioc_timer, bnad_ioc_timeout,
((unsigned long)bnad));
- setup_timer(&bnad->bna.device.ioc.hb_timer, bnad_ioc_hb_check,
+ setup_timer(&bnad->bna.ioceth.ioc.hb_timer, bnad_ioc_hb_check,
((unsigned long)bnad));
- setup_timer(&bnad->bna.device.ioc.iocpf_timer, bnad_iocpf_timeout,
+ setup_timer(&bnad->bna.ioceth.ioc.iocpf_timer, bnad_iocpf_timeout,
((unsigned long)bnad));
- setup_timer(&bnad->bna.device.ioc.sem_timer, bnad_iocpf_sem_timeout,
+ setup_timer(&bnad->bna.ioceth.ioc.sem_timer, bnad_iocpf_sem_timeout,
((unsigned long)bnad));
/* Now start the timer before calling IOC */
- mod_timer(&bnad->bna.device.ioc.iocpf_timer,
+ mod_timer(&bnad->bna.ioceth.ioc.iocpf_timer,
jiffies + msecs_to_jiffies(BNA_IOC_TIMER_FREQ));
/*
* Start the chip
- * Don't care even if err != 0, bna state machine will
- * deal with it
+ * If the call back comes with error, we bail out.
+ * This is a catastrophic error.
*/
- err = bnad_device_enable(bnad);
+ err = bnad_ioceth_enable(bnad);
+ if (err) {
+ pr_err("BNA: Initialization failed err=%d\n",
+ err);
+ goto probe_success;
+ }
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ if (bna_num_txq_set(bna, BNAD_NUM_TXQ + 1) ||
+ bna_num_rxp_set(bna, BNAD_NUM_RXP + 1)) {
+ bnad_q_num_adjust(bnad, bna_attr(bna)->num_txq - 1,
+ bna_attr(bna)->num_rxp - 1);
+ if (bna_num_txq_set(bna, BNAD_NUM_TXQ + 1) ||
+ bna_num_rxp_set(bna, BNAD_NUM_RXP + 1))
+ err = -EIO;
+ }
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+ if (err)
+ goto disable_ioceth;
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bna_mod_res_req(&bnad->bna, &bnad->mod_res_info[0]);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+ err = bnad_res_alloc(bnad, &bnad->mod_res_info[0], BNA_MOD_RES_T_MAX);
+ if (err) {
+ err = -EIO;
+ goto disable_ioceth;
+ }
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bna_mod_init(&bnad->bna, &bnad->mod_res_info[0]);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
/* Get the burnt-in mac */
spin_lock_irqsave(&bnad->bna_lock, flags);
- bna_port_mac_get(&bna->port, &bnad->perm_addr);
+ bna_enet_perm_mac_get(&bna->enet, &bnad->perm_addr);
bnad_set_netdev_perm_addr(bnad);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
@@ -3147,29 +3371,38 @@ bnad_pci_probe(struct pci_dev *pdev,
err = register_netdev(netdev);
if (err) {
pr_err("BNA : Registering with netdev failed\n");
- goto disable_device;
+ goto probe_uninit;
}
+ set_bit(BNAD_RF_NETDEV_REGISTERED, &bnad->run_flags);
return 0;
-disable_device:
+probe_success:
+ mutex_unlock(&bnad->conf_mutex);
+ return 0;
+
+probe_uninit:
mutex_lock(&bnad->conf_mutex);
- bnad_device_disable(bnad);
- del_timer_sync(&bnad->bna.device.ioc.ioc_timer);
- del_timer_sync(&bnad->bna.device.ioc.sem_timer);
- del_timer_sync(&bnad->bna.device.ioc.hb_timer);
+ bnad_res_free(bnad, &bnad->mod_res_info[0], BNA_MOD_RES_T_MAX);
+disable_ioceth:
+ bnad_ioceth_disable(bnad);
+ del_timer_sync(&bnad->bna.ioceth.ioc.ioc_timer);
+ del_timer_sync(&bnad->bna.ioceth.ioc.sem_timer);
+ del_timer_sync(&bnad->bna.ioceth.ioc.hb_timer);
spin_lock_irqsave(&bnad->bna_lock, flags);
bna_uninit(bna);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
- mutex_unlock(&bnad->conf_mutex);
-
- bnad_res_free(bnad);
+ bnad_mbox_irq_free(bnad);
bnad_disable_msix(bnad);
+res_free:
+ bnad_res_free(bnad, &bnad->res_info[0], BNA_RES_T_MAX);
+drv_uninit:
+ bnad_uninit(bnad);
pci_uninit:
bnad_pci_uninit(pdev);
+unlock_mutex:
+ mutex_unlock(&bnad->conf_mutex);
bnad_lock_uninit(bnad);
- bnad_uninit(bnad);
-free_netdev:
free_netdev(netdev);
return err;
}
@@ -3189,21 +3422,24 @@ bnad_pci_remove(struct pci_dev *pdev)
bnad = netdev_priv(netdev);
bna = &bnad->bna;
- unregister_netdev(netdev);
+ if (test_and_clear_bit(BNAD_RF_NETDEV_REGISTERED, &bnad->run_flags))
+ unregister_netdev(netdev);
mutex_lock(&bnad->conf_mutex);
- bnad_device_disable(bnad);
- del_timer_sync(&bnad->bna.device.ioc.ioc_timer);
- del_timer_sync(&bnad->bna.device.ioc.sem_timer);
- del_timer_sync(&bnad->bna.device.ioc.hb_timer);
+ bnad_ioceth_disable(bnad);
+ del_timer_sync(&bnad->bna.ioceth.ioc.ioc_timer);
+ del_timer_sync(&bnad->bna.ioceth.ioc.sem_timer);
+ del_timer_sync(&bnad->bna.ioceth.ioc.hb_timer);
spin_lock_irqsave(&bnad->bna_lock, flags);
bna_uninit(bna);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
- mutex_unlock(&bnad->conf_mutex);
- bnad_res_free(bnad);
+ bnad_res_free(bnad, &bnad->mod_res_info[0], BNA_MOD_RES_T_MAX);
+ bnad_res_free(bnad, &bnad->res_info[0], BNA_RES_T_MAX);
+ bnad_mbox_irq_free(bnad);
bnad_disable_msix(bnad);
bnad_pci_uninit(pdev);
+ mutex_unlock(&bnad->conf_mutex);
bnad_lock_uninit(bnad);
bnad_uninit(bnad);
free_netdev(netdev);
@@ -3215,7 +3451,14 @@ static DEFINE_PCI_DEVICE_TABLE(bnad_pci_id_table) = {
PCI_DEVICE_ID_BROCADE_CT),
.class = PCI_CLASS_NETWORK_ETHERNET << 8,
.class_mask = 0xffff00
- }, {0, }
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_BROCADE,
+ BFA_PCI_DEVICE_ID_CT2),
+ .class = PCI_CLASS_NETWORK_ETHERNET << 8,
+ .class_mask = 0xffff00
+ },
+ {0, },
};
MODULE_DEVICE_TABLE(pci, bnad_pci_id_table);
@@ -3264,3 +3507,4 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Brocade 10G PCIe Ethernet driver");
MODULE_VERSION(BNAD_VERSION);
MODULE_FIRMWARE(CNA_FW_FILE_CT);
+MODULE_FIRMWARE(CNA_FW_FILE_CT2);
diff --git a/drivers/net/bna/bnad.h b/drivers/net/ethernet/brocade/bna/bnad.h
index 458eb30371b5..5487ca42d018 100644
--- a/drivers/net/bna/bnad.h
+++ b/drivers/net/ethernet/brocade/bna/bnad.h
@@ -38,12 +38,13 @@
#define BNAD_TXQ_DEPTH 2048
#define BNAD_RXQ_DEPTH 2048
-#define BNAD_MAX_TXS 1
+#define BNAD_MAX_TX 1
#define BNAD_MAX_TXQ_PER_TX 8 /* 8 priority queues */
#define BNAD_TXQ_NUM 1
-#define BNAD_MAX_RXS 1
-#define BNAD_MAX_RXPS_PER_RX 16
+#define BNAD_MAX_RX 1
+#define BNAD_MAX_RXP_PER_RX 16
+#define BNAD_MAX_RXQ_PER_RXP 2
/*
* Control structure pointed to ccb->ctrl, which
@@ -52,21 +53,25 @@
*/
struct bnad_rx_ctrl {
struct bna_ccb *ccb;
+ struct bnad *bnad;
unsigned long flags;
struct napi_struct napi;
+ u64 rx_intr_ctr;
+ u64 rx_poll_ctr;
+ u64 rx_schedule;
+ u64 rx_keep_poll;
+ u64 rx_complete;
};
#define BNAD_RXMODE_PROMISC_DEFAULT BNA_RXMODE_PROMISC
-#define BNAD_GET_TX_ID(_skb) (0)
-
/*
* GLOBAL #defines (CONSTANTS)
*/
#define BNAD_NAME "bna"
#define BNAD_NAME_LEN 64
-#define BNAD_VERSION "2.3.2.3"
+#define BNAD_VERSION "3.0.2.2"
#define BNAD_MAILBOX_MSIX_INDEX 0
#define BNAD_MAILBOX_MSIX_VECTORS 1
@@ -76,9 +81,15 @@ struct bnad_rx_ctrl {
#define BNAD_STATS_TIMER_FREQ 1000 /* in msecs */
#define BNAD_DIM_TIMER_FREQ 1000 /* in msecs */
+#define BNAD_IOCETH_TIMEOUT 10000
+
#define BNAD_MAX_Q_DEPTH 0x10000
#define BNAD_MIN_Q_DEPTH 0x200
+#define BNAD_MAX_RXQ_DEPTH (BNAD_MAX_Q_DEPTH / bnad_rxqs_per_cq)
+/* keeping MAX TX and RX Q depth equal */
+#define BNAD_MAX_TXQ_DEPTH BNAD_MAX_RXQ_DEPTH
+
#define BNAD_JUMBO_MTU 9000
#define BNAD_NETIF_WAKE_THRESHOLD 8
@@ -92,6 +103,11 @@ struct bnad_rx_ctrl {
/* Bit positions for rcb->flags */
#define BNAD_RXQ_REFILL 0
#define BNAD_RXQ_STARTED 1
+#define BNAD_RXQ_POST_OK 2
+
+/* Resource limits */
+#define BNAD_NUM_TXQ (bnad->num_tx * bnad->num_txq_per_tx)
+#define BNAD_NUM_RXP (bnad->num_rx * bnad->num_rxp_per_rx)
/*
* DATA STRUCTURES
@@ -115,7 +131,8 @@ struct bnad_completion {
struct completion tx_comp;
struct completion rx_comp;
struct completion stats_comp;
- struct completion port_comp;
+ struct completion enet_comp;
+ struct completion mtu_comp;
u8 ioc_comp_status;
u8 ucast_comp_status;
@@ -124,6 +141,7 @@ struct bnad_completion {
u8 rx_comp_status;
u8 stats_comp_status;
u8 port_comp_status;
+ u8 mtu_comp_status;
};
/* Tx Rx Control Stats */
@@ -137,15 +155,26 @@ struct bnad_drv_stats {
u64 tcpcsum_offload;
u64 udpcsum_offload;
u64 csum_help;
- u64 csum_help_err;
+ u64 tx_skb_too_short;
+ u64 tx_skb_stopping;
+ u64 tx_skb_max_vectors;
+ u64 tx_skb_mss_too_long;
+ u64 tx_skb_tso_too_short;
+ u64 tx_skb_tso_prepare;
+ u64 tx_skb_non_tso_too_long;
+ u64 tx_skb_tcp_hdr;
+ u64 tx_skb_udp_hdr;
+ u64 tx_skb_csum_err;
+ u64 tx_skb_headlen_too_long;
+ u64 tx_skb_headlen_zero;
+ u64 tx_skb_frag_zero;
+ u64 tx_skb_len_mismatch;
u64 hw_stats_updates;
- u64 netif_rx_schedule;
- u64 netif_rx_complete;
u64 netif_rx_dropped;
u64 link_toggle;
- u64 cee_up;
+ u64 cee_toggle;
u64 rxp_info_alloc_failed;
u64 mbox_intr_disabled;
@@ -174,12 +203,14 @@ struct bnad_rx_res_info {
struct bnad_tx_info {
struct bna_tx *tx; /* 1:1 between tx_info & tx */
struct bna_tcb *tcb[BNAD_MAX_TXQ_PER_TX];
+ u32 tx_id;
} ____cacheline_aligned;
struct bnad_rx_info {
struct bna_rx *rx; /* 1:1 between rx_info & rx */
- struct bnad_rx_ctrl rx_ctrl[BNAD_MAX_RXPS_PER_RX];
+ struct bnad_rx_ctrl rx_ctrl[BNAD_MAX_RXP_PER_RX];
+ u32 rx_id;
} ____cacheline_aligned;
/* Unmap queues for Tx / Rx cleanup */
@@ -205,20 +236,25 @@ struct bnad_unmap_q {
/* Defines for run_flags bit-mask */
/* Set, tested & cleared using xxx_bit() functions */
/* Values indicated bit positions */
-#define BNAD_RF_CEE_RUNNING 1
+#define BNAD_RF_CEE_RUNNING 0
+#define BNAD_RF_MTU_SET 1
#define BNAD_RF_MBOX_IRQ_DISABLED 2
-#define BNAD_RF_RX_STARTED 3
+#define BNAD_RF_NETDEV_REGISTERED 3
#define BNAD_RF_DIM_TIMER_RUNNING 4
#define BNAD_RF_STATS_TIMER_RUNNING 5
-#define BNAD_RF_TX_SHUTDOWN_DELAYED 6
-#define BNAD_RF_RX_SHUTDOWN_DELAYED 7
+#define BNAD_RF_TX_PRIO_SET 6
+
+
+/* Define for Fast Path flags */
+/* Defined as bit positions */
+#define BNAD_FP_IN_RX_PATH 0
struct bnad {
struct net_device *netdev;
/* Data path */
- struct bnad_tx_info tx_info[BNAD_MAX_TXS];
- struct bnad_rx_info rx_info[BNAD_MAX_RXS];
+ struct bnad_tx_info tx_info[BNAD_MAX_TX];
+ struct bnad_rx_info rx_info[BNAD_MAX_RX];
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
/*
@@ -238,8 +274,8 @@ struct bnad {
u8 tx_coalescing_timeo;
u8 rx_coalescing_timeo;
- struct bna_rx_config rx_config[BNAD_MAX_RXS];
- struct bna_tx_config tx_config[BNAD_MAX_TXS];
+ struct bna_rx_config rx_config[BNAD_MAX_RX];
+ struct bna_tx_config tx_config[BNAD_MAX_TX];
void __iomem *bar0; /* BAR0 address */
@@ -265,8 +301,9 @@ struct bnad {
/* Control path resources, memory & irq */
struct bna_res_info res_info[BNA_RES_T_MAX];
- struct bnad_tx_res_info tx_res_info[BNAD_MAX_TXS];
- struct bnad_rx_res_info rx_res_info[BNAD_MAX_RXS];
+ struct bna_res_info mod_res_info[BNA_MOD_RES_T_MAX];
+ struct bnad_tx_res_info tx_res_info[BNAD_MAX_TX];
+ struct bnad_rx_res_info rx_res_info[BNAD_MAX_RX];
struct bnad_completion bnad_completions;
@@ -296,16 +333,22 @@ extern u32 bnad_rxqs_per_cq;
*/
extern u32 *cna_get_firmware_buf(struct pci_dev *pdev);
/* Netdev entry point prototypes */
+extern void bnad_set_rx_mode(struct net_device *netdev);
+extern struct net_device_stats *bnad_get_netdev_stats(
+ struct net_device *netdev);
+extern int bnad_mac_addr_set_locked(struct bnad *bnad, u8 *mac_addr);
+extern int bnad_enable_default_bcast(struct bnad *bnad);
+extern void bnad_restore_vlans(struct bnad *bnad, u32 rx_id);
extern void bnad_set_ethtool_ops(struct net_device *netdev);
/* Configuration & setup */
extern void bnad_tx_coalescing_timeo_set(struct bnad *bnad);
extern void bnad_rx_coalescing_timeo_set(struct bnad *bnad);
-extern int bnad_setup_rx(struct bnad *bnad, uint rx_id);
-extern int bnad_setup_tx(struct bnad *bnad, uint tx_id);
-extern void bnad_cleanup_tx(struct bnad *bnad, uint tx_id);
-extern void bnad_cleanup_rx(struct bnad *bnad, uint rx_id);
+extern int bnad_setup_rx(struct bnad *bnad, u32 rx_id);
+extern int bnad_setup_tx(struct bnad *bnad, u32 tx_id);
+extern void bnad_cleanup_tx(struct bnad *bnad, u32 tx_id);
+extern void bnad_cleanup_rx(struct bnad *bnad, u32 rx_id);
/* Timer start/stop protos */
extern void bnad_dim_timer_start(struct bnad *bnad);
@@ -327,15 +370,11 @@ extern void bnad_netdev_hwstats_fill(struct bnad *bnad,
#define bnad_enable_rx_irq_unsafe(_ccb) \
{ \
- if (likely(test_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags))) {\
+ if (likely(test_bit(BNAD_RXQ_STARTED, &(_ccb)->rcb[0]->flags))) {\
bna_ib_coalescing_timer_set((_ccb)->i_dbell, \
(_ccb)->rx_coalescing_timeo); \
bna_ib_ack((_ccb)->i_dbell, 0); \
} \
}
-#define bnad_dim_timer_running(_bnad) \
- (((_bnad)->cfg_flags & BNAD_CF_DIM_ENABLED) && \
- (test_bit(BNAD_RF_DIM_TIMER_RUNNING, &((_bnad)->run_flags))))
-
#endif /* __BNAD_H__ */
diff --git a/drivers/net/bna/bnad_ethtool.c b/drivers/net/ethernet/brocade/bna/bnad_ethtool.c
index fea07f19a5db..fd3dcc1e9145 100644
--- a/drivers/net/bna/bnad_ethtool.c
+++ b/drivers/net/ethernet/brocade/bna/bnad_ethtool.c
@@ -29,14 +29,14 @@
#define BNAD_NUM_TXF_COUNTERS 12
#define BNAD_NUM_RXF_COUNTERS 10
-#define BNAD_NUM_CQ_COUNTERS 3
+#define BNAD_NUM_CQ_COUNTERS (3 + 5)
#define BNAD_NUM_RXQ_COUNTERS 6
#define BNAD_NUM_TXQ_COUNTERS 5
#define BNAD_ETHTOOL_STATS_NUM \
(sizeof(struct rtnl_link_stats64) / sizeof(u64) + \
sizeof(struct bnad_drv_stats) / sizeof(u64) + \
- offsetof(struct bfi_ll_stats, rxf_stats[0]) / sizeof(u64))
+ offsetof(struct bfi_enet_stats, rxf_stats[0]) / sizeof(u64))
static char *bnad_net_stats_strings[BNAD_ETHTOOL_STATS_NUM] = {
"rx_packets",
@@ -75,14 +75,25 @@ static char *bnad_net_stats_strings[BNAD_ETHTOOL_STATS_NUM] = {
"tcpcsum_offload",
"udpcsum_offload",
"csum_help",
- "csum_help_err",
+ "tx_skb_too_short",
+ "tx_skb_stopping",
+ "tx_skb_max_vectors",
+ "tx_skb_mss_too_long",
+ "tx_skb_tso_too_short",
+ "tx_skb_tso_prepare",
+ "tx_skb_non_tso_too_long",
+ "tx_skb_tcp_hdr",
+ "tx_skb_udp_hdr",
+ "tx_skb_csum_err",
+ "tx_skb_headlen_too_long",
+ "tx_skb_headlen_zero",
+ "tx_skb_frag_zero",
+ "tx_skb_len_mismatch",
"hw_stats_updates",
- "netif_rx_schedule",
- "netif_rx_complete",
"netif_rx_dropped",
"link_toggle",
- "cee_up",
+ "cee_toggle",
"rxp_info_alloc_failed",
"mbox_intr_disabled",
@@ -201,6 +212,20 @@ static char *bnad_net_stats_strings[BNAD_ETHTOOL_STATS_NUM] = {
"rad_rx_bcast_vlan",
"rad_rx_drops",
+ "rlb_rad_rx_frames",
+ "rlb_rad_rx_octets",
+ "rlb_rad_rx_vlan_frames",
+ "rlb_rad_rx_ucast",
+ "rlb_rad_rx_ucast_octets",
+ "rlb_rad_rx_ucast_vlan",
+ "rlb_rad_rx_mcast",
+ "rlb_rad_rx_mcast_octets",
+ "rlb_rad_rx_mcast_vlan",
+ "rlb_rad_rx_bcast",
+ "rlb_rad_rx_bcast_octets",
+ "rlb_rad_rx_bcast_vlan",
+ "rlb_rad_rx_drops",
+
"fc_rx_ucast_octets",
"fc_rx_ucast",
"fc_rx_ucast_vlan",
@@ -277,7 +302,7 @@ bnad_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
ioc_attr = kzalloc(sizeof(*ioc_attr), GFP_KERNEL);
if (ioc_attr) {
spin_lock_irqsave(&bnad->bna_lock, flags);
- bfa_nw_ioc_get_attr(&bnad->bna.device.ioc, ioc_attr);
+ bfa_nw_ioc_get_attr(&bnad->bna.ioceth.ioc, ioc_attr);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
strncpy(drvinfo->fw_version, ioc_attr->adapter_attr.fw_ver,
@@ -288,323 +313,6 @@ bnad_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
strncpy(drvinfo->bus_info, pci_name(bnad->pcidev), ETHTOOL_BUSINFO_LEN);
}
-static int
-get_regs(struct bnad *bnad, u32 * regs)
-{
- int num = 0, i;
- u32 reg_addr;
- unsigned long flags;
-
-#define BNAD_GET_REG(addr) \
-do { \
- if (regs) \
- regs[num++] = readl(bnad->bar0 + (addr)); \
- else \
- num++; \
-} while (0)
-
- spin_lock_irqsave(&bnad->bna_lock, flags);
-
- /* DMA Block Internal Registers */
- BNAD_GET_REG(DMA_CTRL_REG0);
- BNAD_GET_REG(DMA_CTRL_REG1);
- BNAD_GET_REG(DMA_ERR_INT_STATUS);
- BNAD_GET_REG(DMA_ERR_INT_ENABLE);
- BNAD_GET_REG(DMA_ERR_INT_STATUS_SET);
-
- /* APP Block Register Address Offset from BAR0 */
- BNAD_GET_REG(HOSTFN0_INT_STATUS);
- BNAD_GET_REG(HOSTFN0_INT_MASK);
- BNAD_GET_REG(HOST_PAGE_NUM_FN0);
- BNAD_GET_REG(HOST_MSIX_ERR_INDEX_FN0);
- BNAD_GET_REG(FN0_PCIE_ERR_REG);
- BNAD_GET_REG(FN0_ERR_TYPE_STATUS_REG);
- BNAD_GET_REG(FN0_ERR_TYPE_MSK_STATUS_REG);
-
- BNAD_GET_REG(HOSTFN1_INT_STATUS);
- BNAD_GET_REG(HOSTFN1_INT_MASK);
- BNAD_GET_REG(HOST_PAGE_NUM_FN1);
- BNAD_GET_REG(HOST_MSIX_ERR_INDEX_FN1);
- BNAD_GET_REG(FN1_PCIE_ERR_REG);
- BNAD_GET_REG(FN1_ERR_TYPE_STATUS_REG);
- BNAD_GET_REG(FN1_ERR_TYPE_MSK_STATUS_REG);
-
- BNAD_GET_REG(PCIE_MISC_REG);
-
- BNAD_GET_REG(HOST_SEM0_INFO_REG);
- BNAD_GET_REG(HOST_SEM1_INFO_REG);
- BNAD_GET_REG(HOST_SEM2_INFO_REG);
- BNAD_GET_REG(HOST_SEM3_INFO_REG);
-
- BNAD_GET_REG(TEMPSENSE_CNTL_REG);
- BNAD_GET_REG(TEMPSENSE_STAT_REG);
-
- BNAD_GET_REG(APP_LOCAL_ERR_STAT);
- BNAD_GET_REG(APP_LOCAL_ERR_MSK);
-
- BNAD_GET_REG(PCIE_LNK_ERR_STAT);
- BNAD_GET_REG(PCIE_LNK_ERR_MSK);
-
- BNAD_GET_REG(FCOE_FIP_ETH_TYPE);
- BNAD_GET_REG(RESV_ETH_TYPE);
-
- BNAD_GET_REG(HOSTFN2_INT_STATUS);
- BNAD_GET_REG(HOSTFN2_INT_MASK);
- BNAD_GET_REG(HOST_PAGE_NUM_FN2);
- BNAD_GET_REG(HOST_MSIX_ERR_INDEX_FN2);
- BNAD_GET_REG(FN2_PCIE_ERR_REG);
- BNAD_GET_REG(FN2_ERR_TYPE_STATUS_REG);
- BNAD_GET_REG(FN2_ERR_TYPE_MSK_STATUS_REG);
-
- BNAD_GET_REG(HOSTFN3_INT_STATUS);
- BNAD_GET_REG(HOSTFN3_INT_MASK);
- BNAD_GET_REG(HOST_PAGE_NUM_FN3);
- BNAD_GET_REG(HOST_MSIX_ERR_INDEX_FN3);
- BNAD_GET_REG(FN3_PCIE_ERR_REG);
- BNAD_GET_REG(FN3_ERR_TYPE_STATUS_REG);
- BNAD_GET_REG(FN3_ERR_TYPE_MSK_STATUS_REG);
-
- /* Host Command Status Registers */
- reg_addr = HOST_CMDSTS0_CLR_REG;
- for (i = 0; i < 16; i++) {
- BNAD_GET_REG(reg_addr);
- BNAD_GET_REG(reg_addr + 4);
- BNAD_GET_REG(reg_addr + 8);
- reg_addr += 0x10;
- }
-
- /* Function ID register */
- BNAD_GET_REG(FNC_ID_REG);
-
- /* Function personality register */
- BNAD_GET_REG(FNC_PERS_REG);
-
- /* Operation mode register */
- BNAD_GET_REG(OP_MODE);
-
- /* LPU0 Registers */
- BNAD_GET_REG(LPU0_MBOX_CTL_REG);
- BNAD_GET_REG(LPU0_MBOX_CMD_REG);
- BNAD_GET_REG(LPU0_MBOX_LINK_0REG);
- BNAD_GET_REG(LPU1_MBOX_LINK_0REG);
- BNAD_GET_REG(LPU0_MBOX_STATUS_0REG);
- BNAD_GET_REG(LPU1_MBOX_STATUS_0REG);
- BNAD_GET_REG(LPU0_ERR_STATUS_REG);
- BNAD_GET_REG(LPU0_ERR_SET_REG);
-
- /* LPU1 Registers */
- BNAD_GET_REG(LPU1_MBOX_CTL_REG);
- BNAD_GET_REG(LPU1_MBOX_CMD_REG);
- BNAD_GET_REG(LPU0_MBOX_LINK_1REG);
- BNAD_GET_REG(LPU1_MBOX_LINK_1REG);
- BNAD_GET_REG(LPU0_MBOX_STATUS_1REG);
- BNAD_GET_REG(LPU1_MBOX_STATUS_1REG);
- BNAD_GET_REG(LPU1_ERR_STATUS_REG);
- BNAD_GET_REG(LPU1_ERR_SET_REG);
-
- /* PSS Registers */
- BNAD_GET_REG(PSS_CTL_REG);
- BNAD_GET_REG(PSS_ERR_STATUS_REG);
- BNAD_GET_REG(ERR_STATUS_SET);
- BNAD_GET_REG(PSS_RAM_ERR_STATUS_REG);
-
- /* Catapult CPQ Registers */
- BNAD_GET_REG(HOSTFN0_LPU0_MBOX0_CMD_STAT);
- BNAD_GET_REG(HOSTFN0_LPU1_MBOX0_CMD_STAT);
- BNAD_GET_REG(LPU0_HOSTFN0_MBOX0_CMD_STAT);
- BNAD_GET_REG(LPU1_HOSTFN0_MBOX0_CMD_STAT);
-
- BNAD_GET_REG(HOSTFN0_LPU0_MBOX1_CMD_STAT);
- BNAD_GET_REG(HOSTFN0_LPU1_MBOX1_CMD_STAT);
- BNAD_GET_REG(LPU0_HOSTFN0_MBOX1_CMD_STAT);
- BNAD_GET_REG(LPU1_HOSTFN0_MBOX1_CMD_STAT);
-
- BNAD_GET_REG(HOSTFN1_LPU0_MBOX0_CMD_STAT);
- BNAD_GET_REG(HOSTFN1_LPU1_MBOX0_CMD_STAT);
- BNAD_GET_REG(LPU0_HOSTFN1_MBOX0_CMD_STAT);
- BNAD_GET_REG(LPU1_HOSTFN1_MBOX0_CMD_STAT);
-
- BNAD_GET_REG(HOSTFN1_LPU0_MBOX1_CMD_STAT);
- BNAD_GET_REG(HOSTFN1_LPU1_MBOX1_CMD_STAT);
- BNAD_GET_REG(LPU0_HOSTFN1_MBOX1_CMD_STAT);
- BNAD_GET_REG(LPU1_HOSTFN1_MBOX1_CMD_STAT);
-
- BNAD_GET_REG(HOSTFN2_LPU0_MBOX0_CMD_STAT);
- BNAD_GET_REG(HOSTFN2_LPU1_MBOX0_CMD_STAT);
- BNAD_GET_REG(LPU0_HOSTFN2_MBOX0_CMD_STAT);
- BNAD_GET_REG(LPU1_HOSTFN2_MBOX0_CMD_STAT);
-
- BNAD_GET_REG(HOSTFN2_LPU0_MBOX1_CMD_STAT);
- BNAD_GET_REG(HOSTFN2_LPU1_MBOX1_CMD_STAT);
- BNAD_GET_REG(LPU0_HOSTFN2_MBOX1_CMD_STAT);
- BNAD_GET_REG(LPU1_HOSTFN2_MBOX1_CMD_STAT);
-
- BNAD_GET_REG(HOSTFN3_LPU0_MBOX0_CMD_STAT);
- BNAD_GET_REG(HOSTFN3_LPU1_MBOX0_CMD_STAT);
- BNAD_GET_REG(LPU0_HOSTFN3_MBOX0_CMD_STAT);
- BNAD_GET_REG(LPU1_HOSTFN3_MBOX0_CMD_STAT);
-
- BNAD_GET_REG(HOSTFN3_LPU0_MBOX1_CMD_STAT);
- BNAD_GET_REG(HOSTFN3_LPU1_MBOX1_CMD_STAT);
- BNAD_GET_REG(LPU0_HOSTFN3_MBOX1_CMD_STAT);
- BNAD_GET_REG(LPU1_HOSTFN3_MBOX1_CMD_STAT);
-
- /* Host Function Force Parity Error Registers */
- BNAD_GET_REG(HOSTFN0_LPU_FORCE_PERR);
- BNAD_GET_REG(HOSTFN1_LPU_FORCE_PERR);
- BNAD_GET_REG(HOSTFN2_LPU_FORCE_PERR);
- BNAD_GET_REG(HOSTFN3_LPU_FORCE_PERR);
-
- /* LL Port[0|1] Halt Mask Registers */
- BNAD_GET_REG(LL_HALT_MSK_P0);
- BNAD_GET_REG(LL_HALT_MSK_P1);
-
- /* LL Port[0|1] Error Mask Registers */
- BNAD_GET_REG(LL_ERR_MSK_P0);
- BNAD_GET_REG(LL_ERR_MSK_P1);
-
- /* EMC FLI Registers */
- BNAD_GET_REG(FLI_CMD_REG);
- BNAD_GET_REG(FLI_ADDR_REG);
- BNAD_GET_REG(FLI_CTL_REG);
- BNAD_GET_REG(FLI_WRDATA_REG);
- BNAD_GET_REG(FLI_RDDATA_REG);
- BNAD_GET_REG(FLI_DEV_STATUS_REG);
- BNAD_GET_REG(FLI_SIG_WD_REG);
-
- BNAD_GET_REG(FLI_DEV_VENDOR_REG);
- BNAD_GET_REG(FLI_ERR_STATUS_REG);
-
- /* RxAdm 0 Registers */
- BNAD_GET_REG(RAD0_CTL_REG);
- BNAD_GET_REG(RAD0_PE_PARM_REG);
- BNAD_GET_REG(RAD0_BCN_REG);
- BNAD_GET_REG(RAD0_DEFAULT_REG);
- BNAD_GET_REG(RAD0_PROMISC_REG);
- BNAD_GET_REG(RAD0_BCNQ_REG);
- BNAD_GET_REG(RAD0_DEFAULTQ_REG);
-
- BNAD_GET_REG(RAD0_ERR_STS);
- BNAD_GET_REG(RAD0_SET_ERR_STS);
- BNAD_GET_REG(RAD0_ERR_INT_EN);
- BNAD_GET_REG(RAD0_FIRST_ERR);
- BNAD_GET_REG(RAD0_FORCE_ERR);
-
- BNAD_GET_REG(RAD0_MAC_MAN_1H);
- BNAD_GET_REG(RAD0_MAC_MAN_1L);
- BNAD_GET_REG(RAD0_MAC_MAN_2H);
- BNAD_GET_REG(RAD0_MAC_MAN_2L);
- BNAD_GET_REG(RAD0_MAC_MAN_3H);
- BNAD_GET_REG(RAD0_MAC_MAN_3L);
- BNAD_GET_REG(RAD0_MAC_MAN_4H);
- BNAD_GET_REG(RAD0_MAC_MAN_4L);
-
- BNAD_GET_REG(RAD0_LAST4_IP);
-
- /* RxAdm 1 Registers */
- BNAD_GET_REG(RAD1_CTL_REG);
- BNAD_GET_REG(RAD1_PE_PARM_REG);
- BNAD_GET_REG(RAD1_BCN_REG);
- BNAD_GET_REG(RAD1_DEFAULT_REG);
- BNAD_GET_REG(RAD1_PROMISC_REG);
- BNAD_GET_REG(RAD1_BCNQ_REG);
- BNAD_GET_REG(RAD1_DEFAULTQ_REG);
-
- BNAD_GET_REG(RAD1_ERR_STS);
- BNAD_GET_REG(RAD1_SET_ERR_STS);
- BNAD_GET_REG(RAD1_ERR_INT_EN);
-
- /* TxA0 Registers */
- BNAD_GET_REG(TXA0_CTRL_REG);
- /* TxA0 TSO Sequence # Registers (RO) */
- for (i = 0; i < 8; i++) {
- BNAD_GET_REG(TXA0_TSO_TCP_SEQ_REG(i));
- BNAD_GET_REG(TXA0_TSO_IP_INFO_REG(i));
- }
-
- /* TxA1 Registers */
- BNAD_GET_REG(TXA1_CTRL_REG);
- /* TxA1 TSO Sequence # Registers (RO) */
- for (i = 0; i < 8; i++) {
- BNAD_GET_REG(TXA1_TSO_TCP_SEQ_REG(i));
- BNAD_GET_REG(TXA1_TSO_IP_INFO_REG(i));
- }
-
- /* RxA Registers */
- BNAD_GET_REG(RXA0_CTL_REG);
- BNAD_GET_REG(RXA1_CTL_REG);
-
- /* PLB0 Registers */
- BNAD_GET_REG(PLB0_ECM_TIMER_REG);
- BNAD_GET_REG(PLB0_RL_CTL);
- for (i = 0; i < 8; i++)
- BNAD_GET_REG(PLB0_RL_MAX_BC(i));
- BNAD_GET_REG(PLB0_RL_TU_PRIO);
- for (i = 0; i < 8; i++)
- BNAD_GET_REG(PLB0_RL_BYTE_CNT(i));
- BNAD_GET_REG(PLB0_RL_MIN_REG);
- BNAD_GET_REG(PLB0_RL_MAX_REG);
- BNAD_GET_REG(PLB0_EMS_ADD_REG);
-
- /* PLB1 Registers */
- BNAD_GET_REG(PLB1_ECM_TIMER_REG);
- BNAD_GET_REG(PLB1_RL_CTL);
- for (i = 0; i < 8; i++)
- BNAD_GET_REG(PLB1_RL_MAX_BC(i));
- BNAD_GET_REG(PLB1_RL_TU_PRIO);
- for (i = 0; i < 8; i++)
- BNAD_GET_REG(PLB1_RL_BYTE_CNT(i));
- BNAD_GET_REG(PLB1_RL_MIN_REG);
- BNAD_GET_REG(PLB1_RL_MAX_REG);
- BNAD_GET_REG(PLB1_EMS_ADD_REG);
-
- /* HQM Control Register */
- BNAD_GET_REG(HQM0_CTL_REG);
- BNAD_GET_REG(HQM0_RXQ_STOP_SEM);
- BNAD_GET_REG(HQM0_TXQ_STOP_SEM);
- BNAD_GET_REG(HQM1_CTL_REG);
- BNAD_GET_REG(HQM1_RXQ_STOP_SEM);
- BNAD_GET_REG(HQM1_TXQ_STOP_SEM);
-
- /* LUT Registers */
- BNAD_GET_REG(LUT0_ERR_STS);
- BNAD_GET_REG(LUT0_SET_ERR_STS);
- BNAD_GET_REG(LUT1_ERR_STS);
- BNAD_GET_REG(LUT1_SET_ERR_STS);
-
- /* TRC Registers */
- BNAD_GET_REG(TRC_CTL_REG);
- BNAD_GET_REG(TRC_MODS_REG);
- BNAD_GET_REG(TRC_TRGC_REG);
- BNAD_GET_REG(TRC_CNT1_REG);
- BNAD_GET_REG(TRC_CNT2_REG);
- BNAD_GET_REG(TRC_NXTS_REG);
- BNAD_GET_REG(TRC_DIRR_REG);
- for (i = 0; i < 10; i++)
- BNAD_GET_REG(TRC_TRGM_REG(i));
- for (i = 0; i < 10; i++)
- BNAD_GET_REG(TRC_NXTM_REG(i));
- for (i = 0; i < 10; i++)
- BNAD_GET_REG(TRC_STRM_REG(i));
-
- spin_unlock_irqrestore(&bnad->bna_lock, flags);
-#undef BNAD_GET_REG
- return num;
-}
-static int
-bnad_get_regs_len(struct net_device *netdev)
-{
- int ret = get_regs(netdev_priv(netdev), NULL) * sizeof(u32);
- return ret;
-}
-
-static void
-bnad_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *buf)
-{
- memset(buf, 0, bnad_get_regs_len(netdev));
- get_regs(netdev_priv(netdev), buf);
-}
-
static void
bnad_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wolinfo)
{
@@ -638,7 +346,7 @@ bnad_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
{
struct bnad *bnad = netdev_priv(netdev);
unsigned long flags;
- int dim_timer_del = 0;
+ int to_del = 0;
if (coalesce->rx_coalesce_usecs == 0 ||
coalesce->rx_coalesce_usecs >
@@ -665,14 +373,17 @@ bnad_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
} else {
if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED) {
bnad->cfg_flags &= ~BNAD_CF_DIM_ENABLED;
- dim_timer_del = bnad_dim_timer_running(bnad);
- if (dim_timer_del) {
+ if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED &&
+ test_bit(BNAD_RF_DIM_TIMER_RUNNING,
+ &bnad->run_flags)) {
clear_bit(BNAD_RF_DIM_TIMER_RUNNING,
&bnad->run_flags);
- spin_unlock_irqrestore(&bnad->bna_lock, flags);
- del_timer_sync(&bnad->dim_timer);
- spin_lock_irqsave(&bnad->bna_lock, flags);
+ to_del = 1;
}
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+ if (to_del)
+ del_timer_sync(&bnad->dim_timer);
+ spin_lock_irqsave(&bnad->bna_lock, flags);
bnad_rx_coalescing_timeo_set(bnad);
}
}
@@ -707,14 +418,10 @@ bnad_get_ringparam(struct net_device *netdev,
{
struct bnad *bnad = netdev_priv(netdev);
- ringparam->rx_max_pending = BNAD_MAX_Q_DEPTH / bnad_rxqs_per_cq;
- ringparam->rx_mini_max_pending = 0;
- ringparam->rx_jumbo_max_pending = 0;
- ringparam->tx_max_pending = BNAD_MAX_Q_DEPTH;
+ ringparam->rx_max_pending = BNAD_MAX_RXQ_DEPTH;
+ ringparam->tx_max_pending = BNAD_MAX_TXQ_DEPTH;
ringparam->rx_pending = bnad->rxq_depth;
- ringparam->rx_mini_max_pending = 0;
- ringparam->rx_jumbo_max_pending = 0;
ringparam->tx_pending = bnad->txq_depth;
}
@@ -724,6 +431,7 @@ bnad_set_ringparam(struct net_device *netdev,
{
int i, current_err, err = 0;
struct bnad *bnad = netdev_priv(netdev);
+ unsigned long flags;
mutex_lock(&bnad->conf_mutex);
if (ringparam->rx_pending == bnad->rxq_depth &&
@@ -733,13 +441,13 @@ bnad_set_ringparam(struct net_device *netdev,
}
if (ringparam->rx_pending < BNAD_MIN_Q_DEPTH ||
- ringparam->rx_pending > BNAD_MAX_Q_DEPTH / bnad_rxqs_per_cq ||
+ ringparam->rx_pending > BNAD_MAX_RXQ_DEPTH ||
!BNA_POWER_OF_2(ringparam->rx_pending)) {
mutex_unlock(&bnad->conf_mutex);
return -EINVAL;
}
if (ringparam->tx_pending < BNAD_MIN_Q_DEPTH ||
- ringparam->tx_pending > BNAD_MAX_Q_DEPTH ||
+ ringparam->tx_pending > BNAD_MAX_TXQ_DEPTH ||
!BNA_POWER_OF_2(ringparam->tx_pending)) {
mutex_unlock(&bnad->conf_mutex);
return -EINVAL;
@@ -747,6 +455,11 @@ bnad_set_ringparam(struct net_device *netdev,
if (ringparam->rx_pending != bnad->rxq_depth) {
bnad->rxq_depth = ringparam->rx_pending;
+ if (!netif_running(netdev)) {
+ mutex_unlock(&bnad->conf_mutex);
+ return 0;
+ }
+
for (i = 0; i < bnad->num_rx; i++) {
if (!bnad->rx_info[i].rx)
continue;
@@ -755,9 +468,26 @@ bnad_set_ringparam(struct net_device *netdev,
if (current_err && !err)
err = current_err;
}
+
+ if (!err && bnad->rx_info[0].rx) {
+ /* restore rx configuration */
+ bnad_restore_vlans(bnad, 0);
+ bnad_enable_default_bcast(bnad);
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+ bnad_mac_addr_set_locked(bnad, netdev->dev_addr);
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+ bnad->cfg_flags &= ~(BNAD_CF_ALLMULTI |
+ BNAD_CF_PROMISC);
+ bnad_set_rx_mode(netdev);
+ }
}
if (ringparam->tx_pending != bnad->txq_depth) {
bnad->txq_depth = ringparam->tx_pending;
+ if (!netif_running(netdev)) {
+ mutex_unlock(&bnad->conf_mutex);
+ return 0;
+ }
+
for (i = 0; i < bnad->num_tx; i++) {
if (!bnad->tx_info[i].tx)
continue;
@@ -779,8 +509,8 @@ bnad_get_pauseparam(struct net_device *netdev,
struct bnad *bnad = netdev_priv(netdev);
pauseparam->autoneg = 0;
- pauseparam->rx_pause = bnad->bna.port.pause_config.rx_pause;
- pauseparam->tx_pause = bnad->bna.port.pause_config.tx_pause;
+ pauseparam->rx_pause = bnad->bna.enet.pause_config.rx_pause;
+ pauseparam->tx_pause = bnad->bna.enet.pause_config.tx_pause;
}
static int
@@ -795,12 +525,12 @@ bnad_set_pauseparam(struct net_device *netdev,
return -EINVAL;
mutex_lock(&bnad->conf_mutex);
- if (pauseparam->rx_pause != bnad->bna.port.pause_config.rx_pause ||
- pauseparam->tx_pause != bnad->bna.port.pause_config.tx_pause) {
+ if (pauseparam->rx_pause != bnad->bna.enet.pause_config.rx_pause ||
+ pauseparam->tx_pause != bnad->bna.enet.pause_config.tx_pause) {
pause_config.rx_pause = pauseparam->rx_pause;
pause_config.tx_pause = pauseparam->tx_pause;
spin_lock_irqsave(&bnad->bna_lock, flags);
- bna_port_pause_config(&bnad->bna.port, &pause_config, NULL);
+ bna_enet_pause_config(&bnad->bna.enet, &pause_config, NULL);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
}
mutex_unlock(&bnad->conf_mutex);
@@ -812,7 +542,7 @@ bnad_get_strings(struct net_device *netdev, u32 stringset, u8 * string)
{
struct bnad *bnad = netdev_priv(netdev);
int i, j, q_num;
- u64 bmap;
+ u32 bmap;
mutex_lock(&bnad->conf_mutex);
@@ -825,9 +555,8 @@ bnad_get_strings(struct net_device *netdev, u32 stringset, u8 * string)
ETH_GSTRING_LEN);
string += ETH_GSTRING_LEN;
}
- bmap = (u64)bnad->bna.tx_mod.txf_bmap[0] |
- ((u64)bnad->bna.tx_mod.txf_bmap[1] << 32);
- for (i = 0; bmap && (i < BFI_LL_TXF_ID_MAX); i++) {
+ bmap = bna_tx_rid_mask(&bnad->bna);
+ for (i = 0; bmap; i++) {
if (bmap & 1) {
sprintf(string, "txf%d_ucast_octets", i);
string += ETH_GSTRING_LEN;
@@ -857,9 +586,8 @@ bnad_get_strings(struct net_device *netdev, u32 stringset, u8 * string)
bmap >>= 1;
}
- bmap = (u64)bnad->bna.rx_mod.rxf_bmap[0] |
- ((u64)bnad->bna.rx_mod.rxf_bmap[1] << 32);
- for (i = 0; bmap && (i < BFI_LL_RXF_ID_MAX); i++) {
+ bmap = bna_rx_rid_mask(&bnad->bna);
+ for (i = 0; bmap; i++) {
if (bmap & 1) {
sprintf(string, "rxf%d_ucast_octets", i);
string += ETH_GSTRING_LEN;
@@ -897,6 +625,16 @@ bnad_get_strings(struct net_device *netdev, u32 stringset, u8 * string)
sprintf(string, "cq%d_hw_producer_index",
q_num);
string += ETH_GSTRING_LEN;
+ sprintf(string, "cq%d_intr", q_num);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "cq%d_poll", q_num);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "cq%d_schedule", q_num);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "cq%d_keep_poll", q_num);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "cq%d_complete", q_num);
+ string += ETH_GSTRING_LEN;
q_num++;
}
}
@@ -979,19 +717,17 @@ static int
bnad_get_stats_count_locked(struct net_device *netdev)
{
struct bnad *bnad = netdev_priv(netdev);
- int i, j, count, rxf_active_num = 0, txf_active_num = 0;
- u64 bmap;
+ int i, j, count = 0, rxf_active_num = 0, txf_active_num = 0;
+ u32 bmap;
- bmap = (u64)bnad->bna.tx_mod.txf_bmap[0] |
- ((u64)bnad->bna.tx_mod.txf_bmap[1] << 32);
- for (i = 0; bmap && (i < BFI_LL_TXF_ID_MAX); i++) {
+ bmap = bna_tx_rid_mask(&bnad->bna);
+ for (i = 0; bmap; i++) {
if (bmap & 1)
txf_active_num++;
bmap >>= 1;
}
- bmap = (u64)bnad->bna.rx_mod.rxf_bmap[0] |
- ((u64)bnad->bna.rx_mod.rxf_bmap[1] << 32);
- for (i = 0; bmap && (i < BFI_LL_RXF_ID_MAX); i++) {
+ bmap = bna_rx_rid_mask(&bnad->bna);
+ for (i = 0; bmap; i++) {
if (bmap & 1)
rxf_active_num++;
bmap >>= 1;
@@ -1039,6 +775,17 @@ bnad_per_q_stats_fill(struct bnad *bnad, u64 *buf, int bi)
buf[bi++] = 0; /* ccb->consumer_index */
buf[bi++] = *(bnad->rx_info[i].rx_ctrl[j].
ccb->hw_producer_index);
+
+ buf[bi++] = bnad->rx_info[i].
+ rx_ctrl[j].rx_intr_ctr;
+ buf[bi++] = bnad->rx_info[i].
+ rx_ctrl[j].rx_poll_ctr;
+ buf[bi++] = bnad->rx_info[i].
+ rx_ctrl[j].rx_schedule;
+ buf[bi++] = bnad->rx_info[i].
+ rx_ctrl[j].rx_keep_poll;
+ buf[bi++] = bnad->rx_info[i].
+ rx_ctrl[j].rx_complete;
}
}
for (i = 0; i < bnad->num_rx; i++) {
@@ -1104,7 +851,7 @@ bnad_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats,
unsigned long flags;
struct rtnl_link_stats64 *net_stats64;
u64 *stats64;
- u64 bmap;
+ u32 bmap;
mutex_lock(&bnad->conf_mutex);
if (bnad_get_stats_count_locked(netdev) != stats->n_stats) {
@@ -1135,20 +882,20 @@ bnad_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats,
buf[bi++] = stats64[i];
/* Fill hardware stats excluding the rxf/txf into ethtool bufs */
- stats64 = (u64 *) bnad->stats.bna_stats->hw_stats;
+ stats64 = (u64 *) &bnad->stats.bna_stats->hw_stats;
for (i = 0;
- i < offsetof(struct bfi_ll_stats, rxf_stats[0]) / sizeof(u64);
+ i < offsetof(struct bfi_enet_stats, rxf_stats[0]) /
+ sizeof(u64);
i++)
buf[bi++] = stats64[i];
/* Fill txf stats into ethtool buffers */
- bmap = (u64)bnad->bna.tx_mod.txf_bmap[0] |
- ((u64)bnad->bna.tx_mod.txf_bmap[1] << 32);
- for (i = 0; bmap && (i < BFI_LL_TXF_ID_MAX); i++) {
+ bmap = bna_tx_rid_mask(&bnad->bna);
+ for (i = 0; bmap; i++) {
if (bmap & 1) {
stats64 = (u64 *)&bnad->stats.bna_stats->
- hw_stats->txf_stats[i];
- for (j = 0; j < sizeof(struct bfi_ll_stats_txf) /
+ hw_stats.txf_stats[i];
+ for (j = 0; j < sizeof(struct bfi_enet_stats_txf) /
sizeof(u64); j++)
buf[bi++] = stats64[j];
}
@@ -1156,13 +903,12 @@ bnad_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats,
}
/* Fill rxf stats into ethtool buffers */
- bmap = (u64)bnad->bna.rx_mod.rxf_bmap[0] |
- ((u64)bnad->bna.rx_mod.rxf_bmap[1] << 32);
- for (i = 0; bmap && (i < BFI_LL_RXF_ID_MAX); i++) {
+ bmap = bna_rx_rid_mask(&bnad->bna);
+ for (i = 0; bmap; i++) {
if (bmap & 1) {
stats64 = (u64 *)&bnad->stats.bna_stats->
- hw_stats->rxf_stats[i];
- for (j = 0; j < sizeof(struct bfi_ll_stats_rxf) /
+ hw_stats.rxf_stats[i];
+ for (j = 0; j < sizeof(struct bfi_enet_stats_rxf) /
sizeof(u64); j++)
buf[bi++] = stats64[j];
}
@@ -1192,8 +938,6 @@ static struct ethtool_ops bnad_ethtool_ops = {
.get_settings = bnad_get_settings,
.set_settings = bnad_set_settings,
.get_drvinfo = bnad_get_drvinfo,
- .get_regs_len = bnad_get_regs_len,
- .get_regs = bnad_get_regs,
.get_wol = bnad_get_wol,
.get_link = ethtool_op_get_link,
.get_coalesce = bnad_get_coalesce,
diff --git a/drivers/net/bna/cna.h b/drivers/net/ethernet/brocade/bna/cna.h
index a679e038747b..1b3e90dfbd9a 100644
--- a/drivers/net/bna/cna.h
+++ b/drivers/net/ethernet/brocade/bna/cna.h
@@ -21,26 +21,24 @@
#include <linux/kernel.h>
#include <linux/types.h>
+#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/bitops.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
+#include <linux/if_vlan.h>
#include <linux/if_ether.h>
-#include <asm/page.h>
-#include <asm/io.h>
-#include <asm/string.h>
-
-#include <linux/list.h>
#define bfa_sm_fault(__event) do { \
- pr_err("SM Assertion failure: %s: %d: event = %d", __FILE__, __LINE__, \
- __event); \
+ pr_err("SM Assertion failure: %s: %d: event = %d\n", \
+ __FILE__, __LINE__, __event); \
} while (0)
extern char bfa_version[];
-#define CNA_FW_FILE_CT "ctfw_cna.bin"
+#define CNA_FW_FILE_CT "ctfw.bin"
+#define CNA_FW_FILE_CT2 "ct2fw.bin"
#define FC_SYMNAME_MAX 256 /*!< max name server symbolic name size */
#pragma pack(1)
@@ -77,4 +75,33 @@ typedef struct mac { u8 mac[MAC_ADDRLEN]; } mac_t;
} \
}
+/*
+ * bfa_q_deq_tail - dequeue an element from tail of the queue
+ */
+#define bfa_q_deq_tail(_q, _qe) { \
+ if (!list_empty(_q)) { \
+ *((struct list_head **) (_qe)) = bfa_q_prev(_q); \
+ bfa_q_next(bfa_q_prev(*((struct list_head **) _qe))) = \
+ (struct list_head *) (_q); \
+ bfa_q_prev(_q) = bfa_q_prev(*(struct list_head **) _qe);\
+ bfa_q_qe_init(*((struct list_head **) _qe)); \
+ } else { \
+ *((struct list_head **) (_qe)) = (struct list_head *) NULL; \
+ } \
+}
+
+/*
+ * bfa_add_tail_head - enqueue an element at the head of queue
+ */
+#define bfa_q_enq_head(_q, _qe) { \
+ if (!(bfa_q_next(_qe) == NULL) && (bfa_q_prev(_qe) == NULL)) \
+ pr_err("Assertion failure: %s:%d: %d", \
+ __FILE__, __LINE__, \
+ (bfa_q_next(_qe) == NULL) && (bfa_q_prev(_qe) == NULL));\
+ bfa_q_next(_qe) = bfa_q_next(_q); \
+ bfa_q_prev(_qe) = (struct list_head *) (_q); \
+ bfa_q_prev(bfa_q_next(_q)) = (struct list_head *) (_qe); \
+ bfa_q_next(_q) = (struct list_head *) (_qe); \
+}
+
#endif /* __CNA_H__ */
diff --git a/drivers/net/bna/cna_fwimg.c b/drivers/net/ethernet/brocade/bna/cna_fwimg.c
index e8f4ecd9ebb5..725b9fff337f 100644
--- a/drivers/net/bna/cna_fwimg.c
+++ b/drivers/net/ethernet/brocade/bna/cna_fwimg.c
@@ -16,11 +16,12 @@
* www.brocade.com
*/
#include <linux/firmware.h>
+#include "bfi.h"
#include "cna.h"
const struct firmware *bfi_fw;
-static u32 *bfi_image_ct_cna;
-static u32 bfi_image_ct_cna_size;
+static u32 *bfi_image_ct_cna, *bfi_image_ct2_cna;
+static u32 bfi_image_ct_cna_size, bfi_image_ct2_cna_size;
static u32 *
cna_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
@@ -45,20 +46,47 @@ error:
u32 *
cna_get_firmware_buf(struct pci_dev *pdev)
{
- if (bfi_image_ct_cna_size == 0)
- cna_read_firmware(pdev, &bfi_image_ct_cna,
- &bfi_image_ct_cna_size, CNA_FW_FILE_CT);
- return bfi_image_ct_cna;
+ if (pdev->device == BFA_PCI_DEVICE_ID_CT2) {
+ if (bfi_image_ct2_cna_size == 0)
+ cna_read_firmware(pdev, &bfi_image_ct2_cna,
+ &bfi_image_ct2_cna_size, CNA_FW_FILE_CT2);
+ return bfi_image_ct2_cna;
+ } else if (bfa_asic_id_ct(pdev->device)) {
+ if (bfi_image_ct_cna_size == 0)
+ cna_read_firmware(pdev, &bfi_image_ct_cna,
+ &bfi_image_ct_cna_size, CNA_FW_FILE_CT);
+ return bfi_image_ct_cna;
+ }
+
+ return NULL;
}
u32 *
-bfa_cb_image_get_chunk(int type, u32 off)
+bfa_cb_image_get_chunk(enum bfi_asic_gen asic_gen, u32 off)
{
- return (u32 *)(bfi_image_ct_cna + off);
+ switch (asic_gen) {
+ case BFI_ASIC_GEN_CT:
+ return (u32 *)(bfi_image_ct_cna + off);
+ break;
+ case BFI_ASIC_GEN_CT2:
+ return (u32 *)(bfi_image_ct2_cna + off);
+ break;
+ default:
+ return NULL;
+ }
}
u32
-bfa_cb_image_get_size(int type)
+bfa_cb_image_get_size(enum bfi_asic_gen asic_gen)
{
- return bfi_image_ct_cna_size;
+ switch (asic_gen) {
+ case BFI_ASIC_GEN_CT:
+ return bfi_image_ct_cna_size;
+ break;
+ case BFI_ASIC_GEN_CT2:
+ return bfi_image_ct2_cna_size;
+ break;
+ default:
+ return 0;
+ }
}
diff --git a/drivers/net/ethernet/cadence/Kconfig b/drivers/net/ethernet/cadence/Kconfig
new file mode 100644
index 000000000000..98849a1fc749
--- /dev/null
+++ b/drivers/net/ethernet/cadence/Kconfig
@@ -0,0 +1,45 @@
+#
+# Atmel device configuration
+#
+
+config HAVE_NET_MACB
+ bool
+
+config NET_ATMEL
+ bool "Atmel devices"
+ depends on HAVE_NET_MACB || (ARM && ARCH_AT91RM9200)
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y.
+ Make sure you know the name of your card. Read the Ethernet-HOWTO,
+ available from <http://www.tldp.org/docs.html#howto>.
+
+ If unsure, say Y.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the remaining Atmel network card questions. If you say Y, you will be
+ asked for your specific card in the following questions.
+
+if NET_ATMEL
+
+config ARM_AT91_ETHER
+ tristate "AT91RM9200 Ethernet support"
+ depends on ARM && ARCH_AT91RM9200
+ select NET_CORE
+ select MII
+ ---help---
+ If you wish to compile a kernel for the AT91RM9200 and enable
+ ethernet support, then you should always answer Y to this.
+
+config MACB
+ tristate "Atmel MACB support"
+ depends on HAVE_NET_MACB
+ select PHYLIB
+ ---help---
+ The Atmel MACB ethernet interface is found on many AT32 and AT91
+ parts. Say Y to include support for the MACB chip.
+
+ To compile this driver as a module, choose M here: the module
+ will be called macb.
+
+endif # NET_ATMEL
diff --git a/drivers/net/ethernet/cadence/Makefile b/drivers/net/ethernet/cadence/Makefile
new file mode 100644
index 000000000000..9068b8331ed1
--- /dev/null
+++ b/drivers/net/ethernet/cadence/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the Atmel network device drivers.
+#
+
+obj-$(CONFIG_ARM_AT91_ETHER) += at91_ether.o
+obj-$(CONFIG_MACB) += macb.o
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/ethernet/cadence/at91_ether.c
index 29dc43523cec..1b0ba8c819f7 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/ethernet/cadence/at91_ether.c
@@ -968,7 +968,7 @@ static const struct net_device_ops at91ether_netdev_ops = {
.ndo_stop = at91ether_close,
.ndo_start_xmit = at91ether_start_xmit,
.ndo_get_stats = at91ether_stats,
- .ndo_set_multicast_list = at91ether_set_multicast_list,
+ .ndo_set_rx_mode = at91ether_set_multicast_list,
.ndo_set_mac_address = set_mac_address,
.ndo_do_ioctl = at91ether_ioctl,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/arm/at91_ether.h b/drivers/net/ethernet/cadence/at91_ether.h
index 353f4dab62be..353f4dab62be 100644
--- a/drivers/net/arm/at91_ether.h
+++ b/drivers/net/ethernet/cadence/at91_ether.h
diff --git a/drivers/net/macb.c b/drivers/net/ethernet/cadence/macb.c
index dc4e305a1087..a437b46e5490 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -1106,7 +1106,7 @@ static const struct net_device_ops macb_netdev_ops = {
.ndo_open = macb_open,
.ndo_stop = macb_close,
.ndo_start_xmit = macb_start_xmit,
- .ndo_set_multicast_list = macb_set_rx_mode,
+ .ndo_set_rx_mode = macb_set_rx_mode,
.ndo_get_stats = macb_get_stats,
.ndo_do_ioctl = macb_ioctl,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/macb.h b/drivers/net/ethernet/cadence/macb.h
index d3212f6db703..d3212f6db703 100644
--- a/drivers/net/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
diff --git a/drivers/net/ethernet/chelsio/Kconfig b/drivers/net/ethernet/chelsio/Kconfig
new file mode 100644
index 000000000000..2de50f95798f
--- /dev/null
+++ b/drivers/net/ethernet/chelsio/Kconfig
@@ -0,0 +1,107 @@
+#
+# Chelsio device configuration
+#
+
+config NET_VENDOR_CHELSIO
+ bool "Chelsio devices"
+ default y
+ depends on PCI || INET
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Chelsio devices. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_CHELSIO
+
+config CHELSIO_T1
+ tristate "Chelsio 10Gb Ethernet support"
+ depends on PCI
+ select CRC32
+ select MDIO
+ ---help---
+ This driver supports Chelsio gigabit and 10-gigabit
+ Ethernet cards. More information about adapter features and
+ performance tuning is in <file:Documentation/networking/cxgb.txt>.
+
+ For general information about Chelsio and our products, visit
+ our website at <http://www.chelsio.com>.
+
+ For customer support, please visit our customer support page at
+ <http://www.chelsio.com/support.html>.
+
+ Please send feedback to <linux-bugs@chelsio.com>.
+
+ To compile this driver as a module, choose M here: the module
+ will be called cxgb.
+
+config CHELSIO_T1_1G
+ bool "Chelsio gigabit Ethernet support"
+ depends on CHELSIO_T1
+ ---help---
+ Enables support for Chelsio's gigabit Ethernet PCI cards. If you
+ are using only 10G cards say 'N' here.
+
+config CHELSIO_T3
+ tristate "Chelsio Communications T3 10Gb Ethernet support"
+ depends on PCI && INET
+ select FW_LOADER
+ select MDIO
+ ---help---
+ This driver supports Chelsio T3-based gigabit and 10Gb Ethernet
+ adapters.
+
+ For general information about Chelsio and our products, visit
+ our website at <http://www.chelsio.com>.
+
+ For customer support, please visit our customer support page at
+ <http://www.chelsio.com/support.html>.
+
+ Please send feedback to <linux-bugs@chelsio.com>.
+
+ To compile this driver as a module, choose M here: the module
+ will be called cxgb3.
+
+config CHELSIO_T4
+ tristate "Chelsio Communications T4 Ethernet support"
+ depends on PCI
+ select FW_LOADER
+ select MDIO
+ ---help---
+ This driver supports Chelsio T4-based gigabit and 10Gb Ethernet
+ adapters.
+
+ For general information about Chelsio and our products, visit
+ our website at <http://www.chelsio.com>.
+
+ For customer support, please visit our customer support page at
+ <http://www.chelsio.com/support.html>.
+
+ Please send feedback to <linux-bugs@chelsio.com>.
+
+ To compile this driver as a module choose M here; the module
+ will be called cxgb4.
+
+config CHELSIO_T4VF
+ tristate "Chelsio Communications T4 Virtual Function Ethernet support"
+ depends on PCI
+ ---help---
+ This driver supports Chelsio T4-based gigabit and 10Gb Ethernet
+ adapters with PCI-E SR-IOV Virtual Functions.
+
+ For general information about Chelsio and our products, visit
+ our website at <http://www.chelsio.com>.
+
+ For customer support, please visit our customer support page at
+ <http://www.chelsio.com/support.html>.
+
+ Please send feedback to <linux-bugs@chelsio.com>.
+
+ To compile this driver as a module choose M here; the module
+ will be called cxgb4vf.
+
+endif # NET_VENDOR_CHELSIO
diff --git a/drivers/net/ethernet/chelsio/Makefile b/drivers/net/ethernet/chelsio/Makefile
new file mode 100644
index 000000000000..390510b5e90f
--- /dev/null
+++ b/drivers/net/ethernet/chelsio/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the Chelsio network device drivers.
+#
+
+obj-$(CONFIG_CHELSIO_T1) += cxgb/
+obj-$(CONFIG_CHELSIO_T3) += cxgb3/
+obj-$(CONFIG_CHELSIO_T4) += cxgb4/
+obj-$(CONFIG_CHELSIO_T4VF) += cxgb4vf/
diff --git a/drivers/net/chelsio/Makefile b/drivers/net/ethernet/chelsio/cxgb/Makefile
index 57a4b262fd3f..57a4b262fd3f 100644
--- a/drivers/net/chelsio/Makefile
+++ b/drivers/net/ethernet/chelsio/cxgb/Makefile
diff --git a/drivers/net/chelsio/common.h b/drivers/net/ethernet/chelsio/cxgb/common.h
index 5ccbed1784d2..5ccbed1784d2 100644
--- a/drivers/net/chelsio/common.h
+++ b/drivers/net/ethernet/chelsio/cxgb/common.h
diff --git a/drivers/net/chelsio/cphy.h b/drivers/net/ethernet/chelsio/cxgb/cphy.h
index 1f095a9fc739..1f095a9fc739 100644
--- a/drivers/net/chelsio/cphy.h
+++ b/drivers/net/ethernet/chelsio/cxgb/cphy.h
diff --git a/drivers/net/chelsio/cpl5_cmd.h b/drivers/net/ethernet/chelsio/cxgb/cpl5_cmd.h
index e36d45b78cc7..e36d45b78cc7 100644
--- a/drivers/net/chelsio/cpl5_cmd.h
+++ b/drivers/net/ethernet/chelsio/cxgb/cpl5_cmd.h
diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c
index 3edbbc4c5112..ca26d97171bd 100644
--- a/drivers/net/chelsio/cxgb2.c
+++ b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c
@@ -712,12 +712,10 @@ static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
int jumbo_fl = t1_is_T1B(adapter) ? 1 : 0;
e->rx_max_pending = MAX_RX_BUFFERS;
- e->rx_mini_max_pending = 0;
e->rx_jumbo_max_pending = MAX_RX_JUMBO_BUFFERS;
e->tx_max_pending = MAX_CMDQ_ENTRIES;
e->rx_pending = adapter->params.sge.freelQ_size[!jumbo_fl];
- e->rx_mini_pending = 0;
e->rx_jumbo_pending = adapter->params.sge.freelQ_size[jumbo_fl];
e->tx_pending = adapter->params.sge.cmdQ_size[0];
}
@@ -964,7 +962,7 @@ static const struct net_device_ops cxgb_netdev_ops = {
.ndo_start_xmit = t1_start_xmit,
.ndo_get_stats = t1_get_stats,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = t1_set_rxmode,
+ .ndo_set_rx_mode = t1_set_rxmode,
.ndo_do_ioctl = t1_ioctl,
.ndo_change_mtu = t1_change_mtu,
.ndo_set_mac_address = t1_set_mac_addr,
diff --git a/drivers/net/chelsio/elmer0.h b/drivers/net/ethernet/chelsio/cxgb/elmer0.h
index eef655c827d9..eef655c827d9 100644
--- a/drivers/net/chelsio/elmer0.h
+++ b/drivers/net/ethernet/chelsio/cxgb/elmer0.h
diff --git a/drivers/net/chelsio/espi.c b/drivers/net/ethernet/chelsio/cxgb/espi.c
index 639ff1955739..639ff1955739 100644
--- a/drivers/net/chelsio/espi.c
+++ b/drivers/net/ethernet/chelsio/cxgb/espi.c
diff --git a/drivers/net/chelsio/espi.h b/drivers/net/ethernet/chelsio/cxgb/espi.h
index 5694aad4fbc0..5694aad4fbc0 100644
--- a/drivers/net/chelsio/espi.h
+++ b/drivers/net/ethernet/chelsio/cxgb/espi.h
diff --git a/drivers/net/chelsio/fpga_defs.h b/drivers/net/ethernet/chelsio/cxgb/fpga_defs.h
index ccdb2bc9ae98..ccdb2bc9ae98 100644
--- a/drivers/net/chelsio/fpga_defs.h
+++ b/drivers/net/ethernet/chelsio/cxgb/fpga_defs.h
diff --git a/drivers/net/chelsio/gmac.h b/drivers/net/ethernet/chelsio/cxgb/gmac.h
index d42337457cf7..d42337457cf7 100644
--- a/drivers/net/chelsio/gmac.h
+++ b/drivers/net/ethernet/chelsio/cxgb/gmac.h
diff --git a/drivers/net/chelsio/mv88e1xxx.c b/drivers/net/ethernet/chelsio/cxgb/mv88e1xxx.c
index 71018a4fdf15..71018a4fdf15 100644
--- a/drivers/net/chelsio/mv88e1xxx.c
+++ b/drivers/net/ethernet/chelsio/cxgb/mv88e1xxx.c
diff --git a/drivers/net/chelsio/mv88e1xxx.h b/drivers/net/ethernet/chelsio/cxgb/mv88e1xxx.h
index 967cc4286359..967cc4286359 100644
--- a/drivers/net/chelsio/mv88e1xxx.h
+++ b/drivers/net/ethernet/chelsio/cxgb/mv88e1xxx.h
diff --git a/drivers/net/chelsio/mv88x201x.c b/drivers/net/ethernet/chelsio/cxgb/mv88x201x.c
index f7136b2fd1e5..f7136b2fd1e5 100644
--- a/drivers/net/chelsio/mv88x201x.c
+++ b/drivers/net/ethernet/chelsio/cxgb/mv88x201x.c
diff --git a/drivers/net/chelsio/my3126.c b/drivers/net/ethernet/chelsio/cxgb/my3126.c
index a683fd3bb624..a683fd3bb624 100644
--- a/drivers/net/chelsio/my3126.c
+++ b/drivers/net/ethernet/chelsio/cxgb/my3126.c
diff --git a/drivers/net/chelsio/pm3393.c b/drivers/net/ethernet/chelsio/cxgb/pm3393.c
index 40c7b93ababc..40c7b93ababc 100644
--- a/drivers/net/chelsio/pm3393.c
+++ b/drivers/net/ethernet/chelsio/cxgb/pm3393.c
diff --git a/drivers/net/chelsio/regs.h b/drivers/net/ethernet/chelsio/cxgb/regs.h
index c80bf4d6d0a6..c80bf4d6d0a6 100644
--- a/drivers/net/chelsio/regs.h
+++ b/drivers/net/ethernet/chelsio/cxgb/regs.h
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/ethernet/chelsio/cxgb/sge.c
index e9a03fffef15..f9b602300040 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb/sge.c
@@ -1135,8 +1135,8 @@ static inline unsigned int compute_large_page_tx_descs(struct sk_buff *skb)
len -= SGE_TX_DESC_MAX_PLEN;
}
for (i = 0; nfrags--; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- len = frag->size;
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ len = skb_frag_size(frag);
while (len > SGE_TX_DESC_MAX_PLEN) {
count++;
len -= SGE_TX_DESC_MAX_PLEN;
@@ -1277,11 +1277,10 @@ static inline void write_tx_descs(struct adapter *adapter, struct sk_buff *skb,
ce = q->centries;
}
- mapping = pci_map_page(adapter->pdev, frag->page,
- frag->page_offset, frag->size,
- PCI_DMA_TODEVICE);
+ mapping = skb_frag_dma_map(&adapter->pdev->dev, frag, 0,
+ skb_frag_size(frag), DMA_TO_DEVICE);
desc_mapping = mapping;
- desc_len = frag->size;
+ desc_len = skb_frag_size(frag);
pidx = write_large_page_tx_descs(pidx, &e1, &ce, &gen,
&desc_mapping, &desc_len,
@@ -1291,7 +1290,7 @@ static inline void write_tx_descs(struct adapter *adapter, struct sk_buff *skb,
nfrags == 0);
ce->skb = NULL;
dma_unmap_addr_set(ce, dma_addr, mapping);
- dma_unmap_len_set(ce, dma_len, frag->size);
+ dma_unmap_len_set(ce, dma_len, skb_frag_size(frag));
}
ce->skb = skb;
wmb();
diff --git a/drivers/net/chelsio/sge.h b/drivers/net/ethernet/chelsio/cxgb/sge.h
index e03980bcdd65..e03980bcdd65 100644
--- a/drivers/net/chelsio/sge.h
+++ b/drivers/net/ethernet/chelsio/cxgb/sge.h
diff --git a/drivers/net/chelsio/subr.c b/drivers/net/ethernet/chelsio/cxgb/subr.c
index 8a43c7e19701..8a43c7e19701 100644
--- a/drivers/net/chelsio/subr.c
+++ b/drivers/net/ethernet/chelsio/cxgb/subr.c
diff --git a/drivers/net/chelsio/suni1x10gexp_regs.h b/drivers/net/ethernet/chelsio/cxgb/suni1x10gexp_regs.h
index d0f87d82566a..d0f87d82566a 100644
--- a/drivers/net/chelsio/suni1x10gexp_regs.h
+++ b/drivers/net/ethernet/chelsio/cxgb/suni1x10gexp_regs.h
diff --git a/drivers/net/chelsio/tp.c b/drivers/net/ethernet/chelsio/cxgb/tp.c
index 8bed4a59e65f..8bed4a59e65f 100644
--- a/drivers/net/chelsio/tp.c
+++ b/drivers/net/ethernet/chelsio/cxgb/tp.c
diff --git a/drivers/net/chelsio/tp.h b/drivers/net/ethernet/chelsio/cxgb/tp.h
index dfd8ce25106a..dfd8ce25106a 100644
--- a/drivers/net/chelsio/tp.h
+++ b/drivers/net/ethernet/chelsio/cxgb/tp.h
diff --git a/drivers/net/chelsio/vsc7326.c b/drivers/net/ethernet/chelsio/cxgb/vsc7326.c
index b0cb388f5e12..b0cb388f5e12 100644
--- a/drivers/net/chelsio/vsc7326.c
+++ b/drivers/net/ethernet/chelsio/cxgb/vsc7326.c
diff --git a/drivers/net/chelsio/vsc7326_reg.h b/drivers/net/ethernet/chelsio/cxgb/vsc7326_reg.h
index 479edbcabe68..479edbcabe68 100644
--- a/drivers/net/chelsio/vsc7326_reg.h
+++ b/drivers/net/ethernet/chelsio/cxgb/vsc7326_reg.h
diff --git a/drivers/net/cxgb3/Makefile b/drivers/net/ethernet/chelsio/cxgb3/Makefile
index 29aff78c7820..29aff78c7820 100644
--- a/drivers/net/cxgb3/Makefile
+++ b/drivers/net/ethernet/chelsio/cxgb3/Makefile
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/ethernet/chelsio/cxgb3/adapter.h
index 8b395b537330..8b395b537330 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/ethernet/chelsio/cxgb3/adapter.h
diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/ethernet/chelsio/cxgb3/ael1002.c
index 2028da95afa1..2028da95afa1 100644
--- a/drivers/net/cxgb3/ael1002.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/ael1002.c
diff --git a/drivers/net/cxgb3/aq100x.c b/drivers/net/ethernet/chelsio/cxgb3/aq100x.c
index 341b7ef1508f..341b7ef1508f 100644
--- a/drivers/net/cxgb3/aq100x.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/aq100x.c
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/ethernet/chelsio/cxgb3/common.h
index df01b6343241..df01b6343241 100644
--- a/drivers/net/cxgb3/common.h
+++ b/drivers/net/ethernet/chelsio/cxgb3/common.h
diff --git a/drivers/net/cxgb3/cxgb3_ctl_defs.h b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_ctl_defs.h
index 369fe711fd7f..369fe711fd7f 100644
--- a/drivers/net/cxgb3/cxgb3_ctl_defs.h
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_ctl_defs.h
diff --git a/drivers/net/cxgb3/cxgb3_defs.h b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_defs.h
index 920d918ed193..920d918ed193 100644
--- a/drivers/net/cxgb3/cxgb3_defs.h
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_defs.h
diff --git a/drivers/net/cxgb3/cxgb3_ioctl.h b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_ioctl.h
index b19e4376ba76..b19e4376ba76 100644
--- a/drivers/net/cxgb3/cxgb3_ioctl.h
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_ioctl.h
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
index 93b41a7ac175..4d15c8f99c3b 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
@@ -1898,7 +1898,6 @@ static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
const struct qset_params *q = &adapter->params.sge.qset[pi->first_qset];
e->rx_max_pending = MAX_RX_BUFFERS;
- e->rx_mini_max_pending = 0;
e->rx_jumbo_max_pending = MAX_RX_JUMBO_BUFFERS;
e->tx_max_pending = MAX_TXQ_ENTRIES;
@@ -3153,7 +3152,7 @@ static const struct net_device_ops cxgb_netdev_ops = {
.ndo_start_xmit = t3_eth_xmit,
.ndo_get_stats = cxgb_get_stats,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = cxgb_set_rxmode,
+ .ndo_set_rx_mode = cxgb_set_rxmode,
.ndo_do_ioctl = cxgb_ioctl,
.ndo_change_mtu = cxgb_change_mtu,
.ndo_set_mac_address = cxgb_set_mac_addr,
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
index 805076c54f1b..da5a5d9b8aff 100644
--- a/drivers/net/cxgb3/cxgb3_offload.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
@@ -1146,12 +1146,14 @@ static void cxgb_redirect(struct dst_entry *old, struct dst_entry *new)
if (te && te->ctx && te->client && te->client->redirect) {
update_tcb = te->client->redirect(te->ctx, old, new, e);
if (update_tcb) {
+ rcu_read_lock();
l2t_hold(L2DATA(tdev), e);
+ rcu_read_unlock();
set_l2t_ix(tdev, tid, e);
}
}
}
- l2t_release(L2DATA(tdev), e);
+ l2t_release(tdev, e);
}
/*
@@ -1264,7 +1266,7 @@ int cxgb3_offload_activate(struct adapter *adapter)
goto out_free;
err = -ENOMEM;
- L2DATA(dev) = t3_init_l2t(l2t_capacity);
+ RCU_INIT_POINTER(dev->l2opt, t3_init_l2t(l2t_capacity));
if (!L2DATA(dev))
goto out_free;
@@ -1298,16 +1300,24 @@ int cxgb3_offload_activate(struct adapter *adapter)
out_free_l2t:
t3_free_l2t(L2DATA(dev));
- L2DATA(dev) = NULL;
+ rcu_assign_pointer(dev->l2opt, NULL);
out_free:
kfree(t);
return err;
}
+static void clean_l2_data(struct rcu_head *head)
+{
+ struct l2t_data *d = container_of(head, struct l2t_data, rcu_head);
+ t3_free_l2t(d);
+}
+
+
void cxgb3_offload_deactivate(struct adapter *adapter)
{
struct t3cdev *tdev = &adapter->tdev;
struct t3c_data *t = T3C_DATA(tdev);
+ struct l2t_data *d;
remove_adapter(adapter);
if (list_empty(&adapter_list))
@@ -1315,8 +1325,11 @@ void cxgb3_offload_deactivate(struct adapter *adapter)
free_tid_maps(&t->tid_maps);
T3C_DATA(tdev) = NULL;
- t3_free_l2t(L2DATA(tdev));
- L2DATA(tdev) = NULL;
+ rcu_read_lock();
+ d = L2DATA(tdev);
+ rcu_read_unlock();
+ rcu_assign_pointer(tdev->l2opt, NULL);
+ call_rcu(&d->rcu_head, clean_l2_data);
if (t->nofail_skb)
kfree_skb(t->nofail_skb);
kfree(t);
diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.h
index 929c298115ca..929c298115ca 100644
--- a/drivers/net/cxgb3/cxgb3_offload.h
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.h
diff --git a/drivers/net/cxgb3/firmware_exports.h b/drivers/net/ethernet/chelsio/cxgb3/firmware_exports.h
index 0d9b0e6dccff..0d9b0e6dccff 100644
--- a/drivers/net/cxgb3/firmware_exports.h
+++ b/drivers/net/ethernet/chelsio/cxgb3/firmware_exports.h
diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/ethernet/chelsio/cxgb3/l2t.c
index f452c4003253..41540978a173 100644
--- a/drivers/net/cxgb3/l2t.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/l2t.c
@@ -300,14 +300,21 @@ static inline void reuse_entry(struct l2t_entry *e, struct neighbour *neigh)
struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh,
struct net_device *dev)
{
- struct l2t_entry *e;
- struct l2t_data *d = L2DATA(cdev);
+ struct l2t_entry *e = NULL;
+ struct l2t_data *d;
+ int hash;
u32 addr = *(u32 *) neigh->primary_key;
int ifidx = neigh->dev->ifindex;
- int hash = arp_hash(addr, ifidx, d);
struct port_info *p = netdev_priv(dev);
int smt_idx = p->port_id;
+ rcu_read_lock();
+ d = L2DATA(cdev);
+ if (!d)
+ goto done_rcu;
+
+ hash = arp_hash(addr, ifidx, d);
+
write_lock_bh(&d->lock);
for (e = d->l2tab[hash].first; e; e = e->next)
if (e->addr == addr && e->ifindex == ifidx &&
@@ -338,6 +345,8 @@ struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh,
}
done:
write_unlock_bh(&d->lock);
+done_rcu:
+ rcu_read_unlock();
return e;
}
diff --git a/drivers/net/cxgb3/l2t.h b/drivers/net/ethernet/chelsio/cxgb3/l2t.h
index 7a12d52ed4fc..c5f54796e2cb 100644
--- a/drivers/net/cxgb3/l2t.h
+++ b/drivers/net/ethernet/chelsio/cxgb3/l2t.h
@@ -76,6 +76,7 @@ struct l2t_data {
atomic_t nfree; /* number of free entries */
rwlock_t lock;
struct l2t_entry l2tab[0];
+ struct rcu_head rcu_head; /* to handle rcu cleanup */
};
typedef void (*arp_failure_handler_func)(struct t3cdev * dev,
@@ -99,7 +100,7 @@ static inline void set_arp_failure_handler(struct sk_buff *skb,
/*
* Getting to the L2 data from an offload device.
*/
-#define L2DATA(dev) ((dev)->l2opt)
+#define L2DATA(cdev) (rcu_dereference((cdev)->l2opt))
#define W_TCB_L2T_IX 0
#define S_TCB_L2T_IX 7
@@ -126,15 +127,22 @@ static inline int l2t_send(struct t3cdev *dev, struct sk_buff *skb,
return t3_l2t_send_slow(dev, skb, e);
}
-static inline void l2t_release(struct l2t_data *d, struct l2t_entry *e)
+static inline void l2t_release(struct t3cdev *t, struct l2t_entry *e)
{
- if (atomic_dec_and_test(&e->refcnt))
+ struct l2t_data *d;
+
+ rcu_read_lock();
+ d = L2DATA(t);
+
+ if (atomic_dec_and_test(&e->refcnt) && d)
t3_l2e_free(d, e);
+
+ rcu_read_unlock();
}
static inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e)
{
- if (atomic_add_return(1, &e->refcnt) == 1) /* 0 -> 1 transition */
+ if (d && atomic_add_return(1, &e->refcnt) == 1) /* 0 -> 1 transition */
atomic_dec(&d->nfree);
}
diff --git a/drivers/net/cxgb3/mc5.c b/drivers/net/ethernet/chelsio/cxgb3/mc5.c
index e13b7fe9d082..e13b7fe9d082 100644
--- a/drivers/net/cxgb3/mc5.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/mc5.c
diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/ethernet/chelsio/cxgb3/regs.h
index 6990f6c65221..6990f6c65221 100644
--- a/drivers/net/cxgb3/regs.h
+++ b/drivers/net/ethernet/chelsio/cxgb3/regs.h
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/ethernet/chelsio/cxgb3/sge.c
index d6fa1777a343..cfb60e1f51da 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c
@@ -254,7 +254,7 @@ static inline void unmap_skb(struct sk_buff *skb, struct sge_txq *q,
while (frag_idx < nfrags && curflit < WR_FLITS) {
pci_unmap_page(pdev, be64_to_cpu(sgp->addr[j]),
- skb_shinfo(skb)->frags[frag_idx].size,
+ skb_frag_size(&skb_shinfo(skb)->frags[frag_idx]),
PCI_DMA_TODEVICE);
j ^= 1;
if (j == 0) {
@@ -977,11 +977,11 @@ static inline unsigned int make_sgl(const struct sk_buff *skb,
nfrags = skb_shinfo(skb)->nr_frags;
for (i = 0; i < nfrags; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- mapping = pci_map_page(pdev, frag->page, frag->page_offset,
- frag->size, PCI_DMA_TODEVICE);
- sgp->len[j] = cpu_to_be32(frag->size);
+ mapping = skb_frag_dma_map(&pdev->dev, frag, 0, skb_frag_size(frag),
+ DMA_TO_DEVICE);
+ sgp->len[j] = cpu_to_be32(skb_frag_size(frag));
sgp->addr[j] = cpu_to_be64(mapping);
j ^= 1;
if (j == 0)
@@ -1544,7 +1544,7 @@ static void deferred_unmap_destructor(struct sk_buff *skb)
si = skb_shinfo(skb);
for (i = 0; i < si->nr_frags; i++)
- pci_unmap_page(dui->pdev, *p++, si->frags[i].size,
+ pci_unmap_page(dui->pdev, *p++, skb_frag_size(&si->frags[i]),
PCI_DMA_TODEVICE);
}
@@ -2116,9 +2116,9 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs,
len -= offset;
rx_frag += nr_frags;
- rx_frag->page = sd->pg_chunk.page;
+ __skb_frag_set_page(rx_frag, sd->pg_chunk.page);
rx_frag->page_offset = sd->pg_chunk.offset + offset;
- rx_frag->size = len;
+ skb_frag_size_set(rx_frag, len);
skb->len += len;
skb->data_len += len;
diff --git a/drivers/net/cxgb3/sge_defs.h b/drivers/net/ethernet/chelsio/cxgb3/sge_defs.h
index 29b6c800b238..29b6c800b238 100644
--- a/drivers/net/cxgb3/sge_defs.h
+++ b/drivers/net/ethernet/chelsio/cxgb3/sge_defs.h
diff --git a/drivers/net/cxgb3/t3_cpl.h b/drivers/net/ethernet/chelsio/cxgb3/t3_cpl.h
index 852c399a8b0a..852c399a8b0a 100644
--- a/drivers/net/cxgb3/t3_cpl.h
+++ b/drivers/net/ethernet/chelsio/cxgb3/t3_cpl.h
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c
index 44ac2f40b644..44ac2f40b644 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c
diff --git a/drivers/net/cxgb3/t3cdev.h b/drivers/net/ethernet/chelsio/cxgb3/t3cdev.h
index 705713b56636..705713b56636 100644
--- a/drivers/net/cxgb3/t3cdev.h
+++ b/drivers/net/ethernet/chelsio/cxgb3/t3cdev.h
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/ethernet/chelsio/cxgb3/version.h
index 8bda06e366c8..8bda06e366c8 100644
--- a/drivers/net/cxgb3/version.h
+++ b/drivers/net/ethernet/chelsio/cxgb3/version.h
diff --git a/drivers/net/cxgb3/vsc8211.c b/drivers/net/ethernet/chelsio/cxgb3/vsc8211.c
index 4f9a1c2724f4..4f9a1c2724f4 100644
--- a/drivers/net/cxgb3/vsc8211.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/vsc8211.c
diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/ethernet/chelsio/cxgb3/xgmac.c
index 3af19a550372..3af19a550372 100644
--- a/drivers/net/cxgb3/xgmac.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/xgmac.c
diff --git a/drivers/net/cxgb4/Makefile b/drivers/net/ethernet/chelsio/cxgb4/Makefile
index 498667487f52..498667487f52 100644
--- a/drivers/net/cxgb4/Makefile
+++ b/drivers/net/ethernet/chelsio/cxgb4/Makefile
diff --git a/drivers/net/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
index 223a7f72343b..0fe18850c838 100644
--- a/drivers/net/cxgb4/cxgb4.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -326,7 +326,7 @@ struct sge_fl { /* SGE free-buffer queue state */
/* A packet gather list */
struct pkt_gl {
- skb_frag_t frags[MAX_SKB_FRAGS];
+ struct page_frag frags[MAX_SKB_FRAGS];
void *va; /* virtual address of first byte */
unsigned int nfrags; /* # of fragments */
unsigned int tot_len; /* total length of fragments */
diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index c9957b7f17b5..4c8f42afa3c6 100644
--- a/drivers/net/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -41,6 +41,7 @@
#include <linux/err.h>
#include <linux/etherdevice.h>
#include <linux/firmware.h>
+#include <linux/if.h>
#include <linux/if_vlan.h>
#include <linux/init.h>
#include <linux/log2.h>
@@ -1901,7 +1902,7 @@ static int set_rss_table(struct net_device *dev,
}
static int get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
- void *rules)
+ u32 *rules)
{
const struct port_info *pi = netdev_priv(dev);
@@ -3639,6 +3640,8 @@ static int __devinit init_one(struct pci_dev *pdev,
netdev->features |= netdev->hw_features | highdma;
netdev->vlan_features = netdev->features & VLAN_FEAT;
+ netdev->priv_flags |= IFF_UNICAST_FLT;
+
netdev->netdev_ops = &cxgb4_netdev_ops;
SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
}
@@ -3712,6 +3715,9 @@ static int __devinit init_one(struct pci_dev *pdev,
setup_debugfs(adapter);
}
+ /* PCIe EEH recovery on powerpc platforms needs fundamental reset */
+ pdev->needs_freset = 1;
+
if (is_offload(adapter))
attach_ulds(adapter);
diff --git a/drivers/net/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
index b1d39b8d141a..b1d39b8d141a 100644
--- a/drivers/net/cxgb4/cxgb4_uld.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
diff --git a/drivers/net/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c
index a2d323c473f8..a2d323c473f8 100644
--- a/drivers/net/cxgb4/l2t.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c
diff --git a/drivers/net/cxgb4/l2t.h b/drivers/net/ethernet/chelsio/cxgb4/l2t.h
index 02b31d0c6410..02b31d0c6410 100644
--- a/drivers/net/cxgb4/l2t.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.h
diff --git a/drivers/net/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c
index 56adf448b9fe..ddc16985d0f6 100644
--- a/drivers/net/cxgb4/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c
@@ -215,8 +215,8 @@ static int map_skb(struct device *dev, const struct sk_buff *skb,
end = &si->frags[si->nr_frags];
for (fp = si->frags; fp < end; fp++) {
- *++addr = dma_map_page(dev, fp->page, fp->page_offset, fp->size,
- DMA_TO_DEVICE);
+ *++addr = skb_frag_dma_map(dev, fp, 0, skb_frag_size(fp),
+ DMA_TO_DEVICE);
if (dma_mapping_error(dev, *addr))
goto unwind;
}
@@ -224,7 +224,7 @@ static int map_skb(struct device *dev, const struct sk_buff *skb,
unwind:
while (fp-- > si->frags)
- dma_unmap_page(dev, *--addr, fp->size, DMA_TO_DEVICE);
+ dma_unmap_page(dev, *--addr, skb_frag_size(fp), DMA_TO_DEVICE);
dma_unmap_single(dev, addr[-1], skb_headlen(skb), DMA_TO_DEVICE);
out_err:
@@ -243,7 +243,7 @@ static void unmap_skb(struct device *dev, const struct sk_buff *skb,
si = skb_shinfo(skb);
end = &si->frags[si->nr_frags];
for (fp = si->frags; fp < end; fp++)
- dma_unmap_page(dev, *addr++, fp->size, DMA_TO_DEVICE);
+ dma_unmap_page(dev, *addr++, skb_frag_size(fp), DMA_TO_DEVICE);
}
/**
@@ -717,7 +717,7 @@ static void write_sgl(const struct sk_buff *skb, struct sge_txq *q,
sgl->addr0 = cpu_to_be64(addr[0] + start);
nfrags++;
} else {
- sgl->len0 = htonl(si->frags[0].size);
+ sgl->len0 = htonl(skb_frag_size(&si->frags[0]));
sgl->addr0 = cpu_to_be64(addr[1]);
}
@@ -732,13 +732,13 @@ static void write_sgl(const struct sk_buff *skb, struct sge_txq *q,
to = (u8 *)end > (u8 *)q->stat ? buf : sgl->sge;
for (i = (nfrags != si->nr_frags); nfrags >= 2; nfrags -= 2, to++) {
- to->len[0] = cpu_to_be32(si->frags[i].size);
- to->len[1] = cpu_to_be32(si->frags[++i].size);
+ to->len[0] = cpu_to_be32(skb_frag_size(&si->frags[i]));
+ to->len[1] = cpu_to_be32(skb_frag_size(&si->frags[++i]));
to->addr[0] = cpu_to_be64(addr[i]);
to->addr[1] = cpu_to_be64(addr[++i]);
}
if (nfrags) {
- to->len[0] = cpu_to_be32(si->frags[i].size);
+ to->len[0] = cpu_to_be32(skb_frag_size(&si->frags[i]));
to->len[1] = cpu_to_be32(0);
to->addr[0] = cpu_to_be64(addr[i + 1]);
}
@@ -1409,22 +1409,23 @@ int cxgb4_ofld_send(struct net_device *dev, struct sk_buff *skb)
}
EXPORT_SYMBOL(cxgb4_ofld_send);
-static inline void copy_frags(struct skb_shared_info *ssi,
+static inline void copy_frags(struct sk_buff *skb,
const struct pkt_gl *gl, unsigned int offset)
{
- unsigned int n;
+ int i;
/* usually there's just one frag */
- ssi->frags[0].page = gl->frags[0].page;
- ssi->frags[0].page_offset = gl->frags[0].page_offset + offset;
- ssi->frags[0].size = gl->frags[0].size - offset;
- ssi->nr_frags = gl->nfrags;
- n = gl->nfrags - 1;
- if (n)
- memcpy(&ssi->frags[1], &gl->frags[1], n * sizeof(skb_frag_t));
+ __skb_fill_page_desc(skb, 0, gl->frags[0].page,
+ gl->frags[0].offset + offset,
+ gl->frags[0].size - offset);
+ skb_shinfo(skb)->nr_frags = gl->nfrags;
+ for (i = 1; i < gl->nfrags; i++)
+ __skb_fill_page_desc(skb, i, gl->frags[i].page,
+ gl->frags[i].offset,
+ gl->frags[i].size);
/* get a reference to the last page, we don't own it */
- get_page(gl->frags[n].page);
+ get_page(gl->frags[gl->nfrags - 1].page);
}
/**
@@ -1459,7 +1460,7 @@ struct sk_buff *cxgb4_pktgl_to_skb(const struct pkt_gl *gl,
__skb_put(skb, pull_len);
skb_copy_to_linear_data(skb, gl->va, pull_len);
- copy_frags(skb_shinfo(skb), gl, pull_len);
+ copy_frags(skb, gl, pull_len);
skb->len = gl->tot_len;
skb->data_len = skb->len - pull_len;
skb->truesize += skb->data_len;
@@ -1478,7 +1479,7 @@ EXPORT_SYMBOL(cxgb4_pktgl_to_skb);
static void t4_pktgl_free(const struct pkt_gl *gl)
{
int n;
- const skb_frag_t *p;
+ const struct page_frag *p;
for (p = gl->frags, n = gl->nfrags - 1; n--; p++)
put_page(p->page);
@@ -1522,7 +1523,7 @@ static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl,
return;
}
- copy_frags(skb_shinfo(skb), gl, RX_PKT_PAD);
+ copy_frags(skb, gl, RX_PKT_PAD);
skb->len = gl->tot_len - RX_PKT_PAD;
skb->data_len = skb->len;
skb->truesize += skb->data_len;
@@ -1698,7 +1699,7 @@ static int process_responses(struct sge_rspq *q, int budget)
rmb();
rsp_type = RSPD_TYPE(rc->type_gen);
if (likely(rsp_type == RSP_TYPE_FLBUF)) {
- skb_frag_t *fp;
+ struct page_frag *fp;
struct pkt_gl si;
const struct rx_sw_desc *rsd;
u32 len = ntohl(rc->pldbuflen_qid), bufsz, frags;
@@ -1717,7 +1718,7 @@ static int process_responses(struct sge_rspq *q, int budget)
rsd = &rxq->fl.sdesc[rxq->fl.cidx];
bufsz = get_buf_size(rsd);
fp->page = rsd->page;
- fp->page_offset = q->offset;
+ fp->offset = q->offset;
fp->size = min(bufsz, len);
len -= fp->size;
if (!len)
@@ -1734,7 +1735,7 @@ static int process_responses(struct sge_rspq *q, int budget)
fp->size, DMA_FROM_DEVICE);
si.va = page_address(si.frags[0].page) +
- si.frags[0].page_offset;
+ si.frags[0].offset;
prefetch(si.va);
si.nfrags = frags + 1;
diff --git a/drivers/net/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index d1ec111aebd8..d1ec111aebd8 100644
--- a/drivers/net/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
diff --git a/drivers/net/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
index c26b455f37de..c26b455f37de 100644
--- a/drivers/net/cxgb4/t4_hw.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
diff --git a/drivers/net/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
index eb71b8250b91..eb71b8250b91 100644
--- a/drivers/net/cxgb4/t4_msg.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
diff --git a/drivers/net/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
index 0adc5bcec7c4..0adc5bcec7c4 100644
--- a/drivers/net/cxgb4/t4_regs.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
diff --git a/drivers/net/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
index edcfd7ec7802..edcfd7ec7802 100644
--- a/drivers/net/cxgb4/t4fw_api.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
diff --git a/drivers/net/cxgb4vf/Makefile b/drivers/net/ethernet/chelsio/cxgb4vf/Makefile
index d72ee26cb4c7..d72ee26cb4c7 100644
--- a/drivers/net/cxgb4vf/Makefile
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/Makefile
diff --git a/drivers/net/cxgb4vf/adapter.h b/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h
index 594334d5c711..611396c4b381 100644
--- a/drivers/net/cxgb4vf/adapter.h
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h
@@ -144,7 +144,7 @@ struct sge_fl {
* An ingress packet gather list.
*/
struct pkt_gl {
- skb_frag_t frags[MAX_SKB_FRAGS];
+ struct page_frag frags[MAX_SKB_FRAGS];
void *va; /* virtual address of first byte */
unsigned int nfrags; /* # of fragments */
unsigned int tot_len; /* total length of fragments */
diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
index ec799139dfe2..da9072bfca8b 100644
--- a/drivers/net/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
@@ -2625,6 +2625,8 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
+ netdev->priv_flags |= IFF_UNICAST_FLT;
+
netdev->netdev_ops = &cxgb4vf_netdev_ops;
SET_ETHTOOL_OPS(netdev, &cxgb4vf_ethtool_ops);
diff --git a/drivers/net/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
index cffb328c46c3..8d5d55ad102d 100644
--- a/drivers/net/cxgb4vf/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
@@ -296,8 +296,8 @@ static int map_skb(struct device *dev, const struct sk_buff *skb,
si = skb_shinfo(skb);
end = &si->frags[si->nr_frags];
for (fp = si->frags; fp < end; fp++) {
- *++addr = dma_map_page(dev, fp->page, fp->page_offset, fp->size,
- DMA_TO_DEVICE);
+ *++addr = skb_frag_dma_map(dev, fp, 0, skb_frag_size(fp),
+ DMA_TO_DEVICE);
if (dma_mapping_error(dev, *addr))
goto unwind;
}
@@ -305,7 +305,7 @@ static int map_skb(struct device *dev, const struct sk_buff *skb,
unwind:
while (fp-- > si->frags)
- dma_unmap_page(dev, *--addr, fp->size, DMA_TO_DEVICE);
+ dma_unmap_page(dev, *--addr, skb_frag_size(fp), DMA_TO_DEVICE);
dma_unmap_single(dev, addr[-1], skb_headlen(skb), DMA_TO_DEVICE);
out_err:
@@ -899,7 +899,7 @@ static void write_sgl(const struct sk_buff *skb, struct sge_txq *tq,
sgl->addr0 = cpu_to_be64(addr[0] + start);
nfrags++;
} else {
- sgl->len0 = htonl(si->frags[0].size);
+ sgl->len0 = htonl(skb_frag_size(&si->frags[0]));
sgl->addr0 = cpu_to_be64(addr[1]);
}
@@ -915,13 +915,13 @@ static void write_sgl(const struct sk_buff *skb, struct sge_txq *tq,
to = (u8 *)end > (u8 *)tq->stat ? buf : sgl->sge;
for (i = (nfrags != si->nr_frags); nfrags >= 2; nfrags -= 2, to++) {
- to->len[0] = cpu_to_be32(si->frags[i].size);
- to->len[1] = cpu_to_be32(si->frags[++i].size);
+ to->len[0] = cpu_to_be32(skb_frag_size(&si->frags[i]));
+ to->len[1] = cpu_to_be32(skb_frag_size(&si->frags[++i]));
to->addr[0] = cpu_to_be64(addr[i]);
to->addr[1] = cpu_to_be64(addr[++i]);
}
if (nfrags) {
- to->len[0] = cpu_to_be32(si->frags[i].size);
+ to->len[0] = cpu_to_be32(skb_frag_size(&si->frags[i]));
to->len[1] = cpu_to_be32(0);
to->addr[0] = cpu_to_be64(addr[i + 1]);
}
@@ -1357,6 +1357,35 @@ out_free:
}
/**
+ * copy_frags - copy fragments from gather list into skb_shared_info
+ * @skb: destination skb
+ * @gl: source internal packet gather list
+ * @offset: packet start offset in first page
+ *
+ * Copy an internal packet gather list into a Linux skb_shared_info
+ * structure.
+ */
+static inline void copy_frags(struct sk_buff *skb,
+ const struct pkt_gl *gl,
+ unsigned int offset)
+{
+ int i;
+
+ /* usually there's just one frag */
+ __skb_fill_page_desc(skb, 0, gl->frags[0].page,
+ gl->frags[0].offset + offset,
+ gl->frags[0].size - offset);
+ skb_shinfo(skb)->nr_frags = gl->nfrags;
+ for (i = 1; i < gl->nfrags; i++)
+ __skb_fill_page_desc(skb, i, gl->frags[i].page,
+ gl->frags[i].offset,
+ gl->frags[i].size);
+
+ /* get a reference to the last page, we don't own it */
+ get_page(gl->frags[gl->nfrags - 1].page);
+}
+
+/**
* t4vf_pktgl_to_skb - build an sk_buff from a packet gather list
* @gl: the gather list
* @skb_len: size of sk_buff main body if it carries fragments
@@ -1369,7 +1398,6 @@ struct sk_buff *t4vf_pktgl_to_skb(const struct pkt_gl *gl,
unsigned int skb_len, unsigned int pull_len)
{
struct sk_buff *skb;
- struct skb_shared_info *ssi;
/*
* If the ingress packet is small enough, allocate an skb large enough
@@ -1396,21 +1424,10 @@ struct sk_buff *t4vf_pktgl_to_skb(const struct pkt_gl *gl,
__skb_put(skb, pull_len);
skb_copy_to_linear_data(skb, gl->va, pull_len);
- ssi = skb_shinfo(skb);
- ssi->frags[0].page = gl->frags[0].page;
- ssi->frags[0].page_offset = gl->frags[0].page_offset + pull_len;
- ssi->frags[0].size = gl->frags[0].size - pull_len;
- if (gl->nfrags > 1)
- memcpy(&ssi->frags[1], &gl->frags[1],
- (gl->nfrags-1) * sizeof(skb_frag_t));
- ssi->nr_frags = gl->nfrags;
-
+ copy_frags(skb, gl, pull_len);
skb->len = gl->tot_len;
skb->data_len = skb->len - pull_len;
skb->truesize += skb->data_len;
-
- /* Get a reference for the last page, we don't own it */
- get_page(gl->frags[gl->nfrags - 1].page);
}
out:
@@ -1434,35 +1451,6 @@ void t4vf_pktgl_free(const struct pkt_gl *gl)
}
/**
- * copy_frags - copy fragments from gather list into skb_shared_info
- * @si: destination skb shared info structure
- * @gl: source internal packet gather list
- * @offset: packet start offset in first page
- *
- * Copy an internal packet gather list into a Linux skb_shared_info
- * structure.
- */
-static inline void copy_frags(struct skb_shared_info *si,
- const struct pkt_gl *gl,
- unsigned int offset)
-{
- unsigned int n;
-
- /* usually there's just one frag */
- si->frags[0].page = gl->frags[0].page;
- si->frags[0].page_offset = gl->frags[0].page_offset + offset;
- si->frags[0].size = gl->frags[0].size - offset;
- si->nr_frags = gl->nfrags;
-
- n = gl->nfrags - 1;
- if (n)
- memcpy(&si->frags[1], &gl->frags[1], n * sizeof(skb_frag_t));
-
- /* get a reference to the last page, we don't own it */
- get_page(gl->frags[n].page);
-}
-
-/**
* do_gro - perform Generic Receive Offload ingress packet processing
* @rxq: ingress RX Ethernet Queue
* @gl: gather list for ingress packet
@@ -1484,7 +1472,7 @@ static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl,
return;
}
- copy_frags(skb_shinfo(skb), gl, PKTSHIFT);
+ copy_frags(skb, gl, PKTSHIFT);
skb->len = gl->tot_len - PKTSHIFT;
skb->data_len = skb->len;
skb->truesize += skb->data_len;
@@ -1667,7 +1655,7 @@ int process_responses(struct sge_rspq *rspq, int budget)
rmb();
rsp_type = RSPD_TYPE(rc->type_gen);
if (likely(rsp_type == RSP_TYPE_FLBUF)) {
- skb_frag_t *fp;
+ struct page_frag *fp;
struct pkt_gl gl;
const struct rx_sw_desc *sdesc;
u32 bufsz, frag;
@@ -1701,7 +1689,7 @@ int process_responses(struct sge_rspq *rspq, int budget)
sdesc = &rxq->fl.sdesc[rxq->fl.cidx];
bufsz = get_buf_size(sdesc);
fp->page = sdesc->page;
- fp->page_offset = rspq->offset;
+ fp->offset = rspq->offset;
fp->size = min(bufsz, len);
len -= fp->size;
if (!len)
@@ -1719,7 +1707,7 @@ int process_responses(struct sge_rspq *rspq, int budget)
get_buf_addr(sdesc),
fp->size, DMA_FROM_DEVICE);
gl.va = (page_address(gl.frags[0].page) +
- gl.frags[0].page_offset);
+ gl.frags[0].offset);
prefetch(gl.va);
/*
diff --git a/drivers/net/cxgb4vf/t4vf_common.h b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h
index a65c80aed1f2..a65c80aed1f2 100644
--- a/drivers/net/cxgb4vf/t4vf_common.h
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h
diff --git a/drivers/net/cxgb4vf/t4vf_defs.h b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_defs.h
index c7b127d93767..c7b127d93767 100644
--- a/drivers/net/cxgb4vf/t4vf_defs.h
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_defs.h
diff --git a/drivers/net/cxgb4vf/t4vf_hw.c b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
index fe3fd3dad6f7..fe3fd3dad6f7 100644
--- a/drivers/net/cxgb4vf/t4vf_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
diff --git a/drivers/net/ethernet/cirrus/Kconfig b/drivers/net/ethernet/cirrus/Kconfig
new file mode 100644
index 000000000000..6cbb81ccc02e
--- /dev/null
+++ b/drivers/net/ethernet/cirrus/Kconfig
@@ -0,0 +1,50 @@
+#
+# Cirrus network device configuration
+#
+
+config NET_VENDOR_CIRRUS
+ bool "Cirrus devices"
+ default y
+ depends on ISA || EISA || MACH_IXDP2351 || ARCH_IXDP2X01 \
+ || MACH_MX31ADS || MACH_QQ2440 || (ARM && ARCH_EP93XX)
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Cirrus cards. If you say Y, you will be asked
+ for your specific card in the following questions.
+
+if NET_VENDOR_CIRRUS
+
+config CS89x0
+ tristate "CS89x0 support"
+ depends on (ISA || EISA || MACH_IXDP2351 \
+ || ARCH_IXDP2X01 || MACH_MX31ADS || MACH_QQ2440)
+ ---help---
+ Support for CS89x0 chipset based Ethernet cards. If you have a
+ network (Ethernet) card of this type, say Y and read the
+ Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto> as well as
+ <file:Documentation/networking/cs89x0.txt>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called cs89x0.
+
+config CS89x0_NONISA_IRQ
+ def_bool y
+ depends on CS89x0 != n
+ depends on MACH_IXDP2351 || ARCH_IXDP2X01 || MACH_MX31ADS || MACH_QQ2440
+
+config EP93XX_ETH
+ tristate "EP93xx Ethernet support"
+ depends on ARM && ARCH_EP93XX
+ select NET_CORE
+ select MII
+ help
+ This is a driver for the ethernet hardware included in EP93xx CPUs.
+ Say Y if you are building a kernel for EP93xx based devices.
+
+endif # NET_VENDOR_CIRRUS
diff --git a/drivers/net/ethernet/cirrus/Makefile b/drivers/net/ethernet/cirrus/Makefile
new file mode 100644
index 000000000000..14bd77e0cb57
--- /dev/null
+++ b/drivers/net/ethernet/cirrus/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the Cirrus network device drivers.
+#
+
+obj-$(CONFIG_CS89x0) += cs89x0.o
+obj-$(CONFIG_EP93XX_ETH) += ep93xx_eth.o
diff --git a/drivers/net/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c
index 537a4b2e2020..f328da24c8fa 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/ethernet/cirrus/cs89x0.c
@@ -488,7 +488,7 @@ static const struct net_device_ops net_ops = {
.ndo_tx_timeout = net_timeout,
.ndo_start_xmit = net_send_packet,
.ndo_get_stats = net_get_stats,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_set_mac_address = set_mac_address,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = net_poll_controller,
diff --git a/drivers/net/cs89x0.h b/drivers/net/ethernet/cirrus/cs89x0.h
index 91423b70bb45..91423b70bb45 100644
--- a/drivers/net/cs89x0.h
+++ b/drivers/net/ethernet/cirrus/cs89x0.h
diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/ethernet/cirrus/ep93xx_eth.c
index 4317af8d2f0a..4317af8d2f0a 100644
--- a/drivers/net/arm/ep93xx_eth.c
+++ b/drivers/net/ethernet/cirrus/ep93xx_eth.c
diff --git a/drivers/net/ethernet/cisco/Kconfig b/drivers/net/ethernet/cisco/Kconfig
new file mode 100644
index 000000000000..94606f7ee13a
--- /dev/null
+++ b/drivers/net/ethernet/cisco/Kconfig
@@ -0,0 +1,23 @@
+#
+# Cisco device configuration
+#
+
+config NET_VENDOR_CISCO
+ bool "Cisco devices"
+ default y
+ depends on PCI && INET
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Cisco cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_CISCO
+
+source "drivers/net/ethernet/cisco/enic/Kconfig"
+
+endif # NET_VENDOR_CISCO
diff --git a/drivers/net/ethernet/cisco/Makefile b/drivers/net/ethernet/cisco/Makefile
new file mode 100644
index 000000000000..6c7437bc4a92
--- /dev/null
+++ b/drivers/net/ethernet/cisco/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Cisco device drivers.
+#
+
+obj-$(CONFIG_ENIC) += enic/
diff --git a/drivers/net/ethernet/cisco/enic/Kconfig b/drivers/net/ethernet/cisco/enic/Kconfig
new file mode 100644
index 000000000000..9cc706a6cffd
--- /dev/null
+++ b/drivers/net/ethernet/cisco/enic/Kconfig
@@ -0,0 +1,9 @@
+#
+# Cisco device configuration
+#
+
+config ENIC
+ tristate "Cisco VIC Ethernet NIC Support"
+ depends on PCI && INET
+ ---help---
+ This enables the support for the Cisco VIC Ethernet card.
diff --git a/drivers/net/enic/Makefile b/drivers/net/ethernet/cisco/enic/Makefile
index 9d4974bba247..9d4974bba247 100644
--- a/drivers/net/enic/Makefile
+++ b/drivers/net/ethernet/cisco/enic/Makefile
diff --git a/drivers/net/enic/cq_desc.h b/drivers/net/ethernet/cisco/enic/cq_desc.h
index d6dd1b4edf6e..d6dd1b4edf6e 100644
--- a/drivers/net/enic/cq_desc.h
+++ b/drivers/net/ethernet/cisco/enic/cq_desc.h
diff --git a/drivers/net/enic/cq_enet_desc.h b/drivers/net/ethernet/cisco/enic/cq_enet_desc.h
index c2c0680a1146..c2c0680a1146 100644
--- a/drivers/net/enic/cq_enet_desc.h
+++ b/drivers/net/ethernet/cisco/enic/cq_enet_desc.h
diff --git a/drivers/net/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h
index ce76d9a8ca6e..fe0c29acdbe6 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/ethernet/cisco/enic/enic.h
@@ -32,7 +32,7 @@
#define DRV_NAME "enic"
#define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver"
-#define DRV_VERSION "2.1.1.24"
+#define DRV_VERSION "2.1.1.28"
#define DRV_COPYRIGHT "Copyright 2008-2011 Cisco Systems, Inc"
#define ENIC_BARS_MAX 6
@@ -49,6 +49,10 @@ struct enic_msix_entry {
void *devid;
};
+/* priv_flags */
+#define ENIC_SRIOV_ENABLED (1 << 0)
+
+/* enic port profile set flags */
#define ENIC_PORT_REQUEST_APPLIED (1 << 0)
#define ENIC_SET_REQUEST (1 << 1)
#define ENIC_SET_NAME (1 << 2)
@@ -83,12 +87,16 @@ struct enic {
u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN];
u8 uc_addr[ENIC_UNICAST_PERFECT_FILTERS][ETH_ALEN];
unsigned int flags;
+ unsigned int priv_flags;
unsigned int mc_count;
unsigned int uc_count;
u32 port_mtu;
u32 rx_coalesce_usecs;
u32 tx_coalesce_usecs;
- struct enic_port_profile pp;
+#ifdef CONFIG_PCI_IOV
+ u32 num_vfs;
+#endif
+ struct enic_port_profile *pp;
/* work queue cache line section */
____cacheline_aligned struct vnic_wq wq[ENIC_WQ_MAX];
@@ -120,5 +128,8 @@ static inline struct device *enic_get_dev(struct enic *enic)
}
void enic_reset_addr_lists(struct enic *enic);
+int enic_sriov_enabled(struct enic *enic);
+int enic_is_valid_vf(struct enic *enic, int vf);
+int enic_is_dynamic(struct enic *enic);
#endif /* _ENIC_H_ */
diff --git a/drivers/net/enic/enic_dev.c b/drivers/net/ethernet/cisco/enic/enic_dev.c
index fd6247b3c0ee..fd6247b3c0ee 100644
--- a/drivers/net/enic/enic_dev.c
+++ b/drivers/net/ethernet/cisco/enic/enic_dev.c
diff --git a/drivers/net/enic/enic_dev.h b/drivers/net/ethernet/cisco/enic/enic_dev.h
index ff8e87fdfc1d..1f83a4747ba0 100644
--- a/drivers/net/enic/enic_dev.h
+++ b/drivers/net/ethernet/cisco/enic/enic_dev.h
@@ -19,6 +19,25 @@
#ifndef _ENIC_DEV_H_
#define _ENIC_DEV_H_
+#include "vnic_dev.h"
+
+/*
+ * Calls the devcmd function given by argument vnicdevcmdfn.
+ * If vf argument is valid, it proxies the devcmd
+ */
+#define ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnicdevcmdfn, ...) \
+ do { \
+ spin_lock(&enic->devcmd_lock); \
+ if (enic_is_valid_vf(enic, vf)) { \
+ vnic_dev_cmd_proxy_by_index_start(enic->vdev, vf); \
+ err = vnicdevcmdfn(enic->vdev, ##__VA_ARGS__); \
+ vnic_dev_cmd_proxy_end(enic->vdev); \
+ } else { \
+ err = vnicdevcmdfn(enic->vdev, ##__VA_ARGS__); \
+ } \
+ spin_unlock(&enic->devcmd_lock); \
+ } while (0)
+
int enic_dev_fw_info(struct enic *enic, struct vnic_devcmd_fw_info **fw_info);
int enic_dev_stats_dump(struct enic *enic, struct vnic_stats **vstats);
int enic_dev_add_station_addr(struct enic *enic);
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c
index 67a27cd304dd..c3786fda11db 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/ethernet/cisco/enic/enic_main.c
@@ -28,6 +28,7 @@
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/ethtool.h>
@@ -121,11 +122,25 @@ static const struct enic_stat enic_rx_stats[] = {
static const unsigned int enic_n_tx_stats = ARRAY_SIZE(enic_tx_stats);
static const unsigned int enic_n_rx_stats = ARRAY_SIZE(enic_rx_stats);
-static int enic_is_dynamic(struct enic *enic)
+int enic_is_dynamic(struct enic *enic)
{
return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_DYN;
}
+int enic_sriov_enabled(struct enic *enic)
+{
+ return (enic->priv_flags & ENIC_SRIOV_ENABLED) ? 1 : 0;
+}
+
+int enic_is_valid_vf(struct enic *enic, int vf)
+{
+#ifdef CONFIG_PCI_IOV
+ return vf >= 0 && vf < enic->num_vfs;
+#else
+ return 0;
+#endif
+}
+
static inline unsigned int enic_cq_rq(struct enic *enic, unsigned int rq)
{
return rq;
@@ -584,16 +599,16 @@ static inline void enic_queue_wq_skb_cont(struct enic *enic,
struct vnic_wq *wq, struct sk_buff *skb,
unsigned int len_left, int loopback)
{
- skb_frag_t *frag;
+ const skb_frag_t *frag;
/* Queue additional data fragments */
for (frag = skb_shinfo(skb)->frags; len_left; frag++) {
- len_left -= frag->size;
+ len_left -= skb_frag_size(frag);
enic_queue_wq_desc_cont(wq, skb,
- pci_map_page(enic->pdev, frag->page,
- frag->page_offset, frag->size,
- PCI_DMA_TODEVICE),
- frag->size,
+ skb_frag_dma_map(&enic->pdev->dev,
+ frag, 0, skb_frag_size(frag),
+ DMA_TO_DEVICE),
+ skb_frag_size(frag),
(len_left == 0), /* EOP? */
loopback);
}
@@ -702,16 +717,16 @@ static inline void enic_queue_wq_skb_tso(struct enic *enic,
* for additional data fragments
*/
for (frag = skb_shinfo(skb)->frags; len_left; frag++) {
- len_left -= frag->size;
- frag_len_left = frag->size;
- offset = frag->page_offset;
+ len_left -= skb_frag_size(frag);
+ frag_len_left = skb_frag_size(frag);
+ offset = 0;
while (frag_len_left) {
len = min(frag_len_left,
(unsigned int)WQ_ENET_MAX_DESC_LEN);
- dma_addr = pci_map_page(enic->pdev, frag->page,
- offset, len,
- PCI_DMA_TODEVICE);
+ dma_addr = skb_frag_dma_map(&enic->pdev->dev, frag,
+ offset, len,
+ DMA_TO_DEVICE);
enic_queue_wq_desc_cont(wq, skb,
dma_addr,
len,
@@ -1039,15 +1054,15 @@ static void enic_tx_timeout(struct net_device *netdev)
static int enic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
{
struct enic *enic = netdev_priv(netdev);
+ struct enic_port_profile *pp;
+ int err;
- if (vf != PORT_SELF_VF)
- return -EOPNOTSUPP;
+ ENIC_PP_BY_INDEX(enic, vf, pp, &err);
+ if (err)
+ return err;
- /* Ignore the vf argument for now. We can assume the request
- * is coming on a vf.
- */
if (is_valid_ether_addr(mac)) {
- memcpy(enic->pp.vf_mac, mac, ETH_ALEN);
+ memcpy(pp->vf_mac, mac, ETH_ALEN);
return 0;
} else
return -EINVAL;
@@ -1058,71 +1073,74 @@ static int enic_set_vf_port(struct net_device *netdev, int vf,
{
struct enic *enic = netdev_priv(netdev);
struct enic_port_profile prev_pp;
+ struct enic_port_profile *pp;
int err = 0, restore_pp = 1;
- /* don't support VFs, yet */
- if (vf != PORT_SELF_VF)
- return -EOPNOTSUPP;
+ ENIC_PP_BY_INDEX(enic, vf, pp, &err);
+ if (err)
+ return err;
if (!port[IFLA_PORT_REQUEST])
return -EOPNOTSUPP;
- memcpy(&prev_pp, &enic->pp, sizeof(enic->pp));
- memset(&enic->pp, 0, sizeof(enic->pp));
+ memcpy(&prev_pp, pp, sizeof(*enic->pp));
+ memset(pp, 0, sizeof(*enic->pp));
- enic->pp.set |= ENIC_SET_REQUEST;
- enic->pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]);
+ pp->set |= ENIC_SET_REQUEST;
+ pp->request = nla_get_u8(port[IFLA_PORT_REQUEST]);
if (port[IFLA_PORT_PROFILE]) {
- enic->pp.set |= ENIC_SET_NAME;
- memcpy(enic->pp.name, nla_data(port[IFLA_PORT_PROFILE]),
+ pp->set |= ENIC_SET_NAME;
+ memcpy(pp->name, nla_data(port[IFLA_PORT_PROFILE]),
PORT_PROFILE_MAX);
}
if (port[IFLA_PORT_INSTANCE_UUID]) {
- enic->pp.set |= ENIC_SET_INSTANCE;
- memcpy(enic->pp.instance_uuid,
+ pp->set |= ENIC_SET_INSTANCE;
+ memcpy(pp->instance_uuid,
nla_data(port[IFLA_PORT_INSTANCE_UUID]), PORT_UUID_MAX);
}
if (port[IFLA_PORT_HOST_UUID]) {
- enic->pp.set |= ENIC_SET_HOST;
- memcpy(enic->pp.host_uuid,
+ pp->set |= ENIC_SET_HOST;
+ memcpy(pp->host_uuid,
nla_data(port[IFLA_PORT_HOST_UUID]), PORT_UUID_MAX);
}
/* Special case handling: mac came from IFLA_VF_MAC */
if (!is_zero_ether_addr(prev_pp.vf_mac))
- memcpy(enic->pp.mac_addr, prev_pp.vf_mac, ETH_ALEN);
+ memcpy(pp->mac_addr, prev_pp.vf_mac, ETH_ALEN);
- if (is_zero_ether_addr(netdev->dev_addr))
- random_ether_addr(netdev->dev_addr);
+ if (vf == PORT_SELF_VF && is_zero_ether_addr(netdev->dev_addr))
+ random_ether_addr(netdev->dev_addr);
- err = enic_process_set_pp_request(enic, &prev_pp, &restore_pp);
+ err = enic_process_set_pp_request(enic, vf, &prev_pp, &restore_pp);
if (err) {
if (restore_pp) {
/* Things are still the way they were: Implicit
* DISASSOCIATE failed
*/
- memcpy(&enic->pp, &prev_pp, sizeof(enic->pp));
+ memcpy(pp, &prev_pp, sizeof(*pp));
} else {
- memset(&enic->pp, 0, sizeof(enic->pp));
- memset(netdev->dev_addr, 0, ETH_ALEN);
+ memset(pp, 0, sizeof(*pp));
+ if (vf == PORT_SELF_VF)
+ memset(netdev->dev_addr, 0, ETH_ALEN);
}
} else {
/* Set flag to indicate that the port assoc/disassoc
* request has been sent out to fw
*/
- enic->pp.set |= ENIC_PORT_REQUEST_APPLIED;
+ pp->set |= ENIC_PORT_REQUEST_APPLIED;
/* If DISASSOCIATE, clean up all assigned/saved macaddresses */
- if (enic->pp.request == PORT_REQUEST_DISASSOCIATE) {
- memset(enic->pp.mac_addr, 0, ETH_ALEN);
- memset(netdev->dev_addr, 0, ETH_ALEN);
+ if (pp->request == PORT_REQUEST_DISASSOCIATE) {
+ memset(pp->mac_addr, 0, ETH_ALEN);
+ if (vf == PORT_SELF_VF)
+ memset(netdev->dev_addr, 0, ETH_ALEN);
}
}
- memset(enic->pp.vf_mac, 0, ETH_ALEN);
+ memset(pp->vf_mac, 0, ETH_ALEN);
return err;
}
@@ -1132,26 +1150,31 @@ static int enic_get_vf_port(struct net_device *netdev, int vf,
{
struct enic *enic = netdev_priv(netdev);
u16 response = PORT_PROFILE_RESPONSE_SUCCESS;
+ struct enic_port_profile *pp;
int err;
- if (!(enic->pp.set & ENIC_PORT_REQUEST_APPLIED))
+ ENIC_PP_BY_INDEX(enic, vf, pp, &err);
+ if (err)
+ return err;
+
+ if (!(pp->set & ENIC_PORT_REQUEST_APPLIED))
return -ENODATA;
- err = enic_process_get_pp_request(enic, enic->pp.request, &response);
+ err = enic_process_get_pp_request(enic, vf, pp->request, &response);
if (err)
return err;
- NLA_PUT_U16(skb, IFLA_PORT_REQUEST, enic->pp.request);
+ NLA_PUT_U16(skb, IFLA_PORT_REQUEST, pp->request);
NLA_PUT_U16(skb, IFLA_PORT_RESPONSE, response);
- if (enic->pp.set & ENIC_SET_NAME)
+ if (pp->set & ENIC_SET_NAME)
NLA_PUT(skb, IFLA_PORT_PROFILE, PORT_PROFILE_MAX,
- enic->pp.name);
- if (enic->pp.set & ENIC_SET_INSTANCE)
+ pp->name);
+ if (pp->set & ENIC_SET_INSTANCE)
NLA_PUT(skb, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX,
- enic->pp.instance_uuid);
- if (enic->pp.set & ENIC_SET_HOST)
+ pp->instance_uuid);
+ if (pp->set & ENIC_SET_HOST)
NLA_PUT(skb, IFLA_PORT_HOST_UUID, PORT_UUID_MAX,
- enic->pp.host_uuid);
+ pp->host_uuid);
return 0;
@@ -1585,10 +1608,9 @@ static int enic_open(struct net_device *netdev)
for (i = 0; i < enic->rq_count; i++)
vnic_rq_enable(&enic->rq[i]);
- if (enic_is_dynamic(enic) && !is_zero_ether_addr(enic->pp.mac_addr))
- enic_dev_add_addr(enic, enic->pp.mac_addr);
- else
+ if (!enic_is_dynamic(enic))
enic_dev_add_station_addr(enic);
+
enic_set_rx_mode(netdev);
netif_wake_queue(netdev);
@@ -1636,9 +1658,8 @@ static int enic_stop(struct net_device *netdev)
netif_carrier_off(netdev);
netif_tx_disable(netdev);
- if (enic_is_dynamic(enic) && !is_zero_ether_addr(enic->pp.mac_addr))
- enic_dev_del_addr(enic, enic->pp.mac_addr);
- else
+
+ if (!enic_is_dynamic(enic))
enic_dev_del_station_addr(enic);
for (i = 0; i < enic->wq_count; i++) {
@@ -2103,7 +2124,6 @@ static const struct net_device_ops enic_netdev_dynamic_ops = {
.ndo_get_stats64 = enic_get_stats,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_rx_mode = enic_set_rx_mode,
- .ndo_set_multicast_list = enic_set_rx_mode,
.ndo_set_mac_address = enic_set_mac_address_dynamic,
.ndo_change_mtu = enic_change_mtu,
.ndo_vlan_rx_add_vid = enic_vlan_rx_add_vid,
@@ -2125,11 +2145,13 @@ static const struct net_device_ops enic_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = enic_set_mac_address,
.ndo_set_rx_mode = enic_set_rx_mode,
- .ndo_set_multicast_list = enic_set_rx_mode,
.ndo_change_mtu = enic_change_mtu,
.ndo_vlan_rx_add_vid = enic_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = enic_vlan_rx_kill_vid,
.ndo_tx_timeout = enic_tx_timeout,
+ .ndo_set_vf_port = enic_set_vf_port,
+ .ndo_get_vf_port = enic_get_vf_port,
+ .ndo_set_vf_mac = enic_set_vf_mac,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = enic_poll_controller,
#endif
@@ -2241,6 +2263,10 @@ static int __devinit enic_probe(struct pci_dev *pdev,
int using_dac = 0;
unsigned int i;
int err;
+ int num_pps = 1;
+#ifdef CONFIG_PCI_IOV
+ int pos = 0;
+#endif
/* Allocate net device structure and initialize. Private
* instance data is initialized to zero.
@@ -2332,13 +2358,41 @@ static int __devinit enic_probe(struct pci_dev *pdev,
goto err_out_iounmap;
}
+#ifdef CONFIG_PCI_IOV
+ /* Get number of subvnics */
+ pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
+ if (pos) {
+ pci_read_config_word(pdev, pos + PCI_SRIOV_TOTAL_VF,
+ (u16 *)&enic->num_vfs);
+ if (enic->num_vfs) {
+ err = pci_enable_sriov(pdev, enic->num_vfs);
+ if (err) {
+ dev_err(dev, "SRIOV enable failed, aborting."
+ " pci_enable_sriov() returned %d\n",
+ err);
+ goto err_out_vnic_unregister;
+ }
+ enic->priv_flags |= ENIC_SRIOV_ENABLED;
+ num_pps = enic->num_vfs;
+ }
+ }
+
+#endif
+ /* Allocate structure for port profiles */
+ enic->pp = kzalloc(num_pps * sizeof(*enic->pp), GFP_KERNEL);
+ if (!enic->pp) {
+ pr_err("port profile alloc failed, aborting\n");
+ err = -ENOMEM;
+ goto err_out_disable_sriov;
+ }
+
/* Issue device open to get device in known state
*/
err = enic_dev_open(enic);
if (err) {
dev_err(dev, "vNIC dev open failed, aborting\n");
- goto err_out_vnic_unregister;
+ goto err_out_free_pp;
}
/* Setup devcmd lock
@@ -2405,6 +2459,12 @@ static int __devinit enic_probe(struct pci_dev *pdev,
enic->port_mtu = enic->config.mtu;
(void)enic_change_mtu(netdev, enic->port_mtu);
+#ifdef CONFIG_PCI_IOV
+ if (enic_is_dynamic(enic) && pdev->is_virtfn &&
+ is_zero_ether_addr(enic->mac_addr))
+ random_ether_addr(enic->mac_addr);
+#endif
+
err = enic_set_mac_addr(netdev, enic->mac_addr);
if (err) {
dev_err(dev, "Invalid MAC address, aborting\n");
@@ -2442,6 +2502,8 @@ static int __devinit enic_probe(struct pci_dev *pdev,
if (using_dac)
netdev->features |= NETIF_F_HIGHDMA;
+ netdev->priv_flags |= IFF_UNICAST_FLT;
+
err = register_netdev(netdev);
if (err) {
dev_err(dev, "Cannot register net device, aborting\n");
@@ -2454,8 +2516,17 @@ err_out_dev_deinit:
enic_dev_deinit(enic);
err_out_dev_close:
vnic_dev_close(enic->vdev);
+err_out_free_pp:
+ kfree(enic->pp);
+err_out_disable_sriov:
+#ifdef CONFIG_PCI_IOV
+ if (enic_sriov_enabled(enic)) {
+ pci_disable_sriov(pdev);
+ enic->priv_flags &= ~ENIC_SRIOV_ENABLED;
+ }
err_out_vnic_unregister:
vnic_dev_unregister(enic->vdev);
+#endif
err_out_iounmap:
enic_iounmap(enic);
err_out_release_regions:
@@ -2481,6 +2552,13 @@ static void __devexit enic_remove(struct pci_dev *pdev)
unregister_netdev(netdev);
enic_dev_deinit(enic);
vnic_dev_close(enic->vdev);
+#ifdef CONFIG_PCI_IOV
+ if (enic_sriov_enabled(enic)) {
+ pci_disable_sriov(pdev);
+ enic->priv_flags &= ~ENIC_SRIOV_ENABLED;
+ }
+#endif
+ kfree(enic->pp);
vnic_dev_unregister(enic->vdev);
enic_iounmap(enic);
pci_release_regions(pdev);
diff --git a/drivers/net/enic/enic_pp.c b/drivers/net/ethernet/cisco/enic/enic_pp.c
index ffaa75dd1ded..22bf03a1829e 100644
--- a/drivers/net/enic/enic_pp.c
+++ b/drivers/net/ethernet/cisco/enic/enic_pp.c
@@ -29,10 +29,47 @@
#include "enic_res.h"
#include "enic.h"
#include "enic_dev.h"
+#include "enic_pp.h"
-static int enic_set_port_profile(struct enic *enic)
+/*
+ * Checks validity of vf index that came in
+ * port profile request
+ */
+int enic_is_valid_pp_vf(struct enic *enic, int vf, int *err)
+{
+ if (vf != PORT_SELF_VF) {
+#ifdef CONFIG_PCI_IOV
+ if (enic_sriov_enabled(enic)) {
+ if (vf < 0 || vf >= enic->num_vfs) {
+ *err = -EINVAL;
+ goto err_out;
+ }
+ } else {
+ *err = -EOPNOTSUPP;
+ goto err_out;
+ }
+#else
+ *err = -EOPNOTSUPP;
+ goto err_out;
+#endif
+ }
+
+ if (vf == PORT_SELF_VF && !enic_is_dynamic(enic)) {
+ *err = -EOPNOTSUPP;
+ goto err_out;
+ }
+
+ *err = 0;
+ return 1;
+
+err_out:
+ return 0;
+}
+
+static int enic_set_port_profile(struct enic *enic, int vf)
{
struct net_device *netdev = enic->netdev;
+ struct enic_port_profile *pp;
struct vic_provinfo *vp;
const u8 oui[3] = VIC_PROVINFO_CISCO_OUI;
const u16 os_type = htons(VIC_GENERIC_PROV_OS_TYPE_LINUX);
@@ -41,7 +78,11 @@ static int enic_set_port_profile(struct enic *enic)
u8 *client_mac;
int err;
- if (!(enic->pp.set & ENIC_SET_NAME) || !strlen(enic->pp.name))
+ ENIC_PP_BY_INDEX(enic, vf, pp, &err);
+ if (err)
+ return err;
+
+ if (!(pp->set & ENIC_SET_NAME) || !strlen(pp->name))
return -EINVAL;
vp = vic_provinfo_alloc(GFP_KERNEL, oui,
@@ -51,12 +92,18 @@ static int enic_set_port_profile(struct enic *enic)
VIC_PROVINFO_ADD_TLV(vp,
VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR,
- strlen(enic->pp.name) + 1, enic->pp.name);
+ strlen(pp->name) + 1, pp->name);
- if (!is_zero_ether_addr(enic->pp.mac_addr))
- client_mac = enic->pp.mac_addr;
- else
+ if (!is_zero_ether_addr(pp->mac_addr)) {
+ client_mac = pp->mac_addr;
+ } else if (vf == PORT_SELF_VF) {
client_mac = netdev->dev_addr;
+ } else {
+ netdev_err(netdev, "Cannot find pp mac address "
+ "for VF %d\n", vf);
+ err = -EINVAL;
+ goto add_tlv_failure;
+ }
VIC_PROVINFO_ADD_TLV(vp,
VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR,
@@ -67,15 +114,15 @@ static int enic_set_port_profile(struct enic *enic)
VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR,
sizeof(client_mac_str), client_mac_str);
- if (enic->pp.set & ENIC_SET_INSTANCE) {
- sprintf(uuid_str, "%pUB", enic->pp.instance_uuid);
+ if (pp->set & ENIC_SET_INSTANCE) {
+ sprintf(uuid_str, "%pUB", pp->instance_uuid);
VIC_PROVINFO_ADD_TLV(vp,
VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR,
sizeof(uuid_str), uuid_str);
}
- if (enic->pp.set & ENIC_SET_HOST) {
- sprintf(uuid_str, "%pUB", enic->pp.host_uuid);
+ if (pp->set & ENIC_SET_HOST) {
+ sprintf(uuid_str, "%pUB", pp->host_uuid);
VIC_PROVINFO_ADD_TLV(vp,
VIC_GENERIC_PROV_TLV_HOST_UUID_STR,
sizeof(uuid_str), uuid_str);
@@ -85,7 +132,9 @@ static int enic_set_port_profile(struct enic *enic)
VIC_GENERIC_PROV_TLV_OS_TYPE,
sizeof(os_type), &os_type);
- err = enic_dev_status_to_errno(enic_dev_init_prov2(enic, vp));
+ ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_init_prov2, (u8 *)vp,
+ vic_provinfo_size(vp));
+ err = enic_dev_status_to_errno(err);
add_tlv_failure:
vic_provinfo_free(vp);
@@ -93,15 +142,16 @@ add_tlv_failure:
return err;
}
-static int enic_unset_port_profile(struct enic *enic)
+static int enic_unset_port_profile(struct enic *enic, int vf)
{
int err;
- err = enic_vnic_dev_deinit(enic);
+ ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_deinit);
if (err)
return enic_dev_status_to_errno(err);
- enic_reset_addr_lists(enic);
+ if (vf == PORT_SELF_VF)
+ enic_reset_addr_lists(enic);
return 0;
}
@@ -115,17 +165,18 @@ static int enic_are_pp_different(struct enic_port_profile *pp1,
!!memcmp(pp1->mac_addr, pp2->mac_addr, ETH_ALEN);
}
-static int enic_pp_preassociate(struct enic *enic,
+static int enic_pp_preassociate(struct enic *enic, int vf,
struct enic_port_profile *prev_pp, int *restore_pp);
-static int enic_pp_disassociate(struct enic *enic,
+static int enic_pp_disassociate(struct enic *enic, int vf,
struct enic_port_profile *prev_pp, int *restore_pp);
-static int enic_pp_preassociate_rr(struct enic *enic,
+static int enic_pp_preassociate_rr(struct enic *enic, int vf,
struct enic_port_profile *prev_pp, int *restore_pp);
-static int enic_pp_associate(struct enic *enic,
+static int enic_pp_associate(struct enic *enic, int vf,
struct enic_port_profile *prev_pp, int *restore_pp);
-static int (*enic_pp_handlers[])(struct enic *enic,
- struct enic_port_profile *prev_state, int *restore_pp) = {
+static int (*enic_pp_handlers[])(struct enic *enic, int vf,
+ struct enic_port_profile *prev_state,
+ int *restore_pp) = {
[PORT_REQUEST_PREASSOCIATE] = enic_pp_preassociate,
[PORT_REQUEST_PREASSOCIATE_RR] = enic_pp_preassociate_rr,
[PORT_REQUEST_ASSOCIATE] = enic_pp_associate,
@@ -135,28 +186,49 @@ static int (*enic_pp_handlers[])(struct enic *enic,
static const int enic_pp_handlers_count =
sizeof(enic_pp_handlers)/sizeof(*enic_pp_handlers);
-static int enic_pp_preassociate(struct enic *enic,
+static int enic_pp_preassociate(struct enic *enic, int vf,
struct enic_port_profile *prev_pp, int *restore_pp)
{
return -EOPNOTSUPP;
}
-static int enic_pp_disassociate(struct enic *enic,
+static int enic_pp_disassociate(struct enic *enic, int vf,
struct enic_port_profile *prev_pp, int *restore_pp)
{
- return enic_unset_port_profile(enic);
+ struct net_device *netdev = enic->netdev;
+ struct enic_port_profile *pp;
+ int err;
+
+ ENIC_PP_BY_INDEX(enic, vf, pp, &err);
+ if (err)
+ return err;
+
+ /* Deregister mac addresses */
+ if (!is_zero_ether_addr(pp->mac_addr))
+ ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_del_addr,
+ pp->mac_addr);
+ else if (!is_zero_ether_addr(netdev->dev_addr))
+ ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_del_addr,
+ netdev->dev_addr);
+
+ return enic_unset_port_profile(enic, vf);
}
-static int enic_pp_preassociate_rr(struct enic *enic,
+static int enic_pp_preassociate_rr(struct enic *enic, int vf,
struct enic_port_profile *prev_pp, int *restore_pp)
{
+ struct enic_port_profile *pp;
int err;
int active = 0;
- if (enic->pp.request != PORT_REQUEST_ASSOCIATE) {
+ ENIC_PP_BY_INDEX(enic, vf, pp, &err);
+ if (err)
+ return err;
+
+ if (pp->request != PORT_REQUEST_ASSOCIATE) {
/* If pre-associate is not part of an associate.
We always disassociate first */
- err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](enic,
+ err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](enic, vf,
prev_pp, restore_pp);
if (err)
return err;
@@ -166,29 +238,39 @@ static int enic_pp_preassociate_rr(struct enic *enic,
*restore_pp = 0;
- err = enic_set_port_profile(enic);
+ err = enic_set_port_profile(enic, vf);
if (err)
return err;
/* If pre-associate is not part of an associate. */
- if (enic->pp.request != PORT_REQUEST_ASSOCIATE)
- err = enic_dev_status_to_errno(enic_dev_enable2(enic, active));
+ if (pp->request != PORT_REQUEST_ASSOCIATE) {
+ /* Enable device as standby */
+ ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_enable2,
+ active);
+ err = enic_dev_status_to_errno(err);
+ }
return err;
}
-static int enic_pp_associate(struct enic *enic,
+static int enic_pp_associate(struct enic *enic, int vf,
struct enic_port_profile *prev_pp, int *restore_pp)
{
+ struct net_device *netdev = enic->netdev;
+ struct enic_port_profile *pp;
int err;
int active = 1;
+ ENIC_PP_BY_INDEX(enic, vf, pp, &err);
+ if (err)
+ return err;
+
/* Check if a pre-associate was called before */
if (prev_pp->request != PORT_REQUEST_PREASSOCIATE_RR ||
(prev_pp->request == PORT_REQUEST_PREASSOCIATE_RR &&
- enic_are_pp_different(prev_pp, &enic->pp))) {
+ enic_are_pp_different(prev_pp, pp))) {
err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](
- enic, prev_pp, restore_pp);
+ enic, vf, prev_pp, restore_pp);
if (err)
return err;
@@ -196,28 +278,48 @@ static int enic_pp_associate(struct enic *enic,
}
err = enic_pp_handlers[PORT_REQUEST_PREASSOCIATE_RR](
- enic, prev_pp, restore_pp);
+ enic, vf, prev_pp, restore_pp);
if (err)
return err;
*restore_pp = 0;
- return enic_dev_status_to_errno(enic_dev_enable2(enic, active));
+ /* Enable device as active */
+ ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_enable2, active);
+ err = enic_dev_status_to_errno(err);
+ if (err)
+ return err;
+
+ /* Register mac address */
+ if (!is_zero_ether_addr(pp->mac_addr))
+ ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_add_addr,
+ pp->mac_addr);
+ else if (!is_zero_ether_addr(netdev->dev_addr))
+ ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_add_addr,
+ netdev->dev_addr);
+
+ return 0;
}
-int enic_process_set_pp_request(struct enic *enic,
+int enic_process_set_pp_request(struct enic *enic, int vf,
struct enic_port_profile *prev_pp, int *restore_pp)
{
- if (enic->pp.request < enic_pp_handlers_count
- && enic_pp_handlers[enic->pp.request])
- return enic_pp_handlers[enic->pp.request](enic,
- prev_pp, restore_pp);
- else
+ struct enic_port_profile *pp;
+ int err;
+
+ ENIC_PP_BY_INDEX(enic, vf, pp, &err);
+ if (err)
+ return err;
+
+ if (pp->request >= enic_pp_handlers_count
+ || !enic_pp_handlers[pp->request])
return -EOPNOTSUPP;
+
+ return enic_pp_handlers[pp->request](enic, vf, prev_pp, restore_pp);
}
-int enic_process_get_pp_request(struct enic *enic, int request,
- u16 *response)
+int enic_process_get_pp_request(struct enic *enic, int vf,
+ int request, u16 *response)
{
int err, status = ERR_SUCCESS;
@@ -225,11 +327,13 @@ int enic_process_get_pp_request(struct enic *enic, int request,
case PORT_REQUEST_PREASSOCIATE_RR:
case PORT_REQUEST_ASSOCIATE:
- err = enic_dev_enable2_done(enic, &status);
+ ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic,
+ vnic_dev_enable2_done, &status);
break;
case PORT_REQUEST_DISASSOCIATE:
- err = enic_dev_deinit_done(enic, &status);
+ ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic,
+ vnic_dev_deinit_done, &status);
break;
default:
diff --git a/drivers/net/enic/enic_pp.h b/drivers/net/ethernet/cisco/enic/enic_pp.h
index 699e365a944d..a09ff392c1c6 100644
--- a/drivers/net/enic/enic_pp.h
+++ b/drivers/net/ethernet/cisco/enic/enic_pp.h
@@ -19,9 +19,18 @@
#ifndef _ENIC_PP_H_
#define _ENIC_PP_H_
-int enic_process_set_pp_request(struct enic *enic,
+#define ENIC_PP_BY_INDEX(enic, vf, pp, err) \
+ do { \
+ if (enic_is_valid_pp_vf(enic, vf, err)) \
+ pp = (vf == PORT_SELF_VF) ? enic->pp : enic->pp + vf; \
+ else \
+ pp = NULL; \
+ } while (0)
+
+int enic_process_set_pp_request(struct enic *enic, int vf,
struct enic_port_profile *prev_pp, int *restore_pp);
-int enic_process_get_pp_request(struct enic *enic, int request,
- u16 *response);
+int enic_process_get_pp_request(struct enic *enic, int vf,
+ int request, u16 *response);
+int enic_is_valid_pp_vf(struct enic *enic, int vf, int *err);
#endif /* _ENIC_PP_H_ */
diff --git a/drivers/net/enic/enic_res.c b/drivers/net/ethernet/cisco/enic/enic_res.c
index 4a35367de790..4a35367de790 100644
--- a/drivers/net/enic/enic_res.c
+++ b/drivers/net/ethernet/cisco/enic/enic_res.c
diff --git a/drivers/net/enic/enic_res.h b/drivers/net/ethernet/cisco/enic/enic_res.h
index 25be2734c3fe..25be2734c3fe 100644
--- a/drivers/net/enic/enic_res.h
+++ b/drivers/net/ethernet/cisco/enic/enic_res.h
diff --git a/drivers/net/enic/rq_enet_desc.h b/drivers/net/ethernet/cisco/enic/rq_enet_desc.h
index e6dd30988d6f..e6dd30988d6f 100644
--- a/drivers/net/enic/rq_enet_desc.h
+++ b/drivers/net/ethernet/cisco/enic/rq_enet_desc.h
diff --git a/drivers/net/enic/vnic_cq.c b/drivers/net/ethernet/cisco/enic/vnic_cq.c
index 0daa1c7073cb..0daa1c7073cb 100644
--- a/drivers/net/enic/vnic_cq.c
+++ b/drivers/net/ethernet/cisco/enic/vnic_cq.c
diff --git a/drivers/net/enic/vnic_cq.h b/drivers/net/ethernet/cisco/enic/vnic_cq.h
index 579315cbe803..579315cbe803 100644
--- a/drivers/net/enic/vnic_cq.h
+++ b/drivers/net/ethernet/cisco/enic/vnic_cq.h
diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/ethernet/cisco/enic/vnic_dev.c
index 8c4c8cf486f6..31e7f9bc2067 100644
--- a/drivers/net/enic/vnic_dev.c
+++ b/drivers/net/ethernet/cisco/enic/vnic_dev.c
@@ -32,6 +32,7 @@
enum vnic_proxy_type {
PROXY_NONE,
PROXY_BY_BDF,
+ PROXY_BY_INDEX,
};
struct vnic_res {
@@ -328,20 +329,21 @@ static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
return -ETIMEDOUT;
}
-static int vnic_dev_cmd_proxy_by_bdf(struct vnic_dev *vdev,
- enum vnic_devcmd_cmd cmd, u64 *a0, u64 *a1, int wait)
+static int vnic_dev_cmd_proxy(struct vnic_dev *vdev,
+ enum vnic_devcmd_cmd proxy_cmd, enum vnic_devcmd_cmd cmd,
+ u64 *a0, u64 *a1, int wait)
{
u32 status;
int err;
memset(vdev->args, 0, sizeof(vdev->args));
- vdev->args[0] = vdev->proxy_index; /* bdf */
+ vdev->args[0] = vdev->proxy_index;
vdev->args[1] = cmd;
vdev->args[2] = *a0;
vdev->args[3] = *a1;
- err = _vnic_dev_cmd(vdev, CMD_PROXY_BY_BDF, wait);
+ err = _vnic_dev_cmd(vdev, proxy_cmd, wait);
if (err)
return err;
@@ -376,14 +378,30 @@ static int vnic_dev_cmd_no_proxy(struct vnic_dev *vdev,
return err;
}
+void vnic_dev_cmd_proxy_by_index_start(struct vnic_dev *vdev, u16 index)
+{
+ vdev->proxy = PROXY_BY_INDEX;
+ vdev->proxy_index = index;
+}
+
+void vnic_dev_cmd_proxy_end(struct vnic_dev *vdev)
+{
+ vdev->proxy = PROXY_NONE;
+ vdev->proxy_index = 0;
+}
+
int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
u64 *a0, u64 *a1, int wait)
{
memset(vdev->args, 0, sizeof(vdev->args));
switch (vdev->proxy) {
+ case PROXY_BY_INDEX:
+ return vnic_dev_cmd_proxy(vdev, CMD_PROXY_BY_INDEX, cmd,
+ a0, a1, wait);
case PROXY_BY_BDF:
- return vnic_dev_cmd_proxy_by_bdf(vdev, cmd, a0, a1, wait);
+ return vnic_dev_cmd_proxy(vdev, CMD_PROXY_BY_BDF, cmd,
+ a0, a1, wait);
case PROXY_NONE:
default:
return vnic_dev_cmd_no_proxy(vdev, cmd, a0, a1, wait);
diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/ethernet/cisco/enic/vnic_dev.h
index 852b698fbe7d..6a138b625d13 100644
--- a/drivers/net/enic/vnic_dev.h
+++ b/drivers/net/ethernet/cisco/enic/vnic_dev.h
@@ -85,6 +85,8 @@ void vnic_dev_free_desc_ring(struct vnic_dev *vdev,
struct vnic_dev_ring *ring);
int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
u64 *a0, u64 *a1, int wait);
+void vnic_dev_cmd_proxy_by_index_start(struct vnic_dev *vdev, u16 index);
+void vnic_dev_cmd_proxy_end(struct vnic_dev *vdev);
int vnic_dev_fw_info(struct vnic_dev *vdev,
struct vnic_devcmd_fw_info **fw_info);
int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size,
diff --git a/drivers/net/enic/vnic_devcmd.h b/drivers/net/ethernet/cisco/enic/vnic_devcmd.h
index 8025e8808d61..8025e8808d61 100644
--- a/drivers/net/enic/vnic_devcmd.h
+++ b/drivers/net/ethernet/cisco/enic/vnic_devcmd.h
diff --git a/drivers/net/enic/vnic_enet.h b/drivers/net/ethernet/cisco/enic/vnic_enet.h
index 609542848e02..609542848e02 100644
--- a/drivers/net/enic/vnic_enet.h
+++ b/drivers/net/ethernet/cisco/enic/vnic_enet.h
diff --git a/drivers/net/enic/vnic_intr.c b/drivers/net/ethernet/cisco/enic/vnic_intr.c
index 0ca107f7bc8c..0ca107f7bc8c 100644
--- a/drivers/net/enic/vnic_intr.c
+++ b/drivers/net/ethernet/cisco/enic/vnic_intr.c
diff --git a/drivers/net/enic/vnic_intr.h b/drivers/net/ethernet/cisco/enic/vnic_intr.h
index 2b1636392294..2b1636392294 100644
--- a/drivers/net/enic/vnic_intr.h
+++ b/drivers/net/ethernet/cisco/enic/vnic_intr.h
diff --git a/drivers/net/enic/vnic_nic.h b/drivers/net/ethernet/cisco/enic/vnic_nic.h
index 995a50dd4c99..995a50dd4c99 100644
--- a/drivers/net/enic/vnic_nic.h
+++ b/drivers/net/ethernet/cisco/enic/vnic_nic.h
diff --git a/drivers/net/enic/vnic_resource.h b/drivers/net/ethernet/cisco/enic/vnic_resource.h
index e0a73f1ca6f4..e0a73f1ca6f4 100644
--- a/drivers/net/enic/vnic_resource.h
+++ b/drivers/net/ethernet/cisco/enic/vnic_resource.h
diff --git a/drivers/net/enic/vnic_rq.c b/drivers/net/ethernet/cisco/enic/vnic_rq.c
index 34105e0951a5..34105e0951a5 100644
--- a/drivers/net/enic/vnic_rq.c
+++ b/drivers/net/ethernet/cisco/enic/vnic_rq.c
diff --git a/drivers/net/enic/vnic_rq.h b/drivers/net/ethernet/cisco/enic/vnic_rq.h
index 2056586f4d4b..2056586f4d4b 100644
--- a/drivers/net/enic/vnic_rq.h
+++ b/drivers/net/ethernet/cisco/enic/vnic_rq.h
diff --git a/drivers/net/enic/vnic_rss.h b/drivers/net/ethernet/cisco/enic/vnic_rss.h
index fa421baf45b8..fa421baf45b8 100644
--- a/drivers/net/enic/vnic_rss.h
+++ b/drivers/net/ethernet/cisco/enic/vnic_rss.h
diff --git a/drivers/net/enic/vnic_stats.h b/drivers/net/ethernet/cisco/enic/vnic_stats.h
index 77750ec93954..77750ec93954 100644
--- a/drivers/net/enic/vnic_stats.h
+++ b/drivers/net/ethernet/cisco/enic/vnic_stats.h
diff --git a/drivers/net/enic/vnic_vic.c b/drivers/net/ethernet/cisco/enic/vnic_vic.c
index 24ef8cd40545..24ef8cd40545 100644
--- a/drivers/net/enic/vnic_vic.c
+++ b/drivers/net/ethernet/cisco/enic/vnic_vic.c
diff --git a/drivers/net/enic/vnic_vic.h b/drivers/net/ethernet/cisco/enic/vnic_vic.h
index 9ef81f148351..9ef81f148351 100644
--- a/drivers/net/enic/vnic_vic.h
+++ b/drivers/net/ethernet/cisco/enic/vnic_vic.h
diff --git a/drivers/net/enic/vnic_wq.c b/drivers/net/ethernet/cisco/enic/vnic_wq.c
index df61bd932ea6..df61bd932ea6 100644
--- a/drivers/net/enic/vnic_wq.c
+++ b/drivers/net/ethernet/cisco/enic/vnic_wq.c
diff --git a/drivers/net/enic/vnic_wq.h b/drivers/net/ethernet/cisco/enic/vnic_wq.h
index 7dd937ac11c2..7dd937ac11c2 100644
--- a/drivers/net/enic/vnic_wq.h
+++ b/drivers/net/ethernet/cisco/enic/vnic_wq.h
diff --git a/drivers/net/enic/wq_enet_desc.h b/drivers/net/ethernet/cisco/enic/wq_enet_desc.h
index c7021e3a631f..c7021e3a631f 100644
--- a/drivers/net/enic/wq_enet_desc.h
+++ b/drivers/net/ethernet/cisco/enic/wq_enet_desc.h
diff --git a/drivers/net/ethernet/davicom/Kconfig b/drivers/net/ethernet/davicom/Kconfig
new file mode 100644
index 000000000000..972b62b31837
--- /dev/null
+++ b/drivers/net/ethernet/davicom/Kconfig
@@ -0,0 +1,24 @@
+#
+# Davicom device configuration
+#
+
+config DM9000
+ tristate "DM9000 support"
+ depends on ARM || BLACKFIN || MIPS
+ select CRC32
+ select NET_CORE
+ select MII
+ ---help---
+ Support for DM9000 chipset.
+
+ To compile this driver as a module, choose M here. The module
+ will be called dm9000.
+
+config DM9000_FORCE_SIMPLE_PHY_POLL
+ bool "Force simple NSR based PHY polling"
+ depends on DM9000
+ ---help---
+ This configuration forces the DM9000 to use the NSR's LinkStatus
+ bit to determine if the link is up or down instead of the more
+ costly MII PHY reads. Note, this will not work if the chip is
+ operating with an external PHY.
diff --git a/drivers/net/ethernet/davicom/Makefile b/drivers/net/ethernet/davicom/Makefile
new file mode 100644
index 000000000000..74b31f0ebe18
--- /dev/null
+++ b/drivers/net/ethernet/davicom/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Davicom device drivers.
+#
+
+obj-$(CONFIG_DM9000) += dm9000.o
diff --git a/drivers/net/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c
index 8ef31dc4704d..438f4580bf66 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/ethernet/davicom/dm9000.c
@@ -56,6 +56,13 @@ static int watchdog = 5000;
module_param(watchdog, int, 0400);
MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");
+/*
+ * Debug messages level
+ */
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "dm9000 debug level (0-4)");
+
/* DM9000 register address locking.
*
* The DM9000 uses an address register to control where data written
@@ -103,7 +110,6 @@ typedef struct board_info {
unsigned int flags;
unsigned int in_suspend :1;
unsigned int wake_supported :1;
- int debug_level;
enum dm9000_type type;
@@ -138,8 +144,7 @@ typedef struct board_info {
/* debug code */
#define dm9000_dbg(db, lev, msg...) do { \
- if ((lev) < CONFIG_DM9000_DEBUGLEVEL && \
- (lev) < db->debug_level) { \
+ if ((lev) < debug) { \
dev_dbg(db->dev, msg); \
} \
} while (0)
@@ -1339,7 +1344,7 @@ static const struct net_device_ops dm9000_netdev_ops = {
.ndo_stop = dm9000_stop,
.ndo_start_xmit = dm9000_start_xmit,
.ndo_tx_timeout = dm9000_timeout,
- .ndo_set_multicast_list = dm9000_hash_table,
+ .ndo_set_rx_mode = dm9000_hash_table,
.ndo_do_ioctl = dm9000_ioctl,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_features = dm9000_set_features,
diff --git a/drivers/net/dm9000.h b/drivers/net/ethernet/davicom/dm9000.h
index 55688bd1a3ef..55688bd1a3ef 100644
--- a/drivers/net/dm9000.h
+++ b/drivers/net/ethernet/davicom/dm9000.h
diff --git a/drivers/net/ethernet/dec/Kconfig b/drivers/net/ethernet/dec/Kconfig
new file mode 100644
index 000000000000..37940279ded8
--- /dev/null
+++ b/drivers/net/ethernet/dec/Kconfig
@@ -0,0 +1,37 @@
+#
+# Digital Equipment Inc network device configuration
+#
+
+config NET_VENDOR_DEC
+ bool "Digital Equipment devices"
+ default y
+ depends on PCI || EISA || CARDBUS
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about DEC cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_DEC
+
+config EWRK3
+ tristate "EtherWORKS 3 (DE203, DE204, DE205) support"
+ depends on ISA
+ select CRC32
+ ---help---
+ This driver supports the DE203, DE204 and DE205 network (Ethernet)
+ cards. If this is for you, say Y and read
+ <file:Documentation/networking/ewrk3.txt> in the kernel source as
+ well as the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called ewrk3.
+
+source "drivers/net/ethernet/dec/tulip/Kconfig"
+
+endif # NET_VENDOR_DEC
diff --git a/drivers/net/ethernet/dec/Makefile b/drivers/net/ethernet/dec/Makefile
new file mode 100644
index 000000000000..1b01ed8d42c8
--- /dev/null
+++ b/drivers/net/ethernet/dec/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the Digital Equipment Inc. network device drivers.
+#
+
+obj-$(CONFIG_EWRK3) += ewrk3.o
+obj-$(CONFIG_NET_TULIP) += tulip/
diff --git a/drivers/net/ewrk3.c b/drivers/net/ethernet/dec/ewrk3.c
index 05a5f71451a7..f9df5e4d0341 100644
--- a/drivers/net/ewrk3.c
+++ b/drivers/net/ethernet/dec/ewrk3.c
@@ -393,7 +393,7 @@ static const struct net_device_ops ewrk3_netdev_ops = {
.ndo_open = ewrk3_open,
.ndo_start_xmit = ewrk3_queue_pkt,
.ndo_stop = ewrk3_close,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_do_ioctl = ewrk3_ioctl,
.ndo_tx_timeout = ewrk3_timeout,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/ewrk3.h b/drivers/net/ethernet/dec/ewrk3.h
index 8e0ee906567b..8e0ee906567b 100644
--- a/drivers/net/ewrk3.h
+++ b/drivers/net/ethernet/dec/ewrk3.h
diff --git a/drivers/net/tulip/21142.c b/drivers/net/ethernet/dec/tulip/21142.c
index 092c3faa882a..25b8deedbef8 100644
--- a/drivers/net/tulip/21142.c
+++ b/drivers/net/ethernet/dec/tulip/21142.c
@@ -7,9 +7,6 @@
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
- Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html}
- for more information on this driver.
-
DC21143 manual "21143 PCI/CardBus 10/100Mb/s Ethernet LAN Controller
Hardware Reference Manual" is currently available at :
http://developer.intel.com/design/network/manuals/278074.htm
diff --git a/drivers/net/tulip/Kconfig b/drivers/net/ethernet/dec/tulip/Kconfig
index 1f8d4a8d8ea4..1203be0436e2 100644
--- a/drivers/net/tulip/Kconfig
+++ b/drivers/net/ethernet/dec/tulip/Kconfig
@@ -2,10 +2,10 @@
# Tulip family network device configuration
#
-menuconfig NET_TULIP
- bool "\"Tulip\" family network device support"
- depends on PCI || EISA || CARDBUS
- help
+config NET_TULIP
+ bool "DEC - Tulip devices"
+ depends on (PCI || EISA || CARDBUS)
+ ---help---
This selects the "Tulip" family of EISA/PCI network cards.
if NET_TULIP
@@ -32,7 +32,7 @@ config DE2104X_DSL
depends on DE2104X
range 0 31
default 0
- help
+ ---help---
Setting this value allows to align ring buffer descriptors into their
own cache lines. Value of 4 corresponds to the typical 32 byte line
(the descriptor is 16 bytes). This is necessary on systems that lack
@@ -59,7 +59,7 @@ config TULIP
config TULIP_MWI
bool "New bus configuration (EXPERIMENTAL)"
depends on TULIP && EXPERIMENTAL
- help
+ ---help---
This configures your Tulip card specifically for the card and
system cache line size type you are using.
@@ -70,7 +70,7 @@ config TULIP_MWI
config TULIP_MMIO
bool "Use PCI shared mem for NIC registers"
depends on TULIP
- help
+ ---help---
Use PCI shared memory for the NIC registers, rather than going through
the Tulip's PIO (programmed I/O ports). Faster, but could produce
obscure bugs if your mainboard has memory controller timing issues.
@@ -79,7 +79,7 @@ config TULIP_MMIO
config TULIP_NAPI
bool "Use RX polling (NAPI)"
depends on TULIP
- help
+ ---help---
NAPI is a new driver API designed to reduce CPU and interrupt load
when the driver is receiving lots of packets from the card. It is
still somewhat experimental and thus not yet enabled by default.
@@ -107,7 +107,7 @@ config TULIP_DM910X
config DE4X5
tristate "Generic DECchip & DIGITAL EtherWORKS PCI/EISA"
- depends on PCI || EISA
+ depends on (PCI || EISA)
select CRC32
---help---
This is support for the DIGITAL series of PCI/EISA Ethernet cards.
@@ -125,8 +125,9 @@ config WINBOND_840
tristate "Winbond W89c840 Ethernet support"
depends on PCI
select CRC32
+ select NET_CORE
select MII
- help
+ ---help---
This driver is for the Winbond W89c840 chip. It also works with
the TX9882 chip on the Compex RL100-ATX board.
More specific information and updates are available from
diff --git a/drivers/net/tulip/Makefile b/drivers/net/ethernet/dec/tulip/Makefile
index 5e8be38b45bb..5e8be38b45bb 100644
--- a/drivers/net/tulip/Makefile
+++ b/drivers/net/ethernet/dec/tulip/Makefile
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/ethernet/dec/tulip/de2104x.c
index ce90efc6ba3c..1427739d9a51 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/ethernet/dec/tulip/de2104x.c
@@ -1956,7 +1956,7 @@ bad_srom:
static const struct net_device_ops de_netdev_ops = {
.ndo_open = de_open,
.ndo_stop = de_close,
- .ndo_set_multicast_list = de_set_rx_mode,
+ .ndo_set_rx_mode = de_set_rx_mode,
.ndo_start_xmit = de_start_xmit,
.ndo_get_stats = de_get_stats,
.ndo_tx_timeout = de_tx_timeout,
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/ethernet/dec/tulip/de4x5.c
index 959b41021a65..871bcaa7068d 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/ethernet/dec/tulip/de4x5.c
@@ -1084,7 +1084,7 @@ static const struct net_device_ops de4x5_netdev_ops = {
.ndo_stop = de4x5_close,
.ndo_start_xmit = de4x5_queue_pkt,
.ndo_get_stats = de4x5_get_stats,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_do_ioctl = de4x5_ioctl,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address= eth_mac_addr,
diff --git a/drivers/net/tulip/de4x5.h b/drivers/net/ethernet/dec/tulip/de4x5.h
index 9f2877438fb0..ec756eba397b 100644
--- a/drivers/net/tulip/de4x5.h
+++ b/drivers/net/ethernet/dec/tulip/de4x5.h
@@ -991,8 +991,6 @@
*/
#include <linux/sockios.h>
-#define DE4X5IOCTL SIOCDEVPRIVATE
-
struct de4x5_ioctl {
unsigned short cmd; /* Command to run */
unsigned short len; /* Length of the data buffer */
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/ethernet/dec/tulip/dmfe.c
index 9a21ca3873fc..17b11ee1745a 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/ethernet/dec/tulip/dmfe.c
@@ -356,7 +356,7 @@ static const struct net_device_ops netdev_ops = {
.ndo_open = dmfe_open,
.ndo_stop = dmfe_stop,
.ndo_start_xmit = dmfe_start_xmit,
- .ndo_set_multicast_list = dmfe_set_filter_mode,
+ .ndo_set_rx_mode = dmfe_set_filter_mode,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/ethernet/dec/tulip/eeprom.c
index fa5eee925f25..14d5b611783d 100644
--- a/drivers/net/tulip/eeprom.c
+++ b/drivers/net/ethernet/dec/tulip/eeprom.c
@@ -7,8 +7,6 @@
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
- Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html}
- for more information on this driver.
Please submit bug reports to http://bugzilla.kernel.org/.
*/
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/ethernet/dec/tulip/interrupt.c
index 5350d753e0ff..4fb8c8c0a420 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/ethernet/dec/tulip/interrupt.c
@@ -7,10 +7,7 @@
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
- Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html}
- for more information on this driver.
Please submit bugs to http://bugzilla.kernel.org/ .
-
*/
#include <linux/pci.h>
diff --git a/drivers/net/tulip/media.c b/drivers/net/ethernet/dec/tulip/media.c
index 4bd13922875d..beeb17b52ad4 100644
--- a/drivers/net/tulip/media.c
+++ b/drivers/net/ethernet/dec/tulip/media.c
@@ -7,9 +7,6 @@
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
- Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html}
- for more information on this driver.
-
Please submit bugs to http://bugzilla.kernel.org/ .
*/
diff --git a/drivers/net/tulip/pnic.c b/drivers/net/ethernet/dec/tulip/pnic.c
index 52d898bdbeb4..9c16e4ad02a6 100644
--- a/drivers/net/tulip/pnic.c
+++ b/drivers/net/ethernet/dec/tulip/pnic.c
@@ -7,9 +7,6 @@
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
- Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html}
- for more information on this driver.
-
Please submit bugs to http://bugzilla.kernel.org/ .
*/
diff --git a/drivers/net/tulip/pnic2.c b/drivers/net/ethernet/dec/tulip/pnic2.c
index 93358ee4d830..04a7e477eaff 100644
--- a/drivers/net/tulip/pnic2.c
+++ b/drivers/net/ethernet/dec/tulip/pnic2.c
@@ -8,9 +8,6 @@
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
- Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html}
- for more information on this driver.
-
Please submit bugs to http://bugzilla.kernel.org/ .
*/
diff --git a/drivers/net/tulip/timer.c b/drivers/net/ethernet/dec/tulip/timer.c
index 2017faf2d0e6..19078d28ffb9 100644
--- a/drivers/net/tulip/timer.c
+++ b/drivers/net/ethernet/dec/tulip/timer.c
@@ -7,9 +7,6 @@
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
- Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html}
- for more information on this driver.
-
Please submit bugs to http://bugzilla.kernel.org/ .
*/
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/ethernet/dec/tulip/tulip.h
index 9db528967da9..fb3887c18dc6 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/ethernet/dec/tulip/tulip.h
@@ -7,9 +7,6 @@
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
- Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html}
- for more information on this driver.
-
Please submit bugs to http://bugzilla.kernel.org/ .
*/
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/ethernet/dec/tulip/tulip_core.c
index 1246998a677c..9656dd0647d9 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/ethernet/dec/tulip/tulip_core.c
@@ -6,9 +6,6 @@
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
- Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html}
- for more information on this driver.
-
Please submit bugs to http://bugzilla.kernel.org/ .
*/
@@ -1291,7 +1288,7 @@ static const struct net_device_ops tulip_netdev_ops = {
.ndo_stop = tulip_close,
.ndo_get_stats = tulip_get_stats,
.ndo_do_ioctl = private_ioctl,
- .ndo_set_multicast_list = set_rx_mode,
+ .ndo_set_rx_mode = set_rx_mode,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/ethernet/dec/tulip/uli526x.c
index 9e63f406f72d..7a44a7a6adc8 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/ethernet/dec/tulip/uli526x.c
@@ -259,7 +259,7 @@ static const struct net_device_ops netdev_ops = {
.ndo_open = uli526x_open,
.ndo_stop = uli526x_stop,
.ndo_start_xmit = uli526x_start_xmit,
- .ndo_set_multicast_list = uli526x_set_filter_mode,
+ .ndo_set_rx_mode = uli526x_set_filter_mode,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/ethernet/dec/tulip/winbond-840.c
index 862eadf07191..4d01219ba22f 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/ethernet/dec/tulip/winbond-840.c
@@ -350,7 +350,7 @@ static const struct net_device_ops netdev_ops = {
.ndo_stop = netdev_close,
.ndo_start_xmit = start_tx,
.ndo_get_stats = get_stats,
- .ndo_set_multicast_list = set_rx_mode,
+ .ndo_set_rx_mode = set_rx_mode,
.ndo_do_ioctl = netdev_ioctl,
.ndo_tx_timeout = tx_timeout,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/ethernet/dec/tulip/xircom_cb.c
index 988b8eb24d37..988b8eb24d37 100644
--- a/drivers/net/tulip/xircom_cb.c
+++ b/drivers/net/ethernet/dec/tulip/xircom_cb.c
diff --git a/drivers/net/ethernet/dlink/Kconfig b/drivers/net/ethernet/dlink/Kconfig
new file mode 100644
index 000000000000..b5afe218c31b
--- /dev/null
+++ b/drivers/net/ethernet/dlink/Kconfig
@@ -0,0 +1,86 @@
+#
+# D-Link device configuration
+#
+
+config NET_VENDOR_DLINK
+ bool "D-Link devices"
+ default y
+ depends on PCI || PARPORT
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about D-Link devices. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_DLINK
+
+config DE600
+ tristate "D-Link DE600 pocket adapter support"
+ depends on PARPORT
+ ---help---
+ This is a network (Ethernet) device which attaches to your parallel
+ port. Read <file:Documentation/networking/DLINK.txt> as well as the
+ Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>, if you want to use
+ this. It is possible to have several devices share a single parallel
+ port and it is safe to compile the corresponding drivers into the
+ kernel.
+
+ To compile this driver as a module, choose M here: the module
+ will be called de600.
+
+config DE620
+ tristate "D-Link DE620 pocket adapter support"
+ depends on PARPORT
+ ---help---
+ This is a network (Ethernet) device which attaches to your parallel
+ port. Read <file:Documentation/networking/DLINK.txt> as well as the
+ Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>, if you want to use
+ this. It is possible to have several devices share a single parallel
+ port and it is safe to compile the corresponding drivers into the
+ kernel.
+
+ To compile this driver as a module, choose M here: the module
+ will be called de620.
+
+config DL2K
+ tristate "DL2000/TC902x-based Gigabit Ethernet support"
+ depends on PCI
+ select CRC32
+ ---help---
+ This driver supports DL2000/TC902x-based Gigabit ethernet cards,
+ which includes
+ D-Link DGE-550T Gigabit Ethernet Adapter.
+ D-Link DL2000-based Gigabit Ethernet Adapter.
+ Sundance/Tamarack TC902x Gigabit Ethernet Adapter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called dl2k.
+
+config SUNDANCE
+ tristate "Sundance Alta support"
+ depends on PCI
+ select CRC32
+ select NET_CORE
+ select MII
+ ---help---
+ This driver is for the Sundance "Alta" chip.
+ More specific information and updates are available from
+ <http://www.scyld.com/network/sundance.html>.
+
+config SUNDANCE_MMIO
+ bool "Use MMIO instead of PIO"
+ depends on SUNDANCE
+ ---help---
+ Enable memory-mapped I/O for interaction with Sundance NIC registers.
+ Do NOT enable this by default, PIO (enabled when MMIO is disabled)
+ is known to solve bugs on certain chips.
+
+ If unsure, say N.
+
+endif # NET_VENDOR_DLINK
diff --git a/drivers/net/ethernet/dlink/Makefile b/drivers/net/ethernet/dlink/Makefile
new file mode 100644
index 000000000000..c705eaa4f5b2
--- /dev/null
+++ b/drivers/net/ethernet/dlink/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the D-Link network device drivers.
+#
+
+obj-$(CONFIG_DE600) += de600.o
+obj-$(CONFIG_DE620) += de620.o
+obj-$(CONFIG_DL2K) += dl2k.o
+obj-$(CONFIG_SUNDANCE) += sundance.o
diff --git a/drivers/net/de600.c b/drivers/net/ethernet/dlink/de600.c
index 23a65398d011..23a65398d011 100644
--- a/drivers/net/de600.c
+++ b/drivers/net/ethernet/dlink/de600.c
diff --git a/drivers/net/de600.h b/drivers/net/ethernet/dlink/de600.h
index e80ecbabcf4e..e80ecbabcf4e 100644
--- a/drivers/net/de600.h
+++ b/drivers/net/ethernet/dlink/de600.h
diff --git a/drivers/net/de620.c b/drivers/net/ethernet/dlink/de620.c
index 1c51a7576119..3b934ab784d3 100644
--- a/drivers/net/de620.c
+++ b/drivers/net/ethernet/dlink/de620.c
@@ -767,7 +767,7 @@ static const struct net_device_ops de620_netdev_ops = {
.ndo_stop = de620_close,
.ndo_start_xmit = de620_start_xmit,
.ndo_tx_timeout = de620_timeout,
- .ndo_set_multicast_list = de620_set_multicast_list,
+ .ndo_set_rx_mode = de620_set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/de620.h b/drivers/net/ethernet/dlink/de620.h
index e8d9a88f4cb5..e8d9a88f4cb5 100644
--- a/drivers/net/de620.h
+++ b/drivers/net/ethernet/dlink/de620.h
diff --git a/drivers/net/dl2k.c b/drivers/net/ethernet/dlink/dl2k.c
index ed73e4a93508..b2dc2c81a147 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/ethernet/dlink/dl2k.c
@@ -92,7 +92,7 @@ static const struct net_device_ops netdev_ops = {
.ndo_get_stats = get_stats,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
- .ndo_set_multicast_list = set_multicast,
+ .ndo_set_rx_mode = set_multicast,
.ndo_do_ioctl = rio_ioctl,
.ndo_tx_timeout = rio_tx_timeout,
.ndo_change_mtu = change_mtu,
@@ -1428,7 +1428,7 @@ mii_wait_link (struct net_device *dev, int wait)
do {
bmsr = mii_read (dev, phy_addr, MII_BMSR);
- if (bmsr & MII_BMSR_LINK_STATUS)
+ if (bmsr & BMSR_LSTATUS)
return 0;
mdelay (1);
} while (--wait > 0);
@@ -1449,60 +1449,60 @@ mii_get_media (struct net_device *dev)
bmsr = mii_read (dev, phy_addr, MII_BMSR);
if (np->an_enable) {
- if (!(bmsr & MII_BMSR_AN_COMPLETE)) {
+ if (!(bmsr & BMSR_ANEGCOMPLETE)) {
/* Auto-Negotiation not completed */
return -1;
}
- negotiate = mii_read (dev, phy_addr, MII_ANAR) &
- mii_read (dev, phy_addr, MII_ANLPAR);
- mscr = mii_read (dev, phy_addr, MII_MSCR);
- mssr = mii_read (dev, phy_addr, MII_MSSR);
- if (mscr & MII_MSCR_1000BT_FD && mssr & MII_MSSR_LP_1000BT_FD) {
+ negotiate = mii_read (dev, phy_addr, MII_ADVERTISE) &
+ mii_read (dev, phy_addr, MII_LPA);
+ mscr = mii_read (dev, phy_addr, MII_CTRL1000);
+ mssr = mii_read (dev, phy_addr, MII_STAT1000);
+ if (mscr & ADVERTISE_1000FULL && mssr & LPA_1000FULL) {
np->speed = 1000;
np->full_duplex = 1;
printk (KERN_INFO "Auto 1000 Mbps, Full duplex\n");
- } else if (mscr & MII_MSCR_1000BT_HD && mssr & MII_MSSR_LP_1000BT_HD) {
+ } else if (mscr & ADVERTISE_1000HALF && mssr & LPA_1000HALF) {
np->speed = 1000;
np->full_duplex = 0;
printk (KERN_INFO "Auto 1000 Mbps, Half duplex\n");
- } else if (negotiate & MII_ANAR_100BX_FD) {
+ } else if (negotiate & ADVERTISE_100FULL) {
np->speed = 100;
np->full_duplex = 1;
printk (KERN_INFO "Auto 100 Mbps, Full duplex\n");
- } else if (negotiate & MII_ANAR_100BX_HD) {
+ } else if (negotiate & ADVERTISE_100HALF) {
np->speed = 100;
np->full_duplex = 0;
printk (KERN_INFO "Auto 100 Mbps, Half duplex\n");
- } else if (negotiate & MII_ANAR_10BT_FD) {
+ } else if (negotiate & ADVERTISE_10FULL) {
np->speed = 10;
np->full_duplex = 1;
printk (KERN_INFO "Auto 10 Mbps, Full duplex\n");
- } else if (negotiate & MII_ANAR_10BT_HD) {
+ } else if (negotiate & ADVERTISE_10HALF) {
np->speed = 10;
np->full_duplex = 0;
printk (KERN_INFO "Auto 10 Mbps, Half duplex\n");
}
- if (negotiate & MII_ANAR_PAUSE) {
+ if (negotiate & ADVERTISE_PAUSE_CAP) {
np->tx_flow &= 1;
np->rx_flow &= 1;
- } else if (negotiate & MII_ANAR_ASYMMETRIC) {
+ } else if (negotiate & ADVERTISE_PAUSE_ASYM) {
np->tx_flow = 0;
np->rx_flow &= 1;
}
/* else tx_flow, rx_flow = user select */
} else {
__u16 bmcr = mii_read (dev, phy_addr, MII_BMCR);
- switch (bmcr & (MII_BMCR_SPEED_100 | MII_BMCR_SPEED_1000)) {
- case MII_BMCR_SPEED_1000:
+ switch (bmcr & (BMCR_SPEED100 | BMCR_SPEED1000)) {
+ case BMCR_SPEED1000:
printk (KERN_INFO "Operating at 1000 Mbps, ");
break;
- case MII_BMCR_SPEED_100:
+ case BMCR_SPEED100:
printk (KERN_INFO "Operating at 100 Mbps, ");
break;
case 0:
printk (KERN_INFO "Operating at 10 Mbps, ");
}
- if (bmcr & MII_BMCR_DUPLEX_MODE) {
+ if (bmcr & BMCR_FULLDPLX) {
printk (KERN_CONT "Full duplex\n");
} else {
printk (KERN_CONT "Half duplex\n");
@@ -1536,24 +1536,22 @@ mii_set_media (struct net_device *dev)
if (np->an_enable) {
/* Advertise capabilities */
bmsr = mii_read (dev, phy_addr, MII_BMSR);
- anar = mii_read (dev, phy_addr, MII_ANAR) &
- ~MII_ANAR_100BX_FD &
- ~MII_ANAR_100BX_HD &
- ~MII_ANAR_100BT4 &
- ~MII_ANAR_10BT_FD &
- ~MII_ANAR_10BT_HD;
- if (bmsr & MII_BMSR_100BX_FD)
- anar |= MII_ANAR_100BX_FD;
- if (bmsr & MII_BMSR_100BX_HD)
- anar |= MII_ANAR_100BX_HD;
- if (bmsr & MII_BMSR_100BT4)
- anar |= MII_ANAR_100BT4;
- if (bmsr & MII_BMSR_10BT_FD)
- anar |= MII_ANAR_10BT_FD;
- if (bmsr & MII_BMSR_10BT_HD)
- anar |= MII_ANAR_10BT_HD;
- anar |= MII_ANAR_PAUSE | MII_ANAR_ASYMMETRIC;
- mii_write (dev, phy_addr, MII_ANAR, anar);
+ anar = mii_read (dev, phy_addr, MII_ADVERTISE) &
+ ~(ADVERTISE_100FULL | ADVERTISE_10FULL |
+ ADVERTISE_100HALF | ADVERTISE_10HALF |
+ ADVERTISE_100BASE4);
+ if (bmsr & BMSR_100FULL)
+ anar |= ADVERTISE_100FULL;
+ if (bmsr & BMSR_100HALF)
+ anar |= ADVERTISE_100HALF;
+ if (bmsr & BMSR_100BASE4)
+ anar |= ADVERTISE_100BASE4;
+ if (bmsr & BMSR_10FULL)
+ anar |= ADVERTISE_10FULL;
+ if (bmsr & BMSR_10HALF)
+ anar |= ADVERTISE_10HALF;
+ anar |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+ mii_write (dev, phy_addr, MII_ADVERTISE, anar);
/* Enable Auto crossover */
pscr = mii_read (dev, phy_addr, MII_PHY_SCR);
@@ -1561,8 +1559,8 @@ mii_set_media (struct net_device *dev)
mii_write (dev, phy_addr, MII_PHY_SCR, pscr);
/* Soft reset PHY */
- mii_write (dev, phy_addr, MII_BMCR, MII_BMCR_RESET);
- bmcr = MII_BMCR_AN_ENABLE | MII_BMCR_RESTART_AN | MII_BMCR_RESET;
+ mii_write (dev, phy_addr, MII_BMCR, BMCR_RESET);
+ bmcr = BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET;
mii_write (dev, phy_addr, MII_BMCR, bmcr);
mdelay(1);
} else {
@@ -1574,7 +1572,7 @@ mii_set_media (struct net_device *dev)
/* 2) PHY Reset */
bmcr = mii_read (dev, phy_addr, MII_BMCR);
- bmcr |= MII_BMCR_RESET;
+ bmcr |= BMCR_RESET;
mii_write (dev, phy_addr, MII_BMCR, bmcr);
/* 3) Power Down */
@@ -1583,25 +1581,25 @@ mii_set_media (struct net_device *dev)
mdelay (100); /* wait a certain time */
/* 4) Advertise nothing */
- mii_write (dev, phy_addr, MII_ANAR, 0);
+ mii_write (dev, phy_addr, MII_ADVERTISE, 0);
/* 5) Set media and Power Up */
- bmcr = MII_BMCR_POWER_DOWN;
+ bmcr = BMCR_PDOWN;
if (np->speed == 100) {
- bmcr |= MII_BMCR_SPEED_100;
+ bmcr |= BMCR_SPEED100;
printk (KERN_INFO "Manual 100 Mbps, ");
} else if (np->speed == 10) {
printk (KERN_INFO "Manual 10 Mbps, ");
}
if (np->full_duplex) {
- bmcr |= MII_BMCR_DUPLEX_MODE;
+ bmcr |= BMCR_FULLDPLX;
printk (KERN_CONT "Full duplex\n");
} else {
printk (KERN_CONT "Half duplex\n");
}
#if 0
/* Set 1000BaseT Master/Slave setting */
- mscr = mii_read (dev, phy_addr, MII_MSCR);
+ mscr = mii_read (dev, phy_addr, MII_CTRL1000);
mscr |= MII_MSCR_CFG_ENABLE;
mscr &= ~MII_MSCR_CFG_VALUE = 0;
#endif
@@ -1624,7 +1622,7 @@ mii_get_media_pcs (struct net_device *dev)
bmsr = mii_read (dev, phy_addr, PCS_BMSR);
if (np->an_enable) {
- if (!(bmsr & MII_BMSR_AN_COMPLETE)) {
+ if (!(bmsr & BMSR_ANEGCOMPLETE)) {
/* Auto-Negotiation not completed */
return -1;
}
@@ -1649,7 +1647,7 @@ mii_get_media_pcs (struct net_device *dev)
} else {
__u16 bmcr = mii_read (dev, phy_addr, PCS_BMCR);
printk (KERN_INFO "Operating at 1000 Mbps, ");
- if (bmcr & MII_BMCR_DUPLEX_MODE) {
+ if (bmcr & BMCR_FULLDPLX) {
printk (KERN_CONT "Full duplex\n");
} else {
printk (KERN_CONT "Half duplex\n");
@@ -1682,7 +1680,7 @@ mii_set_media_pcs (struct net_device *dev)
if (np->an_enable) {
/* Advertise capabilities */
esr = mii_read (dev, phy_addr, PCS_ESR);
- anar = mii_read (dev, phy_addr, MII_ANAR) &
+ anar = mii_read (dev, phy_addr, MII_ADVERTISE) &
~PCS_ANAR_HALF_DUPLEX &
~PCS_ANAR_FULL_DUPLEX;
if (esr & (MII_ESR_1000BT_HD | MII_ESR_1000BX_HD))
@@ -1690,22 +1688,21 @@ mii_set_media_pcs (struct net_device *dev)
if (esr & (MII_ESR_1000BT_FD | MII_ESR_1000BX_FD))
anar |= PCS_ANAR_FULL_DUPLEX;
anar |= PCS_ANAR_PAUSE | PCS_ANAR_ASYMMETRIC;
- mii_write (dev, phy_addr, MII_ANAR, anar);
+ mii_write (dev, phy_addr, MII_ADVERTISE, anar);
/* Soft reset PHY */
- mii_write (dev, phy_addr, MII_BMCR, MII_BMCR_RESET);
- bmcr = MII_BMCR_AN_ENABLE | MII_BMCR_RESTART_AN |
- MII_BMCR_RESET;
+ mii_write (dev, phy_addr, MII_BMCR, BMCR_RESET);
+ bmcr = BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET;
mii_write (dev, phy_addr, MII_BMCR, bmcr);
mdelay(1);
} else {
/* Force speed setting */
/* PHY Reset */
- bmcr = MII_BMCR_RESET;
+ bmcr = BMCR_RESET;
mii_write (dev, phy_addr, MII_BMCR, bmcr);
mdelay(10);
if (np->full_duplex) {
- bmcr = MII_BMCR_DUPLEX_MODE;
+ bmcr = BMCR_FULLDPLX;
printk (KERN_INFO "Manual full duplex\n");
} else {
bmcr = 0;
@@ -1715,7 +1712,7 @@ mii_set_media_pcs (struct net_device *dev)
mdelay(10);
/* Advertise nothing */
- mii_write (dev, phy_addr, MII_ANAR, 0);
+ mii_write (dev, phy_addr, MII_ADVERTISE, 0);
}
return 0;
}
diff --git a/drivers/net/dl2k.h b/drivers/net/ethernet/dlink/dl2k.h
index 7caab3d26a9e..ba0adcafa55a 100644
--- a/drivers/net/dl2k.h
+++ b/drivers/net/ethernet/dlink/dl2k.h
@@ -28,6 +28,7 @@
#include <linux/init.h>
#include <linux/crc32.h>
#include <linux/ethtool.h>
+#include <linux/mii.h>
#include <linux/bitops.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/io.h>
@@ -271,20 +272,9 @@ enum RFS_bits {
#define MII_RESET_TIME_OUT 10000
/* MII register */
enum _mii_reg {
- MII_BMCR = 0,
- MII_BMSR = 1,
- MII_PHY_ID1 = 2,
- MII_PHY_ID2 = 3,
- MII_ANAR = 4,
- MII_ANLPAR = 5,
- MII_ANER = 6,
- MII_ANNPT = 7,
- MII_ANLPRNP = 8,
- MII_MSCR = 9,
- MII_MSSR = 10,
- MII_ESR = 15,
MII_PHY_SCR = 16,
};
+
/* PCS register */
enum _pcs_reg {
PCS_BMCR = 0,
@@ -297,102 +287,6 @@ enum _pcs_reg {
PCS_ESR = 15,
};
-/* Basic Mode Control Register */
-enum _mii_bmcr {
- MII_BMCR_RESET = 0x8000,
- MII_BMCR_LOOP_BACK = 0x4000,
- MII_BMCR_SPEED_LSB = 0x2000,
- MII_BMCR_AN_ENABLE = 0x1000,
- MII_BMCR_POWER_DOWN = 0x0800,
- MII_BMCR_ISOLATE = 0x0400,
- MII_BMCR_RESTART_AN = 0x0200,
- MII_BMCR_DUPLEX_MODE = 0x0100,
- MII_BMCR_COL_TEST = 0x0080,
- MII_BMCR_SPEED_MSB = 0x0040,
- MII_BMCR_SPEED_RESERVED = 0x003f,
- MII_BMCR_SPEED_10 = 0,
- MII_BMCR_SPEED_100 = MII_BMCR_SPEED_LSB,
- MII_BMCR_SPEED_1000 = MII_BMCR_SPEED_MSB,
-};
-
-/* Basic Mode Status Register */
-enum _mii_bmsr {
- MII_BMSR_100BT4 = 0x8000,
- MII_BMSR_100BX_FD = 0x4000,
- MII_BMSR_100BX_HD = 0x2000,
- MII_BMSR_10BT_FD = 0x1000,
- MII_BMSR_10BT_HD = 0x0800,
- MII_BMSR_100BT2_FD = 0x0400,
- MII_BMSR_100BT2_HD = 0x0200,
- MII_BMSR_EXT_STATUS = 0x0100,
- MII_BMSR_PREAMBLE_SUPP = 0x0040,
- MII_BMSR_AN_COMPLETE = 0x0020,
- MII_BMSR_REMOTE_FAULT = 0x0010,
- MII_BMSR_AN_ABILITY = 0x0008,
- MII_BMSR_LINK_STATUS = 0x0004,
- MII_BMSR_JABBER_DETECT = 0x0002,
- MII_BMSR_EXT_CAP = 0x0001,
-};
-
-/* ANAR */
-enum _mii_anar {
- MII_ANAR_NEXT_PAGE = 0x8000,
- MII_ANAR_REMOTE_FAULT = 0x4000,
- MII_ANAR_ASYMMETRIC = 0x0800,
- MII_ANAR_PAUSE = 0x0400,
- MII_ANAR_100BT4 = 0x0200,
- MII_ANAR_100BX_FD = 0x0100,
- MII_ANAR_100BX_HD = 0x0080,
- MII_ANAR_10BT_FD = 0x0020,
- MII_ANAR_10BT_HD = 0x0010,
- MII_ANAR_SELECTOR = 0x001f,
- MII_IEEE8023_CSMACD = 0x0001,
-};
-
-/* ANLPAR */
-enum _mii_anlpar {
- MII_ANLPAR_NEXT_PAGE = MII_ANAR_NEXT_PAGE,
- MII_ANLPAR_REMOTE_FAULT = MII_ANAR_REMOTE_FAULT,
- MII_ANLPAR_ASYMMETRIC = MII_ANAR_ASYMMETRIC,
- MII_ANLPAR_PAUSE = MII_ANAR_PAUSE,
- MII_ANLPAR_100BT4 = MII_ANAR_100BT4,
- MII_ANLPAR_100BX_FD = MII_ANAR_100BX_FD,
- MII_ANLPAR_100BX_HD = MII_ANAR_100BX_HD,
- MII_ANLPAR_10BT_FD = MII_ANAR_10BT_FD,
- MII_ANLPAR_10BT_HD = MII_ANAR_10BT_HD,
- MII_ANLPAR_SELECTOR = MII_ANAR_SELECTOR,
-};
-
-/* Auto-Negotiation Expansion Register */
-enum _mii_aner {
- MII_ANER_PAR_DETECT_FAULT = 0x0010,
- MII_ANER_LP_NEXTPAGABLE = 0x0008,
- MII_ANER_NETXTPAGABLE = 0x0004,
- MII_ANER_PAGE_RECEIVED = 0x0002,
- MII_ANER_LP_NEGOTIABLE = 0x0001,
-};
-
-/* MASTER-SLAVE Control Register */
-enum _mii_mscr {
- MII_MSCR_TEST_MODE = 0xe000,
- MII_MSCR_CFG_ENABLE = 0x1000,
- MII_MSCR_CFG_VALUE = 0x0800,
- MII_MSCR_PORT_VALUE = 0x0400,
- MII_MSCR_1000BT_FD = 0x0200,
- MII_MSCR_1000BT_HD = 0X0100,
-};
-
-/* MASTER-SLAVE Status Register */
-enum _mii_mssr {
- MII_MSSR_CFG_FAULT = 0x8000,
- MII_MSSR_CFG_RES = 0x4000,
- MII_MSSR_LOCAL_RCV_STATUS = 0x2000,
- MII_MSSR_REMOTE_RCVR = 0x1000,
- MII_MSSR_LP_1000BT_FD = 0x0800,
- MII_MSSR_LP_1000BT_HD = 0x0400,
- MII_MSSR_IDLE_ERR_COUNT = 0x00ff,
-};
-
/* IEEE Extened Status Register */
enum _mii_esr {
MII_ESR_1000BX_FD = 0x8000,
diff --git a/drivers/net/sundance.c b/drivers/net/ethernet/dlink/sundance.c
index 4793df843c24..dcd7f7a71ad4 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/ethernet/dlink/sundance.c
@@ -464,7 +464,7 @@ static const struct net_device_ops netdev_ops = {
.ndo_stop = netdev_close,
.ndo_start_xmit = start_tx,
.ndo_get_stats = get_stats,
- .ndo_set_multicast_list = set_rx_mode,
+ .ndo_set_rx_mode = set_rx_mode,
.ndo_do_ioctl = netdev_ioctl,
.ndo_tx_timeout = tx_timeout,
.ndo_change_mtu = change_mtu,
diff --git a/drivers/net/dnet.c b/drivers/net/ethernet/dnet.c
index c1063d1540c2..c1063d1540c2 100644
--- a/drivers/net/dnet.c
+++ b/drivers/net/ethernet/dnet.c
diff --git a/drivers/net/dnet.h b/drivers/net/ethernet/dnet.h
index 37f5b30fa78b..37f5b30fa78b 100644
--- a/drivers/net/dnet.h
+++ b/drivers/net/ethernet/dnet.h
diff --git a/drivers/net/ethernet/emulex/Kconfig b/drivers/net/ethernet/emulex/Kconfig
new file mode 100644
index 000000000000..7a28a6433944
--- /dev/null
+++ b/drivers/net/ethernet/emulex/Kconfig
@@ -0,0 +1,23 @@
+#
+# Emulex driver configuration
+#
+
+config NET_VENDOR_EMULEX
+ bool "Emulex devices"
+ default y
+ depends on PCI && INET
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Emulex cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_EMULEX
+
+source "drivers/net/ethernet/emulex/benet/Kconfig"
+
+endif # NET_VENDOR_EMULEX
diff --git a/drivers/net/ethernet/emulex/Makefile b/drivers/net/ethernet/emulex/Makefile
new file mode 100644
index 000000000000..ea8ec574d45a
--- /dev/null
+++ b/drivers/net/ethernet/emulex/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Emulex device drivers.
+#
+
+obj-$(CONFIG_BE2NET) += benet/
diff --git a/drivers/net/ethernet/emulex/benet/Kconfig b/drivers/net/ethernet/emulex/benet/Kconfig
new file mode 100644
index 000000000000..804db04a2bd0
--- /dev/null
+++ b/drivers/net/ethernet/emulex/benet/Kconfig
@@ -0,0 +1,6 @@
+config BE2NET
+ tristate "ServerEngines' 10Gbps NIC - BladeEngine"
+ depends on PCI && INET
+ ---help---
+ This driver implements the NIC functionality for ServerEngines'
+ 10Gbps network adapter - BladeEngine.
diff --git a/drivers/net/benet/Makefile b/drivers/net/ethernet/emulex/benet/Makefile
index a60cd8051135..a60cd8051135 100644
--- a/drivers/net/benet/Makefile
+++ b/drivers/net/ethernet/emulex/benet/Makefile
diff --git a/drivers/net/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index c85768cd1b18..644e8fed8364 100644
--- a/drivers/net/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -29,6 +29,7 @@
#include <linux/interrupt.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/u64_stats_sync.h>
#include "be_hw.h"
@@ -136,6 +137,11 @@ static inline void *queue_tail_node(struct be_queue_info *q)
return q->dma_mem.va + q->tail * q->entry_size;
}
+static inline void *queue_index_node(struct be_queue_info *q, u16 index)
+{
+ return q->dma_mem.va + index * q->entry_size;
+}
+
static inline void queue_head_inc(struct be_queue_info *q)
{
index_inc(&q->head, q->len);
@@ -167,15 +173,15 @@ struct be_mcc_obj {
};
struct be_tx_stats {
- u32 be_tx_reqs; /* number of TX requests initiated */
- u32 be_tx_stops; /* number of times TX Q was stopped */
- u32 be_tx_wrbs; /* number of tx WRBs used */
- u32 be_tx_compl; /* number of tx completion entries processed */
- ulong be_tx_jiffies;
- u64 be_tx_bytes;
- u64 be_tx_bytes_prev;
- u64 be_tx_pkts;
- u32 be_tx_rate;
+ u64 tx_bytes;
+ u64 tx_pkts;
+ u64 tx_reqs;
+ u64 tx_wrbs;
+ u64 tx_compl;
+ ulong tx_jiffies;
+ u32 tx_stops;
+ struct u64_stats_sync sync;
+ struct u64_stats_sync sync_compl;
};
struct be_tx_obj {
@@ -195,22 +201,20 @@ struct be_rx_page_info {
};
struct be_rx_stats {
- u32 rx_post_fail;/* number of ethrx buffer alloc failures */
- u32 rx_polls; /* number of times NAPI called poll function */
- u32 rx_events; /* number of ucast rx completion events */
- u32 rx_compl; /* number of rx completion entries processed */
- ulong rx_dropped; /* number of skb allocation errors */
- ulong rx_jiffies;
u64 rx_bytes;
- u64 rx_bytes_prev;
u64 rx_pkts;
- u32 rx_rate;
+ u64 rx_pkts_prev;
+ ulong rx_jiffies;
+ u32 rx_drops_no_skbs; /* skb allocation errors */
+ u32 rx_drops_no_frags; /* HW has no fetched frags */
+ u32 rx_post_fail; /* page post alloc failures */
+ u32 rx_polls; /* NAPI calls */
+ u32 rx_events;
+ u32 rx_compl;
u32 rx_mcast_pkts;
- u32 rxcp_err; /* Num rx completion entries w/ err set. */
- ulong rx_fps_jiffies; /* jiffies at last FPS calc */
- u32 rx_frags;
- u32 prev_rx_frags;
- u32 rx_fps; /* Rx frags per second */
+ u32 rx_compl_err; /* completions with err set */
+ u32 rx_pps; /* pkts per second */
+ struct u64_stats_sync sync;
};
struct be_rx_compl_info {
@@ -218,7 +222,7 @@ struct be_rx_compl_info {
u16 vlan_tag;
u16 pkt_size;
u16 rxq_idx;
- u16 mac_id;
+ u16 port;
u8 vlanf;
u8 num_rcvd;
u8 err;
@@ -246,44 +250,41 @@ struct be_rx_obj {
};
struct be_drv_stats {
- u8 be_on_die_temperature;
- u64 be_tx_events;
- u64 eth_red_drops;
- u64 rx_drops_no_pbuf;
- u64 rx_drops_no_txpb;
- u64 rx_drops_no_erx_descr;
- u64 rx_drops_no_tpre_descr;
- u64 rx_drops_too_many_frags;
- u64 rx_drops_invalid_ring;
- u64 forwarded_packets;
- u64 rx_drops_mtu;
- u64 rx_crc_errors;
- u64 rx_alignment_symbol_errors;
- u64 rx_pause_frames;
- u64 rx_priority_pause_frames;
- u64 rx_control_frames;
- u64 rx_in_range_errors;
- u64 rx_out_range_errors;
- u64 rx_frame_too_long;
- u64 rx_address_match_errors;
- u64 rx_dropped_too_small;
- u64 rx_dropped_too_short;
- u64 rx_dropped_header_too_small;
- u64 rx_dropped_tcp_length;
- u64 rx_dropped_runt;
- u64 rx_ip_checksum_errs;
- u64 rx_tcp_checksum_errs;
- u64 rx_udp_checksum_errs;
- u64 rx_switched_unicast_packets;
- u64 rx_switched_multicast_packets;
- u64 rx_switched_broadcast_packets;
- u64 tx_pauseframes;
- u64 tx_priority_pauseframes;
- u64 tx_controlframes;
- u64 rxpp_fifo_overflow_drop;
- u64 rx_input_fifo_overflow_drop;
- u64 pmem_fifo_overflow_drop;
- u64 jabber_events;
+ u32 be_on_die_temperature;
+ u32 tx_events;
+ u32 eth_red_drops;
+ u32 rx_drops_no_pbuf;
+ u32 rx_drops_no_txpb;
+ u32 rx_drops_no_erx_descr;
+ u32 rx_drops_no_tpre_descr;
+ u32 rx_drops_too_many_frags;
+ u32 rx_drops_invalid_ring;
+ u32 forwarded_packets;
+ u32 rx_drops_mtu;
+ u32 rx_crc_errors;
+ u32 rx_alignment_symbol_errors;
+ u32 rx_pause_frames;
+ u32 rx_priority_pause_frames;
+ u32 rx_control_frames;
+ u32 rx_in_range_errors;
+ u32 rx_out_range_errors;
+ u32 rx_frame_too_long;
+ u32 rx_address_match_errors;
+ u32 rx_dropped_too_small;
+ u32 rx_dropped_too_short;
+ u32 rx_dropped_header_too_small;
+ u32 rx_dropped_tcp_length;
+ u32 rx_dropped_runt;
+ u32 rx_ip_checksum_errs;
+ u32 rx_tcp_checksum_errs;
+ u32 rx_udp_checksum_errs;
+ u32 tx_pauseframes;
+ u32 tx_priority_pauseframes;
+ u32 tx_controlframes;
+ u32 rxpp_fifo_overflow_drop;
+ u32 rx_input_fifo_overflow_drop;
+ u32 pmem_fifo_overflow_drop;
+ u32 jabber_events;
};
struct be_vf_cfg {
@@ -302,7 +303,6 @@ struct be_adapter {
u8 __iomem *csr;
u8 __iomem *db; /* Door Bell */
- u8 __iomem *pcicfg; /* PCI config space */
struct mutex mbox_lock; /* For serializing mbox cmds to BE card */
struct be_dma_mem mbox_mem;
@@ -338,7 +338,7 @@ struct be_adapter {
u8 vlan_tag[VLAN_N_VID];
u8 vlan_prio_bmap; /* Available Priority BitMap */
u16 recommended_prio; /* Recommended Priority */
- struct be_dma_mem mc_cmd_mem;
+ struct be_dma_mem rx_filter; /* Cmd DMA mem for rx-filter */
struct be_dma_mem stats_cmd;
/* Work queue used to perform periodic tasks like getting statistics */
@@ -352,7 +352,6 @@ struct be_adapter {
u32 beacon_state; /* for set_phys_id */
bool eeh_err;
- bool link_up;
u32 port_num;
bool promiscuous;
bool wol;
@@ -385,6 +384,8 @@ struct be_adapter {
#define BE_GEN2 2
#define BE_GEN3 3
+#define ON 1
+#define OFF 0
#define lancer_chip(adapter) ((adapter->pdev->device == OC_DEVICE_ID3) || \
(adapter->pdev->device == OC_DEVICE_ID4))
@@ -525,8 +526,7 @@ static inline bool be_multi_rxq(const struct be_adapter *adapter)
extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm,
u16 num_popped);
-extern void be_link_status_update(struct be_adapter *adapter, bool link_up);
-extern void netdev_stats_update(struct be_adapter *adapter);
+extern void be_link_status_update(struct be_adapter *adapter, u32 link_status);
extern void be_parse_stats(struct be_adapter *adapter);
extern int be_load_fw(struct be_adapter *adapter, u8 *func);
#endif /* BE_H */
diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
index 054fa67bc4e3..e0ff96193c49 100644
--- a/drivers/net/benet/be_cmds.c
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -19,7 +19,12 @@
#include "be_cmds.h"
/* Must be a power of 2 or else MODULO will BUG_ON */
-static int be_get_temp_freq = 32;
+static int be_get_temp_freq = 64;
+
+static inline void *embedded_payload(struct be_mcc_wrb *wrb)
+{
+ return wrb->payload.embedded_payload;
+}
static void be_mcc_notify(struct be_adapter *adapter)
{
@@ -82,31 +87,23 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
if (((compl->tag0 == OPCODE_ETH_GET_STATISTICS) ||
(compl->tag0 == OPCODE_ETH_GET_PPORT_STATS)) &&
(compl->tag1 == CMD_SUBSYSTEM_ETH)) {
- if (adapter->generation == BE_GEN3) {
- if (lancer_chip(adapter)) {
- struct lancer_cmd_resp_pport_stats
- *resp = adapter->stats_cmd.va;
- be_dws_le_to_cpu(&resp->pport_stats,
- sizeof(resp->pport_stats));
- } else {
- struct be_cmd_resp_get_stats_v1 *resp =
- adapter->stats_cmd.va;
-
- be_dws_le_to_cpu(&resp->hw_stats,
- sizeof(resp->hw_stats));
- }
- } else {
- struct be_cmd_resp_get_stats_v0 *resp =
- adapter->stats_cmd.va;
-
- be_dws_le_to_cpu(&resp->hw_stats,
- sizeof(resp->hw_stats));
- }
be_parse_stats(adapter);
- netdev_stats_update(adapter);
adapter->stats_cmd_sent = false;
}
+ if (compl->tag0 ==
+ OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES) {
+ struct be_mcc_wrb *mcc_wrb =
+ queue_index_node(&adapter->mcc_obj.q,
+ compl->tag1);
+ struct be_cmd_resp_get_cntl_addnl_attribs *resp =
+ embedded_payload(mcc_wrb);
+ adapter->drv_stats.be_on_die_temperature =
+ resp->on_die_temperature;
+ }
} else {
+ if (compl->tag0 == OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES)
+ be_get_temp_freq = 0;
+
if (compl_status == MCC_STATUS_NOT_SUPPORTED ||
compl_status == MCC_STATUS_ILLEGAL_REQUEST)
goto done;
@@ -131,8 +128,7 @@ done:
static void be_async_link_state_process(struct be_adapter *adapter,
struct be_async_event_link_state *evt)
{
- be_link_status_update(adapter,
- evt->port_link_status == ASYNC_EVENT_LINK_UP);
+ be_link_status_update(adapter, evt->port_link_status);
}
/* Grp5 CoS Priority evt */
@@ -162,7 +158,7 @@ static void be_async_grp5_pvid_state_process(struct be_adapter *adapter,
struct be_async_event_grp5_pvid_state *evt)
{
if (evt->enabled)
- adapter->pvid = le16_to_cpu(evt->tag);
+ adapter->pvid = le16_to_cpu(evt->tag) & VLAN_VID_MASK;
else
adapter->pvid = 0;
}
@@ -420,16 +416,12 @@ int be_cmd_POST(struct be_adapter *adapter)
} else {
return 0;
}
- } while (timeout < 40);
+ } while (timeout < 60);
dev_err(dev, "POST timeout; stage=0x%x\n", stage);
return -1;
}
-static inline void *embedded_payload(struct be_mcc_wrb *wrb)
-{
- return wrb->payload.embedded_payload;
-}
static inline struct be_sge *nonembedded_sgl(struct be_mcc_wrb *wrb)
{
@@ -623,7 +615,7 @@ int be_cmd_eq_create(struct be_adapter *adapter,
return status;
}
-/* Uses mbox */
+/* Use MCC */
int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
u8 type, bool permanent, u32 if_handle)
{
@@ -631,10 +623,13 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
struct be_cmd_req_mac_query *req;
int status;
- if (mutex_lock_interruptible(&adapter->mbox_lock))
- return -1;
+ spin_lock_bh(&adapter->mcc_lock);
- wrb = wrb_from_mbox(adapter);
+ wrb = wrb_from_mccq(adapter);
+ if (!wrb) {
+ status = -EBUSY;
+ goto err;
+ }
req = embedded_payload(wrb);
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
@@ -651,13 +646,14 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
req->permanent = 0;
}
- status = be_mbox_notify_wait(adapter);
+ status = be_mcc_notify_wait(adapter);
if (!status) {
struct be_cmd_resp_mac_query *resp = embedded_payload(wrb);
memcpy(mac_addr, resp->mac.addr, ETH_ALEN);
}
- mutex_unlock(&adapter->mbox_lock);
+err:
+ spin_unlock_bh(&adapter->mcc_lock);
return status;
}
@@ -1119,20 +1115,22 @@ err:
}
/* Create an rx filtering policy configuration on an i/f
- * Uses mbox
+ * Uses MCCQ
*/
int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags,
- u8 *mac, bool pmac_invalid, u32 *if_handle, u32 *pmac_id,
- u32 domain)
+ u8 *mac, u32 *if_handle, u32 *pmac_id, u32 domain)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_if_create *req;
int status;
- if (mutex_lock_interruptible(&adapter->mbox_lock))
- return -1;
+ spin_lock_bh(&adapter->mcc_lock);
- wrb = wrb_from_mbox(adapter);
+ wrb = wrb_from_mccq(adapter);
+ if (!wrb) {
+ status = -EBUSY;
+ goto err;
+ }
req = embedded_payload(wrb);
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
@@ -1144,23 +1142,25 @@ int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags,
req->hdr.domain = domain;
req->capability_flags = cpu_to_le32(cap_flags);
req->enable_flags = cpu_to_le32(en_flags);
- req->pmac_invalid = pmac_invalid;
- if (!pmac_invalid)
+ if (mac)
memcpy(req->mac_addr, mac, ETH_ALEN);
+ else
+ req->pmac_invalid = true;
- status = be_mbox_notify_wait(adapter);
+ status = be_mcc_notify_wait(adapter);
if (!status) {
struct be_cmd_resp_if_create *resp = embedded_payload(wrb);
*if_handle = le32_to_cpu(resp->interface_id);
- if (!pmac_invalid)
+ if (mac)
*pmac_id = le32_to_cpu(resp->pmac_id);
}
- mutex_unlock(&adapter->mbox_lock);
+err:
+ spin_unlock_bh(&adapter->mcc_lock);
return status;
}
-/* Uses mbox */
+/* Uses MCCQ */
int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id, u32 domain)
{
struct be_mcc_wrb *wrb;
@@ -1170,10 +1170,16 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id, u32 domain)
if (adapter->eeh_err)
return -EIO;
- if (mutex_lock_interruptible(&adapter->mbox_lock))
- return -1;
+ if (!interface_id)
+ return 0;
- wrb = wrb_from_mbox(adapter);
+ spin_lock_bh(&adapter->mcc_lock);
+
+ wrb = wrb_from_mccq(adapter);
+ if (!wrb) {
+ status = -EBUSY;
+ goto err;
+ }
req = embedded_payload(wrb);
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
@@ -1185,10 +1191,9 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id, u32 domain)
req->hdr.domain = domain;
req->interface_id = cpu_to_le32(interface_id);
- status = be_mbox_notify_wait(adapter);
-
- mutex_unlock(&adapter->mbox_lock);
-
+ status = be_mcc_notify_wait(adapter);
+err:
+ spin_unlock_bh(&adapter->mcc_lock);
return status;
}
@@ -1282,8 +1287,8 @@ err:
}
/* Uses synchronous mcc */
-int be_cmd_link_status_query(struct be_adapter *adapter,
- bool *link_up, u8 *mac_speed, u16 *link_speed, u32 dom)
+int be_cmd_link_status_query(struct be_adapter *adapter, u8 *mac_speed,
+ u16 *link_speed, u32 dom)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_link_status *req;
@@ -1298,8 +1303,6 @@ int be_cmd_link_status_query(struct be_adapter *adapter,
}
req = embedded_payload(wrb);
- *link_up = false;
-
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
OPCODE_COMMON_NTWK_LINK_STATUS_QUERY);
@@ -1310,9 +1313,9 @@ int be_cmd_link_status_query(struct be_adapter *adapter,
if (!status) {
struct be_cmd_resp_link_status *resp = embedded_payload(wrb);
if (resp->mac_speed != PHY_LINK_SPEED_ZERO) {
- *link_up = true;
*link_speed = le16_to_cpu(resp->link_speed);
- *mac_speed = resp->mac_speed;
+ if (mac_speed)
+ *mac_speed = resp->mac_speed;
}
}
@@ -1326,10 +1329,13 @@ int be_cmd_get_die_temperature(struct be_adapter *adapter)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_get_cntl_addnl_attribs *req;
+ u16 mccq_index;
int status;
spin_lock_bh(&adapter->mcc_lock);
+ mccq_index = adapter->mcc_obj.q.head;
+
wrb = wrb_from_mccq(adapter);
if (!wrb) {
status = -EBUSY;
@@ -1343,16 +1349,9 @@ int be_cmd_get_die_temperature(struct be_adapter *adapter)
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES, sizeof(*req));
- status = be_mcc_notify_wait(adapter);
- if (!status) {
- struct be_cmd_resp_get_cntl_addnl_attribs *resp =
- embedded_payload(wrb);
- adapter->drv_stats.be_on_die_temperature =
- resp->on_die_temperature;
- }
- /* If IOCTL fails once, do not bother issuing it again */
- else
- be_get_temp_freq = 0;
+ wrb->tag1 = mccq_index;
+
+ be_mcc_notify(adapter);
err:
spin_unlock_bh(&adapter->mcc_lock);
@@ -1454,7 +1453,7 @@ void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf)
struct be_cmd_resp_get_fat *resp = get_fat_cmd.va;
memcpy(buf + offset,
resp->data_buffer,
- resp->read_log_length);
+ le32_to_cpu(resp->read_log_length));
} else {
dev_err(&adapter->pdev->dev, "FAT Table Retrieve error\n");
goto err;
@@ -1469,32 +1468,37 @@ err:
spin_unlock_bh(&adapter->mcc_lock);
}
-/* Uses Mbox */
-int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver)
+/* Uses synchronous mcc */
+int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver,
+ char *fw_on_flash)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_get_fw_version *req;
int status;
- if (mutex_lock_interruptible(&adapter->mbox_lock))
- return -1;
+ spin_lock_bh(&adapter->mcc_lock);
- wrb = wrb_from_mbox(adapter);
- req = embedded_payload(wrb);
+ wrb = wrb_from_mccq(adapter);
+ if (!wrb) {
+ status = -EBUSY;
+ goto err;
+ }
+ req = embedded_payload(wrb);
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
- OPCODE_COMMON_GET_FW_VERSION);
-
+ OPCODE_COMMON_GET_FW_VERSION);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
- OPCODE_COMMON_GET_FW_VERSION, sizeof(*req));
+ OPCODE_COMMON_GET_FW_VERSION, sizeof(*req));
- status = be_mbox_notify_wait(adapter);
+ status = be_mcc_notify_wait(adapter);
if (!status) {
struct be_cmd_resp_get_fw_version *resp = embedded_payload(wrb);
- strncpy(fw_ver, resp->firmware_version_string, FW_VER_LEN);
+ strcpy(fw_ver, resp->firmware_version_string);
+ if (fw_on_flash)
+ strcpy(fw_on_flash, resp->fw_on_flash_version_string);
}
-
- mutex_unlock(&adapter->mbox_lock);
+err:
+ spin_unlock_bh(&adapter->mcc_lock);
return status;
}
@@ -1573,27 +1577,14 @@ err:
return status;
}
-/* Uses MCC for this command as it may be called in BH context
- * Uses synchronous mcc
- */
-int be_cmd_promiscuous_config(struct be_adapter *adapter, bool en)
+int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value)
{
struct be_mcc_wrb *wrb;
- struct be_cmd_req_rx_filter *req;
- struct be_dma_mem promiscous_cmd;
+ struct be_dma_mem *mem = &adapter->rx_filter;
+ struct be_cmd_req_rx_filter *req = mem->va;
struct be_sge *sge;
int status;
- memset(&promiscous_cmd, 0, sizeof(struct be_dma_mem));
- promiscous_cmd.size = sizeof(struct be_cmd_req_rx_filter);
- promiscous_cmd.va = pci_alloc_consistent(adapter->pdev,
- promiscous_cmd.size, &promiscous_cmd.dma);
- if (!promiscous_cmd.va) {
- dev_err(&adapter->pdev->dev,
- "Memory allocation failure\n");
- return -ENOMEM;
- }
-
spin_lock_bh(&adapter->mcc_lock);
wrb = wrb_from_mccq(adapter);
@@ -1601,80 +1592,39 @@ int be_cmd_promiscuous_config(struct be_adapter *adapter, bool en)
status = -EBUSY;
goto err;
}
-
- req = promiscous_cmd.va;
sge = nonembedded_sgl(wrb);
-
- be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1,
- OPCODE_COMMON_NTWK_RX_FILTER);
- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
- OPCODE_COMMON_NTWK_RX_FILTER, sizeof(*req));
-
- req->if_id = cpu_to_le32(adapter->if_handle);
- req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS);
- if (en)
- req->if_flags = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS);
-
- sge->pa_hi = cpu_to_le32(upper_32_bits(promiscous_cmd.dma));
- sge->pa_lo = cpu_to_le32(promiscous_cmd.dma & 0xFFFFFFFF);
- sge->len = cpu_to_le32(promiscous_cmd.size);
-
- status = be_mcc_notify_wait(adapter);
-
-err:
- spin_unlock_bh(&adapter->mcc_lock);
- pci_free_consistent(adapter->pdev, promiscous_cmd.size,
- promiscous_cmd.va, promiscous_cmd.dma);
- return status;
-}
-
-/*
- * Uses MCC for this command as it may be called in BH context
- * (mc == NULL) => multicast promiscuous
- */
-int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id,
- struct net_device *netdev, struct be_dma_mem *mem)
-{
- struct be_mcc_wrb *wrb;
- struct be_cmd_req_mcast_mac_config *req = mem->va;
- struct be_sge *sge;
- int status;
-
- spin_lock_bh(&adapter->mcc_lock);
-
- wrb = wrb_from_mccq(adapter);
- if (!wrb) {
- status = -EBUSY;
- goto err;
- }
- sge = nonembedded_sgl(wrb);
- memset(req, 0, sizeof(*req));
-
- be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1,
- OPCODE_COMMON_NTWK_MULTICAST_SET);
sge->pa_hi = cpu_to_le32(upper_32_bits(mem->dma));
sge->pa_lo = cpu_to_le32(mem->dma & 0xFFFFFFFF);
sge->len = cpu_to_le32(mem->size);
+ be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1,
+ OPCODE_COMMON_NTWK_RX_FILTER);
+ memset(req, 0, sizeof(*req));
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
- OPCODE_COMMON_NTWK_MULTICAST_SET, sizeof(*req));
+ OPCODE_COMMON_NTWK_RX_FILTER, sizeof(*req));
- req->interface_id = if_id;
- if (netdev) {
- int i;
+ req->if_id = cpu_to_le32(adapter->if_handle);
+ if (flags & IFF_PROMISC) {
+ req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS |
+ BE_IF_FLAGS_VLAN_PROMISCUOUS);
+ if (value == ON)
+ req->if_flags = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS |
+ BE_IF_FLAGS_VLAN_PROMISCUOUS);
+ } else if (flags & IFF_ALLMULTI) {
+ req->if_flags_mask = req->if_flags =
+ cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS);
+ } else {
struct netdev_hw_addr *ha;
+ int i = 0;
- req->num_mac = cpu_to_le16(netdev_mc_count(netdev));
-
- i = 0;
- netdev_for_each_mc_addr(ha, netdev)
- memcpy(req->mac[i++].byte, ha->addr, ETH_ALEN);
- } else {
- req->promiscuous = 1;
+ req->if_flags_mask = req->if_flags =
+ cpu_to_le32(BE_IF_FLAGS_MULTICAST);
+ req->mcast_num = cpu_to_le16(netdev_mc_count(adapter->netdev));
+ netdev_for_each_mc_addr(ha, adapter->netdev)
+ memcpy(req->mcast_mac[i++].byte, ha->addr, ETH_ALEN);
}
status = be_mcc_notify_wait(adapter);
-
err:
spin_unlock_bh(&adapter->mcc_lock);
return status;
@@ -2020,7 +1970,7 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
spin_unlock_bh(&adapter->mcc_lock);
if (!wait_for_completion_timeout(&adapter->flash_compl,
- msecs_to_jiffies(12000)))
+ msecs_to_jiffies(40000)))
status = -1;
else
status = adapter->flash_status;
@@ -2268,11 +2218,13 @@ err:
return status;
}
-int be_cmd_get_phy_info(struct be_adapter *adapter, struct be_dma_mem *cmd)
+int be_cmd_get_phy_info(struct be_adapter *adapter,
+ struct be_phy_info *phy_info)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_get_phy_info *req;
struct be_sge *sge;
+ struct be_dma_mem cmd;
int status;
spin_lock_bh(&adapter->mcc_lock);
@@ -2282,8 +2234,16 @@ int be_cmd_get_phy_info(struct be_adapter *adapter, struct be_dma_mem *cmd)
status = -EBUSY;
goto err;
}
+ cmd.size = sizeof(struct be_cmd_req_get_phy_info);
+ cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size,
+ &cmd.dma);
+ if (!cmd.va) {
+ dev_err(&adapter->pdev->dev, "Memory alloc failure\n");
+ status = -ENOMEM;
+ goto err;
+ }
- req = cmd->va;
+ req = cmd.va;
sge = nonembedded_sgl(wrb);
be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1,
@@ -2293,11 +2253,20 @@ int be_cmd_get_phy_info(struct be_adapter *adapter, struct be_dma_mem *cmd)
OPCODE_COMMON_GET_PHY_DETAILS,
sizeof(*req));
- sge->pa_hi = cpu_to_le32(upper_32_bits(cmd->dma));
- sge->pa_lo = cpu_to_le32(cmd->dma & 0xFFFFFFFF);
- sge->len = cpu_to_le32(cmd->size);
+ sge->pa_hi = cpu_to_le32(upper_32_bits(cmd.dma));
+ sge->pa_lo = cpu_to_le32(cmd.dma & 0xFFFFFFFF);
+ sge->len = cpu_to_le32(cmd.size);
status = be_mcc_notify_wait(adapter);
+ if (!status) {
+ struct be_phy_info *resp_phy_info =
+ cmd.va + sizeof(struct be_cmd_req_hdr);
+ phy_info->phy_type = le16_to_cpu(resp_phy_info->phy_type);
+ phy_info->interface_type =
+ le16_to_cpu(resp_phy_info->interface_type);
+ }
+ pci_free_consistent(adapter->pdev, cmd.size,
+ cmd.va, cmd.dma);
err:
spin_unlock_bh(&adapter->mcc_lock);
return status;
diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h
index 8e4d48824fe9..a35cd03fac4e 100644
--- a/drivers/net/benet/be_cmds.h
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.h
@@ -89,9 +89,10 @@ struct be_async_event_trailer {
};
enum {
- ASYNC_EVENT_LINK_DOWN = 0x0,
- ASYNC_EVENT_LINK_UP = 0x1
+ LINK_DOWN = 0x0,
+ LINK_UP = 0x1
};
+#define LINK_STATUS_MASK 0x1
/* When the event code of an async trailer is link-state, the mcc_compl
* must be interpreted as follows
@@ -693,8 +694,7 @@ struct be_cmd_resp_get_stats_v0 {
struct be_hw_stats_v0 hw_stats;
};
-#define make_64bit_val(hi_32, lo_32) (((u64)hi_32<<32) | lo_32)
-struct lancer_cmd_pport_stats {
+struct lancer_pport_stats {
u32 tx_packets_lo;
u32 tx_packets_hi;
u32 tx_unicast_packets_lo;
@@ -871,16 +871,16 @@ struct lancer_cmd_req_pport_stats {
struct be_cmd_req_hdr hdr;
union {
struct pport_stats_params params;
- u8 rsvd[sizeof(struct lancer_cmd_pport_stats)];
+ u8 rsvd[sizeof(struct lancer_pport_stats)];
} cmd_params;
};
struct lancer_cmd_resp_pport_stats {
struct be_cmd_resp_hdr hdr;
- struct lancer_cmd_pport_stats pport_stats;
+ struct lancer_pport_stats pport_stats;
};
-static inline struct lancer_cmd_pport_stats*
+static inline struct lancer_pport_stats*
pport_stats_from_cmd(struct be_adapter *adapter)
{
struct lancer_cmd_resp_pport_stats *cmd = adapter->stats_cmd.va;
@@ -910,21 +910,12 @@ struct be_cmd_req_vlan_config {
u16 normal_vlan[64];
} __packed;
-/******************** Multicast MAC Config *******************/
+/******************* RX FILTER ******************************/
#define BE_MAX_MC 64 /* set mcast promisc if > 64 */
struct macaddr {
u8 byte[ETH_ALEN];
};
-struct be_cmd_req_mcast_mac_config {
- struct be_cmd_req_hdr hdr;
- u16 num_mac;
- u8 promiscuous;
- u8 interface_id;
- struct macaddr mac[BE_MAX_MC];
-} __packed;
-
-/******************* RX FILTER ******************************/
struct be_cmd_req_rx_filter {
struct be_cmd_req_hdr hdr;
u32 global_flags_mask;
@@ -932,11 +923,10 @@ struct be_cmd_req_rx_filter {
u32 if_flags_mask;
u32 if_flags;
u32 if_id;
- u32 multicast_num;
- struct macaddr mac[BE_MAX_MC];
+ u32 mcast_num;
+ struct macaddr mcast_mac[BE_MAX_MC];
};
-
/******************** Link Status Query *******************/
struct be_cmd_req_link_status {
struct be_cmd_req_hdr hdr;
@@ -1056,6 +1046,12 @@ struct be_cmd_resp_modify_eq_delay {
/******************** Get FW Config *******************/
#define BE_FUNCTION_CAPS_RSS 0x2
+/* The HW can come up in either of the following multi-channel modes
+ * based on the skew/IPL.
+ */
+#define FLEX10_MODE 0x400
+#define VNIC_MODE 0x20000
+#define UMC_ENABLED 0x1000000
struct be_cmd_req_query_fw_cfg {
struct be_cmd_req_hdr hdr;
u32 rsvd[31];
@@ -1254,14 +1250,19 @@ struct be_cmd_req_get_phy_info {
struct be_cmd_req_hdr hdr;
u8 rsvd0[24];
};
-struct be_cmd_resp_get_phy_info {
- struct be_cmd_req_hdr hdr;
+
+struct be_phy_info {
u16 phy_type;
u16 interface_type;
u32 misc_params;
u32 future_use[4];
};
+struct be_cmd_resp_get_phy_info {
+ struct be_cmd_req_hdr hdr;
+ struct be_phy_info phy_info;
+};
+
/*********************** Set QOS ***********************/
#define BE_QOS_BITS_NIC 1
@@ -1383,8 +1384,7 @@ struct be_cmd_resp_get_stats_v1 {
struct be_hw_stats_v1 hw_stats;
};
-static inline void *
-hw_stats_from_cmd(struct be_adapter *adapter)
+static inline void *hw_stats_from_cmd(struct be_adapter *adapter)
{
if (adapter->generation == BE_GEN3) {
struct be_cmd_resp_get_stats_v1 *cmd = adapter->stats_cmd.va;
@@ -1397,34 +1397,6 @@ hw_stats_from_cmd(struct be_adapter *adapter)
}
}
-static inline void *be_port_rxf_stats_from_cmd(struct be_adapter *adapter)
-{
- if (adapter->generation == BE_GEN3) {
- struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter);
- struct be_rxf_stats_v1 *rxf_stats = &hw_stats->rxf;
-
- return &rxf_stats->port[adapter->port_num];
- } else {
- struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter);
- struct be_rxf_stats_v0 *rxf_stats = &hw_stats->rxf;
-
- return &rxf_stats->port[adapter->port_num];
- }
-}
-
-static inline void *be_rxf_stats_from_cmd(struct be_adapter *adapter)
-{
- if (adapter->generation == BE_GEN3) {
- struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter);
-
- return &hw_stats->rxf;
- } else {
- struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter);
-
- return &hw_stats->rxf;
- }
-}
-
static inline void *be_erx_stats_from_cmd(struct be_adapter *adapter)
{
if (adapter->generation == BE_GEN3) {
@@ -1438,19 +1410,6 @@ static inline void *be_erx_stats_from_cmd(struct be_adapter *adapter)
}
}
-static inline void *be_pmem_stats_from_cmd(struct be_adapter *adapter)
-{
- if (adapter->generation == BE_GEN3) {
- struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter);
-
- return &hw_stats->pmem;
- } else {
- struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter);
-
- return &hw_stats->pmem;
- }
-}
-
extern int be_pci_fnum_get(struct be_adapter *adapter);
extern int be_cmd_POST(struct be_adapter *adapter);
extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
@@ -1460,8 +1419,8 @@ extern int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr,
extern int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id,
u32 pmac_id, u32 domain);
extern int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags,
- u32 en_flags, u8 *mac, bool pmac_invalid,
- u32 *if_handle, u32 *pmac_id, u32 domain);
+ u32 en_flags, u8 *mac, u32 *if_handle, u32 *pmac_id,
+ u32 domain);
extern int be_cmd_if_destroy(struct be_adapter *adapter, u32 if_handle,
u32 domain);
extern int be_cmd_eq_create(struct be_adapter *adapter,
@@ -1485,21 +1444,20 @@ extern int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q,
extern int be_cmd_rxq_destroy(struct be_adapter *adapter,
struct be_queue_info *q);
extern int be_cmd_link_status_query(struct be_adapter *adapter,
- bool *link_up, u8 *mac_speed, u16 *link_speed, u32 dom);
+ u8 *mac_speed, u16 *link_speed, u32 dom);
extern int be_cmd_reset(struct be_adapter *adapter);
extern int be_cmd_get_stats(struct be_adapter *adapter,
struct be_dma_mem *nonemb_cmd);
extern int lancer_cmd_get_pport_stats(struct be_adapter *adapter,
struct be_dma_mem *nonemb_cmd);
-extern int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver);
+extern int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver,
+ char *fw_on_flash);
extern int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd);
extern int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id,
u16 *vtag_array, u32 num, bool untagged,
bool promiscuous);
-extern int be_cmd_promiscuous_config(struct be_adapter *adapter, bool en);
-extern int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id,
- struct net_device *netdev, struct be_dma_mem *mem);
+extern int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 status);
extern int be_cmd_set_flow_control(struct be_adapter *adapter,
u32 tx_fc, u32 rx_fc);
extern int be_cmd_get_flow_control(struct be_adapter *adapter,
@@ -1540,7 +1498,7 @@ extern int be_cmd_get_seeprom_data(struct be_adapter *adapter,
extern int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num,
u8 loopback_type, u8 enable);
extern int be_cmd_get_phy_info(struct be_adapter *adapter,
- struct be_dma_mem *cmd);
+ struct be_phy_info *phy_info);
extern int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain);
extern void be_detect_dump_ue(struct be_adapter *adapter);
extern int be_cmd_get_die_temperature(struct be_adapter *adapter);
diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c
index 7fd8130d86ea..bf8153ea4ed8 100644
--- a/drivers/net/benet/be_ethtool.c
+++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c
@@ -26,33 +26,18 @@ struct be_ethtool_stat {
int offset;
};
-enum {NETSTAT, DRVSTAT_TX, DRVSTAT_RX, ERXSTAT,
- DRVSTAT};
+enum {DRVSTAT_TX, DRVSTAT_RX, DRVSTAT};
#define FIELDINFO(_struct, field) FIELD_SIZEOF(_struct, field), \
offsetof(_struct, field)
-#define NETSTAT_INFO(field) #field, NETSTAT,\
- FIELDINFO(struct net_device_stats,\
- field)
#define DRVSTAT_TX_INFO(field) #field, DRVSTAT_TX,\
FIELDINFO(struct be_tx_stats, field)
#define DRVSTAT_RX_INFO(field) #field, DRVSTAT_RX,\
FIELDINFO(struct be_rx_stats, field)
-#define ERXSTAT_INFO(field) #field, ERXSTAT,\
- FIELDINFO(struct be_erx_stats_v1, field)
#define DRVSTAT_INFO(field) #field, DRVSTAT,\
- FIELDINFO(struct be_drv_stats, \
- field)
+ FIELDINFO(struct be_drv_stats, field)
static const struct be_ethtool_stat et_stats[] = {
- {NETSTAT_INFO(rx_packets)},
- {NETSTAT_INFO(tx_packets)},
- {NETSTAT_INFO(rx_bytes)},
- {NETSTAT_INFO(tx_bytes)},
- {NETSTAT_INFO(rx_errors)},
- {NETSTAT_INFO(tx_errors)},
- {NETSTAT_INFO(rx_dropped)},
- {NETSTAT_INFO(tx_dropped)},
- {DRVSTAT_INFO(be_tx_events)},
+ {DRVSTAT_INFO(tx_events)},
{DRVSTAT_INFO(rx_crc_errors)},
{DRVSTAT_INFO(rx_alignment_symbol_errors)},
{DRVSTAT_INFO(rx_pause_frames)},
@@ -71,9 +56,6 @@ static const struct be_ethtool_stat et_stats[] = {
{DRVSTAT_INFO(rx_ip_checksum_errs)},
{DRVSTAT_INFO(rx_tcp_checksum_errs)},
{DRVSTAT_INFO(rx_udp_checksum_errs)},
- {DRVSTAT_INFO(rx_switched_unicast_packets)},
- {DRVSTAT_INFO(rx_switched_multicast_packets)},
- {DRVSTAT_INFO(rx_switched_broadcast_packets)},
{DRVSTAT_INFO(tx_pauseframes)},
{DRVSTAT_INFO(tx_controlframes)},
{DRVSTAT_INFO(rx_priority_pause_frames)},
@@ -92,28 +74,33 @@ static const struct be_ethtool_stat et_stats[] = {
};
#define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats)
-/* Stats related to multi RX queues */
+/* Stats related to multi RX queues: get_stats routine assumes bytes, pkts
+ * are first and second members respectively.
+ */
static const struct be_ethtool_stat et_rx_stats[] = {
- {DRVSTAT_RX_INFO(rx_bytes)},
- {DRVSTAT_RX_INFO(rx_pkts)},
- {DRVSTAT_RX_INFO(rx_rate)},
+ {DRVSTAT_RX_INFO(rx_bytes)},/* If moving this member see above note */
+ {DRVSTAT_RX_INFO(rx_pkts)}, /* If moving this member see above note */
{DRVSTAT_RX_INFO(rx_polls)},
{DRVSTAT_RX_INFO(rx_events)},
{DRVSTAT_RX_INFO(rx_compl)},
{DRVSTAT_RX_INFO(rx_mcast_pkts)},
{DRVSTAT_RX_INFO(rx_post_fail)},
- {DRVSTAT_RX_INFO(rx_dropped)},
- {ERXSTAT_INFO(rx_drops_no_fragments)}
+ {DRVSTAT_RX_INFO(rx_drops_no_skbs)},
+ {DRVSTAT_RX_INFO(rx_drops_no_frags)}
};
#define ETHTOOL_RXSTATS_NUM (ARRAY_SIZE(et_rx_stats))
-/* Stats related to multi TX queues */
+/* Stats related to multi TX queues: get_stats routine assumes compl is the
+ * first member
+ */
static const struct be_ethtool_stat et_tx_stats[] = {
- {DRVSTAT_TX_INFO(be_tx_rate)},
- {DRVSTAT_TX_INFO(be_tx_reqs)},
- {DRVSTAT_TX_INFO(be_tx_wrbs)},
- {DRVSTAT_TX_INFO(be_tx_stops)},
- {DRVSTAT_TX_INFO(be_tx_compl)}
+ {DRVSTAT_TX_INFO(tx_compl)}, /* If moving this member see above note */
+ {DRVSTAT_TX_INFO(tx_bytes)},
+ {DRVSTAT_TX_INFO(tx_pkts)},
+ {DRVSTAT_TX_INFO(tx_reqs)},
+ {DRVSTAT_TX_INFO(tx_wrbs)},
+ {DRVSTAT_TX_INFO(tx_compl)},
+ {DRVSTAT_TX_INFO(tx_stops)}
};
#define ETHTOOL_TXSTATS_NUM (ARRAY_SIZE(et_tx_stats))
@@ -131,14 +118,24 @@ static const char et_self_tests[][ETH_GSTRING_LEN] = {
#define BE_ONE_PORT_EXT_LOOPBACK 0x2
#define BE_NO_LOOPBACK 0xff
-static void
-be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
+static void be_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *drvinfo)
{
struct be_adapter *adapter = netdev_priv(netdev);
+ char fw_on_flash[FW_VER_LEN];
+
+ memset(fw_on_flash, 0 , sizeof(fw_on_flash));
+ be_cmd_get_fw_ver(adapter, adapter->fw_ver, fw_on_flash);
strcpy(drvinfo->driver, DRV_NAME);
strcpy(drvinfo->version, DRV_VER);
strncpy(drvinfo->fw_version, adapter->fw_ver, FW_VER_LEN);
+ if (memcmp(adapter->fw_ver, fw_on_flash, FW_VER_LEN) != 0) {
+ strcat(drvinfo->fw_version, " [");
+ strcat(drvinfo->fw_version, fw_on_flash);
+ strcat(drvinfo->fw_version, "]");
+ }
+
strcpy(drvinfo->bus_info, pci_name(adapter->pdev));
drvinfo->testinfo_len = 0;
drvinfo->regdump_len = 0;
@@ -260,50 +257,49 @@ be_get_ethtool_stats(struct net_device *netdev,
struct be_adapter *adapter = netdev_priv(netdev);
struct be_rx_obj *rxo;
struct be_tx_obj *txo;
- void *p = NULL;
- int i, j, base;
+ void *p;
+ unsigned int i, j, base = 0, start;
for (i = 0; i < ETHTOOL_STATS_NUM; i++) {
- switch (et_stats[i].type) {
- case NETSTAT:
- p = &netdev->stats;
- break;
- case DRVSTAT:
- p = &adapter->drv_stats;
- break;
- }
-
- p = (u8 *)p + et_stats[i].offset;
- data[i] = (et_stats[i].size == sizeof(u64)) ?
- *(u64 *)p: *(u32 *)p;
+ p = (u8 *)&adapter->drv_stats + et_stats[i].offset;
+ data[i] = *(u32 *)p;
}
+ base += ETHTOOL_STATS_NUM;
- base = ETHTOOL_STATS_NUM;
for_all_rx_queues(adapter, rxo, j) {
- for (i = 0; i < ETHTOOL_RXSTATS_NUM; i++) {
- switch (et_rx_stats[i].type) {
- case DRVSTAT_RX:
- p = (u8 *)&rxo->stats + et_rx_stats[i].offset;
- break;
- case ERXSTAT:
- p = (u32 *)be_erx_stats_from_cmd(adapter) +
- rxo->q.id;
- break;
- }
- data[base + j * ETHTOOL_RXSTATS_NUM + i] =
- (et_rx_stats[i].size == sizeof(u64)) ?
- *(u64 *)p: *(u32 *)p;
+ struct be_rx_stats *stats = rx_stats(rxo);
+
+ do {
+ start = u64_stats_fetch_begin_bh(&stats->sync);
+ data[base] = stats->rx_bytes;
+ data[base + 1] = stats->rx_pkts;
+ } while (u64_stats_fetch_retry_bh(&stats->sync, start));
+
+ for (i = 2; i < ETHTOOL_RXSTATS_NUM; i++) {
+ p = (u8 *)stats + et_rx_stats[i].offset;
+ data[base + i] = *(u32 *)p;
}
+ base += ETHTOOL_RXSTATS_NUM;
}
- base = ETHTOOL_STATS_NUM + adapter->num_rx_qs * ETHTOOL_RXSTATS_NUM;
for_all_tx_queues(adapter, txo, j) {
- for (i = 0; i < ETHTOOL_TXSTATS_NUM; i++) {
- p = (u8 *)&txo->stats + et_tx_stats[i].offset;
- data[base + j * ETHTOOL_TXSTATS_NUM + i] =
- (et_tx_stats[i].size == sizeof(u64)) ?
- *(u64 *)p: *(u32 *)p;
- }
+ struct be_tx_stats *stats = tx_stats(txo);
+
+ do {
+ start = u64_stats_fetch_begin_bh(&stats->sync_compl);
+ data[base] = stats->tx_compl;
+ } while (u64_stats_fetch_retry_bh(&stats->sync_compl, start));
+
+ do {
+ start = u64_stats_fetch_begin_bh(&stats->sync);
+ for (i = 1; i < ETHTOOL_TXSTATS_NUM; i++) {
+ p = (u8 *)stats + et_tx_stats[i].offset;
+ data[base + i] =
+ (et_tx_stats[i].size == sizeof(u64)) ?
+ *(u64 *)p : *(u32 *)p;
+ }
+ } while (u64_stats_fetch_retry_bh(&stats->sync, start));
+ base += ETHTOOL_TXSTATS_NUM;
}
}
@@ -363,19 +359,15 @@ static int be_get_sset_count(struct net_device *netdev, int stringset)
static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
{
struct be_adapter *adapter = netdev_priv(netdev);
- struct be_dma_mem phy_cmd;
- struct be_cmd_resp_get_phy_info *resp;
+ struct be_phy_info phy_info;
u8 mac_speed = 0;
u16 link_speed = 0;
- bool link_up = false;
int status;
- u16 intf_type;
if ((adapter->link_speed < 0) || (!(netdev->flags & IFF_UP))) {
- status = be_cmd_link_status_query(adapter, &link_up,
- &mac_speed, &link_speed, 0);
+ status = be_cmd_link_status_query(adapter, &mac_speed,
+ &link_speed, 0);
- be_link_status_update(adapter, link_up);
/* link_speed is in units of 10 Mbps */
if (link_speed) {
ethtool_cmd_speed_set(ecmd, link_speed*10);
@@ -399,20 +391,9 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
}
}
- phy_cmd.size = sizeof(struct be_cmd_req_get_phy_info);
- phy_cmd.va = dma_alloc_coherent(&adapter->pdev->dev,
- phy_cmd.size, &phy_cmd.dma,
- GFP_KERNEL);
- if (!phy_cmd.va) {
- dev_err(&adapter->pdev->dev, "Memory alloc failure\n");
- return -ENOMEM;
- }
- status = be_cmd_get_phy_info(adapter, &phy_cmd);
+ status = be_cmd_get_phy_info(adapter, &phy_info);
if (!status) {
- resp = phy_cmd.va;
- intf_type = le16_to_cpu(resp->interface_type);
-
- switch (intf_type) {
+ switch (phy_info.interface_type) {
case PHY_TYPE_XFP_10GB:
case PHY_TYPE_SFP_1GB:
case PHY_TYPE_SFP_PLUS_10GB:
@@ -423,7 +404,7 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
break;
}
- switch (intf_type) {
+ switch (phy_info.interface_type) {
case PHY_TYPE_KR_10GB:
case PHY_TYPE_KX4_10GB:
ecmd->autoneg = AUTONEG_ENABLE;
@@ -441,8 +422,6 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
adapter->port_type = ecmd->port;
adapter->transceiver = ecmd->transceiver;
adapter->autoneg = ecmd->autoneg;
- dma_free_coherent(&adapter->pdev->dev, phy_cmd.size, phy_cmd.va,
- phy_cmd.dma);
} else {
ethtool_cmd_speed_set(ecmd, adapter->link_speed);
ecmd->port = adapter->port_type;
@@ -631,7 +610,6 @@ static void
be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data)
{
struct be_adapter *adapter = netdev_priv(netdev);
- bool link_up;
u8 mac_speed = 0;
u16 qos_link_speed = 0;
@@ -657,7 +635,7 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data)
test->flags |= ETH_TEST_FL_FAILED;
}
- if (be_cmd_link_status_query(adapter, &link_up, &mac_speed,
+ if (be_cmd_link_status_query(adapter, &mac_speed,
&qos_link_speed, 0) != 0) {
test->flags |= ETH_TEST_FL_FAILED;
data[4] = -1;
diff --git a/drivers/net/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h
index 53d658afea2a..fbc8a915519e 100644
--- a/drivers/net/benet/be_hw.h
+++ b/drivers/net/ethernet/emulex/benet/be_hw.h
@@ -175,18 +175,24 @@
#define IMG_TYPE_FCOE_FW_ACTIVE 10
#define IMG_TYPE_FCOE_FW_BACKUP 11
#define IMG_TYPE_NCSI_FW 13
+#define IMG_TYPE_PHY_FW 99
+#define TN_8022 13
+#define ILLEGAL_IOCTL_REQ 2
+#define FLASHROM_OPER_PHY_FLASH 9
+#define FLASHROM_OPER_PHY_SAVE 10
#define FLASHROM_OPER_FLASH 1
#define FLASHROM_OPER_SAVE 2
#define FLASHROM_OPER_REPORT 4
-#define FLASH_IMAGE_MAX_SIZE_g2 (1310720) /* Max firmware image sz */
-#define FLASH_BIOS_IMAGE_MAX_SIZE_g2 (262144) /* Max OPTION ROM img sz */
-#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g2 (262144) /* Max Redboot image sz */
-#define FLASH_IMAGE_MAX_SIZE_g3 (2097152) /* Max fw image size */
-#define FLASH_BIOS_IMAGE_MAX_SIZE_g3 (524288) /* Max OPTION ROM img sz */
-#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g3 (1048576) /* Max Redboot image sz */
-#define FLASH_NCSI_IMAGE_MAX_SIZE_g3 (262144) /* Max NSCI image sz */
+#define FLASH_IMAGE_MAX_SIZE_g2 (1310720) /* Max firmware image size */
+#define FLASH_BIOS_IMAGE_MAX_SIZE_g2 (262144) /* Max OPTION ROM image sz */
+#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g2 (262144) /* Max Redboot image sz */
+#define FLASH_IMAGE_MAX_SIZE_g3 (2097152) /* Max firmware image size */
+#define FLASH_BIOS_IMAGE_MAX_SIZE_g3 (524288) /* Max OPTION ROM image sz */
+#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g3 (1048576) /* Max Redboot image sz */
+#define FLASH_NCSI_IMAGE_MAX_SIZE_g3 (262144)
+#define FLASH_PHY_FW_IMAGE_MAX_SIZE_g3 262144
#define FLASH_NCSI_MAGIC (0x16032009)
#define FLASH_NCSI_DISABLED (0)
@@ -213,6 +219,7 @@
#define FLASH_PXE_BIOS_START_g3 (13107200)
#define FLASH_FCoE_BIOS_START_g3 (13631488)
#define FLASH_REDBOOT_START_g3 (262144)
+#define FLASH_PHY_FW_START_g3 1310720
/************* Rx Packet Type Encoding **************/
#define BE_UNICAST_PACKET 0
diff --git a/drivers/net/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index c411bb1845fd..d6a232a300ad 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -114,6 +114,13 @@ static const char * const ue_status_hi_desc[] = {
"Unknown"
};
+/* Is BE in a multi-channel mode */
+static inline bool be_is_mc(struct be_adapter *adapter) {
+ return (adapter->function_mode & FLEX10_MODE ||
+ adapter->function_mode & VNIC_MODE ||
+ adapter->function_mode & UMC_ENABLED);
+}
+
static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q)
{
struct be_dma_mem *mem = &q->dma_mem;
@@ -141,13 +148,15 @@ static int be_queue_alloc(struct be_adapter *adapter, struct be_queue_info *q,
static void be_intr_set(struct be_adapter *adapter, bool enable)
{
- u8 __iomem *addr = adapter->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET;
- u32 reg = ioread32(addr);
- u32 enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
+ u32 reg, enabled;
if (adapter->eeh_err)
return;
+ pci_read_config_dword(adapter->pdev, PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET,
+ &reg);
+ enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
+
if (!enabled && enable)
reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
else if (enabled && !enable)
@@ -155,7 +164,8 @@ static void be_intr_set(struct be_adapter *adapter, bool enable)
else
return;
- iowrite32(reg, addr);
+ pci_write_config_dword(adapter->pdev,
+ PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET, reg);
}
static void be_rxq_notify(struct be_adapter *adapter, u16 qid, u16 posted)
@@ -245,14 +255,14 @@ netdev_addr:
static void populate_be2_stats(struct be_adapter *adapter)
{
-
- struct be_drv_stats *drvs = &adapter->drv_stats;
- struct be_pmem_stats *pmem_sts = be_pmem_stats_from_cmd(adapter);
+ struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter);
+ struct be_pmem_stats *pmem_sts = &hw_stats->pmem;
+ struct be_rxf_stats_v0 *rxf_stats = &hw_stats->rxf;
struct be_port_rxf_stats_v0 *port_stats =
- be_port_rxf_stats_from_cmd(adapter);
- struct be_rxf_stats_v0 *rxf_stats =
- be_rxf_stats_from_cmd(adapter);
+ &rxf_stats->port[adapter->port_num];
+ struct be_drv_stats *drvs = &adapter->drv_stats;
+ be_dws_le_to_cpu(hw_stats, sizeof(*hw_stats));
drvs->rx_pause_frames = port_stats->rx_pause_frames;
drvs->rx_crc_errors = port_stats->rx_crc_errors;
drvs->rx_control_frames = port_stats->rx_control_frames;
@@ -267,12 +277,10 @@ static void populate_be2_stats(struct be_adapter *adapter)
drvs->rx_dropped_too_small = port_stats->rx_dropped_too_small;
drvs->rx_dropped_too_short = port_stats->rx_dropped_too_short;
drvs->rx_out_range_errors = port_stats->rx_out_range_errors;
- drvs->rx_input_fifo_overflow_drop =
- port_stats->rx_input_fifo_overflow;
+ drvs->rx_input_fifo_overflow_drop = port_stats->rx_input_fifo_overflow;
drvs->rx_dropped_header_too_small =
port_stats->rx_dropped_header_too_small;
- drvs->rx_address_match_errors =
- port_stats->rx_address_match_errors;
+ drvs->rx_address_match_errors = port_stats->rx_address_match_errors;
drvs->rx_alignment_symbol_errors =
port_stats->rx_alignment_symbol_errors;
@@ -280,36 +288,30 @@ static void populate_be2_stats(struct be_adapter *adapter)
drvs->tx_controlframes = port_stats->tx_controlframes;
if (adapter->port_num)
- drvs->jabber_events =
- rxf_stats->port1_jabber_events;
+ drvs->jabber_events = rxf_stats->port1_jabber_events;
else
- drvs->jabber_events =
- rxf_stats->port0_jabber_events;
+ drvs->jabber_events = rxf_stats->port0_jabber_events;
drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf;
drvs->rx_drops_no_txpb = rxf_stats->rx_drops_no_txpb;
drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr;
drvs->rx_drops_invalid_ring = rxf_stats->rx_drops_invalid_ring;
drvs->forwarded_packets = rxf_stats->forwarded_packets;
drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu;
- drvs->rx_drops_no_tpre_descr =
- rxf_stats->rx_drops_no_tpre_descr;
- drvs->rx_drops_too_many_frags =
- rxf_stats->rx_drops_too_many_frags;
+ drvs->rx_drops_no_tpre_descr = rxf_stats->rx_drops_no_tpre_descr;
+ drvs->rx_drops_too_many_frags = rxf_stats->rx_drops_too_many_frags;
adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops;
}
static void populate_be3_stats(struct be_adapter *adapter)
{
- struct be_drv_stats *drvs = &adapter->drv_stats;
- struct be_pmem_stats *pmem_sts = be_pmem_stats_from_cmd(adapter);
-
- struct be_rxf_stats_v1 *rxf_stats =
- be_rxf_stats_from_cmd(adapter);
+ struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter);
+ struct be_pmem_stats *pmem_sts = &hw_stats->pmem;
+ struct be_rxf_stats_v1 *rxf_stats = &hw_stats->rxf;
struct be_port_rxf_stats_v1 *port_stats =
- be_port_rxf_stats_from_cmd(adapter);
+ &rxf_stats->port[adapter->port_num];
+ struct be_drv_stats *drvs = &adapter->drv_stats;
- drvs->rx_priority_pause_frames = 0;
- drvs->pmem_fifo_overflow_drop = 0;
+ be_dws_le_to_cpu(hw_stats, sizeof(*hw_stats));
drvs->rx_pause_frames = port_stats->rx_pause_frames;
drvs->rx_crc_errors = port_stats->rx_crc_errors;
drvs->rx_control_frames = port_stats->rx_control_frames;
@@ -327,12 +329,10 @@ static void populate_be3_stats(struct be_adapter *adapter)
port_stats->rx_dropped_header_too_small;
drvs->rx_input_fifo_overflow_drop =
port_stats->rx_input_fifo_overflow_drop;
- drvs->rx_address_match_errors =
- port_stats->rx_address_match_errors;
+ drvs->rx_address_match_errors = port_stats->rx_address_match_errors;
drvs->rx_alignment_symbol_errors =
port_stats->rx_alignment_symbol_errors;
- drvs->rxpp_fifo_overflow_drop =
- port_stats->rxpp_fifo_overflow_drop;
+ drvs->rxpp_fifo_overflow_drop = port_stats->rxpp_fifo_overflow_drop;
drvs->tx_pauseframes = port_stats->tx_pauseframes;
drvs->tx_controlframes = port_stats->tx_controlframes;
drvs->jabber_events = port_stats->jabber_events;
@@ -342,10 +342,8 @@ static void populate_be3_stats(struct be_adapter *adapter)
drvs->rx_drops_invalid_ring = rxf_stats->rx_drops_invalid_ring;
drvs->forwarded_packets = rxf_stats->forwarded_packets;
drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu;
- drvs->rx_drops_no_tpre_descr =
- rxf_stats->rx_drops_no_tpre_descr;
- drvs->rx_drops_too_many_frags =
- rxf_stats->rx_drops_too_many_frags;
+ drvs->rx_drops_no_tpre_descr = rxf_stats->rx_drops_no_tpre_descr;
+ drvs->rx_drops_too_many_frags = rxf_stats->rx_drops_too_many_frags;
adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops;
}
@@ -353,22 +351,15 @@ static void populate_lancer_stats(struct be_adapter *adapter)
{
struct be_drv_stats *drvs = &adapter->drv_stats;
- struct lancer_cmd_pport_stats *pport_stats = pport_stats_from_cmd
- (adapter);
- drvs->rx_priority_pause_frames = 0;
- drvs->pmem_fifo_overflow_drop = 0;
- drvs->rx_pause_frames =
- make_64bit_val(pport_stats->rx_pause_frames_hi,
- pport_stats->rx_pause_frames_lo);
- drvs->rx_crc_errors = make_64bit_val(pport_stats->rx_crc_errors_hi,
- pport_stats->rx_crc_errors_lo);
- drvs->rx_control_frames =
- make_64bit_val(pport_stats->rx_control_frames_hi,
- pport_stats->rx_control_frames_lo);
+ struct lancer_pport_stats *pport_stats =
+ pport_stats_from_cmd(adapter);
+
+ be_dws_le_to_cpu(pport_stats, sizeof(*pport_stats));
+ drvs->rx_pause_frames = pport_stats->rx_pause_frames_lo;
+ drvs->rx_crc_errors = pport_stats->rx_crc_errors_lo;
+ drvs->rx_control_frames = pport_stats->rx_control_frames_lo;
drvs->rx_in_range_errors = pport_stats->rx_in_range_errors;
- drvs->rx_frame_too_long =
- make_64bit_val(pport_stats->rx_internal_mac_errors_hi,
- pport_stats->rx_frames_too_long_lo);
+ drvs->rx_frame_too_long = pport_stats->rx_frames_too_long_lo;
drvs->rx_dropped_runt = pport_stats->rx_dropped_runt;
drvs->rx_ip_checksum_errs = pport_stats->rx_ip_checksum_errors;
drvs->rx_tcp_checksum_errs = pport_stats->rx_tcp_checksum_errors;
@@ -382,32 +373,36 @@ static void populate_lancer_stats(struct be_adapter *adapter)
pport_stats->rx_dropped_header_too_small;
drvs->rx_input_fifo_overflow_drop = pport_stats->rx_fifo_overflow;
drvs->rx_address_match_errors = pport_stats->rx_address_match_errors;
- drvs->rx_alignment_symbol_errors =
- make_64bit_val(pport_stats->rx_symbol_errors_hi,
- pport_stats->rx_symbol_errors_lo);
+ drvs->rx_alignment_symbol_errors = pport_stats->rx_symbol_errors_lo;
drvs->rxpp_fifo_overflow_drop = pport_stats->rx_fifo_overflow;
- drvs->tx_pauseframes = make_64bit_val(pport_stats->tx_pause_frames_hi,
- pport_stats->tx_pause_frames_lo);
- drvs->tx_controlframes =
- make_64bit_val(pport_stats->tx_control_frames_hi,
- pport_stats->tx_control_frames_lo);
+ drvs->tx_pauseframes = pport_stats->tx_pause_frames_lo;
+ drvs->tx_controlframes = pport_stats->tx_control_frames_lo;
drvs->jabber_events = pport_stats->rx_jabbers;
- drvs->rx_drops_no_pbuf = 0;
- drvs->rx_drops_no_txpb = 0;
- drvs->rx_drops_no_erx_descr = 0;
drvs->rx_drops_invalid_ring = pport_stats->rx_drops_invalid_queue;
- drvs->forwarded_packets = make_64bit_val(pport_stats->num_forwards_hi,
- pport_stats->num_forwards_lo);
- drvs->rx_drops_mtu = make_64bit_val(pport_stats->rx_drops_mtu_hi,
- pport_stats->rx_drops_mtu_lo);
- drvs->rx_drops_no_tpre_descr = 0;
+ drvs->forwarded_packets = pport_stats->num_forwards_lo;
+ drvs->rx_drops_mtu = pport_stats->rx_drops_mtu_lo;
drvs->rx_drops_too_many_frags =
- make_64bit_val(pport_stats->rx_drops_too_many_frags_hi,
- pport_stats->rx_drops_too_many_frags_lo);
+ pport_stats->rx_drops_too_many_frags_lo;
+}
+
+static void accumulate_16bit_val(u32 *acc, u16 val)
+{
+#define lo(x) (x & 0xFFFF)
+#define hi(x) (x & 0xFFFF0000)
+ bool wrapped = val < lo(*acc);
+ u32 newacc = hi(*acc) + val;
+
+ if (wrapped)
+ newacc += 65536;
+ ACCESS_ONCE(*acc) = newacc;
}
void be_parse_stats(struct be_adapter *adapter)
{
+ struct be_erx_stats_v1 *erx = be_erx_stats_from_cmd(adapter);
+ struct be_rx_obj *rxo;
+ int i;
+
if (adapter->generation == BE_GEN3) {
if (lancer_chip(adapter))
populate_lancer_stats(adapter);
@@ -416,50 +411,55 @@ void be_parse_stats(struct be_adapter *adapter)
} else {
populate_be2_stats(adapter);
}
+
+ /* as erx_v1 is longer than v0, ok to use v1 defn for v0 access */
+ for_all_rx_queues(adapter, rxo, i) {
+ /* below erx HW counter can actually wrap around after
+ * 65535. Driver accumulates a 32-bit value
+ */
+ accumulate_16bit_val(&rx_stats(rxo)->rx_drops_no_frags,
+ (u16)erx->rx_drops_no_fragments[rxo->q.id]);
+ }
}
-void netdev_stats_update(struct be_adapter *adapter)
+static struct rtnl_link_stats64 *be_get_stats64(struct net_device *netdev,
+ struct rtnl_link_stats64 *stats)
{
+ struct be_adapter *adapter = netdev_priv(netdev);
struct be_drv_stats *drvs = &adapter->drv_stats;
- struct net_device_stats *dev_stats = &adapter->netdev->stats;
struct be_rx_obj *rxo;
struct be_tx_obj *txo;
- unsigned long pkts = 0, bytes = 0, mcast = 0, drops = 0;
+ u64 pkts, bytes;
+ unsigned int start;
int i;
for_all_rx_queues(adapter, rxo, i) {
- pkts += rx_stats(rxo)->rx_pkts;
- bytes += rx_stats(rxo)->rx_bytes;
- mcast += rx_stats(rxo)->rx_mcast_pkts;
- drops += rx_stats(rxo)->rx_dropped;
- /* no space in linux buffers: best possible approximation */
- if (adapter->generation == BE_GEN3) {
- if (!(lancer_chip(adapter))) {
- struct be_erx_stats_v1 *erx =
- be_erx_stats_from_cmd(adapter);
- drops += erx->rx_drops_no_fragments[rxo->q.id];
- }
- } else {
- struct be_erx_stats_v0 *erx =
- be_erx_stats_from_cmd(adapter);
- drops += erx->rx_drops_no_fragments[rxo->q.id];
- }
+ const struct be_rx_stats *rx_stats = rx_stats(rxo);
+ do {
+ start = u64_stats_fetch_begin_bh(&rx_stats->sync);
+ pkts = rx_stats(rxo)->rx_pkts;
+ bytes = rx_stats(rxo)->rx_bytes;
+ } while (u64_stats_fetch_retry_bh(&rx_stats->sync, start));
+ stats->rx_packets += pkts;
+ stats->rx_bytes += bytes;
+ stats->multicast += rx_stats(rxo)->rx_mcast_pkts;
+ stats->rx_dropped += rx_stats(rxo)->rx_drops_no_skbs +
+ rx_stats(rxo)->rx_drops_no_frags;
}
- dev_stats->rx_packets = pkts;
- dev_stats->rx_bytes = bytes;
- dev_stats->multicast = mcast;
- dev_stats->rx_dropped = drops;
- pkts = bytes = 0;
for_all_tx_queues(adapter, txo, i) {
- pkts += tx_stats(txo)->be_tx_pkts;
- bytes += tx_stats(txo)->be_tx_bytes;
+ const struct be_tx_stats *tx_stats = tx_stats(txo);
+ do {
+ start = u64_stats_fetch_begin_bh(&tx_stats->sync);
+ pkts = tx_stats(txo)->tx_pkts;
+ bytes = tx_stats(txo)->tx_bytes;
+ } while (u64_stats_fetch_retry_bh(&tx_stats->sync, start));
+ stats->tx_packets += pkts;
+ stats->tx_bytes += bytes;
}
- dev_stats->tx_packets = pkts;
- dev_stats->tx_bytes = bytes;
/* bad pkts received */
- dev_stats->rx_errors = drvs->rx_crc_errors +
+ stats->rx_errors = drvs->rx_crc_errors +
drvs->rx_alignment_symbol_errors +
drvs->rx_in_range_errors +
drvs->rx_out_range_errors +
@@ -468,115 +468,38 @@ void netdev_stats_update(struct be_adapter *adapter)
drvs->rx_dropped_too_short +
drvs->rx_dropped_header_too_small +
drvs->rx_dropped_tcp_length +
- drvs->rx_dropped_runt +
- drvs->rx_tcp_checksum_errs +
- drvs->rx_ip_checksum_errs +
- drvs->rx_udp_checksum_errs;
+ drvs->rx_dropped_runt;
/* detailed rx errors */
- dev_stats->rx_length_errors = drvs->rx_in_range_errors +
+ stats->rx_length_errors = drvs->rx_in_range_errors +
drvs->rx_out_range_errors +
drvs->rx_frame_too_long;
- dev_stats->rx_crc_errors = drvs->rx_crc_errors;
+ stats->rx_crc_errors = drvs->rx_crc_errors;
/* frame alignment errors */
- dev_stats->rx_frame_errors = drvs->rx_alignment_symbol_errors;
+ stats->rx_frame_errors = drvs->rx_alignment_symbol_errors;
/* receiver fifo overrun */
/* drops_no_pbuf is no per i/f, it's per BE card */
- dev_stats->rx_fifo_errors = drvs->rxpp_fifo_overflow_drop +
+ stats->rx_fifo_errors = drvs->rxpp_fifo_overflow_drop +
drvs->rx_input_fifo_overflow_drop +
drvs->rx_drops_no_pbuf;
+ return stats;
}
-void be_link_status_update(struct be_adapter *adapter, bool link_up)
+void be_link_status_update(struct be_adapter *adapter, u32 link_status)
{
struct net_device *netdev = adapter->netdev;
- /* If link came up or went down */
- if (adapter->link_up != link_up) {
- adapter->link_speed = -1;
- if (link_up) {
- netif_carrier_on(netdev);
- printk(KERN_INFO "%s: Link up\n", netdev->name);
- } else {
- netif_carrier_off(netdev);
- printk(KERN_INFO "%s: Link down\n", netdev->name);
- }
- adapter->link_up = link_up;
- }
-}
-
-/* Update the EQ delay n BE based on the RX frags consumed / sec */
-static void be_rx_eqd_update(struct be_adapter *adapter, struct be_rx_obj *rxo)
-{
- struct be_eq_obj *rx_eq = &rxo->rx_eq;
- struct be_rx_stats *stats = &rxo->stats;
- ulong now = jiffies;
- u32 eqd;
-
- if (!rx_eq->enable_aic)
- return;
-
- /* Wrapped around */
- if (time_before(now, stats->rx_fps_jiffies)) {
- stats->rx_fps_jiffies = now;
- return;
- }
-
- /* Update once a second */
- if ((now - stats->rx_fps_jiffies) < HZ)
- return;
-
- stats->rx_fps = (stats->rx_frags - stats->prev_rx_frags) /
- ((now - stats->rx_fps_jiffies) / HZ);
-
- stats->rx_fps_jiffies = now;
- stats->prev_rx_frags = stats->rx_frags;
- eqd = stats->rx_fps / 110000;
- eqd = eqd << 3;
- if (eqd > rx_eq->max_eqd)
- eqd = rx_eq->max_eqd;
- if (eqd < rx_eq->min_eqd)
- eqd = rx_eq->min_eqd;
- if (eqd < 10)
- eqd = 0;
- if (eqd != rx_eq->cur_eqd)
- be_cmd_modify_eqd(adapter, rx_eq->q.id, eqd);
-
- rx_eq->cur_eqd = eqd;
-}
-
-static u32 be_calc_rate(u64 bytes, unsigned long ticks)
-{
- u64 rate = bytes;
-
- do_div(rate, ticks / HZ);
- rate <<= 3; /* bytes/sec -> bits/sec */
- do_div(rate, 1000000ul); /* MB/Sec */
-
- return rate;
-}
-
-static void be_tx_rate_update(struct be_tx_obj *txo)
-{
- struct be_tx_stats *stats = tx_stats(txo);
- ulong now = jiffies;
-
- /* Wrapped around? */
- if (time_before(now, stats->be_tx_jiffies)) {
- stats->be_tx_jiffies = now;
- return;
- }
-
- /* Update tx rate once in two seconds */
- if ((now - stats->be_tx_jiffies) > 2 * HZ) {
- stats->be_tx_rate = be_calc_rate(stats->be_tx_bytes
- - stats->be_tx_bytes_prev,
- now - stats->be_tx_jiffies);
- stats->be_tx_jiffies = now;
- stats->be_tx_bytes_prev = stats->be_tx_bytes;
+ /* when link status changes, link speed must be re-queried from card */
+ adapter->link_speed = -1;
+ if ((link_status & LINK_STATUS_MASK) == LINK_UP) {
+ netif_carrier_on(netdev);
+ dev_info(&adapter->pdev->dev, "%s: Link up\n", netdev->name);
+ } else {
+ netif_carrier_off(netdev);
+ dev_info(&adapter->pdev->dev, "%s: Link down\n", netdev->name);
}
}
@@ -585,12 +508,14 @@ static void be_tx_stats_update(struct be_tx_obj *txo,
{
struct be_tx_stats *stats = tx_stats(txo);
- stats->be_tx_reqs++;
- stats->be_tx_wrbs += wrb_cnt;
- stats->be_tx_bytes += copied;
- stats->be_tx_pkts += (gso_segs ? gso_segs : 1);
+ u64_stats_update_begin(&stats->sync);
+ stats->tx_reqs++;
+ stats->tx_wrbs += wrb_cnt;
+ stats->tx_bytes += copied;
+ stats->tx_pkts += (gso_segs ? gso_segs : 1);
if (stopped)
- stats->be_tx_stops++;
+ stats->tx_stops++;
+ u64_stats_update_end(&stats->sync);
}
/* Determine number of WRB entries needed to xmit data in an skb */
@@ -718,17 +643,17 @@ static int make_tx_wrbs(struct be_adapter *adapter, struct be_queue_info *txq,
}
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- struct skb_frag_struct *frag =
+ const struct skb_frag_struct *frag =
&skb_shinfo(skb)->frags[i];
- busaddr = dma_map_page(dev, frag->page, frag->page_offset,
- frag->size, DMA_TO_DEVICE);
+ busaddr = skb_frag_dma_map(dev, frag, 0,
+ skb_frag_size(frag), DMA_TO_DEVICE);
if (dma_mapping_error(dev, busaddr))
goto dma_err;
wrb = queue_head_node(txq);
- wrb_fill(wrb, busaddr, frag->size);
+ wrb_fill(wrb, busaddr, skb_frag_size(frag));
be_dws_cpu_to_le(wrb, sizeof(*wrb));
queue_head_inc(txq);
- copied += frag->size;
+ copied += skb_frag_size(frag);
}
if (dummy_wrb) {
@@ -829,6 +754,10 @@ static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num)
status = be_cmd_vlan_config(adapter, if_handle, vtag, 1, 1, 0);
}
+ /* No need to further configure vids if in promiscuous mode */
+ if (adapter->promiscuous)
+ return 0;
+
if (adapter->vlans_added <= adapter->max_vlans) {
/* Construct VLAN Table to give to HW */
for (i = 0; i < VLAN_N_VID; i++) {
@@ -874,12 +803,12 @@ static void be_vlan_rem_vid(struct net_device *netdev, u16 vid)
be_vid_config(adapter, false, 0);
}
-static void be_set_multicast_list(struct net_device *netdev)
+static void be_set_rx_mode(struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
if (netdev->flags & IFF_PROMISC) {
- be_cmd_promiscuous_config(adapter, true);
+ be_cmd_rx_filter(adapter, IFF_PROMISC, ON);
adapter->promiscuous = true;
goto done;
}
@@ -887,19 +816,20 @@ static void be_set_multicast_list(struct net_device *netdev)
/* BE was previously in promiscuous mode; disable it */
if (adapter->promiscuous) {
adapter->promiscuous = false;
- be_cmd_promiscuous_config(adapter, false);
+ be_cmd_rx_filter(adapter, IFF_PROMISC, OFF);
+
+ if (adapter->vlans_added)
+ be_vid_config(adapter, false, 0);
}
/* Enable multicast promisc if num configured exceeds what we support */
if (netdev->flags & IFF_ALLMULTI ||
- netdev_mc_count(netdev) > BE_MAX_MC) {
- be_cmd_multicast_set(adapter, adapter->if_handle, NULL,
- &adapter->mc_cmd_mem);
+ netdev_mc_count(netdev) > BE_MAX_MC) {
+ be_cmd_rx_filter(adapter, IFF_ALLMULTI, ON);
goto done;
}
- be_cmd_multicast_set(adapter, adapter->if_handle, netdev,
- &adapter->mc_cmd_mem);
+ be_cmd_rx_filter(adapter, IFF_MULTICAST, ON);
done:
return;
}
@@ -1005,10 +935,17 @@ static int be_set_vf_tx_rate(struct net_device *netdev,
return status;
}
-static void be_rx_rate_update(struct be_rx_obj *rxo)
+static void be_rx_eqd_update(struct be_adapter *adapter, struct be_rx_obj *rxo)
{
- struct be_rx_stats *stats = &rxo->stats;
+ struct be_eq_obj *rx_eq = &rxo->rx_eq;
+ struct be_rx_stats *stats = rx_stats(rxo);
ulong now = jiffies;
+ ulong delta = now - stats->rx_jiffies;
+ u64 pkts;
+ unsigned int start, eqd;
+
+ if (!rx_eq->enable_aic)
+ return;
/* Wrapped around */
if (time_before(now, stats->rx_jiffies)) {
@@ -1016,29 +953,46 @@ static void be_rx_rate_update(struct be_rx_obj *rxo)
return;
}
- /* Update the rate once in two seconds */
- if ((now - stats->rx_jiffies) < 2 * HZ)
+ /* Update once a second */
+ if (delta < HZ)
return;
- stats->rx_rate = be_calc_rate(stats->rx_bytes - stats->rx_bytes_prev,
- now - stats->rx_jiffies);
+ do {
+ start = u64_stats_fetch_begin_bh(&stats->sync);
+ pkts = stats->rx_pkts;
+ } while (u64_stats_fetch_retry_bh(&stats->sync, start));
+
+ stats->rx_pps = (unsigned long)(pkts - stats->rx_pkts_prev) / (delta / HZ);
+ stats->rx_pkts_prev = pkts;
stats->rx_jiffies = now;
- stats->rx_bytes_prev = stats->rx_bytes;
+ eqd = stats->rx_pps / 110000;
+ eqd = eqd << 3;
+ if (eqd > rx_eq->max_eqd)
+ eqd = rx_eq->max_eqd;
+ if (eqd < rx_eq->min_eqd)
+ eqd = rx_eq->min_eqd;
+ if (eqd < 10)
+ eqd = 0;
+ if (eqd != rx_eq->cur_eqd) {
+ be_cmd_modify_eqd(adapter, rx_eq->q.id, eqd);
+ rx_eq->cur_eqd = eqd;
+ }
}
static void be_rx_stats_update(struct be_rx_obj *rxo,
struct be_rx_compl_info *rxcp)
{
- struct be_rx_stats *stats = &rxo->stats;
+ struct be_rx_stats *stats = rx_stats(rxo);
+ u64_stats_update_begin(&stats->sync);
stats->rx_compl++;
- stats->rx_frags += rxcp->num_rcvd;
stats->rx_bytes += rxcp->pkt_size;
stats->rx_pkts++;
if (rxcp->pkt_type == BE_MULTICAST_PACKET)
stats->rx_mcast_pkts++;
if (rxcp->err)
- stats->rxcp_err++;
+ stats->rx_compl_err++;
+ u64_stats_update_end(&stats->sync);
}
static inline bool csum_passed(struct be_rx_compl_info *rxcp)
@@ -1119,11 +1073,12 @@ static void skb_fill_rx_data(struct be_adapter *adapter, struct be_rx_obj *rxo,
skb->tail += curr_frag_len;
} else {
skb_shinfo(skb)->nr_frags = 1;
- skb_shinfo(skb)->frags[0].page = page_info->page;
+ skb_frag_set_page(skb, 0, page_info->page);
skb_shinfo(skb)->frags[0].page_offset =
page_info->page_offset + hdr_len;
- skb_shinfo(skb)->frags[0].size = curr_frag_len - hdr_len;
+ skb_frag_size_set(&skb_shinfo(skb)->frags[0], curr_frag_len - hdr_len);
skb->data_len = curr_frag_len - hdr_len;
+ skb->truesize += rx_frag_size;
skb->tail += hdr_len;
}
page_info->page = NULL;
@@ -1144,19 +1099,19 @@ static void skb_fill_rx_data(struct be_adapter *adapter, struct be_rx_obj *rxo,
if (page_info->page_offset == 0) {
/* Fresh page */
j++;
- skb_shinfo(skb)->frags[j].page = page_info->page;
+ skb_frag_set_page(skb, j, page_info->page);
skb_shinfo(skb)->frags[j].page_offset =
page_info->page_offset;
- skb_shinfo(skb)->frags[j].size = 0;
+ skb_frag_size_set(&skb_shinfo(skb)->frags[j], 0);
skb_shinfo(skb)->nr_frags++;
} else {
put_page(page_info->page);
}
- skb_shinfo(skb)->frags[j].size += curr_frag_len;
+ skb_frag_size_add(&skb_shinfo(skb)->frags[j], curr_frag_len);
skb->len += curr_frag_len;
skb->data_len += curr_frag_len;
-
+ skb->truesize += rx_frag_size;
remaining -= curr_frag_len;
index_inc(&rxcp->rxq_idx, rxq->len);
page_info->page = NULL;
@@ -1174,7 +1129,7 @@ static void be_rx_compl_process(struct be_adapter *adapter,
skb = netdev_alloc_skb_ip_align(netdev, BE_HDR_LEN);
if (unlikely(!skb)) {
- rxo->stats.rx_dropped++;
+ rx_stats(rxo)->rx_drops_no_skbs++;
be_rx_compl_discard(adapter, rxo, rxcp);
return;
}
@@ -1186,13 +1141,12 @@ static void be_rx_compl_process(struct be_adapter *adapter,
else
skb_checksum_none_assert(skb);
- skb->truesize = skb->len + sizeof(struct sk_buff);
skb->protocol = eth_type_trans(skb, netdev);
if (adapter->netdev->features & NETIF_F_RXHASH)
skb->rxhash = rxcp->rss_hash;
- if (unlikely(rxcp->vlanf))
+ if (rxcp->vlanf)
__vlan_hwaccel_put_tag(skb, rxcp->vlan_tag);
netif_receive_skb(skb);
@@ -1226,15 +1180,15 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
if (i == 0 || page_info->page_offset == 0) {
/* First frag or Fresh page */
j++;
- skb_shinfo(skb)->frags[j].page = page_info->page;
+ skb_frag_set_page(skb, j, page_info->page);
skb_shinfo(skb)->frags[j].page_offset =
page_info->page_offset;
- skb_shinfo(skb)->frags[j].size = 0;
+ skb_frag_size_set(&skb_shinfo(skb)->frags[j], 0);
} else {
put_page(page_info->page);
}
- skb_shinfo(skb)->frags[j].size += curr_frag_len;
-
+ skb_frag_size_add(&skb_shinfo(skb)->frags[j], curr_frag_len);
+ skb->truesize += rx_frag_size;
remaining -= curr_frag_len;
index_inc(&rxcp->rxq_idx, rxq->len);
memset(page_info, 0, sizeof(*page_info));
@@ -1244,12 +1198,11 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
skb_shinfo(skb)->nr_frags = j + 1;
skb->len = rxcp->pkt_size;
skb->data_len = rxcp->pkt_size;
- skb->truesize += rxcp->pkt_size;
skb->ip_summed = CHECKSUM_UNNECESSARY;
if (adapter->netdev->features & NETIF_F_RXHASH)
skb->rxhash = rxcp->rss_hash;
- if (unlikely(rxcp->vlanf))
+ if (rxcp->vlanf)
__vlan_hwaccel_put_tag(skb, rxcp->vlan_tag);
napi_gro_frags(&eq_obj->napi);
@@ -1285,6 +1238,7 @@ static void be_parse_rx_compl_v1(struct be_adapter *adapter,
rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag,
compl);
}
+ rxcp->port = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, port, compl);
}
static void be_parse_rx_compl_v0(struct be_adapter *adapter,
@@ -1317,6 +1271,7 @@ static void be_parse_rx_compl_v0(struct be_adapter *adapter,
rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag,
compl);
}
+ rxcp->port = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, port, compl);
}
static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo)
@@ -1341,14 +1296,13 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo)
if (rxcp->vlanf) {
/* vlanf could be wrongly set in some cards.
* ignore if vtm is not set */
- if ((adapter->function_mode & 0x400) && !rxcp->vtm)
+ if ((adapter->function_mode & FLEX10_MODE) && !rxcp->vtm)
rxcp->vlanf = 0;
if (!lancer_chip(adapter))
rxcp->vlan_tag = swab16(rxcp->vlan_tag);
- if (((adapter->pvid & VLAN_VID_MASK) ==
- (rxcp->vlan_tag & VLAN_VID_MASK)) &&
+ if (adapter->pvid == (rxcp->vlan_tag & VLAN_VID_MASK) &&
!adapter->vlan_tag[rxcp->vlan_tag])
rxcp->vlanf = 0;
}
@@ -1389,7 +1343,7 @@ static void be_post_rx_frags(struct be_rx_obj *rxo, gfp_t gfp)
if (!pagep) {
pagep = be_alloc_pages(adapter->big_page_size, gfp);
if (unlikely(!pagep)) {
- rxo->stats.rx_post_fail++;
+ rx_stats(rxo)->rx_post_fail++;
break;
}
page_dmaaddr = dma_map_page(&adapter->pdev->dev, pagep,
@@ -1686,6 +1640,17 @@ static void be_tx_queues_destroy(struct be_adapter *adapter)
be_queue_free(adapter, q);
}
+static int be_num_txqs_want(struct be_adapter *adapter)
+{
+ if ((num_vfs && adapter->sriov_enabled) ||
+ be_is_mc(adapter) ||
+ lancer_chip(adapter) || !be_physfn(adapter) ||
+ adapter->generation == BE_GEN2)
+ return 1;
+ else
+ return MAX_TX_QS;
+}
+
/* One TX event queue is shared by all TX compl qs */
static int be_tx_queues_create(struct be_adapter *adapter)
{
@@ -1693,6 +1658,11 @@ static int be_tx_queues_create(struct be_adapter *adapter)
struct be_tx_obj *txo;
u8 i;
+ adapter->num_tx_qs = be_num_txqs_want(adapter);
+ if (adapter->num_tx_qs != MAX_TX_QS)
+ netif_set_real_num_tx_queues(adapter->netdev,
+ adapter->num_tx_qs);
+
adapter->tx_eq.max_eqd = 0;
adapter->tx_eq.min_eqd = 0;
adapter->tx_eq.cur_eqd = 96;
@@ -1755,7 +1725,8 @@ static void be_rx_queues_destroy(struct be_adapter *adapter)
static u32 be_num_rxqs_want(struct be_adapter *adapter)
{
if ((adapter->function_caps & BE_FUNCTION_CAPS_RSS) &&
- !adapter->sriov_enabled && !(adapter->function_mode & 0x400)) {
+ !adapter->sriov_enabled && be_physfn(adapter) &&
+ !be_is_mc(adapter)) {
return 1 + MAX_RSS_QS; /* one default non-RSS queue */
} else {
dev_warn(&adapter->pdev->dev,
@@ -1899,27 +1870,41 @@ static int be_poll_rx(struct napi_struct *napi, int budget)
struct be_rx_compl_info *rxcp;
u32 work_done;
- rxo->stats.rx_polls++;
+ rx_stats(rxo)->rx_polls++;
for (work_done = 0; work_done < budget; work_done++) {
rxcp = be_rx_compl_get(rxo);
if (!rxcp)
break;
- /* Ignore flush completions */
- if (rxcp->num_rcvd && rxcp->pkt_size) {
- if (do_gro(rxcp))
- be_rx_compl_process_gro(adapter, rxo, rxcp);
- else
- be_rx_compl_process(adapter, rxo, rxcp);
- } else if (rxcp->pkt_size == 0) {
+ /* Is it a flush compl that has no data */
+ if (unlikely(rxcp->num_rcvd == 0))
+ goto loop_continue;
+
+ /* Discard compl with partial DMA Lancer B0 */
+ if (unlikely(!rxcp->pkt_size)) {
be_rx_compl_discard(adapter, rxo, rxcp);
+ goto loop_continue;
}
+ /* On BE drop pkts that arrive due to imperfect filtering in
+ * promiscuous mode on some skews
+ */
+ if (unlikely(rxcp->port != adapter->port_num &&
+ !lancer_chip(adapter))) {
+ be_rx_compl_discard(adapter, rxo, rxcp);
+ goto loop_continue;
+ }
+
+ if (do_gro(rxcp))
+ be_rx_compl_process_gro(adapter, rxo, rxcp);
+ else
+ be_rx_compl_process(adapter, rxo, rxcp);
+loop_continue:
be_rx_stats_update(rxo, rxcp);
}
/* Refill the queue */
- if (atomic_read(&rxo->q.used) < RX_FRAGS_REFILL_WM)
+ if (work_done && atomic_read(&rxo->q.used) < RX_FRAGS_REFILL_WM)
be_post_rx_frags(rxo, GFP_ATOMIC);
/* All consumed */
@@ -1968,8 +1953,9 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
netif_wake_subqueue(adapter->netdev, i);
}
- adapter->drv_stats.be_tx_events++;
- txo->stats.be_tx_compl += tx_compl;
+ u64_stats_update_begin(&tx_stats(txo)->sync_compl);
+ tx_stats(txo)->tx_compl += tx_compl;
+ u64_stats_update_end(&tx_stats(txo)->sync_compl);
}
}
@@ -1983,6 +1969,7 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
napi_complete(napi);
be_eq_notify(adapter, tx_eq->q.id, true, false, 0);
+ adapter->drv_stats.tx_events++;
return 1;
}
@@ -2031,7 +2018,6 @@ static void be_worker(struct work_struct *work)
struct be_adapter *adapter =
container_of(work, struct be_adapter, work.work);
struct be_rx_obj *rxo;
- struct be_tx_obj *txo;
int i;
if (!adapter->ue_detected && !lancer_chip(adapter))
@@ -2060,11 +2046,7 @@ static void be_worker(struct work_struct *work)
be_cmd_get_stats(adapter, &adapter->stats_cmd);
}
- for_all_tx_queues(adapter, txo, i)
- be_tx_rate_update(txo);
-
for_all_rx_queues(adapter, rxo, i) {
- be_rx_rate_update(rxo);
be_rx_eqd_update(adapter, rxo);
if (rxo->rx_post_starved) {
@@ -2111,7 +2093,7 @@ done:
return;
}
-static void be_sriov_enable(struct be_adapter *adapter)
+static int be_sriov_enable(struct be_adapter *adapter)
{
be_check_sriov_fn_type(adapter);
#ifdef CONFIG_PCI_IOV
@@ -2133,8 +2115,17 @@ static void be_sriov_enable(struct be_adapter *adapter)
status = pci_enable_sriov(adapter->pdev, num_vfs);
adapter->sriov_enabled = status ? false : true;
+
+ if (adapter->sriov_enabled) {
+ adapter->vf_cfg = kcalloc(num_vfs,
+ sizeof(struct be_vf_cfg),
+ GFP_KERNEL);
+ if (!adapter->vf_cfg)
+ return -ENOMEM;
+ }
}
#endif
+ return 0;
}
static void be_sriov_disable(struct be_adapter *adapter)
@@ -2142,6 +2133,7 @@ static void be_sriov_disable(struct be_adapter *adapter)
#ifdef CONFIG_PCI_IOV
if (adapter->sriov_enabled) {
pci_disable_sriov(adapter->pdev);
+ kfree(adapter->vf_cfg);
adapter->sriov_enabled = false;
}
#endif
@@ -2294,9 +2286,6 @@ static int be_close(struct net_device *netdev)
be_async_mcc_disable(adapter);
- netif_carrier_off(netdev);
- adapter->link_up = false;
-
if (!lancer_chip(adapter))
be_intr_set(adapter, false);
@@ -2374,10 +2363,7 @@ static int be_open(struct net_device *netdev)
struct be_adapter *adapter = netdev_priv(netdev);
struct be_eq_obj *tx_eq = &adapter->tx_eq;
struct be_rx_obj *rxo;
- bool link_up;
int status, i;
- u8 mac_speed;
- u16 link_speed;
status = be_rx_queues_setup(adapter);
if (status)
@@ -2400,23 +2386,6 @@ static int be_open(struct net_device *netdev)
/* Now that interrupts are on we can process async mcc */
be_async_mcc_enable(adapter);
- status = be_cmd_link_status_query(adapter, &link_up, &mac_speed,
- &link_speed, 0);
- if (status)
- goto err;
- be_link_status_update(adapter, link_up);
-
- if (be_physfn(adapter)) {
- status = be_vid_config(adapter, false, 0);
- if (status)
- goto err;
-
- status = be_cmd_set_flow_control(adapter,
- adapter->tx_fc, adapter->rx_fc);
- if (status)
- goto err;
- }
-
return 0;
err:
be_close(adapter->netdev);
@@ -2470,7 +2439,7 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable)
*/
static inline int be_vf_eth_addr_config(struct be_adapter *adapter)
{
- u32 vf = 0;
+ u32 vf;
int status = 0;
u8 mac[ETH_ALEN];
@@ -2492,7 +2461,7 @@ static inline int be_vf_eth_addr_config(struct be_adapter *adapter)
return status;
}
-static inline void be_vf_eth_addr_rem(struct be_adapter *adapter)
+static void be_vf_clear(struct be_adapter *adapter)
{
u32 vf;
@@ -2502,132 +2471,159 @@ static inline void be_vf_eth_addr_rem(struct be_adapter *adapter)
adapter->vf_cfg[vf].vf_if_handle,
adapter->vf_cfg[vf].vf_pmac_id, vf + 1);
}
+
+ for (vf = 0; vf < num_vfs; vf++)
+ if (adapter->vf_cfg[vf].vf_if_handle)
+ be_cmd_if_destroy(adapter,
+ adapter->vf_cfg[vf].vf_if_handle, vf + 1);
}
-static int be_setup(struct be_adapter *adapter)
+static int be_clear(struct be_adapter *adapter)
{
- struct net_device *netdev = adapter->netdev;
- u32 cap_flags, en_flags, vf = 0;
- int status;
- u8 mac[ETH_ALEN];
+ if (be_physfn(adapter) && adapter->sriov_enabled)
+ be_vf_clear(adapter);
- be_cmd_req_native_mode(adapter);
+ be_cmd_if_destroy(adapter, adapter->if_handle, 0);
- cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED |
- BE_IF_FLAGS_BROADCAST |
- BE_IF_FLAGS_MULTICAST;
+ be_mcc_queues_destroy(adapter);
+ be_rx_queues_destroy(adapter);
+ be_tx_queues_destroy(adapter);
+ adapter->eq_next_idx = 0;
- if (be_physfn(adapter)) {
- cap_flags |= BE_IF_FLAGS_MCAST_PROMISCUOUS |
- BE_IF_FLAGS_PROMISCUOUS |
- BE_IF_FLAGS_PASS_L3L4_ERRORS;
- en_flags |= BE_IF_FLAGS_PASS_L3L4_ERRORS;
-
- if (adapter->function_caps & BE_FUNCTION_CAPS_RSS) {
- cap_flags |= BE_IF_FLAGS_RSS;
- en_flags |= BE_IF_FLAGS_RSS;
- }
- }
+ adapter->be3_native = false;
+ adapter->promiscuous = false;
- status = be_cmd_if_create(adapter, cap_flags, en_flags,
- netdev->dev_addr, false/* pmac_invalid */,
- &adapter->if_handle, &adapter->pmac_id, 0);
- if (status != 0)
- goto do_none;
+ /* tell fw we're done with firing cmds */
+ be_cmd_fw_clean(adapter);
+ return 0;
+}
- if (be_physfn(adapter)) {
- if (adapter->sriov_enabled) {
- while (vf < num_vfs) {
- cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED |
- BE_IF_FLAGS_BROADCAST;
- status = be_cmd_if_create(adapter, cap_flags,
- en_flags, mac, true,
+static int be_vf_setup(struct be_adapter *adapter)
+{
+ u32 cap_flags, en_flags, vf;
+ u16 lnk_speed;
+ int status;
+
+ cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST;
+ for (vf = 0; vf < num_vfs; vf++) {
+ status = be_cmd_if_create(adapter, cap_flags, en_flags, NULL,
&adapter->vf_cfg[vf].vf_if_handle,
NULL, vf+1);
- if (status) {
- dev_err(&adapter->pdev->dev,
- "Interface Create failed for VF %d\n",
- vf);
- goto if_destroy;
- }
- adapter->vf_cfg[vf].vf_pmac_id =
- BE_INVALID_PMAC_ID;
- vf++;
- }
- }
- } else {
- status = be_cmd_mac_addr_query(adapter, mac,
- MAC_ADDRESS_TYPE_NETWORK, false, adapter->if_handle);
- if (!status) {
- memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
- memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
- }
+ if (status)
+ goto err;
+ adapter->vf_cfg[vf].vf_pmac_id = BE_INVALID_PMAC_ID;
}
+ if (!lancer_chip(adapter)) {
+ status = be_vf_eth_addr_config(adapter);
+ if (status)
+ goto err;
+ }
+
+ for (vf = 0; vf < num_vfs; vf++) {
+ status = be_cmd_link_status_query(adapter, NULL, &lnk_speed,
+ vf + 1);
+ if (status)
+ goto err;
+ adapter->vf_cfg[vf].vf_tx_rate = lnk_speed * 10;
+ }
+ return 0;
+err:
+ return status;
+}
+
+static int be_setup(struct be_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ u32 cap_flags, en_flags;
+ u32 tx_fc, rx_fc;
+ int status;
+ u8 mac[ETH_ALEN];
+
+ /* Allow all priorities by default. A GRP5 evt may modify this */
+ adapter->vlan_prio_bmap = 0xff;
+ adapter->link_speed = -1;
+
+ be_cmd_req_native_mode(adapter);
+
status = be_tx_queues_create(adapter);
if (status != 0)
- goto if_destroy;
+ goto err;
status = be_rx_queues_create(adapter);
if (status != 0)
- goto tx_qs_destroy;
-
- /* Allow all priorities by default. A GRP5 evt may modify this */
- adapter->vlan_prio_bmap = 0xff;
+ goto err;
status = be_mcc_queues_create(adapter);
if (status != 0)
- goto rx_qs_destroy;
+ goto err;
- adapter->link_speed = -1;
+ memset(mac, 0, ETH_ALEN);
+ status = be_cmd_mac_addr_query(adapter, mac, MAC_ADDRESS_TYPE_NETWORK,
+ true /*permanent */, 0);
+ if (status)
+ return status;
+ memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
+ memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
- return 0;
+ en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
+ BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS;
+ cap_flags = en_flags | BE_IF_FLAGS_MCAST_PROMISCUOUS |
+ BE_IF_FLAGS_PROMISCUOUS;
+ if (adapter->function_caps & BE_FUNCTION_CAPS_RSS) {
+ cap_flags |= BE_IF_FLAGS_RSS;
+ en_flags |= BE_IF_FLAGS_RSS;
+ }
+ status = be_cmd_if_create(adapter, cap_flags, en_flags,
+ netdev->dev_addr, &adapter->if_handle,
+ &adapter->pmac_id, 0);
+ if (status != 0)
+ goto err;
-rx_qs_destroy:
- be_rx_queues_destroy(adapter);
-tx_qs_destroy:
- be_tx_queues_destroy(adapter);
-if_destroy:
- if (be_physfn(adapter) && adapter->sriov_enabled)
- for (vf = 0; vf < num_vfs; vf++)
- if (adapter->vf_cfg[vf].vf_if_handle)
- be_cmd_if_destroy(adapter,
- adapter->vf_cfg[vf].vf_if_handle,
- vf + 1);
- be_cmd_if_destroy(adapter, adapter->if_handle, 0);
-do_none:
- return status;
-}
+ /* For BEx, the VF's permanent mac queried from card is incorrect.
+ * Query the mac configued by the PF using if_handle
+ */
+ if (!be_physfn(adapter) && !lancer_chip(adapter)) {
+ status = be_cmd_mac_addr_query(adapter, mac,
+ MAC_ADDRESS_TYPE_NETWORK, false, adapter->if_handle);
+ if (!status) {
+ memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
+ memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
+ }
+ }
-static int be_clear(struct be_adapter *adapter)
-{
- int vf;
+ be_cmd_get_fw_ver(adapter, adapter->fw_ver, NULL);
- if (be_physfn(adapter) && adapter->sriov_enabled)
- be_vf_eth_addr_rem(adapter);
+ status = be_vid_config(adapter, false, 0);
+ if (status)
+ goto err;
- be_mcc_queues_destroy(adapter);
- be_rx_queues_destroy(adapter);
- be_tx_queues_destroy(adapter);
- adapter->eq_next_idx = 0;
+ be_set_rx_mode(adapter->netdev);
- if (be_physfn(adapter) && adapter->sriov_enabled)
- for (vf = 0; vf < num_vfs; vf++)
- if (adapter->vf_cfg[vf].vf_if_handle)
- be_cmd_if_destroy(adapter,
- adapter->vf_cfg[vf].vf_if_handle,
- vf + 1);
+ status = be_cmd_get_flow_control(adapter, &tx_fc, &rx_fc);
+ if (status)
+ goto err;
+ if (rx_fc != adapter->rx_fc || tx_fc != adapter->tx_fc) {
+ status = be_cmd_set_flow_control(adapter, adapter->tx_fc,
+ adapter->rx_fc);
+ if (status)
+ goto err;
+ }
- be_cmd_if_destroy(adapter, adapter->if_handle, 0);
+ pcie_set_readrq(adapter->pdev, 4096);
- adapter->be3_native = 0;
+ if (be_physfn(adapter) && adapter->sriov_enabled) {
+ status = be_vf_setup(adapter);
+ if (status)
+ goto err;
+ }
- /* tell fw we're done with firing cmds */
- be_cmd_fw_clean(adapter);
return 0;
+err:
+ be_clear(adapter);
+ return status;
}
-
#define FW_FILE_HDR_SIGN "ServerEngines Corp. "
static bool be_flash_redboot(struct be_adapter *adapter,
const u8 *p, u32 img_start, int image_size,
@@ -2656,6 +2652,21 @@ static bool be_flash_redboot(struct be_adapter *adapter,
return true;
}
+static bool phy_flashing_required(struct be_adapter *adapter)
+{
+ int status = 0;
+ struct be_phy_info phy_info;
+
+ status = be_cmd_get_phy_info(adapter, &phy_info);
+ if (status)
+ return false;
+ if ((phy_info.phy_type == TN_8022) &&
+ (phy_info.interface_type == PHY_TYPE_BASET_10GB)) {
+ return true;
+ }
+ return false;
+}
+
static int be_flash_data(struct be_adapter *adapter,
const struct firmware *fw,
struct be_dma_mem *flash_cmd, int num_of_images)
@@ -2669,7 +2680,7 @@ static int be_flash_data(struct be_adapter *adapter,
const struct flash_comp *pflashcomp;
int num_comp;
- static const struct flash_comp gen3_flash_types[9] = {
+ static const struct flash_comp gen3_flash_types[10] = {
{ FLASH_iSCSI_PRIMARY_IMAGE_START_g3, IMG_TYPE_ISCSI_ACTIVE,
FLASH_IMAGE_MAX_SIZE_g3},
{ FLASH_REDBOOT_START_g3, IMG_TYPE_REDBOOT,
@@ -2687,7 +2698,9 @@ static int be_flash_data(struct be_adapter *adapter,
{ FLASH_FCoE_BACKUP_IMAGE_START_g3, IMG_TYPE_FCOE_FW_BACKUP,
FLASH_IMAGE_MAX_SIZE_g3},
{ FLASH_NCSI_START_g3, IMG_TYPE_NCSI_FW,
- FLASH_NCSI_IMAGE_MAX_SIZE_g3}
+ FLASH_NCSI_IMAGE_MAX_SIZE_g3},
+ { FLASH_PHY_FW_START_g3, IMG_TYPE_PHY_FW,
+ FLASH_PHY_FW_IMAGE_MAX_SIZE_g3}
};
static const struct flash_comp gen2_flash_types[8] = {
{ FLASH_iSCSI_PRIMARY_IMAGE_START_g2, IMG_TYPE_ISCSI_ACTIVE,
@@ -2721,6 +2734,10 @@ static int be_flash_data(struct be_adapter *adapter,
if ((pflashcomp[i].optype == IMG_TYPE_NCSI_FW) &&
memcmp(adapter->fw_ver, "3.102.148.0", 11) < 0)
continue;
+ if (pflashcomp[i].optype == IMG_TYPE_PHY_FW) {
+ if (!phy_flashing_required(adapter))
+ continue;
+ }
if ((pflashcomp[i].optype == IMG_TYPE_REDBOOT) &&
(!be_flash_redboot(adapter, fw->data,
pflashcomp[i].offset, pflashcomp[i].size, filehdr_size +
@@ -2729,25 +2746,35 @@ static int be_flash_data(struct be_adapter *adapter,
p = fw->data;
p += filehdr_size + pflashcomp[i].offset
+ (num_of_images * sizeof(struct image_hdr));
- if (p + pflashcomp[i].size > fw->data + fw->size)
- return -1;
- total_bytes = pflashcomp[i].size;
+ if (p + pflashcomp[i].size > fw->data + fw->size)
+ return -1;
+ total_bytes = pflashcomp[i].size;
while (total_bytes) {
if (total_bytes > 32*1024)
num_bytes = 32*1024;
else
num_bytes = total_bytes;
total_bytes -= num_bytes;
-
- if (!total_bytes)
- flash_op = FLASHROM_OPER_FLASH;
- else
- flash_op = FLASHROM_OPER_SAVE;
+ if (!total_bytes) {
+ if (pflashcomp[i].optype == IMG_TYPE_PHY_FW)
+ flash_op = FLASHROM_OPER_PHY_FLASH;
+ else
+ flash_op = FLASHROM_OPER_FLASH;
+ } else {
+ if (pflashcomp[i].optype == IMG_TYPE_PHY_FW)
+ flash_op = FLASHROM_OPER_PHY_SAVE;
+ else
+ flash_op = FLASHROM_OPER_SAVE;
+ }
memcpy(req->params.data_buf, p, num_bytes);
p += num_bytes;
status = be_cmd_write_flashrom(adapter, flash_cmd,
pflashcomp[i].optype, flash_op, num_bytes);
if (status) {
+ if ((status == ILLEGAL_IOCTL_REQ) &&
+ (pflashcomp[i].optype ==
+ IMG_TYPE_PHY_FW))
+ break;
dev_err(&adapter->pdev->dev,
"cmd to write to flash rom failed.\n");
return -1;
@@ -2935,9 +2962,10 @@ static struct net_device_ops be_netdev_ops = {
.ndo_open = be_open,
.ndo_stop = be_close,
.ndo_start_xmit = be_xmit,
- .ndo_set_rx_mode = be_set_multicast_list,
+ .ndo_set_rx_mode = be_set_rx_mode,
.ndo_set_mac_address = be_mac_addr_set,
.ndo_change_mtu = be_change_mtu,
+ .ndo_get_stats64 = be_get_stats64,
.ndo_validate_addr = eth_validate_addr,
.ndo_vlan_rx_add_vid = be_vlan_add_vid,
.ndo_vlan_rx_kill_vid = be_vlan_rem_vid,
@@ -2967,10 +2995,6 @@ static void be_netdev_init(struct net_device *netdev)
netdev->flags |= IFF_MULTICAST;
- /* Default settings for Rx and Tx flow control */
- adapter->rx_fc = true;
- adapter->tx_fc = true;
-
netif_set_gso_max_size(netdev, 65535);
BE_SET_NETDEV_OPS(netdev, &be_netdev_ops);
@@ -2991,14 +3015,12 @@ static void be_unmap_pci_bars(struct be_adapter *adapter)
iounmap(adapter->csr);
if (adapter->db)
iounmap(adapter->db);
- if (adapter->pcicfg && be_physfn(adapter))
- iounmap(adapter->pcicfg);
}
static int be_map_pci_bars(struct be_adapter *adapter)
{
u8 __iomem *addr;
- int pcicfg_reg, db_reg;
+ int db_reg;
if (lancer_chip(adapter)) {
addr = ioremap_nocache(pci_resource_start(adapter->pdev, 0),
@@ -3018,10 +3040,8 @@ static int be_map_pci_bars(struct be_adapter *adapter)
}
if (adapter->generation == BE_GEN2) {
- pcicfg_reg = 1;
db_reg = 4;
} else {
- pcicfg_reg = 0;
if (be_physfn(adapter))
db_reg = 4;
else
@@ -3033,16 +3053,6 @@ static int be_map_pci_bars(struct be_adapter *adapter)
goto pci_map_err;
adapter->db = addr;
- if (be_physfn(adapter)) {
- addr = ioremap_nocache(
- pci_resource_start(adapter->pdev, pcicfg_reg),
- pci_resource_len(adapter->pdev, pcicfg_reg));
- if (addr == NULL)
- goto pci_map_err;
- adapter->pcicfg = addr;
- } else
- adapter->pcicfg = adapter->db + SRIOV_VF_PCICFG_OFFSET;
-
return 0;
pci_map_err:
be_unmap_pci_bars(adapter);
@@ -3060,7 +3070,7 @@ static void be_ctrl_cleanup(struct be_adapter *adapter)
dma_free_coherent(&adapter->pdev->dev, mem->size, mem->va,
mem->dma);
- mem = &adapter->mc_cmd_mem;
+ mem = &adapter->rx_filter;
if (mem->va)
dma_free_coherent(&adapter->pdev->dev, mem->size, mem->va,
mem->dma);
@@ -3070,7 +3080,7 @@ static int be_ctrl_init(struct be_adapter *adapter)
{
struct be_dma_mem *mbox_mem_alloc = &adapter->mbox_mem_alloced;
struct be_dma_mem *mbox_mem_align = &adapter->mbox_mem;
- struct be_dma_mem *mc_cmd_mem = &adapter->mc_cmd_mem;
+ struct be_dma_mem *rx_filter = &adapter->rx_filter;
int status;
status = be_map_pci_bars(adapter);
@@ -3086,21 +3096,19 @@ static int be_ctrl_init(struct be_adapter *adapter)
status = -ENOMEM;
goto unmap_pci_bars;
}
-
mbox_mem_align->size = sizeof(struct be_mcc_mailbox);
mbox_mem_align->va = PTR_ALIGN(mbox_mem_alloc->va, 16);
mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16);
memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox));
- mc_cmd_mem->size = sizeof(struct be_cmd_req_mcast_mac_config);
- mc_cmd_mem->va = dma_alloc_coherent(&adapter->pdev->dev,
- mc_cmd_mem->size, &mc_cmd_mem->dma,
- GFP_KERNEL);
- if (mc_cmd_mem->va == NULL) {
+ rx_filter->size = sizeof(struct be_cmd_req_rx_filter);
+ rx_filter->va = dma_alloc_coherent(&adapter->pdev->dev, rx_filter->size,
+ &rx_filter->dma, GFP_KERNEL);
+ if (rx_filter->va == NULL) {
status = -ENOMEM;
goto free_mbox;
}
- memset(mc_cmd_mem->va, 0, mc_cmd_mem->size);
+ memset(rx_filter->va, 0, rx_filter->size);
mutex_init(&adapter->mbox_lock);
spin_lock_init(&adapter->mcc_lock);
@@ -3167,7 +3175,6 @@ static void __devexit be_remove(struct pci_dev *pdev)
be_ctrl_cleanup(adapter);
- kfree(adapter->vf_cfg);
be_sriov_disable(adapter);
be_msix_disable(adapter);
@@ -3182,35 +3189,13 @@ static void __devexit be_remove(struct pci_dev *pdev)
static int be_get_config(struct be_adapter *adapter)
{
int status;
- u8 mac[ETH_ALEN];
-
- status = be_cmd_get_fw_ver(adapter, adapter->fw_ver);
- if (status)
- return status;
status = be_cmd_query_fw_cfg(adapter, &adapter->port_num,
&adapter->function_mode, &adapter->function_caps);
if (status)
return status;
- memset(mac, 0, ETH_ALEN);
-
- /* A default permanent address is given to each VF for Lancer*/
- if (be_physfn(adapter) || lancer_chip(adapter)) {
- status = be_cmd_mac_addr_query(adapter, mac,
- MAC_ADDRESS_TYPE_NETWORK, true /*permanent */, 0);
-
- if (status)
- return status;
-
- if (!is_valid_ether_addr(mac))
- return -EADDRNOTAVAIL;
-
- memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
- memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
- }
-
- if (adapter->function_mode & 0x400)
+ if (adapter->function_mode & FLEX10_MODE)
adapter->max_vlans = BE_NUM_VLANS_SUPPORTED/4;
else
adapter->max_vlans = BE_NUM_VLANS_SUPPORTED;
@@ -3219,16 +3204,6 @@ static int be_get_config(struct be_adapter *adapter)
if (status)
return status;
- if ((num_vfs && adapter->sriov_enabled) ||
- (adapter->function_mode & 0x400) ||
- lancer_chip(adapter) || !be_physfn(adapter)) {
- adapter->num_tx_qs = 1;
- netif_set_real_num_tx_queues(adapter->netdev,
- adapter->num_tx_qs);
- } else {
- adapter->num_tx_qs = MAX_TX_QS;
- }
-
return 0;
}
@@ -3358,18 +3333,13 @@ static int __devinit be_probe(struct pci_dev *pdev,
}
}
- be_sriov_enable(adapter);
- if (adapter->sriov_enabled) {
- adapter->vf_cfg = kcalloc(num_vfs,
- sizeof(struct be_vf_cfg), GFP_KERNEL);
-
- if (!adapter->vf_cfg)
- goto free_netdev;
- }
+ status = be_sriov_enable(adapter);
+ if (status)
+ goto free_netdev;
status = be_ctrl_init(adapter);
if (status)
- goto free_vf_cfg;
+ goto disable_sriov;
if (lancer_chip(adapter)) {
status = lancer_test_and_set_rdy_state(adapter);
@@ -3412,6 +3382,7 @@ static int __devinit be_probe(struct pci_dev *pdev,
be_msix_enable(adapter);
INIT_DELAYED_WORK(&adapter->work, be_worker);
+ adapter->rx_fc = adapter->tx_fc = true;
status = be_setup(adapter);
if (status)
@@ -3421,36 +3392,12 @@ static int __devinit be_probe(struct pci_dev *pdev,
status = register_netdev(netdev);
if (status != 0)
goto unsetup;
- netif_carrier_off(netdev);
-
- if (be_physfn(adapter) && adapter->sriov_enabled) {
- u8 mac_speed;
- bool link_up;
- u16 vf, lnk_speed;
-
- if (!lancer_chip(adapter)) {
- status = be_vf_eth_addr_config(adapter);
- if (status)
- goto unreg_netdev;
- }
-
- for (vf = 0; vf < num_vfs; vf++) {
- status = be_cmd_link_status_query(adapter, &link_up,
- &mac_speed, &lnk_speed, vf + 1);
- if (!status)
- adapter->vf_cfg[vf].vf_tx_rate = lnk_speed * 10;
- else
- goto unreg_netdev;
- }
- }
dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num);
schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
return 0;
-unreg_netdev:
- unregister_netdev(netdev);
unsetup:
be_clear(adapter);
msix_disable:
@@ -3459,10 +3406,9 @@ stats_clean:
be_stats_cleanup(adapter);
ctrl_clean:
be_ctrl_cleanup(adapter);
-free_vf_cfg:
- kfree(adapter->vf_cfg);
-free_netdev:
+disable_sriov:
be_sriov_disable(adapter);
+free_netdev:
free_netdev(netdev);
pci_set_drvdata(pdev, NULL);
rel_reg:
@@ -3489,7 +3435,6 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state)
be_close(netdev);
rtnl_unlock();
}
- be_cmd_get_flow_control(adapter, &adapter->tx_fc, &adapter->rx_fc);
be_clear(adapter);
be_msix_disable(adapter);
diff --git a/drivers/net/ethoc.c b/drivers/net/ethernet/ethoc.c
index 8abbe1d82826..bdb348a5ccf6 100644
--- a/drivers/net/ethoc.c
+++ b/drivers/net/ethernet/ethoc.c
@@ -888,7 +888,7 @@ static const struct net_device_ops ethoc_netdev_ops = {
.ndo_do_ioctl = ethoc_ioctl,
.ndo_set_config = ethoc_config,
.ndo_set_mac_address = ethoc_set_mac_address,
- .ndo_set_multicast_list = ethoc_set_multicast_list,
+ .ndo_set_rx_mode = ethoc_set_multicast_list,
.ndo_change_mtu = ethoc_change_mtu,
.ndo_tx_timeout = ethoc_tx_timeout,
.ndo_start_xmit = ethoc_start_xmit,
diff --git a/drivers/net/ethernet/faraday/Kconfig b/drivers/net/ethernet/faraday/Kconfig
new file mode 100644
index 000000000000..b8974b9e3b47
--- /dev/null
+++ b/drivers/net/ethernet/faraday/Kconfig
@@ -0,0 +1,40 @@
+#
+# Faraday device configuration
+#
+
+config NET_VENDOR_FARADAY
+ bool "Faraday devices"
+ default y
+ depends on ARM
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Faraday cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_FARADAY
+
+config FTMAC100
+ tristate "Faraday FTMAC100 10/100 Ethernet support"
+ depends on ARM
+ select NET_CORE
+ select MII
+ ---help---
+ This driver supports the FTMAC100 10/100 Ethernet controller
+ from Faraday. It is used on Faraday A320, Andes AG101 and some
+ other ARM/NDS32 SoC's.
+
+config FTGMAC100
+ tristate "Faraday FTGMAC100 Gigabit Ethernet support"
+ depends on ARM
+ select PHYLIB
+ ---help---
+ This driver supports the FTGMAC100 Gigabit Ethernet controller
+ from Faraday. It is used on Faraday A369, Andes AG102 and some
+ other ARM/NDS32 SoC's.
+
+endif # NET_VENDOR_FARADAY
diff --git a/drivers/net/ethernet/faraday/Makefile b/drivers/net/ethernet/faraday/Makefile
new file mode 100644
index 000000000000..408b53980d53
--- /dev/null
+++ b/drivers/net/ethernet/faraday/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the Faraday device drivers.
+#
+
+obj-$(CONFIG_FTGMAC100) += ftgmac100.o
+obj-$(CONFIG_FTMAC100) += ftmac100.o
diff --git a/drivers/net/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c
index 54709af917e9..fb5579a3b19d 100644
--- a/drivers/net/ftgmac100.c
+++ b/drivers/net/ethernet/faraday/ftgmac100.c
@@ -467,7 +467,7 @@ static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
skb->len += size;
skb->data_len += size;
- skb->truesize += size;
+ skb->truesize += PAGE_SIZE;
if (ftgmac100_rxdes_last_segment(rxdes))
done = true;
@@ -478,6 +478,8 @@ static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
rxdes = ftgmac100_current_rxdes(priv);
} while (!done);
+ if (skb->len <= 64)
+ skb->truesize -= PAGE_SIZE;
__pskb_pull_tail(skb, min(skb->len, 64U));
skb->protocol = eth_type_trans(skb, netdev);
diff --git a/drivers/net/ftgmac100.h b/drivers/net/ethernet/faraday/ftgmac100.h
index 13408d448b05..13408d448b05 100644
--- a/drivers/net/ftgmac100.h
+++ b/drivers/net/ethernet/faraday/ftgmac100.h
diff --git a/drivers/net/ftmac100.c b/drivers/net/ethernet/faraday/ftmac100.c
index 9bd7746cbfcf..a127cb2476c7 100644
--- a/drivers/net/ftmac100.c
+++ b/drivers/net/ethernet/faraday/ftmac100.c
@@ -439,7 +439,10 @@ static bool ftmac100_rx_packet(struct ftmac100 *priv, int *processed)
skb_fill_page_desc(skb, 0, page, 0, length);
skb->len += length;
skb->data_len += length;
- skb->truesize += length;
+
+ /* page might be freed in __pskb_pull_tail() */
+ if (length > 64)
+ skb->truesize += PAGE_SIZE;
__pskb_pull_tail(skb, min(length, 64));
ftmac100_alloc_rx_page(priv, rxdes, GFP_ATOMIC);
diff --git a/drivers/net/ftmac100.h b/drivers/net/ethernet/faraday/ftmac100.h
index 46a0c47b1ee1..46a0c47b1ee1 100644
--- a/drivers/net/ftmac100.h
+++ b/drivers/net/ethernet/faraday/ftmac100.h
diff --git a/drivers/net/fealnx.c b/drivers/net/ethernet/fealnx.c
index fa8677c32384..61d2bddec1fa 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/ethernet/fealnx.c
@@ -469,7 +469,7 @@ static const struct net_device_ops netdev_ops = {
.ndo_stop = netdev_close,
.ndo_start_xmit = start_tx,
.ndo_get_stats = get_stats,
- .ndo_set_multicast_list = set_rx_mode,
+ .ndo_set_rx_mode = set_rx_mode,
.ndo_do_ioctl = mii_ioctl,
.ndo_tx_timeout = fealnx_tx_timeout,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig
new file mode 100644
index 000000000000..1cf671643d1f
--- /dev/null
+++ b/drivers/net/ethernet/freescale/Kconfig
@@ -0,0 +1,88 @@
+#
+# Freescale device configuration
+#
+
+config NET_VENDOR_FREESCALE
+ bool "Freescale devices"
+ default y
+ depends on FSL_SOC || QUICC_ENGINE || CPM1 || CPM2 || PPC_MPC512x || \
+ M523x || M527x || M5272 || M528x || M520x || M532x || \
+ ARCH_MXC || ARCH_MXS || \
+ (PPC_MPC52xx && PPC_BESTCOMM)
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Freescale devices. If you say Y, you will be
+ asked for your specific card in the following questions.
+
+if NET_VENDOR_FREESCALE
+
+config FEC
+ bool "FEC ethernet controller (of ColdFire and some i.MX CPUs)"
+ depends on (M523x || M527x || M5272 || M528x || M520x || M532x || \
+ ARCH_MXC || ARCH_MXS)
+ select PHYLIB
+ ---help---
+ Say Y here if you want to use the built-in 10/100 Fast ethernet
+ controller on some Motorola ColdFire and Freescale i.MX processors.
+
+config FEC_MPC52xx
+ tristate "FEC MPC52xx driver"
+ depends on PPC_MPC52xx && PPC_BESTCOMM
+ select CRC32
+ select PHYLIB
+ select PPC_BESTCOMM_FEC
+ ---help---
+ This option enables support for the MPC5200's on-chip
+ Fast Ethernet Controller
+ If compiled as module, it will be called fec_mpc52xx.
+
+config FEC_MPC52xx_MDIO
+ bool "FEC MPC52xx MDIO bus driver"
+ depends on FEC_MPC52xx
+ default y
+ ---help---
+ The MPC5200's FEC can connect to the Ethernet either with
+ an external MII PHY chip or 10 Mbps 7-wire interface
+ (Motorola? industry standard).
+ If your board uses an external PHY connected to FEC, enable this.
+ If not sure, enable.
+ If compiled as module, it will be called fec_mpc52xx_phy.
+
+source "drivers/net/ethernet/freescale/fs_enet/Kconfig"
+
+config FSL_PQ_MDIO
+ tristate "Freescale PQ MDIO"
+ depends on FSL_SOC
+ select PHYLIB
+ ---help---
+ This driver supports the MDIO bus used by the gianfar and UCC drivers.
+
+config UCC_GETH
+ tristate "Freescale QE Gigabit Ethernet"
+ depends on QUICC_ENGINE
+ select FSL_PQ_MDIO
+ select PHYLIB
+ ---help---
+ This driver supports the Gigabit Ethernet mode of the QUICC Engine,
+ which is available on some Freescale SOCs.
+
+config UGETH_TX_ON_DEMAND
+ bool "Transmit on Demand support"
+ depends on UCC_GETH
+
+config GIANFAR
+ tristate "Gianfar Ethernet"
+ depends on FSL_SOC
+ select FSL_PQ_MDIO
+ select PHYLIB
+ select CRC32
+ ---help---
+ This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx,
+ and MPC86xx family of chips, and the FEC on the 8540.
+
+endif # NET_VENDOR_FREESCALE
diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile
new file mode 100644
index 000000000000..1752488c9ee5
--- /dev/null
+++ b/drivers/net/ethernet/freescale/Makefile
@@ -0,0 +1,18 @@
+#
+# Makefile for the Freescale network device drivers.
+#
+
+obj-$(CONFIG_FEC) += fec.o
+obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
+ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
+ obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o
+endif
+obj-$(CONFIG_FS_ENET) += fs_enet/
+obj-$(CONFIG_FSL_PQ_MDIO) += fsl_pq_mdio.o
+obj-$(CONFIG_GIANFAR) += gianfar_driver.o
+obj-$(CONFIG_PTP_1588_CLOCK_GIANFAR) += gianfar_ptp.o
+gianfar_driver-objs := gianfar.o \
+ gianfar_ethtool.o \
+ gianfar_sysfs.o
+obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o
+ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o
diff --git a/drivers/net/fec.c b/drivers/net/ethernet/freescale/fec.c
index e8266ccf818a..1124ce0a1594 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/ethernet/freescale/fec.c
@@ -18,7 +18,7 @@
* Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be)
* Copyright (c) 2004-2006 Macq Electronique SA.
*
- * Copyright (C) 2010 Freescale Semiconductor, Inc.
+ * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
*/
#include <linux/module.h>
@@ -72,6 +72,8 @@
#define FEC_QUIRK_SWAP_FRAME (1 << 1)
/* Controller uses gasket */
#define FEC_QUIRK_USE_GASKET (1 << 2)
+/* Controller has GBIT support */
+#define FEC_QUIRK_HAS_GBIT (1 << 3)
static struct platform_device_id fec_devtype[] = {
{
@@ -88,6 +90,9 @@ static struct platform_device_id fec_devtype[] = {
.name = "imx28-fec",
.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME,
}, {
+ .name = "imx6q-fec",
+ .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT,
+ }, {
/* sentinel */
}
};
@@ -97,12 +102,14 @@ enum imx_fec_type {
IMX25_FEC = 1, /* runs on i.mx25/50/53 */
IMX27_FEC, /* runs on i.mx27/35/51 */
IMX28_FEC,
+ IMX6Q_FEC,
};
static const struct of_device_id fec_dt_ids[] = {
{ .compatible = "fsl,imx25-fec", .data = &fec_devtype[IMX25_FEC], },
{ .compatible = "fsl,imx27-fec", .data = &fec_devtype[IMX27_FEC], },
{ .compatible = "fsl,imx28-fec", .data = &fec_devtype[IMX28_FEC], },
+ { .compatible = "fsl,imx6q-fec", .data = &fec_devtype[IMX6Q_FEC], },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fec_dt_ids);
@@ -170,6 +177,8 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
#define PKT_MINBUF_SIZE 64
#define PKT_MAXBLR_SIZE 1520
+/* This device has up to three irqs on some platforms */
+#define FEC_IRQ_NUM 3
/*
* The 5270/5271/5280/5282/532x RX control register also contains maximum frame
@@ -233,6 +242,7 @@ struct fec_enet_private {
int link;
int full_duplex;
struct completion mdio_done;
+ int irq[FEC_IRQ_NUM];
};
/* FEC MII MMFR bits definition */
@@ -373,6 +383,7 @@ fec_restart(struct net_device *ndev, int duplex)
int i;
u32 temp_mac[2];
u32 rcntl = OPT_FRAME_SIZE | 0x04;
+ u32 ecntl = 0x2; /* ETHEREN */
/* Whack a reset. We should wait for this. */
writel(1, fep->hwp + FEC_ECNTRL);
@@ -442,18 +453,23 @@ fec_restart(struct net_device *ndev, int duplex)
/* Enable flow control and length check */
rcntl |= 0x40000000 | 0x00000020;
- /* MII or RMII */
- if (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
+ /* RGMII, RMII or MII */
+ if (fep->phy_interface == PHY_INTERFACE_MODE_RGMII)
+ rcntl |= (1 << 6);
+ else if (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
rcntl |= (1 << 8);
else
rcntl &= ~(1 << 8);
- /* 10M or 100M */
- if (fep->phy_dev && fep->phy_dev->speed == SPEED_100)
- rcntl &= ~(1 << 9);
- else
- rcntl |= (1 << 9);
-
+ /* 1G, 100M or 10M */
+ if (fep->phy_dev) {
+ if (fep->phy_dev->speed == SPEED_1000)
+ ecntl |= (1 << 5);
+ else if (fep->phy_dev->speed == SPEED_100)
+ rcntl &= ~(1 << 9);
+ else
+ rcntl |= (1 << 9);
+ }
} else {
#ifdef FEC_MIIGSK_ENR
if (id_entry->driver_data & FEC_QUIRK_USE_GASKET) {
@@ -478,8 +494,15 @@ fec_restart(struct net_device *ndev, int duplex)
}
writel(rcntl, fep->hwp + FEC_R_CNTRL);
+ if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
+ /* enable ENET endian swap */
+ ecntl |= (1 << 8);
+ /* enable ENET store and forward mode */
+ writel(1 << 8, fep->hwp + FEC_X_WMRK);
+ }
+
/* And last, enable the transmit and receive processing */
- writel(2, fep->hwp + FEC_ECNTRL);
+ writel(ecntl, fep->hwp + FEC_ECNTRL);
writel(0, fep->hwp + FEC_R_DES_ACTIVE);
/* Enable interrupts we wish to service */
@@ -490,6 +513,8 @@ static void
fec_stop(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
+ const struct platform_device_id *id_entry =
+ platform_get_device_id(fep->pdev);
/* We cannot expect a graceful transmit stop without link !!! */
if (fep->link) {
@@ -504,6 +529,10 @@ fec_stop(struct net_device *ndev)
udelay(10);
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
+
+ /* We have to keep ENET enabled to have MII interrupt stay working */
+ if (id_entry->driver_data & FEC_QUIRK_ENET_MAC)
+ writel(2, fep->hwp + FEC_ECNTRL);
}
@@ -918,6 +947,8 @@ static int fec_enet_mdio_reset(struct mii_bus *bus)
static int fec_enet_mii_probe(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
+ const struct platform_device_id *id_entry =
+ platform_get_device_id(fep->pdev);
struct phy_device *phy_dev = NULL;
char mdio_bus_id[MII_BUS_ID_SIZE];
char phy_name[MII_BUS_ID_SIZE + 3];
@@ -949,14 +980,18 @@ static int fec_enet_mii_probe(struct net_device *ndev)
snprintf(phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, phy_id);
phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link, 0,
- PHY_INTERFACE_MODE_MII);
+ fep->phy_interface);
if (IS_ERR(phy_dev)) {
printk(KERN_ERR "%s: could not attach to PHY\n", ndev->name);
return PTR_ERR(phy_dev);
}
/* mask with MAC supported features */
- phy_dev->supported &= PHY_BASIC_FEATURES;
+ if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT)
+ phy_dev->supported &= PHY_GBIT_FEATURES;
+ else
+ phy_dev->supported &= PHY_BASIC_FEATURES;
+
phy_dev->advertising = phy_dev->supported;
fep->phy_dev = phy_dev;
@@ -996,7 +1031,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
* mdio interface in board design, and need to be configured by
* fec0 mii_bus.
*/
- if ((id_entry->driver_data & FEC_QUIRK_ENET_MAC) && pdev->id) {
+ if ((id_entry->driver_data & FEC_QUIRK_ENET_MAC) && pdev->id > 0) {
/* fec1 uses fec0 mii_bus */
fep->mii_bus = fec0_mii_bus;
return 0;
@@ -1006,8 +1041,16 @@ static int fec_enet_mii_init(struct platform_device *pdev)
/*
* Set MII speed to 2.5 MHz (= clk_get_rate() / 2 * phy_speed)
+ *
+ * The formula for FEC MDC is 'ref_freq / (MII_SPEED x 2)' while
+ * for ENET-MAC is 'ref_freq / ((MII_SPEED + 1) x 2)'. The i.MX28
+ * Reference Manual has an error on this, and gets fixed on i.MX6Q
+ * document.
*/
- fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000) << 1;
+ fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000);
+ if (id_entry->driver_data & FEC_QUIRK_ENET_MAC)
+ fep->phy_speed--;
+ fep->phy_speed <<= 1;
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
fep->mii_bus = mdiobus_alloc();
@@ -1321,16 +1364,42 @@ fec_set_mac_address(struct net_device *ndev, void *p)
return 0;
}
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * fec_poll_controller: FEC Poll controller function
+ * @dev: The FEC network adapter
+ *
+ * Polled functionality used by netconsole and others in non interrupt mode
+ *
+ */
+void fec_poll_controller(struct net_device *dev)
+{
+ int i;
+ struct fec_enet_private *fep = netdev_priv(dev);
+
+ for (i = 0; i < FEC_IRQ_NUM; i++) {
+ if (fep->irq[i] > 0) {
+ disable_irq(fep->irq[i]);
+ fec_enet_interrupt(fep->irq[i], dev);
+ enable_irq(fep->irq[i]);
+ }
+ }
+}
+#endif
+
static const struct net_device_ops fec_netdev_ops = {
.ndo_open = fec_enet_open,
.ndo_stop = fec_enet_close,
.ndo_start_xmit = fec_enet_start_xmit,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_tx_timeout = fec_timeout,
.ndo_set_mac_address = fec_set_mac_address,
.ndo_do_ioctl = fec_enet_ioctl,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = fec_poll_controller,
+#endif
};
/*
@@ -1411,24 +1480,22 @@ static int __devinit fec_get_phy_mode_dt(struct platform_device *pdev)
return -ENODEV;
}
-static int __devinit fec_reset_phy(struct platform_device *pdev)
+static void __devinit fec_reset_phy(struct platform_device *pdev)
{
int err, phy_reset;
struct device_node *np = pdev->dev.of_node;
if (!np)
- return -ENODEV;
+ return;
phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0);
err = gpio_request_one(phy_reset, GPIOF_OUT_INIT_LOW, "phy-reset");
if (err) {
- pr_warn("FEC: failed to get gpio phy-reset: %d\n", err);
- return err;
+ pr_debug("FEC: failed to get gpio phy-reset: %d\n", err);
+ return;
}
msleep(1);
gpio_set_value(phy_reset, 1);
-
- return 0;
}
#else /* CONFIG_OF */
static inline int fec_get_phy_mode_dt(struct platform_device *pdev)
@@ -1436,13 +1503,12 @@ static inline int fec_get_phy_mode_dt(struct platform_device *pdev)
return -ENODEV;
}
-static inline int fec_reset_phy(struct platform_device *pdev)
+static inline void fec_reset_phy(struct platform_device *pdev)
{
/*
* In case of platform probe, the reset has been done
* by machine code.
*/
- return 0;
}
#endif /* CONFIG_OF */
@@ -1503,8 +1569,7 @@ fec_probe(struct platform_device *pdev)
fec_reset_phy(pdev);
- /* This device has up to three irqs on some platforms */
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < FEC_IRQ_NUM; i++) {
irq = platform_get_irq(pdev, i);
if (i && irq < 0)
break;
@@ -1549,7 +1614,7 @@ failed_init:
clk_disable(fep->clk);
clk_put(fep->clk);
failed_clk:
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < FEC_IRQ_NUM; i++) {
irq = platform_get_irq(pdev, i);
if (irq > 0)
free_irq(irq, ndev);
diff --git a/drivers/net/fec.h b/drivers/net/ethernet/freescale/fec.h
index 8b2c6d797e6d..8b2c6d797e6d 100644
--- a/drivers/net/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/ethernet/freescale/fec_mpc52xx.c
index cb4416e591f1..30745b56fe5d 100644
--- a/drivers/net/fec_mpc52xx.c
+++ b/drivers/net/ethernet/freescale/fec_mpc52xx.c
@@ -828,7 +828,7 @@ static const struct net_device_ops mpc52xx_fec_netdev_ops = {
.ndo_open = mpc52xx_fec_open,
.ndo_stop = mpc52xx_fec_close,
.ndo_start_xmit = mpc52xx_fec_start_xmit,
- .ndo_set_multicast_list = mpc52xx_fec_set_multicast_list,
+ .ndo_set_rx_mode = mpc52xx_fec_set_multicast_list,
.ndo_set_mac_address = mpc52xx_fec_set_mac_address,
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = mpc52xx_fec_ioctl,
diff --git a/drivers/net/fec_mpc52xx.h b/drivers/net/ethernet/freescale/fec_mpc52xx.h
index 41d2dffde55b..41d2dffde55b 100644
--- a/drivers/net/fec_mpc52xx.h
+++ b/drivers/net/ethernet/freescale/fec_mpc52xx.h
diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/ethernet/freescale/fec_mpc52xx_phy.c
index 360a578c2bb7..360a578c2bb7 100644
--- a/drivers/net/fec_mpc52xx_phy.c
+++ b/drivers/net/ethernet/freescale/fec_mpc52xx_phy.c
diff --git a/drivers/net/fs_enet/Kconfig b/drivers/net/ethernet/freescale/fs_enet/Kconfig
index fc073b5a38c7..268414d9f2cb 100644
--- a/drivers/net/fs_enet/Kconfig
+++ b/drivers/net/ethernet/freescale/fs_enet/Kconfig
@@ -1,6 +1,7 @@
config FS_ENET
tristate "Freescale Ethernet Driver"
- depends on CPM1 || CPM2 || PPC_MPC512x
+ depends on NET_VENDOR_FREESCALE && (CPM1 || CPM2 || PPC_MPC512x)
+ select NET_CORE
select MII
select PHYLIB
diff --git a/drivers/net/fs_enet/Makefile b/drivers/net/ethernet/freescale/fs_enet/Makefile
index d4a305ee3455..d4a305ee3455 100644
--- a/drivers/net/fs_enet/Makefile
+++ b/drivers/net/ethernet/freescale/fs_enet/Makefile
diff --git a/drivers/net/fs_enet/fec.h b/drivers/net/ethernet/freescale/fs_enet/fec.h
index e980527e2b99..e980527e2b99 100644
--- a/drivers/net/fs_enet/fec.h
+++ b/drivers/net/ethernet/freescale/fs_enet/fec.h
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
index 329ef231a096..5bf5471f06ff 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
@@ -988,7 +988,7 @@ static const struct net_device_ops fs_enet_netdev_ops = {
.ndo_get_stats = fs_enet_get_stats,
.ndo_start_xmit = fs_enet_start_xmit,
.ndo_tx_timeout = fs_timeout,
- .ndo_set_multicast_list = fs_set_multicast_list,
+ .ndo_set_rx_mode = fs_set_multicast_list,
.ndo_do_ioctl = fs_ioctl,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/ethernet/freescale/fs_enet/fs_enet.h
index 1ece4b1a689e..1ece4b1a689e 100644
--- a/drivers/net/fs_enet/fs_enet.h
+++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet.h
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c
index 7583a9572bcc..7583a9572bcc 100644
--- a/drivers/net/fs_enet/mac-fcc.c
+++ b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/ethernet/freescale/fs_enet/mac-fec.c
index b9fbc83d64a7..b9fbc83d64a7 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/ethernet/freescale/fs_enet/mac-fec.c
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/ethernet/freescale/fs_enet/mac-scc.c
index 22a02a767069..22a02a767069 100644
--- a/drivers/net/fs_enet/mac-scc.c
+++ b/drivers/net/ethernet/freescale/fs_enet/mac-scc.c
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c
index b09270b5d0a5..b09270b5d0a5 100644
--- a/drivers/net/fs_enet/mii-bitbang.c
+++ b/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/ethernet/freescale/fs_enet/mii-fec.c
index e0e9d6c35d83..e0e9d6c35d83 100644
--- a/drivers/net/fs_enet/mii-fec.c
+++ b/drivers/net/ethernet/freescale/fs_enet/mii-fec.c
diff --git a/drivers/net/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c
index 52f4e8ad48e7..52f4e8ad48e7 100644
--- a/drivers/net/fsl_pq_mdio.c
+++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c
diff --git a/drivers/net/fsl_pq_mdio.h b/drivers/net/ethernet/freescale/fsl_pq_mdio.h
index bd17a2a0139b..bd17a2a0139b 100644
--- a/drivers/net/fsl_pq_mdio.h
+++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.h
diff --git a/drivers/net/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 2659daad783d..83199fd0d62b 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -458,7 +458,7 @@ static const struct net_device_ops gfar_netdev_ops = {
.ndo_stop = gfar_close,
.ndo_change_mtu = gfar_change_mtu,
.ndo_set_features = gfar_set_features,
- .ndo_set_multicast_list = gfar_set_multi,
+ .ndo_set_rx_mode = gfar_set_multi,
.ndo_tx_timeout = gfar_timeout,
.ndo_do_ioctl = gfar_ioctl,
.ndo_get_stats = gfar_get_stats,
@@ -2140,11 +2140,11 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (i == nr_frags - 1)
lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
- bufaddr = dma_map_page(&priv->ofdev->dev,
- skb_shinfo(skb)->frags[i].page,
- skb_shinfo(skb)->frags[i].page_offset,
- length,
- DMA_TO_DEVICE);
+ bufaddr = skb_frag_dma_map(&priv->ofdev->dev,
+ &skb_shinfo(skb)->frags[i],
+ 0,
+ length,
+ DMA_TO_DEVICE);
/* set the TxBD length and buffer pointer */
txbdp->bufPtr = bufaddr;
@@ -2710,8 +2710,13 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
/* Tell the skb what kind of packet this is */
skb->protocol = eth_type_trans(skb, dev);
- /* Set vlan tag */
- if (fcb->flags & RXFCB_VLN)
+ /*
+ * There's need to check for NETIF_F_HW_VLAN_RX here.
+ * Even if vlan rx accel is disabled, on some chips
+ * RXFCB_VLN is pseudo randomly set.
+ */
+ if (dev->features & NETIF_F_HW_VLAN_RX &&
+ fcb->flags & RXFCB_VLN)
__vlan_hwaccel_put_tag(skb, fcb->vlctl);
/* Send the packet up the stack */
diff --git a/drivers/net/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h
index 9aa43773e8e3..9aa43773e8e3 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/ethernet/freescale/gianfar.h
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c
index 6e350692d118..212736bab6bb 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c
@@ -686,10 +686,21 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u
{
unsigned int last_rule_idx = priv->cur_filer_idx;
unsigned int cmp_rqfpr;
- unsigned int local_rqfpr[MAX_FILER_IDX + 1];
- unsigned int local_rqfcr[MAX_FILER_IDX + 1];
+ unsigned int *local_rqfpr;
+ unsigned int *local_rqfcr;
int i = 0x0, k = 0x0;
int j = MAX_FILER_IDX, l = 0x0;
+ int ret = 1;
+
+ local_rqfpr = kmalloc(sizeof(unsigned int) * (MAX_FILER_IDX + 1),
+ GFP_KERNEL);
+ local_rqfcr = kmalloc(sizeof(unsigned int) * (MAX_FILER_IDX + 1),
+ GFP_KERNEL);
+ if (!local_rqfpr || !local_rqfcr) {
+ pr_err("Out of memory\n");
+ ret = 0;
+ goto err;
+ }
switch (class) {
case TCP_V4_FLOW:
@@ -706,7 +717,8 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u
break;
default:
pr_err("Right now this class is not supported\n");
- return 0;
+ ret = 0;
+ goto err;
}
for (i = 0; i < MAX_FILER_IDX + 1; i++) {
@@ -721,7 +733,8 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u
if (i == MAX_FILER_IDX + 1) {
pr_err("No parse rule found, can't create hash rules\n");
- return 0;
+ ret = 0;
+ goto err;
}
/* If a match was found, then it begins the starting of a cluster rule
@@ -765,7 +778,10 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u
priv->cur_filer_idx = priv->cur_filer_idx - 1;
}
- return 1;
+err:
+ kfree(local_rqfcr);
+ kfree(local_rqfpr);
+ return ret;
}
static int gfar_set_hash_opts(struct gfar_private *priv, struct ethtool_rxnfc *cmd)
@@ -1653,13 +1669,14 @@ static int gfar_get_cls_all(struct gfar_private *priv,
u32 i = 0;
list_for_each_entry(comp, &priv->rx_list.list, list) {
- if (i <= cmd->rule_cnt) {
- rule_locs[i] = comp->fs.location;
- i++;
- }
+ if (i == cmd->rule_cnt)
+ return -EMSGSIZE;
+ rule_locs[i] = comp->fs.location;
+ i++;
}
cmd->data = MAX_FILER_IDX;
+ cmd->rule_cnt = i;
return 0;
}
@@ -1696,7 +1713,7 @@ static int gfar_set_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
}
static int gfar_get_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
- void *rule_locs)
+ u32 *rule_locs)
{
struct gfar_private *priv = netdev_priv(dev);
int ret = 0;
@@ -1712,7 +1729,7 @@ static int gfar_get_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
ret = gfar_get_cls(priv, cmd);
break;
case ETHTOOL_GRXCLSRLALL:
- ret = gfar_get_cls_all(priv, cmd, (u32 *) rule_locs);
+ ret = gfar_get_cls_all(priv, cmd, rule_locs);
break;
default:
ret = -EINVAL;
diff --git a/drivers/net/gianfar_ptp.c b/drivers/net/ethernet/freescale/gianfar_ptp.c
index f67b8aebc89c..f67b8aebc89c 100644
--- a/drivers/net/gianfar_ptp.c
+++ b/drivers/net/ethernet/freescale/gianfar_ptp.c
diff --git a/drivers/net/gianfar_sysfs.c b/drivers/net/ethernet/freescale/gianfar_sysfs.c
index 64f4094ac7f1..64f4094ac7f1 100644
--- a/drivers/net/gianfar_sysfs.c
+++ b/drivers/net/ethernet/freescale/gianfar_sysfs.c
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c
index d3465ab50e56..46d690a92c0b 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ethernet/freescale/ucc_geth.c
@@ -1761,10 +1761,12 @@ static int init_phy(struct net_device *dev)
if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII)
uec_configure_serdes(dev);
- phydev->supported &= (ADVERTISED_10baseT_Half |
- ADVERTISED_10baseT_Full |
- ADVERTISED_100baseT_Half |
- ADVERTISED_100baseT_Full);
+ phydev->supported &= (SUPPORTED_MII |
+ SUPPORTED_Autoneg |
+ ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full);
if (priv->max_speed == SPEED_1000)
phydev->supported |= ADVERTISED_1000baseT_Full;
@@ -3729,7 +3731,7 @@ static const struct net_device_ops ucc_geth_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = ucc_geth_set_mac_addr,
.ndo_change_mtu = eth_change_mtu,
- .ndo_set_multicast_list = ucc_geth_set_multi,
+ .ndo_set_rx_mode = ucc_geth_set_multi,
.ndo_tx_timeout = ucc_geth_timeout,
.ndo_do_ioctl = ucc_geth_ioctl,
#ifdef CONFIG_NET_POLL_CONTROLLER
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ethernet/freescale/ucc_geth.h
index d12fcad145e9..d12fcad145e9 100644
--- a/drivers/net/ucc_geth.h
+++ b/drivers/net/ethernet/freescale/ucc_geth.h
diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c
index a97257f91a3d..a97257f91a3d 100644
--- a/drivers/net/ucc_geth_ethtool.c
+++ b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c
diff --git a/drivers/net/ethernet/fujitsu/Kconfig b/drivers/net/ethernet/fujitsu/Kconfig
new file mode 100644
index 000000000000..dffee9d44fd5
--- /dev/null
+++ b/drivers/net/ethernet/fujitsu/Kconfig
@@ -0,0 +1,54 @@
+#
+# Fujitsu Network device configuration
+#
+
+config NET_VENDOR_FUJITSU
+ bool "Fujitsu devices"
+ default y
+ depends on ISA || PCMCIA || ((ISA || MCA_LEGACY) && EXPERIMENTAL)
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ the questions about Fujitsu cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_FUJITSU
+
+config AT1700
+ tristate "AT1700/1720 support (EXPERIMENTAL)"
+ depends on (ISA || MCA_LEGACY) && EXPERIMENTAL
+ select CRC32
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called at1700.
+
+config PCMCIA_FMVJ18X
+ tristate "Fujitsu FMV-J18x PCMCIA support"
+ depends on PCMCIA
+ select CRC32
+ ---help---
+ Say Y here if you intend to attach a Fujitsu FMV-J18x or compatible
+ PCMCIA (PC-card) Ethernet card to your computer.
+
+ To compile this driver as a module, choose M here: the module will be
+ called fmvj18x_cs. If unsure, say N.
+
+config ETH16I
+ tristate "ICL EtherTeam 16i/32 support"
+ depends on ISA
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called eth16i.
+
+endif # NET_VENDOR_FUJITSU
diff --git a/drivers/net/ethernet/fujitsu/Makefile b/drivers/net/ethernet/fujitsu/Makefile
new file mode 100644
index 000000000000..2730ae67d3aa
--- /dev/null
+++ b/drivers/net/ethernet/fujitsu/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Fujitsu network device drivers.
+#
+
+obj-$(CONFIG_AT1700) += at1700.o
+obj-$(CONFIG_ETH16I) += eth16i.o
+obj-$(CONFIG_PCMCIA_FMVJ18X) += fmvj18x_cs.o
diff --git a/drivers/net/at1700.c b/drivers/net/ethernet/fujitsu/at1700.c
index 65a78f965dd2..7c6c908bdf02 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/ethernet/fujitsu/at1700.c
@@ -253,7 +253,7 @@ static const struct net_device_ops at1700_netdev_ops = {
.ndo_open = net_open,
.ndo_stop = net_close,
.ndo_start_xmit = net_send_packet,
- .ndo_set_multicast_list = set_rx_mode,
+ .ndo_set_rx_mode = set_rx_mode,
.ndo_tx_timeout = net_tx_timeout,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/eth16i.c b/drivers/net/ethernet/fujitsu/eth16i.c
index 12d28e9d0cb7..b0e2313af3d1 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/ethernet/fujitsu/eth16i.c
@@ -478,7 +478,7 @@ static const struct net_device_ops eth16i_netdev_ops = {
.ndo_open = eth16i_open,
.ndo_stop = eth16i_close,
.ndo_start_xmit = eth16i_tx,
- .ndo_set_multicast_list = eth16i_multicast,
+ .ndo_set_rx_mode = eth16i_multicast,
.ndo_tx_timeout = eth16i_timeout,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
index 723815e7a997..15416752c13e 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
@@ -226,7 +226,7 @@ static const struct net_device_ops fjn_netdev_ops = {
.ndo_start_xmit = fjn_start_xmit,
.ndo_tx_timeout = fjn_tx_timeout,
.ndo_set_config = fjn_config,
- .ndo_set_multicast_list = set_rx_mode,
+ .ndo_set_rx_mode = set_rx_mode,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/ethernet/hp/Kconfig b/drivers/net/ethernet/hp/Kconfig
new file mode 100644
index 000000000000..a0b8ece1e3bc
--- /dev/null
+++ b/drivers/net/ethernet/hp/Kconfig
@@ -0,0 +1,32 @@
+#
+# HP network device configuration
+#
+
+config NET_VENDOR_HP
+ bool "HP devices"
+ default y
+ depends on ISA || EISA || PCI
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about HP cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_HP
+
+config HP100
+ tristate "HP 10/100VG PCLAN (ISA, EISA, PCI) support"
+ depends on (ISA || EISA || PCI)
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called hp100.
+
+endif # NET_VENDOR_HP
diff --git a/drivers/net/ethernet/hp/Makefile b/drivers/net/ethernet/hp/Makefile
new file mode 100644
index 000000000000..20b6918b52bd
--- /dev/null
+++ b/drivers/net/ethernet/hp/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the HP network device drivers.
+#
+
+obj-$(CONFIG_HP100) += hp100.o
diff --git a/drivers/net/hp100.c b/drivers/net/ethernet/hp/hp100.c
index b6519c1ba7e1..6a5ee0776b28 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/ethernet/hp/hp100.c
@@ -430,7 +430,7 @@ static const struct net_device_ops hp100_bm_netdev_ops = {
.ndo_stop = hp100_close,
.ndo_start_xmit = hp100_start_xmit_bm,
.ndo_get_stats = hp100_get_stats,
- .ndo_set_multicast_list = hp100_set_multicast_list,
+ .ndo_set_rx_mode = hp100_set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
@@ -441,7 +441,7 @@ static const struct net_device_ops hp100_netdev_ops = {
.ndo_stop = hp100_close,
.ndo_start_xmit = hp100_start_xmit,
.ndo_get_stats = hp100_get_stats,
- .ndo_set_multicast_list = hp100_set_multicast_list,
+ .ndo_set_rx_mode = hp100_set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/hp100.h b/drivers/net/ethernet/hp/hp100.h
index b60e96fe38b4..b60e96fe38b4 100644
--- a/drivers/net/hp100.h
+++ b/drivers/net/ethernet/hp/hp100.h
diff --git a/drivers/net/3c505.c b/drivers/net/ethernet/i825xx/3c505.c
index 88d766ee0e1b..40e1a175fceb 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/ethernet/i825xx/3c505.c
@@ -1363,7 +1363,7 @@ static const struct net_device_ops elp_netdev_ops = {
.ndo_get_stats = elp_get_stats,
.ndo_start_xmit = elp_start_xmit,
.ndo_tx_timeout = elp_timeout,
- .ndo_set_multicast_list = elp_set_mc_list,
+ .ndo_set_rx_mode = elp_set_mc_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/3c505.h b/drivers/net/ethernet/i825xx/3c505.h
index 04df2a9002b6..04df2a9002b6 100644
--- a/drivers/net/3c505.h
+++ b/drivers/net/ethernet/i825xx/3c505.h
diff --git a/drivers/net/3c507.c b/drivers/net/ethernet/i825xx/3c507.c
index 1e945551c144..1e945551c144 100644
--- a/drivers/net/3c507.c
+++ b/drivers/net/ethernet/i825xx/3c507.c
diff --git a/drivers/net/3c523.c b/drivers/net/ethernet/i825xx/3c523.c
index bc0d1a1c2e28..d70d3df4c985 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/ethernet/i825xx/3c523.c
@@ -409,7 +409,7 @@ static const struct net_device_ops netdev_ops = {
.ndo_start_xmit = elmc_send_packet,
.ndo_tx_timeout = elmc_timeout,
#ifdef ELMC_MULTICAST
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
#endif
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/3c523.h b/drivers/net/ethernet/i825xx/3c523.h
index 6956441687b9..6956441687b9 100644
--- a/drivers/net/3c523.h
+++ b/drivers/net/ethernet/i825xx/3c523.h
diff --git a/drivers/net/3c527.c b/drivers/net/ethernet/i825xx/3c527.c
index d9d056d207f3..474b5e71a53a 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/ethernet/i825xx/3c527.c
@@ -292,7 +292,7 @@ static const struct net_device_ops netdev_ops = {
.ndo_stop = mc32_close,
.ndo_start_xmit = mc32_send_packet,
.ndo_get_stats = mc32_get_stats,
- .ndo_set_multicast_list = mc32_set_multicast_list,
+ .ndo_set_rx_mode = mc32_set_multicast_list,
.ndo_tx_timeout = mc32_timeout,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/3c527.h b/drivers/net/ethernet/i825xx/3c527.h
index d693b8d15cde..d693b8d15cde 100644
--- a/drivers/net/3c527.h
+++ b/drivers/net/ethernet/i825xx/3c527.h
diff --git a/drivers/net/82596.c b/drivers/net/ethernet/i825xx/82596.c
index be1f1970c842..f2408a4d5d9c 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/ethernet/i825xx/82596.c
@@ -1145,7 +1145,7 @@ static const struct net_device_ops i596_netdev_ops = {
.ndo_open = i596_open,
.ndo_stop = i596_close,
.ndo_start_xmit = i596_start_xmit,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_tx_timeout = i596_tx_timeout,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/ethernet/i825xx/Kconfig b/drivers/net/ethernet/i825xx/Kconfig
new file mode 100644
index 000000000000..2be46986cbe2
--- /dev/null
+++ b/drivers/net/ethernet/i825xx/Kconfig
@@ -0,0 +1,183 @@
+#
+# Intel 82596/82593/82596 network device configuration
+#
+
+config NET_VENDOR_I825XX
+ bool "Intel (82586/82593/82596) devices"
+ default y
+ depends on NET_VENDOR_INTEL && (ISA || ISA_DMA_API || ARM || \
+ ARCH_ACORN || MCA || MCA_LEGACY || SNI_RM || SUN3 || \
+ GSC || BVME6000 || MVME16x || EXPERIMENTAL)
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question does not directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about these devices. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_I825XX
+
+config ELPLUS
+ tristate "3c505 \"EtherLink Plus\" support"
+ depends on ISA && ISA_DMA_API
+ ---help---
+ Information about this network (Ethernet) card can be found in
+ <file:Documentation/networking/3c505.txt>. If you have a card of
+ this type, say Y and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called 3c505.
+
+config EL16
+ tristate "3c507 \"EtherLink 16\" support (EXPERIMENTAL)"
+ depends on ISA && EXPERIMENTAL
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called 3c507.
+
+config ELMC
+ tristate "3c523 \"EtherLink/MC\" support"
+ depends on MCA_LEGACY
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called 3c523.
+
+config ELMC_II
+ tristate "3c527 \"EtherLink/MC 32\" support (EXPERIMENTAL)"
+ depends on MCA && MCA_LEGACY
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called 3c527.
+
+config ARM_ETHER1
+ tristate "Acorn Ether1 support"
+ depends on ARM && ARCH_ACORN
+ ---help---
+ If you have an Acorn system with one of these (AKA25) network cards,
+ you should say Y to this option if you wish to use it with Linux.
+
+config APRICOT
+ tristate "Apricot Xen-II on board Ethernet"
+ depends on ISA
+ ---help---
+ If you have a network (Ethernet) controller of this type, say Y and
+ read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called apricot.
+
+config BVME6000_NET
+ tristate "BVME6000 Ethernet support"
+ depends on BVME6000MVME16x
+ ---help---
+ This is the driver for the Ethernet interface on BVME4000 and
+ BVME6000 VME boards. Say Y here to include the driver for this chip
+ in your kernel.
+ To compile this driver as a module, choose M here.
+
+config EEXPRESS
+ tristate "EtherExpress 16 support"
+ depends on ISA
+ ---help---
+ If you have an EtherExpress16 network (Ethernet) card, say Y and
+ read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>. Note that the Intel
+ EtherExpress16 card used to be regarded as a very poor choice
+ because the driver was very unreliable. We now have a new driver
+ that should do better.
+
+ To compile this driver as a module, choose M here. The module
+ will be called eexpress.
+
+config EEXPRESS_PRO
+ tristate "EtherExpressPro support/EtherExpress 10 (i82595) support"
+ depends on ISA
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y. This
+ driver supports Intel i82595{FX,TX} based boards. Note however
+ that the EtherExpress PRO/100 Ethernet card has its own separate
+ driver. Please read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called eepro.
+
+config LASI_82596
+ tristate "Lasi ethernet"
+ depends on GSC
+ ---help---
+ Say Y here to support the builtin Intel 82596 ethernet controller
+ found in Hewlett-Packard PA-RISC machines with 10Mbit ethernet.
+
+config LP486E
+ tristate "LP486E on board Ethernet"
+ depends on ISA
+ ---help---
+ Say Y here to support the 82596-based on-board Ethernet controller
+ for the Panther motherboard, which is one of the two shipped in the
+ Intel Professional Workstation.
+
+config MVME16x_NET
+ tristate "MVME16x Ethernet support"
+ depends on MVME16x
+ ---help---
+ This is the driver for the Ethernet interface on the Motorola
+ MVME162, 166, 167, 172 and 177 boards. Say Y here to include the
+ driver for this chip in your kernel.
+ To compile this driver as a module, choose M here.
+
+config NI52
+ tristate "NI5210 support"
+ depends on ISA
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called ni52.
+
+config SNI_82596
+ tristate "SNI RM ethernet"
+ depends on SNI_RM
+ ---help---
+ Say Y here to support the on-board Intel 82596 ethernet controller
+ built into SNI RM machines.
+
+config SUN3_82586
+ bool "Sun3 on-board Intel 82586 support"
+ depends on SUN3
+ ---help---
+ This driver enables support for the on-board Intel 82586 based
+ Ethernet adapter found on Sun 3/1xx and 3/2xx motherboards. Note
+ that this driver does not support 82586-based adapters on additional
+ VME boards.
+
+config ZNET
+ tristate "Zenith Z-Note support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && ISA_DMA_API
+ ---help---
+ The Zenith Z-Note notebook computer has a built-in network
+ (Ethernet) card, and this is the Linux driver for it. Note that the
+ IBM Thinkpad 300 is compatible with the Z-Note and is also supported
+ by this driver. Read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+endif # NET_VENDOR_I825XX
diff --git a/drivers/net/ethernet/i825xx/Makefile b/drivers/net/ethernet/i825xx/Makefile
new file mode 100644
index 000000000000..f68a3694968a
--- /dev/null
+++ b/drivers/net/ethernet/i825xx/Makefile
@@ -0,0 +1,20 @@
+#
+# Makefile for the Intel 82586/82593/82596 chipset device drivers.
+#
+
+obj-$(CONFIG_ARM_ETHER1) += ether1.o
+obj-$(CONFIG_EEXPRESS) += eexpress.o
+obj-$(CONFIG_EEXPRESS_PRO) += eepro.o
+obj-$(CONFIG_ELPLUS) += 3c505.o
+obj-$(CONFIG_EL16) += 3c507.o
+obj-$(CONFIG_ELMC) += 3c523.o
+obj-$(CONFIG_ELMC_II) += 3c527.o
+obj-$(CONFIG_LP486E) += lp486e.o
+obj-$(CONFIG_NI52) += ni52.o
+obj-$(CONFIG_SUN3_82586) += sun3_82586.o
+obj-$(CONFIG_ZNET) += znet.o
+obj-$(CONFIG_APRICOT) += 82596.o
+obj-$(CONFIG_LASI_82596) += lasi_82596.o
+obj-$(CONFIG_SNI_82596) += sni_82596.o
+obj-$(CONFIG_MVME16x_NET) += 82596.o
+obj-$(CONFIG_BVME6000_NET) += 82596.o
diff --git a/drivers/net/eepro.c b/drivers/net/ethernet/i825xx/eepro.c
index dfeb006035df..067c46069a11 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/ethernet/i825xx/eepro.c
@@ -743,7 +743,7 @@ static const struct net_device_ops eepro_netdev_ops = {
.ndo_open = eepro_open,
.ndo_stop = eepro_close,
.ndo_start_xmit = eepro_send_packet,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_tx_timeout = eepro_tx_timeout,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/eexpress.c b/drivers/net/ethernet/i825xx/eexpress.c
index a19228563efd..3a9580f3d4dd 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/ethernet/i825xx/eexpress.c
@@ -1047,7 +1047,7 @@ static const struct net_device_ops eexp_netdev_ops = {
.ndo_open = eexp_open,
.ndo_stop = eexp_close,
.ndo_start_xmit = eexp_xmit,
- .ndo_set_multicast_list = eexp_set_multicast,
+ .ndo_set_rx_mode = eexp_set_multicast,
.ndo_tx_timeout = eexp_timeout,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/eexpress.h b/drivers/net/ethernet/i825xx/eexpress.h
index dc9c6ea289e9..dc9c6ea289e9 100644
--- a/drivers/net/eexpress.h
+++ b/drivers/net/ethernet/i825xx/eexpress.h
diff --git a/drivers/net/arm/ether1.c b/drivers/net/ethernet/i825xx/ether1.c
index b00781c02d5d..42e90a97c7a5 100644
--- a/drivers/net/arm/ether1.c
+++ b/drivers/net/ethernet/i825xx/ether1.c
@@ -985,7 +985,7 @@ static const struct net_device_ops ether1_netdev_ops = {
.ndo_open = ether1_open,
.ndo_stop = ether1_close,
.ndo_start_xmit = ether1_sendpacket,
- .ndo_set_multicast_list = ether1_setmulticastlist,
+ .ndo_set_rx_mode = ether1_setmulticastlist,
.ndo_tx_timeout = ether1_timeout,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/arm/ether1.h b/drivers/net/ethernet/i825xx/ether1.h
index 3a5830ab3dc7..3a5830ab3dc7 100644
--- a/drivers/net/arm/ether1.h
+++ b/drivers/net/ethernet/i825xx/ether1.h
diff --git a/drivers/net/lasi_82596.c b/drivers/net/ethernet/i825xx/lasi_82596.c
index 6eba352c52e0..6eba352c52e0 100644
--- a/drivers/net/lasi_82596.c
+++ b/drivers/net/ethernet/i825xx/lasi_82596.c
diff --git a/drivers/net/lib82596.c b/drivers/net/ethernet/i825xx/lib82596.c
index 9e042894479b..3efbd8dbb63d 100644
--- a/drivers/net/lib82596.c
+++ b/drivers/net/ethernet/i825xx/lib82596.c
@@ -1038,7 +1038,7 @@ static const struct net_device_ops i596_netdev_ops = {
.ndo_open = i596_open,
.ndo_stop = i596_close,
.ndo_start_xmit = i596_start_xmit,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_tx_timeout = i596_tx_timeout,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/lp486e.c b/drivers/net/ethernet/i825xx/lp486e.c
index 385a95311cd2..414044b3cb11 100644
--- a/drivers/net/lp486e.c
+++ b/drivers/net/ethernet/i825xx/lp486e.c
@@ -954,7 +954,7 @@ static const struct net_device_ops i596_netdev_ops = {
.ndo_open = i596_open,
.ndo_stop = i596_close,
.ndo_start_xmit = i596_start_xmit,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_tx_timeout = i596_tx_timeout,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/ni52.c b/drivers/net/ethernet/i825xx/ni52.c
index d973fc6c6b88..c0893715ef47 100644
--- a/drivers/net/ni52.c
+++ b/drivers/net/ethernet/i825xx/ni52.c
@@ -445,7 +445,7 @@ static const struct net_device_ops ni52_netdev_ops = {
.ndo_get_stats = ni52_get_stats,
.ndo_tx_timeout = ni52_timeout,
.ndo_start_xmit = ni52_send_packet,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/ni52.h b/drivers/net/ethernet/i825xx/ni52.h
index 0a03b2883327..0a03b2883327 100644
--- a/drivers/net/ni52.h
+++ b/drivers/net/ethernet/i825xx/ni52.h
diff --git a/drivers/net/sni_82596.c b/drivers/net/ethernet/i825xx/sni_82596.c
index 6b2a88817473..6b2a88817473 100644
--- a/drivers/net/sni_82596.c
+++ b/drivers/net/ethernet/i825xx/sni_82596.c
diff --git a/drivers/net/sun3_82586.c b/drivers/net/ethernet/i825xx/sun3_82586.c
index b6ae53bada75..6ef5e11d1c84 100644
--- a/drivers/net/sun3_82586.c
+++ b/drivers/net/ethernet/i825xx/sun3_82586.c
@@ -333,7 +333,7 @@ static const struct net_device_ops sun3_82586_netdev_ops = {
.ndo_open = sun3_82586_open,
.ndo_stop = sun3_82586_close,
.ndo_start_xmit = sun3_82586_send_packet,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_tx_timeout = sun3_82586_timeout,
.ndo_get_stats = sun3_82586_get_stats,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/sun3_82586.h b/drivers/net/ethernet/i825xx/sun3_82586.h
index 93346f00486b..93346f00486b 100644
--- a/drivers/net/sun3_82586.h
+++ b/drivers/net/ethernet/i825xx/sun3_82586.h
diff --git a/drivers/net/znet.c b/drivers/net/ethernet/i825xx/znet.c
index 8b8881718f5e..962b4c421f3f 100644
--- a/drivers/net/znet.c
+++ b/drivers/net/ethernet/i825xx/znet.c
@@ -356,7 +356,7 @@ static const struct net_device_ops znet_netdev_ops = {
.ndo_open = znet_open,
.ndo_stop = znet_close,
.ndo_start_xmit = znet_send_packet,
- .ndo_set_multicast_list = znet_set_multicast_list,
+ .ndo_set_rx_mode = znet_set_multicast_list,
.ndo_tx_timeout = znet_tx_timeout,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/ethernet/ibm/Kconfig b/drivers/net/ethernet/ibm/Kconfig
new file mode 100644
index 000000000000..9e16f3fa97b2
--- /dev/null
+++ b/drivers/net/ethernet/ibm/Kconfig
@@ -0,0 +1,48 @@
+#
+# IBM device configuration.
+#
+
+config NET_VENDOR_IBM
+ bool "IBM devices"
+ default y
+ depends on MCA || PPC_PSERIES || PPC_PSERIES || PPC_DCR || \
+ (IBMEBUS && INET && SPARSEMEM)
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about IBM devices. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_IBM
+
+config IBMVETH
+ tristate "IBM LAN Virtual Ethernet support"
+ depends on PPC_PSERIES
+ ---help---
+ This driver supports virtual ethernet adapters on newer IBM iSeries
+ and pSeries systems.
+
+ To compile this driver as a module, choose M here. The module will
+ be called ibmveth.
+
+config ISERIES_VETH
+ tristate "iSeries Virtual Ethernet driver support"
+ depends on PPC_ISERIES
+
+source "drivers/net/ethernet/ibm/emac/Kconfig"
+
+config EHEA
+ tristate "eHEA Ethernet support"
+ depends on IBMEBUS && INET && SPARSEMEM
+ select INET_LRO
+ ---help---
+ This driver supports the IBM pSeries eHEA ethernet adapter.
+
+ To compile the driver as a module, choose M here. The module
+ will be called ehea.
+
+endif # NET_VENDOR_IBM
diff --git a/drivers/net/ethernet/ibm/Makefile b/drivers/net/ethernet/ibm/Makefile
new file mode 100644
index 000000000000..5a7d4e9ac803
--- /dev/null
+++ b/drivers/net/ethernet/ibm/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for th IBM network device drivers.
+#
+
+obj-$(CONFIG_IBMVETH) += ibmveth.o
+obj-$(CONFIG_ISERIES_VETH) += iseries_veth.o
+obj-$(CONFIG_IBM_EMAC) += emac/
+obj-$(CONFIG_EHEA) += ehea/
diff --git a/drivers/net/ehea/Makefile b/drivers/net/ethernet/ibm/ehea/Makefile
index 775d9969b5c2..775d9969b5c2 100644
--- a/drivers/net/ehea/Makefile
+++ b/drivers/net/ethernet/ibm/ehea/Makefile
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ethernet/ibm/ehea/ehea.h
index 7dd5e6a0d998..410d6a1984ed 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ethernet/ibm/ehea/ehea.h
@@ -33,7 +33,6 @@
#include <linux/ethtool.h>
#include <linux/vmalloc.h>
#include <linux/if_vlan.h>
-#include <linux/inet_lro.h>
#include <asm/ibmebus.h>
#include <asm/abs_addr.h>
@@ -58,8 +57,6 @@
#define EHEA_MIN_ENTRIES_QP 127
#define EHEA_SMALL_QUEUES
-#define EHEA_NUM_TX_QP 1
-#define EHEA_LRO_MAX_AGGR 64
#ifdef EHEA_SMALL_QUEUES
#define EHEA_MAX_CQE_COUNT 1023
@@ -83,18 +80,16 @@
#define EHEA_SG_RQ3 0
#define EHEA_MAX_PACKET_SIZE 9022 /* for jumbo frames */
-#define EHEA_RQ2_PKT_SIZE 1522
+#define EHEA_RQ2_PKT_SIZE 2048
#define EHEA_L_PKT_SIZE 256 /* low latency */
-#define MAX_LRO_DESCRIPTORS 8
-
/* Send completion signaling */
/* Protection Domain Identifier */
#define EHEA_PD_ID 0xaabcdeff
#define EHEA_RQ2_THRESHOLD 1
-#define EHEA_RQ3_THRESHOLD 9 /* use RQ3 threshold of 1522 bytes */
+#define EHEA_RQ3_THRESHOLD 4 /* use RQ3 threshold of 2048 bytes */
#define EHEA_SPEED_10G 10000
#define EHEA_SPEED_1G 1000
@@ -363,7 +358,6 @@ struct ehea_port_res {
struct port_stats p_stats;
struct ehea_mr send_mr; /* send memory region */
struct ehea_mr recv_mr; /* receive memory region */
- spinlock_t xmit_lock;
struct ehea_port *port;
char int_recv_name[EHEA_IRQ_NAME_SIZE];
char int_send_name[EHEA_IRQ_NAME_SIZE];
@@ -376,8 +370,6 @@ struct ehea_port_res {
struct ehea_q_skb_arr rq3_skba;
struct ehea_q_skb_arr sq_skba;
int sq_skba_size;
- spinlock_t netif_queue;
- int queue_stopped;
int swqe_refill_th;
atomic_t swqe_avail;
int swqe_ll_count;
@@ -386,9 +378,6 @@ struct ehea_port_res {
u64 tx_bytes;
u64 rx_packets;
u64 rx_bytes;
- u32 poll_counter;
- struct net_lro_mgr lro_mgr;
- struct net_lro_desc lro_desc[MAX_LRO_DESCRIPTORS];
int sq_restart_flag;
};
@@ -453,18 +442,17 @@ struct ehea_bcmc_reg_array {
struct ehea_port {
struct ehea_adapter *adapter; /* adapter that owns this port */
struct net_device *netdev;
- struct net_device_stats stats;
+ struct rtnl_link_stats64 stats;
struct ehea_port_res port_res[EHEA_MAX_PORT_RES];
struct platform_device ofdev; /* Open Firmware Device */
struct ehea_mc_list *mc_list; /* Multicast MAC addresses */
struct ehea_eq *qp_eq;
struct work_struct reset_task;
+ struct delayed_work stats_work;
struct mutex port_lock;
char int_aff_name[EHEA_IRQ_NAME_SIZE];
int allmulti; /* Indicates IFF_ALLMULTI state */
int promisc; /* Indicates IFF_PROMISC state */
- int num_tx_qps;
- int num_add_tx_qps;
int num_mcs;
int resets;
unsigned long flags;
@@ -474,7 +462,6 @@ struct ehea_port {
u32 msg_enable;
u32 sig_comp_iv;
u32 state;
- u32 lro_max_aggr;
u8 phy_link;
u8 full_duplex;
u8 autoneg;
diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ethernet/ibm/ehea/ehea_ethtool.c
index 7f642aef5e82..05b7359bde8d 100644
--- a/drivers/net/ehea/ehea_ethtool.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_ethtool.c
@@ -180,7 +180,7 @@ static void ehea_set_msglevel(struct net_device *dev, u32 value)
port->msg_enable = value;
}
-static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = {
+static const char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = {
{"sig_comp_iv"},
{"swqe_refill_th"},
{"port resets"},
@@ -189,7 +189,6 @@ static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = {
{"IP cksum errors"},
{"Frame cksum errors"},
{"num SQ stopped"},
- {"SQ stopped"},
{"PR0 free_swqes"},
{"PR1 free_swqes"},
{"PR2 free_swqes"},
@@ -198,9 +197,14 @@ static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = {
{"PR5 free_swqes"},
{"PR6 free_swqes"},
{"PR7 free_swqes"},
- {"LRO aggregated"},
- {"LRO flushed"},
- {"LRO no_desc"},
+ {"PR8 free_swqes"},
+ {"PR9 free_swqes"},
+ {"PR10 free_swqes"},
+ {"PR11 free_swqes"},
+ {"PR12 free_swqes"},
+ {"PR13 free_swqes"},
+ {"PR14 free_swqes"},
+ {"PR15 free_swqes"},
};
static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data)
@@ -255,25 +259,8 @@ static void ehea_get_ethtool_stats(struct net_device *dev,
tmp += port->port_res[k].p_stats.queue_stopped;
data[i++] = tmp;
- for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
- tmp |= port->port_res[k].queue_stopped;
- data[i++] = tmp;
-
- for (k = 0; k < 8; k++)
+ for (k = 0; k < 16; k++)
data[i++] = atomic_read(&port->port_res[k].swqe_avail);
-
- for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
- tmp |= port->port_res[k].lro_mgr.stats.aggregated;
- data[i++] = tmp;
-
- for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
- tmp |= port->port_res[k].lro_mgr.stats.flushed;
- data[i++] = tmp;
-
- for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
- tmp |= port->port_res[k].lro_mgr.stats.no_desc;
- data[i++] = tmp;
-
}
const struct ethtool_ops ehea_ethtool_ops = {
diff --git a/drivers/net/ehea/ehea_hw.h b/drivers/net/ethernet/ibm/ehea/ehea_hw.h
index 567981b4b2cc..1a2fe4dc3eb3 100644
--- a/drivers/net/ehea/ehea_hw.h
+++ b/drivers/net/ethernet/ibm/ehea/ehea_hw.h
@@ -210,36 +210,11 @@ static inline void epa_store_acc(struct h_epa epa, u32 offset, u64 value)
__raw_writeq(value, (void __iomem *)(epa.addr + offset));
}
-#define epa_store_eq(epa, offset, value)\
- epa_store(epa, EQTEMM_OFFSET(offset), value)
-#define epa_load_eq(epa, offset)\
- epa_load(epa, EQTEMM_OFFSET(offset))
-
#define epa_store_cq(epa, offset, value)\
epa_store(epa, CQTEMM_OFFSET(offset), value)
#define epa_load_cq(epa, offset)\
epa_load(epa, CQTEMM_OFFSET(offset))
-#define epa_store_qp(epa, offset, value)\
- epa_store(epa, QPTEMM_OFFSET(offset), value)
-#define epa_load_qp(epa, offset)\
- epa_load(epa, QPTEMM_OFFSET(offset))
-
-#define epa_store_qped(epa, offset, value)\
- epa_store(epa, QPEDMM_OFFSET(offset), value)
-#define epa_load_qped(epa, offset)\
- epa_load(epa, QPEDMM_OFFSET(offset))
-
-#define epa_store_mrmw(epa, offset, value)\
- epa_store(epa, MRMWMM_OFFSET(offset), value)
-#define epa_load_mrmw(epa, offset)\
- epa_load(epa, MRMWMM_OFFSET(offset))
-
-#define epa_store_base(epa, offset, value)\
- epa_store(epa, HCAGR_OFFSET(offset), value)
-#define epa_load_base(epa, offset)\
- epa_load(epa, HCAGR_OFFSET(offset))
-
static inline void ehea_update_sqa(struct ehea_qp *qp, u16 nr_wqes)
{
struct h_epa epa = qp->epas.kernel;
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c
index be2cb4ab8b4f..37b70f7052b6 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c
@@ -61,10 +61,7 @@ static int rq1_entries = EHEA_DEF_ENTRIES_RQ1;
static int rq2_entries = EHEA_DEF_ENTRIES_RQ2;
static int rq3_entries = EHEA_DEF_ENTRIES_RQ3;
static int sq_entries = EHEA_DEF_ENTRIES_SQ;
-static int use_mcs;
-static int use_lro;
-static int lro_max_aggr = EHEA_LRO_MAX_AGGR;
-static int num_tx_qps = EHEA_NUM_TX_QP;
+static int use_mcs = 1;
static int prop_carrier_state;
module_param(msg_level, int, 0);
@@ -74,11 +71,7 @@ module_param(rq3_entries, int, 0);
module_param(sq_entries, int, 0);
module_param(prop_carrier_state, int, 0);
module_param(use_mcs, int, 0);
-module_param(use_lro, int, 0);
-module_param(lro_max_aggr, int, 0);
-module_param(num_tx_qps, int, 0);
-MODULE_PARM_DESC(num_tx_qps, "Number of TX-QPS");
MODULE_PARM_DESC(msg_level, "msg_level");
MODULE_PARM_DESC(prop_carrier_state, "Propagate carrier state of physical "
"port to stack. 1:yes, 0:no. Default = 0 ");
@@ -94,12 +87,8 @@ MODULE_PARM_DESC(rq1_entries, "Number of entries for Receive Queue 1 "
MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue "
"[2^x - 1], x = [6..14]. Default = "
__MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")");
-MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 0 ");
-
-MODULE_PARM_DESC(lro_max_aggr, " LRO: Max packets to be aggregated. Default = "
- __MODULE_STRING(EHEA_LRO_MAX_AGGR));
-MODULE_PARM_DESC(use_lro, " Large Receive Offload, 1: enable, 0: disable, "
- "Default = 0");
+MODULE_PARM_DESC(use_mcs, " Multiple receive queues, 1: enable, 0: disable, "
+ "Default = 1");
static int port_name_cnt;
static LIST_HEAD(adapter_list);
@@ -173,7 +162,7 @@ static void ehea_update_firmware_handles(void)
continue;
num_ports++;
- num_portres += port->num_def_qps + port->num_add_tx_qps;
+ num_portres += port->num_def_qps;
}
}
@@ -199,9 +188,7 @@ static void ehea_update_firmware_handles(void)
(num_ports == 0))
continue;
- for (l = 0;
- l < port->num_def_qps + port->num_add_tx_qps;
- l++) {
+ for (l = 0; l < port->num_def_qps; l++) {
struct ehea_port_res *pr = &port->port_res[l];
arr[i].adh = adapter->handle;
@@ -327,20 +314,44 @@ out:
spin_unlock_irqrestore(&ehea_bcmc_regs.lock, flags);
}
-static struct net_device_stats *ehea_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *ehea_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *stats)
{
struct ehea_port *port = netdev_priv(dev);
- struct net_device_stats *stats = &port->stats;
- struct hcp_ehea_port_cb2 *cb2;
- u64 hret, rx_packets, tx_packets, rx_bytes = 0, tx_bytes = 0;
+ u64 rx_packets = 0, tx_packets = 0, rx_bytes = 0, tx_bytes = 0;
int i;
- memset(stats, 0, sizeof(*stats));
+ for (i = 0; i < port->num_def_qps; i++) {
+ rx_packets += port->port_res[i].rx_packets;
+ rx_bytes += port->port_res[i].rx_bytes;
+ }
+
+ for (i = 0; i < port->num_def_qps; i++) {
+ tx_packets += port->port_res[i].tx_packets;
+ tx_bytes += port->port_res[i].tx_bytes;
+ }
+
+ stats->tx_packets = tx_packets;
+ stats->rx_bytes = rx_bytes;
+ stats->tx_bytes = tx_bytes;
+ stats->rx_packets = rx_packets;
+
+ return &port->stats;
+}
+
+static void ehea_update_stats(struct work_struct *work)
+{
+ struct ehea_port *port =
+ container_of(work, struct ehea_port, stats_work.work);
+ struct net_device *dev = port->netdev;
+ struct rtnl_link_stats64 *stats = &port->stats;
+ struct hcp_ehea_port_cb2 *cb2;
+ u64 hret;
cb2 = (void *)get_zeroed_page(GFP_KERNEL);
if (!cb2) {
- netdev_err(dev, "no mem for cb2\n");
- goto out;
+ netdev_err(dev, "No mem for cb2. Some interface statistics were not updated\n");
+ goto resched;
}
hret = ehea_h_query_ehea_port(port->adapter->handle,
@@ -354,29 +365,13 @@ static struct net_device_stats *ehea_get_stats(struct net_device *dev)
if (netif_msg_hw(port))
ehea_dump(cb2, sizeof(*cb2), "net_device_stats");
- rx_packets = 0;
- for (i = 0; i < port->num_def_qps; i++) {
- rx_packets += port->port_res[i].rx_packets;
- rx_bytes += port->port_res[i].rx_bytes;
- }
-
- tx_packets = 0;
- for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
- tx_packets += port->port_res[i].tx_packets;
- tx_bytes += port->port_res[i].tx_bytes;
- }
-
- stats->tx_packets = tx_packets;
stats->multicast = cb2->rxmcp;
stats->rx_errors = cb2->rxuerr;
- stats->rx_bytes = rx_bytes;
- stats->tx_bytes = tx_bytes;
- stats->rx_packets = rx_packets;
out_herr:
free_page((unsigned long)cb2);
-out:
- return stats;
+resched:
+ schedule_delayed_work(&port->stats_work, msecs_to_jiffies(1000));
}
static void ehea_refill_rq1(struct ehea_port_res *pr, int index, int nr_of_wqes)
@@ -543,7 +538,8 @@ static inline int ehea_check_cqe(struct ehea_cqe *cqe, int *rq_num)
}
static inline void ehea_fill_skb(struct net_device *dev,
- struct sk_buff *skb, struct ehea_cqe *cqe)
+ struct sk_buff *skb, struct ehea_cqe *cqe,
+ struct ehea_port_res *pr)
{
int length = cqe->num_bytes_transfered - 4; /*remove CRC */
@@ -557,6 +553,8 @@ static inline void ehea_fill_skb(struct net_device *dev,
skb->csum = csum_unfold(~cqe->inet_checksum_value);
} else
skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ skb_record_rx_queue(skb, pr - &pr->port->port_res[0]);
}
static inline struct sk_buff *get_skb_by_index(struct sk_buff **skb_array,
@@ -649,49 +647,6 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq,
return 0;
}
-static int get_skb_hdr(struct sk_buff *skb, void **iphdr,
- void **tcph, u64 *hdr_flags, void *priv)
-{
- struct ehea_cqe *cqe = priv;
- unsigned int ip_len;
- struct iphdr *iph;
-
- /* non tcp/udp packets */
- if (!cqe->header_length)
- return -1;
-
- /* non tcp packet */
- skb_reset_network_header(skb);
- iph = ip_hdr(skb);
- if (iph->protocol != IPPROTO_TCP)
- return -1;
-
- ip_len = ip_hdrlen(skb);
- skb_set_transport_header(skb, ip_len);
- *tcph = tcp_hdr(skb);
-
- /* check if ip header and tcp header are complete */
- if (ntohs(iph->tot_len) < ip_len + tcp_hdrlen(skb))
- return -1;
-
- *hdr_flags = LRO_IPV4 | LRO_TCP;
- *iphdr = iph;
-
- return 0;
-}
-
-static void ehea_proc_skb(struct ehea_port_res *pr, struct ehea_cqe *cqe,
- struct sk_buff *skb)
-{
- if (cqe->status & EHEA_CQE_VLAN_TAG_XTRACT)
- __vlan_hwaccel_put_tag(skb, cqe->vlan_tag);
-
- if (skb->dev->features & NETIF_F_LRO)
- lro_receive_skb(&pr->lro_mgr, skb, cqe);
- else
- netif_receive_skb(skb);
-}
-
static int ehea_proc_rwqes(struct net_device *dev,
struct ehea_port_res *pr,
int budget)
@@ -742,7 +697,7 @@ static int ehea_proc_rwqes(struct net_device *dev,
}
skb_copy_to_linear_data(skb, ((char *)cqe) + 64,
cqe->num_bytes_transfered - 4);
- ehea_fill_skb(dev, skb, cqe);
+ ehea_fill_skb(dev, skb, cqe, pr);
} else if (rq == 2) {
/* RQ2 */
skb = get_skb_by_index(skb_arr_rq2,
@@ -752,7 +707,7 @@ static int ehea_proc_rwqes(struct net_device *dev,
"rq2: skb=NULL\n");
break;
}
- ehea_fill_skb(dev, skb, cqe);
+ ehea_fill_skb(dev, skb, cqe, pr);
processed_rq2++;
} else {
/* RQ3 */
@@ -763,12 +718,16 @@ static int ehea_proc_rwqes(struct net_device *dev,
"rq3: skb=NULL\n");
break;
}
- ehea_fill_skb(dev, skb, cqe);
+ ehea_fill_skb(dev, skb, cqe, pr);
processed_rq3++;
}
processed_bytes += skb->len;
- ehea_proc_skb(pr, cqe, skb);
+
+ if (cqe->status & EHEA_CQE_VLAN_TAG_XTRACT)
+ __vlan_hwaccel_put_tag(skb, cqe->vlan_tag);
+
+ napi_gro_receive(&pr->napi, skb);
} else {
pr->p_stats.poll_receive_errors++;
port_reset = ehea_treat_poll_error(pr, rq, cqe,
@@ -779,8 +738,6 @@ static int ehea_proc_rwqes(struct net_device *dev,
}
cqe = ehea_poll_rq1(qp, &wqe_index);
}
- if (dev->features & NETIF_F_LRO)
- lro_flush_all(&pr->lro_mgr);
pr->rx_packets += processed;
pr->rx_bytes += processed_bytes;
@@ -798,7 +755,7 @@ static void reset_sq_restart_flag(struct ehea_port *port)
{
int i;
- for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
+ for (i = 0; i < port->num_def_qps; i++) {
struct ehea_port_res *pr = &port->port_res[i];
pr->sq_restart_flag = 0;
}
@@ -811,7 +768,7 @@ static void check_sqs(struct ehea_port *port)
int swqe_index;
int i, k;
- for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
+ for (i = 0; i < port->num_def_qps; i++) {
struct ehea_port_res *pr = &port->port_res[i];
int ret;
k = 0;
@@ -849,7 +806,8 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
int cqe_counter = 0;
int swqe_av = 0;
int index;
- unsigned long flags;
+ struct netdev_queue *txq = netdev_get_tx_queue(pr->port->netdev,
+ pr - &pr->port->port_res[0]);
cqe = ehea_poll_cq(send_cq);
while (cqe && (quota > 0)) {
@@ -899,20 +857,20 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
ehea_update_feca(send_cq, cqe_counter);
atomic_add(swqe_av, &pr->swqe_avail);
- spin_lock_irqsave(&pr->netif_queue, flags);
-
- if (pr->queue_stopped && (atomic_read(&pr->swqe_avail)
- >= pr->swqe_refill_th)) {
- netif_wake_queue(pr->port->netdev);
- pr->queue_stopped = 0;
+ if (unlikely(netif_tx_queue_stopped(txq) &&
+ (atomic_read(&pr->swqe_avail) >= pr->swqe_refill_th))) {
+ __netif_tx_lock(txq, smp_processor_id());
+ if (netif_tx_queue_stopped(txq) &&
+ (atomic_read(&pr->swqe_avail) >= pr->swqe_refill_th))
+ netif_tx_wake_queue(txq);
+ __netif_tx_unlock(txq);
}
- spin_unlock_irqrestore(&pr->netif_queue, flags);
+
wake_up(&pr->port->swqe_avail_wq);
return cqe;
}
-#define EHEA_NAPI_POLL_NUM_BEFORE_IRQ 16
#define EHEA_POLL_MAX_CQES 65535
static int ehea_poll(struct napi_struct *napi, int budget)
@@ -922,18 +880,13 @@ static int ehea_poll(struct napi_struct *napi, int budget)
struct net_device *dev = pr->port->netdev;
struct ehea_cqe *cqe;
struct ehea_cqe *cqe_skb = NULL;
- int force_irq, wqe_index;
+ int wqe_index;
int rx = 0;
- force_irq = (pr->poll_counter > EHEA_NAPI_POLL_NUM_BEFORE_IRQ);
cqe_skb = ehea_proc_cqes(pr, EHEA_POLL_MAX_CQES);
+ rx += ehea_proc_rwqes(dev, pr, budget - rx);
- if (!force_irq)
- rx += ehea_proc_rwqes(dev, pr, budget - rx);
-
- while ((rx != budget) || force_irq) {
- pr->poll_counter = 0;
- force_irq = 0;
+ while (rx != budget) {
napi_complete(napi);
ehea_reset_cq_ep(pr->recv_cq);
ehea_reset_cq_ep(pr->send_cq);
@@ -953,7 +906,6 @@ static int ehea_poll(struct napi_struct *napi, int budget)
rx += ehea_proc_rwqes(dev, pr, budget - rx);
}
- pr->poll_counter++;
return rx;
}
@@ -1105,13 +1057,6 @@ int ehea_sense_port_attr(struct ehea_port *port)
goto out_free;
}
- port->num_tx_qps = num_tx_qps;
-
- if (port->num_def_qps >= port->num_tx_qps)
- port->num_add_tx_qps = 0;
- else
- port->num_add_tx_qps = port->num_tx_qps - port->num_def_qps;
-
ret = 0;
out_free:
if (ret || netif_msg_probe(port))
@@ -1243,7 +1188,7 @@ static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe)
netif_info(port, link, dev,
"Logical port down\n");
netif_carrier_off(dev);
- netif_stop_queue(dev);
+ netif_tx_disable(dev);
}
if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PORT_UP, eqe)) {
@@ -1274,7 +1219,7 @@ static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe)
case EHEA_EC_PORT_MALFUNC:
netdev_info(dev, "Port malfunction\n");
netif_carrier_off(dev);
- netif_stop_queue(dev);
+ netif_tx_disable(dev);
break;
default:
netdev_err(dev, "unknown event code %x, eqe=0x%llX\n", ec, eqe);
@@ -1352,7 +1297,7 @@ static int ehea_reg_interrupts(struct net_device *dev)
port->qp_eq->attr.ist1);
- for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
+ for (i = 0; i < port->num_def_qps; i++) {
pr = &port->port_res[i];
snprintf(pr->int_send_name, EHEA_IRQ_NAME_SIZE - 1,
"%s-queue%d", dev->name, i);
@@ -1395,7 +1340,7 @@ static void ehea_free_interrupts(struct net_device *dev)
/* send */
- for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
+ for (i = 0; i < port->num_def_qps; i++) {
pr = &port->port_res[i];
ibmebus_free_irq(pr->eq->attr.ist1, pr);
netif_info(port, intr, dev,
@@ -1526,8 +1471,6 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
pr->rx_packets = rx_packets;
pr->port = port;
- spin_lock_init(&pr->xmit_lock);
- spin_lock_init(&pr->netif_queue);
pr->eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0);
if (!pr->eq) {
@@ -1618,15 +1561,6 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
netif_napi_add(pr->port->netdev, &pr->napi, ehea_poll, 64);
- pr->lro_mgr.max_aggr = pr->port->lro_max_aggr;
- pr->lro_mgr.max_desc = MAX_LRO_DESCRIPTORS;
- pr->lro_mgr.lro_arr = pr->lro_desc;
- pr->lro_mgr.get_skb_header = get_skb_hdr;
- pr->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID;
- pr->lro_mgr.dev = port->netdev;
- pr->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
- pr->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
-
ret = 0;
goto out;
@@ -1683,96 +1617,35 @@ static int ehea_clean_portres(struct ehea_port *port, struct ehea_port_res *pr)
return ret;
}
-/*
- * The write_* functions store information in swqe which is used by
- * the hardware to calculate the ip/tcp/udp checksum
- */
-
-static inline void write_ip_start_end(struct ehea_swqe *swqe,
- const struct sk_buff *skb)
-{
- swqe->ip_start = skb_network_offset(skb);
- swqe->ip_end = (u8)(swqe->ip_start + ip_hdrlen(skb) - 1);
-}
-
-static inline void write_tcp_offset_end(struct ehea_swqe *swqe,
- const struct sk_buff *skb)
-{
- swqe->tcp_offset =
- (u8)(swqe->ip_end + 1 + offsetof(struct tcphdr, check));
-
- swqe->tcp_end = (u16)skb->len - 1;
-}
-
-static inline void write_udp_offset_end(struct ehea_swqe *swqe,
- const struct sk_buff *skb)
-{
- swqe->tcp_offset =
- (u8)(swqe->ip_end + 1 + offsetof(struct udphdr, check));
-
- swqe->tcp_end = (u16)skb->len - 1;
-}
-
-
-static void write_swqe2_TSO(struct sk_buff *skb,
- struct ehea_swqe *swqe, u32 lkey)
-{
- struct ehea_vsgentry *sg1entry = &swqe->u.immdata_desc.sg_entry;
- u8 *imm_data = &swqe->u.immdata_desc.immediate_data[0];
- int skb_data_size = skb_headlen(skb);
- int headersize;
-
- /* Packet is TCP with TSO enabled */
- swqe->tx_control |= EHEA_SWQE_TSO;
- swqe->mss = skb_shinfo(skb)->gso_size;
- /* copy only eth/ip/tcp headers to immediate data and
- * the rest of skb->data to sg1entry
- */
- headersize = ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb);
-
- skb_data_size = skb_headlen(skb);
-
- if (skb_data_size >= headersize) {
- /* copy immediate data */
- skb_copy_from_linear_data(skb, imm_data, headersize);
- swqe->immediate_data_length = headersize;
-
- if (skb_data_size > headersize) {
- /* set sg1entry data */
- sg1entry->l_key = lkey;
- sg1entry->len = skb_data_size - headersize;
- sg1entry->vaddr =
- ehea_map_vaddr(skb->data + headersize);
- swqe->descriptors++;
- }
- } else
- pr_err("cannot handle fragmented headers\n");
-}
-
-static void write_swqe2_nonTSO(struct sk_buff *skb,
- struct ehea_swqe *swqe, u32 lkey)
+static void write_swqe2_immediate(struct sk_buff *skb, struct ehea_swqe *swqe,
+ u32 lkey)
{
int skb_data_size = skb_headlen(skb);
u8 *imm_data = &swqe->u.immdata_desc.immediate_data[0];
struct ehea_vsgentry *sg1entry = &swqe->u.immdata_desc.sg_entry;
+ unsigned int immediate_len = SWQE2_MAX_IMM;
- /* Packet is any nonTSO type
- *
- * Copy as much as possible skb->data to immediate data and
- * the rest to sg1entry
- */
- if (skb_data_size >= SWQE2_MAX_IMM) {
- /* copy immediate data */
- skb_copy_from_linear_data(skb, imm_data, SWQE2_MAX_IMM);
+ swqe->descriptors = 0;
- swqe->immediate_data_length = SWQE2_MAX_IMM;
+ if (skb_is_gso(skb)) {
+ swqe->tx_control |= EHEA_SWQE_TSO;
+ swqe->mss = skb_shinfo(skb)->gso_size;
+ /*
+ * For TSO packets we only copy the headers into the
+ * immediate area.
+ */
+ immediate_len = ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb);
+ }
- if (skb_data_size > SWQE2_MAX_IMM) {
- /* copy sg1entry data */
+ if (skb_is_gso(skb) || skb_data_size >= SWQE2_MAX_IMM) {
+ skb_copy_from_linear_data(skb, imm_data, immediate_len);
+ swqe->immediate_data_length = immediate_len;
+
+ if (skb_data_size > immediate_len) {
sg1entry->l_key = lkey;
- sg1entry->len = skb_data_size - SWQE2_MAX_IMM;
+ sg1entry->len = skb_data_size - immediate_len;
sg1entry->vaddr =
- ehea_map_vaddr(skb->data + SWQE2_MAX_IMM);
+ ehea_map_vaddr(skb->data + immediate_len);
swqe->descriptors++;
}
} else {
@@ -1791,13 +1664,9 @@ static inline void write_swqe2_data(struct sk_buff *skb, struct net_device *dev,
nfrags = skb_shinfo(skb)->nr_frags;
sg1entry = &swqe->u.immdata_desc.sg_entry;
sg_list = (struct ehea_vsgentry *)&swqe->u.immdata_desc.sg_list;
- swqe->descriptors = 0;
sg1entry_contains_frag_data = 0;
- if ((dev->features & NETIF_F_TSO) && skb_shinfo(skb)->gso_size)
- write_swqe2_TSO(skb, swqe, lkey);
- else
- write_swqe2_nonTSO(skb, swqe, lkey);
+ write_swqe2_immediate(skb, swqe, lkey);
/* write descriptors */
if (nfrags > 0) {
@@ -1807,10 +1676,9 @@ static inline void write_swqe2_data(struct sk_buff *skb, struct net_device *dev,
/* copy sg1entry data */
sg1entry->l_key = lkey;
- sg1entry->len = frag->size;
+ sg1entry->len = skb_frag_size(frag);
sg1entry->vaddr =
- ehea_map_vaddr(page_address(frag->page)
- + frag->page_offset);
+ ehea_map_vaddr(skb_frag_address(frag));
swqe->descriptors++;
sg1entry_contains_frag_data = 1;
}
@@ -1821,10 +1689,8 @@ static inline void write_swqe2_data(struct sk_buff *skb, struct net_device *dev,
sgentry = &sg_list[i - sg1entry_contains_frag_data];
sgentry->l_key = lkey;
- sgentry->len = frag->size;
- sgentry->vaddr =
- ehea_map_vaddr(page_address(frag->page)
- + frag->page_offset);
+ sgentry->len = skb_frag_size(frag);
+ sgentry->vaddr = ehea_map_vaddr(skb_frag_address(frag));
swqe->descriptors++;
}
}
@@ -2115,41 +1981,44 @@ static int ehea_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
-static void ehea_xmit2(struct sk_buff *skb, struct net_device *dev,
- struct ehea_swqe *swqe, u32 lkey)
+static void xmit_common(struct sk_buff *skb, struct ehea_swqe *swqe)
{
- if (skb->protocol == htons(ETH_P_IP)) {
- const struct iphdr *iph = ip_hdr(skb);
+ swqe->tx_control |= EHEA_SWQE_IMM_DATA_PRESENT | EHEA_SWQE_CRC;
+
+ if (skb->protocol != htons(ETH_P_IP))
+ return;
- /* IPv4 */
- swqe->tx_control |= EHEA_SWQE_CRC
- | EHEA_SWQE_IP_CHECKSUM
- | EHEA_SWQE_TCP_CHECKSUM
- | EHEA_SWQE_IMM_DATA_PRESENT
- | EHEA_SWQE_DESCRIPTORS_PRESENT;
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ swqe->tx_control |= EHEA_SWQE_IP_CHECKSUM;
- write_ip_start_end(swqe, skb);
+ swqe->ip_start = skb_network_offset(skb);
+ swqe->ip_end = swqe->ip_start + ip_hdrlen(skb) - 1;
- if (iph->protocol == IPPROTO_UDP) {
- if ((iph->frag_off & IP_MF) ||
- (iph->frag_off & IP_OFFSET))
- /* IP fragment, so don't change cs */
- swqe->tx_control &= ~EHEA_SWQE_TCP_CHECKSUM;
- else
- write_udp_offset_end(swqe, skb);
- } else if (iph->protocol == IPPROTO_TCP) {
- write_tcp_offset_end(swqe, skb);
- }
+ switch (ip_hdr(skb)->protocol) {
+ case IPPROTO_UDP:
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ swqe->tx_control |= EHEA_SWQE_TCP_CHECKSUM;
+
+ swqe->tcp_offset = swqe->ip_end + 1 +
+ offsetof(struct udphdr, check);
+ break;
- /* icmp (big data) and ip segmentation packets (all other ip
- packets) do not require any special handling */
+ case IPPROTO_TCP:
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ swqe->tx_control |= EHEA_SWQE_TCP_CHECKSUM;
- } else {
- /* Other Ethernet Protocol */
- swqe->tx_control |= EHEA_SWQE_CRC
- | EHEA_SWQE_IMM_DATA_PRESENT
- | EHEA_SWQE_DESCRIPTORS_PRESENT;
+ swqe->tcp_offset = swqe->ip_end + 1 +
+ offsetof(struct tcphdr, check);
+ break;
}
+}
+
+static void ehea_xmit2(struct sk_buff *skb, struct net_device *dev,
+ struct ehea_swqe *swqe, u32 lkey)
+{
+ swqe->tx_control |= EHEA_SWQE_DESCRIPTORS_PRESENT;
+
+ xmit_common(skb, swqe);
write_swqe2_data(skb, dev, swqe, lkey);
}
@@ -2157,107 +2026,30 @@ static void ehea_xmit2(struct sk_buff *skb, struct net_device *dev,
static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev,
struct ehea_swqe *swqe)
{
- int nfrags = skb_shinfo(skb)->nr_frags;
u8 *imm_data = &swqe->u.immdata_nodesc.immediate_data[0];
- skb_frag_t *frag;
- int i;
-
- if (skb->protocol == htons(ETH_P_IP)) {
- const struct iphdr *iph = ip_hdr(skb);
-
- /* IPv4 */
- write_ip_start_end(swqe, skb);
-
- if (iph->protocol == IPPROTO_TCP) {
- swqe->tx_control |= EHEA_SWQE_CRC
- | EHEA_SWQE_IP_CHECKSUM
- | EHEA_SWQE_TCP_CHECKSUM
- | EHEA_SWQE_IMM_DATA_PRESENT;
-
- write_tcp_offset_end(swqe, skb);
- } else if (iph->protocol == IPPROTO_UDP) {
- if ((iph->frag_off & IP_MF) ||
- (iph->frag_off & IP_OFFSET))
- /* IP fragment, so don't change cs */
- swqe->tx_control |= EHEA_SWQE_CRC
- | EHEA_SWQE_IMM_DATA_PRESENT;
- else {
- swqe->tx_control |= EHEA_SWQE_CRC
- | EHEA_SWQE_IP_CHECKSUM
- | EHEA_SWQE_TCP_CHECKSUM
- | EHEA_SWQE_IMM_DATA_PRESENT;
+ xmit_common(skb, swqe);
- write_udp_offset_end(swqe, skb);
- }
- } else {
- /* icmp (big data) and
- ip segmentation packets (all other ip packets) */
- swqe->tx_control |= EHEA_SWQE_CRC
- | EHEA_SWQE_IP_CHECKSUM
- | EHEA_SWQE_IMM_DATA_PRESENT;
- }
- } else {
- /* Other Ethernet Protocol */
- swqe->tx_control |= EHEA_SWQE_CRC | EHEA_SWQE_IMM_DATA_PRESENT;
- }
- /* copy (immediate) data */
- if (nfrags == 0) {
- /* data is in a single piece */
+ if (!skb->data_len)
skb_copy_from_linear_data(skb, imm_data, skb->len);
- } else {
- /* first copy data from the skb->data buffer ... */
- skb_copy_from_linear_data(skb, imm_data,
- skb_headlen(skb));
- imm_data += skb_headlen(skb);
+ else
+ skb_copy_bits(skb, 0, imm_data, skb->len);
- /* ... then copy data from the fragments */
- for (i = 0; i < nfrags; i++) {
- frag = &skb_shinfo(skb)->frags[i];
- memcpy(imm_data,
- page_address(frag->page) + frag->page_offset,
- frag->size);
- imm_data += frag->size;
- }
- }
swqe->immediate_data_length = skb->len;
dev_kfree_skb(skb);
}
-static inline int ehea_hash_skb(struct sk_buff *skb, int num_qps)
-{
- struct tcphdr *tcp;
- u32 tmp;
-
- if ((skb->protocol == htons(ETH_P_IP)) &&
- (ip_hdr(skb)->protocol == IPPROTO_TCP)) {
- tcp = (struct tcphdr *)(skb_network_header(skb) +
- (ip_hdr(skb)->ihl * 4));
- tmp = (tcp->source + (tcp->dest << 16)) % 31;
- tmp += ip_hdr(skb)->daddr % 31;
- return tmp % num_qps;
- } else
- return 0;
-}
-
static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ehea_port *port = netdev_priv(dev);
struct ehea_swqe *swqe;
- unsigned long flags;
u32 lkey;
int swqe_index;
struct ehea_port_res *pr;
+ struct netdev_queue *txq;
- pr = &port->port_res[ehea_hash_skb(skb, port->num_tx_qps)];
-
- if (!spin_trylock(&pr->xmit_lock))
- return NETDEV_TX_BUSY;
-
- if (pr->queue_stopped) {
- spin_unlock(&pr->xmit_lock);
- return NETDEV_TX_BUSY;
- }
+ pr = &port->port_res[skb_get_queue_mapping(skb)];
+ txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
swqe = ehea_get_swqe(pr->qp, &swqe_index);
memset(swqe, 0, SWQE_HEADER_SIZE);
@@ -2307,23 +2099,16 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
ehea_dump(swqe, 512, "swqe");
if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) {
- netif_stop_queue(dev);
+ netif_tx_stop_queue(txq);
swqe->tx_control |= EHEA_SWQE_PURGE;
}
ehea_post_swqe(pr->qp, swqe);
if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
- spin_lock_irqsave(&pr->netif_queue, flags);
- if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
- pr->p_stats.queue_stopped++;
- netif_stop_queue(dev);
- pr->queue_stopped = 1;
- }
- spin_unlock_irqrestore(&pr->netif_queue, flags);
+ pr->p_stats.queue_stopped++;
+ netif_tx_stop_queue(txq);
}
- dev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */
- spin_unlock(&pr->xmit_lock);
return NETDEV_TX_OK;
}
@@ -2468,8 +2253,7 @@ out:
return ret;
}
-static int ehea_port_res_setup(struct ehea_port *port, int def_qps,
- int add_tx_qps)
+static int ehea_port_res_setup(struct ehea_port *port, int def_qps)
{
int ret, i;
struct port_res_cfg pr_cfg, pr_cfg_small_rx;
@@ -2502,7 +2286,7 @@ static int ehea_port_res_setup(struct ehea_port *port, int def_qps,
if (ret)
goto out_clean_pr;
}
- for (i = def_qps; i < def_qps + add_tx_qps; i++) {
+ for (i = def_qps; i < def_qps; i++) {
ret = ehea_init_port_res(port, &port->port_res[i],
&pr_cfg_small_rx, i);
if (ret)
@@ -2525,7 +2309,7 @@ static int ehea_clean_all_portres(struct ehea_port *port)
int ret = 0;
int i;
- for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++)
+ for (i = 0; i < port->num_def_qps; i++)
ret |= ehea_clean_portres(port, &port->port_res[i]);
ret |= ehea_destroy_eq(port->qp_eq);
@@ -2557,8 +2341,7 @@ static int ehea_up(struct net_device *dev)
if (port->state == EHEA_PORT_UP)
return 0;
- ret = ehea_port_res_setup(port, port->num_def_qps,
- port->num_add_tx_qps);
+ ret = ehea_port_res_setup(port, port->num_def_qps);
if (ret) {
netdev_err(dev, "port_res_failed\n");
goto out;
@@ -2577,7 +2360,7 @@ static int ehea_up(struct net_device *dev)
goto out_clean_pr;
}
- for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
+ for (i = 0; i < port->num_def_qps; i++) {
ret = ehea_activate_qp(port->adapter, port->port_res[i].qp);
if (ret) {
netdev_err(dev, "activate_qp failed\n");
@@ -2623,7 +2406,7 @@ static void port_napi_disable(struct ehea_port *port)
{
int i;
- for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++)
+ for (i = 0; i < port->num_def_qps; i++)
napi_disable(&port->port_res[i].napi);
}
@@ -2631,7 +2414,7 @@ static void port_napi_enable(struct ehea_port *port)
{
int i;
- for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++)
+ for (i = 0; i < port->num_def_qps; i++)
napi_enable(&port->port_res[i].napi);
}
@@ -2647,10 +2430,11 @@ static int ehea_open(struct net_device *dev)
ret = ehea_up(dev);
if (!ret) {
port_napi_enable(port);
- netif_start_queue(dev);
+ netif_tx_start_all_queues(dev);
}
mutex_unlock(&port->port_lock);
+ schedule_delayed_work(&port->stats_work, msecs_to_jiffies(1000));
return ret;
}
@@ -2690,8 +2474,9 @@ static int ehea_stop(struct net_device *dev)
set_bit(__EHEA_DISABLE_PORT_RESET, &port->flags);
cancel_work_sync(&port->reset_task);
+ cancel_delayed_work_sync(&port->stats_work);
mutex_lock(&port->port_lock);
- netif_stop_queue(dev);
+ netif_tx_stop_all_queues(dev);
port_napi_disable(port);
ret = ehea_down(dev);
mutex_unlock(&port->port_lock);
@@ -2717,7 +2502,7 @@ static void ehea_flush_sq(struct ehea_port *port)
{
int i;
- for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
+ for (i = 0; i < port->num_def_qps; i++) {
struct ehea_port_res *pr = &port->port_res[i];
int swqe_max = pr->sq_skba_size - 2 - pr->swqe_ll_count;
int ret;
@@ -2751,7 +2536,7 @@ int ehea_stop_qps(struct net_device *dev)
goto out;
}
- for (i = 0; i < (port->num_def_qps + port->num_add_tx_qps); i++) {
+ for (i = 0; i < (port->num_def_qps); i++) {
struct ehea_port_res *pr = &port->port_res[i];
struct ehea_qp *qp = pr->qp;
@@ -2853,7 +2638,7 @@ int ehea_restart_qps(struct net_device *dev)
goto out;
}
- for (i = 0; i < (port->num_def_qps + port->num_add_tx_qps); i++) {
+ for (i = 0; i < (port->num_def_qps); i++) {
struct ehea_port_res *pr = &port->port_res[i];
struct ehea_qp *qp = pr->qp;
@@ -2915,7 +2700,7 @@ static void ehea_reset_port(struct work_struct *work)
mutex_lock(&dlpar_mem_lock);
port->resets++;
mutex_lock(&port->port_lock);
- netif_stop_queue(dev);
+ netif_tx_disable(dev);
port_napi_disable(port);
@@ -2931,7 +2716,7 @@ static void ehea_reset_port(struct work_struct *work)
port_napi_enable(port);
- netif_wake_queue(dev);
+ netif_tx_wake_all_queues(dev);
out:
mutex_unlock(&port->port_lock);
mutex_unlock(&dlpar_mem_lock);
@@ -2958,7 +2743,7 @@ static void ehea_rereg_mrs(void)
if (dev->flags & IFF_UP) {
mutex_lock(&port->port_lock);
- netif_stop_queue(dev);
+ netif_tx_disable(dev);
ehea_flush_sq(port);
ret = ehea_stop_qps(dev);
if (ret) {
@@ -3003,7 +2788,7 @@ static void ehea_rereg_mrs(void)
if (!ret) {
check_sqs(port);
port_napi_enable(port);
- netif_wake_queue(dev);
+ netif_tx_wake_all_queues(dev);
} else {
netdev_err(dev, "Unable to restart QPS\n");
}
@@ -3158,10 +2943,10 @@ static const struct net_device_ops ehea_netdev_ops = {
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ehea_netpoll,
#endif
- .ndo_get_stats = ehea_get_stats,
+ .ndo_get_stats64 = ehea_get_stats64,
.ndo_set_mac_address = ehea_set_mac_addr,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = ehea_set_multicast_list,
+ .ndo_set_rx_mode = ehea_set_multicast_list,
.ndo_change_mtu = ehea_change_mtu,
.ndo_vlan_rx_add_vid = ehea_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = ehea_vlan_rx_kill_vid,
@@ -3179,7 +2964,7 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
int jumbo;
/* allocate memory for the port structures */
- dev = alloc_etherdev(sizeof(struct ehea_port));
+ dev = alloc_etherdev_mq(sizeof(struct ehea_port), EHEA_MAX_PORT_RES);
if (!dev) {
pr_err("no mem for net_device\n");
@@ -3211,6 +2996,9 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
if (ret)
goto out_free_mc_list;
+ netif_set_real_num_rx_queues(dev, port->num_def_qps);
+ netif_set_real_num_tx_queues(dev, port->num_def_qps);
+
port_dev = ehea_register_port(port, dn);
if (!port_dev)
goto out_free_mc_list;
@@ -3223,30 +3011,29 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
dev->netdev_ops = &ehea_netdev_ops;
ehea_set_ethtool_ops(dev);
- dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO
+ dev->hw_features = NETIF_F_SG | NETIF_F_TSO
| NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX | NETIF_F_LRO;
dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO
| NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX
| NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER
- | NETIF_F_LLTX | NETIF_F_RXCSUM;
+ | NETIF_F_RXCSUM;
+ dev->vlan_features = NETIF_F_SG | NETIF_F_TSO | NETIF_F_HIGHDMA |
+ NETIF_F_IP_CSUM;
dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT;
- if (use_lro)
- dev->features |= NETIF_F_LRO;
-
INIT_WORK(&port->reset_task, ehea_reset_port);
+ INIT_DELAYED_WORK(&port->stats_work, ehea_update_stats);
init_waitqueue_head(&port->swqe_avail_wq);
init_waitqueue_head(&port->restart_wq);
+ memset(&port->stats, 0, sizeof(struct net_device_stats));
ret = register_netdev(dev);
if (ret) {
pr_err("register_netdev failed. ret=%d\n", ret);
goto out_unreg_port;
}
- port->lro_max_aggr = lro_max_aggr;
-
ret = ehea_get_jumboframe_status(port, &jumbo);
if (ret)
netdev_err(dev, "failed determining jumbo frame status\n");
@@ -3278,6 +3065,7 @@ static void ehea_shutdown_single_port(struct ehea_port *port)
struct ehea_adapter *adapter = port->adapter;
cancel_work_sync(&port->reset_task);
+ cancel_delayed_work_sync(&port->stats_work);
unregister_netdev(port->netdev);
ehea_unregister_port(port);
kfree(port->mc_list);
diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ethernet/ibm/ehea/ehea_phyp.c
index 0506967b9044..0506967b9044 100644
--- a/drivers/net/ehea/ehea_phyp.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_phyp.c
diff --git a/drivers/net/ehea/ehea_phyp.h b/drivers/net/ethernet/ibm/ehea/ehea_phyp.h
index 2f8174c248bc..2f8174c248bc 100644
--- a/drivers/net/ehea/ehea_phyp.h
+++ b/drivers/net/ethernet/ibm/ehea/ehea_phyp.h
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ethernet/ibm/ehea/ehea_qmr.c
index 95b9f4fa811e..95b9f4fa811e 100644
--- a/drivers/net/ehea/ehea_qmr.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_qmr.c
diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ethernet/ibm/ehea/ehea_qmr.h
index fddff8ec8cfd..337a47ecf4aa 100644
--- a/drivers/net/ehea/ehea_qmr.h
+++ b/drivers/net/ethernet/ibm/ehea/ehea_qmr.h
@@ -107,7 +107,7 @@ struct ehea_swqe {
u8 immediate_data_length;
u8 tcp_offset;
u8 reserved2;
- u16 tcp_end;
+ u16 reserved2b;
u8 wrap_tag;
u8 descriptors; /* number of valid descriptors in WQE */
u16 reserved3;
diff --git a/drivers/net/ibm_newemac/Kconfig b/drivers/net/ethernet/ibm/emac/Kconfig
index 78a1628c9892..3f44a30e0615 100644
--- a/drivers/net/ibm_newemac/Kconfig
+++ b/drivers/net/ethernet/ibm/emac/Kconfig
@@ -1,4 +1,4 @@
-config IBM_NEW_EMAC
+config IBM_EMAC
tristate "IBM EMAC Ethernet support"
depends on PPC_DCR
select CRC32
@@ -7,29 +7,29 @@ config IBM_NEW_EMAC
typically found on 4xx embedded PowerPC chips, but also on the
Axon southbridge for Cell.
-config IBM_NEW_EMAC_RXB
+config IBM_EMAC_RXB
int "Number of receive buffers"
- depends on IBM_NEW_EMAC
+ depends on IBM_EMAC
default "128"
-config IBM_NEW_EMAC_TXB
+config IBM_EMAC_TXB
int "Number of transmit buffers"
- depends on IBM_NEW_EMAC
+ depends on IBM_EMAC
default "64"
-config IBM_NEW_EMAC_POLL_WEIGHT
+config IBM_EMAC_POLL_WEIGHT
int "MAL NAPI polling weight"
- depends on IBM_NEW_EMAC
+ depends on IBM_EMAC
default "32"
-config IBM_NEW_EMAC_RX_COPY_THRESHOLD
+config IBM_EMAC_RX_COPY_THRESHOLD
int "RX skb copy threshold (bytes)"
- depends on IBM_NEW_EMAC
+ depends on IBM_EMAC
default "256"
-config IBM_NEW_EMAC_RX_SKB_HEADROOM
+config IBM_EMAC_RX_SKB_HEADROOM
int "Additional RX skb headroom (bytes)"
- depends on IBM_NEW_EMAC
+ depends on IBM_EMAC
default "0"
help
Additional receive skb headroom. Note, that driver
@@ -39,38 +39,38 @@ config IBM_NEW_EMAC_RX_SKB_HEADROOM
If unsure, set to 0.
-config IBM_NEW_EMAC_DEBUG
+config IBM_EMAC_DEBUG
bool "Debugging"
- depends on IBM_NEW_EMAC
+ depends on IBM_EMAC
default n
# The options below has to be select'ed by the respective
# processor types or platforms
-config IBM_NEW_EMAC_ZMII
+config IBM_EMAC_ZMII
bool
default n
-config IBM_NEW_EMAC_RGMII
+config IBM_EMAC_RGMII
bool
default n
-config IBM_NEW_EMAC_TAH
+config IBM_EMAC_TAH
bool
default n
-config IBM_NEW_EMAC_EMAC4
+config IBM_EMAC_EMAC4
bool
default n
-config IBM_NEW_EMAC_NO_FLOW_CTRL
+config IBM_EMAC_NO_FLOW_CTRL
bool
default n
-config IBM_NEW_EMAC_MAL_CLR_ICINTSTAT
+config IBM_EMAC_MAL_CLR_ICINTSTAT
bool
default n
-config IBM_NEW_EMAC_MAL_COMMON_ERR
+config IBM_EMAC_MAL_COMMON_ERR
bool
default n
diff --git a/drivers/net/ethernet/ibm/emac/Makefile b/drivers/net/ethernet/ibm/emac/Makefile
new file mode 100644
index 000000000000..eba21835d90d
--- /dev/null
+++ b/drivers/net/ethernet/ibm/emac/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the PowerPC 4xx on-chip ethernet driver
+#
+
+obj-$(CONFIG_IBM_EMAC) += ibm_emac.o
+
+ibm_emac-y := mal.o core.o phy.o
+ibm_emac-$(CONFIG_IBM_EMAC_ZMII) += zmii.o
+ibm_emac-$(CONFIG_IBM_EMAC_RGMII) += rgmii.o
+ibm_emac-$(CONFIG_IBM_EMAC_TAH) += tah.o
+ibm_emac-$(CONFIG_IBM_EMAC_DEBUG) += debug.o
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ethernet/ibm/emac/core.c
index 70cb7d8a3b53..ed79b2d3ad3e 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ethernet/ibm/emac/core.c
@@ -90,7 +90,7 @@ MODULE_LICENSE("GPL");
/* If packet size is less than this number, we allocate small skb and copy packet
* contents into it instead of just sending original big skb up
*/
-#define EMAC_RX_COPY_THRESH CONFIG_IBM_NEW_EMAC_RX_COPY_THRESHOLD
+#define EMAC_RX_COPY_THRESH CONFIG_IBM_EMAC_RX_COPY_THRESHOLD
/* Since multiple EMACs share MDIO lines in various ways, we need
* to avoid re-using the same PHY ID in cases where the arch didn't
@@ -1453,13 +1453,13 @@ static int emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev)
/* skb fragments */
for (i = 0; i < nr_frags; ++i) {
struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
- len = frag->size;
+ len = skb_frag_size(frag);
if (unlikely(dev->tx_cnt + mal_tx_chunks(len) >= NUM_TX_BUFF))
goto undo_frame;
- pd = dma_map_page(&dev->ofdev->dev, frag->page, frag->page_offset, len,
- DMA_TO_DEVICE);
+ pd = skb_frag_dma_map(&dev->ofdev->dev, frag, 0, len,
+ DMA_TO_DEVICE);
slot = emac_xmit_split(dev, slot, pd, len, i == nr_frags - 1,
ctrl);
@@ -1618,7 +1618,7 @@ static void emac_parse_rx_error(struct emac_instance *dev, u16 ctrl)
static inline void emac_rx_csum(struct emac_instance *dev,
struct sk_buff *skb, u16 ctrl)
{
-#ifdef CONFIG_IBM_NEW_EMAC_TAH
+#ifdef CONFIG_IBM_EMAC_TAH
if (!ctrl && dev->tah_dev) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
++dev->stats.rx_packets_csum;
@@ -2577,7 +2577,7 @@ static int __devinit emac_init_config(struct emac_instance *dev)
of_device_is_compatible(np, "ibm,emac-440gr"))
dev->features |= EMAC_FTR_440EP_PHY_CLK_FIX;
if (of_device_is_compatible(np, "ibm,emac-405ez")) {
-#ifdef CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL
+#ifdef CONFIG_IBM_EMAC_NO_FLOW_CTRL
dev->features |= EMAC_FTR_NO_FLOW_CONTROL_40x;
#else
printk(KERN_ERR "%s: Flow control not disabled!\n",
@@ -2601,7 +2601,7 @@ static int __devinit emac_init_config(struct emac_instance *dev)
/* Enable TAH/ZMII/RGMII features as found */
if (dev->tah_ph != 0) {
-#ifdef CONFIG_IBM_NEW_EMAC_TAH
+#ifdef CONFIG_IBM_EMAC_TAH
dev->features |= EMAC_FTR_HAS_TAH;
#else
printk(KERN_ERR "%s: TAH support not enabled !\n",
@@ -2611,7 +2611,7 @@ static int __devinit emac_init_config(struct emac_instance *dev)
}
if (dev->zmii_ph != 0) {
-#ifdef CONFIG_IBM_NEW_EMAC_ZMII
+#ifdef CONFIG_IBM_EMAC_ZMII
dev->features |= EMAC_FTR_HAS_ZMII;
#else
printk(KERN_ERR "%s: ZMII support not enabled !\n",
@@ -2621,7 +2621,7 @@ static int __devinit emac_init_config(struct emac_instance *dev)
}
if (dev->rgmii_ph != 0) {
-#ifdef CONFIG_IBM_NEW_EMAC_RGMII
+#ifdef CONFIG_IBM_EMAC_RGMII
dev->features |= EMAC_FTR_HAS_RGMII;
#else
printk(KERN_ERR "%s: RGMII support not enabled !\n",
@@ -2661,7 +2661,7 @@ static const struct net_device_ops emac_netdev_ops = {
.ndo_open = emac_open,
.ndo_stop = emac_close,
.ndo_get_stats = emac_stats,
- .ndo_set_multicast_list = emac_set_multicast_list,
+ .ndo_set_rx_mode = emac_set_multicast_list,
.ndo_do_ioctl = emac_ioctl,
.ndo_tx_timeout = emac_tx_timeout,
.ndo_validate_addr = eth_validate_addr,
@@ -2674,7 +2674,7 @@ static const struct net_device_ops emac_gige_netdev_ops = {
.ndo_open = emac_open,
.ndo_stop = emac_close,
.ndo_get_stats = emac_stats,
- .ndo_set_multicast_list = emac_set_multicast_list,
+ .ndo_set_rx_mode = emac_set_multicast_list,
.ndo_do_ioctl = emac_ioctl,
.ndo_tx_timeout = emac_tx_timeout,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/ibm_newemac/core.h b/drivers/net/ethernet/ibm/emac/core.h
index 4fec0844d59d..fa3ec57935fa 100644
--- a/drivers/net/ibm_newemac/core.h
+++ b/drivers/net/ethernet/ibm/emac/core.h
@@ -47,8 +47,8 @@
#include "tah.h"
#include "debug.h"
-#define NUM_TX_BUFF CONFIG_IBM_NEW_EMAC_TXB
-#define NUM_RX_BUFF CONFIG_IBM_NEW_EMAC_RXB
+#define NUM_TX_BUFF CONFIG_IBM_EMAC_TXB
+#define NUM_RX_BUFF CONFIG_IBM_EMAC_RXB
/* Simple sanity check */
#if NUM_TX_BUFF > 256 || NUM_RX_BUFF > 256
@@ -72,7 +72,7 @@ static inline int emac_rx_size(int mtu)
#define EMAC_DMA_ALIGN(x) ALIGN((x), dma_get_cache_alignment())
#define EMAC_RX_SKB_HEADROOM \
- EMAC_DMA_ALIGN(CONFIG_IBM_NEW_EMAC_RX_SKB_HEADROOM)
+ EMAC_DMA_ALIGN(CONFIG_IBM_EMAC_RX_SKB_HEADROOM)
/* Size of RX skb for the given MTU */
static inline int emac_rx_skb_size(int mtu)
@@ -335,21 +335,21 @@ enum {
EMAC_FTRS_ALWAYS = 0,
EMAC_FTRS_POSSIBLE =
-#ifdef CONFIG_IBM_NEW_EMAC_EMAC4
+#ifdef CONFIG_IBM_EMAC_EMAC4
EMAC_FTR_EMAC4 | EMAC_FTR_EMAC4SYNC |
EMAC_FTR_HAS_NEW_STACR |
EMAC_FTR_STACR_OC_INVERT | EMAC_FTR_440GX_PHY_CLK_FIX |
#endif
-#ifdef CONFIG_IBM_NEW_EMAC_TAH
+#ifdef CONFIG_IBM_EMAC_TAH
EMAC_FTR_HAS_TAH |
#endif
-#ifdef CONFIG_IBM_NEW_EMAC_ZMII
+#ifdef CONFIG_IBM_EMAC_ZMII
EMAC_FTR_HAS_ZMII |
#endif
-#ifdef CONFIG_IBM_NEW_EMAC_RGMII
+#ifdef CONFIG_IBM_EMAC_RGMII
EMAC_FTR_HAS_RGMII |
#endif
-#ifdef CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL
+#ifdef CONFIG_IBM_EMAC_NO_FLOW_CTRL
EMAC_FTR_NO_FLOW_CONTROL_40x |
#endif
EMAC_FTR_460EX_PHY_CLK_FIX |
diff --git a/drivers/net/ibm_newemac/debug.c b/drivers/net/ethernet/ibm/emac/debug.c
index 8c6c1e2a8750..8c6c1e2a8750 100644
--- a/drivers/net/ibm_newemac/debug.c
+++ b/drivers/net/ethernet/ibm/emac/debug.c
diff --git a/drivers/net/ibm_newemac/debug.h b/drivers/net/ethernet/ibm/emac/debug.h
index e596c77ccdf7..90477fe69d0c 100644
--- a/drivers/net/ibm_newemac/debug.h
+++ b/drivers/net/ethernet/ibm/emac/debug.h
@@ -24,7 +24,7 @@
#include "core.h"
-#if defined(CONFIG_IBM_NEW_EMAC_DEBUG)
+#if defined(CONFIG_IBM_EMAC_DEBUG)
struct emac_instance;
struct mal_instance;
diff --git a/drivers/net/ibm_newemac/emac.h b/drivers/net/ethernet/ibm/emac/emac.h
index 1568278d759a..1568278d759a 100644
--- a/drivers/net/ibm_newemac/emac.h
+++ b/drivers/net/ethernet/ibm/emac/emac.h
diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ethernet/ibm/emac/mal.c
index d268f404b7b0..f3c50b97ec61 100644
--- a/drivers/net/ibm_newemac/mal.c
+++ b/drivers/net/ethernet/ibm/emac/mal.c
@@ -577,8 +577,8 @@ static int __devinit mal_probe(struct platform_device *ofdev)
}
if (of_device_is_compatible(ofdev->dev.of_node, "ibm,mcmal-405ez")) {
-#if defined(CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT) && \
- defined(CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR)
+#if defined(CONFIG_IBM_EMAC_MAL_CLR_ICINTSTAT) && \
+ defined(CONFIG_IBM_EMAC_MAL_COMMON_ERR)
mal->features |= (MAL_FTR_CLEAR_ICINTSTAT |
MAL_FTR_COMMON_ERR_INT);
#else
@@ -616,7 +616,7 @@ static int __devinit mal_probe(struct platform_device *ofdev)
init_dummy_netdev(&mal->dummy_dev);
netif_napi_add(&mal->dummy_dev, &mal->napi, mal_poll,
- CONFIG_IBM_NEW_EMAC_POLL_WEIGHT);
+ CONFIG_IBM_EMAC_POLL_WEIGHT);
/* Load power-on reset defaults */
mal_reset(mal);
diff --git a/drivers/net/ibm_newemac/mal.h b/drivers/net/ethernet/ibm/emac/mal.h
index 66084214bf45..d06f985bda32 100644
--- a/drivers/net/ibm_newemac/mal.h
+++ b/drivers/net/ethernet/ibm/emac/mal.h
@@ -245,10 +245,10 @@ enum {
MAL_FTRS_ALWAYS = 0,
MAL_FTRS_POSSIBLE =
-#ifdef CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT
+#ifdef CONFIG_IBM_EMAC_MAL_CLR_ICINTSTAT
MAL_FTR_CLEAR_ICINTSTAT |
#endif
-#ifdef CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR
+#ifdef CONFIG_IBM_EMAC_MAL_COMMON_ERR
MAL_FTR_COMMON_ERR_INT |
#endif
0,
diff --git a/drivers/net/ibm_newemac/phy.c b/drivers/net/ethernet/ibm/emac/phy.c
index ab4e5969fe65..ab4e5969fe65 100644
--- a/drivers/net/ibm_newemac/phy.c
+++ b/drivers/net/ethernet/ibm/emac/phy.c
diff --git a/drivers/net/ibm_newemac/phy.h b/drivers/net/ethernet/ibm/emac/phy.h
index 5d2bf4cbe50b..5d2bf4cbe50b 100644
--- a/drivers/net/ibm_newemac/phy.h
+++ b/drivers/net/ethernet/ibm/emac/phy.h
diff --git a/drivers/net/ibm_newemac/rgmii.c b/drivers/net/ethernet/ibm/emac/rgmii.c
index 4fa53f3def64..4fa53f3def64 100644
--- a/drivers/net/ibm_newemac/rgmii.c
+++ b/drivers/net/ethernet/ibm/emac/rgmii.c
diff --git a/drivers/net/ibm_newemac/rgmii.h b/drivers/net/ethernet/ibm/emac/rgmii.h
index d69799049865..9296b6c5f920 100644
--- a/drivers/net/ibm_newemac/rgmii.h
+++ b/drivers/net/ethernet/ibm/emac/rgmii.h
@@ -54,7 +54,7 @@ struct rgmii_instance {
struct platform_device *ofdev;
};
-#ifdef CONFIG_IBM_NEW_EMAC_RGMII
+#ifdef CONFIG_IBM_EMAC_RGMII
extern int rgmii_init(void);
extern void rgmii_exit(void);
@@ -77,6 +77,6 @@ extern void *rgmii_dump_regs(struct platform_device *ofdev, void *buf);
# define rgmii_set_speed(x,y,z) do { } while(0)
# define rgmii_get_regs_len(x) 0
# define rgmii_dump_regs(x,buf) (buf)
-#endif /* !CONFIG_IBM_NEW_EMAC_RGMII */
+#endif /* !CONFIG_IBM_EMAC_RGMII */
#endif /* __IBM_NEWEMAC_RGMII_H */
diff --git a/drivers/net/ibm_newemac/tah.c b/drivers/net/ethernet/ibm/emac/tah.c
index 5f51bf7c9dc5..5f51bf7c9dc5 100644
--- a/drivers/net/ibm_newemac/tah.c
+++ b/drivers/net/ethernet/ibm/emac/tah.c
diff --git a/drivers/net/ibm_newemac/tah.h b/drivers/net/ethernet/ibm/emac/tah.h
index 61dbeca006d1..3437ab4964c7 100644
--- a/drivers/net/ibm_newemac/tah.h
+++ b/drivers/net/ethernet/ibm/emac/tah.h
@@ -70,7 +70,7 @@ struct tah_instance {
#define TAH_MR_DTFP 0x00100000
#define TAH_MR_DIG 0x00080000
-#ifdef CONFIG_IBM_NEW_EMAC_TAH
+#ifdef CONFIG_IBM_EMAC_TAH
extern int tah_init(void);
extern void tah_exit(void);
@@ -90,6 +90,6 @@ extern void *tah_dump_regs(struct platform_device *ofdev, void *buf);
# define tah_get_regs_len(x) 0
# define tah_dump_regs(x,buf) (buf)
-#endif /* !CONFIG_IBM_NEW_EMAC_TAH */
+#endif /* !CONFIG_IBM_EMAC_TAH */
#endif /* __IBM_NEWEMAC_TAH_H */
diff --git a/drivers/net/ibm_newemac/zmii.c b/drivers/net/ethernet/ibm/emac/zmii.c
index 97449e786d61..97449e786d61 100644
--- a/drivers/net/ibm_newemac/zmii.c
+++ b/drivers/net/ethernet/ibm/emac/zmii.c
diff --git a/drivers/net/ibm_newemac/zmii.h b/drivers/net/ethernet/ibm/emac/zmii.h
index 1333fa2b2781..ceaed823a83c 100644
--- a/drivers/net/ibm_newemac/zmii.h
+++ b/drivers/net/ethernet/ibm/emac/zmii.h
@@ -51,7 +51,7 @@ struct zmii_instance {
struct platform_device *ofdev;
};
-#ifdef CONFIG_IBM_NEW_EMAC_ZMII
+#ifdef CONFIG_IBM_EMAC_ZMII
extern int zmii_init(void);
extern void zmii_exit(void);
@@ -73,6 +73,6 @@ extern void *zmii_dump_regs(struct platform_device *ofdev, void *buf);
# define zmii_set_speed(x,y,z) do { } while(0)
# define zmii_get_regs_len(x) 0
# define zmii_dump_regs(x,buf) (buf)
-#endif /* !CONFIG_IBM_NEW_EMAC_ZMII */
+#endif /* !CONFIG_IBM_EMAC_ZMII */
#endif /* __IBM_NEWEMAC_ZMII_H */
diff --git a/drivers/net/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index ba99af05bf62..b1cd41b9c61c 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -395,7 +395,7 @@ static inline struct sk_buff *ibmveth_rxq_get_buffer(struct ibmveth_adapter *ada
}
/* recycle the current buffer on the rx queue */
-static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
+static int ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
{
u32 q_index = adapter->rx_queue.index;
u64 correlator = adapter->rx_queue.queue_addr[q_index].correlator;
@@ -403,6 +403,7 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
unsigned int index = correlator & 0xffffffffUL;
union ibmveth_buf_desc desc;
unsigned long lpar_rc;
+ int ret = 1;
BUG_ON(pool >= IBMVETH_NUM_BUFF_POOLS);
BUG_ON(index >= adapter->rx_buff_pool[pool].size);
@@ -410,7 +411,7 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
if (!adapter->rx_buff_pool[pool].active) {
ibmveth_rxq_harvest_buffer(adapter);
ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[pool]);
- return;
+ goto out;
}
desc.fields.flags_len = IBMVETH_BUF_VALID |
@@ -423,12 +424,16 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
netdev_dbg(adapter->netdev, "h_add_logical_lan_buffer failed "
"during recycle rc=%ld", lpar_rc);
ibmveth_remove_buffer_from_pool(adapter, adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator);
+ ret = 0;
}
if (++adapter->rx_queue.index == adapter->rx_queue.num_slots) {
adapter->rx_queue.index = 0;
adapter->rx_queue.toggle = !adapter->rx_queue.toggle;
}
+
+out:
+ return ret;
}
static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter)
@@ -631,8 +636,8 @@ static int ibmveth_open(struct net_device *netdev)
netdev_err(netdev, "unable to request irq 0x%x, rc %d\n",
netdev->irq, rc);
do {
- rc = h_free_logical_lan(adapter->vdev->unit_address);
- } while (H_IS_LONG_BUSY(rc) || (rc == H_BUSY));
+ lpar_rc = h_free_logical_lan(adapter->vdev->unit_address);
+ } while (H_IS_LONG_BUSY(lpar_rc) || (lpar_rc == H_BUSY));
goto err_out;
}
@@ -752,7 +757,7 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data)
struct ibmveth_adapter *adapter = netdev_priv(dev);
unsigned long set_attr, clr_attr, ret_attr;
unsigned long set_attr6, clr_attr6;
- long ret, ret6;
+ long ret, ret4, ret6;
int rc1 = 0, rc2 = 0;
int restart = 0;
@@ -765,6 +770,8 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data)
set_attr = 0;
clr_attr = 0;
+ set_attr6 = 0;
+ clr_attr6 = 0;
if (data) {
set_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM;
@@ -779,16 +786,20 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data)
if (ret == H_SUCCESS && !(ret_attr & IBMVETH_ILLAN_ACTIVE_TRUNK) &&
!(ret_attr & IBMVETH_ILLAN_TRUNK_PRI_MASK) &&
(ret_attr & IBMVETH_ILLAN_PADDED_PKT_CSUM)) {
- ret = h_illan_attributes(adapter->vdev->unit_address, clr_attr,
+ ret4 = h_illan_attributes(adapter->vdev->unit_address, clr_attr,
set_attr, &ret_attr);
- if (ret != H_SUCCESS) {
+ if (ret4 != H_SUCCESS) {
netdev_err(dev, "unable to change IPv4 checksum "
"offload settings. %d rc=%ld\n",
- data, ret);
+ data, ret4);
+
+ h_illan_attributes(adapter->vdev->unit_address,
+ set_attr, clr_attr, &ret_attr);
+
+ if (data == 1)
+ dev->features &= ~NETIF_F_IP_CSUM;
- ret = h_illan_attributes(adapter->vdev->unit_address,
- set_attr, clr_attr, &ret_attr);
} else {
adapter->fw_ipv4_csum_support = data;
}
@@ -799,15 +810,18 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data)
if (ret6 != H_SUCCESS) {
netdev_err(dev, "unable to change IPv6 checksum "
"offload settings. %d rc=%ld\n",
- data, ret);
+ data, ret6);
+
+ h_illan_attributes(adapter->vdev->unit_address,
+ set_attr6, clr_attr6, &ret_attr);
+
+ if (data == 1)
+ dev->features &= ~NETIF_F_IPV6_CSUM;
- ret = h_illan_attributes(adapter->vdev->unit_address,
- set_attr6, clr_attr6,
- &ret_attr);
} else
adapter->fw_ipv6_csum_support = data;
- if (ret != H_SUCCESS || ret6 != H_SUCCESS)
+ if (ret4 == H_SUCCESS || ret6 == H_SUCCESS)
adapter->rx_csum = data;
else
rc1 = -EIO;
@@ -925,6 +939,7 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb,
union ibmveth_buf_desc descs[6];
int last, i;
int force_bounce = 0;
+ dma_addr_t dma_addr;
/*
* veth handles a maximum of 6 segments including the header, so
@@ -989,27 +1004,25 @@ retry_bounce:
}
/* Map the header */
- descs[0].fields.address = dma_map_single(&adapter->vdev->dev, skb->data,
- skb_headlen(skb),
- DMA_TO_DEVICE);
- if (dma_mapping_error(&adapter->vdev->dev, descs[0].fields.address))
+ dma_addr = dma_map_single(&adapter->vdev->dev, skb->data,
+ skb_headlen(skb), DMA_TO_DEVICE);
+ if (dma_mapping_error(&adapter->vdev->dev, dma_addr))
goto map_failed;
descs[0].fields.flags_len = desc_flags | skb_headlen(skb);
+ descs[0].fields.address = dma_addr;
/* Map the frags */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- unsigned long dma_addr;
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- dma_addr = dma_map_page(&adapter->vdev->dev, frag->page,
- frag->page_offset, frag->size,
- DMA_TO_DEVICE);
+ dma_addr = skb_frag_dma_map(&adapter->vdev->dev, frag, 0,
+ skb_frag_size(frag), DMA_TO_DEVICE);
if (dma_mapping_error(&adapter->vdev->dev, dma_addr))
goto map_failed_frags;
- descs[i+1].fields.flags_len = desc_flags | frag->size;
+ descs[i+1].fields.flags_len = desc_flags | skb_frag_size(frag);
descs[i+1].fields.address = dma_addr;
}
@@ -1021,7 +1034,12 @@ retry_bounce:
netdev->stats.tx_bytes += skb->len;
}
- for (i = 0; i < skb_shinfo(skb)->nr_frags + 1; i++)
+ dma_unmap_single(&adapter->vdev->dev,
+ descs[0].fields.address,
+ descs[0].fields.flags_len & IBMVETH_BUF_LEN_MASK,
+ DMA_TO_DEVICE);
+
+ for (i = 1; i < skb_shinfo(skb)->nr_frags + 1; i++)
dma_unmap_page(&adapter->vdev->dev, descs[i].fields.address,
descs[i].fields.flags_len & IBMVETH_BUF_LEN_MASK,
DMA_TO_DEVICE);
@@ -1084,8 +1102,9 @@ restart_poll:
if (rx_flush)
ibmveth_flush_buffer(skb->data,
length + offset);
+ if (!ibmveth_rxq_recycle_buffer(adapter))
+ kfree_skb(skb);
skb = new_skb;
- ibmveth_rxq_recycle_buffer(adapter);
} else {
ibmveth_rxq_harvest_buffer(adapter);
skb_reserve(skb, offset);
@@ -1299,7 +1318,7 @@ static const struct net_device_ops ibmveth_netdev_ops = {
.ndo_open = ibmveth_open,
.ndo_stop = ibmveth_close,
.ndo_start_xmit = ibmveth_start_xmit,
- .ndo_set_multicast_list = ibmveth_set_multicast_list,
+ .ndo_set_rx_mode = ibmveth_set_multicast_list,
.ndo_do_ioctl = ibmveth_ioctl,
.ndo_change_mtu = ibmveth_change_mtu,
.ndo_fix_features = ibmveth_fix_features,
diff --git a/drivers/net/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h
index 43a794fab9ff..43a794fab9ff 100644
--- a/drivers/net/ibmveth.h
+++ b/drivers/net/ethernet/ibm/ibmveth.h
diff --git a/drivers/net/iseries_veth.c b/drivers/net/ethernet/ibm/iseries_veth.c
index 53dd39e9130e..4326681df382 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/ethernet/ibm/iseries_veth.c
@@ -1009,7 +1009,7 @@ static const struct net_device_ops veth_netdev_ops = {
.ndo_stop = veth_close,
.ndo_start_xmit = veth_start_xmit,
.ndo_change_mtu = veth_change_mtu,
- .ndo_set_multicast_list = veth_set_multicast_list,
+ .ndo_set_rx_mode = veth_set_multicast_list,
.ndo_set_mac_address = NULL,
.ndo_validate_addr = eth_validate_addr,
};
diff --git a/drivers/net/ethernet/icplus/Kconfig b/drivers/net/ethernet/icplus/Kconfig
new file mode 100644
index 000000000000..3aff81d7989f
--- /dev/null
+++ b/drivers/net/ethernet/icplus/Kconfig
@@ -0,0 +1,14 @@
+#
+# IC Plus device configuration
+#
+
+config IP1000
+ tristate "IP1000 Gigabit Ethernet support"
+ depends on PCI && EXPERIMENTAL
+ select NET_CORE
+ select MII
+ ---help---
+ This driver supports IP1000 gigabit Ethernet cards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called ipg. This is recommended.
diff --git a/drivers/net/ethernet/icplus/Makefile b/drivers/net/ethernet/icplus/Makefile
new file mode 100644
index 000000000000..5bc87c1f36aa
--- /dev/null
+++ b/drivers/net/ethernet/icplus/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the IC Plus device drivers
+#
+
+obj-$(CONFIG_IP1000) += ipg.o
diff --git a/drivers/net/ipg.c b/drivers/net/ethernet/icplus/ipg.c
index d4aa40adf1e9..8fd80a00b898 100644
--- a/drivers/net/ipg.c
+++ b/drivers/net/ethernet/icplus/ipg.c
@@ -20,6 +20,9 @@
* http://www.icplus.com.tw
* jesse@icplus.com.tw
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/crc32.h>
#include <linux/ethtool.h>
#include <linux/interrupt.h>
@@ -67,7 +70,7 @@ MODULE_LICENSE("GPL");
* Variable record -- index by leading revision/length
* Revision/Length(=N*4), Address1, Data1, Address2, Data2,...,AddressN,DataN
*/
-static unsigned short DefaultPhyParam[] = {
+static const unsigned short DefaultPhyParam[] = {
/* 11/12/03 IP1000A v1-3 rev=0x40 */
/*--------------------------------------------------------------------------
(0x4000|(15*4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 22, 0x85bd, 24, 0xfff2,
@@ -85,7 +88,7 @@ static unsigned short DefaultPhyParam[] = {
0x0000
};
-static const char *ipg_brand_name[] = {
+static const char * const ipg_brand_name[] = {
"IC PLUS IP1000 1000/100/10 based NIC",
"Sundance Technology ST2021 based NIC",
"Tamarack Microelectronics TC9020/9021 based NIC",
@@ -118,23 +121,23 @@ static void ipg_dump_rfdlist(struct net_device *dev)
IPG_DEBUG_MSG("_dump_rfdlist\n");
- printk(KERN_INFO "rx_current = %2.2x\n", sp->rx_current);
- printk(KERN_INFO "rx_dirty = %2.2x\n", sp->rx_dirty);
- printk(KERN_INFO "RFDList start address = %16.16lx\n",
- (unsigned long) sp->rxd_map);
- printk(KERN_INFO "RFDListPtr register = %8.8x%8.8x\n",
- ipg_r32(IPG_RFDLISTPTR1), ipg_r32(IPG_RFDLISTPTR0));
+ netdev_info(dev, "rx_current = %02x\n", sp->rx_current);
+ netdev_info(dev, "rx_dirty = %02x\n", sp->rx_dirty);
+ netdev_info(dev, "RFDList start address = %016lx\n",
+ (unsigned long)sp->rxd_map);
+ netdev_info(dev, "RFDListPtr register = %08x%08x\n",
+ ipg_r32(IPG_RFDLISTPTR1), ipg_r32(IPG_RFDLISTPTR0));
for (i = 0; i < IPG_RFDLIST_LENGTH; i++) {
offset = (u32) &sp->rxd[i].next_desc - (u32) sp->rxd;
- printk(KERN_INFO "%2.2x %4.4x RFDNextPtr = %16.16lx\n", i,
- offset, (unsigned long) sp->rxd[i].next_desc);
+ netdev_info(dev, "%02x %04x RFDNextPtr = %016lx\n",
+ i, offset, (unsigned long)sp->rxd[i].next_desc);
offset = (u32) &sp->rxd[i].rfs - (u32) sp->rxd;
- printk(KERN_INFO "%2.2x %4.4x RFS = %16.16lx\n", i,
- offset, (unsigned long) sp->rxd[i].rfs);
+ netdev_info(dev, "%02x %04x RFS = %016lx\n",
+ i, offset, (unsigned long)sp->rxd[i].rfs);
offset = (u32) &sp->rxd[i].frag_info - (u32) sp->rxd;
- printk(KERN_INFO "%2.2x %4.4x frag_info = %16.16lx\n", i,
- offset, (unsigned long) sp->rxd[i].frag_info);
+ netdev_info(dev, "%02x %04x frag_info = %016lx\n",
+ i, offset, (unsigned long)sp->rxd[i].frag_info);
}
}
@@ -147,24 +150,24 @@ static void ipg_dump_tfdlist(struct net_device *dev)
IPG_DEBUG_MSG("_dump_tfdlist\n");
- printk(KERN_INFO "tx_current = %2.2x\n", sp->tx_current);
- printk(KERN_INFO "tx_dirty = %2.2x\n", sp->tx_dirty);
- printk(KERN_INFO "TFDList start address = %16.16lx\n",
- (unsigned long) sp->txd_map);
- printk(KERN_INFO "TFDListPtr register = %8.8x%8.8x\n",
- ipg_r32(IPG_TFDLISTPTR1), ipg_r32(IPG_TFDLISTPTR0));
+ netdev_info(dev, "tx_current = %02x\n", sp->tx_current);
+ netdev_info(dev, "tx_dirty = %02x\n", sp->tx_dirty);
+ netdev_info(dev, "TFDList start address = %016lx\n",
+ (unsigned long) sp->txd_map);
+ netdev_info(dev, "TFDListPtr register = %08x%08x\n",
+ ipg_r32(IPG_TFDLISTPTR1), ipg_r32(IPG_TFDLISTPTR0));
for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
offset = (u32) &sp->txd[i].next_desc - (u32) sp->txd;
- printk(KERN_INFO "%2.2x %4.4x TFDNextPtr = %16.16lx\n", i,
- offset, (unsigned long) sp->txd[i].next_desc);
+ netdev_info(dev, "%02x %04x TFDNextPtr = %016lx\n",
+ i, offset, (unsigned long)sp->txd[i].next_desc);
offset = (u32) &sp->txd[i].tfc - (u32) sp->txd;
- printk(KERN_INFO "%2.2x %4.4x TFC = %16.16lx\n", i,
- offset, (unsigned long) sp->txd[i].tfc);
+ netdev_info(dev, "%02x %04x TFC = %016lx\n",
+ i, offset, (unsigned long) sp->txd[i].tfc);
offset = (u32) &sp->txd[i].frag_info - (u32) sp->txd;
- printk(KERN_INFO "%2.2x %4.4x frag_info = %16.16lx\n", i,
- offset, (unsigned long) sp->txd[i].frag_info);
+ netdev_info(dev, "%02x %04x frag_info = %016lx\n",
+ i, offset, (unsigned long) sp->txd[i].frag_info);
}
}
#endif
@@ -480,6 +483,10 @@ static int ipg_config_autoneg(struct net_device *dev)
u32 mac_ctrl_val;
u32 asicctrl;
u8 phyctrl;
+ const char *speed;
+ const char *duplex;
+ const char *tx_desc;
+ const char *rx_desc;
IPG_DEBUG_MSG("_config_autoneg\n");
@@ -499,27 +506,27 @@ static int ipg_config_autoneg(struct net_device *dev)
*/
sp->tenmbpsmode = 0;
- printk(KERN_INFO "%s: Link speed = ", dev->name);
-
/* Determine actual speed of operation. */
switch (phyctrl & IPG_PC_LINK_SPEED) {
case IPG_PC_LINK_SPEED_10MBPS:
- printk("10Mbps.\n");
- printk(KERN_INFO "%s: 10Mbps operational mode enabled.\n",
- dev->name);
+ speed = "10Mbps";
sp->tenmbpsmode = 1;
break;
case IPG_PC_LINK_SPEED_100MBPS:
- printk("100Mbps.\n");
+ speed = "100Mbps";
break;
case IPG_PC_LINK_SPEED_1000MBPS:
- printk("1000Mbps.\n");
+ speed = "1000Mbps";
break;
default:
- printk("undefined!\n");
+ speed = "undefined!";
return 0;
}
+ netdev_info(dev, "Link speed = %s\n", speed);
+ if (sp->tenmbpsmode == 1)
+ netdev_info(dev, "10Mbps operational mode enabled\n");
+
if (phyctrl & IPG_PC_DUPLEX_STATUS) {
fullduplex = 1;
txflowcontrol = 1;
@@ -528,38 +535,41 @@ static int ipg_config_autoneg(struct net_device *dev)
/* Configure full duplex, and flow control. */
if (fullduplex == 1) {
+
/* Configure IPG for full duplex operation. */
- printk(KERN_INFO "%s: setting full duplex, ", dev->name);
+
+ duplex = "full";
mac_ctrl_val |= IPG_MC_DUPLEX_SELECT_FD;
if (txflowcontrol == 1) {
- printk("TX flow control");
+ tx_desc = "";
mac_ctrl_val |= IPG_MC_TX_FLOW_CONTROL_ENABLE;
} else {
- printk("no TX flow control");
+ tx_desc = "no ";
mac_ctrl_val &= ~IPG_MC_TX_FLOW_CONTROL_ENABLE;
}
if (rxflowcontrol == 1) {
- printk(", RX flow control.");
+ rx_desc = "";
mac_ctrl_val |= IPG_MC_RX_FLOW_CONTROL_ENABLE;
} else {
- printk(", no RX flow control.");
+ rx_desc = "no ";
mac_ctrl_val &= ~IPG_MC_RX_FLOW_CONTROL_ENABLE;
}
-
- printk("\n");
} else {
- /* Configure IPG for half duplex operation. */
- printk(KERN_INFO "%s: setting half duplex, "
- "no TX flow control, no RX flow control.\n", dev->name);
-
- mac_ctrl_val &= ~IPG_MC_DUPLEX_SELECT_FD &
- ~IPG_MC_TX_FLOW_CONTROL_ENABLE &
- ~IPG_MC_RX_FLOW_CONTROL_ENABLE;
+ duplex = "half";
+ tx_desc = "no ";
+ rx_desc = "no ";
+ mac_ctrl_val &= (~IPG_MC_DUPLEX_SELECT_FD &
+ ~IPG_MC_TX_FLOW_CONTROL_ENABLE &
+ ~IPG_MC_RX_FLOW_CONTROL_ENABLE);
}
+
+ netdev_info(dev, "setting %s duplex, %sTX, %sRX flow control\n",
+ duplex, tx_desc, rx_desc);
ipg_w32(mac_ctrl_val, MAC_CTRL);
+
return 0;
}
@@ -784,14 +794,13 @@ static int init_rfdlist(struct net_device *dev)
* A receive buffer was not ready, break the
* RFD list here.
*/
- IPG_DEBUG_MSG("Cannot allocate Rx buffer.\n");
+ IPG_DEBUG_MSG("Cannot allocate Rx buffer\n");
/* Just in case we cannot allocate a single RFD.
* Should not occur.
*/
if (i == 0) {
- printk(KERN_ERR "%s: No memory available"
- " for RFD list.\n", dev->name);
+ netdev_err(dev, "No memory available for RFD list\n");
return -ENOMEM;
}
}
@@ -838,7 +847,7 @@ static void init_tfdlist(struct net_device *dev)
sp->tx_dirty = 0;
/* Write the location of the TFDList to the IPG. */
- IPG_DDEBUG_MSG("Starting TFDListPtr = %8.8x\n",
+ IPG_DDEBUG_MSG("Starting TFDListPtr = %08x\n",
(u32) sp->txd_map);
ipg_w32((u32) sp->txd_map, TFD_LIST_PTR_0);
ipg_w32(0x00000000, TFD_LIST_PTR_1);
@@ -864,7 +873,7 @@ static void ipg_nic_txfree(struct net_device *dev)
struct sk_buff *skb = sp->tx_buff[dirty];
struct ipg_tx *txfd = sp->txd + dirty;
- IPG_DEBUG_MSG("TFC = %16.16lx\n", (unsigned long) txfd->tfc);
+ IPG_DEBUG_MSG("TFC = %016lx\n", (unsigned long) txfd->tfc);
/* Look at each TFD's TFC field beginning
* at the last freed TFD up to the current TFD.
@@ -906,10 +915,8 @@ static void ipg_tx_timeout(struct net_device *dev)
spin_lock_irq(&sp->lock);
/* Re-configure after DMA reset. */
- if (ipg_io_config(dev) < 0) {
- printk(KERN_INFO "%s: Error during re-configuration.\n",
- dev->name);
- }
+ if (ipg_io_config(dev) < 0)
+ netdev_info(dev, "Error during re-configuration\n");
init_tfdlist(dev);
@@ -938,7 +945,7 @@ static void ipg_nic_txcleanup(struct net_device *dev)
*/
u32 txstatusdword = ipg_r32(TX_STATUS);
- IPG_DEBUG_MSG("TxStatus = %8.8x\n", txstatusdword);
+ IPG_DEBUG_MSG("TxStatus = %08x\n", txstatusdword);
/* Check for Transmit errors. Error bits only valid if
* TX_COMPLETE bit in the TXSTATUS register is a 1.
@@ -953,20 +960,20 @@ static void ipg_nic_txcleanup(struct net_device *dev)
/* Transmit error, increment stat counters. */
if (txstatusdword & IPG_TS_TX_ERROR) {
- IPG_DEBUG_MSG("Transmit error.\n");
+ IPG_DEBUG_MSG("Transmit error\n");
sp->stats.tx_errors++;
}
/* Late collision, re-enable transmitter. */
if (txstatusdword & IPG_TS_LATE_COLLISION) {
- IPG_DEBUG_MSG("Late collision on transmit.\n");
+ IPG_DEBUG_MSG("Late collision on transmit\n");
ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) &
IPG_MC_RSVD_MASK, MAC_CTRL);
}
/* Maximum collisions, re-enable transmitter. */
if (txstatusdword & IPG_TS_TX_MAX_COLL) {
- IPG_DEBUG_MSG("Maximum collisions on transmit.\n");
+ IPG_DEBUG_MSG("Maximum collisions on transmit\n");
ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) &
IPG_MC_RSVD_MASK, MAC_CTRL);
}
@@ -975,16 +982,14 @@ static void ipg_nic_txcleanup(struct net_device *dev)
* transmitter.
*/
if (txstatusdword & IPG_TS_TX_UNDERRUN) {
- IPG_DEBUG_MSG("Transmitter underrun.\n");
+ IPG_DEBUG_MSG("Transmitter underrun\n");
sp->stats.tx_fifo_errors++;
ipg_reset(dev, IPG_AC_TX_RESET | IPG_AC_DMA |
IPG_AC_NETWORK | IPG_AC_FIFO);
/* Re-configure after DMA reset. */
if (ipg_io_config(dev) < 0) {
- printk(KERN_INFO
- "%s: Error during re-configuration.\n",
- dev->name);
+ netdev_info(dev, "Error during re-configuration\n");
}
init_tfdlist(dev);
@@ -1063,7 +1068,7 @@ static int ipg_nic_rxrestore(struct net_device *dev)
* Linux system).
*/
if (ipg_get_rxbuff(dev, entry) < 0) {
- IPG_DEBUG_MSG("Cannot allocate new Rx buffer.\n");
+ IPG_DEBUG_MSG("Cannot allocate new Rx buffer\n");
break;
}
@@ -1134,7 +1139,7 @@ static int ipg_nic_rx_check_error(struct net_device *dev)
(IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME |
IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR |
IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR))) {
- IPG_DEBUG_MSG("Rx error, RFS = %16.16lx\n",
+ IPG_DEBUG_MSG("Rx error, RFS = %016lx\n",
(unsigned long) rxfd->rfs);
/* Increment general receive error statistic. */
@@ -1142,13 +1147,13 @@ static int ipg_nic_rx_check_error(struct net_device *dev)
/* Increment detailed receive error statistics. */
if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) {
- IPG_DEBUG_MSG("RX FIFO overrun occurred.\n");
+ IPG_DEBUG_MSG("RX FIFO overrun occurred\n");
sp->stats.rx_fifo_errors++;
}
if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) {
- IPG_DEBUG_MSG("RX runt occurred.\n");
+ IPG_DEBUG_MSG("RX runt occurred\n");
sp->stats.rx_length_errors++;
}
@@ -1157,7 +1162,7 @@ static int ipg_nic_rx_check_error(struct net_device *dev)
*/
if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) {
- IPG_DEBUG_MSG("RX alignment error occurred.\n");
+ IPG_DEBUG_MSG("RX alignment error occurred\n");
sp->stats.rx_frame_errors++;
}
@@ -1404,7 +1409,7 @@ static int ipg_nic_rx(struct net_device *dev)
*/
if (framelen > sp->rxfrag_size) {
IPG_DEBUG_MSG
- ("RFS FrameLen > allocated fragment size.\n");
+ ("RFS FrameLen > allocated fragment size\n");
framelen = sp->rxfrag_size;
}
@@ -1414,7 +1419,7 @@ static int ipg_nic_rx(struct net_device *dev)
IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR |
IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR)))) {
- IPG_DEBUG_MSG("Rx error, RFS = %16.16lx\n",
+ IPG_DEBUG_MSG("Rx error, RFS = %016lx\n",
(unsigned long int) rxfd->rfs);
/* Increment general receive error statistic. */
@@ -1422,12 +1427,12 @@ static int ipg_nic_rx(struct net_device *dev)
/* Increment detailed receive error statistics. */
if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) {
- IPG_DEBUG_MSG("RX FIFO overrun occurred.\n");
+ IPG_DEBUG_MSG("RX FIFO overrun occurred\n");
sp->stats.rx_fifo_errors++;
}
if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) {
- IPG_DEBUG_MSG("RX runt occurred.\n");
+ IPG_DEBUG_MSG("RX runt occurred\n");
sp->stats.rx_length_errors++;
}
@@ -1437,7 +1442,7 @@ static int ipg_nic_rx(struct net_device *dev)
*/
if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) {
- IPG_DEBUG_MSG("RX alignment error occurred.\n");
+ IPG_DEBUG_MSG("RX alignment error occurred\n");
sp->stats.rx_frame_errors++;
}
@@ -1508,7 +1513,7 @@ static int ipg_nic_rx(struct net_device *dev)
rxfd = sp->rxd + entry;
- IPG_DEBUG_MSG("Frame requires multiple RFDs.\n");
+ IPG_DEBUG_MSG("Frame requires multiple RFDs\n");
/* An unexpected event, additional code needed to handle
* properly. So for the time being, just disregard the
@@ -1557,8 +1562,7 @@ static void ipg_reset_after_host_error(struct work_struct *work)
init_tfdlist(dev);
if (ipg_io_config(dev) < 0) {
- printk(KERN_INFO "%s: Cannot recover from PCI error.\n",
- dev->name);
+ netdev_info(dev, "Cannot recover from PCI error\n");
schedule_delayed_work(&sp->task, HZ);
}
}
@@ -1586,7 +1590,7 @@ static irqreturn_t ipg_interrupt_handler(int irq, void *dev_inst)
*/
status = ipg_r16(INT_STATUS_ACK);
- IPG_DEBUG_MSG("IntStatusAck = %4.4x\n", status);
+ IPG_DEBUG_MSG("IntStatusAck = %04x\n", status);
/* Shared IRQ of remove event. */
if (!(status & IPG_IS_RSVD_MASK))
@@ -1599,7 +1603,7 @@ static irqreturn_t ipg_interrupt_handler(int irq, void *dev_inst)
/* If RFDListEnd interrupt, restore all used RFDs. */
if (status & IPG_IS_RFD_LIST_END) {
- IPG_DEBUG_MSG("RFDListEnd Interrupt.\n");
+ IPG_DEBUG_MSG("RFDListEnd Interrupt\n");
/* The RFD list end indicates an RFD was encountered
* with a 0 NextPtr, or with an RFDDone bit set to 1
@@ -1661,21 +1665,20 @@ static irqreturn_t ipg_interrupt_handler(int irq, void *dev_inst)
/* If LinkEvent interrupt, resolve autonegotiation. */
if (status & IPG_IS_LINK_EVENT) {
if (ipg_config_autoneg(dev) < 0)
- printk(KERN_INFO "%s: Auto-negotiation error.\n",
- dev->name);
+ netdev_info(dev, "Auto-negotiation error\n");
}
/* If MACCtrlFrame interrupt, do nothing. */
if (status & IPG_IS_MAC_CTRL_FRAME)
- IPG_DEBUG_MSG("MACCtrlFrame interrupt.\n");
+ IPG_DEBUG_MSG("MACCtrlFrame interrupt\n");
/* If RxComplete interrupt, do nothing. */
if (status & IPG_IS_RX_COMPLETE)
- IPG_DEBUG_MSG("RxComplete interrupt.\n");
+ IPG_DEBUG_MSG("RxComplete interrupt\n");
/* If RxEarly interrupt, do nothing. */
if (status & IPG_IS_RX_EARLY)
- IPG_DEBUG_MSG("RxEarly interrupt.\n");
+ IPG_DEBUG_MSG("RxEarly interrupt\n");
out_enable:
/* Re-enable IPG interrupts. */
@@ -1749,8 +1752,7 @@ static int ipg_nic_open(struct net_device *dev)
rc = request_irq(pdev->irq, ipg_interrupt_handler, IRQF_SHARED,
dev->name, dev);
if (rc < 0) {
- printk(KERN_INFO "%s: Error when requesting interrupt.\n",
- dev->name);
+ netdev_info(dev, "Error when requesting interrupt\n");
goto out;
}
@@ -1770,8 +1772,7 @@ static int ipg_nic_open(struct net_device *dev)
rc = init_rfdlist(dev);
if (rc < 0) {
- printk(KERN_INFO "%s: Error during configuration.\n",
- dev->name);
+ netdev_info(dev, "Error during configuration\n");
goto err_free_tx_2;
}
@@ -1779,14 +1780,13 @@ static int ipg_nic_open(struct net_device *dev)
rc = ipg_io_config(dev);
if (rc < 0) {
- printk(KERN_INFO "%s: Error during configuration.\n",
- dev->name);
+ netdev_info(dev, "Error during configuration\n");
goto err_release_tfdlist_3;
}
/* Resolve autonegotiation. */
if (ipg_config_autoneg(dev) < 0)
- printk(KERN_INFO "%s: Auto-negotiation error.\n", dev->name);
+ netdev_info(dev, "Auto-negotiation error\n");
/* initialize JUMBO Frame control variable */
sp->jumbo.found_start = 0;
@@ -1961,7 +1961,7 @@ static void ipg_set_phy_default_param(unsigned char rev,
{
unsigned short length;
unsigned char revision;
- unsigned short *phy_param;
+ const unsigned short *phy_param;
unsigned short address, value;
phy_param = &DefaultPhyParam[0];
@@ -2201,7 +2201,7 @@ static const struct net_device_ops ipg_netdev_ops = {
.ndo_stop = ipg_nic_stop,
.ndo_start_xmit = ipg_nic_hard_start_xmit,
.ndo_get_stats = ipg_nic_get_stats,
- .ndo_set_multicast_list = ipg_nic_set_multicast_list,
+ .ndo_set_rx_mode = ipg_nic_set_multicast_list,
.ndo_do_ioctl = ipg_ioctl,
.ndo_tx_timeout = ipg_tx_timeout,
.ndo_change_mtu = ipg_nic_change_mtu,
@@ -2222,7 +2222,7 @@ static int __devinit ipg_probe(struct pci_dev *pdev,
if (rc < 0)
goto out;
- printk(KERN_INFO "%s: %s\n", pci_name(pdev), ipg_brand_name[i]);
+ pr_info("%s: %s\n", pci_name(pdev), ipg_brand_name[i]);
pci_set_master(pdev);
@@ -2230,8 +2230,7 @@ static int __devinit ipg_probe(struct pci_dev *pdev,
if (rc < 0) {
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc < 0) {
- printk(KERN_ERR "%s: DMA config failed.\n",
- pci_name(pdev));
+ pr_err("%s: DMA config failed\n", pci_name(pdev));
goto err_disable_0;
}
}
@@ -2241,7 +2240,7 @@ static int __devinit ipg_probe(struct pci_dev *pdev,
*/
dev = alloc_etherdev(sizeof(struct ipg_nic_private));
if (!dev) {
- printk(KERN_ERR "%s: alloc_etherdev failed\n", pci_name(pdev));
+ pr_err("%s: alloc_etherdev failed\n", pci_name(pdev));
rc = -ENOMEM;
goto err_disable_0;
}
@@ -2267,7 +2266,7 @@ static int __devinit ipg_probe(struct pci_dev *pdev,
ioaddr = pci_iomap(pdev, 1, pci_resource_len(pdev, 1));
if (!ioaddr) {
- printk(KERN_ERR "%s cannot map MMIO\n", pci_name(pdev));
+ pr_err("%s: cannot map MMIO\n", pci_name(pdev));
rc = -EIO;
goto err_release_regions_2;
}
@@ -2289,7 +2288,7 @@ static int __devinit ipg_probe(struct pci_dev *pdev,
if (rc < 0)
goto err_unmap_3;
- printk(KERN_INFO "Ethernet device registered as: %s\n", dev->name);
+ netdev_info(dev, "Ethernet device registered\n");
out:
return rc;
diff --git a/drivers/net/ipg.h b/drivers/net/ethernet/icplus/ipg.h
index 6ce027355fcf..6ce027355fcf 100644
--- a/drivers/net/ipg.h
+++ b/drivers/net/ethernet/icplus/ipg.h
diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig
new file mode 100644
index 000000000000..61029dc7fa6f
--- /dev/null
+++ b/drivers/net/ethernet/intel/Kconfig
@@ -0,0 +1,222 @@
+#
+# Intel network device configuration
+#
+
+config NET_VENDOR_INTEL
+ bool "Intel devices"
+ default y
+ depends on PCI || PCI_MSI
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Intel cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_INTEL
+
+config E100
+ tristate "Intel(R) PRO/100+ support"
+ depends on PCI
+ select NET_CORE
+ select MII
+ ---help---
+ This driver supports Intel(R) PRO/100 family of adapters.
+ To verify that your adapter is supported, find the board ID number
+ on the adapter. Look for a label that has a barcode and a number
+ in the format 123456-001 (six digits hyphen three digits).
+
+ Use the above information and the Adapter & Driver ID Guide at:
+
+ <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+ to identify the adapter.
+
+ For the latest Intel PRO/100 network driver for Linux, see:
+
+ <http://www.intel.com/p/en_US/support/highlights/network/pro100plus>
+
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/e100.txt>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called e100.
+
+config E1000
+ tristate "Intel(R) PRO/1000 Gigabit Ethernet support"
+ depends on PCI
+ ---help---
+ This driver supports Intel(R) PRO/1000 gigabit ethernet family of
+ adapters. For more information on how to identify your adapter, go
+ to the Adapter & Driver ID Guide at:
+
+ <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+ For general information and support, go to the Intel support
+ website at:
+
+ <http://support.intel.com>
+
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/e1000.txt>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called e1000.
+
+config E1000E
+ tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support"
+ depends on PCI && (!SPARC32 || BROKEN)
+ select CRC32
+ ---help---
+ This driver supports the PCI-Express Intel(R) PRO/1000 gigabit
+ ethernet family of adapters. For PCI or PCI-X e1000 adapters,
+ use the regular e1000 driver For more information on how to
+ identify your adapter, go to the Adapter & Driver ID Guide at:
+
+ <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+ For general information and support, go to the Intel support
+ website at:
+
+ <http://support.intel.com>
+
+ To compile this driver as a module, choose M here. The module
+ will be called e1000e.
+
+config IGB
+ tristate "Intel(R) 82575/82576 PCI-Express Gigabit Ethernet support"
+ depends on PCI
+ ---help---
+ This driver supports Intel(R) 82575/82576 gigabit ethernet family of
+ adapters. For more information on how to identify your adapter, go
+ to the Adapter & Driver ID Guide at:
+
+ <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+ For general information and support, go to the Intel support
+ website at:
+
+ <http://support.intel.com>
+
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/e1000.txt>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called igb.
+
+config IGB_DCA
+ bool "Direct Cache Access (DCA) Support"
+ default y
+ depends on IGB && DCA && !(IGB=y && DCA=m)
+ ---help---
+ Say Y here if you want to use Direct Cache Access (DCA) in the
+ driver. DCA is a method for warming the CPU cache before data
+ is used, with the intent of lessening the impact of cache misses.
+
+config IGBVF
+ tristate "Intel(R) 82576 Virtual Function Ethernet support"
+ depends on PCI
+ ---help---
+ This driver supports Intel(R) 82576 virtual functions. For more
+ information on how to identify your adapter, go to the Adapter &
+ Driver ID Guide at:
+
+ <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+ For general information and support, go to the Intel support
+ website at:
+
+ <http://support.intel.com>
+
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/e1000.txt>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called igbvf.
+
+config IXGB
+ tristate "Intel(R) PRO/10GbE support"
+ depends on PCI
+ ---help---
+ This driver supports Intel(R) PRO/10GbE family of adapters for
+ PCI-X type cards. For PCI-E type cards, use the "ixgbe" driver
+ instead. For more information on how to identify your adapter, go
+ to the Adapter & Driver ID Guide at:
+
+ <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+ For general information and support, go to the Intel support
+ website at:
+
+ <http://support.intel.com>
+
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/ixgb.txt>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called ixgb.
+
+config IXGBE
+ tristate "Intel(R) 10GbE PCI Express adapters support"
+ depends on PCI && INET
+ select MDIO
+ ---help---
+ This driver supports Intel(R) 10GbE PCI Express family of
+ adapters. For more information on how to identify your adapter, go
+ to the Adapter & Driver ID Guide at:
+
+ <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+ For general information and support, go to the Intel support
+ website at:
+
+ <http://support.intel.com>
+
+ To compile this driver as a module, choose M here. The module
+ will be called ixgbe.
+
+config IXGBE_DCA
+ bool "Direct Cache Access (DCA) Support"
+ default y
+ depends on IXGBE && DCA && !(IXGBE=y && DCA=m)
+ ---help---
+ Say Y here if you want to use Direct Cache Access (DCA) in the
+ driver. DCA is a method for warming the CPU cache before data
+ is used, with the intent of lessening the impact of cache misses.
+
+config IXGBE_DCB
+ bool "Data Center Bridging (DCB) Support"
+ default n
+ depends on IXGBE && DCB
+ ---help---
+ Say Y here if you want to use Data Center Bridging (DCB) in the
+ driver.
+
+ If unsure, say N.
+
+config IXGBEVF
+ tristate "Intel(R) 82599 Virtual Function Ethernet support"
+ depends on PCI_MSI
+ ---help---
+ This driver supports Intel(R) 82599 virtual functions. For more
+ information on how to identify your adapter, go to the Adapter &
+ Driver ID Guide at:
+
+ <http://support.intel.com/support/network/sb/CS-008441.htm>
+
+ For general information and support, go to the Intel support
+ website at:
+
+ <http://support.intel.com>
+
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/ixgbevf.txt>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called ixgbevf. MSI-X interrupt support is required
+ for this driver to work correctly.
+
+endif # NET_VENDOR_INTEL
diff --git a/drivers/net/ethernet/intel/Makefile b/drivers/net/ethernet/intel/Makefile
new file mode 100644
index 000000000000..c8210e688669
--- /dev/null
+++ b/drivers/net/ethernet/intel/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for the Intel network device drivers.
+#
+
+obj-$(CONFIG_E100) += e100.o
+obj-$(CONFIG_E1000) += e1000/
+obj-$(CONFIG_E1000E) += e1000e/
+obj-$(CONFIG_IGB) += igb/
+obj-$(CONFIG_IGBVF) += igbvf/
+obj-$(CONFIG_IXGBE) += ixgbe/
+obj-$(CONFIG_IXGBEVF) += ixgbevf/
+obj-$(CONFIG_IXGB) += ixgb/
diff --git a/drivers/net/e100.c b/drivers/net/ethernet/intel/e100.c
index c1352c60c299..ae17cd1a907f 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/ethernet/intel/e100.c
@@ -2502,12 +2502,8 @@ static void e100_get_ringparam(struct net_device *netdev,
ring->rx_max_pending = rfds->max;
ring->tx_max_pending = cbs->max;
- ring->rx_mini_max_pending = 0;
- ring->rx_jumbo_max_pending = 0;
ring->rx_pending = rfds->count;
ring->tx_pending = cbs->count;
- ring->rx_mini_pending = 0;
- ring->rx_jumbo_pending = 0;
}
static int e100_set_ringparam(struct net_device *netdev,
@@ -2738,7 +2734,7 @@ static const struct net_device_ops e100_netdev_ops = {
.ndo_stop = e100_close,
.ndo_start_xmit = e100_xmit_frame,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = e100_set_multicast_list,
+ .ndo_set_rx_mode = e100_set_multicast_list,
.ndo_set_mac_address = e100_set_mac_address,
.ndo_change_mtu = e100_change_mtu,
.ndo_do_ioctl = e100_do_ioctl,
diff --git a/drivers/net/e1000/Makefile b/drivers/net/ethernet/intel/e1000/Makefile
index 4a6ab1522451..4a6ab1522451 100644
--- a/drivers/net/e1000/Makefile
+++ b/drivers/net/ethernet/intel/e1000/Makefile
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/ethernet/intel/e1000/e1000.h
index 24f41da8c4be..1e1596990b5c 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/ethernet/intel/e1000/e1000.h
@@ -150,6 +150,8 @@ struct e1000_buffer {
unsigned long time_stamp;
u16 length;
u16 next_to_watch;
+ unsigned int segs;
+ unsigned int bytecount;
u16 mapped_as_page;
};
@@ -212,9 +214,6 @@ struct e1000_rx_ring {
/* board specific private data structure */
struct e1000_adapter {
- struct timer_list tx_fifo_stall_timer;
- struct timer_list watchdog_timer;
- struct timer_list phy_info_timer;
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
u16 mng_vlan_id;
u32 bd_number;
@@ -235,7 +234,6 @@ struct e1000_adapter {
u16 tx_itr;
u16 rx_itr;
- struct work_struct reset_task;
u8 fc_autoneg;
/* TX */
@@ -308,8 +306,12 @@ struct e1000_adapter {
bool discarding;
- struct work_struct fifo_stall_task;
- struct work_struct phy_info_task;
+ struct work_struct reset_task;
+ struct delayed_work watchdog_task;
+ struct delayed_work fifo_stall_task;
+ struct delayed_work phy_info_task;
+
+ struct mutex mutex;
};
enum e1000_state_t {
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
index 5548d464261a..2b223ac99c42 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
@@ -540,12 +540,8 @@ static void e1000_get_ringparam(struct net_device *netdev,
E1000_MAX_82544_RXD;
ring->tx_max_pending = (mac_type < e1000_82544) ? E1000_MAX_TXD :
E1000_MAX_82544_TXD;
- ring->rx_mini_max_pending = 0;
- ring->rx_jumbo_max_pending = 0;
ring->rx_pending = rxdr->count;
ring->tx_pending = txdr->count;
- ring->rx_mini_pending = 0;
- ring->rx_jumbo_pending = 0;
}
static int e1000_set_ringparam(struct net_device *netdev,
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/ethernet/intel/e1000/e1000_hw.c
index 8545c7aa93eb..36ee76bf4cba 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_hw.c
@@ -4026,6 +4026,12 @@ s32 e1000_validate_eeprom_checksum(struct e1000_hw *hw)
checksum += eeprom_data;
}
+#ifdef CONFIG_PARISC
+ /* This is a signature and not a checksum on HP c8000 */
+ if ((hw->subsystem_vendor_id == 0x103C) && (eeprom_data == 0x16d6))
+ return E1000_SUCCESS;
+
+#endif
if (checksum == (u16) EEPROM_SUM)
return E1000_SUCCESS;
else {
@@ -5379,7 +5385,7 @@ static s32 e1000_config_dsp_after_link_change(struct e1000_hw *hw, bool link_up)
if (ret_val)
return ret_val;
- mdelay(20);
+ msleep(20);
ret_val = e1000_write_phy_reg(hw, 0x0000,
IGP01E1000_IEEE_FORCE_GIGA);
@@ -5407,7 +5413,7 @@ static s32 e1000_config_dsp_after_link_change(struct e1000_hw *hw, bool link_up)
if (ret_val)
return ret_val;
- mdelay(20);
+ msleep(20);
/* Now enable the transmitter */
ret_val =
@@ -5434,7 +5440,7 @@ static s32 e1000_config_dsp_after_link_change(struct e1000_hw *hw, bool link_up)
if (ret_val)
return ret_val;
- mdelay(20);
+ msleep(20);
ret_val = e1000_write_phy_reg(hw, 0x0000,
IGP01E1000_IEEE_FORCE_GIGA);
@@ -5451,7 +5457,7 @@ static s32 e1000_config_dsp_after_link_change(struct e1000_hw *hw, bool link_up)
if (ret_val)
return ret_val;
- mdelay(20);
+ msleep(20);
/* Now enable the transmitter */
ret_val =
@@ -5744,26 +5750,26 @@ static s32 e1000_polarity_reversal_workaround(struct e1000_hw *hw)
if ((mii_status_reg & ~MII_SR_LINK_STATUS) == 0)
break;
- mdelay(100);
+ msleep(100);
}
/* Recommended delay time after link has been lost */
- mdelay(1000);
+ msleep(1000);
/* Now we will re-enable th transmitter on the PHY */
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019);
if (ret_val)
return ret_val;
- mdelay(50);
+ msleep(50);
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFF0);
if (ret_val)
return ret_val;
- mdelay(50);
+ msleep(50);
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFF00);
if (ret_val)
return ret_val;
- mdelay(50);
+ msleep(50);
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0x0000);
if (ret_val)
return ret_val;
@@ -5788,7 +5794,7 @@ static s32 e1000_polarity_reversal_workaround(struct e1000_hw *hw)
if (mii_status_reg & MII_SR_LINK_STATUS)
break;
- mdelay(100);
+ msleep(100);
}
return E1000_SUCCESS;
}
@@ -5819,6 +5825,6 @@ static s32 e1000_get_auto_rd_done(struct e1000_hw *hw)
static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw)
{
e_dbg("e1000_get_phy_cfg_done");
- mdelay(10);
+ msleep(10);
return E1000_SUCCESS;
}
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/ethernet/intel/e1000/e1000_hw.h
index 5c9a8403668b..5c9a8403668b 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/ethernet/intel/e1000/e1000_hw.h
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index f97afda941d7..cf480b554622 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -131,10 +131,8 @@ static void e1000_clean_tx_ring(struct e1000_adapter *adapter,
static void e1000_clean_rx_ring(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring);
static void e1000_set_rx_mode(struct net_device *netdev);
-static void e1000_update_phy_info(unsigned long data);
static void e1000_update_phy_info_task(struct work_struct *work);
-static void e1000_watchdog(unsigned long data);
-static void e1000_82547_tx_fifo_stall(unsigned long data);
+static void e1000_watchdog(struct work_struct *work);
static void e1000_82547_tx_fifo_stall_task(struct work_struct *work);
static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
struct net_device *netdev);
@@ -487,12 +485,21 @@ static void e1000_power_down_phy(struct e1000_adapter *adapter)
e1000_read_phy_reg(hw, PHY_CTRL, &mii_reg);
mii_reg |= MII_CR_POWER_DOWN;
e1000_write_phy_reg(hw, PHY_CTRL, mii_reg);
- mdelay(1);
+ msleep(1);
}
out:
return;
}
+static void e1000_down_and_stop(struct e1000_adapter *adapter)
+{
+ set_bit(__E1000_DOWN, &adapter->flags);
+ cancel_work_sync(&adapter->reset_task);
+ cancel_delayed_work_sync(&adapter->watchdog_task);
+ cancel_delayed_work_sync(&adapter->phy_info_task);
+ cancel_delayed_work_sync(&adapter->fifo_stall_task);
+}
+
void e1000_down(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
@@ -522,13 +529,9 @@ void e1000_down(struct e1000_adapter *adapter)
/*
* Setting DOWN must be after irq_disable to prevent
* a screaming interrupt. Setting DOWN also prevents
- * timers and tasks from rescheduling.
+ * tasks from rescheduling.
*/
- set_bit(__E1000_DOWN, &adapter->flags);
-
- del_timer_sync(&adapter->tx_fifo_stall_timer);
- del_timer_sync(&adapter->watchdog_timer);
- del_timer_sync(&adapter->phy_info_timer);
+ e1000_down_and_stop(adapter);
adapter->link_speed = 0;
adapter->link_duplex = 0;
@@ -543,10 +546,10 @@ static void e1000_reinit_safe(struct e1000_adapter *adapter)
{
while (test_and_set_bit(__E1000_RESETTING, &adapter->flags))
msleep(1);
- rtnl_lock();
+ mutex_lock(&adapter->mutex);
e1000_down(adapter);
e1000_up(adapter);
- rtnl_unlock();
+ mutex_unlock(&adapter->mutex);
clear_bit(__E1000_RESETTING, &adapter->flags);
}
@@ -1080,6 +1083,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
netdev->vlan_features |= NETIF_F_HW_CSUM;
netdev->vlan_features |= NETIF_F_SG;
+ netdev->priv_flags |= IFF_UNICAST_FLT;
+
adapter->en_mng_pt = e1000_enable_mng_pass_thru(hw);
/* initialize eeprom parameters */
@@ -1118,21 +1123,12 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
if (!is_valid_ether_addr(netdev->perm_addr))
e_err(probe, "Invalid MAC Address\n");
- init_timer(&adapter->tx_fifo_stall_timer);
- adapter->tx_fifo_stall_timer.function = e1000_82547_tx_fifo_stall;
- adapter->tx_fifo_stall_timer.data = (unsigned long)adapter;
-
- init_timer(&adapter->watchdog_timer);
- adapter->watchdog_timer.function = e1000_watchdog;
- adapter->watchdog_timer.data = (unsigned long) adapter;
- init_timer(&adapter->phy_info_timer);
- adapter->phy_info_timer.function = e1000_update_phy_info;
- adapter->phy_info_timer.data = (unsigned long)adapter;
-
- INIT_WORK(&adapter->fifo_stall_task, e1000_82547_tx_fifo_stall_task);
+ INIT_DELAYED_WORK(&adapter->watchdog_task, e1000_watchdog);
+ INIT_DELAYED_WORK(&adapter->fifo_stall_task,
+ e1000_82547_tx_fifo_stall_task);
+ INIT_DELAYED_WORK(&adapter->phy_info_task, e1000_update_phy_info_task);
INIT_WORK(&adapter->reset_task, e1000_reset_task);
- INIT_WORK(&adapter->phy_info_task, e1000_update_phy_info_task);
e1000_check_options(adapter);
@@ -1277,13 +1273,7 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- set_bit(__E1000_DOWN, &adapter->flags);
- del_timer_sync(&adapter->tx_fifo_stall_timer);
- del_timer_sync(&adapter->watchdog_timer);
- del_timer_sync(&adapter->phy_info_timer);
-
- cancel_work_sync(&adapter->reset_task);
-
+ e1000_down_and_stop(adapter);
e1000_release_manageability(adapter);
unregister_netdev(netdev);
@@ -1327,6 +1317,7 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter)
e1000_irq_disable(adapter);
spin_lock_init(&adapter->stats_lock);
+ mutex_init(&adapter->mutex);
set_bit(__E1000_DOWN, &adapter->flags);
@@ -1367,7 +1358,7 @@ static int __devinit e1000_alloc_queues(struct e1000_adapter *adapter)
* The open entry point is called when a network interface is made
* active by the system (IFF_UP). At this point all resources needed
* for transmit and receive operations are allocated, the interrupt
- * handler is registered with the OS, the watchdog timer is started,
+ * handler is registered with the OS, the watchdog task is started,
* and the stack is notified that the interface is ready.
**/
@@ -1812,8 +1803,8 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
- rctl |= E1000_RCTL_EN | E1000_RCTL_BAM |
- E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
+ rctl |= E1000_RCTL_BAM | E1000_RCTL_LBM_NO |
+ E1000_RCTL_RDMTS_HALF |
(hw->mc_filter_type << E1000_RCTL_MO_SHIFT);
if (hw->tbi_compatibility_on == 1)
@@ -1915,7 +1906,7 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
}
/* Enable Receives */
- ew32(RCTL, rctl);
+ ew32(RCTL, rctl | E1000_RCTL_EN);
}
/**
@@ -2329,35 +2320,23 @@ static void e1000_set_rx_mode(struct net_device *netdev)
kfree(mcarray);
}
-/* Need to wait a few seconds after link up to get diagnostic information from
- * the phy */
-
-static void e1000_update_phy_info(unsigned long data)
-{
- struct e1000_adapter *adapter = (struct e1000_adapter *)data;
- schedule_work(&adapter->phy_info_task);
-}
-
+/**
+ * e1000_update_phy_info_task - get phy info
+ * @work: work struct contained inside adapter struct
+ *
+ * Need to wait a few seconds after link up to get diagnostic information from
+ * the phy
+ */
static void e1000_update_phy_info_task(struct work_struct *work)
{
struct e1000_adapter *adapter = container_of(work,
- struct e1000_adapter,
- phy_info_task);
- struct e1000_hw *hw = &adapter->hw;
-
- rtnl_lock();
- e1000_phy_get_info(hw, &adapter->phy_info);
- rtnl_unlock();
-}
-
-/**
- * e1000_82547_tx_fifo_stall - Timer Call-back
- * @data: pointer to adapter cast into an unsigned long
- **/
-static void e1000_82547_tx_fifo_stall(unsigned long data)
-{
- struct e1000_adapter *adapter = (struct e1000_adapter *)data;
- schedule_work(&adapter->fifo_stall_task);
+ struct e1000_adapter,
+ phy_info_task.work);
+ if (test_bit(__E1000_DOWN, &adapter->flags))
+ return;
+ mutex_lock(&adapter->mutex);
+ e1000_phy_get_info(&adapter->hw, &adapter->phy_info);
+ mutex_unlock(&adapter->mutex);
}
/**
@@ -2367,13 +2346,15 @@ static void e1000_82547_tx_fifo_stall(unsigned long data)
static void e1000_82547_tx_fifo_stall_task(struct work_struct *work)
{
struct e1000_adapter *adapter = container_of(work,
- struct e1000_adapter,
- fifo_stall_task);
+ struct e1000_adapter,
+ fifo_stall_task.work);
struct e1000_hw *hw = &adapter->hw;
struct net_device *netdev = adapter->netdev;
u32 tctl;
- rtnl_lock();
+ if (test_bit(__E1000_DOWN, &adapter->flags))
+ return;
+ mutex_lock(&adapter->mutex);
if (atomic_read(&adapter->tx_fifo_stall)) {
if ((er32(TDT) == er32(TDH)) &&
(er32(TDFT) == er32(TDFH)) &&
@@ -2391,10 +2372,10 @@ static void e1000_82547_tx_fifo_stall_task(struct work_struct *work)
atomic_set(&adapter->tx_fifo_stall, 0);
netif_wake_queue(netdev);
} else if (!test_bit(__E1000_DOWN, &adapter->flags)) {
- mod_timer(&adapter->tx_fifo_stall_timer, jiffies + 1);
+ schedule_delayed_work(&adapter->fifo_stall_task, 1);
}
}
- rtnl_unlock();
+ mutex_unlock(&adapter->mutex);
}
bool e1000_has_link(struct e1000_adapter *adapter)
@@ -2435,17 +2416,23 @@ bool e1000_has_link(struct e1000_adapter *adapter)
}
/**
- * e1000_watchdog - Timer Call-back
- * @data: pointer to adapter cast into an unsigned long
+ * e1000_watchdog - work function
+ * @work: work struct contained inside adapter struct
**/
-static void e1000_watchdog(unsigned long data)
+static void e1000_watchdog(struct work_struct *work)
{
- struct e1000_adapter *adapter = (struct e1000_adapter *)data;
+ struct e1000_adapter *adapter = container_of(work,
+ struct e1000_adapter,
+ watchdog_task.work);
struct e1000_hw *hw = &adapter->hw;
struct net_device *netdev = adapter->netdev;
struct e1000_tx_ring *txdr = adapter->tx_ring;
u32 link, tctl;
+ if (test_bit(__E1000_DOWN, &adapter->flags))
+ return;
+
+ mutex_lock(&adapter->mutex);
link = e1000_has_link(adapter);
if ((netif_carrier_ok(netdev)) && link)
goto link_up;
@@ -2491,8 +2478,8 @@ static void e1000_watchdog(unsigned long data)
netif_carrier_on(netdev);
if (!test_bit(__E1000_DOWN, &adapter->flags))
- mod_timer(&adapter->phy_info_timer,
- round_jiffies(jiffies + 2 * HZ));
+ schedule_delayed_work(&adapter->phy_info_task,
+ 2 * HZ);
adapter->smartspeed = 0;
}
} else {
@@ -2504,8 +2491,8 @@ static void e1000_watchdog(unsigned long data)
netif_carrier_off(netdev);
if (!test_bit(__E1000_DOWN, &adapter->flags))
- mod_timer(&adapter->phy_info_timer,
- round_jiffies(jiffies + 2 * HZ));
+ schedule_delayed_work(&adapter->phy_info_task,
+ 2 * HZ);
}
e1000_smartspeed(adapter);
@@ -2534,8 +2521,8 @@ link_up:
* (Do the reset outside of interrupt context). */
adapter->tx_timeout_count++;
schedule_work(&adapter->reset_task);
- /* return immediately since reset is imminent */
- return;
+ /* exit immediately since reset is imminent */
+ goto unlock;
}
}
@@ -2561,10 +2548,12 @@ link_up:
/* Force detection of hung controller every watchdog period */
adapter->detect_tx_hung = true;
- /* Reset the timer */
+ /* Reschedule the task */
if (!test_bit(__E1000_DOWN, &adapter->flags))
- mod_timer(&adapter->watchdog_timer,
- round_jiffies(jiffies + 2 * HZ));
+ schedule_delayed_work(&adapter->watchdog_task, 2 * HZ);
+
+unlock:
+ mutex_unlock(&adapter->mutex);
}
enum latency_range {
@@ -2846,7 +2835,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
struct e1000_buffer *buffer_info;
unsigned int len = skb_headlen(skb);
unsigned int offset = 0, size, count = 0, i;
- unsigned int f;
+ unsigned int f, bytecount, segs;
i = tx_ring->next_to_use;
@@ -2905,13 +2894,14 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
}
for (f = 0; f < nr_frags; f++) {
- struct skb_frag_struct *frag;
+ const struct skb_frag_struct *frag;
frag = &skb_shinfo(skb)->frags[f];
- len = frag->size;
- offset = frag->page_offset;
+ len = skb_frag_size(frag);
+ offset = 0;
while (len) {
+ unsigned long bufend;
i++;
if (unlikely(i == tx_ring->count))
i = 0;
@@ -2925,18 +2915,19 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
/* Workaround for potential 82544 hang in PCI-X.
* Avoid terminating buffers within evenly-aligned
* dwords. */
+ bufend = (unsigned long)
+ page_to_phys(skb_frag_page(frag));
+ bufend += offset + size - 1;
if (unlikely(adapter->pcix_82544 &&
- !((unsigned long)(page_to_phys(frag->page) + offset
- + size - 1) & 4) &&
- size > 4))
+ !(bufend & 4) &&
+ size > 4))
size -= 4;
buffer_info->length = size;
buffer_info->time_stamp = jiffies;
buffer_info->mapped_as_page = true;
- buffer_info->dma = dma_map_page(&pdev->dev, frag->page,
- offset, size,
- DMA_TO_DEVICE);
+ buffer_info->dma = skb_frag_dma_map(&pdev->dev, frag,
+ offset, size, DMA_TO_DEVICE);
if (dma_mapping_error(&pdev->dev, buffer_info->dma))
goto dma_error;
buffer_info->next_to_watch = i;
@@ -2947,7 +2938,13 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
}
}
+ segs = skb_shinfo(skb)->gso_segs ?: 1;
+ /* multiply data chunks by size of headers */
+ bytecount = ((segs - 1) * skb_headlen(skb)) + skb->len;
+
tx_ring->buffer_info[i].skb = skb;
+ tx_ring->buffer_info[i].segs = segs;
+ tx_ring->buffer_info[i].bytecount = bytecount;
tx_ring->buffer_info[first].next_to_watch = i;
return count;
@@ -3186,7 +3183,7 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
nr_frags = skb_shinfo(skb)->nr_frags;
for (f = 0; f < nr_frags; f++)
- count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size,
+ count += TXD_USE_COUNT(skb_frag_size(&skb_shinfo(skb)->frags[f]),
max_txd_pwr);
if (adapter->pcix_82544)
count += nr_frags;
@@ -3196,14 +3193,12 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
if (unlikely(e1000_maybe_stop_tx(netdev, tx_ring, count + 2)))
return NETDEV_TX_BUSY;
- if (unlikely(hw->mac_type == e1000_82547)) {
- if (unlikely(e1000_82547_fifo_workaround(adapter, skb))) {
- netif_stop_queue(netdev);
- if (!test_bit(__E1000_DOWN, &adapter->flags))
- mod_timer(&adapter->tx_fifo_stall_timer,
- jiffies + 1);
- return NETDEV_TX_BUSY;
- }
+ if (unlikely((hw->mac_type == e1000_82547) &&
+ (e1000_82547_fifo_workaround(adapter, skb)))) {
+ netif_stop_queue(netdev);
+ if (!test_bit(__E1000_DOWN, &adapter->flags))
+ schedule_delayed_work(&adapter->fifo_stall_task, 1);
+ return NETDEV_TX_BUSY;
}
if (vlan_tx_tag_present(skb)) {
@@ -3265,6 +3260,8 @@ static void e1000_reset_task(struct work_struct *work)
struct e1000_adapter *adapter =
container_of(work, struct e1000_adapter, reset_task);
+ if (test_bit(__E1000_DOWN, &adapter->flags))
+ return;
e1000_reinit_safe(adapter);
}
@@ -3273,7 +3270,7 @@ static void e1000_reset_task(struct work_struct *work)
* @netdev: network interface device structure
*
* Returns the address of the device statistics structure.
- * The statistics are actually updated from the timer callback.
+ * The statistics are actually updated from the watchdog.
**/
static struct net_device_stats *e1000_get_stats(struct net_device *netdev)
@@ -3541,7 +3538,7 @@ static irqreturn_t e1000_intr(int irq, void *data)
hw->get_link_status = 1;
/* guard against interrupt when we're going down */
if (!test_bit(__E1000_DOWN, &adapter->flags))
- mod_timer(&adapter->watchdog_timer, jiffies + 1);
+ schedule_delayed_work(&adapter->watchdog_task, 1);
}
/* disable interrupts, without the synchronize_irq bit */
@@ -3621,14 +3618,8 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
cleaned = (i == eop);
if (cleaned) {
- struct sk_buff *skb = buffer_info->skb;
- unsigned int segs, bytecount;
- segs = skb_shinfo(skb)->gso_segs ?: 1;
- /* multiply data chunks by size of headers */
- bytecount = ((segs - 1) * skb_headlen(skb)) +
- skb->len;
- total_tx_packets += segs;
- total_tx_bytes += bytecount;
+ total_tx_packets += buffer_info->segs;
+ total_tx_bytes += buffer_info->bytecount;
}
e1000_unmap_and_free_tx_resource(adapter, buffer_info);
tx_desc->upper.data = 0;
@@ -3746,7 +3737,7 @@ static void e1000_consume_page(struct e1000_buffer *bi, struct sk_buff *skb,
bi->page = NULL;
skb->len += length;
skb->data_len += length;
- skb->truesize += length;
+ skb->truesize += PAGE_SIZE;
}
/**
@@ -4725,6 +4716,8 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake)
netif_device_detach(netdev);
+ mutex_lock(&adapter->mutex);
+
if (netif_running(netdev)) {
WARN_ON(test_bit(__E1000_RESETTING, &adapter->flags));
e1000_down(adapter);
@@ -4732,8 +4725,10 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake)
#ifdef CONFIG_PM
retval = pci_save_state(pdev);
- if (retval)
+ if (retval) {
+ mutex_unlock(&adapter->mutex);
return retval;
+ }
#endif
status = er32(STATUS);
@@ -4788,6 +4783,8 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake)
if (netif_running(netdev))
e1000_free_irq(adapter);
+ mutex_unlock(&adapter->mutex);
+
pci_disable_device(pdev);
return 0;
diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/ethernet/intel/e1000/e1000_osdep.h
index 33e7c45a4fe4..33e7c45a4fe4 100644
--- a/drivers/net/e1000/e1000_osdep.h
+++ b/drivers/net/ethernet/intel/e1000/e1000_osdep.h
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/ethernet/intel/e1000/e1000_param.c
index 1301eba8b57a..1301eba8b57a 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_param.c
diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/ethernet/intel/e1000e/80003es2lan.c
index e4f42257c24c..e1159e54334a 100644
--- a/drivers/net/e1000e/es2lan.c
+++ b/drivers/net/ethernet/intel/e1000e/80003es2lan.c
@@ -1441,7 +1441,7 @@ static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw)
er32(ICRXDMTC);
}
-static struct e1000_mac_operations es2_mac_ops = {
+static const struct e1000_mac_operations es2_mac_ops = {
.read_mac_addr = e1000_read_mac_addr_80003es2lan,
.id_led_init = e1000e_id_led_init,
.blink_led = e1000e_blink_led_generic,
@@ -1464,7 +1464,7 @@ static struct e1000_mac_operations es2_mac_ops = {
.setup_led = e1000e_setup_led_generic,
};
-static struct e1000_phy_operations es2_phy_ops = {
+static const struct e1000_phy_operations es2_phy_ops = {
.acquire = e1000_acquire_phy_80003es2lan,
.check_polarity = e1000_check_polarity_m88,
.check_reset_block = e1000e_check_reset_block_generic,
@@ -1482,7 +1482,7 @@ static struct e1000_phy_operations es2_phy_ops = {
.cfg_on_link_up = e1000_cfg_on_link_up_80003es2lan,
};
-static struct e1000_nvm_operations es2_nvm_ops = {
+static const struct e1000_nvm_operations es2_nvm_ops = {
.acquire = e1000_acquire_nvm_80003es2lan,
.read = e1000e_read_nvm_eerd,
.release = e1000_release_nvm_80003es2lan,
@@ -1492,13 +1492,12 @@ static struct e1000_nvm_operations es2_nvm_ops = {
.write = e1000_write_nvm_80003es2lan,
};
-struct e1000_info e1000_es2_info = {
+const struct e1000_info e1000_es2_info = {
.mac = e1000_80003es2lan,
.flags = FLAG_HAS_HW_VLAN_FILTER
| FLAG_HAS_JUMBO_FRAMES
| FLAG_HAS_WOL
| FLAG_APME_IN_CTRL3
- | FLAG_RX_CSUM_ENABLED
| FLAG_HAS_CTRLEXT_ON_LOAD
| FLAG_RX_NEEDS_RESTART /* errata */
| FLAG_TARC_SET_BIT_ZERO /* errata */
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/ethernet/intel/e1000e/82571.c
index 536b3a55c45f..a3e65fd26e09 100644
--- a/drivers/net/e1000e/82571.c
+++ b/drivers/net/ethernet/intel/e1000e/82571.c
@@ -1927,7 +1927,7 @@ static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw)
er32(ICRXDMTC);
}
-static struct e1000_mac_operations e82571_mac_ops = {
+static const struct e1000_mac_operations e82571_mac_ops = {
/* .check_mng_mode: mac type dependent */
/* .check_for_link: media type dependent */
.id_led_init = e1000e_id_led_init,
@@ -1949,7 +1949,7 @@ static struct e1000_mac_operations e82571_mac_ops = {
.read_mac_addr = e1000_read_mac_addr_82571,
};
-static struct e1000_phy_operations e82_phy_ops_igp = {
+static const struct e1000_phy_operations e82_phy_ops_igp = {
.acquire = e1000_get_hw_semaphore_82571,
.check_polarity = e1000_check_polarity_igp,
.check_reset_block = e1000e_check_reset_block_generic,
@@ -1967,7 +1967,7 @@ static struct e1000_phy_operations e82_phy_ops_igp = {
.cfg_on_link_up = NULL,
};
-static struct e1000_phy_operations e82_phy_ops_m88 = {
+static const struct e1000_phy_operations e82_phy_ops_m88 = {
.acquire = e1000_get_hw_semaphore_82571,
.check_polarity = e1000_check_polarity_m88,
.check_reset_block = e1000e_check_reset_block_generic,
@@ -1985,7 +1985,7 @@ static struct e1000_phy_operations e82_phy_ops_m88 = {
.cfg_on_link_up = NULL,
};
-static struct e1000_phy_operations e82_phy_ops_bm = {
+static const struct e1000_phy_operations e82_phy_ops_bm = {
.acquire = e1000_get_hw_semaphore_82571,
.check_polarity = e1000_check_polarity_m88,
.check_reset_block = e1000e_check_reset_block_generic,
@@ -2003,7 +2003,7 @@ static struct e1000_phy_operations e82_phy_ops_bm = {
.cfg_on_link_up = NULL,
};
-static struct e1000_nvm_operations e82571_nvm_ops = {
+static const struct e1000_nvm_operations e82571_nvm_ops = {
.acquire = e1000_acquire_nvm_82571,
.read = e1000e_read_nvm_eerd,
.release = e1000_release_nvm_82571,
@@ -2013,13 +2013,12 @@ static struct e1000_nvm_operations e82571_nvm_ops = {
.write = e1000_write_nvm_82571,
};
-struct e1000_info e1000_82571_info = {
+const struct e1000_info e1000_82571_info = {
.mac = e1000_82571,
.flags = FLAG_HAS_HW_VLAN_FILTER
| FLAG_HAS_JUMBO_FRAMES
| FLAG_HAS_WOL
| FLAG_APME_IN_CTRL3
- | FLAG_RX_CSUM_ENABLED
| FLAG_HAS_CTRLEXT_ON_LOAD
| FLAG_HAS_SMART_POWER_DOWN
| FLAG_RESET_OVERWRITES_LAA /* errata */
@@ -2035,13 +2034,12 @@ struct e1000_info e1000_82571_info = {
.nvm_ops = &e82571_nvm_ops,
};
-struct e1000_info e1000_82572_info = {
+const struct e1000_info e1000_82572_info = {
.mac = e1000_82572,
.flags = FLAG_HAS_HW_VLAN_FILTER
| FLAG_HAS_JUMBO_FRAMES
| FLAG_HAS_WOL
| FLAG_APME_IN_CTRL3
- | FLAG_RX_CSUM_ENABLED
| FLAG_HAS_CTRLEXT_ON_LOAD
| FLAG_TARC_SPEED_MODE_BIT, /* errata */
.flags2 = FLAG2_DISABLE_ASPM_L1 /* errata 13 */
@@ -2054,12 +2052,11 @@ struct e1000_info e1000_82572_info = {
.nvm_ops = &e82571_nvm_ops,
};
-struct e1000_info e1000_82573_info = {
+const struct e1000_info e1000_82573_info = {
.mac = e1000_82573,
.flags = FLAG_HAS_HW_VLAN_FILTER
| FLAG_HAS_WOL
| FLAG_APME_IN_CTRL3
- | FLAG_RX_CSUM_ENABLED
| FLAG_HAS_SMART_POWER_DOWN
| FLAG_HAS_AMT
| FLAG_HAS_SWSM_ON_LOAD,
@@ -2073,14 +2070,13 @@ struct e1000_info e1000_82573_info = {
.nvm_ops = &e82571_nvm_ops,
};
-struct e1000_info e1000_82574_info = {
+const struct e1000_info e1000_82574_info = {
.mac = e1000_82574,
.flags = FLAG_HAS_HW_VLAN_FILTER
| FLAG_HAS_MSIX
| FLAG_HAS_JUMBO_FRAMES
| FLAG_HAS_WOL
| FLAG_APME_IN_CTRL3
- | FLAG_RX_CSUM_ENABLED
| FLAG_HAS_SMART_POWER_DOWN
| FLAG_HAS_AMT
| FLAG_HAS_CTRLEXT_ON_LOAD,
@@ -2095,12 +2091,11 @@ struct e1000_info e1000_82574_info = {
.nvm_ops = &e82571_nvm_ops,
};
-struct e1000_info e1000_82583_info = {
+const struct e1000_info e1000_82583_info = {
.mac = e1000_82583,
.flags = FLAG_HAS_HW_VLAN_FILTER
| FLAG_HAS_WOL
| FLAG_APME_IN_CTRL3
- | FLAG_RX_CSUM_ENABLED
| FLAG_HAS_SMART_POWER_DOWN
| FLAG_HAS_AMT
| FLAG_HAS_JUMBO_FRAMES
diff --git a/drivers/net/e1000e/Makefile b/drivers/net/ethernet/intel/e1000e/Makefile
index 28519acacd2d..948c05db5d68 100644
--- a/drivers/net/e1000e/Makefile
+++ b/drivers/net/ethernet/intel/e1000e/Makefile
@@ -32,6 +32,6 @@
obj-$(CONFIG_E1000E) += e1000e.o
-e1000e-objs := 82571.o ich8lan.o es2lan.o \
+e1000e-objs := 82571.o ich8lan.o 80003es2lan.o \
lib.o phy.o param.o ethtool.o netdev.o
diff --git a/drivers/net/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h
index c516a7440bec..c516a7440bec 100644
--- a/drivers/net/e1000e/defines.h
+++ b/drivers/net/ethernet/intel/e1000e/defines.h
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h
index 35916f485028..9fe18d1d53d8 100644
--- a/drivers/net/e1000e/e1000.h
+++ b/drivers/net/ethernet/intel/e1000e/e1000.h
@@ -155,6 +155,9 @@ struct e1000_info;
#define HV_M_STATUS_SPEED_1000 0x0200
#define HV_M_STATUS_LINK_UP 0x0040
+#define E1000_ICH_FWSM_PCIM2PCI 0x01000000 /* ME PCIm-to-PCI active */
+#define E1000_ICH_FWSM_PCIM2PCI_COUNT 2000
+
/* Time to wait before putting the device into D3 if there's no link (in ms). */
#define LINK_TIMEOUT 100
@@ -403,9 +406,9 @@ struct e1000_info {
u32 pba;
u32 max_hw_frame_size;
s32 (*get_variants)(struct e1000_adapter *);
- struct e1000_mac_operations *mac_ops;
- struct e1000_phy_operations *phy_ops;
- struct e1000_nvm_operations *nvm_ops;
+ const struct e1000_mac_operations *mac_ops;
+ const struct e1000_phy_operations *phy_ops;
+ const struct e1000_nvm_operations *nvm_ops;
};
/* hardware capability, feature, and workaround flags */
@@ -437,12 +440,11 @@ struct e1000_info {
#define FLAG_LSC_GIG_SPEED_DROP (1 << 25)
#define FLAG_SMART_POWER_DOWN (1 << 26)
#define FLAG_MSI_ENABLED (1 << 27)
-#define FLAG_RX_CSUM_ENABLED (1 << 28)
+/* reserved (1 << 28) */
#define FLAG_TSO_FORCE (1 << 29)
#define FLAG_RX_RESTART_NOW (1 << 30)
#define FLAG_MSI_TEST_FAILED (1 << 31)
-/* CRC Stripping defines */
#define FLAG2_CRC_STRIPPING (1 << 0)
#define FLAG2_HAS_PHY_WAKEUP (1 << 1)
#define FLAG2_IS_DISCARDING (1 << 2)
@@ -454,17 +456,20 @@ struct e1000_info {
#define FLAG2_DISABLE_AIM (1 << 8)
#define FLAG2_CHECK_PHY_HANG (1 << 9)
#define FLAG2_NO_DISABLE_RX (1 << 10)
+#define FLAG2_PCIM2PCI_ARBITER_WA (1 << 11)
#define E1000_RX_DESC_PS(R, i) \
(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
+#define E1000_RX_DESC_EXT(R, i) \
+ (&(((union e1000_rx_desc_extended *)((R).desc))[i]))
#define E1000_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i]))
-#define E1000_RX_DESC(R, i) E1000_GET_DESC(R, i, e1000_rx_desc)
#define E1000_TX_DESC(R, i) E1000_GET_DESC(R, i, e1000_tx_desc)
#define E1000_CONTEXT_DESC(R, i) E1000_GET_DESC(R, i, e1000_context_desc)
enum e1000_state_t {
__E1000_TESTING,
__E1000_RESETTING,
+ __E1000_ACCESS_SHARED_RESOURCE,
__E1000_DOWN
};
@@ -502,17 +507,17 @@ extern unsigned int copybreak;
extern char *e1000e_get_hw_dev_name(struct e1000_hw *hw);
-extern struct e1000_info e1000_82571_info;
-extern struct e1000_info e1000_82572_info;
-extern struct e1000_info e1000_82573_info;
-extern struct e1000_info e1000_82574_info;
-extern struct e1000_info e1000_82583_info;
-extern struct e1000_info e1000_ich8_info;
-extern struct e1000_info e1000_ich9_info;
-extern struct e1000_info e1000_ich10_info;
-extern struct e1000_info e1000_pch_info;
-extern struct e1000_info e1000_pch2_info;
-extern struct e1000_info e1000_es2_info;
+extern const struct e1000_info e1000_82571_info;
+extern const struct e1000_info e1000_82572_info;
+extern const struct e1000_info e1000_82573_info;
+extern const struct e1000_info e1000_82574_info;
+extern const struct e1000_info e1000_82583_info;
+extern const struct e1000_info e1000_ich8_info;
+extern const struct e1000_info e1000_ich9_info;
+extern const struct e1000_info e1000_ich10_info;
+extern const struct e1000_info e1000_pch_info;
+extern const struct e1000_info e1000_pch2_info;
+extern const struct e1000_info e1000_es2_info;
extern s32 e1000_read_pba_string_generic(struct e1000_hw *hw, u8 *pba_num,
u32 pba_num_size);
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c
index 6a0526a59a8a..69c9d2199140 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/ethernet/intel/e1000e/ethtool.c
@@ -367,59 +367,6 @@ out:
return retval;
}
-static u32 e1000_get_rx_csum(struct net_device *netdev)
-{
- struct e1000_adapter *adapter = netdev_priv(netdev);
- return adapter->flags & FLAG_RX_CSUM_ENABLED;
-}
-
-static int e1000_set_rx_csum(struct net_device *netdev, u32 data)
-{
- struct e1000_adapter *adapter = netdev_priv(netdev);
-
- if (data)
- adapter->flags |= FLAG_RX_CSUM_ENABLED;
- else
- adapter->flags &= ~FLAG_RX_CSUM_ENABLED;
-
- if (netif_running(netdev))
- e1000e_reinit_locked(adapter);
- else
- e1000e_reset(adapter);
- return 0;
-}
-
-static u32 e1000_get_tx_csum(struct net_device *netdev)
-{
- return (netdev->features & NETIF_F_HW_CSUM) != 0;
-}
-
-static int e1000_set_tx_csum(struct net_device *netdev, u32 data)
-{
- if (data)
- netdev->features |= NETIF_F_HW_CSUM;
- else
- netdev->features &= ~NETIF_F_HW_CSUM;
-
- return 0;
-}
-
-static int e1000_set_tso(struct net_device *netdev, u32 data)
-{
- struct e1000_adapter *adapter = netdev_priv(netdev);
-
- if (data) {
- netdev->features |= NETIF_F_TSO;
- netdev->features |= NETIF_F_TSO6;
- } else {
- netdev->features &= ~NETIF_F_TSO;
- netdev->features &= ~NETIF_F_TSO6;
- }
-
- adapter->flags |= FLAG_TSO_FORCE;
- return 0;
-}
-
static u32 e1000_get_msglevel(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -665,12 +612,8 @@ static void e1000_get_ringparam(struct net_device *netdev,
ring->rx_max_pending = E1000_MAX_RXD;
ring->tx_max_pending = E1000_MAX_TXD;
- ring->rx_mini_max_pending = 0;
- ring->rx_jumbo_max_pending = 0;
ring->rx_pending = rx_ring->count;
ring->tx_pending = tx_ring->count;
- ring->rx_mini_pending = 0;
- ring->rx_jumbo_pending = 0;
}
static int e1000_set_ringparam(struct net_device *netdev,
@@ -1195,7 +1138,7 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
goto err_nomem;
}
- rx_ring->size = rx_ring->count * sizeof(struct e1000_rx_desc);
+ rx_ring->size = rx_ring->count * sizeof(union e1000_rx_desc_extended);
rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size,
&rx_ring->dma, GFP_KERNEL);
if (!rx_ring->desc) {
@@ -1221,7 +1164,7 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
ew32(RCTL, rctl);
for (i = 0; i < rx_ring->count; i++) {
- struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rx_ring, i);
+ union e1000_rx_desc_extended *rx_desc;
struct sk_buff *skb;
skb = alloc_skb(2048 + NET_IP_ALIGN, GFP_KERNEL);
@@ -1239,8 +1182,9 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
ret_val = 8;
goto err_nomem;
}
- rx_desc->buffer_addr =
- cpu_to_le64(rx_ring->buffer_info[i].dma);
+ rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
+ rx_desc->read.buffer_addr =
+ cpu_to_le64(rx_ring->buffer_info[i].dma);
memset(skb->data, 0x00, skb->len);
}
@@ -2013,31 +1957,6 @@ static void e1000_get_strings(struct net_device *netdev, u32 stringset,
}
}
-static int e1000e_set_flags(struct net_device *netdev, u32 data)
-{
- struct e1000_adapter *adapter = netdev_priv(netdev);
- bool need_reset = false;
- int rc;
-
- need_reset = (data & ETH_FLAG_RXVLAN) !=
- (netdev->features & NETIF_F_HW_VLAN_RX);
-
- rc = ethtool_op_set_flags(netdev, data, ETH_FLAG_RXVLAN |
- ETH_FLAG_TXVLAN);
-
- if (rc)
- return rc;
-
- if (need_reset) {
- if (netif_running(netdev))
- e1000e_reinit_locked(adapter);
- else
- e1000e_reset(adapter);
- }
-
- return 0;
-}
-
static const struct ethtool_ops e1000_ethtool_ops = {
.get_settings = e1000_get_settings,
.set_settings = e1000_set_settings,
@@ -2057,14 +1976,6 @@ static const struct ethtool_ops e1000_ethtool_ops = {
.set_ringparam = e1000_set_ringparam,
.get_pauseparam = e1000_get_pauseparam,
.set_pauseparam = e1000_set_pauseparam,
- .get_rx_csum = e1000_get_rx_csum,
- .set_rx_csum = e1000_set_rx_csum,
- .get_tx_csum = e1000_get_tx_csum,
- .set_tx_csum = e1000_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
- .set_tso = e1000_set_tso,
.self_test = e1000_diag_test,
.get_strings = e1000_get_strings,
.set_phys_id = e1000_set_phys_id,
@@ -2072,8 +1983,6 @@ static const struct ethtool_ops e1000_ethtool_ops = {
.get_sset_count = e1000e_get_sset_count,
.get_coalesce = e1000_get_coalesce,
.set_coalesce = e1000_set_coalesce,
- .get_flags = ethtool_op_get_flags,
- .set_flags = e1000e_set_flags,
};
void e1000e_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h
index 29670397079b..29670397079b 100644
--- a/drivers/net/e1000e/hw.h
+++ b/drivers/net/ethernet/intel/e1000e/hw.h
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c
index 4e36978b8fd8..6a17c62cb86f 100644
--- a/drivers/net/e1000e/ich8lan.c
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c
@@ -137,8 +137,9 @@
#define HV_PM_CTRL PHY_REG(770, 17)
/* PHY Low Power Idle Control */
-#define I82579_LPI_CTRL PHY_REG(772, 20)
-#define I82579_LPI_CTRL_ENABLE_MASK 0x6000
+#define I82579_LPI_CTRL PHY_REG(772, 20)
+#define I82579_LPI_CTRL_ENABLE_MASK 0x6000
+#define I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT 0x80
/* EMI Registers */
#define I82579_EMI_ADDR 0x10
@@ -163,6 +164,11 @@
#define HV_KMRN_MODE_CTRL PHY_REG(769, 16)
#define HV_KMRN_MDIO_SLOW 0x0400
+/* KMRN FIFO Control and Status */
+#define HV_KMRN_FIFO_CTRLSTA PHY_REG(770, 16)
+#define HV_KMRN_FIFO_CTRLSTA_PREAMBLE_MASK 0x7000
+#define HV_KMRN_FIFO_CTRLSTA_PREAMBLE_SHIFT 12
+
/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
/* Offset 04h HSFSTS */
union ich8_hws_flash_status {
@@ -657,6 +663,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
struct e1000_mac_info *mac = &hw->mac;
s32 ret_val;
bool link;
+ u16 phy_reg;
/*
* We only want to go out to the PHY registers to see if Auto-Neg
@@ -689,16 +696,35 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
mac->get_link_status = false;
- if (hw->phy.type == e1000_phy_82578) {
- ret_val = e1000_link_stall_workaround_hv(hw);
- if (ret_val)
- goto out;
- }
-
- if (hw->mac.type == e1000_pch2lan) {
+ switch (hw->mac.type) {
+ case e1000_pch2lan:
ret_val = e1000_k1_workaround_lv(hw);
if (ret_val)
goto out;
+ /* fall-thru */
+ case e1000_pchlan:
+ if (hw->phy.type == e1000_phy_82578) {
+ ret_val = e1000_link_stall_workaround_hv(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ /*
+ * Workaround for PCHx parts in half-duplex:
+ * Set the number of preambles removed from the packet
+ * when it is passed from the PHY to the MAC to prevent
+ * the MAC from misinterpreting the packet type.
+ */
+ e1e_rphy(hw, HV_KMRN_FIFO_CTRLSTA, &phy_reg);
+ phy_reg &= ~HV_KMRN_FIFO_CTRLSTA_PREAMBLE_MASK;
+
+ if ((er32(STATUS) & E1000_STATUS_FD) != E1000_STATUS_FD)
+ phy_reg |= (1 << HV_KMRN_FIFO_CTRLSTA_PREAMBLE_SHIFT);
+
+ e1e_wphy(hw, HV_KMRN_FIFO_CTRLSTA, phy_reg);
+ break;
+ default:
+ break;
}
/*
@@ -785,9 +811,14 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
}
if ((adapter->hw.mac.type == e1000_ich8lan) &&
- (adapter->hw.phy.type == e1000_phy_igp_3))
+ (adapter->hw.phy.type != e1000_phy_ife))
adapter->flags |= FLAG_LSC_GIG_SPEED_DROP;
+ /* Enable workaround for 82579 w/ ME enabled */
+ if ((adapter->hw.mac.type == e1000_pch2lan) &&
+ (er32(FWSM) & E1000_ICH_FWSM_FW_VALID))
+ adapter->flags2 |= FLAG2_PCIM2PCI_ARBITER_WA;
+
/* Disable EEE by default until IEEE802.3az spec is finalized */
if (adapter->flags2 & FLAG2_HAS_EEE)
adapter->hw.dev_spec.ich8lan.eee_disable = true;
@@ -821,8 +852,6 @@ static void e1000_release_nvm_ich8lan(struct e1000_hw *hw)
mutex_unlock(&nvm_mutex);
}
-static DEFINE_MUTEX(swflag_mutex);
-
/**
* e1000_acquire_swflag_ich8lan - Acquire software control flag
* @hw: pointer to the HW structure
@@ -835,7 +864,12 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
u32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT;
s32 ret_val = 0;
- mutex_lock(&swflag_mutex);
+ if (test_and_set_bit(__E1000_ACCESS_SHARED_RESOURCE,
+ &hw->adapter->state)) {
+ WARN(1, "e1000e: %s: contention for Phy access\n",
+ hw->adapter->netdev->name);
+ return -E1000_ERR_PHY;
+ }
while (timeout) {
extcnf_ctrl = er32(EXTCNF_CTRL);
@@ -847,7 +881,7 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
}
if (!timeout) {
- e_dbg("SW/FW/HW has locked the resource for too long.\n");
+ e_dbg("SW has already locked the resource.\n");
ret_val = -E1000_ERR_CONFIG;
goto out;
}
@@ -867,7 +901,9 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
}
if (!timeout) {
- e_dbg("Failed to acquire the semaphore.\n");
+ e_dbg("Failed to acquire the semaphore, FW or HW has it: "
+ "FWSM=0x%8.8x EXTCNF_CTRL=0x%8.8x)\n",
+ er32(FWSM), extcnf_ctrl);
extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
ew32(EXTCNF_CTRL, extcnf_ctrl);
ret_val = -E1000_ERR_CONFIG;
@@ -876,7 +912,7 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
out:
if (ret_val)
- mutex_unlock(&swflag_mutex);
+ clear_bit(__E1000_ACCESS_SHARED_RESOURCE, &hw->adapter->state);
return ret_val;
}
@@ -901,7 +937,7 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
e_dbg("Semaphore unexpectedly released by sw/fw/hw\n");
}
- mutex_unlock(&swflag_mutex);
+ clear_bit(__E1000_ACCESS_SHARED_RESOURCE, &hw->adapter->state);
}
/**
@@ -1288,16 +1324,20 @@ static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state)
if (mac_reg & E1000_PHY_CTRL_D0A_LPLU)
oem_reg |= HV_OEM_BITS_LPLU;
+
+ /* Set Restart auto-neg to activate the bits */
+ if (!e1000_check_reset_block(hw))
+ oem_reg |= HV_OEM_BITS_RESTART_AN;
} else {
- if (mac_reg & E1000_PHY_CTRL_NOND0A_GBE_DISABLE)
+ if (mac_reg & (E1000_PHY_CTRL_GBE_DISABLE |
+ E1000_PHY_CTRL_NOND0A_GBE_DISABLE))
oem_reg |= HV_OEM_BITS_GBE_DIS;
- if (mac_reg & E1000_PHY_CTRL_NOND0A_LPLU)
+ if (mac_reg & (E1000_PHY_CTRL_D0A_LPLU |
+ E1000_PHY_CTRL_NOND0A_LPLU))
oem_reg |= HV_OEM_BITS_LPLU;
}
- /* Restart auto-neg to activate the bits */
- if (!e1000_check_reset_block(hw))
- oem_reg |= HV_OEM_BITS_RESTART_AN;
+
ret_val = hw->phy.ops.write_reg_locked(hw, HV_OEM_BITS, oem_reg);
out:
@@ -1355,7 +1395,7 @@ static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw)
return ret_val;
/* Preamble tuning for SSC */
- ret_val = e1e_wphy(hw, PHY_REG(770, 16), 0xA204);
+ ret_val = e1e_wphy(hw, HV_KMRN_FIFO_CTRLSTA, 0xA204);
if (ret_val)
return ret_val;
}
@@ -1543,7 +1583,7 @@ s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable)
ret_val = e1e_wphy(hw, PHY_REG(776, 20), data);
if (ret_val)
goto out;
- ret_val = e1e_wphy(hw, PHY_REG(776, 23), 0xFE00);
+ ret_val = e1e_wphy(hw, PHY_REG(776, 23), 0xF100);
if (ret_val)
goto out;
e1e_rphy(hw, HV_PM_CTRL, &data);
@@ -1645,6 +1685,7 @@ static s32 e1000_k1_workaround_lv(struct e1000_hw *hw)
s32 ret_val = 0;
u16 status_reg = 0;
u32 mac_reg;
+ u16 phy_reg;
if (hw->mac.type != e1000_pch2lan)
goto out;
@@ -1659,12 +1700,19 @@ static s32 e1000_k1_workaround_lv(struct e1000_hw *hw)
mac_reg = er32(FEXTNVM4);
mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK;
- if (status_reg & HV_M_STATUS_SPEED_1000)
+ ret_val = e1e_rphy(hw, I82579_LPI_CTRL, &phy_reg);
+ if (ret_val)
+ goto out;
+
+ if (status_reg & HV_M_STATUS_SPEED_1000) {
mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_8USEC;
- else
+ phy_reg &= ~I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT;
+ } else {
mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_16USEC;
-
+ phy_reg |= I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT;
+ }
ew32(FEXTNVM4, mac_reg);
+ ret_val = e1e_wphy(hw, I82579_LPI_CTRL, phy_reg);
}
out:
@@ -3096,7 +3144,7 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
msleep(20);
if (!ret_val)
- mutex_unlock(&swflag_mutex);
+ clear_bit(__E1000_ACCESS_SHARED_RESOURCE, &hw->adapter->state);
if (ctrl & E1000_CTRL_PHY_RST) {
ret_val = hw->phy.ops.get_cfg_done(hw);
@@ -3599,15 +3647,14 @@ void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
* LPLU, Gig disable, MDIC PHY reset):
* 1) Set Kumeran Near-end loopback
* 2) Clear Kumeran Near-end loopback
- * Should only be called for ICH8[m] devices with IGP_3 Phy.
+ * Should only be called for ICH8[m] devices with any 1G Phy.
**/
void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
{
s32 ret_val;
u16 reg_data;
- if ((hw->mac.type != e1000_ich8lan) ||
- (hw->phy.type != e1000_phy_igp_3))
+ if ((hw->mac.type != e1000_ich8lan) || (hw->phy.type == e1000_phy_ife))
return;
ret_val = e1000e_read_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
@@ -3643,8 +3690,12 @@ void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw)
phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU | E1000_PHY_CTRL_GBE_DISABLE;
ew32(PHY_CTRL, phy_ctrl);
+ if (hw->mac.type == e1000_ich8lan)
+ e1000e_gig_downshift_workaround_ich8lan(hw);
+
if (hw->mac.type >= e1000_pchlan) {
e1000_oem_bits_config_ich8lan(hw, false);
+ e1000_phy_hw_reset_ich8lan(hw);
ret_val = hw->phy.ops.acquire(hw);
if (ret_val)
return;
@@ -3972,7 +4023,7 @@ release:
}
}
-static struct e1000_mac_operations ich8_mac_ops = {
+static const struct e1000_mac_operations ich8_mac_ops = {
.id_led_init = e1000e_id_led_init,
/* check_mng_mode dependent on mac type */
.check_for_link = e1000_check_for_copper_link_ich8lan,
@@ -3991,7 +4042,7 @@ static struct e1000_mac_operations ich8_mac_ops = {
/* id_led_init dependent on mac type */
};
-static struct e1000_phy_operations ich8_phy_ops = {
+static const struct e1000_phy_operations ich8_phy_ops = {
.acquire = e1000_acquire_swflag_ich8lan,
.check_reset_block = e1000_check_reset_block_ich8lan,
.commit = NULL,
@@ -4005,7 +4056,7 @@ static struct e1000_phy_operations ich8_phy_ops = {
.write_reg = e1000e_write_phy_reg_igp,
};
-static struct e1000_nvm_operations ich8_nvm_ops = {
+static const struct e1000_nvm_operations ich8_nvm_ops = {
.acquire = e1000_acquire_nvm_ich8lan,
.read = e1000_read_nvm_ich8lan,
.release = e1000_release_nvm_ich8lan,
@@ -4015,11 +4066,10 @@ static struct e1000_nvm_operations ich8_nvm_ops = {
.write = e1000_write_nvm_ich8lan,
};
-struct e1000_info e1000_ich8_info = {
+const struct e1000_info e1000_ich8_info = {
.mac = e1000_ich8lan,
.flags = FLAG_HAS_WOL
| FLAG_IS_ICH
- | FLAG_RX_CSUM_ENABLED
| FLAG_HAS_CTRLEXT_ON_LOAD
| FLAG_HAS_AMT
| FLAG_HAS_FLASH
@@ -4032,12 +4082,11 @@ struct e1000_info e1000_ich8_info = {
.nvm_ops = &ich8_nvm_ops,
};
-struct e1000_info e1000_ich9_info = {
+const struct e1000_info e1000_ich9_info = {
.mac = e1000_ich9lan,
.flags = FLAG_HAS_JUMBO_FRAMES
| FLAG_IS_ICH
| FLAG_HAS_WOL
- | FLAG_RX_CSUM_ENABLED
| FLAG_HAS_CTRLEXT_ON_LOAD
| FLAG_HAS_AMT
| FLAG_HAS_ERT
@@ -4051,12 +4100,11 @@ struct e1000_info e1000_ich9_info = {
.nvm_ops = &ich8_nvm_ops,
};
-struct e1000_info e1000_ich10_info = {
+const struct e1000_info e1000_ich10_info = {
.mac = e1000_ich10lan,
.flags = FLAG_HAS_JUMBO_FRAMES
| FLAG_IS_ICH
| FLAG_HAS_WOL
- | FLAG_RX_CSUM_ENABLED
| FLAG_HAS_CTRLEXT_ON_LOAD
| FLAG_HAS_AMT
| FLAG_HAS_ERT
@@ -4070,11 +4118,10 @@ struct e1000_info e1000_ich10_info = {
.nvm_ops = &ich8_nvm_ops,
};
-struct e1000_info e1000_pch_info = {
+const struct e1000_info e1000_pch_info = {
.mac = e1000_pchlan,
.flags = FLAG_IS_ICH
| FLAG_HAS_WOL
- | FLAG_RX_CSUM_ENABLED
| FLAG_HAS_CTRLEXT_ON_LOAD
| FLAG_HAS_AMT
| FLAG_HAS_FLASH
@@ -4090,11 +4137,10 @@ struct e1000_info e1000_pch_info = {
.nvm_ops = &ich8_nvm_ops,
};
-struct e1000_info e1000_pch2_info = {
+const struct e1000_info e1000_pch2_info = {
.mac = e1000_pch2lan,
.flags = FLAG_IS_ICH
| FLAG_HAS_WOL
- | FLAG_RX_CSUM_ENABLED
| FLAG_HAS_CTRLEXT_ON_LOAD
| FLAG_HAS_AMT
| FLAG_HAS_FLASH
diff --git a/drivers/net/e1000e/lib.c b/drivers/net/ethernet/intel/e1000e/lib.c
index 0893ab107adf..0893ab107adf 100644
--- a/drivers/net/e1000e/lib.c
+++ b/drivers/net/ethernet/intel/e1000e/lib.c
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 362f70382cdd..a855db1ad249 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -47,7 +47,7 @@
#include <linux/if_vlan.h>
#include <linux/cpu.h>
#include <linux/smp.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
#include <linux/pm_runtime.h>
#include <linux/aer.h>
#include <linux/prefetch.h>
@@ -56,7 +56,7 @@
#define DRV_EXTRAVERSION "-k"
-#define DRV_VERSION "1.4.4" DRV_EXTRAVERSION
+#define DRV_VERSION "1.5.1" DRV_EXTRAVERSION
char e1000e_driver_name[] = "e1000e";
const char e1000e_driver_version[] = DRV_VERSION;
@@ -192,7 +192,7 @@ static void e1000e_dump(struct e1000_adapter *adapter)
struct e1000_buffer *buffer_info;
struct e1000_ring *rx_ring = adapter->rx_ring;
union e1000_rx_desc_packet_split *rx_desc_ps;
- struct e1000_rx_desc *rx_desc;
+ union e1000_rx_desc_extended *rx_desc;
struct my_u1 {
u64 a;
u64 b;
@@ -399,41 +399,70 @@ rx_ring_summary:
break;
default:
case 0:
- /* Legacy Receive Descriptor Format
+ /* Extended Receive Descriptor (Read) Format
*
- * +-----------------------------------------------------+
- * | Buffer Address [63:0] |
- * +-----------------------------------------------------+
- * | VLAN Tag | Errors | Status 0 | Packet csum | Length |
- * +-----------------------------------------------------+
- * 63 48 47 40 39 32 31 16 15 0
+ * +-----------------------------------------------------+
+ * 0 | Buffer Address [63:0] |
+ * +-----------------------------------------------------+
+ * 8 | Reserved |
+ * +-----------------------------------------------------+
*/
- printk(KERN_INFO "Rl[desc] [address 63:0 ] "
- "[vl er S cks ln] [bi->dma ] [bi->skb] "
- "<-- Legacy format\n");
- for (i = 0; rx_ring->desc && (i < rx_ring->count); i++) {
- rx_desc = E1000_RX_DESC(*rx_ring, i);
+ printk(KERN_INFO "R [desc] [buf addr 63:0 ] "
+ "[reserved 63:0 ] [bi->dma ] "
+ "[bi->skb] <-- Ext (Read) format\n");
+ /* Extended Receive Descriptor (Write-Back) Format
+ *
+ * 63 48 47 32 31 24 23 4 3 0
+ * +------------------------------------------------------+
+ * | RSS Hash | | | |
+ * 0 +-------------------+ Rsvd | Reserved | MRQ RSS |
+ * | Packet | IP | | | Type |
+ * | Checksum | Ident | | | |
+ * +------------------------------------------------------+
+ * 8 | VLAN Tag | Length | Extended Error | Extended Status |
+ * +------------------------------------------------------+
+ * 63 48 47 32 31 20 19 0
+ */
+ printk(KERN_INFO "RWB[desc] [cs ipid mrq] "
+ "[vt ln xe xs] "
+ "[bi->skb] <-- Ext (Write-Back) format\n");
+
+ for (i = 0; i < rx_ring->count; i++) {
buffer_info = &rx_ring->buffer_info[i];
- u0 = (struct my_u0 *)rx_desc;
- printk(KERN_INFO "Rl[0x%03X] %016llX %016llX "
- "%016llX %p", i,
- (unsigned long long)le64_to_cpu(u0->a),
- (unsigned long long)le64_to_cpu(u0->b),
- (unsigned long long)buffer_info->dma,
- buffer_info->skb);
+ rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
+ u1 = (struct my_u1 *)rx_desc;
+ staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+ if (staterr & E1000_RXD_STAT_DD) {
+ /* Descriptor Done */
+ printk(KERN_INFO "RWB[0x%03X] %016llX "
+ "%016llX ---------------- %p", i,
+ (unsigned long long)le64_to_cpu(u1->a),
+ (unsigned long long)le64_to_cpu(u1->b),
+ buffer_info->skb);
+ } else {
+ printk(KERN_INFO "R [0x%03X] %016llX "
+ "%016llX %016llX %p", i,
+ (unsigned long long)le64_to_cpu(u1->a),
+ (unsigned long long)le64_to_cpu(u1->b),
+ (unsigned long long)buffer_info->dma,
+ buffer_info->skb);
+
+ if (netif_msg_pktdata(adapter))
+ print_hex_dump(KERN_INFO, "",
+ DUMP_PREFIX_ADDRESS, 16,
+ 1,
+ phys_to_virt
+ (buffer_info->dma),
+ adapter->rx_buffer_len,
+ true);
+ }
+
if (i == rx_ring->next_to_use)
printk(KERN_CONT " NTU\n");
else if (i == rx_ring->next_to_clean)
printk(KERN_CONT " NTC\n");
else
printk(KERN_CONT "\n");
-
- if (netif_msg_pktdata(adapter))
- print_hex_dump(KERN_INFO, "",
- DUMP_PREFIX_ADDRESS,
- 16, 1,
- phys_to_virt(buffer_info->dma),
- adapter->rx_buffer_len, true);
}
}
@@ -519,7 +548,64 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,
}
/**
- * e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended
+ * e1000e_update_tail_wa - helper function for e1000e_update_[rt]dt_wa()
+ * @hw: pointer to the HW structure
+ * @tail: address of tail descriptor register
+ * @i: value to write to tail descriptor register
+ *
+ * When updating the tail register, the ME could be accessing Host CSR
+ * registers at the same time. Normally, this is handled in h/w by an
+ * arbiter but on some parts there is a bug that acknowledges Host accesses
+ * later than it should which could result in the descriptor register to
+ * have an incorrect value. Workaround this by checking the FWSM register
+ * which has bit 24 set while ME is accessing Host CSR registers, wait
+ * if it is set and try again a number of times.
+ **/
+static inline s32 e1000e_update_tail_wa(struct e1000_hw *hw, u8 __iomem * tail,
+ unsigned int i)
+{
+ unsigned int j = 0;
+
+ while ((j++ < E1000_ICH_FWSM_PCIM2PCI_COUNT) &&
+ (er32(FWSM) & E1000_ICH_FWSM_PCIM2PCI))
+ udelay(50);
+
+ writel(i, tail);
+
+ if ((j == E1000_ICH_FWSM_PCIM2PCI_COUNT) && (i != readl(tail)))
+ return E1000_ERR_SWFW_SYNC;
+
+ return 0;
+}
+
+static void e1000e_update_rdt_wa(struct e1000_adapter *adapter, unsigned int i)
+{
+ u8 __iomem *tail = (adapter->hw.hw_addr + adapter->rx_ring->tail);
+ struct e1000_hw *hw = &adapter->hw;
+
+ if (e1000e_update_tail_wa(hw, tail, i)) {
+ u32 rctl = er32(RCTL);
+ ew32(RCTL, rctl & ~E1000_RCTL_EN);
+ e_err("ME firmware caused invalid RDT - resetting\n");
+ schedule_work(&adapter->reset_task);
+ }
+}
+
+static void e1000e_update_tdt_wa(struct e1000_adapter *adapter, unsigned int i)
+{
+ u8 __iomem *tail = (adapter->hw.hw_addr + adapter->tx_ring->tail);
+ struct e1000_hw *hw = &adapter->hw;
+
+ if (e1000e_update_tail_wa(hw, tail, i)) {
+ u32 tctl = er32(TCTL);
+ ew32(TCTL, tctl & ~E1000_TCTL_EN);
+ e_err("ME firmware caused invalid TDT - resetting\n");
+ schedule_work(&adapter->reset_task);
+ }
+}
+
+/**
+ * e1000_alloc_rx_buffers - Replace used receive buffers
* @adapter: address of board private structure
**/
static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
@@ -528,7 +614,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
struct e1000_ring *rx_ring = adapter->rx_ring;
- struct e1000_rx_desc *rx_desc;
+ union e1000_rx_desc_extended *rx_desc;
struct e1000_buffer *buffer_info;
struct sk_buff *skb;
unsigned int i;
@@ -562,8 +648,8 @@ map_skb:
break;
}
- rx_desc = E1000_RX_DESC(*rx_ring, i);
- rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+ rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
+ rx_desc->read.buffer_addr = cpu_to_le64(buffer_info->dma);
if (unlikely(!(i & (E1000_RX_BUFFER_WRITE - 1)))) {
/*
@@ -573,7 +659,10 @@ map_skb:
* such as IA-64).
*/
wmb();
- writel(i, adapter->hw.hw_addr + rx_ring->tail);
+ if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
+ e1000e_update_rdt_wa(adapter, i);
+ else
+ writel(i, adapter->hw.hw_addr + rx_ring->tail);
}
i++;
if (i == rx_ring->count)
@@ -673,7 +762,11 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
* such as IA-64).
*/
wmb();
- writel(i << 1, adapter->hw.hw_addr + rx_ring->tail);
+ if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
+ e1000e_update_rdt_wa(adapter, i << 1);
+ else
+ writel(i << 1,
+ adapter->hw.hw_addr + rx_ring->tail);
}
i++;
@@ -697,7 +790,7 @@ static void e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
{
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
- struct e1000_rx_desc *rx_desc;
+ union e1000_rx_desc_extended *rx_desc;
struct e1000_ring *rx_ring = adapter->rx_ring;
struct e1000_buffer *buffer_info;
struct sk_buff *skb;
@@ -738,8 +831,8 @@ check_page:
PAGE_SIZE,
DMA_FROM_DEVICE);
- rx_desc = E1000_RX_DESC(*rx_ring, i);
- rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+ rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
+ rx_desc->read.buffer_addr = cpu_to_le64(buffer_info->dma);
if (unlikely(++i == rx_ring->count))
i = 0;
@@ -756,7 +849,10 @@ check_page:
* applicable for weak-ordered memory model archs,
* such as IA-64). */
wmb();
- writel(i, adapter->hw.hw_addr + rx_ring->tail);
+ if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
+ e1000e_update_rdt_wa(adapter, i);
+ else
+ writel(i, adapter->hw.hw_addr + rx_ring->tail);
}
}
@@ -774,28 +870,27 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
struct pci_dev *pdev = adapter->pdev;
struct e1000_hw *hw = &adapter->hw;
struct e1000_ring *rx_ring = adapter->rx_ring;
- struct e1000_rx_desc *rx_desc, *next_rxd;
+ union e1000_rx_desc_extended *rx_desc, *next_rxd;
struct e1000_buffer *buffer_info, *next_buffer;
- u32 length;
+ u32 length, staterr;
unsigned int i;
int cleaned_count = 0;
bool cleaned = 0;
unsigned int total_rx_bytes = 0, total_rx_packets = 0;
i = rx_ring->next_to_clean;
- rx_desc = E1000_RX_DESC(*rx_ring, i);
+ rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
+ staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
buffer_info = &rx_ring->buffer_info[i];
- while (rx_desc->status & E1000_RXD_STAT_DD) {
+ while (staterr & E1000_RXD_STAT_DD) {
struct sk_buff *skb;
- u8 status;
if (*work_done >= work_to_do)
break;
(*work_done)++;
rmb(); /* read descriptor and rx_buffer_info after status DD */
- status = rx_desc->status;
skb = buffer_info->skb;
buffer_info->skb = NULL;
@@ -804,7 +899,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
i++;
if (i == rx_ring->count)
i = 0;
- next_rxd = E1000_RX_DESC(*rx_ring, i);
+ next_rxd = E1000_RX_DESC_EXT(*rx_ring, i);
prefetch(next_rxd);
next_buffer = &rx_ring->buffer_info[i];
@@ -817,7 +912,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
DMA_FROM_DEVICE);
buffer_info->dma = 0;
- length = le16_to_cpu(rx_desc->length);
+ length = le16_to_cpu(rx_desc->wb.upper.length);
/*
* !EOP means multiple descriptors were used to store a single
@@ -826,7 +921,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
* next frame that _does_ have the EOP bit set, as it is by
* definition only a frame fragment
*/
- if (unlikely(!(status & E1000_RXD_STAT_EOP)))
+ if (unlikely(!(staterr & E1000_RXD_STAT_EOP)))
adapter->flags2 |= FLAG2_IS_DISCARDING;
if (adapter->flags2 & FLAG2_IS_DISCARDING) {
@@ -834,12 +929,12 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
e_dbg("Receive packet consumed multiple buffers\n");
/* recycle */
buffer_info->skb = skb;
- if (status & E1000_RXD_STAT_EOP)
+ if (staterr & E1000_RXD_STAT_EOP)
adapter->flags2 &= ~FLAG2_IS_DISCARDING;
goto next_desc;
}
- if (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) {
+ if (staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) {
/* recycle */
buffer_info->skb = skb;
goto next_desc;
@@ -877,15 +972,15 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
skb_put(skb, length);
/* Receive Checksum Offload */
- e1000_rx_checksum(adapter,
- (u32)(status) |
- ((u32)(rx_desc->errors) << 24),
- le16_to_cpu(rx_desc->csum), skb);
+ e1000_rx_checksum(adapter, staterr,
+ le16_to_cpu(rx_desc->wb.lower.hi_dword.
+ csum_ip.csum), skb);
- e1000_receive_skb(adapter, netdev, skb,status,rx_desc->special);
+ e1000_receive_skb(adapter, netdev, skb, staterr,
+ rx_desc->wb.upper.vlan);
next_desc:
- rx_desc->status = 0;
+ rx_desc->wb.upper.status_error &= cpu_to_le32(~0xFF);
/* return some buffers to hardware, one at a time is too slow */
if (cleaned_count >= E1000_RX_BUFFER_WRITE) {
@@ -897,6 +992,8 @@ next_desc:
/* use prefetched values */
rx_desc = next_rxd;
buffer_info = next_buffer;
+
+ staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
}
rx_ring->next_to_clean = i;
@@ -1203,7 +1300,7 @@ static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
ps_page->page = NULL;
skb->len += length;
skb->data_len += length;
- skb->truesize += length;
+ skb->truesize += PAGE_SIZE;
}
/* strip the ethernet crc, problem is we're using pages now so
@@ -1263,7 +1360,7 @@ static void e1000_consume_page(struct e1000_buffer *bi, struct sk_buff *skb,
bi->page = NULL;
skb->len += length;
skb->data_len += length;
- skb->truesize += length;
+ skb->truesize += PAGE_SIZE;
}
/**
@@ -1280,35 +1377,34 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
struct e1000_ring *rx_ring = adapter->rx_ring;
- struct e1000_rx_desc *rx_desc, *next_rxd;
+ union e1000_rx_desc_extended *rx_desc, *next_rxd;
struct e1000_buffer *buffer_info, *next_buffer;
- u32 length;
+ u32 length, staterr;
unsigned int i;
int cleaned_count = 0;
bool cleaned = false;
unsigned int total_rx_bytes=0, total_rx_packets=0;
i = rx_ring->next_to_clean;
- rx_desc = E1000_RX_DESC(*rx_ring, i);
+ rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
+ staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
buffer_info = &rx_ring->buffer_info[i];
- while (rx_desc->status & E1000_RXD_STAT_DD) {
+ while (staterr & E1000_RXD_STAT_DD) {
struct sk_buff *skb;
- u8 status;
if (*work_done >= work_to_do)
break;
(*work_done)++;
rmb(); /* read descriptor and rx_buffer_info after status DD */
- status = rx_desc->status;
skb = buffer_info->skb;
buffer_info->skb = NULL;
++i;
if (i == rx_ring->count)
i = 0;
- next_rxd = E1000_RX_DESC(*rx_ring, i);
+ next_rxd = E1000_RX_DESC_EXT(*rx_ring, i);
prefetch(next_rxd);
next_buffer = &rx_ring->buffer_info[i];
@@ -1319,23 +1415,22 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
DMA_FROM_DEVICE);
buffer_info->dma = 0;
- length = le16_to_cpu(rx_desc->length);
+ length = le16_to_cpu(rx_desc->wb.upper.length);
/* errors is only valid for DD + EOP descriptors */
- if (unlikely((status & E1000_RXD_STAT_EOP) &&
- (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK))) {
- /* recycle both page and skb */
- buffer_info->skb = skb;
- /* an error means any chain goes out the window
- * too */
- if (rx_ring->rx_skb_top)
- dev_kfree_skb_irq(rx_ring->rx_skb_top);
- rx_ring->rx_skb_top = NULL;
- goto next_desc;
+ if (unlikely((staterr & E1000_RXD_STAT_EOP) &&
+ (staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK))) {
+ /* recycle both page and skb */
+ buffer_info->skb = skb;
+ /* an error means any chain goes out the window too */
+ if (rx_ring->rx_skb_top)
+ dev_kfree_skb_irq(rx_ring->rx_skb_top);
+ rx_ring->rx_skb_top = NULL;
+ goto next_desc;
}
#define rxtop (rx_ring->rx_skb_top)
- if (!(status & E1000_RXD_STAT_EOP)) {
+ if (!(staterr & E1000_RXD_STAT_EOP)) {
/* this descriptor is only the beginning (or middle) */
if (!rxtop) {
/* this is the beginning of a chain */
@@ -1390,10 +1485,9 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
}
/* Receive Checksum Offload XXX recompute due to CRC strip? */
- e1000_rx_checksum(adapter,
- (u32)(status) |
- ((u32)(rx_desc->errors) << 24),
- le16_to_cpu(rx_desc->csum), skb);
+ e1000_rx_checksum(adapter, staterr,
+ le16_to_cpu(rx_desc->wb.lower.hi_dword.
+ csum_ip.csum), skb);
/* probably a little skewed due to removing CRC */
total_rx_bytes += skb->len;
@@ -1406,11 +1500,11 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
goto next_desc;
}
- e1000_receive_skb(adapter, netdev, skb, status,
- rx_desc->special);
+ e1000_receive_skb(adapter, netdev, skb, staterr,
+ rx_desc->wb.upper.vlan);
next_desc:
- rx_desc->status = 0;
+ rx_desc->wb.upper.status_error &= cpu_to_le32(~0xFF);
/* return some buffers to hardware, one at a time is too slow */
if (unlikely(cleaned_count >= E1000_RX_BUFFER_WRITE)) {
@@ -1422,6 +1516,8 @@ next_desc:
/* use prefetched values */
rx_desc = next_rxd;
buffer_info = next_buffer;
+
+ staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
}
rx_ring->next_to_clean = i;
@@ -2820,6 +2916,10 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
break;
}
+ /* Enable Extended Status in all Receive Descriptors */
+ rfctl = er32(RFCTL);
+ rfctl |= E1000_RFCTL_EXTEN;
+
/*
* 82571 and greater support packet-split where the protocol
* header is placed in skb->data and the packet data is
@@ -2845,9 +2945,6 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
if (adapter->rx_ps_pages) {
u32 psrctl = 0;
- /* Configure extra packet-split registers */
- rfctl = er32(RFCTL);
- rfctl |= E1000_RFCTL_EXTEN;
/*
* disable packet split support for IPv6 extension headers,
* because some malformed IPv6 headers can hang the Rx
@@ -2855,8 +2952,6 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
rfctl |= (E1000_RFCTL_IPV6_EX_DIS |
E1000_RFCTL_NEW_IPV6_EXT_DIS);
- ew32(RFCTL, rfctl);
-
/* Enable Packet split descriptors */
rctl |= E1000_RCTL_DTYP_PS;
@@ -2879,6 +2974,7 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
ew32(PSRCTL, psrctl);
}
+ ew32(RFCTL, rfctl);
ew32(RCTL, rctl);
/* just started the receive unit, no need to restart */
adapter->flags &= ~FLAG_RX_RESTART_NOW;
@@ -2904,11 +3000,11 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
adapter->clean_rx = e1000_clean_rx_irq_ps;
adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps;
} else if (adapter->netdev->mtu > ETH_FRAME_LEN + ETH_FCS_LEN) {
- rdlen = rx_ring->count * sizeof(struct e1000_rx_desc);
+ rdlen = rx_ring->count * sizeof(union e1000_rx_desc_extended);
adapter->clean_rx = e1000_clean_jumbo_rx_irq;
adapter->alloc_rx_buf = e1000_alloc_jumbo_rx_buffers;
} else {
- rdlen = rx_ring->count * sizeof(struct e1000_rx_desc);
+ rdlen = rx_ring->count * sizeof(union e1000_rx_desc_extended);
adapter->clean_rx = e1000_clean_rx_irq;
adapter->alloc_rx_buf = e1000_alloc_rx_buffers;
}
@@ -2973,7 +3069,7 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
/* Enable Receive Checksum Offload for TCP and UDP */
rxcsum = er32(RXCSUM);
- if (adapter->flags & FLAG_RX_CSUM_ENABLED) {
+ if (adapter->netdev->features & NETIF_F_RXCSUM) {
rxcsum |= E1000_RXCSUM_TUOFL;
/*
@@ -4577,11 +4673,11 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
}
for (f = 0; f < nr_frags; f++) {
- struct skb_frag_struct *frag;
+ const struct skb_frag_struct *frag;
frag = &skb_shinfo(skb)->frags[f];
- len = frag->size;
- offset = frag->page_offset;
+ len = skb_frag_size(frag);
+ offset = 0;
while (len) {
i++;
@@ -4594,9 +4690,8 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
buffer_info->length = size;
buffer_info->time_stamp = jiffies;
buffer_info->next_to_watch = i;
- buffer_info->dma = dma_map_page(&pdev->dev, frag->page,
- offset, size,
- DMA_TO_DEVICE);
+ buffer_info->dma = skb_frag_dma_map(&pdev->dev, frag,
+ offset, size, DMA_TO_DEVICE);
buffer_info->mapped_as_page = true;
if (dma_mapping_error(&pdev->dev, buffer_info->dma))
goto dma_error;
@@ -4689,7 +4784,12 @@ static void e1000_tx_queue(struct e1000_adapter *adapter,
wmb();
tx_ring->next_to_use = i;
- writel(i, adapter->hw.hw_addr + tx_ring->tail);
+
+ if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
+ e1000e_update_tdt_wa(adapter, i);
+ else
+ writel(i, adapter->hw.hw_addr + tx_ring->tail);
+
/*
* we need this if more than one processor can write to our tail
* at a time, it synchronizes IO on IA64/Altix systems
@@ -4843,7 +4943,7 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
nr_frags = skb_shinfo(skb)->nr_frags;
for (f = 0; f < nr_frags; f++)
- count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size,
+ count += TXD_USE_COUNT(skb_frag_size(&skb_shinfo(skb)->frags[f]),
max_txd_pwr);
if (adapter->hw.mac.tx_pkt_filtering)
@@ -5759,12 +5859,32 @@ static void e1000_eeprom_checks(struct e1000_adapter *adapter)
}
}
+static int e1000_set_features(struct net_device *netdev, u32 features)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ u32 changed = features ^ netdev->features;
+
+ if (changed & (NETIF_F_TSO | NETIF_F_TSO6))
+ adapter->flags |= FLAG_TSO_FORCE;
+
+ if (!(changed & (NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX |
+ NETIF_F_RXCSUM)))
+ return 0;
+
+ if (netif_running(netdev))
+ e1000e_reinit_locked(adapter);
+ else
+ e1000e_reset(adapter);
+
+ return 0;
+}
+
static const struct net_device_ops e1000e_netdev_ops = {
.ndo_open = e1000_open,
.ndo_stop = e1000_close,
.ndo_start_xmit = e1000_xmit_frame,
.ndo_get_stats64 = e1000e_get_stats64,
- .ndo_set_multicast_list = e1000_set_multi,
+ .ndo_set_rx_mode = e1000_set_multi,
.ndo_set_mac_address = e1000_set_mac,
.ndo_change_mtu = e1000_change_mtu,
.ndo_do_ioctl = e1000_ioctl,
@@ -5776,6 +5896,7 @@ static const struct net_device_ops e1000e_netdev_ops = {
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = e1000_netpoll,
#endif
+ .ndo_set_features = e1000_set_features,
};
/**
@@ -5935,21 +6056,25 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
if (e1000_check_reset_block(&adapter->hw))
e_info("PHY reset is blocked due to SOL/IDER session.\n");
- netdev->features = NETIF_F_SG |
- NETIF_F_HW_CSUM |
- NETIF_F_HW_VLAN_TX |
- NETIF_F_HW_VLAN_RX;
+ /* Set initial default active device features */
+ netdev->features = (NETIF_F_SG |
+ NETIF_F_HW_VLAN_RX |
+ NETIF_F_HW_VLAN_TX |
+ NETIF_F_TSO |
+ NETIF_F_TSO6 |
+ NETIF_F_RXCSUM |
+ NETIF_F_HW_CSUM);
+
+ /* Set user-changeable features (subset of all device features) */
+ netdev->hw_features = netdev->features;
if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER)
netdev->features |= NETIF_F_HW_VLAN_FILTER;
- netdev->features |= NETIF_F_TSO;
- netdev->features |= NETIF_F_TSO6;
-
- netdev->vlan_features |= NETIF_F_TSO;
- netdev->vlan_features |= NETIF_F_TSO6;
- netdev->vlan_features |= NETIF_F_HW_CSUM;
- netdev->vlan_features |= NETIF_F_SG;
+ netdev->vlan_features |= (NETIF_F_SG |
+ NETIF_F_TSO |
+ NETIF_F_TSO6 |
+ NETIF_F_HW_CSUM);
if (pci_using_dac) {
netdev->features |= NETIF_F_HIGHDMA;
diff --git a/drivers/net/e1000e/param.c b/drivers/net/ethernet/intel/e1000e/param.c
index 4dd9b63273f6..4dd9b63273f6 100644
--- a/drivers/net/e1000e/param.c
+++ b/drivers/net/ethernet/intel/e1000e/param.c
diff --git a/drivers/net/e1000e/phy.c b/drivers/net/ethernet/intel/e1000e/phy.c
index 8666476cb9be..8666476cb9be 100644
--- a/drivers/net/e1000e/phy.c
+++ b/drivers/net/ethernet/intel/e1000e/phy.c
diff --git a/drivers/net/igb/Makefile b/drivers/net/ethernet/intel/igb/Makefile
index c6e4621b6262..c6e4621b6262 100644
--- a/drivers/net/igb/Makefile
+++ b/drivers/net/ethernet/intel/igb/Makefile
diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c
index c0857bdfb03a..7881fb95a25b 100644
--- a/drivers/net/igb/e1000_82575.c
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c
@@ -66,10 +66,6 @@ static s32 igb_set_pcie_completion_timeout(struct e1000_hw *hw);
static s32 igb_reset_mdicnfg_82580(struct e1000_hw *hw);
static s32 igb_validate_nvm_checksum_82580(struct e1000_hw *hw);
static s32 igb_update_nvm_checksum_82580(struct e1000_hw *hw);
-static s32 igb_update_nvm_checksum_with_offset(struct e1000_hw *hw,
- u16 offset);
-static s32 igb_validate_nvm_checksum_with_offset(struct e1000_hw *hw,
- u16 offset);
static s32 igb_validate_nvm_checksum_i350(struct e1000_hw *hw);
static s32 igb_update_nvm_checksum_i350(struct e1000_hw *hw);
static const u16 e1000_82580_rxpbs_table[] =
@@ -1055,7 +1051,10 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw)
/* Disabling VLAN filtering */
hw_dbg("Initializing the IEEE VLAN\n");
- igb_clear_vfta(hw);
+ if (hw->mac.type == e1000_i350)
+ igb_clear_vfta_i350(hw);
+ else
+ igb_clear_vfta(hw);
/* Setup the receive address */
igb_init_rx_addrs(hw, rar_count);
@@ -1584,14 +1583,31 @@ void igb_vmdq_set_anti_spoofing_pf(struct e1000_hw *hw, bool enable, int pf)
**/
void igb_vmdq_set_loopback_pf(struct e1000_hw *hw, bool enable)
{
- u32 dtxswc = rd32(E1000_DTXSWC);
+ u32 dtxswc;
+
+ switch (hw->mac.type) {
+ case e1000_82576:
+ dtxswc = rd32(E1000_DTXSWC);
+ if (enable)
+ dtxswc |= E1000_DTXSWC_VMDQ_LOOPBACK_EN;
+ else
+ dtxswc &= ~E1000_DTXSWC_VMDQ_LOOPBACK_EN;
+ wr32(E1000_DTXSWC, dtxswc);
+ break;
+ case e1000_i350:
+ dtxswc = rd32(E1000_TXSWC);
+ if (enable)
+ dtxswc |= E1000_DTXSWC_VMDQ_LOOPBACK_EN;
+ else
+ dtxswc &= ~E1000_DTXSWC_VMDQ_LOOPBACK_EN;
+ wr32(E1000_TXSWC, dtxswc);
+ break;
+ default:
+ /* Currently no other hardware supports loopback */
+ break;
+ }
- if (enable)
- dtxswc |= E1000_DTXSWC_VMDQ_LOOPBACK_EN;
- else
- dtxswc &= ~E1000_DTXSWC_VMDQ_LOOPBACK_EN;
- wr32(E1000_DTXSWC, dtxswc);
}
/**
@@ -1820,7 +1836,8 @@ u16 igb_rxpbs_adjust_82580(u32 data)
* Calculates the EEPROM checksum by reading/adding each word of the EEPROM
* and then verifies that the sum of the EEPROM is equal to 0xBABA.
**/
-s32 igb_validate_nvm_checksum_with_offset(struct e1000_hw *hw, u16 offset)
+static s32 igb_validate_nvm_checksum_with_offset(struct e1000_hw *hw,
+ u16 offset)
{
s32 ret_val = 0;
u16 checksum = 0;
@@ -1855,7 +1872,7 @@ out:
* up to the checksum. Then calculates the EEPROM checksum and writes the
* value to the EEPROM.
**/
-s32 igb_update_nvm_checksum_with_offset(struct e1000_hw *hw, u16 offset)
+static s32 igb_update_nvm_checksum_with_offset(struct e1000_hw *hw, u16 offset)
{
s32 ret_val;
u16 checksum = 0;
diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/ethernet/intel/igb/e1000_82575.h
index 786e110011a3..08a757eb6608 100644
--- a/drivers/net/igb/e1000_82575.h
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.h
@@ -130,7 +130,9 @@ union e1000_adv_tx_desc {
#define E1000_ADVTXD_MAC_TSTAMP 0x00080000 /* IEEE1588 Timestamp packet */
#define E1000_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Descriptor */
#define E1000_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */
+#define E1000_ADVTXD_DCMD_EOP 0x01000000 /* End of Packet */
#define E1000_ADVTXD_DCMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_ADVTXD_DCMD_RS 0x08000000 /* Report Status */
#define E1000_ADVTXD_DCMD_DEXT 0x20000000 /* Descriptor extension (1=Adv) */
#define E1000_ADVTXD_DCMD_VLE 0x40000000 /* VLAN pkt enable */
#define E1000_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */
diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h
index 7b8ddd830f19..f5fc5725ea94 100644
--- a/drivers/net/igb/e1000_defines.h
+++ b/drivers/net/ethernet/intel/igb/e1000_defines.h
@@ -85,6 +85,7 @@
#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */
#define E1000_RXD_STAT_TS 0x10000 /* Pkt was time stamped */
+#define E1000_RXDEXT_STATERR_LB 0x00040000
#define E1000_RXDEXT_STATERR_CE 0x01000000
#define E1000_RXDEXT_STATERR_SE 0x02000000
#define E1000_RXDEXT_STATERR_SEQ 0x04000000
@@ -409,6 +410,9 @@
#define E1000_ICS_DRSTA E1000_ICR_DRSTA /* Device Reset Aserted */
/* Extended Interrupt Cause Set */
+/* E1000_EITR_CNT_IGNR is only for 82576 and newer */
+#define E1000_EITR_CNT_IGNR 0x80000000 /* Don't reset counters on write */
+
/* Transmit Descriptor Control */
/* Enable the counting of descriptors still to be processed. */
diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/ethernet/intel/igb/e1000_hw.h
index 4519a1367170..4519a1367170 100644
--- a/drivers/net/igb/e1000_hw.h
+++ b/drivers/net/ethernet/intel/igb/e1000_hw.h
diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/ethernet/intel/igb/e1000_mac.c
index 2b5ef761d2ab..73aac082c44d 100644
--- a/drivers/net/igb/e1000_mac.c
+++ b/drivers/net/ethernet/intel/igb/e1000_mac.c
@@ -117,6 +117,50 @@ static void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
wrfl();
}
+/* Due to a hw errata, if the host tries to configure the VFTA register
+ * while performing queries from the BMC or DMA, then the VFTA in some
+ * cases won't be written.
+ */
+
+/**
+ * igb_clear_vfta_i350 - Clear VLAN filter table
+ * @hw: pointer to the HW structure
+ *
+ * Clears the register array which contains the VLAN filter table by
+ * setting all the values to 0.
+ **/
+void igb_clear_vfta_i350(struct e1000_hw *hw)
+{
+ u32 offset;
+ int i;
+
+ for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
+ for (i = 0; i < 10; i++)
+ array_wr32(E1000_VFTA, offset, 0);
+
+ wrfl();
+ }
+}
+
+/**
+ * igb_write_vfta_i350 - Write value to VLAN filter table
+ * @hw: pointer to the HW structure
+ * @offset: register offset in VLAN filter table
+ * @value: register value written to VLAN filter table
+ *
+ * Writes value at the given offset in the register array which stores
+ * the VLAN filter table.
+ **/
+void igb_write_vfta_i350(struct e1000_hw *hw, u32 offset, u32 value)
+{
+ int i;
+
+ for (i = 0; i < 10; i++)
+ array_wr32(E1000_VFTA, offset, value);
+
+ wrfl();
+}
+
/**
* igb_init_rx_addrs - Initialize receive address's
* @hw: pointer to the HW structure
@@ -155,9 +199,12 @@ s32 igb_vfta_set(struct e1000_hw *hw, u32 vid, bool add)
{
u32 index = (vid >> E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK;
u32 mask = 1 << (vid & E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
- u32 vfta = array_rd32(E1000_VFTA, index);
+ u32 vfta;
+ struct igb_adapter *adapter = hw->back;
s32 ret_val = 0;
+ vfta = adapter->shadow_vfta[index];
+
/* bit was set/cleared before we started */
if ((!!(vfta & mask)) == add) {
ret_val = -E1000_ERR_CONFIG;
@@ -167,8 +214,11 @@ s32 igb_vfta_set(struct e1000_hw *hw, u32 vid, bool add)
else
vfta &= ~mask;
}
-
- igb_write_vfta(hw, index, vfta);
+ if (hw->mac.type == e1000_i350)
+ igb_write_vfta_i350(hw, index, vfta);
+ else
+ igb_write_vfta(hw, index, vfta);
+ adapter->shadow_vfta[index] = vfta;
return ret_val;
}
@@ -191,6 +241,13 @@ s32 igb_check_alt_mac_addr(struct e1000_hw *hw)
u16 offset, nvm_alt_mac_addr_offset, nvm_data;
u8 alt_mac_addr[ETH_ALEN];
+ /*
+ * Alternate MAC address is handled by the option ROM for 82580
+ * and newer. SW support not required.
+ */
+ if (hw->mac.type >= e1000_82580)
+ goto out;
+
ret_val = hw->nvm.ops.read(hw, NVM_ALT_MAC_ADDR_PTR, 1,
&nvm_alt_mac_addr_offset);
if (ret_val) {
@@ -198,13 +255,18 @@ s32 igb_check_alt_mac_addr(struct e1000_hw *hw)
goto out;
}
- if (nvm_alt_mac_addr_offset == 0xFFFF) {
+ if ((nvm_alt_mac_addr_offset == 0xFFFF) ||
+ (nvm_alt_mac_addr_offset == 0x0000))
/* There is no Alternate MAC Address */
goto out;
- }
if (hw->bus.func == E1000_FUNC_1)
nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1;
+ if (hw->bus.func == E1000_FUNC_2)
+ nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN2;
+
+ if (hw->bus.func == E1000_FUNC_3)
+ nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN3;
for (i = 0; i < ETH_ALEN; i += 2) {
offset = nvm_alt_mac_addr_offset + (i >> 1);
ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
diff --git a/drivers/net/igb/e1000_mac.h b/drivers/net/ethernet/intel/igb/e1000_mac.h
index 4927f61fbbc8..e45996b4ea34 100644
--- a/drivers/net/igb/e1000_mac.h
+++ b/drivers/net/ethernet/intel/igb/e1000_mac.h
@@ -60,6 +60,7 @@ s32 igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg,
void igb_clear_hw_cntrs_base(struct e1000_hw *hw);
void igb_clear_vfta(struct e1000_hw *hw);
+void igb_clear_vfta_i350(struct e1000_hw *hw);
s32 igb_vfta_set(struct e1000_hw *hw, u32 vid, bool add);
void igb_config_collision_dist(struct e1000_hw *hw);
void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
diff --git a/drivers/net/igb/e1000_mbx.c b/drivers/net/ethernet/intel/igb/e1000_mbx.c
index 74f2f11ac290..469d95eaa154 100644
--- a/drivers/net/igb/e1000_mbx.c
+++ b/drivers/net/ethernet/intel/igb/e1000_mbx.c
@@ -34,7 +34,7 @@
* @size: Length of buffer
* @mbx_id: id of mailbox to read
*
- * returns SUCCESS if it successfuly read message from buffer
+ * returns SUCCESS if it successfully read message from buffer
**/
s32 igb_read_mbx(struct e1000_hw *hw, u32 *msg, u16 size, u16 mbx_id)
{
diff --git a/drivers/net/igb/e1000_mbx.h b/drivers/net/ethernet/intel/igb/e1000_mbx.h
index eddb0f83dcea..eddb0f83dcea 100644
--- a/drivers/net/igb/e1000_mbx.h
+++ b/drivers/net/ethernet/intel/igb/e1000_mbx.h
diff --git a/drivers/net/igb/e1000_nvm.c b/drivers/net/ethernet/intel/igb/e1000_nvm.c
index 40407124e722..40407124e722 100644
--- a/drivers/net/igb/e1000_nvm.c
+++ b/drivers/net/ethernet/intel/igb/e1000_nvm.c
diff --git a/drivers/net/igb/e1000_nvm.h b/drivers/net/ethernet/intel/igb/e1000_nvm.h
index a2a7ca9fa733..a2a7ca9fa733 100644
--- a/drivers/net/igb/e1000_nvm.h
+++ b/drivers/net/ethernet/intel/igb/e1000_nvm.h
diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/ethernet/intel/igb/e1000_phy.c
index e662554c62d6..7edf31efe756 100644
--- a/drivers/net/igb/e1000_phy.c
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.c
@@ -306,6 +306,12 @@ s32 igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data)
u32 i, i2ccmd = 0;
u16 phy_data_swapped;
+ /* Prevent overwritting SFP I2C EEPROM which is at A0 address.*/
+ if ((hw->phy.addr == 0) || (hw->phy.addr > 7)) {
+ hw_dbg("PHY I2C Address %d is out of range.\n",
+ hw->phy.addr);
+ return -E1000_ERR_CONFIG;
+ }
/* Swap the data bytes for the I2C interface */
phy_data_swapped = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00);
diff --git a/drivers/net/igb/e1000_phy.h b/drivers/net/ethernet/intel/igb/e1000_phy.h
index 8510797b9d81..8510797b9d81 100644
--- a/drivers/net/igb/e1000_phy.h
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.h
diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/ethernet/intel/igb/e1000_regs.h
index 0990f6d860c7..0a860bc1198e 100644
--- a/drivers/net/igb/e1000_regs.h
+++ b/drivers/net/ethernet/intel/igb/e1000_regs.h
@@ -318,6 +318,7 @@
#define E1000_RPLOLR 0x05AF0 /* Replication Offload - RW */
#define E1000_UTA 0x0A000 /* Unicast Table Array - RW */
#define E1000_IOVTCL 0x05BBC /* IOV Control Register */
+#define E1000_TXSWC 0x05ACC /* Tx Switch Control */
/* These act per VF so an array friendly macro is used */
#define E1000_P2VMAILBOX(_n) (0x00C00 + (4 * (_n)))
#define E1000_VMBMEM(_n) (0x00800 + (64 * (_n)))
diff --git a/drivers/net/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index 265e151b66c4..c69feebf2653 100644
--- a/drivers/net/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -42,11 +42,15 @@
struct igb_adapter;
-/* ((1000000000ns / (6000ints/s * 1024ns)) << 2 = 648 */
-#define IGB_START_ITR 648
+/* Interrupt defines */
+#define IGB_START_ITR 648 /* ~6000 ints/sec */
+#define IGB_4K_ITR 980
+#define IGB_20K_ITR 196
+#define IGB_70K_ITR 56
/* TX/RX descriptor defines */
#define IGB_DEFAULT_TXD 256
+#define IGB_DEFAULT_TX_WORK 128
#define IGB_MIN_TXD 80
#define IGB_MAX_TXD 4096
@@ -63,12 +67,13 @@ struct igb_adapter;
/* Transmit and receive queues */
#define IGB_MAX_RX_QUEUES (adapter->vfs_allocated_count ? 2 : \
(hw->mac.type > e1000_82575 ? 8 : 4))
-#define IGB_ABS_MAX_TX_QUEUES 8
-#define IGB_MAX_TX_QUEUES IGB_MAX_RX_QUEUES
+#define IGB_MAX_TX_QUEUES 16
#define IGB_MAX_VF_MC_ENTRIES 30
#define IGB_MAX_VF_FUNCTIONS 8
#define IGB_MAX_VFTA_ENTRIES 128
+#define IGB_82576_VF_DEV_ID 0x10CA
+#define IGB_I350_VF_DEV_ID 0x1520
struct vf_data_storage {
unsigned char vf_mac_addresses[ETH_ALEN];
@@ -80,6 +85,7 @@ struct vf_data_storage {
u16 pf_vlan; /* When set, guest VLAN config not allowed. */
u16 pf_qos;
u16 tx_rate;
+ struct pci_dev *vfdev;
};
#define IGB_VF_FLAG_CTS 0x00000001 /* VF is clear to send data */
@@ -100,23 +106,20 @@ struct vf_data_storage {
*/
#define IGB_RX_PTHRESH 8
#define IGB_RX_HTHRESH 8
-#define IGB_RX_WTHRESH 1
#define IGB_TX_PTHRESH 8
#define IGB_TX_HTHRESH 1
+#define IGB_RX_WTHRESH ((hw->mac.type == e1000_82576 && \
+ adapter->msix_entries) ? 1 : 4)
#define IGB_TX_WTHRESH ((hw->mac.type == e1000_82576 && \
- adapter->msix_entries) ? 1 : 16)
+ adapter->msix_entries) ? 1 : 16)
/* this is the size past which hardware will drop packets when setting LPE=0 */
#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
/* Supported Rx Buffer Sizes */
-#define IGB_RXBUFFER_64 64 /* Used for packet split */
-#define IGB_RXBUFFER_128 128 /* Used for packet split */
-#define IGB_RXBUFFER_1024 1024
-#define IGB_RXBUFFER_2048 2048
+#define IGB_RXBUFFER_512 512
#define IGB_RXBUFFER_16384 16384
-
-#define MAX_STD_JUMBO_FRAME_SIZE 9234
+#define IGB_RX_HDR_LEN IGB_RXBUFFER_512
/* How many Tx Descriptors do we need to call netif_wake_queue ? */
#define IGB_TX_QUEUE_WAKE 16
@@ -133,29 +136,34 @@ struct vf_data_storage {
#define IGB_MNG_VLAN_NONE -1
+#define IGB_TX_FLAGS_CSUM 0x00000001
+#define IGB_TX_FLAGS_VLAN 0x00000002
+#define IGB_TX_FLAGS_TSO 0x00000004
+#define IGB_TX_FLAGS_IPV4 0x00000008
+#define IGB_TX_FLAGS_TSTAMP 0x00000010
+#define IGB_TX_FLAGS_VLAN_MASK 0xffff0000
+#define IGB_TX_FLAGS_VLAN_SHIFT 16
+
/* wrapper around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer */
-struct igb_buffer {
+struct igb_tx_buffer {
+ union e1000_adv_tx_desc *next_to_watch;
+ unsigned long time_stamp;
struct sk_buff *skb;
+ unsigned int bytecount;
+ u16 gso_segs;
+ __be16 protocol;
dma_addr_t dma;
- union {
- /* TX */
- struct {
- unsigned long time_stamp;
- u16 length;
- u16 next_to_watch;
- unsigned int bytecount;
- u16 gso_segs;
- u8 tx_flags;
- u8 mapped_as_page;
- };
- /* RX */
- struct {
- struct page *page;
- dma_addr_t page_dma;
- u16 page_offset;
- };
- };
+ u32 length;
+ u32 tx_flags;
+};
+
+struct igb_rx_buffer {
+ struct sk_buff *skb;
+ dma_addr_t dma;
+ struct page *page;
+ dma_addr_t page_dma;
+ u32 page_offset;
};
struct igb_tx_queue_stats {
@@ -173,14 +181,24 @@ struct igb_rx_queue_stats {
u64 alloc_failed;
};
+struct igb_ring_container {
+ struct igb_ring *ring; /* pointer to linked list of rings */
+ unsigned int total_bytes; /* total bytes processed this int */
+ unsigned int total_packets; /* total packets processed this int */
+ u16 work_limit; /* total work allowed per interrupt */
+ u8 count; /* total number of rings in vector */
+ u8 itr; /* current ITR setting for ring */
+};
+
struct igb_q_vector {
- struct igb_adapter *adapter; /* backlink */
- struct igb_ring *rx_ring;
- struct igb_ring *tx_ring;
- struct napi_struct napi;
+ struct igb_adapter *adapter; /* backlink */
+ int cpu; /* CPU for DCA */
+ u32 eims_value; /* EIMS mask value */
- u32 eims_value;
- u16 cpu;
+ struct igb_ring_container rx, tx;
+
+ struct napi_struct napi;
+ int numa_node;
u16 itr_val;
u8 set_itr;
@@ -190,25 +208,25 @@ struct igb_q_vector {
};
struct igb_ring {
- struct igb_q_vector *q_vector; /* backlink to q_vector */
- struct net_device *netdev; /* back pointer to net_device */
- struct device *dev; /* device pointer for dma mapping */
- dma_addr_t dma; /* phys address of the ring */
- void *desc; /* descriptor ring memory */
- unsigned int size; /* length of desc. ring in bytes */
- u16 count; /* number of desc. in the ring */
- u16 next_to_use;
- u16 next_to_clean;
- u8 queue_index;
- u8 reg_idx;
- void __iomem *head;
- void __iomem *tail;
- struct igb_buffer *buffer_info; /* array of buffer info structs */
+ struct igb_q_vector *q_vector; /* backlink to q_vector */
+ struct net_device *netdev; /* back pointer to net_device */
+ struct device *dev; /* device pointer for dma mapping */
+ union { /* array of buffer info structs */
+ struct igb_tx_buffer *tx_buffer_info;
+ struct igb_rx_buffer *rx_buffer_info;
+ };
+ void *desc; /* descriptor ring memory */
+ unsigned long flags; /* ring specific flags */
+ void __iomem *tail; /* pointer to ring tail register */
- unsigned int total_bytes;
- unsigned int total_packets;
+ u16 count; /* number of desc. in the ring */
+ u8 queue_index; /* logical index of the ring*/
+ u8 reg_idx; /* physical index of the ring */
+ u32 size; /* length of desc. ring in bytes */
- u32 flags;
+ /* everything past this point are written often */
+ u16 next_to_clean ____cacheline_aligned_in_smp;
+ u16 next_to_use;
union {
/* TX */
@@ -216,30 +234,40 @@ struct igb_ring {
struct igb_tx_queue_stats tx_stats;
struct u64_stats_sync tx_syncp;
struct u64_stats_sync tx_syncp2;
- bool detect_tx_hung;
};
/* RX */
struct {
struct igb_rx_queue_stats rx_stats;
struct u64_stats_sync rx_syncp;
- u32 rx_buffer_len;
};
};
+ /* Items past this point are only used during ring alloc / free */
+ dma_addr_t dma; /* phys address of the ring */
+ int numa_node; /* node to alloc ring memory on */
};
-#define IGB_RING_FLAG_RX_CSUM 0x00000001 /* RX CSUM enabled */
-#define IGB_RING_FLAG_RX_SCTP_CSUM 0x00000002 /* SCTP CSUM offload enabled */
+enum e1000_ring_flags_t {
+ IGB_RING_FLAG_RX_SCTP_CSUM,
+ IGB_RING_FLAG_RX_LB_VLAN_BSWAP,
+ IGB_RING_FLAG_TX_CTX_IDX,
+ IGB_RING_FLAG_TX_DETECT_HANG
+};
-#define IGB_RING_FLAG_TX_CTX_IDX 0x00000001 /* HW requires context index */
+#define IGB_TXD_DCMD (E1000_ADVTXD_DCMD_EOP | E1000_ADVTXD_DCMD_RS)
-#define IGB_ADVTXD_DCMD (E1000_TXD_CMD_EOP | E1000_TXD_CMD_RS)
+#define IGB_RX_DESC(R, i) \
+ (&(((union e1000_adv_rx_desc *)((R)->desc))[i]))
+#define IGB_TX_DESC(R, i) \
+ (&(((union e1000_adv_tx_desc *)((R)->desc))[i]))
+#define IGB_TX_CTXTDESC(R, i) \
+ (&(((struct e1000_adv_tx_context_desc *)((R)->desc))[i]))
-#define E1000_RX_DESC_ADV(R, i) \
- (&(((union e1000_adv_rx_desc *)((R).desc))[i]))
-#define E1000_TX_DESC_ADV(R, i) \
- (&(((union e1000_adv_tx_desc *)((R).desc))[i]))
-#define E1000_TX_CTXTDESC_ADV(R, i) \
- (&(((struct e1000_adv_tx_context_desc *)((R).desc))[i]))
+/* igb_test_staterr - tests bits within Rx descriptor status and error fields */
+static inline __le32 igb_test_staterr(union e1000_adv_rx_desc *rx_desc,
+ const u32 stat_err_bits)
+{
+ return rx_desc->wb.upper.status_error & cpu_to_le32(stat_err_bits);
+}
/* igb_desc_unused - calculate if we have unused descriptors */
static inline int igb_desc_unused(struct igb_ring *ring)
@@ -252,15 +280,15 @@ static inline int igb_desc_unused(struct igb_ring *ring)
/* board specific private data structure */
struct igb_adapter {
- struct timer_list watchdog_timer;
- struct timer_list phy_info_timer;
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
- u16 mng_vlan_id;
- u32 bd_number;
- u32 wol;
- u32 en_mng_pt;
- u16 link_speed;
- u16 link_duplex;
+
+ struct net_device *netdev;
+
+ unsigned long state;
+ unsigned int flags;
+
+ unsigned int num_q_vectors;
+ struct msix_entry *msix_entries;
/* Interrupt Throttle Rate */
u32 rx_itr_setting;
@@ -268,27 +296,37 @@ struct igb_adapter {
u16 tx_itr;
u16 rx_itr;
- struct work_struct reset_task;
- struct work_struct watchdog_task;
- bool fc_autoneg;
- u8 tx_timeout_factor;
- struct timer_list blink_timer;
- unsigned long led_status;
-
/* TX */
- struct igb_ring *tx_ring[16];
+ u16 tx_work_limit;
u32 tx_timeout_count;
+ int num_tx_queues;
+ struct igb_ring *tx_ring[16];
/* RX */
- struct igb_ring *rx_ring[16];
- int num_tx_queues;
int num_rx_queues;
+ struct igb_ring *rx_ring[16];
u32 max_frame_size;
u32 min_frame_size;
+ struct timer_list watchdog_timer;
+ struct timer_list phy_info_timer;
+
+ u16 mng_vlan_id;
+ u32 bd_number;
+ u32 wol;
+ u32 en_mng_pt;
+ u16 link_speed;
+ u16 link_duplex;
+
+ struct work_struct reset_task;
+ struct work_struct watchdog_task;
+ bool fc_autoneg;
+ u8 tx_timeout_factor;
+ struct timer_list blink_timer;
+ unsigned long led_status;
+
/* OS defined structs */
- struct net_device *netdev;
struct pci_dev *pdev;
struct cyclecounter cycles;
struct timecounter clock;
@@ -310,18 +348,13 @@ struct igb_adapter {
int msg_enable;
- unsigned int num_q_vectors;
struct igb_q_vector *q_vector[MAX_Q_VECTORS];
- struct msix_entry *msix_entries;
u32 eims_enable_mask;
u32 eims_other;
/* to not mess up cache alignment, always add to the bottom */
- unsigned long state;
- unsigned int flags;
u32 eeprom_wol;
- struct igb_ring *multi_tx_table[IGB_ABS_MAX_TX_QUEUES];
u16 tx_ring_count;
u16 rx_ring_count;
unsigned int vfs_allocated_count;
@@ -329,6 +362,8 @@ struct igb_adapter {
int vf_rate_link_speed;
u32 rss_queues;
u32 wvbr;
+ int node;
+ u32 *shadow_vfta;
};
#define IGB_FLAG_HAS_MSI (1 << 0)
@@ -371,10 +406,10 @@ extern void igb_configure_tx_ring(struct igb_adapter *, struct igb_ring *);
extern void igb_configure_rx_ring(struct igb_adapter *, struct igb_ring *);
extern void igb_setup_tctl(struct igb_adapter *);
extern void igb_setup_rctl(struct igb_adapter *);
-extern netdev_tx_t igb_xmit_frame_ring_adv(struct sk_buff *, struct igb_ring *);
+extern netdev_tx_t igb_xmit_frame_ring(struct sk_buff *, struct igb_ring *);
extern void igb_unmap_and_free_tx_resource(struct igb_ring *,
- struct igb_buffer *);
-extern void igb_alloc_rx_buffers_adv(struct igb_ring *, int);
+ struct igb_tx_buffer *);
+extern void igb_alloc_rx_buffers(struct igb_ring *, u16);
extern void igb_update_stats(struct igb_adapter *, struct rtnl_link_stats64 *);
extern bool igb_has_link(struct igb_adapter *adapter);
extern void igb_set_ethtool_ops(struct net_device *);
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index 414b0225be89..43873eba2f63 100644
--- a/drivers/net/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -705,12 +705,8 @@ static void igb_get_ringparam(struct net_device *netdev,
ring->rx_max_pending = IGB_MAX_RXD;
ring->tx_max_pending = IGB_MAX_TXD;
- ring->rx_mini_max_pending = 0;
- ring->rx_jumbo_max_pending = 0;
ring->rx_pending = adapter->rx_ring_count;
ring->tx_pending = adapter->tx_ring_count;
- ring->rx_mini_pending = 0;
- ring->rx_jumbo_pending = 0;
}
static int igb_set_ringparam(struct net_device *netdev,
@@ -1368,7 +1364,6 @@ static int igb_setup_desc_rings(struct igb_adapter *adapter)
rx_ring->count = IGB_DEFAULT_RXD;
rx_ring->dev = &adapter->pdev->dev;
rx_ring->netdev = adapter->netdev;
- rx_ring->rx_buffer_len = IGB_RXBUFFER_2048;
rx_ring->reg_idx = adapter->vfs_allocated_count;
if (igb_setup_rx_resources(rx_ring)) {
@@ -1383,7 +1378,7 @@ static int igb_setup_desc_rings(struct igb_adapter *adapter)
igb_setup_rctl(adapter);
igb_configure_rx_ring(adapter, rx_ring);
- igb_alloc_rx_buffers_adv(rx_ring, igb_desc_unused(rx_ring));
+ igb_alloc_rx_buffers(rx_ring, igb_desc_unused(rx_ring));
return 0;
@@ -1580,34 +1575,33 @@ static int igb_clean_test_rings(struct igb_ring *rx_ring,
unsigned int size)
{
union e1000_adv_rx_desc *rx_desc;
- struct igb_buffer *buffer_info;
- int rx_ntc, tx_ntc, count = 0;
- u32 staterr;
+ struct igb_rx_buffer *rx_buffer_info;
+ struct igb_tx_buffer *tx_buffer_info;
+ u16 rx_ntc, tx_ntc, count = 0;
/* initialize next to clean and descriptor values */
rx_ntc = rx_ring->next_to_clean;
tx_ntc = tx_ring->next_to_clean;
- rx_desc = E1000_RX_DESC_ADV(*rx_ring, rx_ntc);
- staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+ rx_desc = IGB_RX_DESC(rx_ring, rx_ntc);
- while (staterr & E1000_RXD_STAT_DD) {
+ while (igb_test_staterr(rx_desc, E1000_RXD_STAT_DD)) {
/* check rx buffer */
- buffer_info = &rx_ring->buffer_info[rx_ntc];
+ rx_buffer_info = &rx_ring->rx_buffer_info[rx_ntc];
/* unmap rx buffer, will be remapped by alloc_rx_buffers */
dma_unmap_single(rx_ring->dev,
- buffer_info->dma,
- rx_ring->rx_buffer_len,
+ rx_buffer_info->dma,
+ IGB_RX_HDR_LEN,
DMA_FROM_DEVICE);
- buffer_info->dma = 0;
+ rx_buffer_info->dma = 0;
/* verify contents of skb */
- if (!igb_check_lbtest_frame(buffer_info->skb, size))
+ if (!igb_check_lbtest_frame(rx_buffer_info->skb, size))
count++;
/* unmap buffer on tx side */
- buffer_info = &tx_ring->buffer_info[tx_ntc];
- igb_unmap_and_free_tx_resource(tx_ring, buffer_info);
+ tx_buffer_info = &tx_ring->tx_buffer_info[tx_ntc];
+ igb_unmap_and_free_tx_resource(tx_ring, tx_buffer_info);
/* increment rx/tx next to clean counters */
rx_ntc++;
@@ -1618,12 +1612,11 @@ static int igb_clean_test_rings(struct igb_ring *rx_ring,
tx_ntc = 0;
/* fetch next descriptor */
- rx_desc = E1000_RX_DESC_ADV(*rx_ring, rx_ntc);
- staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+ rx_desc = IGB_RX_DESC(rx_ring, rx_ntc);
}
/* re-map buffers to ring, store next to clean values */
- igb_alloc_rx_buffers_adv(rx_ring, count);
+ igb_alloc_rx_buffers(rx_ring, count);
rx_ring->next_to_clean = rx_ntc;
tx_ring->next_to_clean = tx_ntc;
@@ -1634,8 +1627,9 @@ static int igb_run_loopback_test(struct igb_adapter *adapter)
{
struct igb_ring *tx_ring = &adapter->test_tx_ring;
struct igb_ring *rx_ring = &adapter->test_rx_ring;
- int i, j, lc, good_cnt, ret_val = 0;
- unsigned int size = 1024;
+ u16 i, j, lc, good_cnt;
+ int ret_val = 0;
+ unsigned int size = IGB_RX_HDR_LEN;
netdev_tx_t tx_ret_val;
struct sk_buff *skb;
@@ -1666,7 +1660,7 @@ static int igb_run_loopback_test(struct igb_adapter *adapter)
/* place 64 packets on the transmit queue*/
for (i = 0; i < 64; i++) {
skb_get(skb);
- tx_ret_val = igb_xmit_frame_ring_adv(skb, tx_ring);
+ tx_ret_val = igb_xmit_frame_ring(skb, tx_ring);
if (tx_ret_val == NETDEV_TX_OK)
good_cnt++;
}
@@ -2012,7 +2006,8 @@ static int igb_set_coalesce(struct net_device *netdev,
for (i = 0; i < adapter->num_q_vectors; i++) {
struct igb_q_vector *q_vector = adapter->q_vector[i];
- if (q_vector->rx_ring)
+ q_vector->tx.work_limit = adapter->tx_work_limit;
+ if (q_vector->rx.ring)
q_vector->itr_val = adapter->rx_itr_setting;
else
q_vector->itr_val = adapter->tx_itr_setting;
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 40d4c405fd7e..ced544499f1b 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -39,11 +39,15 @@
#include <linux/net_tstamp.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
+#include <linux/if.h>
#include <linux/if_vlan.h>
#include <linux/pci.h>
#include <linux/pci-aspm.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/sctp.h>
#include <linux/if_ether.h>
#include <linux/aer.h>
#include <linux/prefetch.h>
@@ -53,8 +57,8 @@
#include "igb.h"
#define MAJ 3
-#define MIN 0
-#define BUILD 6
+#define MIN 2
+#define BUILD 10
#define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \
__stringify(BUILD) "-k"
char igb_driver_name[] = "igb";
@@ -121,7 +125,7 @@ static void igb_set_rx_mode(struct net_device *);
static void igb_update_phy_info(unsigned long);
static void igb_watchdog(unsigned long);
static void igb_watchdog_task(struct work_struct *);
-static netdev_tx_t igb_xmit_frame_adv(struct sk_buff *skb, struct net_device *);
+static netdev_tx_t igb_xmit_frame(struct sk_buff *skb, struct net_device *);
static struct rtnl_link_stats64 *igb_get_stats64(struct net_device *dev,
struct rtnl_link_stats64 *stats);
static int igb_change_mtu(struct net_device *, int);
@@ -135,9 +139,9 @@ static irqreturn_t igb_msix_ring(int irq, void *);
static void igb_update_dca(struct igb_q_vector *);
static void igb_setup_dca(struct igb_adapter *);
#endif /* CONFIG_IGB_DCA */
-static bool igb_clean_tx_irq(struct igb_q_vector *);
static int igb_poll(struct napi_struct *, int);
-static bool igb_clean_rx_irq_adv(struct igb_q_vector *, int *, int);
+static bool igb_clean_tx_irq(struct igb_q_vector *);
+static bool igb_clean_rx_irq(struct igb_q_vector *, int);
static int igb_ioctl(struct net_device *, struct ifreq *, int cmd);
static void igb_tx_timeout(struct net_device *);
static void igb_reset_task(struct work_struct *);
@@ -159,6 +163,12 @@ static int igb_ndo_get_vf_config(struct net_device *netdev, int vf,
struct ifla_vf_info *ivi);
static void igb_check_vf_rate_limit(struct igb_adapter *);
+#ifdef CONFIG_PCI_IOV
+static int igb_vf_configure(struct igb_adapter *adapter, int vf);
+static int igb_find_enabled_vfs(struct igb_adapter *adapter);
+static int igb_check_vf_assignment(struct igb_adapter *adapter);
+#endif
+
#ifdef CONFIG_PM
static int igb_suspend(struct pci_dev *, pm_message_t);
static int igb_resume(struct pci_dev *);
@@ -194,6 +204,7 @@ static struct pci_error_handlers igb_err_handler = {
.resume = igb_io_resume,
};
+static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
static struct pci_driver igb_driver = {
.name = igb_driver_name,
@@ -334,15 +345,13 @@ static void igb_dump(struct igb_adapter *adapter)
struct net_device *netdev = adapter->netdev;
struct e1000_hw *hw = &adapter->hw;
struct igb_reg_info *reginfo;
- int n = 0;
struct igb_ring *tx_ring;
union e1000_adv_tx_desc *tx_desc;
struct my_u0 { u64 a; u64 b; } *u0;
- struct igb_buffer *buffer_info;
struct igb_ring *rx_ring;
union e1000_adv_rx_desc *rx_desc;
u32 staterr;
- int i = 0;
+ u16 i, n;
if (!netif_msg_hw(adapter))
return;
@@ -375,9 +384,10 @@ static void igb_dump(struct igb_adapter *adapter)
printk(KERN_INFO "Queue [NTU] [NTC] [bi(ntc)->dma ]"
" leng ntw timestamp\n");
for (n = 0; n < adapter->num_tx_queues; n++) {
+ struct igb_tx_buffer *buffer_info;
tx_ring = adapter->tx_ring[n];
- buffer_info = &tx_ring->buffer_info[tx_ring->next_to_clean];
- printk(KERN_INFO " %5d %5X %5X %016llX %04X %3X %016llX\n",
+ buffer_info = &tx_ring->tx_buffer_info[tx_ring->next_to_clean];
+ printk(KERN_INFO " %5d %5X %5X %016llX %04X %p %016llX\n",
n, tx_ring->next_to_use, tx_ring->next_to_clean,
(u64)buffer_info->dma,
buffer_info->length,
@@ -412,11 +422,12 @@ static void igb_dump(struct igb_adapter *adapter)
"leng ntw timestamp bi->skb\n");
for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
- tx_desc = E1000_TX_DESC_ADV(*tx_ring, i);
- buffer_info = &tx_ring->buffer_info[i];
+ struct igb_tx_buffer *buffer_info;
+ tx_desc = IGB_TX_DESC(tx_ring, i);
+ buffer_info = &tx_ring->tx_buffer_info[i];
u0 = (struct my_u0 *)tx_desc;
printk(KERN_INFO "T [0x%03X] %016llX %016llX %016llX"
- " %04X %3X %016llX %p", i,
+ " %04X %p %016llX %p", i,
le64_to_cpu(u0->a),
le64_to_cpu(u0->b),
(u64)buffer_info->dma,
@@ -492,8 +503,9 @@ rx_ring_summary:
"<-- Adv Rx Write-Back format\n");
for (i = 0; i < rx_ring->count; i++) {
- buffer_info = &rx_ring->buffer_info[i];
- rx_desc = E1000_RX_DESC_ADV(*rx_ring, i);
+ struct igb_rx_buffer *buffer_info;
+ buffer_info = &rx_ring->rx_buffer_info[i];
+ rx_desc = IGB_RX_DESC(rx_ring, i);
u0 = (struct my_u0 *)rx_desc;
staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
if (staterr & E1000_RXD_STAT_DD) {
@@ -516,16 +528,14 @@ rx_ring_summary:
DUMP_PREFIX_ADDRESS,
16, 1,
phys_to_virt(buffer_info->dma),
- rx_ring->rx_buffer_len, true);
- if (rx_ring->rx_buffer_len
- < IGB_RXBUFFER_1024)
- print_hex_dump(KERN_INFO, "",
- DUMP_PREFIX_ADDRESS,
- 16, 1,
- phys_to_virt(
- buffer_info->page_dma +
- buffer_info->page_offset),
- PAGE_SIZE/2, true);
+ IGB_RX_HDR_LEN, true);
+ print_hex_dump(KERN_INFO, "",
+ DUMP_PREFIX_ADDRESS,
+ 16, 1,
+ phys_to_virt(
+ buffer_info->page_dma +
+ buffer_info->page_offset),
+ PAGE_SIZE/2, true);
}
}
@@ -560,7 +570,7 @@ static cycle_t igb_read_clock(const struct cyclecounter *tc)
* the lowest register is SYSTIMR instead of SYSTIML. However we never
* adjusted TIMINCA so SYSTIMR will just read as all 0s so ignore it.
*/
- if (hw->mac.type == e1000_82580) {
+ if (hw->mac.type >= e1000_82580) {
stamp = rd32(E1000_SYSTIMR) >> 8;
shift = IGB_82580_TSYNC_SHIFT;
}
@@ -683,61 +693,116 @@ static int igb_alloc_queues(struct igb_adapter *adapter)
{
struct igb_ring *ring;
int i;
+ int orig_node = adapter->node;
for (i = 0; i < adapter->num_tx_queues; i++) {
- ring = kzalloc(sizeof(struct igb_ring), GFP_KERNEL);
+ if (orig_node == -1) {
+ int cur_node = next_online_node(adapter->node);
+ if (cur_node == MAX_NUMNODES)
+ cur_node = first_online_node;
+ adapter->node = cur_node;
+ }
+ ring = kzalloc_node(sizeof(struct igb_ring), GFP_KERNEL,
+ adapter->node);
+ if (!ring)
+ ring = kzalloc(sizeof(struct igb_ring), GFP_KERNEL);
if (!ring)
goto err;
ring->count = adapter->tx_ring_count;
ring->queue_index = i;
ring->dev = &adapter->pdev->dev;
ring->netdev = adapter->netdev;
+ ring->numa_node = adapter->node;
/* For 82575, context index must be unique per ring. */
if (adapter->hw.mac.type == e1000_82575)
- ring->flags = IGB_RING_FLAG_TX_CTX_IDX;
+ set_bit(IGB_RING_FLAG_TX_CTX_IDX, &ring->flags);
adapter->tx_ring[i] = ring;
}
+ /* Restore the adapter's original node */
+ adapter->node = orig_node;
for (i = 0; i < adapter->num_rx_queues; i++) {
- ring = kzalloc(sizeof(struct igb_ring), GFP_KERNEL);
+ if (orig_node == -1) {
+ int cur_node = next_online_node(adapter->node);
+ if (cur_node == MAX_NUMNODES)
+ cur_node = first_online_node;
+ adapter->node = cur_node;
+ }
+ ring = kzalloc_node(sizeof(struct igb_ring), GFP_KERNEL,
+ adapter->node);
+ if (!ring)
+ ring = kzalloc(sizeof(struct igb_ring), GFP_KERNEL);
if (!ring)
goto err;
ring->count = adapter->rx_ring_count;
ring->queue_index = i;
ring->dev = &adapter->pdev->dev;
ring->netdev = adapter->netdev;
- ring->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
- ring->flags = IGB_RING_FLAG_RX_CSUM; /* enable rx checksum */
+ ring->numa_node = adapter->node;
/* set flag indicating ring supports SCTP checksum offload */
if (adapter->hw.mac.type >= e1000_82576)
- ring->flags |= IGB_RING_FLAG_RX_SCTP_CSUM;
+ set_bit(IGB_RING_FLAG_RX_SCTP_CSUM, &ring->flags);
+
+ /* On i350, loopback VLAN packets have the tag byte-swapped. */
+ if (adapter->hw.mac.type == e1000_i350)
+ set_bit(IGB_RING_FLAG_RX_LB_VLAN_BSWAP, &ring->flags);
+
adapter->rx_ring[i] = ring;
}
+ /* Restore the adapter's original node */
+ adapter->node = orig_node;
igb_cache_ring_register(adapter);
return 0;
err:
+ /* Restore the adapter's original node */
+ adapter->node = orig_node;
igb_free_queues(adapter);
return -ENOMEM;
}
+/**
+ * igb_write_ivar - configure ivar for given MSI-X vector
+ * @hw: pointer to the HW structure
+ * @msix_vector: vector number we are allocating to a given ring
+ * @index: row index of IVAR register to write within IVAR table
+ * @offset: column offset of in IVAR, should be multiple of 8
+ *
+ * This function is intended to handle the writing of the IVAR register
+ * for adapters 82576 and newer. The IVAR table consists of 2 columns,
+ * each containing an cause allocation for an Rx and Tx ring, and a
+ * variable number of rows depending on the number of queues supported.
+ **/
+static void igb_write_ivar(struct e1000_hw *hw, int msix_vector,
+ int index, int offset)
+{
+ u32 ivar = array_rd32(E1000_IVAR0, index);
+
+ /* clear any bits that are currently set */
+ ivar &= ~((u32)0xFF << offset);
+
+ /* write vector and valid bit */
+ ivar |= (msix_vector | E1000_IVAR_VALID) << offset;
+
+ array_wr32(E1000_IVAR0, index, ivar);
+}
+
#define IGB_N0_QUEUE -1
static void igb_assign_vector(struct igb_q_vector *q_vector, int msix_vector)
{
- u32 msixbm = 0;
struct igb_adapter *adapter = q_vector->adapter;
struct e1000_hw *hw = &adapter->hw;
- u32 ivar, index;
int rx_queue = IGB_N0_QUEUE;
int tx_queue = IGB_N0_QUEUE;
+ u32 msixbm = 0;
- if (q_vector->rx_ring)
- rx_queue = q_vector->rx_ring->reg_idx;
- if (q_vector->tx_ring)
- tx_queue = q_vector->tx_ring->reg_idx;
+ if (q_vector->rx.ring)
+ rx_queue = q_vector->rx.ring->reg_idx;
+ if (q_vector->tx.ring)
+ tx_queue = q_vector->tx.ring->reg_idx;
switch (hw->mac.type) {
case e1000_82575:
@@ -755,72 +820,39 @@ static void igb_assign_vector(struct igb_q_vector *q_vector, int msix_vector)
q_vector->eims_value = msixbm;
break;
case e1000_82576:
- /* 82576 uses a table-based method for assigning vectors.
- Each queue has a single entry in the table to which we write
- a vector number along with a "valid" bit. Sadly, the layout
- of the table is somewhat counterintuitive. */
- if (rx_queue > IGB_N0_QUEUE) {
- index = (rx_queue & 0x7);
- ivar = array_rd32(E1000_IVAR0, index);
- if (rx_queue < 8) {
- /* vector goes into low byte of register */
- ivar = ivar & 0xFFFFFF00;
- ivar |= msix_vector | E1000_IVAR_VALID;
- } else {
- /* vector goes into third byte of register */
- ivar = ivar & 0xFF00FFFF;
- ivar |= (msix_vector | E1000_IVAR_VALID) << 16;
- }
- array_wr32(E1000_IVAR0, index, ivar);
- }
- if (tx_queue > IGB_N0_QUEUE) {
- index = (tx_queue & 0x7);
- ivar = array_rd32(E1000_IVAR0, index);
- if (tx_queue < 8) {
- /* vector goes into second byte of register */
- ivar = ivar & 0xFFFF00FF;
- ivar |= (msix_vector | E1000_IVAR_VALID) << 8;
- } else {
- /* vector goes into high byte of register */
- ivar = ivar & 0x00FFFFFF;
- ivar |= (msix_vector | E1000_IVAR_VALID) << 24;
- }
- array_wr32(E1000_IVAR0, index, ivar);
- }
+ /*
+ * 82576 uses a table that essentially consists of 2 columns
+ * with 8 rows. The ordering is column-major so we use the
+ * lower 3 bits as the row index, and the 4th bit as the
+ * column offset.
+ */
+ if (rx_queue > IGB_N0_QUEUE)
+ igb_write_ivar(hw, msix_vector,
+ rx_queue & 0x7,
+ (rx_queue & 0x8) << 1);
+ if (tx_queue > IGB_N0_QUEUE)
+ igb_write_ivar(hw, msix_vector,
+ tx_queue & 0x7,
+ ((tx_queue & 0x8) << 1) + 8);
q_vector->eims_value = 1 << msix_vector;
break;
case e1000_82580:
case e1000_i350:
- /* 82580 uses the same table-based approach as 82576 but has fewer
- entries as a result we carry over for queues greater than 4. */
- if (rx_queue > IGB_N0_QUEUE) {
- index = (rx_queue >> 1);
- ivar = array_rd32(E1000_IVAR0, index);
- if (rx_queue & 0x1) {
- /* vector goes into third byte of register */
- ivar = ivar & 0xFF00FFFF;
- ivar |= (msix_vector | E1000_IVAR_VALID) << 16;
- } else {
- /* vector goes into low byte of register */
- ivar = ivar & 0xFFFFFF00;
- ivar |= msix_vector | E1000_IVAR_VALID;
- }
- array_wr32(E1000_IVAR0, index, ivar);
- }
- if (tx_queue > IGB_N0_QUEUE) {
- index = (tx_queue >> 1);
- ivar = array_rd32(E1000_IVAR0, index);
- if (tx_queue & 0x1) {
- /* vector goes into high byte of register */
- ivar = ivar & 0x00FFFFFF;
- ivar |= (msix_vector | E1000_IVAR_VALID) << 24;
- } else {
- /* vector goes into second byte of register */
- ivar = ivar & 0xFFFF00FF;
- ivar |= (msix_vector | E1000_IVAR_VALID) << 8;
- }
- array_wr32(E1000_IVAR0, index, ivar);
- }
+ /*
+ * On 82580 and newer adapters the scheme is similar to 82576
+ * however instead of ordering column-major we have things
+ * ordered row-major. So we traverse the table by using
+ * bit 0 as the column offset, and the remaining bits as the
+ * row index.
+ */
+ if (rx_queue > IGB_N0_QUEUE)
+ igb_write_ivar(hw, msix_vector,
+ rx_queue >> 1,
+ (rx_queue & 0x1) << 4);
+ if (tx_queue > IGB_N0_QUEUE)
+ igb_write_ivar(hw, msix_vector,
+ tx_queue >> 1,
+ ((tx_queue & 0x1) << 4) + 8);
q_vector->eims_value = 1 << msix_vector;
break;
default:
@@ -920,15 +952,15 @@ static int igb_request_msix(struct igb_adapter *adapter)
q_vector->itr_register = hw->hw_addr + E1000_EITR(vector);
- if (q_vector->rx_ring && q_vector->tx_ring)
+ if (q_vector->rx.ring && q_vector->tx.ring)
sprintf(q_vector->name, "%s-TxRx-%u", netdev->name,
- q_vector->rx_ring->queue_index);
- else if (q_vector->tx_ring)
+ q_vector->rx.ring->queue_index);
+ else if (q_vector->tx.ring)
sprintf(q_vector->name, "%s-tx-%u", netdev->name,
- q_vector->tx_ring->queue_index);
- else if (q_vector->rx_ring)
+ q_vector->tx.ring->queue_index);
+ else if (q_vector->rx.ring)
sprintf(q_vector->name, "%s-rx-%u", netdev->name,
- q_vector->rx_ring->queue_index);
+ q_vector->rx.ring->queue_index);
else
sprintf(q_vector->name, "%s-unused", netdev->name);
@@ -1084,9 +1116,24 @@ static int igb_alloc_q_vectors(struct igb_adapter *adapter)
struct igb_q_vector *q_vector;
struct e1000_hw *hw = &adapter->hw;
int v_idx;
+ int orig_node = adapter->node;
for (v_idx = 0; v_idx < adapter->num_q_vectors; v_idx++) {
- q_vector = kzalloc(sizeof(struct igb_q_vector), GFP_KERNEL);
+ if ((adapter->num_q_vectors == (adapter->num_rx_queues +
+ adapter->num_tx_queues)) &&
+ (adapter->num_rx_queues == v_idx))
+ adapter->node = orig_node;
+ if (orig_node == -1) {
+ int cur_node = next_online_node(adapter->node);
+ if (cur_node == MAX_NUMNODES)
+ cur_node = first_online_node;
+ adapter->node = cur_node;
+ }
+ q_vector = kzalloc_node(sizeof(struct igb_q_vector), GFP_KERNEL,
+ adapter->node);
+ if (!q_vector)
+ q_vector = kzalloc(sizeof(struct igb_q_vector),
+ GFP_KERNEL);
if (!q_vector)
goto err_out;
q_vector->adapter = adapter;
@@ -1095,9 +1142,14 @@ static int igb_alloc_q_vectors(struct igb_adapter *adapter)
netif_napi_add(adapter->netdev, &q_vector->napi, igb_poll, 64);
adapter->q_vector[v_idx] = q_vector;
}
+ /* Restore the adapter's original node */
+ adapter->node = orig_node;
+
return 0;
err_out:
+ /* Restore the adapter's original node */
+ adapter->node = orig_node;
igb_free_q_vectors(adapter);
return -ENOMEM;
}
@@ -1107,8 +1159,9 @@ static void igb_map_rx_ring_to_vector(struct igb_adapter *adapter,
{
struct igb_q_vector *q_vector = adapter->q_vector[v_idx];
- q_vector->rx_ring = adapter->rx_ring[ring_idx];
- q_vector->rx_ring->q_vector = q_vector;
+ q_vector->rx.ring = adapter->rx_ring[ring_idx];
+ q_vector->rx.ring->q_vector = q_vector;
+ q_vector->rx.count++;
q_vector->itr_val = adapter->rx_itr_setting;
if (q_vector->itr_val && q_vector->itr_val <= 3)
q_vector->itr_val = IGB_START_ITR;
@@ -1119,9 +1172,11 @@ static void igb_map_tx_ring_to_vector(struct igb_adapter *adapter,
{
struct igb_q_vector *q_vector = adapter->q_vector[v_idx];
- q_vector->tx_ring = adapter->tx_ring[ring_idx];
- q_vector->tx_ring->q_vector = q_vector;
+ q_vector->tx.ring = adapter->tx_ring[ring_idx];
+ q_vector->tx.ring->q_vector = q_vector;
+ q_vector->tx.count++;
q_vector->itr_val = adapter->tx_itr_setting;
+ q_vector->tx.work_limit = adapter->tx_work_limit;
if (q_vector->itr_val && q_vector->itr_val <= 3)
q_vector->itr_val = IGB_START_ITR;
}
@@ -1219,7 +1274,7 @@ static int igb_request_irq(struct igb_adapter *adapter)
goto request_done;
/* fall back to MSI */
igb_clear_interrupt_scheme(adapter);
- if (!pci_enable_msi(adapter->pdev))
+ if (!pci_enable_msi(pdev))
adapter->flags |= IGB_FLAG_HAS_MSI;
igb_free_all_tx_resources(adapter);
igb_free_all_rx_resources(adapter);
@@ -1241,12 +1296,12 @@ static int igb_request_irq(struct igb_adapter *adapter)
}
igb_setup_all_tx_resources(adapter);
igb_setup_all_rx_resources(adapter);
- } else {
- igb_assign_vector(adapter->q_vector[0], 0);
}
+ igb_assign_vector(adapter->q_vector[0], 0);
+
if (adapter->flags & IGB_FLAG_HAS_MSI) {
- err = request_irq(adapter->pdev->irq, igb_intr_msi, 0,
+ err = request_irq(pdev->irq, igb_intr_msi, 0,
netdev->name, adapter);
if (!err)
goto request_done;
@@ -1256,11 +1311,11 @@ static int igb_request_irq(struct igb_adapter *adapter)
adapter->flags &= ~IGB_FLAG_HAS_MSI;
}
- err = request_irq(adapter->pdev->irq, igb_intr, IRQF_SHARED,
+ err = request_irq(pdev->irq, igb_intr, IRQF_SHARED,
netdev->name, adapter);
if (err)
- dev_err(&adapter->pdev->dev, "Error %d getting interrupt\n",
+ dev_err(&pdev->dev, "Error %d getting interrupt\n",
err);
request_done:
@@ -1274,11 +1329,9 @@ static void igb_free_irq(struct igb_adapter *adapter)
free_irq(adapter->msix_entries[vector++].vector, adapter);
- for (i = 0; i < adapter->num_q_vectors; i++) {
- struct igb_q_vector *q_vector = adapter->q_vector[i];
+ for (i = 0; i < adapter->num_q_vectors; i++)
free_irq(adapter->msix_entries[vector++].vector,
- q_vector);
- }
+ adapter->q_vector[i]);
} else {
free_irq(adapter->pdev->irq, adapter);
}
@@ -1326,7 +1379,7 @@ static void igb_irq_enable(struct igb_adapter *adapter)
struct e1000_hw *hw = &adapter->hw;
if (adapter->msix_entries) {
- u32 ims = E1000_IMS_LSC | E1000_IMS_DOUTSYNC;
+ u32 ims = E1000_IMS_LSC | E1000_IMS_DOUTSYNC | E1000_IMS_DRSTA;
u32 regval = rd32(E1000_EIAC);
wr32(E1000_EIAC, regval | adapter->eims_enable_mask);
regval = rd32(E1000_EIAM);
@@ -1336,9 +1389,6 @@ static void igb_irq_enable(struct igb_adapter *adapter)
wr32(E1000_MBVFIMR, 0xFF);
ims |= E1000_IMS_VMMB;
}
- if (adapter->hw.mac.type == e1000_82580)
- ims |= E1000_IMS_DRSTA;
-
wr32(E1000_IMS, ims);
} else {
wr32(E1000_IMS, IMS_ENABLE_MASK |
@@ -1438,7 +1488,7 @@ static void igb_configure(struct igb_adapter *adapter)
* next_to_use != next_to_clean */
for (i = 0; i < adapter->num_rx_queues; i++) {
struct igb_ring *ring = adapter->rx_ring[i];
- igb_alloc_rx_buffers_adv(ring, igb_desc_unused(ring));
+ igb_alloc_rx_buffers(ring, igb_desc_unused(ring));
}
}
@@ -1480,10 +1530,9 @@ int igb_up(struct igb_adapter *adapter)
clear_bit(__IGB_DOWN, &adapter->state);
- for (i = 0; i < adapter->num_q_vectors; i++) {
- struct igb_q_vector *q_vector = adapter->q_vector[i];
- napi_enable(&q_vector->napi);
- }
+ for (i = 0; i < adapter->num_q_vectors; i++)
+ napi_enable(&(adapter->q_vector[i]->napi));
+
if (adapter->msix_entries)
igb_configure_msix(adapter);
else
@@ -1535,10 +1584,8 @@ void igb_down(struct igb_adapter *adapter)
wrfl();
msleep(10);
- for (i = 0; i < adapter->num_q_vectors; i++) {
- struct igb_q_vector *q_vector = adapter->q_vector[i];
- napi_disable(&q_vector->napi);
- }
+ for (i = 0; i < adapter->num_q_vectors; i++)
+ napi_disable(&(adapter->q_vector[i]->napi));
igb_irq_disable(adapter);
@@ -1682,63 +1729,8 @@ void igb_reset(struct igb_adapter *adapter)
if (hw->mac.ops.init_hw(hw))
dev_err(&pdev->dev, "Hardware Error\n");
- if (hw->mac.type > e1000_82580) {
- if (adapter->flags & IGB_FLAG_DMAC) {
- u32 reg;
-
- /*
- * DMA Coalescing high water mark needs to be higher
- * than * the * Rx threshold. The Rx threshold is
- * currently * pba - 6, so we * should use a high water
- * mark of pba * - 4. */
- hwm = (pba - 4) << 10;
- reg = (((pba-6) << E1000_DMACR_DMACTHR_SHIFT)
- & E1000_DMACR_DMACTHR_MASK);
-
- /* transition to L0x or L1 if available..*/
- reg |= (E1000_DMACR_DMAC_EN | E1000_DMACR_DMAC_LX_MASK);
-
- /* watchdog timer= +-1000 usec in 32usec intervals */
- reg |= (1000 >> 5);
- wr32(E1000_DMACR, reg);
-
- /* no lower threshold to disable coalescing(smart fifb)
- * -UTRESH=0*/
- wr32(E1000_DMCRTRH, 0);
-
- /* set hwm to PBA - 2 * max frame size */
- wr32(E1000_FCRTC, hwm);
-
- /*
- * This sets the time to wait before requesting tran-
- * sition to * low power state to number of usecs needed
- * to receive 1 512 * byte frame at gigabit line rate
- */
- reg = rd32(E1000_DMCTLX);
- reg |= IGB_DMCTLX_DCFLUSH_DIS;
-
- /* Delay 255 usec before entering Lx state. */
- reg |= 0xFF;
- wr32(E1000_DMCTLX, reg);
-
- /* free space in Tx packet buffer to wake from DMAC */
- wr32(E1000_DMCTXTH,
- (IGB_MIN_TXPBSIZE -
- (IGB_TX_BUF_4096 + adapter->max_frame_size))
- >> 6);
-
- /* make low power state decision controlled by DMAC */
- reg = rd32(E1000_PCIEMISC);
- reg |= E1000_PCIEMISC_LX_DECISION;
- wr32(E1000_PCIEMISC, reg);
- } /* end if IGB_FLAG_DMAC set */
- }
- if (hw->mac.type == e1000_82580) {
- u32 reg = rd32(E1000_PCIEMISC);
- wr32(E1000_PCIEMISC,
- reg & ~E1000_PCIEMISC_LX_DECISION);
- }
+ igb_init_dmac(adapter, pba);
if (!netif_running(adapter->netdev))
igb_power_down_link(adapter);
@@ -1766,17 +1758,8 @@ static u32 igb_fix_features(struct net_device *netdev, u32 features)
static int igb_set_features(struct net_device *netdev, u32 features)
{
- struct igb_adapter *adapter = netdev_priv(netdev);
- int i;
u32 changed = netdev->features ^ features;
- for (i = 0; i < adapter->num_rx_queues; i++) {
- if (features & NETIF_F_RXCSUM)
- adapter->rx_ring[i]->flags |= IGB_RING_FLAG_RX_CSUM;
- else
- adapter->rx_ring[i]->flags &= ~IGB_RING_FLAG_RX_CSUM;
- }
-
if (changed & NETIF_F_HW_VLAN_RX)
igb_vlan_mode(netdev, features);
@@ -1786,10 +1769,9 @@ static int igb_set_features(struct net_device *netdev, u32 features)
static const struct net_device_ops igb_netdev_ops = {
.ndo_open = igb_open,
.ndo_stop = igb_close,
- .ndo_start_xmit = igb_xmit_frame_adv,
+ .ndo_start_xmit = igb_xmit_frame,
.ndo_get_stats64 = igb_get_stats64,
.ndo_set_rx_mode = igb_set_rx_mode,
- .ndo_set_multicast_list = igb_set_rx_mode,
.ndo_set_mac_address = igb_set_mac,
.ndo_change_mtu = igb_change_mtu,
.ndo_do_ioctl = igb_ioctl,
@@ -1878,7 +1860,7 @@ static int __devinit igb_probe(struct pci_dev *pdev,
err = -ENOMEM;
netdev = alloc_etherdev_mq(sizeof(struct igb_adapter),
- IGB_ABS_MAX_TX_QUEUES);
+ IGB_MAX_TX_QUEUES);
if (!netdev)
goto err_alloc_etherdev;
@@ -1945,23 +1927,32 @@ static int __devinit igb_probe(struct pci_dev *pdev,
dev_info(&pdev->dev,
"PHY reset is blocked due to SOL/IDER session.\n");
- netdev->hw_features = NETIF_F_SG |
- NETIF_F_IP_CSUM |
- NETIF_F_IPV6_CSUM |
- NETIF_F_TSO |
- NETIF_F_TSO6 |
- NETIF_F_RXCSUM |
- NETIF_F_HW_VLAN_RX;
-
- netdev->features = netdev->hw_features |
- NETIF_F_HW_VLAN_TX |
- NETIF_F_HW_VLAN_FILTER;
-
- netdev->vlan_features |= NETIF_F_TSO;
- netdev->vlan_features |= NETIF_F_TSO6;
- netdev->vlan_features |= NETIF_F_IP_CSUM;
- netdev->vlan_features |= NETIF_F_IPV6_CSUM;
- netdev->vlan_features |= NETIF_F_SG;
+ /*
+ * features is initialized to 0 in allocation, it might have bits
+ * set by igb_sw_init so we should use an or instead of an
+ * assignment.
+ */
+ netdev->features |= NETIF_F_SG |
+ NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM |
+ NETIF_F_TSO |
+ NETIF_F_TSO6 |
+ NETIF_F_RXHASH |
+ NETIF_F_RXCSUM |
+ NETIF_F_HW_VLAN_RX |
+ NETIF_F_HW_VLAN_TX;
+
+ /* copy netdev features into list of user selectable features */
+ netdev->hw_features |= netdev->features;
+
+ /* set this bit last since it cannot be part of hw_features */
+ netdev->features |= NETIF_F_HW_VLAN_FILTER;
+
+ netdev->vlan_features |= NETIF_F_TSO |
+ NETIF_F_TSO6 |
+ NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM |
+ NETIF_F_SG;
if (pci_using_dac) {
netdev->features |= NETIF_F_HIGHDMA;
@@ -1973,6 +1964,8 @@ static int __devinit igb_probe(struct pci_dev *pdev,
netdev->features |= NETIF_F_SCTP_CSUM;
}
+ netdev->priv_flags |= IFF_UNICAST_FLT;
+
adapter->en_mng_pt = igb_enable_mng_pass_thru(hw);
/* before reading the NVM, reset the controller to put the device in a
@@ -2077,8 +2070,6 @@ static int __devinit igb_probe(struct pci_dev *pdev,
if (err)
goto err_register;
- igb_vlan_mode(netdev, netdev->features);
-
/* carrier off reporting is important to ethtool even BEFORE open */
netif_carrier_off(netdev);
@@ -2193,8 +2184,12 @@ static void __devexit igb_remove(struct pci_dev *pdev)
/* reclaim resources allocated to VFs */
if (adapter->vf_data) {
/* disable iov and allow time for transactions to clear */
- pci_disable_sriov(pdev);
- msleep(500);
+ if (!igb_check_vf_assignment(adapter)) {
+ pci_disable_sriov(pdev);
+ msleep(500);
+ } else {
+ dev_info(&pdev->dev, "VF(s) assigned to guests!\n");
+ }
kfree(adapter->vf_data);
adapter->vf_data = NULL;
@@ -2211,6 +2206,7 @@ static void __devexit igb_remove(struct pci_dev *pdev)
pci_release_selected_regions(pdev,
pci_select_bars(pdev, IORESOURCE_MEM));
+ kfree(adapter->shadow_vfta);
free_netdev(netdev);
pci_disable_pcie_error_reporting(pdev);
@@ -2231,42 +2227,49 @@ static void __devinit igb_probe_vfs(struct igb_adapter * adapter)
{
#ifdef CONFIG_PCI_IOV
struct pci_dev *pdev = adapter->pdev;
+ int old_vfs = igb_find_enabled_vfs(adapter);
+ int i;
- if (adapter->vfs_allocated_count) {
- adapter->vf_data = kcalloc(adapter->vfs_allocated_count,
- sizeof(struct vf_data_storage),
- GFP_KERNEL);
- /* if allocation failed then we do not support SR-IOV */
- if (!adapter->vf_data) {
- adapter->vfs_allocated_count = 0;
- dev_err(&pdev->dev, "Unable to allocate memory for VF "
- "Data Storage\n");
- }
+ if (old_vfs) {
+ dev_info(&pdev->dev, "%d pre-allocated VFs found - override "
+ "max_vfs setting of %d\n", old_vfs, max_vfs);
+ adapter->vfs_allocated_count = old_vfs;
}
- if (pci_enable_sriov(pdev, adapter->vfs_allocated_count)) {
- kfree(adapter->vf_data);
- adapter->vf_data = NULL;
-#endif /* CONFIG_PCI_IOV */
+ if (!adapter->vfs_allocated_count)
+ return;
+
+ adapter->vf_data = kcalloc(adapter->vfs_allocated_count,
+ sizeof(struct vf_data_storage), GFP_KERNEL);
+ /* if allocation failed then we do not support SR-IOV */
+ if (!adapter->vf_data) {
adapter->vfs_allocated_count = 0;
-#ifdef CONFIG_PCI_IOV
- } else {
- unsigned char mac_addr[ETH_ALEN];
- int i;
- dev_info(&pdev->dev, "%d vfs allocated\n",
- adapter->vfs_allocated_count);
- for (i = 0; i < adapter->vfs_allocated_count; i++) {
- random_ether_addr(mac_addr);
- igb_set_vf_mac(adapter, i, mac_addr);
- }
- /* DMA Coalescing is not supported in IOV mode. */
- if (adapter->flags & IGB_FLAG_DMAC)
- adapter->flags &= ~IGB_FLAG_DMAC;
+ dev_err(&pdev->dev, "Unable to allocate memory for VF "
+ "Data Storage\n");
+ goto out;
+ }
+
+ if (!old_vfs) {
+ if (pci_enable_sriov(pdev, adapter->vfs_allocated_count))
+ goto err_out;
}
+ dev_info(&pdev->dev, "%d VFs allocated\n",
+ adapter->vfs_allocated_count);
+ for (i = 0; i < adapter->vfs_allocated_count; i++)
+ igb_vf_configure(adapter, i);
+
+ /* DMA Coalescing is not supported in IOV mode. */
+ adapter->flags &= ~IGB_FLAG_DMAC;
+ goto out;
+err_out:
+ kfree(adapter->vf_data);
+ adapter->vf_data = NULL;
+ adapter->vfs_allocated_count = 0;
+out:
+ return;
#endif /* CONFIG_PCI_IOV */
}
-
/**
* igb_init_hw_timer - Initialize hardware timer used with IEEE 1588 timestamp
* @adapter: board private structure to initialize
@@ -2389,14 +2392,23 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter)
pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
+ /* set default ring sizes */
adapter->tx_ring_count = IGB_DEFAULT_TXD;
adapter->rx_ring_count = IGB_DEFAULT_RXD;
+
+ /* set default ITR values */
adapter->rx_itr_setting = IGB_DEFAULT_ITR;
adapter->tx_itr_setting = IGB_DEFAULT_ITR;
- adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+ /* set default work limits */
+ adapter->tx_work_limit = IGB_DEFAULT_TX_WORK;
+
+ adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN +
+ VLAN_HLEN;
adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
+ adapter->node = -1;
+
spin_lock_init(&adapter->stats64_lock);
#ifdef CONFIG_PCI_IOV
switch (hw->mac.type) {
@@ -2427,6 +2439,11 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter)
((adapter->rss_queues > 1) && (adapter->vfs_allocated_count > 6)))
adapter->flags |= IGB_FLAG_QUEUE_PAIRS;
+ /* Setup and initialize a copy of the hw vlan table array */
+ adapter->shadow_vfta = kzalloc(sizeof(u32) *
+ E1000_VLAN_FILTER_TBL_SIZE,
+ GFP_ATOMIC);
+
/* This call may decrease the number of queues */
if (igb_init_interrupt_scheme(adapter)) {
dev_err(&pdev->dev, "Unable to allocate memory for queues\n");
@@ -2495,10 +2512,8 @@ static int igb_open(struct net_device *netdev)
/* From here on the code is the same as igb_up() */
clear_bit(__IGB_DOWN, &adapter->state);
- for (i = 0; i < adapter->num_q_vectors; i++) {
- struct igb_q_vector *q_vector = adapter->q_vector[i];
- napi_enable(&q_vector->napi);
- }
+ for (i = 0; i < adapter->num_q_vectors; i++)
+ napi_enable(&(adapter->q_vector[i]->napi));
/* Clear any pending interrupts. */
rd32(E1000_ICR);
@@ -2567,31 +2582,42 @@ static int igb_close(struct net_device *netdev)
int igb_setup_tx_resources(struct igb_ring *tx_ring)
{
struct device *dev = tx_ring->dev;
+ int orig_node = dev_to_node(dev);
int size;
- size = sizeof(struct igb_buffer) * tx_ring->count;
- tx_ring->buffer_info = vzalloc(size);
- if (!tx_ring->buffer_info)
+ size = sizeof(struct igb_tx_buffer) * tx_ring->count;
+ tx_ring->tx_buffer_info = vzalloc_node(size, tx_ring->numa_node);
+ if (!tx_ring->tx_buffer_info)
+ tx_ring->tx_buffer_info = vzalloc(size);
+ if (!tx_ring->tx_buffer_info)
goto err;
/* round up to nearest 4K */
tx_ring->size = tx_ring->count * sizeof(union e1000_adv_tx_desc);
tx_ring->size = ALIGN(tx_ring->size, 4096);
+ set_dev_node(dev, tx_ring->numa_node);
tx_ring->desc = dma_alloc_coherent(dev,
tx_ring->size,
&tx_ring->dma,
GFP_KERNEL);
+ set_dev_node(dev, orig_node);
+ if (!tx_ring->desc)
+ tx_ring->desc = dma_alloc_coherent(dev,
+ tx_ring->size,
+ &tx_ring->dma,
+ GFP_KERNEL);
if (!tx_ring->desc)
goto err;
tx_ring->next_to_use = 0;
tx_ring->next_to_clean = 0;
+
return 0;
err:
- vfree(tx_ring->buffer_info);
+ vfree(tx_ring->tx_buffer_info);
dev_err(dev,
"Unable to allocate memory for the transmit descriptor ring\n");
return -ENOMEM;
@@ -2620,10 +2646,6 @@ static int igb_setup_all_tx_resources(struct igb_adapter *adapter)
}
}
- for (i = 0; i < IGB_ABS_MAX_TX_QUEUES; i++) {
- int r_idx = i % adapter->num_tx_queues;
- adapter->multi_tx_table[i] = adapter->tx_ring[r_idx];
- }
return err;
}
@@ -2664,14 +2686,12 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
struct igb_ring *ring)
{
struct e1000_hw *hw = &adapter->hw;
- u32 txdctl;
+ u32 txdctl = 0;
u64 tdba = ring->dma;
int reg_idx = ring->reg_idx;
/* disable the queue */
- txdctl = rd32(E1000_TXDCTL(reg_idx));
- wr32(E1000_TXDCTL(reg_idx),
- txdctl & ~E1000_TXDCTL_QUEUE_ENABLE);
+ wr32(E1000_TXDCTL(reg_idx), 0);
wrfl();
mdelay(10);
@@ -2681,9 +2701,8 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
tdba & 0x00000000ffffffffULL);
wr32(E1000_TDBAH(reg_idx), tdba >> 32);
- ring->head = hw->hw_addr + E1000_TDH(reg_idx);
ring->tail = hw->hw_addr + E1000_TDT(reg_idx);
- writel(0, ring->head);
+ wr32(E1000_TDH(reg_idx), 0);
writel(0, ring->tail);
txdctl |= IGB_TX_PTHRESH;
@@ -2717,11 +2736,14 @@ static void igb_configure_tx(struct igb_adapter *adapter)
int igb_setup_rx_resources(struct igb_ring *rx_ring)
{
struct device *dev = rx_ring->dev;
+ int orig_node = dev_to_node(dev);
int size, desc_len;
- size = sizeof(struct igb_buffer) * rx_ring->count;
- rx_ring->buffer_info = vzalloc(size);
- if (!rx_ring->buffer_info)
+ size = sizeof(struct igb_rx_buffer) * rx_ring->count;
+ rx_ring->rx_buffer_info = vzalloc_node(size, rx_ring->numa_node);
+ if (!rx_ring->rx_buffer_info)
+ rx_ring->rx_buffer_info = vzalloc(size);
+ if (!rx_ring->rx_buffer_info)
goto err;
desc_len = sizeof(union e1000_adv_rx_desc);
@@ -2730,10 +2752,17 @@ int igb_setup_rx_resources(struct igb_ring *rx_ring)
rx_ring->size = rx_ring->count * desc_len;
rx_ring->size = ALIGN(rx_ring->size, 4096);
+ set_dev_node(dev, rx_ring->numa_node);
rx_ring->desc = dma_alloc_coherent(dev,
rx_ring->size,
&rx_ring->dma,
GFP_KERNEL);
+ set_dev_node(dev, orig_node);
+ if (!rx_ring->desc)
+ rx_ring->desc = dma_alloc_coherent(dev,
+ rx_ring->size,
+ &rx_ring->dma,
+ GFP_KERNEL);
if (!rx_ring->desc)
goto err;
@@ -2744,8 +2773,8 @@ int igb_setup_rx_resources(struct igb_ring *rx_ring)
return 0;
err:
- vfree(rx_ring->buffer_info);
- rx_ring->buffer_info = NULL;
+ vfree(rx_ring->rx_buffer_info);
+ rx_ring->rx_buffer_info = NULL;
dev_err(dev, "Unable to allocate memory for the receive descriptor"
" ring\n");
return -ENOMEM;
@@ -2962,16 +2991,19 @@ static inline int igb_set_vf_rlpml(struct igb_adapter *adapter, int size,
**/
static void igb_rlpml_set(struct igb_adapter *adapter)
{
- u32 max_frame_size;
+ u32 max_frame_size = adapter->max_frame_size;
struct e1000_hw *hw = &adapter->hw;
u16 pf_id = adapter->vfs_allocated_count;
- max_frame_size = adapter->max_frame_size + VLAN_TAG_SIZE;
-
- /* if vfs are enabled we set RLPML to the largest possible request
- * size and set the VMOLR RLPML to the size we need */
if (pf_id) {
igb_set_vf_rlpml(adapter, max_frame_size, pf_id);
+ /*
+ * If we're in VMDQ or SR-IOV mode, then set global RLPML
+ * to our max jumbo frame size, in case we need to enable
+ * jumbo frames on one of the rings later.
+ * This will not pass over-length frames into the default
+ * queue because it's gated by the VMOLR.RLPML.
+ */
max_frame_size = MAX_JUMBO_FRAME_SIZE;
}
@@ -3026,12 +3058,10 @@ void igb_configure_rx_ring(struct igb_adapter *adapter,
struct e1000_hw *hw = &adapter->hw;
u64 rdba = ring->dma;
int reg_idx = ring->reg_idx;
- u32 srrctl, rxdctl;
+ u32 srrctl = 0, rxdctl = 0;
/* disable the queue */
- rxdctl = rd32(E1000_RXDCTL(reg_idx));
- wr32(E1000_RXDCTL(reg_idx),
- rxdctl & ~E1000_RXDCTL_QUEUE_ENABLE);
+ wr32(E1000_RXDCTL(reg_idx), 0);
/* Set DMA base address registers */
wr32(E1000_RDBAL(reg_idx),
@@ -3041,29 +3071,19 @@ void igb_configure_rx_ring(struct igb_adapter *adapter,
ring->count * sizeof(union e1000_adv_rx_desc));
/* initialize head and tail */
- ring->head = hw->hw_addr + E1000_RDH(reg_idx);
ring->tail = hw->hw_addr + E1000_RDT(reg_idx);
- writel(0, ring->head);
+ wr32(E1000_RDH(reg_idx), 0);
writel(0, ring->tail);
/* set descriptor configuration */
- if (ring->rx_buffer_len < IGB_RXBUFFER_1024) {
- srrctl = ALIGN(ring->rx_buffer_len, 64) <<
- E1000_SRRCTL_BSIZEHDRSIZE_SHIFT;
+ srrctl = IGB_RX_HDR_LEN << E1000_SRRCTL_BSIZEHDRSIZE_SHIFT;
#if (PAGE_SIZE / 2) > IGB_RXBUFFER_16384
- srrctl |= IGB_RXBUFFER_16384 >>
- E1000_SRRCTL_BSIZEPKT_SHIFT;
+ srrctl |= IGB_RXBUFFER_16384 >> E1000_SRRCTL_BSIZEPKT_SHIFT;
#else
- srrctl |= (PAGE_SIZE / 2) >>
- E1000_SRRCTL_BSIZEPKT_SHIFT;
+ srrctl |= (PAGE_SIZE / 2) >> E1000_SRRCTL_BSIZEPKT_SHIFT;
#endif
- srrctl |= E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS;
- } else {
- srrctl = ALIGN(ring->rx_buffer_len, 1024) >>
- E1000_SRRCTL_BSIZEPKT_SHIFT;
- srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
- }
- if (hw->mac.type == e1000_82580)
+ srrctl |= E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS;
+ if (hw->mac.type >= e1000_82580)
srrctl |= E1000_SRRCTL_TIMESTAMP;
/* Only set Drop Enable if we are supporting multiple queues */
if (adapter->vfs_allocated_count || adapter->num_rx_queues > 1)
@@ -3074,13 +3094,12 @@ void igb_configure_rx_ring(struct igb_adapter *adapter,
/* set filtering for VMDQ pools */
igb_set_vmolr(adapter, reg_idx & 0x7, true);
- /* enable receive descriptor fetching */
- rxdctl = rd32(E1000_RXDCTL(reg_idx));
- rxdctl |= E1000_RXDCTL_QUEUE_ENABLE;
- rxdctl &= 0xFFF00000;
rxdctl |= IGB_RX_PTHRESH;
rxdctl |= IGB_RX_HTHRESH << 8;
rxdctl |= IGB_RX_WTHRESH << 16;
+
+ /* enable receive descriptor fetching */
+ rxdctl |= E1000_RXDCTL_QUEUE_ENABLE;
wr32(E1000_RXDCTL(reg_idx), rxdctl);
}
@@ -3117,8 +3136,8 @@ void igb_free_tx_resources(struct igb_ring *tx_ring)
{
igb_clean_tx_ring(tx_ring);
- vfree(tx_ring->buffer_info);
- tx_ring->buffer_info = NULL;
+ vfree(tx_ring->tx_buffer_info);
+ tx_ring->tx_buffer_info = NULL;
/* if not set, then don't free */
if (!tx_ring->desc)
@@ -3144,30 +3163,26 @@ static void igb_free_all_tx_resources(struct igb_adapter *adapter)
igb_free_tx_resources(adapter->tx_ring[i]);
}
-void igb_unmap_and_free_tx_resource(struct igb_ring *tx_ring,
- struct igb_buffer *buffer_info)
+void igb_unmap_and_free_tx_resource(struct igb_ring *ring,
+ struct igb_tx_buffer *tx_buffer)
{
- if (buffer_info->dma) {
- if (buffer_info->mapped_as_page)
- dma_unmap_page(tx_ring->dev,
- buffer_info->dma,
- buffer_info->length,
- DMA_TO_DEVICE);
- else
- dma_unmap_single(tx_ring->dev,
- buffer_info->dma,
- buffer_info->length,
- DMA_TO_DEVICE);
- buffer_info->dma = 0;
- }
- if (buffer_info->skb) {
- dev_kfree_skb_any(buffer_info->skb);
- buffer_info->skb = NULL;
+ if (tx_buffer->skb) {
+ dev_kfree_skb_any(tx_buffer->skb);
+ if (tx_buffer->dma)
+ dma_unmap_single(ring->dev,
+ tx_buffer->dma,
+ tx_buffer->length,
+ DMA_TO_DEVICE);
+ } else if (tx_buffer->dma) {
+ dma_unmap_page(ring->dev,
+ tx_buffer->dma,
+ tx_buffer->length,
+ DMA_TO_DEVICE);
}
- buffer_info->time_stamp = 0;
- buffer_info->length = 0;
- buffer_info->next_to_watch = 0;
- buffer_info->mapped_as_page = false;
+ tx_buffer->next_to_watch = NULL;
+ tx_buffer->skb = NULL;
+ tx_buffer->dma = 0;
+ /* buffer_info must be completely set up in the transmit path */
}
/**
@@ -3176,21 +3191,21 @@ void igb_unmap_and_free_tx_resource(struct igb_ring *tx_ring,
**/
static void igb_clean_tx_ring(struct igb_ring *tx_ring)
{
- struct igb_buffer *buffer_info;
+ struct igb_tx_buffer *buffer_info;
unsigned long size;
- unsigned int i;
+ u16 i;
- if (!tx_ring->buffer_info)
+ if (!tx_ring->tx_buffer_info)
return;
/* Free all the Tx ring sk_buffs */
for (i = 0; i < tx_ring->count; i++) {
- buffer_info = &tx_ring->buffer_info[i];
+ buffer_info = &tx_ring->tx_buffer_info[i];
igb_unmap_and_free_tx_resource(tx_ring, buffer_info);
}
- size = sizeof(struct igb_buffer) * tx_ring->count;
- memset(tx_ring->buffer_info, 0, size);
+ size = sizeof(struct igb_tx_buffer) * tx_ring->count;
+ memset(tx_ring->tx_buffer_info, 0, size);
/* Zero out the descriptor ring */
memset(tx_ring->desc, 0, tx_ring->size);
@@ -3221,8 +3236,8 @@ void igb_free_rx_resources(struct igb_ring *rx_ring)
{
igb_clean_rx_ring(rx_ring);
- vfree(rx_ring->buffer_info);
- rx_ring->buffer_info = NULL;
+ vfree(rx_ring->rx_buffer_info);
+ rx_ring->rx_buffer_info = NULL;
/* if not set, then don't free */
if (!rx_ring->desc)
@@ -3254,20 +3269,19 @@ static void igb_free_all_rx_resources(struct igb_adapter *adapter)
**/
static void igb_clean_rx_ring(struct igb_ring *rx_ring)
{
- struct igb_buffer *buffer_info;
unsigned long size;
- unsigned int i;
+ u16 i;
- if (!rx_ring->buffer_info)
+ if (!rx_ring->rx_buffer_info)
return;
/* Free all the Rx ring sk_buffs */
for (i = 0; i < rx_ring->count; i++) {
- buffer_info = &rx_ring->buffer_info[i];
+ struct igb_rx_buffer *buffer_info = &rx_ring->rx_buffer_info[i];
if (buffer_info->dma) {
dma_unmap_single(rx_ring->dev,
buffer_info->dma,
- rx_ring->rx_buffer_len,
+ IGB_RX_HDR_LEN,
DMA_FROM_DEVICE);
buffer_info->dma = 0;
}
@@ -3290,8 +3304,8 @@ static void igb_clean_rx_ring(struct igb_ring *rx_ring)
}
}
- size = sizeof(struct igb_buffer) * rx_ring->count;
- memset(rx_ring->buffer_info, 0, size);
+ size = sizeof(struct igb_rx_buffer) * rx_ring->count;
+ memset(rx_ring->rx_buffer_info, 0, size);
/* Zero out the descriptor ring */
memset(rx_ring->desc, 0, rx_ring->size);
@@ -3713,16 +3727,14 @@ static void igb_watchdog_task(struct work_struct *work)
}
/* Force detection of hung controller every watchdog period */
- tx_ring->detect_tx_hung = true;
+ set_bit(IGB_RING_FLAG_TX_DETECT_HANG, &tx_ring->flags);
}
/* Cause software interrupt to ensure rx ring is cleaned */
if (adapter->msix_entries) {
u32 eics = 0;
- for (i = 0; i < adapter->num_q_vectors; i++) {
- struct igb_q_vector *q_vector = adapter->q_vector[i];
- eics |= q_vector->eims_value;
- }
+ for (i = 0; i < adapter->num_q_vectors; i++)
+ eics |= adapter->q_vector[i]->eims_value;
wr32(E1000_EICS, eics);
} else {
wr32(E1000_ICS, E1000_ICS_RXDMT0);
@@ -3764,33 +3776,24 @@ static void igb_update_ring_itr(struct igb_q_vector *q_vector)
int new_val = q_vector->itr_val;
int avg_wire_size = 0;
struct igb_adapter *adapter = q_vector->adapter;
- struct igb_ring *ring;
unsigned int packets;
/* For non-gigabit speeds, just fix the interrupt rate at 4000
* ints/sec - ITR timer value of 120 ticks.
*/
if (adapter->link_speed != SPEED_1000) {
- new_val = 976;
+ new_val = IGB_4K_ITR;
goto set_itr_val;
}
- ring = q_vector->rx_ring;
- if (ring) {
- packets = ACCESS_ONCE(ring->total_packets);
-
- if (packets)
- avg_wire_size = ring->total_bytes / packets;
- }
-
- ring = q_vector->tx_ring;
- if (ring) {
- packets = ACCESS_ONCE(ring->total_packets);
+ packets = q_vector->rx.total_packets;
+ if (packets)
+ avg_wire_size = q_vector->rx.total_bytes / packets;
- if (packets)
- avg_wire_size = max_t(u32, avg_wire_size,
- ring->total_bytes / packets);
- }
+ packets = q_vector->tx.total_packets;
+ if (packets)
+ avg_wire_size = max_t(u32, avg_wire_size,
+ q_vector->tx.total_bytes / packets);
/* if avg_wire_size isn't set no work was done */
if (!avg_wire_size)
@@ -3808,9 +3811,11 @@ static void igb_update_ring_itr(struct igb_q_vector *q_vector)
else
new_val = avg_wire_size / 2;
- /* when in itr mode 3 do not exceed 20K ints/sec */
- if (adapter->rx_itr_setting == 3 && new_val < 196)
- new_val = 196;
+ /* conservative mode (itr 3) eliminates the lowest_latency setting */
+ if (new_val < IGB_20K_ITR &&
+ ((q_vector->rx.ring && adapter->rx_itr_setting == 3) ||
+ (!q_vector->rx.ring && adapter->tx_itr_setting == 3)))
+ new_val = IGB_20K_ITR;
set_itr_val:
if (new_val != q_vector->itr_val) {
@@ -3818,14 +3823,10 @@ set_itr_val:
q_vector->set_itr = 1;
}
clear_counts:
- if (q_vector->rx_ring) {
- q_vector->rx_ring->total_bytes = 0;
- q_vector->rx_ring->total_packets = 0;
- }
- if (q_vector->tx_ring) {
- q_vector->tx_ring->total_bytes = 0;
- q_vector->tx_ring->total_packets = 0;
- }
+ q_vector->rx.total_bytes = 0;
+ q_vector->rx.total_packets = 0;
+ q_vector->tx.total_bytes = 0;
+ q_vector->tx.total_packets = 0;
}
/**
@@ -3841,106 +3842,102 @@ clear_counts:
* parameter (see igb_param.c)
* NOTE: These calculations are only valid when operating in a single-
* queue environment.
- * @adapter: pointer to adapter
- * @itr_setting: current q_vector->itr_val
- * @packets: the number of packets during this measurement interval
- * @bytes: the number of bytes during this measurement interval
+ * @q_vector: pointer to q_vector
+ * @ring_container: ring info to update the itr for
**/
-static unsigned int igb_update_itr(struct igb_adapter *adapter, u16 itr_setting,
- int packets, int bytes)
+static void igb_update_itr(struct igb_q_vector *q_vector,
+ struct igb_ring_container *ring_container)
{
- unsigned int retval = itr_setting;
+ unsigned int packets = ring_container->total_packets;
+ unsigned int bytes = ring_container->total_bytes;
+ u8 itrval = ring_container->itr;
+ /* no packets, exit with status unchanged */
if (packets == 0)
- goto update_itr_done;
+ return;
- switch (itr_setting) {
+ switch (itrval) {
case lowest_latency:
/* handle TSO and jumbo frames */
if (bytes/packets > 8000)
- retval = bulk_latency;
+ itrval = bulk_latency;
else if ((packets < 5) && (bytes > 512))
- retval = low_latency;
+ itrval = low_latency;
break;
case low_latency: /* 50 usec aka 20000 ints/s */
if (bytes > 10000) {
/* this if handles the TSO accounting */
if (bytes/packets > 8000) {
- retval = bulk_latency;
+ itrval = bulk_latency;
} else if ((packets < 10) || ((bytes/packets) > 1200)) {
- retval = bulk_latency;
+ itrval = bulk_latency;
} else if ((packets > 35)) {
- retval = lowest_latency;
+ itrval = lowest_latency;
}
} else if (bytes/packets > 2000) {
- retval = bulk_latency;
+ itrval = bulk_latency;
} else if (packets <= 2 && bytes < 512) {
- retval = lowest_latency;
+ itrval = lowest_latency;
}
break;
case bulk_latency: /* 250 usec aka 4000 ints/s */
if (bytes > 25000) {
if (packets > 35)
- retval = low_latency;
+ itrval = low_latency;
} else if (bytes < 1500) {
- retval = low_latency;
+ itrval = low_latency;
}
break;
}
-update_itr_done:
- return retval;
+ /* clear work counters since we have the values we need */
+ ring_container->total_bytes = 0;
+ ring_container->total_packets = 0;
+
+ /* write updated itr to ring container */
+ ring_container->itr = itrval;
}
-static void igb_set_itr(struct igb_adapter *adapter)
+static void igb_set_itr(struct igb_q_vector *q_vector)
{
- struct igb_q_vector *q_vector = adapter->q_vector[0];
- u16 current_itr;
+ struct igb_adapter *adapter = q_vector->adapter;
u32 new_itr = q_vector->itr_val;
+ u8 current_itr = 0;
/* for non-gigabit speeds, just fix the interrupt rate at 4000 */
if (adapter->link_speed != SPEED_1000) {
current_itr = 0;
- new_itr = 4000;
+ new_itr = IGB_4K_ITR;
goto set_itr_now;
}
- adapter->rx_itr = igb_update_itr(adapter,
- adapter->rx_itr,
- q_vector->rx_ring->total_packets,
- q_vector->rx_ring->total_bytes);
+ igb_update_itr(q_vector, &q_vector->tx);
+ igb_update_itr(q_vector, &q_vector->rx);
- adapter->tx_itr = igb_update_itr(adapter,
- adapter->tx_itr,
- q_vector->tx_ring->total_packets,
- q_vector->tx_ring->total_bytes);
- current_itr = max(adapter->rx_itr, adapter->tx_itr);
+ current_itr = max(q_vector->rx.itr, q_vector->tx.itr);
/* conservative mode (itr 3) eliminates the lowest_latency setting */
- if (adapter->rx_itr_setting == 3 && current_itr == lowest_latency)
+ if (current_itr == lowest_latency &&
+ ((q_vector->rx.ring && adapter->rx_itr_setting == 3) ||
+ (!q_vector->rx.ring && adapter->tx_itr_setting == 3)))
current_itr = low_latency;
switch (current_itr) {
/* counts and packets in update_itr are dependent on these numbers */
case lowest_latency:
- new_itr = 56; /* aka 70,000 ints/sec */
+ new_itr = IGB_70K_ITR; /* 70,000 ints/sec */
break;
case low_latency:
- new_itr = 196; /* aka 20,000 ints/sec */
+ new_itr = IGB_20K_ITR; /* 20,000 ints/sec */
break;
case bulk_latency:
- new_itr = 980; /* aka 4,000 ints/sec */
+ new_itr = IGB_4K_ITR; /* 4,000 ints/sec */
break;
default:
break;
}
set_itr_now:
- q_vector->rx_ring->total_bytes = 0;
- q_vector->rx_ring->total_packets = 0;
- q_vector->tx_ring->total_bytes = 0;
- q_vector->tx_ring->total_packets = 0;
-
if (new_itr != q_vector->itr_val) {
/* this attempts to bias the interrupt rate towards Bulk
* by adding intermediate steps when interrupt rate is
@@ -3948,7 +3945,7 @@ set_itr_now:
new_itr = new_itr > q_vector->itr_val ?
max((new_itr * q_vector->itr_val) /
(new_itr + (q_vector->itr_val >> 2)),
- new_itr) :
+ new_itr) :
new_itr;
/* Don't write the value here; it resets the adapter's
* internal timer, and causes us to delay far longer than
@@ -3961,35 +3958,51 @@ set_itr_now:
}
}
-#define IGB_TX_FLAGS_CSUM 0x00000001
-#define IGB_TX_FLAGS_VLAN 0x00000002
-#define IGB_TX_FLAGS_TSO 0x00000004
-#define IGB_TX_FLAGS_IPV4 0x00000008
-#define IGB_TX_FLAGS_TSTAMP 0x00000010
-#define IGB_TX_FLAGS_VLAN_MASK 0xffff0000
-#define IGB_TX_FLAGS_VLAN_SHIFT 16
-
-static inline int igb_tso_adv(struct igb_ring *tx_ring,
- struct sk_buff *skb, u32 tx_flags, u8 *hdr_len)
+void igb_tx_ctxtdesc(struct igb_ring *tx_ring, u32 vlan_macip_lens,
+ u32 type_tucmd, u32 mss_l4len_idx)
{
struct e1000_adv_tx_context_desc *context_desc;
- unsigned int i;
- int err;
- struct igb_buffer *buffer_info;
- u32 info = 0, tu_cmd = 0;
- u32 mss_l4len_idx;
- u8 l4len;
+ u16 i = tx_ring->next_to_use;
+
+ context_desc = IGB_TX_CTXTDESC(tx_ring, i);
+
+ i++;
+ tx_ring->next_to_use = (i < tx_ring->count) ? i : 0;
+
+ /* set bits to identify this as an advanced context descriptor */
+ type_tucmd |= E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT;
+
+ /* For 82575, context index must be unique per ring. */
+ if (test_bit(IGB_RING_FLAG_TX_CTX_IDX, &tx_ring->flags))
+ mss_l4len_idx |= tx_ring->reg_idx << 4;
+
+ context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens);
+ context_desc->seqnum_seed = 0;
+ context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd);
+ context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx);
+}
+
+static int igb_tso(struct igb_ring *tx_ring,
+ struct igb_tx_buffer *first,
+ u8 *hdr_len)
+{
+ struct sk_buff *skb = first->skb;
+ u32 vlan_macip_lens, type_tucmd;
+ u32 mss_l4len_idx, l4len;
+
+ if (!skb_is_gso(skb))
+ return 0;
if (skb_header_cloned(skb)) {
- err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+ int err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
if (err)
return err;
}
- l4len = tcp_hdrlen(skb);
- *hdr_len += l4len;
+ /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */
+ type_tucmd = E1000_ADVTXD_TUCMD_L4T_TCP;
- if (skb->protocol == htons(ETH_P_IP)) {
+ if (first->protocol == __constant_htons(ETH_P_IP)) {
struct iphdr *iph = ip_hdr(skb);
iph->tot_len = 0;
iph->check = 0;
@@ -3997,290 +4010,289 @@ static inline int igb_tso_adv(struct igb_ring *tx_ring,
iph->daddr, 0,
IPPROTO_TCP,
0);
+ type_tucmd |= E1000_ADVTXD_TUCMD_IPV4;
+ first->tx_flags |= IGB_TX_FLAGS_TSO |
+ IGB_TX_FLAGS_CSUM |
+ IGB_TX_FLAGS_IPV4;
} else if (skb_is_gso_v6(skb)) {
ipv6_hdr(skb)->payload_len = 0;
tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
&ipv6_hdr(skb)->daddr,
0, IPPROTO_TCP, 0);
+ first->tx_flags |= IGB_TX_FLAGS_TSO |
+ IGB_TX_FLAGS_CSUM;
}
- i = tx_ring->next_to_use;
-
- buffer_info = &tx_ring->buffer_info[i];
- context_desc = E1000_TX_CTXTDESC_ADV(*tx_ring, i);
- /* VLAN MACLEN IPLEN */
- if (tx_flags & IGB_TX_FLAGS_VLAN)
- info |= (tx_flags & IGB_TX_FLAGS_VLAN_MASK);
- info |= (skb_network_offset(skb) << E1000_ADVTXD_MACLEN_SHIFT);
- *hdr_len += skb_network_offset(skb);
- info |= skb_network_header_len(skb);
- *hdr_len += skb_network_header_len(skb);
- context_desc->vlan_macip_lens = cpu_to_le32(info);
-
- /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */
- tu_cmd |= (E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT);
-
- if (skb->protocol == htons(ETH_P_IP))
- tu_cmd |= E1000_ADVTXD_TUCMD_IPV4;
- tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
+ /* compute header lengths */
+ l4len = tcp_hdrlen(skb);
+ *hdr_len = skb_transport_offset(skb) + l4len;
- context_desc->type_tucmd_mlhl = cpu_to_le32(tu_cmd);
+ /* update gso size and bytecount with header size */
+ first->gso_segs = skb_shinfo(skb)->gso_segs;
+ first->bytecount += (first->gso_segs - 1) * *hdr_len;
/* MSS L4LEN IDX */
- mss_l4len_idx = (skb_shinfo(skb)->gso_size << E1000_ADVTXD_MSS_SHIFT);
- mss_l4len_idx |= (l4len << E1000_ADVTXD_L4LEN_SHIFT);
+ mss_l4len_idx = l4len << E1000_ADVTXD_L4LEN_SHIFT;
+ mss_l4len_idx |= skb_shinfo(skb)->gso_size << E1000_ADVTXD_MSS_SHIFT;
- /* For 82575, context index must be unique per ring. */
- if (tx_ring->flags & IGB_RING_FLAG_TX_CTX_IDX)
- mss_l4len_idx |= tx_ring->reg_idx << 4;
-
- context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx);
- context_desc->seqnum_seed = 0;
-
- buffer_info->time_stamp = jiffies;
- buffer_info->next_to_watch = i;
- buffer_info->dma = 0;
- i++;
- if (i == tx_ring->count)
- i = 0;
+ /* VLAN MACLEN IPLEN */
+ vlan_macip_lens = skb_network_header_len(skb);
+ vlan_macip_lens |= skb_network_offset(skb) << E1000_ADVTXD_MACLEN_SHIFT;
+ vlan_macip_lens |= first->tx_flags & IGB_TX_FLAGS_VLAN_MASK;
- tx_ring->next_to_use = i;
+ igb_tx_ctxtdesc(tx_ring, vlan_macip_lens, type_tucmd, mss_l4len_idx);
- return true;
+ return 1;
}
-static inline bool igb_tx_csum_adv(struct igb_ring *tx_ring,
- struct sk_buff *skb, u32 tx_flags)
+static void igb_tx_csum(struct igb_ring *tx_ring, struct igb_tx_buffer *first)
{
- struct e1000_adv_tx_context_desc *context_desc;
- struct device *dev = tx_ring->dev;
- struct igb_buffer *buffer_info;
- u32 info = 0, tu_cmd = 0;
- unsigned int i;
+ struct sk_buff *skb = first->skb;
+ u32 vlan_macip_lens = 0;
+ u32 mss_l4len_idx = 0;
+ u32 type_tucmd = 0;
- if ((skb->ip_summed == CHECKSUM_PARTIAL) ||
- (tx_flags & IGB_TX_FLAGS_VLAN)) {
- i = tx_ring->next_to_use;
- buffer_info = &tx_ring->buffer_info[i];
- context_desc = E1000_TX_CTXTDESC_ADV(*tx_ring, i);
+ if (skb->ip_summed != CHECKSUM_PARTIAL) {
+ if (!(first->tx_flags & IGB_TX_FLAGS_VLAN))
+ return;
+ } else {
+ u8 l4_hdr = 0;
+ switch (first->protocol) {
+ case __constant_htons(ETH_P_IP):
+ vlan_macip_lens |= skb_network_header_len(skb);
+ type_tucmd |= E1000_ADVTXD_TUCMD_IPV4;
+ l4_hdr = ip_hdr(skb)->protocol;
+ break;
+ case __constant_htons(ETH_P_IPV6):
+ vlan_macip_lens |= skb_network_header_len(skb);
+ l4_hdr = ipv6_hdr(skb)->nexthdr;
+ break;
+ default:
+ if (unlikely(net_ratelimit())) {
+ dev_warn(tx_ring->dev,
+ "partial checksum but proto=%x!\n",
+ first->protocol);
+ }
+ break;
+ }
- if (tx_flags & IGB_TX_FLAGS_VLAN)
- info |= (tx_flags & IGB_TX_FLAGS_VLAN_MASK);
+ switch (l4_hdr) {
+ case IPPROTO_TCP:
+ type_tucmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
+ mss_l4len_idx = tcp_hdrlen(skb) <<
+ E1000_ADVTXD_L4LEN_SHIFT;
+ break;
+ case IPPROTO_SCTP:
+ type_tucmd |= E1000_ADVTXD_TUCMD_L4T_SCTP;
+ mss_l4len_idx = sizeof(struct sctphdr) <<
+ E1000_ADVTXD_L4LEN_SHIFT;
+ break;
+ case IPPROTO_UDP:
+ mss_l4len_idx = sizeof(struct udphdr) <<
+ E1000_ADVTXD_L4LEN_SHIFT;
+ break;
+ default:
+ if (unlikely(net_ratelimit())) {
+ dev_warn(tx_ring->dev,
+ "partial checksum but l4 proto=%x!\n",
+ l4_hdr);
+ }
+ break;
+ }
- info |= (skb_network_offset(skb) << E1000_ADVTXD_MACLEN_SHIFT);
- if (skb->ip_summed == CHECKSUM_PARTIAL)
- info |= skb_network_header_len(skb);
+ /* update TX checksum flag */
+ first->tx_flags |= IGB_TX_FLAGS_CSUM;
+ }
- context_desc->vlan_macip_lens = cpu_to_le32(info);
+ vlan_macip_lens |= skb_network_offset(skb) << E1000_ADVTXD_MACLEN_SHIFT;
+ vlan_macip_lens |= first->tx_flags & IGB_TX_FLAGS_VLAN_MASK;
- tu_cmd |= (E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT);
+ igb_tx_ctxtdesc(tx_ring, vlan_macip_lens, type_tucmd, mss_l4len_idx);
+}
- if (skb->ip_summed == CHECKSUM_PARTIAL) {
- __be16 protocol;
+static __le32 igb_tx_cmd_type(u32 tx_flags)
+{
+ /* set type for advanced descriptor with frame checksum insertion */
+ __le32 cmd_type = cpu_to_le32(E1000_ADVTXD_DTYP_DATA |
+ E1000_ADVTXD_DCMD_IFCS |
+ E1000_ADVTXD_DCMD_DEXT);
- if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) {
- const struct vlan_ethhdr *vhdr =
- (const struct vlan_ethhdr*)skb->data;
+ /* set HW vlan bit if vlan is present */
+ if (tx_flags & IGB_TX_FLAGS_VLAN)
+ cmd_type |= cpu_to_le32(E1000_ADVTXD_DCMD_VLE);
- protocol = vhdr->h_vlan_encapsulated_proto;
- } else {
- protocol = skb->protocol;
- }
+ /* set timestamp bit if present */
+ if (tx_flags & IGB_TX_FLAGS_TSTAMP)
+ cmd_type |= cpu_to_le32(E1000_ADVTXD_MAC_TSTAMP);
- switch (protocol) {
- case cpu_to_be16(ETH_P_IP):
- tu_cmd |= E1000_ADVTXD_TUCMD_IPV4;
- if (ip_hdr(skb)->protocol == IPPROTO_TCP)
- tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
- else if (ip_hdr(skb)->protocol == IPPROTO_SCTP)
- tu_cmd |= E1000_ADVTXD_TUCMD_L4T_SCTP;
- break;
- case cpu_to_be16(ETH_P_IPV6):
- /* XXX what about other V6 headers?? */
- if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
- tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
- else if (ipv6_hdr(skb)->nexthdr == IPPROTO_SCTP)
- tu_cmd |= E1000_ADVTXD_TUCMD_L4T_SCTP;
- break;
- default:
- if (unlikely(net_ratelimit()))
- dev_warn(dev,
- "partial checksum but proto=%x!\n",
- skb->protocol);
- break;
- }
- }
+ /* set segmentation bits for TSO */
+ if (tx_flags & IGB_TX_FLAGS_TSO)
+ cmd_type |= cpu_to_le32(E1000_ADVTXD_DCMD_TSE);
- context_desc->type_tucmd_mlhl = cpu_to_le32(tu_cmd);
- context_desc->seqnum_seed = 0;
- if (tx_ring->flags & IGB_RING_FLAG_TX_CTX_IDX)
- context_desc->mss_l4len_idx =
- cpu_to_le32(tx_ring->reg_idx << 4);
+ return cmd_type;
+}
- buffer_info->time_stamp = jiffies;
- buffer_info->next_to_watch = i;
- buffer_info->dma = 0;
+static void igb_tx_olinfo_status(struct igb_ring *tx_ring,
+ union e1000_adv_tx_desc *tx_desc,
+ u32 tx_flags, unsigned int paylen)
+{
+ u32 olinfo_status = paylen << E1000_ADVTXD_PAYLEN_SHIFT;
- i++;
- if (i == tx_ring->count)
- i = 0;
- tx_ring->next_to_use = i;
+ /* 82575 requires a unique index per ring if any offload is enabled */
+ if ((tx_flags & (IGB_TX_FLAGS_CSUM | IGB_TX_FLAGS_VLAN)) &&
+ test_bit(IGB_RING_FLAG_TX_CTX_IDX, &tx_ring->flags))
+ olinfo_status |= tx_ring->reg_idx << 4;
- return true;
+ /* insert L4 checksum */
+ if (tx_flags & IGB_TX_FLAGS_CSUM) {
+ olinfo_status |= E1000_TXD_POPTS_TXSM << 8;
+
+ /* insert IPv4 checksum */
+ if (tx_flags & IGB_TX_FLAGS_IPV4)
+ olinfo_status |= E1000_TXD_POPTS_IXSM << 8;
}
- return false;
+
+ tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
}
-#define IGB_MAX_TXD_PWR 16
+/*
+ * The largest size we can write to the descriptor is 65535. In order to
+ * maintain a power of two alignment we have to limit ourselves to 32K.
+ */
+#define IGB_MAX_TXD_PWR 15
#define IGB_MAX_DATA_PER_TXD (1<<IGB_MAX_TXD_PWR)
-static inline int igb_tx_map_adv(struct igb_ring *tx_ring, struct sk_buff *skb,
- unsigned int first)
+static void igb_tx_map(struct igb_ring *tx_ring,
+ struct igb_tx_buffer *first,
+ const u8 hdr_len)
{
- struct igb_buffer *buffer_info;
- struct device *dev = tx_ring->dev;
- unsigned int hlen = skb_headlen(skb);
- unsigned int count = 0, i;
- unsigned int f;
- u16 gso_segs = skb_shinfo(skb)->gso_segs ?: 1;
-
- i = tx_ring->next_to_use;
-
- buffer_info = &tx_ring->buffer_info[i];
- BUG_ON(hlen >= IGB_MAX_DATA_PER_TXD);
- buffer_info->length = hlen;
- /* set time_stamp *before* dma to help avoid a possible race */
- buffer_info->time_stamp = jiffies;
- buffer_info->next_to_watch = i;
- buffer_info->dma = dma_map_single(dev, skb->data, hlen,
- DMA_TO_DEVICE);
- if (dma_mapping_error(dev, buffer_info->dma))
+ struct sk_buff *skb = first->skb;
+ struct igb_tx_buffer *tx_buffer_info;
+ union e1000_adv_tx_desc *tx_desc;
+ dma_addr_t dma;
+ struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0];
+ unsigned int data_len = skb->data_len;
+ unsigned int size = skb_headlen(skb);
+ unsigned int paylen = skb->len - hdr_len;
+ __le32 cmd_type;
+ u32 tx_flags = first->tx_flags;
+ u16 i = tx_ring->next_to_use;
+
+ tx_desc = IGB_TX_DESC(tx_ring, i);
+
+ igb_tx_olinfo_status(tx_ring, tx_desc, tx_flags, paylen);
+ cmd_type = igb_tx_cmd_type(tx_flags);
+
+ dma = dma_map_single(tx_ring->dev, skb->data, size, DMA_TO_DEVICE);
+ if (dma_mapping_error(tx_ring->dev, dma))
goto dma_error;
- for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
- struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[f];
- unsigned int len = frag->size;
+ /* record length, and DMA address */
+ first->length = size;
+ first->dma = dma;
+ tx_desc->read.buffer_addr = cpu_to_le64(dma);
- count++;
- i++;
- if (i == tx_ring->count)
- i = 0;
+ for (;;) {
+ while (unlikely(size > IGB_MAX_DATA_PER_TXD)) {
+ tx_desc->read.cmd_type_len =
+ cmd_type | cpu_to_le32(IGB_MAX_DATA_PER_TXD);
- buffer_info = &tx_ring->buffer_info[i];
- BUG_ON(len >= IGB_MAX_DATA_PER_TXD);
- buffer_info->length = len;
- buffer_info->time_stamp = jiffies;
- buffer_info->next_to_watch = i;
- buffer_info->mapped_as_page = true;
- buffer_info->dma = dma_map_page(dev,
- frag->page,
- frag->page_offset,
- len,
- DMA_TO_DEVICE);
- if (dma_mapping_error(dev, buffer_info->dma))
- goto dma_error;
-
- }
-
- tx_ring->buffer_info[i].skb = skb;
- tx_ring->buffer_info[i].tx_flags = skb_shinfo(skb)->tx_flags;
- /* multiply data chunks by size of headers */
- tx_ring->buffer_info[i].bytecount = ((gso_segs - 1) * hlen) + skb->len;
- tx_ring->buffer_info[i].gso_segs = gso_segs;
- tx_ring->buffer_info[first].next_to_watch = i;
-
- return ++count;
-
-dma_error:
- dev_err(dev, "TX DMA map failed\n");
+ i++;
+ tx_desc++;
+ if (i == tx_ring->count) {
+ tx_desc = IGB_TX_DESC(tx_ring, 0);
+ i = 0;
+ }
- /* clear timestamp and dma mappings for failed buffer_info mapping */
- buffer_info->dma = 0;
- buffer_info->time_stamp = 0;
- buffer_info->length = 0;
- buffer_info->next_to_watch = 0;
- buffer_info->mapped_as_page = false;
+ dma += IGB_MAX_DATA_PER_TXD;
+ size -= IGB_MAX_DATA_PER_TXD;
- /* clear timestamp and dma mappings for remaining portion of packet */
- while (count--) {
- if (i == 0)
- i = tx_ring->count;
- i--;
- buffer_info = &tx_ring->buffer_info[i];
- igb_unmap_and_free_tx_resource(tx_ring, buffer_info);
- }
-
- return 0;
-}
+ tx_desc->read.olinfo_status = 0;
+ tx_desc->read.buffer_addr = cpu_to_le64(dma);
+ }
-static inline void igb_tx_queue_adv(struct igb_ring *tx_ring,
- u32 tx_flags, int count, u32 paylen,
- u8 hdr_len)
-{
- union e1000_adv_tx_desc *tx_desc;
- struct igb_buffer *buffer_info;
- u32 olinfo_status = 0, cmd_type_len;
- unsigned int i = tx_ring->next_to_use;
+ if (likely(!data_len))
+ break;
- cmd_type_len = (E1000_ADVTXD_DTYP_DATA | E1000_ADVTXD_DCMD_IFCS |
- E1000_ADVTXD_DCMD_DEXT);
+ tx_desc->read.cmd_type_len = cmd_type | cpu_to_le32(size);
- if (tx_flags & IGB_TX_FLAGS_VLAN)
- cmd_type_len |= E1000_ADVTXD_DCMD_VLE;
+ i++;
+ tx_desc++;
+ if (i == tx_ring->count) {
+ tx_desc = IGB_TX_DESC(tx_ring, 0);
+ i = 0;
+ }
- if (tx_flags & IGB_TX_FLAGS_TSTAMP)
- cmd_type_len |= E1000_ADVTXD_MAC_TSTAMP;
+ size = skb_frag_size(frag);
+ data_len -= size;
- if (tx_flags & IGB_TX_FLAGS_TSO) {
- cmd_type_len |= E1000_ADVTXD_DCMD_TSE;
+ dma = skb_frag_dma_map(tx_ring->dev, frag, 0,
+ size, DMA_TO_DEVICE);
+ if (dma_mapping_error(tx_ring->dev, dma))
+ goto dma_error;
- /* insert tcp checksum */
- olinfo_status |= E1000_TXD_POPTS_TXSM << 8;
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ tx_buffer_info->length = size;
+ tx_buffer_info->dma = dma;
- /* insert ip checksum */
- if (tx_flags & IGB_TX_FLAGS_IPV4)
- olinfo_status |= E1000_TXD_POPTS_IXSM << 8;
+ tx_desc->read.olinfo_status = 0;
+ tx_desc->read.buffer_addr = cpu_to_le64(dma);
- } else if (tx_flags & IGB_TX_FLAGS_CSUM) {
- olinfo_status |= E1000_TXD_POPTS_TXSM << 8;
+ frag++;
}
- if ((tx_ring->flags & IGB_RING_FLAG_TX_CTX_IDX) &&
- (tx_flags & (IGB_TX_FLAGS_CSUM |
- IGB_TX_FLAGS_TSO |
- IGB_TX_FLAGS_VLAN)))
- olinfo_status |= tx_ring->reg_idx << 4;
+ /* write last descriptor with RS and EOP bits */
+ cmd_type |= cpu_to_le32(size) | cpu_to_le32(IGB_TXD_DCMD);
+ tx_desc->read.cmd_type_len = cmd_type;
- olinfo_status |= ((paylen - hdr_len) << E1000_ADVTXD_PAYLEN_SHIFT);
+ /* set the timestamp */
+ first->time_stamp = jiffies;
- do {
- buffer_info = &tx_ring->buffer_info[i];
- tx_desc = E1000_TX_DESC_ADV(*tx_ring, i);
- tx_desc->read.buffer_addr = cpu_to_le64(buffer_info->dma);
- tx_desc->read.cmd_type_len =
- cpu_to_le32(cmd_type_len | buffer_info->length);
- tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
- count--;
- i++;
- if (i == tx_ring->count)
- i = 0;
- } while (count > 0);
-
- tx_desc->read.cmd_type_len |= cpu_to_le32(IGB_ADVTXD_DCMD);
- /* Force memory writes to complete before letting h/w
- * know there are new descriptors to fetch. (Only
- * applicable for weak-ordered memory model archs,
- * such as IA-64). */
+ /*
+ * Force memory writes to complete before letting h/w know there
+ * are new descriptors to fetch. (Only applicable for weak-ordered
+ * memory model archs, such as IA-64).
+ *
+ * We also need this memory barrier to make certain all of the
+ * status bits have been updated before next_to_watch is written.
+ */
wmb();
+ /* set next_to_watch value indicating a packet is present */
+ first->next_to_watch = tx_desc;
+
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+
tx_ring->next_to_use = i;
+
writel(i, tx_ring->tail);
+
/* we need this if more than one processor can write to our tail
* at a time, it syncronizes IO on IA64/Altix systems */
mmiowb();
+
+ return;
+
+dma_error:
+ dev_err(tx_ring->dev, "TX DMA map failed\n");
+
+ /* clear dma mappings for failed tx_buffer_info map */
+ for (;;) {
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ igb_unmap_and_free_tx_resource(tx_ring, tx_buffer_info);
+ if (tx_buffer_info == first)
+ break;
+ if (i == 0)
+ i = tx_ring->count;
+ i--;
+ }
+
+ tx_ring->next_to_use = i;
}
-static int __igb_maybe_stop_tx(struct igb_ring *tx_ring, int size)
+static int __igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size)
{
struct net_device *netdev = tx_ring->netdev;
@@ -4306,19 +4318,20 @@ static int __igb_maybe_stop_tx(struct igb_ring *tx_ring, int size)
return 0;
}
-static inline int igb_maybe_stop_tx(struct igb_ring *tx_ring, int size)
+static inline int igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size)
{
if (igb_desc_unused(tx_ring) >= size)
return 0;
return __igb_maybe_stop_tx(tx_ring, size);
}
-netdev_tx_t igb_xmit_frame_ring_adv(struct sk_buff *skb,
- struct igb_ring *tx_ring)
+netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
+ struct igb_ring *tx_ring)
{
- int tso = 0, count;
+ struct igb_tx_buffer *first;
+ int tso;
u32 tx_flags = 0;
- u16 first;
+ __be16 protocol = vlan_get_protocol(skb);
u8 hdr_len = 0;
/* need: 1 descriptor per page,
@@ -4331,6 +4344,12 @@ netdev_tx_t igb_xmit_frame_ring_adv(struct sk_buff *skb,
return NETDEV_TX_BUSY;
}
+ /* record the location of the first descriptor for this packet */
+ first = &tx_ring->tx_buffer_info[tx_ring->next_to_use];
+ first->skb = skb;
+ first->bytecount = skb->len;
+ first->gso_segs = 1;
+
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
tx_flags |= IGB_TX_FLAGS_TSTAMP;
@@ -4341,51 +4360,44 @@ netdev_tx_t igb_xmit_frame_ring_adv(struct sk_buff *skb,
tx_flags |= (vlan_tx_tag_get(skb) << IGB_TX_FLAGS_VLAN_SHIFT);
}
- if (skb->protocol == htons(ETH_P_IP))
- tx_flags |= IGB_TX_FLAGS_IPV4;
-
- first = tx_ring->next_to_use;
- if (skb_is_gso(skb)) {
- tso = igb_tso_adv(tx_ring, skb, tx_flags, &hdr_len);
-
- if (tso < 0) {
- dev_kfree_skb_any(skb);
- return NETDEV_TX_OK;
- }
- }
-
- if (tso)
- tx_flags |= IGB_TX_FLAGS_TSO;
- else if (igb_tx_csum_adv(tx_ring, skb, tx_flags) &&
- (skb->ip_summed == CHECKSUM_PARTIAL))
- tx_flags |= IGB_TX_FLAGS_CSUM;
+ /* record initial flags and protocol */
+ first->tx_flags = tx_flags;
+ first->protocol = protocol;
- /*
- * count reflects descriptors mapped, if 0 or less then mapping error
- * has occurred and we need to rewind the descriptor queue
- */
- count = igb_tx_map_adv(tx_ring, skb, first);
- if (!count) {
- dev_kfree_skb_any(skb);
- tx_ring->buffer_info[first].time_stamp = 0;
- tx_ring->next_to_use = first;
- return NETDEV_TX_OK;
- }
+ tso = igb_tso(tx_ring, first, &hdr_len);
+ if (tso < 0)
+ goto out_drop;
+ else if (!tso)
+ igb_tx_csum(tx_ring, first);
- igb_tx_queue_adv(tx_ring, tx_flags, count, skb->len, hdr_len);
+ igb_tx_map(tx_ring, first, hdr_len);
/* Make sure there is space in the ring for the next send. */
igb_maybe_stop_tx(tx_ring, MAX_SKB_FRAGS + 4);
return NETDEV_TX_OK;
+
+out_drop:
+ igb_unmap_and_free_tx_resource(tx_ring, first);
+
+ return NETDEV_TX_OK;
}
-static netdev_tx_t igb_xmit_frame_adv(struct sk_buff *skb,
- struct net_device *netdev)
+static inline struct igb_ring *igb_tx_queue_mapping(struct igb_adapter *adapter,
+ struct sk_buff *skb)
+{
+ unsigned int r_idx = skb->queue_mapping;
+
+ if (r_idx >= adapter->num_tx_queues)
+ r_idx = r_idx % adapter->num_tx_queues;
+
+ return adapter->tx_ring[r_idx];
+}
+
+static netdev_tx_t igb_xmit_frame(struct sk_buff *skb,
+ struct net_device *netdev)
{
struct igb_adapter *adapter = netdev_priv(netdev);
- struct igb_ring *tx_ring;
- int r_idx = 0;
if (test_bit(__IGB_DOWN, &adapter->state)) {
dev_kfree_skb_any(skb);
@@ -4397,14 +4409,17 @@ static netdev_tx_t igb_xmit_frame_adv(struct sk_buff *skb,
return NETDEV_TX_OK;
}
- r_idx = skb->queue_mapping & (IGB_ABS_MAX_TX_QUEUES - 1);
- tx_ring = adapter->multi_tx_table[r_idx];
+ /*
+ * The minimum packet size with TCTL.PSP set is 17 so pad the skb
+ * in order to meet this minimum size requirement.
+ */
+ if (skb->len < 17) {
+ if (skb_padto(skb, 17))
+ return NETDEV_TX_OK;
+ skb->len = 17;
+ }
- /* This goes back to the question of how to logically map a tx queue
- * to a flow. Right now, performance is impacted slightly negatively
- * if using multiple tx queues. If the stack breaks away from a
- * single qdisc implementation, we can look at this again. */
- return igb_xmit_frame_ring_adv(skb, tx_ring);
+ return igb_xmit_frame_ring(skb, igb_tx_queue_mapping(adapter, skb));
}
/**
@@ -4419,7 +4434,7 @@ static void igb_tx_timeout(struct net_device *netdev)
/* Do the reset outside of interrupt context */
adapter->tx_timeout_count++;
- if (hw->mac.type == e1000_82580)
+ if (hw->mac.type >= e1000_82580)
hw->dev_spec._82575.global_device_reset = true;
schedule_work(&adapter->reset_task);
@@ -4467,14 +4482,14 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct pci_dev *pdev = adapter->pdev;
- int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
- u32 rx_buffer_len, i;
+ int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
if ((new_mtu < 68) || (max_frame > MAX_JUMBO_FRAME_SIZE)) {
dev_err(&pdev->dev, "Invalid MTU setting\n");
return -EINVAL;
}
+#define MAX_STD_JUMBO_FRAME_SIZE 9238
if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) {
dev_err(&pdev->dev, "MTU > 9216 not supported.\n");
return -EINVAL;
@@ -4486,30 +4501,6 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu)
/* igb_down has a dependency on max_frame_size */
adapter->max_frame_size = max_frame;
- /* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN
- * means we reserve 2 more, this pushes us to allocate from the next
- * larger slab size.
- * i.e. RXBUFFER_2048 --> size-4096 slab
- */
-
- if (adapter->hw.mac.type == e1000_82580)
- max_frame += IGB_TS_HDR_LEN;
-
- if (max_frame <= IGB_RXBUFFER_1024)
- rx_buffer_len = IGB_RXBUFFER_1024;
- else if (max_frame <= MAXIMUM_ETHERNET_VLAN_SIZE)
- rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
- else
- rx_buffer_len = IGB_RXBUFFER_128;
-
- if ((max_frame == ETH_FRAME_LEN + ETH_FCS_LEN + IGB_TS_HDR_LEN) ||
- (max_frame == MAXIMUM_ETHERNET_VLAN_SIZE + IGB_TS_HDR_LEN))
- rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE + IGB_TS_HDR_LEN;
-
- if ((adapter->hw.mac.type == e1000_82580) &&
- (rx_buffer_len == IGB_RXBUFFER_128))
- rx_buffer_len += IGB_RXBUFFER_64;
-
if (netif_running(netdev))
igb_down(adapter);
@@ -4517,9 +4508,6 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu)
netdev->mtu, new_mtu);
netdev->mtu = new_mtu;
- for (i = 0; i < adapter->num_rx_queues; i++)
- adapter->rx_ring[i]->rx_buffer_len = rx_buffer_len;
-
if (netif_running(netdev))
igb_up(adapter);
else
@@ -4752,12 +4740,6 @@ static irqreturn_t igb_msix_other(int irq, void *data)
mod_timer(&adapter->watchdog_timer, jiffies + 1);
}
- if (adapter->vfs_allocated_count)
- wr32(E1000_IMS, E1000_IMS_LSC |
- E1000_IMS_VMMB |
- E1000_IMS_DOUTSYNC);
- else
- wr32(E1000_IMS, E1000_IMS_LSC | E1000_IMS_DOUTSYNC);
wr32(E1000_EIMS, adapter->eims_other);
return IRQ_HANDLED;
@@ -4777,7 +4759,7 @@ static void igb_write_itr(struct igb_q_vector *q_vector)
if (adapter->hw.mac.type == e1000_82575)
itr_val |= itr_val << 16;
else
- itr_val |= 0x8000000;
+ itr_val |= E1000_EITR_CNT_IGNR;
writel(itr_val, q_vector->itr_register);
q_vector->set_itr = 0;
@@ -4805,8 +4787,8 @@ static void igb_update_dca(struct igb_q_vector *q_vector)
if (q_vector->cpu == cpu)
goto out_no_update;
- if (q_vector->tx_ring) {
- int q = q_vector->tx_ring->reg_idx;
+ if (q_vector->tx.ring) {
+ int q = q_vector->tx.ring->reg_idx;
u32 dca_txctrl = rd32(E1000_DCA_TXCTRL(q));
if (hw->mac.type == e1000_82575) {
dca_txctrl &= ~E1000_DCA_TXCTRL_CPUID_MASK;
@@ -4819,8 +4801,8 @@ static void igb_update_dca(struct igb_q_vector *q_vector)
dca_txctrl |= E1000_DCA_TXCTRL_DESC_DCA_EN;
wr32(E1000_DCA_TXCTRL(q), dca_txctrl);
}
- if (q_vector->rx_ring) {
- int q = q_vector->rx_ring->reg_idx;
+ if (q_vector->rx.ring) {
+ int q = q_vector->rx.ring->reg_idx;
u32 dca_rxctrl = rd32(E1000_DCA_RXCTRL(q));
if (hw->mac.type == e1000_82575) {
dca_rxctrl &= ~E1000_DCA_RXCTRL_CPUID_MASK;
@@ -4904,6 +4886,109 @@ static int igb_notify_dca(struct notifier_block *nb, unsigned long event,
}
#endif /* CONFIG_IGB_DCA */
+#ifdef CONFIG_PCI_IOV
+static int igb_vf_configure(struct igb_adapter *adapter, int vf)
+{
+ unsigned char mac_addr[ETH_ALEN];
+ struct pci_dev *pdev = adapter->pdev;
+ struct e1000_hw *hw = &adapter->hw;
+ struct pci_dev *pvfdev;
+ unsigned int device_id;
+ u16 thisvf_devfn;
+
+ random_ether_addr(mac_addr);
+ igb_set_vf_mac(adapter, vf, mac_addr);
+
+ switch (adapter->hw.mac.type) {
+ case e1000_82576:
+ device_id = IGB_82576_VF_DEV_ID;
+ /* VF Stride for 82576 is 2 */
+ thisvf_devfn = (pdev->devfn + 0x80 + (vf << 1)) |
+ (pdev->devfn & 1);
+ break;
+ case e1000_i350:
+ device_id = IGB_I350_VF_DEV_ID;
+ /* VF Stride for I350 is 4 */
+ thisvf_devfn = (pdev->devfn + 0x80 + (vf << 2)) |
+ (pdev->devfn & 3);
+ break;
+ default:
+ device_id = 0;
+ thisvf_devfn = 0;
+ break;
+ }
+
+ pvfdev = pci_get_device(hw->vendor_id, device_id, NULL);
+ while (pvfdev) {
+ if (pvfdev->devfn == thisvf_devfn)
+ break;
+ pvfdev = pci_get_device(hw->vendor_id,
+ device_id, pvfdev);
+ }
+
+ if (pvfdev)
+ adapter->vf_data[vf].vfdev = pvfdev;
+ else
+ dev_err(&pdev->dev,
+ "Couldn't find pci dev ptr for VF %4.4x\n",
+ thisvf_devfn);
+ return pvfdev != NULL;
+}
+
+static int igb_find_enabled_vfs(struct igb_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct pci_dev *pdev = adapter->pdev;
+ struct pci_dev *pvfdev;
+ u16 vf_devfn = 0;
+ u16 vf_stride;
+ unsigned int device_id;
+ int vfs_found = 0;
+
+ switch (adapter->hw.mac.type) {
+ case e1000_82576:
+ device_id = IGB_82576_VF_DEV_ID;
+ /* VF Stride for 82576 is 2 */
+ vf_stride = 2;
+ break;
+ case e1000_i350:
+ device_id = IGB_I350_VF_DEV_ID;
+ /* VF Stride for I350 is 4 */
+ vf_stride = 4;
+ break;
+ default:
+ device_id = 0;
+ vf_stride = 0;
+ break;
+ }
+
+ vf_devfn = pdev->devfn + 0x80;
+ pvfdev = pci_get_device(hw->vendor_id, device_id, NULL);
+ while (pvfdev) {
+ if (pvfdev->devfn == vf_devfn)
+ vfs_found++;
+ vf_devfn += vf_stride;
+ pvfdev = pci_get_device(hw->vendor_id,
+ device_id, pvfdev);
+ }
+
+ return vfs_found;
+}
+
+static int igb_check_vf_assignment(struct igb_adapter *adapter)
+{
+ int i;
+ for (i = 0; i < adapter->vfs_allocated_count; i++) {
+ if (adapter->vf_data[i].vfdev) {
+ if (adapter->vf_data[i].vfdev->dev_flags &
+ PCI_DEV_FLAGS_ASSIGNED)
+ return true;
+ }
+ }
+ return false;
+}
+
+#endif
static void igb_ping_all_vfs(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
@@ -5101,7 +5186,6 @@ static s32 igb_vlvf_set(struct igb_adapter *adapter, u32 vid, bool add, u32 vf)
}
adapter->vf_data[vf].vlans_enabled++;
- return 0;
}
} else {
if (i < E1000_VLVF_ARRAY_SIZE) {
@@ -5464,16 +5548,14 @@ static irqreturn_t igb_intr(int irq, void *data)
/* Interrupt Auto-Mask...upon reading ICR, interrupts are masked. No
* need for the IMC write */
u32 icr = rd32(E1000_ICR);
- if (!icr)
- return IRQ_NONE; /* Not our interrupt */
-
- igb_write_itr(q_vector);
/* IMS will not auto-mask if INT_ASSERTED is not set, and if it is
* not set, then the adapter didn't send an interrupt */
if (!(icr & E1000_ICR_INT_ASSERTED))
return IRQ_NONE;
+ igb_write_itr(q_vector);
+
if (icr & E1000_ICR_DRSTA)
schedule_work(&adapter->reset_task);
@@ -5494,15 +5576,15 @@ static irqreturn_t igb_intr(int irq, void *data)
return IRQ_HANDLED;
}
-static inline void igb_ring_irq_enable(struct igb_q_vector *q_vector)
+void igb_ring_irq_enable(struct igb_q_vector *q_vector)
{
struct igb_adapter *adapter = q_vector->adapter;
struct e1000_hw *hw = &adapter->hw;
- if ((q_vector->rx_ring && (adapter->rx_itr_setting & 3)) ||
- (!q_vector->rx_ring && (adapter->tx_itr_setting & 3))) {
- if (!adapter->msix_entries)
- igb_set_itr(adapter);
+ if ((q_vector->rx.ring && (adapter->rx_itr_setting & 3)) ||
+ (!q_vector->rx.ring && (adapter->tx_itr_setting & 3))) {
+ if ((adapter->num_q_vectors == 1) && !adapter->vf_data)
+ igb_set_itr(q_vector);
else
igb_update_ring_itr(q_vector);
}
@@ -5525,28 +5607,27 @@ static int igb_poll(struct napi_struct *napi, int budget)
struct igb_q_vector *q_vector = container_of(napi,
struct igb_q_vector,
napi);
- int tx_clean_complete = 1, work_done = 0;
+ bool clean_complete = true;
#ifdef CONFIG_IGB_DCA
if (q_vector->adapter->flags & IGB_FLAG_DCA_ENABLED)
igb_update_dca(q_vector);
#endif
- if (q_vector->tx_ring)
- tx_clean_complete = igb_clean_tx_irq(q_vector);
+ if (q_vector->tx.ring)
+ clean_complete = igb_clean_tx_irq(q_vector);
- if (q_vector->rx_ring)
- igb_clean_rx_irq_adv(q_vector, &work_done, budget);
+ if (q_vector->rx.ring)
+ clean_complete &= igb_clean_rx_irq(q_vector, budget);
- if (!tx_clean_complete)
- work_done = budget;
+ /* If all work not completed, return budget and keep polling */
+ if (!clean_complete)
+ return budget;
/* If not enough Rx work done, exit the polling mode */
- if (work_done < budget) {
- napi_complete(napi);
- igb_ring_irq_enable(q_vector);
- }
+ napi_complete(napi);
+ igb_ring_irq_enable(q_vector);
- return work_done;
+ return 0;
}
/**
@@ -5568,7 +5649,7 @@ static void igb_systim_to_hwtstamp(struct igb_adapter *adapter,
* The 82580 starts with 1ns at bit 0 in RX/TXSTMPL, shift this up to
* 24 to match clock shift we setup earlier.
*/
- if (adapter->hw.mac.type == e1000_82580)
+ if (adapter->hw.mac.type >= e1000_82580)
regval <<= IGB_82580_TSYNC_SHIFT;
ns = timecounter_cyc2time(&adapter->clock, regval);
@@ -5581,13 +5662,14 @@ static void igb_systim_to_hwtstamp(struct igb_adapter *adapter,
/**
* igb_tx_hwtstamp - utility function which checks for TX time stamp
* @q_vector: pointer to q_vector containing needed info
- * @buffer: pointer to igb_buffer structure
+ * @buffer: pointer to igb_tx_buffer structure
*
* If we were asked to do hardware stamping and such a time stamp is
* available, then it must have been for this skb here because we only
* allow only one such packet into the queue.
*/
-static void igb_tx_hwtstamp(struct igb_q_vector *q_vector, struct igb_buffer *buffer_info)
+static void igb_tx_hwtstamp(struct igb_q_vector *q_vector,
+ struct igb_tx_buffer *buffer_info)
{
struct igb_adapter *adapter = q_vector->adapter;
struct e1000_hw *hw = &adapter->hw;
@@ -5595,7 +5677,7 @@ static void igb_tx_hwtstamp(struct igb_q_vector *q_vector, struct igb_buffer *bu
u64 regval;
/* if skb does not support hw timestamp or TX stamp not valid exit */
- if (likely(!(buffer_info->tx_flags & SKBTX_HW_TSTAMP)) ||
+ if (likely(!(buffer_info->tx_flags & IGB_TX_FLAGS_TSTAMP)) ||
!(rd32(E1000_TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID))
return;
@@ -5614,70 +5696,109 @@ static void igb_tx_hwtstamp(struct igb_q_vector *q_vector, struct igb_buffer *bu
static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
{
struct igb_adapter *adapter = q_vector->adapter;
- struct igb_ring *tx_ring = q_vector->tx_ring;
- struct net_device *netdev = tx_ring->netdev;
- struct e1000_hw *hw = &adapter->hw;
- struct igb_buffer *buffer_info;
+ struct igb_ring *tx_ring = q_vector->tx.ring;
+ struct igb_tx_buffer *tx_buffer;
union e1000_adv_tx_desc *tx_desc, *eop_desc;
unsigned int total_bytes = 0, total_packets = 0;
- unsigned int i, eop, count = 0;
- bool cleaned = false;
-
- i = tx_ring->next_to_clean;
- eop = tx_ring->buffer_info[i].next_to_watch;
- eop_desc = E1000_TX_DESC_ADV(*tx_ring, eop);
-
- while ((eop_desc->wb.status & cpu_to_le32(E1000_TXD_STAT_DD)) &&
- (count < tx_ring->count)) {
- rmb(); /* read buffer_info after eop_desc status */
- for (cleaned = false; !cleaned; count++) {
- tx_desc = E1000_TX_DESC_ADV(*tx_ring, i);
- buffer_info = &tx_ring->buffer_info[i];
- cleaned = (i == eop);
-
- if (buffer_info->skb) {
- total_bytes += buffer_info->bytecount;
- /* gso_segs is currently only valid for tcp */
- total_packets += buffer_info->gso_segs;
- igb_tx_hwtstamp(q_vector, buffer_info);
- }
+ unsigned int budget = q_vector->tx.work_limit;
+ unsigned int i = tx_ring->next_to_clean;
+
+ if (test_bit(__IGB_DOWN, &adapter->state))
+ return true;
+
+ tx_buffer = &tx_ring->tx_buffer_info[i];
+ tx_desc = IGB_TX_DESC(tx_ring, i);
+ i -= tx_ring->count;
- igb_unmap_and_free_tx_resource(tx_ring, buffer_info);
- tx_desc->wb.status = 0;
+ for (; budget; budget--) {
+ eop_desc = tx_buffer->next_to_watch;
+ /* prevent any other reads prior to eop_desc */
+ rmb();
+
+ /* if next_to_watch is not set then there is no work pending */
+ if (!eop_desc)
+ break;
+
+ /* if DD is not set pending work has not been completed */
+ if (!(eop_desc->wb.status & cpu_to_le32(E1000_TXD_STAT_DD)))
+ break;
+
+ /* clear next_to_watch to prevent false hangs */
+ tx_buffer->next_to_watch = NULL;
+
+ /* update the statistics for this packet */
+ total_bytes += tx_buffer->bytecount;
+ total_packets += tx_buffer->gso_segs;
+
+ /* retrieve hardware timestamp */
+ igb_tx_hwtstamp(q_vector, tx_buffer);
+
+ /* free the skb */
+ dev_kfree_skb_any(tx_buffer->skb);
+ tx_buffer->skb = NULL;
+
+ /* unmap skb header data */
+ dma_unmap_single(tx_ring->dev,
+ tx_buffer->dma,
+ tx_buffer->length,
+ DMA_TO_DEVICE);
+
+ /* clear last DMA location and unmap remaining buffers */
+ while (tx_desc != eop_desc) {
+ tx_buffer->dma = 0;
+
+ tx_buffer++;
+ tx_desc++;
i++;
- if (i == tx_ring->count)
- i = 0;
+ if (unlikely(!i)) {
+ i -= tx_ring->count;
+ tx_buffer = tx_ring->tx_buffer_info;
+ tx_desc = IGB_TX_DESC(tx_ring, 0);
+ }
+
+ /* unmap any remaining paged data */
+ if (tx_buffer->dma) {
+ dma_unmap_page(tx_ring->dev,
+ tx_buffer->dma,
+ tx_buffer->length,
+ DMA_TO_DEVICE);
+ }
+ }
+
+ /* clear last DMA location */
+ tx_buffer->dma = 0;
+
+ /* move us one more past the eop_desc for start of next pkt */
+ tx_buffer++;
+ tx_desc++;
+ i++;
+ if (unlikely(!i)) {
+ i -= tx_ring->count;
+ tx_buffer = tx_ring->tx_buffer_info;
+ tx_desc = IGB_TX_DESC(tx_ring, 0);
}
- eop = tx_ring->buffer_info[i].next_to_watch;
- eop_desc = E1000_TX_DESC_ADV(*tx_ring, eop);
}
+ i += tx_ring->count;
tx_ring->next_to_clean = i;
+ u64_stats_update_begin(&tx_ring->tx_syncp);
+ tx_ring->tx_stats.bytes += total_bytes;
+ tx_ring->tx_stats.packets += total_packets;
+ u64_stats_update_end(&tx_ring->tx_syncp);
+ q_vector->tx.total_bytes += total_bytes;
+ q_vector->tx.total_packets += total_packets;
- if (unlikely(count &&
- netif_carrier_ok(netdev) &&
- igb_desc_unused(tx_ring) >= IGB_TX_QUEUE_WAKE)) {
- /* Make sure that anybody stopping the queue after this
- * sees the new next_to_clean.
- */
- smp_mb();
- if (__netif_subqueue_stopped(netdev, tx_ring->queue_index) &&
- !(test_bit(__IGB_DOWN, &adapter->state))) {
- netif_wake_subqueue(netdev, tx_ring->queue_index);
+ if (test_bit(IGB_RING_FLAG_TX_DETECT_HANG, &tx_ring->flags)) {
+ struct e1000_hw *hw = &adapter->hw;
- u64_stats_update_begin(&tx_ring->tx_syncp);
- tx_ring->tx_stats.restart_queue++;
- u64_stats_update_end(&tx_ring->tx_syncp);
- }
- }
+ eop_desc = tx_buffer->next_to_watch;
- if (tx_ring->detect_tx_hung) {
/* Detect a transmit hang in hardware, this serializes the
* check with the clearing of time_stamp and movement of i */
- tx_ring->detect_tx_hung = false;
- if (tx_ring->buffer_info[i].time_stamp &&
- time_after(jiffies, tx_ring->buffer_info[i].time_stamp +
+ clear_bit(IGB_RING_FLAG_TX_DETECT_HANG, &tx_ring->flags);
+ if (eop_desc &&
+ time_after(jiffies, tx_buffer->time_stamp +
(adapter->tx_timeout_factor * HZ)) &&
!(rd32(E1000_STATUS) & E1000_STATUS_TXOFF)) {
@@ -5691,50 +5812,73 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
" next_to_clean <%x>\n"
"buffer_info[next_to_clean]\n"
" time_stamp <%lx>\n"
- " next_to_watch <%x>\n"
+ " next_to_watch <%p>\n"
" jiffies <%lx>\n"
" desc.status <%x>\n",
tx_ring->queue_index,
- readl(tx_ring->head),
+ rd32(E1000_TDH(tx_ring->reg_idx)),
readl(tx_ring->tail),
tx_ring->next_to_use,
tx_ring->next_to_clean,
- tx_ring->buffer_info[eop].time_stamp,
- eop,
+ tx_buffer->time_stamp,
+ eop_desc,
jiffies,
eop_desc->wb.status);
- netif_stop_subqueue(netdev, tx_ring->queue_index);
+ netif_stop_subqueue(tx_ring->netdev,
+ tx_ring->queue_index);
+
+ /* we are about to reset, no point in enabling stuff */
+ return true;
}
}
- tx_ring->total_bytes += total_bytes;
- tx_ring->total_packets += total_packets;
- u64_stats_update_begin(&tx_ring->tx_syncp);
- tx_ring->tx_stats.bytes += total_bytes;
- tx_ring->tx_stats.packets += total_packets;
- u64_stats_update_end(&tx_ring->tx_syncp);
- return count < tx_ring->count;
+
+ if (unlikely(total_packets &&
+ netif_carrier_ok(tx_ring->netdev) &&
+ igb_desc_unused(tx_ring) >= IGB_TX_QUEUE_WAKE)) {
+ /* Make sure that anybody stopping the queue after this
+ * sees the new next_to_clean.
+ */
+ smp_mb();
+ if (__netif_subqueue_stopped(tx_ring->netdev,
+ tx_ring->queue_index) &&
+ !(test_bit(__IGB_DOWN, &adapter->state))) {
+ netif_wake_subqueue(tx_ring->netdev,
+ tx_ring->queue_index);
+
+ u64_stats_update_begin(&tx_ring->tx_syncp);
+ tx_ring->tx_stats.restart_queue++;
+ u64_stats_update_end(&tx_ring->tx_syncp);
+ }
+ }
+
+ return !!budget;
}
-static inline void igb_rx_checksum_adv(struct igb_ring *ring,
- u32 status_err, struct sk_buff *skb)
+static inline void igb_rx_checksum(struct igb_ring *ring,
+ union e1000_adv_rx_desc *rx_desc,
+ struct sk_buff *skb)
{
skb_checksum_none_assert(skb);
- /* Ignore Checksum bit is set or checksum is disabled through ethtool */
- if (!(ring->flags & IGB_RING_FLAG_RX_CSUM) ||
- (status_err & E1000_RXD_STAT_IXSM))
+ /* Ignore Checksum bit is set */
+ if (igb_test_staterr(rx_desc, E1000_RXD_STAT_IXSM))
+ return;
+
+ /* Rx checksum disabled via ethtool */
+ if (!(ring->netdev->features & NETIF_F_RXCSUM))
return;
/* TCP/UDP checksum error bit is set */
- if (status_err &
- (E1000_RXDEXT_STATERR_TCPE | E1000_RXDEXT_STATERR_IPE)) {
+ if (igb_test_staterr(rx_desc,
+ E1000_RXDEXT_STATERR_TCPE |
+ E1000_RXDEXT_STATERR_IPE)) {
/*
* work around errata with sctp packets where the TCPE aka
* L4E bit is set incorrectly on 64 byte (60 byte w/o crc)
* packets, (aka let the stack check the crc32c)
*/
- if ((skb->len == 60) &&
- (ring->flags & IGB_RING_FLAG_RX_SCTP_CSUM)) {
+ if (!((skb->len == 60) &&
+ test_bit(IGB_RING_FLAG_RX_SCTP_CSUM, &ring->flags))) {
u64_stats_update_begin(&ring->rx_syncp);
ring->rx_stats.csum_err++;
u64_stats_update_end(&ring->rx_syncp);
@@ -5743,19 +5887,34 @@ static inline void igb_rx_checksum_adv(struct igb_ring *ring,
return;
}
/* It must be a TCP or UDP packet with a valid checksum */
- if (status_err & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS))
+ if (igb_test_staterr(rx_desc, E1000_RXD_STAT_TCPCS |
+ E1000_RXD_STAT_UDPCS))
skb->ip_summed = CHECKSUM_UNNECESSARY;
- dev_dbg(ring->dev, "cksum success: bits %08X\n", status_err);
+ dev_dbg(ring->dev, "cksum success: bits %08X\n",
+ le32_to_cpu(rx_desc->wb.upper.status_error));
+}
+
+static inline void igb_rx_hash(struct igb_ring *ring,
+ union e1000_adv_rx_desc *rx_desc,
+ struct sk_buff *skb)
+{
+ if (ring->netdev->features & NETIF_F_RXHASH)
+ skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);
}
-static void igb_rx_hwtstamp(struct igb_q_vector *q_vector, u32 staterr,
- struct sk_buff *skb)
+static void igb_rx_hwtstamp(struct igb_q_vector *q_vector,
+ union e1000_adv_rx_desc *rx_desc,
+ struct sk_buff *skb)
{
struct igb_adapter *adapter = q_vector->adapter;
struct e1000_hw *hw = &adapter->hw;
u64 regval;
+ if (!igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP |
+ E1000_RXDADV_STAT_TS))
+ return;
+
/*
* If this bit is set, then the RX registers contain the time stamp. No
* other packet will be time stamped until we read these registers, so
@@ -5767,7 +5926,7 @@ static void igb_rx_hwtstamp(struct igb_q_vector *q_vector, u32 staterr,
* If nothing went wrong, then it should have a shared tx_flags that we
* can turn into a skb_shared_hwtstamps.
*/
- if (staterr & E1000_RXDADV_STAT_TSIP) {
+ if (igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP)) {
u32 *stamp = (u32 *)skb->data;
regval = le32_to_cpu(*(stamp + 2));
regval |= (u64)le32_to_cpu(*(stamp + 3)) << 32;
@@ -5782,8 +5941,24 @@ static void igb_rx_hwtstamp(struct igb_q_vector *q_vector, u32 staterr,
igb_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), regval);
}
-static inline u16 igb_get_hlen(struct igb_ring *rx_ring,
- union e1000_adv_rx_desc *rx_desc)
+
+static void igb_rx_vlan(struct igb_ring *ring,
+ union e1000_adv_rx_desc *rx_desc,
+ struct sk_buff *skb)
+{
+ if (igb_test_staterr(rx_desc, E1000_RXD_STAT_VP)) {
+ u16 vid;
+ if (igb_test_staterr(rx_desc, E1000_RXDEXT_STATERR_LB) &&
+ test_bit(IGB_RING_FLAG_RX_LB_VLAN_BSWAP, &ring->flags))
+ vid = be16_to_cpu(rx_desc->wb.upper.vlan);
+ else
+ vid = le16_to_cpu(rx_desc->wb.upper.vlan);
+
+ __vlan_hwaccel_put_tag(skb, vid);
+ }
+}
+
+static inline u16 igb_get_hlen(union e1000_adv_rx_desc *rx_desc)
{
/* HW will not DMA in data larger than the given buffer, even if it
* parses the (NFS, of course) header to be larger. In that case, it
@@ -5791,247 +5966,244 @@ static inline u16 igb_get_hlen(struct igb_ring *rx_ring,
*/
u16 hlen = (le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info) &
E1000_RXDADV_HDRBUFLEN_MASK) >> E1000_RXDADV_HDRBUFLEN_SHIFT;
- if (hlen > rx_ring->rx_buffer_len)
- hlen = rx_ring->rx_buffer_len;
+ if (hlen > IGB_RX_HDR_LEN)
+ hlen = IGB_RX_HDR_LEN;
return hlen;
}
-static bool igb_clean_rx_irq_adv(struct igb_q_vector *q_vector,
- int *work_done, int budget)
+static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
{
- struct igb_ring *rx_ring = q_vector->rx_ring;
- struct net_device *netdev = rx_ring->netdev;
- struct device *dev = rx_ring->dev;
- union e1000_adv_rx_desc *rx_desc , *next_rxd;
- struct igb_buffer *buffer_info , *next_buffer;
- struct sk_buff *skb;
- bool cleaned = false;
- int cleaned_count = 0;
- int current_node = numa_node_id();
+ struct igb_ring *rx_ring = q_vector->rx.ring;
+ union e1000_adv_rx_desc *rx_desc;
+ const int current_node = numa_node_id();
unsigned int total_bytes = 0, total_packets = 0;
- unsigned int i;
- u32 staterr;
- u16 length;
+ u16 cleaned_count = igb_desc_unused(rx_ring);
+ u16 i = rx_ring->next_to_clean;
- i = rx_ring->next_to_clean;
- buffer_info = &rx_ring->buffer_info[i];
- rx_desc = E1000_RX_DESC_ADV(*rx_ring, i);
- staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+ rx_desc = IGB_RX_DESC(rx_ring, i);
- while (staterr & E1000_RXD_STAT_DD) {
- if (*work_done >= budget)
- break;
- (*work_done)++;
- rmb(); /* read descriptor and rx_buffer_info after status DD */
+ while (igb_test_staterr(rx_desc, E1000_RXD_STAT_DD)) {
+ struct igb_rx_buffer *buffer_info = &rx_ring->rx_buffer_info[i];
+ struct sk_buff *skb = buffer_info->skb;
+ union e1000_adv_rx_desc *next_rxd;
- skb = buffer_info->skb;
- prefetch(skb->data - NET_IP_ALIGN);
buffer_info->skb = NULL;
+ prefetch(skb->data);
i++;
if (i == rx_ring->count)
i = 0;
- next_rxd = E1000_RX_DESC_ADV(*rx_ring, i);
+ next_rxd = IGB_RX_DESC(rx_ring, i);
prefetch(next_rxd);
- next_buffer = &rx_ring->buffer_info[i];
- length = le16_to_cpu(rx_desc->wb.upper.length);
- cleaned = true;
- cleaned_count++;
+ /*
+ * This memory barrier is needed to keep us from reading
+ * any other fields out of the rx_desc until we know the
+ * RXD_STAT_DD bit is set
+ */
+ rmb();
- if (buffer_info->dma) {
- dma_unmap_single(dev, buffer_info->dma,
- rx_ring->rx_buffer_len,
+ if (!skb_is_nonlinear(skb)) {
+ __skb_put(skb, igb_get_hlen(rx_desc));
+ dma_unmap_single(rx_ring->dev, buffer_info->dma,
+ IGB_RX_HDR_LEN,
DMA_FROM_DEVICE);
buffer_info->dma = 0;
- if (rx_ring->rx_buffer_len >= IGB_RXBUFFER_1024) {
- skb_put(skb, length);
- goto send_up;
- }
- skb_put(skb, igb_get_hlen(rx_ring, rx_desc));
}
- if (length) {
- dma_unmap_page(dev, buffer_info->page_dma,
- PAGE_SIZE / 2, DMA_FROM_DEVICE);
- buffer_info->page_dma = 0;
+ if (rx_desc->wb.upper.length) {
+ u16 length = le16_to_cpu(rx_desc->wb.upper.length);
skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
buffer_info->page,
buffer_info->page_offset,
length);
+ skb->len += length;
+ skb->data_len += length;
+ skb->truesize += PAGE_SIZE / 2;
+
if ((page_count(buffer_info->page) != 1) ||
(page_to_nid(buffer_info->page) != current_node))
buffer_info->page = NULL;
else
get_page(buffer_info->page);
- skb->len += length;
- skb->data_len += length;
- skb->truesize += length;
+ dma_unmap_page(rx_ring->dev, buffer_info->page_dma,
+ PAGE_SIZE / 2, DMA_FROM_DEVICE);
+ buffer_info->page_dma = 0;
}
- if (!(staterr & E1000_RXD_STAT_EOP)) {
+ if (!igb_test_staterr(rx_desc, E1000_RXD_STAT_EOP)) {
+ struct igb_rx_buffer *next_buffer;
+ next_buffer = &rx_ring->rx_buffer_info[i];
buffer_info->skb = next_buffer->skb;
buffer_info->dma = next_buffer->dma;
next_buffer->skb = skb;
next_buffer->dma = 0;
goto next_desc;
}
-send_up:
- if (staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) {
- dev_kfree_skb_irq(skb);
+
+ if (igb_test_staterr(rx_desc,
+ E1000_RXDEXT_ERR_FRAME_ERR_MASK)) {
+ dev_kfree_skb_any(skb);
goto next_desc;
}
- if (staterr & (E1000_RXDADV_STAT_TSIP | E1000_RXDADV_STAT_TS))
- igb_rx_hwtstamp(q_vector, staterr, skb);
+ igb_rx_hwtstamp(q_vector, rx_desc, skb);
+ igb_rx_hash(rx_ring, rx_desc, skb);
+ igb_rx_checksum(rx_ring, rx_desc, skb);
+ igb_rx_vlan(rx_ring, rx_desc, skb);
+
total_bytes += skb->len;
total_packets++;
- igb_rx_checksum_adv(rx_ring, staterr, skb);
-
- skb->protocol = eth_type_trans(skb, netdev);
- skb_record_rx_queue(skb, rx_ring->queue_index);
-
- if (staterr & E1000_RXD_STAT_VP) {
- u16 vid = le16_to_cpu(rx_desc->wb.upper.vlan);
+ skb->protocol = eth_type_trans(skb, rx_ring->netdev);
- __vlan_hwaccel_put_tag(skb, vid);
- }
napi_gro_receive(&q_vector->napi, skb);
+ budget--;
next_desc:
- rx_desc->wb.upper.status_error = 0;
+ if (!budget)
+ break;
+ cleaned_count++;
/* return some buffers to hardware, one at a time is too slow */
if (cleaned_count >= IGB_RX_BUFFER_WRITE) {
- igb_alloc_rx_buffers_adv(rx_ring, cleaned_count);
+ igb_alloc_rx_buffers(rx_ring, cleaned_count);
cleaned_count = 0;
}
/* use prefetched values */
rx_desc = next_rxd;
- buffer_info = next_buffer;
- staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
}
rx_ring->next_to_clean = i;
- cleaned_count = igb_desc_unused(rx_ring);
-
- if (cleaned_count)
- igb_alloc_rx_buffers_adv(rx_ring, cleaned_count);
-
- rx_ring->total_packets += total_packets;
- rx_ring->total_bytes += total_bytes;
u64_stats_update_begin(&rx_ring->rx_syncp);
rx_ring->rx_stats.packets += total_packets;
rx_ring->rx_stats.bytes += total_bytes;
u64_stats_update_end(&rx_ring->rx_syncp);
- return cleaned;
+ q_vector->rx.total_packets += total_packets;
+ q_vector->rx.total_bytes += total_bytes;
+
+ if (cleaned_count)
+ igb_alloc_rx_buffers(rx_ring, cleaned_count);
+
+ return !!budget;
+}
+
+static bool igb_alloc_mapped_skb(struct igb_ring *rx_ring,
+ struct igb_rx_buffer *bi)
+{
+ struct sk_buff *skb = bi->skb;
+ dma_addr_t dma = bi->dma;
+
+ if (dma)
+ return true;
+
+ if (likely(!skb)) {
+ skb = netdev_alloc_skb_ip_align(rx_ring->netdev,
+ IGB_RX_HDR_LEN);
+ bi->skb = skb;
+ if (!skb) {
+ rx_ring->rx_stats.alloc_failed++;
+ return false;
+ }
+
+ /* initialize skb for ring */
+ skb_record_rx_queue(skb, rx_ring->queue_index);
+ }
+
+ dma = dma_map_single(rx_ring->dev, skb->data,
+ IGB_RX_HDR_LEN, DMA_FROM_DEVICE);
+
+ if (dma_mapping_error(rx_ring->dev, dma)) {
+ rx_ring->rx_stats.alloc_failed++;
+ return false;
+ }
+
+ bi->dma = dma;
+ return true;
+}
+
+static bool igb_alloc_mapped_page(struct igb_ring *rx_ring,
+ struct igb_rx_buffer *bi)
+{
+ struct page *page = bi->page;
+ dma_addr_t page_dma = bi->page_dma;
+ unsigned int page_offset = bi->page_offset ^ (PAGE_SIZE / 2);
+
+ if (page_dma)
+ return true;
+
+ if (!page) {
+ page = netdev_alloc_page(rx_ring->netdev);
+ bi->page = page;
+ if (unlikely(!page)) {
+ rx_ring->rx_stats.alloc_failed++;
+ return false;
+ }
+ }
+
+ page_dma = dma_map_page(rx_ring->dev, page,
+ page_offset, PAGE_SIZE / 2,
+ DMA_FROM_DEVICE);
+
+ if (dma_mapping_error(rx_ring->dev, page_dma)) {
+ rx_ring->rx_stats.alloc_failed++;
+ return false;
+ }
+
+ bi->page_dma = page_dma;
+ bi->page_offset = page_offset;
+ return true;
}
/**
- * igb_alloc_rx_buffers_adv - Replace used receive buffers; packet split
+ * igb_alloc_rx_buffers - Replace used receive buffers; packet split
* @adapter: address of board private structure
**/
-void igb_alloc_rx_buffers_adv(struct igb_ring *rx_ring, int cleaned_count)
+void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
{
- struct net_device *netdev = rx_ring->netdev;
union e1000_adv_rx_desc *rx_desc;
- struct igb_buffer *buffer_info;
- struct sk_buff *skb;
- unsigned int i;
- int bufsz;
+ struct igb_rx_buffer *bi;
+ u16 i = rx_ring->next_to_use;
- i = rx_ring->next_to_use;
- buffer_info = &rx_ring->buffer_info[i];
-
- bufsz = rx_ring->rx_buffer_len;
+ rx_desc = IGB_RX_DESC(rx_ring, i);
+ bi = &rx_ring->rx_buffer_info[i];
+ i -= rx_ring->count;
while (cleaned_count--) {
- rx_desc = E1000_RX_DESC_ADV(*rx_ring, i);
-
- if ((bufsz < IGB_RXBUFFER_1024) && !buffer_info->page_dma) {
- if (!buffer_info->page) {
- buffer_info->page = netdev_alloc_page(netdev);
- if (unlikely(!buffer_info->page)) {
- u64_stats_update_begin(&rx_ring->rx_syncp);
- rx_ring->rx_stats.alloc_failed++;
- u64_stats_update_end(&rx_ring->rx_syncp);
- goto no_buffers;
- }
- buffer_info->page_offset = 0;
- } else {
- buffer_info->page_offset ^= PAGE_SIZE / 2;
- }
- buffer_info->page_dma =
- dma_map_page(rx_ring->dev, buffer_info->page,
- buffer_info->page_offset,
- PAGE_SIZE / 2,
- DMA_FROM_DEVICE);
- if (dma_mapping_error(rx_ring->dev,
- buffer_info->page_dma)) {
- buffer_info->page_dma = 0;
- u64_stats_update_begin(&rx_ring->rx_syncp);
- rx_ring->rx_stats.alloc_failed++;
- u64_stats_update_end(&rx_ring->rx_syncp);
- goto no_buffers;
- }
- }
+ if (!igb_alloc_mapped_skb(rx_ring, bi))
+ break;
- skb = buffer_info->skb;
- if (!skb) {
- skb = netdev_alloc_skb_ip_align(netdev, bufsz);
- if (unlikely(!skb)) {
- u64_stats_update_begin(&rx_ring->rx_syncp);
- rx_ring->rx_stats.alloc_failed++;
- u64_stats_update_end(&rx_ring->rx_syncp);
- goto no_buffers;
- }
+ /* Refresh the desc even if buffer_addrs didn't change
+ * because each write-back erases this info. */
+ rx_desc->read.hdr_addr = cpu_to_le64(bi->dma);
- buffer_info->skb = skb;
- }
- if (!buffer_info->dma) {
- buffer_info->dma = dma_map_single(rx_ring->dev,
- skb->data,
- bufsz,
- DMA_FROM_DEVICE);
- if (dma_mapping_error(rx_ring->dev,
- buffer_info->dma)) {
- buffer_info->dma = 0;
- u64_stats_update_begin(&rx_ring->rx_syncp);
- rx_ring->rx_stats.alloc_failed++;
- u64_stats_update_end(&rx_ring->rx_syncp);
- goto no_buffers;
- }
- }
- /* Refresh the desc even if buffer_addrs didn't change because
- * each write-back erases this info. */
- if (bufsz < IGB_RXBUFFER_1024) {
- rx_desc->read.pkt_addr =
- cpu_to_le64(buffer_info->page_dma);
- rx_desc->read.hdr_addr = cpu_to_le64(buffer_info->dma);
- } else {
- rx_desc->read.pkt_addr = cpu_to_le64(buffer_info->dma);
- rx_desc->read.hdr_addr = 0;
- }
+ if (!igb_alloc_mapped_page(rx_ring, bi))
+ break;
+
+ rx_desc->read.pkt_addr = cpu_to_le64(bi->page_dma);
+ rx_desc++;
+ bi++;
i++;
- if (i == rx_ring->count)
- i = 0;
- buffer_info = &rx_ring->buffer_info[i];
+ if (unlikely(!i)) {
+ rx_desc = IGB_RX_DESC(rx_ring, 0);
+ bi = rx_ring->rx_buffer_info;
+ i -= rx_ring->count;
+ }
+
+ /* clear the hdr_addr for the next_to_use descriptor */
+ rx_desc->read.hdr_addr = 0;
}
-no_buffers:
+ i += rx_ring->count;
+
if (rx_ring->next_to_use != i) {
rx_ring->next_to_use = i;
- if (i == 0)
- i = (rx_ring->count - 1);
- else
- i--;
/* Force memory writes to complete before letting h/w
* know there are new descriptors to fetch. (Only
@@ -6168,6 +6340,7 @@ static int igb_hwtstamp_ioctl(struct net_device *netdev,
tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_EVENT_V2;
config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
is_l2 = true;
+ is_l4 = true;
break;
default:
return -ERANGE;
@@ -6184,7 +6357,7 @@ static int igb_hwtstamp_ioctl(struct net_device *netdev,
* timestamped, so enable timestamping in all packets as
* long as one rx filter was configured.
*/
- if ((hw->mac.type == e1000_82580) && tsync_rx_ctl) {
+ if ((hw->mac.type >= e1000_82580) && tsync_rx_ctl) {
tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED;
tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL;
}
@@ -6299,10 +6472,9 @@ static void igb_vlan_mode(struct net_device *netdev, u32 features)
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
u32 ctrl, rctl;
+ bool enable = !!(features & NETIF_F_HW_VLAN_RX);
- igb_irq_disable(adapter);
-
- if (features & NETIF_F_HW_VLAN_RX) {
+ if (enable) {
/* enable VLAN tag insert/strip */
ctrl = rd32(E1000_CTRL);
ctrl |= E1000_CTRL_VME;
@@ -6320,9 +6492,6 @@ static void igb_vlan_mode(struct net_device *netdev, u32 features)
}
igb_rlpml_set(adapter);
-
- if (!test_bit(__IGB_DOWN, &adapter->state))
- igb_irq_enable(adapter);
}
static void igb_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
@@ -6347,11 +6516,6 @@ static void igb_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
int pf_id = adapter->vfs_allocated_count;
s32 err;
- igb_irq_disable(adapter);
-
- if (!test_bit(__IGB_DOWN, &adapter->state))
- igb_irq_enable(adapter);
-
/* remove vlan from VLVF table array */
err = igb_vlvf_set(adapter, vid, false, pf_id);
@@ -6366,6 +6530,8 @@ static void igb_restore_vlan(struct igb_adapter *adapter)
{
u16 vid;
+ igb_vlan_mode(adapter->netdev, adapter->netdev->features);
+
for_each_set_bit(vid, adapter->active_vlans, VLAN_N_VID)
igb_vlan_rx_add_vid(adapter->netdev, vid);
}
@@ -6577,18 +6743,15 @@ static void igb_netpoll(struct net_device *netdev)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
+ struct igb_q_vector *q_vector;
int i;
- if (!adapter->msix_entries) {
- struct igb_q_vector *q_vector = adapter->q_vector[0];
- igb_irq_disable(adapter);
- napi_schedule(&q_vector->napi);
- return;
- }
-
for (i = 0; i < adapter->num_q_vectors; i++) {
- struct igb_q_vector *q_vector = adapter->q_vector[i];
- wr32(E1000_EIMC, q_vector->eims_value);
+ q_vector = adapter->q_vector[i];
+ if (adapter->msix_entries)
+ wr32(E1000_EIMC, q_vector->eims_value);
+ else
+ igb_irq_disable(adapter);
napi_schedule(&q_vector->napi);
}
}
@@ -6887,4 +7050,70 @@ static void igb_vmm_control(struct igb_adapter *adapter)
}
}
+static void igb_init_dmac(struct igb_adapter *adapter, u32 pba)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 dmac_thr;
+ u16 hwm;
+
+ if (hw->mac.type > e1000_82580) {
+ if (adapter->flags & IGB_FLAG_DMAC) {
+ u32 reg;
+
+ /* force threshold to 0. */
+ wr32(E1000_DMCTXTH, 0);
+
+ /*
+ * DMA Coalescing high water mark needs to be higher
+ * than the RX threshold. set hwm to PBA - 2 * max
+ * frame size
+ */
+ hwm = pba - (2 * adapter->max_frame_size);
+ reg = rd32(E1000_DMACR);
+ reg &= ~E1000_DMACR_DMACTHR_MASK;
+ dmac_thr = pba - 4;
+
+ reg |= ((dmac_thr << E1000_DMACR_DMACTHR_SHIFT)
+ & E1000_DMACR_DMACTHR_MASK);
+
+ /* transition to L0x or L1 if available..*/
+ reg |= (E1000_DMACR_DMAC_EN | E1000_DMACR_DMAC_LX_MASK);
+
+ /* watchdog timer= +-1000 usec in 32usec intervals */
+ reg |= (1000 >> 5);
+ wr32(E1000_DMACR, reg);
+
+ /*
+ * no lower threshold to disable
+ * coalescing(smart fifb)-UTRESH=0
+ */
+ wr32(E1000_DMCRTRH, 0);
+ wr32(E1000_FCRTC, hwm);
+
+ reg = (IGB_DMCTLX_DCFLUSH_DIS | 0x4);
+
+ wr32(E1000_DMCTLX, reg);
+
+ /*
+ * free space in tx packet buffer to wake from
+ * DMA coal
+ */
+ wr32(E1000_DMCTXTH, (IGB_MIN_TXPBSIZE -
+ (IGB_TX_BUF_4096 + adapter->max_frame_size)) >> 6);
+
+ /*
+ * make low power state decision controlled
+ * by DMA coal
+ */
+ reg = rd32(E1000_PCIEMISC);
+ reg &= ~E1000_PCIEMISC_LX_DECISION;
+ wr32(E1000_PCIEMISC, reg);
+ } /* endif adapter->dmac is not disabled */
+ } else if (hw->mac.type == e1000_82580) {
+ u32 reg = rd32(E1000_PCIEMISC);
+ wr32(E1000_PCIEMISC, reg & ~E1000_PCIEMISC_LX_DECISION);
+ wr32(E1000_DMACR, 0);
+ }
+}
+
/* igb_main.c */
diff --git a/drivers/net/igbvf/Makefile b/drivers/net/ethernet/intel/igbvf/Makefile
index 0fa3db3dd8b6..0fa3db3dd8b6 100644
--- a/drivers/net/igbvf/Makefile
+++ b/drivers/net/ethernet/intel/igbvf/Makefile
diff --git a/drivers/net/igbvf/defines.h b/drivers/net/ethernet/intel/igbvf/defines.h
index 79f2604673fe..79f2604673fe 100644
--- a/drivers/net/igbvf/defines.h
+++ b/drivers/net/ethernet/intel/igbvf/defines.h
diff --git a/drivers/net/igbvf/ethtool.c b/drivers/net/ethernet/intel/igbvf/ethtool.c
index b0b14d63dfbf..2c25858cc0ff 100644
--- a/drivers/net/igbvf/ethtool.c
+++ b/drivers/net/ethernet/intel/igbvf/ethtool.c
@@ -128,55 +128,6 @@ static int igbvf_set_pauseparam(struct net_device *netdev,
return -EOPNOTSUPP;
}
-static u32 igbvf_get_rx_csum(struct net_device *netdev)
-{
- struct igbvf_adapter *adapter = netdev_priv(netdev);
- return !(adapter->flags & IGBVF_FLAG_RX_CSUM_DISABLED);
-}
-
-static int igbvf_set_rx_csum(struct net_device *netdev, u32 data)
-{
- struct igbvf_adapter *adapter = netdev_priv(netdev);
-
- if (data)
- adapter->flags &= ~IGBVF_FLAG_RX_CSUM_DISABLED;
- else
- adapter->flags |= IGBVF_FLAG_RX_CSUM_DISABLED;
-
- return 0;
-}
-
-static u32 igbvf_get_tx_csum(struct net_device *netdev)
-{
- return (netdev->features & NETIF_F_IP_CSUM) != 0;
-}
-
-static int igbvf_set_tx_csum(struct net_device *netdev, u32 data)
-{
- if (data)
- netdev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
- else
- netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
- return 0;
-}
-
-static int igbvf_set_tso(struct net_device *netdev, u32 data)
-{
- struct igbvf_adapter *adapter = netdev_priv(netdev);
-
- if (data) {
- netdev->features |= NETIF_F_TSO;
- netdev->features |= NETIF_F_TSO6;
- } else {
- netdev->features &= ~NETIF_F_TSO;
- netdev->features &= ~NETIF_F_TSO6;
- }
-
- dev_info(&adapter->pdev->dev, "TSO is %s\n",
- data ? "Enabled" : "Disabled");
- return 0;
-}
-
static u32 igbvf_get_msglevel(struct net_device *netdev)
{
struct igbvf_adapter *adapter = netdev_priv(netdev);
@@ -259,12 +210,8 @@ static void igbvf_get_ringparam(struct net_device *netdev,
ring->rx_max_pending = IGBVF_MAX_RXD;
ring->tx_max_pending = IGBVF_MAX_TXD;
- ring->rx_mini_max_pending = 0;
- ring->rx_jumbo_max_pending = 0;
ring->rx_pending = rx_ring->count;
ring->tx_pending = tx_ring->count;
- ring->rx_mini_pending = 0;
- ring->rx_jumbo_pending = 0;
}
static int igbvf_set_ringparam(struct net_device *netdev,
@@ -511,14 +458,6 @@ static const struct ethtool_ops igbvf_ethtool_ops = {
.set_ringparam = igbvf_set_ringparam,
.get_pauseparam = igbvf_get_pauseparam,
.set_pauseparam = igbvf_set_pauseparam,
- .get_rx_csum = igbvf_get_rx_csum,
- .set_rx_csum = igbvf_set_rx_csum,
- .get_tx_csum = igbvf_get_tx_csum,
- .set_tx_csum = igbvf_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
- .set_tso = igbvf_set_tso,
.self_test = igbvf_diag_test,
.get_sset_count = igbvf_get_sset_count,
.get_strings = igbvf_get_strings,
diff --git a/drivers/net/igbvf/igbvf.h b/drivers/net/ethernet/intel/igbvf/igbvf.h
index fd4a7b780fdd..fd4a7b780fdd 100644
--- a/drivers/net/igbvf/igbvf.h
+++ b/drivers/net/ethernet/intel/igbvf/igbvf.h
diff --git a/drivers/net/igbvf/mbx.c b/drivers/net/ethernet/intel/igbvf/mbx.c
index 3d6f4cc3998a..048aae248d06 100644
--- a/drivers/net/igbvf/mbx.c
+++ b/drivers/net/ethernet/intel/igbvf/mbx.c
@@ -288,7 +288,7 @@ out_no_write:
* @msg: The message buffer
* @size: Length of buffer
*
- * returns SUCCESS if it successfuly read message from buffer
+ * returns SUCCESS if it successfully read message from buffer
**/
static s32 e1000_read_mbx_vf(struct e1000_hw *hw, u32 *msg, u16 size)
{
diff --git a/drivers/net/igbvf/mbx.h b/drivers/net/ethernet/intel/igbvf/mbx.h
index c2883c45d477..c2883c45d477 100644
--- a/drivers/net/igbvf/mbx.h
+++ b/drivers/net/ethernet/intel/igbvf/mbx.h
diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c
index 40ed066e3ef4..cca78124be31 100644
--- a/drivers/net/igbvf/netdev.c
+++ b/drivers/net/ethernet/intel/igbvf/netdev.c
@@ -45,13 +45,13 @@
#include "igbvf.h"
-#define DRV_VERSION "2.0.0-k"
+#define DRV_VERSION "2.0.1-k"
char igbvf_driver_name[] = "igbvf";
const char igbvf_driver_version[] = DRV_VERSION;
static const char igbvf_driver_string[] =
- "Intel(R) Virtual Function Network Driver";
+ "Intel(R) Gigabit Virtual Function Network Driver";
static const char igbvf_copyright[] =
- "Copyright (c) 2009 - 2010 Intel Corporation.";
+ "Copyright (c) 2009 - 2011 Intel Corporation.";
static int igbvf_poll(struct napi_struct *napi, int budget);
static void igbvf_reset(struct igbvf_adapter *);
@@ -102,8 +102,8 @@ static void igbvf_receive_skb(struct igbvf_adapter *adapter,
{
if (status & E1000_RXD_STAT_VP) {
u16 vid = le16_to_cpu(vlan) & E1000_RXD_SPC_VLAN_MASK;
-
- __vlan_hwaccel_put_tag(skb, vid);
+ if (test_bit(vid, adapter->active_vlans))
+ __vlan_hwaccel_put_tag(skb, vid);
}
netif_receive_skb(skb);
}
@@ -312,7 +312,7 @@ static bool igbvf_clean_rx_irq(struct igbvf_adapter *adapter,
skb->len += length;
skb->data_len += length;
- skb->truesize += length;
+ skb->truesize += PAGE_SIZE / 2;
}
send_up:
i++;
@@ -2045,7 +2045,7 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter,
for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
- struct skb_frag_struct *frag;
+ const struct skb_frag_struct *frag;
count++;
i++;
@@ -2053,7 +2053,7 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter,
i = 0;
frag = &skb_shinfo(skb)->frags[f];
- len = frag->size;
+ len = skb_frag_size(frag);
buffer_info = &tx_ring->buffer_info[i];
BUG_ON(len >= IGBVF_MAX_DATA_PER_TXD);
@@ -2061,10 +2061,7 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter,
buffer_info->time_stamp = jiffies;
buffer_info->next_to_watch = i;
buffer_info->mapped_as_page = true;
- buffer_info->dma = dma_map_page(&pdev->dev,
- frag->page,
- frag->page_offset,
- len,
+ buffer_info->dma = skb_frag_dma_map(&pdev->dev, frag, 0, len,
DMA_TO_DEVICE);
if (dma_mapping_error(&pdev->dev, buffer_info->dma))
goto dma_error;
@@ -2528,9 +2525,23 @@ static void igbvf_print_device_info(struct igbvf_adapter *adapter)
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
- dev_info(&pdev->dev, "Intel(R) 82576 Virtual Function\n");
+ if (hw->mac.type == e1000_vfadapt_i350)
+ dev_info(&pdev->dev, "Intel(R) I350 Virtual Function\n");
+ else
+ dev_info(&pdev->dev, "Intel(R) 82576 Virtual Function\n");
dev_info(&pdev->dev, "Address: %pM\n", netdev->dev_addr);
- dev_info(&pdev->dev, "MAC: %d\n", hw->mac.type);
+}
+
+static int igbvf_set_features(struct net_device *netdev, u32 features)
+{
+ struct igbvf_adapter *adapter = netdev_priv(netdev);
+
+ if (features & NETIF_F_RXCSUM)
+ adapter->flags &= ~IGBVF_FLAG_RX_CSUM_DISABLED;
+ else
+ adapter->flags |= IGBVF_FLAG_RX_CSUM_DISABLED;
+
+ return 0;
}
static const struct net_device_ops igbvf_netdev_ops = {
@@ -2538,7 +2549,7 @@ static const struct net_device_ops igbvf_netdev_ops = {
.ndo_stop = igbvf_close,
.ndo_start_xmit = igbvf_xmit_frame,
.ndo_get_stats = igbvf_get_stats,
- .ndo_set_multicast_list = igbvf_set_multi,
+ .ndo_set_rx_mode = igbvf_set_multi,
.ndo_set_mac_address = igbvf_set_mac,
.ndo_change_mtu = igbvf_change_mtu,
.ndo_do_ioctl = igbvf_ioctl,
@@ -2548,6 +2559,7 @@ static const struct net_device_ops igbvf_netdev_ops = {
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = igbvf_netpoll,
#endif
+ .ndo_set_features = igbvf_set_features,
};
/**
@@ -2655,16 +2667,18 @@ static int __devinit igbvf_probe(struct pci_dev *pdev,
adapter->bd_number = cards_found++;
- netdev->features = NETIF_F_SG |
+ netdev->hw_features = NETIF_F_SG |
NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM |
+ NETIF_F_TSO |
+ NETIF_F_TSO6 |
+ NETIF_F_RXCSUM;
+
+ netdev->features = netdev->hw_features |
NETIF_F_HW_VLAN_TX |
NETIF_F_HW_VLAN_RX |
NETIF_F_HW_VLAN_FILTER;
- netdev->features |= NETIF_F_IPV6_CSUM;
- netdev->features |= NETIF_F_TSO;
- netdev->features |= NETIF_F_TSO6;
-
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
@@ -2852,7 +2866,7 @@ module_exit(igbvf_exit_module);
MODULE_AUTHOR("Intel Corporation, <e1000-devel@lists.sourceforge.net>");
-MODULE_DESCRIPTION("Intel(R) 82576 Virtual Function Network Driver");
+MODULE_DESCRIPTION("Intel(R) Gigabit Virtual Function Network Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/net/igbvf/regs.h b/drivers/net/ethernet/intel/igbvf/regs.h
index 77e18d3d6b15..77e18d3d6b15 100644
--- a/drivers/net/igbvf/regs.h
+++ b/drivers/net/ethernet/intel/igbvf/regs.h
diff --git a/drivers/net/igbvf/vf.c b/drivers/net/ethernet/intel/igbvf/vf.c
index af3822f9ea9a..af3822f9ea9a 100644
--- a/drivers/net/igbvf/vf.c
+++ b/drivers/net/ethernet/intel/igbvf/vf.c
diff --git a/drivers/net/igbvf/vf.h b/drivers/net/ethernet/intel/igbvf/vf.h
index d7ed58fcd9bb..d7ed58fcd9bb 100644
--- a/drivers/net/igbvf/vf.h
+++ b/drivers/net/ethernet/intel/igbvf/vf.h
diff --git a/drivers/net/ixgb/Makefile b/drivers/net/ethernet/intel/ixgb/Makefile
index 0b20c5e62ffe..0b20c5e62ffe 100644
--- a/drivers/net/ixgb/Makefile
+++ b/drivers/net/ethernet/intel/ixgb/Makefile
diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ethernet/intel/ixgb/ixgb.h
index 49e8408f05fc..cb23448fe2fa 100644
--- a/drivers/net/ixgb/ixgb.h
+++ b/drivers/net/ethernet/intel/ixgb/ixgb.h
@@ -204,6 +204,8 @@ extern void ixgb_set_ethtool_ops(struct net_device *netdev);
extern char ixgb_driver_name[];
extern const char ixgb_driver_version[];
+extern void ixgb_set_speed_duplex(struct net_device *netdev);
+
extern int ixgb_up(struct ixgb_adapter *adapter);
extern void ixgb_down(struct ixgb_adapter *adapter, bool kill_watchdog);
extern void ixgb_reset(struct ixgb_adapter *adapter);
diff --git a/drivers/net/ixgb/ixgb_ee.c b/drivers/net/ethernet/intel/ixgb/ixgb_ee.c
index 38b362b67857..2ed925f38811 100644
--- a/drivers/net/ixgb/ixgb_ee.c
+++ b/drivers/net/ethernet/intel/ixgb/ixgb_ee.c
@@ -559,7 +559,7 @@ ixgb_get_ee_mac_addr(struct ixgb_hw *hw,
ENTER();
if (ixgb_check_and_get_eeprom_data(hw) == true) {
- for (i = 0; i < IXGB_ETH_LENGTH_OF_ADDRESS; i++) {
+ for (i = 0; i < ETH_ALEN; i++) {
mac_addr[i] = ee_map->mac_addr[i];
}
pr_debug("eeprom mac address = %pM\n", mac_addr);
diff --git a/drivers/net/ixgb/ixgb_ee.h b/drivers/net/ethernet/intel/ixgb/ixgb_ee.h
index 7ea12652f471..5680f64314b8 100644
--- a/drivers/net/ixgb/ixgb_ee.h
+++ b/drivers/net/ethernet/intel/ixgb/ixgb_ee.h
@@ -31,8 +31,6 @@
#define IXGB_EEPROM_SIZE 64 /* Size in words */
-#define IXGB_ETH_LENGTH_OF_ADDRESS 6
-
/* EEPROM Commands */
#define EEPROM_READ_OPCODE 0x6 /* EEPROM read opcode */
#define EEPROM_WRITE_OPCODE 0x5 /* EEPROM write opcode */
@@ -75,7 +73,7 @@
/* EEPROM structure */
struct ixgb_ee_map_type {
- u8 mac_addr[IXGB_ETH_LENGTH_OF_ADDRESS];
+ u8 mac_addr[ETH_ALEN];
__le16 compatibility;
__le16 reserved1[4];
__le32 pba_number;
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ethernet/intel/ixgb/ixgb_ethtool.c
index 6da890b9534c..9dfce7dff79b 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ethernet/intel/ixgb/ixgb_ethtool.c
@@ -115,7 +115,7 @@ ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
return 0;
}
-static void ixgb_set_speed_duplex(struct net_device *netdev)
+void ixgb_set_speed_duplex(struct net_device *netdev)
{
struct ixgb_adapter *adapter = netdev_priv(netdev);
/* be optimistic about our link, since we were up before */
@@ -195,57 +195,6 @@ ixgb_set_pauseparam(struct net_device *netdev,
}
static u32
-ixgb_get_rx_csum(struct net_device *netdev)
-{
- struct ixgb_adapter *adapter = netdev_priv(netdev);
-
- return adapter->rx_csum;
-}
-
-static int
-ixgb_set_rx_csum(struct net_device *netdev, u32 data)
-{
- struct ixgb_adapter *adapter = netdev_priv(netdev);
-
- adapter->rx_csum = data;
-
- if (netif_running(netdev)) {
- ixgb_down(adapter, true);
- ixgb_up(adapter);
- ixgb_set_speed_duplex(netdev);
- } else
- ixgb_reset(adapter);
- return 0;
-}
-
-static u32
-ixgb_get_tx_csum(struct net_device *netdev)
-{
- return (netdev->features & NETIF_F_HW_CSUM) != 0;
-}
-
-static int
-ixgb_set_tx_csum(struct net_device *netdev, u32 data)
-{
- if (data)
- netdev->features |= NETIF_F_HW_CSUM;
- else
- netdev->features &= ~NETIF_F_HW_CSUM;
-
- return 0;
-}
-
-static int
-ixgb_set_tso(struct net_device *netdev, u32 data)
-{
- if (data)
- netdev->features |= NETIF_F_TSO;
- else
- netdev->features &= ~NETIF_F_TSO;
- return 0;
-}
-
-static u32
ixgb_get_msglevel(struct net_device *netdev)
{
struct ixgb_adapter *adapter = netdev_priv(netdev);
@@ -543,12 +492,8 @@ ixgb_get_ringparam(struct net_device *netdev,
ring->rx_max_pending = MAX_RXD;
ring->tx_max_pending = MAX_TXD;
- ring->rx_mini_max_pending = 0;
- ring->rx_jumbo_max_pending = 0;
ring->rx_pending = rxdr->count;
ring->tx_pending = txdr->count;
- ring->rx_mini_pending = 0;
- ring->rx_jumbo_pending = 0;
}
static int
@@ -685,43 +630,6 @@ ixgb_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
}
}
-static int ixgb_set_flags(struct net_device *netdev, u32 data)
-{
- struct ixgb_adapter *adapter = netdev_priv(netdev);
- bool need_reset;
- int rc;
-
- /*
- * Tx VLAN insertion does not work per HW design when Rx stripping is
- * disabled. Disable txvlan when rxvlan is turned off, and enable
- * rxvlan when txvlan is turned on.
- */
- if (!(data & ETH_FLAG_RXVLAN) &&
- (netdev->features & NETIF_F_HW_VLAN_TX))
- data &= ~ETH_FLAG_TXVLAN;
- else if (data & ETH_FLAG_TXVLAN)
- data |= ETH_FLAG_RXVLAN;
-
- need_reset = (data & ETH_FLAG_RXVLAN) !=
- (netdev->features & NETIF_F_HW_VLAN_RX);
-
- rc = ethtool_op_set_flags(netdev, data, ETH_FLAG_RXVLAN |
- ETH_FLAG_TXVLAN);
- if (rc)
- return rc;
-
- if (need_reset) {
- if (netif_running(netdev)) {
- ixgb_down(adapter, true);
- ixgb_up(adapter);
- ixgb_set_speed_duplex(netdev);
- } else
- ixgb_reset(adapter);
- }
-
- return 0;
-}
-
static const struct ethtool_ops ixgb_ethtool_ops = {
.get_settings = ixgb_get_settings,
.set_settings = ixgb_set_settings,
@@ -736,20 +644,12 @@ static const struct ethtool_ops ixgb_ethtool_ops = {
.set_ringparam = ixgb_set_ringparam,
.get_pauseparam = ixgb_get_pauseparam,
.set_pauseparam = ixgb_set_pauseparam,
- .get_rx_csum = ixgb_get_rx_csum,
- .set_rx_csum = ixgb_set_rx_csum,
- .get_tx_csum = ixgb_get_tx_csum,
- .set_tx_csum = ixgb_set_tx_csum,
- .set_sg = ethtool_op_set_sg,
.get_msglevel = ixgb_get_msglevel,
.set_msglevel = ixgb_set_msglevel,
- .set_tso = ixgb_set_tso,
.get_strings = ixgb_get_strings,
.set_phys_id = ixgb_set_phys_id,
.get_sset_count = ixgb_get_sset_count,
.get_ethtool_stats = ixgb_get_ethtool_stats,
- .get_flags = ethtool_op_get_flags,
- .set_flags = ixgb_set_flags,
};
void ixgb_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/ixgb/ixgb_hw.c b/drivers/net/ethernet/intel/ixgb/ixgb_hw.c
index 3d61a9e4faf7..99b69adb4a0f 100644
--- a/drivers/net/ixgb/ixgb_hw.c
+++ b/drivers/net/ethernet/intel/ixgb/ixgb_hw.c
@@ -478,7 +478,7 @@ ixgb_mc_addr_list_update(struct ixgb_hw *hw,
ixgb_mta_set(hw, hash_value);
}
- mca += IXGB_ETH_LENGTH_OF_ADDRESS + pad;
+ mca += ETH_ALEN + pad;
}
pr_debug("MC Update Complete\n");
diff --git a/drivers/net/ixgb/ixgb_hw.h b/drivers/net/ethernet/intel/ixgb/ixgb_hw.h
index 873d32b89fba..2a99a35c33aa 100644
--- a/drivers/net/ixgb/ixgb_hw.h
+++ b/drivers/net/ethernet/intel/ixgb/ixgb_hw.h
@@ -97,8 +97,6 @@ typedef enum {
ixgb_bus_width_64
} ixgb_bus_width;
-#define IXGB_ETH_LENGTH_OF_ADDRESS 6
-
#define IXGB_EEPROM_SIZE 64 /* Size in words */
#define SPEED_10000 10000
@@ -674,7 +672,7 @@ struct ixgb_hw {
u32 max_frame_size; /* Maximum frame size supported */
u32 mc_filter_type; /* Multicast filter hash type */
u32 num_mc_addrs; /* Number of current Multicast addrs */
- u8 curr_mac_addr[IXGB_ETH_LENGTH_OF_ADDRESS]; /* Individual address currently programmed in MAC */
+ u8 curr_mac_addr[ETH_ALEN]; /* Individual address currently programmed in MAC */
u32 num_tx_desc; /* Number of Transmit descriptors */
u32 num_rx_desc; /* Number of Receive descriptors */
u32 rx_buffer_size; /* Size of Receive buffer */
diff --git a/drivers/net/ixgb/ixgb_ids.h b/drivers/net/ethernet/intel/ixgb/ixgb_ids.h
index 2a58847f46e8..2a58847f46e8 100644
--- a/drivers/net/ixgb/ixgb_ids.h
+++ b/drivers/net/ethernet/intel/ixgb/ixgb_ids.h
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c
index 6a130eb51cfa..e21148f8b160 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c
@@ -325,12 +325,47 @@ ixgb_reset(struct ixgb_adapter *adapter)
}
}
+static u32
+ixgb_fix_features(struct net_device *netdev, u32 features)
+{
+ /*
+ * Tx VLAN insertion does not work per HW design when Rx stripping is
+ * disabled.
+ */
+ if (!(features & NETIF_F_HW_VLAN_RX))
+ features &= ~NETIF_F_HW_VLAN_TX;
+
+ return features;
+}
+
+static int
+ixgb_set_features(struct net_device *netdev, u32 features)
+{
+ struct ixgb_adapter *adapter = netdev_priv(netdev);
+ u32 changed = features ^ netdev->features;
+
+ if (!(changed & (NETIF_F_RXCSUM|NETIF_F_HW_VLAN_RX)))
+ return 0;
+
+ adapter->rx_csum = !!(features & NETIF_F_RXCSUM);
+
+ if (netif_running(netdev)) {
+ ixgb_down(adapter, true);
+ ixgb_up(adapter);
+ ixgb_set_speed_duplex(netdev);
+ } else
+ ixgb_reset(adapter);
+
+ return 0;
+}
+
+
static const struct net_device_ops ixgb_netdev_ops = {
.ndo_open = ixgb_open,
.ndo_stop = ixgb_close,
.ndo_start_xmit = ixgb_xmit_frame,
.ndo_get_stats = ixgb_get_stats,
- .ndo_set_multicast_list = ixgb_set_multi,
+ .ndo_set_rx_mode = ixgb_set_multi,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = ixgb_set_mac,
.ndo_change_mtu = ixgb_change_mtu,
@@ -340,6 +375,8 @@ static const struct net_device_ops ixgb_netdev_ops = {
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ixgb_netpoll,
#endif
+ .ndo_fix_features = ixgb_fix_features,
+ .ndo_set_features = ixgb_set_features,
};
/**
@@ -439,12 +476,14 @@ ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto err_sw_init;
- netdev->features = NETIF_F_SG |
+ netdev->hw_features = NETIF_F_SG |
+ NETIF_F_TSO |
NETIF_F_HW_CSUM |
NETIF_F_HW_VLAN_TX |
- NETIF_F_HW_VLAN_RX |
+ NETIF_F_HW_VLAN_RX;
+ netdev->features = netdev->hw_features |
NETIF_F_HW_VLAN_FILTER;
- netdev->features |= NETIF_F_TSO;
+ netdev->hw_features |= NETIF_F_RXCSUM;
if (pci_using_dac) {
netdev->features |= NETIF_F_HIGHDMA;
@@ -1068,7 +1107,6 @@ ixgb_set_multi(struct net_device *netdev)
struct ixgb_hw *hw = &adapter->hw;
struct netdev_hw_addr *ha;
u32 rctl;
- int i;
/* Check for Promiscuous and All Multicast modes */
@@ -1095,19 +1133,27 @@ ixgb_set_multi(struct net_device *netdev)
rctl |= IXGB_RCTL_MPE;
IXGB_WRITE_REG(hw, RCTL, rctl);
} else {
- u8 mta[IXGB_MAX_NUM_MULTICAST_ADDRESSES *
- IXGB_ETH_LENGTH_OF_ADDRESS];
+ u8 *mta = kmalloc(IXGB_MAX_NUM_MULTICAST_ADDRESSES *
+ ETH_ALEN, GFP_ATOMIC);
+ u8 *addr;
+ if (!mta) {
+ pr_err("allocation of multicast memory failed\n");
+ goto alloc_failed;
+ }
IXGB_WRITE_REG(hw, RCTL, rctl);
- i = 0;
- netdev_for_each_mc_addr(ha, netdev)
- memcpy(&mta[i++ * IXGB_ETH_LENGTH_OF_ADDRESS],
- ha->addr, IXGB_ETH_LENGTH_OF_ADDRESS);
+ addr = mta;
+ netdev_for_each_mc_addr(ha, netdev) {
+ memcpy(addr, ha->addr, ETH_ALEN);
+ addr += ETH_ALEN;
+ }
ixgb_mc_addr_list_update(hw, mta, netdev_mc_count(netdev), 0);
+ kfree(mta);
}
+alloc_failed:
if (netdev->features & NETIF_F_HW_VLAN_RX)
ixgb_vlan_strip_enable(adapter);
else
@@ -1337,11 +1383,11 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
}
for (f = 0; f < nr_frags; f++) {
- struct skb_frag_struct *frag;
+ const struct skb_frag_struct *frag;
frag = &skb_shinfo(skb)->frags[f];
- len = frag->size;
- offset = frag->page_offset;
+ len = skb_frag_size(frag);
+ offset = 0;
while (len) {
i++;
@@ -1361,8 +1407,8 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
buffer_info->time_stamp = jiffies;
buffer_info->mapped_as_page = true;
buffer_info->dma =
- dma_map_page(&pdev->dev, frag->page,
- offset, size, DMA_TO_DEVICE);
+ skb_frag_dma_map(&pdev->dev, frag, offset, size,
+ DMA_TO_DEVICE);
if (dma_mapping_error(&pdev->dev, buffer_info->dma))
goto dma_error;
buffer_info->next_to_watch = 0;
diff --git a/drivers/net/ixgb/ixgb_osdep.h b/drivers/net/ethernet/intel/ixgb/ixgb_osdep.h
index e361185920ef..8fc905192231 100644
--- a/drivers/net/ixgb/ixgb_osdep.h
+++ b/drivers/net/ethernet/intel/ixgb/ixgb_osdep.h
@@ -38,6 +38,7 @@
#include <asm/io.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
+#include <linux/if_ether.h>
#undef ASSERT
#define ASSERT(x) BUG_ON(!(x))
diff --git a/drivers/net/ixgb/ixgb_param.c b/drivers/net/ethernet/intel/ixgb/ixgb_param.c
index dd7fbeb1f7d1..07d83ab46e21 100644
--- a/drivers/net/ixgb/ixgb_param.c
+++ b/drivers/net/ethernet/intel/ixgb/ixgb_param.c
@@ -267,7 +267,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
}
{ /* Transmit Descriptor Count */
- const struct ixgb_option opt = {
+ static const struct ixgb_option opt = {
.type = range_option,
.name = "Transmit Descriptors",
.err = "using default of " __MODULE_STRING(DEFAULT_TXD),
@@ -286,7 +286,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
tx_ring->count = ALIGN(tx_ring->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE);
}
{ /* Receive Descriptor Count */
- const struct ixgb_option opt = {
+ static const struct ixgb_option opt = {
.type = range_option,
.name = "Receive Descriptors",
.err = "using default of " __MODULE_STRING(DEFAULT_RXD),
@@ -305,7 +305,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
rx_ring->count = ALIGN(rx_ring->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE);
}
{ /* Receive Checksum Offload Enable */
- const struct ixgb_option opt = {
+ static const struct ixgb_option opt = {
.type = enable_option,
.name = "Receive Checksum Offload",
.err = "defaulting to Enabled",
@@ -348,7 +348,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
}
}
{ /* Receive Flow Control High Threshold */
- const struct ixgb_option opt = {
+ static const struct ixgb_option opt = {
.type = range_option,
.name = "Rx Flow Control High Threshold",
.err = "using default of " __MODULE_STRING(DEFAULT_FCRTH),
@@ -367,7 +367,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
pr_info("Ignoring RxFCHighThresh when no RxFC\n");
}
{ /* Receive Flow Control Low Threshold */
- const struct ixgb_option opt = {
+ static const struct ixgb_option opt = {
.type = range_option,
.name = "Rx Flow Control Low Threshold",
.err = "using default of " __MODULE_STRING(DEFAULT_FCRTL),
@@ -386,7 +386,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
pr_info("Ignoring RxFCLowThresh when no RxFC\n");
}
{ /* Flow Control Pause Time Request*/
- const struct ixgb_option opt = {
+ static const struct ixgb_option opt = {
.type = range_option,
.name = "Flow Control Pause Time Request",
.err = "using default of "__MODULE_STRING(DEFAULT_FCPAUSE),
@@ -416,7 +416,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
}
}
{ /* Receive Interrupt Delay */
- const struct ixgb_option opt = {
+ static const struct ixgb_option opt = {
.type = range_option,
.name = "Receive Interrupt Delay",
.err = "using default of " __MODULE_STRING(DEFAULT_RDTR),
@@ -433,7 +433,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
}
}
{ /* Transmit Interrupt Delay */
- const struct ixgb_option opt = {
+ static const struct ixgb_option opt = {
.type = range_option,
.name = "Transmit Interrupt Delay",
.err = "using default of " __MODULE_STRING(DEFAULT_TIDV),
@@ -451,7 +451,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
}
{ /* Transmit Interrupt Delay Enable */
- const struct ixgb_option opt = {
+ static const struct ixgb_option opt = {
.type = enable_option,
.name = "Tx Interrupt Delay Enable",
.err = "defaulting to Enabled",
diff --git a/drivers/net/ixgbe/Makefile b/drivers/net/ethernet/intel/ixgbe/Makefile
index 7d7387fbdecd..7d7387fbdecd 100644
--- a/drivers/net/ixgbe/Makefile
+++ b/drivers/net/ethernet/intel/ixgbe/Makefile
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index e04a8e49e6dc..a8368d5cf686 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -53,6 +53,7 @@
/* TX/RX descriptor defines */
#define IXGBE_DEFAULT_TXD 512
+#define IXGBE_DEFAULT_TX_WORK 256
#define IXGBE_MAX_TXD 4096
#define IXGBE_MIN_TXD 64
@@ -71,10 +72,13 @@
/* Supported Rx Buffer Sizes */
#define IXGBE_RXBUFFER_512 512 /* Used for packet split */
-#define IXGBE_RXBUFFER_2048 2048
-#define IXGBE_RXBUFFER_4096 4096
-#define IXGBE_RXBUFFER_8192 8192
-#define IXGBE_MAX_RXBUFFER 16384 /* largest size for a single descriptor */
+#define IXGBE_RXBUFFER_2K 2048
+#define IXGBE_RXBUFFER_3K 3072
+#define IXGBE_RXBUFFER_4K 4096
+#define IXGBE_RXBUFFER_7K 7168
+#define IXGBE_RXBUFFER_8K 8192
+#define IXGBE_RXBUFFER_15K 15360
+#define IXGBE_MAX_RXBUFFER 16384 /* largest size for a single descriptor */
/*
* NOTE: netdev_alloc_skb reserves up to 64 bytes, NET_IP_ALIGN mans we
@@ -91,13 +95,17 @@
#define IXGBE_RX_BUFFER_WRITE 16 /* Must be power of 2 */
#define IXGBE_TX_FLAGS_CSUM (u32)(1)
-#define IXGBE_TX_FLAGS_VLAN (u32)(1 << 1)
-#define IXGBE_TX_FLAGS_TSO (u32)(1 << 2)
-#define IXGBE_TX_FLAGS_IPV4 (u32)(1 << 3)
-#define IXGBE_TX_FLAGS_FCOE (u32)(1 << 4)
-#define IXGBE_TX_FLAGS_FSO (u32)(1 << 5)
+#define IXGBE_TX_FLAGS_HW_VLAN (u32)(1 << 1)
+#define IXGBE_TX_FLAGS_SW_VLAN (u32)(1 << 2)
+#define IXGBE_TX_FLAGS_TSO (u32)(1 << 3)
+#define IXGBE_TX_FLAGS_IPV4 (u32)(1 << 4)
+#define IXGBE_TX_FLAGS_FCOE (u32)(1 << 5)
+#define IXGBE_TX_FLAGS_FSO (u32)(1 << 6)
+#define IXGBE_TX_FLAGS_TXSW (u32)(1 << 7)
+#define IXGBE_TX_FLAGS_MAPPED_AS_PAGE (u32)(1 << 8)
#define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000
-#define IXGBE_TX_FLAGS_VLAN_PRIO_MASK 0x0000e000
+#define IXGBE_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000
+#define IXGBE_TX_FLAGS_VLAN_PRIO_SHIFT 29
#define IXGBE_TX_FLAGS_VLAN_SHIFT 16
#define IXGBE_MAX_RSC_INT_RATE 162760
@@ -108,6 +116,8 @@
#define MAX_EMULATION_MAC_ADDRS 16
#define IXGBE_MAX_PF_MACVLANS 15
#define VMDQ_P(p) ((p) + adapter->num_vfs)
+#define IXGBE_82599_VF_DEVICE_ID 0x10ED
+#define IXGBE_X540_VF_DEVICE_ID 0x1515
struct vf_data_storage {
unsigned char vf_mac_addresses[ETH_ALEN];
@@ -120,6 +130,9 @@ struct vf_data_storage {
u16 pf_vlan; /* When set, guest VLAN config not allowed. */
u16 pf_qos;
u16 tx_rate;
+ u16 vlan_count;
+ u8 spoofchk_enabled;
+ struct pci_dev *vfdev;
};
struct vf_macvlans {
@@ -141,14 +154,14 @@ struct vf_macvlans {
/* wrapper around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer */
struct ixgbe_tx_buffer {
- struct sk_buff *skb;
- dma_addr_t dma;
+ union ixgbe_adv_tx_desc *next_to_watch;
unsigned long time_stamp;
- u16 length;
- u16 next_to_watch;
- unsigned int bytecount;
+ dma_addr_t dma;
+ u32 length;
+ u32 tx_flags;
+ struct sk_buff *skb;
+ u32 bytecount;
u16 gso_segs;
- u8 mapped_as_page;
};
struct ixgbe_rx_buffer {
@@ -206,6 +219,7 @@ enum ixbge_ring_state_t {
#define clear_ring_rsc_enabled(ring) \
clear_bit(__IXGBE_RX_RSC_ENABLED, &(ring)->state)
struct ixgbe_ring {
+ struct ixgbe_ring *next; /* pointer to next ring in q_vector */
void *desc; /* descriptor ring memory */
struct device *dev; /* device for DMA mapping */
struct net_device *netdev; /* netdev ring belongs to */
@@ -274,11 +288,7 @@ struct ixgbe_ring_feature {
} ____cacheline_internodealigned_in_smp;
struct ixgbe_ring_container {
-#if MAX_RX_QUEUES > MAX_TX_QUEUES
- DECLARE_BITMAP(idx, MAX_RX_QUEUES);
-#else
- DECLARE_BITMAP(idx, MAX_TX_QUEUES);
-#endif
+ struct ixgbe_ring *ring; /* pointer to linked list of rings */
unsigned int total_bytes; /* total bytes processed this int */
unsigned int total_packets; /* total packets processed this int */
u16 work_limit; /* total work allowed per interrupt */
@@ -295,26 +305,29 @@ struct ixgbe_ring_container {
*/
struct ixgbe_q_vector {
struct ixgbe_adapter *adapter;
- unsigned int v_idx; /* index of q_vector within array, also used for
- * finding the bit in EICR and friends that
- * represents the vector for this ring */
#ifdef CONFIG_IXGBE_DCA
int cpu; /* CPU for DCA */
#endif
- struct napi_struct napi;
+ u16 v_idx; /* index of q_vector within array, also used for
+ * finding the bit in EICR and friends that
+ * represents the vector for this ring */
+ u16 itr; /* Interrupt throttle rate written to EITR */
struct ixgbe_ring_container rx, tx;
- u32 eitr;
+
+ struct napi_struct napi;
cpumask_var_t affinity_mask;
char name[IFNAMSIZ + 9];
};
-/* Helper macros to switch between ints/sec and what the register uses.
- * And yes, it's the same math going both ways. The lowest value
- * supported by all of the ixgbe hardware is 8.
+/*
+ * microsecond values for various ITR rates shifted by 2 to fit itr register
+ * with the first 3 bits reserved 0
*/
-#define EITR_INTS_PER_SEC_TO_REG(_eitr) \
- ((_eitr) ? (1000000000 / ((_eitr) * 256)) : 8)
-#define EITR_REG_TO_INTS_PER_SEC EITR_INTS_PER_SEC_TO_REG
+#define IXGBE_MIN_RSC_ITR 24
+#define IXGBE_100K_ITR 40
+#define IXGBE_20K_ITR 200
+#define IXGBE_10K_ITR 400
+#define IXGBE_8K_ITR 500
static inline u16 ixgbe_desc_unused(struct ixgbe_ring *ring)
{
@@ -484,12 +497,13 @@ struct ixgbe_adapter {
u64 rsc_total_count;
u64 rsc_total_flush;
u32 wol;
- u16 eeprom_version;
+ u16 eeprom_verh;
+ u16 eeprom_verl;
+ u16 eeprom_cap;
int node;
u32 led_reg;
u32 interrupt_event;
- char lsc_int_name[IFNAMSIZ + 9];
/* SR-IOV */
DECLARE_BITMAP(active_vfs, IXGBE_MAX_VF_FUNCTIONS);
@@ -498,11 +512,12 @@ struct ixgbe_adapter {
int vf_rate_link_speed;
struct vf_macvlans vf_mvs;
struct vf_macvlans *mv_list;
- bool antispoofing_enabled;
struct hlist_head fdir_filter_list;
union ixgbe_atr_input fdir_mask;
int fdir_filter_count;
+ u32 timer_event_accumulator;
+ u32 vferr_refcount;
};
struct ixgbe_fdir_filter {
@@ -546,7 +561,7 @@ extern int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *src_dcb_cfg,
extern char ixgbe_driver_name[];
extern const char ixgbe_driver_version[];
-extern int ixgbe_up(struct ixgbe_adapter *adapter);
+extern void ixgbe_up(struct ixgbe_adapter *adapter);
extern void ixgbe_down(struct ixgbe_adapter *adapter);
extern void ixgbe_reinit_locked(struct ixgbe_adapter *adapter);
extern void ixgbe_reset(struct ixgbe_adapter *adapter);
diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
index 0d4e38264492..ef2afefb0cd4 100644
--- a/drivers/net/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
@@ -307,7 +307,6 @@ static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw)
switch (hw->phy.type) {
case ixgbe_phy_cu_unknown:
case ixgbe_phy_tn:
- case ixgbe_phy_aq:
media_type = ixgbe_media_type_copper;
goto out;
default:
@@ -358,7 +357,6 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num)
u32 fctrl_reg;
u32 rmcs_reg;
u32 reg;
- u32 rx_pba_size;
u32 link_speed = 0;
bool link_up;
@@ -461,16 +459,13 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num)
/* Set up and enable Rx high/low water mark thresholds, enable XON. */
if (hw->fc.current_mode & ixgbe_fc_tx_pause) {
- rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(packetbuf_num));
- rx_pba_size >>= IXGBE_RXPBSIZE_SHIFT;
-
- reg = (rx_pba_size - hw->fc.low_water) << 6;
+ reg = hw->fc.low_water << 6;
if (hw->fc.send_xon)
reg |= IXGBE_FCRTL_XONE;
IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num), reg);
- reg = (rx_pba_size - hw->fc.high_water) << 6;
+ reg = hw->fc.high_water[packetbuf_num] << 6;
reg |= IXGBE_FCRTH_FCEN;
IXGBE_WRITE_REG(hw, IXGBE_FCRTH(packetbuf_num), reg);
@@ -654,11 +649,6 @@ static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw,
(ixgbe_validate_link_ready(hw) != 0))
*link_up = false;
- /* if link is down, zero out the current_mode */
- if (*link_up == false) {
- hw->fc.current_mode = ixgbe_fc_none;
- hw->fc.fc_was_autonegged = false;
- }
out:
return 0;
}
@@ -759,7 +749,9 @@ static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw)
u8 analog_val;
/* Call adapter stop to disable tx/rx and clear interrupts */
- hw->mac.ops.stop_adapter(hw);
+ status = hw->mac.ops.stop_adapter(hw);
+ if (status != 0)
+ goto reset_hw_out;
/*
* Power up the Atlas Tx lanes if they are currently powered down.
@@ -802,26 +794,19 @@ static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw)
phy_status = hw->phy.ops.init(hw);
if (phy_status == IXGBE_ERR_SFP_NOT_SUPPORTED)
goto reset_hw_out;
- else if (phy_status == IXGBE_ERR_SFP_NOT_PRESENT)
- goto no_phy_reset;
+ if (phy_status == IXGBE_ERR_SFP_NOT_PRESENT)
+ goto mac_reset_top;
hw->phy.ops.reset(hw);
}
-no_phy_reset:
- /*
- * Prevent the PCI-E bus from from hanging by disabling PCI-E master
- * access and verify no pending requests before reset
- */
- ixgbe_disable_pcie_master(hw);
-
mac_reset_top:
/*
* Issue global reset to the MAC. This needs to be a SW reset.
* If link reset is used, it might reset the MAC when mng is using it
*/
- ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
- IXGBE_WRITE_REG(hw, IXGBE_CTRL, (ctrl | IXGBE_CTRL_RST));
+ ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL) | IXGBE_CTRL_RST;
+ IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl);
IXGBE_WRITE_FLUSH(hw);
/* Poll for reset bit to self-clear indicating reset is complete */
@@ -836,21 +821,18 @@ mac_reset_top:
hw_dbg(hw, "Reset polling failed to complete.\n");
}
+ msleep(50);
+
/*
* Double resets are required for recovery from certain error
* conditions. Between resets, it is necessary to stall to allow time
- * for any pending HW events to complete. We use 1usec since that is
- * what is needed for ixgbe_disable_pcie_master(). The second reset
- * then clears out any effects of those events.
+ * for any pending HW events to complete.
*/
if (hw->mac.flags & IXGBE_FLAGS_DOUBLE_RESET_REQUIRED) {
hw->mac.flags &= ~IXGBE_FLAGS_DOUBLE_RESET_REQUIRED;
- udelay(1);
goto mac_reset_top;
}
- msleep(50);
-
gheccr = IXGBE_READ_REG(hw, IXGBE_GHECCR);
gheccr &= ~((1 << 21) | (1 << 18) | (1 << 9) | (1 << 6));
IXGBE_WRITE_REG(hw, IXGBE_GHECCR, gheccr);
@@ -1129,7 +1111,6 @@ static u32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw)
* physical layer because 10GBase-T PHYs use LMS = KX4/KX */
switch (hw->phy.type) {
case ixgbe_phy_tn:
- case ixgbe_phy_aq:
case ixgbe_phy_cu_unknown:
hw->phy.ops.read_reg(hw, MDIO_PMA_EXTABLE,
MDIO_MMD_PMAPMD, &ext_ability);
@@ -1324,6 +1305,8 @@ static struct ixgbe_mac_operations mac_ops_82598 = {
static struct ixgbe_eeprom_operations eeprom_ops_82598 = {
.init_params = &ixgbe_init_eeprom_params_generic,
.read = &ixgbe_read_eerd_generic,
+ .write = &ixgbe_write_eeprom_generic,
+ .write_buffer = &ixgbe_write_eeprom_buffer_bit_bang_generic,
.read_buffer = &ixgbe_read_eerd_buffer_generic,
.calc_checksum = &ixgbe_calc_eeprom_checksum_generic,
.validate_checksum = &ixgbe_validate_eeprom_checksum_generic,
diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
index 34f30ec79c2e..4ae26a748da0 100644
--- a/drivers/net/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
@@ -217,10 +217,6 @@ static s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw)
phy->ops.get_firmware_version =
&ixgbe_get_phy_firmware_version_tnx;
break;
- case ixgbe_phy_aq:
- phy->ops.get_firmware_version =
- &ixgbe_get_phy_firmware_version_generic;
- break;
default:
break;
}
@@ -340,7 +336,6 @@ static enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw)
switch (hw->phy.type) {
case ixgbe_phy_cu_unknown:
case ixgbe_phy_tn:
- case ixgbe_phy_aq:
media_type = ixgbe_media_type_copper;
goto out;
default:
@@ -361,6 +356,7 @@ static enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw)
case IXGBE_DEV_ID_82599_SFP_FCOE:
case IXGBE_DEV_ID_82599_SFP_EM:
case IXGBE_DEV_ID_82599_SFP_SF2:
+ case IXGBE_DEV_ID_82599EN_SFP:
media_type = ixgbe_media_type_fiber;
break;
case IXGBE_DEV_ID_82599_CX4:
@@ -904,14 +900,18 @@ static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw,
**/
static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw)
{
- s32 status = 0;
- u32 ctrl;
- u32 i;
- u32 autoc;
- u32 autoc2;
+ ixgbe_link_speed link_speed;
+ s32 status;
+ u32 ctrl, i, autoc, autoc2;
+ bool link_up = false;
/* Call adapter stop to disable tx/rx and clear interrupts */
- hw->mac.ops.stop_adapter(hw);
+ status = hw->mac.ops.stop_adapter(hw);
+ if (status != 0)
+ goto reset_hw_out;
+
+ /* flush pending Tx transactions */
+ ixgbe_clear_tx_pending(hw);
/* PHY ops must be identified and initialized prior to reset */
@@ -934,48 +934,49 @@ static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw)
if (hw->phy.reset_disable == false && hw->phy.ops.reset != NULL)
hw->phy.ops.reset(hw);
- /*
- * Prevent the PCI-E bus from from hanging by disabling PCI-E master
- * access and verify no pending requests before reset
- */
- ixgbe_disable_pcie_master(hw);
-
mac_reset_top:
/*
- * Issue global reset to the MAC. This needs to be a SW reset.
- * If link reset is used, it might reset the MAC when mng is using it
+ * Issue global reset to the MAC. Needs to be SW reset if link is up.
+ * If link reset is used when link is up, it might reset the PHY when
+ * mng is using it. If link is down or the flag to force full link
+ * reset is set, then perform link reset.
*/
- ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
- IXGBE_WRITE_REG(hw, IXGBE_CTRL, (ctrl | IXGBE_CTRL_RST));
+ ctrl = IXGBE_CTRL_LNK_RST;
+ if (!hw->force_full_reset) {
+ hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
+ if (link_up)
+ ctrl = IXGBE_CTRL_RST;
+ }
+
+ ctrl |= IXGBE_READ_REG(hw, IXGBE_CTRL);
+ IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl);
IXGBE_WRITE_FLUSH(hw);
/* Poll for reset bit to self-clear indicating reset is complete */
for (i = 0; i < 10; i++) {
udelay(1);
ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
- if (!(ctrl & IXGBE_CTRL_RST))
+ if (!(ctrl & IXGBE_CTRL_RST_MASK))
break;
}
- if (ctrl & IXGBE_CTRL_RST) {
+
+ if (ctrl & IXGBE_CTRL_RST_MASK) {
status = IXGBE_ERR_RESET_FAILED;
hw_dbg(hw, "Reset polling failed to complete.\n");
}
+ msleep(50);
+
/*
* Double resets are required for recovery from certain error
* conditions. Between resets, it is necessary to stall to allow time
- * for any pending HW events to complete. We use 1usec since that is
- * what is needed for ixgbe_disable_pcie_master(). The second reset
- * then clears out any effects of those events.
+ * for any pending HW events to complete.
*/
if (hw->mac.flags & IXGBE_FLAGS_DOUBLE_RESET_REQUIRED) {
hw->mac.flags &= ~IXGBE_FLAGS_DOUBLE_RESET_REQUIRED;
- udelay(1);
goto mac_reset_top;
}
- msleep(50);
-
/*
* Store the original AUTOC/AUTOC2 values if they have not been
* stored off yet. Otherwise restore the stored original
@@ -1108,79 +1109,6 @@ s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw)
}
/**
- * ixgbe_set_fdir_rxpba_82599 - Initialize Flow Director Rx packet buffer
- * @hw: pointer to hardware structure
- * @pballoc: which mode to allocate filters with
- **/
-static s32 ixgbe_set_fdir_rxpba_82599(struct ixgbe_hw *hw, const u32 pballoc)
-{
- u32 fdir_pbsize = hw->mac.rx_pb_size << IXGBE_RXPBSIZE_SHIFT;
- u32 current_rxpbsize = 0;
- int i;
-
- /* reserve space for Flow Director filters */
- switch (pballoc) {
- case IXGBE_FDIR_PBALLOC_256K:
- fdir_pbsize -= 256 << IXGBE_RXPBSIZE_SHIFT;
- break;
- case IXGBE_FDIR_PBALLOC_128K:
- fdir_pbsize -= 128 << IXGBE_RXPBSIZE_SHIFT;
- break;
- case IXGBE_FDIR_PBALLOC_64K:
- fdir_pbsize -= 64 << IXGBE_RXPBSIZE_SHIFT;
- break;
- case IXGBE_FDIR_PBALLOC_NONE:
- default:
- return IXGBE_ERR_PARAM;
- }
-
- /* determine current RX packet buffer size */
- for (i = 0; i < 8; i++)
- current_rxpbsize += IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i));
-
- /* if there is already room for the filters do nothing */
- if (current_rxpbsize <= fdir_pbsize)
- return 0;
-
- if (current_rxpbsize > hw->mac.rx_pb_size) {
- /*
- * if rxpbsize is greater than max then HW max the Rx buffer
- * sizes are unconfigured or misconfigured since HW default is
- * to give the full buffer to each traffic class resulting in
- * the total size being buffer size 8x actual size
- *
- * This assumes no DCB since the RXPBSIZE registers appear to
- * be unconfigured.
- */
- IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(0), fdir_pbsize);
- for (i = 1; i < 8; i++)
- IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), 0);
- } else {
- /*
- * Since the Rx packet buffer appears to have already been
- * configured we need to shrink each packet buffer by enough
- * to make room for the filters. As such we take each rxpbsize
- * value and multiply it by a fraction representing the size
- * needed over the size we currently have.
- *
- * We need to reduce fdir_pbsize and current_rxpbsize to
- * 1/1024 of their original values in order to avoid
- * overflowing the u32 being used to store rxpbsize.
- */
- fdir_pbsize >>= IXGBE_RXPBSIZE_SHIFT;
- current_rxpbsize >>= IXGBE_RXPBSIZE_SHIFT;
- for (i = 0; i < 8; i++) {
- u32 rxpbsize = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i));
- rxpbsize *= fdir_pbsize;
- rxpbsize /= current_rxpbsize;
- IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), rxpbsize);
- }
- }
-
- return 0;
-}
-
-/**
* ixgbe_fdir_enable_82599 - Initialize Flow Director control registers
* @hw: pointer to hardware structure
* @fdirctrl: value to write to flow director control register
@@ -1227,13 +1155,6 @@ static void ixgbe_fdir_enable_82599(struct ixgbe_hw *hw, u32 fdirctrl)
**/
s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 fdirctrl)
{
- s32 err;
-
- /* Before enabling Flow Director, verify the Rx Packet Buffer size */
- err = ixgbe_set_fdir_rxpba_82599(hw, fdirctrl);
- if (err)
- return err;
-
/*
* Continue setup of fdirctrl register bits:
* Move the flexible bytes to use the ethertype - shift 6 words
@@ -1258,13 +1179,6 @@ s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 fdirctrl)
**/
s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 fdirctrl)
{
- s32 err;
-
- /* Before enabling Flow Director, verify the Rx Packet Buffer size */
- err = ixgbe_set_fdir_rxpba_82599(hw, fdirctrl);
- if (err)
- return err;
-
/*
* Continue setup of fdirctrl register bits:
* Turn perfect match filtering on
@@ -1886,7 +1800,6 @@ static u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw)
switch (hw->phy.type) {
case ixgbe_phy_tn:
- case ixgbe_phy_aq:
case ixgbe_phy_cu_unknown:
hw->phy.ops.read_reg(hw, MDIO_PMA_EXTABLE, MDIO_MMD_PMAPMD,
&ext_ability);
diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
index fc1375f26fe5..834f044be4c3 100644
--- a/drivers/net/ixgbe/ixgbe_common.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
@@ -61,6 +61,7 @@ static s32 ixgbe_write_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset,
u16 words, u16 *data);
static s32 ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw,
u16 offset);
+static s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw);
/**
* ixgbe_start_hw_generic - Prepare hardware for Tx/Rx
@@ -225,8 +226,9 @@ s32 ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw)
IXGBE_READ_REG(hw, IXGBE_GORCH);
IXGBE_READ_REG(hw, IXGBE_GOTCL);
IXGBE_READ_REG(hw, IXGBE_GOTCH);
- for (i = 0; i < 8; i++)
- IXGBE_READ_REG(hw, IXGBE_RNBC(i));
+ if (hw->mac.type == ixgbe_mac_82598EB)
+ for (i = 0; i < 8; i++)
+ IXGBE_READ_REG(hw, IXGBE_RNBC(i));
IXGBE_READ_REG(hw, IXGBE_RUC);
IXGBE_READ_REG(hw, IXGBE_RFC);
IXGBE_READ_REG(hw, IXGBE_ROC);
@@ -495,7 +497,6 @@ void ixgbe_set_lan_id_multi_port_pcie(struct ixgbe_hw *hw)
**/
s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw)
{
- u32 number_of_queues;
u32 reg_val;
u16 i;
@@ -506,35 +507,35 @@ s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw)
hw->adapter_stopped = true;
/* Disable the receive unit */
- reg_val = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
- reg_val &= ~(IXGBE_RXCTRL_RXEN);
- IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_val);
- IXGBE_WRITE_FLUSH(hw);
- usleep_range(2000, 4000);
+ IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, 0);
- /* Clear interrupt mask to stop from interrupts being generated */
+ /* Clear interrupt mask to stop interrupts from being generated */
IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_IRQ_CLEAR_MASK);
- /* Clear any pending interrupts */
+ /* Clear any pending interrupts, flush previous writes */
IXGBE_READ_REG(hw, IXGBE_EICR);
/* Disable the transmit unit. Each queue must be disabled. */
- number_of_queues = hw->mac.max_tx_queues;
- for (i = 0; i < number_of_queues; i++) {
- reg_val = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i));
- if (reg_val & IXGBE_TXDCTL_ENABLE) {
- reg_val &= ~IXGBE_TXDCTL_ENABLE;
- IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(i), reg_val);
- }
+ for (i = 0; i < hw->mac.max_tx_queues; i++)
+ IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(i), IXGBE_TXDCTL_SWFLSH);
+
+ /* Disable the receive unit by stopping each queue */
+ for (i = 0; i < hw->mac.max_rx_queues; i++) {
+ reg_val = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i));
+ reg_val &= ~IXGBE_RXDCTL_ENABLE;
+ reg_val |= IXGBE_RXDCTL_SWFLSH;
+ IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), reg_val);
}
+ /* flush all queues disables */
+ IXGBE_WRITE_FLUSH(hw);
+ usleep_range(1000, 2000);
+
/*
* Prevent the PCI-E bus from from hanging by disabling PCI-E master
* access and verify no pending requests
*/
- ixgbe_disable_pcie_master(hw);
-
- return 0;
+ return ixgbe_disable_pcie_master(hw);
}
/**
@@ -1931,7 +1932,6 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packetbuf_num)
s32 ret_val = 0;
u32 mflcn_reg, fccfg_reg;
u32 reg;
- u32 rx_pba_size;
u32 fcrtl, fcrth;
#ifdef CONFIG_DCB
@@ -2011,11 +2011,8 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packetbuf_num)
IXGBE_WRITE_REG(hw, IXGBE_MFLCN, mflcn_reg);
IXGBE_WRITE_REG(hw, IXGBE_FCCFG, fccfg_reg);
- rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(packetbuf_num));
- rx_pba_size >>= IXGBE_RXPBSIZE_SHIFT;
-
- fcrth = (rx_pba_size - hw->fc.high_water) << 10;
- fcrtl = (rx_pba_size - hw->fc.low_water) << 10;
+ fcrth = hw->fc.high_water[packetbuf_num] << 10;
+ fcrtl = hw->fc.low_water << 10;
if (hw->fc.current_mode & ixgbe_fc_tx_pause) {
fcrth |= IXGBE_FCRTH_FCEN;
@@ -2121,8 +2118,8 @@ static s32 ixgbe_fc_autoneg_fiber(struct ixgbe_hw *hw)
*/
linkstat = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA);
- if (((linkstat & IXGBE_PCS1GLSTA_AN_COMPLETE) == 0) ||
- ((linkstat & IXGBE_PCS1GLSTA_AN_TIMED_OUT) == 1)) {
+ if ((!!(linkstat & IXGBE_PCS1GLSTA_AN_COMPLETE) == 0) ||
+ (!!(linkstat & IXGBE_PCS1GLSTA_AN_TIMED_OUT) == 1)) {
ret_val = IXGBE_ERR_FC_NOT_NEGOTIATED;
goto out;
}
@@ -2292,7 +2289,9 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num)
* Validate the water mark configuration. Zero water marks are invalid
* because it causes the controller to just blast out fc packets.
*/
- if (!hw->fc.low_water || !hw->fc.high_water || !hw->fc.pause_time) {
+ if (!hw->fc.low_water ||
+ !hw->fc.high_water[packetbuf_num] ||
+ !hw->fc.pause_time) {
hw_dbg(hw, "Invalid water mark configuration\n");
ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS;
goto out;
@@ -2457,75 +2456,57 @@ out:
* bit hasn't caused the master requests to be disabled, else 0
* is returned signifying master requests disabled.
**/
-s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw)
+static s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw)
{
struct ixgbe_adapter *adapter = hw->back;
- u32 i;
- u32 reg_val;
- u32 number_of_queues;
s32 status = 0;
- u16 dev_status = 0;
+ u32 i;
+ u16 value;
- /* Just jump out if bus mastering is already disabled */
+ /* Always set this bit to ensure any future transactions are blocked */
+ IXGBE_WRITE_REG(hw, IXGBE_CTRL, IXGBE_CTRL_GIO_DIS);
+
+ /* Exit if master requests are blocked */
if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO))
goto out;
- /* Disable the receive unit by stopping each queue */
- number_of_queues = hw->mac.max_rx_queues;
- for (i = 0; i < number_of_queues; i++) {
- reg_val = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i));
- if (reg_val & IXGBE_RXDCTL_ENABLE) {
- reg_val &= ~IXGBE_RXDCTL_ENABLE;
- IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), reg_val);
- }
- }
-
- reg_val = IXGBE_READ_REG(hw, IXGBE_CTRL);
- reg_val |= IXGBE_CTRL_GIO_DIS;
- IXGBE_WRITE_REG(hw, IXGBE_CTRL, reg_val);
-
+ /* Poll for master request bit to clear */
for (i = 0; i < IXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) {
- if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO))
- goto check_device_status;
udelay(100);
+ if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO))
+ goto out;
}
+ /*
+ * Two consecutive resets are required via CTRL.RST per datasheet
+ * 5.2.5.3.2 Master Disable. We set a flag to inform the reset routine
+ * of this need. The first reset prevents new master requests from
+ * being issued by our device. We then must wait 1usec or more for any
+ * remaining completions from the PCIe bus to trickle in, and then reset
+ * again to clear out any effects they may have had on our device.
+ */
hw_dbg(hw, "GIO Master Disable bit didn't clear - requesting resets\n");
- status = IXGBE_ERR_MASTER_REQUESTS_PENDING;
+ hw->mac.flags |= IXGBE_FLAGS_DOUBLE_RESET_REQUIRED;
/*
* Before proceeding, make sure that the PCIe block does not have
* transactions pending.
*/
-check_device_status:
for (i = 0; i < IXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) {
- pci_read_config_word(adapter->pdev, IXGBE_PCI_DEVICE_STATUS,
- &dev_status);
- if (!(dev_status & IXGBE_PCI_DEVICE_STATUS_TRANSACTION_PENDING))
- break;
udelay(100);
+ pci_read_config_word(adapter->pdev, IXGBE_PCI_DEVICE_STATUS,
+ &value);
+ if (!(value & IXGBE_PCI_DEVICE_STATUS_TRANSACTION_PENDING))
+ goto out;
}
- if (i == IXGBE_PCI_MASTER_DISABLE_TIMEOUT)
- hw_dbg(hw, "PCIe transaction pending bit also did not clear.\n");
- else
- goto out;
-
- /*
- * Two consecutive resets are required via CTRL.RST per datasheet
- * 5.2.5.3.2 Master Disable. We set a flag to inform the reset routine
- * of this need. The first reset prevents new master requests from
- * being issued by our device. We then must wait 1usec for any
- * remaining completions from the PCIe bus to trickle in, and then reset
- * again to clear out any effects they may have had on our device.
- */
- hw->mac.flags |= IXGBE_FLAGS_DOUBLE_RESET_REQUIRED;
+ hw_dbg(hw, "PCIe transaction pending bit also did not clear.\n");
+ status = IXGBE_ERR_MASTER_REQUESTS_PENDING;
out:
return status;
}
-
/**
* ixgbe_acquire_swfw_sync - Acquire SWFW semaphore
* @hw: pointer to hardware structure
@@ -3114,12 +3095,6 @@ s32 ixgbe_check_mac_link_generic(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
else
*speed = IXGBE_LINK_SPEED_UNKNOWN;
- /* if link is down, zero out the current_mode */
- if (*link_up == false) {
- hw->fc.current_mode = ixgbe_fc_none;
- hw->fc.fc_was_autonegged = false;
- }
-
return 0;
}
@@ -3366,7 +3341,7 @@ static u8 ixgbe_calculate_checksum(u8 *buffer, u32 length)
* Communicates with the manageability block. On success return 0
* else return IXGBE_ERR_HOST_INTERFACE_COMMAND.
**/
-static s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, u8 *buffer,
+static s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, u32 *buffer,
u32 length)
{
u32 hicr, i;
@@ -3399,7 +3374,7 @@ static s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, u8 *buffer,
*/
for (i = 0; i < dword_len; i++)
IXGBE_WRITE_REG_ARRAY(hw, IXGBE_FLEX_MNG,
- i, *((u32 *)buffer + i));
+ i, cpu_to_le32(buffer[i]));
/* Setting this bit tells the ARC that a new command is pending. */
IXGBE_WRITE_REG(hw, IXGBE_HICR, hicr | IXGBE_HICR_C);
@@ -3423,9 +3398,10 @@ static s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, u8 *buffer,
dword_len = hdr_size >> 2;
/* first pull in the header so we know the buffer length */
- for (i = 0; i < dword_len; i++)
- *((u32 *)buffer + i) =
- IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG, i);
+ for (i = 0; i < dword_len; i++) {
+ buffer[i] = IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG, i);
+ le32_to_cpus(&buffer[i]);
+ }
/* If there is any thing in data position pull it in */
buf_len = ((struct ixgbe_hic_hdr *)buffer)->buf_len;
@@ -3443,8 +3419,7 @@ static s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, u8 *buffer,
/* Pull in the rest of the buffer (i is where we left off)*/
for (; i < buf_len; i++)
- *((u32 *)buffer + i) =
- IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG, i);
+ buffer[i] = IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG, i);
out:
return ret_val;
@@ -3490,7 +3465,7 @@ s32 ixgbe_set_fw_drv_ver_generic(struct ixgbe_hw *hw, u8 maj, u8 min,
fw_cmd.pad2 = 0;
for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) {
- ret_val = ixgbe_host_interface_command(hw, (u8 *)&fw_cmd,
+ ret_val = ixgbe_host_interface_command(hw, (u32 *)&fw_cmd,
sizeof(fw_cmd));
if (ret_val != 0)
continue;
@@ -3508,3 +3483,44 @@ s32 ixgbe_set_fw_drv_ver_generic(struct ixgbe_hw *hw, u8 maj, u8 min,
out:
return ret_val;
}
+
+/**
+ * ixgbe_clear_tx_pending - Clear pending TX work from the PCIe fifo
+ * @hw: pointer to the hardware structure
+ *
+ * The 82599 and x540 MACs can experience issues if TX work is still pending
+ * when a reset occurs. This function prevents this by flushing the PCIe
+ * buffers on the system.
+ **/
+void ixgbe_clear_tx_pending(struct ixgbe_hw *hw)
+{
+ u32 gcr_ext, hlreg0;
+
+ /*
+ * If double reset is not requested then all transactions should
+ * already be clear and as such there is no work to do
+ */
+ if (!(hw->mac.flags & IXGBE_FLAGS_DOUBLE_RESET_REQUIRED))
+ return;
+
+ /*
+ * Set loopback enable to prevent any transmits from being sent
+ * should the link come up. This assumes that the RXCTRL.RXEN bit
+ * has already been cleared.
+ */
+ hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0);
+ IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0 | IXGBE_HLREG0_LPBK);
+
+ /* initiate cleaning flow for buffers in the PCIe transaction layer */
+ gcr_ext = IXGBE_READ_REG(hw, IXGBE_GCR_EXT);
+ IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT,
+ gcr_ext | IXGBE_GCR_EXT_BUFFERS_CLEAR);
+
+ /* Flush all writes and allow 20usec for all transactions to clear */
+ IXGBE_WRITE_FLUSH(hw);
+ udelay(20);
+
+ /* restore previous register values */
+ IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, gcr_ext);
+ IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0);
+}
diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
index f24fd64a4c46..863f9c1f145b 100644
--- a/drivers/net/ixgbe/ixgbe_common.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
@@ -81,7 +81,6 @@ s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw);
s32 ixgbe_validate_mac_addr(u8 *mac_addr);
s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask);
void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask);
-s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw);
s32 ixgbe_get_san_mac_addr_generic(struct ixgbe_hw *hw, u8 *san_mac_addr);
s32 ixgbe_set_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq);
s32 ixgbe_clear_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq);
@@ -101,6 +100,7 @@ void ixgbe_set_vlan_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf);
s32 ixgbe_get_device_caps_generic(struct ixgbe_hw *hw, u16 *device_caps);
s32 ixgbe_set_fw_drv_ver_generic(struct ixgbe_hw *hw, u8 maj, u8 min,
u8 build, u8 ver);
+void ixgbe_clear_tx_pending(struct ixgbe_hw *hw);
void ixgbe_set_rxpba_generic(struct ixgbe_hw *hw, int num_pb,
u32 headroom, int strategy);
diff --git a/drivers/net/ixgbe/ixgbe_dcb.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c
index 9d88c31487bc..318caf4bf623 100644
--- a/drivers/net/ixgbe/ixgbe_dcb.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c
@@ -40,7 +40,8 @@
* hardware. The IEEE 802.1Qaz specification do not use bandwidth
* groups so this is much simplified from the CEE case.
*/
-s32 ixgbe_ieee_credits(__u8 *bw, __u16 *refill, __u16 *max, int max_frame)
+static s32 ixgbe_ieee_credits(__u8 *bw, __u16 *refill,
+ __u16 *max, int max_frame)
{
int min_percent = 100;
int min_credit, multiplier;
@@ -183,7 +184,7 @@ void ixgbe_dcb_unpack_pfc(struct ixgbe_dcb_config *cfg, u8 *pfc_en)
*pfc_en = 0;
for (i = 0; i < MAX_TRAFFIC_CLASS; i++)
- *pfc_en |= (cfg->tc_config[i].dcb_pfc & 0xF) << i;
+ *pfc_en |= !!(cfg->tc_config[i].dcb_pfc & 0xF) << i;
}
void ixgbe_dcb_unpack_refill(struct ixgbe_dcb_config *cfg, int direction,
@@ -230,6 +231,18 @@ void ixgbe_dcb_unpack_prio(struct ixgbe_dcb_config *cfg, int direction,
}
}
+void ixgbe_dcb_unpack_map(struct ixgbe_dcb_config *cfg, int direction, u8 *map)
+{
+ int i, up;
+ unsigned long bitmap;
+
+ for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+ bitmap = cfg->tc_config[i].path[direction].up_to_tc_bitmap;
+ for_each_set_bit(up, &bitmap, MAX_USER_PRIORITY)
+ map[up] = i;
+ }
+}
+
/**
* ixgbe_dcb_hw_config - Config and enable DCB
* @hw: pointer to hardware structure
@@ -244,10 +257,9 @@ s32 ixgbe_dcb_hw_config(struct ixgbe_hw *hw,
u8 pfc_en;
u8 ptype[MAX_TRAFFIC_CLASS];
u8 bwgid[MAX_TRAFFIC_CLASS];
+ u8 prio_tc[MAX_TRAFFIC_CLASS];
u16 refill[MAX_TRAFFIC_CLASS];
u16 max[MAX_TRAFFIC_CLASS];
- /* CEE does not define a priority to tc mapping so map 1:1 */
- u8 prio_tc[MAX_TRAFFIC_CLASS] = {0, 1, 2, 3, 4, 5, 6, 7};
/* Unpack CEE standard containers */
ixgbe_dcb_unpack_pfc(dcb_config, &pfc_en);
@@ -255,6 +267,7 @@ s32 ixgbe_dcb_hw_config(struct ixgbe_hw *hw,
ixgbe_dcb_unpack_max(dcb_config, max);
ixgbe_dcb_unpack_bwgid(dcb_config, DCB_TX_CONFIG, bwgid);
ixgbe_dcb_unpack_prio(dcb_config, DCB_TX_CONFIG, ptype);
+ ixgbe_dcb_unpack_map(dcb_config, DCB_TX_CONFIG, prio_tc);
switch (hw->mac.type) {
case ixgbe_mac_82598EB:
@@ -273,7 +286,7 @@ s32 ixgbe_dcb_hw_config(struct ixgbe_hw *hw,
}
/* Helper routines to abstract HW specifics from DCB netlink ops */
-s32 ixgbe_dcb_hw_pfc_config(struct ixgbe_hw *hw, u8 pfc_en)
+s32 ixgbe_dcb_hw_pfc_config(struct ixgbe_hw *hw, u8 pfc_en, u8 *prio_tc)
{
int ret = -EINVAL;
@@ -283,7 +296,7 @@ s32 ixgbe_dcb_hw_pfc_config(struct ixgbe_hw *hw, u8 pfc_en)
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
- ret = ixgbe_dcb_config_pfc_82599(hw, pfc_en);
+ ret = ixgbe_dcb_config_pfc_82599(hw, pfc_en, prio_tc);
break;
default:
break;
@@ -291,6 +304,39 @@ s32 ixgbe_dcb_hw_pfc_config(struct ixgbe_hw *hw, u8 pfc_en)
return ret;
}
+s32 ixgbe_dcb_hw_ets(struct ixgbe_hw *hw, struct ieee_ets *ets, int max_frame)
+{
+ __u16 refill[IEEE_8021QAZ_MAX_TCS], max[IEEE_8021QAZ_MAX_TCS];
+ __u8 prio_type[IEEE_8021QAZ_MAX_TCS];
+ int i;
+
+ /* naively give each TC a bwg to map onto CEE hardware */
+ __u8 bwg_id[IEEE_8021QAZ_MAX_TCS] = {0, 1, 2, 3, 4, 5, 6, 7};
+
+ /* Map TSA onto CEE prio type */
+ for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
+ switch (ets->tc_tsa[i]) {
+ case IEEE_8021QAZ_TSA_STRICT:
+ prio_type[i] = 2;
+ break;
+ case IEEE_8021QAZ_TSA_ETS:
+ prio_type[i] = 0;
+ break;
+ default:
+ /* Hardware only supports priority strict or
+ * ETS transmission selection algorithms if
+ * we receive some other value from dcbnl
+ * throw an error
+ */
+ return -EINVAL;
+ }
+ }
+
+ ixgbe_ieee_credits(ets->tc_tx_bw, refill, max, max_frame);
+ return ixgbe_dcb_hw_ets_config(hw, refill, max,
+ bwg_id, prio_type, ets->prio_tc);
+}
+
s32 ixgbe_dcb_hw_ets_config(struct ixgbe_hw *hw,
u16 *refill, u16 *max, u8 *bwg_id,
u8 *prio_type, u8 *prio_tc)
diff --git a/drivers/net/ixgbe/ixgbe_dcb.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h
index e85826ae0320..e162775064da 100644
--- a/drivers/net/ixgbe/ixgbe_dcb.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h
@@ -29,13 +29,13 @@
#ifndef _DCB_CONFIG_H_
#define _DCB_CONFIG_H_
+#include <linux/dcbnl.h>
#include "ixgbe_type.h"
/* DCB data structures */
#define IXGBE_MAX_PACKET_BUFFERS 8
#define MAX_USER_PRIORITY 8
-#define MAX_TRAFFIC_CLASS 8
#define MAX_BW_GROUP 8
#define BW_PERCENT 100
@@ -145,16 +145,17 @@ void ixgbe_dcb_unpack_refill(struct ixgbe_dcb_config *, int, u16 *);
void ixgbe_dcb_unpack_max(struct ixgbe_dcb_config *, u16 *);
void ixgbe_dcb_unpack_bwgid(struct ixgbe_dcb_config *, int, u8 *);
void ixgbe_dcb_unpack_prio(struct ixgbe_dcb_config *, int, u8 *);
+void ixgbe_dcb_unpack_map(struct ixgbe_dcb_config *, int, u8 *);
/* DCB credits calculation */
-s32 ixgbe_ieee_credits(__u8 *bw, __u16 *refill, __u16 *max, int max_frame);
s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_hw *,
struct ixgbe_dcb_config *, int, u8);
/* DCB hw initialization */
+s32 ixgbe_dcb_hw_ets(struct ixgbe_hw *hw, struct ieee_ets *ets, int max);
s32 ixgbe_dcb_hw_ets_config(struct ixgbe_hw *hw, u16 *refill, u16 *max,
u8 *bwg_id, u8 *prio_type, u8 *tc_prio);
-s32 ixgbe_dcb_hw_pfc_config(struct ixgbe_hw *hw, u8 pfc_en);
+s32 ixgbe_dcb_hw_pfc_config(struct ixgbe_hw *hw, u8 pfc_en, u8 *tc_prio);
s32 ixgbe_dcb_hw_config(struct ixgbe_hw *, struct ixgbe_dcb_config *);
/* DCB definitions for credit calculation */
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c
index 2288c3cac010..fcd0e479721f 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_82598.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c
@@ -191,7 +191,7 @@ s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw,
*/
s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, u8 pfc_en)
{
- u32 reg, rx_pba_size;
+ u32 reg;
u8 i;
if (pfc_en) {
@@ -222,9 +222,8 @@ s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, u8 pfc_en)
*/
for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
int enabled = pfc_en & (1 << i);
- rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i));
- rx_pba_size >>= IXGBE_RXPBSIZE_SHIFT;
- reg = (rx_pba_size - hw->fc.low_water) << 10;
+
+ reg = hw->fc.low_water << 10;
if (enabled == pfc_enabled_tx ||
enabled == pfc_enabled_full)
@@ -232,7 +231,7 @@ s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, u8 pfc_en)
IXGBE_WRITE_REG(hw, IXGBE_FCRTL(i), reg);
- reg = (rx_pba_size - hw->fc.high_water) << 10;
+ reg = hw->fc.high_water[i] << 10;
if (enabled == pfc_enabled_tx ||
enabled == pfc_enabled_full)
reg |= IXGBE_FCRTH_FCEN;
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.h
index 2f318935561a..2f318935561a 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_82598.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.h
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c
index ade98200288c..32cd97bc794d 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_82599.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c
@@ -59,9 +59,9 @@ s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw,
reg = IXGBE_RTRPCS_RRM | IXGBE_RTRPCS_RAC | IXGBE_RTRPCS_ARBDIS;
IXGBE_WRITE_REG(hw, IXGBE_RTRPCS, reg);
- /* Map all traffic classes to their UP, 1 to 1 */
+ /* Map all traffic classes to their UP */
reg = 0;
- for (i = 0; i < MAX_TRAFFIC_CLASS; i++)
+ for (i = 0; i < MAX_USER_PRIORITY; i++)
reg |= (prio_tc[i] << (i * IXGBE_RTRUP2TC_UP_SHIFT));
IXGBE_WRITE_REG(hw, IXGBE_RTRUP2TC, reg);
@@ -169,9 +169,9 @@ s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw,
IXGBE_RTTPCS_ARBDIS;
IXGBE_WRITE_REG(hw, IXGBE_RTTPCS, reg);
- /* Map all traffic classes to their UP, 1 to 1 */
+ /* Map all traffic classes to their UP */
reg = 0;
- for (i = 0; i < MAX_TRAFFIC_CLASS; i++)
+ for (i = 0; i < MAX_USER_PRIORITY; i++)
reg |= (prio_tc[i] << (i * IXGBE_RTTUP2TC_UP_SHIFT));
IXGBE_WRITE_REG(hw, IXGBE_RTTUP2TC, reg);
@@ -205,26 +205,44 @@ s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw,
* ixgbe_dcb_config_pfc_82599 - Configure priority flow control
* @hw: pointer to hardware structure
* @pfc_en: enabled pfc bitmask
+ * @prio_tc: priority to tc assignments indexed by priority
*
* Configure Priority Flow Control (PFC) for each traffic class.
*/
-s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en)
+s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en, u8 *prio_tc)
{
- u32 i, reg, rx_pba_size;
+ u32 i, j, reg;
+ u8 max_tc = 0;
+
+ for (i = 0; i < MAX_USER_PRIORITY; i++)
+ if (prio_tc[i] > max_tc)
+ max_tc = prio_tc[i];
/* Configure PFC Tx thresholds per TC */
for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
- int enabled = pfc_en & (1 << i);
- rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i));
- rx_pba_size >>= IXGBE_RXPBSIZE_SHIFT;
+ int enabled = 0;
+
+ if (i > max_tc) {
+ reg = 0;
+ IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), reg);
+ IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(i), reg);
+ continue;
+ }
+
+ for (j = 0; j < MAX_USER_PRIORITY; j++) {
+ if ((prio_tc[j] == i) && (pfc_en & (1 << j))) {
+ enabled = 1;
+ break;
+ }
+ }
- reg = (rx_pba_size - hw->fc.low_water) << 10;
+ reg = hw->fc.low_water << 10;
if (enabled)
reg |= IXGBE_FCRTL_XONE;
IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), reg);
- reg = (rx_pba_size - hw->fc.high_water) << 10;
+ reg = hw->fc.high_water[i] << 10;
if (enabled)
reg |= IXGBE_FCRTH_FCEN;
IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(i), reg);
@@ -252,12 +270,24 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en)
reg &= ~IXGBE_MFLCN_RFCE;
reg |= IXGBE_MFLCN_RPFCE | IXGBE_MFLCN_DPF;
- if (hw->mac.type == ixgbe_mac_X540)
+ if (hw->mac.type == ixgbe_mac_X540) {
+ reg &= ~IXGBE_MFLCN_RPFCE_MASK;
reg |= pfc_en << IXGBE_MFLCN_RPFCE_SHIFT;
+ }
IXGBE_WRITE_REG(hw, IXGBE_MFLCN, reg);
} else {
+ /* X540 devices have a RX bit that should be cleared
+ * if PFC is disabled on all TCs but PFC features is
+ * enabled.
+ */
+ if (hw->mac.type == ixgbe_mac_X540) {
+ reg = IXGBE_READ_REG(hw, IXGBE_MFLCN);
+ reg &= ~IXGBE_MFLCN_RPFCE_MASK;
+ IXGBE_WRITE_REG(hw, IXGBE_MFLCN, reg);
+ }
+
for (i = 0; i < MAX_TRAFFIC_CLASS; i++)
hw->mac.ops.fc_enable(hw, i);
}
@@ -338,7 +368,7 @@ s32 ixgbe_dcb_hw_config_82599(struct ixgbe_hw *hw, u8 pfc_en, u16 *refill,
bwg_id, prio_type);
ixgbe_dcb_config_tx_data_arbiter_82599(hw, refill, max,
bwg_id, prio_type, prio_tc);
- ixgbe_dcb_config_pfc_82599(hw, pfc_en);
+ ixgbe_dcb_config_pfc_82599(hw, pfc_en, prio_tc);
ixgbe_dcb_config_tc_stats_82599(hw);
return 0;
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h
index 08d1749862a3..a59d5dc59d04 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_82599.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h
@@ -93,7 +93,7 @@
/* DCB hardware-specific driver APIs */
/* DCB PFC functions */
-s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en);
+s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en, u8 *prio_tc);
/* DCB hw initialization */
s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw,
diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
index 0ace6ce1d0b4..3631d639d86a 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_nl.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
@@ -114,53 +114,19 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state)
u8 err = 0;
struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ /* Fail command if not in CEE mode */
+ if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE))
+ return 1;
+
/* verify there is something to do, if not then exit */
if (!!state != !(adapter->flags & IXGBE_FLAG_DCB_ENABLED))
return err;
- if (state > 0) {
- /* Turn on DCB */
- if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) {
- e_err(drv, "Enable failed, needs MSI-X\n");
- err = 1;
- goto out;
- }
-
- adapter->flags |= IXGBE_FLAG_DCB_ENABLED;
-
- switch (adapter->hw.mac.type) {
- case ixgbe_mac_82598EB:
- adapter->last_lfc_mode = adapter->hw.fc.current_mode;
- adapter->hw.fc.requested_mode = ixgbe_fc_none;
- break;
- case ixgbe_mac_82599EB:
- case ixgbe_mac_X540:
- adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE;
- break;
- default:
- break;
- }
-
- ixgbe_setup_tc(netdev, MAX_TRAFFIC_CLASS);
- } else {
- /* Turn off DCB */
- adapter->hw.fc.requested_mode = adapter->last_lfc_mode;
- adapter->temp_dcb_cfg.pfc_mode_enable = false;
- adapter->dcb_cfg.pfc_mode_enable = false;
- adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED;
- switch (adapter->hw.mac.type) {
- case ixgbe_mac_82599EB:
- case ixgbe_mac_X540:
- if (!(adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))
- adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
- break;
- default:
- break;
- }
- ixgbe_setup_tc(netdev, 0);
- }
+ if (state > 0)
+ err = ixgbe_setup_tc(netdev, adapter->dcb_cfg.num_tcs.pg_tcs);
+ else
+ err = ixgbe_setup_tc(netdev, 0);
-out:
return err;
}
@@ -192,6 +158,10 @@ static void ixgbe_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc,
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ /* Abort a bad configuration */
+ if (ffs(up_map) > adapter->dcb_cfg.num_tcs.pg_tcs)
+ return;
+
if (prio != DCB_ATTR_VALUE_UNDEFINED)
adapter->temp_dcb_cfg.tc_config[tc].path[0].prio_type = prio;
if (bwg_id != DCB_ATTR_VALUE_UNDEFINED)
@@ -212,6 +182,10 @@ static void ixgbe_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc,
(adapter->temp_dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap !=
adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap))
adapter->dcb_set_bitmap |= BIT_PG_TX;
+
+ if (adapter->temp_dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap !=
+ adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap)
+ adapter->dcb_set_bitmap |= BIT_PFC;
}
static void ixgbe_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id,
@@ -232,6 +206,10 @@ static void ixgbe_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, int tc,
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ /* Abort bad configurations */
+ if (ffs(up_map) > adapter->dcb_cfg.num_tcs.pg_tcs)
+ return;
+
if (prio != DCB_ATTR_VALUE_UNDEFINED)
adapter->temp_dcb_cfg.tc_config[tc].path[1].prio_type = prio;
if (bwg_id != DCB_ATTR_VALUE_UNDEFINED)
@@ -252,6 +230,10 @@ static void ixgbe_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, int tc,
(adapter->temp_dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap !=
adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap))
adapter->dcb_set_bitmap |= BIT_PG_RX;
+
+ if (adapter->temp_dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap !=
+ adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap)
+ adapter->dcb_set_bitmap |= BIT_PFC;
}
static void ixgbe_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id,
@@ -330,22 +312,34 @@ static void ixgbe_dcbnl_get_pfc_cfg(struct net_device *netdev, int priority,
static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
- int ret;
+ int ret, i;
#ifdef IXGBE_FCOE
struct dcb_app app = {
.selector = DCB_APP_IDTYPE_ETHTYPE,
.protocol = ETH_P_FCOE,
};
- u8 up = dcb_getapp(netdev, &app);
+ u8 up;
+
+ /* In IEEE mode, use the IEEE Ethertype selector value */
+ if (adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) {
+ app.selector = IEEE_8021QAZ_APP_SEL_ETHERTYPE;
+ up = dcb_ieee_getapp_mask(netdev, &app);
+ } else {
+ up = dcb_getapp(netdev, &app);
+ }
#endif
+ /* Fail command if not in CEE mode */
+ if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE))
+ return 1;
+
ret = ixgbe_copy_dcb_cfg(&adapter->temp_dcb_cfg, &adapter->dcb_cfg,
MAX_TRAFFIC_CLASS);
if (ret)
return DCB_NO_HW_CHG;
#ifdef IXGBE_FCOE
- if (up && (up != (1 << adapter->fcoe.up)))
+ if (up && !(up & (1 << adapter->fcoe.up)))
adapter->dcb_set_bitmap |= BIT_APP_UPCHG;
/*
@@ -400,21 +394,14 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
}
#endif
- if (adapter->dcb_set_bitmap & BIT_PFC) {
- u8 pfc_en;
- ixgbe_dcb_unpack_pfc(&adapter->dcb_cfg, &pfc_en);
- ixgbe_dcb_hw_pfc_config(&adapter->hw, pfc_en);
- ret = DCB_HW_CHG;
- }
-
if (adapter->dcb_set_bitmap & (BIT_PG_TX|BIT_PG_RX)) {
u16 refill[MAX_TRAFFIC_CLASS], max[MAX_TRAFFIC_CLASS];
u8 bwg_id[MAX_TRAFFIC_CLASS], prio_type[MAX_TRAFFIC_CLASS];
/* Priority to TC mapping in CEE case default to 1:1 */
- u8 prio_tc[MAX_TRAFFIC_CLASS] = {0, 1, 2, 3, 4, 5, 6, 7};
+ u8 prio_tc[MAX_USER_PRIORITY];
int max_frame = adapter->netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
-#ifdef CONFIG_FCOE
+#ifdef IXGBE_FCOE
if (adapter->netdev->features & NETIF_F_FCOE_MTU)
max_frame = max(max_frame, IXGBE_FCOE_JUMBO_FRAME_SIZE);
#endif
@@ -431,9 +418,25 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
DCB_TX_CONFIG, bwg_id);
ixgbe_dcb_unpack_prio(&adapter->dcb_cfg,
DCB_TX_CONFIG, prio_type);
+ ixgbe_dcb_unpack_map(&adapter->dcb_cfg,
+ DCB_TX_CONFIG, prio_tc);
ixgbe_dcb_hw_ets_config(&adapter->hw, refill, max,
bwg_id, prio_type, prio_tc);
+
+ for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
+ netdev_set_prio_tc_map(netdev, i, prio_tc[i]);
+ }
+
+ if (adapter->dcb_set_bitmap & BIT_PFC) {
+ u8 pfc_en;
+ u8 prio_tc[MAX_USER_PRIORITY];
+
+ ixgbe_dcb_unpack_map(&adapter->dcb_cfg,
+ DCB_TX_CONFIG, prio_tc);
+ ixgbe_dcb_unpack_pfc(&adapter->dcb_cfg, &pfc_en);
+ ixgbe_dcb_hw_pfc_config(&adapter->hw, pfc_en, prio_tc);
+ ret = DCB_HW_CHG;
}
if (adapter->dcb_cfg.pfc_mode_enable)
@@ -490,10 +493,10 @@ static u8 ixgbe_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num)
if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
switch (tcid) {
case DCB_NUMTCS_ATTR_PG:
- *num = MAX_TRAFFIC_CLASS;
+ *num = adapter->dcb_cfg.num_tcs.pg_tcs;
break;
case DCB_NUMTCS_ATTR_PFC:
- *num = MAX_TRAFFIC_CLASS;
+ *num = adapter->dcb_cfg.num_tcs.pfc_tcs;
break;
default:
rval = -EINVAL;
@@ -562,7 +565,7 @@ static int ixgbe_dcbnl_ieee_getets(struct net_device *dev,
if (!my_ets)
return -EINVAL;
- ets->ets_cap = MAX_TRAFFIC_CLASS;
+ ets->ets_cap = adapter->dcb_cfg.num_tcs.pg_tcs;
ets->cbs = my_ets->cbs;
memcpy(ets->tc_tx_bw, my_ets->tc_tx_bw, sizeof(ets->tc_tx_bw));
memcpy(ets->tc_rx_bw, my_ets->tc_rx_bw, sizeof(ets->tc_rx_bw));
@@ -575,13 +578,9 @@ static int ixgbe_dcbnl_ieee_setets(struct net_device *dev,
struct ieee_ets *ets)
{
struct ixgbe_adapter *adapter = netdev_priv(dev);
- __u16 refill[IEEE_8021QAZ_MAX_TCS], max[IEEE_8021QAZ_MAX_TCS];
- __u8 prio_type[IEEE_8021QAZ_MAX_TCS];
int max_frame = dev->mtu + ETH_HLEN + ETH_FCS_LEN;
- int i, err;
- __u64 *p = (__u64 *) ets->prio_tc;
- /* naively give each TC a bwg to map onto CEE hardware */
- __u8 bwg_id[IEEE_8021QAZ_MAX_TCS] = {0, 1, 2, 3, 4, 5, 6, 7};
+ int i;
+ __u8 max_tc = 0;
if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
return -EINVAL;
@@ -595,34 +594,24 @@ static int ixgbe_dcbnl_ieee_setets(struct net_device *dev,
memcpy(adapter->ixgbe_ieee_ets, ets, sizeof(*adapter->ixgbe_ieee_ets));
- /* Map TSA onto CEE prio type */
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
- switch (ets->tc_tsa[i]) {
- case IEEE_8021QAZ_TSA_STRICT:
- prio_type[i] = 2;
- break;
- case IEEE_8021QAZ_TSA_ETS:
- prio_type[i] = 0;
- break;
- default:
- /* Hardware only supports priority strict or
- * ETS transmission selection algorithms if
- * we receive some other value from dcbnl
- * throw an error
- */
- return -EINVAL;
- }
+ if (ets->prio_tc[i] > max_tc)
+ max_tc = ets->prio_tc[i];
}
- if (*p)
- ixgbe_dcbnl_set_state(dev, 1);
- else
- ixgbe_dcbnl_set_state(dev, 0);
+ if (max_tc)
+ max_tc++;
- ixgbe_ieee_credits(ets->tc_tx_bw, refill, max, max_frame);
- err = ixgbe_dcb_hw_ets_config(&adapter->hw, refill, max,
- bwg_id, prio_type, ets->prio_tc);
- return err;
+ if (max_tc > adapter->dcb_cfg.num_tcs.pg_tcs)
+ return -EINVAL;
+
+ if (max_tc != netdev_get_num_tc(dev))
+ ixgbe_setup_tc(dev, max_tc);
+
+ for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
+ netdev_set_prio_tc_map(dev, i, ets->prio_tc[i]);
+
+ return ixgbe_dcb_hw_ets(&adapter->hw, ets, max_frame);
}
static int ixgbe_dcbnl_ieee_getpfc(struct net_device *dev,
@@ -636,7 +625,7 @@ static int ixgbe_dcbnl_ieee_getpfc(struct net_device *dev,
if (!my_pfc)
return -EINVAL;
- pfc->pfc_cap = MAX_TRAFFIC_CLASS;
+ pfc->pfc_cap = adapter->dcb_cfg.num_tcs.pfc_tcs;
pfc->pfc_en = my_pfc->pfc_en;
pfc->mbc = my_pfc->mbc;
pfc->delay = my_pfc->delay;
@@ -653,7 +642,7 @@ static int ixgbe_dcbnl_ieee_setpfc(struct net_device *dev,
struct ieee_pfc *pfc)
{
struct ixgbe_adapter *adapter = netdev_priv(dev);
- int err;
+ u8 *prio_tc;
if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
return -EINVAL;
@@ -665,9 +654,9 @@ static int ixgbe_dcbnl_ieee_setpfc(struct net_device *dev,
return -ENOMEM;
}
+ prio_tc = adapter->ixgbe_ieee_ets->prio_tc;
memcpy(adapter->ixgbe_ieee_pfc, pfc, sizeof(*adapter->ixgbe_ieee_pfc));
- err = ixgbe_dcb_hw_pfc_config(&adapter->hw, pfc->pfc_en);
- return err;
+ return ixgbe_dcb_hw_pfc_config(&adapter->hw, pfc->pfc_en, prio_tc);
}
#ifdef IXGBE_FCOE
@@ -778,7 +767,7 @@ static u8 ixgbe_dcbnl_setdcbx(struct net_device *dev, u8 mode)
*/
ixgbe_dcbnl_ieee_setets(dev, &ets);
ixgbe_dcbnl_ieee_setpfc(dev, &pfc);
- ixgbe_dcbnl_set_state(dev, 0);
+ ixgbe_setup_tc(dev, 0);
}
return 0;
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
index 82d4244c6e10..70d58c3849b0 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
@@ -113,6 +113,8 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = {
{"rx_fcoe_dropped", IXGBE_STAT(stats.fcoerpdc)},
{"rx_fcoe_packets", IXGBE_STAT(stats.fcoeprc)},
{"rx_fcoe_dwords", IXGBE_STAT(stats.fcoedwrc)},
+ {"fcoe_noddp", IXGBE_STAT(stats.fcoe_noddp)},
+ {"fcoe_noddp_ext_buff", IXGBE_STAT(stats.fcoe_noddp_ext_buff)},
{"tx_fcoe_packets", IXGBE_STAT(stats.fcoeptc)},
{"tx_fcoe_dwords", IXGBE_STAT(stats.fcoedwtc)},
#endif /* IXGBE_FCOE */
@@ -324,12 +326,16 @@ static int ixgbe_set_settings(struct net_device *netdev,
if ((hw->phy.media_type == ixgbe_media_type_copper) ||
(hw->phy.multispeed_fiber)) {
- /* 10000/copper and 1000/copper must autoneg
- * this function does not support any duplex forcing, but can
- * limit the advertising of the adapter to only 10000 or 1000 */
+ /*
+ * this function does not support duplex forcing, but can
+ * limit the advertising of the adapter to the specified speed
+ */
if (ecmd->autoneg == AUTONEG_DISABLE)
return -EINVAL;
+ if (ecmd->advertising & ~ecmd->supported)
+ return -EINVAL;
+
old = hw->phy.autoneg_advertised;
advertised = 0;
if (ecmd->advertising & ADVERTISED_10000baseT_Full)
@@ -368,13 +374,7 @@ static void ixgbe_get_pauseparam(struct net_device *netdev,
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw;
- /*
- * Flow Control Autoneg isn't on if
- * - we didn't ask for it OR
- * - it failed, we know this by tx & rx being off
- */
- if (hw->fc.disable_fc_autoneg ||
- (hw->fc.current_mode == ixgbe_fc_none))
+ if (hw->fc.disable_fc_autoneg)
pause->autoneg = 0;
else
pause->autoneg = 1;
@@ -456,7 +456,7 @@ static void ixgbe_set_msglevel(struct net_device *netdev, u32 data)
static int ixgbe_get_regs_len(struct net_device *netdev)
{
-#define IXGBE_REGS_LEN 1128
+#define IXGBE_REGS_LEN 1129
return IXGBE_REGS_LEN * sizeof(u32);
}
@@ -525,6 +525,7 @@ static void ixgbe_get_regs(struct net_device *netdev,
regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTH(i));
break;
case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTL_82599(i));
regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTH_82599(i));
break;
@@ -766,6 +767,9 @@ static void ixgbe_get_regs(struct net_device *netdev,
regs_buff[1125] = IXGBE_READ_REG(hw, IXGBE_PCIEECCCTL);
regs_buff[1126] = IXGBE_READ_REG(hw, IXGBE_PBTXECC);
regs_buff[1127] = IXGBE_READ_REG(hw, IXGBE_PBRXECC);
+
+ /* 82599 X540 specific registers */
+ regs_buff[1128] = IXGBE_READ_REG(hw, IXGBE_MFLCN);
}
static int ixgbe_get_eeprom_len(struct net_device *netdev)
@@ -810,26 +814,97 @@ static int ixgbe_get_eeprom(struct net_device *netdev,
return ret_val;
}
+static int ixgbe_set_eeprom(struct net_device *netdev,
+ struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ u16 *eeprom_buff;
+ void *ptr;
+ int max_len, first_word, last_word, ret_val = 0;
+ u16 i;
+
+ if (eeprom->len == 0)
+ return -EINVAL;
+
+ if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))
+ return -EINVAL;
+
+ max_len = hw->eeprom.word_size * 2;
+
+ first_word = eeprom->offset >> 1;
+ last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+ eeprom_buff = kmalloc(max_len, GFP_KERNEL);
+ if (!eeprom_buff)
+ return -ENOMEM;
+
+ ptr = eeprom_buff;
+
+ if (eeprom->offset & 1) {
+ /*
+ * need read/modify/write of first changed EEPROM word
+ * only the second byte of the word is being modified
+ */
+ ret_val = hw->eeprom.ops.read(hw, first_word, &eeprom_buff[0]);
+ if (ret_val)
+ goto err;
+
+ ptr++;
+ }
+ if ((eeprom->offset + eeprom->len) & 1) {
+ /*
+ * need read/modify/write of last changed EEPROM word
+ * only the first byte of the word is being modified
+ */
+ ret_val = hw->eeprom.ops.read(hw, last_word,
+ &eeprom_buff[last_word - first_word]);
+ if (ret_val)
+ goto err;
+ }
+
+ /* Device's eeprom is always little-endian, word addressable */
+ for (i = 0; i < last_word - first_word + 1; i++)
+ le16_to_cpus(&eeprom_buff[i]);
+
+ memcpy(ptr, bytes, eeprom->len);
+
+ for (i = 0; i < last_word - first_word + 1; i++)
+ cpu_to_le16s(&eeprom_buff[i]);
+
+ ret_val = hw->eeprom.ops.write_buffer(hw, first_word,
+ last_word - first_word + 1,
+ eeprom_buff);
+
+ /* Update the checksum */
+ if (ret_val == 0)
+ hw->eeprom.ops.update_checksum(hw);
+
+err:
+ kfree(eeprom_buff);
+ return ret_val;
+}
+
static void ixgbe_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *drvinfo)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
char firmware_version[32];
+ u32 nvm_track_id;
strncpy(drvinfo->driver, ixgbe_driver_name,
sizeof(drvinfo->driver) - 1);
strncpy(drvinfo->version, ixgbe_driver_version,
sizeof(drvinfo->version) - 1);
- snprintf(firmware_version, sizeof(firmware_version), "%d.%d-%d",
- (adapter->eeprom_version & 0xF000) >> 12,
- (adapter->eeprom_version & 0x0FF0) >> 4,
- adapter->eeprom_version & 0x000F);
+ nvm_track_id = (adapter->eeprom_verh << 16) |
+ adapter->eeprom_verl;
+ snprintf(firmware_version, sizeof(firmware_version), "0x%08x",
+ nvm_track_id);
strncpy(drvinfo->fw_version, firmware_version,
- sizeof(drvinfo->fw_version));
+ sizeof(drvinfo->fw_version) - 1);
strncpy(drvinfo->bus_info, pci_name(adapter->pdev),
- sizeof(drvinfo->bus_info));
+ sizeof(drvinfo->bus_info) - 1);
drvinfo->n_stats = IXGBE_STATS_LEN;
drvinfo->testinfo_len = IXGBE_TEST_LEN;
drvinfo->regdump_len = ixgbe_get_regs_len(netdev);
@@ -844,12 +919,8 @@ static void ixgbe_get_ringparam(struct net_device *netdev,
ring->rx_max_pending = IXGBE_MAX_RXD;
ring->tx_max_pending = IXGBE_MAX_TXD;
- ring->rx_mini_max_pending = 0;
- ring->rx_jumbo_max_pending = 0;
ring->rx_pending = rx_ring->count;
ring->tx_pending = tx_ring->count;
- ring->rx_mini_pending = 0;
- ring->rx_jumbo_pending = 0;
}
static int ixgbe_set_ringparam(struct net_device *netdev,
@@ -1535,7 +1606,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
rx_ring->dev = &adapter->pdev->dev;
rx_ring->netdev = adapter->netdev;
rx_ring->reg_idx = adapter->rx_ring[0]->reg_idx;
- rx_ring->rx_buf_len = IXGBE_RXBUFFER_2048;
+ rx_ring->rx_buf_len = IXGBE_RXBUFFER_2K;
rx_ring->numa_node = adapter->node;
err = ixgbe_setup_rx_resources(rx_ring);
@@ -1566,26 +1637,26 @@ static int ixgbe_setup_loopback_test(struct ixgbe_adapter *adapter)
/* X540 needs to set the MACC.FLU bit to force link up */
if (adapter->hw.mac.type == ixgbe_mac_X540) {
- reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_MACC);
+ reg_data = IXGBE_READ_REG(hw, IXGBE_MACC);
reg_data |= IXGBE_MACC_FLU;
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_MACC, reg_data);
+ IXGBE_WRITE_REG(hw, IXGBE_MACC, reg_data);
}
/* right now we only support MAC loopback in the driver */
- reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0);
+ reg_data = IXGBE_READ_REG(hw, IXGBE_HLREG0);
/* Setup MAC loopback */
reg_data |= IXGBE_HLREG0_LPBK;
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data);
+ IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_data);
- reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL);
+ reg_data = IXGBE_READ_REG(hw, IXGBE_FCTRL);
reg_data |= IXGBE_FCTRL_BAM | IXGBE_FCTRL_SBP | IXGBE_FCTRL_MPE;
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_data);
+ IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg_data);
- reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_AUTOC);
+ reg_data = IXGBE_READ_REG(hw, IXGBE_AUTOC);
reg_data &= ~IXGBE_AUTOC_LMS_MASK;
reg_data |= IXGBE_AUTOC_LMS_10G_LINK_NO_AN | IXGBE_AUTOC_FLU;
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_AUTOC, reg_data);
- IXGBE_WRITE_FLUSH(&adapter->hw);
+ IXGBE_WRITE_REG(hw, IXGBE_AUTOC, reg_data);
+ IXGBE_WRITE_FLUSH(hw);
usleep_range(10000, 20000);
/* Disable Atlas Tx lanes; re-enabled in reset path */
@@ -1883,6 +1954,7 @@ static int ixgbe_wol_exclusion(struct ixgbe_adapter *adapter,
{
struct ixgbe_hw *hw = &adapter->hw;
int retval = 1;
+ u16 wol_cap = adapter->eeprom_cap & IXGBE_DEVICE_CAPS_WOL_MASK;
/* WOL not supported except for the following */
switch(hw->device_id) {
@@ -1906,6 +1978,18 @@ static int ixgbe_wol_exclusion(struct ixgbe_adapter *adapter,
case IXGBE_DEV_ID_82599_KX4:
retval = 0;
break;
+ case IXGBE_DEV_ID_X540T:
+ /* check eeprom to see if enabled wol */
+ if ((wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0_1) ||
+ ((wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0) &&
+ (hw->bus.func == 0))) {
+ retval = 0;
+ break;
+ }
+
+ /* All others not supported */
+ wol->supported = 0;
+ break;
default:
wol->supported = 0;
}
@@ -2008,39 +2092,20 @@ static int ixgbe_get_coalesce(struct net_device *netdev,
ec->tx_max_coalesced_frames_irq = adapter->tx_work_limit;
/* only valid if in constant ITR mode */
- switch (adapter->rx_itr_setting) {
- case 0:
- /* throttling disabled */
- ec->rx_coalesce_usecs = 0;
- break;
- case 1:
- /* dynamic ITR mode */
- ec->rx_coalesce_usecs = 1;
- break;
- default:
- /* fixed interrupt rate mode */
- ec->rx_coalesce_usecs = 1000000/adapter->rx_eitr_param;
- break;
- }
+ if (adapter->rx_itr_setting <= 1)
+ ec->rx_coalesce_usecs = adapter->rx_itr_setting;
+ else
+ ec->rx_coalesce_usecs = adapter->rx_itr_setting >> 2;
/* if in mixed tx/rx queues per vector mode, report only rx settings */
if (adapter->q_vector[0]->tx.count && adapter->q_vector[0]->rx.count)
return 0;
/* only valid if in constant ITR mode */
- switch (adapter->tx_itr_setting) {
- case 0:
- /* throttling disabled */
- ec->tx_coalesce_usecs = 0;
- break;
- case 1:
- /* dynamic ITR mode */
- ec->tx_coalesce_usecs = 1;
- break;
- default:
- ec->tx_coalesce_usecs = 1000000/adapter->tx_eitr_param;
- break;
- }
+ if (adapter->tx_itr_setting <= 1)
+ ec->tx_coalesce_usecs = adapter->tx_itr_setting;
+ else
+ ec->tx_coalesce_usecs = adapter->tx_itr_setting >> 2;
return 0;
}
@@ -2059,10 +2124,9 @@ static bool ixgbe_update_rsc(struct ixgbe_adapter *adapter,
/* if interrupt rate is too high then disable RSC */
if (ec->rx_coalesce_usecs != 1 &&
- ec->rx_coalesce_usecs <= 1000000/IXGBE_MAX_RSC_INT_RATE) {
+ ec->rx_coalesce_usecs <= (IXGBE_MIN_RSC_ITR >> 2)) {
if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) {
- e_info(probe, "rx-usecs set too low, "
- "disabling RSC\n");
+ e_info(probe, "rx-usecs set too low, disabling RSC\n");
adapter->flags2 &= ~IXGBE_FLAG2_RSC_ENABLED;
return true;
}
@@ -2070,8 +2134,7 @@ static bool ixgbe_update_rsc(struct ixgbe_adapter *adapter,
/* check the feature flag value and enable RSC if necessary */
if ((netdev->features & NETIF_F_LRO) &&
!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED)) {
- e_info(probe, "rx-usecs set to %d, "
- "re-enabling RSC\n",
+ e_info(probe, "rx-usecs set to %d, re-enabling RSC\n",
ec->rx_coalesce_usecs);
adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED;
return true;
@@ -2086,97 +2149,59 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_q_vector *q_vector;
int i;
+ int num_vectors;
+ u16 tx_itr_param, rx_itr_param;
bool need_reset = false;
/* don't accept tx specific changes if we've got mixed RxTx vectors */
if (adapter->q_vector[0]->tx.count && adapter->q_vector[0]->rx.count
- && ec->tx_coalesce_usecs)
+ && ec->tx_coalesce_usecs)
return -EINVAL;
if (ec->tx_max_coalesced_frames_irq)
adapter->tx_work_limit = ec->tx_max_coalesced_frames_irq;
- if (ec->rx_coalesce_usecs > 1) {
- /* check the limits */
- if ((1000000/ec->rx_coalesce_usecs > IXGBE_MAX_INT_RATE) ||
- (1000000/ec->rx_coalesce_usecs < IXGBE_MIN_INT_RATE))
- return -EINVAL;
-
- /* check the old value and enable RSC if necessary */
- need_reset = ixgbe_update_rsc(adapter, ec);
-
- /* store the value in ints/second */
- adapter->rx_eitr_param = 1000000/ec->rx_coalesce_usecs;
+ if ((ec->rx_coalesce_usecs > (IXGBE_MAX_EITR >> 2)) ||
+ (ec->tx_coalesce_usecs > (IXGBE_MAX_EITR >> 2)))
+ return -EINVAL;
- /* static value of interrupt rate */
- adapter->rx_itr_setting = adapter->rx_eitr_param;
- /* clear the lower bit as its used for dynamic state */
- adapter->rx_itr_setting &= ~1;
- } else if (ec->rx_coalesce_usecs == 1) {
- /* check the old value and enable RSC if necessary */
- need_reset = ixgbe_update_rsc(adapter, ec);
+ /* check the old value and enable RSC if necessary */
+ need_reset = ixgbe_update_rsc(adapter, ec);
- /* 1 means dynamic mode */
- adapter->rx_eitr_param = 20000;
- adapter->rx_itr_setting = 1;
- } else {
- /* check the old value and enable RSC if necessary */
- need_reset = ixgbe_update_rsc(adapter, ec);
- /*
- * any other value means disable eitr, which is best
- * served by setting the interrupt rate very high
- */
- adapter->rx_eitr_param = IXGBE_MAX_INT_RATE;
- adapter->rx_itr_setting = 0;
- }
+ if (ec->rx_coalesce_usecs > 1)
+ adapter->rx_itr_setting = ec->rx_coalesce_usecs << 2;
+ else
+ adapter->rx_itr_setting = ec->rx_coalesce_usecs;
- if (ec->tx_coalesce_usecs > 1) {
- /*
- * don't have to worry about max_int as above because
- * tx vectors don't do hardware RSC (an rx function)
- */
- /* check the limits */
- if ((1000000/ec->tx_coalesce_usecs > IXGBE_MAX_INT_RATE) ||
- (1000000/ec->tx_coalesce_usecs < IXGBE_MIN_INT_RATE))
- return -EINVAL;
+ if (adapter->rx_itr_setting == 1)
+ rx_itr_param = IXGBE_20K_ITR;
+ else
+ rx_itr_param = adapter->rx_itr_setting;
- /* store the value in ints/second */
- adapter->tx_eitr_param = 1000000/ec->tx_coalesce_usecs;
+ if (ec->tx_coalesce_usecs > 1)
+ adapter->tx_itr_setting = ec->tx_coalesce_usecs << 2;
+ else
+ adapter->tx_itr_setting = ec->tx_coalesce_usecs;
- /* static value of interrupt rate */
- adapter->tx_itr_setting = adapter->tx_eitr_param;
+ if (adapter->tx_itr_setting == 1)
+ tx_itr_param = IXGBE_10K_ITR;
+ else
+ tx_itr_param = adapter->tx_itr_setting;
- /* clear the lower bit as its used for dynamic state */
- adapter->tx_itr_setting &= ~1;
- } else if (ec->tx_coalesce_usecs == 1) {
- /* 1 means dynamic mode */
- adapter->tx_eitr_param = 10000;
- adapter->tx_itr_setting = 1;
- } else {
- adapter->tx_eitr_param = IXGBE_MAX_INT_RATE;
- adapter->tx_itr_setting = 0;
- }
+ if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
+ num_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+ else
+ num_vectors = 1;
- /* MSI/MSIx Interrupt Mode */
- if (adapter->flags &
- (IXGBE_FLAG_MSIX_ENABLED | IXGBE_FLAG_MSI_ENABLED)) {
- int num_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
- for (i = 0; i < num_vectors; i++) {
- q_vector = adapter->q_vector[i];
- if (q_vector->tx.count && !q_vector->rx.count)
- /* tx only */
- q_vector->eitr = adapter->tx_eitr_param;
- else
- /* rx only or mixed */
- q_vector->eitr = adapter->rx_eitr_param;
- q_vector->tx.work_limit = adapter->tx_work_limit;
- ixgbe_write_eitr(q_vector);
- }
- /* Legacy Interrupt Mode */
- } else {
- q_vector = adapter->q_vector[0];
- q_vector->eitr = adapter->rx_eitr_param;
+ for (i = 0; i < num_vectors; i++) {
+ q_vector = adapter->q_vector[i];
q_vector->tx.work_limit = adapter->tx_work_limit;
+ if (q_vector->tx.count && !q_vector->rx.count)
+ /* tx only */
+ q_vector->itr = tx_itr_param;
+ else
+ /* rx only or mixed */
+ q_vector->itr = rx_itr_param;
ixgbe_write_eitr(q_vector);
}
@@ -2279,11 +2304,13 @@ static int ixgbe_get_ethtool_fdir_all(struct ixgbe_adapter *adapter,
cnt++;
}
+ cmd->rule_cnt = cnt;
+
return 0;
}
static int ixgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
- void *rule_locs)
+ u32 *rule_locs)
{
struct ixgbe_adapter *adapter = netdev_priv(dev);
int ret = -EOPNOTSUPP;
@@ -2301,8 +2328,7 @@ static int ixgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
ret = ixgbe_get_ethtool_fdir_entry(adapter, cmd);
break;
case ETHTOOL_GRXCLSRLALL:
- ret = ixgbe_get_ethtool_fdir_all(adapter, cmd,
- (u32 *)rule_locs);
+ ret = ixgbe_get_ethtool_fdir_all(adapter, cmd, rule_locs);
break;
default:
break;
@@ -2569,6 +2595,7 @@ static const struct ethtool_ops ixgbe_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_eeprom_len = ixgbe_get_eeprom_len,
.get_eeprom = ixgbe_get_eeprom,
+ .set_eeprom = ixgbe_set_eeprom,
.get_ringparam = ixgbe_get_ringparam,
.set_ringparam = ixgbe_set_ringparam,
.get_pauseparam = ixgbe_get_pauseparam,
diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
index 824edae77865..df3b1be69d83 100644
--- a/drivers/net/ixgbe/ixgbe_fcoe.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
@@ -145,6 +145,7 @@ static int ixgbe_fcoe_ddp_setup(struct net_device *netdev, u16 xid,
u32 fcbuff, fcdmarw, fcfltrw, fcrxctl;
dma_addr_t addr = 0;
struct pci_pool *pool;
+ unsigned int cpu;
if (!netdev || !sgl)
return 0;
@@ -182,7 +183,8 @@ static int ixgbe_fcoe_ddp_setup(struct net_device *netdev, u16 xid,
}
/* alloc the udl from per cpu ddp pool */
- pool = *per_cpu_ptr(fcoe->pool, get_cpu());
+ cpu = get_cpu();
+ pool = *per_cpu_ptr(fcoe->pool, cpu);
ddp->udl = pci_pool_alloc(pool, GFP_ATOMIC, &ddp->udp);
if (!ddp->udl) {
e_err(drv, "failed allocated ddp context\n");
@@ -199,9 +201,7 @@ static int ixgbe_fcoe_ddp_setup(struct net_device *netdev, u16 xid,
while (len) {
/* max number of buffers allowed in one DDP context */
if (j >= IXGBE_BUFFCNT_MAX) {
- e_err(drv, "xid=%x:%d,%d,%d:addr=%llx "
- "not enough descriptors\n",
- xid, i, j, dmacount, (u64)addr);
+ *per_cpu_ptr(fcoe->pcpu_noddp, cpu) += 1;
goto out_noddp_free;
}
@@ -241,10 +241,7 @@ static int ixgbe_fcoe_ddp_setup(struct net_device *netdev, u16 xid,
*/
if (lastsize == bufflen) {
if (j >= IXGBE_BUFFCNT_MAX) {
- e_err(drv, "xid=%x:%d,%d,%d:addr=%llx "
- "not enough user buffers. We need an extra "
- "buffer because lastsize is bufflen.\n",
- xid, i, j, dmacount, (u64)addr);
+ *per_cpu_ptr(fcoe->pcpu_noddp_ext_buff, cpu) += 1;
goto out_noddp_free;
}
@@ -438,7 +435,6 @@ ddp_out:
/**
* ixgbe_fso - ixgbe FCoE Sequence Offload (FSO)
- * @adapter: ixgbe adapter
* @tx_ring: tx desc ring
* @skb: associated skb
* @tx_flags: tx flags
@@ -599,6 +595,7 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter)
struct ixgbe_hw *hw = &adapter->hw;
struct ixgbe_fcoe *fcoe = &adapter->fcoe;
struct ixgbe_ring_feature *f = &adapter->ring_feature[RING_F_FCOE];
+ unsigned int cpu;
if (!fcoe->pool) {
spin_lock_init(&fcoe->lock);
@@ -626,6 +623,24 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter)
e_err(drv, "failed to map extra DDP buffer\n");
goto out_extra_ddp_buffer;
}
+
+ /* Alloc per cpu mem to count the ddp alloc failure number */
+ fcoe->pcpu_noddp = alloc_percpu(u64);
+ if (!fcoe->pcpu_noddp) {
+ e_err(drv, "failed to alloc noddp counter\n");
+ goto out_pcpu_noddp_alloc_fail;
+ }
+
+ fcoe->pcpu_noddp_ext_buff = alloc_percpu(u64);
+ if (!fcoe->pcpu_noddp_ext_buff) {
+ e_err(drv, "failed to alloc noddp extra buff cnt\n");
+ goto out_pcpu_noddp_extra_buff_alloc_fail;
+ }
+
+ for_each_possible_cpu(cpu) {
+ *per_cpu_ptr(fcoe->pcpu_noddp, cpu) = 0;
+ *per_cpu_ptr(fcoe->pcpu_noddp_ext_buff, cpu) = 0;
+ }
}
/* Enable L2 eth type filter for FCoE */
@@ -660,12 +675,16 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter)
IXGBE_ETQS_QUEUE_EN |
(fcoe_q << IXGBE_ETQS_RX_QUEUE_SHIFT));
- IXGBE_WRITE_REG(hw, IXGBE_FCRXCTRL,
- IXGBE_FCRXCTRL_FCOELLI |
- IXGBE_FCRXCTRL_FCCRCBO |
+ IXGBE_WRITE_REG(hw, IXGBE_FCRXCTRL, IXGBE_FCRXCTRL_FCCRCBO |
(FC_FCOE_VER << IXGBE_FCRXCTRL_FCOEVER_SHIFT));
return;
-
+out_pcpu_noddp_extra_buff_alloc_fail:
+ free_percpu(fcoe->pcpu_noddp);
+out_pcpu_noddp_alloc_fail:
+ dma_unmap_single(&adapter->pdev->dev,
+ fcoe->extra_ddp_buffer_dma,
+ IXGBE_FCBUFF_MIN,
+ DMA_FROM_DEVICE);
out_extra_ddp_buffer:
kfree(fcoe->extra_ddp_buffer);
out_ddp_pools:
@@ -694,6 +713,8 @@ void ixgbe_cleanup_fcoe(struct ixgbe_adapter *adapter)
fcoe->extra_ddp_buffer_dma,
IXGBE_FCBUFF_MIN,
DMA_FROM_DEVICE);
+ free_percpu(fcoe->pcpu_noddp);
+ free_percpu(fcoe->pcpu_noddp_ext_buff);
kfree(fcoe->extra_ddp_buffer);
ixgbe_fcoe_ddp_pools_free(fcoe);
}
diff --git a/drivers/net/ixgbe/ixgbe_fcoe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h
index 99de145e290d..261fd62dda18 100644
--- a/drivers/net/ixgbe/ixgbe_fcoe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h
@@ -73,6 +73,8 @@ struct ixgbe_fcoe {
unsigned char *extra_ddp_buffer;
dma_addr_t extra_ddp_buffer_dma;
unsigned long mode;
+ u64 __percpu *pcpu_noddp;
+ u64 __percpu *pcpu_noddp_ext_buff;
#ifdef CONFIG_IXGBE_DCB
u8 up;
#endif
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index e86297b32733..09b8e88b2999 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -42,6 +42,7 @@
#include <net/checksum.h>
#include <net/ip6_checksum.h>
#include <linux/ethtool.h>
+#include <linux/if.h>
#include <linux/if_vlan.h>
#include <linux/prefetch.h>
#include <scsi/fc/fc_fcoe.h>
@@ -55,8 +56,8 @@ char ixgbe_driver_name[] = "ixgbe";
static const char ixgbe_driver_string[] =
"Intel(R) 10 Gigabit PCI Express Network Driver";
#define MAJ 3
-#define MIN 4
-#define BUILD 8
+#define MIN 6
+#define BUILD 7
#define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \
__stringify(BUILD) "-k"
const char ixgbe_driver_version[] = DRV_VERSION;
@@ -78,59 +79,33 @@ static const struct ixgbe_info *ixgbe_info_tbl[] = {
* Class, Class Mask, private data (not used) }
*/
static DEFINE_PCI_DEVICE_TABLE(ixgbe_pci_tbl) = {
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598),
- board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_DUAL_PORT),
- board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_SINGLE_PORT),
- board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT),
- board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT2),
- board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_CX4),
- board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_CX4_DUAL_PORT),
- board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_DA_DUAL_PORT),
- board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM),
- board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_XF_LR),
- board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_SFP_LOM),
- board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_BX),
- board_82598 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_KX4),
- board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_XAUI_LOM),
- board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_KR),
- board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP),
- board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_EM),
- board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_KX4_MEZZ),
- board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_CX4),
- board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_BACKPLANE_FCOE),
- board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_FCOE),
- board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_T3_LOM),
- board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_COMBO_BACKPLANE),
- board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T),
- board_X540 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_SF2),
- board_82599 },
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_LS),
- board_82599 },
-
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598), board_82598 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_DUAL_PORT), board_82598 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_SINGLE_PORT), board_82598 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT), board_82598 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT2), board_82598 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_CX4), board_82598 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_CX4_DUAL_PORT), board_82598 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_DA_DUAL_PORT), board_82598 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM), board_82598 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_XF_LR), board_82598 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_SFP_LOM), board_82598 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_BX), board_82598 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_KX4), board_82599 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_XAUI_LOM), board_82599 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_KR), board_82599 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP), board_82599 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_EM), board_82599 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_KX4_MEZZ), board_82599 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_CX4), board_82599 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_BACKPLANE_FCOE), board_82599 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_FCOE), board_82599 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_T3_LOM), board_82599 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_COMBO_BACKPLANE), board_82599 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T), board_X540 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_SF2), board_82599 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_LS), board_82599 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599EN_SFP), board_82599 },
/* required last entry */
{0, }
};
@@ -160,42 +135,6 @@ MODULE_VERSION(DRV_VERSION);
#define DEFAULT_DEBUG_LEVEL_SHIFT 3
-static inline void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
-{
- struct ixgbe_hw *hw = &adapter->hw;
- u32 gcr;
- u32 gpie;
- u32 vmdctl;
-
-#ifdef CONFIG_PCI_IOV
- /* disable iov and allow time for transactions to clear */
- pci_disable_sriov(adapter->pdev);
-#endif
-
- /* turn off device IOV mode */
- gcr = IXGBE_READ_REG(hw, IXGBE_GCR_EXT);
- gcr &= ~(IXGBE_GCR_EXT_SRIOV);
- IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, gcr);
- gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
- gpie &= ~IXGBE_GPIE_VTMODE_MASK;
- IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
-
- /* set default pool back to 0 */
- vmdctl = IXGBE_READ_REG(hw, IXGBE_VT_CTL);
- vmdctl &= ~IXGBE_VT_CTL_POOL_MASK;
- IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vmdctl);
- IXGBE_WRITE_FLUSH(hw);
-
- /* take a breather then clean up driver data */
- msleep(100);
-
- kfree(adapter->vfinfo);
- adapter->vfinfo = NULL;
-
- adapter->num_vfs = 0;
- adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED;
-}
-
static void ixgbe_service_event_schedule(struct ixgbe_adapter *adapter)
{
if (!test_bit(__IXGBE_DOWN, &adapter->state) &&
@@ -384,7 +323,7 @@ static void ixgbe_dump(struct ixgbe_adapter *adapter)
tx_ring = adapter->tx_ring[n];
tx_buffer_info =
&tx_ring->tx_buffer_info[tx_ring->next_to_clean];
- pr_info(" %5d %5X %5X %016llX %04X %3X %016llX\n",
+ pr_info(" %5d %5X %5X %016llX %04X %p %016llX\n",
n, tx_ring->next_to_use, tx_ring->next_to_clean,
(u64)tx_buffer_info->dma,
tx_buffer_info->length,
@@ -423,7 +362,7 @@ static void ixgbe_dump(struct ixgbe_adapter *adapter)
tx_buffer_info = &tx_ring->tx_buffer_info[i];
u0 = (struct my_u0 *)tx_desc;
pr_info("T [0x%03X] %016llX %016llX %016llX"
- " %04X %3X %016llX %p", i,
+ " %04X %p %016llX %p", i,
le64_to_cpu(u0->a),
le64_to_cpu(u0->b),
(u64)tx_buffer_info->dma,
@@ -525,7 +464,7 @@ rx_ring_summary:
rx_ring->rx_buf_len, true);
if (rx_ring->rx_buf_len
- < IXGBE_RXBUFFER_2048)
+ < IXGBE_RXBUFFER_2K)
print_hex_dump(KERN_INFO, "",
DUMP_PREFIX_ADDRESS, 16, 1,
phys_to_virt(
@@ -642,27 +581,31 @@ static inline void ixgbe_irq_rearm_queues(struct ixgbe_adapter *adapter,
}
}
-void ixgbe_unmap_and_free_tx_resource(struct ixgbe_ring *tx_ring,
- struct ixgbe_tx_buffer *tx_buffer_info)
+static inline void ixgbe_unmap_tx_resource(struct ixgbe_ring *ring,
+ struct ixgbe_tx_buffer *tx_buffer)
{
- if (tx_buffer_info->dma) {
- if (tx_buffer_info->mapped_as_page)
- dma_unmap_page(tx_ring->dev,
- tx_buffer_info->dma,
- tx_buffer_info->length,
- DMA_TO_DEVICE);
+ if (tx_buffer->dma) {
+ if (tx_buffer->tx_flags & IXGBE_TX_FLAGS_MAPPED_AS_PAGE)
+ dma_unmap_page(ring->dev,
+ tx_buffer->dma,
+ tx_buffer->length,
+ DMA_TO_DEVICE);
else
- dma_unmap_single(tx_ring->dev,
- tx_buffer_info->dma,
- tx_buffer_info->length,
- DMA_TO_DEVICE);
- tx_buffer_info->dma = 0;
+ dma_unmap_single(ring->dev,
+ tx_buffer->dma,
+ tx_buffer->length,
+ DMA_TO_DEVICE);
}
- if (tx_buffer_info->skb) {
+ tx_buffer->dma = 0;
+}
+
+void ixgbe_unmap_and_free_tx_resource(struct ixgbe_ring *tx_ring,
+ struct ixgbe_tx_buffer *tx_buffer_info)
+{
+ ixgbe_unmap_tx_resource(tx_ring, tx_buffer_info);
+ if (tx_buffer_info->skb)
dev_kfree_skb_any(tx_buffer_info->skb);
- tx_buffer_info->skb = NULL;
- }
- tx_buffer_info->time_stamp = 0;
+ tx_buffer_info->skb = NULL;
/* tx_buffer_info must be completely set up in the transmit path */
}
@@ -796,56 +739,72 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
struct ixgbe_ring *tx_ring)
{
struct ixgbe_adapter *adapter = q_vector->adapter;
- union ixgbe_adv_tx_desc *tx_desc, *eop_desc;
- struct ixgbe_tx_buffer *tx_buffer_info;
+ struct ixgbe_tx_buffer *tx_buffer;
+ union ixgbe_adv_tx_desc *tx_desc;
unsigned int total_bytes = 0, total_packets = 0;
- u16 i, eop, count = 0;
+ unsigned int budget = q_vector->tx.work_limit;
+ u16 i = tx_ring->next_to_clean;
- i = tx_ring->next_to_clean;
- eop = tx_ring->tx_buffer_info[i].next_to_watch;
- eop_desc = IXGBE_TX_DESC_ADV(tx_ring, eop);
+ tx_buffer = &tx_ring->tx_buffer_info[i];
+ tx_desc = IXGBE_TX_DESC_ADV(tx_ring, i);
- while ((eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) &&
- (count < q_vector->tx.work_limit)) {
- bool cleaned = false;
- rmb(); /* read buffer_info after eop_desc */
- for ( ; !cleaned; count++) {
- tx_desc = IXGBE_TX_DESC_ADV(tx_ring, i);
- tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ for (; budget; budget--) {
+ union ixgbe_adv_tx_desc *eop_desc = tx_buffer->next_to_watch;
+
+ /* if next_to_watch is not set then there is no work pending */
+ if (!eop_desc)
+ break;
+
+ /* if DD is not set pending work has not been completed */
+ if (!(eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)))
+ break;
+
+ /* count the packet as being completed */
+ tx_ring->tx_stats.completed++;
+ /* clear next_to_watch to prevent false hangs */
+ tx_buffer->next_to_watch = NULL;
+
+ /* prevent any other reads prior to eop_desc being verified */
+ rmb();
+
+ do {
+ ixgbe_unmap_tx_resource(tx_ring, tx_buffer);
tx_desc->wb.status = 0;
- cleaned = (i == eop);
+ if (likely(tx_desc == eop_desc)) {
+ eop_desc = NULL;
+ dev_kfree_skb_any(tx_buffer->skb);
+ tx_buffer->skb = NULL;
+
+ total_bytes += tx_buffer->bytecount;
+ total_packets += tx_buffer->gso_segs;
+ }
+ tx_buffer++;
+ tx_desc++;
i++;
- if (i == tx_ring->count)
+ if (unlikely(i == tx_ring->count)) {
i = 0;
- if (cleaned && tx_buffer_info->skb) {
- total_bytes += tx_buffer_info->bytecount;
- total_packets += tx_buffer_info->gso_segs;
+ tx_buffer = tx_ring->tx_buffer_info;
+ tx_desc = IXGBE_TX_DESC_ADV(tx_ring, 0);
}
- ixgbe_unmap_and_free_tx_resource(tx_ring,
- tx_buffer_info);
- }
-
- tx_ring->tx_stats.completed++;
- eop = tx_ring->tx_buffer_info[i].next_to_watch;
- eop_desc = IXGBE_TX_DESC_ADV(tx_ring, eop);
+ } while (eop_desc);
}
tx_ring->next_to_clean = i;
+ u64_stats_update_begin(&tx_ring->syncp);
tx_ring->stats.bytes += total_bytes;
tx_ring->stats.packets += total_packets;
- u64_stats_update_begin(&tx_ring->syncp);
+ u64_stats_update_end(&tx_ring->syncp);
q_vector->tx.total_bytes += total_bytes;
q_vector->tx.total_packets += total_packets;
- u64_stats_update_end(&tx_ring->syncp);
if (check_for_tx_hang(tx_ring) && ixgbe_check_tx_hang(tx_ring)) {
/* schedule immediate reset if we believe we hung */
struct ixgbe_hw *hw = &adapter->hw;
- tx_desc = IXGBE_TX_DESC_ADV(tx_ring, eop);
+ tx_desc = IXGBE_TX_DESC_ADV(tx_ring, i);
e_err(drv, "Detected Tx Unit Hang\n"
" Tx Queue <%d>\n"
" TDH, TDT <%x>, <%x>\n"
@@ -857,8 +816,8 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
tx_ring->queue_index,
IXGBE_READ_REG(hw, IXGBE_TDH(tx_ring->reg_idx)),
IXGBE_READ_REG(hw, IXGBE_TDT(tx_ring->reg_idx)),
- tx_ring->next_to_use, eop,
- tx_ring->tx_buffer_info[eop].time_stamp, jiffies);
+ tx_ring->next_to_use, i,
+ tx_ring->tx_buffer_info[i].time_stamp, jiffies);
netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
@@ -874,7 +833,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
}
#define TX_WAKE_THRESHOLD (DESC_NEEDED * 2)
- if (unlikely(count && netif_carrier_ok(tx_ring->netdev) &&
+ if (unlikely(total_packets && netif_carrier_ok(tx_ring->netdev) &&
(ixgbe_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD))) {
/* Make sure that anybody stopping the queue after this
* sees the new next_to_clean.
@@ -887,7 +846,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
}
}
- return count < q_vector->tx.work_limit;
+ return !!budget;
}
#ifdef CONFIG_IXGBE_DCA
@@ -903,12 +862,12 @@ static void ixgbe_update_rx_dca(struct ixgbe_adapter *adapter,
switch (hw->mac.type) {
case ixgbe_mac_82598EB:
rxctrl &= ~IXGBE_DCA_RXCTRL_CPUID_MASK;
- rxctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
+ rxctrl |= dca3_get_tag(rx_ring->dev, cpu);
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
rxctrl &= ~IXGBE_DCA_RXCTRL_CPUID_MASK_82599;
- rxctrl |= (dca3_get_tag(&adapter->pdev->dev, cpu) <<
+ rxctrl |= (dca3_get_tag(rx_ring->dev, cpu) <<
IXGBE_DCA_RXCTRL_CPUID_SHIFT_82599);
break;
default:
@@ -932,7 +891,7 @@ static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter,
case ixgbe_mac_82598EB:
txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(reg_idx));
txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK;
- txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
+ txctrl |= dca3_get_tag(tx_ring->dev, cpu);
txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN;
IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(reg_idx), txctrl);
break;
@@ -940,7 +899,7 @@ static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter,
case ixgbe_mac_X540:
txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(reg_idx));
txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK_82599;
- txctrl |= (dca3_get_tag(&adapter->pdev->dev, cpu) <<
+ txctrl |= (dca3_get_tag(tx_ring->dev, cpu) <<
IXGBE_DCA_TXCTRL_CPUID_SHIFT_82599);
txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN;
IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(reg_idx), txctrl);
@@ -953,26 +912,17 @@ static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter,
static void ixgbe_update_dca(struct ixgbe_q_vector *q_vector)
{
struct ixgbe_adapter *adapter = q_vector->adapter;
+ struct ixgbe_ring *ring;
int cpu = get_cpu();
- long r_idx;
- int i;
if (q_vector->cpu == cpu)
goto out_no_update;
- r_idx = find_first_bit(q_vector->tx.idx, adapter->num_tx_queues);
- for (i = 0; i < q_vector->tx.count; i++) {
- ixgbe_update_tx_dca(adapter, adapter->tx_ring[r_idx], cpu);
- r_idx = find_next_bit(q_vector->tx.idx, adapter->num_tx_queues,
- r_idx + 1);
- }
+ for (ring = q_vector->tx.ring; ring != NULL; ring = ring->next)
+ ixgbe_update_tx_dca(adapter, ring, cpu);
- r_idx = find_first_bit(q_vector->rx.idx, adapter->num_rx_queues);
- for (i = 0; i < q_vector->rx.count; i++) {
- ixgbe_update_rx_dca(adapter, adapter->rx_ring[r_idx], cpu);
- r_idx = find_next_bit(q_vector->rx.idx, adapter->num_rx_queues,
- r_idx + 1);
- }
+ for (ring = q_vector->rx.ring; ring != NULL; ring = ring->next)
+ ixgbe_update_rx_dca(adapter, ring, cpu);
q_vector->cpu = cpu;
out_no_update:
@@ -1285,9 +1235,9 @@ static inline bool ixgbe_get_rsc_state(union ixgbe_adv_rx_desc *rx_desc)
IXGBE_RXDADV_RSCCNT_MASK);
}
-static void ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
struct ixgbe_ring *rx_ring,
- int *work_done, int work_to_do)
+ int budget)
{
struct ixgbe_adapter *adapter = q_vector->adapter;
union ixgbe_adv_rx_desc *rx_desc, *next_rxd;
@@ -1321,8 +1271,8 @@ static void ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
if (ring_is_rsc_enabled(rx_ring))
pkt_is_rsc = ixgbe_get_rsc_state(rx_desc);
- /* if this is a skb from previous receive DMA will be 0 */
- if (rx_buffer_info->dma) {
+ /* linear means we are building an skb from multiple pages */
+ if (!skb_is_nonlinear(skb)) {
u16 hlen;
if (pkt_is_rsc &&
!(staterr & IXGBE_RXD_STAT_EOP) &&
@@ -1376,7 +1326,7 @@ static void ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
skb->len += upper_len;
skb->data_len += upper_len;
- skb->truesize += upper_len;
+ skb->truesize += PAGE_SIZE / 2;
}
i++;
@@ -1459,17 +1409,19 @@ static void ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
if (ixgbe_rx_is_fcoe(adapter, rx_desc)) {
ddp_bytes = ixgbe_fcoe_ddp(adapter, rx_desc, skb,
staterr);
- if (!ddp_bytes)
+ if (!ddp_bytes) {
+ dev_kfree_skb_any(skb);
goto next_desc;
+ }
}
#endif /* IXGBE_FCOE */
ixgbe_receive_skb(q_vector, skb, staterr, rx_ring, rx_desc);
+ budget--;
next_desc:
rx_desc->wb.upper.status_error = 0;
- (*work_done)++;
- if (*work_done >= work_to_do)
+ if (!budget)
break;
/* return some buffers to hardware, one at a time is too slow */
@@ -1510,9 +1462,10 @@ next_desc:
u64_stats_update_end(&rx_ring->syncp);
q_vector->rx.total_packets += total_rx_packets;
q_vector->rx.total_bytes += total_rx_bytes;
+
+ return !!budget;
}
-static int ixgbe_clean_rxonly(struct napi_struct *, int);
/**
* ixgbe_configure_msix - Configure MSI-X hardware
* @adapter: board private structure
@@ -1523,61 +1476,46 @@ static int ixgbe_clean_rxonly(struct napi_struct *, int);
static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
{
struct ixgbe_q_vector *q_vector;
- int i, q_vectors, v_idx, r_idx;
+ int q_vectors, v_idx;
u32 mask;
q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+ /* Populate MSIX to EITR Select */
+ if (adapter->num_vfs > 32) {
+ u32 eitrsel = (1 << (adapter->num_vfs - 32)) - 1;
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITRSEL, eitrsel);
+ }
+
/*
* Populate the IVAR table and set the ITR values to the
* corresponding register.
*/
for (v_idx = 0; v_idx < q_vectors; v_idx++) {
+ struct ixgbe_ring *ring;
q_vector = adapter->q_vector[v_idx];
- /* XXX for_each_set_bit(...) */
- r_idx = find_first_bit(q_vector->rx.idx,
- adapter->num_rx_queues);
-
- for (i = 0; i < q_vector->rx.count; i++) {
- u8 reg_idx = adapter->rx_ring[r_idx]->reg_idx;
- ixgbe_set_ivar(adapter, 0, reg_idx, v_idx);
- r_idx = find_next_bit(q_vector->rx.idx,
- adapter->num_rx_queues,
- r_idx + 1);
- }
- r_idx = find_first_bit(q_vector->tx.idx,
- adapter->num_tx_queues);
-
- for (i = 0; i < q_vector->tx.count; i++) {
- u8 reg_idx = adapter->tx_ring[r_idx]->reg_idx;
- ixgbe_set_ivar(adapter, 1, reg_idx, v_idx);
- r_idx = find_next_bit(q_vector->tx.idx,
- adapter->num_tx_queues,
- r_idx + 1);
- }
- if (q_vector->tx.count && !q_vector->rx.count)
- /* tx only */
- q_vector->eitr = adapter->tx_eitr_param;
- else if (q_vector->rx.count)
- /* rx or mixed */
- q_vector->eitr = adapter->rx_eitr_param;
+ for (ring = q_vector->rx.ring; ring != NULL; ring = ring->next)
+ ixgbe_set_ivar(adapter, 0, ring->reg_idx, v_idx);
- ixgbe_write_eitr(q_vector);
- /* If ATR is enabled, set interrupt affinity */
- if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) {
- /*
- * Allocate the affinity_hint cpumask, assign the mask
- * for this vector, and set our affinity_hint for
- * this irq.
- */
- if (!alloc_cpumask_var(&q_vector->affinity_mask,
- GFP_KERNEL))
- return;
- cpumask_set_cpu(v_idx, q_vector->affinity_mask);
- irq_set_affinity_hint(adapter->msix_entries[v_idx].vector,
- q_vector->affinity_mask);
+ for (ring = q_vector->tx.ring; ring != NULL; ring = ring->next)
+ ixgbe_set_ivar(adapter, 1, ring->reg_idx, v_idx);
+
+ if (q_vector->tx.ring && !q_vector->rx.ring) {
+ /* tx only vector */
+ if (adapter->tx_itr_setting == 1)
+ q_vector->itr = IXGBE_10K_ITR;
+ else
+ q_vector->itr = adapter->tx_itr_setting;
+ } else {
+ /* rx or rx/tx vector */
+ if (adapter->rx_itr_setting == 1)
+ q_vector->itr = IXGBE_20K_ITR;
+ else
+ q_vector->itr = adapter->rx_itr_setting;
}
+
+ ixgbe_write_eitr(q_vector);
}
switch (adapter->hw.mac.type) {
@@ -1589,7 +1527,6 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
case ixgbe_mac_X540:
ixgbe_set_ivar(adapter, -1, 1, v_idx);
break;
-
default:
break;
}
@@ -1597,12 +1534,10 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
/* set up to autoclear timer, and the vectors */
mask = IXGBE_EIMS_ENABLE_MASK;
- if (adapter->num_vfs)
- mask &= ~(IXGBE_EIMS_OTHER |
- IXGBE_EIMS_MAILBOX |
- IXGBE_EIMS_LSC);
- else
- mask &= ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC);
+ mask &= ~(IXGBE_EIMS_OTHER |
+ IXGBE_EIMS_MAILBOX |
+ IXGBE_EIMS_LSC);
+
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, mask);
}
@@ -1647,7 +1582,7 @@ static void ixgbe_update_itr(struct ixgbe_q_vector *q_vector,
* 100-1249MB/s bulk (8000 ints/s)
*/
/* what was last interrupt timeslice? */
- timepassed_us = 1000000/q_vector->eitr;
+ timepassed_us = q_vector->itr >> 2;
bytes_perint = bytes / timepassed_us; /* bytes/usec */
switch (itr_setting) {
@@ -1688,7 +1623,7 @@ void ixgbe_write_eitr(struct ixgbe_q_vector *q_vector)
struct ixgbe_adapter *adapter = q_vector->adapter;
struct ixgbe_hw *hw = &adapter->hw;
int v_idx = q_vector->v_idx;
- u32 itr_reg = EITR_INTS_PER_SEC_TO_REG(q_vector->eitr);
+ u32 itr_reg = q_vector->itr;
switch (adapter->hw.mac.type) {
case ixgbe_mac_82598EB:
@@ -1698,15 +1633,6 @@ void ixgbe_write_eitr(struct ixgbe_q_vector *q_vector)
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
/*
- * 82599 and X540 can support a value of zero, so allow it for
- * max interrupt rate, but there is an errata where it can
- * not be zero with RSC
- */
- if (itr_reg == 8 &&
- !(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED))
- itr_reg = 0;
-
- /*
* set the WDIS bit to not clear the timer bits and cause an
* immediate assertion of the interrupt
*/
@@ -1720,7 +1646,7 @@ void ixgbe_write_eitr(struct ixgbe_q_vector *q_vector)
static void ixgbe_set_itr(struct ixgbe_q_vector *q_vector)
{
- u32 new_itr = q_vector->eitr;
+ u32 new_itr = q_vector->itr;
u8 current_itr;
ixgbe_update_itr(q_vector, &q_vector->tx);
@@ -1731,24 +1657,25 @@ static void ixgbe_set_itr(struct ixgbe_q_vector *q_vector)
switch (current_itr) {
/* counts and packets in update_itr are dependent on these numbers */
case lowest_latency:
- new_itr = 100000;
+ new_itr = IXGBE_100K_ITR;
break;
case low_latency:
- new_itr = 20000; /* aka hwitr = ~200 */
+ new_itr = IXGBE_20K_ITR;
break;
case bulk_latency:
- new_itr = 8000;
+ new_itr = IXGBE_8K_ITR;
break;
default:
break;
}
- if (new_itr != q_vector->eitr) {
+ if (new_itr != q_vector->itr) {
/* do an exponential smoothing */
- new_itr = ((q_vector->eitr * 9) + new_itr)/10;
+ new_itr = (10 * new_itr * q_vector->itr) /
+ ((9 * new_itr) + q_vector->itr);
/* save the algorithm value here */
- q_vector->eitr = new_itr;
+ q_vector->itr = new_itr & IXGBE_MAX_EITR;
ixgbe_write_eitr(q_vector);
}
@@ -1825,6 +1752,39 @@ static void ixgbe_check_fan_failure(struct ixgbe_adapter *adapter, u32 eicr)
}
}
+static void ixgbe_check_overtemp_event(struct ixgbe_adapter *adapter, u32 eicr)
+{
+ if (!(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE))
+ return;
+
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82599EB:
+ /*
+ * Need to check link state so complete overtemp check
+ * on service task
+ */
+ if (((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC)) &&
+ (!test_bit(__IXGBE_DOWN, &adapter->state))) {
+ adapter->interrupt_event = eicr;
+ adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_EVENT;
+ ixgbe_service_event_schedule(adapter);
+ return;
+ }
+ return;
+ case ixgbe_mac_X540:
+ if (!(eicr & IXGBE_EICR_TS))
+ return;
+ break;
+ default:
+ return;
+ }
+
+ e_crit(drv,
+ "Network adapter has been stopped because it has over heated. "
+ "Restart the computer. If the problem persists, "
+ "power off the system and replace the adapter\n");
+}
+
static void ixgbe_check_sfp_event(struct ixgbe_adapter *adapter, u32 eicr)
{
struct ixgbe_hw *hw = &adapter->hw;
@@ -1862,72 +1822,6 @@ static void ixgbe_check_lsc(struct ixgbe_adapter *adapter)
}
}
-static irqreturn_t ixgbe_msix_lsc(int irq, void *data)
-{
- struct ixgbe_adapter *adapter = data;
- struct ixgbe_hw *hw = &adapter->hw;
- u32 eicr;
-
- /*
- * Workaround for Silicon errata. Use clear-by-write instead
- * of clear-by-read. Reading with EICS will return the
- * interrupt causes without clearing, which later be done
- * with the write to EICR.
- */
- eicr = IXGBE_READ_REG(hw, IXGBE_EICS);
- IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr);
-
- if (eicr & IXGBE_EICR_LSC)
- ixgbe_check_lsc(adapter);
-
- if (eicr & IXGBE_EICR_MAILBOX)
- ixgbe_msg_task(adapter);
-
- switch (hw->mac.type) {
- case ixgbe_mac_82599EB:
- case ixgbe_mac_X540:
- /* Handle Flow Director Full threshold interrupt */
- if (eicr & IXGBE_EICR_FLOW_DIR) {
- int reinit_count = 0;
- int i;
- for (i = 0; i < adapter->num_tx_queues; i++) {
- struct ixgbe_ring *ring = adapter->tx_ring[i];
- if (test_and_clear_bit(__IXGBE_TX_FDIR_INIT_DONE,
- &ring->state))
- reinit_count++;
- }
- if (reinit_count) {
- /* no more flow director interrupts until after init */
- IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_FLOW_DIR);
- eicr &= ~IXGBE_EICR_FLOW_DIR;
- adapter->flags2 |= IXGBE_FLAG2_FDIR_REQUIRES_REINIT;
- ixgbe_service_event_schedule(adapter);
- }
- }
- ixgbe_check_sfp_event(adapter, eicr);
- if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) &&
- ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) {
- if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
- adapter->interrupt_event = eicr;
- adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_EVENT;
- ixgbe_service_event_schedule(adapter);
- }
- }
- break;
- default:
- break;
- }
-
- ixgbe_check_fan_failure(adapter, eicr);
-
- /* re-enable the original interrupt state, no lsc, no queues */
- if (!test_bit(__IXGBE_DOWN, &adapter->state))
- IXGBE_WRITE_REG(hw, IXGBE_EIMS, eicr &
- ~(IXGBE_EIMS_LSC | IXGBE_EIMS_RTX_QUEUE));
-
- return IRQ_HANDLED;
-}
-
static inline void ixgbe_irq_enable_queues(struct ixgbe_adapter *adapter,
u64 qmask)
{
@@ -1980,232 +1874,124 @@ static inline void ixgbe_irq_disable_queues(struct ixgbe_adapter *adapter,
/* skip the flush */
}
-static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data)
-{
- struct ixgbe_q_vector *q_vector = data;
- struct ixgbe_adapter *adapter = q_vector->adapter;
- struct ixgbe_ring *tx_ring;
- int i, r_idx;
-
- if (!q_vector->tx.count)
- return IRQ_HANDLED;
-
- r_idx = find_first_bit(q_vector->tx.idx, adapter->num_tx_queues);
- for (i = 0; i < q_vector->tx.count; i++) {
- tx_ring = adapter->tx_ring[r_idx];
- r_idx = find_next_bit(q_vector->tx.idx, adapter->num_tx_queues,
- r_idx + 1);
- }
-
- /* EIAM disabled interrupts (on this vector) for us */
- napi_schedule(&q_vector->napi);
-
- return IRQ_HANDLED;
-}
-
/**
- * ixgbe_msix_clean_rx - single unshared vector rx clean (all queues)
- * @irq: unused
- * @data: pointer to our q_vector struct for this interrupt vector
+ * ixgbe_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
**/
-static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data)
-{
- struct ixgbe_q_vector *q_vector = data;
- struct ixgbe_adapter *adapter = q_vector->adapter;
- struct ixgbe_ring *rx_ring;
- int r_idx;
- int i;
-
-#ifdef CONFIG_IXGBE_DCA
- if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
- ixgbe_update_dca(q_vector);
-#endif
-
- r_idx = find_first_bit(q_vector->rx.idx, adapter->num_rx_queues);
- for (i = 0; i < q_vector->rx.count; i++) {
- rx_ring = adapter->rx_ring[r_idx];
- r_idx = find_next_bit(q_vector->rx.idx, adapter->num_rx_queues,
- r_idx + 1);
- }
-
- if (!q_vector->rx.count)
- return IRQ_HANDLED;
-
- /* EIAM disabled interrupts (on this vector) for us */
- napi_schedule(&q_vector->napi);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t ixgbe_msix_clean_many(int irq, void *data)
+static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter, bool queues,
+ bool flush)
{
- struct ixgbe_q_vector *q_vector = data;
- struct ixgbe_adapter *adapter = q_vector->adapter;
- struct ixgbe_ring *ring;
- int r_idx;
- int i;
+ u32 mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE);
- if (!q_vector->tx.count && !q_vector->rx.count)
- return IRQ_HANDLED;
-
- r_idx = find_first_bit(q_vector->tx.idx, adapter->num_tx_queues);
- for (i = 0; i < q_vector->tx.count; i++) {
- ring = adapter->tx_ring[r_idx];
- r_idx = find_next_bit(q_vector->tx.idx, adapter->num_tx_queues,
- r_idx + 1);
- }
+ /* don't reenable LSC while waiting for link */
+ if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE)
+ mask &= ~IXGBE_EIMS_LSC;
- r_idx = find_first_bit(q_vector->rx.idx, adapter->num_rx_queues);
- for (i = 0; i < q_vector->rx.count; i++) {
- ring = adapter->rx_ring[r_idx];
- r_idx = find_next_bit(q_vector->rx.idx, adapter->num_rx_queues,
- r_idx + 1);
+ if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82599EB:
+ mask |= IXGBE_EIMS_GPI_SDP0;
+ break;
+ case ixgbe_mac_X540:
+ mask |= IXGBE_EIMS_TS;
+ break;
+ default:
+ break;
+ }
+ if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE)
+ mask |= IXGBE_EIMS_GPI_SDP1;
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82599EB:
+ mask |= IXGBE_EIMS_GPI_SDP1;
+ mask |= IXGBE_EIMS_GPI_SDP2;
+ case ixgbe_mac_X540:
+ mask |= IXGBE_EIMS_ECC;
+ mask |= IXGBE_EIMS_MAILBOX;
+ break;
+ default:
+ break;
}
+ if ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) &&
+ !(adapter->flags2 & IXGBE_FLAG2_FDIR_REQUIRES_REINIT))
+ mask |= IXGBE_EIMS_FLOW_DIR;
- /* EIAM disabled interrupts (on this vector) for us */
- napi_schedule(&q_vector->napi);
-
- return IRQ_HANDLED;
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask);
+ if (queues)
+ ixgbe_irq_enable_queues(adapter, ~0);
+ if (flush)
+ IXGBE_WRITE_FLUSH(&adapter->hw);
}
-/**
- * ixgbe_clean_rxonly - msix (aka one shot) rx clean routine
- * @napi: napi struct with our devices info in it
- * @budget: amount of work driver is allowed to do this pass, in packets
- *
- * This function is optimized for cleaning one queue only on a single
- * q_vector!!!
- **/
-static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget)
+static irqreturn_t ixgbe_msix_other(int irq, void *data)
{
- struct ixgbe_q_vector *q_vector =
- container_of(napi, struct ixgbe_q_vector, napi);
- struct ixgbe_adapter *adapter = q_vector->adapter;
- struct ixgbe_ring *rx_ring = NULL;
- int work_done = 0;
- long r_idx;
+ struct ixgbe_adapter *adapter = data;
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 eicr;
-#ifdef CONFIG_IXGBE_DCA
- if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
- ixgbe_update_dca(q_vector);
-#endif
+ /*
+ * Workaround for Silicon errata. Use clear-by-write instead
+ * of clear-by-read. Reading with EICS will return the
+ * interrupt causes without clearing, which later be done
+ * with the write to EICR.
+ */
+ eicr = IXGBE_READ_REG(hw, IXGBE_EICS);
+ IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr);
- r_idx = find_first_bit(q_vector->rx.idx, adapter->num_rx_queues);
- rx_ring = adapter->rx_ring[r_idx];
+ if (eicr & IXGBE_EICR_LSC)
+ ixgbe_check_lsc(adapter);
- ixgbe_clean_rx_irq(q_vector, rx_ring, &work_done, budget);
+ if (eicr & IXGBE_EICR_MAILBOX)
+ ixgbe_msg_task(adapter);
- /* If all Rx work done, exit the polling mode */
- if (work_done < budget) {
- napi_complete(napi);
- if (adapter->rx_itr_setting & 1)
- ixgbe_set_itr(q_vector);
- if (!test_bit(__IXGBE_DOWN, &adapter->state))
- ixgbe_irq_enable_queues(adapter,
- ((u64)1 << q_vector->v_idx));
+ switch (hw->mac.type) {
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
+ if (eicr & IXGBE_EICR_ECC)
+ e_info(link, "Received unrecoverable ECC Err, please "
+ "reboot\n");
+ /* Handle Flow Director Full threshold interrupt */
+ if (eicr & IXGBE_EICR_FLOW_DIR) {
+ int reinit_count = 0;
+ int i;
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ struct ixgbe_ring *ring = adapter->tx_ring[i];
+ if (test_and_clear_bit(__IXGBE_TX_FDIR_INIT_DONE,
+ &ring->state))
+ reinit_count++;
+ }
+ if (reinit_count) {
+ /* no more flow director interrupts until after init */
+ IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_FLOW_DIR);
+ adapter->flags2 |= IXGBE_FLAG2_FDIR_REQUIRES_REINIT;
+ ixgbe_service_event_schedule(adapter);
+ }
+ }
+ ixgbe_check_sfp_event(adapter, eicr);
+ ixgbe_check_overtemp_event(adapter, eicr);
+ break;
+ default:
+ break;
}
- return work_done;
-}
-
-/**
- * ixgbe_clean_rxtx_many - msix (aka one shot) rx clean routine
- * @napi: napi struct with our devices info in it
- * @budget: amount of work driver is allowed to do this pass, in packets
- *
- * This function will clean more than one rx queue associated with a
- * q_vector.
- **/
-static int ixgbe_clean_rxtx_many(struct napi_struct *napi, int budget)
-{
- struct ixgbe_q_vector *q_vector =
- container_of(napi, struct ixgbe_q_vector, napi);
- struct ixgbe_adapter *adapter = q_vector->adapter;
- struct ixgbe_ring *ring = NULL;
- int work_done = 0, i;
- long r_idx;
- bool tx_clean_complete = true;
-
-#ifdef CONFIG_IXGBE_DCA
- if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
- ixgbe_update_dca(q_vector);
-#endif
-
- r_idx = find_first_bit(q_vector->tx.idx, adapter->num_tx_queues);
- for (i = 0; i < q_vector->tx.count; i++) {
- ring = adapter->tx_ring[r_idx];
- tx_clean_complete &= ixgbe_clean_tx_irq(q_vector, ring);
- r_idx = find_next_bit(q_vector->tx.idx, adapter->num_tx_queues,
- r_idx + 1);
- }
+ ixgbe_check_fan_failure(adapter, eicr);
- /* attempt to distribute budget to each queue fairly, but don't allow
- * the budget to go below 1 because we'll exit polling */
- budget /= (q_vector->rx.count ?: 1);
- budget = max(budget, 1);
- r_idx = find_first_bit(q_vector->rx.idx, adapter->num_rx_queues);
- for (i = 0; i < q_vector->rx.count; i++) {
- ring = adapter->rx_ring[r_idx];
- ixgbe_clean_rx_irq(q_vector, ring, &work_done, budget);
- r_idx = find_next_bit(q_vector->rx.idx, adapter->num_rx_queues,
- r_idx + 1);
- }
-
- r_idx = find_first_bit(q_vector->rx.idx, adapter->num_rx_queues);
- ring = adapter->rx_ring[r_idx];
- /* If all Rx work done, exit the polling mode */
- if (work_done < budget) {
- napi_complete(napi);
- if (adapter->rx_itr_setting & 1)
- ixgbe_set_itr(q_vector);
- if (!test_bit(__IXGBE_DOWN, &adapter->state))
- ixgbe_irq_enable_queues(adapter,
- ((u64)1 << q_vector->v_idx));
- return 0;
- }
+ /* re-enable the original interrupt state, no lsc, no queues */
+ if (!test_bit(__IXGBE_DOWN, &adapter->state))
+ ixgbe_irq_enable(adapter, false, false);
- return work_done;
+ return IRQ_HANDLED;
}
-/**
- * ixgbe_clean_txonly - msix (aka one shot) tx clean routine
- * @napi: napi struct with our devices info in it
- * @budget: amount of work driver is allowed to do this pass, in packets
- *
- * This function is optimized for cleaning one queue only on a single
- * q_vector!!!
- **/
-static int ixgbe_clean_txonly(struct napi_struct *napi, int budget)
+static irqreturn_t ixgbe_msix_clean_rings(int irq, void *data)
{
- struct ixgbe_q_vector *q_vector =
- container_of(napi, struct ixgbe_q_vector, napi);
- struct ixgbe_adapter *adapter = q_vector->adapter;
- struct ixgbe_ring *tx_ring = NULL;
- int work_done = 0;
- long r_idx;
-
-#ifdef CONFIG_IXGBE_DCA
- if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
- ixgbe_update_dca(q_vector);
-#endif
-
- r_idx = find_first_bit(q_vector->tx.idx, adapter->num_tx_queues);
- tx_ring = adapter->tx_ring[r_idx];
+ struct ixgbe_q_vector *q_vector = data;
- if (!ixgbe_clean_tx_irq(q_vector, tx_ring))
- work_done = budget;
+ /* EIAM disabled interrupts (on this vector) for us */
- /* If all Tx work done, exit the polling mode */
- if (work_done < budget) {
- napi_complete(napi);
- if (adapter->tx_itr_setting & 1)
- ixgbe_set_itr(q_vector);
- if (!test_bit(__IXGBE_DOWN, &adapter->state))
- ixgbe_irq_enable_queues(adapter,
- ((u64)1 << q_vector->v_idx));
- }
+ if (q_vector->rx.ring || q_vector->tx.ring)
+ napi_schedule(&q_vector->napi);
- return work_done;
+ return IRQ_HANDLED;
}
static inline void map_vector_to_rxq(struct ixgbe_adapter *a, int v_idx,
@@ -2214,9 +2000,10 @@ static inline void map_vector_to_rxq(struct ixgbe_adapter *a, int v_idx,
struct ixgbe_q_vector *q_vector = a->q_vector[v_idx];
struct ixgbe_ring *rx_ring = a->rx_ring[r_idx];
- set_bit(r_idx, q_vector->rx.idx);
- q_vector->rx.count++;
rx_ring->q_vector = q_vector;
+ rx_ring->next = q_vector->rx.ring;
+ q_vector->rx.ring = rx_ring;
+ q_vector->rx.count++;
}
static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx,
@@ -2225,9 +2012,10 @@ static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx,
struct ixgbe_q_vector *q_vector = a->q_vector[v_idx];
struct ixgbe_ring *tx_ring = a->tx_ring[t_idx];
- set_bit(t_idx, q_vector->tx.idx);
- q_vector->tx.count++;
tx_ring->q_vector = q_vector;
+ tx_ring->next = q_vector->tx.ring;
+ q_vector->tx.ring = tx_ring;
+ q_vector->tx.count++;
q_vector->tx.work_limit = a->tx_work_limit;
}
@@ -2241,59 +2029,41 @@ static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx,
* group the rings as "efficiently" as possible. You would add new
* mapping configurations in here.
**/
-static int ixgbe_map_rings_to_vectors(struct ixgbe_adapter *adapter)
+static void ixgbe_map_rings_to_vectors(struct ixgbe_adapter *adapter)
{
- int q_vectors;
+ int q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+ int rxr_remaining = adapter->num_rx_queues, rxr_idx = 0;
+ int txr_remaining = adapter->num_tx_queues, txr_idx = 0;
int v_start = 0;
- int rxr_idx = 0, txr_idx = 0;
- int rxr_remaining = adapter->num_rx_queues;
- int txr_remaining = adapter->num_tx_queues;
- int i, j;
- int rqpv, tqpv;
- int err = 0;
- /* No mapping required if MSI-X is disabled. */
+ /* only one q_vector if MSI-X is disabled. */
if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED))
- goto out;
-
- q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+ q_vectors = 1;
/*
- * The ideal configuration...
- * We have enough vectors to map one per queue.
+ * If we don't have enough vectors for a 1-to-1 mapping, we'll have to
+ * group them so there are multiple queues per vector.
+ *
+ * Re-adjusting *qpv takes care of the remainder.
*/
- if (q_vectors == adapter->num_rx_queues + adapter->num_tx_queues) {
- for (; rxr_idx < rxr_remaining; v_start++, rxr_idx++)
+ for (; v_start < q_vectors && rxr_remaining; v_start++) {
+ int rqpv = DIV_ROUND_UP(rxr_remaining, q_vectors - v_start);
+ for (; rqpv; rqpv--, rxr_idx++, rxr_remaining--)
map_vector_to_rxq(adapter, v_start, rxr_idx);
-
- for (; txr_idx < txr_remaining; v_start++, txr_idx++)
- map_vector_to_txq(adapter, v_start, txr_idx);
-
- goto out;
}
/*
- * If we don't have enough vectors for a 1-to-1
- * mapping, we'll have to group them so there are
- * multiple queues per vector.
+ * If there are not enough q_vectors for each ring to have it's own
+ * vector then we must pair up Rx/Tx on a each vector
*/
- /* Re-adjusting *qpv takes care of the remainder. */
- for (i = v_start; i < q_vectors; i++) {
- rqpv = DIV_ROUND_UP(rxr_remaining, q_vectors - i);
- for (j = 0; j < rqpv; j++) {
- map_vector_to_rxq(adapter, i, rxr_idx);
- rxr_idx++;
- rxr_remaining--;
- }
- tqpv = DIV_ROUND_UP(txr_remaining, q_vectors - i);
- for (j = 0; j < tqpv; j++) {
- map_vector_to_txq(adapter, i, txr_idx);
- txr_idx++;
- txr_remaining--;
- }
+ if ((v_start + txr_remaining) > q_vectors)
+ v_start = 0;
+
+ for (; v_start < q_vectors && txr_remaining; v_start++) {
+ int tqpv = DIV_ROUND_UP(txr_remaining, q_vectors - v_start);
+ for (; tqpv; tqpv--, txr_idx++, txr_remaining--)
+ map_vector_to_txq(adapter, v_start, txr_idx);
}
-out:
- return err;
}
/**
@@ -2306,53 +2076,45 @@ out:
static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
- irqreturn_t (*handler)(int, void *);
- int i, vector, q_vectors, err;
+ int q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+ int vector, err;
int ri = 0, ti = 0;
- /* Decrement for Other and TCP Timer vectors */
- q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
-
- err = ixgbe_map_rings_to_vectors(adapter);
- if (err)
- return err;
-
-#define SET_HANDLER(_v) (((_v)->rx.count && (_v)->tx.count) \
- ? &ixgbe_msix_clean_many : \
- (_v)->rx.count ? &ixgbe_msix_clean_rx : \
- (_v)->tx.count ? &ixgbe_msix_clean_tx : \
- NULL)
for (vector = 0; vector < q_vectors; vector++) {
struct ixgbe_q_vector *q_vector = adapter->q_vector[vector];
- handler = SET_HANDLER(q_vector);
+ struct msix_entry *entry = &adapter->msix_entries[vector];
- if (handler == &ixgbe_msix_clean_rx) {
+ if (q_vector->tx.ring && q_vector->rx.ring) {
snprintf(q_vector->name, sizeof(q_vector->name) - 1,
- "%s-%s-%d", netdev->name, "rx", ri++);
- } else if (handler == &ixgbe_msix_clean_tx) {
+ "%s-%s-%d", netdev->name, "TxRx", ri++);
+ ti++;
+ } else if (q_vector->rx.ring) {
snprintf(q_vector->name, sizeof(q_vector->name) - 1,
- "%s-%s-%d", netdev->name, "tx", ti++);
- } else if (handler == &ixgbe_msix_clean_many) {
+ "%s-%s-%d", netdev->name, "rx", ri++);
+ } else if (q_vector->tx.ring) {
snprintf(q_vector->name, sizeof(q_vector->name) - 1,
- "%s-%s-%d", netdev->name, "TxRx", ri++);
- ti++;
+ "%s-%s-%d", netdev->name, "tx", ti++);
} else {
/* skip this unused q_vector */
continue;
}
- err = request_irq(adapter->msix_entries[vector].vector,
- handler, 0, q_vector->name,
- q_vector);
+ err = request_irq(entry->vector, &ixgbe_msix_clean_rings, 0,
+ q_vector->name, q_vector);
if (err) {
e_err(probe, "request_irq failed for MSIX interrupt "
"Error: %d\n", err);
goto free_queue_irqs;
}
+ /* If Flow Director is enabled, set interrupt affinity */
+ if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) {
+ /* assign the mask for this irq */
+ irq_set_affinity_hint(entry->vector,
+ q_vector->affinity_mask);
+ }
}
- sprintf(adapter->lsc_int_name, "%s:lsc", netdev->name);
err = request_irq(adapter->msix_entries[vector].vector,
- ixgbe_msix_lsc, 0, adapter->lsc_int_name, adapter);
+ ixgbe_msix_other, 0, netdev->name, adapter);
if (err) {
e_err(probe, "request_irq for msix_lsc failed: %d\n", err);
goto free_queue_irqs;
@@ -2361,9 +2123,13 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter)
return 0;
free_queue_irqs:
- for (i = vector - 1; i >= 0; i--)
- free_irq(adapter->msix_entries[--vector].vector,
- adapter->q_vector[i]);
+ while (vector) {
+ vector--;
+ irq_set_affinity_hint(adapter->msix_entries[vector].vector,
+ NULL);
+ free_irq(adapter->msix_entries[vector].vector,
+ adapter->q_vector[vector]);
+ }
adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED;
pci_disable_msix(adapter->pdev);
kfree(adapter->msix_entries);
@@ -2372,47 +2138,6 @@ free_queue_irqs:
}
/**
- * ixgbe_irq_enable - Enable default interrupt generation settings
- * @adapter: board private structure
- **/
-static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter, bool queues,
- bool flush)
-{
- u32 mask;
-
- mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE);
- if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
- mask |= IXGBE_EIMS_GPI_SDP0;
- if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE)
- mask |= IXGBE_EIMS_GPI_SDP1;
- switch (adapter->hw.mac.type) {
- case ixgbe_mac_82599EB:
- case ixgbe_mac_X540:
- mask |= IXGBE_EIMS_ECC;
- mask |= IXGBE_EIMS_GPI_SDP1;
- mask |= IXGBE_EIMS_GPI_SDP2;
- if (adapter->num_vfs)
- mask |= IXGBE_EIMS_MAILBOX;
- break;
- default:
- break;
- }
- if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE)
- mask |= IXGBE_EIMS_FLOW_DIR;
-
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask);
- if (queues)
- ixgbe_irq_enable_queues(adapter, ~0);
- if (flush)
- IXGBE_WRITE_FLUSH(&adapter->hw);
-
- if (adapter->num_vfs > 32) {
- u32 eitrsel = (1 << (adapter->num_vfs - 32)) - 1;
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITRSEL, eitrsel);
- }
-}
-
-/**
* ixgbe_intr - legacy mode Interrupt Handler
* @irq: interrupt number
* @data: pointer to a network interface device structure
@@ -2452,14 +2177,12 @@ static irqreturn_t ixgbe_intr(int irq, void *data)
switch (hw->mac.type) {
case ixgbe_mac_82599EB:
ixgbe_check_sfp_event(adapter, eicr);
- if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) &&
- ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) {
- if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
- adapter->interrupt_event = eicr;
- adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_EVENT;
- ixgbe_service_event_schedule(adapter);
- }
- }
+ /* Fall through */
+ case ixgbe_mac_X540:
+ if (eicr & IXGBE_EICR_ECC)
+ e_info(link, "Received unrecoverable ECC err, please "
+ "reboot\n");
+ ixgbe_check_overtemp_event(adapter, eicr);
break;
default:
break;
@@ -2485,14 +2208,26 @@ static irqreturn_t ixgbe_intr(int irq, void *data)
static inline void ixgbe_reset_q_vectors(struct ixgbe_adapter *adapter)
{
- int i, q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+ int q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+ int i;
+
+ /* legacy and MSI only use one vector */
+ if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED))
+ q_vectors = 1;
+
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ adapter->rx_ring[i]->q_vector = NULL;
+ adapter->rx_ring[i]->next = NULL;
+ }
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ adapter->tx_ring[i]->q_vector = NULL;
+ adapter->tx_ring[i]->next = NULL;
+ }
for (i = 0; i < q_vectors; i++) {
struct ixgbe_q_vector *q_vector = adapter->q_vector[i];
- bitmap_zero(q_vector->rx.idx, MAX_RX_QUEUES);
- bitmap_zero(q_vector->tx.idx, MAX_TX_QUEUES);
- q_vector->rx.count = 0;
- q_vector->tx.count = 0;
+ memset(&q_vector->rx, 0, sizeof(struct ixgbe_ring_container));
+ memset(&q_vector->tx, 0, sizeof(struct ixgbe_ring_container));
}
}
@@ -2508,19 +2243,25 @@ static int ixgbe_request_irq(struct ixgbe_adapter *adapter)
struct net_device *netdev = adapter->netdev;
int err;
- if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+ /* map all of the rings to the q_vectors */
+ ixgbe_map_rings_to_vectors(adapter);
+
+ if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
err = ixgbe_request_msix_irqs(adapter);
- } else if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) {
+ else if (adapter->flags & IXGBE_FLAG_MSI_ENABLED)
err = request_irq(adapter->pdev->irq, ixgbe_intr, 0,
netdev->name, adapter);
- } else {
+ else
err = request_irq(adapter->pdev->irq, ixgbe_intr, IRQF_SHARED,
netdev->name, adapter);
- }
- if (err)
+ if (err) {
e_err(probe, "request_irq failed, Error %d\n", err);
+ /* place q_vectors and rings back into a known good state */
+ ixgbe_reset_q_vectors(adapter);
+ }
+
return err;
}
@@ -2530,25 +2271,29 @@ static void ixgbe_free_irq(struct ixgbe_adapter *adapter)
int i, q_vectors;
q_vectors = adapter->num_msix_vectors;
-
i = q_vectors - 1;
free_irq(adapter->msix_entries[i].vector, adapter);
-
i--;
+
for (; i >= 0; i--) {
/* free only the irqs that were actually requested */
- if (!adapter->q_vector[i]->rx.count &&
- !adapter->q_vector[i]->tx.count)
+ if (!adapter->q_vector[i]->rx.ring &&
+ !adapter->q_vector[i]->tx.ring)
continue;
+ /* clear the affinity_mask in the IRQ descriptor */
+ irq_set_affinity_hint(adapter->msix_entries[i].vector,
+ NULL);
+
free_irq(adapter->msix_entries[i].vector,
adapter->q_vector[i]);
}
-
- ixgbe_reset_q_vectors(adapter);
} else {
free_irq(adapter->pdev->irq, adapter);
}
+
+ /* clear q_vector state information */
+ ixgbe_reset_q_vectors(adapter);
}
/**
@@ -2566,8 +2311,6 @@ static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFF0000);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), ~0);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0);
- if (adapter->num_vfs > 32)
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITRSEL, 0);
break;
default:
break;
@@ -2588,17 +2331,19 @@ static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter)
**/
static void ixgbe_configure_msi_and_legacy(struct ixgbe_adapter *adapter)
{
- struct ixgbe_hw *hw = &adapter->hw;
+ struct ixgbe_q_vector *q_vector = adapter->q_vector[0];
- IXGBE_WRITE_REG(hw, IXGBE_EITR(0),
- EITR_INTS_PER_SEC_TO_REG(adapter->rx_eitr_param));
+ /* rx/tx vector */
+ if (adapter->rx_itr_setting == 1)
+ q_vector->itr = IXGBE_20K_ITR;
+ else
+ q_vector->itr = adapter->rx_itr_setting;
+
+ ixgbe_write_eitr(q_vector);
ixgbe_set_ivar(adapter, 0, 0, 0);
ixgbe_set_ivar(adapter, 1, 0, 0);
- map_vector_to_rxq(adapter, 0, 0);
- map_vector_to_txq(adapter, 0, 0);
-
e_info(hw, "Legacy interrupt IVAR setup done\n");
}
@@ -2615,13 +2360,11 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
struct ixgbe_hw *hw = &adapter->hw;
u64 tdba = ring->dma;
int wait_loop = 10;
- u32 txdctl;
+ u32 txdctl = IXGBE_TXDCTL_ENABLE;
u8 reg_idx = ring->reg_idx;
/* disable queue to avoid issues while updating state */
- txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx));
- IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx),
- txdctl & ~IXGBE_TXDCTL_ENABLE);
+ IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), 0);
IXGBE_WRITE_FLUSH(hw);
IXGBE_WRITE_REG(hw, IXGBE_TDBAL(reg_idx),
@@ -2633,18 +2376,22 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
IXGBE_WRITE_REG(hw, IXGBE_TDT(reg_idx), 0);
ring->tail = hw->hw_addr + IXGBE_TDT(reg_idx);
- /* configure fetching thresholds */
- if (adapter->rx_itr_setting == 0) {
- /* cannot set wthresh when itr==0 */
- txdctl &= ~0x007F0000;
- } else {
- /* enable WTHRESH=8 descriptors, to encourage burst writeback */
- txdctl |= (8 << 16);
- }
- if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
- /* PThresh workaround for Tx hang with DFP enabled. */
- txdctl |= 32;
- }
+ /*
+ * set WTHRESH to encourage burst writeback, it should not be set
+ * higher than 1 when ITR is 0 as it could cause false TX hangs
+ *
+ * In order to avoid issues WTHRESH + PTHRESH should always be equal
+ * to or less than the number of on chip descriptors, which is
+ * currently 40.
+ */
+ if (!adapter->tx_itr_setting || !adapter->rx_itr_setting)
+ txdctl |= (1 << 16); /* WTHRESH = 1 */
+ else
+ txdctl |= (8 << 16); /* WTHRESH = 8 */
+
+ /* PTHRESH=32 is needed to avoid a Tx hang with DFP enabled. */
+ txdctl |= (1 << 8) | /* HTHRESH = 1 */
+ 32; /* PTHRESH = 32 */
/* reinitialize flowdirector state */
if ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) &&
@@ -2659,7 +2406,6 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
/* enable queue */
- txdctl |= IXGBE_TXDCTL_ENABLE;
IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
/* TXDCTL.EN will return 0 on 82598 if link is down, so skip it */
@@ -2897,9 +2643,9 @@ static void ixgbe_configure_rscctl(struct ixgbe_adapter *adapter,
rscctrl |= IXGBE_RSCCTL_MAXDESC_1;
#endif
} else {
- if (rx_buf_len < IXGBE_RXBUFFER_4096)
+ if (rx_buf_len < IXGBE_RXBUFFER_4K)
rscctrl |= IXGBE_RSCCTL_MAXDESC_16;
- else if (rx_buf_len < IXGBE_RXBUFFER_8192)
+ else if (rx_buf_len < IXGBE_RXBUFFER_8K)
rscctrl |= IXGBE_RSCCTL_MAXDESC_8;
else
rscctrl |= IXGBE_RSCCTL_MAXDESC_4;
@@ -3070,6 +2816,7 @@ static void ixgbe_configure_virtualization(struct ixgbe_adapter *adapter)
u32 vt_reg_bits;
u32 reg_offset, vf_shift;
u32 vmdctl;
+ int i;
if (!(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
return;
@@ -3105,9 +2852,13 @@ static void ixgbe_configure_virtualization(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN);
/* Enable MAC Anti-Spoofing */
hw->mac.ops.set_mac_anti_spoofing(hw,
- (adapter->antispoofing_enabled =
- (adapter->num_vfs != 0)),
+ (adapter->num_vfs != 0),
adapter->num_vfs);
+ /* For VFs that have spoof checking turned off */
+ for (i = 0; i < adapter->num_vfs; i++) {
+ if (!adapter->vfinfo[i].spoofchk_enabled)
+ ixgbe_ndo_set_vf_spoofchk(adapter->netdev, i, false);
+ }
}
static void ixgbe_set_rx_buffer_len(struct ixgbe_adapter *adapter)
@@ -3132,17 +2883,6 @@ static void ixgbe_set_rx_buffer_len(struct ixgbe_adapter *adapter)
if (hw->mac.type == ixgbe_mac_82599EB)
adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED;
- /* Set the RX buffer length according to the mode */
- if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
- rx_buf_len = IXGBE_RX_HDR_SIZE;
- } else {
- if (!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) &&
- (netdev->mtu <= ETH_DATA_LEN))
- rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE;
- else
- rx_buf_len = ALIGN(max_frame + VLAN_HLEN, 1024);
- }
-
#ifdef IXGBE_FCOE
/* adjust max frame to be able to do baby jumbo for FCoE */
if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) &&
@@ -3158,6 +2898,30 @@ static void ixgbe_set_rx_buffer_len(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd);
}
+ /* MHADD will allow an extra 4 bytes past for vlan tagged frames */
+ max_frame += VLAN_HLEN;
+
+ /* Set the RX buffer length according to the mode */
+ if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+ rx_buf_len = IXGBE_RX_HDR_SIZE;
+ } else {
+ if (!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) &&
+ (netdev->mtu <= ETH_DATA_LEN))
+ rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE;
+ /*
+ * Make best use of allocation by using all but 1K of a
+ * power of 2 allocation that will be used for skb->head.
+ */
+ else if (max_frame <= IXGBE_RXBUFFER_3K)
+ rx_buf_len = IXGBE_RXBUFFER_3K;
+ else if (max_frame <= IXGBE_RXBUFFER_7K)
+ rx_buf_len = IXGBE_RXBUFFER_7K;
+ else if (max_frame <= IXGBE_RXBUFFER_15K)
+ rx_buf_len = IXGBE_RXBUFFER_15K;
+ else
+ rx_buf_len = IXGBE_MAX_RXBUFFER;
+ }
+
hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0);
/* set jumbo enable since MHADD.MFS is keeping size locked at max_frame */
hlreg0 |= IXGBE_HLREG0_JUMBOEN;
@@ -3531,19 +3295,8 @@ static void ixgbe_napi_enable_all(struct ixgbe_adapter *adapter)
q_vectors = 1;
for (q_idx = 0; q_idx < q_vectors; q_idx++) {
- struct napi_struct *napi;
q_vector = adapter->q_vector[q_idx];
- napi = &q_vector->napi;
- if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
- if (!q_vector->rx.count || !q_vector->tx.count) {
- if (q_vector->tx.count == 1)
- napi->poll = &ixgbe_clean_txonly;
- else if (q_vector->rx.count == 1)
- napi->poll = &ixgbe_clean_rxonly;
- }
- }
-
- napi_enable(napi);
+ napi_enable(&q_vector->napi);
}
}
@@ -3594,7 +3347,7 @@ static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter)
/* reconfigure the hardware */
if (adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE) {
-#ifdef CONFIG_FCOE
+#ifdef IXGBE_FCOE
if (adapter->netdev->features & NETIF_F_FCOE_MTU)
max_frame = max(max_frame, IXGBE_FCOE_JUMBO_FRAME_SIZE);
#endif
@@ -3606,12 +3359,20 @@ static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter)
} else {
struct net_device *dev = adapter->netdev;
- if (adapter->ixgbe_ieee_ets)
- dev->dcbnl_ops->ieee_setets(dev,
- adapter->ixgbe_ieee_ets);
- if (adapter->ixgbe_ieee_pfc)
- dev->dcbnl_ops->ieee_setpfc(dev,
- adapter->ixgbe_ieee_pfc);
+ if (adapter->ixgbe_ieee_ets) {
+ struct ieee_ets *ets = adapter->ixgbe_ieee_ets;
+ int max_frame = dev->mtu + ETH_HLEN + ETH_FCS_LEN;
+
+ ixgbe_dcb_hw_ets(&adapter->hw, ets, max_frame);
+ }
+
+ if (adapter->ixgbe_ieee_pfc) {
+ struct ieee_pfc *pfc = adapter->ixgbe_ieee_pfc;
+ u8 *prio_tc = adapter->ixgbe_ieee_ets->prio_tc;
+
+ ixgbe_dcb_hw_pfc_config(&adapter->hw, pfc->pfc_en,
+ prio_tc);
+ }
}
/* Enable RSS Hash per TC */
@@ -3631,20 +3392,142 @@ static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(hw, IXGBE_RQTC, reg);
}
}
+#endif
+
+/* Additional bittime to account for IXGBE framing */
+#define IXGBE_ETH_FRAMING 20
+
+/*
+ * ixgbe_hpbthresh - calculate high water mark for flow control
+ *
+ * @adapter: board private structure to calculate for
+ * @pb - packet buffer to calculate
+ */
+static int ixgbe_hpbthresh(struct ixgbe_adapter *adapter, int pb)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct net_device *dev = adapter->netdev;
+ int link, tc, kb, marker;
+ u32 dv_id, rx_pba;
+
+ /* Calculate max LAN frame size */
+ tc = link = dev->mtu + ETH_HLEN + ETH_FCS_LEN + IXGBE_ETH_FRAMING;
+
+#ifdef IXGBE_FCOE
+ /* FCoE traffic class uses FCOE jumbo frames */
+ if (dev->features & NETIF_F_FCOE_MTU) {
+ int fcoe_pb = 0;
+
+#ifdef CONFIG_IXGBE_DCB
+ fcoe_pb = netdev_get_prio_tc_map(dev, adapter->fcoe.up);
#endif
+ if (fcoe_pb == pb && tc < IXGBE_FCOE_JUMBO_FRAME_SIZE)
+ tc = IXGBE_FCOE_JUMBO_FRAME_SIZE;
+ }
+#endif
-static void ixgbe_configure_pb(struct ixgbe_adapter *adapter)
+ /* Calculate delay value for device */
+ switch (hw->mac.type) {
+ case ixgbe_mac_X540:
+ dv_id = IXGBE_DV_X540(link, tc);
+ break;
+ default:
+ dv_id = IXGBE_DV(link, tc);
+ break;
+ }
+
+ /* Loopback switch introduces additional latency */
+ if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
+ dv_id += IXGBE_B2BT(tc);
+
+ /* Delay value is calculated in bit times convert to KB */
+ kb = IXGBE_BT2KB(dv_id);
+ rx_pba = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(pb)) >> 10;
+
+ marker = rx_pba - kb;
+
+ /* It is possible that the packet buffer is not large enough
+ * to provide required headroom. In this case throw an error
+ * to user and a do the best we can.
+ */
+ if (marker < 0) {
+ e_warn(drv, "Packet Buffer(%i) can not provide enough"
+ "headroom to support flow control."
+ "Decrease MTU or number of traffic classes\n", pb);
+ marker = tc + 1;
+ }
+
+ return marker;
+}
+
+/*
+ * ixgbe_lpbthresh - calculate low water mark for for flow control
+ *
+ * @adapter: board private structure to calculate for
+ * @pb - packet buffer to calculate
+ */
+static int ixgbe_lpbthresh(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct net_device *dev = adapter->netdev;
+ int tc;
+ u32 dv_id;
+
+ /* Calculate max LAN frame size */
+ tc = dev->mtu + ETH_HLEN + ETH_FCS_LEN;
+
+ /* Calculate delay value for device */
+ switch (hw->mac.type) {
+ case ixgbe_mac_X540:
+ dv_id = IXGBE_LOW_DV_X540(tc);
+ break;
+ default:
+ dv_id = IXGBE_LOW_DV(tc);
+ break;
+ }
+
+ /* Delay value is calculated in bit times convert to KB */
+ return IXGBE_BT2KB(dv_id);
+}
+
+/*
+ * ixgbe_pbthresh_setup - calculate and setup high low water marks
+ */
+static void ixgbe_pbthresh_setup(struct ixgbe_adapter *adapter)
{
- int hdrm = 0;
+ struct ixgbe_hw *hw = &adapter->hw;
int num_tc = netdev_get_num_tc(adapter->netdev);
+ int i;
+
+ if (!num_tc)
+ num_tc = 1;
+
+ hw->fc.low_water = ixgbe_lpbthresh(adapter);
+
+ for (i = 0; i < num_tc; i++) {
+ hw->fc.high_water[i] = ixgbe_hpbthresh(adapter, i);
+
+ /* Low water marks must not be larger than high water marks */
+ if (hw->fc.low_water > hw->fc.high_water[i])
+ hw->fc.low_water = 0;
+ }
+}
+
+static void ixgbe_configure_pb(struct ixgbe_adapter *adapter)
+{
struct ixgbe_hw *hw = &adapter->hw;
+ int hdrm;
+ u8 tc = netdev_get_num_tc(adapter->netdev);
if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||
adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
- hdrm = 64 << adapter->fdir_pballoc;
+ hdrm = 32 << adapter->fdir_pballoc;
+ else
+ hdrm = 0;
- hw->mac.ops.set_rxpba(&adapter->hw, num_tc, hdrm, PBA_STRATEGY_EQUAL);
+ hw->mac.ops.set_rxpba(hw, tc, hdrm, PBA_STRATEGY_EQUAL);
+ ixgbe_pbthresh_setup(adapter);
}
static void ixgbe_fdir_filter_restore(struct ixgbe_adapter *adapter)
@@ -3673,16 +3556,12 @@ static void ixgbe_fdir_filter_restore(struct ixgbe_adapter *adapter)
static void ixgbe_configure(struct ixgbe_adapter *adapter)
{
- struct net_device *netdev = adapter->netdev;
- struct ixgbe_hw *hw = &adapter->hw;
- int i;
-
ixgbe_configure_pb(adapter);
#ifdef CONFIG_IXGBE_DCB
ixgbe_configure_dcb(adapter);
#endif
- ixgbe_set_rx_mode(netdev);
+ ixgbe_set_rx_mode(adapter->netdev);
ixgbe_restore_vlan(adapter);
#ifdef IXGBE_FCOE
@@ -3691,15 +3570,14 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter)
#endif /* IXGBE_FCOE */
if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) {
- for (i = 0; i < adapter->num_tx_queues; i++)
- adapter->tx_ring[i]->atr_sample_rate =
- adapter->atr_sample_rate;
- ixgbe_init_fdir_signature_82599(hw, adapter->fdir_pballoc);
+ ixgbe_init_fdir_signature_82599(&adapter->hw,
+ adapter->fdir_pballoc);
} else if (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) {
ixgbe_init_fdir_perfect_82599(&adapter->hw,
adapter->fdir_pballoc);
ixgbe_fdir_filter_restore(adapter);
}
+
ixgbe_configure_virtualization(adapter);
ixgbe_configure_tx(adapter);
@@ -3718,6 +3596,9 @@ static inline bool ixgbe_is_sfp(struct ixgbe_hw *hw)
case ixgbe_phy_sfp_active_unknown:
case ixgbe_phy_sfp_ftl_active:
return true;
+ case ixgbe_phy_nl:
+ if (hw->mac.type == ixgbe_mac_82598EB)
+ return true;
default:
return false;
}
@@ -3810,6 +3691,20 @@ static void ixgbe_setup_gpie(struct ixgbe_adapter *adapter)
gpie |= IXGBE_GPIE_VTMODE_64;
}
+ /* Enable Thermal over heat sensor interrupt */
+ if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) {
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82599EB:
+ gpie |= IXGBE_SDP0_GPIEN;
+ break;
+ case ixgbe_mac_X540:
+ gpie |= IXGBE_EIMS_TS;
+ break;
+ default:
+ break;
+ }
+ }
+
/* Enable fan failure interrupt */
if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE)
gpie |= IXGBE_SDP1_GPIEN;
@@ -3822,7 +3717,7 @@ static void ixgbe_setup_gpie(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
}
-static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
+static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
int err;
@@ -3881,8 +3776,6 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
ctrl_ext |= IXGBE_CTRL_EXT_PFRSTD;
IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
-
- return 0;
}
void ixgbe_reinit_locked(struct ixgbe_adapter *adapter)
@@ -3906,12 +3799,12 @@ void ixgbe_reinit_locked(struct ixgbe_adapter *adapter)
clear_bit(__IXGBE_RESETTING, &adapter->state);
}
-int ixgbe_up(struct ixgbe_adapter *adapter)
+void ixgbe_up(struct ixgbe_adapter *adapter)
{
/* hardware has been reset, we need to reload some things */
ixgbe_configure(adapter);
- return ixgbe_up_complete(adapter);
+ ixgbe_up_complete(adapter);
}
void ixgbe_reset(struct ixgbe_adapter *adapter)
@@ -4098,7 +3991,6 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
struct ixgbe_hw *hw = &adapter->hw;
u32 rxctrl;
int i;
- int num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
/* signal that we are down to the interrupt handler */
set_bit(__IXGBE_DOWN, &adapter->state);
@@ -4130,26 +4022,19 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
del_timer_sync(&adapter->service_timer);
- /* disable receive for all VFs and wait one second */
if (adapter->num_vfs) {
- /* ping all the active vfs to let them know we are going down */
- ixgbe_ping_all_vfs(adapter);
-
- /* Disable all VFTE/VFRE TX/RX */
- ixgbe_disable_tx_rx(adapter);
+ /* Clear EITR Select mapping */
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITRSEL, 0);
/* Mark all the VFs as inactive */
for (i = 0 ; i < adapter->num_vfs; i++)
adapter->vfinfo[i].clear_to_send = 0;
- }
- /* Cleanup the affinity_hint CPU mask memory and callback */
- for (i = 0; i < num_q_vectors; i++) {
- struct ixgbe_q_vector *q_vector = adapter->q_vector[i];
- /* clear the affinity_mask in the IRQ descriptor */
- irq_set_affinity_hint(adapter->msix_entries[i]. vector, NULL);
- /* release the CPU mask memory */
- free_cpumask_var(q_vector->affinity_mask);
+ /* ping all the active vfs to let them know we are going down */
+ ixgbe_ping_all_vfs(adapter);
+
+ /* Disable all VFTE/VFRE TX/RX */
+ ixgbe_disable_tx_rx(adapter);
}
/* disable transmits in the hardware now that interrupts are off */
@@ -4201,28 +4086,41 @@ static int ixgbe_poll(struct napi_struct *napi, int budget)
struct ixgbe_q_vector *q_vector =
container_of(napi, struct ixgbe_q_vector, napi);
struct ixgbe_adapter *adapter = q_vector->adapter;
- int tx_clean_complete, work_done = 0;
+ struct ixgbe_ring *ring;
+ int per_ring_budget;
+ bool clean_complete = true;
#ifdef CONFIG_IXGBE_DCA
if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
ixgbe_update_dca(q_vector);
#endif
- tx_clean_complete = ixgbe_clean_tx_irq(q_vector, adapter->tx_ring[0]);
- ixgbe_clean_rx_irq(q_vector, adapter->rx_ring[0], &work_done, budget);
+ for (ring = q_vector->tx.ring; ring != NULL; ring = ring->next)
+ clean_complete &= !!ixgbe_clean_tx_irq(q_vector, ring);
- if (!tx_clean_complete)
- work_done = budget;
+ /* attempt to distribute budget to each queue fairly, but don't allow
+ * the budget to go below 1 because we'll exit polling */
+ if (q_vector->rx.count > 1)
+ per_ring_budget = max(budget/q_vector->rx.count, 1);
+ else
+ per_ring_budget = budget;
- /* If budget not fully consumed, exit the polling mode */
- if (work_done < budget) {
- napi_complete(napi);
- if (adapter->rx_itr_setting & 1)
- ixgbe_set_itr(q_vector);
- if (!test_bit(__IXGBE_DOWN, &adapter->state))
- ixgbe_irq_enable_queues(adapter, IXGBE_EIMS_RTX_QUEUE);
- }
- return work_done;
+ for (ring = q_vector->rx.ring; ring != NULL; ring = ring->next)
+ clean_complete &= ixgbe_clean_rx_irq(q_vector, ring,
+ per_ring_budget);
+
+ /* If all work not completed, return budget and keep polling */
+ if (!clean_complete)
+ return budget;
+
+ /* all work done, exit the polling mode */
+ napi_complete(napi);
+ if (adapter->rx_itr_setting & 1)
+ ixgbe_set_itr(q_vector);
+ if (!test_bit(__IXGBE_DOWN, &adapter->state))
+ ixgbe_irq_enable_queues(adapter, ((u64)1 << q_vector->v_idx));
+
+ return 0;
}
/**
@@ -4350,7 +4248,6 @@ static inline bool ixgbe_set_dcb_queues(struct ixgbe_adapter *adapter)
q = min((int)num_online_cpus(), per_tc_q);
for (i = 0; i < tcs; i++) {
- netdev_set_prio_tc_map(dev, i, i);
netdev_set_tc_queue(dev, i, q, offset);
offset += q;
}
@@ -4534,7 +4431,7 @@ static void ixgbe_get_first_reg_idx(struct ixgbe_adapter *adapter, u8 tc,
break;
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
- if (num_tcs == 8) {
+ if (num_tcs > 4) {
if (tc < 3) {
*tx = tc << 5;
*rx = tc << 4;
@@ -4545,7 +4442,7 @@ static void ixgbe_get_first_reg_idx(struct ixgbe_adapter *adapter, u8 tc,
*tx = ((tc + 8) << 3);
*rx = tc << 4;
}
- } else if (num_tcs == 4) {
+ } else {
*rx = tc << 5;
switch (tc) {
case 0:
@@ -4863,19 +4760,15 @@ out:
**/
static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter)
{
- int q_idx, num_q_vectors;
+ int v_idx, num_q_vectors;
struct ixgbe_q_vector *q_vector;
- int (*poll)(struct napi_struct *, int);
- if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+ if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
- poll = &ixgbe_clean_rxtx_many;
- } else {
+ else
num_q_vectors = 1;
- poll = &ixgbe_poll;
- }
- for (q_idx = 0; q_idx < num_q_vectors; q_idx++) {
+ for (v_idx = 0; v_idx < num_q_vectors; v_idx++) {
q_vector = kzalloc_node(sizeof(struct ixgbe_q_vector),
GFP_KERNEL, adapter->node);
if (!q_vector)
@@ -4883,25 +4776,29 @@ static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter)
GFP_KERNEL);
if (!q_vector)
goto err_out;
+
q_vector->adapter = adapter;
- if (q_vector->tx.count && !q_vector->rx.count)
- q_vector->eitr = adapter->tx_eitr_param;
- else
- q_vector->eitr = adapter->rx_eitr_param;
- q_vector->v_idx = q_idx;
- netif_napi_add(adapter->netdev, &q_vector->napi, (*poll), 64);
- adapter->q_vector[q_idx] = q_vector;
+ q_vector->v_idx = v_idx;
+
+ /* Allocate the affinity_hint cpumask, configure the mask */
+ if (!alloc_cpumask_var(&q_vector->affinity_mask, GFP_KERNEL))
+ goto err_out;
+ cpumask_set_cpu(v_idx, q_vector->affinity_mask);
+ netif_napi_add(adapter->netdev, &q_vector->napi,
+ ixgbe_poll, 64);
+ adapter->q_vector[v_idx] = q_vector;
}
return 0;
err_out:
- while (q_idx) {
- q_idx--;
- q_vector = adapter->q_vector[q_idx];
+ while (v_idx) {
+ v_idx--;
+ q_vector = adapter->q_vector[v_idx];
netif_napi_del(&q_vector->napi);
+ free_cpumask_var(q_vector->affinity_mask);
kfree(q_vector);
- adapter->q_vector[q_idx] = NULL;
+ adapter->q_vector[v_idx] = NULL;
}
return -ENOMEM;
}
@@ -4916,17 +4813,18 @@ err_out:
**/
static void ixgbe_free_q_vectors(struct ixgbe_adapter *adapter)
{
- int q_idx, num_q_vectors;
+ int v_idx, num_q_vectors;
if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
else
num_q_vectors = 1;
- for (q_idx = 0; q_idx < num_q_vectors; q_idx++) {
- struct ixgbe_q_vector *q_vector = adapter->q_vector[q_idx];
- adapter->q_vector[q_idx] = NULL;
+ for (v_idx = 0; v_idx < num_q_vectors; v_idx++) {
+ struct ixgbe_q_vector *q_vector = adapter->q_vector[v_idx];
+ adapter->q_vector[v_idx] = NULL;
netif_napi_del(&q_vector->napi);
+ free_cpumask_var(q_vector->affinity_mask);
kfree(q_vector);
}
}
@@ -5041,13 +4939,11 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
struct pci_dev *pdev = adapter->pdev;
- struct net_device *dev = adapter->netdev;
unsigned int rss;
#ifdef CONFIG_IXGBE_DCB
int j;
struct tc_configuration *tc;
#endif
- int max_frame = dev->mtu + ETH_HLEN + ETH_FCS_LEN;
/* PCI config space info */
@@ -5067,8 +4963,9 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
adapter->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE;
adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82598;
break;
- case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_CAPABLE;
+ case ixgbe_mac_82599EB:
adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82599;
adapter->flags2 |= IXGBE_FLAG2_RSC_CAPABLE;
adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED;
@@ -5098,6 +4995,17 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
spin_lock_init(&adapter->fdir_perfect_lock);
#ifdef CONFIG_IXGBE_DCB
+ switch (hw->mac.type) {
+ case ixgbe_mac_X540:
+ adapter->dcb_cfg.num_tcs.pg_tcs = X540_TRAFFIC_CLASS;
+ adapter->dcb_cfg.num_tcs.pfc_tcs = X540_TRAFFIC_CLASS;
+ break;
+ default:
+ adapter->dcb_cfg.num_tcs.pg_tcs = MAX_TRAFFIC_CLASS;
+ adapter->dcb_cfg.num_tcs.pfc_tcs = MAX_TRAFFIC_CLASS;
+ break;
+ }
+
/* Configure DCB traffic classes */
for (j = 0; j < MAX_TRAFFIC_CLASS; j++) {
tc = &adapter->dcb_cfg.tc_config[j];
@@ -5107,6 +5015,12 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
tc->path[DCB_RX_CONFIG].bwg_percent = 12 + (j & 1);
tc->dcb_pfc = pfc_disabled;
}
+
+ /* Initialize default user to priority mapping, UPx->TC0 */
+ tc = &adapter->dcb_cfg.tc_config[0];
+ tc->path[DCB_TX_CONFIG].up_to_tc_bitmap = 0xFF;
+ tc->path[DCB_RX_CONFIG].up_to_tc_bitmap = 0xFF;
+
adapter->dcb_cfg.bw_percentage[DCB_TX_CONFIG][0] = 100;
adapter->dcb_cfg.bw_percentage[DCB_RX_CONFIG][0] = 100;
adapter->dcb_cfg.pfc_mode_enable = false;
@@ -5123,17 +5037,14 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
#ifdef CONFIG_DCB
adapter->last_lfc_mode = hw->fc.current_mode;
#endif
- hw->fc.high_water = FC_HIGH_WATER(max_frame);
- hw->fc.low_water = FC_LOW_WATER(max_frame);
+ ixgbe_pbthresh_setup(adapter);
hw->fc.pause_time = IXGBE_DEFAULT_FCPAUSE;
hw->fc.send_xon = true;
hw->fc.disable_fc_autoneg = false;
/* enable itr by default in dynamic mode */
adapter->rx_itr_setting = 1;
- adapter->rx_eitr_param = 20000;
adapter->tx_itr_setting = 1;
- adapter->tx_eitr_param = 10000;
/* set defaults for eitr in MegaBytes */
adapter->eitr_low = 10;
@@ -5144,7 +5055,7 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
adapter->rx_ring_count = IXGBE_DEFAULT_RXD;
/* set default work limits */
- adapter->tx_work_limit = adapter->tx_ring_count;
+ adapter->tx_work_limit = IXGBE_DEFAULT_TX_WORK;
/* initialize eeprom parameters */
if (ixgbe_init_eeprom_params_generic(hw)) {
@@ -5393,9 +5304,6 @@ static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu)
/* must set new MTU before calling down or up */
netdev->mtu = new_mtu;
- hw->fc.high_water = FC_HIGH_WATER(max_frame);
- hw->fc.low_water = FC_LOW_WATER(max_frame);
-
if (netif_running(netdev))
ixgbe_reinit_locked(adapter);
@@ -5441,17 +5349,10 @@ static int ixgbe_open(struct net_device *netdev)
if (err)
goto err_req_irq;
- err = ixgbe_up_complete(adapter);
- if (err)
- goto err_up;
-
- netif_tx_start_all_queues(netdev);
+ ixgbe_up_complete(adapter);
return 0;
-err_up:
- ixgbe_release_hw_control(adapter);
- ixgbe_free_irq(adapter);
err_req_irq:
err_setup_rx:
ixgbe_free_all_rx_resources(adapter);
@@ -5656,6 +5557,11 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
u64 non_eop_descs = 0, restart_queue = 0, tx_busy = 0;
u64 alloc_rx_page_failed = 0, alloc_rx_buff_failed = 0;
u64 bytes = 0, packets = 0;
+#ifdef IXGBE_FCOE
+ struct ixgbe_fcoe *fcoe = &adapter->fcoe;
+ unsigned int cpu;
+ u64 fcoe_noddp_counts_sum = 0, fcoe_noddp_ext_buff_counts_sum = 0;
+#endif /* IXGBE_FCOE */
if (test_bit(__IXGBE_DOWN, &adapter->state) ||
test_bit(__IXGBE_RESETTING, &adapter->state))
@@ -5705,20 +5611,21 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
netdev->stats.tx_packets = packets;
hwstats->crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS);
+
+ /* 8 register reads */
for (i = 0; i < 8; i++) {
/* for packet buffers not used, the register should read 0 */
mpc = IXGBE_READ_REG(hw, IXGBE_MPC(i));
missed_rx += mpc;
hwstats->mpc[i] += mpc;
total_mpc += hwstats->mpc[i];
- if (hw->mac.type == ixgbe_mac_82598EB)
- hwstats->rnbc[i] += IXGBE_READ_REG(hw, IXGBE_RNBC(i));
- hwstats->qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i));
- hwstats->qbtc[i] += IXGBE_READ_REG(hw, IXGBE_QBTC(i));
- hwstats->qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i));
- hwstats->qbrc[i] += IXGBE_READ_REG(hw, IXGBE_QBRC(i));
+ hwstats->pxontxc[i] += IXGBE_READ_REG(hw, IXGBE_PXONTXC(i));
+ hwstats->pxofftxc[i] += IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(i));
switch (hw->mac.type) {
case ixgbe_mac_82598EB:
+ hwstats->rnbc[i] += IXGBE_READ_REG(hw, IXGBE_RNBC(i));
+ hwstats->qbtc[i] += IXGBE_READ_REG(hw, IXGBE_QBTC(i));
+ hwstats->qbrc[i] += IXGBE_READ_REG(hw, IXGBE_QBRC(i));
hwstats->pxonrxc[i] +=
IXGBE_READ_REG(hw, IXGBE_PXONRXC(i));
break;
@@ -5730,9 +5637,21 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
default:
break;
}
- hwstats->pxontxc[i] += IXGBE_READ_REG(hw, IXGBE_PXONTXC(i));
- hwstats->pxofftxc[i] += IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(i));
}
+
+ /*16 register reads */
+ for (i = 0; i < 16; i++) {
+ hwstats->qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i));
+ hwstats->qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i));
+ if ((hw->mac.type == ixgbe_mac_82599EB) ||
+ (hw->mac.type == ixgbe_mac_X540)) {
+ hwstats->qbtc[i] += IXGBE_READ_REG(hw, IXGBE_QBTC_L(i));
+ IXGBE_READ_REG(hw, IXGBE_QBTC_H(i)); /* to clear */
+ hwstats->qbrc[i] += IXGBE_READ_REG(hw, IXGBE_QBRC_L(i));
+ IXGBE_READ_REG(hw, IXGBE_QBRC_H(i)); /* to clear */
+ }
+ }
+
hwstats->gprc += IXGBE_READ_REG(hw, IXGBE_GPRC);
/* work around hardware counting issue */
hwstats->gprc -= missed_rx;
@@ -5770,6 +5689,18 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
hwstats->fcoeptc += IXGBE_READ_REG(hw, IXGBE_FCOEPTC);
hwstats->fcoedwrc += IXGBE_READ_REG(hw, IXGBE_FCOEDWRC);
hwstats->fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC);
+ /* Add up per cpu counters for total ddp aloc fail */
+ if (fcoe->pcpu_noddp && fcoe->pcpu_noddp_ext_buff) {
+ for_each_possible_cpu(cpu) {
+ fcoe_noddp_counts_sum +=
+ *per_cpu_ptr(fcoe->pcpu_noddp, cpu);
+ fcoe_noddp_ext_buff_counts_sum +=
+ *per_cpu_ptr(fcoe->
+ pcpu_noddp_ext_buff, cpu);
+ }
+ }
+ hwstats->fcoe_noddp = fcoe_noddp_counts_sum;
+ hwstats->fcoe_noddp_ext_buff = fcoe_noddp_ext_buff_counts_sum;
#endif /* IXGBE_FCOE */
break;
default:
@@ -5792,7 +5723,6 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
hwstats->lxontxc += lxon;
lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC);
hwstats->lxofftxc += lxoff;
- hwstats->ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
hwstats->gptc += IXGBE_READ_REG(hw, IXGBE_GPTC);
hwstats->mptc += IXGBE_READ_REG(hw, IXGBE_MPTC);
/*
@@ -5900,7 +5830,7 @@ static void ixgbe_check_hang_subtask(struct ixgbe_adapter *adapter)
/* get one bit for every active tx/rx interrupt vector */
for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) {
struct ixgbe_q_vector *qv = adapter->q_vector[i];
- if (qv->rx.count || qv->tx.count)
+ if (qv->rx.ring || qv->tx.ring)
eics |= ((u64)1 << i);
}
}
@@ -6089,7 +6019,8 @@ static void ixgbe_spoof_check(struct ixgbe_adapter *adapter)
static void ixgbe_watchdog_subtask(struct ixgbe_adapter *adapter)
{
/* if interface is down do nothing */
- if (test_bit(__IXGBE_DOWN, &adapter->state))
+ if (test_bit(__IXGBE_DOWN, &adapter->state) ||
+ test_bit(__IXGBE_RESETTING, &adapter->state))
return;
ixgbe_watchdog_update_link(adapter);
@@ -6203,6 +6134,51 @@ static void ixgbe_sfp_link_config_subtask(struct ixgbe_adapter *adapter)
clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state);
}
+#ifdef CONFIG_PCI_IOV
+static void ixgbe_check_for_bad_vf(struct ixgbe_adapter *adapter)
+{
+ int vf;
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+ u32 gpc;
+ u32 ciaa, ciad;
+
+ gpc = IXGBE_READ_REG(hw, IXGBE_TXDGPC);
+ if (gpc) /* If incrementing then no need for the check below */
+ return;
+ /*
+ * Check to see if a bad DMA write target from an errant or
+ * malicious VF has caused a PCIe error. If so then we can
+ * issue a VFLR to the offending VF(s) and then resume without
+ * requesting a full slot reset.
+ */
+
+ for (vf = 0; vf < adapter->num_vfs; vf++) {
+ ciaa = (vf << 16) | 0x80000000;
+ /* 32 bit read so align, we really want status at offset 6 */
+ ciaa |= PCI_COMMAND;
+ IXGBE_WRITE_REG(hw, IXGBE_CIAA_82599, ciaa);
+ ciad = IXGBE_READ_REG(hw, IXGBE_CIAD_82599);
+ ciaa &= 0x7FFFFFFF;
+ /* disable debug mode asap after reading data */
+ IXGBE_WRITE_REG(hw, IXGBE_CIAA_82599, ciaa);
+ /* Get the upper 16 bits which will be the PCI status reg */
+ ciad >>= 16;
+ if (ciad & PCI_STATUS_REC_MASTER_ABORT) {
+ netdev_err(netdev, "VF %d Hung DMA\n", vf);
+ /* Issue VFLR */
+ ciaa = (vf << 16) | 0x80000000;
+ ciaa |= 0xA8;
+ IXGBE_WRITE_REG(hw, IXGBE_CIAA_82599, ciaa);
+ ciad = 0x00008000; /* VFLR */
+ IXGBE_WRITE_REG(hw, IXGBE_CIAD_82599, ciad);
+ ciaa &= 0x7FFFFFFF;
+ IXGBE_WRITE_REG(hw, IXGBE_CIAA_82599, ciaa);
+ }
+ }
+}
+
+#endif
/**
* ixgbe_service_timer - Timer Call-back
* @data: pointer to adapter cast into an unsigned long
@@ -6211,17 +6187,49 @@ static void ixgbe_service_timer(unsigned long data)
{
struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
unsigned long next_event_offset;
+ bool ready = true;
+
+#ifdef CONFIG_PCI_IOV
+ ready = false;
+
+ /*
+ * don't bother with SR-IOV VF DMA hang check if there are
+ * no VFs or the link is down
+ */
+ if (!adapter->num_vfs ||
+ (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE)) {
+ ready = true;
+ goto normal_timer_service;
+ }
+
+ /* If we have VFs allocated then we must check for DMA hangs */
+ ixgbe_check_for_bad_vf(adapter);
+ next_event_offset = HZ / 50;
+ adapter->timer_event_accumulator++;
+
+ if (adapter->timer_event_accumulator >= 100) {
+ ready = true;
+ adapter->timer_event_accumulator = 0;
+ }
+ goto schedule_event;
+
+normal_timer_service:
+#endif
/* poll faster when waiting for link */
if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE)
next_event_offset = HZ / 10;
else
next_event_offset = HZ * 2;
+#ifdef CONFIG_PCI_IOV
+schedule_event:
+#endif
/* Reset the timer */
mod_timer(&adapter->service_timer, next_event_offset + jiffies);
- ixgbe_service_event_schedule(adapter);
+ if (ready)
+ ixgbe_service_event_schedule(adapter);
}
static void ixgbe_reset_subtask(struct ixgbe_adapter *adapter)
@@ -6348,7 +6356,8 @@ static bool ixgbe_tx_csum(struct ixgbe_ring *tx_ring,
u32 type_tucmd = 0;
if (skb->ip_summed != CHECKSUM_PARTIAL) {
- if (!(tx_flags & IXGBE_TX_FLAGS_VLAN))
+ if (!(tx_flags & IXGBE_TX_FLAGS_HW_VLAN) &&
+ !(tx_flags & IXGBE_TX_FLAGS_TXSW))
return false;
} else {
u8 l4_hdr = 0;
@@ -6405,185 +6414,185 @@ static bool ixgbe_tx_csum(struct ixgbe_ring *tx_ring,
return (skb->ip_summed == CHECKSUM_PARTIAL);
}
-static int ixgbe_tx_map(struct ixgbe_adapter *adapter,
- struct ixgbe_ring *tx_ring,
- struct sk_buff *skb, u32 tx_flags,
- unsigned int first, const u8 hdr_len)
+static __le32 ixgbe_tx_cmd_type(u32 tx_flags)
{
- struct device *dev = tx_ring->dev;
- struct ixgbe_tx_buffer *tx_buffer_info;
- unsigned int len;
- unsigned int total = skb->len;
- unsigned int offset = 0, size, count = 0;
- unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
- unsigned int f;
- unsigned int bytecount = skb->len;
- u16 gso_segs = 1;
- u16 i;
+ /* set type for advanced descriptor with frame checksum insertion */
+ __le32 cmd_type = cpu_to_le32(IXGBE_ADVTXD_DTYP_DATA |
+ IXGBE_ADVTXD_DCMD_IFCS |
+ IXGBE_ADVTXD_DCMD_DEXT);
- i = tx_ring->next_to_use;
+ /* set HW vlan bit if vlan is present */
+ if (tx_flags & IXGBE_TX_FLAGS_HW_VLAN)
+ cmd_type |= cpu_to_le32(IXGBE_ADVTXD_DCMD_VLE);
- if (tx_flags & IXGBE_TX_FLAGS_FCOE)
- /* excluding fcoe_crc_eof for FCoE */
- total -= sizeof(struct fcoe_crc_eof);
+ /* set segmentation enable bits for TSO/FSO */
+#ifdef IXGBE_FCOE
+ if ((tx_flags & IXGBE_TX_FLAGS_TSO) || (tx_flags & IXGBE_TX_FLAGS_FSO))
+#else
+ if (tx_flags & IXGBE_TX_FLAGS_TSO)
+#endif
+ cmd_type |= cpu_to_le32(IXGBE_ADVTXD_DCMD_TSE);
- len = min(skb_headlen(skb), total);
- while (len) {
- tx_buffer_info = &tx_ring->tx_buffer_info[i];
- size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD);
-
- tx_buffer_info->length = size;
- tx_buffer_info->mapped_as_page = false;
- tx_buffer_info->dma = dma_map_single(dev,
- skb->data + offset,
- size, DMA_TO_DEVICE);
- if (dma_mapping_error(dev, tx_buffer_info->dma))
- goto dma_error;
- tx_buffer_info->time_stamp = jiffies;
- tx_buffer_info->next_to_watch = i;
+ return cmd_type;
+}
- len -= size;
- total -= size;
- offset += size;
- count++;
+static __le32 ixgbe_tx_olinfo_status(u32 tx_flags, unsigned int paylen)
+{
+ __le32 olinfo_status =
+ cpu_to_le32(paylen << IXGBE_ADVTXD_PAYLEN_SHIFT);
- if (len) {
- i++;
- if (i == tx_ring->count)
- i = 0;
- }
+ if (tx_flags & IXGBE_TX_FLAGS_TSO) {
+ olinfo_status |= cpu_to_le32(IXGBE_ADVTXD_POPTS_TXSM |
+ (1 << IXGBE_ADVTXD_IDX_SHIFT));
+ /* enble IPv4 checksum for TSO */
+ if (tx_flags & IXGBE_TX_FLAGS_IPV4)
+ olinfo_status |= cpu_to_le32(IXGBE_ADVTXD_POPTS_IXSM);
}
- for (f = 0; f < nr_frags; f++) {
- struct skb_frag_struct *frag;
-
- frag = &skb_shinfo(skb)->frags[f];
- len = min((unsigned int)frag->size, total);
- offset = frag->page_offset;
-
- while (len) {
- i++;
- if (i == tx_ring->count)
- i = 0;
-
- tx_buffer_info = &tx_ring->tx_buffer_info[i];
- size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD);
-
- tx_buffer_info->length = size;
- tx_buffer_info->dma = dma_map_page(dev,
- frag->page,
- offset, size,
- DMA_TO_DEVICE);
- tx_buffer_info->mapped_as_page = true;
- if (dma_mapping_error(dev, tx_buffer_info->dma))
- goto dma_error;
- tx_buffer_info->time_stamp = jiffies;
- tx_buffer_info->next_to_watch = i;
-
- len -= size;
- total -= size;
- offset += size;
- count++;
- }
- if (total == 0)
- break;
- }
+ /* enable L4 checksum for TSO and TX checksum offload */
+ if (tx_flags & IXGBE_TX_FLAGS_CSUM)
+ olinfo_status |= cpu_to_le32(IXGBE_ADVTXD_POPTS_TXSM);
- if (tx_flags & IXGBE_TX_FLAGS_TSO)
- gso_segs = skb_shinfo(skb)->gso_segs;
#ifdef IXGBE_FCOE
- /* adjust for FCoE Sequence Offload */
- else if (tx_flags & IXGBE_TX_FLAGS_FSO)
- gso_segs = DIV_ROUND_UP(skb->len - hdr_len,
- skb_shinfo(skb)->gso_size);
-#endif /* IXGBE_FCOE */
- bytecount += (gso_segs - 1) * hdr_len;
+ /* use index 1 context for FCOE/FSO */
+ if (tx_flags & IXGBE_TX_FLAGS_FCOE)
+ olinfo_status |= cpu_to_le32(IXGBE_ADVTXD_CC |
+ (1 << IXGBE_ADVTXD_IDX_SHIFT));
- /* multiply data chunks by size of headers */
- tx_ring->tx_buffer_info[i].bytecount = bytecount;
- tx_ring->tx_buffer_info[i].gso_segs = gso_segs;
- tx_ring->tx_buffer_info[i].skb = skb;
- tx_ring->tx_buffer_info[first].next_to_watch = i;
+#endif
+ /*
+ * Check Context must be set if Tx switch is enabled, which it
+ * always is for case where virtual functions are running
+ */
+ if (tx_flags & IXGBE_TX_FLAGS_TXSW)
+ olinfo_status |= cpu_to_le32(IXGBE_ADVTXD_CC);
- return count;
+ return olinfo_status;
+}
-dma_error:
- e_dev_err("TX DMA map failed\n");
+#define IXGBE_TXD_CMD (IXGBE_TXD_CMD_EOP | \
+ IXGBE_TXD_CMD_RS)
- /* clear timestamp and dma mappings for failed tx_buffer_info map */
- tx_buffer_info->dma = 0;
- tx_buffer_info->time_stamp = 0;
- tx_buffer_info->next_to_watch = 0;
- if (count)
- count--;
+static void ixgbe_tx_map(struct ixgbe_ring *tx_ring,
+ struct sk_buff *skb,
+ struct ixgbe_tx_buffer *first,
+ u32 tx_flags,
+ const u8 hdr_len)
+{
+ struct device *dev = tx_ring->dev;
+ struct ixgbe_tx_buffer *tx_buffer_info;
+ union ixgbe_adv_tx_desc *tx_desc;
+ dma_addr_t dma;
+ __le32 cmd_type, olinfo_status;
+ struct skb_frag_struct *frag;
+ unsigned int f = 0;
+ unsigned int data_len = skb->data_len;
+ unsigned int size = skb_headlen(skb);
+ u32 offset = 0;
+ u32 paylen = skb->len - hdr_len;
+ u16 i = tx_ring->next_to_use;
+ u16 gso_segs;
- /* clear timestamp and dma mappings for remaining portion of packet */
- while (count--) {
- if (i == 0)
- i += tx_ring->count;
- i--;
- tx_buffer_info = &tx_ring->tx_buffer_info[i];
- ixgbe_unmap_and_free_tx_resource(tx_ring, tx_buffer_info);
+#ifdef IXGBE_FCOE
+ if (tx_flags & IXGBE_TX_FLAGS_FCOE) {
+ if (data_len >= sizeof(struct fcoe_crc_eof)) {
+ data_len -= sizeof(struct fcoe_crc_eof);
+ } else {
+ size -= sizeof(struct fcoe_crc_eof) - data_len;
+ data_len = 0;
+ }
}
- return 0;
-}
+#endif
+ dma = dma_map_single(dev, skb->data, size, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, dma))
+ goto dma_error;
-static void ixgbe_tx_queue(struct ixgbe_ring *tx_ring,
- int tx_flags, int count, u32 paylen, u8 hdr_len)
-{
- union ixgbe_adv_tx_desc *tx_desc = NULL;
- struct ixgbe_tx_buffer *tx_buffer_info;
- u32 olinfo_status = 0, cmd_type_len = 0;
- unsigned int i;
- u32 txd_cmd = IXGBE_TXD_CMD_EOP | IXGBE_TXD_CMD_RS | IXGBE_TXD_CMD_IFCS;
+ cmd_type = ixgbe_tx_cmd_type(tx_flags);
+ olinfo_status = ixgbe_tx_olinfo_status(tx_flags, paylen);
- cmd_type_len |= IXGBE_ADVTXD_DTYP_DATA;
+ tx_desc = IXGBE_TX_DESC_ADV(tx_ring, i);
- cmd_type_len |= IXGBE_ADVTXD_DCMD_IFCS | IXGBE_ADVTXD_DCMD_DEXT;
+ for (;;) {
+ while (size > IXGBE_MAX_DATA_PER_TXD) {
+ tx_desc->read.buffer_addr = cpu_to_le64(dma + offset);
+ tx_desc->read.cmd_type_len =
+ cmd_type | cpu_to_le32(IXGBE_MAX_DATA_PER_TXD);
+ tx_desc->read.olinfo_status = olinfo_status;
- if (tx_flags & IXGBE_TX_FLAGS_VLAN)
- cmd_type_len |= IXGBE_ADVTXD_DCMD_VLE;
+ offset += IXGBE_MAX_DATA_PER_TXD;
+ size -= IXGBE_MAX_DATA_PER_TXD;
- if (tx_flags & IXGBE_TX_FLAGS_TSO) {
- cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE;
+ tx_desc++;
+ i++;
+ if (i == tx_ring->count) {
+ tx_desc = IXGBE_TX_DESC_ADV(tx_ring, 0);
+ i = 0;
+ }
+ }
- olinfo_status |= IXGBE_TXD_POPTS_TXSM <<
- IXGBE_ADVTXD_POPTS_SHIFT;
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ tx_buffer_info->length = offset + size;
+ tx_buffer_info->tx_flags = tx_flags;
+ tx_buffer_info->dma = dma;
- /* use index 1 context for tso */
- olinfo_status |= (1 << IXGBE_ADVTXD_IDX_SHIFT);
- if (tx_flags & IXGBE_TX_FLAGS_IPV4)
- olinfo_status |= IXGBE_TXD_POPTS_IXSM <<
- IXGBE_ADVTXD_POPTS_SHIFT;
+ tx_desc->read.buffer_addr = cpu_to_le64(dma + offset);
+ tx_desc->read.cmd_type_len = cmd_type | cpu_to_le32(size);
+ tx_desc->read.olinfo_status = olinfo_status;
- } else if (tx_flags & IXGBE_TX_FLAGS_CSUM)
- olinfo_status |= IXGBE_TXD_POPTS_TXSM <<
- IXGBE_ADVTXD_POPTS_SHIFT;
+ if (!data_len)
+ break;
- if (tx_flags & IXGBE_TX_FLAGS_FCOE) {
- olinfo_status |= IXGBE_ADVTXD_CC;
- olinfo_status |= (1 << IXGBE_ADVTXD_IDX_SHIFT);
- if (tx_flags & IXGBE_TX_FLAGS_FSO)
- cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE;
- }
+ frag = &skb_shinfo(skb)->frags[f];
+#ifdef IXGBE_FCOE
+ size = min_t(unsigned int, data_len, skb_frag_size(frag));
+#else
+ size = skb_frag_size(frag);
+#endif
+ data_len -= size;
+ f++;
- olinfo_status |= ((paylen - hdr_len) << IXGBE_ADVTXD_PAYLEN_SHIFT);
+ offset = 0;
+ tx_flags |= IXGBE_TX_FLAGS_MAPPED_AS_PAGE;
- i = tx_ring->next_to_use;
- while (count--) {
- tx_buffer_info = &tx_ring->tx_buffer_info[i];
- tx_desc = IXGBE_TX_DESC_ADV(tx_ring, i);
- tx_desc->read.buffer_addr = cpu_to_le64(tx_buffer_info->dma);
- tx_desc->read.cmd_type_len =
- cpu_to_le32(cmd_type_len | tx_buffer_info->length);
- tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
+ dma = skb_frag_dma_map(dev, frag, 0, size, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, dma))
+ goto dma_error;
+
+ tx_desc++;
i++;
- if (i == tx_ring->count)
+ if (i == tx_ring->count) {
+ tx_desc = IXGBE_TX_DESC_ADV(tx_ring, 0);
i = 0;
+ }
}
- tx_desc->read.cmd_type_len |= cpu_to_le32(txd_cmd);
+ tx_desc->read.cmd_type_len |= cpu_to_le32(IXGBE_TXD_CMD);
+
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+
+ tx_ring->next_to_use = i;
+
+ if (tx_flags & IXGBE_TX_FLAGS_TSO)
+ gso_segs = skb_shinfo(skb)->gso_segs;
+#ifdef IXGBE_FCOE
+ /* adjust for FCoE Sequence Offload */
+ else if (tx_flags & IXGBE_TX_FLAGS_FSO)
+ gso_segs = DIV_ROUND_UP(skb->len - hdr_len,
+ skb_shinfo(skb)->gso_size);
+#endif /* IXGBE_FCOE */
+ else
+ gso_segs = 1;
+
+ /* multiply data chunks by size of headers */
+ tx_buffer_info->bytecount = paylen + (gso_segs * hdr_len);
+ tx_buffer_info->gso_segs = gso_segs;
+ tx_buffer_info->skb = skb;
+
+ /* set the timestamp */
+ first->time_stamp = jiffies;
/*
* Force memory writes to complete before letting h/w
@@ -6593,8 +6602,30 @@ static void ixgbe_tx_queue(struct ixgbe_ring *tx_ring,
*/
wmb();
- tx_ring->next_to_use = i;
+ /* set next_to_watch value indicating a packet is present */
+ first->next_to_watch = tx_desc;
+
+ /* notify HW of packet */
writel(i, tx_ring->tail);
+
+ return;
+dma_error:
+ dev_err(dev, "TX DMA map failed\n");
+
+ /* clear dma mappings for failed tx_buffer_info map */
+ for (;;) {
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ ixgbe_unmap_tx_resource(tx_ring, tx_buffer_info);
+ if (tx_buffer_info == first)
+ break;
+ if (i == 0)
+ i = tx_ring->count;
+ i--;
+ }
+
+ dev_kfree_skb_any(skb);
+
+ tx_ring->next_to_use = i;
}
static void ixgbe_atr(struct ixgbe_ring *ring, struct sk_buff *skb,
@@ -6633,8 +6664,8 @@ static void ixgbe_atr(struct ixgbe_ring *ring, struct sk_buff *skb,
th = tcp_hdr(skb);
- /* skip this packet since the socket is closing */
- if (th->fin)
+ /* skip this packet since it is invalid or the socket is closing */
+ if (!th || th->fin)
return;
/* sample on all syn packets or once every atr sample count */
@@ -6659,7 +6690,7 @@ static void ixgbe_atr(struct ixgbe_ring *ring, struct sk_buff *skb,
* since src port and flex bytes occupy the same word XOR them together
* and write the value to source port portion of compressed dword
*/
- if (vlan_id)
+ if (tx_flags & (IXGBE_TX_FLAGS_SW_VLAN | IXGBE_TX_FLAGS_HW_VLAN))
common.port.src ^= th->dest ^ __constant_htons(ETH_P_8021Q);
else
common.port.src ^= th->dest ^ protocol;
@@ -6741,14 +6772,14 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
struct ixgbe_adapter *adapter,
struct ixgbe_ring *tx_ring)
{
+ struct ixgbe_tx_buffer *first;
int tso;
- u32 tx_flags = 0;
+ u32 tx_flags = 0;
#if PAGE_SIZE > IXGBE_MAX_DATA_PER_TXD
unsigned short f;
#endif
- u16 first;
u16 count = TXD_USE_COUNT(skb_headlen(skb));
- __be16 protocol;
+ __be16 protocol = skb->protocol;
u8 hdr_len = 0;
/*
@@ -6769,68 +6800,89 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
return NETDEV_TX_BUSY;
}
- protocol = vlan_get_protocol(skb);
+#ifdef CONFIG_PCI_IOV
+ if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
+ tx_flags |= IXGBE_TX_FLAGS_TXSW;
+#endif
+ /* if we have a HW VLAN tag being added default to the HW one */
if (vlan_tx_tag_present(skb)) {
- tx_flags |= vlan_tx_tag_get(skb);
- if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
- tx_flags &= ~IXGBE_TX_FLAGS_VLAN_PRIO_MASK;
- tx_flags |= tx_ring->dcb_tc << 13;
+ tx_flags |= vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT;
+ tx_flags |= IXGBE_TX_FLAGS_HW_VLAN;
+ /* else if it is a SW VLAN check the next protocol and store the tag */
+ } else if (protocol == __constant_htons(ETH_P_8021Q)) {
+ struct vlan_hdr *vhdr, _vhdr;
+ vhdr = skb_header_pointer(skb, ETH_HLEN, sizeof(_vhdr), &_vhdr);
+ if (!vhdr)
+ goto out_drop;
+
+ protocol = vhdr->h_vlan_encapsulated_proto;
+ tx_flags |= ntohs(vhdr->h_vlan_TCI) << IXGBE_TX_FLAGS_VLAN_SHIFT;
+ tx_flags |= IXGBE_TX_FLAGS_SW_VLAN;
+ }
+
+ /* DCB maps skb priorities 0-7 onto 3 bit PCP of VLAN tag. */
+ if ((adapter->flags & IXGBE_FLAG_DCB_ENABLED) &&
+ ((tx_flags & (IXGBE_TX_FLAGS_HW_VLAN | IXGBE_TX_FLAGS_SW_VLAN)) ||
+ (skb->priority != TC_PRIO_CONTROL))) {
+ tx_flags &= ~IXGBE_TX_FLAGS_VLAN_PRIO_MASK;
+ tx_flags |= (skb->priority & 0x7) <<
+ IXGBE_TX_FLAGS_VLAN_PRIO_SHIFT;
+ if (tx_flags & IXGBE_TX_FLAGS_SW_VLAN) {
+ struct vlan_ethhdr *vhdr;
+ if (skb_header_cloned(skb) &&
+ pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ goto out_drop;
+ vhdr = (struct vlan_ethhdr *)skb->data;
+ vhdr->h_vlan_TCI = htons(tx_flags >>
+ IXGBE_TX_FLAGS_VLAN_SHIFT);
+ } else {
+ tx_flags |= IXGBE_TX_FLAGS_HW_VLAN;
}
- tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT;
- tx_flags |= IXGBE_TX_FLAGS_VLAN;
- } else if (adapter->flags & IXGBE_FLAG_DCB_ENABLED &&
- skb->priority != TC_PRIO_CONTROL) {
- tx_flags |= tx_ring->dcb_tc << 13;
- tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT;
- tx_flags |= IXGBE_TX_FLAGS_VLAN;
}
-#ifdef IXGBE_FCOE
- /* for FCoE with DCB, we force the priority to what
- * was specified by the switch */
- if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED &&
- (protocol == htons(ETH_P_FCOE)))
- tx_flags |= IXGBE_TX_FLAGS_FCOE;
-
-#endif
/* record the location of the first descriptor for this packet */
- first = tx_ring->next_to_use;
+ first = &tx_ring->tx_buffer_info[tx_ring->next_to_use];
- if (tx_flags & IXGBE_TX_FLAGS_FCOE) {
#ifdef IXGBE_FCOE
- /* setup tx offload for FCoE */
+ /* setup tx offload for FCoE */
+ if ((protocol == __constant_htons(ETH_P_FCOE)) &&
+ (adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) {
tso = ixgbe_fso(tx_ring, skb, tx_flags, &hdr_len);
if (tso < 0)
goto out_drop;
else if (tso)
- tx_flags |= IXGBE_TX_FLAGS_FSO;
-#endif /* IXGBE_FCOE */
- } else {
- if (protocol == htons(ETH_P_IP))
- tx_flags |= IXGBE_TX_FLAGS_IPV4;
- tso = ixgbe_tso(tx_ring, skb, tx_flags, protocol, &hdr_len);
- if (tso < 0)
- goto out_drop;
- else if (tso)
- tx_flags |= IXGBE_TX_FLAGS_TSO;
- else if (ixgbe_tx_csum(tx_ring, skb, tx_flags, protocol))
- tx_flags |= IXGBE_TX_FLAGS_CSUM;
+ tx_flags |= IXGBE_TX_FLAGS_FSO |
+ IXGBE_TX_FLAGS_FCOE;
+ else
+ tx_flags |= IXGBE_TX_FLAGS_FCOE;
+
+ goto xmit_fcoe;
}
- count = ixgbe_tx_map(adapter, tx_ring, skb, tx_flags, first, hdr_len);
- if (count) {
- /* add the ATR filter if ATR is on */
- if (test_bit(__IXGBE_TX_FDIR_INIT_DONE, &tx_ring->state))
- ixgbe_atr(tx_ring, skb, tx_flags, protocol);
- ixgbe_tx_queue(tx_ring, tx_flags, count, skb->len, hdr_len);
- ixgbe_maybe_stop_tx(tx_ring, DESC_NEEDED);
+#endif /* IXGBE_FCOE */
+ /* setup IPv4/IPv6 offloads */
+ if (protocol == __constant_htons(ETH_P_IP))
+ tx_flags |= IXGBE_TX_FLAGS_IPV4;
- } else {
- tx_ring->tx_buffer_info[first].time_stamp = 0;
- tx_ring->next_to_use = first;
+ tso = ixgbe_tso(tx_ring, skb, tx_flags, protocol, &hdr_len);
+ if (tso < 0)
goto out_drop;
- }
+ else if (tso)
+ tx_flags |= IXGBE_TX_FLAGS_TSO;
+ else if (ixgbe_tx_csum(tx_ring, skb, tx_flags, protocol))
+ tx_flags |= IXGBE_TX_FLAGS_CSUM;
+
+ /* add the ATR filter if ATR is on */
+ if (test_bit(__IXGBE_TX_FDIR_INIT_DONE, &tx_ring->state))
+ ixgbe_atr(tx_ring, skb, tx_flags, protocol);
+
+#ifdef IXGBE_FCOE
+xmit_fcoe:
+#endif /* IXGBE_FCOE */
+ ixgbe_tx_map(tx_ring, skb, first, tx_flags, hdr_len);
+
+ ixgbe_maybe_stop_tx(tx_ring, DESC_NEEDED);
return NETDEV_TX_OK;
@@ -6969,7 +7021,7 @@ static void ixgbe_netpoll(struct net_device *netdev)
int num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
for (i = 0; i < num_q_vectors; i++) {
struct ixgbe_q_vector *q_vector = adapter->q_vector[i];
- ixgbe_msix_clean_many(0, q_vector);
+ ixgbe_msix_clean_rings(0, q_vector);
}
} else {
ixgbe_intr(adapter->pdev->irq, netdev);
@@ -7074,14 +7126,14 @@ int ixgbe_setup_tc(struct net_device *dev, u8 tc)
struct ixgbe_adapter *adapter = netdev_priv(dev);
struct ixgbe_hw *hw = &adapter->hw;
- /* If DCB is anabled do not remove traffic classes, multiple
- * traffic classes are required to implement DCB
- */
- if (!tc && (adapter->flags & IXGBE_FLAG_DCB_ENABLED))
- return 0;
+ /* Multiple traffic classes requires multiple queues */
+ if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) {
+ e_err(drv, "Enable failed, needs MSI-X\n");
+ return -EINVAL;
+ }
/* Hardware supports up to 8 traffic classes */
- if (tc > MAX_TRAFFIC_CLASS ||
+ if (tc > adapter->dcb_cfg.num_tcs.pg_tcs ||
(hw->mac.type == ixgbe_mac_82598EB && tc < MAX_TRAFFIC_CLASS))
return -EINVAL;
@@ -7093,11 +7145,27 @@ int ixgbe_setup_tc(struct net_device *dev, u8 tc)
ixgbe_close(dev);
ixgbe_clear_interrupt_scheme(adapter);
- if (tc)
+ if (tc) {
netdev_set_num_tc(dev, tc);
- else
+ adapter->last_lfc_mode = adapter->hw.fc.current_mode;
+
+ adapter->flags |= IXGBE_FLAG_DCB_ENABLED;
+ adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE;
+
+ if (adapter->hw.mac.type == ixgbe_mac_82598EB)
+ adapter->hw.fc.requested_mode = ixgbe_fc_none;
+ } else {
netdev_reset_tc(dev);
+ adapter->hw.fc.requested_mode = adapter->last_lfc_mode;
+
+ adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED;
+ adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
+
+ adapter->temp_dcb_cfg.pfc_mode_enable = false;
+ adapter->dcb_cfg.pfc_mode_enable = false;
+ }
+
ixgbe_init_interrupt_scheme(adapter);
ixgbe_validate_rtr(adapter, tc);
if (netif_running(dev))
@@ -7204,7 +7272,6 @@ static const struct net_device_ops ixgbe_netdev_ops = {
.ndo_start_xmit = ixgbe_xmit_frame,
.ndo_select_queue = ixgbe_select_queue,
.ndo_set_rx_mode = ixgbe_set_rx_mode,
- .ndo_set_multicast_list = ixgbe_set_rx_mode,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = ixgbe_set_mac,
.ndo_change_mtu = ixgbe_change_mtu,
@@ -7215,6 +7282,7 @@ static const struct net_device_ops ixgbe_netdev_ops = {
.ndo_set_vf_mac = ixgbe_ndo_set_vf_mac,
.ndo_set_vf_vlan = ixgbe_ndo_set_vf_vlan,
.ndo_set_vf_tx_rate = ixgbe_ndo_set_vf_bw,
+ .ndo_set_vf_spoofchk = ixgbe_ndo_set_vf_spoofchk,
.ndo_get_vf_config = ixgbe_ndo_get_vf_config,
.ndo_get_stats64 = ixgbe_get_stats64,
.ndo_setup_tc = ixgbe_setup_tc,
@@ -7238,11 +7306,8 @@ static void __devinit ixgbe_probe_vf(struct ixgbe_adapter *adapter,
{
#ifdef CONFIG_PCI_IOV
struct ixgbe_hw *hw = &adapter->hw;
- int err;
- int num_vf_macvlans, i;
- struct vf_macvlans *mv_list;
- if (hw->mac.type == ixgbe_mac_82598EB || !max_vfs)
+ if (hw->mac.type == ixgbe_mac_82598EB)
return;
/* The 82599 supports up to 64 VFs per physical function
@@ -7251,60 +7316,7 @@ static void __devinit ixgbe_probe_vf(struct ixgbe_adapter *adapter,
* physical function
*/
adapter->num_vfs = (max_vfs > 63) ? 63 : max_vfs;
- adapter->flags |= IXGBE_FLAG_SRIOV_ENABLED;
- err = pci_enable_sriov(adapter->pdev, adapter->num_vfs);
- if (err) {
- e_err(probe, "Failed to enable PCI sriov: %d\n", err);
- goto err_novfs;
- }
-
- num_vf_macvlans = hw->mac.num_rar_entries -
- (IXGBE_MAX_PF_MACVLANS + 1 + adapter->num_vfs);
-
- adapter->mv_list = mv_list = kcalloc(num_vf_macvlans,
- sizeof(struct vf_macvlans),
- GFP_KERNEL);
- if (mv_list) {
- /* Initialize list of VF macvlans */
- INIT_LIST_HEAD(&adapter->vf_mvs.l);
- for (i = 0; i < num_vf_macvlans; i++) {
- mv_list->vf = -1;
- mv_list->free = true;
- mv_list->rar_entry = hw->mac.num_rar_entries -
- (i + adapter->num_vfs + 1);
- list_add(&mv_list->l, &adapter->vf_mvs.l);
- mv_list++;
- }
- }
-
- /* If call to enable VFs succeeded then allocate memory
- * for per VF control structures.
- */
- adapter->vfinfo =
- kcalloc(adapter->num_vfs,
- sizeof(struct vf_data_storage), GFP_KERNEL);
- if (adapter->vfinfo) {
- /* Now that we're sure SR-IOV is enabled
- * and memory allocated set up the mailbox parameters
- */
- ixgbe_init_mbx_params_pf(hw);
- memcpy(&hw->mbx.ops, ii->mbx_ops,
- sizeof(hw->mbx.ops));
-
- /* Disable RSC when in SR-IOV mode */
- adapter->flags2 &= ~(IXGBE_FLAG2_RSC_CAPABLE |
- IXGBE_FLAG2_RSC_ENABLED);
- return;
- }
-
- /* Oh oh */
- e_err(probe, "Unable to allocate memory for VF Data Storage - "
- "SRIOV disabled\n");
- pci_disable_sriov(adapter->pdev);
-
-err_novfs:
- adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED;
- adapter->num_vfs = 0;
+ ixgbe_enable_sriov(adapter, ii);
#endif /* CONFIG_PCI_IOV */
}
@@ -7334,6 +7346,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
u16 device_caps;
#endif
u32 eec;
+ u16 wol_cap;
/* Catch broken hardware that put the wrong VF device ID in
* the PCIe SR-IOV capability.
@@ -7504,7 +7517,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
NETIF_F_HW_VLAN_FILTER |
NETIF_F_TSO |
NETIF_F_TSO6 |
- NETIF_F_GRO |
NETIF_F_RXHASH |
NETIF_F_RXCSUM;
@@ -7527,6 +7539,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
netdev->vlan_features |= NETIF_F_IPV6_CSUM;
netdev->vlan_features |= NETIF_F_SG;
+ netdev->priv_flags |= IFF_UNICAST_FLT;
+
if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
adapter->flags &= ~(IXGBE_FLAG_RSS_ENABLED |
IXGBE_FLAG_DCB_ENABLED);
@@ -7597,6 +7611,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
netdev->features &= ~NETIF_F_RXHASH;
}
+ /* WOL not supported for all but the following */
+ adapter->wol = 0;
switch (pdev->device) {
case IXGBE_DEV_ID_82599_SFP:
/* Only this subdevice supports WOL */
@@ -7611,12 +7627,23 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
case IXGBE_DEV_ID_82599_KX4:
adapter->wol = IXGBE_WUFC_MAG;
break;
- default:
- adapter->wol = 0;
+ case IXGBE_DEV_ID_X540T:
+ /* Check eeprom to see if it is enabled */
+ hw->eeprom.ops.read(hw, 0x2c, &adapter->eeprom_cap);
+ wol_cap = adapter->eeprom_cap & IXGBE_DEVICE_CAPS_WOL_MASK;
+
+ if ((wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0_1) ||
+ ((wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0) &&
+ (hw->bus.func == 0)))
+ adapter->wol = IXGBE_WUFC_MAG;
break;
}
device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
+ /* save off EEPROM version number */
+ hw->eeprom.ops.read(hw, 0x2e, &adapter->eeprom_verh);
+ hw->eeprom.ops.read(hw, 0x2d, &adapter->eeprom_verl);
+
/* pick up the PCI bus settings for reporting later */
hw->mac.ops.get_bus_info(hw);
@@ -7649,9 +7676,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
"is required.\n");
}
- /* save off EEPROM version number */
- hw->eeprom.ops.read(hw, 0x29, &adapter->eeprom_version);
-
/* reset the hardware with the new settings */
err = hw->mac.ops.start_hw(hw);
@@ -7684,10 +7708,12 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
ixgbe_vf_configuration(pdev, (i | 0x10000000));
}
- /* Inform firmware of driver version */
+ /* firmware requires driver version to be 0xFFFFFFFF
+ * since os does not support feature
+ */
if (hw->mac.ops.set_fw_drv_ver)
- hw->mac.ops.set_fw_drv_ver(hw, MAJ, MIN, BUILD,
- FW_CEM_UNUSED_VER);
+ hw->mac.ops.set_fw_drv_ver(hw, 0xFF, 0xFF, 0xFF,
+ 0xFF);
/* add san mac addr to netdev */
ixgbe_add_sanmac_netdev(netdev);
@@ -7753,8 +7779,13 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
if (netdev->reg_state == NETREG_REGISTERED)
unregister_netdev(netdev);
- if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
- ixgbe_disable_sriov(adapter);
+ if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
+ if (!(ixgbe_check_vf_assignment(adapter)))
+ ixgbe_disable_sriov(adapter);
+ else
+ e_dev_warn("Unloading driver while VFs are assigned "
+ "- VFs will not be deallocated\n");
+ }
ixgbe_clear_interrupt_scheme(adapter);
@@ -7787,6 +7818,91 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev,
struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
struct net_device *netdev = adapter->netdev;
+#ifdef CONFIG_PCI_IOV
+ struct pci_dev *bdev, *vfdev;
+ u32 dw0, dw1, dw2, dw3;
+ int vf, pos;
+ u16 req_id, pf_func;
+
+ if (adapter->hw.mac.type == ixgbe_mac_82598EB ||
+ adapter->num_vfs == 0)
+ goto skip_bad_vf_detection;
+
+ bdev = pdev->bus->self;
+ while (bdev && (bdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT))
+ bdev = bdev->bus->self;
+
+ if (!bdev)
+ goto skip_bad_vf_detection;
+
+ pos = pci_find_ext_capability(bdev, PCI_EXT_CAP_ID_ERR);
+ if (!pos)
+ goto skip_bad_vf_detection;
+
+ pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG, &dw0);
+ pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG + 4, &dw1);
+ pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG + 8, &dw2);
+ pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG + 12, &dw3);
+
+ req_id = dw1 >> 16;
+ /* On the 82599 if bit 7 of the requestor ID is set then it's a VF */
+ if (!(req_id & 0x0080))
+ goto skip_bad_vf_detection;
+
+ pf_func = req_id & 0x01;
+ if ((pf_func & 1) == (pdev->devfn & 1)) {
+ unsigned int device_id;
+
+ vf = (req_id & 0x7F) >> 1;
+ e_dev_err("VF %d has caused a PCIe error\n", vf);
+ e_dev_err("TLP: dw0: %8.8x\tdw1: %8.8x\tdw2: "
+ "%8.8x\tdw3: %8.8x\n",
+ dw0, dw1, dw2, dw3);
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82599EB:
+ device_id = IXGBE_82599_VF_DEVICE_ID;
+ break;
+ case ixgbe_mac_X540:
+ device_id = IXGBE_X540_VF_DEVICE_ID;
+ break;
+ default:
+ device_id = 0;
+ break;
+ }
+
+ /* Find the pci device of the offending VF */
+ vfdev = pci_get_device(IXGBE_INTEL_VENDOR_ID, device_id, NULL);
+ while (vfdev) {
+ if (vfdev->devfn == (req_id & 0xFF))
+ break;
+ vfdev = pci_get_device(IXGBE_INTEL_VENDOR_ID,
+ device_id, vfdev);
+ }
+ /*
+ * There's a slim chance the VF could have been hot plugged,
+ * so if it is no longer present we don't need to issue the
+ * VFLR. Just clean up the AER in that case.
+ */
+ if (vfdev) {
+ e_dev_err("Issuing VFLR to VF %d\n", vf);
+ pci_write_config_dword(vfdev, 0xA8, 0x00008000);
+ }
+
+ pci_cleanup_aer_uncorrect_error_status(pdev);
+ }
+
+ /*
+ * Even though the error may have occurred on the other port
+ * we still need to increment the vf error reference count for
+ * both ports because the I/O resume function will be called
+ * for both of them.
+ */
+ adapter->vferr_refcount++;
+
+ return PCI_ERS_RESULT_RECOVERED;
+
+skip_bad_vf_detection:
+#endif /* CONFIG_PCI_IOV */
netif_device_detach(netdev);
if (state == pci_channel_io_perm_failure)
@@ -7849,13 +7965,17 @@ static void ixgbe_io_resume(struct pci_dev *pdev)
struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
struct net_device *netdev = adapter->netdev;
- if (netif_running(netdev)) {
- if (ixgbe_up(adapter)) {
- e_info(probe, "ixgbe_up failed after reset\n");
- return;
- }
+#ifdef CONFIG_PCI_IOV
+ if (adapter->vferr_refcount) {
+ e_info(drv, "Resuming after VF err\n");
+ adapter->vferr_refcount--;
+ return;
}
+#endif
+ if (netif_running(netdev))
+ ixgbe_up(adapter);
+
netif_device_attach(netdev);
}
diff --git a/drivers/net/ixgbe/ixgbe_mbx.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c
index 1ff0eefcfd0a..3f725d48336d 100644
--- a/drivers/net/ixgbe/ixgbe_mbx.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c
@@ -38,7 +38,7 @@
* @size: Length of buffer
* @mbx_id: id of mailbox to read
*
- * returns SUCCESS if it successfuly read message from buffer
+ * returns SUCCESS if it successfully read message from buffer
**/
s32 ixgbe_read_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id)
{
diff --git a/drivers/net/ixgbe/ixgbe_mbx.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
index b239bdac38da..b239bdac38da 100644
--- a/drivers/net/ixgbe/ixgbe_mbx.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
index f7ca3511b9fe..9a56fd74e673 100644
--- a/drivers/net/ixgbe/ixgbe_phy.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
@@ -39,7 +39,7 @@ static s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data);
static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw);
static s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data);
static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data);
-static s32 ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl);
+static void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl);
static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl);
static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data);
static bool ixgbe_get_i2c_data(u32 *i2cctl);
@@ -1205,7 +1205,7 @@ s32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
* @data: value read
*
* Performs byte read operation to SFP module's EEPROM over I2C interface at
- * a specified deivce address.
+ * a specified device address.
**/
s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
u8 dev_addr, u8 *data)
@@ -1215,6 +1215,7 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
u32 retry = 0;
u16 swfw_mask = 0;
bool nack = 1;
+ *data = 0;
if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
swfw_mask = IXGBE_GSSR_PHY1_SM;
@@ -1419,19 +1420,15 @@ static void ixgbe_i2c_stop(struct ixgbe_hw *hw)
**/
static s32 ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data)
{
- s32 status = 0;
s32 i;
bool bit = 0;
for (i = 7; i >= 0; i--) {
- status = ixgbe_clock_in_i2c_bit(hw, &bit);
+ ixgbe_clock_in_i2c_bit(hw, &bit);
*data |= bit << i;
-
- if (status != 0)
- break;
}
- return status;
+ return 0;
}
/**
@@ -1472,16 +1469,14 @@ static s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data)
**/
static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw)
{
- s32 status;
+ s32 status = 0;
u32 i = 0;
u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
u32 timeout = 10;
bool ack = 1;
- status = ixgbe_raise_i2c_clk(hw, &i2cctl);
+ ixgbe_raise_i2c_clk(hw, &i2cctl);
- if (status != 0)
- goto out;
/* Minimum high period of clock is 4us */
udelay(IXGBE_I2C_T_HIGH);
@@ -1507,7 +1502,6 @@ static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw)
/* Minimum low period of clock is 4.7 us */
udelay(IXGBE_I2C_T_LOW);
-out:
return status;
}
@@ -1520,10 +1514,9 @@ out:
**/
static s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data)
{
- s32 status;
u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
- status = ixgbe_raise_i2c_clk(hw, &i2cctl);
+ ixgbe_raise_i2c_clk(hw, &i2cctl);
/* Minimum high period of clock is 4us */
udelay(IXGBE_I2C_T_HIGH);
@@ -1536,7 +1529,7 @@ static s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data)
/* Minimum low period of clock is 4.7 us */
udelay(IXGBE_I2C_T_LOW);
- return status;
+ return 0;
}
/**
@@ -1553,7 +1546,7 @@ static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data)
status = ixgbe_set_i2c_data(hw, &i2cctl, data);
if (status == 0) {
- status = ixgbe_raise_i2c_clk(hw, &i2cctl);
+ ixgbe_raise_i2c_clk(hw, &i2cctl);
/* Minimum high period of clock is 4us */
udelay(IXGBE_I2C_T_HIGH);
@@ -1578,10 +1571,8 @@ static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data)
*
* Raises the I2C clock line '0'->'1'
**/
-static s32 ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
+static void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
{
- s32 status = 0;
-
*i2cctl |= IXGBE_I2C_CLK_OUT;
IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl);
@@ -1589,8 +1580,6 @@ static s32 ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
/* SCL rise time (1000ns) */
udelay(IXGBE_I2C_T_RISE);
-
- return status;
}
/**
diff --git a/drivers/net/ixgbe/ixgbe_phy.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
index 197bdd13106a..197bdd13106a 100644
--- a/drivers/net/ixgbe/ixgbe_phy.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
diff --git a/drivers/net/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
index d99d01e21326..db95731863d7 100644
--- a/drivers/net/ixgbe/ixgbe_sriov.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
@@ -40,9 +40,176 @@
#endif
#include "ixgbe.h"
-
+#include "ixgbe_type.h"
#include "ixgbe_sriov.h"
+#ifdef CONFIG_PCI_IOV
+static int ixgbe_find_enabled_vfs(struct ixgbe_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct pci_dev *pvfdev;
+ u16 vf_devfn = 0;
+ int device_id;
+ int vfs_found = 0;
+
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82599EB:
+ device_id = IXGBE_DEV_ID_82599_VF;
+ break;
+ case ixgbe_mac_X540:
+ device_id = IXGBE_DEV_ID_X540_VF;
+ break;
+ default:
+ device_id = 0;
+ break;
+ }
+
+ vf_devfn = pdev->devfn + 0x80;
+ pvfdev = pci_get_device(IXGBE_INTEL_VENDOR_ID, device_id, NULL);
+ while (pvfdev) {
+ if (pvfdev->devfn == vf_devfn)
+ vfs_found++;
+ vf_devfn += 2;
+ pvfdev = pci_get_device(IXGBE_INTEL_VENDOR_ID,
+ device_id, pvfdev);
+ }
+
+ return vfs_found;
+}
+
+void ixgbe_enable_sriov(struct ixgbe_adapter *adapter,
+ const struct ixgbe_info *ii)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ int err = 0;
+ int num_vf_macvlans, i;
+ struct vf_macvlans *mv_list;
+ int pre_existing_vfs = 0;
+
+ pre_existing_vfs = ixgbe_find_enabled_vfs(adapter);
+ if (!pre_existing_vfs && !adapter->num_vfs)
+ return;
+
+ /* If there are pre-existing VFs then we have to force
+ * use of that many because they were not deleted the last
+ * time someone removed the PF driver. That would have
+ * been because they were allocated to guest VMs and can't
+ * be removed. Go ahead and just re-enable the old amount.
+ * If the user wants to change the number of VFs they can
+ * use ethtool while making sure no VFs are allocated to
+ * guest VMs... i.e. the right way.
+ */
+ if (pre_existing_vfs) {
+ adapter->num_vfs = pre_existing_vfs;
+ dev_warn(&adapter->pdev->dev, "Virtual Functions already "
+ "enabled for this device - Please reload all "
+ "VF drivers to avoid spoofed packet errors\n");
+ } else {
+ err = pci_enable_sriov(adapter->pdev, adapter->num_vfs);
+ }
+ if (err) {
+ e_err(probe, "Failed to enable PCI sriov: %d\n", err);
+ goto err_novfs;
+ }
+ adapter->flags |= IXGBE_FLAG_SRIOV_ENABLED;
+
+ e_info(probe, "SR-IOV enabled with %d VFs\n", adapter->num_vfs);
+
+ num_vf_macvlans = hw->mac.num_rar_entries -
+ (IXGBE_MAX_PF_MACVLANS + 1 + adapter->num_vfs);
+
+ adapter->mv_list = mv_list = kcalloc(num_vf_macvlans,
+ sizeof(struct vf_macvlans),
+ GFP_KERNEL);
+ if (mv_list) {
+ /* Initialize list of VF macvlans */
+ INIT_LIST_HEAD(&adapter->vf_mvs.l);
+ for (i = 0; i < num_vf_macvlans; i++) {
+ mv_list->vf = -1;
+ mv_list->free = true;
+ mv_list->rar_entry = hw->mac.num_rar_entries -
+ (i + adapter->num_vfs + 1);
+ list_add(&mv_list->l, &adapter->vf_mvs.l);
+ mv_list++;
+ }
+ }
+
+ /* If call to enable VFs succeeded then allocate memory
+ * for per VF control structures.
+ */
+ adapter->vfinfo =
+ kcalloc(adapter->num_vfs,
+ sizeof(struct vf_data_storage), GFP_KERNEL);
+ if (adapter->vfinfo) {
+ /* Now that we're sure SR-IOV is enabled
+ * and memory allocated set up the mailbox parameters
+ */
+ ixgbe_init_mbx_params_pf(hw);
+ memcpy(&hw->mbx.ops, ii->mbx_ops,
+ sizeof(hw->mbx.ops));
+
+ /* Disable RSC when in SR-IOV mode */
+ adapter->flags2 &= ~(IXGBE_FLAG2_RSC_CAPABLE |
+ IXGBE_FLAG2_RSC_ENABLED);
+ for (i = 0; i < adapter->num_vfs; i++)
+ adapter->vfinfo[i].spoofchk_enabled = true;
+ return;
+ }
+
+ /* Oh oh */
+ e_err(probe, "Unable to allocate memory for VF Data Storage - "
+ "SRIOV disabled\n");
+ pci_disable_sriov(adapter->pdev);
+
+err_novfs:
+ adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED;
+ adapter->num_vfs = 0;
+}
+#endif /* #ifdef CONFIG_PCI_IOV */
+
+void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 gcr;
+ u32 gpie;
+ u32 vmdctl;
+ int i;
+
+#ifdef CONFIG_PCI_IOV
+ /* disable iov and allow time for transactions to clear */
+ pci_disable_sriov(adapter->pdev);
+#endif
+
+ /* turn off device IOV mode */
+ gcr = IXGBE_READ_REG(hw, IXGBE_GCR_EXT);
+ gcr &= ~(IXGBE_GCR_EXT_SRIOV);
+ IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, gcr);
+ gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
+ gpie &= ~IXGBE_GPIE_VTMODE_MASK;
+ IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
+
+ /* set default pool back to 0 */
+ vmdctl = IXGBE_READ_REG(hw, IXGBE_VT_CTL);
+ vmdctl &= ~IXGBE_VT_CTL_POOL_MASK;
+ IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vmdctl);
+ IXGBE_WRITE_FLUSH(hw);
+
+ /* take a breather then clean up driver data */
+ msleep(100);
+
+ /* Release reference to VF devices */
+ for (i = 0; i < adapter->num_vfs; i++) {
+ if (adapter->vfinfo[i].vfdev)
+ pci_dev_put(adapter->vfinfo[i].vfdev);
+ }
+ kfree(adapter->vfinfo);
+ kfree(adapter->mv_list);
+ adapter->vfinfo = NULL;
+
+ adapter->num_vfs = 0;
+ adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED;
+}
+
static int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter,
int entries, u16 *hash_list, u32 vf)
{
@@ -273,11 +440,26 @@ static int ixgbe_set_vf_macvlan(struct ixgbe_adapter *adapter,
return 0;
}
+int ixgbe_check_vf_assignment(struct ixgbe_adapter *adapter)
+{
+ int i;
+ for (i = 0; i < adapter->num_vfs; i++) {
+ if (adapter->vfinfo[i].vfdev->dev_flags &
+ PCI_DEV_FLAGS_ASSIGNED)
+ return true;
+ }
+ return false;
+}
+
int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask)
{
unsigned char vf_mac_addr[6];
struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
unsigned int vfn = (event_mask & 0x3f);
+ struct pci_dev *pvfdev;
+ unsigned int device_id;
+ u16 thisvf_devfn = (pdev->devfn + 0x80 + (vfn << 1)) |
+ (pdev->devfn & 1);
bool enable = ((event_mask & 0x10000000U) != 0);
@@ -290,6 +472,31 @@ int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask)
* for it later.
*/
memcpy(adapter->vfinfo[vfn].vf_mac_addresses, vf_mac_addr, 6);
+
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82599EB:
+ device_id = IXGBE_DEV_ID_82599_VF;
+ break;
+ case ixgbe_mac_X540:
+ device_id = IXGBE_DEV_ID_X540_VF;
+ break;
+ default:
+ device_id = 0;
+ break;
+ }
+
+ pvfdev = pci_get_device(IXGBE_INTEL_VENDOR_ID, device_id, NULL);
+ while (pvfdev) {
+ if (pvfdev->devfn == thisvf_devfn)
+ break;
+ pvfdev = pci_get_device(IXGBE_INTEL_VENDOR_ID,
+ device_id, pvfdev);
+ }
+ if (pvfdev)
+ adapter->vfinfo[vfn].vfdev = pvfdev;
+ else
+ e_err(drv, "Couldn't find pci dev ptr for VF %4.4x\n",
+ thisvf_devfn);
}
return 0;
@@ -415,7 +622,13 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
vf);
retval = -1;
} else {
+ if (add)
+ adapter->vfinfo[vf].vlan_count++;
+ else if (adapter->vfinfo[vf].vlan_count)
+ adapter->vfinfo[vf].vlan_count--;
retval = ixgbe_set_vf_vlan(adapter, add, vid, vf);
+ if (!retval && adapter->vfinfo[vf].spoofchk_enabled)
+ hw->mac.ops.set_vlan_anti_spoofing(hw, true, vf);
}
break;
case IXGBE_VF_SET_MACVLAN:
@@ -427,12 +640,8 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
* greater than 0 will indicate the VF is setting a
* macvlan MAC filter.
*/
- if (index > 0 && adapter->antispoofing_enabled) {
- hw->mac.ops.set_mac_anti_spoofing(hw, false,
- adapter->num_vfs);
- hw->mac.ops.set_vlan_anti_spoofing(hw, false, vf);
- adapter->antispoofing_enabled = false;
- }
+ if (index > 0 && adapter->vfinfo[vf].spoofchk_enabled)
+ ixgbe_ndo_set_vf_spoofchk(adapter->netdev, vf, false);
retval = ixgbe_set_vf_macvlan(adapter, vf, index,
(unsigned char *)(&msgbuf[1]));
break;
@@ -543,8 +752,9 @@ int ixgbe_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)
goto out;
ixgbe_set_vmvir(adapter, vlan | (qos << VLAN_PRIO_SHIFT), vf);
ixgbe_set_vmolr(hw, vf, false);
- if (adapter->antispoofing_enabled)
+ if (adapter->vfinfo[vf].spoofchk_enabled)
hw->mac.ops.set_vlan_anti_spoofing(hw, true, vf);
+ adapter->vfinfo[vf].vlan_count++;
adapter->vfinfo[vf].pf_vlan = vlan;
adapter->vfinfo[vf].pf_qos = qos;
dev_info(&adapter->pdev->dev,
@@ -563,6 +773,8 @@ int ixgbe_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)
ixgbe_set_vmvir(adapter, vlan, vf);
ixgbe_set_vmolr(hw, vf, true);
hw->mac.ops.set_vlan_anti_spoofing(hw, false, vf);
+ if (adapter->vfinfo[vf].vlan_count)
+ adapter->vfinfo[vf].vlan_count--;
adapter->vfinfo[vf].pf_vlan = 0;
adapter->vfinfo[vf].pf_qos = 0;
}
@@ -672,6 +884,32 @@ int ixgbe_ndo_set_vf_bw(struct net_device *netdev, int vf, int tx_rate)
return 0;
}
+int ixgbe_ndo_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ int vf_target_reg = vf >> 3;
+ int vf_target_shift = vf % 8;
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 regval;
+
+ adapter->vfinfo[vf].spoofchk_enabled = setting;
+
+ regval = IXGBE_READ_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg));
+ regval &= ~(1 << vf_target_shift);
+ regval |= (setting << vf_target_shift);
+ IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg), regval);
+
+ if (adapter->vfinfo[vf].vlan_count) {
+ vf_target_shift += IXGBE_SPOOF_VLANAS_SHIFT;
+ regval = IXGBE_READ_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg));
+ regval &= ~(1 << vf_target_shift);
+ regval |= (setting << vf_target_shift);
+ IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg), regval);
+ }
+
+ return 0;
+}
+
int ixgbe_ndo_get_vf_config(struct net_device *netdev,
int vf, struct ifla_vf_info *ivi)
{
@@ -683,5 +921,6 @@ int ixgbe_ndo_get_vf_config(struct net_device *netdev,
ivi->tx_rate = adapter->vfinfo[vf].tx_rate;
ivi->vlan = adapter->vfinfo[vf].pf_vlan;
ivi->qos = adapter->vfinfo[vf].pf_qos;
+ ivi->spoofchk = adapter->vfinfo[vf].spoofchk_enabled;
return 0;
}
diff --git a/drivers/net/ixgbe/ixgbe_sriov.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h
index 34175564bb78..5a7e1eb33599 100644
--- a/drivers/net/ixgbe/ixgbe_sriov.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h
@@ -38,9 +38,15 @@ int ixgbe_ndo_set_vf_mac(struct net_device *netdev, int queue, u8 *mac);
int ixgbe_ndo_set_vf_vlan(struct net_device *netdev, int queue, u16 vlan,
u8 qos);
int ixgbe_ndo_set_vf_bw(struct net_device *netdev, int vf, int tx_rate);
+int ixgbe_ndo_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting);
int ixgbe_ndo_get_vf_config(struct net_device *netdev,
int vf, struct ifla_vf_info *ivi);
void ixgbe_check_vf_rate_limit(struct ixgbe_adapter *adapter);
+void ixgbe_disable_sriov(struct ixgbe_adapter *adapter);
+void ixgbe_enable_sriov(struct ixgbe_adapter *adapter,
+ const struct ixgbe_info *ii);
+int ixgbe_check_vf_assignment(struct ixgbe_adapter *adapter);
+
#endif /* _IXGBE_SRIOV_H_ */
diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
index e0d970ebab7a..6c5cca808bd7 100644
--- a/drivers/net/ixgbe/ixgbe_type.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
@@ -59,12 +59,17 @@
#define IXGBE_SUBDEV_ID_82599_SFP 0x11A9
#define IXGBE_DEV_ID_82599_SFP_EM 0x1507
#define IXGBE_DEV_ID_82599_SFP_SF2 0x154D
+#define IXGBE_DEV_ID_82599EN_SFP 0x1557
#define IXGBE_DEV_ID_82599_XAUI_LOM 0x10FC
#define IXGBE_DEV_ID_82599_COMBO_BACKPLANE 0x10F8
#define IXGBE_SUBDEV_ID_82599_KX4_KR_MEZZ 0x000C
#define IXGBE_DEV_ID_82599_LS 0x154F
#define IXGBE_DEV_ID_X540T 0x1528
+/* VF Device IDs */
+#define IXGBE_DEV_ID_82599_VF 0x10ED
+#define IXGBE_DEV_ID_X540_VF 0x1515
+
/* General Registers */
#define IXGBE_CTRL 0x00000
#define IXGBE_STATUS 0x00008
@@ -400,6 +405,8 @@
#define IXGBE_WUPL_LENGTH_MASK 0xFFFF
/* DCB registers */
+#define MAX_TRAFFIC_CLASS 8
+#define X540_TRAFFIC_CLASS 4
#define IXGBE_RMCS 0x03D00
#define IXGBE_DPMCS 0x07F40
#define IXGBE_PDPMCS 0x0CD00
@@ -766,6 +773,7 @@
#define IXGBE_GCR_CAP_VER2 0x00040000
#define IXGBE_GCR_EXT_MSIX_EN 0x80000000
+#define IXGBE_GCR_EXT_BUFFERS_CLEAR 0x40000000
#define IXGBE_GCR_EXT_VT_MODE_16 0x00000001
#define IXGBE_GCR_EXT_VT_MODE_32 0x00000002
#define IXGBE_GCR_EXT_VT_MODE_64 0x00000003
@@ -982,6 +990,7 @@
#define IXGBE_CTRL_GIO_DIS 0x00000004 /* Global IO Master Disable bit */
#define IXGBE_CTRL_LNK_RST 0x00000008 /* Link Reset. Resets everything. */
#define IXGBE_CTRL_RST 0x04000000 /* Reset (SW) */
+#define IXGBE_CTRL_RST_MASK (IXGBE_CTRL_LNK_RST | IXGBE_CTRL_RST)
/* FACTPS */
#define IXGBE_FACTPS_LFS 0x40000000 /* LAN Function Select */
@@ -1273,6 +1282,7 @@ enum {
#define IXGBE_EICR_LSC 0x00100000 /* Link Status Change */
#define IXGBE_EICR_LINKSEC 0x00200000 /* PN Threshold */
#define IXGBE_EICR_MNG 0x00400000 /* Manageability Event Interrupt */
+#define IXGBE_EICR_TS 0x00800000 /* Thermal Sensor Event */
#define IXGBE_EICR_GPI_SDP0 0x01000000 /* Gen Purpose Interrupt on SDP0 */
#define IXGBE_EICR_GPI_SDP1 0x02000000 /* Gen Purpose Interrupt on SDP1 */
#define IXGBE_EICR_GPI_SDP2 0x04000000 /* Gen Purpose Interrupt on SDP2 */
@@ -1307,6 +1317,7 @@ enum {
#define IXGBE_EIMS_MAILBOX IXGBE_EICR_MAILBOX /* VF to PF Mailbox Int */
#define IXGBE_EIMS_LSC IXGBE_EICR_LSC /* Link Status Change */
#define IXGBE_EIMS_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */
+#define IXGBE_EIMS_TS IXGBE_EICR_TS /* Thermel Sensor Event */
#define IXGBE_EIMS_GPI_SDP0 IXGBE_EICR_GPI_SDP0 /* SDP0 Gen Purpose Int */
#define IXGBE_EIMS_GPI_SDP1 IXGBE_EICR_GPI_SDP1 /* SDP1 Gen Purpose Int */
#define IXGBE_EIMS_GPI_SDP2 IXGBE_EICR_GPI_SDP2 /* SDP2 Gen Purpose Int */
@@ -1748,6 +1759,10 @@ enum {
#define IXGBE_ALT_SAN_MAC_ADDR_CAPS_SANMAC 0x0 /* Alt. SAN MAC exists */
#define IXGBE_ALT_SAN_MAC_ADDR_CAPS_ALTWWN 0x1 /* Alt. WWN base exists */
+#define IXGBE_DEVICE_CAPS_WOL_PORT0_1 0x4 /* WoL supported on ports 0 & 1 */
+#define IXGBE_DEVICE_CAPS_WOL_PORT0 0x8 /* WoL supported on port 0 */
+#define IXGBE_DEVICE_CAPS_WOL_MASK 0xC /* Mask for WoL capabilities */
+
/* PCI Bus Info */
#define IXGBE_PCI_DEVICE_STATUS 0xAA
#define IXGBE_PCI_DEVICE_STATUS_TRANSACTION_PENDING 0x0020
@@ -1817,6 +1832,7 @@ enum {
#define IXGBE_RXCTRL_RXEN 0x00000001 /* Enable Receiver */
#define IXGBE_RXCTRL_DMBYPS 0x00000002 /* Descriptor Monitor Bypass */
#define IXGBE_RXDCTL_ENABLE 0x02000000 /* Enable specific Rx Queue */
+#define IXGBE_RXDCTL_SWFLSH 0x04000000 /* Rx Desc. write-back flushing */
#define IXGBE_RXDCTL_RLPMLMASK 0x00003FFF /* Only supported on the X540 */
#define IXGBE_RXDCTL_RLPML_EN 0x00008000
#define IXGBE_RXDCTL_VME 0x40000000 /* VLAN mode enable */
@@ -1834,6 +1850,7 @@ enum {
#define IXGBE_MFLCN_DPF 0x00000002 /* Discard Pause Frame */
#define IXGBE_MFLCN_RPFCE 0x00000004 /* Receive Priority FC Enable */
#define IXGBE_MFLCN_RFCE 0x00000008 /* Receive FC Enable */
+#define IXGBE_MFLCN_RPFCE_MASK 0x00000FF0 /* Receive FC Mask */
#define IXGBE_MFLCN_RPFCE_SHIFT 4
@@ -2311,13 +2328,60 @@ typedef u32 ixgbe_physical_layer;
#define IXGBE_PHYSICAL_LAYER_10GBASE_XAUI 0x1000
#define IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA 0x2000
-/* Flow Control Macros */
-#define PAUSE_RTT 8
-#define PAUSE_MTU(MTU) ((MTU + 1024 - 1) / 1024)
+/* Flow Control Data Sheet defined values
+ * Calculation and defines taken from 802.1bb Annex O
+ */
+
+/* BitTimes (BT) conversion */
+#define IXGBE_BT2KB(BT) ((BT + 1023) / (8 * 1024))
+#define IXGBE_B2BT(BT) (BT * 8)
+
+/* Calculate Delay to respond to PFC */
+#define IXGBE_PFC_D 672
+
+/* Calculate Cable Delay */
+#define IXGBE_CABLE_DC 5556 /* Delay Copper */
+#define IXGBE_CABLE_DO 5000 /* Delay Optical */
+
+/* Calculate Interface Delay X540 */
+#define IXGBE_PHY_DC 25600 /* Delay 10G BASET */
+#define IXGBE_MAC_DC 8192 /* Delay Copper XAUI interface */
+#define IXGBE_XAUI_DC (2 * 2048) /* Delay Copper Phy */
+
+#define IXGBE_ID_X540 (IXGBE_MAC_DC + IXGBE_XAUI_DC + IXGBE_PHY_DC)
+
+/* Calculate Interface Delay 82598, 82599 */
+#define IXGBE_PHY_D 12800
+#define IXGBE_MAC_D 4096
+#define IXGBE_XAUI_D (2 * 1024)
+
+#define IXGBE_ID (IXGBE_MAC_D + IXGBE_XAUI_D + IXGBE_PHY_D)
+
+/* Calculate Delay incurred from higher layer */
+#define IXGBE_HD 6144
+
+/* Calculate PCI Bus delay for low thresholds */
+#define IXGBE_PCI_DELAY 10000
+
+/* Calculate X540 delay value in bit times */
+#define IXGBE_FILL_RATE (36 / 25)
+
+#define IXGBE_DV_X540(LINK, TC) (IXGBE_FILL_RATE * \
+ (IXGBE_B2BT(LINK) + IXGBE_PFC_D + \
+ (2 * IXGBE_CABLE_DC) + \
+ (2 * IXGBE_ID_X540) + \
+ IXGBE_HD + IXGBE_B2BT(TC)))
+
+/* Calculate 82599, 82598 delay value in bit times */
+#define IXGBE_DV(LINK, TC) (IXGBE_FILL_RATE * \
+ (IXGBE_B2BT(LINK) + IXGBE_PFC_D + \
+ (2 * IXGBE_CABLE_DC) + (2 * IXGBE_ID) + \
+ IXGBE_HD + IXGBE_B2BT(TC)))
-#define FC_HIGH_WATER(MTU) ((((PAUSE_RTT + PAUSE_MTU(MTU)) * 144) + 99) / 100 +\
- PAUSE_MTU(MTU))
-#define FC_LOW_WATER(MTU) (2 * (2 * PAUSE_MTU(MTU) + PAUSE_RTT))
+/* Calculate low threshold delay values */
+#define IXGBE_LOW_DV_X540(TC) (2 * IXGBE_B2BT(TC) + \
+ (IXGBE_FILL_RATE * IXGBE_PCI_DELAY))
+#define IXGBE_LOW_DV(TC) (2 * IXGBE_LOW_DV_X540(TC))
/* Software ATR hash keys */
#define IXGBE_ATR_BUCKET_HASH_KEY 0x3DAD14E2
@@ -2536,7 +2600,7 @@ struct ixgbe_bus_info {
/* Flow control parameters */
struct ixgbe_fc_info {
- u32 high_water; /* Flow Control High-water */
+ u32 high_water[MAX_TRAFFIC_CLASS]; /* Flow Control High-water */
u32 low_water; /* Flow Control Low-water */
u16 pause_time; /* Flow Control Pause timer */
bool send_xon; /* Flow control send XON */
@@ -2618,6 +2682,8 @@ struct ixgbe_hw_stats {
u64 fcoeptc;
u64 fcoedwrc;
u64 fcoedwtc;
+ u64 fcoe_noddp;
+ u64 fcoe_noddp_ext_buff;
u64 b2ospc;
u64 b2ogprc;
u64 o2bgptc;
diff --git a/drivers/net/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
index 2696c78e9f46..e5101e91b6b5 100644
--- a/drivers/net/ixgbe/ixgbe_x540.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
@@ -93,79 +93,47 @@ static s32 ixgbe_setup_mac_link_X540(struct ixgbe_hw *hw,
**/
static s32 ixgbe_reset_hw_X540(struct ixgbe_hw *hw)
{
- ixgbe_link_speed link_speed;
- s32 status = 0;
- u32 ctrl;
- u32 ctrl_ext;
- u32 reset_bit;
- u32 i;
- u32 autoc;
- u32 autoc2;
- bool link_up = false;
+ s32 status;
+ u32 ctrl, i;
/* Call adapter stop to disable tx/rx and clear interrupts */
- hw->mac.ops.stop_adapter(hw);
+ status = hw->mac.ops.stop_adapter(hw);
+ if (status != 0)
+ goto reset_hw_out;
- /*
- * Prevent the PCI-E bus from from hanging by disabling PCI-E master
- * access and verify no pending requests before reset
- */
- ixgbe_disable_pcie_master(hw);
+ /* flush pending Tx transactions */
+ ixgbe_clear_tx_pending(hw);
mac_reset_top:
- /*
- * Issue global reset to the MAC. Needs to be SW reset if link is up.
- * If link reset is used when link is up, it might reset the PHY when
- * mng is using it. If link is down or the flag to force full link
- * reset is set, then perform link reset.
- */
- if (hw->force_full_reset) {
- reset_bit = IXGBE_CTRL_LNK_RST;
- } else {
- hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
- if (!link_up)
- reset_bit = IXGBE_CTRL_LNK_RST;
- else
- reset_bit = IXGBE_CTRL_RST;
- }
-
- ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
- IXGBE_WRITE_REG(hw, IXGBE_CTRL, (ctrl | reset_bit));
+ ctrl = IXGBE_CTRL_RST;
+ ctrl |= IXGBE_READ_REG(hw, IXGBE_CTRL);
+ IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl);
IXGBE_WRITE_FLUSH(hw);
/* Poll for reset bit to self-clear indicating reset is complete */
for (i = 0; i < 10; i++) {
udelay(1);
ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
- if (!(ctrl & reset_bit))
+ if (!(ctrl & IXGBE_CTRL_RST_MASK))
break;
}
- if (ctrl & reset_bit) {
+
+ if (ctrl & IXGBE_CTRL_RST_MASK) {
status = IXGBE_ERR_RESET_FAILED;
hw_dbg(hw, "Reset polling failed to complete.\n");
}
+ msleep(100);
/*
* Double resets are required for recovery from certain error
* conditions. Between resets, it is necessary to stall to allow time
- * for any pending HW events to complete. We use 1usec since that is
- * what is needed for ixgbe_disable_pcie_master(). The second reset
- * then clears out any effects of those events.
+ * for any pending HW events to complete.
*/
if (hw->mac.flags & IXGBE_FLAGS_DOUBLE_RESET_REQUIRED) {
hw->mac.flags &= ~IXGBE_FLAGS_DOUBLE_RESET_REQUIRED;
- udelay(1);
goto mac_reset_top;
}
- /* Clear PF Reset Done bit so PF/VF Mail Ops can work */
- ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
- ctrl_ext |= IXGBE_CTRL_EXT_PFRSTD;
- IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
- IXGBE_WRITE_FLUSH(hw);
-
- msleep(50);
-
/* Set the Rx packet buffer size. */
IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(0), 384 << IXGBE_RXPBSIZE_SHIFT);
@@ -173,31 +141,6 @@ mac_reset_top:
hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr);
/*
- * Store the original AUTOC/AUTOC2 values if they have not been
- * stored off yet. Otherwise restore the stored original
- * values since the reset operation sets back to defaults.
- */
- autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
- autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2);
- if (hw->mac.orig_link_settings_stored == false) {
- hw->mac.orig_autoc = autoc;
- hw->mac.orig_autoc2 = autoc2;
- hw->mac.orig_link_settings_stored = true;
- } else {
- if (autoc != hw->mac.orig_autoc)
- IXGBE_WRITE_REG(hw, IXGBE_AUTOC, (hw->mac.orig_autoc |
- IXGBE_AUTOC_AN_RESTART));
-
- if ((autoc2 & IXGBE_AUTOC2_UPPER_MASK) !=
- (hw->mac.orig_autoc2 & IXGBE_AUTOC2_UPPER_MASK)) {
- autoc2 &= ~IXGBE_AUTOC2_UPPER_MASK;
- autoc2 |= (hw->mac.orig_autoc2 &
- IXGBE_AUTOC2_UPPER_MASK);
- IXGBE_WRITE_REG(hw, IXGBE_AUTOC2, autoc2);
- }
- }
-
- /*
* Store MAC address from RAR0, clear receive address registers, and
* clear the multicast table. Also reset num_rar_entries to 128,
* since we modify this value when programming the SAN MAC address.
@@ -205,9 +148,6 @@ mac_reset_top:
hw->mac.num_rar_entries = IXGBE_X540_MAX_TX_QUEUES;
hw->mac.ops.init_rx_addrs(hw);
- /* Store the permanent mac address */
- hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr);
-
/* Store the permanent SAN mac address */
hw->mac.ops.get_san_mac_addr(hw, hw->mac.san_addr);
@@ -224,6 +164,7 @@ mac_reset_top:
hw->mac.ops.get_wwn_prefix(hw, &hw->mac.wwnn_prefix,
&hw->mac.wwpn_prefix);
+reset_hw_out:
return status;
}
@@ -929,6 +870,7 @@ static struct ixgbe_phy_operations phy_ops_X540 = {
.read_i2c_eeprom = &ixgbe_read_i2c_eeprom_generic,
.write_i2c_eeprom = &ixgbe_write_i2c_eeprom_generic,
.check_overtemp = &ixgbe_tn_check_overtemp,
+ .get_firmware_version = &ixgbe_get_phy_firmware_version_generic,
};
struct ixgbe_info ixgbe_X540_info = {
diff --git a/drivers/net/ixgbevf/Makefile b/drivers/net/ethernet/intel/ixgbevf/Makefile
index 1f35d229e71a..1f35d229e71a 100644
--- a/drivers/net/ixgbevf/Makefile
+++ b/drivers/net/ethernet/intel/ixgbevf/Makefile
diff --git a/drivers/net/ixgbevf/defines.h b/drivers/net/ethernet/intel/ixgbevf/defines.h
index 78abb6f1a866..78abb6f1a866 100644
--- a/drivers/net/ixgbevf/defines.h
+++ b/drivers/net/ethernet/intel/ixgbevf/defines.h
diff --git a/drivers/net/ixgbevf/ethtool.c b/drivers/net/ethernet/intel/ixgbevf/ethtool.c
index deee3754b1f7..e29ba4506b74 100644
--- a/drivers/net/ixgbevf/ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ethtool.c
@@ -117,44 +117,6 @@ static int ixgbevf_get_settings(struct net_device *netdev,
return 0;
}
-static u32 ixgbevf_get_rx_csum(struct net_device *netdev)
-{
- struct ixgbevf_adapter *adapter = netdev_priv(netdev);
- return adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED;
-}
-
-static int ixgbevf_set_rx_csum(struct net_device *netdev, u32 data)
-{
- struct ixgbevf_adapter *adapter = netdev_priv(netdev);
- if (data)
- adapter->flags |= IXGBE_FLAG_RX_CSUM_ENABLED;
- else
- adapter->flags &= ~IXGBE_FLAG_RX_CSUM_ENABLED;
-
- if (netif_running(netdev)) {
- if (!adapter->dev_closed)
- ixgbevf_reinit_locked(adapter);
- } else {
- ixgbevf_reset(adapter);
- }
-
- return 0;
-}
-
-static int ixgbevf_set_tso(struct net_device *netdev, u32 data)
-{
- if (data) {
- netdev->features |= NETIF_F_TSO;
- netdev->features |= NETIF_F_TSO6;
- } else {
- netif_tx_stop_all_queues(netdev);
- netdev->features &= ~NETIF_F_TSO;
- netdev->features &= ~NETIF_F_TSO6;
- netif_tx_start_all_queues(netdev);
- }
- return 0;
-}
-
static u32 ixgbevf_get_msglevel(struct net_device *netdev)
{
struct ixgbevf_adapter *adapter = netdev_priv(netdev);
@@ -319,12 +281,8 @@ static void ixgbevf_get_ringparam(struct net_device *netdev,
ring->rx_max_pending = IXGBEVF_MAX_RXD;
ring->tx_max_pending = IXGBEVF_MAX_TXD;
- ring->rx_mini_max_pending = 0;
- ring->rx_jumbo_max_pending = 0;
ring->rx_pending = rx_ring->count;
ring->tx_pending = tx_ring->count;
- ring->rx_mini_pending = 0;
- ring->rx_jumbo_pending = 0;
}
static int ixgbevf_set_ringparam(struct net_device *netdev,
@@ -720,16 +678,8 @@ static struct ethtool_ops ixgbevf_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_ringparam = ixgbevf_get_ringparam,
.set_ringparam = ixgbevf_set_ringparam,
- .get_rx_csum = ixgbevf_get_rx_csum,
- .set_rx_csum = ixgbevf_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_ipv6_csum,
- .get_sg = ethtool_op_get_sg,
- .set_sg = ethtool_op_set_sg,
.get_msglevel = ixgbevf_get_msglevel,
.set_msglevel = ixgbevf_set_msglevel,
- .get_tso = ethtool_op_get_tso,
- .set_tso = ixgbevf_set_tso,
.self_test = ixgbevf_diag_test,
.get_sset_count = ixgbevf_get_sset_count,
.get_strings = ixgbevf_get_strings,
diff --git a/drivers/net/ixgbevf/ixgbevf.h b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
index 8857df4dd3b9..e6c9d1a927a9 100644
--- a/drivers/net/ixgbevf/ixgbevf.h
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
@@ -34,6 +34,7 @@
#include <linux/io.h>
#include <linux/netdevice.h>
#include <linux/if_vlan.h>
+#include <linux/u64_stats_sync.h>
#include "vf.h"
@@ -71,12 +72,13 @@ struct ixgbevf_ring {
struct ixgbevf_rx_buffer *rx_buffer_info;
};
+ u64 total_bytes;
+ u64 total_packets;
+ struct u64_stats_sync syncp;
+
u16 head;
u16 tail;
- unsigned int total_bytes;
- unsigned int total_packets;
-
u16 reg_idx; /* holds the special value that gets the hardware register
* offset associated with this ring, which is different
* for DCB and RSS modes */
diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
index 3b880a27f8d1..5e92cc2079bd 100644
--- a/drivers/net/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
@@ -44,6 +44,7 @@
#include <net/checksum.h>
#include <net/ip6_checksum.h>
#include <linux/ethtool.h>
+#include <linux/if.h>
#include <linux/if_vlan.h>
#include <linux/prefetch.h>
@@ -202,6 +203,9 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_adapter *adapter,
(count < tx_ring->work_limit)) {
bool cleaned = false;
rmb(); /* read buffer_info after eop_desc */
+ /* eop could change between read and DD-check */
+ if (unlikely(eop != tx_ring->tx_buffer_info[i].next_to_watch))
+ goto cont_loop;
for ( ; !cleaned; count++) {
struct sk_buff *skb;
tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
@@ -231,6 +235,7 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_adapter *adapter,
i = 0;
}
+cont_loop:
eop = tx_ring->tx_buffer_info[i].next_to_watch;
eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
}
@@ -265,11 +270,10 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_adapter *adapter,
IXGBE_WRITE_REG(hw, IXGBE_VTEICS, tx_ring->v_idx);
}
+ u64_stats_update_begin(&tx_ring->syncp);
tx_ring->total_bytes += total_bytes;
tx_ring->total_packets += total_packets;
-
- netdev->stats.tx_bytes += total_bytes;
- netdev->stats.tx_packets += total_packets;
+ u64_stats_update_end(&tx_ring->syncp);
return count < tx_ring->work_limit;
}
@@ -289,12 +293,10 @@ static void ixgbevf_receive_skb(struct ixgbevf_q_vector *q_vector,
{
struct ixgbevf_adapter *adapter = q_vector->adapter;
bool is_vlan = (status & IXGBE_RXD_STAT_VP);
+ u16 tag = le16_to_cpu(rx_desc->wb.upper.vlan);
- if (is_vlan) {
- u16 tag = le16_to_cpu(rx_desc->wb.upper.vlan);
-
+ if (is_vlan && test_bit(tag, adapter->active_vlans))
__vlan_hwaccel_put_tag(skb, tag);
- }
if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL))
napi_gro_receive(&q_vector->napi, skb);
@@ -592,10 +594,10 @@ next_desc:
if (cleaned_count)
ixgbevf_alloc_rx_buffers(adapter, rx_ring, cleaned_count);
+ u64_stats_update_begin(&rx_ring->syncp);
rx_ring->total_packets += total_rx_packets;
rx_ring->total_bytes += total_rx_bytes;
- adapter->netdev->stats.rx_bytes += total_rx_bytes;
- adapter->netdev->stats.rx_packets += total_rx_packets;
+ u64_stats_update_end(&rx_ring->syncp);
return cleaned;
}
@@ -2255,10 +2257,6 @@ void ixgbevf_update_stats(struct ixgbevf_adapter *adapter)
adapter->stats.vfgotc);
UPDATE_VF_COUNTER_32bit(IXGBE_VFMPRC, adapter->stats.last_vfmprc,
adapter->stats.vfmprc);
-
- /* Fill out the OS statistics structure */
- adapter->netdev->stats.multicast = adapter->stats.vfmprc -
- adapter->stats.base_vfmprc;
}
/**
@@ -2914,22 +2912,20 @@ static int ixgbevf_tx_map(struct ixgbevf_adapter *adapter,
}
for (f = 0; f < nr_frags; f++) {
- struct skb_frag_struct *frag;
+ const struct skb_frag_struct *frag;
frag = &skb_shinfo(skb)->frags[f];
- len = min((unsigned int)frag->size, total);
- offset = frag->page_offset;
+ len = min((unsigned int)skb_frag_size(frag), total);
+ offset = 0;
while (len) {
tx_buffer_info = &tx_ring->tx_buffer_info[i];
size = min(len, (unsigned int)IXGBE_MAX_DATA_PER_TXD);
tx_buffer_info->length = size;
- tx_buffer_info->dma = dma_map_page(&adapter->pdev->dev,
- frag->page,
- offset,
- size,
- DMA_TO_DEVICE);
+ tx_buffer_info->dma =
+ skb_frag_dma_map(&adapter->pdev->dev, frag,
+ offset, size, DMA_TO_DEVICE);
tx_buffer_info->mapped_as_page = true;
if (dma_mapping_error(&pdev->dev, tx_buffer_info->dma))
goto dma_error;
@@ -3100,7 +3096,7 @@ static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
count += TXD_USE_COUNT(skb_headlen(skb));
for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
- count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
+ count += TXD_USE_COUNT(skb_frag_size(&skb_shinfo(skb)->frags[f]));
if (ixgbevf_maybe_stop_tx(netdev, tx_ring, count)) {
adapter->tx_busy++;
@@ -3215,18 +3211,69 @@ static void ixgbevf_shutdown(struct pci_dev *pdev)
pci_disable_device(pdev);
}
+static struct rtnl_link_stats64 *ixgbevf_get_stats(struct net_device *netdev,
+ struct rtnl_link_stats64 *stats)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ unsigned int start;
+ u64 bytes, packets;
+ const struct ixgbevf_ring *ring;
+ int i;
+
+ ixgbevf_update_stats(adapter);
+
+ stats->multicast = adapter->stats.vfmprc - adapter->stats.base_vfmprc;
+
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ ring = &adapter->rx_ring[i];
+ do {
+ start = u64_stats_fetch_begin_bh(&ring->syncp);
+ bytes = ring->total_bytes;
+ packets = ring->total_packets;
+ } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+ stats->rx_bytes += bytes;
+ stats->rx_packets += packets;
+ }
+
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ ring = &adapter->tx_ring[i];
+ do {
+ start = u64_stats_fetch_begin_bh(&ring->syncp);
+ bytes = ring->total_bytes;
+ packets = ring->total_packets;
+ } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+ stats->tx_bytes += bytes;
+ stats->tx_packets += packets;
+ }
+
+ return stats;
+}
+
+static int ixgbevf_set_features(struct net_device *netdev, u32 features)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+
+ if (features & NETIF_F_RXCSUM)
+ adapter->flags |= IXGBE_FLAG_RX_CSUM_ENABLED;
+ else
+ adapter->flags &= ~IXGBE_FLAG_RX_CSUM_ENABLED;
+
+ return 0;
+}
+
static const struct net_device_ops ixgbe_netdev_ops = {
.ndo_open = ixgbevf_open,
.ndo_stop = ixgbevf_close,
.ndo_start_xmit = ixgbevf_xmit_frame,
.ndo_set_rx_mode = ixgbevf_set_rx_mode,
- .ndo_set_multicast_list = ixgbevf_set_rx_mode,
+ .ndo_get_stats64 = ixgbevf_get_stats,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = ixgbevf_set_mac,
.ndo_change_mtu = ixgbevf_change_mtu,
.ndo_tx_timeout = ixgbevf_tx_timeout,
.ndo_vlan_rx_add_vid = ixgbevf_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = ixgbevf_vlan_rx_kill_vid,
+ .ndo_set_features = ixgbevf_set_features,
};
static void ixgbevf_assign_netdev_ops(struct net_device *dev)
@@ -3339,16 +3386,18 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
/* setup the private structure */
err = ixgbevf_sw_init(adapter);
- netdev->features = NETIF_F_SG |
+ netdev->hw_features = NETIF_F_SG |
NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM |
+ NETIF_F_TSO |
+ NETIF_F_TSO6 |
+ NETIF_F_RXCSUM;
+
+ netdev->features = netdev->hw_features |
NETIF_F_HW_VLAN_TX |
NETIF_F_HW_VLAN_RX |
NETIF_F_HW_VLAN_FILTER;
- netdev->features |= NETIF_F_IPV6_CSUM;
- netdev->features |= NETIF_F_TSO;
- netdev->features |= NETIF_F_TSO6;
- netdev->features |= NETIF_F_GRO;
netdev->vlan_features |= NETIF_F_TSO;
netdev->vlan_features |= NETIF_F_TSO6;
netdev->vlan_features |= NETIF_F_IP_CSUM;
@@ -3358,6 +3407,8 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
+ netdev->priv_flags |= IFF_UNICAST_FLT;
+
/* The HW MAC address was set and/or determined in sw_init */
memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len);
memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
diff --git a/drivers/net/ixgbevf/mbx.c b/drivers/net/ethernet/intel/ixgbevf/mbx.c
index 7a8833125770..930fa83f2568 100644
--- a/drivers/net/ixgbevf/mbx.c
+++ b/drivers/net/ethernet/intel/ixgbevf/mbx.c
@@ -276,7 +276,7 @@ out_no_write:
* @msg: The message buffer
* @size: Length of buffer
*
- * returns 0 if it successfuly read message from buffer
+ * returns 0 if it successfully read message from buffer
**/
static s32 ixgbevf_read_mbx_vf(struct ixgbe_hw *hw, u32 *msg, u16 size)
{
diff --git a/drivers/net/ixgbevf/mbx.h b/drivers/net/ethernet/intel/ixgbevf/mbx.h
index ea393eb03f3a..ea393eb03f3a 100644
--- a/drivers/net/ixgbevf/mbx.h
+++ b/drivers/net/ethernet/intel/ixgbevf/mbx.h
diff --git a/drivers/net/ixgbevf/regs.h b/drivers/net/ethernet/intel/ixgbevf/regs.h
index 189200eeca26..189200eeca26 100644
--- a/drivers/net/ixgbevf/regs.h
+++ b/drivers/net/ethernet/intel/ixgbevf/regs.h
diff --git a/drivers/net/ixgbevf/vf.c b/drivers/net/ethernet/intel/ixgbevf/vf.c
index aa3682e8c473..aa3682e8c473 100644
--- a/drivers/net/ixgbevf/vf.c
+++ b/drivers/net/ethernet/intel/ixgbevf/vf.c
diff --git a/drivers/net/ixgbevf/vf.h b/drivers/net/ethernet/intel/ixgbevf/vf.h
index 10306b492ee6..10306b492ee6 100644
--- a/drivers/net/ixgbevf/vf.h
+++ b/drivers/net/ethernet/intel/ixgbevf/vf.h
diff --git a/drivers/net/jme.c b/drivers/net/ethernet/jme.c
index 3ac262f55633..7becff1f387d 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/ethernet/jme.c
@@ -1920,7 +1920,7 @@ jme_map_tx_skb(struct jme_adapter *jme, struct sk_buff *skb, int idx)
u8 hidma = jme->dev->features & NETIF_F_HIGHDMA;
int i, nr_frags = skb_shinfo(skb)->nr_frags;
int mask = jme->tx_ring_mask;
- struct skb_frag_struct *frag;
+ const struct skb_frag_struct *frag;
u32 len;
for (i = 0 ; i < nr_frags ; ++i) {
@@ -1928,8 +1928,9 @@ jme_map_tx_skb(struct jme_adapter *jme, struct sk_buff *skb, int idx)
ctxdesc = txdesc + ((idx + i + 2) & (mask));
ctxbi = txbi + ((idx + i + 2) & (mask));
- jme_fill_tx_map(jme->pdev, ctxdesc, ctxbi, frag->page,
- frag->page_offset, frag->size, hidma);
+ jme_fill_tx_map(jme->pdev, ctxdesc, ctxbi,
+ skb_frag_page(frag),
+ frag->page_offset, skb_frag_size(frag), hidma);
}
len = skb_is_nonlinear(skb) ? skb_headlen(skb) : skb->len;
@@ -2839,7 +2840,7 @@ static const struct net_device_ops jme_netdev_ops = {
.ndo_do_ioctl = jme_ioctl,
.ndo_start_xmit = jme_start_xmit,
.ndo_set_mac_address = jme_set_macaddr,
- .ndo_set_multicast_list = jme_set_multi,
+ .ndo_set_rx_mode = jme_set_multi,
.ndo_change_mtu = jme_change_mtu,
.ndo_tx_timeout = jme_tx_timeout,
.ndo_fix_features = jme_fix_features,
@@ -3131,6 +3132,9 @@ jme_suspend(struct device *dev)
struct net_device *netdev = pci_get_drvdata(pdev);
struct jme_adapter *jme = netdev_priv(netdev);
+ if (!netif_running(netdev))
+ return 0;
+
atomic_dec(&jme->link_changing);
netif_device_detach(netdev);
@@ -3171,6 +3175,9 @@ jme_resume(struct device *dev)
struct net_device *netdev = pci_get_drvdata(pdev);
struct jme_adapter *jme = netdev_priv(netdev);
+ if (!netif_running(netdev))
+ return 0;
+
jme_clear_pm(jme);
jme_phy_on(jme);
if (test_bit(JME_FLAG_SSET, &jme->flags))
diff --git a/drivers/net/jme.h b/drivers/net/ethernet/jme.h
index c1f8b893e2ea..02ea27c1dcb5 100644
--- a/drivers/net/jme.h
+++ b/drivers/net/ethernet/jme.h
@@ -102,7 +102,6 @@ enum jme_spi_op_bits {
};
#define HALF_US 500 /* 500 ns */
-#define JMESPIIOCTL SIOCDEVPRIVATE
#define PCI_PRIV_PE1 0xE4
diff --git a/drivers/net/korina.c b/drivers/net/ethernet/korina.c
index 763844c587fd..d8430f487b84 100644
--- a/drivers/net/korina.c
+++ b/drivers/net/ethernet/korina.c
@@ -58,7 +58,6 @@
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/pgtable.h>
-#include <asm/segment.h>
#include <asm/io.h>
#include <asm/dma.h>
@@ -1089,7 +1088,7 @@ static const struct net_device_ops korina_netdev_ops = {
.ndo_open = korina_open,
.ndo_stop = korina_close,
.ndo_start_xmit = korina_send_packet,
- .ndo_set_multicast_list = korina_multicast_list,
+ .ndo_set_rx_mode = korina_multicast_list,
.ndo_tx_timeout = korina_tx_timeout,
.ndo_do_ioctl = korina_ioctl,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c
index 45f252b7da30..6bb2b9506cad 100644
--- a/drivers/net/lantiq_etop.c
+++ b/drivers/net/ethernet/lantiq_etop.c
@@ -687,7 +687,7 @@ static const struct net_device_ops ltq_eth_netdev_ops = {
.ndo_do_ioctl = ltq_etop_ioctl,
.ndo_set_mac_address = ltq_etop_set_mac_address,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = ltq_etop_set_multicast_list,
+ .ndo_set_rx_mode = ltq_etop_set_multicast_list,
.ndo_select_queue = ltq_etop_select_queue,
.ndo_init = ltq_etop_init,
.ndo_tx_timeout = ltq_etop_tx_timeout,
diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig
new file mode 100644
index 000000000000..0029934748bc
--- /dev/null
+++ b/drivers/net/ethernet/marvell/Kconfig
@@ -0,0 +1,111 @@
+#
+# Marvell device configuration
+#
+
+config NET_VENDOR_MARVELL
+ bool "Marvell devices"
+ default y
+ depends on PCI || CPU_PXA168 || MV64X60 || PPC32 || PLAT_ORION || INET
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Marvell devices. If you say Y, you will be
+ asked for your specific card in the following questions.
+
+if NET_VENDOR_MARVELL
+
+config MV643XX_ETH
+ tristate "Marvell Discovery (643XX) and Orion ethernet support"
+ depends on (MV64X60 || PPC32 || PLAT_ORION) && INET
+ select INET_LRO
+ select PHYLIB
+ ---help---
+ This driver supports the gigabit ethernet MACs in the
+ Marvell Discovery PPC/MIPS chipset family (MV643XX) and
+ in the Marvell Orion ARM SoC family.
+
+ Some boards that use the Discovery chipset are the Momenco
+ Ocelot C and Jaguar ATX and Pegasos II.
+
+config PXA168_ETH
+ tristate "Marvell pxa168 ethernet support"
+ depends on CPU_PXA168
+ select PHYLIB
+ ---help---
+ This driver supports the pxa168 Ethernet ports.
+
+ To compile this driver as a module, choose M here. The module
+ will be called pxa168_eth.
+
+config SKGE
+ tristate "Marvell Yukon Gigabit Ethernet support"
+ depends on PCI
+ select CRC32
+ ---help---
+ This driver support the Marvell Yukon or SysKonnect SK-98xx/SK-95xx
+ and related Gigabit Ethernet adapters. It is a new smaller driver
+ with better performance and more complete ethtool support.
+
+ It does not support the link failover and network management
+ features that "portable" vendor supplied sk98lin driver does.
+
+ This driver supports adapters based on the original Yukon chipset:
+ Marvell 88E8001, Belkin F5D5005, CNet GigaCard, DLink DGE-530T,
+ Linksys EG1032/EG1064, 3Com 3C940/3C940B, SysKonnect SK-9871/9872.
+
+ It does not support the newer Yukon2 chipset: a separate driver,
+ sky2, is provided for these adapters.
+
+ To compile this driver as a module, choose M here: the module
+ will be called skge. This is recommended.
+
+config SKGE_DEBUG
+ bool "Debugging interface"
+ depends on SKGE && DEBUG_FS
+ ---help---
+ This option adds the ability to dump driver state for debugging.
+ The file /sys/kernel/debug/skge/ethX displays the state of the internal
+ transmit and receive rings.
+
+ If unsure, say N.
+
+config SKGE_GENESIS
+ bool "Support for older SysKonnect Genesis boards"
+ depends on SKGE
+ ---help---
+ This enables support for the older and uncommon SysKonnect Genesis
+ chips, which support MII via an external transceiver, instead of
+ an internal one. Disabling this option will save some memory
+ by making code smaller. If unsure say Y.
+
+config SKY2
+ tristate "Marvell Yukon 2 support"
+ depends on PCI
+ select CRC32
+ ---help---
+ This driver supports Gigabit Ethernet adapters based on the
+ Marvell Yukon 2 chipset:
+ Marvell 88E8021/88E8022/88E8035/88E8036/88E8038/88E8050/88E8052/
+ 88E8053/88E8055/88E8061/88E8062, SysKonnect SK-9E21D/SK-9S21
+
+ There is companion driver for the older Marvell Yukon and
+ SysKonnect Genesis based adapters: skge.
+
+ To compile this driver as a module, choose M here: the module
+ will be called sky2. This is recommended.
+
+config SKY2_DEBUG
+ bool "Debugging interface"
+ depends on SKY2 && DEBUG_FS
+ ---help---
+ This option adds the ability to dump driver state for debugging.
+ The file /sys/kernel/debug/sky2/ethX displays the state of the internal
+ transmit and receive rings.
+
+ If unsure, say N.
+
+endif # NET_VENDOR_MARVELL
diff --git a/drivers/net/ethernet/marvell/Makefile b/drivers/net/ethernet/marvell/Makefile
new file mode 100644
index 000000000000..57e3234a37ba
--- /dev/null
+++ b/drivers/net/ethernet/marvell/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the Marvell device drivers.
+#
+
+obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o
+obj-$(CONFIG_PXA168_ETH) += pxa168_eth.o
+obj-$(CONFIG_SKGE) += skge.o
+obj-$(CONFIG_SKY2) += sky2.o
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index 259699983ca5..194a03113802 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -713,8 +713,9 @@ static inline unsigned int has_tiny_unaligned_frags(struct sk_buff *skb)
int frag;
for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
- skb_frag_t *fragp = &skb_shinfo(skb)->frags[frag];
- if (fragp->size <= 8 && fragp->page_offset & 7)
+ const skb_frag_t *fragp = &skb_shinfo(skb)->frags[frag];
+
+ if (skb_frag_size(fragp) <= 8 && fragp->page_offset & 7)
return 1;
}
@@ -751,11 +752,11 @@ static void txq_submit_frag_skb(struct tx_queue *txq, struct sk_buff *skb)
}
desc->l4i_chk = 0;
- desc->byte_cnt = this_frag->size;
- desc->buf_ptr = dma_map_page(mp->dev->dev.parent,
- this_frag->page,
- this_frag->page_offset,
- this_frag->size, DMA_TO_DEVICE);
+ desc->byte_cnt = skb_frag_size(this_frag);
+ desc->buf_ptr = skb_frag_dma_map(mp->dev->dev.parent,
+ this_frag, 0,
+ skb_frag_size(this_frag),
+ DMA_TO_DEVICE);
}
}
@@ -1547,13 +1548,9 @@ mv643xx_eth_get_ringparam(struct net_device *dev, struct ethtool_ringparam *er)
er->rx_max_pending = 4096;
er->tx_max_pending = 4096;
- er->rx_mini_max_pending = 0;
- er->rx_jumbo_max_pending = 0;
er->rx_pending = mp->rx_ring_size;
er->tx_pending = mp->tx_ring_size;
- er->rx_mini_pending = 0;
- er->rx_jumbo_pending = 0;
}
static int
@@ -2923,6 +2920,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM;
+ dev->priv_flags |= IFF_UNICAST_FLT;
+
SET_NETDEV_DEV(dev, &pdev->dev);
if (mp->shared->win_protect)
diff --git a/drivers/net/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c
index 1a3033d8e7ed..d17d0624c5e6 100644
--- a/drivers/net/pxa168_eth.c
+++ b/drivers/net/ethernet/marvell/pxa168_eth.c
@@ -40,6 +40,7 @@
#include <linux/clk.h>
#include <linux/phy.h>
#include <linux/io.h>
+#include <linux/interrupt.h>
#include <linux/types.h>
#include <asm/pgtable.h>
#include <asm/system.h>
diff --git a/drivers/net/skge.c b/drivers/net/ethernet/marvell/skge.c
index 98ec614c5690..c7b60839ac99 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/ethernet/marvell/skge.c
@@ -113,6 +113,7 @@ static void yukon_init(struct skge_hw *hw, int port);
static void genesis_mac_init(struct skge_hw *hw, int port);
static void genesis_link_up(struct skge_port *skge);
static void skge_set_multicast(struct net_device *dev);
+static irqreturn_t skge_intr(int irq, void *dev_id);
/* Avoid conditionals by using array */
static const int txqaddr[] = { Q_XA1, Q_XA2 };
@@ -496,13 +497,9 @@ static void skge_get_ring_param(struct net_device *dev,
p->rx_max_pending = MAX_RX_RING_SIZE;
p->tx_max_pending = MAX_TX_RING_SIZE;
- p->rx_mini_max_pending = 0;
- p->rx_jumbo_max_pending = 0;
p->rx_pending = skge->rx_ring.count;
p->tx_pending = skge->tx_ring.count;
- p->rx_mini_pending = 0;
- p->rx_jumbo_pending = 0;
}
static int skge_set_ring_param(struct net_device *dev,
@@ -2568,6 +2565,16 @@ static int skge_up(struct net_device *dev)
if (err)
goto free_rx_ring;
+ if (hw->ports == 1) {
+ err = request_irq(hw->pdev->irq, skge_intr, IRQF_SHARED,
+ dev->name, hw);
+ if (err) {
+ netdev_err(dev, "Unable to allocate interrupt %d error: %d\n",
+ hw->pdev->irq, err);
+ goto free_tx_ring;
+ }
+ }
+
/* Initialize MAC */
spin_lock_bh(&hw->phy_lock);
if (is_genesis(hw))
@@ -2595,11 +2602,14 @@ static int skge_up(struct net_device *dev)
spin_lock_irq(&hw->hw_lock);
hw->intr_mask |= portmask[port];
skge_write32(hw, B0_IMSK, hw->intr_mask);
+ skge_read32(hw, B0_IMSK);
spin_unlock_irq(&hw->hw_lock);
napi_enable(&skge->napi);
return 0;
+ free_tx_ring:
+ kfree(skge->tx_ring.start);
free_rx_ring:
skge_rx_clean(skge);
kfree(skge->rx_ring.start);
@@ -2640,9 +2650,13 @@ static int skge_down(struct net_device *dev)
spin_lock_irq(&hw->hw_lock);
hw->intr_mask &= ~portmask[port];
- skge_write32(hw, B0_IMSK, hw->intr_mask);
+ skge_write32(hw, B0_IMSK, (hw->ports == 1) ? 0 : hw->intr_mask);
+ skge_read32(hw, B0_IMSK);
spin_unlock_irq(&hw->hw_lock);
+ if (hw->ports == 1)
+ free_irq(hw->pdev->irq, hw);
+
skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF);
if (is_genesis(hw))
genesis_stop(skge);
@@ -2756,10 +2770,10 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb,
control |= BMU_STFWD;
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- map = pci_map_page(hw->pdev, frag->page, frag->page_offset,
- frag->size, PCI_DMA_TODEVICE);
+ map = skb_frag_dma_map(&hw->pdev->dev, frag, 0,
+ skb_frag_size(frag), DMA_TO_DEVICE);
e = e->next;
e->skb = skb;
@@ -2769,9 +2783,9 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb,
tf->dma_lo = map;
tf->dma_hi = (u64) map >> 32;
dma_unmap_addr_set(e, mapaddr, map);
- dma_unmap_len_set(e, maplen, frag->size);
+ dma_unmap_len_set(e, maplen, skb_frag_size(frag));
- tf->control = BMU_OWN | BMU_SW | control | frag->size;
+ tf->control = BMU_OWN | BMU_SW | control | skb_frag_size(frag);
}
tf->control |= BMU_EOF | BMU_IRQ_EOF;
}
@@ -3603,7 +3617,8 @@ static int skge_reset(struct skge_hw *hw)
skge_write32(hw, B2_IRQM_INI, skge_usecs2clk(hw, 100));
skge_write32(hw, B2_IRQM_CTRL, TIM_START);
- skge_write32(hw, B0_IMSK, hw->intr_mask);
+ /* Leave irq disabled until first port is brought up. */
+ skge_write32(hw, B0_IMSK, 0);
for (i = 0; i < hw->ports; i++) {
if (is_genesis(hw))
@@ -3762,7 +3777,7 @@ static const struct net_device_ops skge_netdev_ops = {
.ndo_tx_timeout = skge_tx_timeout,
.ndo_change_mtu = skge_change_mtu,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = skge_set_multicast,
+ .ndo_set_rx_mode = skge_set_multicast,
.ndo_set_mac_address = skge_set_mac_address,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = skge_netpoll,
@@ -3930,31 +3945,39 @@ static int __devinit skge_probe(struct pci_dev *pdev,
goto err_out_free_netdev;
}
- err = request_irq(pdev->irq, skge_intr, IRQF_SHARED, hw->irq_name, hw);
- if (err) {
- dev_err(&pdev->dev, "%s: cannot assign irq %d\n",
- dev->name, pdev->irq);
- goto err_out_unregister;
- }
skge_show_addr(dev);
if (hw->ports > 1) {
dev1 = skge_devinit(hw, 1, using_dac);
- if (dev1 && register_netdev(dev1) == 0)
- skge_show_addr(dev1);
- else {
- /* Failure to register second port need not be fatal */
- dev_warn(&pdev->dev, "register of second port failed\n");
- hw->dev[1] = NULL;
- hw->ports = 1;
- if (dev1)
- free_netdev(dev1);
+ if (!dev1) {
+ err = -ENOMEM;
+ goto err_out_unregister;
}
+
+ err = register_netdev(dev1);
+ if (err) {
+ dev_err(&pdev->dev, "cannot register second net device\n");
+ goto err_out_free_dev1;
+ }
+
+ err = request_irq(pdev->irq, skge_intr, IRQF_SHARED,
+ hw->irq_name, hw);
+ if (err) {
+ dev_err(&pdev->dev, "cannot assign irq %d\n",
+ pdev->irq);
+ goto err_out_unregister_dev1;
+ }
+
+ skge_show_addr(dev1);
}
pci_set_drvdata(pdev, hw);
return 0;
+err_out_unregister_dev1:
+ unregister_netdev(dev1);
+err_out_free_dev1:
+ free_netdev(dev1);
err_out_unregister:
unregister_netdev(dev);
err_out_free_netdev:
@@ -3992,14 +4015,19 @@ static void __devexit skge_remove(struct pci_dev *pdev)
spin_lock_irq(&hw->hw_lock);
hw->intr_mask = 0;
- skge_write32(hw, B0_IMSK, 0);
- skge_read32(hw, B0_IMSK);
+
+ if (hw->ports > 1) {
+ skge_write32(hw, B0_IMSK, 0);
+ skge_read32(hw, B0_IMSK);
+ free_irq(pdev->irq, hw);
+ }
spin_unlock_irq(&hw->hw_lock);
skge_write16(hw, B0_LED, LED_STAT_OFF);
skge_write8(hw, B0_CTST, CS_RST_SET);
- free_irq(pdev->irq, hw);
+ if (hw->ports > 1)
+ free_irq(pdev->irq, hw);
pci_release_regions(pdev);
pci_disable_device(pdev);
if (dev1)
diff --git a/drivers/net/skge.h b/drivers/net/ethernet/marvell/skge.h
index a2eb34115844..a2eb34115844 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/ethernet/marvell/skge.h
diff --git a/drivers/net/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index 57339da76326..cbd026f3bc57 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -148,6 +148,7 @@ static const unsigned rxqaddr[] = { Q_R1, Q_R2 };
static const u32 portirq_msk[] = { Y2_IS_PORT_1, Y2_IS_PORT_2 };
static void sky2_set_multicast(struct net_device *dev);
+static irqreturn_t sky2_intr(int irq, void *dev_id);
/* Access to PHY via serial interconnect */
static int gm_phy_write(struct sky2_hw *hw, unsigned port, u16 reg, u16 val)
@@ -1224,14 +1225,13 @@ static int sky2_rx_map_skb(struct pci_dev *pdev, struct rx_ring_info *re,
dma_unmap_len_set(re, data_size, size);
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- re->frag_addr[i] = pci_map_page(pdev, frag->page,
- frag->page_offset,
- frag->size,
- PCI_DMA_FROMDEVICE);
+ re->frag_addr[i] = skb_frag_dma_map(&pdev->dev, frag, 0,
+ skb_frag_size(frag),
+ DMA_FROM_DEVICE);
- if (pci_dma_mapping_error(pdev, re->frag_addr[i]))
+ if (dma_mapping_error(&pdev->dev, re->frag_addr[i]))
goto map_page_error;
}
return 0;
@@ -1239,7 +1239,7 @@ static int sky2_rx_map_skb(struct pci_dev *pdev, struct rx_ring_info *re,
map_page_error:
while (--i >= 0) {
pci_unmap_page(pdev, re->frag_addr[i],
- skb_shinfo(skb)->frags[i].size,
+ skb_frag_size(&skb_shinfo(skb)->frags[i]),
PCI_DMA_FROMDEVICE);
}
@@ -1263,7 +1263,7 @@ static void sky2_rx_unmap_skb(struct pci_dev *pdev, struct rx_ring_info *re)
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
pci_unmap_page(pdev, re->frag_addr[i],
- skb_shinfo(skb)->frags[i].size,
+ skb_frag_size(&skb_shinfo(skb)->frags[i]),
PCI_DMA_FROMDEVICE);
}
@@ -1716,6 +1716,27 @@ static void sky2_hw_up(struct sky2_port *sky2)
sky2_rx_start(sky2);
}
+/* Setup device IRQ and enable napi to process */
+static int sky2_setup_irq(struct sky2_hw *hw, const char *name)
+{
+ struct pci_dev *pdev = hw->pdev;
+ int err;
+
+ err = request_irq(pdev->irq, sky2_intr,
+ (hw->flags & SKY2_HW_USE_MSI) ? 0 : IRQF_SHARED,
+ name, hw);
+ if (err)
+ dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq);
+ else {
+ napi_enable(&hw->napi);
+ sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
+ sky2_read32(hw, B0_IMSK);
+ }
+
+ return err;
+}
+
+
/* Bring up network interface. */
static int sky2_up(struct net_device *dev)
{
@@ -1731,6 +1752,10 @@ static int sky2_up(struct net_device *dev)
if (err)
goto err_out;
+ /* With single port, IRQ is setup when device is brought up */
+ if (hw->ports == 1 && (err = sky2_setup_irq(hw, dev->name)))
+ goto err_out;
+
sky2_hw_up(sky2);
/* Enable interrupts from phy/mac for port */
@@ -1910,10 +1935,10 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- mapping = pci_map_page(hw->pdev, frag->page, frag->page_offset,
- frag->size, PCI_DMA_TODEVICE);
+ mapping = skb_frag_dma_map(&hw->pdev->dev, frag, 0,
+ skb_frag_size(frag), DMA_TO_DEVICE);
- if (pci_dma_mapping_error(hw->pdev, mapping))
+ if (dma_mapping_error(&hw->pdev->dev, mapping))
goto mapping_unwind;
upper = upper_32_bits(mapping);
@@ -1927,11 +1952,11 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
re = sky2->tx_ring + slot;
re->flags = TX_MAP_PAGE;
dma_unmap_addr_set(re, mapaddr, mapping);
- dma_unmap_len_set(re, maplen, frag->size);
+ dma_unmap_len_set(re, maplen, skb_frag_size(frag));
le = get_tx_le(sky2, &slot);
le->addr = cpu_to_le32(lower_32_bits(mapping));
- le->length = cpu_to_le16(frag->size);
+ le->length = cpu_to_le16(skb_frag_size(frag));
le->ctrl = ctrl;
le->opcode = OP_BUFFER | HW_OWNER;
}
@@ -2057,7 +2082,7 @@ static void sky2_hw_down(struct sky2_port *sky2)
sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
- /* Force any delayed status interrrupt and NAPI */
+ /* Force any delayed status interrupt and NAPI */
sky2_write32(hw, STAT_LEV_TIMER_CNT, 0);
sky2_write32(hw, STAT_TX_TIMER_CNT, 0);
sky2_write32(hw, STAT_ISR_TIMER_CNT, 0);
@@ -2092,8 +2117,13 @@ static int sky2_down(struct net_device *dev)
sky2_read32(hw, B0_IMSK) & ~portirq_msk[sky2->port]);
sky2_read32(hw, B0_IMSK);
- synchronize_irq(hw->pdev->irq);
- napi_synchronize(&hw->napi);
+ if (hw->ports == 1) {
+ napi_disable(&hw->napi);
+ free_irq(hw->pdev->irq, hw);
+ } else {
+ synchronize_irq(hw->pdev->irq);
+ napi_synchronize(&hw->napi);
+ }
sky2_hw_down(sky2);
@@ -2449,14 +2479,14 @@ static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space,
if (length == 0) {
/* don't need this page */
- __free_page(frag->page);
+ __skb_frag_unref(frag);
--skb_shinfo(skb)->nr_frags;
} else {
size = min(length, (unsigned) PAGE_SIZE);
- frag->size = size;
+ skb_frag_size_set(frag, size);
skb->data_len += size;
- skb->truesize += size;
+ skb->truesize += PAGE_SIZE;
skb->len += size;
length -= size;
}
@@ -4058,13 +4088,9 @@ static void sky2_get_ringparam(struct net_device *dev,
struct sky2_port *sky2 = netdev_priv(dev);
ering->rx_max_pending = RX_MAX_PENDING;
- ering->rx_mini_max_pending = 0;
- ering->rx_jumbo_max_pending = 0;
ering->tx_max_pending = TX_MAX_PENDING;
ering->rx_pending = sky2->rx_pending;
- ering->rx_mini_pending = 0;
- ering->rx_jumbo_pending = 0;
ering->tx_pending = sky2->tx_pending;
}
@@ -4612,7 +4638,7 @@ static const struct net_device_ops sky2_netdev_ops[2] = {
.ndo_do_ioctl = sky2_ioctl,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = sky2_set_mac_address,
- .ndo_set_multicast_list = sky2_set_multicast,
+ .ndo_set_rx_mode = sky2_set_multicast,
.ndo_change_mtu = sky2_change_mtu,
.ndo_fix_features = sky2_fix_features,
.ndo_set_features = sky2_set_features,
@@ -4629,7 +4655,7 @@ static const struct net_device_ops sky2_netdev_ops[2] = {
.ndo_do_ioctl = sky2_ioctl,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = sky2_set_mac_address,
- .ndo_set_multicast_list = sky2_set_multicast,
+ .ndo_set_rx_mode = sky2_set_multicast,
.ndo_change_mtu = sky2_change_mtu,
.ndo_fix_features = sky2_fix_features,
.ndo_set_features = sky2_set_features,
@@ -4799,7 +4825,7 @@ static const char *sky2_name(u8 chipid, char *buf, int sz)
static int __devinit sky2_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- struct net_device *dev;
+ struct net_device *dev, *dev1;
struct sky2_hw *hw;
int err, using_dac = 0, wol_default;
u32 reg;
@@ -4925,33 +4951,26 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
netif_napi_add(dev, &hw->napi, sky2_poll, NAPI_WEIGHT);
- err = request_irq(pdev->irq, sky2_intr,
- (hw->flags & SKY2_HW_USE_MSI) ? 0 : IRQF_SHARED,
- hw->irq_name, hw);
- if (err) {
- dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq);
- goto err_out_unregister;
- }
- sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
- napi_enable(&hw->napi);
-
sky2_show_addr(dev);
if (hw->ports > 1) {
- struct net_device *dev1;
-
- err = -ENOMEM;
dev1 = sky2_init_netdev(hw, 1, using_dac, wol_default);
- if (dev1 && (err = register_netdev(dev1)) == 0)
- sky2_show_addr(dev1);
- else {
- dev_warn(&pdev->dev,
- "register of second port failed (%d)\n", err);
- hw->dev[1] = NULL;
- hw->ports = 1;
- if (dev1)
- free_netdev(dev1);
+ if (!dev1) {
+ err = -ENOMEM;
+ goto err_out_unregister;
}
+
+ err = register_netdev(dev1);
+ if (err) {
+ dev_err(&pdev->dev, "cannot register second net device\n");
+ goto err_out_free_dev1;
+ }
+
+ err = sky2_setup_irq(hw, hw->irq_name);
+ if (err)
+ goto err_out_unregister_dev1;
+
+ sky2_show_addr(dev1);
}
setup_timer(&hw->watchdog_timer, sky2_watchdog, (unsigned long) hw);
@@ -4962,6 +4981,10 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
return 0;
+err_out_unregister_dev1:
+ unregister_netdev(dev1);
+err_out_free_dev1:
+ free_netdev(dev1);
err_out_unregister:
if (hw->flags & SKY2_HW_USE_MSI)
pci_disable_msi(pdev);
@@ -5001,13 +5024,18 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
unregister_netdev(hw->dev[i]);
sky2_write32(hw, B0_IMSK, 0);
+ sky2_read32(hw, B0_IMSK);
sky2_power_aux(hw);
sky2_write8(hw, B0_CTST, CS_RST_SET);
sky2_read8(hw, B0_CTST);
- free_irq(pdev->irq, hw);
+ if (hw->ports > 1) {
+ napi_disable(&hw->napi);
+ free_irq(pdev->irq, hw);
+ }
+
if (hw->flags & SKY2_HW_USE_MSI)
pci_disable_msi(pdev);
pci_free_consistent(pdev, hw->st_size * sizeof(struct sky2_status_le),
diff --git a/drivers/net/sky2.h b/drivers/net/ethernet/marvell/sky2.h
index 0af31b8b5f10..0af31b8b5f10 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/ethernet/marvell/sky2.h
diff --git a/drivers/net/ethernet/mellanox/Kconfig b/drivers/net/ethernet/mellanox/Kconfig
new file mode 100644
index 000000000000..d8099a7903d3
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/Kconfig
@@ -0,0 +1,23 @@
+#
+# Mellanox driver configuration
+#
+
+config NET_VENDOR_MELLANOX
+ bool "Mellanox devices"
+ default y
+ depends on PCI && INET
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Mellanox cards. If you say Y, you will be asked
+ for your specific card in the following questions.
+
+if NET_VENDOR_MELLANOX
+
+source "drivers/net/ethernet/mellanox/mlx4/Kconfig"
+
+endif # NET_VENDOR_MELLANOX
diff --git a/drivers/net/ethernet/mellanox/Makefile b/drivers/net/ethernet/mellanox/Makefile
new file mode 100644
index 000000000000..37afb9683372
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Mellanox device drivers.
+#
+
+obj-$(CONFIG_MLX4_CORE) += mlx4/
diff --git a/drivers/net/ethernet/mellanox/mlx4/Kconfig b/drivers/net/ethernet/mellanox/mlx4/Kconfig
new file mode 100644
index 000000000000..1bb93531f1ba
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx4/Kconfig
@@ -0,0 +1,27 @@
+#
+# Mellanox driver configuration
+#
+
+config MLX4_EN
+ tristate "Mellanox Technologies 10Gbit Ethernet support"
+ depends on PCI && INET
+ select MLX4_CORE
+ select INET_LRO
+ ---help---
+ This driver supports Mellanox Technologies ConnectX Ethernet
+ devices.
+
+config MLX4_CORE
+ tristate
+ depends on PCI
+ default n
+
+config MLX4_DEBUG
+ bool "Verbose debugging output" if (MLX4_CORE && EXPERT)
+ depends on MLX4_CORE
+ default y
+ ---help---
+ This option causes debugging code to be compiled into the
+ mlx4_core driver. The output can be turned on via the
+ debug_level module parameter (which can also be set after
+ the driver is loaded through sysfs).
diff --git a/drivers/net/mlx4/Makefile b/drivers/net/ethernet/mellanox/mlx4/Makefile
index d1aa45a15854..d1aa45a15854 100644
--- a/drivers/net/mlx4/Makefile
+++ b/drivers/net/ethernet/mellanox/mlx4/Makefile
diff --git a/drivers/net/mlx4/alloc.c b/drivers/net/ethernet/mellanox/mlx4/alloc.c
index 116cae334dad..116cae334dad 100644
--- a/drivers/net/mlx4/alloc.c
+++ b/drivers/net/ethernet/mellanox/mlx4/alloc.c
diff --git a/drivers/net/mlx4/catas.c b/drivers/net/ethernet/mellanox/mlx4/catas.c
index 32f947154c33..32f947154c33 100644
--- a/drivers/net/mlx4/catas.c
+++ b/drivers/net/ethernet/mellanox/mlx4/catas.c
diff --git a/drivers/net/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c
index 23cee7b6af91..23cee7b6af91 100644
--- a/drivers/net/mlx4/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c
diff --git a/drivers/net/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c
index bd8ef9f2fa71..bd8ef9f2fa71 100644
--- a/drivers/net/mlx4/cq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/cq.c
diff --git a/drivers/net/mlx4/en_cq.c b/drivers/net/ethernet/mellanox/mlx4/en_cq.c
index ec4b6d047fe0..227997d775e8 100644
--- a/drivers/net/mlx4/en_cq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_cq.c
@@ -74,7 +74,8 @@ int mlx4_en_create_cq(struct mlx4_en_priv *priv,
return err;
}
-int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
+int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
+ int cq_idx)
{
struct mlx4_en_dev *mdev = priv->mdev;
int err = 0;
@@ -90,13 +91,15 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
if (cq->is_tx == RX) {
if (mdev->dev->caps.comp_pool) {
if (!cq->vector) {
- sprintf(name , "%s-rx-%d", priv->dev->name, cq->ring);
+ sprintf(name, "%s-%d", priv->dev->name,
+ cq->ring);
+ /* Set IRQ for specific name (per ring) */
if (mlx4_assign_eq(mdev->dev, name, &cq->vector)) {
- cq->vector = (cq->ring + 1 + priv->port) %
- mdev->dev->caps.num_comp_vectors;
+ cq->vector = (cq->ring + 1 + priv->port)
+ % mdev->dev->caps.num_comp_vectors;
mlx4_warn(mdev, "Failed Assigning an EQ to "
- "%s_rx-%d ,Falling back to legacy EQ's\n",
- priv->dev->name, cq->ring);
+ "%s ,Falling back to legacy EQ's\n",
+ name);
}
}
} else {
@@ -104,10 +107,13 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
mdev->dev->caps.num_comp_vectors;
}
} else {
- if (!cq->vector || !mdev->dev->caps.comp_pool) {
- /*Fallback to legacy pool in case of error*/
- cq->vector = 0;
- }
+ /* For TX we use the same irq per
+ ring we assigned for the RX */
+ struct mlx4_en_cq *rx_cq;
+
+ cq_idx = cq_idx % priv->rx_ring_num;
+ rx_cq = &priv->rx_cq[cq_idx];
+ cq->vector = rx_cq->vector;
}
if (!cq->is_tx)
@@ -133,14 +139,13 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
return 0;
}
-void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
- bool reserve_vectors)
+void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
{
struct mlx4_en_dev *mdev = priv->mdev;
mlx4_en_unmap_buffer(&cq->wqres.buf);
mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size);
- if (priv->mdev->dev->caps.comp_pool && cq->vector && !reserve_vectors)
+ if (priv->mdev->dev->caps.comp_pool && cq->vector)
mlx4_release_eq(priv->mdev->dev, cq->vector);
cq->buf_size = 0;
cq->buf = NULL;
diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
index eb096253d781..74e2a2a8a02b 100644
--- a/drivers/net/mlx4/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -342,13 +342,13 @@ static int mlx4_en_set_coalesce(struct net_device *dev,
priv->rx_usecs_high = coal->rx_coalesce_usecs_high;
priv->sample_interval = coal->rate_sample_interval;
priv->adaptive_rx_coal = coal->use_adaptive_rx_coalesce;
- priv->last_moder_time = MLX4_EN_AUTO_CONF;
if (priv->adaptive_rx_coal)
return 0;
for (i = 0; i < priv->rx_ring_num; i++) {
priv->rx_cq[i].moder_cnt = priv->rx_frames;
priv->rx_cq[i].moder_time = priv->rx_usecs;
+ priv->last_moder_time[i] = MLX4_EN_AUTO_CONF;
err = mlx4_en_set_cq_moder(priv, &priv->rx_cq[i]);
if (err)
return err;
@@ -394,6 +394,7 @@ static int mlx4_en_set_ringparam(struct net_device *dev,
u32 rx_size, tx_size;
int port_up = 0;
int err = 0;
+ int i;
if (param->rx_jumbo_pending || param->rx_mini_pending)
return -EINVAL;
@@ -416,7 +417,7 @@ static int mlx4_en_set_ringparam(struct net_device *dev,
mlx4_en_stop_port(dev);
}
- mlx4_en_free_resources(priv, true);
+ mlx4_en_free_resources(priv);
priv->prof->tx_ring_size = tx_size;
priv->prof->rx_ring_size = rx_size;
@@ -432,6 +433,15 @@ static int mlx4_en_set_ringparam(struct net_device *dev,
en_err(priv, "Failed starting port\n");
}
+ for (i = 0; i < priv->rx_ring_num; i++) {
+ priv->rx_cq[i].moder_cnt = priv->rx_frames;
+ priv->rx_cq[i].moder_time = priv->rx_usecs;
+ priv->last_moder_time[i] = MLX4_EN_AUTO_CONF;
+ err = mlx4_en_set_cq_moder(priv, &priv->rx_cq[i]);
+ if (err)
+ goto out;
+ }
+
out:
mutex_unlock(&mdev->state_lock);
return err;
diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c
index 6bfea233a9f2..a06096fcc0b8 100644
--- a/drivers/net/mlx4/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c
@@ -176,6 +176,7 @@ static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr)
flush_workqueue(mdev->workqueue);
destroy_workqueue(mdev->workqueue);
mlx4_mr_free(dev, &mdev->mr);
+ iounmap(mdev->uar_map);
mlx4_uar_free(dev, &mdev->priv_uar);
mlx4_pd_free(dev, mdev->priv_pdn);
kfree(mdev);
@@ -223,7 +224,7 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
MLX4_PERM_LOCAL_WRITE | MLX4_PERM_LOCAL_READ,
0, 0, &mdev->mr)) {
mlx4_err(mdev, "Failed allocating memory region\n");
- goto err_uar;
+ goto err_map;
}
if (mlx4_mr_enable(mdev->dev, &mdev->mr)) {
mlx4_err(mdev, "Failed enabling memory region\n");
@@ -282,6 +283,9 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
err_mr:
mlx4_mr_free(dev, &mdev->mr);
+err_map:
+ if (!mdev->uar_map)
+ iounmap(mdev->uar_map);
err_uar:
mlx4_uar_free(dev, &mdev->priv_uar);
err_pd:
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 4b0f32e568f8..78d776bc355c 100644
--- a/drivers/net/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -415,6 +415,9 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv)
cq = &priv->rx_cq[i];
cq->moder_cnt = priv->rx_frames;
cq->moder_time = priv->rx_usecs;
+ priv->last_moder_time[i] = MLX4_EN_AUTO_CONF;
+ priv->last_moder_packets[i] = 0;
+ priv->last_moder_bytes[i] = 0;
}
for (i = 0; i < priv->tx_ring_num; i++) {
@@ -430,11 +433,8 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv)
priv->rx_usecs_high = MLX4_EN_RX_COAL_TIME_HIGH;
priv->sample_interval = MLX4_EN_SAMPLE_INTERVAL;
priv->adaptive_rx_coal = 1;
- priv->last_moder_time = MLX4_EN_AUTO_CONF;
priv->last_moder_jiffies = 0;
- priv->last_moder_packets = 0;
priv->last_moder_tx_packets = 0;
- priv->last_moder_bytes = 0;
}
static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv)
@@ -446,43 +446,30 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv)
unsigned long avg_pkt_size;
unsigned long rx_packets;
unsigned long rx_bytes;
- unsigned long tx_packets;
- unsigned long tx_pkt_diff;
unsigned long rx_pkt_diff;
int moder_time;
- int i, err;
+ int ring, err;
if (!priv->adaptive_rx_coal || period < priv->sample_interval * HZ)
return;
- spin_lock_bh(&priv->stats_lock);
- rx_packets = priv->stats.rx_packets;
- rx_bytes = priv->stats.rx_bytes;
- tx_packets = priv->stats.tx_packets;
- spin_unlock_bh(&priv->stats_lock);
-
- if (!priv->last_moder_jiffies || !period)
- goto out;
-
- tx_pkt_diff = ((unsigned long) (tx_packets -
- priv->last_moder_tx_packets));
- rx_pkt_diff = ((unsigned long) (rx_packets -
- priv->last_moder_packets));
- packets = max(tx_pkt_diff, rx_pkt_diff);
- rate = packets * HZ / period;
- avg_pkt_size = packets ? ((unsigned long) (rx_bytes -
- priv->last_moder_bytes)) / packets : 0;
-
- /* Apply auto-moderation only when packet rate exceeds a rate that
- * it matters */
- if (rate > MLX4_EN_RX_RATE_THRESH && avg_pkt_size > MLX4_EN_AVG_PKT_SMALL) {
- /* If tx and rx packet rates are not balanced, assume that
- * traffic is mainly BW bound and apply maximum moderation.
- * Otherwise, moderate according to packet rate */
- if (2 * tx_pkt_diff > 3 * rx_pkt_diff ||
- 2 * rx_pkt_diff > 3 * tx_pkt_diff) {
- moder_time = priv->rx_usecs_high;
- } else {
+ for (ring = 0; ring < priv->rx_ring_num; ring++) {
+ spin_lock_bh(&priv->stats_lock);
+ rx_packets = priv->rx_ring[ring].packets;
+ rx_bytes = priv->rx_ring[ring].bytes;
+ spin_unlock_bh(&priv->stats_lock);
+
+ rx_pkt_diff = ((unsigned long) (rx_packets -
+ priv->last_moder_packets[ring]));
+ packets = rx_pkt_diff;
+ rate = packets * HZ / period;
+ avg_pkt_size = packets ? ((unsigned long) (rx_bytes -
+ priv->last_moder_bytes[ring])) / packets : 0;
+
+ /* Apply auto-moderation only when packet rate
+ * exceeds a rate that it matters */
+ if (rate > (MLX4_EN_RX_RATE_THRESH / priv->rx_ring_num) &&
+ avg_pkt_size > MLX4_EN_AVG_PKT_SMALL) {
if (rate < priv->pkt_rate_low)
moder_time = priv->rx_usecs_low;
else if (rate > priv->pkt_rate_high)
@@ -492,36 +479,23 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv)
(priv->rx_usecs_high - priv->rx_usecs_low) /
(priv->pkt_rate_high - priv->pkt_rate_low) +
priv->rx_usecs_low;
+ } else {
+ moder_time = priv->rx_usecs_low;
}
- } else {
- moder_time = priv->rx_usecs_low;
- }
-
- en_dbg(INTR, priv, "tx rate:%lu rx_rate:%lu\n",
- tx_pkt_diff * HZ / period, rx_pkt_diff * HZ / period);
- en_dbg(INTR, priv, "Rx moder_time changed from:%d to %d period:%lu "
- "[jiff] packets:%lu avg_pkt_size:%lu rate:%lu [p/s])\n",
- priv->last_moder_time, moder_time, period, packets,
- avg_pkt_size, rate);
-
- if (moder_time != priv->last_moder_time) {
- priv->last_moder_time = moder_time;
- for (i = 0; i < priv->rx_ring_num; i++) {
- cq = &priv->rx_cq[i];
+ if (moder_time != priv->last_moder_time[ring]) {
+ priv->last_moder_time[ring] = moder_time;
+ cq = &priv->rx_cq[ring];
cq->moder_time = moder_time;
err = mlx4_en_set_cq_moder(priv, cq);
- if (err) {
- en_err(priv, "Failed modifying moderation for cq:%d\n", i);
- break;
- }
+ if (err)
+ en_err(priv, "Failed modifying moderation "
+ "for cq:%d\n", ring);
}
+ priv->last_moder_packets[ring] = rx_packets;
+ priv->last_moder_bytes[ring] = rx_bytes;
}
-out:
- priv->last_moder_packets = rx_packets;
- priv->last_moder_tx_packets = tx_packets;
- priv->last_moder_bytes = rx_bytes;
priv->last_moder_jiffies = jiffies;
}
@@ -587,7 +561,6 @@ int mlx4_en_start_port(struct net_device *dev)
int i;
int j;
u8 mc_list[16] = {0};
- char name[32];
if (priv->port_up) {
en_dbg(DRV, priv, "start port called while port already up\n");
@@ -608,7 +581,7 @@ int mlx4_en_start_port(struct net_device *dev)
for (i = 0; i < priv->rx_ring_num; i++) {
cq = &priv->rx_cq[i];
- err = mlx4_en_activate_cq(priv, cq);
+ err = mlx4_en_activate_cq(priv, cq, i);
if (err) {
en_err(priv, "Failed activating Rx CQ\n");
goto cq_err;
@@ -642,20 +615,11 @@ int mlx4_en_start_port(struct net_device *dev)
goto mac_err;
}
- if (mdev->dev->caps.comp_pool && !priv->tx_vector) {
- sprintf(name , "%s-tx", priv->dev->name);
- if (mlx4_assign_eq(mdev->dev , name, &priv->tx_vector)) {
- mlx4_warn(mdev, "Failed Assigning an EQ to "
- "%s_tx ,Falling back to legacy "
- "EQ's\n", priv->dev->name);
- }
- }
/* Configure tx cq's and rings */
for (i = 0; i < priv->tx_ring_num; i++) {
/* Configure cq */
cq = &priv->tx_cq[i];
- cq->vector = priv->tx_vector;
- err = mlx4_en_activate_cq(priv, cq);
+ err = mlx4_en_activate_cq(priv, cq, i);
if (err) {
en_err(priv, "Failed allocating Tx CQ\n");
goto tx_err;
@@ -886,7 +850,7 @@ static int mlx4_en_close(struct net_device *dev)
return 0;
}
-void mlx4_en_free_resources(struct mlx4_en_priv *priv, bool reserve_vectors)
+void mlx4_en_free_resources(struct mlx4_en_priv *priv)
{
int i;
@@ -894,14 +858,14 @@ void mlx4_en_free_resources(struct mlx4_en_priv *priv, bool reserve_vectors)
if (priv->tx_ring[i].tx_info)
mlx4_en_destroy_tx_ring(priv, &priv->tx_ring[i]);
if (priv->tx_cq[i].buf)
- mlx4_en_destroy_cq(priv, &priv->tx_cq[i], reserve_vectors);
+ mlx4_en_destroy_cq(priv, &priv->tx_cq[i]);
}
for (i = 0; i < priv->rx_ring_num; i++) {
if (priv->rx_ring[i].rx_info)
mlx4_en_destroy_rx_ring(priv, &priv->rx_ring[i]);
if (priv->rx_cq[i].buf)
- mlx4_en_destroy_cq(priv, &priv->rx_cq[i], reserve_vectors);
+ mlx4_en_destroy_cq(priv, &priv->rx_cq[i]);
}
}
@@ -971,7 +935,7 @@ void mlx4_en_destroy_netdev(struct net_device *dev)
mdev->pndev[priv->port] = NULL;
mutex_unlock(&mdev->state_lock);
- mlx4_en_free_resources(priv, false);
+ mlx4_en_free_resources(priv);
free_netdev(dev);
}
@@ -1016,7 +980,7 @@ static const struct net_device_ops mlx4_netdev_ops = {
.ndo_start_xmit = mlx4_en_xmit,
.ndo_select_queue = mlx4_en_select_queue,
.ndo_get_stats = mlx4_en_get_stats,
- .ndo_set_multicast_list = mlx4_en_set_multicast,
+ .ndo_set_rx_mode = mlx4_en_set_multicast,
.ndo_set_mac_address = mlx4_en_set_mac,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = mlx4_en_change_mtu,
@@ -1120,7 +1084,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
dev->vlan_features = dev->hw_features;
- dev->hw_features |= NETIF_F_RXCSUM;
+ dev->hw_features |= NETIF_F_RXCSUM | NETIF_F_RXHASH;
dev->features = dev->hw_features | NETIF_F_HIGHDMA |
NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
NETIF_F_HW_VLAN_FILTER;
@@ -1133,6 +1097,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
en_err(priv, "Netdev registration failed for port %d\n", port);
goto out;
}
+ priv->registered = 1;
en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num);
en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num);
@@ -1154,7 +1119,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
en_err(priv, "Failed Initializing port\n");
goto out;
}
- priv->registered = 1;
mlx4_en_set_default_moderation(priv);
queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY);
return 0;
diff --git a/drivers/net/mlx4/en_port.c b/drivers/net/ethernet/mellanox/mlx4/en_port.c
index 5ada5b469112..03c84cd78cde 100644
--- a/drivers/net/mlx4/en_port.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_port.c
@@ -128,7 +128,7 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
memset(context, 0, sizeof *context);
context->base_qpn = cpu_to_be32(base_qpn);
- context->n_mac = 0x2;
+ context->n_mac = dev->caps.log_num_macs;
context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT |
base_qpn);
context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT |
@@ -167,11 +167,21 @@ int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port)
/* This command is always accessed from Ethtool context
* already synchronized, no need in locking */
state->link_state = !!(qport_context->link_up & MLX4_EN_LINK_UP_MASK);
- if ((qport_context->link_speed & MLX4_EN_SPEED_MASK) ==
- MLX4_EN_1G_SPEED)
+ switch (qport_context->link_speed & MLX4_EN_SPEED_MASK) {
+ case MLX4_EN_1G_SPEED:
state->link_speed = 1000;
- else
+ break;
+ case MLX4_EN_10G_SPEED_XAUI:
+ case MLX4_EN_10G_SPEED_XFI:
state->link_speed = 10000;
+ break;
+ case MLX4_EN_40G_SPEED:
+ state->link_speed = 40000;
+ break;
+ default:
+ state->link_speed = -1;
+ break;
+ }
state->transciver = qport_context->transceiver;
out:
@@ -204,15 +214,21 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
stats->rx_packets = 0;
stats->rx_bytes = 0;
+ priv->port_stats.rx_chksum_good = 0;
+ priv->port_stats.rx_chksum_none = 0;
for (i = 0; i < priv->rx_ring_num; i++) {
stats->rx_packets += priv->rx_ring[i].packets;
stats->rx_bytes += priv->rx_ring[i].bytes;
+ priv->port_stats.rx_chksum_good += priv->rx_ring[i].csum_ok;
+ priv->port_stats.rx_chksum_none += priv->rx_ring[i].csum_none;
}
stats->tx_packets = 0;
stats->tx_bytes = 0;
+ priv->port_stats.tx_chksum_offload = 0;
for (i = 0; i < priv->tx_ring_num; i++) {
stats->tx_packets += priv->tx_ring[i].packets;
stats->tx_bytes += priv->tx_ring[i].bytes;
+ priv->port_stats.tx_chksum_offload += priv->tx_ring[i].tx_csum;
}
stats->rx_errors = be64_to_cpu(mlx4_en_stats->PCS) +
diff --git a/drivers/net/mlx4/en_port.h b/drivers/net/ethernet/mellanox/mlx4/en_port.h
index e3d73e41c567..19eb244f5165 100644
--- a/drivers/net/mlx4/en_port.h
+++ b/drivers/net/ethernet/mellanox/mlx4/en_port.h
@@ -94,6 +94,14 @@ enum {
MLX4_MCAST_ENABLE = 2,
};
+enum {
+ MLX4_EN_1G_SPEED = 0x02,
+ MLX4_EN_10G_SPEED_XFI = 0x01,
+ MLX4_EN_10G_SPEED_XAUI = 0x00,
+ MLX4_EN_40G_SPEED = 0x40,
+ MLX4_EN_OTHER_SPEED = 0x0f,
+};
+
struct mlx4_en_query_port_context {
u8 link_up;
#define MLX4_EN_LINK_UP_MASK 0x80
@@ -101,8 +109,7 @@ struct mlx4_en_query_port_context {
__be16 mtu;
u8 reserved2;
u8 link_speed;
-#define MLX4_EN_SPEED_MASK 0x3
-#define MLX4_EN_1G_SPEED 0x2
+#define MLX4_EN_SPEED_MASK 0x43
u16 reserved3[5];
__be64 mac;
u8 transceiver;
diff --git a/drivers/net/mlx4/en_resources.c b/drivers/net/ethernet/mellanox/mlx4/en_resources.c
index 0dfb4ec8a9dd..0dfb4ec8a9dd 100644
--- a/drivers/net/mlx4/en_resources.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_resources.c
diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index 37cc9e5c56be..b89c36dbf5b3 100644
--- a/drivers/net/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -44,7 +44,7 @@
static int mlx4_en_alloc_frag(struct mlx4_en_priv *priv,
struct mlx4_en_rx_desc *rx_desc,
- struct skb_frag_struct *skb_frags,
+ struct page_frag *skb_frags,
struct mlx4_en_rx_alloc *ring_alloc,
int i)
{
@@ -61,7 +61,7 @@ static int mlx4_en_alloc_frag(struct mlx4_en_priv *priv,
return -ENOMEM;
skb_frags[i].page = page_alloc->page;
- skb_frags[i].page_offset = page_alloc->offset;
+ skb_frags[i].offset = page_alloc->offset;
page_alloc->page = page;
page_alloc->offset = frag_info->frag_align;
} else {
@@ -69,11 +69,11 @@ static int mlx4_en_alloc_frag(struct mlx4_en_priv *priv,
get_page(page);
skb_frags[i].page = page;
- skb_frags[i].page_offset = page_alloc->offset;
+ 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) +
- skb_frags[i].page_offset, frag_info->frag_size,
+ skb_frags[i].offset, frag_info->frag_size,
PCI_DMA_FROMDEVICE);
rx_desc->data[i].addr = cpu_to_be64(dma);
return 0;
@@ -135,7 +135,7 @@ static void mlx4_en_init_rx_desc(struct mlx4_en_priv *priv,
/* Set size and memtype fields */
for (i = 0; i < priv->num_frags; i++) {
- skb_frags[i].size = priv->frag_info[i].frag_size;
+ skb_frag_size_set(&skb_frags[i], priv->frag_info[i].frag_size);
rx_desc->data[i].byte_count =
cpu_to_be32(priv->frag_info[i].frag_size);
rx_desc->data[i].lkey = cpu_to_be32(priv->mdev->mr.key);
@@ -157,8 +157,8 @@ static int mlx4_en_prepare_rx_desc(struct mlx4_en_priv *priv,
struct mlx4_en_rx_ring *ring, int index)
{
struct mlx4_en_rx_desc *rx_desc = ring->buf + (index * ring->stride);
- struct skb_frag_struct *skb_frags = ring->rx_info +
- (index << priv->log_rx_info);
+ struct page_frag *skb_frags = ring->rx_info +
+ (index << priv->log_rx_info);
int i;
for (i = 0; i < priv->num_frags; i++)
@@ -183,7 +183,7 @@ static void mlx4_en_free_rx_desc(struct mlx4_en_priv *priv,
int index)
{
struct mlx4_en_dev *mdev = priv->mdev;
- struct skb_frag_struct *skb_frags;
+ struct page_frag *skb_frags;
struct mlx4_en_rx_desc *rx_desc = ring->buf + (index << ring->log_stride);
dma_addr_t dma;
int nr;
@@ -403,11 +403,12 @@ void mlx4_en_deactivate_rx_ring(struct mlx4_en_priv *priv,
/* Unmap a completed descriptor and free unused pages */
static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv,
struct mlx4_en_rx_desc *rx_desc,
- struct skb_frag_struct *skb_frags,
- struct skb_frag_struct *skb_frags_rx,
+ struct page_frag *skb_frags,
+ struct sk_buff *skb,
struct mlx4_en_rx_alloc *page_alloc,
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;
@@ -420,9 +421,10 @@ static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv,
break;
/* Save page reference in skb */
- skb_frags_rx[nr].page = skb_frags[nr].page;
- skb_frags_rx[nr].size = skb_frags[nr].size;
- skb_frags_rx[nr].page_offset = skb_frags[nr].page_offset;
+ __skb_frag_set_page(&skb_frags_rx[nr], skb_frags[nr].page);
+ skb_frag_size_set(&skb_frags_rx[nr], skb_frags[nr].size);
+ skb_frags_rx[nr].page_offset = skb_frags[nr].offset;
+ skb->truesize += frag_info->frag_stride;
dma = be64_to_cpu(rx_desc->data[nr].addr);
/* Allocate a replacement page */
@@ -430,13 +432,13 @@ static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv,
goto fail;
/* Unmap buffer */
- pci_unmap_single(mdev->pdev, dma, skb_frags_rx[nr].size,
+ pci_unmap_single(mdev->pdev, dma, skb_frag_size(&skb_frags_rx[nr]),
PCI_DMA_FROMDEVICE);
}
/* Adjust size of last fragment to match actual length */
if (nr > 0)
- skb_frags_rx[nr - 1].size = length -
- priv->frag_info[nr - 1].frag_prefix_size;
+ skb_frag_size_set(&skb_frags_rx[nr - 1],
+ length - priv->frag_info[nr - 1].frag_prefix_size);
return nr;
fail:
@@ -444,7 +446,7 @@ fail:
* the descriptor) of this packet; remaining fragments are reused... */
while (nr > 0) {
nr--;
- put_page(skb_frags_rx[nr].page);
+ __skb_frag_unref(&skb_frags_rx[nr]);
}
return 0;
}
@@ -452,7 +454,7 @@ fail:
static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv,
struct mlx4_en_rx_desc *rx_desc,
- struct skb_frag_struct *skb_frags,
+ struct page_frag *skb_frags,
struct mlx4_en_rx_alloc *page_alloc,
unsigned int length)
{
@@ -470,11 +472,10 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv,
skb->dev = priv->dev;
skb_reserve(skb, NET_IP_ALIGN);
skb->len = length;
- skb->truesize = length + sizeof(struct sk_buff);
/* Get pointer to first fragment so we could copy the headers into the
* (linear part of the) skb */
- va = page_address(skb_frags[0].page) + skb_frags[0].page_offset;
+ va = page_address(skb_frags[0].page) + skb_frags[0].offset;
if (length <= SMALL_PACKET_SIZE) {
/* We are copying all relevant data to the skb - temporarily
@@ -490,8 +491,7 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv,
/* Move relevant fragments to skb */
used_frags = mlx4_en_complete_rx_desc(priv, rx_desc, skb_frags,
- skb_shinfo(skb)->frags,
- page_alloc, length);
+ skb, page_alloc, length);
if (unlikely(!used_frags)) {
kfree_skb(skb);
return NULL;
@@ -506,7 +506,7 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv,
skb_shinfo(skb)->frags[0].page_offset += HEADER_COPY_SIZE;
/* Adjust size of first fragment */
- skb_shinfo(skb)->frags[0].size -= HEADER_COPY_SIZE;
+ skb_frag_size_sub(&skb_shinfo(skb)->frags[0], HEADER_COPY_SIZE);
skb->data_len = length - HEADER_COPY_SIZE;
}
return skb;
@@ -533,7 +533,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_cqe *cqe;
struct mlx4_en_rx_ring *ring = &priv->rx_ring[cq->ring];
- struct skb_frag_struct *skb_frags;
+ struct page_frag *skb_frags;
struct mlx4_en_rx_desc *rx_desc;
struct sk_buff *skb;
int index;
@@ -587,7 +587,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
if (likely(dev->features & NETIF_F_RXCSUM)) {
if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) &&
(cqe->checksum == cpu_to_be16(0xffff))) {
- priv->port_stats.rx_chksum_good++;
+ ring->csum_ok++;
/* This packet is eligible for LRO if it is:
* - DIX Ethernet (type interpretation)
* - TCP/IP (v4)
@@ -600,7 +600,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
nr = mlx4_en_complete_rx_desc(
priv, rx_desc,
- skb_frags, skb_shinfo(gro_skb)->frags,
+ skb_frags, gro_skb,
ring->page_alloc, length);
if (!nr)
goto next;
@@ -608,7 +608,6 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
skb_shinfo(gro_skb)->nr_frags = nr;
gro_skb->len = length;
gro_skb->data_len = length;
- gro_skb->truesize += length;
gro_skb->ip_summed = CHECKSUM_UNNECESSARY;
if (cqe->vlan_my_qpn &
@@ -618,6 +617,10 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
__vlan_hwaccel_put_tag(gro_skb, vid);
}
+ if (dev->features & NETIF_F_RXHASH)
+ gro_skb->rxhash = be32_to_cpu(cqe->immed_rss_invalid);
+
+ skb_record_rx_queue(gro_skb, cq->ring);
napi_gro_frags(&cq->napi);
goto next;
@@ -627,11 +630,11 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
ip_summed = CHECKSUM_UNNECESSARY;
} else {
ip_summed = CHECKSUM_NONE;
- priv->port_stats.rx_chksum_none++;
+ ring->csum_none++;
}
} else {
ip_summed = CHECKSUM_NONE;
- priv->port_stats.rx_chksum_none++;
+ ring->csum_none++;
}
skb = mlx4_en_rx_skb(priv, rx_desc, skb_frags,
@@ -650,6 +653,9 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
skb->protocol = eth_type_trans(skb, dev);
skb_record_rx_queue(skb, cq->ring);
+ if (dev->features & NETIF_F_RXHASH)
+ skb->rxhash = be32_to_cpu(cqe->immed_rss_invalid);
+
if (be32_to_cpu(cqe->vlan_my_qpn) &
MLX4_CQE_VLAN_PRESENT_MASK)
__vlan_hwaccel_put_tag(skb, be16_to_cpu(cqe->sl_vid));
@@ -806,6 +812,10 @@ static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, int qpn,
qpn, ring->cqn, context);
context->db_rec_addr = cpu_to_be64(ring->wqres.db.dma);
+ /* Cancel FCS removal if FW allows */
+ if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_FCS_KEEP)
+ context->param3 |= cpu_to_be32(1 << 29);
+
err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, context, qp, state);
if (err) {
mlx4_qp_remove(mdev->dev, qp);
@@ -829,6 +839,9 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
int i, qpn;
int err = 0;
int good_qps = 0;
+ static const u32 rsskey[10] = { 0xD181C62C, 0xF7F4DB5B, 0x1983A2FC,
+ 0x943E1ADB, 0xD9389E6B, 0xD1039C2C, 0xA74499AD,
+ 0x593D56D9, 0xF3253C06, 0x2ADC1FFC};
en_dbg(DRV, priv, "Configuring rss steering\n");
err = mlx4_qp_reserve_range(mdev->dev, priv->rx_ring_num,
@@ -866,6 +879,9 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
(rss_map->base_qpn));
rss_context->default_qpn = cpu_to_be32(rss_map->base_qpn);
rss_context->flags = rss_mask;
+ rss_context->hash_fn = 1;
+ for (i = 0; i < 10; i++)
+ rss_context->rss_key[i] = rsskey[i];
if (priv->mdev->profile.udp_rss)
rss_context->base_qpn_udp = rss_context->default_qpn;
diff --git a/drivers/net/mlx4/en_selftest.c b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
index 9fdbcecd499d..9fdbcecd499d 100644
--- a/drivers/net/mlx4/en_selftest.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index 6e03de034ac7..90f2cd24faac 100644
--- a/drivers/net/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -172,7 +172,7 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
memset(ring->buf, 0, ring->buf_size);
ring->qp_state = MLX4_QP_STATE_RST;
- ring->doorbell_qpn = swab32(ring->qp.qpn << 8);
+ ring->doorbell_qpn = ring->qp.qpn << 8;
mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 1, 0, ring->qpn,
ring->cqn, &ring->context);
@@ -226,7 +226,7 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
frag = &skb_shinfo(skb)->frags[i];
pci_unmap_page(mdev->pdev,
(dma_addr_t) be64_to_cpu(data[i].addr),
- frag->size, PCI_DMA_TODEVICE);
+ skb_frag_size(frag), PCI_DMA_TODEVICE);
}
}
/* Stamp the freed descriptor */
@@ -256,7 +256,7 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
frag = &skb_shinfo(skb)->frags[i];
pci_unmap_page(mdev->pdev,
(dma_addr_t) be64_to_cpu(data->addr),
- frag->size, PCI_DMA_TODEVICE);
+ skb_frag_size(frag), PCI_DMA_TODEVICE);
++data;
}
}
@@ -460,26 +460,13 @@ static inline void mlx4_en_xmit_poll(struct mlx4_en_priv *priv, int tx_ind)
}
}
-static void *get_frag_ptr(struct sk_buff *skb)
-{
- struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0];
- struct page *page = frag->page;
- void *ptr;
-
- ptr = page_address(page);
- if (unlikely(!ptr))
- return NULL;
-
- return ptr + frag->page_offset;
-}
-
static int is_inline(struct sk_buff *skb, void **pfrag)
{
void *ptr;
if (inline_thold && !skb_is_gso(skb) && skb->len <= inline_thold) {
if (skb_shinfo(skb)->nr_frags == 1) {
- ptr = get_frag_ptr(skb);
+ ptr = skb_frag_address_safe(&skb_shinfo(skb)->frags[0]);
if (unlikely(!ptr))
return 0;
@@ -550,7 +537,7 @@ static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *sk
skb_copy_from_linear_data(skb, inl + 1, skb_headlen(skb));
if (skb_shinfo(skb)->nr_frags)
memcpy(((void *)(inl + 1)) + skb_headlen(skb), fragptr,
- skb_shinfo(skb)->frags[0].size);
+ skb_frag_size(&skb_shinfo(skb)->frags[0]));
} else {
inl->byte_count = cpu_to_be32(1 << 31 | spc);
@@ -570,7 +557,7 @@ static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *sk
skb_headlen(skb) - spc);
if (skb_shinfo(skb)->nr_frags)
memcpy(((void *)(inl + 1)) + skb_headlen(skb) - spc,
- fragptr, skb_shinfo(skb)->frags[0].size);
+ fragptr, skb_frag_size(&skb_shinfo(skb)->frags[0]));
}
wmb();
@@ -695,7 +682,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
tx_desc->ctrl.srcrb_flags |= cpu_to_be32(MLX4_WQE_CTRL_IP_CSUM |
MLX4_WQE_CTRL_TCP_UDP_CSUM);
- priv->port_stats.tx_chksum_offload++;
+ ring->tx_csum++;
}
if (unlikely(priv->validate_loopback)) {
@@ -756,12 +743,13 @@ 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 = pci_map_page(mdev->dev->pdev, frag->page, frag->page_offset,
- frag->size, PCI_DMA_TODEVICE);
+ dma = skb_frag_dma_map(&mdev->dev->pdev->dev, frag,
+ 0, skb_frag_size(frag),
+ DMA_TO_DEVICE);
data->addr = cpu_to_be64(dma);
data->lkey = cpu_to_be32(mdev->mr.key);
wmb();
- data->byte_count = cpu_to_be32(frag->size);
+ data->byte_count = cpu_to_be32(skb_frag_size(frag));
--data;
}
@@ -791,7 +779,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
skb_orphan(skb);
if (ring->bf_enabled && desc_size <= MAX_BF && !bounce && !vlan_tag) {
- *(u32 *) (&tx_desc->ctrl.vlan_tag) |= ring->doorbell_qpn;
+ *(__be32 *) (&tx_desc->ctrl.vlan_tag) |= cpu_to_be32(ring->doorbell_qpn);
op_own |= htonl((bf_index & 0xffff) << 8);
/* Ensure new descirptor hits memory
* before setting ownership of this descriptor to HW */
@@ -812,7 +800,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
wmb();
tx_desc->ctrl.owner_opcode = op_own;
wmb();
- writel(ring->doorbell_qpn, ring->bf.uar->map + MLX4_SEND_DOORBELL);
+ iowrite32be(ring->doorbell_qpn, ring->bf.uar->map + MLX4_SEND_DOORBELL);
}
/* Poll CQ here */
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c
index 1ad1f6029af8..1ad1f6029af8 100644
--- a/drivers/net/mlx4/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/eq.c
diff --git a/drivers/net/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c
index 7eb8ba822e97..ed452ddfe342 100644
--- a/drivers/net/mlx4/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.c
@@ -101,6 +101,7 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags)
[25] = "Router support",
[30] = "IBoE support",
[32] = "Unicast loopback support",
+ [34] = "FCS header control",
[38] = "Wake On LAN support",
[40] = "UDP RSS support",
[41] = "Unicast VEP steering support",
diff --git a/drivers/net/mlx4/fw.h b/drivers/net/ethernet/mellanox/mlx4/fw.h
index 1e8ecc3708e2..1e8ecc3708e2 100644
--- a/drivers/net/mlx4/fw.h
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.h
diff --git a/drivers/net/mlx4/icm.c b/drivers/net/ethernet/mellanox/mlx4/icm.c
index 02393fdf44c1..02393fdf44c1 100644
--- a/drivers/net/mlx4/icm.c
+++ b/drivers/net/ethernet/mellanox/mlx4/icm.c
diff --git a/drivers/net/mlx4/icm.h b/drivers/net/ethernet/mellanox/mlx4/icm.h
index b10c07a1dc1a..b10c07a1dc1a 100644
--- a/drivers/net/mlx4/icm.h
+++ b/drivers/net/ethernet/mellanox/mlx4/icm.h
diff --git a/drivers/net/mlx4/intf.c b/drivers/net/ethernet/mellanox/mlx4/intf.c
index 73c94fcdfddf..73c94fcdfddf 100644
--- a/drivers/net/mlx4/intf.c
+++ b/drivers/net/ethernet/mellanox/mlx4/intf.c
diff --git a/drivers/net/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index f0ee35df4dd7..f0ee35df4dd7 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c
index cd1784593a3c..cd1784593a3c 100644
--- a/drivers/net/mlx4/mcg.c
+++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
index a2fcd8402d37..a2fcd8402d37 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index ed84811766e6..fca66165110e 100644
--- a/drivers/net/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -51,8 +51,8 @@
#include "en_port.h"
#define DRV_NAME "mlx4_en"
-#define DRV_VERSION "1.5.4.1"
-#define DRV_RELDATE "March 2011"
+#define DRV_VERSION "1.5.4.2"
+#define DRV_RELDATE "October 2011"
#define MLX4_EN_MSG_LEVEL (NETIF_MSG_LINK | NETIF_MSG_IFDOWN)
@@ -249,6 +249,7 @@ struct mlx4_en_tx_ring {
struct mlx4_srq dummy;
unsigned long bytes;
unsigned long packets;
+ unsigned long tx_csum;
spinlock_t comp_lock;
struct mlx4_bf bf;
bool bf_enabled;
@@ -275,6 +276,8 @@ struct mlx4_en_rx_ring {
void *rx_info;
unsigned long bytes;
unsigned long packets;
+ unsigned long csum_ok;
+ unsigned long csum_none;
};
@@ -426,11 +429,11 @@ struct mlx4_en_priv {
struct mlx4_en_port_state port_state;
spinlock_t stats_lock;
- unsigned long last_moder_packets;
+ unsigned long last_moder_packets[MAX_RX_RINGS];
unsigned long last_moder_tx_packets;
- unsigned long last_moder_bytes;
+ unsigned long last_moder_bytes[MAX_RX_RINGS];
unsigned long last_moder_jiffies;
- int last_moder_time;
+ int last_moder_time[MAX_RX_RINGS];
u16 rx_usecs;
u16 rx_frames;
u16 tx_usecs;
@@ -470,7 +473,6 @@ struct mlx4_en_priv {
u16 log_rx_info;
struct mlx4_en_tx_ring tx_ring[MAX_TX_RINGS];
- int tx_vector;
struct mlx4_en_rx_ring rx_ring[MAX_RX_RINGS];
struct mlx4_en_cq tx_cq[MAX_TX_RINGS];
struct mlx4_en_cq rx_cq[MAX_RX_RINGS];
@@ -503,14 +505,14 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
int mlx4_en_start_port(struct net_device *dev);
void mlx4_en_stop_port(struct net_device *dev);
-void mlx4_en_free_resources(struct mlx4_en_priv *priv, bool reserve_vectors);
+void mlx4_en_free_resources(struct mlx4_en_priv *priv);
int mlx4_en_alloc_resources(struct mlx4_en_priv *priv);
int mlx4_en_create_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
int entries, int ring, enum cq_type mode);
-void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
- bool reserve_vectors);
-int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
+void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
+int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
+ int cq_idx);
void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
int mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
diff --git a/drivers/net/mlx4/mr.c b/drivers/net/ethernet/mellanox/mlx4/mr.c
index 9c188bdd7f4f..9c188bdd7f4f 100644
--- a/drivers/net/mlx4/mr.c
+++ b/drivers/net/ethernet/mellanox/mlx4/mr.c
diff --git a/drivers/net/mlx4/pd.c b/drivers/net/ethernet/mellanox/mlx4/pd.c
index 1286b886dcea..1286b886dcea 100644
--- a/drivers/net/mlx4/pd.c
+++ b/drivers/net/ethernet/mellanox/mlx4/pd.c
diff --git a/drivers/net/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c
index 609e0ec14cee..163a314c148f 100644
--- a/drivers/net/mlx4/port.c
+++ b/drivers/net/ethernet/mellanox/mlx4/port.c
@@ -65,7 +65,7 @@ void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table)
table->entries[i] = 0;
table->refs[i] = 0;
}
- table->max = 1 << dev->caps.log_num_vlans;
+ table->max = (1 << dev->caps.log_num_vlans) - MLX4_VLAN_REGULAR;
table->total = 0;
}
@@ -354,6 +354,13 @@ int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index)
int free = -1;
mutex_lock(&table->mutex);
+
+ if (table->total == table->max) {
+ /* No free vlan entries */
+ err = -ENOSPC;
+ goto out;
+ }
+
for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) {
if (free < 0 && (table->refs[i] == 0)) {
free = i;
@@ -375,12 +382,6 @@ int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index)
goto out;
}
- if (table->total == table->max) {
- /* No free vlan entries */
- err = -ENOSPC;
- goto out;
- }
-
/* Register new MAC */
table->refs[free] = 1;
table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID);
diff --git a/drivers/net/mlx4/profile.c b/drivers/net/ethernet/mellanox/mlx4/profile.c
index b967647d0c76..b967647d0c76 100644
--- a/drivers/net/mlx4/profile.c
+++ b/drivers/net/ethernet/mellanox/mlx4/profile.c
diff --git a/drivers/net/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c
index ec9350e5f21a..ec9350e5f21a 100644
--- a/drivers/net/mlx4/qp.c
+++ b/drivers/net/ethernet/mellanox/mlx4/qp.c
diff --git a/drivers/net/mlx4/reset.c b/drivers/net/ethernet/mellanox/mlx4/reset.c
index 11e7c1cb99bf..11e7c1cb99bf 100644
--- a/drivers/net/mlx4/reset.c
+++ b/drivers/net/ethernet/mellanox/mlx4/reset.c
diff --git a/drivers/net/mlx4/sense.c b/drivers/net/ethernet/mellanox/mlx4/sense.c
index e2337a7411d9..e2337a7411d9 100644
--- a/drivers/net/mlx4/sense.c
+++ b/drivers/net/ethernet/mellanox/mlx4/sense.c
diff --git a/drivers/net/mlx4/srq.c b/drivers/net/ethernet/mellanox/mlx4/srq.c
index 3b07b80a0456..3b07b80a0456 100644
--- a/drivers/net/mlx4/srq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/srq.c
diff --git a/drivers/net/ethernet/micrel/Kconfig b/drivers/net/ethernet/micrel/Kconfig
new file mode 100644
index 000000000000..d10c2e15f4ed
--- /dev/null
+++ b/drivers/net/ethernet/micrel/Kconfig
@@ -0,0 +1,69 @@
+#
+# Micrel device configuration
+#
+
+config NET_VENDOR_MICREL
+ bool "Micrel devices"
+ default y
+ depends on (HAS_IOMEM && DMA_ENGINE) || SPI || PCI || HAS_IOMEM || \
+ (ARM && ARCH_KS8695)
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Micrel devices. If you say Y, you will be asked
+ for your specific card in the following questions.
+
+if NET_VENDOR_MICREL
+
+config ARM_KS8695_ETHER
+ tristate "KS8695 Ethernet support"
+ depends on ARM && ARCH_KS8695
+ select NET_CORE
+ select MII
+ ---help---
+ If you wish to compile a kernel for the KS8695 and want to
+ use the internal ethernet then you should answer Y to this.
+
+config KS8842
+ tristate "Micrel KSZ8841/42 with generic bus interface"
+ depends on HAS_IOMEM && DMA_ENGINE
+ ---help---
+ This platform driver is for KSZ8841(1-port) / KS8842(2-port)
+ ethernet switch chip (managed, VLAN, QoS) from Micrel or
+ Timberdale(FPGA).
+
+config KS8851
+ tristate "Micrel KS8851 SPI"
+ depends on SPI
+ select NET_CORE
+ select MII
+ select CRC32
+ ---help---
+ SPI driver for Micrel KS8851 SPI attached network chip.
+
+config KS8851_MLL
+ tristate "Micrel KS8851 MLL"
+ depends on HAS_IOMEM
+ select NET_CORE
+ select MII
+ ---help---
+ This platform driver is for Micrel KS8851 Address/data bus
+ multiplexed network chip.
+
+config KSZ884X_PCI
+ tristate "Micrel KSZ8841/2 PCI"
+ depends on PCI
+ select NET_CORE
+ select MII
+ select CRC32
+ ---help---
+ This PCI driver is for Micrel KSZ8841/KSZ8842 PCI Ethernet chip.
+
+ To compile this driver as a module, choose M here. The module
+ will be called ksz884x.
+
+endif # NET_VENDOR_MICREL
diff --git a/drivers/net/ethernet/micrel/Makefile b/drivers/net/ethernet/micrel/Makefile
new file mode 100644
index 000000000000..c83e4bc50c73
--- /dev/null
+++ b/drivers/net/ethernet/micrel/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the Micrel network device drivers.
+#
+
+obj-$(CONFIG_ARM_KS8695_ETHER) += ks8695net.o
+obj-$(CONFIG_KS8842) += ks8842.o
+obj-$(CONFIG_KS8851) += ks8851.o
+obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o
+obj-$(CONFIG_KSZ884X_PCI) += ksz884x.o
diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/ethernet/micrel/ks8695net.c
index c827a6097d02..ab81c0dc96e2 100644
--- a/drivers/net/arm/ks8695net.c
+++ b/drivers/net/ethernet/micrel/ks8695net.c
@@ -414,7 +414,7 @@ ks8695_tx_irq(int irq, void *dev_id)
* Interrupt Status Register (Offset 0xF208)
* Bit29: WAN MAC Receive Status
* Bit16: LAN MAC Receive Status
- * So, this Rx interrrupt enable/status bit number is equal
+ * So, this Rx interrupt enable/status bit number is equal
* as Rx IRQ number.
*/
static inline u32 ks8695_get_rx_enable_bit(struct ks8695_priv *ksp)
@@ -1333,7 +1333,7 @@ static const struct net_device_ops ks8695_netdev_ops = {
.ndo_tx_timeout = ks8695_timeout,
.ndo_set_mac_address = ks8695_set_mac,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = ks8695_set_multicast,
+ .ndo_set_rx_mode = ks8695_set_multicast,
};
/**
diff --git a/drivers/net/arm/ks8695net.h b/drivers/net/ethernet/micrel/ks8695net.h
index 80eff6ea5163..80eff6ea5163 100644
--- a/drivers/net/arm/ks8695net.h
+++ b/drivers/net/ethernet/micrel/ks8695net.h
diff --git a/drivers/net/ks8842.c b/drivers/net/ethernet/micrel/ks8842.c
index 4a6ae057e3b1..4a6ae057e3b1 100644
--- a/drivers/net/ks8842.c
+++ b/drivers/net/ethernet/micrel/ks8842.c
diff --git a/drivers/net/ks8851.c b/drivers/net/ethernet/micrel/ks8851.c
index f56743a28fc0..f56743a28fc0 100644
--- a/drivers/net/ks8851.c
+++ b/drivers/net/ethernet/micrel/ks8851.c
diff --git a/drivers/net/ks8851.h b/drivers/net/ethernet/micrel/ks8851.h
index 537fb06e5932..537fb06e5932 100644
--- a/drivers/net/ks8851.h
+++ b/drivers/net/ethernet/micrel/ks8851.h
diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ethernet/micrel/ks8851_mll.c
index d19c849059d8..d19c849059d8 100644
--- a/drivers/net/ks8851_mll.c
+++ b/drivers/net/ethernet/micrel/ks8851_mll.c
diff --git a/drivers/net/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c
index 27418d31a09f..7ece990381c8 100644
--- a/drivers/net/ksz884x.c
+++ b/drivers/net/ethernet/micrel/ksz884x.c
@@ -4700,12 +4700,11 @@ static void send_packet(struct sk_buff *skb, struct net_device *dev)
++hw->tx_int_cnt;
dma_buf = DMA_BUFFER(desc);
- dma_buf->len = this_frag->size;
+ dma_buf->len = skb_frag_size(this_frag);
dma_buf->dma = pci_map_single(
hw_priv->pdev,
- page_address(this_frag->page) +
- this_frag->page_offset,
+ skb_frag_address(this_frag),
dma_buf->len,
PCI_DMA_TODEVICE);
set_tx_buf(desc, dma_buf->dma);
diff --git a/drivers/net/ethernet/microchip/Kconfig b/drivers/net/ethernet/microchip/Kconfig
new file mode 100644
index 000000000000..8163fd0f453f
--- /dev/null
+++ b/drivers/net/ethernet/microchip/Kconfig
@@ -0,0 +1,38 @@
+#
+# Microchip network device configuration
+#
+
+config NET_VENDOR_MICROCHIP
+ bool "Microchip devices"
+ default y
+ depends on SPI && EXPERIMENTAL
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Microchip cards. If you say Y, you will be asked
+ for your specific card in the following questions.
+
+if NET_VENDOR_MICROCHIP
+
+config ENC28J60
+ tristate "ENC28J60 support"
+ depends on SPI && EXPERIMENTAL
+ select CRC32
+ ---help---
+ Support for the Microchip EN28J60 ethernet chip.
+
+ To compile this driver as a module, choose M here. The module will be
+ called enc28j60.
+
+config ENC28J60_WRITEVERIFY
+ bool "Enable write verify"
+ depends on ENC28J60
+ ---help---
+ Enable the verify after the buffer write useful for debugging purpose.
+ If unsure, say N.
+
+endif # NET_VENDOR_MICROCHIP
diff --git a/drivers/net/ethernet/microchip/Makefile b/drivers/net/ethernet/microchip/Makefile
new file mode 100644
index 000000000000..573d4292b9ea
--- /dev/null
+++ b/drivers/net/ethernet/microchip/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Microchip network device drivers.
+#
+
+obj-$(CONFIG_ENC28J60) += enc28j60.o
diff --git a/drivers/net/enc28j60.c b/drivers/net/ethernet/microchip/enc28j60.c
index 2837ce209cd7..50055e0282ed 100644
--- a/drivers/net/enc28j60.c
+++ b/drivers/net/ethernet/microchip/enc28j60.c
@@ -1534,7 +1534,7 @@ static const struct net_device_ops enc28j60_netdev_ops = {
.ndo_open = enc28j60_net_open,
.ndo_stop = enc28j60_net_close,
.ndo_start_xmit = enc28j60_send_packet,
- .ndo_set_multicast_list = enc28j60_set_multicast_list,
+ .ndo_set_rx_mode = enc28j60_set_multicast_list,
.ndo_set_mac_address = enc28j60_set_mac_address,
.ndo_tx_timeout = enc28j60_tx_timeout,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/enc28j60_hw.h b/drivers/net/ethernet/microchip/enc28j60_hw.h
index 25b41de49f0e..25b41de49f0e 100644
--- a/drivers/net/enc28j60_hw.h
+++ b/drivers/net/ethernet/microchip/enc28j60_hw.h
diff --git a/drivers/net/mipsnet.c b/drivers/net/ethernet/mipsnet.c
index 004e64ab1f95..d05b0c9e1e9c 100644
--- a/drivers/net/mipsnet.c
+++ b/drivers/net/ethernet/mipsnet.c
@@ -242,7 +242,7 @@ static const struct net_device_ops mipsnet_netdev_ops = {
.ndo_open = mipsnet_open,
.ndo_stop = mipsnet_close,
.ndo_start_xmit = mipsnet_xmit,
- .ndo_set_multicast_list = mipsnet_set_mclist,
+ .ndo_set_rx_mode = mipsnet_set_mclist,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/ethernet/myricom/Kconfig b/drivers/net/ethernet/myricom/Kconfig
new file mode 100644
index 000000000000..540f0c6fc160
--- /dev/null
+++ b/drivers/net/ethernet/myricom/Kconfig
@@ -0,0 +1,47 @@
+#
+# Myricom device configuration
+#
+
+config NET_VENDOR_MYRI
+ bool "Myricom devices"
+ default y
+ depends on PCI && INET
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say
+ Y and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Myricom cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_MYRI
+
+config MYRI10GE
+ tristate "Myricom Myri-10G Ethernet support"
+ depends on PCI && INET
+ select FW_LOADER
+ select CRC32
+ select INET_LRO
+ ---help---
+ This driver supports Myricom Myri-10G Dual Protocol interface in
+ Ethernet mode. If the eeprom on your board is not recent enough,
+ you will need a newer firmware image.
+ You may get this image or more information, at:
+
+ <http://www.myri.com/scs/download-Myri10GE.html>
+
+ To compile this driver as a module, choose M here. The module
+ will be called myri10ge.
+
+config MYRI10GE_DCA
+ bool "Direct Cache Access (DCA) Support"
+ default y
+ depends on MYRI10GE && DCA && !(MYRI10GE=y && DCA=m)
+ ---help---
+ Say Y here if you want to use Direct Cache Access (DCA) in the
+ driver. DCA is a method for warming the CPU cache before data
+ is used, with the intent of lessening the impact of cache misses.
+
+endif # NET_VENDOR_MYRI
diff --git a/drivers/net/ethernet/myricom/Makefile b/drivers/net/ethernet/myricom/Makefile
new file mode 100644
index 000000000000..296c0a10056b
--- /dev/null
+++ b/drivers/net/ethernet/myricom/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Myricom network device drivers.
+#
+
+obj-$(CONFIG_MYRI10GE) += myri10ge/
diff --git a/drivers/net/myri10ge/Makefile b/drivers/net/ethernet/myricom/myri10ge/Makefile
index 5df891647aee..5df891647aee 100644
--- a/drivers/net/myri10ge/Makefile
+++ b/drivers/net/ethernet/myricom/myri10ge/Makefile
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
index 1d2247554a35..0778edcf7b9a 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
@@ -1210,13 +1210,12 @@ myri10ge_rx_skb_build(struct sk_buff *skb, u8 * va,
struct skb_frag_struct *skb_frags;
skb->len = skb->data_len = len;
- skb->truesize = len + sizeof(struct sk_buff);
/* attach the page(s) */
skb_frags = skb_shinfo(skb)->frags;
while (len > 0) {
memcpy(skb_frags, rx_frags, sizeof(*skb_frags));
- len -= rx_frags->size;
+ len -= skb_frag_size(rx_frags);
skb_frags++;
rx_frags++;
skb_shinfo(skb)->nr_frags++;
@@ -1228,7 +1227,7 @@ myri10ge_rx_skb_build(struct sk_buff *skb, u8 * va,
* manually */
skb_copy_to_linear_data(skb, va, hlen);
skb_shinfo(skb)->frags[0].page_offset += hlen;
- skb_shinfo(skb)->frags[0].size -= hlen;
+ skb_frag_size_sub(&skb_shinfo(skb)->frags[0], hlen);
skb->data_len -= hlen;
skb->tail += hlen;
skb_pull(skb, MXGEFW_PAD);
@@ -1342,12 +1341,12 @@ myri10ge_rx_done(struct myri10ge_slice_state *ss, int len, __wsum csum,
/* Fill skb_frag_struct(s) with data from our receive */
for (i = 0, remainder = len; remainder > 0; i++) {
myri10ge_unmap_rx_page(pdev, &rx->info[idx], bytes);
- rx_frags[i].page = rx->info[idx].page;
+ __skb_frag_set_page(&rx_frags[i], rx->info[idx].page);
rx_frags[i].page_offset = rx->info[idx].page_offset;
if (remainder < MYRI10GE_ALLOC_SIZE)
- rx_frags[i].size = remainder;
+ skb_frag_size_set(&rx_frags[i], remainder);
else
- rx_frags[i].size = MYRI10GE_ALLOC_SIZE;
+ skb_frag_size_set(&rx_frags[i], MYRI10GE_ALLOC_SIZE);
rx->cnt++;
idx = rx->cnt & rx->mask;
remainder -= MYRI10GE_ALLOC_SIZE;
@@ -1355,7 +1354,7 @@ myri10ge_rx_done(struct myri10ge_slice_state *ss, int len, __wsum csum,
if (lro_enabled) {
rx_frags[0].page_offset += MXGEFW_PAD;
- rx_frags[0].size -= MXGEFW_PAD;
+ skb_frag_size_sub(&rx_frags[0], MXGEFW_PAD);
len -= MXGEFW_PAD;
lro_receive_frags(&ss->rx_done.lro_mgr, rx_frags,
/* opaque, will come back in get_frag_header */
@@ -1375,16 +1374,18 @@ myri10ge_rx_done(struct myri10ge_slice_state *ss, int len, __wsum csum,
ss->stats.rx_dropped++;
do {
i--;
- put_page(rx_frags[i].page);
+ __skb_frag_unref(&rx_frags[i]);
} while (i != 0);
return 0;
}
/* Attach the pages to the skb, and trim off any padding */
myri10ge_rx_skb_build(skb, va, rx_frags, len, hlen);
- if (skb_shinfo(skb)->frags[0].size <= 0) {
- put_page(skb_shinfo(skb)->frags[0].page);
+ if (skb_frag_size(&skb_shinfo(skb)->frags[0]) <= 0) {
+ skb_frag_unref(skb, 0);
skb_shinfo(skb)->nr_frags = 0;
+ } else {
+ skb->truesize += bytes * skb_shinfo(skb)->nr_frags;
}
skb->protocol = eth_type_trans(skb, dev);
skb_record_rx_queue(skb, ss - &mgp->ss[0]);
@@ -2284,7 +2285,7 @@ myri10ge_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr,
struct ethhdr *eh;
struct vlan_ethhdr *veh;
struct iphdr *iph;
- u8 *va = page_address(frag->page) + frag->page_offset;
+ u8 *va = skb_frag_address(frag);
unsigned long ll_hlen;
/* passed opaque through lro_receive_frags() */
__wsum csum = (__force __wsum) (unsigned long)priv;
@@ -2926,9 +2927,9 @@ again:
idx = (count + tx->req) & tx->mask;
frag = &skb_shinfo(skb)->frags[frag_idx];
frag_idx++;
- len = frag->size;
- bus = pci_map_page(mgp->pdev, frag->page, frag->page_offset,
- len, PCI_DMA_TODEVICE);
+ len = skb_frag_size(frag);
+ bus = skb_frag_dma_map(&mgp->pdev->dev, frag, 0, len,
+ DMA_TO_DEVICE);
dma_unmap_addr_set(&tx->info[idx], bus, bus);
dma_unmap_len_set(&tx->info[idx], len, len);
}
@@ -3892,7 +3893,7 @@ static const struct net_device_ops myri10ge_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = myri10ge_change_mtu,
.ndo_fix_features = myri10ge_fix_features,
- .ndo_set_multicast_list = myri10ge_set_multicast_list,
+ .ndo_set_rx_mode = myri10ge_set_multicast_list,
.ndo_set_mac_address = myri10ge_set_mac_address,
};
diff --git a/drivers/net/myri10ge/myri10ge_mcp.h b/drivers/net/ethernet/myricom/myri10ge/myri10ge_mcp.h
index 11be150e4d67..11be150e4d67 100644
--- a/drivers/net/myri10ge/myri10ge_mcp.h
+++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge_mcp.h
diff --git a/drivers/net/myri10ge/myri10ge_mcp_gen_header.h b/drivers/net/ethernet/myricom/myri10ge/myri10ge_mcp_gen_header.h
index 7ec4b864a550..7ec4b864a550 100644
--- a/drivers/net/myri10ge/myri10ge_mcp_gen_header.h
+++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge_mcp_gen_header.h
diff --git a/drivers/net/ethernet/natsemi/Kconfig b/drivers/net/ethernet/natsemi/Kconfig
new file mode 100644
index 000000000000..4a6b9fd073b6
--- /dev/null
+++ b/drivers/net/ethernet/natsemi/Kconfig
@@ -0,0 +1,83 @@
+#
+# National Semi-conductor device configuration
+#
+
+config NET_VENDOR_NATSEMI
+ bool "National Semi-conductor devices"
+ default y
+ depends on MCA || MAC || MACH_JAZZ || PCI || XTENSA_PLATFORM_XT2000
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about National Semi-conductor devices. If you say Y,
+ you will be asked for your specific card in the following questions.
+
+if NET_VENDOR_NATSEMI
+
+config IBMLANA
+ tristate "IBM LAN Adapter/A support"
+ depends on MCA
+ ---help---
+ This is a Micro Channel Ethernet adapter. You need to set
+ CONFIG_MCA to use this driver. It is both available as an in-kernel
+ driver and as a module.
+
+ To compile this driver as a module, choose M here. The only
+ currently supported card is the IBM LAN Adapter/A for Ethernet. It
+ will both support 16K and 32K memory windows, however a 32K window
+ gives a better security against packet losses. Usage of multiple
+ boards with this driver should be possible, but has not been tested
+ up to now due to lack of hardware.
+
+config MACSONIC
+ tristate "Macintosh SONIC based ethernet (onboard, NuBus, LC, CS)"
+ depends on MAC
+ ---help---
+ Support for NatSemi SONIC based Ethernet devices. This includes
+ the onboard Ethernet in many Quadras as well as some LC-PDS,
+ a few Nubus and all known Comm Slot Ethernet cards. If you have
+ one of these say Y and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. This module will
+ be called macsonic.
+
+config MIPS_JAZZ_SONIC
+ tristate "MIPS JAZZ onboard SONIC Ethernet support"
+ depends on MACH_JAZZ
+ ---help---
+ This is the driver for the onboard card of MIPS Magnum 4000,
+ Acer PICA, Olivetti M700-10 and a few other identical OEM systems.
+
+config NATSEMI
+ tristate "National Semiconductor DP8381x series PCI Ethernet support"
+ depends on PCI
+ select CRC32
+ ---help---
+ This driver is for the National Semiconductor DP83810 series,
+ which is used in cards from PureData, NetGear, Linksys
+ and others, including the 83815 chip.
+ More specific information and updates are available from
+ <http://www.scyld.com/network/natsemi.html>.
+
+config NS83820
+ tristate "National Semiconductor DP83820 support"
+ depends on PCI
+ ---help---
+ This is a driver for the National Semiconductor DP83820 series
+ of gigabit ethernet MACs. Cards using this chipset include
+ the D-Link DGE-500T, PureData's PDP8023Z-TG, SMC's SMC9462TX,
+ SOHO-GA2000T, SOHO-GA2500T. The driver supports the use of
+ zero copy.
+
+config XTENSA_XT2000_SONIC
+ tristate "Xtensa XT2000 onboard SONIC Ethernet support"
+ depends on XTENSA_PLATFORM_XT2000
+ ---help---
+ This is the driver for the onboard card of the Xtensa XT2000 board.
+
+endif # NET_VENDOR_NATSEMI
diff --git a/drivers/net/ethernet/natsemi/Makefile b/drivers/net/ethernet/natsemi/Makefile
new file mode 100644
index 000000000000..9aa5dea52b3e
--- /dev/null
+++ b/drivers/net/ethernet/natsemi/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the National Semi-conductor Sonic devices.
+#
+
+obj-$(CONFIG_IBMLANA) += ibmlana.o
+obj-$(CONFIG_MACSONIC) += macsonic.o
+obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o
+obj-$(CONFIG_NATSEMI) += natsemi.o
+obj-$(CONFIG_NS83820) += ns83820.o
+obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o
diff --git a/drivers/net/ibmlana.c b/drivers/net/ethernet/natsemi/ibmlana.c
index a7d6cad32953..999407f7ebdf 100644
--- a/drivers/net/ibmlana.c
+++ b/drivers/net/ethernet/natsemi/ibmlana.c
@@ -910,7 +910,7 @@ static const struct net_device_ops ibmlana_netdev_ops = {
.ndo_open = ibmlana_open,
.ndo_stop = ibmlana_close,
.ndo_start_xmit = ibmlana_tx,
- .ndo_set_multicast_list = ibmlana_set_multicast_list,
+ .ndo_set_rx_mode = ibmlana_set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/ibmlana.h b/drivers/net/ethernet/natsemi/ibmlana.h
index accd5efc9c8a..accd5efc9c8a 100644
--- a/drivers/net/ibmlana.h
+++ b/drivers/net/ethernet/natsemi/ibmlana.h
diff --git a/drivers/net/jazzsonic.c b/drivers/net/ethernet/natsemi/jazzsonic.c
index 949c1f933644..fc7c6a932ad9 100644
--- a/drivers/net/jazzsonic.c
+++ b/drivers/net/ethernet/natsemi/jazzsonic.c
@@ -111,7 +111,7 @@ static const struct net_device_ops sonic_netdev_ops = {
.ndo_stop = jazzsonic_close,
.ndo_start_xmit = sonic_send_packet,
.ndo_get_stats = sonic_get_stats,
- .ndo_set_multicast_list = sonic_multicast_list,
+ .ndo_set_rx_mode = sonic_multicast_list,
.ndo_tx_timeout = sonic_tx_timeout,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/macsonic.c b/drivers/net/ethernet/natsemi/macsonic.c
index c93679ee6994..a2eacbfb4252 100644
--- a/drivers/net/macsonic.c
+++ b/drivers/net/ethernet/natsemi/macsonic.c
@@ -190,7 +190,7 @@ static const struct net_device_ops macsonic_netdev_ops = {
.ndo_open = macsonic_open,
.ndo_stop = macsonic_close,
.ndo_start_xmit = sonic_send_packet,
- .ndo_set_multicast_list = sonic_multicast_list,
+ .ndo_set_rx_mode = sonic_multicast_list,
.ndo_tx_timeout = sonic_tx_timeout,
.ndo_get_stats = sonic_get_stats,
.ndo_validate_addr = eth_validate_addr,
@@ -313,22 +313,13 @@ static void __devinit mac_onboard_sonic_ethernet_addr(struct net_device *dev)
static int __devinit mac_onboard_sonic_probe(struct net_device *dev)
{
- /* Bwahahaha */
- static int once_is_more_than_enough;
struct sonic_local* lp = netdev_priv(dev);
int sr;
int commslot = 0;
- if (once_is_more_than_enough)
- return -ENODEV;
- once_is_more_than_enough = 1;
-
if (!MACH_IS_MAC)
return -ENODEV;
- if (macintosh_config->ether_type != MAC_ETHER_SONIC)
- return -ENODEV;
-
printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. ");
/* Bogus probing, on the models which may or may not have
diff --git a/drivers/net/natsemi.c b/drivers/net/ethernet/natsemi/natsemi.c
index 2962cc695ce3..6ca047aab793 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/ethernet/natsemi/natsemi.c
@@ -783,7 +783,7 @@ static const struct net_device_ops natsemi_netdev_ops = {
.ndo_stop = netdev_close,
.ndo_start_xmit = start_tx,
.ndo_get_stats = get_stats,
- .ndo_set_multicast_list = set_rx_mode,
+ .ndo_set_rx_mode = set_rx_mode,
.ndo_change_mtu = natsemi_change_mtu,
.ndo_do_ioctl = netdev_ioctl,
.ndo_tx_timeout = ns_tx_timeout,
diff --git a/drivers/net/ns83820.c b/drivers/net/ethernet/natsemi/ns83820.c
index e736aec588fc..2b8f64ddfb55 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ethernet/natsemi/ns83820.c
@@ -1160,13 +1160,12 @@ again:
if (!nr_frags)
break;
- buf = pci_map_page(dev->pci_dev, frag->page,
- frag->page_offset,
- frag->size, PCI_DMA_TODEVICE);
+ buf = skb_frag_dma_map(&dev->pci_dev->dev, frag, 0,
+ skb_frag_size(frag), DMA_TO_DEVICE);
dprintk("frag: buf=%08Lx page=%08lx offset=%08lx\n",
(long long)buf, (long) page_to_pfn(frag->page),
frag->page_offset);
- len = frag->size;
+ len = skb_frag_size(frag);
frag++;
nr_frags--;
}
@@ -1937,7 +1936,7 @@ static const struct net_device_ops netdev_ops = {
.ndo_start_xmit = ns83820_hard_start_xmit,
.ndo_get_stats = ns83820_get_stats,
.ndo_change_mtu = ns83820_change_mtu,
- .ndo_set_multicast_list = ns83820_set_multicast,
+ .ndo_set_rx_mode = ns83820_set_multicast,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
.ndo_tx_timeout = ns83820_tx_timeout,
diff --git a/drivers/net/sonic.c b/drivers/net/ethernet/natsemi/sonic.c
index 26e25d7f5829..26e25d7f5829 100644
--- a/drivers/net/sonic.c
+++ b/drivers/net/ethernet/natsemi/sonic.c
diff --git a/drivers/net/sonic.h b/drivers/net/ethernet/natsemi/sonic.h
index 07091dd27e5d..07091dd27e5d 100644
--- a/drivers/net/sonic.h
+++ b/drivers/net/ethernet/natsemi/sonic.h
diff --git a/drivers/net/xtsonic.c b/drivers/net/ethernet/natsemi/xtsonic.c
index 9f12026d98e7..ccf61b9da8d1 100644
--- a/drivers/net/xtsonic.c
+++ b/drivers/net/ethernet/natsemi/xtsonic.c
@@ -122,7 +122,7 @@ static const struct net_device_ops xtsonic_netdev_ops = {
.ndo_stop = xtsonic_close,
.ndo_start_xmit = sonic_send_packet,
.ndo_get_stats = sonic_get_stats,
- .ndo_set_multicast_list = sonic_multicast_list,
+ .ndo_set_rx_mode = sonic_multicast_list,
.ndo_tx_timeout = sonic_tx_timeout,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/ethernet/neterion/Kconfig b/drivers/net/ethernet/neterion/Kconfig
new file mode 100644
index 000000000000..ff26b54bd3fb
--- /dev/null
+++ b/drivers/net/ethernet/neterion/Kconfig
@@ -0,0 +1,55 @@
+#
+# Exar device configuration
+#
+
+config NET_VENDOR_EXAR
+ bool "Exar devices"
+ default y
+ depends on PCI
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say
+ Y and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Exar cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_EXAR
+
+config S2IO
+ tristate "Exar Xframe 10Gb Ethernet Adapter"
+ depends on PCI
+ ---help---
+ This driver supports Exar Corp's Xframe Series 10Gb Ethernet Adapters.
+
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/s2io.txt>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called s2io.
+
+config VXGE
+ tristate "Exar X3100 Series 10GbE PCIe Server Adapter"
+ depends on PCI && INET
+ ---help---
+ This driver supports Exar Corp's X3100 Series 10 GbE PCIe
+ I/O Virtualized Server Adapter.
+
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/vxge.txt>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called vxge.
+
+config VXGE_DEBUG_TRACE_ALL
+ bool "Enabling All Debug trace statements in driver"
+ default n
+ depends on VXGE
+ ---help---
+ Say Y here if you want to enabling all the debug trace statements in
+ the vxge driver. By default only few debug trace statements are
+ enabled.
+
+endif # NET_VENDOR_EXAR
diff --git a/drivers/net/ethernet/neterion/Makefile b/drivers/net/ethernet/neterion/Makefile
new file mode 100644
index 000000000000..70c8058a601a
--- /dev/null
+++ b/drivers/net/ethernet/neterion/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the Exar network device drivers.
+#
+
+obj-$(CONFIG_S2IO) += s2io.o
+obj-$(CONFIG_VXGE) += vxge/
diff --git a/drivers/net/s2io-regs.h b/drivers/net/ethernet/neterion/s2io-regs.h
index 3688325c11f5..3688325c11f5 100644
--- a/drivers/net/s2io-regs.h
+++ b/drivers/net/ethernet/neterion/s2io-regs.h
diff --git a/drivers/net/s2io.c b/drivers/net/ethernet/neterion/s2io.c
index 277d48b0800a..c27fb3dda9f4 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/ethernet/neterion/s2io.c
@@ -2350,12 +2350,12 @@ static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data,
if (frg_cnt) {
txds++;
for (j = 0; j < frg_cnt; j++, txds++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[j];
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[j];
if (!txds->Buffer_Pointer)
break;
pci_unmap_page(nic->pdev,
(dma_addr_t)txds->Buffer_Pointer,
- frag->size, PCI_DMA_TODEVICE);
+ skb_frag_size(frag), PCI_DMA_TODEVICE);
}
}
memset(txdlp, 0, (sizeof(struct TxD) * fifo_data->max_txds));
@@ -4185,16 +4185,16 @@ static netdev_tx_t s2io_xmit(struct sk_buff *skb, struct net_device *dev)
frg_cnt = skb_shinfo(skb)->nr_frags;
/* For fragmented SKB. */
for (i = 0; i < frg_cnt; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
/* A '0' length fragment will be ignored */
- if (!frag->size)
+ if (!skb_frag_size(frag))
continue;
txdp++;
- txdp->Buffer_Pointer = (u64)pci_map_page(sp->pdev, frag->page,
- frag->page_offset,
- frag->size,
- PCI_DMA_TODEVICE);
- txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size);
+ txdp->Buffer_Pointer = (u64)skb_frag_dma_map(&sp->pdev->dev,
+ frag, 0,
+ skb_frag_size(frag),
+ DMA_TO_DEVICE);
+ txdp->Control_1 = TXD_BUFFER0_SIZE(skb_frag_size(frag));
if (offload_type == SKB_GSO_UDP)
txdp->Control_1 |= TXD_UFO_EN;
}
@@ -5522,14 +5522,12 @@ static void s2io_ethtool_gringparam(struct net_device *dev,
ering->rx_jumbo_max_pending = MAX_RX_DESC_2;
}
- ering->rx_mini_max_pending = 0;
ering->tx_max_pending = MAX_TX_DESC;
for (i = 0; i < sp->config.rx_ring_num; i++)
rx_desc_count += sp->config.rx_cfg[i].num_rxd;
ering->rx_pending = rx_desc_count;
ering->rx_jumbo_pending = rx_desc_count;
- ering->rx_mini_pending = 0;
for (i = 0; i < sp->config.tx_fifo_num; i++)
tx_desc_count += sp->config.tx_cfg[i].fifo_len;
@@ -7682,7 +7680,7 @@ static const struct net_device_ops s2io_netdev_ops = {
.ndo_get_stats = s2io_get_stats,
.ndo_start_xmit = s2io_xmit,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = s2io_set_multicast,
+ .ndo_set_rx_mode = s2io_set_multicast,
.ndo_do_ioctl = s2io_ioctl,
.ndo_set_mac_address = s2io_set_mac_addr,
.ndo_change_mtu = s2io_change_mtu,
diff --git a/drivers/net/s2io.h b/drivers/net/ethernet/neterion/s2io.h
index d5596926a1ef..d5596926a1ef 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/ethernet/neterion/s2io.h
diff --git a/drivers/net/vxge/Makefile b/drivers/net/ethernet/neterion/vxge/Makefile
index b625e2c503f5..b625e2c503f5 100644
--- a/drivers/net/vxge/Makefile
+++ b/drivers/net/ethernet/neterion/vxge/Makefile
diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/ethernet/neterion/vxge/vxge-config.c
index 1520c574cb20..98e2c10ae08b 100644
--- a/drivers/net/vxge/vxge-config.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-config.c
@@ -1342,9 +1342,7 @@ vxge_hw_device_initialize(
hldev->bar0 = attr->bar0;
hldev->pdev = attr->pdev;
- hldev->uld_callbacks.link_up = attr->uld_callbacks.link_up;
- hldev->uld_callbacks.link_down = attr->uld_callbacks.link_down;
- hldev->uld_callbacks.crit_err = attr->uld_callbacks.crit_err;
+ hldev->uld_callbacks = attr->uld_callbacks;
__vxge_hw_device_pci_e_init(hldev);
@@ -2633,7 +2631,7 @@ __vxge_hw_mempool_create(struct __vxge_hw_device *devh,
u32 items_priv_size,
u32 items_initial,
u32 items_max,
- struct vxge_hw_mempool_cbs *mp_callback,
+ const struct vxge_hw_mempool_cbs *mp_callback,
void *userdata)
{
enum vxge_hw_status status = VXGE_HW_OK;
@@ -2817,7 +2815,9 @@ __vxge_hw_ring_create(struct __vxge_hw_vpath_handle *vp,
struct vxge_hw_ring_config *config;
struct __vxge_hw_device *hldev;
u32 vp_id;
- struct vxge_hw_mempool_cbs ring_mp_callback;
+ static const struct vxge_hw_mempool_cbs ring_mp_callback = {
+ .item_func_alloc = __vxge_hw_ring_mempool_item_alloc,
+ };
if ((vp == NULL) || (attr == NULL)) {
status = VXGE_HW_FAIL;
@@ -2872,7 +2872,6 @@ __vxge_hw_ring_create(struct __vxge_hw_vpath_handle *vp,
/* calculate actual RxD block private size */
ring->rxdblock_priv_size = ring->rxd_priv_size * ring->rxds_per_block;
- ring_mp_callback.item_func_alloc = __vxge_hw_ring_mempool_item_alloc;
ring->mempool = __vxge_hw_mempool_create(hldev,
VXGE_HW_BLOCK_SIZE,
VXGE_HW_BLOCK_SIZE,
diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/ethernet/neterion/vxge/vxge-config.h
index dd362584f5ca..5046a64f0fe8 100644
--- a/drivers/net/vxge/vxge-config.h
+++ b/drivers/net/ethernet/neterion/vxge/vxge-config.h
@@ -740,7 +740,7 @@ struct __vxge_hw_device {
struct vxge_hw_device_config config;
enum vxge_hw_device_link_state link_state;
- struct vxge_hw_uld_cbs uld_callbacks;
+ const struct vxge_hw_uld_cbs *uld_callbacks;
u32 host_type;
u32 func_id;
@@ -840,7 +840,7 @@ struct vxge_hw_device_hw_info {
struct vxge_hw_device_attr {
void __iomem *bar0;
struct pci_dev *pdev;
- struct vxge_hw_uld_cbs uld_callbacks;
+ const struct vxge_hw_uld_cbs *uld_callbacks;
};
#define VXGE_HW_DEVICE_LINK_STATE_SET(hldev, ls) (hldev->link_state = ls)
diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/ethernet/neterion/vxge/vxge-ethtool.c
index 92dd72d3f9de..92dd72d3f9de 100644
--- a/drivers/net/vxge/vxge-ethtool.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-ethtool.c
diff --git a/drivers/net/vxge/vxge-ethtool.h b/drivers/net/ethernet/neterion/vxge/vxge-ethtool.h
index 6cf3044d7f43..6cf3044d7f43 100644
--- a/drivers/net/vxge/vxge-ethtool.h
+++ b/drivers/net/ethernet/neterion/vxge/vxge-ethtool.h
diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c
index 178348a258d2..671e166b5af1 100644
--- a/drivers/net/vxge/vxge-main.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c
@@ -585,7 +585,7 @@ vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr,
for (j = 0; j < frg_cnt; j++) {
pci_unmap_page(fifo->pdev,
txd_priv->dma_buffers[i++],
- frag->size, PCI_DMA_TODEVICE);
+ skb_frag_size(frag), PCI_DMA_TODEVICE);
frag += 1;
}
@@ -920,14 +920,14 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
frag = &skb_shinfo(skb)->frags[0];
for (i = 0; i < frg_cnt; i++) {
/* ignore 0 length fragment */
- if (!frag->size)
+ if (!skb_frag_size(frag))
continue;
- dma_pointer = (u64) pci_map_page(fifo->pdev, frag->page,
- frag->page_offset, frag->size,
- PCI_DMA_TODEVICE);
+ dma_pointer = (u64)skb_frag_dma_map(&fifo->pdev->dev, frag,
+ 0, skb_frag_size(frag),
+ DMA_TO_DEVICE);
- if (unlikely(pci_dma_mapping_error(fifo->pdev, dma_pointer)))
+ if (unlikely(dma_mapping_error(&fifo->pdev->dev, dma_pointer)))
goto _exit2;
vxge_debug_tx(VXGE_TRACE,
"%s: %s:%d frag = %d dma_pointer = 0x%llx",
@@ -936,7 +936,7 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
txdl_priv->dma_buffers[j] = dma_pointer;
vxge_hw_fifo_txdl_buffer_set(fifo_hw, dtr, j++, dma_pointer,
- frag->size);
+ skb_frag_size(frag));
frag += 1;
}
@@ -979,7 +979,7 @@ _exit1:
for (; j < i; j++) {
pci_unmap_page(fifo->pdev, txdl_priv->dma_buffers[j],
- frag->size, PCI_DMA_TODEVICE);
+ skb_frag_size(frag), PCI_DMA_TODEVICE);
frag += 1;
}
@@ -1050,7 +1050,7 @@ vxge_tx_term(void *dtrh, enum vxge_hw_txdl_state state, void *userdata)
for (j = 0; j < frg_cnt; j++) {
pci_unmap_page(fifo->pdev, txd_priv->dma_buffers[i++],
- frag->size, PCI_DMA_TODEVICE);
+ skb_frag_size(frag), PCI_DMA_TODEVICE);
frag += 1;
}
@@ -3354,7 +3354,7 @@ static const struct net_device_ops vxge_netdev_ops = {
.ndo_get_stats64 = vxge_get_stats64,
.ndo_start_xmit = vxge_xmit,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = vxge_set_multicast,
+ .ndo_set_rx_mode = vxge_set_multicast,
.ndo_do_ioctl = vxge_ioctl,
.ndo_set_mac_address = vxge_set_mac_addr,
.ndo_change_mtu = vxge_change_mtu,
@@ -4284,6 +4284,12 @@ static int __devinit is_sriov_initialized(struct pci_dev *pdev)
return 0;
}
+static const struct vxge_hw_uld_cbs vxge_callbacks = {
+ .link_up = vxge_callback_link_up,
+ .link_down = vxge_callback_link_down,
+ .crit_err = vxge_callback_crit_err,
+};
+
/**
* vxge_probe
* @pdev : structure containing the PCI related information of the device.
@@ -4494,9 +4500,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
}
/* Setting driver callbacks */
- attr.uld_callbacks.link_up = vxge_callback_link_up;
- attr.uld_callbacks.link_down = vxge_callback_link_down;
- attr.uld_callbacks.crit_err = vxge_callback_crit_err;
+ attr.uld_callbacks = &vxge_callbacks;
status = vxge_hw_device_initialize(&hldev, &attr, device_config);
if (status != VXGE_HW_OK) {
diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/ethernet/neterion/vxge/vxge-main.h
index f52a42d1dbb7..f52a42d1dbb7 100644
--- a/drivers/net/vxge/vxge-main.h
+++ b/drivers/net/ethernet/neterion/vxge/vxge-main.h
diff --git a/drivers/net/vxge/vxge-reg.h b/drivers/net/ethernet/neterion/vxge/vxge-reg.h
index 3e658b175947..3e658b175947 100644
--- a/drivers/net/vxge/vxge-reg.h
+++ b/drivers/net/ethernet/neterion/vxge/vxge-reg.h
diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/ethernet/neterion/vxge/vxge-traffic.c
index ad64ce0afe3f..5954fa264da1 100644
--- a/drivers/net/vxge/vxge-traffic.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-traffic.c
@@ -532,8 +532,8 @@ __vxge_hw_device_handle_error(struct __vxge_hw_device *hldev, u32 vp_id,
}
/* notify driver */
- if (hldev->uld_callbacks.crit_err)
- hldev->uld_callbacks.crit_err(
+ if (hldev->uld_callbacks->crit_err)
+ hldev->uld_callbacks->crit_err(
(struct __vxge_hw_device *)hldev,
type, vp_id);
out:
@@ -560,8 +560,8 @@ __vxge_hw_device_handle_link_down_ind(struct __vxge_hw_device *hldev)
hldev->link_state = VXGE_HW_LINK_DOWN;
/* notify driver */
- if (hldev->uld_callbacks.link_down)
- hldev->uld_callbacks.link_down(hldev);
+ if (hldev->uld_callbacks->link_down)
+ hldev->uld_callbacks->link_down(hldev);
exit:
return VXGE_HW_OK;
}
@@ -585,8 +585,8 @@ __vxge_hw_device_handle_link_up_ind(struct __vxge_hw_device *hldev)
hldev->link_state = VXGE_HW_LINK_UP;
/* notify driver */
- if (hldev->uld_callbacks.link_up)
- hldev->uld_callbacks.link_up(hldev);
+ if (hldev->uld_callbacks->link_up)
+ hldev->uld_callbacks->link_up(hldev);
exit:
return VXGE_HW_OK;
}
diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/ethernet/neterion/vxge/vxge-traffic.h
index 4a518a3b131c..4a518a3b131c 100644
--- a/drivers/net/vxge/vxge-traffic.h
+++ b/drivers/net/ethernet/neterion/vxge/vxge-traffic.h
diff --git a/drivers/net/vxge/vxge-version.h b/drivers/net/ethernet/neterion/vxge/vxge-version.h
index b9efa28bab3e..b9efa28bab3e 100644
--- a/drivers/net/vxge/vxge-version.h
+++ b/drivers/net/ethernet/neterion/vxge/vxge-version.h
diff --git a/drivers/net/netx-eth.c b/drivers/net/ethernet/netx-eth.c
index 2dfee892d200..8d288af16fc9 100644
--- a/drivers/net/netx-eth.c
+++ b/drivers/net/ethernet/netx-eth.c
@@ -306,7 +306,7 @@ static const struct net_device_ops netx_eth_netdev_ops = {
.ndo_stop = netx_eth_close,
.ndo_start_xmit = netx_eth_hard_start_xmit,
.ndo_tx_timeout = netx_eth_timeout,
- .ndo_set_multicast_list = netx_eth_set_multicast_list,
+ .ndo_set_rx_mode = netx_eth_set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/ethernet/nuvoton/Kconfig b/drivers/net/ethernet/nuvoton/Kconfig
new file mode 100644
index 000000000000..334c17183095
--- /dev/null
+++ b/drivers/net/ethernet/nuvoton/Kconfig
@@ -0,0 +1,31 @@
+#
+# Nuvoton network device configuration
+#
+
+config NET_VENDOR_NUVOTON
+ bool "Nuvoton devices"
+ default y
+ depends on ARM && ARCH_W90X900
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Nuvoton cards. If you say Y, you will be asked
+ for your specific card in the following questions.
+
+if NET_VENDOR_NUVOTON
+
+config W90P910_ETH
+ tristate "Nuvoton w90p910 Ethernet support"
+ depends on ARM && ARCH_W90X900
+ select PHYLIB
+ select NET_CORE
+ select MII
+ ---help---
+ Say Y here if you want to use built-in Ethernet ports
+ on w90p910 processor.
+
+endif # NET_VENDOR_NUVOTON
diff --git a/drivers/net/ethernet/nuvoton/Makefile b/drivers/net/ethernet/nuvoton/Makefile
new file mode 100644
index 000000000000..171aa044bd3b
--- /dev/null
+++ b/drivers/net/ethernet/nuvoton/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Nuvoton network device drivers.
+#
+
+obj-$(CONFIG_W90P910_ETH) += w90p910_ether.o
diff --git a/drivers/net/arm/w90p910_ether.c b/drivers/net/ethernet/nuvoton/w90p910_ether.c
index bfea499a3513..f1bfb8f8fcf0 100644
--- a/drivers/net/arm/w90p910_ether.c
+++ b/drivers/net/ethernet/nuvoton/w90p910_ether.c
@@ -919,7 +919,7 @@ static const struct net_device_ops w90p910_ether_netdev_ops = {
.ndo_stop = w90p910_ether_close,
.ndo_start_xmit = w90p910_ether_start_xmit,
.ndo_get_stats = w90p910_ether_stats,
- .ndo_set_multicast_list = w90p910_ether_set_multicast_list,
+ .ndo_set_rx_mode = w90p910_ether_set_multicast_list,
.ndo_set_mac_address = w90p910_set_mac_address,
.ndo_do_ioctl = w90p910_ether_ioctl,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/ethernet/nvidia/Kconfig b/drivers/net/ethernet/nvidia/Kconfig
new file mode 100644
index 000000000000..ace19e7f6d13
--- /dev/null
+++ b/drivers/net/ethernet/nvidia/Kconfig
@@ -0,0 +1,32 @@
+#
+# NVIDIA network device configuration
+#
+
+config NET_VENDOR_NVIDIA
+ bool "NVIDIA devices"
+ default y
+ depends on PCI
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about NVIDIA cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_NVIDIA
+
+config FORCEDETH
+ tristate "nForce Ethernet support"
+ depends on PCI
+ ---help---
+ If you have a network (Ethernet) controller of this type, say Y and
+ read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called forcedeth.
+
+endif # NET_VENDOR_NVIDIA
diff --git a/drivers/net/ethernet/nvidia/Makefile b/drivers/net/ethernet/nvidia/Makefile
new file mode 100644
index 000000000000..e079ae5771d5
--- /dev/null
+++ b/drivers/net/ethernet/nvidia/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the NVIDIA network device drivers.
+#
+
+obj-$(CONFIG_FORCEDETH) += forcedeth.o
diff --git a/drivers/net/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c
index e55df308a3af..1e37eb98c4e2 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/ethernet/nvidia/forcedeth.c
@@ -2099,8 +2099,10 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* add fragments to entries count */
for (i = 0; i < fragments; i++) {
- entries += (skb_shinfo(skb)->frags[i].size >> NV_TX2_TSO_MAX_SHIFT) +
- ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
+ u32 size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
+
+ entries += (size >> NV_TX2_TSO_MAX_SHIFT) +
+ ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
}
spin_lock_irqsave(&np->lock, flags);
@@ -2138,16 +2140,19 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* setup the fragments */
for (i = 0; i < fragments; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- u32 size = frag->size;
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ u32 size = skb_frag_size(frag);
offset = 0;
do {
prev_tx = put_tx;
prev_tx_ctx = np->put_tx_ctx;
bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
- np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
- PCI_DMA_TODEVICE);
+ np->put_tx_ctx->dma = skb_frag_dma_map(
+ &np->pci_dev->dev,
+ frag, offset,
+ bcnt,
+ DMA_TO_DEVICE);
np->put_tx_ctx->dma_len = bcnt;
np->put_tx_ctx->dma_single = 0;
put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma);
@@ -2208,8 +2213,10 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb,
/* add fragments to entries count */
for (i = 0; i < fragments; i++) {
- entries += (skb_shinfo(skb)->frags[i].size >> NV_TX2_TSO_MAX_SHIFT) +
- ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
+ u32 size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
+
+ entries += (size >> NV_TX2_TSO_MAX_SHIFT) +
+ ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
}
spin_lock_irqsave(&np->lock, flags);
@@ -2250,15 +2257,18 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb,
/* setup the fragments */
for (i = 0; i < fragments; i++) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- u32 size = frag->size;
+ u32 size = skb_frag_size(frag);
offset = 0;
do {
prev_tx = put_tx;
prev_tx_ctx = np->put_tx_ctx;
bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
- np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
- PCI_DMA_TODEVICE);
+ np->put_tx_ctx->dma = skb_frag_dma_map(
+ &np->pci_dev->dev,
+ frag, offset,
+ bcnt,
+ DMA_TO_DEVICE);
np->put_tx_ctx->dma_len = bcnt;
np->put_tx_ctx->dma_single = 0;
put_tx->bufhigh = cpu_to_le32(dma_high(np->put_tx_ctx->dma));
@@ -4274,13 +4284,9 @@ static void nv_get_ringparam(struct net_device *dev, struct ethtool_ringparam* r
struct fe_priv *np = netdev_priv(dev);
ring->rx_max_pending = (np->desc_ver == DESC_VER_1) ? RING_MAX_DESC_VER_1 : RING_MAX_DESC_VER_2_3;
- ring->rx_mini_max_pending = 0;
- ring->rx_jumbo_max_pending = 0;
ring->tx_max_pending = (np->desc_ver == DESC_VER_1) ? RING_MAX_DESC_VER_1 : RING_MAX_DESC_VER_2_3;
ring->rx_pending = np->rx_ring_size;
- ring->rx_mini_pending = 0;
- ring->rx_jumbo_pending = 0;
ring->tx_pending = np->tx_ring_size;
}
@@ -5208,7 +5214,7 @@ static const struct net_device_ops nv_netdev_ops = {
.ndo_set_features = nv_set_features,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = nv_set_mac_address,
- .ndo_set_multicast_list = nv_set_multicast,
+ .ndo_set_rx_mode = nv_set_multicast,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = nv_poll_controller,
#endif
@@ -5225,7 +5231,7 @@ static const struct net_device_ops nv_netdev_ops_optimized = {
.ndo_set_features = nv_set_features,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = nv_set_mac_address,
- .ndo_set_multicast_list = nv_set_multicast,
+ .ndo_set_rx_mode = nv_set_multicast,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = nv_poll_controller,
#endif
@@ -5615,7 +5621,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
goto out_error;
}
- nv_vlan_mode(dev, dev->features);
+ if (id->driver_data & DEV_HAS_VLAN)
+ nv_vlan_mode(dev, dev->features);
netif_carrier_off(dev);
diff --git a/drivers/net/octeon/Kconfig b/drivers/net/ethernet/octeon/Kconfig
index 1e56bbf3f5c0..3de52ffd2872 100644
--- a/drivers/net/octeon/Kconfig
+++ b/drivers/net/ethernet/octeon/Kconfig
@@ -1,10 +1,14 @@
+#
+# Cavium network device configuration
+#
+
config OCTEON_MGMT_ETHERNET
tristate "Octeon Management port ethernet driver (CN5XXX, CN6XXX)"
depends on CPU_CAVIUM_OCTEON
select PHYLIB
select MDIO_OCTEON
default y
- help
+ ---help---
This option enables the ethernet driver for the management
port on Cavium Networks' Octeon CN57XX, CN56XX, CN55XX,
CN54XX, CN52XX, and CN6XXX chips.
diff --git a/drivers/net/ethernet/octeon/Makefile b/drivers/net/ethernet/octeon/Makefile
new file mode 100644
index 000000000000..efa41c1d91c5
--- /dev/null
+++ b/drivers/net/ethernet/octeon/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Cavium network device drivers.
+#
+
+obj-$(CONFIG_OCTEON_MGMT_ETHERNET) += octeon_mgmt.o
diff --git a/drivers/net/octeon/octeon_mgmt.c b/drivers/net/ethernet/octeon/octeon_mgmt.c
index 429e08c84e9b..bc1d946b7971 100644
--- a/drivers/net/octeon/octeon_mgmt.c
+++ b/drivers/net/ethernet/octeon/octeon_mgmt.c
@@ -13,6 +13,7 @@
#include <linux/platform_device.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/if.h>
#include <linux/if_vlan.h>
#include <linux/slab.h>
#include <linux/phy.h>
@@ -1059,7 +1060,6 @@ static const struct net_device_ops octeon_mgmt_ops = {
.ndo_stop = octeon_mgmt_stop,
.ndo_start_xmit = octeon_mgmt_xmit,
.ndo_set_rx_mode = octeon_mgmt_set_rx_filtering,
- .ndo_set_multicast_list = octeon_mgmt_set_rx_filtering,
.ndo_set_mac_address = octeon_mgmt_set_mac_address,
.ndo_do_ioctl = octeon_mgmt_ioctl,
.ndo_change_mtu = octeon_mgmt_change_mtu,
@@ -1102,6 +1102,8 @@ static int __devinit octeon_mgmt_probe(struct platform_device *pdev)
tasklet_init(&p->tx_clean_tasklet,
octeon_mgmt_clean_tx_tasklet, (unsigned long)p);
+ netdev->priv_flags |= IFF_UNICAST_FLT;
+
netdev->netdev_ops = &octeon_mgmt_ops;
netdev->ethtool_ops = &octeon_mgmt_ethtool_ops;
diff --git a/drivers/net/ethernet/oki-semi/Kconfig b/drivers/net/ethernet/oki-semi/Kconfig
new file mode 100644
index 000000000000..ecd45f9ea9d9
--- /dev/null
+++ b/drivers/net/ethernet/oki-semi/Kconfig
@@ -0,0 +1,23 @@
+#
+# OKI Semiconductor device configuration
+#
+
+config NET_VENDOR_OKI
+ bool "OKI Semiconductor devices"
+ default y
+ depends on PCI
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about OKI Semiconductor cards. If you say Y, you will
+ be asked for your specific card in the following questions.
+
+if NET_VENDOR_OKI
+
+source "drivers/net/ethernet/oki-semi/pch_gbe/Kconfig"
+
+endif # NET_VENDOR_OKI
diff --git a/drivers/net/ethernet/oki-semi/Makefile b/drivers/net/ethernet/oki-semi/Makefile
new file mode 100644
index 000000000000..b6780c877c19
--- /dev/null
+++ b/drivers/net/ethernet/oki-semi/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the OKI Semiconductor device drivers.
+#
+
+obj-$(CONFIG_PCH_GBE) += pch_gbe/
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig b/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig
new file mode 100644
index 000000000000..00bc4fc968c7
--- /dev/null
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig
@@ -0,0 +1,22 @@
+#
+# OKI Semiconductor device configuration
+#
+
+config PCH_GBE
+ tristate "OKI SEMICONDUCTOR IOH(ML7223/ML7831) GbE"
+ depends on PCI
+ select NET_CORE
+ select MII
+ ---help---
+ This is a gigabit ethernet driver for EG20T PCH.
+ EG20T PCH is the platform controller hub that is used in Intel's
+ general embedded platform. EG20T PCH has Gigabit Ethernet interface.
+ Using this interface, it is able to access system devices connected
+ to Gigabit Ethernet. This driver enables Gigabit Ethernet function.
+
+ This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
+ Output Hub), ML7223/ML7831.
+ ML7223 IOH is for MP(Media Phone) use. ML7831 IOH is for general
+ purpose use.
+ ML7223/ML7831 is companion chip for Intel Atom E6xx series.
+ ML7223/ML7831 is completely compatible for Intel EG20T PCH.
diff --git a/drivers/net/pch_gbe/Makefile b/drivers/net/ethernet/oki-semi/pch_gbe/Makefile
index 31288d4ad248..31288d4ad248 100644
--- a/drivers/net/pch_gbe/Makefile
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/Makefile
diff --git a/drivers/net/pch_gbe/pch_gbe.h b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h
index 59fac77d0dbb..a09a07197eb5 100644
--- a/drivers/net/pch_gbe/pch_gbe.h
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h
@@ -127,8 +127,8 @@ struct pch_gbe_regs {
/* Reset */
#define PCH_GBE_ALL_RST 0x80000000 /* All reset */
-#define PCH_GBE_TX_RST 0x40000000 /* TX MAC, TX FIFO, TX DMA reset */
-#define PCH_GBE_RX_RST 0x04000000 /* RX MAC, RX FIFO, RX DMA reset */
+#define PCH_GBE_TX_RST 0x00008000 /* TX MAC, TX FIFO, TX DMA reset */
+#define PCH_GBE_RX_RST 0x00004000 /* RX MAC, RX FIFO, RX DMA reset */
/* TCP/IP Accelerator Control */
#define PCH_GBE_EX_LIST_EN 0x00000008 /* External List Enable */
@@ -276,6 +276,9 @@ struct pch_gbe_regs {
#define PCH_GBE_RX_DMA_EN 0x00000002 /* Enables Receive DMA */
#define PCH_GBE_TX_DMA_EN 0x00000001 /* Enables Transmission DMA */
+/* RX DMA STATUS */
+#define PCH_GBE_IDLE_CHECK 0xFFFFFFFE
+
/* Wake On LAN Status */
#define PCH_GBE_WLS_BR 0x00000008 /* Broadcas Address */
#define PCH_GBE_WLS_MLT 0x00000004 /* Multicast Address */
@@ -471,6 +474,7 @@ struct pch_gbe_tx_desc {
struct pch_gbe_buffer {
struct sk_buff *skb;
dma_addr_t dma;
+ unsigned char *rx_buffer;
unsigned long time_stamp;
u16 length;
bool mapped;
@@ -511,6 +515,9 @@ struct pch_gbe_tx_ring {
struct pch_gbe_rx_ring {
struct pch_gbe_rx_desc *desc;
dma_addr_t dma;
+ unsigned char *rx_buff_pool;
+ dma_addr_t rx_buff_pool_logic;
+ unsigned int rx_buff_pool_size;
unsigned int size;
unsigned int count;
unsigned int next_to_use;
@@ -622,6 +629,7 @@ struct pch_gbe_adapter {
unsigned long rx_buffer_len;
unsigned long tx_queue_len;
bool have_msi;
+ bool rx_stop_flag;
};
extern const char pch_driver_version[];
diff --git a/drivers/net/pch_gbe/pch_gbe_api.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_api.c
index e48f084ad226..e48f084ad226 100644
--- a/drivers/net/pch_gbe/pch_gbe_api.c
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_api.c
diff --git a/drivers/net/pch_gbe/pch_gbe_api.h b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_api.h
index 94aaac5b057b..94aaac5b057b 100644
--- a/drivers/net/pch_gbe/pch_gbe_api.h
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_api.h
diff --git a/drivers/net/pch_gbe/pch_gbe_ethtool.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c
index ea2d8e41887a..8c8027176bef 100644
--- a/drivers/net/pch_gbe/pch_gbe_ethtool.c
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c
@@ -273,12 +273,8 @@ static void pch_gbe_get_ringparam(struct net_device *netdev,
ring->rx_max_pending = PCH_GBE_MAX_RXD;
ring->tx_max_pending = PCH_GBE_MAX_TXD;
- ring->rx_mini_max_pending = 0;
- ring->rx_jumbo_max_pending = 0;
ring->rx_pending = rxdr->count;
ring->tx_pending = txdr->count;
- ring->rx_mini_pending = 0;
- ring->rx_jumbo_pending = 0;
}
/**
diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
index eac3c5ca9731..b89f3a684aec 100644
--- a/drivers/net/pch_gbe/pch_gbe_main.c
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
@@ -20,7 +20,6 @@
#include "pch_gbe.h"
#include "pch_gbe_api.h"
-#include <linux/prefetch.h>
#define DRV_VERSION "1.00"
const char pch_driver_version[] = DRV_VERSION;
@@ -34,11 +33,15 @@ const char pch_driver_version[] = DRV_VERSION;
#define PCH_GBE_WATCHDOG_PERIOD (1 * HZ) /* watchdog time */
#define PCH_GBE_COPYBREAK_DEFAULT 256
#define PCH_GBE_PCI_BAR 1
+#define PCH_GBE_RESERVE_MEMORY 0x200000 /* 2MB */
/* Macros for ML7223 */
#define PCI_VENDOR_ID_ROHM 0x10db
#define PCI_DEVICE_ID_ROHM_ML7223_GBE 0x8013
+/* Macros for ML7831 */
+#define PCI_DEVICE_ID_ROHM_ML7831_GBE 0x8802
+
#define PCH_GBE_TX_WEIGHT 64
#define PCH_GBE_RX_WEIGHT 64
#define PCH_GBE_RX_BUFFER_WRITE 16
@@ -52,6 +55,7 @@ const char pch_driver_version[] = DRV_VERSION;
)
/* Ethertype field values */
+#define PCH_GBE_MAX_RX_BUFFER_SIZE 0x2880
#define PCH_GBE_MAX_JUMBO_FRAME_SIZE 10318
#define PCH_GBE_FRAME_SIZE_2048 2048
#define PCH_GBE_FRAME_SIZE_4096 4096
@@ -83,10 +87,12 @@ const char pch_driver_version[] = DRV_VERSION;
#define PCH_GBE_INT_ENABLE_MASK ( \
PCH_GBE_INT_RX_DMA_CMPLT | \
PCH_GBE_INT_RX_DSC_EMP | \
+ PCH_GBE_INT_RX_FIFO_ERR | \
PCH_GBE_INT_WOL_DET | \
PCH_GBE_INT_TX_CMPLT \
)
+#define PCH_GBE_INT_DISABLE_ALL 0
static unsigned int copybreak __read_mostly = PCH_GBE_COPYBREAK_DEFAULT;
@@ -138,6 +144,27 @@ static void pch_gbe_wait_clr_bit(void *reg, u32 bit)
if (!tmp)
pr_err("Error: busy bit is not cleared\n");
}
+
+/**
+ * pch_gbe_wait_clr_bit_irq - Wait to clear a bit for interrupt context
+ * @reg: Pointer of register
+ * @busy: Busy bit
+ */
+static int pch_gbe_wait_clr_bit_irq(void *reg, u32 bit)
+{
+ u32 tmp;
+ int ret = -1;
+ /* wait busy */
+ tmp = 20;
+ while ((ioread32(reg) & bit) && --tmp)
+ udelay(5);
+ if (!tmp)
+ pr_err("Error: busy bit is not cleared\n");
+ else
+ ret = 0;
+ return ret;
+}
+
/**
* pch_gbe_mac_mar_set - Set MAC address register
* @hw: Pointer to the HW structure
@@ -189,6 +216,17 @@ static void pch_gbe_mac_reset_hw(struct pch_gbe_hw *hw)
return;
}
+static void pch_gbe_mac_reset_rx(struct pch_gbe_hw *hw)
+{
+ /* Read the MAC address. and store to the private data */
+ pch_gbe_mac_read_mac_addr(hw);
+ iowrite32(PCH_GBE_RX_RST, &hw->reg->RESET);
+ pch_gbe_wait_clr_bit_irq(&hw->reg->RESET, PCH_GBE_RX_RST);
+ /* Setup the MAC address */
+ pch_gbe_mac_mar_set(hw, hw->mac.addr, 0);
+ return;
+}
+
/**
* pch_gbe_mac_init_rx_addrs - Initialize receive address's
* @hw: Pointer to the HW structure
@@ -660,7 +698,6 @@ static void pch_gbe_configure_tx(struct pch_gbe_adapter *adapter)
*/
static void pch_gbe_setup_rctl(struct pch_gbe_adapter *adapter)
{
- struct net_device *netdev = adapter->netdev;
struct pch_gbe_hw *hw = &adapter->hw;
u32 rx_mode, tcpip;
@@ -671,13 +708,8 @@ static void pch_gbe_setup_rctl(struct pch_gbe_adapter *adapter)
tcpip = ioread32(&hw->reg->TCPIP_ACC);
- if (netdev->features & NETIF_F_RXCSUM) {
- tcpip &= ~PCH_GBE_RX_TCPIPACC_OFF;
- tcpip |= PCH_GBE_RX_TCPIPACC_EN;
- } else {
- tcpip |= PCH_GBE_RX_TCPIPACC_OFF;
- tcpip &= ~PCH_GBE_RX_TCPIPACC_EN;
- }
+ tcpip |= PCH_GBE_RX_TCPIPACC_OFF;
+ tcpip &= ~PCH_GBE_RX_TCPIPACC_EN;
iowrite32(tcpip, &hw->reg->TCPIP_ACC);
return;
}
@@ -717,13 +749,6 @@ static void pch_gbe_configure_rx(struct pch_gbe_adapter *adapter)
iowrite32(rdba, &hw->reg->RX_DSC_BASE);
iowrite32(rdlen, &hw->reg->RX_DSC_SIZE);
iowrite32((rdba + rdlen), &hw->reg->RX_DSC_SW_P);
-
- /* Enables Receive DMA */
- rxdma = ioread32(&hw->reg->DMA_CTRL);
- rxdma |= PCH_GBE_RX_DMA_EN;
- iowrite32(rxdma, &hw->reg->DMA_CTRL);
- /* Enables Receive */
- iowrite32(PCH_GBE_MRE_MAC_RX_EN, &hw->reg->MAC_RX_EN);
}
/**
@@ -1097,6 +1122,48 @@ void pch_gbe_update_stats(struct pch_gbe_adapter *adapter)
spin_unlock_irqrestore(&adapter->stats_lock, flags);
}
+static void pch_gbe_stop_receive(struct pch_gbe_adapter *adapter)
+{
+ struct pch_gbe_hw *hw = &adapter->hw;
+ u32 rxdma;
+ u16 value;
+ int ret;
+
+ /* Disable Receive DMA */
+ rxdma = ioread32(&hw->reg->DMA_CTRL);
+ rxdma &= ~PCH_GBE_RX_DMA_EN;
+ iowrite32(rxdma, &hw->reg->DMA_CTRL);
+ /* Wait Rx DMA BUS is IDLE */
+ ret = pch_gbe_wait_clr_bit_irq(&hw->reg->RX_DMA_ST, PCH_GBE_IDLE_CHECK);
+ if (ret) {
+ /* Disable Bus master */
+ pci_read_config_word(adapter->pdev, PCI_COMMAND, &value);
+ value &= ~PCI_COMMAND_MASTER;
+ pci_write_config_word(adapter->pdev, PCI_COMMAND, value);
+ /* Stop Receive */
+ pch_gbe_mac_reset_rx(hw);
+ /* Enable Bus master */
+ value |= PCI_COMMAND_MASTER;
+ pci_write_config_word(adapter->pdev, PCI_COMMAND, value);
+ } else {
+ /* Stop Receive */
+ pch_gbe_mac_reset_rx(hw);
+ }
+}
+
+static void pch_gbe_start_receive(struct pch_gbe_hw *hw)
+{
+ u32 rxdma;
+
+ /* Enables Receive DMA */
+ rxdma = ioread32(&hw->reg->DMA_CTRL);
+ rxdma |= PCH_GBE_RX_DMA_EN;
+ iowrite32(rxdma, &hw->reg->DMA_CTRL);
+ /* Enables Receive */
+ iowrite32(PCH_GBE_MRE_MAC_RX_EN, &hw->reg->MAC_RX_EN);
+ return;
+}
+
/**
* pch_gbe_intr - Interrupt Handler
* @irq: Interrupt number
@@ -1123,7 +1190,17 @@ static irqreturn_t pch_gbe_intr(int irq, void *data)
if (int_st & PCH_GBE_INT_RX_FRAME_ERR)
adapter->stats.intr_rx_frame_err_count++;
if (int_st & PCH_GBE_INT_RX_FIFO_ERR)
- adapter->stats.intr_rx_fifo_err_count++;
+ if (!adapter->rx_stop_flag) {
+ adapter->stats.intr_rx_fifo_err_count++;
+ pr_debug("Rx fifo over run\n");
+ adapter->rx_stop_flag = true;
+ int_en = ioread32(&hw->reg->INT_EN);
+ iowrite32((int_en & ~PCH_GBE_INT_RX_FIFO_ERR),
+ &hw->reg->INT_EN);
+ pch_gbe_stop_receive(adapter);
+ int_st |= ioread32(&hw->reg->INT_ST);
+ int_st = int_st & ioread32(&hw->reg->INT_EN);
+ }
if (int_st & PCH_GBE_INT_RX_DMA_ERR)
adapter->stats.intr_rx_dma_err_count++;
if (int_st & PCH_GBE_INT_TX_FIFO_ERR)
@@ -1135,21 +1212,18 @@ static irqreturn_t pch_gbe_intr(int irq, void *data)
/* When Rx descriptor is empty */
if ((int_st & PCH_GBE_INT_RX_DSC_EMP)) {
adapter->stats.intr_rx_dsc_empty_count++;
- pr_err("Rx descriptor is empty\n");
+ pr_debug("Rx descriptor is empty\n");
int_en = ioread32(&hw->reg->INT_EN);
iowrite32((int_en & ~PCH_GBE_INT_RX_DSC_EMP), &hw->reg->INT_EN);
if (hw->mac.tx_fc_enable) {
/* Set Pause packet */
pch_gbe_mac_set_pause_packet(hw);
}
- if ((int_en & (PCH_GBE_INT_RX_DMA_CMPLT | PCH_GBE_INT_TX_CMPLT))
- == 0) {
- return IRQ_HANDLED;
- }
}
/* When request status is Receive interruption */
- if ((int_st & (PCH_GBE_INT_RX_DMA_CMPLT | PCH_GBE_INT_TX_CMPLT))) {
+ if ((int_st & (PCH_GBE_INT_RX_DMA_CMPLT | PCH_GBE_INT_TX_CMPLT)) ||
+ (adapter->rx_stop_flag == true)) {
if (likely(napi_schedule_prep(&adapter->napi))) {
/* Enable only Rx Descriptor empty */
atomic_inc(&adapter->irq_sem);
@@ -1185,29 +1259,23 @@ pch_gbe_alloc_rx_buffers(struct pch_gbe_adapter *adapter,
unsigned int i;
unsigned int bufsz;
- bufsz = adapter->rx_buffer_len + PCH_GBE_DMA_ALIGN;
+ bufsz = adapter->rx_buffer_len + NET_IP_ALIGN;
i = rx_ring->next_to_use;
while ((cleaned_count--)) {
buffer_info = &rx_ring->buffer_info[i];
- skb = buffer_info->skb;
- if (skb) {
- skb_trim(skb, 0);
- } else {
- skb = netdev_alloc_skb(netdev, bufsz);
- if (unlikely(!skb)) {
- /* Better luck next round */
- adapter->stats.rx_alloc_buff_failed++;
- break;
- }
- /* 64byte align */
- skb_reserve(skb, PCH_GBE_DMA_ALIGN);
-
- buffer_info->skb = skb;
- buffer_info->length = adapter->rx_buffer_len;
+ skb = netdev_alloc_skb(netdev, bufsz);
+ if (unlikely(!skb)) {
+ /* Better luck next round */
+ adapter->stats.rx_alloc_buff_failed++;
+ break;
}
+ /* align */
+ skb_reserve(skb, NET_IP_ALIGN);
+ buffer_info->skb = skb;
+
buffer_info->dma = dma_map_single(&pdev->dev,
- skb->data,
+ buffer_info->rx_buffer,
buffer_info->length,
DMA_FROM_DEVICE);
if (dma_mapping_error(&adapter->pdev->dev, buffer_info->dma)) {
@@ -1240,6 +1308,36 @@ pch_gbe_alloc_rx_buffers(struct pch_gbe_adapter *adapter,
return;
}
+static int
+pch_gbe_alloc_rx_buffers_pool(struct pch_gbe_adapter *adapter,
+ struct pch_gbe_rx_ring *rx_ring, int cleaned_count)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct pch_gbe_buffer *buffer_info;
+ unsigned int i;
+ unsigned int bufsz;
+ unsigned int size;
+
+ bufsz = adapter->rx_buffer_len;
+
+ size = rx_ring->count * bufsz + PCH_GBE_RESERVE_MEMORY;
+ rx_ring->rx_buff_pool = dma_alloc_coherent(&pdev->dev, size,
+ &rx_ring->rx_buff_pool_logic,
+ GFP_KERNEL);
+ if (!rx_ring->rx_buff_pool) {
+ pr_err("Unable to allocate memory for the receive poll buffer\n");
+ return -ENOMEM;
+ }
+ memset(rx_ring->rx_buff_pool, 0, size);
+ rx_ring->rx_buff_pool_size = size;
+ for (i = 0; i < rx_ring->count; i++) {
+ buffer_info = &rx_ring->buffer_info[i];
+ buffer_info->rx_buffer = rx_ring->rx_buff_pool + bufsz * i;
+ buffer_info->length = bufsz;
+ }
+ return 0;
+}
+
/**
* pch_gbe_alloc_tx_buffers - Allocate transmit buffers
* @adapter: Board private structure
@@ -1285,7 +1383,7 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter,
struct sk_buff *skb;
unsigned int i;
unsigned int cleaned_count = 0;
- bool cleaned = false;
+ bool cleaned = true;
pr_debug("next_to_clean : %d\n", tx_ring->next_to_clean);
@@ -1296,7 +1394,6 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter,
while ((tx_desc->gbec_status & DSC_INIT16) == 0x0000) {
pr_debug("gbec_status:0x%04x\n", tx_desc->gbec_status);
- cleaned = true;
buffer_info = &tx_ring->buffer_info[i];
skb = buffer_info->skb;
@@ -1339,8 +1436,10 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter,
tx_desc = PCH_GBE_TX_DESC(*tx_ring, i);
/* weight of a sort for tx, to avoid endless transmit cleanup */
- if (cleaned_count++ == PCH_GBE_TX_WEIGHT)
+ if (cleaned_count++ == PCH_GBE_TX_WEIGHT) {
+ cleaned = false;
break;
+ }
}
pr_debug("called pch_gbe_unmap_and_free_tx_resource() %d count\n",
cleaned_count);
@@ -1380,7 +1479,7 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,
unsigned int i;
unsigned int cleaned_count = 0;
bool cleaned = false;
- struct sk_buff *skb, *new_skb;
+ struct sk_buff *skb;
u8 dma_status;
u16 gbec_status;
u32 tcp_ip_status;
@@ -1401,13 +1500,12 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,
rx_desc->gbec_status = DSC_INIT16;
buffer_info = &rx_ring->buffer_info[i];
skb = buffer_info->skb;
+ buffer_info->skb = NULL;
/* unmap dma */
dma_unmap_single(&pdev->dev, buffer_info->dma,
buffer_info->length, DMA_FROM_DEVICE);
buffer_info->mapped = false;
- /* Prefetch the packet */
- prefetch(skb->data);
pr_debug("RxDecNo = 0x%04x Status[DMA:0x%02x GBE:0x%04x "
"TCP:0x%08x] BufInf = 0x%p\n",
@@ -1427,70 +1525,16 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,
pr_err("Receive CRC Error\n");
} else {
/* get receive length */
- /* length convert[-3] */
- length = (rx_desc->rx_words_eob) - 3;
-
- /* Decide the data conversion method */
- if (!(netdev->features & NETIF_F_RXCSUM)) {
- /* [Header:14][payload] */
- if (NET_IP_ALIGN) {
- /* Because alignment differs,
- * the new_skb is newly allocated,
- * and data is copied to new_skb.*/
- new_skb = netdev_alloc_skb(netdev,
- length + NET_IP_ALIGN);
- if (!new_skb) {
- /* dorrop error */
- pr_err("New skb allocation "
- "Error\n");
- goto dorrop;
- }
- skb_reserve(new_skb, NET_IP_ALIGN);
- memcpy(new_skb->data, skb->data,
- length);
- skb = new_skb;
- } else {
- /* DMA buffer is used as SKB as it is.*/
- buffer_info->skb = NULL;
- }
- } else {
- /* [Header:14][padding:2][payload] */
- /* The length includes padding length */
- length = length - PCH_GBE_DMA_PADDING;
- if ((length < copybreak) ||
- (NET_IP_ALIGN != PCH_GBE_DMA_PADDING)) {
- /* Because alignment differs,
- * the new_skb is newly allocated,
- * and data is copied to new_skb.
- * Padding data is deleted
- * at the time of a copy.*/
- new_skb = netdev_alloc_skb(netdev,
- length + NET_IP_ALIGN);
- if (!new_skb) {
- /* dorrop error */
- pr_err("New skb allocation "
- "Error\n");
- goto dorrop;
- }
- skb_reserve(new_skb, NET_IP_ALIGN);
- memcpy(new_skb->data, skb->data,
- ETH_HLEN);
- memcpy(&new_skb->data[ETH_HLEN],
- &skb->data[ETH_HLEN +
- PCH_GBE_DMA_PADDING],
- length - ETH_HLEN);
- skb = new_skb;
- } else {
- /* Padding data is deleted
- * by moving header data.*/
- memmove(&skb->data[PCH_GBE_DMA_PADDING],
- &skb->data[0], ETH_HLEN);
- skb_reserve(skb, NET_IP_ALIGN);
- buffer_info->skb = NULL;
- }
- }
- /* The length includes FCS length */
- length = length - ETH_FCS_LEN;
+ /* length convert[-3], length includes FCS length */
+ length = (rx_desc->rx_words_eob) - 3 - ETH_FCS_LEN;
+ if (rx_desc->rx_words_eob & 0x02)
+ length = length - 4;
+ /*
+ * buffer_info->rx_buffer: [Header:14][payload]
+ * skb->data: [Reserve:2][Header:14][payload]
+ */
+ memcpy(skb->data, buffer_info->rx_buffer, length);
+
/* update status of driver */
adapter->stats.rx_bytes += length;
adapter->stats.rx_packets++;
@@ -1509,7 +1553,6 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,
pr_debug("Receive skb->ip_summed: %d length: %d\n",
skb->ip_summed, length);
}
-dorrop:
/* return some buffers to hardware, one at a time is too slow */
if (unlikely(cleaned_count >= PCH_GBE_RX_BUFFER_WRITE)) {
pch_gbe_alloc_rx_buffers(adapter, rx_ring,
@@ -1714,9 +1757,15 @@ int pch_gbe_up(struct pch_gbe_adapter *adapter)
pr_err("Error: can't bring device up\n");
return err;
}
+ err = pch_gbe_alloc_rx_buffers_pool(adapter, rx_ring, rx_ring->count);
+ if (err) {
+ pr_err("Error: can't bring device up\n");
+ return err;
+ }
pch_gbe_alloc_tx_buffers(adapter, tx_ring);
pch_gbe_alloc_rx_buffers(adapter, rx_ring, rx_ring->count);
adapter->tx_queue_len = netdev->tx_queue_len;
+ pch_gbe_start_receive(&adapter->hw);
mod_timer(&adapter->watchdog_timer, jiffies);
@@ -1734,6 +1783,7 @@ int pch_gbe_up(struct pch_gbe_adapter *adapter)
void pch_gbe_down(struct pch_gbe_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
+ struct pch_gbe_rx_ring *rx_ring = adapter->rx_ring;
/* signal that we're down so the interrupt handler does not
* reschedule our watchdog timer */
@@ -1752,6 +1802,12 @@ void pch_gbe_down(struct pch_gbe_adapter *adapter)
pch_gbe_reset(adapter);
pch_gbe_clean_tx_ring(adapter, adapter->tx_ring);
pch_gbe_clean_rx_ring(adapter, adapter->rx_ring);
+
+ pci_free_consistent(adapter->pdev, rx_ring->rx_buff_pool_size,
+ rx_ring->rx_buff_pool, rx_ring->rx_buff_pool_logic);
+ rx_ring->rx_buff_pool_logic = 0;
+ rx_ring->rx_buff_pool_size = 0;
+ rx_ring->rx_buff_pool = NULL;
}
/**
@@ -2004,6 +2060,8 @@ static int pch_gbe_change_mtu(struct net_device *netdev, int new_mtu)
{
struct pch_gbe_adapter *adapter = netdev_priv(netdev);
int max_frame;
+ unsigned long old_rx_buffer_len = adapter->rx_buffer_len;
+ int err;
max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) ||
@@ -2018,14 +2076,24 @@ static int pch_gbe_change_mtu(struct net_device *netdev, int new_mtu)
else if (max_frame <= PCH_GBE_FRAME_SIZE_8192)
adapter->rx_buffer_len = PCH_GBE_FRAME_SIZE_8192;
else
- adapter->rx_buffer_len = PCH_GBE_MAX_JUMBO_FRAME_SIZE;
- netdev->mtu = new_mtu;
- adapter->hw.mac.max_frame_size = max_frame;
+ adapter->rx_buffer_len = PCH_GBE_MAX_RX_BUFFER_SIZE;
- if (netif_running(netdev))
- pch_gbe_reinit_locked(adapter);
- else
+ if (netif_running(netdev)) {
+ pch_gbe_down(adapter);
+ err = pch_gbe_up(adapter);
+ if (err) {
+ adapter->rx_buffer_len = old_rx_buffer_len;
+ pch_gbe_up(adapter);
+ return -ENOMEM;
+ } else {
+ netdev->mtu = new_mtu;
+ adapter->hw.mac.max_frame_size = max_frame;
+ }
+ } else {
pch_gbe_reset(adapter);
+ netdev->mtu = new_mtu;
+ adapter->hw.mac.max_frame_size = max_frame;
+ }
pr_debug("max_frame : %d rx_buffer_len : %d mtu : %d max_frame_size : %d\n",
max_frame, (u32) adapter->rx_buffer_len, netdev->mtu,
@@ -2099,33 +2167,39 @@ static int pch_gbe_napi_poll(struct napi_struct *napi, int budget)
{
struct pch_gbe_adapter *adapter =
container_of(napi, struct pch_gbe_adapter, napi);
- struct net_device *netdev = adapter->netdev;
int work_done = 0;
bool poll_end_flag = false;
bool cleaned = false;
+ u32 int_en;
pr_debug("budget : %d\n", budget);
- /* Keep link state information with original netdev */
- if (!netif_carrier_ok(netdev)) {
- poll_end_flag = true;
- } else {
- cleaned = pch_gbe_clean_tx(adapter, adapter->tx_ring);
- pch_gbe_clean_rx(adapter, adapter->rx_ring, &work_done, budget);
+ pch_gbe_clean_rx(adapter, adapter->rx_ring, &work_done, budget);
+ cleaned = pch_gbe_clean_tx(adapter, adapter->tx_ring);
- if (cleaned)
- work_done = budget;
- /* If no Tx and not enough Rx work done,
- * exit the polling mode
- */
- if ((work_done < budget) || !netif_running(netdev))
- poll_end_flag = true;
- }
+ if (!cleaned)
+ work_done = budget;
+ /* If no Tx and not enough Rx work done,
+ * exit the polling mode
+ */
+ if (work_done < budget)
+ poll_end_flag = true;
if (poll_end_flag) {
napi_complete(napi);
+ if (adapter->rx_stop_flag) {
+ adapter->rx_stop_flag = false;
+ pch_gbe_start_receive(&adapter->hw);
+ }
pch_gbe_irq_enable(adapter);
- }
+ } else
+ if (adapter->rx_stop_flag) {
+ adapter->rx_stop_flag = false;
+ pch_gbe_start_receive(&adapter->hw);
+ int_en = ioread32(&adapter->hw.reg->INT_EN);
+ iowrite32((int_en | PCH_GBE_INT_RX_FIFO_ERR),
+ &adapter->hw.reg->INT_EN);
+ }
pr_debug("poll_end_flag : %d work_done : %d budget : %d\n",
poll_end_flag, work_done, budget);
@@ -2158,7 +2232,7 @@ static const struct net_device_ops pch_gbe_netdev_ops = {
.ndo_change_mtu = pch_gbe_change_mtu,
.ndo_set_features = pch_gbe_set_features,
.ndo_do_ioctl = pch_gbe_ioctl,
- .ndo_set_multicast_list = &pch_gbe_set_multi,
+ .ndo_set_rx_mode = pch_gbe_set_multi,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = pch_gbe_netpoll,
#endif
@@ -2452,6 +2526,13 @@ static DEFINE_PCI_DEVICE_TABLE(pch_gbe_pcidev_id) = {
.class = (PCI_CLASS_NETWORK_ETHERNET << 8),
.class_mask = (0xFFFF00)
},
+ {.vendor = PCI_VENDOR_ID_ROHM,
+ .device = PCI_DEVICE_ID_ROHM_ML7831_GBE,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .class = (PCI_CLASS_NETWORK_ETHERNET << 8),
+ .class_mask = (0xFFFF00)
+ },
/* required last entry */
{0}
};
diff --git a/drivers/net/pch_gbe/pch_gbe_param.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c
index 5b5d90a47e29..5b5d90a47e29 100644
--- a/drivers/net/pch_gbe/pch_gbe_param.c
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c
diff --git a/drivers/net/pch_gbe/pch_gbe_phy.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.c
index 28bb9603d736..28bb9603d736 100644
--- a/drivers/net/pch_gbe/pch_gbe_phy.c
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.c
diff --git a/drivers/net/pch_gbe/pch_gbe_phy.h b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.h
index 03264dc7b5ec..03264dc7b5ec 100644
--- a/drivers/net/pch_gbe/pch_gbe_phy.h
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.h
diff --git a/drivers/net/ethernet/packetengines/Kconfig b/drivers/net/ethernet/packetengines/Kconfig
new file mode 100644
index 000000000000..b97132d9dff0
--- /dev/null
+++ b/drivers/net/ethernet/packetengines/Kconfig
@@ -0,0 +1,47 @@
+#
+# Packet engine device configuration
+#
+
+config NET_PACKET_ENGINE
+ bool "Packet Engine devices"
+ depends on PCI
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about packet engine devices. If you say Y, you will
+ be asked for your specific card in the following questions.
+
+if NET_PACKET_ENGINE
+
+config HAMACHI
+ tristate "Packet Engines Hamachi GNIC-II support"
+ depends on PCI
+ select NET_CORE
+ select MII
+ ---help---
+ If you have a Gigabit Ethernet card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module will be
+ called hamachi.
+
+config YELLOWFIN
+ tristate "Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)"
+ depends on PCI && EXPERIMENTAL
+ select CRC32
+ ---help---
+ Say Y here if you have a Packet Engines G-NIC PCI Gigabit Ethernet
+ adapter or the SYM53C885 Ethernet controller. The Gigabit adapter is
+ used by the Beowulf Linux cluster project. See
+ <http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html> for more
+ information about this driver in particular and Beowulf in general.
+
+ To compile this driver as a module, choose M here: the module
+ will be called yellowfin. This is recommended.
+
+endif # NET_PACKET_ENGINE
diff --git a/drivers/net/ethernet/packetengines/Makefile b/drivers/net/ethernet/packetengines/Makefile
new file mode 100644
index 000000000000..995ccd077d0c
--- /dev/null
+++ b/drivers/net/ethernet/packetengines/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the Packet Engine network device drivers.
+#
+
+obj-$(CONFIG_HAMACHI) += hamachi.o
+obj-$(CONFIG_YELLOWFIN) += yellowfin.o
diff --git a/drivers/net/hamachi.c b/drivers/net/ethernet/packetengines/hamachi.c
index c274b3d77eb5..3458df3780b8 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/ethernet/packetengines/hamachi.c
@@ -567,7 +567,7 @@ static const struct net_device_ops hamachi_netdev_ops = {
.ndo_stop = hamachi_close,
.ndo_start_xmit = hamachi_start_xmit,
.ndo_get_stats = hamachi_get_stats,
- .ndo_set_multicast_list = set_rx_mode,
+ .ndo_set_rx_mode = set_rx_mode,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/yellowfin.c b/drivers/net/ethernet/packetengines/yellowfin.c
index 3e5ac60b89ac..db44e9af03c3 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/ethernet/packetengines/yellowfin.c
@@ -359,7 +359,7 @@ static const struct net_device_ops netdev_ops = {
.ndo_open = yellowfin_open,
.ndo_stop = yellowfin_close,
.ndo_start_xmit = yellowfin_start_xmit,
- .ndo_set_multicast_list = set_rx_mode,
+ .ndo_set_rx_mode = set_rx_mode,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/ethernet/pasemi/Kconfig b/drivers/net/ethernet/pasemi/Kconfig
new file mode 100644
index 000000000000..01e6c329d78c
--- /dev/null
+++ b/drivers/net/ethernet/pasemi/Kconfig
@@ -0,0 +1,30 @@
+#
+# PA Semi network device configuration
+#
+
+config NET_VENDOR_PASEMI
+ bool "PA Semi devices"
+ default y
+ depends on PPC_PASEMI && PCI && INET
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about PA Semi cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_PASEMI
+
+config PASEMI_MAC
+ tristate "PA Semi 1/10Gbit MAC"
+ depends on PPC_PASEMI && PCI && INET
+ select PHYLIB
+ select INET_LRO
+ ---help---
+ This driver supports the on-chip 1/10Gbit Ethernet controller on
+ PA Semi's PWRficient line of chips.
+
+endif # NET_VENDOR_PASEMI
diff --git a/drivers/net/ethernet/pasemi/Makefile b/drivers/net/ethernet/pasemi/Makefile
new file mode 100644
index 000000000000..05db5434bafc
--- /dev/null
+++ b/drivers/net/ethernet/pasemi/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the A Semi network device drivers.
+#
+
+obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o pasemi_mac_ethtool.o
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/ethernet/pasemi/pasemi_mac.c
index 9ec112ca62e4..49b549ff2c78 100644
--- a/drivers/net/pasemi_mac.c
+++ b/drivers/net/ethernet/pasemi/pasemi_mac.c
@@ -300,9 +300,9 @@ static int pasemi_mac_unmap_tx_skb(struct pasemi_mac *mac,
pci_unmap_single(pdev, dmas[0], skb_headlen(skb), PCI_DMA_TODEVICE);
for (f = 0; f < nfrags; f++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[f];
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[f];
- pci_unmap_page(pdev, dmas[f+1], frag->size, PCI_DMA_TODEVICE);
+ pci_unmap_page(pdev, dmas[f+1], skb_frag_size(frag), PCI_DMA_TODEVICE);
}
dev_kfree_skb_irq(skb);
@@ -1505,11 +1505,10 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev)
for (i = 0; i < nfrags; i++) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- map[i+1] = pci_map_page(mac->dma_pdev, frag->page,
- frag->page_offset, frag->size,
- PCI_DMA_TODEVICE);
- map_size[i+1] = frag->size;
- if (pci_dma_mapping_error(mac->dma_pdev, map[i+1])) {
+ map[i + 1] = skb_frag_dma_map(&mac->dma_pdev->dev, frag, 0,
+ skb_frag_size(frag), DMA_TO_DEVICE);
+ map_size[i+1] = skb_frag_size(frag);
+ if (dma_mapping_error(&mac->dma_pdev->dev, map[i + 1])) {
nfrags = i;
goto out_err_nolock;
}
@@ -1719,7 +1718,7 @@ static const struct net_device_ops pasemi_netdev_ops = {
.ndo_open = pasemi_mac_open,
.ndo_stop = pasemi_mac_close,
.ndo_start_xmit = pasemi_mac_start_tx,
- .ndo_set_multicast_list = pasemi_mac_set_rx_mode,
+ .ndo_set_rx_mode = pasemi_mac_set_rx_mode,
.ndo_set_mac_address = pasemi_mac_set_mac_addr,
.ndo_change_mtu = pasemi_mac_change_mtu,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/pasemi_mac.h b/drivers/net/ethernet/pasemi/pasemi_mac.h
index e2f4efa8ad46..e2f4efa8ad46 100644
--- a/drivers/net/pasemi_mac.h
+++ b/drivers/net/ethernet/pasemi/pasemi_mac.h
diff --git a/drivers/net/pasemi_mac_ethtool.c b/drivers/net/ethernet/pasemi/pasemi_mac_ethtool.c
index 4825959a0efe..4825959a0efe 100644
--- a/drivers/net/pasemi_mac_ethtool.c
+++ b/drivers/net/ethernet/pasemi/pasemi_mac_ethtool.c
diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig
new file mode 100644
index 000000000000..a8669adecc97
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/Kconfig
@@ -0,0 +1,54 @@
+#
+# QLogic network device configuration
+#
+
+config NET_VENDOR_QLOGIC
+ bool "QLogic devices"
+ default y
+ depends on PCI
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about QLogic cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_QLOGIC
+
+config QLA3XXX
+ tristate "QLogic QLA3XXX Network Driver Support"
+ depends on PCI
+ ---help---
+ This driver supports QLogic ISP3XXX gigabit Ethernet cards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called qla3xxx.
+
+config QLCNIC
+ tristate "QLOGIC QLCNIC 1/10Gb Converged Ethernet NIC Support"
+ depends on PCI
+ select FW_LOADER
+ ---help---
+ This driver supports QLogic QLE8240 and QLE8242 Converged Ethernet
+ devices.
+
+config QLGE
+ tristate "QLogic QLGE 10Gb Ethernet Driver Support"
+ depends on PCI
+ ---help---
+ This driver supports QLogic ISP8XXX 10Gb Ethernet cards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called qlge.
+
+config NETXEN_NIC
+ tristate "NetXen Multi port (1/10) Gigabit Ethernet NIC"
+ depends on PCI
+ select FW_LOADER
+ ---help---
+ This enables the support for NetXen's Gigabit Ethernet card.
+
+endif # NET_VENDOR_QLOGIC
diff --git a/drivers/net/ethernet/qlogic/Makefile b/drivers/net/ethernet/qlogic/Makefile
new file mode 100644
index 000000000000..b2a283d9ae60
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the QLogic network device drivers.
+#
+
+obj-$(CONFIG_QLA3XXX) += qla3xxx.o
+obj-$(CONFIG_QLCNIC) += qlcnic/
+obj-$(CONFIG_QLGE) += qlge/
+obj-$(CONFIG_NETXEN_NIC) += netxen/
diff --git a/drivers/net/netxen/Makefile b/drivers/net/ethernet/qlogic/netxen/Makefile
index 861a0590b1f4..861a0590b1f4 100644
--- a/drivers/net/netxen/Makefile
+++ b/drivers/net/ethernet/qlogic/netxen/Makefile
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/ethernet/qlogic/netxen/netxen_nic.h
index f744d291218a..a876dffd7101 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic.h
@@ -53,8 +53,8 @@
#define _NETXEN_NIC_LINUX_MAJOR 4
#define _NETXEN_NIC_LINUX_MINOR 0
-#define _NETXEN_NIC_LINUX_SUBVERSION 76
-#define NETXEN_NIC_LINUX_VERSIONID "4.0.76"
+#define _NETXEN_NIC_LINUX_SUBVERSION 77
+#define NETXEN_NIC_LINUX_VERSIONID "4.0.77"
#define NETXEN_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c))
#define _major(v) (((v) >> 24) & 0xff)
@@ -940,6 +940,11 @@ typedef struct nx_mac_list_s {
uint8_t mac_addr[ETH_ALEN+2];
} nx_mac_list_t;
+struct nx_vlan_ip_list {
+ struct list_head list;
+ u32 ip_addr;
+};
+
/*
* Interrupt coalescing defaults. The defaults are for 1500 MTU. It is
* adjusted based on configured MTU.
@@ -1165,6 +1170,7 @@ struct netxen_adapter {
struct net_device *netdev;
struct pci_dev *pdev;
struct list_head mac_list;
+ struct list_head vlan_ip_list;
spinlock_t tx_clean_lock;
diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
index a925392abd6f..a925392abd6f 100644
--- a/drivers/net/netxen/netxen_nic_ctx.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c
index b34fb74d07e3..e09ea83b8c47 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c
@@ -413,9 +413,6 @@ netxen_nic_get_ringparam(struct net_device *dev,
}
ring->tx_max_pending = MAX_CMD_DESCRIPTORS;
-
- ring->rx_mini_max_pending = 0;
- ring->rx_mini_pending = 0;
}
static u32
diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h
index dc1967c1f312..dc1967c1f312 100644
--- a/drivers/net/netxen/netxen_nic_hdr.h
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c
index 3f89e57cae50..3f89e57cae50 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c
diff --git a/drivers/net/netxen/netxen_nic_hw.h b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.h
index e2c5b6f2df03..e2c5b6f2df03 100644
--- a/drivers/net/netxen/netxen_nic_hw.h
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.h
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
index e8993a76a080..a8259cc19a63 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
@@ -26,6 +26,7 @@
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/if_vlan.h>
#include "netxen_nic.h"
#include "netxen_nic_hw.h"
@@ -1619,6 +1620,7 @@ netxen_process_lro(struct netxen_adapter *adapter,
int index;
u16 lro_length, length, data_offset;
u32 seq_number;
+ u8 vhdr_len = 0;
if (unlikely(ring > adapter->max_rds_rings))
return NULL;
@@ -1652,8 +1654,10 @@ netxen_process_lro(struct netxen_adapter *adapter,
skb_pull(skb, l2_hdr_offset);
skb->protocol = eth_type_trans(skb, netdev);
- iph = (struct iphdr *)skb->data;
- th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
+ if (skb->protocol == htons(ETH_P_8021Q))
+ vhdr_len = VLAN_HLEN;
+ iph = (struct iphdr *)(skb->data + vhdr_len);
+ th = (struct tcphdr *)((skb->data + vhdr_len) + (iph->ihl << 2));
length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
iph->tot_len = htons(length);
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
index f574edff7fcb..8cf3173ba488 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
@@ -91,7 +91,8 @@ static irqreturn_t netxen_intr(int irq, void *data);
static irqreturn_t netxen_msi_intr(int irq, void *data);
static irqreturn_t netxen_msix_intr(int irq, void *data);
-static void netxen_config_indev_addr(struct net_device *dev, unsigned long);
+static void netxen_free_vlan_ip_list(struct netxen_adapter *);
+static void netxen_restore_indev_addr(struct net_device *dev, unsigned long);
static struct rtnl_link_stats64 *netxen_nic_get_stats(struct net_device *dev,
struct rtnl_link_stats64 *stats);
static int netxen_nic_set_mac(struct net_device *netdev, void *p);
@@ -399,6 +400,63 @@ static void netxen_set_port_mode(struct netxen_adapter *adapter)
}
}
+#define PCI_CAP_ID_GEN 0x10
+
+static void netxen_pcie_strap_init(struct netxen_adapter *adapter)
+{
+ u32 pdevfuncsave;
+ u32 c8c9value = 0;
+ u32 chicken = 0;
+ u32 control = 0;
+ int i, pos;
+ struct pci_dev *pdev;
+
+ pdev = adapter->pdev;
+
+ chicken = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_CHICKEN3));
+ /* clear chicken3.25:24 */
+ chicken &= 0xFCFFFFFF;
+ /*
+ * if gen1 and B0, set F1020 - if gen 2, do nothing
+ * if gen2 set to F1000
+ */
+ pos = pci_find_capability(pdev, PCI_CAP_ID_GEN);
+ if (pos == 0xC0) {
+ pci_read_config_dword(pdev, pos + 0x10, &control);
+ if ((control & 0x000F0000) != 0x00020000) {
+ /* set chicken3.24 if gen1 */
+ chicken |= 0x01000000;
+ }
+ dev_info(&adapter->pdev->dev, "Gen2 strapping detected\n");
+ c8c9value = 0xF1000;
+ } else {
+ /* set chicken3.24 if gen1 */
+ chicken |= 0x01000000;
+ dev_info(&adapter->pdev->dev, "Gen1 strapping detected\n");
+ if (adapter->ahw.revision_id == NX_P3_B0)
+ c8c9value = 0xF1020;
+ else
+ c8c9value = 0;
+ }
+
+ NXWR32(adapter, NETXEN_PCIE_REG(PCIE_CHICKEN3), chicken);
+
+ if (!c8c9value)
+ return;
+
+ pdevfuncsave = pdev->devfn;
+ if (pdevfuncsave & 0x07)
+ return;
+
+ for (i = 0; i < 8; i++) {
+ pci_read_config_dword(pdev, pos + 8, &control);
+ pci_read_config_dword(pdev, pos + 8, &control);
+ pci_write_config_dword(pdev, pos + 8, c8c9value);
+ pdev->devfn++;
+ }
+ pdev->devfn = pdevfuncsave;
+}
+
static void netxen_set_msix_bit(struct pci_dev *pdev, int enable)
{
u32 control;
@@ -523,7 +581,7 @@ static const struct net_device_ops netxen_netdev_ops = {
.ndo_start_xmit = netxen_nic_xmit_frame,
.ndo_get_stats64 = netxen_nic_get_stats,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = netxen_set_multicast_list,
+ .ndo_set_rx_mode = netxen_set_multicast_list,
.ndo_set_mac_address = netxen_nic_set_mac,
.ndo_change_mtu = netxen_nic_change_mtu,
.ndo_tx_timeout = netxen_tx_timeout,
@@ -866,7 +924,7 @@ netxen_start_firmware(struct netxen_adapter *adapter)
if (err < 0)
goto err_out;
if (err == 0)
- goto wait_init;
+ goto pcie_strap_init;
if (first_boot != 0x55555555) {
NXWR32(adapter, CRB_CMDPEG_STATE, 0);
@@ -909,6 +967,10 @@ netxen_start_firmware(struct netxen_adapter *adapter)
| (_NETXEN_NIC_LINUX_SUBVERSION);
NXWR32(adapter, CRB_DRIVER_VERSION, val);
+pcie_strap_init:
+ if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+ netxen_pcie_strap_init(adapter);
+
wait_init:
/* Handshake with the card before we register the devices. */
err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
@@ -1359,6 +1421,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
spin_lock_init(&adapter->tx_clean_lock);
INIT_LIST_HEAD(&adapter->mac_list);
+ INIT_LIST_HEAD(&adapter->vlan_ip_list);
err = netxen_setup_pci_map(adapter);
if (err)
@@ -1481,6 +1544,7 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
cancel_work_sync(&adapter->tx_timeout_task);
+ netxen_free_vlan_ip_list(adapter);
netxen_nic_detach(adapter);
nx_decr_dev_ref_cnt(adapter);
@@ -1563,7 +1627,7 @@ static int netxen_nic_attach_func(struct pci_dev *pdev)
if (err)
goto err_out_detach;
- netxen_config_indev_addr(netdev, NETDEV_UP);
+ netxen_restore_indev_addr(netdev, NETDEV_UP);
}
netif_device_attach(netdev);
@@ -1841,13 +1905,13 @@ netxen_map_tx_skb(struct pci_dev *pdev,
frag = &skb_shinfo(skb)->frags[i];
nf = &pbuf->frag_array[i+1];
- map = pci_map_page(pdev, frag->page, frag->page_offset,
- frag->size, PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(pdev, map))
+ map = skb_frag_dma_map(&pdev->dev, frag, 0, skb_frag_size(frag),
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(&pdev->dev, map))
goto unwind;
nf->dma = map;
- nf->length = frag->size;
+ nf->length = skb_frag_size(frag);
}
return 0;
@@ -1898,7 +1962,7 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
for (i = 0; i < (frag_count - NETXEN_MAX_FRAGS_PER_TX); i++) {
frag = &skb_shinfo(skb)->frags[i];
- delta += frag->size;
+ delta += skb_frag_size(frag);
}
if (!__pskb_pull_tail(skb, delta))
@@ -2374,7 +2438,7 @@ netxen_attach_work(struct work_struct *work)
goto done;
}
- netxen_config_indev_addr(netdev, NETDEV_UP);
+ netxen_restore_indev_addr(netdev, NETDEV_UP);
}
netif_device_attach(netdev);
@@ -2848,10 +2912,70 @@ netxen_destip_supported(struct netxen_adapter *adapter)
}
static void
-netxen_config_indev_addr(struct net_device *dev, unsigned long event)
+netxen_free_vlan_ip_list(struct netxen_adapter *adapter)
+{
+ struct nx_vlan_ip_list *cur;
+ struct list_head *head = &adapter->vlan_ip_list;
+
+ while (!list_empty(head)) {
+ cur = list_entry(head->next, struct nx_vlan_ip_list, list);
+ netxen_config_ipaddr(adapter, cur->ip_addr, NX_IP_DOWN);
+ list_del(&cur->list);
+ kfree(cur);
+ }
+
+}
+static void
+netxen_list_config_vlan_ip(struct netxen_adapter *adapter,
+ struct in_ifaddr *ifa, unsigned long event)
+{
+ struct net_device *dev;
+ struct nx_vlan_ip_list *cur, *tmp_cur;
+ struct list_head *head;
+
+ dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL;
+
+ if (dev == NULL)
+ return;
+
+ if (!is_vlan_dev(dev))
+ return;
+
+ switch (event) {
+ case NX_IP_UP:
+ list_for_each(head, &adapter->vlan_ip_list) {
+ cur = list_entry(head, struct nx_vlan_ip_list, list);
+
+ if (cur->ip_addr == ifa->ifa_address)
+ return;
+ }
+
+ cur = kzalloc(sizeof(struct nx_vlan_ip_list), GFP_ATOMIC);
+ if (cur == NULL) {
+ printk(KERN_ERR "%s: failed to add vlan ip to list\n",
+ adapter->netdev->name);
+ return;
+ }
+
+ cur->ip_addr = ifa->ifa_address;
+ list_add_tail(&cur->list, &adapter->vlan_ip_list);
+ break;
+ case NX_IP_DOWN:
+ list_for_each_entry_safe(cur, tmp_cur,
+ &adapter->vlan_ip_list, list) {
+ if (cur->ip_addr == ifa->ifa_address) {
+ list_del(&cur->list);
+ kfree(cur);
+ break;
+ }
+ }
+ }
+}
+static void
+netxen_config_indev_addr(struct netxen_adapter *adapter,
+ struct net_device *dev, unsigned long event)
{
struct in_device *indev;
- struct netxen_adapter *adapter = netdev_priv(dev);
if (!netxen_destip_supported(adapter))
return;
@@ -2865,10 +2989,12 @@ netxen_config_indev_addr(struct net_device *dev, unsigned long event)
case NETDEV_UP:
netxen_config_ipaddr(adapter,
ifa->ifa_address, NX_IP_UP);
+ netxen_list_config_vlan_ip(adapter, ifa, NX_IP_UP);
break;
case NETDEV_DOWN:
netxen_config_ipaddr(adapter,
ifa->ifa_address, NX_IP_DOWN);
+ netxen_list_config_vlan_ip(adapter, ifa, NX_IP_DOWN);
break;
default:
break;
@@ -2878,11 +3004,28 @@ netxen_config_indev_addr(struct net_device *dev, unsigned long event)
in_dev_put(indev);
}
+static void
+netxen_restore_indev_addr(struct net_device *netdev, unsigned long event)
+
+{
+ struct netxen_adapter *adapter = netdev_priv(netdev);
+ struct nx_vlan_ip_list *pos, *tmp_pos;
+ unsigned long ip_event;
+
+ ip_event = (event == NETDEV_UP) ? NX_IP_UP : NX_IP_DOWN;
+ netxen_config_indev_addr(adapter, netdev, event);
+
+ list_for_each_entry_safe(pos, tmp_pos, &adapter->vlan_ip_list, list) {
+ netxen_config_ipaddr(adapter, pos->ip_addr, ip_event);
+ }
+}
+
static int netxen_netdev_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct netxen_adapter *adapter;
struct net_device *dev = (struct net_device *)ptr;
+ struct net_device *orig_dev = dev;
recheck:
if (dev == NULL)
@@ -2904,7 +3047,7 @@ recheck:
if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
goto done;
- netxen_config_indev_addr(dev, event);
+ netxen_config_indev_addr(adapter, orig_dev, event);
done:
return NOTIFY_DONE;
}
@@ -2921,7 +3064,7 @@ netxen_inetaddr_event(struct notifier_block *this,
dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL;
recheck:
- if (dev == NULL || !netif_running(dev))
+ if (dev == NULL)
goto done;
if (dev->priv_flags & IFF_802_1Q_VLAN) {
@@ -2943,9 +3086,11 @@ recheck:
switch (event) {
case NETDEV_UP:
netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_UP);
+ netxen_list_config_vlan_ip(adapter, ifa, NX_IP_UP);
break;
case NETDEV_DOWN:
netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_DOWN);
+ netxen_list_config_vlan_ip(adapter, ifa, NX_IP_DOWN);
break;
default:
break;
@@ -2964,7 +3109,10 @@ static struct notifier_block netxen_inetaddr_cb = {
};
#else
static void
-netxen_config_indev_addr(struct net_device *dev, unsigned long event)
+netxen_restore_indev_addr(struct net_device *dev, unsigned long event)
+{ }
+static void
+netxen_free_vlan_ip_list(struct netxen_adapter *adapter)
{ }
#endif
diff --git a/drivers/net/qla3xxx.c b/drivers/net/ethernet/qlogic/qla3xxx.c
index 2f6914025efc..a4bdff438a5e 100644
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/ethernet/qlogic/qla3xxx.c
@@ -1650,7 +1650,7 @@ static int ql_mii_setup(struct ql3_adapter *qdev)
SUPPORTED_1000baseT_Half | \
SUPPORTED_1000baseT_Full | \
SUPPORTED_Autoneg | \
- SUPPORTED_TP); \
+ SUPPORTED_TP) \
static u32 ql_supported_modes(struct ql3_adapter *qdev)
{
@@ -2388,11 +2388,10 @@ static int ql_send_map(struct ql3_adapter *qdev,
seg++;
}
- map = pci_map_page(qdev->pdev, frag->page,
- frag->page_offset, frag->size,
- PCI_DMA_TODEVICE);
+ map = skb_frag_dma_map(&qdev->pdev->dev, frag, 0, skb_frag_size(frag),
+ DMA_TO_DEVICE);
- err = pci_dma_mapping_error(qdev->pdev, map);
+ err = dma_mapping_error(&qdev->pdev->dev, map);
if (err) {
netdev_err(qdev->ndev,
"PCI mapping frags failed with error: %d\n",
@@ -2402,9 +2401,9 @@ static int ql_send_map(struct ql3_adapter *qdev,
oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
- oal_entry->len = cpu_to_le32(frag->size);
+ oal_entry->len = cpu_to_le32(skb_frag_size(frag));
dma_unmap_addr_set(&tx_cb->map[seg], mapaddr, map);
- dma_unmap_len_set(&tx_cb->map[seg], maplen, frag->size);
+ dma_unmap_len_set(&tx_cb->map[seg], maplen, skb_frag_size(frag));
}
/* Terminate the last segment. */
oal_entry->len |= cpu_to_le32(OAL_LAST_ENTRY);
@@ -3762,7 +3761,6 @@ static const struct net_device_ops ql3xxx_netdev_ops = {
.ndo_open = ql3xxx_open,
.ndo_start_xmit = ql3xxx_send,
.ndo_stop = ql3xxx_close,
- .ndo_set_multicast_list = NULL, /* not allowed on NIC side */
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = ql3xxx_set_mac_address,
diff --git a/drivers/net/qla3xxx.h b/drivers/net/ethernet/qlogic/qla3xxx.h
index 73e234366a82..73e234366a82 100644
--- a/drivers/net/qla3xxx.h
+++ b/drivers/net/ethernet/qlogic/qla3xxx.h
diff --git a/drivers/net/qlcnic/Makefile b/drivers/net/ethernet/qlogic/qlcnic/Makefile
index ddba83ef3f44..ddba83ef3f44 100644
--- a/drivers/net/qlcnic/Makefile
+++ b/drivers/net/ethernet/qlogic/qlcnic/Makefile
diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index baf646d98fa0..2fd1ba8fee4a 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -36,8 +36,8 @@
#define _QLCNIC_LINUX_MAJOR 5
#define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 21
-#define QLCNIC_LINUX_VERSIONID "5.0.21"
+#define _QLCNIC_LINUX_SUBVERSION 24
+#define QLCNIC_LINUX_VERSIONID "5.0.24"
#define QLCNIC_DRV_IDC_VER 0x01
#define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\
(_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
@@ -73,6 +73,7 @@
(sizeof(struct cmd_desc_type0) * tx_ring->num_desc)
#define QLCNIC_P3P_A0 0x50
+#define QLCNIC_P3P_C0 0x58
#define QLCNIC_IS_REVISION_P3P(REVISION) (REVISION >= QLCNIC_P3P_A0)
@@ -291,7 +292,8 @@ struct uni_data_desc{
/* Flash Defines and Structures */
#define QLCNIC_FLT_LOCATION 0x3F1000
-#define QLCNIC_FW_IMAGE_REGION 0x74
+#define QLCNIC_B0_FW_IMAGE_REGION 0x74
+#define QLCNIC_C0_FW_IMAGE_REGION 0x97
#define QLCNIC_BOOTLD_REGION 0X72
struct qlcnic_flt_header {
u16 version;
@@ -455,6 +457,8 @@ struct qlcnic_hardware_context {
u16 port_type;
u16 board_type;
+ u8 beacon_state;
+
struct qlcnic_nic_intr_coalesce coal;
struct qlcnic_fw_dump fw_dump;
};
@@ -579,6 +583,7 @@ struct qlcnic_recv_context {
#define QLCNIC_CDRP_CMD_DESTROY_RX_CTX 0x00000008
#define QLCNIC_CDRP_CMD_CREATE_TX_CTX 0x00000009
#define QLCNIC_CDRP_CMD_DESTROY_TX_CTX 0x0000000a
+#define QLCNIC_CDRP_CMD_INTRPT_TEST 0x00000011
#define QLCNIC_CDRP_CMD_SET_MTU 0x00000012
#define QLCNIC_CDRP_CMD_READ_PHY 0x00000013
#define QLCNIC_CDRP_CMD_WRITE_PHY 0x00000014
@@ -911,6 +916,7 @@ struct qlcnic_ipaddr {
#define QLCNIC_PROMISC_DISABLED 0x800
#define QLCNIC_NEED_FLR 0x1000
#define QLCNIC_FW_RESET_OWNER 0x2000
+#define QLCNIC_FW_HANG 0x4000
#define QLCNIC_IS_MSI_FAMILY(adapter) \
((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
@@ -928,6 +934,7 @@ struct qlcnic_ipaddr {
#define __QLCNIC_START_FW 4
#define __QLCNIC_AER 5
#define __QLCNIC_DIAG_RES_ALLOC 6
+#define __QLCNIC_LED_ENABLE 7
#define QLCNIC_INTERRUPT_TEST 1
#define QLCNIC_LOOPBACK_TEST 2
@@ -1344,6 +1351,7 @@ enum op_codes {
#define QLCNIC_FORCE_FW_DUMP_KEY 0xdeadfeed
#define QLCNIC_ENABLE_FW_DUMP 0xaddfeed
#define QLCNIC_DISABLE_FW_DUMP 0xbadfeed
+#define QLCNIC_FORCE_FW_RESET 0xdeaddead
struct qlcnic_dump_operations {
enum op_codes opcode;
@@ -1351,6 +1359,18 @@ struct qlcnic_dump_operations {
struct qlcnic_dump_entry *, u32 *);
};
+struct _cdrp_cmd {
+ u32 cmd;
+ u32 arg1;
+ u32 arg2;
+ u32 arg3;
+};
+
+struct qlcnic_cmd_args {
+ struct _cdrp_cmd req;
+ struct _cdrp_cmd rsp;
+};
+
int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter);
int qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config);
@@ -1393,6 +1413,9 @@ void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int);
#define crb_win_unlock(a) \
qlcnic_pcie_sem_unlock((a), 7)
+#define __QLCNIC_MAX_LED_RATE 0xf
+#define __QLCNIC_MAX_LED_STATE 0x2
+
int qlcnic_get_board_info(struct qlcnic_adapter *adapter);
int qlcnic_wol_supported(struct qlcnic_adapter *adapter);
int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate);
@@ -1460,8 +1483,7 @@ int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[]);
/* Functions from qlcnic_main.c */
int qlcnic_reset_context(struct qlcnic_adapter *);
-u32 qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
- u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd);
+void qlcnic_issue_cmd(struct qlcnic_adapter *adapter, struct qlcnic_cmd_args *);
void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings);
int qlcnic_diag_alloc_res(struct net_device *netdev, int test);
netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
index b0d32ddd2ccb..569a837d2ac4 100644
--- a/drivers/net/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
@@ -26,42 +26,54 @@ qlcnic_poll_rsp(struct qlcnic_adapter *adapter)
return rsp;
}
-u32
-qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
- u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd)
+void
+qlcnic_issue_cmd(struct qlcnic_adapter *adapter, struct qlcnic_cmd_args *cmd)
{
u32 rsp;
u32 signature;
- u32 rcode = QLCNIC_RCODE_SUCCESS;
struct pci_dev *pdev = adapter->pdev;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
- signature = QLCNIC_CDRP_SIGNATURE_MAKE(pci_fn, version);
+ signature = QLCNIC_CDRP_SIGNATURE_MAKE(ahw->pci_func,
+ adapter->fw_hal_version);
/* Acquire semaphore before accessing CRB */
- if (qlcnic_api_lock(adapter))
- return QLCNIC_RCODE_TIMEOUT;
+ if (qlcnic_api_lock(adapter)) {
+ cmd->rsp.cmd = QLCNIC_RCODE_TIMEOUT;
+ return;
+ }
QLCWR32(adapter, QLCNIC_SIGN_CRB_OFFSET, signature);
- QLCWR32(adapter, QLCNIC_ARG1_CRB_OFFSET, arg1);
- QLCWR32(adapter, QLCNIC_ARG2_CRB_OFFSET, arg2);
- QLCWR32(adapter, QLCNIC_ARG3_CRB_OFFSET, arg3);
- QLCWR32(adapter, QLCNIC_CDRP_CRB_OFFSET, QLCNIC_CDRP_FORM_CMD(cmd));
+ QLCWR32(adapter, QLCNIC_ARG1_CRB_OFFSET, cmd->req.arg1);
+ QLCWR32(adapter, QLCNIC_ARG2_CRB_OFFSET, cmd->req.arg2);
+ QLCWR32(adapter, QLCNIC_ARG3_CRB_OFFSET, cmd->req.arg3);
+ QLCWR32(adapter, QLCNIC_CDRP_CRB_OFFSET,
+ QLCNIC_CDRP_FORM_CMD(cmd->req.cmd));
rsp = qlcnic_poll_rsp(adapter);
if (rsp == QLCNIC_CDRP_RSP_TIMEOUT) {
dev_err(&pdev->dev, "card response timeout.\n");
- rcode = QLCNIC_RCODE_TIMEOUT;
+ cmd->rsp.cmd = QLCNIC_RCODE_TIMEOUT;
} else if (rsp == QLCNIC_CDRP_RSP_FAIL) {
- rcode = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
+ cmd->rsp.cmd = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
dev_err(&pdev->dev, "failed card response code:0x%x\n",
- rcode);
+ cmd->rsp.cmd);
+ } else if (rsp == QLCNIC_CDRP_RSP_OK) {
+ cmd->rsp.cmd = QLCNIC_RCODE_SUCCESS;
+ if (cmd->rsp.arg2)
+ cmd->rsp.arg2 = QLCRD32(adapter,
+ QLCNIC_ARG2_CRB_OFFSET);
+ if (cmd->rsp.arg3)
+ cmd->rsp.arg3 = QLCRD32(adapter,
+ QLCNIC_ARG3_CRB_OFFSET);
}
+ if (cmd->rsp.arg1)
+ cmd->rsp.arg1 = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
/* Release semaphore */
qlcnic_api_unlock(adapter);
- return rcode;
}
static uint32_t qlcnic_temp_checksum(uint32_t *temp_buffer, u16 temp_size)
@@ -81,27 +93,24 @@ int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
u16 temp_size;
void *tmp_addr;
u32 version, csum, *template, *tmp_buf;
+ struct qlcnic_cmd_args cmd;
struct qlcnic_hardware_context *ahw;
struct qlcnic_dump_template_hdr *tmpl_hdr, *tmp_tmpl;
dma_addr_t tmp_addr_t = 0;
ahw = adapter->ahw;
- err = qlcnic_issue_cmd(adapter,
- adapter->ahw->pci_func,
- adapter->fw_hal_version,
- 0,
- 0,
- 0,
- QLCNIC_CDRP_CMD_TEMP_SIZE);
- if (err != QLCNIC_RCODE_SUCCESS) {
- err = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.req.cmd = QLCNIC_CDRP_CMD_TEMP_SIZE;
+ memset(&cmd.rsp, 1, sizeof(struct _cdrp_cmd));
+ qlcnic_issue_cmd(adapter, &cmd);
+ if (cmd.rsp.cmd != QLCNIC_RCODE_SUCCESS) {
dev_info(&adapter->pdev->dev,
- "Can't get template size %d\n", err);
+ "Can't get template size %d\n", cmd.rsp.cmd);
err = -EIO;
return err;
}
- version = QLCRD32(adapter, QLCNIC_ARG3_CRB_OFFSET);
- temp_size = QLCRD32(adapter, QLCNIC_ARG2_CRB_OFFSET);
+ temp_size = cmd.rsp.arg2;
+ version = cmd.rsp.arg3;
if (!temp_size)
return -EIO;
@@ -112,14 +121,14 @@ int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
"Can't get memory for FW dump template\n");
return -ENOMEM;
}
- err = qlcnic_issue_cmd(adapter,
- adapter->ahw->pci_func,
- adapter->fw_hal_version,
- LSD(tmp_addr_t),
- MSD(tmp_addr_t),
- temp_size,
- QLCNIC_CDRP_CMD_GET_TEMP_HDR);
-
+ memset(&cmd.rsp, 0, sizeof(struct _cdrp_cmd));
+ cmd.req.cmd = QLCNIC_CDRP_CMD_GET_TEMP_HDR;
+ cmd.req.arg1 = LSD(tmp_addr_t);
+ cmd.req.arg2 = MSD(tmp_addr_t);
+ cmd.req.arg3 = temp_size;
+ qlcnic_issue_cmd(adapter, &cmd);
+
+ err = cmd.rsp.cmd;
if (err != QLCNIC_RCODE_SUCCESS) {
dev_err(&adapter->pdev->dev,
"Failed to get mini dump template header %d\n", err);
@@ -155,17 +164,17 @@ error:
int
qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu)
{
+ struct qlcnic_cmd_args cmd;
struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.req.cmd = QLCNIC_CDRP_CMD_SET_MTU;
+ cmd.req.arg1 = recv_ctx->context_id;
+ cmd.req.arg2 = mtu;
+ cmd.req.arg3 = 0;
if (recv_ctx->state == QLCNIC_HOST_CTX_STATE_ACTIVE) {
- if (qlcnic_issue_cmd(adapter,
- adapter->ahw->pci_func,
- adapter->fw_hal_version,
- recv_ctx->context_id,
- mtu,
- 0,
- QLCNIC_CDRP_CMD_SET_MTU)) {
-
+ qlcnic_issue_cmd(adapter, &cmd);
+ if (cmd.rsp.cmd) {
dev_err(&adapter->pdev->dev, "Failed to set mtu\n");
return -EIO;
}
@@ -186,6 +195,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
struct qlcnic_cardrsp_sds_ring *prsp_sds;
struct qlcnic_host_rds_ring *rds_ring;
struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_cmd_args cmd;
dma_addr_t hostrq_phys_addr, cardrsp_phys_addr;
u64 phys_addr;
@@ -274,13 +284,13 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
}
phys_addr = hostrq_phys_addr;
- err = qlcnic_issue_cmd(adapter,
- adapter->ahw->pci_func,
- adapter->fw_hal_version,
- (u32)(phys_addr >> 32),
- (u32)(phys_addr & 0xffffffff),
- rq_size,
- QLCNIC_CDRP_CMD_CREATE_RX_CTX);
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.req.arg1 = (u32) (phys_addr >> 32);
+ cmd.req.arg2 = (u32) (phys_addr & 0xffffffff);
+ cmd.req.arg3 = rq_size;
+ cmd.req.cmd = QLCNIC_CDRP_CMD_CREATE_RX_CTX;
+ qlcnic_issue_cmd(adapter, &cmd);
+ err = cmd.rsp.cmd;
if (err) {
dev_err(&adapter->pdev->dev,
"Failed to create rx ctx in firmware%d\n", err);
@@ -326,19 +336,18 @@ out_free_rq:
static void
qlcnic_fw_cmd_destroy_rx_ctx(struct qlcnic_adapter *adapter)
{
+ struct qlcnic_cmd_args cmd;
struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
- if (qlcnic_issue_cmd(adapter,
- adapter->ahw->pci_func,
- adapter->fw_hal_version,
- recv_ctx->context_id,
- QLCNIC_DESTROY_CTX_RESET,
- 0,
- QLCNIC_CDRP_CMD_DESTROY_RX_CTX)) {
-
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.req.arg1 = recv_ctx->context_id;
+ cmd.req.arg2 = QLCNIC_DESTROY_CTX_RESET;
+ cmd.req.arg3 = 0;
+ cmd.req.cmd = QLCNIC_CDRP_CMD_DESTROY_RX_CTX;
+ qlcnic_issue_cmd(adapter, &cmd);
+ if (cmd.rsp.cmd)
dev_err(&adapter->pdev->dev,
"Failed to destroy rx ctx in firmware\n");
- }
recv_ctx->state = QLCNIC_HOST_CTX_STATE_FREED;
}
@@ -352,6 +361,7 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
void *rq_addr, *rsp_addr;
size_t rq_size, rsp_size;
u32 temp;
+ struct qlcnic_cmd_args cmd;
int err;
u64 phys_addr;
dma_addr_t rq_phys_addr, rsp_phys_addr;
@@ -401,13 +411,13 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
prq_cds->ring_size = cpu_to_le32(tx_ring->num_desc);
phys_addr = rq_phys_addr;
- err = qlcnic_issue_cmd(adapter,
- adapter->ahw->pci_func,
- adapter->fw_hal_version,
- (u32)(phys_addr >> 32),
- ((u32)phys_addr & 0xffffffff),
- rq_size,
- QLCNIC_CDRP_CMD_CREATE_TX_CTX);
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.req.arg1 = (u32)(phys_addr >> 32);
+ cmd.req.arg2 = ((u32)phys_addr & 0xffffffff);
+ cmd.req.arg3 = rq_size;
+ cmd.req.cmd = QLCNIC_CDRP_CMD_CREATE_TX_CTX;
+ qlcnic_issue_cmd(adapter, &cmd);
+ err = cmd.rsp.cmd;
if (err == QLCNIC_RCODE_SUCCESS) {
temp = le32_to_cpu(prsp->cds_ring.host_producer_crb);
@@ -433,29 +443,30 @@ out_free_rq:
static void
qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter)
{
- if (qlcnic_issue_cmd(adapter,
- adapter->ahw->pci_func,
- adapter->fw_hal_version,
- adapter->tx_context_id,
- QLCNIC_DESTROY_CTX_RESET,
- 0,
- QLCNIC_CDRP_CMD_DESTROY_TX_CTX)) {
-
+ struct qlcnic_cmd_args cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.req.arg1 = adapter->tx_context_id;
+ cmd.req.arg2 = QLCNIC_DESTROY_CTX_RESET;
+ cmd.req.arg3 = 0;
+ cmd.req.cmd = QLCNIC_CDRP_CMD_DESTROY_TX_CTX;
+ qlcnic_issue_cmd(adapter, &cmd);
+ if (cmd.rsp.cmd)
dev_err(&adapter->pdev->dev,
"Failed to destroy tx ctx in firmware\n");
- }
}
int
qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config)
{
- return qlcnic_issue_cmd(adapter,
- adapter->ahw->pci_func,
- adapter->fw_hal_version,
- config,
- 0,
- 0,
- QLCNIC_CDRP_CMD_CONFIG_PORT);
+ struct qlcnic_cmd_args cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.req.arg1 = config;
+ cmd.req.cmd = QLCNIC_CDRP_CMD_CONFIG_PORT;
+ qlcnic_issue_cmd(adapter, &cmd);
+
+ return cmd.rsp.cmd;
}
int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter)
@@ -620,20 +631,17 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
int qlcnic_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
{
int err;
- u32 arg1;
+ struct qlcnic_cmd_args cmd;
- arg1 = adapter->ahw->pci_func | BIT_8;
- err = qlcnic_issue_cmd(adapter,
- adapter->ahw->pci_func,
- adapter->fw_hal_version,
- arg1,
- 0,
- 0,
- QLCNIC_CDRP_CMD_MAC_ADDRESS);
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.req.arg1 = adapter->ahw->pci_func | BIT_8;
+ cmd.req.cmd = QLCNIC_CDRP_CMD_MAC_ADDRESS;
+ cmd.rsp.arg1 = cmd.rsp.arg2 = 1;
+ qlcnic_issue_cmd(adapter, &cmd);
+ err = cmd.rsp.cmd;
if (err == QLCNIC_RCODE_SUCCESS)
- qlcnic_fetch_mac(adapter, QLCNIC_ARG1_CRB_OFFSET,
- QLCNIC_ARG2_CRB_OFFSET, 0, mac);
+ qlcnic_fetch_mac(adapter, cmd.rsp.arg1, cmd.rsp.arg2, 0, mac);
else {
dev_err(&adapter->pdev->dev,
"Failed to get mac address%d\n", err);
@@ -651,6 +659,7 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter,
dma_addr_t nic_dma_t;
struct qlcnic_info *nic_info;
void *nic_info_addr;
+ struct qlcnic_cmd_args cmd;
size_t nic_size = sizeof(struct qlcnic_info);
nic_info_addr = dma_alloc_coherent(&adapter->pdev->dev, nic_size,
@@ -660,13 +669,13 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter,
memset(nic_info_addr, 0, nic_size);
nic_info = nic_info_addr;
- err = qlcnic_issue_cmd(adapter,
- adapter->ahw->pci_func,
- adapter->fw_hal_version,
- MSD(nic_dma_t),
- LSD(nic_dma_t),
- (func_id << 16 | nic_size),
- QLCNIC_CDRP_CMD_GET_NIC_INFO);
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.req.cmd = QLCNIC_CDRP_CMD_GET_NIC_INFO;
+ cmd.req.arg1 = MSD(nic_dma_t);
+ cmd.req.arg2 = LSD(nic_dma_t);
+ cmd.req.arg3 = (func_id << 16 | nic_size);
+ qlcnic_issue_cmd(adapter, &cmd);
+ err = cmd.rsp.cmd;
if (err == QLCNIC_RCODE_SUCCESS) {
npar_info->pci_func = le16_to_cpu(nic_info->pci_func);
@@ -705,6 +714,7 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
int err = -EIO;
dma_addr_t nic_dma_t;
void *nic_info_addr;
+ struct qlcnic_cmd_args cmd;
struct qlcnic_info *nic_info;
size_t nic_size = sizeof(struct qlcnic_info);
@@ -730,13 +740,13 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
nic_info->min_tx_bw = cpu_to_le16(nic->min_tx_bw);
nic_info->max_tx_bw = cpu_to_le16(nic->max_tx_bw);
- err = qlcnic_issue_cmd(adapter,
- adapter->ahw->pci_func,
- adapter->fw_hal_version,
- MSD(nic_dma_t),
- LSD(nic_dma_t),
- ((nic->pci_func << 16) | nic_size),
- QLCNIC_CDRP_CMD_SET_NIC_INFO);
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.req.cmd = QLCNIC_CDRP_CMD_SET_NIC_INFO;
+ cmd.req.arg1 = MSD(nic_dma_t);
+ cmd.req.arg2 = LSD(nic_dma_t);
+ cmd.req.arg3 = ((nic->pci_func << 16) | nic_size);
+ qlcnic_issue_cmd(adapter, &cmd);
+ err = cmd.rsp.cmd;
if (err != QLCNIC_RCODE_SUCCESS) {
dev_err(&adapter->pdev->dev,
@@ -754,6 +764,7 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
struct qlcnic_pci_info *pci_info)
{
int err = 0, i;
+ struct qlcnic_cmd_args cmd;
dma_addr_t pci_info_dma_t;
struct qlcnic_pci_info *npar;
void *pci_info_addr;
@@ -767,13 +778,13 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
memset(pci_info_addr, 0, pci_size);
npar = pci_info_addr;
- err = qlcnic_issue_cmd(adapter,
- adapter->ahw->pci_func,
- adapter->fw_hal_version,
- MSD(pci_info_dma_t),
- LSD(pci_info_dma_t),
- pci_size,
- QLCNIC_CDRP_CMD_GET_PCI_INFO);
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.req.cmd = QLCNIC_CDRP_CMD_GET_PCI_INFO;
+ cmd.req.arg1 = MSD(pci_info_dma_t);
+ cmd.req.arg2 = LSD(pci_info_dma_t);
+ cmd.req.arg3 = pci_size;
+ qlcnic_issue_cmd(adapter, &cmd);
+ err = cmd.rsp.cmd;
if (err == QLCNIC_RCODE_SUCCESS) {
for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++, npar++, pci_info++) {
@@ -805,6 +816,7 @@ int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id,
{
int err = -EIO;
u32 arg1;
+ struct qlcnic_cmd_args cmd;
if (adapter->op_mode != QLCNIC_MGMT_FUNC ||
!(adapter->eswitch[id].flags & QLCNIC_SWITCH_ENABLE))
@@ -813,13 +825,11 @@ int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id,
arg1 = id | (enable_mirroring ? BIT_4 : 0);
arg1 |= pci_func << 8;
- err = qlcnic_issue_cmd(adapter,
- adapter->ahw->pci_func,
- adapter->fw_hal_version,
- arg1,
- 0,
- 0,
- QLCNIC_CDRP_CMD_SET_PORTMIRRORING);
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.req.cmd = QLCNIC_CDRP_CMD_SET_PORTMIRRORING;
+ cmd.req.arg1 = arg1;
+ qlcnic_issue_cmd(adapter, &cmd);
+ err = cmd.rsp.cmd;
if (err != QLCNIC_RCODE_SUCCESS) {
dev_err(&adapter->pdev->dev,
@@ -842,6 +852,7 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func,
dma_addr_t stats_dma_t;
void *stats_addr;
u32 arg1;
+ struct qlcnic_cmd_args cmd;
int err;
if (esw_stats == NULL)
@@ -865,13 +876,13 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func,
arg1 = func | QLCNIC_STATS_VERSION << 8 | QLCNIC_STATS_PORT << 12;
arg1 |= rx_tx << 15 | stats_size << 16;
- err = qlcnic_issue_cmd(adapter,
- adapter->ahw->pci_func,
- adapter->fw_hal_version,
- arg1,
- MSD(stats_dma_t),
- LSD(stats_dma_t),
- QLCNIC_CDRP_CMD_GET_ESWITCH_STATS);
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.req.cmd = QLCNIC_CDRP_CMD_GET_ESWITCH_STATS;
+ cmd.req.arg1 = arg1;
+ cmd.req.arg2 = MSD(stats_dma_t);
+ cmd.req.arg3 = LSD(stats_dma_t);
+ qlcnic_issue_cmd(adapter, &cmd);
+ err = cmd.rsp.cmd;
if (!err) {
stats = stats_addr;
@@ -952,6 +963,7 @@ int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, const u8 func_esw,
{
u32 arg1;
+ struct qlcnic_cmd_args cmd;
if (adapter->op_mode != QLCNIC_MGMT_FUNC)
return -EIO;
@@ -972,13 +984,11 @@ int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, const u8 func_esw,
arg1 = port | QLCNIC_STATS_VERSION << 8 | func_esw << 12;
arg1 |= BIT_14 | rx_tx << 15;
- return qlcnic_issue_cmd(adapter,
- adapter->ahw->pci_func,
- adapter->fw_hal_version,
- arg1,
- 0,
- 0,
- QLCNIC_CDRP_CMD_GET_ESWITCH_STATS);
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.req.cmd = QLCNIC_CDRP_CMD_GET_ESWITCH_STATS;
+ cmd.req.arg1 = arg1;
+ qlcnic_issue_cmd(adapter, &cmd);
+ return cmd.rsp.cmd;
err_ret:
dev_err(&adapter->pdev->dev, "Invalid argument func_esw=%d port=%d"
@@ -991,19 +1001,19 @@ __qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter,
u32 *arg1, u32 *arg2)
{
int err = -EIO;
+ struct qlcnic_cmd_args cmd;
u8 pci_func;
pci_func = (*arg1 >> 8);
- err = qlcnic_issue_cmd(adapter,
- adapter->ahw->pci_func,
- adapter->fw_hal_version,
- *arg1,
- 0,
- 0,
- QLCNIC_CDRP_CMD_GET_ESWITCH_PORT_CONFIG);
+
+ cmd.req.cmd = QLCNIC_CDRP_CMD_GET_ESWITCH_PORT_CONFIG;
+ cmd.req.arg1 = *arg1;
+ cmd.rsp.arg1 = cmd.rsp.arg2 = 1;
+ qlcnic_issue_cmd(adapter, &cmd);
+ *arg1 = cmd.rsp.arg1;
+ *arg2 = cmd.rsp.arg2;
+ err = cmd.rsp.cmd;
if (err == QLCNIC_RCODE_SUCCESS) {
- *arg1 = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
- *arg2 = QLCRD32(adapter, QLCNIC_ARG2_CRB_OFFSET);
dev_info(&adapter->pdev->dev,
"eSwitch port config for pci func %d\n", pci_func);
} else {
@@ -1025,6 +1035,7 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,
{
int err = -EIO;
u32 arg1, arg2 = 0;
+ struct qlcnic_cmd_args cmd;
u8 pci_func;
if (adapter->op_mode != QLCNIC_MGMT_FUNC)
@@ -1071,14 +1082,13 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,
return err;
}
- err = qlcnic_issue_cmd(adapter,
- adapter->ahw->pci_func,
- adapter->fw_hal_version,
- arg1,
- arg2,
- 0,
- QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH);
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.req.cmd = QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH;
+ cmd.req.arg1 = arg1;
+ cmd.req.arg2 = arg2;
+ qlcnic_issue_cmd(adapter, &cmd);
+ err = cmd.rsp.cmd;
if (err != QLCNIC_RCODE_SUCCESS) {
dev_err(&adapter->pdev->dev,
"Failed to configure eswitch pci func %d\n", pci_func);
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
index 72a723d5c988..5d8bec283267 100644
--- a/drivers/net/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
@@ -418,9 +418,6 @@ qlcnic_get_ringparam(struct net_device *dev,
ring->rx_max_pending = adapter->max_rxd;
ring->rx_jumbo_max_pending = adapter->max_jumbo_rxd;
ring->tx_max_pending = MAX_CMD_DESCRIPTORS;
-
- ring->rx_mini_max_pending = 0;
- ring->rx_mini_pending = 0;
}
static u32
@@ -659,6 +656,7 @@ static int qlcnic_irq_test(struct net_device *netdev)
struct qlcnic_adapter *adapter = netdev_priv(netdev);
int max_sds_rings = adapter->max_sds_rings;
int ret;
+ struct qlcnic_cmd_args cmd;
if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
return -EIO;
@@ -668,9 +666,12 @@ static int qlcnic_irq_test(struct net_device *netdev)
goto clear_it;
adapter->diag_cnt = 0;
- ret = qlcnic_issue_cmd(adapter, adapter->ahw->pci_func,
- adapter->fw_hal_version, adapter->ahw->pci_func,
- 0, 0, 0x00000011);
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.req.cmd = QLCNIC_CDRP_CMD_INTRPT_TEST;
+ cmd.req.arg1 = adapter->ahw->pci_func;
+ qlcnic_issue_cmd(adapter, &cmd);
+ ret = cmd.rsp.cmd;
+
if (ret)
goto done;
@@ -710,7 +711,7 @@ int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[])
return memcmp(data, buff, QLCNIC_ILB_PKT_SIZE);
}
-static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter)
+static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
{
struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
@@ -736,13 +737,18 @@ static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter)
dev_kfree_skb_any(skb);
if (!adapter->diag_cnt)
- dev_warn(&adapter->pdev->dev, "LB Test: %dth packet"
- " not recevied\n", i + 1);
+ QLCDB(adapter, DRV,
+ "LB Test: packet #%d was not received\n", i + 1);
else
cnt++;
}
if (cnt != i) {
dev_warn(&adapter->pdev->dev, "LB Test failed\n");
+ if (mode != QLCNIC_ILB_MODE) {
+ dev_warn(&adapter->pdev->dev,
+ "WARNING: Please make sure external"
+ "loopback connector is plugged in\n");
+ }
return -1;
}
return 0;
@@ -761,7 +767,7 @@ static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
return -EOPNOTSUPP;
}
- netdev_info(netdev, "%s loopback test in progress\n",
+ QLCDB(adapter, DRV, "%s loopback test in progress\n",
mode == QLCNIC_ILB_MODE ? "internal" : "external");
if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
netdev_warn(netdev, "Loopback test not supported for non "
@@ -797,7 +803,7 @@ static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
}
} while (!QLCNIC_IS_LB_CONFIGURED(adapter->ahw->loopback_state));
- ret = qlcnic_do_lb_test(adapter);
+ ret = qlcnic_do_lb_test(adapter, mode);
qlcnic_clear_lb_mode(adapter);
@@ -832,7 +838,6 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
data[3] = qlcnic_loopback_test(dev, QLCNIC_ILB_MODE);
if (data[3])
eth_test->flags |= ETH_TEST_FL_FAILED;
-
if (eth_test->flags & ETH_TEST_FL_EXTERNAL_LB) {
data[4] = qlcnic_loopback_test(dev, QLCNIC_ELB_MODE);
if (data[4])
@@ -933,6 +938,9 @@ static int qlcnic_set_led(struct net_device *dev,
switch (state) {
case ETHTOOL_ID_ACTIVE:
+ if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state))
+ return -EBUSY;
+
if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
return -EIO;
@@ -967,6 +975,8 @@ static int qlcnic_set_led(struct net_device *dev,
clear_bit(__QLCNIC_RESETTING, &adapter->state);
}
+ clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
+
return -EIO;
}
@@ -1105,7 +1115,10 @@ qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
- dump->len = fw_dump->tmpl_hdr->size + fw_dump->size;
+ if (fw_dump->clr)
+ dump->len = fw_dump->tmpl_hdr->size + fw_dump->size;
+ else
+ dump->len = 0;
dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
dump->version = adapter->fw_version;
return 0;
@@ -1152,7 +1165,8 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
- if (val->flag == QLCNIC_FORCE_FW_DUMP_KEY) {
+ switch (val->flag) {
+ case QLCNIC_FORCE_FW_DUMP_KEY:
if (!fw_dump->enable) {
netdev_info(netdev, "FW dump not enabled\n");
return ret;
@@ -1164,17 +1178,25 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
}
netdev_info(netdev, "Forcing a FW dump\n");
qlcnic_dev_request_reset(adapter);
- } else if (val->flag == QLCNIC_DISABLE_FW_DUMP) {
+ break;
+ case QLCNIC_DISABLE_FW_DUMP:
if (fw_dump->enable) {
netdev_info(netdev, "Disabling FW dump\n");
fw_dump->enable = 0;
}
- } else if (val->flag == QLCNIC_ENABLE_FW_DUMP) {
+ break;
+ case QLCNIC_ENABLE_FW_DUMP:
if (!fw_dump->enable && fw_dump->tmpl_hdr) {
netdev_info(netdev, "Enabling FW dump\n");
fw_dump->enable = 1;
}
- } else {
+ break;
+ case QLCNIC_FORCE_FW_RESET:
+ netdev_info(netdev, "Forcing a FW reset\n");
+ qlcnic_dev_request_reset(adapter);
+ adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
+ break;
+ default:
if (val->flag > QLCNIC_DUMP_MASK_MAX ||
val->flag < QLCNIC_DUMP_MASK_MIN) {
netdev_info(netdev,
diff --git a/drivers/net/qlcnic/qlcnic_hdr.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
index d14506f764e0..92bc8ce9b287 100644
--- a/drivers/net/qlcnic/qlcnic_hdr.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
@@ -609,6 +609,7 @@ enum {
QLCNIC_TEMP_PANIC /* Fatal error, hardware has shut down. */
};
+
/* Lock IDs for PHY lock */
#define PHY_LOCK_DRIVER 0x44524956
@@ -723,7 +724,8 @@ enum {
#define QLCNIC_RCODE_DRIVER_CAN_RELOAD BIT_30
#define QLCNIC_RCODE_FATAL_ERROR BIT_31
#define QLCNIC_FWERROR_PEGNUM(code) ((code) & 0xff)
-#define QLCNIC_FWERROR_CODE(code) ((code >> 8) & 0xfffff)
+#define QLCNIC_FWERROR_CODE(code) ((code >> 8) & 0x1fffff)
+#define QLCNIC_FWERROR_FAN_FAILURE 0x16
#define FW_POLL_DELAY (1 * HZ)
#define FW_FAIL_THRESH 2
diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
index 4055c218ef2a..74e9d7b94965 100644
--- a/drivers/net/qlcnic/qlcnic_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
@@ -1773,8 +1773,8 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
goto error;
} else {
fw_dump->clr = 1;
- snprintf(mesg, sizeof(mesg), "FW dump for device: %d\n",
- adapter->pdev->devfn);
+ snprintf(mesg, sizeof(mesg), "FW_DUMP=%s",
+ adapter->netdev->name);
dev_info(&adapter->pdev->dev, "Dump data, %d bytes captured\n",
fw_dump->size);
/* Send a udev event to notify availability of FW dump */
diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
index ee8a3982395e..312c1c37889d 100644
--- a/drivers/net/qlcnic/qlcnic_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
@@ -686,7 +686,13 @@ qlcnic_check_flash_fw_ver(struct qlcnic_adapter *adapter)
u32 ver = -1, min_ver;
int ret;
- ret = qlcnic_get_flt_entry(adapter, QLCNIC_FW_IMAGE_REGION, &fw_entry);
+ if (adapter->ahw->revision_id == QLCNIC_P3P_C0)
+ ret = qlcnic_get_flt_entry(adapter, QLCNIC_C0_FW_IMAGE_REGION,
+ &fw_entry);
+ else
+ ret = qlcnic_get_flt_entry(adapter, QLCNIC_B0_FW_IMAGE_REGION,
+ &fw_entry);
+
if (!ret)
/* 0-4:-signature, 4-8:-fw version */
qlcnic_rom_fast_read(adapter, fw_entry.start_addr + 4,
@@ -1056,7 +1062,8 @@ qlcnic_check_fw_hearbeat(struct qlcnic_adapter *adapter)
int
qlcnic_need_fw_reset(struct qlcnic_adapter *adapter)
{
- if (qlcnic_check_fw_hearbeat(adapter)) {
+ if ((adapter->flags & QLCNIC_FW_HANG) ||
+ qlcnic_check_fw_hearbeat(adapter)) {
qlcnic_rom_lock_recovery(adapter);
return 1;
}
@@ -1778,14 +1785,14 @@ qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
spin_unlock(&rds_ring->lock);
}
-static void dump_skb(struct sk_buff *skb)
+static void dump_skb(struct sk_buff *skb, struct qlcnic_adapter *adapter)
{
int i;
unsigned char *data = skb->data;
printk(KERN_INFO "\n");
for (i = 0; i < skb->len; i++) {
- printk(KERN_INFO "%02x ", data[i]);
+ QLCDB(adapter, DRV, "%02x ", data[i]);
if ((i & 0x0f) == 8)
printk(KERN_INFO "\n");
}
@@ -1828,7 +1835,7 @@ void qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter,
if (!qlcnic_check_loopback_buff(skb->data, adapter->mac_addr))
adapter->diag_cnt++;
else
- dump_skb(skb);
+ dump_skb(skb, adapter);
dev_kfree_skb_any(skb);
adapter->stats.rx_pkts++;
@@ -1882,8 +1889,8 @@ qlcnic_fetch_mac(struct qlcnic_adapter *adapter, u32 off1, u32 off2,
u32 mac_low, mac_high;
int i;
- mac_low = QLCRD32(adapter, off1);
- mac_high = QLCRD32(adapter, off2);
+ mac_low = off1;
+ mac_high = off2;
if (alt_mac) {
mac_low |= (mac_low >> 16) | (mac_high << 16);
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 5ca1b562443c..106503f118f6 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -325,7 +325,7 @@ static const struct net_device_ops qlcnic_netdev_ops = {
.ndo_start_xmit = qlcnic_xmit_frame,
.ndo_get_stats = qlcnic_get_stats,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = qlcnic_set_multi,
+ .ndo_set_rx_mode = qlcnic_set_multi,
.ndo_set_mac_address = qlcnic_set_mac,
.ndo_change_mtu = qlcnic_change_mtu,
.ndo_fix_features = qlcnic_fix_features,
@@ -643,8 +643,11 @@ static void get_brd_name(struct qlcnic_adapter *adapter, char *name)
static void
qlcnic_check_options(struct qlcnic_adapter *adapter)
{
- u32 fw_major, fw_minor, fw_build;
+ u32 fw_major, fw_minor, fw_build, prev_fw_version;
struct pci_dev *pdev = adapter->pdev;
+ struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+
+ prev_fw_version = adapter->fw_version;
fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
@@ -652,6 +655,17 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
adapter->fw_version = QLCNIC_VERSION_CODE(fw_major, fw_minor, fw_build);
+ if (adapter->op_mode != QLCNIC_NON_PRIV_FUNC) {
+ if (fw_dump->tmpl_hdr == NULL ||
+ adapter->fw_version > prev_fw_version) {
+ if (fw_dump->tmpl_hdr)
+ vfree(fw_dump->tmpl_hdr);
+ if (!qlcnic_fw_cmd_get_minidump_temp(adapter))
+ dev_info(&pdev->dev,
+ "Supports FW dump capability\n");
+ }
+ }
+
dev_info(&pdev->dev, "firmware v%d.%d.%d\n",
fw_major, fw_minor, fw_build);
if (adapter->ahw->port_type == QLCNIC_XGBE) {
@@ -1610,12 +1624,6 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_decr_ref;
}
- /* Get FW dump template and store it */
- if (adapter->op_mode != QLCNIC_NON_PRIV_FUNC)
- if (!qlcnic_fw_cmd_get_minidump_temp(adapter))
- dev_info(&pdev->dev,
- "Supports FW dump capability\n");
-
if (qlcnic_read_mac_addr(adapter))
dev_warn(&pdev->dev, "failed to read mac addr\n");
@@ -2127,13 +2135,13 @@ qlcnic_map_tx_skb(struct pci_dev *pdev,
frag = &skb_shinfo(skb)->frags[i];
nf = &pbuf->frag_array[i+1];
- map = pci_map_page(pdev, frag->page, frag->page_offset,
- frag->size, PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(pdev, map))
+ map = skb_frag_dma_map(&pdev->dev, frag, 0, skb_frag_size(frag),
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(&pdev->dev, map))
goto unwind;
nf->dma = map;
- nf->length = frag->size;
+ nf->length = skb_frag_size(frag);
}
return 0;
@@ -2213,7 +2221,7 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if (!skb_is_gso(skb) && frag_count > QLCNIC_MAX_FRAGS_PER_TX) {
for (i = 0; i < (frag_count - QLCNIC_MAX_FRAGS_PER_TX); i++)
- delta += skb_shinfo(skb)->frags[i].size;
+ delta += skb_frag_size(&skb_shinfo(skb)->frags[i]);
if (!__pskb_pull_tail(skb, delta))
goto drop_packet;
@@ -2682,6 +2690,7 @@ qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8 failed)
qlcnic_api_unlock(adapter);
err:
adapter->fw_fail_cnt = 0;
+ adapter->flags &= ~QLCNIC_FW_HANG;
clear_bit(__QLCNIC_START_FW, &adapter->state);
clear_bit(__QLCNIC_RESETTING, &adapter->state);
}
@@ -2859,6 +2868,7 @@ skip_ack_check:
(adapter->flags & QLCNIC_FW_RESET_OWNER)) {
QLCDB(adapter, DRV, "Take FW dump\n");
qlcnic_dump_fw(adapter);
+ adapter->flags |= QLCNIC_FW_HANG;
}
rtnl_unlock();
@@ -2918,15 +2928,36 @@ qlcnic_detach_work(struct work_struct *work)
status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
- if (status & QLCNIC_RCODE_FATAL_ERROR)
+ if (status & QLCNIC_RCODE_FATAL_ERROR) {
+ dev_err(&adapter->pdev->dev,
+ "Detaching the device: peg halt status1=0x%x\n",
+ status);
+
+ if (QLCNIC_FWERROR_CODE(status) == QLCNIC_FWERROR_FAN_FAILURE) {
+ dev_err(&adapter->pdev->dev,
+ "On board active cooling fan failed. "
+ "Device has been halted.\n");
+ dev_err(&adapter->pdev->dev,
+ "Replace the adapter.\n");
+ }
+
goto err_ret;
+ }
- if (adapter->temp == QLCNIC_TEMP_PANIC)
+ if (adapter->temp == QLCNIC_TEMP_PANIC) {
+ dev_err(&adapter->pdev->dev, "Detaching the device: temp=%d\n",
+ adapter->temp);
goto err_ret;
+ }
+
/* Dont ack if this instance is the reset owner */
if (!(adapter->flags & QLCNIC_FW_RESET_OWNER)) {
- if (qlcnic_set_drv_state(adapter, adapter->dev_state))
+ if (qlcnic_set_drv_state(adapter, adapter->dev_state)) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to set driver state,"
+ "detaching the device.\n");
goto err_ret;
+ }
}
adapter->fw_wait_cnt = 0;
@@ -2936,8 +2967,6 @@ qlcnic_detach_work(struct work_struct *work)
return;
err_ret:
- dev_err(&adapter->pdev->dev, "detach failed; status=%d temp=%d\n",
- status, adapter->temp);
netif_device_attach(netdev);
qlcnic_clr_all_drv_state(adapter, 1);
}
@@ -3046,6 +3075,7 @@ attach:
done:
netif_device_attach(netdev);
adapter->fw_fail_cnt = 0;
+ adapter->flags &= ~QLCNIC_FW_HANG;
clear_bit(__QLCNIC_RESETTING, &adapter->state);
if (!qlcnic_clr_drv_state(adapter))
@@ -3057,7 +3087,7 @@ static int
qlcnic_check_health(struct qlcnic_adapter *adapter)
{
u32 state = 0, heartbeat;
- struct net_device *netdev = adapter->netdev;
+ u32 peg_status;
if (qlcnic_check_temp(adapter))
goto detach;
@@ -3090,13 +3120,31 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
if (++adapter->fw_fail_cnt < FW_FAIL_THRESH)
return 0;
+ adapter->flags |= QLCNIC_FW_HANG;
+
qlcnic_dev_request_reset(adapter);
if (auto_fw_reset)
clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
- dev_info(&netdev->dev, "firmware hang detected\n");
-
+ dev_err(&adapter->pdev->dev, "firmware hang detected\n");
+ dev_err(&adapter->pdev->dev, "Dumping hw/fw registers\n"
+ "PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n"
+ "PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n"
+ "PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n"
+ "PEG_NET_4_PC: 0x%x\n",
+ QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1),
+ QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS2),
+ QLCRD32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x3c),
+ QLCRD32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x3c),
+ QLCRD32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x3c),
+ QLCRD32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c),
+ QLCRD32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c));
+ peg_status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
+ if (LSW(MSB(peg_status)) == 0x67)
+ dev_err(&adapter->pdev->dev,
+ "Firmware aborted with error code 0x00006700. "
+ "Device is being reset.\n");
detach:
adapter->dev_state = (state == QLCNIC_DEV_NEED_QUISCENT) ? state :
QLCNIC_DEV_NEED_RESET;
@@ -3423,6 +3471,98 @@ int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data)
}
static int
+qlcnic_validate_beacon(struct qlcnic_adapter *adapter, u16 beacon, u8 *state,
+ u8 *rate)
+{
+ *rate = LSB(beacon);
+ *state = MSB(beacon);
+
+ QLCDB(adapter, DRV, "rate %x state %x\n", *rate, *state);
+
+ if (!*state) {
+ *rate = __QLCNIC_MAX_LED_RATE;
+ return 0;
+ } else if (*state > __QLCNIC_MAX_LED_STATE)
+ return -EINVAL;
+
+ if ((!*rate) || (*rate > __QLCNIC_MAX_LED_RATE))
+ return -EINVAL;
+
+ return 0;
+}
+
+static ssize_t
+qlcnic_store_beacon(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ int max_sds_rings = adapter->max_sds_rings;
+ int dev_down = 0;
+ u16 beacon;
+ u8 b_state, b_rate;
+ int err;
+
+ if (len != sizeof(u16))
+ return QL_STATUS_INVALID_PARAM;
+
+ memcpy(&beacon, buf, sizeof(u16));
+ err = qlcnic_validate_beacon(adapter, beacon, &b_state, &b_rate);
+ if (err)
+ return err;
+
+ if (adapter->ahw->beacon_state == b_state)
+ return len;
+
+ if (!adapter->ahw->beacon_state)
+ if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state))
+ return -EBUSY;
+
+ if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
+ if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+ return -EIO;
+ err = qlcnic_diag_alloc_res(adapter->netdev, QLCNIC_LED_TEST);
+ if (err) {
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
+ return err;
+ }
+ dev_down = 1;
+ }
+
+ err = qlcnic_config_led(adapter, b_state, b_rate);
+
+ if (!err) {
+ adapter->ahw->beacon_state = b_state;
+ err = len;
+ }
+
+ if (dev_down) {
+ qlcnic_diag_free_res(adapter->netdev, max_sds_rings);
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ }
+
+ if (!b_state)
+ clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
+
+ return err;
+}
+
+static ssize_t
+qlcnic_show_beacon(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", adapter->ahw->beacon_state);
+}
+
+static struct device_attribute dev_attr_beacon = {
+ .attr = {.name = "beacon", .mode = (S_IRUGO | S_IWUSR)},
+ .show = qlcnic_show_beacon,
+ .store = qlcnic_store_beacon,
+};
+
+static int
qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
loff_t offset, size_t size)
{
@@ -4119,6 +4259,8 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
return;
if (device_create_file(dev, &dev_attr_diag_mode))
dev_info(dev, "failed to create diag_mode sysfs entry\n");
+ if (device_create_file(dev, &dev_attr_beacon))
+ dev_info(dev, "failed to create beacon sysfs entry");
if (device_create_bin_file(dev, &bin_attr_crb))
dev_info(dev, "failed to create crb sysfs entry\n");
if (device_create_bin_file(dev, &bin_attr_mem))
@@ -4149,6 +4291,7 @@ qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
return;
device_remove_file(dev, &dev_attr_diag_mode);
+ device_remove_file(dev, &dev_attr_beacon);
device_remove_bin_file(dev, &bin_attr_crb);
device_remove_bin_file(dev, &bin_attr_mem);
device_remove_bin_file(dev, &bin_attr_pci_config);
diff --git a/drivers/net/qlge/Makefile b/drivers/net/ethernet/qlogic/qlge/Makefile
index 8a197658d76f..8a197658d76f 100644
--- a/drivers/net/qlge/Makefile
+++ b/drivers/net/ethernet/qlogic/qlge/Makefile
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/ethernet/qlogic/qlge/qlge.h
index 8731f79c9efc..8731f79c9efc 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/ethernet/qlogic/qlge/qlge.h
diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c
index fca804f36d61..fca804f36d61 100644
--- a/drivers/net/qlge/qlge_dbg.c
+++ b/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c
diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/ethernet/qlogic/qlge/qlge_ethtool.c
index 9b67bfea035f..9b67bfea035f 100644
--- a/drivers/net/qlge/qlge_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qlge/qlge_ethtool.c
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
index f07e96ec8843..c92afcd912e2 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
@@ -1431,12 +1431,10 @@ static int ql_map_send(struct ql_adapter *qdev,
map_idx++;
}
- map =
- pci_map_page(qdev->pdev, frag->page,
- frag->page_offset, frag->size,
- PCI_DMA_TODEVICE);
+ map = skb_frag_dma_map(&qdev->pdev->dev, frag, 0, skb_frag_size(frag),
+ DMA_TO_DEVICE);
- err = pci_dma_mapping_error(qdev->pdev, map);
+ err = dma_mapping_error(&qdev->pdev->dev, map);
if (err) {
netif_err(qdev, tx_queued, qdev->ndev,
"PCI mapping frags failed with error: %d.\n",
@@ -1445,10 +1443,10 @@ static int ql_map_send(struct ql_adapter *qdev,
}
tbd->addr = cpu_to_le64(map);
- tbd->len = cpu_to_le32(frag->size);
+ tbd->len = cpu_to_le32(skb_frag_size(frag));
dma_unmap_addr_set(&tx_ring_desc->map[map_idx], mapaddr, map);
dma_unmap_len_set(&tx_ring_desc->map[map_idx], maplen,
- frag->size);
+ skb_frag_size(frag));
}
/* Save the number of segments we've mapped. */
@@ -1477,8 +1475,6 @@ static void ql_process_mac_rx_gro_page(struct ql_adapter *qdev,
{
struct sk_buff *skb;
struct bq_desc *lbq_desc = ql_get_curr_lchunk(qdev, rx_ring);
- struct skb_frag_struct *rx_frag;
- int nr_frags;
struct napi_struct *napi = &rx_ring->napi;
napi->dev = qdev->ndev;
@@ -1492,12 +1488,10 @@ static void ql_process_mac_rx_gro_page(struct ql_adapter *qdev,
return;
}
prefetch(lbq_desc->p.pg_chunk.va);
- rx_frag = skb_shinfo(skb)->frags;
- nr_frags = skb_shinfo(skb)->nr_frags;
- rx_frag += nr_frags;
- rx_frag->page = lbq_desc->p.pg_chunk.page;
- rx_frag->page_offset = lbq_desc->p.pg_chunk.offset;
- rx_frag->size = length;
+ __skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
+ lbq_desc->p.pg_chunk.page,
+ lbq_desc->p.pg_chunk.offset,
+ length);
skb->len += length;
skb->data_len += length;
@@ -4676,7 +4670,7 @@ static const struct net_device_ops qlge_netdev_ops = {
.ndo_start_xmit = qlge_send,
.ndo_change_mtu = qlge_change_mtu,
.ndo_get_stats = qlge_get_stats,
- .ndo_set_multicast_list = qlge_set_multicast_list,
+ .ndo_set_rx_mode = qlge_set_multicast_list,
.ndo_set_mac_address = qlge_set_mac_address,
.ndo_validate_addr = eth_validate_addr,
.ndo_tx_timeout = qlge_tx_timeout,
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/ethernet/qlogic/qlge/qlge_mpi.c
index ff2bf8a4e247..ff2bf8a4e247 100644
--- a/drivers/net/qlge/qlge_mpi.c
+++ b/drivers/net/ethernet/qlogic/qlge/qlge_mpi.c
diff --git a/drivers/net/ethernet/racal/Kconfig b/drivers/net/ethernet/racal/Kconfig
new file mode 100644
index 000000000000..01969e0a9c68
--- /dev/null
+++ b/drivers/net/ethernet/racal/Kconfig
@@ -0,0 +1,33 @@
+#
+# Racal-Interlan device configuration
+#
+
+config NET_VENDOR_RACAL
+ bool "Racal-Interlan (Micom) NI devices"
+ default y
+ depends on ISA
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, such
+ as the NI5010, NI5210 or NI6210, say Y and read the Ethernet-HOWTO,
+ available from <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about NI cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_RACAL
+
+config NI5010
+ tristate "NI5010 support (EXPERIMENTAL)"
+ depends on ISA && EXPERIMENTAL && BROKEN_ON_SMP
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>. Note that this is still
+ experimental code.
+
+ To compile this driver as a module, choose M here. The module
+ will be called ni5010.
+
+endif # NET_VENDOR_RACAL
diff --git a/drivers/net/ethernet/racal/Makefile b/drivers/net/ethernet/racal/Makefile
new file mode 100644
index 000000000000..1e210ca1d78b
--- /dev/null
+++ b/drivers/net/ethernet/racal/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Racal-Interlan network device drivers.
+#
+
+obj-$(CONFIG_NI5010) += ni5010.o
diff --git a/drivers/net/ni5010.c b/drivers/net/ethernet/racal/ni5010.c
index 4d3f2e2b28bd..072810da9a37 100644
--- a/drivers/net/ni5010.c
+++ b/drivers/net/ethernet/racal/ni5010.c
@@ -192,7 +192,7 @@ static const struct net_device_ops ni5010_netdev_ops = {
.ndo_open = ni5010_open,
.ndo_stop = ni5010_close,
.ndo_start_xmit = ni5010_send_packet,
- .ndo_set_multicast_list = ni5010_set_multicast_list,
+ .ndo_set_rx_mode = ni5010_set_multicast_list,
.ndo_tx_timeout = ni5010_timeout,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/ni5010.h b/drivers/net/ethernet/racal/ni5010.h
index e10e717fcd76..e10e717fcd76 100644
--- a/drivers/net/ni5010.h
+++ b/drivers/net/ethernet/racal/ni5010.h
diff --git a/drivers/net/ethernet/rdc/Kconfig b/drivers/net/ethernet/rdc/Kconfig
new file mode 100644
index 000000000000..c8ba4b3494c1
--- /dev/null
+++ b/drivers/net/ethernet/rdc/Kconfig
@@ -0,0 +1,35 @@
+#
+# RDC network device configuration
+#
+
+config NET_VENDOR_RDC
+ bool "RDC devices"
+ default y
+ depends on PCI
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about RDC cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_RDC
+
+config R6040
+ tristate "RDC R6040 Fast Ethernet Adapter support"
+ depends on PCI
+ select CRC32
+ select NET_CORE
+ select MII
+ select PHYLIB
+ ---help---
+ This is a driver for the R6040 Fast Ethernet MACs found in the
+ the RDC R-321x System-on-chips.
+
+ To compile this driver as a module, choose M here: the module
+ will be called r6040. This is recommended.
+
+endif # NET_VENDOR_RDC
diff --git a/drivers/net/ethernet/rdc/Makefile b/drivers/net/ethernet/rdc/Makefile
new file mode 100644
index 000000000000..8d51fd2d07fc
--- /dev/null
+++ b/drivers/net/ethernet/rdc/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the RDC network device drivers.
+#
+
+obj-$(CONFIG_R6040) += r6040.o
diff --git a/drivers/net/r6040.c b/drivers/net/ethernet/rdc/r6040.c
index b64fcee483aa..1fc01ca72b46 100644
--- a/drivers/net/r6040.c
+++ b/drivers/net/ethernet/rdc/r6040.c
@@ -49,8 +49,8 @@
#include <asm/processor.h>
#define DRV_NAME "r6040"
-#define DRV_VERSION "0.27"
-#define DRV_RELDATE "23Feb2011"
+#define DRV_VERSION "0.28"
+#define DRV_RELDATE "07Oct2011"
/* PHY CHIP Address */
#define PHY1_ADDR 1 /* For MAC1 */
@@ -470,6 +470,8 @@ static void r6040_down(struct net_device *dev)
iowrite16(adrp[0], ioaddr + MID_0L);
iowrite16(adrp[1], ioaddr + MID_0M);
iowrite16(adrp[2], ioaddr + MID_0H);
+
+ phy_stop(lp->phydev);
}
static int r6040_close(struct net_device *dev)
@@ -727,6 +729,8 @@ static int r6040_up(struct net_device *dev)
/* Initialize all MAC registers */
r6040_init_mac_regs(dev);
+ phy_start(lp->phydev);
+
return 0;
}
@@ -982,7 +986,7 @@ static const struct net_device_ops r6040_netdev_ops = {
.ndo_stop = r6040_close,
.ndo_start_xmit = r6040_start_xmit,
.ndo_get_stats = r6040_get_stats,
- .ndo_set_multicast_list = r6040_multicast_list,
+ .ndo_set_rx_mode = r6040_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c
index cc4c210a91f8..ee5da9293ce0 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/ethernet/realtek/8139cp.c
@@ -777,15 +777,14 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
entry = NEXT_TX(entry);
for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
- skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
+ const skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
u32 len;
u32 ctrl;
dma_addr_t mapping;
- len = this_frag->size;
+ len = skb_frag_size(this_frag);
mapping = dma_map_single(&cp->pdev->dev,
- ((void *) page_address(this_frag->page) +
- this_frag->page_offset),
+ skb_frag_address(this_frag),
len, PCI_DMA_TODEVICE);
eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
@@ -1325,6 +1324,15 @@ static void cp_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info
strcpy (info->bus_info, pci_name(cp->pdev));
}
+static void cp_get_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ring)
+{
+ ring->rx_max_pending = CP_RX_RING_SIZE;
+ ring->tx_max_pending = CP_TX_RING_SIZE;
+ ring->rx_pending = CP_RX_RING_SIZE;
+ ring->tx_pending = CP_TX_RING_SIZE;
+}
+
static int cp_get_regs_len(struct net_device *dev)
{
return CP_REGS_SIZE;
@@ -1526,6 +1534,7 @@ static const struct ethtool_ops cp_ethtool_ops = {
.get_eeprom_len = cp_get_eeprom_len,
.get_eeprom = cp_get_eeprom,
.set_eeprom = cp_set_eeprom,
+ .get_ringparam = cp_get_ringparam,
};
static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
@@ -1785,7 +1794,7 @@ static const struct net_device_ops cp_netdev_ops = {
.ndo_stop = cp_close,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = cp_set_mac_address,
- .ndo_set_multicast_list = cp_set_rx_mode,
+ .ndo_set_rx_mode = cp_set_rx_mode,
.ndo_get_stats = cp_get_stats,
.ndo_do_ioctl = cp_ioctl,
.ndo_start_xmit = cp_start_xmit,
diff --git a/drivers/net/8139too.c b/drivers/net/ethernet/realtek/8139too.c
index c2672c692d6f..4d6b254fc6c1 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/ethernet/realtek/8139too.c
@@ -916,7 +916,7 @@ static const struct net_device_ops rtl8139_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = rtl8139_set_mac_address,
.ndo_start_xmit = rtl8139_start_xmit,
- .ndo_set_multicast_list = rtl8139_set_rx_mode,
+ .ndo_set_rx_mode = rtl8139_set_rx_mode,
.ndo_do_ioctl = netdev_ioctl,
.ndo_tx_timeout = rtl8139_tx_timeout,
#ifdef CONFIG_NET_POLL_CONTROLLER
diff --git a/drivers/net/ethernet/realtek/Kconfig b/drivers/net/ethernet/realtek/Kconfig
new file mode 100644
index 000000000000..84083ec6e612
--- /dev/null
+++ b/drivers/net/ethernet/realtek/Kconfig
@@ -0,0 +1,130 @@
+#
+# Realtek device configuration
+#
+
+config NET_VENDOR_REALTEK
+ bool "Realtek devices"
+ default y
+ depends on PCI || (PARPORT && X86)
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Realtek devices. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_REALTEK
+
+config ATP
+ tristate "AT-LAN-TEC/RealTek pocket adapter support"
+ depends on PARPORT && X86
+ select CRC32
+ ---help---
+ This is a network (Ethernet) device which attaches to your parallel
+ port. Read <file:drivers/net/atp.c> as well as the Ethernet-HOWTO,
+ available from <http://www.tldp.org/docs.html#howto>, if you
+ want to use this. If you intend to use this driver, you should have
+ said N to the "Parallel printer support", because the two drivers
+ don't like each other.
+
+ To compile this driver as a module, choose M here: the module
+ will be called atp.
+
+config 8139CP
+ tristate "RealTek RTL-8139 C+ PCI Fast Ethernet Adapter support (EXPERIMENTAL)"
+ depends on PCI && EXPERIMENTAL
+ select CRC32
+ select NET_CORE
+ select MII
+ ---help---
+ This is a driver for the Fast Ethernet PCI network cards based on
+ the RTL8139C+ chips. If you have one of those, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here: the module
+ will be called 8139cp. This is recommended.
+
+config 8139TOO
+ tristate "RealTek RTL-8129/8130/8139 PCI Fast Ethernet Adapter support"
+ depends on PCI
+ select CRC32
+ select NET_CORE
+ select MII
+ ---help---
+ This is a driver for the Fast Ethernet PCI network cards based on
+ the RTL 8129/8130/8139 chips. If you have one of those, say Y and
+ read the Ethernet-HOWTO <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here: the module
+ will be called 8139too. This is recommended.
+
+config 8139TOO_PIO
+ bool "Use PIO instead of MMIO"
+ default y
+ depends on 8139TOO
+ ---help---
+ This instructs the driver to use programmed I/O ports (PIO) instead
+ of PCI shared memory (MMIO). This can possibly solve some problems
+ in case your mainboard has memory consistency issues. If unsure,
+ say N.
+
+config 8139TOO_TUNE_TWISTER
+ bool "Support for uncommon RTL-8139 rev. K (automatic channel equalization)"
+ depends on 8139TOO
+ ---help---
+ This implements a function which might come in handy in case you
+ are using low quality on long cabling. It is required for RealTek
+ RTL-8139 revision K boards, and totally unused otherwise. It tries
+ to match the transceiver to the cable characteristics. This is
+ experimental since hardly documented by the manufacturer.
+ If unsure, say Y.
+
+config 8139TOO_8129
+ bool "Support for older RTL-8129/8130 boards"
+ depends on 8139TOO
+ ---help---
+ This enables support for the older and uncommon RTL-8129 and
+ RTL-8130 chips, which support MII via an external transceiver,
+ instead of an internal one. Disabling this option will save some
+ memory by making the code size smaller. If unsure, say Y.
+
+config 8139_OLD_RX_RESET
+ bool "Use older RX-reset method"
+ depends on 8139TOO
+ ---help---
+ The 8139too driver was recently updated to contain a more rapid
+ reset sequence, in the face of severe receive errors. This "new"
+ RX-reset method should be adequate for all boards. But if you
+ experience problems, you can enable this option to restore the
+ old RX-reset behavior. If unsure, say N.
+
+config R8169
+ tristate "Realtek 8169 gigabit ethernet support"
+ depends on PCI
+ select FW_LOADER
+ select CRC32
+ select NET_CORE
+ select MII
+ ---help---
+ Say Y here if you have a Realtek 8169 PCI Gigabit Ethernet adapter.
+
+ To compile this driver as a module, choose M here: the module
+ will be called r8169. This is recommended.
+
+config SC92031
+ tristate "Silan SC92031 PCI Fast Ethernet Adapter driver (EXPERIMENTAL)"
+ depends on PCI && EXPERIMENTAL
+ select CRC32
+ ---help---
+ This is a driver for the Fast Ethernet PCI network cards based on
+ the Silan SC92031 chip (sometimes also called Rsltek 8139D). If you
+ have one of these, say Y here.
+
+ To compile this driver as a module, choose M here: the module
+ will be called sc92031. This is recommended.
+
+endif # NET_VENDOR_REALTEK
diff --git a/drivers/net/ethernet/realtek/Makefile b/drivers/net/ethernet/realtek/Makefile
new file mode 100644
index 000000000000..e48cfb6ac42d
--- /dev/null
+++ b/drivers/net/ethernet/realtek/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the Realtek network device drivers.
+#
+
+obj-$(CONFIG_8139CP) += 8139cp.o
+obj-$(CONFIG_8139TOO) += 8139too.o
+obj-$(CONFIG_ATP) += atp.o
+obj-$(CONFIG_R8169) += r8169.o
+obj-$(CONFIG_SC92031) += sc92031.o
diff --git a/drivers/net/atp.c b/drivers/net/ethernet/realtek/atp.c
index f3459798b0e9..e3f57fdbf0ea 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/ethernet/realtek/atp.c
@@ -245,7 +245,7 @@ static const struct net_device_ops atp_netdev_ops = {
.ndo_open = net_open,
.ndo_stop = net_close,
.ndo_start_xmit = atp_send_packet,
- .ndo_set_multicast_list = set_rx_mode,
+ .ndo_set_rx_mode = set_rx_mode,
.ndo_tx_timeout = tx_timeout,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/atp.h b/drivers/net/ethernet/realtek/atp.h
index 0edc642c2c2f..0edc642c2c2f 100644
--- a/drivers/net/atp.h
+++ b/drivers/net/ethernet/realtek/atp.h
diff --git a/drivers/net/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 02339b3352e7..92b45f08858f 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -42,6 +42,8 @@
#define FIRMWARE_8168E_1 "rtl_nic/rtl8168e-1.fw"
#define FIRMWARE_8168E_2 "rtl_nic/rtl8168e-2.fw"
#define FIRMWARE_8168E_3 "rtl_nic/rtl8168e-3.fw"
+#define FIRMWARE_8168F_1 "rtl_nic/rtl8168f-1.fw"
+#define FIRMWARE_8168F_2 "rtl_nic/rtl8168f-2.fw"
#define FIRMWARE_8105E_1 "rtl_nic/rtl8105e-1.fw"
#ifdef RTL8169_DEBUG
@@ -133,6 +135,8 @@ enum mac_version {
RTL_GIGA_MAC_VER_32,
RTL_GIGA_MAC_VER_33,
RTL_GIGA_MAC_VER_34,
+ RTL_GIGA_MAC_VER_35,
+ RTL_GIGA_MAC_VER_36,
RTL_GIGA_MAC_NONE = 0xff,
};
@@ -141,84 +145,110 @@ enum rtl_tx_desc_version {
RTL_TD_1 = 1,
};
-#define _R(NAME,TD,FW) \
- { .name = NAME, .txd_version = TD, .fw_name = FW }
+#define JUMBO_1K ETH_DATA_LEN
+#define JUMBO_4K (4*1024 - ETH_HLEN - 2)
+#define JUMBO_6K (6*1024 - ETH_HLEN - 2)
+#define JUMBO_7K (7*1024 - ETH_HLEN - 2)
+#define JUMBO_9K (9*1024 - ETH_HLEN - 2)
+
+#define _R(NAME,TD,FW,SZ,B) { \
+ .name = NAME, \
+ .txd_version = TD, \
+ .fw_name = FW, \
+ .jumbo_max = SZ, \
+ .jumbo_tx_csum = B \
+}
static const struct {
const char *name;
enum rtl_tx_desc_version txd_version;
const char *fw_name;
+ u16 jumbo_max;
+ bool jumbo_tx_csum;
} rtl_chip_infos[] = {
/* PCI devices. */
[RTL_GIGA_MAC_VER_01] =
- _R("RTL8169", RTL_TD_0, NULL),
+ _R("RTL8169", RTL_TD_0, NULL, JUMBO_7K, true),
[RTL_GIGA_MAC_VER_02] =
- _R("RTL8169s", RTL_TD_0, NULL),
+ _R("RTL8169s", RTL_TD_0, NULL, JUMBO_7K, true),
[RTL_GIGA_MAC_VER_03] =
- _R("RTL8110s", RTL_TD_0, NULL),
+ _R("RTL8110s", RTL_TD_0, NULL, JUMBO_7K, true),
[RTL_GIGA_MAC_VER_04] =
- _R("RTL8169sb/8110sb", RTL_TD_0, NULL),
+ _R("RTL8169sb/8110sb", RTL_TD_0, NULL, JUMBO_7K, true),
[RTL_GIGA_MAC_VER_05] =
- _R("RTL8169sc/8110sc", RTL_TD_0, NULL),
+ _R("RTL8169sc/8110sc", RTL_TD_0, NULL, JUMBO_7K, true),
[RTL_GIGA_MAC_VER_06] =
- _R("RTL8169sc/8110sc", RTL_TD_0, NULL),
+ _R("RTL8169sc/8110sc", RTL_TD_0, NULL, JUMBO_7K, true),
/* PCI-E devices. */
[RTL_GIGA_MAC_VER_07] =
- _R("RTL8102e", RTL_TD_1, NULL),
+ _R("RTL8102e", RTL_TD_1, NULL, JUMBO_1K, true),
[RTL_GIGA_MAC_VER_08] =
- _R("RTL8102e", RTL_TD_1, NULL),
+ _R("RTL8102e", RTL_TD_1, NULL, JUMBO_1K, true),
[RTL_GIGA_MAC_VER_09] =
- _R("RTL8102e", RTL_TD_1, NULL),
+ _R("RTL8102e", RTL_TD_1, NULL, JUMBO_1K, true),
[RTL_GIGA_MAC_VER_10] =
- _R("RTL8101e", RTL_TD_0, NULL),
+ _R("RTL8101e", RTL_TD_0, NULL, JUMBO_1K, true),
[RTL_GIGA_MAC_VER_11] =
- _R("RTL8168b/8111b", RTL_TD_0, NULL),
+ _R("RTL8168b/8111b", RTL_TD_0, NULL, JUMBO_4K, false),
[RTL_GIGA_MAC_VER_12] =
- _R("RTL8168b/8111b", RTL_TD_0, NULL),
+ _R("RTL8168b/8111b", RTL_TD_0, NULL, JUMBO_4K, false),
[RTL_GIGA_MAC_VER_13] =
- _R("RTL8101e", RTL_TD_0, NULL),
+ _R("RTL8101e", RTL_TD_0, NULL, JUMBO_1K, true),
[RTL_GIGA_MAC_VER_14] =
- _R("RTL8100e", RTL_TD_0, NULL),
+ _R("RTL8100e", RTL_TD_0, NULL, JUMBO_1K, true),
[RTL_GIGA_MAC_VER_15] =
- _R("RTL8100e", RTL_TD_0, NULL),
+ _R("RTL8100e", RTL_TD_0, NULL, JUMBO_1K, true),
[RTL_GIGA_MAC_VER_16] =
- _R("RTL8101e", RTL_TD_0, NULL),
+ _R("RTL8101e", RTL_TD_0, NULL, JUMBO_1K, true),
[RTL_GIGA_MAC_VER_17] =
- _R("RTL8168b/8111b", RTL_TD_0, NULL),
+ _R("RTL8168b/8111b", RTL_TD_1, NULL, JUMBO_4K, false),
[RTL_GIGA_MAC_VER_18] =
- _R("RTL8168cp/8111cp", RTL_TD_1, NULL),
+ _R("RTL8168cp/8111cp", RTL_TD_1, NULL, JUMBO_6K, false),
[RTL_GIGA_MAC_VER_19] =
- _R("RTL8168c/8111c", RTL_TD_1, NULL),
+ _R("RTL8168c/8111c", RTL_TD_1, NULL, JUMBO_6K, false),
[RTL_GIGA_MAC_VER_20] =
- _R("RTL8168c/8111c", RTL_TD_1, NULL),
+ _R("RTL8168c/8111c", RTL_TD_1, NULL, JUMBO_6K, false),
[RTL_GIGA_MAC_VER_21] =
- _R("RTL8168c/8111c", RTL_TD_1, NULL),
+ _R("RTL8168c/8111c", RTL_TD_1, NULL, JUMBO_6K, false),
[RTL_GIGA_MAC_VER_22] =
- _R("RTL8168c/8111c", RTL_TD_1, NULL),
+ _R("RTL8168c/8111c", RTL_TD_1, NULL, JUMBO_6K, false),
[RTL_GIGA_MAC_VER_23] =
- _R("RTL8168cp/8111cp", RTL_TD_1, NULL),
+ _R("RTL8168cp/8111cp", RTL_TD_1, NULL, JUMBO_6K, false),
[RTL_GIGA_MAC_VER_24] =
- _R("RTL8168cp/8111cp", RTL_TD_1, NULL),
+ _R("RTL8168cp/8111cp", RTL_TD_1, NULL, JUMBO_6K, false),
[RTL_GIGA_MAC_VER_25] =
- _R("RTL8168d/8111d", RTL_TD_1, FIRMWARE_8168D_1),
+ _R("RTL8168d/8111d", RTL_TD_1, FIRMWARE_8168D_1,
+ JUMBO_9K, false),
[RTL_GIGA_MAC_VER_26] =
- _R("RTL8168d/8111d", RTL_TD_1, FIRMWARE_8168D_2),
+ _R("RTL8168d/8111d", RTL_TD_1, FIRMWARE_8168D_2,
+ JUMBO_9K, false),
[RTL_GIGA_MAC_VER_27] =
- _R("RTL8168dp/8111dp", RTL_TD_1, NULL),
+ _R("RTL8168dp/8111dp", RTL_TD_1, NULL, JUMBO_9K, false),
[RTL_GIGA_MAC_VER_28] =
- _R("RTL8168dp/8111dp", RTL_TD_1, NULL),
+ _R("RTL8168dp/8111dp", RTL_TD_1, NULL, JUMBO_9K, false),
[RTL_GIGA_MAC_VER_29] =
- _R("RTL8105e", RTL_TD_1, FIRMWARE_8105E_1),
+ _R("RTL8105e", RTL_TD_1, FIRMWARE_8105E_1,
+ JUMBO_1K, true),
[RTL_GIGA_MAC_VER_30] =
- _R("RTL8105e", RTL_TD_1, FIRMWARE_8105E_1),
+ _R("RTL8105e", RTL_TD_1, FIRMWARE_8105E_1,
+ JUMBO_1K, true),
[RTL_GIGA_MAC_VER_31] =
- _R("RTL8168dp/8111dp", RTL_TD_1, NULL),
+ _R("RTL8168dp/8111dp", RTL_TD_1, NULL, JUMBO_9K, false),
[RTL_GIGA_MAC_VER_32] =
- _R("RTL8168e/8111e", RTL_TD_1, FIRMWARE_8168E_1),
+ _R("RTL8168e/8111e", RTL_TD_1, FIRMWARE_8168E_1,
+ JUMBO_9K, false),
[RTL_GIGA_MAC_VER_33] =
- _R("RTL8168e/8111e", RTL_TD_1, FIRMWARE_8168E_2),
+ _R("RTL8168e/8111e", RTL_TD_1, FIRMWARE_8168E_2,
+ JUMBO_9K, false),
[RTL_GIGA_MAC_VER_34] =
- _R("RTL8168evl/8111evl",RTL_TD_1, FIRMWARE_8168E_3)
+ _R("RTL8168evl/8111evl",RTL_TD_1, FIRMWARE_8168E_3,
+ JUMBO_9K, false),
+ [RTL_GIGA_MAC_VER_35] =
+ _R("RTL8168f/8111f", RTL_TD_1, FIRMWARE_8168F_1,
+ JUMBO_9K, false),
+ [RTL_GIGA_MAC_VER_36] =
+ _R("RTL8168f/8111f", RTL_TD_1, FIRMWARE_8168F_2,
+ JUMBO_9K, false),
};
#undef _R
@@ -311,6 +341,7 @@ enum rtl_registers {
MaxTxPacketSize = 0xec, /* 8101/8168. Unit of 128 bytes. */
#define TxPacketMax (8064 >> 7)
+#define EarlySize 0x27
FuncEvent = 0xf0,
FuncEventMask = 0xf4,
@@ -407,6 +438,7 @@ enum rtl_register_content {
RxOK = 0x0001,
/* RxStatusDesc */
+ RxBOVF = (1 << 24),
RxFOVF = (1 << 23),
RxRWT = (1 << 22),
RxRES = (1 << 21),
@@ -459,8 +491,12 @@ enum rtl_register_content {
/* Config3 register p.25 */
MagicPacket = (1 << 5), /* Wake up when receives a Magic Packet */
LinkUp = (1 << 4), /* Wake up when the cable connection is re-established */
+ Jumbo_En0 = (1 << 2), /* 8168 only. Reserved in the 8168b */
Beacon_en = (1 << 0), /* 8168 only. Reserved in the 8168b */
+ /* Config4 register */
+ Jumbo_En1 = (1 << 1), /* 8168 only. Reserved in the 8168b */
+
/* Config5 register p.27 */
BWF = (1 << 6), /* Accept Broadcast wakeup frame */
MWF = (1 << 5), /* Accept Multicast wakeup frame */
@@ -669,6 +705,11 @@ struct rtl8169_private {
void (*up)(struct rtl8169_private *);
} pll_power_ops;
+ struct jumbo_ops {
+ void (*enable)(struct rtl8169_private *);
+ void (*disable)(struct rtl8169_private *);
+ } jumbo_ops;
+
int (*set_speed)(struct net_device *, u8 aneg, u16 sp, u8 dpx, u32 adv);
int (*get_settings)(struct net_device *, struct ethtool_cmd *);
void (*phy_reset_enable)(struct rtl8169_private *tp);
@@ -682,6 +723,7 @@ struct rtl8169_private {
struct mii_if_info mii;
struct rtl8169_counters counters;
u32 saved_wolopts;
+ u32 opts1_mask;
struct rtl_fw {
const struct firmware *fw;
@@ -710,7 +752,10 @@ MODULE_FIRMWARE(FIRMWARE_8168D_1);
MODULE_FIRMWARE(FIRMWARE_8168D_2);
MODULE_FIRMWARE(FIRMWARE_8168E_1);
MODULE_FIRMWARE(FIRMWARE_8168E_2);
+MODULE_FIRMWARE(FIRMWARE_8168E_3);
MODULE_FIRMWARE(FIRMWARE_8105E_1);
+MODULE_FIRMWARE(FIRMWARE_8168F_1);
+MODULE_FIRMWARE(FIRMWARE_8168F_2);
static int rtl8169_open(struct net_device *dev);
static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
@@ -729,6 +774,19 @@ static void rtl8169_down(struct net_device *dev);
static void rtl8169_rx_clear(struct rtl8169_private *tp);
static int rtl8169_poll(struct napi_struct *napi, int budget);
+static void rtl_tx_performance_tweak(struct pci_dev *pdev, u16 force)
+{
+ int cap = pci_pcie_cap(pdev);
+
+ if (cap) {
+ u16 ctl;
+
+ pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl);
+ ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | force;
+ pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl);
+ }
+}
+
static u32 ocp_read(struct rtl8169_private *tp, u8 mask, u16 reg)
{
void __iomem *ioaddr = tp->mmio_addr;
@@ -1199,6 +1257,19 @@ static void rtl_link_chg_patch(struct rtl8169_private *tp)
ERIAR_EXGMAC);
rtl_w1w0_eri(ioaddr, 0xdc, ERIAR_MASK_0001, 0x01, 0x00,
ERIAR_EXGMAC);
+ } else if (tp->mac_version == RTL_GIGA_MAC_VER_35 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_36) {
+ if (RTL_R8(PHYstatus) & _1000bpsF) {
+ rtl_eri_write(ioaddr, 0x1bc, ERIAR_MASK_1111,
+ 0x00000011, ERIAR_EXGMAC);
+ rtl_eri_write(ioaddr, 0x1dc, ERIAR_MASK_1111,
+ 0x00000005, ERIAR_EXGMAC);
+ } else {
+ rtl_eri_write(ioaddr, 0x1bc, ERIAR_MASK_1111,
+ 0x0000001f, ERIAR_EXGMAC);
+ rtl_eri_write(ioaddr, 0x1dc, ERIAR_MASK_1111,
+ 0x0000003f, ERIAR_EXGMAC);
+ }
}
}
@@ -1484,9 +1555,15 @@ static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
static u32 rtl8169_fix_features(struct net_device *dev, u32 features)
{
+ struct rtl8169_private *tp = netdev_priv(dev);
+
if (dev->mtu > TD_MSS_MAX)
features &= ~NETIF_F_ALL_TSO;
+ if (dev->mtu > JUMBO_1K &&
+ !rtl_chip_infos[tp->mac_version].jumbo_tx_csum)
+ features &= ~NETIF_F_IP_CSUM;
+
return features;
}
@@ -1738,6 +1815,10 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
u32 val;
int mac_version;
} mac_info[] = {
+ /* 8168F family. */
+ { 0x7cf00000, 0x48100000, RTL_GIGA_MAC_VER_36 },
+ { 0x7cf00000, 0x48000000, RTL_GIGA_MAC_VER_35 },
+
/* 8168E family. */
{ 0x7c800000, 0x2c800000, RTL_GIGA_MAC_VER_34 },
{ 0x7cf00000, 0x2c200000, RTL_GIGA_MAC_VER_33 },
@@ -2856,7 +2937,7 @@ static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp)
rtl_writephy(tp, 0x1f, 0x0004);
rtl_writephy(tp, 0x1f, 0x0007);
rtl_writephy(tp, 0x1e, 0x0020);
- rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
+ rtl_w1w0_phy(tp, 0x15, 0x0000, 0x0100);
rtl_writephy(tp, 0x1f, 0x0002);
rtl_writephy(tp, 0x1f, 0x0000);
rtl_writephy(tp, 0x0d, 0x0007);
@@ -2872,6 +2953,97 @@ static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp)
rtl_writephy(tp, 0x1f, 0x0000);
}
+static void rtl8168f_1_hw_phy_config(struct rtl8169_private *tp)
+{
+ static const struct phy_reg phy_reg_init[] = {
+ /* Channel estimation fine tune */
+ { 0x1f, 0x0003 },
+ { 0x09, 0xa20f },
+ { 0x1f, 0x0000 },
+
+ /* Modify green table for giga & fnet */
+ { 0x1f, 0x0005 },
+ { 0x05, 0x8b55 },
+ { 0x06, 0x0000 },
+ { 0x05, 0x8b5e },
+ { 0x06, 0x0000 },
+ { 0x05, 0x8b67 },
+ { 0x06, 0x0000 },
+ { 0x05, 0x8b70 },
+ { 0x06, 0x0000 },
+ { 0x1f, 0x0000 },
+ { 0x1f, 0x0007 },
+ { 0x1e, 0x0078 },
+ { 0x17, 0x0000 },
+ { 0x19, 0x00fb },
+ { 0x1f, 0x0000 },
+
+ /* Modify green table for 10M */
+ { 0x1f, 0x0005 },
+ { 0x05, 0x8b79 },
+ { 0x06, 0xaa00 },
+ { 0x1f, 0x0000 },
+
+ /* Disable hiimpedance detection (RTCT) */
+ { 0x1f, 0x0003 },
+ { 0x01, 0x328a },
+ { 0x1f, 0x0000 }
+ };
+
+ rtl_apply_firmware(tp);
+
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+ /* For 4-corner performance improve */
+ rtl_writephy(tp, 0x1f, 0x0005);
+ rtl_writephy(tp, 0x05, 0x8b80);
+ rtl_w1w0_phy(tp, 0x06, 0x0006, 0x0000);
+ rtl_writephy(tp, 0x1f, 0x0000);
+
+ /* PHY auto speed down */
+ rtl_writephy(tp, 0x1f, 0x0007);
+ rtl_writephy(tp, 0x1e, 0x002d);
+ rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000);
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
+
+ /* Improve 10M EEE waveform */
+ rtl_writephy(tp, 0x1f, 0x0005);
+ rtl_writephy(tp, 0x05, 0x8b86);
+ rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
+ rtl_writephy(tp, 0x1f, 0x0000);
+
+ /* Improve 2-pair detection performance */
+ rtl_writephy(tp, 0x1f, 0x0005);
+ rtl_writephy(tp, 0x05, 0x8b85);
+ rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
+ rtl_writephy(tp, 0x1f, 0x0000);
+}
+
+static void rtl8168f_2_hw_phy_config(struct rtl8169_private *tp)
+{
+ rtl_apply_firmware(tp);
+
+ /* For 4-corner performance improve */
+ rtl_writephy(tp, 0x1f, 0x0005);
+ rtl_writephy(tp, 0x05, 0x8b80);
+ rtl_w1w0_phy(tp, 0x06, 0x0006, 0x0000);
+ rtl_writephy(tp, 0x1f, 0x0000);
+
+ /* PHY auto speed down */
+ rtl_writephy(tp, 0x1f, 0x0007);
+ rtl_writephy(tp, 0x1e, 0x002d);
+ rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000);
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
+
+ /* Improve 10M EEE waveform */
+ rtl_writephy(tp, 0x1f, 0x0005);
+ rtl_writephy(tp, 0x05, 0x8b86);
+ rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
+ rtl_writephy(tp, 0x1f, 0x0000);
+}
+
static void rtl8102e_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
@@ -2996,6 +3168,12 @@ static void rtl_hw_phy_config(struct net_device *dev)
case RTL_GIGA_MAC_VER_34:
rtl8168e_2_hw_phy_config(tp);
break;
+ case RTL_GIGA_MAC_VER_35:
+ rtl8168f_1_hw_phy_config(tp);
+ break;
+ case RTL_GIGA_MAC_VER_36:
+ rtl8168f_2_hw_phy_config(tp);
+ break;
default:
break;
@@ -3077,6 +3255,14 @@ static void rtl8169_phy_reset(struct net_device *dev,
netif_err(tp, link, dev, "PHY reset failed\n");
}
+static bool rtl_tbi_enabled(struct rtl8169_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+
+ return (tp->mac_version == RTL_GIGA_MAC_VER_01) &&
+ (RTL_R8(PHYstatus) & TBI_Enable);
+}
+
static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
{
void __iomem *ioaddr = tp->mmio_addr;
@@ -3109,7 +3295,7 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
ADVERTISED_1000baseT_Half |
ADVERTISED_1000baseT_Full : 0));
- if (RTL_R8(PHYstatus) & TBI_Enable)
+ if (rtl_tbi_enabled(tp))
netif_info(tp, link, dev, "TBI auto-negotiating\n");
}
@@ -3277,7 +3463,7 @@ static const struct net_device_ops rtl8169_netdev_ops = {
.ndo_set_features = rtl8169_set_features,
.ndo_set_mac_address = rtl_set_mac_address,
.ndo_do_ioctl = rtl8169_ioctl,
- .ndo_set_multicast_list = rtl_set_rx_mode,
+ .ndo_set_rx_mode = rtl_set_rx_mode,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = rtl8169_netpoll,
#endif
@@ -3305,6 +3491,37 @@ static void __devinit rtl_init_mdio_ops(struct rtl8169_private *tp)
}
}
+static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_29:
+ case RTL_GIGA_MAC_VER_30:
+ case RTL_GIGA_MAC_VER_32:
+ case RTL_GIGA_MAC_VER_33:
+ case RTL_GIGA_MAC_VER_34:
+ RTL_W32(RxConfig, RTL_R32(RxConfig) |
+ AcceptBroadcast | AcceptMulticast | AcceptMyPhys);
+ break;
+ default:
+ break;
+ }
+}
+
+static bool rtl_wol_pll_power_down(struct rtl8169_private *tp)
+{
+ if (!(__rtl8169_get_wol(tp) & WAKE_ANY))
+ return false;
+
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_writephy(tp, MII_BMCR, 0x0000);
+
+ rtl_wol_suspend_quirk(tp);
+
+ return true;
+}
+
static void r810x_phy_power_down(struct rtl8169_private *tp)
{
rtl_writephy(tp, 0x1f, 0x0000);
@@ -3319,11 +3536,8 @@ static void r810x_phy_power_up(struct rtl8169_private *tp)
static void r810x_pll_power_down(struct rtl8169_private *tp)
{
- if (__rtl8169_get_wol(tp) & WAKE_ANY) {
- rtl_writephy(tp, 0x1f, 0x0000);
- rtl_writephy(tp, MII_BMCR, 0x0000);
+ if (rtl_wol_pll_power_down(tp))
return;
- }
r810x_phy_power_down(tp);
}
@@ -3412,16 +3626,8 @@ static void r8168_pll_power_down(struct rtl8169_private *tp)
tp->mac_version == RTL_GIGA_MAC_VER_33)
rtl_ephy_write(ioaddr, 0x19, 0xff64);
- if (__rtl8169_get_wol(tp) & WAKE_ANY) {
- rtl_writephy(tp, 0x1f, 0x0000);
- rtl_writephy(tp, MII_BMCR, 0x0000);
-
- if (tp->mac_version == RTL_GIGA_MAC_VER_32 ||
- tp->mac_version == RTL_GIGA_MAC_VER_33)
- RTL_W32(RxConfig, RTL_R32(RxConfig) | AcceptBroadcast |
- AcceptMulticast | AcceptMyPhys);
+ if (rtl_wol_pll_power_down(tp))
return;
- }
r8168_phy_power_down(tp);
@@ -3464,8 +3670,8 @@ static void r8168_pll_power_up(struct rtl8169_private *tp)
r8168_phy_power_up(tp);
}
-static void rtl_pll_power_op(struct rtl8169_private *tp,
- void (*op)(struct rtl8169_private *))
+static void rtl_generic_op(struct rtl8169_private *tp,
+ void (*op)(struct rtl8169_private *))
{
if (op)
op(tp);
@@ -3473,12 +3679,12 @@ static void rtl_pll_power_op(struct rtl8169_private *tp,
static void rtl_pll_power_down(struct rtl8169_private *tp)
{
- rtl_pll_power_op(tp, tp->pll_power_ops.down);
+ rtl_generic_op(tp, tp->pll_power_ops.down);
}
static void rtl_pll_power_up(struct rtl8169_private *tp)
{
- rtl_pll_power_op(tp, tp->pll_power_ops.up);
+ rtl_generic_op(tp, tp->pll_power_ops.up);
}
static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp)
@@ -3515,6 +3721,8 @@ static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp)
case RTL_GIGA_MAC_VER_32:
case RTL_GIGA_MAC_VER_33:
case RTL_GIGA_MAC_VER_34:
+ case RTL_GIGA_MAC_VER_35:
+ case RTL_GIGA_MAC_VER_36:
ops->down = r8168_pll_power_down;
ops->up = r8168_pll_power_up;
break;
@@ -3567,6 +3775,150 @@ static void rtl8169_init_ring_indexes(struct rtl8169_private *tp)
tp->dirty_tx = tp->dirty_rx = tp->cur_tx = tp->cur_rx = 0;
}
+static void rtl_hw_jumbo_enable(struct rtl8169_private *tp)
+{
+ rtl_generic_op(tp, tp->jumbo_ops.enable);
+}
+
+static void rtl_hw_jumbo_disable(struct rtl8169_private *tp)
+{
+ rtl_generic_op(tp, tp->jumbo_ops.disable);
+}
+
+static void r8168c_hw_jumbo_enable(struct rtl8169_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+
+ RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
+ RTL_W8(Config4, RTL_R8(Config4) | Jumbo_En1);
+ rtl_tx_performance_tweak(tp->pci_dev, 0x2 << MAX_READ_REQUEST_SHIFT);
+}
+
+static void r8168c_hw_jumbo_disable(struct rtl8169_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+
+ RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
+ RTL_W8(Config4, RTL_R8(Config4) & ~Jumbo_En1);
+ rtl_tx_performance_tweak(tp->pci_dev, 0x5 << MAX_READ_REQUEST_SHIFT);
+}
+
+static void r8168dp_hw_jumbo_enable(struct rtl8169_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+
+ RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
+}
+
+static void r8168dp_hw_jumbo_disable(struct rtl8169_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+
+ RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
+}
+
+static void r8168e_hw_jumbo_enable(struct rtl8169_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+ struct pci_dev *pdev = tp->pci_dev;
+
+ RTL_W8(MaxTxPacketSize, 0x3f);
+ RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
+ RTL_W8(Config4, RTL_R8(Config4) | 0x01);
+ pci_write_config_byte(pdev, 0x79, 0x20);
+}
+
+static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+ struct pci_dev *pdev = tp->pci_dev;
+
+ RTL_W8(MaxTxPacketSize, 0x0c);
+ RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
+ RTL_W8(Config4, RTL_R8(Config4) & ~0x01);
+ pci_write_config_byte(pdev, 0x79, 0x50);
+}
+
+static void r8168b_0_hw_jumbo_enable(struct rtl8169_private *tp)
+{
+ rtl_tx_performance_tweak(tp->pci_dev,
+ (0x2 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
+}
+
+static void r8168b_0_hw_jumbo_disable(struct rtl8169_private *tp)
+{
+ rtl_tx_performance_tweak(tp->pci_dev,
+ (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
+}
+
+static void r8168b_1_hw_jumbo_enable(struct rtl8169_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+
+ r8168b_0_hw_jumbo_enable(tp);
+
+ RTL_W8(Config4, RTL_R8(Config4) | (1 << 0));
+}
+
+static void r8168b_1_hw_jumbo_disable(struct rtl8169_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+
+ r8168b_0_hw_jumbo_disable(tp);
+
+ RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
+}
+
+static void __devinit rtl_init_jumbo_ops(struct rtl8169_private *tp)
+{
+ struct jumbo_ops *ops = &tp->jumbo_ops;
+
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_11:
+ ops->disable = r8168b_0_hw_jumbo_disable;
+ ops->enable = r8168b_0_hw_jumbo_enable;
+ break;
+ case RTL_GIGA_MAC_VER_12:
+ case RTL_GIGA_MAC_VER_17:
+ ops->disable = r8168b_1_hw_jumbo_disable;
+ ops->enable = r8168b_1_hw_jumbo_enable;
+ break;
+ case RTL_GIGA_MAC_VER_18: /* Wild guess. Needs info from Realtek. */
+ case RTL_GIGA_MAC_VER_19:
+ case RTL_GIGA_MAC_VER_20:
+ case RTL_GIGA_MAC_VER_21: /* Wild guess. Needs info from Realtek. */
+ case RTL_GIGA_MAC_VER_22:
+ case RTL_GIGA_MAC_VER_23:
+ case RTL_GIGA_MAC_VER_24:
+ case RTL_GIGA_MAC_VER_25:
+ case RTL_GIGA_MAC_VER_26:
+ ops->disable = r8168c_hw_jumbo_disable;
+ ops->enable = r8168c_hw_jumbo_enable;
+ break;
+ case RTL_GIGA_MAC_VER_27:
+ case RTL_GIGA_MAC_VER_28:
+ ops->disable = r8168dp_hw_jumbo_disable;
+ ops->enable = r8168dp_hw_jumbo_enable;
+ break;
+ case RTL_GIGA_MAC_VER_31: /* Wild guess. Needs info from Realtek. */
+ case RTL_GIGA_MAC_VER_32:
+ case RTL_GIGA_MAC_VER_33:
+ case RTL_GIGA_MAC_VER_34:
+ ops->disable = r8168e_hw_jumbo_disable;
+ ops->enable = r8168e_hw_jumbo_enable;
+ break;
+
+ /*
+ * No action needed for jumbo frames with 8169.
+ * No jumbo for 810x at all.
+ */
+ default:
+ ops->disable = NULL;
+ ops->enable = NULL;
+ break;
+ }
+}
+
static void rtl_hw_reset(struct rtl8169_private *tp)
{
void __iomem *ioaddr = tp->mmio_addr;
@@ -3711,6 +4063,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rtl_init_mdio_ops(tp);
rtl_init_pll_power_ops(tp);
+ rtl_init_jumbo_ops(tp);
rtl8169_print_mac_version(tp);
@@ -3727,8 +4080,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
tp->features |= rtl_try_msi(pdev, ioaddr, cfg);
RTL_W8(Cfg9346, Cfg9346_Lock);
- if ((tp->mac_version <= RTL_GIGA_MAC_VER_06) &&
- (RTL_R8(PHYstatus) & TBI_Enable)) {
+ if (rtl_tbi_enabled(tp)) {
tp->set_speed = rtl8169_set_speed_tbi;
tp->get_settings = rtl8169_gset_tbi;
tp->phy_reset_enable = rtl8169_tbi_reset_enable;
@@ -3777,6 +4129,9 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
tp->intr_event = cfg->intr_event;
tp->napi_event = cfg->napi_event;
+ tp->opts1_mask = (tp->mac_version != RTL_GIGA_MAC_VER_01) ?
+ ~(RxBOVF | RxFOVF) : ~0;
+
init_timer(&tp->timer);
tp->timer.data = (unsigned long) dev;
tp->timer.function = rtl8169_phy_timer;
@@ -3792,6 +4147,12 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
netif_info(tp, probe, dev, "%s at 0x%lx, %pM, XID %08x IRQ %d\n",
rtl_chip_infos[chipset].name, dev->base_addr, dev->dev_addr,
(u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), dev->irq);
+ if (rtl_chip_infos[chipset].jumbo_max != JUMBO_1K) {
+ netif_info(tp, probe, dev, "jumbo features [frames: %d bytes, "
+ "tx checksumming: %s]\n",
+ rtl_chip_infos[chipset].jumbo_max,
+ rtl_chip_infos[chipset].jumbo_tx_csum ? "ok" : "ko");
+ }
if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
tp->mac_version == RTL_GIGA_MAC_VER_28 ||
@@ -3987,7 +4348,10 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp)
tp->mac_version == RTL_GIGA_MAC_VER_31) {
while (RTL_R8(TxPoll) & NPQ)
udelay(20);
- } else if (tp->mac_version == RTL_GIGA_MAC_VER_34) {
+ } else if (tp->mac_version == RTL_GIGA_MAC_VER_34 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_35 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_36) {
+ RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
while (!(RTL_R32(TxConfig) & TXCFG_EMPTY))
udelay(100);
} else {
@@ -4145,19 +4509,6 @@ static void rtl_hw_start_8169(struct net_device *dev)
RTL_W16(IntrMask, tp->intr_event);
}
-static void rtl_tx_performance_tweak(struct pci_dev *pdev, u16 force)
-{
- int cap = pci_pcie_cap(pdev);
-
- if (cap) {
- u16 ctl;
-
- pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl);
- ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | force;
- pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl);
- }
-}
-
static void rtl_csi_access_enable(void __iomem *ioaddr, u32 bits)
{
u32 csi;
@@ -4457,7 +4808,50 @@ static void rtl_hw_start_8168e_2(void __iomem *ioaddr, struct pci_dev *pdev)
rtl_w1w0_eri(ioaddr, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00,
ERIAR_EXGMAC);
- RTL_W8(MaxTxPacketSize, 0x27);
+ RTL_W8(MaxTxPacketSize, EarlySize);
+
+ rtl_disable_clock_request(pdev);
+
+ RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
+ RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
+
+ /* Adjust EEE LED frequency */
+ RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
+
+ RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
+ RTL_W32(MISC, RTL_R32(MISC) | PWM_EN);
+ RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
+}
+
+static void rtl_hw_start_8168f_1(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+ static const struct ephy_info e_info_8168f_1[] = {
+ { 0x06, 0x00c0, 0x0020 },
+ { 0x08, 0x0001, 0x0002 },
+ { 0x09, 0x0000, 0x0080 },
+ { 0x19, 0x0000, 0x0224 }
+ };
+
+ rtl_csi_access_enable_1(ioaddr);
+
+ rtl_ephy_init(ioaddr, e_info_8168f_1, ARRAY_SIZE(e_info_8168f_1));
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ rtl_eri_write(ioaddr, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+ rtl_eri_write(ioaddr, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+ rtl_eri_write(ioaddr, 0xc8, ERIAR_MASK_1111, 0x00100002, ERIAR_EXGMAC);
+ rtl_eri_write(ioaddr, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
+ rtl_w1w0_eri(ioaddr, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
+ rtl_w1w0_eri(ioaddr, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
+ rtl_w1w0_eri(ioaddr, 0x1b0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
+ rtl_w1w0_eri(ioaddr, 0x1d0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
+ rtl_eri_write(ioaddr, 0xcc, ERIAR_MASK_1111, 0x00000050, ERIAR_EXGMAC);
+ rtl_eri_write(ioaddr, 0xd0, ERIAR_MASK_1111, 0x00000060, ERIAR_EXGMAC);
+ rtl_w1w0_eri(ioaddr, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00,
+ ERIAR_EXGMAC);
+
+ RTL_W8(MaxTxPacketSize, EarlySize);
rtl_disable_clock_request(pdev);
@@ -4566,6 +4960,11 @@ static void rtl_hw_start_8168(struct net_device *dev)
rtl_hw_start_8168e_2(ioaddr, pdev);
break;
+ case RTL_GIGA_MAC_VER_35:
+ case RTL_GIGA_MAC_VER_36:
+ rtl_hw_start_8168f_1(ioaddr, pdev);
+ break;
+
default:
printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n",
dev->name, tp->mac_version);
@@ -4737,9 +5136,17 @@ static void rtl_hw_start_8101(struct net_device *dev)
static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
{
- if (new_mtu < ETH_ZLEN || new_mtu > SafeMtu)
+ struct rtl8169_private *tp = netdev_priv(dev);
+
+ if (new_mtu < ETH_ZLEN ||
+ new_mtu > rtl_chip_infos[tp->mac_version].jumbo_max)
return -EINVAL;
+ if (new_mtu > ETH_DATA_LEN)
+ rtl_hw_jumbo_enable(tp);
+ else
+ rtl_hw_jumbo_disable(tp);
+
dev->mtu = new_mtu;
netdev_update_features(dev);
@@ -5018,7 +5425,7 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
entry = tp->cur_tx;
for (cur_frag = 0; cur_frag < info->nr_frags; cur_frag++) {
- skb_frag_t *frag = info->frags + cur_frag;
+ const skb_frag_t *frag = info->frags + cur_frag;
dma_addr_t mapping;
u32 status, len;
void *addr;
@@ -5026,8 +5433,8 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
entry = (entry + 1) % NUM_TX_DESC;
txd = tp->TxDescArray + entry;
- len = frag->size;
- addr = ((void *) page_address(frag->page)) + frag->page_offset;
+ len = skb_frag_size(frag);
+ addr = skb_frag_address(frag);
mapping = dma_map_single(d, addr, len, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(d, mapping))) {
if (net_ratelimit())
@@ -5314,7 +5721,7 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
u32 status;
rmb();
- status = le32_to_cpu(desc->opts1);
+ status = le32_to_cpu(desc->opts1) & tp->opts1_mask;
if (status & DescOwn)
break;
@@ -5334,7 +5741,7 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
} else {
struct sk_buff *skb;
dma_addr_t addr = le64_to_cpu(desc->addr);
- int pkt_size = (status & 0x00001FFF) - 4;
+ int pkt_size = (status & 0x00003fff) - 4;
/*
* The driver does not support incoming fragmented
@@ -5766,11 +6173,30 @@ static const struct dev_pm_ops rtl8169_pm_ops = {
#endif /* !CONFIG_PM */
+static void rtl_wol_shutdown_quirk(struct rtl8169_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+
+ /* WoL fails with 8168b when the receiver is disabled. */
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_11:
+ case RTL_GIGA_MAC_VER_12:
+ case RTL_GIGA_MAC_VER_17:
+ pci_clear_master(tp->pci_dev);
+
+ RTL_W8(ChipCmd, CmdRxEnb);
+ /* PCI commit */
+ RTL_R8(ChipCmd);
+ break;
+ default:
+ break;
+ }
+}
+
static void rtl_shutdown(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct rtl8169_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
rtl8169_net_suspend(dev);
@@ -5784,16 +6210,9 @@ static void rtl_shutdown(struct pci_dev *pdev)
spin_unlock_irq(&tp->lock);
if (system_state == SYSTEM_POWER_OFF) {
- /* WoL fails with 8168b when the receiver is disabled. */
- if ((tp->mac_version == RTL_GIGA_MAC_VER_11 ||
- tp->mac_version == RTL_GIGA_MAC_VER_12 ||
- tp->mac_version == RTL_GIGA_MAC_VER_17) &&
- (tp->features & RTL_FEATURE_WOL)) {
- pci_clear_master(pdev);
-
- RTL_W8(ChipCmd, CmdRxEnb);
- /* PCI commit */
- RTL_R8(ChipCmd);
+ if (__rtl8169_get_wol(tp) & WAKE_ANY) {
+ rtl_wol_suspend_quirk(tp);
+ rtl_wol_shutdown_quirk(tp);
}
pci_wake_from_d3(pdev, true);
diff --git a/drivers/net/sc92031.c b/drivers/net/ethernet/realtek/sc92031.c
index 9da47337b7c3..a284d6440538 100644
--- a/drivers/net/sc92031.c
+++ b/drivers/net/ethernet/realtek/sc92031.c
@@ -31,6 +31,7 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
+#include <linux/mii.h>
#include <linux/crc32.h>
#include <asm/irq.h>
@@ -116,16 +117,9 @@ enum silan_registers {
TestD8 = 0xD8,
};
-#define MII_BMCR 0 // Basic mode control register
-#define MII_BMSR 1 // Basic mode status register
#define MII_JAB 16
#define MII_OutputStatus 24
-#define BMCR_FULLDPLX 0x0100 // Full duplex
-#define BMCR_ANRESTART 0x0200 // Auto negotiation restart
-#define BMCR_ANENABLE 0x1000 // Enable auto negotiation
-#define BMCR_SPEED100 0x2000 // Select 100Mbps
-#define BMSR_LSTATUS 0x0004 // Link status
#define PHY_16_JAB_ENB 0x1000
#define PHY_16_PORT_ENB 0x1
@@ -1390,7 +1384,7 @@ static const struct net_device_ops sc92031_netdev_ops = {
.ndo_start_xmit = sc92031_start_xmit,
.ndo_open = sc92031_open,
.ndo_stop = sc92031_stop,
- .ndo_set_multicast_list = sc92031_set_multicast_list,
+ .ndo_set_rx_mode = sc92031_set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/ethernet/renesas/Kconfig b/drivers/net/ethernet/renesas/Kconfig
new file mode 100644
index 000000000000..9755b49bbefb
--- /dev/null
+++ b/drivers/net/ethernet/renesas/Kconfig
@@ -0,0 +1,19 @@
+#
+# Renesas device configuration
+#
+
+config SH_ETH
+ tristate "Renesas SuperH Ethernet support"
+ depends on SUPERH && \
+ (CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712 || \
+ CPU_SUBTYPE_SH7763 || CPU_SUBTYPE_SH7619 || \
+ CPU_SUBTYPE_SH7724 || CPU_SUBTYPE_SH7757)
+ select CRC32
+ select NET_CORE
+ select MII
+ select MDIO_BITBANG
+ select PHYLIB
+ ---help---
+ Renesas SuperH Ethernet device driver.
+ This driver supporting CPUs are:
+ - SH7710, SH7712, SH7763, SH7619, SH7724, and SH7757.
diff --git a/drivers/net/ethernet/renesas/Makefile b/drivers/net/ethernet/renesas/Makefile
new file mode 100644
index 000000000000..1c278a8e066a
--- /dev/null
+++ b/drivers/net/ethernet/renesas/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Renesas device drivers.
+#
+
+obj-$(CONFIG_SH_ETH) += sh_eth.o
diff --git a/drivers/net/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index ad35c210b839..9b230740c6ab 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -21,6 +21,10 @@
*/
#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
@@ -30,9 +34,11 @@
#include <linux/phy.h>
#include <linux/cache.h>
#include <linux/io.h>
+#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/ethtool.h>
+#include <linux/sh_eth.h>
#include "sh_eth.h"
@@ -153,18 +159,18 @@ static void sh_eth_chip_reset_giga(struct net_device *ndev)
/* save MAHR and MALR */
for (i = 0; i < 2; i++) {
- malr[i] = readl(GIGA_MALR(i));
- mahr[i] = readl(GIGA_MAHR(i));
+ malr[i] = ioread32((void *)GIGA_MALR(i));
+ mahr[i] = ioread32((void *)GIGA_MAHR(i));
}
/* reset device */
- writel(ARSTR_ARSTR, SH_GIGA_ETH_BASE + 0x1800);
+ iowrite32(ARSTR_ARSTR, (void *)(SH_GIGA_ETH_BASE + 0x1800));
mdelay(1);
/* restore MAHR and MALR */
for (i = 0; i < 2; i++) {
- writel(malr[i], GIGA_MALR(i));
- writel(mahr[i], GIGA_MAHR(i));
+ iowrite32(malr[i], (void *)GIGA_MALR(i));
+ iowrite32(mahr[i], (void *)GIGA_MAHR(i));
}
}
@@ -513,9 +519,9 @@ static unsigned long sh_eth_get_edtrr_trns(struct sh_eth_private *mdp)
}
struct bb_info {
- void (*set_gate)(unsigned long addr);
+ void (*set_gate)(void *addr);
struct mdiobb_ctrl ctrl;
- u32 addr;
+ void *addr;
u32 mmd_msk;/* MMD */
u32 mdo_msk;
u32 mdi_msk;
@@ -523,21 +529,21 @@ struct bb_info {
};
/* PHY bit set */
-static void bb_set(u32 addr, u32 msk)
+static void bb_set(void *addr, u32 msk)
{
- writel(readl(addr) | msk, addr);
+ iowrite32(ioread32(addr) | msk, addr);
}
/* PHY bit clear */
-static void bb_clr(u32 addr, u32 msk)
+static void bb_clr(void *addr, u32 msk)
{
- writel((readl(addr) & ~msk), addr);
+ iowrite32((ioread32(addr) & ~msk), addr);
}
/* PHY bit read */
-static int bb_read(u32 addr, u32 msk)
+static int bb_read(void *addr, u32 msk)
{
- return (readl(addr) & msk) != 0;
+ return (ioread32(addr) & msk) != 0;
}
/* Data I/O pin control */
@@ -1678,7 +1684,7 @@ static int sh_mdio_init(struct net_device *ndev, int id,
}
/* bitbang init */
- bitbang->addr = ndev->base_addr + mdp->reg_offset[PIR];
+ bitbang->addr = mdp->addr + mdp->reg_offset[PIR];
bitbang->set_gate = pd->set_mdio_gate;
bitbang->mdi_msk = 0x08;
bitbang->mdo_msk = 0x04;
@@ -1758,7 +1764,7 @@ static const struct net_device_ops sh_eth_netdev_ops = {
.ndo_start_xmit = sh_eth_start_xmit,
.ndo_get_stats = sh_eth_get_stats,
#if defined(SH_ETH_HAS_TSU)
- .ndo_set_multicast_list = sh_eth_set_multicast_list,
+ .ndo_set_rx_mode = sh_eth_set_multicast_list,
#endif
.ndo_tx_timeout = sh_eth_tx_timeout,
.ndo_do_ioctl = sh_eth_do_ioctl,
@@ -1810,6 +1816,13 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
ether_setup(ndev);
mdp = netdev_priv(ndev);
+ mdp->addr = ioremap(res->start, resource_size(res));
+ if (mdp->addr == NULL) {
+ ret = -ENOMEM;
+ dev_err(&pdev->dev, "ioremap failed.\n");
+ goto out_release;
+ }
+
spin_lock_init(&mdp->lock);
mdp->pdev = pdev;
pm_runtime_enable(&pdev->dev);
@@ -1890,6 +1903,8 @@ out_unregister:
out_release:
/* net_dev free */
+ if (mdp && mdp->addr)
+ iounmap(mdp->addr);
if (mdp && mdp->tsu_addr)
iounmap(mdp->tsu_addr);
if (ndev)
@@ -1908,6 +1923,7 @@ static int sh_eth_drv_remove(struct platform_device *pdev)
sh_mdio_release(ndev);
unregister_netdev(ndev);
pm_runtime_disable(&pdev->dev);
+ iounmap(mdp->addr);
free_netdev(ndev);
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/net/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h
index c3048a6ba676..47877b13ffad 100644
--- a/drivers/net/sh_eth.h
+++ b/drivers/net/ethernet/renesas/sh_eth.h
@@ -23,14 +23,6 @@
#ifndef __SH_ETH_H__
#define __SH_ETH_H__
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/netdevice.h>
-#include <linux/phy.h>
-
-#include <asm/sh_eth.h>
-
#define CARDNAME "sh-eth"
#define TX_TIMEOUT (5*HZ)
#define TX_RING_SIZE 64 /* Tx ring size */
@@ -762,6 +754,7 @@ struct sh_eth_private {
struct platform_device *pdev;
struct sh_eth_cpu_data *cd;
const u16 *reg_offset;
+ void __iomem *addr;
void __iomem *tsu_addr;
dma_addr_t rx_desc_dma;
dma_addr_t tx_desc_dma;
@@ -811,7 +804,7 @@ static inline void sh_eth_write(struct net_device *ndev, unsigned long data,
{
struct sh_eth_private *mdp = netdev_priv(ndev);
- writel(data, ndev->base_addr + mdp->reg_offset[enum_index]);
+ iowrite32(data, mdp->addr + mdp->reg_offset[enum_index]);
}
static inline unsigned long sh_eth_read(struct net_device *ndev,
@@ -819,19 +812,19 @@ static inline unsigned long sh_eth_read(struct net_device *ndev,
{
struct sh_eth_private *mdp = netdev_priv(ndev);
- return readl(ndev->base_addr + mdp->reg_offset[enum_index]);
+ return ioread32(mdp->addr + mdp->reg_offset[enum_index]);
}
static inline void sh_eth_tsu_write(struct sh_eth_private *mdp,
unsigned long data, int enum_index)
{
- writel(data, mdp->tsu_addr + mdp->reg_offset[enum_index]);
+ iowrite32(data, mdp->tsu_addr + mdp->reg_offset[enum_index]);
}
static inline unsigned long sh_eth_tsu_read(struct sh_eth_private *mdp,
int enum_index)
{
- return readl(mdp->tsu_addr + mdp->reg_offset[enum_index]);
+ return ioread32(mdp->tsu_addr + mdp->reg_offset[enum_index]);
}
#endif /* #ifndef __SH_ETH_H__ */
diff --git a/drivers/net/s6gmac.c b/drivers/net/ethernet/s6gmac.c
index a7ff8ea342b4..a7ff8ea342b4 100644
--- a/drivers/net/s6gmac.c
+++ b/drivers/net/ethernet/s6gmac.c
diff --git a/drivers/net/ethernet/seeq/Kconfig b/drivers/net/ethernet/seeq/Kconfig
new file mode 100644
index 000000000000..29f18533fdc7
--- /dev/null
+++ b/drivers/net/ethernet/seeq/Kconfig
@@ -0,0 +1,47 @@
+#
+# SEEQ device configuration
+#
+
+config NET_VENDOR_SEEQ
+ bool "SEEQ devices"
+ default y
+ depends on HAS_IOMEM
+ depends on (ARM && ARCH_ACORN) || SGI_HAS_SEEQ || EXPERIMENTAL
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about SEEQ devices. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_SEEQ
+
+config ARM_ETHER3
+ tristate "Acorn/ANT Ether3 support"
+ depends on ARM && ARCH_ACORN
+ ---help---
+ If you have an Acorn system with one of these network cards, you
+ should say Y to this option if you wish to use it with Linux.
+
+config SEEQ8005
+ tristate "SEEQ8005 support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ ---help---
+ This is a driver for the SEEQ 8005 network (Ethernet) card. If this
+ is for you, read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called seeq8005.
+
+config SGISEEQ
+ tristate "SGI Seeq ethernet controller support"
+ depends on SGI_HAS_SEEQ
+ ---help---
+ Say Y here if you have an Seeq based Ethernet network card. This is
+ used in many Silicon Graphics machines.
+
+endif # NET_VENDOR_SEEQ
diff --git a/drivers/net/ethernet/seeq/Makefile b/drivers/net/ethernet/seeq/Makefile
new file mode 100644
index 000000000000..3e258a580c05
--- /dev/null
+++ b/drivers/net/ethernet/seeq/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the SEEQ network device drivers
+#
+
+obj-$(CONFIG_ARM_ETHER3) += ether3.o
+obj-$(CONFIG_SEEQ8005) += seeq8005.o
+obj-$(CONFIG_SGISEEQ) += sgiseeq.o
diff --git a/drivers/net/arm/ether3.c b/drivers/net/ethernet/seeq/ether3.c
index 44a8746f4014..893c880dadf0 100644
--- a/drivers/net/arm/ether3.c
+++ b/drivers/net/ethernet/seeq/ether3.c
@@ -761,7 +761,7 @@ static const struct net_device_ops ether3_netdev_ops = {
.ndo_open = ether3_open,
.ndo_stop = ether3_close,
.ndo_start_xmit = ether3_sendpacket,
- .ndo_set_multicast_list = ether3_setmulticastlist,
+ .ndo_set_rx_mode = ether3_setmulticastlist,
.ndo_tx_timeout = ether3_timeout,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/arm/ether3.h b/drivers/net/ethernet/seeq/ether3.h
index 2db63b08bdf3..2db63b08bdf3 100644
--- a/drivers/net/arm/ether3.h
+++ b/drivers/net/ethernet/seeq/ether3.h
diff --git a/drivers/net/seeq8005.c b/drivers/net/ethernet/seeq/seeq8005.c
index d2fce98f557f..60561451789b 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/ethernet/seeq/seeq8005.c
@@ -148,7 +148,7 @@ static const struct net_device_ops seeq8005_netdev_ops = {
.ndo_stop = seeq8005_close,
.ndo_start_xmit = seeq8005_send_packet,
.ndo_tx_timeout = seeq8005_timeout,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/seeq8005.h b/drivers/net/ethernet/seeq/seeq8005.h
index 5dfb0098c6ca..5dfb0098c6ca 100644
--- a/drivers/net/seeq8005.h
+++ b/drivers/net/ethernet/seeq/seeq8005.h
diff --git a/drivers/net/sgiseeq.c b/drivers/net/ethernet/seeq/sgiseeq.c
index 52fb7ed9f365..c3673f151a41 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/ethernet/seeq/sgiseeq.c
@@ -715,7 +715,7 @@ static const struct net_device_ops sgiseeq_netdev_ops = {
.ndo_stop = sgiseeq_close,
.ndo_start_xmit = sgiseeq_start_xmit,
.ndo_tx_timeout = timeout,
- .ndo_set_multicast_list = sgiseeq_set_multicast,
+ .ndo_set_rx_mode = sgiseeq_set_multicast,
.ndo_set_mac_address = sgiseeq_set_mac_address,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/sgiseeq.h b/drivers/net/ethernet/seeq/sgiseeq.h
index 2211e2987a8d..2211e2987a8d 100644
--- a/drivers/net/sgiseeq.h
+++ b/drivers/net/ethernet/seeq/sgiseeq.h
diff --git a/drivers/net/sfc/Kconfig b/drivers/net/ethernet/sfc/Kconfig
index a3d5bb9e39dc..5d18841f0f3d 100644
--- a/drivers/net/sfc/Kconfig
+++ b/drivers/net/ethernet/sfc/Kconfig
@@ -5,7 +5,7 @@ config SFC
select CRC32
select I2C
select I2C_ALGOBIT
- help
+ ---help---
This driver supports 10-gigabit Ethernet cards based on
the Solarflare SFC4000 and SFC9000-family controllers.
@@ -15,7 +15,7 @@ config SFC_MTD
bool "Solarflare SFC4000/SFC9000-family MTD support"
depends on SFC && MTD && !(SFC=y && MTD=m)
default y
- help
+ ---help---
This exposes the on-board flash memory as MTD devices (e.g.
/dev/mtd1). This makes it possible to upload new firmware
to the NIC.
diff --git a/drivers/net/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile
index ab31c7124db1..ab31c7124db1 100644
--- a/drivers/net/sfc/Makefile
+++ b/drivers/net/ethernet/sfc/Makefile
diff --git a/drivers/net/sfc/bitfield.h b/drivers/net/ethernet/sfc/bitfield.h
index 098ac2ad757d..098ac2ad757d 100644
--- a/drivers/net/sfc/bitfield.h
+++ b/drivers/net/ethernet/sfc/bitfield.h
diff --git a/drivers/net/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index faca764aa21b..de9afebe1830 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -1050,7 +1050,6 @@ static int efx_init_io(struct efx_nic *efx)
{
struct pci_dev *pci_dev = efx->pci_dev;
dma_addr_t dma_mask = efx->type->max_dma_mask;
- bool use_wc;
int rc;
netif_dbg(efx, probe, efx->net_dev, "initialising I/O\n");
@@ -1101,21 +1100,8 @@ static int efx_init_io(struct efx_nic *efx)
rc = -EIO;
goto fail3;
}
-
- /* bug22643: If SR-IOV is enabled then tx push over a write combined
- * mapping is unsafe. We need to disable write combining in this case.
- * MSI is unsupported when SR-IOV is enabled, and the firmware will
- * have removed the MSI capability. So write combining is safe if
- * there is an MSI capability.
- */
- use_wc = (!EFX_WORKAROUND_22643(efx) ||
- pci_find_capability(pci_dev, PCI_CAP_ID_MSI));
- if (use_wc)
- efx->membase = ioremap_wc(efx->membase_phys,
- efx->type->mem_map_size);
- else
- efx->membase = ioremap_nocache(efx->membase_phys,
- efx->type->mem_map_size);
+ efx->membase = ioremap_nocache(efx->membase_phys,
+ efx->type->mem_map_size);
if (!efx->membase) {
netif_err(efx, probe, efx->net_dev,
"could not map memory BAR at %llx+%x\n",
@@ -1357,7 +1343,8 @@ static int efx_probe_nic(struct efx_nic *efx)
netif_set_real_num_rx_queues(efx->net_dev, efx->n_rx_channels);
/* Initialise the interrupt moderation settings */
- efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec, true);
+ efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec, true,
+ true);
return 0;
@@ -1556,18 +1543,19 @@ static void efx_remove_all(struct efx_nic *efx)
*
**************************************************************************/
-static unsigned irq_mod_ticks(int usecs, int resolution)
+static unsigned int irq_mod_ticks(unsigned int usecs, unsigned int resolution)
{
- if (usecs <= 0)
- return 0; /* cannot receive interrupts ahead of time :-) */
+ if (usecs == 0)
+ return 0;
if (usecs < resolution)
return 1; /* never round down to 0 */
return usecs / resolution;
}
/* Set interrupt moderation parameters */
-void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs,
- bool rx_adaptive)
+int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs,
+ unsigned int rx_usecs, bool rx_adaptive,
+ bool rx_may_override_tx)
{
struct efx_channel *channel;
unsigned tx_ticks = irq_mod_ticks(tx_usecs, EFX_IRQ_MOD_RESOLUTION);
@@ -1575,6 +1563,16 @@ void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs,
EFX_ASSERT_RESET_SERIALISED(efx);
+ if (tx_ticks > EFX_IRQ_MOD_MAX || rx_ticks > EFX_IRQ_MOD_MAX)
+ return -EINVAL;
+
+ if (tx_ticks != rx_ticks && efx->tx_channel_offset == 0 &&
+ !rx_may_override_tx) {
+ netif_err(efx, drv, efx->net_dev, "Channels are shared. "
+ "RX and TX IRQ moderation must be equal\n");
+ return -EINVAL;
+ }
+
efx->irq_rx_adaptive = rx_adaptive;
efx->irq_rx_moderation = rx_ticks;
efx_for_each_channel(channel, efx) {
@@ -1583,6 +1581,26 @@ void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs,
else if (efx_channel_has_tx_queues(channel))
channel->irq_moderation = tx_ticks;
}
+
+ return 0;
+}
+
+void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs,
+ unsigned int *rx_usecs, bool *rx_adaptive)
+{
+ *rx_adaptive = efx->irq_rx_adaptive;
+ *rx_usecs = efx->irq_rx_moderation * EFX_IRQ_MOD_RESOLUTION;
+
+ /* If channels are shared between RX and TX, so is IRQ
+ * moderation. Otherwise, IRQ moderation is the same for all
+ * TX channels and is not adaptive.
+ */
+ if (efx->tx_channel_offset == 0)
+ *tx_usecs = *rx_usecs;
+ else
+ *tx_usecs =
+ efx->channel[efx->tx_channel_offset]->irq_moderation *
+ EFX_IRQ_MOD_RESOLUTION;
}
/**************************************************************************
@@ -1903,7 +1921,7 @@ static const struct net_device_ops efx_netdev_ops = {
.ndo_do_ioctl = efx_ioctl,
.ndo_change_mtu = efx_change_mtu,
.ndo_set_mac_address = efx_set_mac_address,
- .ndo_set_multicast_list = efx_set_multicast_list,
+ .ndo_set_rx_mode = efx_set_multicast_list,
.ndo_set_features = efx_set_features,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = efx_netpoll,
diff --git a/drivers/net/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h
index b0d1209ea18d..442f4d0c247d 100644
--- a/drivers/net/sfc/efx.h
+++ b/drivers/net/ethernet/sfc/efx.h
@@ -111,8 +111,11 @@ extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok);
/* Global */
extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type);
-extern void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs,
- int rx_usecs, bool rx_adaptive);
+extern int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs,
+ unsigned int rx_usecs, bool rx_adaptive,
+ bool rx_may_override_tx);
+extern void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs,
+ unsigned int *rx_usecs, bool *rx_adaptive);
/* Dummy PHY ops for PHY drivers */
extern int efx_port_dummy_op_int(struct efx_nic *efx);
diff --git a/drivers/net/sfc/enum.h b/drivers/net/ethernet/sfc/enum.h
index d725a8fbe1a6..d725a8fbe1a6 100644
--- a/drivers/net/sfc/enum.h
+++ b/drivers/net/ethernet/sfc/enum.h
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c
index bc4643af6dd1..f3cd96dfa398 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/ethernet/sfc/ethtool.c
@@ -586,72 +586,89 @@ static int efx_ethtool_nway_reset(struct net_device *net_dev)
return mdio45_nway_restart(&efx->mdio);
}
+/*
+ * Each channel has a single IRQ and moderation timer, started by any
+ * completion (or other event). Unless the module parameter
+ * separate_tx_channels is set, IRQs and moderation are therefore
+ * shared between RX and TX completions. In this case, when RX IRQ
+ * moderation is explicitly changed then TX IRQ moderation is
+ * automatically changed too, but otherwise we fail if the two values
+ * are requested to be different.
+ *
+ * The hardware does not support a limit on the number of completions
+ * before an IRQ, so we do not use the max_frames fields. We should
+ * report and require that max_frames == (usecs != 0), but this would
+ * invalidate existing user documentation.
+ *
+ * The hardware does not have distinct settings for interrupt
+ * moderation while the previous IRQ is being handled, so we should
+ * not use the 'irq' fields. However, an earlier developer
+ * misunderstood the meaning of the 'irq' fields and the driver did
+ * not support the standard fields. To avoid invalidating existing
+ * user documentation, we report and accept changes through either the
+ * standard or 'irq' fields. If both are changed at the same time, we
+ * prefer the standard field.
+ *
+ * We implement adaptive IRQ moderation, but use a different algorithm
+ * from that assumed in the definition of struct ethtool_coalesce.
+ * Therefore we do not use any of the adaptive moderation parameters
+ * in it.
+ */
+
static int efx_ethtool_get_coalesce(struct net_device *net_dev,
struct ethtool_coalesce *coalesce)
{
struct efx_nic *efx = netdev_priv(net_dev);
- struct efx_channel *channel;
-
- memset(coalesce, 0, sizeof(*coalesce));
-
- /* Find lowest IRQ moderation across all used TX queues */
- coalesce->tx_coalesce_usecs_irq = ~((u32) 0);
- efx_for_each_channel(channel, efx) {
- if (!efx_channel_has_tx_queues(channel))
- continue;
- if (channel->irq_moderation < coalesce->tx_coalesce_usecs_irq) {
- if (channel->channel < efx->n_rx_channels)
- coalesce->tx_coalesce_usecs_irq =
- channel->irq_moderation;
- else
- coalesce->tx_coalesce_usecs_irq = 0;
- }
- }
+ unsigned int tx_usecs, rx_usecs;
+ bool rx_adaptive;
- coalesce->use_adaptive_rx_coalesce = efx->irq_rx_adaptive;
- coalesce->rx_coalesce_usecs_irq = efx->irq_rx_moderation;
+ efx_get_irq_moderation(efx, &tx_usecs, &rx_usecs, &rx_adaptive);
- coalesce->tx_coalesce_usecs_irq *= EFX_IRQ_MOD_RESOLUTION;
- coalesce->rx_coalesce_usecs_irq *= EFX_IRQ_MOD_RESOLUTION;
+ coalesce->tx_coalesce_usecs = tx_usecs;
+ coalesce->tx_coalesce_usecs_irq = tx_usecs;
+ coalesce->rx_coalesce_usecs = rx_usecs;
+ coalesce->rx_coalesce_usecs_irq = rx_usecs;
+ coalesce->use_adaptive_rx_coalesce = rx_adaptive;
return 0;
}
-/* Set coalescing parameters
- * The difficulties occur for shared channels
- */
static int efx_ethtool_set_coalesce(struct net_device *net_dev,
struct ethtool_coalesce *coalesce)
{
struct efx_nic *efx = netdev_priv(net_dev);
struct efx_channel *channel;
- unsigned tx_usecs, rx_usecs, adaptive;
+ unsigned int tx_usecs, rx_usecs;
+ bool adaptive, rx_may_override_tx;
+ int rc;
if (coalesce->use_adaptive_tx_coalesce)
- return -EOPNOTSUPP;
+ return -EINVAL;
- if (coalesce->rx_coalesce_usecs || coalesce->tx_coalesce_usecs) {
- netif_err(efx, drv, efx->net_dev, "invalid coalescing setting. "
- "Only rx/tx_coalesce_usecs_irq are supported\n");
- return -EOPNOTSUPP;
- }
+ efx_get_irq_moderation(efx, &tx_usecs, &rx_usecs, &adaptive);
+
+ if (coalesce->rx_coalesce_usecs != rx_usecs)
+ rx_usecs = coalesce->rx_coalesce_usecs;
+ else
+ rx_usecs = coalesce->rx_coalesce_usecs_irq;
- rx_usecs = coalesce->rx_coalesce_usecs_irq;
- tx_usecs = coalesce->tx_coalesce_usecs_irq;
adaptive = coalesce->use_adaptive_rx_coalesce;
- /* If the channel is shared only allow RX parameters to be set */
- efx_for_each_channel(channel, efx) {
- if (efx_channel_has_rx_queue(channel) &&
- efx_channel_has_tx_queues(channel) &&
- tx_usecs) {
- netif_err(efx, drv, efx->net_dev, "Channel is shared. "
- "Only RX coalescing may be set\n");
- return -EOPNOTSUPP;
- }
- }
+ /* If channels are shared, TX IRQ moderation can be quietly
+ * overridden unless it is changed from its old value.
+ */
+ rx_may_override_tx = (coalesce->tx_coalesce_usecs == tx_usecs &&
+ coalesce->tx_coalesce_usecs_irq == tx_usecs);
+ if (coalesce->tx_coalesce_usecs != tx_usecs)
+ tx_usecs = coalesce->tx_coalesce_usecs;
+ else
+ tx_usecs = coalesce->tx_coalesce_usecs_irq;
+
+ rc = efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive,
+ rx_may_override_tx);
+ if (rc != 0)
+ return rc;
- efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive);
efx_for_each_channel(channel, efx)
efx->type->push_irq_moderation(channel);
@@ -665,12 +682,8 @@ static void efx_ethtool_get_ringparam(struct net_device *net_dev,
ring->rx_max_pending = EFX_MAX_DMAQ_SIZE;
ring->tx_max_pending = EFX_MAX_DMAQ_SIZE;
- ring->rx_mini_max_pending = 0;
- ring->rx_jumbo_max_pending = 0;
ring->rx_pending = efx->rxq_entries;
ring->tx_pending = efx->txq_entries;
- ring->rx_mini_pending = 0;
- ring->rx_jumbo_pending = 0;
}
static int efx_ethtool_set_ringparam(struct net_device *net_dev,
@@ -807,7 +820,7 @@ static int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)
static int
efx_ethtool_get_rxnfc(struct net_device *net_dev,
- struct ethtool_rxnfc *info, void *rules __always_unused)
+ struct ethtool_rxnfc *info, u32 *rules __always_unused)
{
struct efx_nic *efx = netdev_priv(net_dev);
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c
index 94bf4aaf984d..4dd1748a19c6 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/ethernet/sfc/falcon.c
@@ -104,6 +104,8 @@ static void falcon_push_irq_moderation(struct efx_channel *channel)
efx_dword_t timer_cmd;
struct efx_nic *efx = channel->efx;
+ BUILD_BUG_ON(EFX_IRQ_MOD_MAX > (1 << FRF_AB_TC_TIMER_VAL_WIDTH));
+
/* Set timer register */
if (channel->irq_moderation) {
EFX_POPULATE_DWORD_2(timer_cmd,
diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/ethernet/sfc/falcon_boards.c
index b9cc846811d6..b9cc846811d6 100644
--- a/drivers/net/sfc/falcon_boards.c
+++ b/drivers/net/ethernet/sfc/falcon_boards.c
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/ethernet/sfc/falcon_xmac.c
index 9516452c079c..9516452c079c 100644
--- a/drivers/net/sfc/falcon_xmac.c
+++ b/drivers/net/ethernet/sfc/falcon_xmac.c
diff --git a/drivers/net/sfc/filter.c b/drivers/net/ethernet/sfc/filter.c
index 2b9636f96e05..2b9636f96e05 100644
--- a/drivers/net/sfc/filter.c
+++ b/drivers/net/ethernet/sfc/filter.c
diff --git a/drivers/net/sfc/filter.h b/drivers/net/ethernet/sfc/filter.h
index 872f2132a496..872f2132a496 100644
--- a/drivers/net/sfc/filter.h
+++ b/drivers/net/ethernet/sfc/filter.h
diff --git a/drivers/net/sfc/io.h b/drivers/net/ethernet/sfc/io.h
index cc978803d484..751d1ec112cc 100644
--- a/drivers/net/sfc/io.h
+++ b/drivers/net/ethernet/sfc/io.h
@@ -103,7 +103,6 @@ static inline void efx_writeo(struct efx_nic *efx, efx_oword_t *value,
_efx_writed(efx, value->u32[2], reg + 8);
_efx_writed(efx, value->u32[3], reg + 12);
#endif
- wmb();
mmiowb();
spin_unlock_irqrestore(&efx->biu_lock, flags);
}
@@ -126,7 +125,6 @@ static inline void efx_sram_writeq(struct efx_nic *efx, void __iomem *membase,
__raw_writel((__force u32)value->u32[0], membase + addr);
__raw_writel((__force u32)value->u32[1], membase + addr + 4);
#endif
- wmb();
mmiowb();
spin_unlock_irqrestore(&efx->biu_lock, flags);
}
@@ -141,7 +139,6 @@ static inline void efx_writed(struct efx_nic *efx, efx_dword_t *value,
/* No lock required */
_efx_writed(efx, value->u32[0], reg);
- wmb();
}
/* Read a 128-bit CSR, locking as appropriate. */
@@ -152,7 +149,6 @@ static inline void efx_reado(struct efx_nic *efx, efx_oword_t *value,
spin_lock_irqsave(&efx->biu_lock, flags);
value->u32[0] = _efx_readd(efx, reg + 0);
- rmb();
value->u32[1] = _efx_readd(efx, reg + 4);
value->u32[2] = _efx_readd(efx, reg + 8);
value->u32[3] = _efx_readd(efx, reg + 12);
@@ -175,7 +171,6 @@ static inline void efx_sram_readq(struct efx_nic *efx, void __iomem *membase,
value->u64[0] = (__force __le64)__raw_readq(membase + addr);
#else
value->u32[0] = (__force __le32)__raw_readl(membase + addr);
- rmb();
value->u32[1] = (__force __le32)__raw_readl(membase + addr + 4);
#endif
spin_unlock_irqrestore(&efx->biu_lock, flags);
@@ -249,7 +244,6 @@ static inline void _efx_writeo_page(struct efx_nic *efx, efx_oword_t *value,
_efx_writed(efx, value->u32[2], reg + 8);
_efx_writed(efx, value->u32[3], reg + 12);
#endif
- wmb();
}
#define efx_writeo_page(efx, value, reg, page) \
_efx_writeo_page(efx, value, \
diff --git a/drivers/net/sfc/mac.h b/drivers/net/ethernet/sfc/mac.h
index d6a255d0856b..d6a255d0856b 100644
--- a/drivers/net/sfc/mac.h
+++ b/drivers/net/ethernet/sfc/mac.h
diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
index 3dd45ed61f0a..81a425397468 100644
--- a/drivers/net/sfc/mcdi.c
+++ b/drivers/net/ethernet/sfc/mcdi.c
@@ -50,20 +50,6 @@ static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx)
return &nic_data->mcdi;
}
-static inline void
-efx_mcdi_readd(struct efx_nic *efx, efx_dword_t *value, unsigned reg)
-{
- struct siena_nic_data *nic_data = efx->nic_data;
- value->u32[0] = (__force __le32)__raw_readl(nic_data->mcdi_smem + reg);
-}
-
-static inline void
-efx_mcdi_writed(struct efx_nic *efx, const efx_dword_t *value, unsigned reg)
-{
- struct siena_nic_data *nic_data = efx->nic_data;
- __raw_writel((__force u32)value->u32[0], nic_data->mcdi_smem + reg);
-}
-
void efx_mcdi_init(struct efx_nic *efx)
{
struct efx_mcdi_iface *mcdi;
@@ -84,8 +70,8 @@ static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd,
const u8 *inbuf, size_t inlen)
{
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
- unsigned pdu = MCDI_PDU(efx);
- unsigned doorbell = MCDI_DOORBELL(efx);
+ unsigned pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx);
+ unsigned doorbell = FR_CZ_MC_TREG_SMEM + MCDI_DOORBELL(efx);
unsigned int i;
efx_dword_t hdr;
u32 xflags, seqno;
@@ -106,28 +92,29 @@ static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd,
MCDI_HEADER_SEQ, seqno,
MCDI_HEADER_XFLAGS, xflags);
- efx_mcdi_writed(efx, &hdr, pdu);
+ efx_writed(efx, &hdr, pdu);
for (i = 0; i < inlen; i += 4)
- efx_mcdi_writed(efx, (const efx_dword_t *)(inbuf + i),
- pdu + 4 + i);
+ _efx_writed(efx, *((__le32 *)(inbuf + i)), pdu + 4 + i);
+
+ /* Ensure the payload is written out before the header */
+ wmb();
/* ring the doorbell with a distinctive value */
- EFX_POPULATE_DWORD_1(hdr, EFX_DWORD_0, 0x45789abc);
- efx_mcdi_writed(efx, &hdr, doorbell);
+ _efx_writed(efx, (__force __le32) 0x45789abc, doorbell);
}
static void efx_mcdi_copyout(struct efx_nic *efx, u8 *outbuf, size_t outlen)
{
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
- unsigned int pdu = MCDI_PDU(efx);
+ unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx);
int i;
BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT);
BUG_ON(outlen & 3 || outlen >= 0x100);
for (i = 0; i < outlen; i += 4)
- efx_mcdi_readd(efx, (efx_dword_t *)(outbuf + i), pdu + 4 + i);
+ *((__le32 *)(outbuf + i)) = _efx_readd(efx, pdu + 4 + i);
}
static int efx_mcdi_poll(struct efx_nic *efx)
@@ -135,7 +122,7 @@ static int efx_mcdi_poll(struct efx_nic *efx)
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
unsigned int time, finish;
unsigned int respseq, respcmd, error;
- unsigned int pdu = MCDI_PDU(efx);
+ unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx);
unsigned int rc, spins;
efx_dword_t reg;
@@ -161,7 +148,8 @@ static int efx_mcdi_poll(struct efx_nic *efx)
time = get_seconds();
- efx_mcdi_readd(efx, &reg, pdu);
+ rmb();
+ efx_readd(efx, &reg, pdu);
/* All 1's indicates that shared memory is in reset (and is
* not a valid header). Wait for it to come out reset before
@@ -188,7 +176,7 @@ static int efx_mcdi_poll(struct efx_nic *efx)
respseq, mcdi->seqno);
rc = EIO;
} else if (error) {
- efx_mcdi_readd(efx, &reg, pdu + 4);
+ efx_readd(efx, &reg, pdu + 4);
switch (EFX_DWORD_FIELD(reg, EFX_DWORD_0)) {
#define TRANSLATE_ERROR(name) \
case MC_CMD_ERR_ ## name: \
@@ -222,21 +210,21 @@ out:
/* Test and clear MC-rebooted flag for this port/function */
int efx_mcdi_poll_reboot(struct efx_nic *efx)
{
- unsigned int addr = MCDI_REBOOT_FLAG(efx);
+ unsigned int addr = FR_CZ_MC_TREG_SMEM + MCDI_REBOOT_FLAG(efx);
efx_dword_t reg;
uint32_t value;
if (efx_nic_rev(efx) < EFX_REV_SIENA_A0)
return false;
- efx_mcdi_readd(efx, &reg, addr);
+ efx_readd(efx, &reg, addr);
value = EFX_DWORD_FIELD(reg, EFX_DWORD_0);
if (value == 0)
return 0;
EFX_ZERO_DWORD(reg);
- efx_mcdi_writed(efx, &reg, addr);
+ efx_writed(efx, &reg, addr);
if (value == MC_STATUS_DWORD_ASSERT)
return -EINTR;
diff --git a/drivers/net/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
index aced2a7856fc..aced2a7856fc 100644
--- a/drivers/net/sfc/mcdi.h
+++ b/drivers/net/ethernet/sfc/mcdi.h
diff --git a/drivers/net/sfc/mcdi_mac.c b/drivers/net/ethernet/sfc/mcdi_mac.c
index 50c20777a564..50c20777a564 100644
--- a/drivers/net/sfc/mcdi_mac.c
+++ b/drivers/net/ethernet/sfc/mcdi_mac.c
diff --git a/drivers/net/sfc/mcdi_pcol.h b/drivers/net/ethernet/sfc/mcdi_pcol.h
index 41fe06fa0600..41fe06fa0600 100644
--- a/drivers/net/sfc/mcdi_pcol.h
+++ b/drivers/net/ethernet/sfc/mcdi_pcol.h
diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/ethernet/sfc/mcdi_phy.c
index 6c63ab0710af..6c63ab0710af 100644
--- a/drivers/net/sfc/mcdi_phy.c
+++ b/drivers/net/ethernet/sfc/mcdi_phy.c
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/ethernet/sfc/mdio_10g.c
index 7ab385c8136d..7ab385c8136d 100644
--- a/drivers/net/sfc/mdio_10g.c
+++ b/drivers/net/ethernet/sfc/mdio_10g.c
diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/ethernet/sfc/mdio_10g.h
index a97dbbd2de99..a97dbbd2de99 100644
--- a/drivers/net/sfc/mdio_10g.h
+++ b/drivers/net/ethernet/sfc/mdio_10g.h
diff --git a/drivers/net/sfc/mtd.c b/drivers/net/ethernet/sfc/mtd.c
index b6304486f244..b6304486f244 100644
--- a/drivers/net/sfc/mtd.c
+++ b/drivers/net/ethernet/sfc/mtd.c
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index b8e251a1ee48..b8e251a1ee48 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
diff --git a/drivers/net/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c
index bafa23a6874c..3edfbaf5f022 100644
--- a/drivers/net/sfc/nic.c
+++ b/drivers/net/ethernet/sfc/nic.c
@@ -1936,13 +1936,6 @@ void efx_nic_get_regs(struct efx_nic *efx, void *buf)
size = min_t(size_t, table->step, 16);
- if (table->offset >= efx->type->mem_map_size) {
- /* No longer mapped; return dummy data */
- memcpy(buf, "\xde\xc0\xad\xde", 4);
- buf += table->rows * size;
- continue;
- }
-
for (i = 0; i < table->rows; i++) {
switch (table->step) {
case 4: /* 32-bit register or SRAM */
diff --git a/drivers/net/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h
index 4bd1f2839dfe..5fb24d3aa3ca 100644
--- a/drivers/net/sfc/nic.h
+++ b/drivers/net/ethernet/sfc/nic.h
@@ -143,12 +143,10 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx)
/**
* struct siena_nic_data - Siena NIC state
* @mcdi: Management-Controller-to-Driver Interface
- * @mcdi_smem: MCDI shared memory mapping. The mapping is always uncacheable.
* @wol_filter_id: Wake-on-LAN packet filter id
*/
struct siena_nic_data {
struct efx_mcdi_iface mcdi;
- void __iomem *mcdi_smem;
int wol_filter_id;
};
@@ -204,7 +202,8 @@ extern irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx);
extern irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id);
extern void falcon_irq_ack_a1(struct efx_nic *efx);
-#define EFX_IRQ_MOD_RESOLUTION 5
+#define EFX_IRQ_MOD_RESOLUTION 5
+#define EFX_IRQ_MOD_MAX 0x1000
/* Global Resources */
extern int efx_nic_flush_queues(struct efx_nic *efx);
diff --git a/drivers/net/sfc/phy.h b/drivers/net/ethernet/sfc/phy.h
index 11d148cd8441..11d148cd8441 100644
--- a/drivers/net/sfc/phy.h
+++ b/drivers/net/ethernet/sfc/phy.h
diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/ethernet/sfc/qt202x_phy.c
index 7ad97e397406..7ad97e397406 100644
--- a/drivers/net/sfc/qt202x_phy.c
+++ b/drivers/net/ethernet/sfc/qt202x_phy.c
diff --git a/drivers/net/sfc/regs.h b/drivers/net/ethernet/sfc/regs.h
index cc2c86b76a7b..cc2c86b76a7b 100644
--- a/drivers/net/sfc/regs.h
+++ b/drivers/net/ethernet/sfc/regs.h
diff --git a/drivers/net/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c
index 62e43649466e..adbda182f159 100644
--- a/drivers/net/sfc/rx.c
+++ b/drivers/net/ethernet/sfc/rx.c
@@ -478,10 +478,10 @@ static void efx_rx_packet_gro(struct efx_channel *channel,
if (efx->net_dev->features & NETIF_F_RXHASH)
skb->rxhash = efx_rx_buf_hash(eh);
- skb_shinfo(skb)->frags[0].page = page;
+ skb_frag_set_page(skb, 0, page);
skb_shinfo(skb)->frags[0].page_offset =
efx_rx_buf_offset(efx, rx_buf);
- skb_shinfo(skb)->frags[0].size = rx_buf->len;
+ skb_frag_size_set(&skb_shinfo(skb)->frags[0], rx_buf->len);
skb_shinfo(skb)->nr_frags = 1;
skb->len = rx_buf->len;
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c
index 822f6c2a6a7c..822f6c2a6a7c 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/ethernet/sfc/selftest.c
diff --git a/drivers/net/sfc/selftest.h b/drivers/net/ethernet/sfc/selftest.h
index dba5456e70f3..dba5456e70f3 100644
--- a/drivers/net/sfc/selftest.h
+++ b/drivers/net/ethernet/sfc/selftest.h
diff --git a/drivers/net/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c
index 5735e84c69de..cc2549cb7076 100644
--- a/drivers/net/sfc/siena.c
+++ b/drivers/net/ethernet/sfc/siena.c
@@ -36,6 +36,8 @@ static void siena_push_irq_moderation(struct efx_channel *channel)
{
efx_dword_t timer_cmd;
+ BUILD_BUG_ON(EFX_IRQ_MOD_MAX > (1 << FRF_CZ_TC_TIMER_VAL_WIDTH));
+
if (channel->irq_moderation)
EFX_POPULATE_DWORD_2(timer_cmd,
FRF_CZ_TC_TIMER_MODE,
@@ -250,26 +252,12 @@ static int siena_probe_nic(struct efx_nic *efx)
efx_reado(efx, &reg, FR_AZ_CS_DEBUG);
efx->net_dev->dev_id = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1;
- /* Initialise MCDI */
- nic_data->mcdi_smem = ioremap_nocache(efx->membase_phys +
- FR_CZ_MC_TREG_SMEM,
- FR_CZ_MC_TREG_SMEM_STEP *
- FR_CZ_MC_TREG_SMEM_ROWS);
- if (!nic_data->mcdi_smem) {
- netif_err(efx, probe, efx->net_dev,
- "could not map MCDI at %llx+%x\n",
- (unsigned long long)efx->membase_phys +
- FR_CZ_MC_TREG_SMEM,
- FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS);
- rc = -ENOMEM;
- goto fail1;
- }
efx_mcdi_init(efx);
/* Recover from a failed assertion before probing */
rc = efx_mcdi_handle_assertion(efx);
if (rc)
- goto fail2;
+ goto fail1;
/* Let the BMC know that the driver is now in charge of link and
* filter settings. We must do this before we reset the NIC */
@@ -324,7 +312,6 @@ fail4:
fail3:
efx_mcdi_drv_attach(efx, false, NULL);
fail2:
- iounmap(nic_data->mcdi_smem);
fail1:
kfree(efx->nic_data);
return rc;
@@ -404,8 +391,6 @@ static int siena_init_nic(struct efx_nic *efx)
static void siena_remove_nic(struct efx_nic *efx)
{
- struct siena_nic_data *nic_data = efx->nic_data;
-
efx_nic_free_buffer(efx, &efx->irq_status);
siena_reset_hw(efx, RESET_TYPE_ALL);
@@ -415,8 +400,7 @@ static void siena_remove_nic(struct efx_nic *efx)
efx_mcdi_drv_attach(efx, false, NULL);
/* Tear down the private nic state */
- iounmap(nic_data->mcdi_smem);
- kfree(nic_data);
+ kfree(efx->nic_data);
efx->nic_data = NULL;
}
@@ -656,7 +640,8 @@ const struct efx_nic_type siena_a0_nic_type = {
.default_mac_ops = &efx_mcdi_mac_operations,
.revision = EFX_REV_SIENA_A0,
- .mem_map_size = FR_CZ_MC_TREG_SMEM, /* MC_TREG_SMEM mapped separately */
+ .mem_map_size = (FR_CZ_MC_TREG_SMEM +
+ FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS),
.txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL,
.rxd_ptr_tbl_base = FR_BZ_RX_DESC_PTR_TBL,
.buf_tbl_base = FR_BZ_BUF_FULL_TBL,
diff --git a/drivers/net/sfc/spi.h b/drivers/net/ethernet/sfc/spi.h
index 71f2e3ebe1c7..71f2e3ebe1c7 100644
--- a/drivers/net/sfc/spi.h
+++ b/drivers/net/ethernet/sfc/spi.h
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/ethernet/sfc/tenxpress.c
index 7b0fd89e7b85..7b0fd89e7b85 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/ethernet/sfc/tenxpress.c
diff --git a/drivers/net/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c
index 84eb99e0f8d2..df88c5430f95 100644
--- a/drivers/net/sfc/tx.c
+++ b/drivers/net/ethernet/sfc/tx.c
@@ -137,8 +137,6 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
struct pci_dev *pci_dev = efx->pci_dev;
struct efx_tx_buffer *buffer;
skb_frag_t *fragment;
- struct page *page;
- int page_offset;
unsigned int len, unmap_len = 0, fill_level, insert_ptr;
dma_addr_t dma_addr, unmap_addr = 0;
unsigned int dma_len;
@@ -240,14 +238,12 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
if (i >= skb_shinfo(skb)->nr_frags)
break;
fragment = &skb_shinfo(skb)->frags[i];
- len = fragment->size;
- page = fragment->page;
- page_offset = fragment->page_offset;
+ len = skb_frag_size(fragment);
i++;
/* Map for DMA */
unmap_single = false;
- dma_addr = pci_map_page(pci_dev, page, page_offset, len,
- PCI_DMA_TODEVICE);
+ dma_addr = skb_frag_dma_map(&pci_dev->dev, fragment, 0, len,
+ DMA_TO_DEVICE);
}
/* Transfer ownership of the skb to the final buffer */
@@ -929,13 +925,12 @@ static void tso_start(struct tso_state *st, const struct sk_buff *skb)
static int tso_get_fragment(struct tso_state *st, struct efx_nic *efx,
skb_frag_t *frag)
{
- st->unmap_addr = pci_map_page(efx->pci_dev, frag->page,
- frag->page_offset, frag->size,
- PCI_DMA_TODEVICE);
- if (likely(!pci_dma_mapping_error(efx->pci_dev, st->unmap_addr))) {
+ st->unmap_addr = skb_frag_dma_map(&efx->pci_dev->dev, frag, 0,
+ skb_frag_size(frag), DMA_TO_DEVICE);
+ if (likely(!dma_mapping_error(&efx->pci_dev->dev, st->unmap_addr))) {
st->unmap_single = false;
- st->unmap_len = frag->size;
- st->in_len = frag->size;
+ st->unmap_len = skb_frag_size(frag);
+ st->in_len = skb_frag_size(frag);
st->dma_addr = st->unmap_addr;
return 0;
}
diff --git a/drivers/net/sfc/txc43128_phy.c b/drivers/net/ethernet/sfc/txc43128_phy.c
index 7c21b334a75b..7c21b334a75b 100644
--- a/drivers/net/sfc/txc43128_phy.c
+++ b/drivers/net/ethernet/sfc/txc43128_phy.c
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/ethernet/sfc/workarounds.h
index 99ff11400cef..e4dd3a7f304b 100644
--- a/drivers/net/sfc/workarounds.h
+++ b/drivers/net/ethernet/sfc/workarounds.h
@@ -38,8 +38,6 @@
#define EFX_WORKAROUND_15783 EFX_WORKAROUND_ALWAYS
/* Legacy interrupt storm when interrupt fifo fills */
#define EFX_WORKAROUND_17213 EFX_WORKAROUND_SIENA
-/* Write combining and sriov=enabled are incompatible */
-#define EFX_WORKAROUND_22643 EFX_WORKAROUND_SIENA
/* Spurious parity errors in TSORT buffers */
#define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A
diff --git a/drivers/net/ethernet/sgi/Kconfig b/drivers/net/ethernet/sgi/Kconfig
new file mode 100644
index 000000000000..c1c4bb868a3b
--- /dev/null
+++ b/drivers/net/ethernet/sgi/Kconfig
@@ -0,0 +1,36 @@
+#
+# SGI device configuration
+#
+
+config NET_VENDOR_SGI
+ bool "SGI devices"
+ default y
+ depends on (PCI && SGI_IP27) || SGI_IP32
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about SGI devices. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_SGI
+
+config SGI_IOC3_ETH
+ bool "SGI IOC3 Ethernet"
+ depends on PCI && SGI_IP27
+ select CRC32
+ select NET_CORE
+ select MII
+ ---help---
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+config SGI_O2MACE_ETH
+ tristate "SGI O2 MACE Fast Ethernet support"
+ depends on SGI_IP32=y
+
+endif # NET_VENDOR_SGI
diff --git a/drivers/net/ethernet/sgi/Makefile b/drivers/net/ethernet/sgi/Makefile
new file mode 100644
index 000000000000..e5bedd271e29
--- /dev/null
+++ b/drivers/net/ethernet/sgi/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the SGI device drivers.
+#
+
+obj-$(CONFIG_SGI_O2MACE_ETH) += meth.o
+obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c
index a234e4504522..ac149d99f78f 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ethernet/sgi/ioc3-eth.c
@@ -1220,7 +1220,7 @@ static const struct net_device_ops ioc3_netdev_ops = {
.ndo_start_xmit = ioc3_start_xmit,
.ndo_tx_timeout = ioc3_timeout,
.ndo_get_stats = ioc3_get_stats,
- .ndo_set_multicast_list = ioc3_set_multicast_list,
+ .ndo_set_rx_mode = ioc3_set_multicast_list,
.ndo_do_ioctl = ioc3_ioctl,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = ioc3_set_mac_address,
diff --git a/drivers/net/meth.c b/drivers/net/ethernet/sgi/meth.c
index 60135aa55802..60135aa55802 100644
--- a/drivers/net/meth.c
+++ b/drivers/net/ethernet/sgi/meth.c
diff --git a/drivers/net/meth.h b/drivers/net/ethernet/sgi/meth.h
index 5b145c6bad60..5b145c6bad60 100644
--- a/drivers/net/meth.h
+++ b/drivers/net/ethernet/sgi/meth.h
diff --git a/drivers/net/ethernet/sis/Kconfig b/drivers/net/ethernet/sis/Kconfig
new file mode 100644
index 000000000000..f1135cc1bd48
--- /dev/null
+++ b/drivers/net/ethernet/sis/Kconfig
@@ -0,0 +1,53 @@
+#
+# Silicon Integrated Systems (SiS) device configuration
+#
+
+config NET_VENDOR_SIS
+ bool "Silicon Integrated Systems (SiS) devices"
+ default y
+ depends on PCI
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about SiS devices. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_SIS
+
+config SIS900
+ tristate "SiS 900/7016 PCI Fast Ethernet Adapter support"
+ depends on PCI
+ select CRC32
+ select NET_CORE
+ select MII
+ ---help---
+ This is a driver for the Fast Ethernet PCI network cards based on
+ the SiS 900 and SiS 7016 chips. The SiS 900 core is also embedded in
+ SiS 630 and SiS 540 chipsets.
+
+ This driver also supports AMD 79C901 HomePNA so that you can use
+ your phone line as a network cable.
+
+ To compile this driver as a module, choose M here: the module
+ will be called sis900. This is recommended.
+
+config SIS190
+ tristate "SiS190/SiS191 gigabit ethernet support"
+ depends on PCI
+ select CRC32
+ select NET_CORE
+ select MII
+ ---help---
+ Say Y here if you have a SiS 190 PCI Fast Ethernet adapter or
+ a SiS 191 PCI Gigabit Ethernet adapter. Both are expected to
+ appear in lan on motherboard designs which are based on SiS 965
+ and SiS 966 south bridge.
+
+ To compile this driver as a module, choose M here: the module
+ will be called sis190. This is recommended.
+
+endif # NET_VENDOR_SIS
diff --git a/drivers/net/ethernet/sis/Makefile b/drivers/net/ethernet/sis/Makefile
new file mode 100644
index 000000000000..58d3ac1985df
--- /dev/null
+++ b/drivers/net/ethernet/sis/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for Silicon Integrated Systems (SiS) network device drivers.
+#
+
+obj-$(CONFIG_SIS190) += sis190.o
+obj-$(CONFIG_SIS900) += sis900.o
diff --git a/drivers/net/sis190.c b/drivers/net/ethernet/sis/sis190.c
index 3c0f1312b391..1b4658c99391 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/ethernet/sis/sis190.c
@@ -1841,7 +1841,7 @@ static const struct net_device_ops sis190_netdev_ops = {
.ndo_do_ioctl = sis190_ioctl,
.ndo_start_xmit = sis190_start_xmit,
.ndo_tx_timeout = sis190_tx_timeout,
- .ndo_set_multicast_list = sis190_set_rx_mode,
+ .ndo_set_rx_mode = sis190_set_rx_mode,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = sis190_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/sis900.c b/drivers/net/ethernet/sis/sis900.c
index 658a1928fe79..a184abc5ef11 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/ethernet/sis/sis900.c
@@ -403,7 +403,7 @@ static const struct net_device_ops sis900_netdev_ops = {
.ndo_stop = sis900_close,
.ndo_start_xmit = sis900_start_xmit,
.ndo_set_config = sis900_set_config,
- .ndo_set_multicast_list = set_rx_mode,
+ .ndo_set_rx_mode = set_rx_mode,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/sis900.h b/drivers/net/ethernet/sis/sis900.h
index 150511a922ef..150511a922ef 100644
--- a/drivers/net/sis900.h
+++ b/drivers/net/ethernet/sis/sis900.h
diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/Kconfig
new file mode 100644
index 000000000000..5a689af516e9
--- /dev/null
+++ b/drivers/net/ethernet/smsc/Kconfig
@@ -0,0 +1,136 @@
+#
+# Western Digital/SMC network device configuration
+#
+
+config NET_VENDOR_SMSC
+ bool "SMC (SMSC)/Western Digital devices"
+ default y
+ depends on ARM || ISA || MAC || ARM || MIPS || M32R || SUPERH || \
+ BLACKFIN || MN10300 || COLDFIRE || PCI || PCMCIA
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about SMC/Western Digital cards. If you say Y, you will
+ be asked for your specific card in the following questions.
+
+if NET_VENDOR_SMSC
+
+config SMC9194
+ tristate "SMC 9194 support"
+ depends on (ISA || MAC && BROKEN)
+ select CRC32
+ ---help---
+ This is support for the SMC9xxx based Ethernet cards. Choose this
+ option if you have a DELL laptop with the docking station, or
+ another SMC9192/9194 based chipset. Say Y if you want it compiled
+ into the kernel, and read the file
+ <file:Documentation/networking/smc9.txt> and the Ethernet-HOWTO,
+ available from <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called smc9194.
+
+config SMC91X
+ tristate "SMC 91C9x/91C1xxx support"
+ select CRC32
+ select NET_CORE
+ select MII
+ depends on (ARM || M32R || SUPERH || MIPS || BLACKFIN || \
+ MN10300 || COLDFIRE)
+ ---help---
+ This is a driver for SMC's 91x series of Ethernet chipsets,
+ including the SMC91C94 and the SMC91C111. Say Y if you want it
+ compiled into the kernel, and read the file
+ <file:Documentation/networking/smc9.txt> and the Ethernet-HOWTO,
+ available from <http://www.tldp.org/docs.html#howto>.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called smc91x. If you want to compile it as a
+ module, say M here and read <file:Documentation/kbuild/modules.txt>.
+
+config PCMCIA_SMC91C92
+ tristate "SMC 91Cxx PCMCIA support"
+ depends on PCMCIA
+ select CRC32
+ select NET_CORE
+ select MII
+ ---help---
+ Say Y here if you intend to attach an SMC 91Cxx compatible PCMCIA
+ (PC-card) Ethernet or Fast Ethernet card to your computer.
+
+ To compile this driver as a module, choose M here: the module will be
+ called smc91c92_cs. If unsure, say N.
+
+config EPIC100
+ tristate "SMC EtherPower II"
+ depends on PCI
+ select CRC32
+ select NET_CORE
+ select MII
+ ---help---
+ This driver is for the SMC EtherPower II 9432 PCI Ethernet NIC,
+ which is based on the SMC83c17x (EPIC/100).
+ More specific information and updates are available from
+ <http://www.scyld.com/network/epic100.html>.
+
+config SMC911X
+ tristate "SMSC LAN911[5678] support"
+ select CRC32
+ select NET_CORE
+ select MII
+ depends on (ARM || SUPERH || MN10300)
+ ---help---
+ This is a driver for SMSC's LAN911x series of Ethernet chipsets
+ including the new LAN9115, LAN9116, LAN9117, and LAN9118.
+ Say Y if you want it compiled into the kernel,
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ This driver is also available as a module. The module will be
+ called smc911x. If you want to compile it as a module, say M
+ here and read <file:Documentation/kbuild/modules.txt>
+
+config SMSC911X
+ tristate "SMSC LAN911x/LAN921x families embedded ethernet support"
+ depends on (ARM || SUPERH || BLACKFIN || MIPS || MN10300)
+ select CRC32
+ select NET_CORE
+ select MII
+ select PHYLIB
+ ---help---
+ Say Y here if you want support for SMSC LAN911x and LAN921x families
+ of ethernet controllers.
+
+ To compile this driver as a module, choose M here. The module
+ will be called smsc911x.
+
+config SMSC911X_ARCH_HOOKS
+ def_bool n
+ depends on SMSC911X
+ ---help---
+ If the arch enables this, it allows the arch to implement various
+ hooks for more comprehensive interrupt control and also to override
+ the source of the MAC address.
+
+config SMSC9420
+ tristate "SMSC LAN9420 PCI ethernet adapter support"
+ depends on PCI
+ select CRC32
+ select PHYLIB
+ select SMSC_PHY
+ ---help---
+ This is a driver for SMSC's LAN9420 PCI ethernet adapter.
+ Say Y if you want it compiled into the kernel,
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ This driver is also available as a module. The module will be
+ called smsc9420. If you want to compile it as a module, say M
+ here and read <file:Documentation/kbuild/modules.txt>
+
+endif # NET_VENDOR_SMSC
diff --git a/drivers/net/ethernet/smsc/Makefile b/drivers/net/ethernet/smsc/Makefile
new file mode 100644
index 000000000000..f3438dec9d90
--- /dev/null
+++ b/drivers/net/ethernet/smsc/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the SMSC network device drivers.
+#
+
+obj-$(CONFIG_SMC9194) += smc9194.o
+obj-$(CONFIG_SMC91X) += smc91x.o
+obj-$(CONFIG_PCMCIA_SMC91C92) += smc91c92_cs.o
+obj-$(CONFIG_EPIC100) += epic100.o
+obj-$(CONFIG_SMSC9420) += smsc9420.o
+obj-$(CONFIG_SMC911X) += smc911x.o
+obj-$(CONFIG_SMSC911X) += smsc911x.o
diff --git a/drivers/net/epic100.c b/drivers/net/ethernet/smsc/epic100.c
index 814c187d5f95..0a5dfb814157 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/ethernet/smsc/epic100.c
@@ -314,7 +314,7 @@ static const struct net_device_ops epic_netdev_ops = {
.ndo_start_xmit = epic_start_xmit,
.ndo_tx_timeout = epic_tx_timeout,
.ndo_get_stats = epic_get_stats,
- .ndo_set_multicast_list = set_rx_mode,
+ .ndo_set_rx_mode = set_rx_mode,
.ndo_do_ioctl = netdev_ioctl,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/smc911x.c b/drivers/net/ethernet/smsc/smc911x.c
index a91fe1723020..8f61fe9db1d0 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/ethernet/smsc/smc911x.c
@@ -1768,7 +1768,7 @@ static const struct net_device_ops smc911x_netdev_ops = {
.ndo_stop = smc911x_close,
.ndo_start_xmit = smc911x_hard_start_xmit,
.ndo_tx_timeout = smc911x_timeout,
- .ndo_set_multicast_list = smc911x_set_multicast_list,
+ .ndo_set_rx_mode = smc911x_set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/smc911x.h b/drivers/net/ethernet/smsc/smc911x.h
index 3269292efecc..3269292efecc 100644
--- a/drivers/net/smc911x.h
+++ b/drivers/net/ethernet/smsc/smc911x.h
diff --git a/drivers/net/smc9194.c b/drivers/net/ethernet/smsc/smc9194.c
index 5b65ac4b3cef..4e45094efb18 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/ethernet/smsc/smc9194.c
@@ -827,7 +827,7 @@ static const struct net_device_ops smc_netdev_ops = {
.ndo_stop = smc_close,
.ndo_start_xmit = smc_wait_to_send_packet,
.ndo_tx_timeout = smc_timeout,
- .ndo_set_multicast_list = smc_set_multicast_list,
+ .ndo_set_rx_mode = smc_set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/smc9194.h b/drivers/net/ethernet/smsc/smc9194.h
index cf69d0a5a1cb..cf69d0a5a1cb 100644
--- a/drivers/net/smc9194.h
+++ b/drivers/net/ethernet/smsc/smc9194.h
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/ethernet/smsc/smc91c92_cs.c
index cffbc0373fa9..cbfa98187131 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/ethernet/smsc/smc91c92_cs.c
@@ -294,7 +294,7 @@ static const struct net_device_ops smc_netdev_ops = {
.ndo_start_xmit = smc_start_xmit,
.ndo_tx_timeout = smc_tx_timeout,
.ndo_set_config = s9k_config,
- .ndo_set_multicast_list = set_rx_mode,
+ .ndo_set_rx_mode = set_rx_mode,
.ndo_do_ioctl = smc_ioctl,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
index 2b1d254d59af..f47f81e25322 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/ethernet/smsc/smc91x.c
@@ -1768,7 +1768,7 @@ static const struct net_device_ops smc_netdev_ops = {
.ndo_stop = smc_close,
.ndo_start_xmit = smc_hard_start_xmit,
.ndo_tx_timeout = smc_timeout,
- .ndo_set_multicast_list = smc_set_multicast_list,
+ .ndo_set_rx_mode = smc_set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/smc91x.h b/drivers/net/ethernet/smsc/smc91x.h
index 5f53fbbf67be..5f53fbbf67be 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/ethernet/smsc/smc91x.h
diff --git a/drivers/net/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c
index b9016a30cdc5..d2be42aafbef 100644
--- a/drivers/net/smsc911x.c
+++ b/drivers/net/ethernet/smsc/smsc911x.c
@@ -26,6 +26,7 @@
* LAN9215, LAN9216, LAN9217, LAN9218
* LAN9210, LAN9211
* LAN9220, LAN9221
+ * LAN89218
*
*/
@@ -53,6 +54,10 @@
#include <linux/phy.h>
#include <linux/smsc911x.h>
#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_net.h>
#include "smsc911x.h"
#define SMSC_CHIPNAME "smsc911x"
@@ -1902,7 +1907,7 @@ static const struct net_device_ops smsc911x_netdev_ops = {
.ndo_stop = smsc911x_stop,
.ndo_start_xmit = smsc911x_hard_start_xmit,
.ndo_get_stats = smsc911x_get_stats,
- .ndo_set_multicast_list = smsc911x_set_multicast_list,
+ .ndo_set_rx_mode = smsc911x_set_multicast_list,
.ndo_do_ioctl = smsc911x_do_ioctl,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
@@ -1983,6 +1988,7 @@ static int __devinit smsc911x_init(struct net_device *dev)
case 0x01170000:
case 0x01160000:
case 0x01150000:
+ case 0x218A0000:
/* LAN911[5678] family */
pdata->generation = pdata->idrev & 0x0000FFFF;
break;
@@ -2095,8 +2101,60 @@ static const struct smsc911x_ops shifted_smsc911x_ops = {
.tx_writefifo = smsc911x_tx_writefifo_shift,
};
+#ifdef CONFIG_OF
+static int __devinit smsc911x_probe_config_dt(
+ struct smsc911x_platform_config *config,
+ struct device_node *np)
+{
+ const char *mac;
+ u32 width = 0;
+
+ if (!np)
+ return -ENODEV;
+
+ config->phy_interface = of_get_phy_mode(np);
+
+ mac = of_get_mac_address(np);
+ if (mac)
+ memcpy(config->mac, mac, ETH_ALEN);
+
+ of_property_read_u32(np, "reg-shift", &config->shift);
+
+ of_property_read_u32(np, "reg-io-width", &width);
+ if (width == 4)
+ config->flags |= SMSC911X_USE_32BIT;
+ else
+ config->flags |= SMSC911X_USE_16BIT;
+
+ if (of_get_property(np, "smsc,irq-active-high", NULL))
+ config->irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH;
+
+ if (of_get_property(np, "smsc,irq-push-pull", NULL))
+ config->irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL;
+
+ if (of_get_property(np, "smsc,force-internal-phy", NULL))
+ config->flags |= SMSC911X_FORCE_INTERNAL_PHY;
+
+ if (of_get_property(np, "smsc,force-external-phy", NULL))
+ config->flags |= SMSC911X_FORCE_EXTERNAL_PHY;
+
+ if (of_get_property(np, "smsc,save-mac-address", NULL))
+ config->flags |= SMSC911X_SAVE_MAC_ADDRESS;
+
+ return 0;
+}
+#else
+static inline int smsc911x_probe_config_dt(
+ struct smsc911x_platform_config *config,
+ struct device_node *np)
+{
+ return -ENODEV;
+}
+#endif /* CONFIG_OF */
+
static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
{
+ struct device_node *np = pdev->dev.of_node;
struct net_device *dev;
struct smsc911x_data *pdata;
struct smsc911x_platform_config *config = pdev->dev.platform_data;
@@ -2107,13 +2165,6 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
pr_info("Driver version %s\n", SMSC_DRV_VERSION);
- /* platform data specifies irq & dynamic bus configuration */
- if (!pdev->dev.platform_data) {
- pr_warn("platform_data not provided\n");
- retval = -ENODEV;
- goto out_0;
- }
-
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"smsc911x-memory");
if (!res)
@@ -2152,9 +2203,6 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
irq_flags = irq_res->flags & IRQF_TRIGGER_MASK;
pdata->ioaddr = ioremap_nocache(res->start, res_size);
- /* copy config parameters across to pdata */
- memcpy(&pdata->config, config, sizeof(pdata->config));
-
pdata->dev = dev;
pdata->msg_enable = ((1 << debug) - 1);
@@ -2164,10 +2212,22 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
goto out_free_netdev_2;
}
+ retval = smsc911x_probe_config_dt(&pdata->config, np);
+ if (retval && config) {
+ /* copy config parameters across to pdata */
+ memcpy(&pdata->config, config, sizeof(pdata->config));
+ retval = 0;
+ }
+
+ if (retval) {
+ SMSC_WARN(pdata, probe, "Error smsc911x config not found");
+ goto out_unmap_io_3;
+ }
+
/* assume standard, non-shifted, access to HW registers */
pdata->ops = &standard_smsc911x_ops;
/* apply the right access if shifting is needed */
- if (config->shift)
+ if (pdata->config.shift)
pdata->ops = &shifted_smsc911x_ops;
retval = smsc911x_init(dev);
@@ -2314,6 +2374,12 @@ static const struct dev_pm_ops smsc911x_pm_ops = {
#define SMSC911X_PM_OPS NULL
#endif
+static const struct of_device_id smsc911x_dt_ids[] = {
+ { .compatible = "smsc,lan9115", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, smsc911x_dt_ids);
+
static struct platform_driver smsc911x_driver = {
.probe = smsc911x_drv_probe,
.remove = __devexit_p(smsc911x_drv_remove),
@@ -2321,6 +2387,7 @@ static struct platform_driver smsc911x_driver = {
.name = SMSC_CHIPNAME,
.owner = THIS_MODULE,
.pm = SMSC911X_PM_OPS,
+ .of_match_table = smsc911x_dt_ids,
},
};
diff --git a/drivers/net/smsc911x.h b/drivers/net/ethernet/smsc/smsc911x.h
index 8d67aacf8867..8d67aacf8867 100644
--- a/drivers/net/smsc911x.h
+++ b/drivers/net/ethernet/smsc/smsc911x.h
diff --git a/drivers/net/smsc9420.c b/drivers/net/ethernet/smsc/smsc9420.c
index 459726f54754..4f15680849ff 100644
--- a/drivers/net/smsc9420.c
+++ b/drivers/net/ethernet/smsc/smsc9420.c
@@ -1566,7 +1566,7 @@ static const struct net_device_ops smsc9420_netdev_ops = {
.ndo_stop = smsc9420_stop,
.ndo_start_xmit = smsc9420_hard_start_xmit,
.ndo_get_stats = smsc9420_get_stats,
- .ndo_set_multicast_list = smsc9420_set_multicast_list,
+ .ndo_set_rx_mode = smsc9420_set_multicast_list,
.ndo_do_ioctl = smsc9420_do_ioctl,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/smsc9420.h b/drivers/net/ethernet/smsc/smsc9420.h
index e441402f77a2..e441402f77a2 100644
--- a/drivers/net/smsc9420.h
+++ b/drivers/net/ethernet/smsc/smsc9420.h
diff --git a/drivers/net/ethernet/stmicro/Kconfig b/drivers/net/ethernet/stmicro/Kconfig
new file mode 100644
index 000000000000..f4a80da00650
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/Kconfig
@@ -0,0 +1,23 @@
+#
+# STMicroelectronics device configuration
+#
+
+config NET_VENDOR_STMICRO
+ bool "STMicroelectronics devices"
+ default y
+ depends on HAS_IOMEM
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about STMicroelectronics cards. If you say Y, you will
+ be asked for your specific card in the following questions.
+
+if NET_VENDOR_STMICRO
+
+source "drivers/net/ethernet/stmicro/stmmac/Kconfig"
+
+endif # NET_VENDOR_STMICRO
diff --git a/drivers/net/ethernet/stmicro/Makefile b/drivers/net/ethernet/stmicro/Makefile
new file mode 100644
index 000000000000..9b3bfddda7dd
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the STMicroelectronics device drivers.
+#
+
+obj-$(CONFIG_STMMAC_ETH) += stmmac/
diff --git a/drivers/net/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 7df7df4e79c5..ac6f190743dd 100644
--- a/drivers/net/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -1,20 +1,29 @@
config STMMAC_ETH
tristate "STMicroelectronics 10/100/1000 Ethernet driver"
+ depends on HAS_IOMEM
+ select NET_CORE
select MII
select PHYLIB
select CRC32
- depends on NETDEVICES && HAS_IOMEM
- help
+ ---help---
This is the driver for the Ethernet IPs are built around a
Synopsys IP Core and only tested on the STMicroelectronics
platforms.
if STMMAC_ETH
+config STMMAC_DEBUG_FS
+ bool "Enable monitoring via sysFS "
+ default n
+ depends on STMMAC_ETH && DEBUG_FS
+ -- help
+ The stmmac entry in /sys reports DMA TX/RX rings
+ or (if supported) the HW cap register.
+
config STMMAC_DA
bool "STMMAC DMA arbitration scheme"
default n
- help
+ ---help---
Selecting this option, rx has priority over Tx (only for Giga
Ethernet device).
By default, the DMA arbitration scheme is based on Round-robin
@@ -24,7 +33,7 @@ config STMMAC_DUAL_MAC
bool "STMMAC: dual mac support (EXPERIMENTAL)"
default n
depends on EXPERIMENTAL && STMMAC_ETH && !STMMAC_TIMER
- help
+ ---help---
Some ST SoCs (for example the stx7141 and stx7200c2) have two
Ethernet Controllers. This option turns on the second Ethernet
device on this kind of platforms.
@@ -33,7 +42,7 @@ config STMMAC_TIMER
bool "STMMAC Timer optimisation"
default n
depends on RTC_HCTOSYS_DEVICE
- help
+ ---help---
Use an external timer for mitigating the number of network
interrupts. Currently, for SH architectures, it is possible
to use the TMU channel 2 and the SH-RTC device.
@@ -45,13 +54,31 @@ choice
config STMMAC_TMU_TIMER
bool "TMU channel 2"
depends on CPU_SH4
- help
+ ---help---
config STMMAC_RTC_TIMER
bool "Real time clock"
depends on RTC_CLASS
- help
+ ---help---
endchoice
+choice
+ prompt "Select the DMA TX/RX descriptor operating modes"
+ depends on STMMAC_ETH
+ ---help---
+ This driver supports DMA descriptor to operate both in dual buffer
+ (RING) and linked-list(CHAINED) mode. In RING mode each descriptor
+ points to two data buffer pointers whereas in CHAINED mode they
+ points to only one data buffer pointer.
+
+config STMMAC_RING
+ bool "Enable Descriptor Ring Mode"
+
+config STMMAC_CHAINED
+ bool "Enable Descriptor Chained Mode"
+
+endchoice
+
+
endif
diff --git a/drivers/net/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index 9691733ddb8e..d7c45164ea79 100644
--- a/drivers/net/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -1,5 +1,8 @@
obj-$(CONFIG_STMMAC_ETH) += stmmac.o
stmmac-$(CONFIG_STMMAC_TIMER) += stmmac_timer.o
+stmmac-$(CONFIG_STMMAC_RING) += ring_mode.o
+stmmac-$(CONFIG_STMMAC_CHAINED) += chain_mode.o
stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \
dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
- dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o $(stmmac-y)
+ dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
+ mmc_core.o $(stmmac-y)
diff --git a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
new file mode 100644
index 000000000000..0668659803ed
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ Specialised functions for managing Chained mode
+
+ Copyright(C) 2011 STMicroelectronics Ltd
+
+ It defines all the functions used to handle the normal/enhanced
+ descriptors in case of the DMA is configured to work in chained or
+ in ring mode.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#include "stmmac.h"
+
+unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
+{
+ struct stmmac_priv *priv = (struct stmmac_priv *) p;
+ unsigned int txsize = priv->dma_tx_size;
+ unsigned int entry = priv->cur_tx % txsize;
+ struct dma_desc *desc = priv->dma_tx + entry;
+ unsigned int nopaged_len = skb_headlen(skb);
+ unsigned int bmax;
+ unsigned int i = 1, len;
+
+ if (priv->plat->enh_desc)
+ bmax = BUF_SIZE_8KiB;
+ else
+ bmax = BUF_SIZE_2KiB;
+
+ len = nopaged_len - bmax;
+
+ desc->des2 = dma_map_single(priv->device, skb->data,
+ bmax, DMA_TO_DEVICE);
+ priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum);
+
+ while (len != 0) {
+ entry = (++priv->cur_tx) % txsize;
+ desc = priv->dma_tx + entry;
+
+ if (len > bmax) {
+ desc->des2 = dma_map_single(priv->device,
+ (skb->data + bmax * i),
+ bmax, DMA_TO_DEVICE);
+ priv->hw->desc->prepare_tx_desc(desc, 0, bmax,
+ csum);
+ priv->hw->desc->set_tx_owner(desc);
+ priv->tx_skbuff[entry] = NULL;
+ len -= bmax;
+ i++;
+ } else {
+ desc->des2 = dma_map_single(priv->device,
+ (skb->data + bmax * i), len,
+ DMA_TO_DEVICE);
+ priv->hw->desc->prepare_tx_desc(desc, 0, len,
+ csum);
+ priv->hw->desc->set_tx_owner(desc);
+ priv->tx_skbuff[entry] = NULL;
+ len = 0;
+ }
+ }
+ return entry;
+}
+
+static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
+{
+ unsigned int ret = 0;
+
+ if ((enh_desc && (len > BUF_SIZE_8KiB)) ||
+ (!enh_desc && (len > BUF_SIZE_2KiB))) {
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static void stmmac_refill_desc3(int bfsize, struct dma_desc *p)
+{
+}
+
+static void stmmac_init_desc3(int des3_as_data_buf, struct dma_desc *p)
+{
+}
+
+static void stmmac_clean_desc3(struct dma_desc *p)
+{
+}
+
+static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr,
+ unsigned int size)
+{
+ /*
+ * In chained mode the des3 points to the next element in the ring.
+ * The latest element has to point to the head.
+ */
+ int i;
+ struct dma_desc *p = des;
+ dma_addr_t dma_phy = phy_addr;
+
+ for (i = 0; i < (size - 1); i++) {
+ dma_phy += sizeof(struct dma_desc);
+ p->des3 = (unsigned int)dma_phy;
+ p++;
+ }
+ p->des3 = (unsigned int)phy_addr;
+}
+
+static int stmmac_set_16kib_bfsize(int mtu)
+{
+ /* Not supported */
+ return 0;
+}
+
+const struct stmmac_ring_mode_ops ring_mode_ops = {
+ .is_jumbo_frm = stmmac_is_jumbo_frm,
+ .jumbo_frm = stmmac_jumbo_frm,
+ .refill_desc3 = stmmac_refill_desc3,
+ .init_desc3 = stmmac_init_desc3,
+ .init_dma_chain = stmmac_init_dma_chain,
+ .clean_desc3 = stmmac_clean_desc3,
+ .set_16kib_bfsize = stmmac_set_16kib_bfsize,
+};
diff --git a/drivers/net/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 375ea193e139..9100c100d295 100644
--- a/drivers/net/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -29,6 +29,7 @@
#endif
#include "descs.h"
+#include "mmc.h"
#undef CHIP_DEBUG_PRINT
/* Turn-on extra printk debug for MAC core, dma and descriptors */
@@ -102,6 +103,36 @@ struct stmmac_extra_stats {
#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */
+/* DAM HW feature register fields */
+#define DMA_HW_FEAT_MIISEL 0x00000001 /* 10/100 Mbps Support */
+#define DMA_HW_FEAT_GMIISEL 0x00000002 /* 1000 Mbps Support */
+#define DMA_HW_FEAT_HDSEL 0x00000004 /* Half-Duplex Support */
+#define DMA_HW_FEAT_EXTHASHEN 0x00000008 /* Expanded DA Hash Filter */
+#define DMA_HW_FEAT_HASHSEL 0x00000010 /* HASH Filter */
+#define DMA_HW_FEAT_ADDMACADRSEL 0x00000020 /* Multiple MAC Addr Reg */
+#define DMA_HW_FEAT_PCSSEL 0x00000040 /* PCS registers */
+#define DMA_HW_FEAT_L3L4FLTREN 0x00000080 /* Layer 3 & Layer 4 Feature */
+#define DMA_HW_FEAT_SMASEL 0x00000100 /* SMA(MDIO) Interface */
+#define DMA_HW_FEAT_RWKSEL 0x00000200 /* PMT Remote Wakeup */
+#define DMA_HW_FEAT_MGKSEL 0x00000400 /* PMT Magic Packet */
+#define DMA_HW_FEAT_MMCSEL 0x00000800 /* RMON Module */
+#define DMA_HW_FEAT_TSVER1SEL 0x00001000 /* Only IEEE 1588-2002 Timestamp */
+#define DMA_HW_FEAT_TSVER2SEL 0x00002000 /* IEEE 1588-2008 Adv Timestamp */
+#define DMA_HW_FEAT_EEESEL 0x00004000 /* Energy Efficient Ethernet */
+#define DMA_HW_FEAT_AVSEL 0x00008000 /* AV Feature */
+#define DMA_HW_FEAT_TXCOESEL 0x00010000 /* Checksum Offload in Tx */
+#define DMA_HW_FEAT_RXTYP1COE 0x00020000 /* IP csum Offload(Type 1) in Rx */
+#define DMA_HW_FEAT_RXTYP2COE 0x00040000 /* IP csum Offload(Type 2) in Rx */
+#define DMA_HW_FEAT_RXFIFOSIZE 0x00080000 /* Rx FIFO > 2048 Bytes */
+#define DMA_HW_FEAT_RXCHCNT 0x00300000 /* No. of additional Rx Channels */
+#define DMA_HW_FEAT_TXCHCNT 0x00c00000 /* No. of additional Tx Channels */
+#define DMA_HW_FEAT_ENHDESSEL 0x01000000 /* Alternate (Enhanced Descriptor) */
+#define DMA_HW_FEAT_INTTSEN 0x02000000 /* Timestamping with Internal
+ System Time */
+#define DMA_HW_FEAT_FLEXIPPSEN 0x04000000 /* Flexible PPS Output */
+#define DMA_HW_FEAT_SAVLANINS 0x08000000 /* Source Addr or VLAN Insertion */
+#define DMA_HW_FEAT_ACTPHYIF 0x70000000 /* Active/selected PHY interface */
+
enum rx_frame_status { /* IPC status */
good_frame = 0,
discard_frame = 1,
@@ -115,6 +146,37 @@ enum tx_dma_irq_status {
handle_tx_rx = 3,
};
+/* DMA HW capabilities */
+struct dma_features {
+ unsigned int mbps_10_100;
+ unsigned int mbps_1000;
+ unsigned int half_duplex;
+ unsigned int hash_filter;
+ unsigned int multi_addr;
+ unsigned int pcs;
+ unsigned int sma_mdio;
+ unsigned int pmt_remote_wake_up;
+ unsigned int pmt_magic_frame;
+ unsigned int rmon;
+ /* IEEE 1588-2002*/
+ unsigned int time_stamp;
+ /* IEEE 1588-2008*/
+ unsigned int atime_stamp;
+ /* 802.3az - Energy-Efficient Ethernet (EEE) */
+ unsigned int eee;
+ unsigned int av;
+ /* TX and RX csum */
+ unsigned int tx_coe;
+ unsigned int rx_coe_type1;
+ unsigned int rx_coe_type2;
+ unsigned int rxfifo_over_2048;
+ /* TX and RX number of channels */
+ unsigned int number_rx_channel;
+ unsigned int number_tx_channel;
+ /* Alternate (enhanced) DESC mode*/
+ unsigned int enh_desc;
+};
+
/* GMAC TX FIFO is 8K, Rx FIFO is 16K */
#define BUF_SIZE_16KiB 16384
#define BUF_SIZE_8KiB 8192
@@ -130,17 +192,6 @@ enum tx_dma_irq_status {
#define MAC_ENABLE_TX 0x00000008 /* Transmitter Enable */
#define MAC_RNABLE_RX 0x00000004 /* Receiver Enable */
-/* MAC Management Counters register */
-#define MMC_CONTROL 0x00000100 /* MMC Control */
-#define MMC_HIGH_INTR 0x00000104 /* MMC High Interrupt */
-#define MMC_LOW_INTR 0x00000108 /* MMC Low Interrupt */
-#define MMC_HIGH_INTR_MASK 0x0000010c /* MMC High Interrupt Mask */
-#define MMC_LOW_INTR_MASK 0x00000110 /* MMC Low Interrupt Mask */
-
-#define MMC_CONTROL_MAX_FRM_MASK 0x0003ff8 /* Maximum Frame Size */
-#define MMC_CONTROL_MAX_FRM_SHIFT 3
-#define MMC_CONTROL_MAX_FRAME 0x7FF
-
struct stmmac_desc_ops {
/* DMA RX descriptor ring initialization */
void (*init_rx_desc) (struct dma_desc *p, unsigned int ring_size,
@@ -198,6 +249,8 @@ struct stmmac_dma_ops {
void (*stop_rx) (void __iomem *ioaddr);
int (*dma_interrupt) (void __iomem *ioaddr,
struct stmmac_extra_stats *x);
+ /* If supported then get the optional core features */
+ unsigned int (*get_hw_feature) (void __iomem *ioaddr);
};
struct stmmac_ops {
@@ -234,12 +287,25 @@ struct mii_regs {
unsigned int data; /* MII Data */
};
+struct stmmac_ring_mode_ops {
+ unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
+ unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
+ void (*refill_desc3) (int bfsize, struct dma_desc *p);
+ void (*init_desc3) (int des3_as_data_buf, struct dma_desc *p);
+ void (*init_dma_chain) (struct dma_desc *des, dma_addr_t phy_addr,
+ unsigned int size);
+ void (*clean_desc3) (struct dma_desc *p);
+ int (*set_16kib_bfsize) (int mtu);
+};
+
struct mac_device_info {
const struct stmmac_ops *mac;
const struct stmmac_desc_ops *desc;
const struct stmmac_dma_ops *dma;
+ const struct stmmac_ring_mode_ops *ring;
struct mii_regs mii; /* MII register Addresses */
struct mac_link link;
+ unsigned int synopsys_uid;
};
struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr);
@@ -250,3 +316,4 @@ extern void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6],
extern void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
unsigned int high, unsigned int low);
extern void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
+extern const struct stmmac_ring_mode_ops ring_mode_ops;
diff --git a/drivers/net/stmmac/descs.h b/drivers/net/ethernet/stmicro/stmmac/descs.h
index 63a03e264694..63a03e264694 100644
--- a/drivers/net/stmmac/descs.h
+++ b/drivers/net/ethernet/stmicro/stmmac/descs.h
diff --git a/drivers/net/ethernet/stmicro/stmmac/descs_com.h b/drivers/net/ethernet/stmicro/stmmac/descs_com.h
new file mode 100644
index 000000000000..dd8d6e19dff6
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/descs_com.h
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ Header File to describe Normal/enhanced descriptor functions used for RING
+ and CHAINED modes.
+
+ Copyright(C) 2011 STMicroelectronics Ltd
+
+ It defines all the functions used to handle the normal/enhanced
+ descriptors in case of the DMA is configured to work in chained or
+ in ring mode.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#if defined(CONFIG_STMMAC_RING)
+static inline void ehn_desc_rx_set_on_ring_chain(struct dma_desc *p, int end)
+{
+ p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1;
+ if (end)
+ p->des01.erx.end_ring = 1;
+}
+
+static inline void ehn_desc_tx_set_on_ring_chain(struct dma_desc *p, int end)
+{
+ if (end)
+ p->des01.etx.end_ring = 1;
+}
+
+static inline void enh_desc_end_tx_desc(struct dma_desc *p, int ter)
+{
+ p->des01.etx.end_ring = ter;
+}
+
+static inline void enh_set_tx_desc_len(struct dma_desc *p, int len)
+{
+ if (unlikely(len > BUF_SIZE_4KiB)) {
+ p->des01.etx.buffer1_size = BUF_SIZE_4KiB;
+ p->des01.etx.buffer2_size = len - BUF_SIZE_4KiB;
+ } else
+ p->des01.etx.buffer1_size = len;
+}
+
+static inline void ndesc_rx_set_on_ring_chain(struct dma_desc *p, int end)
+{
+ p->des01.rx.buffer2_size = BUF_SIZE_2KiB - 1;
+ if (end)
+ p->des01.rx.end_ring = 1;
+}
+
+static inline void ndesc_tx_set_on_ring_chain(struct dma_desc *p, int end)
+{
+ if (end)
+ p->des01.tx.end_ring = 1;
+}
+
+static inline void ndesc_end_tx_desc(struct dma_desc *p, int ter)
+{
+ p->des01.tx.end_ring = ter;
+}
+
+static inline void norm_set_tx_desc_len(struct dma_desc *p, int len)
+{
+ if (unlikely(len > BUF_SIZE_2KiB)) {
+ p->des01.etx.buffer1_size = BUF_SIZE_2KiB - 1;
+ p->des01.etx.buffer2_size = len - p->des01.etx.buffer1_size;
+ } else
+ p->des01.tx.buffer1_size = len;
+}
+
+#else
+
+static inline void ehn_desc_rx_set_on_ring_chain(struct dma_desc *p, int end)
+{
+ p->des01.erx.second_address_chained = 1;
+}
+
+static inline void ehn_desc_tx_set_on_ring_chain(struct dma_desc *p, int end)
+{
+ p->des01.etx.second_address_chained = 1;
+}
+
+static inline void enh_desc_end_tx_desc(struct dma_desc *p, int ter)
+{
+ p->des01.etx.second_address_chained = 1;
+}
+
+static inline void enh_set_tx_desc_len(struct dma_desc *p, int len)
+{
+ p->des01.etx.buffer1_size = len;
+}
+
+static inline void ndesc_rx_set_on_ring_chain(struct dma_desc *p, int end)
+{
+ p->des01.rx.second_address_chained = 1;
+}
+
+static inline void ndesc_tx_set_on_ring_chain(struct dma_desc *p, int ring_size)
+{
+ p->des01.tx.second_address_chained = 1;
+}
+
+static inline void ndesc_end_tx_desc(struct dma_desc *p, int ter)
+{
+ p->des01.tx.second_address_chained = 1;
+}
+
+static inline void norm_set_tx_desc_len(struct dma_desc *p, int len)
+{
+ p->des01.tx.buffer1_size = len;
+}
+#endif
diff --git a/drivers/net/stmmac/dwmac100.h b/drivers/net/ethernet/stmicro/stmmac/dwmac100.h
index 7c6d857a9cc7..7c6d857a9cc7 100644
--- a/drivers/net/stmmac/dwmac100.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100.h
diff --git a/drivers/net/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
index cfcef0ea0fa5..cfcef0ea0fa5 100644
--- a/drivers/net/stmmac/dwmac1000.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
diff --git a/drivers/net/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
index 0f63b3c83c19..b1c48b975945 100644
--- a/drivers/net/stmmac/dwmac1000_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
@@ -37,11 +37,6 @@ static void dwmac1000_core_init(void __iomem *ioaddr)
value |= GMAC_CORE_INIT;
writel(value, ioaddr + GMAC_CONTROL);
- /* STBus Bridge Configuration */
- /*writel(0xc5608, ioaddr + 0x00007000);*/
-
- /* Freeze MMC counters */
- writel(0x8, ioaddr + GMAC_MMC_CTRL);
/* Mask GMAC interrupts */
writel(0x207, ioaddr + GMAC_INT_MASK);
@@ -229,10 +224,7 @@ static const struct stmmac_ops dwmac1000_ops = {
struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr)
{
struct mac_device_info *mac;
- u32 uid = readl(ioaddr + GMAC_VERSION);
-
- pr_info("\tDWMAC1000 - user ID: 0x%x, Synopsys ID: 0x%x\n",
- ((uid & 0x0000ff00) >> 8), (uid & 0x000000ff));
+ u32 hwid = readl(ioaddr + GMAC_VERSION);
mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
if (!mac)
@@ -246,6 +238,7 @@ struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr)
mac->link.speed = GMAC_CONTROL_FES;
mac->mii.addr = GMAC_MII_ADDR;
mac->mii.data = GMAC_MII_DATA;
+ mac->synopsys_uid = hwid;
return mac;
}
diff --git a/drivers/net/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
index 3dbeea619085..da66ac511c4c 100644
--- a/drivers/net/stmmac/dwmac1000_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
@@ -118,13 +118,6 @@ static void dwmac1000_dma_operation_mode(void __iomem *ioaddr, int txmode,
writel(csr6, ioaddr + DMA_CONTROL);
}
-/* Not yet implemented --- no RMON module */
-static void dwmac1000_dma_diagnostic_fr(void *data,
- struct stmmac_extra_stats *x, void __iomem *ioaddr)
-{
- return;
-}
-
static void dwmac1000_dump_dma_regs(void __iomem *ioaddr)
{
int i;
@@ -139,11 +132,15 @@ static void dwmac1000_dump_dma_regs(void __iomem *ioaddr)
}
}
+static unsigned int dwmac1000_get_hw_feature(void __iomem *ioaddr)
+{
+ return readl(ioaddr + DMA_HW_FEATURE);
+}
+
const struct stmmac_dma_ops dwmac1000_dma_ops = {
.init = dwmac1000_dma_init,
.dump_regs = dwmac1000_dump_dma_regs,
.dma_mode = dwmac1000_dma_operation_mode,
- .dma_diagnostic_fr = dwmac1000_dma_diagnostic_fr,
.enable_dma_transmission = dwmac_enable_dma_transmission,
.enable_dma_irq = dwmac_enable_dma_irq,
.disable_dma_irq = dwmac_disable_dma_irq,
@@ -152,4 +149,5 @@ const struct stmmac_dma_ops dwmac1000_dma_ops = {
.start_rx = dwmac_dma_start_rx,
.stop_rx = dwmac_dma_stop_rx,
.dma_interrupt = dwmac_dma_interrupt,
+ .get_hw_feature = dwmac1000_get_hw_feature,
};
diff --git a/drivers/net/stmmac/dwmac100_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
index 743a58017637..138fb8dd1e87 100644
--- a/drivers/net/stmmac/dwmac100_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
@@ -70,17 +70,6 @@ static void dwmac100_dump_mac_regs(void __iomem *ioaddr)
readl(ioaddr + MAC_VLAN1));
pr_info("\tVLAN2 tag (offset 0x%x): 0x%08x\n", MAC_VLAN2,
readl(ioaddr + MAC_VLAN2));
- pr_info("\n\tMAC management counter registers\n");
- pr_info("\t MMC crtl (offset 0x%x): 0x%08x\n",
- MMC_CONTROL, readl(ioaddr + MMC_CONTROL));
- pr_info("\t MMC High Interrupt (offset 0x%x): 0x%08x\n",
- MMC_HIGH_INTR, readl(ioaddr + MMC_HIGH_INTR));
- pr_info("\t MMC Low Interrupt (offset 0x%x): 0x%08x\n",
- MMC_LOW_INTR, readl(ioaddr + MMC_LOW_INTR));
- pr_info("\t MMC High Interrupt Mask (offset 0x%x): 0x%08x\n",
- MMC_HIGH_INTR_MASK, readl(ioaddr + MMC_HIGH_INTR_MASK));
- pr_info("\t MMC Low Interrupt Mask (offset 0x%x): 0x%08x\n",
- MMC_LOW_INTR_MASK, readl(ioaddr + MMC_LOW_INTR_MASK));
}
static void dwmac100_irq_status(void __iomem *ioaddr)
@@ -199,6 +188,7 @@ struct mac_device_info *dwmac100_setup(void __iomem *ioaddr)
mac->link.speed = 0;
mac->mii.addr = MAC_MII_ADDR;
mac->mii.data = MAC_MII_DATA;
+ mac->synopsys_uid = 0;
return mac;
}
diff --git a/drivers/net/stmmac/dwmac100_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
index 627f656b0f3c..627f656b0f3c 100644
--- a/drivers/net/stmmac/dwmac100_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
diff --git a/drivers/net/stmmac/dwmac_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
index da3f5ccf83d3..437edacd602e 100644
--- a/drivers/net/stmmac/dwmac_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
@@ -34,6 +34,7 @@
#define DMA_MISSED_FRAME_CTR 0x00001020 /* Missed Frame Counter */
#define DMA_CUR_TX_BUF_ADDR 0x00001050 /* Current Host Tx Buffer */
#define DMA_CUR_RX_BUF_ADDR 0x00001054 /* Current Host Rx Buffer */
+#define DMA_HW_FEATURE 0x00001058 /* HW Feature Register */
/* DMA Control register defines */
#define DMA_CONTROL_ST 0x00002000 /* Start/Stop Transmission */
diff --git a/drivers/net/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
index e25093510b0c..e25093510b0c 100644
--- a/drivers/net/stmmac/dwmac_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
diff --git a/drivers/net/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
index e5dfb6a30182..d87976364ec5 100644
--- a/drivers/net/stmmac/enh_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
@@ -23,6 +23,7 @@
*******************************************************************************/
#include "common.h"
+#include "descs_com.h"
static int enh_desc_get_tx_status(void *data, struct stmmac_extra_stats *x,
struct dma_desc *p, void __iomem *ioaddr)
@@ -233,10 +234,9 @@ static void enh_desc_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
for (i = 0; i < ring_size; i++) {
p->des01.erx.own = 1;
p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1;
- /* To support jumbo frames */
- p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1;
- if (i == ring_size - 1)
- p->des01.erx.end_ring = 1;
+
+ ehn_desc_rx_set_on_ring_chain(p, (i == ring_size - 1));
+
if (disable_rx_ic)
p->des01.erx.disable_ic = 1;
p++;
@@ -249,8 +249,7 @@ static void enh_desc_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
for (i = 0; i < ring_size; i++) {
p->des01.etx.own = 0;
- if (i == ring_size - 1)
- p->des01.etx.end_ring = 1;
+ ehn_desc_tx_set_on_ring_chain(p, (i == ring_size - 1));
p++;
}
}
@@ -285,19 +284,16 @@ static void enh_desc_release_tx_desc(struct dma_desc *p)
int ter = p->des01.etx.end_ring;
memset(p, 0, offsetof(struct dma_desc, des2));
- p->des01.etx.end_ring = ter;
+ enh_desc_end_tx_desc(p, ter);
}
static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
int csum_flag)
{
p->des01.etx.first_segment = is_fs;
- if (unlikely(len > BUF_SIZE_4KiB)) {
- p->des01.etx.buffer1_size = BUF_SIZE_4KiB;
- p->des01.etx.buffer2_size = len - BUF_SIZE_4KiB;
- } else {
- p->des01.etx.buffer1_size = len;
- }
+
+ enh_set_tx_desc_len(p, len);
+
if (likely(csum_flag))
p->des01.etx.checksum_insertion = cic_full;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc.h b/drivers/net/ethernet/stmicro/stmmac/mmc.h
new file mode 100644
index 000000000000..a38352024cb8
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/mmc.h
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ MMC Header file
+
+ Copyright (C) 2011 STMicroelectronics Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+/* MMC control register */
+/* When set, all counter are reset */
+#define MMC_CNTRL_COUNTER_RESET 0x1
+/* When set, do not roll over zero
+ * after reaching the max value*/
+#define MMC_CNTRL_COUNTER_STOP_ROLLOVER 0x2
+#define MMC_CNTRL_RESET_ON_READ 0x4 /* Reset after reading */
+#define MMC_CNTRL_COUNTER_FREEZER 0x8 /* Freeze counter values to the
+ * current value.*/
+#define MMC_CNTRL_PRESET 0x10
+#define MMC_CNTRL_FULL_HALF_PRESET 0x20
+struct stmmac_counters {
+ unsigned int mmc_tx_octetcount_gb;
+ unsigned int mmc_tx_framecount_gb;
+ unsigned int mmc_tx_broadcastframe_g;
+ unsigned int mmc_tx_multicastframe_g;
+ unsigned int mmc_tx_64_octets_gb;
+ unsigned int mmc_tx_65_to_127_octets_gb;
+ unsigned int mmc_tx_128_to_255_octets_gb;
+ unsigned int mmc_tx_256_to_511_octets_gb;
+ unsigned int mmc_tx_512_to_1023_octets_gb;
+ unsigned int mmc_tx_1024_to_max_octets_gb;
+ unsigned int mmc_tx_unicast_gb;
+ unsigned int mmc_tx_multicast_gb;
+ unsigned int mmc_tx_broadcast_gb;
+ unsigned int mmc_tx_underflow_error;
+ unsigned int mmc_tx_singlecol_g;
+ unsigned int mmc_tx_multicol_g;
+ unsigned int mmc_tx_deferred;
+ unsigned int mmc_tx_latecol;
+ unsigned int mmc_tx_exesscol;
+ unsigned int mmc_tx_carrier_error;
+ unsigned int mmc_tx_octetcount_g;
+ unsigned int mmc_tx_framecount_g;
+ unsigned int mmc_tx_excessdef;
+ unsigned int mmc_tx_pause_frame;
+ unsigned int mmc_tx_vlan_frame_g;
+
+ /* MMC RX counter registers */
+ unsigned int mmc_rx_framecount_gb;
+ unsigned int mmc_rx_octetcount_gb;
+ unsigned int mmc_rx_octetcount_g;
+ unsigned int mmc_rx_broadcastframe_g;
+ unsigned int mmc_rx_multicastframe_g;
+ unsigned int mmc_rx_crc_errror;
+ unsigned int mmc_rx_align_error;
+ unsigned int mmc_rx_run_error;
+ unsigned int mmc_rx_jabber_error;
+ unsigned int mmc_rx_undersize_g;
+ unsigned int mmc_rx_oversize_g;
+ unsigned int mmc_rx_64_octets_gb;
+ unsigned int mmc_rx_65_to_127_octets_gb;
+ unsigned int mmc_rx_128_to_255_octets_gb;
+ unsigned int mmc_rx_256_to_511_octets_gb;
+ unsigned int mmc_rx_512_to_1023_octets_gb;
+ unsigned int mmc_rx_1024_to_max_octets_gb;
+ unsigned int mmc_rx_unicast_g;
+ unsigned int mmc_rx_length_error;
+ unsigned int mmc_rx_autofrangetype;
+ unsigned int mmc_rx_pause_frames;
+ unsigned int mmc_rx_fifo_overflow;
+ unsigned int mmc_rx_vlan_frames_gb;
+ unsigned int mmc_rx_watchdog_error;
+ /* IPC */
+ unsigned int mmc_rx_ipc_intr_mask;
+ unsigned int mmc_rx_ipc_intr;
+ /* IPv4 */
+ unsigned int mmc_rx_ipv4_gd;
+ unsigned int mmc_rx_ipv4_hderr;
+ unsigned int mmc_rx_ipv4_nopay;
+ unsigned int mmc_rx_ipv4_frag;
+ unsigned int mmc_rx_ipv4_udsbl;
+
+ unsigned int mmc_rx_ipv4_gd_octets;
+ unsigned int mmc_rx_ipv4_hderr_octets;
+ unsigned int mmc_rx_ipv4_nopay_octets;
+ unsigned int mmc_rx_ipv4_frag_octets;
+ unsigned int mmc_rx_ipv4_udsbl_octets;
+
+ /* IPV6 */
+ unsigned int mmc_rx_ipv6_gd_octets;
+ unsigned int mmc_rx_ipv6_hderr_octets;
+ unsigned int mmc_rx_ipv6_nopay_octets;
+
+ unsigned int mmc_rx_ipv6_gd;
+ unsigned int mmc_rx_ipv6_hderr;
+ unsigned int mmc_rx_ipv6_nopay;
+
+ /* Protocols */
+ unsigned int mmc_rx_udp_gd;
+ unsigned int mmc_rx_udp_err;
+ unsigned int mmc_rx_tcp_gd;
+ unsigned int mmc_rx_tcp_err;
+ unsigned int mmc_rx_icmp_gd;
+ unsigned int mmc_rx_icmp_err;
+
+ unsigned int mmc_rx_udp_gd_octets;
+ unsigned int mmc_rx_udp_err_octets;
+ unsigned int mmc_rx_tcp_gd_octets;
+ unsigned int mmc_rx_tcp_err_octets;
+ unsigned int mmc_rx_icmp_gd_octets;
+ unsigned int mmc_rx_icmp_err_octets;
+};
+
+extern void dwmac_mmc_ctrl(void __iomem *ioaddr, unsigned int mode);
+extern void dwmac_mmc_intr_all_mask(void __iomem *ioaddr);
+extern void dwmac_mmc_read(void __iomem *ioaddr, struct stmmac_counters *mmc);
diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
new file mode 100644
index 000000000000..41e6b33e1b08
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
@@ -0,0 +1,265 @@
+/*******************************************************************************
+ DWMAC Management Counters
+
+ Copyright (C) 2011 STMicroelectronics Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#include <linux/io.h>
+#include "mmc.h"
+
+/* MAC Management Counters register offset */
+
+#define MMC_CNTRL 0x00000100 /* MMC Control */
+#define MMC_RX_INTR 0x00000104 /* MMC RX Interrupt */
+#define MMC_TX_INTR 0x00000108 /* MMC TX Interrupt */
+#define MMC_RX_INTR_MASK 0x0000010c /* MMC Interrupt Mask */
+#define MMC_TX_INTR_MASK 0x00000110 /* MMC Interrupt Mask */
+#define MMC_DEFAUL_MASK 0xffffffff
+
+/* MMC TX counter registers */
+
+/* Note:
+ * _GB register stands for good and bad frames
+ * _G is for good only.
+ */
+#define MMC_TX_OCTETCOUNT_GB 0x00000114
+#define MMC_TX_FRAMECOUNT_GB 0x00000118
+#define MMC_TX_BROADCASTFRAME_G 0x0000011c
+#define MMC_TX_MULTICASTFRAME_G 0x00000120
+#define MMC_TX_64_OCTETS_GB 0x00000124
+#define MMC_TX_65_TO_127_OCTETS_GB 0x00000128
+#define MMC_TX_128_TO_255_OCTETS_GB 0x0000012c
+#define MMC_TX_256_TO_511_OCTETS_GB 0x00000130
+#define MMC_TX_512_TO_1023_OCTETS_GB 0x00000134
+#define MMC_TX_1024_TO_MAX_OCTETS_GB 0x00000138
+#define MMC_TX_UNICAST_GB 0x0000013c
+#define MMC_TX_MULTICAST_GB 0x00000140
+#define MMC_TX_BROADCAST_GB 0x00000144
+#define MMC_TX_UNDERFLOW_ERROR 0x00000148
+#define MMC_TX_SINGLECOL_G 0x0000014c
+#define MMC_TX_MULTICOL_G 0x00000150
+#define MMC_TX_DEFERRED 0x00000154
+#define MMC_TX_LATECOL 0x00000158
+#define MMC_TX_EXESSCOL 0x0000015c
+#define MMC_TX_CARRIER_ERROR 0x00000160
+#define MMC_TX_OCTETCOUNT_G 0x00000164
+#define MMC_TX_FRAMECOUNT_G 0x00000168
+#define MMC_TX_EXCESSDEF 0x0000016c
+#define MMC_TX_PAUSE_FRAME 0x00000170
+#define MMC_TX_VLAN_FRAME_G 0x00000174
+
+/* MMC RX counter registers */
+#define MMC_RX_FRAMECOUNT_GB 0x00000180
+#define MMC_RX_OCTETCOUNT_GB 0x00000184
+#define MMC_RX_OCTETCOUNT_G 0x00000188
+#define MMC_RX_BROADCASTFRAME_G 0x0000018c
+#define MMC_RX_MULTICASTFRAME_G 0x00000190
+#define MMC_RX_CRC_ERRROR 0x00000194
+#define MMC_RX_ALIGN_ERROR 0x00000198
+#define MMC_RX_RUN_ERROR 0x0000019C
+#define MMC_RX_JABBER_ERROR 0x000001A0
+#define MMC_RX_UNDERSIZE_G 0x000001A4
+#define MMC_RX_OVERSIZE_G 0x000001A8
+#define MMC_RX_64_OCTETS_GB 0x000001AC
+#define MMC_RX_65_TO_127_OCTETS_GB 0x000001b0
+#define MMC_RX_128_TO_255_OCTETS_GB 0x000001b4
+#define MMC_RX_256_TO_511_OCTETS_GB 0x000001b8
+#define MMC_RX_512_TO_1023_OCTETS_GB 0x000001bc
+#define MMC_RX_1024_TO_MAX_OCTETS_GB 0x000001c0
+#define MMC_RX_UNICAST_G 0x000001c4
+#define MMC_RX_LENGTH_ERROR 0x000001c8
+#define MMC_RX_AUTOFRANGETYPE 0x000001cc
+#define MMC_RX_PAUSE_FRAMES 0x000001d0
+#define MMC_RX_FIFO_OVERFLOW 0x000001d4
+#define MMC_RX_VLAN_FRAMES_GB 0x000001d8
+#define MMC_RX_WATCHDOG_ERROR 0x000001dc
+/* IPC*/
+#define MMC_RX_IPC_INTR_MASK 0x00000200
+#define MMC_RX_IPC_INTR 0x00000208
+/* IPv4*/
+#define MMC_RX_IPV4_GD 0x00000210
+#define MMC_RX_IPV4_HDERR 0x00000214
+#define MMC_RX_IPV4_NOPAY 0x00000218
+#define MMC_RX_IPV4_FRAG 0x0000021C
+#define MMC_RX_IPV4_UDSBL 0x00000220
+
+#define MMC_RX_IPV4_GD_OCTETS 0x00000250
+#define MMC_RX_IPV4_HDERR_OCTETS 0x00000254
+#define MMC_RX_IPV4_NOPAY_OCTETS 0x00000258
+#define MMC_RX_IPV4_FRAG_OCTETS 0x0000025c
+#define MMC_RX_IPV4_UDSBL_OCTETS 0x00000260
+
+/* IPV6*/
+#define MMC_RX_IPV6_GD_OCTETS 0x00000264
+#define MMC_RX_IPV6_HDERR_OCTETS 0x00000268
+#define MMC_RX_IPV6_NOPAY_OCTETS 0x0000026c
+
+#define MMC_RX_IPV6_GD 0x00000224
+#define MMC_RX_IPV6_HDERR 0x00000228
+#define MMC_RX_IPV6_NOPAY 0x0000022c
+
+/* Protocols*/
+#define MMC_RX_UDP_GD 0x00000230
+#define MMC_RX_UDP_ERR 0x00000234
+#define MMC_RX_TCP_GD 0x00000238
+#define MMC_RX_TCP_ERR 0x0000023c
+#define MMC_RX_ICMP_GD 0x00000240
+#define MMC_RX_ICMP_ERR 0x00000244
+
+#define MMC_RX_UDP_GD_OCTETS 0x00000270
+#define MMC_RX_UDP_ERR_OCTETS 0x00000274
+#define MMC_RX_TCP_GD_OCTETS 0x00000278
+#define MMC_RX_TCP_ERR_OCTETS 0x0000027c
+#define MMC_RX_ICMP_GD_OCTETS 0x00000280
+#define MMC_RX_ICMP_ERR_OCTETS 0x00000284
+
+void dwmac_mmc_ctrl(void __iomem *ioaddr, unsigned int mode)
+{
+ u32 value = readl(ioaddr + MMC_CNTRL);
+
+ value |= (mode & 0x3F);
+
+ writel(value, ioaddr + MMC_CNTRL);
+
+ pr_debug("stmmac: MMC ctrl register (offset 0x%x): 0x%08x\n",
+ MMC_CNTRL, value);
+}
+
+/* To mask all all interrupts.*/
+void dwmac_mmc_intr_all_mask(void __iomem *ioaddr)
+{
+ writel(MMC_DEFAUL_MASK, ioaddr + MMC_RX_INTR_MASK);
+ writel(MMC_DEFAUL_MASK, ioaddr + MMC_TX_INTR_MASK);
+}
+
+/* This reads the MAC core counters (if actaully supported).
+ * by default the MMC core is programmed to reset each
+ * counter after a read. So all the field of the mmc struct
+ * have to be incremented.
+ */
+void dwmac_mmc_read(void __iomem *ioaddr, struct stmmac_counters *mmc)
+{
+ mmc->mmc_tx_octetcount_gb += readl(ioaddr + MMC_TX_OCTETCOUNT_GB);
+ mmc->mmc_tx_framecount_gb += readl(ioaddr + MMC_TX_FRAMECOUNT_GB);
+ mmc->mmc_tx_broadcastframe_g += readl(ioaddr + MMC_TX_BROADCASTFRAME_G);
+ mmc->mmc_tx_multicastframe_g += readl(ioaddr + MMC_TX_MULTICASTFRAME_G);
+ mmc->mmc_tx_64_octets_gb += readl(ioaddr + MMC_TX_64_OCTETS_GB);
+ mmc->mmc_tx_65_to_127_octets_gb +=
+ readl(ioaddr + MMC_TX_65_TO_127_OCTETS_GB);
+ mmc->mmc_tx_128_to_255_octets_gb +=
+ readl(ioaddr + MMC_TX_128_TO_255_OCTETS_GB);
+ mmc->mmc_tx_256_to_511_octets_gb +=
+ readl(ioaddr + MMC_TX_256_TO_511_OCTETS_GB);
+ mmc->mmc_tx_512_to_1023_octets_gb +=
+ readl(ioaddr + MMC_TX_512_TO_1023_OCTETS_GB);
+ mmc->mmc_tx_1024_to_max_octets_gb +=
+ readl(ioaddr + MMC_TX_1024_TO_MAX_OCTETS_GB);
+ mmc->mmc_tx_unicast_gb += readl(ioaddr + MMC_TX_UNICAST_GB);
+ mmc->mmc_tx_multicast_gb += readl(ioaddr + MMC_TX_MULTICAST_GB);
+ mmc->mmc_tx_broadcast_gb += readl(ioaddr + MMC_TX_BROADCAST_GB);
+ mmc->mmc_tx_underflow_error += readl(ioaddr + MMC_TX_UNDERFLOW_ERROR);
+ mmc->mmc_tx_singlecol_g += readl(ioaddr + MMC_TX_SINGLECOL_G);
+ mmc->mmc_tx_multicol_g += readl(ioaddr + MMC_TX_MULTICOL_G);
+ mmc->mmc_tx_deferred += readl(ioaddr + MMC_TX_DEFERRED);
+ mmc->mmc_tx_latecol += readl(ioaddr + MMC_TX_LATECOL);
+ mmc->mmc_tx_exesscol += readl(ioaddr + MMC_TX_EXESSCOL);
+ mmc->mmc_tx_carrier_error += readl(ioaddr + MMC_TX_CARRIER_ERROR);
+ mmc->mmc_tx_octetcount_g += readl(ioaddr + MMC_TX_OCTETCOUNT_G);
+ mmc->mmc_tx_framecount_g += readl(ioaddr + MMC_TX_FRAMECOUNT_G);
+ mmc->mmc_tx_excessdef += readl(ioaddr + MMC_TX_EXCESSDEF);
+ mmc->mmc_tx_pause_frame += readl(ioaddr + MMC_TX_PAUSE_FRAME);
+ mmc->mmc_tx_vlan_frame_g += readl(ioaddr + MMC_TX_VLAN_FRAME_G);
+
+ /* MMC RX counter registers */
+ mmc->mmc_rx_framecount_gb += readl(ioaddr + MMC_RX_FRAMECOUNT_GB);
+ mmc->mmc_rx_octetcount_gb += readl(ioaddr + MMC_RX_OCTETCOUNT_GB);
+ mmc->mmc_rx_octetcount_g += readl(ioaddr + MMC_RX_OCTETCOUNT_G);
+ mmc->mmc_rx_broadcastframe_g += readl(ioaddr + MMC_RX_BROADCASTFRAME_G);
+ mmc->mmc_rx_multicastframe_g += readl(ioaddr + MMC_RX_MULTICASTFRAME_G);
+ mmc->mmc_rx_crc_errror += readl(ioaddr + MMC_RX_CRC_ERRROR);
+ mmc->mmc_rx_align_error += readl(ioaddr + MMC_RX_ALIGN_ERROR);
+ mmc->mmc_rx_run_error += readl(ioaddr + MMC_RX_RUN_ERROR);
+ mmc->mmc_rx_jabber_error += readl(ioaddr + MMC_RX_JABBER_ERROR);
+ mmc->mmc_rx_undersize_g += readl(ioaddr + MMC_RX_UNDERSIZE_G);
+ mmc->mmc_rx_oversize_g += readl(ioaddr + MMC_RX_OVERSIZE_G);
+ mmc->mmc_rx_64_octets_gb += readl(ioaddr + MMC_RX_64_OCTETS_GB);
+ mmc->mmc_rx_65_to_127_octets_gb +=
+ readl(ioaddr + MMC_RX_65_TO_127_OCTETS_GB);
+ mmc->mmc_rx_128_to_255_octets_gb +=
+ readl(ioaddr + MMC_RX_128_TO_255_OCTETS_GB);
+ mmc->mmc_rx_256_to_511_octets_gb +=
+ readl(ioaddr + MMC_RX_256_TO_511_OCTETS_GB);
+ mmc->mmc_rx_512_to_1023_octets_gb +=
+ readl(ioaddr + MMC_RX_512_TO_1023_OCTETS_GB);
+ mmc->mmc_rx_1024_to_max_octets_gb +=
+ readl(ioaddr + MMC_RX_1024_TO_MAX_OCTETS_GB);
+ mmc->mmc_rx_unicast_g += readl(ioaddr + MMC_RX_UNICAST_G);
+ mmc->mmc_rx_length_error += readl(ioaddr + MMC_RX_LENGTH_ERROR);
+ mmc->mmc_rx_autofrangetype += readl(ioaddr + MMC_RX_AUTOFRANGETYPE);
+ mmc->mmc_rx_pause_frames += readl(ioaddr + MMC_RX_PAUSE_FRAMES);
+ mmc->mmc_rx_fifo_overflow += readl(ioaddr + MMC_RX_FIFO_OVERFLOW);
+ mmc->mmc_rx_vlan_frames_gb += readl(ioaddr + MMC_RX_VLAN_FRAMES_GB);
+ mmc->mmc_rx_watchdog_error += readl(ioaddr + MMC_RX_WATCHDOG_ERROR);
+ /* IPC */
+ mmc->mmc_rx_ipc_intr_mask += readl(ioaddr + MMC_RX_IPC_INTR_MASK);
+ mmc->mmc_rx_ipc_intr += readl(ioaddr + MMC_RX_IPC_INTR);
+ /* IPv4 */
+ mmc->mmc_rx_ipv4_gd += readl(ioaddr + MMC_RX_IPV4_GD);
+ mmc->mmc_rx_ipv4_hderr += readl(ioaddr + MMC_RX_IPV4_HDERR);
+ mmc->mmc_rx_ipv4_nopay += readl(ioaddr + MMC_RX_IPV4_NOPAY);
+ mmc->mmc_rx_ipv4_frag += readl(ioaddr + MMC_RX_IPV4_FRAG);
+ mmc->mmc_rx_ipv4_udsbl += readl(ioaddr + MMC_RX_IPV4_UDSBL);
+
+ mmc->mmc_rx_ipv4_gd_octets += readl(ioaddr + MMC_RX_IPV4_GD_OCTETS);
+ mmc->mmc_rx_ipv4_hderr_octets +=
+ readl(ioaddr + MMC_RX_IPV4_HDERR_OCTETS);
+ mmc->mmc_rx_ipv4_nopay_octets +=
+ readl(ioaddr + MMC_RX_IPV4_NOPAY_OCTETS);
+ mmc->mmc_rx_ipv4_frag_octets += readl(ioaddr + MMC_RX_IPV4_FRAG_OCTETS);
+ mmc->mmc_rx_ipv4_udsbl_octets +=
+ readl(ioaddr + MMC_RX_IPV4_UDSBL_OCTETS);
+
+ /* IPV6 */
+ mmc->mmc_rx_ipv6_gd_octets += readl(ioaddr + MMC_RX_IPV6_GD_OCTETS);
+ mmc->mmc_rx_ipv6_hderr_octets +=
+ readl(ioaddr + MMC_RX_IPV6_HDERR_OCTETS);
+ mmc->mmc_rx_ipv6_nopay_octets +=
+ readl(ioaddr + MMC_RX_IPV6_NOPAY_OCTETS);
+
+ mmc->mmc_rx_ipv6_gd += readl(ioaddr + MMC_RX_IPV6_GD);
+ mmc->mmc_rx_ipv6_hderr += readl(ioaddr + MMC_RX_IPV6_HDERR);
+ mmc->mmc_rx_ipv6_nopay += readl(ioaddr + MMC_RX_IPV6_NOPAY);
+
+ /* Protocols */
+ mmc->mmc_rx_udp_gd += readl(ioaddr + MMC_RX_UDP_GD);
+ mmc->mmc_rx_udp_err += readl(ioaddr + MMC_RX_UDP_ERR);
+ mmc->mmc_rx_tcp_gd += readl(ioaddr + MMC_RX_TCP_GD);
+ mmc->mmc_rx_tcp_err += readl(ioaddr + MMC_RX_TCP_ERR);
+ mmc->mmc_rx_icmp_gd += readl(ioaddr + MMC_RX_ICMP_GD);
+ mmc->mmc_rx_icmp_err += readl(ioaddr + MMC_RX_ICMP_ERR);
+
+ mmc->mmc_rx_udp_gd_octets += readl(ioaddr + MMC_RX_UDP_GD_OCTETS);
+ mmc->mmc_rx_udp_err_octets += readl(ioaddr + MMC_RX_UDP_ERR_OCTETS);
+ mmc->mmc_rx_tcp_gd_octets += readl(ioaddr + MMC_RX_TCP_GD_OCTETS);
+ mmc->mmc_rx_tcp_err_octets += readl(ioaddr + MMC_RX_TCP_ERR_OCTETS);
+ mmc->mmc_rx_icmp_gd_octets += readl(ioaddr + MMC_RX_ICMP_GD_OCTETS);
+ mmc->mmc_rx_icmp_err_octets += readl(ioaddr + MMC_RX_ICMP_ERR_OCTETS);
+}
diff --git a/drivers/net/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
index 029c2a2cf524..f7e8ba7f501a 100644
--- a/drivers/net/stmmac/norm_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
@@ -23,6 +23,7 @@
*******************************************************************************/
#include "common.h"
+#include "descs_com.h"
static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x,
struct dma_desc *p, void __iomem *ioaddr)
@@ -126,8 +127,9 @@ static void ndesc_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
for (i = 0; i < ring_size; i++) {
p->des01.rx.own = 1;
p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
- if (i == ring_size - 1)
- p->des01.rx.end_ring = 1;
+
+ ndesc_rx_set_on_ring_chain(p, (i == ring_size - 1));
+
if (disable_rx_ic)
p->des01.rx.disable_ic = 1;
p++;
@@ -139,8 +141,7 @@ static void ndesc_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
int i;
for (i = 0; i < ring_size; i++) {
p->des01.tx.own = 0;
- if (i == ring_size - 1)
- p->des01.tx.end_ring = 1;
+ ndesc_tx_set_on_ring_chain(p, (i == (ring_size - 1)));
p++;
}
}
@@ -175,15 +176,14 @@ static void ndesc_release_tx_desc(struct dma_desc *p)
int ter = p->des01.tx.end_ring;
memset(p, 0, offsetof(struct dma_desc, des2));
- /* set termination field */
- p->des01.tx.end_ring = ter;
+ ndesc_end_tx_desc(p, ter);
}
static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
int csum_flag)
{
p->des01.tx.first_segment = is_fs;
- p->des01.tx.buffer1_size = len;
+ norm_set_tx_desc_len(p, len);
}
static void ndesc_clear_tx_ic(struct dma_desc *p)
diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
new file mode 100644
index 000000000000..fb8377da1687
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ Specialised functions for managing Ring mode
+
+ Copyright(C) 2011 STMicroelectronics Ltd
+
+ It defines all the functions used to handle the normal/enhanced
+ descriptors in case of the DMA is configured to work in chained or
+ in ring mode.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#include "stmmac.h"
+
+static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
+{
+ struct stmmac_priv *priv = (struct stmmac_priv *) p;
+ unsigned int txsize = priv->dma_tx_size;
+ unsigned int entry = priv->cur_tx % txsize;
+ struct dma_desc *desc = priv->dma_tx + entry;
+ unsigned int nopaged_len = skb_headlen(skb);
+ unsigned int bmax, len;
+
+ if (priv->plat->enh_desc)
+ bmax = BUF_SIZE_8KiB;
+ else
+ bmax = BUF_SIZE_2KiB;
+
+ len = nopaged_len - bmax;
+
+ if (nopaged_len > BUF_SIZE_8KiB) {
+
+ desc->des2 = dma_map_single(priv->device, skb->data,
+ bmax, DMA_TO_DEVICE);
+ desc->des3 = desc->des2 + BUF_SIZE_4KiB;
+ priv->hw->desc->prepare_tx_desc(desc, 1, bmax,
+ csum);
+
+ entry = (++priv->cur_tx) % txsize;
+ desc = priv->dma_tx + entry;
+
+ desc->des2 = dma_map_single(priv->device, skb->data + bmax,
+ len, DMA_TO_DEVICE);
+ desc->des3 = desc->des2 + BUF_SIZE_4KiB;
+ priv->hw->desc->prepare_tx_desc(desc, 0, len, csum);
+ priv->hw->desc->set_tx_owner(desc);
+ priv->tx_skbuff[entry] = NULL;
+ } else {
+ desc->des2 = dma_map_single(priv->device, skb->data,
+ nopaged_len, DMA_TO_DEVICE);
+ desc->des3 = desc->des2 + BUF_SIZE_4KiB;
+ priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, csum);
+ }
+
+ return entry;
+}
+
+static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
+{
+ unsigned int ret = 0;
+
+ if (len >= BUF_SIZE_4KiB)
+ ret = 1;
+
+ return ret;
+}
+
+static void stmmac_refill_desc3(int bfsize, struct dma_desc *p)
+{
+ /* Fill DES3 in case of RING mode */
+ if (bfsize >= BUF_SIZE_8KiB)
+ p->des3 = p->des2 + BUF_SIZE_8KiB;
+}
+
+/* In ring mode we need to fill the desc3 because it is used
+ * as buffer */
+static void stmmac_init_desc3(int des3_as_data_buf, struct dma_desc *p)
+{
+ if (unlikely(des3_as_data_buf))
+ p->des3 = p->des2 + BUF_SIZE_8KiB;
+}
+
+static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr,
+ unsigned int size)
+{
+}
+
+static void stmmac_clean_desc3(struct dma_desc *p)
+{
+ if (unlikely(p->des3))
+ p->des3 = 0;
+}
+
+static int stmmac_set_16kib_bfsize(int mtu)
+{
+ int ret = 0;
+ if (unlikely(mtu >= BUF_SIZE_8KiB))
+ ret = BUF_SIZE_16KiB;
+ return ret;
+}
+
+const struct stmmac_ring_mode_ops ring_mode_ops = {
+ .is_jumbo_frm = stmmac_is_jumbo_frm,
+ .jumbo_frm = stmmac_jumbo_frm,
+ .refill_desc3 = stmmac_refill_desc3,
+ .init_desc3 = stmmac_init_desc3,
+ .init_dma_chain = stmmac_init_dma_chain,
+ .clean_desc3 = stmmac_clean_desc3,
+ .set_16kib_bfsize = stmmac_set_16kib_bfsize,
+};
diff --git a/drivers/net/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index de1929b2641b..9bafa6cf9e8b 100644
--- a/drivers/net/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -20,9 +20,9 @@
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
*******************************************************************************/
-#define DRV_MODULE_VERSION "July_2011"
+#define DRV_MODULE_VERSION "Oct_2011"
#include <linux/stmmac.h>
-
+#include <linux/phy.h>
#include "common.h"
#ifdef CONFIG_STMMAC_TIMER
#include "stmmac_timer.h"
@@ -70,12 +70,16 @@ struct stmmac_priv {
u32 msg_enable;
spinlock_t lock;
+ spinlock_t tx_lock;
int wolopts;
int wolenabled;
+ int wol_irq;
#ifdef CONFIG_STMMAC_TIMER
struct stmmac_timer *tm;
#endif
struct plat_stmmacenet_data *plat;
+ struct stmmac_counters mmc;
+ struct dma_features dma_cap;
};
extern int stmmac_mdio_unregister(struct net_device *ndev);
diff --git a/drivers/net/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index 7ed8fb6c2117..406404f6e321 100644
--- a/drivers/net/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -46,7 +46,7 @@ struct stmmac_stats {
{ #m, FIELD_SIZEOF(struct stmmac_extra_stats, m), \
offsetof(struct stmmac_priv, xstats.m)}
-static const struct stmmac_stats stmmac_gstrings_stats[] = {
+static const struct stmmac_stats stmmac_gstrings_stats[] = {
STMMAC_STAT(tx_underflow),
STMMAC_STAT(tx_carrier),
STMMAC_STAT(tx_losscarrier),
@@ -91,19 +91,106 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
};
#define STMMAC_STATS_LEN ARRAY_SIZE(stmmac_gstrings_stats)
+/* HW MAC Management counters (if supported) */
+#define STMMAC_MMC_STAT(m) \
+ { #m, FIELD_SIZEOF(struct stmmac_counters, m), \
+ offsetof(struct stmmac_priv, mmc.m)}
+
+static const struct stmmac_stats stmmac_mmc[] = {
+ STMMAC_MMC_STAT(mmc_tx_octetcount_gb),
+ STMMAC_MMC_STAT(mmc_tx_framecount_gb),
+ STMMAC_MMC_STAT(mmc_tx_broadcastframe_g),
+ STMMAC_MMC_STAT(mmc_tx_multicastframe_g),
+ STMMAC_MMC_STAT(mmc_tx_64_octets_gb),
+ STMMAC_MMC_STAT(mmc_tx_65_to_127_octets_gb),
+ STMMAC_MMC_STAT(mmc_tx_128_to_255_octets_gb),
+ STMMAC_MMC_STAT(mmc_tx_256_to_511_octets_gb),
+ STMMAC_MMC_STAT(mmc_tx_512_to_1023_octets_gb),
+ STMMAC_MMC_STAT(mmc_tx_1024_to_max_octets_gb),
+ STMMAC_MMC_STAT(mmc_tx_unicast_gb),
+ STMMAC_MMC_STAT(mmc_tx_multicast_gb),
+ STMMAC_MMC_STAT(mmc_tx_broadcast_gb),
+ STMMAC_MMC_STAT(mmc_tx_underflow_error),
+ STMMAC_MMC_STAT(mmc_tx_singlecol_g),
+ STMMAC_MMC_STAT(mmc_tx_multicol_g),
+ STMMAC_MMC_STAT(mmc_tx_deferred),
+ STMMAC_MMC_STAT(mmc_tx_latecol),
+ STMMAC_MMC_STAT(mmc_tx_exesscol),
+ STMMAC_MMC_STAT(mmc_tx_carrier_error),
+ STMMAC_MMC_STAT(mmc_tx_octetcount_g),
+ STMMAC_MMC_STAT(mmc_tx_framecount_g),
+ STMMAC_MMC_STAT(mmc_tx_excessdef),
+ STMMAC_MMC_STAT(mmc_tx_pause_frame),
+ STMMAC_MMC_STAT(mmc_tx_vlan_frame_g),
+ STMMAC_MMC_STAT(mmc_rx_framecount_gb),
+ STMMAC_MMC_STAT(mmc_rx_octetcount_gb),
+ STMMAC_MMC_STAT(mmc_rx_octetcount_g),
+ STMMAC_MMC_STAT(mmc_rx_broadcastframe_g),
+ STMMAC_MMC_STAT(mmc_rx_multicastframe_g),
+ STMMAC_MMC_STAT(mmc_rx_crc_errror),
+ STMMAC_MMC_STAT(mmc_rx_align_error),
+ STMMAC_MMC_STAT(mmc_rx_run_error),
+ STMMAC_MMC_STAT(mmc_rx_jabber_error),
+ STMMAC_MMC_STAT(mmc_rx_undersize_g),
+ STMMAC_MMC_STAT(mmc_rx_oversize_g),
+ STMMAC_MMC_STAT(mmc_rx_64_octets_gb),
+ STMMAC_MMC_STAT(mmc_rx_65_to_127_octets_gb),
+ STMMAC_MMC_STAT(mmc_rx_128_to_255_octets_gb),
+ STMMAC_MMC_STAT(mmc_rx_256_to_511_octets_gb),
+ STMMAC_MMC_STAT(mmc_rx_512_to_1023_octets_gb),
+ STMMAC_MMC_STAT(mmc_rx_1024_to_max_octets_gb),
+ STMMAC_MMC_STAT(mmc_rx_unicast_g),
+ STMMAC_MMC_STAT(mmc_rx_length_error),
+ STMMAC_MMC_STAT(mmc_rx_autofrangetype),
+ STMMAC_MMC_STAT(mmc_rx_pause_frames),
+ STMMAC_MMC_STAT(mmc_rx_fifo_overflow),
+ STMMAC_MMC_STAT(mmc_rx_vlan_frames_gb),
+ STMMAC_MMC_STAT(mmc_rx_watchdog_error),
+ STMMAC_MMC_STAT(mmc_rx_ipc_intr_mask),
+ STMMAC_MMC_STAT(mmc_rx_ipc_intr),
+ STMMAC_MMC_STAT(mmc_rx_ipv4_gd),
+ STMMAC_MMC_STAT(mmc_rx_ipv4_hderr),
+ STMMAC_MMC_STAT(mmc_rx_ipv4_nopay),
+ STMMAC_MMC_STAT(mmc_rx_ipv4_frag),
+ STMMAC_MMC_STAT(mmc_rx_ipv4_udsbl),
+ STMMAC_MMC_STAT(mmc_rx_ipv4_gd_octets),
+ STMMAC_MMC_STAT(mmc_rx_ipv4_hderr_octets),
+ STMMAC_MMC_STAT(mmc_rx_ipv4_nopay_octets),
+ STMMAC_MMC_STAT(mmc_rx_ipv4_frag_octets),
+ STMMAC_MMC_STAT(mmc_rx_ipv4_udsbl_octets),
+ STMMAC_MMC_STAT(mmc_rx_ipv6_gd_octets),
+ STMMAC_MMC_STAT(mmc_rx_ipv6_hderr_octets),
+ STMMAC_MMC_STAT(mmc_rx_ipv6_nopay_octets),
+ STMMAC_MMC_STAT(mmc_rx_ipv6_gd),
+ STMMAC_MMC_STAT(mmc_rx_ipv6_hderr),
+ STMMAC_MMC_STAT(mmc_rx_ipv6_nopay),
+ STMMAC_MMC_STAT(mmc_rx_udp_gd),
+ STMMAC_MMC_STAT(mmc_rx_udp_err),
+ STMMAC_MMC_STAT(mmc_rx_tcp_gd),
+ STMMAC_MMC_STAT(mmc_rx_tcp_err),
+ STMMAC_MMC_STAT(mmc_rx_icmp_gd),
+ STMMAC_MMC_STAT(mmc_rx_icmp_err),
+ STMMAC_MMC_STAT(mmc_rx_udp_gd_octets),
+ STMMAC_MMC_STAT(mmc_rx_udp_err_octets),
+ STMMAC_MMC_STAT(mmc_rx_tcp_gd_octets),
+ STMMAC_MMC_STAT(mmc_rx_tcp_err_octets),
+ STMMAC_MMC_STAT(mmc_rx_icmp_gd_octets),
+ STMMAC_MMC_STAT(mmc_rx_icmp_err_octets),
+};
+#define STMMAC_MMC_STATS_LEN ARRAY_SIZE(stmmac_mmc)
+
static void stmmac_ethtool_getdrvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
struct stmmac_priv *priv = netdev_priv(dev);
- if (!priv->plat->has_gmac)
- strcpy(info->driver, MAC100_ETHTOOL_NAME);
- else
+ if (priv->plat->has_gmac)
strcpy(info->driver, GMAC_ETHTOOL_NAME);
+ else
+ strcpy(info->driver, MAC100_ETHTOOL_NAME);
strcpy(info->version, DRV_MODULE_VERSION);
info->fw_version[0] = '\0';
- info->n_stats = STMMAC_STATS_LEN;
}
static int stmmac_ethtool_getsettings(struct net_device *dev,
@@ -252,24 +339,48 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *dummy, u64 *data)
{
struct stmmac_priv *priv = netdev_priv(dev);
- int i;
-
- /* Update HW stats if supported */
- priv->hw->dma->dma_diagnostic_fr(&dev->stats, (void *) &priv->xstats,
- priv->ioaddr);
+ int i, j = 0;
+ /* Update the DMA HW counters for dwmac10/100 */
+ if (!priv->plat->has_gmac)
+ priv->hw->dma->dma_diagnostic_fr(&dev->stats,
+ (void *) &priv->xstats,
+ priv->ioaddr);
+ else {
+ /* If supported, for new GMAC chips expose the MMC counters */
+ if (priv->dma_cap.rmon) {
+ dwmac_mmc_read(priv->ioaddr, &priv->mmc);
+
+ for (i = 0; i < STMMAC_MMC_STATS_LEN; i++) {
+ char *p;
+ p = (char *)priv + stmmac_mmc[i].stat_offset;
+
+ data[j++] = (stmmac_mmc[i].sizeof_stat ==
+ sizeof(u64)) ? (*(u64 *)p) :
+ (*(u32 *)p);
+ }
+ }
+ }
for (i = 0; i < STMMAC_STATS_LEN; i++) {
char *p = (char *)priv + stmmac_gstrings_stats[i].stat_offset;
- data[i] = (stmmac_gstrings_stats[i].sizeof_stat ==
- sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p);
+ data[j++] = (stmmac_gstrings_stats[i].sizeof_stat ==
+ sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p);
}
}
static int stmmac_get_sset_count(struct net_device *netdev, int sset)
{
+ struct stmmac_priv *priv = netdev_priv(netdev);
+ int len;
+
switch (sset) {
case ETH_SS_STATS:
- return STMMAC_STATS_LEN;
+ len = STMMAC_STATS_LEN;
+
+ if (priv->dma_cap.rmon)
+ len += STMMAC_MMC_STATS_LEN;
+
+ return len;
default:
return -EOPNOTSUPP;
}
@@ -279,9 +390,16 @@ static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data)
{
int i;
u8 *p = data;
+ struct stmmac_priv *priv = netdev_priv(dev);
switch (stringset) {
case ETH_SS_STATS:
+ if (priv->dma_cap.rmon)
+ for (i = 0; i < STMMAC_MMC_STATS_LEN; i++) {
+ memcpy(p, stmmac_mmc[i].stat_string,
+ ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
for (i = 0; i < STMMAC_STATS_LEN; i++) {
memcpy(p, stmmac_gstrings_stats[i].stat_string,
ETH_GSTRING_LEN);
@@ -321,10 +439,10 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
if (wol->wolopts) {
pr_info("stmmac: wakeup enable\n");
device_set_wakeup_enable(priv->device, 1);
- enable_irq_wake(dev->irq);
+ enable_irq_wake(priv->wol_irq);
} else {
device_set_wakeup_enable(priv->device, 0);
- disable_irq_wake(dev->irq);
+ disable_irq_wake(priv->wol_irq);
}
spin_lock_irq(&priv->lock);
diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index c6e567e04eff..aeaa15b451de 100644
--- a/drivers/net/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2,7 +2,7 @@
This is the driver for the ST MAC 10/100/1000 on-chip Ethernet controllers.
ST Ethernet IPs are built around a Synopsys IP Core.
- Copyright (C) 2007-2009 STMicroelectronics Ltd
+ Copyright(C) 2007-2011 STMicroelectronics Ltd
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -41,11 +41,15 @@
#include <linux/if_ether.h>
#include <linux/crc32.h>
#include <linux/mii.h>
-#include <linux/phy.h>
+#include <linux/if.h>
#include <linux/if_vlan.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/prefetch.h>
+#ifdef CONFIG_STMMAC_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#endif
#include "stmmac.h"
#define STMMAC_RESOURCE_NAME "stmmaceth"
@@ -299,7 +303,7 @@ static int stmmac_init_phy(struct net_device *dev)
struct phy_device *phydev;
char phy_id[MII_BUS_ID_SIZE + 3];
char bus_id[MII_BUS_ID_SIZE];
-
+ int interface = priv->plat->interface;
priv->oldlink = 0;
priv->speed = 0;
priv->oldduplex = -1;
@@ -309,14 +313,21 @@ static int stmmac_init_phy(struct net_device *dev)
priv->plat->phy_addr);
pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id);
- phydev = phy_connect(dev, phy_id, &stmmac_adjust_link, 0,
- priv->plat->interface);
+ phydev = phy_connect(dev, phy_id, &stmmac_adjust_link, 0, interface);
if (IS_ERR(phydev)) {
pr_err("%s: Could not attach to PHY\n", dev->name);
return PTR_ERR(phydev);
}
+ /* Stop Advertising 1000BASE Capability if interface is not GMII */
+ if ((interface) && ((interface == PHY_INTERFACE_MODE_MII) ||
+ (interface == PHY_INTERFACE_MODE_RMII))) {
+ phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause);
+ priv->phydev->advertising = priv->phydev->supported;
+ }
+
/*
* Broken HW is sometimes missing the pull-up resistor on the
* MDIO line, which results in reads to non-existent devices returning
@@ -376,11 +387,28 @@ static void display_ring(struct dma_desc *p, int size)
}
}
+static int stmmac_set_bfsize(int mtu, int bufsize)
+{
+ int ret = bufsize;
+
+ if (mtu >= BUF_SIZE_4KiB)
+ ret = BUF_SIZE_8KiB;
+ else if (mtu >= BUF_SIZE_2KiB)
+ ret = BUF_SIZE_4KiB;
+ else if (mtu >= DMA_BUFFER_SIZE)
+ ret = BUF_SIZE_2KiB;
+ else
+ ret = DMA_BUFFER_SIZE;
+
+ return ret;
+}
+
/**
* init_dma_desc_rings - init the RX/TX descriptor rings
* @dev: net device structure
* Description: this function initializes the DMA RX/TX descriptors
- * and allocates the socket buffers.
+ * and allocates the socket buffers. It suppors the chained and ring
+ * modes.
*/
static void init_dma_desc_rings(struct net_device *dev)
{
@@ -389,31 +417,24 @@ static void init_dma_desc_rings(struct net_device *dev)
struct sk_buff *skb;
unsigned int txsize = priv->dma_tx_size;
unsigned int rxsize = priv->dma_rx_size;
- unsigned int bfsize = priv->dma_buf_sz;
- int buff2_needed = 0, dis_ic = 0;
+ unsigned int bfsize;
+ int dis_ic = 0;
+ int des3_as_data_buf = 0;
- /* Set the Buffer size according to the MTU;
- * indeed, in case of jumbo we need to bump-up the buffer sizes.
- */
- if (unlikely(dev->mtu >= BUF_SIZE_8KiB))
- bfsize = BUF_SIZE_16KiB;
- else if (unlikely(dev->mtu >= BUF_SIZE_4KiB))
- bfsize = BUF_SIZE_8KiB;
- else if (unlikely(dev->mtu >= BUF_SIZE_2KiB))
- bfsize = BUF_SIZE_4KiB;
- else if (unlikely(dev->mtu >= DMA_BUFFER_SIZE))
- bfsize = BUF_SIZE_2KiB;
+ /* Set the max buffer size according to the DESC mode
+ * and the MTU. Note that RING mode allows 16KiB bsize. */
+ bfsize = priv->hw->ring->set_16kib_bfsize(dev->mtu);
+
+ if (bfsize == BUF_SIZE_16KiB)
+ des3_as_data_buf = 1;
else
- bfsize = DMA_BUFFER_SIZE;
+ bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_buf_sz);
#ifdef CONFIG_STMMAC_TIMER
/* Disable interrupts on completion for the reception if timer is on */
if (likely(priv->tm->enable))
dis_ic = 1;
#endif
- /* If the MTU exceeds 8k so use the second buffer in the chain */
- if (bfsize >= BUF_SIZE_8KiB)
- buff2_needed = 1;
DBG(probe, INFO, "stmmac: txsize %d, rxsize %d, bfsize %d\n",
txsize, rxsize, bfsize);
@@ -441,7 +462,7 @@ static void init_dma_desc_rings(struct net_device *dev)
return;
}
- DBG(probe, INFO, "stmmac (%s) DMA desc rings: virt addr (Rx %p, "
+ DBG(probe, INFO, "stmmac (%s) DMA desc: virt addr (Rx %p, "
"Tx %p)\n\tDMA phy addr (Rx 0x%08x, Tx 0x%08x)\n",
dev->name, priv->dma_rx, priv->dma_tx,
(unsigned int)priv->dma_rx_phy, (unsigned int)priv->dma_tx_phy);
@@ -453,18 +474,21 @@ static void init_dma_desc_rings(struct net_device *dev)
for (i = 0; i < rxsize; i++) {
struct dma_desc *p = priv->dma_rx + i;
- skb = netdev_alloc_skb_ip_align(dev, bfsize);
+ skb = __netdev_alloc_skb(dev, bfsize + NET_IP_ALIGN,
+ GFP_KERNEL);
if (unlikely(skb == NULL)) {
pr_err("%s: Rx init fails; skb is NULL\n", __func__);
break;
}
+ skb_reserve(skb, NET_IP_ALIGN);
priv->rx_skbuff[i] = skb;
priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data,
bfsize, DMA_FROM_DEVICE);
p->des2 = priv->rx_skbuff_dma[i];
- if (unlikely(buff2_needed))
- p->des3 = p->des2 + BUF_SIZE_8KiB;
+
+ priv->hw->ring->init_desc3(des3_as_data_buf, p);
+
DBG(probe, INFO, "[%p]\t[%p]\t[%x]\n", priv->rx_skbuff[i],
priv->rx_skbuff[i]->data, priv->rx_skbuff_dma[i]);
}
@@ -478,6 +502,12 @@ static void init_dma_desc_rings(struct net_device *dev)
priv->tx_skbuff[i] = NULL;
priv->dma_tx[i].des2 = 0;
}
+
+ /* In case of Chained mode this sets the des3 to the next
+ * element in the chain */
+ priv->hw->ring->init_dma_chain(priv->dma_rx, priv->dma_rx_phy, rxsize);
+ priv->hw->ring->init_dma_chain(priv->dma_tx, priv->dma_tx_phy, txsize);
+
priv->dirty_tx = 0;
priv->cur_tx = 0;
@@ -576,6 +606,8 @@ static void stmmac_tx(struct stmmac_priv *priv)
{
unsigned int txsize = priv->dma_tx_size;
+ spin_lock(&priv->tx_lock);
+
while (priv->dirty_tx != priv->cur_tx) {
int last;
unsigned int entry = priv->dirty_tx % txsize;
@@ -606,8 +638,7 @@ static void stmmac_tx(struct stmmac_priv *priv)
dma_unmap_single(priv->device, p->des2,
priv->hw->desc->get_tx_len(p),
DMA_TO_DEVICE);
- if (unlikely(p->des3))
- p->des3 = 0;
+ priv->hw->ring->clean_desc3(p);
if (likely(skb != NULL)) {
/*
@@ -639,6 +670,7 @@ static void stmmac_tx(struct stmmac_priv *priv)
}
netif_tx_unlock(priv->dev);
}
+ spin_unlock(&priv->tx_lock);
}
static inline void stmmac_enable_irq(struct stmmac_priv *priv)
@@ -713,7 +745,6 @@ static void stmmac_no_timer_stopped(void)
*/
static void stmmac_tx_err(struct stmmac_priv *priv)
{
-
netif_stop_queue(priv->dev);
priv->hw->dma->stop_tx(priv->ioaddr);
@@ -747,6 +778,89 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv)
stmmac_tx_err(priv);
}
+static void stmmac_mmc_setup(struct stmmac_priv *priv)
+{
+ unsigned int mode = MMC_CNTRL_RESET_ON_READ | MMC_CNTRL_COUNTER_RESET |
+ MMC_CNTRL_PRESET | MMC_CNTRL_FULL_HALF_PRESET;
+
+ /* Do not manage MMC IRQ (FIXME) */
+ dwmac_mmc_intr_all_mask(priv->ioaddr);
+ dwmac_mmc_ctrl(priv->ioaddr, mode);
+ memset(&priv->mmc, 0, sizeof(struct stmmac_counters));
+}
+
+static u32 stmmac_get_synopsys_id(struct stmmac_priv *priv)
+{
+ u32 hwid = priv->hw->synopsys_uid;
+
+ /* Only check valid Synopsys Id because old MAC chips
+ * have no HW registers where get the ID */
+ if (likely(hwid)) {
+ u32 uid = ((hwid & 0x0000ff00) >> 8);
+ u32 synid = (hwid & 0x000000ff);
+
+ pr_info("STMMAC - user ID: 0x%x, Synopsys ID: 0x%x\n",
+ uid, synid);
+
+ return synid;
+ }
+ return 0;
+}
+
+/* New GMAC chips support a new register to indicate the
+ * presence of the optional feature/functions.
+ */
+static int stmmac_get_hw_features(struct stmmac_priv *priv)
+{
+ u32 hw_cap = priv->hw->dma->get_hw_feature(priv->ioaddr);
+
+ if (likely(hw_cap)) {
+ priv->dma_cap.mbps_10_100 = (hw_cap & DMA_HW_FEAT_MIISEL);
+ priv->dma_cap.mbps_1000 = (hw_cap & DMA_HW_FEAT_GMIISEL) >> 1;
+ priv->dma_cap.half_duplex = (hw_cap & DMA_HW_FEAT_HDSEL) >> 2;
+ priv->dma_cap.hash_filter = (hw_cap & DMA_HW_FEAT_HASHSEL) >> 4;
+ priv->dma_cap.multi_addr =
+ (hw_cap & DMA_HW_FEAT_ADDMACADRSEL) >> 5;
+ priv->dma_cap.pcs = (hw_cap & DMA_HW_FEAT_PCSSEL) >> 6;
+ priv->dma_cap.sma_mdio = (hw_cap & DMA_HW_FEAT_SMASEL) >> 8;
+ priv->dma_cap.pmt_remote_wake_up =
+ (hw_cap & DMA_HW_FEAT_RWKSEL) >> 9;
+ priv->dma_cap.pmt_magic_frame =
+ (hw_cap & DMA_HW_FEAT_MGKSEL) >> 10;
+ /*MMC*/
+ priv->dma_cap.rmon = (hw_cap & DMA_HW_FEAT_MMCSEL) >> 11;
+ /* IEEE 1588-2002*/
+ priv->dma_cap.time_stamp =
+ (hw_cap & DMA_HW_FEAT_TSVER1SEL) >> 12;
+ /* IEEE 1588-2008*/
+ priv->dma_cap.atime_stamp =
+ (hw_cap & DMA_HW_FEAT_TSVER2SEL) >> 13;
+ /* 802.3az - Energy-Efficient Ethernet (EEE) */
+ priv->dma_cap.eee = (hw_cap & DMA_HW_FEAT_EEESEL) >> 14;
+ priv->dma_cap.av = (hw_cap & DMA_HW_FEAT_AVSEL) >> 15;
+ /* TX and RX csum */
+ priv->dma_cap.tx_coe = (hw_cap & DMA_HW_FEAT_TXCOESEL) >> 16;
+ priv->dma_cap.rx_coe_type1 =
+ (hw_cap & DMA_HW_FEAT_RXTYP1COE) >> 17;
+ priv->dma_cap.rx_coe_type2 =
+ (hw_cap & DMA_HW_FEAT_RXTYP2COE) >> 18;
+ priv->dma_cap.rxfifo_over_2048 =
+ (hw_cap & DMA_HW_FEAT_RXFIFOSIZE) >> 19;
+ /* TX and RX number of channels */
+ priv->dma_cap.number_rx_channel =
+ (hw_cap & DMA_HW_FEAT_RXCHCNT) >> 20;
+ priv->dma_cap.number_tx_channel =
+ (hw_cap & DMA_HW_FEAT_TXCHCNT) >> 22;
+ /* Alternate (enhanced) DESC mode*/
+ priv->dma_cap.enh_desc =
+ (hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24;
+
+ } else
+ pr_debug("\tNo HW DMA feature register supported");
+
+ return hw_cap;
+}
+
/**
* stmmac_open - open entry point of the driver
* @dev : pointer to the device structure.
@@ -819,17 +933,16 @@ static int stmmac_open(struct net_device *dev)
/* Initialize the MAC Core */
priv->hw->mac->core_init(priv->ioaddr);
- priv->rx_coe = priv->hw->mac->rx_coe(priv->ioaddr);
+ stmmac_get_synopsys_id(priv);
+
+ stmmac_get_hw_features(priv);
+
if (priv->rx_coe)
pr_info("stmmac: Rx Checksum Offload Engine supported\n");
if (priv->plat->tx_coe)
pr_info("\tTX Checksum insertion supported\n");
netdev_update_features(dev);
- /* Initialise the MMC (if present) to disable all interrupts. */
- writel(0xffffffff, priv->ioaddr + MMC_HIGH_INTR_MASK);
- writel(0xffffffff, priv->ioaddr + MMC_LOW_INTR_MASK);
-
/* Request the IRQ lines */
ret = request_irq(dev->irq, stmmac_interrupt,
IRQF_SHARED, dev->name, dev);
@@ -849,6 +962,9 @@ static int stmmac_open(struct net_device *dev)
memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats));
priv->xstats.threshold = tc;
+ if (priv->dma_cap.rmon)
+ stmmac_mmc_setup(priv);
+
/* Start the ball rolling... */
DBG(probe, DEBUG, "%s: DMA RX/TX processes started...\n", dev->name);
priv->hw->dma->start_tx(priv->ioaddr);
@@ -928,47 +1044,6 @@ static int stmmac_release(struct net_device *dev)
return 0;
}
-static unsigned int stmmac_handle_jumbo_frames(struct sk_buff *skb,
- struct net_device *dev,
- int csum_insertion)
-{
- struct stmmac_priv *priv = netdev_priv(dev);
- unsigned int nopaged_len = skb_headlen(skb);
- unsigned int txsize = priv->dma_tx_size;
- unsigned int entry = priv->cur_tx % txsize;
- struct dma_desc *desc = priv->dma_tx + entry;
-
- if (nopaged_len > BUF_SIZE_8KiB) {
-
- int buf2_size = nopaged_len - BUF_SIZE_8KiB;
-
- desc->des2 = dma_map_single(priv->device, skb->data,
- BUF_SIZE_8KiB, DMA_TO_DEVICE);
- desc->des3 = desc->des2 + BUF_SIZE_4KiB;
- priv->hw->desc->prepare_tx_desc(desc, 1, BUF_SIZE_8KiB,
- csum_insertion);
-
- entry = (++priv->cur_tx) % txsize;
- desc = priv->dma_tx + entry;
-
- desc->des2 = dma_map_single(priv->device,
- skb->data + BUF_SIZE_8KiB,
- buf2_size, DMA_TO_DEVICE);
- desc->des3 = desc->des2 + BUF_SIZE_4KiB;
- priv->hw->desc->prepare_tx_desc(desc, 0, buf2_size,
- csum_insertion);
- priv->hw->desc->set_tx_owner(desc);
- priv->tx_skbuff[entry] = NULL;
- } else {
- desc->des2 = dma_map_single(priv->device, skb->data,
- nopaged_len, DMA_TO_DEVICE);
- desc->des3 = desc->des2 + BUF_SIZE_4KiB;
- priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
- csum_insertion);
- }
- return entry;
-}
-
/**
* stmmac_xmit:
* @skb : the socket buffer
@@ -983,6 +1058,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
int i, csum_insertion = 0;
int nfrags = skb_shinfo(skb)->nr_frags;
struct dma_desc *desc, *first;
+ unsigned int nopaged_len = skb_headlen(skb);
if (unlikely(stmmac_tx_avail(priv) < nfrags + 1)) {
if (!netif_queue_stopped(dev)) {
@@ -994,6 +1070,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_BUSY;
}
+ spin_lock(&priv->tx_lock);
+
entry = priv->cur_tx % txsize;
#ifdef STMMAC_XMIT_DEBUG
@@ -1001,7 +1079,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
pr_info("stmmac xmit:\n"
"\tskb addr %p - len: %d - nopaged_len: %d\n"
"\tn_frags: %d - ip_summed: %d - %s gso\n",
- skb, skb->len, skb_headlen(skb), nfrags, skb->ip_summed,
+ skb, skb->len, nopaged_len, nfrags, skb->ip_summed,
!skb_is_gso(skb) ? "isn't" : "is");
#endif
@@ -1014,14 +1092,14 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
if ((nfrags > 0) || (skb->len > ETH_FRAME_LEN))
pr_debug("stmmac xmit: skb len: %d, nopaged_len: %d,\n"
"\t\tn_frags: %d, ip_summed: %d\n",
- skb->len, skb_headlen(skb), nfrags, skb->ip_summed);
+ skb->len, nopaged_len, nfrags, skb->ip_summed);
#endif
priv->tx_skbuff[entry] = skb;
- if (unlikely(skb->len >= BUF_SIZE_4KiB)) {
- entry = stmmac_handle_jumbo_frames(skb, dev, csum_insertion);
+
+ if (priv->hw->ring->is_jumbo_frm(skb->len, priv->plat->enh_desc)) {
+ entry = priv->hw->ring->jumbo_frm(priv, skb, csum_insertion);
desc = priv->dma_tx + entry;
} else {
- unsigned int nopaged_len = skb_headlen(skb);
desc->des2 = dma_map_single(priv->device, skb->data,
nopaged_len, DMA_TO_DEVICE);
priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
@@ -1029,16 +1107,15 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
}
for (i = 0; i < nfrags; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- int len = frag->size;
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ int len = skb_frag_size(frag);
entry = (++priv->cur_tx) % txsize;
desc = priv->dma_tx + entry;
TX_DBG("\t[entry %d] segment len: %d\n", entry, len);
- desc->des2 = dma_map_page(priv->device, frag->page,
- frag->page_offset,
- len, DMA_TO_DEVICE);
+ desc->des2 = skb_frag_dma_map(priv->device, frag, 0, len,
+ DMA_TO_DEVICE);
priv->tx_skbuff[entry] = NULL;
priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion);
wmb();
@@ -1083,6 +1160,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
priv->hw->dma->enable_dma_transmission(priv->ioaddr);
+ spin_unlock(&priv->tx_lock);
+
return NETDEV_TX_OK;
}
@@ -1111,11 +1190,10 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
DMA_FROM_DEVICE);
(p + entry)->des2 = priv->rx_skbuff_dma[entry];
- if (unlikely(priv->plat->has_gmac)) {
- if (bfsize >= BUF_SIZE_8KiB)
- (p + entry)->des3 =
- (p + entry)->des2 + BUF_SIZE_8KiB;
- }
+
+ if (unlikely(priv->plat->has_gmac))
+ priv->hw->ring->refill_desc3(bfsize, p + entry);
+
RX_DBG(KERN_INFO "\trefill entry #%d\n", entry);
}
wmb();
@@ -1284,7 +1362,7 @@ static int stmmac_config(struct net_device *dev, struct ifmap *map)
}
/**
- * stmmac_multicast_list - entry point for multicast addressing
+ * stmmac_set_rx_mode - entry point for multicast addressing
* @dev : pointer to the device structure
* Description:
* This function is a driver entry point which gets called by the kernel
@@ -1292,7 +1370,7 @@ static int stmmac_config(struct net_device *dev, struct ifmap *map)
* Return value:
* void.
*/
-static void stmmac_multicast_list(struct net_device *dev)
+static void stmmac_set_rx_mode(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
@@ -1322,10 +1400,10 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu)
return -EBUSY;
}
- if (priv->plat->has_gmac)
+ if (priv->plat->enh_desc)
max_mtu = JUMBO_LEN;
else
- max_mtu = ETH_DATA_LEN;
+ max_mtu = SKB_MAX_HEAD(NET_SKB_PAD + NET_IP_ALIGN);
if ((new_mtu < 46) || (new_mtu > max_mtu)) {
pr_err("%s: invalid MTU, max MTU is: %d\n", dev->name, max_mtu);
@@ -1415,13 +1493,189 @@ static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return ret;
}
+#ifdef CONFIG_STMMAC_DEBUG_FS
+static struct dentry *stmmac_fs_dir;
+static struct dentry *stmmac_rings_status;
+static struct dentry *stmmac_dma_cap;
+
+static int stmmac_sysfs_ring_read(struct seq_file *seq, void *v)
+{
+ struct tmp_s {
+ u64 a;
+ unsigned int b;
+ unsigned int c;
+ };
+ int i;
+ struct net_device *dev = seq->private;
+ struct stmmac_priv *priv = netdev_priv(dev);
+
+ seq_printf(seq, "=======================\n");
+ seq_printf(seq, " RX descriptor ring\n");
+ seq_printf(seq, "=======================\n");
+
+ for (i = 0; i < priv->dma_rx_size; i++) {
+ struct tmp_s *x = (struct tmp_s *)(priv->dma_rx + i);
+ seq_printf(seq, "[%d] DES0=0x%x DES1=0x%x BUF1=0x%x BUF2=0x%x",
+ i, (unsigned int)(x->a),
+ (unsigned int)((x->a) >> 32), x->b, x->c);
+ seq_printf(seq, "\n");
+ }
+
+ seq_printf(seq, "\n");
+ seq_printf(seq, "=======================\n");
+ seq_printf(seq, " TX descriptor ring\n");
+ seq_printf(seq, "=======================\n");
+
+ for (i = 0; i < priv->dma_tx_size; i++) {
+ struct tmp_s *x = (struct tmp_s *)(priv->dma_tx + i);
+ seq_printf(seq, "[%d] DES0=0x%x DES1=0x%x BUF1=0x%x BUF2=0x%x",
+ i, (unsigned int)(x->a),
+ (unsigned int)((x->a) >> 32), x->b, x->c);
+ seq_printf(seq, "\n");
+ }
+
+ return 0;
+}
+
+static int stmmac_sysfs_ring_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, stmmac_sysfs_ring_read, inode->i_private);
+}
+
+static const struct file_operations stmmac_rings_status_fops = {
+ .owner = THIS_MODULE,
+ .open = stmmac_sysfs_ring_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static int stmmac_sysfs_dma_cap_read(struct seq_file *seq, void *v)
+{
+ struct net_device *dev = seq->private;
+ struct stmmac_priv *priv = netdev_priv(dev);
+
+ if (!stmmac_get_hw_features(priv)) {
+ seq_printf(seq, "DMA HW features not supported\n");
+ return 0;
+ }
+
+ seq_printf(seq, "==============================\n");
+ seq_printf(seq, "\tDMA HW features\n");
+ seq_printf(seq, "==============================\n");
+
+ seq_printf(seq, "\t10/100 Mbps %s\n",
+ (priv->dma_cap.mbps_10_100) ? "Y" : "N");
+ seq_printf(seq, "\t1000 Mbps %s\n",
+ (priv->dma_cap.mbps_1000) ? "Y" : "N");
+ seq_printf(seq, "\tHalf duple %s\n",
+ (priv->dma_cap.half_duplex) ? "Y" : "N");
+ seq_printf(seq, "\tHash Filter: %s\n",
+ (priv->dma_cap.hash_filter) ? "Y" : "N");
+ seq_printf(seq, "\tMultiple MAC address registers: %s\n",
+ (priv->dma_cap.multi_addr) ? "Y" : "N");
+ seq_printf(seq, "\tPCS (TBI/SGMII/RTBI PHY interfatces): %s\n",
+ (priv->dma_cap.pcs) ? "Y" : "N");
+ seq_printf(seq, "\tSMA (MDIO) Interface: %s\n",
+ (priv->dma_cap.sma_mdio) ? "Y" : "N");
+ seq_printf(seq, "\tPMT Remote wake up: %s\n",
+ (priv->dma_cap.pmt_remote_wake_up) ? "Y" : "N");
+ seq_printf(seq, "\tPMT Magic Frame: %s\n",
+ (priv->dma_cap.pmt_magic_frame) ? "Y" : "N");
+ seq_printf(seq, "\tRMON module: %s\n",
+ (priv->dma_cap.rmon) ? "Y" : "N");
+ seq_printf(seq, "\tIEEE 1588-2002 Time Stamp: %s\n",
+ (priv->dma_cap.time_stamp) ? "Y" : "N");
+ seq_printf(seq, "\tIEEE 1588-2008 Advanced Time Stamp:%s\n",
+ (priv->dma_cap.atime_stamp) ? "Y" : "N");
+ seq_printf(seq, "\t802.3az - Energy-Efficient Ethernet (EEE) %s\n",
+ (priv->dma_cap.eee) ? "Y" : "N");
+ seq_printf(seq, "\tAV features: %s\n", (priv->dma_cap.av) ? "Y" : "N");
+ seq_printf(seq, "\tChecksum Offload in TX: %s\n",
+ (priv->dma_cap.tx_coe) ? "Y" : "N");
+ seq_printf(seq, "\tIP Checksum Offload (type1) in RX: %s\n",
+ (priv->dma_cap.rx_coe_type1) ? "Y" : "N");
+ seq_printf(seq, "\tIP Checksum Offload (type2) in RX: %s\n",
+ (priv->dma_cap.rx_coe_type2) ? "Y" : "N");
+ seq_printf(seq, "\tRXFIFO > 2048bytes: %s\n",
+ (priv->dma_cap.rxfifo_over_2048) ? "Y" : "N");
+ seq_printf(seq, "\tNumber of Additional RX channel: %d\n",
+ priv->dma_cap.number_rx_channel);
+ seq_printf(seq, "\tNumber of Additional TX channel: %d\n",
+ priv->dma_cap.number_tx_channel);
+ seq_printf(seq, "\tEnhanced descriptors: %s\n",
+ (priv->dma_cap.enh_desc) ? "Y" : "N");
+
+ return 0;
+}
+
+static int stmmac_sysfs_dma_cap_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, stmmac_sysfs_dma_cap_read, inode->i_private);
+}
+
+static const struct file_operations stmmac_dma_cap_fops = {
+ .owner = THIS_MODULE,
+ .open = stmmac_sysfs_dma_cap_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static int stmmac_init_fs(struct net_device *dev)
+{
+ /* Create debugfs entries */
+ stmmac_fs_dir = debugfs_create_dir(STMMAC_RESOURCE_NAME, NULL);
+
+ if (!stmmac_fs_dir || IS_ERR(stmmac_fs_dir)) {
+ pr_err("ERROR %s, debugfs create directory failed\n",
+ STMMAC_RESOURCE_NAME);
+
+ return -ENOMEM;
+ }
+
+ /* Entry to report DMA RX/TX rings */
+ stmmac_rings_status = debugfs_create_file("descriptors_status",
+ S_IRUGO, stmmac_fs_dir, dev,
+ &stmmac_rings_status_fops);
+
+ if (!stmmac_rings_status || IS_ERR(stmmac_rings_status)) {
+ pr_info("ERROR creating stmmac ring debugfs file\n");
+ debugfs_remove(stmmac_fs_dir);
+
+ return -ENOMEM;
+ }
+
+ /* Entry to report the DMA HW features */
+ stmmac_dma_cap = debugfs_create_file("dma_cap", S_IRUGO, stmmac_fs_dir,
+ dev, &stmmac_dma_cap_fops);
+
+ if (!stmmac_dma_cap || IS_ERR(stmmac_dma_cap)) {
+ pr_info("ERROR creating stmmac MMC debugfs file\n");
+ debugfs_remove(stmmac_rings_status);
+ debugfs_remove(stmmac_fs_dir);
+
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void stmmac_exit_fs(void)
+{
+ debugfs_remove(stmmac_rings_status);
+ debugfs_remove(stmmac_dma_cap);
+ debugfs_remove(stmmac_fs_dir);
+}
+#endif /* CONFIG_STMMAC_DEBUG_FS */
+
static const struct net_device_ops stmmac_netdev_ops = {
.ndo_open = stmmac_open,
.ndo_start_xmit = stmmac_xmit,
.ndo_stop = stmmac_release,
.ndo_change_mtu = stmmac_change_mtu,
.ndo_fix_features = stmmac_fix_features,
- .ndo_set_multicast_list = stmmac_multicast_list,
+ .ndo_set_rx_mode = stmmac_set_rx_mode,
.ndo_tx_timeout = stmmac_tx_timeout,
.ndo_do_ioctl = stmmac_ioctl,
.ndo_set_config = stmmac_config,
@@ -1472,6 +1726,7 @@ static int stmmac_probe(struct net_device *dev)
"please, use ifconfig or nwhwconfig!\n");
spin_lock_init(&priv->lock);
+ spin_lock_init(&priv->tx_lock);
ret = register_netdev(dev);
if (ret) {
@@ -1498,10 +1753,12 @@ static int stmmac_mac_device_setup(struct net_device *dev)
struct mac_device_info *device;
- if (priv->plat->has_gmac)
+ if (priv->plat->has_gmac) {
+ dev->priv_flags |= IFF_UNICAST_FLT;
device = dwmac1000_setup(priv->ioaddr);
- else
+ } else {
device = dwmac100_setup(priv->ioaddr);
+ }
if (!device)
return -ENOMEM;
@@ -1513,10 +1770,11 @@ static int stmmac_mac_device_setup(struct net_device *dev)
device->desc = &ndesc_ops;
priv->hw = device;
+ priv->hw->ring = &ring_mode_ops;
if (device_can_wakeup(priv->device)) {
priv->wolopts = WAKE_MAGIC; /* Magic Frame as default */
- enable_irq_wake(dev->irq);
+ enable_irq_wake(priv->wol_irq);
}
return 0;
@@ -1589,6 +1847,18 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
pr_info("\tPMT module supported\n");
device_set_wakeup_capable(&pdev->dev, 1);
}
+ /*
+ * On some platforms e.g. SPEAr the wake up irq differs from the mac irq
+ * The external wake up irq can be passed through the platform code
+ * named as "eth_wake_irq"
+ *
+ * In case the wake up interrupt is not passed from the platform
+ * so the driver will continue to use the mac irq (ndev->irq)
+ */
+ priv->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
+ if (priv->wol_irq == -ENXIO)
+ priv->wol_irq = ndev->irq;
+
platform_set_drvdata(pdev, ndev);
@@ -1627,6 +1897,13 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
if (ret < 0)
goto out_unregister;
pr_debug("registered!\n");
+
+#ifdef CONFIG_STMMAC_DEBUG_FS
+ ret = stmmac_init_fs(ndev);
+ if (ret < 0)
+ pr_warning("\tFailed debugFS registration");
+#endif
+
return 0;
out_unregister:
@@ -1679,6 +1956,10 @@ static int stmmac_dvr_remove(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
+#ifdef CONFIG_STMMAC_DEBUG_FS
+ stmmac_exit_fs();
+#endif
+
free_netdev(ndev);
return 0;
diff --git a/drivers/net/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index 9c3b9d5c3411..9c3b9d5c3411 100644
--- a/drivers/net/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
diff --git a/drivers/net/stmmac/stmmac_timer.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_timer.c
index 2a0e1abde7e7..2a0e1abde7e7 100644
--- a/drivers/net/stmmac/stmmac_timer.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_timer.c
diff --git a/drivers/net/stmmac/stmmac_timer.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_timer.h
index 6863590d184b..6863590d184b 100644
--- a/drivers/net/stmmac/stmmac_timer.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_timer.h
diff --git a/drivers/net/ethernet/sun/Kconfig b/drivers/net/ethernet/sun/Kconfig
new file mode 100644
index 000000000000..57bfd8599679
--- /dev/null
+++ b/drivers/net/ethernet/sun/Kconfig
@@ -0,0 +1,88 @@
+#
+# Sun network device configuration
+#
+
+config NET_VENDOR_SUN
+ bool "Sun devices"
+ default y
+ depends on SUN3 || SBUS || PCI || SUN_LDOMS
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say
+ Y and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Sun network interfaces. If you say Y, you will be
+ asked for your specific card in the following questions.
+
+if NET_VENDOR_SUN
+
+config HAPPYMEAL
+ tristate "Sun Happy Meal 10/100baseT support"
+ depends on (SBUS || PCI)
+ select CRC32
+ ---help---
+ This driver supports the "hme" interface present on most Ultra
+ systems and as an option on older Sbus systems. This driver supports
+ both PCI and Sbus devices. This driver also supports the "qfe" quad
+ 100baseT device available in both PCI and Sbus configurations.
+
+ To compile this driver as a module, choose M here: the module
+ will be called sunhme.
+
+config SUNBMAC
+ tristate "Sun BigMAC 10/100baseT support (EXPERIMENTAL)"
+ depends on SBUS && EXPERIMENTAL
+ select CRC32
+ ---help---
+ This driver supports the "be" interface available as an Sbus option.
+ This is Sun's older 100baseT Ethernet device.
+
+ To compile this driver as a module, choose M here: the module
+ will be called sunbmac.
+
+config SUNQE
+ tristate "Sun QuadEthernet support"
+ depends on SBUS
+ select CRC32
+ ---help---
+ This driver supports the "qe" 10baseT Ethernet device, available as
+ an Sbus option. Note that this is not the same as Quad FastEthernet
+ "qfe" which is supported by the Happy Meal driver instead.
+
+ To compile this driver as a module, choose M here: the module
+ will be called sunqe.
+
+config SUNGEM
+ tristate "Sun GEM support"
+ depends on PCI
+ select CRC32
+ select SUNGEM_PHY
+ ---help---
+ Support for the Sun GEM chip, aka Sun GigabitEthernet/P 2.0. See also
+ <http://www.sun.com/products-n-solutions/hardware/docs/pdf/806-3985-10.pdf>.
+
+config CASSINI
+ tristate "Sun Cassini support"
+ depends on PCI
+ select CRC32
+ ---help---
+ Support for the Sun Cassini chip, aka Sun GigaSwift Ethernet. See also
+ <http://www.sun.com/products-n-solutions/hardware/docs/pdf/817-4341-10.pdf>
+
+config SUNVNET
+ tristate "Sun Virtual Network support"
+ depends on SUN_LDOMS
+ ---help---
+ Support for virtual network devices under Sun Logical Domains.
+
+config NIU
+ tristate "Sun Neptune 10Gbit Ethernet support"
+ depends on PCI
+ select CRC32
+ ---help---
+ This enables support for cards based upon Sun's
+ Neptune chipset.
+
+endif # NET_VENDOR_SUN
diff --git a/drivers/net/ethernet/sun/Makefile b/drivers/net/ethernet/sun/Makefile
new file mode 100644
index 000000000000..1e620ff88eba
--- /dev/null
+++ b/drivers/net/ethernet/sun/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the Sun network device drivers.
+#
+
+obj-$(CONFIG_HAPPYMEAL) += sunhme.o
+obj-$(CONFIG_SUNQE) += sunqe.o
+obj-$(CONFIG_SUNBMAC) += sunbmac.o
+obj-$(CONFIG_SUNGEM) += sungem.o
+obj-$(CONFIG_CASSINI) += cassini.o
+obj-$(CONFIG_SUNVNET) += sunvnet.o
+obj-$(CONFIG_NIU) += niu.o
diff --git a/drivers/net/cassini.c b/drivers/net/ethernet/sun/cassini.c
index 646c86bcc545..fd40988c19a6 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/ethernet/sun/cassini.c
@@ -2048,10 +2048,10 @@ static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc,
skb->truesize += hlen - swivel;
skb->len += hlen - swivel;
- get_page(page->buffer);
- frag->page = page->buffer;
+ __skb_frag_set_page(frag, page->buffer);
+ __skb_frag_ref(frag);
frag->page_offset = off;
- frag->size = hlen - swivel;
+ skb_frag_size_set(frag, hlen - swivel);
/* any more data? */
if ((words[0] & RX_COMP1_SPLIT_PKT) && ((dlen -= hlen) > 0)) {
@@ -2072,10 +2072,10 @@ static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc,
skb->len += hlen;
frag++;
- get_page(page->buffer);
- frag->page = page->buffer;
+ __skb_frag_set_page(frag, page->buffer);
+ __skb_frag_ref(frag);
frag->page_offset = 0;
- frag->size = hlen;
+ skb_frag_size_set(frag, hlen);
RX_USED_ADD(page, hlen + cp->crc_size);
}
@@ -2452,14 +2452,13 @@ static irqreturn_t cas_interruptN(int irq, void *dev_id)
struct net_device *dev = dev_id;
struct cas *cp = netdev_priv(dev);
unsigned long flags;
- int ring;
+ int ring = (irq == cp->pci_irq_INTC) ? 2 : 3;
u32 status = readl(cp->regs + REG_PLUS_INTRN_STATUS(ring));
/* check for shared irq */
if (status == 0)
return IRQ_NONE;
- ring = (irq == cp->pci_irq_INTC) ? 2 : 3;
spin_lock_irqsave(&cp->lock, flags);
if (status & INTR_RX_DONE_ALT) { /* handle rx separately */
#ifdef USE_NAPI
@@ -2827,12 +2826,11 @@ static inline int cas_xmit_tx_ringN(struct cas *cp, int ring,
entry = TX_DESC_NEXT(ring, entry);
for (frag = 0; frag < nr_frags; frag++) {
- skb_frag_t *fragp = &skb_shinfo(skb)->frags[frag];
+ const skb_frag_t *fragp = &skb_shinfo(skb)->frags[frag];
- len = fragp->size;
- mapping = pci_map_page(cp->pdev, fragp->page,
- fragp->page_offset, len,
- PCI_DMA_TODEVICE);
+ len = skb_frag_size(fragp);
+ mapping = skb_frag_dma_map(&cp->pdev->dev, fragp, 0, len,
+ DMA_TO_DEVICE);
tabort = cas_calc_tabort(cp, fragp->page_offset, len);
if (unlikely(tabort)) {
@@ -2843,7 +2841,7 @@ static inline int cas_xmit_tx_ringN(struct cas *cp, int ring,
ctrl, 0);
entry = TX_DESC_NEXT(ring, entry);
- addr = cas_page_map(fragp->page);
+ addr = cas_page_map(skb_frag_page(fragp));
memcpy(tx_tiny_buf(cp, ring, entry),
addr + fragp->page_offset + len - tabort,
tabort);
@@ -4910,7 +4908,7 @@ static const struct net_device_ops cas_netdev_ops = {
.ndo_stop = cas_close,
.ndo_start_xmit = cas_start_xmit,
.ndo_get_stats = cas_get_stats,
- .ndo_set_multicast_list = cas_set_multicast,
+ .ndo_set_rx_mode = cas_set_multicast,
.ndo_do_ioctl = cas_ioctl,
.ndo_tx_timeout = cas_tx_timeout,
.ndo_change_mtu = cas_change_mtu,
diff --git a/drivers/net/cassini.h b/drivers/net/ethernet/sun/cassini.h
index b361424d5f57..b361424d5f57 100644
--- a/drivers/net/cassini.h
+++ b/drivers/net/ethernet/sun/cassini.h
diff --git a/drivers/net/niu.c b/drivers/net/ethernet/sun/niu.c
index ed47585a6862..73c708107a37 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/ethernet/sun/niu.c
@@ -17,6 +17,7 @@
#include <linux/delay.h>
#include <linux/bitops.h>
#include <linux/mii.h>
+#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/ip.h>
@@ -3286,20 +3287,13 @@ static u16 tcam_get_valid_entry_cnt(struct niu *np)
}
static void niu_rx_skb_append(struct sk_buff *skb, struct page *page,
- u32 offset, u32 size)
+ u32 offset, u32 size, u32 truesize)
{
- int i = skb_shinfo(skb)->nr_frags;
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-
- frag->page = page;
- frag->page_offset = offset;
- frag->size = size;
+ skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page, offset, size);
skb->len += size;
skb->data_len += size;
- skb->truesize += size;
-
- skb_shinfo(skb)->nr_frags = i + 1;
+ skb->truesize += truesize;
}
static unsigned int niu_hash_rxaddr(struct rx_ring_info *rp, u64 a)
@@ -3482,7 +3476,7 @@ static int niu_process_rx_pkt(struct napi_struct *napi, struct niu *np,
} else if (!(val & RCR_ENTRY_MULTI))
append_size = len - skb->len;
- niu_rx_skb_append(skb, page, off, append_size);
+ niu_rx_skb_append(skb, page, off, append_size, rcr_size);
if ((page->index + rp->rbr_block_size) - rcr_size == addr) {
*link = (struct page *) page->mapping;
np->ops->unmap_page(np->device, page->index,
@@ -3600,7 +3594,7 @@ static int release_tx_packet(struct niu *np, struct tx_ring_info *rp, int idx)
tb = &rp->tx_buffs[idx];
BUG_ON(tb->skb != NULL);
np->ops->unmap_page(np->device, tb->mapping,
- skb_shinfo(skb)->frags[i].size,
+ skb_frag_size(&skb_shinfo(skb)->frags[i]),
DMA_TO_DEVICE);
idx = NEXT_TX(rp, idx);
}
@@ -6733,10 +6727,10 @@ static netdev_tx_t niu_start_xmit(struct sk_buff *skb,
}
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- len = frag->size;
- mapping = np->ops->map_page(np->device, frag->page,
+ len = skb_frag_size(frag);
+ mapping = np->ops->map_page(np->device, skb_frag_page(frag),
frag->page_offset, len,
DMA_TO_DEVICE);
@@ -7301,11 +7295,13 @@ static int niu_get_ethtool_tcam_all(struct niu *np,
}
niu_unlock_parent(np, flags);
+ nfc->rule_cnt = cnt;
+
return ret;
}
static int niu_get_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
- void *rule_locs)
+ u32 *rule_locs)
{
struct niu *np = netdev_priv(dev);
int ret = 0;
@@ -7324,7 +7320,7 @@ static int niu_get_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
ret = niu_get_ethtool_tcam_entry(np, cmd);
break;
case ETHTOOL_GRXCLSRLALL:
- ret = niu_get_ethtool_tcam_all(np, cmd, (u32 *)rule_locs);
+ ret = niu_get_ethtool_tcam_all(np, cmd, rule_locs);
break;
default:
ret = -EINVAL;
@@ -9716,7 +9712,7 @@ static const struct net_device_ops niu_netdev_ops = {
.ndo_stop = niu_close,
.ndo_start_xmit = niu_start_xmit,
.ndo_get_stats64 = niu_get_stats,
- .ndo_set_multicast_list = niu_set_rx_mode,
+ .ndo_set_rx_mode = niu_set_rx_mode,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = niu_set_mac_addr,
.ndo_do_ioctl = niu_ioctl,
@@ -9852,6 +9848,8 @@ static int __devinit niu_pci_init_one(struct pci_dev *pdev,
niu_set_basic_features(dev);
+ dev->priv_flags |= IFF_UNICAST_FLT;
+
np->regs = pci_ioremap_bar(pdev, 0);
if (!np->regs) {
dev_err(&pdev->dev, "Cannot map device registers, aborting\n");
diff --git a/drivers/net/niu.h b/drivers/net/ethernet/sun/niu.h
index 51e177e1860d..51e177e1860d 100644
--- a/drivers/net/niu.h
+++ b/drivers/net/ethernet/sun/niu.h
diff --git a/drivers/net/sunbmac.c b/drivers/net/ethernet/sun/sunbmac.c
index 297a4242106b..0d8cfd9ea053 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/ethernet/sun/sunbmac.c
@@ -17,6 +17,7 @@
#include <linux/crc32.h>
#include <linux/errno.h>
#include <linux/ethtool.h>
+#include <linux/mii.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
@@ -500,13 +501,13 @@ static int try_next_permutation(struct bigmac *bp, void __iomem *tregs)
/* Reset the PHY. */
bp->sw_bmcr = (BMCR_ISOLATE | BMCR_PDOWN | BMCR_LOOPBACK);
- bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr);
+ bigmac_tcvr_write(bp, tregs, MII_BMCR, bp->sw_bmcr);
bp->sw_bmcr = (BMCR_RESET);
- bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr);
+ bigmac_tcvr_write(bp, tregs, MII_BMCR, bp->sw_bmcr);
timeout = 64;
while (--timeout) {
- bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR);
+ bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, MII_BMCR);
if ((bp->sw_bmcr & BMCR_RESET) == 0)
break;
udelay(20);
@@ -514,11 +515,11 @@ static int try_next_permutation(struct bigmac *bp, void __iomem *tregs)
if (timeout == 0)
printk(KERN_ERR "%s: PHY reset failed.\n", bp->dev->name);
- bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR);
+ bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, MII_BMCR);
/* Now we try 10baseT. */
bp->sw_bmcr &= ~(BMCR_SPEED100);
- bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr);
+ bigmac_tcvr_write(bp, tregs, MII_BMCR, bp->sw_bmcr);
return 0;
}
@@ -534,8 +535,8 @@ static void bigmac_timer(unsigned long data)
bp->timer_ticks++;
if (bp->timer_state == ltrywait) {
- bp->sw_bmsr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMSR);
- bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR);
+ bp->sw_bmsr = bigmac_tcvr_read(bp, tregs, MII_BMSR);
+ bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, MII_BMCR);
if (bp->sw_bmsr & BMSR_LSTATUS) {
printk(KERN_INFO "%s: Link is now up at %s.\n",
bp->dev->name,
@@ -588,18 +589,18 @@ static void bigmac_begin_auto_negotiation(struct bigmac *bp)
int timeout;
/* Grab new software copies of PHY registers. */
- bp->sw_bmsr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMSR);
- bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR);
+ bp->sw_bmsr = bigmac_tcvr_read(bp, tregs, MII_BMSR);
+ bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, MII_BMCR);
/* Reset the PHY. */
bp->sw_bmcr = (BMCR_ISOLATE | BMCR_PDOWN | BMCR_LOOPBACK);
- bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr);
+ bigmac_tcvr_write(bp, tregs, MII_BMCR, bp->sw_bmcr);
bp->sw_bmcr = (BMCR_RESET);
- bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr);
+ bigmac_tcvr_write(bp, tregs, MII_BMCR, bp->sw_bmcr);
timeout = 64;
while (--timeout) {
- bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR);
+ bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, MII_BMCR);
if ((bp->sw_bmcr & BMCR_RESET) == 0)
break;
udelay(20);
@@ -607,11 +608,11 @@ static void bigmac_begin_auto_negotiation(struct bigmac *bp)
if (timeout == 0)
printk(KERN_ERR "%s: PHY reset failed.\n", bp->dev->name);
- bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR);
+ bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, MII_BMCR);
/* First we try 100baseT. */
bp->sw_bmcr |= BMCR_SPEED100;
- bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr);
+ bigmac_tcvr_write(bp, tregs, MII_BMCR, bp->sw_bmcr);
bp->timer_state = ltrywait;
bp->timer_ticks = 0;
@@ -1054,7 +1055,7 @@ static u32 bigmac_get_link(struct net_device *dev)
struct bigmac *bp = netdev_priv(dev);
spin_lock_irq(&bp->lock);
- bp->sw_bmsr = bigmac_tcvr_read(bp, bp->tregs, BIGMAC_BMSR);
+ bp->sw_bmsr = bigmac_tcvr_read(bp, bp->tregs, MII_BMSR);
spin_unlock_irq(&bp->lock);
return (bp->sw_bmsr & BMSR_LSTATUS);
@@ -1070,7 +1071,7 @@ static const struct net_device_ops bigmac_ops = {
.ndo_stop = bigmac_close,
.ndo_start_xmit = bigmac_start_xmit,
.ndo_get_stats = bigmac_get_stats,
- .ndo_set_multicast_list = bigmac_set_multicast,
+ .ndo_set_rx_mode = bigmac_set_multicast,
.ndo_tx_timeout = bigmac_tx_timeout,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/sunbmac.h b/drivers/net/ethernet/sun/sunbmac.h
index 4943e975a731..06dd21707353 100644
--- a/drivers/net/sunbmac.h
+++ b/drivers/net/ethernet/sun/sunbmac.h
@@ -223,23 +223,6 @@
#define BIGMAC_PHY_EXTERNAL 0 /* External transceiver */
#define BIGMAC_PHY_INTERNAL 1 /* Internal transceiver */
-/* PHY registers */
-#define BIGMAC_BMCR 0x00 /* Basic mode control register */
-#define BIGMAC_BMSR 0x01 /* Basic mode status register */
-
-/* BMCR bits */
-#define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */
-#define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */
-#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */
-#define BMCR_SPEED100 0x2000 /* Select 100Mbps */
-#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */
-#define BMCR_RESET 0x8000 /* Reset the DP83840 */
-
-/* BMSR bits */
-#define BMSR_ERCAP 0x0001 /* Ext-reg capability */
-#define BMSR_JCD 0x0002 /* Jabber detected */
-#define BMSR_LSTATUS 0x0004 /* Link status */
-
/* Ring descriptors and such, same as Quad Ethernet. */
struct be_rxd {
u32 rx_flags;
diff --git a/drivers/net/sungem.c b/drivers/net/ethernet/sun/sungem.c
index ade35dde5b51..ceab215bb4a3 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/ethernet/sun/sungem.c
@@ -59,7 +59,7 @@
#include <asm/pmac_feature.h>
#endif
-#include "sungem_phy.h"
+#include <linux/sungem_phy.h>
#include "sungem.h"
/* Stripping FCS is causing problems, disabled for now */
@@ -1065,16 +1065,14 @@ static netdev_tx_t gem_start_xmit(struct sk_buff *skb,
entry = NEXT_TX(entry);
for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
- skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
+ const skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
u32 len;
dma_addr_t mapping;
u64 this_ctrl;
- len = this_frag->size;
- mapping = pci_map_page(gp->pdev,
- this_frag->page,
- this_frag->page_offset,
- len, PCI_DMA_TODEVICE);
+ len = skb_frag_size(this_frag);
+ mapping = skb_frag_dma_map(&gp->pdev->dev, this_frag,
+ 0, len, DMA_TO_DEVICE);
this_ctrl = ctrl;
if (frag == skb_shinfo(skb)->nr_frags - 1)
this_ctrl |= TXDCTRL_EOF;
@@ -1721,7 +1719,7 @@ static void gem_init_phy(struct gem *gp)
if (gp->phy_type == phy_mii_mdio0 ||
gp->phy_type == phy_mii_mdio1) {
/* Reset and detect MII PHY */
- mii_phy_probe(&gp->phy_mii, gp->mii_phy_addr);
+ sungem_phy_probe(&gp->phy_mii, gp->mii_phy_addr);
/* Init PHY */
if (gp->phy_mii.def && gp->phy_mii.def->ops->init)
@@ -2820,7 +2818,7 @@ static const struct net_device_ops gem_netdev_ops = {
.ndo_stop = gem_close,
.ndo_start_xmit = gem_start_xmit,
.ndo_get_stats = gem_get_stats,
- .ndo_set_multicast_list = gem_set_multicast,
+ .ndo_set_rx_mode = gem_set_multicast,
.ndo_do_ioctl = gem_ioctl,
.ndo_tx_timeout = gem_tx_timeout,
.ndo_change_mtu = gem_change_mtu,
diff --git a/drivers/net/sungem.h b/drivers/net/ethernet/sun/sungem.h
index 835ce1b3cb9f..835ce1b3cb9f 100644
--- a/drivers/net/sungem.h
+++ b/drivers/net/ethernet/sun/sungem.h
diff --git a/drivers/net/sunhme.c b/drivers/net/ethernet/sun/sunhme.c
index 856e05b9fba3..c517dac02ae1 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/ethernet/sun/sunhme.c
@@ -2305,13 +2305,12 @@ static netdev_tx_t happy_meal_start_xmit(struct sk_buff *skb,
entry = NEXT_TX(entry);
for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
- skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
+ const skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
u32 len, mapping, this_txflags;
- len = this_frag->size;
- mapping = dma_map_page(hp->dma_dev, this_frag->page,
- this_frag->page_offset, len,
- DMA_TO_DEVICE);
+ len = skb_frag_size(this_frag);
+ mapping = skb_frag_dma_map(hp->dma_dev, this_frag,
+ 0, len, DMA_TO_DEVICE);
this_txflags = tx_flags;
if (frag == skb_shinfo(skb)->nr_frags - 1)
this_txflags |= TXFLAG_EOP;
@@ -2619,7 +2618,7 @@ static const struct net_device_ops hme_netdev_ops = {
.ndo_start_xmit = happy_meal_start_xmit,
.ndo_tx_timeout = happy_meal_tx_timeout,
.ndo_get_stats = happy_meal_get_stats,
- .ndo_set_multicast_list = happy_meal_set_multicast,
+ .ndo_set_rx_mode = happy_meal_set_multicast,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/sunhme.h b/drivers/net/ethernet/sun/sunhme.h
index 64f278360d89..64f278360d89 100644
--- a/drivers/net/sunhme.h
+++ b/drivers/net/ethernet/sun/sunhme.h
diff --git a/drivers/net/sunqe.c b/drivers/net/ethernet/sun/sunqe.c
index 209c7f8df003..b28f74367ebe 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/ethernet/sun/sunqe.c
@@ -824,7 +824,7 @@ static const struct net_device_ops qec_ops = {
.ndo_open = qe_open,
.ndo_stop = qe_close,
.ndo_start_xmit = qe_start_xmit,
- .ndo_set_multicast_list = qe_set_multicast,
+ .ndo_set_rx_mode = qe_set_multicast,
.ndo_tx_timeout = qe_tx_timeout,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/sunqe.h b/drivers/net/ethernet/sun/sunqe.h
index 581781b6b2fa..581781b6b2fa 100644
--- a/drivers/net/sunqe.h
+++ b/drivers/net/ethernet/sun/sunqe.h
diff --git a/drivers/net/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c
index bf3c762de620..8c6c059f3489 100644
--- a/drivers/net/sunvnet.c
+++ b/drivers/net/ethernet/sun/sunvnet.c
@@ -1012,7 +1012,7 @@ static DEFINE_MUTEX(vnet_list_mutex);
static const struct net_device_ops vnet_ops = {
.ndo_open = vnet_open,
.ndo_stop = vnet_close,
- .ndo_set_multicast_list = vnet_set_rx_mode,
+ .ndo_set_rx_mode = vnet_set_rx_mode,
.ndo_set_mac_address = vnet_set_mac_addr,
.ndo_validate_addr = eth_validate_addr,
.ndo_tx_timeout = vnet_tx_timeout,
diff --git a/drivers/net/sunvnet.h b/drivers/net/ethernet/sun/sunvnet.h
index d347a5bf24b0..d347a5bf24b0 100644
--- a/drivers/net/sunvnet.h
+++ b/drivers/net/ethernet/sun/sunvnet.h
diff --git a/drivers/net/ethernet/tehuti/Kconfig b/drivers/net/ethernet/tehuti/Kconfig
new file mode 100644
index 000000000000..1fc027eda33e
--- /dev/null
+++ b/drivers/net/ethernet/tehuti/Kconfig
@@ -0,0 +1,27 @@
+#
+# Tehuti network device configuration
+#
+
+config NET_VENDOR_TEHUTI
+ bool "Tehuti devices"
+ default y
+ depends on PCI
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Tehuti cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_TEHUTI
+
+config TEHUTI
+ tristate "Tehuti Networks 10G Ethernet"
+ depends on PCI
+ ---help---
+ Tehuti Networks 10G Ethernet NIC
+
+endif # NET_VENDOR_TEHUTI
diff --git a/drivers/net/ethernet/tehuti/Makefile b/drivers/net/ethernet/tehuti/Makefile
new file mode 100644
index 000000000000..f995421ddbc8
--- /dev/null
+++ b/drivers/net/ethernet/tehuti/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Tehuti network device drivers.
+#
+
+obj-$(CONFIG_TEHUTI) += tehuti.o
diff --git a/drivers/net/tehuti.c b/drivers/net/ethernet/tehuti/tehuti.c
index 749bbf18dc6a..3a90af6d111c 100644
--- a/drivers/net/tehuti.c
+++ b/drivers/net/ethernet/tehuti/tehuti.c
@@ -67,10 +67,10 @@
#include "tehuti.h"
static DEFINE_PCI_DEVICE_TABLE(bdx_pci_tbl) = {
- {0x1FC9, 0x3009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {0x1FC9, 0x3010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {0x1FC9, 0x3014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {0}
+ { PCI_VDEVICE(TEHUTI, 0x3009), },
+ { PCI_VDEVICE(TEHUTI, 0x3010), },
+ { PCI_VDEVICE(TEHUTI, 0x3014), },
+ { 0 }
};
MODULE_DEVICE_TABLE(pci, bdx_pci_tbl);
@@ -1493,13 +1493,13 @@ bdx_tx_map_skb(struct bdx_priv *priv, struct sk_buff *skb,
bdx_tx_db_inc_wptr(db);
for (i = 0; i < nr_frags; i++) {
- struct skb_frag_struct *frag;
+ const struct skb_frag_struct *frag;
frag = &skb_shinfo(skb)->frags[i];
- db->wptr->len = frag->size;
- db->wptr->addr.dma =
- pci_map_page(priv->pdev, frag->page, frag->page_offset,
- frag->size, PCI_DMA_TODEVICE);
+ db->wptr->len = skb_frag_size(frag);
+ db->wptr->addr.dma = skb_frag_dma_map(&priv->pdev->dev, frag,
+ 0, skb_frag_size(frag),
+ DMA_TO_DEVICE);
pbl++;
pbl->len = CPU_CHIP_SWAP32(db->wptr->len);
@@ -1860,7 +1860,7 @@ static const struct net_device_ops bdx_netdev_ops = {
.ndo_start_xmit = bdx_tx_transmit,
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = bdx_ioctl,
- .ndo_set_multicast_list = bdx_setmulti,
+ .ndo_set_rx_mode = bdx_setmulti,
.ndo_change_mtu = bdx_change_mtu,
.ndo_set_mac_address = bdx_set_mac,
.ndo_vlan_rx_add_vid = bdx_vlan_rx_add_vid,
diff --git a/drivers/net/tehuti.h b/drivers/net/ethernet/tehuti/tehuti.h
index 709ebd6e28b4..709ebd6e28b4 100644
--- a/drivers/net/tehuti.h
+++ b/drivers/net/ethernet/tehuti/tehuti.h
diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig
new file mode 100644
index 000000000000..de76c70ec8fb
--- /dev/null
+++ b/drivers/net/ethernet/ti/Kconfig
@@ -0,0 +1,77 @@
+#
+# TI device configuration
+#
+
+config NET_VENDOR_TI
+ bool "Texas Instruments (TI) devices"
+ default y
+ depends on PCI || EISA || AR7 || (ARM && (ARCH_DAVINCI || ARCH_OMAP3))
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about TI devices. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_TI
+
+config TI_DAVINCI_EMAC
+ tristate "TI DaVinci EMAC Support"
+ depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 )
+ select TI_DAVINCI_MDIO
+ select TI_DAVINCI_CPDMA
+ select PHYLIB
+ ---help---
+ This driver supports TI's DaVinci Ethernet .
+
+ To compile this driver as a module, choose M here: the module
+ will be called davinci_emac_driver. This is recommended.
+
+config TI_DAVINCI_MDIO
+ tristate "TI DaVinci MDIO Support"
+ depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 )
+ select PHYLIB
+ ---help---
+ This driver supports TI's DaVinci MDIO module.
+
+ To compile this driver as a module, choose M here: the module
+ will be called davinci_mdio. This is recommended.
+
+config TI_DAVINCI_CPDMA
+ tristate "TI DaVinci CPDMA Support"
+ depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 )
+ ---help---
+ This driver supports TI's DaVinci CPDMA dma engine.
+
+ To compile this driver as a module, choose M here: the module
+ will be called davinci_cpdma. This is recommended.
+
+config TLAN
+ tristate "TI ThunderLAN support"
+ depends on (PCI || EISA)
+ ---help---
+ If you have a PCI Ethernet network card based on the ThunderLAN chip
+ which is supported by this driver, say Y and read the
+ Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Devices currently supported by this driver are Compaq Netelligent,
+ Compaq NetFlex and Olicom cards. Please read the file
+ <file:Documentation/networking/tlan.txt> for more details.
+
+ To compile this driver as a module, choose M here. The module
+ will be called tlan.
+
+ Please email feedback to <torben.mathiasen@compaq.com>.
+
+config CPMAC
+ tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && AR7
+ select PHYLIB
+ ---help---
+ TI AR7 CPMAC Ethernet support
+
+endif # NET_VENDOR_TI
diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile
new file mode 100644
index 000000000000..aedb3af74e5a
--- /dev/null
+++ b/drivers/net/ethernet/ti/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the TI network device drivers.
+#
+
+obj-$(CONFIG_TLAN) += tlan.o
+obj-$(CONFIG_CPMAC) += cpmac.o
+obj-$(CONFIG_TI_DAVINCI_EMAC) += davinci_emac.o
+obj-$(CONFIG_TI_DAVINCI_MDIO) += davinci_mdio.o
+obj-$(CONFIG_TI_DAVINCI_CPDMA) += davinci_cpdma.o
diff --git a/drivers/net/cpmac.c b/drivers/net/ethernet/ti/cpmac.c
index e0638cb4b07c..aaac0c7ad111 100644
--- a/drivers/net/cpmac.c
+++ b/drivers/net/ethernet/ti/cpmac.c
@@ -1100,7 +1100,7 @@ static const struct net_device_ops cpmac_netdev_ops = {
.ndo_stop = cpmac_stop,
.ndo_start_xmit = cpmac_start_xmit,
.ndo_tx_timeout = cpmac_tx_timeout,
- .ndo_set_multicast_list = cpmac_set_multicast_list,
+ .ndo_set_rx_mode = cpmac_set_multicast_list,
.ndo_do_ioctl = cpmac_ioctl,
.ndo_set_config = cpmac_config,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c
index dca9d3369cdd..dca9d3369cdd 100644
--- a/drivers/net/davinci_cpdma.c
+++ b/drivers/net/ethernet/ti/davinci_cpdma.c
diff --git a/drivers/net/davinci_cpdma.h b/drivers/net/ethernet/ti/davinci_cpdma.h
index afa19a0c0d81..afa19a0c0d81 100644
--- a/drivers/net/davinci_cpdma.h
+++ b/drivers/net/ethernet/ti/davinci_cpdma.h
diff --git a/drivers/net/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c
index 3f451e4d8361..815c7970261b 100644
--- a/drivers/net/davinci_emac.c
+++ b/drivers/net/ethernet/ti/davinci_emac.c
@@ -1741,7 +1741,7 @@ static const struct net_device_ops emac_netdev_ops = {
.ndo_open = emac_dev_open,
.ndo_stop = emac_dev_stop,
.ndo_start_xmit = emac_dev_xmit,
- .ndo_set_multicast_list = emac_dev_mcast_set,
+ .ndo_set_rx_mode = emac_dev_mcast_set,
.ndo_set_mac_address = emac_dev_setmac_addr,
.ndo_do_ioctl = emac_devioctl,
.ndo_tx_timeout = emac_dev_tx_timeout,
diff --git a/drivers/net/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c
index 7615040df756..7615040df756 100644
--- a/drivers/net/davinci_mdio.c
+++ b/drivers/net/ethernet/ti/davinci_mdio.c
diff --git a/drivers/net/tlan.c b/drivers/net/ethernet/ti/tlan.c
index 145871b3130b..9c0dd6b8d6c9 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/ethernet/ti/tlan.c
@@ -774,7 +774,7 @@ static const struct net_device_ops tlan_netdev_ops = {
.ndo_start_xmit = tlan_start_tx,
.ndo_tx_timeout = tlan_tx_timeout,
.ndo_get_stats = tlan_get_stats,
- .ndo_set_multicast_list = tlan_set_multicast_list,
+ .ndo_set_rx_mode = tlan_set_multicast_list,
.ndo_do_ioctl = tlan_ioctl,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/tlan.h b/drivers/net/ethernet/ti/tlan.h
index 5fc98a8e4889..5fc98a8e4889 100644
--- a/drivers/net/tlan.h
+++ b/drivers/net/ethernet/ti/tlan.h
diff --git a/drivers/net/ethernet/tile/Kconfig b/drivers/net/ethernet/tile/Kconfig
new file mode 100644
index 000000000000..2d9218f86bca
--- /dev/null
+++ b/drivers/net/ethernet/tile/Kconfig
@@ -0,0 +1,15 @@
+#
+# Tilera network device configuration
+#
+
+config TILE_NET
+ tristate "Tilera GBE/XGBE network driver support"
+ depends on TILE
+ default y
+ select CRC32
+ ---help---
+ This is a standard Linux network device driver for the
+ on-chip Tilera Gigabit Ethernet and XAUI interfaces.
+
+ To compile this driver as a module, choose M here: the module
+ will be called tile_net.
diff --git a/drivers/net/tile/Makefile b/drivers/net/ethernet/tile/Makefile
index f634f142cab4..f634f142cab4 100644
--- a/drivers/net/tile/Makefile
+++ b/drivers/net/ethernet/tile/Makefile
diff --git a/drivers/net/tile/tilepro.c b/drivers/net/ethernet/tile/tilepro.c
index 1e2af96fc29c..10826d8a2a2d 100644
--- a/drivers/net/tile/tilepro.c
+++ b/drivers/net/ethernet/tile/tilepro.c
@@ -177,7 +177,7 @@ struct tile_net_cpu {
struct tile_net_stats_t stats;
/* True iff NAPI is enabled. */
bool napi_enabled;
- /* True if this tile has succcessfully registered with the IPP. */
+ /* True if this tile has successfully registered with the IPP. */
bool registered;
/* True if the link was down last time we tried to register. */
bool link_down;
@@ -1713,7 +1713,7 @@ static unsigned int tile_net_tx_frags(lepp_frag_t *frags,
cpa = ((phys_addr_t)pfn << PAGE_SHIFT) + f->page_offset;
frags[n].cpa_lo = cpa;
frags[n].cpa_hi = cpa >> 32;
- frags[n].length = f->size;
+ frags[n].length = skb_frag_size(f);
frags[n].hash_for_home = hash_for_home;
n++;
}
diff --git a/drivers/net/ethernet/toshiba/Kconfig b/drivers/net/ethernet/toshiba/Kconfig
new file mode 100644
index 000000000000..051764704559
--- /dev/null
+++ b/drivers/net/ethernet/toshiba/Kconfig
@@ -0,0 +1,57 @@
+#
+# Toshiba network device configuration
+#
+
+config NET_VENDOR_TOSHIBA
+ bool "Toshiba devices"
+ default y
+ depends on PCI && (PPC_IBM_CELL_BLADE || PPC_CELLEB) || PPC_PS3
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Toshiba cards. If you say Y, you will be asked
+ for your specific card in the following questions.
+
+if NET_VENDOR_TOSHIBA
+
+config GELIC_NET
+ tristate "PS3 Gigabit Ethernet driver"
+ depends on PPC_PS3
+ select PS3_SYS_MANAGER
+ ---help---
+ This driver supports the network device on the PS3 game
+ console. This driver has built-in support for Ethernet.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ps3_gelic.
+
+config GELIC_WIRELESS
+ bool "PS3 Wireless support"
+ depends on GELIC_NET && WLAN
+ select WIRELESS_EXT
+ ---help---
+ This option adds the support for the wireless feature of PS3.
+ If you have the wireless-less model of PS3 or have no plan to
+ use wireless feature, disabling this option saves memory. As
+ the driver automatically distinguishes the models, you can
+ safely enable this option even if you have a wireless-less model.
+
+config SPIDER_NET
+ tristate "Spider Gigabit Ethernet driver"
+ depends on PCI && (PPC_IBM_CELL_BLADE || PPC_CELLEB)
+ select FW_LOADER
+ select SUNGEM_PHY
+ ---help---
+ This driver supports the Gigabit Ethernet chips present on the
+ Cell Processor-Based Blades from IBM.
+
+config TC35815
+ tristate "TOSHIBA TC35815 Ethernet support"
+ depends on PCI && MIPS
+ select PHYLIB
+
+endif # NET_VENDOR_TOSHIBA
diff --git a/drivers/net/ethernet/toshiba/Makefile b/drivers/net/ethernet/toshiba/Makefile
new file mode 100644
index 000000000000..a5069008435b
--- /dev/null
+++ b/drivers/net/ethernet/toshiba/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the Toshiba network device drivers.
+#
+
+obj-$(CONFIG_GELIC_NET) += ps3_gelic.o
+gelic_wireless-$(CONFIG_GELIC_WIRELESS) += ps3_gelic_wireless.o
+ps3_gelic-objs += ps3_gelic_net.o $(gelic_wireless-y)
+spidernet-y += spider_net.o spider_net_ethtool.o
+obj-$(CONFIG_SPIDER_NET) += spidernet.o
+obj-$(CONFIG_TC35815) += tc35815.o
diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ethernet/toshiba/ps3_gelic_net.c
index d82a82d9870c..ddb33cfd3543 100644
--- a/drivers/net/ps3_gelic_net.c
+++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.c
@@ -1452,7 +1452,7 @@ static const struct net_device_ops gelic_netdevice_ops = {
.ndo_open = gelic_net_open,
.ndo_stop = gelic_net_stop,
.ndo_start_xmit = gelic_net_xmit,
- .ndo_set_multicast_list = gelic_net_set_multi,
+ .ndo_set_rx_mode = gelic_net_set_multi,
.ndo_change_mtu = gelic_net_change_mtu,
.ndo_tx_timeout = gelic_net_tx_timeout,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/ps3_gelic_net.h b/drivers/net/ethernet/toshiba/ps3_gelic_net.h
index d3fadfbc3bcc..d3fadfbc3bcc 100644
--- a/drivers/net/ps3_gelic_net.h
+++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.h
diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c
index 2e62938c0f82..fd4ed7f8cfa1 100644
--- a/drivers/net/ps3_gelic_wireless.c
+++ b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c
@@ -2568,7 +2568,7 @@ static const struct net_device_ops gelic_wl_netdevice_ops = {
.ndo_open = gelic_wl_open,
.ndo_stop = gelic_wl_stop,
.ndo_start_xmit = gelic_net_xmit,
- .ndo_set_multicast_list = gelic_net_set_multi,
+ .ndo_set_rx_mode = gelic_net_set_multi,
.ndo_change_mtu = gelic_net_change_mtu,
.ndo_tx_timeout = gelic_net_tx_timeout,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/ps3_gelic_wireless.h b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.h
index f7e51b7d7049..f7e51b7d7049 100644
--- a/drivers/net/ps3_gelic_wireless.h
+++ b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.h
diff --git a/drivers/net/spider_net.c b/drivers/net/ethernet/toshiba/spider_net.c
index 1ff3491c8240..6199f6b387b6 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/ethernet/toshiba/spider_net.c
@@ -196,7 +196,7 @@ spider_net_setup_aneg(struct spider_net_card *card)
if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_THALF))
advertise |= SUPPORTED_1000baseT_Half;
- mii_phy_probe(phy, phy->mii_id);
+ sungem_phy_probe(phy, phy->mii_id);
phy->def->ops->setup_aneg(phy, advertise);
}
@@ -2120,7 +2120,7 @@ spider_net_setup_phy(struct spider_net_card *card)
unsigned short id;
id = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR);
if (id != 0x0000 && id != 0xffff) {
- if (!mii_phy_probe(phy, phy->mii_id)) {
+ if (!sungem_phy_probe(phy, phy->mii_id)) {
pr_info("Found %s.\n", phy->def->name);
break;
}
@@ -2259,7 +2259,7 @@ static const struct net_device_ops spider_net_ops = {
.ndo_open = spider_net_open,
.ndo_stop = spider_net_stop,
.ndo_start_xmit = spider_net_xmit,
- .ndo_set_multicast_list = spider_net_set_multi,
+ .ndo_set_rx_mode = spider_net_set_multi,
.ndo_set_mac_address = spider_net_set_mac,
.ndo_change_mtu = spider_net_change_mtu,
.ndo_do_ioctl = spider_net_do_ioctl,
diff --git a/drivers/net/spider_net.h b/drivers/net/ethernet/toshiba/spider_net.h
index 020f64a8fcf7..4ba2135474d1 100644
--- a/drivers/net/spider_net.h
+++ b/drivers/net/ethernet/toshiba/spider_net.h
@@ -27,7 +27,7 @@
#define VERSION "2.0 B"
-#include "sungem_phy.h"
+#include <linux/sungem_phy.h>
extern int spider_net_stop(struct net_device *netdev);
extern int spider_net_open(struct net_device *netdev);
diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/ethernet/toshiba/spider_net_ethtool.c
index 9c288cd7d171..9c288cd7d171 100644
--- a/drivers/net/spider_net_ethtool.c
+++ b/drivers/net/ethernet/toshiba/spider_net_ethtool.c
diff --git a/drivers/net/tc35815.c b/drivers/net/ethernet/toshiba/tc35815.c
index 4a55a162dfe6..71b785cd7563 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/ethernet/toshiba/tc35815.c
@@ -774,7 +774,7 @@ static const struct net_device_ops tc35815_netdev_ops = {
.ndo_stop = tc35815_close,
.ndo_start_xmit = tc35815_send_packet,
.ndo_get_stats = tc35815_get_stats,
- .ndo_set_multicast_list = tc35815_set_multicast_list,
+ .ndo_set_rx_mode = tc35815_set_multicast_list,
.ndo_tx_timeout = tc35815_tx_timeout,
.ndo_do_ioctl = tc35815_ioctl,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/ethernet/tundra/Kconfig b/drivers/net/ethernet/tundra/Kconfig
new file mode 100644
index 000000000000..cf7d69b62c42
--- /dev/null
+++ b/drivers/net/ethernet/tundra/Kconfig
@@ -0,0 +1,29 @@
+#
+# Tundra network device configuration
+#
+
+config NET_VENDOR_TUNDRA
+ bool "Tundra devices"
+ default y
+ depends on TSI108_BRIDGE
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Tundra cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_TUNDRA
+
+config TSI108_ETH
+ tristate "Tundra TSI108 gigabit Ethernet support"
+ depends on TSI108_BRIDGE
+ ---help---
+ This driver supports Tundra TSI108 gigabit Ethernet ports.
+ To compile this driver as a module, choose M here: the module
+ will be called tsi108_eth.
+
+endif # NET_VENDOR_TUNDRA
diff --git a/drivers/net/ethernet/tundra/Makefile b/drivers/net/ethernet/tundra/Makefile
new file mode 100644
index 000000000000..439f6930235b
--- /dev/null
+++ b/drivers/net/ethernet/tundra/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Tundra network device drivers.
+#
+
+obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o
diff --git a/drivers/net/tsi108_eth.c b/drivers/net/ethernet/tundra/tsi108_eth.c
index 64cb9ac19ed9..a8df7eca0956 100644
--- a/drivers/net/tsi108_eth.c
+++ b/drivers/net/ethernet/tundra/tsi108_eth.c
@@ -709,12 +709,13 @@ static int tsi108_send_packet(struct sk_buff * skb, struct net_device *dev)
data->txring[tx].len = skb_headlen(skb);
misc |= TSI108_TX_SOF;
} else {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1];
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1];
- data->txring[tx].buf0 =
- dma_map_page(NULL, frag->page, frag->page_offset,
- frag->size, DMA_TO_DEVICE);
- data->txring[tx].len = frag->size;
+ data->txring[tx].buf0 = skb_frag_dma_map(NULL, frag,
+ 0,
+ skb_frag_size(frag),
+ DMA_TO_DEVICE);
+ data->txring[tx].len = skb_frag_size(frag);
}
if (i == frags - 1)
@@ -1554,7 +1555,7 @@ static const struct net_device_ops tsi108_netdev_ops = {
.ndo_open = tsi108_open,
.ndo_stop = tsi108_close,
.ndo_start_xmit = tsi108_send_packet,
- .ndo_set_multicast_list = tsi108_set_rx_mode,
+ .ndo_set_rx_mode = tsi108_set_rx_mode,
.ndo_get_stats = tsi108_get_stats,
.ndo_do_ioctl = tsi108_do_ioctl,
.ndo_set_mac_address = tsi108_set_mac,
diff --git a/drivers/net/tsi108_eth.h b/drivers/net/ethernet/tundra/tsi108_eth.h
index 5fee7d78dc6d..5fee7d78dc6d 100644
--- a/drivers/net/tsi108_eth.h
+++ b/drivers/net/ethernet/tundra/tsi108_eth.h
diff --git a/drivers/net/ethernet/via/Kconfig b/drivers/net/ethernet/via/Kconfig
new file mode 100644
index 000000000000..68a9ba66feba
--- /dev/null
+++ b/drivers/net/ethernet/via/Kconfig
@@ -0,0 +1,59 @@
+#
+# VIA device configuration
+#
+
+config NET_VENDOR_VIA
+ bool "VIA devices"
+ default y
+ depends on PCI
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about VIA devices. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_VIA
+
+config VIA_RHINE
+ tristate "VIA Rhine support"
+ depends on PCI
+ select CRC32
+ select NET_CORE
+ select MII
+ ---help---
+ If you have a VIA "Rhine" based network card (Rhine-I (VT86C100A),
+ Rhine-II (VT6102), or Rhine-III (VT6105)), say Y here. Rhine-type
+ Ethernet functions can also be found integrated on South Bridges
+ (e.g. VT8235).
+
+ To compile this driver as a module, choose M here. The module
+ will be called via-rhine.
+
+config VIA_RHINE_MMIO
+ bool "Use MMIO instead of PIO"
+ depends on VIA_RHINE
+ ---help---
+ This instructs the driver to use PCI shared memory (MMIO) instead of
+ programmed I/O ports (PIO). Enabling this gives an improvement in
+ processing time in parts of the driver.
+
+ If unsure, say Y.
+
+config VIA_VELOCITY
+ tristate "VIA Velocity support"
+ depends on PCI
+ select CRC32
+ select CRC_CCITT
+ select NET_CORE
+ select MII
+ ---help---
+ If you have a VIA "Velocity" based network card say Y here.
+
+ To compile this driver as a module, choose M here. The module
+ will be called via-velocity.
+
+endif # NET_VENDOR_VIA
diff --git a/drivers/net/ethernet/via/Makefile b/drivers/net/ethernet/via/Makefile
new file mode 100644
index 000000000000..46c5d4a3d8f1
--- /dev/null
+++ b/drivers/net/ethernet/via/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the VIA device drivers.
+#
+
+obj-$(CONFIG_VIA_RHINE) += via-rhine.o
+obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o
diff --git a/drivers/net/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c
index 7f23ab913fd9..f34dd99fe579 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/ethernet/via/via-rhine.c
@@ -697,7 +697,7 @@ static const struct net_device_ops rhine_netdev_ops = {
.ndo_stop = rhine_close,
.ndo_start_xmit = rhine_start_tx,
.ndo_get_stats = rhine_get_stats,
- .ndo_set_multicast_list = rhine_set_rx_mode,
+ .ndo_set_rx_mode = rhine_set_rx_mode,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/via-velocity.c b/drivers/net/ethernet/via/via-velocity.c
index deb1eca13c9f..4535d7cc848e 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/ethernet/via/via-velocity.c
@@ -42,7 +42,6 @@
*
*/
-
#include <linux/module.h>
#include <linux/types.h>
#include <linux/bitops.h>
@@ -112,7 +111,6 @@ static void mac_get_cam_mask(struct mac_regs __iomem *regs, u8 *mask)
BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
}
-
/**
* mac_set_cam_mask - Set a CAM mask
* @regs: register block for this velocity
@@ -515,10 +513,6 @@ static void velocity_init_cam_filter(struct velocity_info *vptr)
mac_set_cam_mask(regs, vptr->mCAMmask);
/* Enable VCAMs */
-
- if (test_bit(0, vptr->active_vlans))
- WORD_REG_BITS_ON(MCFG_RTGOPT, &regs->MCFG);
-
for_each_set_bit(vid, vptr->active_vlans, VLAN_N_VID) {
mac_set_vlan_cam(regs, i, (u8 *) &vid);
vptr->vCAMmask[i / 8] |= 0x1 << (i % 8);
@@ -700,7 +694,6 @@ static int velocity_mii_read(struct mac_regs __iomem *regs, u8 index, u16 *data)
return 0;
}
-
/**
* mii_check_media_mode - check media state
* @regs: velocity registers
@@ -866,8 +859,6 @@ static u32 check_connection_type(struct mac_regs __iomem *regs)
return status;
}
-
-
/**
* velocity_set_media_mode - set media mode
* @mii_status: old MII link state
@@ -1262,6 +1253,7 @@ static void setup_queue_timers(struct velocity_info *vptr)
writeb(rxqueue_timer, &vptr->mac_regs->RQETMR);
}
}
+
/**
* setup_adaptive_interrupts - Setup interrupt suppression
*
@@ -1601,8 +1593,6 @@ static void velocity_free_rd_ring(struct velocity_info *vptr)
vptr->rx.info = NULL;
}
-
-
/**
* velocity_init_rd_ring - set up receive ring
* @vptr: velocity to configure
@@ -1676,7 +1666,6 @@ static void velocity_free_dma_rings(struct velocity_info *vptr)
pci_free_consistent(vptr->pdev, size, vptr->rx.ring, vptr->rx.pool_dma);
}
-
static int velocity_init_rings(struct velocity_info *vptr, int mtu)
{
int ret;
@@ -1739,7 +1728,6 @@ static void velocity_free_tx_buf(struct velocity_info *vptr,
tdinfo->skb = NULL;
}
-
/*
* FIXME: could we merge this with velocity_free_tx_buf ?
*/
@@ -1787,7 +1775,6 @@ static void velocity_free_td_ring(struct velocity_info *vptr)
}
}
-
static void velocity_free_rings(struct velocity_info *vptr)
{
velocity_free_td_ring(vptr);
@@ -2025,7 +2012,6 @@ static inline void velocity_iph_realign(struct velocity_info *vptr,
}
}
-
/**
* velocity_receive_frame - received packet processor
* @vptr: velocity we are handling
@@ -2092,11 +2078,11 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
netif_rx(skb);
stats->rx_bytes += pkt_len;
+ stats->rx_packets++;
return 0;
}
-
/**
* velocity_rx_srv - service RX interrupt
* @vptr: velocity
@@ -2404,7 +2390,6 @@ static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd
return 0;
}
-
/**
* velocity_ioctl - ioctl entry point
* @dev: network device
@@ -2569,15 +2554,16 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb,
/* Handle fragments */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- tdinfo->skb_dma[i + 1] = pci_map_page(vptr->pdev, frag->page,
- frag->page_offset, frag->size,
- PCI_DMA_TODEVICE);
+ tdinfo->skb_dma[i + 1] = skb_frag_dma_map(&vptr->pdev->dev,
+ frag, 0,
+ skb_frag_size(frag),
+ DMA_TO_DEVICE);
td_ptr->td_buf[i + 1].pa_low = cpu_to_le32(tdinfo->skb_dma[i + 1]);
td_ptr->td_buf[i + 1].pa_high = 0;
- td_ptr->td_buf[i + 1].size = cpu_to_le16(frag->size);
+ td_ptr->td_buf[i + 1].size = cpu_to_le16(skb_frag_size(frag));
}
tdinfo->nskb_dma = i + 1;
@@ -2619,15 +2605,14 @@ out:
return NETDEV_TX_OK;
}
-
static const struct net_device_ops velocity_netdev_ops = {
.ndo_open = velocity_open,
.ndo_stop = velocity_close,
.ndo_start_xmit = velocity_xmit,
.ndo_get_stats = velocity_get_stats,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_set_multicast_list = velocity_set_multi,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_set_rx_mode = velocity_set_multi,
.ndo_change_mtu = velocity_change_mtu,
.ndo_do_ioctl = velocity_ioctl,
.ndo_vlan_rx_add_vid = velocity_vlan_rx_add_vid,
@@ -2717,7 +2702,6 @@ static u32 velocity_get_link(struct net_device *dev)
return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, &regs->PHYSR0) ? 1 : 0;
}
-
/**
* velocity_found1 - set up discovered velocity card
* @pdev: PCI device
@@ -2864,7 +2848,6 @@ err_free_dev:
goto out;
}
-
#ifdef CONFIG_PM
/**
* wol_calc_crc - WOL CRC
@@ -3035,7 +3018,7 @@ static int velocity_suspend(struct pci_dev *pdev, pm_message_t state)
spin_lock_irqsave(&vptr->lock, flags);
pci_save_state(pdev);
-#ifdef ETHTOOL_GWOL
+
if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) {
velocity_get_ip(vptr);
velocity_save_context(vptr, &vptr->context);
@@ -3049,9 +3032,7 @@ static int velocity_suspend(struct pci_dev *pdev, pm_message_t state)
pci_disable_device(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
}
-#else
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
-#endif
+
spin_unlock_irqrestore(&vptr->lock, flags);
return 0;
}
@@ -3132,13 +3113,13 @@ static int velocity_resume(struct pci_dev *pdev)
* uses this to handle all our card discover and plugging
*/
static struct pci_driver velocity_driver = {
- .name = VELOCITY_NAME,
- .id_table = velocity_id_table,
- .probe = velocity_found1,
- .remove = __devexit_p(velocity_remove1),
+ .name = VELOCITY_NAME,
+ .id_table = velocity_id_table,
+ .probe = velocity_found1,
+ .remove = __devexit_p(velocity_remove1),
#ifdef CONFIG_PM
- .suspend = velocity_suspend,
- .resume = velocity_resume,
+ .suspend = velocity_suspend,
+ .resume = velocity_resume,
#endif
};
@@ -3448,26 +3429,99 @@ static int velocity_set_coalesce(struct net_device *dev,
return 0;
}
+static const char velocity_gstrings[][ETH_GSTRING_LEN] = {
+ "rx_all",
+ "rx_ok",
+ "tx_ok",
+ "rx_error",
+ "rx_runt_ok",
+ "rx_runt_err",
+ "rx_64",
+ "tx_64",
+ "rx_65_to_127",
+ "tx_65_to_127",
+ "rx_128_to_255",
+ "tx_128_to_255",
+ "rx_256_to_511",
+ "tx_256_to_511",
+ "rx_512_to_1023",
+ "tx_512_to_1023",
+ "rx_1024_to_1518",
+ "tx_1024_to_1518",
+ "tx_ether_collisions",
+ "rx_crc_errors",
+ "rx_jumbo",
+ "tx_jumbo",
+ "rx_mac_control_frames",
+ "tx_mac_control_frames",
+ "rx_frame_alignement_errors",
+ "rx_long_ok",
+ "rx_long_err",
+ "tx_sqe_errors",
+ "rx_no_buf",
+ "rx_symbol_errors",
+ "in_range_length_errors",
+ "late_collisions"
+};
+
+static void velocity_get_strings(struct net_device *dev, u32 sset, u8 *data)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ memcpy(data, *velocity_gstrings, sizeof(velocity_gstrings));
+ break;
+ }
+}
+
+static int velocity_get_sset_count(struct net_device *dev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(velocity_gstrings);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void velocity_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ if (netif_running(dev)) {
+ struct velocity_info *vptr = netdev_priv(dev);
+ u32 *p = vptr->mib_counter;
+ int i;
+
+ spin_lock_irq(&vptr->lock);
+ velocity_update_hw_mibs(vptr);
+ spin_unlock_irq(&vptr->lock);
+
+ for (i = 0; i < ARRAY_SIZE(velocity_gstrings); i++)
+ *data++ = *p++;
+ }
+}
+
static const struct ethtool_ops velocity_ethtool_ops = {
- .get_settings = velocity_get_settings,
- .set_settings = velocity_set_settings,
- .get_drvinfo = velocity_get_drvinfo,
- .get_wol = velocity_ethtool_get_wol,
- .set_wol = velocity_ethtool_set_wol,
- .get_msglevel = velocity_get_msglevel,
- .set_msglevel = velocity_set_msglevel,
- .get_link = velocity_get_link,
- .get_coalesce = velocity_get_coalesce,
- .set_coalesce = velocity_set_coalesce,
- .begin = velocity_ethtool_up,
- .complete = velocity_ethtool_down
+ .get_settings = velocity_get_settings,
+ .set_settings = velocity_set_settings,
+ .get_drvinfo = velocity_get_drvinfo,
+ .get_wol = velocity_ethtool_get_wol,
+ .set_wol = velocity_ethtool_set_wol,
+ .get_msglevel = velocity_get_msglevel,
+ .set_msglevel = velocity_set_msglevel,
+ .get_link = velocity_get_link,
+ .get_strings = velocity_get_strings,
+ .get_sset_count = velocity_get_sset_count,
+ .get_ethtool_stats = velocity_get_ethtool_stats,
+ .get_coalesce = velocity_get_coalesce,
+ .set_coalesce = velocity_set_coalesce,
+ .begin = velocity_ethtool_up,
+ .complete = velocity_ethtool_down
};
-#ifdef CONFIG_PM
-#ifdef CONFIG_INET
+#if defined(CONFIG_PM) && defined(CONFIG_INET)
static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr)
{
- struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
+ struct in_ifaddr *ifa = ptr;
struct net_device *dev = ifa->ifa_dev->dev;
if (dev_net(dev) == &init_net &&
@@ -3476,12 +3530,9 @@ static int velocity_netdev_event(struct notifier_block *nb, unsigned long notifi
return NOTIFY_DONE;
}
-#endif /* CONFIG_INET */
-#endif /* CONFIG_PM */
-#if defined(CONFIG_PM) && defined(CONFIG_INET)
static struct notifier_block velocity_inetaddr_notifier = {
- .notifier_call = velocity_netdev_event,
+ .notifier_call = velocity_netdev_event,
};
static void velocity_register_notifier(void)
diff --git a/drivers/net/via-velocity.h b/drivers/net/ethernet/via/via-velocity.h
index 4cb9f13485e9..4cb9f13485e9 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/ethernet/via/via-velocity.h
diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig
new file mode 100644
index 000000000000..d5a826063a82
--- /dev/null
+++ b/drivers/net/ethernet/xilinx/Kconfig
@@ -0,0 +1,36 @@
+#
+# Xilink device configuration
+#
+
+config NET_VENDOR_XILINX
+ bool "Xilinx devices"
+ default y
+ depends on PPC || PPC32 || MICROBLAZE
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Xilinx devices. If you say Y, you will be asked
+ for your specific card in the following questions.
+
+if NET_VENDOR_XILINX
+
+config XILINX_EMACLITE
+ tristate "Xilinx 10/100 Ethernet Lite support"
+ depends on (PPC32 || MICROBLAZE)
+ select PHYLIB
+ ---help---
+ This driver supports the 10/100 Ethernet Lite from Xilinx.
+
+config XILINX_LL_TEMAC
+ tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver"
+ depends on (PPC || MICROBLAZE)
+ select PHYLIB
+ ---help---
+ This driver supports the Xilinx 10/100/1000 LocalLink TEMAC
+ core used in Xilinx Spartan and Virtex FPGAs
+
+endif # NET_VENDOR_XILINX
diff --git a/drivers/net/ethernet/xilinx/Makefile b/drivers/net/ethernet/xilinx/Makefile
new file mode 100644
index 000000000000..5feac734ea45
--- /dev/null
+++ b/drivers/net/ethernet/xilinx/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Xilink network device drivers.
+#
+
+ll_temac-objs := ll_temac_main.o ll_temac_mdio.o
+obj-$(CONFIG_XILINX_LL_TEMAC) += ll_temac.o
+obj-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o
diff --git a/drivers/net/ll_temac.h b/drivers/net/ethernet/xilinx/ll_temac.h
index 522abe2ff25a..522abe2ff25a 100644
--- a/drivers/net/ll_temac.h
+++ b/drivers/net/ethernet/xilinx/ll_temac.h
diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 728fe414147a..4d1658e78dee 100644
--- a/drivers/net/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -715,10 +715,9 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
cur_p->phys = dma_map_single(ndev->dev.parent,
- (void *)page_address(frag->page) +
- frag->page_offset,
- frag->size, DMA_TO_DEVICE);
- cur_p->len = frag->size;
+ skb_frag_address(frag),
+ frag_size(frag), DMA_TO_DEVICE);
+ cur_p->len = frag_size(frag);
cur_p->app0 = 0;
frag++;
}
@@ -922,7 +921,6 @@ static const struct net_device_ops temac_netdev_ops = {
.ndo_start_xmit = temac_start_xmit,
.ndo_set_mac_address = netdev_set_mac_address,
.ndo_validate_addr = eth_validate_addr,
- //.ndo_set_multicast_list = temac_set_multicast_list,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = temac_poll_controller,
#endif
@@ -957,6 +955,32 @@ static const struct attribute_group temac_attr_group = {
.attrs = temac_device_attrs,
};
+/* ethtool support */
+static int temac_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
+{
+ struct temac_local *lp = netdev_priv(ndev);
+ return phy_ethtool_gset(lp->phy_dev, cmd);
+}
+
+static int temac_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
+{
+ struct temac_local *lp = netdev_priv(ndev);
+ return phy_ethtool_sset(lp->phy_dev, cmd);
+}
+
+static int temac_nway_reset(struct net_device *ndev)
+{
+ struct temac_local *lp = netdev_priv(ndev);
+ return phy_start_aneg(lp->phy_dev);
+}
+
+static const struct ethtool_ops temac_ethtool_ops = {
+ .get_settings = temac_get_settings,
+ .set_settings = temac_set_settings,
+ .nway_reset = temac_nway_reset,
+ .get_link = ethtool_op_get_link,
+};
+
static int __devinit temac_of_probe(struct platform_device *op)
{
struct device_node *np;
@@ -978,6 +1002,7 @@ static int __devinit temac_of_probe(struct platform_device *op)
ndev->flags &= ~IFF_MULTICAST; /* clear multicast */
ndev->features = NETIF_F_SG | NETIF_F_FRAGLIST;
ndev->netdev_ops = &temac_netdev_ops;
+ ndev->ethtool_ops = &temac_ethtool_ops;
#if 0
ndev->features |= NETIF_F_IP_CSUM; /* Can checksum TCP/UDP over IPv4. */
ndev->features |= NETIF_F_HW_CSUM; /* Can checksum all the packets. */
diff --git a/drivers/net/ll_temac_mdio.c b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
index 8cf9d4f56bb2..8cf9d4f56bb2 100644
--- a/drivers/net/ll_temac_mdio.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
index 8018d7d045b0..8018d7d045b0 100644
--- a/drivers/net/xilinx_emaclite.c
+++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
diff --git a/drivers/net/ethernet/xircom/Kconfig b/drivers/net/ethernet/xircom/Kconfig
new file mode 100644
index 000000000000..69f56a6de821
--- /dev/null
+++ b/drivers/net/ethernet/xircom/Kconfig
@@ -0,0 +1,31 @@
+#
+# Xircom network device configuration
+#
+
+config NET_VENDOR_XIRCOM
+ bool "Xircom devices"
+ default y
+ depends on PCMCIA
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Xircom cards. If you say Y, you will be asked for
+ your specific card in the following questions.
+
+if NET_VENDOR_XIRCOM
+
+config PCMCIA_XIRC2PS
+ tristate "Xircom 16-bit PCMCIA support"
+ depends on PCMCIA
+ ---help---
+ Say Y here if you intend to attach a Xircom 16-bit PCMCIA (PC-card)
+ Ethernet or Fast Ethernet card to your computer.
+
+ To compile this driver as a module, choose M here: the module will be
+ called xirc2ps_cs. If unsure, say N.
+
+endif # NET_VENDOR_XIRCOM
diff --git a/drivers/net/ethernet/xircom/Makefile b/drivers/net/ethernet/xircom/Makefile
new file mode 100644
index 000000000000..3b7aebd8b849
--- /dev/null
+++ b/drivers/net/ethernet/xircom/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Xircom network device drivers.
+#
+
+obj-$(CONFIG_PCMCIA_XIRC2PS) += xirc2ps_cs.o
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/ethernet/xircom/xirc2ps_cs.c
index e33b190d716f..bbe8b7dbf3f3 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/ethernet/xircom/xirc2ps_cs.c
@@ -467,7 +467,7 @@ static const struct net_device_ops netdev_ops = {
.ndo_tx_timeout = xirc_tx_timeout,
.ndo_set_config = do_config,
.ndo_do_ioctl = do_ioctl,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/ethernet/xscale/Kconfig b/drivers/net/ethernet/xscale/Kconfig
new file mode 100644
index 000000000000..cf67352cea14
--- /dev/null
+++ b/drivers/net/ethernet/xscale/Kconfig
@@ -0,0 +1,32 @@
+#
+# Intel XScale IXP device configuration
+#
+
+config NET_VENDOR_XSCALE
+ bool "Intel XScale IXP devices"
+ default y
+ depends on NET_VENDOR_INTEL && ((ARM && ARCH_IXP4XX && \
+ IXP4XX_NPE && IXP4XX_QMGR) || ARCH_ENP2611)
+ ---help---
+ If you have a network (Ethernet) card belonging to this class, say Y
+ and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question does not directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about XSacle IXP devices. If you say Y, you will be
+ asked for your specific card in the following questions.
+
+if NET_VENDOR_XSCALE
+
+config IXP4XX_ETH
+ tristate "Intel IXP4xx Ethernet support"
+ depends on ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR
+ select PHYLIB
+ ---help---
+ Say Y here if you want to use built-in Ethernet ports
+ on IXP4xx processor.
+
+source "drivers/net/ethernet/xscale/ixp2000/Kconfig"
+
+endif # NET_VENDOR_XSCALE
diff --git a/drivers/net/ethernet/xscale/Makefile b/drivers/net/ethernet/xscale/Makefile
new file mode 100644
index 000000000000..b195b9d7fe81
--- /dev/null
+++ b/drivers/net/ethernet/xscale/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the Intel XScale IXP device drivers.
+#
+
+obj-$(CONFIG_ENP2611_MSF_NET) += ixp2000/
+obj-$(CONFIG_IXP4XX_ETH) += ixp4xx_eth.o
diff --git a/drivers/net/ixp2000/Kconfig b/drivers/net/ethernet/xscale/ixp2000/Kconfig
index 2fec2415651f..58dbc5b876bc 100644
--- a/drivers/net/ixp2000/Kconfig
+++ b/drivers/net/ethernet/xscale/ixp2000/Kconfig
@@ -1,6 +1,6 @@
config ENP2611_MSF_NET
tristate "Radisys ENP2611 MSF network interface support"
depends on ARCH_ENP2611
- help
+ ---help---
This is a driver for the MSF network interface unit in
the IXP2400 on the Radisys ENP2611 platform.
diff --git a/drivers/net/ixp2000/Makefile b/drivers/net/ethernet/xscale/ixp2000/Makefile
index fd38351ceaa7..fd38351ceaa7 100644
--- a/drivers/net/ixp2000/Makefile
+++ b/drivers/net/ethernet/xscale/ixp2000/Makefile
diff --git a/drivers/net/ixp2000/caleb.c b/drivers/net/ethernet/xscale/ixp2000/caleb.c
index 7dea5b95012c..7dea5b95012c 100644
--- a/drivers/net/ixp2000/caleb.c
+++ b/drivers/net/ethernet/xscale/ixp2000/caleb.c
diff --git a/drivers/net/ixp2000/caleb.h b/drivers/net/ethernet/xscale/ixp2000/caleb.h
index e93a1ef5b8a3..e93a1ef5b8a3 100644
--- a/drivers/net/ixp2000/caleb.h
+++ b/drivers/net/ethernet/xscale/ixp2000/caleb.h
diff --git a/drivers/net/ixp2000/enp2611.c b/drivers/net/ethernet/xscale/ixp2000/enp2611.c
index 34a6cfd17930..34a6cfd17930 100644
--- a/drivers/net/ixp2000/enp2611.c
+++ b/drivers/net/ethernet/xscale/ixp2000/enp2611.c
diff --git a/drivers/net/ixp2000/ixp2400-msf.c b/drivers/net/ethernet/xscale/ixp2000/ixp2400-msf.c
index f5ffd7e05d26..f5ffd7e05d26 100644
--- a/drivers/net/ixp2000/ixp2400-msf.c
+++ b/drivers/net/ethernet/xscale/ixp2000/ixp2400-msf.c
diff --git a/drivers/net/ixp2000/ixp2400-msf.h b/drivers/net/ethernet/xscale/ixp2000/ixp2400-msf.h
index 3ac1af2771da..3ac1af2771da 100644
--- a/drivers/net/ixp2000/ixp2400-msf.h
+++ b/drivers/net/ethernet/xscale/ixp2000/ixp2400-msf.h
diff --git a/drivers/net/ixp2000/ixp2400_rx.uc b/drivers/net/ethernet/xscale/ixp2000/ixp2400_rx.uc
index 42a73e357afa..42a73e357afa 100644
--- a/drivers/net/ixp2000/ixp2400_rx.uc
+++ b/drivers/net/ethernet/xscale/ixp2000/ixp2400_rx.uc
diff --git a/drivers/net/ixp2000/ixp2400_rx.ucode b/drivers/net/ethernet/xscale/ixp2000/ixp2400_rx.ucode
index e8aee2f81aad..e8aee2f81aad 100644
--- a/drivers/net/ixp2000/ixp2400_rx.ucode
+++ b/drivers/net/ethernet/xscale/ixp2000/ixp2400_rx.ucode
diff --git a/drivers/net/ixp2000/ixp2400_tx.uc b/drivers/net/ethernet/xscale/ixp2000/ixp2400_tx.uc
index d090d1884fb7..d090d1884fb7 100644
--- a/drivers/net/ixp2000/ixp2400_tx.uc
+++ b/drivers/net/ethernet/xscale/ixp2000/ixp2400_tx.uc
diff --git a/drivers/net/ixp2000/ixp2400_tx.ucode b/drivers/net/ethernet/xscale/ixp2000/ixp2400_tx.ucode
index a433e24b0a51..a433e24b0a51 100644
--- a/drivers/net/ixp2000/ixp2400_tx.ucode
+++ b/drivers/net/ethernet/xscale/ixp2000/ixp2400_tx.ucode
diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ethernet/xscale/ixp2000/ixpdev.c
index e122493ab70e..e122493ab70e 100644
--- a/drivers/net/ixp2000/ixpdev.c
+++ b/drivers/net/ethernet/xscale/ixp2000/ixpdev.c
diff --git a/drivers/net/ixp2000/ixpdev.h b/drivers/net/ethernet/xscale/ixp2000/ixpdev.h
index 391ece623243..391ece623243 100644
--- a/drivers/net/ixp2000/ixpdev.h
+++ b/drivers/net/ethernet/xscale/ixp2000/ixpdev.h
diff --git a/drivers/net/ixp2000/ixpdev_priv.h b/drivers/net/ethernet/xscale/ixp2000/ixpdev_priv.h
index 86aa08ea0c33..86aa08ea0c33 100644
--- a/drivers/net/ixp2000/ixpdev_priv.h
+++ b/drivers/net/ethernet/xscale/ixp2000/ixpdev_priv.h
diff --git a/drivers/net/ixp2000/pm3386.c b/drivers/net/ethernet/xscale/ixp2000/pm3386.c
index e08d3f9863b8..e08d3f9863b8 100644
--- a/drivers/net/ixp2000/pm3386.c
+++ b/drivers/net/ethernet/xscale/ixp2000/pm3386.c
diff --git a/drivers/net/ixp2000/pm3386.h b/drivers/net/ethernet/xscale/ixp2000/pm3386.h
index cc4183dca911..cc4183dca911 100644
--- a/drivers/net/ixp2000/pm3386.h
+++ b/drivers/net/ethernet/xscale/ixp2000/pm3386.h
diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c
index de51e8453c13..ec96d910e9a3 100644
--- a/drivers/net/arm/ixp4xx_eth.c
+++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c
@@ -1339,7 +1339,7 @@ static const struct net_device_ops ixp4xx_netdev_ops = {
.ndo_open = eth_open,
.ndo_stop = eth_close,
.ndo_start_xmit = eth_xmit,
- .ndo_set_multicast_list = eth_set_mcast_list,
+ .ndo_set_rx_mode = eth_set_mcast_list,
.ndo_do_ioctl = eth_ioctl,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/fddi/Kconfig b/drivers/net/fddi/Kconfig
new file mode 100644
index 000000000000..3a424c864f4d
--- /dev/null
+++ b/drivers/net/fddi/Kconfig
@@ -0,0 +1,77 @@
+#
+# FDDI network device configuration
+#
+
+config FDDI
+ tristate "FDDI driver support"
+ depends on PCI || EISA || TC
+ ---help---
+ Fiber Distributed Data Interface is a high speed local area network
+ design; essentially a replacement for high speed Ethernet. FDDI can
+ run over copper or fiber. If you are connected to such a network and
+ want a driver for the FDDI card in your computer, say Y here (and
+ then also Y to the driver for your FDDI card, below). Most people
+ will say N.
+
+if FDDI
+
+config DEFXX
+ tristate "Digital DEFTA/DEFEA/DEFPA adapter support"
+ depends on FDDI && (PCI || EISA || TC)
+ ---help---
+ This is support for the DIGITAL series of TURBOchannel (DEFTA),
+ EISA (DEFEA) and PCI (DEFPA) controllers which can connect you
+ to a local FDDI network.
+
+ To compile this driver as a module, choose M here: the module
+ will be called defxx. If unsure, say N.
+
+config DEFXX_MMIO
+ bool
+ prompt "Use MMIO instead of PIO" if PCI || EISA
+ depends on DEFXX
+ default n if PCI || EISA
+ default y
+ ---help---
+ This instructs the driver to use EISA or PCI memory-mapped I/O
+ (MMIO) as appropriate instead of programmed I/O ports (PIO).
+ Enabling this gives an improvement in processing time in parts
+ of the driver, but it may cause problems with EISA (DEFEA)
+ adapters. TURBOchannel does not have the concept of I/O ports,
+ so MMIO is always used for these (DEFTA) adapters.
+
+ If unsure, say N.
+
+config SKFP
+ tristate "SysKonnect FDDI PCI support"
+ depends on FDDI && PCI
+ select BITREVERSE
+ ---help---
+ Say Y here if you have a SysKonnect FDDI PCI adapter.
+ The following adapters are supported by this driver:
+ - SK-5521 (SK-NET FDDI-UP)
+ - SK-5522 (SK-NET FDDI-UP DAS)
+ - SK-5541 (SK-NET FDDI-FP)
+ - SK-5543 (SK-NET FDDI-LP)
+ - SK-5544 (SK-NET FDDI-LP DAS)
+ - SK-5821 (SK-NET FDDI-UP64)
+ - SK-5822 (SK-NET FDDI-UP64 DAS)
+ - SK-5841 (SK-NET FDDI-FP64)
+ - SK-5843 (SK-NET FDDI-LP64)
+ - SK-5844 (SK-NET FDDI-LP64 DAS)
+ - Netelligent 100 FDDI DAS Fibre SC
+ - Netelligent 100 FDDI SAS Fibre SC
+ - Netelligent 100 FDDI DAS UTP
+ - Netelligent 100 FDDI SAS UTP
+ - Netelligent 100 FDDI SAS Fibre MIC
+
+ Read <file:Documentation/networking/skfp.txt> for information about
+ the driver.
+
+ Questions concerning this driver can be addressed to:
+ <linux@syskonnect.de>
+
+ To compile this driver as a module, choose M here: the module
+ will be called skfp. This is recommended.
+
+endif # FDDI
diff --git a/drivers/net/fddi/Makefile b/drivers/net/fddi/Makefile
new file mode 100644
index 000000000000..36da19c9a8aa
--- /dev/null
+++ b/drivers/net/fddi/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the Linux FDDI network device drivers.
+#
+
+obj-$(CONFIG_DEFXX) += defxx.o
+obj-$(CONFIG_SKFP) += skfp/
diff --git a/drivers/net/defxx.c b/drivers/net/fddi/defxx.c
index 417e14385623..4ad80f771099 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/fddi/defxx.c
@@ -483,7 +483,7 @@ static const struct net_device_ops dfx_netdev_ops = {
.ndo_stop = dfx_close,
.ndo_start_xmit = dfx_xmt_queue_pkt,
.ndo_get_stats = dfx_ctl_get_stats,
- .ndo_set_multicast_list = dfx_ctl_set_multicast_list,
+ .ndo_set_rx_mode = dfx_ctl_set_multicast_list,
.ndo_set_mac_address = dfx_ctl_set_mac_address,
};
diff --git a/drivers/net/defxx.h b/drivers/net/fddi/defxx.h
index 19a6f64df198..19a6f64df198 100644
--- a/drivers/net/defxx.h
+++ b/drivers/net/fddi/defxx.h
diff --git a/drivers/net/skfp/Makefile b/drivers/net/fddi/skfp/Makefile
index b0be0234abf6..b0be0234abf6 100644
--- a/drivers/net/skfp/Makefile
+++ b/drivers/net/fddi/skfp/Makefile
diff --git a/drivers/net/skfp/cfm.c b/drivers/net/fddi/skfp/cfm.c
index e395ace3120b..e395ace3120b 100644
--- a/drivers/net/skfp/cfm.c
+++ b/drivers/net/fddi/skfp/cfm.c
diff --git a/drivers/net/skfp/drvfbi.c b/drivers/net/fddi/skfp/drvfbi.c
index 07da97c303d6..07da97c303d6 100644
--- a/drivers/net/skfp/drvfbi.c
+++ b/drivers/net/fddi/skfp/drvfbi.c
diff --git a/drivers/net/skfp/ecm.c b/drivers/net/fddi/skfp/ecm.c
index 47d922cb3c08..47d922cb3c08 100644
--- a/drivers/net/skfp/ecm.c
+++ b/drivers/net/fddi/skfp/ecm.c
diff --git a/drivers/net/skfp/ess.c b/drivers/net/fddi/skfp/ess.c
index 2fc5987b41dc..2fc5987b41dc 100644
--- a/drivers/net/skfp/ess.c
+++ b/drivers/net/fddi/skfp/ess.c
diff --git a/drivers/net/skfp/fplustm.c b/drivers/net/fddi/skfp/fplustm.c
index a20ed1a98099..a20ed1a98099 100644
--- a/drivers/net/skfp/fplustm.c
+++ b/drivers/net/fddi/skfp/fplustm.c
diff --git a/drivers/net/skfp/h/cmtdef.h b/drivers/net/fddi/skfp/h/cmtdef.h
index 5a6c6122ccb0..f5bc90ff2a2a 100644
--- a/drivers/net/skfp/h/cmtdef.h
+++ b/drivers/net/fddi/skfp/h/cmtdef.h
@@ -477,8 +477,8 @@ struct s_plc {
/*
* function prototypes
*/
-#include "h/mbuf.h" /* Type definitions for MBUFs */
-#include "h/smtstate.h" /* struct smt_state */
+#include "mbuf.h" /* Type definitions for MBUFs */
+#include "smtstate.h" /* struct smt_state */
void hwt_restart(struct s_smc *smc); /* hwt.c */
SMbuf *smt_build_frame(struct s_smc *smc, int class, int type,
diff --git a/drivers/net/skfp/h/fddi.h b/drivers/net/fddi/skfp/h/fddi.h
index c9a28a8a383b..c9a28a8a383b 100644
--- a/drivers/net/skfp/h/fddi.h
+++ b/drivers/net/fddi/skfp/h/fddi.h
diff --git a/drivers/net/skfp/h/fddimib.h b/drivers/net/fddi/skfp/h/fddimib.h
index d1acdc773950..d1acdc773950 100644
--- a/drivers/net/skfp/h/fddimib.h
+++ b/drivers/net/fddi/skfp/h/fddimib.h
diff --git a/drivers/net/skfp/h/fplustm.h b/drivers/net/fddi/skfp/h/fplustm.h
index d43191ed938b..d43191ed938b 100644
--- a/drivers/net/skfp/h/fplustm.h
+++ b/drivers/net/fddi/skfp/h/fplustm.h
diff --git a/drivers/net/skfp/h/hwmtm.h b/drivers/net/fddi/skfp/h/hwmtm.h
index e1a7e5f683dc..5924d4219e9e 100644
--- a/drivers/net/skfp/h/hwmtm.h
+++ b/drivers/net/fddi/skfp/h/hwmtm.h
@@ -15,7 +15,7 @@
#ifndef _HWM_
#define _HWM_
-#include "h/mbuf.h"
+#include "mbuf.h"
/*
* MACRO for DMA synchronization:
diff --git a/drivers/net/skfp/h/mbuf.h b/drivers/net/fddi/skfp/h/mbuf.h
index f2aadcda9e7f..f2aadcda9e7f 100644
--- a/drivers/net/skfp/h/mbuf.h
+++ b/drivers/net/fddi/skfp/h/mbuf.h
diff --git a/drivers/net/skfp/h/osdef1st.h b/drivers/net/fddi/skfp/h/osdef1st.h
index 763ca18cbea8..763ca18cbea8 100644
--- a/drivers/net/skfp/h/osdef1st.h
+++ b/drivers/net/fddi/skfp/h/osdef1st.h
diff --git a/drivers/net/skfp/h/sba.h b/drivers/net/fddi/skfp/h/sba.h
index 638cf0283bc4..35ddb44a1120 100644
--- a/drivers/net/skfp/h/sba.h
+++ b/drivers/net/fddi/skfp/h/sba.h
@@ -19,8 +19,8 @@
#ifndef _SBA_
#define _SBA_
-#include "h/mbuf.h"
-#include "h/sba_def.h"
+#include "mbuf.h"
+#include "sba_def.h"
#ifdef SBA
diff --git a/drivers/net/skfp/h/sba_def.h b/drivers/net/fddi/skfp/h/sba_def.h
index 0459a095d0cd..0459a095d0cd 100644
--- a/drivers/net/skfp/h/sba_def.h
+++ b/drivers/net/fddi/skfp/h/sba_def.h
diff --git a/drivers/net/skfp/h/skfbi.h b/drivers/net/fddi/skfp/h/skfbi.h
index c1ba26c06d73..c1ba26c06d73 100644
--- a/drivers/net/skfp/h/skfbi.h
+++ b/drivers/net/fddi/skfp/h/skfbi.h
diff --git a/drivers/net/skfp/h/skfbiinc.h b/drivers/net/fddi/skfp/h/skfbiinc.h
index ac2d7192f1ca..ce72557c354c 100644
--- a/drivers/net/skfp/h/skfbiinc.h
+++ b/drivers/net/fddi/skfp/h/skfbiinc.h
@@ -15,7 +15,7 @@
#ifndef _SKFBIINC_
#define _SKFBIINC_
-#include "h/supern_2.h"
+#include "supern_2.h"
/*
* special defines for use into .asm files
diff --git a/drivers/net/skfp/h/smc.h b/drivers/net/fddi/skfp/h/smc.h
index c774a95902f5..3ca308b28214 100644
--- a/drivers/net/skfp/h/smc.h
+++ b/drivers/net/fddi/skfp/h/smc.h
@@ -38,18 +38,18 @@
* fddi.h
*/
#ifdef OSDEF
-#include "h/osdef1st.h"
+#include "osdef1st.h"
#endif /* OSDEF */
#ifdef OEM_CONCEPT
#include "oemdef.h"
#endif /* OEM_CONCEPT */
-#include "h/smt.h"
-#include "h/cmtdef.h"
-#include "h/fddimib.h"
-#include "h/targethw.h" /* all target hw dependencies */
-#include "h/targetos.h" /* all target os dependencies */
+#include "smt.h"
+#include "cmtdef.h"
+#include "fddimib.h"
+#include "targethw.h" /* all target hw dependencies */
+#include "targetos.h" /* all target os dependencies */
#ifdef ESS
-#include "h/sba.h"
+#include "sba.h"
#endif
/*
diff --git a/drivers/net/skfp/h/smt.h b/drivers/net/fddi/skfp/h/smt.h
index 2030f9cbb24b..2030f9cbb24b 100644
--- a/drivers/net/skfp/h/smt.h
+++ b/drivers/net/fddi/skfp/h/smt.h
diff --git a/drivers/net/skfp/h/smt_p.h b/drivers/net/fddi/skfp/h/smt_p.h
index 99f9be9552bb..99f9be9552bb 100644
--- a/drivers/net/skfp/h/smt_p.h
+++ b/drivers/net/fddi/skfp/h/smt_p.h
diff --git a/drivers/net/skfp/h/smtstate.h b/drivers/net/fddi/skfp/h/smtstate.h
index 62fe695077a9..62fe695077a9 100644
--- a/drivers/net/skfp/h/smtstate.h
+++ b/drivers/net/fddi/skfp/h/smtstate.h
diff --git a/drivers/net/skfp/h/supern_2.h b/drivers/net/fddi/skfp/h/supern_2.h
index 0b73690280f6..0b73690280f6 100644
--- a/drivers/net/skfp/h/supern_2.h
+++ b/drivers/net/fddi/skfp/h/supern_2.h
diff --git a/drivers/net/skfp/h/targethw.h b/drivers/net/fddi/skfp/h/targethw.h
index 626dc7263591..842a690446f3 100644
--- a/drivers/net/skfp/h/targethw.h
+++ b/drivers/net/fddi/skfp/h/targethw.h
@@ -25,11 +25,11 @@
#define SK_ML_ID_2 0x30
#endif
-#include "h/skfbi.h"
+#include "skfbi.h"
#ifndef TAG_MODE
-#include "h/fplus.h"
+#include "fplus.h"
#else
-#include "h/fplustm.h"
+#include "fplustm.h"
#endif
#ifndef HW_PTR
diff --git a/drivers/net/skfp/h/targetos.h b/drivers/net/fddi/skfp/h/targetos.h
index 5d940e7b8ea0..53bacc107160 100644
--- a/drivers/net/skfp/h/targetos.h
+++ b/drivers/net/fddi/skfp/h/targetos.h
@@ -58,7 +58,7 @@
#define ADDR(a) (((a)>>7) ? (outp(smc->hw.iop+B0_RAP,(a)>>7), (smc->hw.iop+( ((a)&0x7F) | ((a)>>7 ? 0x80:0)) )) : (smc->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0))))
#endif
-#include "h/hwmtm.h"
+#include "hwmtm.h"
#define TRUE 1
#define FALSE 0
diff --git a/drivers/net/skfp/h/types.h b/drivers/net/fddi/skfp/h/types.h
index 5a3bf8378f9e..5a3bf8378f9e 100644
--- a/drivers/net/skfp/h/types.h
+++ b/drivers/net/fddi/skfp/h/types.h
diff --git a/drivers/net/skfp/hwmtm.c b/drivers/net/fddi/skfp/hwmtm.c
index e26398b5a7dc..e26398b5a7dc 100644
--- a/drivers/net/skfp/hwmtm.c
+++ b/drivers/net/fddi/skfp/hwmtm.c
diff --git a/drivers/net/skfp/hwt.c b/drivers/net/fddi/skfp/hwt.c
index c0798fd2ca69..c0798fd2ca69 100644
--- a/drivers/net/skfp/hwt.c
+++ b/drivers/net/fddi/skfp/hwt.c
diff --git a/drivers/net/skfp/pcmplc.c b/drivers/net/fddi/skfp/pcmplc.c
index 88d02d0a42c4..88d02d0a42c4 100644
--- a/drivers/net/skfp/pcmplc.c
+++ b/drivers/net/fddi/skfp/pcmplc.c
diff --git a/drivers/net/skfp/pmf.c b/drivers/net/fddi/skfp/pmf.c
index 9ac4665d7411..9ac4665d7411 100644
--- a/drivers/net/skfp/pmf.c
+++ b/drivers/net/fddi/skfp/pmf.c
diff --git a/drivers/net/skfp/queue.c b/drivers/net/fddi/skfp/queue.c
index c1a0df455a59..c1a0df455a59 100644
--- a/drivers/net/skfp/queue.c
+++ b/drivers/net/fddi/skfp/queue.c
diff --git a/drivers/net/skfp/rmt.c b/drivers/net/fddi/skfp/rmt.c
index ef8d5672d9e8..ef8d5672d9e8 100644
--- a/drivers/net/skfp/rmt.c
+++ b/drivers/net/fddi/skfp/rmt.c
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/fddi/skfp/skfddi.c
index 16c62659cdd9..3d9a4596a423 100644
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/fddi/skfp/skfddi.c
@@ -167,7 +167,7 @@ static const struct net_device_ops skfp_netdev_ops = {
.ndo_start_xmit = skfp_send_pkt,
.ndo_get_stats = skfp_ctl_get_stats,
.ndo_change_mtu = fddi_change_mtu,
- .ndo_set_multicast_list = skfp_ctl_set_multicast_list,
+ .ndo_set_rx_mode = skfp_ctl_set_multicast_list,
.ndo_set_mac_address = skfp_ctl_set_mac_address,
.ndo_do_ioctl = skfp_ioctl,
};
diff --git a/drivers/net/skfp/smt.c b/drivers/net/fddi/skfp/smt.c
index 08d94329c12f..08d94329c12f 100644
--- a/drivers/net/skfp/smt.c
+++ b/drivers/net/fddi/skfp/smt.c
diff --git a/drivers/net/skfp/smtdef.c b/drivers/net/fddi/skfp/smtdef.c
index 1acab0b368e3..1acab0b368e3 100644
--- a/drivers/net/skfp/smtdef.c
+++ b/drivers/net/fddi/skfp/smtdef.c
diff --git a/drivers/net/skfp/smtinit.c b/drivers/net/fddi/skfp/smtinit.c
index e3a0c0bc2233..e3a0c0bc2233 100644
--- a/drivers/net/skfp/smtinit.c
+++ b/drivers/net/fddi/skfp/smtinit.c
diff --git a/drivers/net/skfp/smttimer.c b/drivers/net/fddi/skfp/smttimer.c
index 531795e98c30..531795e98c30 100644
--- a/drivers/net/skfp/smttimer.c
+++ b/drivers/net/fddi/skfp/smttimer.c
diff --git a/drivers/net/skfp/srf.c b/drivers/net/fddi/skfp/srf.c
index f6f7baf9f27a..f6f7baf9f27a 100644
--- a/drivers/net/skfp/srf.c
+++ b/drivers/net/fddi/skfp/srf.c
diff --git a/drivers/net/hippi/Kconfig b/drivers/net/hippi/Kconfig
new file mode 100644
index 000000000000..7393eb732ee6
--- /dev/null
+++ b/drivers/net/hippi/Kconfig
@@ -0,0 +1,39 @@
+#
+# HIPPI network device configuration
+#
+
+config HIPPI
+ bool "HIPPI driver support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && INET && PCI
+ ---help---
+ HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and
+ 1600Mbit/sec dual-simplex switched or point-to-point network. HIPPI
+ can run over copper (25m) or fiber (300m on multi-mode or 10km on
+ single-mode). HIPPI networks are commonly used for clusters and to
+ connect to super computers. If you are connected to a HIPPI network
+ and have a HIPPI network card in your computer that you want to use
+ under Linux, say Y here (you must also remember to enable the driver
+ for your HIPPI card below). Most people will say N here.
+
+if HIPPI
+
+config ROADRUNNER
+ tristate "Essential RoadRunner HIPPI PCI adapter support (EXPERIMENTAL)"
+ depends on PCI
+ ---help---
+ Say Y here if this is your PCI HIPPI network card.
+
+ To compile this driver as a module, choose M here: the module
+ will be called rrunner. If unsure, say N.
+
+config ROADRUNNER_LARGE_RINGS
+ bool "Use large TX/RX rings (EXPERIMENTAL)"
+ depends on ROADRUNNER
+ ---help---
+ If you say Y here, the RoadRunner driver will preallocate up to 2 MB
+ of additional memory to allow for fastest operation, both for
+ transmitting and receiving. This memory cannot be used by any other
+ kernel code or by user space programs. Say Y here only if you have
+ the memory.
+
+endif /* HIPPI */
diff --git a/drivers/net/hippi/Makefile b/drivers/net/hippi/Makefile
new file mode 100644
index 000000000000..b95d629baee5
--- /dev/null
+++ b/drivers/net/hippi/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the HIPPI network device drivers.
+#
+
+obj-$(CONFIG_ROADRUNNER) += rrunner.o
diff --git a/drivers/net/rrunner.c b/drivers/net/hippi/rrunner.c
index e68c941926f1..e68c941926f1 100644
--- a/drivers/net/rrunner.c
+++ b/drivers/net/hippi/rrunner.c
diff --git a/drivers/net/rrunner.h b/drivers/net/hippi/rrunner.h
index 28169043ae49..28169043ae49 100644
--- a/drivers/net/rrunner.h
+++ b/drivers/net/hippi/rrunner.h
diff --git a/drivers/net/ibm_newemac/Makefile b/drivers/net/ibm_newemac/Makefile
deleted file mode 100644
index 0b5c99512762..000000000000
--- a/drivers/net/ibm_newemac/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# Makefile for the PowerPC 4xx on-chip ethernet driver
-#
-
-obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac.o
-
-ibm_newemac-y := mal.o core.o phy.o
-ibm_newemac-$(CONFIG_IBM_NEW_EMAC_ZMII) += zmii.o
-ibm_newemac-$(CONFIG_IBM_NEW_EMAC_RGMII) += rgmii.o
-ibm_newemac-$(CONFIG_IBM_NEW_EMAC_TAH) += tah.o
-ibm_newemac-$(CONFIG_IBM_NEW_EMAC_DEBUG) += debug.o
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index 25bb2a015e18..a40fab44b9ae 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -183,7 +183,7 @@ config OLD_BELKIN_DONGLE
Say Y here if you want to build support for the Adaptec Airport 1000
and 2000 dongles. If you want to compile it as a module, choose
M here. Some information is contained in the comments
- at the top of <file:drivers/net/irda/old_belkin.c>.
+ at the top of <file:drivers/net/irda/old_belkin-sir.c>.
config ACT200L_DONGLE
tristate "ACTiSYS IR-200L dongle"
diff --git a/drivers/net/irda/sh_irda.c b/drivers/net/irda/sh_irda.c
index 82660672dcd9..d275e276e742 100644
--- a/drivers/net/irda/sh_irda.c
+++ b/drivers/net/irda/sh_irda.c
@@ -2,7 +2,7 @@
* SuperH IrDA Driver
*
* Copyright (C) 2010 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*
* Based on sh_sir.c
* Copyright (C) 2009 Renesas Solutions Corp.
@@ -26,6 +26,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/clk.h>
#include <net/irda/wrapper.h>
#include <net/irda/irda_device.h>
@@ -144,8 +145,8 @@ struct sh_irda_xir_func {
struct sh_irda_self {
void __iomem *membase;
- unsigned int irq;
- struct clk *clk;
+ unsigned int irq;
+ struct platform_device *pdev;
struct net_device *ndev;
@@ -264,7 +265,7 @@ static int sh_irda_set_baudrate(struct sh_irda_self *self, int baudrate)
return 0;
}
-static int xir_get_rcv_length(struct sh_irda_self *self)
+static int sh_irda_get_rcv_length(struct sh_irda_self *self)
{
return RFL_MASK & sh_irda_read(self, IRRFLR);
}
@@ -274,47 +275,47 @@ static int xir_get_rcv_length(struct sh_irda_self *self)
* NONE MODE
*
*=====================================*/
-static int xir_fre(struct sh_irda_self *self)
+static int sh_irda_xir_fre(struct sh_irda_self *self)
{
struct device *dev = &self->ndev->dev;
dev_err(dev, "none mode: frame recv\n");
return 0;
}
-static int xir_trov(struct sh_irda_self *self)
+static int sh_irda_xir_trov(struct sh_irda_self *self)
{
struct device *dev = &self->ndev->dev;
dev_err(dev, "none mode: buffer ram over\n");
return 0;
}
-static int xir_9(struct sh_irda_self *self)
+static int sh_irda_xir_9(struct sh_irda_self *self)
{
struct device *dev = &self->ndev->dev;
dev_err(dev, "none mode: time over\n");
return 0;
}
-static int xir_8(struct sh_irda_self *self)
+static int sh_irda_xir_8(struct sh_irda_self *self)
{
struct device *dev = &self->ndev->dev;
dev_err(dev, "none mode: framing error\n");
return 0;
}
-static int xir_fte(struct sh_irda_self *self)
+static int sh_irda_xir_fte(struct sh_irda_self *self)
{
struct device *dev = &self->ndev->dev;
dev_err(dev, "none mode: frame transmit end\n");
return 0;
}
-static struct sh_irda_xir_func xir_func = {
- .xir_fre = xir_fre,
- .xir_trov = xir_trov,
- .xir_9 = xir_9,
- .xir_8 = xir_8,
- .xir_fte = xir_fte,
+static struct sh_irda_xir_func sh_irda_xir_func = {
+ .xir_fre = sh_irda_xir_fre,
+ .xir_trov = sh_irda_xir_trov,
+ .xir_9 = sh_irda_xir_9,
+ .xir_8 = sh_irda_xir_8,
+ .xir_fte = sh_irda_xir_fte,
};
/*=====================================
@@ -323,12 +324,12 @@ static struct sh_irda_xir_func xir_func = {
*
* MIR/FIR are not supported now
*=====================================*/
-static struct sh_irda_xir_func mfir_func = {
- .xir_fre = xir_fre,
- .xir_trov = xir_trov,
- .xir_9 = xir_9,
- .xir_8 = xir_8,
- .xir_fte = xir_fte,
+static struct sh_irda_xir_func sh_irda_mfir_func = {
+ .xir_fre = sh_irda_xir_fre,
+ .xir_trov = sh_irda_xir_trov,
+ .xir_9 = sh_irda_xir_9,
+ .xir_8 = sh_irda_xir_8,
+ .xir_fte = sh_irda_xir_fte,
};
/*=====================================
@@ -336,12 +337,12 @@ static struct sh_irda_xir_func mfir_func = {
* SIR MODE
*
*=====================================*/
-static int sir_fre(struct sh_irda_self *self)
+static int sh_irda_sir_fre(struct sh_irda_self *self)
{
struct device *dev = &self->ndev->dev;
u16 data16;
u8 *data = (u8 *)&data16;
- int len = xir_get_rcv_length(self);
+ int len = sh_irda_get_rcv_length(self);
int i, j;
if (len > IRDARAM_LEN)
@@ -364,7 +365,7 @@ static int sir_fre(struct sh_irda_self *self)
return 0;
}
-static int sir_trov(struct sh_irda_self *self)
+static int sh_irda_sir_trov(struct sh_irda_self *self)
{
struct device *dev = &self->ndev->dev;
@@ -373,7 +374,7 @@ static int sir_trov(struct sh_irda_self *self)
return 0;
}
-static int sir_tot(struct sh_irda_self *self)
+static int sh_irda_sir_tot(struct sh_irda_self *self)
{
struct device *dev = &self->ndev->dev;
@@ -383,7 +384,7 @@ static int sir_tot(struct sh_irda_self *self)
return 0;
}
-static int sir_fer(struct sh_irda_self *self)
+static int sh_irda_sir_fer(struct sh_irda_self *self)
{
struct device *dev = &self->ndev->dev;
@@ -392,7 +393,7 @@ static int sir_fer(struct sh_irda_self *self)
return 0;
}
-static int sir_fte(struct sh_irda_self *self)
+static int sh_irda_sir_fte(struct sh_irda_self *self)
{
struct device *dev = &self->ndev->dev;
@@ -402,12 +403,12 @@ static int sir_fte(struct sh_irda_self *self)
return 0;
}
-static struct sh_irda_xir_func sir_func = {
- .xir_fre = sir_fre,
- .xir_trov = sir_trov,
- .xir_9 = sir_tot,
- .xir_8 = sir_fer,
- .xir_fte = sir_fte,
+static struct sh_irda_xir_func sh_irda_sir_func = {
+ .xir_fre = sh_irda_sir_fre,
+ .xir_trov = sh_irda_sir_trov,
+ .xir_9 = sh_irda_sir_tot,
+ .xir_8 = sh_irda_sir_fer,
+ .xir_fte = sh_irda_sir_fte,
};
static void sh_irda_set_mode(struct sh_irda_self *self, enum sh_irda_mode mode)
@@ -421,22 +422,22 @@ static void sh_irda_set_mode(struct sh_irda_self *self, enum sh_irda_mode mode)
case SH_IRDA_SIR:
name = "SIR";
data = TMD_SIR;
- func = &sir_func;
+ func = &sh_irda_sir_func;
break;
case SH_IRDA_MIR:
name = "MIR";
data = TMD_MIR;
- func = &mfir_func;
+ func = &sh_irda_mfir_func;
break;
case SH_IRDA_FIR:
name = "FIR";
data = TMD_FIR;
- func = &mfir_func;
+ func = &sh_irda_mfir_func;
break;
default:
- name = "NONE";
- data = 0;
- func = &xir_func;
+ name = "NONE";
+ data = 0;
+ func = &sh_irda_xir_func;
break;
}
@@ -694,7 +695,7 @@ static int sh_irda_open(struct net_device *ndev)
struct sh_irda_self *self = netdev_priv(ndev);
int err;
- clk_enable(self->clk);
+ pm_runtime_get_sync(&self->pdev->dev);
err = sh_irda_crc_init(self);
if (err)
goto open_err;
@@ -718,7 +719,7 @@ static int sh_irda_open(struct net_device *ndev)
return 0;
open_err:
- clk_disable(self->clk);
+ pm_runtime_put_sync(&self->pdev->dev);
return err;
}
@@ -734,6 +735,7 @@ static int sh_irda_stop(struct net_device *ndev)
}
netif_stop_queue(ndev);
+ pm_runtime_put_sync(&self->pdev->dev);
dev_info(&ndev->dev, "stoped\n");
@@ -786,11 +788,8 @@ static int __devinit sh_irda_probe(struct platform_device *pdev)
if (err)
goto err_mem_2;
- self->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(self->clk)) {
- dev_err(&pdev->dev, "cannot get irda clock\n");
- goto err_mem_3;
- }
+ self->pdev = pdev;
+ pm_runtime_enable(&pdev->dev);
irda_init_max_qos_capabilies(&self->qos);
@@ -820,8 +819,7 @@ static int __devinit sh_irda_probe(struct platform_device *pdev)
goto exit;
err_mem_4:
- clk_put(self->clk);
-err_mem_3:
+ pm_runtime_disable(&pdev->dev);
sh_irda_remove_iobuf(self);
err_mem_2:
iounmap(self->membase);
@@ -840,7 +838,7 @@ static int __devexit sh_irda_remove(struct platform_device *pdev)
return 0;
unregister_netdev(ndev);
- clk_put(self->clk);
+ pm_runtime_disable(&pdev->dev);
sh_irda_remove_iobuf(self);
iounmap(self->membase);
free_netdev(ndev);
@@ -849,11 +847,29 @@ static int __devexit sh_irda_remove(struct platform_device *pdev)
return 0;
}
+static int sh_irda_runtime_nop(struct device *dev)
+{
+ /* Runtime PM callback shared between ->runtime_suspend()
+ * and ->runtime_resume(). Simply returns success.
+ *
+ * This driver re-initializes all registers after
+ * pm_runtime_get_sync() anyway so there is no need
+ * to save and restore registers here.
+ */
+ return 0;
+}
+
+static const struct dev_pm_ops sh_irda_pm_ops = {
+ .runtime_suspend = sh_irda_runtime_nop,
+ .runtime_resume = sh_irda_runtime_nop,
+};
+
static struct platform_driver sh_irda_driver = {
- .probe = sh_irda_probe,
- .remove = __devexit_p(sh_irda_remove),
- .driver = {
- .name = DRIVER_NAME,
+ .probe = sh_irda_probe,
+ .remove = __devexit_p(sh_irda_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ .pm = &sh_irda_pm_ops,
},
};
@@ -870,6 +886,6 @@ static void __exit sh_irda_exit(void)
module_init(sh_irda_init);
module_exit(sh_irda_exit);
-MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
MODULE_DESCRIPTION("SuperH IrDA driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 05172c39a0ce..a3ce3d4561ed 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -169,6 +169,9 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
port = macvlan_port_get_rcu(skb->dev);
if (is_multicast_ether_addr(eth->h_dest)) {
+ skb = ip_check_defrag(skb, IP_DEFRAG_MACVLAN);
+ if (!skb)
+ return RX_HANDLER_CONSUMED;
src = macvlan_hash_lookup(port, eth->h_source);
if (!src)
/* frame comes from an external address */
@@ -239,7 +242,7 @@ static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
dest = macvlan_hash_lookup(port, eth->h_dest);
if (dest && dest->mode == MACVLAN_MODE_BRIDGE) {
/* send to lowerdev first for its network taps */
- vlan->forward(vlan->lowerdev, skb);
+ dev_forward_skb(vlan->lowerdev, skb);
return NET_XMIT_SUCCESS;
}
@@ -543,7 +546,8 @@ static int macvlan_ethtool_get_settings(struct net_device *dev,
struct ethtool_cmd *cmd)
{
const struct macvlan_dev *vlan = netdev_priv(dev);
- return dev_ethtool_get_settings(vlan->lowerdev, cmd);
+
+ return __ethtool_get_settings(vlan->lowerdev, cmd);
}
static const struct ethtool_ops macvlan_ethtool_ops = {
@@ -561,7 +565,7 @@ static const struct net_device_ops macvlan_netdev_ops = {
.ndo_change_mtu = macvlan_change_mtu,
.ndo_change_rx_flags = macvlan_change_rx_flags,
.ndo_set_mac_address = macvlan_set_mac_address,
- .ndo_set_multicast_list = macvlan_set_multicast_list,
+ .ndo_set_rx_mode = macvlan_set_multicast_list,
.ndo_get_stats64 = macvlan_dev_get_stats64,
.ndo_validate_addr = eth_validate_addr,
.ndo_vlan_rx_add_vid = macvlan_vlan_rx_add_vid,
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index ab96c319a240..1b7082d08f33 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -51,15 +51,13 @@ static struct proto macvtap_proto = {
};
/*
- * Minor number matches netdev->ifindex, so need a potentially
- * large value. This also makes it possible to split the
- * tap functionality out again in the future by offering it
- * from other drivers besides macvtap. As long as every device
- * only has one tap, the interface numbers assure that the
- * device nodes are unique.
+ * Variables for dealing with macvtaps device numbers.
*/
static dev_t macvtap_major;
-#define MACVTAP_NUM_DEVS 65536
+#define MACVTAP_NUM_DEVS (1U << MINORBITS)
+static DEFINE_MUTEX(minor_lock);
+static DEFINE_IDR(minor_idr);
+
#define GOODCOPY_LEN 128
static struct class *macvtap_class;
static struct cdev macvtap_cdev;
@@ -231,6 +229,8 @@ static void macvtap_del_queues(struct net_device *dev)
}
}
BUG_ON(vlan->numvtaps != 0);
+ /* guarantee that any future macvtap_set_queue will fail */
+ vlan->numvtaps = MAX_MACVTAP_QUEUES;
spin_unlock(&macvtap_lock);
synchronize_rcu();
@@ -273,39 +273,73 @@ static int macvtap_receive(struct sk_buff *skb)
return macvtap_forward(skb->dev, skb);
}
-static int macvtap_newlink(struct net *src_net,
- struct net_device *dev,
- struct nlattr *tb[],
- struct nlattr *data[])
+static int macvtap_get_minor(struct macvlan_dev *vlan)
{
- struct device *classdev;
- dev_t devt;
- int err;
+ int retval = -ENOMEM;
+ int id;
+
+ mutex_lock(&minor_lock);
+ if (idr_pre_get(&minor_idr, GFP_KERNEL) == 0)
+ goto exit;
+
+ retval = idr_get_new_above(&minor_idr, vlan, 1, &id);
+ if (retval < 0) {
+ if (retval == -EAGAIN)
+ retval = -ENOMEM;
+ goto exit;
+ }
+ if (id < MACVTAP_NUM_DEVS) {
+ vlan->minor = id;
+ } else {
+ printk(KERN_ERR "too many macvtap devices\n");
+ retval = -EINVAL;
+ idr_remove(&minor_idr, id);
+ }
+exit:
+ mutex_unlock(&minor_lock);
+ return retval;
+}
- err = macvlan_common_newlink(src_net, dev, tb, data,
- macvtap_receive, macvtap_forward);
- if (err)
- goto out;
+static void macvtap_free_minor(struct macvlan_dev *vlan)
+{
+ mutex_lock(&minor_lock);
+ if (vlan->minor) {
+ idr_remove(&minor_idr, vlan->minor);
+ vlan->minor = 0;
+ }
+ mutex_unlock(&minor_lock);
+}
- devt = MKDEV(MAJOR(macvtap_major), dev->ifindex);
+static struct net_device *dev_get_by_macvtap_minor(int minor)
+{
+ struct net_device *dev = NULL;
+ struct macvlan_dev *vlan;
- classdev = device_create(macvtap_class, &dev->dev, devt,
- dev, "tap%d", dev->ifindex);
- if (IS_ERR(classdev)) {
- err = PTR_ERR(classdev);
- macvtap_del_queues(dev);
+ mutex_lock(&minor_lock);
+ vlan = idr_find(&minor_idr, minor);
+ if (vlan) {
+ dev = vlan->dev;
+ dev_hold(dev);
}
+ mutex_unlock(&minor_lock);
+ return dev;
+}
-out:
- return err;
+static int macvtap_newlink(struct net *src_net,
+ struct net_device *dev,
+ struct nlattr *tb[],
+ struct nlattr *data[])
+{
+ /* Don't put anything that may fail after macvlan_common_newlink
+ * because we can't undo what it does.
+ */
+ return macvlan_common_newlink(src_net, dev, tb, data,
+ macvtap_receive, macvtap_forward);
}
static void macvtap_dellink(struct net_device *dev,
struct list_head *head)
{
- device_destroy(macvtap_class,
- MKDEV(MAJOR(macvtap_major), dev->ifindex));
-
macvtap_del_queues(dev);
macvlan_dellink(dev, head);
}
@@ -337,11 +371,15 @@ static void macvtap_sock_write_space(struct sock *sk)
wake_up_interruptible_poll(wqueue, POLLOUT | POLLWRNORM | POLLWRBAND);
}
+static void macvtap_sock_destruct(struct sock *sk)
+{
+ skb_queue_purge(&sk->sk_receive_queue);
+}
+
static int macvtap_open(struct inode *inode, struct file *file)
{
struct net *net = current->nsproxy->net_ns;
- struct net_device *dev = dev_get_by_index(net, iminor(inode));
- struct macvlan_dev *vlan = netdev_priv(dev);
+ struct net_device *dev = dev_get_by_macvtap_minor(iminor(inode));
struct macvtap_queue *q;
int err;
@@ -349,11 +387,6 @@ static int macvtap_open(struct inode *inode, struct file *file)
if (!dev)
goto out;
- /* check if this is a macvtap device */
- err = -EINVAL;
- if (dev->rtnl_link_ops != &macvtap_link_ops)
- goto out;
-
err = -ENOMEM;
q = (struct macvtap_queue *)sk_alloc(net, AF_UNSPEC, GFP_KERNEL,
&macvtap_proto);
@@ -368,18 +401,19 @@ static int macvtap_open(struct inode *inode, struct file *file)
q->sock.ops = &macvtap_socket_ops;
sock_init_data(&q->sock, &q->sk);
q->sk.sk_write_space = macvtap_sock_write_space;
+ q->sk.sk_destruct = macvtap_sock_destruct;
q->flags = IFF_VNET_HDR | IFF_NO_PI | IFF_TAP;
q->vnet_hdr_sz = sizeof(struct virtio_net_hdr);
/*
* so far only KVM virtio_net uses macvtap, enable zero copy between
* guest kernel and host kernel when lower device supports zerocopy
+ *
+ * The macvlan supports zerocopy iff the lower device supports zero
+ * copy so we don't have to look at the lower device directly.
*/
- if (vlan) {
- if ((vlan->lowerdev->features & NETIF_F_HIGHDMA) &&
- (vlan->lowerdev->features & NETIF_F_SG))
- sock_set_flag(&q->sk, SOCK_ZEROCOPY);
- }
+ if ((dev->features & NETIF_F_HIGHDMA) && (dev->features & NETIF_F_SG))
+ sock_set_flag(&q->sk, SOCK_ZEROCOPY);
err = macvtap_set_queue(dev, file, q);
if (err)
@@ -453,7 +487,6 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from,
int copy = skb_headlen(skb);
int size, offset1 = 0;
int i = 0;
- skb_frag_t *f;
/* Skip over from offset */
while (count && (offset >= from->iov_len)) {
@@ -503,14 +536,13 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from,
skb->truesize += len;
atomic_add(len, &skb->sk->sk_wmem_alloc);
while (len) {
- f = &skb_shinfo(skb)->frags[i];
- f->page = page[i];
- f->page_offset = base & ~PAGE_MASK;
- f->size = min_t(int, len, PAGE_SIZE - f->page_offset);
+ int off = base & ~PAGE_MASK;
+ int size = min_t(int, len, PAGE_SIZE - off);
+ __skb_fill_page_desc(skb, i, page[i], off, size);
skb_shinfo(skb)->nr_frags++;
/* increase sk_wmem_alloc */
- base += f->size;
- len -= f->size;
+ base += size;
+ len -= size;
i++;
}
offset1 = 0;
@@ -970,6 +1002,52 @@ struct socket *macvtap_get_socket(struct file *file)
}
EXPORT_SYMBOL_GPL(macvtap_get_socket);
+static int macvtap_device_event(struct notifier_block *unused,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = ptr;
+ struct macvlan_dev *vlan;
+ struct device *classdev;
+ dev_t devt;
+ int err;
+
+ if (dev->rtnl_link_ops != &macvtap_link_ops)
+ return NOTIFY_DONE;
+
+ vlan = netdev_priv(dev);
+
+ switch (event) {
+ case NETDEV_REGISTER:
+ /* Create the device node here after the network device has
+ * been registered but before register_netdevice has
+ * finished running.
+ */
+ err = macvtap_get_minor(vlan);
+ if (err)
+ return notifier_from_errno(err);
+
+ devt = MKDEV(MAJOR(macvtap_major), vlan->minor);
+ classdev = device_create(macvtap_class, &dev->dev, devt,
+ dev, "tap%d", dev->ifindex);
+ if (IS_ERR(classdev)) {
+ macvtap_free_minor(vlan);
+ return notifier_from_errno(PTR_ERR(classdev));
+ }
+ break;
+ case NETDEV_UNREGISTER:
+ devt = MKDEV(MAJOR(macvtap_major), vlan->minor);
+ device_destroy(macvtap_class, devt);
+ macvtap_free_minor(vlan);
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block macvtap_notifier_block __read_mostly = {
+ .notifier_call = macvtap_device_event,
+};
+
static int macvtap_init(void)
{
int err;
@@ -990,12 +1068,18 @@ static int macvtap_init(void)
goto out3;
}
- err = macvlan_link_register(&macvtap_link_ops);
+ err = register_netdevice_notifier(&macvtap_notifier_block);
if (err)
goto out4;
+ err = macvlan_link_register(&macvtap_link_ops);
+ if (err)
+ goto out5;
+
return 0;
+out5:
+ unregister_netdevice_notifier(&macvtap_notifier_block);
out4:
class_unregister(macvtap_class);
out3:
@@ -1010,6 +1094,7 @@ module_init(macvtap_init);
static void macvtap_exit(void)
{
rtnl_link_unregister(&macvtap_link_ops);
+ unregister_netdevice_notifier(&macvtap_notifier_block);
class_unregister(macvtap_class);
cdev_del(&macvtap_cdev);
unregister_chrdev_region(macvtap_major, MACVTAP_NUM_DEVS);
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index dfc82720065a..e8882023576b 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -307,6 +307,11 @@ static ssize_t store_enabled(struct netconsole_target *nt,
return err;
if (enabled < 0 || enabled > 1)
return -EINVAL;
+ if (enabled == nt->enabled) {
+ printk(KERN_INFO "netconsole: network logging has already %s\n",
+ nt->enabled ? "started" : "stopped");
+ return -EINVAL;
+ }
if (enabled) { /* 1 */
@@ -799,5 +804,11 @@ static void __exit cleanup_netconsole(void)
}
}
-module_init(init_netconsole);
+/*
+ * Use late_initcall to ensure netconsole is
+ * initialized after network device driver if built-in.
+ *
+ * late_initcall() and module_init() are identical if built as module.
+ */
+late_initcall(init_netconsole);
module_exit(cleanup_netconsole);
diff --git a/drivers/net/octeon/Makefile b/drivers/net/octeon/Makefile
deleted file mode 100644
index 906edecacfd3..000000000000
--- a/drivers/net/octeon/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-
-obj-$(CONFIG_OCTEON_MGMT_ETHERNET) += octeon_mgmt.o
diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
deleted file mode 100644
index c0f23376a462..000000000000
--- a/drivers/net/pci-skeleton.c
+++ /dev/null
@@ -1,1923 +0,0 @@
-/*
-
- drivers/net/pci-skeleton.c
-
- Maintained by Jeff Garzik <jgarzik@pobox.com>
-
- Original code came from 8139too.c, which in turns was based
- originally on Donald Becker's rtl8139.c driver, versions 1.11
- and older. This driver was originally based on rtl8139.c
- version 1.07. Header of rtl8139.c version 1.11:
-
- -----<snip>-----
-
- Written 1997-2000 by Donald Becker.
- This software may be used and distributed according to the
- terms of the GNU General Public License (GPL), incorporated
- herein by reference. Drivers based on or derived from this
- code fall under the GPL and must retain the authorship,
- copyright and license notice. This file is not a complete
- program and may only be used when the entire operating
- system is licensed under the GPL.
-
- This driver is for boards based on the RTL8129 and RTL8139
- PCI ethernet chips.
-
- The author may be reached as becker@scyld.com, or C/O Scyld
- Computing Corporation 410 Severn Ave., Suite 210 Annapolis
- MD 21403
-
- Support and updates available at
- http://www.scyld.com/network/rtl8139.html
-
- Twister-tuning table provided by Kinston
- <shangh@realtek.com.tw>.
-
- -----<snip>-----
-
- This software may be used and distributed according to the terms
- of the GNU General Public License, incorporated herein by reference.
-
-
------------------------------------------------------------------------------
-
- Theory of Operation
-
-I. Board Compatibility
-
-This device driver is designed for the RealTek RTL8139 series, the RealTek
-Fast Ethernet controllers for PCI and CardBus. This chip is used on many
-low-end boards, sometimes with its markings changed.
-
-
-II. Board-specific settings
-
-PCI bus devices are configured by the system at boot time, so no jumpers
-need to be set on the board. The system BIOS will assign the
-PCI INTA signal to a (preferably otherwise unused) system IRQ line.
-
-III. Driver operation
-
-IIIa. Rx Ring buffers
-
-The receive unit uses a single linear ring buffer rather than the more
-common (and more efficient) descriptor-based architecture. Incoming frames
-are sequentially stored into the Rx region, and the host copies them into
-skbuffs.
-
-Comment: While it is theoretically possible to process many frames in place,
-any delay in Rx processing would cause us to drop frames. More importantly,
-the Linux protocol stack is not designed to operate in this manner.
-
-IIIb. Tx operation
-
-The RTL8139 uses a fixed set of four Tx descriptors in register space.
-In a stunningly bad design choice, Tx frames must be 32 bit aligned. Linux
-aligns the IP header on word boundaries, and 14 byte ethernet header means
-that almost all frames will need to be copied to an alignment buffer.
-
-IVb. References
-
-http://www.realtek.com.tw/
-http://www.scyld.com/expert/NWay.html
-
-IVc. Errata
-
-*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/delay.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
-#include <linux/crc32.h>
-#include <linux/io.h>
-
-#define NETDRV_VERSION "1.0.1"
-#define MODNAME "netdrv"
-#define NETDRV_DRIVER_LOAD_MSG "MyVendor Fast Ethernet driver " NETDRV_VERSION " loaded"
-
-static char version[] __devinitdata =
- KERN_INFO NETDRV_DRIVER_LOAD_MSG "\n"
- " Support available from http://foo.com/bar/baz.html\n";
-
-/* define to 1 to enable PIO instead of MMIO */
-#undef USE_IO_OPS
-
-/* define to 1 to enable copious debugging info */
-#undef NETDRV_DEBUG
-
-/* define to 1 to disable lightweight runtime debugging checks */
-#undef NETDRV_NDEBUG
-
-
-#ifdef NETDRV_DEBUG
-/* note: prints function name for you */
-#define DPRINTK(fmt, args...) \
- printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
-#else
-#define DPRINTK(fmt, args...) \
-do { \
- if (0) \
- printk(KERN_DEBUG fmt, ##args); \
-} while (0)
-#endif
-
-#ifdef NETDRV_NDEBUG
-#define assert(expr) do {} while (0)
-#else
-#define assert(expr) \
- if (!(expr)) { \
- printk("Assertion failed! %s,%s,%s,line=%d\n", \
- #expr, __FILE__, __func__, __LINE__); \
- }
-#endif
-
-
-/* A few user-configurable values. */
-/* media options */
-static int media[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
-
-/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
- The RTL chips use a 64 element hash table based on the Ethernet CRC. */
-static int multicast_filter_limit = 32;
-
-/* Size of the in-memory receive ring. */
-#define RX_BUF_LEN_IDX 2 /* 0==8K, 1==16K, 2==32K, 3==64K */
-#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
-#define RX_BUF_PAD 16
-#define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */
-#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD)
-
-/* Number of Tx descriptor registers. */
-#define NUM_TX_DESC 4
-
-/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/
-#define MAX_ETH_FRAME_SIZE 1536
-
-/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
-#define TX_BUF_SIZE MAX_ETH_FRAME_SIZE
-#define TX_BUF_TOT_LEN (TX_BUF_SIZE * NUM_TX_DESC)
-
-/* PCI Tuning Parameters
- Threshold is bytes transferred to chip before transmission starts. */
-#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */
-
-/* The following settings are log_2(bytes)-4:
- 0==16 bytes 1==32 2==64 3==128 4==256 5==512 6==1024 7==end of packet.
-*/
-#define RX_FIFO_THRESH 6 /* Rx buffer level before first PCI xfer. */
-#define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
-#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
-
-
-/* Operational parameters that usually are not changed. */
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT (6 * HZ)
-
-enum {
- HAS_CHIP_XCVR = 0x020000,
- HAS_LNK_CHNG = 0x040000,
-};
-
-#define NETDRV_MIN_IO_SIZE 0x80
-#define RTL8139B_IO_SIZE 256
-
-#define NETDRV_CAPS (HAS_CHIP_XCVR | HAS_LNK_CHNG)
-
-typedef enum {
- RTL8139 = 0,
- NETDRV_CB,
- SMC1211TX,
- /*MPX5030,*/
- DELTA8139,
- ADDTRON8139,
-} board_t;
-
-
-/* indexed by board_t, above */
-static struct {
- const char *name;
-} board_info[] __devinitdata = {
- { "RealTek RTL8139 Fast Ethernet" },
- { "RealTek RTL8139B PCI/CardBus" },
- { "SMC1211TX EZCard 10/100 (RealTek RTL8139)" },
-/* { MPX5030, "Accton MPX5030 (RealTek RTL8139)" },*/
- { "Delta Electronics 8139 10/100BaseTX" },
- { "Addtron Technology 8139 10/100BaseTX" },
-};
-
-
-static DEFINE_PCI_DEVICE_TABLE(netdrv_pci_tbl) = {
- {0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NETDRV_CB },
- {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMC1211TX },
-/* {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MPX5030 },*/
- {0x1500, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DELTA8139 },
- {0x4033, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ADDTRON8139 },
- {0,}
-};
-MODULE_DEVICE_TABLE(pci, netdrv_pci_tbl);
-
-
-/* The rest of these values should never change. */
-
-/* Symbolic offsets to registers. */
-enum NETDRV_registers {
- MAC0 = 0, /* Ethernet hardware address. */
- MAR0 = 8, /* Multicast filter. */
- TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */
- TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */
- RxBuf = 0x30,
- RxEarlyCnt = 0x34,
- RxEarlyStatus = 0x36,
- ChipCmd = 0x37,
- RxBufPtr = 0x38,
- RxBufAddr = 0x3A,
- IntrMask = 0x3C,
- IntrStatus = 0x3E,
- TxConfig = 0x40,
- ChipVersion = 0x43,
- RxConfig = 0x44,
- Timer = 0x48, /* A general-purpose counter. */
- RxMissed = 0x4C, /* 24 bits valid, write clears. */
- Cfg9346 = 0x50,
- Config0 = 0x51,
- Config1 = 0x52,
- FlashReg = 0x54,
- MediaStatus = 0x58,
- Config3 = 0x59,
- Config4 = 0x5A, /* absent on RTL-8139A */
- HltClk = 0x5B,
- MultiIntr = 0x5C,
- TxSummary = 0x60,
- BasicModeCtrl = 0x62,
- BasicModeStatus = 0x64,
- NWayAdvert = 0x66,
- NWayLPAR = 0x68,
- NWayExpansion = 0x6A,
- /* Undocumented registers, but required for proper operation. */
- FIFOTMS = 0x70, /* FIFO Control and test. */
- CSCR = 0x74, /* Chip Status and Configuration Register. */
- PARA78 = 0x78,
- PARA7c = 0x7c, /* Magic transceiver parameter register. */
- Config5 = 0xD8, /* absent on RTL-8139A */
-};
-
-enum ClearBitMasks {
- MultiIntrClear = 0xF000,
- ChipCmdClear = 0xE2,
- Config1Clear = (1 << 7) | (1 << 6) | (1 << 3) | (1 << 2) | (1 << 1),
-};
-
-enum ChipCmdBits {
- CmdReset = 0x10,
- CmdRxEnb = 0x08,
- CmdTxEnb = 0x04,
- RxBufEmpty = 0x01,
-};
-
-/* Interrupt register bits, using my own meaningful names. */
-enum IntrStatusBits {
- PCIErr = 0x8000,
- PCSTimeout = 0x4000,
- RxFIFOOver = 0x40,
- RxUnderrun = 0x20,
- RxOverflow = 0x10,
- TxErr = 0x08,
- TxOK = 0x04,
- RxErr = 0x02,
- RxOK = 0x01,
-};
-enum TxStatusBits {
- TxHostOwns = 0x2000,
- TxUnderrun = 0x4000,
- TxStatOK = 0x8000,
- TxOutOfWindow = 0x20000000,
- TxAborted = 0x40000000,
- TxCarrierLost = 0x80000000,
-};
-enum RxStatusBits {
- RxMulticast = 0x8000,
- RxPhysical = 0x4000,
- RxBroadcast = 0x2000,
- RxBadSymbol = 0x0020,
- RxRunt = 0x0010,
- RxTooLong = 0x0008,
- RxCRCErr = 0x0004,
- RxBadAlign = 0x0002,
- RxStatusOK = 0x0001,
-};
-
-/* Bits in RxConfig. */
-enum rx_mode_bits {
- AcceptErr = 0x20,
- AcceptRunt = 0x10,
- AcceptBroadcast = 0x08,
- AcceptMulticast = 0x04,
- AcceptMyPhys = 0x02,
- AcceptAllPhys = 0x01,
-};
-
-/* Bits in TxConfig. */
-enum tx_config_bits {
- TxIFG1 = (1 << 25), /* Interframe Gap Time */
- TxIFG0 = (1 << 24), /* Enabling these bits violates IEEE 802.3 */
- TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
- TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */
- TxClearAbt = (1 << 0), /* Clear abort (WO) */
- TxDMAShift = 8, /* DMA burst value(0-7) is shift this many bits */
-
- TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
-};
-
-/* Bits in Config1 */
-enum Config1Bits {
- Cfg1_PM_Enable = 0x01,
- Cfg1_VPD_Enable = 0x02,
- Cfg1_PIO = 0x04,
- Cfg1_MMIO = 0x08,
- Cfg1_LWAKE = 0x10,
- Cfg1_Driver_Load = 0x20,
- Cfg1_LED0 = 0x40,
- Cfg1_LED1 = 0x80,
-};
-
-enum RxConfigBits {
- /* Early Rx threshold, none or X/16 */
- RxCfgEarlyRxNone = 0,
- RxCfgEarlyRxShift = 24,
-
- /* rx fifo threshold */
- RxCfgFIFOShift = 13,
- RxCfgFIFONone = (7 << RxCfgFIFOShift),
-
- /* Max DMA burst */
- RxCfgDMAShift = 8,
- RxCfgDMAUnlimited = (7 << RxCfgDMAShift),
-
- /* rx ring buffer length */
- RxCfgRcv8K = 0,
- RxCfgRcv16K = (1 << 11),
- RxCfgRcv32K = (1 << 12),
- RxCfgRcv64K = (1 << 11) | (1 << 12),
-
- /* Disable packet wrap at end of Rx buffer */
- RxNoWrap = (1 << 7),
-};
-
-
-/* Twister tuning parameters from RealTek.
- Completely undocumented, but required to tune bad links. */
-enum CSCRBits {
- CSCR_LinkOKBit = 0x0400,
- CSCR_LinkChangeBit = 0x0800,
- CSCR_LinkStatusBits = 0x0f000,
- CSCR_LinkDownOffCmd = 0x003c0,
- CSCR_LinkDownCmd = 0x0f3c0,
-};
-
-
-enum Cfg9346Bits {
- Cfg9346_Lock = 0x00,
- Cfg9346_Unlock = 0xC0,
-};
-
-
-#define PARA78_default 0x78fa8388
-#define PARA7c_default 0xcb38de43 /* param[0][3] */
-#define PARA7c_xxx 0xcb38de43
-static const unsigned long param[4][4] = {
- {0xcb39de43, 0xcb39ce43, 0xfb38de03, 0xcb38de43},
- {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
- {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
- {0xbb39de43, 0xbb39ce43, 0xbb39ce83, 0xbb39ce83}
-};
-
-struct ring_info {
- struct sk_buff *skb;
- dma_addr_t mapping;
-};
-
-
-typedef enum {
- CH_8139 = 0,
- CH_8139_K,
- CH_8139A,
- CH_8139B,
- CH_8130,
- CH_8139C,
-} chip_t;
-
-
-/* directly indexed by chip_t, above */
-static const struct {
- const char *name;
- u8 version; /* from RTL8139C docs */
- u32 RxConfigMask; /* should clear the bits supported by this chip */
-} rtl_chip_info[] = {
- { "RTL-8139",
- 0x40,
- 0xf0fe0040, /* XXX copied from RTL8139A, verify */
- },
-
- { "RTL-8139 rev K",
- 0x60,
- 0xf0fe0040,
- },
-
- { "RTL-8139A",
- 0x70,
- 0xf0fe0040,
- },
-
- { "RTL-8139B",
- 0x78,
- 0xf0fc0040
- },
-
- { "RTL-8130",
- 0x7C,
- 0xf0fe0040, /* XXX copied from RTL8139A, verify */
- },
-
- { "RTL-8139C",
- 0x74,
- 0xf0fc0040, /* XXX copied from RTL8139B, verify */
- },
-
-};
-
-
-struct netdrv_private {
- board_t board;
- void *mmio_addr;
- int drv_flags;
- struct pci_dev *pci_dev;
- struct timer_list timer; /* Media selection timer. */
- unsigned char *rx_ring;
- unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */
- unsigned int tx_flag;
- atomic_t cur_tx;
- atomic_t dirty_tx;
- /* The saved address of a sent-in-place packet/buffer, for skfree(). */
- struct ring_info tx_info[NUM_TX_DESC];
- unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */
- unsigned char *tx_bufs; /* Tx bounce buffer region. */
- dma_addr_t rx_ring_dma;
- dma_addr_t tx_bufs_dma;
- char phys[4]; /* MII device addresses. */
- char twistie, twist_row, twist_col; /* Twister tune state. */
- unsigned int full_duplex:1; /* Full-duplex operation requested. */
- unsigned int duplex_lock:1;
- unsigned int default_port:4; /* Last dev->if_port value. */
- unsigned int media2:4; /* Secondary monitored media port. */
- unsigned int medialock:1; /* Don't sense media type. */
- unsigned int mediasense:1; /* Media sensing in progress. */
- spinlock_t lock;
- chip_t chipset;
-};
-
-MODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>");
-MODULE_DESCRIPTION("Skeleton for a PCI Fast Ethernet driver");
-MODULE_LICENSE("GPL");
-module_param(multicast_filter_limit, int, 0);
-module_param(max_interrupt_work, int, 0);
-module_param_array(media, int, NULL, 0);
-MODULE_PARM_DESC(multicast_filter_limit,
- MODNAME " maximum number of filtered multicast addresses");
-MODULE_PARM_DESC(max_interrupt_work,
- MODNAME " maximum events handled per interrupt");
-MODULE_PARM_DESC(media,
- MODNAME " Bits 0-3: media type, bit 17: full duplex");
-
-static int read_eeprom(void *ioaddr, int location, int addr_len);
-static int netdrv_open(struct net_device *dev);
-static int mdio_read(struct net_device *dev, int phy_id, int location);
-static void mdio_write(struct net_device *dev, int phy_id, int location,
- int val);
-static void netdrv_timer(unsigned long data);
-static void netdrv_tx_timeout(struct net_device *dev);
-static void netdrv_init_ring(struct net_device *dev);
-static int netdrv_start_xmit(struct sk_buff *skb,
- struct net_device *dev);
-static irqreturn_t netdrv_interrupt(int irq, void *dev_instance);
-static int netdrv_close(struct net_device *dev);
-static int netdrv_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static void netdrv_set_rx_mode(struct net_device *dev);
-static void netdrv_hw_start(struct net_device *dev);
-
-
-#ifdef USE_IO_OPS
-
-#define NETDRV_R8(reg) inb(((unsigned long)ioaddr) + (reg))
-#define NETDRV_R16(reg) inw(((unsigned long)ioaddr) + (reg))
-#define NETDRV_R32(reg) ((unsigned long)inl(((unsigned long)ioaddr) + (reg)))
-#define NETDRV_W8(reg, val8) outb((val8), ((unsigned long)ioaddr) + (reg))
-#define NETDRV_W16(reg, val16) outw((val16), ((unsigned long)ioaddr) + (reg))
-#define NETDRV_W32(reg, val32) outl((val32), ((unsigned long)ioaddr) + (reg))
-#define NETDRV_W8_F NETDRV_W8
-#define NETDRV_W16_F NETDRV_W16
-#define NETDRV_W32_F NETDRV_W32
-#undef readb
-#undef readw
-#undef readl
-#undef writeb
-#undef writew
-#undef writel
-#define readb(addr) inb((unsigned long)(addr))
-#define readw(addr) inw((unsigned long)(addr))
-#define readl(addr) inl((unsigned long)(addr))
-#define writeb(val, addr) outb((val), (unsigned long)(addr))
-#define writew(val, addr) outw((val), (unsigned long)(addr))
-#define writel(val, addr) outl((val), (unsigned long)(addr))
-
-#else
-
-/* write MMIO register, with flush */
-/* Flush avoids rtl8139 bug w/ posted MMIO writes */
-#define NETDRV_W8_F(reg, val8) \
-do { \
- writeb((val8), ioaddr + (reg)); \
- readb(ioaddr + (reg)); \
-} while (0)
-#define NETDRV_W16_F(reg, val16) \
-do { \
- writew((val16), ioaddr + (reg)); \
- readw(ioaddr + (reg)); \
-} while (0)
-#define NETDRV_W32_F(reg, val32) \
-do { \
- writel((val32), ioaddr + (reg)); \
- readl(ioaddr + (reg)); \
-} while (0)
-
-
-#ifdef MMIO_FLUSH_AUDIT_COMPLETE
-
-/* write MMIO register */
-#define NETDRV_W8(reg, val8) writeb((val8), ioaddr + (reg))
-#define NETDRV_W16(reg, val16) writew((val16), ioaddr + (reg))
-#define NETDRV_W32(reg, val32) writel((val32), ioaddr + (reg))
-
-#else
-
-/* write MMIO register, then flush */
-#define NETDRV_W8 NETDRV_W8_F
-#define NETDRV_W16 NETDRV_W16_F
-#define NETDRV_W32 NETDRV_W32_F
-
-#endif /* MMIO_FLUSH_AUDIT_COMPLETE */
-
-/* read MMIO register */
-#define NETDRV_R8(reg) readb(ioaddr + (reg))
-#define NETDRV_R16(reg) readw(ioaddr + (reg))
-#define NETDRV_R32(reg) ((unsigned long) readl(ioaddr + (reg)))
-
-#endif /* USE_IO_OPS */
-
-
-static const u16 netdrv_intr_mask =
- PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver |
- TxErr | TxOK | RxErr | RxOK;
-
-static const unsigned int netdrv_rx_config =
- RxCfgEarlyRxNone | RxCfgRcv32K | RxNoWrap |
- (RX_FIFO_THRESH << RxCfgFIFOShift) |
- (RX_DMA_BURST << RxCfgDMAShift);
-
-
-static int __devinit netdrv_init_board(struct pci_dev *pdev,
- struct net_device **dev_out,
- void **ioaddr_out)
-{
- void *ioaddr = NULL;
- struct net_device *dev;
- struct netdrv_private *tp;
- int rc, i;
- u32 pio_start, pio_end, pio_flags, pio_len;
- unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
- u32 tmp;
-
- DPRINTK("ENTER\n");
-
- assert(pdev != NULL);
- assert(ioaddr_out != NULL);
-
- *ioaddr_out = NULL;
- *dev_out = NULL;
-
- /* dev zeroed in alloc_etherdev */
- dev = alloc_etherdev(sizeof(*tp));
- if (dev == NULL) {
- dev_err(&pdev->dev, "unable to alloc new ethernet\n");
- DPRINTK("EXIT, returning -ENOMEM\n");
- return -ENOMEM;
- }
- SET_NETDEV_DEV(dev, &pdev->dev);
- tp = netdev_priv(dev);
-
- /* enable device(incl. PCI PM wakeup), and bus-mastering */
- rc = pci_enable_device(pdev);
- if (rc)
- goto err_out;
-
- pio_start = pci_resource_start(pdev, 0);
- pio_end = pci_resource_end(pdev, 0);
- pio_flags = pci_resource_flags(pdev, 0);
- pio_len = pci_resource_len(pdev, 0);
-
- mmio_start = pci_resource_start(pdev, 1);
- mmio_end = pci_resource_end(pdev, 1);
- mmio_flags = pci_resource_flags(pdev, 1);
- mmio_len = pci_resource_len(pdev, 1);
-
- /* set this immediately, we need to know before
- * we talk to the chip directly */
- DPRINTK("PIO region size == %#02X\n", pio_len);
- DPRINTK("MMIO region size == %#02lX\n", mmio_len);
-
- /* make sure PCI base addr 0 is PIO */
- if (!(pio_flags & IORESOURCE_IO)) {
- dev_err(&pdev->dev, "region #0 not a PIO resource, aborting\n");
- rc = -ENODEV;
- goto err_out;
- }
-
- /* make sure PCI base addr 1 is MMIO */
- if (!(mmio_flags & IORESOURCE_MEM)) {
- dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n");
- rc = -ENODEV;
- goto err_out;
- }
-
- /* check for weird/broken PCI region reporting */
- if ((pio_len < NETDRV_MIN_IO_SIZE) ||
- (mmio_len < NETDRV_MIN_IO_SIZE)) {
- dev_err(&pdev->dev, "Invalid PCI region size(s), aborting\n");
- rc = -ENODEV;
- goto err_out;
- }
-
- rc = pci_request_regions(pdev, MODNAME);
- if (rc)
- goto err_out;
-
- pci_set_master(pdev);
-
-#ifdef USE_IO_OPS
- ioaddr = (void *)pio_start;
-#else
- /* ioremap MMIO region */
- ioaddr = ioremap(mmio_start, mmio_len);
- if (ioaddr == NULL) {
- dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
- rc = -EIO;
- goto err_out_free_res;
- }
-#endif /* USE_IO_OPS */
-
- /* Soft reset the chip. */
- NETDRV_W8(ChipCmd, (NETDRV_R8(ChipCmd) & ChipCmdClear) | CmdReset);
-
- /* Check that the chip has finished the reset. */
- for (i = 1000; i > 0; i--)
- if ((NETDRV_R8(ChipCmd) & CmdReset) == 0)
- break;
- else
- udelay(10);
-
- /* Bring the chip out of low-power mode. */
- /* <insert device-specific code here> */
-
-#ifndef USE_IO_OPS
- /* sanity checks -- ensure PIO and MMIO registers agree */
- assert(inb(pio_start+Config0) == readb(ioaddr+Config0));
- assert(inb(pio_start+Config1) == readb(ioaddr+Config1));
- assert(inb(pio_start+TxConfig) == readb(ioaddr+TxConfig));
- assert(inb(pio_start+RxConfig) == readb(ioaddr+RxConfig));
-#endif /* !USE_IO_OPS */
-
- /* identify chip attached to board */
- tmp = NETDRV_R8(ChipVersion);
- for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--)
- if (tmp == rtl_chip_info[i].version) {
- tp->chipset = i;
- goto match;
- }
-
- /* if unknown chip, assume array element #0, original RTL-8139 in this case */
- dev_printk(KERN_DEBUG, &pdev->dev,
- "unknown chip version, assuming RTL-8139\n");
- dev_printk(KERN_DEBUG, &pdev->dev, "TxConfig = %#lx\n",
- NETDRV_R32(TxConfig));
- tp->chipset = 0;
-
-match:
- DPRINTK("chipset id(%d) == index %d, '%s'\n",
- tmp, tp->chipset, rtl_chip_info[tp->chipset].name);
-
- rc = register_netdev(dev);
- if (rc)
- goto err_out_unmap;
-
- DPRINTK("EXIT, returning 0\n");
- *ioaddr_out = ioaddr;
- *dev_out = dev;
- return 0;
-
-err_out_unmap:
-#ifndef USE_IO_OPS
- iounmap(ioaddr);
-err_out_free_res:
-#endif
- pci_release_regions(pdev);
-err_out:
- free_netdev(dev);
- DPRINTK("EXIT, returning %d\n", rc);
- return rc;
-}
-
-static const struct net_device_ops netdrv_netdev_ops = {
- .ndo_open = netdrv_open,
- .ndo_stop = netdrv_close,
- .ndo_start_xmit = netdrv_start_xmit,
- .ndo_set_multicast_list = netdrv_set_rx_mode,
- .ndo_do_ioctl = netdrv_ioctl,
- .ndo_tx_timeout = netdrv_tx_timeout,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
-};
-
-static int __devinit netdrv_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- struct net_device *dev = NULL;
- struct netdrv_private *tp;
- int i, addr_len, option;
- void *ioaddr = NULL;
- static int board_idx = -1;
-
-/* when built into the kernel, we only print version if device is found */
-#ifndef MODULE
- static int printed_version;
- if (!printed_version++)
- printk(version);
-#endif
-
- DPRINTK("ENTER\n");
-
- assert(pdev != NULL);
- assert(ent != NULL);
-
- board_idx++;
-
- i = netdrv_init_board(pdev, &dev, &ioaddr);
- if (i < 0) {
- DPRINTK("EXIT, returning %d\n", i);
- return i;
- }
-
- tp = netdev_priv(dev);
-
- assert(ioaddr != NULL);
- assert(dev != NULL);
- assert(tp != NULL);
-
- addr_len = read_eeprom(ioaddr, 0, 8) == 0x8129 ? 8 : 6;
- for (i = 0; i < 3; i++)
- ((u16 *)(dev->dev_addr))[i] =
- le16_to_cpu(read_eeprom(ioaddr, i + 7, addr_len));
-
- dev->netdev_ops = &netdrv_netdev_ops;
- dev->watchdog_timeo = TX_TIMEOUT;
-
- dev->irq = pdev->irq;
- dev->base_addr = (unsigned long) ioaddr;
-
- /* netdev_priv()/tp zeroed and aligned in alloc_etherdev */
- tp = netdev_priv(dev);
-
- /* note: tp->chipset set in netdrv_init_board */
- tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
- PCI_COMMAND_MASTER | NETDRV_CAPS;
- tp->pci_dev = pdev;
- tp->board = ent->driver_data;
- tp->mmio_addr = ioaddr;
- spin_lock_init(&tp->lock);
-
- pci_set_drvdata(pdev, dev);
-
- tp->phys[0] = 32;
-
- netdev_info(dev, "%s at %#lx, %pM IRQ %d\n",
- board_info[ent->driver_data].name,
- dev->base_addr, dev->dev_addr, dev->irq);
-
- netdev_printk(KERN_DEBUG, dev, "Identified 8139 chip type '%s'\n",
- rtl_chip_info[tp->chipset].name);
-
- /* Put the chip into low-power mode. */
- NETDRV_W8_F(Cfg9346, Cfg9346_Unlock);
-
- /* The lower four bits are the media type. */
- option = (board_idx > 7) ? 0 : media[board_idx];
- if (option > 0) {
- tp->full_duplex = (option & 0x200) ? 1 : 0;
- tp->default_port = option & 15;
- if (tp->default_port)
- tp->medialock = 1;
- }
-
- if (tp->full_duplex) {
- netdev_info(dev, "Media type forced to Full Duplex\n");
- mdio_write(dev, tp->phys[0], MII_ADVERTISE, ADVERTISE_FULL);
- tp->duplex_lock = 1;
- }
-
- DPRINTK("EXIT - returning 0\n");
- return 0;
-}
-
-
-static void __devexit netdrv_remove_one(struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct netdrv_private *np;
-
- DPRINTK("ENTER\n");
-
- assert(dev != NULL);
-
- np = netdev_priv(dev);
- assert(np != NULL);
-
- unregister_netdev(dev);
-
-#ifndef USE_IO_OPS
- iounmap(np->mmio_addr);
-#endif /* !USE_IO_OPS */
-
- pci_release_regions(pdev);
-
- free_netdev(dev);
-
- pci_set_drvdata(pdev, NULL);
-
- pci_disable_device(pdev);
-
- DPRINTK("EXIT\n");
-}
-
-
-/* Serial EEPROM section. */
-
-/* EEPROM_Ctrl bits. */
-#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */
-#define EE_CS 0x08 /* EEPROM chip select. */
-#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */
-#define EE_WRITE_0 0x00
-#define EE_WRITE_1 0x02
-#define EE_DATA_READ 0x01 /* EEPROM chip data out. */
-#define EE_ENB (0x80 | EE_CS)
-
-/* Delay between EEPROM clock transitions.
- No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
-*/
-
-#define eeprom_delay() readl(ee_addr)
-
-/* The EEPROM commands include the alway-set leading bit. */
-#define EE_WRITE_CMD (5)
-#define EE_READ_CMD (6)
-#define EE_ERASE_CMD (7)
-
-static int __devinit read_eeprom(void *ioaddr, int location, int addr_len)
-{
- int i;
- unsigned retval = 0;
- void *ee_addr = ioaddr + Cfg9346;
- int read_cmd = location | (EE_READ_CMD << addr_len);
-
- DPRINTK("ENTER\n");
-
- writeb(EE_ENB & ~EE_CS, ee_addr);
- writeb(EE_ENB, ee_addr);
- eeprom_delay();
-
- /* Shift the read command bits out. */
- for (i = 4 + addr_len; i >= 0; i--) {
- int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
- writeb(EE_ENB | dataval, ee_addr);
- eeprom_delay();
- writeb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
- eeprom_delay();
- }
- writeb(EE_ENB, ee_addr);
- eeprom_delay();
-
- for (i = 16; i > 0; i--) {
- writeb(EE_ENB | EE_SHIFT_CLK, ee_addr);
- eeprom_delay();
- retval =
- (retval << 1) | ((readb(ee_addr) & EE_DATA_READ) ? 1 :
- 0);
- writeb(EE_ENB, ee_addr);
- eeprom_delay();
- }
-
- /* Terminate the EEPROM access. */
- writeb(~EE_CS, ee_addr);
- eeprom_delay();
-
- DPRINTK("EXIT - returning %d\n", retval);
- return retval;
-}
-
-/* MII serial management: mostly bogus for now. */
-/* Read and write the MII management registers using software-generated
- serial MDIO protocol.
- The maximum data clock rate is 2.5 Mhz. The minimum timing is usually
- met by back-to-back PCI I/O cycles, but we insert a delay to avoid
- "overclocking" issues. */
-#define MDIO_DIR 0x80
-#define MDIO_DATA_OUT 0x04
-#define MDIO_DATA_IN 0x02
-#define MDIO_CLK 0x01
-#define MDIO_WRITE0 (MDIO_DIR)
-#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)
-
-#define mdio_delay() readb(mdio_addr)
-
-
-static char mii_2_8139_map[8] = {
- BasicModeCtrl,
- BasicModeStatus,
- 0,
- 0,
- NWayAdvert,
- NWayLPAR,
- NWayExpansion,
- 0
-};
-
-
-/* Syncronize the MII management interface by shifting 32 one bits out. */
-static void mdio_sync(void *mdio_addr)
-{
- int i;
-
- DPRINTK("ENTER\n");
-
- for (i = 32; i >= 0; i--) {
- writeb(MDIO_WRITE1, mdio_addr);
- mdio_delay();
- writeb(MDIO_WRITE1 | MDIO_CLK, mdio_addr);
- mdio_delay();
- }
-
- DPRINTK("EXIT\n");
-}
-
-
-static int mdio_read(struct net_device *dev, int phy_id, int location)
-{
- struct netdrv_private *tp = netdev_priv(dev);
- void *mdio_addr = tp->mmio_addr + Config4;
- int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
- int retval = 0;
- int i;
-
- DPRINTK("ENTER\n");
-
- if (phy_id > 31) { /* Really a 8139. Use internal registers. */
- DPRINTK("EXIT after directly using 8139 internal regs\n");
- return location < 8 && mii_2_8139_map[location] ?
- readw(tp->mmio_addr + mii_2_8139_map[location]) : 0;
- }
- mdio_sync(mdio_addr);
- /* Shift the read command bits out. */
- for (i = 15; i >= 0; i--) {
- int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;
-
- writeb(MDIO_DIR | dataval, mdio_addr);
- mdio_delay();
- writeb(MDIO_DIR | dataval | MDIO_CLK, mdio_addr);
- mdio_delay();
- }
-
- /* Read the two transition, 16 data, and wire-idle bits. */
- for (i = 19; i > 0; i--) {
- writeb(0, mdio_addr);
- mdio_delay();
- retval = ((retval << 1) | ((readb(mdio_addr) & MDIO_DATA_IN))
- ? 1 : 0);
- writeb(MDIO_CLK, mdio_addr);
- mdio_delay();
- }
-
- DPRINTK("EXIT, returning %d\n", (retval >> 1) & 0xffff);
- return (retval >> 1) & 0xffff;
-}
-
-
-static void mdio_write(struct net_device *dev, int phy_id, int location,
- int value)
-{
- struct netdrv_private *tp = netdev_priv(dev);
- void *mdio_addr = tp->mmio_addr + Config4;
- int mii_cmd =
- (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
- int i;
-
- DPRINTK("ENTER\n");
-
- if (phy_id > 31) { /* Really a 8139. Use internal registers. */
- if (location < 8 && mii_2_8139_map[location]) {
- writew(value,
- tp->mmio_addr + mii_2_8139_map[location]);
- readw(tp->mmio_addr + mii_2_8139_map[location]);
- }
- DPRINTK("EXIT after directly using 8139 internal regs\n");
- return;
- }
- mdio_sync(mdio_addr);
-
- /* Shift the command bits out. */
- for (i = 31; i >= 0; i--) {
- int dataval =
- (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
- writeb(dataval, mdio_addr);
- mdio_delay();
- writeb(dataval | MDIO_CLK, mdio_addr);
- mdio_delay();
- }
-
- /* Clear out extra bits. */
- for (i = 2; i > 0; i--) {
- writeb(0, mdio_addr);
- mdio_delay();
- writeb(MDIO_CLK, mdio_addr);
- mdio_delay();
- }
-
- DPRINTK("EXIT\n");
-}
-
-
-static int netdrv_open(struct net_device *dev)
-{
- struct netdrv_private *tp = netdev_priv(dev);
- int retval;
- void *ioaddr = tp->mmio_addr;
-
- DPRINTK("ENTER\n");
-
- retval = request_irq(dev->irq, netdrv_interrupt, IRQF_SHARED, dev->name, dev);
- if (retval) {
- DPRINTK("EXIT, returning %d\n", retval);
- return retval;
- }
-
- tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
- &tp->tx_bufs_dma);
- tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
- &tp->rx_ring_dma);
- if (tp->tx_bufs == NULL || tp->rx_ring == NULL) {
- free_irq(dev->irq, dev);
-
- if (tp->tx_bufs)
- pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
- tp->tx_bufs, tp->tx_bufs_dma);
- if (tp->rx_ring)
- pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
- tp->rx_ring, tp->rx_ring_dma);
-
- DPRINTK("EXIT, returning -ENOMEM\n");
- return -ENOMEM;
-
- }
-
- tp->full_duplex = tp->duplex_lock;
- tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
-
- netdrv_init_ring(dev);
- netdrv_hw_start(dev);
-
- netdev_dbg(dev, "ioaddr %#llx IRQ %d GP Pins %02x %s-duplex\n",
- (unsigned long long)pci_resource_start(tp->pci_dev, 1),
- dev->irq, NETDRV_R8(MediaStatus),
- tp->full_duplex ? "full" : "half");
-
- /* Set the timer to switch to check for link beat and perhaps switch
- to an alternate media type. */
- init_timer(&tp->timer);
- tp->timer.expires = jiffies + 3 * HZ;
- tp->timer.data = (unsigned long) dev;
- tp->timer.function = netdrv_timer;
- add_timer(&tp->timer);
-
- DPRINTK("EXIT, returning 0\n");
- return 0;
-}
-
-
-/* Start the hardware at open or resume. */
-static void netdrv_hw_start(struct net_device *dev)
-{
- struct netdrv_private *tp = netdev_priv(dev);
- void *ioaddr = tp->mmio_addr;
- u32 i;
-
- DPRINTK("ENTER\n");
-
- /* Soft reset the chip. */
- NETDRV_W8(ChipCmd, (NETDRV_R8(ChipCmd) & ChipCmdClear) | CmdReset);
- udelay(100);
-
- /* Check that the chip has finished the reset. */
- for (i = 1000; i > 0; i--)
- if ((NETDRV_R8(ChipCmd) & CmdReset) == 0)
- break;
-
- /* Restore our idea of the MAC address. */
- NETDRV_W32_F(MAC0 + 0, cpu_to_le32(*(u32 *)(dev->dev_addr + 0)));
- NETDRV_W32_F(MAC0 + 4, cpu_to_le32(*(u32 *)(dev->dev_addr + 4)));
-
- /* Must enable Tx/Rx before setting transfer thresholds! */
- NETDRV_W8_F(ChipCmd, (NETDRV_R8(ChipCmd) & ChipCmdClear) |
- CmdRxEnb | CmdTxEnb);
-
- i = netdrv_rx_config |
- (NETDRV_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
- NETDRV_W32_F(RxConfig, i);
-
- /* Check this value: the documentation for IFG contradicts ifself. */
- NETDRV_W32(TxConfig, (TX_DMA_BURST << TxDMAShift));
-
- /* unlock Config[01234] and BMCR register writes */
- NETDRV_W8_F(Cfg9346, Cfg9346_Unlock);
- udelay(10);
-
- tp->cur_rx = 0;
-
- /* Lock Config[01234] and BMCR register writes */
- NETDRV_W8_F(Cfg9346, Cfg9346_Lock);
- udelay(10);
-
- /* init Rx ring buffer DMA address */
- NETDRV_W32_F(RxBuf, tp->rx_ring_dma);
-
- /* init Tx buffer DMA addresses */
- for (i = 0; i < NUM_TX_DESC; i++)
- NETDRV_W32_F(TxAddr0 + (i * 4), tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs));
-
- NETDRV_W32_F(RxMissed, 0);
-
- netdrv_set_rx_mode(dev);
-
- /* no early-rx interrupts */
- NETDRV_W16(MultiIntr, NETDRV_R16(MultiIntr) & MultiIntrClear);
-
- /* make sure RxTx has started */
- NETDRV_W8_F(ChipCmd, (NETDRV_R8(ChipCmd) & ChipCmdClear) |
- CmdRxEnb | CmdTxEnb);
-
- /* Enable all known interrupts by setting the interrupt mask. */
- NETDRV_W16_F(IntrMask, netdrv_intr_mask);
-
- netif_start_queue(dev);
-
- DPRINTK("EXIT\n");
-}
-
-
-/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static void netdrv_init_ring(struct net_device *dev)
-{
- struct netdrv_private *tp = netdev_priv(dev);
- int i;
-
- DPRINTK("ENTER\n");
-
- tp->cur_rx = 0;
- atomic_set(&tp->cur_tx, 0);
- atomic_set(&tp->dirty_tx, 0);
-
- for (i = 0; i < NUM_TX_DESC; i++) {
- tp->tx_info[i].skb = NULL;
- tp->tx_info[i].mapping = 0;
- tp->tx_buf[i] = &tp->tx_bufs[i * TX_BUF_SIZE];
- }
-
- DPRINTK("EXIT\n");
-}
-
-
-static void netdrv_timer(unsigned long data)
-{
- struct net_device *dev = (struct net_device *) data;
- struct netdrv_private *tp = netdev_priv(dev);
- void *ioaddr = tp->mmio_addr;
- int next_tick = 60 * HZ;
- int mii_lpa;
-
- mii_lpa = mdio_read(dev, tp->phys[0], MII_LPA);
-
- if (!tp->duplex_lock && mii_lpa != 0xffff) {
- int duplex = ((mii_lpa & LPA_100FULL) ||
- (mii_lpa & 0x01C0) == 0x0040);
- if (tp->full_duplex != duplex) {
- tp->full_duplex = duplex;
- netdev_info(dev, "Setting %s-duplex based on MII #%d link partner ability of %04x\n",
- tp->full_duplex ? "full" : "half",
- tp->phys[0], mii_lpa);
- NETDRV_W8(Cfg9346, Cfg9346_Unlock);
- NETDRV_W8(Config1, tp->full_duplex ? 0x60 : 0x20);
- NETDRV_W8(Cfg9346, Cfg9346_Lock);
- }
- }
-
- netdev_dbg(dev, "Media selection tick, Link partner %04x\n",
- NETDRV_R16(NWayLPAR));
- netdev_dbg(dev, "Other registers are IntMask %04x IntStatus %04x RxStatus %04lx\n",
- NETDRV_R16(IntrMask),
- NETDRV_R16(IntrStatus),
- NETDRV_R32(RxEarlyStatus));
- netdev_dbg(dev, "Chip config %02x %02x\n",
- NETDRV_R8(Config0), NETDRV_R8(Config1));
-
- tp->timer.expires = jiffies + next_tick;
- add_timer(&tp->timer);
-}
-
-
-static void netdrv_tx_clear(struct net_device *dev)
-{
- int i;
- struct netdrv_private *tp = netdev_priv(dev);
-
- atomic_set(&tp->cur_tx, 0);
- atomic_set(&tp->dirty_tx, 0);
-
- /* Dump the unsent Tx packets. */
- for (i = 0; i < NUM_TX_DESC; i++) {
- struct ring_info *rp = &tp->tx_info[i];
- if (rp->mapping != 0) {
- pci_unmap_single(tp->pci_dev, rp->mapping,
- rp->skb->len, PCI_DMA_TODEVICE);
- rp->mapping = 0;
- }
- if (rp->skb) {
- dev_kfree_skb(rp->skb);
- rp->skb = NULL;
- dev->stats.tx_dropped++;
- }
- }
-}
-
-
-static void netdrv_tx_timeout(struct net_device *dev)
-{
- struct netdrv_private *tp = netdev_priv(dev);
- void *ioaddr = tp->mmio_addr;
- int i;
- u8 tmp8;
- unsigned long flags;
-
- netdev_dbg(dev, "Transmit timeout, status %02x %04x media %02x\n",
- NETDRV_R8(ChipCmd),
- NETDRV_R16(IntrStatus),
- NETDRV_R8(MediaStatus));
-
- /* disable Tx ASAP, if not already */
- tmp8 = NETDRV_R8(ChipCmd);
- if (tmp8 & CmdTxEnb)
- NETDRV_W8(ChipCmd, tmp8 & ~CmdTxEnb);
-
- /* Disable interrupts by clearing the interrupt mask. */
- NETDRV_W16(IntrMask, 0x0000);
-
- /* Emit info to figure out what went wrong. */
- netdev_dbg(dev, "Tx queue start entry %d dirty entry %d\n",
- atomic_read(&tp->cur_tx),
- atomic_read(&tp->dirty_tx));
- for (i = 0; i < NUM_TX_DESC; i++)
- netdev_dbg(dev, "Tx descriptor %d is %08lx%s\n",
- i, NETDRV_R32(TxStatus0 + (i * 4)),
- i == atomic_read(&tp->dirty_tx) % NUM_TX_DESC ?
- "(queue head)" : "");
-
- /* Stop a shared interrupt from scavenging while we are. */
- spin_lock_irqsave(&tp->lock, flags);
-
- netdrv_tx_clear(dev);
-
- spin_unlock_irqrestore(&tp->lock, flags);
-
- /* ...and finally, reset everything */
- netdrv_hw_start(dev);
-
- netif_wake_queue(dev);
-}
-
-
-
-static int netdrv_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct netdrv_private *tp = netdev_priv(dev);
- void *ioaddr = tp->mmio_addr;
- int entry;
-
- /* Calculate the next Tx descriptor entry. */
- entry = atomic_read(&tp->cur_tx) % NUM_TX_DESC;
-
- assert(tp->tx_info[entry].skb == NULL);
- assert(tp->tx_info[entry].mapping == 0);
-
- tp->tx_info[entry].skb = skb;
- /* tp->tx_info[entry].mapping = 0; */
- skb_copy_from_linear_data(skb, tp->tx_buf[entry], skb->len);
-
- /* Note: the chip doesn't have auto-pad! */
- NETDRV_W32(TxStatus0 + (entry * sizeof(u32)),
- tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
-
- atomic_inc(&tp->cur_tx);
- if ((atomic_read(&tp->cur_tx) - atomic_read(&tp->dirty_tx)) >= NUM_TX_DESC)
- netif_stop_queue(dev);
-
- netdev_dbg(dev, "Queued Tx packet at %p size %u to slot %d\n",
- skb->data, skb->len, entry);
-
- return NETDEV_TX_OK;
-}
-
-
-static void netdrv_tx_interrupt(struct net_device *dev,
- struct netdrv_private *tp,
- void *ioaddr)
-{
- int cur_tx, dirty_tx, tx_left;
-
- assert(dev != NULL);
- assert(tp != NULL);
- assert(ioaddr != NULL);
-
- dirty_tx = atomic_read(&tp->dirty_tx);
-
- cur_tx = atomic_read(&tp->cur_tx);
- tx_left = cur_tx - dirty_tx;
- while (tx_left > 0) {
- int entry = dirty_tx % NUM_TX_DESC;
- int txstatus;
-
- txstatus = NETDRV_R32(TxStatus0 + (entry * sizeof(u32)));
-
- if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted)))
- break; /* It still hasn't been Txed */
-
- /* Note: TxCarrierLost is always asserted at 100mbps. */
- if (txstatus & (TxOutOfWindow | TxAborted)) {
- /* There was an major error, log it. */
- netdev_dbg(dev, "Transmit error, Tx status %#08x\n",
- txstatus);
- dev->stats.tx_errors++;
- if (txstatus & TxAborted) {
- dev->stats.tx_aborted_errors++;
- NETDRV_W32(TxConfig, TxClearAbt | (TX_DMA_BURST << TxDMAShift));
- }
- if (txstatus & TxCarrierLost)
- dev->stats.tx_carrier_errors++;
- if (txstatus & TxOutOfWindow)
- dev->stats.tx_window_errors++;
- } else {
- if (txstatus & TxUnderrun) {
- /* Add 64 to the Tx FIFO threshold. */
- if (tp->tx_flag < 0x00300000)
- tp->tx_flag += 0x00020000;
- dev->stats.tx_fifo_errors++;
- }
- dev->stats.collisions += (txstatus >> 24) & 15;
- dev->stats.tx_bytes += txstatus & 0x7ff;
- dev->stats.tx_packets++;
- }
-
- /* Free the original skb. */
- if (tp->tx_info[entry].mapping != 0) {
- pci_unmap_single(tp->pci_dev,
- tp->tx_info[entry].mapping,
- tp->tx_info[entry].skb->len,
- PCI_DMA_TODEVICE);
- tp->tx_info[entry].mapping = 0;
- }
- dev_kfree_skb_irq(tp->tx_info[entry].skb);
- tp->tx_info[entry].skb = NULL;
- dirty_tx++;
- if (dirty_tx < 0) { /* handle signed int overflow */
- atomic_sub(cur_tx, &tp->cur_tx); /* XXX racy? */
- dirty_tx = cur_tx - tx_left + 1;
- }
- if (netif_queue_stopped(dev))
- netif_wake_queue(dev);
-
- cur_tx = atomic_read(&tp->cur_tx);
- tx_left = cur_tx - dirty_tx;
-
- }
-
-#ifndef NETDRV_NDEBUG
- if (atomic_read(&tp->cur_tx) - dirty_tx > NUM_TX_DESC) {
- netdev_err(dev, "Out-of-sync dirty pointer, %d vs. %d\n",
- dirty_tx, atomic_read(&tp->cur_tx));
- dirty_tx += NUM_TX_DESC;
- }
-#endif /* NETDRV_NDEBUG */
-
- atomic_set(&tp->dirty_tx, dirty_tx);
-}
-
-
-/* TODO: clean this up! Rx reset need not be this intensive */
-static void netdrv_rx_err(u32 rx_status, struct net_device *dev,
- struct netdrv_private *tp, void *ioaddr)
-{
- u8 tmp8;
- int tmp_work = 1000;
-
- netdev_dbg(dev, "Ethernet frame had errors, status %08x\n", rx_status);
- if (rx_status & RxTooLong)
- netdev_dbg(dev, "Oversized Ethernet frame, status %04x!\n",
- rx_status);
- /* A.C.: The chip hangs here. */
- dev->stats.rx_errors++;
- if (rx_status & (RxBadSymbol | RxBadAlign))
- dev->stats.rx_frame_errors++;
- if (rx_status & (RxRunt | RxTooLong))
- dev->stats.rx_length_errors++;
- if (rx_status & RxCRCErr)
- dev->stats.rx_crc_errors++;
- /* Reset the receiver, based on RealTek recommendation.(Bug?) */
- tp->cur_rx = 0;
-
- /* disable receive */
- tmp8 = NETDRV_R8(ChipCmd) & ChipCmdClear;
- NETDRV_W8_F(ChipCmd, tmp8 | CmdTxEnb);
-
- /* A.C.: Reset the multicast list. */
- netdrv_set_rx_mode(dev);
-
- /* XXX potentially temporary hack to
- * restart hung receiver */
- while (--tmp_work > 0) {
- tmp8 = NETDRV_R8(ChipCmd);
- if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb))
- break;
- NETDRV_W8_F(ChipCmd,
- (tmp8 & ChipCmdClear) | CmdRxEnb | CmdTxEnb);
- }
-
- /* G.S.: Re-enable receiver */
- /* XXX temporary hack to work around receiver hang */
- netdrv_set_rx_mode(dev);
-
- if (tmp_work <= 0)
- netdev_warn(dev, "tx/rx enable wait too long\n");
-}
-
-
-/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the
- field alignments and semantics. */
-static void netdrv_rx_interrupt(struct net_device *dev,
- struct netdrv_private *tp, void *ioaddr)
-{
- unsigned char *rx_ring;
- u16 cur_rx;
-
- assert(dev != NULL);
- assert(tp != NULL);
- assert(ioaddr != NULL);
-
- rx_ring = tp->rx_ring;
- cur_rx = tp->cur_rx;
-
- netdev_dbg(dev, "In netdrv_rx(), current %04x BufAddr %04x, free to %04x, Cmd %02x\n",
- cur_rx, NETDRV_R16(RxBufAddr),
- NETDRV_R16(RxBufPtr), NETDRV_R8(ChipCmd));
-
- while ((NETDRV_R8(ChipCmd) & RxBufEmpty) == 0) {
- int ring_offset = cur_rx % RX_BUF_LEN;
- u32 rx_status;
- unsigned int rx_size;
- unsigned int pkt_size;
- struct sk_buff *skb;
-
- /* read size+status of next frame from DMA ring buffer */
- rx_status = le32_to_cpu(*(u32 *)(rx_ring + ring_offset));
- rx_size = rx_status >> 16;
- pkt_size = rx_size - 4;
-
- netdev_dbg(dev, "netdrv_rx() status %04x, size %04x, cur %04x\n",
- rx_status, rx_size, cur_rx);
-#if defined(NETDRV_DEBUG) && (NETDRV_DEBUG > 2)
- print_hex_dump_bytes("Frame contents: ", HEX_DUMP_OFFSET,
- &rx_ring[ring_offset], 70);
-#endif
-
- /* If Rx err or invalid rx_size/rx_status received
- *(which happens if we get lost in the ring),
- * Rx process gets reset, so we abort any further
- * Rx processing.
- */
- if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) ||
- (!(rx_status & RxStatusOK))) {
- netdrv_rx_err(rx_status, dev, tp, ioaddr);
- return;
- }
-
- /* Malloc up new buffer, compatible with net-2e. */
- /* Omit the four octet CRC from the length. */
-
- /* TODO: consider allocating skb's outside of
- * interrupt context, both to speed interrupt processing,
- * and also to reduce the chances of having to
- * drop packets here under memory pressure.
- */
-
- skb = dev_alloc_skb(pkt_size + 2);
- if (skb) {
- skb_reserve(skb, 2); /* 16 byte align the IP fields. */
-
- skb_copy_to_linear_data(skb, &rx_ring[ring_offset + 4], pkt_size);
- skb_put(skb, pkt_size);
-
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- dev->stats.rx_bytes += pkt_size;
- dev->stats.rx_packets++;
- } else {
- netdev_warn(dev, "Memory squeeze, dropping packet\n");
- dev->stats.rx_dropped++;
- }
-
- cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
- NETDRV_W16_F(RxBufPtr, cur_rx - 16);
- }
-
- netdev_dbg(dev, "Done netdrv_rx(), current %04x BufAddr %04x, free to %04x, Cmd %02x\n",
- cur_rx, NETDRV_R16(RxBufAddr),
- NETDRV_R16(RxBufPtr), NETDRV_R8(ChipCmd));
-
- tp->cur_rx = cur_rx;
-}
-
-
-static void netdrv_weird_interrupt(struct net_device *dev,
- struct netdrv_private *tp,
- void *ioaddr,
- int status, int link_changed)
-{
- netdev_printk(KERN_DEBUG, dev, "Abnormal interrupt, status %08x\n",
- status);
-
- assert(dev != NULL);
- assert(tp != NULL);
- assert(ioaddr != NULL);
-
- /* Update the error count. */
- dev->stats.rx_missed_errors += NETDRV_R32(RxMissed);
- NETDRV_W32(RxMissed, 0);
-
- if ((status & RxUnderrun) && link_changed &&
- (tp->drv_flags & HAS_LNK_CHNG)) {
- /* Really link-change on new chips. */
- int lpar = NETDRV_R16(NWayLPAR);
- int duplex = ((lpar & 0x0100) || (lpar & 0x01C0) == 0x0040 ||
- tp->duplex_lock);
- if (tp->full_duplex != duplex) {
- tp->full_duplex = duplex;
- NETDRV_W8(Cfg9346, Cfg9346_Unlock);
- NETDRV_W8(Config1, tp->full_duplex ? 0x60 : 0x20);
- NETDRV_W8(Cfg9346, Cfg9346_Lock);
- }
- status &= ~RxUnderrun;
- }
-
- /* XXX along with netdrv_rx_err, are we double-counting errors? */
- if (status & (RxUnderrun | RxOverflow | RxErr | RxFIFOOver))
- dev->stats.rx_errors++;
-
- if (status & (PCSTimeout))
- dev->stats.rx_length_errors++;
- if (status & (RxUnderrun | RxFIFOOver))
- dev->stats.rx_fifo_errors++;
- if (status & RxOverflow) {
- dev->stats.rx_over_errors++;
- tp->cur_rx = NETDRV_R16(RxBufAddr) % RX_BUF_LEN;
- NETDRV_W16_F(RxBufPtr, tp->cur_rx - 16);
- }
- if (status & PCIErr) {
- u16 pci_cmd_status;
- pci_read_config_word(tp->pci_dev, PCI_STATUS, &pci_cmd_status);
-
- netdev_err(dev, "PCI Bus error %04x\n", pci_cmd_status);
- }
-}
-
-
-/* The interrupt handler does all of the Rx thread work and cleans up
- after the Tx thread. */
-static irqreturn_t netdrv_interrupt(int irq, void *dev_instance)
-{
- struct net_device *dev = (struct net_device *) dev_instance;
- struct netdrv_private *tp = netdev_priv(dev);
- int boguscnt = max_interrupt_work;
- void *ioaddr = tp->mmio_addr;
- int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */
- int handled = 0;
-
- spin_lock(&tp->lock);
-
- do {
- status = NETDRV_R16(IntrStatus);
-
- /* h/w no longer present(hotplug?) or major error, bail */
- if (status == 0xFFFF)
- break;
-
- handled = 1;
- /* Acknowledge all of the current interrupt sources ASAP */
- NETDRV_W16_F(IntrStatus, status);
-
- netdev_dbg(dev, "interrupt status=%#04x new intstat=%#04x\n",
- status, NETDRV_R16(IntrStatus));
-
- if ((status &
- (PCIErr | PCSTimeout | RxUnderrun | RxOverflow |
- RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0)
- break;
-
- /* Check uncommon events with one test. */
- if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow |
- RxFIFOOver | TxErr | RxErr))
- netdrv_weird_interrupt(dev, tp, ioaddr,
- status, link_changed);
-
- if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) /* Rx interrupt */
- netdrv_rx_interrupt(dev, tp, ioaddr);
-
- if (status & (TxOK | TxErr))
- netdrv_tx_interrupt(dev, tp, ioaddr);
-
- boguscnt--;
- } while (boguscnt > 0);
-
- if (boguscnt <= 0) {
- netdev_warn(dev, "Too much work at interrupt, IntrStatus=%#04x\n",
- status);
-
- /* Clear all interrupt sources. */
- NETDRV_W16(IntrStatus, 0xffff);
- }
-
- spin_unlock(&tp->lock);
-
- netdev_dbg(dev, "exiting interrupt, intr_status=%#04x\n",
- NETDRV_R16(IntrStatus));
- return IRQ_RETVAL(handled);
-}
-
-
-static int netdrv_close(struct net_device *dev)
-{
- struct netdrv_private *tp = netdev_priv(dev);
- void *ioaddr = tp->mmio_addr;
- unsigned long flags;
-
- DPRINTK("ENTER\n");
-
- netif_stop_queue(dev);
-
- netdev_dbg(dev, "Shutting down ethercard, status was %#04x\n",
- NETDRV_R16(IntrStatus));
-
- del_timer_sync(&tp->timer);
-
- spin_lock_irqsave(&tp->lock, flags);
-
- /* Stop the chip's Tx and Rx DMA processes. */
- NETDRV_W8(ChipCmd, (NETDRV_R8(ChipCmd) & ChipCmdClear));
-
- /* Disable interrupts by clearing the interrupt mask. */
- NETDRV_W16(IntrMask, 0x0000);
-
- /* Update the error counts. */
- dev->stats.rx_missed_errors += NETDRV_R32(RxMissed);
- NETDRV_W32(RxMissed, 0);
-
- spin_unlock_irqrestore(&tp->lock, flags);
-
- free_irq(dev->irq, dev);
-
- netdrv_tx_clear(dev);
-
- pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
- tp->rx_ring, tp->rx_ring_dma);
- pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
- tp->tx_bufs, tp->tx_bufs_dma);
- tp->rx_ring = NULL;
- tp->tx_bufs = NULL;
-
- /* Green! Put the chip in low-power mode. */
- NETDRV_W8(Cfg9346, Cfg9346_Unlock);
- NETDRV_W8(Config1, 0x03);
- NETDRV_W8(Cfg9346, Cfg9346_Lock);
-
- DPRINTK("EXIT\n");
- return 0;
-}
-
-
-static int netdrv_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
- struct netdrv_private *tp = netdev_priv(dev);
- struct mii_ioctl_data *data = if_mii(rq);
- unsigned long flags;
- int rc = 0;
-
- DPRINTK("ENTER\n");
-
- switch (cmd) {
- case SIOCGMIIPHY: /* Get address of MII PHY in use. */
- data->phy_id = tp->phys[0] & 0x3f;
- /* Fall Through */
-
- case SIOCGMIIREG: /* Read MII PHY register. */
- spin_lock_irqsave(&tp->lock, flags);
- data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
- spin_unlock_irqrestore(&tp->lock, flags);
- break;
-
- case SIOCSMIIREG: /* Write MII PHY register. */
- spin_lock_irqsave(&tp->lock, flags);
- mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
- spin_unlock_irqrestore(&tp->lock, flags);
- break;
-
- default:
- rc = -EOPNOTSUPP;
- break;
- }
-
- DPRINTK("EXIT, returning %d\n", rc);
- return rc;
-}
-
-/* Set or clear the multicast filter for this adaptor.
- This routine is not state sensitive and need not be SMP locked. */
-
-static void netdrv_set_rx_mode(struct net_device *dev)
-{
- struct netdrv_private *tp = netdev_priv(dev);
- void *ioaddr = tp->mmio_addr;
- u32 mc_filter[2]; /* Multicast hash filter */
- int rx_mode;
- u32 tmp;
-
- DPRINTK("ENTER\n");
-
- netdev_dbg(dev, "%s(%04x) done -- Rx config %08lx\n",
- __func__, dev->flags, NETDRV_R32(RxConfig));
-
- /* Note: do not reorder, GCC is clever about common statements. */
- if (dev->flags & IFF_PROMISC) {
- rx_mode =
- AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
- AcceptAllPhys;
- mc_filter[1] = mc_filter[0] = 0xffffffff;
- } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
- (dev->flags & IFF_ALLMULTI)) {
- /* Too many to filter perfectly -- accept all multicasts. */
- rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
- mc_filter[1] = mc_filter[0] = 0xffffffff;
- } else {
- struct netdev_hw_addr *ha;
-
- rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
- mc_filter[1] = mc_filter[0] = 0;
- netdev_for_each_mc_addr(ha, dev) {
- int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
-
- mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
- }
- }
-
- /* if called from irq handler, lock already acquired */
- if (!in_irq())
- spin_lock_irq(&tp->lock);
-
- /* We can safely update without stopping the chip. */
- tmp = netdrv_rx_config | rx_mode |
- (NETDRV_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
- NETDRV_W32_F(RxConfig, tmp);
- NETDRV_W32_F(MAR0 + 0, mc_filter[0]);
- NETDRV_W32_F(MAR0 + 4, mc_filter[1]);
-
- if (!in_irq())
- spin_unlock_irq(&tp->lock);
-
- DPRINTK("EXIT\n");
-}
-
-
-#ifdef CONFIG_PM
-
-static int netdrv_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct netdrv_private *tp = netdev_priv(dev);
- void *ioaddr = tp->mmio_addr;
- unsigned long flags;
-
- if (!netif_running(dev))
- return 0;
- netif_device_detach(dev);
-
- spin_lock_irqsave(&tp->lock, flags);
-
- /* Disable interrupts, stop Tx and Rx. */
- NETDRV_W16(IntrMask, 0x0000);
- NETDRV_W8(ChipCmd, (NETDRV_R8(ChipCmd) & ChipCmdClear));
-
- /* Update the error counts. */
- dev->stats.rx_missed_errors += NETDRV_R32(RxMissed);
- NETDRV_W32(RxMissed, 0);
-
- spin_unlock_irqrestore(&tp->lock, flags);
-
- pci_save_state(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
-
- return 0;
-}
-
-
-static int netdrv_resume(struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- /*struct netdrv_private *tp = netdev_priv(dev);*/
-
- if (!netif_running(dev))
- return 0;
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
- netif_device_attach(dev);
- netdrv_hw_start(dev);
-
- return 0;
-}
-
-#endif /* CONFIG_PM */
-
-
-static struct pci_driver netdrv_pci_driver = {
- .name = MODNAME,
- .id_table = netdrv_pci_tbl,
- .probe = netdrv_init_one,
- .remove = __devexit_p(netdrv_remove_one),
-#ifdef CONFIG_PM
- .suspend = netdrv_suspend,
- .resume = netdrv_resume,
-#endif /* CONFIG_PM */
-};
-
-
-static int __init netdrv_init_module(void)
-{
-/* when a module, this is printed whether or not devices are found in probe */
-#ifdef MODULE
- printk(version);
-#endif
- return pci_register_driver(&netdrv_pci_driver);
-}
-
-
-static void __exit netdrv_cleanup_module(void)
-{
- pci_unregister_driver(&netdrv_pci_driver);
-}
-
-
-module_init(netdrv_init_module);
-module_exit(netdrv_cleanup_module);
diff --git a/drivers/net/pcmcia/Kconfig b/drivers/net/pcmcia/Kconfig
deleted file mode 100644
index 9b8f793b1cc8..000000000000
--- a/drivers/net/pcmcia/Kconfig
+++ /dev/null
@@ -1,123 +0,0 @@
-#
-# PCMCIA Network device configuration
-#
-
-menuconfig NET_PCMCIA
- bool "PCMCIA network device support"
- depends on PCMCIA
- ---help---
- Say Y if you would like to include support for any PCMCIA or CardBus
- network adapters, then say Y to the driver for your particular card
- below. PCMCIA- or PC-cards are credit-card size devices often used
- with laptops computers; CardBus is the newer and faster version of
- PCMCIA.
-
- To use your PC-cards, you will need supporting software from David
- Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
- for location). You also want to check out the PCMCIA-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>.
-
- If unsure, say N.
-
-if NET_PCMCIA && PCMCIA
-
-config PCMCIA_3C589
- tristate "3Com 3c589 PCMCIA support"
- help
- Say Y here if you intend to attach a 3Com 3c589 or compatible PCMCIA
- (PC-card) Ethernet card to your computer.
-
- To compile this driver as a module, choose M here: the module will be
- called 3c589_cs. If unsure, say N.
-
-config PCMCIA_3C574
- tristate "3Com 3c574 PCMCIA support"
- help
- Say Y here if you intend to attach a 3Com 3c574 or compatible PCMCIA
- (PC-card) Fast Ethernet card to your computer.
-
- To compile this driver as a module, choose M here: the module will be
- called 3c574_cs. If unsure, say N.
-
-config PCMCIA_FMVJ18X
- tristate "Fujitsu FMV-J18x PCMCIA support"
- select CRC32
- help
- Say Y here if you intend to attach a Fujitsu FMV-J18x or compatible
- PCMCIA (PC-card) Ethernet card to your computer.
-
- To compile this driver as a module, choose M here: the module will be
- called fmvj18x_cs. If unsure, say N.
-
-config PCMCIA_PCNET
- tristate "NE2000 compatible PCMCIA support"
- select CRC32
- help
- Say Y here if you intend to attach an NE2000 compatible PCMCIA
- (PC-card) Ethernet or Fast Ethernet card to your computer.
-
- To compile this driver as a module, choose M here: the module will be
- called pcnet_cs. If unsure, say N.
-
-config PCMCIA_NMCLAN
- tristate "New Media PCMCIA support"
- help
- Say Y here if you intend to attach a New Media Ethernet or LiveWire
- PCMCIA (PC-card) Ethernet card to your computer.
-
- To compile this driver as a module, choose M here: the module will be
- called nmclan_cs. If unsure, say N.
-
-config PCMCIA_SMC91C92
- tristate "SMC 91Cxx PCMCIA support"
- select CRC32
- select MII
- help
- Say Y here if you intend to attach an SMC 91Cxx compatible PCMCIA
- (PC-card) Ethernet or Fast Ethernet card to your computer.
-
- To compile this driver as a module, choose M here: the module will be
- called smc91c92_cs. If unsure, say N.
-
-config PCMCIA_XIRC2PS
- tristate "Xircom 16-bit PCMCIA support"
- help
- Say Y here if you intend to attach a Xircom 16-bit PCMCIA (PC-card)
- Ethernet or Fast Ethernet card to your computer.
-
- To compile this driver as a module, choose M here: the module will be
- called xirc2ps_cs. If unsure, say N.
-
-config PCMCIA_AXNET
- tristate "Asix AX88190 PCMCIA support"
- ---help---
- Say Y here if you intend to attach an Asix AX88190-based PCMCIA
- (PC-card) Fast Ethernet card to your computer. These cards are
- nearly NE2000 compatible but need a separate driver due to a few
- misfeatures.
-
- To compile this driver as a module, choose M here: the module will be
- called axnet_cs. If unsure, say N.
-
-config ARCNET_COM20020_CS
- tristate "COM20020 ARCnet PCMCIA support"
- depends on ARCNET_COM20020
- help
- Say Y here if you intend to attach this type of ARCnet PCMCIA card
- to your computer.
-
- To compile this driver as a module, choose M here: the module will be
- called com20020_cs. If unsure, say N.
-
-config PCMCIA_IBMTR
- tristate "IBM PCMCIA tokenring adapter support"
- depends on IBMTR!=y && TR
- help
- Say Y here if you intend to attach this type of Token Ring PCMCIA
- card to your computer. You then also need to say Y to "Token Ring
- driver support".
-
- To compile this driver as a module, choose M here: the module will be
- called ibmtr_cs.
-
-endif # NET_PCMCIA
diff --git a/drivers/net/pcmcia/Makefile b/drivers/net/pcmcia/Makefile
deleted file mode 100644
index 87d2d99f4c14..000000000000
--- a/drivers/net/pcmcia/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# Makefile for the Linux PCMCIA network device drivers.
-#
-
-# 16-bit client drivers
-obj-$(CONFIG_PCMCIA_3C589) += 3c589_cs.o
-obj-$(CONFIG_PCMCIA_3C574) += 3c574_cs.o
-obj-$(CONFIG_PCMCIA_FMVJ18X) += fmvj18x_cs.o
-obj-$(CONFIG_PCMCIA_NMCLAN) += nmclan_cs.o
-obj-$(CONFIG_PCMCIA_PCNET) += pcnet_cs.o
-obj-$(CONFIG_PCMCIA_SMC91C92) += smc91c92_cs.o
-obj-$(CONFIG_PCMCIA_XIRC2PS) += xirc2ps_cs.o
-obj-$(CONFIG_ARCNET_COM20020_CS)+= com20020_cs.o
-obj-$(CONFIG_PCMCIA_AXNET) += axnet_cs.o
-
-obj-$(CONFIG_PCMCIA_IBMTR) += ibmtr_cs.o
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index a70244306c94..bb88e12101c7 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -3,7 +3,7 @@
#
menuconfig PHYLIB
- tristate "PHY Device support and infrastructure"
+ bool "PHY Device support and infrastructure"
depends on !S390
depends on NETDEVICES
help
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index d84c4224dd12..e8be47d6d7d0 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -553,7 +553,7 @@ static int bcm5481_config_aneg(struct phy_device *phydev)
/*
* There is no BCM5481 specification available, so down
* here is everything we know about "register 0x18". This
- * at least helps BCM5481 to successfuly receive packets
+ * at least helps BCM5481 to successfully receive packets
* on MPC8360E-RDK board. Peter Barada <peterb@logicpd.com>
* says: "This sets delay between the RXD and RXC signals
* instead of using trace lengths to achieve timing".
diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
index cb6e0b486b1e..9663e0ba6003 100644
--- a/drivers/net/phy/dp83640.c
+++ b/drivers/net/phy/dp83640.c
@@ -35,16 +35,15 @@
#define LAYER4 0x02
#define LAYER2 0x01
#define MAX_RXTS 64
-#define N_EXT_TS 1
+#define N_EXT_TS 6
#define PSF_PTPVER 2
#define PSF_EVNT 0x4000
#define PSF_RX 0x2000
#define PSF_TX 0x1000
#define EXT_EVENT 1
-#define EXT_GPIO 1
-#define CAL_EVENT 2
-#define CAL_GPIO 9
-#define CAL_TRIGGER 2
+#define CAL_EVENT 7
+#define CAL_TRIGGER 7
+#define PER_TRIGGER 6
/* phyter seems to miss the mark by 16 ns */
#define ADJTIME_FIX 16
@@ -131,16 +130,30 @@ struct dp83640_clock {
/* globals */
+enum {
+ CALIBRATE_GPIO,
+ PEROUT_GPIO,
+ EXTTS0_GPIO,
+ EXTTS1_GPIO,
+ EXTTS2_GPIO,
+ EXTTS3_GPIO,
+ EXTTS4_GPIO,
+ EXTTS5_GPIO,
+ GPIO_TABLE_SIZE
+};
+
static int chosen_phy = -1;
-static ushort cal_gpio = 4;
+static ushort gpio_tab[GPIO_TABLE_SIZE] = {
+ 1, 2, 3, 4, 8, 9, 10, 11
+};
module_param(chosen_phy, int, 0444);
-module_param(cal_gpio, ushort, 0444);
+module_param_array(gpio_tab, ushort, NULL, 0444);
MODULE_PARM_DESC(chosen_phy, \
"The address of the PHY to use for the ancillary clock features");
-MODULE_PARM_DESC(cal_gpio, \
- "Which GPIO line to use for synchronizing multiple PHYs");
+MODULE_PARM_DESC(gpio_tab, \
+ "Which GPIO line to use for which purpose: cal,perout,extts1,...,extts6");
/* a list of clocks and a mutex to protect it */
static LIST_HEAD(phyter_clocks);
@@ -235,6 +248,61 @@ static u64 phy2txts(struct phy_txts *p)
return ns;
}
+static void periodic_output(struct dp83640_clock *clock,
+ struct ptp_clock_request *clkreq, bool on)
+{
+ struct dp83640_private *dp83640 = clock->chosen;
+ struct phy_device *phydev = dp83640->phydev;
+ u32 sec, nsec, period;
+ u16 gpio, ptp_trig, trigger, val;
+
+ gpio = on ? gpio_tab[PEROUT_GPIO] : 0;
+ trigger = PER_TRIGGER;
+
+ ptp_trig = TRIG_WR |
+ (trigger & TRIG_CSEL_MASK) << TRIG_CSEL_SHIFT |
+ (gpio & TRIG_GPIO_MASK) << TRIG_GPIO_SHIFT |
+ TRIG_PER |
+ TRIG_PULSE;
+
+ val = (trigger & TRIG_SEL_MASK) << TRIG_SEL_SHIFT;
+
+ if (!on) {
+ val |= TRIG_DIS;
+ mutex_lock(&clock->extreg_lock);
+ ext_write(0, phydev, PAGE5, PTP_TRIG, ptp_trig);
+ ext_write(0, phydev, PAGE4, PTP_CTL, val);
+ mutex_unlock(&clock->extreg_lock);
+ return;
+ }
+
+ sec = clkreq->perout.start.sec;
+ nsec = clkreq->perout.start.nsec;
+ period = clkreq->perout.period.sec * 1000000000UL;
+ period += clkreq->perout.period.nsec;
+
+ mutex_lock(&clock->extreg_lock);
+
+ ext_write(0, phydev, PAGE5, PTP_TRIG, ptp_trig);
+
+ /*load trigger*/
+ val |= TRIG_LOAD;
+ ext_write(0, phydev, PAGE4, PTP_CTL, val);
+ ext_write(0, phydev, PAGE4, PTP_TDR, nsec & 0xffff); /* ns[15:0] */
+ ext_write(0, phydev, PAGE4, PTP_TDR, nsec >> 16); /* ns[31:16] */
+ ext_write(0, phydev, PAGE4, PTP_TDR, sec & 0xffff); /* sec[15:0] */
+ ext_write(0, phydev, PAGE4, PTP_TDR, sec >> 16); /* sec[31:16] */
+ ext_write(0, phydev, PAGE4, PTP_TDR, period & 0xffff); /* ns[15:0] */
+ ext_write(0, phydev, PAGE4, PTP_TDR, period >> 16); /* ns[31:16] */
+
+ /*enable trigger*/
+ val &= ~TRIG_LOAD;
+ val |= TRIG_EN;
+ ext_write(0, phydev, PAGE4, PTP_CTL, val);
+
+ mutex_unlock(&clock->extreg_lock);
+}
+
/* ptp clock methods */
static int ptp_dp83640_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
@@ -338,19 +406,30 @@ static int ptp_dp83640_enable(struct ptp_clock_info *ptp,
struct dp83640_clock *clock =
container_of(ptp, struct dp83640_clock, caps);
struct phy_device *phydev = clock->chosen->phydev;
- u16 evnt;
+ int index;
+ u16 evnt, event_num, gpio_num;
switch (rq->type) {
case PTP_CLK_REQ_EXTTS:
- if (rq->extts.index != 0)
+ index = rq->extts.index;
+ if (index < 0 || index >= N_EXT_TS)
return -EINVAL;
- evnt = EVNT_WR | (EXT_EVENT & EVNT_SEL_MASK) << EVNT_SEL_SHIFT;
+ event_num = EXT_EVENT + index;
+ evnt = EVNT_WR | (event_num & EVNT_SEL_MASK) << EVNT_SEL_SHIFT;
if (on) {
- evnt |= (EXT_GPIO & EVNT_GPIO_MASK) << EVNT_GPIO_SHIFT;
+ gpio_num = gpio_tab[EXTTS0_GPIO + index];
+ evnt |= (gpio_num & EVNT_GPIO_MASK) << EVNT_GPIO_SHIFT;
evnt |= EVNT_RISE;
}
ext_write(0, phydev, PAGE5, PTP_EVNT, evnt);
return 0;
+
+ case PTP_CLK_REQ_PEROUT:
+ if (rq->perout.index != 0)
+ return -EINVAL;
+ periodic_output(clock, rq, on);
+ return 0;
+
default:
break;
}
@@ -441,9 +520,10 @@ static void recalibrate(struct dp83640_clock *clock)
struct list_head *this;
struct dp83640_private *tmp;
struct phy_device *master = clock->chosen->phydev;
- u16 cfg0, evnt, ptp_trig, trigger, val;
+ u16 cal_gpio, cfg0, evnt, ptp_trig, trigger, val;
trigger = CAL_TRIGGER;
+ cal_gpio = gpio_tab[CALIBRATE_GPIO];
mutex_lock(&clock->extreg_lock);
@@ -542,11 +622,17 @@ static void recalibrate(struct dp83640_clock *clock)
/* time stamping methods */
+static inline u16 exts_chan_to_edata(int ch)
+{
+ return 1 << ((ch + EXT_EVENT) * 2);
+}
+
static int decode_evnt(struct dp83640_private *dp83640,
void *data, u16 ests)
{
struct phy_txts *phy_txts;
struct ptp_clock_event event;
+ int i, parsed;
int words = (ests >> EVNT_TS_LEN_SHIFT) & EVNT_TS_LEN_MASK;
u16 ext_status = 0;
@@ -568,14 +654,25 @@ static int decode_evnt(struct dp83640_private *dp83640,
dp83640->edata.ns_lo = phy_txts->ns_lo;
}
+ if (ext_status) {
+ parsed = words + 2;
+ } else {
+ parsed = words + 1;
+ i = ((ests >> EVNT_NUM_SHIFT) & EVNT_NUM_MASK) - EXT_EVENT;
+ ext_status = exts_chan_to_edata(i);
+ }
+
event.type = PTP_CLOCK_EXTTS;
- event.index = 0;
event.timestamp = phy2txts(&dp83640->edata);
- ptp_clock_event(dp83640->clock->ptp_clock, &event);
+ for (i = 0; i < N_EXT_TS; i++) {
+ if (ext_status & exts_chan_to_edata(i)) {
+ event.index = i;
+ ptp_clock_event(dp83640->clock->ptp_clock, &event);
+ }
+ }
- words = ext_status ? words + 2 : words + 1;
- return words * sizeof(u16);
+ return parsed * sizeof(u16);
}
static void decode_rxts(struct dp83640_private *dp83640,
@@ -589,7 +686,7 @@ static void decode_rxts(struct dp83640_private *dp83640,
prune_rx_ts(dp83640);
if (list_empty(&dp83640->rxpool)) {
- pr_warning("dp83640: rx timestamp pool is empty\n");
+ pr_debug("dp83640: rx timestamp pool is empty\n");
goto out;
}
rxts = list_first_entry(&dp83640->rxpool, struct rxts, list);
@@ -612,7 +709,7 @@ static void decode_txts(struct dp83640_private *dp83640,
skb = skb_dequeue(&dp83640->tx_queue);
if (!skb) {
- pr_warning("dp83640: have timestamp but tx_queue empty\n");
+ pr_debug("dp83640: have timestamp but tx_queue empty\n");
return;
}
ns = phy2txts(phy_txts);
@@ -664,6 +761,41 @@ static void decode_status_frame(struct dp83640_private *dp83640,
}
}
+static int is_sync(struct sk_buff *skb, int type)
+{
+ u8 *data = skb->data, *msgtype;
+ unsigned int offset = 0;
+
+ switch (type) {
+ case PTP_CLASS_V1_IPV4:
+ case PTP_CLASS_V2_IPV4:
+ offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN;
+ break;
+ case PTP_CLASS_V1_IPV6:
+ case PTP_CLASS_V2_IPV6:
+ offset = OFF_PTP6;
+ break;
+ case PTP_CLASS_V2_L2:
+ offset = ETH_HLEN;
+ break;
+ case PTP_CLASS_V2_VLAN:
+ offset = ETH_HLEN + VLAN_HLEN;
+ break;
+ default:
+ return 0;
+ }
+
+ if (type & PTP_CLASS_V1)
+ offset += OFF_PTP_CONTROL;
+
+ if (skb->len < offset + 1)
+ return 0;
+
+ msgtype = data + offset;
+
+ return (*msgtype & 0xf) == 0;
+}
+
static int match(struct sk_buff *skb, unsigned int type, struct rxts *rxts)
{
u16 *seqid;
@@ -740,7 +872,7 @@ static void dp83640_clock_init(struct dp83640_clock *clock, struct mii_bus *bus)
clock->caps.max_adj = 1953124;
clock->caps.n_alarm = 0;
clock->caps.n_ext_ts = N_EXT_TS;
- clock->caps.n_per_out = 0;
+ clock->caps.n_per_out = 1;
clock->caps.pps = 0;
clock->caps.adjfreq = ptp_dp83640_adjfreq;
clock->caps.adjtime = ptp_dp83640_adjtime;
@@ -875,6 +1007,7 @@ static void dp83640_remove(struct phy_device *phydev)
struct dp83640_clock *clock;
struct list_head *this, *next;
struct dp83640_private *tmp, *dp83640 = phydev->priv;
+ struct sk_buff *skb;
if (phydev->addr == BROADCAST_ADDR)
return;
@@ -882,6 +1015,12 @@ static void dp83640_remove(struct phy_device *phydev)
enable_status_frames(phydev, false);
cancel_work_sync(&dp83640->ts_work);
+ while ((skb = skb_dequeue(&dp83640->rx_queue)) != NULL)
+ kfree_skb(skb);
+
+ while ((skb = skb_dequeue(&dp83640->tx_queue)) != NULL)
+ skb_complete_tx_timestamp(skb, NULL);
+
clock = dp83640_clock_get(dp83640->clock);
if (dp83640 == clock->chosen) {
@@ -913,16 +1052,10 @@ static int dp83640_hwtstamp(struct phy_device *phydev, struct ifreq *ifr)
if (cfg.flags) /* reserved for future extensions */
return -EINVAL;
- switch (cfg.tx_type) {
- case HWTSTAMP_TX_OFF:
- dp83640->hwts_tx_en = 0;
- break;
- case HWTSTAMP_TX_ON:
- dp83640->hwts_tx_en = 1;
- break;
- default:
+ if (cfg.tx_type < 0 || cfg.tx_type > HWTSTAMP_TX_ONESTEP_SYNC)
return -ERANGE;
- }
+
+ dp83640->hwts_tx_en = cfg.tx_type;
switch (cfg.rx_filter) {
case HWTSTAMP_FILTER_NONE:
@@ -977,6 +1110,9 @@ static int dp83640_hwtstamp(struct phy_device *phydev, struct ifreq *ifr)
if (dp83640->hwts_tx_en)
txcfg0 |= TX_TS_EN;
+ if (dp83640->hwts_tx_en == HWTSTAMP_TX_ONESTEP_SYNC)
+ txcfg0 |= SYNC_1STEP | CHK_1STEP;
+
if (dp83640->hwts_rx_en)
rxcfg0 |= RX_TS_EN;
@@ -1059,12 +1195,24 @@ static void dp83640_txtstamp(struct phy_device *phydev,
{
struct dp83640_private *dp83640 = phydev->priv;
- if (!dp83640->hwts_tx_en) {
- kfree_skb(skb);
- return;
+ switch (dp83640->hwts_tx_en) {
+
+ case HWTSTAMP_TX_ONESTEP_SYNC:
+ if (is_sync(skb, type)) {
+ skb_complete_tx_timestamp(skb, NULL);
+ return;
+ }
+ /* fall through */
+ case HWTSTAMP_TX_ON:
+ skb_queue_tail(&dp83640->tx_queue, skb);
+ schedule_work(&dp83640->ts_work);
+ break;
+
+ case HWTSTAMP_TX_OFF:
+ default:
+ skb_complete_tx_timestamp(skb, NULL);
+ break;
}
- skb_queue_tail(&dp83640->tx_queue, skb);
- schedule_work(&dp83640->ts_work);
}
static struct phy_driver dp83640_driver = {
diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c
index d4cbc2922b23..c81f136ae670 100644
--- a/drivers/net/phy/icplus.c
+++ b/drivers/net/phy/icplus.c
@@ -30,10 +30,17 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
-MODULE_DESCRIPTION("ICPlus IP175C/IC1001 PHY drivers");
+MODULE_DESCRIPTION("ICPlus IP175C/IP101A/IC1001 PHY drivers");
MODULE_AUTHOR("Michael Barkowski");
MODULE_LICENSE("GPL");
+/* IP101A/IP1001 */
+#define IP10XX_SPEC_CTRL_STATUS 16 /* Spec. Control Register */
+#define IP1001_SPEC_CTRL_STATUS_2 20 /* IP1001 Spec. Control Reg 2 */
+#define IP1001_PHASE_SEL_MASK 3 /* IP1001 RX/TXPHASE_SEL */
+#define IP1001_APS_ON 11 /* IP1001 APS Mode bit */
+#define IP101A_APS_ON 2 /* IP101A APS Mode bit */
+
static int ip175c_config_init(struct phy_device *phydev)
{
int err, i;
@@ -42,36 +49,36 @@ static int ip175c_config_init(struct phy_device *phydev)
if (full_reset_performed == 0) {
/* master reset */
- err = phydev->bus->write(phydev->bus, 30, 0, 0x175c);
+ err = mdiobus_write(phydev->bus, 30, 0, 0x175c);
if (err < 0)
return err;
/* ensure no bus delays overlap reset period */
- err = phydev->bus->read(phydev->bus, 30, 0);
+ err = mdiobus_read(phydev->bus, 30, 0);
/* data sheet specifies reset period is 2 msec */
mdelay(2);
/* enable IP175C mode */
- err = phydev->bus->write(phydev->bus, 29, 31, 0x175c);
+ err = mdiobus_write(phydev->bus, 29, 31, 0x175c);
if (err < 0)
return err;
/* Set MII0 speed and duplex (in PHY mode) */
- err = phydev->bus->write(phydev->bus, 29, 22, 0x420);
+ err = mdiobus_write(phydev->bus, 29, 22, 0x420);
if (err < 0)
return err;
/* reset switch ports */
for (i = 0; i < 5; i++) {
- err = phydev->bus->write(phydev->bus, i,
- MII_BMCR, BMCR_RESET);
+ err = mdiobus_write(phydev->bus, i,
+ MII_BMCR, BMCR_RESET);
if (err < 0)
return err;
}
for (i = 0; i < 5; i++)
- err = phydev->bus->read(phydev->bus, i, MII_BMCR);
+ err = mdiobus_read(phydev->bus, i, MII_BMCR);
mdelay(2);
@@ -89,27 +96,61 @@ static int ip175c_config_init(struct phy_device *phydev)
return 0;
}
-static int ip1001_config_init(struct phy_device *phydev)
+static int ip1xx_reset(struct phy_device *phydev)
{
- int err, value;
+ int err, bmcr;
/* Software Reset PHY */
- value = phy_read(phydev, MII_BMCR);
- value |= BMCR_RESET;
- err = phy_write(phydev, MII_BMCR, value);
+ bmcr = phy_read(phydev, MII_BMCR);
+ bmcr |= BMCR_RESET;
+ err = phy_write(phydev, MII_BMCR, bmcr);
if (err < 0)
return err;
do {
- value = phy_read(phydev, MII_BMCR);
- } while (value & BMCR_RESET);
+ bmcr = phy_read(phydev, MII_BMCR);
+ } while (bmcr & BMCR_RESET);
+
+ return err;
+}
+
+static int ip1001_config_init(struct phy_device *phydev)
+{
+ int c;
+
+ c = ip1xx_reset(phydev);
+ if (c < 0)
+ return c;
+
+ /* Enable Auto Power Saving mode */
+ c = phy_read(phydev, IP1001_SPEC_CTRL_STATUS_2);
+ c |= IP1001_APS_ON;
+ if (c < 0)
+ return c;
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
+ /* Additional delay (2ns) used to adjust RX clock phase
+ * at RGMII interface */
+ c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS);
+ c |= IP1001_PHASE_SEL_MASK;
+ c = phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c);
+ }
+
+ return c;
+}
+
+static int ip101a_config_init(struct phy_device *phydev)
+{
+ int c;
- /* Additional delay (2ns) used to adjust RX clock phase
- * at GMII/ RGMII interface */
- value = phy_read(phydev, 16);
- value |= 0x3;
+ c = ip1xx_reset(phydev);
+ if (c < 0)
+ return c;
- return phy_write(phydev, 16, value);
+ /* Enable Auto Power Saving mode */
+ c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS);
+ c |= IP101A_APS_ON;
+ return c;
}
static int ip175c_read_status(struct phy_device *phydev)
@@ -158,6 +199,20 @@ static struct phy_driver ip1001_driver = {
.driver = { .owner = THIS_MODULE,},
};
+static struct phy_driver ip101a_driver = {
+ .phy_id = 0x02430c54,
+ .name = "ICPlus IP101A",
+ .phy_id_mask = 0x0ffffff0,
+ .features = PHY_BASIC_FEATURES | SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause,
+ .config_init = &ip101a_config_init,
+ .config_aneg = &genphy_config_aneg,
+ .read_status = &genphy_read_status,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .driver = { .owner = THIS_MODULE,},
+};
+
static int __init icplus_init(void)
{
int ret = 0;
@@ -166,12 +221,17 @@ static int __init icplus_init(void)
if (ret < 0)
return -ENODEV;
+ ret = phy_driver_register(&ip101a_driver);
+ if (ret < 0)
+ return -ENODEV;
+
return phy_driver_register(&ip175c_driver);
}
static void __exit icplus_exit(void)
{
phy_driver_unregister(&ip1001_driver);
+ phy_driver_unregister(&ip101a_driver);
phy_driver_unregister(&ip175c_driver);
}
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
index 47c8339a0359..2843c90f712f 100644
--- a/drivers/net/phy/mdio-gpio.c
+++ b/drivers/net/phy/mdio-gpio.c
@@ -241,7 +241,7 @@ MODULE_DEVICE_TABLE(of, mdio_ofgpio_match);
static struct platform_driver mdio_ofgpio_driver = {
.driver = {
- .name = "mdio-gpio",
+ .name = "mdio-ofgpio",
.owner = THIS_MODULE,
.of_match_table = mdio_ofgpio_match,
},
diff --git a/drivers/net/phy/national.c b/drivers/net/phy/national.c
index 0620ba963508..04bb8fcc0cb5 100644
--- a/drivers/net/phy/national.c
+++ b/drivers/net/phy/national.c
@@ -25,8 +25,9 @@
/* DP83865 phy identifier values */
#define DP83865_PHY_ID 0x20005c7a
-#define DP83865_INT_MASK_REG 0x15
-#define DP83865_INT_MASK_STATUS 0x14
+#define DP83865_INT_STATUS 0x14
+#define DP83865_INT_MASK 0x15
+#define DP83865_INT_CLEAR 0x17
#define DP83865_INT_REMOTE_FAULT 0x0008
#define DP83865_INT_ANE_COMPLETED 0x0010
@@ -68,21 +69,25 @@ static int ns_config_intr(struct phy_device *phydev)
int err;
if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
- err = phy_write(phydev, DP83865_INT_MASK_REG,
+ err = phy_write(phydev, DP83865_INT_MASK,
DP83865_INT_MASK_DEFAULT);
else
- err = phy_write(phydev, DP83865_INT_MASK_REG, 0);
+ err = phy_write(phydev, DP83865_INT_MASK, 0);
return err;
}
static int ns_ack_interrupt(struct phy_device *phydev)
{
- int ret = phy_read(phydev, DP83865_INT_MASK_STATUS);
+ int ret = phy_read(phydev, DP83865_INT_STATUS);
if (ret < 0)
return ret;
- return 0;
+ /* Clear the interrupt status bit by writing a “1â€
+ * to the corresponding bit in INT_CLEAR (2:0 are reserved) */
+ ret = phy_write(phydev, DP83865_INT_CLEAR, ret & ~0x7);
+
+ return ret;
}
static void ns_giga_speed_fallback(struct phy_device *phydev, int mode)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index ff109fe5af6b..83a5a5afec67 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -213,7 +213,7 @@ int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id)
/* Grab the bits from PHYIR1, and put them
* in the upper half */
- phy_reg = bus->read(bus, addr, MII_PHYSID1);
+ phy_reg = mdiobus_read(bus, addr, MII_PHYSID1);
if (phy_reg < 0)
return -EIO;
@@ -221,7 +221,7 @@ int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id)
*phy_id = (phy_reg & 0xffff) << 16;
/* Grab the bits from PHYIR2, and put them in the lower half */
- phy_reg = bus->read(bus, addr, MII_PHYSID2);
+ phy_reg = mdiobus_read(bus, addr, MII_PHYSID2);
if (phy_reg < 0)
return -EIO;
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c
index 5d8f6e17bd55..0ec8e09cc2ac 100644
--- a/drivers/net/phy/vitesse.c
+++ b/drivers/net/phy/vitesse.c
@@ -3,7 +3,7 @@
*
* Author: Kriston Carson
*
- * Copyright (c) 2005 Freescale Semiconductor, Inc.
+ * Copyright (c) 2005, 2009 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -61,32 +61,42 @@ MODULE_DESCRIPTION("Vitesse PHY driver");
MODULE_AUTHOR("Kriston Carson");
MODULE_LICENSE("GPL");
-static int vsc824x_config_init(struct phy_device *phydev)
+int vsc824x_add_skew(struct phy_device *phydev)
{
- int extcon;
int err;
-
- err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT,
- MII_VSC8244_AUXCONSTAT_INIT);
- if (err < 0)
- return err;
+ int extcon;
extcon = phy_read(phydev, MII_VSC8244_EXT_CON1);
if (extcon < 0)
- return err;
+ return extcon;
extcon &= ~(MII_VSC8244_EXTCON1_TX_SKEW_MASK |
MII_VSC8244_EXTCON1_RX_SKEW_MASK);
- if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
- extcon |= (MII_VSC8244_EXTCON1_TX_SKEW |
- MII_VSC8244_EXTCON1_RX_SKEW);
+ extcon |= (MII_VSC8244_EXTCON1_TX_SKEW |
+ MII_VSC8244_EXTCON1_RX_SKEW);
err = phy_write(phydev, MII_VSC8244_EXT_CON1, extcon);
return err;
}
+EXPORT_SYMBOL(vsc824x_add_skew);
+
+static int vsc824x_config_init(struct phy_device *phydev)
+{
+ int err;
+
+ err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT,
+ MII_VSC8244_AUXCONSTAT_INIT);
+ if (err < 0)
+ return err;
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+ err = vsc824x_add_skew(phydev);
+
+ return err;
+}
static int vsc824x_ack_interrupt(struct phy_device *phydev)
{
diff --git a/drivers/net/plip/Kconfig b/drivers/net/plip/Kconfig
new file mode 100644
index 000000000000..80c4a3373e51
--- /dev/null
+++ b/drivers/net/plip/Kconfig
@@ -0,0 +1,38 @@
+#
+# Parallel Line Internet Protocol (PLIP) network device configuration
+#
+
+config PLIP
+ tristate "PLIP (parallel port) support"
+ depends on PARPORT
+ ---help---
+ PLIP (Parallel Line Internet Protocol) is used to create a
+ reasonably fast mini network consisting of two (or, rarely, more)
+ local machines. A PLIP link from a Linux box is a popular means to
+ install a Linux distribution on a machine which doesn't have a
+ CD-ROM drive (a minimal system has to be transferred with floppies
+ first). The kernels on both machines need to have this PLIP option
+ enabled for this to work.
+
+ The PLIP driver has two modes, mode 0 and mode 1. The parallel
+ ports (the connectors at the computers with 25 holes) are connected
+ with "null printer" or "Turbo Laplink" cables which can transmit 4
+ bits at a time (mode 0) or with special PLIP cables, to be used on
+ bidirectional parallel ports only, which can transmit 8 bits at a
+ time (mode 1); you can find the wiring of these cables in
+ <file:Documentation/networking/PLIP.txt>. The cables can be up to
+ 15m long. Mode 0 works also if one of the machines runs DOS/Windows
+ and has some PLIP software installed, e.g. the Crynwr PLIP packet
+ driver (<http://oak.oakland.edu/simtel.net/msdos/pktdrvr-pre.html>)
+ and winsock or NCSA's telnet.
+
+ If you want to use PLIP, say Y and read the PLIP mini-HOWTO as well
+ as the NET-3-HOWTO, both available from
+ <http://www.tldp.org/docs.html#howto>. Note that the PLIP
+ protocol has been changed and this PLIP driver won't work together
+ with the PLIP support in Linux versions 1.0.x. This option enlarges
+ your kernel by about 8 KB.
+
+ To compile this driver as a module, choose M here. The module
+ will be called plip. If unsure, say Y or M, in case you buy
+ a laptop later.
diff --git a/drivers/net/plip/Makefile b/drivers/net/plip/Makefile
new file mode 100644
index 000000000000..ed958796dc64
--- /dev/null
+++ b/drivers/net/plip/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the PLIP network device drivers.
+#
+
+obj-$(CONFIG_PLIP) += plip.o
diff --git a/drivers/net/plip.c b/drivers/net/plip/plip.c
index a9e9ca8a86ed..a9e9ca8a86ed 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip/plip.c
diff --git a/drivers/net/ppp/Kconfig b/drivers/net/ppp/Kconfig
new file mode 100644
index 000000000000..872df3ef07a6
--- /dev/null
+++ b/drivers/net/ppp/Kconfig
@@ -0,0 +1,175 @@
+#
+# PPP network device configuration
+#
+
+config PPP
+ tristate "PPP (point-to-point protocol) support"
+ select SLHC
+ ---help---
+ PPP (Point to Point Protocol) is a newer and better SLIP. It serves
+ the same purpose: sending Internet traffic over telephone (and other
+ serial) lines. Ask your access provider if they support it, because
+ otherwise you can't use it; most Internet access providers these
+ days support PPP rather than SLIP.
+
+ To use PPP, you need an additional program called pppd as described
+ in the PPP-HOWTO, available at
+ <http://www.tldp.org/docs.html#howto>. Make sure that you have
+ the version of pppd recommended in <file:Documentation/Changes>.
+ The PPP option enlarges your kernel by about 16 KB.
+
+ There are actually two versions of PPP: the traditional PPP for
+ asynchronous lines, such as regular analog phone lines, and
+ synchronous PPP which can be used over digital ISDN lines for
+ example. If you want to use PPP over phone lines or other
+ asynchronous serial lines, you need to say Y (or M) here and also to
+ the next option, "PPP support for async serial ports". For PPP over
+ synchronous lines, you should say Y (or M) here and to "Support
+ synchronous PPP", below.
+
+ If you said Y to "Version information on all symbols" above, then
+ you cannot compile the PPP driver into the kernel; you can then only
+ compile it as a module. To compile this driver as a module, choose M
+ here. The module will be called ppp_generic.
+
+if PPP
+
+config PPP_BSDCOMP
+ tristate "PPP BSD-Compress compression"
+ depends on PPP
+ ---help---
+ Support for the BSD-Compress compression method for PPP, which uses
+ the LZW compression method to compress each PPP packet before it is
+ sent over the wire. The machine at the other end of the PPP link
+ (usually your ISP) has to support the BSD-Compress compression
+ method as well for this to be useful. Even if they don't support it,
+ it is safe to say Y here.
+
+ The PPP Deflate compression method ("PPP Deflate compression",
+ above) is preferable to BSD-Compress, because it compresses better
+ and is patent-free.
+
+ Note that the BSD compression code will always be compiled as a
+ module; it is called bsd_comp and will show up in the directory
+ modules once you have said "make modules". If unsure, say N.
+
+config PPP_DEFLATE
+ tristate "PPP Deflate compression"
+ depends on PPP
+ select ZLIB_INFLATE
+ select ZLIB_DEFLATE
+ ---help---
+ Support for the Deflate compression method for PPP, which uses the
+ Deflate algorithm (the same algorithm that gzip uses) to compress
+ each PPP packet before it is sent over the wire. The machine at the
+ other end of the PPP link (usually your ISP) has to support the
+ Deflate compression method as well for this to be useful. Even if
+ they don't support it, it is safe to say Y here.
+
+ To compile this driver as a module, choose M here.
+
+config PPP_FILTER
+ bool "PPP filtering"
+ depends on PPP
+ ---help---
+ Say Y here if you want to be able to filter the packets passing over
+ PPP interfaces. This allows you to control which packets count as
+ activity (i.e. which packets will reset the idle timer or bring up
+ a demand-dialed link) and which packets are to be dropped entirely.
+ You need to say Y here if you wish to use the pass-filter and
+ active-filter options to pppd.
+
+ If unsure, say N.
+
+config PPP_MPPE
+ tristate "PPP MPPE compression (encryption) (EXPERIMENTAL)"
+ depends on PPP && EXPERIMENTAL
+ select CRYPTO
+ select CRYPTO_SHA1
+ select CRYPTO_ARC4
+ select CRYPTO_ECB
+ ---help---
+ Support for the MPPE Encryption protocol, as employed by the
+ Microsoft Point-to-Point Tunneling Protocol.
+
+ See http://pptpclient.sourceforge.net/ for information on
+ configuring PPTP clients and servers to utilize this method.
+
+config PPP_MULTILINK
+ bool "PPP multilink support (EXPERIMENTAL)"
+ depends on PPP && EXPERIMENTAL
+ ---help---
+ PPP multilink is a protocol (defined in RFC 1990) which allows you
+ to combine several (logical or physical) lines into one logical PPP
+ connection, so that you can utilize your full bandwidth.
+
+ This has to be supported at the other end as well and you need a
+ version of the pppd daemon which understands the multilink protocol.
+
+ If unsure, say N.
+
+config PPPOATM
+ tristate "PPP over ATM"
+ depends on ATM && PPP
+ ---help---
+ Support PPP (Point to Point Protocol) encapsulated in ATM frames.
+ This implementation does not yet comply with section 8 of RFC2364,
+ which can lead to bad results if the ATM peer loses state and
+ changes its encapsulation unilaterally.
+
+config PPPOE
+ tristate "PPP over Ethernet (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && PPP
+ ---help---
+ Support for PPP over Ethernet.
+
+ This driver requires the latest version of pppd from the CVS
+ repository at cvs.samba.org. Alternatively, see the
+ RoaringPenguin package (<http://www.roaringpenguin.com/pppoe>)
+ which contains instruction on how to use this driver (under
+ the heading "Kernel mode PPPoE").
+
+config PPTP
+ tristate "PPP over IPv4 (PPTP) (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && PPP && NET_IPGRE_DEMUX
+ ---help---
+ Support for PPP over IPv4.(Point-to-Point Tunneling Protocol)
+
+ This driver requires pppd plugin to work in client mode or
+ modified pptpd (poptop) to work in server mode.
+ See http://accel-pptp.sourceforge.net/ for information how to
+ utilize this module.
+
+config PPPOL2TP
+ tristate "PPP over L2TP (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && L2TP && PPP
+ ---help---
+ Support for PPP-over-L2TP socket family. L2TP is a protocol
+ used by ISPs and enterprises to tunnel PPP traffic over UDP
+ tunnels. L2TP is replacing PPTP for VPN uses.
+
+config PPP_ASYNC
+ tristate "PPP support for async serial ports"
+ depends on PPP
+ select CRC_CCITT
+ ---help---
+ Say Y (or M) here if you want to be able to use PPP over standard
+ asynchronous serial ports, such as COM1 or COM2 on a PC. If you use
+ a modem (not a synchronous or ISDN modem) to contact your ISP, you
+ need this option.
+
+ To compile this driver as a module, choose M here.
+
+ If unsure, say Y.
+
+config PPP_SYNC_TTY
+ tristate "PPP support for sync tty ports"
+ depends on PPP
+ ---help---
+ Say Y (or M) here if you want to be able to use PPP over synchronous
+ (HDLC) tty devices, such as the SyncLink adapter. These devices
+ are often used for high-speed leased lines like T1/E1.
+
+ To compile this driver as a module, choose M here.
+
+endif # PPP
diff --git a/drivers/net/ppp/Makefile b/drivers/net/ppp/Makefile
new file mode 100644
index 000000000000..a6b6297b0066
--- /dev/null
+++ b/drivers/net/ppp/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for the Linux PPP network device drivers.
+#
+
+obj-$(CONFIG_PPP) += ppp_generic.o
+obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
+obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o
+obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o
+obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o
+obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o
+obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
+obj-$(CONFIG_PPPOL2TP) += pppox.o
+obj-$(CONFIG_PPTP) += pppox.o pptp.o
diff --git a/drivers/net/bsd_comp.c b/drivers/net/ppp/bsd_comp.c
index a9b759add187..a9b759add187 100644
--- a/drivers/net/bsd_comp.c
+++ b/drivers/net/ppp/bsd_comp.c
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp/ppp_async.c
index c6ba64380829..c6ba64380829 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp/ppp_async.c
diff --git a/drivers/net/ppp_deflate.c b/drivers/net/ppp/ppp_deflate.c
index 1dbdf82a6dfd..1dbdf82a6dfd 100644
--- a/drivers/net/ppp_deflate.c
+++ b/drivers/net/ppp/ppp_deflate.c
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index 10e5d985afa3..edfa15d2e795 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -1465,7 +1465,12 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
continue;
}
- mtu = pch->chan->mtu - hdrlen;
+ /*
+ * hdrlen includes the 2-byte PPP protocol field, but the
+ * MTU counts only the payload excluding the protocol field.
+ * (RFC1661 Section 2)
+ */
+ mtu = pch->chan->mtu - (hdrlen - 2);
if (mtu < 4)
mtu = 4;
if (flen > mtu)
diff --git a/drivers/net/ppp_mppe.c b/drivers/net/ppp/ppp_mppe.c
index 9a1849a83e2a..9a1849a83e2a 100644
--- a/drivers/net/ppp_mppe.c
+++ b/drivers/net/ppp/ppp_mppe.c
diff --git a/drivers/net/ppp_mppe.h b/drivers/net/ppp/ppp_mppe.h
index 7a14e058c668..7a14e058c668 100644
--- a/drivers/net/ppp_mppe.h
+++ b/drivers/net/ppp/ppp_mppe.h
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c
index 736a39ee05bb..736a39ee05bb 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp/ppp_synctty.c
diff --git a/drivers/net/pppoe.c b/drivers/net/ppp/pppoe.c
index bc9a4bb31980..bc9a4bb31980 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
diff --git a/drivers/net/pppox.c b/drivers/net/ppp/pppox.c
index 8c0d170dabcd..8c0d170dabcd 100644
--- a/drivers/net/pppox.c
+++ b/drivers/net/ppp/pppox.c
diff --git a/drivers/net/pptp.c b/drivers/net/ppp/pptp.c
index eae542a7e987..89f829f5f725 100644
--- a/drivers/net/pptp.c
+++ b/drivers/net/ppp/pptp.c
@@ -285,8 +285,10 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
ip_send_check(iph);
ip_local_out(skb);
+ return 1;
tx_error:
+ kfree_skb(skb);
return 1;
}
@@ -305,11 +307,18 @@ static int pptp_rcv_core(struct sock *sk, struct sk_buff *skb)
}
header = (struct pptp_gre_header *)(skb->data);
+ headersize = sizeof(*header);
/* test if acknowledgement present */
if (PPTP_GRE_IS_A(header->ver)) {
- __u32 ack = (PPTP_GRE_IS_S(header->flags)) ?
- header->ack : header->seq; /* ack in different place if S = 0 */
+ __u32 ack;
+
+ if (!pskb_may_pull(skb, headersize))
+ goto drop;
+ header = (struct pptp_gre_header *)(skb->data);
+
+ /* ack in different place if S = 0 */
+ ack = PPTP_GRE_IS_S(header->flags) ? header->ack : header->seq;
ack = ntohl(ack);
@@ -318,21 +327,18 @@ static int pptp_rcv_core(struct sock *sk, struct sk_buff *skb)
/* also handle sequence number wrap-around */
if (WRAPPED(ack, opt->ack_recv))
opt->ack_recv = ack;
+ } else {
+ headersize -= sizeof(header->ack);
}
-
/* test if payload present */
if (!PPTP_GRE_IS_S(header->flags))
goto drop;
- headersize = sizeof(*header);
payload_len = ntohs(header->payload_len);
seq = ntohl(header->seq);
- /* no ack present? */
- if (!PPTP_GRE_IS_A(header->ver))
- headersize -= sizeof(header->ack);
/* check for incomplete packet (length smaller than expected) */
- if (skb->len - headersize < payload_len)
+ if (!pskb_may_pull(skb, headersize + payload_len))
goto drop;
payload = skb->data + headersize;
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
index 86ac38c96bcf..3bb131137033 100644
--- a/drivers/net/rionet.c
+++ b/drivers/net/rionet.c
@@ -80,13 +80,13 @@ static int rionet_capable = 1;
*/
static struct rio_dev **rionet_active;
-#define is_rionet_capable(pef, src_ops, dst_ops) \
- ((pef & RIO_PEF_INB_MBOX) && \
- (pef & RIO_PEF_INB_DOORBELL) && \
+#define is_rionet_capable(src_ops, dst_ops) \
+ ((src_ops & RIO_SRC_OPS_DATA_MSG) && \
+ (dst_ops & RIO_DST_OPS_DATA_MSG) && \
(src_ops & RIO_SRC_OPS_DOORBELL) && \
(dst_ops & RIO_DST_OPS_DOORBELL))
#define dev_rionet_capable(dev) \
- is_rionet_capable(dev->pef, dev->src_ops, dev->dst_ops)
+ is_rionet_capable(dev->src_ops, dev->dst_ops)
#define RIONET_MAC_MATCH(x) (*(u32 *)x == 0x00010001)
#define RIONET_GET_DESTID(x) (*(u16 *)(x + 4))
@@ -282,7 +282,6 @@ static int rionet_open(struct net_device *ndev)
{
int i, rc = 0;
struct rionet_peer *peer, *tmp;
- u32 pwdcsr;
struct rionet_private *rnet = netdev_priv(ndev);
if (netif_msg_ifup(rnet))
@@ -332,13 +331,8 @@ static int rionet_open(struct net_device *ndev)
continue;
}
- /*
- * If device has initialized inbound doorbells,
- * send a join message
- */
- rio_read_config_32(peer->rdev, RIO_WRITE_PORT_CSR, &pwdcsr);
- if (pwdcsr & RIO_DOORBELL_AVAIL)
- rio_send_doorbell(peer->rdev, RIONET_DOORBELL_JOIN);
+ /* Send a join message */
+ rio_send_doorbell(peer->rdev, RIONET_DOORBELL_JOIN);
}
out:
@@ -492,7 +486,7 @@ static int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev)
static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id)
{
int rc = -ENODEV;
- u32 lpef, lsrc_ops, ldst_ops;
+ u32 lsrc_ops, ldst_ops;
struct rionet_peer *peer;
struct net_device *ndev = NULL;
@@ -515,12 +509,11 @@ static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id)
* on later probes
*/
if (!rionet_check) {
- rio_local_read_config_32(rdev->net->hport, RIO_PEF_CAR, &lpef);
rio_local_read_config_32(rdev->net->hport, RIO_SRC_OPS_CAR,
&lsrc_ops);
rio_local_read_config_32(rdev->net->hport, RIO_DST_OPS_CAR,
&ldst_ops);
- if (!is_rionet_capable(lpef, lsrc_ops, ldst_ops)) {
+ if (!is_rionet_capable(lsrc_ops, ldst_ops)) {
printk(KERN_ERR
"%s: local device is not network capable\n",
DRV_NAME);
diff --git a/drivers/net/slip/Kconfig b/drivers/net/slip/Kconfig
new file mode 100644
index 000000000000..211b160e4e9c
--- /dev/null
+++ b/drivers/net/slip/Kconfig
@@ -0,0 +1,79 @@
+#
+# SLIP network device configuration
+#
+
+config SLIP
+ tristate "SLIP (serial line) support"
+ ---help---
+ Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to
+ connect to your Internet service provider or to connect to some
+ other local Unix box or if you want to configure your Linux box as a
+ Slip/CSlip server for other people to dial in. SLIP (Serial Line
+ Internet Protocol) is a protocol used to send Internet traffic over
+ serial connections such as telephone lines or null modem cables;
+ nowadays, the protocol PPP is more commonly used for this same
+ purpose.
+
+ Normally, your access provider has to support SLIP in order for you
+ to be able to use it, but there is now a SLIP emulator called SLiRP
+ around (available from
+ <ftp://ibiblio.org/pub/Linux/system/network/serial/>) which
+ allows you to use SLIP over a regular dial up shell connection. If
+ you plan to use SLiRP, make sure to say Y to CSLIP, below. The
+ NET-3-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>, explains how to
+ configure SLIP. Note that you don't need this option if you just
+ want to run term (term is a program which gives you almost full
+ Internet connectivity if you have a regular dial up shell account on
+ some Internet connected Unix computer. Read
+ <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>). SLIP
+ support will enlarge your kernel by about 4 KB. If unsure, say N.
+
+ To compile this driver as a module, choose M here. The module
+ will be called slip.
+
+config SLHC
+ tristate
+ ---help---
+ This option enables Van Jacobsen serial line header compression
+ routines.
+
+if SLIP
+
+config SLIP_COMPRESSED
+ bool "CSLIP compressed headers"
+ depends on SLIP
+ select SLHC
+ ---help---
+ This protocol is faster than SLIP because it uses compression on the
+ TCP/IP headers (not on the data itself), but it has to be supported
+ on both ends. Ask your access provider if you are not sure and
+ answer Y, just in case. You will still be able to use plain SLIP. If
+ you plan to use SLiRP, the SLIP emulator (available from
+ <ftp://ibiblio.org/pub/Linux/system/network/serial/>) which
+ allows you to use SLIP over a regular dial up shell connection, you
+ definitely want to say Y here. The NET-3-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>, explains how to configure
+ CSLIP. This won't enlarge your kernel.
+
+config SLIP_SMART
+ bool "Keepalive and linefill"
+ depends on SLIP
+ ---help---
+ Adds additional capabilities to the SLIP driver to support the
+ RELCOM line fill and keepalive monitoring. Ideal on poor quality
+ analogue lines.
+
+config SLIP_MODE_SLIP6
+ bool "Six bit SLIP encapsulation"
+ depends on SLIP
+ ---help---
+ Just occasionally you may need to run IP over hostile serial
+ networks that don't pass all control characters or are only seven
+ bit. Saying Y here adds an extra mode you can use with SLIP:
+ "slip6". In this mode, SLIP will only send normal ASCII symbols over
+ the serial device. Naturally, this has to be supported at the other
+ end of the link as well. It's good enough, for example, to run IP
+ over the async ports of a Camtec JNT Pad. If unsure, say N.
+
+endif # SLIP
diff --git a/drivers/net/slip/Makefile b/drivers/net/slip/Makefile
new file mode 100644
index 000000000000..e3ebc59e6fb9
--- /dev/null
+++ b/drivers/net/slip/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the SLIP network device drivers.
+#
+
+obj-$(CONFIG_SLIP) += slip.o
+obj-$(CONFIG_SLHC) += slhc.o
diff --git a/drivers/net/slhc.c b/drivers/net/slip/slhc.c
index 0a0a6643cf3a..0a0a6643cf3a 100644
--- a/drivers/net/slhc.c
+++ b/drivers/net/slip/slhc.c
diff --git a/drivers/net/slip.c b/drivers/net/slip/slip.c
index 4c617534f937..ba08341fb92c 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip/slip.c
@@ -562,34 +562,33 @@ static struct rtnl_link_stats64 *
sl_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
{
struct net_device_stats *devstats = &dev->stats;
- unsigned long c_rx_dropped = 0;
#ifdef SL_INCLUDE_CSLIP
- unsigned long c_rx_fifo_errors = 0;
- unsigned long c_tx_fifo_errors = 0;
- unsigned long c_collisions = 0;
struct slip *sl = netdev_priv(dev);
struct slcompress *comp = sl->slcomp;
-
- if (comp) {
- c_rx_fifo_errors = comp->sls_i_compressed;
- c_rx_dropped = comp->sls_i_tossed;
- c_tx_fifo_errors = comp->sls_o_compressed;
- c_collisions = comp->sls_o_misses;
- }
- stats->rx_fifo_errors = sl->rx_compressed + c_rx_fifo_errors;
- stats->tx_fifo_errors = sl->tx_compressed + c_tx_fifo_errors;
- stats->collisions = sl->tx_misses + c_collisions;
#endif
stats->rx_packets = devstats->rx_packets;
stats->tx_packets = devstats->tx_packets;
stats->rx_bytes = devstats->rx_bytes;
stats->tx_bytes = devstats->tx_bytes;
- stats->rx_dropped = devstats->rx_dropped + c_rx_dropped;
+ stats->rx_dropped = devstats->rx_dropped;
stats->tx_dropped = devstats->tx_dropped;
stats->tx_errors = devstats->tx_errors;
stats->rx_errors = devstats->rx_errors;
stats->rx_over_errors = devstats->rx_over_errors;
+#ifdef SL_INCLUDE_CSLIP
+ if (comp) {
+ /* Generic compressed statistics */
+ stats->rx_compressed = comp->sls_i_compressed;
+ stats->tx_compressed = comp->sls_o_compressed;
+
+ /* Are we really still needs this? */
+ stats->rx_fifo_errors += comp->sls_i_compressed;
+ stats->rx_dropped += comp->sls_i_tossed;
+ stats->tx_fifo_errors += comp->sls_o_compressed;
+ stats->collisions += comp->sls_o_misses;
+ }
+#endif
return stats;
}
diff --git a/drivers/net/slip.h b/drivers/net/slip/slip.h
index aa0764ce2342..67673cf1266b 100644
--- a/drivers/net/slip.h
+++ b/drivers/net/slip/slip.h
@@ -65,15 +65,6 @@ struct slip {
unsigned char *xbuff; /* transmitter buffer */
unsigned char *xhead; /* pointer to next byte to XMIT */
int xleft; /* bytes left in XMIT queue */
-
- /* SLIP interface statistics. */
-#ifdef SL_INCLUDE_CSLIP
- unsigned long tx_compressed;
- unsigned long rx_compressed;
- unsigned long tx_misses;
-#endif
- /* Detailed SLIP statistics. */
-
int mtu; /* Our mtu (to spot changes!) */
int buffsize; /* Max buffers sizes */
diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c
index d16880d7099b..58f13adaa549 100644
--- a/drivers/net/sungem_phy.c
+++ b/drivers/net/sungem_phy.c
@@ -33,7 +33,7 @@
#include <asm/prom.h>
#endif
-#include "sungem_phy.h"
+#include <linux/sungem_phy.h>
/* Link modes of the BCM5400 PHY */
static const int phy_BCM5400_link_table[8][3] = {
@@ -1156,7 +1156,7 @@ static struct mii_phy_def* mii_phy_table[] = {
NULL
};
-int mii_phy_probe(struct mii_phy *phy, int mii_id)
+int sungem_phy_probe(struct mii_phy *phy, int mii_id)
{
int rc;
u32 id;
@@ -1195,6 +1195,5 @@ fail:
return -ENODEV;
}
-EXPORT_SYMBOL(mii_phy_probe);
+EXPORT_SYMBOL(sungem_phy_probe);
MODULE_LICENSE("GPL");
-
diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c
index b6162fe2348e..ef9fdf3652f6 100644
--- a/drivers/net/tokenring/3c359.c
+++ b/drivers/net/tokenring/3c359.c
@@ -282,7 +282,7 @@ static const struct net_device_ops xl_netdev_ops = {
.ndo_stop = xl_close,
.ndo_start_xmit = xl_xmit,
.ndo_change_mtu = xl_change_mtu,
- .ndo_set_multicast_list = xl_set_rx_mode,
+ .ndo_set_rx_mode = xl_set_rx_mode,
.ndo_set_mac_address = xl_set_mac_address,
};
diff --git a/drivers/net/tokenring/Kconfig b/drivers/net/tokenring/Kconfig
index c4137b0f808e..c7e0149d1514 100644
--- a/drivers/net/tokenring/Kconfig
+++ b/drivers/net/tokenring/Kconfig
@@ -4,9 +4,9 @@
# So far, we only have PCI, ISA, and MCA token ring devices
menuconfig TR
- tristate "Token Ring driver support"
+ bool "Token Ring driver support"
depends on NETDEVICES && !UML
- depends on (PCI || ISA || MCA || CCW)
+ depends on (PCI || ISA || MCA || CCW || PCMCIA)
select LLC
help
Token Ring is IBM's way of communication on a local network; the
@@ -20,6 +20,17 @@ menuconfig TR
if TR
+config PCMCIA_IBMTR
+ tristate "IBM PCMCIA tokenring adapter support"
+ depends on IBMTR!=y && PCMCIA
+ ---help---
+ Say Y here if you intend to attach this type of Token Ring PCMCIA
+ card to your computer. You then also need to say Y to "Token Ring
+ driver support".
+
+ To compile this driver as a module, choose M here: the module will be
+ called ibmtr_cs.
+
config IBMTR
tristate "IBM Tropic chipset based adapter support"
depends on ISA || MCA
diff --git a/drivers/net/tokenring/Makefile b/drivers/net/tokenring/Makefile
index c88b0a5e5380..f1be8d97b7a8 100644
--- a/drivers/net/tokenring/Makefile
+++ b/drivers/net/tokenring/Makefile
@@ -2,14 +2,15 @@
# Makefile for drivers/net/tokenring
#
-obj-$(CONFIG_IBMTR) += ibmtr.o
-obj-$(CONFIG_IBMOL) += olympic.o
-obj-$(CONFIG_IBMLS) += lanstreamer.o
-obj-$(CONFIG_TMS380TR) += tms380tr.o
-obj-$(CONFIG_ABYSS) += abyss.o
-obj-$(CONFIG_MADGEMC) += madgemc.o
-obj-$(CONFIG_PROTEON) += proteon.o
-obj-$(CONFIG_TMSPCI) += tmspci.o
-obj-$(CONFIG_SKISA) += skisa.o
-obj-$(CONFIG_SMCTR) += smctr.o
+obj-$(CONFIG_PCMCIA_IBMTR) += ibmtr_cs.o
+obj-$(CONFIG_IBMTR) += ibmtr.o
+obj-$(CONFIG_IBMOL) += olympic.o
+obj-$(CONFIG_IBMLS) += lanstreamer.o
+obj-$(CONFIG_TMS380TR) += tms380tr.o
+obj-$(CONFIG_ABYSS) += abyss.o
+obj-$(CONFIG_MADGEMC) += madgemc.o
+obj-$(CONFIG_PROTEON) += proteon.o
+obj-$(CONFIG_TMSPCI) += tmspci.o
+obj-$(CONFIG_SKISA) += skisa.o
+obj-$(CONFIG_SMCTR) += smctr.o
obj-$(CONFIG_3C359) += 3c359.o
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index e257a00fe14b..b5c8c18f5046 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -823,7 +823,7 @@ static const struct net_device_ops trdev_netdev_ops = {
.ndo_open = tok_open,
.ndo_stop = tok_close,
.ndo_start_xmit = tok_send_packet,
- .ndo_set_multicast_list = tok_set_multicast_list,
+ .ndo_set_rx_mode = tok_set_multicast_list,
.ndo_change_mtu = ibmtr_change_mtu,
};
diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/tokenring/ibmtr_cs.c
index 6006d5488fbe..91b684630fc5 100644
--- a/drivers/net/pcmcia/ibmtr_cs.c
+++ b/drivers/net/tokenring/ibmtr_cs.c
@@ -66,7 +66,7 @@
#include <asm/system.h>
#define PCMCIA
-#include "../tokenring/ibmtr.c"
+#include "ibmtr.c"
/*====================================================================*/
diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
index 9354ca9da576..8d71e0d29062 100644
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -231,7 +231,7 @@ static const struct net_device_ops streamer_netdev_ops = {
#if STREAMER_IOCTL
.ndo_do_ioctl = streamer_ioctl,
#endif
- .ndo_set_multicast_list = streamer_set_rx_mode,
+ .ndo_set_rx_mode = streamer_set_rx_mode,
.ndo_set_mac_address = streamer_set_mac_address,
};
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index e3855aeb13d4..fd8dce90c957 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -201,7 +201,7 @@ static const struct net_device_ops olympic_netdev_ops = {
.ndo_stop = olympic_close,
.ndo_start_xmit = olympic_xmit,
.ndo_change_mtu = olympic_change_mtu,
- .ndo_set_multicast_list = olympic_set_rx_mode,
+ .ndo_set_rx_mode = olympic_set_rx_mode,
.ndo_set_mac_address = olympic_set_mac_address,
};
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index d9044aba7afa..029846a98636 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -3623,7 +3623,7 @@ static const struct net_device_ops smctr_netdev_ops = {
.ndo_start_xmit = smctr_send_packet,
.ndo_tx_timeout = smctr_timeout,
.ndo_get_stats = smctr_get_stats,
- .ndo_set_multicast_list = smctr_set_multicast_list,
+ .ndo_set_rx_mode = smctr_set_multicast_list,
};
static int __init smctr_probe1(struct net_device *dev, int ioaddr)
diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c
index 793020347e54..65e9cf3a71fe 100644
--- a/drivers/net/tokenring/tms380tr.c
+++ b/drivers/net/tokenring/tms380tr.c
@@ -2289,7 +2289,7 @@ const struct net_device_ops tms380tr_netdev_ops = {
.ndo_start_xmit = tms380tr_send_packet,
.ndo_tx_timeout = tms380tr_timeout,
.ndo_get_stats = tms380tr_get_stats,
- .ndo_set_multicast_list = tms380tr_set_multicast_list,
+ .ndo_set_rx_mode = tms380tr_set_multicast_list,
.ndo_set_mac_address = tms380tr_set_mac_address,
};
EXPORT_SYMBOL(tms380tr_netdev_ops);
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 71f3d1a35b74..7bea9c65119e 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -496,7 +496,7 @@ static const struct net_device_ops tap_netdev_ops = {
.ndo_start_xmit = tun_net_xmit,
.ndo_change_mtu = tun_net_change_mtu,
.ndo_fix_features = tun_net_fix_features,
- .ndo_set_multicast_list = tun_net_mclist,
+ .ndo_set_rx_mode = tun_net_mclist,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
#ifdef CONFIG_NET_POLL_CONTROLLER
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 84d4608153c9..233576127934 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -68,6 +68,7 @@ config USB_KAWETH
config USB_PEGASUS
tristate "USB Pegasus/Pegasus-II based ethernet device support"
+ select NET_CORE
select MII
---help---
Say Y here if you know you have Pegasus or Pegasus-II based adapter.
@@ -84,6 +85,7 @@ config USB_PEGASUS
config USB_RTL8150
tristate "USB RTL8150 based ethernet device support (EXPERIMENTAL)"
depends on EXPERIMENTAL
+ select NET_CORE
select MII
help
Say Y here if you have RTL8150 based usb-ethernet adapter.
@@ -95,6 +97,7 @@ config USB_RTL8150
config USB_USBNET
tristate "Multi-purpose USB Networking Framework"
+ select NET_CORE
select MII
---help---
This driver supports several kinds of network links over USB,
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index c5c4b4def7fb..e81e22e3d1d2 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -36,8 +36,8 @@
#include <linux/usb/usbnet.h>
#include <linux/slab.h>
-#define DRIVER_VERSION "14-Jun-2006"
-static const char driver_name [] = "asix";
+#define DRIVER_VERSION "26-Sep-2011"
+#define DRIVER_NAME "asix"
/* ASIX AX8817X based USB 2.0 Ethernet Devices */
@@ -115,28 +115,27 @@ static const char driver_name [] = "asix";
#define AX88178_MEDIUM_DEFAULT \
(AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \
AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \
- AX_MEDIUM_RE )
+ AX_MEDIUM_RE)
#define AX88772_MEDIUM_DEFAULT \
(AX_MEDIUM_FD | AX_MEDIUM_RFC | \
AX_MEDIUM_TFC | AX_MEDIUM_PS | \
- AX_MEDIUM_AC | AX_MEDIUM_RE )
+ AX_MEDIUM_AC | AX_MEDIUM_RE)
/* AX88772 & AX88178 RX_CTL values */
-#define AX_RX_CTL_SO 0x0080
-#define AX_RX_CTL_AP 0x0020
-#define AX_RX_CTL_AM 0x0010
-#define AX_RX_CTL_AB 0x0008
-#define AX_RX_CTL_SEP 0x0004
-#define AX_RX_CTL_AMALL 0x0002
-#define AX_RX_CTL_PRO 0x0001
-#define AX_RX_CTL_MFB_2048 0x0000
-#define AX_RX_CTL_MFB_4096 0x0100
-#define AX_RX_CTL_MFB_8192 0x0200
-#define AX_RX_CTL_MFB_16384 0x0300
-
-#define AX_DEFAULT_RX_CTL \
- (AX_RX_CTL_SO | AX_RX_CTL_AB )
+#define AX_RX_CTL_SO 0x0080
+#define AX_RX_CTL_AP 0x0020
+#define AX_RX_CTL_AM 0x0010
+#define AX_RX_CTL_AB 0x0008
+#define AX_RX_CTL_SEP 0x0004
+#define AX_RX_CTL_AMALL 0x0002
+#define AX_RX_CTL_PRO 0x0001
+#define AX_RX_CTL_MFB_2048 0x0000
+#define AX_RX_CTL_MFB_4096 0x0100
+#define AX_RX_CTL_MFB_8192 0x0200
+#define AX_RX_CTL_MFB_16384 0x0300
+
+#define AX_DEFAULT_RX_CTL (AX_RX_CTL_SO | AX_RX_CTL_AB)
/* GPIO 0 .. 2 toggles */
#define AX_GPIO_GPO0EN 0x01 /* GPIO0 Output enable */
@@ -164,6 +163,8 @@ static const char driver_name [] = "asix";
#define MARVELL_CTRL_TXDELAY 0x0002
#define MARVELL_CTRL_RXDELAY 0x0080
+#define PHY_MODE_RTL8211CL 0x0004
+
/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */
struct asix_data {
u8 multi_filter[AX_MCAST_FILTER_SIZE];
@@ -268,12 +269,15 @@ asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
netdev_dbg(dev->net, "asix_write_cmd_async() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n",
cmd, value, index, size);
- if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) {
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
netdev_err(dev->net, "Error allocating URB in write_cmd_async!\n");
return;
}
- if ((req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC)) == NULL) {
+ req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
+ if (!req) {
netdev_err(dev->net, "Failed to allocate memory for control request\n");
usb_free_urb(urb);
return;
@@ -290,7 +294,8 @@ asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
(void *)req, data, size,
asix_async_cmd_callback, req);
- if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status < 0) {
netdev_err(dev->net, "Error submitting the control message: status=%d\n",
status);
kfree(req);
@@ -531,11 +536,11 @@ static u16 asix_read_medium_status(struct usbnet *dev)
if (ret < 0) {
netdev_err(dev->net, "Error reading Medium Status register: %02x\n",
ret);
- goto out;
+ return ret; /* TODO: callers not checking for error ret */
}
- ret = le16_to_cpu(v);
-out:
- return ret;
+
+ return le16_to_cpu(v);
+
}
static int asix_write_medium_mode(struct usbnet *dev, u16 mode)
@@ -676,12 +681,6 @@ asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
}
wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
wolinfo->wolopts = 0;
- if (opt & AX_MONITOR_MODE) {
- if (opt & AX_MONITOR_LINK)
- wolinfo->wolopts |= WAKE_PHY;
- if (opt & AX_MONITOR_MAGIC)
- wolinfo->wolopts |= WAKE_MAGIC;
- }
}
static int
@@ -694,8 +693,6 @@ asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
opt |= AX_MONITOR_LINK;
if (wolinfo->wolopts & WAKE_MAGIC)
opt |= AX_MONITOR_MAGIC;
- if (opt != 0)
- opt |= AX_MONITOR_MODE;
if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE,
opt, 0, 0, NULL) < 0)
@@ -744,7 +741,7 @@ static void asix_get_drvinfo (struct net_device *net,
/* Inherit standard device info */
usbnet_get_drvinfo(net, info);
- strncpy (info->driver, driver_name, sizeof info->driver);
+ strncpy (info->driver, DRIVER_NAME, sizeof info->driver);
strncpy (info->version, DRIVER_VERSION, sizeof info->version);
info->eedump_len = data->eeprom_len;
}
@@ -872,7 +869,7 @@ static const struct net_device_ops ax88172_netdev_ops = {
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = asix_ioctl,
- .ndo_set_multicast_list = ax88172_set_multicast,
+ .ndo_set_rx_mode = ax88172_set_multicast,
};
static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
@@ -889,19 +886,20 @@ static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
/* Toggle the GPIOs in a manufacturer/model specific way */
for (i = 2; i >= 0; i--) {
- if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS,
- (gpio_bits >> (i * 8)) & 0xff, 0, 0,
- NULL)) < 0)
+ ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS,
+ (gpio_bits >> (i * 8)) & 0xff, 0, 0, NULL);
+ if (ret < 0)
goto out;
msleep(5);
}
- if ((ret = asix_write_rx_ctl(dev, 0x80)) < 0)
+ ret = asix_write_rx_ctl(dev, 0x80);
+ if (ret < 0)
goto out;
/* Get the MAC address */
- if ((ret = asix_read_cmd(dev, AX88172_CMD_READ_NODE_ID,
- 0, 0, ETH_ALEN, buf)) < 0) {
+ ret = asix_read_cmd(dev, AX88172_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf);
+ if (ret < 0) {
dbg("read AX_CMD_READ_NODE_ID failed: %d", ret);
goto out;
}
@@ -966,117 +964,88 @@ static int ax88772_link_reset(struct usbnet *dev)
return 0;
}
-static const struct net_device_ops ax88772_netdev_ops = {
- .ndo_open = usbnet_open,
- .ndo_stop = usbnet_stop,
- .ndo_start_xmit = usbnet_start_xmit,
- .ndo_tx_timeout = usbnet_tx_timeout,
- .ndo_change_mtu = usbnet_change_mtu,
- .ndo_set_mac_address = asix_set_mac_address,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_do_ioctl = asix_ioctl,
- .ndo_set_multicast_list = asix_set_multicast,
-};
-
-static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
+static int ax88772_reset(struct usbnet *dev)
{
int ret, embd_phy;
u16 rx_ctl;
- struct asix_data *data = (struct asix_data *)&dev->data;
- u8 buf[ETH_ALEN];
- u32 phyid;
- data->eeprom_len = AX88772_EEPROM_LEN;
-
- usbnet_get_endpoints(dev,intf);
-
- if ((ret = asix_write_gpio(dev,
- AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5)) < 0)
+ ret = asix_write_gpio(dev,
+ AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5);
+ if (ret < 0)
goto out;
- /* 0x10 is the phy id of the embedded 10/100 ethernet phy */
embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0);
- if ((ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT,
- embd_phy, 0, 0, NULL)) < 0) {
+
+ ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL);
+ if (ret < 0) {
dbg("Select PHY #1 failed: %d", ret);
goto out;
}
- if ((ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL)) < 0)
+ ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL);
+ if (ret < 0)
goto out;
msleep(150);
- if ((ret = asix_sw_reset(dev, AX_SWRESET_CLEAR)) < 0)
+
+ ret = asix_sw_reset(dev, AX_SWRESET_CLEAR);
+ if (ret < 0)
goto out;
msleep(150);
+
if (embd_phy) {
- if ((ret = asix_sw_reset(dev, AX_SWRESET_IPRL)) < 0)
+ ret = asix_sw_reset(dev, AX_SWRESET_IPRL);
+ if (ret < 0)
goto out;
- }
- else {
- if ((ret = asix_sw_reset(dev, AX_SWRESET_PRTE)) < 0)
+ } else {
+ ret = asix_sw_reset(dev, AX_SWRESET_PRTE);
+ if (ret < 0)
goto out;
}
msleep(150);
rx_ctl = asix_read_rx_ctl(dev);
dbg("RX_CTL is 0x%04x after software reset", rx_ctl);
- if ((ret = asix_write_rx_ctl(dev, 0x0000)) < 0)
+ ret = asix_write_rx_ctl(dev, 0x0000);
+ if (ret < 0)
goto out;
rx_ctl = asix_read_rx_ctl(dev);
dbg("RX_CTL is 0x%04x setting to 0x0000", rx_ctl);
- /* Get the MAC address */
- if ((ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID,
- 0, 0, ETH_ALEN, buf)) < 0) {
- dbg("Failed to read MAC address: %d", ret);
- goto out;
- }
- memcpy(dev->net->dev_addr, buf, ETH_ALEN);
-
- /* Initialize MII structure */
- dev->mii.dev = dev->net;
- dev->mii.mdio_read = asix_mdio_read;
- dev->mii.mdio_write = asix_mdio_write;
- dev->mii.phy_id_mask = 0x1f;
- dev->mii.reg_num_mask = 0x1f;
- dev->mii.phy_id = asix_get_phy_addr(dev);
-
- phyid = asix_get_phyid(dev);
- dbg("PHYID=0x%08x", phyid);
-
- if ((ret = asix_sw_reset(dev, AX_SWRESET_PRL)) < 0)
+ ret = asix_sw_reset(dev, AX_SWRESET_PRL);
+ if (ret < 0)
goto out;
msleep(150);
- if ((ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL)) < 0)
+ ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL);
+ if (ret < 0)
goto out;
msleep(150);
- dev->net->netdev_ops = &ax88772_netdev_ops;
- dev->net->ethtool_ops = &ax88772_ethtool_ops;
-
asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
ADVERTISE_ALL | ADVERTISE_CSMA);
mii_nway_restart(&dev->mii);
- if ((ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT)) < 0)
+ ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT);
+ if (ret < 0)
goto out;
- if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0,
+ ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0,
AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,
- AX88772_IPG2_DEFAULT, 0, NULL)) < 0) {
+ AX88772_IPG2_DEFAULT, 0, NULL);
+ if (ret < 0) {
dbg("Write IPG,IPG1,IPG2 failed: %d", ret);
goto out;
}
/* Set RX_CTL to default values with 2k buffer, and enable cactus */
- if ((ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL)) < 0)
+ ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL);
+ if (ret < 0)
goto out;
rx_ctl = asix_read_rx_ctl(dev);
@@ -1085,16 +1054,70 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
rx_ctl = asix_read_medium_status(dev);
dbg("Medium Status is 0x%04x after all initializations", rx_ctl);
+ return 0;
+
+out:
+ return ret;
+
+}
+
+static const struct net_device_ops ax88772_netdev_ops = {
+ .ndo_open = usbnet_open,
+ .ndo_stop = usbnet_stop,
+ .ndo_start_xmit = usbnet_start_xmit,
+ .ndo_tx_timeout = usbnet_tx_timeout,
+ .ndo_change_mtu = usbnet_change_mtu,
+ .ndo_set_mac_address = asix_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_do_ioctl = asix_ioctl,
+ .ndo_set_rx_mode = asix_set_multicast,
+};
+
+static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+ int ret;
+ struct asix_data *data = (struct asix_data *)&dev->data;
+ u8 buf[ETH_ALEN];
+ u32 phyid;
+
+ data->eeprom_len = AX88772_EEPROM_LEN;
+
+ usbnet_get_endpoints(dev,intf);
+
+ /* Get the MAC address */
+ ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf);
+ if (ret < 0) {
+ dbg("Failed to read MAC address: %d", ret);
+ return ret;
+ }
+ memcpy(dev->net->dev_addr, buf, ETH_ALEN);
+
+ /* Initialize MII structure */
+ dev->mii.dev = dev->net;
+ dev->mii.mdio_read = asix_mdio_read;
+ dev->mii.mdio_write = asix_mdio_write;
+ dev->mii.phy_id_mask = 0x1f;
+ dev->mii.reg_num_mask = 0x1f;
+ dev->mii.phy_id = asix_get_phy_addr(dev);
+
+ phyid = asix_get_phyid(dev);
+ dbg("PHYID=0x%08x", phyid);
+
+ dev->net->netdev_ops = &ax88772_netdev_ops;
+ dev->net->ethtool_ops = &ax88772_ethtool_ops;
+
+ ret = ax88772_reset(dev);
+ if (ret < 0)
+ return ret;
+
/* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
if (dev->driver_info->flags & FLAG_FRAMING_AX) {
/* hard_mtu is still the default - the device does not support
jumbo eth frames */
dev->rx_urb_size = 2048;
}
- return 0;
-out:
- return ret;
+ return 0;
}
static struct ethtool_ops ax88178_ethtool_ops = {
@@ -1143,6 +1166,27 @@ static int marvell_phy_init(struct usbnet *dev)
return 0;
}
+static int rtl8211cl_phy_init(struct usbnet *dev)
+{
+ struct asix_data *data = (struct asix_data *)&dev->data;
+
+ netdev_dbg(dev->net, "rtl8211cl_phy_init()\n");
+
+ asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0x0005);
+ asix_mdio_write (dev->net, dev->mii.phy_id, 0x0c, 0);
+ asix_mdio_write (dev->net, dev->mii.phy_id, 0x01,
+ asix_mdio_read (dev->net, dev->mii.phy_id, 0x01) | 0x0080);
+ asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0);
+
+ if (data->ledmode == 12) {
+ asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0x0002);
+ asix_mdio_write (dev->net, dev->mii.phy_id, 0x1a, 0x00cb);
+ asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0);
+ }
+
+ return 0;
+}
+
static int marvell_led_status(struct usbnet *dev, u16 speed)
{
u16 reg = asix_mdio_read(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL);
@@ -1169,6 +1213,79 @@ static int marvell_led_status(struct usbnet *dev, u16 speed)
return 0;
}
+static int ax88178_reset(struct usbnet *dev)
+{
+ struct asix_data *data = (struct asix_data *)&dev->data;
+ int ret;
+ __le16 eeprom;
+ u8 status;
+ int gpio0 = 0;
+
+ asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status);
+ dbg("GPIO Status: 0x%04x", status);
+
+ asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL);
+ asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom);
+ asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL);
+
+ dbg("EEPROM index 0x17 is 0x%04x", eeprom);
+
+ if (eeprom == cpu_to_le16(0xffff)) {
+ data->phymode = PHY_MODE_MARVELL;
+ data->ledmode = 0;
+ gpio0 = 1;
+ } else {
+ data->phymode = le16_to_cpu(eeprom) & 7;
+ data->ledmode = le16_to_cpu(eeprom) >> 8;
+ gpio0 = (le16_to_cpu(eeprom) & 0x80) ? 0 : 1;
+ }
+ dbg("GPIO0: %d, PhyMode: %d", gpio0, data->phymode);
+
+ asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40);
+ if ((le16_to_cpu(eeprom) >> 8) != 1) {
+ asix_write_gpio(dev, 0x003c, 30);
+ asix_write_gpio(dev, 0x001c, 300);
+ asix_write_gpio(dev, 0x003c, 30);
+ } else {
+ dbg("gpio phymode == 1 path");
+ asix_write_gpio(dev, AX_GPIO_GPO1EN, 30);
+ asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30);
+ }
+
+ asix_sw_reset(dev, 0);
+ msleep(150);
+
+ asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD);
+ msleep(150);
+
+ asix_write_rx_ctl(dev, 0);
+
+ if (data->phymode == PHY_MODE_MARVELL) {
+ marvell_phy_init(dev);
+ msleep(60);
+ } else if (data->phymode == PHY_MODE_RTL8211CL)
+ rtl8211cl_phy_init(dev);
+
+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR,
+ BMCR_RESET | BMCR_ANENABLE);
+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+ ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000,
+ ADVERTISE_1000FULL);
+
+ mii_nway_restart(&dev->mii);
+
+ ret = asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT);
+ if (ret < 0)
+ return ret;
+
+ ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
static int ax88178_link_reset(struct usbnet *dev)
{
u16 mode;
@@ -1270,67 +1387,27 @@ static const struct net_device_ops ax88178_netdev_ops = {
.ndo_tx_timeout = usbnet_tx_timeout,
.ndo_set_mac_address = asix_set_mac_address,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = asix_set_multicast,
+ .ndo_set_rx_mode = asix_set_multicast,
.ndo_do_ioctl = asix_ioctl,
.ndo_change_mtu = ax88178_change_mtu,
};
static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
{
- struct asix_data *data = (struct asix_data *)&dev->data;
int ret;
u8 buf[ETH_ALEN];
- __le16 eeprom;
- u8 status;
- int gpio0 = 0;
u32 phyid;
+ struct asix_data *data = (struct asix_data *)&dev->data;
- usbnet_get_endpoints(dev,intf);
-
- asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status);
- dbg("GPIO Status: 0x%04x", status);
-
- asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL);
- asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom);
- asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL);
-
- dbg("EEPROM index 0x17 is 0x%04x", eeprom);
-
- if (eeprom == cpu_to_le16(0xffff)) {
- data->phymode = PHY_MODE_MARVELL;
- data->ledmode = 0;
- gpio0 = 1;
- } else {
- data->phymode = le16_to_cpu(eeprom) & 7;
- data->ledmode = le16_to_cpu(eeprom) >> 8;
- gpio0 = (le16_to_cpu(eeprom) & 0x80) ? 0 : 1;
- }
- dbg("GPIO0: %d, PhyMode: %d", gpio0, data->phymode);
-
- asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40);
- if ((le16_to_cpu(eeprom) >> 8) != 1) {
- asix_write_gpio(dev, 0x003c, 30);
- asix_write_gpio(dev, 0x001c, 300);
- asix_write_gpio(dev, 0x003c, 30);
- } else {
- dbg("gpio phymode == 1 path");
- asix_write_gpio(dev, AX_GPIO_GPO1EN, 30);
- asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30);
- }
-
- asix_sw_reset(dev, 0);
- msleep(150);
-
- asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD);
- msleep(150);
+ data->eeprom_len = AX88772_EEPROM_LEN;
- asix_write_rx_ctl(dev, 0);
+ usbnet_get_endpoints(dev,intf);
/* Get the MAC address */
- if ((ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID,
- 0, 0, ETH_ALEN, buf)) < 0) {
+ ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf);
+ if (ret < 0) {
dbg("Failed to read MAC address: %d", ret);
- goto out;
+ return ret;
}
memcpy(dev->net->dev_addr, buf, ETH_ALEN);
@@ -1349,25 +1426,9 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
phyid = asix_get_phyid(dev);
dbg("PHYID=0x%08x", phyid);
- if (data->phymode == PHY_MODE_MARVELL) {
- marvell_phy_init(dev);
- msleep(60);
- }
-
- asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR,
- BMCR_RESET | BMCR_ANENABLE);
- asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
- ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
- asix_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000,
- ADVERTISE_1000FULL);
-
- mii_nway_restart(&dev->mii);
-
- if ((ret = asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT)) < 0)
- goto out;
-
- if ((ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL)) < 0)
- goto out;
+ ret = ax88178_reset(dev);
+ if (ret < 0)
+ return ret;
/* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
if (dev->driver_info->flags & FLAG_FRAMING_AX) {
@@ -1375,10 +1436,8 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
jumbo eth frames */
dev->rx_urb_size = 2048;
}
- return 0;
-out:
- return ret;
+ return 0;
}
static const struct driver_info ax8817x_info = {
@@ -1426,7 +1485,7 @@ static const struct driver_info ax88772_info = {
.bind = ax88772_bind,
.status = asix_status,
.link_reset = ax88772_link_reset,
- .reset = ax88772_link_reset,
+ .reset = ax88772_reset,
.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR,
.rx_fixup = asix_rx_fixup,
.tx_fixup = asix_tx_fixup,
@@ -1437,7 +1496,7 @@ static const struct driver_info ax88178_info = {
.bind = ax88178_bind,
.status = asix_status,
.link_reset = ax88178_link_reset,
- .reset = ax88178_link_reset,
+ .reset = ax88178_reset,
.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR,
.rx_fixup = asix_rx_fixup,
.tx_fixup = asix_tx_fixup,
@@ -1566,7 +1625,7 @@ static const struct usb_device_id products [] = {
MODULE_DEVICE_TABLE(usb, products);
static struct usb_driver asix_driver = {
- .name = "asix",
+ .name = DRIVER_NAME,
.id_table = products,
.probe = usbnet_probe,
.suspend = usbnet_suspend,
@@ -1588,6 +1647,7 @@ static void __exit asix_exit(void)
module_exit(asix_exit);
MODULE_AUTHOR("David Hollis");
+MODULE_VERSION(DRIVER_VERSION);
MODULE_DESCRIPTION("ASIX AX8817X based USB 2.0 Ethernet Devices");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c
index 8056f8a27c6a..a68272c93381 100644
--- a/drivers/net/usb/catc.c
+++ b/drivers/net/usb/catc.c
@@ -749,7 +749,7 @@ static const struct net_device_ops catc_netdev_ops = {
.ndo_start_xmit = catc_start_xmit,
.ndo_tx_timeout = catc_tx_timeout,
- .ndo_set_multicast_list = catc_set_multicast_list,
+ .ndo_set_rx_mode = catc_set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index a03336e086d5..f06fb78383a1 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -228,23 +228,40 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx)
if (ctx->rx_max != le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize)) {
if (flags & USB_CDC_NCM_NCAP_NTB_INPUT_SIZE) {
- struct usb_cdc_ncm_ndp_input_size ndp_in_sz;
+ struct usb_cdc_ncm_ndp_input_size *ndp_in_sz;
+
+ ndp_in_sz = kzalloc(sizeof(*ndp_in_sz), GFP_KERNEL);
+ if (!ndp_in_sz) {
+ err = -ENOMEM;
+ goto size_err;
+ }
+
err = usb_control_msg(ctx->udev,
usb_sndctrlpipe(ctx->udev, 0),
USB_CDC_SET_NTB_INPUT_SIZE,
USB_TYPE_CLASS | USB_DIR_OUT
| USB_RECIP_INTERFACE,
- 0, iface_no, &ndp_in_sz, 8, 1000);
+ 0, iface_no, ndp_in_sz, 8, 1000);
+ kfree(ndp_in_sz);
} else {
- __le32 dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
+ __le32 *dwNtbInMaxSize;
+ dwNtbInMaxSize = kzalloc(sizeof(*dwNtbInMaxSize),
+ GFP_KERNEL);
+ if (!dwNtbInMaxSize) {
+ err = -ENOMEM;
+ goto size_err;
+ }
+ *dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
+
err = usb_control_msg(ctx->udev,
usb_sndctrlpipe(ctx->udev, 0),
USB_CDC_SET_NTB_INPUT_SIZE,
USB_TYPE_CLASS | USB_DIR_OUT
| USB_RECIP_INTERFACE,
- 0, iface_no, &dwNtbInMaxSize, 4, 1000);
+ 0, iface_no, dwNtbInMaxSize, 4, 1000);
+ kfree(dwNtbInMaxSize);
}
-
+size_err:
if (err < 0)
pr_debug("Setting NTB Input Size failed\n");
}
@@ -325,19 +342,29 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx)
/* set Max Datagram Size (MTU) */
if (flags & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE) {
- __le16 max_datagram_size;
+ __le16 *max_datagram_size;
u16 eth_max_sz = le16_to_cpu(ctx->ether_desc->wMaxSegmentSize);
+
+ max_datagram_size = kzalloc(sizeof(*max_datagram_size),
+ GFP_KERNEL);
+ if (!max_datagram_size) {
+ err = -ENOMEM;
+ goto max_dgram_err;
+ }
+
err = usb_control_msg(ctx->udev, usb_rcvctrlpipe(ctx->udev, 0),
USB_CDC_GET_MAX_DATAGRAM_SIZE,
USB_TYPE_CLASS | USB_DIR_IN
| USB_RECIP_INTERFACE,
- 0, iface_no, &max_datagram_size,
+ 0, iface_no, max_datagram_size,
2, 1000);
if (err < 0) {
pr_debug("GET_MAX_DATAGRAM_SIZE failed, use size=%u\n",
CDC_NCM_MIN_DATAGRAM_SIZE);
+ kfree(max_datagram_size);
} else {
- ctx->max_datagram_size = le16_to_cpu(max_datagram_size);
+ ctx->max_datagram_size =
+ le16_to_cpu(*max_datagram_size);
/* Check Eth descriptor value */
if (eth_max_sz < CDC_NCM_MAX_DATAGRAM_SIZE) {
if (ctx->max_datagram_size > eth_max_sz)
@@ -360,8 +387,10 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx)
USB_TYPE_CLASS | USB_DIR_OUT
| USB_RECIP_INTERFACE,
0,
- iface_no, &max_datagram_size,
+ iface_no, max_datagram_size,
2, 1000);
+ kfree(max_datagram_size);
+max_dgram_err:
if (err < 0)
pr_debug("SET_MAX_DATAGRAM_SIZE failed\n");
}
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
index 1d93133e9b74..fbc0e4def767 100644
--- a/drivers/net/usb/dm9601.c
+++ b/drivers/net/usb/dm9601.c
@@ -428,7 +428,7 @@ static const struct net_device_ops dm9601_netdev_ops = {
.ndo_change_mtu = usbnet_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = dm9601_ioctl,
- .ndo_set_multicast_list = dm9601_set_multicast,
+ .ndo_set_rx_mode = dm9601_set_multicast,
.ndo_set_mac_address = dm9601_set_mac_address,
};
diff --git a/drivers/net/usb/int51x1.c b/drivers/net/usb/int51x1.c
index be02a25da71a..131ac6c172f6 100644
--- a/drivers/net/usb/int51x1.c
+++ b/drivers/net/usb/int51x1.c
@@ -193,7 +193,7 @@ static const struct net_device_ops int51x1_netdev_ops = {
.ndo_change_mtu = usbnet_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = int51x1_set_multicast,
+ .ndo_set_rx_mode = int51x1_set_multicast,
};
static int int51x1_bind(struct usbnet *dev, struct usb_interface *intf)
diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c
index 15772b1b6a91..13c1f044b40d 100644
--- a/drivers/net/usb/ipheth.c
+++ b/drivers/net/usb/ipheth.c
@@ -59,6 +59,7 @@
#define USB_PRODUCT_IPHONE_3G 0x1292
#define USB_PRODUCT_IPHONE_3GS 0x1294
#define USB_PRODUCT_IPHONE_4 0x1297
+#define USB_PRODUCT_IPHONE_4_VZW 0x129c
#define IPHETH_USBINTF_CLASS 255
#define IPHETH_USBINTF_SUBCLASS 253
@@ -98,6 +99,10 @@ static struct usb_device_id ipheth_table[] = {
USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4,
IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
IPHETH_USBINTF_PROTO) },
+ { USB_DEVICE_AND_INTERFACE_INFO(
+ USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4_VZW,
+ IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
+ IPHETH_USBINTF_PROTO) },
{ }
};
MODULE_DEVICE_TABLE(usb, ipheth_table);
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index ad0298f9b5f9..582ca2dfa5f9 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -985,7 +985,7 @@ static const struct net_device_ops kaweth_netdev_ops = {
.ndo_stop = kaweth_close,
.ndo_start_xmit = kaweth_start_xmit,
.ndo_tx_timeout = kaweth_tx_timeout,
- .ndo_set_multicast_list = kaweth_set_rx_mode,
+ .ndo_set_rx_mode = kaweth_set_rx_mode,
.ndo_get_stats = kaweth_netdev_stats,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/usb/lg-vl600.c b/drivers/net/usb/lg-vl600.c
index 1d83ccfd7277..1e7221951056 100644
--- a/drivers/net/usb/lg-vl600.c
+++ b/drivers/net/usb/lg-vl600.c
@@ -89,6 +89,8 @@ static int vl600_bind(struct usbnet *dev, struct usb_interface *intf)
* addresses have no meaning, the destination and the source of every
* packet depend only on whether it is on the IN or OUT endpoint. */
dev->net->flags |= IFF_NOARP;
+ /* IPv6 NDP relies on multicast. Enable it by default. */
+ dev->net->flags |= IFF_MULTICAST;
return ret;
}
@@ -200,6 +202,14 @@ static int vl600_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
} else {
memset(ethhdr->h_source, 0, ETH_ALEN);
memcpy(ethhdr->h_dest, dev->net->dev_addr, ETH_ALEN);
+
+ /* Inbound IPv6 packets have an IPv4 ethertype (0x800)
+ * for some reason. Peek at the L3 header to check
+ * for IPv6 packets, and set the ethertype to IPv6
+ * (0x86dd) so Linux can understand it.
+ */
+ if ((buf->data[sizeof(*ethhdr)] & 0xf0) == 0x60)
+ ethhdr->h_proto = __constant_htons(ETH_P_IPV6);
}
if (count) {
@@ -297,6 +307,15 @@ encapsulate:
if (skb->len < full_len) /* Pad */
skb_put(skb, full_len - skb->len);
+ /* The VL600 wants IPv6 packets to have an IPv4 ethertype
+ * Check if this is an IPv6 packet, and set the ethertype
+ * to 0x800
+ */
+ if ((skb->data[sizeof(struct vl600_pkt_hdr *) + 0x22] & 0xf0) == 0x60) {
+ skb->data[sizeof(struct vl600_pkt_hdr *) + 0x20] = 0x08;
+ skb->data[sizeof(struct vl600_pkt_hdr *) + 0x21] = 0;
+ }
+
return skb;
}
diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c
index 2b791392e788..db2cb74bf854 100644
--- a/drivers/net/usb/mcs7830.c
+++ b/drivers/net/usb/mcs7830.c
@@ -553,7 +553,7 @@ static const struct net_device_ops mcs7830_netdev_ops = {
.ndo_change_mtu = usbnet_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = mcs7830_ioctl,
- .ndo_set_multicast_list = mcs7830_set_multicast,
+ .ndo_set_rx_mode = mcs7830_set_multicast,
.ndo_set_mac_address = mcs7830_set_mac_address,
};
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index ef3667690b12..769f5090bda1 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -1476,7 +1476,7 @@ static const struct net_device_ops pegasus_netdev_ops = {
.ndo_stop = pegasus_close,
.ndo_do_ioctl = pegasus_ioctl,
.ndo_start_xmit = pegasus_start_xmit,
- .ndo_set_multicast_list = pegasus_set_multicast,
+ .ndo_set_rx_mode = pegasus_set_multicast,
.ndo_get_stats = pegasus_netdev_stats,
.ndo_tx_timeout = pegasus_tx_timeout,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index ef3b236b5145..bf8c84d0adf2 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -169,26 +169,8 @@ struct rtl8150 {
typedef struct rtl8150 rtl8150_t;
-static void fill_skb_pool(rtl8150_t *);
-static void free_skb_pool(rtl8150_t *);
-static inline struct sk_buff *pull_skb(rtl8150_t *);
-static void rtl8150_disconnect(struct usb_interface *intf);
-static int rtl8150_probe(struct usb_interface *intf,
- const struct usb_device_id *id);
-static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message);
-static int rtl8150_resume(struct usb_interface *intf);
-
static const char driver_name [] = "rtl8150";
-static struct usb_driver rtl8150_driver = {
- .name = driver_name,
- .probe = rtl8150_probe,
- .disconnect = rtl8150_disconnect,
- .id_table = rtl8150_table,
- .suspend = rtl8150_suspend,
- .resume = rtl8150_resume
-};
-
/*
**
** device related part of the code
@@ -333,7 +315,7 @@ static int rtl8150_set_mac_address(struct net_device *netdev, void *p)
/* Write the MAC address into eeprom. Eeprom writes must be word-sized,
so we need to split them up. */
for (i = 0; i * 2 < netdev->addr_len; i++) {
- set_registers(dev, IDR_EEPROM + (i * 2), 2,
+ set_registers(dev, IDR_EEPROM + (i * 2), 2,
netdev->dev_addr + (i * 2));
}
/* Clear the WEPROM bit (preventing accidental eeprom writes). */
@@ -490,44 +472,6 @@ resched:
tasklet_schedule(&dev->tl);
}
-static void rx_fixup(unsigned long data)
-{
- rtl8150_t *dev;
- struct sk_buff *skb;
- int status;
-
- dev = (rtl8150_t *)data;
-
- spin_lock_irq(&dev->rx_pool_lock);
- fill_skb_pool(dev);
- spin_unlock_irq(&dev->rx_pool_lock);
- if (test_bit(RX_URB_FAIL, &dev->flags))
- if (dev->rx_skb)
- goto try_again;
- spin_lock_irq(&dev->rx_pool_lock);
- skb = pull_skb(dev);
- spin_unlock_irq(&dev->rx_pool_lock);
- if (skb == NULL)
- goto tlsched;
- dev->rx_skb = skb;
- usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
- dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
-try_again:
- status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC);
- if (status == -ENODEV) {
- netif_device_detach(dev->netdev);
- } else if (status) {
- set_bit(RX_URB_FAIL, &dev->flags);
- goto tlsched;
- } else {
- clear_bit(RX_URB_FAIL, &dev->flags);
- }
-
- return;
-tlsched:
- tasklet_schedule(&dev->tl);
-}
-
static void write_bulk_callback(struct urb *urb)
{
rtl8150_t *dev;
@@ -665,6 +609,42 @@ static void free_skb_pool(rtl8150_t *dev)
dev_kfree_skb(dev->rx_skb_pool[i]);
}
+static void rx_fixup(unsigned long data)
+{
+ struct rtl8150 *dev = (struct rtl8150 *)data;
+ struct sk_buff *skb;
+ int status;
+
+ spin_lock_irq(&dev->rx_pool_lock);
+ fill_skb_pool(dev);
+ spin_unlock_irq(&dev->rx_pool_lock);
+ if (test_bit(RX_URB_FAIL, &dev->flags))
+ if (dev->rx_skb)
+ goto try_again;
+ spin_lock_irq(&dev->rx_pool_lock);
+ skb = pull_skb(dev);
+ spin_unlock_irq(&dev->rx_pool_lock);
+ if (skb == NULL)
+ goto tlsched;
+ dev->rx_skb = skb;
+ usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
+ dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
+try_again:
+ status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC);
+ if (status == -ENODEV) {
+ netif_device_detach(dev->netdev);
+ } else if (status) {
+ set_bit(RX_URB_FAIL, &dev->flags);
+ goto tlsched;
+ } else {
+ clear_bit(RX_URB_FAIL, &dev->flags);
+ }
+
+ return;
+tlsched:
+ tasklet_schedule(&dev->tl);
+}
+
static int enable_net_traffic(rtl8150_t * dev)
{
u8 cr, tcr, rcr, msr;
@@ -778,7 +758,7 @@ static int rtl8150_open(struct net_device *netdev)
return -ENOMEM;
set_registers(dev, IDR, 6, netdev->dev_addr);
-
+
usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL))) {
@@ -898,8 +878,8 @@ static const struct net_device_ops rtl8150_netdev_ops = {
.ndo_stop = rtl8150_close,
.ndo_do_ioctl = rtl8150_ioctl,
.ndo_start_xmit = rtl8150_start_xmit,
- .ndo_tx_timeout = rtl8150_tx_timeout,
- .ndo_set_multicast_list = rtl8150_set_multicast,
+ .ndo_tx_timeout = rtl8150_tx_timeout,
+ .ndo_set_rx_mode = rtl8150_set_multicast,
.ndo_set_mac_address = rtl8150_set_mac_address,
.ndo_change_mtu = eth_change_mtu,
@@ -929,7 +909,7 @@ static int rtl8150_probe(struct usb_interface *intf,
tasklet_init(&dev->tl, rx_fixup, (unsigned long)dev);
spin_lock_init(&dev->rx_pool_lock);
-
+
dev->udev = udev;
dev->netdev = netdev;
netdev->netdev_ops = &rtl8150_netdev_ops;
@@ -947,7 +927,7 @@ static int rtl8150_probe(struct usb_interface *intf,
}
fill_skb_pool(dev);
set_ethernet_addr(dev);
-
+
usb_set_intfdata(intf, dev);
SET_NETDEV_DEV(netdev, &intf->dev);
if (register_netdev(netdev) != 0) {
@@ -989,6 +969,15 @@ static void rtl8150_disconnect(struct usb_interface *intf)
}
}
+static struct usb_driver rtl8150_driver = {
+ .name = driver_name,
+ .probe = rtl8150_probe,
+ .disconnect = rtl8150_disconnect,
+ .id_table = rtl8150_table,
+ .suspend = rtl8150_suspend,
+ .resume = rtl8150_resume
+};
+
static int __init usb_rtl8150_init(void)
{
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index 15b3d6888ae9..22a7cf951e72 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -1000,7 +1000,7 @@ static const struct net_device_ops smsc75xx_netdev_ops = {
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = smsc75xx_ioctl,
- .ndo_set_multicast_list = smsc75xx_set_multicast,
+ .ndo_set_rx_mode = smsc75xx_set_multicast,
.ndo_set_features = smsc75xx_set_features,
};
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index f74f3ce71526..eff67678c5a6 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -972,7 +972,7 @@ static const struct net_device_ops smsc95xx_netdev_ops = {
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = smsc95xx_ioctl,
- .ndo_set_multicast_list = smsc95xx_set_multicast,
+ .ndo_set_rx_mode = smsc95xx_set_multicast,
.ndo_set_features = smsc95xx_set_features,
};
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index ce395fe5de26..7d6082160bcc 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -238,6 +238,10 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb)
netif_dbg(dev, rx_status, dev->net, "< rx, len %zu, type 0x%x\n",
skb->len + sizeof (struct ethhdr), skb->protocol);
memset (skb->cb, 0, sizeof (struct skb_data));
+
+ if (skb_defer_rx_timestamp(skb))
+ return;
+
status = netif_rx (skb);
if (status != NET_RX_SUCCESS)
netif_dbg(dev, rx_err, dev->net,
@@ -1053,6 +1057,8 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
unsigned long flags;
int retval;
+ skb_tx_timestamp(skb);
+
// some devices want funky USB-level framing, for
// win32 driver (usually) and/or hardware quirks
if (info->tx_fixup) {
@@ -1470,7 +1476,7 @@ int usbnet_suspend (struct usb_interface *intf, pm_message_t message)
if (!dev->suspend_count++) {
spin_lock_irq(&dev->txq.lock);
/* don't autosuspend while transmitting */
- if (dev->txq.qlen && (message.event & PM_EVENT_AUTO)) {
+ if (dev->txq.qlen && PMSG_IS_AUTO(message)) {
spin_unlock_irq(&dev->txq.lock);
return -EBUSY;
} else {
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 0c7321c35ad4..91039ab16728 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -143,18 +143,16 @@ static void skb_xmit_done(struct virtqueue *svq)
static void set_skb_frag(struct sk_buff *skb, struct page *page,
unsigned int offset, unsigned int *len)
{
+ int size = min((unsigned)PAGE_SIZE - offset, *len);
int i = skb_shinfo(skb)->nr_frags;
- skb_frag_t *f;
- f = &skb_shinfo(skb)->frags[i];
- f->size = min((unsigned)PAGE_SIZE - offset, *len);
- f->page_offset = offset;
- f->page = page;
+ __skb_fill_page_desc(skb, i, page, offset, size);
- skb->data_len += f->size;
- skb->len += f->size;
+ skb->data_len += size;
+ skb->len += size;
+ skb->truesize += PAGE_SIZE;
skb_shinfo(skb)->nr_frags++;
- *len -= f->size;
+ *len -= size;
}
static struct sk_buff *page_to_skb(struct virtnet_info *vi,
@@ -195,6 +193,19 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
len -= copy;
offset += copy;
+ /*
+ * Verify that we can indeed put this data into a skb.
+ * This is here to handle cases when the device erroneously
+ * tries to receive more than is possible. This is usually
+ * the case of a broken device.
+ */
+ if (unlikely(len > MAX_SKB_FRAGS * PAGE_SIZE)) {
+ if (net_ratelimit())
+ pr_debug("%s: too much data\n", skb->dev->name);
+ dev_kfree_skb(skb);
+ return NULL;
+ }
+
while (len) {
set_skb_frag(skb, page, offset, &len);
page = (struct page *)page->private;
@@ -277,7 +288,6 @@ static void receive_buf(struct net_device *dev, void *buf, unsigned int len)
}
hdr = skb_vnet_hdr(skb);
- skb->truesize += skb->data_len;
u64_stats_update_begin(&stats->syncp);
stats->rx_bytes += skb->len;
@@ -867,8 +877,21 @@ static void virtnet_vlan_rx_kill_vid(struct net_device *dev, u16 vid)
dev_warn(&dev->dev, "Failed to kill VLAN ID %d.\n", vid);
}
+static void virtnet_get_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ring)
+{
+ struct virtnet_info *vi = netdev_priv(dev);
+
+ ring->rx_max_pending = virtqueue_get_vring_size(vi->rvq);
+ ring->tx_max_pending = virtqueue_get_vring_size(vi->svq);
+ ring->rx_pending = ring->rx_max_pending;
+ ring->tx_pending = ring->tx_max_pending;
+
+}
+
static const struct ethtool_ops virtnet_ethtool_ops = {
.get_link = ethtool_op_get_link,
+ .get_ringparam = virtnet_get_ringparam,
};
#define MIN_MTU 68
@@ -949,6 +972,7 @@ static int virtnet_probe(struct virtio_device *vdev)
return -ENOMEM;
/* Set up network device as normal. */
+ dev->priv_flags |= IFF_UNICAST_FLT;
dev->netdev_ops = &virtnet_netdev;
dev->features = NETIF_F_HIGHDMA;
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index 1cbacb389652..b771ebac0f01 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -654,10 +654,11 @@ vmxnet3_append_frag(struct sk_buff *skb, struct Vmxnet3_RxCompDesc *rcd,
BUG_ON(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS);
- frag->page = rbi->page;
+ __skb_frag_set_page(frag, rbi->page);
frag->page_offset = 0;
- frag->size = rcd->len;
- skb->data_len += frag->size;
+ skb_frag_size_set(frag, rcd->len);
+ skb->data_len += rcd->len;
+ skb->truesize += PAGE_SIZE;
skb_shinfo(skb)->nr_frags++;
}
@@ -744,21 +745,21 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
}
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
+ const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
tbi = tq->buf_info + tq->tx_ring.next2fill;
tbi->map_type = VMXNET3_MAP_PAGE;
- tbi->dma_addr = pci_map_page(adapter->pdev, frag->page,
- frag->page_offset, frag->size,
- PCI_DMA_TODEVICE);
+ tbi->dma_addr = skb_frag_dma_map(&adapter->pdev->dev, frag,
+ 0, skb_frag_size(frag),
+ DMA_TO_DEVICE);
- tbi->len = frag->size;
+ tbi->len = skb_frag_size(frag);
gdesc = tq->tx_ring.base + tq->tx_ring.next2fill;
BUG_ON(gdesc->txd.gen == tq->tx_ring.gen);
gdesc->txd.addr = cpu_to_le64(tbi->dma_addr);
- gdesc->dword[2] = cpu_to_le32(dw2 | frag->size);
+ gdesc->dword[2] = cpu_to_le32(dw2 | skb_frag_size(frag));
gdesc->dword[3] = 0;
dev_dbg(&adapter->netdev->dev,
@@ -1277,7 +1278,6 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
skb = ctx->skb;
if (rcd->eop) {
skb->len += skb->data_len;
- skb->truesize += skb->data_len;
vmxnet3_rx_csum(adapter, skb,
(union Vmxnet3_GenericDesc *)rcd);
@@ -1929,14 +1929,17 @@ static void
vmxnet3_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
- u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
- unsigned long flags;
- VMXNET3_SET_VFTABLE_ENTRY(vfTable, vid);
- spin_lock_irqsave(&adapter->cmd_lock, flags);
- VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
- VMXNET3_CMD_UPDATE_VLAN_FILTERS);
- spin_unlock_irqrestore(&adapter->cmd_lock, flags);
+ if (!(netdev->flags & IFF_PROMISC)) {
+ u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
+ unsigned long flags;
+
+ VMXNET3_SET_VFTABLE_ENTRY(vfTable, vid);
+ spin_lock_irqsave(&adapter->cmd_lock, flags);
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+ VMXNET3_CMD_UPDATE_VLAN_FILTERS);
+ spin_unlock_irqrestore(&adapter->cmd_lock, flags);
+ }
set_bit(vid, adapter->active_vlans);
}
@@ -1946,14 +1949,17 @@ static void
vmxnet3_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
- u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
- unsigned long flags;
- VMXNET3_CLEAR_VFTABLE_ENTRY(vfTable, vid);
- spin_lock_irqsave(&adapter->cmd_lock, flags);
- VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
- VMXNET3_CMD_UPDATE_VLAN_FILTERS);
- spin_unlock_irqrestore(&adapter->cmd_lock, flags);
+ if (!(netdev->flags & IFF_PROMISC)) {
+ u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
+ unsigned long flags;
+
+ VMXNET3_CLEAR_VFTABLE_ENTRY(vfTable, vid);
+ spin_lock_irqsave(&adapter->cmd_lock, flags);
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+ VMXNET3_CMD_UPDATE_VLAN_FILTERS);
+ spin_unlock_irqrestore(&adapter->cmd_lock, flags);
+ }
clear_bit(vid, adapter->active_vlans);
}
@@ -2870,7 +2876,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
.ndo_set_features = vmxnet3_set_features,
.ndo_get_stats64 = vmxnet3_get_stats64,
.ndo_tx_timeout = vmxnet3_tx_timeout,
- .ndo_set_multicast_list = vmxnet3_set_mc,
+ .ndo_set_rx_mode = vmxnet3_set_mc,
.ndo_vlan_rx_add_vid = vmxnet3_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = vmxnet3_vlan_rx_kill_vid,
#ifdef CONFIG_NET_POLL_CONTROLLER
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index 27400edeef55..e662cbc8bfbd 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -558,7 +558,7 @@ out:
static int
vmxnet3_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info,
- void *rules)
+ u32 *rules)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
switch (info->cmd) {
diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c
index 055a918067e6..0d7645581f91 100644
--- a/drivers/net/wan/hdlc_ppp.c
+++ b/drivers/net/wan/hdlc_ppp.c
@@ -515,37 +515,37 @@ static int ppp_rx(struct sk_buff *skb)
switch (cp->code) {
case CP_CONF_REQ:
ppp_cp_parse_cr(dev, pid, cp->id, len, skb->data);
- goto out;
+ break;
case CP_CONF_ACK:
if (cp->id == proto->cr_id)
ppp_cp_event(dev, pid, RCA, 0, 0, 0, NULL);
- goto out;
+ break;
case CP_CONF_REJ:
case CP_CONF_NAK:
if (cp->id == proto->cr_id)
ppp_cp_event(dev, pid, RCN, 0, 0, 0, NULL);
- goto out;
+ break;
case CP_TERM_REQ:
ppp_cp_event(dev, pid, RTR, 0, cp->id, 0, NULL);
- goto out;
+ break;
case CP_TERM_ACK:
ppp_cp_event(dev, pid, RTA, 0, 0, 0, NULL);
- goto out;
+ break;
case CP_CODE_REJ:
ppp_cp_event(dev, pid, RXJ_BAD, 0, 0, 0, NULL);
- goto out;
+ break;
default:
len += sizeof(struct cp_header);
if (len > dev->mtu)
len = dev->mtu;
ppp_cp_event(dev, pid, RUC, 0, 0, len, cp);
- goto out;
+ break;
}
goto out;
diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c
index 56aeb011cb3d..a49aec5efd20 100644
--- a/drivers/net/wan/hdlc_x25.c
+++ b/drivers/net/wan/hdlc_x25.c
@@ -134,15 +134,15 @@ static netdev_tx_t x25_xmit(struct sk_buff *skb, struct net_device *dev)
static int x25_open(struct net_device *dev)
{
- struct lapb_register_struct cb;
int result;
-
- cb.connect_confirmation = x25_connected;
- cb.connect_indication = x25_connected;
- cb.disconnect_confirmation = x25_disconnected;
- cb.disconnect_indication = x25_disconnected;
- cb.data_indication = x25_data_indication;
- cb.data_transmit = x25_data_transmit;
+ static const struct lapb_register_struct cb = {
+ .connect_confirmation = x25_connected,
+ .connect_indication = x25_connected,
+ .disconnect_confirmation = x25_disconnected,
+ .disconnect_indication = x25_disconnected,
+ .data_indication = x25_data_indication,
+ .data_transmit = x25_data_transmit,
+ };
result = lapb_register(dev, &cb);
if (result != LAPB_OK)
diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
index a817081737a0..7beeb9b88a3b 100644
--- a/drivers/net/wan/lapbether.c
+++ b/drivers/net/wan/lapbether.c
@@ -259,14 +259,13 @@ static int lapbeth_set_mac_address(struct net_device *dev, void *addr)
}
-static struct lapb_register_struct lapbeth_callbacks = {
+static const struct lapb_register_struct lapbeth_callbacks = {
.connect_confirmation = lapbeth_connected,
.connect_indication = lapbeth_connected,
.disconnect_confirmation = lapbeth_disconnected,
.disconnect_indication = lapbeth_disconnected,
.data_indication = lapbeth_data_indication,
.data_transmit = lapbeth_data_transmit,
-
};
/*
diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
index 86127bcc9f7a..783168cce077 100644
--- a/drivers/net/wan/sbni.c
+++ b/drivers/net/wan/sbni.c
@@ -212,7 +212,7 @@ static const struct net_device_ops sbni_netdev_ops = {
.ndo_open = sbni_open,
.ndo_stop = sbni_close,
.ndo_start_xmit = sbni_start_xmit,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_do_ioctl = sbni_ioctl,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index 46ceb3ae9073..8a10bb730d5a 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -434,14 +434,13 @@ static void x25_asy_disconnected(struct net_device *dev, int reason)
netif_rx(skb);
}
-static struct lapb_register_struct x25_asy_callbacks = {
+static const struct lapb_register_struct x25_asy_callbacks = {
.connect_confirmation = x25_asy_connected,
.connect_indication = x25_asy_connected,
.disconnect_confirmation = x25_asy_disconnected,
.disconnect_indication = x25_asy_disconnected,
.data_indication = x25_asy_data_indication,
.data_transmit = x25_asy_data_transmit,
-
};
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index 298f2b0b6311..9a644d052f1e 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -599,7 +599,7 @@ void i2400mu_disconnect(struct usb_interface *iface)
*
* As well, the device might refuse going to sleep for whichever
* reason. In this case we just fail. For system suspend/hibernate,
- * we *can't* fail. We check PM_EVENT_AUTO to see if the
+ * we *can't* fail. We check PMSG_IS_AUTO to see if the
* suspend call comes from the USB stack or from the system and act
* in consequence.
*
@@ -615,7 +615,7 @@ int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg)
struct i2400m *i2400m = &i2400mu->i2400m;
#ifdef CONFIG_PM
- if (pm_msg.event & PM_EVENT_AUTO)
+ if (PMSG_IS_AUTO(pm_msg))
is_autosuspend = 1;
#endif
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index f354bd4e121e..abd3b71cd4ab 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -271,6 +271,7 @@ config MWL8K
source "drivers/net/wireless/ath/Kconfig"
source "drivers/net/wireless/b43/Kconfig"
source "drivers/net/wireless/b43legacy/Kconfig"
+source "drivers/net/wireless/brcm80211/Kconfig"
source "drivers/net/wireless/hostap/Kconfig"
source "drivers/net/wireless/ipw2x00/Kconfig"
source "drivers/net/wireless/iwlwifi/Kconfig"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 7bba6a82b875..0a304b060b6c 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -41,7 +41,7 @@ obj-$(CONFIG_ADM8211) += adm8211.o
obj-$(CONFIG_MWL8K) += mwl8k.o
-obj-$(CONFIG_IWLAGN) += iwlwifi/
+obj-$(CONFIG_IWLWIFI) += iwlwifi/
obj-$(CONFIG_IWLWIFI_LEGACY) += iwlegacy/
obj-$(CONFIG_RT2X00) += rt2x00/
@@ -58,3 +58,6 @@ obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/
obj-$(CONFIG_IWM) += iwmc3200wifi/
obj-$(CONFIG_MWIFIEX) += mwifiex/
+obj-$(CONFIG_BRCMFMAC) += brcm80211/
+obj-$(CONFIG_BRCMUMAC) += brcm80211/
+obj-$(CONFIG_BRCMSMAC) += brcm80211/
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index 43ebc44fc82c..3b752d9fb3cd 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -1249,7 +1249,8 @@ static int adm8211_hw_reset(struct ieee80211_hw *dev)
return 0;
}
-static u64 adm8211_get_tsft(struct ieee80211_hw *dev)
+static u64 adm8211_get_tsft(struct ieee80211_hw *dev,
+ struct ieee80211_vif *vif)
{
struct adm8211_priv *priv = dev->priv;
u32 tsftl;
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index e1b3e3c134fd..ac1176a4f465 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -2754,7 +2754,7 @@ static const struct net_device_ops airo_netdev_ops = {
.ndo_stop = airo_close,
.ndo_start_xmit = airo_start_xmit,
.ndo_get_stats = airo_get_stats,
- .ndo_set_multicast_list = airo_set_multicast_list,
+ .ndo_set_rx_mode = airo_set_multicast_list,
.ndo_set_mac_address = airo_set_mac_address,
.ndo_do_ioctl = airo_ioctl,
.ndo_change_mtu = airo_change_mtu,
@@ -2766,7 +2766,7 @@ static const struct net_device_ops mpi_netdev_ops = {
.ndo_stop = airo_close,
.ndo_start_xmit = mpi_start_xmit,
.ndo_get_stats = airo_get_stats,
- .ndo_set_multicast_list = airo_set_multicast_list,
+ .ndo_set_rx_mode = airo_set_multicast_list,
.ndo_set_mac_address = airo_set_mac_address,
.ndo_do_ioctl = airo_ioctl,
.ndo_change_mtu = airo_change_mtu,
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 298601436ee2..39322d4121b7 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -500,10 +500,9 @@ exit:
#define HEX2STR_BUFFERS 4
#define HEX2STR_MAX_LEN 64
-#define BIN2HEX(x) ((x) < 10 ? '0' + (x) : (x) + 'A' - 10)
/* Convert binary data into hex string */
-static char *hex2str(void *buf, int len)
+static char *hex2str(void *buf, size_t len)
{
static atomic_t a = ATOMIC_INIT(0);
static char bufs[HEX2STR_BUFFERS][3 * HEX2STR_MAX_LEN + 1];
@@ -514,18 +513,17 @@ static char *hex2str(void *buf, int len)
if (len > HEX2STR_MAX_LEN)
len = HEX2STR_MAX_LEN;
- if (len <= 0) {
- ret[0] = '\0';
- return ret;
- }
+ if (len == 0)
+ goto exit;
while (len--) {
- *obuf++ = BIN2HEX(*ibuf >> 4);
- *obuf++ = BIN2HEX(*ibuf & 0xf);
+ obuf = pack_hex_byte(obuf, *ibuf++);
*obuf++ = '-';
- ibuf++;
}
- *(--obuf) = '\0';
+ obuf--;
+
+exit:
+ *obuf = '\0';
return ret;
}
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig
index d1b23067619f..073548836413 100644
--- a/drivers/net/wireless/ath/Kconfig
+++ b/drivers/net/wireless/ath/Kconfig
@@ -25,5 +25,6 @@ config ATH_DEBUG
source "drivers/net/wireless/ath/ath5k/Kconfig"
source "drivers/net/wireless/ath/ath9k/Kconfig"
source "drivers/net/wireless/ath/carl9170/Kconfig"
+source "drivers/net/wireless/ath/ath6kl/Kconfig"
endif
diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile
index 0e8f528c81c0..d1214696a35b 100644
--- a/drivers/net/wireless/ath/Makefile
+++ b/drivers/net/wireless/ath/Makefile
@@ -1,6 +1,7 @@
obj-$(CONFIG_ATH5K) += ath5k/
obj-$(CONFIG_ATH9K_HW) += ath9k/
obj-$(CONFIG_CARL9170) += carl9170/
+obj-$(CONFIG_ATH6KL) += ath6kl/
obj-$(CONFIG_ATH_COMMON) += ath.o
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index 17c4b56c3874..908fdbc3e0ee 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -71,9 +71,7 @@ struct ath_regulatory {
char alpha2[2];
u16 country_code;
u16 max_power_level;
- u32 tp_scale;
u16 current_rd;
- u16 current_rd_ext;
int16_t power_limit;
struct reg_dmn_pair_mapping *regpair;
};
@@ -140,9 +138,6 @@ struct ath_common {
u8 curbssid[ETH_ALEN];
u8 bssidmask[ETH_ALEN];
- u8 tx_chainmask;
- u8 rx_chainmask;
-
u32 rx_bufsize;
u32 keymax;
@@ -178,23 +173,29 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry);
void ath_hw_cycle_counters_update(struct ath_common *common);
int32_t ath_hw_get_listen_time(struct ath_common *common);
-extern __attribute__ ((format (printf, 3, 4))) int
-ath_printk(const char *level, struct ath_common *common, const char *fmt, ...);
+extern __attribute__((format (printf, 2, 3)))
+void ath_printk(const char *level, const char *fmt, ...);
+
+#define _ath_printk(level, common, fmt, ...) \
+do { \
+ __always_unused struct ath_common *unused = common; \
+ ath_printk(level, fmt, ##__VA_ARGS__); \
+} while (0)
#define ath_emerg(common, fmt, ...) \
- ath_printk(KERN_EMERG, common, fmt, ##__VA_ARGS__)
+ _ath_printk(KERN_EMERG, common, fmt, ##__VA_ARGS__)
#define ath_alert(common, fmt, ...) \
- ath_printk(KERN_ALERT, common, fmt, ##__VA_ARGS__)
+ _ath_printk(KERN_ALERT, common, fmt, ##__VA_ARGS__)
#define ath_crit(common, fmt, ...) \
- ath_printk(KERN_CRIT, common, fmt, ##__VA_ARGS__)
+ _ath_printk(KERN_CRIT, common, fmt, ##__VA_ARGS__)
#define ath_err(common, fmt, ...) \
- ath_printk(KERN_ERR, common, fmt, ##__VA_ARGS__)
+ _ath_printk(KERN_ERR, common, fmt, ##__VA_ARGS__)
#define ath_warn(common, fmt, ...) \
- ath_printk(KERN_WARNING, common, fmt, ##__VA_ARGS__)
+ _ath_printk(KERN_WARNING, common, fmt, ##__VA_ARGS__)
#define ath_notice(common, fmt, ...) \
- ath_printk(KERN_NOTICE, common, fmt, ##__VA_ARGS__)
+ _ath_printk(KERN_NOTICE, common, fmt, ##__VA_ARGS__)
#define ath_info(common, fmt, ...) \
- ath_printk(KERN_INFO, common, fmt, ##__VA_ARGS__)
+ _ath_printk(KERN_INFO, common, fmt, ##__VA_ARGS__)
/**
* enum ath_debug_level - atheros wireless debug level
@@ -246,27 +247,21 @@ enum ATH_DEBUG {
#ifdef CONFIG_ATH_DEBUG
-#define ath_dbg(common, dbg_mask, fmt, ...) \
-({ \
- int rtn; \
- if ((common)->debug_mask & dbg_mask) \
- rtn = ath_printk(KERN_DEBUG, common, fmt, \
- ##__VA_ARGS__); \
- else \
- rtn = 0; \
- \
- rtn; \
-})
+#define ath_dbg(common, dbg_mask, fmt, ...) \
+do { \
+ if ((common)->debug_mask & dbg_mask) \
+ _ath_printk(KERN_DEBUG, common, fmt, ##__VA_ARGS__); \
+} while (0)
+
#define ATH_DBG_WARN(foo, arg...) WARN(foo, arg)
#define ATH_DBG_WARN_ON_ONCE(foo) WARN_ON_ONCE(foo)
#else
-static inline __attribute__ ((format (printf, 3, 4))) int
-ath_dbg(struct ath_common *common, enum ATH_DEBUG dbg_mask,
- const char *fmt, ...)
+static inline __attribute__((format (printf, 3, 4)))
+void ath_dbg(struct ath_common *common, enum ATH_DEBUG dbg_mask,
+ const char *fmt, ...)
{
- return 0;
}
#define ATH_DBG_WARN(foo, arg...) do {} while (0)
#define ATH_DBG_WARN_ON_ONCE(foo) ({ \
diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c
index a2a167363dbf..e5be7e701816 100644
--- a/drivers/net/wireless/ath/ath5k/ahb.c
+++ b/drivers/net/wireless/ath/ath5k/ahb.c
@@ -169,7 +169,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
__set_bit(ATH_STAT_2G_DISABLED, ah->status);
}
- ret = ath5k_init_softc(ah, &ath_ahb_bus_ops);
+ ret = ath5k_init_ah(ah, &ath_ahb_bus_ops);
if (ret != 0) {
dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret);
ret = -ENODEV;
@@ -214,7 +214,7 @@ static int ath_ahb_remove(struct platform_device *pdev)
__raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE);
}
- ath5k_deinit_softc(ah);
+ ath5k_deinit_ah(ah);
platform_set_drvdata(pdev, NULL);
ieee80211_free_hw(hw);
diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c
index 603ae15f139b..bea90e6be70e 100644
--- a/drivers/net/wireless/ath/ath5k/ani.c
+++ b/drivers/net/wireless/ath/ath5k/ani.c
@@ -15,7 +15,6 @@
*/
#include "ath5k.h"
-#include "base.h"
#include "reg.h"
#include "debug.h"
#include "ani.h"
diff --git a/drivers/net/wireless/ath/ath5k/ani.h b/drivers/net/wireless/ath/ath5k/ani.h
index 034015397093..7358b6c83c6c 100644
--- a/drivers/net/wireless/ath/ath5k/ani.h
+++ b/drivers/net/wireless/ath/ath5k/ani.h
@@ -16,6 +16,10 @@
#ifndef ANI_H
#define ANI_H
+#include "../ath.h"
+
+enum ath5k_phy_error_code;
+
/* these thresholds are relative to the ATH5K_ANI_LISTEN_PERIOD */
#define ATH5K_ANI_LISTEN_PERIOD 100
#define ATH5K_ANI_OFDM_TRIG_HIGH 500
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 277d5cbe0068..fecbcd9a4259 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -131,13 +131,6 @@
#define AR5K_REG_DISABLE_BITS(ah, _reg, _flags) \
ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) & ~(_flags), _reg)
-/* Access to PHY registers */
-#define AR5K_PHY_READ(ah, _reg) \
- ath5k_hw_reg_read(ah, (ah)->ah_phy + ((_reg) << 2))
-
-#define AR5K_PHY_WRITE(ah, _reg, _val) \
- ath5k_hw_reg_write(ah, _val, (ah)->ah_phy + ((_reg) << 2))
-
/* Access QCU registers per queue */
#define AR5K_REG_READ_Q(ah, _reg, _queue) \
(ath5k_hw_reg_read(ah, _reg) & (1 << _queue)) \
@@ -166,7 +159,6 @@
#define AR5K_TUNE_DMA_BEACON_RESP 2
#define AR5K_TUNE_SW_BEACON_RESP 10
#define AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF 0
-#define AR5K_TUNE_RADAR_ALERT false
#define AR5K_TUNE_MIN_TX_FIFO_THRES 1
#define AR5K_TUNE_MAX_TX_FIFO_THRES ((IEEE80211_MAX_FRAME_LEN / 64) + 1)
#define AR5K_TUNE_REGISTER_TIMEOUT 20000
@@ -295,17 +287,6 @@ enum ath5k_radio {
* Common silicon revision/version values
*/
-enum ath5k_srev_type {
- AR5K_VERSION_MAC,
- AR5K_VERSION_RAD,
-};
-
-struct ath5k_srev_name {
- const char *sr_name;
- enum ath5k_srev_type sr_type;
- u_int sr_val;
-};
-
#define AR5K_SREV_UNKNOWN 0xffff
#define AR5K_SREV_AR5210 0x00 /* Crete */
@@ -424,7 +405,6 @@ enum ath5k_driver_mode {
AR5K_MODE_11A = 0,
AR5K_MODE_11B = 1,
AR5K_MODE_11G = 2,
- AR5K_MODE_XR = 0,
AR5K_MODE_MAX = 3
};
@@ -694,33 +674,6 @@ struct ath5k_gain {
#define AR5K_SLOT_TIME_20 880
#define AR5K_SLOT_TIME_MAX 0xffff
-/* channel_flags */
-#define CHANNEL_CW_INT 0x0008 /* Contention Window interference detected */
-#define CHANNEL_CCK 0x0020 /* CCK channel */
-#define CHANNEL_OFDM 0x0040 /* OFDM channel */
-#define CHANNEL_2GHZ 0x0080 /* 2GHz channel. */
-#define CHANNEL_5GHZ 0x0100 /* 5GHz channel */
-#define CHANNEL_PASSIVE 0x0200 /* Only passive scan allowed */
-#define CHANNEL_DYN 0x0400 /* Dynamic CCK-OFDM channel (for g operation) */
-#define CHANNEL_XR 0x0800 /* XR channel */
-
-#define CHANNEL_A (CHANNEL_5GHZ | CHANNEL_OFDM)
-#define CHANNEL_B (CHANNEL_2GHZ | CHANNEL_CCK)
-#define CHANNEL_G (CHANNEL_2GHZ | CHANNEL_OFDM)
-#define CHANNEL_X (CHANNEL_5GHZ | CHANNEL_OFDM | CHANNEL_XR)
-
-#define CHANNEL_ALL (CHANNEL_OFDM | CHANNEL_CCK | \
- CHANNEL_2GHZ | CHANNEL_5GHZ)
-
-#define CHANNEL_MODES CHANNEL_ALL
-
-/*
- * Used internally for ath5k_hw_reset_tx_queue().
- * Also see struct struct ieee80211_channel.
- */
-#define IS_CHAN_XR(_c) ((_c->hw_value & CHANNEL_XR) != 0)
-#define IS_CHAN_B(_c) ((_c->hw_value & CHANNEL_B) != 0)
-
/*
* The following structure is used to map 2GHz channels to
* 5GHz Atheros channels.
@@ -977,7 +930,7 @@ enum ath5k_power_mode {
struct ath5k_capabilities {
/*
* Supported PHY modes
- * (ie. CHANNEL_A, CHANNEL_B, ...)
+ * (ie. AR5K_MODE_11A, AR5K_MODE_11B, ...)
*/
DECLARE_BITMAP(cap_mode, AR5K_MODE_MAX);
@@ -1013,16 +966,6 @@ struct ath5k_nfcal_hist {
s16 nfval[ATH5K_NF_CAL_HIST_MAX]; /* last few noise floors */
};
-/**
- * struct avg_val - Helper structure for average calculation
- * @avg: contains the actual average value
- * @avg_weight: is used internally during calculation to prevent rounding errors
- */
-struct ath5k_avg_val {
- int avg;
- int avg_weight;
-};
-
#define ATH5K_LED_MAX_NAME_LEN 31
/*
@@ -1148,7 +1091,6 @@ struct ath5k_hw {
bool rx_pending; /* rx tasklet pending */
bool tx_pending; /* tx tasklet pending */
- u8 lladdr[ETH_ALEN];
u8 bssidmask[ETH_ALEN];
unsigned int led_pin, /* GPIO pin for driving LED */
@@ -1156,7 +1098,6 @@ struct ath5k_hw {
struct work_struct reset_work; /* deferred chip reset */
- unsigned int rxbufsize; /* rx size based on mtu */
struct list_head rxbuf; /* receive buffer */
spinlock_t rxbuflock;
u32 *rxlink; /* link ptr in last RX desc */
@@ -1208,10 +1149,8 @@ struct ath5k_hw {
enum ath5k_version ah_version;
enum ath5k_radio ah_radio;
- u32 ah_phy;
u32 ah_mac_srev;
u16 ah_mac_version;
- u16 ah_mac_revision;
u16 ah_phy_revision;
u16 ah_radio_5ghz_revision;
u16 ah_radio_2ghz_revision;
@@ -1279,12 +1218,6 @@ struct ath5k_hw {
bool txp_setup;
} ah_txpower;
- struct {
- bool r_enabled;
- int r_last_alert;
- struct ieee80211_channel r_last_channel;
- } ah_radar;
-
struct ath5k_nfcal_hist ah_nfcal_hist;
/* average beacon RSSI in our BSS (used by ANI) */
@@ -1327,36 +1260,13 @@ struct ath_bus_ops {
extern const struct ieee80211_ops ath5k_hw_ops;
/* Initialization and detach functions */
-int ath5k_init_softc(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops);
-void ath5k_deinit_softc(struct ath5k_hw *ah);
int ath5k_hw_init(struct ath5k_hw *ah);
void ath5k_hw_deinit(struct ath5k_hw *ah);
int ath5k_sysfs_register(struct ath5k_hw *ah);
void ath5k_sysfs_unregister(struct ath5k_hw *ah);
-/* base.c */
-struct ath5k_buf;
-struct ath5k_txq;
-
-void ath5k_set_beacon_filter(struct ieee80211_hw *hw, bool enable);
-bool ath5k_any_vif_assoc(struct ath5k_hw *ah);
-void ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ath5k_txq *txq);
-int ath5k_start(struct ieee80211_hw *hw);
-void ath5k_stop(struct ieee80211_hw *hw);
-void ath5k_mode_setup(struct ath5k_hw *ah, struct ieee80211_vif *vif);
-void ath5k_update_bssid_mask_and_opmode(struct ath5k_hw *ah,
- struct ieee80211_vif *vif);
-int ath5k_chan_set(struct ath5k_hw *ah, struct ieee80211_channel *chan);
-void ath5k_beacon_update_timers(struct ath5k_hw *ah, u64 bc_tsf);
-int ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
-void ath5k_beacon_config(struct ath5k_hw *ah);
-void ath5k_txbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf);
-void ath5k_rxbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf);
-
/*Chip id helper functions */
-const char *ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val);
int ath5k_hw_read_srev(struct ath5k_hw *ah);
/* LED functions */
@@ -1367,7 +1277,7 @@ void ath5k_unregister_leds(struct ath5k_hw *ah);
/* Reset Functions */
-int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial);
+int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel);
int ath5k_hw_on_hold(struct ath5k_hw *ah);
int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
struct ieee80211_channel *channel, bool fast, bool skip_pcu);
@@ -1487,13 +1397,13 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel);
/* PHY functions */
/* Misc PHY functions */
-u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan);
+u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band);
int ath5k_hw_phy_disable(struct ath5k_hw *ah);
/* Gain_F optimization */
enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah);
int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah);
/* PHY/RF channel functions */
-bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
+bool ath5k_channel_ok(struct ath5k_hw *ah, struct ieee80211_channel *channel);
/* PHY calibration */
void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah);
int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index f8a6b380d96d..91627dd2c26a 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -25,7 +25,6 @@
#include "ath5k.h"
#include "reg.h"
#include "debug.h"
-#include "base.h"
/**
* ath5k_hw_post - Power On Self Test helper function
@@ -95,7 +94,7 @@ static int ath5k_hw_post(struct ath5k_hw *ah)
/**
* ath5k_hw_init - Check if hw is supported and init the needed structs
*
- * @ah: The &struct ath5k_hw we got from the driver's init_softc function
+ * @ah: The &struct ath5k_hw associated with the device
*
* Check if the device is supported, perform a POST and initialize the needed
* structs. Returns -ENOMEM if we don't have memory for the needed structs,
@@ -114,7 +113,6 @@ int ath5k_hw_init(struct ath5k_hw *ah)
/*
* HW information
*/
- ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT;
ah->ah_bwmode = AR5K_BWMODE_DEFAULT;
ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
ah->ah_imr = 0;
@@ -137,9 +135,8 @@ int ath5k_hw_init(struct ath5k_hw *ah)
else
ah->ah_version = AR5K_AR5212;
- /* Get the MAC revision */
+ /* Get the MAC version */
ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
- ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV);
/* Fill the ath5k_hw struct with the needed functions */
ret = ath5k_hw_init_desc_functions(ah);
@@ -147,7 +144,7 @@ int ath5k_hw_init(struct ath5k_hw *ah)
goto err;
/* Bring device out of sleep and reset its units */
- ret = ath5k_hw_nic_wakeup(ah, 0, true);
+ ret = ath5k_hw_nic_wakeup(ah, NULL);
if (ret)
goto err;
@@ -155,8 +152,7 @@ int ath5k_hw_init(struct ath5k_hw *ah)
ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) &
0xffffffff;
ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah,
- CHANNEL_5GHZ);
- ah->ah_phy = AR5K_PHY(0);
+ IEEE80211_BAND_5GHZ);
/* Try to identify radio chip based on its srev */
switch (ah->ah_radio_5ghz_revision & 0xf0) {
@@ -164,14 +160,14 @@ int ath5k_hw_init(struct ath5k_hw *ah)
ah->ah_radio = AR5K_RF5111;
ah->ah_single_chip = false;
ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
- CHANNEL_2GHZ);
+ IEEE80211_BAND_2GHZ);
break;
case AR5K_SREV_RAD_5112:
case AR5K_SREV_RAD_2112:
ah->ah_radio = AR5K_RF5112;
ah->ah_single_chip = false;
ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
- CHANNEL_2GHZ);
+ IEEE80211_BAND_2GHZ);
break;
case AR5K_SREV_RAD_2413:
ah->ah_radio = AR5K_RF2413;
@@ -208,7 +204,7 @@ int ath5k_hw_init(struct ath5k_hw *ah)
ah->ah_radio = AR5K_RF5111;
ah->ah_single_chip = false;
ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
- CHANNEL_2GHZ);
+ IEEE80211_BAND_2GHZ);
} else if (ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4) ||
ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4) ||
ah->ah_phy_revision == AR5K_SREV_PHY_2425) {
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index c3119a6caace..b346d0492001 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -52,6 +52,7 @@
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/etherdevice.h>
+#include <linux/nl80211.h>
#include <net/ieee80211_radiotap.h>
@@ -61,6 +62,8 @@
#include "reg.h"
#include "debug.h"
#include "ani.h"
+#include "ath5k.h"
+#include "../regd.h"
#define CREATE_TRACE_POINTS
#include "trace.h"
@@ -272,20 +275,18 @@ static unsigned int
ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels,
unsigned int mode, unsigned int max)
{
- unsigned int count, size, chfreq, freq, ch;
+ unsigned int count, size, freq, ch;
enum ieee80211_band band;
switch (mode) {
case AR5K_MODE_11A:
/* 1..220, but 2GHz frequencies are filtered by check_channel */
size = 220;
- chfreq = CHANNEL_5GHZ;
band = IEEE80211_BAND_5GHZ;
break;
case AR5K_MODE_11B:
case AR5K_MODE_11G:
size = 26;
- chfreq = CHANNEL_2GHZ;
band = IEEE80211_BAND_2GHZ;
break;
default:
@@ -300,26 +301,19 @@ ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels,
if (freq == 0) /* mapping failed - not a standard channel */
continue;
+ /* Write channel info, needed for ath5k_channel_ok() */
+ channels[count].center_freq = freq;
+ channels[count].band = band;
+ channels[count].hw_value = mode;
+
/* Check if channel is supported by the chipset */
- if (!ath5k_channel_ok(ah, freq, chfreq))
+ if (!ath5k_channel_ok(ah, &channels[count]))
continue;
if (!modparam_all_channels &&
!ath5k_is_standard_channel(ch, band))
continue;
- /* Write channel info and increment counter */
- channels[count].center_freq = freq;
- channels[count].band = band;
- switch (mode) {
- case AR5K_MODE_11A:
- case AR5K_MODE_11G:
- channels[count].hw_value = chfreq | CHANNEL_OFDM;
- break;
- case AR5K_MODE_11B:
- channels[count].hw_value = CHANNEL_B;
- }
-
count++;
}
@@ -927,12 +921,6 @@ ath5k_txq_setup(struct ath5k_hw *ah,
*/
return ERR_PTR(qnum);
}
- if (qnum >= ARRAY_SIZE(ah->txqs)) {
- ATH5K_ERR(ah, "hw qnum %u out of range, max %tu!\n",
- qnum, ARRAY_SIZE(ah->txqs));
- ath5k_hw_release_tx_queue(ah, qnum);
- return ERR_PTR(-EINVAL);
- }
txq = &ah->txqs[qnum];
if (!txq->setup) {
txq->qnum = qnum;
@@ -2349,7 +2337,7 @@ ath5k_tx_complete_poll_work(struct work_struct *work)
\*************************/
int __devinit
-ath5k_init_softc(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops)
+ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops)
{
struct ieee80211_hw *hw = ah->hw;
struct ath_common *common;
@@ -2867,7 +2855,6 @@ ath5k_init(struct ieee80211_hw *hw)
}
SET_IEEE80211_PERM_ADDR(hw, mac);
- memcpy(&ah->lladdr, mac, ETH_ALEN);
/* All MAC address bits matter for ACKs */
ath5k_update_bssid_mask_and_opmode(ah, NULL);
@@ -2903,7 +2890,7 @@ err:
}
void
-ath5k_deinit_softc(struct ath5k_hw *ah)
+ath5k_deinit_ah(struct ath5k_hw *ah)
{
struct ieee80211_hw *hw = ah->hw;
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index a81f28d5bddc..6c94c7ff2350 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -38,19 +38,27 @@
/*
* Definitions for the Atheros Wireless LAN controller driver.
*/
-#ifndef _DEV_ATH_ATHVAR_H
-#define _DEV_ATH_ATHVAR_H
+#ifndef _DEV_ATH5K_BASE_H
+#define _DEV_ATH5K_BASE_H
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/wireless.h>
-#include <linux/if_ether.h>
-#include <linux/rfkill.h>
-#include <linux/workqueue.h>
+struct ieee80211_vif;
+struct ieee80211_hw;
+struct ath5k_hw;
+struct ath5k_txq;
+struct ieee80211_channel;
+struct ath_bus_ops;
+enum nl80211_iftype;
-#include "ath5k.h"
-#include "../regd.h"
-#include "../ath.h"
+enum ath5k_srev_type {
+ AR5K_VERSION_MAC,
+ AR5K_VERSION_RAD,
+};
+
+struct ath5k_srev_name {
+ const char *sr_name;
+ enum ath5k_srev_type sr_type;
+ u_int sr_val;
+};
struct ath5k_buf {
struct list_head list;
@@ -65,7 +73,6 @@ struct ath5k_vif {
enum nl80211_iftype opmode;
int bslot;
struct ath5k_buf *bbuf; /* beacon buffer */
- u8 lladdr[ETH_ALEN];
};
struct ath5k_vif_iter_data {
@@ -78,8 +85,30 @@ struct ath5k_vif_iter_data {
enum nl80211_iftype opmode;
int n_stas;
};
+
void ath5k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif);
+bool ath5k_any_vif_assoc(struct ath5k_hw *ah);
+
+int ath5k_start(struct ieee80211_hw *hw);
+void ath5k_stop(struct ieee80211_hw *hw);
+
+void ath5k_beacon_update_timers(struct ath5k_hw *ah, u64 bc_tsf);
+int ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+void ath5k_beacon_config(struct ath5k_hw *ah);
+void ath5k_set_beacon_filter(struct ieee80211_hw *hw, bool enable);
+
+void ath5k_update_bssid_mask_and_opmode(struct ath5k_hw *ah,
+ struct ieee80211_vif *vif);
+int ath5k_chan_set(struct ath5k_hw *ah, struct ieee80211_channel *chan);
+void ath5k_txbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf);
+void ath5k_rxbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf);
+void ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ath5k_txq *txq);
+
+const char *ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val);
+int ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops);
+void ath5k_deinit_ah(struct ath5k_hw *ah);
/* Check whether BSSID mask is supported */
#define ath5k_hw_hasbssidmask(_ah) (ah->ah_version == AR5K_AR5212)
@@ -87,4 +116,4 @@ void ath5k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif);
/* Check whether virtual EOL is supported */
#define ath5k_hw_hasveol(_ah) (ah->ah_version != AR5K_AR5210)
-#endif
+#endif /* _DEV_ATH5K_BASE_H */
diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c
index eefe670e28a7..810fba96702b 100644
--- a/drivers/net/wireless/ath/ath5k/caps.c
+++ b/drivers/net/wireless/ath/ath5k/caps.c
@@ -24,7 +24,7 @@
#include "ath5k.h"
#include "reg.h"
#include "debug.h"
-#include "base.h"
+#include "../regd.h"
/*
* Fill the capabilities struct
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index ccca724de173..fce8c904eea9 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -58,19 +58,18 @@
* THE POSSIBILITY OF SUCH DAMAGES.
*/
-#include "base.h"
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/list.h>
#include "debug.h"
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
static unsigned int ath5k_debug;
module_param_named(debug, ath5k_debug, uint, 0);
-#ifdef CONFIG_ATH5K_DEBUG
-
-#include <linux/seq_file.h>
-#include "reg.h"
-#include "ani.h"
-
static int ath5k_debugfs_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
@@ -1031,5 +1030,3 @@ ath5k_debug_printtxbuf(struct ath5k_hw *ah, struct ath5k_buf *bf)
td->tx_stat.tx_status_0, td->tx_stat.tx_status_1,
done ? ' ' : (ts.ts_status == 0) ? '*' : '!');
}
-
-#endif /* ifdef CONFIG_ATH5K_DEBUG */
diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c
index 846535f59efc..7e88dda82221 100644
--- a/drivers/net/wireless/ath/ath5k/desc.c
+++ b/drivers/net/wireless/ath/ath5k/desc.c
@@ -24,7 +24,6 @@
#include "ath5k.h"
#include "reg.h"
#include "debug.h"
-#include "base.h"
/************************\
diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c
index 0d5d4033f12a..2481f9c7f4b6 100644
--- a/drivers/net/wireless/ath/ath5k/dma.c
+++ b/drivers/net/wireless/ath/ath5k/dma.c
@@ -35,7 +35,6 @@
#include "ath5k.h"
#include "reg.h"
#include "debug.h"
-#include "base.h"
/*********\
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c
index 9068b9165265..cd708c15b774 100644
--- a/drivers/net/wireless/ath/ath5k/eeprom.c
+++ b/drivers/net/wireless/ath/ath5k/eeprom.c
@@ -26,7 +26,6 @@
#include "ath5k.h"
#include "reg.h"
#include "debug.h"
-#include "base.h"
/******************\
@@ -1780,13 +1779,12 @@ ath5k_eeprom_detach(struct ath5k_hw *ah)
int
ath5k_eeprom_mode_from_channel(struct ieee80211_channel *channel)
{
- switch (channel->hw_value & CHANNEL_MODES) {
- case CHANNEL_A:
- case CHANNEL_XR:
+ switch (channel->hw_value) {
+ case AR5K_MODE_11A:
return AR5K_EEPROM_MODE_11A;
- case CHANNEL_G:
+ case AR5K_MODE_11G:
return AR5K_EEPROM_MODE_11G;
- case CHANNEL_B:
+ case AR5K_MODE_11B:
return AR5K_EEPROM_MODE_11B;
default:
return -1;
diff --git a/drivers/net/wireless/ath/ath5k/gpio.c b/drivers/net/wireless/ath/ath5k/gpio.c
index bc90503f4b7a..859297811914 100644
--- a/drivers/net/wireless/ath/ath5k/gpio.c
+++ b/drivers/net/wireless/ath/ath5k/gpio.c
@@ -23,7 +23,6 @@
#include "ath5k.h"
#include "reg.h"
#include "debug.h"
-#include "base.h"
/*
* Set led state
diff --git a/drivers/net/wireless/ath/ath5k/initvals.c b/drivers/net/wireless/ath/ath5k/initvals.c
index 5ab607f40e0e..1ffecc0fd3ed 100644
--- a/drivers/net/wireless/ath/ath5k/initvals.c
+++ b/drivers/net/wireless/ath/ath5k/initvals.c
@@ -22,7 +22,6 @@
#include "ath5k.h"
#include "reg.h"
#include "debug.h"
-#include "base.h"
/*
* Mode-independent initial register writes
diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c
index 8c17a00f7dad..c1151c723711 100644
--- a/drivers/net/wireless/ath/ath5k/led.c
+++ b/drivers/net/wireless/ath/ath5k/led.c
@@ -41,7 +41,6 @@
#include <linux/pci.h>
#include "ath5k.h"
-#include "base.h"
#define ATH_SDEVICE(subv, subd) \
.vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
index 2a715ca0c5e4..6ed4c0717e3e 100644
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
@@ -41,8 +41,10 @@
*
*/
+#include <net/mac80211.h>
#include <asm/unaligned.h>
+#include "ath5k.h"
#include "base.h"
#include "reg.h"
@@ -137,11 +139,8 @@ ath5k_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
/* Any MAC address is fine, all others are included through the
* filter.
*/
- memcpy(&ah->lladdr, vif->addr, ETH_ALEN);
ath5k_hw_set_lladdr(ah, vif->addr);
- memcpy(&avf->lladdr, vif->addr, ETH_ALEN);
-
ath5k_update_bssid_mask_and_opmode(ah, vif);
ret = 0;
end:
@@ -564,7 +563,7 @@ ath5k_get_stats(struct ieee80211_hw *hw,
static int
-ath5k_conf_tx(struct ieee80211_hw *hw, u16 queue,
+ath5k_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct ath5k_hw *ah = hw->priv;
@@ -603,7 +602,7 @@ ath5k_conf_tx(struct ieee80211_hw *hw, u16 queue,
static u64
-ath5k_get_tsf(struct ieee80211_hw *hw)
+ath5k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct ath5k_hw *ah = hw->priv;
@@ -612,7 +611,7 @@ ath5k_get_tsf(struct ieee80211_hw *hw)
static void
-ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+ath5k_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 tsf)
{
struct ath5k_hw *ah = hw->priv;
@@ -621,7 +620,7 @@ ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
static void
-ath5k_reset_tsf(struct ieee80211_hw *hw)
+ath5k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct ath5k_hw *ah = hw->priv;
diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c
index eaf79b49341e..c1dff2ced044 100644
--- a/drivers/net/wireless/ath/ath5k/pci.c
+++ b/drivers/net/wireless/ath/ath5k/pci.c
@@ -261,7 +261,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
ah->iobase = mem; /* So we can unmap it on detach */
/* Initialize */
- ret = ath5k_init_softc(ah, &ath_pci_bus_ops);
+ ret = ath5k_init_ah(ah, &ath_pci_bus_ops);
if (ret)
goto err_free;
@@ -287,7 +287,7 @@ ath5k_pci_remove(struct pci_dev *pdev)
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
struct ath5k_hw *ah = hw->priv;
- ath5k_deinit_softc(ah);
+ ath5k_deinit_ah(ah);
pci_iounmap(pdev, ah->iobase);
pci_release_region(pdev, 0);
pci_disable_device(pdev);
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c
index 067313845060..a7eafa3edc21 100644
--- a/drivers/net/wireless/ath/ath5k/pcu.c
+++ b/drivers/net/wireless/ath/ath5k/pcu.c
@@ -29,7 +29,6 @@
#include "ath5k.h"
#include "reg.h"
#include "debug.h"
-#include "base.h"
/*
* AR5212+ can use higher rates for ack transmission
@@ -152,7 +151,7 @@ unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
case AR5K_BWMODE_DEFAULT:
default:
slot_time = AR5K_INIT_SLOT_TIME_DEFAULT;
- if ((channel->hw_value & CHANNEL_CCK) && !ah->ah_short_slot)
+ if ((channel->hw_value == AR5K_MODE_11B) && !ah->ah_short_slot)
slot_time = AR5K_INIT_SLOT_TIME_B;
break;
}
@@ -183,7 +182,7 @@ unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah)
case AR5K_BWMODE_DEFAULT:
sifs = AR5K_INIT_SIFS_DEFAULT_BG;
default:
- if (channel->hw_value & CHANNEL_5GHZ)
+ if (channel->band == IEEE80211_BAND_5GHZ)
sifs = AR5K_INIT_SIFS_DEFAULT_A;
break;
}
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index 81e465e70175..01cb72de44cb 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -26,9 +26,9 @@
#include "ath5k.h"
#include "reg.h"
-#include "base.h"
#include "rfbuffer.h"
#include "rfgain.h"
+#include "../regd.h"
/******************\
@@ -38,7 +38,7 @@
/*
* Get the PHY Chip revision
*/
-u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
+u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band)
{
unsigned int i;
u32 srev;
@@ -47,11 +47,11 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
/*
* Set the radio chip access register
*/
- switch (chan) {
- case CHANNEL_2GHZ:
+ switch (band) {
+ case IEEE80211_BAND_2GHZ:
ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0));
break;
- case CHANNEL_5GHZ:
+ case IEEE80211_BAND_5GHZ:
ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
break;
default:
@@ -84,14 +84,16 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
/*
* Check if a channel is supported
*/
-bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags)
+bool ath5k_channel_ok(struct ath5k_hw *ah, struct ieee80211_channel *channel)
{
+ u16 freq = channel->center_freq;
+
/* Check if the channel is in our supported range */
- if (flags & CHANNEL_2GHZ) {
+ if (channel->band == IEEE80211_BAND_2GHZ) {
if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) &&
(freq <= ah->ah_capabilities.cap_range.range_2ghz_max))
return true;
- } else if (flags & CHANNEL_5GHZ)
+ } else if (channel->band == IEEE80211_BAND_5GHZ)
if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) &&
(freq <= ah->ah_capabilities.cap_range.range_5ghz_max))
return true;
@@ -224,7 +226,7 @@ static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
ds_coef_exp, ds_coef_man, clock;
BUG_ON(!(ah->ah_version == AR5K_AR5212) ||
- !(channel->hw_value & CHANNEL_OFDM));
+ (channel->hw_value == AR5K_MODE_11B));
/* Get coefficient
* ALGO: coef = (5 * clock / carrier_freq) / 2
@@ -298,7 +300,7 @@ static void ath5k_hw_wait_for_synth(struct ath5k_hw *ah,
u32 delay;
delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
AR5K_PHY_RX_DELAY_M;
- delay = (channel->hw_value & CHANNEL_CCK) ?
+ delay = (channel->hw_value == AR5K_MODE_11B) ?
((delay << 2) / 22) : (delay / 10);
if (ah->ah_bwmode == AR5K_BWMODE_10MHZ)
delay = delay << 1;
@@ -798,9 +800,9 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
}
/* Set Output and Driver bias current (OB/DB) */
- if (channel->hw_value & CHANNEL_2GHZ) {
+ if (channel->band == IEEE80211_BAND_2GHZ) {
- if (channel->hw_value & CHANNEL_CCK)
+ if (channel->hw_value == AR5K_MODE_11B)
ee_mode = AR5K_EEPROM_MODE_11B;
else
ee_mode = AR5K_EEPROM_MODE_11G;
@@ -825,7 +827,7 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
AR5K_RF_DB_2GHZ, true);
/* RF5111 always needs OB/DB for 5GHz, even if we use 2GHz */
- } else if ((channel->hw_value & CHANNEL_5GHZ) ||
+ } else if ((channel->band == IEEE80211_BAND_5GHZ) ||
(ah->ah_radio == AR5K_RF5111)) {
/* For 11a, Turbo and XR we need to choose
@@ -857,7 +859,7 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
if (ah->ah_radio == AR5K_RF5111) {
/* Set gain_F settings according to current step */
- if (channel->hw_value & CHANNEL_OFDM) {
+ if (channel->hw_value != AR5K_MODE_11B) {
AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL,
AR5K_PHY_FRAME_CTL_TX_CLIP,
@@ -914,7 +916,7 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
if (ah->ah_radio == AR5K_RF5112) {
/* Set gain_F settings according to current step */
- if (channel->hw_value & CHANNEL_OFDM) {
+ if (channel->hw_value != AR5K_MODE_11B) {
ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[0],
AR5K_RF_MIXGAIN_OVR, true);
@@ -1026,7 +1028,7 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
}
if (ah->ah_radio == AR5K_RF5413 &&
- channel->hw_value & CHANNEL_2GHZ) {
+ channel->band == IEEE80211_BAND_2GHZ) {
ath5k_hw_rfb_op(ah, rf_regs, 1, AR5K_RF_DERBY_CHAN_SEL_MODE,
true);
@@ -1138,7 +1140,7 @@ static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah,
*/
data0 = data1 = 0;
- if (channel->hw_value & CHANNEL_2GHZ) {
+ if (channel->band == IEEE80211_BAND_2GHZ) {
/* Map 2GHz channel to 5GHz Atheros channel ID */
ret = ath5k_hw_rf5111_chan2athchan(
ieee80211_frequency_to_channel(channel->center_freq),
@@ -1265,10 +1267,9 @@ static int ath5k_hw_channel(struct ath5k_hw *ah,
int ret;
/*
* Check bounds supported by the PHY (we don't care about regulatory
- * restrictions at this point). Note: hw_value already has the band
- * (CHANNEL_2GHZ, or CHANNEL_5GHZ) so we inform ath5k_channel_ok()
- * of the band by that */
- if (!ath5k_channel_ok(ah, channel->center_freq, channel->hw_value)) {
+ * restrictions at this point).
+ */
+ if (!ath5k_channel_ok(ah, channel)) {
ATH5K_ERR(ah,
"channel frequency (%u MHz) out of supported "
"band range\n",
@@ -1614,7 +1615,7 @@ int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
ret = ath5k_hw_rf511x_iq_calibrate(ah);
if ((ah->ah_radio == AR5K_RF5111 || ah->ah_radio == AR5K_RF5112) &&
- (channel->hw_value & CHANNEL_OFDM))
+ (channel->hw_value != AR5K_MODE_11B))
ath5k_hw_request_rfgain_probe(ah);
return ret;
@@ -1641,7 +1642,7 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
/* Convert current frequency to fbin value (the same way channels
* are stored on EEPROM, check out ath5k_eeprom_bin2freq) and scale
* up by 2 so we can compare it later */
- if (channel->hw_value & CHANNEL_2GHZ) {
+ if (channel->band == IEEE80211_BAND_2GHZ) {
chan_fbin = (channel->center_freq - 2300) * 10;
freq_band = AR5K_EEPROM_BAND_2GHZ;
} else {
@@ -1703,7 +1704,7 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
spur_freq_sigma_delta = (spur_delta_phase >> 10);
symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 4;
default:
- if (channel->hw_value == CHANNEL_A) {
+ if (channel->band == IEEE80211_BAND_5GHZ) {
/* Both sample_freq and chip_freq are 40MHz */
spur_delta_phase = (spur_offset << 17) / 25;
spur_freq_sigma_delta =
@@ -2226,15 +2227,20 @@ ath5k_get_chan_pcal_surrounding_piers(struct ath5k_hw *ah,
idx_l = 0;
idx_r = 0;
- if (!(channel->hw_value & CHANNEL_OFDM)) {
+ switch (channel->hw_value) {
+ case AR5K_EEPROM_MODE_11A:
+ pcinfo = ee->ee_pwr_cal_a;
+ mode = AR5K_EEPROM_MODE_11A;
+ break;
+ case AR5K_EEPROM_MODE_11B:
pcinfo = ee->ee_pwr_cal_b;
mode = AR5K_EEPROM_MODE_11B;
- } else if (channel->hw_value & CHANNEL_2GHZ) {
+ break;
+ case AR5K_EEPROM_MODE_11G:
+ default:
pcinfo = ee->ee_pwr_cal_g;
mode = AR5K_EEPROM_MODE_11G;
- } else {
- pcinfo = ee->ee_pwr_cal_a;
- mode = AR5K_EEPROM_MODE_11A;
+ break;
}
max = ee->ee_n_piers[mode] - 1;
@@ -2303,15 +2309,20 @@ ath5k_get_rate_pcal_data(struct ath5k_hw *ah,
idx_l = 0;
idx_r = 0;
- if (!(channel->hw_value & CHANNEL_OFDM)) {
+ switch (channel->hw_value) {
+ case AR5K_MODE_11A:
+ rpinfo = ee->ee_rate_tpwr_a;
+ mode = AR5K_EEPROM_MODE_11A;
+ break;
+ case AR5K_MODE_11B:
rpinfo = ee->ee_rate_tpwr_b;
mode = AR5K_EEPROM_MODE_11B;
- } else if (channel->hw_value & CHANNEL_2GHZ) {
+ break;
+ case AR5K_MODE_11G:
+ default:
rpinfo = ee->ee_rate_tpwr_g;
mode = AR5K_EEPROM_MODE_11G;
- } else {
- rpinfo = ee->ee_rate_tpwr_a;
- mode = AR5K_EEPROM_MODE_11A;
+ break;
}
max = ee->ee_rate_target_pwr_num[mode] - 1;
@@ -2392,24 +2403,22 @@ ath5k_get_max_ctl_power(struct ath5k_hw *ah,
ctl_mode = ath_regd_get_band_ctl(regulatory, channel->band);
- switch (channel->hw_value & CHANNEL_MODES) {
- case CHANNEL_A:
+ switch (channel->hw_value) {
+ case AR5K_MODE_11A:
if (ah->ah_bwmode == AR5K_BWMODE_40MHZ)
ctl_mode |= AR5K_CTL_TURBO;
else
ctl_mode |= AR5K_CTL_11A;
break;
- case CHANNEL_G:
+ case AR5K_MODE_11G:
if (ah->ah_bwmode == AR5K_BWMODE_40MHZ)
ctl_mode |= AR5K_CTL_TURBOG;
else
ctl_mode |= AR5K_CTL_11G;
break;
- case CHANNEL_B:
+ case AR5K_MODE_11B:
ctl_mode |= AR5K_CTL_11B;
break;
- case CHANNEL_XR:
- /* Fall through */
default:
return;
}
@@ -3292,7 +3301,7 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
/* Write OFDM timings on 5212*/
if (ah->ah_version == AR5K_AR5212 &&
- channel->hw_value & CHANNEL_OFDM) {
+ channel->hw_value != AR5K_MODE_11B) {
ret = ath5k_hw_write_ofdm_timings(ah, channel);
if (ret)
diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c
index 65f10398999e..776654228eaa 100644
--- a/drivers/net/wireless/ath/ath5k/qcu.c
+++ b/drivers/net/wireless/ath/ath5k/qcu.c
@@ -23,7 +23,6 @@ Queue Control Unit, DFS Control Unit Functions
#include "ath5k.h"
#include "reg.h"
#include "debug.h"
-#include "base.h"
/******************\
@@ -185,13 +184,6 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
case AR5K_TX_QUEUE_CAB:
queue = AR5K_TX_QUEUE_ID_CAB;
break;
- case AR5K_TX_QUEUE_XR_DATA:
- if (ah->ah_version != AR5K_AR5212)
- ATH5K_ERR(ah,
- "XR data queues only supported in"
- " 5212!\n");
- queue = AR5K_TX_QUEUE_ID_XR_DATA;
- break;
default:
return -EINVAL;
}
@@ -544,7 +536,7 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time)
*
* Also we have different lowest rate for 802.11a
*/
- if (channel->hw_value & CHANNEL_5GHZ)
+ if (channel->band == IEEE80211_BAND_5GHZ)
rate = &ah->sbands[IEEE80211_BAND_5GHZ].bitrates[0];
else
rate = &ah->sbands[IEEE80211_BAND_2GHZ].bitrates[0];
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 0686c5d8d56e..2abac257b4b4 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -30,7 +30,6 @@
#include <linux/platform_device.h>
#include "ath5k.h"
#include "reg.h"
-#include "base.h"
#include "debug.h"
@@ -102,12 +101,18 @@ static void ath5k_hw_init_core_clock(struct ath5k_hw *ah)
/*
* Set core clock frequency
*/
- if (channel->hw_value & CHANNEL_5GHZ)
- clock = 40; /* 802.11a */
- else if (channel->hw_value & CHANNEL_CCK)
- clock = 22; /* 802.11b */
- else
- clock = 44; /* 802.11g */
+ switch (channel->hw_value) {
+ case AR5K_MODE_11A:
+ clock = 40;
+ break;
+ case AR5K_MODE_11B:
+ clock = 22;
+ break;
+ case AR5K_MODE_11G:
+ default:
+ clock = 44;
+ break;
+ }
/* Use clock multiplier for non-default
* bwmode */
@@ -581,8 +586,9 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah)
/*
* Bring up MAC + PHY Chips and program PLL
+ * Channel is NULL for the initial wakeup.
*/
-int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
+int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel)
{
struct pci_dev *pdev = ah->pdev;
u32 turbo, mode, clock, bus_flags;
@@ -592,7 +598,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
mode = 0;
clock = 0;
- if ((ath5k_get_bus_type(ah) != ATH_AHB) || !initial) {
+ if ((ath5k_get_bus_type(ah) != ATH_AHB) || channel) {
/* Wakeup the device */
ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
if (ret) {
@@ -652,7 +658,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
/* On initialization skip PLL programming since we don't have
* a channel / mode set yet */
- if (initial)
+ if (!channel)
return 0;
if (ah->ah_version != AR5K_AR5210) {
@@ -668,13 +674,13 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
clock = AR5K_PHY_PLL_RF5111; /*Zero*/
}
- if (flags & CHANNEL_2GHZ) {
+ if (channel->band == IEEE80211_BAND_2GHZ) {
mode |= AR5K_PHY_MODE_FREQ_2GHZ;
clock |= AR5K_PHY_PLL_44MHZ;
- if (flags & CHANNEL_CCK) {
+ if (channel->hw_value == AR5K_MODE_11B) {
mode |= AR5K_PHY_MODE_MOD_CCK;
- } else if (flags & CHANNEL_OFDM) {
+ } else {
/* XXX Dynamic OFDM/CCK is not supported by the
* AR5211 so we set MOD_OFDM for plain g (no
* CCK headers) operation. We need to test
@@ -686,27 +692,16 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
mode |= AR5K_PHY_MODE_MOD_OFDM;
else
mode |= AR5K_PHY_MODE_MOD_DYN;
- } else {
- ATH5K_ERR(ah,
- "invalid radio modulation mode\n");
- return -EINVAL;
}
- } else if (flags & CHANNEL_5GHZ) {
- mode |= AR5K_PHY_MODE_FREQ_5GHZ;
+ } else if (channel->band == IEEE80211_BAND_5GHZ) {
+ mode |= (AR5K_PHY_MODE_FREQ_5GHZ |
+ AR5K_PHY_MODE_MOD_OFDM);
/* Different PLL setting for 5413 */
if (ah->ah_radio == AR5K_RF5413)
clock = AR5K_PHY_PLL_40MHZ_5413;
else
clock |= AR5K_PHY_PLL_40MHZ;
-
- if (flags & CHANNEL_OFDM)
- mode |= AR5K_PHY_MODE_MOD_OFDM;
- else {
- ATH5K_ERR(ah,
- "invalid radio modulation mode\n");
- return -EINVAL;
- }
} else {
ATH5K_ERR(ah, "invalid radio frequency mode\n");
return -EINVAL;
@@ -822,7 +817,7 @@ static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
u32 data;
ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD,
AR5K_PHY_CCKTXCTL);
- if (channel->hw_value & CHANNEL_5GHZ)
+ if (channel->band == IEEE80211_BAND_5GHZ)
data = 0xffb81020;
else
data = 0xffb80d20;
@@ -905,7 +900,7 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
/* Set CCK to OFDM power delta on tx power
* adjustment register */
if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
- if (channel->hw_value == CHANNEL_G)
+ if (channel->hw_value == AR5K_MODE_11G)
ath5k_hw_reg_write(ah,
AR5K_REG_SM((ee->ee_cck_ofdm_gain_delta * -1),
AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA) |
@@ -1084,37 +1079,23 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
ret = 0;
}
- switch (channel->hw_value & CHANNEL_MODES) {
- case CHANNEL_A:
- mode = AR5K_MODE_11A;
+ mode = channel->hw_value;
+ switch (mode) {
+ case AR5K_MODE_11A:
break;
- case CHANNEL_G:
-
+ case AR5K_MODE_11G:
if (ah->ah_version <= AR5K_AR5211) {
ATH5K_ERR(ah,
"G mode not available on 5210/5211");
return -EINVAL;
}
-
- mode = AR5K_MODE_11G;
break;
- case CHANNEL_B:
-
+ case AR5K_MODE_11B:
if (ah->ah_version < AR5K_AR5211) {
ATH5K_ERR(ah,
"B mode not available on 5210");
return -EINVAL;
}
-
- mode = AR5K_MODE_11B;
- break;
- case CHANNEL_XR:
- if (ah->ah_version == AR5K_AR5211) {
- ATH5K_ERR(ah,
- "XR mode not available on 5211");
- return -EINVAL;
- }
- mode = AR5K_MODE_XR;
break;
default:
ATH5K_ERR(ah,
@@ -1200,7 +1181,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
}
/* Wakeup the device */
- ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false);
+ ret = ath5k_hw_nic_wakeup(ah, channel);
if (ret)
return ret;
diff --git a/drivers/net/wireless/ath/ath5k/rfkill.c b/drivers/net/wireless/ath/ath5k/rfkill.c
index 945fc9f21e76..270a319f3aeb 100644
--- a/drivers/net/wireless/ath/ath5k/rfkill.c
+++ b/drivers/net/wireless/ath/ath5k/rfkill.c
@@ -33,7 +33,7 @@
* THE POSSIBILITY OF SUCH DAMAGES.
*/
-#include "base.h"
+#include "ath5k.h"
static inline void ath5k_rfkill_disable(struct ath5k_hw *ah)
diff --git a/drivers/net/wireless/ath/ath5k/sysfs.c b/drivers/net/wireless/ath/ath5k/sysfs.c
index 0244a36ba958..9364da7bd131 100644
--- a/drivers/net/wireless/ath/ath5k/sysfs.c
+++ b/drivers/net/wireless/ath/ath5k/sysfs.c
@@ -1,7 +1,6 @@
#include <linux/device.h>
#include <linux/pci.h>
-#include "base.h"
#include "ath5k.h"
#include "reg.h"
diff --git a/drivers/net/wireless/ath/ath5k/trace.h b/drivers/net/wireless/ath/ath5k/trace.h
index c741c871f4e9..39f002ed4a88 100644
--- a/drivers/net/wireless/ath/ath5k/trace.h
+++ b/drivers/net/wireless/ath/ath5k/trace.h
@@ -2,7 +2,6 @@
#define __TRACE_ATH5K_H
#include <linux/tracepoint.h>
-#include "base.h"
#ifndef CONFIG_ATH5K_TRACER
#undef TRACE_EVENT
@@ -11,6 +10,8 @@ static inline void trace_ ## name(proto) {}
#endif
struct sk_buff;
+struct ath5k_txq;
+struct ath5k_tx_status;
#undef TRACE_SYSTEM
#define TRACE_SYSTEM ath5k
diff --git a/drivers/net/wireless/ath/ath6kl/Kconfig b/drivers/net/wireless/ath/ath6kl/Kconfig
new file mode 100644
index 000000000000..3d5f8be20eac
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/Kconfig
@@ -0,0 +1,15 @@
+config ATH6KL
+ tristate "Atheros ath6kl support"
+ depends on MMC
+ depends on CFG80211
+ ---help---
+ This module adds support for wireless adapters based on
+ Atheros AR6003 chipset running over SDIO. If you choose to
+ build it as a module, it will be called ath6kl. Pls note
+ that AR6002 and AR6001 are not supported by this driver.
+
+config ATH6KL_DEBUG
+ bool "Atheros ath6kl debugging"
+ depends on ATH6KL
+ ---help---
+ Enables debug support
diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile
new file mode 100644
index 000000000000..8f7a0d1c290c
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/Makefile
@@ -0,0 +1,37 @@
+#------------------------------------------------------------------------------
+# Copyright (c) 2004-2010 Atheros Communications Inc.
+# All rights reserved.
+#
+#
+#
+# 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.
+#
+#
+#
+# Author(s): ="Atheros"
+#------------------------------------------------------------------------------
+
+obj-$(CONFIG_ATH6KL) := ath6kl.o
+ath6kl-y += debug.o
+ath6kl-y += htc_hif.o
+ath6kl-y += htc.o
+ath6kl-y += bmi.o
+ath6kl-y += cfg80211.o
+ath6kl-y += init.o
+ath6kl-y += main.o
+ath6kl-y += txrx.o
+ath6kl-y += wmi.o
+ath6kl-y += sdio.o
+ath6kl-$(CONFIG_NL80211_TESTMODE) += testmode.o
+
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/ath/ath6kl/bmi.c b/drivers/net/wireless/ath/ath6kl/bmi.c
new file mode 100644
index 000000000000..c5d11cc536e0
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/bmi.c
@@ -0,0 +1,689 @@
+/*
+ * Copyright (c) 2004-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "hif-ops.h"
+#include "target.h"
+#include "debug.h"
+
+static int ath6kl_get_bmi_cmd_credits(struct ath6kl *ar)
+{
+ u32 addr;
+ unsigned long timeout;
+ int ret;
+
+ ar->bmi.cmd_credits = 0;
+
+ /* Read the counter register to get the command credits */
+ addr = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4;
+
+ timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
+ while (time_before(jiffies, timeout) && !ar->bmi.cmd_credits) {
+
+ /*
+ * Hit the credit counter with a 4-byte access, the first byte
+ * read will hit the counter and cause a decrement, while the
+ * remaining 3 bytes has no effect. The rationale behind this
+ * is to make all HIF accesses 4-byte aligned.
+ */
+ ret = hif_read_write_sync(ar, addr,
+ (u8 *)&ar->bmi.cmd_credits, 4,
+ HIF_RD_SYNC_BYTE_INC);
+ if (ret) {
+ ath6kl_err("Unable to decrement the command credit count register: %d\n",
+ ret);
+ return ret;
+ }
+
+ /* The counter is only 8 bits.
+ * Ignore anything in the upper 3 bytes
+ */
+ ar->bmi.cmd_credits &= 0xFF;
+ }
+
+ if (!ar->bmi.cmd_credits) {
+ ath6kl_err("bmi communication timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int ath6kl_bmi_get_rx_lkahd(struct ath6kl *ar)
+{
+ unsigned long timeout;
+ u32 rx_word = 0;
+ int ret = 0;
+
+ timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
+ while (time_before(jiffies, timeout) && !rx_word) {
+ ret = hif_read_write_sync(ar, RX_LOOKAHEAD_VALID_ADDRESS,
+ (u8 *)&rx_word, sizeof(rx_word),
+ HIF_RD_SYNC_BYTE_INC);
+ if (ret) {
+ ath6kl_err("unable to read RX_LOOKAHEAD_VALID\n");
+ return ret;
+ }
+
+ /* all we really want is one bit */
+ rx_word &= (1 << ENDPOINT1);
+ }
+
+ if (!rx_word) {
+ ath6kl_err("bmi_recv_buf FIFO empty\n");
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int ath6kl_bmi_send_buf(struct ath6kl *ar, u8 *buf, u32 len)
+{
+ int ret;
+ u32 addr;
+
+ ret = ath6kl_get_bmi_cmd_credits(ar);
+ if (ret)
+ return ret;
+
+ addr = ar->mbox_info.htc_addr;
+
+ ret = hif_read_write_sync(ar, addr, buf, len,
+ HIF_WR_SYNC_BYTE_INC);
+ if (ret)
+ ath6kl_err("unable to send the bmi data to the device\n");
+
+ return ret;
+}
+
+static int ath6kl_bmi_recv_buf(struct ath6kl *ar, u8 *buf, u32 len)
+{
+ int ret;
+ u32 addr;
+
+ /*
+ * During normal bootup, small reads may be required.
+ * Rather than issue an HIF Read and then wait as the Target
+ * adds successive bytes to the FIFO, we wait here until
+ * we know that response data is available.
+ *
+ * This allows us to cleanly timeout on an unexpected
+ * Target failure rather than risk problems at the HIF level.
+ * In particular, this avoids SDIO timeouts and possibly garbage
+ * data on some host controllers. And on an interconnect
+ * such as Compact Flash (as well as some SDIO masters) which
+ * does not provide any indication on data timeout, it avoids
+ * a potential hang or garbage response.
+ *
+ * Synchronization is more difficult for reads larger than the
+ * size of the MBOX FIFO (128B), because the Target is unable
+ * to push the 129th byte of data until AFTER the Host posts an
+ * HIF Read and removes some FIFO data. So for large reads the
+ * Host proceeds to post an HIF Read BEFORE all the data is
+ * actually available to read. Fortunately, large BMI reads do
+ * not occur in practice -- they're supported for debug/development.
+ *
+ * So Host/Target BMI synchronization is divided into these cases:
+ * CASE 1: length < 4
+ * Should not happen
+ *
+ * CASE 2: 4 <= length <= 128
+ * Wait for first 4 bytes to be in FIFO
+ * If CONSERVATIVE_BMI_READ is enabled, also wait for
+ * a BMI command credit, which indicates that the ENTIRE
+ * response is available in the the FIFO
+ *
+ * CASE 3: length > 128
+ * Wait for the first 4 bytes to be in FIFO
+ *
+ * For most uses, a small timeout should be sufficient and we will
+ * usually see a response quickly; but there may be some unusual
+ * (debug) cases of BMI_EXECUTE where we want an larger timeout.
+ * For now, we use an unbounded busy loop while waiting for
+ * BMI_EXECUTE.
+ *
+ * If BMI_EXECUTE ever needs to support longer-latency execution,
+ * especially in production, this code needs to be enhanced to sleep
+ * and yield. Also note that BMI_COMMUNICATION_TIMEOUT is currently
+ * a function of Host processor speed.
+ */
+ if (len >= 4) { /* NB: Currently, always true */
+ ret = ath6kl_bmi_get_rx_lkahd(ar);
+ if (ret)
+ return ret;
+ }
+
+ addr = ar->mbox_info.htc_addr;
+ ret = hif_read_write_sync(ar, addr, buf, len,
+ HIF_RD_SYNC_BYTE_INC);
+ if (ret) {
+ ath6kl_err("Unable to read the bmi data from the device: %d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int ath6kl_bmi_done(struct ath6kl *ar)
+{
+ int ret;
+ u32 cid = BMI_DONE;
+
+ if (ar->bmi.done_sent) {
+ ath6kl_dbg(ATH6KL_DBG_BMI, "bmi done skipped\n");
+ return 0;
+ }
+
+ ar->bmi.done_sent = true;
+
+ ret = ath6kl_bmi_send_buf(ar, (u8 *)&cid, sizeof(cid));
+ if (ret) {
+ ath6kl_err("Unable to send bmi done: %d\n", ret);
+ return ret;
+ }
+
+ ath6kl_bmi_cleanup(ar);
+
+ return 0;
+}
+
+int ath6kl_bmi_get_target_info(struct ath6kl *ar,
+ struct ath6kl_bmi_target_info *targ_info)
+{
+ int ret;
+ u32 cid = BMI_GET_TARGET_INFO;
+
+ if (ar->bmi.done_sent) {
+ ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
+ return -EACCES;
+ }
+
+ ret = ath6kl_bmi_send_buf(ar, (u8 *)&cid, sizeof(cid));
+ if (ret) {
+ ath6kl_err("Unable to send get target info: %d\n", ret);
+ return ret;
+ }
+
+ ret = ath6kl_bmi_recv_buf(ar, (u8 *)&targ_info->version,
+ sizeof(targ_info->version));
+ if (ret) {
+ ath6kl_err("Unable to recv target info: %d\n", ret);
+ return ret;
+ }
+
+ if (le32_to_cpu(targ_info->version) == TARGET_VERSION_SENTINAL) {
+ /* Determine how many bytes are in the Target's targ_info */
+ ret = ath6kl_bmi_recv_buf(ar,
+ (u8 *)&targ_info->byte_count,
+ sizeof(targ_info->byte_count));
+ if (ret) {
+ ath6kl_err("unable to read target info byte count: %d\n",
+ ret);
+ return ret;
+ }
+
+ /*
+ * The target's targ_info doesn't match the host's targ_info.
+ * We need to do some backwards compatibility to make this work.
+ */
+ if (le32_to_cpu(targ_info->byte_count) != sizeof(*targ_info)) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ /* Read the remainder of the targ_info */
+ ret = ath6kl_bmi_recv_buf(ar,
+ ((u8 *)targ_info) +
+ sizeof(targ_info->byte_count),
+ sizeof(*targ_info) -
+ sizeof(targ_info->byte_count));
+
+ if (ret) {
+ ath6kl_err("Unable to read target info (%d bytes): %d\n",
+ targ_info->byte_count, ret);
+ return ret;
+ }
+ }
+
+ ath6kl_dbg(ATH6KL_DBG_BMI, "target info (ver: 0x%x type: 0x%x)\n",
+ targ_info->version, targ_info->type);
+
+ return 0;
+}
+
+int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
+{
+ u32 cid = BMI_READ_MEMORY;
+ int ret;
+ u32 offset;
+ u32 len_remain, rx_len;
+ u16 size;
+
+ if (ar->bmi.done_sent) {
+ ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
+ return -EACCES;
+ }
+
+ size = BMI_DATASZ_MAX + sizeof(cid) + sizeof(addr) + sizeof(len);
+ if (size > MAX_BMI_CMDBUF_SZ) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+ memset(ar->bmi.cmd_buf, 0, size);
+
+ ath6kl_dbg(ATH6KL_DBG_BMI,
+ "bmi read memory: device: addr: 0x%x, len: %d\n",
+ addr, len);
+
+ len_remain = len;
+
+ while (len_remain) {
+ rx_len = (len_remain < BMI_DATASZ_MAX) ?
+ len_remain : BMI_DATASZ_MAX;
+ offset = 0;
+ memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
+ offset += sizeof(cid);
+ memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
+ offset += sizeof(addr);
+ memcpy(&(ar->bmi.cmd_buf[offset]), &rx_len, sizeof(rx_len));
+ offset += sizeof(len);
+
+ ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+ if (ret) {
+ ath6kl_err("Unable to write to the device: %d\n",
+ ret);
+ return ret;
+ }
+ ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, rx_len);
+ if (ret) {
+ ath6kl_err("Unable to read from the device: %d\n",
+ ret);
+ return ret;
+ }
+ memcpy(&buf[len - len_remain], ar->bmi.cmd_buf, rx_len);
+ len_remain -= rx_len; addr += rx_len;
+ }
+
+ return 0;
+}
+
+int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
+{
+ u32 cid = BMI_WRITE_MEMORY;
+ int ret;
+ u32 offset;
+ u32 len_remain, tx_len;
+ const u32 header = sizeof(cid) + sizeof(addr) + sizeof(len);
+ u8 aligned_buf[BMI_DATASZ_MAX];
+ u8 *src;
+
+ if (ar->bmi.done_sent) {
+ ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
+ return -EACCES;
+ }
+
+ if ((BMI_DATASZ_MAX + header) > MAX_BMI_CMDBUF_SZ) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ memset(ar->bmi.cmd_buf, 0, BMI_DATASZ_MAX + header);
+
+ ath6kl_dbg(ATH6KL_DBG_BMI,
+ "bmi write memory: addr: 0x%x, len: %d\n", addr, len);
+
+ len_remain = len;
+ while (len_remain) {
+ src = &buf[len - len_remain];
+
+ if (len_remain < (BMI_DATASZ_MAX - header)) {
+ if (len_remain & 3) {
+ /* align it with 4 bytes */
+ len_remain = len_remain +
+ (4 - (len_remain & 3));
+ memcpy(aligned_buf, src, len_remain);
+ src = aligned_buf;
+ }
+ tx_len = len_remain;
+ } else {
+ tx_len = (BMI_DATASZ_MAX - header);
+ }
+
+ offset = 0;
+ memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
+ offset += sizeof(cid);
+ memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
+ offset += sizeof(addr);
+ memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len));
+ offset += sizeof(tx_len);
+ memcpy(&(ar->bmi.cmd_buf[offset]), src, tx_len);
+ offset += tx_len;
+
+ ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+ if (ret) {
+ ath6kl_err("Unable to write to the device: %d\n",
+ ret);
+ return ret;
+ }
+ len_remain -= tx_len; addr += tx_len;
+ }
+
+ return 0;
+}
+
+int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param)
+{
+ u32 cid = BMI_EXECUTE;
+ int ret;
+ u32 offset;
+ u16 size;
+
+ if (ar->bmi.done_sent) {
+ ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
+ return -EACCES;
+ }
+
+ size = sizeof(cid) + sizeof(addr) + sizeof(param);
+ if (size > MAX_BMI_CMDBUF_SZ) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+ memset(ar->bmi.cmd_buf, 0, size);
+
+ ath6kl_dbg(ATH6KL_DBG_BMI, "bmi execute: addr: 0x%x, param: %d)\n",
+ addr, *param);
+
+ offset = 0;
+ memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
+ offset += sizeof(cid);
+ memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
+ offset += sizeof(addr);
+ memcpy(&(ar->bmi.cmd_buf[offset]), param, sizeof(*param));
+ offset += sizeof(*param);
+
+ ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+ if (ret) {
+ ath6kl_err("Unable to write to the device: %d\n", ret);
+ return ret;
+ }
+
+ ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param));
+ if (ret) {
+ ath6kl_err("Unable to read from the device: %d\n", ret);
+ return ret;
+ }
+
+ memcpy(param, ar->bmi.cmd_buf, sizeof(*param));
+
+ return 0;
+}
+
+int ath6kl_bmi_set_app_start(struct ath6kl *ar, u32 addr)
+{
+ u32 cid = BMI_SET_APP_START;
+ int ret;
+ u32 offset;
+ u16 size;
+
+ if (ar->bmi.done_sent) {
+ ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
+ return -EACCES;
+ }
+
+ size = sizeof(cid) + sizeof(addr);
+ if (size > MAX_BMI_CMDBUF_SZ) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+ memset(ar->bmi.cmd_buf, 0, size);
+
+ ath6kl_dbg(ATH6KL_DBG_BMI, "bmi set app start: addr: 0x%x\n", addr);
+
+ offset = 0;
+ memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
+ offset += sizeof(cid);
+ memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
+ offset += sizeof(addr);
+
+ ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+ if (ret) {
+ ath6kl_err("Unable to write to the device: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param)
+{
+ u32 cid = BMI_READ_SOC_REGISTER;
+ int ret;
+ u32 offset;
+ u16 size;
+
+ if (ar->bmi.done_sent) {
+ ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
+ return -EACCES;
+ }
+
+ size = sizeof(cid) + sizeof(addr);
+ if (size > MAX_BMI_CMDBUF_SZ) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+ memset(ar->bmi.cmd_buf, 0, size);
+
+ ath6kl_dbg(ATH6KL_DBG_BMI, "bmi read SOC reg: addr: 0x%x\n", addr);
+
+ offset = 0;
+ memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
+ offset += sizeof(cid);
+ memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
+ offset += sizeof(addr);
+
+ ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+ if (ret) {
+ ath6kl_err("Unable to write to the device: %d\n", ret);
+ return ret;
+ }
+
+ ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param));
+ if (ret) {
+ ath6kl_err("Unable to read from the device: %d\n", ret);
+ return ret;
+ }
+ memcpy(param, ar->bmi.cmd_buf, sizeof(*param));
+
+ return 0;
+}
+
+int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param)
+{
+ u32 cid = BMI_WRITE_SOC_REGISTER;
+ int ret;
+ u32 offset;
+ u16 size;
+
+ if (ar->bmi.done_sent) {
+ ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
+ return -EACCES;
+ }
+
+ size = sizeof(cid) + sizeof(addr) + sizeof(param);
+ if (size > MAX_BMI_CMDBUF_SZ) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+ memset(ar->bmi.cmd_buf, 0, size);
+
+ ath6kl_dbg(ATH6KL_DBG_BMI,
+ "bmi write SOC reg: addr: 0x%x, param: %d\n",
+ addr, param);
+
+ offset = 0;
+ memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
+ offset += sizeof(cid);
+ memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
+ offset += sizeof(addr);
+ memcpy(&(ar->bmi.cmd_buf[offset]), &param, sizeof(param));
+ offset += sizeof(param);
+
+ ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+ if (ret) {
+ ath6kl_err("Unable to write to the device: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len)
+{
+ u32 cid = BMI_LZ_DATA;
+ int ret;
+ u32 offset;
+ u32 len_remain, tx_len;
+ const u32 header = sizeof(cid) + sizeof(len);
+ u16 size;
+
+ if (ar->bmi.done_sent) {
+ ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
+ return -EACCES;
+ }
+
+ size = BMI_DATASZ_MAX + header;
+ if (size > MAX_BMI_CMDBUF_SZ) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+ memset(ar->bmi.cmd_buf, 0, size);
+
+ ath6kl_dbg(ATH6KL_DBG_BMI, "bmi send LZ data: len: %d)\n",
+ len);
+
+ len_remain = len;
+ while (len_remain) {
+ tx_len = (len_remain < (BMI_DATASZ_MAX - header)) ?
+ len_remain : (BMI_DATASZ_MAX - header);
+
+ offset = 0;
+ memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
+ offset += sizeof(cid);
+ memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len));
+ offset += sizeof(tx_len);
+ memcpy(&(ar->bmi.cmd_buf[offset]), &buf[len - len_remain],
+ tx_len);
+ offset += tx_len;
+
+ ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+ if (ret) {
+ ath6kl_err("Unable to write to the device: %d\n",
+ ret);
+ return ret;
+ }
+
+ len_remain -= tx_len;
+ }
+
+ return 0;
+}
+
+int ath6kl_bmi_lz_stream_start(struct ath6kl *ar, u32 addr)
+{
+ u32 cid = BMI_LZ_STREAM_START;
+ int ret;
+ u32 offset;
+ u16 size;
+
+ if (ar->bmi.done_sent) {
+ ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
+ return -EACCES;
+ }
+
+ size = sizeof(cid) + sizeof(addr);
+ if (size > MAX_BMI_CMDBUF_SZ) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+ memset(ar->bmi.cmd_buf, 0, size);
+
+ ath6kl_dbg(ATH6KL_DBG_BMI,
+ "bmi LZ stream start: addr: 0x%x)\n",
+ addr);
+
+ offset = 0;
+ memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
+ offset += sizeof(cid);
+ memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
+ offset += sizeof(addr);
+
+ ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+ if (ret) {
+ ath6kl_err("Unable to start LZ stream to the device: %d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int ath6kl_bmi_fast_download(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
+{
+ int ret;
+ u32 last_word = 0;
+ u32 last_word_offset = len & ~0x3;
+ u32 unaligned_bytes = len & 0x3;
+
+ ret = ath6kl_bmi_lz_stream_start(ar, addr);
+ if (ret)
+ return ret;
+
+ if (unaligned_bytes) {
+ /* copy the last word into a zero padded buffer */
+ memcpy(&last_word, &buf[last_word_offset], unaligned_bytes);
+ }
+
+ ret = ath6kl_bmi_lz_data(ar, buf, last_word_offset);
+ if (ret)
+ return ret;
+
+ if (unaligned_bytes)
+ ret = ath6kl_bmi_lz_data(ar, (u8 *)&last_word, 4);
+
+ if (!ret) {
+ /* Close compressed stream and open a new (fake) one.
+ * This serves mainly to flush Target caches. */
+ ret = ath6kl_bmi_lz_stream_start(ar, 0x00);
+ }
+ return ret;
+}
+
+int ath6kl_bmi_init(struct ath6kl *ar)
+{
+ ar->bmi.cmd_buf = kzalloc(MAX_BMI_CMDBUF_SZ, GFP_ATOMIC);
+
+ if (!ar->bmi.cmd_buf)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void ath6kl_bmi_cleanup(struct ath6kl *ar)
+{
+ kfree(ar->bmi.cmd_buf);
+ ar->bmi.cmd_buf = NULL;
+}
diff --git a/drivers/net/wireless/ath/ath6kl/bmi.h b/drivers/net/wireless/ath/ath6kl/bmi.h
new file mode 100644
index 000000000000..96851d5df24b
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/bmi.h
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2004-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BMI_H
+#define BMI_H
+
+/*
+ * Bootloader Messaging Interface (BMI)
+ *
+ * BMI is a very simple messaging interface used during initialization
+ * to read memory, write memory, execute code, and to define an
+ * application entry PC.
+ *
+ * It is used to download an application to ATH6KL, to provide
+ * patches to code that is already resident on ATH6KL, and generally
+ * to examine and modify state. The Host has an opportunity to use
+ * BMI only once during bootup. Once the Host issues a BMI_DONE
+ * command, this opportunity ends.
+ *
+ * The Host writes BMI requests to mailbox0, and reads BMI responses
+ * from mailbox0. BMI requests all begin with a command
+ * (see below for specific commands), and are followed by
+ * command-specific data.
+ *
+ * Flow control:
+ * The Host can only issue a command once the Target gives it a
+ * "BMI Command Credit", using ATH6KL Counter #4. As soon as the
+ * Target has completed a command, it issues another BMI Command
+ * Credit (so the Host can issue the next command).
+ *
+ * BMI handles all required Target-side cache flushing.
+ */
+
+#define MAX_BMI_CMDBUF_SZ (BMI_DATASZ_MAX + \
+ (sizeof(u32) * 3 /* cmd + addr + len */))
+
+/* Maximum data size used for BMI transfers */
+#define BMI_DATASZ_MAX 256
+
+/* BMI Commands */
+
+#define BMI_NO_COMMAND 0
+
+#define BMI_DONE 1
+/*
+ * Semantics: Host is done using BMI
+ * Request format:
+ * u32 command (BMI_DONE)
+ * Response format: none
+ */
+
+#define BMI_READ_MEMORY 2
+/*
+ * Semantics: Host reads ATH6KL memory
+ * Request format:
+ * u32 command (BMI_READ_MEMORY)
+ * u32 address
+ * u32 length, at most BMI_DATASZ_MAX
+ * Response format:
+ * u8 data[length]
+ */
+
+#define BMI_WRITE_MEMORY 3
+/*
+ * Semantics: Host writes ATH6KL memory
+ * Request format:
+ * u32 command (BMI_WRITE_MEMORY)
+ * u32 address
+ * u32 length, at most BMI_DATASZ_MAX
+ * u8 data[length]
+ * Response format: none
+ */
+
+#define BMI_EXECUTE 4
+/*
+ * Semantics: Causes ATH6KL to execute code
+ * Request format:
+ * u32 command (BMI_EXECUTE)
+ * u32 address
+ * u32 parameter
+ * Response format:
+ * u32 return value
+ */
+
+#define BMI_SET_APP_START 5
+/*
+ * Semantics: Set Target application starting address
+ * Request format:
+ * u32 command (BMI_SET_APP_START)
+ * u32 address
+ * Response format: none
+ */
+
+#define BMI_READ_SOC_REGISTER 6
+/*
+ * Semantics: Read a 32-bit Target SOC register.
+ * Request format:
+ * u32 command (BMI_READ_REGISTER)
+ * u32 address
+ * Response format:
+ * u32 value
+ */
+
+#define BMI_WRITE_SOC_REGISTER 7
+/*
+ * Semantics: Write a 32-bit Target SOC register.
+ * Request format:
+ * u32 command (BMI_WRITE_REGISTER)
+ * u32 address
+ * u32 value
+ *
+ * Response format: none
+ */
+
+#define BMI_GET_TARGET_ID 8
+#define BMI_GET_TARGET_INFO 8
+/*
+ * Semantics: Fetch the 4-byte Target information
+ * Request format:
+ * u32 command (BMI_GET_TARGET_ID/INFO)
+ * Response format1 (old firmware):
+ * u32 TargetVersionID
+ * Response format2 (newer firmware):
+ * u32 TARGET_VERSION_SENTINAL
+ * struct bmi_target_info;
+ */
+
+#define TARGET_VERSION_SENTINAL 0xffffffff
+#define TARGET_TYPE_AR6003 3
+#define TARGET_TYPE_AR6004 5
+#define BMI_ROMPATCH_INSTALL 9
+/*
+ * Semantics: Install a ROM Patch.
+ * Request format:
+ * u32 command (BMI_ROMPATCH_INSTALL)
+ * u32 Target ROM Address
+ * u32 Target RAM Address or Value (depending on Target Type)
+ * u32 Size, in bytes
+ * u32 Activate? 1-->activate;
+ * 0-->install but do not activate
+ * Response format:
+ * u32 PatchID
+ */
+
+#define BMI_ROMPATCH_UNINSTALL 10
+/*
+ * Semantics: Uninstall a previously-installed ROM Patch,
+ * automatically deactivating, if necessary.
+ * Request format:
+ * u32 command (BMI_ROMPATCH_UNINSTALL)
+ * u32 PatchID
+ *
+ * Response format: none
+ */
+
+#define BMI_ROMPATCH_ACTIVATE 11
+/*
+ * Semantics: Activate a list of previously-installed ROM Patches.
+ * Request format:
+ * u32 command (BMI_ROMPATCH_ACTIVATE)
+ * u32 rompatch_count
+ * u32 PatchID[rompatch_count]
+ *
+ * Response format: none
+ */
+
+#define BMI_ROMPATCH_DEACTIVATE 12
+/*
+ * Semantics: Deactivate a list of active ROM Patches.
+ * Request format:
+ * u32 command (BMI_ROMPATCH_DEACTIVATE)
+ * u32 rompatch_count
+ * u32 PatchID[rompatch_count]
+ *
+ * Response format: none
+ */
+
+
+#define BMI_LZ_STREAM_START 13
+/*
+ * Semantics: Begin an LZ-compressed stream of input
+ * which is to be uncompressed by the Target to an
+ * output buffer at address. The output buffer must
+ * be sufficiently large to hold the uncompressed
+ * output from the compressed input stream. This BMI
+ * command should be followed by a series of 1 or more
+ * BMI_LZ_DATA commands.
+ * u32 command (BMI_LZ_STREAM_START)
+ * u32 address
+ * Note: Not supported on all versions of ROM firmware.
+ */
+
+#define BMI_LZ_DATA 14
+/*
+ * Semantics: Host writes ATH6KL memory with LZ-compressed
+ * data which is uncompressed by the Target. This command
+ * must be preceded by a BMI_LZ_STREAM_START command. A series
+ * of BMI_LZ_DATA commands are considered part of a single
+ * input stream until another BMI_LZ_STREAM_START is issued.
+ * Request format:
+ * u32 command (BMI_LZ_DATA)
+ * u32 length (of compressed data),
+ * at most BMI_DATASZ_MAX
+ * u8 CompressedData[length]
+ * Response format: none
+ * Note: Not supported on all versions of ROM firmware.
+ */
+
+#define BMI_COMMUNICATION_TIMEOUT 1000 /* in msec */
+
+struct ath6kl;
+struct ath6kl_bmi_target_info {
+ __le32 byte_count; /* size of this structure */
+ __le32 version; /* target version id */
+ __le32 type; /* target type */
+} __packed;
+
+int ath6kl_bmi_init(struct ath6kl *ar);
+void ath6kl_bmi_cleanup(struct ath6kl *ar);
+int ath6kl_bmi_done(struct ath6kl *ar);
+int ath6kl_bmi_get_target_info(struct ath6kl *ar,
+ struct ath6kl_bmi_target_info *targ_info);
+int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len);
+int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len);
+int ath6kl_bmi_execute(struct ath6kl *ar,
+ u32 addr, u32 *param);
+int ath6kl_bmi_set_app_start(struct ath6kl *ar,
+ u32 addr);
+int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param);
+int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param);
+int ath6kl_bmi_lz_data(struct ath6kl *ar,
+ u8 *buf, u32 len);
+int ath6kl_bmi_lz_stream_start(struct ath6kl *ar,
+ u32 addr);
+int ath6kl_bmi_fast_download(struct ath6kl *ar,
+ u32 addr, u8 *buf, u32 len);
+#endif
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
new file mode 100644
index 000000000000..3aff36bad5d3
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -0,0 +1,1914 @@
+/*
+ * Copyright (c) 2004-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "cfg80211.h"
+#include "debug.h"
+#include "hif-ops.h"
+#include "testmode.h"
+
+static unsigned int ath6kl_p2p;
+
+module_param(ath6kl_p2p, uint, 0644);
+
+#define RATETAB_ENT(_rate, _rateid, _flags) { \
+ .bitrate = (_rate), \
+ .flags = (_flags), \
+ .hw_value = (_rateid), \
+}
+
+#define CHAN2G(_channel, _freq, _flags) { \
+ .band = IEEE80211_BAND_2GHZ, \
+ .hw_value = (_channel), \
+ .center_freq = (_freq), \
+ .flags = (_flags), \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+}
+
+#define CHAN5G(_channel, _flags) { \
+ .band = IEEE80211_BAND_5GHZ, \
+ .hw_value = (_channel), \
+ .center_freq = 5000 + (5 * (_channel)), \
+ .flags = (_flags), \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+}
+
+static struct ieee80211_rate ath6kl_rates[] = {
+ RATETAB_ENT(10, 0x1, 0),
+ RATETAB_ENT(20, 0x2, 0),
+ RATETAB_ENT(55, 0x4, 0),
+ RATETAB_ENT(110, 0x8, 0),
+ RATETAB_ENT(60, 0x10, 0),
+ RATETAB_ENT(90, 0x20, 0),
+ RATETAB_ENT(120, 0x40, 0),
+ RATETAB_ENT(180, 0x80, 0),
+ RATETAB_ENT(240, 0x100, 0),
+ RATETAB_ENT(360, 0x200, 0),
+ RATETAB_ENT(480, 0x400, 0),
+ RATETAB_ENT(540, 0x800, 0),
+};
+
+#define ath6kl_a_rates (ath6kl_rates + 4)
+#define ath6kl_a_rates_size 8
+#define ath6kl_g_rates (ath6kl_rates + 0)
+#define ath6kl_g_rates_size 12
+
+static struct ieee80211_channel ath6kl_2ghz_channels[] = {
+ CHAN2G(1, 2412, 0),
+ CHAN2G(2, 2417, 0),
+ CHAN2G(3, 2422, 0),
+ CHAN2G(4, 2427, 0),
+ CHAN2G(5, 2432, 0),
+ CHAN2G(6, 2437, 0),
+ CHAN2G(7, 2442, 0),
+ CHAN2G(8, 2447, 0),
+ CHAN2G(9, 2452, 0),
+ CHAN2G(10, 2457, 0),
+ CHAN2G(11, 2462, 0),
+ CHAN2G(12, 2467, 0),
+ CHAN2G(13, 2472, 0),
+ CHAN2G(14, 2484, 0),
+};
+
+static struct ieee80211_channel ath6kl_5ghz_a_channels[] = {
+ CHAN5G(34, 0), CHAN5G(36, 0),
+ CHAN5G(38, 0), CHAN5G(40, 0),
+ CHAN5G(42, 0), CHAN5G(44, 0),
+ CHAN5G(46, 0), CHAN5G(48, 0),
+ CHAN5G(52, 0), CHAN5G(56, 0),
+ CHAN5G(60, 0), CHAN5G(64, 0),
+ CHAN5G(100, 0), CHAN5G(104, 0),
+ CHAN5G(108, 0), CHAN5G(112, 0),
+ CHAN5G(116, 0), CHAN5G(120, 0),
+ CHAN5G(124, 0), CHAN5G(128, 0),
+ CHAN5G(132, 0), CHAN5G(136, 0),
+ CHAN5G(140, 0), CHAN5G(149, 0),
+ CHAN5G(153, 0), CHAN5G(157, 0),
+ CHAN5G(161, 0), CHAN5G(165, 0),
+ CHAN5G(184, 0), CHAN5G(188, 0),
+ CHAN5G(192, 0), CHAN5G(196, 0),
+ CHAN5G(200, 0), CHAN5G(204, 0),
+ CHAN5G(208, 0), CHAN5G(212, 0),
+ CHAN5G(216, 0),
+};
+
+static struct ieee80211_supported_band ath6kl_band_2ghz = {
+ .n_channels = ARRAY_SIZE(ath6kl_2ghz_channels),
+ .channels = ath6kl_2ghz_channels,
+ .n_bitrates = ath6kl_g_rates_size,
+ .bitrates = ath6kl_g_rates,
+};
+
+static struct ieee80211_supported_band ath6kl_band_5ghz = {
+ .n_channels = ARRAY_SIZE(ath6kl_5ghz_a_channels),
+ .channels = ath6kl_5ghz_a_channels,
+ .n_bitrates = ath6kl_a_rates_size,
+ .bitrates = ath6kl_a_rates,
+};
+
+static int ath6kl_set_wpa_version(struct ath6kl *ar,
+ enum nl80211_wpa_versions wpa_version)
+{
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: %u\n", __func__, wpa_version);
+
+ if (!wpa_version) {
+ ar->auth_mode = NONE_AUTH;
+ } else if (wpa_version & NL80211_WPA_VERSION_2) {
+ ar->auth_mode = WPA2_AUTH;
+ } else if (wpa_version & NL80211_WPA_VERSION_1) {
+ ar->auth_mode = WPA_AUTH;
+ } else {
+ ath6kl_err("%s: %u not supported\n", __func__, wpa_version);
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int ath6kl_set_auth_type(struct ath6kl *ar,
+ enum nl80211_auth_type auth_type)
+{
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, auth_type);
+
+ switch (auth_type) {
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+ ar->dot11_auth_mode = OPEN_AUTH;
+ break;
+ case NL80211_AUTHTYPE_SHARED_KEY:
+ ar->dot11_auth_mode = SHARED_AUTH;
+ break;
+ case NL80211_AUTHTYPE_NETWORK_EAP:
+ ar->dot11_auth_mode = LEAP_AUTH;
+ break;
+
+ case NL80211_AUTHTYPE_AUTOMATIC:
+ ar->dot11_auth_mode = OPEN_AUTH | SHARED_AUTH;
+ break;
+
+ default:
+ ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type);
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int ath6kl_set_cipher(struct ath6kl *ar, u32 cipher, bool ucast)
+{
+ u8 *ar_cipher = ucast ? &ar->prwise_crypto : &ar->grp_crypto;
+ u8 *ar_cipher_len = ucast ? &ar->prwise_crypto_len :
+ &ar->grp_crypto_len;
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n",
+ __func__, cipher, ucast);
+
+ switch (cipher) {
+ case 0:
+ /* our own hack to use value 0 as no crypto used */
+ *ar_cipher = NONE_CRYPT;
+ *ar_cipher_len = 0;
+ break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ *ar_cipher = WEP_CRYPT;
+ *ar_cipher_len = 5;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ *ar_cipher = WEP_CRYPT;
+ *ar_cipher_len = 13;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ *ar_cipher = TKIP_CRYPT;
+ *ar_cipher_len = 0;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ *ar_cipher = AES_CRYPT;
+ *ar_cipher_len = 0;
+ break;
+ default:
+ ath6kl_err("cipher 0x%x not supported\n", cipher);
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static void ath6kl_set_key_mgmt(struct ath6kl *ar, u32 key_mgmt)
+{
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, key_mgmt);
+
+ if (key_mgmt == WLAN_AKM_SUITE_PSK) {
+ if (ar->auth_mode == WPA_AUTH)
+ ar->auth_mode = WPA_PSK_AUTH;
+ else if (ar->auth_mode == WPA2_AUTH)
+ ar->auth_mode = WPA2_PSK_AUTH;
+ } else if (key_mgmt != WLAN_AKM_SUITE_8021X) {
+ ar->auth_mode = NONE_AUTH;
+ }
+}
+
+static bool ath6kl_cfg80211_ready(struct ath6kl *ar)
+{
+ if (!test_bit(WMI_READY, &ar->flag)) {
+ ath6kl_err("wmi is not ready\n");
+ return false;
+ }
+
+ if (!test_bit(WLAN_ENABLED, &ar->flag)) {
+ ath6kl_err("wlan disabled\n");
+ return false;
+ }
+
+ return true;
+}
+
+static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+ int status;
+
+ ar->sme_state = SME_CONNECTING;
+
+ if (!ath6kl_cfg80211_ready(ar))
+ return -EIO;
+
+ if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
+ ath6kl_err("destroy in progress\n");
+ return -EBUSY;
+ }
+
+ if (test_bit(SKIP_SCAN, &ar->flag) &&
+ ((sme->channel && sme->channel->center_freq == 0) ||
+ (sme->bssid && is_zero_ether_addr(sme->bssid)))) {
+ ath6kl_err("SkipScan: channel or bssid invalid\n");
+ return -EINVAL;
+ }
+
+ if (down_interruptible(&ar->sem)) {
+ ath6kl_err("busy, couldn't get access\n");
+ return -ERESTARTSYS;
+ }
+
+ if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
+ ath6kl_err("busy, destroy in progress\n");
+ up(&ar->sem);
+ return -EBUSY;
+ }
+
+ if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) {
+ /*
+ * sleep until the command queue drains
+ */
+ wait_event_interruptible_timeout(ar->event_wq,
+ ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0,
+ WMI_TIMEOUT);
+ if (signal_pending(current)) {
+ ath6kl_err("cmd queue drain timeout\n");
+ up(&ar->sem);
+ return -EINTR;
+ }
+ }
+
+ if (test_bit(CONNECTED, &ar->flag) &&
+ ar->ssid_len == sme->ssid_len &&
+ !memcmp(ar->ssid, sme->ssid, ar->ssid_len)) {
+ ar->reconnect_flag = true;
+ status = ath6kl_wmi_reconnect_cmd(ar->wmi, ar->req_bssid,
+ ar->ch_hint);
+
+ up(&ar->sem);
+ if (status) {
+ ath6kl_err("wmi_reconnect_cmd failed\n");
+ return -EIO;
+ }
+ return 0;
+ } else if (ar->ssid_len == sme->ssid_len &&
+ !memcmp(ar->ssid, sme->ssid, ar->ssid_len)) {
+ ath6kl_disconnect(ar);
+ }
+
+ memset(ar->ssid, 0, sizeof(ar->ssid));
+ ar->ssid_len = sme->ssid_len;
+ memcpy(ar->ssid, sme->ssid, sme->ssid_len);
+
+ if (sme->channel)
+ ar->ch_hint = sme->channel->center_freq;
+
+ memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
+ if (sme->bssid && !is_broadcast_ether_addr(sme->bssid))
+ memcpy(ar->req_bssid, sme->bssid, sizeof(ar->req_bssid));
+
+ ath6kl_set_wpa_version(ar, sme->crypto.wpa_versions);
+
+ status = ath6kl_set_auth_type(ar, sme->auth_type);
+ if (status) {
+ up(&ar->sem);
+ return status;
+ }
+
+ if (sme->crypto.n_ciphers_pairwise)
+ ath6kl_set_cipher(ar, sme->crypto.ciphers_pairwise[0], true);
+ else
+ ath6kl_set_cipher(ar, 0, true);
+
+ ath6kl_set_cipher(ar, sme->crypto.cipher_group, false);
+
+ if (sme->crypto.n_akm_suites)
+ ath6kl_set_key_mgmt(ar, sme->crypto.akm_suites[0]);
+
+ if ((sme->key_len) &&
+ (ar->auth_mode == NONE_AUTH) && (ar->prwise_crypto == WEP_CRYPT)) {
+ struct ath6kl_key *key = NULL;
+
+ if (sme->key_idx < WMI_MIN_KEY_INDEX ||
+ sme->key_idx > WMI_MAX_KEY_INDEX) {
+ ath6kl_err("key index %d out of bounds\n",
+ sme->key_idx);
+ up(&ar->sem);
+ return -ENOENT;
+ }
+
+ key = &ar->keys[sme->key_idx];
+ key->key_len = sme->key_len;
+ memcpy(key->key, sme->key, key->key_len);
+ key->cipher = ar->prwise_crypto;
+ ar->def_txkey_index = sme->key_idx;
+
+ ath6kl_wmi_addkey_cmd(ar->wmi, sme->key_idx,
+ ar->prwise_crypto,
+ GROUP_USAGE | TX_USAGE,
+ key->key_len,
+ NULL,
+ key->key, KEY_OP_INIT_VAL, NULL,
+ NO_SYNC_WMIFLAG);
+ }
+
+ if (!ar->usr_bss_filter) {
+ clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag);
+ if (ath6kl_wmi_bssfilter_cmd(ar->wmi, ALL_BSS_FILTER, 0) != 0) {
+ ath6kl_err("couldn't set bss filtering\n");
+ up(&ar->sem);
+ return -EIO;
+ }
+ }
+
+ ar->nw_type = ar->next_mode;
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+ "%s: connect called with authmode %d dot11 auth %d"
+ " PW crypto %d PW crypto len %d GRP crypto %d"
+ " GRP crypto len %d channel hint %u\n",
+ __func__,
+ ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto,
+ ar->prwise_crypto_len, ar->grp_crypto,
+ ar->grp_crypto_len, ar->ch_hint);
+
+ ar->reconnect_flag = 0;
+ status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type,
+ ar->dot11_auth_mode, ar->auth_mode,
+ ar->prwise_crypto,
+ ar->prwise_crypto_len,
+ ar->grp_crypto, ar->grp_crypto_len,
+ ar->ssid_len, ar->ssid,
+ ar->req_bssid, ar->ch_hint,
+ ar->connect_ctrl_flags);
+
+ up(&ar->sem);
+
+ if (status == -EINVAL) {
+ memset(ar->ssid, 0, sizeof(ar->ssid));
+ ar->ssid_len = 0;
+ ath6kl_err("invalid request\n");
+ return -ENOENT;
+ } else if (status) {
+ ath6kl_err("ath6kl_wmi_connect_cmd failed\n");
+ return -EIO;
+ }
+
+ if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
+ ((ar->auth_mode == WPA_PSK_AUTH)
+ || (ar->auth_mode == WPA2_PSK_AUTH))) {
+ mod_timer(&ar->disconnect_timer,
+ jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
+ }
+
+ ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD;
+ set_bit(CONNECT_PEND, &ar->flag);
+
+ return 0;
+}
+
+static int ath6kl_add_bss_if_needed(struct ath6kl *ar, const u8 *bssid,
+ struct ieee80211_channel *chan,
+ const u8 *beacon_ie, size_t beacon_ie_len)
+{
+ struct cfg80211_bss *bss;
+ u8 *ie;
+
+ bss = cfg80211_get_bss(ar->wdev->wiphy, chan, bssid,
+ ar->ssid, ar->ssid_len, WLAN_CAPABILITY_ESS,
+ WLAN_CAPABILITY_ESS);
+ if (bss == NULL) {
+ /*
+ * Since cfg80211 may not yet know about the BSS,
+ * generate a partial entry until the first BSS info
+ * event becomes available.
+ *
+ * Prepend SSID element since it is not included in the Beacon
+ * IEs from the target.
+ */
+ ie = kmalloc(2 + ar->ssid_len + beacon_ie_len, GFP_KERNEL);
+ if (ie == NULL)
+ return -ENOMEM;
+ ie[0] = WLAN_EID_SSID;
+ ie[1] = ar->ssid_len;
+ memcpy(ie + 2, ar->ssid, ar->ssid_len);
+ memcpy(ie + 2 + ar->ssid_len, beacon_ie, beacon_ie_len);
+ bss = cfg80211_inform_bss(ar->wdev->wiphy, chan,
+ bssid, 0, WLAN_CAPABILITY_ESS, 100,
+ ie, 2 + ar->ssid_len + beacon_ie_len,
+ 0, GFP_KERNEL);
+ if (bss)
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added dummy bss for "
+ "%pM prior to indicating connect/roamed "
+ "event\n", bssid);
+ kfree(ie);
+ } else
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss "
+ "entry\n");
+
+ if (bss == NULL)
+ return -ENOMEM;
+
+ cfg80211_put_bss(bss);
+
+ return 0;
+}
+
+void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel,
+ u8 *bssid, u16 listen_intvl,
+ u16 beacon_intvl,
+ enum network_type nw_type,
+ u8 beacon_ie_len, u8 assoc_req_len,
+ u8 assoc_resp_len, u8 *assoc_info)
+{
+ struct ieee80211_channel *chan;
+
+ /* capinfo + listen interval */
+ u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
+
+ /* capinfo + status code + associd */
+ u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16);
+
+ u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset;
+ u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len +
+ assoc_resp_ie_offset;
+
+ assoc_req_len -= assoc_req_ie_offset;
+ assoc_resp_len -= assoc_resp_ie_offset;
+
+ /*
+ * Store Beacon interval here; DTIM period will be available only once
+ * a Beacon frame from the AP is seen.
+ */
+ ar->assoc_bss_beacon_int = beacon_intvl;
+ clear_bit(DTIM_PERIOD_AVAIL, &ar->flag);
+
+ if (nw_type & ADHOC_NETWORK) {
+ if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+ "%s: ath6k not in ibss mode\n", __func__);
+ return;
+ }
+ }
+
+ if (nw_type & INFRA_NETWORK) {
+ if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
+ ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+ "%s: ath6k not in station mode\n", __func__);
+ return;
+ }
+ }
+
+ chan = ieee80211_get_channel(ar->wdev->wiphy, (int) channel);
+
+
+ if (nw_type & ADHOC_NETWORK) {
+ cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL);
+ return;
+ }
+
+ if (ath6kl_add_bss_if_needed(ar, bssid, chan, assoc_info,
+ beacon_ie_len) < 0) {
+ ath6kl_err("could not add cfg80211 bss entry for "
+ "connect/roamed notification\n");
+ return;
+ }
+
+ if (ar->sme_state == SME_CONNECTING) {
+ /* inform connect result to cfg80211 */
+ ar->sme_state = SME_CONNECTED;
+ cfg80211_connect_result(ar->net_dev, bssid,
+ assoc_req_ie, assoc_req_len,
+ assoc_resp_ie, assoc_resp_len,
+ WLAN_STATUS_SUCCESS, GFP_KERNEL);
+ } else if (ar->sme_state == SME_CONNECTED) {
+ /* inform roam event to cfg80211 */
+ cfg80211_roamed(ar->net_dev, chan, bssid,
+ assoc_req_ie, assoc_req_len,
+ assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
+ }
+}
+
+static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
+ struct net_device *dev, u16 reason_code)
+{
+ struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
+ reason_code);
+
+ if (!ath6kl_cfg80211_ready(ar))
+ return -EIO;
+
+ if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
+ ath6kl_err("busy, destroy in progress\n");
+ return -EBUSY;
+ }
+
+ if (down_interruptible(&ar->sem)) {
+ ath6kl_err("busy, couldn't get access\n");
+ return -ERESTARTSYS;
+ }
+
+ ar->reconnect_flag = 0;
+ ath6kl_disconnect(ar);
+ memset(ar->ssid, 0, sizeof(ar->ssid));
+ ar->ssid_len = 0;
+
+ if (!test_bit(SKIP_SCAN, &ar->flag))
+ memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
+
+ up(&ar->sem);
+
+ ar->sme_state = SME_DISCONNECTED;
+
+ return 0;
+}
+
+void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason,
+ u8 *bssid, u8 assoc_resp_len,
+ u8 *assoc_info, u16 proto_reason)
+{
+ if (ar->scan_req) {
+ cfg80211_scan_done(ar->scan_req, true);
+ ar->scan_req = NULL;
+ }
+
+ if (ar->nw_type & ADHOC_NETWORK) {
+ if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) {
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+ "%s: ath6k not in ibss mode\n", __func__);
+ return;
+ }
+ memset(bssid, 0, ETH_ALEN);
+ cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL);
+ return;
+ }
+
+ if (ar->nw_type & INFRA_NETWORK) {
+ if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
+ ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+ "%s: ath6k not in station mode\n", __func__);
+ return;
+ }
+ }
+
+ /*
+ * Send a disconnect command to target when a disconnect event is
+ * received with reason code other than 3 (DISCONNECT_CMD - disconnect
+ * request from host) to make the firmware stop trying to connect even
+ * after giving disconnect event. There will be one more disconnect
+ * event for this disconnect command with reason code DISCONNECT_CMD
+ * which will be notified to cfg80211.
+ */
+
+ if (reason != DISCONNECT_CMD) {
+ ath6kl_wmi_disconnect_cmd(ar->wmi);
+ return;
+ }
+
+ clear_bit(CONNECT_PEND, &ar->flag);
+
+ if (ar->sme_state == SME_CONNECTING) {
+ cfg80211_connect_result(ar->net_dev,
+ bssid, NULL, 0,
+ NULL, 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
+ GFP_KERNEL);
+ } else if (ar->sme_state == SME_CONNECTED) {
+ cfg80211_disconnected(ar->net_dev, reason,
+ NULL, 0, GFP_KERNEL);
+ }
+
+ ar->sme_state = SME_DISCONNECTED;
+}
+
+static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_scan_request *request)
+{
+ struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
+ s8 n_channels = 0;
+ u16 *channels = NULL;
+ int ret = 0;
+
+ if (!ath6kl_cfg80211_ready(ar))
+ return -EIO;
+
+ if (!ar->usr_bss_filter) {
+ clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag);
+ ret = ath6kl_wmi_bssfilter_cmd(
+ ar->wmi,
+ (test_bit(CONNECTED, &ar->flag) ?
+ ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
+ if (ret) {
+ ath6kl_err("couldn't set bss filtering\n");
+ return ret;
+ }
+ }
+
+ if (request->n_ssids && request->ssids[0].ssid_len) {
+ u8 i;
+
+ if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
+ request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
+
+ for (i = 0; i < request->n_ssids; i++)
+ ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
+ SPECIFIC_SSID_FLAG,
+ request->ssids[i].ssid_len,
+ request->ssids[i].ssid);
+ }
+
+ if (request->ie) {
+ ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_REQ,
+ request->ie, request->ie_len);
+ if (ret) {
+ ath6kl_err("failed to set Probe Request appie for "
+ "scan");
+ return ret;
+ }
+ }
+
+ /*
+ * Scan only the requested channels if the request specifies a set of
+ * channels. If the list is longer than the target supports, do not
+ * configure the list and instead, scan all available channels.
+ */
+ if (request->n_channels > 0 &&
+ request->n_channels <= WMI_MAX_CHANNELS) {
+ u8 i;
+
+ n_channels = request->n_channels;
+
+ channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
+ if (channels == NULL) {
+ ath6kl_warn("failed to set scan channels, "
+ "scan all channels");
+ n_channels = 0;
+ }
+
+ for (i = 0; i < n_channels; i++)
+ channels[i] = request->channels[i]->center_freq;
+ }
+
+ ret = ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, 0,
+ false, 0, 0, n_channels, channels);
+ if (ret)
+ ath6kl_err("wmi_startscan_cmd failed\n");
+ else
+ ar->scan_req = request;
+
+ kfree(channels);
+
+ return ret;
+}
+
+void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status)
+{
+ int i;
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status %d\n", __func__, status);
+
+ if (!ar->scan_req)
+ return;
+
+ if ((status == -ECANCELED) || (status == -EBUSY)) {
+ cfg80211_scan_done(ar->scan_req, true);
+ goto out;
+ }
+
+ cfg80211_scan_done(ar->scan_req, false);
+
+ if (ar->scan_req->n_ssids && ar->scan_req->ssids[0].ssid_len) {
+ for (i = 0; i < ar->scan_req->n_ssids; i++) {
+ ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1,
+ DISABLE_SSID_FLAG,
+ 0, NULL);
+ }
+ }
+
+out:
+ ar->scan_req = NULL;
+}
+
+static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_index, bool pairwise,
+ const u8 *mac_addr,
+ struct key_params *params)
+{
+ struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
+ struct ath6kl_key *key = NULL;
+ u8 key_usage;
+ u8 key_type;
+ int status = 0;
+
+ if (!ath6kl_cfg80211_ready(ar))
+ return -EIO;
+
+ if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+ "%s: key index %d out of bounds\n", __func__,
+ key_index);
+ return -ENOENT;
+ }
+
+ key = &ar->keys[key_index];
+ memset(key, 0, sizeof(struct ath6kl_key));
+
+ if (pairwise)
+ key_usage = PAIRWISE_USAGE;
+ else
+ key_usage = GROUP_USAGE;
+
+ if (params) {
+ if (params->key_len > WLAN_MAX_KEY_LEN ||
+ params->seq_len > sizeof(key->seq))
+ return -EINVAL;
+
+ key->key_len = params->key_len;
+ memcpy(key->key, params->key, key->key_len);
+ key->seq_len = params->seq_len;
+ memcpy(key->seq, params->seq, key->seq_len);
+ key->cipher = params->cipher;
+ }
+
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ key_type = WEP_CRYPT;
+ break;
+
+ case WLAN_CIPHER_SUITE_TKIP:
+ key_type = TKIP_CRYPT;
+ break;
+
+ case WLAN_CIPHER_SUITE_CCMP:
+ key_type = AES_CRYPT;
+ break;
+
+ default:
+ return -ENOTSUPP;
+ }
+
+ if (((ar->auth_mode == WPA_PSK_AUTH)
+ || (ar->auth_mode == WPA2_PSK_AUTH))
+ && (key_usage & GROUP_USAGE))
+ del_timer(&ar->disconnect_timer);
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+ "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n",
+ __func__, key_index, key->key_len, key_type,
+ key_usage, key->seq_len);
+
+ ar->def_txkey_index = key_index;
+
+ if (ar->nw_type == AP_NETWORK && !pairwise &&
+ (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
+ ar->ap_mode_bkey.valid = true;
+ ar->ap_mode_bkey.key_index = key_index;
+ ar->ap_mode_bkey.key_type = key_type;
+ ar->ap_mode_bkey.key_len = key->key_len;
+ memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
+ if (!test_bit(CONNECTED, &ar->flag)) {
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
+ "key configuration until AP mode has been "
+ "started\n");
+ /*
+ * The key will be set in ath6kl_connect_ap_mode() once
+ * the connected event is received from the target.
+ */
+ return 0;
+ }
+ }
+
+ if (ar->next_mode == AP_NETWORK && key_type == WEP_CRYPT &&
+ !test_bit(CONNECTED, &ar->flag)) {
+ /*
+ * Store the key locally so that it can be re-configured after
+ * the AP mode has properly started
+ * (ath6kl_install_statioc_wep_keys).
+ */
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
+ "until AP mode has been started\n");
+ ar->wep_key_list[key_index].key_len = key->key_len;
+ memcpy(ar->wep_key_list[key_index].key, key->key, key->key_len);
+ return 0;
+ }
+
+ status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
+ key_type, key_usage, key->key_len,
+ key->seq, key->key, KEY_OP_INIT_VAL,
+ (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
+
+ if (status)
+ return -EIO;
+
+ return 0;
+}
+
+static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_index, bool pairwise,
+ const u8 *mac_addr)
+{
+ struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
+
+ if (!ath6kl_cfg80211_ready(ar))
+ return -EIO;
+
+ if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+ "%s: key index %d out of bounds\n", __func__,
+ key_index);
+ return -ENOENT;
+ }
+
+ if (!ar->keys[key_index].key_len) {
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+ "%s: index %d is empty\n", __func__, key_index);
+ return 0;
+ }
+
+ ar->keys[key_index].key_len = 0;
+
+ return ath6kl_wmi_deletekey_cmd(ar->wmi, key_index);
+}
+
+static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_index, bool pairwise,
+ const u8 *mac_addr, void *cookie,
+ void (*callback) (void *cookie,
+ struct key_params *))
+{
+ struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
+ struct ath6kl_key *key = NULL;
+ struct key_params params;
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
+
+ if (!ath6kl_cfg80211_ready(ar))
+ return -EIO;
+
+ if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+ "%s: key index %d out of bounds\n", __func__,
+ key_index);
+ return -ENOENT;
+ }
+
+ key = &ar->keys[key_index];
+ memset(&params, 0, sizeof(params));
+ params.cipher = key->cipher;
+ params.key_len = key->key_len;
+ params.seq_len = key->seq_len;
+ params.seq = key->seq;
+ params.key = key->key;
+
+ callback(cookie, &params);
+
+ return key->key_len ? 0 : -ENOENT;
+}
+
+static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
+ struct net_device *ndev,
+ u8 key_index, bool unicast,
+ bool multicast)
+{
+ struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
+ struct ath6kl_key *key = NULL;
+ int status = 0;
+ u8 key_usage;
+ enum crypto_type key_type = NONE_CRYPT;
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
+
+ if (!ath6kl_cfg80211_ready(ar))
+ return -EIO;
+
+ if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+ "%s: key index %d out of bounds\n",
+ __func__, key_index);
+ return -ENOENT;
+ }
+
+ if (!ar->keys[key_index].key_len) {
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n",
+ __func__, key_index);
+ return -EINVAL;
+ }
+
+ ar->def_txkey_index = key_index;
+ key = &ar->keys[ar->def_txkey_index];
+ key_usage = GROUP_USAGE;
+ if (ar->prwise_crypto == WEP_CRYPT)
+ key_usage |= TX_USAGE;
+ if (unicast)
+ key_type = ar->prwise_crypto;
+ if (multicast)
+ key_type = ar->grp_crypto;
+
+ if (ar->next_mode == AP_NETWORK && !test_bit(CONNECTED, &ar->flag))
+ return 0; /* Delay until AP mode has been started */
+
+ status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
+ key_type, key_usage,
+ key->key_len, key->seq, key->key,
+ KEY_OP_INIT_VAL, NULL,
+ SYNC_BOTH_WMIFLAG);
+ if (status)
+ return -EIO;
+
+ return 0;
+}
+
+void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid,
+ bool ismcast)
+{
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+ "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast);
+
+ cfg80211_michael_mic_failure(ar->net_dev, ar->bssid,
+ (ismcast ? NL80211_KEYTYPE_GROUP :
+ NL80211_KEYTYPE_PAIRWISE), keyid, NULL,
+ GFP_KERNEL);
+}
+
+static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+ struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
+ int ret;
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__,
+ changed);
+
+ if (!ath6kl_cfg80211_ready(ar))
+ return -EIO;
+
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
+ ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold);
+ if (ret != 0) {
+ ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n");
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * The type nl80211_tx_power_setting replaces the following
+ * data type from 2.6.36 onwards
+*/
+static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
+ enum nl80211_tx_power_setting type,
+ int dbm)
+{
+ struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
+ u8 ath6kl_dbm;
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
+ type, dbm);
+
+ if (!ath6kl_cfg80211_ready(ar))
+ return -EIO;
+
+ switch (type) {
+ case NL80211_TX_POWER_AUTOMATIC:
+ return 0;
+ case NL80211_TX_POWER_LIMITED:
+ ar->tx_pwr = ath6kl_dbm = dbm;
+ break;
+ default:
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
+ __func__, type);
+ return -EOPNOTSUPP;
+ }
+
+ ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, ath6kl_dbm);
+
+ return 0;
+}
+
+static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
+{
+ struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
+
+ if (!ath6kl_cfg80211_ready(ar))
+ return -EIO;
+
+ if (test_bit(CONNECTED, &ar->flag)) {
+ ar->tx_pwr = 0;
+
+ if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi) != 0) {
+ ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n");
+ return -EIO;
+ }
+
+ wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0,
+ 5 * HZ);
+
+ if (signal_pending(current)) {
+ ath6kl_err("target did not respond\n");
+ return -EINTR;
+ }
+ }
+
+ *dbm = ar->tx_pwr;
+ return 0;
+}
+
+static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
+ struct net_device *dev,
+ bool pmgmt, int timeout)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+ struct wmi_power_mode_cmd mode;
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n",
+ __func__, pmgmt, timeout);
+
+ if (!ath6kl_cfg80211_ready(ar))
+ return -EIO;
+
+ if (pmgmt) {
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
+ mode.pwr_mode = REC_POWER;
+ } else {
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
+ mode.pwr_mode = MAX_PERF_POWER;
+ }
+
+ if (ath6kl_wmi_powermode_cmd(ar->wmi, mode.pwr_mode) != 0) {
+ ath6kl_err("wmi_powermode_cmd failed\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
+ struct net_device *ndev,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
+{
+ struct ath6kl *ar = ath6kl_priv(ndev);
+ struct wireless_dev *wdev = ar->wdev;
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
+
+ if (!ath6kl_cfg80211_ready(ar))
+ return -EIO;
+
+ switch (type) {
+ case NL80211_IFTYPE_STATION:
+ ar->next_mode = INFRA_NETWORK;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ ar->next_mode = ADHOC_NETWORK;
+ break;
+ case NL80211_IFTYPE_AP:
+ ar->next_mode = AP_NETWORK;
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ ar->next_mode = INFRA_NETWORK;
+ break;
+ case NL80211_IFTYPE_P2P_GO:
+ ar->next_mode = AP_NETWORK;
+ break;
+ default:
+ ath6kl_err("invalid interface type %u\n", type);
+ return -EOPNOTSUPP;
+ }
+
+ wdev->iftype = type;
+
+ return 0;
+}
+
+static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_ibss_params *ibss_param)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+ int status;
+
+ if (!ath6kl_cfg80211_ready(ar))
+ return -EIO;
+
+ ar->ssid_len = ibss_param->ssid_len;
+ memcpy(ar->ssid, ibss_param->ssid, ar->ssid_len);
+
+ if (ibss_param->channel)
+ ar->ch_hint = ibss_param->channel->center_freq;
+
+ if (ibss_param->channel_fixed) {
+ /*
+ * TODO: channel_fixed: The channel should be fixed, do not
+ * search for IBSSs to join on other channels. Target
+ * firmware does not support this feature, needs to be
+ * updated.
+ */
+ return -EOPNOTSUPP;
+ }
+
+ memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
+ if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid))
+ memcpy(ar->req_bssid, ibss_param->bssid, sizeof(ar->req_bssid));
+
+ ath6kl_set_wpa_version(ar, 0);
+
+ status = ath6kl_set_auth_type(ar, NL80211_AUTHTYPE_OPEN_SYSTEM);
+ if (status)
+ return status;
+
+ if (ibss_param->privacy) {
+ ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, true);
+ ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, false);
+ } else {
+ ath6kl_set_cipher(ar, 0, true);
+ ath6kl_set_cipher(ar, 0, false);
+ }
+
+ ar->nw_type = ar->next_mode;
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+ "%s: connect called with authmode %d dot11 auth %d"
+ " PW crypto %d PW crypto len %d GRP crypto %d"
+ " GRP crypto len %d channel hint %u\n",
+ __func__,
+ ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto,
+ ar->prwise_crypto_len, ar->grp_crypto,
+ ar->grp_crypto_len, ar->ch_hint);
+
+ status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type,
+ ar->dot11_auth_mode, ar->auth_mode,
+ ar->prwise_crypto,
+ ar->prwise_crypto_len,
+ ar->grp_crypto, ar->grp_crypto_len,
+ ar->ssid_len, ar->ssid,
+ ar->req_bssid, ar->ch_hint,
+ ar->connect_ctrl_flags);
+ set_bit(CONNECT_PEND, &ar->flag);
+
+ return 0;
+}
+
+static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy,
+ struct net_device *dev)
+{
+ struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
+
+ if (!ath6kl_cfg80211_ready(ar))
+ return -EIO;
+
+ ath6kl_disconnect(ar);
+ memset(ar->ssid, 0, sizeof(ar->ssid));
+ ar->ssid_len = 0;
+
+ return 0;
+}
+
+static const u32 cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+};
+
+static bool is_rate_legacy(s32 rate)
+{
+ static const s32 legacy[] = { 1000, 2000, 5500, 11000,
+ 6000, 9000, 12000, 18000, 24000,
+ 36000, 48000, 54000
+ };
+ u8 i;
+
+ for (i = 0; i < ARRAY_SIZE(legacy); i++)
+ if (rate == legacy[i])
+ return true;
+
+ return false;
+}
+
+static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
+{
+ static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
+ 52000, 58500, 65000, 72200
+ };
+ u8 i;
+
+ for (i = 0; i < ARRAY_SIZE(ht20); i++) {
+ if (rate == ht20[i]) {
+ if (i == ARRAY_SIZE(ht20) - 1)
+ /* last rate uses sgi */
+ *sgi = true;
+ else
+ *sgi = false;
+
+ *mcs = i;
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
+{
+ static const s32 ht40[] = { 13500, 27000, 40500, 54000,
+ 81000, 108000, 121500, 135000,
+ 150000
+ };
+ u8 i;
+
+ for (i = 0; i < ARRAY_SIZE(ht40); i++) {
+ if (rate == ht40[i]) {
+ if (i == ARRAY_SIZE(ht40) - 1)
+ /* last rate uses sgi */
+ *sgi = true;
+ else
+ *sgi = false;
+
+ *mcs = i;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
+ u8 *mac, struct station_info *sinfo)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+ long left;
+ bool sgi;
+ s32 rate;
+ int ret;
+ u8 mcs;
+
+ if (memcmp(mac, ar->bssid, ETH_ALEN) != 0)
+ return -ENOENT;
+
+ if (down_interruptible(&ar->sem))
+ return -EBUSY;
+
+ set_bit(STATS_UPDATE_PEND, &ar->flag);
+
+ ret = ath6kl_wmi_get_stats_cmd(ar->wmi);
+
+ if (ret != 0) {
+ up(&ar->sem);
+ return -EIO;
+ }
+
+ left = wait_event_interruptible_timeout(ar->event_wq,
+ !test_bit(STATS_UPDATE_PEND,
+ &ar->flag),
+ WMI_TIMEOUT);
+
+ up(&ar->sem);
+
+ if (left == 0)
+ return -ETIMEDOUT;
+ else if (left < 0)
+ return left;
+
+ if (ar->target_stats.rx_byte) {
+ sinfo->rx_bytes = ar->target_stats.rx_byte;
+ sinfo->filled |= STATION_INFO_RX_BYTES;
+ sinfo->rx_packets = ar->target_stats.rx_pkt;
+ sinfo->filled |= STATION_INFO_RX_PACKETS;
+ }
+
+ if (ar->target_stats.tx_byte) {
+ sinfo->tx_bytes = ar->target_stats.tx_byte;
+ sinfo->filled |= STATION_INFO_TX_BYTES;
+ sinfo->tx_packets = ar->target_stats.tx_pkt;
+ sinfo->filled |= STATION_INFO_TX_PACKETS;
+ }
+
+ sinfo->signal = ar->target_stats.cs_rssi;
+ sinfo->filled |= STATION_INFO_SIGNAL;
+
+ rate = ar->target_stats.tx_ucast_rate;
+
+ if (is_rate_legacy(rate)) {
+ sinfo->txrate.legacy = rate / 100;
+ } else if (is_rate_ht20(rate, &mcs, &sgi)) {
+ if (sgi) {
+ sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+ sinfo->txrate.mcs = mcs - 1;
+ } else {
+ sinfo->txrate.mcs = mcs;
+ }
+
+ sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
+ } else if (is_rate_ht40(rate, &mcs, &sgi)) {
+ if (sgi) {
+ sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+ sinfo->txrate.mcs = mcs - 1;
+ } else {
+ sinfo->txrate.mcs = mcs;
+ }
+
+ sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+ sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
+ } else {
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+ "invalid rate from stats: %d\n", rate);
+ ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE);
+ return 0;
+ }
+
+ sinfo->filled |= STATION_INFO_TX_BITRATE;
+
+ if (test_bit(CONNECTED, &ar->flag) &&
+ test_bit(DTIM_PERIOD_AVAIL, &ar->flag) &&
+ ar->nw_type == INFRA_NETWORK) {
+ sinfo->filled |= STATION_INFO_BSS_PARAM;
+ sinfo->bss_param.flags = 0;
+ sinfo->bss_param.dtim_period = ar->assoc_bss_dtim_period;
+ sinfo->bss_param.beacon_interval = ar->assoc_bss_beacon_int;
+ }
+
+ return 0;
+}
+
+static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
+ struct cfg80211_pmksa *pmksa)
+{
+ struct ath6kl *ar = ath6kl_priv(netdev);
+ return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
+ pmksa->pmkid, true);
+}
+
+static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
+ struct cfg80211_pmksa *pmksa)
+{
+ struct ath6kl *ar = ath6kl_priv(netdev);
+ return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid,
+ pmksa->pmkid, false);
+}
+
+static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
+{
+ struct ath6kl *ar = ath6kl_priv(netdev);
+ if (test_bit(CONNECTED, &ar->flag))
+ return ath6kl_wmi_setpmkid_cmd(ar->wmi, ar->bssid, NULL, false);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ar6k_cfg80211_suspend(struct wiphy *wiphy,
+ struct cfg80211_wowlan *wow)
+{
+ struct ath6kl *ar = wiphy_priv(wiphy);
+
+ return ath6kl_hif_suspend(ar);
+}
+#endif
+
+static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+
+ if (!ath6kl_cfg80211_ready(ar))
+ return -EIO;
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
+ __func__, chan->center_freq, chan->hw_value);
+ ar->next_chan = chan->center_freq;
+
+ return 0;
+}
+
+static bool ath6kl_is_p2p_ie(const u8 *pos)
+{
+ return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+ pos[2] == 0x50 && pos[3] == 0x6f &&
+ pos[4] == 0x9a && pos[5] == 0x09;
+}
+
+static int ath6kl_set_ap_probe_resp_ies(struct ath6kl *ar, const u8 *ies,
+ size_t ies_len)
+{
+ const u8 *pos;
+ u8 *buf = NULL;
+ size_t len = 0;
+ int ret;
+
+ /*
+ * Filter out P2P IE(s) since they will be included depending on
+ * the Probe Request frame in ath6kl_send_go_probe_resp().
+ */
+
+ if (ies && ies_len) {
+ buf = kmalloc(ies_len, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+ pos = ies;
+ while (pos + 1 < ies + ies_len) {
+ if (pos + 2 + pos[1] > ies + ies_len)
+ break;
+ if (!ath6kl_is_p2p_ie(pos)) {
+ memcpy(buf + len, pos, 2 + pos[1]);
+ len += 2 + pos[1];
+ }
+ pos += 2 + pos[1];
+ }
+ }
+
+ ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_RESP,
+ buf, len);
+ kfree(buf);
+ return ret;
+}
+
+static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct beacon_parameters *info, bool add)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+ struct ieee80211_mgmt *mgmt;
+ u8 *ies;
+ int ies_len;
+ struct wmi_connect_cmd p;
+ int res;
+ int i;
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
+
+ if (!ath6kl_cfg80211_ready(ar))
+ return -EIO;
+
+ if (ar->next_mode != AP_NETWORK)
+ return -EOPNOTSUPP;
+
+ if (info->beacon_ies) {
+ res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_BEACON,
+ info->beacon_ies,
+ info->beacon_ies_len);
+ if (res)
+ return res;
+ }
+ if (info->proberesp_ies) {
+ res = ath6kl_set_ap_probe_resp_ies(ar, info->proberesp_ies,
+ info->proberesp_ies_len);
+ if (res)
+ return res;
+ }
+ if (info->assocresp_ies) {
+ res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_RESP,
+ info->assocresp_ies,
+ info->assocresp_ies_len);
+ if (res)
+ return res;
+ }
+
+ if (!add)
+ return 0;
+
+ ar->ap_mode_bkey.valid = false;
+
+ /* TODO:
+ * info->interval
+ * info->dtim_period
+ */
+
+ if (info->head == NULL)
+ return -EINVAL;
+ mgmt = (struct ieee80211_mgmt *) info->head;
+ ies = mgmt->u.beacon.variable;
+ if (ies > info->head + info->head_len)
+ return -EINVAL;
+ ies_len = info->head + info->head_len - ies;
+
+ if (info->ssid == NULL)
+ return -EINVAL;
+ memcpy(ar->ssid, info->ssid, info->ssid_len);
+ ar->ssid_len = info->ssid_len;
+ if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
+ return -EOPNOTSUPP; /* TODO */
+
+ ar->dot11_auth_mode = OPEN_AUTH;
+
+ memset(&p, 0, sizeof(p));
+
+ for (i = 0; i < info->crypto.n_akm_suites; i++) {
+ switch (info->crypto.akm_suites[i]) {
+ case WLAN_AKM_SUITE_8021X:
+ if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ p.auth_mode |= WPA_AUTH;
+ if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ p.auth_mode |= WPA2_AUTH;
+ break;
+ case WLAN_AKM_SUITE_PSK:
+ if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ p.auth_mode |= WPA_PSK_AUTH;
+ if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ p.auth_mode |= WPA2_PSK_AUTH;
+ break;
+ }
+ }
+ if (p.auth_mode == 0)
+ p.auth_mode = NONE_AUTH;
+ ar->auth_mode = p.auth_mode;
+
+ for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
+ switch (info->crypto.ciphers_pairwise[i]) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ p.prwise_crypto_type |= WEP_CRYPT;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ p.prwise_crypto_type |= TKIP_CRYPT;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ p.prwise_crypto_type |= AES_CRYPT;
+ break;
+ }
+ }
+ if (p.prwise_crypto_type == 0) {
+ p.prwise_crypto_type = NONE_CRYPT;
+ ath6kl_set_cipher(ar, 0, true);
+ } else if (info->crypto.n_ciphers_pairwise == 1)
+ ath6kl_set_cipher(ar, info->crypto.ciphers_pairwise[0], true);
+
+ switch (info->crypto.cipher_group) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ p.grp_crypto_type = WEP_CRYPT;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ p.grp_crypto_type = TKIP_CRYPT;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ p.grp_crypto_type = AES_CRYPT;
+ break;
+ default:
+ p.grp_crypto_type = NONE_CRYPT;
+ break;
+ }
+ ath6kl_set_cipher(ar, info->crypto.cipher_group, false);
+
+ p.nw_type = AP_NETWORK;
+ ar->nw_type = ar->next_mode;
+
+ p.ssid_len = ar->ssid_len;
+ memcpy(p.ssid, ar->ssid, ar->ssid_len);
+ p.dot11_auth_mode = ar->dot11_auth_mode;
+ p.ch = cpu_to_le16(ar->next_chan);
+
+ res = ath6kl_wmi_ap_profile_commit(ar->wmi, &p);
+ if (res < 0)
+ return res;
+
+ return 0;
+}
+
+static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct beacon_parameters *info)
+{
+ return ath6kl_ap_beacon(wiphy, dev, info, true);
+}
+
+static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct beacon_parameters *info)
+{
+ return ath6kl_ap_beacon(wiphy, dev, info, false);
+}
+
+static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+
+ if (ar->nw_type != AP_NETWORK)
+ return -EOPNOTSUPP;
+ if (!test_bit(CONNECTED, &ar->flag))
+ return -ENOTCONN;
+
+ ath6kl_wmi_disconnect_cmd(ar->wmi);
+ clear_bit(CONNECTED, &ar->flag);
+
+ return 0;
+}
+
+static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
+ u8 *mac, struct station_parameters *params)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+
+ if (ar->nw_type != AP_NETWORK)
+ return -EOPNOTSUPP;
+
+ /* Use this only for authorizing/unauthorizing a station */
+ if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
+ return -EOPNOTSUPP;
+
+ if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
+ return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_AUTHORIZE,
+ mac, 0);
+ return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_UNAUTHORIZE, mac,
+ 0);
+}
+
+static int ath6kl_remain_on_channel(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type,
+ unsigned int duration,
+ u64 *cookie)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+
+ /* TODO: if already pending or ongoing remain-on-channel,
+ * return -EBUSY */
+ *cookie = 1; /* only a single pending request is supported */
+
+ return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, chan->center_freq,
+ duration);
+}
+
+static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
+ struct net_device *dev,
+ u64 cookie)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+
+ if (cookie != 1)
+ return -ENOENT;
+
+ return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi);
+}
+
+static int ath6kl_send_go_probe_resp(struct ath6kl *ar, const u8 *buf,
+ size_t len, unsigned int freq)
+{
+ const u8 *pos;
+ u8 *p2p;
+ int p2p_len;
+ int ret;
+ const struct ieee80211_mgmt *mgmt;
+
+ mgmt = (const struct ieee80211_mgmt *) buf;
+
+ /* Include P2P IE(s) from the frame generated in user space. */
+
+ p2p = kmalloc(len, GFP_KERNEL);
+ if (p2p == NULL)
+ return -ENOMEM;
+ p2p_len = 0;
+
+ pos = mgmt->u.probe_resp.variable;
+ while (pos + 1 < buf + len) {
+ if (pos + 2 + pos[1] > buf + len)
+ break;
+ if (ath6kl_is_p2p_ie(pos)) {
+ memcpy(p2p + p2p_len, pos, 2 + pos[1]);
+ p2p_len += 2 + pos[1];
+ }
+ pos += 2 + pos[1];
+ }
+
+ ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, freq, mgmt->da,
+ p2p, p2p_len);
+ kfree(p2p);
+ return ret;
+}
+
+static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
+ struct ieee80211_channel *chan, bool offchan,
+ enum nl80211_channel_type channel_type,
+ bool channel_type_valid, unsigned int wait,
+ const u8 *buf, size_t len, bool no_cck, u64 *cookie)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+ u32 id;
+ const struct ieee80211_mgmt *mgmt;
+
+ mgmt = (const struct ieee80211_mgmt *) buf;
+ if (buf + len >= mgmt->u.probe_resp.variable &&
+ ar->nw_type == AP_NETWORK && test_bit(CONNECTED, &ar->flag) &&
+ ieee80211_is_probe_resp(mgmt->frame_control)) {
+ /*
+ * Send Probe Response frame in AP mode using a separate WMI
+ * command to allow the target to fill in the generic IEs.
+ */
+ *cookie = 0; /* TX status not supported */
+ return ath6kl_send_go_probe_resp(ar, buf, len,
+ chan->center_freq);
+ }
+
+ id = ar->send_action_id++;
+ if (id == 0) {
+ /*
+ * 0 is a reserved value in the WMI command and shall not be
+ * used for the command.
+ */
+ id = ar->send_action_id++;
+ }
+
+ *cookie = id;
+ return ath6kl_wmi_send_action_cmd(ar->wmi, id, chan->center_freq, wait,
+ buf, len);
+}
+
+static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
+ struct net_device *dev,
+ u16 frame_type, bool reg)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
+ __func__, frame_type, reg);
+ if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
+ /*
+ * Note: This notification callback is not allowed to sleep, so
+ * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
+ * hardcode target to report Probe Request frames all the time.
+ */
+ ar->probe_req_report = reg;
+ }
+}
+
+static const struct ieee80211_txrx_stypes
+ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
+ [NL80211_IFTYPE_STATION] = {
+ .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+ [NL80211_IFTYPE_P2P_CLIENT] = {
+ .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+ [NL80211_IFTYPE_P2P_GO] = {
+ .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+};
+
+static struct cfg80211_ops ath6kl_cfg80211_ops = {
+ .change_virtual_intf = ath6kl_cfg80211_change_iface,
+ .scan = ath6kl_cfg80211_scan,
+ .connect = ath6kl_cfg80211_connect,
+ .disconnect = ath6kl_cfg80211_disconnect,
+ .add_key = ath6kl_cfg80211_add_key,
+ .get_key = ath6kl_cfg80211_get_key,
+ .del_key = ath6kl_cfg80211_del_key,
+ .set_default_key = ath6kl_cfg80211_set_default_key,
+ .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params,
+ .set_tx_power = ath6kl_cfg80211_set_txpower,
+ .get_tx_power = ath6kl_cfg80211_get_txpower,
+ .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt,
+ .join_ibss = ath6kl_cfg80211_join_ibss,
+ .leave_ibss = ath6kl_cfg80211_leave_ibss,
+ .get_station = ath6kl_get_station,
+ .set_pmksa = ath6kl_set_pmksa,
+ .del_pmksa = ath6kl_del_pmksa,
+ .flush_pmksa = ath6kl_flush_pmksa,
+ CFG80211_TESTMODE_CMD(ath6kl_tm_cmd)
+#ifdef CONFIG_PM
+ .suspend = ar6k_cfg80211_suspend,
+#endif
+ .set_channel = ath6kl_set_channel,
+ .add_beacon = ath6kl_add_beacon,
+ .set_beacon = ath6kl_set_beacon,
+ .del_beacon = ath6kl_del_beacon,
+ .change_station = ath6kl_change_station,
+ .remain_on_channel = ath6kl_remain_on_channel,
+ .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
+ .mgmt_tx = ath6kl_mgmt_tx,
+ .mgmt_frame_register = ath6kl_mgmt_frame_register,
+};
+
+struct wireless_dev *ath6kl_cfg80211_init(struct device *dev)
+{
+ int ret = 0;
+ struct wireless_dev *wdev;
+ struct ath6kl *ar;
+
+ wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+ if (!wdev) {
+ ath6kl_err("couldn't allocate wireless device\n");
+ return NULL;
+ }
+
+ /* create a new wiphy for use with cfg80211 */
+ wdev->wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
+ if (!wdev->wiphy) {
+ ath6kl_err("couldn't allocate wiphy device\n");
+ kfree(wdev);
+ return NULL;
+ }
+
+ ar = wiphy_priv(wdev->wiphy);
+ ar->p2p = !!ath6kl_p2p;
+
+ wdev->wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
+
+ wdev->wiphy->max_remain_on_channel_duration = 5000;
+
+ /* set device pointer for wiphy */
+ set_wiphy_dev(wdev->wiphy, dev);
+
+ wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
+ if (ar->p2p) {
+ wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT);
+ }
+ /* max num of ssids that can be probed during scanning */
+ wdev->wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
+ wdev->wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
+ wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
+ wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
+ wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+ wdev->wiphy->cipher_suites = cipher_suites;
+ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+
+ ret = wiphy_register(wdev->wiphy);
+ if (ret < 0) {
+ ath6kl_err("couldn't register wiphy device\n");
+ wiphy_free(wdev->wiphy);
+ kfree(wdev);
+ return NULL;
+ }
+
+ return wdev;
+}
+
+void ath6kl_cfg80211_deinit(struct ath6kl *ar)
+{
+ struct wireless_dev *wdev = ar->wdev;
+
+ if (ar->scan_req) {
+ cfg80211_scan_done(ar->scan_req, true);
+ ar->scan_req = NULL;
+ }
+
+ if (!wdev)
+ return;
+
+ wiphy_unregister(wdev->wiphy);
+ wiphy_free(wdev->wiphy);
+ kfree(wdev);
+}
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h
new file mode 100644
index 000000000000..a84adc249c61
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef ATH6KL_CFG80211_H
+#define ATH6KL_CFG80211_H
+
+struct wireless_dev *ath6kl_cfg80211_init(struct device *dev);
+void ath6kl_cfg80211_deinit(struct ath6kl *ar);
+
+void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status);
+
+void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel,
+ u8 *bssid, u16 listen_intvl,
+ u16 beacon_intvl,
+ enum network_type nw_type,
+ u8 beacon_ie_len, u8 assoc_req_len,
+ u8 assoc_resp_len, u8 *assoc_info);
+
+void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason,
+ u8 *bssid, u8 assoc_resp_len,
+ u8 *assoc_info, u16 proto_reason);
+
+void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid,
+ bool ismcast);
+
+#endif /* ATH6KL_CFG80211_H */
diff --git a/drivers/net/wireless/ath/ath6kl/common.h b/drivers/net/wireless/ath/ath6kl/common.h
new file mode 100644
index 000000000000..b92f0e5d2336
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/common.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <linux/netdevice.h>
+
+#define ATH6KL_MAX_IE 256
+
+extern int ath6kl_printk(const char *level, const char *fmt, ...);
+
+#define A_CACHE_LINE_PAD 128
+
+/*
+ * Reflects the version of binary interface exposed by ATH6KL target
+ * firmware. Needs to be incremented by 1 for any change in the firmware
+ * that requires upgrade of the driver on the host side for the change to
+ * work correctly
+ */
+#define ATH6KL_ABI_VERSION 1
+
+#define SIGNAL_QUALITY_METRICS_NUM_MAX 2
+
+enum {
+ SIGNAL_QUALITY_METRICS_SNR = 0,
+ SIGNAL_QUALITY_METRICS_RSSI,
+ SIGNAL_QUALITY_METRICS_ALL,
+};
+
+/*
+ * Data Path
+ */
+
+#define WMI_MAX_TX_DATA_FRAME_LENGTH \
+ (1500 + sizeof(struct wmi_data_hdr) + \
+ sizeof(struct ethhdr) + \
+ sizeof(struct ath6kl_llc_snap_hdr))
+
+/* An AMSDU frame */ /* The MAX AMSDU length of AR6003 is 3839 */
+#define WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH \
+ (3840 + sizeof(struct wmi_data_hdr) + \
+ sizeof(struct ethhdr) + \
+ sizeof(struct ath6kl_llc_snap_hdr))
+
+#define EPPING_ALIGNMENT_PAD \
+ (((sizeof(struct htc_frame_hdr) + 3) & (~0x3)) \
+ - sizeof(struct htc_frame_hdr))
+
+struct ath6kl_llc_snap_hdr {
+ u8 dsap;
+ u8 ssap;
+ u8 cntl;
+ u8 org_code[3];
+ __be16 eth_type;
+} __packed;
+
+enum crypto_type {
+ NONE_CRYPT = 0x01,
+ WEP_CRYPT = 0x02,
+ TKIP_CRYPT = 0x04,
+ AES_CRYPT = 0x08,
+};
+
+struct htc_endpoint_credit_dist;
+struct ath6kl;
+enum htc_credit_dist_reason;
+struct htc_credit_state_info;
+
+int ath6k_setup_credit_dist(void *htc_handle,
+ struct htc_credit_state_info *cred_info);
+void ath6k_credit_distribute(struct htc_credit_state_info *cred_inf,
+ struct list_head *epdist_list,
+ enum htc_credit_dist_reason reason);
+void ath6k_credit_init(struct htc_credit_state_info *cred_inf,
+ struct list_head *ep_list,
+ int tot_credits);
+void ath6k_seek_credits(struct htc_credit_state_info *cred_inf,
+ struct htc_endpoint_credit_dist *ep_dist);
+struct ath6kl *ath6kl_core_alloc(struct device *sdev);
+int ath6kl_core_init(struct ath6kl *ar);
+int ath6kl_unavail_ev(struct ath6kl *ar);
+struct sk_buff *ath6kl_buf_alloc(int size);
+#endif /* COMMON_H */
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
new file mode 100644
index 000000000000..6d8a4845baaf
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -0,0 +1,637 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef CORE_H
+#define CORE_H
+
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/firmware.h>
+#include <linux/sched.h>
+#include <linux/circ_buf.h>
+#include <net/cfg80211.h>
+#include "htc.h"
+#include "wmi.h"
+#include "bmi.h"
+#include "target.h"
+
+#define MAX_ATH6KL 1
+#define ATH6KL_MAX_RX_BUFFERS 16
+#define ATH6KL_BUFFER_SIZE 1664
+#define ATH6KL_MAX_AMSDU_RX_BUFFERS 4
+#define ATH6KL_AMSDU_REFILL_THRESHOLD 3
+#define ATH6KL_AMSDU_BUFFER_SIZE (WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH + 128)
+#define MAX_MSDU_SUBFRAME_PAYLOAD_LEN 1508
+#define MIN_MSDU_SUBFRAME_PAYLOAD_LEN 46
+
+#define USER_SAVEDKEYS_STAT_INIT 0
+#define USER_SAVEDKEYS_STAT_RUN 1
+
+#define ATH6KL_TX_TIMEOUT 10
+#define ATH6KL_MAX_ENDPOINTS 4
+#define MAX_NODE_NUM 15
+
+/* Extra bytes for htc header alignment */
+#define ATH6KL_HTC_ALIGN_BYTES 3
+
+/* MAX_HI_COOKIE_NUM are reserved for high priority traffic */
+#define MAX_DEF_COOKIE_NUM 180
+#define MAX_HI_COOKIE_NUM 18 /* 10% of MAX_COOKIE_NUM */
+#define MAX_COOKIE_NUM (MAX_DEF_COOKIE_NUM + MAX_HI_COOKIE_NUM)
+
+#define MAX_DEFAULT_SEND_QUEUE_DEPTH (MAX_DEF_COOKIE_NUM / WMM_NUM_AC)
+
+#define DISCON_TIMER_INTVAL 10000 /* in msec */
+#define A_DEFAULT_LISTEN_INTERVAL 100
+#define A_MAX_WOW_LISTEN_INTERVAL 1000
+
+/* includes also the null byte */
+#define ATH6KL_FIRMWARE_MAGIC "QCA-ATH6KL"
+
+enum ath6kl_fw_ie_type {
+ ATH6KL_FW_IE_FW_VERSION = 0,
+ ATH6KL_FW_IE_TIMESTAMP = 1,
+ ATH6KL_FW_IE_OTP_IMAGE = 2,
+ ATH6KL_FW_IE_FW_IMAGE = 3,
+ ATH6KL_FW_IE_PATCH_IMAGE = 4,
+ ATH6KL_FW_IE_RESERVED_RAM_SIZE = 5,
+ ATH6KL_FW_IE_CAPABILITIES = 6,
+ ATH6KL_FW_IE_PATCH_ADDR = 7,
+};
+
+enum ath6kl_fw_capability {
+ ATH6KL_FW_CAPABILITY_HOST_P2P = 0,
+
+ /* this needs to be last */
+ ATH6KL_FW_CAPABILITY_MAX,
+};
+
+#define ATH6KL_CAPABILITY_LEN (ALIGN(ATH6KL_FW_CAPABILITY_MAX, 32) / 32)
+
+struct ath6kl_fw_ie {
+ __le32 id;
+ __le32 len;
+ u8 data[0];
+};
+
+/* AR6003 1.0 definitions */
+#define AR6003_REV1_VERSION 0x300002ba
+
+/* AR6003 2.0 definitions */
+#define AR6003_REV2_VERSION 0x30000384
+#define AR6003_REV2_PATCH_DOWNLOAD_ADDRESS 0x57e910
+#define AR6003_REV2_OTP_FILE "ath6k/AR6003/hw2.0/otp.bin.z77"
+#define AR6003_REV2_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athwlan.bin.z77"
+#define AR6003_REV2_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athtcmd_ram.bin"
+#define AR6003_REV2_PATCH_FILE "ath6k/AR6003/hw2.0/data.patch.bin"
+#define AR6003_REV2_FIRMWARE_2_FILE "ath6k/AR6003/hw2.0/fw-2.bin"
+#define AR6003_REV2_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin"
+#define AR6003_REV2_DEFAULT_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.SD31.bin"
+
+/* AR6003 3.0 definitions */
+#define AR6003_REV3_VERSION 0x30000582
+#define AR6003_REV3_OTP_FILE "ath6k/AR6003/hw2.1.1/otp.bin"
+#define AR6003_REV3_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athwlan.bin"
+#define AR6003_REV3_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athtcmd_ram.bin"
+#define AR6003_REV3_PATCH_FILE "ath6k/AR6003/hw2.1.1/data.patch.bin"
+#define AR6003_REV3_FIRMWARE_2_FILE "ath6k/AR6003/hw2.1.1/fw-2.bin"
+#define AR6003_REV3_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin"
+#define AR6003_REV3_DEFAULT_BOARD_DATA_FILE \
+ "ath6k/AR6003/hw2.1.1/bdata.SD31.bin"
+
+/* AR6004 1.0 definitions */
+#define AR6004_REV1_VERSION 0x30000623
+#define AR6004_REV1_FIRMWARE_FILE "ath6k/AR6004/hw6.1/fw.ram.bin"
+#define AR6004_REV1_FIRMWARE_2_FILE "ath6k/AR6004/hw6.1/fw-2.bin"
+#define AR6004_REV1_BOARD_DATA_FILE "ath6k/AR6004/hw6.1/bdata.bin"
+#define AR6004_REV1_DEFAULT_BOARD_DATA_FILE "ath6k/AR6004/hw6.1/bdata.DB132.bin"
+#define AR6004_REV1_EPPING_FIRMWARE_FILE "ath6k/AR6004/hw6.1/endpointping.bin"
+
+/* Per STA data, used in AP mode */
+#define STA_PS_AWAKE BIT(0)
+#define STA_PS_SLEEP BIT(1)
+#define STA_PS_POLLED BIT(2)
+
+/* HTC TX packet tagging definitions */
+#define ATH6KL_CONTROL_PKT_TAG HTC_TX_PACKET_TAG_USER_DEFINED
+#define ATH6KL_DATA_PKT_TAG (ATH6KL_CONTROL_PKT_TAG + 1)
+
+#define AR6003_CUST_DATA_SIZE 16
+
+#define AGGR_WIN_IDX(x, y) ((x) % (y))
+#define AGGR_INCR_IDX(x, y) AGGR_WIN_IDX(((x) + 1), (y))
+#define AGGR_DCRM_IDX(x, y) AGGR_WIN_IDX(((x) - 1), (y))
+#define ATH6KL_MAX_SEQ_NO 0xFFF
+#define ATH6KL_NEXT_SEQ_NO(x) (((x) + 1) & ATH6KL_MAX_SEQ_NO)
+
+#define NUM_OF_TIDS 8
+#define AGGR_SZ_DEFAULT 8
+
+#define AGGR_WIN_SZ_MIN 2
+#define AGGR_WIN_SZ_MAX 8
+
+#define TID_WINDOW_SZ(_x) ((_x) << 1)
+
+#define AGGR_NUM_OF_FREE_NETBUFS 16
+
+#define AGGR_RX_TIMEOUT 400 /* in ms */
+
+#define WMI_TIMEOUT (2 * HZ)
+
+#define MBOX_YIELD_LIMIT 99
+
+/* configuration lags */
+/*
+ * ATH6KL_CONF_IGNORE_ERP_BARKER: Ignore the barker premable in
+ * ERP IE of beacon to determine the short premable support when
+ * sending (Re)Assoc req.
+ * ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN: Don't send the power
+ * module state transition failure events which happen during
+ * scan, to the host.
+ */
+#define ATH6KL_CONF_IGNORE_ERP_BARKER BIT(0)
+#define ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN BIT(1)
+#define ATH6KL_CONF_ENABLE_11N BIT(2)
+#define ATH6KL_CONF_ENABLE_TX_BURST BIT(3)
+
+enum wlan_low_pwr_state {
+ WLAN_POWER_STATE_ON,
+ WLAN_POWER_STATE_CUT_PWR,
+ WLAN_POWER_STATE_DEEP_SLEEP,
+ WLAN_POWER_STATE_WOW
+};
+
+enum sme_state {
+ SME_DISCONNECTED,
+ SME_CONNECTING,
+ SME_CONNECTED
+};
+
+struct skb_hold_q {
+ struct sk_buff *skb;
+ bool is_amsdu;
+ u16 seq_no;
+};
+
+struct rxtid {
+ bool aggr;
+ bool progress;
+ bool timer_mon;
+ u16 win_sz;
+ u16 seq_next;
+ u32 hold_q_sz;
+ struct skb_hold_q *hold_q;
+ struct sk_buff_head q;
+ spinlock_t lock;
+};
+
+struct rxtid_stats {
+ u32 num_into_aggr;
+ u32 num_dups;
+ u32 num_oow;
+ u32 num_mpdu;
+ u32 num_amsdu;
+ u32 num_delivered;
+ u32 num_timeouts;
+ u32 num_hole;
+ u32 num_bar;
+};
+
+struct aggr_info {
+ u8 aggr_sz;
+ u8 timer_scheduled;
+ struct timer_list timer;
+ struct net_device *dev;
+ struct rxtid rx_tid[NUM_OF_TIDS];
+ struct sk_buff_head free_q;
+ struct rxtid_stats stat[NUM_OF_TIDS];
+};
+
+struct ath6kl_wep_key {
+ u8 key_index;
+ u8 key_len;
+ u8 key[64];
+};
+
+#define ATH6KL_KEY_SEQ_LEN 8
+
+struct ath6kl_key {
+ u8 key[WLAN_MAX_KEY_LEN];
+ u8 key_len;
+ u8 seq[ATH6KL_KEY_SEQ_LEN];
+ u8 seq_len;
+ u32 cipher;
+};
+
+struct ath6kl_node_mapping {
+ u8 mac_addr[ETH_ALEN];
+ u8 ep_id;
+ u8 tx_pend;
+};
+
+struct ath6kl_cookie {
+ struct sk_buff *skb;
+ u32 map_no;
+ struct htc_packet htc_pkt;
+ struct ath6kl_cookie *arc_list_next;
+};
+
+struct ath6kl_sta {
+ u16 sta_flags;
+ u8 mac[ETH_ALEN];
+ u8 aid;
+ u8 keymgmt;
+ u8 ucipher;
+ u8 auth;
+ u8 wpa_ie[ATH6KL_MAX_IE];
+ struct sk_buff_head psq;
+ spinlock_t psq_lock;
+};
+
+struct ath6kl_version {
+ u32 target_ver;
+ u32 wlan_ver;
+ u32 abi_ver;
+};
+
+struct ath6kl_bmi {
+ u32 cmd_credits;
+ bool done_sent;
+ u8 *cmd_buf;
+};
+
+struct target_stats {
+ u64 tx_pkt;
+ u64 tx_byte;
+ u64 tx_ucast_pkt;
+ u64 tx_ucast_byte;
+ u64 tx_mcast_pkt;
+ u64 tx_mcast_byte;
+ u64 tx_bcast_pkt;
+ u64 tx_bcast_byte;
+ u64 tx_rts_success_cnt;
+ u64 tx_pkt_per_ac[4];
+
+ u64 tx_err;
+ u64 tx_fail_cnt;
+ u64 tx_retry_cnt;
+ u64 tx_mult_retry_cnt;
+ u64 tx_rts_fail_cnt;
+
+ u64 rx_pkt;
+ u64 rx_byte;
+ u64 rx_ucast_pkt;
+ u64 rx_ucast_byte;
+ u64 rx_mcast_pkt;
+ u64 rx_mcast_byte;
+ u64 rx_bcast_pkt;
+ u64 rx_bcast_byte;
+ u64 rx_frgment_pkt;
+
+ u64 rx_err;
+ u64 rx_crc_err;
+ u64 rx_key_cache_miss;
+ u64 rx_decrypt_err;
+ u64 rx_dupl_frame;
+
+ u64 tkip_local_mic_fail;
+ u64 tkip_cnter_measures_invoked;
+ u64 tkip_replays;
+ u64 tkip_fmt_err;
+ u64 ccmp_fmt_err;
+ u64 ccmp_replays;
+
+ u64 pwr_save_fail_cnt;
+
+ u64 cs_bmiss_cnt;
+ u64 cs_low_rssi_cnt;
+ u64 cs_connect_cnt;
+ u64 cs_discon_cnt;
+
+ s32 tx_ucast_rate;
+ s32 rx_ucast_rate;
+
+ u32 lq_val;
+
+ u32 wow_pkt_dropped;
+ u16 wow_evt_discarded;
+
+ s16 noise_floor_calib;
+ s16 cs_rssi;
+ s16 cs_ave_beacon_rssi;
+ u8 cs_ave_beacon_snr;
+ u8 cs_last_roam_msec;
+ u8 cs_snr;
+
+ u8 wow_host_pkt_wakeups;
+ u8 wow_host_evt_wakeups;
+
+ u32 arp_received;
+ u32 arp_matched;
+ u32 arp_replied;
+};
+
+struct ath6kl_mbox_info {
+ u32 htc_addr;
+ u32 htc_ext_addr;
+ u32 htc_ext_sz;
+
+ u32 block_size;
+
+ u32 gmbox_addr;
+
+ u32 gmbox_sz;
+};
+
+/*
+ * 802.11i defines an extended IV for use with non-WEP ciphers.
+ * When the EXTIV bit is set in the key id byte an additional
+ * 4 bytes immediately follow the IV for TKIP. For CCMP the
+ * EXTIV bit is likewise set but the 8 bytes represent the
+ * CCMP header rather than IV+extended-IV.
+ */
+
+#define ATH6KL_KEYBUF_SIZE 16
+#define ATH6KL_MICBUF_SIZE (8+8) /* space for both tx and rx */
+
+#define ATH6KL_KEY_XMIT 0x01
+#define ATH6KL_KEY_RECV 0x02
+#define ATH6KL_KEY_DEFAULT 0x80 /* default xmit key */
+
+/* Initial group key for AP mode */
+struct ath6kl_req_key {
+ bool valid;
+ u8 key_index;
+ int key_type;
+ u8 key[WLAN_MAX_KEY_LEN];
+ u8 key_len;
+};
+
+/* Flag info */
+#define WMI_ENABLED 0
+#define WMI_READY 1
+#define CONNECTED 2
+#define STATS_UPDATE_PEND 3
+#define CONNECT_PEND 4
+#define WMM_ENABLED 5
+#define NETQ_STOPPED 6
+#define WMI_CTRL_EP_FULL 7
+#define DTIM_EXPIRED 8
+#define DESTROY_IN_PROGRESS 9
+#define NETDEV_REGISTERED 10
+#define SKIP_SCAN 11
+#define WLAN_ENABLED 12
+#define TESTMODE 13
+#define CLEAR_BSSFILTER_ON_BEACON 14
+#define DTIM_PERIOD_AVAIL 15
+
+struct ath6kl {
+ struct device *dev;
+ struct net_device *net_dev;
+ struct ath6kl_bmi bmi;
+ const struct ath6kl_hif_ops *hif_ops;
+ struct wmi *wmi;
+ int tx_pending[ENDPOINT_MAX];
+ int total_tx_data_pend;
+ struct htc_target *htc_target;
+ void *hif_priv;
+ spinlock_t lock;
+ struct semaphore sem;
+ int ssid_len;
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ u8 next_mode;
+ u8 nw_type;
+ u8 dot11_auth_mode;
+ u8 auth_mode;
+ u8 prwise_crypto;
+ u8 prwise_crypto_len;
+ u8 grp_crypto;
+ u8 grp_crypto_len;
+ u8 def_txkey_index;
+ struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1];
+ u8 bssid[ETH_ALEN];
+ u8 req_bssid[ETH_ALEN];
+ u16 ch_hint;
+ u16 bss_ch;
+ u16 listen_intvl_b;
+ u16 listen_intvl_t;
+ u8 lrssi_roam_threshold;
+ struct ath6kl_version version;
+ u32 target_type;
+ u8 tx_pwr;
+ struct net_device_stats net_stats;
+ struct target_stats target_stats;
+ struct ath6kl_node_mapping node_map[MAX_NODE_NUM];
+ u8 ibss_ps_enable;
+ u8 node_num;
+ u8 next_ep_id;
+ struct ath6kl_cookie *cookie_list;
+ u32 cookie_count;
+ enum htc_endpoint_id ac2ep_map[WMM_NUM_AC];
+ bool ac_stream_active[WMM_NUM_AC];
+ u8 ac_stream_pri_map[WMM_NUM_AC];
+ u8 hiac_stream_active_pri;
+ u8 ep2ac_map[ENDPOINT_MAX];
+ enum htc_endpoint_id ctrl_ep;
+ struct htc_credit_state_info credit_state_info;
+ u32 connect_ctrl_flags;
+ u32 user_key_ctrl;
+ u8 usr_bss_filter;
+ struct ath6kl_sta sta_list[AP_MAX_NUM_STA];
+ u8 sta_list_index;
+ struct ath6kl_req_key ap_mode_bkey;
+ struct sk_buff_head mcastpsq;
+ spinlock_t mcastpsq_lock;
+ u8 intra_bss;
+ struct aggr_info *aggr_cntxt;
+ struct wmi_ap_mode_stat ap_stats;
+ u8 ap_country_code[3];
+ struct list_head amsdu_rx_buffer_queue;
+ struct timer_list disconnect_timer;
+ u8 rx_meta_ver;
+ struct wireless_dev *wdev;
+ struct cfg80211_scan_request *scan_req;
+ struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1];
+ enum sme_state sme_state;
+ enum wlan_low_pwr_state wlan_pwr_state;
+ struct wmi_scan_params_cmd sc_params;
+#define AR_MCAST_FILTER_MAC_ADDR_SIZE 4
+ struct {
+ void *rx_report;
+ size_t rx_report_len;
+ } tm;
+
+ struct {
+ u32 dataset_patch_addr;
+ u32 app_load_addr;
+ u32 app_start_override_addr;
+ u32 board_ext_data_addr;
+ u32 reserved_ram_size;
+ } hw;
+
+ u16 conf_flags;
+ wait_queue_head_t event_wq;
+ struct ath6kl_mbox_info mbox_info;
+
+ struct ath6kl_cookie cookie_mem[MAX_COOKIE_NUM];
+ int reconnect_flag;
+ unsigned long flag;
+
+ u8 *fw_board;
+ size_t fw_board_len;
+
+ u8 *fw_otp;
+ size_t fw_otp_len;
+
+ u8 *fw;
+ size_t fw_len;
+
+ u8 *fw_patch;
+ size_t fw_patch_len;
+
+ unsigned long fw_capabilities[ATH6KL_CAPABILITY_LEN];
+
+ struct workqueue_struct *ath6kl_wq;
+
+ struct dentry *debugfs_phy;
+
+ u32 send_action_id;
+ bool probe_req_report;
+ u16 next_chan;
+
+ bool p2p;
+ u16 assoc_bss_beacon_int;
+ u8 assoc_bss_dtim_period;
+
+#ifdef CONFIG_ATH6KL_DEBUG
+ struct {
+ struct circ_buf fwlog_buf;
+ spinlock_t fwlog_lock;
+ void *fwlog_tmp;
+ u32 fwlog_mask;
+ unsigned int dbgfs_diag_reg;
+ u32 diag_reg_addr_wr;
+ u32 diag_reg_val_wr;
+
+ struct {
+ unsigned int invalid_rate;
+ } war_stats;
+ } debug;
+#endif /* CONFIG_ATH6KL_DEBUG */
+};
+
+static inline void *ath6kl_priv(struct net_device *dev)
+{
+ return wdev_priv(dev->ieee80211_ptr);
+}
+
+static inline void ath6kl_deposit_credit_to_ep(struct htc_credit_state_info
+ *cred_info,
+ struct htc_endpoint_credit_dist
+ *ep_dist, int credits)
+{
+ ep_dist->credits += credits;
+ ep_dist->cred_assngd += credits;
+ cred_info->cur_free_credits -= credits;
+}
+
+static inline u32 ath6kl_get_hi_item_addr(struct ath6kl *ar,
+ u32 item_offset)
+{
+ u32 addr = 0;
+
+ if (ar->target_type == TARGET_TYPE_AR6003)
+ addr = ATH6KL_AR6003_HI_START_ADDR + item_offset;
+ else if (ar->target_type == TARGET_TYPE_AR6004)
+ addr = ATH6KL_AR6004_HI_START_ADDR + item_offset;
+
+ return addr;
+}
+
+void ath6kl_destroy(struct net_device *dev, unsigned int unregister);
+int ath6kl_configure_target(struct ath6kl *ar);
+void ath6kl_detect_error(unsigned long ptr);
+void disconnect_timer_handler(unsigned long ptr);
+void init_netdev(struct net_device *dev);
+void ath6kl_cookie_init(struct ath6kl *ar);
+void ath6kl_cookie_cleanup(struct ath6kl *ar);
+void ath6kl_rx(struct htc_target *target, struct htc_packet *packet);
+void ath6kl_tx_complete(void *context, struct list_head *packet_queue);
+enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
+ struct htc_packet *packet);
+void ath6kl_stop_txrx(struct ath6kl *ar);
+void ath6kl_cleanup_amsdu_rxbufs(struct ath6kl *ar);
+int ath6kl_diag_write32(struct ath6kl *ar, u32 address, __le32 value);
+int ath6kl_diag_write(struct ath6kl *ar, u32 address, void *data, u32 length);
+int ath6kl_diag_read32(struct ath6kl *ar, u32 address, u32 *value);
+int ath6kl_diag_read(struct ath6kl *ar, u32 address, void *data, u32 length);
+int ath6kl_read_fwlogs(struct ath6kl *ar);
+void ath6kl_init_profile_info(struct ath6kl *ar);
+void ath6kl_tx_data_cleanup(struct ath6kl *ar);
+void ath6kl_stop_endpoint(struct net_device *dev, bool keep_profile,
+ bool get_dbglogs);
+
+struct ath6kl_cookie *ath6kl_alloc_cookie(struct ath6kl *ar);
+void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie);
+int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev);
+
+struct aggr_info *aggr_init(struct net_device *dev);
+void ath6kl_rx_refill(struct htc_target *target,
+ enum htc_endpoint_id endpoint);
+void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count);
+struct htc_packet *ath6kl_alloc_amsdu_rxbuf(struct htc_target *target,
+ enum htc_endpoint_id endpoint,
+ int len);
+void aggr_module_destroy(struct aggr_info *aggr_info);
+void aggr_reset_state(struct aggr_info *aggr_info);
+
+struct ath6kl_sta *ath6kl_find_sta(struct ath6kl *ar, u8 * node_addr);
+struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid);
+
+void ath6kl_ready_event(void *devt, u8 * datap, u32 sw_ver, u32 abi_ver);
+int ath6kl_control_tx(void *devt, struct sk_buff *skb,
+ enum htc_endpoint_id eid);
+void ath6kl_connect_event(struct ath6kl *ar, u16 channel,
+ u8 *bssid, u16 listen_int,
+ u16 beacon_int, enum network_type net_type,
+ u8 beacon_ie_len, u8 assoc_req_len,
+ u8 assoc_resp_len, u8 *assoc_info);
+void ath6kl_connect_ap_mode_bss(struct ath6kl *ar, u16 channel);
+void ath6kl_connect_ap_mode_sta(struct ath6kl *ar, u16 aid, u8 *mac_addr,
+ u8 keymgmt, u8 ucipher, u8 auth,
+ u8 assoc_req_len, u8 *assoc_info);
+void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason,
+ u8 *bssid, u8 assoc_resp_len,
+ u8 *assoc_info, u16 prot_reason_status);
+void ath6kl_tkip_micerr_event(struct ath6kl *ar, u8 keyid, bool ismcast);
+void ath6kl_txpwr_rx_evt(void *devt, u8 tx_pwr);
+void ath6kl_scan_complete_evt(struct ath6kl *ar, int status);
+void ath6kl_tgt_stats_event(struct ath6kl *ar, u8 *ptr, u32 len);
+void ath6kl_indicate_tx_activity(void *devt, u8 traffic_class, bool active);
+enum htc_endpoint_id ath6kl_ac2_endpoint_id(void *devt, u8 ac);
+
+void ath6kl_pspoll_event(struct ath6kl *ar, u8 aid);
+
+void ath6kl_dtimexpiry_event(struct ath6kl *ar);
+void ath6kl_disconnect(struct ath6kl *ar);
+void ath6kl_deep_sleep_enable(struct ath6kl *ar);
+void aggr_recv_delba_req_evt(struct ath6kl *ar, u8 tid);
+void aggr_recv_addba_req_evt(struct ath6kl *ar, u8 tid, u16 seq_no,
+ u8 win_sz);
+void ath6kl_wakeup_event(void *dev);
+void ath6kl_target_failure(struct ath6kl *ar);
+
+#endif /* CORE_H */
diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c
new file mode 100644
index 000000000000..ba3f23d71150
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/debug.c
@@ -0,0 +1,934 @@
+/*
+ * Copyright (c) 2004-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+
+#include <linux/circ_buf.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+
+#include "debug.h"
+#include "target.h"
+
+struct ath6kl_fwlog_slot {
+ __le32 timestamp;
+ __le32 length;
+
+ /* max ATH6KL_FWLOG_PAYLOAD_SIZE bytes */
+ u8 payload[0];
+};
+
+#define ATH6KL_FWLOG_SIZE 32768
+#define ATH6KL_FWLOG_SLOT_SIZE (sizeof(struct ath6kl_fwlog_slot) + \
+ ATH6KL_FWLOG_PAYLOAD_SIZE)
+#define ATH6KL_FWLOG_VALID_MASK 0x1ffff
+
+int ath6kl_printk(const char *level, const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+ int rtn;
+
+ va_start(args, fmt);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ rtn = printk("%sath6kl: %pV", level, &vaf);
+
+ va_end(args);
+
+ return rtn;
+}
+
+#ifdef CONFIG_ATH6KL_DEBUG
+
+#define REG_OUTPUT_LEN_PER_LINE 25
+#define REGTYPE_STR_LEN 100
+
+struct ath6kl_diag_reg_info {
+ u32 reg_start;
+ u32 reg_end;
+ const char *reg_info;
+};
+
+static const struct ath6kl_diag_reg_info diag_reg[] = {
+ { 0x20000, 0x200fc, "General DMA and Rx registers" },
+ { 0x28000, 0x28900, "MAC PCU register & keycache" },
+ { 0x20800, 0x20a40, "QCU" },
+ { 0x21000, 0x212f0, "DCU" },
+ { 0x4000, 0x42e4, "RTC" },
+ { 0x540000, 0x540000 + (256 * 1024), "RAM" },
+ { 0x29800, 0x2B210, "Base Band" },
+ { 0x1C000, 0x1C748, "Analog" },
+};
+
+void ath6kl_dump_registers(struct ath6kl_device *dev,
+ struct ath6kl_irq_proc_registers *irq_proc_reg,
+ struct ath6kl_irq_enable_reg *irq_enable_reg)
+{
+
+ ath6kl_dbg(ATH6KL_DBG_ANY, ("<------- Register Table -------->\n"));
+
+ if (irq_proc_reg != NULL) {
+ ath6kl_dbg(ATH6KL_DBG_ANY,
+ "Host Int status: 0x%x\n",
+ irq_proc_reg->host_int_status);
+ ath6kl_dbg(ATH6KL_DBG_ANY,
+ "CPU Int status: 0x%x\n",
+ irq_proc_reg->cpu_int_status);
+ ath6kl_dbg(ATH6KL_DBG_ANY,
+ "Error Int status: 0x%x\n",
+ irq_proc_reg->error_int_status);
+ ath6kl_dbg(ATH6KL_DBG_ANY,
+ "Counter Int status: 0x%x\n",
+ irq_proc_reg->counter_int_status);
+ ath6kl_dbg(ATH6KL_DBG_ANY,
+ "Mbox Frame: 0x%x\n",
+ irq_proc_reg->mbox_frame);
+ ath6kl_dbg(ATH6KL_DBG_ANY,
+ "Rx Lookahead Valid: 0x%x\n",
+ irq_proc_reg->rx_lkahd_valid);
+ ath6kl_dbg(ATH6KL_DBG_ANY,
+ "Rx Lookahead 0: 0x%x\n",
+ irq_proc_reg->rx_lkahd[0]);
+ ath6kl_dbg(ATH6KL_DBG_ANY,
+ "Rx Lookahead 1: 0x%x\n",
+ irq_proc_reg->rx_lkahd[1]);
+
+ if (dev->ar->mbox_info.gmbox_addr != 0) {
+ /*
+ * If the target supports GMBOX hardware, dump some
+ * additional state.
+ */
+ ath6kl_dbg(ATH6KL_DBG_ANY,
+ "GMBOX Host Int status 2: 0x%x\n",
+ irq_proc_reg->host_int_status2);
+ ath6kl_dbg(ATH6KL_DBG_ANY,
+ "GMBOX RX Avail: 0x%x\n",
+ irq_proc_reg->gmbox_rx_avail);
+ ath6kl_dbg(ATH6KL_DBG_ANY,
+ "GMBOX lookahead alias 0: 0x%x\n",
+ irq_proc_reg->rx_gmbox_lkahd_alias[0]);
+ ath6kl_dbg(ATH6KL_DBG_ANY,
+ "GMBOX lookahead alias 1: 0x%x\n",
+ irq_proc_reg->rx_gmbox_lkahd_alias[1]);
+ }
+
+ }
+
+ if (irq_enable_reg != NULL) {
+ ath6kl_dbg(ATH6KL_DBG_ANY,
+ "Int status Enable: 0x%x\n",
+ irq_enable_reg->int_status_en);
+ ath6kl_dbg(ATH6KL_DBG_ANY, "Counter Int status Enable: 0x%x\n",
+ irq_enable_reg->cntr_int_status_en);
+ }
+ ath6kl_dbg(ATH6KL_DBG_ANY, "<------------------------------->\n");
+}
+
+static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist)
+{
+ ath6kl_dbg(ATH6KL_DBG_ANY,
+ "--- endpoint: %d svc_id: 0x%X ---\n",
+ ep_dist->endpoint, ep_dist->svc_id);
+ ath6kl_dbg(ATH6KL_DBG_ANY, " dist_flags : 0x%X\n",
+ ep_dist->dist_flags);
+ ath6kl_dbg(ATH6KL_DBG_ANY, " cred_norm : %d\n",
+ ep_dist->cred_norm);
+ ath6kl_dbg(ATH6KL_DBG_ANY, " cred_min : %d\n",
+ ep_dist->cred_min);
+ ath6kl_dbg(ATH6KL_DBG_ANY, " credits : %d\n",
+ ep_dist->credits);
+ ath6kl_dbg(ATH6KL_DBG_ANY, " cred_assngd : %d\n",
+ ep_dist->cred_assngd);
+ ath6kl_dbg(ATH6KL_DBG_ANY, " seek_cred : %d\n",
+ ep_dist->seek_cred);
+ ath6kl_dbg(ATH6KL_DBG_ANY, " cred_sz : %d\n",
+ ep_dist->cred_sz);
+ ath6kl_dbg(ATH6KL_DBG_ANY, " cred_per_msg : %d\n",
+ ep_dist->cred_per_msg);
+ ath6kl_dbg(ATH6KL_DBG_ANY, " cred_to_dist : %d\n",
+ ep_dist->cred_to_dist);
+ ath6kl_dbg(ATH6KL_DBG_ANY, " txq_depth : %d\n",
+ get_queue_depth(&((struct htc_endpoint *)
+ ep_dist->htc_rsvd)->txq));
+ ath6kl_dbg(ATH6KL_DBG_ANY,
+ "----------------------------------\n");
+}
+
+void dump_cred_dist_stats(struct htc_target *target)
+{
+ struct htc_endpoint_credit_dist *ep_list;
+
+ if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_TRC))
+ return;
+
+ list_for_each_entry(ep_list, &target->cred_dist_list, list)
+ dump_cred_dist(ep_list);
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:%p dist:%p\n",
+ target->cred_dist_cntxt, NULL);
+ ath6kl_dbg(ATH6KL_DBG_TRC, "credit distribution, total : %d, free : %d\n",
+ target->cred_dist_cntxt->total_avail_credits,
+ target->cred_dist_cntxt->cur_free_credits);
+}
+
+static int ath6kl_debugfs_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war)
+{
+ switch (war) {
+ case ATH6KL_WAR_INVALID_RATE:
+ ar->debug.war_stats.invalid_rate++;
+ break;
+ }
+}
+
+static ssize_t read_file_war_stats(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath6kl *ar = file->private_data;
+ char *buf;
+ unsigned int len = 0, buf_len = 1500;
+ ssize_t ret_cnt;
+
+ buf = kzalloc(buf_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ len += scnprintf(buf + len, buf_len - len, "\n");
+ len += scnprintf(buf + len, buf_len - len, "%25s\n",
+ "Workaround stats");
+ len += scnprintf(buf + len, buf_len - len, "%25s\n\n",
+ "=================");
+ len += scnprintf(buf + len, buf_len - len, "%20s %10u\n",
+ "Invalid rates", ar->debug.war_stats.invalid_rate);
+
+ if (WARN_ON(len > buf_len))
+ len = buf_len;
+
+ ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+ kfree(buf);
+ return ret_cnt;
+}
+
+static const struct file_operations fops_war_stats = {
+ .read = read_file_war_stats,
+ .open = ath6kl_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static void ath6kl_debug_fwlog_add(struct ath6kl *ar, const void *buf,
+ size_t buf_len)
+{
+ struct circ_buf *fwlog = &ar->debug.fwlog_buf;
+ size_t space;
+ int i;
+
+ /* entries must all be equal size */
+ if (WARN_ON(buf_len != ATH6KL_FWLOG_SLOT_SIZE))
+ return;
+
+ space = CIRC_SPACE(fwlog->head, fwlog->tail, ATH6KL_FWLOG_SIZE);
+ if (space < buf_len)
+ /* discard oldest slot */
+ fwlog->tail = (fwlog->tail + ATH6KL_FWLOG_SLOT_SIZE) &
+ (ATH6KL_FWLOG_SIZE - 1);
+
+ for (i = 0; i < buf_len; i += space) {
+ space = CIRC_SPACE_TO_END(fwlog->head, fwlog->tail,
+ ATH6KL_FWLOG_SIZE);
+
+ if ((size_t) space > buf_len - i)
+ space = buf_len - i;
+
+ memcpy(&fwlog->buf[fwlog->head], buf, space);
+ fwlog->head = (fwlog->head + space) & (ATH6KL_FWLOG_SIZE - 1);
+ }
+
+}
+
+void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len)
+{
+ struct ath6kl_fwlog_slot *slot = ar->debug.fwlog_tmp;
+ size_t slot_len;
+
+ if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE))
+ return;
+
+ spin_lock_bh(&ar->debug.fwlog_lock);
+
+ slot->timestamp = cpu_to_le32(jiffies);
+ slot->length = cpu_to_le32(len);
+ memcpy(slot->payload, buf, len);
+
+ slot_len = sizeof(*slot) + len;
+
+ if (slot_len < ATH6KL_FWLOG_SLOT_SIZE)
+ memset(slot->payload + len, 0,
+ ATH6KL_FWLOG_SLOT_SIZE - slot_len);
+
+ ath6kl_debug_fwlog_add(ar, slot, ATH6KL_FWLOG_SLOT_SIZE);
+
+ spin_unlock_bh(&ar->debug.fwlog_lock);
+}
+
+static bool ath6kl_debug_fwlog_empty(struct ath6kl *ar)
+{
+ return CIRC_CNT(ar->debug.fwlog_buf.head,
+ ar->debug.fwlog_buf.tail,
+ ATH6KL_FWLOG_SLOT_SIZE) == 0;
+}
+
+static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath6kl *ar = file->private_data;
+ struct circ_buf *fwlog = &ar->debug.fwlog_buf;
+ size_t len = 0, buf_len = count;
+ ssize_t ret_cnt;
+ char *buf;
+ int ccnt;
+
+ buf = vmalloc(buf_len);
+ if (!buf)
+ return -ENOMEM;
+
+ /* read undelivered logs from firmware */
+ ath6kl_read_fwlogs(ar);
+
+ spin_lock_bh(&ar->debug.fwlog_lock);
+
+ while (len < buf_len && !ath6kl_debug_fwlog_empty(ar)) {
+ ccnt = CIRC_CNT_TO_END(fwlog->head, fwlog->tail,
+ ATH6KL_FWLOG_SIZE);
+
+ if ((size_t) ccnt > buf_len - len)
+ ccnt = buf_len - len;
+
+ memcpy(buf + len, &fwlog->buf[fwlog->tail], ccnt);
+ len += ccnt;
+
+ fwlog->tail = (fwlog->tail + ccnt) &
+ (ATH6KL_FWLOG_SIZE - 1);
+ }
+
+ spin_unlock_bh(&ar->debug.fwlog_lock);
+
+ if (WARN_ON(len > buf_len))
+ len = buf_len;
+
+ ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+ vfree(buf);
+
+ return ret_cnt;
+}
+
+static const struct file_operations fops_fwlog = {
+ .open = ath6kl_debugfs_open,
+ .read = ath6kl_fwlog_read,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath6kl *ar = file->private_data;
+ char buf[16];
+ int len;
+
+ len = snprintf(buf, sizeof(buf), "0x%x\n", ar->debug.fwlog_mask);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath6kl_fwlog_mask_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath6kl *ar = file->private_data;
+ int ret;
+
+ ret = kstrtou32_from_user(user_buf, count, 0, &ar->debug.fwlog_mask);
+ if (ret)
+ return ret;
+
+ ret = ath6kl_wmi_config_debug_module_cmd(ar->wmi,
+ ATH6KL_FWLOG_VALID_MASK,
+ ar->debug.fwlog_mask);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static const struct file_operations fops_fwlog_mask = {
+ .open = ath6kl_debugfs_open,
+ .read = ath6kl_fwlog_mask_read,
+ .write = ath6kl_fwlog_mask_write,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath6kl *ar = file->private_data;
+ struct target_stats *tgt_stats = &ar->target_stats;
+ char *buf;
+ unsigned int len = 0, buf_len = 1500;
+ int i;
+ long left;
+ ssize_t ret_cnt;
+
+ buf = kzalloc(buf_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (down_interruptible(&ar->sem)) {
+ kfree(buf);
+ return -EBUSY;
+ }
+
+ set_bit(STATS_UPDATE_PEND, &ar->flag);
+
+ if (ath6kl_wmi_get_stats_cmd(ar->wmi)) {
+ up(&ar->sem);
+ kfree(buf);
+ return -EIO;
+ }
+
+ left = wait_event_interruptible_timeout(ar->event_wq,
+ !test_bit(STATS_UPDATE_PEND,
+ &ar->flag), WMI_TIMEOUT);
+
+ up(&ar->sem);
+
+ if (left <= 0) {
+ kfree(buf);
+ return -ETIMEDOUT;
+ }
+
+ len += scnprintf(buf + len, buf_len - len, "\n");
+ len += scnprintf(buf + len, buf_len - len, "%25s\n",
+ "Target Tx stats");
+ len += scnprintf(buf + len, buf_len - len, "%25s\n\n",
+ "=================");
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Ucast packets", tgt_stats->tx_ucast_pkt);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Bcast packets", tgt_stats->tx_bcast_pkt);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Ucast byte", tgt_stats->tx_ucast_byte);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Bcast byte", tgt_stats->tx_bcast_byte);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Rts success cnt", tgt_stats->tx_rts_success_cnt);
+ for (i = 0; i < 4; i++)
+ len += scnprintf(buf + len, buf_len - len,
+ "%18s %d %10llu\n", "PER on ac",
+ i, tgt_stats->tx_pkt_per_ac[i]);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Error", tgt_stats->tx_err);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Fail count", tgt_stats->tx_fail_cnt);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Retry count", tgt_stats->tx_retry_cnt);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Multi retry cnt", tgt_stats->tx_mult_retry_cnt);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Rts fail cnt", tgt_stats->tx_rts_fail_cnt);
+ len += scnprintf(buf + len, buf_len - len, "%25s %10llu\n\n",
+ "TKIP counter measure used",
+ tgt_stats->tkip_cnter_measures_invoked);
+
+ len += scnprintf(buf + len, buf_len - len, "%25s\n",
+ "Target Rx stats");
+ len += scnprintf(buf + len, buf_len - len, "%25s\n",
+ "=================");
+
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Ucast packets", tgt_stats->rx_ucast_pkt);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
+ "Ucast Rate", tgt_stats->rx_ucast_rate);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Bcast packets", tgt_stats->rx_bcast_pkt);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Ucast byte", tgt_stats->rx_ucast_byte);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Bcast byte", tgt_stats->rx_bcast_byte);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Fragmented pkt", tgt_stats->rx_frgment_pkt);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Error", tgt_stats->rx_err);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "CRC Err", tgt_stats->rx_crc_err);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Key chache miss", tgt_stats->rx_key_cache_miss);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Decrypt Err", tgt_stats->rx_decrypt_err);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Duplicate frame", tgt_stats->rx_dupl_frame);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Tkip Mic failure", tgt_stats->tkip_local_mic_fail);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "TKIP format err", tgt_stats->tkip_fmt_err);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "CCMP format Err", tgt_stats->ccmp_fmt_err);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n\n",
+ "CCMP Replay Err", tgt_stats->ccmp_replays);
+
+ len += scnprintf(buf + len, buf_len - len, "%25s\n",
+ "Misc Target stats");
+ len += scnprintf(buf + len, buf_len - len, "%25s\n",
+ "=================");
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Beacon Miss count", tgt_stats->cs_bmiss_cnt);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Num Connects", tgt_stats->cs_connect_cnt);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
+ "Num disconnects", tgt_stats->cs_discon_cnt);
+ len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
+ "Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi);
+
+ if (len > buf_len)
+ len = buf_len;
+
+ ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+ kfree(buf);
+ return ret_cnt;
+}
+
+static const struct file_operations fops_tgt_stats = {
+ .read = read_file_tgt_stats,
+ .open = ath6kl_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+#define print_credit_info(fmt_str, ep_list_field) \
+ (len += scnprintf(buf + len, buf_len - len, fmt_str, \
+ ep_list->ep_list_field))
+#define CREDIT_INFO_DISPLAY_STRING_LEN 200
+#define CREDIT_INFO_LEN 128
+
+static ssize_t read_file_credit_dist_stats(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath6kl *ar = file->private_data;
+ struct htc_target *target = ar->htc_target;
+ struct htc_endpoint_credit_dist *ep_list;
+ char *buf;
+ unsigned int buf_len, len = 0;
+ ssize_t ret_cnt;
+
+ buf_len = CREDIT_INFO_DISPLAY_STRING_LEN +
+ get_queue_depth(&target->cred_dist_list) * CREDIT_INFO_LEN;
+ buf = kzalloc(buf_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ len += scnprintf(buf + len, buf_len - len, "%25s%5d\n",
+ "Total Avail Credits: ",
+ target->cred_dist_cntxt->total_avail_credits);
+ len += scnprintf(buf + len, buf_len - len, "%25s%5d\n",
+ "Free credits :",
+ target->cred_dist_cntxt->cur_free_credits);
+
+ len += scnprintf(buf + len, buf_len - len,
+ " Epid Flags Cred_norm Cred_min Credits Cred_assngd"
+ " Seek_cred Cred_sz Cred_per_msg Cred_to_dist"
+ " qdepth\n");
+
+ list_for_each_entry(ep_list, &target->cred_dist_list, list) {
+ print_credit_info(" %2d", endpoint);
+ print_credit_info("%10x", dist_flags);
+ print_credit_info("%8d", cred_norm);
+ print_credit_info("%9d", cred_min);
+ print_credit_info("%9d", credits);
+ print_credit_info("%10d", cred_assngd);
+ print_credit_info("%13d", seek_cred);
+ print_credit_info("%12d", cred_sz);
+ print_credit_info("%9d", cred_per_msg);
+ print_credit_info("%14d", cred_to_dist);
+ len += scnprintf(buf + len, buf_len - len, "%12d\n",
+ get_queue_depth(&((struct htc_endpoint *)
+ ep_list->htc_rsvd)->txq));
+ }
+
+ if (len > buf_len)
+ len = buf_len;
+
+ ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+ return ret_cnt;
+}
+
+static const struct file_operations fops_credit_dist_stats = {
+ .read = read_file_credit_dist_stats,
+ .open = ath6kl_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static unsigned long ath6kl_get_num_reg(void)
+{
+ int i;
+ unsigned long n_reg = 0;
+
+ for (i = 0; i < ARRAY_SIZE(diag_reg); i++)
+ n_reg = n_reg +
+ (diag_reg[i].reg_end - diag_reg[i].reg_start) / 4 + 1;
+
+ return n_reg;
+}
+
+static bool ath6kl_dbg_is_diag_reg_valid(u32 reg_addr)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(diag_reg); i++) {
+ if (reg_addr >= diag_reg[i].reg_start &&
+ reg_addr <= diag_reg[i].reg_end)
+ return true;
+ }
+
+ return false;
+}
+
+static ssize_t ath6kl_regread_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath6kl *ar = file->private_data;
+ u8 buf[50];
+ unsigned int len = 0;
+
+ if (ar->debug.dbgfs_diag_reg)
+ len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n",
+ ar->debug.dbgfs_diag_reg);
+ else
+ len += scnprintf(buf + len, sizeof(buf) - len,
+ "All diag registers\n");
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath6kl_regread_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath6kl *ar = file->private_data;
+ u8 buf[50];
+ unsigned int len;
+ unsigned long reg_addr;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+
+ if (strict_strtoul(buf, 0, &reg_addr))
+ return -EINVAL;
+
+ if ((reg_addr % 4) != 0)
+ return -EINVAL;
+
+ if (reg_addr && !ath6kl_dbg_is_diag_reg_valid(reg_addr))
+ return -EINVAL;
+
+ ar->debug.dbgfs_diag_reg = reg_addr;
+
+ return count;
+}
+
+static const struct file_operations fops_diag_reg_read = {
+ .read = ath6kl_regread_read,
+ .write = ath6kl_regread_write,
+ .open = ath6kl_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static int ath6kl_regdump_open(struct inode *inode, struct file *file)
+{
+ struct ath6kl *ar = inode->i_private;
+ u8 *buf;
+ unsigned long int reg_len;
+ unsigned int len = 0, n_reg;
+ u32 addr;
+ __le32 reg_val;
+ int i, status;
+
+ /* Dump all the registers if no register is specified */
+ if (!ar->debug.dbgfs_diag_reg)
+ n_reg = ath6kl_get_num_reg();
+ else
+ n_reg = 1;
+
+ reg_len = n_reg * REG_OUTPUT_LEN_PER_LINE;
+ if (n_reg > 1)
+ reg_len += REGTYPE_STR_LEN;
+
+ buf = vmalloc(reg_len);
+ if (!buf)
+ return -ENOMEM;
+
+ if (n_reg == 1) {
+ addr = ar->debug.dbgfs_diag_reg;
+
+ status = ath6kl_diag_read32(ar,
+ TARG_VTOP(ar->target_type, addr),
+ (u32 *)&reg_val);
+ if (status)
+ goto fail_reg_read;
+
+ len += scnprintf(buf + len, reg_len - len,
+ "0x%06x 0x%08x\n", addr, le32_to_cpu(reg_val));
+ goto done;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(diag_reg); i++) {
+ len += scnprintf(buf + len, reg_len - len,
+ "%s\n", diag_reg[i].reg_info);
+ for (addr = diag_reg[i].reg_start;
+ addr <= diag_reg[i].reg_end; addr += 4) {
+ status = ath6kl_diag_read32(ar,
+ TARG_VTOP(ar->target_type, addr),
+ (u32 *)&reg_val);
+ if (status)
+ goto fail_reg_read;
+
+ len += scnprintf(buf + len, reg_len - len,
+ "0x%06x 0x%08x\n",
+ addr, le32_to_cpu(reg_val));
+ }
+ }
+
+done:
+ file->private_data = buf;
+ return 0;
+
+fail_reg_read:
+ ath6kl_warn("Unable to read memory:%u\n", addr);
+ vfree(buf);
+ return -EIO;
+}
+
+static ssize_t ath6kl_regdump_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ u8 *buf = file->private_data;
+ return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+}
+
+static int ath6kl_regdump_release(struct inode *inode, struct file *file)
+{
+ vfree(file->private_data);
+ return 0;
+}
+
+static const struct file_operations fops_reg_dump = {
+ .open = ath6kl_regdump_open,
+ .read = ath6kl_regdump_read,
+ .release = ath6kl_regdump_release,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t ath6kl_lrssi_roam_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath6kl *ar = file->private_data;
+ unsigned long lrssi_roam_threshold;
+ char buf[32];
+ ssize_t len;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+ if (strict_strtoul(buf, 0, &lrssi_roam_threshold))
+ return -EINVAL;
+
+ ar->lrssi_roam_threshold = lrssi_roam_threshold;
+
+ ath6kl_wmi_set_roam_lrssi_cmd(ar->wmi, ar->lrssi_roam_threshold);
+
+ return count;
+}
+
+static ssize_t ath6kl_lrssi_roam_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath6kl *ar = file->private_data;
+ char buf[32];
+ unsigned int len;
+
+ len = snprintf(buf, sizeof(buf), "%u\n", ar->lrssi_roam_threshold);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_lrssi_roam_threshold = {
+ .read = ath6kl_lrssi_roam_read,
+ .write = ath6kl_lrssi_roam_write,
+ .open = ath6kl_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t ath6kl_regwrite_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath6kl *ar = file->private_data;
+ u8 buf[32];
+ unsigned int len = 0;
+
+ len = scnprintf(buf, sizeof(buf), "Addr: 0x%x Val: 0x%x\n",
+ ar->debug.diag_reg_addr_wr, ar->debug.diag_reg_val_wr);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath6kl_regwrite_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath6kl *ar = file->private_data;
+ char buf[32];
+ char *sptr, *token;
+ unsigned int len = 0;
+ u32 reg_addr, reg_val;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+ sptr = buf;
+
+ token = strsep(&sptr, "=");
+ if (!token)
+ return -EINVAL;
+
+ if (kstrtou32(token, 0, &reg_addr))
+ return -EINVAL;
+
+ if (!ath6kl_dbg_is_diag_reg_valid(reg_addr))
+ return -EINVAL;
+
+ if (kstrtou32(sptr, 0, &reg_val))
+ return -EINVAL;
+
+ ar->debug.diag_reg_addr_wr = reg_addr;
+ ar->debug.diag_reg_val_wr = reg_val;
+
+ if (ath6kl_diag_write32(ar, ar->debug.diag_reg_addr_wr,
+ cpu_to_le32(ar->debug.diag_reg_val_wr)))
+ return -EIO;
+
+ return count;
+}
+
+static const struct file_operations fops_diag_reg_write = {
+ .read = ath6kl_regwrite_read,
+ .write = ath6kl_regwrite_write,
+ .open = ath6kl_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+int ath6kl_debug_init(struct ath6kl *ar)
+{
+ ar->debug.fwlog_buf.buf = vmalloc(ATH6KL_FWLOG_SIZE);
+ if (ar->debug.fwlog_buf.buf == NULL)
+ return -ENOMEM;
+
+ ar->debug.fwlog_tmp = kmalloc(ATH6KL_FWLOG_SLOT_SIZE, GFP_KERNEL);
+ if (ar->debug.fwlog_tmp == NULL) {
+ vfree(ar->debug.fwlog_buf.buf);
+ return -ENOMEM;
+ }
+
+ spin_lock_init(&ar->debug.fwlog_lock);
+
+ /*
+ * Actually we are lying here but don't know how to read the mask
+ * value from the firmware.
+ */
+ ar->debug.fwlog_mask = 0;
+
+ ar->debugfs_phy = debugfs_create_dir("ath6kl",
+ ar->wdev->wiphy->debugfsdir);
+ if (!ar->debugfs_phy) {
+ vfree(ar->debug.fwlog_buf.buf);
+ kfree(ar->debug.fwlog_tmp);
+ return -ENOMEM;
+ }
+
+ debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar,
+ &fops_tgt_stats);
+
+ debugfs_create_file("credit_dist_stats", S_IRUSR, ar->debugfs_phy, ar,
+ &fops_credit_dist_stats);
+
+ debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar,
+ &fops_fwlog);
+
+ debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy,
+ ar, &fops_fwlog_mask);
+
+ debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR, ar->debugfs_phy, ar,
+ &fops_diag_reg_read);
+
+ debugfs_create_file("reg_dump", S_IRUSR, ar->debugfs_phy, ar,
+ &fops_reg_dump);
+
+ debugfs_create_file("lrssi_roam_threshold", S_IRUSR | S_IWUSR,
+ ar->debugfs_phy, ar, &fops_lrssi_roam_threshold);
+
+ debugfs_create_file("reg_write", S_IRUSR | S_IWUSR,
+ ar->debugfs_phy, ar, &fops_diag_reg_write);
+
+ debugfs_create_file("war_stats", S_IRUSR, ar->debugfs_phy, ar,
+ &fops_war_stats);
+
+ return 0;
+}
+
+void ath6kl_debug_cleanup(struct ath6kl *ar)
+{
+ vfree(ar->debug.fwlog_buf.buf);
+ kfree(ar->debug.fwlog_tmp);
+}
+
+#endif
diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h
new file mode 100644
index 000000000000..9288a3ce1e39
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/debug.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include "htc_hif.h"
+
+enum ATH6K_DEBUG_MASK {
+ ATH6KL_DBG_WLAN_CONNECT = BIT(0), /* wlan connect */
+ ATH6KL_DBG_WLAN_SCAN = BIT(1), /* wlan scan */
+ ATH6KL_DBG_WLAN_TX = BIT(2), /* wlan tx */
+ ATH6KL_DBG_WLAN_RX = BIT(3), /* wlan rx */
+ ATH6KL_DBG_BMI = BIT(4), /* bmi tracing */
+ ATH6KL_DBG_HTC_SEND = BIT(5), /* htc send */
+ ATH6KL_DBG_HTC_RECV = BIT(6), /* htc recv */
+ ATH6KL_DBG_IRQ = BIT(7), /* interrupt processing */
+ ATH6KL_DBG_PM = BIT(8), /* power management */
+ ATH6KL_DBG_WLAN_NODE = BIT(9), /* general wlan node tracing */
+ ATH6KL_DBG_WMI = BIT(10), /* wmi tracing */
+ ATH6KL_DBG_TRC = BIT(11), /* generic func tracing */
+ ATH6KL_DBG_SCATTER = BIT(12), /* hif scatter tracing */
+ ATH6KL_DBG_WLAN_CFG = BIT(13), /* cfg80211 i/f file tracing */
+ ATH6KL_DBG_RAW_BYTES = BIT(14), /* dump tx/rx frames */
+ ATH6KL_DBG_AGGR = BIT(15), /* aggregation */
+ ATH6KL_DBG_SDIO = BIT(16),
+ ATH6KL_DBG_SDIO_DUMP = BIT(17),
+ ATH6KL_DBG_BOOT = BIT(18), /* driver init and fw boot */
+ ATH6KL_DBG_WMI_DUMP = BIT(19),
+ ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */
+};
+
+extern unsigned int debug_mask;
+extern int ath6kl_printk(const char *level, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+
+#define ath6kl_info(fmt, ...) \
+ ath6kl_printk(KERN_INFO, fmt, ##__VA_ARGS__)
+#define ath6kl_err(fmt, ...) \
+ ath6kl_printk(KERN_ERR, fmt, ##__VA_ARGS__)
+#define ath6kl_warn(fmt, ...) \
+ ath6kl_printk(KERN_WARNING, fmt, ##__VA_ARGS__)
+
+#define AR_DBG_LVL_CHECK(mask) (debug_mask & mask)
+
+enum ath6kl_war {
+ ATH6KL_WAR_INVALID_RATE,
+};
+
+#ifdef CONFIG_ATH6KL_DEBUG
+#define ath6kl_dbg(mask, fmt, ...) \
+ ({ \
+ int rtn; \
+ if (debug_mask & mask) \
+ rtn = ath6kl_printk(KERN_DEBUG, fmt, ##__VA_ARGS__); \
+ else \
+ rtn = 0; \
+ \
+ rtn; \
+ })
+
+static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,
+ const char *msg, const char *prefix,
+ const void *buf, size_t len)
+{
+ if (debug_mask & mask) {
+ if (msg)
+ ath6kl_dbg(mask, "%s\n", msg);
+
+ print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
+ }
+}
+
+void ath6kl_dump_registers(struct ath6kl_device *dev,
+ struct ath6kl_irq_proc_registers *irq_proc_reg,
+ struct ath6kl_irq_enable_reg *irq_en_reg);
+void dump_cred_dist_stats(struct htc_target *target);
+void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len);
+void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war);
+int ath6kl_debug_init(struct ath6kl *ar);
+void ath6kl_debug_cleanup(struct ath6kl *ar);
+
+#else
+static inline int ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask,
+ const char *fmt, ...)
+{
+ return 0;
+}
+
+static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,
+ const char *msg, const char *prefix,
+ const void *buf, size_t len)
+{
+}
+
+static inline void ath6kl_dump_registers(struct ath6kl_device *dev,
+ struct ath6kl_irq_proc_registers *irq_proc_reg,
+ struct ath6kl_irq_enable_reg *irq_en_reg)
+{
+
+}
+static inline void dump_cred_dist_stats(struct htc_target *target)
+{
+}
+
+static inline void ath6kl_debug_fwlog_event(struct ath6kl *ar,
+ const void *buf, size_t len)
+{
+}
+
+static inline void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war)
+{
+}
+
+static inline int ath6kl_debug_init(struct ath6kl *ar)
+{
+ return 0;
+}
+
+static inline void ath6kl_debug_cleanup(struct ath6kl *ar)
+{
+}
+
+#endif
+#endif
diff --git a/drivers/net/wireless/ath/ath6kl/hif-ops.h b/drivers/net/wireless/ath/ath6kl/hif-ops.h
new file mode 100644
index 000000000000..d6c898f3d0b3
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/hif-ops.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2004-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef HIF_OPS_H
+#define HIF_OPS_H
+
+#include "hif.h"
+
+static inline int hif_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,
+ u32 len, u32 request)
+{
+ return ar->hif_ops->read_write_sync(ar, addr, buf, len, request);
+}
+
+static inline int hif_write_async(struct ath6kl *ar, u32 address, u8 *buffer,
+ u32 length, u32 request,
+ struct htc_packet *packet)
+{
+ return ar->hif_ops->write_async(ar, address, buffer, length,
+ request, packet);
+}
+static inline void ath6kl_hif_irq_enable(struct ath6kl *ar)
+{
+ return ar->hif_ops->irq_enable(ar);
+}
+
+static inline void ath6kl_hif_irq_disable(struct ath6kl *ar)
+{
+ return ar->hif_ops->irq_disable(ar);
+}
+
+static inline struct hif_scatter_req *hif_scatter_req_get(struct ath6kl *ar)
+{
+ return ar->hif_ops->scatter_req_get(ar);
+}
+
+static inline void hif_scatter_req_add(struct ath6kl *ar,
+ struct hif_scatter_req *s_req)
+{
+ return ar->hif_ops->scatter_req_add(ar, s_req);
+}
+
+static inline int ath6kl_hif_enable_scatter(struct ath6kl *ar)
+{
+ return ar->hif_ops->enable_scatter(ar);
+}
+
+static inline int ath6kl_hif_scat_req_rw(struct ath6kl *ar,
+ struct hif_scatter_req *scat_req)
+{
+ return ar->hif_ops->scat_req_rw(ar, scat_req);
+}
+
+static inline void ath6kl_hif_cleanup_scatter(struct ath6kl *ar)
+{
+ return ar->hif_ops->cleanup_scatter(ar);
+}
+
+static inline int ath6kl_hif_suspend(struct ath6kl *ar)
+{
+ return ar->hif_ops->suspend(ar);
+}
+
+#endif
diff --git a/drivers/net/wireless/ath/ath6kl/hif.h b/drivers/net/wireless/ath/ath6kl/hif.h
new file mode 100644
index 000000000000..797e2d1d9bf9
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/hif.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2004-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef HIF_H
+#define HIF_H
+
+#include "common.h"
+#include "core.h"
+
+#include <linux/scatterlist.h>
+
+#define BUS_REQUEST_MAX_NUM 64
+#define HIF_MBOX_BLOCK_SIZE 128
+#define HIF_MBOX0_BLOCK_SIZE 1
+
+#define HIF_DMA_BUFFER_SIZE (32 * 1024)
+#define CMD53_FIXED_ADDRESS 1
+#define CMD53_INCR_ADDRESS 2
+
+#define MAX_SCATTER_REQUESTS 4
+#define MAX_SCATTER_ENTRIES_PER_REQ 16
+#define MAX_SCATTER_REQ_TRANSFER_SIZE (32 * 1024)
+
+#define MANUFACTURER_ID_AR6003_BASE 0x300
+ /* SDIO manufacturer ID and Codes */
+#define MANUFACTURER_ID_ATH6KL_BASE_MASK 0xFF00
+#define MANUFACTURER_CODE 0x271 /* Atheros */
+
+/* Mailbox address in SDIO address space */
+#define HIF_MBOX_BASE_ADDR 0x800
+#define HIF_MBOX_WIDTH 0x800
+
+#define HIF_MBOX_END_ADDR (HTC_MAILBOX_NUM_MAX * HIF_MBOX_WIDTH - 1)
+
+/* version 1 of the chip has only a 12K extended mbox range */
+#define HIF_MBOX0_EXT_BASE_ADDR 0x4000
+#define HIF_MBOX0_EXT_WIDTH (12*1024)
+
+/* GMBOX addresses */
+#define HIF_GMBOX_BASE_ADDR 0x7000
+#define HIF_GMBOX_WIDTH 0x4000
+
+/* interrupt mode register */
+#define CCCR_SDIO_IRQ_MODE_REG 0xF0
+
+/* mode to enable special 4-bit interrupt assertion without clock */
+#define SDIO_IRQ_MODE_ASYNC_4BIT_IRQ (1 << 0)
+
+struct bus_request {
+ struct list_head list;
+
+ /* request data */
+ u32 address;
+
+ u8 *buffer;
+ u32 length;
+ u32 request;
+ struct htc_packet *packet;
+ int status;
+
+ /* this is a scatter request */
+ struct hif_scatter_req *scat_req;
+};
+
+/* direction of transfer (read/write) */
+#define HIF_READ 0x00000001
+#define HIF_WRITE 0x00000002
+#define HIF_DIR_MASK (HIF_READ | HIF_WRITE)
+
+/*
+ * emode - This indicates the whether the command is to be executed in a
+ * blocking or non-blocking fashion (HIF_SYNCHRONOUS/
+ * HIF_ASYNCHRONOUS). The read/write data paths in HTC have been
+ * implemented using the asynchronous mode allowing the the bus
+ * driver to indicate the completion of operation through the
+ * registered callback routine. The requirement primarily comes
+ * from the contexts these operations get called from (a driver's
+ * transmit context or the ISR context in case of receive).
+ * Support for both of these modes is essential.
+ */
+#define HIF_SYNCHRONOUS 0x00000010
+#define HIF_ASYNCHRONOUS 0x00000020
+#define HIF_EMODE_MASK (HIF_SYNCHRONOUS | HIF_ASYNCHRONOUS)
+
+/*
+ * dmode - An interface may support different kinds of commands based on
+ * the tradeoff between the amount of data it can carry and the
+ * setup time. Byte and Block modes are supported (HIF_BYTE_BASIS/
+ * HIF_BLOCK_BASIS). In case of latter, the data is rounded off
+ * to the nearest block size by padding. The size of the block is
+ * configurable at compile time using the HIF_BLOCK_SIZE and is
+ * negotiated with the target during initialization after the
+ * ATH6KL interrupts are enabled.
+ */
+#define HIF_BYTE_BASIS 0x00000040
+#define HIF_BLOCK_BASIS 0x00000080
+#define HIF_DMODE_MASK (HIF_BYTE_BASIS | HIF_BLOCK_BASIS)
+
+/*
+ * amode - This indicates if the address has to be incremented on ATH6KL
+ * after every read/write operation (HIF?FIXED_ADDRESS/
+ * HIF_INCREMENTAL_ADDRESS).
+ */
+#define HIF_FIXED_ADDRESS 0x00000100
+#define HIF_INCREMENTAL_ADDRESS 0x00000200
+#define HIF_AMODE_MASK (HIF_FIXED_ADDRESS | HIF_INCREMENTAL_ADDRESS)
+
+#define HIF_WR_ASYNC_BYTE_INC \
+ (HIF_WRITE | HIF_ASYNCHRONOUS | \
+ HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
+
+#define HIF_WR_ASYNC_BLOCK_INC \
+ (HIF_WRITE | HIF_ASYNCHRONOUS | \
+ HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
+
+#define HIF_WR_SYNC_BYTE_FIX \
+ (HIF_WRITE | HIF_SYNCHRONOUS | \
+ HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
+
+#define HIF_WR_SYNC_BYTE_INC \
+ (HIF_WRITE | HIF_SYNCHRONOUS | \
+ HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
+
+#define HIF_WR_SYNC_BLOCK_INC \
+ (HIF_WRITE | HIF_SYNCHRONOUS | \
+ HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
+
+#define HIF_RD_SYNC_BYTE_INC \
+ (HIF_READ | HIF_SYNCHRONOUS | \
+ HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
+
+#define HIF_RD_SYNC_BYTE_FIX \
+ (HIF_READ | HIF_SYNCHRONOUS | \
+ HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
+
+#define HIF_RD_ASYNC_BLOCK_FIX \
+ (HIF_READ | HIF_ASYNCHRONOUS | \
+ HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS)
+
+#define HIF_RD_SYNC_BLOCK_FIX \
+ (HIF_READ | HIF_SYNCHRONOUS | \
+ HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS)
+
+struct hif_scatter_item {
+ u8 *buf;
+ int len;
+ struct htc_packet *packet;
+};
+
+struct hif_scatter_req {
+ struct list_head list;
+ /* address for the read/write operation */
+ u32 addr;
+
+ /* request flags */
+ u32 req;
+
+ /* total length of entire transfer */
+ u32 len;
+
+ bool virt_scat;
+
+ void (*complete) (struct htc_target *, struct hif_scatter_req *);
+ int status;
+ int scat_entries;
+
+ struct bus_request *busrequest;
+ struct scatterlist *sgentries;
+
+ /* bounce buffer for upper layers to copy to/from */
+ u8 *virt_dma_buf;
+
+ struct hif_scatter_item scat_list[1];
+};
+
+struct ath6kl_hif_ops {
+ int (*read_write_sync)(struct ath6kl *ar, u32 addr, u8 *buf,
+ u32 len, u32 request);
+ int (*write_async)(struct ath6kl *ar, u32 address, u8 *buffer,
+ u32 length, u32 request, struct htc_packet *packet);
+
+ void (*irq_enable)(struct ath6kl *ar);
+ void (*irq_disable)(struct ath6kl *ar);
+
+ struct hif_scatter_req *(*scatter_req_get)(struct ath6kl *ar);
+ void (*scatter_req_add)(struct ath6kl *ar,
+ struct hif_scatter_req *s_req);
+ int (*enable_scatter)(struct ath6kl *ar);
+ int (*scat_req_rw) (struct ath6kl *ar,
+ struct hif_scatter_req *scat_req);
+ void (*cleanup_scatter)(struct ath6kl *ar);
+ int (*suspend)(struct ath6kl *ar);
+};
+
+#endif
diff --git a/drivers/net/wireless/ath/ath6kl/htc.c b/drivers/net/wireless/ath/ath6kl/htc.c
new file mode 100644
index 000000000000..f88a7c9e4148
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/htc.c
@@ -0,0 +1,2478 @@
+/*
+ * Copyright (c) 2007-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "htc_hif.h"
+#include "debug.h"
+#include "hif-ops.h"
+#include <asm/unaligned.h>
+
+#define CALC_TXRX_PADDED_LEN(dev, len) (__ALIGN_MASK((len), (dev)->block_mask))
+
+static void ath6kl_htc_tx_buf_align(u8 **buf, unsigned long len)
+{
+ u8 *align_addr;
+
+ if (!IS_ALIGNED((unsigned long) *buf, 4)) {
+ align_addr = PTR_ALIGN(*buf - 4, 4);
+ memmove(align_addr, *buf, len);
+ *buf = align_addr;
+ }
+}
+
+static void ath6kl_htc_tx_prep_pkt(struct htc_packet *packet, u8 flags,
+ int ctrl0, int ctrl1)
+{
+ struct htc_frame_hdr *hdr;
+
+ packet->buf -= HTC_HDR_LENGTH;
+ hdr = (struct htc_frame_hdr *)packet->buf;
+
+ /* Endianess? */
+ put_unaligned((u16)packet->act_len, &hdr->payld_len);
+ hdr->flags = flags;
+ hdr->eid = packet->endpoint;
+ hdr->ctrl[0] = ctrl0;
+ hdr->ctrl[1] = ctrl1;
+}
+
+static void htc_reclaim_txctrl_buf(struct htc_target *target,
+ struct htc_packet *pkt)
+{
+ spin_lock_bh(&target->htc_lock);
+ list_add_tail(&pkt->list, &target->free_ctrl_txbuf);
+ spin_unlock_bh(&target->htc_lock);
+}
+
+static struct htc_packet *htc_get_control_buf(struct htc_target *target,
+ bool tx)
+{
+ struct htc_packet *packet = NULL;
+ struct list_head *buf_list;
+
+ buf_list = tx ? &target->free_ctrl_txbuf : &target->free_ctrl_rxbuf;
+
+ spin_lock_bh(&target->htc_lock);
+
+ if (list_empty(buf_list)) {
+ spin_unlock_bh(&target->htc_lock);
+ return NULL;
+ }
+
+ packet = list_first_entry(buf_list, struct htc_packet, list);
+ list_del(&packet->list);
+ spin_unlock_bh(&target->htc_lock);
+
+ if (tx)
+ packet->buf = packet->buf_start + HTC_HDR_LENGTH;
+
+ return packet;
+}
+
+static void htc_tx_comp_update(struct htc_target *target,
+ struct htc_endpoint *endpoint,
+ struct htc_packet *packet)
+{
+ packet->completion = NULL;
+ packet->buf += HTC_HDR_LENGTH;
+
+ if (!packet->status)
+ return;
+
+ ath6kl_err("req failed (status:%d, ep:%d, len:%d creds:%d)\n",
+ packet->status, packet->endpoint, packet->act_len,
+ packet->info.tx.cred_used);
+
+ /* on failure to submit, reclaim credits for this packet */
+ spin_lock_bh(&target->tx_lock);
+ endpoint->cred_dist.cred_to_dist +=
+ packet->info.tx.cred_used;
+ endpoint->cred_dist.txq_depth = get_queue_depth(&endpoint->txq);
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:0x%p dist:0x%p\n",
+ target->cred_dist_cntxt, &target->cred_dist_list);
+
+ ath6k_credit_distribute(target->cred_dist_cntxt,
+ &target->cred_dist_list,
+ HTC_CREDIT_DIST_SEND_COMPLETE);
+
+ spin_unlock_bh(&target->tx_lock);
+}
+
+static void htc_tx_complete(struct htc_endpoint *endpoint,
+ struct list_head *txq)
+{
+ if (list_empty(txq))
+ return;
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+ "send complete ep %d, (%d pkts)\n",
+ endpoint->eid, get_queue_depth(txq));
+
+ ath6kl_tx_complete(endpoint->target->dev->ar, txq);
+}
+
+static void htc_tx_comp_handler(struct htc_target *target,
+ struct htc_packet *packet)
+{
+ struct htc_endpoint *endpoint = &target->endpoint[packet->endpoint];
+ struct list_head container;
+
+ htc_tx_comp_update(target, endpoint, packet);
+ INIT_LIST_HEAD(&container);
+ list_add_tail(&packet->list, &container);
+ /* do completion */
+ htc_tx_complete(endpoint, &container);
+}
+
+static void htc_async_tx_scat_complete(struct htc_target *target,
+ struct hif_scatter_req *scat_req)
+{
+ struct htc_endpoint *endpoint;
+ struct htc_packet *packet;
+ struct list_head tx_compq;
+ int i;
+
+ INIT_LIST_HEAD(&tx_compq);
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+ "htc_async_tx_scat_complete total len: %d entries: %d\n",
+ scat_req->len, scat_req->scat_entries);
+
+ if (scat_req->status)
+ ath6kl_err("send scatter req failed: %d\n", scat_req->status);
+
+ packet = scat_req->scat_list[0].packet;
+ endpoint = &target->endpoint[packet->endpoint];
+
+ /* walk through the scatter list and process */
+ for (i = 0; i < scat_req->scat_entries; i++) {
+ packet = scat_req->scat_list[i].packet;
+ if (!packet) {
+ WARN_ON(1);
+ return;
+ }
+
+ packet->status = scat_req->status;
+ htc_tx_comp_update(target, endpoint, packet);
+ list_add_tail(&packet->list, &tx_compq);
+ }
+
+ /* free scatter request */
+ hif_scatter_req_add(target->dev->ar, scat_req);
+
+ /* complete all packets */
+ htc_tx_complete(endpoint, &tx_compq);
+}
+
+static int ath6kl_htc_tx_issue(struct htc_target *target,
+ struct htc_packet *packet)
+{
+ int status;
+ bool sync = false;
+ u32 padded_len, send_len;
+
+ if (!packet->completion)
+ sync = true;
+
+ send_len = packet->act_len + HTC_HDR_LENGTH;
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "%s: transmit len : %d (%s)\n",
+ __func__, send_len, sync ? "sync" : "async");
+
+ padded_len = CALC_TXRX_PADDED_LEN(target, send_len);
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+ "DevSendPacket, padded len: %d mbox:0x%X (mode:%s)\n",
+ padded_len,
+ target->dev->ar->mbox_info.htc_addr,
+ sync ? "sync" : "async");
+
+ if (sync) {
+ status = hif_read_write_sync(target->dev->ar,
+ target->dev->ar->mbox_info.htc_addr,
+ packet->buf, padded_len,
+ HIF_WR_SYNC_BLOCK_INC);
+
+ packet->status = status;
+ packet->buf += HTC_HDR_LENGTH;
+ } else
+ status = hif_write_async(target->dev->ar,
+ target->dev->ar->mbox_info.htc_addr,
+ packet->buf, padded_len,
+ HIF_WR_ASYNC_BLOCK_INC, packet);
+
+ return status;
+}
+
+static int htc_check_credits(struct htc_target *target,
+ struct htc_endpoint *ep, u8 *flags,
+ enum htc_endpoint_id eid, unsigned int len,
+ int *req_cred)
+{
+
+ *req_cred = (len > target->tgt_cred_sz) ?
+ DIV_ROUND_UP(len, target->tgt_cred_sz) : 1;
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "creds required:%d got:%d\n",
+ *req_cred, ep->cred_dist.credits);
+
+ if (ep->cred_dist.credits < *req_cred) {
+ if (eid == ENDPOINT_0)
+ return -EINVAL;
+
+ /* Seek more credits */
+ ep->cred_dist.seek_cred = *req_cred - ep->cred_dist.credits;
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:0x%p dist:0x%p\n",
+ target->cred_dist_cntxt, &ep->cred_dist);
+
+ ath6k_seek_credits(target->cred_dist_cntxt, &ep->cred_dist);
+
+ ep->cred_dist.seek_cred = 0;
+
+ if (ep->cred_dist.credits < *req_cred) {
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+ "not enough credits for ep %d - leaving packet in queue\n",
+ eid);
+ return -EINVAL;
+ }
+ }
+
+ ep->cred_dist.credits -= *req_cred;
+ ep->ep_st.cred_cosumd += *req_cred;
+
+ /* When we are getting low on credits, ask for more */
+ if (ep->cred_dist.credits < ep->cred_dist.cred_per_msg) {
+ ep->cred_dist.seek_cred =
+ ep->cred_dist.cred_per_msg - ep->cred_dist.credits;
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:0x%p dist:0x%p\n",
+ target->cred_dist_cntxt, &ep->cred_dist);
+
+ ath6k_seek_credits(target->cred_dist_cntxt, &ep->cred_dist);
+
+ /* see if we were successful in getting more */
+ if (ep->cred_dist.credits < ep->cred_dist.cred_per_msg) {
+ /* tell the target we need credits ASAP! */
+ *flags |= HTC_FLAGS_NEED_CREDIT_UPDATE;
+ ep->ep_st.cred_low_indicate += 1;
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "host needs credits\n");
+ }
+ }
+
+ return 0;
+}
+
+static void ath6kl_htc_tx_pkts_get(struct htc_target *target,
+ struct htc_endpoint *endpoint,
+ struct list_head *queue)
+{
+ int req_cred;
+ u8 flags;
+ struct htc_packet *packet;
+ unsigned int len;
+
+ while (true) {
+
+ flags = 0;
+
+ if (list_empty(&endpoint->txq))
+ break;
+ packet = list_first_entry(&endpoint->txq, struct htc_packet,
+ list);
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+ "got head pkt:0x%p , queue depth: %d\n",
+ packet, get_queue_depth(&endpoint->txq));
+
+ len = CALC_TXRX_PADDED_LEN(target,
+ packet->act_len + HTC_HDR_LENGTH);
+
+ if (htc_check_credits(target, endpoint, &flags,
+ packet->endpoint, len, &req_cred))
+ break;
+
+ /* now we can fully move onto caller's queue */
+ packet = list_first_entry(&endpoint->txq, struct htc_packet,
+ list);
+ list_move_tail(&packet->list, queue);
+
+ /* save the number of credits this packet consumed */
+ packet->info.tx.cred_used = req_cred;
+
+ /* all TX packets are handled asynchronously */
+ packet->completion = htc_tx_comp_handler;
+ packet->context = target;
+ endpoint->ep_st.tx_issued += 1;
+
+ /* save send flags */
+ packet->info.tx.flags = flags;
+ packet->info.tx.seqno = endpoint->seqno;
+ endpoint->seqno++;
+ }
+}
+
+/* See if the padded tx length falls on a credit boundary */
+static int htc_get_credit_padding(unsigned int cred_sz, int *len,
+ struct htc_endpoint *ep)
+{
+ int rem_cred, cred_pad;
+
+ rem_cred = *len % cred_sz;
+
+ /* No padding needed */
+ if (!rem_cred)
+ return 0;
+
+ if (!(ep->conn_flags & HTC_FLGS_TX_BNDL_PAD_EN))
+ return -1;
+
+ /*
+ * The transfer consumes a "partial" credit, this
+ * packet cannot be bundled unless we add
+ * additional "dummy" padding (max 255 bytes) to
+ * consume the entire credit.
+ */
+ cred_pad = *len < cred_sz ? (cred_sz - *len) : rem_cred;
+
+ if ((cred_pad > 0) && (cred_pad <= 255))
+ *len += cred_pad;
+ else
+ /* The amount of padding is too large, send as non-bundled */
+ return -1;
+
+ return cred_pad;
+}
+
+static int ath6kl_htc_tx_setup_scat_list(struct htc_target *target,
+ struct htc_endpoint *endpoint,
+ struct hif_scatter_req *scat_req,
+ int n_scat,
+ struct list_head *queue)
+{
+ struct htc_packet *packet;
+ int i, len, rem_scat, cred_pad;
+ int status = 0;
+
+ rem_scat = target->max_tx_bndl_sz;
+
+ for (i = 0; i < n_scat; i++) {
+ scat_req->scat_list[i].packet = NULL;
+
+ if (list_empty(queue))
+ break;
+
+ packet = list_first_entry(queue, struct htc_packet, list);
+ len = CALC_TXRX_PADDED_LEN(target,
+ packet->act_len + HTC_HDR_LENGTH);
+
+ cred_pad = htc_get_credit_padding(target->tgt_cred_sz,
+ &len, endpoint);
+ if (cred_pad < 0 || rem_scat < len) {
+ status = -ENOSPC;
+ break;
+ }
+
+ rem_scat -= len;
+ /* now remove it from the queue */
+ list_del(&packet->list);
+
+ scat_req->scat_list[i].packet = packet;
+ /* prepare packet and flag message as part of a send bundle */
+ ath6kl_htc_tx_prep_pkt(packet,
+ packet->info.tx.flags | HTC_FLAGS_SEND_BUNDLE,
+ cred_pad, packet->info.tx.seqno);
+ /* Make sure the buffer is 4-byte aligned */
+ ath6kl_htc_tx_buf_align(&packet->buf,
+ packet->act_len + HTC_HDR_LENGTH);
+ scat_req->scat_list[i].buf = packet->buf;
+ scat_req->scat_list[i].len = len;
+
+ scat_req->len += len;
+ scat_req->scat_entries++;
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+ "%d, adding pkt : 0x%p len:%d (remaining space:%d)\n",
+ i, packet, len, rem_scat);
+ }
+
+ /* Roll back scatter setup in case of any failure */
+ if (scat_req->scat_entries < HTC_MIN_HTC_MSGS_TO_BUNDLE) {
+ for (i = scat_req->scat_entries - 1; i >= 0; i--) {
+ packet = scat_req->scat_list[i].packet;
+ if (packet) {
+ packet->buf += HTC_HDR_LENGTH;
+ list_add(&packet->list, queue);
+ }
+ }
+ return -EAGAIN;
+ }
+
+ return status;
+}
+
+/*
+ * Drain a queue and send as bundles this function may return without fully
+ * draining the queue when
+ *
+ * 1. scatter resources are exhausted
+ * 2. a message that will consume a partial credit will stop the
+ * bundling process early
+ * 3. we drop below the minimum number of messages for a bundle
+ */
+static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint,
+ struct list_head *queue,
+ int *sent_bundle, int *n_bundle_pkts)
+{
+ struct htc_target *target = endpoint->target;
+ struct hif_scatter_req *scat_req = NULL;
+ int n_scat, n_sent_bundle = 0, tot_pkts_bundle = 0;
+ int status;
+
+ while (true) {
+ status = 0;
+ n_scat = get_queue_depth(queue);
+ n_scat = min(n_scat, target->msg_per_bndl_max);
+
+ if (n_scat < HTC_MIN_HTC_MSGS_TO_BUNDLE)
+ /* not enough to bundle */
+ break;
+
+ scat_req = hif_scatter_req_get(target->dev->ar);
+
+ if (!scat_req) {
+ /* no scatter resources */
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+ "no more scatter resources\n");
+ break;
+ }
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "pkts to scatter: %d\n",
+ n_scat);
+
+ scat_req->len = 0;
+ scat_req->scat_entries = 0;
+
+ status = ath6kl_htc_tx_setup_scat_list(target, endpoint,
+ scat_req, n_scat,
+ queue);
+ if (status == -EAGAIN) {
+ hif_scatter_req_add(target->dev->ar, scat_req);
+ break;
+ }
+
+ /* send path is always asynchronous */
+ scat_req->complete = htc_async_tx_scat_complete;
+ n_sent_bundle++;
+ tot_pkts_bundle += scat_req->scat_entries;
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+ "send scatter total bytes: %d , entries: %d\n",
+ scat_req->len, scat_req->scat_entries);
+ ath6kldev_submit_scat_req(target->dev, scat_req, false);
+
+ if (status)
+ break;
+ }
+
+ *sent_bundle = n_sent_bundle;
+ *n_bundle_pkts = tot_pkts_bundle;
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "%s (sent:%d)\n",
+ __func__, n_sent_bundle);
+
+ return;
+}
+
+static void ath6kl_htc_tx_from_queue(struct htc_target *target,
+ struct htc_endpoint *endpoint)
+{
+ struct list_head txq;
+ struct htc_packet *packet;
+ int bundle_sent;
+ int n_pkts_bundle;
+
+ spin_lock_bh(&target->tx_lock);
+
+ endpoint->tx_proc_cnt++;
+ if (endpoint->tx_proc_cnt > 1) {
+ endpoint->tx_proc_cnt--;
+ spin_unlock_bh(&target->tx_lock);
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "htc_try_send (busy)\n");
+ return;
+ }
+
+ /*
+ * drain the endpoint TX queue for transmission as long
+ * as we have enough credits.
+ */
+ INIT_LIST_HEAD(&txq);
+
+ while (true) {
+
+ if (list_empty(&endpoint->txq))
+ break;
+
+ ath6kl_htc_tx_pkts_get(target, endpoint, &txq);
+
+ if (list_empty(&txq))
+ break;
+
+ spin_unlock_bh(&target->tx_lock);
+
+ bundle_sent = 0;
+ n_pkts_bundle = 0;
+
+ while (true) {
+ /* try to send a bundle on each pass */
+ if ((target->tx_bndl_enable) &&
+ (get_queue_depth(&txq) >=
+ HTC_MIN_HTC_MSGS_TO_BUNDLE)) {
+ int temp1 = 0, temp2 = 0;
+
+ ath6kl_htc_tx_bundle(endpoint, &txq,
+ &temp1, &temp2);
+ bundle_sent += temp1;
+ n_pkts_bundle += temp2;
+ }
+
+ if (list_empty(&txq))
+ break;
+
+ packet = list_first_entry(&txq, struct htc_packet,
+ list);
+ list_del(&packet->list);
+
+ ath6kl_htc_tx_prep_pkt(packet, packet->info.tx.flags,
+ 0, packet->info.tx.seqno);
+ ath6kl_htc_tx_issue(target, packet);
+ }
+
+ spin_lock_bh(&target->tx_lock);
+
+ endpoint->ep_st.tx_bundles += bundle_sent;
+ endpoint->ep_st.tx_pkt_bundled += n_pkts_bundle;
+ }
+
+ endpoint->tx_proc_cnt = 0;
+ spin_unlock_bh(&target->tx_lock);
+}
+
+static bool ath6kl_htc_tx_try(struct htc_target *target,
+ struct htc_endpoint *endpoint,
+ struct htc_packet *tx_pkt)
+{
+ struct htc_ep_callbacks ep_cb;
+ int txq_depth;
+ bool overflow = false;
+
+ ep_cb = endpoint->ep_cb;
+
+ spin_lock_bh(&target->tx_lock);
+ txq_depth = get_queue_depth(&endpoint->txq);
+ spin_unlock_bh(&target->tx_lock);
+
+ if (txq_depth >= endpoint->max_txq_depth)
+ overflow = true;
+
+ if (overflow)
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+ "ep %d, tx queue will overflow :%d , tx depth:%d, max:%d\n",
+ endpoint->eid, overflow, txq_depth,
+ endpoint->max_txq_depth);
+
+ if (overflow && ep_cb.tx_full) {
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+ "indicating overflowed tx packet: 0x%p\n", tx_pkt);
+
+ if (ep_cb.tx_full(endpoint->target, tx_pkt) ==
+ HTC_SEND_FULL_DROP) {
+ endpoint->ep_st.tx_dropped += 1;
+ return false;
+ }
+ }
+
+ spin_lock_bh(&target->tx_lock);
+ list_add_tail(&tx_pkt->list, &endpoint->txq);
+ spin_unlock_bh(&target->tx_lock);
+
+ ath6kl_htc_tx_from_queue(target, endpoint);
+
+ return true;
+}
+
+static void htc_chk_ep_txq(struct htc_target *target)
+{
+ struct htc_endpoint *endpoint;
+ struct htc_endpoint_credit_dist *cred_dist;
+
+ /*
+ * Run through the credit distribution list to see if there are
+ * packets queued. NOTE: no locks need to be taken since the
+ * distribution list is not dynamic (cannot be re-ordered) and we
+ * are not modifying any state.
+ */
+ list_for_each_entry(cred_dist, &target->cred_dist_list, list) {
+ endpoint = (struct htc_endpoint *)cred_dist->htc_rsvd;
+
+ spin_lock_bh(&target->tx_lock);
+ if (!list_empty(&endpoint->txq)) {
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+ "ep %d has %d credits and %d packets in tx queue\n",
+ cred_dist->endpoint,
+ endpoint->cred_dist.credits,
+ get_queue_depth(&endpoint->txq));
+ spin_unlock_bh(&target->tx_lock);
+ /*
+ * Try to start the stalled queue, this list is
+ * ordered by priority. If there are credits
+ * available the highest priority queue will get a
+ * chance to reclaim credits from lower priority
+ * ones.
+ */
+ ath6kl_htc_tx_from_queue(target, endpoint);
+ spin_lock_bh(&target->tx_lock);
+ }
+ spin_unlock_bh(&target->tx_lock);
+ }
+}
+
+static int htc_setup_tx_complete(struct htc_target *target)
+{
+ struct htc_packet *send_pkt = NULL;
+ int status;
+
+ send_pkt = htc_get_control_buf(target, true);
+
+ if (!send_pkt)
+ return -ENOMEM;
+
+ if (target->htc_tgt_ver >= HTC_VERSION_2P1) {
+ struct htc_setup_comp_ext_msg *setup_comp_ext;
+ u32 flags = 0;
+
+ setup_comp_ext =
+ (struct htc_setup_comp_ext_msg *)send_pkt->buf;
+ memset(setup_comp_ext, 0, sizeof(*setup_comp_ext));
+ setup_comp_ext->msg_id =
+ cpu_to_le16(HTC_MSG_SETUP_COMPLETE_EX_ID);
+
+ if (target->msg_per_bndl_max > 0) {
+ /* Indicate HTC bundling to the target */
+ flags |= HTC_SETUP_COMP_FLG_RX_BNDL_EN;
+ setup_comp_ext->msg_per_rxbndl =
+ target->msg_per_bndl_max;
+ }
+
+ memcpy(&setup_comp_ext->flags, &flags,
+ sizeof(setup_comp_ext->flags));
+ set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp_ext,
+ sizeof(struct htc_setup_comp_ext_msg),
+ ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG);
+
+ } else {
+ struct htc_setup_comp_msg *setup_comp;
+ setup_comp = (struct htc_setup_comp_msg *)send_pkt->buf;
+ memset(setup_comp, 0, sizeof(struct htc_setup_comp_msg));
+ setup_comp->msg_id = cpu_to_le16(HTC_MSG_SETUP_COMPLETE_ID);
+ set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp,
+ sizeof(struct htc_setup_comp_msg),
+ ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG);
+ }
+
+ /* we want synchronous operation */
+ send_pkt->completion = NULL;
+ ath6kl_htc_tx_prep_pkt(send_pkt, 0, 0, 0);
+ status = ath6kl_htc_tx_issue(target, send_pkt);
+
+ if (send_pkt != NULL)
+ htc_reclaim_txctrl_buf(target, send_pkt);
+
+ return status;
+}
+
+void ath6kl_htc_set_credit_dist(struct htc_target *target,
+ struct htc_credit_state_info *cred_dist_cntxt,
+ u16 srvc_pri_order[], int list_len)
+{
+ struct htc_endpoint *endpoint;
+ int i, ep;
+
+ target->cred_dist_cntxt = cred_dist_cntxt;
+
+ list_add_tail(&target->endpoint[ENDPOINT_0].cred_dist.list,
+ &target->cred_dist_list);
+
+ for (i = 0; i < list_len; i++) {
+ for (ep = ENDPOINT_1; ep < ENDPOINT_MAX; ep++) {
+ endpoint = &target->endpoint[ep];
+ if (endpoint->svc_id == srvc_pri_order[i]) {
+ list_add_tail(&endpoint->cred_dist.list,
+ &target->cred_dist_list);
+ break;
+ }
+ }
+ if (ep >= ENDPOINT_MAX) {
+ WARN_ON(1);
+ return;
+ }
+ }
+}
+
+int ath6kl_htc_tx(struct htc_target *target, struct htc_packet *packet)
+{
+ struct htc_endpoint *endpoint;
+ struct list_head queue;
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+ "htc_tx: ep id: %d, buf: 0x%p, len: %d\n",
+ packet->endpoint, packet->buf, packet->act_len);
+
+ if (packet->endpoint >= ENDPOINT_MAX) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ endpoint = &target->endpoint[packet->endpoint];
+
+ if (!ath6kl_htc_tx_try(target, endpoint, packet)) {
+ packet->status = (target->htc_flags & HTC_OP_STATE_STOPPING) ?
+ -ECANCELED : -ENOSPC;
+ INIT_LIST_HEAD(&queue);
+ list_add(&packet->list, &queue);
+ htc_tx_complete(endpoint, &queue);
+ }
+
+ return 0;
+}
+
+/* flush endpoint TX queue */
+void ath6kl_htc_flush_txep(struct htc_target *target,
+ enum htc_endpoint_id eid, u16 tag)
+{
+ struct htc_packet *packet, *tmp_pkt;
+ struct list_head discard_q, container;
+ struct htc_endpoint *endpoint = &target->endpoint[eid];
+
+ if (!endpoint->svc_id) {
+ WARN_ON(1);
+ return;
+ }
+
+ /* initialize the discard queue */
+ INIT_LIST_HEAD(&discard_q);
+
+ spin_lock_bh(&target->tx_lock);
+
+ list_for_each_entry_safe(packet, tmp_pkt, &endpoint->txq, list) {
+ if ((tag == HTC_TX_PACKET_TAG_ALL) ||
+ (tag == packet->info.tx.tag))
+ list_move_tail(&packet->list, &discard_q);
+ }
+
+ spin_unlock_bh(&target->tx_lock);
+
+ list_for_each_entry_safe(packet, tmp_pkt, &discard_q, list) {
+ packet->status = -ECANCELED;
+ list_del(&packet->list);
+ ath6kl_dbg(ATH6KL_DBG_TRC,
+ "flushing tx pkt:0x%p, len:%d, ep:%d tag:0x%X\n",
+ packet, packet->act_len,
+ packet->endpoint, packet->info.tx.tag);
+
+ INIT_LIST_HEAD(&container);
+ list_add_tail(&packet->list, &container);
+ htc_tx_complete(endpoint, &container);
+ }
+
+}
+
+static void ath6kl_htc_flush_txep_all(struct htc_target *target)
+{
+ struct htc_endpoint *endpoint;
+ int i;
+
+ dump_cred_dist_stats(target);
+
+ for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
+ endpoint = &target->endpoint[i];
+ if (endpoint->svc_id == 0)
+ /* not in use.. */
+ continue;
+ ath6kl_htc_flush_txep(target, i, HTC_TX_PACKET_TAG_ALL);
+ }
+}
+
+void ath6kl_htc_indicate_activity_change(struct htc_target *target,
+ enum htc_endpoint_id eid, bool active)
+{
+ struct htc_endpoint *endpoint = &target->endpoint[eid];
+ bool dist = false;
+
+ if (endpoint->svc_id == 0) {
+ WARN_ON(1);
+ return;
+ }
+
+ spin_lock_bh(&target->tx_lock);
+
+ if (active) {
+ if (!(endpoint->cred_dist.dist_flags & HTC_EP_ACTIVE)) {
+ endpoint->cred_dist.dist_flags |= HTC_EP_ACTIVE;
+ dist = true;
+ }
+ } else {
+ if (endpoint->cred_dist.dist_flags & HTC_EP_ACTIVE) {
+ endpoint->cred_dist.dist_flags &= ~HTC_EP_ACTIVE;
+ dist = true;
+ }
+ }
+
+ if (dist) {
+ endpoint->cred_dist.txq_depth =
+ get_queue_depth(&endpoint->txq);
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:0x%p dist:0x%p\n",
+ target->cred_dist_cntxt, &target->cred_dist_list);
+
+ ath6k_credit_distribute(target->cred_dist_cntxt,
+ &target->cred_dist_list,
+ HTC_CREDIT_DIST_ACTIVITY_CHANGE);
+ }
+
+ spin_unlock_bh(&target->tx_lock);
+
+ if (dist && !active)
+ htc_chk_ep_txq(target);
+}
+
+/* HTC Rx */
+
+static inline void ath6kl_htc_rx_update_stats(struct htc_endpoint *endpoint,
+ int n_look_ahds)
+{
+ endpoint->ep_st.rx_pkts++;
+ if (n_look_ahds == 1)
+ endpoint->ep_st.rx_lkahds++;
+ else if (n_look_ahds > 1)
+ endpoint->ep_st.rx_bundle_lkahd++;
+}
+
+static inline bool htc_valid_rx_frame_len(struct htc_target *target,
+ enum htc_endpoint_id eid, int len)
+{
+ return (eid == target->dev->ar->ctrl_ep) ?
+ len <= ATH6KL_BUFFER_SIZE : len <= ATH6KL_AMSDU_BUFFER_SIZE;
+}
+
+static int htc_add_rxbuf(struct htc_target *target, struct htc_packet *packet)
+{
+ struct list_head queue;
+
+ INIT_LIST_HEAD(&queue);
+ list_add_tail(&packet->list, &queue);
+ return ath6kl_htc_add_rxbuf_multiple(target, &queue);
+}
+
+static void htc_reclaim_rxbuf(struct htc_target *target,
+ struct htc_packet *packet,
+ struct htc_endpoint *ep)
+{
+ if (packet->info.rx.rx_flags & HTC_RX_PKT_NO_RECYCLE) {
+ htc_rxpkt_reset(packet);
+ packet->status = -ECANCELED;
+ ep->ep_cb.rx(ep->target, packet);
+ } else {
+ htc_rxpkt_reset(packet);
+ htc_add_rxbuf((void *)(target), packet);
+ }
+}
+
+static void reclaim_rx_ctrl_buf(struct htc_target *target,
+ struct htc_packet *packet)
+{
+ spin_lock_bh(&target->htc_lock);
+ list_add_tail(&packet->list, &target->free_ctrl_rxbuf);
+ spin_unlock_bh(&target->htc_lock);
+}
+
+static int ath6kl_htc_rx_packet(struct htc_target *target,
+ struct htc_packet *packet,
+ u32 rx_len)
+{
+ struct ath6kl_device *dev = target->dev;
+ u32 padded_len;
+ int status;
+
+ padded_len = CALC_TXRX_PADDED_LEN(target, rx_len);
+
+ if (padded_len > packet->buf_len) {
+ ath6kl_err("not enough receive space for packet - padlen:%d recvlen:%d bufferlen:%d\n",
+ padded_len, rx_len, packet->buf_len);
+ return -ENOMEM;
+ }
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
+ "dev_rx_pkt (0x%p : hdr:0x%X) padded len: %d mbox:0x%X (mode:%s)\n",
+ packet, packet->info.rx.exp_hdr,
+ padded_len, dev->ar->mbox_info.htc_addr, "sync");
+
+ status = hif_read_write_sync(dev->ar,
+ dev->ar->mbox_info.htc_addr,
+ packet->buf, padded_len,
+ HIF_RD_SYNC_BLOCK_FIX);
+
+ packet->status = status;
+
+ return status;
+}
+
+/*
+ * optimization for recv packets, we can indicate a
+ * "hint" that there are more single-packets to fetch
+ * on this endpoint.
+ */
+static void ath6kl_htc_rx_set_indicate(u32 lk_ahd,
+ struct htc_endpoint *endpoint,
+ struct htc_packet *packet)
+{
+ struct htc_frame_hdr *htc_hdr = (struct htc_frame_hdr *)&lk_ahd;
+
+ if (htc_hdr->eid == packet->endpoint) {
+ if (!list_empty(&endpoint->rx_bufq))
+ packet->info.rx.indicat_flags |=
+ HTC_RX_FLAGS_INDICATE_MORE_PKTS;
+ }
+}
+
+static void ath6kl_htc_rx_chk_water_mark(struct htc_endpoint *endpoint)
+{
+ struct htc_ep_callbacks ep_cb = endpoint->ep_cb;
+
+ if (ep_cb.rx_refill_thresh > 0) {
+ spin_lock_bh(&endpoint->target->rx_lock);
+ if (get_queue_depth(&endpoint->rx_bufq)
+ < ep_cb.rx_refill_thresh) {
+ spin_unlock_bh(&endpoint->target->rx_lock);
+ ep_cb.rx_refill(endpoint->target, endpoint->eid);
+ return;
+ }
+ spin_unlock_bh(&endpoint->target->rx_lock);
+ }
+}
+
+/* This function is called with rx_lock held */
+static int ath6kl_htc_rx_setup(struct htc_target *target,
+ struct htc_endpoint *ep,
+ u32 *lk_ahds, struct list_head *queue, int n_msg)
+{
+ struct htc_packet *packet;
+ /* FIXME: type of lk_ahds can't be right */
+ struct htc_frame_hdr *htc_hdr = (struct htc_frame_hdr *)lk_ahds;
+ struct htc_ep_callbacks ep_cb;
+ int status = 0, j, full_len;
+ bool no_recycle;
+
+ full_len = CALC_TXRX_PADDED_LEN(target,
+ le16_to_cpu(htc_hdr->payld_len) +
+ sizeof(*htc_hdr));
+
+ if (!htc_valid_rx_frame_len(target, ep->eid, full_len)) {
+ ath6kl_warn("Rx buffer requested with invalid length\n");
+ return -EINVAL;
+ }
+
+ ep_cb = ep->ep_cb;
+ for (j = 0; j < n_msg; j++) {
+
+ /*
+ * Reset flag, any packets allocated using the
+ * rx_alloc() API cannot be recycled on
+ * cleanup,they must be explicitly returned.
+ */
+ no_recycle = false;
+
+ if (ep_cb.rx_allocthresh &&
+ (full_len > ep_cb.rx_alloc_thresh)) {
+ ep->ep_st.rx_alloc_thresh_hit += 1;
+ ep->ep_st.rxalloc_thresh_byte +=
+ le16_to_cpu(htc_hdr->payld_len);
+
+ spin_unlock_bh(&target->rx_lock);
+ no_recycle = true;
+
+ packet = ep_cb.rx_allocthresh(ep->target, ep->eid,
+ full_len);
+ spin_lock_bh(&target->rx_lock);
+ } else {
+ /* refill handler is being used */
+ if (list_empty(&ep->rx_bufq)) {
+ if (ep_cb.rx_refill) {
+ spin_unlock_bh(&target->rx_lock);
+ ep_cb.rx_refill(ep->target, ep->eid);
+ spin_lock_bh(&target->rx_lock);
+ }
+ }
+
+ if (list_empty(&ep->rx_bufq))
+ packet = NULL;
+ else {
+ packet = list_first_entry(&ep->rx_bufq,
+ struct htc_packet, list);
+ list_del(&packet->list);
+ }
+ }
+
+ if (!packet) {
+ target->rx_st_flags |= HTC_RECV_WAIT_BUFFERS;
+ target->ep_waiting = ep->eid;
+ return -ENOSPC;
+ }
+
+ /* clear flags */
+ packet->info.rx.rx_flags = 0;
+ packet->info.rx.indicat_flags = 0;
+ packet->status = 0;
+
+ if (no_recycle)
+ /*
+ * flag that these packets cannot be
+ * recycled, they have to be returned to
+ * the user
+ */
+ packet->info.rx.rx_flags |= HTC_RX_PKT_NO_RECYCLE;
+
+ /* Caller needs to free this upon any failure */
+ list_add_tail(&packet->list, queue);
+
+ if (target->htc_flags & HTC_OP_STATE_STOPPING) {
+ status = -ECANCELED;
+ break;
+ }
+
+ if (j) {
+ packet->info.rx.rx_flags |= HTC_RX_PKT_REFRESH_HDR;
+ packet->info.rx.exp_hdr = 0xFFFFFFFF;
+ } else
+ /* set expected look ahead */
+ packet->info.rx.exp_hdr = *lk_ahds;
+
+ packet->act_len = le16_to_cpu(htc_hdr->payld_len) +
+ HTC_HDR_LENGTH;
+ }
+
+ return status;
+}
+
+static int ath6kl_htc_rx_alloc(struct htc_target *target,
+ u32 lk_ahds[], int msg,
+ struct htc_endpoint *endpoint,
+ struct list_head *queue)
+{
+ int status = 0;
+ struct htc_packet *packet, *tmp_pkt;
+ struct htc_frame_hdr *htc_hdr;
+ int i, n_msg;
+
+ spin_lock_bh(&target->rx_lock);
+
+ for (i = 0; i < msg; i++) {
+
+ htc_hdr = (struct htc_frame_hdr *)&lk_ahds[i];
+
+ if (htc_hdr->eid >= ENDPOINT_MAX) {
+ ath6kl_err("invalid ep in look-ahead: %d\n",
+ htc_hdr->eid);
+ status = -ENOMEM;
+ break;
+ }
+
+ if (htc_hdr->eid != endpoint->eid) {
+ ath6kl_err("invalid ep in look-ahead: %d should be : %d (index:%d)\n",
+ htc_hdr->eid, endpoint->eid, i);
+ status = -ENOMEM;
+ break;
+ }
+
+ if (le16_to_cpu(htc_hdr->payld_len) > HTC_MAX_PAYLOAD_LENGTH) {
+ ath6kl_err("payload len %d exceeds max htc : %d !\n",
+ htc_hdr->payld_len,
+ (u32) HTC_MAX_PAYLOAD_LENGTH);
+ status = -ENOMEM;
+ break;
+ }
+
+ if (endpoint->svc_id == 0) {
+ ath6kl_err("ep %d is not connected !\n", htc_hdr->eid);
+ status = -ENOMEM;
+ break;
+ }
+
+ if (htc_hdr->flags & HTC_FLG_RX_BNDL_CNT) {
+ /*
+ * HTC header indicates that every packet to follow
+ * has the same padded length so that it can be
+ * optimally fetched as a full bundle.
+ */
+ n_msg = (htc_hdr->flags & HTC_FLG_RX_BNDL_CNT) >>
+ HTC_FLG_RX_BNDL_CNT_S;
+
+ /* the count doesn't include the starter frame */
+ n_msg++;
+ if (n_msg > target->msg_per_bndl_max) {
+ status = -ENOMEM;
+ break;
+ }
+
+ endpoint->ep_st.rx_bundle_from_hdr += 1;
+ ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
+ "htc hdr indicates :%d msg can be fetched as a bundle\n",
+ n_msg);
+ } else
+ /* HTC header only indicates 1 message to fetch */
+ n_msg = 1;
+
+ /* Setup packet buffers for each message */
+ status = ath6kl_htc_rx_setup(target, endpoint, &lk_ahds[i],
+ queue, n_msg);
+
+ /*
+ * This is due to unavailabilty of buffers to rx entire data.
+ * Return no error so that free buffers from queue can be used
+ * to receive partial data.
+ */
+ if (status == -ENOSPC) {
+ spin_unlock_bh(&target->rx_lock);
+ return 0;
+ }
+
+ if (status)
+ break;
+ }
+
+ spin_unlock_bh(&target->rx_lock);
+
+ if (status) {
+ list_for_each_entry_safe(packet, tmp_pkt, queue, list) {
+ list_del(&packet->list);
+ htc_reclaim_rxbuf(target, packet,
+ &target->endpoint[packet->endpoint]);
+ }
+ }
+
+ return status;
+}
+
+static void htc_ctrl_rx(struct htc_target *context, struct htc_packet *packets)
+{
+ if (packets->endpoint != ENDPOINT_0) {
+ WARN_ON(1);
+ return;
+ }
+
+ if (packets->status == -ECANCELED) {
+ reclaim_rx_ctrl_buf(context, packets);
+ return;
+ }
+
+ if (packets->act_len > 0) {
+ ath6kl_err("htc_ctrl_rx, got message with len:%zu\n",
+ packets->act_len + HTC_HDR_LENGTH);
+
+ ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES,
+ "Unexpected ENDPOINT 0 Message", "",
+ packets->buf - HTC_HDR_LENGTH,
+ packets->act_len + HTC_HDR_LENGTH);
+ }
+
+ htc_reclaim_rxbuf(context, packets, &context->endpoint[0]);
+}
+
+static void htc_proc_cred_rpt(struct htc_target *target,
+ struct htc_credit_report *rpt,
+ int n_entries,
+ enum htc_endpoint_id from_ep)
+{
+ struct htc_endpoint *endpoint;
+ int tot_credits = 0, i;
+ bool dist = false;
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+ "htc_proc_cred_rpt, credit report entries:%d\n", n_entries);
+
+ spin_lock_bh(&target->tx_lock);
+
+ for (i = 0; i < n_entries; i++, rpt++) {
+ if (rpt->eid >= ENDPOINT_MAX) {
+ WARN_ON(1);
+ spin_unlock_bh(&target->tx_lock);
+ return;
+ }
+
+ endpoint = &target->endpoint[rpt->eid];
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND, " ep %d got %d credits\n",
+ rpt->eid, rpt->credits);
+
+ endpoint->ep_st.tx_cred_rpt += 1;
+ endpoint->ep_st.cred_retnd += rpt->credits;
+
+ if (from_ep == rpt->eid) {
+ /*
+ * This credit report arrived on the same endpoint
+ * indicating it arrived in an RX packet.
+ */
+ endpoint->ep_st.cred_from_rx += rpt->credits;
+ endpoint->ep_st.cred_rpt_from_rx += 1;
+ } else if (from_ep == ENDPOINT_0) {
+ /* credit arrived on endpoint 0 as a NULL message */
+ endpoint->ep_st.cred_from_ep0 += rpt->credits;
+ endpoint->ep_st.cred_rpt_ep0 += 1;
+ } else {
+ endpoint->ep_st.cred_from_other += rpt->credits;
+ endpoint->ep_st.cred_rpt_from_other += 1;
+ }
+
+ if (rpt->eid == ENDPOINT_0)
+ /* always give endpoint 0 credits back */
+ endpoint->cred_dist.credits += rpt->credits;
+ else {
+ endpoint->cred_dist.cred_to_dist += rpt->credits;
+ dist = true;
+ }
+
+ /*
+ * Refresh tx depth for distribution function that will
+ * recover these credits NOTE: this is only valid when
+ * there are credits to recover!
+ */
+ endpoint->cred_dist.txq_depth =
+ get_queue_depth(&endpoint->txq);
+
+ tot_credits += rpt->credits;
+ }
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND,
+ "report indicated %d credits to distribute\n",
+ tot_credits);
+
+ if (dist) {
+ /*
+ * This was a credit return based on a completed send
+ * operations note, this is done with the lock held
+ */
+ ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:0x%p dist:0x%p\n",
+ target->cred_dist_cntxt, &target->cred_dist_list);
+
+ ath6k_credit_distribute(target->cred_dist_cntxt,
+ &target->cred_dist_list,
+ HTC_CREDIT_DIST_SEND_COMPLETE);
+ }
+
+ spin_unlock_bh(&target->tx_lock);
+
+ if (tot_credits)
+ htc_chk_ep_txq(target);
+}
+
+static int htc_parse_trailer(struct htc_target *target,
+ struct htc_record_hdr *record,
+ u8 *record_buf, u32 *next_lk_ahds,
+ enum htc_endpoint_id endpoint,
+ int *n_lk_ahds)
+{
+ struct htc_bundle_lkahd_rpt *bundle_lkahd_rpt;
+ struct htc_lookahead_report *lk_ahd;
+ int len;
+
+ switch (record->rec_id) {
+ case HTC_RECORD_CREDITS:
+ len = record->len / sizeof(struct htc_credit_report);
+ if (!len) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ htc_proc_cred_rpt(target,
+ (struct htc_credit_report *) record_buf,
+ len, endpoint);
+ break;
+ case HTC_RECORD_LOOKAHEAD:
+ len = record->len / sizeof(*lk_ahd);
+ if (!len) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ lk_ahd = (struct htc_lookahead_report *) record_buf;
+ if ((lk_ahd->pre_valid == ((~lk_ahd->post_valid) & 0xFF))
+ && next_lk_ahds) {
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
+ "lk_ahd report found (pre valid:0x%X, post valid:0x%X)\n",
+ lk_ahd->pre_valid, lk_ahd->post_valid);
+
+ /* look ahead bytes are valid, copy them over */
+ memcpy((u8 *)&next_lk_ahds[0], lk_ahd->lk_ahd, 4);
+
+ ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Next Look Ahead",
+ "", next_lk_ahds, 4);
+
+ *n_lk_ahds = 1;
+ }
+ break;
+ case HTC_RECORD_LOOKAHEAD_BUNDLE:
+ len = record->len / sizeof(*bundle_lkahd_rpt);
+ if (!len || (len > HTC_HOST_MAX_MSG_PER_BUNDLE)) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ if (next_lk_ahds) {
+ int i;
+
+ bundle_lkahd_rpt =
+ (struct htc_bundle_lkahd_rpt *) record_buf;
+
+ ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Bundle lk_ahd",
+ "", record_buf, record->len);
+
+ for (i = 0; i < len; i++) {
+ memcpy((u8 *)&next_lk_ahds[i],
+ bundle_lkahd_rpt->lk_ahd, 4);
+ bundle_lkahd_rpt++;
+ }
+
+ *n_lk_ahds = i;
+ }
+ break;
+ default:
+ ath6kl_err("unhandled record: id:%d len:%d\n",
+ record->rec_id, record->len);
+ break;
+ }
+
+ return 0;
+
+}
+
+static int htc_proc_trailer(struct htc_target *target,
+ u8 *buf, int len, u32 *next_lk_ahds,
+ int *n_lk_ahds, enum htc_endpoint_id endpoint)
+{
+ struct htc_record_hdr *record;
+ int orig_len;
+ int status;
+ u8 *record_buf;
+ u8 *orig_buf;
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_RECV, "+htc_proc_trailer (len:%d)\n", len);
+
+ ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Recv Trailer", "",
+ buf, len);
+
+ orig_buf = buf;
+ orig_len = len;
+ status = 0;
+
+ while (len > 0) {
+
+ if (len < sizeof(struct htc_record_hdr)) {
+ status = -ENOMEM;
+ break;
+ }
+ /* these are byte aligned structs */
+ record = (struct htc_record_hdr *) buf;
+ len -= sizeof(struct htc_record_hdr);
+ buf += sizeof(struct htc_record_hdr);
+
+ if (record->len > len) {
+ ath6kl_err("invalid record len: %d (id:%d) buf has: %d bytes left\n",
+ record->len, record->rec_id, len);
+ status = -ENOMEM;
+ break;
+ }
+ record_buf = buf;
+
+ status = htc_parse_trailer(target, record, record_buf,
+ next_lk_ahds, endpoint, n_lk_ahds);
+
+ if (status)
+ break;
+
+ /* advance buffer past this record for next time around */
+ buf += record->len;
+ len -= record->len;
+ }
+
+ if (status)
+ ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "BAD Recv Trailer",
+ "", orig_buf, orig_len);
+
+ return status;
+}
+
+static int ath6kl_htc_rx_process_hdr(struct htc_target *target,
+ struct htc_packet *packet,
+ u32 *next_lkahds, int *n_lkahds)
+{
+ int status = 0;
+ u16 payload_len;
+ u32 lk_ahd;
+ struct htc_frame_hdr *htc_hdr = (struct htc_frame_hdr *)packet->buf;
+
+ if (n_lkahds != NULL)
+ *n_lkahds = 0;
+
+ ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "HTC Recv PKT", "htc ",
+ packet->buf, packet->act_len);
+
+ /*
+ * NOTE: we cannot assume the alignment of buf, so we use the safe
+ * macros to retrieve 16 bit fields.
+ */
+ payload_len = le16_to_cpu(get_unaligned(&htc_hdr->payld_len));
+
+ memcpy((u8 *)&lk_ahd, packet->buf, sizeof(lk_ahd));
+
+ if (packet->info.rx.rx_flags & HTC_RX_PKT_REFRESH_HDR) {
+ /*
+ * Refresh the expected header and the actual length as it
+ * was unknown when this packet was grabbed as part of the
+ * bundle.
+ */
+ packet->info.rx.exp_hdr = lk_ahd;
+ packet->act_len = payload_len + HTC_HDR_LENGTH;
+
+ /* validate the actual header that was refreshed */
+ if (packet->act_len > packet->buf_len) {
+ ath6kl_err("refreshed hdr payload len (%d) in bundled recv is invalid (hdr: 0x%X)\n",
+ payload_len, lk_ahd);
+ /*
+ * Limit this to max buffer just to print out some
+ * of the buffer.
+ */
+ packet->act_len = min(packet->act_len, packet->buf_len);
+ status = -ENOMEM;
+ goto fail_rx;
+ }
+
+ if (packet->endpoint != htc_hdr->eid) {
+ ath6kl_err("refreshed hdr ep (%d) does not match expected ep (%d)\n",
+ htc_hdr->eid, packet->endpoint);
+ status = -ENOMEM;
+ goto fail_rx;
+ }
+ }
+
+ if (lk_ahd != packet->info.rx.exp_hdr) {
+ ath6kl_err("%s(): lk_ahd mismatch! (pPkt:0x%p flags:0x%X)\n",
+ __func__, packet, packet->info.rx.rx_flags);
+ ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Expected Message lk_ahd",
+ "", &packet->info.rx.exp_hdr, 4);
+ ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Current Frame Header",
+ "", (u8 *)&lk_ahd, sizeof(lk_ahd));
+ status = -ENOMEM;
+ goto fail_rx;
+ }
+
+ if (htc_hdr->flags & HTC_FLG_RX_TRAILER) {
+ if (htc_hdr->ctrl[0] < sizeof(struct htc_record_hdr) ||
+ htc_hdr->ctrl[0] > payload_len) {
+ ath6kl_err("%s(): invalid hdr (payload len should be :%d, CB[0] is:%d)\n",
+ __func__, payload_len, htc_hdr->ctrl[0]);
+ status = -ENOMEM;
+ goto fail_rx;
+ }
+
+ if (packet->info.rx.rx_flags & HTC_RX_PKT_IGNORE_LOOKAHEAD) {
+ next_lkahds = NULL;
+ n_lkahds = NULL;
+ }
+
+ status = htc_proc_trailer(target, packet->buf + HTC_HDR_LENGTH
+ + payload_len - htc_hdr->ctrl[0],
+ htc_hdr->ctrl[0], next_lkahds,
+ n_lkahds, packet->endpoint);
+
+ if (status)
+ goto fail_rx;
+
+ packet->act_len -= htc_hdr->ctrl[0];
+ }
+
+ packet->buf += HTC_HDR_LENGTH;
+ packet->act_len -= HTC_HDR_LENGTH;
+
+fail_rx:
+ if (status)
+ ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "BAD HTC Recv PKT",
+ "", packet->buf,
+ packet->act_len < 256 ? packet->act_len : 256);
+ else {
+ if (packet->act_len > 0)
+ ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES,
+ "HTC - Application Msg", "",
+ packet->buf, packet->act_len);
+ }
+
+ return status;
+}
+
+static void ath6kl_htc_rx_complete(struct htc_endpoint *endpoint,
+ struct htc_packet *packet)
+{
+ ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
+ "htc calling ep %d recv callback on packet 0x%p\n",
+ endpoint->eid, packet);
+ endpoint->ep_cb.rx(endpoint->target, packet);
+}
+
+static int ath6kl_htc_rx_bundle(struct htc_target *target,
+ struct list_head *rxq,
+ struct list_head *sync_compq,
+ int *n_pkt_fetched, bool part_bundle)
+{
+ struct hif_scatter_req *scat_req;
+ struct htc_packet *packet;
+ int rem_space = target->max_rx_bndl_sz;
+ int n_scat_pkt, status = 0, i, len;
+
+ n_scat_pkt = get_queue_depth(rxq);
+ n_scat_pkt = min(n_scat_pkt, target->msg_per_bndl_max);
+
+ if ((get_queue_depth(rxq) - n_scat_pkt) > 0) {
+ /*
+ * We were forced to split this bundle receive operation
+ * all packets in this partial bundle must have their
+ * lookaheads ignored.
+ */
+ part_bundle = true;
+
+ /*
+ * This would only happen if the target ignored our max
+ * bundle limit.
+ */
+ ath6kl_warn("%s(): partial bundle detected num:%d , %d\n",
+ __func__, get_queue_depth(rxq), n_scat_pkt);
+ }
+
+ len = 0;
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
+ "%s(): (numpackets: %d , actual : %d)\n",
+ __func__, get_queue_depth(rxq), n_scat_pkt);
+
+ scat_req = hif_scatter_req_get(target->dev->ar);
+
+ if (scat_req == NULL)
+ goto fail_rx_pkt;
+
+ for (i = 0; i < n_scat_pkt; i++) {
+ int pad_len;
+
+ packet = list_first_entry(rxq, struct htc_packet, list);
+ list_del(&packet->list);
+
+ pad_len = CALC_TXRX_PADDED_LEN(target,
+ packet->act_len);
+
+ if ((rem_space - pad_len) < 0) {
+ list_add(&packet->list, rxq);
+ break;
+ }
+
+ rem_space -= pad_len;
+
+ if (part_bundle || (i < (n_scat_pkt - 1)))
+ /*
+ * Packet 0..n-1 cannot be checked for look-aheads
+ * since we are fetching a bundle the last packet
+ * however can have it's lookahead used
+ */
+ packet->info.rx.rx_flags |=
+ HTC_RX_PKT_IGNORE_LOOKAHEAD;
+
+ /* NOTE: 1 HTC packet per scatter entry */
+ scat_req->scat_list[i].buf = packet->buf;
+ scat_req->scat_list[i].len = pad_len;
+
+ packet->info.rx.rx_flags |= HTC_RX_PKT_PART_OF_BUNDLE;
+
+ list_add_tail(&packet->list, sync_compq);
+
+ WARN_ON(!scat_req->scat_list[i].len);
+ len += scat_req->scat_list[i].len;
+ }
+
+ scat_req->len = len;
+ scat_req->scat_entries = i;
+
+ status = ath6kldev_submit_scat_req(target->dev, scat_req, true);
+
+ if (!status)
+ *n_pkt_fetched = i;
+
+ /* free scatter request */
+ hif_scatter_req_add(target->dev->ar, scat_req);
+
+fail_rx_pkt:
+
+ return status;
+}
+
+static int ath6kl_htc_rx_process_packets(struct htc_target *target,
+ struct list_head *comp_pktq,
+ u32 lk_ahds[],
+ int *n_lk_ahd)
+{
+ struct htc_packet *packet, *tmp_pkt;
+ struct htc_endpoint *ep;
+ int status = 0;
+
+ list_for_each_entry_safe(packet, tmp_pkt, comp_pktq, list) {
+ list_del(&packet->list);
+ ep = &target->endpoint[packet->endpoint];
+
+ /* process header for each of the recv packet */
+ status = ath6kl_htc_rx_process_hdr(target, packet, lk_ahds,
+ n_lk_ahd);
+ if (status)
+ return status;
+
+ if (list_empty(comp_pktq)) {
+ /*
+ * Last packet's more packet flag is set
+ * based on the lookahead.
+ */
+ if (*n_lk_ahd > 0)
+ ath6kl_htc_rx_set_indicate(lk_ahds[0],
+ ep, packet);
+ } else
+ /*
+ * Packets in a bundle automatically have
+ * this flag set.
+ */
+ packet->info.rx.indicat_flags |=
+ HTC_RX_FLAGS_INDICATE_MORE_PKTS;
+
+ ath6kl_htc_rx_update_stats(ep, *n_lk_ahd);
+
+ if (packet->info.rx.rx_flags & HTC_RX_PKT_PART_OF_BUNDLE)
+ ep->ep_st.rx_bundl += 1;
+
+ ath6kl_htc_rx_complete(ep, packet);
+ }
+
+ return status;
+}
+
+static int ath6kl_htc_rx_fetch(struct htc_target *target,
+ struct list_head *rx_pktq,
+ struct list_head *comp_pktq)
+{
+ int fetched_pkts;
+ bool part_bundle = false;
+ int status = 0;
+
+ /* now go fetch the list of HTC packets */
+ while (!list_empty(rx_pktq)) {
+ fetched_pkts = 0;
+
+ if (target->rx_bndl_enable && (get_queue_depth(rx_pktq) > 1)) {
+ /*
+ * There are enough packets to attempt a
+ * bundle transfer and recv bundling is
+ * allowed.
+ */
+ status = ath6kl_htc_rx_bundle(target, rx_pktq,
+ comp_pktq,
+ &fetched_pkts,
+ part_bundle);
+ if (status)
+ return status;
+
+ if (!list_empty(rx_pktq))
+ part_bundle = true;
+ }
+
+ if (!fetched_pkts) {
+ struct htc_packet *packet;
+
+ packet = list_first_entry(rx_pktq, struct htc_packet,
+ list);
+
+ list_del(&packet->list);
+
+ /* fully synchronous */
+ packet->completion = NULL;
+
+ if (!list_empty(rx_pktq))
+ /*
+ * look_aheads in all packet
+ * except the last one in the
+ * bundle must be ignored
+ */
+ packet->info.rx.rx_flags |=
+ HTC_RX_PKT_IGNORE_LOOKAHEAD;
+
+ /* go fetch the packet */
+ status = ath6kl_htc_rx_packet(target, packet,
+ packet->act_len);
+ if (status)
+ return status;
+
+ list_add_tail(&packet->list, comp_pktq);
+ }
+ }
+
+ return status;
+}
+
+int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
+ u32 msg_look_ahead[], int *num_pkts)
+{
+ struct htc_packet *packets, *tmp_pkt;
+ struct htc_endpoint *endpoint;
+ struct list_head rx_pktq, comp_pktq;
+ int status = 0;
+ u32 look_aheads[HTC_HOST_MAX_MSG_PER_BUNDLE];
+ int num_look_ahead = 1;
+ enum htc_endpoint_id id;
+ int n_fetched = 0;
+
+ *num_pkts = 0;
+
+ /*
+ * On first entry copy the look_aheads into our temp array for
+ * processing
+ */
+ memcpy(look_aheads, msg_look_ahead, sizeof(look_aheads));
+
+ while (true) {
+
+ /*
+ * First lookahead sets the expected endpoint IDs for all
+ * packets in a bundle.
+ */
+ id = ((struct htc_frame_hdr *)&look_aheads[0])->eid;
+ endpoint = &target->endpoint[id];
+
+ if (id >= ENDPOINT_MAX) {
+ ath6kl_err("MsgPend, invalid endpoint in look-ahead: %d\n",
+ id);
+ status = -ENOMEM;
+ break;
+ }
+
+ INIT_LIST_HEAD(&rx_pktq);
+ INIT_LIST_HEAD(&comp_pktq);
+
+ /*
+ * Try to allocate as many HTC RX packets indicated by the
+ * look_aheads.
+ */
+ status = ath6kl_htc_rx_alloc(target, look_aheads,
+ num_look_ahead, endpoint,
+ &rx_pktq);
+ if (status)
+ break;
+
+ if (get_queue_depth(&rx_pktq) >= 2)
+ /*
+ * A recv bundle was detected, force IRQ status
+ * re-check again
+ */
+ target->chk_irq_status_cnt = 1;
+
+ n_fetched += get_queue_depth(&rx_pktq);
+
+ num_look_ahead = 0;
+
+ status = ath6kl_htc_rx_fetch(target, &rx_pktq, &comp_pktq);
+
+ if (!status)
+ ath6kl_htc_rx_chk_water_mark(endpoint);
+
+ /* Process fetched packets */
+ status = ath6kl_htc_rx_process_packets(target, &comp_pktq,
+ look_aheads,
+ &num_look_ahead);
+
+ if (!num_look_ahead || status)
+ break;
+
+ /*
+ * For SYNCH processing, if we get here, we are running
+ * through the loop again due to a detected lookahead. Set
+ * flag that we should re-check IRQ status registers again
+ * before leaving IRQ processing, this can net better
+ * performance in high throughput situations.
+ */
+ target->chk_irq_status_cnt = 1;
+ }
+
+ if (status) {
+ ath6kl_err("failed to get pending recv messages: %d\n",
+ status);
+ /*
+ * Cleanup any packets we allocated but didn't use to
+ * actually fetch any packets.
+ */
+ list_for_each_entry_safe(packets, tmp_pkt, &rx_pktq, list) {
+ list_del(&packets->list);
+ htc_reclaim_rxbuf(target, packets,
+ &target->endpoint[packets->endpoint]);
+ }
+
+ /* cleanup any packets in sync completion queue */
+ list_for_each_entry_safe(packets, tmp_pkt, &comp_pktq, list) {
+ list_del(&packets->list);
+ htc_reclaim_rxbuf(target, packets,
+ &target->endpoint[packets->endpoint]);
+ }
+
+ if (target->htc_flags & HTC_OP_STATE_STOPPING) {
+ ath6kl_warn("host is going to stop blocking receiver for htc_stop\n");
+ ath6kldev_rx_control(target->dev, false);
+ }
+ }
+
+ /*
+ * Before leaving, check to see if host ran out of buffers and
+ * needs to stop the receiver.
+ */
+ if (target->rx_st_flags & HTC_RECV_WAIT_BUFFERS) {
+ ath6kl_warn("host has no rx buffers blocking receiver to prevent overrun\n");
+ ath6kldev_rx_control(target->dev, false);
+ }
+ *num_pkts = n_fetched;
+
+ return status;
+}
+
+/*
+ * Synchronously wait for a control message from the target,
+ * This function is used at initialization time ONLY. At init messages
+ * on ENDPOINT 0 are expected.
+ */
+static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target)
+{
+ struct htc_packet *packet = NULL;
+ struct htc_frame_hdr *htc_hdr;
+ u32 look_ahead;
+
+ if (ath6kldev_poll_mboxmsg_rx(target->dev, &look_ahead,
+ HTC_TARGET_RESPONSE_TIMEOUT))
+ return NULL;
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
+ "htc_wait_for_ctrl_msg: look_ahead : 0x%X\n", look_ahead);
+
+ htc_hdr = (struct htc_frame_hdr *)&look_ahead;
+
+ if (htc_hdr->eid != ENDPOINT_0)
+ return NULL;
+
+ packet = htc_get_control_buf(target, false);
+
+ if (!packet)
+ return NULL;
+
+ packet->info.rx.rx_flags = 0;
+ packet->info.rx.exp_hdr = look_ahead;
+ packet->act_len = le16_to_cpu(htc_hdr->payld_len) + HTC_HDR_LENGTH;
+
+ if (packet->act_len > packet->buf_len)
+ goto fail_ctrl_rx;
+
+ /* we want synchronous operation */
+ packet->completion = NULL;
+
+ /* get the message from the device, this will block */
+ if (ath6kl_htc_rx_packet(target, packet, packet->act_len))
+ goto fail_ctrl_rx;
+
+ /* process receive header */
+ packet->status = ath6kl_htc_rx_process_hdr(target, packet, NULL, NULL);
+
+ if (packet->status) {
+ ath6kl_err("htc_wait_for_ctrl_msg, ath6kl_htc_rx_process_hdr failed (status = %d)\n",
+ packet->status);
+ goto fail_ctrl_rx;
+ }
+
+ return packet;
+
+fail_ctrl_rx:
+ if (packet != NULL) {
+ htc_rxpkt_reset(packet);
+ reclaim_rx_ctrl_buf(target, packet);
+ }
+
+ return NULL;
+}
+
+int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target,
+ struct list_head *pkt_queue)
+{
+ struct htc_endpoint *endpoint;
+ struct htc_packet *first_pkt;
+ bool rx_unblock = false;
+ int status = 0, depth;
+
+ if (list_empty(pkt_queue))
+ return -ENOMEM;
+
+ first_pkt = list_first_entry(pkt_queue, struct htc_packet, list);
+
+ if (first_pkt->endpoint >= ENDPOINT_MAX)
+ return status;
+
+ depth = get_queue_depth(pkt_queue);
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
+ "htc_add_rxbuf_multiple: ep id: %d, cnt:%d, len: %d\n",
+ first_pkt->endpoint, depth, first_pkt->buf_len);
+
+ endpoint = &target->endpoint[first_pkt->endpoint];
+
+ if (target->htc_flags & HTC_OP_STATE_STOPPING) {
+ struct htc_packet *packet, *tmp_pkt;
+
+ /* walk through queue and mark each one canceled */
+ list_for_each_entry_safe(packet, tmp_pkt, pkt_queue, list) {
+ packet->status = -ECANCELED;
+ list_del(&packet->list);
+ ath6kl_htc_rx_complete(endpoint, packet);
+ }
+
+ return status;
+ }
+
+ spin_lock_bh(&target->rx_lock);
+
+ list_splice_tail_init(pkt_queue, &endpoint->rx_bufq);
+
+ /* check if we are blocked waiting for a new buffer */
+ if (target->rx_st_flags & HTC_RECV_WAIT_BUFFERS) {
+ if (target->ep_waiting == first_pkt->endpoint) {
+ ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
+ "receiver was blocked on ep:%d, unblocking.\n",
+ target->ep_waiting);
+ target->rx_st_flags &= ~HTC_RECV_WAIT_BUFFERS;
+ target->ep_waiting = ENDPOINT_MAX;
+ rx_unblock = true;
+ }
+ }
+
+ spin_unlock_bh(&target->rx_lock);
+
+ if (rx_unblock && !(target->htc_flags & HTC_OP_STATE_STOPPING))
+ /* TODO : implement a buffer threshold count? */
+ ath6kldev_rx_control(target->dev, true);
+
+ return status;
+}
+
+void ath6kl_htc_flush_rx_buf(struct htc_target *target)
+{
+ struct htc_endpoint *endpoint;
+ struct htc_packet *packet, *tmp_pkt;
+ int i;
+
+ for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
+ endpoint = &target->endpoint[i];
+ if (!endpoint->svc_id)
+ /* not in use.. */
+ continue;
+
+ spin_lock_bh(&target->rx_lock);
+ list_for_each_entry_safe(packet, tmp_pkt,
+ &endpoint->rx_bufq, list) {
+ list_del(&packet->list);
+ spin_unlock_bh(&target->rx_lock);
+ ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
+ "flushing rx pkt:0x%p, len:%d, ep:%d\n",
+ packet, packet->buf_len,
+ packet->endpoint);
+ dev_kfree_skb(packet->pkt_cntxt);
+ spin_lock_bh(&target->rx_lock);
+ }
+ spin_unlock_bh(&target->rx_lock);
+ }
+}
+
+int ath6kl_htc_conn_service(struct htc_target *target,
+ struct htc_service_connect_req *conn_req,
+ struct htc_service_connect_resp *conn_resp)
+{
+ struct htc_packet *rx_pkt = NULL;
+ struct htc_packet *tx_pkt = NULL;
+ struct htc_conn_service_resp *resp_msg;
+ struct htc_conn_service_msg *conn_msg;
+ struct htc_endpoint *endpoint;
+ enum htc_endpoint_id assigned_ep = ENDPOINT_MAX;
+ unsigned int max_msg_sz = 0;
+ int status = 0;
+
+ ath6kl_dbg(ATH6KL_DBG_TRC,
+ "htc_conn_service, target:0x%p service id:0x%X\n",
+ target, conn_req->svc_id);
+
+ if (conn_req->svc_id == HTC_CTRL_RSVD_SVC) {
+ /* special case for pseudo control service */
+ assigned_ep = ENDPOINT_0;
+ max_msg_sz = HTC_MAX_CTRL_MSG_LEN;
+ } else {
+ /* allocate a packet to send to the target */
+ tx_pkt = htc_get_control_buf(target, true);
+
+ if (!tx_pkt)
+ return -ENOMEM;
+
+ conn_msg = (struct htc_conn_service_msg *)tx_pkt->buf;
+ memset(conn_msg, 0, sizeof(*conn_msg));
+ conn_msg->msg_id = cpu_to_le16(HTC_MSG_CONN_SVC_ID);
+ conn_msg->svc_id = cpu_to_le16(conn_req->svc_id);
+ conn_msg->conn_flags = cpu_to_le16(conn_req->conn_flags);
+
+ set_htc_pkt_info(tx_pkt, NULL, (u8 *) conn_msg,
+ sizeof(*conn_msg) + conn_msg->svc_meta_len,
+ ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG);
+
+ /* we want synchronous operation */
+ tx_pkt->completion = NULL;
+ ath6kl_htc_tx_prep_pkt(tx_pkt, 0, 0, 0);
+ status = ath6kl_htc_tx_issue(target, tx_pkt);
+
+ if (status)
+ goto fail_tx;
+
+ /* wait for response */
+ rx_pkt = htc_wait_for_ctrl_msg(target);
+
+ if (!rx_pkt) {
+ status = -ENOMEM;
+ goto fail_tx;
+ }
+
+ resp_msg = (struct htc_conn_service_resp *)rx_pkt->buf;
+
+ if ((le16_to_cpu(resp_msg->msg_id) != HTC_MSG_CONN_SVC_RESP_ID)
+ || (rx_pkt->act_len < sizeof(*resp_msg))) {
+ status = -ENOMEM;
+ goto fail_tx;
+ }
+
+ conn_resp->resp_code = resp_msg->status;
+ /* check response status */
+ if (resp_msg->status != HTC_SERVICE_SUCCESS) {
+ ath6kl_err("target failed service 0x%X connect request (status:%d)\n",
+ resp_msg->svc_id, resp_msg->status);
+ status = -ENOMEM;
+ goto fail_tx;
+ }
+
+ assigned_ep = (enum htc_endpoint_id)resp_msg->eid;
+ max_msg_sz = le16_to_cpu(resp_msg->max_msg_sz);
+ }
+
+ if (assigned_ep >= ENDPOINT_MAX || !max_msg_sz) {
+ status = -ENOMEM;
+ goto fail_tx;
+ }
+
+ endpoint = &target->endpoint[assigned_ep];
+ endpoint->eid = assigned_ep;
+ if (endpoint->svc_id) {
+ status = -ENOMEM;
+ goto fail_tx;
+ }
+
+ /* return assigned endpoint to caller */
+ conn_resp->endpoint = assigned_ep;
+ conn_resp->len_max = max_msg_sz;
+
+ /* setup the endpoint */
+
+ /* this marks the endpoint in use */
+ endpoint->svc_id = conn_req->svc_id;
+
+ endpoint->max_txq_depth = conn_req->max_txq_depth;
+ endpoint->len_max = max_msg_sz;
+ endpoint->ep_cb = conn_req->ep_cb;
+ endpoint->cred_dist.svc_id = conn_req->svc_id;
+ endpoint->cred_dist.htc_rsvd = endpoint;
+ endpoint->cred_dist.endpoint = assigned_ep;
+ endpoint->cred_dist.cred_sz = target->tgt_cred_sz;
+
+ if (conn_req->max_rxmsg_sz) {
+ /*
+ * Override cred_per_msg calculation, this optimizes
+ * the credit-low indications since the host will actually
+ * issue smaller messages in the Send path.
+ */
+ if (conn_req->max_rxmsg_sz > max_msg_sz) {
+ status = -ENOMEM;
+ goto fail_tx;
+ }
+ endpoint->cred_dist.cred_per_msg =
+ conn_req->max_rxmsg_sz / target->tgt_cred_sz;
+ } else
+ endpoint->cred_dist.cred_per_msg =
+ max_msg_sz / target->tgt_cred_sz;
+
+ if (!endpoint->cred_dist.cred_per_msg)
+ endpoint->cred_dist.cred_per_msg = 1;
+
+ /* save local connection flags */
+ endpoint->conn_flags = conn_req->flags;
+
+fail_tx:
+ if (tx_pkt)
+ htc_reclaim_txctrl_buf(target, tx_pkt);
+
+ if (rx_pkt) {
+ htc_rxpkt_reset(rx_pkt);
+ reclaim_rx_ctrl_buf(target, rx_pkt);
+ }
+
+ return status;
+}
+
+static void reset_ep_state(struct htc_target *target)
+{
+ struct htc_endpoint *endpoint;
+ int i;
+
+ for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
+ endpoint = &target->endpoint[i];
+ memset(&endpoint->cred_dist, 0, sizeof(endpoint->cred_dist));
+ endpoint->svc_id = 0;
+ endpoint->len_max = 0;
+ endpoint->max_txq_depth = 0;
+ memset(&endpoint->ep_st, 0,
+ sizeof(endpoint->ep_st));
+ INIT_LIST_HEAD(&endpoint->rx_bufq);
+ INIT_LIST_HEAD(&endpoint->txq);
+ endpoint->target = target;
+ }
+
+ /* reset distribution list */
+ INIT_LIST_HEAD(&target->cred_dist_list);
+}
+
+int ath6kl_htc_get_rxbuf_num(struct htc_target *target,
+ enum htc_endpoint_id endpoint)
+{
+ int num;
+
+ spin_lock_bh(&target->rx_lock);
+ num = get_queue_depth(&(target->endpoint[endpoint].rx_bufq));
+ spin_unlock_bh(&target->rx_lock);
+ return num;
+}
+
+static void htc_setup_msg_bndl(struct htc_target *target)
+{
+ /* limit what HTC can handle */
+ target->msg_per_bndl_max = min(HTC_HOST_MAX_MSG_PER_BUNDLE,
+ target->msg_per_bndl_max);
+
+ if (ath6kl_hif_enable_scatter(target->dev->ar)) {
+ target->msg_per_bndl_max = 0;
+ return;
+ }
+
+ /* limit bundle what the device layer can handle */
+ target->msg_per_bndl_max = min(target->max_scat_entries,
+ target->msg_per_bndl_max);
+
+ ath6kl_dbg(ATH6KL_DBG_TRC,
+ "htc bundling allowed. max msg per htc bundle: %d\n",
+ target->msg_per_bndl_max);
+
+ /* Max rx bundle size is limited by the max tx bundle size */
+ target->max_rx_bndl_sz = target->max_xfer_szper_scatreq;
+ /* Max tx bundle size if limited by the extended mbox address range */
+ target->max_tx_bndl_sz = min(HIF_MBOX0_EXT_WIDTH,
+ target->max_xfer_szper_scatreq);
+
+ ath6kl_dbg(ATH6KL_DBG_ANY, "max recv: %d max send: %d\n",
+ target->max_rx_bndl_sz, target->max_tx_bndl_sz);
+
+ if (target->max_tx_bndl_sz)
+ target->tx_bndl_enable = true;
+
+ if (target->max_rx_bndl_sz)
+ target->rx_bndl_enable = true;
+
+ if ((target->tgt_cred_sz % target->block_sz) != 0) {
+ ath6kl_warn("credit size: %d is not block aligned! Disabling send bundling\n",
+ target->tgt_cred_sz);
+
+ /*
+ * Disallow send bundling since the credit size is
+ * not aligned to a block size the I/O block
+ * padding will spill into the next credit buffer
+ * which is fatal.
+ */
+ target->tx_bndl_enable = false;
+ }
+}
+
+int ath6kl_htc_wait_target(struct htc_target *target)
+{
+ struct htc_packet *packet = NULL;
+ struct htc_ready_ext_msg *rdy_msg;
+ struct htc_service_connect_req connect;
+ struct htc_service_connect_resp resp;
+ int status;
+
+ /* we should be getting 1 control message that the target is ready */
+ packet = htc_wait_for_ctrl_msg(target);
+
+ if (!packet)
+ return -ENOMEM;
+
+ /* we controlled the buffer creation so it's properly aligned */
+ rdy_msg = (struct htc_ready_ext_msg *)packet->buf;
+
+ if ((le16_to_cpu(rdy_msg->ver2_0_info.msg_id) != HTC_MSG_READY_ID) ||
+ (packet->act_len < sizeof(struct htc_ready_msg))) {
+ status = -ENOMEM;
+ goto fail_wait_target;
+ }
+
+ if (!rdy_msg->ver2_0_info.cred_cnt || !rdy_msg->ver2_0_info.cred_sz) {
+ status = -ENOMEM;
+ goto fail_wait_target;
+ }
+
+ target->tgt_creds = le16_to_cpu(rdy_msg->ver2_0_info.cred_cnt);
+ target->tgt_cred_sz = le16_to_cpu(rdy_msg->ver2_0_info.cred_sz);
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
+ "target ready: credits: %d credit size: %d\n",
+ target->tgt_creds, target->tgt_cred_sz);
+
+ /* check if this is an extended ready message */
+ if (packet->act_len >= sizeof(struct htc_ready_ext_msg)) {
+ /* this is an extended message */
+ target->htc_tgt_ver = rdy_msg->htc_ver;
+ target->msg_per_bndl_max = rdy_msg->msg_per_htc_bndl;
+ } else {
+ /* legacy */
+ target->htc_tgt_ver = HTC_VERSION_2P0;
+ target->msg_per_bndl_max = 0;
+ }
+
+ ath6kl_dbg(ATH6KL_DBG_TRC, "using htc protocol version : %s (%d)\n",
+ (target->htc_tgt_ver == HTC_VERSION_2P0) ? "2.0" : ">= 2.1",
+ target->htc_tgt_ver);
+
+ if (target->msg_per_bndl_max > 0)
+ htc_setup_msg_bndl(target);
+
+ /* setup our pseudo HTC control endpoint connection */
+ memset(&connect, 0, sizeof(connect));
+ memset(&resp, 0, sizeof(resp));
+ connect.ep_cb.rx = htc_ctrl_rx;
+ connect.ep_cb.rx_refill = NULL;
+ connect.ep_cb.tx_full = NULL;
+ connect.max_txq_depth = NUM_CONTROL_BUFFERS;
+ connect.svc_id = HTC_CTRL_RSVD_SVC;
+
+ /* connect fake service */
+ status = ath6kl_htc_conn_service((void *)target, &connect, &resp);
+
+ if (status)
+ ath6kl_hif_cleanup_scatter(target->dev->ar);
+
+fail_wait_target:
+ if (packet) {
+ htc_rxpkt_reset(packet);
+ reclaim_rx_ctrl_buf(target, packet);
+ }
+
+ return status;
+}
+
+/*
+ * Start HTC, enable interrupts and let the target know
+ * host has finished setup.
+ */
+int ath6kl_htc_start(struct htc_target *target)
+{
+ struct htc_packet *packet;
+ int status;
+
+ /* Disable interrupts at the chip level */
+ ath6kldev_disable_intrs(target->dev);
+
+ target->htc_flags = 0;
+ target->rx_st_flags = 0;
+
+ /* Push control receive buffers into htc control endpoint */
+ while ((packet = htc_get_control_buf(target, false)) != NULL) {
+ status = htc_add_rxbuf(target, packet);
+ if (status)
+ return status;
+ }
+
+ /* NOTE: the first entry in the distribution list is ENDPOINT_0 */
+ ath6k_credit_init(target->cred_dist_cntxt, &target->cred_dist_list,
+ target->tgt_creds);
+
+ dump_cred_dist_stats(target);
+
+ /* Indicate to the target of the setup completion */
+ status = htc_setup_tx_complete(target);
+
+ if (status)
+ return status;
+
+ /* unmask interrupts */
+ status = ath6kldev_unmask_intrs(target->dev);
+
+ if (status)
+ ath6kl_htc_stop(target);
+
+ return status;
+}
+
+/* htc_stop: stop interrupt reception, and flush all queued buffers */
+void ath6kl_htc_stop(struct htc_target *target)
+{
+ spin_lock_bh(&target->htc_lock);
+ target->htc_flags |= HTC_OP_STATE_STOPPING;
+ spin_unlock_bh(&target->htc_lock);
+
+ /*
+ * Masking interrupts is a synchronous operation, when this
+ * function returns all pending HIF I/O has completed, we can
+ * safely flush the queues.
+ */
+ ath6kldev_mask_intrs(target->dev);
+
+ ath6kl_htc_flush_txep_all(target);
+
+ ath6kl_htc_flush_rx_buf(target);
+
+ reset_ep_state(target);
+}
+
+void *ath6kl_htc_create(struct ath6kl *ar)
+{
+ struct htc_target *target = NULL;
+ struct htc_packet *packet;
+ int status = 0, i = 0;
+ u32 block_size, ctrl_bufsz;
+
+ target = kzalloc(sizeof(*target), GFP_KERNEL);
+ if (!target) {
+ ath6kl_err("unable to allocate memory\n");
+ return NULL;
+ }
+
+ target->dev = kzalloc(sizeof(*target->dev), GFP_KERNEL);
+ if (!target->dev) {
+ ath6kl_err("unable to allocate memory\n");
+ status = -ENOMEM;
+ goto fail_create_htc;
+ }
+
+ spin_lock_init(&target->htc_lock);
+ spin_lock_init(&target->rx_lock);
+ spin_lock_init(&target->tx_lock);
+
+ INIT_LIST_HEAD(&target->free_ctrl_txbuf);
+ INIT_LIST_HEAD(&target->free_ctrl_rxbuf);
+ INIT_LIST_HEAD(&target->cred_dist_list);
+
+ target->dev->ar = ar;
+ target->dev->htc_cnxt = target;
+ target->ep_waiting = ENDPOINT_MAX;
+
+ reset_ep_state(target);
+
+ status = ath6kldev_setup(target->dev);
+
+ if (status)
+ goto fail_create_htc;
+
+ block_size = ar->mbox_info.block_size;
+
+ ctrl_bufsz = (block_size > HTC_MAX_CTRL_MSG_LEN) ?
+ (block_size + HTC_HDR_LENGTH) :
+ (HTC_MAX_CTRL_MSG_LEN + HTC_HDR_LENGTH);
+
+ for (i = 0; i < NUM_CONTROL_BUFFERS; i++) {
+ packet = kzalloc(sizeof(*packet), GFP_KERNEL);
+ if (!packet)
+ break;
+
+ packet->buf_start = kzalloc(ctrl_bufsz, GFP_KERNEL);
+ if (!packet->buf_start) {
+ kfree(packet);
+ break;
+ }
+
+ packet->buf_len = ctrl_bufsz;
+ if (i < NUM_CONTROL_RX_BUFFERS) {
+ packet->act_len = 0;
+ packet->buf = packet->buf_start;
+ packet->endpoint = ENDPOINT_0;
+ list_add_tail(&packet->list, &target->free_ctrl_rxbuf);
+ } else
+ list_add_tail(&packet->list, &target->free_ctrl_txbuf);
+ }
+
+fail_create_htc:
+ if (i != NUM_CONTROL_BUFFERS || status) {
+ if (target) {
+ ath6kl_htc_cleanup(target);
+ target = NULL;
+ }
+ }
+
+ return target;
+}
+
+/* cleanup the HTC instance */
+void ath6kl_htc_cleanup(struct htc_target *target)
+{
+ struct htc_packet *packet, *tmp_packet;
+
+ ath6kl_hif_cleanup_scatter(target->dev->ar);
+
+ list_for_each_entry_safe(packet, tmp_packet,
+ &target->free_ctrl_txbuf, list) {
+ list_del(&packet->list);
+ kfree(packet->buf_start);
+ kfree(packet);
+ }
+
+ list_for_each_entry_safe(packet, tmp_packet,
+ &target->free_ctrl_rxbuf, list) {
+ list_del(&packet->list);
+ kfree(packet->buf_start);
+ kfree(packet);
+ }
+
+ kfree(target->dev);
+ kfree(target);
+}
diff --git a/drivers/net/wireless/ath/ath6kl/htc.h b/drivers/net/wireless/ath/ath6kl/htc.h
new file mode 100644
index 000000000000..8ce0c2c07ded
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/htc.h
@@ -0,0 +1,607 @@
+/*
+ * Copyright (c) 2004-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef HTC_H
+#define HTC_H
+
+#include "common.h"
+
+/* frame header flags */
+
+/* send direction */
+#define HTC_FLAGS_NEED_CREDIT_UPDATE (1 << 0)
+#define HTC_FLAGS_SEND_BUNDLE (1 << 1)
+
+/* receive direction */
+#define HTC_FLG_RX_UNUSED (1 << 0)
+#define HTC_FLG_RX_TRAILER (1 << 1)
+/* Bundle count maske and shift */
+#define HTC_FLG_RX_BNDL_CNT (0xF0)
+#define HTC_FLG_RX_BNDL_CNT_S 4
+
+#define HTC_HDR_LENGTH (sizeof(struct htc_frame_hdr))
+#define HTC_MAX_PAYLOAD_LENGTH (4096 - sizeof(struct htc_frame_hdr))
+
+/* HTC control message IDs */
+
+#define HTC_MSG_READY_ID 1
+#define HTC_MSG_CONN_SVC_ID 2
+#define HTC_MSG_CONN_SVC_RESP_ID 3
+#define HTC_MSG_SETUP_COMPLETE_ID 4
+#define HTC_MSG_SETUP_COMPLETE_EX_ID 5
+
+#define HTC_MAX_CTRL_MSG_LEN 256
+
+#define HTC_VERSION_2P0 0x00
+#define HTC_VERSION_2P1 0x01
+
+#define HTC_SERVICE_META_DATA_MAX_LENGTH 128
+
+#define HTC_CONN_FLGS_THRESH_LVL_QUAT 0x0
+#define HTC_CONN_FLGS_THRESH_LVL_HALF 0x1
+#define HTC_CONN_FLGS_THRESH_LVL_THREE_QUAT 0x2
+#define HTC_CONN_FLGS_REDUCE_CRED_DRIB 0x4
+#define HTC_CONN_FLGS_THRESH_MASK 0x3
+
+/* connect response status codes */
+#define HTC_SERVICE_SUCCESS 0
+#define HTC_SERVICE_NOT_FOUND 1
+#define HTC_SERVICE_FAILED 2
+
+/* no resources (i.e. no more endpoints) */
+#define HTC_SERVICE_NO_RESOURCES 3
+
+/* specific service is not allowing any more endpoints */
+#define HTC_SERVICE_NO_MORE_EP 4
+
+/* report record IDs */
+#define HTC_RECORD_NULL 0
+#define HTC_RECORD_CREDITS 1
+#define HTC_RECORD_LOOKAHEAD 2
+#define HTC_RECORD_LOOKAHEAD_BUNDLE 3
+
+#define HTC_SETUP_COMP_FLG_RX_BNDL_EN (1 << 0)
+
+#define MAKE_SERVICE_ID(group, index) \
+ (int)(((int)group << 8) | (int)(index))
+
+/* NOTE: service ID of 0x0000 is reserved and should never be used */
+#define HTC_CTRL_RSVD_SVC MAKE_SERVICE_ID(RSVD_SERVICE_GROUP, 1)
+#define WMI_CONTROL_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 0)
+#define WMI_DATA_BE_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 1)
+#define WMI_DATA_BK_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 2)
+#define WMI_DATA_VI_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 3)
+#define WMI_DATA_VO_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 4)
+#define WMI_MAX_SERVICES 5
+
+/* reserved and used to flush ALL packets */
+#define HTC_TX_PACKET_TAG_ALL 0
+#define HTC_SERVICE_TX_PACKET_TAG 1
+#define HTC_TX_PACKET_TAG_USER_DEFINED (HTC_SERVICE_TX_PACKET_TAG + 9)
+
+/* more packets on this endpoint are being fetched */
+#define HTC_RX_FLAGS_INDICATE_MORE_PKTS (1 << 0)
+
+/* TODO.. for BMI */
+#define ENDPOINT1 0
+/* TODO -remove me, but we have to fix BMI first */
+#define HTC_MAILBOX_NUM_MAX 4
+
+/* enable send bundle padding for this endpoint */
+#define HTC_FLGS_TX_BNDL_PAD_EN (1 << 0)
+#define HTC_EP_ACTIVE ((u32) (1u << 31))
+
+/* HTC operational parameters */
+#define HTC_TARGET_RESPONSE_TIMEOUT 2000 /* in ms */
+#define HTC_TARGET_DEBUG_INTR_MASK 0x01
+#define HTC_TARGET_CREDIT_INTR_MASK 0xF0
+
+#define HTC_HOST_MAX_MSG_PER_BUNDLE 8
+#define HTC_MIN_HTC_MSGS_TO_BUNDLE 2
+
+/* packet flags */
+
+#define HTC_RX_PKT_IGNORE_LOOKAHEAD (1 << 0)
+#define HTC_RX_PKT_REFRESH_HDR (1 << 1)
+#define HTC_RX_PKT_PART_OF_BUNDLE (1 << 2)
+#define HTC_RX_PKT_NO_RECYCLE (1 << 3)
+
+#define NUM_CONTROL_BUFFERS 8
+#define NUM_CONTROL_TX_BUFFERS 2
+#define NUM_CONTROL_RX_BUFFERS (NUM_CONTROL_BUFFERS - NUM_CONTROL_TX_BUFFERS)
+
+#define HTC_RECV_WAIT_BUFFERS (1 << 0)
+#define HTC_OP_STATE_STOPPING (1 << 0)
+
+/*
+ * The frame header length and message formats defined herein were selected
+ * to accommodate optimal alignment for target processing. This reduces
+ * code size and improves performance. Any changes to the header length may
+ * alter the alignment and cause exceptions on the target. When adding to
+ * the messagestructures insure that fields are properly aligned.
+ */
+
+/* HTC frame header
+ *
+ * NOTE: do not remove or re-arrange the fields, these are minimally
+ * required to take advantage of 4-byte lookaheads in some hardware
+ * implementations.
+ */
+struct htc_frame_hdr {
+ u8 eid;
+ u8 flags;
+
+ /* length of data (including trailer) that follows the header */
+ __le16 payld_len;
+
+ /* end of 4-byte lookahead */
+
+ u8 ctrl[2];
+} __packed;
+
+/* HTC ready message */
+struct htc_ready_msg {
+ __le16 msg_id;
+ __le16 cred_cnt;
+ __le16 cred_sz;
+ u8 max_ep;
+ u8 pad;
+} __packed;
+
+/* extended HTC ready message */
+struct htc_ready_ext_msg {
+ struct htc_ready_msg ver2_0_info;
+ u8 htc_ver;
+ u8 msg_per_htc_bndl;
+} __packed;
+
+/* connect service */
+struct htc_conn_service_msg {
+ __le16 msg_id;
+ __le16 svc_id;
+ __le16 conn_flags;
+ u8 svc_meta_len;
+ u8 pad;
+} __packed;
+
+/* connect response */
+struct htc_conn_service_resp {
+ __le16 msg_id;
+ __le16 svc_id;
+ u8 status;
+ u8 eid;
+ __le16 max_msg_sz;
+ u8 svc_meta_len;
+ u8 pad;
+} __packed;
+
+struct htc_setup_comp_msg {
+ __le16 msg_id;
+} __packed;
+
+/* extended setup completion message */
+struct htc_setup_comp_ext_msg {
+ __le16 msg_id;
+ __le32 flags;
+ u8 msg_per_rxbndl;
+ u8 Rsvd[3];
+} __packed;
+
+struct htc_record_hdr {
+ u8 rec_id;
+ u8 len;
+} __packed;
+
+struct htc_credit_report {
+ u8 eid;
+ u8 credits;
+} __packed;
+
+/*
+ * NOTE: The lk_ahd array is guarded by a pre_valid
+ * and Post Valid guard bytes. The pre_valid bytes must
+ * equal the inverse of the post_valid byte.
+ */
+struct htc_lookahead_report {
+ u8 pre_valid;
+ u8 lk_ahd[4];
+ u8 post_valid;
+} __packed;
+
+struct htc_bundle_lkahd_rpt {
+ u8 lk_ahd[4];
+} __packed;
+
+/* Current service IDs */
+
+enum htc_service_grp_ids {
+ RSVD_SERVICE_GROUP = 0,
+ WMI_SERVICE_GROUP = 1,
+
+ HTC_TEST_GROUP = 254,
+ HTC_SERVICE_GROUP_LAST = 255
+};
+
+/* ------ endpoint IDS ------ */
+
+enum htc_endpoint_id {
+ ENDPOINT_UNUSED = -1,
+ ENDPOINT_0 = 0,
+ ENDPOINT_1 = 1,
+ ENDPOINT_2 = 2,
+ ENDPOINT_3,
+ ENDPOINT_4,
+ ENDPOINT_5,
+ ENDPOINT_6,
+ ENDPOINT_7,
+ ENDPOINT_8,
+ ENDPOINT_MAX,
+};
+
+struct htc_tx_packet_info {
+ u16 tag;
+ int cred_used;
+ u8 flags;
+ int seqno;
+};
+
+struct htc_rx_packet_info {
+ u32 exp_hdr;
+ u32 rx_flags;
+ u32 indicat_flags;
+};
+
+struct htc_target;
+
+/* wrapper around endpoint-specific packets */
+struct htc_packet {
+ struct list_head list;
+
+ /* caller's per packet specific context */
+ void *pkt_cntxt;
+
+ /*
+ * the true buffer start , the caller can store the real
+ * buffer start here. In receive callbacks, the HTC layer
+ * sets buf to the start of the payload past the header.
+ * This field allows the caller to reset buf when it recycles
+ * receive packets back to HTC.
+ */
+ u8 *buf_start;
+
+ /*
+ * Pointer to the start of the buffer. In the transmit
+ * direction this points to the start of the payload. In the
+ * receive direction, however, the buffer when queued up
+ * points to the start of the HTC header but when returned
+ * to the caller points to the start of the payload
+ */
+ u8 *buf;
+ u32 buf_len;
+
+ /* actual length of payload */
+ u32 act_len;
+
+ /* endpoint that this packet was sent/recv'd from */
+ enum htc_endpoint_id endpoint;
+
+ /* completion status */
+
+ int status;
+ union {
+ struct htc_tx_packet_info tx;
+ struct htc_rx_packet_info rx;
+ } info;
+
+ void (*completion) (struct htc_target *, struct htc_packet *);
+ struct htc_target *context;
+};
+
+enum htc_send_full_action {
+ HTC_SEND_FULL_KEEP = 0,
+ HTC_SEND_FULL_DROP = 1,
+};
+
+struct htc_ep_callbacks {
+ void (*rx) (struct htc_target *, struct htc_packet *);
+ void (*rx_refill) (struct htc_target *, enum htc_endpoint_id endpoint);
+ enum htc_send_full_action (*tx_full) (struct htc_target *,
+ struct htc_packet *);
+ struct htc_packet *(*rx_allocthresh) (struct htc_target *,
+ enum htc_endpoint_id, int);
+ int rx_alloc_thresh;
+ int rx_refill_thresh;
+};
+
+/* service connection information */
+struct htc_service_connect_req {
+ u16 svc_id;
+ u16 conn_flags;
+ struct htc_ep_callbacks ep_cb;
+ int max_txq_depth;
+ u32 flags;
+ unsigned int max_rxmsg_sz;
+};
+
+/* service connection response information */
+struct htc_service_connect_resp {
+ u8 buf_len;
+ u8 act_len;
+ enum htc_endpoint_id endpoint;
+ unsigned int len_max;
+ u8 resp_code;
+};
+
+/* endpoint distributionstructure */
+struct htc_endpoint_credit_dist {
+ struct list_head list;
+
+ /* Service ID (set by HTC) */
+ u16 svc_id;
+
+ /* endpoint for this distributionstruct (set by HTC) */
+ enum htc_endpoint_id endpoint;
+
+ u32 dist_flags;
+
+ /*
+ * credits for normal operation, anything above this
+ * indicates the endpoint is over-subscribed.
+ */
+ int cred_norm;
+
+ /* floor for credit distribution */
+ int cred_min;
+
+ int cred_assngd;
+
+ /* current credits available */
+ int credits;
+
+ /*
+ * pending credits to distribute on this endpoint, this
+ * is set by HTC when credit reports arrive. The credit
+ * distribution functions sets this to zero when it distributes
+ * the credits.
+ */
+ int cred_to_dist;
+
+ /*
+ * the number of credits that the current pending TX packet needs
+ * to transmit. This is set by HTC when endpoint needs credits in
+ * order to transmit.
+ */
+ int seek_cred;
+
+ /* size in bytes of each credit */
+ int cred_sz;
+
+ /* credits required for a maximum sized messages */
+ int cred_per_msg;
+
+ /* reserved for HTC use */
+ void *htc_rsvd;
+
+ /*
+ * current depth of TX queue , i.e. messages waiting for credits
+ * This field is valid only when HTC_CREDIT_DIST_ACTIVITY_CHANGE
+ * or HTC_CREDIT_DIST_SEND_COMPLETE is indicated on an endpoint
+ * that has non-zero credits to recover.
+ */
+ int txq_depth;
+};
+
+/*
+ * credit distibution code that is passed into the distrbution function,
+ * there are mandatory and optional codes that must be handled
+ */
+enum htc_credit_dist_reason {
+ HTC_CREDIT_DIST_SEND_COMPLETE = 0,
+ HTC_CREDIT_DIST_ACTIVITY_CHANGE = 1,
+ HTC_CREDIT_DIST_SEEK_CREDITS,
+};
+
+struct htc_credit_state_info {
+ int total_avail_credits;
+ int cur_free_credits;
+ struct list_head lowestpri_ep_dist;
+};
+
+/* endpoint statistics */
+struct htc_endpoint_stats {
+ /*
+ * number of times the host set the credit-low flag in a send
+ * message on this endpoint
+ */
+ u32 cred_low_indicate;
+
+ u32 tx_issued;
+ u32 tx_pkt_bundled;
+ u32 tx_bundles;
+ u32 tx_dropped;
+
+ /* running count of total credit reports received for this endpoint */
+ u32 tx_cred_rpt;
+
+ /* credit reports received from this endpoint's RX packets */
+ u32 cred_rpt_from_rx;
+
+ /* credit reports received from RX packets of other endpoints */
+ u32 cred_rpt_from_other;
+
+ /* credit reports received from endpoint 0 RX packets */
+ u32 cred_rpt_ep0;
+
+ /* count of credits received via Rx packets on this endpoint */
+ u32 cred_from_rx;
+
+ /* count of credits received via another endpoint */
+ u32 cred_from_other;
+
+ /* count of credits received via another endpoint */
+ u32 cred_from_ep0;
+
+ /* count of consummed credits */
+ u32 cred_cosumd;
+
+ /* count of credits returned */
+ u32 cred_retnd;
+
+ u32 rx_pkts;
+
+ /* count of lookahead records found in Rx msg */
+ u32 rx_lkahds;
+
+ /* count of recv packets received in a bundle */
+ u32 rx_bundl;
+
+ /* count of number of bundled lookaheads */
+ u32 rx_bundle_lkahd;
+
+ /* count of the number of bundle indications from the HTC header */
+ u32 rx_bundle_from_hdr;
+
+ /* the number of times the recv allocation threshold was hit */
+ u32 rx_alloc_thresh_hit;
+
+ /* total number of bytes */
+ u32 rxalloc_thresh_byte;
+};
+
+struct htc_endpoint {
+ enum htc_endpoint_id eid;
+ u16 svc_id;
+ struct list_head txq;
+ struct list_head rx_bufq;
+ struct htc_endpoint_credit_dist cred_dist;
+ struct htc_ep_callbacks ep_cb;
+ int max_txq_depth;
+ int len_max;
+ int tx_proc_cnt;
+ int rx_proc_cnt;
+ struct htc_target *target;
+ u8 seqno;
+ u32 conn_flags;
+ struct htc_endpoint_stats ep_st;
+};
+
+struct htc_control_buffer {
+ struct htc_packet packet;
+ u8 *buf;
+};
+
+struct ath6kl_device;
+
+/* our HTC target state */
+struct htc_target {
+ struct htc_endpoint endpoint[ENDPOINT_MAX];
+ struct list_head cred_dist_list;
+ struct list_head free_ctrl_txbuf;
+ struct list_head free_ctrl_rxbuf;
+ struct htc_credit_state_info *cred_dist_cntxt;
+ int tgt_creds;
+ unsigned int tgt_cred_sz;
+ spinlock_t htc_lock;
+ spinlock_t rx_lock;
+ spinlock_t tx_lock;
+ struct ath6kl_device *dev;
+ u32 htc_flags;
+ u32 rx_st_flags;
+ enum htc_endpoint_id ep_waiting;
+ u8 htc_tgt_ver;
+
+ /* max messages per bundle for HTC */
+ int msg_per_bndl_max;
+
+ bool tx_bndl_enable;
+ int rx_bndl_enable;
+ int max_rx_bndl_sz;
+ int max_tx_bndl_sz;
+
+ u32 block_sz;
+ u32 block_mask;
+
+ int max_scat_entries;
+ int max_xfer_szper_scatreq;
+
+ int chk_irq_status_cnt;
+};
+
+void *ath6kl_htc_create(struct ath6kl *ar);
+void ath6kl_htc_set_credit_dist(struct htc_target *target,
+ struct htc_credit_state_info *cred_info,
+ u16 svc_pri_order[], int len);
+int ath6kl_htc_wait_target(struct htc_target *target);
+int ath6kl_htc_start(struct htc_target *target);
+int ath6kl_htc_conn_service(struct htc_target *target,
+ struct htc_service_connect_req *req,
+ struct htc_service_connect_resp *resp);
+int ath6kl_htc_tx(struct htc_target *target, struct htc_packet *packet);
+void ath6kl_htc_stop(struct htc_target *target);
+void ath6kl_htc_cleanup(struct htc_target *target);
+void ath6kl_htc_flush_txep(struct htc_target *target,
+ enum htc_endpoint_id endpoint, u16 tag);
+void ath6kl_htc_flush_rx_buf(struct htc_target *target);
+void ath6kl_htc_indicate_activity_change(struct htc_target *target,
+ enum htc_endpoint_id endpoint,
+ bool active);
+int ath6kl_htc_get_rxbuf_num(struct htc_target *target,
+ enum htc_endpoint_id endpoint);
+int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target,
+ struct list_head *pktq);
+int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
+ u32 msg_look_ahead[], int *n_pkts);
+
+static inline void set_htc_pkt_info(struct htc_packet *packet, void *context,
+ u8 *buf, unsigned int len,
+ enum htc_endpoint_id eid, u16 tag)
+{
+ packet->pkt_cntxt = context;
+ packet->buf = buf;
+ packet->act_len = len;
+ packet->endpoint = eid;
+ packet->info.tx.tag = tag;
+}
+
+static inline void htc_rxpkt_reset(struct htc_packet *packet)
+{
+ packet->buf = packet->buf_start;
+ packet->act_len = 0;
+}
+
+static inline void set_htc_rxpkt_info(struct htc_packet *packet, void *context,
+ u8 *buf, unsigned long len,
+ enum htc_endpoint_id eid)
+{
+ packet->pkt_cntxt = context;
+ packet->buf = buf;
+ packet->buf_start = buf;
+ packet->buf_len = len;
+ packet->endpoint = eid;
+}
+
+static inline int get_queue_depth(struct list_head *queue)
+{
+ struct list_head *tmp_list;
+ int depth = 0;
+
+ list_for_each(tmp_list, queue)
+ depth++;
+
+ return depth;
+}
+
+#endif
diff --git a/drivers/net/wireless/ath/ath6kl/htc_hif.c b/drivers/net/wireless/ath/ath6kl/htc_hif.c
new file mode 100644
index 000000000000..86b1cc7409c2
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/htc_hif.c
@@ -0,0 +1,641 @@
+/*
+ * Copyright (c) 2007-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "target.h"
+#include "hif-ops.h"
+#include "htc_hif.h"
+#include "debug.h"
+
+#define MAILBOX_FOR_BLOCK_SIZE 1
+
+#define ATH6KL_TIME_QUANTUM 10 /* in ms */
+
+static int ath6kldev_cp_scat_dma_buf(struct hif_scatter_req *req, bool from_dma)
+{
+ u8 *buf;
+ int i;
+
+ buf = req->virt_dma_buf;
+
+ for (i = 0; i < req->scat_entries; i++) {
+
+ if (from_dma)
+ memcpy(req->scat_list[i].buf, buf,
+ req->scat_list[i].len);
+ else
+ memcpy(buf, req->scat_list[i].buf,
+ req->scat_list[i].len);
+
+ buf += req->scat_list[i].len;
+ }
+
+ return 0;
+}
+
+int ath6kldev_rw_comp_handler(void *context, int status)
+{
+ struct htc_packet *packet = context;
+
+ ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
+ "ath6kldev_rw_comp_handler (pkt:0x%p , status: %d\n",
+ packet, status);
+
+ packet->status = status;
+ packet->completion(packet->context, packet);
+
+ return 0;
+}
+
+static int ath6kldev_proc_dbg_intr(struct ath6kl_device *dev)
+{
+ u32 dummy;
+ int status;
+
+ ath6kl_err("target debug interrupt\n");
+
+ ath6kl_target_failure(dev->ar);
+
+ /*
+ * read counter to clear the interrupt, the debug error interrupt is
+ * counter 0.
+ */
+ status = hif_read_write_sync(dev->ar, COUNT_DEC_ADDRESS,
+ (u8 *)&dummy, 4, HIF_RD_SYNC_BYTE_INC);
+ if (status)
+ WARN_ON(1);
+
+ return status;
+}
+
+/* mailbox recv message polling */
+int ath6kldev_poll_mboxmsg_rx(struct ath6kl_device *dev, u32 *lk_ahd,
+ int timeout)
+{
+ struct ath6kl_irq_proc_registers *rg;
+ int status = 0, i;
+ u8 htc_mbox = 1 << HTC_MAILBOX;
+
+ for (i = timeout / ATH6KL_TIME_QUANTUM; i > 0; i--) {
+ /* this is the standard HIF way, load the reg table */
+ status = hif_read_write_sync(dev->ar, HOST_INT_STATUS_ADDRESS,
+ (u8 *) &dev->irq_proc_reg,
+ sizeof(dev->irq_proc_reg),
+ HIF_RD_SYNC_BYTE_INC);
+
+ if (status) {
+ ath6kl_err("failed to read reg table\n");
+ return status;
+ }
+
+ /* check for MBOX data and valid lookahead */
+ if (dev->irq_proc_reg.host_int_status & htc_mbox) {
+ if (dev->irq_proc_reg.rx_lkahd_valid &
+ htc_mbox) {
+ /*
+ * Mailbox has a message and the look ahead
+ * is valid.
+ */
+ rg = &dev->irq_proc_reg;
+ *lk_ahd =
+ le32_to_cpu(rg->rx_lkahd[HTC_MAILBOX]);
+ break;
+ }
+ }
+
+ /* delay a little */
+ mdelay(ATH6KL_TIME_QUANTUM);
+ ath6kl_dbg(ATH6KL_DBG_HTC_RECV, "retry mbox poll : %d\n", i);
+ }
+
+ if (i == 0) {
+ ath6kl_err("timeout waiting for recv message\n");
+ status = -ETIME;
+ /* check if the target asserted */
+ if (dev->irq_proc_reg.counter_int_status &
+ ATH6KL_TARGET_DEBUG_INTR_MASK)
+ /*
+ * Target failure handler will be called in case of
+ * an assert.
+ */
+ ath6kldev_proc_dbg_intr(dev);
+ }
+
+ return status;
+}
+
+/*
+ * Disable packet reception (used in case the host runs out of buffers)
+ * using the interrupt enable registers through the host I/F
+ */
+int ath6kldev_rx_control(struct ath6kl_device *dev, bool enable_rx)
+{
+ struct ath6kl_irq_enable_reg regs;
+ int status = 0;
+
+ /* take the lock to protect interrupt enable shadows */
+ spin_lock_bh(&dev->lock);
+
+ if (enable_rx)
+ dev->irq_en_reg.int_status_en |=
+ SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01);
+ else
+ dev->irq_en_reg.int_status_en &=
+ ~SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01);
+
+ memcpy(&regs, &dev->irq_en_reg, sizeof(regs));
+
+ spin_unlock_bh(&dev->lock);
+
+ status = hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS,
+ &regs.int_status_en,
+ sizeof(struct ath6kl_irq_enable_reg),
+ HIF_WR_SYNC_BYTE_INC);
+
+ return status;
+}
+
+int ath6kldev_submit_scat_req(struct ath6kl_device *dev,
+ struct hif_scatter_req *scat_req, bool read)
+{
+ int status = 0;
+
+ if (read) {
+ scat_req->req = HIF_RD_SYNC_BLOCK_FIX;
+ scat_req->addr = dev->ar->mbox_info.htc_addr;
+ } else {
+ scat_req->req = HIF_WR_ASYNC_BLOCK_INC;
+
+ scat_req->addr =
+ (scat_req->len > HIF_MBOX_WIDTH) ?
+ dev->ar->mbox_info.htc_ext_addr :
+ dev->ar->mbox_info.htc_addr;
+ }
+
+ ath6kl_dbg((ATH6KL_DBG_HTC_RECV | ATH6KL_DBG_HTC_SEND),
+ "ath6kldev_submit_scat_req, entries: %d, total len: %d mbox:0x%X (mode: %s : %s)\n",
+ scat_req->scat_entries, scat_req->len,
+ scat_req->addr, !read ? "async" : "sync",
+ (read) ? "rd" : "wr");
+
+ if (!read && scat_req->virt_scat) {
+ status = ath6kldev_cp_scat_dma_buf(scat_req, false);
+ if (status) {
+ scat_req->status = status;
+ scat_req->complete(dev->ar->htc_target, scat_req);
+ return 0;
+ }
+ }
+
+ status = ath6kl_hif_scat_req_rw(dev->ar, scat_req);
+
+ if (read) {
+ /* in sync mode, we can touch the scatter request */
+ scat_req->status = status;
+ if (!status && scat_req->virt_scat)
+ scat_req->status =
+ ath6kldev_cp_scat_dma_buf(scat_req, true);
+ }
+
+ return status;
+}
+
+static int ath6kldev_proc_counter_intr(struct ath6kl_device *dev)
+{
+ u8 counter_int_status;
+
+ ath6kl_dbg(ATH6KL_DBG_IRQ, "counter interrupt\n");
+
+ counter_int_status = dev->irq_proc_reg.counter_int_status &
+ dev->irq_en_reg.cntr_int_status_en;
+
+ ath6kl_dbg(ATH6KL_DBG_IRQ,
+ "valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n",
+ counter_int_status);
+
+ /*
+ * NOTE: other modules like GMBOX may use the counter interrupt for
+ * credit flow control on other counters, we only need to check for
+ * the debug assertion counter interrupt.
+ */
+ if (counter_int_status & ATH6KL_TARGET_DEBUG_INTR_MASK)
+ return ath6kldev_proc_dbg_intr(dev);
+
+ return 0;
+}
+
+static int ath6kldev_proc_err_intr(struct ath6kl_device *dev)
+{
+ int status;
+ u8 error_int_status;
+ u8 reg_buf[4];
+
+ ath6kl_dbg(ATH6KL_DBG_IRQ, "error interrupt\n");
+
+ error_int_status = dev->irq_proc_reg.error_int_status & 0x0F;
+ if (!error_int_status) {
+ WARN_ON(1);
+ return -EIO;
+ }
+
+ ath6kl_dbg(ATH6KL_DBG_IRQ,
+ "valid interrupt source(s) in ERROR_INT_STATUS: 0x%x\n",
+ error_int_status);
+
+ if (MS(ERROR_INT_STATUS_WAKEUP, error_int_status))
+ ath6kl_dbg(ATH6KL_DBG_IRQ, "error : wakeup\n");
+
+ if (MS(ERROR_INT_STATUS_RX_UNDERFLOW, error_int_status))
+ ath6kl_err("rx underflow\n");
+
+ if (MS(ERROR_INT_STATUS_TX_OVERFLOW, error_int_status))
+ ath6kl_err("tx overflow\n");
+
+ /* Clear the interrupt */
+ dev->irq_proc_reg.error_int_status &= ~error_int_status;
+
+ /* set W1C value to clear the interrupt, this hits the register first */
+ reg_buf[0] = error_int_status;
+ reg_buf[1] = 0;
+ reg_buf[2] = 0;
+ reg_buf[3] = 0;
+
+ status = hif_read_write_sync(dev->ar, ERROR_INT_STATUS_ADDRESS,
+ reg_buf, 4, HIF_WR_SYNC_BYTE_FIX);
+
+ if (status)
+ WARN_ON(1);
+
+ return status;
+}
+
+static int ath6kldev_proc_cpu_intr(struct ath6kl_device *dev)
+{
+ int status;
+ u8 cpu_int_status;
+ u8 reg_buf[4];
+
+ ath6kl_dbg(ATH6KL_DBG_IRQ, "cpu interrupt\n");
+
+ cpu_int_status = dev->irq_proc_reg.cpu_int_status &
+ dev->irq_en_reg.cpu_int_status_en;
+ if (!cpu_int_status) {
+ WARN_ON(1);
+ return -EIO;
+ }
+
+ ath6kl_dbg(ATH6KL_DBG_IRQ,
+ "valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n",
+ cpu_int_status);
+
+ /* Clear the interrupt */
+ dev->irq_proc_reg.cpu_int_status &= ~cpu_int_status;
+
+ /*
+ * Set up the register transfer buffer to hit the register 4 times ,
+ * this is done to make the access 4-byte aligned to mitigate issues
+ * with host bus interconnects that restrict bus transfer lengths to
+ * be a multiple of 4-bytes.
+ */
+
+ /* set W1C value to clear the interrupt, this hits the register first */
+ reg_buf[0] = cpu_int_status;
+ /* the remaining are set to zero which have no-effect */
+ reg_buf[1] = 0;
+ reg_buf[2] = 0;
+ reg_buf[3] = 0;
+
+ status = hif_read_write_sync(dev->ar, CPU_INT_STATUS_ADDRESS,
+ reg_buf, 4, HIF_WR_SYNC_BYTE_FIX);
+
+ if (status)
+ WARN_ON(1);
+
+ return status;
+}
+
+/* process pending interrupts synchronously */
+static int proc_pending_irqs(struct ath6kl_device *dev, bool *done)
+{
+ struct ath6kl_irq_proc_registers *rg;
+ int status = 0;
+ u8 host_int_status = 0;
+ u32 lk_ahd = 0;
+ u8 htc_mbox = 1 << HTC_MAILBOX;
+
+ ath6kl_dbg(ATH6KL_DBG_IRQ, "proc_pending_irqs: (dev: 0x%p)\n", dev);
+
+ /*
+ * NOTE: HIF implementation guarantees that the context of this
+ * call allows us to perform SYNCHRONOUS I/O, that is we can block,
+ * sleep or call any API that can block or switch thread/task
+ * contexts. This is a fully schedulable context.
+ */
+
+ /*
+ * Process pending intr only when int_status_en is clear, it may
+ * result in unnecessary bus transaction otherwise. Target may be
+ * unresponsive at the time.
+ */
+ if (dev->irq_en_reg.int_status_en) {
+ /*
+ * Read the first 28 bytes of the HTC register table. This
+ * will yield us the value of different int status
+ * registers and the lookahead registers.
+ *
+ * length = sizeof(int_status) + sizeof(cpu_int_status)
+ * + sizeof(error_int_status) +
+ * sizeof(counter_int_status) +
+ * sizeof(mbox_frame) + sizeof(rx_lkahd_valid)
+ * + sizeof(hole) + sizeof(rx_lkahd) +
+ * sizeof(int_status_en) +
+ * sizeof(cpu_int_status_en) +
+ * sizeof(err_int_status_en) +
+ * sizeof(cntr_int_status_en);
+ */
+ status = hif_read_write_sync(dev->ar, HOST_INT_STATUS_ADDRESS,
+ (u8 *) &dev->irq_proc_reg,
+ sizeof(dev->irq_proc_reg),
+ HIF_RD_SYNC_BYTE_INC);
+ if (status)
+ goto out;
+
+ if (AR_DBG_LVL_CHECK(ATH6KL_DBG_IRQ))
+ ath6kl_dump_registers(dev, &dev->irq_proc_reg,
+ &dev->irq_en_reg);
+
+ /* Update only those registers that are enabled */
+ host_int_status = dev->irq_proc_reg.host_int_status &
+ dev->irq_en_reg.int_status_en;
+
+ /* Look at mbox status */
+ if (host_int_status & htc_mbox) {
+ /*
+ * Mask out pending mbox value, we use "lookAhead as
+ * the real flag for mbox processing.
+ */
+ host_int_status &= ~htc_mbox;
+ if (dev->irq_proc_reg.rx_lkahd_valid &
+ htc_mbox) {
+ rg = &dev->irq_proc_reg;
+ lk_ahd = le32_to_cpu(rg->rx_lkahd[HTC_MAILBOX]);
+ if (!lk_ahd)
+ ath6kl_err("lookAhead is zero!\n");
+ }
+ }
+ }
+
+ if (!host_int_status && !lk_ahd) {
+ *done = true;
+ goto out;
+ }
+
+ if (lk_ahd) {
+ int fetched = 0;
+
+ ath6kl_dbg(ATH6KL_DBG_IRQ,
+ "pending mailbox msg, lk_ahd: 0x%X\n", lk_ahd);
+ /*
+ * Mailbox Interrupt, the HTC layer may issue async
+ * requests to empty the mailbox. When emptying the recv
+ * mailbox we use the async handler above called from the
+ * completion routine of the callers read request. This can
+ * improve performance by reducing context switching when
+ * we rapidly pull packets.
+ */
+ status = ath6kl_htc_rxmsg_pending_handler(dev->htc_cnxt,
+ &lk_ahd, &fetched);
+ if (status)
+ goto out;
+
+ if (!fetched)
+ /*
+ * HTC could not pull any messages out due to lack
+ * of resources.
+ */
+ dev->htc_cnxt->chk_irq_status_cnt = 0;
+ }
+
+ /* now handle the rest of them */
+ ath6kl_dbg(ATH6KL_DBG_IRQ,
+ "valid interrupt source(s) for other interrupts: 0x%x\n",
+ host_int_status);
+
+ if (MS(HOST_INT_STATUS_CPU, host_int_status)) {
+ /* CPU Interrupt */
+ status = ath6kldev_proc_cpu_intr(dev);
+ if (status)
+ goto out;
+ }
+
+ if (MS(HOST_INT_STATUS_ERROR, host_int_status)) {
+ /* Error Interrupt */
+ status = ath6kldev_proc_err_intr(dev);
+ if (status)
+ goto out;
+ }
+
+ if (MS(HOST_INT_STATUS_COUNTER, host_int_status))
+ /* Counter Interrupt */
+ status = ath6kldev_proc_counter_intr(dev);
+
+out:
+ /*
+ * An optimization to bypass reading the IRQ status registers
+ * unecessarily which can re-wake the target, if upper layers
+ * determine that we are in a low-throughput mode, we can rely on
+ * taking another interrupt rather than re-checking the status
+ * registers which can re-wake the target.
+ *
+ * NOTE : for host interfaces that makes use of detecting pending
+ * mbox messages at hif can not use this optimization due to
+ * possible side effects, SPI requires the host to drain all
+ * messages from the mailbox before exiting the ISR routine.
+ */
+
+ ath6kl_dbg(ATH6KL_DBG_IRQ,
+ "bypassing irq status re-check, forcing done\n");
+
+ if (!dev->htc_cnxt->chk_irq_status_cnt)
+ *done = true;
+
+ ath6kl_dbg(ATH6KL_DBG_IRQ,
+ "proc_pending_irqs: (done:%d, status=%d\n", *done, status);
+
+ return status;
+}
+
+/* interrupt handler, kicks off all interrupt processing */
+int ath6kldev_intr_bh_handler(struct ath6kl *ar)
+{
+ struct ath6kl_device *dev = ar->htc_target->dev;
+ int status = 0;
+ bool done = false;
+
+ /*
+ * Reset counter used to flag a re-scan of IRQ status registers on
+ * the target.
+ */
+ dev->htc_cnxt->chk_irq_status_cnt = 0;
+
+ /*
+ * IRQ processing is synchronous, interrupt status registers can be
+ * re-read.
+ */
+ while (!done) {
+ status = proc_pending_irqs(dev, &done);
+ if (status)
+ break;
+ }
+
+ return status;
+}
+
+static int ath6kldev_enable_intrs(struct ath6kl_device *dev)
+{
+ struct ath6kl_irq_enable_reg regs;
+ int status;
+
+ spin_lock_bh(&dev->lock);
+
+ /* Enable all but ATH6KL CPU interrupts */
+ dev->irq_en_reg.int_status_en =
+ SM(INT_STATUS_ENABLE_ERROR, 0x01) |
+ SM(INT_STATUS_ENABLE_CPU, 0x01) |
+ SM(INT_STATUS_ENABLE_COUNTER, 0x01);
+
+ /*
+ * NOTE: There are some cases where HIF can do detection of
+ * pending mbox messages which is disabled now.
+ */
+ dev->irq_en_reg.int_status_en |= SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01);
+
+ /* Set up the CPU Interrupt status Register */
+ dev->irq_en_reg.cpu_int_status_en = 0;
+
+ /* Set up the Error Interrupt status Register */
+ dev->irq_en_reg.err_int_status_en =
+ SM(ERROR_STATUS_ENABLE_RX_UNDERFLOW, 0x01) |
+ SM(ERROR_STATUS_ENABLE_TX_OVERFLOW, 0x1);
+
+ /*
+ * Enable Counter interrupt status register to get fatal errors for
+ * debugging.
+ */
+ dev->irq_en_reg.cntr_int_status_en = SM(COUNTER_INT_STATUS_ENABLE_BIT,
+ ATH6KL_TARGET_DEBUG_INTR_MASK);
+ memcpy(&regs, &dev->irq_en_reg, sizeof(regs));
+
+ spin_unlock_bh(&dev->lock);
+
+ status = hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS,
+ &regs.int_status_en, sizeof(regs),
+ HIF_WR_SYNC_BYTE_INC);
+
+ if (status)
+ ath6kl_err("failed to update interrupt ctl reg err: %d\n",
+ status);
+
+ return status;
+}
+
+int ath6kldev_disable_intrs(struct ath6kl_device *dev)
+{
+ struct ath6kl_irq_enable_reg regs;
+
+ spin_lock_bh(&dev->lock);
+ /* Disable all interrupts */
+ dev->irq_en_reg.int_status_en = 0;
+ dev->irq_en_reg.cpu_int_status_en = 0;
+ dev->irq_en_reg.err_int_status_en = 0;
+ dev->irq_en_reg.cntr_int_status_en = 0;
+ memcpy(&regs, &dev->irq_en_reg, sizeof(regs));
+ spin_unlock_bh(&dev->lock);
+
+ return hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS,
+ &regs.int_status_en, sizeof(regs),
+ HIF_WR_SYNC_BYTE_INC);
+}
+
+/* enable device interrupts */
+int ath6kldev_unmask_intrs(struct ath6kl_device *dev)
+{
+ int status = 0;
+
+ /*
+ * Make sure interrupt are disabled before unmasking at the HIF
+ * layer. The rationale here is that between device insertion
+ * (where we clear the interrupts the first time) and when HTC
+ * is finally ready to handle interrupts, other software can perform
+ * target "soft" resets. The ATH6KL interrupt enables reset back to an
+ * "enabled" state when this happens.
+ */
+ ath6kldev_disable_intrs(dev);
+
+ /* unmask the host controller interrupts */
+ ath6kl_hif_irq_enable(dev->ar);
+ status = ath6kldev_enable_intrs(dev);
+
+ return status;
+}
+
+/* disable all device interrupts */
+int ath6kldev_mask_intrs(struct ath6kl_device *dev)
+{
+ /*
+ * Mask the interrupt at the HIF layer to avoid any stray interrupt
+ * taken while we zero out our shadow registers in
+ * ath6kldev_disable_intrs().
+ */
+ ath6kl_hif_irq_disable(dev->ar);
+
+ return ath6kldev_disable_intrs(dev);
+}
+
+int ath6kldev_setup(struct ath6kl_device *dev)
+{
+ int status = 0;
+
+ spin_lock_init(&dev->lock);
+
+ /*
+ * NOTE: we actually get the block size of a mailbox other than 0,
+ * for SDIO the block size on mailbox 0 is artificially set to 1.
+ * So we use the block size that is set for the other 3 mailboxes.
+ */
+ dev->htc_cnxt->block_sz = dev->ar->mbox_info.block_size;
+
+ /* must be a power of 2 */
+ if ((dev->htc_cnxt->block_sz & (dev->htc_cnxt->block_sz - 1)) != 0) {
+ WARN_ON(1);
+ goto fail_setup;
+ }
+
+ /* assemble mask, used for padding to a block */
+ dev->htc_cnxt->block_mask = dev->htc_cnxt->block_sz - 1;
+
+ ath6kl_dbg(ATH6KL_DBG_TRC, "block size: %d, mbox addr:0x%X\n",
+ dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr);
+
+ ath6kl_dbg(ATH6KL_DBG_TRC,
+ "hif interrupt processing is sync only\n");
+
+ status = ath6kldev_disable_intrs(dev);
+
+fail_setup:
+ return status;
+
+}
diff --git a/drivers/net/wireless/ath/ath6kl/htc_hif.h b/drivers/net/wireless/ath/ath6kl/htc_hif.h
new file mode 100644
index 000000000000..171ad63d89b0
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/htc_hif.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2007-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef HTC_HIF_H
+#define HTC_HIF_H
+
+#include "htc.h"
+#include "hif.h"
+
+#define ATH6KL_MAILBOXES 4
+
+/* HTC runs over mailbox 0 */
+#define HTC_MAILBOX 0
+
+#define ATH6KL_TARGET_DEBUG_INTR_MASK 0x01
+
+#define OTHER_INTS_ENABLED (INT_STATUS_ENABLE_ERROR_MASK | \
+ INT_STATUS_ENABLE_CPU_MASK | \
+ INT_STATUS_ENABLE_COUNTER_MASK)
+
+#define ATH6KL_REG_IO_BUFFER_SIZE 32
+#define ATH6KL_MAX_REG_IO_BUFFERS 8
+#define ATH6KL_SCATTER_ENTRIES_PER_REQ 16
+#define ATH6KL_MAX_TRANSFER_SIZE_PER_SCATTER (16 * 1024)
+#define ATH6KL_SCATTER_REQS 4
+
+#ifndef A_CACHE_LINE_PAD
+#define A_CACHE_LINE_PAD 128
+#endif
+#define ATH6KL_MIN_SCATTER_ENTRIES_PER_REQ 2
+#define ATH6KL_MIN_TRANSFER_SIZE_PER_SCATTER (4 * 1024)
+
+struct ath6kl_irq_proc_registers {
+ u8 host_int_status;
+ u8 cpu_int_status;
+ u8 error_int_status;
+ u8 counter_int_status;
+ u8 mbox_frame;
+ u8 rx_lkahd_valid;
+ u8 host_int_status2;
+ u8 gmbox_rx_avail;
+ __le32 rx_lkahd[2];
+ __le32 rx_gmbox_lkahd_alias[2];
+} __packed;
+
+struct ath6kl_irq_enable_reg {
+ u8 int_status_en;
+ u8 cpu_int_status_en;
+ u8 err_int_status_en;
+ u8 cntr_int_status_en;
+} __packed;
+
+struct ath6kl_device {
+ spinlock_t lock;
+ u8 pad1[A_CACHE_LINE_PAD];
+ struct ath6kl_irq_proc_registers irq_proc_reg;
+ u8 pad2[A_CACHE_LINE_PAD];
+ struct ath6kl_irq_enable_reg irq_en_reg;
+ u8 pad3[A_CACHE_LINE_PAD];
+ struct htc_target *htc_cnxt;
+ struct ath6kl *ar;
+};
+
+int ath6kldev_setup(struct ath6kl_device *dev);
+int ath6kldev_unmask_intrs(struct ath6kl_device *dev);
+int ath6kldev_mask_intrs(struct ath6kl_device *dev);
+int ath6kldev_poll_mboxmsg_rx(struct ath6kl_device *dev,
+ u32 *lk_ahd, int timeout);
+int ath6kldev_rx_control(struct ath6kl_device *dev, bool enable_rx);
+int ath6kldev_disable_intrs(struct ath6kl_device *dev);
+
+int ath6kldev_rw_comp_handler(void *context, int status);
+int ath6kldev_intr_bh_handler(struct ath6kl *ar);
+
+/* Scatter Function and Definitions */
+int ath6kldev_submit_scat_req(struct ath6kl_device *dev,
+ struct hif_scatter_req *scat_req, bool read);
+
+#endif /*ATH6KL_H_ */
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
new file mode 100644
index 000000000000..c1d2366704b5
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -0,0 +1,1727 @@
+
+/*
+ * Copyright (c) 2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/mmc/sdio_func.h>
+#include "core.h"
+#include "cfg80211.h"
+#include "target.h"
+#include "debug.h"
+#include "hif-ops.h"
+
+unsigned int debug_mask;
+static unsigned int testmode;
+
+module_param(debug_mask, uint, 0644);
+module_param(testmode, uint, 0644);
+
+/*
+ * Include definitions here that can be used to tune the WLAN module
+ * behavior. Different customers can tune the behavior as per their needs,
+ * here.
+ */
+
+/*
+ * This configuration item enable/disable keepalive support.
+ * Keepalive support: In the absence of any data traffic to AP, null
+ * frames will be sent to the AP at periodic interval, to keep the association
+ * active. This configuration item defines the periodic interval.
+ * Use value of zero to disable keepalive support
+ * Default: 60 seconds
+ */
+#define WLAN_CONFIG_KEEP_ALIVE_INTERVAL 60
+
+/*
+ * This configuration item sets the value of disconnect timeout
+ * Firmware delays sending the disconnec event to the host for this
+ * timeout after is gets disconnected from the current AP.
+ * If the firmware successly roams within the disconnect timeout
+ * it sends a new connect event
+ */
+#define WLAN_CONFIG_DISCONNECT_TIMEOUT 10
+
+#define CONFIG_AR600x_DEBUG_UART_TX_PIN 8
+
+#define ATH6KL_DATA_OFFSET 64
+struct sk_buff *ath6kl_buf_alloc(int size)
+{
+ struct sk_buff *skb;
+ u16 reserved;
+
+ /* Add chacheline space at front and back of buffer */
+ reserved = (2 * L1_CACHE_BYTES) + ATH6KL_DATA_OFFSET +
+ sizeof(struct htc_packet) + ATH6KL_HTC_ALIGN_BYTES;
+ skb = dev_alloc_skb(size + reserved);
+
+ if (skb)
+ skb_reserve(skb, reserved - L1_CACHE_BYTES);
+ return skb;
+}
+
+void ath6kl_init_profile_info(struct ath6kl *ar)
+{
+ ar->ssid_len = 0;
+ memset(ar->ssid, 0, sizeof(ar->ssid));
+
+ ar->dot11_auth_mode = OPEN_AUTH;
+ ar->auth_mode = NONE_AUTH;
+ ar->prwise_crypto = NONE_CRYPT;
+ ar->prwise_crypto_len = 0;
+ ar->grp_crypto = NONE_CRYPT;
+ ar->grp_crypto_len = 0;
+ memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list));
+ memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
+ memset(ar->bssid, 0, sizeof(ar->bssid));
+ ar->bss_ch = 0;
+ ar->nw_type = ar->next_mode = INFRA_NETWORK;
+}
+
+static u8 ath6kl_get_fw_iftype(struct ath6kl *ar)
+{
+ switch (ar->nw_type) {
+ case INFRA_NETWORK:
+ return HI_OPTION_FW_MODE_BSS_STA;
+ case ADHOC_NETWORK:
+ return HI_OPTION_FW_MODE_IBSS;
+ case AP_NETWORK:
+ return HI_OPTION_FW_MODE_AP;
+ default:
+ ath6kl_err("Unsupported interface type :%d\n", ar->nw_type);
+ return 0xff;
+ }
+}
+
+static int ath6kl_set_host_app_area(struct ath6kl *ar)
+{
+ u32 address, data;
+ struct host_app_area host_app_area;
+
+ /* Fetch the address of the host_app_area_s
+ * instance in the host interest area */
+ address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_app_host_interest));
+ address = TARG_VTOP(ar->target_type, address);
+
+ if (ath6kl_diag_read32(ar, address, &data))
+ return -EIO;
+
+ address = TARG_VTOP(ar->target_type, data);
+ host_app_area.wmi_protocol_ver = WMI_PROTOCOL_VERSION;
+ if (ath6kl_diag_write(ar, address, (u8 *) &host_app_area,
+ sizeof(struct host_app_area)))
+ return -EIO;
+
+ return 0;
+}
+
+static inline void set_ac2_ep_map(struct ath6kl *ar,
+ u8 ac,
+ enum htc_endpoint_id ep)
+{
+ ar->ac2ep_map[ac] = ep;
+ ar->ep2ac_map[ep] = ac;
+}
+
+/* connect to a service */
+static int ath6kl_connectservice(struct ath6kl *ar,
+ struct htc_service_connect_req *con_req,
+ char *desc)
+{
+ int status;
+ struct htc_service_connect_resp response;
+
+ memset(&response, 0, sizeof(response));
+
+ status = ath6kl_htc_conn_service(ar->htc_target, con_req, &response);
+ if (status) {
+ ath6kl_err("failed to connect to %s service status:%d\n",
+ desc, status);
+ return status;
+ }
+
+ switch (con_req->svc_id) {
+ case WMI_CONTROL_SVC:
+ if (test_bit(WMI_ENABLED, &ar->flag))
+ ath6kl_wmi_set_control_ep(ar->wmi, response.endpoint);
+ ar->ctrl_ep = response.endpoint;
+ break;
+ case WMI_DATA_BE_SVC:
+ set_ac2_ep_map(ar, WMM_AC_BE, response.endpoint);
+ break;
+ case WMI_DATA_BK_SVC:
+ set_ac2_ep_map(ar, WMM_AC_BK, response.endpoint);
+ break;
+ case WMI_DATA_VI_SVC:
+ set_ac2_ep_map(ar, WMM_AC_VI, response.endpoint);
+ break;
+ case WMI_DATA_VO_SVC:
+ set_ac2_ep_map(ar, WMM_AC_VO, response.endpoint);
+ break;
+ default:
+ ath6kl_err("service id is not mapped %d\n", con_req->svc_id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ath6kl_init_service_ep(struct ath6kl *ar)
+{
+ struct htc_service_connect_req connect;
+
+ memset(&connect, 0, sizeof(connect));
+
+ /* these fields are the same for all service endpoints */
+ connect.ep_cb.rx = ath6kl_rx;
+ connect.ep_cb.rx_refill = ath6kl_rx_refill;
+ connect.ep_cb.tx_full = ath6kl_tx_queue_full;
+
+ /*
+ * Set the max queue depth so that our ath6kl_tx_queue_full handler
+ * gets called.
+ */
+ connect.max_txq_depth = MAX_DEFAULT_SEND_QUEUE_DEPTH;
+ connect.ep_cb.rx_refill_thresh = ATH6KL_MAX_RX_BUFFERS / 4;
+ if (!connect.ep_cb.rx_refill_thresh)
+ connect.ep_cb.rx_refill_thresh++;
+
+ /* connect to control service */
+ connect.svc_id = WMI_CONTROL_SVC;
+ if (ath6kl_connectservice(ar, &connect, "WMI CONTROL"))
+ return -EIO;
+
+ connect.flags |= HTC_FLGS_TX_BNDL_PAD_EN;
+
+ /*
+ * Limit the HTC message size on the send path, although e can
+ * receive A-MSDU frames of 4K, we will only send ethernet-sized
+ * (802.3) frames on the send path.
+ */
+ connect.max_rxmsg_sz = WMI_MAX_TX_DATA_FRAME_LENGTH;
+
+ /*
+ * To reduce the amount of committed memory for larger A_MSDU
+ * frames, use the recv-alloc threshold mechanism for larger
+ * packets.
+ */
+ connect.ep_cb.rx_alloc_thresh = ATH6KL_BUFFER_SIZE;
+ connect.ep_cb.rx_allocthresh = ath6kl_alloc_amsdu_rxbuf;
+
+ /*
+ * For the remaining data services set the connection flag to
+ * reduce dribbling, if configured to do so.
+ */
+ connect.conn_flags |= HTC_CONN_FLGS_REDUCE_CRED_DRIB;
+ connect.conn_flags &= ~HTC_CONN_FLGS_THRESH_MASK;
+ connect.conn_flags |= HTC_CONN_FLGS_THRESH_LVL_HALF;
+
+ connect.svc_id = WMI_DATA_BE_SVC;
+
+ if (ath6kl_connectservice(ar, &connect, "WMI DATA BE"))
+ return -EIO;
+
+ /* connect to back-ground map this to WMI LOW_PRI */
+ connect.svc_id = WMI_DATA_BK_SVC;
+ if (ath6kl_connectservice(ar, &connect, "WMI DATA BK"))
+ return -EIO;
+
+ /* connect to Video service, map this to to HI PRI */
+ connect.svc_id = WMI_DATA_VI_SVC;
+ if (ath6kl_connectservice(ar, &connect, "WMI DATA VI"))
+ return -EIO;
+
+ /*
+ * Connect to VO service, this is currently not mapped to a WMI
+ * priority stream due to historical reasons. WMI originally
+ * defined 3 priorities over 3 mailboxes We can change this when
+ * WMI is reworked so that priorities are not dependent on
+ * mailboxes.
+ */
+ connect.svc_id = WMI_DATA_VO_SVC;
+ if (ath6kl_connectservice(ar, &connect, "WMI DATA VO"))
+ return -EIO;
+
+ return 0;
+}
+
+static void ath6kl_init_control_info(struct ath6kl *ar)
+{
+ u8 ctr;
+
+ clear_bit(WMI_ENABLED, &ar->flag);
+ ath6kl_init_profile_info(ar);
+ ar->def_txkey_index = 0;
+ memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list));
+ ar->ch_hint = 0;
+ ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL;
+ ar->listen_intvl_b = 0;
+ ar->tx_pwr = 0;
+ clear_bit(SKIP_SCAN, &ar->flag);
+ set_bit(WMM_ENABLED, &ar->flag);
+ ar->intra_bss = 1;
+ memset(&ar->sc_params, 0, sizeof(ar->sc_params));
+ ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT;
+ ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS;
+ ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
+
+ memset((u8 *)ar->sta_list, 0,
+ AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
+
+ spin_lock_init(&ar->mcastpsq_lock);
+
+ /* Init the PS queues */
+ for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
+ spin_lock_init(&ar->sta_list[ctr].psq_lock);
+ skb_queue_head_init(&ar->sta_list[ctr].psq);
+ }
+
+ skb_queue_head_init(&ar->mcastpsq);
+
+ memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
+}
+
+/*
+ * Set HTC/Mbox operational parameters, this can only be called when the
+ * target is in the BMI phase.
+ */
+static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val,
+ u8 htc_ctrl_buf)
+{
+ int status;
+ u32 blk_size;
+
+ blk_size = ar->mbox_info.block_size;
+
+ if (htc_ctrl_buf)
+ blk_size |= ((u32)htc_ctrl_buf) << 16;
+
+ /* set the host interest area for the block size */
+ status = ath6kl_bmi_write(ar,
+ ath6kl_get_hi_item_addr(ar,
+ HI_ITEM(hi_mbox_io_block_sz)),
+ (u8 *)&blk_size,
+ 4);
+ if (status) {
+ ath6kl_err("bmi_write_memory for IO block size failed\n");
+ goto out;
+ }
+
+ ath6kl_dbg(ATH6KL_DBG_TRC, "block size set: %d (target addr:0x%X)\n",
+ blk_size,
+ ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_mbox_io_block_sz)));
+
+ if (mbox_isr_yield_val) {
+ /* set the host interest area for the mbox ISR yield limit */
+ status = ath6kl_bmi_write(ar,
+ ath6kl_get_hi_item_addr(ar,
+ HI_ITEM(hi_mbox_isr_yield_limit)),
+ (u8 *)&mbox_isr_yield_val,
+ 4);
+ if (status) {
+ ath6kl_err("bmi_write_memory for yield limit failed\n");
+ goto out;
+ }
+ }
+
+out:
+ return status;
+}
+
+#define REG_DUMP_COUNT_AR6003 60
+#define REGISTER_DUMP_LEN_MAX 60
+
+static void ath6kl_dump_target_assert_info(struct ath6kl *ar)
+{
+ u32 address;
+ u32 regdump_loc = 0;
+ int status;
+ u32 regdump_val[REGISTER_DUMP_LEN_MAX];
+ u32 i;
+
+ if (ar->target_type != TARGET_TYPE_AR6003)
+ return;
+
+ /* the reg dump pointer is copied to the host interest area */
+ address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_failure_state));
+ address = TARG_VTOP(ar->target_type, address);
+
+ /* read RAM location through diagnostic window */
+ status = ath6kl_diag_read32(ar, address, &regdump_loc);
+
+ if (status || !regdump_loc) {
+ ath6kl_err("failed to get ptr to register dump area\n");
+ return;
+ }
+
+ ath6kl_dbg(ATH6KL_DBG_TRC, "location of register dump data: 0x%X\n",
+ regdump_loc);
+ regdump_loc = TARG_VTOP(ar->target_type, regdump_loc);
+
+ /* fetch register dump data */
+ status = ath6kl_diag_read(ar, regdump_loc, (u8 *)&regdump_val[0],
+ REG_DUMP_COUNT_AR6003 * (sizeof(u32)));
+
+ if (status) {
+ ath6kl_err("failed to get register dump\n");
+ return;
+ }
+ ath6kl_dbg(ATH6KL_DBG_TRC, "Register Dump:\n");
+
+ for (i = 0; i < REG_DUMP_COUNT_AR6003; i++)
+ ath6kl_dbg(ATH6KL_DBG_TRC, " %d : 0x%8.8X\n",
+ i, regdump_val[i]);
+
+}
+
+void ath6kl_target_failure(struct ath6kl *ar)
+{
+ ath6kl_err("target asserted\n");
+
+ /* try dumping target assertion information (if any) */
+ ath6kl_dump_target_assert_info(ar);
+
+}
+
+static int ath6kl_target_config_wlan_params(struct ath6kl *ar)
+{
+ int status = 0;
+ int ret;
+
+ /*
+ * Configure the device for rx dot11 header rules. "0,0" are the
+ * default values. Required if checksum offload is needed. Set
+ * RxMetaVersion to 2.
+ */
+ if (ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi,
+ ar->rx_meta_ver, 0, 0)) {
+ ath6kl_err("unable to set the rx frame format\n");
+ status = -EIO;
+ }
+
+ if (ar->conf_flags & ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN)
+ if ((ath6kl_wmi_pmparams_cmd(ar->wmi, 0, 1, 0, 0, 1,
+ IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN)) != 0) {
+ ath6kl_err("unable to set power save fail event policy\n");
+ status = -EIO;
+ }
+
+ if (!(ar->conf_flags & ATH6KL_CONF_IGNORE_ERP_BARKER))
+ if ((ath6kl_wmi_set_lpreamble_cmd(ar->wmi, 0,
+ WMI_DONOT_IGNORE_BARKER_IN_ERP)) != 0) {
+ ath6kl_err("unable to set barker preamble policy\n");
+ status = -EIO;
+ }
+
+ if (ath6kl_wmi_set_keepalive_cmd(ar->wmi,
+ WLAN_CONFIG_KEEP_ALIVE_INTERVAL)) {
+ ath6kl_err("unable to set keep alive interval\n");
+ status = -EIO;
+ }
+
+ if (ath6kl_wmi_disctimeout_cmd(ar->wmi,
+ WLAN_CONFIG_DISCONNECT_TIMEOUT)) {
+ ath6kl_err("unable to set disconnect timeout\n");
+ status = -EIO;
+ }
+
+ if (!(ar->conf_flags & ATH6KL_CONF_ENABLE_TX_BURST))
+ if (ath6kl_wmi_set_wmm_txop(ar->wmi, WMI_TXOP_DISABLED)) {
+ ath6kl_err("unable to set txop bursting\n");
+ status = -EIO;
+ }
+
+ if (ar->p2p) {
+ ret = ath6kl_wmi_info_req_cmd(ar->wmi,
+ P2P_FLAG_CAPABILITIES_REQ |
+ P2P_FLAG_MACADDR_REQ |
+ P2P_FLAG_HMODEL_REQ);
+ if (ret) {
+ ath6kl_dbg(ATH6KL_DBG_TRC, "failed to request P2P "
+ "capabilities (%d) - assuming P2P not "
+ "supported\n", ret);
+ ar->p2p = 0;
+ }
+ }
+
+ if (ar->p2p) {
+ /* Enable Probe Request reporting for P2P */
+ ret = ath6kl_wmi_probe_report_req_cmd(ar->wmi, true);
+ if (ret) {
+ ath6kl_dbg(ATH6KL_DBG_TRC, "failed to enable Probe "
+ "Request reporting (%d)\n", ret);
+ }
+ }
+
+ return status;
+}
+
+int ath6kl_configure_target(struct ath6kl *ar)
+{
+ u32 param, ram_reserved_size;
+ u8 fw_iftype;
+
+ fw_iftype = ath6kl_get_fw_iftype(ar);
+ if (fw_iftype == 0xff)
+ return -EINVAL;
+
+ /* Tell target which HTC version it is used*/
+ param = HTC_PROTOCOL_VERSION;
+ if (ath6kl_bmi_write(ar,
+ ath6kl_get_hi_item_addr(ar,
+ HI_ITEM(hi_app_host_interest)),
+ (u8 *)&param, 4) != 0) {
+ ath6kl_err("bmi_write_memory for htc version failed\n");
+ return -EIO;
+ }
+
+ /* set the firmware mode to STA/IBSS/AP */
+ param = 0;
+
+ if (ath6kl_bmi_read(ar,
+ ath6kl_get_hi_item_addr(ar,
+ HI_ITEM(hi_option_flag)),
+ (u8 *)&param, 4) != 0) {
+ ath6kl_err("bmi_read_memory for setting fwmode failed\n");
+ return -EIO;
+ }
+
+ param |= (1 << HI_OPTION_NUM_DEV_SHIFT);
+ param |= (fw_iftype << HI_OPTION_FW_MODE_SHIFT);
+ if (ar->p2p && fw_iftype == HI_OPTION_FW_MODE_BSS_STA) {
+ param |= HI_OPTION_FW_SUBMODE_P2PDEV <<
+ HI_OPTION_FW_SUBMODE_SHIFT;
+ }
+ param |= (0 << HI_OPTION_MAC_ADDR_METHOD_SHIFT);
+ param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT);
+
+ if (ath6kl_bmi_write(ar,
+ ath6kl_get_hi_item_addr(ar,
+ HI_ITEM(hi_option_flag)),
+ (u8 *)&param,
+ 4) != 0) {
+ ath6kl_err("bmi_write_memory for setting fwmode failed\n");
+ return -EIO;
+ }
+
+ ath6kl_dbg(ATH6KL_DBG_TRC, "firmware mode set\n");
+
+ /*
+ * Hardcode the address use for the extended board data
+ * Ideally this should be pre-allocate by the OS at boot time
+ * But since it is a new feature and board data is loaded
+ * at init time, we have to workaround this from host.
+ * It is difficult to patch the firmware boot code,
+ * but possible in theory.
+ */
+
+ param = ar->hw.board_ext_data_addr;
+ ram_reserved_size = ar->hw.reserved_ram_size;
+
+ if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar,
+ HI_ITEM(hi_board_ext_data)),
+ (u8 *)&param, 4) != 0) {
+ ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n");
+ return -EIO;
+ }
+
+ if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar,
+ HI_ITEM(hi_end_ram_reserve_sz)),
+ (u8 *)&ram_reserved_size, 4) != 0) {
+ ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n");
+ return -EIO;
+ }
+
+ /* set the block size for the target */
+ if (ath6kl_set_htc_params(ar, MBOX_YIELD_LIMIT, 0))
+ /* use default number of control buffers */
+ return -EIO;
+
+ return 0;
+}
+
+struct ath6kl *ath6kl_core_alloc(struct device *sdev)
+{
+ struct net_device *dev;
+ struct ath6kl *ar;
+ struct wireless_dev *wdev;
+
+ wdev = ath6kl_cfg80211_init(sdev);
+ if (!wdev) {
+ ath6kl_err("ath6kl_cfg80211_init failed\n");
+ return NULL;
+ }
+
+ ar = wdev_priv(wdev);
+ ar->dev = sdev;
+ ar->wdev = wdev;
+ wdev->iftype = NL80211_IFTYPE_STATION;
+
+ if (ath6kl_debug_init(ar)) {
+ ath6kl_err("Failed to initialize debugfs\n");
+ ath6kl_cfg80211_deinit(ar);
+ return NULL;
+ }
+
+ dev = alloc_netdev(0, "wlan%d", ether_setup);
+ if (!dev) {
+ ath6kl_err("no memory for network device instance\n");
+ ath6kl_cfg80211_deinit(ar);
+ return NULL;
+ }
+
+ dev->ieee80211_ptr = wdev;
+ SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy));
+ wdev->netdev = dev;
+ ar->sme_state = SME_DISCONNECTED;
+
+ init_netdev(dev);
+
+ ar->net_dev = dev;
+ set_bit(WLAN_ENABLED, &ar->flag);
+
+ ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
+
+ spin_lock_init(&ar->lock);
+
+ ath6kl_init_control_info(ar);
+ init_waitqueue_head(&ar->event_wq);
+ sema_init(&ar->sem, 1);
+ clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
+
+ INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
+
+ setup_timer(&ar->disconnect_timer, disconnect_timer_handler,
+ (unsigned long) dev);
+
+ return ar;
+}
+
+int ath6kl_unavail_ev(struct ath6kl *ar)
+{
+ ath6kl_destroy(ar->net_dev, 1);
+
+ return 0;
+}
+
+/* firmware upload */
+static int ath6kl_get_fw(struct ath6kl *ar, const char *filename,
+ u8 **fw, size_t *fw_len)
+{
+ const struct firmware *fw_entry;
+ int ret;
+
+ ret = request_firmware(&fw_entry, filename, ar->dev);
+ if (ret)
+ return ret;
+
+ *fw_len = fw_entry->size;
+ *fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
+
+ if (*fw == NULL)
+ ret = -ENOMEM;
+
+ release_firmware(fw_entry);
+
+ return ret;
+}
+
+#ifdef CONFIG_OF
+static const char *get_target_ver_dir(const struct ath6kl *ar)
+{
+ switch (ar->version.target_ver) {
+ case AR6003_REV1_VERSION:
+ return "ath6k/AR6003/hw1.0";
+ case AR6003_REV2_VERSION:
+ return "ath6k/AR6003/hw2.0";
+ case AR6003_REV3_VERSION:
+ return "ath6k/AR6003/hw2.1.1";
+ }
+ ath6kl_warn("%s: unsupported target version 0x%x.\n", __func__,
+ ar->version.target_ver);
+ return NULL;
+}
+
+/*
+ * Check the device tree for a board-id and use it to construct
+ * the pathname to the firmware file. Used (for now) to find a
+ * fallback to the "bdata.bin" file--typically a symlink to the
+ * appropriate board-specific file.
+ */
+static bool check_device_tree(struct ath6kl *ar)
+{
+ static const char *board_id_prop = "atheros,board-id";
+ struct device_node *node;
+ char board_filename[64];
+ const char *board_id;
+ int ret;
+
+ for_each_compatible_node(node, NULL, "atheros,ath6kl") {
+ board_id = of_get_property(node, board_id_prop, NULL);
+ if (board_id == NULL) {
+ ath6kl_warn("No \"%s\" property on %s node.\n",
+ board_id_prop, node->name);
+ continue;
+ }
+ snprintf(board_filename, sizeof(board_filename),
+ "%s/bdata.%s.bin", get_target_ver_dir(ar), board_id);
+
+ ret = ath6kl_get_fw(ar, board_filename, &ar->fw_board,
+ &ar->fw_board_len);
+ if (ret) {
+ ath6kl_err("Failed to get DT board file %s: %d\n",
+ board_filename, ret);
+ continue;
+ }
+ return true;
+ }
+ return false;
+}
+#else
+static bool check_device_tree(struct ath6kl *ar)
+{
+ return false;
+}
+#endif /* CONFIG_OF */
+
+static int ath6kl_fetch_board_file(struct ath6kl *ar)
+{
+ const char *filename;
+ int ret;
+
+ if (ar->fw_board != NULL)
+ return 0;
+
+ switch (ar->version.target_ver) {
+ case AR6003_REV2_VERSION:
+ filename = AR6003_REV2_BOARD_DATA_FILE;
+ break;
+ case AR6004_REV1_VERSION:
+ filename = AR6004_REV1_BOARD_DATA_FILE;
+ break;
+ default:
+ filename = AR6003_REV3_BOARD_DATA_FILE;
+ break;
+ }
+
+ ret = ath6kl_get_fw(ar, filename, &ar->fw_board,
+ &ar->fw_board_len);
+ if (ret == 0) {
+ /* managed to get proper board file */
+ return 0;
+ }
+
+ if (check_device_tree(ar)) {
+ /* got board file from device tree */
+ return 0;
+ }
+
+ /* there was no proper board file, try to use default instead */
+ ath6kl_warn("Failed to get board file %s (%d), trying to find default board file.\n",
+ filename, ret);
+
+ switch (ar->version.target_ver) {
+ case AR6003_REV2_VERSION:
+ filename = AR6003_REV2_DEFAULT_BOARD_DATA_FILE;
+ break;
+ case AR6004_REV1_VERSION:
+ filename = AR6004_REV1_DEFAULT_BOARD_DATA_FILE;
+ break;
+ default:
+ filename = AR6003_REV3_DEFAULT_BOARD_DATA_FILE;
+ break;
+ }
+
+ ret = ath6kl_get_fw(ar, filename, &ar->fw_board,
+ &ar->fw_board_len);
+ if (ret) {
+ ath6kl_err("Failed to get default board file %s: %d\n",
+ filename, ret);
+ return ret;
+ }
+
+ ath6kl_warn("WARNING! No proper board file was not found, instead using a default board file.\n");
+ ath6kl_warn("Most likely your hardware won't work as specified. Install correct board file!\n");
+
+ return 0;
+}
+
+static int ath6kl_fetch_otp_file(struct ath6kl *ar)
+{
+ const char *filename;
+ int ret;
+
+ if (ar->fw_otp != NULL)
+ return 0;
+
+ switch (ar->version.target_ver) {
+ case AR6003_REV2_VERSION:
+ filename = AR6003_REV2_OTP_FILE;
+ break;
+ case AR6004_REV1_VERSION:
+ ath6kl_dbg(ATH6KL_DBG_TRC, "AR6004 doesn't need OTP file\n");
+ return 0;
+ break;
+ default:
+ filename = AR6003_REV3_OTP_FILE;
+ break;
+ }
+
+ ret = ath6kl_get_fw(ar, filename, &ar->fw_otp,
+ &ar->fw_otp_len);
+ if (ret) {
+ ath6kl_err("Failed to get OTP file %s: %d\n",
+ filename, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ath6kl_fetch_fw_file(struct ath6kl *ar)
+{
+ const char *filename;
+ int ret;
+
+ if (ar->fw != NULL)
+ return 0;
+
+ if (testmode) {
+ switch (ar->version.target_ver) {
+ case AR6003_REV2_VERSION:
+ filename = AR6003_REV2_TCMD_FIRMWARE_FILE;
+ break;
+ case AR6003_REV3_VERSION:
+ filename = AR6003_REV3_TCMD_FIRMWARE_FILE;
+ break;
+ case AR6004_REV1_VERSION:
+ ath6kl_warn("testmode not supported with ar6004\n");
+ return -EOPNOTSUPP;
+ default:
+ ath6kl_warn("unknown target version: 0x%x\n",
+ ar->version.target_ver);
+ return -EINVAL;
+ }
+
+ set_bit(TESTMODE, &ar->flag);
+
+ goto get_fw;
+ }
+
+ switch (ar->version.target_ver) {
+ case AR6003_REV2_VERSION:
+ filename = AR6003_REV2_FIRMWARE_FILE;
+ break;
+ case AR6004_REV1_VERSION:
+ filename = AR6004_REV1_FIRMWARE_FILE;
+ break;
+ default:
+ filename = AR6003_REV3_FIRMWARE_FILE;
+ break;
+ }
+
+get_fw:
+ ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len);
+ if (ret) {
+ ath6kl_err("Failed to get firmware file %s: %d\n",
+ filename, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ath6kl_fetch_patch_file(struct ath6kl *ar)
+{
+ const char *filename;
+ int ret;
+
+ switch (ar->version.target_ver) {
+ case AR6003_REV2_VERSION:
+ filename = AR6003_REV2_PATCH_FILE;
+ break;
+ case AR6004_REV1_VERSION:
+ /* FIXME: implement for AR6004 */
+ return 0;
+ break;
+ default:
+ filename = AR6003_REV3_PATCH_FILE;
+ break;
+ }
+
+ if (ar->fw_patch == NULL) {
+ ret = ath6kl_get_fw(ar, filename, &ar->fw_patch,
+ &ar->fw_patch_len);
+ if (ret) {
+ ath6kl_err("Failed to get patch file %s: %d\n",
+ filename, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int ath6kl_fetch_fw_api1(struct ath6kl *ar)
+{
+ int ret;
+
+ ret = ath6kl_fetch_otp_file(ar);
+ if (ret)
+ return ret;
+
+ ret = ath6kl_fetch_fw_file(ar);
+ if (ret)
+ return ret;
+
+ ret = ath6kl_fetch_patch_file(ar);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int ath6kl_fetch_fw_api2(struct ath6kl *ar)
+{
+ size_t magic_len, len, ie_len;
+ const struct firmware *fw;
+ struct ath6kl_fw_ie *hdr;
+ const char *filename;
+ const u8 *data;
+ int ret, ie_id, i, index, bit;
+ __le32 *val;
+
+ switch (ar->version.target_ver) {
+ case AR6003_REV2_VERSION:
+ filename = AR6003_REV2_FIRMWARE_2_FILE;
+ break;
+ case AR6003_REV3_VERSION:
+ filename = AR6003_REV3_FIRMWARE_2_FILE;
+ break;
+ case AR6004_REV1_VERSION:
+ filename = AR6004_REV1_FIRMWARE_2_FILE;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ ret = request_firmware(&fw, filename, ar->dev);
+ if (ret)
+ return ret;
+
+ data = fw->data;
+ len = fw->size;
+
+ /* magic also includes the null byte, check that as well */
+ magic_len = strlen(ATH6KL_FIRMWARE_MAGIC) + 1;
+
+ if (len < magic_len) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (memcmp(data, ATH6KL_FIRMWARE_MAGIC, magic_len) != 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ len -= magic_len;
+ data += magic_len;
+
+ /* loop elements */
+ while (len > sizeof(struct ath6kl_fw_ie)) {
+ /* hdr is unaligned! */
+ hdr = (struct ath6kl_fw_ie *) data;
+
+ ie_id = le32_to_cpup(&hdr->id);
+ ie_len = le32_to_cpup(&hdr->len);
+
+ len -= sizeof(*hdr);
+ data += sizeof(*hdr);
+
+ if (len < ie_len) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ switch (ie_id) {
+ case ATH6KL_FW_IE_OTP_IMAGE:
+ ath6kl_dbg(ATH6KL_DBG_BOOT, "found otp image ie (%zd B)\n",
+ ie_len);
+
+ ar->fw_otp = kmemdup(data, ie_len, GFP_KERNEL);
+
+ if (ar->fw_otp == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ar->fw_otp_len = ie_len;
+ break;
+ case ATH6KL_FW_IE_FW_IMAGE:
+ ath6kl_dbg(ATH6KL_DBG_BOOT, "found fw image ie (%zd B)\n",
+ ie_len);
+
+ ar->fw = kmemdup(data, ie_len, GFP_KERNEL);
+
+ if (ar->fw == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ar->fw_len = ie_len;
+ break;
+ case ATH6KL_FW_IE_PATCH_IMAGE:
+ ath6kl_dbg(ATH6KL_DBG_BOOT, "found patch image ie (%zd B)\n",
+ ie_len);
+
+ ar->fw_patch = kmemdup(data, ie_len, GFP_KERNEL);
+
+ if (ar->fw_patch == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ar->fw_patch_len = ie_len;
+ break;
+ case ATH6KL_FW_IE_RESERVED_RAM_SIZE:
+ val = (__le32 *) data;
+ ar->hw.reserved_ram_size = le32_to_cpup(val);
+
+ ath6kl_dbg(ATH6KL_DBG_BOOT,
+ "found reserved ram size ie 0x%d\n",
+ ar->hw.reserved_ram_size);
+ break;
+ case ATH6KL_FW_IE_CAPABILITIES:
+ ath6kl_dbg(ATH6KL_DBG_BOOT,
+ "found firmware capabilities ie (%zd B)\n",
+ ie_len);
+
+ for (i = 0; i < ATH6KL_FW_CAPABILITY_MAX; i++) {
+ index = ALIGN(i, 8) / 8;
+ bit = i % 8;
+
+ if (data[index] & (1 << bit))
+ __set_bit(i, ar->fw_capabilities);
+ }
+
+ ath6kl_dbg_dump(ATH6KL_DBG_BOOT, "capabilities", "",
+ ar->fw_capabilities,
+ sizeof(ar->fw_capabilities));
+ break;
+ case ATH6KL_FW_IE_PATCH_ADDR:
+ if (ie_len != sizeof(*val))
+ break;
+
+ val = (__le32 *) data;
+ ar->hw.dataset_patch_addr = le32_to_cpup(val);
+
+ ath6kl_dbg(ATH6KL_DBG_BOOT,
+ "found patch address ie 0x%d\n",
+ ar->hw.dataset_patch_addr);
+ break;
+ default:
+ ath6kl_dbg(ATH6KL_DBG_BOOT, "Unknown fw ie: %u\n",
+ le32_to_cpup(&hdr->id));
+ break;
+ }
+
+ len -= ie_len;
+ data += ie_len;
+ };
+
+ ret = 0;
+out:
+ release_firmware(fw);
+
+ return ret;
+}
+
+static int ath6kl_fetch_firmwares(struct ath6kl *ar)
+{
+ int ret;
+
+ ret = ath6kl_fetch_board_file(ar);
+ if (ret)
+ return ret;
+
+ ret = ath6kl_fetch_fw_api2(ar);
+ if (ret == 0) {
+ ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api 2\n");
+ return 0;
+ }
+
+ ret = ath6kl_fetch_fw_api1(ar);
+ if (ret)
+ return ret;
+
+ ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api 1\n");
+
+ return 0;
+}
+
+static int ath6kl_upload_board_file(struct ath6kl *ar)
+{
+ u32 board_address, board_ext_address, param;
+ u32 board_data_size, board_ext_data_size;
+ int ret;
+
+ if (WARN_ON(ar->fw_board == NULL))
+ return -ENOENT;
+
+ /*
+ * Determine where in Target RAM to write Board Data.
+ * For AR6004, host determine Target RAM address for
+ * writing board data.
+ */
+ if (ar->target_type == TARGET_TYPE_AR6004) {
+ board_address = AR6004_REV1_BOARD_DATA_ADDRESS;
+ ath6kl_bmi_write(ar,
+ ath6kl_get_hi_item_addr(ar,
+ HI_ITEM(hi_board_data)),
+ (u8 *) &board_address, 4);
+ } else {
+ ath6kl_bmi_read(ar,
+ ath6kl_get_hi_item_addr(ar,
+ HI_ITEM(hi_board_data)),
+ (u8 *) &board_address, 4);
+ }
+
+ /* determine where in target ram to write extended board data */
+ ath6kl_bmi_read(ar,
+ ath6kl_get_hi_item_addr(ar,
+ HI_ITEM(hi_board_ext_data)),
+ (u8 *) &board_ext_address, 4);
+
+ if (board_ext_address == 0) {
+ ath6kl_err("Failed to get board file target address.\n");
+ return -EINVAL;
+ }
+
+ switch (ar->target_type) {
+ case TARGET_TYPE_AR6003:
+ board_data_size = AR6003_BOARD_DATA_SZ;
+ board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ;
+ break;
+ case TARGET_TYPE_AR6004:
+ board_data_size = AR6004_BOARD_DATA_SZ;
+ board_ext_data_size = AR6004_BOARD_EXT_DATA_SZ;
+ break;
+ default:
+ WARN_ON(1);
+ return -EINVAL;
+ break;
+ }
+
+ if (ar->fw_board_len == (board_data_size +
+ board_ext_data_size)) {
+
+ /* write extended board data */
+ ath6kl_dbg(ATH6KL_DBG_BOOT,
+ "writing extended board data to 0x%x (%d B)\n",
+ board_ext_address, board_ext_data_size);
+
+ ret = ath6kl_bmi_write(ar, board_ext_address,
+ ar->fw_board + board_data_size,
+ board_ext_data_size);
+ if (ret) {
+ ath6kl_err("Failed to write extended board data: %d\n",
+ ret);
+ return ret;
+ }
+
+ /* record that extended board data is initialized */
+ param = (board_ext_data_size << 16) | 1;
+
+ ath6kl_bmi_write(ar,
+ ath6kl_get_hi_item_addr(ar,
+ HI_ITEM(hi_board_ext_data_config)),
+ (unsigned char *) &param, 4);
+ }
+
+ if (ar->fw_board_len < board_data_size) {
+ ath6kl_err("Too small board file: %zu\n", ar->fw_board_len);
+ ret = -EINVAL;
+ return ret;
+ }
+
+ ath6kl_dbg(ATH6KL_DBG_BOOT, "writing board file to 0x%x (%d B)\n",
+ board_address, board_data_size);
+
+ ret = ath6kl_bmi_write(ar, board_address, ar->fw_board,
+ board_data_size);
+
+ if (ret) {
+ ath6kl_err("Board file bmi write failed: %d\n", ret);
+ return ret;
+ }
+
+ /* record the fact that Board Data IS initialized */
+ param = 1;
+ ath6kl_bmi_write(ar,
+ ath6kl_get_hi_item_addr(ar,
+ HI_ITEM(hi_board_data_initialized)),
+ (u8 *)&param, 4);
+
+ return ret;
+}
+
+static int ath6kl_upload_otp(struct ath6kl *ar)
+{
+ u32 address, param;
+ int ret;
+
+ if (WARN_ON(ar->fw_otp == NULL))
+ return -ENOENT;
+
+ address = ar->hw.app_load_addr;
+
+ ath6kl_dbg(ATH6KL_DBG_BOOT, "writing otp to 0x%x (%zd B)\n", address,
+ ar->fw_otp_len);
+
+ ret = ath6kl_bmi_fast_download(ar, address, ar->fw_otp,
+ ar->fw_otp_len);
+ if (ret) {
+ ath6kl_err("Failed to upload OTP file: %d\n", ret);
+ return ret;
+ }
+
+ /* read firmware start address */
+ ret = ath6kl_bmi_read(ar,
+ ath6kl_get_hi_item_addr(ar,
+ HI_ITEM(hi_app_start)),
+ (u8 *) &address, sizeof(address));
+
+ if (ret) {
+ ath6kl_err("Failed to read hi_app_start: %d\n", ret);
+ return ret;
+ }
+
+ ar->hw.app_start_override_addr = address;
+
+ ath6kl_dbg(ATH6KL_DBG_BOOT, "app_start_override_addr 0x%x\n",
+ ar->hw.app_start_override_addr);
+
+ /* execute the OTP code */
+ ath6kl_dbg(ATH6KL_DBG_BOOT, "executing OTP at 0x%x\n", address);
+ param = 0;
+ ath6kl_bmi_execute(ar, address, &param);
+
+ return ret;
+}
+
+static int ath6kl_upload_firmware(struct ath6kl *ar)
+{
+ u32 address;
+ int ret;
+
+ if (WARN_ON(ar->fw == NULL))
+ return -ENOENT;
+
+ address = ar->hw.app_load_addr;
+
+ ath6kl_dbg(ATH6KL_DBG_BOOT, "writing firmware to 0x%x (%zd B)\n",
+ address, ar->fw_len);
+
+ ret = ath6kl_bmi_fast_download(ar, address, ar->fw, ar->fw_len);
+
+ if (ret) {
+ ath6kl_err("Failed to write firmware: %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * Set starting address for firmware
+ * Don't need to setup app_start override addr on AR6004
+ */
+ if (ar->target_type != TARGET_TYPE_AR6004) {
+ address = ar->hw.app_start_override_addr;
+ ath6kl_bmi_set_app_start(ar, address);
+ }
+ return ret;
+}
+
+static int ath6kl_upload_patch(struct ath6kl *ar)
+{
+ u32 address, param;
+ int ret;
+
+ if (WARN_ON(ar->fw_patch == NULL))
+ return -ENOENT;
+
+ address = ar->hw.dataset_patch_addr;
+
+ ath6kl_dbg(ATH6KL_DBG_BOOT, "writing patch to 0x%x (%zd B)\n",
+ address, ar->fw_patch_len);
+
+ ret = ath6kl_bmi_write(ar, address, ar->fw_patch, ar->fw_patch_len);
+ if (ret) {
+ ath6kl_err("Failed to write patch file: %d\n", ret);
+ return ret;
+ }
+
+ param = address;
+ ath6kl_bmi_write(ar,
+ ath6kl_get_hi_item_addr(ar,
+ HI_ITEM(hi_dset_list_head)),
+ (unsigned char *) &param, 4);
+
+ return 0;
+}
+
+static int ath6kl_init_upload(struct ath6kl *ar)
+{
+ u32 param, options, sleep, address;
+ int status = 0;
+
+ if (ar->target_type != TARGET_TYPE_AR6003 &&
+ ar->target_type != TARGET_TYPE_AR6004)
+ return -EINVAL;
+
+ /* temporarily disable system sleep */
+ address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS;
+ status = ath6kl_bmi_reg_read(ar, address, &param);
+ if (status)
+ return status;
+
+ options = param;
+
+ param |= ATH6KL_OPTION_SLEEP_DISABLE;
+ status = ath6kl_bmi_reg_write(ar, address, param);
+ if (status)
+ return status;
+
+ address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS;
+ status = ath6kl_bmi_reg_read(ar, address, &param);
+ if (status)
+ return status;
+
+ sleep = param;
+
+ param |= SM(SYSTEM_SLEEP_DISABLE, 1);
+ status = ath6kl_bmi_reg_write(ar, address, param);
+ if (status)
+ return status;
+
+ ath6kl_dbg(ATH6KL_DBG_TRC, "old options: %d, old sleep: %d\n",
+ options, sleep);
+
+ /* program analog PLL register */
+ /* no need to control 40/44MHz clock on AR6004 */
+ if (ar->target_type != TARGET_TYPE_AR6004) {
+ status = ath6kl_bmi_reg_write(ar, ATH6KL_ANALOG_PLL_REGISTER,
+ 0xF9104001);
+
+ if (status)
+ return status;
+
+ /* Run at 80/88MHz by default */
+ param = SM(CPU_CLOCK_STANDARD, 1);
+
+ address = RTC_BASE_ADDRESS + CPU_CLOCK_ADDRESS;
+ status = ath6kl_bmi_reg_write(ar, address, param);
+ if (status)
+ return status;
+ }
+
+ param = 0;
+ address = RTC_BASE_ADDRESS + LPO_CAL_ADDRESS;
+ param = SM(LPO_CAL_ENABLE, 1);
+ status = ath6kl_bmi_reg_write(ar, address, param);
+ if (status)
+ return status;
+
+ /* WAR to avoid SDIO CRC err */
+ if (ar->version.target_ver == AR6003_REV2_VERSION) {
+ ath6kl_err("temporary war to avoid sdio crc error\n");
+
+ param = 0x20;
+
+ address = GPIO_BASE_ADDRESS + GPIO_PIN10_ADDRESS;
+ status = ath6kl_bmi_reg_write(ar, address, param);
+ if (status)
+ return status;
+
+ address = GPIO_BASE_ADDRESS + GPIO_PIN11_ADDRESS;
+ status = ath6kl_bmi_reg_write(ar, address, param);
+ if (status)
+ return status;
+
+ address = GPIO_BASE_ADDRESS + GPIO_PIN12_ADDRESS;
+ status = ath6kl_bmi_reg_write(ar, address, param);
+ if (status)
+ return status;
+
+ address = GPIO_BASE_ADDRESS + GPIO_PIN13_ADDRESS;
+ status = ath6kl_bmi_reg_write(ar, address, param);
+ if (status)
+ return status;
+ }
+
+ /* write EEPROM data to Target RAM */
+ status = ath6kl_upload_board_file(ar);
+ if (status)
+ return status;
+
+ /* transfer One time Programmable data */
+ status = ath6kl_upload_otp(ar);
+ if (status)
+ return status;
+
+ /* Download Target firmware */
+ status = ath6kl_upload_firmware(ar);
+ if (status)
+ return status;
+
+ status = ath6kl_upload_patch(ar);
+ if (status)
+ return status;
+
+ /* Restore system sleep */
+ address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS;
+ status = ath6kl_bmi_reg_write(ar, address, sleep);
+ if (status)
+ return status;
+
+ address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS;
+ param = options | 0x20;
+ status = ath6kl_bmi_reg_write(ar, address, param);
+ if (status)
+ return status;
+
+ /* Configure GPIO AR6003 UART */
+ param = CONFIG_AR600x_DEBUG_UART_TX_PIN;
+ status = ath6kl_bmi_write(ar,
+ ath6kl_get_hi_item_addr(ar,
+ HI_ITEM(hi_dbg_uart_txpin)),
+ (u8 *)&param, 4);
+
+ return status;
+}
+
+static int ath6kl_init_hw_params(struct ath6kl *ar)
+{
+ switch (ar->version.target_ver) {
+ case AR6003_REV2_VERSION:
+ ar->hw.dataset_patch_addr = AR6003_REV2_DATASET_PATCH_ADDRESS;
+ ar->hw.app_load_addr = AR6003_REV2_APP_LOAD_ADDRESS;
+ ar->hw.board_ext_data_addr = AR6003_REV2_BOARD_EXT_DATA_ADDRESS;
+ ar->hw.reserved_ram_size = AR6003_REV2_RAM_RESERVE_SIZE;
+ break;
+ case AR6003_REV3_VERSION:
+ ar->hw.dataset_patch_addr = AR6003_REV3_DATASET_PATCH_ADDRESS;
+ ar->hw.app_load_addr = 0x1234;
+ ar->hw.board_ext_data_addr = AR6003_REV3_BOARD_EXT_DATA_ADDRESS;
+ ar->hw.reserved_ram_size = AR6003_REV3_RAM_RESERVE_SIZE;
+ break;
+ case AR6004_REV1_VERSION:
+ ar->hw.dataset_patch_addr = AR6003_REV2_DATASET_PATCH_ADDRESS;
+ ar->hw.app_load_addr = AR6003_REV3_APP_LOAD_ADDRESS;
+ ar->hw.board_ext_data_addr = AR6004_REV1_BOARD_EXT_DATA_ADDRESS;
+ ar->hw.reserved_ram_size = AR6004_REV1_RAM_RESERVE_SIZE;
+ break;
+ default:
+ ath6kl_err("Unsupported hardware version: 0x%x\n",
+ ar->version.target_ver);
+ return -EINVAL;
+ }
+
+ ath6kl_dbg(ATH6KL_DBG_BOOT,
+ "target_ver 0x%x target_type 0x%x dataset_patch 0x%x app_load_addr 0x%x\n",
+ ar->version.target_ver, ar->target_type,
+ ar->hw.dataset_patch_addr, ar->hw.app_load_addr);
+ ath6kl_dbg(ATH6KL_DBG_BOOT,
+ "app_start_override_addr 0x%x board_ext_data_addr 0x%x reserved_ram_size 0x%x",
+ ar->hw.app_start_override_addr, ar->hw.board_ext_data_addr,
+ ar->hw.reserved_ram_size);
+
+ return 0;
+}
+
+static int ath6kl_init(struct net_device *dev)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+ int status = 0;
+ s32 timeleft;
+
+ if (!ar)
+ return -EIO;
+
+ /* Do we need to finish the BMI phase */
+ if (ath6kl_bmi_done(ar)) {
+ status = -EIO;
+ goto ath6kl_init_done;
+ }
+
+ /* Indicate that WMI is enabled (although not ready yet) */
+ set_bit(WMI_ENABLED, &ar->flag);
+ ar->wmi = ath6kl_wmi_init(ar);
+ if (!ar->wmi) {
+ ath6kl_err("failed to initialize wmi\n");
+ status = -EIO;
+ goto ath6kl_init_done;
+ }
+
+ ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi);
+
+ /*
+ * The reason we have to wait for the target here is that the
+ * driver layer has to init BMI in order to set the host block
+ * size.
+ */
+ if (ath6kl_htc_wait_target(ar->htc_target)) {
+ status = -EIO;
+ goto err_node_cleanup;
+ }
+
+ if (ath6kl_init_service_ep(ar)) {
+ status = -EIO;
+ goto err_cleanup_scatter;
+ }
+
+ /* setup access class priority mappings */
+ ar->ac_stream_pri_map[WMM_AC_BK] = 0; /* lowest */
+ ar->ac_stream_pri_map[WMM_AC_BE] = 1;
+ ar->ac_stream_pri_map[WMM_AC_VI] = 2;
+ ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */
+
+ /* give our connected endpoints some buffers */
+ ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep);
+ ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]);
+
+ /* allocate some buffers that handle larger AMSDU frames */
+ ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS);
+
+ /* setup credit distribution */
+ ath6k_setup_credit_dist(ar->htc_target, &ar->credit_state_info);
+
+ ath6kl_cookie_init(ar);
+
+ /* start HTC */
+ status = ath6kl_htc_start(ar->htc_target);
+
+ if (status) {
+ ath6kl_cookie_cleanup(ar);
+ goto err_rxbuf_cleanup;
+ }
+
+ /* Wait for Wmi event to be ready */
+ timeleft = wait_event_interruptible_timeout(ar->event_wq,
+ test_bit(WMI_READY,
+ &ar->flag),
+ WMI_TIMEOUT);
+
+ ath6kl_dbg(ATH6KL_DBG_BOOT, "firmware booted\n");
+
+ if (ar->version.abi_ver != ATH6KL_ABI_VERSION) {
+ ath6kl_err("abi version mismatch: host(0x%x), target(0x%x)\n",
+ ATH6KL_ABI_VERSION, ar->version.abi_ver);
+ status = -EIO;
+ goto err_htc_stop;
+ }
+
+ if (!timeleft || signal_pending(current)) {
+ ath6kl_err("wmi is not ready or wait was interrupted\n");
+ status = -EIO;
+ goto err_htc_stop;
+ }
+
+ ath6kl_dbg(ATH6KL_DBG_TRC, "%s: wmi is ready\n", __func__);
+
+ /* communicate the wmi protocol verision to the target */
+ if ((ath6kl_set_host_app_area(ar)) != 0)
+ ath6kl_err("unable to set the host app area\n");
+
+ ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER |
+ ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST;
+
+ ar->wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
+
+ status = ath6kl_target_config_wlan_params(ar);
+ if (!status)
+ goto ath6kl_init_done;
+
+err_htc_stop:
+ ath6kl_htc_stop(ar->htc_target);
+err_rxbuf_cleanup:
+ ath6kl_htc_flush_rx_buf(ar->htc_target);
+ ath6kl_cleanup_amsdu_rxbufs(ar);
+err_cleanup_scatter:
+ ath6kl_hif_cleanup_scatter(ar);
+err_node_cleanup:
+ ath6kl_wmi_shutdown(ar->wmi);
+ clear_bit(WMI_ENABLED, &ar->flag);
+ ar->wmi = NULL;
+
+ath6kl_init_done:
+ return status;
+}
+
+int ath6kl_core_init(struct ath6kl *ar)
+{
+ int ret = 0;
+ struct ath6kl_bmi_target_info targ_info;
+
+ ar->ath6kl_wq = create_singlethread_workqueue("ath6kl");
+ if (!ar->ath6kl_wq)
+ return -ENOMEM;
+
+ ret = ath6kl_bmi_init(ar);
+ if (ret)
+ goto err_wq;
+
+ ret = ath6kl_bmi_get_target_info(ar, &targ_info);
+ if (ret)
+ goto err_bmi_cleanup;
+
+ ar->version.target_ver = le32_to_cpu(targ_info.version);
+ ar->target_type = le32_to_cpu(targ_info.type);
+ ar->wdev->wiphy->hw_version = le32_to_cpu(targ_info.version);
+
+ ret = ath6kl_init_hw_params(ar);
+ if (ret)
+ goto err_bmi_cleanup;
+
+ ret = ath6kl_configure_target(ar);
+ if (ret)
+ goto err_bmi_cleanup;
+
+ ar->htc_target = ath6kl_htc_create(ar);
+
+ if (!ar->htc_target) {
+ ret = -ENOMEM;
+ goto err_bmi_cleanup;
+ }
+
+ ar->aggr_cntxt = aggr_init(ar->net_dev);
+ if (!ar->aggr_cntxt) {
+ ath6kl_err("failed to initialize aggr\n");
+ ret = -ENOMEM;
+ goto err_htc_cleanup;
+ }
+
+ ret = ath6kl_fetch_firmwares(ar);
+ if (ret)
+ goto err_htc_cleanup;
+
+ ret = ath6kl_init_upload(ar);
+ if (ret)
+ goto err_htc_cleanup;
+
+ ret = ath6kl_init(ar->net_dev);
+ if (ret)
+ goto err_htc_cleanup;
+
+ /* This runs the init function if registered */
+ ret = register_netdev(ar->net_dev);
+ if (ret) {
+ ath6kl_err("register_netdev failed\n");
+ ath6kl_destroy(ar->net_dev, 0);
+ return ret;
+ }
+
+ set_bit(NETDEV_REGISTERED, &ar->flag);
+
+ ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n",
+ __func__, ar->net_dev->name, ar->net_dev, ar);
+
+ return ret;
+
+err_htc_cleanup:
+ ath6kl_htc_cleanup(ar->htc_target);
+err_bmi_cleanup:
+ ath6kl_bmi_cleanup(ar);
+err_wq:
+ destroy_workqueue(ar->ath6kl_wq);
+ return ret;
+}
+
+void ath6kl_stop_txrx(struct ath6kl *ar)
+{
+ struct net_device *ndev = ar->net_dev;
+
+ if (!ndev)
+ return;
+
+ set_bit(DESTROY_IN_PROGRESS, &ar->flag);
+
+ if (down_interruptible(&ar->sem)) {
+ ath6kl_err("down_interruptible failed\n");
+ return;
+ }
+
+ if (ar->wlan_pwr_state != WLAN_POWER_STATE_CUT_PWR)
+ ath6kl_stop_endpoint(ndev, false, true);
+
+ clear_bit(WLAN_ENABLED, &ar->flag);
+}
+
+/*
+ * We need to differentiate between the surprise and planned removal of the
+ * device because of the following consideration:
+ *
+ * - In case of surprise removal, the hcd already frees up the pending
+ * for the device and hence there is no need to unregister the function
+ * driver inorder to get these requests. For planned removal, the function
+ * driver has to explicitly unregister itself to have the hcd return all the
+ * pending requests before the data structures for the devices are freed up.
+ * Note that as per the current implementation, the function driver will
+ * end up releasing all the devices since there is no API to selectively
+ * release a particular device.
+ *
+ * - Certain commands issued to the target can be skipped for surprise
+ * removal since they will anyway not go through.
+ */
+void ath6kl_destroy(struct net_device *dev, unsigned int unregister)
+{
+ struct ath6kl *ar;
+
+ if (!dev || !ath6kl_priv(dev)) {
+ ath6kl_err("failed to get device structure\n");
+ return;
+ }
+
+ ar = ath6kl_priv(dev);
+
+ destroy_workqueue(ar->ath6kl_wq);
+
+ if (ar->htc_target)
+ ath6kl_htc_cleanup(ar->htc_target);
+
+ aggr_module_destroy(ar->aggr_cntxt);
+
+ ath6kl_cookie_cleanup(ar);
+
+ ath6kl_cleanup_amsdu_rxbufs(ar);
+
+ ath6kl_bmi_cleanup(ar);
+
+ ath6kl_debug_cleanup(ar);
+
+ if (unregister && test_bit(NETDEV_REGISTERED, &ar->flag)) {
+ unregister_netdev(dev);
+ clear_bit(NETDEV_REGISTERED, &ar->flag);
+ }
+
+ free_netdev(dev);
+
+ kfree(ar->fw_board);
+ kfree(ar->fw_otp);
+ kfree(ar->fw);
+ kfree(ar->fw_patch);
+
+ ath6kl_cfg80211_deinit(ar);
+}
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
new file mode 100644
index 000000000000..30b5a53db9ed
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -0,0 +1,1477 @@
+/*
+ * Copyright (c) 2004-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "hif-ops.h"
+#include "cfg80211.h"
+#include "target.h"
+#include "debug.h"
+
+struct ath6kl_sta *ath6kl_find_sta(struct ath6kl *ar, u8 *node_addr)
+{
+ struct ath6kl_sta *conn = NULL;
+ u8 i, max_conn;
+
+ max_conn = (ar->nw_type == AP_NETWORK) ? AP_MAX_NUM_STA : 0;
+
+ for (i = 0; i < max_conn; i++) {
+ if (memcmp(node_addr, ar->sta_list[i].mac, ETH_ALEN) == 0) {
+ conn = &ar->sta_list[i];
+ break;
+ }
+ }
+
+ return conn;
+}
+
+struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid)
+{
+ struct ath6kl_sta *conn = NULL;
+ u8 ctr;
+
+ for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
+ if (ar->sta_list[ctr].aid == aid) {
+ conn = &ar->sta_list[ctr];
+ break;
+ }
+ }
+ return conn;
+}
+
+static void ath6kl_add_new_sta(struct ath6kl *ar, u8 *mac, u16 aid, u8 *wpaie,
+ u8 ielen, u8 keymgmt, u8 ucipher, u8 auth)
+{
+ struct ath6kl_sta *sta;
+ u8 free_slot;
+
+ free_slot = aid - 1;
+
+ sta = &ar->sta_list[free_slot];
+ memcpy(sta->mac, mac, ETH_ALEN);
+ if (ielen <= ATH6KL_MAX_IE)
+ memcpy(sta->wpa_ie, wpaie, ielen);
+ sta->aid = aid;
+ sta->keymgmt = keymgmt;
+ sta->ucipher = ucipher;
+ sta->auth = auth;
+
+ ar->sta_list_index = ar->sta_list_index | (1 << free_slot);
+ ar->ap_stats.sta[free_slot].aid = cpu_to_le32(aid);
+}
+
+static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i)
+{
+ struct ath6kl_sta *sta = &ar->sta_list[i];
+
+ /* empty the queued pkts in the PS queue if any */
+ spin_lock_bh(&sta->psq_lock);
+ skb_queue_purge(&sta->psq);
+ spin_unlock_bh(&sta->psq_lock);
+
+ memset(&ar->ap_stats.sta[sta->aid - 1], 0,
+ sizeof(struct wmi_per_sta_stat));
+ memset(sta->mac, 0, ETH_ALEN);
+ memset(sta->wpa_ie, 0, ATH6KL_MAX_IE);
+ sta->aid = 0;
+ sta->sta_flags = 0;
+
+ ar->sta_list_index = ar->sta_list_index & ~(1 << i);
+
+}
+
+static u8 ath6kl_remove_sta(struct ath6kl *ar, u8 *mac, u16 reason)
+{
+ u8 i, removed = 0;
+
+ if (is_zero_ether_addr(mac))
+ return removed;
+
+ if (is_broadcast_ether_addr(mac)) {
+ ath6kl_dbg(ATH6KL_DBG_TRC, "deleting all station\n");
+
+ for (i = 0; i < AP_MAX_NUM_STA; i++) {
+ if (!is_zero_ether_addr(ar->sta_list[i].mac)) {
+ ath6kl_sta_cleanup(ar, i);
+ removed = 1;
+ }
+ }
+ } else {
+ for (i = 0; i < AP_MAX_NUM_STA; i++) {
+ if (memcmp(ar->sta_list[i].mac, mac, ETH_ALEN) == 0) {
+ ath6kl_dbg(ATH6KL_DBG_TRC,
+ "deleting station %pM aid=%d reason=%d\n",
+ mac, ar->sta_list[i].aid, reason);
+ ath6kl_sta_cleanup(ar, i);
+ removed = 1;
+ break;
+ }
+ }
+ }
+
+ return removed;
+}
+
+enum htc_endpoint_id ath6kl_ac2_endpoint_id(void *devt, u8 ac)
+{
+ struct ath6kl *ar = devt;
+ return ar->ac2ep_map[ac];
+}
+
+struct ath6kl_cookie *ath6kl_alloc_cookie(struct ath6kl *ar)
+{
+ struct ath6kl_cookie *cookie;
+
+ cookie = ar->cookie_list;
+ if (cookie != NULL) {
+ ar->cookie_list = cookie->arc_list_next;
+ ar->cookie_count--;
+ }
+
+ return cookie;
+}
+
+void ath6kl_cookie_init(struct ath6kl *ar)
+{
+ u32 i;
+
+ ar->cookie_list = NULL;
+ ar->cookie_count = 0;
+
+ memset(ar->cookie_mem, 0, sizeof(ar->cookie_mem));
+
+ for (i = 0; i < MAX_COOKIE_NUM; i++)
+ ath6kl_free_cookie(ar, &ar->cookie_mem[i]);
+}
+
+void ath6kl_cookie_cleanup(struct ath6kl *ar)
+{
+ ar->cookie_list = NULL;
+ ar->cookie_count = 0;
+}
+
+void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie)
+{
+ /* Insert first */
+
+ if (!ar || !cookie)
+ return;
+
+ cookie->arc_list_next = ar->cookie_list;
+ ar->cookie_list = cookie;
+ ar->cookie_count++;
+}
+
+/* set the window address register (using 4-byte register access ). */
+static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr)
+{
+ int status;
+ s32 i;
+ __le32 addr_val;
+
+ /*
+ * Write bytes 1,2,3 of the register to set the upper address bytes,
+ * the LSB is written last to initiate the access cycle
+ */
+
+ for (i = 1; i <= 3; i++) {
+ /*
+ * Fill the buffer with the address byte value we want to
+ * hit 4 times. No need to worry about endianness as the
+ * same byte is copied to all four bytes of addr_val at
+ * any time.
+ */
+ memset((u8 *)&addr_val, ((u8 *)&addr)[i], 4);
+
+ /*
+ * Hit each byte of the register address with a 4-byte
+ * write operation to the same address, this is a harmless
+ * operation.
+ */
+ status = hif_read_write_sync(ar, reg_addr + i, (u8 *)&addr_val,
+ 4, HIF_WR_SYNC_BYTE_FIX);
+ if (status)
+ break;
+ }
+
+ if (status) {
+ ath6kl_err("failed to write initial bytes of 0x%x to window reg: 0x%X\n",
+ addr, reg_addr);
+ return status;
+ }
+
+ /*
+ * Write the address register again, this time write the whole
+ * 4-byte value. The effect here is that the LSB write causes the
+ * cycle to start, the extra 3 byte write to bytes 1,2,3 has no
+ * effect since we are writing the same values again
+ */
+ addr_val = cpu_to_le32(addr);
+ status = hif_read_write_sync(ar, reg_addr,
+ (u8 *)&(addr_val),
+ 4, HIF_WR_SYNC_BYTE_INC);
+
+ if (status) {
+ ath6kl_err("failed to write 0x%x to window reg: 0x%X\n",
+ addr, reg_addr);
+ return status;
+ }
+
+ return 0;
+}
+
+/*
+ * Read from the hardware through its diagnostic window. No cooperation
+ * from the firmware is required for this.
+ */
+int ath6kl_diag_read32(struct ath6kl *ar, u32 address, u32 *value)
+{
+ int ret;
+
+ /* set window register to start read cycle */
+ ret = ath6kl_set_addrwin_reg(ar, WINDOW_READ_ADDR_ADDRESS, address);
+ if (ret)
+ return ret;
+
+ /* read the data */
+ ret = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *) value,
+ sizeof(*value), HIF_RD_SYNC_BYTE_INC);
+ if (ret) {
+ ath6kl_warn("failed to read32 through diagnose window: %d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * Write to the ATH6KL through its diagnostic window. No cooperation from
+ * the Target is required for this.
+ */
+int ath6kl_diag_write32(struct ath6kl *ar, u32 address, __le32 value)
+{
+ int ret;
+
+ /* set write data */
+ ret = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *) &value,
+ sizeof(value), HIF_WR_SYNC_BYTE_INC);
+ if (ret) {
+ ath6kl_err("failed to write 0x%x during diagnose window to 0x%d\n",
+ address, value);
+ return ret;
+ }
+
+ /* set window register, which starts the write cycle */
+ return ath6kl_set_addrwin_reg(ar, WINDOW_WRITE_ADDR_ADDRESS,
+ address);
+}
+
+int ath6kl_diag_read(struct ath6kl *ar, u32 address, void *data, u32 length)
+{
+ u32 count, *buf = data;
+ int ret;
+
+ if (WARN_ON(length % 4))
+ return -EINVAL;
+
+ for (count = 0; count < length / 4; count++, address += 4) {
+ ret = ath6kl_diag_read32(ar, address, &buf[count]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int ath6kl_diag_write(struct ath6kl *ar, u32 address, void *data, u32 length)
+{
+ u32 count;
+ __le32 *buf = data;
+ int ret;
+
+ if (WARN_ON(length % 4))
+ return -EINVAL;
+
+ for (count = 0; count < length / 4; count++, address += 4) {
+ ret = ath6kl_diag_write32(ar, address, buf[count]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int ath6kl_read_fwlogs(struct ath6kl *ar)
+{
+ struct ath6kl_dbglog_hdr debug_hdr;
+ struct ath6kl_dbglog_buf debug_buf;
+ u32 address, length, dropped, firstbuf, debug_hdr_addr;
+ int ret = 0, loop;
+ u8 *buf;
+
+ buf = kmalloc(ATH6KL_FWLOG_PAYLOAD_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ address = TARG_VTOP(ar->target_type,
+ ath6kl_get_hi_item_addr(ar,
+ HI_ITEM(hi_dbglog_hdr)));
+
+ ret = ath6kl_diag_read32(ar, address, &debug_hdr_addr);
+ if (ret)
+ goto out;
+
+ /* Get the contents of the ring buffer */
+ if (debug_hdr_addr == 0) {
+ ath6kl_warn("Invalid address for debug_hdr_addr\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ address = TARG_VTOP(ar->target_type, debug_hdr_addr);
+ ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr));
+
+ address = TARG_VTOP(ar->target_type,
+ le32_to_cpu(debug_hdr.dbuf_addr));
+ firstbuf = address;
+ dropped = le32_to_cpu(debug_hdr.dropped);
+ ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf));
+
+ loop = 100;
+
+ do {
+ address = TARG_VTOP(ar->target_type,
+ le32_to_cpu(debug_buf.buffer_addr));
+ length = le32_to_cpu(debug_buf.length);
+
+ if (length != 0 && (le32_to_cpu(debug_buf.length) <=
+ le32_to_cpu(debug_buf.bufsize))) {
+ length = ALIGN(length, 4);
+
+ ret = ath6kl_diag_read(ar, address,
+ buf, length);
+ if (ret)
+ goto out;
+
+ ath6kl_debug_fwlog_event(ar, buf, length);
+ }
+
+ address = TARG_VTOP(ar->target_type,
+ le32_to_cpu(debug_buf.next));
+ ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf));
+ if (ret)
+ goto out;
+
+ loop--;
+
+ if (WARN_ON(loop == 0)) {
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+ } while (address != firstbuf);
+
+out:
+ kfree(buf);
+
+ return ret;
+}
+
+/* FIXME: move to a better place, target.h? */
+#define AR6003_RESET_CONTROL_ADDRESS 0x00004000
+#define AR6004_RESET_CONTROL_ADDRESS 0x00004000
+
+static void ath6kl_reset_device(struct ath6kl *ar, u32 target_type,
+ bool wait_fot_compltn, bool cold_reset)
+{
+ int status = 0;
+ u32 address;
+ __le32 data;
+
+ if (target_type != TARGET_TYPE_AR6003 &&
+ target_type != TARGET_TYPE_AR6004)
+ return;
+
+ data = cold_reset ? cpu_to_le32(RESET_CONTROL_COLD_RST) :
+ cpu_to_le32(RESET_CONTROL_MBOX_RST);
+
+ switch (target_type) {
+ case TARGET_TYPE_AR6003:
+ address = AR6003_RESET_CONTROL_ADDRESS;
+ break;
+ case TARGET_TYPE_AR6004:
+ address = AR6004_RESET_CONTROL_ADDRESS;
+ break;
+ default:
+ address = AR6003_RESET_CONTROL_ADDRESS;
+ break;
+ }
+
+ status = ath6kl_diag_write32(ar, address, data);
+
+ if (status)
+ ath6kl_err("failed to reset target\n");
+}
+
+void ath6kl_stop_endpoint(struct net_device *dev, bool keep_profile,
+ bool get_dbglogs)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+ static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ bool discon_issued;
+
+ netif_stop_queue(dev);
+
+ /* disable the target and the interrupts associated with it */
+ if (test_bit(WMI_READY, &ar->flag)) {
+ discon_issued = (test_bit(CONNECTED, &ar->flag) ||
+ test_bit(CONNECT_PEND, &ar->flag));
+ ath6kl_disconnect(ar);
+ if (!keep_profile)
+ ath6kl_init_profile_info(ar);
+
+ del_timer(&ar->disconnect_timer);
+
+ clear_bit(WMI_READY, &ar->flag);
+ ath6kl_wmi_shutdown(ar->wmi);
+ clear_bit(WMI_ENABLED, &ar->flag);
+ ar->wmi = NULL;
+
+ /*
+ * After wmi_shudown all WMI events will be dropped. We
+ * need to cleanup the buffers allocated in AP mode and
+ * give disconnect notification to stack, which usually
+ * happens in the disconnect_event. Simulate the disconnect
+ * event by calling the function directly. Sometimes
+ * disconnect_event will be received when the debug logs
+ * are collected.
+ */
+ if (discon_issued)
+ ath6kl_disconnect_event(ar, DISCONNECT_CMD,
+ (ar->nw_type & AP_NETWORK) ?
+ bcast_mac : ar->bssid,
+ 0, NULL, 0);
+
+ ar->user_key_ctrl = 0;
+
+ } else {
+ ath6kl_dbg(ATH6KL_DBG_TRC,
+ "%s: wmi is not ready 0x%p 0x%p\n",
+ __func__, ar, ar->wmi);
+
+ /* Shut down WMI if we have started it */
+ if (test_bit(WMI_ENABLED, &ar->flag)) {
+ ath6kl_dbg(ATH6KL_DBG_TRC,
+ "%s: shut down wmi\n", __func__);
+ ath6kl_wmi_shutdown(ar->wmi);
+ clear_bit(WMI_ENABLED, &ar->flag);
+ ar->wmi = NULL;
+ }
+ }
+
+ if (ar->htc_target) {
+ ath6kl_dbg(ATH6KL_DBG_TRC, "%s: shut down htc\n", __func__);
+ ath6kl_htc_stop(ar->htc_target);
+ }
+
+ /*
+ * Try to reset the device if we can. The driver may have been
+ * configure NOT to reset the target during a debug session.
+ */
+ ath6kl_dbg(ATH6KL_DBG_TRC,
+ "attempting to reset target on instance destroy\n");
+ ath6kl_reset_device(ar, ar->target_type, true, true);
+}
+
+static void ath6kl_install_static_wep_keys(struct ath6kl *ar)
+{
+ u8 index;
+ u8 keyusage;
+
+ for (index = WMI_MIN_KEY_INDEX; index <= WMI_MAX_KEY_INDEX; index++) {
+ if (ar->wep_key_list[index].key_len) {
+ keyusage = GROUP_USAGE;
+ if (index == ar->def_txkey_index)
+ keyusage |= TX_USAGE;
+
+ ath6kl_wmi_addkey_cmd(ar->wmi,
+ index,
+ WEP_CRYPT,
+ keyusage,
+ ar->wep_key_list[index].key_len,
+ NULL,
+ ar->wep_key_list[index].key,
+ KEY_OP_INIT_VAL, NULL,
+ NO_SYNC_WMIFLAG);
+ }
+ }
+}
+
+void ath6kl_connect_ap_mode_bss(struct ath6kl *ar, u16 channel)
+{
+ struct ath6kl_req_key *ik;
+ int res;
+ u8 key_rsc[ATH6KL_KEY_SEQ_LEN];
+
+ ik = &ar->ap_mode_bkey;
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "AP mode started on %u MHz\n", channel);
+
+ switch (ar->auth_mode) {
+ case NONE_AUTH:
+ if (ar->prwise_crypto == WEP_CRYPT)
+ ath6kl_install_static_wep_keys(ar);
+ break;
+ case WPA_PSK_AUTH:
+ case WPA2_PSK_AUTH:
+ case (WPA_PSK_AUTH | WPA2_PSK_AUTH):
+ if (!ik->valid)
+ break;
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed addkey for "
+ "the initial group key for AP mode\n");
+ memset(key_rsc, 0, sizeof(key_rsc));
+ res = ath6kl_wmi_addkey_cmd(
+ ar->wmi, ik->key_index, ik->key_type,
+ GROUP_USAGE, ik->key_len, key_rsc, ik->key,
+ KEY_OP_INIT_VAL, NULL, SYNC_BOTH_WMIFLAG);
+ if (res) {
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed "
+ "addkey failed: %d\n", res);
+ }
+ break;
+ }
+
+ ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0);
+ set_bit(CONNECTED, &ar->flag);
+ netif_carrier_on(ar->net_dev);
+}
+
+void ath6kl_connect_ap_mode_sta(struct ath6kl *ar, u16 aid, u8 *mac_addr,
+ u8 keymgmt, u8 ucipher, u8 auth,
+ u8 assoc_req_len, u8 *assoc_info)
+{
+ u8 *ies = NULL, *wpa_ie = NULL, *pos;
+ size_t ies_len = 0;
+ struct station_info sinfo;
+
+ ath6kl_dbg(ATH6KL_DBG_TRC, "new station %pM aid=%d\n", mac_addr, aid);
+
+ if (assoc_req_len > sizeof(struct ieee80211_hdr_3addr)) {
+ struct ieee80211_mgmt *mgmt =
+ (struct ieee80211_mgmt *) assoc_info;
+ if (ieee80211_is_assoc_req(mgmt->frame_control) &&
+ assoc_req_len >= sizeof(struct ieee80211_hdr_3addr) +
+ sizeof(mgmt->u.assoc_req)) {
+ ies = mgmt->u.assoc_req.variable;
+ ies_len = assoc_info + assoc_req_len - ies;
+ } else if (ieee80211_is_reassoc_req(mgmt->frame_control) &&
+ assoc_req_len >= sizeof(struct ieee80211_hdr_3addr)
+ + sizeof(mgmt->u.reassoc_req)) {
+ ies = mgmt->u.reassoc_req.variable;
+ ies_len = assoc_info + assoc_req_len - ies;
+ }
+ }
+
+ pos = ies;
+ while (pos && pos + 1 < ies + ies_len) {
+ if (pos + 2 + pos[1] > ies + ies_len)
+ break;
+ if (pos[0] == WLAN_EID_RSN)
+ wpa_ie = pos; /* RSN IE */
+ else if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
+ pos[1] >= 4 &&
+ pos[2] == 0x00 && pos[3] == 0x50 && pos[4] == 0xf2) {
+ if (pos[5] == 0x01)
+ wpa_ie = pos; /* WPA IE */
+ else if (pos[5] == 0x04) {
+ wpa_ie = pos; /* WPS IE */
+ break; /* overrides WPA/RSN IE */
+ }
+ }
+ pos += 2 + pos[1];
+ }
+
+ ath6kl_add_new_sta(ar, mac_addr, aid, wpa_ie,
+ wpa_ie ? 2 + wpa_ie[1] : 0,
+ keymgmt, ucipher, auth);
+
+ /* send event to application */
+ memset(&sinfo, 0, sizeof(sinfo));
+
+ /* TODO: sinfo.generation */
+
+ sinfo.assoc_req_ies = ies;
+ sinfo.assoc_req_ies_len = ies_len;
+ sinfo.filled |= STATION_INFO_ASSOC_REQ_IES;
+
+ cfg80211_new_sta(ar->net_dev, mac_addr, &sinfo, GFP_KERNEL);
+
+ netif_wake_queue(ar->net_dev);
+}
+
+/* Functions for Tx credit handling */
+void ath6k_credit_init(struct htc_credit_state_info *cred_info,
+ struct list_head *ep_list,
+ int tot_credits)
+{
+ struct htc_endpoint_credit_dist *cur_ep_dist;
+ int count;
+
+ cred_info->cur_free_credits = tot_credits;
+ cred_info->total_avail_credits = tot_credits;
+
+ list_for_each_entry(cur_ep_dist, ep_list, list) {
+ if (cur_ep_dist->endpoint == ENDPOINT_0)
+ continue;
+
+ cur_ep_dist->cred_min = cur_ep_dist->cred_per_msg;
+
+ if (tot_credits > 4)
+ if ((cur_ep_dist->svc_id == WMI_DATA_BK_SVC) ||
+ (cur_ep_dist->svc_id == WMI_DATA_BE_SVC)) {
+ ath6kl_deposit_credit_to_ep(cred_info,
+ cur_ep_dist,
+ cur_ep_dist->cred_min);
+ cur_ep_dist->dist_flags |= HTC_EP_ACTIVE;
+ }
+
+ if (cur_ep_dist->svc_id == WMI_CONTROL_SVC) {
+ ath6kl_deposit_credit_to_ep(cred_info, cur_ep_dist,
+ cur_ep_dist->cred_min);
+ /*
+ * Control service is always marked active, it
+ * never goes inactive EVER.
+ */
+ cur_ep_dist->dist_flags |= HTC_EP_ACTIVE;
+ } else if (cur_ep_dist->svc_id == WMI_DATA_BK_SVC)
+ /* this is the lowest priority data endpoint */
+ cred_info->lowestpri_ep_dist = cur_ep_dist->list;
+
+ /*
+ * Streams have to be created (explicit | implicit) for all
+ * kinds of traffic. BE endpoints are also inactive in the
+ * beginning. When BE traffic starts it creates implicit
+ * streams that redistributes credits.
+ *
+ * Note: all other endpoints have minimums set but are
+ * initially given NO credits. credits will be distributed
+ * as traffic activity demands
+ */
+ }
+
+ WARN_ON(cred_info->cur_free_credits <= 0);
+
+ list_for_each_entry(cur_ep_dist, ep_list, list) {
+ if (cur_ep_dist->endpoint == ENDPOINT_0)
+ continue;
+
+ if (cur_ep_dist->svc_id == WMI_CONTROL_SVC)
+ cur_ep_dist->cred_norm = cur_ep_dist->cred_per_msg;
+ else {
+ /*
+ * For the remaining data endpoints, we assume that
+ * each cred_per_msg are the same. We use a simple
+ * calculation here, we take the remaining credits
+ * and determine how many max messages this can
+ * cover and then set each endpoint's normal value
+ * equal to 3/4 this amount.
+ */
+ count = (cred_info->cur_free_credits /
+ cur_ep_dist->cred_per_msg)
+ * cur_ep_dist->cred_per_msg;
+ count = (count * 3) >> 2;
+ count = max(count, cur_ep_dist->cred_per_msg);
+ cur_ep_dist->cred_norm = count;
+
+ }
+ }
+}
+
+/* initialize and setup credit distribution */
+int ath6k_setup_credit_dist(void *htc_handle,
+ struct htc_credit_state_info *cred_info)
+{
+ u16 servicepriority[5];
+
+ memset(cred_info, 0, sizeof(struct htc_credit_state_info));
+
+ servicepriority[0] = WMI_CONTROL_SVC; /* highest */
+ servicepriority[1] = WMI_DATA_VO_SVC;
+ servicepriority[2] = WMI_DATA_VI_SVC;
+ servicepriority[3] = WMI_DATA_BE_SVC;
+ servicepriority[4] = WMI_DATA_BK_SVC; /* lowest */
+
+ /* set priority list */
+ ath6kl_htc_set_credit_dist(htc_handle, cred_info, servicepriority, 5);
+
+ return 0;
+}
+
+/* reduce an ep's credits back to a set limit */
+static void ath6k_reduce_credits(struct htc_credit_state_info *cred_info,
+ struct htc_endpoint_credit_dist *ep_dist,
+ int limit)
+{
+ int credits;
+
+ ep_dist->cred_assngd = limit;
+
+ if (ep_dist->credits <= limit)
+ return;
+
+ credits = ep_dist->credits - limit;
+ ep_dist->credits -= credits;
+ cred_info->cur_free_credits += credits;
+}
+
+static void ath6k_credit_update(struct htc_credit_state_info *cred_info,
+ struct list_head *epdist_list)
+{
+ struct htc_endpoint_credit_dist *cur_dist_list;
+
+ list_for_each_entry(cur_dist_list, epdist_list, list) {
+ if (cur_dist_list->endpoint == ENDPOINT_0)
+ continue;
+
+ if (cur_dist_list->cred_to_dist > 0) {
+ cur_dist_list->credits +=
+ cur_dist_list->cred_to_dist;
+ cur_dist_list->cred_to_dist = 0;
+ if (cur_dist_list->credits >
+ cur_dist_list->cred_assngd)
+ ath6k_reduce_credits(cred_info,
+ cur_dist_list,
+ cur_dist_list->cred_assngd);
+
+ if (cur_dist_list->credits >
+ cur_dist_list->cred_norm)
+ ath6k_reduce_credits(cred_info, cur_dist_list,
+ cur_dist_list->cred_norm);
+
+ if (!(cur_dist_list->dist_flags & HTC_EP_ACTIVE)) {
+ if (cur_dist_list->txq_depth == 0)
+ ath6k_reduce_credits(cred_info,
+ cur_dist_list, 0);
+ }
+ }
+ }
+}
+
+/*
+ * HTC has an endpoint that needs credits, ep_dist is the endpoint in
+ * question.
+ */
+void ath6k_seek_credits(struct htc_credit_state_info *cred_info,
+ struct htc_endpoint_credit_dist *ep_dist)
+{
+ struct htc_endpoint_credit_dist *curdist_list;
+ int credits = 0;
+ int need;
+
+ if (ep_dist->svc_id == WMI_CONTROL_SVC)
+ goto out;
+
+ if ((ep_dist->svc_id == WMI_DATA_VI_SVC) ||
+ (ep_dist->svc_id == WMI_DATA_VO_SVC))
+ if ((ep_dist->cred_assngd >= ep_dist->cred_norm))
+ goto out;
+
+ /*
+ * For all other services, we follow a simple algorithm of:
+ *
+ * 1. checking the free pool for credits
+ * 2. checking lower priority endpoints for credits to take
+ */
+
+ credits = min(cred_info->cur_free_credits, ep_dist->seek_cred);
+
+ if (credits >= ep_dist->seek_cred)
+ goto out;
+
+ /*
+ * We don't have enough in the free pool, try taking away from
+ * lower priority services The rule for taking away credits:
+ *
+ * 1. Only take from lower priority endpoints
+ * 2. Only take what is allocated above the minimum (never
+ * starve an endpoint completely)
+ * 3. Only take what you need.
+ */
+
+ list_for_each_entry_reverse(curdist_list,
+ &cred_info->lowestpri_ep_dist,
+ list) {
+ if (curdist_list == ep_dist)
+ break;
+
+ need = ep_dist->seek_cred - cred_info->cur_free_credits;
+
+ if ((curdist_list->cred_assngd - need) >=
+ curdist_list->cred_min) {
+ /*
+ * The current one has been allocated more than
+ * it's minimum and it has enough credits assigned
+ * above it's minimum to fulfill our need try to
+ * take away just enough to fulfill our need.
+ */
+ ath6k_reduce_credits(cred_info, curdist_list,
+ curdist_list->cred_assngd - need);
+
+ if (cred_info->cur_free_credits >=
+ ep_dist->seek_cred)
+ break;
+ }
+
+ if (curdist_list->endpoint == ENDPOINT_0)
+ break;
+ }
+
+ credits = min(cred_info->cur_free_credits, ep_dist->seek_cred);
+
+out:
+ /* did we find some credits? */
+ if (credits)
+ ath6kl_deposit_credit_to_ep(cred_info, ep_dist, credits);
+
+ ep_dist->seek_cred = 0;
+}
+
+/* redistribute credits based on activity change */
+static void ath6k_redistribute_credits(struct htc_credit_state_info *info,
+ struct list_head *ep_dist_list)
+{
+ struct htc_endpoint_credit_dist *curdist_list;
+
+ list_for_each_entry(curdist_list, ep_dist_list, list) {
+ if (curdist_list->endpoint == ENDPOINT_0)
+ continue;
+
+ if ((curdist_list->svc_id == WMI_DATA_BK_SVC) ||
+ (curdist_list->svc_id == WMI_DATA_BE_SVC))
+ curdist_list->dist_flags |= HTC_EP_ACTIVE;
+
+ if ((curdist_list->svc_id != WMI_CONTROL_SVC) &&
+ !(curdist_list->dist_flags & HTC_EP_ACTIVE)) {
+ if (curdist_list->txq_depth == 0)
+ ath6k_reduce_credits(info,
+ curdist_list, 0);
+ else
+ ath6k_reduce_credits(info,
+ curdist_list,
+ curdist_list->cred_min);
+ }
+ }
+}
+
+/*
+ *
+ * This function is invoked whenever endpoints require credit
+ * distributions. A lock is held while this function is invoked, this
+ * function shall NOT block. The ep_dist_list is a list of distribution
+ * structures in prioritized order as defined by the call to the
+ * htc_set_credit_dist() api.
+ */
+void ath6k_credit_distribute(struct htc_credit_state_info *cred_info,
+ struct list_head *ep_dist_list,
+ enum htc_credit_dist_reason reason)
+{
+ switch (reason) {
+ case HTC_CREDIT_DIST_SEND_COMPLETE:
+ ath6k_credit_update(cred_info, ep_dist_list);
+ break;
+ case HTC_CREDIT_DIST_ACTIVITY_CHANGE:
+ ath6k_redistribute_credits(cred_info, ep_dist_list);
+ break;
+ default:
+ break;
+ }
+
+ WARN_ON(cred_info->cur_free_credits > cred_info->total_avail_credits);
+ WARN_ON(cred_info->cur_free_credits < 0);
+}
+
+void disconnect_timer_handler(unsigned long ptr)
+{
+ struct net_device *dev = (struct net_device *)ptr;
+ struct ath6kl *ar = ath6kl_priv(dev);
+
+ ath6kl_init_profile_info(ar);
+ ath6kl_disconnect(ar);
+}
+
+void ath6kl_disconnect(struct ath6kl *ar)
+{
+ if (test_bit(CONNECTED, &ar->flag) ||
+ test_bit(CONNECT_PEND, &ar->flag)) {
+ ath6kl_wmi_disconnect_cmd(ar->wmi);
+ /*
+ * Disconnect command is issued, clear the connect pending
+ * flag. The connected flag will be cleared in
+ * disconnect event notification.
+ */
+ clear_bit(CONNECT_PEND, &ar->flag);
+ }
+}
+
+void ath6kl_deep_sleep_enable(struct ath6kl *ar)
+{
+ switch (ar->sme_state) {
+ case SME_CONNECTING:
+ cfg80211_connect_result(ar->net_dev, ar->bssid, NULL, 0,
+ NULL, 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
+ GFP_KERNEL);
+ break;
+ case SME_CONNECTED:
+ default:
+ /*
+ * FIXME: oddly enough smeState is in DISCONNECTED during
+ * suspend, why? Need to send disconnected event in that
+ * state.
+ */
+ cfg80211_disconnected(ar->net_dev, 0, NULL, 0, GFP_KERNEL);
+ break;
+ }
+
+ if (test_bit(CONNECTED, &ar->flag) ||
+ test_bit(CONNECT_PEND, &ar->flag))
+ ath6kl_wmi_disconnect_cmd(ar->wmi);
+
+ ar->sme_state = SME_DISCONNECTED;
+
+ /* disable scanning */
+ if (ath6kl_wmi_scanparams_cmd(ar->wmi, 0xFFFF, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0) != 0)
+ printk(KERN_WARNING "ath6kl: failed to disable scan "
+ "during suspend\n");
+
+ ath6kl_cfg80211_scan_complete_event(ar, -ECANCELED);
+}
+
+/* WMI Event handlers */
+
+static const char *get_hw_id_string(u32 id)
+{
+ switch (id) {
+ case AR6003_REV1_VERSION:
+ return "1.0";
+ case AR6003_REV2_VERSION:
+ return "2.0";
+ case AR6003_REV3_VERSION:
+ return "2.1.1";
+ default:
+ return "unknown";
+ }
+}
+
+void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver)
+{
+ struct ath6kl *ar = devt;
+ struct net_device *dev = ar->net_dev;
+
+ memcpy(dev->dev_addr, datap, ETH_ALEN);
+ ath6kl_dbg(ATH6KL_DBG_TRC, "%s: mac addr = %pM\n",
+ __func__, dev->dev_addr);
+
+ ar->version.wlan_ver = sw_ver;
+ ar->version.abi_ver = abi_ver;
+
+ snprintf(ar->wdev->wiphy->fw_version,
+ sizeof(ar->wdev->wiphy->fw_version),
+ "%u.%u.%u.%u",
+ (ar->version.wlan_ver & 0xf0000000) >> 28,
+ (ar->version.wlan_ver & 0x0f000000) >> 24,
+ (ar->version.wlan_ver & 0x00ff0000) >> 16,
+ (ar->version.wlan_ver & 0x0000ffff));
+
+ /* indicate to the waiting thread that the ready event was received */
+ set_bit(WMI_READY, &ar->flag);
+ wake_up(&ar->event_wq);
+
+ ath6kl_info("hw %s fw %s%s\n",
+ get_hw_id_string(ar->wdev->wiphy->hw_version),
+ ar->wdev->wiphy->fw_version,
+ test_bit(TESTMODE, &ar->flag) ? " testmode" : "");
+}
+
+void ath6kl_scan_complete_evt(struct ath6kl *ar, int status)
+{
+ ath6kl_cfg80211_scan_complete_event(ar, status);
+
+ if (!ar->usr_bss_filter) {
+ clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag);
+ ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0);
+ }
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_SCAN, "scan complete: %d\n", status);
+}
+
+void ath6kl_connect_event(struct ath6kl *ar, u16 channel, u8 *bssid,
+ u16 listen_int, u16 beacon_int,
+ enum network_type net_type, u8 beacon_ie_len,
+ u8 assoc_req_len, u8 assoc_resp_len,
+ u8 *assoc_info)
+{
+ unsigned long flags;
+
+ ath6kl_cfg80211_connect_event(ar, channel, bssid,
+ listen_int, beacon_int,
+ net_type, beacon_ie_len,
+ assoc_req_len, assoc_resp_len,
+ assoc_info);
+
+ memcpy(ar->bssid, bssid, sizeof(ar->bssid));
+ ar->bss_ch = channel;
+
+ if ((ar->nw_type == INFRA_NETWORK))
+ ath6kl_wmi_listeninterval_cmd(ar->wmi, ar->listen_intvl_t,
+ ar->listen_intvl_b);
+
+ netif_wake_queue(ar->net_dev);
+
+ /* Update connect & link status atomically */
+ spin_lock_irqsave(&ar->lock, flags);
+ set_bit(CONNECTED, &ar->flag);
+ clear_bit(CONNECT_PEND, &ar->flag);
+ netif_carrier_on(ar->net_dev);
+ spin_unlock_irqrestore(&ar->lock, flags);
+
+ aggr_reset_state(ar->aggr_cntxt);
+ ar->reconnect_flag = 0;
+
+ if ((ar->nw_type == ADHOC_NETWORK) && ar->ibss_ps_enable) {
+ memset(ar->node_map, 0, sizeof(ar->node_map));
+ ar->node_num = 0;
+ ar->next_ep_id = ENDPOINT_2;
+ }
+
+ if (!ar->usr_bss_filter) {
+ set_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag);
+ ath6kl_wmi_bssfilter_cmd(ar->wmi, CURRENT_BSS_FILTER, 0);
+ }
+}
+
+void ath6kl_tkip_micerr_event(struct ath6kl *ar, u8 keyid, bool ismcast)
+{
+ struct ath6kl_sta *sta;
+ u8 tsc[6];
+ /*
+ * For AP case, keyid will have aid of STA which sent pkt with
+ * MIC error. Use this aid to get MAC & send it to hostapd.
+ */
+ if (ar->nw_type == AP_NETWORK) {
+ sta = ath6kl_find_sta_by_aid(ar, (keyid >> 2));
+ if (!sta)
+ return;
+
+ ath6kl_dbg(ATH6KL_DBG_TRC,
+ "ap tkip mic error received from aid=%d\n", keyid);
+
+ memset(tsc, 0, sizeof(tsc)); /* FIX: get correct TSC */
+ cfg80211_michael_mic_failure(ar->net_dev, sta->mac,
+ NL80211_KEYTYPE_PAIRWISE, keyid,
+ tsc, GFP_KERNEL);
+ } else
+ ath6kl_cfg80211_tkip_micerr_event(ar, keyid, ismcast);
+
+}
+
+static void ath6kl_update_target_stats(struct ath6kl *ar, u8 *ptr, u32 len)
+{
+ struct wmi_target_stats *tgt_stats =
+ (struct wmi_target_stats *) ptr;
+ struct target_stats *stats = &ar->target_stats;
+ struct tkip_ccmp_stats *ccmp_stats;
+ u8 ac;
+
+ if (len < sizeof(*tgt_stats))
+ return;
+
+ ath6kl_dbg(ATH6KL_DBG_TRC, "updating target stats\n");
+
+ stats->tx_pkt += le32_to_cpu(tgt_stats->stats.tx.pkt);
+ stats->tx_byte += le32_to_cpu(tgt_stats->stats.tx.byte);
+ stats->tx_ucast_pkt += le32_to_cpu(tgt_stats->stats.tx.ucast_pkt);
+ stats->tx_ucast_byte += le32_to_cpu(tgt_stats->stats.tx.ucast_byte);
+ stats->tx_mcast_pkt += le32_to_cpu(tgt_stats->stats.tx.mcast_pkt);
+ stats->tx_mcast_byte += le32_to_cpu(tgt_stats->stats.tx.mcast_byte);
+ stats->tx_bcast_pkt += le32_to_cpu(tgt_stats->stats.tx.bcast_pkt);
+ stats->tx_bcast_byte += le32_to_cpu(tgt_stats->stats.tx.bcast_byte);
+ stats->tx_rts_success_cnt +=
+ le32_to_cpu(tgt_stats->stats.tx.rts_success_cnt);
+
+ for (ac = 0; ac < WMM_NUM_AC; ac++)
+ stats->tx_pkt_per_ac[ac] +=
+ le32_to_cpu(tgt_stats->stats.tx.pkt_per_ac[ac]);
+
+ stats->tx_err += le32_to_cpu(tgt_stats->stats.tx.err);
+ stats->tx_fail_cnt += le32_to_cpu(tgt_stats->stats.tx.fail_cnt);
+ stats->tx_retry_cnt += le32_to_cpu(tgt_stats->stats.tx.retry_cnt);
+ stats->tx_mult_retry_cnt +=
+ le32_to_cpu(tgt_stats->stats.tx.mult_retry_cnt);
+ stats->tx_rts_fail_cnt +=
+ le32_to_cpu(tgt_stats->stats.tx.rts_fail_cnt);
+ stats->tx_ucast_rate =
+ ath6kl_wmi_get_rate(a_sle32_to_cpu(tgt_stats->stats.tx.ucast_rate));
+
+ stats->rx_pkt += le32_to_cpu(tgt_stats->stats.rx.pkt);
+ stats->rx_byte += le32_to_cpu(tgt_stats->stats.rx.byte);
+ stats->rx_ucast_pkt += le32_to_cpu(tgt_stats->stats.rx.ucast_pkt);
+ stats->rx_ucast_byte += le32_to_cpu(tgt_stats->stats.rx.ucast_byte);
+ stats->rx_mcast_pkt += le32_to_cpu(tgt_stats->stats.rx.mcast_pkt);
+ stats->rx_mcast_byte += le32_to_cpu(tgt_stats->stats.rx.mcast_byte);
+ stats->rx_bcast_pkt += le32_to_cpu(tgt_stats->stats.rx.bcast_pkt);
+ stats->rx_bcast_byte += le32_to_cpu(tgt_stats->stats.rx.bcast_byte);
+ stats->rx_frgment_pkt += le32_to_cpu(tgt_stats->stats.rx.frgment_pkt);
+ stats->rx_err += le32_to_cpu(tgt_stats->stats.rx.err);
+ stats->rx_crc_err += le32_to_cpu(tgt_stats->stats.rx.crc_err);
+ stats->rx_key_cache_miss +=
+ le32_to_cpu(tgt_stats->stats.rx.key_cache_miss);
+ stats->rx_decrypt_err += le32_to_cpu(tgt_stats->stats.rx.decrypt_err);
+ stats->rx_dupl_frame += le32_to_cpu(tgt_stats->stats.rx.dupl_frame);
+ stats->rx_ucast_rate =
+ ath6kl_wmi_get_rate(a_sle32_to_cpu(tgt_stats->stats.rx.ucast_rate));
+
+ ccmp_stats = &tgt_stats->stats.tkip_ccmp_stats;
+
+ stats->tkip_local_mic_fail +=
+ le32_to_cpu(ccmp_stats->tkip_local_mic_fail);
+ stats->tkip_cnter_measures_invoked +=
+ le32_to_cpu(ccmp_stats->tkip_cnter_measures_invoked);
+ stats->tkip_fmt_err += le32_to_cpu(ccmp_stats->tkip_fmt_err);
+
+ stats->ccmp_fmt_err += le32_to_cpu(ccmp_stats->ccmp_fmt_err);
+ stats->ccmp_replays += le32_to_cpu(ccmp_stats->ccmp_replays);
+
+ stats->pwr_save_fail_cnt +=
+ le32_to_cpu(tgt_stats->pm_stats.pwr_save_failure_cnt);
+ stats->noise_floor_calib =
+ a_sle32_to_cpu(tgt_stats->noise_floor_calib);
+
+ stats->cs_bmiss_cnt +=
+ le32_to_cpu(tgt_stats->cserv_stats.cs_bmiss_cnt);
+ stats->cs_low_rssi_cnt +=
+ le32_to_cpu(tgt_stats->cserv_stats.cs_low_rssi_cnt);
+ stats->cs_connect_cnt +=
+ le16_to_cpu(tgt_stats->cserv_stats.cs_connect_cnt);
+ stats->cs_discon_cnt +=
+ le16_to_cpu(tgt_stats->cserv_stats.cs_discon_cnt);
+
+ stats->cs_ave_beacon_rssi =
+ a_sle16_to_cpu(tgt_stats->cserv_stats.cs_ave_beacon_rssi);
+
+ stats->cs_last_roam_msec =
+ tgt_stats->cserv_stats.cs_last_roam_msec;
+ stats->cs_snr = tgt_stats->cserv_stats.cs_snr;
+ stats->cs_rssi = a_sle16_to_cpu(tgt_stats->cserv_stats.cs_rssi);
+
+ stats->lq_val = le32_to_cpu(tgt_stats->lq_val);
+
+ stats->wow_pkt_dropped +=
+ le32_to_cpu(tgt_stats->wow_stats.wow_pkt_dropped);
+ stats->wow_host_pkt_wakeups +=
+ tgt_stats->wow_stats.wow_host_pkt_wakeups;
+ stats->wow_host_evt_wakeups +=
+ tgt_stats->wow_stats.wow_host_evt_wakeups;
+ stats->wow_evt_discarded +=
+ le16_to_cpu(tgt_stats->wow_stats.wow_evt_discarded);
+
+ if (test_bit(STATS_UPDATE_PEND, &ar->flag)) {
+ clear_bit(STATS_UPDATE_PEND, &ar->flag);
+ wake_up(&ar->event_wq);
+ }
+}
+
+static void ath6kl_add_le32(__le32 *var, __le32 val)
+{
+ *var = cpu_to_le32(le32_to_cpu(*var) + le32_to_cpu(val));
+}
+
+void ath6kl_tgt_stats_event(struct ath6kl *ar, u8 *ptr, u32 len)
+{
+ struct wmi_ap_mode_stat *p = (struct wmi_ap_mode_stat *) ptr;
+ struct wmi_ap_mode_stat *ap = &ar->ap_stats;
+ struct wmi_per_sta_stat *st_ap, *st_p;
+ u8 ac;
+
+ if (ar->nw_type == AP_NETWORK) {
+ if (len < sizeof(*p))
+ return;
+
+ for (ac = 0; ac < AP_MAX_NUM_STA; ac++) {
+ st_ap = &ap->sta[ac];
+ st_p = &p->sta[ac];
+
+ ath6kl_add_le32(&st_ap->tx_bytes, st_p->tx_bytes);
+ ath6kl_add_le32(&st_ap->tx_pkts, st_p->tx_pkts);
+ ath6kl_add_le32(&st_ap->tx_error, st_p->tx_error);
+ ath6kl_add_le32(&st_ap->tx_discard, st_p->tx_discard);
+ ath6kl_add_le32(&st_ap->rx_bytes, st_p->rx_bytes);
+ ath6kl_add_le32(&st_ap->rx_pkts, st_p->rx_pkts);
+ ath6kl_add_le32(&st_ap->rx_error, st_p->rx_error);
+ ath6kl_add_le32(&st_ap->rx_discard, st_p->rx_discard);
+ }
+
+ } else {
+ ath6kl_update_target_stats(ar, ptr, len);
+ }
+}
+
+void ath6kl_wakeup_event(void *dev)
+{
+ struct ath6kl *ar = (struct ath6kl *) dev;
+
+ wake_up(&ar->event_wq);
+}
+
+void ath6kl_txpwr_rx_evt(void *devt, u8 tx_pwr)
+{
+ struct ath6kl *ar = (struct ath6kl *) devt;
+
+ ar->tx_pwr = tx_pwr;
+ wake_up(&ar->event_wq);
+}
+
+void ath6kl_pspoll_event(struct ath6kl *ar, u8 aid)
+{
+ struct ath6kl_sta *conn;
+ struct sk_buff *skb;
+ bool psq_empty = false;
+
+ conn = ath6kl_find_sta_by_aid(ar, aid);
+
+ if (!conn)
+ return;
+ /*
+ * Send out a packet queued on ps queue. When the ps queue
+ * becomes empty update the PVB for this station.
+ */
+ spin_lock_bh(&conn->psq_lock);
+ psq_empty = skb_queue_empty(&conn->psq);
+ spin_unlock_bh(&conn->psq_lock);
+
+ if (psq_empty)
+ /* TODO: Send out a NULL data frame */
+ return;
+
+ spin_lock_bh(&conn->psq_lock);
+ skb = skb_dequeue(&conn->psq);
+ spin_unlock_bh(&conn->psq_lock);
+
+ conn->sta_flags |= STA_PS_POLLED;
+ ath6kl_data_tx(skb, ar->net_dev);
+ conn->sta_flags &= ~STA_PS_POLLED;
+
+ spin_lock_bh(&conn->psq_lock);
+ psq_empty = skb_queue_empty(&conn->psq);
+ spin_unlock_bh(&conn->psq_lock);
+
+ if (psq_empty)
+ ath6kl_wmi_set_pvb_cmd(ar->wmi, conn->aid, 0);
+}
+
+void ath6kl_dtimexpiry_event(struct ath6kl *ar)
+{
+ bool mcastq_empty = false;
+ struct sk_buff *skb;
+
+ /*
+ * If there are no associated STAs, ignore the DTIM expiry event.
+ * There can be potential race conditions where the last associated
+ * STA may disconnect & before the host could clear the 'Indicate
+ * DTIM' request to the firmware, the firmware would have just
+ * indicated a DTIM expiry event. The race is between 'clear DTIM
+ * expiry cmd' going from the host to the firmware & the DTIM
+ * expiry event happening from the firmware to the host.
+ */
+ if (!ar->sta_list_index)
+ return;
+
+ spin_lock_bh(&ar->mcastpsq_lock);
+ mcastq_empty = skb_queue_empty(&ar->mcastpsq);
+ spin_unlock_bh(&ar->mcastpsq_lock);
+
+ if (mcastq_empty)
+ return;
+
+ /* set the STA flag to dtim_expired for the frame to go out */
+ set_bit(DTIM_EXPIRED, &ar->flag);
+
+ spin_lock_bh(&ar->mcastpsq_lock);
+ while ((skb = skb_dequeue(&ar->mcastpsq)) != NULL) {
+ spin_unlock_bh(&ar->mcastpsq_lock);
+
+ ath6kl_data_tx(skb, ar->net_dev);
+
+ spin_lock_bh(&ar->mcastpsq_lock);
+ }
+ spin_unlock_bh(&ar->mcastpsq_lock);
+
+ clear_bit(DTIM_EXPIRED, &ar->flag);
+
+ /* clear the LSB of the BitMapCtl field of the TIM IE */
+ ath6kl_wmi_set_pvb_cmd(ar->wmi, MCAST_AID, 0);
+}
+
+void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason, u8 *bssid,
+ u8 assoc_resp_len, u8 *assoc_info,
+ u16 prot_reason_status)
+{
+ unsigned long flags;
+
+ if (ar->nw_type == AP_NETWORK) {
+ if (!ath6kl_remove_sta(ar, bssid, prot_reason_status))
+ return;
+
+ /* if no more associated STAs, empty the mcast PS q */
+ if (ar->sta_list_index == 0) {
+ spin_lock_bh(&ar->mcastpsq_lock);
+ skb_queue_purge(&ar->mcastpsq);
+ spin_unlock_bh(&ar->mcastpsq_lock);
+
+ /* clear the LSB of the TIM IE's BitMapCtl field */
+ if (test_bit(WMI_READY, &ar->flag))
+ ath6kl_wmi_set_pvb_cmd(ar->wmi, MCAST_AID, 0);
+ }
+
+ if (!is_broadcast_ether_addr(bssid)) {
+ /* send event to application */
+ cfg80211_del_sta(ar->net_dev, bssid, GFP_KERNEL);
+ }
+
+ if (memcmp(ar->net_dev->dev_addr, bssid, ETH_ALEN) == 0) {
+ memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list));
+ clear_bit(CONNECTED, &ar->flag);
+ }
+ return;
+ }
+
+ ath6kl_cfg80211_disconnect_event(ar, reason, bssid,
+ assoc_resp_len, assoc_info,
+ prot_reason_status);
+
+ aggr_reset_state(ar->aggr_cntxt);
+
+ del_timer(&ar->disconnect_timer);
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CONNECT,
+ "disconnect reason is %d\n", reason);
+
+ /*
+ * If the event is due to disconnect cmd from the host, only they
+ * the target would stop trying to connect. Under any other
+ * condition, target would keep trying to connect.
+ */
+ if (reason == DISCONNECT_CMD) {
+ if (!ar->usr_bss_filter && test_bit(WMI_READY, &ar->flag))
+ ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0);
+ } else {
+ set_bit(CONNECT_PEND, &ar->flag);
+ if (((reason == ASSOC_FAILED) &&
+ (prot_reason_status == 0x11)) ||
+ ((reason == ASSOC_FAILED) && (prot_reason_status == 0x0)
+ && (ar->reconnect_flag == 1))) {
+ set_bit(CONNECTED, &ar->flag);
+ return;
+ }
+ }
+
+ /* update connect & link status atomically */
+ spin_lock_irqsave(&ar->lock, flags);
+ clear_bit(CONNECTED, &ar->flag);
+ netif_carrier_off(ar->net_dev);
+ spin_unlock_irqrestore(&ar->lock, flags);
+
+ if ((reason != CSERV_DISCONNECT) || (ar->reconnect_flag != 1))
+ ar->reconnect_flag = 0;
+
+ if (reason != CSERV_DISCONNECT)
+ ar->user_key_ctrl = 0;
+
+ netif_stop_queue(ar->net_dev);
+ memset(ar->bssid, 0, sizeof(ar->bssid));
+ ar->bss_ch = 0;
+
+ ath6kl_tx_data_cleanup(ar);
+}
+
+static int ath6kl_open(struct net_device *dev)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ar->lock, flags);
+
+ set_bit(WLAN_ENABLED, &ar->flag);
+
+ if (test_bit(CONNECTED, &ar->flag)) {
+ netif_carrier_on(dev);
+ netif_wake_queue(dev);
+ } else
+ netif_carrier_off(dev);
+
+ spin_unlock_irqrestore(&ar->lock, flags);
+
+ return 0;
+}
+
+static int ath6kl_close(struct net_device *dev)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+
+ netif_stop_queue(dev);
+
+ ath6kl_disconnect(ar);
+
+ if (test_bit(WMI_READY, &ar->flag)) {
+ if (ath6kl_wmi_scanparams_cmd(ar->wmi, 0xFFFF, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0))
+ return -EIO;
+
+ clear_bit(WLAN_ENABLED, &ar->flag);
+ }
+
+ ath6kl_cfg80211_scan_complete_event(ar, -ECANCELED);
+
+ return 0;
+}
+
+static struct net_device_stats *ath6kl_get_stats(struct net_device *dev)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+
+ return &ar->net_stats;
+}
+
+static struct net_device_ops ath6kl_netdev_ops = {
+ .ndo_open = ath6kl_open,
+ .ndo_stop = ath6kl_close,
+ .ndo_start_xmit = ath6kl_data_tx,
+ .ndo_get_stats = ath6kl_get_stats,
+};
+
+void init_netdev(struct net_device *dev)
+{
+ dev->netdev_ops = &ath6kl_netdev_ops;
+ dev->watchdog_timeo = ATH6KL_TX_TIMEOUT;
+
+ dev->needed_headroom = ETH_HLEN;
+ dev->needed_headroom += sizeof(struct ath6kl_llc_snap_hdr) +
+ sizeof(struct wmi_data_hdr) + HTC_HDR_LENGTH
+ + WMI_MAX_TX_META_SZ + ATH6KL_HTC_ALIGN_BYTES;
+
+ return;
+}
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
new file mode 100644
index 000000000000..f1dc311ee0c7
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -0,0 +1,949 @@
+/*
+ * Copyright (c) 2004-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sd.h>
+#include "htc_hif.h"
+#include "hif-ops.h"
+#include "target.h"
+#include "debug.h"
+#include "cfg80211.h"
+
+struct ath6kl_sdio {
+ struct sdio_func *func;
+
+ spinlock_t lock;
+
+ /* free list */
+ struct list_head bus_req_freeq;
+
+ /* available bus requests */
+ struct bus_request bus_req[BUS_REQUEST_MAX_NUM];
+
+ struct ath6kl *ar;
+ u8 *dma_buffer;
+
+ /* scatter request list head */
+ struct list_head scat_req;
+
+ spinlock_t scat_lock;
+ bool is_disabled;
+ atomic_t irq_handling;
+ const struct sdio_device_id *id;
+ struct work_struct wr_async_work;
+ struct list_head wr_asyncq;
+ spinlock_t wr_async_lock;
+};
+
+#define CMD53_ARG_READ 0
+#define CMD53_ARG_WRITE 1
+#define CMD53_ARG_BLOCK_BASIS 1
+#define CMD53_ARG_FIXED_ADDRESS 0
+#define CMD53_ARG_INCR_ADDRESS 1
+
+static inline struct ath6kl_sdio *ath6kl_sdio_priv(struct ath6kl *ar)
+{
+ return ar->hif_priv;
+}
+
+/*
+ * Macro to check if DMA buffer is WORD-aligned and DMA-able.
+ * Most host controllers assume the buffer is DMA'able and will
+ * bug-check otherwise (i.e. buffers on the stack). virt_addr_valid
+ * check fails on stack memory.
+ */
+static inline bool buf_needs_bounce(u8 *buf)
+{
+ return ((unsigned long) buf & 0x3) || !virt_addr_valid(buf);
+}
+
+static void ath6kl_sdio_set_mbox_info(struct ath6kl *ar)
+{
+ struct ath6kl_mbox_info *mbox_info = &ar->mbox_info;
+
+ /* EP1 has an extended range */
+ mbox_info->htc_addr = HIF_MBOX_BASE_ADDR;
+ mbox_info->htc_ext_addr = HIF_MBOX0_EXT_BASE_ADDR;
+ mbox_info->htc_ext_sz = HIF_MBOX0_EXT_WIDTH;
+ mbox_info->block_size = HIF_MBOX_BLOCK_SIZE;
+ mbox_info->gmbox_addr = HIF_GMBOX_BASE_ADDR;
+ mbox_info->gmbox_sz = HIF_GMBOX_WIDTH;
+}
+
+static inline void ath6kl_sdio_set_cmd53_arg(u32 *arg, u8 rw, u8 func,
+ u8 mode, u8 opcode, u32 addr,
+ u16 blksz)
+{
+ *arg = (((rw & 1) << 31) |
+ ((func & 0x7) << 28) |
+ ((mode & 1) << 27) |
+ ((opcode & 1) << 26) |
+ ((addr & 0x1FFFF) << 9) |
+ (blksz & 0x1FF));
+}
+
+static inline void ath6kl_sdio_set_cmd52_arg(u32 *arg, u8 write, u8 raw,
+ unsigned int address,
+ unsigned char val)
+{
+ const u8 func = 0;
+
+ *arg = ((write & 1) << 31) |
+ ((func & 0x7) << 28) |
+ ((raw & 1) << 27) |
+ (1 << 26) |
+ ((address & 0x1FFFF) << 9) |
+ (1 << 8) |
+ (val & 0xFF);
+}
+
+static int ath6kl_sdio_func0_cmd52_wr_byte(struct mmc_card *card,
+ unsigned int address,
+ unsigned char byte)
+{
+ struct mmc_command io_cmd;
+
+ memset(&io_cmd, 0, sizeof(io_cmd));
+ ath6kl_sdio_set_cmd52_arg(&io_cmd.arg, 1, 0, address, byte);
+ io_cmd.opcode = SD_IO_RW_DIRECT;
+ io_cmd.flags = MMC_RSP_R5 | MMC_CMD_AC;
+
+ return mmc_wait_for_cmd(card->host, &io_cmd, 0);
+}
+
+static int ath6kl_sdio_io(struct sdio_func *func, u32 request, u32 addr,
+ u8 *buf, u32 len)
+{
+ int ret = 0;
+
+ if (request & HIF_WRITE) {
+ /* FIXME: looks like ugly workaround for something */
+ if (addr >= HIF_MBOX_BASE_ADDR &&
+ addr <= HIF_MBOX_END_ADDR)
+ addr += (HIF_MBOX_WIDTH - len);
+
+ /* FIXME: this also looks like ugly workaround */
+ if (addr == HIF_MBOX0_EXT_BASE_ADDR)
+ addr += HIF_MBOX0_EXT_WIDTH - len;
+
+ if (request & HIF_FIXED_ADDRESS)
+ ret = sdio_writesb(func, addr, buf, len);
+ else
+ ret = sdio_memcpy_toio(func, addr, buf, len);
+ } else {
+ if (request & HIF_FIXED_ADDRESS)
+ ret = sdio_readsb(func, buf, addr, len);
+ else
+ ret = sdio_memcpy_fromio(func, buf, addr, len);
+ }
+
+ ath6kl_dbg(ATH6KL_DBG_SDIO, "%s addr 0x%x%s buf 0x%p len %d\n",
+ request & HIF_WRITE ? "wr" : "rd", addr,
+ request & HIF_FIXED_ADDRESS ? " (fixed)" : "", buf, len);
+ ath6kl_dbg_dump(ATH6KL_DBG_SDIO_DUMP, NULL, "sdio ", buf, len);
+
+ return ret;
+}
+
+static struct bus_request *ath6kl_sdio_alloc_busreq(struct ath6kl_sdio *ar_sdio)
+{
+ struct bus_request *bus_req;
+ unsigned long flag;
+
+ spin_lock_irqsave(&ar_sdio->lock, flag);
+
+ if (list_empty(&ar_sdio->bus_req_freeq)) {
+ spin_unlock_irqrestore(&ar_sdio->lock, flag);
+ return NULL;
+ }
+
+ bus_req = list_first_entry(&ar_sdio->bus_req_freeq,
+ struct bus_request, list);
+ list_del(&bus_req->list);
+
+ spin_unlock_irqrestore(&ar_sdio->lock, flag);
+ ath6kl_dbg(ATH6KL_DBG_SCATTER, "%s: bus request 0x%p\n",
+ __func__, bus_req);
+
+ return bus_req;
+}
+
+static void ath6kl_sdio_free_bus_req(struct ath6kl_sdio *ar_sdio,
+ struct bus_request *bus_req)
+{
+ unsigned long flag;
+
+ ath6kl_dbg(ATH6KL_DBG_SCATTER, "%s: bus request 0x%p\n",
+ __func__, bus_req);
+
+ spin_lock_irqsave(&ar_sdio->lock, flag);
+ list_add_tail(&bus_req->list, &ar_sdio->bus_req_freeq);
+ spin_unlock_irqrestore(&ar_sdio->lock, flag);
+}
+
+static void ath6kl_sdio_setup_scat_data(struct hif_scatter_req *scat_req,
+ struct mmc_data *data)
+{
+ struct scatterlist *sg;
+ int i;
+
+ data->blksz = HIF_MBOX_BLOCK_SIZE;
+ data->blocks = scat_req->len / HIF_MBOX_BLOCK_SIZE;
+
+ ath6kl_dbg(ATH6KL_DBG_SCATTER,
+ "hif-scatter: (%s) addr: 0x%X, (block len: %d, block count: %d) , (tot:%d,sg:%d)\n",
+ (scat_req->req & HIF_WRITE) ? "WR" : "RD", scat_req->addr,
+ data->blksz, data->blocks, scat_req->len,
+ scat_req->scat_entries);
+
+ data->flags = (scat_req->req & HIF_WRITE) ? MMC_DATA_WRITE :
+ MMC_DATA_READ;
+
+ /* fill SG entries */
+ sg = scat_req->sgentries;
+ sg_init_table(sg, scat_req->scat_entries);
+
+ /* assemble SG list */
+ for (i = 0; i < scat_req->scat_entries; i++, sg++) {
+ ath6kl_dbg(ATH6KL_DBG_SCATTER, "%d: addr:0x%p, len:%d\n",
+ i, scat_req->scat_list[i].buf,
+ scat_req->scat_list[i].len);
+
+ sg_set_buf(sg, scat_req->scat_list[i].buf,
+ scat_req->scat_list[i].len);
+ }
+
+ /* set scatter-gather table for request */
+ data->sg = scat_req->sgentries;
+ data->sg_len = scat_req->scat_entries;
+}
+
+static int ath6kl_sdio_scat_rw(struct ath6kl_sdio *ar_sdio,
+ struct bus_request *req)
+{
+ struct mmc_request mmc_req;
+ struct mmc_command cmd;
+ struct mmc_data data;
+ struct hif_scatter_req *scat_req;
+ u8 opcode, rw;
+ int status, len;
+
+ scat_req = req->scat_req;
+
+ if (scat_req->virt_scat) {
+ len = scat_req->len;
+ if (scat_req->req & HIF_BLOCK_BASIS)
+ len = round_down(len, HIF_MBOX_BLOCK_SIZE);
+
+ status = ath6kl_sdio_io(ar_sdio->func, scat_req->req,
+ scat_req->addr, scat_req->virt_dma_buf,
+ len);
+ goto scat_complete;
+ }
+
+ memset(&mmc_req, 0, sizeof(struct mmc_request));
+ memset(&cmd, 0, sizeof(struct mmc_command));
+ memset(&data, 0, sizeof(struct mmc_data));
+
+ ath6kl_sdio_setup_scat_data(scat_req, &data);
+
+ opcode = (scat_req->req & HIF_FIXED_ADDRESS) ?
+ CMD53_ARG_FIXED_ADDRESS : CMD53_ARG_INCR_ADDRESS;
+
+ rw = (scat_req->req & HIF_WRITE) ? CMD53_ARG_WRITE : CMD53_ARG_READ;
+
+ /* Fixup the address so that the last byte will fall on MBOX EOM */
+ if (scat_req->req & HIF_WRITE) {
+ if (scat_req->addr == HIF_MBOX_BASE_ADDR)
+ scat_req->addr += HIF_MBOX_WIDTH - scat_req->len;
+ else
+ /* Uses extended address range */
+ scat_req->addr += HIF_MBOX0_EXT_WIDTH - scat_req->len;
+ }
+
+ /* set command argument */
+ ath6kl_sdio_set_cmd53_arg(&cmd.arg, rw, ar_sdio->func->num,
+ CMD53_ARG_BLOCK_BASIS, opcode, scat_req->addr,
+ data.blocks);
+
+ cmd.opcode = SD_IO_RW_EXTENDED;
+ cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
+
+ mmc_req.cmd = &cmd;
+ mmc_req.data = &data;
+
+ mmc_set_data_timeout(&data, ar_sdio->func->card);
+ /* synchronous call to process request */
+ mmc_wait_for_req(ar_sdio->func->card->host, &mmc_req);
+
+ status = cmd.error ? cmd.error : data.error;
+
+scat_complete:
+ scat_req->status = status;
+
+ if (scat_req->status)
+ ath6kl_err("Scatter write request failed:%d\n",
+ scat_req->status);
+
+ if (scat_req->req & HIF_ASYNCHRONOUS)
+ scat_req->complete(ar_sdio->ar->htc_target, scat_req);
+
+ return status;
+}
+
+static int ath6kl_sdio_alloc_prep_scat_req(struct ath6kl_sdio *ar_sdio,
+ int n_scat_entry, int n_scat_req,
+ bool virt_scat)
+{
+ struct hif_scatter_req *s_req;
+ struct bus_request *bus_req;
+ int i, scat_req_sz, scat_list_sz, sg_sz, buf_sz;
+ u8 *virt_buf;
+
+ scat_list_sz = (n_scat_entry - 1) * sizeof(struct hif_scatter_item);
+ scat_req_sz = sizeof(*s_req) + scat_list_sz;
+
+ if (!virt_scat)
+ sg_sz = sizeof(struct scatterlist) * n_scat_entry;
+ else
+ buf_sz = 2 * L1_CACHE_BYTES +
+ ATH6KL_MAX_TRANSFER_SIZE_PER_SCATTER;
+
+ for (i = 0; i < n_scat_req; i++) {
+ /* allocate the scatter request */
+ s_req = kzalloc(scat_req_sz, GFP_KERNEL);
+ if (!s_req)
+ return -ENOMEM;
+
+ if (virt_scat) {
+ virt_buf = kzalloc(buf_sz, GFP_KERNEL);
+ if (!virt_buf) {
+ kfree(s_req);
+ return -ENOMEM;
+ }
+
+ s_req->virt_dma_buf =
+ (u8 *)L1_CACHE_ALIGN((unsigned long)virt_buf);
+ } else {
+ /* allocate sglist */
+ s_req->sgentries = kzalloc(sg_sz, GFP_KERNEL);
+
+ if (!s_req->sgentries) {
+ kfree(s_req);
+ return -ENOMEM;
+ }
+ }
+
+ /* allocate a bus request for this scatter request */
+ bus_req = ath6kl_sdio_alloc_busreq(ar_sdio);
+ if (!bus_req) {
+ kfree(s_req->sgentries);
+ kfree(s_req->virt_dma_buf);
+ kfree(s_req);
+ return -ENOMEM;
+ }
+
+ /* assign the scatter request to this bus request */
+ bus_req->scat_req = s_req;
+ s_req->busrequest = bus_req;
+
+ s_req->virt_scat = virt_scat;
+
+ /* add it to the scatter pool */
+ hif_scatter_req_add(ar_sdio->ar, s_req);
+ }
+
+ return 0;
+}
+
+static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,
+ u32 len, u32 request)
+{
+ struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
+ u8 *tbuf = NULL;
+ int ret;
+ bool bounced = false;
+
+ if (request & HIF_BLOCK_BASIS)
+ len = round_down(len, HIF_MBOX_BLOCK_SIZE);
+
+ if (buf_needs_bounce(buf)) {
+ if (!ar_sdio->dma_buffer)
+ return -ENOMEM;
+ tbuf = ar_sdio->dma_buffer;
+ memcpy(tbuf, buf, len);
+ bounced = true;
+ } else
+ tbuf = buf;
+
+ sdio_claim_host(ar_sdio->func);
+ ret = ath6kl_sdio_io(ar_sdio->func, request, addr, tbuf, len);
+ if ((request & HIF_READ) && bounced)
+ memcpy(buf, tbuf, len);
+ sdio_release_host(ar_sdio->func);
+
+ return ret;
+}
+
+static void __ath6kl_sdio_write_async(struct ath6kl_sdio *ar_sdio,
+ struct bus_request *req)
+{
+ if (req->scat_req)
+ ath6kl_sdio_scat_rw(ar_sdio, req);
+ else {
+ void *context;
+ int status;
+
+ status = ath6kl_sdio_read_write_sync(ar_sdio->ar, req->address,
+ req->buffer, req->length,
+ req->request);
+ context = req->packet;
+ ath6kl_sdio_free_bus_req(ar_sdio, req);
+ ath6kldev_rw_comp_handler(context, status);
+ }
+}
+
+static void ath6kl_sdio_write_async_work(struct work_struct *work)
+{
+ struct ath6kl_sdio *ar_sdio;
+ unsigned long flags;
+ struct bus_request *req, *tmp_req;
+
+ ar_sdio = container_of(work, struct ath6kl_sdio, wr_async_work);
+ sdio_claim_host(ar_sdio->func);
+
+ spin_lock_irqsave(&ar_sdio->wr_async_lock, flags);
+ list_for_each_entry_safe(req, tmp_req, &ar_sdio->wr_asyncq, list) {
+ list_del(&req->list);
+ spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags);
+ __ath6kl_sdio_write_async(ar_sdio, req);
+ spin_lock_irqsave(&ar_sdio->wr_async_lock, flags);
+ }
+ spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags);
+
+ sdio_release_host(ar_sdio->func);
+}
+
+static void ath6kl_sdio_irq_handler(struct sdio_func *func)
+{
+ int status;
+ struct ath6kl_sdio *ar_sdio;
+
+ ath6kl_dbg(ATH6KL_DBG_SDIO, "irq\n");
+
+ ar_sdio = sdio_get_drvdata(func);
+ atomic_set(&ar_sdio->irq_handling, 1);
+
+ /*
+ * Release the host during interrups so we can pick it back up when
+ * we process commands.
+ */
+ sdio_release_host(ar_sdio->func);
+
+ status = ath6kldev_intr_bh_handler(ar_sdio->ar);
+ sdio_claim_host(ar_sdio->func);
+ atomic_set(&ar_sdio->irq_handling, 0);
+ WARN_ON(status && status != -ECANCELED);
+}
+
+static int ath6kl_sdio_power_on(struct ath6kl_sdio *ar_sdio)
+{
+ struct sdio_func *func = ar_sdio->func;
+ int ret = 0;
+
+ if (!ar_sdio->is_disabled)
+ return 0;
+
+ sdio_claim_host(func);
+
+ ret = sdio_enable_func(func);
+ if (ret) {
+ ath6kl_err("Unable to enable sdio func: %d)\n", ret);
+ sdio_release_host(func);
+ return ret;
+ }
+
+ sdio_release_host(func);
+
+ /*
+ * Wait for hardware to initialise. It should take a lot less than
+ * 10 ms but let's be conservative here.
+ */
+ msleep(10);
+
+ ar_sdio->is_disabled = false;
+
+ return ret;
+}
+
+static int ath6kl_sdio_power_off(struct ath6kl_sdio *ar_sdio)
+{
+ int ret;
+
+ if (ar_sdio->is_disabled)
+ return 0;
+
+ /* Disable the card */
+ sdio_claim_host(ar_sdio->func);
+ ret = sdio_disable_func(ar_sdio->func);
+ sdio_release_host(ar_sdio->func);
+
+ if (ret)
+ return ret;
+
+ ar_sdio->is_disabled = true;
+
+ return ret;
+}
+
+static int ath6kl_sdio_write_async(struct ath6kl *ar, u32 address, u8 *buffer,
+ u32 length, u32 request,
+ struct htc_packet *packet)
+{
+ struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
+ struct bus_request *bus_req;
+ unsigned long flags;
+
+ bus_req = ath6kl_sdio_alloc_busreq(ar_sdio);
+
+ if (!bus_req)
+ return -ENOMEM;
+
+ bus_req->address = address;
+ bus_req->buffer = buffer;
+ bus_req->length = length;
+ bus_req->request = request;
+ bus_req->packet = packet;
+
+ spin_lock_irqsave(&ar_sdio->wr_async_lock, flags);
+ list_add_tail(&bus_req->list, &ar_sdio->wr_asyncq);
+ spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags);
+ queue_work(ar->ath6kl_wq, &ar_sdio->wr_async_work);
+
+ return 0;
+}
+
+static void ath6kl_sdio_irq_enable(struct ath6kl *ar)
+{
+ struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
+ int ret;
+
+ sdio_claim_host(ar_sdio->func);
+
+ /* Register the isr */
+ ret = sdio_claim_irq(ar_sdio->func, ath6kl_sdio_irq_handler);
+ if (ret)
+ ath6kl_err("Failed to claim sdio irq: %d\n", ret);
+
+ sdio_release_host(ar_sdio->func);
+}
+
+static void ath6kl_sdio_irq_disable(struct ath6kl *ar)
+{
+ struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
+ int ret;
+
+ sdio_claim_host(ar_sdio->func);
+
+ /* Mask our function IRQ */
+ while (atomic_read(&ar_sdio->irq_handling)) {
+ sdio_release_host(ar_sdio->func);
+ schedule_timeout(HZ / 10);
+ sdio_claim_host(ar_sdio->func);
+ }
+
+ ret = sdio_release_irq(ar_sdio->func);
+ if (ret)
+ ath6kl_err("Failed to release sdio irq: %d\n", ret);
+
+ sdio_release_host(ar_sdio->func);
+}
+
+static struct hif_scatter_req *ath6kl_sdio_scatter_req_get(struct ath6kl *ar)
+{
+ struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
+ struct hif_scatter_req *node = NULL;
+ unsigned long flag;
+
+ spin_lock_irqsave(&ar_sdio->scat_lock, flag);
+
+ if (!list_empty(&ar_sdio->scat_req)) {
+ node = list_first_entry(&ar_sdio->scat_req,
+ struct hif_scatter_req, list);
+ list_del(&node->list);
+ }
+
+ spin_unlock_irqrestore(&ar_sdio->scat_lock, flag);
+
+ return node;
+}
+
+static void ath6kl_sdio_scatter_req_add(struct ath6kl *ar,
+ struct hif_scatter_req *s_req)
+{
+ struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
+ unsigned long flag;
+
+ spin_lock_irqsave(&ar_sdio->scat_lock, flag);
+
+ list_add_tail(&s_req->list, &ar_sdio->scat_req);
+
+ spin_unlock_irqrestore(&ar_sdio->scat_lock, flag);
+
+}
+
+/* scatter gather read write request */
+static int ath6kl_sdio_async_rw_scatter(struct ath6kl *ar,
+ struct hif_scatter_req *scat_req)
+{
+ struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
+ u32 request = scat_req->req;
+ int status = 0;
+ unsigned long flags;
+
+ if (!scat_req->len)
+ return -EINVAL;
+
+ ath6kl_dbg(ATH6KL_DBG_SCATTER,
+ "hif-scatter: total len: %d scatter entries: %d\n",
+ scat_req->len, scat_req->scat_entries);
+
+ if (request & HIF_SYNCHRONOUS) {
+ sdio_claim_host(ar_sdio->func);
+ status = ath6kl_sdio_scat_rw(ar_sdio, scat_req->busrequest);
+ sdio_release_host(ar_sdio->func);
+ } else {
+ spin_lock_irqsave(&ar_sdio->wr_async_lock, flags);
+ list_add_tail(&scat_req->busrequest->list, &ar_sdio->wr_asyncq);
+ spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags);
+ queue_work(ar->ath6kl_wq, &ar_sdio->wr_async_work);
+ }
+
+ return status;
+}
+
+/* clean up scatter support */
+static void ath6kl_sdio_cleanup_scatter(struct ath6kl *ar)
+{
+ struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
+ struct hif_scatter_req *s_req, *tmp_req;
+ unsigned long flag;
+
+ /* empty the free list */
+ spin_lock_irqsave(&ar_sdio->scat_lock, flag);
+ list_for_each_entry_safe(s_req, tmp_req, &ar_sdio->scat_req, list) {
+ list_del(&s_req->list);
+ spin_unlock_irqrestore(&ar_sdio->scat_lock, flag);
+
+ if (s_req->busrequest)
+ ath6kl_sdio_free_bus_req(ar_sdio, s_req->busrequest);
+ kfree(s_req->virt_dma_buf);
+ kfree(s_req->sgentries);
+ kfree(s_req);
+
+ spin_lock_irqsave(&ar_sdio->scat_lock, flag);
+ }
+ spin_unlock_irqrestore(&ar_sdio->scat_lock, flag);
+}
+
+/* setup of HIF scatter resources */
+static int ath6kl_sdio_enable_scatter(struct ath6kl *ar)
+{
+ struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
+ struct htc_target *target = ar->htc_target;
+ int ret;
+ bool virt_scat = false;
+
+ /* check if host supports scatter and it meets our requirements */
+ if (ar_sdio->func->card->host->max_segs < MAX_SCATTER_ENTRIES_PER_REQ) {
+ ath6kl_err("host only supports scatter of :%d entries, need: %d\n",
+ ar_sdio->func->card->host->max_segs,
+ MAX_SCATTER_ENTRIES_PER_REQ);
+ virt_scat = true;
+ }
+
+ if (!virt_scat) {
+ ret = ath6kl_sdio_alloc_prep_scat_req(ar_sdio,
+ MAX_SCATTER_ENTRIES_PER_REQ,
+ MAX_SCATTER_REQUESTS, virt_scat);
+
+ if (!ret) {
+ ath6kl_dbg(ATH6KL_DBG_SCATTER,
+ "hif-scatter enabled: max scatter req : %d entries: %d\n",
+ MAX_SCATTER_REQUESTS,
+ MAX_SCATTER_ENTRIES_PER_REQ);
+
+ target->max_scat_entries = MAX_SCATTER_ENTRIES_PER_REQ;
+ target->max_xfer_szper_scatreq =
+ MAX_SCATTER_REQ_TRANSFER_SIZE;
+ } else {
+ ath6kl_sdio_cleanup_scatter(ar);
+ ath6kl_warn("hif scatter resource setup failed, trying virtual scatter method\n");
+ }
+ }
+
+ if (virt_scat || ret) {
+ ret = ath6kl_sdio_alloc_prep_scat_req(ar_sdio,
+ ATH6KL_SCATTER_ENTRIES_PER_REQ,
+ ATH6KL_SCATTER_REQS, virt_scat);
+
+ if (ret) {
+ ath6kl_err("failed to alloc virtual scatter resources !\n");
+ ath6kl_sdio_cleanup_scatter(ar);
+ return ret;
+ }
+
+ ath6kl_dbg(ATH6KL_DBG_SCATTER,
+ "Vitual scatter enabled, max_scat_req:%d, entries:%d\n",
+ ATH6KL_SCATTER_REQS, ATH6KL_SCATTER_ENTRIES_PER_REQ);
+
+ target->max_scat_entries = ATH6KL_SCATTER_ENTRIES_PER_REQ;
+ target->max_xfer_szper_scatreq =
+ ATH6KL_MAX_TRANSFER_SIZE_PER_SCATTER;
+ }
+
+ return 0;
+}
+
+static int ath6kl_sdio_suspend(struct ath6kl *ar)
+{
+ struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
+ struct sdio_func *func = ar_sdio->func;
+ mmc_pm_flag_t flags;
+ int ret;
+
+ flags = sdio_get_host_pm_caps(func);
+
+ if (!(flags & MMC_PM_KEEP_POWER))
+ /* as host doesn't support keep power we need to bail out */
+ ath6kl_dbg(ATH6KL_DBG_SDIO,
+ "func %d doesn't support MMC_PM_KEEP_POWER\n",
+ func->num);
+ return -EINVAL;
+
+ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+ if (ret) {
+ printk(KERN_ERR "ath6kl: set sdio pm flags failed: %d\n",
+ ret);
+ return ret;
+ }
+
+ ath6kl_deep_sleep_enable(ar);
+
+ return 0;
+}
+
+static const struct ath6kl_hif_ops ath6kl_sdio_ops = {
+ .read_write_sync = ath6kl_sdio_read_write_sync,
+ .write_async = ath6kl_sdio_write_async,
+ .irq_enable = ath6kl_sdio_irq_enable,
+ .irq_disable = ath6kl_sdio_irq_disable,
+ .scatter_req_get = ath6kl_sdio_scatter_req_get,
+ .scatter_req_add = ath6kl_sdio_scatter_req_add,
+ .enable_scatter = ath6kl_sdio_enable_scatter,
+ .scat_req_rw = ath6kl_sdio_async_rw_scatter,
+ .cleanup_scatter = ath6kl_sdio_cleanup_scatter,
+ .suspend = ath6kl_sdio_suspend,
+};
+
+static int ath6kl_sdio_probe(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ int ret;
+ struct ath6kl_sdio *ar_sdio;
+ struct ath6kl *ar;
+ int count;
+
+ ath6kl_dbg(ATH6KL_DBG_SDIO,
+ "new func %d vendor 0x%x device 0x%x block 0x%x/0x%x\n",
+ func->num, func->vendor, func->device,
+ func->max_blksize, func->cur_blksize);
+
+ ar_sdio = kzalloc(sizeof(struct ath6kl_sdio), GFP_KERNEL);
+ if (!ar_sdio)
+ return -ENOMEM;
+
+ ar_sdio->dma_buffer = kzalloc(HIF_DMA_BUFFER_SIZE, GFP_KERNEL);
+ if (!ar_sdio->dma_buffer) {
+ ret = -ENOMEM;
+ goto err_hif;
+ }
+
+ ar_sdio->func = func;
+ sdio_set_drvdata(func, ar_sdio);
+
+ ar_sdio->id = id;
+ ar_sdio->is_disabled = true;
+
+ spin_lock_init(&ar_sdio->lock);
+ spin_lock_init(&ar_sdio->scat_lock);
+ spin_lock_init(&ar_sdio->wr_async_lock);
+
+ INIT_LIST_HEAD(&ar_sdio->scat_req);
+ INIT_LIST_HEAD(&ar_sdio->bus_req_freeq);
+ INIT_LIST_HEAD(&ar_sdio->wr_asyncq);
+
+ INIT_WORK(&ar_sdio->wr_async_work, ath6kl_sdio_write_async_work);
+
+ for (count = 0; count < BUS_REQUEST_MAX_NUM; count++)
+ ath6kl_sdio_free_bus_req(ar_sdio, &ar_sdio->bus_req[count]);
+
+ ar = ath6kl_core_alloc(&ar_sdio->func->dev);
+ if (!ar) {
+ ath6kl_err("Failed to alloc ath6kl core\n");
+ ret = -ENOMEM;
+ goto err_dma;
+ }
+
+ ar_sdio->ar = ar;
+ ar->hif_priv = ar_sdio;
+ ar->hif_ops = &ath6kl_sdio_ops;
+
+ ath6kl_sdio_set_mbox_info(ar);
+
+ sdio_claim_host(func);
+
+ if ((ar_sdio->id->device & MANUFACTURER_ID_ATH6KL_BASE_MASK) >=
+ MANUFACTURER_ID_AR6003_BASE) {
+ /* enable 4-bit ASYNC interrupt on AR6003 or later */
+ ret = ath6kl_sdio_func0_cmd52_wr_byte(func->card,
+ CCCR_SDIO_IRQ_MODE_REG,
+ SDIO_IRQ_MODE_ASYNC_4BIT_IRQ);
+ if (ret) {
+ ath6kl_err("Failed to enable 4-bit async irq mode %d\n",
+ ret);
+ sdio_release_host(func);
+ goto err_cfg80211;
+ }
+
+ ath6kl_dbg(ATH6KL_DBG_SDIO, "4-bit async irq mode enabled\n");
+ }
+
+ /* give us some time to enable, in ms */
+ func->enable_timeout = 100;
+
+ sdio_release_host(func);
+
+ ret = ath6kl_sdio_power_on(ar_sdio);
+ if (ret)
+ goto err_cfg80211;
+
+ sdio_claim_host(func);
+
+ ret = sdio_set_block_size(func, HIF_MBOX_BLOCK_SIZE);
+ if (ret) {
+ ath6kl_err("Set sdio block size %d failed: %d)\n",
+ HIF_MBOX_BLOCK_SIZE, ret);
+ sdio_release_host(func);
+ goto err_off;
+ }
+
+ sdio_release_host(func);
+
+ ret = ath6kl_core_init(ar);
+ if (ret) {
+ ath6kl_err("Failed to init ath6kl core\n");
+ goto err_off;
+ }
+
+ return ret;
+
+err_off:
+ ath6kl_sdio_power_off(ar_sdio);
+err_cfg80211:
+ ath6kl_cfg80211_deinit(ar_sdio->ar);
+err_dma:
+ kfree(ar_sdio->dma_buffer);
+err_hif:
+ kfree(ar_sdio);
+
+ return ret;
+}
+
+static void ath6kl_sdio_remove(struct sdio_func *func)
+{
+ struct ath6kl_sdio *ar_sdio;
+
+ ath6kl_dbg(ATH6KL_DBG_SDIO,
+ "removed func %d vendor 0x%x device 0x%x\n",
+ func->num, func->vendor, func->device);
+
+ ar_sdio = sdio_get_drvdata(func);
+
+ ath6kl_stop_txrx(ar_sdio->ar);
+ cancel_work_sync(&ar_sdio->wr_async_work);
+
+ ath6kl_unavail_ev(ar_sdio->ar);
+
+ ath6kl_sdio_power_off(ar_sdio);
+
+ kfree(ar_sdio->dma_buffer);
+ kfree(ar_sdio);
+}
+
+static const struct sdio_device_id ath6kl_sdio_devices[] = {
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x0))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x1))},
+ {},
+};
+
+MODULE_DEVICE_TABLE(sdio, ath6kl_sdio_devices);
+
+static struct sdio_driver ath6kl_sdio_driver = {
+ .name = "ath6kl_sdio",
+ .id_table = ath6kl_sdio_devices,
+ .probe = ath6kl_sdio_probe,
+ .remove = ath6kl_sdio_remove,
+};
+
+static int __init ath6kl_sdio_init(void)
+{
+ int ret;
+
+ ret = sdio_register_driver(&ath6kl_sdio_driver);
+ if (ret)
+ ath6kl_err("sdio driver registration failed: %d\n", ret);
+
+ return ret;
+}
+
+static void __exit ath6kl_sdio_exit(void)
+{
+ sdio_unregister_driver(&ath6kl_sdio_driver);
+}
+
+module_init(ath6kl_sdio_init);
+module_exit(ath6kl_sdio_exit);
+
+MODULE_AUTHOR("Atheros Communications, Inc.");
+MODULE_DESCRIPTION("Driver support for Atheros AR600x SDIO devices");
+MODULE_LICENSE("Dual BSD/GPL");
+
+MODULE_FIRMWARE(AR6003_REV2_OTP_FILE);
+MODULE_FIRMWARE(AR6003_REV2_FIRMWARE_FILE);
+MODULE_FIRMWARE(AR6003_REV2_PATCH_FILE);
+MODULE_FIRMWARE(AR6003_REV2_BOARD_DATA_FILE);
+MODULE_FIRMWARE(AR6003_REV2_DEFAULT_BOARD_DATA_FILE);
+MODULE_FIRMWARE(AR6003_REV3_OTP_FILE);
+MODULE_FIRMWARE(AR6003_REV3_FIRMWARE_FILE);
+MODULE_FIRMWARE(AR6003_REV3_PATCH_FILE);
+MODULE_FIRMWARE(AR6003_REV3_BOARD_DATA_FILE);
+MODULE_FIRMWARE(AR6003_REV3_DEFAULT_BOARD_DATA_FILE);
diff --git a/drivers/net/wireless/ath/ath6kl/target.h b/drivers/net/wireless/ath/ath6kl/target.h
new file mode 100644
index 000000000000..c9a76051f042
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/target.h
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2004-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 TARGET_H
+#define TARGET_H
+
+#define AR6003_BOARD_DATA_SZ 1024
+#define AR6003_BOARD_EXT_DATA_SZ 768
+
+#define AR6004_BOARD_DATA_SZ 7168
+#define AR6004_BOARD_EXT_DATA_SZ 0
+
+#define RESET_CONTROL_ADDRESS 0x00000000
+#define RESET_CONTROL_COLD_RST 0x00000100
+#define RESET_CONTROL_MBOX_RST 0x00000004
+
+#define CPU_CLOCK_STANDARD_S 0
+#define CPU_CLOCK_STANDARD 0x00000003
+#define CPU_CLOCK_ADDRESS 0x00000020
+
+#define CLOCK_CONTROL_ADDRESS 0x00000028
+#define CLOCK_CONTROL_LF_CLK32_S 2
+#define CLOCK_CONTROL_LF_CLK32 0x00000004
+
+#define SYSTEM_SLEEP_ADDRESS 0x000000c4
+#define SYSTEM_SLEEP_DISABLE_S 0
+#define SYSTEM_SLEEP_DISABLE 0x00000001
+
+#define LPO_CAL_ADDRESS 0x000000e0
+#define LPO_CAL_ENABLE_S 20
+#define LPO_CAL_ENABLE 0x00100000
+
+#define GPIO_PIN10_ADDRESS 0x00000050
+#define GPIO_PIN11_ADDRESS 0x00000054
+#define GPIO_PIN12_ADDRESS 0x00000058
+#define GPIO_PIN13_ADDRESS 0x0000005c
+
+#define HOST_INT_STATUS_ADDRESS 0x00000400
+#define HOST_INT_STATUS_ERROR_S 7
+#define HOST_INT_STATUS_ERROR 0x00000080
+
+#define HOST_INT_STATUS_CPU_S 6
+#define HOST_INT_STATUS_CPU 0x00000040
+
+#define HOST_INT_STATUS_COUNTER_S 4
+#define HOST_INT_STATUS_COUNTER 0x00000010
+
+#define CPU_INT_STATUS_ADDRESS 0x00000401
+
+#define ERROR_INT_STATUS_ADDRESS 0x00000402
+#define ERROR_INT_STATUS_WAKEUP_S 2
+#define ERROR_INT_STATUS_WAKEUP 0x00000004
+
+#define ERROR_INT_STATUS_RX_UNDERFLOW_S 1
+#define ERROR_INT_STATUS_RX_UNDERFLOW 0x00000002
+
+#define ERROR_INT_STATUS_TX_OVERFLOW_S 0
+#define ERROR_INT_STATUS_TX_OVERFLOW 0x00000001
+
+#define COUNTER_INT_STATUS_ADDRESS 0x00000403
+#define COUNTER_INT_STATUS_COUNTER_S 0
+#define COUNTER_INT_STATUS_COUNTER 0x000000ff
+
+#define RX_LOOKAHEAD_VALID_ADDRESS 0x00000405
+
+#define INT_STATUS_ENABLE_ADDRESS 0x00000418
+#define INT_STATUS_ENABLE_ERROR_S 7
+#define INT_STATUS_ENABLE_ERROR 0x00000080
+
+#define INT_STATUS_ENABLE_CPU_S 6
+#define INT_STATUS_ENABLE_CPU 0x00000040
+
+#define INT_STATUS_ENABLE_INT_S 5
+#define INT_STATUS_ENABLE_INT 0x00000020
+#define INT_STATUS_ENABLE_COUNTER_S 4
+#define INT_STATUS_ENABLE_COUNTER 0x00000010
+
+#define INT_STATUS_ENABLE_MBOX_DATA_S 0
+#define INT_STATUS_ENABLE_MBOX_DATA 0x0000000f
+
+#define CPU_INT_STATUS_ENABLE_ADDRESS 0x00000419
+#define CPU_INT_STATUS_ENABLE_BIT_S 0
+#define CPU_INT_STATUS_ENABLE_BIT 0x000000ff
+
+#define ERROR_STATUS_ENABLE_ADDRESS 0x0000041a
+#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_S 1
+#define ERROR_STATUS_ENABLE_RX_UNDERFLOW 0x00000002
+
+#define ERROR_STATUS_ENABLE_TX_OVERFLOW_S 0
+#define ERROR_STATUS_ENABLE_TX_OVERFLOW 0x00000001
+
+#define COUNTER_INT_STATUS_ENABLE_ADDRESS 0x0000041b
+#define COUNTER_INT_STATUS_ENABLE_BIT_S 0
+#define COUNTER_INT_STATUS_ENABLE_BIT 0x000000ff
+
+#define COUNT_ADDRESS 0x00000420
+
+#define COUNT_DEC_ADDRESS 0x00000440
+
+#define WINDOW_DATA_ADDRESS 0x00000474
+#define WINDOW_WRITE_ADDR_ADDRESS 0x00000478
+#define WINDOW_READ_ADDR_ADDRESS 0x0000047c
+#define CPU_DBG_SEL_ADDRESS 0x00000483
+#define CPU_DBG_ADDRESS 0x00000484
+
+#define LOCAL_SCRATCH_ADDRESS 0x000000c0
+#define ATH6KL_OPTION_SLEEP_DISABLE 0x08
+
+#define RTC_BASE_ADDRESS 0x00004000
+#define GPIO_BASE_ADDRESS 0x00014000
+#define MBOX_BASE_ADDRESS 0x00018000
+#define ANALOG_INTF_BASE_ADDRESS 0x0001c000
+
+/* real name of the register is unknown */
+#define ATH6KL_ANALOG_PLL_REGISTER (ANALOG_INTF_BASE_ADDRESS + 0x284)
+
+#define SM(f, v) (((v) << f##_S) & f)
+#define MS(f, v) (((v) & f) >> f##_S)
+
+/*
+ * xxx_HOST_INTEREST_ADDRESS is the address in Target RAM of the
+ * host_interest structure.
+ *
+ * Host Interest is shared between Host and Target in order to coordinate
+ * between the two, and is intended to remain constant (with additions only
+ * at the end).
+ */
+#define ATH6KL_AR6003_HI_START_ADDR 0x00540600
+#define ATH6KL_AR6004_HI_START_ADDR 0x00400800
+
+/*
+ * These are items that the Host may need to access
+ * via BMI or via the Diagnostic Window. The position
+ * of items in this structure must remain constant.
+ * across firmware revisions!
+ *
+ * Types for each item must be fixed size across target and host platforms.
+ * The structure is used only to calculate offset for each register with
+ * HI_ITEM() macro, no values are stored to it.
+ *
+ * More items may be added at the end.
+ */
+struct host_interest {
+ /*
+ * Pointer to application-defined area, if any.
+ * Set by Target application during startup.
+ */
+ u32 hi_app_host_interest; /* 0x00 */
+
+ /* Pointer to register dump area, valid after Target crash. */
+ u32 hi_failure_state; /* 0x04 */
+
+ /* Pointer to debug logging header */
+ u32 hi_dbglog_hdr; /* 0x08 */
+
+ u32 hi_unused1; /* 0x0c */
+
+ /*
+ * General-purpose flag bits, similar to ATH6KL_OPTION_* flags.
+ * Can be used by application rather than by OS.
+ */
+ u32 hi_option_flag; /* 0x10 */
+
+ /*
+ * Boolean that determines whether or not to
+ * display messages on the serial port.
+ */
+ u32 hi_serial_enable; /* 0x14 */
+
+ /* Start address of DataSet index, if any */
+ u32 hi_dset_list_head; /* 0x18 */
+
+ /* Override Target application start address */
+ u32 hi_app_start; /* 0x1c */
+
+ /* Clock and voltage tuning */
+ u32 hi_skip_clock_init; /* 0x20 */
+ u32 hi_core_clock_setting; /* 0x24 */
+ u32 hi_cpu_clock_setting; /* 0x28 */
+ u32 hi_system_sleep_setting; /* 0x2c */
+ u32 hi_xtal_control_setting; /* 0x30 */
+ u32 hi_pll_ctrl_setting_24ghz; /* 0x34 */
+ u32 hi_pll_ctrl_setting_5ghz; /* 0x38 */
+ u32 hi_ref_voltage_trim_setting; /* 0x3c */
+ u32 hi_clock_info; /* 0x40 */
+
+ /*
+ * Flash configuration overrides, used only
+ * when firmware is not executing from flash.
+ * (When using flash, modify the global variables
+ * with equivalent names.)
+ */
+ u32 hi_bank0_addr_value; /* 0x44 */
+ u32 hi_bank0_read_value; /* 0x48 */
+ u32 hi_bank0_write_value; /* 0x4c */
+ u32 hi_bank0_config_value; /* 0x50 */
+
+ /* Pointer to Board Data */
+ u32 hi_board_data; /* 0x54 */
+ u32 hi_board_data_initialized; /* 0x58 */
+
+ u32 hi_dset_ram_index_tbl; /* 0x5c */
+
+ u32 hi_desired_baud_rate; /* 0x60 */
+ u32 hi_dbglog_config; /* 0x64 */
+ u32 hi_end_ram_reserve_sz; /* 0x68 */
+ u32 hi_mbox_io_block_sz; /* 0x6c */
+
+ u32 hi_num_bpatch_streams; /* 0x70 -- unused */
+ u32 hi_mbox_isr_yield_limit; /* 0x74 */
+
+ u32 hi_refclk_hz; /* 0x78 */
+ u32 hi_ext_clk_detected; /* 0x7c */
+ u32 hi_dbg_uart_txpin; /* 0x80 */
+ u32 hi_dbg_uart_rxpin; /* 0x84 */
+ u32 hi_hci_uart_baud; /* 0x88 */
+ u32 hi_hci_uart_pin_assignments; /* 0x8C */
+ /*
+ * NOTE: byte [0] = tx pin, [1] = rx pin, [2] = rts pin, [3] = cts
+ * pin
+ */
+ u32 hi_hci_uart_baud_scale_val; /* 0x90 */
+ u32 hi_hci_uart_baud_step_val; /* 0x94 */
+
+ u32 hi_allocram_start; /* 0x98 */
+ u32 hi_allocram_sz; /* 0x9c */
+ u32 hi_hci_bridge_flags; /* 0xa0 */
+ u32 hi_hci_uart_support_pins; /* 0xa4 */
+ /*
+ * NOTE: byte [0] = RESET pin (bit 7 is polarity),
+ * bytes[1]..bytes[3] are for future use
+ */
+ u32 hi_hci_uart_pwr_mgmt_params; /* 0xa8 */
+ /*
+ * 0xa8 - [1]: 0 = UART FC active low, 1 = UART FC active high
+ * [31:16]: wakeup timeout in ms
+ */
+
+ /* Pointer to extended board data */
+ u32 hi_board_ext_data; /* 0xac */
+ u32 hi_board_ext_data_config; /* 0xb0 */
+
+ /*
+ * Bit [0] : valid
+ * Bit[31:16: size
+ */
+ /*
+ * hi_reset_flag is used to do some stuff when target reset.
+ * such as restore app_start after warm reset or
+ * preserve host Interest area, or preserve ROM data, literals etc.
+ */
+ u32 hi_reset_flag; /* 0xb4 */
+ /* indicate hi_reset_flag is valid */
+ u32 hi_reset_flag_valid; /* 0xb8 */
+ u32 hi_hci_uart_pwr_mgmt_params_ext; /* 0xbc */
+ /*
+ * 0xbc - [31:0]: idle timeout in ms
+ */
+ /* ACS flags */
+ u32 hi_acs_flags; /* 0xc0 */
+ u32 hi_console_flags; /* 0xc4 */
+ u32 hi_nvram_state; /* 0xc8 */
+ u32 hi_option_flag2; /* 0xcc */
+
+ /* If non-zero, override values sent to Host in WMI_READY event. */
+ u32 hi_sw_version_override; /* 0xd0 */
+ u32 hi_abi_version_override; /* 0xd4 */
+
+ /*
+ * Percentage of high priority RX traffic to total expected RX traffic -
+ * applicable only to ar6004
+ */
+ u32 hi_hp_rx_traffic_ratio; /* 0xd8 */
+
+ /* test applications flags */
+ u32 hi_test_apps_related ; /* 0xdc */
+ /* location of test script */
+ u32 hi_ota_testscript; /* 0xe0 */
+ /* location of CAL data */
+ u32 hi_cal_data; /* 0xe4 */
+ /* Number of packet log buffers */
+ u32 hi_pktlog_num_buffers; /* 0xe8 */
+
+} __packed;
+
+#define HI_ITEM(item) offsetof(struct host_interest, item)
+
+#define HI_OPTION_MAC_ADDR_METHOD_SHIFT 3
+
+#define HI_OPTION_FW_MODE_IBSS 0x0
+#define HI_OPTION_FW_MODE_BSS_STA 0x1
+#define HI_OPTION_FW_MODE_AP 0x2
+
+#define HI_OPTION_FW_SUBMODE_NONE 0x0
+#define HI_OPTION_FW_SUBMODE_P2PDEV 0x1
+#define HI_OPTION_FW_SUBMODE_P2PCLIENT 0x2
+#define HI_OPTION_FW_SUBMODE_P2PGO 0x3
+
+#define HI_OPTION_NUM_DEV_SHIFT 0x9
+
+#define HI_OPTION_FW_BRIDGE_SHIFT 0x04
+
+/* Fw Mode/SubMode Mask
+|------------------------------------------------------------------------------|
+| SUB | SUB | SUB | SUB | | | |
+| MODE[3] | MODE[2] | MODE[1] | MODE[0] | MODE[3] | MODE[2] | MODE[1] | MODE[0|
+| (2) | (2) | (2) | (2) | (2) | (2) | (2) | (2)
+|------------------------------------------------------------------------------|
+*/
+#define HI_OPTION_FW_MODE_SHIFT 0xC
+#define HI_OPTION_FW_SUBMODE_SHIFT 0x14
+
+/* Convert a Target virtual address into a Target physical address */
+#define AR6003_VTOP(vaddr) ((vaddr) & 0x001fffff)
+#define AR6004_VTOP(vaddr) (vaddr)
+
+#define TARG_VTOP(target_type, vaddr) \
+ (((target_type) == TARGET_TYPE_AR6003) ? AR6003_VTOP(vaddr) : \
+ (((target_type) == TARGET_TYPE_AR6004) ? AR6004_VTOP(vaddr) : 0))
+
+#define AR6003_REV2_APP_LOAD_ADDRESS 0x543180
+#define AR6003_REV2_BOARD_EXT_DATA_ADDRESS 0x57E500
+#define AR6003_REV2_DATASET_PATCH_ADDRESS 0x57e884
+#define AR6003_REV2_RAM_RESERVE_SIZE 6912
+
+#define AR6003_REV3_APP_LOAD_ADDRESS 0x545000
+#define AR6003_REV3_BOARD_EXT_DATA_ADDRESS 0x542330
+#define AR6003_REV3_DATASET_PATCH_ADDRESS 0x57FF74
+#define AR6003_REV3_RAM_RESERVE_SIZE 512
+
+#define AR6004_REV1_BOARD_DATA_ADDRESS 0x435400
+#define AR6004_REV1_BOARD_EXT_DATA_ADDRESS 0x437000
+#define AR6004_REV1_RAM_RESERVE_SIZE 11264
+
+#define ATH6KL_FWLOG_PAYLOAD_SIZE 1500
+
+struct ath6kl_dbglog_buf {
+ __le32 next;
+ __le32 buffer_addr;
+ __le32 bufsize;
+ __le32 length;
+ __le32 count;
+ __le32 free;
+} __packed;
+
+struct ath6kl_dbglog_hdr {
+ __le32 dbuf_addr;
+ __le32 dropped;
+} __packed;
+
+#endif
diff --git a/drivers/net/wireless/ath/ath6kl/testmode.c b/drivers/net/wireless/ath/ath6kl/testmode.c
new file mode 100644
index 000000000000..381eb66a605f
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/testmode.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "testmode.h"
+
+#include <net/netlink.h>
+
+enum ath6kl_tm_attr {
+ __ATH6KL_TM_ATTR_INVALID = 0,
+ ATH6KL_TM_ATTR_CMD = 1,
+ ATH6KL_TM_ATTR_DATA = 2,
+
+ /* keep last */
+ __ATH6KL_TM_ATTR_AFTER_LAST,
+ ATH6KL_TM_ATTR_MAX = __ATH6KL_TM_ATTR_AFTER_LAST - 1,
+};
+
+enum ath6kl_tm_cmd {
+ ATH6KL_TM_CMD_TCMD = 0,
+ ATH6KL_TM_CMD_RX_REPORT = 1,
+};
+
+#define ATH6KL_TM_DATA_MAX_LEN 5000
+
+static const struct nla_policy ath6kl_tm_policy[ATH6KL_TM_ATTR_MAX + 1] = {
+ [ATH6KL_TM_ATTR_CMD] = { .type = NLA_U32 },
+ [ATH6KL_TM_ATTR_DATA] = { .type = NLA_BINARY,
+ .len = ATH6KL_TM_DATA_MAX_LEN },
+};
+
+void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf, size_t buf_len)
+{
+ if (down_interruptible(&ar->sem))
+ return;
+
+ kfree(ar->tm.rx_report);
+
+ ar->tm.rx_report = kmemdup(buf, buf_len, GFP_KERNEL);
+ ar->tm.rx_report_len = buf_len;
+
+ up(&ar->sem);
+
+ wake_up(&ar->event_wq);
+}
+
+static int ath6kl_tm_rx_report(struct ath6kl *ar, void *buf, size_t buf_len,
+ struct sk_buff *skb)
+{
+ int ret = 0;
+ long left;
+
+ if (down_interruptible(&ar->sem))
+ return -ERESTARTSYS;
+
+ if (!test_bit(WMI_READY, &ar->flag)) {
+ ret = -EIO;
+ goto out;
+ }
+
+ if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (ath6kl_wmi_test_cmd(ar->wmi, buf, buf_len) < 0) {
+ up(&ar->sem);
+ return -EIO;
+ }
+
+ left = wait_event_interruptible_timeout(ar->event_wq,
+ ar->tm.rx_report != NULL,
+ WMI_TIMEOUT);
+
+ if (left == 0) {
+ ret = -ETIMEDOUT;
+ goto out;
+ } else if (left < 0) {
+ ret = left;
+ goto out;
+ }
+
+ if (ar->tm.rx_report == NULL || ar->tm.rx_report_len == 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ NLA_PUT(skb, ATH6KL_TM_ATTR_DATA, ar->tm.rx_report_len,
+ ar->tm.rx_report);
+
+ kfree(ar->tm.rx_report);
+ ar->tm.rx_report = NULL;
+
+out:
+ up(&ar->sem);
+
+ return ret;
+
+nla_put_failure:
+ ret = -ENOBUFS;
+ goto out;
+}
+
+int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len)
+{
+ struct ath6kl *ar = wiphy_priv(wiphy);
+ struct nlattr *tb[ATH6KL_TM_ATTR_MAX + 1];
+ int err, buf_len, reply_len;
+ struct sk_buff *skb;
+ void *buf;
+
+ err = nla_parse(tb, ATH6KL_TM_ATTR_MAX, data, len,
+ ath6kl_tm_policy);
+ if (err)
+ return err;
+
+ if (!tb[ATH6KL_TM_ATTR_CMD])
+ return -EINVAL;
+
+ switch (nla_get_u32(tb[ATH6KL_TM_ATTR_CMD])) {
+ case ATH6KL_TM_CMD_TCMD:
+ if (!tb[ATH6KL_TM_ATTR_DATA])
+ return -EINVAL;
+
+ buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]);
+ buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]);
+
+ ath6kl_wmi_test_cmd(ar->wmi, buf, buf_len);
+
+ return 0;
+
+ break;
+ case ATH6KL_TM_CMD_RX_REPORT:
+ if (!tb[ATH6KL_TM_ATTR_DATA])
+ return -EINVAL;
+
+ buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]);
+ buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]);
+
+ reply_len = nla_total_size(ATH6KL_TM_DATA_MAX_LEN);
+ skb = cfg80211_testmode_alloc_reply_skb(wiphy, reply_len);
+ if (!skb)
+ return -ENOMEM;
+
+ err = ath6kl_tm_rx_report(ar, buf, buf_len, skb);
+ if (err < 0) {
+ kfree_skb(skb);
+ return err;
+ }
+
+ return cfg80211_testmode_reply(skb);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
diff --git a/drivers/net/wireless/ath/ath6kl/testmode.h b/drivers/net/wireless/ath/ath6kl/testmode.h
new file mode 100644
index 000000000000..43dffcc11fb1
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/testmode.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+
+#ifdef CONFIG_NL80211_TESTMODE
+
+void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf, size_t buf_len);
+int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len);
+
+#else
+
+static inline void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf,
+ size_t buf_len)
+{
+}
+
+static inline int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len)
+{
+ return 0;
+}
+
+#endif
diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c
new file mode 100644
index 000000000000..a7117074f81c
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/txrx.c
@@ -0,0 +1,1478 @@
+/*
+ * Copyright (c) 2004-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "debug.h"
+
+static u8 ath6kl_ibss_map_epid(struct sk_buff *skb, struct net_device *dev,
+ u32 *map_no)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+ struct ethhdr *eth_hdr;
+ u32 i, ep_map = -1;
+ u8 *datap;
+
+ *map_no = 0;
+ datap = skb->data;
+ eth_hdr = (struct ethhdr *) (datap + sizeof(struct wmi_data_hdr));
+
+ if (is_multicast_ether_addr(eth_hdr->h_dest))
+ return ENDPOINT_2;
+
+ for (i = 0; i < ar->node_num; i++) {
+ if (memcmp(eth_hdr->h_dest, ar->node_map[i].mac_addr,
+ ETH_ALEN) == 0) {
+ *map_no = i + 1;
+ ar->node_map[i].tx_pend++;
+ return ar->node_map[i].ep_id;
+ }
+
+ if ((ep_map == -1) && !ar->node_map[i].tx_pend)
+ ep_map = i;
+ }
+
+ if (ep_map == -1) {
+ ep_map = ar->node_num;
+ ar->node_num++;
+ if (ar->node_num > MAX_NODE_NUM)
+ return ENDPOINT_UNUSED;
+ }
+
+ memcpy(ar->node_map[ep_map].mac_addr, eth_hdr->h_dest, ETH_ALEN);
+
+ for (i = ENDPOINT_2; i <= ENDPOINT_5; i++) {
+ if (!ar->tx_pending[i]) {
+ ar->node_map[ep_map].ep_id = i;
+ break;
+ }
+
+ /*
+ * No free endpoint is available, start redistribution on
+ * the inuse endpoints.
+ */
+ if (i == ENDPOINT_5) {
+ ar->node_map[ep_map].ep_id = ar->next_ep_id;
+ ar->next_ep_id++;
+ if (ar->next_ep_id > ENDPOINT_5)
+ ar->next_ep_id = ENDPOINT_2;
+ }
+ }
+
+ *map_no = ep_map + 1;
+ ar->node_map[ep_map].tx_pend++;
+
+ return ar->node_map[ep_map].ep_id;
+}
+
+static bool ath6kl_powersave_ap(struct ath6kl *ar, struct sk_buff *skb,
+ bool *more_data)
+{
+ struct ethhdr *datap = (struct ethhdr *) skb->data;
+ struct ath6kl_sta *conn = NULL;
+ bool ps_queued = false, is_psq_empty = false;
+
+ if (is_multicast_ether_addr(datap->h_dest)) {
+ u8 ctr = 0;
+ bool q_mcast = false;
+
+ for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
+ if (ar->sta_list[ctr].sta_flags & STA_PS_SLEEP) {
+ q_mcast = true;
+ break;
+ }
+ }
+
+ if (q_mcast) {
+ /*
+ * If this transmit is not because of a Dtim Expiry
+ * q it.
+ */
+ if (!test_bit(DTIM_EXPIRED, &ar->flag)) {
+ bool is_mcastq_empty = false;
+
+ spin_lock_bh(&ar->mcastpsq_lock);
+ is_mcastq_empty =
+ skb_queue_empty(&ar->mcastpsq);
+ skb_queue_tail(&ar->mcastpsq, skb);
+ spin_unlock_bh(&ar->mcastpsq_lock);
+
+ /*
+ * If this is the first Mcast pkt getting
+ * queued indicate to the target to set the
+ * BitmapControl LSB of the TIM IE.
+ */
+ if (is_mcastq_empty)
+ ath6kl_wmi_set_pvb_cmd(ar->wmi,
+ MCAST_AID, 1);
+
+ ps_queued = true;
+ } else {
+ /*
+ * This transmit is because of Dtim expiry.
+ * Determine if MoreData bit has to be set.
+ */
+ spin_lock_bh(&ar->mcastpsq_lock);
+ if (!skb_queue_empty(&ar->mcastpsq))
+ *more_data = true;
+ spin_unlock_bh(&ar->mcastpsq_lock);
+ }
+ }
+ } else {
+ conn = ath6kl_find_sta(ar, datap->h_dest);
+ if (!conn) {
+ dev_kfree_skb(skb);
+
+ /* Inform the caller that the skb is consumed */
+ return true;
+ }
+
+ if (conn->sta_flags & STA_PS_SLEEP) {
+ if (!(conn->sta_flags & STA_PS_POLLED)) {
+ /* Queue the frames if the STA is sleeping */
+ spin_lock_bh(&conn->psq_lock);
+ is_psq_empty = skb_queue_empty(&conn->psq);
+ skb_queue_tail(&conn->psq, skb);
+ spin_unlock_bh(&conn->psq_lock);
+
+ /*
+ * If this is the first pkt getting queued
+ * for this STA, update the PVB for this
+ * STA.
+ */
+ if (is_psq_empty)
+ ath6kl_wmi_set_pvb_cmd(ar->wmi,
+ conn->aid, 1);
+
+ ps_queued = true;
+ } else {
+ /*
+ * This tx is because of a PsPoll.
+ * Determine if MoreData bit has to be set.
+ */
+ spin_lock_bh(&conn->psq_lock);
+ if (!skb_queue_empty(&conn->psq))
+ *more_data = true;
+ spin_unlock_bh(&conn->psq_lock);
+ }
+ }
+ }
+
+ return ps_queued;
+}
+
+/* Tx functions */
+
+int ath6kl_control_tx(void *devt, struct sk_buff *skb,
+ enum htc_endpoint_id eid)
+{
+ struct ath6kl *ar = devt;
+ int status = 0;
+ struct ath6kl_cookie *cookie = NULL;
+
+ spin_lock_bh(&ar->lock);
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_TX,
+ "%s: skb=0x%p, len=0x%x eid =%d\n", __func__,
+ skb, skb->len, eid);
+
+ if (test_bit(WMI_CTRL_EP_FULL, &ar->flag) && (eid == ar->ctrl_ep)) {
+ /*
+ * Control endpoint is full, don't allocate resources, we
+ * are just going to drop this packet.
+ */
+ cookie = NULL;
+ ath6kl_err("wmi ctrl ep full, dropping pkt : 0x%p, len:%d\n",
+ skb, skb->len);
+ } else
+ cookie = ath6kl_alloc_cookie(ar);
+
+ if (cookie == NULL) {
+ spin_unlock_bh(&ar->lock);
+ status = -ENOMEM;
+ goto fail_ctrl_tx;
+ }
+
+ ar->tx_pending[eid]++;
+
+ if (eid != ar->ctrl_ep)
+ ar->total_tx_data_pend++;
+
+ spin_unlock_bh(&ar->lock);
+
+ cookie->skb = skb;
+ cookie->map_no = 0;
+ set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len,
+ eid, ATH6KL_CONTROL_PKT_TAG);
+
+ /*
+ * This interface is asynchronous, if there is an error, cleanup
+ * will happen in the TX completion callback.
+ */
+ ath6kl_htc_tx(ar->htc_target, &cookie->htc_pkt);
+
+ return 0;
+
+fail_ctrl_tx:
+ dev_kfree_skb(skb);
+ return status;
+}
+
+int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+ struct ath6kl_cookie *cookie = NULL;
+ enum htc_endpoint_id eid = ENDPOINT_UNUSED;
+ u32 map_no = 0;
+ u16 htc_tag = ATH6KL_DATA_PKT_TAG;
+ u8 ac = 99 ; /* initialize to unmapped ac */
+ bool chk_adhoc_ps_mapping = false, more_data = false;
+ int ret;
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_TX,
+ "%s: skb=0x%p, data=0x%p, len=0x%x\n", __func__,
+ skb, skb->data, skb->len);
+
+ /* If target is not associated */
+ if (!test_bit(CONNECTED, &ar->flag)) {
+ dev_kfree_skb(skb);
+ return 0;
+ }
+
+ if (!test_bit(WMI_READY, &ar->flag))
+ goto fail_tx;
+
+ /* AP mode Power saving processing */
+ if (ar->nw_type == AP_NETWORK) {
+ if (ath6kl_powersave_ap(ar, skb, &more_data))
+ return 0;
+ }
+
+ if (test_bit(WMI_ENABLED, &ar->flag)) {
+ if (skb_headroom(skb) < dev->needed_headroom) {
+ WARN_ON(1);
+ goto fail_tx;
+ }
+
+ if (ath6kl_wmi_dix_2_dot3(ar->wmi, skb)) {
+ ath6kl_err("ath6kl_wmi_dix_2_dot3 failed\n");
+ goto fail_tx;
+ }
+
+ if (ath6kl_wmi_data_hdr_add(ar->wmi, skb, DATA_MSGTYPE,
+ more_data, 0, 0, NULL)) {
+ ath6kl_err("wmi_data_hdr_add failed\n");
+ goto fail_tx;
+ }
+
+ if ((ar->nw_type == ADHOC_NETWORK) &&
+ ar->ibss_ps_enable && test_bit(CONNECTED, &ar->flag))
+ chk_adhoc_ps_mapping = true;
+ else {
+ /* get the stream mapping */
+ ret = ath6kl_wmi_implicit_create_pstream(ar->wmi, skb,
+ 0, test_bit(WMM_ENABLED, &ar->flag), &ac);
+ if (ret)
+ goto fail_tx;
+ }
+ } else
+ goto fail_tx;
+
+ spin_lock_bh(&ar->lock);
+
+ if (chk_adhoc_ps_mapping)
+ eid = ath6kl_ibss_map_epid(skb, dev, &map_no);
+ else
+ eid = ar->ac2ep_map[ac];
+
+ if (eid == 0 || eid == ENDPOINT_UNUSED) {
+ ath6kl_err("eid %d is not mapped!\n", eid);
+ spin_unlock_bh(&ar->lock);
+ goto fail_tx;
+ }
+
+ /* allocate resource for this packet */
+ cookie = ath6kl_alloc_cookie(ar);
+
+ if (!cookie) {
+ spin_unlock_bh(&ar->lock);
+ goto fail_tx;
+ }
+
+ /* update counts while the lock is held */
+ ar->tx_pending[eid]++;
+ ar->total_tx_data_pend++;
+
+ spin_unlock_bh(&ar->lock);
+
+ if (!IS_ALIGNED((unsigned long) skb->data - HTC_HDR_LENGTH, 4) &&
+ skb_cloned(skb)) {
+ /*
+ * We will touch (move the buffer data to align it. Since the
+ * skb buffer is cloned and not only the header is changed, we
+ * have to copy it to allow the changes. Since we are copying
+ * the data here, we may as well align it by reserving suitable
+ * headroom to avoid the memmove in ath6kl_htc_tx_buf_align().
+ */
+ struct sk_buff *nskb;
+
+ nskb = skb_copy_expand(skb, HTC_HDR_LENGTH, 0, GFP_ATOMIC);
+ if (nskb == NULL)
+ goto fail_tx;
+ kfree_skb(skb);
+ skb = nskb;
+ }
+
+ cookie->skb = skb;
+ cookie->map_no = map_no;
+ set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len,
+ eid, htc_tag);
+
+ ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "tx ",
+ skb->data, skb->len);
+
+ /*
+ * HTC interface is asynchronous, if this fails, cleanup will
+ * happen in the ath6kl_tx_complete callback.
+ */
+ ath6kl_htc_tx(ar->htc_target, &cookie->htc_pkt);
+
+ return 0;
+
+fail_tx:
+ dev_kfree_skb(skb);
+
+ ar->net_stats.tx_dropped++;
+ ar->net_stats.tx_aborted_errors++;
+
+ return 0;
+}
+
+/* indicate tx activity or inactivity on a WMI stream */
+void ath6kl_indicate_tx_activity(void *devt, u8 traffic_class, bool active)
+{
+ struct ath6kl *ar = devt;
+ enum htc_endpoint_id eid;
+ int i;
+
+ eid = ar->ac2ep_map[traffic_class];
+
+ if (!test_bit(WMI_ENABLED, &ar->flag))
+ goto notify_htc;
+
+ spin_lock_bh(&ar->lock);
+
+ ar->ac_stream_active[traffic_class] = active;
+
+ if (active) {
+ /*
+ * Keep track of the active stream with the highest
+ * priority.
+ */
+ if (ar->ac_stream_pri_map[traffic_class] >
+ ar->hiac_stream_active_pri)
+ /* set the new highest active priority */
+ ar->hiac_stream_active_pri =
+ ar->ac_stream_pri_map[traffic_class];
+
+ } else {
+ /*
+ * We may have to search for the next active stream
+ * that is the highest priority.
+ */
+ if (ar->hiac_stream_active_pri ==
+ ar->ac_stream_pri_map[traffic_class]) {
+ /*
+ * The highest priority stream just went inactive
+ * reset and search for the "next" highest "active"
+ * priority stream.
+ */
+ ar->hiac_stream_active_pri = 0;
+
+ for (i = 0; i < WMM_NUM_AC; i++) {
+ if (ar->ac_stream_active[i] &&
+ (ar->ac_stream_pri_map[i] >
+ ar->hiac_stream_active_pri))
+ /*
+ * Set the new highest active
+ * priority.
+ */
+ ar->hiac_stream_active_pri =
+ ar->ac_stream_pri_map[i];
+ }
+ }
+ }
+
+ spin_unlock_bh(&ar->lock);
+
+notify_htc:
+ /* notify HTC, this may cause credit distribution changes */
+ ath6kl_htc_indicate_activity_change(ar->htc_target, eid, active);
+}
+
+enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
+ struct htc_packet *packet)
+{
+ struct ath6kl *ar = target->dev->ar;
+ enum htc_endpoint_id endpoint = packet->endpoint;
+
+ if (endpoint == ar->ctrl_ep) {
+ /*
+ * Under normal WMI if this is getting full, then something
+ * is running rampant the host should not be exhausting the
+ * WMI queue with too many commands the only exception to
+ * this is during testing using endpointping.
+ */
+ spin_lock_bh(&ar->lock);
+ set_bit(WMI_CTRL_EP_FULL, &ar->flag);
+ spin_unlock_bh(&ar->lock);
+ ath6kl_err("wmi ctrl ep is full\n");
+ return HTC_SEND_FULL_KEEP;
+ }
+
+ if (packet->info.tx.tag == ATH6KL_CONTROL_PKT_TAG)
+ return HTC_SEND_FULL_KEEP;
+
+ if (ar->nw_type == ADHOC_NETWORK)
+ /*
+ * In adhoc mode, we cannot differentiate traffic
+ * priorities so there is no need to continue, however we
+ * should stop the network.
+ */
+ goto stop_net_queues;
+
+ /*
+ * The last MAX_HI_COOKIE_NUM "batch" of cookies are reserved for
+ * the highest active stream.
+ */
+ if (ar->ac_stream_pri_map[ar->ep2ac_map[endpoint]] <
+ ar->hiac_stream_active_pri &&
+ ar->cookie_count <= MAX_HI_COOKIE_NUM)
+ /*
+ * Give preference to the highest priority stream by
+ * dropping the packets which overflowed.
+ */
+ return HTC_SEND_FULL_DROP;
+
+stop_net_queues:
+ spin_lock_bh(&ar->lock);
+ set_bit(NETQ_STOPPED, &ar->flag);
+ spin_unlock_bh(&ar->lock);
+ netif_stop_queue(ar->net_dev);
+
+ return HTC_SEND_FULL_KEEP;
+}
+
+/* TODO this needs to be looked at */
+static void ath6kl_tx_clear_node_map(struct ath6kl *ar,
+ enum htc_endpoint_id eid, u32 map_no)
+{
+ u32 i;
+
+ if (ar->nw_type != ADHOC_NETWORK)
+ return;
+
+ if (!ar->ibss_ps_enable)
+ return;
+
+ if (eid == ar->ctrl_ep)
+ return;
+
+ if (map_no == 0)
+ return;
+
+ map_no--;
+ ar->node_map[map_no].tx_pend--;
+
+ if (ar->node_map[map_no].tx_pend)
+ return;
+
+ if (map_no != (ar->node_num - 1))
+ return;
+
+ for (i = ar->node_num; i > 0; i--) {
+ if (ar->node_map[i - 1].tx_pend)
+ break;
+
+ memset(&ar->node_map[i - 1], 0,
+ sizeof(struct ath6kl_node_mapping));
+ ar->node_num--;
+ }
+}
+
+void ath6kl_tx_complete(void *context, struct list_head *packet_queue)
+{
+ struct ath6kl *ar = context;
+ struct sk_buff_head skb_queue;
+ struct htc_packet *packet;
+ struct sk_buff *skb;
+ struct ath6kl_cookie *ath6kl_cookie;
+ u32 map_no = 0;
+ int status;
+ enum htc_endpoint_id eid;
+ bool wake_event = false;
+ bool flushing = false;
+
+ skb_queue_head_init(&skb_queue);
+
+ /* lock the driver as we update internal state */
+ spin_lock_bh(&ar->lock);
+
+ /* reap completed packets */
+ while (!list_empty(packet_queue)) {
+
+ packet = list_first_entry(packet_queue, struct htc_packet,
+ list);
+ list_del(&packet->list);
+
+ ath6kl_cookie = (struct ath6kl_cookie *)packet->pkt_cntxt;
+ if (!ath6kl_cookie)
+ goto fatal;
+
+ status = packet->status;
+ skb = ath6kl_cookie->skb;
+ eid = packet->endpoint;
+ map_no = ath6kl_cookie->map_no;
+
+ if (!skb || !skb->data)
+ goto fatal;
+
+ packet->buf = skb->data;
+
+ __skb_queue_tail(&skb_queue, skb);
+
+ if (!status && (packet->act_len != skb->len))
+ goto fatal;
+
+ ar->tx_pending[eid]--;
+
+ if (eid != ar->ctrl_ep)
+ ar->total_tx_data_pend--;
+
+ if (eid == ar->ctrl_ep) {
+ if (test_bit(WMI_CTRL_EP_FULL, &ar->flag))
+ clear_bit(WMI_CTRL_EP_FULL, &ar->flag);
+
+ if (ar->tx_pending[eid] == 0)
+ wake_event = true;
+ }
+
+ if (status) {
+ if (status == -ECANCELED)
+ /* a packet was flushed */
+ flushing = true;
+
+ ar->net_stats.tx_errors++;
+
+ if (status != -ENOSPC)
+ ath6kl_err("tx error, status: 0x%x\n", status);
+ ath6kl_dbg(ATH6KL_DBG_WLAN_TX,
+ "%s: skb=0x%p data=0x%p len=0x%x eid=%d %s\n",
+ __func__, skb, packet->buf, packet->act_len,
+ eid, "error!");
+ } else {
+ ath6kl_dbg(ATH6KL_DBG_WLAN_TX,
+ "%s: skb=0x%p data=0x%p len=0x%x eid=%d %s\n",
+ __func__, skb, packet->buf, packet->act_len,
+ eid, "OK");
+
+ flushing = false;
+ ar->net_stats.tx_packets++;
+ ar->net_stats.tx_bytes += skb->len;
+ }
+
+ ath6kl_tx_clear_node_map(ar, eid, map_no);
+
+ ath6kl_free_cookie(ar, ath6kl_cookie);
+
+ if (test_bit(NETQ_STOPPED, &ar->flag))
+ clear_bit(NETQ_STOPPED, &ar->flag);
+ }
+
+ spin_unlock_bh(&ar->lock);
+
+ __skb_queue_purge(&skb_queue);
+
+ if (test_bit(CONNECTED, &ar->flag)) {
+ if (!flushing)
+ netif_wake_queue(ar->net_dev);
+ }
+
+ if (wake_event)
+ wake_up(&ar->event_wq);
+
+ return;
+
+fatal:
+ WARN_ON(1);
+ spin_unlock_bh(&ar->lock);
+ return;
+}
+
+void ath6kl_tx_data_cleanup(struct ath6kl *ar)
+{
+ int i;
+
+ /* flush all the data (non-control) streams */
+ for (i = 0; i < WMM_NUM_AC; i++)
+ ath6kl_htc_flush_txep(ar->htc_target, ar->ac2ep_map[i],
+ ATH6KL_DATA_PKT_TAG);
+}
+
+/* Rx functions */
+
+static void ath6kl_deliver_frames_to_nw_stack(struct net_device *dev,
+ struct sk_buff *skb)
+{
+ if (!skb)
+ return;
+
+ skb->dev = dev;
+
+ if (!(skb->dev->flags & IFF_UP)) {
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ skb->protocol = eth_type_trans(skb, skb->dev);
+
+ netif_rx_ni(skb);
+}
+
+static void ath6kl_alloc_netbufs(struct sk_buff_head *q, u16 num)
+{
+ struct sk_buff *skb;
+
+ while (num) {
+ skb = ath6kl_buf_alloc(ATH6KL_BUFFER_SIZE);
+ if (!skb) {
+ ath6kl_err("netbuf allocation failed\n");
+ return;
+ }
+ skb_queue_tail(q, skb);
+ num--;
+ }
+}
+
+static struct sk_buff *aggr_get_free_skb(struct aggr_info *p_aggr)
+{
+ struct sk_buff *skb = NULL;
+
+ if (skb_queue_len(&p_aggr->free_q) < (AGGR_NUM_OF_FREE_NETBUFS >> 2))
+ ath6kl_alloc_netbufs(&p_aggr->free_q, AGGR_NUM_OF_FREE_NETBUFS);
+
+ skb = skb_dequeue(&p_aggr->free_q);
+
+ return skb;
+}
+
+void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint)
+{
+ struct ath6kl *ar = target->dev->ar;
+ struct sk_buff *skb;
+ int rx_buf;
+ int n_buf_refill;
+ struct htc_packet *packet;
+ struct list_head queue;
+
+ n_buf_refill = ATH6KL_MAX_RX_BUFFERS -
+ ath6kl_htc_get_rxbuf_num(ar->htc_target, endpoint);
+
+ if (n_buf_refill <= 0)
+ return;
+
+ INIT_LIST_HEAD(&queue);
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_RX,
+ "%s: providing htc with %d buffers at eid=%d\n",
+ __func__, n_buf_refill, endpoint);
+
+ for (rx_buf = 0; rx_buf < n_buf_refill; rx_buf++) {
+ skb = ath6kl_buf_alloc(ATH6KL_BUFFER_SIZE);
+ if (!skb)
+ break;
+
+ packet = (struct htc_packet *) skb->head;
+ if (!IS_ALIGNED((unsigned long) skb->data, 4))
+ skb->data = PTR_ALIGN(skb->data - 4, 4);
+ set_htc_rxpkt_info(packet, skb, skb->data,
+ ATH6KL_BUFFER_SIZE, endpoint);
+ list_add_tail(&packet->list, &queue);
+ }
+
+ if (!list_empty(&queue))
+ ath6kl_htc_add_rxbuf_multiple(ar->htc_target, &queue);
+}
+
+void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count)
+{
+ struct htc_packet *packet;
+ struct sk_buff *skb;
+
+ while (count) {
+ skb = ath6kl_buf_alloc(ATH6KL_AMSDU_BUFFER_SIZE);
+ if (!skb)
+ return;
+
+ packet = (struct htc_packet *) skb->head;
+ if (!IS_ALIGNED((unsigned long) skb->data, 4))
+ skb->data = PTR_ALIGN(skb->data - 4, 4);
+ set_htc_rxpkt_info(packet, skb, skb->data,
+ ATH6KL_AMSDU_BUFFER_SIZE, 0);
+ spin_lock_bh(&ar->lock);
+ list_add_tail(&packet->list, &ar->amsdu_rx_buffer_queue);
+ spin_unlock_bh(&ar->lock);
+ count--;
+ }
+}
+
+/*
+ * Callback to allocate a receive buffer for a pending packet. We use a
+ * pre-allocated list of buffers of maximum AMSDU size (4K).
+ */
+struct htc_packet *ath6kl_alloc_amsdu_rxbuf(struct htc_target *target,
+ enum htc_endpoint_id endpoint,
+ int len)
+{
+ struct ath6kl *ar = target->dev->ar;
+ struct htc_packet *packet = NULL;
+ struct list_head *pkt_pos;
+ int refill_cnt = 0, depth = 0;
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: eid=%d, len:%d\n",
+ __func__, endpoint, len);
+
+ if ((len <= ATH6KL_BUFFER_SIZE) ||
+ (len > ATH6KL_AMSDU_BUFFER_SIZE))
+ return NULL;
+
+ spin_lock_bh(&ar->lock);
+
+ if (list_empty(&ar->amsdu_rx_buffer_queue)) {
+ spin_unlock_bh(&ar->lock);
+ refill_cnt = ATH6KL_MAX_AMSDU_RX_BUFFERS;
+ goto refill_buf;
+ }
+
+ packet = list_first_entry(&ar->amsdu_rx_buffer_queue,
+ struct htc_packet, list);
+ list_del(&packet->list);
+ list_for_each(pkt_pos, &ar->amsdu_rx_buffer_queue)
+ depth++;
+
+ refill_cnt = ATH6KL_MAX_AMSDU_RX_BUFFERS - depth;
+ spin_unlock_bh(&ar->lock);
+
+ /* set actual endpoint ID */
+ packet->endpoint = endpoint;
+
+refill_buf:
+ if (refill_cnt >= ATH6KL_AMSDU_REFILL_THRESHOLD)
+ ath6kl_refill_amsdu_rxbufs(ar, refill_cnt);
+
+ return packet;
+}
+
+static void aggr_slice_amsdu(struct aggr_info *p_aggr,
+ struct rxtid *rxtid, struct sk_buff *skb)
+{
+ struct sk_buff *new_skb;
+ struct ethhdr *hdr;
+ u16 frame_8023_len, payload_8023_len, mac_hdr_len, amsdu_len;
+ u8 *framep;
+
+ mac_hdr_len = sizeof(struct ethhdr);
+ framep = skb->data + mac_hdr_len;
+ amsdu_len = skb->len - mac_hdr_len;
+
+ while (amsdu_len > mac_hdr_len) {
+ hdr = (struct ethhdr *) framep;
+ payload_8023_len = ntohs(hdr->h_proto);
+
+ if (payload_8023_len < MIN_MSDU_SUBFRAME_PAYLOAD_LEN ||
+ payload_8023_len > MAX_MSDU_SUBFRAME_PAYLOAD_LEN) {
+ ath6kl_err("802.3 AMSDU frame bound check failed. len %d\n",
+ payload_8023_len);
+ break;
+ }
+
+ frame_8023_len = payload_8023_len + mac_hdr_len;
+ new_skb = aggr_get_free_skb(p_aggr);
+ if (!new_skb) {
+ ath6kl_err("no buffer available\n");
+ break;
+ }
+
+ memcpy(new_skb->data, framep, frame_8023_len);
+ skb_put(new_skb, frame_8023_len);
+ if (ath6kl_wmi_dot3_2_dix(new_skb)) {
+ ath6kl_err("dot3_2_dix error\n");
+ dev_kfree_skb(new_skb);
+ break;
+ }
+
+ skb_queue_tail(&rxtid->q, new_skb);
+
+ /* Is this the last subframe within this aggregate ? */
+ if ((amsdu_len - frame_8023_len) == 0)
+ break;
+
+ /* Add the length of A-MSDU subframe padding bytes -
+ * Round to nearest word.
+ */
+ frame_8023_len = ALIGN(frame_8023_len, 4);
+
+ framep += frame_8023_len;
+ amsdu_len -= frame_8023_len;
+ }
+
+ dev_kfree_skb(skb);
+}
+
+static void aggr_deque_frms(struct aggr_info *p_aggr, u8 tid,
+ u16 seq_no, u8 order)
+{
+ struct sk_buff *skb;
+ struct rxtid *rxtid;
+ struct skb_hold_q *node;
+ u16 idx, idx_end, seq_end;
+ struct rxtid_stats *stats;
+
+ if (!p_aggr)
+ return;
+
+ rxtid = &p_aggr->rx_tid[tid];
+ stats = &p_aggr->stat[tid];
+
+ idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz);
+
+ /*
+ * idx_end is typically the last possible frame in the window,
+ * but changes to 'the' seq_no, when BAR comes. If seq_no
+ * is non-zero, we will go up to that and stop.
+ * Note: last seq no in current window will occupy the same
+ * index position as index that is just previous to start.
+ * An imp point : if win_sz is 7, for seq_no space of 4095,
+ * then, there would be holes when sequence wrap around occurs.
+ * Target should judiciously choose the win_sz, based on
+ * this condition. For 4095, (TID_WINDOW_SZ = 2 x win_sz
+ * 2, 4, 8, 16 win_sz works fine).
+ * We must deque from "idx" to "idx_end", including both.
+ */
+ seq_end = seq_no ? seq_no : rxtid->seq_next;
+ idx_end = AGGR_WIN_IDX(seq_end, rxtid->hold_q_sz);
+
+ spin_lock_bh(&rxtid->lock);
+
+ do {
+ node = &rxtid->hold_q[idx];
+ if ((order == 1) && (!node->skb))
+ break;
+
+ if (node->skb) {
+ if (node->is_amsdu)
+ aggr_slice_amsdu(p_aggr, rxtid, node->skb);
+ else
+ skb_queue_tail(&rxtid->q, node->skb);
+ node->skb = NULL;
+ } else
+ stats->num_hole++;
+
+ rxtid->seq_next = ATH6KL_NEXT_SEQ_NO(rxtid->seq_next);
+ idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz);
+ } while (idx != idx_end);
+
+ spin_unlock_bh(&rxtid->lock);
+
+ stats->num_delivered += skb_queue_len(&rxtid->q);
+
+ while ((skb = skb_dequeue(&rxtid->q)))
+ ath6kl_deliver_frames_to_nw_stack(p_aggr->dev, skb);
+}
+
+static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid,
+ u16 seq_no,
+ bool is_amsdu, struct sk_buff *frame)
+{
+ struct rxtid *rxtid;
+ struct rxtid_stats *stats;
+ struct sk_buff *skb;
+ struct skb_hold_q *node;
+ u16 idx, st, cur, end;
+ bool is_queued = false;
+ u16 extended_end;
+
+ rxtid = &agg_info->rx_tid[tid];
+ stats = &agg_info->stat[tid];
+
+ stats->num_into_aggr++;
+
+ if (!rxtid->aggr) {
+ if (is_amsdu) {
+ aggr_slice_amsdu(agg_info, rxtid, frame);
+ is_queued = true;
+ stats->num_amsdu++;
+ while ((skb = skb_dequeue(&rxtid->q)))
+ ath6kl_deliver_frames_to_nw_stack(agg_info->dev,
+ skb);
+ }
+ return is_queued;
+ }
+
+ /* Check the incoming sequence no, if it's in the window */
+ st = rxtid->seq_next;
+ cur = seq_no;
+ end = (st + rxtid->hold_q_sz-1) & ATH6KL_MAX_SEQ_NO;
+
+ if (((st < end) && (cur < st || cur > end)) ||
+ ((st > end) && (cur > end) && (cur < st))) {
+ extended_end = (end + rxtid->hold_q_sz - 1) &
+ ATH6KL_MAX_SEQ_NO;
+
+ if (((end < extended_end) &&
+ (cur < end || cur > extended_end)) ||
+ ((end > extended_end) && (cur > extended_end) &&
+ (cur < end))) {
+ aggr_deque_frms(agg_info, tid, 0, 0);
+ if (cur >= rxtid->hold_q_sz - 1)
+ rxtid->seq_next = cur - (rxtid->hold_q_sz - 1);
+ else
+ rxtid->seq_next = ATH6KL_MAX_SEQ_NO -
+ (rxtid->hold_q_sz - 2 - cur);
+ } else {
+ /*
+ * Dequeue only those frames that are outside the
+ * new shifted window.
+ */
+ if (cur >= rxtid->hold_q_sz - 1)
+ st = cur - (rxtid->hold_q_sz - 1);
+ else
+ st = ATH6KL_MAX_SEQ_NO -
+ (rxtid->hold_q_sz - 2 - cur);
+
+ aggr_deque_frms(agg_info, tid, st, 0);
+ }
+
+ stats->num_oow++;
+ }
+
+ idx = AGGR_WIN_IDX(seq_no, rxtid->hold_q_sz);
+
+ node = &rxtid->hold_q[idx];
+
+ spin_lock_bh(&rxtid->lock);
+
+ /*
+ * Is the cur frame duplicate or something beyond our window(hold_q
+ * -> which is 2x, already)?
+ *
+ * 1. Duplicate is easy - drop incoming frame.
+ * 2. Not falling in current sliding window.
+ * 2a. is the frame_seq_no preceding current tid_seq_no?
+ * -> drop the frame. perhaps sender did not get our ACK.
+ * this is taken care of above.
+ * 2b. is the frame_seq_no beyond window(st, TID_WINDOW_SZ);
+ * -> Taken care of it above, by moving window forward.
+ */
+ dev_kfree_skb(node->skb);
+ stats->num_dups++;
+
+ node->skb = frame;
+ is_queued = true;
+ node->is_amsdu = is_amsdu;
+ node->seq_no = seq_no;
+
+ if (node->is_amsdu)
+ stats->num_amsdu++;
+ else
+ stats->num_mpdu++;
+
+ spin_unlock_bh(&rxtid->lock);
+
+ aggr_deque_frms(agg_info, tid, 0, 1);
+
+ if (agg_info->timer_scheduled)
+ rxtid->progress = true;
+ else
+ for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) {
+ if (rxtid->hold_q[idx].skb) {
+ /*
+ * There is a frame in the queue and no
+ * timer so start a timer to ensure that
+ * the frame doesn't remain stuck
+ * forever.
+ */
+ agg_info->timer_scheduled = true;
+ mod_timer(&agg_info->timer,
+ (jiffies +
+ HZ * (AGGR_RX_TIMEOUT) / 1000));
+ rxtid->progress = false;
+ rxtid->timer_mon = true;
+ break;
+ }
+ }
+
+ return is_queued;
+}
+
+void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
+{
+ struct ath6kl *ar = target->dev->ar;
+ struct sk_buff *skb = packet->pkt_cntxt;
+ struct wmi_rx_meta_v2 *meta;
+ struct wmi_data_hdr *dhdr;
+ int min_hdr_len;
+ u8 meta_type, dot11_hdr = 0;
+ int status = packet->status;
+ enum htc_endpoint_id ept = packet->endpoint;
+ bool is_amsdu, prev_ps, ps_state = false;
+ struct ath6kl_sta *conn = NULL;
+ struct sk_buff *skb1 = NULL;
+ struct ethhdr *datap = NULL;
+ u16 seq_no, offset;
+ u8 tid;
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_RX,
+ "%s: ar=0x%p eid=%d, skb=0x%p, data=0x%p, len=0x%x status:%d",
+ __func__, ar, ept, skb, packet->buf,
+ packet->act_len, status);
+
+ if (status || !(skb->data + HTC_HDR_LENGTH)) {
+ ar->net_stats.rx_errors++;
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ /*
+ * Take lock to protect buffer counts and adaptive power throughput
+ * state.
+ */
+ spin_lock_bh(&ar->lock);
+
+ ar->net_stats.rx_packets++;
+ ar->net_stats.rx_bytes += packet->act_len;
+
+ spin_unlock_bh(&ar->lock);
+
+ skb_put(skb, packet->act_len + HTC_HDR_LENGTH);
+ skb_pull(skb, HTC_HDR_LENGTH);
+
+ ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "rx ",
+ skb->data, skb->len);
+
+ skb->dev = ar->net_dev;
+
+ if (!test_bit(WMI_ENABLED, &ar->flag)) {
+ if (EPPING_ALIGNMENT_PAD > 0)
+ skb_pull(skb, EPPING_ALIGNMENT_PAD);
+ ath6kl_deliver_frames_to_nw_stack(ar->net_dev, skb);
+ return;
+ }
+
+ if (ept == ar->ctrl_ep) {
+ ath6kl_wmi_control_rx(ar->wmi, skb);
+ return;
+ }
+
+ min_hdr_len = sizeof(struct ethhdr) + sizeof(struct wmi_data_hdr) +
+ sizeof(struct ath6kl_llc_snap_hdr);
+
+ dhdr = (struct wmi_data_hdr *) skb->data;
+
+ /*
+ * In the case of AP mode we may receive NULL data frames
+ * that do not have LLC hdr. They are 16 bytes in size.
+ * Allow these frames in the AP mode.
+ */
+ if (ar->nw_type != AP_NETWORK &&
+ ((packet->act_len < min_hdr_len) ||
+ (packet->act_len > WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH))) {
+ ath6kl_info("frame len is too short or too long\n");
+ ar->net_stats.rx_errors++;
+ ar->net_stats.rx_length_errors++;
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ /* Get the Power save state of the STA */
+ if (ar->nw_type == AP_NETWORK) {
+ meta_type = wmi_data_hdr_get_meta(dhdr);
+
+ ps_state = !!((dhdr->info >> WMI_DATA_HDR_PS_SHIFT) &
+ WMI_DATA_HDR_PS_MASK);
+
+ offset = sizeof(struct wmi_data_hdr);
+
+ switch (meta_type) {
+ case 0:
+ break;
+ case WMI_META_VERSION_1:
+ offset += sizeof(struct wmi_rx_meta_v1);
+ break;
+ case WMI_META_VERSION_2:
+ offset += sizeof(struct wmi_rx_meta_v2);
+ break;
+ default:
+ break;
+ }
+
+ datap = (struct ethhdr *) (skb->data + offset);
+ conn = ath6kl_find_sta(ar, datap->h_source);
+
+ if (!conn) {
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ /*
+ * If there is a change in PS state of the STA,
+ * take appropriate steps:
+ *
+ * 1. If Sleep-->Awake, flush the psq for the STA
+ * Clear the PVB for the STA.
+ * 2. If Awake-->Sleep, Starting queueing frames
+ * the STA.
+ */
+ prev_ps = !!(conn->sta_flags & STA_PS_SLEEP);
+
+ if (ps_state)
+ conn->sta_flags |= STA_PS_SLEEP;
+ else
+ conn->sta_flags &= ~STA_PS_SLEEP;
+
+ if (prev_ps ^ !!(conn->sta_flags & STA_PS_SLEEP)) {
+ if (!(conn->sta_flags & STA_PS_SLEEP)) {
+ struct sk_buff *skbuff = NULL;
+
+ spin_lock_bh(&conn->psq_lock);
+ while ((skbuff = skb_dequeue(&conn->psq))
+ != NULL) {
+ spin_unlock_bh(&conn->psq_lock);
+ ath6kl_data_tx(skbuff, ar->net_dev);
+ spin_lock_bh(&conn->psq_lock);
+ }
+ spin_unlock_bh(&conn->psq_lock);
+ /* Clear the PVB for this STA */
+ ath6kl_wmi_set_pvb_cmd(ar->wmi, conn->aid, 0);
+ }
+ }
+
+ /* drop NULL data frames here */
+ if ((packet->act_len < min_hdr_len) ||
+ (packet->act_len >
+ WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH)) {
+ dev_kfree_skb(skb);
+ return;
+ }
+ }
+
+ is_amsdu = wmi_data_hdr_is_amsdu(dhdr) ? true : false;
+ tid = wmi_data_hdr_get_up(dhdr);
+ seq_no = wmi_data_hdr_get_seqno(dhdr);
+ meta_type = wmi_data_hdr_get_meta(dhdr);
+ dot11_hdr = wmi_data_hdr_get_dot11(dhdr);
+ skb_pull(skb, sizeof(struct wmi_data_hdr));
+
+ switch (meta_type) {
+ case WMI_META_VERSION_1:
+ skb_pull(skb, sizeof(struct wmi_rx_meta_v1));
+ break;
+ case WMI_META_VERSION_2:
+ meta = (struct wmi_rx_meta_v2 *) skb->data;
+ if (meta->csum_flags & 0x1) {
+ skb->ip_summed = CHECKSUM_COMPLETE;
+ skb->csum = (__force __wsum) meta->csum;
+ }
+ skb_pull(skb, sizeof(struct wmi_rx_meta_v2));
+ break;
+ default:
+ break;
+ }
+
+ if (dot11_hdr)
+ status = ath6kl_wmi_dot11_hdr_remove(ar->wmi, skb);
+ else if (!is_amsdu)
+ status = ath6kl_wmi_dot3_2_dix(skb);
+
+ if (status) {
+ /*
+ * Drop frames that could not be processed (lack of
+ * memory, etc.)
+ */
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ if (!(ar->net_dev->flags & IFF_UP)) {
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ if (ar->nw_type == AP_NETWORK) {
+ datap = (struct ethhdr *) skb->data;
+ if (is_multicast_ether_addr(datap->h_dest))
+ /*
+ * Bcast/Mcast frames should be sent to the
+ * OS stack as well as on the air.
+ */
+ skb1 = skb_copy(skb, GFP_ATOMIC);
+ else {
+ /*
+ * Search for a connected STA with dstMac
+ * as the Mac address. If found send the
+ * frame to it on the air else send the
+ * frame up the stack.
+ */
+ struct ath6kl_sta *conn = NULL;
+ conn = ath6kl_find_sta(ar, datap->h_dest);
+
+ if (conn && ar->intra_bss) {
+ skb1 = skb;
+ skb = NULL;
+ } else if (conn && !ar->intra_bss) {
+ dev_kfree_skb(skb);
+ skb = NULL;
+ }
+ }
+ if (skb1)
+ ath6kl_data_tx(skb1, ar->net_dev);
+ }
+
+ datap = (struct ethhdr *) skb->data;
+
+ if (is_unicast_ether_addr(datap->h_dest) &&
+ aggr_process_recv_frm(ar->aggr_cntxt, tid, seq_no,
+ is_amsdu, skb))
+ /* aggregation code will handle the skb */
+ return;
+
+ ath6kl_deliver_frames_to_nw_stack(ar->net_dev, skb);
+}
+
+static void aggr_timeout(unsigned long arg)
+{
+ u8 i, j;
+ struct aggr_info *p_aggr = (struct aggr_info *) arg;
+ struct rxtid *rxtid;
+ struct rxtid_stats *stats;
+
+ for (i = 0; i < NUM_OF_TIDS; i++) {
+ rxtid = &p_aggr->rx_tid[i];
+ stats = &p_aggr->stat[i];
+
+ if (!rxtid->aggr || !rxtid->timer_mon || rxtid->progress)
+ continue;
+
+ stats->num_timeouts++;
+ ath6kl_dbg(ATH6KL_DBG_AGGR,
+ "aggr timeout (st %d end %d)\n",
+ rxtid->seq_next,
+ ((rxtid->seq_next + rxtid->hold_q_sz-1) &
+ ATH6KL_MAX_SEQ_NO));
+ aggr_deque_frms(p_aggr, i, 0, 0);
+ }
+
+ p_aggr->timer_scheduled = false;
+
+ for (i = 0; i < NUM_OF_TIDS; i++) {
+ rxtid = &p_aggr->rx_tid[i];
+
+ if (rxtid->aggr && rxtid->hold_q) {
+ for (j = 0; j < rxtid->hold_q_sz; j++) {
+ if (rxtid->hold_q[j].skb) {
+ p_aggr->timer_scheduled = true;
+ rxtid->timer_mon = true;
+ rxtid->progress = false;
+ break;
+ }
+ }
+
+ if (j >= rxtid->hold_q_sz)
+ rxtid->timer_mon = false;
+ }
+ }
+
+ if (p_aggr->timer_scheduled)
+ mod_timer(&p_aggr->timer,
+ jiffies + msecs_to_jiffies(AGGR_RX_TIMEOUT));
+}
+
+static void aggr_delete_tid_state(struct aggr_info *p_aggr, u8 tid)
+{
+ struct rxtid *rxtid;
+ struct rxtid_stats *stats;
+
+ if (!p_aggr || tid >= NUM_OF_TIDS)
+ return;
+
+ rxtid = &p_aggr->rx_tid[tid];
+ stats = &p_aggr->stat[tid];
+
+ if (rxtid->aggr)
+ aggr_deque_frms(p_aggr, tid, 0, 0);
+
+ rxtid->aggr = false;
+ rxtid->progress = false;
+ rxtid->timer_mon = false;
+ rxtid->win_sz = 0;
+ rxtid->seq_next = 0;
+ rxtid->hold_q_sz = 0;
+
+ kfree(rxtid->hold_q);
+ rxtid->hold_q = NULL;
+
+ memset(stats, 0, sizeof(struct rxtid_stats));
+}
+
+void aggr_recv_addba_req_evt(struct ath6kl *ar, u8 tid, u16 seq_no, u8 win_sz)
+{
+ struct aggr_info *p_aggr = ar->aggr_cntxt;
+ struct rxtid *rxtid;
+ struct rxtid_stats *stats;
+ u16 hold_q_size;
+
+ if (!p_aggr)
+ return;
+
+ rxtid = &p_aggr->rx_tid[tid];
+ stats = &p_aggr->stat[tid];
+
+ if (win_sz < AGGR_WIN_SZ_MIN || win_sz > AGGR_WIN_SZ_MAX)
+ ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: win_sz %d, tid %d\n",
+ __func__, win_sz, tid);
+
+ if (rxtid->aggr)
+ aggr_delete_tid_state(p_aggr, tid);
+
+ rxtid->seq_next = seq_no;
+ hold_q_size = TID_WINDOW_SZ(win_sz) * sizeof(struct skb_hold_q);
+ rxtid->hold_q = kzalloc(hold_q_size, GFP_KERNEL);
+ if (!rxtid->hold_q)
+ return;
+
+ rxtid->win_sz = win_sz;
+ rxtid->hold_q_sz = TID_WINDOW_SZ(win_sz);
+ if (!skb_queue_empty(&rxtid->q))
+ return;
+
+ rxtid->aggr = true;
+}
+
+struct aggr_info *aggr_init(struct net_device *dev)
+{
+ struct aggr_info *p_aggr = NULL;
+ struct rxtid *rxtid;
+ u8 i;
+
+ p_aggr = kzalloc(sizeof(struct aggr_info), GFP_KERNEL);
+ if (!p_aggr) {
+ ath6kl_err("failed to alloc memory for aggr_node\n");
+ return NULL;
+ }
+
+ p_aggr->aggr_sz = AGGR_SZ_DEFAULT;
+ p_aggr->dev = dev;
+ init_timer(&p_aggr->timer);
+ p_aggr->timer.function = aggr_timeout;
+ p_aggr->timer.data = (unsigned long) p_aggr;
+
+ p_aggr->timer_scheduled = false;
+ skb_queue_head_init(&p_aggr->free_q);
+
+ ath6kl_alloc_netbufs(&p_aggr->free_q, AGGR_NUM_OF_FREE_NETBUFS);
+
+ for (i = 0; i < NUM_OF_TIDS; i++) {
+ rxtid = &p_aggr->rx_tid[i];
+ rxtid->aggr = false;
+ rxtid->progress = false;
+ rxtid->timer_mon = false;
+ skb_queue_head_init(&rxtid->q);
+ spin_lock_init(&rxtid->lock);
+ }
+
+ return p_aggr;
+}
+
+void aggr_recv_delba_req_evt(struct ath6kl *ar, u8 tid)
+{
+ struct aggr_info *p_aggr = ar->aggr_cntxt;
+ struct rxtid *rxtid;
+
+ if (!p_aggr)
+ return;
+
+ rxtid = &p_aggr->rx_tid[tid];
+
+ if (rxtid->aggr)
+ aggr_delete_tid_state(p_aggr, tid);
+}
+
+void aggr_reset_state(struct aggr_info *aggr_info)
+{
+ u8 tid;
+
+ for (tid = 0; tid < NUM_OF_TIDS; tid++)
+ aggr_delete_tid_state(aggr_info, tid);
+}
+
+/* clean up our amsdu buffer list */
+void ath6kl_cleanup_amsdu_rxbufs(struct ath6kl *ar)
+{
+ struct htc_packet *packet, *tmp_pkt;
+
+ spin_lock_bh(&ar->lock);
+ if (list_empty(&ar->amsdu_rx_buffer_queue)) {
+ spin_unlock_bh(&ar->lock);
+ return;
+ }
+
+ list_for_each_entry_safe(packet, tmp_pkt, &ar->amsdu_rx_buffer_queue,
+ list) {
+ list_del(&packet->list);
+ spin_unlock_bh(&ar->lock);
+ dev_kfree_skb(packet->pkt_cntxt);
+ spin_lock_bh(&ar->lock);
+ }
+
+ spin_unlock_bh(&ar->lock);
+}
+
+void aggr_module_destroy(struct aggr_info *aggr_info)
+{
+ struct rxtid *rxtid;
+ u8 i, k;
+
+ if (!aggr_info)
+ return;
+
+ if (aggr_info->timer_scheduled) {
+ del_timer(&aggr_info->timer);
+ aggr_info->timer_scheduled = false;
+ }
+
+ for (i = 0; i < NUM_OF_TIDS; i++) {
+ rxtid = &aggr_info->rx_tid[i];
+ if (rxtid->hold_q) {
+ for (k = 0; k < rxtid->hold_q_sz; k++)
+ dev_kfree_skb(rxtid->hold_q[k].skb);
+ kfree(rxtid->hold_q);
+ }
+
+ skb_queue_purge(&rxtid->q);
+ }
+
+ skb_queue_purge(&aggr_info->free_q);
+ kfree(aggr_info);
+}
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
new file mode 100644
index 000000000000..a7de23cbd2c7
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -0,0 +1,3127 @@
+/*
+ * Copyright (c) 2004-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/ip.h>
+#include "core.h"
+#include "debug.h"
+#include "testmode.h"
+#include "../regd.h"
+#include "../regd_common.h"
+
+static int ath6kl_wmi_sync_point(struct wmi *wmi);
+
+static const s32 wmi_rate_tbl[][2] = {
+ /* {W/O SGI, with SGI} */
+ {1000, 1000},
+ {2000, 2000},
+ {5500, 5500},
+ {11000, 11000},
+ {6000, 6000},
+ {9000, 9000},
+ {12000, 12000},
+ {18000, 18000},
+ {24000, 24000},
+ {36000, 36000},
+ {48000, 48000},
+ {54000, 54000},
+ {6500, 7200},
+ {13000, 14400},
+ {19500, 21700},
+ {26000, 28900},
+ {39000, 43300},
+ {52000, 57800},
+ {58500, 65000},
+ {65000, 72200},
+ {13500, 15000},
+ {27000, 30000},
+ {40500, 45000},
+ {54000, 60000},
+ {81000, 90000},
+ {108000, 120000},
+ {121500, 135000},
+ {135000, 150000},
+ {0, 0}
+};
+
+/* 802.1d to AC mapping. Refer pg 57 of WMM-test-plan-v1.2 */
+static const u8 up_to_ac[] = {
+ WMM_AC_BE,
+ WMM_AC_BK,
+ WMM_AC_BK,
+ WMM_AC_BE,
+ WMM_AC_VI,
+ WMM_AC_VI,
+ WMM_AC_VO,
+ WMM_AC_VO,
+};
+
+void ath6kl_wmi_set_control_ep(struct wmi *wmi, enum htc_endpoint_id ep_id)
+{
+ if (WARN_ON(ep_id == ENDPOINT_UNUSED || ep_id >= ENDPOINT_MAX))
+ return;
+
+ wmi->ep_id = ep_id;
+}
+
+enum htc_endpoint_id ath6kl_wmi_get_control_ep(struct wmi *wmi)
+{
+ return wmi->ep_id;
+}
+
+/* Performs DIX to 802.3 encapsulation for transmit packets.
+ * Assumes the entire DIX header is contigous and that there is
+ * enough room in the buffer for a 802.3 mac header and LLC+SNAP headers.
+ */
+int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb)
+{
+ struct ath6kl_llc_snap_hdr *llc_hdr;
+ struct ethhdr *eth_hdr;
+ size_t new_len;
+ __be16 type;
+ u8 *datap;
+ u16 size;
+
+ if (WARN_ON(skb == NULL))
+ return -EINVAL;
+
+ size = sizeof(struct ath6kl_llc_snap_hdr) + sizeof(struct wmi_data_hdr);
+ if (skb_headroom(skb) < size)
+ return -ENOMEM;
+
+ eth_hdr = (struct ethhdr *) skb->data;
+ type = eth_hdr->h_proto;
+
+ if (!is_ethertype(be16_to_cpu(type))) {
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "%s: pkt is already in 802.3 format\n", __func__);
+ return 0;
+ }
+
+ new_len = skb->len - sizeof(*eth_hdr) + sizeof(*llc_hdr);
+
+ skb_push(skb, sizeof(struct ath6kl_llc_snap_hdr));
+ datap = skb->data;
+
+ eth_hdr->h_proto = cpu_to_be16(new_len);
+
+ memcpy(datap, eth_hdr, sizeof(*eth_hdr));
+
+ llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap + sizeof(*eth_hdr));
+ llc_hdr->dsap = 0xAA;
+ llc_hdr->ssap = 0xAA;
+ llc_hdr->cntl = 0x03;
+ llc_hdr->org_code[0] = 0x0;
+ llc_hdr->org_code[1] = 0x0;
+ llc_hdr->org_code[2] = 0x0;
+ llc_hdr->eth_type = type;
+
+ return 0;
+}
+
+static int ath6kl_wmi_meta_add(struct wmi *wmi, struct sk_buff *skb,
+ u8 *version, void *tx_meta_info)
+{
+ struct wmi_tx_meta_v1 *v1;
+ struct wmi_tx_meta_v2 *v2;
+
+ if (WARN_ON(skb == NULL || version == NULL))
+ return -EINVAL;
+
+ switch (*version) {
+ case WMI_META_VERSION_1:
+ skb_push(skb, WMI_MAX_TX_META_SZ);
+ v1 = (struct wmi_tx_meta_v1 *) skb->data;
+ v1->pkt_id = 0;
+ v1->rate_plcy_id = 0;
+ *version = WMI_META_VERSION_1;
+ break;
+ case WMI_META_VERSION_2:
+ skb_push(skb, WMI_MAX_TX_META_SZ);
+ v2 = (struct wmi_tx_meta_v2 *) skb->data;
+ memcpy(v2, (struct wmi_tx_meta_v2 *) tx_meta_info,
+ sizeof(struct wmi_tx_meta_v2));
+ break;
+ }
+
+ return 0;
+}
+
+int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,
+ u8 msg_type, bool more_data,
+ enum wmi_data_hdr_data_type data_type,
+ u8 meta_ver, void *tx_meta_info)
+{
+ struct wmi_data_hdr *data_hdr;
+ int ret;
+
+ if (WARN_ON(skb == NULL))
+ return -EINVAL;
+
+ if (tx_meta_info) {
+ ret = ath6kl_wmi_meta_add(wmi, skb, &meta_ver, tx_meta_info);
+ if (ret)
+ return ret;
+ }
+
+ skb_push(skb, sizeof(struct wmi_data_hdr));
+
+ data_hdr = (struct wmi_data_hdr *)skb->data;
+ memset(data_hdr, 0, sizeof(struct wmi_data_hdr));
+
+ data_hdr->info = msg_type << WMI_DATA_HDR_MSG_TYPE_SHIFT;
+ data_hdr->info |= data_type << WMI_DATA_HDR_DATA_TYPE_SHIFT;
+
+ if (more_data)
+ data_hdr->info |=
+ WMI_DATA_HDR_MORE_MASK << WMI_DATA_HDR_MORE_SHIFT;
+
+ data_hdr->info2 = cpu_to_le16(meta_ver << WMI_DATA_HDR_META_SHIFT);
+ data_hdr->info3 = 0;
+
+ return 0;
+}
+
+static u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri)
+{
+ struct iphdr *ip_hdr = (struct iphdr *) pkt;
+ u8 ip_pri;
+
+ /*
+ * Determine IPTOS priority
+ *
+ * IP-TOS - 8bits
+ * : DSCP(6-bits) ECN(2-bits)
+ * : DSCP - P2 P1 P0 X X X
+ * where (P2 P1 P0) form 802.1D
+ */
+ ip_pri = ip_hdr->tos >> 5;
+ ip_pri &= 0x7;
+
+ if ((layer2_pri & 0x7) > ip_pri)
+ return (u8) layer2_pri & 0x7;
+ else
+ return ip_pri;
+}
+
+int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, struct sk_buff *skb,
+ u32 layer2_priority, bool wmm_enabled,
+ u8 *ac)
+{
+ struct wmi_data_hdr *data_hdr;
+ struct ath6kl_llc_snap_hdr *llc_hdr;
+ struct wmi_create_pstream_cmd cmd;
+ u32 meta_size, hdr_size;
+ u16 ip_type = IP_ETHERTYPE;
+ u8 stream_exist, usr_pri;
+ u8 traffic_class = WMM_AC_BE;
+ u8 *datap;
+
+ if (WARN_ON(skb == NULL))
+ return -EINVAL;
+
+ datap = skb->data;
+ data_hdr = (struct wmi_data_hdr *) datap;
+
+ meta_size = ((le16_to_cpu(data_hdr->info2) >> WMI_DATA_HDR_META_SHIFT) &
+ WMI_DATA_HDR_META_MASK) ? WMI_MAX_TX_META_SZ : 0;
+
+ if (!wmm_enabled) {
+ /* If WMM is disabled all traffic goes as BE traffic */
+ usr_pri = 0;
+ } else {
+ hdr_size = sizeof(struct ethhdr);
+
+ llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap +
+ sizeof(struct
+ wmi_data_hdr) +
+ meta_size + hdr_size);
+
+ if (llc_hdr->eth_type == htons(ip_type)) {
+ /*
+ * Extract the endpoint info from the TOS field
+ * in the IP header.
+ */
+ usr_pri =
+ ath6kl_wmi_determine_user_priority(((u8 *) llc_hdr) +
+ sizeof(struct ath6kl_llc_snap_hdr),
+ layer2_priority);
+ } else
+ usr_pri = layer2_priority & 0x7;
+ }
+
+ /* workaround for WMM S5 */
+ if ((wmi->traffic_class == WMM_AC_VI) &&
+ ((usr_pri == 5) || (usr_pri == 4)))
+ usr_pri = 1;
+
+ /* Convert user priority to traffic class */
+ traffic_class = up_to_ac[usr_pri & 0x7];
+
+ wmi_data_hdr_set_up(data_hdr, usr_pri);
+
+ spin_lock_bh(&wmi->lock);
+ stream_exist = wmi->fat_pipe_exist;
+ spin_unlock_bh(&wmi->lock);
+
+ if (!(stream_exist & (1 << traffic_class))) {
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.traffic_class = traffic_class;
+ cmd.user_pri = usr_pri;
+ cmd.inactivity_int =
+ cpu_to_le32(WMI_IMPLICIT_PSTREAM_INACTIVITY_INT);
+ /* Implicit streams are created with TSID 0xFF */
+ cmd.tsid = WMI_IMPLICIT_PSTREAM;
+ ath6kl_wmi_create_pstream_cmd(wmi, &cmd);
+ }
+
+ *ac = traffic_class;
+
+ return 0;
+}
+
+int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb)
+{
+ struct ieee80211_hdr_3addr *pwh, wh;
+ struct ath6kl_llc_snap_hdr *llc_hdr;
+ struct ethhdr eth_hdr;
+ u32 hdr_size;
+ u8 *datap;
+ __le16 sub_type;
+
+ if (WARN_ON(skb == NULL))
+ return -EINVAL;
+
+ datap = skb->data;
+ pwh = (struct ieee80211_hdr_3addr *) datap;
+
+ sub_type = pwh->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE);
+
+ memcpy((u8 *) &wh, datap, sizeof(struct ieee80211_hdr_3addr));
+
+ /* Strip off the 802.11 header */
+ if (sub_type == cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
+ hdr_size = roundup(sizeof(struct ieee80211_qos_hdr),
+ sizeof(u32));
+ skb_pull(skb, hdr_size);
+ } else if (sub_type == cpu_to_le16(IEEE80211_STYPE_DATA))
+ skb_pull(skb, sizeof(struct ieee80211_hdr_3addr));
+
+ datap = skb->data;
+ llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap);
+
+ memset(&eth_hdr, 0, sizeof(eth_hdr));
+ eth_hdr.h_proto = llc_hdr->eth_type;
+
+ switch ((le16_to_cpu(wh.frame_control)) &
+ (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
+ case 0:
+ memcpy(eth_hdr.h_dest, wh.addr1, ETH_ALEN);
+ memcpy(eth_hdr.h_source, wh.addr2, ETH_ALEN);
+ break;
+ case IEEE80211_FCTL_TODS:
+ memcpy(eth_hdr.h_dest, wh.addr3, ETH_ALEN);
+ memcpy(eth_hdr.h_source, wh.addr2, ETH_ALEN);
+ break;
+ case IEEE80211_FCTL_FROMDS:
+ memcpy(eth_hdr.h_dest, wh.addr1, ETH_ALEN);
+ memcpy(eth_hdr.h_source, wh.addr3, ETH_ALEN);
+ break;
+ case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
+ break;
+ }
+
+ skb_pull(skb, sizeof(struct ath6kl_llc_snap_hdr));
+ skb_push(skb, sizeof(eth_hdr));
+
+ datap = skb->data;
+
+ memcpy(datap, &eth_hdr, sizeof(eth_hdr));
+
+ return 0;
+}
+
+/*
+ * Performs 802.3 to DIX encapsulation for received packets.
+ * Assumes the entire 802.3 header is contigous.
+ */
+int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb)
+{
+ struct ath6kl_llc_snap_hdr *llc_hdr;
+ struct ethhdr eth_hdr;
+ u8 *datap;
+
+ if (WARN_ON(skb == NULL))
+ return -EINVAL;
+
+ datap = skb->data;
+
+ memcpy(&eth_hdr, datap, sizeof(eth_hdr));
+
+ llc_hdr = (struct ath6kl_llc_snap_hdr *) (datap + sizeof(eth_hdr));
+ eth_hdr.h_proto = llc_hdr->eth_type;
+
+ skb_pull(skb, sizeof(struct ath6kl_llc_snap_hdr));
+ datap = skb->data;
+
+ memcpy(datap, &eth_hdr, sizeof(eth_hdr));
+
+ return 0;
+}
+
+static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len)
+{
+ struct tx_complete_msg_v1 *msg_v1;
+ struct wmi_tx_complete_event *evt;
+ int index;
+ u16 size;
+
+ evt = (struct wmi_tx_complete_event *) datap;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "comp: %d %d %d\n",
+ evt->num_msg, evt->msg_len, evt->msg_type);
+
+ if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_WMI))
+ return 0;
+
+ for (index = 0; index < evt->num_msg; index++) {
+ size = sizeof(struct wmi_tx_complete_event) +
+ (index * sizeof(struct tx_complete_msg_v1));
+ msg_v1 = (struct tx_complete_msg_v1 *)(datap + size);
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "msg: %d %d %d %d\n",
+ msg_v1->status, msg_v1->pkt_id,
+ msg_v1->rate_idx, msg_v1->ack_failures);
+ }
+
+ return 0;
+}
+
+static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap,
+ int len)
+{
+ struct wmi_remain_on_chnl_event *ev;
+ u32 freq;
+ u32 dur;
+ struct ieee80211_channel *chan;
+ struct ath6kl *ar = wmi->parent_dev;
+
+ if (len < sizeof(*ev))
+ return -EINVAL;
+
+ ev = (struct wmi_remain_on_chnl_event *) datap;
+ freq = le32_to_cpu(ev->freq);
+ dur = le32_to_cpu(ev->duration);
+ ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl: freq=%u dur=%u\n",
+ freq, dur);
+ chan = ieee80211_get_channel(ar->wdev->wiphy, freq);
+ if (!chan) {
+ ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl: Unknown channel "
+ "(freq=%u)\n", freq);
+ return -EINVAL;
+ }
+ cfg80211_ready_on_channel(ar->net_dev, 1, chan, NL80211_CHAN_NO_HT,
+ dur, GFP_ATOMIC);
+
+ return 0;
+}
+
+static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi,
+ u8 *datap, int len)
+{
+ struct wmi_cancel_remain_on_chnl_event *ev;
+ u32 freq;
+ u32 dur;
+ struct ieee80211_channel *chan;
+ struct ath6kl *ar = wmi->parent_dev;
+
+ if (len < sizeof(*ev))
+ return -EINVAL;
+
+ ev = (struct wmi_cancel_remain_on_chnl_event *) datap;
+ freq = le32_to_cpu(ev->freq);
+ dur = le32_to_cpu(ev->duration);
+ ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl: freq=%u dur=%u "
+ "status=%u\n", freq, dur, ev->status);
+ chan = ieee80211_get_channel(ar->wdev->wiphy, freq);
+ if (!chan) {
+ ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl: Unknown "
+ "channel (freq=%u)\n", freq);
+ return -EINVAL;
+ }
+ cfg80211_remain_on_channel_expired(ar->net_dev, 1, chan,
+ NL80211_CHAN_NO_HT, GFP_ATOMIC);
+
+ return 0;
+}
+
+static int ath6kl_wmi_tx_status_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ struct wmi_tx_status_event *ev;
+ u32 id;
+ struct ath6kl *ar = wmi->parent_dev;
+
+ if (len < sizeof(*ev))
+ return -EINVAL;
+
+ ev = (struct wmi_tx_status_event *) datap;
+ id = le32_to_cpu(ev->id);
+ ath6kl_dbg(ATH6KL_DBG_WMI, "tx_status: id=%x ack_status=%u\n",
+ id, ev->ack_status);
+ if (wmi->last_mgmt_tx_frame) {
+ cfg80211_mgmt_tx_status(ar->net_dev, id,
+ wmi->last_mgmt_tx_frame,
+ wmi->last_mgmt_tx_frame_len,
+ !!ev->ack_status, GFP_ATOMIC);
+ kfree(wmi->last_mgmt_tx_frame);
+ wmi->last_mgmt_tx_frame = NULL;
+ wmi->last_mgmt_tx_frame_len = 0;
+ }
+
+ return 0;
+}
+
+static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ struct wmi_p2p_rx_probe_req_event *ev;
+ u32 freq;
+ u16 dlen;
+ struct ath6kl *ar = wmi->parent_dev;
+
+ if (len < sizeof(*ev))
+ return -EINVAL;
+
+ ev = (struct wmi_p2p_rx_probe_req_event *) datap;
+ freq = le32_to_cpu(ev->freq);
+ dlen = le16_to_cpu(ev->len);
+ if (datap + len < ev->data + dlen) {
+ ath6kl_err("invalid wmi_p2p_rx_probe_req_event: "
+ "len=%d dlen=%u\n", len, dlen);
+ return -EINVAL;
+ }
+ ath6kl_dbg(ATH6KL_DBG_WMI, "rx_probe_req: len=%u freq=%u "
+ "probe_req_report=%d\n",
+ dlen, freq, ar->probe_req_report);
+
+ if (ar->probe_req_report || ar->nw_type == AP_NETWORK)
+ cfg80211_rx_mgmt(ar->net_dev, freq, ev->data, dlen, GFP_ATOMIC);
+
+ return 0;
+}
+
+static int ath6kl_wmi_p2p_capabilities_event_rx(u8 *datap, int len)
+{
+ struct wmi_p2p_capabilities_event *ev;
+ u16 dlen;
+
+ if (len < sizeof(*ev))
+ return -EINVAL;
+
+ ev = (struct wmi_p2p_capabilities_event *) datap;
+ dlen = le16_to_cpu(ev->len);
+ ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_capab: len=%u\n", dlen);
+
+ return 0;
+}
+
+static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ struct wmi_rx_action_event *ev;
+ u32 freq;
+ u16 dlen;
+ struct ath6kl *ar = wmi->parent_dev;
+
+ if (len < sizeof(*ev))
+ return -EINVAL;
+
+ ev = (struct wmi_rx_action_event *) datap;
+ freq = le32_to_cpu(ev->freq);
+ dlen = le16_to_cpu(ev->len);
+ if (datap + len < ev->data + dlen) {
+ ath6kl_err("invalid wmi_rx_action_event: "
+ "len=%d dlen=%u\n", len, dlen);
+ return -EINVAL;
+ }
+ ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq);
+ cfg80211_rx_mgmt(ar->net_dev, freq, ev->data, dlen, GFP_ATOMIC);
+
+ return 0;
+}
+
+static int ath6kl_wmi_p2p_info_event_rx(u8 *datap, int len)
+{
+ struct wmi_p2p_info_event *ev;
+ u32 flags;
+ u16 dlen;
+
+ if (len < sizeof(*ev))
+ return -EINVAL;
+
+ ev = (struct wmi_p2p_info_event *) datap;
+ flags = le32_to_cpu(ev->info_req_flags);
+ dlen = le16_to_cpu(ev->len);
+ ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: flags=%x len=%d\n", flags, dlen);
+
+ if (flags & P2P_FLAG_CAPABILITIES_REQ) {
+ struct wmi_p2p_capabilities *cap;
+ if (dlen < sizeof(*cap))
+ return -EINVAL;
+ cap = (struct wmi_p2p_capabilities *) ev->data;
+ ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: GO Power Save = %d\n",
+ cap->go_power_save);
+ }
+
+ if (flags & P2P_FLAG_MACADDR_REQ) {
+ struct wmi_p2p_macaddr *mac;
+ if (dlen < sizeof(*mac))
+ return -EINVAL;
+ mac = (struct wmi_p2p_macaddr *) ev->data;
+ ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: MAC Address = %pM\n",
+ mac->mac_addr);
+ }
+
+ if (flags & P2P_FLAG_HMODEL_REQ) {
+ struct wmi_p2p_hmodel *mod;
+ if (dlen < sizeof(*mod))
+ return -EINVAL;
+ mod = (struct wmi_p2p_hmodel *) ev->data;
+ ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: P2P Model = %d (%s)\n",
+ mod->p2p_model,
+ mod->p2p_model ? "host" : "firmware");
+ }
+ return 0;
+}
+
+static inline struct sk_buff *ath6kl_wmi_get_new_buf(u32 size)
+{
+ struct sk_buff *skb;
+
+ skb = ath6kl_buf_alloc(size);
+ if (!skb)
+ return NULL;
+
+ skb_put(skb, size);
+ if (size)
+ memset(skb->data, 0, size);
+
+ return skb;
+}
+
+/* Send a "simple" wmi command -- one with no arguments */
+static int ath6kl_wmi_simple_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id)
+{
+ struct sk_buff *skb;
+ int ret;
+
+ skb = ath6kl_wmi_get_new_buf(0);
+ if (!skb)
+ return -ENOMEM;
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, cmd_id, NO_SYNC_WMIFLAG);
+
+ return ret;
+}
+
+static int ath6kl_wmi_ready_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ struct wmi_ready_event_2 *ev = (struct wmi_ready_event_2 *) datap;
+
+ if (len < sizeof(struct wmi_ready_event_2))
+ return -EINVAL;
+
+ wmi->ready = true;
+ ath6kl_ready_event(wmi->parent_dev, ev->mac_addr,
+ le32_to_cpu(ev->sw_version),
+ le32_to_cpu(ev->abi_version));
+
+ return 0;
+}
+
+/*
+ * Mechanism to modify the roaming behavior in the firmware. The lower rssi
+ * at which the station has to roam can be passed with
+ * WMI_SET_LRSSI_SCAN_PARAMS. Subtract 96 from RSSI to get the signal level
+ * in dBm.
+ */
+int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi)
+{
+ struct sk_buff *skb;
+ struct roam_ctrl_cmd *cmd;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct roam_ctrl_cmd *) skb->data;
+
+ cmd->info.params.lrssi_scan_period = cpu_to_le16(DEF_LRSSI_SCAN_PERIOD);
+ cmd->info.params.lrssi_scan_threshold = a_cpu_to_sle16(lrssi +
+ DEF_SCAN_FOR_ROAM_INTVL);
+ cmd->info.params.lrssi_roam_threshold = a_cpu_to_sle16(lrssi);
+ cmd->info.params.roam_rssi_floor = DEF_LRSSI_ROAM_FLOOR;
+ cmd->roam_ctrl = WMI_SET_LRSSI_SCAN_PARAMS;
+
+ ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_ROAM_CTRL_CMDID, NO_SYNC_WMIFLAG);
+
+ return 0;
+}
+
+static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ struct wmi_connect_event *ev;
+ u8 *pie, *peie;
+ struct ath6kl *ar = wmi->parent_dev;
+
+ if (len < sizeof(struct wmi_connect_event))
+ return -EINVAL;
+
+ ev = (struct wmi_connect_event *) datap;
+
+ if (ar->nw_type == AP_NETWORK) {
+ /* AP mode start/STA connected event */
+ struct net_device *dev = ar->net_dev;
+ if (memcmp(dev->dev_addr, ev->u.ap_bss.bssid, ETH_ALEN) == 0) {
+ ath6kl_dbg(ATH6KL_DBG_WMI, "%s: freq %d bssid %pM "
+ "(AP started)\n",
+ __func__, le16_to_cpu(ev->u.ap_bss.ch),
+ ev->u.ap_bss.bssid);
+ ath6kl_connect_ap_mode_bss(
+ ar, le16_to_cpu(ev->u.ap_bss.ch));
+ } else {
+ ath6kl_dbg(ATH6KL_DBG_WMI, "%s: aid %u mac_addr %pM "
+ "auth=%u keymgmt=%u cipher=%u apsd_info=%u "
+ "(STA connected)\n",
+ __func__, ev->u.ap_sta.aid,
+ ev->u.ap_sta.mac_addr,
+ ev->u.ap_sta.auth,
+ ev->u.ap_sta.keymgmt,
+ le16_to_cpu(ev->u.ap_sta.cipher),
+ ev->u.ap_sta.apsd_info);
+ ath6kl_connect_ap_mode_sta(
+ ar, ev->u.ap_sta.aid, ev->u.ap_sta.mac_addr,
+ ev->u.ap_sta.keymgmt,
+ le16_to_cpu(ev->u.ap_sta.cipher),
+ ev->u.ap_sta.auth, ev->assoc_req_len,
+ ev->assoc_info + ev->beacon_ie_len);
+ }
+ return 0;
+ }
+
+ /* STA/IBSS mode connection event */
+
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "wmi event connect freq %d bssid %pM listen_intvl %d beacon_intvl %d type %d\n",
+ le16_to_cpu(ev->u.sta.ch), ev->u.sta.bssid,
+ le16_to_cpu(ev->u.sta.listen_intvl),
+ le16_to_cpu(ev->u.sta.beacon_intvl),
+ le32_to_cpu(ev->u.sta.nw_type));
+
+ /* Start of assoc rsp IEs */
+ pie = ev->assoc_info + ev->beacon_ie_len +
+ ev->assoc_req_len + (sizeof(u16) * 3); /* capinfo, status, aid */
+
+ /* End of assoc rsp IEs */
+ peie = ev->assoc_info + ev->beacon_ie_len + ev->assoc_req_len +
+ ev->assoc_resp_len;
+
+ while (pie < peie) {
+ switch (*pie) {
+ case WLAN_EID_VENDOR_SPECIFIC:
+ if (pie[1] > 3 && pie[2] == 0x00 && pie[3] == 0x50 &&
+ pie[4] == 0xf2 && pie[5] == WMM_OUI_TYPE) {
+ /* WMM OUT (00:50:F2) */
+ if (pie[1] > 5
+ && pie[6] == WMM_PARAM_OUI_SUBTYPE)
+ wmi->is_wmm_enabled = true;
+ }
+ break;
+ }
+
+ if (wmi->is_wmm_enabled)
+ break;
+
+ pie += pie[1] + 2;
+ }
+
+ ath6kl_connect_event(wmi->parent_dev, le16_to_cpu(ev->u.sta.ch),
+ ev->u.sta.bssid,
+ le16_to_cpu(ev->u.sta.listen_intvl),
+ le16_to_cpu(ev->u.sta.beacon_intvl),
+ le32_to_cpu(ev->u.sta.nw_type),
+ ev->beacon_ie_len, ev->assoc_req_len,
+ ev->assoc_resp_len, ev->assoc_info);
+
+ return 0;
+}
+
+static struct country_code_to_enum_rd *
+ath6kl_regd_find_country(u16 countryCode)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
+ if (allCountries[i].countryCode == countryCode)
+ return &allCountries[i];
+ }
+
+ return NULL;
+}
+
+static struct reg_dmn_pair_mapping *
+ath6kl_get_regpair(u16 regdmn)
+{
+ int i;
+
+ if (regdmn == NO_ENUMRD)
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
+ if (regDomainPairs[i].regDmnEnum == regdmn)
+ return &regDomainPairs[i];
+ }
+
+ return NULL;
+}
+
+static struct country_code_to_enum_rd *
+ath6kl_regd_find_country_by_rd(u16 regdmn)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
+ if (allCountries[i].regDmnEnum == regdmn)
+ return &allCountries[i];
+ }
+
+ return NULL;
+}
+
+static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len)
+{
+
+ struct ath6kl_wmi_regdomain *ev;
+ struct country_code_to_enum_rd *country = NULL;
+ struct reg_dmn_pair_mapping *regpair = NULL;
+ char alpha2[2];
+ u32 reg_code;
+
+ ev = (struct ath6kl_wmi_regdomain *) datap;
+ reg_code = le32_to_cpu(ev->reg_code);
+
+ if ((reg_code >> ATH6KL_COUNTRY_RD_SHIFT) & COUNTRY_ERD_FLAG)
+ country = ath6kl_regd_find_country((u16) reg_code);
+ else if (!(((u16) reg_code & WORLD_SKU_MASK) == WORLD_SKU_PREFIX)) {
+
+ regpair = ath6kl_get_regpair((u16) reg_code);
+ country = ath6kl_regd_find_country_by_rd((u16) reg_code);
+ ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n",
+ regpair->regDmnEnum);
+ }
+
+ if (country) {
+ alpha2[0] = country->isoName[0];
+ alpha2[1] = country->isoName[1];
+
+ regulatory_hint(wmi->parent_dev->wdev->wiphy, alpha2);
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "Country alpha2 being used: %c%c\n",
+ alpha2[0], alpha2[1]);
+ }
+}
+
+static int ath6kl_wmi_disconnect_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ struct wmi_disconnect_event *ev;
+ wmi->traffic_class = 100;
+
+ if (len < sizeof(struct wmi_disconnect_event))
+ return -EINVAL;
+
+ ev = (struct wmi_disconnect_event *) datap;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "wmi event disconnect proto_reason %d bssid %pM wmi_reason %d assoc_resp_len %d\n",
+ le16_to_cpu(ev->proto_reason_status), ev->bssid,
+ ev->disconn_reason, ev->assoc_resp_len);
+
+ wmi->is_wmm_enabled = false;
+ wmi->pair_crypto_type = NONE_CRYPT;
+ wmi->grp_crypto_type = NONE_CRYPT;
+
+ ath6kl_disconnect_event(wmi->parent_dev, ev->disconn_reason,
+ ev->bssid, ev->assoc_resp_len, ev->assoc_info,
+ le16_to_cpu(ev->proto_reason_status));
+
+ return 0;
+}
+
+static int ath6kl_wmi_peer_node_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ struct wmi_peer_node_event *ev;
+
+ if (len < sizeof(struct wmi_peer_node_event))
+ return -EINVAL;
+
+ ev = (struct wmi_peer_node_event *) datap;
+
+ if (ev->event_code == PEER_NODE_JOIN_EVENT)
+ ath6kl_dbg(ATH6KL_DBG_WMI, "joined node with mac addr: %pM\n",
+ ev->peer_mac_addr);
+ else if (ev->event_code == PEER_NODE_LEAVE_EVENT)
+ ath6kl_dbg(ATH6KL_DBG_WMI, "left node with mac addr: %pM\n",
+ ev->peer_mac_addr);
+
+ return 0;
+}
+
+static int ath6kl_wmi_tkip_micerr_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ struct wmi_tkip_micerr_event *ev;
+
+ if (len < sizeof(struct wmi_tkip_micerr_event))
+ return -EINVAL;
+
+ ev = (struct wmi_tkip_micerr_event *) datap;
+
+ ath6kl_tkip_micerr_event(wmi->parent_dev, ev->key_id, ev->is_mcast);
+
+ return 0;
+}
+
+static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ struct wmi_bss_info_hdr2 *bih;
+ u8 *buf;
+ struct ieee80211_channel *channel;
+ struct ath6kl *ar = wmi->parent_dev;
+ struct ieee80211_mgmt *mgmt;
+ struct cfg80211_bss *bss;
+
+ if (len <= sizeof(struct wmi_bss_info_hdr2))
+ return -EINVAL;
+
+ bih = (struct wmi_bss_info_hdr2 *) datap;
+ buf = datap + sizeof(struct wmi_bss_info_hdr2);
+ len -= sizeof(struct wmi_bss_info_hdr2);
+
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "bss info evt - ch %u, snr %d, rssi %d, bssid \"%pM\" "
+ "frame_type=%d\n",
+ bih->ch, bih->snr, bih->snr - 95, bih->bssid,
+ bih->frame_type);
+
+ if (bih->frame_type != BEACON_FTYPE &&
+ bih->frame_type != PROBERESP_FTYPE)
+ return 0; /* Only update BSS table for now */
+
+ if (bih->frame_type == BEACON_FTYPE &&
+ test_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag)) {
+ clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag);
+ ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0);
+ }
+
+ channel = ieee80211_get_channel(ar->wdev->wiphy, le16_to_cpu(bih->ch));
+ if (channel == NULL)
+ return -EINVAL;
+
+ if (len < 8 + 2 + 2)
+ return -EINVAL;
+
+ if (bih->frame_type == BEACON_FTYPE && test_bit(CONNECTED, &ar->flag) &&
+ memcmp(bih->bssid, ar->bssid, ETH_ALEN) == 0) {
+ const u8 *tim;
+ tim = cfg80211_find_ie(WLAN_EID_TIM, buf + 8 + 2 + 2,
+ len - 8 - 2 - 2);
+ if (tim && tim[1] >= 2) {
+ ar->assoc_bss_dtim_period = tim[3];
+ set_bit(DTIM_PERIOD_AVAIL, &ar->flag);
+ }
+ }
+
+ /*
+ * In theory, use of cfg80211_inform_bss() would be more natural here
+ * since we do not have the full frame. However, at least for now,
+ * cfg80211 can only distinguish Beacon and Probe Response frames from
+ * each other when using cfg80211_inform_bss_frame(), so let's build a
+ * fake IEEE 802.11 header to be able to take benefit of this.
+ */
+ mgmt = kmalloc(24 + len, GFP_ATOMIC);
+ if (mgmt == NULL)
+ return -EINVAL;
+
+ if (bih->frame_type == BEACON_FTYPE) {
+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_BEACON);
+ memset(mgmt->da, 0xff, ETH_ALEN);
+ } else {
+ struct net_device *dev = ar->net_dev;
+
+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_PROBE_RESP);
+ memcpy(mgmt->da, dev->dev_addr, ETH_ALEN);
+ }
+ mgmt->duration = cpu_to_le16(0);
+ memcpy(mgmt->sa, bih->bssid, ETH_ALEN);
+ memcpy(mgmt->bssid, bih->bssid, ETH_ALEN);
+ mgmt->seq_ctrl = cpu_to_le16(0);
+
+ memcpy(&mgmt->u.beacon, buf, len);
+
+ bss = cfg80211_inform_bss_frame(ar->wdev->wiphy, channel, mgmt,
+ 24 + len, (bih->snr - 95) * 100,
+ GFP_ATOMIC);
+ kfree(mgmt);
+ if (bss == NULL)
+ return -ENOMEM;
+ cfg80211_put_bss(bss);
+
+ return 0;
+}
+
+/* Inactivity timeout of a fatpipe(pstream) at the target */
+static int ath6kl_wmi_pstream_timeout_event_rx(struct wmi *wmi, u8 *datap,
+ int len)
+{
+ struct wmi_pstream_timeout_event *ev;
+
+ if (len < sizeof(struct wmi_pstream_timeout_event))
+ return -EINVAL;
+
+ ev = (struct wmi_pstream_timeout_event *) datap;
+
+ /*
+ * When the pstream (fat pipe == AC) timesout, it means there were
+ * no thinStreams within this pstream & it got implicitly created
+ * due to data flow on this AC. We start the inactivity timer only
+ * for implicitly created pstream. Just reset the host state.
+ */
+ spin_lock_bh(&wmi->lock);
+ wmi->stream_exist_for_ac[ev->traffic_class] = 0;
+ wmi->fat_pipe_exist &= ~(1 << ev->traffic_class);
+ spin_unlock_bh(&wmi->lock);
+
+ /* Indicate inactivity to driver layer for this fatpipe (pstream) */
+ ath6kl_indicate_tx_activity(wmi->parent_dev, ev->traffic_class, false);
+
+ return 0;
+}
+
+static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ struct wmi_bit_rate_reply *reply;
+ s32 rate;
+ u32 sgi, index;
+
+ if (len < sizeof(struct wmi_bit_rate_reply))
+ return -EINVAL;
+
+ reply = (struct wmi_bit_rate_reply *) datap;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "rateindex %d\n", reply->rate_index);
+
+ if (reply->rate_index == (s8) RATE_AUTO) {
+ rate = RATE_AUTO;
+ } else {
+ index = reply->rate_index & 0x7f;
+ sgi = (reply->rate_index & 0x80) ? 1 : 0;
+ rate = wmi_rate_tbl[index][sgi];
+ }
+
+ ath6kl_wakeup_event(wmi->parent_dev);
+
+ return 0;
+}
+
+static int ath6kl_wmi_tcmd_test_report_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ ath6kl_tm_rx_report_event(wmi->parent_dev, datap, len);
+
+ return 0;
+}
+
+static int ath6kl_wmi_ratemask_reply_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ if (len < sizeof(struct wmi_fix_rates_reply))
+ return -EINVAL;
+
+ ath6kl_wakeup_event(wmi->parent_dev);
+
+ return 0;
+}
+
+static int ath6kl_wmi_ch_list_reply_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ if (len < sizeof(struct wmi_channel_list_reply))
+ return -EINVAL;
+
+ ath6kl_wakeup_event(wmi->parent_dev);
+
+ return 0;
+}
+
+static int ath6kl_wmi_tx_pwr_reply_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ struct wmi_tx_pwr_reply *reply;
+
+ if (len < sizeof(struct wmi_tx_pwr_reply))
+ return -EINVAL;
+
+ reply = (struct wmi_tx_pwr_reply *) datap;
+ ath6kl_txpwr_rx_evt(wmi->parent_dev, reply->dbM);
+
+ return 0;
+}
+
+static int ath6kl_wmi_keepalive_reply_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ if (len < sizeof(struct wmi_get_keepalive_cmd))
+ return -EINVAL;
+
+ ath6kl_wakeup_event(wmi->parent_dev);
+
+ return 0;
+}
+
+static int ath6kl_wmi_scan_complete_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ struct wmi_scan_complete_event *ev;
+
+ ev = (struct wmi_scan_complete_event *) datap;
+
+ ath6kl_scan_complete_evt(wmi->parent_dev, a_sle32_to_cpu(ev->status));
+ wmi->is_probe_ssid = false;
+
+ return 0;
+}
+
+static int ath6kl_wmi_neighbor_report_event_rx(struct wmi *wmi, u8 *datap,
+ int len)
+{
+ struct wmi_neighbor_report_event *ev;
+ u8 i;
+
+ if (len < sizeof(*ev))
+ return -EINVAL;
+ ev = (struct wmi_neighbor_report_event *) datap;
+ if (sizeof(*ev) + ev->num_neighbors * sizeof(struct wmi_neighbor_info)
+ > len) {
+ ath6kl_dbg(ATH6KL_DBG_WMI, "truncated neighbor event "
+ "(num=%d len=%d)\n", ev->num_neighbors, len);
+ return -EINVAL;
+ }
+ for (i = 0; i < ev->num_neighbors; i++) {
+ ath6kl_dbg(ATH6KL_DBG_WMI, "neighbor %d/%d - %pM 0x%x\n",
+ i + 1, ev->num_neighbors, ev->neighbor[i].bssid,
+ ev->neighbor[i].bss_flags);
+ cfg80211_pmksa_candidate_notify(wmi->parent_dev->net_dev, i,
+ ev->neighbor[i].bssid,
+ !!(ev->neighbor[i].bss_flags &
+ WMI_PREAUTH_CAPABLE_BSS),
+ GFP_ATOMIC);
+ }
+
+ return 0;
+}
+
+/*
+ * Target is reporting a programming error. This is for
+ * developer aid only. Target only checks a few common violations
+ * and it is responsibility of host to do all error checking.
+ * Behavior of target after wmi error event is undefined.
+ * A reset is recommended.
+ */
+static int ath6kl_wmi_error_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ const char *type = "unknown error";
+ struct wmi_cmd_error_event *ev;
+ ev = (struct wmi_cmd_error_event *) datap;
+
+ switch (ev->err_code) {
+ case INVALID_PARAM:
+ type = "invalid parameter";
+ break;
+ case ILLEGAL_STATE:
+ type = "invalid state";
+ break;
+ case INTERNAL_ERROR:
+ type = "internal error";
+ break;
+ }
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "programming error, cmd=%d %s\n",
+ ev->cmd_id, type);
+
+ return 0;
+}
+
+static int ath6kl_wmi_stats_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ ath6kl_tgt_stats_event(wmi->parent_dev, datap, len);
+
+ return 0;
+}
+
+static u8 ath6kl_wmi_get_upper_threshold(s16 rssi,
+ struct sq_threshold_params *sq_thresh,
+ u32 size)
+{
+ u32 index;
+ u8 threshold = (u8) sq_thresh->upper_threshold[size - 1];
+
+ /* The list is already in sorted order. Get the next lower value */
+ for (index = 0; index < size; index++) {
+ if (rssi < sq_thresh->upper_threshold[index]) {
+ threshold = (u8) sq_thresh->upper_threshold[index];
+ break;
+ }
+ }
+
+ return threshold;
+}
+
+static u8 ath6kl_wmi_get_lower_threshold(s16 rssi,
+ struct sq_threshold_params *sq_thresh,
+ u32 size)
+{
+ u32 index;
+ u8 threshold = (u8) sq_thresh->lower_threshold[size - 1];
+
+ /* The list is already in sorted order. Get the next lower value */
+ for (index = 0; index < size; index++) {
+ if (rssi > sq_thresh->lower_threshold[index]) {
+ threshold = (u8) sq_thresh->lower_threshold[index];
+ break;
+ }
+ }
+
+ return threshold;
+}
+
+static int ath6kl_wmi_send_rssi_threshold_params(struct wmi *wmi,
+ struct wmi_rssi_threshold_params_cmd *rssi_cmd)
+{
+ struct sk_buff *skb;
+ struct wmi_rssi_threshold_params_cmd *cmd;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_rssi_threshold_params_cmd *) skb->data;
+ memcpy(cmd, rssi_cmd, sizeof(struct wmi_rssi_threshold_params_cmd));
+
+ return ath6kl_wmi_cmd_send(wmi, skb, WMI_RSSI_THRESHOLD_PARAMS_CMDID,
+ NO_SYNC_WMIFLAG);
+}
+
+static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap,
+ int len)
+{
+ struct wmi_rssi_threshold_event *reply;
+ struct wmi_rssi_threshold_params_cmd cmd;
+ struct sq_threshold_params *sq_thresh;
+ enum wmi_rssi_threshold_val new_threshold;
+ u8 upper_rssi_threshold, lower_rssi_threshold;
+ s16 rssi;
+ int ret;
+
+ if (len < sizeof(struct wmi_rssi_threshold_event))
+ return -EINVAL;
+
+ reply = (struct wmi_rssi_threshold_event *) datap;
+ new_threshold = (enum wmi_rssi_threshold_val) reply->range;
+ rssi = a_sle16_to_cpu(reply->rssi);
+
+ sq_thresh = &wmi->sq_threshld[SIGNAL_QUALITY_METRICS_RSSI];
+
+ /*
+ * Identify the threshold breached and communicate that to the app.
+ * After that install a new set of thresholds based on the signal
+ * quality reported by the target
+ */
+ if (new_threshold) {
+ /* Upper threshold breached */
+ if (rssi < sq_thresh->upper_threshold[0]) {
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "spurious upper rssi threshold event: %d\n",
+ rssi);
+ } else if ((rssi < sq_thresh->upper_threshold[1]) &&
+ (rssi >= sq_thresh->upper_threshold[0])) {
+ new_threshold = WMI_RSSI_THRESHOLD1_ABOVE;
+ } else if ((rssi < sq_thresh->upper_threshold[2]) &&
+ (rssi >= sq_thresh->upper_threshold[1])) {
+ new_threshold = WMI_RSSI_THRESHOLD2_ABOVE;
+ } else if ((rssi < sq_thresh->upper_threshold[3]) &&
+ (rssi >= sq_thresh->upper_threshold[2])) {
+ new_threshold = WMI_RSSI_THRESHOLD3_ABOVE;
+ } else if ((rssi < sq_thresh->upper_threshold[4]) &&
+ (rssi >= sq_thresh->upper_threshold[3])) {
+ new_threshold = WMI_RSSI_THRESHOLD4_ABOVE;
+ } else if ((rssi < sq_thresh->upper_threshold[5]) &&
+ (rssi >= sq_thresh->upper_threshold[4])) {
+ new_threshold = WMI_RSSI_THRESHOLD5_ABOVE;
+ } else if (rssi >= sq_thresh->upper_threshold[5]) {
+ new_threshold = WMI_RSSI_THRESHOLD6_ABOVE;
+ }
+ } else {
+ /* Lower threshold breached */
+ if (rssi > sq_thresh->lower_threshold[0]) {
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "spurious lower rssi threshold event: %d %d\n",
+ rssi, sq_thresh->lower_threshold[0]);
+ } else if ((rssi > sq_thresh->lower_threshold[1]) &&
+ (rssi <= sq_thresh->lower_threshold[0])) {
+ new_threshold = WMI_RSSI_THRESHOLD6_BELOW;
+ } else if ((rssi > sq_thresh->lower_threshold[2]) &&
+ (rssi <= sq_thresh->lower_threshold[1])) {
+ new_threshold = WMI_RSSI_THRESHOLD5_BELOW;
+ } else if ((rssi > sq_thresh->lower_threshold[3]) &&
+ (rssi <= sq_thresh->lower_threshold[2])) {
+ new_threshold = WMI_RSSI_THRESHOLD4_BELOW;
+ } else if ((rssi > sq_thresh->lower_threshold[4]) &&
+ (rssi <= sq_thresh->lower_threshold[3])) {
+ new_threshold = WMI_RSSI_THRESHOLD3_BELOW;
+ } else if ((rssi > sq_thresh->lower_threshold[5]) &&
+ (rssi <= sq_thresh->lower_threshold[4])) {
+ new_threshold = WMI_RSSI_THRESHOLD2_BELOW;
+ } else if (rssi <= sq_thresh->lower_threshold[5]) {
+ new_threshold = WMI_RSSI_THRESHOLD1_BELOW;
+ }
+ }
+
+ /* Calculate and install the next set of thresholds */
+ lower_rssi_threshold = ath6kl_wmi_get_lower_threshold(rssi, sq_thresh,
+ sq_thresh->lower_threshold_valid_count);
+ upper_rssi_threshold = ath6kl_wmi_get_upper_threshold(rssi, sq_thresh,
+ sq_thresh->upper_threshold_valid_count);
+
+ /* Issue a wmi command to install the thresholds */
+ cmd.thresh_above1_val = a_cpu_to_sle16(upper_rssi_threshold);
+ cmd.thresh_below1_val = a_cpu_to_sle16(lower_rssi_threshold);
+ cmd.weight = sq_thresh->weight;
+ cmd.poll_time = cpu_to_le32(sq_thresh->polling_interval);
+
+ ret = ath6kl_wmi_send_rssi_threshold_params(wmi, &cmd);
+ if (ret) {
+ ath6kl_err("unable to configure rssi thresholds\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ struct wmi_cac_event *reply;
+ struct ieee80211_tspec_ie *ts;
+ u16 active_tsids, tsinfo;
+ u8 tsid, index;
+ u8 ts_id;
+
+ if (len < sizeof(struct wmi_cac_event))
+ return -EINVAL;
+
+ reply = (struct wmi_cac_event *) datap;
+
+ if ((reply->cac_indication == CAC_INDICATION_ADMISSION_RESP) &&
+ (reply->status_code != IEEE80211_TSPEC_STATUS_ADMISS_ACCEPTED)) {
+
+ ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion);
+ tsinfo = le16_to_cpu(ts->tsinfo);
+ tsid = (tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) &
+ IEEE80211_WMM_IE_TSPEC_TID_MASK;
+
+ ath6kl_wmi_delete_pstream_cmd(wmi, reply->ac, tsid);
+ } else if (reply->cac_indication == CAC_INDICATION_NO_RESP) {
+ /*
+ * Following assumes that there is only one outstanding
+ * ADDTS request when this event is received
+ */
+ spin_lock_bh(&wmi->lock);
+ active_tsids = wmi->stream_exist_for_ac[reply->ac];
+ spin_unlock_bh(&wmi->lock);
+
+ for (index = 0; index < sizeof(active_tsids) * 8; index++) {
+ if ((active_tsids >> index) & 1)
+ break;
+ }
+ if (index < (sizeof(active_tsids) * 8))
+ ath6kl_wmi_delete_pstream_cmd(wmi, reply->ac, index);
+ }
+
+ /*
+ * Clear active tsids and Add missing handling
+ * for delete qos stream from AP
+ */
+ else if (reply->cac_indication == CAC_INDICATION_DELETE) {
+
+ ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion);
+ tsinfo = le16_to_cpu(ts->tsinfo);
+ ts_id = ((tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) &
+ IEEE80211_WMM_IE_TSPEC_TID_MASK);
+
+ spin_lock_bh(&wmi->lock);
+ wmi->stream_exist_for_ac[reply->ac] &= ~(1 << ts_id);
+ active_tsids = wmi->stream_exist_for_ac[reply->ac];
+ spin_unlock_bh(&wmi->lock);
+
+ /* Indicate stream inactivity to driver layer only if all tsids
+ * within this AC are deleted.
+ */
+ if (!active_tsids) {
+ ath6kl_indicate_tx_activity(wmi->parent_dev, reply->ac,
+ false);
+ wmi->fat_pipe_exist &= ~(1 << reply->ac);
+ }
+ }
+
+ return 0;
+}
+
+static int ath6kl_wmi_send_snr_threshold_params(struct wmi *wmi,
+ struct wmi_snr_threshold_params_cmd *snr_cmd)
+{
+ struct sk_buff *skb;
+ struct wmi_snr_threshold_params_cmd *cmd;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_snr_threshold_params_cmd *) skb->data;
+ memcpy(cmd, snr_cmd, sizeof(struct wmi_snr_threshold_params_cmd));
+
+ return ath6kl_wmi_cmd_send(wmi, skb, WMI_SNR_THRESHOLD_PARAMS_CMDID,
+ NO_SYNC_WMIFLAG);
+}
+
+static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap,
+ int len)
+{
+ struct wmi_snr_threshold_event *reply;
+ struct sq_threshold_params *sq_thresh;
+ struct wmi_snr_threshold_params_cmd cmd;
+ enum wmi_snr_threshold_val new_threshold;
+ u8 upper_snr_threshold, lower_snr_threshold;
+ s16 snr;
+ int ret;
+
+ if (len < sizeof(struct wmi_snr_threshold_event))
+ return -EINVAL;
+
+ reply = (struct wmi_snr_threshold_event *) datap;
+
+ new_threshold = (enum wmi_snr_threshold_val) reply->range;
+ snr = reply->snr;
+
+ sq_thresh = &wmi->sq_threshld[SIGNAL_QUALITY_METRICS_SNR];
+
+ /*
+ * Identify the threshold breached and communicate that to the app.
+ * After that install a new set of thresholds based on the signal
+ * quality reported by the target.
+ */
+ if (new_threshold) {
+ /* Upper threshold breached */
+ if (snr < sq_thresh->upper_threshold[0]) {
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "spurious upper snr threshold event: %d\n",
+ snr);
+ } else if ((snr < sq_thresh->upper_threshold[1]) &&
+ (snr >= sq_thresh->upper_threshold[0])) {
+ new_threshold = WMI_SNR_THRESHOLD1_ABOVE;
+ } else if ((snr < sq_thresh->upper_threshold[2]) &&
+ (snr >= sq_thresh->upper_threshold[1])) {
+ new_threshold = WMI_SNR_THRESHOLD2_ABOVE;
+ } else if ((snr < sq_thresh->upper_threshold[3]) &&
+ (snr >= sq_thresh->upper_threshold[2])) {
+ new_threshold = WMI_SNR_THRESHOLD3_ABOVE;
+ } else if (snr >= sq_thresh->upper_threshold[3]) {
+ new_threshold = WMI_SNR_THRESHOLD4_ABOVE;
+ }
+ } else {
+ /* Lower threshold breached */
+ if (snr > sq_thresh->lower_threshold[0]) {
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "spurious lower snr threshold event: %d\n",
+ sq_thresh->lower_threshold[0]);
+ } else if ((snr > sq_thresh->lower_threshold[1]) &&
+ (snr <= sq_thresh->lower_threshold[0])) {
+ new_threshold = WMI_SNR_THRESHOLD4_BELOW;
+ } else if ((snr > sq_thresh->lower_threshold[2]) &&
+ (snr <= sq_thresh->lower_threshold[1])) {
+ new_threshold = WMI_SNR_THRESHOLD3_BELOW;
+ } else if ((snr > sq_thresh->lower_threshold[3]) &&
+ (snr <= sq_thresh->lower_threshold[2])) {
+ new_threshold = WMI_SNR_THRESHOLD2_BELOW;
+ } else if (snr <= sq_thresh->lower_threshold[3]) {
+ new_threshold = WMI_SNR_THRESHOLD1_BELOW;
+ }
+ }
+
+ /* Calculate and install the next set of thresholds */
+ lower_snr_threshold = ath6kl_wmi_get_lower_threshold(snr, sq_thresh,
+ sq_thresh->lower_threshold_valid_count);
+ upper_snr_threshold = ath6kl_wmi_get_upper_threshold(snr, sq_thresh,
+ sq_thresh->upper_threshold_valid_count);
+
+ /* Issue a wmi command to install the thresholds */
+ cmd.thresh_above1_val = upper_snr_threshold;
+ cmd.thresh_below1_val = lower_snr_threshold;
+ cmd.weight = sq_thresh->weight;
+ cmd.poll_time = cpu_to_le32(sq_thresh->polling_interval);
+
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "snr: %d, threshold: %d, lower: %d, upper: %d\n",
+ snr, new_threshold,
+ lower_snr_threshold, upper_snr_threshold);
+
+ ret = ath6kl_wmi_send_snr_threshold_params(wmi, &cmd);
+ if (ret) {
+ ath6kl_err("unable to configure snr threshold\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int ath6kl_wmi_aplist_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ u16 ap_info_entry_size;
+ struct wmi_aplist_event *ev = (struct wmi_aplist_event *) datap;
+ struct wmi_ap_info_v1 *ap_info_v1;
+ u8 index;
+
+ if (len < sizeof(struct wmi_aplist_event) ||
+ ev->ap_list_ver != APLIST_VER1)
+ return -EINVAL;
+
+ ap_info_entry_size = sizeof(struct wmi_ap_info_v1);
+ ap_info_v1 = (struct wmi_ap_info_v1 *) ev->ap_list;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "number of APs in aplist event: %d\n", ev->num_ap);
+
+ if (len < (int) (sizeof(struct wmi_aplist_event) +
+ (ev->num_ap - 1) * ap_info_entry_size))
+ return -EINVAL;
+
+ /* AP list version 1 contents */
+ for (index = 0; index < ev->num_ap; index++) {
+ ath6kl_dbg(ATH6KL_DBG_WMI, "AP#%d BSSID %pM Channel %d\n",
+ index, ap_info_v1->bssid, ap_info_v1->channel);
+ ap_info_v1++;
+ }
+
+ return 0;
+}
+
+int ath6kl_wmi_cmd_send(struct wmi *wmi, struct sk_buff *skb,
+ enum wmi_cmd_id cmd_id, enum wmi_sync_flag sync_flag)
+{
+ struct wmi_cmd_hdr *cmd_hdr;
+ enum htc_endpoint_id ep_id = wmi->ep_id;
+ int ret;
+
+ if (WARN_ON(skb == NULL))
+ return -EINVAL;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "wmi tx id %d len %d flag %d\n",
+ cmd_id, skb->len, sync_flag);
+ ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi tx ",
+ skb->data, skb->len);
+
+ if (sync_flag >= END_WMIFLAG) {
+ dev_kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ if ((sync_flag == SYNC_BEFORE_WMIFLAG) ||
+ (sync_flag == SYNC_BOTH_WMIFLAG)) {
+ /*
+ * Make sure all data currently queued is transmitted before
+ * the cmd execution. Establish a new sync point.
+ */
+ ath6kl_wmi_sync_point(wmi);
+ }
+
+ skb_push(skb, sizeof(struct wmi_cmd_hdr));
+
+ cmd_hdr = (struct wmi_cmd_hdr *) skb->data;
+ cmd_hdr->cmd_id = cpu_to_le16(cmd_id);
+ cmd_hdr->info1 = 0; /* added for virtual interface */
+
+ /* Only for OPT_TX_CMD, use BE endpoint. */
+ if (cmd_id == WMI_OPT_TX_FRAME_CMDID) {
+ ret = ath6kl_wmi_data_hdr_add(wmi, skb, OPT_MSGTYPE,
+ false, false, 0, NULL);
+ if (ret) {
+ dev_kfree_skb(skb);
+ return ret;
+ }
+ ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev, WMM_AC_BE);
+ }
+
+ ath6kl_control_tx(wmi->parent_dev, skb, ep_id);
+
+ if ((sync_flag == SYNC_AFTER_WMIFLAG) ||
+ (sync_flag == SYNC_BOTH_WMIFLAG)) {
+ /*
+ * Make sure all new data queued waits for the command to
+ * execute. Establish a new sync point.
+ */
+ ath6kl_wmi_sync_point(wmi);
+ }
+
+ return 0;
+}
+
+int ath6kl_wmi_connect_cmd(struct wmi *wmi, enum network_type nw_type,
+ enum dot11_auth_mode dot11_auth_mode,
+ enum auth_mode auth_mode,
+ enum crypto_type pairwise_crypto,
+ u8 pairwise_crypto_len,
+ enum crypto_type group_crypto,
+ u8 group_crypto_len, int ssid_len, u8 *ssid,
+ u8 *bssid, u16 channel, u32 ctrl_flags)
+{
+ struct sk_buff *skb;
+ struct wmi_connect_cmd *cc;
+ int ret;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "wmi connect bssid %pM freq %d flags 0x%x ssid_len %d "
+ "type %d dot11_auth %d auth %d pairwise %d group %d\n",
+ bssid, channel, ctrl_flags, ssid_len, nw_type,
+ dot11_auth_mode, auth_mode, pairwise_crypto, group_crypto);
+ ath6kl_dbg_dump(ATH6KL_DBG_WMI, NULL, "ssid ", ssid, ssid_len);
+
+ wmi->traffic_class = 100;
+
+ if ((pairwise_crypto == NONE_CRYPT) && (group_crypto != NONE_CRYPT))
+ return -EINVAL;
+
+ if ((pairwise_crypto != NONE_CRYPT) && (group_crypto == NONE_CRYPT))
+ return -EINVAL;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_connect_cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cc = (struct wmi_connect_cmd *) skb->data;
+
+ if (ssid_len)
+ memcpy(cc->ssid, ssid, ssid_len);
+
+ cc->ssid_len = ssid_len;
+ cc->nw_type = nw_type;
+ cc->dot11_auth_mode = dot11_auth_mode;
+ cc->auth_mode = auth_mode;
+ cc->prwise_crypto_type = pairwise_crypto;
+ cc->prwise_crypto_len = pairwise_crypto_len;
+ cc->grp_crypto_type = group_crypto;
+ cc->grp_crypto_len = group_crypto_len;
+ cc->ch = cpu_to_le16(channel);
+ cc->ctrl_flags = cpu_to_le32(ctrl_flags);
+
+ if (bssid != NULL)
+ memcpy(cc->bssid, bssid, ETH_ALEN);
+
+ wmi->pair_crypto_type = pairwise_crypto;
+ wmi->grp_crypto_type = group_crypto;
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_CONNECT_CMDID, NO_SYNC_WMIFLAG);
+
+ return ret;
+}
+
+int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 *bssid, u16 channel)
+{
+ struct sk_buff *skb;
+ struct wmi_reconnect_cmd *cc;
+ int ret;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "wmi reconnect bssid %pM freq %d\n",
+ bssid, channel);
+
+ wmi->traffic_class = 100;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_reconnect_cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cc = (struct wmi_reconnect_cmd *) skb->data;
+ cc->channel = cpu_to_le16(channel);
+
+ if (bssid != NULL)
+ memcpy(cc->bssid, bssid, ETH_ALEN);
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_RECONNECT_CMDID,
+ NO_SYNC_WMIFLAG);
+
+ return ret;
+}
+
+int ath6kl_wmi_disconnect_cmd(struct wmi *wmi)
+{
+ int ret;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "wmi disconnect\n");
+
+ wmi->traffic_class = 100;
+
+ /* Disconnect command does not need to do a SYNC before. */
+ ret = ath6kl_wmi_simple_cmd(wmi, WMI_DISCONNECT_CMDID);
+
+ return ret;
+}
+
+int ath6kl_wmi_startscan_cmd(struct wmi *wmi, enum wmi_scan_type scan_type,
+ u32 force_fgscan, u32 is_legacy,
+ u32 home_dwell_time, u32 force_scan_interval,
+ s8 num_chan, u16 *ch_list)
+{
+ struct sk_buff *skb;
+ struct wmi_start_scan_cmd *sc;
+ s8 size;
+ int i, ret;
+
+ size = sizeof(struct wmi_start_scan_cmd);
+
+ if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN))
+ return -EINVAL;
+
+ if (num_chan > WMI_MAX_CHANNELS)
+ return -EINVAL;
+
+ if (num_chan)
+ size += sizeof(u16) * (num_chan - 1);
+
+ skb = ath6kl_wmi_get_new_buf(size);
+ if (!skb)
+ return -ENOMEM;
+
+ sc = (struct wmi_start_scan_cmd *) skb->data;
+ sc->scan_type = scan_type;
+ sc->force_fg_scan = cpu_to_le32(force_fgscan);
+ sc->is_legacy = cpu_to_le32(is_legacy);
+ sc->home_dwell_time = cpu_to_le32(home_dwell_time);
+ sc->force_scan_intvl = cpu_to_le32(force_scan_interval);
+ sc->num_ch = num_chan;
+
+ for (i = 0; i < num_chan; i++)
+ sc->ch_list[i] = cpu_to_le16(ch_list[i]);
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_START_SCAN_CMDID,
+ NO_SYNC_WMIFLAG);
+
+ return ret;
+}
+
+int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u16 fg_start_sec,
+ u16 fg_end_sec, u16 bg_sec,
+ u16 minact_chdw_msec, u16 maxact_chdw_msec,
+ u16 pas_chdw_msec, u8 short_scan_ratio,
+ u8 scan_ctrl_flag, u32 max_dfsch_act_time,
+ u16 maxact_scan_per_ssid)
+{
+ struct sk_buff *skb;
+ struct wmi_scan_params_cmd *sc;
+ int ret;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*sc));
+ if (!skb)
+ return -ENOMEM;
+
+ sc = (struct wmi_scan_params_cmd *) skb->data;
+ sc->fg_start_period = cpu_to_le16(fg_start_sec);
+ sc->fg_end_period = cpu_to_le16(fg_end_sec);
+ sc->bg_period = cpu_to_le16(bg_sec);
+ sc->minact_chdwell_time = cpu_to_le16(minact_chdw_msec);
+ sc->maxact_chdwell_time = cpu_to_le16(maxact_chdw_msec);
+ sc->pas_chdwell_time = cpu_to_le16(pas_chdw_msec);
+ sc->short_scan_ratio = short_scan_ratio;
+ sc->scan_ctrl_flags = scan_ctrl_flag;
+ sc->max_dfsch_act_time = cpu_to_le32(max_dfsch_act_time);
+ sc->maxact_scan_per_ssid = cpu_to_le16(maxact_scan_per_ssid);
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_SCAN_PARAMS_CMDID,
+ NO_SYNC_WMIFLAG);
+ return ret;
+}
+
+int ath6kl_wmi_bssfilter_cmd(struct wmi *wmi, u8 filter, u32 ie_mask)
+{
+ struct sk_buff *skb;
+ struct wmi_bss_filter_cmd *cmd;
+ int ret;
+
+ if (filter >= LAST_BSS_FILTER)
+ return -EINVAL;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_bss_filter_cmd *) skb->data;
+ cmd->bss_filter = filter;
+ cmd->ie_mask = cpu_to_le32(ie_mask);
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_BSS_FILTER_CMDID,
+ NO_SYNC_WMIFLAG);
+ return ret;
+}
+
+int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 index, u8 flag,
+ u8 ssid_len, u8 *ssid)
+{
+ struct sk_buff *skb;
+ struct wmi_probed_ssid_cmd *cmd;
+ int ret;
+
+ if (index > MAX_PROBED_SSID_INDEX)
+ return -EINVAL;
+
+ if (ssid_len > sizeof(cmd->ssid))
+ return -EINVAL;
+
+ if ((flag & (DISABLE_SSID_FLAG | ANY_SSID_FLAG)) && (ssid_len > 0))
+ return -EINVAL;
+
+ if ((flag & SPECIFIC_SSID_FLAG) && !ssid_len)
+ return -EINVAL;
+
+ if (flag & SPECIFIC_SSID_FLAG)
+ wmi->is_probe_ssid = true;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_probed_ssid_cmd *) skb->data;
+ cmd->entry_index = index;
+ cmd->flag = flag;
+ cmd->ssid_len = ssid_len;
+ memcpy(cmd->ssid, ssid, ssid_len);
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_PROBED_SSID_CMDID,
+ NO_SYNC_WMIFLAG);
+ return ret;
+}
+
+int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u16 listen_interval,
+ u16 listen_beacons)
+{
+ struct sk_buff *skb;
+ struct wmi_listen_int_cmd *cmd;
+ int ret;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_listen_int_cmd *) skb->data;
+ cmd->listen_intvl = cpu_to_le16(listen_interval);
+ cmd->num_beacons = cpu_to_le16(listen_beacons);
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_LISTEN_INT_CMDID,
+ NO_SYNC_WMIFLAG);
+ return ret;
+}
+
+int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 pwr_mode)
+{
+ struct sk_buff *skb;
+ struct wmi_power_mode_cmd *cmd;
+ int ret;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_power_mode_cmd *) skb->data;
+ cmd->pwr_mode = pwr_mode;
+ wmi->pwr_mode = pwr_mode;
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_POWER_MODE_CMDID,
+ NO_SYNC_WMIFLAG);
+ return ret;
+}
+
+int ath6kl_wmi_pmparams_cmd(struct wmi *wmi, u16 idle_period,
+ u16 ps_poll_num, u16 dtim_policy,
+ u16 tx_wakeup_policy, u16 num_tx_to_wakeup,
+ u16 ps_fail_event_policy)
+{
+ struct sk_buff *skb;
+ struct wmi_power_params_cmd *pm;
+ int ret;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*pm));
+ if (!skb)
+ return -ENOMEM;
+
+ pm = (struct wmi_power_params_cmd *)skb->data;
+ pm->idle_period = cpu_to_le16(idle_period);
+ pm->pspoll_number = cpu_to_le16(ps_poll_num);
+ pm->dtim_policy = cpu_to_le16(dtim_policy);
+ pm->tx_wakeup_policy = cpu_to_le16(tx_wakeup_policy);
+ pm->num_tx_to_wakeup = cpu_to_le16(num_tx_to_wakeup);
+ pm->ps_fail_event_policy = cpu_to_le16(ps_fail_event_policy);
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_POWER_PARAMS_CMDID,
+ NO_SYNC_WMIFLAG);
+ return ret;
+}
+
+int ath6kl_wmi_disctimeout_cmd(struct wmi *wmi, u8 timeout)
+{
+ struct sk_buff *skb;
+ struct wmi_disc_timeout_cmd *cmd;
+ int ret;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_disc_timeout_cmd *) skb->data;
+ cmd->discon_timeout = timeout;
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_DISC_TIMEOUT_CMDID,
+ NO_SYNC_WMIFLAG);
+ return ret;
+}
+
+int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 key_index,
+ enum crypto_type key_type,
+ u8 key_usage, u8 key_len,
+ u8 *key_rsc, u8 *key_material,
+ u8 key_op_ctrl, u8 *mac_addr,
+ enum wmi_sync_flag sync_flag)
+{
+ struct sk_buff *skb;
+ struct wmi_add_cipher_key_cmd *cmd;
+ int ret;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "addkey cmd: key_index=%u key_type=%d "
+ "key_usage=%d key_len=%d key_op_ctrl=%d\n",
+ key_index, key_type, key_usage, key_len, key_op_ctrl);
+
+ if ((key_index > WMI_MAX_KEY_INDEX) || (key_len > WMI_MAX_KEY_LEN) ||
+ (key_material == NULL))
+ return -EINVAL;
+
+ if ((WEP_CRYPT != key_type) && (NULL == key_rsc))
+ return -EINVAL;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_add_cipher_key_cmd *) skb->data;
+ cmd->key_index = key_index;
+ cmd->key_type = key_type;
+ cmd->key_usage = key_usage;
+ cmd->key_len = key_len;
+ memcpy(cmd->key, key_material, key_len);
+
+ if (key_rsc != NULL)
+ memcpy(cmd->key_rsc, key_rsc, sizeof(cmd->key_rsc));
+
+ cmd->key_op_ctrl = key_op_ctrl;
+
+ if (mac_addr)
+ memcpy(cmd->key_mac_addr, mac_addr, ETH_ALEN);
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_ADD_CIPHER_KEY_CMDID,
+ sync_flag);
+
+ return ret;
+}
+
+int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 *krk)
+{
+ struct sk_buff *skb;
+ struct wmi_add_krk_cmd *cmd;
+ int ret;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_add_krk_cmd *) skb->data;
+ memcpy(cmd->krk, krk, WMI_KRK_LEN);
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_ADD_KRK_CMDID, NO_SYNC_WMIFLAG);
+
+ return ret;
+}
+
+int ath6kl_wmi_deletekey_cmd(struct wmi *wmi, u8 key_index)
+{
+ struct sk_buff *skb;
+ struct wmi_delete_cipher_key_cmd *cmd;
+ int ret;
+
+ if (key_index > WMI_MAX_KEY_INDEX)
+ return -EINVAL;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_delete_cipher_key_cmd *) skb->data;
+ cmd->key_index = key_index;
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_DELETE_CIPHER_KEY_CMDID,
+ NO_SYNC_WMIFLAG);
+
+ return ret;
+}
+
+int ath6kl_wmi_setpmkid_cmd(struct wmi *wmi, const u8 *bssid,
+ const u8 *pmkid, bool set)
+{
+ struct sk_buff *skb;
+ struct wmi_setpmkid_cmd *cmd;
+ int ret;
+
+ if (bssid == NULL)
+ return -EINVAL;
+
+ if (set && pmkid == NULL)
+ return -EINVAL;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_setpmkid_cmd *) skb->data;
+ memcpy(cmd->bssid, bssid, ETH_ALEN);
+ if (set) {
+ memcpy(cmd->pmkid, pmkid, sizeof(cmd->pmkid));
+ cmd->enable = PMKID_ENABLE;
+ } else {
+ memset(cmd->pmkid, 0, sizeof(cmd->pmkid));
+ cmd->enable = PMKID_DISABLE;
+ }
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_PMKID_CMDID,
+ NO_SYNC_WMIFLAG);
+
+ return ret;
+}
+
+static int ath6kl_wmi_data_sync_send(struct wmi *wmi, struct sk_buff *skb,
+ enum htc_endpoint_id ep_id)
+{
+ struct wmi_data_hdr *data_hdr;
+ int ret;
+
+ if (WARN_ON(skb == NULL || ep_id == wmi->ep_id))
+ return -EINVAL;
+
+ skb_push(skb, sizeof(struct wmi_data_hdr));
+
+ data_hdr = (struct wmi_data_hdr *) skb->data;
+ data_hdr->info = SYNC_MSGTYPE << WMI_DATA_HDR_MSG_TYPE_SHIFT;
+ data_hdr->info3 = 0;
+
+ ret = ath6kl_control_tx(wmi->parent_dev, skb, ep_id);
+
+ return ret;
+}
+
+static int ath6kl_wmi_sync_point(struct wmi *wmi)
+{
+ struct sk_buff *skb;
+ struct wmi_sync_cmd *cmd;
+ struct wmi_data_sync_bufs data_sync_bufs[WMM_NUM_AC];
+ enum htc_endpoint_id ep_id;
+ u8 index, num_pri_streams = 0;
+ int ret = 0;
+
+ memset(data_sync_bufs, 0, sizeof(data_sync_bufs));
+
+ spin_lock_bh(&wmi->lock);
+
+ for (index = 0; index < WMM_NUM_AC; index++) {
+ if (wmi->fat_pipe_exist & (1 << index)) {
+ num_pri_streams++;
+ data_sync_bufs[num_pri_streams - 1].traffic_class =
+ index;
+ }
+ }
+
+ spin_unlock_bh(&wmi->lock);
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb) {
+ ret = -ENOMEM;
+ goto free_skb;
+ }
+
+ cmd = (struct wmi_sync_cmd *) skb->data;
+
+ /*
+ * In the SYNC cmd sent on the control Ep, send a bitmap
+ * of the data eps on which the Data Sync will be sent
+ */
+ cmd->data_sync_map = wmi->fat_pipe_exist;
+
+ for (index = 0; index < num_pri_streams; index++) {
+ data_sync_bufs[index].skb = ath6kl_buf_alloc(0);
+ if (data_sync_bufs[index].skb == NULL) {
+ ret = -ENOMEM;
+ break;
+ }
+ }
+
+ /*
+ * If buffer allocation for any of the dataSync fails,
+ * then do not send the Synchronize cmd on the control ep
+ */
+ if (ret)
+ goto free_skb;
+
+ /*
+ * Send sync cmd followed by sync data messages on all
+ * endpoints being used
+ */
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SYNCHRONIZE_CMDID,
+ NO_SYNC_WMIFLAG);
+
+ if (ret)
+ goto free_skb;
+
+ /* cmd buffer sent, we no longer own it */
+ skb = NULL;
+
+ for (index = 0; index < num_pri_streams; index++) {
+
+ if (WARN_ON(!data_sync_bufs[index].skb))
+ break;
+
+ ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev,
+ data_sync_bufs[index].
+ traffic_class);
+ ret =
+ ath6kl_wmi_data_sync_send(wmi, data_sync_bufs[index].skb,
+ ep_id);
+
+ if (ret)
+ break;
+
+ data_sync_bufs[index].skb = NULL;
+ }
+
+free_skb:
+ /* free up any resources left over (possibly due to an error) */
+ if (skb)
+ dev_kfree_skb(skb);
+
+ for (index = 0; index < num_pri_streams; index++) {
+ if (data_sync_bufs[index].skb != NULL) {
+ dev_kfree_skb((struct sk_buff *)data_sync_bufs[index].
+ skb);
+ }
+ }
+
+ return ret;
+}
+
+int ath6kl_wmi_create_pstream_cmd(struct wmi *wmi,
+ struct wmi_create_pstream_cmd *params)
+{
+ struct sk_buff *skb;
+ struct wmi_create_pstream_cmd *cmd;
+ u8 fatpipe_exist_for_ac = 0;
+ s32 min_phy = 0;
+ s32 nominal_phy = 0;
+ int ret;
+
+ if (!((params->user_pri < 8) &&
+ (params->user_pri <= 0x7) &&
+ (up_to_ac[params->user_pri & 0x7] == params->traffic_class) &&
+ (params->traffic_direc == UPLINK_TRAFFIC ||
+ params->traffic_direc == DNLINK_TRAFFIC ||
+ params->traffic_direc == BIDIR_TRAFFIC) &&
+ (params->traffic_type == TRAFFIC_TYPE_APERIODIC ||
+ params->traffic_type == TRAFFIC_TYPE_PERIODIC) &&
+ (params->voice_psc_cap == DISABLE_FOR_THIS_AC ||
+ params->voice_psc_cap == ENABLE_FOR_THIS_AC ||
+ params->voice_psc_cap == ENABLE_FOR_ALL_AC) &&
+ (params->tsid == WMI_IMPLICIT_PSTREAM ||
+ params->tsid <= WMI_MAX_THINSTREAM))) {
+ return -EINVAL;
+ }
+
+ /*
+ * Check nominal PHY rate is >= minimalPHY,
+ * so that DUT can allow TSRS IE
+ */
+
+ /* Get the physical rate (units of bps) */
+ min_phy = ((le32_to_cpu(params->min_phy_rate) / 1000) / 1000);
+
+ /* Check minimal phy < nominal phy rate */
+ if (params->nominal_phy >= min_phy) {
+ /* unit of 500 kbps */
+ nominal_phy = (params->nominal_phy * 1000) / 500;
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "TSRS IE enabled::MinPhy %x->NominalPhy ===> %x\n",
+ min_phy, nominal_phy);
+
+ params->nominal_phy = nominal_phy;
+ } else {
+ params->nominal_phy = 0;
+ }
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "sending create_pstream_cmd: ac=%d tsid:%d\n",
+ params->traffic_class, params->tsid);
+
+ cmd = (struct wmi_create_pstream_cmd *) skb->data;
+ memcpy(cmd, params, sizeof(*cmd));
+
+ /* This is an implicitly created Fat pipe */
+ if ((u32) params->tsid == (u32) WMI_IMPLICIT_PSTREAM) {
+ spin_lock_bh(&wmi->lock);
+ fatpipe_exist_for_ac = (wmi->fat_pipe_exist &
+ (1 << params->traffic_class));
+ wmi->fat_pipe_exist |= (1 << params->traffic_class);
+ spin_unlock_bh(&wmi->lock);
+ } else {
+ /* explicitly created thin stream within a fat pipe */
+ spin_lock_bh(&wmi->lock);
+ fatpipe_exist_for_ac = (wmi->fat_pipe_exist &
+ (1 << params->traffic_class));
+ wmi->stream_exist_for_ac[params->traffic_class] |=
+ (1 << params->tsid);
+ /*
+ * If a thinstream becomes active, the fat pipe automatically
+ * becomes active
+ */
+ wmi->fat_pipe_exist |= (1 << params->traffic_class);
+ spin_unlock_bh(&wmi->lock);
+ }
+
+ /*
+ * Indicate activty change to driver layer only if this is the
+ * first TSID to get created in this AC explicitly or an implicit
+ * fat pipe is getting created.
+ */
+ if (!fatpipe_exist_for_ac)
+ ath6kl_indicate_tx_activity(wmi->parent_dev,
+ params->traffic_class, true);
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_CREATE_PSTREAM_CMDID,
+ NO_SYNC_WMIFLAG);
+ return ret;
+}
+
+int ath6kl_wmi_delete_pstream_cmd(struct wmi *wmi, u8 traffic_class, u8 tsid)
+{
+ struct sk_buff *skb;
+ struct wmi_delete_pstream_cmd *cmd;
+ u16 active_tsids = 0;
+ int ret;
+
+ if (traffic_class > 3) {
+ ath6kl_err("invalid traffic class: %d\n", traffic_class);
+ return -EINVAL;
+ }
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_delete_pstream_cmd *) skb->data;
+ cmd->traffic_class = traffic_class;
+ cmd->tsid = tsid;
+
+ spin_lock_bh(&wmi->lock);
+ active_tsids = wmi->stream_exist_for_ac[traffic_class];
+ spin_unlock_bh(&wmi->lock);
+
+ if (!(active_tsids & (1 << tsid))) {
+ dev_kfree_skb(skb);
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "TSID %d doesn't exist for traffic class: %d\n",
+ tsid, traffic_class);
+ return -ENODATA;
+ }
+
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "sending delete_pstream_cmd: traffic class: %d tsid=%d\n",
+ traffic_class, tsid);
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_DELETE_PSTREAM_CMDID,
+ SYNC_BEFORE_WMIFLAG);
+
+ spin_lock_bh(&wmi->lock);
+ wmi->stream_exist_for_ac[traffic_class] &= ~(1 << tsid);
+ active_tsids = wmi->stream_exist_for_ac[traffic_class];
+ spin_unlock_bh(&wmi->lock);
+
+ /*
+ * Indicate stream inactivity to driver layer only if all tsids
+ * within this AC are deleted.
+ */
+ if (!active_tsids) {
+ ath6kl_indicate_tx_activity(wmi->parent_dev,
+ traffic_class, false);
+ wmi->fat_pipe_exist &= ~(1 << traffic_class);
+ }
+
+ return ret;
+}
+
+int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd)
+{
+ struct sk_buff *skb;
+ struct wmi_set_ip_cmd *cmd;
+ int ret;
+
+ /* Multicast address are not valid */
+ if ((*((u8 *) &ip_cmd->ips[0]) >= 0xE0) ||
+ (*((u8 *) &ip_cmd->ips[1]) >= 0xE0))
+ return -EINVAL;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_ip_cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_set_ip_cmd *) skb->data;
+ memcpy(cmd, ip_cmd, sizeof(struct wmi_set_ip_cmd));
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_IP_CMDID, NO_SYNC_WMIFLAG);
+ return ret;
+}
+
+static int ath6kl_wmi_get_wow_list_event_rx(struct wmi *wmi, u8 * datap,
+ int len)
+{
+ if (len < sizeof(struct wmi_get_wow_list_reply))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int ath6kl_wmi_cmd_send_xtnd(struct wmi *wmi, struct sk_buff *skb,
+ enum wmix_command_id cmd_id,
+ enum wmi_sync_flag sync_flag)
+{
+ struct wmix_cmd_hdr *cmd_hdr;
+ int ret;
+
+ skb_push(skb, sizeof(struct wmix_cmd_hdr));
+
+ cmd_hdr = (struct wmix_cmd_hdr *) skb->data;
+ cmd_hdr->cmd_id = cpu_to_le32(cmd_id);
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_EXTENSION_CMDID, sync_flag);
+
+ return ret;
+}
+
+int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source)
+{
+ struct sk_buff *skb;
+ struct wmix_hb_challenge_resp_cmd *cmd;
+ int ret;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmix_hb_challenge_resp_cmd *) skb->data;
+ cmd->cookie = cpu_to_le32(cookie);
+ cmd->source = cpu_to_le32(source);
+
+ ret = ath6kl_wmi_cmd_send_xtnd(wmi, skb, WMIX_HB_CHALLENGE_RESP_CMDID,
+ NO_SYNC_WMIFLAG);
+ return ret;
+}
+
+int ath6kl_wmi_config_debug_module_cmd(struct wmi *wmi, u32 valid, u32 config)
+{
+ struct ath6kl_wmix_dbglog_cfg_module_cmd *cmd;
+ struct sk_buff *skb;
+ int ret;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct ath6kl_wmix_dbglog_cfg_module_cmd *) skb->data;
+ cmd->valid = cpu_to_le32(valid);
+ cmd->config = cpu_to_le32(config);
+
+ ret = ath6kl_wmi_cmd_send_xtnd(wmi, skb, WMIX_DBGLOG_CFG_MODULE_CMDID,
+ NO_SYNC_WMIFLAG);
+ return ret;
+}
+
+int ath6kl_wmi_get_stats_cmd(struct wmi *wmi)
+{
+ return ath6kl_wmi_simple_cmd(wmi, WMI_GET_STATISTICS_CMDID);
+}
+
+int ath6kl_wmi_set_tx_pwr_cmd(struct wmi *wmi, u8 dbM)
+{
+ struct sk_buff *skb;
+ struct wmi_set_tx_pwr_cmd *cmd;
+ int ret;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_tx_pwr_cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_set_tx_pwr_cmd *) skb->data;
+ cmd->dbM = dbM;
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_TX_PWR_CMDID,
+ NO_SYNC_WMIFLAG);
+
+ return ret;
+}
+
+int ath6kl_wmi_get_tx_pwr_cmd(struct wmi *wmi)
+{
+ return ath6kl_wmi_simple_cmd(wmi, WMI_GET_TX_PWR_CMDID);
+}
+
+int ath6kl_wmi_set_lpreamble_cmd(struct wmi *wmi, u8 status, u8 preamble_policy)
+{
+ struct sk_buff *skb;
+ struct wmi_set_lpreamble_cmd *cmd;
+ int ret;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_lpreamble_cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_set_lpreamble_cmd *) skb->data;
+ cmd->status = status;
+ cmd->preamble_policy = preamble_policy;
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_LPREAMBLE_CMDID,
+ NO_SYNC_WMIFLAG);
+ return ret;
+}
+
+int ath6kl_wmi_set_rts_cmd(struct wmi *wmi, u16 threshold)
+{
+ struct sk_buff *skb;
+ struct wmi_set_rts_cmd *cmd;
+ int ret;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_rts_cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_set_rts_cmd *) skb->data;
+ cmd->threshold = cpu_to_le16(threshold);
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_RTS_CMDID, NO_SYNC_WMIFLAG);
+ return ret;
+}
+
+int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, enum wmi_txop_cfg cfg)
+{
+ struct sk_buff *skb;
+ struct wmi_set_wmm_txop_cmd *cmd;
+ int ret;
+
+ if (!((cfg == WMI_TXOP_DISABLED) || (cfg == WMI_TXOP_ENABLED)))
+ return -EINVAL;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_wmm_txop_cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_set_wmm_txop_cmd *) skb->data;
+ cmd->txop_enable = cfg;
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_WMM_TXOP_CMDID,
+ NO_SYNC_WMIFLAG);
+ return ret;
+}
+
+int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 keep_alive_intvl)
+{
+ struct sk_buff *skb;
+ struct wmi_set_keepalive_cmd *cmd;
+ int ret;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_set_keepalive_cmd *) skb->data;
+ cmd->keep_alive_intvl = keep_alive_intvl;
+ wmi->keep_alive_intvl = keep_alive_intvl;
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_KEEPALIVE_CMDID,
+ NO_SYNC_WMIFLAG);
+ return ret;
+}
+
+int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len)
+{
+ struct sk_buff *skb;
+ int ret;
+
+ skb = ath6kl_wmi_get_new_buf(len);
+ if (!skb)
+ return -ENOMEM;
+
+ memcpy(skb->data, buf, len);
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_TEST_CMDID, NO_SYNC_WMIFLAG);
+
+ return ret;
+}
+
+
+s32 ath6kl_wmi_get_rate(s8 rate_index)
+{
+ if (rate_index == RATE_AUTO)
+ return 0;
+
+ return wmi_rate_tbl[(u32) rate_index][0];
+}
+
+static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap,
+ u32 len)
+{
+ struct wmi_pmkid_list_reply *reply;
+ u32 expected_len;
+
+ if (len < sizeof(struct wmi_pmkid_list_reply))
+ return -EINVAL;
+
+ reply = (struct wmi_pmkid_list_reply *)datap;
+ expected_len = sizeof(reply->num_pmkid) +
+ le32_to_cpu(reply->num_pmkid) * WMI_PMKID_LEN;
+
+ if (len < expected_len)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int ath6kl_wmi_addba_req_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ struct wmi_addba_req_event *cmd = (struct wmi_addba_req_event *) datap;
+
+ aggr_recv_addba_req_evt(wmi->parent_dev, cmd->tid,
+ le16_to_cpu(cmd->st_seq_no), cmd->win_sz);
+
+ return 0;
+}
+
+static int ath6kl_wmi_delba_req_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ struct wmi_delba_event *cmd = (struct wmi_delba_event *) datap;
+
+ aggr_recv_delba_req_evt(wmi->parent_dev, cmd->tid);
+
+ return 0;
+}
+
+/* AP mode functions */
+
+int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, struct wmi_connect_cmd *p)
+{
+ struct sk_buff *skb;
+ struct wmi_connect_cmd *cm;
+ int res;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cm));
+ if (!skb)
+ return -ENOMEM;
+
+ cm = (struct wmi_connect_cmd *) skb->data;
+ memcpy(cm, p, sizeof(*cm));
+
+ res = ath6kl_wmi_cmd_send(wmip, skb, WMI_AP_CONFIG_COMMIT_CMDID,
+ NO_SYNC_WMIFLAG);
+ ath6kl_dbg(ATH6KL_DBG_WMI, "%s: nw_type=%u auth_mode=%u ch=%u "
+ "ctrl_flags=0x%x-> res=%d\n",
+ __func__, p->nw_type, p->auth_mode, le16_to_cpu(p->ch),
+ le32_to_cpu(p->ctrl_flags), res);
+ return res;
+}
+
+int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 cmd, const u8 *mac, u16 reason)
+{
+ struct sk_buff *skb;
+ struct wmi_ap_set_mlme_cmd *cm;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cm));
+ if (!skb)
+ return -ENOMEM;
+
+ cm = (struct wmi_ap_set_mlme_cmd *) skb->data;
+ memcpy(cm->mac, mac, ETH_ALEN);
+ cm->reason = cpu_to_le16(reason);
+ cm->cmd = cmd;
+
+ return ath6kl_wmi_cmd_send(wmip, skb, WMI_AP_SET_MLME_CMDID,
+ NO_SYNC_WMIFLAG);
+}
+
+static int ath6kl_wmi_pspoll_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ struct wmi_pspoll_event *ev;
+
+ if (len < sizeof(struct wmi_pspoll_event))
+ return -EINVAL;
+
+ ev = (struct wmi_pspoll_event *) datap;
+
+ ath6kl_pspoll_event(wmi->parent_dev, le16_to_cpu(ev->aid));
+
+ return 0;
+}
+
+static int ath6kl_wmi_dtimexpiry_event_rx(struct wmi *wmi, u8 *datap, int len)
+{
+ ath6kl_dtimexpiry_event(wmi->parent_dev);
+
+ return 0;
+}
+
+int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u16 aid, bool flag)
+{
+ struct sk_buff *skb;
+ struct wmi_ap_set_pvb_cmd *cmd;
+ int ret;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_ap_set_pvb_cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_ap_set_pvb_cmd *) skb->data;
+ cmd->aid = cpu_to_le16(aid);
+ cmd->rsvd = cpu_to_le16(0);
+ cmd->flag = cpu_to_le32(flag);
+
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_AP_SET_PVB_CMDID,
+ NO_SYNC_WMIFLAG);
+
+ return 0;
+}
+
+int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_ver,
+ bool rx_dot11_hdr, bool defrag_on_host)
+{
+ struct sk_buff *skb;
+ struct wmi_rx_frame_format_cmd *cmd;
+ int ret;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_rx_frame_format_cmd *) skb->data;
+ cmd->dot11_hdr = rx_dot11_hdr ? 1 : 0;
+ cmd->defrag_on_host = defrag_on_host ? 1 : 0;
+ cmd->meta_ver = rx_meta_ver;
+
+ /* Delete the local aggr state, on host */
+ ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_RX_FRAME_FORMAT_CMDID,
+ NO_SYNC_WMIFLAG);
+
+ return ret;
+}
+
+int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 mgmt_frm_type, const u8 *ie,
+ u8 ie_len)
+{
+ struct sk_buff *skb;
+ struct wmi_set_appie_cmd *p;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*p) + ie_len);
+ if (!skb)
+ return -ENOMEM;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "set_appie_cmd: mgmt_frm_type=%u "
+ "ie_len=%u\n", mgmt_frm_type, ie_len);
+ p = (struct wmi_set_appie_cmd *) skb->data;
+ p->mgmt_frm_type = mgmt_frm_type;
+ p->ie_len = ie_len;
+ memcpy(p->ie_info, ie, ie_len);
+ return ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_APPIE_CMDID,
+ NO_SYNC_WMIFLAG);
+}
+
+int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable)
+{
+ struct sk_buff *skb;
+ struct wmi_disable_11b_rates_cmd *cmd;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "disable_11b_rates_cmd: disable=%u\n",
+ disable);
+ cmd = (struct wmi_disable_11b_rates_cmd *) skb->data;
+ cmd->disable = disable ? 1 : 0;
+
+ return ath6kl_wmi_cmd_send(wmi, skb, WMI_DISABLE_11B_RATES_CMDID,
+ NO_SYNC_WMIFLAG);
+}
+
+int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u32 freq, u32 dur)
+{
+ struct sk_buff *skb;
+ struct wmi_remain_on_chnl_cmd *p;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*p));
+ if (!skb)
+ return -ENOMEM;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl_cmd: freq=%u dur=%u\n",
+ freq, dur);
+ p = (struct wmi_remain_on_chnl_cmd *) skb->data;
+ p->freq = cpu_to_le32(freq);
+ p->duration = cpu_to_le32(dur);
+ return ath6kl_wmi_cmd_send(wmi, skb, WMI_REMAIN_ON_CHNL_CMDID,
+ NO_SYNC_WMIFLAG);
+}
+
+int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u32 id, u32 freq, u32 wait,
+ const u8 *data, u16 data_len)
+{
+ struct sk_buff *skb;
+ struct wmi_send_action_cmd *p;
+ u8 *buf;
+
+ if (wait)
+ return -EINVAL; /* Offload for wait not supported */
+
+ buf = kmalloc(data_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len);
+ if (!skb) {
+ kfree(buf);
+ return -ENOMEM;
+ }
+
+ kfree(wmi->last_mgmt_tx_frame);
+ wmi->last_mgmt_tx_frame = buf;
+ wmi->last_mgmt_tx_frame_len = data_len;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "send_action_cmd: id=%u freq=%u wait=%u "
+ "len=%u\n", id, freq, wait, data_len);
+ p = (struct wmi_send_action_cmd *) skb->data;
+ p->id = cpu_to_le32(id);
+ p->freq = cpu_to_le32(freq);
+ p->wait = cpu_to_le32(wait);
+ p->len = cpu_to_le16(data_len);
+ memcpy(p->data, data, data_len);
+ return ath6kl_wmi_cmd_send(wmi, skb, WMI_SEND_ACTION_CMDID,
+ NO_SYNC_WMIFLAG);
+}
+
+int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u32 freq,
+ const u8 *dst,
+ const u8 *data, u16 data_len)
+{
+ struct sk_buff *skb;
+ struct wmi_p2p_probe_response_cmd *p;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len);
+ if (!skb)
+ return -ENOMEM;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "send_probe_response_cmd: freq=%u dst=%pM "
+ "len=%u\n", freq, dst, data_len);
+ p = (struct wmi_p2p_probe_response_cmd *) skb->data;
+ p->freq = cpu_to_le32(freq);
+ memcpy(p->destination_addr, dst, ETH_ALEN);
+ p->len = cpu_to_le16(data_len);
+ memcpy(p->data, data, data_len);
+ return ath6kl_wmi_cmd_send(wmi, skb, WMI_SEND_PROBE_RESPONSE_CMDID,
+ NO_SYNC_WMIFLAG);
+}
+
+int ath6kl_wmi_probe_report_req_cmd(struct wmi *wmi, bool enable)
+{
+ struct sk_buff *skb;
+ struct wmi_probe_req_report_cmd *p;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*p));
+ if (!skb)
+ return -ENOMEM;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "probe_report_req_cmd: enable=%u\n",
+ enable);
+ p = (struct wmi_probe_req_report_cmd *) skb->data;
+ p->enable = enable ? 1 : 0;
+ return ath6kl_wmi_cmd_send(wmi, skb, WMI_PROBE_REQ_REPORT_CMDID,
+ NO_SYNC_WMIFLAG);
+}
+
+int ath6kl_wmi_info_req_cmd(struct wmi *wmi, u32 info_req_flags)
+{
+ struct sk_buff *skb;
+ struct wmi_get_p2p_info *p;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*p));
+ if (!skb)
+ return -ENOMEM;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "info_req_cmd: flags=%x\n",
+ info_req_flags);
+ p = (struct wmi_get_p2p_info *) skb->data;
+ p->info_req_flags = cpu_to_le32(info_req_flags);
+ return ath6kl_wmi_cmd_send(wmi, skb, WMI_GET_P2P_INFO_CMDID,
+ NO_SYNC_WMIFLAG);
+}
+
+int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi)
+{
+ ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl_cmd\n");
+ return ath6kl_wmi_simple_cmd(wmi, WMI_CANCEL_REMAIN_ON_CHNL_CMDID);
+}
+
+static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)
+{
+ struct wmix_cmd_hdr *cmd;
+ u32 len;
+ u16 id;
+ u8 *datap;
+ int ret = 0;
+
+ if (skb->len < sizeof(struct wmix_cmd_hdr)) {
+ ath6kl_err("bad packet 1\n");
+ wmi->stat.cmd_len_err++;
+ return -EINVAL;
+ }
+
+ cmd = (struct wmix_cmd_hdr *) skb->data;
+ id = le32_to_cpu(cmd->cmd_id);
+
+ skb_pull(skb, sizeof(struct wmix_cmd_hdr));
+
+ datap = skb->data;
+ len = skb->len;
+
+ switch (id) {
+ case WMIX_HB_CHALLENGE_RESP_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event hb challenge resp\n");
+ break;
+ case WMIX_DBGLOG_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event dbglog len %d\n", len);
+ ath6kl_debug_fwlog_event(wmi->parent_dev, datap, len);
+ break;
+ default:
+ ath6kl_warn("unknown cmd id 0x%x\n", id);
+ wmi->stat.cmd_id_err++;
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/* Control Path */
+int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
+{
+ struct wmi_cmd_hdr *cmd;
+ u32 len;
+ u16 id;
+ u8 *datap;
+ int ret = 0;
+
+ if (WARN_ON(skb == NULL))
+ return -EINVAL;
+
+ if (skb->len < sizeof(struct wmi_cmd_hdr)) {
+ ath6kl_err("bad packet 1\n");
+ dev_kfree_skb(skb);
+ wmi->stat.cmd_len_err++;
+ return -EINVAL;
+ }
+
+ cmd = (struct wmi_cmd_hdr *) skb->data;
+ id = le16_to_cpu(cmd->cmd_id);
+
+ skb_pull(skb, sizeof(struct wmi_cmd_hdr));
+
+ datap = skb->data;
+ len = skb->len;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "wmi rx id %d len %d\n", id, len);
+ ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi rx ",
+ datap, len);
+
+ switch (id) {
+ case WMI_GET_BITRATE_CMDID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_BITRATE_CMDID\n");
+ ret = ath6kl_wmi_bitrate_reply_rx(wmi, datap, len);
+ break;
+ case WMI_GET_CHANNEL_LIST_CMDID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_CHANNEL_LIST_CMDID\n");
+ ret = ath6kl_wmi_ch_list_reply_rx(wmi, datap, len);
+ break;
+ case WMI_GET_TX_PWR_CMDID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_TX_PWR_CMDID\n");
+ ret = ath6kl_wmi_tx_pwr_reply_rx(wmi, datap, len);
+ break;
+ case WMI_READY_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_READY_EVENTID\n");
+ ret = ath6kl_wmi_ready_event_rx(wmi, datap, len);
+ break;
+ case WMI_CONNECT_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CONNECT_EVENTID\n");
+ ret = ath6kl_wmi_connect_event_rx(wmi, datap, len);
+ break;
+ case WMI_DISCONNECT_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DISCONNECT_EVENTID\n");
+ ret = ath6kl_wmi_disconnect_event_rx(wmi, datap, len);
+ break;
+ case WMI_PEER_NODE_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PEER_NODE_EVENTID\n");
+ ret = ath6kl_wmi_peer_node_event_rx(wmi, datap, len);
+ break;
+ case WMI_TKIP_MICERR_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TKIP_MICERR_EVENTID\n");
+ ret = ath6kl_wmi_tkip_micerr_event_rx(wmi, datap, len);
+ break;
+ case WMI_BSSINFO_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n");
+ ret = ath6kl_wmi_bssinfo_event_rx(wmi, datap, len);
+ break;
+ case WMI_REGDOMAIN_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REGDOMAIN_EVENTID\n");
+ ath6kl_wmi_regdomain_event(wmi, datap, len);
+ break;
+ case WMI_PSTREAM_TIMEOUT_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSTREAM_TIMEOUT_EVENTID\n");
+ ret = ath6kl_wmi_pstream_timeout_event_rx(wmi, datap, len);
+ break;
+ case WMI_NEIGHBOR_REPORT_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n");
+ ret = ath6kl_wmi_neighbor_report_event_rx(wmi, datap, len);
+ break;
+ case WMI_SCAN_COMPLETE_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n");
+ ret = ath6kl_wmi_scan_complete_rx(wmi, datap, len);
+ break;
+ case WMI_CMDERROR_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CMDERROR_EVENTID\n");
+ ret = ath6kl_wmi_error_event_rx(wmi, datap, len);
+ break;
+ case WMI_REPORT_STATISTICS_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_STATISTICS_EVENTID\n");
+ ret = ath6kl_wmi_stats_event_rx(wmi, datap, len);
+ break;
+ case WMI_RSSI_THRESHOLD_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RSSI_THRESHOLD_EVENTID\n");
+ ret = ath6kl_wmi_rssi_threshold_event_rx(wmi, datap, len);
+ break;
+ case WMI_ERROR_REPORT_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ERROR_REPORT_EVENTID\n");
+ break;
+ case WMI_OPT_RX_FRAME_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_OPT_RX_FRAME_EVENTID\n");
+ /* this event has been deprecated */
+ break;
+ case WMI_REPORT_ROAM_TBL_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_TBL_EVENTID\n");
+ break;
+ case WMI_EXTENSION_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_EXTENSION_EVENTID\n");
+ ret = ath6kl_wmi_control_rx_xtnd(wmi, skb);
+ break;
+ case WMI_CAC_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CAC_EVENTID\n");
+ ret = ath6kl_wmi_cac_event_rx(wmi, datap, len);
+ break;
+ case WMI_CHANNEL_CHANGE_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CHANNEL_CHANGE_EVENTID\n");
+ break;
+ case WMI_REPORT_ROAM_DATA_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_DATA_EVENTID\n");
+ break;
+ case WMI_TEST_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TEST_EVENTID\n");
+ ret = ath6kl_wmi_tcmd_test_report_rx(wmi, datap, len);
+ break;
+ case WMI_GET_FIXRATES_CMDID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_FIXRATES_CMDID\n");
+ ret = ath6kl_wmi_ratemask_reply_rx(wmi, datap, len);
+ break;
+ case WMI_TX_RETRY_ERR_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_RETRY_ERR_EVENTID\n");
+ break;
+ case WMI_SNR_THRESHOLD_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SNR_THRESHOLD_EVENTID\n");
+ ret = ath6kl_wmi_snr_threshold_event_rx(wmi, datap, len);
+ break;
+ case WMI_LQ_THRESHOLD_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_LQ_THRESHOLD_EVENTID\n");
+ break;
+ case WMI_APLIST_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_APLIST_EVENTID\n");
+ ret = ath6kl_wmi_aplist_event_rx(wmi, datap, len);
+ break;
+ case WMI_GET_KEEPALIVE_CMDID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_KEEPALIVE_CMDID\n");
+ ret = ath6kl_wmi_keepalive_reply_rx(wmi, datap, len);
+ break;
+ case WMI_GET_WOW_LIST_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_WOW_LIST_EVENTID\n");
+ ret = ath6kl_wmi_get_wow_list_event_rx(wmi, datap, len);
+ break;
+ case WMI_GET_PMKID_LIST_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_PMKID_LIST_EVENTID\n");
+ ret = ath6kl_wmi_get_pmkid_list_event_rx(wmi, datap, len);
+ break;
+ case WMI_PSPOLL_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSPOLL_EVENTID\n");
+ ret = ath6kl_wmi_pspoll_event_rx(wmi, datap, len);
+ break;
+ case WMI_DTIMEXPIRY_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DTIMEXPIRY_EVENTID\n");
+ ret = ath6kl_wmi_dtimexpiry_event_rx(wmi, datap, len);
+ break;
+ case WMI_SET_PARAMS_REPLY_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SET_PARAMS_REPLY_EVENTID\n");
+ break;
+ case WMI_ADDBA_REQ_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_REQ_EVENTID\n");
+ ret = ath6kl_wmi_addba_req_event_rx(wmi, datap, len);
+ break;
+ case WMI_ADDBA_RESP_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_RESP_EVENTID\n");
+ break;
+ case WMI_DELBA_REQ_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DELBA_REQ_EVENTID\n");
+ ret = ath6kl_wmi_delba_req_event_rx(wmi, datap, len);
+ break;
+ case WMI_REPORT_BTCOEX_CONFIG_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "WMI_REPORT_BTCOEX_CONFIG_EVENTID\n");
+ break;
+ case WMI_REPORT_BTCOEX_STATS_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "WMI_REPORT_BTCOEX_STATS_EVENTID\n");
+ break;
+ case WMI_TX_COMPLETE_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n");
+ ret = ath6kl_wmi_tx_complete_event_rx(datap, len);
+ break;
+ case WMI_REMAIN_ON_CHNL_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n");
+ ret = ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len);
+ break;
+ case WMI_CANCEL_REMAIN_ON_CHNL_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "WMI_CANCEL_REMAIN_ON_CHNL_EVENTID\n");
+ ret = ath6kl_wmi_cancel_remain_on_chnl_event_rx(wmi, datap,
+ len);
+ break;
+ case WMI_TX_STATUS_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n");
+ ret = ath6kl_wmi_tx_status_event_rx(wmi, datap, len);
+ break;
+ case WMI_RX_PROBE_REQ_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n");
+ ret = ath6kl_wmi_rx_probe_req_event_rx(wmi, datap, len);
+ break;
+ case WMI_P2P_CAPABILITIES_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_CAPABILITIES_EVENTID\n");
+ ret = ath6kl_wmi_p2p_capabilities_event_rx(datap, len);
+ break;
+ case WMI_RX_ACTION_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n");
+ ret = ath6kl_wmi_rx_action_event_rx(wmi, datap, len);
+ break;
+ case WMI_P2P_INFO_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_INFO_EVENTID\n");
+ ret = ath6kl_wmi_p2p_info_event_rx(datap, len);
+ break;
+ default:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", id);
+ wmi->stat.cmd_id_err++;
+ ret = -EINVAL;
+ break;
+ }
+
+ dev_kfree_skb(skb);
+
+ return ret;
+}
+
+static void ath6kl_wmi_qos_state_init(struct wmi *wmi)
+{
+ if (!wmi)
+ return;
+
+ spin_lock_bh(&wmi->lock);
+
+ wmi->fat_pipe_exist = 0;
+ memset(wmi->stream_exist_for_ac, 0, sizeof(wmi->stream_exist_for_ac));
+
+ spin_unlock_bh(&wmi->lock);
+}
+
+void *ath6kl_wmi_init(struct ath6kl *dev)
+{
+ struct wmi *wmi;
+
+ wmi = kzalloc(sizeof(struct wmi), GFP_KERNEL);
+ if (!wmi)
+ return NULL;
+
+ spin_lock_init(&wmi->lock);
+
+ wmi->parent_dev = dev;
+
+ ath6kl_wmi_qos_state_init(wmi);
+
+ wmi->pwr_mode = REC_POWER;
+ wmi->phy_mode = WMI_11G_MODE;
+
+ wmi->pair_crypto_type = NONE_CRYPT;
+ wmi->grp_crypto_type = NONE_CRYPT;
+
+ wmi->ht_allowed[A_BAND_24GHZ] = 1;
+ wmi->ht_allowed[A_BAND_5GHZ] = 1;
+
+ return wmi;
+}
+
+void ath6kl_wmi_shutdown(struct wmi *wmi)
+{
+ if (!wmi)
+ return;
+
+ kfree(wmi->last_mgmt_tx_frame);
+ kfree(wmi);
+}
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
new file mode 100644
index 000000000000..f8e644d54aa7
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -0,0 +1,2282 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This file contains the definitions of the WMI protocol specified in the
+ * Wireless Module Interface (WMI). It includes definitions of all the
+ * commands and events. Commands are messages from the host to the WM.
+ * Events and Replies are messages from the WM to the host.
+ */
+
+#ifndef WMI_H
+#define WMI_H
+
+#include <linux/ieee80211.h>
+
+#include "htc.h"
+
+#define HTC_PROTOCOL_VERSION 0x0002
+#define WMI_PROTOCOL_VERSION 0x0002
+#define WMI_CONTROL_MSG_MAX_LEN 256
+#define is_ethertype(type_or_len) ((type_or_len) >= 0x0600)
+
+#define IP_ETHERTYPE 0x0800
+
+#define WMI_IMPLICIT_PSTREAM 0xFF
+#define WMI_MAX_THINSTREAM 15
+
+#define SSID_IE_LEN_INDEX 13
+
+/* Host side link management data structures */
+#define SIG_QUALITY_THRESH_LVLS 6
+#define SIG_QUALITY_UPPER_THRESH_LVLS SIG_QUALITY_THRESH_LVLS
+#define SIG_QUALITY_LOWER_THRESH_LVLS SIG_QUALITY_THRESH_LVLS
+
+#define A_BAND_24GHZ 0
+#define A_BAND_5GHZ 1
+#define A_NUM_BANDS 2
+
+/* in ms */
+#define WMI_IMPLICIT_PSTREAM_INACTIVITY_INT 5000
+
+/*
+ * There are no signed versions of __le16 and __le32, so for a temporary
+ * solution come up with our own version. The idea is from fs/ntfs/types.h.
+ *
+ * Use a_ prefix so that it doesn't conflict if we get proper support to
+ * linux/types.h.
+ */
+typedef __s16 __bitwise a_sle16;
+typedef __s32 __bitwise a_sle32;
+
+static inline a_sle32 a_cpu_to_sle32(s32 val)
+{
+ return (__force a_sle32) cpu_to_le32(val);
+}
+
+static inline s32 a_sle32_to_cpu(a_sle32 val)
+{
+ return le32_to_cpu((__force __le32) val);
+}
+
+static inline a_sle16 a_cpu_to_sle16(s16 val)
+{
+ return (__force a_sle16) cpu_to_le16(val);
+}
+
+static inline s16 a_sle16_to_cpu(a_sle16 val)
+{
+ return le16_to_cpu((__force __le16) val);
+}
+
+struct sq_threshold_params {
+ s16 upper_threshold[SIG_QUALITY_UPPER_THRESH_LVLS];
+ s16 lower_threshold[SIG_QUALITY_LOWER_THRESH_LVLS];
+ u32 upper_threshold_valid_count;
+ u32 lower_threshold_valid_count;
+ u32 polling_interval;
+ u8 weight;
+ u8 last_rssi;
+ u8 last_rssi_poll_event;
+};
+
+struct wmi_stats {
+ u32 cmd_len_err;
+ u32 cmd_id_err;
+};
+
+struct wmi_data_sync_bufs {
+ u8 traffic_class;
+ struct sk_buff *skb;
+};
+
+/* WMM stream classes */
+#define WMM_NUM_AC 4
+#define WMM_AC_BE 0 /* best effort */
+#define WMM_AC_BK 1 /* background */
+#define WMM_AC_VI 2 /* video */
+#define WMM_AC_VO 3 /* voice */
+
+struct wmi {
+ bool ready;
+ u16 stream_exist_for_ac[WMM_NUM_AC];
+ u8 fat_pipe_exist;
+ struct ath6kl *parent_dev;
+ struct wmi_stats stat;
+ u8 pwr_mode;
+ u8 phy_mode;
+ u8 keep_alive_intvl;
+ spinlock_t lock;
+ enum htc_endpoint_id ep_id;
+ struct sq_threshold_params
+ sq_threshld[SIGNAL_QUALITY_METRICS_NUM_MAX];
+ enum crypto_type pair_crypto_type;
+ enum crypto_type grp_crypto_type;
+ bool is_wmm_enabled;
+ u8 ht_allowed[A_NUM_BANDS];
+ u8 traffic_class;
+ bool is_probe_ssid;
+
+ u8 *last_mgmt_tx_frame;
+ size_t last_mgmt_tx_frame_len;
+};
+
+struct host_app_area {
+ u32 wmi_protocol_ver;
+};
+
+enum wmi_msg_type {
+ DATA_MSGTYPE = 0x0,
+ CNTL_MSGTYPE,
+ SYNC_MSGTYPE,
+ OPT_MSGTYPE,
+};
+
+/*
+ * Macros for operating on WMI_DATA_HDR (info) field
+ */
+
+#define WMI_DATA_HDR_MSG_TYPE_MASK 0x03
+#define WMI_DATA_HDR_MSG_TYPE_SHIFT 0
+#define WMI_DATA_HDR_UP_MASK 0x07
+#define WMI_DATA_HDR_UP_SHIFT 2
+
+/* In AP mode, the same bit (b5) is used to indicate Power save state in
+ * the Rx dir and More data bit state in the tx direction.
+ */
+#define WMI_DATA_HDR_PS_MASK 0x1
+#define WMI_DATA_HDR_PS_SHIFT 5
+
+#define WMI_DATA_HDR_MORE_MASK 0x1
+#define WMI_DATA_HDR_MORE_SHIFT 5
+
+enum wmi_data_hdr_data_type {
+ WMI_DATA_HDR_DATA_TYPE_802_3 = 0,
+ WMI_DATA_HDR_DATA_TYPE_802_11,
+
+ /* used to be used for the PAL */
+ WMI_DATA_HDR_DATA_TYPE_ACL,
+};
+
+#define WMI_DATA_HDR_DATA_TYPE_MASK 0x3
+#define WMI_DATA_HDR_DATA_TYPE_SHIFT 6
+
+/* Macros for operating on WMI_DATA_HDR (info2) field */
+#define WMI_DATA_HDR_SEQNO_MASK 0xFFF
+#define WMI_DATA_HDR_SEQNO_SHIFT 0
+
+#define WMI_DATA_HDR_AMSDU_MASK 0x1
+#define WMI_DATA_HDR_AMSDU_SHIFT 12
+
+#define WMI_DATA_HDR_META_MASK 0x7
+#define WMI_DATA_HDR_META_SHIFT 13
+
+struct wmi_data_hdr {
+ s8 rssi;
+
+ /*
+ * usage of 'info' field(8-bit):
+ *
+ * b1:b0 - WMI_MSG_TYPE
+ * b4:b3:b2 - UP(tid)
+ * b5 - Used in AP mode.
+ * More-data in tx dir, PS in rx.
+ * b7:b6 - Dot3 header(0),
+ * Dot11 Header(1),
+ * ACL data(2)
+ */
+ u8 info;
+
+ /*
+ * usage of 'info2' field(16-bit):
+ *
+ * b11:b0 - seq_no
+ * b12 - A-MSDU?
+ * b15:b13 - META_DATA_VERSION 0 - 7
+ */
+ __le16 info2;
+ __le16 info3;
+} __packed;
+
+static inline u8 wmi_data_hdr_get_up(struct wmi_data_hdr *dhdr)
+{
+ return (dhdr->info >> WMI_DATA_HDR_UP_SHIFT) & WMI_DATA_HDR_UP_MASK;
+}
+
+static inline void wmi_data_hdr_set_up(struct wmi_data_hdr *dhdr,
+ u8 usr_pri)
+{
+ dhdr->info &= ~(WMI_DATA_HDR_UP_MASK << WMI_DATA_HDR_UP_SHIFT);
+ dhdr->info |= usr_pri << WMI_DATA_HDR_UP_SHIFT;
+}
+
+static inline u8 wmi_data_hdr_get_dot11(struct wmi_data_hdr *dhdr)
+{
+ u8 data_type;
+
+ data_type = (dhdr->info >> WMI_DATA_HDR_DATA_TYPE_SHIFT) &
+ WMI_DATA_HDR_DATA_TYPE_MASK;
+ return (data_type == WMI_DATA_HDR_DATA_TYPE_802_11);
+}
+
+static inline u16 wmi_data_hdr_get_seqno(struct wmi_data_hdr *dhdr)
+{
+ return (le16_to_cpu(dhdr->info2) >> WMI_DATA_HDR_SEQNO_SHIFT) &
+ WMI_DATA_HDR_SEQNO_MASK;
+}
+
+static inline u8 wmi_data_hdr_is_amsdu(struct wmi_data_hdr *dhdr)
+{
+ return (le16_to_cpu(dhdr->info2) >> WMI_DATA_HDR_AMSDU_SHIFT) &
+ WMI_DATA_HDR_AMSDU_MASK;
+}
+
+static inline u8 wmi_data_hdr_get_meta(struct wmi_data_hdr *dhdr)
+{
+ return (le16_to_cpu(dhdr->info2) >> WMI_DATA_HDR_META_SHIFT) &
+ WMI_DATA_HDR_META_MASK;
+}
+
+/* Tx meta version definitions */
+#define WMI_MAX_TX_META_SZ 12
+#define WMI_META_VERSION_1 0x01
+#define WMI_META_VERSION_2 0x02
+
+struct wmi_tx_meta_v1 {
+ /* packet ID to identify the tx request */
+ u8 pkt_id;
+
+ /* rate policy to be used for the tx of this frame */
+ u8 rate_plcy_id;
+} __packed;
+
+struct wmi_tx_meta_v2 {
+ /*
+ * Offset from start of the WMI header for csum calculation to
+ * begin.
+ */
+ u8 csum_start;
+
+ /* offset from start of WMI header where final csum goes */
+ u8 csum_dest;
+
+ /* no of bytes over which csum is calculated */
+ u8 csum_flags;
+} __packed;
+
+struct wmi_rx_meta_v1 {
+ u8 status;
+
+ /* rate index mapped to rate at which this packet was received. */
+ u8 rix;
+
+ /* rssi of packet */
+ u8 rssi;
+
+ /* rf channel during packet reception */
+ u8 channel;
+
+ __le16 flags;
+} __packed;
+
+struct wmi_rx_meta_v2 {
+ __le16 csum;
+
+ /* bit 0 set -partial csum valid bit 1 set -test mode */
+ u8 csum_flags;
+} __packed;
+
+/* Control Path */
+struct wmi_cmd_hdr {
+ __le16 cmd_id;
+
+ /* info1 - 16 bits
+ * b03:b00 - id
+ * b15:b04 - unused */
+ __le16 info1;
+
+ /* for alignment */
+ __le16 reserved;
+} __packed;
+
+/* List of WMI commands */
+enum wmi_cmd_id {
+ WMI_CONNECT_CMDID = 0x0001,
+ WMI_RECONNECT_CMDID,
+ WMI_DISCONNECT_CMDID,
+ WMI_SYNCHRONIZE_CMDID,
+ WMI_CREATE_PSTREAM_CMDID,
+ WMI_DELETE_PSTREAM_CMDID,
+ WMI_START_SCAN_CMDID,
+ WMI_SET_SCAN_PARAMS_CMDID,
+ WMI_SET_BSS_FILTER_CMDID,
+ WMI_SET_PROBED_SSID_CMDID, /* 10 */
+ WMI_SET_LISTEN_INT_CMDID,
+ WMI_SET_BMISS_TIME_CMDID,
+ WMI_SET_DISC_TIMEOUT_CMDID,
+ WMI_GET_CHANNEL_LIST_CMDID,
+ WMI_SET_BEACON_INT_CMDID,
+ WMI_GET_STATISTICS_CMDID,
+ WMI_SET_CHANNEL_PARAMS_CMDID,
+ WMI_SET_POWER_MODE_CMDID,
+ WMI_SET_IBSS_PM_CAPS_CMDID,
+ WMI_SET_POWER_PARAMS_CMDID, /* 20 */
+ WMI_SET_POWERSAVE_TIMERS_POLICY_CMDID,
+ WMI_ADD_CIPHER_KEY_CMDID,
+ WMI_DELETE_CIPHER_KEY_CMDID,
+ WMI_ADD_KRK_CMDID,
+ WMI_DELETE_KRK_CMDID,
+ WMI_SET_PMKID_CMDID,
+ WMI_SET_TX_PWR_CMDID,
+ WMI_GET_TX_PWR_CMDID,
+ WMI_SET_ASSOC_INFO_CMDID,
+ WMI_ADD_BAD_AP_CMDID, /* 30 */
+ WMI_DELETE_BAD_AP_CMDID,
+ WMI_SET_TKIP_COUNTERMEASURES_CMDID,
+ WMI_RSSI_THRESHOLD_PARAMS_CMDID,
+ WMI_TARGET_ERROR_REPORT_BITMASK_CMDID,
+ WMI_SET_ACCESS_PARAMS_CMDID,
+ WMI_SET_RETRY_LIMITS_CMDID,
+ WMI_SET_OPT_MODE_CMDID,
+ WMI_OPT_TX_FRAME_CMDID,
+ WMI_SET_VOICE_PKT_SIZE_CMDID,
+ WMI_SET_MAX_SP_LEN_CMDID, /* 40 */
+ WMI_SET_ROAM_CTRL_CMDID,
+ WMI_GET_ROAM_TBL_CMDID,
+ WMI_GET_ROAM_DATA_CMDID,
+ WMI_ENABLE_RM_CMDID,
+ WMI_SET_MAX_OFFHOME_DURATION_CMDID,
+ WMI_EXTENSION_CMDID, /* Non-wireless extensions */
+ WMI_SNR_THRESHOLD_PARAMS_CMDID,
+ WMI_LQ_THRESHOLD_PARAMS_CMDID,
+ WMI_SET_LPREAMBLE_CMDID,
+ WMI_SET_RTS_CMDID, /* 50 */
+ WMI_CLR_RSSI_SNR_CMDID,
+ WMI_SET_FIXRATES_CMDID,
+ WMI_GET_FIXRATES_CMDID,
+ WMI_SET_AUTH_MODE_CMDID,
+ WMI_SET_REASSOC_MODE_CMDID,
+ WMI_SET_WMM_CMDID,
+ WMI_SET_WMM_TXOP_CMDID,
+ WMI_TEST_CMDID,
+
+ /* COEX AR6002 only */
+ WMI_SET_BT_STATUS_CMDID,
+ WMI_SET_BT_PARAMS_CMDID, /* 60 */
+
+ WMI_SET_KEEPALIVE_CMDID,
+ WMI_GET_KEEPALIVE_CMDID,
+ WMI_SET_APPIE_CMDID,
+ WMI_GET_APPIE_CMDID,
+ WMI_SET_WSC_STATUS_CMDID,
+
+ /* Wake on Wireless */
+ WMI_SET_HOST_SLEEP_MODE_CMDID,
+ WMI_SET_WOW_MODE_CMDID,
+ WMI_GET_WOW_LIST_CMDID,
+ WMI_ADD_WOW_PATTERN_CMDID,
+ WMI_DEL_WOW_PATTERN_CMDID, /* 70 */
+
+ WMI_SET_FRAMERATES_CMDID,
+ WMI_SET_AP_PS_CMDID,
+ WMI_SET_QOS_SUPP_CMDID,
+
+ /* WMI_THIN_RESERVED_... mark the start and end
+ * values for WMI_THIN_RESERVED command IDs. These
+ * command IDs can be found in wmi_thin.h */
+ WMI_THIN_RESERVED_START = 0x8000,
+ WMI_THIN_RESERVED_END = 0x8fff,
+
+ /* Developer commands starts at 0xF000 */
+ WMI_SET_BITRATE_CMDID = 0xF000,
+ WMI_GET_BITRATE_CMDID,
+ WMI_SET_WHALPARAM_CMDID,
+ WMI_SET_MAC_ADDRESS_CMDID,
+ WMI_SET_AKMP_PARAMS_CMDID,
+ WMI_SET_PMKID_LIST_CMDID,
+ WMI_GET_PMKID_LIST_CMDID,
+ WMI_ABORT_SCAN_CMDID,
+ WMI_SET_TARGET_EVENT_REPORT_CMDID,
+
+ /* Unused */
+ WMI_UNUSED1,
+ WMI_UNUSED2,
+
+ /* AP mode commands */
+ WMI_AP_HIDDEN_SSID_CMDID,
+ WMI_AP_SET_NUM_STA_CMDID,
+ WMI_AP_ACL_POLICY_CMDID,
+ WMI_AP_ACL_MAC_LIST_CMDID,
+ WMI_AP_CONFIG_COMMIT_CMDID,
+ WMI_AP_SET_MLME_CMDID,
+ WMI_AP_SET_PVB_CMDID,
+ WMI_AP_CONN_INACT_CMDID,
+ WMI_AP_PROT_SCAN_TIME_CMDID,
+ WMI_AP_SET_COUNTRY_CMDID,
+ WMI_AP_SET_DTIM_CMDID,
+ WMI_AP_MODE_STAT_CMDID,
+
+ WMI_SET_IP_CMDID,
+ WMI_SET_PARAMS_CMDID,
+ WMI_SET_MCAST_FILTER_CMDID,
+ WMI_DEL_MCAST_FILTER_CMDID,
+
+ WMI_ALLOW_AGGR_CMDID,
+ WMI_ADDBA_REQ_CMDID,
+ WMI_DELBA_REQ_CMDID,
+ WMI_SET_HT_CAP_CMDID,
+ WMI_SET_HT_OP_CMDID,
+ WMI_SET_TX_SELECT_RATES_CMDID,
+ WMI_SET_TX_SGI_PARAM_CMDID,
+ WMI_SET_RATE_POLICY_CMDID,
+
+ WMI_HCI_CMD_CMDID,
+ WMI_RX_FRAME_FORMAT_CMDID,
+ WMI_SET_THIN_MODE_CMDID,
+ WMI_SET_BT_WLAN_CONN_PRECEDENCE_CMDID,
+
+ WMI_AP_SET_11BG_RATESET_CMDID,
+ WMI_SET_PMK_CMDID,
+ WMI_MCAST_FILTER_CMDID,
+
+ /* COEX CMDID AR6003 */
+ WMI_SET_BTCOEX_FE_ANT_CMDID,
+ WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMDID,
+ WMI_SET_BTCOEX_SCO_CONFIG_CMDID,
+ WMI_SET_BTCOEX_A2DP_CONFIG_CMDID,
+ WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMDID,
+ WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG_CMDID,
+ WMI_SET_BTCOEX_DEBUG_CMDID,
+ WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMDID,
+ WMI_GET_BTCOEX_STATS_CMDID,
+ WMI_GET_BTCOEX_CONFIG_CMDID,
+
+ WMI_SET_DFS_ENABLE_CMDID, /* F034 */
+ WMI_SET_DFS_MINRSSITHRESH_CMDID,
+ WMI_SET_DFS_MAXPULSEDUR_CMDID,
+ WMI_DFS_RADAR_DETECTED_CMDID,
+
+ /* P2P commands */
+ WMI_P2P_SET_CONFIG_CMDID, /* F038 */
+ WMI_WPS_SET_CONFIG_CMDID,
+ WMI_SET_REQ_DEV_ATTR_CMDID,
+ WMI_P2P_FIND_CMDID,
+ WMI_P2P_STOP_FIND_CMDID,
+ WMI_P2P_GO_NEG_START_CMDID,
+ WMI_P2P_LISTEN_CMDID,
+
+ WMI_CONFIG_TX_MAC_RULES_CMDID, /* F040 */
+ WMI_SET_PROMISCUOUS_MODE_CMDID,
+ WMI_RX_FRAME_FILTER_CMDID,
+ WMI_SET_CHANNEL_CMDID,
+
+ /* WAC commands */
+ WMI_ENABLE_WAC_CMDID,
+ WMI_WAC_SCAN_REPLY_CMDID,
+ WMI_WAC_CTRL_REQ_CMDID,
+ WMI_SET_DIV_PARAMS_CMDID,
+
+ WMI_GET_PMK_CMDID,
+ WMI_SET_PASSPHRASE_CMDID,
+ WMI_SEND_ASSOC_RES_CMDID,
+ WMI_SET_ASSOC_REQ_RELAY_CMDID,
+
+ /* ACS command, consists of sub-commands */
+ WMI_ACS_CTRL_CMDID,
+ WMI_SET_EXCESS_TX_RETRY_THRES_CMDID,
+ WMI_SET_TBD_TIME_CMDID, /*added for wmiconfig command for TBD */
+
+ /* Pktlog cmds */
+ WMI_PKTLOG_ENABLE_CMDID,
+ WMI_PKTLOG_DISABLE_CMDID,
+
+ /* More P2P Cmds */
+ WMI_P2P_GO_NEG_REQ_RSP_CMDID,
+ WMI_P2P_GRP_INIT_CMDID,
+ WMI_P2P_GRP_FORMATION_DONE_CMDID,
+ WMI_P2P_INVITE_CMDID,
+ WMI_P2P_INVITE_REQ_RSP_CMDID,
+ WMI_P2P_PROV_DISC_REQ_CMDID,
+ WMI_P2P_SET_CMDID,
+
+ WMI_GET_RFKILL_MODE_CMDID,
+ WMI_SET_RFKILL_MODE_CMDID,
+ WMI_AP_SET_APSD_CMDID,
+ WMI_AP_APSD_BUFFERED_TRAFFIC_CMDID,
+
+ WMI_P2P_SDPD_TX_CMDID, /* F05C */
+ WMI_P2P_STOP_SDPD_CMDID,
+ WMI_P2P_CANCEL_CMDID,
+ /* Ultra low power store / recall commands */
+ WMI_STORERECALL_CONFIGURE_CMDID,
+ WMI_STORERECALL_RECALL_CMDID,
+ WMI_STORERECALL_HOST_READY_CMDID,
+ WMI_FORCE_TARGET_ASSERT_CMDID,
+
+ WMI_SET_PROBED_SSID_EX_CMDID,
+ WMI_SET_NETWORK_LIST_OFFLOAD_CMDID,
+ WMI_SET_ARP_NS_OFFLOAD_CMDID,
+ WMI_ADD_WOW_EXT_PATTERN_CMDID,
+ WMI_GTK_OFFLOAD_OP_CMDID,
+ WMI_REMAIN_ON_CHNL_CMDID,
+ WMI_CANCEL_REMAIN_ON_CHNL_CMDID,
+ WMI_SEND_ACTION_CMDID,
+ WMI_PROBE_REQ_REPORT_CMDID,
+ WMI_DISABLE_11B_RATES_CMDID,
+ WMI_SEND_PROBE_RESPONSE_CMDID,
+ WMI_GET_P2P_INFO_CMDID,
+ WMI_AP_JOIN_BSS_CMDID,
+};
+
+enum wmi_mgmt_frame_type {
+ WMI_FRAME_BEACON = 0,
+ WMI_FRAME_PROBE_REQ,
+ WMI_FRAME_PROBE_RESP,
+ WMI_FRAME_ASSOC_REQ,
+ WMI_FRAME_ASSOC_RESP,
+ WMI_NUM_MGMT_FRAME
+};
+
+/* WMI_CONNECT_CMDID */
+enum network_type {
+ INFRA_NETWORK = 0x01,
+ ADHOC_NETWORK = 0x02,
+ ADHOC_CREATOR = 0x04,
+ AP_NETWORK = 0x10,
+};
+
+enum dot11_auth_mode {
+ OPEN_AUTH = 0x01,
+ SHARED_AUTH = 0x02,
+
+ /* different from IEEE_AUTH_MODE definitions */
+ LEAP_AUTH = 0x04,
+};
+
+enum auth_mode {
+ NONE_AUTH = 0x01,
+ WPA_AUTH = 0x02,
+ WPA2_AUTH = 0x04,
+ WPA_PSK_AUTH = 0x08,
+ WPA2_PSK_AUTH = 0x10,
+ WPA_AUTH_CCKM = 0x20,
+ WPA2_AUTH_CCKM = 0x40,
+};
+
+#define WMI_MIN_CRYPTO_TYPE NONE_CRYPT
+#define WMI_MAX_CRYPTO_TYPE (AES_CRYPT + 1)
+
+#define WMI_MIN_KEY_INDEX 0
+#define WMI_MAX_KEY_INDEX 3
+
+#define WMI_MAX_KEY_LEN 32
+
+/*
+ * NB: these values are ordered carefully; there are lots of
+ * of implications in any reordering. In particular beware
+ * that 4 is not used to avoid conflicting with IEEE80211_F_PRIVACY.
+ */
+#define ATH6KL_CIPHER_WEP 0
+#define ATH6KL_CIPHER_TKIP 1
+#define ATH6KL_CIPHER_AES_OCB 2
+#define ATH6KL_CIPHER_AES_CCM 3
+#define ATH6KL_CIPHER_CKIP 5
+#define ATH6KL_CIPHER_CCKM_KRK 6
+#define ATH6KL_CIPHER_NONE 7 /* pseudo value */
+
+/*
+ * 802.11 rate set.
+ */
+#define ATH6KL_RATE_MAXSIZE 15 /* max rates we'll handle */
+
+#define ATH_OUI_TYPE 0x01
+#define WPA_OUI_TYPE 0x01
+#define WMM_PARAM_OUI_SUBTYPE 0x01
+#define WMM_OUI_TYPE 0x02
+#define WSC_OUT_TYPE 0x04
+
+enum wmi_connect_ctrl_flags_bits {
+ CONNECT_ASSOC_POLICY_USER = 0x0001,
+ CONNECT_SEND_REASSOC = 0x0002,
+ CONNECT_IGNORE_WPAx_GROUP_CIPHER = 0x0004,
+ CONNECT_PROFILE_MATCH_DONE = 0x0008,
+ CONNECT_IGNORE_AAC_BEACON = 0x0010,
+ CONNECT_CSA_FOLLOW_BSS = 0x0020,
+ CONNECT_DO_WPA_OFFLOAD = 0x0040,
+ CONNECT_DO_NOT_DEAUTH = 0x0080,
+};
+
+struct wmi_connect_cmd {
+ u8 nw_type;
+ u8 dot11_auth_mode;
+ u8 auth_mode;
+ u8 prwise_crypto_type;
+ u8 prwise_crypto_len;
+ u8 grp_crypto_type;
+ u8 grp_crypto_len;
+ u8 ssid_len;
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ __le16 ch;
+ u8 bssid[ETH_ALEN];
+ __le32 ctrl_flags;
+} __packed;
+
+/* WMI_RECONNECT_CMDID */
+struct wmi_reconnect_cmd {
+ /* channel hint */
+ __le16 channel;
+
+ /* mandatory if set */
+ u8 bssid[ETH_ALEN];
+} __packed;
+
+/* WMI_ADD_CIPHER_KEY_CMDID */
+enum key_usage {
+ PAIRWISE_USAGE = 0x00,
+ GROUP_USAGE = 0x01,
+
+ /* default Tx Key - static WEP only */
+ TX_USAGE = 0x02,
+};
+
+/*
+ * Bit Flag
+ * Bit 0 - Initialise TSC - default is Initialize
+ */
+#define KEY_OP_INIT_TSC 0x01
+#define KEY_OP_INIT_RSC 0x02
+
+/* default initialise the TSC & RSC */
+#define KEY_OP_INIT_VAL 0x03
+#define KEY_OP_VALID_MASK 0x03
+
+struct wmi_add_cipher_key_cmd {
+ u8 key_index;
+ u8 key_type;
+
+ /* enum key_usage */
+ u8 key_usage;
+
+ u8 key_len;
+
+ /* key replay sequence counter */
+ u8 key_rsc[8];
+
+ u8 key[WLAN_MAX_KEY_LEN];
+
+ /* additional key control info */
+ u8 key_op_ctrl;
+
+ u8 key_mac_addr[ETH_ALEN];
+} __packed;
+
+/* WMI_DELETE_CIPHER_KEY_CMDID */
+struct wmi_delete_cipher_key_cmd {
+ u8 key_index;
+} __packed;
+
+#define WMI_KRK_LEN 16
+
+/* WMI_ADD_KRK_CMDID */
+struct wmi_add_krk_cmd {
+ u8 krk[WMI_KRK_LEN];
+} __packed;
+
+/* WMI_SETPMKID_CMDID */
+
+#define WMI_PMKID_LEN 16
+
+enum pmkid_enable_flg {
+ PMKID_DISABLE = 0,
+ PMKID_ENABLE = 1,
+};
+
+struct wmi_setpmkid_cmd {
+ u8 bssid[ETH_ALEN];
+
+ /* enum pmkid_enable_flg */
+ u8 enable;
+
+ u8 pmkid[WMI_PMKID_LEN];
+} __packed;
+
+/* WMI_START_SCAN_CMD */
+enum wmi_scan_type {
+ WMI_LONG_SCAN = 0,
+ WMI_SHORT_SCAN = 1,
+};
+
+struct wmi_start_scan_cmd {
+ __le32 force_fg_scan;
+
+ /* for legacy cisco AP compatibility */
+ __le32 is_legacy;
+
+ /* max duration in the home channel(msec) */
+ __le32 home_dwell_time;
+
+ /* time interval between scans (msec) */
+ __le32 force_scan_intvl;
+
+ /* enum wmi_scan_type */
+ u8 scan_type;
+
+ /* how many channels follow */
+ u8 num_ch;
+
+ /* channels in Mhz */
+ __le16 ch_list[1];
+} __packed;
+
+/* WMI_SET_SCAN_PARAMS_CMDID */
+#define WMI_SHORTSCANRATIO_DEFAULT 3
+
+/*
+ * Warning: scan control flag value of 0xFF is used to disable
+ * all flags in WMI_SCAN_PARAMS_CMD. Do not add any more
+ * flags here
+ */
+enum wmi_scan_ctrl_flags_bits {
+
+ /* set if can scan in the connect cmd */
+ CONNECT_SCAN_CTRL_FLAGS = 0x01,
+
+ /* set if scan for the SSID it is already connected to */
+ SCAN_CONNECTED_CTRL_FLAGS = 0x02,
+
+ /* set if enable active scan */
+ ACTIVE_SCAN_CTRL_FLAGS = 0x04,
+
+ /* set if enable roam scan when bmiss and lowrssi */
+ ROAM_SCAN_CTRL_FLAGS = 0x08,
+
+ /* set if follows customer BSSINFO reporting rule */
+ REPORT_BSSINFO_CTRL_FLAGS = 0x10,
+
+ /* if disabled, target doesn't scan after a disconnect event */
+ ENABLE_AUTO_CTRL_FLAGS = 0x20,
+
+ /*
+ * Scan complete event with canceled status will be generated when
+ * a scan is prempted before it gets completed.
+ */
+ ENABLE_SCAN_ABORT_EVENT = 0x40
+};
+
+#define DEFAULT_SCAN_CTRL_FLAGS \
+ (CONNECT_SCAN_CTRL_FLAGS | \
+ SCAN_CONNECTED_CTRL_FLAGS | \
+ ACTIVE_SCAN_CTRL_FLAGS | \
+ ROAM_SCAN_CTRL_FLAGS | \
+ ENABLE_AUTO_CTRL_FLAGS)
+
+struct wmi_scan_params_cmd {
+ /* sec */
+ __le16 fg_start_period;
+
+ /* sec */
+ __le16 fg_end_period;
+
+ /* sec */
+ __le16 bg_period;
+
+ /* msec */
+ __le16 maxact_chdwell_time;
+
+ /* msec */
+ __le16 pas_chdwell_time;
+
+ /* how many shorts scan for one long */
+ u8 short_scan_ratio;
+
+ u8 scan_ctrl_flags;
+
+ /* msec */
+ __le16 minact_chdwell_time;
+
+ /* max active scans per ssid */
+ __le16 maxact_scan_per_ssid;
+
+ /* msecs */
+ __le32 max_dfsch_act_time;
+} __packed;
+
+/* WMI_SET_BSS_FILTER_CMDID */
+enum wmi_bss_filter {
+ /* no beacons forwarded */
+ NONE_BSS_FILTER = 0x0,
+
+ /* all beacons forwarded */
+ ALL_BSS_FILTER,
+
+ /* only beacons matching profile */
+ PROFILE_FILTER,
+
+ /* all but beacons matching profile */
+ ALL_BUT_PROFILE_FILTER,
+
+ /* only beacons matching current BSS */
+ CURRENT_BSS_FILTER,
+
+ /* all but beacons matching BSS */
+ ALL_BUT_BSS_FILTER,
+
+ /* beacons matching probed ssid */
+ PROBED_SSID_FILTER,
+
+ /* marker only */
+ LAST_BSS_FILTER,
+};
+
+struct wmi_bss_filter_cmd {
+ /* see, enum wmi_bss_filter */
+ u8 bss_filter;
+
+ /* for alignment */
+ u8 reserved1;
+
+ /* for alignment */
+ __le16 reserved2;
+
+ __le32 ie_mask;
+} __packed;
+
+/* WMI_SET_PROBED_SSID_CMDID */
+#define MAX_PROBED_SSID_INDEX 9
+
+enum wmi_ssid_flag {
+ /* disables entry */
+ DISABLE_SSID_FLAG = 0,
+
+ /* probes specified ssid */
+ SPECIFIC_SSID_FLAG = 0x01,
+
+ /* probes for any ssid */
+ ANY_SSID_FLAG = 0x02,
+};
+
+struct wmi_probed_ssid_cmd {
+ /* 0 to MAX_PROBED_SSID_INDEX */
+ u8 entry_index;
+
+ /* see, enum wmi_ssid_flg */
+ u8 flag;
+
+ u8 ssid_len;
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+} __packed;
+
+/*
+ * WMI_SET_LISTEN_INT_CMDID
+ * The Listen interval is between 15 and 3000 TUs
+ */
+struct wmi_listen_int_cmd {
+ __le16 listen_intvl;
+ __le16 num_beacons;
+} __packed;
+
+/* WMI_SET_POWER_MODE_CMDID */
+enum wmi_power_mode {
+ REC_POWER = 0x01,
+ MAX_PERF_POWER,
+};
+
+struct wmi_power_mode_cmd {
+ /* see, enum wmi_power_mode */
+ u8 pwr_mode;
+} __packed;
+
+/*
+ * Policy to determnine whether power save failure event should be sent to
+ * host during scanning
+ */
+enum power_save_fail_event_policy {
+ SEND_POWER_SAVE_FAIL_EVENT_ALWAYS = 1,
+ IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN = 2,
+};
+
+struct wmi_power_params_cmd {
+ /* msec */
+ __le16 idle_period;
+
+ __le16 pspoll_number;
+ __le16 dtim_policy;
+ __le16 tx_wakeup_policy;
+ __le16 num_tx_to_wakeup;
+ __le16 ps_fail_event_policy;
+} __packed;
+
+/* WMI_SET_DISC_TIMEOUT_CMDID */
+struct wmi_disc_timeout_cmd {
+ /* seconds */
+ u8 discon_timeout;
+} __packed;
+
+enum dir_type {
+ UPLINK_TRAFFIC = 0,
+ DNLINK_TRAFFIC = 1,
+ BIDIR_TRAFFIC = 2,
+};
+
+enum voiceps_cap_type {
+ DISABLE_FOR_THIS_AC = 0,
+ ENABLE_FOR_THIS_AC = 1,
+ ENABLE_FOR_ALL_AC = 2,
+};
+
+enum traffic_type {
+ TRAFFIC_TYPE_APERIODIC = 0,
+ TRAFFIC_TYPE_PERIODIC = 1,
+};
+
+/* WMI_SYNCHRONIZE_CMDID */
+struct wmi_sync_cmd {
+ u8 data_sync_map;
+} __packed;
+
+/* WMI_CREATE_PSTREAM_CMDID */
+struct wmi_create_pstream_cmd {
+ /* msec */
+ __le32 min_service_int;
+
+ /* msec */
+ __le32 max_service_int;
+
+ /* msec */
+ __le32 inactivity_int;
+
+ /* msec */
+ __le32 suspension_int;
+
+ __le32 service_start_time;
+
+ /* in bps */
+ __le32 min_data_rate;
+
+ /* in bps */
+ __le32 mean_data_rate;
+
+ /* in bps */
+ __le32 peak_data_rate;
+
+ __le32 max_burst_size;
+ __le32 delay_bound;
+
+ /* in bps */
+ __le32 min_phy_rate;
+
+ __le32 sba;
+ __le32 medium_time;
+
+ /* in octects */
+ __le16 nominal_msdu;
+
+ /* in octects */
+ __le16 max_msdu;
+
+ u8 traffic_class;
+
+ /* see, enum dir_type */
+ u8 traffic_direc;
+
+ u8 rx_queue_num;
+
+ /* see, enum traffic_type */
+ u8 traffic_type;
+
+ /* see, enum voiceps_cap_type */
+ u8 voice_psc_cap;
+ u8 tsid;
+
+ /* 802.1D user priority */
+ u8 user_pri;
+
+ /* nominal phy rate */
+ u8 nominal_phy;
+} __packed;
+
+/* WMI_DELETE_PSTREAM_CMDID */
+struct wmi_delete_pstream_cmd {
+ u8 tx_queue_num;
+ u8 rx_queue_num;
+ u8 traffic_direc;
+ u8 traffic_class;
+ u8 tsid;
+} __packed;
+
+/* WMI_SET_CHANNEL_PARAMS_CMDID */
+enum wmi_phy_mode {
+ WMI_11A_MODE = 0x1,
+ WMI_11G_MODE = 0x2,
+ WMI_11AG_MODE = 0x3,
+ WMI_11B_MODE = 0x4,
+ WMI_11GONLY_MODE = 0x5,
+};
+
+#define WMI_MAX_CHANNELS 32
+
+/*
+ * WMI_RSSI_THRESHOLD_PARAMS_CMDID
+ * Setting the polltime to 0 would disable polling. Threshold values are
+ * in the ascending order, and should agree to:
+ * (lowThreshold_lowerVal < lowThreshold_upperVal < highThreshold_lowerVal
+ * < highThreshold_upperVal)
+ */
+
+struct wmi_rssi_threshold_params_cmd {
+ /* polling time as a factor of LI */
+ __le32 poll_time;
+
+ /* lowest of upper */
+ a_sle16 thresh_above1_val;
+
+ a_sle16 thresh_above2_val;
+ a_sle16 thresh_above3_val;
+ a_sle16 thresh_above4_val;
+ a_sle16 thresh_above5_val;
+
+ /* highest of upper */
+ a_sle16 thresh_above6_val;
+
+ /* lowest of bellow */
+ a_sle16 thresh_below1_val;
+
+ a_sle16 thresh_below2_val;
+ a_sle16 thresh_below3_val;
+ a_sle16 thresh_below4_val;
+ a_sle16 thresh_below5_val;
+
+ /* highest of bellow */
+ a_sle16 thresh_below6_val;
+
+ /* "alpha" */
+ u8 weight;
+
+ u8 reserved[3];
+} __packed;
+
+/*
+ * WMI_SNR_THRESHOLD_PARAMS_CMDID
+ * Setting the polltime to 0 would disable polling.
+ */
+
+struct wmi_snr_threshold_params_cmd {
+ /* polling time as a factor of LI */
+ __le32 poll_time;
+
+ /* "alpha" */
+ u8 weight;
+
+ /* lowest of uppper */
+ u8 thresh_above1_val;
+
+ u8 thresh_above2_val;
+ u8 thresh_above3_val;
+
+ /* highest of upper */
+ u8 thresh_above4_val;
+
+ /* lowest of bellow */
+ u8 thresh_below1_val;
+
+ u8 thresh_below2_val;
+ u8 thresh_below3_val;
+
+ /* highest of bellow */
+ u8 thresh_below4_val;
+
+ u8 reserved[3];
+} __packed;
+
+enum wmi_preamble_policy {
+ WMI_IGNORE_BARKER_IN_ERP = 0,
+ WMI_DONOT_IGNORE_BARKER_IN_ERP
+};
+
+struct wmi_set_lpreamble_cmd {
+ u8 status;
+ u8 preamble_policy;
+} __packed;
+
+struct wmi_set_rts_cmd {
+ __le16 threshold;
+} __packed;
+
+/* WMI_SET_TX_PWR_CMDID */
+struct wmi_set_tx_pwr_cmd {
+ /* in dbM units */
+ u8 dbM;
+} __packed;
+
+struct wmi_tx_pwr_reply {
+ /* in dbM units */
+ u8 dbM;
+} __packed;
+
+struct wmi_report_sleep_state_event {
+ __le32 sleep_state;
+};
+
+enum wmi_report_sleep_status {
+ WMI_REPORT_SLEEP_STATUS_IS_DEEP_SLEEP = 0,
+ WMI_REPORT_SLEEP_STATUS_IS_AWAKE
+};
+enum target_event_report_config {
+ /* default */
+ DISCONN_EVT_IN_RECONN = 0,
+
+ NO_DISCONN_EVT_IN_RECONN
+};
+
+/* Command Replies */
+
+/* WMI_GET_CHANNEL_LIST_CMDID reply */
+struct wmi_channel_list_reply {
+ u8 reserved;
+
+ /* number of channels in reply */
+ u8 num_ch;
+
+ /* channel in Mhz */
+ __le16 ch_list[1];
+} __packed;
+
+/* List of Events (target to host) */
+enum wmi_event_id {
+ WMI_READY_EVENTID = 0x1001,
+ WMI_CONNECT_EVENTID,
+ WMI_DISCONNECT_EVENTID,
+ WMI_BSSINFO_EVENTID,
+ WMI_CMDERROR_EVENTID,
+ WMI_REGDOMAIN_EVENTID,
+ WMI_PSTREAM_TIMEOUT_EVENTID,
+ WMI_NEIGHBOR_REPORT_EVENTID,
+ WMI_TKIP_MICERR_EVENTID,
+ WMI_SCAN_COMPLETE_EVENTID, /* 0x100a */
+ WMI_REPORT_STATISTICS_EVENTID,
+ WMI_RSSI_THRESHOLD_EVENTID,
+ WMI_ERROR_REPORT_EVENTID,
+ WMI_OPT_RX_FRAME_EVENTID,
+ WMI_REPORT_ROAM_TBL_EVENTID,
+ WMI_EXTENSION_EVENTID,
+ WMI_CAC_EVENTID,
+ WMI_SNR_THRESHOLD_EVENTID,
+ WMI_LQ_THRESHOLD_EVENTID,
+ WMI_TX_RETRY_ERR_EVENTID, /* 0x1014 */
+ WMI_REPORT_ROAM_DATA_EVENTID,
+ WMI_TEST_EVENTID,
+ WMI_APLIST_EVENTID,
+ WMI_GET_WOW_LIST_EVENTID,
+ WMI_GET_PMKID_LIST_EVENTID,
+ WMI_CHANNEL_CHANGE_EVENTID,
+ WMI_PEER_NODE_EVENTID,
+ WMI_PSPOLL_EVENTID,
+ WMI_DTIMEXPIRY_EVENTID,
+ WMI_WLAN_VERSION_EVENTID,
+ WMI_SET_PARAMS_REPLY_EVENTID,
+ WMI_ADDBA_REQ_EVENTID, /*0x1020 */
+ WMI_ADDBA_RESP_EVENTID,
+ WMI_DELBA_REQ_EVENTID,
+ WMI_TX_COMPLETE_EVENTID,
+ WMI_HCI_EVENT_EVENTID,
+ WMI_ACL_DATA_EVENTID,
+ WMI_REPORT_SLEEP_STATE_EVENTID,
+ WMI_REPORT_BTCOEX_STATS_EVENTID,
+ WMI_REPORT_BTCOEX_CONFIG_EVENTID,
+ WMI_GET_PMK_EVENTID,
+
+ /* DFS Events */
+ WMI_DFS_HOST_ATTACH_EVENTID,
+ WMI_DFS_HOST_INIT_EVENTID,
+ WMI_DFS_RESET_DELAYLINES_EVENTID,
+ WMI_DFS_RESET_RADARQ_EVENTID,
+ WMI_DFS_RESET_AR_EVENTID,
+ WMI_DFS_RESET_ARQ_EVENTID,
+ WMI_DFS_SET_DUR_MULTIPLIER_EVENTID,
+ WMI_DFS_SET_BANGRADAR_EVENTID,
+ WMI_DFS_SET_DEBUGLEVEL_EVENTID,
+ WMI_DFS_PHYERR_EVENTID,
+
+ /* CCX Evants */
+ WMI_CCX_RM_STATUS_EVENTID,
+
+ /* P2P Events */
+ WMI_P2P_GO_NEG_RESULT_EVENTID,
+
+ WMI_WAC_SCAN_DONE_EVENTID,
+ WMI_WAC_REPORT_BSS_EVENTID,
+ WMI_WAC_START_WPS_EVENTID,
+ WMI_WAC_CTRL_REQ_REPLY_EVENTID,
+
+ WMI_REPORT_WMM_PARAMS_EVENTID,
+ WMI_WAC_REJECT_WPS_EVENTID,
+
+ /* More P2P Events */
+ WMI_P2P_GO_NEG_REQ_EVENTID,
+ WMI_P2P_INVITE_REQ_EVENTID,
+ WMI_P2P_INVITE_RCVD_RESULT_EVENTID,
+ WMI_P2P_INVITE_SENT_RESULT_EVENTID,
+ WMI_P2P_PROV_DISC_RESP_EVENTID,
+ WMI_P2P_PROV_DISC_REQ_EVENTID,
+
+ /* RFKILL Events */
+ WMI_RFKILL_STATE_CHANGE_EVENTID,
+ WMI_RFKILL_GET_MODE_CMD_EVENTID,
+
+ WMI_P2P_START_SDPD_EVENTID,
+ WMI_P2P_SDPD_RX_EVENTID,
+
+ WMI_THIN_RESERVED_START_EVENTID = 0x8000,
+ /* Events in this range are reserved for thinmode */
+ WMI_THIN_RESERVED_END_EVENTID = 0x8fff,
+
+ WMI_SET_CHANNEL_EVENTID,
+ WMI_ASSOC_REQ_EVENTID,
+
+ /* Generic ACS event */
+ WMI_ACS_EVENTID,
+ WMI_STORERECALL_STORE_EVENTID,
+ WMI_WOW_EXT_WAKE_EVENTID,
+ WMI_GTK_OFFLOAD_STATUS_EVENTID,
+ WMI_NETWORK_LIST_OFFLOAD_EVENTID,
+ WMI_REMAIN_ON_CHNL_EVENTID,
+ WMI_CANCEL_REMAIN_ON_CHNL_EVENTID,
+ WMI_TX_STATUS_EVENTID,
+ WMI_RX_PROBE_REQ_EVENTID,
+ WMI_P2P_CAPABILITIES_EVENTID,
+ WMI_RX_ACTION_EVENTID,
+ WMI_P2P_INFO_EVENTID,
+};
+
+struct wmi_ready_event_2 {
+ __le32 sw_version;
+ __le32 abi_version;
+ u8 mac_addr[ETH_ALEN];
+ u8 phy_cap;
+} __packed;
+
+/* Connect Event */
+struct wmi_connect_event {
+ union {
+ struct {
+ __le16 ch;
+ u8 bssid[ETH_ALEN];
+ __le16 listen_intvl;
+ __le16 beacon_intvl;
+ __le32 nw_type;
+ } sta;
+ struct {
+ u8 phymode;
+ u8 aid;
+ u8 mac_addr[ETH_ALEN];
+ u8 auth;
+ u8 keymgmt;
+ __le16 cipher;
+ u8 apsd_info;
+ u8 unused[3];
+ } ap_sta;
+ struct {
+ __le16 ch;
+ u8 bssid[ETH_ALEN];
+ u8 unused[8];
+ } ap_bss;
+ } u;
+ u8 beacon_ie_len;
+ u8 assoc_req_len;
+ u8 assoc_resp_len;
+ u8 assoc_info[1];
+} __packed;
+
+/* Disconnect Event */
+enum wmi_disconnect_reason {
+ NO_NETWORK_AVAIL = 0x01,
+
+ /* bmiss */
+ LOST_LINK = 0x02,
+
+ DISCONNECT_CMD = 0x03,
+ BSS_DISCONNECTED = 0x04,
+ AUTH_FAILED = 0x05,
+ ASSOC_FAILED = 0x06,
+ NO_RESOURCES_AVAIL = 0x07,
+ CSERV_DISCONNECT = 0x08,
+ INVALID_PROFILE = 0x0a,
+ DOT11H_CHANNEL_SWITCH = 0x0b,
+ PROFILE_MISMATCH = 0x0c,
+ CONNECTION_EVICTED = 0x0d,
+ IBSS_MERGE = 0xe,
+};
+
+#define ATH6KL_COUNTRY_RD_SHIFT 16
+
+struct ath6kl_wmi_regdomain {
+ __le32 reg_code;
+};
+
+struct wmi_disconnect_event {
+ /* reason code, see 802.11 spec. */
+ __le16 proto_reason_status;
+
+ /* set if known */
+ u8 bssid[ETH_ALEN];
+
+ /* see WMI_DISCONNECT_REASON */
+ u8 disconn_reason;
+
+ u8 assoc_resp_len;
+ u8 assoc_info[1];
+} __packed;
+
+/*
+ * BSS Info Event.
+ * Mechanism used to inform host of the presence and characteristic of
+ * wireless networks present. Consists of bss info header followed by
+ * the beacon or probe-response frame body. The 802.11 header is no included.
+ */
+enum wmi_bi_ftype {
+ BEACON_FTYPE = 0x1,
+ PROBERESP_FTYPE,
+ ACTION_MGMT_FTYPE,
+ PROBEREQ_FTYPE,
+};
+
+#define DEF_LRSSI_SCAN_PERIOD 5
+#define DEF_LRSSI_ROAM_THRESHOLD 20
+#define DEF_LRSSI_ROAM_FLOOR 60
+#define DEF_SCAN_FOR_ROAM_INTVL 2
+
+enum wmi_roam_ctrl {
+ WMI_FORCE_ROAM = 1,
+ WMI_SET_ROAM_MODE,
+ WMI_SET_HOST_BIAS,
+ WMI_SET_LRSSI_SCAN_PARAMS,
+};
+
+struct bss_bias {
+ u8 bssid[ETH_ALEN];
+ u8 bias;
+} __packed;
+
+struct bss_bias_info {
+ u8 num_bss;
+ struct bss_bias bss_bias[1];
+} __packed;
+
+struct low_rssi_scan_params {
+ __le16 lrssi_scan_period;
+ a_sle16 lrssi_scan_threshold;
+ a_sle16 lrssi_roam_threshold;
+ u8 roam_rssi_floor;
+ u8 reserved[1];
+} __packed;
+
+struct roam_ctrl_cmd {
+ union {
+ u8 bssid[ETH_ALEN];
+ u8 roam_mode;
+ struct bss_bias_info bss;
+ struct low_rssi_scan_params params;
+ } __packed info;
+ u8 roam_ctrl;
+} __packed;
+
+/* BSS INFO HDR version 2.0 */
+struct wmi_bss_info_hdr2 {
+ __le16 ch; /* frequency in MHz */
+
+ /* see, enum wmi_bi_ftype */
+ u8 frame_type;
+
+ u8 snr; /* note: rssi = snr - 95 dBm */
+ u8 bssid[ETH_ALEN];
+ __le16 ie_mask;
+} __packed;
+
+/* Command Error Event */
+enum wmi_error_code {
+ INVALID_PARAM = 0x01,
+ ILLEGAL_STATE = 0x02,
+ INTERNAL_ERROR = 0x03,
+};
+
+struct wmi_cmd_error_event {
+ __le16 cmd_id;
+ u8 err_code;
+} __packed;
+
+struct wmi_pstream_timeout_event {
+ u8 tx_queue_num;
+ u8 rx_queue_num;
+ u8 traffic_direc;
+ u8 traffic_class;
+} __packed;
+
+/*
+ * The WMI_NEIGHBOR_REPORT Event is generated by the target to inform
+ * the host of BSS's it has found that matches the current profile.
+ * It can be used by the host to cache PMKs and/to initiate pre-authentication
+ * if the BSS supports it. The first bssid is always the current associated
+ * BSS.
+ * The bssid and bssFlags information repeats according to the number
+ * or APs reported.
+ */
+enum wmi_bss_flags {
+ WMI_DEFAULT_BSS_FLAGS = 0x00,
+ WMI_PREAUTH_CAPABLE_BSS = 0x01,
+ WMI_PMKID_VALID_BSS = 0x02,
+};
+
+struct wmi_neighbor_info {
+ u8 bssid[ETH_ALEN];
+ u8 bss_flags; /* enum wmi_bss_flags */
+} __packed;
+
+struct wmi_neighbor_report_event {
+ u8 num_neighbors;
+ struct wmi_neighbor_info neighbor[0];
+} __packed;
+
+/* TKIP MIC Error Event */
+struct wmi_tkip_micerr_event {
+ u8 key_id;
+ u8 is_mcast;
+} __packed;
+
+/* WMI_SCAN_COMPLETE_EVENTID */
+struct wmi_scan_complete_event {
+ a_sle32 status;
+} __packed;
+
+#define MAX_OPT_DATA_LEN 1400
+
+/*
+ * Special frame receive Event.
+ * Mechanism used to inform host of the receiption of the special frames.
+ * Consists of special frame info header followed by special frame body.
+ * The 802.11 header is not included.
+ */
+struct wmi_opt_rx_info_hdr {
+ __le16 ch;
+ u8 frame_type;
+ s8 snr;
+ u8 src_addr[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+} __packed;
+
+/* Reporting statistic */
+struct tx_stats {
+ __le32 pkt;
+ __le32 byte;
+ __le32 ucast_pkt;
+ __le32 ucast_byte;
+ __le32 mcast_pkt;
+ __le32 mcast_byte;
+ __le32 bcast_pkt;
+ __le32 bcast_byte;
+ __le32 rts_success_cnt;
+ __le32 pkt_per_ac[4];
+ __le32 err_per_ac[4];
+
+ __le32 err;
+ __le32 fail_cnt;
+ __le32 retry_cnt;
+ __le32 mult_retry_cnt;
+ __le32 rts_fail_cnt;
+ a_sle32 ucast_rate;
+} __packed;
+
+struct rx_stats {
+ __le32 pkt;
+ __le32 byte;
+ __le32 ucast_pkt;
+ __le32 ucast_byte;
+ __le32 mcast_pkt;
+ __le32 mcast_byte;
+ __le32 bcast_pkt;
+ __le32 bcast_byte;
+ __le32 frgment_pkt;
+
+ __le32 err;
+ __le32 crc_err;
+ __le32 key_cache_miss;
+ __le32 decrypt_err;
+ __le32 dupl_frame;
+ a_sle32 ucast_rate;
+} __packed;
+
+struct tkip_ccmp_stats {
+ __le32 tkip_local_mic_fail;
+ __le32 tkip_cnter_measures_invoked;
+ __le32 tkip_replays;
+ __le32 tkip_fmt_err;
+ __le32 ccmp_fmt_err;
+ __le32 ccmp_replays;
+} __packed;
+
+struct pm_stats {
+ __le32 pwr_save_failure_cnt;
+ __le16 stop_tx_failure_cnt;
+ __le16 atim_tx_failure_cnt;
+ __le16 atim_rx_failure_cnt;
+ __le16 bcn_rx_failure_cnt;
+} __packed;
+
+struct cserv_stats {
+ __le32 cs_bmiss_cnt;
+ __le32 cs_low_rssi_cnt;
+ __le16 cs_connect_cnt;
+ __le16 cs_discon_cnt;
+ a_sle16 cs_ave_beacon_rssi;
+ __le16 cs_roam_count;
+ a_sle16 cs_rssi;
+ u8 cs_snr;
+ u8 cs_ave_beacon_snr;
+ u8 cs_last_roam_msec;
+} __packed;
+
+struct wlan_net_stats {
+ struct tx_stats tx;
+ struct rx_stats rx;
+ struct tkip_ccmp_stats tkip_ccmp_stats;
+} __packed;
+
+struct arp_stats {
+ __le32 arp_received;
+ __le32 arp_matched;
+ __le32 arp_replied;
+} __packed;
+
+struct wlan_wow_stats {
+ __le32 wow_pkt_dropped;
+ __le16 wow_evt_discarded;
+ u8 wow_host_pkt_wakeups;
+ u8 wow_host_evt_wakeups;
+} __packed;
+
+struct wmi_target_stats {
+ __le32 lq_val;
+ a_sle32 noise_floor_calib;
+ struct pm_stats pm_stats;
+ struct wlan_net_stats stats;
+ struct wlan_wow_stats wow_stats;
+ struct arp_stats arp_stats;
+ struct cserv_stats cserv_stats;
+} __packed;
+
+/*
+ * WMI_RSSI_THRESHOLD_EVENTID.
+ * Indicate the RSSI events to host. Events are indicated when we breach a
+ * thresold value.
+ */
+enum wmi_rssi_threshold_val {
+ WMI_RSSI_THRESHOLD1_ABOVE = 0,
+ WMI_RSSI_THRESHOLD2_ABOVE,
+ WMI_RSSI_THRESHOLD3_ABOVE,
+ WMI_RSSI_THRESHOLD4_ABOVE,
+ WMI_RSSI_THRESHOLD5_ABOVE,
+ WMI_RSSI_THRESHOLD6_ABOVE,
+ WMI_RSSI_THRESHOLD1_BELOW,
+ WMI_RSSI_THRESHOLD2_BELOW,
+ WMI_RSSI_THRESHOLD3_BELOW,
+ WMI_RSSI_THRESHOLD4_BELOW,
+ WMI_RSSI_THRESHOLD5_BELOW,
+ WMI_RSSI_THRESHOLD6_BELOW
+};
+
+struct wmi_rssi_threshold_event {
+ a_sle16 rssi;
+ u8 range;
+} __packed;
+
+enum wmi_snr_threshold_val {
+ WMI_SNR_THRESHOLD1_ABOVE = 1,
+ WMI_SNR_THRESHOLD1_BELOW,
+ WMI_SNR_THRESHOLD2_ABOVE,
+ WMI_SNR_THRESHOLD2_BELOW,
+ WMI_SNR_THRESHOLD3_ABOVE,
+ WMI_SNR_THRESHOLD3_BELOW,
+ WMI_SNR_THRESHOLD4_ABOVE,
+ WMI_SNR_THRESHOLD4_BELOW
+};
+
+struct wmi_snr_threshold_event {
+ /* see, enum wmi_snr_threshold_val */
+ u8 range;
+
+ u8 snr;
+} __packed;
+
+/* WMI_REPORT_ROAM_TBL_EVENTID */
+#define MAX_ROAM_TBL_CAND 5
+
+struct wmi_bss_roam_info {
+ a_sle32 roam_util;
+ u8 bssid[ETH_ALEN];
+ s8 rssi;
+ s8 rssidt;
+ s8 last_rssi;
+ s8 util;
+ s8 bias;
+
+ /* for alignment */
+ u8 reserved;
+} __packed;
+
+/* WMI_CAC_EVENTID */
+enum cac_indication {
+ CAC_INDICATION_ADMISSION = 0x00,
+ CAC_INDICATION_ADMISSION_RESP = 0x01,
+ CAC_INDICATION_DELETE = 0x02,
+ CAC_INDICATION_NO_RESP = 0x03,
+};
+
+#define WMM_TSPEC_IE_LEN 63
+
+struct wmi_cac_event {
+ u8 ac;
+ u8 cac_indication;
+ u8 status_code;
+ u8 tspec_suggestion[WMM_TSPEC_IE_LEN];
+} __packed;
+
+/* WMI_APLIST_EVENTID */
+
+enum aplist_ver {
+ APLIST_VER1 = 1,
+};
+
+struct wmi_ap_info_v1 {
+ u8 bssid[ETH_ALEN];
+ __le16 channel;
+} __packed;
+
+union wmi_ap_info {
+ struct wmi_ap_info_v1 ap_info_v1;
+} __packed;
+
+struct wmi_aplist_event {
+ u8 ap_list_ver;
+ u8 num_ap;
+ union wmi_ap_info ap_list[1];
+} __packed;
+
+/* Developer Commands */
+
+/*
+ * WMI_SET_BITRATE_CMDID
+ *
+ * Get bit rate cmd uses same definition as set bit rate cmd
+ */
+enum wmi_bit_rate {
+ RATE_AUTO = -1,
+ RATE_1Mb = 0,
+ RATE_2Mb = 1,
+ RATE_5_5Mb = 2,
+ RATE_11Mb = 3,
+ RATE_6Mb = 4,
+ RATE_9Mb = 5,
+ RATE_12Mb = 6,
+ RATE_18Mb = 7,
+ RATE_24Mb = 8,
+ RATE_36Mb = 9,
+ RATE_48Mb = 10,
+ RATE_54Mb = 11,
+ RATE_MCS_0_20 = 12,
+ RATE_MCS_1_20 = 13,
+ RATE_MCS_2_20 = 14,
+ RATE_MCS_3_20 = 15,
+ RATE_MCS_4_20 = 16,
+ RATE_MCS_5_20 = 17,
+ RATE_MCS_6_20 = 18,
+ RATE_MCS_7_20 = 19,
+ RATE_MCS_0_40 = 20,
+ RATE_MCS_1_40 = 21,
+ RATE_MCS_2_40 = 22,
+ RATE_MCS_3_40 = 23,
+ RATE_MCS_4_40 = 24,
+ RATE_MCS_5_40 = 25,
+ RATE_MCS_6_40 = 26,
+ RATE_MCS_7_40 = 27,
+};
+
+struct wmi_bit_rate_reply {
+ /* see, enum wmi_bit_rate */
+ s8 rate_index;
+} __packed;
+
+/*
+ * WMI_SET_FIXRATES_CMDID
+ *
+ * Get fix rates cmd uses same definition as set fix rates cmd
+ */
+struct wmi_fix_rates_reply {
+ /* see wmi_bit_rate */
+ __le32 fix_rate_mask;
+} __packed;
+
+enum roam_data_type {
+ /* get the roam time data */
+ ROAM_DATA_TIME = 1,
+};
+
+struct wmi_target_roam_time {
+ __le32 disassoc_time;
+ __le32 no_txrx_time;
+ __le32 assoc_time;
+ __le32 allow_txrx_time;
+ u8 disassoc_bssid[ETH_ALEN];
+ s8 disassoc_bss_rssi;
+ u8 assoc_bssid[ETH_ALEN];
+ s8 assoc_bss_rssi;
+} __packed;
+
+enum wmi_txop_cfg {
+ WMI_TXOP_DISABLED = 0,
+ WMI_TXOP_ENABLED
+};
+
+struct wmi_set_wmm_txop_cmd {
+ u8 txop_enable;
+} __packed;
+
+struct wmi_set_keepalive_cmd {
+ u8 keep_alive_intvl;
+} __packed;
+
+struct wmi_get_keepalive_cmd {
+ __le32 configured;
+ u8 keep_alive_intvl;
+} __packed;
+
+struct wmi_set_appie_cmd {
+ u8 mgmt_frm_type; /* enum wmi_mgmt_frame_type */
+ u8 ie_len;
+ u8 ie_info[0];
+} __packed;
+
+/* Notify the WSC registration status to the target */
+#define WSC_REG_ACTIVE 1
+#define WSC_REG_INACTIVE 0
+
+#define WOW_MAX_FILTER_LISTS 1
+#define WOW_MAX_FILTERS_PER_LIST 4
+#define WOW_PATTERN_SIZE 64
+#define WOW_MASK_SIZE 64
+
+#define MAC_MAX_FILTERS_PER_LIST 4
+
+struct wow_filter {
+ u8 wow_valid_filter;
+ u8 wow_filter_id;
+ u8 wow_filter_size;
+ u8 wow_filter_offset;
+ u8 wow_filter_mask[WOW_MASK_SIZE];
+ u8 wow_filter_pattern[WOW_PATTERN_SIZE];
+} __packed;
+
+#define MAX_IP_ADDRS 2
+
+struct wmi_set_ip_cmd {
+ /* IP in network byte order */
+ __le32 ips[MAX_IP_ADDRS];
+} __packed;
+
+/* WMI_GET_WOW_LIST_CMD reply */
+struct wmi_get_wow_list_reply {
+ /* number of patterns in reply */
+ u8 num_filters;
+
+ /* this is filter # x of total num_filters */
+ u8 this_filter_num;
+
+ u8 wow_mode;
+ u8 host_mode;
+ struct wow_filter wow_filters[1];
+} __packed;
+
+/* WMI_SET_AKMP_PARAMS_CMD */
+
+struct wmi_pmkid {
+ u8 pmkid[WMI_PMKID_LEN];
+} __packed;
+
+/* WMI_GET_PMKID_LIST_CMD Reply */
+struct wmi_pmkid_list_reply {
+ __le32 num_pmkid;
+ u8 bssid_list[ETH_ALEN][1];
+ struct wmi_pmkid pmkid_list[1];
+} __packed;
+
+/* WMI_ADDBA_REQ_EVENTID */
+struct wmi_addba_req_event {
+ u8 tid;
+ u8 win_sz;
+ __le16 st_seq_no;
+
+ /* f/w response for ADDBA Req; OK (0) or failure (!=0) */
+ u8 status;
+} __packed;
+
+/* WMI_ADDBA_RESP_EVENTID */
+struct wmi_addba_resp_event {
+ u8 tid;
+
+ /* OK (0), failure (!=0) */
+ u8 status;
+
+ /* three values: not supported(0), 3839, 8k */
+ __le16 amsdu_sz;
+} __packed;
+
+/* WMI_DELBA_EVENTID
+ * f/w received a DELBA for peer and processed it.
+ * Host is notified of this
+ */
+struct wmi_delba_event {
+ u8 tid;
+ u8 is_peer_initiator;
+ __le16 reason_code;
+} __packed;
+
+#define PEER_NODE_JOIN_EVENT 0x00
+#define PEER_NODE_LEAVE_EVENT 0x01
+#define PEER_FIRST_NODE_JOIN_EVENT 0x10
+#define PEER_LAST_NODE_LEAVE_EVENT 0x11
+
+struct wmi_peer_node_event {
+ u8 event_code;
+ u8 peer_mac_addr[ETH_ALEN];
+} __packed;
+
+/* Transmit complete event data structure(s) */
+
+/* version 1 of tx complete msg */
+struct tx_complete_msg_v1 {
+#define TX_COMPLETE_STATUS_SUCCESS 0
+#define TX_COMPLETE_STATUS_RETRIES 1
+#define TX_COMPLETE_STATUS_NOLINK 2
+#define TX_COMPLETE_STATUS_TIMEOUT 3
+#define TX_COMPLETE_STATUS_OTHER 4
+
+ u8 status;
+
+ /* packet ID to identify parent packet */
+ u8 pkt_id;
+
+ /* rate index on successful transmission */
+ u8 rate_idx;
+
+ /* number of ACK failures in tx attempt */
+ u8 ack_failures;
+} __packed;
+
+struct wmi_tx_complete_event {
+ /* no of tx comp msgs following this struct */
+ u8 num_msg;
+
+ /* length in bytes for each individual msg following this struct */
+ u8 msg_len;
+
+ /* version of tx complete msg data following this struct */
+ u8 msg_type;
+
+ /* individual messages follow this header */
+ u8 reserved;
+} __packed;
+
+/*
+ * ------- AP Mode definitions --------------
+ */
+
+/*
+ * !!! Warning !!!
+ * -Changing the following values needs compilation of both driver and firmware
+ */
+#define AP_MAX_NUM_STA 8
+
+/* Spl. AID used to set DTIM flag in the beacons */
+#define MCAST_AID 0xFF
+
+#define DEF_AP_COUNTRY_CODE "US "
+
+/* Used with WMI_AP_SET_NUM_STA_CMDID */
+
+/*
+ * Used with WMI_AP_SET_MLME_CMDID
+ */
+
+/* MLME Commands */
+#define WMI_AP_MLME_ASSOC 1 /* associate station */
+#define WMI_AP_DISASSOC 2 /* disassociate station */
+#define WMI_AP_DEAUTH 3 /* deauthenticate station */
+#define WMI_AP_MLME_AUTHORIZE 4 /* authorize station */
+#define WMI_AP_MLME_UNAUTHORIZE 5 /* unauthorize station */
+
+struct wmi_ap_set_mlme_cmd {
+ u8 mac[ETH_ALEN];
+ __le16 reason; /* 802.11 reason code */
+ u8 cmd; /* operation to perform (WMI_AP_*) */
+} __packed;
+
+struct wmi_ap_set_pvb_cmd {
+ __le32 flag;
+ __le16 rsvd;
+ __le16 aid;
+} __packed;
+
+struct wmi_rx_frame_format_cmd {
+ /* version of meta data for rx packets <0 = default> (0-7 = valid) */
+ u8 meta_ver;
+
+ /*
+ * 1 == leave .11 header intact,
+ * 0 == replace .11 header with .3 <default>
+ */
+ u8 dot11_hdr;
+
+ /*
+ * 1 == defragmentation is performed by host,
+ * 0 == performed by target <default>
+ */
+ u8 defrag_on_host;
+
+ /* for alignment */
+ u8 reserved[1];
+} __packed;
+
+/* AP mode events */
+
+/* WMI_PS_POLL_EVENT */
+struct wmi_pspoll_event {
+ __le16 aid;
+} __packed;
+
+struct wmi_per_sta_stat {
+ __le32 tx_bytes;
+ __le32 tx_pkts;
+ __le32 tx_error;
+ __le32 tx_discard;
+ __le32 rx_bytes;
+ __le32 rx_pkts;
+ __le32 rx_error;
+ __le32 rx_discard;
+ __le32 aid;
+} __packed;
+
+struct wmi_ap_mode_stat {
+ __le32 action;
+ struct wmi_per_sta_stat sta[AP_MAX_NUM_STA + 1];
+} __packed;
+
+/* End of AP mode definitions */
+
+struct wmi_remain_on_chnl_cmd {
+ __le32 freq;
+ __le32 duration;
+} __packed;
+
+struct wmi_send_action_cmd {
+ __le32 id;
+ __le32 freq;
+ __le32 wait;
+ __le16 len;
+ u8 data[0];
+} __packed;
+
+struct wmi_tx_status_event {
+ __le32 id;
+ u8 ack_status;
+} __packed;
+
+struct wmi_probe_req_report_cmd {
+ u8 enable;
+} __packed;
+
+struct wmi_disable_11b_rates_cmd {
+ u8 disable;
+} __packed;
+
+struct wmi_set_appie_extended_cmd {
+ u8 role_id;
+ u8 mgmt_frm_type;
+ u8 ie_len;
+ u8 ie_info[0];
+} __packed;
+
+struct wmi_remain_on_chnl_event {
+ __le32 freq;
+ __le32 duration;
+} __packed;
+
+struct wmi_cancel_remain_on_chnl_event {
+ __le32 freq;
+ __le32 duration;
+ u8 status;
+} __packed;
+
+struct wmi_rx_action_event {
+ __le32 freq;
+ __le16 len;
+ u8 data[0];
+} __packed;
+
+struct wmi_p2p_capabilities_event {
+ __le16 len;
+ u8 data[0];
+} __packed;
+
+struct wmi_p2p_rx_probe_req_event {
+ __le32 freq;
+ __le16 len;
+ u8 data[0];
+} __packed;
+
+#define P2P_FLAG_CAPABILITIES_REQ (0x00000001)
+#define P2P_FLAG_MACADDR_REQ (0x00000002)
+#define P2P_FLAG_HMODEL_REQ (0x00000002)
+
+struct wmi_get_p2p_info {
+ __le32 info_req_flags;
+} __packed;
+
+struct wmi_p2p_info_event {
+ __le32 info_req_flags;
+ __le16 len;
+ u8 data[0];
+} __packed;
+
+struct wmi_p2p_capabilities {
+ u8 go_power_save;
+} __packed;
+
+struct wmi_p2p_macaddr {
+ u8 mac_addr[ETH_ALEN];
+} __packed;
+
+struct wmi_p2p_hmodel {
+ u8 p2p_model;
+} __packed;
+
+struct wmi_p2p_probe_response_cmd {
+ __le32 freq;
+ u8 destination_addr[ETH_ALEN];
+ __le16 len;
+ u8 data[0];
+} __packed;
+
+/* Extended WMI (WMIX)
+ *
+ * Extended WMIX commands are encapsulated in a WMI message with
+ * cmd=WMI_EXTENSION_CMD.
+ *
+ * Extended WMI commands are those that are needed during wireless
+ * operation, but which are not really wireless commands. This allows,
+ * for instance, platform-specific commands. Extended WMI commands are
+ * embedded in a WMI command message with WMI_COMMAND_ID=WMI_EXTENSION_CMDID.
+ * Extended WMI events are similarly embedded in a WMI event message with
+ * WMI_EVENT_ID=WMI_EXTENSION_EVENTID.
+ */
+struct wmix_cmd_hdr {
+ __le32 cmd_id;
+} __packed;
+
+enum wmix_command_id {
+ WMIX_DSETOPEN_REPLY_CMDID = 0x2001,
+ WMIX_DSETDATA_REPLY_CMDID,
+ WMIX_GPIO_OUTPUT_SET_CMDID,
+ WMIX_GPIO_INPUT_GET_CMDID,
+ WMIX_GPIO_REGISTER_SET_CMDID,
+ WMIX_GPIO_REGISTER_GET_CMDID,
+ WMIX_GPIO_INTR_ACK_CMDID,
+ WMIX_HB_CHALLENGE_RESP_CMDID,
+ WMIX_DBGLOG_CFG_MODULE_CMDID,
+ WMIX_PROF_CFG_CMDID, /* 0x200a */
+ WMIX_PROF_ADDR_SET_CMDID,
+ WMIX_PROF_START_CMDID,
+ WMIX_PROF_STOP_CMDID,
+ WMIX_PROF_COUNT_GET_CMDID,
+};
+
+enum wmix_event_id {
+ WMIX_DSETOPENREQ_EVENTID = 0x3001,
+ WMIX_DSETCLOSE_EVENTID,
+ WMIX_DSETDATAREQ_EVENTID,
+ WMIX_GPIO_INTR_EVENTID,
+ WMIX_GPIO_DATA_EVENTID,
+ WMIX_GPIO_ACK_EVENTID,
+ WMIX_HB_CHALLENGE_RESP_EVENTID,
+ WMIX_DBGLOG_EVENTID,
+ WMIX_PROF_COUNT_EVENTID,
+};
+
+/*
+ * ------Error Detection support-------
+ */
+
+/*
+ * WMIX_HB_CHALLENGE_RESP_CMDID
+ * Heartbeat Challenge Response command
+ */
+struct wmix_hb_challenge_resp_cmd {
+ __le32 cookie;
+ __le32 source;
+} __packed;
+
+struct ath6kl_wmix_dbglog_cfg_module_cmd {
+ __le32 valid;
+ __le32 config;
+} __packed;
+
+/* End of Extended WMI (WMIX) */
+
+enum wmi_sync_flag {
+ NO_SYNC_WMIFLAG = 0,
+
+ /* transmit all queued data before cmd */
+ SYNC_BEFORE_WMIFLAG,
+
+ /* any new data waits until cmd execs */
+ SYNC_AFTER_WMIFLAG,
+
+ SYNC_BOTH_WMIFLAG,
+
+ /* end marker */
+ END_WMIFLAG
+};
+
+enum htc_endpoint_id ath6kl_wmi_get_control_ep(struct wmi *wmi);
+void ath6kl_wmi_set_control_ep(struct wmi *wmi, enum htc_endpoint_id ep_id);
+int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb);
+int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,
+ u8 msg_type, bool more_data,
+ enum wmi_data_hdr_data_type data_type,
+ u8 meta_ver, void *tx_meta_info);
+
+int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb);
+int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb);
+int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, struct sk_buff *skb,
+ u32 layer2_priority, bool wmm_enabled,
+ u8 *ac);
+
+int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb);
+
+int ath6kl_wmi_cmd_send(struct wmi *wmi, struct sk_buff *skb,
+ enum wmi_cmd_id cmd_id, enum wmi_sync_flag sync_flag);
+
+int ath6kl_wmi_connect_cmd(struct wmi *wmi, enum network_type nw_type,
+ enum dot11_auth_mode dot11_auth_mode,
+ enum auth_mode auth_mode,
+ enum crypto_type pairwise_crypto,
+ u8 pairwise_crypto_len,
+ enum crypto_type group_crypto,
+ u8 group_crypto_len, int ssid_len, u8 *ssid,
+ u8 *bssid, u16 channel, u32 ctrl_flags);
+
+int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 *bssid, u16 channel);
+int ath6kl_wmi_disconnect_cmd(struct wmi *wmi);
+int ath6kl_wmi_startscan_cmd(struct wmi *wmi, enum wmi_scan_type scan_type,
+ u32 force_fgscan, u32 is_legacy,
+ u32 home_dwell_time, u32 force_scan_interval,
+ s8 num_chan, u16 *ch_list);
+int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u16 fg_start_sec,
+ u16 fg_end_sec, u16 bg_sec,
+ u16 minact_chdw_msec, u16 maxact_chdw_msec,
+ u16 pas_chdw_msec, u8 short_scan_ratio,
+ u8 scan_ctrl_flag, u32 max_dfsch_act_time,
+ u16 maxact_scan_per_ssid);
+int ath6kl_wmi_bssfilter_cmd(struct wmi *wmi, u8 filter, u32 ie_mask);
+int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 index, u8 flag,
+ u8 ssid_len, u8 *ssid);
+int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u16 listen_interval,
+ u16 listen_beacons);
+int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 pwr_mode);
+int ath6kl_wmi_pmparams_cmd(struct wmi *wmi, u16 idle_period,
+ u16 ps_poll_num, u16 dtim_policy,
+ u16 tx_wakup_policy, u16 num_tx_to_wakeup,
+ u16 ps_fail_event_policy);
+int ath6kl_wmi_disctimeout_cmd(struct wmi *wmi, u8 timeout);
+int ath6kl_wmi_create_pstream_cmd(struct wmi *wmi,
+ struct wmi_create_pstream_cmd *pstream);
+int ath6kl_wmi_delete_pstream_cmd(struct wmi *wmi, u8 traffic_class, u8 tsid);
+
+int ath6kl_wmi_set_rts_cmd(struct wmi *wmi, u16 threshold);
+int ath6kl_wmi_set_lpreamble_cmd(struct wmi *wmi, u8 status,
+ u8 preamble_policy);
+
+int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source);
+int ath6kl_wmi_config_debug_module_cmd(struct wmi *wmi, u32 valid, u32 config);
+
+int ath6kl_wmi_get_stats_cmd(struct wmi *wmi);
+int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 key_index,
+ enum crypto_type key_type,
+ u8 key_usage, u8 key_len,
+ u8 *key_rsc, u8 *key_material,
+ u8 key_op_ctrl, u8 *mac_addr,
+ enum wmi_sync_flag sync_flag);
+int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 *krk);
+int ath6kl_wmi_deletekey_cmd(struct wmi *wmi, u8 key_index);
+int ath6kl_wmi_setpmkid_cmd(struct wmi *wmi, const u8 *bssid,
+ const u8 *pmkid, bool set);
+int ath6kl_wmi_set_tx_pwr_cmd(struct wmi *wmi, u8 dbM);
+int ath6kl_wmi_get_tx_pwr_cmd(struct wmi *wmi);
+
+int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, enum wmi_txop_cfg cfg);
+int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 keep_alive_intvl);
+int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len);
+
+s32 ath6kl_wmi_get_rate(s8 rate_index);
+
+int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd);
+int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi);
+
+/* AP mode */
+int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, struct wmi_connect_cmd *p);
+
+int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 cmd, const u8 *mac, u16 reason);
+
+int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u16 aid, bool flag);
+
+int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_version,
+ bool rx_dot11_hdr, bool defrag_on_host);
+
+int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 mgmt_frm_type, const u8 *ie,
+ u8 ie_len);
+
+/* P2P */
+int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable);
+
+int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u32 freq, u32 dur);
+
+int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u32 id, u32 freq, u32 wait,
+ const u8 *data, u16 data_len);
+
+int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u32 freq,
+ const u8 *dst,
+ const u8 *data, u16 data_len);
+
+int ath6kl_wmi_probe_report_req_cmd(struct wmi *wmi, bool enable);
+
+int ath6kl_wmi_info_req_cmd(struct wmi *wmi, u32 info_req_flags);
+
+int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi);
+
+int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 mgmt_frm_type, const u8 *ie,
+ u8 ie_len);
+
+void *ath6kl_wmi_init(struct ath6kl *devt);
+void ath6kl_wmi_shutdown(struct wmi *wmi);
+
+#endif /* WMI_H */
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index 05a6fade7b1c..36ed3c46fec6 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -21,6 +21,7 @@ ath9k_hw-y:= \
ar5008_phy.o \
ar9002_calib.o \
ar9003_calib.o \
+ ar9003_rtt.o \
calib.o \
eeprom.o \
eeprom_def.o \
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index 0b36fcf8a280..85a54cd2b083 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -133,7 +133,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
goto err_free_hw;
}
- ret = ath9k_init_device(id->driver_data, sc, 0x0, &ath_ahb_bus_ops);
+ ret = ath9k_init_device(id->driver_data, sc, &ath_ahb_bus_ops);
if (ret) {
dev_err(&pdev->dev, "failed to initialize device\n");
goto err_irq;
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index bfb6481f01f9..2776c3c1f506 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -273,7 +273,8 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel)
immunityLevel, aniState->noiseFloor,
aniState->rssiThrLow, aniState->rssiThrHigh);
- aniState->ofdmNoiseImmunityLevel = immunityLevel;
+ if (aniState->update_ani)
+ aniState->ofdmNoiseImmunityLevel = immunityLevel;
entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
@@ -346,7 +347,8 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel)
immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI)
immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI;
- aniState->cckNoiseImmunityLevel = immunityLevel;
+ if (aniState->update_ani)
+ aniState->cckNoiseImmunityLevel = immunityLevel;
entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
@@ -502,9 +504,6 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
ATH9K_ANI_CCK_WEAK_SIG_THR);
- ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
- ATH9K_RX_FILTER_PHYERR);
-
ath9k_ani_restart(ah);
return;
}
@@ -525,8 +524,6 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
aniState->firstepLevel);
- ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
- ~ATH9K_RX_FILTER_PHYERR);
ath9k_ani_restart(ah);
ENABLE_REGWRITE_BUFFER(ah);
@@ -593,6 +590,7 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
aniState->ofdmNoiseImmunityLevel,
aniState->cckNoiseImmunityLevel);
+ aniState->update_ani = false;
ath9k_hw_set_ofdm_nil(ah, ATH9K_ANI_OFDM_DEF_LEVEL);
ath9k_hw_set_cck_nil(ah, ATH9K_ANI_CCK_DEF_LEVEL);
}
@@ -609,6 +607,7 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
aniState->ofdmNoiseImmunityLevel,
aniState->cckNoiseImmunityLevel);
+ aniState->update_ani = true;
ath9k_hw_set_ofdm_nil(ah,
aniState->ofdmNoiseImmunityLevel);
ath9k_hw_set_cck_nil(ah,
@@ -643,7 +642,7 @@ static bool ath9k_hw_ani_read_counters(struct ath_hw *ah)
listenTime = ath_hw_get_listen_time(common);
if (listenTime <= 0) {
- ah->stats.ast_ani_lneg++;
+ ah->stats.ast_ani_lneg_or_lzero++;
ath9k_ani_restart(ah);
return false;
}
@@ -892,6 +891,8 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
ani->ofdmWeakSigDetectOff =
!ATH9K_ANI_USE_OFDM_WEAK_SIG;
ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
+ ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL;
+ ani->update_ani = false;
}
/*
diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h
index dbab5b9ce494..83029d6c7b22 100644
--- a/drivers/net/wireless/ath/ath9k/ani.h
+++ b/drivers/net/wireless/ath/ath9k/ani.h
@@ -122,6 +122,7 @@ struct ar5416AniState {
u8 firstepLevel;
u8 ofdmWeakSigDetectOff;
u8 cckWeakSigThreshold;
+ bool update_ani;
u32 listenTime;
int32_t rssiThrLow;
int32_t rssiThrHigh;
@@ -148,8 +149,7 @@ struct ar5416Stats {
u32 ast_ani_ofdmerrs;
u32 ast_ani_cckerrs;
u32 ast_ani_reset;
- u32 ast_ani_lzero;
- u32 ast_ani_lneg;
+ u32 ast_ani_lneg_or_lzero;
u32 avgbrssi;
struct ath9k_mib_stats ast_mibstats;
};
@@ -159,7 +159,5 @@ void ath9k_enable_mib_counters(struct ath_hw *ah);
void ath9k_hw_disable_mib_counters(struct ath_hw *ah);
void ath9k_hw_ani_setup(struct ath_hw *ah);
void ath9k_hw_ani_init(struct ath_hw *ah);
-int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
- struct ath9k_channel *chan);
#endif /* ANI_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_initvals.h b/drivers/net/wireless/ath/ath9k/ar5008_initvals.h
index 234617c948a1..f81e7fc60a36 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar5008_initvals.h
@@ -14,70 +14,71 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-static const u32 ar5416Modes[][6] = {
- {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0},
- {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0},
- {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180},
- {0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008},
- {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0},
- {0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf},
- {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810},
- {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a},
- {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303},
- {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
- {0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
- {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
- {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
- {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
- {0x00009844, 0x1372161e, 0x1372161e, 0x137216a0, 0x137216a0, 0x137216a0},
- {0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
- {0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
- {0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
- {0x00009850, 0x6c48b4e0, 0x6d48b4e0, 0x6d48b0de, 0x6c48b0de, 0x6c48b0de},
- {0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e},
- {0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e},
- {0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18},
- {0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
- {0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190},
- {0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081},
- {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0},
- {0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134},
- {0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b},
- {0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020},
- {0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80},
- {0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80},
- {0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80},
- {0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120, 0x00001120},
- {0x000099bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00},
- {0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be},
- {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
- {0x000099c8, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c},
- {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
- {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
- {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880},
- {0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788},
- {0x0000a20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120},
- {0x0000b20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120},
- {0x0000c20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120},
- {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
- {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
- {0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa},
- {0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000},
- {0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402},
- {0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06},
- {0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b},
- {0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b},
- {0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a},
- {0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf},
- {0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f},
- {0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f},
- {0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f},
- {0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+static const u32 ar5416Modes[][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},
+ {0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000},
+ {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
+ {0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab},
+ {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810},
+ {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a},
+ {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300},
+ {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
+ {0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
+ {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
+ {0x00009844, 0x1372161e, 0x1372161e, 0x137216a0, 0x137216a0},
+ {0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68},
+ {0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68},
+ {0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68},
+ {0x00009850, 0x6c48b4e0, 0x6d48b4e0, 0x6d48b0de, 0x6c48b0de},
+ {0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e},
+ {0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e},
+ {0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18},
+ {0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+ {0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190},
+ {0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081},
+ {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
+ {0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134},
+ {0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b},
+ {0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020},
+ {0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80},
+ {0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80},
+ {0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80},
+ {0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120},
+ {0x000099bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00},
+ {0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be},
+ {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
+ {0x000099c8, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c},
+ {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
+ {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
+ {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880},
+ {0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788},
+ {0x0000a20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120},
+ {0x0000b20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120},
+ {0x0000c20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120},
+ {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+ {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
+ {0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa},
+ {0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000},
+ {0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402},
+ {0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06},
+ {0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b},
+ {0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b},
+ {0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a},
+ {0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf},
+ {0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f},
+ {0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f},
+ {0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f},
+ {0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000},
+ {0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
};
static const u32 ar5416Common[][2] = {
@@ -668,6 +669,6 @@ static const u32 ar5416Addac[][2] = {
{0x0000989c, 0x00000000},
{0x0000989c, 0x00000000},
{0x0000989c, 0x00000000},
- {0x000098cc, 0x00000000},
+ {0x000098c4, 0x00000000},
};
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index fac2c6da6ca4..f199e9e25149 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -704,8 +704,10 @@ static void ar5008_hw_override_ini(struct ath_hw *ah,
REG_WRITE(ah, AR_PCU_MISC_MODE2, val);
}
- if (!AR_SREV_5416_20_OR_LATER(ah) ||
- AR_SREV_9280_20_OR_LATER(ah))
+ REG_SET_BIT(ah, AR_PHY_CCK_DETECT,
+ AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
+
+ if (AR_SREV_9280_20_OR_LATER(ah))
return;
/*
* Disable BB clock gating
@@ -761,10 +763,8 @@ static void ar5008_hw_set_channel_regs(struct ath_hw *ah,
static int ar5008_hw_process_ini(struct ath_hw *ah,
struct ath9k_channel *chan)
{
- struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
struct ath_common *common = ath9k_hw_common(ah);
int i, regWrites = 0;
- struct ieee80211_channel *channel = chan->chan;
u32 modesIndex, freqIndex;
switch (chan->chanmode) {
@@ -802,7 +802,8 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
/* Write ADDAC shifts */
REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO);
- ah->eep_ops->set_addac(ah, chan);
+ if (ah->eep_ops->set_addac)
+ ah->eep_ops->set_addac(ah, chan);
if (AR_SREV_5416_22_OR_LATER(ah)) {
REG_WRITE_ARRAY(&ah->iniAddac, 1, regWrites);
@@ -900,14 +901,7 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
ar5008_hw_set_channel_regs(ah, chan);
ar5008_hw_init_chain_masks(ah);
ath9k_olc_init(ah);
-
- /* Set TX power */
- ah->eep_ops->set_txpower(ah, chan,
- ath9k_regd_get_ctl(regulatory, chan),
- channel->max_antenna_gain * 2,
- channel->max_power * 2,
- min((u32) MAX_RATE_POWER,
- (u32) regulatory->power_limit), false);
+ ath9k_hw_apply_txpower(ah, chan);
/* Write analog registers */
if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) {
@@ -1007,24 +1001,6 @@ static void ar5008_restore_chainmask(struct ath_hw *ah)
}
}
-static void ar5008_set_diversity(struct ath_hw *ah, bool value)
-{
- u32 v = REG_READ(ah, AR_PHY_CCK_DETECT);
- if (value)
- v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
- else
- v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
- REG_WRITE(ah, AR_PHY_CCK_DETECT, v);
-}
-
-static u32 ar9100_hw_compute_pll_control(struct ath_hw *ah,
- struct ath9k_channel *chan)
-{
- if (chan && IS_CHAN_5GHZ(chan))
- return 0x1450;
- return 0x1458;
-}
-
static u32 ar9160_hw_compute_pll_control(struct ath_hw *ah,
struct ath9k_channel *chan)
{
@@ -1654,7 +1630,6 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
priv_ops->rfbus_req = ar5008_hw_rfbus_req;
priv_ops->rfbus_done = ar5008_hw_rfbus_done;
priv_ops->restore_chainmask = ar5008_restore_chainmask;
- priv_ops->set_diversity = ar5008_set_diversity;
priv_ops->do_getnf = ar5008_hw_do_getnf;
priv_ops->set_radar_params = ar5008_hw_set_radar_params;
@@ -1664,9 +1639,7 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
} else
priv_ops->ani_control = ar5008_hw_ani_control_old;
- if (AR_SREV_9100(ah))
- priv_ops->compute_pll_control = ar9100_hw_compute_pll_control;
- else if (AR_SREV_9160_10_OR_LATER(ah))
+ if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah))
priv_ops->compute_pll_control = ar9160_hw_compute_pll_control;
else
priv_ops->compute_pll_control = ar5008_hw_compute_pll_control;
diff --git a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h
index 6d2e2f3303f9..e8bdc75405f1 100644
--- a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h
@@ -14,73 +14,74 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-static const u32 ar5416Modes_9100[][6] = {
- {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0},
- {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0},
- {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180},
- {0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008},
- {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0},
- {0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf},
- {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810},
- {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a},
- {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303},
- {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
- {0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
- {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
- {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
- {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
- {0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0},
- {0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
- {0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
- {0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
- {0x00009850, 0x6c48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6c48b0e2, 0x6c48b0e2},
- {0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e},
- {0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e},
- {0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18},
- {0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
- {0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0},
- {0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081},
- {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0},
- {0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016},
- {0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d},
- {0x00009940, 0x00750604, 0x00754604, 0xfff81204, 0xfff81204, 0xfff81204},
- {0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020},
- {0x00009954, 0x5f3ca3de, 0x5f3ca3de, 0xe250a51e, 0xe250a51e, 0xe250a51e},
- {0x00009958, 0x2108ecff, 0x2108ecff, 0x3388ffff, 0x3388ffff, 0x3388ffff},
- {0x00009960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0},
- {0x0000a960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0},
- {0x0000b960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0},
- {0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120},
- {0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a1000, 0x001a0c00, 0x001a0c00},
- {0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be},
- {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
- {0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329},
- {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
- {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
- {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880},
- {0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788},
- {0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
- {0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
- {0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
- {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
- {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
- {0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa},
- {0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000},
- {0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402},
- {0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06},
- {0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b},
- {0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b},
- {0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a},
- {0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf},
- {0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f},
- {0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f},
- {0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f},
- {0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+static const u32 ar5416Modes_9100[][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},
+ {0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000},
+ {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
+ {0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab},
+ {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810},
+ {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a},
+ {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300},
+ {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
+ {0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
+ {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
+ {0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
+ {0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68},
+ {0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68},
+ {0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68},
+ {0x00009850, 0x6c48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6c48b0e2},
+ {0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e},
+ {0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e},
+ {0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20},
+ {0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+ {0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0},
+ {0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081},
+ {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
+ {0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
+ {0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d},
+ {0x00009940, 0x00750604, 0x00754604, 0xfff81204, 0xfff81204},
+ {0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020},
+ {0x00009954, 0x5f3ca3de, 0x5f3ca3de, 0xe250a51e, 0xe250a51e},
+ {0x00009958, 0x2108ecff, 0x2108ecff, 0x3388ffff, 0x3388ffff},
+ {0x00009960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0},
+ {0x0000a960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0},
+ {0x0000b960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0},
+ {0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120},
+ {0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a1000, 0x001a0c00},
+ {0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be},
+ {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
+ {0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329},
+ {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
+ {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
+ {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880},
+ {0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788},
+ {0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120},
+ {0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120},
+ {0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120},
+ {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+ {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
+ {0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa},
+ {0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000},
+ {0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402},
+ {0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06},
+ {0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b},
+ {0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b},
+ {0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a},
+ {0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf},
+ {0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f},
+ {0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f},
+ {0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f},
+ {0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000},
+ {0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
};
static const u32 ar5416Common_9100[][2] = {
@@ -666,71 +667,72 @@ static const u32 ar5416Addac_9100[][2] = {
{0x000098cc, 0x00000000},
};
-static const u32 ar5416Modes_9160[][6] = {
- {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0},
- {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0},
- {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180},
- {0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008},
- {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0},
- {0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf},
- {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810},
- {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a},
- {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303},
- {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
- {0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
- {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
- {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
- {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
- {0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0},
- {0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
- {0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
- {0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
- {0x00009850, 0x6c48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6c48b0e2, 0x6c48b0e2},
- {0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e},
- {0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e},
- {0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18},
- {0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
- {0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0},
- {0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081},
- {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0},
- {0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016},
- {0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d},
- {0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020},
- {0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40},
- {0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40},
- {0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40},
- {0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120},
- {0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce},
- {0x000099bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00},
- {0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be},
- {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
- {0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329},
- {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
- {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
- {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880},
- {0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788},
- {0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
- {0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
- {0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
- {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
- {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
- {0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa},
- {0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000},
- {0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402},
- {0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06},
- {0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b},
- {0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b},
- {0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a},
- {0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf},
- {0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f},
- {0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f},
- {0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f},
- {0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+static const u32 ar5416Modes_9160[][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},
+ {0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000},
+ {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
+ {0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab},
+ {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810},
+ {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a},
+ {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300},
+ {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
+ {0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
+ {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
+ {0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
+ {0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68},
+ {0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68},
+ {0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68},
+ {0x00009850, 0x6c48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6c48b0e2},
+ {0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e},
+ {0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e},
+ {0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20},
+ {0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+ {0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0},
+ {0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081},
+ {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
+ {0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
+ {0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d},
+ {0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020},
+ {0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40},
+ {0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40},
+ {0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40},
+ {0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120},
+ {0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
+ {0x000099bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00},
+ {0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be},
+ {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
+ {0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329},
+ {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
+ {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
+ {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880},
+ {0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788},
+ {0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120},
+ {0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120},
+ {0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120},
+ {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+ {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
+ {0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa},
+ {0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000},
+ {0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402},
+ {0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06},
+ {0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b},
+ {0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b},
+ {0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a},
+ {0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf},
+ {0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f},
+ {0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f},
+ {0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f},
+ {0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000},
+ {0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
};
static const u32 ar5416Common_9160[][2] = {
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
index 2d4c0910295b..e0ab0657cc3a 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
@@ -41,7 +41,8 @@ static bool ar9002_hw_is_cal_supported(struct ath_hw *ah,
case ADC_DC_CAL:
/* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */
if (!IS_CHAN_B(chan) &&
- !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan)))
+ !((IS_CHAN_2GHZ(chan) || IS_CHAN_A_FAST_CLOCK(ah, chan)) &&
+ IS_CHAN_HT20(chan)))
supported = true;
break;
}
@@ -868,6 +869,7 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
ar9002_hw_pa_cal(ah, true);
/* Do NF Calibration after DC offset and other calibrations */
+ ath9k_hw_loadnf(ah, chan);
ath9k_hw_start_nfcal(ah, true);
if (ah->caldata)
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
index 44d9d8d56490..626d547d2f06 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
@@ -30,7 +30,7 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
{
if (AR_SREV_9271(ah)) {
INIT_INI_ARRAY(&ah->iniModes, ar9271Modes_9271,
- ARRAY_SIZE(ar9271Modes_9271), 6);
+ ARRAY_SIZE(ar9271Modes_9271), 5);
INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271,
ARRAY_SIZE(ar9271Common_9271), 2);
INIT_INI_ARRAY(&ah->iniCommon_normal_cck_fir_coeff_9271,
@@ -41,21 +41,21 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
ARRAY_SIZE(ar9271Common_japan_2484_cck_fir_coeff_9271), 2);
INIT_INI_ARRAY(&ah->iniModes_9271_1_0_only,
ar9271Modes_9271_1_0_only,
- ARRAY_SIZE(ar9271Modes_9271_1_0_only), 6);
+ ARRAY_SIZE(ar9271Modes_9271_1_0_only), 5);
INIT_INI_ARRAY(&ah->iniModes_9271_ANI_reg, ar9271Modes_9271_ANI_reg,
- ARRAY_SIZE(ar9271Modes_9271_ANI_reg), 6);
+ ARRAY_SIZE(ar9271Modes_9271_ANI_reg), 5);
INIT_INI_ARRAY(&ah->iniModes_high_power_tx_gain_9271,
ar9271Modes_high_power_tx_gain_9271,
- ARRAY_SIZE(ar9271Modes_high_power_tx_gain_9271), 6);
+ ARRAY_SIZE(ar9271Modes_high_power_tx_gain_9271), 5);
INIT_INI_ARRAY(&ah->iniModes_normal_power_tx_gain_9271,
ar9271Modes_normal_power_tx_gain_9271,
- ARRAY_SIZE(ar9271Modes_normal_power_tx_gain_9271), 6);
+ ARRAY_SIZE(ar9271Modes_normal_power_tx_gain_9271), 5);
return;
}
if (AR_SREV_9287_11_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1,
- ARRAY_SIZE(ar9287Modes_9287_1_1), 6);
+ 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)
@@ -71,7 +71,7 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2,
- ARRAY_SIZE(ar9285Modes_9285_1_2), 6);
+ ARRAY_SIZE(ar9285Modes_9285_1_2), 5);
INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285_1_2,
ARRAY_SIZE(ar9285Common_9285_1_2), 2);
@@ -87,7 +87,7 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
}
} else if (AR_SREV_9280_20_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280_2,
- ARRAY_SIZE(ar9280Modes_9280_2), 6);
+ ARRAY_SIZE(ar9280Modes_9280_2), 5);
INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280_2,
ARRAY_SIZE(ar9280Common_9280_2), 2);
@@ -105,7 +105,7 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3);
} else if (AR_SREV_9160_10_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9160,
- ARRAY_SIZE(ar5416Modes_9160), 6);
+ ARRAY_SIZE(ar5416Modes_9160), 5);
INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9160,
ARRAY_SIZE(ar5416Common_9160), 2);
INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9160,
@@ -134,7 +134,7 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
}
} else if (AR_SREV_9100_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9100,
- ARRAY_SIZE(ar5416Modes_9100), 6);
+ ARRAY_SIZE(ar5416Modes_9100), 5);
INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9100,
ARRAY_SIZE(ar5416Common_9100), 2);
INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9100,
@@ -157,7 +157,7 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
ARRAY_SIZE(ar5416Addac_9100), 2);
} else {
INIT_INI_ARRAY(&ah->iniModes, ar5416Modes,
- ARRAY_SIZE(ar5416Modes), 6);
+ ARRAY_SIZE(ar5416Modes), 5);
INIT_INI_ARRAY(&ah->iniCommon, ar5416Common,
ARRAY_SIZE(ar5416Common), 2);
INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0,
@@ -207,19 +207,19 @@ static void ar9280_20_hw_init_rxgain_ini(struct ath_hw *ah)
if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF)
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9280Modes_backoff_13db_rxgain_9280_2,
- ARRAY_SIZE(ar9280Modes_backoff_13db_rxgain_9280_2), 6);
+ ARRAY_SIZE(ar9280Modes_backoff_13db_rxgain_9280_2), 5);
else if (rxgain_type == AR5416_EEP_RXGAIN_23DB_BACKOFF)
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9280Modes_backoff_23db_rxgain_9280_2,
- ARRAY_SIZE(ar9280Modes_backoff_23db_rxgain_9280_2), 6);
+ ARRAY_SIZE(ar9280Modes_backoff_23db_rxgain_9280_2), 5);
else
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9280Modes_original_rxgain_9280_2,
- ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6);
+ ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 5);
} else {
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9280Modes_original_rxgain_9280_2,
- ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6);
+ ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 5);
}
}
@@ -234,15 +234,15 @@ static void ar9280_20_hw_init_txgain_ini(struct ath_hw *ah)
if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER)
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9280Modes_high_power_tx_gain_9280_2,
- ARRAY_SIZE(ar9280Modes_high_power_tx_gain_9280_2), 6);
+ ARRAY_SIZE(ar9280Modes_high_power_tx_gain_9280_2), 5);
else
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9280Modes_original_tx_gain_9280_2,
- ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6);
+ ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 5);
} else {
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9280Modes_original_tx_gain_9280_2,
- ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6);
+ ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 5);
}
}
@@ -251,14 +251,14 @@ static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah)
if (AR_SREV_9287_11_OR_LATER(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9287Modes_rx_gain_9287_1_1,
- ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_1), 6);
+ ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_1), 5);
else if (AR_SREV_9280_20(ah))
ar9280_20_hw_init_rxgain_ini(ah);
if (AR_SREV_9287_11_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9287Modes_tx_gain_9287_1_1,
- ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 6);
+ ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 5);
} else if (AR_SREV_9280_20(ah)) {
ar9280_20_hw_init_txgain_ini(ah);
} else if (AR_SREV_9285_12_OR_LATER(ah)) {
@@ -270,24 +270,24 @@ static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah)
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9285Modes_XE2_0_high_power,
ARRAY_SIZE(
- ar9285Modes_XE2_0_high_power), 6);
+ ar9285Modes_XE2_0_high_power), 5);
} else {
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9285Modes_high_power_tx_gain_9285_1_2,
ARRAY_SIZE(
- ar9285Modes_high_power_tx_gain_9285_1_2), 6);
+ ar9285Modes_high_power_tx_gain_9285_1_2), 5);
}
} else {
if (AR_SREV_9285E_20(ah)) {
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9285Modes_XE2_0_normal_power,
ARRAY_SIZE(
- ar9285Modes_XE2_0_normal_power), 6);
+ ar9285Modes_XE2_0_normal_power), 5);
} else {
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9285Modes_original_tx_gain_9285_1_2,
ARRAY_SIZE(
- ar9285Modes_original_tx_gain_9285_1_2), 6);
+ ar9285Modes_original_tx_gain_9285_1_2), 5);
}
}
}
@@ -303,17 +303,13 @@ static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah)
* register as the other analog registers. Hence the 9 writes.
*/
static void ar9002_hw_configpcipowersave(struct ath_hw *ah,
- int restore,
- int power_off)
+ bool power_off)
{
u8 i;
u32 val;
- if (ah->is_pciexpress != true || ah->aspm_enabled != true)
- return;
-
/* Nothing to do on restore for 11N */
- if (!restore) {
+ if (!power_off /* !restore */) {
if (AR_SREV_9280_20_OR_LATER(ah)) {
/*
* AR9280 2.0 or later chips use SerDes values from the
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h
index 7573257731b6..863db321070d 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h
@@ -14,53 +14,54 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-static const u32 ar9280Modes_9280_2[][6] = {
- {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0},
- {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0},
- {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180},
- {0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008},
- {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0},
- {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f},
- {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810},
- {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a},
- {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880},
- {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303},
- {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
- {0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
- {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
- {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
- {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
- {0x00009840, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e, 0x206a012e},
- {0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0},
- {0x00009850, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2},
- {0x00009858, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
- {0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e},
- {0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18},
- {0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
- {0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
- {0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881},
- {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0},
- {0x00009918, 0x0000000a, 0x00000014, 0x00000268, 0x0000000b, 0x00000016},
- {0x00009924, 0xd00a8a0b, 0xd00a8a0b, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d},
- {0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010},
- {0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010},
- {0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010},
- {0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210},
- {0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce},
- {0x000099b8, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c},
- {0x000099bc, 0x00000a00, 0x00000a00, 0x00000c00, 0x00000c00, 0x00000c00},
- {0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
- {0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444},
- {0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019},
- {0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019},
- {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
- {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
- {0x0000a23c, 0x13c88000, 0x13c88000, 0x13c88001, 0x13c88000, 0x13c88000},
- {0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000, 0x0004a000},
- {0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e},
- {0x0000a388, 0x0c000000, 0x0c000000, 0x08000000, 0x0c000000, 0x0c000000},
- {0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000},
+static const u32 ar9280Modes_9280_2[][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},
+ {0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {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},
+ {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300},
+ {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
+ {0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+ {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
+ {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
+ {0x00009840, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e},
+ {0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
+ {0x00009850, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
+ {0x00009858, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e},
+ {0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e},
+ {0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20},
+ {0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+ {0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+ {0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
+ {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
+ {0x00009918, 0x0000000a, 0x00000014, 0x00000268, 0x0000000b},
+ {0x00009924, 0xd00a8a0b, 0xd00a8a0b, 0xd00a8a0d, 0xd00a8a0d},
+ {0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010},
+ {0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010},
+ {0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010},
+ {0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210},
+ {0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
+ {0x000099b8, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c},
+ {0x000099bc, 0x00000a00, 0x00000a00, 0x00000c00, 0x00000c00},
+ {0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+ {0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444},
+ {0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019},
+ {0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019},
+ {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+ {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
+ {0x0000a23c, 0x13c88000, 0x13c88000, 0x13c88001, 0x13c88000},
+ {0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000},
+ {0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e},
+ {0x0000a388, 0x0c000000, 0x0c000000, 0x08000000, 0x0c000000},
+ {0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000},
};
static const u32 ar9280Common_9280_2[][2] = {
@@ -424,471 +425,476 @@ static const u32 ar9280Modes_fast_clock_9280_2[][3] = {
{0x00009918, 0x0000000b, 0x00000016},
};
-static const u32 ar9280Modes_backoff_23db_rxgain_9280_2[][6] = {
- {0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290},
- {0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300},
- {0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304},
- {0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308},
- {0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c},
- {0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000},
- {0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004},
- {0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008},
- {0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c},
- {0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080},
- {0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084},
- {0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088},
- {0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c},
- {0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100},
- {0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104},
- {0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108},
- {0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c},
- {0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110},
- {0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114},
- {0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180},
- {0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184},
- {0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188},
- {0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c},
- {0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190},
- {0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194},
- {0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0},
- {0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c},
- {0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8},
- {0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284},
- {0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288},
- {0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224},
- {0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290},
- {0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300},
- {0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304},
- {0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308},
- {0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c},
- {0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380},
- {0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384},
- {0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700},
- {0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704},
- {0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708},
- {0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c},
- {0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780},
- {0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784},
- {0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00},
- {0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04},
- {0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08},
- {0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c},
- {0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b10, 0x00008b10, 0x00008b10},
- {0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b80, 0x00008b80, 0x00008b80},
- {0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b84, 0x00008b84, 0x00008b84},
- {0x00009acc, 0x0000b380, 0x0000b380, 0x00008b88, 0x00008b88, 0x00008b88},
- {0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b8c, 0x00008b8c, 0x00008b8c},
- {0x00009ad4, 0x0000b388, 0x0000b388, 0x00008b90, 0x00008b90, 0x00008b90},
- {0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008b94, 0x00008b94, 0x00008b94},
- {0x00009adc, 0x0000b390, 0x0000b390, 0x00008b98, 0x00008b98, 0x00008b98},
- {0x00009ae0, 0x0000b394, 0x0000b394, 0x00008ba4, 0x00008ba4, 0x00008ba4},
- {0x00009ae4, 0x0000b398, 0x0000b398, 0x00008ba8, 0x00008ba8, 0x00008ba8},
- {0x00009ae8, 0x0000b780, 0x0000b780, 0x00008bac, 0x00008bac, 0x00008bac},
- {0x00009aec, 0x0000b784, 0x0000b784, 0x00008bb0, 0x00008bb0, 0x00008bb0},
- {0x00009af0, 0x0000b788, 0x0000b788, 0x00008bb4, 0x00008bb4, 0x00008bb4},
- {0x00009af4, 0x0000b78c, 0x0000b78c, 0x00008ba1, 0x00008ba1, 0x00008ba1},
- {0x00009af8, 0x0000b790, 0x0000b790, 0x00008ba5, 0x00008ba5, 0x00008ba5},
- {0x00009afc, 0x0000b794, 0x0000b794, 0x00008ba9, 0x00008ba9, 0x00008ba9},
- {0x00009b00, 0x0000b798, 0x0000b798, 0x00008bad, 0x00008bad, 0x00008bad},
- {0x00009b04, 0x0000d784, 0x0000d784, 0x00008bb1, 0x00008bb1, 0x00008bb1},
- {0x00009b08, 0x0000d788, 0x0000d788, 0x00008bb5, 0x00008bb5, 0x00008bb5},
- {0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00008ba2, 0x00008ba2, 0x00008ba2},
- {0x00009b10, 0x0000d790, 0x0000d790, 0x00008ba6, 0x00008ba6, 0x00008ba6},
- {0x00009b14, 0x0000f780, 0x0000f780, 0x00008baa, 0x00008baa, 0x00008baa},
- {0x00009b18, 0x0000f784, 0x0000f784, 0x00008bae, 0x00008bae, 0x00008bae},
- {0x00009b1c, 0x0000f788, 0x0000f788, 0x00008bb2, 0x00008bb2, 0x00008bb2},
- {0x00009b20, 0x0000f78c, 0x0000f78c, 0x00008bb6, 0x00008bb6, 0x00008bb6},
- {0x00009b24, 0x0000f790, 0x0000f790, 0x00008ba3, 0x00008ba3, 0x00008ba3},
- {0x00009b28, 0x0000f794, 0x0000f794, 0x00008ba7, 0x00008ba7, 0x00008ba7},
- {0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x00008bab, 0x00008bab, 0x00008bab},
- {0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00008baf, 0x00008baf, 0x00008baf},
- {0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00008bb3, 0x00008bb3, 0x00008bb3},
- {0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00008bb7, 0x00008bb7, 0x00008bb7},
- {0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00008bc3, 0x00008bc3, 0x00008bc3},
- {0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x00008bc7, 0x00008bc7, 0x00008bc7},
- {0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x00008bcb, 0x00008bcb, 0x00008bcb},
- {0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00008bcf, 0x00008bcf, 0x00008bcf},
- {0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00008bd3, 0x00008bd3, 0x00008bd3},
- {0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00008bd7, 0x00008bd7, 0x00008bd7},
- {0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009b98, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009b9c, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009ba0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009ba4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009ba8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009bac, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009bb0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009bb4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009bb8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009bbc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009bc0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009bc4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009bc8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009bcc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009bd0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009bd4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009bd8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009bdc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009be0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009be4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009be8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009bec, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009bf0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009bf4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009bf8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009bfc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
- {0x00009848, 0x00001066, 0x00001066, 0x00001055, 0x00001055, 0x00001055},
- {0x0000a848, 0x00001066, 0x00001066, 0x00001055, 0x00001055, 0x00001055},
+static const u32 ar9280Modes_backoff_23db_rxgain_9280_2[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290},
+ {0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300},
+ {0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304},
+ {0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308},
+ {0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c},
+ {0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000},
+ {0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004},
+ {0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008},
+ {0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c},
+ {0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080},
+ {0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084},
+ {0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088},
+ {0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c},
+ {0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100},
+ {0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104},
+ {0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108},
+ {0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c},
+ {0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110},
+ {0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114},
+ {0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180},
+ {0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184},
+ {0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188},
+ {0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c},
+ {0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190},
+ {0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194},
+ {0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0},
+ {0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c},
+ {0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8},
+ {0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284},
+ {0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288},
+ {0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224},
+ {0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290},
+ {0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300},
+ {0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304},
+ {0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308},
+ {0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c},
+ {0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380},
+ {0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384},
+ {0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700},
+ {0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704},
+ {0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708},
+ {0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c},
+ {0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780},
+ {0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784},
+ {0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00},
+ {0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04},
+ {0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08},
+ {0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c},
+ {0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b10, 0x00008b10},
+ {0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b80, 0x00008b80},
+ {0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b84, 0x00008b84},
+ {0x00009acc, 0x0000b380, 0x0000b380, 0x00008b88, 0x00008b88},
+ {0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b8c, 0x00008b8c},
+ {0x00009ad4, 0x0000b388, 0x0000b388, 0x00008b90, 0x00008b90},
+ {0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008b94, 0x00008b94},
+ {0x00009adc, 0x0000b390, 0x0000b390, 0x00008b98, 0x00008b98},
+ {0x00009ae0, 0x0000b394, 0x0000b394, 0x00008ba4, 0x00008ba4},
+ {0x00009ae4, 0x0000b398, 0x0000b398, 0x00008ba8, 0x00008ba8},
+ {0x00009ae8, 0x0000b780, 0x0000b780, 0x00008bac, 0x00008bac},
+ {0x00009aec, 0x0000b784, 0x0000b784, 0x00008bb0, 0x00008bb0},
+ {0x00009af0, 0x0000b788, 0x0000b788, 0x00008bb4, 0x00008bb4},
+ {0x00009af4, 0x0000b78c, 0x0000b78c, 0x00008ba1, 0x00008ba1},
+ {0x00009af8, 0x0000b790, 0x0000b790, 0x00008ba5, 0x00008ba5},
+ {0x00009afc, 0x0000b794, 0x0000b794, 0x00008ba9, 0x00008ba9},
+ {0x00009b00, 0x0000b798, 0x0000b798, 0x00008bad, 0x00008bad},
+ {0x00009b04, 0x0000d784, 0x0000d784, 0x00008bb1, 0x00008bb1},
+ {0x00009b08, 0x0000d788, 0x0000d788, 0x00008bb5, 0x00008bb5},
+ {0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00008ba2, 0x00008ba2},
+ {0x00009b10, 0x0000d790, 0x0000d790, 0x00008ba6, 0x00008ba6},
+ {0x00009b14, 0x0000f780, 0x0000f780, 0x00008baa, 0x00008baa},
+ {0x00009b18, 0x0000f784, 0x0000f784, 0x00008bae, 0x00008bae},
+ {0x00009b1c, 0x0000f788, 0x0000f788, 0x00008bb2, 0x00008bb2},
+ {0x00009b20, 0x0000f78c, 0x0000f78c, 0x00008bb6, 0x00008bb6},
+ {0x00009b24, 0x0000f790, 0x0000f790, 0x00008ba3, 0x00008ba3},
+ {0x00009b28, 0x0000f794, 0x0000f794, 0x00008ba7, 0x00008ba7},
+ {0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x00008bab, 0x00008bab},
+ {0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00008baf, 0x00008baf},
+ {0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00008bb3, 0x00008bb3},
+ {0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00008bb7, 0x00008bb7},
+ {0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00008bc3, 0x00008bc3},
+ {0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x00008bc7, 0x00008bc7},
+ {0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x00008bcb, 0x00008bcb},
+ {0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00008bcf, 0x00008bcf},
+ {0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00008bd3, 0x00008bd3},
+ {0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00008bd7, 0x00008bd7},
+ {0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00008bdb, 0x00008bdb},
+ {0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x00008bdb, 0x00008bdb},
+ {0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x00008bdb, 0x00008bdb},
+ {0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00008bdb, 0x00008bdb},
+ {0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00008bdb, 0x00008bdb},
+ {0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x00008bdb, 0x00008bdb},
+ {0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x00008bdb, 0x00008bdb},
+ {0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x00008bdb, 0x00008bdb},
+ {0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x00008bdb, 0x00008bdb},
+ {0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x00008bdb, 0x00008bdb},
+ {0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x00008bdb, 0x00008bdb},
+ {0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x00008bdb, 0x00008bdb},
+ {0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x00008bdb, 0x00008bdb},
+ {0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x00008bdb, 0x00008bdb},
+ {0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x00008bdb, 0x00008bdb},
+ {0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x00008bdb, 0x00008bdb},
+ {0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x00008bdb, 0x00008bdb},
+ {0x00009b98, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009b9c, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009ba0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009ba4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009ba8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009bac, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009bb0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009bb4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009bb8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009bbc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009bc0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009bc4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009bc8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009bcc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009bd0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009bd4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009bd8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009bdc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009be0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009be4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009be8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009bec, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009bf0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009bf4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009bf8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009bfc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb},
+ {0x00009848, 0x00001066, 0x00001066, 0x00001055, 0x00001055},
+ {0x0000a848, 0x00001066, 0x00001066, 0x00001055, 0x00001055},
};
-static const u32 ar9280Modes_original_rxgain_9280_2[][6] = {
- {0x00009a00, 0x00008184, 0x00008184, 0x00008000, 0x00008000, 0x00008000},
- {0x00009a04, 0x00008188, 0x00008188, 0x00008000, 0x00008000, 0x00008000},
- {0x00009a08, 0x0000818c, 0x0000818c, 0x00008000, 0x00008000, 0x00008000},
- {0x00009a0c, 0x00008190, 0x00008190, 0x00008000, 0x00008000, 0x00008000},
- {0x00009a10, 0x00008194, 0x00008194, 0x00008000, 0x00008000, 0x00008000},
- {0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000},
- {0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004},
- {0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008},
- {0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c},
- {0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080},
- {0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084},
- {0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088},
- {0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c},
- {0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100},
- {0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104},
- {0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108},
- {0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c},
- {0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110},
- {0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114},
- {0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180},
- {0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184},
- {0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188},
- {0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c},
- {0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190},
- {0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194},
- {0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0},
- {0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c},
- {0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8},
- {0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284},
- {0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288},
- {0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224},
- {0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290},
- {0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300},
- {0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304},
- {0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308},
- {0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c},
- {0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380},
- {0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384},
- {0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700},
- {0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704},
- {0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708},
- {0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c},
- {0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780},
- {0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784},
- {0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00},
- {0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04},
- {0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08},
- {0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c},
- {0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80},
- {0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84},
- {0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88},
- {0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c},
- {0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90},
- {0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80},
- {0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84},
- {0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88},
- {0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c},
- {0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90},
- {0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c},
- {0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310},
- {0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384},
- {0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388},
- {0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324},
- {0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704},
- {0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4},
- {0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8},
- {0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710},
- {0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714},
- {0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720},
- {0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724},
- {0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728},
- {0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c},
- {0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0},
- {0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4},
- {0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8},
- {0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0},
- {0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4},
- {0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8},
- {0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5},
- {0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9},
- {0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad},
- {0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1},
- {0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5},
- {0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9},
- {0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5},
- {0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9},
- {0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1},
- {0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5},
- {0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9},
- {0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6},
- {0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca},
- {0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce},
- {0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2},
- {0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6},
- {0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3},
- {0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7},
- {0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb},
- {0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf},
- {0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7},
- {0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db},
- {0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db},
- {0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db},
- {0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
- {0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063},
- {0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063},
+static const u32 ar9280Modes_original_rxgain_9280_2[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00009a00, 0x00008184, 0x00008184, 0x00008000, 0x00008000},
+ {0x00009a04, 0x00008188, 0x00008188, 0x00008000, 0x00008000},
+ {0x00009a08, 0x0000818c, 0x0000818c, 0x00008000, 0x00008000},
+ {0x00009a0c, 0x00008190, 0x00008190, 0x00008000, 0x00008000},
+ {0x00009a10, 0x00008194, 0x00008194, 0x00008000, 0x00008000},
+ {0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000},
+ {0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004},
+ {0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008},
+ {0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c},
+ {0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080},
+ {0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084},
+ {0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088},
+ {0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c},
+ {0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100},
+ {0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104},
+ {0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108},
+ {0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c},
+ {0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110},
+ {0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114},
+ {0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180},
+ {0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184},
+ {0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188},
+ {0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c},
+ {0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190},
+ {0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194},
+ {0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0},
+ {0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c},
+ {0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8},
+ {0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284},
+ {0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288},
+ {0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224},
+ {0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290},
+ {0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300},
+ {0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304},
+ {0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308},
+ {0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c},
+ {0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380},
+ {0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384},
+ {0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700},
+ {0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704},
+ {0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708},
+ {0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c},
+ {0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780},
+ {0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784},
+ {0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00},
+ {0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04},
+ {0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08},
+ {0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c},
+ {0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80},
+ {0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84},
+ {0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88},
+ {0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c},
+ {0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90},
+ {0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80},
+ {0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84},
+ {0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88},
+ {0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c},
+ {0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90},
+ {0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c},
+ {0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310},
+ {0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384},
+ {0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388},
+ {0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324},
+ {0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704},
+ {0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4},
+ {0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8},
+ {0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710},
+ {0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714},
+ {0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720},
+ {0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724},
+ {0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728},
+ {0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c},
+ {0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0},
+ {0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4},
+ {0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8},
+ {0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0},
+ {0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4},
+ {0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8},
+ {0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5},
+ {0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9},
+ {0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad},
+ {0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1},
+ {0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5},
+ {0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9},
+ {0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5},
+ {0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9},
+ {0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1},
+ {0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5},
+ {0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9},
+ {0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6},
+ {0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca},
+ {0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce},
+ {0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2},
+ {0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6},
+ {0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3},
+ {0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7},
+ {0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb},
+ {0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf},
+ {0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7},
+ {0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db},
+ {0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db},
+ {0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db},
+ {0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db},
+ {0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063},
+ {0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063},
};
-static const u32 ar9280Modes_backoff_13db_rxgain_9280_2[][6] = {
- {0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290},
- {0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300},
- {0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304},
- {0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308},
- {0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c},
- {0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000},
- {0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004},
- {0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008},
- {0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c},
- {0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080},
- {0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084},
- {0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088},
- {0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c},
- {0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100},
- {0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104},
- {0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108},
- {0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c},
- {0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110},
- {0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114},
- {0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180},
- {0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184},
- {0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188},
- {0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c},
- {0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190},
- {0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194},
- {0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0},
- {0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c},
- {0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8},
- {0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284},
- {0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288},
- {0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224},
- {0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290},
- {0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300},
- {0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304},
- {0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308},
- {0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c},
- {0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380},
- {0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384},
- {0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700},
- {0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704},
- {0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708},
- {0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c},
- {0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780},
- {0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784},
- {0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00},
- {0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04},
- {0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08},
- {0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c},
- {0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80},
- {0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84},
- {0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88},
- {0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c},
- {0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90},
- {0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80},
- {0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84},
- {0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88},
- {0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c},
- {0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90},
- {0x00009ae8, 0x0000b780, 0x0000b780, 0x00009310, 0x00009310, 0x00009310},
- {0x00009aec, 0x0000b784, 0x0000b784, 0x00009314, 0x00009314, 0x00009314},
- {0x00009af0, 0x0000b788, 0x0000b788, 0x00009320, 0x00009320, 0x00009320},
- {0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009324, 0x00009324, 0x00009324},
- {0x00009af8, 0x0000b790, 0x0000b790, 0x00009328, 0x00009328, 0x00009328},
- {0x00009afc, 0x0000b794, 0x0000b794, 0x0000932c, 0x0000932c, 0x0000932c},
- {0x00009b00, 0x0000b798, 0x0000b798, 0x00009330, 0x00009330, 0x00009330},
- {0x00009b04, 0x0000d784, 0x0000d784, 0x00009334, 0x00009334, 0x00009334},
- {0x00009b08, 0x0000d788, 0x0000d788, 0x00009321, 0x00009321, 0x00009321},
- {0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009325, 0x00009325, 0x00009325},
- {0x00009b10, 0x0000d790, 0x0000d790, 0x00009329, 0x00009329, 0x00009329},
- {0x00009b14, 0x0000f780, 0x0000f780, 0x0000932d, 0x0000932d, 0x0000932d},
- {0x00009b18, 0x0000f784, 0x0000f784, 0x00009331, 0x00009331, 0x00009331},
- {0x00009b1c, 0x0000f788, 0x0000f788, 0x00009335, 0x00009335, 0x00009335},
- {0x00009b20, 0x0000f78c, 0x0000f78c, 0x00009322, 0x00009322, 0x00009322},
- {0x00009b24, 0x0000f790, 0x0000f790, 0x00009326, 0x00009326, 0x00009326},
- {0x00009b28, 0x0000f794, 0x0000f794, 0x0000932a, 0x0000932a, 0x0000932a},
- {0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x0000932e, 0x0000932e, 0x0000932e},
- {0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00009332, 0x00009332, 0x00009332},
- {0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00009336, 0x00009336, 0x00009336},
- {0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00009323, 0x00009323, 0x00009323},
- {0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00009327, 0x00009327, 0x00009327},
- {0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x0000932b, 0x0000932b, 0x0000932b},
- {0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x0000932f, 0x0000932f, 0x0000932f},
- {0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00009333, 0x00009333, 0x00009333},
- {0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00009337, 0x00009337, 0x00009337},
- {0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00009343, 0x00009343, 0x00009343},
- {0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00009347, 0x00009347, 0x00009347},
- {0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x0000934b, 0x0000934b, 0x0000934b},
- {0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x0000934f, 0x0000934f, 0x0000934f},
- {0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00009353, 0x00009353, 0x00009353},
- {0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00009357, 0x00009357, 0x00009357},
- {0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009b98, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009b9c, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009ba0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009ba4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009ba8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009bac, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009bb0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009bb4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009bb8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009bbc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009bc0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009bc4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009bc8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009bcc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009bd0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009bd4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009bd8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009bdc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009be0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009be4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009be8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009bec, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009bf0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009bf4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009bf8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009bfc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
- {0x00009848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a},
- {0x0000a848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a},
+static const u32 ar9280Modes_backoff_13db_rxgain_9280_2[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290},
+ {0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300},
+ {0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304},
+ {0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308},
+ {0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c},
+ {0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000},
+ {0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004},
+ {0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008},
+ {0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c},
+ {0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080},
+ {0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084},
+ {0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088},
+ {0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c},
+ {0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100},
+ {0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104},
+ {0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108},
+ {0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c},
+ {0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110},
+ {0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114},
+ {0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180},
+ {0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184},
+ {0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188},
+ {0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c},
+ {0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190},
+ {0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194},
+ {0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0},
+ {0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c},
+ {0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8},
+ {0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284},
+ {0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288},
+ {0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224},
+ {0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290},
+ {0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300},
+ {0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304},
+ {0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308},
+ {0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c},
+ {0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380},
+ {0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384},
+ {0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700},
+ {0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704},
+ {0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708},
+ {0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c},
+ {0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780},
+ {0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784},
+ {0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00},
+ {0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04},
+ {0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08},
+ {0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c},
+ {0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80},
+ {0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84},
+ {0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88},
+ {0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c},
+ {0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90},
+ {0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80},
+ {0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84},
+ {0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88},
+ {0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c},
+ {0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90},
+ {0x00009ae8, 0x0000b780, 0x0000b780, 0x00009310, 0x00009310},
+ {0x00009aec, 0x0000b784, 0x0000b784, 0x00009314, 0x00009314},
+ {0x00009af0, 0x0000b788, 0x0000b788, 0x00009320, 0x00009320},
+ {0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009324, 0x00009324},
+ {0x00009af8, 0x0000b790, 0x0000b790, 0x00009328, 0x00009328},
+ {0x00009afc, 0x0000b794, 0x0000b794, 0x0000932c, 0x0000932c},
+ {0x00009b00, 0x0000b798, 0x0000b798, 0x00009330, 0x00009330},
+ {0x00009b04, 0x0000d784, 0x0000d784, 0x00009334, 0x00009334},
+ {0x00009b08, 0x0000d788, 0x0000d788, 0x00009321, 0x00009321},
+ {0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009325, 0x00009325},
+ {0x00009b10, 0x0000d790, 0x0000d790, 0x00009329, 0x00009329},
+ {0x00009b14, 0x0000f780, 0x0000f780, 0x0000932d, 0x0000932d},
+ {0x00009b18, 0x0000f784, 0x0000f784, 0x00009331, 0x00009331},
+ {0x00009b1c, 0x0000f788, 0x0000f788, 0x00009335, 0x00009335},
+ {0x00009b20, 0x0000f78c, 0x0000f78c, 0x00009322, 0x00009322},
+ {0x00009b24, 0x0000f790, 0x0000f790, 0x00009326, 0x00009326},
+ {0x00009b28, 0x0000f794, 0x0000f794, 0x0000932a, 0x0000932a},
+ {0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x0000932e, 0x0000932e},
+ {0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00009332, 0x00009332},
+ {0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00009336, 0x00009336},
+ {0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00009323, 0x00009323},
+ {0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00009327, 0x00009327},
+ {0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x0000932b, 0x0000932b},
+ {0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x0000932f, 0x0000932f},
+ {0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00009333, 0x00009333},
+ {0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00009337, 0x00009337},
+ {0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00009343, 0x00009343},
+ {0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00009347, 0x00009347},
+ {0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x0000934b, 0x0000934b},
+ {0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x0000934f, 0x0000934f},
+ {0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00009353, 0x00009353},
+ {0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00009357, 0x00009357},
+ {0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x0000935b, 0x0000935b},
+ {0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x0000935b, 0x0000935b},
+ {0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x0000935b, 0x0000935b},
+ {0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x0000935b, 0x0000935b},
+ {0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x0000935b, 0x0000935b},
+ {0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x0000935b, 0x0000935b},
+ {0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x0000935b, 0x0000935b},
+ {0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x0000935b, 0x0000935b},
+ {0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x0000935b, 0x0000935b},
+ {0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x0000935b, 0x0000935b},
+ {0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x0000935b, 0x0000935b},
+ {0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x0000935b, 0x0000935b},
+ {0x00009b98, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009b9c, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009ba0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009ba4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009ba8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009bac, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009bb0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009bb4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009bb8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009bbc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009bc0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009bc4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009bc8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009bcc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009bd0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009bd4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009bd8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009bdc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009be0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009be4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009be8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009bec, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009bf0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009bf4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009bf8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009bfc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b},
+ {0x00009848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a},
+ {0x0000a848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a},
};
-static const u32 ar9280Modes_high_power_tx_gain_9280_2[][6] = {
- {0x0000a274, 0x0a19e652, 0x0a19e652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652},
- {0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce},
- {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a304, 0x00003002, 0x00003002, 0x00004002, 0x00004002, 0x00004002},
- {0x0000a308, 0x00006004, 0x00006004, 0x00007008, 0x00007008, 0x00007008},
- {0x0000a30c, 0x0000a006, 0x0000a006, 0x0000c010, 0x0000c010, 0x0000c010},
- {0x0000a310, 0x0000e012, 0x0000e012, 0x00010012, 0x00010012, 0x00010012},
- {0x0000a314, 0x00011014, 0x00011014, 0x00013014, 0x00013014, 0x00013014},
- {0x0000a318, 0x0001504a, 0x0001504a, 0x0001820a, 0x0001820a, 0x0001820a},
- {0x0000a31c, 0x0001904c, 0x0001904c, 0x0001b211, 0x0001b211, 0x0001b211},
- {0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213},
- {0x0000a324, 0x00021092, 0x00021092, 0x00022411, 0x00022411, 0x00022411},
- {0x0000a328, 0x0002510a, 0x0002510a, 0x00025413, 0x00025413, 0x00025413},
- {0x0000a32c, 0x0002910c, 0x0002910c, 0x00029811, 0x00029811, 0x00029811},
- {0x0000a330, 0x0002c18b, 0x0002c18b, 0x0002c813, 0x0002c813, 0x0002c813},
- {0x0000a334, 0x0002f1cc, 0x0002f1cc, 0x00030a14, 0x00030a14, 0x00030a14},
- {0x0000a338, 0x000321eb, 0x000321eb, 0x00035a50, 0x00035a50, 0x00035a50},
- {0x0000a33c, 0x000341ec, 0x000341ec, 0x00039c4c, 0x00039c4c, 0x00039c4c},
- {0x0000a340, 0x000341ec, 0x000341ec, 0x0003de8a, 0x0003de8a, 0x0003de8a},
- {0x0000a344, 0x000341ec, 0x000341ec, 0x00042e92, 0x00042e92, 0x00042e92},
- {0x0000a348, 0x000341ec, 0x000341ec, 0x00046ed2, 0x00046ed2, 0x00046ed2},
- {0x0000a34c, 0x000341ec, 0x000341ec, 0x0004bed5, 0x0004bed5, 0x0004bed5},
- {0x0000a350, 0x000341ec, 0x000341ec, 0x0004ff54, 0x0004ff54, 0x0004ff54},
- {0x0000a354, 0x000341ec, 0x000341ec, 0x00055fd5, 0x00055fd5, 0x00055fd5},
- {0x0000a3ec, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081},
- {0x00007814, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff},
- {0x00007838, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff},
- {0x0000781c, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000},
- {0x00007840, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000},
- {0x00007820, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480},
- {0x00007844, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480},
+static const u32 ar9280Modes_high_power_tx_gain_9280_2[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a274, 0x0a19e652, 0x0a19e652, 0x0a1aa652, 0x0a1aa652},
+ {0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce},
+ {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a304, 0x00003002, 0x00003002, 0x00004002, 0x00004002},
+ {0x0000a308, 0x00006004, 0x00006004, 0x00007008, 0x00007008},
+ {0x0000a30c, 0x0000a006, 0x0000a006, 0x0000c010, 0x0000c010},
+ {0x0000a310, 0x0000e012, 0x0000e012, 0x00010012, 0x00010012},
+ {0x0000a314, 0x00011014, 0x00011014, 0x00013014, 0x00013014},
+ {0x0000a318, 0x0001504a, 0x0001504a, 0x0001820a, 0x0001820a},
+ {0x0000a31c, 0x0001904c, 0x0001904c, 0x0001b211, 0x0001b211},
+ {0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213},
+ {0x0000a324, 0x00021092, 0x00021092, 0x00022411, 0x00022411},
+ {0x0000a328, 0x0002510a, 0x0002510a, 0x00025413, 0x00025413},
+ {0x0000a32c, 0x0002910c, 0x0002910c, 0x00029811, 0x00029811},
+ {0x0000a330, 0x0002c18b, 0x0002c18b, 0x0002c813, 0x0002c813},
+ {0x0000a334, 0x0002f1cc, 0x0002f1cc, 0x00030a14, 0x00030a14},
+ {0x0000a338, 0x000321eb, 0x000321eb, 0x00035a50, 0x00035a50},
+ {0x0000a33c, 0x000341ec, 0x000341ec, 0x00039c4c, 0x00039c4c},
+ {0x0000a340, 0x000341ec, 0x000341ec, 0x0003de8a, 0x0003de8a},
+ {0x0000a344, 0x000341ec, 0x000341ec, 0x00042e92, 0x00042e92},
+ {0x0000a348, 0x000341ec, 0x000341ec, 0x00046ed2, 0x00046ed2},
+ {0x0000a34c, 0x000341ec, 0x000341ec, 0x0004bed5, 0x0004bed5},
+ {0x0000a350, 0x000341ec, 0x000341ec, 0x0004ff54, 0x0004ff54},
+ {0x0000a354, 0x000341ec, 0x000341ec, 0x00055fd5, 0x00055fd5},
+ {0x0000a3ec, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081},
+ {0x00007814, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff},
+ {0x00007838, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff},
+ {0x0000781c, 0x00172000, 0x00172000, 0x00172000, 0x00172000},
+ {0x00007840, 0x00172000, 0x00172000, 0x00172000, 0x00172000},
+ {0x00007820, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480},
+ {0x00007844, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480},
};
-static const u32 ar9280Modes_original_tx_gain_9280_2[][6] = {
- {0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652},
- {0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce},
- {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002},
- {0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009},
- {0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b},
- {0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012},
- {0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048},
- {0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a},
- {0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211},
- {0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213},
- {0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b},
- {0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412},
- {0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414},
- {0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a},
- {0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649},
- {0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b},
- {0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49},
- {0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48},
- {0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a},
- {0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88},
- {0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a},
- {0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9},
- {0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42},
- {0x0000a3ec, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081},
- {0x00007814, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff},
- {0x00007838, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff},
- {0x0000781c, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000},
- {0x00007840, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000},
- {0x00007820, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480},
- {0x00007844, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480},
+static const u32 ar9280Modes_original_tx_gain_9280_2[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652},
+ {0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce},
+ {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002},
+ {0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009},
+ {0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b},
+ {0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012},
+ {0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048},
+ {0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a},
+ {0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211},
+ {0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213},
+ {0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b},
+ {0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412},
+ {0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414},
+ {0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a},
+ {0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649},
+ {0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b},
+ {0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49},
+ {0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48},
+ {0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a},
+ {0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88},
+ {0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a},
+ {0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9},
+ {0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42},
+ {0x0000a3ec, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081},
+ {0x00007814, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff},
+ {0x00007838, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff},
+ {0x0000781c, 0x00392000, 0x00392000, 0x00392000, 0x00392000},
+ {0x00007840, 0x00392000, 0x00392000, 0x00392000, 0x00392000},
+ {0x00007820, 0x92592480, 0x92592480, 0x92592480, 0x92592480},
+ {0x00007844, 0x92592480, 0x92592480, 0x92592480, 0x92592480},
};
static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = {
@@ -947,309 +953,310 @@ static const u32 ar9285PciePhy_clkreq_off_L1_9285[][2] = {
{0x00004044, 0x00000000},
};
-static const u32 ar9285Modes_9285_1_2[][6] = {
- {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0},
- {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0},
- {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180},
- {0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008},
- {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0},
- {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f},
- {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880},
- {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303},
- {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
- {0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
- {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
- {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
- {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
- {0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e},
- {0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0},
- {0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059},
- {0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059},
- {0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2},
- {0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
- {0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e},
- {0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20, 0x00058d18},
- {0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
- {0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
- {0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881},
- {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0},
- {0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016},
- {0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d},
- {0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020, 0xffbc1010},
- {0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c},
- {0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00},
- {0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
- {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
- {0x000099c8, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f},
- {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
- {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
- {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x00009a00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000},
- {0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000},
- {0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000},
- {0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000},
- {0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000},
- {0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000},
- {0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000},
- {0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000},
- {0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000},
- {0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000},
- {0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000},
- {0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000},
- {0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000},
- {0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000},
- {0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000},
- {0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000},
- {0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000},
- {0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000},
- {0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000},
- {0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000},
- {0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000},
- {0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000},
- {0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000},
- {0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000},
- {0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000},
- {0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000},
- {0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000},
- {0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000},
- {0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000},
- {0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000},
- {0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000},
- {0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000},
- {0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000},
- {0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000},
- {0x00009a88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000},
- {0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000},
- {0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000},
- {0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000},
- {0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000},
- {0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000},
- {0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000},
- {0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000},
- {0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000},
- {0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000},
- {0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000},
- {0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000},
- {0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000},
- {0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000},
- {0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000},
- {0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000},
- {0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000},
- {0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000},
- {0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000},
- {0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000},
- {0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000},
- {0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000},
- {0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000},
- {0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000},
- {0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000},
- {0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000},
- {0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000},
- {0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000},
- {0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000},
- {0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000},
- {0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000},
- {0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000},
- {0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000},
- {0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000},
- {0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000},
- {0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000},
- {0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000},
- {0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000},
- {0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000},
- {0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000},
- {0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000},
- {0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000},
- {0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000},
- {0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000},
- {0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000},
- {0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000},
- {0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000},
- {0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000},
- {0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000},
- {0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000},
- {0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000},
- {0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000},
- {0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000},
- {0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000},
- {0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000},
- {0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000},
- {0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000},
- {0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000},
- {0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000},
- {0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000},
- {0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000},
- {0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000},
- {0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000},
- {0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000},
- {0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000},
- {0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000},
- {0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000},
- {0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000},
- {0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000},
- {0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000},
- {0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000},
- {0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000},
- {0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000},
- {0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000},
- {0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000},
- {0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000},
- {0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000},
- {0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000},
- {0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000},
- {0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000},
- {0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000},
- {0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000},
- {0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000},
- {0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000},
- {0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000},
- {0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000},
- {0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000},
- {0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000},
- {0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000},
- {0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000},
- {0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000},
- {0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000},
- {0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000},
- {0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000},
- {0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000},
- {0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000},
- {0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000},
- {0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000},
- {0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000},
- {0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000},
- {0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000},
- {0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000},
- {0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000},
- {0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000},
- {0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000},
- {0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000},
- {0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000},
- {0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000},
- {0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000},
- {0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000},
- {0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000},
- {0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000},
- {0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000},
- {0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000},
- {0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000},
- {0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000},
- {0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000},
- {0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000},
- {0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000},
- {0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000},
- {0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000},
- {0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000},
- {0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000},
- {0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000},
- {0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000},
- {0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000},
- {0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000},
- {0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000},
- {0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000},
- {0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000},
- {0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000},
- {0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000},
- {0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000},
- {0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000},
- {0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000},
- {0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000},
- {0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000},
- {0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000},
- {0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000},
- {0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000},
- {0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000},
- {0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000},
- {0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000},
- {0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000},
- {0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004},
- {0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000},
- {0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000},
- {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
- {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
- {0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000},
- {0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e},
+static const u32 ar9285Modes_9285_1_2[][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},
+ {0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
+ {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b},
+ {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
+ {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300},
+ {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
+ {0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+ {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
+ {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
+ {0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e},
+ {0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620},
+ {0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053},
+ {0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053},
+ {0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2},
+ {0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
+ {0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e},
+ {0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20},
+ {0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00},
+ {0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+ {0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
+ {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
+ {0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
+ {0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d},
+ {0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020},
+ {0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c},
+ {0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00},
+ {0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+ {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
+ {0x000099c8, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f},
+ {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
+ {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
+ {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00009a00, 0x00000000, 0x00000000, 0x00058084, 0x00058084},
+ {0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088},
+ {0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c},
+ {0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100},
+ {0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104},
+ {0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108},
+ {0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c},
+ {0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110},
+ {0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114},
+ {0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180},
+ {0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184},
+ {0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188},
+ {0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c},
+ {0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190},
+ {0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194},
+ {0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0},
+ {0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c},
+ {0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8},
+ {0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284},
+ {0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288},
+ {0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224},
+ {0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290},
+ {0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300},
+ {0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304},
+ {0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308},
+ {0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c},
+ {0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380},
+ {0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384},
+ {0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700},
+ {0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704},
+ {0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708},
+ {0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c},
+ {0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780},
+ {0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784},
+ {0x00009a88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00},
+ {0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04},
+ {0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08},
+ {0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c},
+ {0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80},
+ {0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84},
+ {0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88},
+ {0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c},
+ {0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90},
+ {0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80},
+ {0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84},
+ {0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88},
+ {0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c},
+ {0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90},
+ {0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c},
+ {0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310},
+ {0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384},
+ {0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388},
+ {0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324},
+ {0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704},
+ {0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4},
+ {0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8},
+ {0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710},
+ {0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714},
+ {0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720},
+ {0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724},
+ {0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728},
+ {0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c},
+ {0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0},
+ {0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4},
+ {0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8},
+ {0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0},
+ {0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4},
+ {0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8},
+ {0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5},
+ {0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9},
+ {0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad},
+ {0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1},
+ {0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5},
+ {0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9},
+ {0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5},
+ {0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9},
+ {0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1},
+ {0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5},
+ {0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9},
+ {0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6},
+ {0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca},
+ {0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce},
+ {0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2},
+ {0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6},
+ {0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3},
+ {0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7},
+ {0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb},
+ {0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf},
+ {0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7},
+ {0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084},
+ {0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088},
+ {0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c},
+ {0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100},
+ {0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104},
+ {0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108},
+ {0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c},
+ {0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110},
+ {0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114},
+ {0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180},
+ {0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184},
+ {0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188},
+ {0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c},
+ {0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190},
+ {0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194},
+ {0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0},
+ {0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c},
+ {0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8},
+ {0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284},
+ {0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288},
+ {0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224},
+ {0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290},
+ {0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300},
+ {0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304},
+ {0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308},
+ {0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c},
+ {0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380},
+ {0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384},
+ {0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700},
+ {0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704},
+ {0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708},
+ {0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c},
+ {0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780},
+ {0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784},
+ {0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00},
+ {0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04},
+ {0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08},
+ {0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c},
+ {0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80},
+ {0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84},
+ {0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88},
+ {0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c},
+ {0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90},
+ {0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80},
+ {0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84},
+ {0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88},
+ {0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c},
+ {0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90},
+ {0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c},
+ {0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310},
+ {0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384},
+ {0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388},
+ {0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324},
+ {0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704},
+ {0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4},
+ {0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8},
+ {0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710},
+ {0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714},
+ {0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720},
+ {0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724},
+ {0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728},
+ {0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c},
+ {0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0},
+ {0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4},
+ {0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8},
+ {0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0},
+ {0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4},
+ {0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8},
+ {0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5},
+ {0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9},
+ {0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad},
+ {0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1},
+ {0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5},
+ {0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9},
+ {0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5},
+ {0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9},
+ {0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1},
+ {0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5},
+ {0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9},
+ {0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6},
+ {0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca},
+ {0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce},
+ {0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2},
+ {0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6},
+ {0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3},
+ {0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7},
+ {0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb},
+ {0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf},
+ {0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7},
+ {0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004},
+ {0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000},
+ {0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000},
+ {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+ {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
+ {0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000},
+ {0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e},
};
static const u32 ar9285Common_9285_1_2[][2] = {
@@ -1572,164 +1579,168 @@ static const u32 ar9285Common_9285_1_2[][2] = {
{0x00007870, 0x10142c00},
};
-static const u32 ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
- {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000},
- {0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000},
- {0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000},
- {0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000},
- {0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000},
- {0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000},
- {0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000},
- {0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000},
- {0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000},
- {0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000},
- {0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000},
- {0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000},
- {0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000},
- {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
- {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
- {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8},
- {0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b},
- {0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e},
- {0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803},
- {0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe},
- {0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20},
- {0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe},
- {0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00},
- {0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652},
- {0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
- {0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7},
- {0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
- {0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7},
- {0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
- {0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7},
+static const u32 ar9285Modes_high_power_tx_gain_9285_1_2[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200},
+ {0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201},
+ {0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240},
+ {0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241},
+ {0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600},
+ {0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800},
+ {0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802},
+ {0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805},
+ {0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80},
+ {0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00},
+ {0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40},
+ {0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80},
+ {0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82},
+ {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e},
+ {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e},
+ {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8},
+ {0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b},
+ {0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e},
+ {0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803},
+ {0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe},
+ {0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20},
+ {0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe},
+ {0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00},
+ {0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652},
+ {0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+ {0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7},
+ {0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+ {0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7},
+ {0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+ {0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7},
};
-static const u32 ar9285Modes_original_tx_gain_9285_1_2[][6] = {
- {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000},
- {0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000},
- {0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000},
- {0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618, 0x00000000},
- {0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9, 0x00000000},
- {0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710, 0x00000000},
- {0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718, 0x00000000},
- {0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758, 0x00000000},
- {0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a, 0x00000000},
- {0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c, 0x00000000},
- {0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e, 0x00000000},
- {0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f, 0x00000000},
- {0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df, 0x00000000},
- {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
- {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
- {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8},
- {0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b},
- {0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e},
- {0x00007838, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801},
- {0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe},
- {0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20},
- {0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4},
- {0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04},
- {0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652},
- {0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
- {0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c},
- {0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
- {0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c},
- {0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
- {0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c},
+static const u32 ar9285Modes_original_tx_gain_9285_1_2[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200},
+ {0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208},
+ {0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608},
+ {0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618},
+ {0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9},
+ {0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710},
+ {0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718},
+ {0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758},
+ {0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a},
+ {0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c},
+ {0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e},
+ {0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f},
+ {0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df},
+ {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e},
+ {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e},
+ {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8},
+ {0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b},
+ {0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e},
+ {0x00007838, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801},
+ {0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe},
+ {0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20},
+ {0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4},
+ {0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04},
+ {0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652},
+ {0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+ {0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c},
+ {0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+ {0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c},
+ {0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+ {0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c},
};
-static const u32 ar9285Modes_XE2_0_normal_power[][6] = {
- {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000},
- {0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000},
- {0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000},
- {0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618, 0x00000000},
- {0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9, 0x00000000},
- {0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710, 0x00000000},
- {0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718, 0x00000000},
- {0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758, 0x00000000},
- {0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a, 0x00000000},
- {0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c, 0x00000000},
- {0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e, 0x00000000},
- {0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f, 0x00000000},
- {0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df, 0x00000000},
- {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
- {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
- {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8},
- {0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b, 0x4ad2491b},
- {0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6dbae},
- {0x00007838, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441},
- {0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe},
- {0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c},
- {0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4},
- {0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04},
- {0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652},
- {0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
- {0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c},
- {0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
- {0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c},
- {0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
- {0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c},
+static const u32 ar9285Modes_XE2_0_normal_power[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200},
+ {0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208},
+ {0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608},
+ {0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618},
+ {0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9},
+ {0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710},
+ {0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718},
+ {0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758},
+ {0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a},
+ {0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c},
+ {0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e},
+ {0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f},
+ {0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df},
+ {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e},
+ {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e},
+ {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8},
+ {0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b},
+ {0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e},
+ {0x00007838, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441},
+ {0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe},
+ {0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c},
+ {0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4},
+ {0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04},
+ {0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652},
+ {0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+ {0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c},
+ {0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+ {0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c},
+ {0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+ {0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c},
};
-static const u32 ar9285Modes_XE2_0_high_power[][6] = {
- {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000},
- {0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000},
- {0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000},
- {0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000},
- {0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000},
- {0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000},
- {0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000},
- {0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000},
- {0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000},
- {0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000},
- {0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000},
- {0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000},
- {0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000},
- {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
- {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
- {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8},
- {0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b, 0x4ad2491b},
- {0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e},
- {0x00007838, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443},
- {0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe},
- {0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c},
- {0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe},
- {0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00},
- {0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652},
- {0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
- {0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7},
- {0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
- {0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7},
- {0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
- {0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7},
+static const u32 ar9285Modes_XE2_0_high_power[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200},
+ {0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201},
+ {0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240},
+ {0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241},
+ {0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600},
+ {0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800},
+ {0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802},
+ {0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805},
+ {0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80},
+ {0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00},
+ {0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40},
+ {0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80},
+ {0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82},
+ {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e},
+ {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e},
+ {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8},
+ {0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b},
+ {0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e},
+ {0x00007838, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443},
+ {0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe},
+ {0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c},
+ {0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe},
+ {0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00},
+ {0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652},
+ {0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+ {0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7},
+ {0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+ {0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7},
+ {0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+ {0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7},
};
static const u32 ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = {
@@ -1760,50 +1771,51 @@ static const u32 ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = {
{0x00004044, 0x00000000},
};
-static const u32 ar9287Modes_9287_1_1[][6] = {
- {0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160, 0x000001e0},
- {0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c, 0x000001e0},
- {0x000010b0, 0x00000000, 0x00000000, 0x00007c70, 0x00003e38, 0x00001180},
- {0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008},
- {0x00008014, 0x00000000, 0x00000000, 0x10801600, 0x08400b00, 0x06e006e0},
- {0x0000801c, 0x00000000, 0x00000000, 0x12e00057, 0x12e0002b, 0x0988004f},
- {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810},
- {0x000081d0, 0x00003200, 0x00003200, 0x0000320a, 0x0000320a, 0x0000320a},
- {0x00008318, 0x00000000, 0x00000000, 0x00006880, 0x00003440, 0x00006880},
- {0x00009804, 0x00000000, 0x00000000, 0x000003c4, 0x00000300, 0x00000303},
- {0x00009820, 0x00000000, 0x00000000, 0x02020200, 0x02020200, 0x02020200},
- {0x00009824, 0x00000000, 0x00000000, 0x01000e0e, 0x01000e0e, 0x01000e0e},
- {0x00009828, 0x00000000, 0x00000000, 0x3a020001, 0x3a020001, 0x3a020001},
- {0x00009834, 0x00000000, 0x00000000, 0x00000e0e, 0x00000e0e, 0x00000e0e},
- {0x00009838, 0x00000003, 0x00000003, 0x00000007, 0x00000007, 0x00000007},
- {0x00009840, 0x206a002e, 0x206a002e, 0x206a012e, 0x206a012e, 0x206a012e},
- {0x00009844, 0x03720000, 0x03720000, 0x037216a0, 0x037216a0, 0x037216a0},
- {0x00009850, 0x60000000, 0x60000000, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2},
- {0x00009858, 0x7c000d00, 0x7c000d00, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
- {0x0000985c, 0x3100005e, 0x3100005e, 0x3139605e, 0x31395d5e, 0x31395d5e},
- {0x00009860, 0x00058d00, 0x00058d00, 0x00058d20, 0x00058d20, 0x00058d18},
- {0x00009864, 0x00000e00, 0x00000e00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
- {0x00009868, 0x000040c0, 0x000040c0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
- {0x0000986c, 0x00000080, 0x00000080, 0x06903881, 0x06903881, 0x06903881},
- {0x00009914, 0x00000000, 0x00000000, 0x00001130, 0x00000898, 0x000007d0},
- {0x00009918, 0x00000000, 0x00000000, 0x00000016, 0x0000000b, 0x00000016},
- {0x00009924, 0xd00a8a01, 0xd00a8a01, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d},
- {0x00009944, 0xefbc0000, 0xefbc0000, 0xefbc1010, 0xefbc1010, 0xefbc1010},
- {0x00009960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010},
- {0x0000a960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010},
- {0x00009964, 0x00000000, 0x00000000, 0x00000210, 0x00000210, 0x00000210},
- {0x0000c968, 0x00000200, 0x00000200, 0x000003ce, 0x000003ce, 0x000003ce},
- {0x000099b8, 0x00000000, 0x00000000, 0x0000001c, 0x0000001c, 0x0000001c},
- {0x000099bc, 0x00000000, 0x00000000, 0x00000c00, 0x00000c00, 0x00000c00},
- {0x000099c0, 0x00000000, 0x00000000, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
- {0x0000a204, 0x00000440, 0x00000440, 0x00000444, 0x00000444, 0x00000444},
- {0x0000a20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000b20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a21c, 0x1803800a, 0x1803800a, 0x1883800a, 0x1883800a, 0x1883800a},
- {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
- {0x0000a250, 0x00000000, 0x00000000, 0x0004a000, 0x0004a000, 0x0004a000},
- {0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e},
- {0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+static const u32 ar9287Modes_9287_1_1[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160},
+ {0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c},
+ {0x000010b0, 0x00000000, 0x00000000, 0x00007c70, 0x00003e38},
+ {0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00008014, 0x00000000, 0x00000000, 0x10801600, 0x08400b00},
+ {0x0000801c, 0x00000000, 0x00000000, 0x12e00057, 0x12e0002b},
+ {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810},
+ {0x000081d0, 0x00003200, 0x00003200, 0x0000320a, 0x0000320a},
+ {0x00008318, 0x00000000, 0x00000000, 0x00006880, 0x00003440},
+ {0x00009804, 0x00000000, 0x00000000, 0x000003c4, 0x00000300},
+ {0x00009820, 0x00000000, 0x00000000, 0x02020200, 0x02020200},
+ {0x00009824, 0x00000000, 0x00000000, 0x01000e0e, 0x01000e0e},
+ {0x00009828, 0x00000000, 0x00000000, 0x3a020001, 0x3a020001},
+ {0x00009834, 0x00000000, 0x00000000, 0x00000e0e, 0x00000e0e},
+ {0x00009838, 0x00000003, 0x00000003, 0x00000007, 0x00000007},
+ {0x00009840, 0x206a002e, 0x206a002e, 0x206a012e, 0x206a012e},
+ {0x00009844, 0x03720000, 0x03720000, 0x037216a0, 0x037216a0},
+ {0x00009850, 0x60000000, 0x60000000, 0x6d4000e2, 0x6c4000e2},
+ {0x00009858, 0x7c000d00, 0x7c000d00, 0x7ec84d2e, 0x7ec84d2e},
+ {0x0000985c, 0x3100005e, 0x3100005e, 0x3139605e, 0x31395d5e},
+ {0x00009860, 0x00058d00, 0x00058d00, 0x00058d20, 0x00058d20},
+ {0x00009864, 0x00000e00, 0x00000e00, 0x0001ce00, 0x0001ce00},
+ {0x00009868, 0x000040c0, 0x000040c0, 0x5ac640d0, 0x5ac640d0},
+ {0x0000986c, 0x00000080, 0x00000080, 0x06903881, 0x06903881},
+ {0x00009914, 0x00000000, 0x00000000, 0x00001130, 0x00000898},
+ {0x00009918, 0x00000000, 0x00000000, 0x00000016, 0x0000000b},
+ {0x00009924, 0xd00a8a01, 0xd00a8a01, 0xd00a8a0d, 0xd00a8a0d},
+ {0x00009944, 0xefbc0000, 0xefbc0000, 0xefbc1010, 0xefbc1010},
+ {0x00009960, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
+ {0x0000a960, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
+ {0x00009964, 0x00000000, 0x00000000, 0x00000210, 0x00000210},
+ {0x0000c968, 0x00000200, 0x00000200, 0x000003ce, 0x000003ce},
+ {0x000099b8, 0x00000000, 0x00000000, 0x0000001c, 0x0000001c},
+ {0x000099bc, 0x00000000, 0x00000000, 0x00000c00, 0x00000c00},
+ {0x000099c0, 0x00000000, 0x00000000, 0x05eea6d4, 0x05eea6d4},
+ {0x0000a204, 0x00000440, 0x00000440, 0x00000444, 0x00000444},
+ {0x0000a20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000b20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a21c, 0x1803800a, 0x1803800a, 0x1883800a, 0x1883800a},
+ {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
+ {0x0000a250, 0x00000000, 0x00000000, 0x0004a000, 0x0004a000},
+ {0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e},
+ {0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
};
static const u32 ar9287Common_9287_1_1[][2] = {
@@ -2189,313 +2201,315 @@ static const u32 ar9287Common_japan_2484_cck_fir_coeff_9287_1_1[][2] = {
{0x0000a1fc, 0xca9228ee},
};
-static const u32 ar9287Modes_tx_gain_9287_1_1[][6] = {
- {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002, 0x00004002},
- {0x0000a308, 0x00000000, 0x00000000, 0x00008004, 0x00008004, 0x00008004},
- {0x0000a30c, 0x00000000, 0x00000000, 0x0000c00a, 0x0000c00a, 0x0000c00a},
- {0x0000a310, 0x00000000, 0x00000000, 0x0001000c, 0x0001000c, 0x0001000c},
- {0x0000a314, 0x00000000, 0x00000000, 0x0001420b, 0x0001420b, 0x0001420b},
- {0x0000a318, 0x00000000, 0x00000000, 0x0001824a, 0x0001824a, 0x0001824a},
- {0x0000a31c, 0x00000000, 0x00000000, 0x0001c44a, 0x0001c44a, 0x0001c44a},
- {0x0000a320, 0x00000000, 0x00000000, 0x0002064a, 0x0002064a, 0x0002064a},
- {0x0000a324, 0x00000000, 0x00000000, 0x0002484a, 0x0002484a, 0x0002484a},
- {0x0000a328, 0x00000000, 0x00000000, 0x00028a4a, 0x00028a4a, 0x00028a4a},
- {0x0000a32c, 0x00000000, 0x00000000, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a},
- {0x0000a330, 0x00000000, 0x00000000, 0x00030e4a, 0x00030e4a, 0x00030e4a},
- {0x0000a334, 0x00000000, 0x00000000, 0x00034e8a, 0x00034e8a, 0x00034e8a},
- {0x0000a338, 0x00000000, 0x00000000, 0x00038e8c, 0x00038e8c, 0x00038e8c},
- {0x0000a33c, 0x00000000, 0x00000000, 0x0003cecc, 0x0003cecc, 0x0003cecc},
- {0x0000a340, 0x00000000, 0x00000000, 0x00040ed4, 0x00040ed4, 0x00040ed4},
- {0x0000a344, 0x00000000, 0x00000000, 0x00044edc, 0x00044edc, 0x00044edc},
- {0x0000a348, 0x00000000, 0x00000000, 0x00048ede, 0x00048ede, 0x00048ede},
- {0x0000a34c, 0x00000000, 0x00000000, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e},
- {0x0000a350, 0x00000000, 0x00000000, 0x00050f5e, 0x00050f5e, 0x00050f5e},
- {0x0000a354, 0x00000000, 0x00000000, 0x00054f9e, 0x00054f9e, 0x00054f9e},
- {0x0000a780, 0x00000000, 0x00000000, 0x00000062, 0x00000062, 0x00000062},
- {0x0000a784, 0x00000000, 0x00000000, 0x00004064, 0x00004064, 0x00004064},
- {0x0000a788, 0x00000000, 0x00000000, 0x000080a4, 0x000080a4, 0x000080a4},
- {0x0000a78c, 0x00000000, 0x00000000, 0x0000c0aa, 0x0000c0aa, 0x0000c0aa},
- {0x0000a790, 0x00000000, 0x00000000, 0x000100ac, 0x000100ac, 0x000100ac},
- {0x0000a794, 0x00000000, 0x00000000, 0x000140b4, 0x000140b4, 0x000140b4},
- {0x0000a798, 0x00000000, 0x00000000, 0x000180f4, 0x000180f4, 0x000180f4},
- {0x0000a79c, 0x00000000, 0x00000000, 0x0001c134, 0x0001c134, 0x0001c134},
- {0x0000a7a0, 0x00000000, 0x00000000, 0x00020174, 0x00020174, 0x00020174},
- {0x0000a7a4, 0x00000000, 0x00000000, 0x0002417c, 0x0002417c, 0x0002417c},
- {0x0000a7a8, 0x00000000, 0x00000000, 0x0002817e, 0x0002817e, 0x0002817e},
- {0x0000a7ac, 0x00000000, 0x00000000, 0x0002c1be, 0x0002c1be, 0x0002c1be},
- {0x0000a7b0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
- {0x0000a7b4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
- {0x0000a7b8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
- {0x0000a7bc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
- {0x0000a7c0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
- {0x0000a7c4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
- {0x0000a7c8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
- {0x0000a7cc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
- {0x0000a7d0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
- {0x0000a7d4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
- {0x0000a274, 0x0a180000, 0x0a180000, 0x0a1aa000, 0x0a1aa000, 0x0a1aa000},
+static const u32 ar9287Modes_tx_gain_9287_1_1[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002},
+ {0x0000a308, 0x00000000, 0x00000000, 0x00008004, 0x00008004},
+ {0x0000a30c, 0x00000000, 0x00000000, 0x0000c00a, 0x0000c00a},
+ {0x0000a310, 0x00000000, 0x00000000, 0x0001000c, 0x0001000c},
+ {0x0000a314, 0x00000000, 0x00000000, 0x0001420b, 0x0001420b},
+ {0x0000a318, 0x00000000, 0x00000000, 0x0001824a, 0x0001824a},
+ {0x0000a31c, 0x00000000, 0x00000000, 0x0001c44a, 0x0001c44a},
+ {0x0000a320, 0x00000000, 0x00000000, 0x0002064a, 0x0002064a},
+ {0x0000a324, 0x00000000, 0x00000000, 0x0002484a, 0x0002484a},
+ {0x0000a328, 0x00000000, 0x00000000, 0x00028a4a, 0x00028a4a},
+ {0x0000a32c, 0x00000000, 0x00000000, 0x0002cc4a, 0x0002cc4a},
+ {0x0000a330, 0x00000000, 0x00000000, 0x00030e4a, 0x00030e4a},
+ {0x0000a334, 0x00000000, 0x00000000, 0x00034e8a, 0x00034e8a},
+ {0x0000a338, 0x00000000, 0x00000000, 0x00038e8c, 0x00038e8c},
+ {0x0000a33c, 0x00000000, 0x00000000, 0x0003cecc, 0x0003cecc},
+ {0x0000a340, 0x00000000, 0x00000000, 0x00040ed4, 0x00040ed4},
+ {0x0000a344, 0x00000000, 0x00000000, 0x00044edc, 0x00044edc},
+ {0x0000a348, 0x00000000, 0x00000000, 0x00048ede, 0x00048ede},
+ {0x0000a34c, 0x00000000, 0x00000000, 0x0004cf1e, 0x0004cf1e},
+ {0x0000a350, 0x00000000, 0x00000000, 0x00050f5e, 0x00050f5e},
+ {0x0000a354, 0x00000000, 0x00000000, 0x00054f9e, 0x00054f9e},
+ {0x0000a780, 0x00000000, 0x00000000, 0x00000062, 0x00000062},
+ {0x0000a784, 0x00000000, 0x00000000, 0x00004064, 0x00004064},
+ {0x0000a788, 0x00000000, 0x00000000, 0x000080a4, 0x000080a4},
+ {0x0000a78c, 0x00000000, 0x00000000, 0x0000c0aa, 0x0000c0aa},
+ {0x0000a790, 0x00000000, 0x00000000, 0x000100ac, 0x000100ac},
+ {0x0000a794, 0x00000000, 0x00000000, 0x000140b4, 0x000140b4},
+ {0x0000a798, 0x00000000, 0x00000000, 0x000180f4, 0x000180f4},
+ {0x0000a79c, 0x00000000, 0x00000000, 0x0001c134, 0x0001c134},
+ {0x0000a7a0, 0x00000000, 0x00000000, 0x00020174, 0x00020174},
+ {0x0000a7a4, 0x00000000, 0x00000000, 0x0002417c, 0x0002417c},
+ {0x0000a7a8, 0x00000000, 0x00000000, 0x0002817e, 0x0002817e},
+ {0x0000a7ac, 0x00000000, 0x00000000, 0x0002c1be, 0x0002c1be},
+ {0x0000a7b0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe},
+ {0x0000a7b4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe},
+ {0x0000a7b8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe},
+ {0x0000a7bc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe},
+ {0x0000a7c0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe},
+ {0x0000a7c4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe},
+ {0x0000a7c8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe},
+ {0x0000a7cc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe},
+ {0x0000a7d0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe},
+ {0x0000a7d4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe},
+ {0x0000a274, 0x0a180000, 0x0a180000, 0x0a1aa000, 0x0a1aa000},
};
-static const u32 ar9287Modes_rx_gain_9287_1_1[][6] = {
- {0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120},
- {0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124},
- {0x00009a08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128},
- {0x00009a0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c},
- {0x00009a10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130},
- {0x00009a14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194},
- {0x00009a18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198},
- {0x00009a1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c},
- {0x00009a20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210},
- {0x00009a24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284},
- {0x00009a28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288},
- {0x00009a2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c},
- {0x00009a30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290},
- {0x00009a34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294},
- {0x00009a38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0},
- {0x00009a3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4},
- {0x00009a40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8},
- {0x00009a44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac},
- {0x00009a48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0},
- {0x00009a4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4},
- {0x00009a50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8},
- {0x00009a54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4},
- {0x00009a58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708},
- {0x00009a5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c},
- {0x00009a60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710},
- {0x00009a64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04},
- {0x00009a68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08},
- {0x00009a6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c},
- {0x00009a70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10},
- {0x00009a74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14},
- {0x00009a78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18},
- {0x00009a7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c},
- {0x00009a80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90},
- {0x00009a84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94},
- {0x00009a88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98},
- {0x00009a8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4},
- {0x00009a90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8},
- {0x00009a94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04},
- {0x00009a98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08},
- {0x00009a9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c},
- {0x00009aa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10},
- {0x00009aa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14},
- {0x00009aa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18},
- {0x00009aac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c},
- {0x00009ab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90},
- {0x00009ab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18},
- {0x00009ab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24},
- {0x00009abc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28},
- {0x00009ac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314},
- {0x00009ac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318},
- {0x00009ac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c},
- {0x00009acc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390},
- {0x00009ad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394},
- {0x00009ad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398},
- {0x00009ad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4},
- {0x00009adc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8},
- {0x00009ae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac},
- {0x00009ae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0},
- {0x00009ae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380},
- {0x00009aec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384},
- {0x00009af0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388},
- {0x00009af4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710},
- {0x00009af8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714},
- {0x00009afc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718},
- {0x00009b00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10},
- {0x00009b04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14},
- {0x00009b08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18},
- {0x00009b0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c},
- {0x00009b10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90},
- {0x00009b14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94},
- {0x00009b18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c},
- {0x00009b1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90},
- {0x00009b20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94},
- {0x00009b24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0},
- {0x00009b28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4},
- {0x00009b2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8},
- {0x00009b30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac},
- {0x00009b34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0},
- {0x00009b38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4},
- {0x00009b3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1},
- {0x00009b40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5},
- {0x00009b44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9},
- {0x00009b48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad},
- {0x00009b4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1},
- {0x00009b50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5},
- {0x00009b54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9},
- {0x00009b58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5},
- {0x00009b5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9},
- {0x00009b60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd},
- {0x00009b64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1},
- {0x00009b68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5},
- {0x00009b6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2},
- {0x00009b70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6},
- {0x00009b74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca},
- {0x00009b78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce},
- {0x00009b7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2},
- {0x00009b80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6},
- {0x00009b84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda},
- {0x00009b88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7},
- {0x00009b8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb},
- {0x00009b90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf},
- {0x00009b94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3},
- {0x00009b98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7},
- {0x00009b9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009ba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009ba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009ba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009bac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009bb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009bb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009bb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009bbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009bc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009bc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009bc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009bcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009bd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009bd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009bd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009bdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009be0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009be4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009be8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009bec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009bf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009bf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009bf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009bfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000aa00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120},
- {0x0000aa04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124},
- {0x0000aa08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128},
- {0x0000aa0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c},
- {0x0000aa10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130},
- {0x0000aa14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194},
- {0x0000aa18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198},
- {0x0000aa1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c},
- {0x0000aa20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210},
- {0x0000aa24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284},
- {0x0000aa28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288},
- {0x0000aa2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c},
- {0x0000aa30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290},
- {0x0000aa34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294},
- {0x0000aa38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0},
- {0x0000aa3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4},
- {0x0000aa40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8},
- {0x0000aa44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac},
- {0x0000aa48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0},
- {0x0000aa4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4},
- {0x0000aa50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8},
- {0x0000aa54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4},
- {0x0000aa58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708},
- {0x0000aa5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c},
- {0x0000aa60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710},
- {0x0000aa64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04},
- {0x0000aa68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08},
- {0x0000aa6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c},
- {0x0000aa70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10},
- {0x0000aa74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14},
- {0x0000aa78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18},
- {0x0000aa7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c},
- {0x0000aa80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90},
- {0x0000aa84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94},
- {0x0000aa88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98},
- {0x0000aa8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4},
- {0x0000aa90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8},
- {0x0000aa94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04},
- {0x0000aa98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08},
- {0x0000aa9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c},
- {0x0000aaa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10},
- {0x0000aaa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14},
- {0x0000aaa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18},
- {0x0000aaac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c},
- {0x0000aab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90},
- {0x0000aab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18},
- {0x0000aab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24},
- {0x0000aabc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28},
- {0x0000aac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314},
- {0x0000aac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318},
- {0x0000aac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c},
- {0x0000aacc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390},
- {0x0000aad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394},
- {0x0000aad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398},
- {0x0000aad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4},
- {0x0000aadc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8},
- {0x0000aae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac},
- {0x0000aae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0},
- {0x0000aae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380},
- {0x0000aaec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384},
- {0x0000aaf0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388},
- {0x0000aaf4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710},
- {0x0000aaf8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714},
- {0x0000aafc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718},
- {0x0000ab00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10},
- {0x0000ab04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14},
- {0x0000ab08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18},
- {0x0000ab0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c},
- {0x0000ab10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90},
- {0x0000ab14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94},
- {0x0000ab18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c},
- {0x0000ab1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90},
- {0x0000ab20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94},
- {0x0000ab24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0},
- {0x0000ab28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4},
- {0x0000ab2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8},
- {0x0000ab30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac},
- {0x0000ab34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0},
- {0x0000ab38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4},
- {0x0000ab3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1},
- {0x0000ab40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5},
- {0x0000ab44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9},
- {0x0000ab48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad},
- {0x0000ab4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1},
- {0x0000ab50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5},
- {0x0000ab54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9},
- {0x0000ab58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5},
- {0x0000ab5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9},
- {0x0000ab60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd},
- {0x0000ab64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1},
- {0x0000ab68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5},
- {0x0000ab6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2},
- {0x0000ab70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6},
- {0x0000ab74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca},
- {0x0000ab78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce},
- {0x0000ab7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2},
- {0x0000ab80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6},
- {0x0000ab84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda},
- {0x0000ab88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7},
- {0x0000ab8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb},
- {0x0000ab90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf},
- {0x0000ab94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3},
- {0x0000ab98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7},
- {0x0000ab9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000aba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000aba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000aba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000abac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000abb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000abb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000abb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000abbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000abc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000abc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000abc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000abcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000abd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000abd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000abd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000abdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000abe0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000abe4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000abe8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000abec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000abf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000abf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000abf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x0000abfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
- {0x00009848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067},
- {0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067},
+static const u32 ar9287Modes_rx_gain_9287_1_1[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120},
+ {0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124},
+ {0x00009a08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128},
+ {0x00009a0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c},
+ {0x00009a10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130},
+ {0x00009a14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194},
+ {0x00009a18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198},
+ {0x00009a1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c},
+ {0x00009a20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210},
+ {0x00009a24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284},
+ {0x00009a28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288},
+ {0x00009a2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c},
+ {0x00009a30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290},
+ {0x00009a34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294},
+ {0x00009a38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0},
+ {0x00009a3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4},
+ {0x00009a40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8},
+ {0x00009a44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac},
+ {0x00009a48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0},
+ {0x00009a4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4},
+ {0x00009a50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8},
+ {0x00009a54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4},
+ {0x00009a58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708},
+ {0x00009a5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c},
+ {0x00009a60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710},
+ {0x00009a64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04},
+ {0x00009a68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08},
+ {0x00009a6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c},
+ {0x00009a70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10},
+ {0x00009a74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14},
+ {0x00009a78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18},
+ {0x00009a7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c},
+ {0x00009a80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90},
+ {0x00009a84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94},
+ {0x00009a88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98},
+ {0x00009a8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4},
+ {0x00009a90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8},
+ {0x00009a94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04},
+ {0x00009a98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08},
+ {0x00009a9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c},
+ {0x00009aa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10},
+ {0x00009aa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14},
+ {0x00009aa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18},
+ {0x00009aac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c},
+ {0x00009ab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90},
+ {0x00009ab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18},
+ {0x00009ab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24},
+ {0x00009abc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28},
+ {0x00009ac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314},
+ {0x00009ac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318},
+ {0x00009ac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c},
+ {0x00009acc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390},
+ {0x00009ad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394},
+ {0x00009ad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398},
+ {0x00009ad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4},
+ {0x00009adc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8},
+ {0x00009ae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac},
+ {0x00009ae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0},
+ {0x00009ae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380},
+ {0x00009aec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384},
+ {0x00009af0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388},
+ {0x00009af4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710},
+ {0x00009af8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714},
+ {0x00009afc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718},
+ {0x00009b00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10},
+ {0x00009b04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14},
+ {0x00009b08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18},
+ {0x00009b0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c},
+ {0x00009b10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90},
+ {0x00009b14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94},
+ {0x00009b18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c},
+ {0x00009b1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90},
+ {0x00009b20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94},
+ {0x00009b24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0},
+ {0x00009b28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4},
+ {0x00009b2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8},
+ {0x00009b30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac},
+ {0x00009b34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0},
+ {0x00009b38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4},
+ {0x00009b3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1},
+ {0x00009b40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5},
+ {0x00009b44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9},
+ {0x00009b48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad},
+ {0x00009b4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1},
+ {0x00009b50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5},
+ {0x00009b54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9},
+ {0x00009b58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5},
+ {0x00009b5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9},
+ {0x00009b60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd},
+ {0x00009b64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1},
+ {0x00009b68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5},
+ {0x00009b6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2},
+ {0x00009b70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6},
+ {0x00009b74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca},
+ {0x00009b78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce},
+ {0x00009b7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2},
+ {0x00009b80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6},
+ {0x00009b84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda},
+ {0x00009b88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7},
+ {0x00009b8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb},
+ {0x00009b90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf},
+ {0x00009b94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3},
+ {0x00009b98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7},
+ {0x00009b9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009ba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009ba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009ba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009be0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009be4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009be8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000aa00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120},
+ {0x0000aa04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124},
+ {0x0000aa08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128},
+ {0x0000aa0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c},
+ {0x0000aa10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130},
+ {0x0000aa14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194},
+ {0x0000aa18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198},
+ {0x0000aa1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c},
+ {0x0000aa20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210},
+ {0x0000aa24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284},
+ {0x0000aa28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288},
+ {0x0000aa2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c},
+ {0x0000aa30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290},
+ {0x0000aa34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294},
+ {0x0000aa38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0},
+ {0x0000aa3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4},
+ {0x0000aa40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8},
+ {0x0000aa44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac},
+ {0x0000aa48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0},
+ {0x0000aa4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4},
+ {0x0000aa50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8},
+ {0x0000aa54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4},
+ {0x0000aa58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708},
+ {0x0000aa5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c},
+ {0x0000aa60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710},
+ {0x0000aa64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04},
+ {0x0000aa68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08},
+ {0x0000aa6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c},
+ {0x0000aa70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10},
+ {0x0000aa74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14},
+ {0x0000aa78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18},
+ {0x0000aa7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c},
+ {0x0000aa80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90},
+ {0x0000aa84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94},
+ {0x0000aa88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98},
+ {0x0000aa8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4},
+ {0x0000aa90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8},
+ {0x0000aa94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04},
+ {0x0000aa98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08},
+ {0x0000aa9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c},
+ {0x0000aaa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10},
+ {0x0000aaa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14},
+ {0x0000aaa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18},
+ {0x0000aaac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c},
+ {0x0000aab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90},
+ {0x0000aab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18},
+ {0x0000aab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24},
+ {0x0000aabc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28},
+ {0x0000aac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314},
+ {0x0000aac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318},
+ {0x0000aac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c},
+ {0x0000aacc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390},
+ {0x0000aad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394},
+ {0x0000aad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398},
+ {0x0000aad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4},
+ {0x0000aadc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8},
+ {0x0000aae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac},
+ {0x0000aae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0},
+ {0x0000aae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380},
+ {0x0000aaec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384},
+ {0x0000aaf0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388},
+ {0x0000aaf4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710},
+ {0x0000aaf8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714},
+ {0x0000aafc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718},
+ {0x0000ab00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10},
+ {0x0000ab04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14},
+ {0x0000ab08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18},
+ {0x0000ab0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c},
+ {0x0000ab10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90},
+ {0x0000ab14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94},
+ {0x0000ab18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c},
+ {0x0000ab1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90},
+ {0x0000ab20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94},
+ {0x0000ab24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0},
+ {0x0000ab28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4},
+ {0x0000ab2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8},
+ {0x0000ab30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac},
+ {0x0000ab34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0},
+ {0x0000ab38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4},
+ {0x0000ab3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1},
+ {0x0000ab40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5},
+ {0x0000ab44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9},
+ {0x0000ab48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad},
+ {0x0000ab4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1},
+ {0x0000ab50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5},
+ {0x0000ab54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9},
+ {0x0000ab58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5},
+ {0x0000ab5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9},
+ {0x0000ab60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd},
+ {0x0000ab64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1},
+ {0x0000ab68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5},
+ {0x0000ab6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2},
+ {0x0000ab70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6},
+ {0x0000ab74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca},
+ {0x0000ab78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce},
+ {0x0000ab7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2},
+ {0x0000ab80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6},
+ {0x0000ab84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda},
+ {0x0000ab88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7},
+ {0x0000ab8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb},
+ {0x0000ab90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf},
+ {0x0000ab94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3},
+ {0x0000ab98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7},
+ {0x0000ab9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000aba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000aba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000aba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abe0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abe4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abe8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb},
+ {0x00009848, 0x00000000, 0x00000000, 0x00001067, 0x00001067},
+ {0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067},
};
static const u32 ar9287PciePhy_clkreq_always_on_L1_9287_1_1[][2] = {
@@ -2526,310 +2540,311 @@ static const u32 ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = {
{0x00004044, 0x00000000},
};
-static const u32 ar9271Modes_9271[][6] = {
- {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0},
- {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0},
- {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180},
- {0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008},
- {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0},
- {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f},
- {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880},
- {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303},
- {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
- {0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
- {0x00009828, 0x3a020001, 0x3a020001, 0x3a020001, 0x3a020001, 0x3a020001},
- {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
- {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
- {0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e},
- {0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0},
- {0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059},
- {0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059},
- {0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2},
- {0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
- {0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e},
- {0x00009860, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18},
- {0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
- {0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
- {0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881},
- {0x00009910, 0x30002310, 0x30002310, 0x30002310, 0x30002310, 0x30002310},
- {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0},
- {0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016},
- {0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d},
- {0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020, 0xffbc1010},
- {0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c},
- {0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00},
- {0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
- {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
- {0x000099c8, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f},
- {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
- {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
- {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x00009a00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000},
- {0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000},
- {0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000},
- {0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000},
- {0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000},
- {0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000},
- {0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000},
- {0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000},
- {0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000},
- {0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000},
- {0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000},
- {0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000},
- {0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000},
- {0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000},
- {0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000},
- {0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000},
- {0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000},
- {0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000},
- {0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000},
- {0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000},
- {0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000},
- {0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000},
- {0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000},
- {0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000},
- {0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000},
- {0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000},
- {0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000},
- {0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000},
- {0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000},
- {0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000},
- {0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000},
- {0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000},
- {0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000},
- {0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000},
- {0x00009a88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000},
- {0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000},
- {0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000},
- {0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000},
- {0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000},
- {0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000},
- {0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000},
- {0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000},
- {0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000},
- {0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000},
- {0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000},
- {0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000},
- {0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000},
- {0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000},
- {0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000},
- {0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000},
- {0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000},
- {0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000},
- {0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000},
- {0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000},
- {0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000},
- {0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000},
- {0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000},
- {0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000},
- {0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000},
- {0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000},
- {0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000},
- {0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000},
- {0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000},
- {0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000},
- {0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000},
- {0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000},
- {0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000},
- {0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000},
- {0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000},
- {0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000},
- {0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000},
- {0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000},
- {0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000},
- {0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000},
- {0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000},
- {0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000},
- {0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000},
- {0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000},
- {0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000},
- {0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000},
- {0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000},
- {0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000},
- {0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000},
- {0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000},
- {0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000},
- {0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000},
- {0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000},
- {0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000},
- {0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000},
- {0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000},
- {0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000},
- {0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000},
- {0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000},
- {0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000},
- {0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000},
- {0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000},
- {0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000},
- {0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000},
- {0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000},
- {0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000},
- {0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000},
- {0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000},
- {0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000},
- {0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000},
- {0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000},
- {0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000},
- {0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000},
- {0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000},
- {0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000},
- {0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000},
- {0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000},
- {0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000},
- {0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000},
- {0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000},
- {0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000},
- {0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000},
- {0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000},
- {0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000},
- {0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000},
- {0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000},
- {0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000},
- {0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000},
- {0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000},
- {0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000},
- {0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000},
- {0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000},
- {0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000},
- {0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000},
- {0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000},
- {0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000},
- {0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000},
- {0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000},
- {0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000},
- {0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000},
- {0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000},
- {0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000},
- {0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000},
- {0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000},
- {0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000},
- {0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000},
- {0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000},
- {0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000},
- {0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000},
- {0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000},
- {0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000},
- {0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000},
- {0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000},
- {0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000},
- {0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000},
- {0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000},
- {0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000},
- {0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000},
- {0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000},
- {0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000},
- {0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000},
- {0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000},
- {0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000},
- {0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000},
- {0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000},
- {0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000},
- {0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000},
- {0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000},
- {0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000},
- {0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000},
- {0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000},
- {0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000},
- {0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000},
- {0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000},
- {0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000},
- {0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000},
- {0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000},
- {0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000},
- {0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000},
- {0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000},
- {0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000},
- {0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000},
- {0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000},
- {0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000},
- {0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
- {0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004},
- {0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000},
- {0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000},
- {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
- {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
- {0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000},
- {0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e},
+static const u32 ar9271Modes_9271[][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},
+ {0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
+ {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b},
+ {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
+ {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300},
+ {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
+ {0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+ {0x00009828, 0x3a020001, 0x3a020001, 0x3a020001, 0x3a020001},
+ {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
+ {0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e},
+ {0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620},
+ {0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053},
+ {0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053},
+ {0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2},
+ {0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
+ {0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e},
+ {0x00009860, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18},
+ {0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00},
+ {0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+ {0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
+ {0x00009910, 0x30002310, 0x30002310, 0x30002310, 0x30002310},
+ {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
+ {0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
+ {0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d},
+ {0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020},
+ {0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c},
+ {0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00},
+ {0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+ {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
+ {0x000099c8, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f},
+ {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
+ {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
+ {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00009a00, 0x00000000, 0x00000000, 0x00058084, 0x00058084},
+ {0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088},
+ {0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c},
+ {0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100},
+ {0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104},
+ {0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108},
+ {0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c},
+ {0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110},
+ {0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114},
+ {0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180},
+ {0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184},
+ {0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188},
+ {0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c},
+ {0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190},
+ {0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194},
+ {0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0},
+ {0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c},
+ {0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8},
+ {0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284},
+ {0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288},
+ {0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224},
+ {0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290},
+ {0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300},
+ {0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304},
+ {0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308},
+ {0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c},
+ {0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380},
+ {0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384},
+ {0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700},
+ {0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704},
+ {0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708},
+ {0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c},
+ {0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780},
+ {0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784},
+ {0x00009a88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00},
+ {0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04},
+ {0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08},
+ {0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c},
+ {0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80},
+ {0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84},
+ {0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88},
+ {0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c},
+ {0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90},
+ {0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80},
+ {0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84},
+ {0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88},
+ {0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c},
+ {0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90},
+ {0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c},
+ {0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310},
+ {0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384},
+ {0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388},
+ {0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324},
+ {0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704},
+ {0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4},
+ {0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8},
+ {0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710},
+ {0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714},
+ {0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720},
+ {0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724},
+ {0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728},
+ {0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c},
+ {0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0},
+ {0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4},
+ {0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8},
+ {0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0},
+ {0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4},
+ {0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8},
+ {0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5},
+ {0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9},
+ {0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad},
+ {0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1},
+ {0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5},
+ {0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9},
+ {0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5},
+ {0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9},
+ {0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1},
+ {0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5},
+ {0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9},
+ {0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6},
+ {0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca},
+ {0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce},
+ {0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2},
+ {0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6},
+ {0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3},
+ {0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7},
+ {0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb},
+ {0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf},
+ {0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7},
+ {0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084},
+ {0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088},
+ {0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c},
+ {0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100},
+ {0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104},
+ {0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108},
+ {0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c},
+ {0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110},
+ {0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114},
+ {0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180},
+ {0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184},
+ {0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188},
+ {0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c},
+ {0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190},
+ {0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194},
+ {0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0},
+ {0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c},
+ {0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8},
+ {0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284},
+ {0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288},
+ {0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224},
+ {0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290},
+ {0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300},
+ {0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304},
+ {0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308},
+ {0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c},
+ {0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380},
+ {0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384},
+ {0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700},
+ {0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704},
+ {0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708},
+ {0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c},
+ {0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780},
+ {0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784},
+ {0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00},
+ {0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04},
+ {0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08},
+ {0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c},
+ {0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80},
+ {0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84},
+ {0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88},
+ {0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c},
+ {0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90},
+ {0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80},
+ {0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84},
+ {0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88},
+ {0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c},
+ {0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90},
+ {0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c},
+ {0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310},
+ {0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384},
+ {0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388},
+ {0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324},
+ {0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704},
+ {0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4},
+ {0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8},
+ {0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710},
+ {0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714},
+ {0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720},
+ {0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724},
+ {0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728},
+ {0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c},
+ {0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0},
+ {0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4},
+ {0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8},
+ {0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0},
+ {0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4},
+ {0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8},
+ {0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5},
+ {0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9},
+ {0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad},
+ {0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1},
+ {0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5},
+ {0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9},
+ {0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5},
+ {0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9},
+ {0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1},
+ {0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5},
+ {0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9},
+ {0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6},
+ {0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca},
+ {0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce},
+ {0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2},
+ {0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6},
+ {0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3},
+ {0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7},
+ {0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb},
+ {0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf},
+ {0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7},
+ {0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db},
+ {0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004},
+ {0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000},
+ {0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000},
+ {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+ {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
+ {0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000},
+ {0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e},
};
static const u32 ar9271Common_9271[][2] = {
@@ -3175,91 +3190,95 @@ static const u32 ar9271Common_japan_2484_cck_fir_coeff_9271[][2] = {
{0x0000a1fc, 0xca9228ee},
};
-static const u32 ar9271Modes_9271_1_0_only[][6] = {
- {0x00009910, 0x30002311, 0x30002311, 0x30002311, 0x30002311, 0x30002311},
- {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
+static const u32 ar9271Modes_9271_1_0_only[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00009910, 0x30002311, 0x30002311, 0x30002311, 0x30002311},
+ {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
};
-static const u32 ar9271Modes_9271_ANI_reg[][6] = {
- {0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2},
- {0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e},
- {0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
- {0x0000986c, 0x06903881, 0x06903881, 0x06903881, 0x06903881, 0x06903881},
- {0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
- {0x0000a208, 0x803e68c8, 0x803e68c8, 0x803e68c8, 0x803e68c8, 0x803e68c8},
- {0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d},
- {0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+static const u32 ar9271Modes_9271_ANI_reg[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2},
+ {0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e},
+ {0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
+ {0x0000986c, 0x06903881, 0x06903881, 0x06903881, 0x06903881},
+ {0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+ {0x0000a208, 0x803e68c8, 0x803e68c8, 0x803e68c8, 0x803e68c8},
+ {0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d},
+ {0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
};
-static const u32 ar9271Modes_normal_power_tx_gain_9271[][6] = {
- {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000},
- {0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000},
- {0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000},
- {0x0000a310, 0x00000000, 0x00000000, 0x0001e610, 0x0001e610, 0x00000000},
- {0x0000a314, 0x00000000, 0x00000000, 0x0002d6d0, 0x0002d6d0, 0x00000000},
- {0x0000a318, 0x00000000, 0x00000000, 0x00039758, 0x00039758, 0x00000000},
- {0x0000a31c, 0x00000000, 0x00000000, 0x0003b759, 0x0003b759, 0x00000000},
- {0x0000a320, 0x00000000, 0x00000000, 0x0003d75a, 0x0003d75a, 0x00000000},
- {0x0000a324, 0x00000000, 0x00000000, 0x0004175c, 0x0004175c, 0x00000000},
- {0x0000a328, 0x00000000, 0x00000000, 0x0004575e, 0x0004575e, 0x00000000},
- {0x0000a32c, 0x00000000, 0x00000000, 0x0004979f, 0x0004979f, 0x00000000},
- {0x0000a330, 0x00000000, 0x00000000, 0x0004d7df, 0x0004d7df, 0x00000000},
- {0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000},
- {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
- {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
- {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x00007838, 0x00000029, 0x00000029, 0x00000029, 0x00000029, 0x00000029},
- {0x00007824, 0x00d8abff, 0x00d8abff, 0x00d8abff, 0x00d8abff, 0x00d8abff},
- {0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4},
- {0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04},
- {0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a218652, 0x0a218652, 0x0a22a652},
- {0x0000a278, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd},
- {0x0000a27c, 0x050e83bd, 0x050e83bd, 0x050e83bd, 0x050e83bd, 0x050e83bd},
- {0x0000a394, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd},
- {0x0000a398, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd},
- {0x0000a3dc, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd},
- {0x0000a3e0, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd},
+static const u32 ar9271Modes_normal_power_tx_gain_9271[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200},
+ {0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208},
+ {0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608},
+ {0x0000a310, 0x00000000, 0x00000000, 0x0001e610, 0x0001e610},
+ {0x0000a314, 0x00000000, 0x00000000, 0x00024650, 0x00024650},
+ {0x0000a318, 0x00000000, 0x00000000, 0x0002d6d0, 0x0002d6d0},
+ {0x0000a31c, 0x00000000, 0x00000000, 0x000316d2, 0x000316d2},
+ {0x0000a320, 0x00000000, 0x00000000, 0x00039758, 0x00039758},
+ {0x0000a324, 0x00000000, 0x00000000, 0x0003b759, 0x0003b759},
+ {0x0000a328, 0x00000000, 0x00000000, 0x0003d75a, 0x0003d75a},
+ {0x0000a32c, 0x00000000, 0x00000000, 0x0004175c, 0x0004175c},
+ {0x0000a330, 0x00000000, 0x00000000, 0x0004575e, 0x0004575e},
+ {0x0000a334, 0x000368de, 0x000368de, 0x0004979f, 0x0004979f},
+ {0x0000a338, 0x0003891e, 0x0003891e, 0x0004d7df, 0x0004d7df},
+ {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e},
+ {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x00007838, 0x00000029, 0x00000029, 0x00000029, 0x00000029},
+ {0x00007824, 0x00d8abff, 0x00d8abff, 0x00d8abff, 0x00d8abff},
+ {0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4},
+ {0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04},
+ {0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21c652, 0x0a21c652},
+ {0x0000a278, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd},
+ {0x0000a27c, 0x050e83bd, 0x050e83bd, 0x050e83bd, 0x050e83bd},
+ {0x0000a394, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd},
+ {0x0000a398, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd},
+ {0x0000a3dc, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd},
+ {0x0000a3e0, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd},
};
-static const u32 ar9271Modes_high_power_tx_gain_9271[][6] = {
- {0x0000a300, 0x00000000, 0x00000000, 0x00010000, 0x00010000, 0x00000000},
- {0x0000a304, 0x00000000, 0x00000000, 0x00016200, 0x00016200, 0x00000000},
- {0x0000a308, 0x00000000, 0x00000000, 0x00018201, 0x00018201, 0x00000000},
- {0x0000a30c, 0x00000000, 0x00000000, 0x0001b240, 0x0001b240, 0x00000000},
- {0x0000a310, 0x00000000, 0x00000000, 0x0001d241, 0x0001d241, 0x00000000},
- {0x0000a314, 0x00000000, 0x00000000, 0x0001f600, 0x0001f600, 0x00000000},
- {0x0000a318, 0x00000000, 0x00000000, 0x00022800, 0x00022800, 0x00000000},
- {0x0000a31c, 0x00000000, 0x00000000, 0x00026802, 0x00026802, 0x00000000},
- {0x0000a320, 0x00000000, 0x00000000, 0x0002b805, 0x0002b805, 0x00000000},
- {0x0000a324, 0x00000000, 0x00000000, 0x0002ea41, 0x0002ea41, 0x00000000},
- {0x0000a328, 0x00000000, 0x00000000, 0x00038b00, 0x00038b00, 0x00000000},
- {0x0000a32c, 0x00000000, 0x00000000, 0x0003ab40, 0x0003ab40, 0x00000000},
- {0x0000a330, 0x00000000, 0x00000000, 0x0003cd80, 0x0003cd80, 0x00000000},
- {0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000},
- {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
- {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
- {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
- {0x00007838, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b},
- {0x00007824, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff},
- {0x0000786c, 0x08609eb6, 0x08609eb6, 0x08609eba, 0x08609eba, 0x08609eb6},
- {0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00},
- {0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a214652, 0x0a214652, 0x0a22a652},
- {0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
- {0x0000a27c, 0x05018063, 0x05038063, 0x05018063, 0x05018063, 0x05018063},
- {0x0000a394, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63},
- {0x0000a398, 0x00000063, 0x00000063, 0x00000063, 0x00000063, 0x00000063},
- {0x0000a3dc, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63},
- {0x0000a3e0, 0x00000063, 0x00000063, 0x00000063, 0x00000063, 0x00000063},
+static const u32 ar9271Modes_high_power_tx_gain_9271[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a300, 0x00000000, 0x00000000, 0x00010000, 0x00010000},
+ {0x0000a304, 0x00000000, 0x00000000, 0x00016200, 0x00016200},
+ {0x0000a308, 0x00000000, 0x00000000, 0x00018201, 0x00018201},
+ {0x0000a30c, 0x00000000, 0x00000000, 0x0001b240, 0x0001b240},
+ {0x0000a310, 0x00000000, 0x00000000, 0x0001d241, 0x0001d241},
+ {0x0000a314, 0x00000000, 0x00000000, 0x0001f600, 0x0001f600},
+ {0x0000a318, 0x00000000, 0x00000000, 0x00022800, 0x00022800},
+ {0x0000a31c, 0x00000000, 0x00000000, 0x00026802, 0x00026802},
+ {0x0000a320, 0x00000000, 0x00000000, 0x0002b805, 0x0002b805},
+ {0x0000a324, 0x00000000, 0x00000000, 0x0002ea41, 0x0002ea41},
+ {0x0000a328, 0x00000000, 0x00000000, 0x00038b00, 0x00038b00},
+ {0x0000a32c, 0x00000000, 0x00000000, 0x0003ab40, 0x0003ab40},
+ {0x0000a330, 0x00000000, 0x00000000, 0x0003cd80, 0x0003cd80},
+ {0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de},
+ {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e},
+ {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e},
+ {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df},
+ {0x00007838, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b},
+ {0x00007824, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff},
+ {0x0000786c, 0x08609eb6, 0x08609eb6, 0x08609eba, 0x08609eba},
+ {0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00},
+ {0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a214652, 0x0a214652},
+ {0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+ {0x0000a27c, 0x05018063, 0x05038063, 0x05018063, 0x05018063},
+ {0x0000a394, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63},
+ {0x0000a398, 0x00000063, 0x00000063, 0x00000063, 0x00000063},
+ {0x0000a3dc, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63},
+ {0x0000a3e0, 0x00000063, 0x00000063, 0x00000063, 0x00000063},
};
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
index 45b262fe2c25..f7d8e516a2a9 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
@@ -170,33 +170,104 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
return true;
}
-static void ar9002_hw_fill_txdesc(struct ath_hw *ah, void *ds, u32 seglen,
- bool is_firstseg, bool is_lastseg,
- const void *ds0, dma_addr_t buf_addr,
- unsigned int qcu)
+static void
+ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i)
{
struct ar5416_desc *ads = AR5416DESC(ds);
+ u32 ctl1, ctl6;
- ads->ds_data = buf_addr;
-
- if (is_firstseg) {
- ads->ds_ctl1 |= seglen | (is_lastseg ? 0 : AR_TxMore);
- } else if (is_lastseg) {
- ads->ds_ctl0 = 0;
- ads->ds_ctl1 = seglen;
- ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
- ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
- } else {
- ads->ds_ctl0 = 0;
- ads->ds_ctl1 = seglen | AR_TxMore;
- ads->ds_ctl2 = 0;
- ads->ds_ctl3 = 0;
- }
ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
+
+ ACCESS_ONCE(ads->ds_link) = i->link;
+ ACCESS_ONCE(ads->ds_data) = i->buf_addr[0];
+
+ ctl1 = i->buf_len[0] | (i->is_last ? 0 : AR_TxMore);
+ ctl6 = SM(i->keytype, AR_EncrType);
+
+ if (AR_SREV_9285(ah)) {
+ ads->ds_ctl8 = 0;
+ ads->ds_ctl9 = 0;
+ ads->ds_ctl10 = 0;
+ ads->ds_ctl11 = 0;
+ }
+
+ if ((i->is_first || i->is_last) &&
+ i->aggr != AGGR_BUF_MIDDLE && i->aggr != AGGR_BUF_LAST) {
+ ACCESS_ONCE(ads->ds_ctl2) = set11nTries(i->rates, 0)
+ | set11nTries(i->rates, 1)
+ | set11nTries(i->rates, 2)
+ | set11nTries(i->rates, 3)
+ | (i->dur_update ? AR_DurUpdateEna : 0)
+ | SM(0, AR_BurstDur);
+
+ ACCESS_ONCE(ads->ds_ctl3) = set11nRate(i->rates, 0)
+ | set11nRate(i->rates, 1)
+ | set11nRate(i->rates, 2)
+ | set11nRate(i->rates, 3);
+ } else {
+ ACCESS_ONCE(ads->ds_ctl2) = 0;
+ ACCESS_ONCE(ads->ds_ctl3) = 0;
+ }
+
+ if (!i->is_first) {
+ ACCESS_ONCE(ads->ds_ctl0) = 0;
+ ACCESS_ONCE(ads->ds_ctl1) = ctl1;
+ ACCESS_ONCE(ads->ds_ctl6) = ctl6;
+ return;
+ }
+
+ ctl1 |= (i->keyix != ATH9K_TXKEYIX_INVALID ? SM(i->keyix, AR_DestIdx) : 0)
+ | SM(i->type, AR_FrameType)
+ | (i->flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
+ | (i->flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
+ | (i->flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
+
+ switch (i->aggr) {
+ case AGGR_BUF_FIRST:
+ ctl6 |= SM(i->aggr_len, AR_AggrLen);
+ /* fall through */
+ case AGGR_BUF_MIDDLE:
+ ctl1 |= AR_IsAggr | AR_MoreAggr;
+ ctl6 |= SM(i->ndelim, AR_PadDelim);
+ break;
+ case AGGR_BUF_LAST:
+ ctl1 |= AR_IsAggr;
+ break;
+ case AGGR_BUF_NONE:
+ break;
+ }
+
+ ACCESS_ONCE(ads->ds_ctl0) = (i->pkt_len & AR_FrameLen)
+ | (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
+ | SM(i->txpower, AR_XmitPower)
+ | (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
+ | (i->flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
+ | (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
+ | (i->flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
+ | (i->flags & ATH9K_TXDESC_RTSENA ? AR_RTSEnable :
+ (i->flags & ATH9K_TXDESC_CTSENA ? AR_CTSEnable : 0));
+
+ ACCESS_ONCE(ads->ds_ctl1) = ctl1;
+ ACCESS_ONCE(ads->ds_ctl6) = ctl6;
+
+ if (i->aggr == AGGR_BUF_MIDDLE || i->aggr == AGGR_BUF_LAST)
+ return;
+
+ ACCESS_ONCE(ads->ds_ctl4) = set11nPktDurRTSCTS(i->rates, 0)
+ | set11nPktDurRTSCTS(i->rates, 1);
+
+ ACCESS_ONCE(ads->ds_ctl5) = set11nPktDurRTSCTS(i->rates, 2)
+ | set11nPktDurRTSCTS(i->rates, 3);
+
+ ACCESS_ONCE(ads->ds_ctl7) = set11nRateFlags(i->rates, 0)
+ | set11nRateFlags(i->rates, 1)
+ | set11nRateFlags(i->rates, 2)
+ | set11nRateFlags(i->rates, 3)
+ | SM(i->rtscts_rate, AR_RTSCTSRate);
}
static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds,
@@ -271,145 +342,6 @@ static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds,
return 0;
}
-static void ar9002_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
- u32 pktLen, enum ath9k_pkt_type type,
- u32 txPower, u32 keyIx,
- enum ath9k_key_type keyType, u32 flags)
-{
- struct ar5416_desc *ads = AR5416DESC(ds);
-
- if (txPower > 63)
- txPower = 63;
-
- ads->ds_ctl0 = (pktLen & AR_FrameLen)
- | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
- | SM(txPower, AR_XmitPower)
- | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
- | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
- | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
-
- ads->ds_ctl1 =
- (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0)
- | SM(type, AR_FrameType)
- | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
- | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
- | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
-
- ads->ds_ctl6 = SM(keyType, AR_EncrType);
-
- if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) {
- ads->ds_ctl8 = 0;
- ads->ds_ctl9 = 0;
- ads->ds_ctl10 = 0;
- ads->ds_ctl11 = 0;
- }
-}
-
-static void ar9002_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
-{
- struct ar5416_desc *ads = AR5416DESC(ds);
-
- if (val)
- ads->ds_ctl0 |= AR_ClrDestMask;
- else
- ads->ds_ctl0 &= ~AR_ClrDestMask;
-}
-
-static void ar9002_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
- void *lastds,
- u32 durUpdateEn, u32 rtsctsRate,
- u32 rtsctsDuration,
- struct ath9k_11n_rate_series series[],
- u32 nseries, u32 flags)
-{
- struct ar5416_desc *ads = AR5416DESC(ds);
- struct ar5416_desc *last_ads = AR5416DESC(lastds);
- u32 ds_ctl0;
-
- if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
- ds_ctl0 = ads->ds_ctl0;
-
- if (flags & ATH9K_TXDESC_RTSENA) {
- ds_ctl0 &= ~AR_CTSEnable;
- ds_ctl0 |= AR_RTSEnable;
- } else {
- ds_ctl0 &= ~AR_RTSEnable;
- ds_ctl0 |= AR_CTSEnable;
- }
-
- ads->ds_ctl0 = ds_ctl0;
- } else {
- ads->ds_ctl0 =
- (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable));
- }
-
- ads->ds_ctl2 = set11nTries(series, 0)
- | set11nTries(series, 1)
- | set11nTries(series, 2)
- | set11nTries(series, 3)
- | (durUpdateEn ? AR_DurUpdateEna : 0)
- | SM(0, AR_BurstDur);
-
- ads->ds_ctl3 = set11nRate(series, 0)
- | set11nRate(series, 1)
- | set11nRate(series, 2)
- | set11nRate(series, 3);
-
- ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0)
- | set11nPktDurRTSCTS(series, 1);
-
- ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2)
- | set11nPktDurRTSCTS(series, 3);
-
- ads->ds_ctl7 = set11nRateFlags(series, 0)
- | set11nRateFlags(series, 1)
- | set11nRateFlags(series, 2)
- | set11nRateFlags(series, 3)
- | SM(rtsctsRate, AR_RTSCTSRate);
- last_ads->ds_ctl2 = ads->ds_ctl2;
- last_ads->ds_ctl3 = ads->ds_ctl3;
-}
-
-static void ar9002_hw_set11n_aggr_first(struct ath_hw *ah, void *ds,
- u32 aggrLen)
-{
- struct ar5416_desc *ads = AR5416DESC(ds);
-
- ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
- ads->ds_ctl6 &= ~AR_AggrLen;
- ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
-}
-
-static void ar9002_hw_set11n_aggr_middle(struct ath_hw *ah, void *ds,
- u32 numDelims)
-{
- struct ar5416_desc *ads = AR5416DESC(ds);
- unsigned int ctl6;
-
- ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
-
- ctl6 = ads->ds_ctl6;
- ctl6 &= ~AR_PadDelim;
- ctl6 |= SM(numDelims, AR_PadDelim);
- ads->ds_ctl6 = ctl6;
-}
-
-static void ar9002_hw_set11n_aggr_last(struct ath_hw *ah, void *ds)
-{
- struct ar5416_desc *ads = AR5416DESC(ds);
-
- ads->ds_ctl1 |= AR_IsAggr;
- ads->ds_ctl1 &= ~AR_MoreAggr;
- ads->ds_ctl6 &= ~AR_PadDelim;
-}
-
-static void ar9002_hw_clr11n_aggr(struct ath_hw *ah, void *ds)
-{
- struct ar5416_desc *ads = AR5416DESC(ds);
-
- ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
-}
-
void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
u32 size, u32 flags)
{
@@ -433,13 +365,6 @@ void ar9002_hw_attach_mac_ops(struct ath_hw *ah)
ops->rx_enable = ar9002_hw_rx_enable;
ops->set_desc_link = ar9002_hw_set_desc_link;
ops->get_isr = ar9002_hw_get_isr;
- ops->fill_txdesc = ar9002_hw_fill_txdesc;
+ ops->set_txdesc = ar9002_set_txdesc;
ops->proc_txdesc = ar9002_hw_proc_txdesc;
- ops->set11n_txdesc = ar9002_hw_set11n_txdesc;
- ops->set11n_ratescenario = ar9002_hw_set11n_ratescenario;
- ops->set11n_aggr_first = ar9002_hw_set11n_aggr_first;
- ops->set11n_aggr_middle = ar9002_hw_set11n_aggr_middle;
- ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last;
- ops->clr11n_aggr = ar9002_hw_clr11n_aggr;
- ops->set_clrdmask = ar9002_hw_set_clrdmask;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
index 2339728a7306..026f9de15d15 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
@@ -24,11 +24,11 @@ static const u32 ar9300_2p2_radio_postamble[][5] = {
{0x0001609c, 0x0dd08f29, 0x0dd08f29, 0x0b283f31, 0x0b283f31},
{0x000160ac, 0xa4653c00, 0xa4653c00, 0x24652800, 0x24652800},
{0x000160b0, 0x03284f3e, 0x03284f3e, 0x05d08f20, 0x05d08f20},
- {0x0001610c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0001610c, 0xc8000000, 0xc0000000, 0xc0000000, 0xc0000000},
{0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
- {0x0001650c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0001650c, 0xc8000000, 0xc0000000, 0xc0000000, 0xc0000000},
{0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
- {0x0001690c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0001690c, 0xc8000000, 0xc0000000, 0xc0000000, 0xc0000000},
{0x00016940, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
};
@@ -190,7 +190,7 @@ static const u32 ar9300_2p2_radio_core[][2] = {
{0x00016288, 0x05a20408},
{0x0001628c, 0x00038c07},
{0x00016290, 0x00000004},
- {0x00016294, 0x458aa14f},
+ {0x00016294, 0x458a214f},
{0x00016380, 0x00000000},
{0x00016384, 0x00000000},
{0x00016388, 0x00800700},
@@ -636,7 +636,7 @@ static const u32 ar9300_2p2_baseband_postamble[][5] = {
{0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27},
{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
- {0x0000a204, 0x000037c0, 0x000037c4, 0x000037c4, 0x000037c0},
+ {0x0000a204, 0x000036c0, 0x000036c4, 0x000036c4, 0x000036c0},
{0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
{0x0000a22c, 0x01026a2f, 0x01026a2f, 0x01026a2f, 0x01026a2f},
{0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
@@ -835,108 +835,108 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][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},
+ {0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+ {0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+ {0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
- {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
- {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
- {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
- {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
- {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
- {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
- {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
- {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
- {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
- {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
- {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
- {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
- {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
- {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
- {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
- {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
- {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
- {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
- {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
- {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
- {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83},
- {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
- {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
- {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
- {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
- {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
- {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
- {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
- {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
- {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
- {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
- {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
- {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
- {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
- {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
- {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
- {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
- {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
- {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
- {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
- {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
- {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
- {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
- {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
- {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
- {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
- {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
- {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
- {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
- {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
- {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
- {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
- {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
- {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
- {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
- {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
- {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
- {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
- {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
- {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
- {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
- {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
- {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
- {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
- {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {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, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202},
+ {0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400},
+ {0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402},
+ {0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404},
+ {0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603},
+ {0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02},
+ {0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04},
+ {0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20},
+ {0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20},
+ {0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22},
+ {0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24},
+ {0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640},
+ {0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660},
+ {0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861},
+ {0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81},
+ {0x0000a54c, 0x5a08442e, 0x5a08442e, 0x47001a83, 0x47001a83},
+ {0x0000a550, 0x5e0a4431, 0x5e0a4431, 0x4a001c84, 0x4a001c84},
+ {0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3},
+ {0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5},
+ {0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9},
+ {0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb},
+ {0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+ {0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+ {0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+ {0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+ {0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+ {0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+ {0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+ {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+ {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+ {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+ {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+ {0x0000a590, 0x15800028, 0x15800028, 0x0f800202, 0x0f800202},
+ {0x0000a594, 0x1b80002b, 0x1b80002b, 0x12800400, 0x12800400},
+ {0x0000a598, 0x1f820028, 0x1f820028, 0x16800402, 0x16800402},
+ {0x0000a59c, 0x2582002b, 0x2582002b, 0x19800404, 0x19800404},
+ {0x0000a5a0, 0x2a84002a, 0x2a84002a, 0x1c800603, 0x1c800603},
+ {0x0000a5a4, 0x2e86002a, 0x2e86002a, 0x21800a02, 0x21800a02},
+ {0x0000a5a8, 0x3382202d, 0x3382202d, 0x25800a04, 0x25800a04},
+ {0x0000a5ac, 0x3884202c, 0x3884202c, 0x28800a20, 0x28800a20},
+ {0x0000a5b0, 0x3c86202c, 0x3c86202c, 0x2c800e20, 0x2c800e20},
+ {0x0000a5b4, 0x4188202d, 0x4188202d, 0x30800e22, 0x30800e22},
+ {0x0000a5b8, 0x4586402d, 0x4586402d, 0x34800e24, 0x34800e24},
+ {0x0000a5bc, 0x4986222d, 0x4986222d, 0x38801640, 0x38801640},
+ {0x0000a5c0, 0x4d862231, 0x4d862231, 0x3c801660, 0x3c801660},
+ {0x0000a5c4, 0x50882231, 0x50882231, 0x3f801861, 0x3f801861},
+ {0x0000a5c8, 0x5688422e, 0x5688422e, 0x43801a81, 0x43801a81},
+ {0x0000a5cc, 0x5a88442e, 0x5a88442e, 0x47801a83, 0x47801a83},
+ {0x0000a5d0, 0x5e8a4431, 0x5e8a4431, 0x4a801c84, 0x4a801c84},
+ {0x0000a5d4, 0x648a4432, 0x648a4432, 0x4e801ce3, 0x4e801ce3},
+ {0x0000a5d8, 0x688a4434, 0x688a4434, 0x52801ce5, 0x52801ce5},
+ {0x0000a5dc, 0x6c8a6434, 0x6c8a6434, 0x56801ce9, 0x56801ce9},
+ {0x0000a5e0, 0x6f8a6633, 0x6f8a6633, 0x5a801ceb, 0x5a801ceb},
+ {0x0000a5e4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
+ {0x0000a5e8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
+ {0x0000a5ec, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f0, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
+ {0x0000a5fc, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
{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, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
- {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
- {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+ {0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+ {0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+ {0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000},
+ {0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501},
+ {0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501},
+ {0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03},
+ {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
+ {0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04},
+ {0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+ {0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+ {0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+ {0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+ {0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+ {0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+ {0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+ {0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
- {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
- {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
- {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+ {0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+ {0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
- {0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
- {0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
- {0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
- {0x00016444, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
- {0x00016448, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
- {0x00016468, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
- {0x00016844, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
- {0x00016848, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
- {0x00016868, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
+ {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016048, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
+ {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016448, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
+ {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016848, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
+ {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
};
static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
@@ -1514,7 +1514,7 @@ static const u32 ar9300_2p2_mac_core[][2] = {
{0x00008258, 0x00000000},
{0x0000825c, 0x40000000},
{0x00008260, 0x00080922},
- {0x00008264, 0x9bc00010},
+ {0x00008264, 0x9d400010},
{0x00008268, 0xffffffff},
{0x0000826c, 0x0000ffff},
{0x00008270, 0x00000000},
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index f48051c50092..16851cb109a6 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -17,8 +17,9 @@
#include "hw.h"
#include "hw-ops.h"
#include "ar9003_phy.h"
+#include "ar9003_rtt.h"
-#define MAX_MEASUREMENT 8
+#define MAX_MEASUREMENT MAX_IQCAL_MEASUREMENT
#define MAX_MAG_DELTA 11
#define MAX_PHS_DELTA 10
@@ -615,11 +616,10 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
{
int mp_max = -64, max_idx = 0;
int mp_min = 63, min_idx = 0;
- int mp_avg = 0, i, outlier_idx = 0;
+ int mp_avg = 0, i, outlier_idx = 0, mp_count = 0;
/* find min/max mismatch across all calibrated gains */
for (i = 0; i < nmeasurement; i++) {
- mp_avg += mp_coeff[i];
if (mp_coeff[i] > mp_max) {
mp_max = mp_coeff[i];
max_idx = i;
@@ -632,10 +632,20 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
/* find average (exclude max abs value) */
for (i = 0; i < nmeasurement; i++) {
if ((abs(mp_coeff[i]) < abs(mp_max)) ||
- (abs(mp_coeff[i]) < abs(mp_min)))
+ (abs(mp_coeff[i]) < abs(mp_min))) {
mp_avg += mp_coeff[i];
+ mp_count++;
+ }
}
- mp_avg /= (nmeasurement - 1);
+
+ /*
+ * finding mean magnitude/phase if possible, otherwise
+ * just use the last value as the mean
+ */
+ if (mp_count)
+ mp_avg /= mp_count;
+ else
+ mp_avg = mp_coeff[nmeasurement - 1];
/* detect outlier */
if (abs(mp_max - mp_min) > max_delta) {
@@ -643,16 +653,19 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
outlier_idx = max_idx;
else
outlier_idx = min_idx;
+
+ mp_coeff[outlier_idx] = mp_avg;
}
- mp_coeff[outlier_idx] = mp_avg;
}
static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
u8 num_chains,
- struct coeff *coeff)
+ struct coeff *coeff,
+ bool is_reusable)
{
int i, im, nmeasurement;
u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS];
+ struct ath9k_hw_cal_data *caldata = ah->caldata;
memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff));
for (i = 0; i < MAX_MEASUREMENT / 2; i++) {
@@ -702,7 +715,13 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,
coeff->iqc_coeff[0]);
+
+ if (caldata)
+ caldata->tx_corr_coeff[im][i] =
+ coeff->iqc_coeff[0];
}
+ if (caldata)
+ caldata->num_measures[i] = nmeasurement;
}
REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
@@ -710,8 +729,10 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);
- return;
+ if (caldata)
+ caldata->done_txiqcal_once = is_reusable;
+ return;
}
static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
@@ -738,7 +759,7 @@ static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
return true;
}
-static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah)
+static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
{
struct ath_common *common = ath9k_hw_common(ah);
const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
@@ -827,7 +848,8 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah)
coeff.phs_coeff[i][im] -= 128;
}
}
- ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains, &coeff);
+ ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains,
+ &coeff, is_reusable);
return;
@@ -835,23 +857,129 @@ tx_iqcal_fail:
ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n");
return;
}
+
+static void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah)
+{
+ struct ath9k_hw_cal_data *caldata = ah->caldata;
+ u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS];
+ int i, im;
+
+ memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff));
+ for (i = 0; i < MAX_MEASUREMENT / 2; i++) {
+ tx_corr_coeff[i * 2][0] = tx_corr_coeff[(i * 2) + 1][0] =
+ AR_PHY_TX_IQCAL_CORR_COEFF_B0(i);
+ if (!AR_SREV_9485(ah)) {
+ tx_corr_coeff[i * 2][1] =
+ tx_corr_coeff[(i * 2) + 1][1] =
+ AR_PHY_TX_IQCAL_CORR_COEFF_B1(i);
+
+ tx_corr_coeff[i * 2][2] =
+ tx_corr_coeff[(i * 2) + 1][2] =
+ AR_PHY_TX_IQCAL_CORR_COEFF_B2(i);
+ }
+ }
+
+ for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+ if (!(ah->txchainmask & (1 << i)))
+ continue;
+
+ for (im = 0; im < caldata->num_measures[i]; im++) {
+ if ((im % 2) == 0)
+ REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
+ AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE,
+ caldata->tx_corr_coeff[im][i]);
+ else
+ REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
+ AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,
+ caldata->tx_corr_coeff[im][i]);
+ }
+ }
+
+ REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
+ AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);
+ REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
+ AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);
+}
+
+static bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+ struct ath9k_rtt_hist *hist;
+ u32 *table;
+ int i;
+ bool restore;
+
+ if (!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT) || !ah->caldata)
+ return false;
+
+ hist = &ah->caldata->rtt_hist;
+ ar9003_hw_rtt_enable(ah);
+ ar9003_hw_rtt_set_mask(ah, 0x10);
+ for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+ if (!(ah->rxchainmask & (1 << i)))
+ continue;
+ table = &hist->table[i][hist->num_readings][0];
+ ar9003_hw_rtt_load_hist(ah, i, table);
+ }
+ restore = ar9003_hw_rtt_force_restore(ah);
+ ar9003_hw_rtt_disable(ah);
+
+ return restore;
+}
+
static bool ar9003_hw_init_cal(struct ath_hw *ah,
struct ath9k_channel *chan)
{
struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_hw_capabilities *pCap = &ah->caps;
- int val;
- bool txiqcal_done = false;
+ struct ath9k_hw_cal_data *caldata = ah->caldata;
+ bool txiqcal_done = false, txclcal_done = false;
+ bool is_reusable = true, status = true;
+ bool run_rtt_cal = false, run_agc_cal;
+ bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT);
+ u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |
+ AR_PHY_AGC_CONTROL_FLTR_CAL |
+ AR_PHY_AGC_CONTROL_PKDET_CAL;
+ int i, j;
+ u32 cl_idx[AR9300_MAX_CHAINS] = { AR_PHY_CL_TAB_0,
+ AR_PHY_CL_TAB_1,
+ AR_PHY_CL_TAB_2 };
+
+ if (rtt) {
+ if (!ar9003_hw_rtt_restore(ah, chan))
+ run_rtt_cal = true;
+
+ ath_dbg(common, ATH_DBG_CALIBRATE, "RTT restore %s\n",
+ run_rtt_cal ? "failed" : "succeed");
+ }
+ run_agc_cal = run_rtt_cal;
- val = REG_READ(ah, AR_ENT_OTP);
- ath_dbg(common, ATH_DBG_CALIBRATE, "ath9k: AR_ENT_OTP 0x%x\n", val);
+ if (run_rtt_cal) {
+ ar9003_hw_rtt_enable(ah);
+ ar9003_hw_rtt_set_mask(ah, 0x00);
+ ar9003_hw_rtt_clear_hist(ah);
+ }
- /* Configure rx/tx chains before running AGC/TxiQ cals */
- if (val & AR_ENT_OTP_CHAIN2_DISABLE)
- ar9003_hw_set_chain_masks(ah, 0x3, 0x3);
- else
- ar9003_hw_set_chain_masks(ah, pCap->rx_chainmask,
- pCap->tx_chainmask);
+ if (rtt && !run_rtt_cal) {
+ agc_ctrl = REG_READ(ah, AR_PHY_AGC_CONTROL);
+ agc_supp_cals &= agc_ctrl;
+ agc_ctrl &= ~(AR_PHY_AGC_CONTROL_OFFSET_CAL |
+ AR_PHY_AGC_CONTROL_FLTR_CAL |
+ AR_PHY_AGC_CONTROL_PKDET_CAL);
+ REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl);
+ }
+
+ if (ah->enabled_cals & TX_CL_CAL) {
+ if (caldata && caldata->done_txclcal_once)
+ REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL,
+ AR_PHY_CL_CAL_ENABLE);
+ else {
+ REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL,
+ AR_PHY_CL_CAL_ENABLE);
+ run_agc_cal = true;
+ }
+ }
+
+ if (!(ah->enabled_cals & TX_IQ_CAL))
+ goto skip_tx_iqcal;
/* Do Tx IQ Calibration */
REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
@@ -862,34 +990,98 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
* For AR9485 or later chips, TxIQ cal runs as part of
* AGC calibration
*/
- if (AR_SREV_9485_OR_LATER(ah))
- txiqcal_done = true;
- else {
- txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
- REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
- udelay(5);
- REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
- }
-
- /* Calibrate the AGC */
- REG_WRITE(ah, AR_PHY_AGC_CONTROL,
- REG_READ(ah, AR_PHY_AGC_CONTROL) |
- AR_PHY_AGC_CONTROL_CAL);
-
- /* Poll for offset calibration complete */
- if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
- 0, AH_WAIT_TIMEOUT)) {
+ if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) {
+ if (caldata && !caldata->done_txiqcal_once)
+ REG_SET_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
+ AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
+ else
+ REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
+ AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
+ txiqcal_done = run_agc_cal = true;
+ goto skip_tx_iqcal;
+ } else if (caldata && !caldata->done_txiqcal_once)
+ run_agc_cal = true;
+
+ txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
+ REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
+ udelay(5);
+ REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+
+skip_tx_iqcal:
+ if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
+ /* Calibrate the AGC */
+ REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+ REG_READ(ah, AR_PHY_AGC_CONTROL) |
+ AR_PHY_AGC_CONTROL_CAL);
+
+ /* Poll for offset calibration complete */
+ status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
+ AR_PHY_AGC_CONTROL_CAL,
+ 0, AH_WAIT_TIMEOUT);
+ }
+ if (rtt && !run_rtt_cal) {
+ agc_ctrl |= agc_supp_cals;
+ REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl);
+ }
+
+ if (!status) {
+ if (run_rtt_cal)
+ ar9003_hw_rtt_disable(ah);
+
ath_dbg(common, ATH_DBG_CALIBRATE,
- "offset calibration failed to complete in 1ms; noisy environment?\n");
+ "offset calibration failed to complete in 1ms;"
+ "noisy environment?\n");
return false;
}
if (txiqcal_done)
- ar9003_hw_tx_iq_cal_post_proc(ah);
+ ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable);
+ else if (caldata && caldata->done_txiqcal_once)
+ ar9003_hw_tx_iq_cal_reload(ah);
+
+#define CL_TAB_ENTRY(reg_base) (reg_base + (4 * j))
+ if (caldata && (ah->enabled_cals & TX_CL_CAL)) {
+ txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) &
+ AR_PHY_AGC_CONTROL_CLC_SUCCESS);
+ if (caldata->done_txclcal_once) {
+ for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+ if (!(ah->txchainmask & (1 << i)))
+ continue;
+ for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
+ REG_WRITE(ah, CL_TAB_ENTRY(cl_idx[i]),
+ caldata->tx_clcal[i][j]);
+ }
+ } else if (is_reusable && txclcal_done) {
+ for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+ if (!(ah->txchainmask & (1 << i)))
+ continue;
+ for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
+ caldata->tx_clcal[i][j] =
+ REG_READ(ah,
+ CL_TAB_ENTRY(cl_idx[i]));
+ }
+ caldata->done_txclcal_once = true;
+ }
+ }
+#undef CL_TAB_ENTRY
+
+ if (run_rtt_cal && caldata) {
+ struct ath9k_rtt_hist *hist = &caldata->rtt_hist;
+ if (is_reusable && (hist->num_readings < RTT_HIST_MAX)) {
+ u32 *table;
+
+ for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+ if (!(ah->rxchainmask & (1 << i)))
+ continue;
+ table = &hist->table[i][hist->num_readings][0];
+ ar9003_hw_rtt_fill_hist(ah, i, table);
+ }
+ }
- /* Revert chainmasks to their original values before NF cal */
- ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
+ ar9003_hw_rtt_disable(ah);
+ }
+ ath9k_hw_loadnf(ah, chan);
ath9k_hw_start_nfcal(ah, true);
/* Initialize list pointers */
@@ -916,8 +1108,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
if (ah->cal_list_curr)
ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
- if (ah->caldata)
- ah->caldata->CalValid = 0;
+ if (caldata)
+ caldata->CalValid = 0;
return true;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index c34bef1bf2b0..3b262ba6b172 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -22,25 +22,6 @@
#define COMP_HDR_LEN 4
#define COMP_CKSUM_LEN 2
-#define AR_CH0_TOP (0x00016288)
-#define AR_CH0_TOP_XPABIASLVL (0x300)
-#define AR_CH0_TOP_XPABIASLVL_S (8)
-
-#define AR_CH0_THERM (0x00016290)
-#define AR_CH0_THERM_XPABIASLVL_MSB 0x3
-#define AR_CH0_THERM_XPABIASLVL_MSB_S 0
-#define AR_CH0_THERM_XPASHORT2GND 0x4
-#define AR_CH0_THERM_XPASHORT2GND_S 2
-
-#define AR_SWITCH_TABLE_COM_ALL (0xffff)
-#define AR_SWITCH_TABLE_COM_ALL_S (0)
-
-#define AR_SWITCH_TABLE_COM2_ALL (0xffffff)
-#define AR_SWITCH_TABLE_COM2_ALL_S (0)
-
-#define AR_SWITCH_TABLE_ALL (0xfff)
-#define AR_SWITCH_TABLE_ALL_S (0)
-
#define LE16(x) __constant_cpu_to_le16(x)
#define LE32(x) __constant_cpu_to_le32(x)
@@ -69,7 +50,7 @@ static int ar9003_hw_power_interpolate(int32_t x,
static const struct ar9300_eeprom ar9300_default = {
.eepromVersion = 2,
.templateVersion = 2,
- .macAddr = {1, 2, 3, 4, 5, 6},
+ .macAddr = {0, 2, 3, 4, 5, 6},
.custData = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
.baseEepHeader = {
@@ -158,7 +139,7 @@ static const struct ar9300_eeprom ar9300_default = {
.papdRateMaskHt20 = LE32(0x0cf0e0e0),
.papdRateMaskHt40 = LE32(0x6cf0e0e0),
.futureModal = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
},
},
.base_ext1 = {
@@ -360,7 +341,7 @@ static const struct ar9300_eeprom ar9300_default = {
.papdRateMaskHt20 = LE32(0x0c80c080),
.papdRateMaskHt40 = LE32(0x0080c080),
.futureModal = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
},
},
.base_ext2 = {
@@ -735,7 +716,7 @@ static const struct ar9300_eeprom ar9300_x113 = {
.papdRateMaskHt20 = LE32(0x0c80c080),
.papdRateMaskHt40 = LE32(0x0080c080),
.futureModal = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
},
},
.base_ext1 = {
@@ -937,7 +918,7 @@ static const struct ar9300_eeprom ar9300_x113 = {
.papdRateMaskHt20 = LE32(0x0cf0e0e0),
.papdRateMaskHt40 = LE32(0x6cf0e0e0),
.futureModal = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
},
},
.base_ext2 = {
@@ -1313,7 +1294,7 @@ static const struct ar9300_eeprom ar9300_h112 = {
.papdRateMaskHt20 = LE32(0x80c080),
.papdRateMaskHt40 = LE32(0x80c080),
.futureModal = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
},
},
.base_ext1 = {
@@ -1515,7 +1496,7 @@ static const struct ar9300_eeprom ar9300_h112 = {
.papdRateMaskHt20 = LE32(0x0cf0e0e0),
.papdRateMaskHt40 = LE32(0x6cf0e0e0),
.futureModal = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
},
},
.base_ext2 = {
@@ -1891,7 +1872,7 @@ static const struct ar9300_eeprom ar9300_x112 = {
.papdRateMaskHt20 = LE32(0x0c80c080),
.papdRateMaskHt40 = LE32(0x0080c080),
.futureModal = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
},
},
.base_ext1 = {
@@ -2093,7 +2074,7 @@ static const struct ar9300_eeprom ar9300_x112 = {
.papdRateMaskHt20 = LE32(0x0cf0e0e0),
.papdRateMaskHt40 = LE32(0x6cf0e0e0),
.futureModal = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
},
},
.base_ext2 = {
@@ -2468,7 +2449,7 @@ static const struct ar9300_eeprom ar9300_h116 = {
.papdRateMaskHt20 = LE32(0x0c80C080),
.papdRateMaskHt40 = LE32(0x0080C080),
.futureModal = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
},
},
.base_ext1 = {
@@ -2670,7 +2651,7 @@ static const struct ar9300_eeprom ar9300_h116 = {
.papdRateMaskHt20 = LE32(0x0cf0e0e0),
.papdRateMaskHt40 = LE32(0x6cf0e0e0),
.futureModal = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
},
},
.base_ext2 = {
@@ -3014,8 +2995,6 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah,
return get_unaligned_be16(eep->macAddr + 4);
case EEP_REG_0:
return le16_to_cpu(pBase->regDmn[0]);
- case EEP_REG_1:
- return le16_to_cpu(pBase->regDmn[1]);
case EEP_OP_CAP:
return pBase->deviceCap;
case EEP_OP_MODE:
@@ -3040,6 +3019,10 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah,
return (pBase->miscConfiguration >> 0x3) & 0x1;
case EEP_ANT_DIV_CTL1:
return eep->base_ext1.ant_div_control;
+ case EEP_ANTENNA_GAIN_5G:
+ return eep->modalHeader5G.antennaGain;
+ case EEP_ANTENNA_GAIN_2G:
+ return eep->modalHeader2G.antennaGain;
default:
return 0;
}
@@ -3318,7 +3301,7 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah,
word = kzalloc(2048, GFP_KERNEL);
if (!word)
- return -1;
+ return -ENOMEM;
memcpy(mptr, &ar9300_default, mdata_size);
@@ -3418,6 +3401,133 @@ static bool ath9k_hw_ar9300_fill_eeprom(struct ath_hw *ah)
return true;
}
+#if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS)
+static u32 ar9003_dump_modal_eeprom(char *buf, u32 len, u32 size,
+ struct ar9300_modal_eep_header *modal_hdr)
+{
+ PR_EEP("Chain0 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[0]));
+ PR_EEP("Chain1 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[1]));
+ PR_EEP("Chain2 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[2]));
+ PR_EEP("Ant. Common Control", le32_to_cpu(modal_hdr->antCtrlCommon));
+ PR_EEP("Ant. Common Control2", le32_to_cpu(modal_hdr->antCtrlCommon2));
+ PR_EEP("Ant. Gain", modal_hdr->antennaGain);
+ PR_EEP("Switch Settle", modal_hdr->switchSettling);
+ PR_EEP("Chain0 xatten1DB", modal_hdr->xatten1DB[0]);
+ PR_EEP("Chain1 xatten1DB", modal_hdr->xatten1DB[1]);
+ PR_EEP("Chain2 xatten1DB", modal_hdr->xatten1DB[2]);
+ PR_EEP("Chain0 xatten1Margin", modal_hdr->xatten1Margin[0]);
+ PR_EEP("Chain1 xatten1Margin", modal_hdr->xatten1Margin[1]);
+ PR_EEP("Chain2 xatten1Margin", modal_hdr->xatten1Margin[2]);
+ PR_EEP("Temp Slope", modal_hdr->tempSlope);
+ PR_EEP("Volt Slope", modal_hdr->voltSlope);
+ PR_EEP("spur Channels0", modal_hdr->spurChans[0]);
+ PR_EEP("spur Channels1", modal_hdr->spurChans[1]);
+ PR_EEP("spur Channels2", modal_hdr->spurChans[2]);
+ PR_EEP("spur Channels3", modal_hdr->spurChans[3]);
+ PR_EEP("spur Channels4", modal_hdr->spurChans[4]);
+ PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]);
+ PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]);
+ PR_EEP("Chain2 NF Threshold", modal_hdr->noiseFloorThreshCh[2]);
+ PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl);
+ PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart);
+ PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn);
+ PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn);
+ PR_EEP("txClip", modal_hdr->txClip);
+ PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize);
+ PR_EEP("Chain0 ob", modal_hdr->ob[0]);
+ PR_EEP("Chain1 ob", modal_hdr->ob[1]);
+ PR_EEP("Chain2 ob", modal_hdr->ob[2]);
+
+ PR_EEP("Chain0 db_stage2", modal_hdr->db_stage2[0]);
+ PR_EEP("Chain1 db_stage2", modal_hdr->db_stage2[1]);
+ PR_EEP("Chain2 db_stage2", modal_hdr->db_stage2[2]);
+ PR_EEP("Chain0 db_stage3", modal_hdr->db_stage3[0]);
+ PR_EEP("Chain1 db_stage3", modal_hdr->db_stage3[1]);
+ PR_EEP("Chain2 db_stage3", modal_hdr->db_stage3[2]);
+ PR_EEP("Chain0 db_stage4", modal_hdr->db_stage4[0]);
+ PR_EEP("Chain1 db_stage4", modal_hdr->db_stage4[1]);
+ PR_EEP("Chain2 db_stage4", modal_hdr->db_stage4[2]);
+
+ return len;
+}
+
+static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
+ u8 *buf, u32 len, u32 size)
+{
+ struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+ struct ar9300_base_eep_hdr *pBase;
+
+ if (!dump_base_hdr) {
+ len += snprintf(buf + len, size - len,
+ "%20s :\n", "2GHz modal Header");
+ len += ar9003_dump_modal_eeprom(buf, len, size,
+ &eep->modalHeader2G);
+ len += snprintf(buf + len, size - len,
+ "%20s :\n", "5GHz modal Header");
+ len += ar9003_dump_modal_eeprom(buf, len, size,
+ &eep->modalHeader5G);
+ goto out;
+ }
+
+ pBase = &eep->baseEepHeader;
+
+ PR_EEP("EEPROM Version", ah->eeprom.ar9300_eep.eepromVersion);
+ PR_EEP("RegDomain1", le16_to_cpu(pBase->regDmn[0]));
+ PR_EEP("RegDomain2", le16_to_cpu(pBase->regDmn[1]));
+ PR_EEP("TX Mask", (pBase->txrxMask >> 4));
+ PR_EEP("RX Mask", (pBase->txrxMask & 0x0f));
+ PR_EEP("Allow 5GHz", !!(pBase->opCapFlags.opFlags &
+ AR5416_OPFLAGS_11A));
+ PR_EEP("Allow 2GHz", !!(pBase->opCapFlags.opFlags &
+ AR5416_OPFLAGS_11G));
+ PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags.opFlags &
+ AR5416_OPFLAGS_N_2G_HT20));
+ PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags.opFlags &
+ AR5416_OPFLAGS_N_2G_HT40));
+ PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags.opFlags &
+ AR5416_OPFLAGS_N_5G_HT20));
+ PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags.opFlags &
+ AR5416_OPFLAGS_N_5G_HT40));
+ PR_EEP("Big Endian", !!(pBase->opCapFlags.eepMisc & 0x01));
+ PR_EEP("RF Silent", pBase->rfSilent);
+ PR_EEP("BT option", pBase->blueToothOptions);
+ PR_EEP("Device Cap", pBase->deviceCap);
+ PR_EEP("Device Type", pBase->deviceType);
+ PR_EEP("Power Table Offset", pBase->pwrTableOffset);
+ PR_EEP("Tuning Caps1", pBase->params_for_tuning_caps[0]);
+ PR_EEP("Tuning Caps2", pBase->params_for_tuning_caps[1]);
+ PR_EEP("Enable Tx Temp Comp", !!(pBase->featureEnable & BIT(0)));
+ PR_EEP("Enable Tx Volt Comp", !!(pBase->featureEnable & BIT(1)));
+ PR_EEP("Enable fast clock", !!(pBase->featureEnable & BIT(2)));
+ PR_EEP("Enable doubling", !!(pBase->featureEnable & BIT(3)));
+ PR_EEP("Internal regulator", !!(pBase->featureEnable & BIT(4)));
+ PR_EEP("Enable Paprd", !!(pBase->featureEnable & BIT(5)));
+ PR_EEP("Driver Strength", !!(pBase->miscConfiguration & BIT(0)));
+ PR_EEP("Chain mask Reduce", (pBase->miscConfiguration >> 0x3) & 0x1);
+ PR_EEP("Write enable Gpio", pBase->eepromWriteEnableGpio);
+ PR_EEP("WLAN Disable Gpio", pBase->wlanDisableGpio);
+ PR_EEP("WLAN LED Gpio", pBase->wlanLedGpio);
+ PR_EEP("Rx Band Select Gpio", pBase->rxBandSelectGpio);
+ PR_EEP("Tx Gain", pBase->txrxgain >> 4);
+ PR_EEP("Rx Gain", pBase->txrxgain & 0xf);
+ PR_EEP("SW Reg", le32_to_cpu(pBase->swreg));
+
+ len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
+ ah->eeprom.ar9300_eep.macAddr);
+out:
+ if (len > size)
+ len = size;
+
+ return len;
+}
+#else
+static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
+ u8 *buf, u32 len, u32 size)
+{
+ return 0;
+}
+#endif
+
/* XXX: review hardware docs */
static int ath9k_hw_ar9300_get_eeprom_ver(struct ath_hw *ah)
{
@@ -3446,6 +3556,8 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz)
if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah))
REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias);
+ else if (AR_SREV_9462(ah))
+ REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias);
else {
REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias);
REG_RMW_FIELD(ah, AR_CH0_THERM,
@@ -3456,6 +3568,19 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz)
}
}
+static u16 ar9003_switch_com_spdt_get(struct ath_hw *ah, bool is_2ghz)
+{
+ struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+ __le32 val;
+
+ if (is_2ghz)
+ val = eep->modalHeader2G.switchcomspdt;
+ else
+ val = eep->modalHeader5G.switchcomspdt;
+ return le32_to_cpu(val);
+}
+
+
static u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz)
{
struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
@@ -3510,7 +3635,36 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
u32 value = ar9003_hw_ant_ctrl_common_get(ah, is2ghz);
- REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_ALL, value);
+ 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
+ REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
+ AR_SWITCH_TABLE_COM_ALL, value);
+
+
+ /*
+ * AR9462 defines new switch table for BT/WLAN,
+ * here's new field name in XXX.ref for both 2G and 5G.
+ * Register: [GLB_CONTROL] GLB_CONTROL (@0x20044)
+ * 15:12 R/W SWITCH_TABLE_COM_SPDT_WLAN_RX
+ * SWITCH_TABLE_COM_SPDT_WLAN_RX
+ *
+ * 11:8 R/W SWITCH_TABLE_COM_SPDT_WLAN_TX
+ * SWITCH_TABLE_COM_SPDT_WLAN_TX
+ *
+ * 7:4 R/W SWITCH_TABLE_COM_SPDT_WLAN_IDLE
+ * SWITCH_TABLE_COM_SPDT_WLAN_IDLE
+ */
+ if (AR_SREV_9462_20_OR_LATER(ah)) {
+ value = ar9003_switch_com_spdt_get(ah, is2ghz);
+ REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL,
+ AR_SWITCH_TABLE_COM_SPDT_ALL, value);
+ }
value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz);
REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value);
@@ -3710,6 +3864,7 @@ static void ar9003_hw_internal_regulator_apply(struct ath_hw *ah)
{
int internal_regulator =
ath9k_hw_ar9300_get_eeprom(ah, EEP_INTERNAL_REGULATOR);
+ u32 reg_val;
if (internal_regulator) {
if (AR_SREV_9330(ah) || AR_SREV_9485(ah)) {
@@ -3754,13 +3909,16 @@ static void ar9003_hw_internal_regulator_apply(struct ath_hw *ah)
REG_WRITE(ah, AR_PHY_PMU2, reg_pmu_set);
if (!is_pmu_set(ah, AR_PHY_PMU2, reg_pmu_set))
return;
+ } else if (AR_SREV_9462(ah)) {
+ reg_val = ath9k_hw_ar9300_get_eeprom(ah, EEP_SWREG);
+ REG_WRITE(ah, AR_PHY_PMU1, reg_val);
} else {
/* Internal regulator is ON. Write swreg register. */
- int swreg = ath9k_hw_ar9300_get_eeprom(ah, EEP_SWREG);
+ reg_val = ath9k_hw_ar9300_get_eeprom(ah, EEP_SWREG);
REG_WRITE(ah, AR_RTC_REG_CONTROL1,
REG_READ(ah, AR_RTC_REG_CONTROL1) &
(~AR_RTC_REG_CONTROL1_SWREG_PROGRAM));
- REG_WRITE(ah, AR_RTC_REG_CONTROL0, swreg);
+ REG_WRITE(ah, AR_RTC_REG_CONTROL0, reg_val);
/* Set REG_CONTROL1.SWREG_PROGRAM */
REG_WRITE(ah, AR_RTC_REG_CONTROL1,
REG_READ(ah,
@@ -3771,22 +3929,24 @@ static void ar9003_hw_internal_regulator_apply(struct ath_hw *ah)
if (AR_SREV_9330(ah) || AR_SREV_9485(ah)) {
REG_RMW_FIELD(ah, AR_PHY_PMU2, AR_PHY_PMU2_PGM, 0);
while (REG_READ_FIELD(ah, AR_PHY_PMU2,
- AR_PHY_PMU2_PGM))
+ AR_PHY_PMU2_PGM))
udelay(10);
REG_RMW_FIELD(ah, AR_PHY_PMU1, AR_PHY_PMU1_PWD, 0x1);
while (!REG_READ_FIELD(ah, AR_PHY_PMU1,
- AR_PHY_PMU1_PWD))
+ AR_PHY_PMU1_PWD))
udelay(10);
REG_RMW_FIELD(ah, AR_PHY_PMU2, AR_PHY_PMU2_PGM, 0x1);
while (!REG_READ_FIELD(ah, AR_PHY_PMU2,
- AR_PHY_PMU2_PGM))
+ AR_PHY_PMU2_PGM))
udelay(10);
- } else
- REG_WRITE(ah, AR_RTC_SLEEP_CLK,
- (REG_READ(ah,
- AR_RTC_SLEEP_CLK) |
- AR_RTC_FORCE_SWREG_PRD));
+ } else if (AR_SREV_9462(ah))
+ REG_RMW_FIELD(ah, AR_PHY_PMU1, AR_PHY_PMU1_PWD, 0x1);
+ else {
+ reg_val = REG_READ(ah, AR_RTC_SLEEP_CLK) |
+ AR_RTC_FORCE_SWREG_PRD;
+ REG_WRITE(ah, AR_RTC_SLEEP_CLK, reg_val);
+ }
}
}
@@ -4061,7 +4221,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
/* Write the power for duplicated frames - HT40 */
/* dup40_cck (LSB), dup40_ofdm, ext20_cck, ext20_ofdm (MSB) */
- REG_WRITE(ah, 0xa3e0,
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE(8),
POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 24) |
POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 16) |
POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 8) |
@@ -4366,6 +4526,12 @@ static int ar9003_hw_power_control_override(struct ath_hw *ah,
tempSlope = eep->modalHeader5G.tempSlope;
REG_RMW_FIELD(ah, AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, tempSlope);
+
+ if (AR_SREV_9462_20(ah))
+ REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
+ AR_PHY_TPC_19_B1_ALPHA_THERM, tempSlope);
+
+
REG_RMW_FIELD(ah, AR_PHY_TPC_18, AR_PHY_TPC_18_THERM_CAL_VALUE,
temperature[0]);
@@ -4600,20 +4766,14 @@ static u16 ar9003_hw_get_max_edge_power(struct ar9300_eeprom *eep,
static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
struct ath9k_channel *chan,
u8 *pPwrArray, u16 cfgCtl,
- u8 twiceAntennaReduction,
- u8 twiceMaxRegulatoryPower,
+ u8 antenna_reduction,
u16 powerLimit)
{
- struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
struct ath_common *common = ath9k_hw_common(ah);
struct ar9300_eeprom *pEepData = &ah->eeprom.ar9300_eep;
u16 twiceMaxEdgePower = MAX_RATE_POWER;
- static const u16 tpScaleReductionTable[5] = {
- 0, 3, 6, 9, MAX_RATE_POWER
- };
int i;
- int16_t twiceLargestAntenna;
- u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
+ u16 scaledPower = 0, minCtlPower;
static const u16 ctlModesFor11a[] = {
CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40
};
@@ -4631,28 +4791,7 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
bool is2ghz = IS_CHAN_2GHZ(chan);
ath9k_hw_get_channel_centers(ah, chan, &centers);
-
- /* Compute TxPower reduction due to Antenna Gain */
- if (is2ghz)
- twiceLargestAntenna = pEepData->modalHeader2G.antennaGain;
- else
- twiceLargestAntenna = pEepData->modalHeader5G.antennaGain;
-
- twiceLargestAntenna = (int16_t)min((twiceAntennaReduction) -
- twiceLargestAntenna, 0);
-
- /*
- * scaledPower is the minimum of the user input power level
- * and the regulatory allowed power level
- */
- maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
-
- if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) {
- maxRegAllowedPower -=
- (tpScaleReductionTable[(regulatory->tp_scale)] * 2);
- }
-
- scaledPower = min(powerLimit, maxRegAllowedPower);
+ scaledPower = powerLimit - antenna_reduction;
/*
* Reduce scaled Power by number of chains active to get
@@ -4839,7 +4978,6 @@ static inline u8 mcsidx_to_tgtpwridx(unsigned int mcs_idx, u8 base_pwridx)
static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
struct ath9k_channel *chan, u16 cfgCtl,
u8 twiceAntennaReduction,
- u8 twiceMaxRegulatoryPower,
u8 powerLimit, bool test)
{
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
@@ -4892,7 +5030,6 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
ar9003_hw_set_power_per_rate_table(ah, chan,
targetPowerValT2, cfgCtl,
twiceAntennaReduction,
- twiceMaxRegulatoryPower,
powerLimit);
if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) {
@@ -4922,25 +5059,7 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
"TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]);
}
- /*
- * This is the TX power we send back to driver core,
- * and it can use to pass to userspace to display our
- * currently configured TX power setting.
- *
- * Since power is rate dependent, use one of the indices
- * from the AR9300_Rates enum to select an entry from
- * targetPowerValT2[] to report. Currently returns the
- * power for HT40 MCS 0, HT20 MCS 0, or OFDM 6 Mbps
- * as CCK power is less interesting (?).
- */
- i = ALL_TARGET_LEGACY_6_24; /* legacy */
- if (IS_CHAN_HT40(chan))
- i = ALL_TARGET_HT40_0_8_16; /* ht40 */
- else if (IS_CHAN_HT20(chan))
- i = ALL_TARGET_HT20_0_8_16; /* ht20 */
-
- ah->txpower_limit = targetPowerValT2[i];
- regulatory->max_power_level = targetPowerValT2[i];
+ ah->txpower_limit = regulatory->max_power_level;
/* Write target power array to registers */
ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);
@@ -5015,6 +5134,7 @@ const struct eeprom_ops eep_ar9300_ops = {
.check_eeprom = ath9k_hw_ar9300_check_eeprom,
.get_eeprom = ath9k_hw_ar9300_get_eeprom,
.fill_eeprom = ath9k_hw_ar9300_fill_eeprom,
+ .dump_eeprom = ath9k_hw_ar9003_dump_eeprom,
.get_eeprom_ver = ath9k_hw_ar9300_get_eeprom_ver,
.get_eeprom_rev = ath9k_hw_ar9300_get_eeprom_rev,
.set_board_values = ath9k_hw_ar9300_set_board_values,
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
index ab21a4915981..6335a867527e 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
@@ -233,7 +233,8 @@ struct ar9300_modal_eep_header {
u8 thresh62;
__le32 papdRateMaskHt20;
__le32 papdRateMaskHt40;
- u8 futureModal[10];
+ __le16 switchcomspdt;
+ u8 futureModal[8];
} __packed;
struct ar9300_cal_data_per_freq_op_loop {
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
index ad2bb2bf4e8a..fb937ba93e0c 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
@@ -21,6 +21,9 @@
#include "ar9340_initvals.h"
#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 */
@@ -31,6 +34,14 @@
*/
static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
{
+#define PCIE_PLL_ON_CREQ_DIS_L1_2P0 \
+ ar9462_pciephy_pll_on_clkreq_disable_L1_2p0
+
+#define AR9462_BB_CTX_COEFJ(x) \
+ ar9462_##x##_baseband_core_txfir_coeff_japan_2484
+
+#define AR9462_BBC_TXIFR_COEFFJ \
+ ar9462_2p0_baseband_core_txfir_coeff_japan_2484
if (AR_SREV_9330_11(ah)) {
/* mac */
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
@@ -253,6 +264,182 @@ 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);
+ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], ar9462_2p0_mac_core,
+ ARRAY_SIZE(ar9462_2p0_mac_core), 2);
+ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
+ ar9462_2p0_mac_postamble,
+ ARRAY_SIZE(ar9462_2p0_mac_postamble), 5);
+
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
+ ar9462_2p0_baseband_core,
+ ARRAY_SIZE(ar9462_2p0_baseband_core), 2);
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
+ ar9462_2p0_baseband_postamble,
+ ARRAY_SIZE(ar9462_2p0_baseband_postamble), 5);
+
+ INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
+ ar9462_2p0_radio_core,
+ ARRAY_SIZE(ar9462_2p0_radio_core), 2);
+ INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
+ ar9462_2p0_radio_postamble,
+ ARRAY_SIZE(ar9462_2p0_radio_postamble), 5);
+ INIT_INI_ARRAY(&ah->ini_radio_post_sys2ant,
+ ar9462_2p0_radio_postamble_sys2ant,
+ ARRAY_SIZE(ar9462_2p0_radio_postamble_sys2ant),
+ 5);
+
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
+ ar9462_2p0_soc_preamble,
+ ARRAY_SIZE(ar9462_2p0_soc_preamble), 2);
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
+ ar9462_2p0_soc_postamble,
+ ARRAY_SIZE(ar9462_2p0_soc_postamble), 5);
+
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9462_common_rx_gain_table_2p0,
+ ARRAY_SIZE(ar9462_common_rx_gain_table_2p0), 2);
+
+ INIT_INI_ARRAY(&ah->ini_BTCOEX_MAX_TXPWR,
+ ar9462_2p0_BTCOEX_MAX_TXPWR_table,
+ ARRAY_SIZE(ar9462_2p0_BTCOEX_MAX_TXPWR_table),
+ 2);
+
+ /* Awake -> Sleep Setting */
+ INIT_INI_ARRAY(&ah->iniPcieSerdes,
+ PCIE_PLL_ON_CREQ_DIS_L1_2P0,
+ ARRAY_SIZE(PCIE_PLL_ON_CREQ_DIS_L1_2P0),
+ 2);
+ /* Sleep -> Awake Setting */
+ INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
+ PCIE_PLL_ON_CREQ_DIS_L1_2P0,
+ ARRAY_SIZE(PCIE_PLL_ON_CREQ_DIS_L1_2P0),
+ 2);
+
+ /* Fast clock modal settings */
+ INIT_INI_ARRAY(&ah->iniModesAdditional,
+ ar9462_modes_fast_clock_2p0,
+ ARRAY_SIZE(ar9462_modes_fast_clock_2p0), 3);
+
+ INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
+ AR9462_BB_CTX_COEFJ(2p0),
+ ARRAY_SIZE(AR9462_BB_CTX_COEFJ(2p0)), 2);
+
+ INIT_INI_ARRAY(&ah->ini_japan2484, AR9462_BBC_TXIFR_COEFFJ,
+ ARRAY_SIZE(AR9462_BBC_TXIFR_COEFFJ), 2);
+
+ } else if (AR_SREV_9580(ah)) {
+ /* mac */
+ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
+ ar9580_1p0_mac_core,
+ ARRAY_SIZE(ar9580_1p0_mac_core), 2);
+ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
+ ar9580_1p0_mac_postamble,
+ ARRAY_SIZE(ar9580_1p0_mac_postamble), 5);
+
+ /* bb */
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
+ ar9580_1p0_baseband_core,
+ ARRAY_SIZE(ar9580_1p0_baseband_core), 2);
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
+ ar9580_1p0_baseband_postamble,
+ ARRAY_SIZE(ar9580_1p0_baseband_postamble), 5);
+
+ /* radio */
+ INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
+ ar9580_1p0_radio_core,
+ ARRAY_SIZE(ar9580_1p0_radio_core), 2);
+ INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
+ ar9580_1p0_radio_postamble,
+ ARRAY_SIZE(ar9580_1p0_radio_postamble), 5);
+
+ /* soc */
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
+ ar9580_1p0_soc_preamble,
+ ARRAY_SIZE(ar9580_1p0_soc_preamble), 2);
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
+ ar9580_1p0_soc_postamble,
+ ARRAY_SIZE(ar9580_1p0_soc_postamble), 5);
+
+ /* rx/tx gain */
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9580_1p0_rx_gain_table,
+ ARRAY_SIZE(ar9580_1p0_rx_gain_table), 2);
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9580_1p0_low_ob_db_tx_gain_table,
+ ARRAY_SIZE(ar9580_1p0_low_ob_db_tx_gain_table),
+ 5);
+
+ INIT_INI_ARRAY(&ah->iniModesAdditional,
+ ar9580_1p0_modes_fast_clock,
+ ARRAY_SIZE(ar9580_1p0_modes_fast_clock),
+ 3);
} else {
/* mac */
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
@@ -323,178 +510,293 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
}
}
+static void ar9003_tx_gain_table_mode0(struct ath_hw *ah)
+{
+ if (AR_SREV_9330_12(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9331_modes_lowest_ob_db_tx_gain_1p2,
+ ARRAY_SIZE(ar9331_modes_lowest_ob_db_tx_gain_1p2),
+ 5);
+ else if (AR_SREV_9330_11(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9331_modes_lowest_ob_db_tx_gain_1p1,
+ ARRAY_SIZE(ar9331_modes_lowest_ob_db_tx_gain_1p1),
+ 5);
+ else if (AR_SREV_9340(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
+ ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
+ 5);
+ else if (AR_SREV_9485_11(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9485_modes_lowest_ob_db_tx_gain_1_1,
+ ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1),
+ 5);
+ else if (AR_SREV_9580(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ 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,
+ ARRAY_SIZE(ar9462_modes_low_ob_db_tx_gain_table_2p0),
+ 5);
+ else
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_lowest_ob_db_tx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2),
+ 5);
+}
+
+static void ar9003_tx_gain_table_mode1(struct ath_hw *ah)
+{
+ if (AR_SREV_9330_12(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9331_modes_high_ob_db_tx_gain_1p2,
+ ARRAY_SIZE(ar9331_modes_high_ob_db_tx_gain_1p2),
+ 5);
+ else if (AR_SREV_9330_11(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9331_modes_high_ob_db_tx_gain_1p1,
+ ARRAY_SIZE(ar9331_modes_high_ob_db_tx_gain_1p1),
+ 5);
+ else if (AR_SREV_9340(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
+ ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
+ 5);
+ else if (AR_SREV_9485_11(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9485Modes_high_ob_db_tx_gain_1_1,
+ ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_1),
+ 5);
+ else if (AR_SREV_9580(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ 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,
+ ARRAY_SIZE(ar9462_modes_high_ob_db_tx_gain_table_2p0),
+ 5);
+ else
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_high_ob_db_tx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p2),
+ 5);
+}
+
+static void ar9003_tx_gain_table_mode2(struct ath_hw *ah)
+{
+ if (AR_SREV_9330_12(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9331_modes_low_ob_db_tx_gain_1p2,
+ ARRAY_SIZE(ar9331_modes_low_ob_db_tx_gain_1p2),
+ 5);
+ else if (AR_SREV_9330_11(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9331_modes_low_ob_db_tx_gain_1p1,
+ ARRAY_SIZE(ar9331_modes_low_ob_db_tx_gain_1p1),
+ 5);
+ else if (AR_SREV_9340(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
+ ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
+ 5);
+ else if (AR_SREV_9485_11(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9485Modes_low_ob_db_tx_gain_1_1,
+ ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_1),
+ 5);
+ else if (AR_SREV_9580(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9580_1p0_low_ob_db_tx_gain_table,
+ ARRAY_SIZE(ar9580_1p0_low_ob_db_tx_gain_table),
+ 5);
+ else
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_low_ob_db_tx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p2),
+ 5);
+}
+
+static void ar9003_tx_gain_table_mode3(struct ath_hw *ah)
+{
+ if (AR_SREV_9330_12(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9331_modes_high_power_tx_gain_1p2,
+ ARRAY_SIZE(ar9331_modes_high_power_tx_gain_1p2),
+ 5);
+ else if (AR_SREV_9330_11(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9331_modes_high_power_tx_gain_1p1,
+ ARRAY_SIZE(ar9331_modes_high_power_tx_gain_1p1),
+ 5);
+ else if (AR_SREV_9340(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
+ ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
+ 5);
+ else if (AR_SREV_9485_11(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9485Modes_high_power_tx_gain_1_1,
+ ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_1),
+ 5);
+ else if (AR_SREV_9580(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9580_1p0_high_power_tx_gain_table,
+ ARRAY_SIZE(ar9580_1p0_high_power_tx_gain_table),
+ 5);
+ else
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_high_power_tx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Modes_high_power_tx_gain_table_2p2),
+ 5);
+}
+
static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
{
switch (ar9003_hw_get_tx_gain_idx(ah)) {
case 0:
default:
- if (AR_SREV_9330_12(ah))
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9331_modes_lowest_ob_db_tx_gain_1p2,
- ARRAY_SIZE(ar9331_modes_lowest_ob_db_tx_gain_1p2),
- 5);
- else if (AR_SREV_9330_11(ah))
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9331_modes_lowest_ob_db_tx_gain_1p1,
- ARRAY_SIZE(ar9331_modes_lowest_ob_db_tx_gain_1p1),
- 5);
- else if (AR_SREV_9340(ah))
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
- ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
- 5);
- else if (AR_SREV_9485_11(ah))
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9485_modes_lowest_ob_db_tx_gain_1_1,
- ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1),
- 5);
- else
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9300Modes_lowest_ob_db_tx_gain_table_2p2,
- ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2),
- 5);
+ ar9003_tx_gain_table_mode0(ah);
break;
case 1:
- if (AR_SREV_9330_12(ah))
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9331_modes_high_ob_db_tx_gain_1p2,
- ARRAY_SIZE(ar9331_modes_high_ob_db_tx_gain_1p2),
- 5);
- else if (AR_SREV_9330_11(ah))
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9331_modes_high_ob_db_tx_gain_1p1,
- ARRAY_SIZE(ar9331_modes_high_ob_db_tx_gain_1p1),
- 5);
- else if (AR_SREV_9340(ah))
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
- ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
- 5);
- else if (AR_SREV_9485_11(ah))
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9485Modes_high_ob_db_tx_gain_1_1,
- ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_1),
- 5);
- else
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9300Modes_high_ob_db_tx_gain_table_2p2,
- ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p2),
- 5);
+ ar9003_tx_gain_table_mode1(ah);
break;
case 2:
- if (AR_SREV_9330_12(ah))
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9331_modes_low_ob_db_tx_gain_1p2,
- ARRAY_SIZE(ar9331_modes_low_ob_db_tx_gain_1p2),
- 5);
- else if (AR_SREV_9330_11(ah))
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9331_modes_low_ob_db_tx_gain_1p1,
- ARRAY_SIZE(ar9331_modes_low_ob_db_tx_gain_1p1),
- 5);
- else if (AR_SREV_9340(ah))
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
- ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
- 5);
- else if (AR_SREV_9485_11(ah))
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9485Modes_low_ob_db_tx_gain_1_1,
- ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_1),
- 5);
- else
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9300Modes_low_ob_db_tx_gain_table_2p2,
- ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p2),
- 5);
+ ar9003_tx_gain_table_mode2(ah);
break;
case 3:
- if (AR_SREV_9330_12(ah))
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9331_modes_high_power_tx_gain_1p2,
- ARRAY_SIZE(ar9331_modes_high_power_tx_gain_1p2),
- 5);
- else if (AR_SREV_9330_11(ah))
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9331_modes_high_power_tx_gain_1p1,
- ARRAY_SIZE(ar9331_modes_high_power_tx_gain_1p1),
- 5);
- else if (AR_SREV_9340(ah))
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
- ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
- 5);
- else if (AR_SREV_9485_11(ah))
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9485Modes_high_power_tx_gain_1_1,
- ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_1),
- 5);
- else
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9300Modes_high_power_tx_gain_table_2p2,
- ARRAY_SIZE(ar9300Modes_high_power_tx_gain_table_2p2),
- 5);
+ ar9003_tx_gain_table_mode3(ah);
break;
}
}
+static void ar9003_rx_gain_table_mode0(struct ath_hw *ah)
+{
+ if (AR_SREV_9330_12(ah))
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9331_common_rx_gain_1p2,
+ ARRAY_SIZE(ar9331_common_rx_gain_1p2),
+ 2);
+ else if (AR_SREV_9330_11(ah))
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9331_common_rx_gain_1p1,
+ ARRAY_SIZE(ar9331_common_rx_gain_1p1),
+ 2);
+ else if (AR_SREV_9340(ah))
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9340Common_rx_gain_table_1p0,
+ ARRAY_SIZE(ar9340Common_rx_gain_table_1p0),
+ 2);
+ else if (AR_SREV_9485_11(ah))
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9485Common_wo_xlna_rx_gain_1_1,
+ ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1),
+ 2);
+ else if (AR_SREV_9580(ah))
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ 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,
+ ARRAY_SIZE(ar9462_common_rx_gain_table_2p0),
+ 2);
+ else
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9300Common_rx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Common_rx_gain_table_2p2),
+ 2);
+}
+
+static void ar9003_rx_gain_table_mode1(struct ath_hw *ah)
+{
+ if (AR_SREV_9330_12(ah))
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9331_common_wo_xlna_rx_gain_1p2,
+ ARRAY_SIZE(ar9331_common_wo_xlna_rx_gain_1p2),
+ 2);
+ else if (AR_SREV_9330_11(ah))
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9331_common_wo_xlna_rx_gain_1p1,
+ ARRAY_SIZE(ar9331_common_wo_xlna_rx_gain_1p1),
+ 2);
+ else if (AR_SREV_9340(ah))
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9340Common_wo_xlna_rx_gain_table_1p0,
+ ARRAY_SIZE(ar9340Common_wo_xlna_rx_gain_table_1p0),
+ 2);
+ else if (AR_SREV_9485_11(ah))
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ 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,
+ ARRAY_SIZE(ar9462_common_wo_xlna_rx_gain_table_2p0),
+ 2);
+ else if (AR_SREV_9580(ah))
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9580_1p0_wo_xlna_rx_gain_table,
+ ARRAY_SIZE(ar9580_1p0_wo_xlna_rx_gain_table),
+ 2);
+ else
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9300Common_wo_xlna_rx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p2),
+ 2);
+}
+
+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))
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ 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)
{
switch (ar9003_hw_get_rx_gain_idx(ah)) {
case 0:
default:
- if (AR_SREV_9330_12(ah))
- INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9331_common_rx_gain_1p2,
- ARRAY_SIZE(ar9331_common_rx_gain_1p2),
- 2);
- else if (AR_SREV_9330_11(ah))
- INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9331_common_rx_gain_1p1,
- ARRAY_SIZE(ar9331_common_rx_gain_1p1),
- 2);
- else if (AR_SREV_9340(ah))
- INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9340Common_rx_gain_table_1p0,
- ARRAY_SIZE(ar9340Common_rx_gain_table_1p0),
- 2);
- else if (AR_SREV_9485_11(ah))
- INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9485Common_wo_xlna_rx_gain_1_1,
- ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1),
- 2);
- else
- INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9300Common_rx_gain_table_2p2,
- ARRAY_SIZE(ar9300Common_rx_gain_table_2p2),
- 2);
+ ar9003_rx_gain_table_mode0(ah);
break;
case 1:
- if (AR_SREV_9330_12(ah))
- INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9331_common_wo_xlna_rx_gain_1p2,
- ARRAY_SIZE(ar9331_common_wo_xlna_rx_gain_1p2),
- 2);
- else if (AR_SREV_9330_11(ah))
- INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9331_common_wo_xlna_rx_gain_1p1,
- ARRAY_SIZE(ar9331_common_wo_xlna_rx_gain_1p1),
- 2);
- else if (AR_SREV_9340(ah))
- INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9340Common_wo_xlna_rx_gain_table_1p0,
- ARRAY_SIZE(ar9340Common_wo_xlna_rx_gain_table_1p0),
- 2);
- else if (AR_SREV_9485_11(ah))
- INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9485Common_wo_xlna_rx_gain_1_1,
- ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1),
- 2);
- else
- INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9300Common_wo_xlna_rx_gain_table_2p2,
- ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p2),
- 2);
+ ar9003_rx_gain_table_mode1(ah);
+ break;
+ case 2:
+ ar9003_rx_gain_table_mode2(ah);
break;
}
}
@@ -516,14 +818,10 @@ static void ar9003_hw_init_mode_gain_regs(struct ath_hw *ah)
* register as the other analog registers. Hence the 9 writes.
*/
static void ar9003_hw_configpcipowersave(struct ath_hw *ah,
- int restore,
- int power_off)
+ bool power_off)
{
- if (ah->is_pciexpress != true || ah->aspm_enabled != true)
- return;
-
/* Nothing to do on restore for 11N */
- if (!restore) {
+ if (!power_off /* !restore */) {
/* set bit 19 to allow forcing of pcie core into L1 state */
REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index 8ff0b88a29b9..b363cc06cfd9 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -21,6 +21,132 @@ static void ar9003_hw_rx_enable(struct ath_hw *hw)
REG_WRITE(hw, AR_CR, 0);
}
+static void
+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;
+
+ val = (ATHEROS_VENDOR_ID << AR_DescId_S) |
+ (1 << AR_TxRxDesc_S) |
+ (1 << AR_CtrlStat_S) |
+ (i->qcu << AR_TxQcuNum_S) | 0x17;
+
+ checksum += val;
+ ACCESS_ONCE(ads->info) = val;
+
+ checksum += i->link;
+ ACCESS_ONCE(ads->link) = i->link;
+
+ checksum += i->buf_addr[0];
+ ACCESS_ONCE(ads->data0) = i->buf_addr[0];
+ checksum += i->buf_addr[1];
+ ACCESS_ONCE(ads->data1) = i->buf_addr[1];
+ checksum += i->buf_addr[2];
+ ACCESS_ONCE(ads->data2) = i->buf_addr[2];
+ checksum += i->buf_addr[3];
+ ACCESS_ONCE(ads->data3) = i->buf_addr[3];
+
+ checksum += (val = (i->buf_len[0] << AR_BufLen_S) & AR_BufLen);
+ ACCESS_ONCE(ads->ctl3) = val;
+ checksum += (val = (i->buf_len[1] << AR_BufLen_S) & AR_BufLen);
+ ACCESS_ONCE(ads->ctl5) = val;
+ checksum += (val = (i->buf_len[2] << AR_BufLen_S) & AR_BufLen);
+ ACCESS_ONCE(ads->ctl7) = val;
+ checksum += (val = (i->buf_len[3] << AR_BufLen_S) & AR_BufLen);
+ ACCESS_ONCE(ads->ctl9) = val;
+
+ checksum = (u16) (((checksum & 0xffff) + (checksum >> 16)) & 0xffff);
+ ACCESS_ONCE(ads->ctl10) = checksum;
+
+ if (i->is_first || i->is_last) {
+ ACCESS_ONCE(ads->ctl13) = set11nTries(i->rates, 0)
+ | set11nTries(i->rates, 1)
+ | set11nTries(i->rates, 2)
+ | set11nTries(i->rates, 3)
+ | (i->dur_update ? AR_DurUpdateEna : 0)
+ | SM(0, AR_BurstDur);
+
+ ACCESS_ONCE(ads->ctl14) = set11nRate(i->rates, 0)
+ | set11nRate(i->rates, 1)
+ | set11nRate(i->rates, 2)
+ | set11nRate(i->rates, 3);
+ } else {
+ ACCESS_ONCE(ads->ctl13) = 0;
+ ACCESS_ONCE(ads->ctl14) = 0;
+ }
+
+ ads->ctl20 = 0;
+ ads->ctl21 = 0;
+ ads->ctl22 = 0;
+
+ ctl17 = SM(i->keytype, AR_EncrType);
+ if (!i->is_first) {
+ ACCESS_ONCE(ads->ctl11) = 0;
+ ACCESS_ONCE(ads->ctl12) = i->is_last ? 0 : AR_TxMore;
+ ACCESS_ONCE(ads->ctl15) = 0;
+ ACCESS_ONCE(ads->ctl16) = 0;
+ ACCESS_ONCE(ads->ctl17) = ctl17;
+ ACCESS_ONCE(ads->ctl18) = 0;
+ ACCESS_ONCE(ads->ctl19) = 0;
+ return;
+ }
+
+ ACCESS_ONCE(ads->ctl11) = (i->pkt_len & AR_FrameLen)
+ | (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
+ | SM(i->txpower, AR_XmitPower)
+ | (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
+ | (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
+ | (i->flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0)
+ | (i->flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
+ | (i->flags & ATH9K_TXDESC_RTSENA ? AR_RTSEnable :
+ (i->flags & ATH9K_TXDESC_CTSENA ? AR_CTSEnable : 0));
+
+ ctl12 = (i->keyix != ATH9K_TXKEYIX_INVALID ?
+ SM(i->keyix, AR_DestIdx) : 0)
+ | SM(i->type, AR_FrameType)
+ | (i->flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
+ | (i->flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
+ | (i->flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
+
+ ctl17 |= (i->flags & ATH9K_TXDESC_LDPC ? AR_LDPC : 0);
+ switch (i->aggr) {
+ case AGGR_BUF_FIRST:
+ ctl17 |= SM(i->aggr_len, AR_AggrLen);
+ /* fall through */
+ case AGGR_BUF_MIDDLE:
+ ctl12 |= AR_IsAggr | AR_MoreAggr;
+ ctl17 |= SM(i->ndelim, AR_PadDelim);
+ break;
+ case AGGR_BUF_LAST:
+ ctl12 |= AR_IsAggr;
+ break;
+ case AGGR_BUF_NONE:
+ break;
+ }
+
+ val = (i->flags & ATH9K_TXDESC_PAPRD) >> ATH9K_TXDESC_PAPRD_S;
+ ctl12 |= SM(val, AR_PAPRDChainMask);
+
+ ACCESS_ONCE(ads->ctl12) = ctl12;
+ ACCESS_ONCE(ads->ctl17) = ctl17;
+
+ ACCESS_ONCE(ads->ctl15) = set11nPktDurRTSCTS(i->rates, 0)
+ | set11nPktDurRTSCTS(i->rates, 1);
+
+ ACCESS_ONCE(ads->ctl16) = set11nPktDurRTSCTS(i->rates, 2)
+ | set11nPktDurRTSCTS(i->rates, 3);
+
+ ACCESS_ONCE(ads->ctl18) = set11nRateFlags(i->rates, 0)
+ | set11nRateFlags(i->rates, 1)
+ | set11nRateFlags(i->rates, 2)
+ | set11nRateFlags(i->rates, 3)
+ | SM(i->rtscts_rate, AR_RTSCTSRate);
+
+ ACCESS_ONCE(ads->ctl19) = AR_Not_Sounding;
+}
+
static u16 ar9003_calc_ptr_chksum(struct ar9003_txc *ads)
{
int checksum;
@@ -185,47 +311,6 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
return true;
}
-static void ar9003_hw_fill_txdesc(struct ath_hw *ah, void *ds, u32 seglen,
- bool is_firstseg, bool is_lastseg,
- const void *ds0, dma_addr_t buf_addr,
- unsigned int qcu)
-{
- struct ar9003_txc *ads = (struct ar9003_txc *) ds;
- unsigned int descid = 0;
-
- ads->info = (ATHEROS_VENDOR_ID << AR_DescId_S) |
- (1 << AR_TxRxDesc_S) |
- (1 << AR_CtrlStat_S) |
- (qcu << AR_TxQcuNum_S) | 0x17;
-
- ads->data0 = buf_addr;
- ads->data1 = 0;
- ads->data2 = 0;
- ads->data3 = 0;
-
- ads->ctl3 = (seglen << AR_BufLen_S);
- ads->ctl3 &= AR_BufLen;
-
- /* Fill in pointer checksum and descriptor id */
- ads->ctl10 = ar9003_calc_ptr_chksum(ads);
- ads->ctl10 |= (descid << AR_TxDescId_S);
-
- if (is_firstseg) {
- ads->ctl12 |= (is_lastseg ? 0 : AR_TxMore);
- } else if (is_lastseg) {
- ads->ctl11 = 0;
- ads->ctl12 = 0;
- ads->ctl13 = AR9003TXC_CONST(ds0)->ctl13;
- ads->ctl14 = AR9003TXC_CONST(ds0)->ctl14;
- } else {
- /* XXX Intermediate descriptor in a multi-descriptor frame.*/
- ads->ctl11 = 0;
- ads->ctl12 = AR_TxMore;
- ads->ctl13 = 0;
- ads->ctl14 = 0;
- }
-}
-
static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds,
struct ath_tx_status *ts)
{
@@ -253,8 +338,6 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds,
return -EIO;
}
- if (status & AR_TxOpExceeded)
- ts->ts_status |= ATH9K_TXERR_XTXOP;
ts->ts_rateindex = MS(status, AR_FinalTxIdx);
ts->ts_seqnum = MS(status, AR_SeqNum);
ts->tid = MS(status, AR_TxTid);
@@ -264,6 +347,8 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds,
ts->ts_status = 0;
ts->ts_flags = 0;
+ if (status & AR_TxOpExceeded)
+ ts->ts_status |= ATH9K_TXERR_XTXOP;
status = ACCESS_ONCE(ads->status2);
ts->ts_rssi_ctl0 = MS(status, AR_TxRSSIAnt00);
ts->ts_rssi_ctl1 = MS(status, AR_TxRSSIAnt01);
@@ -310,185 +395,6 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds,
return 0;
}
-static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
- u32 pktlen, enum ath9k_pkt_type type, u32 txpower,
- u32 keyIx, enum ath9k_key_type keyType, u32 flags)
-{
- struct ar9003_txc *ads = (struct ar9003_txc *) ds;
-
- if (txpower > ah->txpower_limit)
- txpower = ah->txpower_limit;
-
- if (txpower > 63)
- txpower = 63;
-
- ads->ctl11 = (pktlen & AR_FrameLen)
- | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
- | SM(txpower, AR_XmitPower)
- | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
- | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
- | (flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0);
-
- ads->ctl12 =
- (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0)
- | SM(type, AR_FrameType)
- | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
- | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
- | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
-
- ads->ctl17 = SM(keyType, AR_EncrType) |
- (flags & ATH9K_TXDESC_LDPC ? AR_LDPC : 0);
- ads->ctl18 = 0;
- ads->ctl19 = AR_Not_Sounding;
-
- ads->ctl20 = 0;
- ads->ctl21 = 0;
- ads->ctl22 = 0;
-}
-
-static void ar9003_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
-{
- struct ar9003_txc *ads = (struct ar9003_txc *) ds;
-
- if (val)
- ads->ctl11 |= AR_ClrDestMask;
- else
- ads->ctl11 &= ~AR_ClrDestMask;
-}
-
-static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
- void *lastds,
- u32 durUpdateEn, u32 rtsctsRate,
- u32 rtsctsDuration,
- struct ath9k_11n_rate_series series[],
- u32 nseries, u32 flags)
-{
- struct ar9003_txc *ads = (struct ar9003_txc *) ds;
- struct ar9003_txc *last_ads = (struct ar9003_txc *) lastds;
- u_int32_t ctl11;
-
- if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
- ctl11 = ads->ctl11;
-
- if (flags & ATH9K_TXDESC_RTSENA) {
- ctl11 &= ~AR_CTSEnable;
- ctl11 |= AR_RTSEnable;
- } else {
- ctl11 &= ~AR_RTSEnable;
- ctl11 |= AR_CTSEnable;
- }
-
- ads->ctl11 = ctl11;
- } else {
- ads->ctl11 = (ads->ctl11 & ~(AR_RTSEnable | AR_CTSEnable));
- }
-
- ads->ctl13 = set11nTries(series, 0)
- | set11nTries(series, 1)
- | set11nTries(series, 2)
- | set11nTries(series, 3)
- | (durUpdateEn ? AR_DurUpdateEna : 0)
- | SM(0, AR_BurstDur);
-
- ads->ctl14 = set11nRate(series, 0)
- | set11nRate(series, 1)
- | set11nRate(series, 2)
- | set11nRate(series, 3);
-
- ads->ctl15 = set11nPktDurRTSCTS(series, 0)
- | set11nPktDurRTSCTS(series, 1);
-
- ads->ctl16 = set11nPktDurRTSCTS(series, 2)
- | set11nPktDurRTSCTS(series, 3);
-
- ads->ctl18 = set11nRateFlags(series, 0)
- | set11nRateFlags(series, 1)
- | set11nRateFlags(series, 2)
- | set11nRateFlags(series, 3)
- | SM(rtsctsRate, AR_RTSCTSRate);
- ads->ctl19 = AR_Not_Sounding;
-
- last_ads->ctl13 = ads->ctl13;
- last_ads->ctl14 = ads->ctl14;
-}
-
-static void ar9003_hw_set11n_aggr_first(struct ath_hw *ah, void *ds,
- u32 aggrLen)
-{
-#define FIRST_DESC_NDELIMS 60
- struct ar9003_txc *ads = (struct ar9003_txc *) ds;
-
- ads->ctl12 |= (AR_IsAggr | AR_MoreAggr);
-
- if (ah->ent_mode & AR_ENT_OTP_MPSD) {
- u32 ctl17, ndelim;
- /*
- * Add delimiter when using RTS/CTS with aggregation
- * and non enterprise AR9003 card
- */
- ctl17 = ads->ctl17;
- ndelim = MS(ctl17, AR_PadDelim);
-
- if (ndelim < FIRST_DESC_NDELIMS) {
- aggrLen += (FIRST_DESC_NDELIMS - ndelim) * 4;
- ndelim = FIRST_DESC_NDELIMS;
- }
-
- ctl17 &= ~AR_AggrLen;
- ctl17 |= SM(aggrLen, AR_AggrLen);
-
- ctl17 &= ~AR_PadDelim;
- ctl17 |= SM(ndelim, AR_PadDelim);
-
- ads->ctl17 = ctl17;
- } else {
- ads->ctl17 &= ~AR_AggrLen;
- ads->ctl17 |= SM(aggrLen, AR_AggrLen);
- }
-}
-
-static void ar9003_hw_set11n_aggr_middle(struct ath_hw *ah, void *ds,
- u32 numDelims)
-{
- struct ar9003_txc *ads = (struct ar9003_txc *) ds;
- unsigned int ctl17;
-
- ads->ctl12 |= (AR_IsAggr | AR_MoreAggr);
-
- /*
- * We use a stack variable to manipulate ctl6 to reduce uncached
- * read modify, modfiy, write.
- */
- ctl17 = ads->ctl17;
- ctl17 &= ~AR_PadDelim;
- ctl17 |= SM(numDelims, AR_PadDelim);
- ads->ctl17 = ctl17;
-}
-
-static void ar9003_hw_set11n_aggr_last(struct ath_hw *ah, void *ds)
-{
- struct ar9003_txc *ads = (struct ar9003_txc *) ds;
-
- ads->ctl12 |= AR_IsAggr;
- ads->ctl12 &= ~AR_MoreAggr;
- ads->ctl17 &= ~AR_PadDelim;
-}
-
-static void ar9003_hw_clr11n_aggr(struct ath_hw *ah, void *ds)
-{
- struct ar9003_txc *ads = (struct ar9003_txc *) ds;
-
- ads->ctl12 &= (~AR_IsAggr & ~AR_MoreAggr);
-}
-
-void ar9003_hw_set_paprd_txdesc(struct ath_hw *ah, void *ds, u8 chains)
-{
- struct ar9003_txc *ads = ds;
-
- ads->ctl12 |= SM(chains, AR_PAPRDChainMask);
-}
-EXPORT_SYMBOL(ar9003_hw_set_paprd_txdesc);
-
void ar9003_hw_attach_mac_ops(struct ath_hw *hw)
{
struct ath_hw_ops *ops = ath9k_hw_ops(hw);
@@ -496,15 +402,8 @@ void ar9003_hw_attach_mac_ops(struct ath_hw *hw)
ops->rx_enable = ar9003_hw_rx_enable;
ops->set_desc_link = ar9003_hw_set_desc_link;
ops->get_isr = ar9003_hw_get_isr;
- ops->fill_txdesc = ar9003_hw_fill_txdesc;
+ ops->set_txdesc = ar9003_set_txdesc;
ops->proc_txdesc = ar9003_hw_proc_txdesc;
- ops->set11n_txdesc = ar9003_hw_set11n_txdesc;
- ops->set11n_ratescenario = ar9003_hw_set11n_ratescenario;
- ops->set11n_aggr_first = ar9003_hw_set11n_aggr_first;
- ops->set11n_aggr_middle = ar9003_hw_set11n_aggr_middle;
- ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last;
- ops->clr11n_aggr = ar9003_hw_clr11n_aggr;
- ops->set_clrdmask = ar9003_hw_set_clrdmask;
}
void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size)
@@ -531,17 +430,18 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
/* TODO: byte swap on big endian for ar9300_10 */
- if ((rxsp->status11 & AR_RxDone) == 0)
- return -EINPROGRESS;
+ if (!rxs) {
+ if ((rxsp->status11 & AR_RxDone) == 0)
+ return -EINPROGRESS;
- if (MS(rxsp->ds_info, AR_DescId) != 0x168c)
- return -EINVAL;
+ if (MS(rxsp->ds_info, AR_DescId) != 0x168c)
+ return -EINVAL;
- if ((rxsp->ds_info & (AR_TxRxDesc | AR_CtrlStat)) != 0)
- return -EINPROGRESS;
+ if ((rxsp->ds_info & (AR_TxRxDesc | AR_CtrlStat)) != 0)
+ return -EINPROGRESS;
- if (!rxs)
return 0;
+ }
rxs->rs_status = 0;
rxs->rs_flags = 0;
@@ -625,8 +525,8 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
rxs->rs_status |= ATH9K_RXERR_DECRYPT;
else if (rxsp->status11 & AR_MichaelErr)
rxs->rs_status |= ATH9K_RXERR_MIC;
- else if (rxsp->status11 & AR_KeyMiss)
- rxs->rs_status |= ATH9K_RXERR_DECRYPT;
+ if (rxsp->status11 & AR_KeyMiss)
+ rxs->rs_status |= ATH9K_RXERR_KEYMISS;
}
return 0;
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
index f80d1d633980..0c462c904cbe 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
@@ -19,7 +19,6 @@
void ar9003_paprd_enable(struct ath_hw *ah, bool val)
{
- struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
struct ath9k_channel *chan = ah->curchan;
struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
@@ -54,13 +53,7 @@ void ar9003_paprd_enable(struct ath_hw *ah, bool val)
if (val) {
ah->paprd_table_write_done = true;
-
- ah->eep_ops->set_txpower(ah, chan,
- ath9k_regd_get_ctl(regulatory, chan),
- chan->chan->max_antenna_gain * 2,
- chan->chan->max_power * 2,
- min((u32) MAX_RATE_POWER,
- (u32) regulatory->power_limit), false);
+ ath9k_hw_apply_txpower(ah, chan);
}
REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B0,
@@ -113,7 +106,7 @@ static int ar9003_get_training_power_5g(struct ath_hw *ah)
if (delta > scale)
return -1;
- switch (get_streams(common->tx_chainmask)) {
+ switch (get_streams(ah->txchainmask)) {
case 1:
delta = 6;
break;
@@ -126,7 +119,7 @@ static int ar9003_get_training_power_5g(struct ath_hw *ah)
default:
delta = 0;
ath_dbg(common, ATH_DBG_CALIBRATE,
- "Invalid tx-chainmask: %u\n", common->tx_chainmask);
+ "Invalid tx-chainmask: %u\n", ah->txchainmask);
}
power += delta;
@@ -147,7 +140,7 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah)
AR_PHY_PAPRD_CTRL1_B2
};
int training_power;
- int i;
+ int i, val;
if (IS_CHAN_2GHZ(ah->curchan))
training_power = ar9003_get_training_power_2g(ah);
@@ -207,8 +200,9 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah)
AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING, 28);
REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE, 1);
+ val = AR_SREV_9462(ah) ? 0x91 : 147;
REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL2,
- AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN, 147);
+ AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN, val);
REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN, 4);
REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
@@ -217,7 +211,7 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah)
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES, 7);
REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL, 1);
- if (AR_SREV_9485(ah))
+ if (AR_SREV_9485(ah) || AR_SREV_9462(ah))
REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP,
-3);
@@ -225,9 +219,10 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah)
REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP,
-6);
+ val = AR_SREV_9462(ah) ? -10 : -15;
REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE,
- -15);
+ val);
REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE, 1);
REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4,
@@ -757,6 +752,7 @@ void ar9003_paprd_populate_single_table(struct ath_hw *ah,
training_power);
if (ah->caps.tx_chainmask & BIT(2))
+ /* val AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL correct? */
REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B2,
AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
training_power);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index 1baca8e4715d..fe96997921d3 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -370,7 +370,7 @@ static void ar9003_hw_spur_ofdm_work(struct ath_hw *ah,
else
spur_subchannel_sd = 0;
- spur_freq_sd = ((freq_offset + 10) << 9) / 11;
+ spur_freq_sd = (freq_offset << 9) / 11;
} else {
if (REG_READ_FIELD(ah, AR_PHY_GEN_CTRL,
@@ -379,7 +379,7 @@ static void ar9003_hw_spur_ofdm_work(struct ath_hw *ah,
else
spur_subchannel_sd = 1;
- spur_freq_sd = ((freq_offset - 10) << 9) / 11;
+ spur_freq_sd = (freq_offset << 9) / 11;
}
@@ -482,7 +482,7 @@ static void ar9003_hw_set_channel_regs(struct ath_hw *ah,
(REG_READ(ah, AR_PHY_GEN_CTRL) & AR_PHY_GC_ENABLE_DAC_FIFO);
/* Enable 11n HT, 20 MHz */
- phymode = AR_PHY_GC_HT_EN | AR_PHY_GC_SINGLE_HT_LTF1 | AR_PHY_GC_WALSH |
+ phymode = AR_PHY_GC_HT_EN | AR_PHY_GC_SINGLE_HT_LTF1 |
AR_PHY_GC_SHORT_GI_40 | enableDacFifo;
/* Configure baseband for dynamic 20/40 operation */
@@ -540,7 +540,7 @@ static void ar9003_hw_init_bb(struct ath_hw *ah,
udelay(synthDelay + BASE_ACTIVATE_DELAY);
}
-void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
+static void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
{
switch (rx) {
case 0x5:
@@ -559,6 +559,9 @@ void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && (tx == 0x7))
REG_WRITE(ah, AR_SELFGEN_MASK, 0x3);
+ else if (AR_SREV_9462(ah))
+ /* xxx only when MCI support is enabled */
+ REG_WRITE(ah, AR_SELFGEN_MASK, 0x3);
else
REG_WRITE(ah, AR_SELFGEN_MASK, tx);
@@ -592,6 +595,9 @@ static void ar9003_hw_override_ini(struct ath_hw *ah)
val = REG_READ(ah, AR_PCU_MISC_MODE2) & (~AR_ADHOC_MCAST_KEYID_ENABLE);
REG_WRITE(ah, AR_PCU_MISC_MODE2,
val | AR_AGG_WEP_ENABLE_FIX | AR_AGG_WEP_ENABLE);
+
+ REG_SET_BIT(ah, AR_PHY_CCK_DETECT,
+ AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
}
static void ar9003_hw_prog_ini(struct ath_hw *ah,
@@ -625,9 +631,7 @@ static void ar9003_hw_prog_ini(struct ath_hw *ah,
static int ar9003_hw_process_ini(struct ath_hw *ah,
struct ath9k_channel *chan)
{
- struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
unsigned int regWrites = 0, i;
- struct ieee80211_channel *channel = chan->chan;
u32 modesIndex;
switch (chan->chanmode) {
@@ -658,6 +662,10 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
ar9003_hw_prog_ini(ah, &ah->iniMac[i], modesIndex);
ar9003_hw_prog_ini(ah, &ah->iniBB[i], modesIndex);
ar9003_hw_prog_ini(ah, &ah->iniRadio[i], modesIndex);
+ if (i == ATH_INI_POST && AR_SREV_9462_20(ah))
+ ar9003_hw_prog_ini(ah,
+ &ah->ini_radio_post_sys2ant,
+ modesIndex);
}
REG_WRITE_ARRAY(&ah->iniModesRxGain, 1, regWrites);
@@ -671,23 +679,33 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
REG_WRITE_ARRAY(&ah->iniModesAdditional,
modesIndex, regWrites);
- if (AR_SREV_9300(ah))
+ if (AR_SREV_9330(ah))
REG_WRITE_ARRAY(&ah->iniModesAdditional, 1, regWrites);
if (AR_SREV_9340(ah) && !ah->is_clk_25mhz)
REG_WRITE_ARRAY(&ah->iniModesAdditional_40M, 1, regWrites);
+ if (AR_SREV_9462(ah))
+ ar9003_hw_prog_ini(ah, &ah->ini_BTCOEX_MAX_TXPWR, 1);
+
+ ah->modes_index = modesIndex;
ar9003_hw_override_ini(ah);
ar9003_hw_set_channel_regs(ah, chan);
ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
+ ath9k_hw_apply_txpower(ah, chan);
- /* Set TX power */
- ah->eep_ops->set_txpower(ah, chan,
- ath9k_regd_get_ctl(regulatory, chan),
- channel->max_antenna_gain * 2,
- channel->max_power * 2,
- min((u32) MAX_RATE_POWER,
- (u32) regulatory->power_limit), false);
+ if (AR_SREV_9462(ah)) {
+ if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0,
+ AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL))
+ ah->enabled_cals |= TX_IQ_CAL;
+ else
+ ah->enabled_cals &= ~TX_IQ_CAL;
+
+ if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE)
+ ah->enabled_cals |= TX_CL_CAL;
+ else
+ ah->enabled_cals &= ~TX_CL_CAL;
+ }
return 0;
}
@@ -785,16 +803,6 @@ static void ar9003_hw_rfbus_done(struct ath_hw *ah)
REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);
}
-static void ar9003_hw_set_diversity(struct ath_hw *ah, bool value)
-{
- u32 v = REG_READ(ah, AR_PHY_CCK_DETECT);
- if (value)
- v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
- else
- v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
- REG_WRITE(ah, AR_PHY_CCK_DETECT, v);
-}
-
static bool ar9003_hw_ani_control(struct ath_hw *ah,
enum ath9k_ani_cmd cmd, int param)
{
@@ -1253,6 +1261,73 @@ static void ar9003_hw_antdiv_comb_conf_set(struct ath_hw *ah,
REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
}
+static int ar9003_hw_fast_chan_change(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ u8 *ini_reloaded)
+{
+ unsigned int regWrites = 0;
+ u32 modesIndex;
+
+ switch (chan->chanmode) {
+ case CHANNEL_A:
+ case CHANNEL_A_HT20:
+ modesIndex = 1;
+ break;
+ case CHANNEL_A_HT40PLUS:
+ case CHANNEL_A_HT40MINUS:
+ modesIndex = 2;
+ break;
+ case CHANNEL_G:
+ case CHANNEL_G_HT20:
+ case CHANNEL_B:
+ modesIndex = 4;
+ break;
+ case CHANNEL_G_HT40PLUS:
+ case CHANNEL_G_HT40MINUS:
+ modesIndex = 3;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (modesIndex == ah->modes_index) {
+ *ini_reloaded = false;
+ goto set_rfmode;
+ }
+
+ ar9003_hw_prog_ini(ah, &ah->iniSOC[ATH_INI_POST], modesIndex);
+ ar9003_hw_prog_ini(ah, &ah->iniMac[ATH_INI_POST], modesIndex);
+ ar9003_hw_prog_ini(ah, &ah->iniBB[ATH_INI_POST], modesIndex);
+ ar9003_hw_prog_ini(ah, &ah->iniRadio[ATH_INI_POST], modesIndex);
+ if (AR_SREV_9462_20(ah))
+ ar9003_hw_prog_ini(ah,
+ &ah->ini_radio_post_sys2ant,
+ modesIndex);
+
+ REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites);
+
+ /*
+ * For 5GHz channels requiring Fast Clock, apply
+ * different modal values.
+ */
+ if (IS_CHAN_A_FAST_CLOCK(ah, chan))
+ REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex, regWrites);
+
+ if (AR_SREV_9330(ah))
+ REG_WRITE_ARRAY(&ah->iniModesAdditional, 1, regWrites);
+
+ if (AR_SREV_9340(ah) && !ah->is_clk_25mhz)
+ REG_WRITE_ARRAY(&ah->iniModesAdditional_40M, 1, regWrites);
+
+ ah->modes_index = modesIndex;
+ *ini_reloaded = true;
+
+set_rfmode:
+ ar9003_hw_set_rfmode(ah, chan);
+ return 0;
+}
+
void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
@@ -1277,11 +1352,11 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
priv_ops->set_delta_slope = ar9003_hw_set_delta_slope;
priv_ops->rfbus_req = ar9003_hw_rfbus_req;
priv_ops->rfbus_done = ar9003_hw_rfbus_done;
- priv_ops->set_diversity = ar9003_hw_set_diversity;
priv_ops->ani_control = ar9003_hw_ani_control;
priv_ops->do_getnf = ar9003_hw_do_getnf;
priv_ops->ani_cache_ini_regs = ar9003_hw_ani_cache_ini_regs;
priv_ops->set_radar_params = ar9003_hw_set_radar_params;
+ priv_ops->fast_chan_change = ar9003_hw_fast_chan_change;
ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get;
ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set;
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index 5c590429f120..2f4023e66081 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -325,10 +325,10 @@
#define AR_PHY_RX_OCGAIN (AR_AGC_BASE + 0x200)
-#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_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_MAX_GOOD_VAL_9300_2GHZ -95
#define AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ -100
@@ -572,6 +572,8 @@
#define AR_PHY_TXGAIN_TABLE (AR_SM_BASE + 0x300)
+#define AR_PHY_TX_IQCAL_CONTROL_0 (AR_SM_BASE + AR_SREV_9485(ah) ? \
+ 0x3c4 : 0x444)
#define AR_PHY_TX_IQCAL_CONTROL_1 (AR_SM_BASE + AR_SREV_9485(ah) ? \
0x3c8 : 0x448)
#define AR_PHY_TX_IQCAL_START (AR_SM_BASE + AR_SREV_9485(ah) ? \
@@ -581,6 +583,7 @@
#define AR_PHY_TX_IQCAL_CORR_COEFF_B0(_i) (AR_SM_BASE + \
(AR_SREV_9485(ah) ? \
0x3d0 : 0x450) + ((_i) << 2))
+#define AR_PHY_RTT_CTRL (AR_SM_BASE + 0x380)
#define AR_PHY_WATCHDOG_STATUS (AR_SM_BASE + 0x5c0)
#define AR_PHY_WATCHDOG_CTL_1 (AR_SM_BASE + 0x5c4)
@@ -600,6 +603,17 @@
#define AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE 0x0000ff00
#define AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE_S 8
+/* AIC Registers */
+#define AR_PHY_AIC_CTRL_0_B0 (AR_SM_BASE + 0x4b0)
+#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_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
@@ -609,7 +623,35 @@
#define AR_PHY_65NM_CH0_BIAS2 0x160c4
#define AR_PHY_65NM_CH0_BIAS4 0x160cc
#define AR_PHY_65NM_CH0_RXTX4 0x1610c
-#define AR_PHY_65NM_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 : 0x1628c)
+
+#define AR_CH0_TOP (AR_SREV_9300(ah) ? 0x16288 : \
+ ((AR_SREV_9462(ah) ? 0x1628c : 0x16280)))
+#define AR_CH0_TOP_XPABIASLVL (0x300)
+#define AR_CH0_TOP_XPABIASLVL_S (8)
+
+#define AR_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 : \
+ ((AR_SREV_9485(ah) ? 0x1628c : 0x16294)))
+#define AR_CH0_THERM_XPABIASLVL_MSB 0x3
+#define AR_CH0_THERM_XPABIASLVL_MSB_S 0
+#define AR_CH0_THERM_XPASHORT2GND 0x4
+#define AR_CH0_THERM_XPASHORT2GND_S 2
+
+#define AR_SWITCH_TABLE_COM_ALL (0xffff)
+#define AR_SWITCH_TABLE_COM_ALL_S (0)
+#define AR_SWITCH_TABLE_COM_AR9462_ALL (0xffffff)
+#define AR_SWITCH_TABLE_COM_AR9462_ALL_S (0)
+#define AR_SWITCH_TABLE_COM_SPDT (0x00f00000)
+#define AR_SWITCH_TABLE_COM_SPDT_ALL (0x0000fff0)
+#define AR_SWITCH_TABLE_COM_SPDT_ALL_S (4)
+
+#define AR_SWITCH_TABLE_COM2_ALL (0xffffff)
+#define AR_SWITCH_TABLE_COM2_ALL_S (0)
+
+#define AR_SWITCH_TABLE_ALL (0xfff)
+#define AR_SWITCH_TABLE_ALL_S (0)
+
+#define AR_PHY_65NM_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 :\
+ (AR_SREV_9485(ah) ? 0x1628c : 0x16294))
#define AR_PHY_65NM_CH0_THERM_LOCAL 0x80000000
#define AR_PHY_65NM_CH0_THERM_LOCAL_S 31
@@ -625,21 +667,23 @@
#define AR_PHY_65NM_CH2_RXTX1 0x16900
#define AR_PHY_65NM_CH2_RXTX2 0x16904
-#define AR_CH0_TOP2 (AR_SREV_9300(ah) ? 0x1628c : 0x16284)
+#define AR_CH0_TOP2 (AR_SREV_9300(ah) ? 0x1628c : \
+ (AR_SREV_9485(ah) ? 0x16284 : 0x16290))
#define AR_CH0_TOP2_XPABIASLVL 0xf000
#define AR_CH0_TOP2_XPABIASLVL_S 12
-#define AR_CH0_XTAL (AR_SREV_9300(ah) ? 0x16294 : 0x16290)
+#define AR_CH0_XTAL (AR_SREV_9300(ah) ? 0x16294 : \
+ (AR_SREV_9485(ah) ? 0x16290 : 0x16298))
#define AR_CH0_XTAL_CAPINDAC 0x7f000000
#define AR_CH0_XTAL_CAPINDAC_S 24
#define AR_CH0_XTAL_CAPOUTDAC 0x00fe0000
#define AR_CH0_XTAL_CAPOUTDAC_S 17
-#define AR_PHY_PMU1 0x16c40
+#define AR_PHY_PMU1 (AR_SREV_9462(ah) ? 0x16340 : 0x16c40)
#define AR_PHY_PMU1_PWD 0x1
#define AR_PHY_PMU1_PWD_S 0
-#define AR_PHY_PMU2 0x16c44
+#define AR_PHY_PMU2 (AR_SREV_9462(ah) ? 0x16344 : 0x16c44)
#define AR_PHY_PMU2_PGM 0x00200000
#define AR_PHY_PMU2_PGM_S 21
@@ -779,6 +823,22 @@
#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x01000000
#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24
#define AR_PHY_CHANNEL_STATUS_RX_CLEAR 0x00000004
+#define AR_PHY_RTT_CTRL_ENA_RADIO_RETENTION 0x00000001
+#define AR_PHY_RTT_CTRL_ENA_RADIO_RETENTION_S 0
+#define AR_PHY_RTT_CTRL_RESTORE_MASK 0x0000007E
+#define AR_PHY_RTT_CTRL_RESTORE_MASK_S 1
+#define AR_PHY_RTT_CTRL_FORCE_RADIO_RESTORE 0x00000080
+#define AR_PHY_RTT_CTRL_FORCE_RADIO_RESTORE_S 7
+#define AR_PHY_RTT_SW_RTT_TABLE_ACCESS 0x00000001
+#define AR_PHY_RTT_SW_RTT_TABLE_ACCESS_S 0
+#define AR_PHY_RTT_SW_RTT_TABLE_WRITE 0x00000002
+#define AR_PHY_RTT_SW_RTT_TABLE_WRITE_S 1
+#define AR_PHY_RTT_SW_RTT_TABLE_ADDR 0x0000001C
+#define AR_PHY_RTT_SW_RTT_TABLE_ADDR_S 2
+#define AR_PHY_RTT_SW_RTT_TABLE_DATA 0xFFFFFFF0
+#define AR_PHY_RTT_SW_RTT_TABLE_DATA_S 4
+#define AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL 0x80000000
+#define AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL_S 31
#define AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT 0x01fc0000
#define AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT_S 18
#define AR_PHY_TX_IQCAL_START_DO_CAL 0x00000001
@@ -839,19 +899,42 @@
*/
#define AR_SM1_BASE 0xb200
-#define AR_PHY_SWITCH_CHAIN_1 (AR_SM1_BASE + 0x84)
-#define AR_PHY_FCAL_2_1 (AR_SM1_BASE + 0xd0)
-#define AR_PHY_DFT_TONE_CTL_1 (AR_SM1_BASE + 0xd4)
-#define AR_PHY_CL_TAB_1 (AR_SM1_BASE + 0x100)
-#define AR_PHY_CHAN_INFO_GAIN_1 (AR_SM1_BASE + 0x180)
-#define AR_PHY_TPC_4_B1 (AR_SM1_BASE + 0x204)
-#define AR_PHY_TPC_5_B1 (AR_SM1_BASE + 0x208)
-#define AR_PHY_TPC_6_B1 (AR_SM1_BASE + 0x20c)
-#define AR_PHY_TPC_11_B1 (AR_SM1_BASE + 0x220)
-#define AR_PHY_PDADC_TAB_1 (AR_SM1_BASE + 0x240)
+#define AR_PHY_SWITCH_CHAIN_1 (AR_SM1_BASE + 0x84)
+#define AR_PHY_FCAL_2_1 (AR_SM1_BASE + 0xd0)
+#define AR_PHY_DFT_TONE_CTL_1 (AR_SM1_BASE + 0xd4)
+#define AR_PHY_CL_TAB_1 (AR_SM1_BASE + 0x100)
+#define AR_PHY_CHAN_INFO_GAIN_1 (AR_SM1_BASE + 0x180)
+#define AR_PHY_TPC_4_B1 (AR_SM1_BASE + 0x204)
+#define AR_PHY_TPC_5_B1 (AR_SM1_BASE + 0x208)
+#define AR_PHY_TPC_6_B1 (AR_SM1_BASE + 0x20c)
+#define AR_PHY_TPC_11_B1 (AR_SM1_BASE + 0x220)
+#define AR_PHY_PDADC_TAB_1 (AR_SM1_BASE + (AR_SREV_AR9300(ah) ? \
+ 0x240 : 0x280))
+#define AR_PHY_TPC_19_B1 (AR_SM1_BASE + 0x240)
+#define AR_PHY_TPC_19_B1_ALPHA_THERM 0xff
+#define AR_PHY_TPC_19_B1_ALPHA_THERM_S 0
#define AR_PHY_TX_IQCAL_STATUS_B1 (AR_SM1_BASE + 0x48c)
#define AR_PHY_TX_IQCAL_CORR_COEFF_B1(_i) (AR_SM1_BASE + 0x450 + ((_i) << 2))
+/* SM 1 AIC Registers */
+
+#define AR_PHY_AIC_CTRL_0_B1 (AR_SM1_BASE + 0x4b0)
+#define AR_PHY_AIC_CTRL_1_B1 (AR_SM1_BASE + 0x4b4)
+#define AR_PHY_AIC_CTRL_2_B1 (AR_SM1_BASE + 0x4b8)
+#define AR_PHY_AIC_STAT_0_B1 (AR_SM1_BASE + (AR_SREV_9462_10(ah) ? \
+ 0x4c0 : 0x4c4))
+#define AR_PHY_AIC_STAT_1_B1 (AR_SM1_BASE + (AR_SREV_9462_10(ah) ? \
+ 0x4c4 : 0x4c8))
+#define AR_PHY_AIC_CTRL_4_B1 (AR_SM1_BASE + 0x4c0)
+#define AR_PHY_AIC_STAT_2_B1 (AR_SM1_BASE + 0x4cc)
+
+#define AR_PHY_AIC_SRAM_ADDR_B1 (AR_SM1_BASE + 0x5f0)
+#define AR_PHY_AIC_SRAM_DATA_B1 (AR_SM1_BASE + 0x5f4)
+
+#define AR_PHY_RTT_TABLE_SW_INTF_B(i) (0x384 + (i) ? \
+ AR_SM1_BASE : AR_SM_BASE)
+#define AR_PHY_RTT_TABLE_SW_INTF_1_B(i) (0x388 + (i) ? \
+ AR_SM1_BASE : AR_SM_BASE)
/*
* Channel 2 Register Map
*/
@@ -914,6 +997,13 @@
#define AR_PHY_RSSI_3 (AR_AGC3_BASE + 0x180)
+/* GLB Registers */
+#define AR_GLB_BASE 0x20000
+#define AR_PHY_GLB_CONTROL (AR_GLB_BASE + 0x44)
+#define AR_GLB_SCRATCH(_ah) (AR_GLB_BASE + \
+ (AR_SREV_9462_20(_ah) ? 0x4c : 0x50))
+#define AR_GLB_STATUS (AR_GLB_BASE + 0x48)
+
/*
* Misc helper defines
*/
@@ -1124,6 +1214,4 @@
#define AR_PHY_CL_TAB_CL_GAIN_MOD 0x1f
#define AR_PHY_CL_TAB_CL_GAIN_MOD_S 0
-void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
-
#endif /* AR9003_PHY_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_rtt.c b/drivers/net/wireless/ath/ath9k/ar9003_rtt.c
new file mode 100644
index 000000000000..48803ee9c0d6
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/ar9003_rtt.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "hw.h"
+#include "ar9003_phy.h"
+
+#define RTT_RESTORE_TIMEOUT 1000
+#define RTT_ACCESS_TIMEOUT 100
+#define RTT_BAD_VALUE 0x0bad0bad
+
+/*
+ * RTT (Radio Retention Table) hardware implementation information
+ *
+ * There is an internal table (i.e. the rtt) for each chain (or bank).
+ * Each table contains 6 entries and each entry is corresponding to
+ * a specific calibration parameter as depicted below.
+ * 0~2 - DC offset DAC calibration: loop, low, high (offsetI/Q_...)
+ * 3 - Filter cal (filterfc)
+ * 4 - RX gain settings
+ * 5 - Peak detector offset calibration (agc_caldac)
+ */
+
+void ar9003_hw_rtt_enable(struct ath_hw *ah)
+{
+ REG_WRITE(ah, AR_PHY_RTT_CTRL, 1);
+}
+
+void ar9003_hw_rtt_disable(struct ath_hw *ah)
+{
+ REG_WRITE(ah, AR_PHY_RTT_CTRL, 0);
+}
+
+void ar9003_hw_rtt_set_mask(struct ath_hw *ah, u32 rtt_mask)
+{
+ REG_RMW_FIELD(ah, AR_PHY_RTT_CTRL,
+ AR_PHY_RTT_CTRL_RESTORE_MASK, rtt_mask);
+}
+
+bool ar9003_hw_rtt_force_restore(struct ath_hw *ah)
+{
+ if (!ath9k_hw_wait(ah, AR_PHY_RTT_CTRL,
+ AR_PHY_RTT_CTRL_FORCE_RADIO_RESTORE,
+ 0, RTT_RESTORE_TIMEOUT))
+ return false;
+
+ REG_RMW_FIELD(ah, AR_PHY_RTT_CTRL,
+ AR_PHY_RTT_CTRL_FORCE_RADIO_RESTORE, 1);
+
+ if (!ath9k_hw_wait(ah, AR_PHY_RTT_CTRL,
+ AR_PHY_RTT_CTRL_FORCE_RADIO_RESTORE,
+ 0, RTT_RESTORE_TIMEOUT))
+ return false;
+
+ return true;
+}
+
+static void ar9003_hw_rtt_load_hist_entry(struct ath_hw *ah, u8 chain,
+ u32 index, u32 data28)
+{
+ u32 val;
+
+ val = SM(data28, AR_PHY_RTT_SW_RTT_TABLE_DATA);
+ REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_1_B(chain), val);
+
+ val = SM(0, AR_PHY_RTT_SW_RTT_TABLE_ACCESS) |
+ SM(1, AR_PHY_RTT_SW_RTT_TABLE_WRITE) |
+ SM(index, AR_PHY_RTT_SW_RTT_TABLE_ADDR);
+ REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), val);
+ udelay(1);
+
+ val |= SM(1, AR_PHY_RTT_SW_RTT_TABLE_ACCESS);
+ REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), val);
+ udelay(1);
+
+ if (!ath9k_hw_wait(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain),
+ AR_PHY_RTT_SW_RTT_TABLE_ACCESS, 0,
+ RTT_ACCESS_TIMEOUT))
+ return;
+
+ val &= ~SM(1, AR_PHY_RTT_SW_RTT_TABLE_WRITE);
+ REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), val);
+ udelay(1);
+
+ ath9k_hw_wait(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain),
+ AR_PHY_RTT_SW_RTT_TABLE_ACCESS, 0,
+ RTT_ACCESS_TIMEOUT);
+}
+
+void ar9003_hw_rtt_load_hist(struct ath_hw *ah, u8 chain, u32 *table)
+{
+ int i;
+
+ for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++)
+ ar9003_hw_rtt_load_hist_entry(ah, chain, i, table[i]);
+}
+
+static int ar9003_hw_rtt_fill_hist_entry(struct ath_hw *ah, u8 chain, u32 index)
+{
+ u32 val;
+
+ val = SM(0, AR_PHY_RTT_SW_RTT_TABLE_ACCESS) |
+ SM(0, AR_PHY_RTT_SW_RTT_TABLE_WRITE) |
+ SM(index, AR_PHY_RTT_SW_RTT_TABLE_ADDR);
+
+ REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), val);
+ udelay(1);
+
+ val |= SM(1, AR_PHY_RTT_SW_RTT_TABLE_ACCESS);
+ REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), val);
+ udelay(1);
+
+ if (!ath9k_hw_wait(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain),
+ AR_PHY_RTT_SW_RTT_TABLE_ACCESS, 0,
+ RTT_ACCESS_TIMEOUT))
+ return RTT_BAD_VALUE;
+
+ val = REG_READ(ah, AR_PHY_RTT_TABLE_SW_INTF_1_B(chain));
+
+ return val;
+}
+
+void ar9003_hw_rtt_fill_hist(struct ath_hw *ah, u8 chain, u32 *table)
+{
+ int i;
+
+ for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++)
+ table[i] = ar9003_hw_rtt_fill_hist_entry(ah, chain, i);
+}
+
+void ar9003_hw_rtt_clear_hist(struct ath_hw *ah)
+{
+ int i, j;
+
+ for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+ if (!(ah->rxchainmask & (1 << i)))
+ continue;
+ for (j = 0; j < MAX_RTT_TABLE_ENTRY; j++)
+ ar9003_hw_rtt_load_hist_entry(ah, i, j, 0);
+ }
+}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_rtt.h b/drivers/net/wireless/ath/ath9k/ar9003_rtt.h
new file mode 100644
index 000000000000..030758d087d6
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/ar9003_rtt.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef AR9003_RTT_H
+#define AR9003_RTT_H
+
+void ar9003_hw_rtt_enable(struct ath_hw *ah);
+void ar9003_hw_rtt_disable(struct ath_hw *ah);
+void ar9003_hw_rtt_set_mask(struct ath_hw *ah, u32 rtt_mask);
+bool ar9003_hw_rtt_force_restore(struct ath_hw *ah);
+void ar9003_hw_rtt_load_hist(struct ath_hw *ah, u8 chain, u32 *table);
+void ar9003_hw_rtt_fill_hist(struct ath_hw *ah, u8 chain, u32 *table);
+void ar9003_hw_rtt_clear_hist(struct ath_hw *ah);
+
+#endif
diff --git a/drivers/net/wireless/ath/ath9k/ar9462_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_1p0_initvals.h
new file mode 100644
index 000000000000..5c55ae389adb
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/ar9462_1p0_initvals.h
@@ -0,0 +1,1833 @@
+/*
+ * 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 */
diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
new file mode 100644
index 000000000000..9c51b395b4ff
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
@@ -0,0 +1,1928 @@
+/*
+ * 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_2P0_H
+#define INITVALS_9462_2P0_H
+
+/* AR9462 2.0 */
+
+static const u32 ar9462_modes_fast_clock_2p0[][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_pciephy_clkreq_enable_L1_2p0[][2] = {
+ /* Addr allmodes */
+ {0x00018c00, 0x18253ede},
+ {0x00018c04, 0x000801d8},
+ {0x00018c08, 0x0003580c},
+};
+
+static const u32 ar9462_2p0_baseband_postamble[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
+ {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e},
+ {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+ {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
+ {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+ {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
+ {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
+ {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0},
+ {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020},
+ {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
+ {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e},
+ {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3039605e, 0x33795d5e},
+ {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, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27},
+ {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
+ {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
+ {0x0000a204, 0x013187c0, 0x013187c4, 0x013187c4, 0x013187c0},
+ {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, 0x00000110, 0x00000110},
+ {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_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},
+ {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_pciephy_clkreq_disable_L1_2p0[][2] = {
+ /* Addr allmodes */
+ {0x00018c00, 0x18213ede},
+ {0x00018c04, 0x000801d8},
+ {0x00018c08, 0x0003580c},
+};
+
+static const u32 ar9462_pciephy_pll_on_clkreq_disable_L1_2p0[][2] = {
+ /* Addr allmodes */
+ {0x00018c00, 0x18212ede},
+ {0x00018c04, 0x000801d8},
+ {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, 0x90804008, 0x90804008},
+ {0x00016540, 0x10804008, 0x10804008, 0x90804008, 0x90804008},
+};
+
+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},
+ {0x00016140, 0x10804008, 0x10804008, 0x90804008, 0x90804008},
+ {0x00016540, 0x10804008, 0x10804008, 0x90804008, 0x90804008},
+};
+
+static const u32 ar9462_common_wo_xlna_rx_gain_table_2p0[][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_2p0_baseband_core_txfir_coeff_japan_2484[][2] = {
+ /* Addr allmodes */
+ {0x0000a398, 0x00000000},
+ {0x0000a39c, 0x6f7f0301},
+ {0x0000a3a0, 0xca9228ee},
+};
+
+static const u32 ar9462_modes_low_ob_db_tx_gain_table_2p0[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
+ {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},
+ {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {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},
+ {0x00016054, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000},
+ {0x00016444, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4},
+ {0x00016448, 0x64992000, 0x64992000, 0x64992000, 0x64992000},
+ {0x00016454, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000},
+};
+
+static const u32 ar9462_2p0_soc_postamble[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00007010, 0x00002233, 0x00002233, 0x00002233, 0x00002233},
+};
+
+static const u32 ar9462_2p0_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, 0x32440bbe},
+ {0x000098d0, 0x004b6a8e},
+ {0x000098d4, 0x00000820},
+ {0x000098dc, 0x00000000},
+ {0x000098e4, 0x01ffffff},
+ {0x000098e8, 0x01ffffff},
+ {0x000098ec, 0x01ffffff},
+ {0x000098f0, 0x00000000},
+ {0x000098f4, 0x00000000},
+ {0x00009bf0, 0x80000000},
+ {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, 0x990bb515},
+ {0x00009e28, 0x0c6f0000},
+ {0x00009e30, 0x06336f77},
+ {0x00009e34, 0x6af6532f},
+ {0x00009e38, 0x0cc80c00},
+ {0x00009e40, 0x0d261820},
+ {0x00009e4c, 0x00001004},
+ {0x00009e50, 0x00ff03f1},
+ {0x00009e54, 0xe4c355c7},
+ {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},
+ {0x0000a444, 0x00000000},
+ {0x0000a448, 0x05000080},
+ {0x0000a44c, 0x00000001},
+ {0x0000a450, 0x00010000},
+ {0x0000a454, 0x07000000},
+ {0x0000a644, 0xbfad9d74},
+ {0x0000a648, 0x0048060a},
+ {0x0000a64c, 0x00002037},
+ {0x0000a670, 0x03020100},
+ {0x0000a674, 0x09080504},
+ {0x0000a678, 0x0d0c0b0a},
+ {0x0000a67c, 0x13121110},
+ {0x0000a680, 0x31301514},
+ {0x0000a684, 0x35343332},
+ {0x0000a688, 0x00000036},
+ {0x0000a690, 0x00000838},
+ {0x0000a6b0, 0x0000000a},
+ {0x0000a6b4, 0x00512c01},
+ {0x0000a7c0, 0x00000000},
+ {0x0000a7c4, 0xfffffffc},
+ {0x0000a7c8, 0x00000000},
+ {0x0000a7cc, 0x00000000},
+ {0x0000a7d0, 0x00000000},
+ {0x0000a7d4, 0x00000004},
+ {0x0000a7dc, 0x00000001},
+ {0x0000a7f0, 0x80000000},
+ {0x0000a8d0, 0x004b6a8e},
+ {0x0000a8d4, 0x00000820},
+ {0x0000a8dc, 0x00000000},
+ {0x0000a8f0, 0x00000000},
+ {0x0000a8f4, 0x00000000},
+ {0x0000abf0, 0x80000000},
+ {0x0000b2d0, 0x00000080},
+ {0x0000b2d4, 0x00000000},
+ {0x0000b2ec, 0x00000000},
+ {0x0000b2f0, 0x00000000},
+ {0x0000b2f4, 0x00000000},
+ {0x0000b2f8, 0x00000000},
+ {0x0000b408, 0x0e79e5c0},
+ {0x0000b40c, 0x00820820},
+ {0x0000b420, 0x00000000},
+ {0x0000b6b0, 0x0000000a},
+ {0x0000b6b4, 0x00000001},
+};
+
+static const u32 ar9462_2p0_radio_postamble[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0001609c, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524},
+ {0x000160b0, 0x01d67f70, 0x01d67f70, 0x01d67f70, 0x01d67f70},
+ {0x0001610c, 0x48000000, 0x40000000, 0x40000000, 0x40000000},
+ {0x0001650c, 0x48000000, 0x40000000, 0x40000000, 0x40000000},
+};
+
+static const u32 ar9462_modes_high_ob_db_tx_gain_table_2p0[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
+ {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, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {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},
+ {0x00016054, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000},
+ {0x00016444, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4},
+ {0x00016448, 0x8db49000, 0x8db49000, 0x8db49000, 0x8db49000},
+ {0x00016454, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000},
+};
+
+static const u32 ar9462_2p0_radio_core[][2] = {
+ /* Addr allmodes */
+ {0x00016000, 0x36db6db6},
+ {0x00016004, 0x6db6db40},
+ {0x00016008, 0x73f00000},
+ {0x0001600c, 0x00000000},
+ {0x00016010, 0x6d820001},
+ {0x00016040, 0x7f80fff8},
+ {0x0001604c, 0x2699e04f},
+ {0x00016050, 0x6db6db6c},
+ {0x00016058, 0x6c200000},
+ {0x00016080, 0x00040000},
+ {0x00016084, 0x9a68048c},
+ {0x00016088, 0x54214514},
+ {0x0001608c, 0x1203040b},
+ {0x00016090, 0x24926490},
+ {0x00016098, 0xd2888888},
+ {0x000160a0, 0x0a108ffe},
+ {0x000160a4, 0x812fc491},
+ {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, 0x54a82900},
+ {0x00016340, 0x121e4276},
+ {0x00016344, 0x00300000},
+ {0x00016400, 0x36db6db6},
+ {0x00016404, 0x6db6db40},
+ {0x00016408, 0x73f00000},
+ {0x0001640c, 0x00000000},
+ {0x00016410, 0x6c800001},
+ {0x00016440, 0x7f80fff8},
+ {0x0001644c, 0x4699e04f},
+ {0x00016450, 0x6db6db6c},
+ {0x00016500, 0x3fffbe04},
+ {0x00016504, 0xfff80000},
+ {0x00016508, 0x00200400},
+ {0x00016510, 0x00000000},
+ {0x00016544, 0x02084080},
+ {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},
+ {0x00007034, 0x00000002},
+ {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},
+ {0x00000030, 0x000e0085},
+ {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, 0x00b00005},
+ {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_2p0_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_common_mixed_rx_gain_table_2p0[][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_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, 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},
+ {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},
+ {0x000018c4, 0x10101010},
+ {0x000018c8, 0x10101010},
+ {0x000018cc, 0x10101010},
+ {0x000018d0, 0x10101010},
+ {0x000018d4, 0x10101010},
+ {0x000018d8, 0x10101010},
+ {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 */
diff --git a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h
new file mode 100644
index 000000000000..06b3f0df9fad
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h
@@ -0,0 +1,1673 @@
+/*
+ * 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_9580_1P0_H
+#define INITVALS_9580_1P0_H
+
+/* AR9580 1.0 */
+
+static const u32 ar9580_1p0_modes_fast_clock[][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, 0x0000000b, 0x00000016},
+ {0x0000a254, 0x00000898, 0x00001130},
+};
+
+static const u32 ar9580_1p0_radio_postamble[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0001609c, 0x0dd08f29, 0x0dd08f29, 0x0b283f31, 0x0b283f31},
+ {0x000160ac, 0xa4653c00, 0xa4653c00, 0x24652800, 0x24652800},
+ {0x000160b0, 0x03284f3e, 0x03284f3e, 0x05d08f20, 0x05d08f20},
+ {0x0001610c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+ {0x0001650c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+ {0x0001690c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00016940, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+};
+
+static const u32 ar9580_1p0_baseband_core[][2] = {
+ /* Addr allmodes */
+ {0x00009800, 0xafe68e30},
+ {0x00009804, 0xfd14e000},
+ {0x00009808, 0x9c0a9f6b},
+ {0x0000980c, 0x04900000},
+ {0x00009814, 0x3280c00a},
+ {0x00009818, 0x00000000},
+ {0x0000981c, 0x00020028},
+ {0x00009834, 0x6400a290},
+ {0x00009838, 0x0108ecff},
+ {0x0000983c, 0x0d000600},
+ {0x00009880, 0x201fff00},
+ {0x00009884, 0x00001042},
+ {0x000098a4, 0x00200400},
+ {0x000098b0, 0x32840bbe},
+ {0x000098d0, 0x004b6a8e},
+ {0x000098d4, 0x00000820},
+ {0x000098dc, 0x00000000},
+ {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, 0x990bb515},
+ {0x00009e28, 0x0c6f0000},
+ {0x00009e30, 0x06336f77},
+ {0x00009e34, 0x6af6532f},
+ {0x00009e38, 0x0cc80c00},
+ {0x00009e40, 0x0d261820},
+ {0x00009e4c, 0x00001004},
+ {0x00009e50, 0x00ff03f1},
+ {0x00009e54, 0x00000000},
+ {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, 0x00000000},
+ {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},
+ {0x0000a640, 0x00000000},
+ {0x0000a644, 0x3fad9d74},
+ {0x0000a648, 0x0048060a},
+ {0x0000a64c, 0x00003c37},
+ {0x0000a670, 0x03020100},
+ {0x0000a674, 0x09080504},
+ {0x0000a678, 0x0d0c0b0a},
+ {0x0000a67c, 0x13121110},
+ {0x0000a680, 0x31301514},
+ {0x0000a684, 0x35343332},
+ {0x0000a688, 0x00000036},
+ {0x0000a690, 0x00000838},
+ {0x0000a7c0, 0x00000000},
+ {0x0000a7c4, 0xfffffffc},
+ {0x0000a7c8, 0x00000000},
+ {0x0000a7cc, 0x00000000},
+ {0x0000a7d0, 0x00000000},
+ {0x0000a7d4, 0x00000004},
+ {0x0000a7dc, 0x00000000},
+ {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},
+ {0x0000b8d0, 0x004b6a8e},
+ {0x0000b8d4, 0x00000820},
+ {0x0000b8dc, 0x00000000},
+ {0x0000b8f0, 0x00000000},
+ {0x0000b8f4, 0x00000000},
+ {0x0000c2d0, 0x00000080},
+ {0x0000c2d4, 0x00000000},
+ {0x0000c2ec, 0x00000000},
+ {0x0000c2f0, 0x00000000},
+ {0x0000c2f4, 0x00000000},
+ {0x0000c2f8, 0x00000000},
+ {0x0000c408, 0x0e79e5c0},
+ {0x0000c40c, 0x00820820},
+ {0x0000c420, 0x00000000},
+};
+
+static const u32 ar9580_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 ar9580_1p0_low_ob_db_tx_gain_table[][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, 0x21002220, 0x21002220, 0x16000402, 0x16000402},
+ {0x0000a51c, 0x27002223, 0x27002223, 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, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83},
+ {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84},
+ {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3},
+ {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5},
+ {0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9},
+ {0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb},
+ {0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+ {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+ {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+ {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+ {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+ {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400},
+ {0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402},
+ {0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
+ {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
+ {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
+ {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
+ {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20},
+ {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20},
+ {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22},
+ {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
+ {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
+ {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
+ {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861},
+ {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81},
+ {0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83},
+ {0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84},
+ {0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3},
+ {0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5},
+ {0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9},
+ {0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb},
+ {0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {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},
+ {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+ {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+ {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+ {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+ {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+ {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+ {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9580_1p0_high_power_tx_gain_table[][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, 0x21002220, 0x21002220, 0x16000402, 0x16000402},
+ {0x0000a51c, 0x27002223, 0x27002223, 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, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83},
+ {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84},
+ {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3},
+ {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5},
+ {0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9},
+ {0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb},
+ {0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+ {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+ {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+ {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+ {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+ {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400},
+ {0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402},
+ {0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
+ {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
+ {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
+ {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
+ {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20},
+ {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20},
+ {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22},
+ {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
+ {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
+ {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
+ {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861},
+ {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81},
+ {0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83},
+ {0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84},
+ {0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3},
+ {0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5},
+ {0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9},
+ {0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb},
+ {0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {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},
+ {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+ {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+ {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+ {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+ {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+ {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+ {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9580_1p0_lowest_ob_db_tx_gain_table[][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, 0x21002220, 0x21002220, 0x16000402, 0x16000402},
+ {0x0000a51c, 0x27002223, 0x27002223, 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, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83},
+ {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84},
+ {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3},
+ {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5},
+ {0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9},
+ {0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb},
+ {0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+ {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+ {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+ {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+ {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+ {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400},
+ {0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402},
+ {0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
+ {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
+ {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
+ {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
+ {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20},
+ {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20},
+ {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22},
+ {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
+ {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
+ {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
+ {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861},
+ {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81},
+ {0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83},
+ {0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84},
+ {0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3},
+ {0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5},
+ {0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9},
+ {0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb},
+ {0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {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},
+ {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+ {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+ {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+ {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016048, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
+ {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016448, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
+ {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016848, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
+ {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9580_1p0_baseband_core_txfir_coeff_japan_2484[][2] = {
+ /* Addr allmodes */
+ {0x0000a398, 0x00000000},
+ {0x0000a39c, 0x6f7f0301},
+ {0x0000a3a0, 0xca9228ee},
+};
+
+static const u32 ar9580_1p0_mac_core[][2] = {
+ /* Addr allmodes */
+ {0x00000008, 0x00000000},
+ {0x00000030, 0x00020085},
+ {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},
+ {0x00008000, 0x00000000},
+ {0x00008004, 0x00000000},
+ {0x00008008, 0x00000000},
+ {0x0000800c, 0x00000000},
+ {0x00008018, 0x00000000},
+ {0x00008020, 0x00000000},
+ {0x00008038, 0x00000000},
+ {0x0000803c, 0x00000000},
+ {0x00008040, 0x00000000},
+ {0x00008044, 0x00000000},
+ {0x00008048, 0x00000000},
+ {0x0000804c, 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, 0x13881c22},
+ {0x000080cc, 0x01f40000},
+ {0x000080d0, 0x00252500},
+ {0x000080d4, 0x00a00000},
+ {0x000080d8, 0x00400000},
+ {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},
+ {0x000081c0, 0x00000000},
+ {0x000081c4, 0x33332210},
+ {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, 0x9bc00010},
+ {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, 0x00000007},
+ {0x00008330, 0x00000302},
+ {0x00008334, 0x00000700},
+ {0x00008338, 0x00ff0000},
+ {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},
+ {0x000083a0, 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 ar9580_1p0_mixed_ob_db_tx_gain_table[][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, 0x11000400, 0x11000400},
+ {0x0000a518, 0x21002220, 0x21002220, 0x15000402, 0x15000402},
+ {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
+ {0x0000a520, 0x2b022220, 0x2b022220, 0x1b000603, 0x1b000603},
+ {0x0000a524, 0x2f022222, 0x2f022222, 0x1f000a02, 0x1f000a02},
+ {0x0000a528, 0x34022225, 0x34022225, 0x23000a04, 0x23000a04},
+ {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x26000a20, 0x26000a20},
+ {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2a000e20, 0x2a000e20},
+ {0x0000a534, 0x4202242a, 0x4202242a, 0x2e000e22, 0x2e000e22},
+ {0x0000a538, 0x4702244a, 0x4702244a, 0x31000e24, 0x31000e24},
+ {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x34001640, 0x34001640},
+ {0x0000a540, 0x4e02246c, 0x4e02246c, 0x38001660, 0x38001660},
+ {0x0000a544, 0x5302266c, 0x5302266c, 0x3b001861, 0x3b001861},
+ {0x0000a548, 0x5702286c, 0x5702286c, 0x3e001a81, 0x3e001a81},
+ {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x42001a83, 0x42001a83},
+ {0x0000a550, 0x61024a6c, 0x61024a6c, 0x44001c84, 0x44001c84},
+ {0x0000a554, 0x66026a6c, 0x66026a6c, 0x48001ce3, 0x48001ce3},
+ {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x4c001ce5, 0x4c001ce5},
+ {0x0000a55c, 0x7002708c, 0x7002708c, 0x50001ce9, 0x50001ce9},
+ {0x0000a560, 0x7302b08a, 0x7302b08a, 0x54001ceb, 0x54001ceb},
+ {0x0000a564, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+ {0x0000a568, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+ {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+ {0x0000a570, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+ {0x0000a574, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+ {0x0000a578, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+ {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+ {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+ {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+ {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+ {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+ {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+ {0x0000a594, 0x1c800223, 0x1c800223, 0x11800400, 0x11800400},
+ {0x0000a598, 0x21802220, 0x21802220, 0x15800402, 0x15800402},
+ {0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
+ {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800603, 0x1b800603},
+ {0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800a02, 0x1f800a02},
+ {0x0000a5a8, 0x34822225, 0x34822225, 0x23800a04, 0x23800a04},
+ {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x26800a20, 0x26800a20},
+ {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2a800e20, 0x2a800e20},
+ {0x0000a5b4, 0x4282242a, 0x4282242a, 0x2e800e22, 0x2e800e22},
+ {0x0000a5b8, 0x4782244a, 0x4782244a, 0x31800e24, 0x31800e24},
+ {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x34801640, 0x34801640},
+ {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38801660, 0x38801660},
+ {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3b801861, 0x3b801861},
+ {0x0000a5c8, 0x5782286c, 0x5782286c, 0x3e801a81, 0x3e801a81},
+ {0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x42801a83, 0x42801a83},
+ {0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x44801c84, 0x44801c84},
+ {0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x48801ce3, 0x48801ce3},
+ {0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x4c801ce5, 0x4c801ce5},
+ {0x0000a5dc, 0x7082708c, 0x7082708c, 0x50801ce9, 0x50801ce9},
+ {0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x54801ceb, 0x54801ceb},
+ {0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x56801eec, 0x56801eec},
+ {0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x56801eec, 0x56801eec},
+ {0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x56801eec, 0x56801eec},
+ {0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x56801eec, 0x56801eec},
+ {0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x56801eec, 0x56801eec},
+ {0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x56801eec, 0x56801eec},
+ {0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x56801eec, 0x56801eec},
+ {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},
+ {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+ {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+ {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+ {0x00016044, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4},
+ {0x00016048, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001},
+ {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016444, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4},
+ {0x00016448, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001},
+ {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016844, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4},
+ {0x00016848, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001},
+ {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9580_1p0_wo_xlna_rx_gain_table[][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 ar9580_1p0_soc_postamble[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023},
+};
+
+static const u32 ar9580_1p0_high_ob_db_tx_gain_table[][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, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
+ {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
+ {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
+ {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
+ {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
+ {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
+ {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
+ {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
+ {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
+ {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
+ {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
+ {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
+ {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
+ {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
+ {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
+ {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
+ {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
+ {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
+ {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
+ {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
+ {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83},
+ {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
+ {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
+ {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
+ {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
+ {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
+ {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
+ {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
+ {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
+ {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
+ {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
+ {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
+ {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
+ {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
+ {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
+ {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
+ {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
+ {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
+ {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
+ {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
+ {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
+ {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
+ {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
+ {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
+ {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
+ {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
+ {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
+ {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
+ {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
+ {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
+ {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
+ {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {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},
+ {0x0000c2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
+ {0x0000c2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
+ {0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+ {0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
+ {0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
+ {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016444, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
+ {0x00016448, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
+ {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016844, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
+ {0x00016848, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
+ {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9580_1p0_soc_preamble[][2] = {
+ /* Addr allmodes */
+ {0x000040a4, 0x00a0c1c9},
+ {0x00007008, 0x00000000},
+ {0x00007020, 0x00000000},
+ {0x00007034, 0x00000002},
+ {0x00007038, 0x000004c2},
+ {0x00007048, 0x00000008},
+};
+
+static const u32 ar9580_1p0_rx_gain_table[][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 ar9580_1p0_radio_core[][2] = {
+ /* Addr allmodes */
+ {0x00016000, 0x36db6db6},
+ {0x00016004, 0x6db6db40},
+ {0x00016008, 0x73f00000},
+ {0x0001600c, 0x00000000},
+ {0x00016040, 0x7f80fff8},
+ {0x0001604c, 0x76d005b5},
+ {0x00016050, 0x556cf031},
+ {0x00016054, 0x13449440},
+ {0x00016058, 0x0c51c92c},
+ {0x0001605c, 0x3db7fffc},
+ {0x00016060, 0xfffffffc},
+ {0x00016064, 0x000f0278},
+ {0x0001606c, 0x6db60000},
+ {0x00016080, 0x00000000},
+ {0x00016084, 0x0e48048c},
+ {0x00016088, 0x54214514},
+ {0x0001608c, 0x119f481e},
+ {0x00016090, 0x24926490},
+ {0x00016098, 0xd2888888},
+ {0x000160a0, 0x0a108ffe},
+ {0x000160a4, 0x812fc370},
+ {0x000160a8, 0x423c8000},
+ {0x000160b4, 0x92480080},
+ {0x000160c0, 0x00adb6d0},
+ {0x000160c4, 0x6db6db60},
+ {0x000160c8, 0x6db6db6c},
+ {0x000160cc, 0x01e6c000},
+ {0x00016100, 0x3fffbe01},
+ {0x00016104, 0xfff80000},
+ {0x00016108, 0x00080010},
+ {0x00016144, 0x02084080},
+ {0x00016148, 0x00000000},
+ {0x00016280, 0x058a0001},
+ {0x00016284, 0x3d840208},
+ {0x00016288, 0x05a20408},
+ {0x0001628c, 0x00038c07},
+ {0x00016290, 0x00000004},
+ {0x00016294, 0x458aa14f},
+ {0x00016380, 0x00000000},
+ {0x00016384, 0x00000000},
+ {0x00016388, 0x00800700},
+ {0x0001638c, 0x00800700},
+ {0x00016390, 0x00800700},
+ {0x00016394, 0x00000000},
+ {0x00016398, 0x00000000},
+ {0x0001639c, 0x00000000},
+ {0x000163a0, 0x00000001},
+ {0x000163a4, 0x00000001},
+ {0x000163a8, 0x00000000},
+ {0x000163ac, 0x00000000},
+ {0x000163b0, 0x00000000},
+ {0x000163b4, 0x00000000},
+ {0x000163b8, 0x00000000},
+ {0x000163bc, 0x00000000},
+ {0x000163c0, 0x000000a0},
+ {0x000163c4, 0x000c0000},
+ {0x000163c8, 0x14021402},
+ {0x000163cc, 0x00001402},
+ {0x000163d0, 0x00000000},
+ {0x000163d4, 0x00000000},
+ {0x00016400, 0x36db6db6},
+ {0x00016404, 0x6db6db40},
+ {0x00016408, 0x73f00000},
+ {0x0001640c, 0x00000000},
+ {0x00016440, 0x7f80fff8},
+ {0x0001644c, 0x76d005b5},
+ {0x00016450, 0x556cf031},
+ {0x00016454, 0x13449440},
+ {0x00016458, 0x0c51c92c},
+ {0x0001645c, 0x3db7fffc},
+ {0x00016460, 0xfffffffc},
+ {0x00016464, 0x000f0278},
+ {0x0001646c, 0x6db60000},
+ {0x00016500, 0x3fffbe01},
+ {0x00016504, 0xfff80000},
+ {0x00016508, 0x00080010},
+ {0x00016544, 0x02084080},
+ {0x00016548, 0x00000000},
+ {0x00016780, 0x00000000},
+ {0x00016784, 0x00000000},
+ {0x00016788, 0x00800700},
+ {0x0001678c, 0x00800700},
+ {0x00016790, 0x00800700},
+ {0x00016794, 0x00000000},
+ {0x00016798, 0x00000000},
+ {0x0001679c, 0x00000000},
+ {0x000167a0, 0x00000001},
+ {0x000167a4, 0x00000001},
+ {0x000167a8, 0x00000000},
+ {0x000167ac, 0x00000000},
+ {0x000167b0, 0x00000000},
+ {0x000167b4, 0x00000000},
+ {0x000167b8, 0x00000000},
+ {0x000167bc, 0x00000000},
+ {0x000167c0, 0x000000a0},
+ {0x000167c4, 0x000c0000},
+ {0x000167c8, 0x14021402},
+ {0x000167cc, 0x00001402},
+ {0x000167d0, 0x00000000},
+ {0x000167d4, 0x00000000},
+ {0x00016800, 0x36db6db6},
+ {0x00016804, 0x6db6db40},
+ {0x00016808, 0x73f00000},
+ {0x0001680c, 0x00000000},
+ {0x00016840, 0x7f80fff8},
+ {0x0001684c, 0x76d005b5},
+ {0x00016850, 0x556cf031},
+ {0x00016854, 0x13449440},
+ {0x00016858, 0x0c51c92c},
+ {0x0001685c, 0x3db7fffc},
+ {0x00016860, 0xfffffffc},
+ {0x00016864, 0x000f0278},
+ {0x0001686c, 0x6db60000},
+ {0x00016900, 0x3fffbe01},
+ {0x00016904, 0xfff80000},
+ {0x00016908, 0x00080010},
+ {0x00016944, 0x02084080},
+ {0x00016948, 0x00000000},
+ {0x00016b80, 0x00000000},
+ {0x00016b84, 0x00000000},
+ {0x00016b88, 0x00800700},
+ {0x00016b8c, 0x00800700},
+ {0x00016b90, 0x00800700},
+ {0x00016b94, 0x00000000},
+ {0x00016b98, 0x00000000},
+ {0x00016b9c, 0x00000000},
+ {0x00016ba0, 0x00000001},
+ {0x00016ba4, 0x00000001},
+ {0x00016ba8, 0x00000000},
+ {0x00016bac, 0x00000000},
+ {0x00016bb0, 0x00000000},
+ {0x00016bb4, 0x00000000},
+ {0x00016bb8, 0x00000000},
+ {0x00016bbc, 0x00000000},
+ {0x00016bc0, 0x000000a0},
+ {0x00016bc4, 0x000c0000},
+ {0x00016bc8, 0x14021402},
+ {0x00016bcc, 0x00001402},
+ {0x00016bd0, 0x00000000},
+ {0x00016bd4, 0x00000000},
+};
+
+static const u32 ar9580_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, 0xcf946222, 0xcf946222},
+ {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27},
+ {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
+ {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
+ {0x0000a204, 0x000036c0, 0x000036c4, 0x000036c4, 0x000036c0},
+ {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
+ {0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f},
+ {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
+ {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff},
+ {0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018},
+ {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, 0x00000110, 0x00000110},
+ {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, 0x001c0000},
+ {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+ {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
+ {0x0000b284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
+ {0x0000b830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+ {0x0000be04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000},
+ {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000be1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+ {0x0000be20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
+ {0x0000c284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
+};
+
+static const u32 ar9580_1p0_pcie_phy_clkreq_enable_L1[][2] = {
+ /* Addr allmodes */
+ {0x00004040, 0x0835365e},
+ {0x00004040, 0x0008003b},
+ {0x00004044, 0x00000000},
+};
+
+static const u32 ar9580_1p0_pcie_phy_clkreq_disable_L1[][2] = {
+ /* Addr allmodes */
+ {0x00004040, 0x0831365e},
+ {0x00004040, 0x0008003b},
+ {0x00004044, 0x00000000},
+};
+
+static const u32 ar9580_1p0_pcie_phy_pll_on_clkreq[][2] = {
+ /* Addr allmodes */
+ {0x00004040, 0x0831265e},
+ {0x00004040, 0x0008003b},
+ {0x00004044, 0x00000000},
+};
+
+#endif /* INITVALS_9580_1P0_H */
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 46393f90f16c..1c269f50822b 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -87,17 +87,14 @@ struct ath_config {
* @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX)
* @BUF_AGGR: Indicates whether the buffer can be aggregated
* (used in aggregation scheduling)
- * @BUF_XRETRY: To denote excessive retries of the buffer
*/
enum buffer_type {
BUF_AMPDU = BIT(0),
BUF_AGGR = BIT(1),
- BUF_XRETRY = BIT(2),
};
#define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU)
#define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR)
-#define bf_isxretried(bf) (bf->bf_state.bf_type & BUF_XRETRY)
#define ATH_TXSTATUS_RING_SIZE 64
@@ -206,18 +203,19 @@ struct ath_atx_ac {
};
struct ath_frame_info {
+ struct ath_buf *bf;
int framelen;
- u32 keyix;
enum ath9k_key_type keytype;
+ u8 keyix;
u8 retries;
- u16 seqno;
};
struct ath_buf_state {
u8 bf_type;
u8 bfs_paprd;
+ u8 ndelim;
+ u16 seqno;
unsigned long bfs_paprd_timestamp;
- enum ath9k_internal_frame_type bfs_ftype;
};
struct ath_buf {
@@ -230,13 +228,12 @@ struct ath_buf {
dma_addr_t bf_daddr; /* physical addr of desc */
dma_addr_t bf_buf_addr; /* physical addr of data buffer, for DMA */
bool bf_stale;
- u16 bf_flags;
struct ath_buf_state bf_state;
};
struct ath_atx_tid {
struct list_head list;
- struct list_head buf_q;
+ struct sk_buff_head buf_q;
struct ath_node *an;
struct ath_atx_ac *ac;
unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)];
@@ -273,14 +270,11 @@ struct ath_node {
struct ath_tx_control {
struct ath_txq *txq;
struct ath_node *an;
- int if_id;
- enum ath9k_internal_frame_type frame_type;
u8 paprd;
};
#define ATH_TX_ERROR 0x01
-#define ATH_TX_XRETRY 0x02
-#define ATH_TX_BAR 0x04
+#define ATH_TX_BAR 0x02
/**
* @txq_map: Index is mac80211 queue number. This is
@@ -346,7 +340,8 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
-bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an);
+void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
+ struct ath_node *an);
/********/
/* VIFs */
@@ -427,6 +422,7 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
#define ATH_PAPRD_TIMEOUT 100 /* msecs */
+void ath_reset_work(struct work_struct *work);
void ath_hw_check(struct work_struct *work);
void ath_hw_pll_work(struct work_struct *work);
void ath_paprd_calibrate(struct work_struct *work);
@@ -462,6 +458,7 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc);
#define ATH_LED_PIN_9287 8
#define ATH_LED_PIN_9300 10
#define ATH_LED_PIN_9485 6
+#define ATH_LED_PIN_9462 0
#ifdef CONFIG_MAC80211_LEDS
void ath_init_leds(struct ath_softc *sc);
@@ -561,8 +558,7 @@ struct ath_ant_comb {
#define SC_OP_BT_PRIORITY_DETECTED BIT(12)
#define SC_OP_BT_SCAN BIT(13)
#define SC_OP_ANI_RUN BIT(14)
-#define SC_OP_ENABLE_APM BIT(15)
-#define SC_OP_PRIM_STA_VIF BIT(16)
+#define SC_OP_PRIM_STA_VIF BIT(15)
/* Powersave flags */
#define PS_WAIT_FOR_BEACON BIT(0)
@@ -570,7 +566,6 @@ struct ath_ant_comb {
#define PS_WAIT_FOR_PSPOLL_DATA BIT(2)
#define PS_WAIT_FOR_TX_ACK BIT(3)
#define PS_BEACON_SYNC BIT(4)
-#define PS_TSFOOR_SYNC BIT(5)
struct ath_rate_table;
@@ -608,6 +603,7 @@ struct ath_softc {
struct mutex mutex;
struct work_struct paprd_work;
struct work_struct hw_check_work;
+ struct work_struct hw_reset_work;
struct completion paprd_complete;
unsigned int hw_busy_count;
@@ -651,10 +647,10 @@ struct ath_softc {
struct ath_descdma txsdma;
struct ath_ant_comb ant_comb;
+ u8 ant_tx, ant_rx;
};
void ath9k_tasklet(unsigned long data);
-int ath_reset(struct ath_softc *sc, bool retry_tx);
int ath_cabq_update(struct ath_softc *);
static inline void ath_read_cachesize(struct ath_common *common, int *csz)
@@ -668,11 +664,11 @@ extern int led_blink;
extern bool is_ath9k_unloaded;
irqreturn_t ath_isr(int irq, void *dev);
-void ath9k_init_crypto(struct ath_softc *sc);
-int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
+int ath9k_init_device(u16 devid, struct ath_softc *sc,
const struct ath_bus_ops *bus_ops);
void ath9k_deinit_device(struct ath_softc *sc);
void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
+void ath9k_reload_chainmask_settings(struct ath_softc *sc);
void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw);
bool ath9k_uses_beacons(int type);
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 0d13ff74a68b..a13cabb95435 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -73,44 +73,39 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
struct sk_buff *skb = bf->bf_mpdu;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
- struct ath_desc *ds;
- struct ath9k_11n_rate_series series[4];
- int flags, ctsrate = 0, ctsduration = 0;
+ struct ath_tx_info info;
struct ieee80211_supported_band *sband;
+ u8 chainmask = ah->txchainmask;
u8 rate = 0;
ath9k_reset_beacon_status(sc);
- ds = bf->bf_desc;
- flags = ATH9K_TXDESC_NOACK;
-
- ds->ds_link = 0;
-
sband = &sc->sbands[common->hw->conf.channel->band];
rate = sband->bitrates[rateidx].hw_value;
if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
rate |= sband->bitrates[rateidx].hw_value_short;
- ath9k_hw_set11n_txdesc(ah, ds, skb->len + FCS_LEN,
- ATH9K_PKT_TYPE_BEACON,
- MAX_RATE_POWER,
- ATH9K_TXKEYIX_INVALID,
- ATH9K_KEY_TYPE_CLEAR,
- flags);
-
- /* NB: beacon's BufLen must be a multiple of 4 bytes */
- ath9k_hw_filltxdesc(ah, ds, roundup(skb->len, 4),
- true, true, ds, bf->bf_buf_addr,
- sc->beacon.beaconq);
-
- memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
- series[0].Tries = 1;
- series[0].Rate = rate;
- series[0].ChSel = ath_txchainmask_reduction(sc,
- common->tx_chainmask, series[0].Rate);
- series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0;
- ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, ctsrate, ctsduration,
- series, 4, 0);
+ memset(&info, 0, sizeof(info));
+ info.pkt_len = skb->len + FCS_LEN;
+ info.type = ATH9K_PKT_TYPE_BEACON;
+ info.txpower = MAX_RATE_POWER;
+ info.keyix = ATH9K_TXKEYIX_INVALID;
+ info.keytype = ATH9K_KEY_TYPE_CLEAR;
+ info.flags = ATH9K_TXDESC_NOACK;
+
+ info.buf_addr[0] = bf->bf_buf_addr;
+ info.buf_len[0] = roundup(skb->len, 4);
+
+ info.is_first = true;
+ info.is_last = true;
+
+ info.qcu = sc->beacon.beaconq;
+
+ info.rates[0].Tries = 1;
+ info.rates[0].Rate = rate;
+ info.rates[0].ChSel = ath_txchainmask_reduction(sc, chainmask, rate);
+
+ ath9k_hw_set_txdesc(ah, bf->bf_desc, &info);
}
static void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
@@ -386,9 +381,7 @@ void ath_beacon_tasklet(unsigned long data)
ath_dbg(common, ATH_DBG_BSTUCK,
"beacon is officially stuck\n");
sc->sc_flags |= SC_OP_TSF_RESET;
- spin_lock(&sc->sc_pcu_lock);
- ath_reset(sc, true);
- spin_unlock(&sc->sc_pcu_lock);
+ ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
}
return;
@@ -519,9 +512,11 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
/* Set the computed AP beacon timers */
ath9k_hw_disable_interrupts(ah);
+ sc->sc_flags |= SC_OP_TSF_RESET;
ath9k_beacon_init(sc, nexttbtt, intval);
sc->beacon.bmisscnt = 0;
- ath9k_hw_set_interrupts(ah, ah->imask);
+ ath9k_hw_set_interrupts(ah);
+ ath9k_hw_enable_interrupts(ah);
}
/*
@@ -648,12 +643,8 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
ath9k_hw_set_sta_beacon_timers(ah, &bs);
ah->imask |= ATH9K_INT_BMISS;
- /*
- * If the beacon config is called beacause of TSFOOR,
- * Interrupts will be enabled back at the end of ath9k_tasklet
- */
- if (!(sc->ps_flags & PS_TSFOOR_SYNC))
- ath9k_hw_set_interrupts(ah, ah->imask);
+ ath9k_hw_set_interrupts(ah);
+ ath9k_hw_enable_interrupts(ah);
}
static void ath_beacon_config_adhoc(struct ath_softc *sc,
@@ -687,12 +678,9 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
ath9k_hw_disable_interrupts(ah);
ath9k_beacon_init(sc, nexttbtt, intval);
sc->beacon.bmisscnt = 0;
- /*
- * If the beacon config is called beacause of TSFOOR,
- * Interrupts will be enabled back at the end of ath9k_tasklet
- */
- if (!(sc->ps_flags & PS_TSFOOR_SYNC))
- ath9k_hw_set_interrupts(ah, ah->imask);
+
+ ath9k_hw_set_interrupts(ah);
+ ath9k_hw_enable_interrupts(ah);
}
static bool ath9k_allow_beacon_config(struct ath_softc *sc,
@@ -833,11 +821,11 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
if (status) {
/* Re-enable beaconing */
ah->imask |= ATH9K_INT_SWBA;
- ath9k_hw_set_interrupts(ah, ah->imask);
+ ath9k_hw_set_interrupts(ah);
} else {
/* Disable SWBA interrupt */
ah->imask &= ~ATH9K_INT_SWBA;
- ath9k_hw_set_interrupts(ah, ah->imask);
+ ath9k_hw_set_interrupts(ah);
tasklet_kill(&sc->bcon_tasklet);
ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
}
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index a1250c586e40..ebaf304f464b 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -63,13 +63,25 @@ static s16 ath9k_hw_get_default_nf(struct ath_hw *ah,
return ath9k_hw_get_nf_limits(ah, chan)->nominal;
}
+s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+ s8 noise = ATH_DEFAULT_NOISE_FLOOR;
+
+ if (chan && chan->noisefloor) {
+ s8 delta = chan->noisefloor -
+ ath9k_hw_get_default_nf(ah, chan);
+ if (delta > 0)
+ noise += delta;
+ }
+ return noise;
+}
+EXPORT_SYMBOL(ath9k_hw_getchan_noise);
static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah,
struct ath9k_hw_cal_data *cal,
int16_t *nfarray)
{
struct ath_common *common = ath9k_hw_common(ah);
- struct ieee80211_conf *conf = &common->hw->conf;
struct ath_nf_limits *limit;
struct ath9k_nfcal_hist *h;
bool high_nf_mid = false;
@@ -81,7 +93,7 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah,
for (i = 0; i < NUM_NF_READINGS; i++) {
if (!(chainmask & (1 << i)) ||
- ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf)))
+ ((i >= AR5416_MAX_CHAINS) && !IS_CHAN_HT40(ah->curchan)))
continue;
h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
@@ -378,6 +390,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
if (!caldata) {
chan->noisefloor = nf;
+ ah->noise = ath9k_hw_getchan_noise(ah, chan);
return false;
}
@@ -385,6 +398,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
caldata->nfcal_pending = false;
ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray);
chan->noisefloor = h[0].privNF;
+ ah->noise = ath9k_hw_getchan_noise(ah, chan);
return true;
}
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index 1bef41d1b1ff..05b9dbf81850 100644
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -108,6 +108,7 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
void ath9k_hw_bstuck_nfcal(struct ath_hw *ah);
void ath9k_hw_reset_calibration(struct ath_hw *ah,
struct ath9k_cal_list *currCal);
+s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan);
#endif /* CALIB_H */
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c
index fa6bd2d189e5..905f1b313961 100644
--- a/drivers/net/wireless/ath/ath9k/common.c
+++ b/drivers/net/wireless/ath/ath9k/common.c
@@ -161,14 +161,42 @@ EXPORT_SYMBOL(ath9k_cmn_count_streams);
void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow,
u16 new_txpow, u16 *txpower)
{
- if (cur_txpow != new_txpow) {
+ struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
+
+ if (reg->power_limit != new_txpow) {
ath9k_hw_set_txpowerlimit(ah, new_txpow, false);
/* read back in case value is clamped */
- *txpower = ath9k_hw_regulatory(ah)->power_limit;
+ *txpower = reg->max_power_level;
}
}
EXPORT_SYMBOL(ath9k_cmn_update_txpow);
+void ath9k_cmn_init_crypto(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ int i = 0;
+
+ /* Get the hardware key cache size. */
+ common->keymax = AR_KEYTABLE_SIZE;
+
+ /*
+ * Check whether the separate key cache entries
+ * are required to handle both tx+rx MIC keys.
+ * With split mic keys the number of stations is limited
+ * to 27 otherwise 59.
+ */
+ if (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA)
+ common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED;
+
+ /*
+ * Reset the key cache since some parts do not
+ * reset the contents on initial power up.
+ */
+ for (i = 0; i < common->keymax; i++)
+ ath_hw_keyreset(common, (u16) i);
+}
+EXPORT_SYMBOL(ath9k_cmn_init_crypto);
+
static int __init ath9k_cmn_init(void)
{
return 0;
diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h
index 77ec288b5a70..ad14fecc76c6 100644
--- a/drivers/net/wireless/ath/ath9k/common.h
+++ b/drivers/net/wireless/ath/ath9k/common.h
@@ -62,3 +62,4 @@ void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common,
enum ath_stomp_type stomp_type);
void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow,
u16 new_txpow, u16 *txpower);
+void ath9k_cmn_init_crypto(struct ath_hw *ah);
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index d1eb89611ff7..327aa28f6030 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -95,11 +95,11 @@ static ssize_t read_file_tx_chainmask(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_hw *ah = sc->sc_ah;
char buf[32];
unsigned int len;
- len = sprintf(buf, "0x%08x\n", common->tx_chainmask);
+ len = sprintf(buf, "0x%08x\n", ah->txchainmask);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -107,7 +107,7 @@ static ssize_t write_file_tx_chainmask(struct file *file, const char __user *use
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_hw *ah = sc->sc_ah;
unsigned long mask;
char buf[32];
ssize_t len;
@@ -120,8 +120,8 @@ static ssize_t write_file_tx_chainmask(struct file *file, const char __user *use
if (strict_strtoul(buf, 0, &mask))
return -EINVAL;
- common->tx_chainmask = mask;
- sc->sc_ah->caps.tx_chainmask = mask;
+ ah->txchainmask = mask;
+ ah->caps.tx_chainmask = mask;
return count;
}
@@ -138,11 +138,11 @@ static ssize_t read_file_rx_chainmask(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_hw *ah = sc->sc_ah;
char buf[32];
unsigned int len;
- len = sprintf(buf, "0x%08x\n", common->rx_chainmask);
+ len = sprintf(buf, "0x%08x\n", ah->rxchainmask);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -150,7 +150,7 @@ static ssize_t write_file_rx_chainmask(struct file *file, const char __user *use
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_hw *ah = sc->sc_ah;
unsigned long mask;
char buf[32];
ssize_t len;
@@ -163,8 +163,8 @@ static ssize_t write_file_rx_chainmask(struct file *file, const char __user *use
if (strict_strtoul(buf, 0, &mask))
return -EINVAL;
- common->rx_chainmask = mask;
- sc->sc_ah->caps.rx_chainmask = mask;
+ ah->rxchainmask = mask;
+ ah->caps.rx_chainmask = mask;
return count;
}
@@ -523,9 +523,22 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
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\n");
- else
- len += snprintf(buf + len, sizeof(buf) - len, "\n");
+ 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);
@@ -711,7 +724,7 @@ static ssize_t read_file_stations(struct file *file, char __user *user_buf,
" tid: %p %s %s %i %p %p\n",
tid, tid->sched ? "sched" : "idle",
tid->paused ? "paused" : "running",
- list_empty(&tid->buf_q),
+ skb_queue_empty(&tid->buf_q),
tid->an, tid->ac);
if (len >= size)
goto done;
@@ -826,20 +839,23 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf,
}
void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
- struct ath_tx_status *ts, struct ath_txq *txq)
+ struct ath_tx_status *ts, struct ath_txq *txq,
+ unsigned int flags)
{
+#define TX_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].ts\
+ [sc->debug.tsidx].c)
int qnum = txq->axq_qnum;
TX_STAT_INC(qnum, tx_pkts_all);
sc->debug.stats.txstats[qnum].tx_bytes_all += bf->bf_mpdu->len;
if (bf_isampdu(bf)) {
- if (bf_isxretried(bf))
+ if (flags & ATH_TX_BAR)
TX_STAT_INC(qnum, a_xretries);
else
TX_STAT_INC(qnum, a_completed);
} else {
- if (bf_isxretried(bf))
+ if (ts->ts_status & ATH9K_TXERR_XRETRY)
TX_STAT_INC(qnum, xretries);
else
TX_STAT_INC(qnum, completed);
@@ -857,6 +873,35 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
TX_STAT_INC(qnum, data_underrun);
if (ts->ts_flags & ATH9K_TX_DELIM_UNDERRUN)
TX_STAT_INC(qnum, delim_underrun);
+
+ spin_lock(&sc->debug.samp_lock);
+ TX_SAMP_DBG(jiffies) = jiffies;
+ TX_SAMP_DBG(rssi_ctl0) = ts->ts_rssi_ctl0;
+ TX_SAMP_DBG(rssi_ctl1) = ts->ts_rssi_ctl1;
+ TX_SAMP_DBG(rssi_ctl2) = ts->ts_rssi_ctl2;
+ TX_SAMP_DBG(rssi_ext0) = ts->ts_rssi_ext0;
+ TX_SAMP_DBG(rssi_ext1) = ts->ts_rssi_ext1;
+ TX_SAMP_DBG(rssi_ext2) = ts->ts_rssi_ext2;
+ TX_SAMP_DBG(rateindex) = ts->ts_rateindex;
+ TX_SAMP_DBG(isok) = !!(ts->ts_status & ATH9K_TXERR_MASK);
+ TX_SAMP_DBG(rts_fail_cnt) = ts->ts_shortretry;
+ TX_SAMP_DBG(data_fail_cnt) = ts->ts_longretry;
+ TX_SAMP_DBG(rssi) = ts->ts_rssi;
+ TX_SAMP_DBG(tid) = ts->tid;
+ TX_SAMP_DBG(qid) = ts->qid;
+
+ if (ts->ts_flags & ATH9K_TX_BA) {
+ TX_SAMP_DBG(ba_low) = ts->ba_low;
+ TX_SAMP_DBG(ba_high) = ts->ba_high;
+ } else {
+ TX_SAMP_DBG(ba_low) = 0;
+ TX_SAMP_DBG(ba_high) = 0;
+ }
+
+ sc->debug.tsidx = (sc->debug.tsidx + 1) % ATH_DBG_MAX_SAMPLES;
+ spin_unlock(&sc->debug.samp_lock);
+
+#undef TX_SAMP_DBG
}
static const struct file_operations fops_xmit = {
@@ -995,6 +1040,8 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs)
{
#define RX_STAT_INC(c) sc->debug.stats.rxstats.c++
#define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++
+#define RX_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].rs\
+ [sc->debug.rsidx].c)
u32 phyerr;
@@ -1030,8 +1077,25 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs)
sc->debug.stats.rxstats.rs_antenna = rs->rs_antenna;
+ spin_lock(&sc->debug.samp_lock);
+ RX_SAMP_DBG(jiffies) = jiffies;
+ RX_SAMP_DBG(rssi_ctl0) = rs->rs_rssi_ctl0;
+ RX_SAMP_DBG(rssi_ctl1) = rs->rs_rssi_ctl1;
+ RX_SAMP_DBG(rssi_ctl2) = rs->rs_rssi_ctl2;
+ RX_SAMP_DBG(rssi_ext0) = rs->rs_rssi_ext0;
+ RX_SAMP_DBG(rssi_ext1) = rs->rs_rssi_ext1;
+ RX_SAMP_DBG(rssi_ext2) = rs->rs_rssi_ext2;
+ RX_SAMP_DBG(antenna) = rs->rs_antenna;
+ RX_SAMP_DBG(rssi) = rs->rs_rssi;
+ RX_SAMP_DBG(rate) = rs->rs_rate;
+ RX_SAMP_DBG(is_mybeacon) = rs->is_mybeacon;
+
+ sc->debug.rsidx = (sc->debug.rsidx + 1) % ATH_DBG_MAX_SAMPLES;
+ spin_unlock(&sc->debug.samp_lock);
+
#undef RX_STAT_INC
#undef RX_PHY_ERR_INC
+#undef RX_SAMP_DBG
}
static const struct file_operations fops_recv = {
@@ -1163,6 +1227,389 @@ static const struct file_operations fops_regdump = {
.llseek = default_llseek,/* read accesses f_pos */
};
+static ssize_t read_file_dump_nfcal(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath9k_nfcal_hist *h = sc->caldata.nfCalHist;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ieee80211_conf *conf = &common->hw->conf;
+ u32 len = 0, size = 1500;
+ u32 i, j;
+ ssize_t retval = 0;
+ char *buf;
+ u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
+ u8 nread;
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ len += snprintf(buf + len, size - len,
+ "Channel Noise Floor : %d\n", ah->noise);
+ len += snprintf(buf + len, size - len,
+ "Chain | privNF | # Readings | NF Readings\n");
+ for (i = 0; i < NUM_NF_READINGS; i++) {
+ if (!(chainmask & (1 << i)) ||
+ ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf)))
+ continue;
+
+ nread = AR_PHY_CCA_FILTERWINDOW_LENGTH - h[i].invalidNFcount;
+ len += snprintf(buf + len, size - len, " %d\t %d\t %d\t\t",
+ i, h[i].privNF, nread);
+ for (j = 0; j < nread; j++)
+ len += snprintf(buf + len, size - len,
+ " %d", h[i].nfCalBuffer[j]);
+ len += snprintf(buf + len, size - len, "\n");
+ }
+
+ if (len > size)
+ len = size;
+
+ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+
+ return retval;
+}
+
+static const struct file_operations fops_dump_nfcal = {
+ .read = read_file_dump_nfcal,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ struct ath_hw *ah = sc->sc_ah;
+ u32 len = 0, size = 1500;
+ ssize_t retval = 0;
+ char *buf;
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ len = ah->eep_ops->dump_eeprom(ah, true, buf, len, size);
+
+ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+
+ return retval;
+}
+
+static const struct file_operations fops_base_eeprom = {
+ .read = read_file_base_eeprom,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ struct ath_hw *ah = sc->sc_ah;
+ u32 len = 0, size = 6000;
+ char *buf;
+ size_t retval;
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ len = ah->eep_ops->dump_eeprom(ah, false, buf, len, size);
+
+ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+
+ return retval;
+}
+
+static const struct file_operations fops_modal_eeprom = {
+ .read = read_file_modal_eeprom,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+void ath9k_debug_samp_bb_mac(struct ath_softc *sc)
+{
+#define ATH_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].c)
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ unsigned long flags;
+ int i;
+
+ ath9k_ps_wakeup(sc);
+
+ spin_lock_bh(&sc->debug.samp_lock);
+
+ spin_lock_irqsave(&common->cc_lock, flags);
+ ath_hw_cycle_counters_update(common);
+
+ ATH_SAMP_DBG(cc.cycles) = common->cc_ani.cycles;
+ ATH_SAMP_DBG(cc.rx_busy) = common->cc_ani.rx_busy;
+ ATH_SAMP_DBG(cc.rx_frame) = common->cc_ani.rx_frame;
+ ATH_SAMP_DBG(cc.tx_frame) = common->cc_ani.tx_frame;
+ spin_unlock_irqrestore(&common->cc_lock, flags);
+
+ ATH_SAMP_DBG(noise) = ah->noise;
+
+ REG_WRITE_D(ah, AR_MACMISC,
+ ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
+ (AR_MACMISC_MISC_OBS_BUS_1 <<
+ AR_MACMISC_MISC_OBS_BUS_MSB_S)));
+
+ for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++)
+ ATH_SAMP_DBG(dma_dbg_reg_vals[i]) = REG_READ_D(ah,
+ AR_DMADBG_0 + (i * sizeof(u32)));
+
+ ATH_SAMP_DBG(pcu_obs) = REG_READ_D(ah, AR_OBS_BUS_1);
+ ATH_SAMP_DBG(pcu_cr) = REG_READ_D(ah, AR_CR);
+
+ memcpy(ATH_SAMP_DBG(nfCalHist), sc->caldata.nfCalHist,
+ sizeof(ATH_SAMP_DBG(nfCalHist)));
+
+ sc->debug.sampidx = (sc->debug.sampidx + 1) % ATH_DBG_MAX_SAMPLES;
+ spin_unlock_bh(&sc->debug.samp_lock);
+ ath9k_ps_restore(sc);
+
+#undef ATH_SAMP_DBG
+}
+
+static int open_file_bb_mac_samps(struct inode *inode, struct file *file)
+{
+#define ATH_SAMP_DBG(c) bb_mac_samp[sampidx].c
+ struct ath_softc *sc = inode->i_private;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ieee80211_conf *conf = &common->hw->conf;
+ struct ath_dbg_bb_mac_samp *bb_mac_samp;
+ struct ath9k_nfcal_hist *h;
+ int i, j, qcuOffset = 0, dcuOffset = 0;
+ u32 *qcuBase, *dcuBase, size = 30000, len = 0;
+ u32 sampidx = 0;
+ u8 *buf;
+ u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
+ u8 nread;
+
+ if (sc->sc_flags & SC_OP_INVALID)
+ return -EAGAIN;
+
+ buf = vmalloc(size);
+ if (!buf)
+ return -ENOMEM;
+ bb_mac_samp = vmalloc(sizeof(*bb_mac_samp) * ATH_DBG_MAX_SAMPLES);
+ if (!bb_mac_samp) {
+ vfree(buf);
+ return -ENOMEM;
+ }
+ /* Account the current state too */
+ ath9k_debug_samp_bb_mac(sc);
+
+ spin_lock_bh(&sc->debug.samp_lock);
+ memcpy(bb_mac_samp, sc->debug.bb_mac_samp,
+ sizeof(*bb_mac_samp) * ATH_DBG_MAX_SAMPLES);
+ len += snprintf(buf + len, size - len,
+ "Current Sample Index: %d\n", sc->debug.sampidx);
+ spin_unlock_bh(&sc->debug.samp_lock);
+
+ len += snprintf(buf + len, size - len,
+ "Raw DMA Debug Dump:\n");
+ len += snprintf(buf + len, size - len, "Sample |\t");
+ for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++)
+ len += snprintf(buf + len, size - len, " DMA Reg%d |\t", i);
+ len += snprintf(buf + len, size - len, "\n");
+
+ for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) {
+ len += snprintf(buf + len, size - len, "%d\t", sampidx);
+
+ for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++)
+ len += snprintf(buf + len, size - len, " %08x\t",
+ ATH_SAMP_DBG(dma_dbg_reg_vals[i]));
+ len += snprintf(buf + len, size - len, "\n");
+ }
+ len += snprintf(buf + len, size - len, "\n");
+
+ len += snprintf(buf + len, size - len,
+ "Sample Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n");
+ for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) {
+ qcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[0]);
+ dcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[4]);
+
+ for (i = 0; i < ATH9K_NUM_QUEUES; i++,
+ qcuOffset += 4, dcuOffset += 5) {
+ if (i == 8) {
+ qcuOffset = 0;
+ qcuBase++;
+ }
+
+ if (i == 6) {
+ dcuOffset = 0;
+ dcuBase++;
+ }
+ if (!sc->debug.stats.txstats[i].queued)
+ continue;
+
+ len += snprintf(buf + len, size - len,
+ "%4d %7d %2x %1x %2x %2x\n",
+ sampidx, i,
+ (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset,
+ (*qcuBase & (0x8 << qcuOffset)) >>
+ (qcuOffset + 3),
+ ATH_SAMP_DBG(dma_dbg_reg_vals[2]) &
+ (0x7 << (i * 3)) >> (i * 3),
+ (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset);
+ }
+ len += snprintf(buf + len, size - len, "\n");
+ }
+ len += snprintf(buf + len, size - len,
+ "samp qcu_sh qcu_fh qcu_comp dcu_comp dcu_arb dcu_fp "
+ "ch_idle_dur ch_idle_dur_val txfifo_val0 txfifo_val1 "
+ "txfifo_dcu0 txfifo_dcu1 pcu_obs AR_CR\n");
+
+ for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) {
+ qcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[0]);
+ dcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[4]);
+
+ len += snprintf(buf + len, size - len, "%4d %5x %5x ", sampidx,
+ (ATH_SAMP_DBG(dma_dbg_reg_vals[3]) & 0x003c0000) >> 18,
+ (ATH_SAMP_DBG(dma_dbg_reg_vals[3]) & 0x03c00000) >> 22);
+ len += snprintf(buf + len, size - len, "%7x %8x ",
+ (ATH_SAMP_DBG(dma_dbg_reg_vals[3]) & 0x1c000000) >> 26,
+ (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x3));
+ len += snprintf(buf + len, size - len, "%7x %7x ",
+ (ATH_SAMP_DBG(dma_dbg_reg_vals[5]) & 0x06000000) >> 25,
+ (ATH_SAMP_DBG(dma_dbg_reg_vals[5]) & 0x38000000) >> 27);
+ len += snprintf(buf + len, size - len, "%7d %12d ",
+ (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x000003fc) >> 2,
+ (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x00000400) >> 10);
+ len += snprintf(buf + len, size - len, "%12d %12d ",
+ (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x00000800) >> 11,
+ (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x00001000) >> 12);
+ len += snprintf(buf + len, size - len, "%12d %12d ",
+ (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x0001e000) >> 13,
+ (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x001e0000) >> 17);
+ len += snprintf(buf + len, size - len, "0x%07x 0x%07x\n",
+ ATH_SAMP_DBG(pcu_obs), ATH_SAMP_DBG(pcu_cr));
+ }
+
+ len += snprintf(buf + len, size - len,
+ "Sample ChNoise Chain privNF #Reading Readings\n");
+ for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) {
+ h = ATH_SAMP_DBG(nfCalHist);
+ if (!ATH_SAMP_DBG(noise))
+ continue;
+
+ for (i = 0; i < NUM_NF_READINGS; i++) {
+ if (!(chainmask & (1 << i)) ||
+ ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf)))
+ continue;
+
+ nread = AR_PHY_CCA_FILTERWINDOW_LENGTH -
+ h[i].invalidNFcount;
+ len += snprintf(buf + len, size - len,
+ "%4d %5d %4d\t %d\t %d\t",
+ sampidx, ATH_SAMP_DBG(noise),
+ i, h[i].privNF, nread);
+ for (j = 0; j < nread; j++)
+ len += snprintf(buf + len, size - len,
+ " %d", h[i].nfCalBuffer[j]);
+ len += snprintf(buf + len, size - len, "\n");
+ }
+ }
+ len += snprintf(buf + len, size - len, "\nCycle counters:\n"
+ "Sample Total Rxbusy Rxframes Txframes\n");
+ for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) {
+ if (!ATH_SAMP_DBG(cc.cycles))
+ continue;
+ len += snprintf(buf + len, size - len,
+ "%4d %08x %08x %08x %08x\n",
+ sampidx, ATH_SAMP_DBG(cc.cycles),
+ ATH_SAMP_DBG(cc.rx_busy),
+ ATH_SAMP_DBG(cc.rx_frame),
+ ATH_SAMP_DBG(cc.tx_frame));
+ }
+
+ len += snprintf(buf + len, size - len, "Tx status Dump :\n");
+ len += snprintf(buf + len, size - len,
+ "Sample rssi:- ctl0 ctl1 ctl2 ext0 ext1 ext2 comb "
+ "isok rts_fail data_fail rate tid qid "
+ "ba_low ba_high tx_before(ms)\n");
+ for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) {
+ for (i = 0; i < ATH_DBG_MAX_SAMPLES; i++) {
+ if (!ATH_SAMP_DBG(ts[i].jiffies))
+ continue;
+ len += snprintf(buf + len, size - len, "%-14d"
+ "%-4d %-4d %-4d %-4d %-4d %-4d %-4d %-4d %-8d "
+ "%-9d %-4d %-3d %-3d %08x %08x %-11d\n",
+ sampidx,
+ ATH_SAMP_DBG(ts[i].rssi_ctl0),
+ ATH_SAMP_DBG(ts[i].rssi_ctl1),
+ ATH_SAMP_DBG(ts[i].rssi_ctl2),
+ ATH_SAMP_DBG(ts[i].rssi_ext0),
+ ATH_SAMP_DBG(ts[i].rssi_ext1),
+ ATH_SAMP_DBG(ts[i].rssi_ext2),
+ ATH_SAMP_DBG(ts[i].rssi),
+ ATH_SAMP_DBG(ts[i].isok),
+ ATH_SAMP_DBG(ts[i].rts_fail_cnt),
+ ATH_SAMP_DBG(ts[i].data_fail_cnt),
+ ATH_SAMP_DBG(ts[i].rateindex),
+ ATH_SAMP_DBG(ts[i].tid),
+ ATH_SAMP_DBG(ts[i].qid),
+ ATH_SAMP_DBG(ts[i].ba_low),
+ ATH_SAMP_DBG(ts[i].ba_high),
+ jiffies_to_msecs(jiffies -
+ ATH_SAMP_DBG(ts[i].jiffies)));
+ }
+ }
+
+ len += snprintf(buf + len, size - len, "Rx status Dump :\n");
+ len += snprintf(buf + len, size - len, "Sample rssi:- ctl0 ctl1 ctl2 "
+ "ext0 ext1 ext2 comb beacon ant rate rx_before(ms)\n");
+ for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) {
+ for (i = 0; i < ATH_DBG_MAX_SAMPLES; i++) {
+ if (!ATH_SAMP_DBG(rs[i].jiffies))
+ continue;
+ len += snprintf(buf + len, size - len, "%-14d"
+ "%-4d %-4d %-4d %-4d %-4d %-4d %-4d %-9s %-2d %02x %-13d\n",
+ sampidx,
+ ATH_SAMP_DBG(rs[i].rssi_ctl0),
+ ATH_SAMP_DBG(rs[i].rssi_ctl1),
+ ATH_SAMP_DBG(rs[i].rssi_ctl2),
+ ATH_SAMP_DBG(rs[i].rssi_ext0),
+ ATH_SAMP_DBG(rs[i].rssi_ext1),
+ ATH_SAMP_DBG(rs[i].rssi_ext2),
+ ATH_SAMP_DBG(rs[i].rssi),
+ ATH_SAMP_DBG(rs[i].is_mybeacon) ?
+ "True" : "False",
+ ATH_SAMP_DBG(rs[i].antenna),
+ ATH_SAMP_DBG(rs[i].rate),
+ jiffies_to_msecs(jiffies -
+ ATH_SAMP_DBG(rs[i].jiffies)));
+ }
+ }
+
+ vfree(bb_mac_samp);
+ file->private_data = buf;
+
+ return 0;
+#undef ATH_SAMP_DBG
+}
+
+static const struct file_operations fops_samps = {
+ .open = open_file_bb_mac_samps,
+ .read = ath9k_debugfs_read_buf,
+ .release = ath9k_debugfs_release_buf,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+
int ath9k_init_debug(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
@@ -1206,6 +1653,14 @@ int ath9k_init_debug(struct ath_hw *ah)
&ah->config.cwm_ignore_extcca);
debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_regdump);
+ debugfs_create_file("dump_nfcal", S_IRUSR, sc->debug.debugfs_phy, sc,
+ &fops_dump_nfcal);
+ debugfs_create_file("base_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
+ &fops_base_eeprom);
+ debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
+ &fops_modal_eeprom);
+ debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc,
+ &fops_samps);
debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask);
@@ -1214,5 +1669,9 @@ int ath9k_init_debug(struct ath_hw *ah)
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;
}
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 4a04510e1111..356352ac2d6e 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -25,8 +25,10 @@ struct ath_buf;
#ifdef CONFIG_ATH9K_DEBUGFS
#define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++
+#define RESET_STAT_INC(sc, type) sc->debug.stats.reset[type]++
#else
#define TX_STAT_INC(q, c) do { } while (0)
+#define RESET_STAT_INC(sc, type) do { } while (0)
#endif
#ifdef CONFIG_ATH9K_DEBUGFS
@@ -171,23 +173,80 @@ struct ath_rx_stats {
u8 rs_antenna;
};
+enum ath_reset_type {
+ RESET_TYPE_BB_HANG,
+ RESET_TYPE_BB_WATCHDOG,
+ RESET_TYPE_FATAL_INT,
+ RESET_TYPE_TX_ERROR,
+ RESET_TYPE_TX_HANG,
+ RESET_TYPE_PLL_HANG,
+ __RESET_TYPE_MAX
+};
+
struct ath_stats {
struct ath_interrupt_stats istats;
struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES];
struct ath_rx_stats rxstats;
+ u32 reset[__RESET_TYPE_MAX];
+};
+
+#define ATH_DBG_MAX_SAMPLES 10
+struct ath_dbg_bb_mac_samp {
+ u32 dma_dbg_reg_vals[ATH9K_NUM_DMA_DEBUG_REGS];
+ u32 pcu_obs, pcu_cr, noise;
+ struct {
+ u64 jiffies;
+ int8_t rssi_ctl0;
+ int8_t rssi_ctl1;
+ int8_t rssi_ctl2;
+ int8_t rssi_ext0;
+ int8_t rssi_ext1;
+ int8_t rssi_ext2;
+ int8_t rssi;
+ bool isok;
+ u8 rts_fail_cnt;
+ u8 data_fail_cnt;
+ u8 rateindex;
+ u8 qid;
+ u8 tid;
+ u32 ba_low;
+ u32 ba_high;
+ } ts[ATH_DBG_MAX_SAMPLES];
+ struct {
+ u64 jiffies;
+ int8_t rssi_ctl0;
+ int8_t rssi_ctl1;
+ int8_t rssi_ctl2;
+ int8_t rssi_ext0;
+ int8_t rssi_ext1;
+ int8_t rssi_ext2;
+ int8_t rssi;
+ bool is_mybeacon;
+ u8 antenna;
+ u8 rate;
+ } rs[ATH_DBG_MAX_SAMPLES];
+ struct ath_cycle_counters cc;
+ struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
};
struct ath9k_debug {
struct dentry *debugfs_phy;
u32 regidx;
struct ath_stats stats;
+ spinlock_t samp_lock;
+ struct ath_dbg_bb_mac_samp bb_mac_samp[ATH_DBG_MAX_SAMPLES];
+ u8 sampidx;
+ u8 tsidx;
+ u8 rsidx;
};
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);
+ struct ath_tx_status *ts, struct ath_txq *txq,
+ unsigned int flags);
void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs);
#else
@@ -197,6 +256,10 @@ 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)
{
@@ -205,7 +268,8 @@ static inline void ath_debug_stat_interrupt(struct ath_softc *sc,
static inline void ath_debug_stat_tx(struct ath_softc *sc,
struct ath_buf *bf,
struct ath_tx_status *ts,
- struct ath_txq *txq)
+ struct ath_txq *txq,
+ unsigned int flags)
{
}
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index e61404dda8c5..e46f751ab508 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -456,12 +456,7 @@ void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah,
pPdGainBoundaries[i] =
min((u16)MAX_RATE_POWER, pPdGainBoundaries[i]);
- if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) {
- minDelta = pPdGainBoundaries[0] - 23;
- pPdGainBoundaries[0] = 23;
- } else {
- minDelta = 0;
- }
+ minDelta = 0;
if (i == 0) {
if (AR_SREV_9280_20_OR_LATER(ah))
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index de99c0da52e4..49abd34be741 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -104,16 +104,11 @@
#define OLC_FOR_AR9287_10_LATER (AR_SREV_9287_11_OR_LATER(ah) && \
ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))
-#define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c
-#define AR_EEPROM_RFSILENT_GPIO_SEL_S 2
-#define AR_EEPROM_RFSILENT_POLARITY 0x0002
-#define AR_EEPROM_RFSILENT_POLARITY_S 1
-
#define EEP_RFSILENT_ENABLED 0x0001
#define EEP_RFSILENT_ENABLED_S 0
#define EEP_RFSILENT_POLARITY 0x0002
#define EEP_RFSILENT_POLARITY_S 1
-#define EEP_RFSILENT_GPIO_SEL 0x001c
+#define EEP_RFSILENT_GPIO_SEL (AR_SREV_9462(ah) ? 0x00fc : 0x001c)
#define EEP_RFSILENT_GPIO_SEL_S 2
#define AR5416_OPFLAGS_11A 0x01
@@ -225,7 +220,6 @@ enum eeprom_param {
EEP_MAC_MID,
EEP_MAC_LSW,
EEP_REG_0,
- EEP_REG_1,
EEP_OP_CAP,
EEP_OP_MODE,
EEP_RF_SILENT,
@@ -253,7 +247,9 @@ enum eeprom_param {
EEP_PAPRD,
EEP_MODAL_VER,
EEP_ANT_DIV_CTL1,
- EEP_CHAIN_MASK_REDUCE
+ EEP_CHAIN_MASK_REDUCE,
+ EEP_ANTENNA_GAIN_2G,
+ EEP_ANTENNA_GAIN_5G
};
enum ar5416_rates {
@@ -649,14 +645,15 @@ struct eeprom_ops {
int (*check_eeprom)(struct ath_hw *hw);
u32 (*get_eeprom)(struct ath_hw *hw, enum eeprom_param param);
bool (*fill_eeprom)(struct ath_hw *hw);
+ u32 (*dump_eeprom)(struct ath_hw *hw, bool dump_base_hdr, u8 *buf,
+ u32 len, u32 size);
int (*get_eeprom_ver)(struct ath_hw *hw);
int (*get_eeprom_rev)(struct ath_hw *hw);
void (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan);
void (*set_addac)(struct ath_hw *hw, struct ath9k_channel *chan);
void (*set_txpower)(struct ath_hw *hw, struct ath9k_channel *chan,
u16 cfgCtl, u8 twiceAntennaReduction,
- u8 twiceMaxRegulatoryPower, u8 powerLimit,
- bool test);
+ u8 powerLimit, bool test);
u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz);
};
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index 47cc95086e6e..9a7520f987f0 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -72,6 +72,117 @@ static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah)
return __ath9k_hw_4k_fill_eeprom(ah);
}
+#if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS)
+static u32 ath9k_dump_4k_modal_eeprom(char *buf, u32 len, u32 size,
+ struct modal_eep_4k_header *modal_hdr)
+{
+ PR_EEP("Chain0 Ant. Control", modal_hdr->antCtrlChain[0]);
+ PR_EEP("Ant. Common Control", modal_hdr->antCtrlCommon);
+ PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]);
+ PR_EEP("Switch Settle", modal_hdr->switchSettling);
+ PR_EEP("Chain0 TxRxAtten", modal_hdr->txRxAttenCh[0]);
+ PR_EEP("Chain0 RxTxMargin", modal_hdr->rxTxMarginCh[0]);
+ PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize);
+ PR_EEP("PGA Desired size", modal_hdr->pgaDesiredSize);
+ PR_EEP("Chain0 xlna Gain", modal_hdr->xlnaGainCh[0]);
+ PR_EEP("txEndToXpaOff", modal_hdr->txEndToXpaOff);
+ PR_EEP("txEndToRxOn", modal_hdr->txEndToRxOn);
+ PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn);
+ PR_EEP("CCA Threshold)", modal_hdr->thresh62);
+ PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]);
+ PR_EEP("xpdGain", modal_hdr->xpdGain);
+ PR_EEP("External PD", modal_hdr->xpd);
+ PR_EEP("Chain0 I Coefficient", modal_hdr->iqCalICh[0]);
+ PR_EEP("Chain0 Q Coefficient", modal_hdr->iqCalQCh[0]);
+ PR_EEP("pdGainOverlap", modal_hdr->pdGainOverlap);
+ PR_EEP("O/D Bias Version", modal_hdr->version);
+ PR_EEP("CCK OutputBias", modal_hdr->ob_0);
+ PR_EEP("BPSK OutputBias", modal_hdr->ob_1);
+ PR_EEP("QPSK OutputBias", modal_hdr->ob_2);
+ PR_EEP("16QAM OutputBias", modal_hdr->ob_3);
+ PR_EEP("64QAM OutputBias", modal_hdr->ob_4);
+ PR_EEP("CCK Driver1_Bias", modal_hdr->db1_0);
+ PR_EEP("BPSK Driver1_Bias", modal_hdr->db1_1);
+ PR_EEP("QPSK Driver1_Bias", modal_hdr->db1_2);
+ PR_EEP("16QAM Driver1_Bias", modal_hdr->db1_3);
+ PR_EEP("64QAM Driver1_Bias", modal_hdr->db1_4);
+ PR_EEP("CCK Driver2_Bias", modal_hdr->db2_0);
+ PR_EEP("BPSK Driver2_Bias", modal_hdr->db2_1);
+ PR_EEP("QPSK Driver2_Bias", modal_hdr->db2_2);
+ PR_EEP("16QAM Driver2_Bias", modal_hdr->db2_3);
+ PR_EEP("64QAM Driver2_Bias", modal_hdr->db2_4);
+ PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl);
+ PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart);
+ PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn);
+ PR_EEP("HT40 Power Inc.", modal_hdr->ht40PowerIncForPdadc);
+ PR_EEP("Chain0 bswAtten", modal_hdr->bswAtten[0]);
+ PR_EEP("Chain0 bswMargin", modal_hdr->bswMargin[0]);
+ PR_EEP("HT40 Switch Settle", modal_hdr->swSettleHt40);
+ PR_EEP("Chain0 xatten2Db", modal_hdr->xatten2Db[0]);
+ PR_EEP("Chain0 xatten2Margin", modal_hdr->xatten2Margin[0]);
+ PR_EEP("Ant. Diversity ctl1", modal_hdr->antdiv_ctl1);
+ PR_EEP("Ant. Diversity ctl2", modal_hdr->antdiv_ctl2);
+ PR_EEP("TX Diversity", modal_hdr->tx_diversity);
+
+ return len;
+}
+
+static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
+ u8 *buf, u32 len, u32 size)
+{
+ struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
+ struct base_eep_header_4k *pBase = &eep->baseEepHeader;
+
+ if (!dump_base_hdr) {
+ len += snprintf(buf + len, size - len,
+ "%20s :\n", "2GHz modal Header");
+ len += ath9k_dump_4k_modal_eeprom(buf, len, size,
+ &eep->modalHeader);
+ goto out;
+ }
+
+ PR_EEP("Major Version", pBase->version >> 12);
+ PR_EEP("Minor Version", pBase->version & 0xFFF);
+ PR_EEP("Checksum", pBase->checksum);
+ PR_EEP("Length", pBase->length);
+ PR_EEP("RegDomain1", pBase->regDmn[0]);
+ PR_EEP("RegDomain2", pBase->regDmn[1]);
+ PR_EEP("TX Mask", pBase->txMask);
+ PR_EEP("RX Mask", pBase->rxMask);
+ PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A));
+ PR_EEP("Allow 2GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11G));
+ PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags &
+ AR5416_OPFLAGS_N_2G_HT20));
+ PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags &
+ AR5416_OPFLAGS_N_2G_HT40));
+ PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags &
+ AR5416_OPFLAGS_N_5G_HT20));
+ PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags &
+ AR5416_OPFLAGS_N_5G_HT40));
+ PR_EEP("Big Endian", !!(pBase->eepMisc & 0x01));
+ PR_EEP("Cal Bin Major Ver", (pBase->binBuildNumber >> 24) & 0xFF);
+ PR_EEP("Cal Bin Minor Ver", (pBase->binBuildNumber >> 16) & 0xFF);
+ PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF);
+ PR_EEP("TX Gain type", pBase->txGainType);
+
+ len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
+ pBase->macAddr);
+
+out:
+ if (len > size)
+ len = size;
+
+ return len;
+}
+#else
+static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
+ u8 *buf, u32 len, u32 size)
+{
+ return 0;
+}
+#endif
+
+
#undef SIZE_EEPROM_4K
static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
@@ -211,8 +322,6 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
return get_unaligned_be16(pBase->macAddr + 4);
case EEP_REG_0:
return pBase->regDmn[0];
- case EEP_REG_1:
- return pBase->regDmn[1];
case EEP_OP_CAP:
return pBase->deviceCap;
case EEP_OP_MODE:
@@ -238,18 +347,16 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
case EEP_ANT_DIV_CTL1:
return pModal->antdiv_ctl1;
case EEP_TXGAIN_TYPE:
- if (ver_minor >= AR5416_EEP_MINOR_VER_19)
- return pBase->txGainType;
- else
- return AR5416_EEP_TXGAIN_ORIGINAL;
+ return pBase->txGainType;
+ case EEP_ANTENNA_GAIN_2G:
+ return pModal->antennaGainCh[0];
default:
return 0;
}
}
static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
- struct ath9k_channel *chan,
- int16_t *pTxPowerIndexOffset)
+ struct ath9k_channel *chan)
{
struct ath_common *common = ath9k_hw_common(ah);
struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
@@ -298,12 +405,7 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 0);
for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) {
- if (AR_SREV_5416_20_OR_LATER(ah) &&
- (ah->rxchainmask == 5 || ah->txchainmask == 5) &&
- (i != 0)) {
- regChainOffset = (i == 1) ? 0x2000 : 0x1000;
- } else
- regChainOffset = i * 0x1000;
+ regChainOffset = i * 0x1000;
if (pEepData->baseEepHeader.txMask & (1 << i)) {
pRawDataset = pEepData->calPierData2G[i];
@@ -316,19 +418,17 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
ENABLE_REGWRITE_BUFFER(ah);
- if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) {
- REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset,
- SM(pdGainOverlap_t2,
- AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
- | SM(gainBoundaries[0],
- AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
- | SM(gainBoundaries[1],
- AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
- | SM(gainBoundaries[2],
- AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
- | SM(gainBoundaries[3],
- AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
- }
+ REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset,
+ SM(pdGainOverlap_t2,
+ AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
+ | SM(gainBoundaries[0],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
+ | SM(gainBoundaries[1],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
+ | SM(gainBoundaries[2],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
+ | SM(gainBoundaries[3],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;
for (j = 0; j < 32; j++) {
@@ -356,16 +456,13 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
REGWRITE_BUFFER_FLUSH(ah);
}
}
-
- *pTxPowerIndexOffset = 0;
}
static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
struct ath9k_channel *chan,
int16_t *ratesArray,
u16 cfgCtl,
- u16 AntennaReduction,
- u16 twiceMaxRegulatoryPower,
+ u16 antenna_reduction,
u16 powerLimit)
{
#define CMP_TEST_GRP \
@@ -374,20 +471,16 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
|| (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))
- struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
int i;
- int16_t twiceLargestAntenna;
u16 twiceMinEdgePower;
u16 twiceMaxEdgePower = MAX_RATE_POWER;
- u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
+ u16 scaledPower = 0, minCtlPower;
u16 numCtlModes;
const u16 *pCtlMode;
u16 ctlMode, freq;
struct chan_centers centers;
struct cal_ctl_data_4k *rep;
struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
- static const u16 tpScaleReductionTable[5] =
- { 0, 3, 6, 9, MAX_RATE_POWER };
struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
0, { 0, 0, 0, 0}
};
@@ -405,19 +498,7 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
ath9k_hw_get_channel_centers(ah, chan, &centers);
- twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0];
- twiceLargestAntenna = (int16_t)min(AntennaReduction -
- twiceLargestAntenna, 0);
-
- maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
- if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) {
- maxRegAllowedPower -=
- (tpScaleReductionTable[(regulatory->tp_scale)] * 2);
- }
-
- scaledPower = min(powerLimit, maxRegAllowedPower);
- scaledPower = max((u16)0, scaledPower);
-
+ scaledPower = powerLimit - antenna_reduction;
numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40;
pCtlMode = ctlModesFor11g;
@@ -573,14 +654,12 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
struct ath9k_channel *chan,
u16 cfgCtl,
u8 twiceAntennaReduction,
- u8 twiceMaxRegulatoryPower,
u8 powerLimit, bool test)
{
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
struct modal_eep_4k_header *pModal = &pEepData->modalHeader;
int16_t ratesArray[Ar5416RateSize];
- int16_t txPowerIndexOffset = 0;
u8 ht40PowerIncForPdadc = 2;
int i;
@@ -594,14 +673,12 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
ath9k_hw_set_4k_power_per_rate_table(ah, chan,
&ratesArray[0], cfgCtl,
twiceAntennaReduction,
- twiceMaxRegulatoryPower,
powerLimit);
- ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset);
+ ath9k_hw_set_4k_power_cal_table(ah, chan);
regulatory->max_power_level = 0;
for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
- ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
if (ratesArray[i] > MAX_RATE_POWER)
ratesArray[i] = MAX_RATE_POWER;
@@ -612,19 +689,8 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
if (test)
return;
- /* Update regulatory */
- i = rate6mb;
- if (IS_CHAN_HT40(chan))
- i = rateHt40_0;
- else if (IS_CHAN_HT20(chan))
- i = rateHt20_0;
-
- regulatory->max_power_level = ratesArray[i];
-
- if (AR_SREV_9280_20_OR_LATER(ah)) {
- for (i = 0; i < Ar5416RateSize; i++)
- ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
- }
+ for (i = 0; i < Ar5416RateSize; i++)
+ ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
ENABLE_REGWRITE_BUFFER(ah);
@@ -694,28 +760,6 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
REGWRITE_BUFFER_FLUSH(ah);
}
-static void ath9k_hw_4k_set_addac(struct ath_hw *ah,
- struct ath9k_channel *chan)
-{
- struct modal_eep_4k_header *pModal;
- struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
- u8 biaslevel;
-
- if (ah->hw_version.macVersion != AR_SREV_VERSION_9160)
- return;
-
- if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7)
- return;
-
- pModal = &eep->modalHeader;
-
- if (pModal->xpaBiasLvl != 0xff) {
- biaslevel = pModal->xpaBiasLvl;
- INI_RA(&ah->iniAddac, 7, 1) =
- (INI_RA(&ah->iniAddac, 7, 1) & (~0x18)) | biaslevel << 3;
- }
-}
-
static void ath9k_hw_4k_set_gain(struct ath_hw *ah,
struct modal_eep_4k_header *pModal,
struct ar5416_eeprom_4k *eep,
@@ -783,6 +827,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
u8 txRxAttenLocal;
u8 ob[5], db1[5], db2[5];
u8 ant_div_control1, ant_div_control2;
+ u8 bb_desired_scale;
u32 regVal;
pModal = &eep->modalHeader;
@@ -1002,30 +1047,29 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
AR_PHY_SETTLING_SWITCH,
pModal->swSettleHt40);
}
- if (AR_SREV_9271(ah) || AR_SREV_9285(ah)) {
- u8 bb_desired_scale = (pModal->bb_scale_smrt_antenna &
- EEP_4K_BB_DESIRED_SCALE_MASK);
- if ((pBase->txGainType == 0) && (bb_desired_scale != 0)) {
- u32 pwrctrl, mask, clr;
-
- mask = BIT(0)|BIT(5)|BIT(10)|BIT(15)|BIT(20)|BIT(25);
- pwrctrl = mask * bb_desired_scale;
- clr = mask * 0x1f;
- REG_RMW(ah, AR_PHY_TX_PWRCTRL8, pwrctrl, clr);
- REG_RMW(ah, AR_PHY_TX_PWRCTRL10, pwrctrl, clr);
- REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL12, pwrctrl, clr);
-
- mask = BIT(0)|BIT(5)|BIT(15);
- pwrctrl = mask * bb_desired_scale;
- clr = mask * 0x1f;
- REG_RMW(ah, AR_PHY_TX_PWRCTRL9, pwrctrl, clr);
-
- mask = BIT(0)|BIT(5);
- pwrctrl = mask * bb_desired_scale;
- clr = mask * 0x1f;
- REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL11, pwrctrl, clr);
- REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL13, pwrctrl, clr);
- }
+
+ bb_desired_scale = (pModal->bb_scale_smrt_antenna &
+ EEP_4K_BB_DESIRED_SCALE_MASK);
+ if ((pBase->txGainType == 0) && (bb_desired_scale != 0)) {
+ u32 pwrctrl, mask, clr;
+
+ mask = BIT(0)|BIT(5)|BIT(10)|BIT(15)|BIT(20)|BIT(25);
+ pwrctrl = mask * bb_desired_scale;
+ clr = mask * 0x1f;
+ REG_RMW(ah, AR_PHY_TX_PWRCTRL8, pwrctrl, clr);
+ REG_RMW(ah, AR_PHY_TX_PWRCTRL10, pwrctrl, clr);
+ REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL12, pwrctrl, clr);
+
+ mask = BIT(0)|BIT(5)|BIT(15);
+ pwrctrl = mask * bb_desired_scale;
+ clr = mask * 0x1f;
+ REG_RMW(ah, AR_PHY_TX_PWRCTRL9, pwrctrl, clr);
+
+ mask = BIT(0)|BIT(5);
+ pwrctrl = mask * bb_desired_scale;
+ clr = mask * 0x1f;
+ REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL11, pwrctrl, clr);
+ REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL13, pwrctrl, clr);
}
}
@@ -1063,10 +1107,10 @@ const struct eeprom_ops eep_4k_ops = {
.check_eeprom = ath9k_hw_4k_check_eeprom,
.get_eeprom = ath9k_hw_4k_get_eeprom,
.fill_eeprom = ath9k_hw_4k_fill_eeprom,
+ .dump_eeprom = ath9k_hw_4k_dump_eeprom,
.get_eeprom_ver = ath9k_hw_4k_get_eeprom_ver,
.get_eeprom_rev = ath9k_hw_4k_get_eeprom_rev,
.set_board_values = ath9k_hw_4k_set_board_values,
- .set_addac = ath9k_hw_4k_set_addac,
.set_txpower = ath9k_hw_4k_set_txpower,
.get_spur_channel = ath9k_hw_4k_get_spur_channel
};
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
index d6f6b192f450..4f5c50a87ce3 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -76,6 +76,111 @@ static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah)
return __ath9k_hw_ar9287_fill_eeprom(ah);
}
+#if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS)
+static u32 ar9287_dump_modal_eeprom(char *buf, u32 len, u32 size,
+ struct modal_eep_ar9287_header *modal_hdr)
+{
+ PR_EEP("Chain0 Ant. Control", modal_hdr->antCtrlChain[0]);
+ PR_EEP("Chain1 Ant. Control", modal_hdr->antCtrlChain[1]);
+ PR_EEP("Ant. Common Control", modal_hdr->antCtrlCommon);
+ PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]);
+ PR_EEP("Chain1 Ant. Gain", modal_hdr->antennaGainCh[1]);
+ PR_EEP("Switch Settle", modal_hdr->switchSettling);
+ PR_EEP("Chain0 TxRxAtten", modal_hdr->txRxAttenCh[0]);
+ PR_EEP("Chain1 TxRxAtten", modal_hdr->txRxAttenCh[1]);
+ PR_EEP("Chain0 RxTxMargin", modal_hdr->rxTxMarginCh[0]);
+ PR_EEP("Chain1 RxTxMargin", modal_hdr->rxTxMarginCh[1]);
+ PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize);
+ PR_EEP("txEndToXpaOff", modal_hdr->txEndToXpaOff);
+ PR_EEP("txEndToRxOn", modal_hdr->txEndToRxOn);
+ PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn);
+ PR_EEP("CCA Threshold)", modal_hdr->thresh62);
+ PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]);
+ PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]);
+ PR_EEP("xpdGain", modal_hdr->xpdGain);
+ PR_EEP("External PD", modal_hdr->xpd);
+ PR_EEP("Chain0 I Coefficient", modal_hdr->iqCalICh[0]);
+ PR_EEP("Chain1 I Coefficient", modal_hdr->iqCalICh[1]);
+ PR_EEP("Chain0 Q Coefficient", modal_hdr->iqCalQCh[0]);
+ PR_EEP("Chain1 Q Coefficient", modal_hdr->iqCalQCh[1]);
+ PR_EEP("pdGainOverlap", modal_hdr->pdGainOverlap);
+ PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl);
+ PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart);
+ PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn);
+ PR_EEP("HT40 Power Inc.", modal_hdr->ht40PowerIncForPdadc);
+ PR_EEP("Chain0 bswAtten", modal_hdr->bswAtten[0]);
+ PR_EEP("Chain1 bswAtten", modal_hdr->bswAtten[1]);
+ PR_EEP("Chain0 bswMargin", modal_hdr->bswMargin[0]);
+ PR_EEP("Chain1 bswMargin", modal_hdr->bswMargin[1]);
+ PR_EEP("HT40 Switch Settle", modal_hdr->swSettleHt40);
+ PR_EEP("AR92x7 Version", modal_hdr->version);
+ PR_EEP("DriverBias1", modal_hdr->db1);
+ PR_EEP("DriverBias2", modal_hdr->db1);
+ PR_EEP("CCK OutputBias", modal_hdr->ob_cck);
+ PR_EEP("PSK OutputBias", modal_hdr->ob_psk);
+ PR_EEP("QAM OutputBias", modal_hdr->ob_qam);
+ PR_EEP("PAL_OFF OutputBias", modal_hdr->ob_pal_off);
+
+ return len;
+}
+
+static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
+ u8 *buf, u32 len, u32 size)
+{
+ struct ar9287_eeprom *eep = &ah->eeprom.map9287;
+ struct base_eep_ar9287_header *pBase = &eep->baseEepHeader;
+
+ if (!dump_base_hdr) {
+ len += snprintf(buf + len, size - len,
+ "%20s :\n", "2GHz modal Header");
+ len += ar9287_dump_modal_eeprom(buf, len, size,
+ &eep->modalHeader);
+ goto out;
+ }
+
+ PR_EEP("Major Version", pBase->version >> 12);
+ PR_EEP("Minor Version", pBase->version & 0xFFF);
+ PR_EEP("Checksum", pBase->checksum);
+ PR_EEP("Length", pBase->length);
+ PR_EEP("RegDomain1", pBase->regDmn[0]);
+ PR_EEP("RegDomain2", pBase->regDmn[1]);
+ PR_EEP("TX Mask", pBase->txMask);
+ PR_EEP("RX Mask", pBase->rxMask);
+ PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A));
+ PR_EEP("Allow 2GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11G));
+ PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags &
+ AR5416_OPFLAGS_N_2G_HT20));
+ PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags &
+ AR5416_OPFLAGS_N_2G_HT40));
+ PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags &
+ AR5416_OPFLAGS_N_5G_HT20));
+ PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags &
+ AR5416_OPFLAGS_N_5G_HT40));
+ PR_EEP("Big Endian", !!(pBase->eepMisc & 0x01));
+ PR_EEP("Cal Bin Major Ver", (pBase->binBuildNumber >> 24) & 0xFF);
+ PR_EEP("Cal Bin Minor Ver", (pBase->binBuildNumber >> 16) & 0xFF);
+ PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF);
+ PR_EEP("Power Table Offset", pBase->pwrTableOffset);
+ PR_EEP("OpenLoop Power Ctrl", pBase->openLoopPwrCntl);
+
+ len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
+ pBase->macAddr);
+
+out:
+ if (len > size)
+ len = size;
+
+ return len;
+}
+#else
+static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
+ u8 *buf, u32 len, u32 size)
+{
+ return 0;
+}
+#endif
+
+
static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
{
u32 sum = 0, el, integer;
@@ -203,8 +308,6 @@ static u32 ath9k_hw_ar9287_get_eeprom(struct ath_hw *ah,
return get_unaligned_be16(pBase->macAddr + 4);
case EEP_REG_0:
return pBase->regDmn[0];
- case EEP_REG_1:
- return pBase->regDmn[1];
case EEP_OP_CAP:
return pBase->deviceCap;
case EEP_OP_MODE:
@@ -231,6 +334,9 @@ static u32 ath9k_hw_ar9287_get_eeprom(struct ath_hw *ah,
return pBase->tempSensSlopePalOn;
else
return 0;
+ case EEP_ANTENNA_GAIN_2G:
+ return max_t(u8, pModal->antennaGainCh[0],
+ pModal->antennaGainCh[1]);
default:
return 0;
}
@@ -307,8 +413,7 @@ static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah,
}
static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah,
- struct ath9k_channel *chan,
- int16_t *pTxPowerIndexOffset)
+ struct ath9k_channel *chan)
{
struct cal_data_per_freq_ar9287 *pRawDataset;
struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop;
@@ -444,16 +549,13 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah,
REGWRITE_BUFFER_FLUSH(ah);
}
}
-
- *pTxPowerIndexOffset = 0;
}
static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
struct ath9k_channel *chan,
int16_t *ratesArray,
u16 cfgCtl,
- u16 AntennaReduction,
- u16 twiceMaxRegulatoryPower,
+ u16 antenna_reduction,
u16 powerLimit)
{
#define CMP_CTL \
@@ -467,12 +569,8 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6
#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10
- struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
u16 twiceMaxEdgePower = MAX_RATE_POWER;
- static const u16 tpScaleReductionTable[5] =
- { 0, 3, 6, 9, MAX_RATE_POWER };
int i;
- int16_t twiceLargestAntenna;
struct cal_ctl_data_ar9287 *rep;
struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} },
targetPowerCck = {0, {0, 0, 0, 0} };
@@ -480,7 +578,7 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
targetPowerCckExt = {0, {0, 0, 0, 0} };
struct cal_target_power_ht targetPowerHt20,
targetPowerHt40 = {0, {0, 0, 0, 0} };
- u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
+ u16 scaledPower = 0, minCtlPower;
static const u16 ctlModesFor11g[] = {
CTL_11B, CTL_11G, CTL_2GHT20,
CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40
@@ -495,24 +593,7 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
tx_chainmask = ah->txchainmask;
ath9k_hw_get_channel_centers(ah, chan, &centers);
-
- /* Compute TxPower reduction due to Antenna Gain */
- twiceLargestAntenna = max(pEepData->modalHeader.antennaGainCh[0],
- pEepData->modalHeader.antennaGainCh[1]);
- twiceLargestAntenna = (int16_t)min((AntennaReduction) -
- twiceLargestAntenna, 0);
-
- /*
- * scaledPower is the minimum of the user input power level
- * and the regulatory allowed power level.
- */
- maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
-
- if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX)
- maxRegAllowedPower -=
- (tpScaleReductionTable[(regulatory->tp_scale)] * 2);
-
- scaledPower = min(powerLimit, maxRegAllowedPower);
+ scaledPower = powerLimit - antenna_reduction;
/*
* Reduce scaled Power by number of chains active
@@ -713,14 +794,12 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
struct ath9k_channel *chan, u16 cfgCtl,
u8 twiceAntennaReduction,
- u8 twiceMaxRegulatoryPower,
u8 powerLimit, bool test)
{
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader;
int16_t ratesArray[Ar5416RateSize];
- int16_t txPowerIndexOffset = 0;
u8 ht40PowerIncForPdadc = 2;
int i;
@@ -733,14 +812,12 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
ath9k_hw_set_ar9287_power_per_rate_table(ah, chan,
&ratesArray[0], cfgCtl,
twiceAntennaReduction,
- twiceMaxRegulatoryPower,
powerLimit);
- ath9k_hw_set_ar9287_power_cal_table(ah, chan, &txPowerIndexOffset);
+ ath9k_hw_set_ar9287_power_cal_table(ah, chan);
regulatory->max_power_level = 0;
for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
- ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
if (ratesArray[i] > MAX_RATE_POWER)
ratesArray[i] = MAX_RATE_POWER;
@@ -751,17 +828,8 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
if (test)
return;
- if (IS_CHAN_2GHZ(chan))
- i = rate1l;
- else
- i = rate6mb;
-
- regulatory->max_power_level = ratesArray[i];
-
- if (AR_SREV_9280_20_OR_LATER(ah)) {
- for (i = 0; i < Ar5416RateSize; i++)
- ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2;
- }
+ for (i = 0; i < Ar5416RateSize; i++)
+ ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2;
ENABLE_REGWRITE_BUFFER(ah);
@@ -851,11 +919,6 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
REGWRITE_BUFFER_FLUSH(ah);
}
-static void ath9k_hw_ar9287_set_addac(struct ath_hw *ah,
- struct ath9k_channel *chan)
-{
-}
-
static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah,
struct ath9k_channel *chan)
{
@@ -1003,10 +1066,10 @@ const struct eeprom_ops eep_ar9287_ops = {
.check_eeprom = ath9k_hw_ar9287_check_eeprom,
.get_eeprom = ath9k_hw_ar9287_get_eeprom,
.fill_eeprom = ath9k_hw_ar9287_fill_eeprom,
+ .dump_eeprom = ath9k_hw_ar9287_dump_eeprom,
.get_eeprom_ver = ath9k_hw_ar9287_get_eeprom_ver,
.get_eeprom_rev = ath9k_hw_ar9287_get_eeprom_rev,
.set_board_values = ath9k_hw_ar9287_set_board_values,
- .set_addac = ath9k_hw_ar9287_set_addac,
.set_txpower = ath9k_hw_ar9287_set_txpower,
.get_spur_channel = ath9k_hw_ar9287_get_spur_channel
};
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c
index b9540a992616..81e629671679 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -133,6 +133,136 @@ static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah)
#undef SIZE_EEPROM_DEF
+#if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS)
+static u32 ath9k_def_dump_modal_eeprom(char *buf, u32 len, u32 size,
+ struct modal_eep_header *modal_hdr)
+{
+ PR_EEP("Chain0 Ant. Control", modal_hdr->antCtrlChain[0]);
+ PR_EEP("Chain1 Ant. Control", modal_hdr->antCtrlChain[1]);
+ PR_EEP("Chain2 Ant. Control", modal_hdr->antCtrlChain[2]);
+ PR_EEP("Ant. Common Control", modal_hdr->antCtrlCommon);
+ PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]);
+ PR_EEP("Chain1 Ant. Gain", modal_hdr->antennaGainCh[1]);
+ PR_EEP("Chain2 Ant. Gain", modal_hdr->antennaGainCh[2]);
+ PR_EEP("Switch Settle", modal_hdr->switchSettling);
+ PR_EEP("Chain0 TxRxAtten", modal_hdr->txRxAttenCh[0]);
+ PR_EEP("Chain1 TxRxAtten", modal_hdr->txRxAttenCh[1]);
+ PR_EEP("Chain2 TxRxAtten", modal_hdr->txRxAttenCh[2]);
+ PR_EEP("Chain0 RxTxMargin", modal_hdr->rxTxMarginCh[0]);
+ PR_EEP("Chain1 RxTxMargin", modal_hdr->rxTxMarginCh[1]);
+ PR_EEP("Chain2 RxTxMargin", modal_hdr->rxTxMarginCh[2]);
+ PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize);
+ PR_EEP("PGA Desired size", modal_hdr->pgaDesiredSize);
+ PR_EEP("Chain0 xlna Gain", modal_hdr->xlnaGainCh[0]);
+ PR_EEP("Chain1 xlna Gain", modal_hdr->xlnaGainCh[1]);
+ PR_EEP("Chain2 xlna Gain", modal_hdr->xlnaGainCh[2]);
+ PR_EEP("txEndToXpaOff", modal_hdr->txEndToXpaOff);
+ PR_EEP("txEndToRxOn", modal_hdr->txEndToRxOn);
+ PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn);
+ PR_EEP("CCA Threshold)", modal_hdr->thresh62);
+ PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]);
+ PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]);
+ PR_EEP("Chain2 NF Threshold", modal_hdr->noiseFloorThreshCh[2]);
+ PR_EEP("xpdGain", modal_hdr->xpdGain);
+ PR_EEP("External PD", modal_hdr->xpd);
+ PR_EEP("Chain0 I Coefficient", modal_hdr->iqCalICh[0]);
+ PR_EEP("Chain1 I Coefficient", modal_hdr->iqCalICh[1]);
+ PR_EEP("Chain2 I Coefficient", modal_hdr->iqCalICh[2]);
+ PR_EEP("Chain0 Q Coefficient", modal_hdr->iqCalQCh[0]);
+ PR_EEP("Chain1 Q Coefficient", modal_hdr->iqCalQCh[1]);
+ PR_EEP("Chain2 Q Coefficient", modal_hdr->iqCalQCh[2]);
+ PR_EEP("pdGainOverlap", modal_hdr->pdGainOverlap);
+ PR_EEP("Chain0 OutputBias", modal_hdr->ob);
+ PR_EEP("Chain0 DriverBias", modal_hdr->db);
+ PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl);
+ PR_EEP("2chain pwr decrease", modal_hdr->pwrDecreaseFor2Chain);
+ PR_EEP("3chain pwr decrease", modal_hdr->pwrDecreaseFor3Chain);
+ PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart);
+ PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn);
+ PR_EEP("HT40 Power Inc.", modal_hdr->ht40PowerIncForPdadc);
+ PR_EEP("Chain0 bswAtten", modal_hdr->bswAtten[0]);
+ PR_EEP("Chain1 bswAtten", modal_hdr->bswAtten[1]);
+ PR_EEP("Chain2 bswAtten", modal_hdr->bswAtten[2]);
+ PR_EEP("Chain0 bswMargin", modal_hdr->bswMargin[0]);
+ PR_EEP("Chain1 bswMargin", modal_hdr->bswMargin[1]);
+ PR_EEP("Chain2 bswMargin", modal_hdr->bswMargin[2]);
+ PR_EEP("HT40 Switch Settle", modal_hdr->swSettleHt40);
+ PR_EEP("Chain0 xatten2Db", modal_hdr->xatten2Db[0]);
+ PR_EEP("Chain1 xatten2Db", modal_hdr->xatten2Db[1]);
+ PR_EEP("Chain2 xatten2Db", modal_hdr->xatten2Db[2]);
+ PR_EEP("Chain0 xatten2Margin", modal_hdr->xatten2Margin[0]);
+ PR_EEP("Chain1 xatten2Margin", modal_hdr->xatten2Margin[1]);
+ PR_EEP("Chain2 xatten2Margin", modal_hdr->xatten2Margin[2]);
+ PR_EEP("Chain1 OutputBias", modal_hdr->ob_ch1);
+ PR_EEP("Chain1 DriverBias", modal_hdr->db_ch1);
+ PR_EEP("LNA Control", modal_hdr->lna_ctl);
+ PR_EEP("XPA Bias Freq0", modal_hdr->xpaBiasLvlFreq[0]);
+ PR_EEP("XPA Bias Freq1", modal_hdr->xpaBiasLvlFreq[1]);
+ PR_EEP("XPA Bias Freq2", modal_hdr->xpaBiasLvlFreq[2]);
+
+ return len;
+}
+
+static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
+ u8 *buf, u32 len, u32 size)
+{
+ struct ar5416_eeprom_def *eep = &ah->eeprom.def;
+ struct base_eep_header *pBase = &eep->baseEepHeader;
+
+ if (!dump_base_hdr) {
+ len += snprintf(buf + len, size - len,
+ "%20s :\n", "2GHz modal Header");
+ len += ath9k_def_dump_modal_eeprom(buf, len, size,
+ &eep->modalHeader[0]);
+ len += snprintf(buf + len, size - len,
+ "%20s :\n", "5GHz modal Header");
+ len += ath9k_def_dump_modal_eeprom(buf, len, size,
+ &eep->modalHeader[1]);
+ goto out;
+ }
+
+ PR_EEP("Major Version", pBase->version >> 12);
+ PR_EEP("Minor Version", pBase->version & 0xFFF);
+ PR_EEP("Checksum", pBase->checksum);
+ PR_EEP("Length", pBase->length);
+ PR_EEP("RegDomain1", pBase->regDmn[0]);
+ PR_EEP("RegDomain2", pBase->regDmn[1]);
+ PR_EEP("TX Mask", pBase->txMask);
+ PR_EEP("RX Mask", pBase->rxMask);
+ PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A));
+ PR_EEP("Allow 2GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11G));
+ PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags &
+ AR5416_OPFLAGS_N_2G_HT20));
+ PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags &
+ AR5416_OPFLAGS_N_2G_HT40));
+ PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags &
+ AR5416_OPFLAGS_N_5G_HT20));
+ PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags &
+ AR5416_OPFLAGS_N_5G_HT40));
+ PR_EEP("Big Endian", !!(pBase->eepMisc & 0x01));
+ PR_EEP("Cal Bin Major Ver", (pBase->binBuildNumber >> 24) & 0xFF);
+ PR_EEP("Cal Bin Minor Ver", (pBase->binBuildNumber >> 16) & 0xFF);
+ PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF);
+ PR_EEP("OpenLoop Power Ctrl", pBase->openLoopPwrCntl);
+
+ len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
+ pBase->macAddr);
+
+out:
+ if (len > size)
+ len = size;
+
+ return len;
+}
+#else
+static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
+ u8 *buf, u32 len, u32 size)
+{
+ return 0;
+}
+#endif
+
+
static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
{
struct ar5416_eeprom_def *eep =
@@ -270,6 +400,7 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah,
struct ar5416_eeprom_def *eep = &ah->eeprom.def;
struct modal_eep_header *pModal = eep->modalHeader;
struct base_eep_header *pBase = &eep->baseEepHeader;
+ int band = 0;
switch (param) {
case EEP_NFTHRESH_5:
@@ -284,8 +415,6 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah,
return get_unaligned_be16(pBase->macAddr + 4);
case EEP_REG_0:
return pBase->regDmn[0];
- case EEP_REG_1:
- return pBase->regDmn[1];
case EEP_OP_CAP:
return pBase->deviceCap;
case EEP_OP_MODE:
@@ -337,6 +466,14 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah,
return pBase->pwr_table_offset;
else
return AR5416_PWR_TABLE_OFFSET_DB;
+ case EEP_ANTENNA_GAIN_2G:
+ band = 1;
+ /* fall through */
+ case EEP_ANTENNA_GAIN_5G:
+ return max_t(u8, max_t(u8,
+ pModal[band].antennaGainCh[0],
+ pModal[band].antennaGainCh[1]),
+ pModal[band].antennaGainCh[2]);
default:
return 0;
}
@@ -417,8 +554,7 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah,
break;
}
- if (AR_SREV_5416_20_OR_LATER(ah) &&
- (ah->rxchainmask == 5 || ah->txchainmask == 5) && (i != 0))
+ if ((ah->rxchainmask == 5 || ah->txchainmask == 5) && (i != 0))
regChainOffset = (i == 1) ? 0x2000 : 0x1000;
else
regChainOffset = i * 0x1000;
@@ -435,9 +571,8 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah,
SM(pModal->iqCalQCh[i],
AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
- if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah))
- ath9k_hw_def_set_gain(ah, pModal, eep, txRxAttenLocal,
- regChainOffset, i);
+ ath9k_hw_def_set_gain(ah, pModal, eep, txRxAttenLocal,
+ regChainOffset, i);
}
if (AR_SREV_9280_20_OR_LATER(ah)) {
@@ -693,8 +828,7 @@ static void ath9k_adjust_pdadc_values(struct ath_hw *ah,
}
static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
- struct ath9k_channel *chan,
- int16_t *pTxPowerIndexOffset)
+ struct ath9k_channel *chan)
{
#define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x)
#define SM_PDGAIN_B(x, y) \
@@ -764,8 +898,7 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
xpdGainValues[2]);
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
- if (AR_SREV_5416_20_OR_LATER(ah) &&
- (ah->rxchainmask == 5 || ah->txchainmask == 5) &&
+ if ((ah->rxchainmask == 5 || ah->txchainmask == 5) &&
(i != 0)) {
regChainOffset = (i == 1) ? 0x2000 : 0x1000;
} else
@@ -806,27 +939,24 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
ENABLE_REGWRITE_BUFFER(ah);
- if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) {
- if (OLC_FOR_AR9280_20_LATER) {
- REG_WRITE(ah,
- AR_PHY_TPCRG5 + regChainOffset,
- SM(0x6,
- AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |
- SM_PD_GAIN(1) | SM_PD_GAIN(2) |
- SM_PD_GAIN(3) | SM_PD_GAIN(4));
- } else {
- REG_WRITE(ah,
- AR_PHY_TPCRG5 + regChainOffset,
- SM(pdGainOverlap_t2,
- AR_PHY_TPCRG5_PD_GAIN_OVERLAP)|
- SM_PDGAIN_B(0, 1) |
- SM_PDGAIN_B(1, 2) |
- SM_PDGAIN_B(2, 3) |
- SM_PDGAIN_B(3, 4));
- }
+ if (OLC_FOR_AR9280_20_LATER) {
+ REG_WRITE(ah,
+ AR_PHY_TPCRG5 + regChainOffset,
+ SM(0x6,
+ AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |
+ SM_PD_GAIN(1) | SM_PD_GAIN(2) |
+ SM_PD_GAIN(3) | SM_PD_GAIN(4));
+ } else {
+ REG_WRITE(ah,
+ AR_PHY_TPCRG5 + regChainOffset,
+ SM(pdGainOverlap_t2,
+ AR_PHY_TPCRG5_PD_GAIN_OVERLAP)|
+ SM_PDGAIN_B(0, 1) |
+ SM_PDGAIN_B(1, 2) |
+ SM_PDGAIN_B(2, 3) |
+ SM_PDGAIN_B(3, 4));
}
-
ath9k_adjust_pdadc_values(ah, pwr_table_offset,
diff, pdadcValues);
@@ -855,7 +985,6 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
}
}
- *pTxPowerIndexOffset = 0;
#undef SM_PD_GAIN
#undef SM_PDGAIN_B
}
@@ -864,21 +993,15 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
struct ath9k_channel *chan,
int16_t *ratesArray,
u16 cfgCtl,
- u16 AntennaReduction,
- u16 twiceMaxRegulatoryPower,
+ u16 antenna_reduction,
u16 powerLimit)
{
#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */
#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 9 /* 10*log10(3)*2 */
- struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
u16 twiceMaxEdgePower = MAX_RATE_POWER;
- static const u16 tpScaleReductionTable[5] =
- { 0, 3, 6, 9, MAX_RATE_POWER };
-
int i;
- int16_t twiceLargestAntenna;
struct cal_ctl_data *rep;
struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
0, { 0, 0, 0, 0}
@@ -890,7 +1013,7 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {
0, {0, 0, 0, 0}
};
- u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
+ u16 scaledPower = 0, minCtlPower;
static const u16 ctlModesFor11a[] = {
CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40
};
@@ -909,27 +1032,7 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
ath9k_hw_get_channel_centers(ah, chan, &centers);
- twiceLargestAntenna = max(
- pEepData->modalHeader
- [IS_CHAN_2GHZ(chan)].antennaGainCh[0],
- pEepData->modalHeader
- [IS_CHAN_2GHZ(chan)].antennaGainCh[1]);
-
- twiceLargestAntenna = max((u8)twiceLargestAntenna,
- pEepData->modalHeader
- [IS_CHAN_2GHZ(chan)].antennaGainCh[2]);
-
- twiceLargestAntenna = (int16_t)min(AntennaReduction -
- twiceLargestAntenna, 0);
-
- maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
-
- if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) {
- maxRegAllowedPower -=
- (tpScaleReductionTable[(regulatory->tp_scale)] * 2);
- }
-
- scaledPower = min(powerLimit, maxRegAllowedPower);
+ scaledPower = powerLimit - antenna_reduction;
switch (ar5416_get_ntxchains(tx_chainmask)) {
case 1:
@@ -1134,7 +1237,6 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
struct ath9k_channel *chan,
u16 cfgCtl,
u8 twiceAntennaReduction,
- u8 twiceMaxRegulatoryPower,
u8 powerLimit, bool test)
{
#define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta)
@@ -1143,7 +1245,6 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
struct modal_eep_header *pModal =
&(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]);
int16_t ratesArray[Ar5416RateSize];
- int16_t txPowerIndexOffset = 0;
u8 ht40PowerIncForPdadc = 2;
int i, cck_ofdm_delta = 0;
@@ -1157,31 +1258,18 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
ath9k_hw_set_def_power_per_rate_table(ah, chan,
&ratesArray[0], cfgCtl,
twiceAntennaReduction,
- twiceMaxRegulatoryPower,
powerLimit);
- ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset);
+ ath9k_hw_set_def_power_cal_table(ah, chan);
regulatory->max_power_level = 0;
for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
- ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
if (ratesArray[i] > MAX_RATE_POWER)
ratesArray[i] = MAX_RATE_POWER;
if (ratesArray[i] > regulatory->max_power_level)
regulatory->max_power_level = ratesArray[i];
}
- if (!test) {
- i = rate6mb;
-
- if (IS_CHAN_HT40(chan))
- i = rateHt40_0;
- else if (IS_CHAN_HT20(chan))
- i = rateHt20_0;
-
- regulatory->max_power_level = ratesArray[i];
- }
-
switch(ar5416_get_ntxchains(ah->txchainmask)) {
case 1:
break;
@@ -1336,6 +1424,7 @@ const struct eeprom_ops eep_def_ops = {
.check_eeprom = ath9k_hw_def_check_eeprom,
.get_eeprom = ath9k_hw_def_get_eeprom,
.fill_eeprom = ath9k_hw_def_fill_eeprom,
+ .dump_eeprom = ath9k_hw_def_dump_eeprom,
.get_eeprom_ver = ath9k_hw_def_get_eeprom_ver,
.get_eeprom_rev = ath9k_hw_def_get_eeprom_rev,
.set_board_values = ath9k_hw_def_set_board_values,
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c
index bc713fc28191..655576c8fdab 100644
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -48,6 +48,8 @@ void ath_init_leds(struct ath_softc *sc)
sc->sc_ah->led_pin = ATH_LED_PIN_9485;
else if (AR_SREV_9300(sc->sc_ah))
sc->sc_ah->led_pin = ATH_LED_PIN_9300;
+ else if (AR_SREV_9462(sc->sc_ah))
+ sc->sc_ah->led_pin = ATH_LED_PIN_9462;
else
sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
}
@@ -82,9 +84,14 @@ void ath_init_leds(struct ath_softc *sc)
static bool ath_is_rfkill_set(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
+ bool is_blocked;
- return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) ==
+ ath9k_ps_wakeup(sc);
+ is_blocked = ath9k_hw_gpio_get(ah, ah->rfkill_gpio) ==
ah->rfkill_polarity;
+ ath9k_ps_restore(sc);
+
+ return is_blocked;
}
void ath9k_rfkill_poll_state(struct ieee80211_hw *hw)
@@ -148,7 +155,8 @@ static void ath9k_gen_timer_start(struct ath_hw *ah,
if ((ah->imask & ATH9K_INT_GENTIMER) == 0) {
ath9k_hw_disable_interrupts(ah);
ah->imask |= ATH9K_INT_GENTIMER;
- ath9k_hw_set_interrupts(ah, ah->imask);
+ ath9k_hw_set_interrupts(ah);
+ ath9k_hw_enable_interrupts(ah);
}
}
@@ -162,7 +170,8 @@ static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
if (timer_table->timer_mask.val == 0) {
ath9k_hw_disable_interrupts(ah);
ah->imask &= ~ATH9K_INT_GENTIMER;
- ath9k_hw_set_interrupts(ah, ah->imask);
+ ath9k_hw_set_interrupts(ah);
+ ath9k_hw_enable_interrupts(ah);
}
}
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index d3f4a59cd456..77c8ded8de57 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -38,6 +38,7 @@ static struct usb_device_id ath9k_hif_usb_ids[] = {
{ USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */
{ USB_DEVICE(0x040D, 0x3801) }, /* VIA */
{ USB_DEVICE(0x0cf3, 0xb003) }, /* Ubiquiti WifiStation Ext */
+ { USB_DEVICE(0x057c, 0x8403) }, /* AVM FRITZ!WLAN 11N v2 USB */
{ USB_DEVICE(0x0cf3, 0x7015),
.driver_info = AR9287_USB }, /* Atheros */
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index 5bc022087e65..da5596766d82 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -521,8 +521,6 @@ void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv,
u8 enable_coex);
-void ath9k_htc_station_work(struct work_struct *work);
-void ath9k_htc_aggr_work(struct work_struct *work);
void ath9k_htc_ani_work(struct work_struct *work);
void ath9k_htc_start_ani(struct ath9k_htc_priv *priv);
void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv);
@@ -542,7 +540,6 @@ int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv);
void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot);
void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv);
void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event);
-void ath9k_htc_tx_failed(struct ath9k_htc_priv *priv);
void ath9k_tx_failed_tasklet(unsigned long data);
void ath9k_htc_tx_cleanup_timer(unsigned long data);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
index db2352e5cc0d..e3a02eb8e0cc 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
@@ -228,8 +228,14 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv)
static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv)
{
- return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) ==
- priv->ah->rfkill_polarity;
+ bool is_blocked;
+
+ ath9k_htc_ps_wakeup(priv);
+ is_blocked = ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) ==
+ priv->ah->rfkill_polarity;
+ ath9k_htc_ps_restore(priv);
+
+ return is_blocked;
}
void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw)
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 3bea7ea86f0a..966661c9e586 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -509,8 +509,8 @@ static void setup_ht_cap(struct ath9k_htc_priv *priv,
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
/* ath9k_htc supports only 1 or 2 stream devices */
- tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, 2);
- rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, 2);
+ tx_streams = ath9k_cmn_count_streams(priv->ah->txchainmask, 2);
+ rx_streams = ath9k_cmn_count_streams(priv->ah->rxchainmask, 2);
ath_dbg(common, ATH_DBG_CONFIG,
"TX streams %d, RX streams: %d\n",
@@ -572,25 +572,6 @@ err:
return -EINVAL;
}
-static void ath9k_init_crypto(struct ath9k_htc_priv *priv)
-{
- struct ath_common *common = ath9k_hw_common(priv->ah);
- int i = 0;
-
- /* Get the hardware key cache size. */
- common->keymax = AR_KEYTABLE_SIZE;
-
- if (priv->ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA)
- common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED;
-
- /*
- * Reset the key cache since some parts do not
- * reset the contents on initial power up.
- */
- for (i = 0; i < common->keymax; i++)
- ath_hw_keyreset(common, (u16) i);
-}
-
static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv)
{
if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
@@ -620,9 +601,6 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
- common->tx_chainmask = priv->ah->caps.tx_chainmask;
- common->rx_chainmask = priv->ah->caps.rx_chainmask;
-
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
priv->ah->opmode = NL80211_IFTYPE_STATION;
@@ -666,7 +644,6 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
return -ENOMEM;
ah->hw_version.devid = devid;
- ah->hw_version.subsysid = 0; /* FIXME */
ah->hw_version.usbdev = drv_info;
ah->ah_flags |= AH_USE_EEPROM;
ah->reg_ops.read = ath9k_regread;
@@ -721,7 +698,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++)
priv->cur_beacon_conf.bslot[i] = NULL;
- ath9k_init_crypto(priv);
+ ath9k_cmn_init_crypto(ah);
ath9k_init_channels_rates(priv);
ath9k_init_misc(priv);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 7212acb2bd6c..0b9a0e8a4958 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -826,8 +826,7 @@ void ath9k_htc_ani_work(struct work_struct *work)
if (longcal || shortcal)
common->ani.caldone =
ath9k_hw_calibrate(ah, ah->curchan,
- common->rx_chainmask,
- longcal);
+ ah->rxchainmask, longcal);
ath9k_htc_ps_restore(priv);
}
@@ -1300,6 +1299,7 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
if (priv->op_flags & OP_INVALID) {
ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_ANY,
"Unable to configure filter on invalid state\n");
+ mutex_unlock(&priv->mutex);
return;
}
ath9k_htc_ps_wakeup(priv);
@@ -1352,7 +1352,8 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw,
return ret;
}
-static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue,
+static int ath9k_htc_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct ath9k_htc_priv *priv = hw->priv;
@@ -1563,7 +1564,8 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
mutex_unlock(&priv->mutex);
}
-static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw)
+static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
{
struct ath9k_htc_priv *priv = hw->priv;
u64 tsf;
@@ -1577,7 +1579,8 @@ static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw)
return tsf;
}
-static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+static void ath9k_htc_set_tsf(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u64 tsf)
{
struct ath9k_htc_priv *priv = hw->priv;
@@ -1588,7 +1591,8 @@ static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf)
mutex_unlock(&priv->mutex);
}
-static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw)
+static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
{
struct ath9k_htc_priv *priv = hw->priv;
@@ -1736,6 +1740,22 @@ out:
return ret;
}
+
+static int ath9k_htc_get_stats(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats)
+{
+ struct ath9k_htc_priv *priv = hw->priv;
+ struct ath_hw *ah = priv->ah;
+ struct ath9k_mib_stats *mib_stats = &ah->ah_mibStats;
+
+ stats->dot11ACKFailureCount = mib_stats->ackrcv_bad;
+ stats->dot11RTSFailureCount = mib_stats->rts_bad;
+ stats->dot11FCSErrorCount = mib_stats->fcs_bad;
+ stats->dot11RTSSuccessCount = mib_stats->rts_good;
+
+ return 0;
+}
+
struct ieee80211_ops ath9k_htc_ops = {
.tx = ath9k_htc_tx,
.start = ath9k_htc_start,
@@ -1759,4 +1779,5 @@ struct ieee80211_ops ath9k_htc_ops = {
.rfkill_poll = ath9k_htc_rfkill_poll_state,
.set_coverage_class = ath9k_htc_set_coverage_class,
.set_bitrate_mask = ath9k_htc_set_bitrate_mask,
+ .get_stats = ath9k_htc_get_stats,
};
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h
index cb29e8875386..e74c233757a2 100644
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
@@ -22,10 +22,12 @@
/* Hardware core and driver accessible callbacks */
static inline void ath9k_hw_configpcipowersave(struct ath_hw *ah,
- int restore,
- int power_off)
+ bool power_off)
{
- ath9k_hw_ops(ah)->config_pci_powersave(ah, restore, power_off);
+ if (ah->aspm_enabled != true)
+ return;
+
+ ath9k_hw_ops(ah)->config_pci_powersave(ah, power_off);
}
static inline void ath9k_hw_rxena(struct ath_hw *ah)
@@ -52,13 +54,10 @@ static inline bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
return ath9k_hw_ops(ah)->get_isr(ah, masked);
}
-static inline void ath9k_hw_filltxdesc(struct ath_hw *ah, void *ds, u32 seglen,
- bool is_firstseg, bool is_lastseg,
- const void *ds0, dma_addr_t buf_addr,
- unsigned int qcu)
+static inline void ath9k_hw_set_txdesc(struct ath_hw *ah, void *ds,
+ struct ath_tx_info *i)
{
- ath9k_hw_ops(ah)->fill_txdesc(ah, ds, seglen, is_firstseg, is_lastseg,
- ds0, buf_addr, qcu);
+ return ath9k_hw_ops(ah)->set_txdesc(ah, ds, i);
}
static inline int ath9k_hw_txprocdesc(struct ath_hw *ah, void *ds,
@@ -67,55 +66,6 @@ static inline int ath9k_hw_txprocdesc(struct ath_hw *ah, void *ds,
return ath9k_hw_ops(ah)->proc_txdesc(ah, ds, ts);
}
-static inline void ath9k_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
- u32 pktLen, enum ath9k_pkt_type type,
- u32 txPower, u32 keyIx,
- enum ath9k_key_type keyType,
- u32 flags)
-{
- ath9k_hw_ops(ah)->set11n_txdesc(ah, ds, pktLen, type, txPower, keyIx,
- keyType, flags);
-}
-
-static inline void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
- void *lastds,
- u32 durUpdateEn, u32 rtsctsRate,
- u32 rtsctsDuration,
- struct ath9k_11n_rate_series series[],
- u32 nseries, u32 flags)
-{
- ath9k_hw_ops(ah)->set11n_ratescenario(ah, ds, lastds, durUpdateEn,
- rtsctsRate, rtsctsDuration, series,
- nseries, flags);
-}
-
-static inline void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, void *ds,
- u32 aggrLen)
-{
- ath9k_hw_ops(ah)->set11n_aggr_first(ah, ds, aggrLen);
-}
-
-static inline void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, void *ds,
- u32 numDelims)
-{
- ath9k_hw_ops(ah)->set11n_aggr_middle(ah, ds, numDelims);
-}
-
-static inline void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, void *ds)
-{
- ath9k_hw_ops(ah)->set11n_aggr_last(ah, ds);
-}
-
-static inline void ath9k_hw_clr11n_aggr(struct ath_hw *ah, void *ds)
-{
- ath9k_hw_ops(ah)->clr11n_aggr(ah, ds);
-}
-
-static inline void ath9k_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
-{
- ath9k_hw_ops(ah)->set_clrdmask(ah, ds, val);
-}
-
static inline void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah,
struct ath_hw_antcomb_conf *antconf)
{
@@ -231,11 +181,6 @@ static inline void ath9k_hw_restore_chainmask(struct ath_hw *ah)
return ath9k_hw_private_ops(ah)->restore_chainmask(ah);
}
-static inline void ath9k_hw_set_diversity(struct ath_hw *ah, bool value)
-{
- return ath9k_hw_private_ops(ah)->set_diversity(ah, value);
-}
-
static inline bool ath9k_hw_ani_control(struct ath_hw *ah,
enum ath9k_ani_cmd cmd, int param)
{
@@ -260,4 +205,11 @@ static inline void ath9k_hw_setup_calibration(struct ath_hw *ah,
ath9k_hw_private_ops(ah)->setup_calibration(ah, currCal);
}
+static inline int ath9k_hw_fast_chan_change(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ u8 *ini_reloaded)
+{
+ return ath9k_hw_private_ops(ah)->fast_chan_change(ah, chan,
+ ini_reloaded);
+}
#endif /* ATH9K_HW_OPS_H */
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 8dcefe74f4c3..f16d2033081f 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -284,7 +284,12 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah)
ah->hw_version.macVersion =
(val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S;
ah->hw_version.macRev = MS(val, AR_SREV_REVISION2);
- ah->is_pciexpress = (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1;
+
+ if (AR_SREV_9462(ah))
+ ah->is_pciexpress = true;
+ else
+ ah->is_pciexpress = (val &
+ AR_SREV_TYPE2_HOST_MODE) ? 0 : 1;
} else {
if (!AR_SREV_9100(ah))
ah->hw_version.macVersion = MS(val, AR_SREV_VERSION);
@@ -428,7 +433,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
regulatory->country_code = CTRY_DEFAULT;
regulatory->power_limit = MAX_RATE_POWER;
- regulatory->tp_scale = ATH9K_TP_SCALE_MAX;
ah->hw_version.magic = AR5416_MAGIC;
ah->hw_version.subvendorid = 0;
@@ -440,7 +444,7 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
if (AR_SREV_9100(ah))
ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX;
ah->enable_32kHz_clock = DONT_USE_32KHZ;
- ah->slottime = 20;
+ ah->slottime = ATH9K_SLOT_TIME_9;
ah->globaltxtimeout = (u32) -1;
ah->power_mode = ATH9K_PM_UNDEFINED;
}
@@ -537,6 +541,9 @@ static int __ath9k_hw_init(struct ath_hw *ah)
return -EIO;
}
+ if (AR_SREV_9462(ah))
+ ah->WARegVal &= ~AR_WA_D3_L1_DISABLE;
+
ath9k_hw_init_defaults(ah);
ath9k_hw_init_config(ah);
@@ -580,6 +587,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
case AR_SREV_VERSION_9330:
case AR_SREV_VERSION_9485:
case AR_SREV_VERSION_9340:
+ case AR_SREV_VERSION_9462:
break;
default:
ath_err(common,
@@ -603,10 +611,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
ath9k_hw_init_mode_regs(ah);
-
- if (ah->is_pciexpress)
- ath9k_hw_aspm_init(ah);
- else
+ if (!ah->is_pciexpress)
ath9k_hw_disablepcie(ah);
if (!AR_SREV_9300_20_OR_LATER(ah))
@@ -621,6 +626,9 @@ static int __ath9k_hw_init(struct ath_hw *ah)
if (r)
return r;
+ if (ah->is_pciexpress)
+ ath9k_hw_aspm_init(ah);
+
r = ath9k_hw_init_macaddr(ah);
if (r) {
ath_err(common, "Failed to initialize MAC address\n");
@@ -663,6 +671,8 @@ int ath9k_hw_init(struct ath_hw *ah)
case AR9300_DEVID_AR9485_PCIE:
case AR9300_DEVID_AR9330:
case AR9300_DEVID_AR9340:
+ case AR9300_DEVID_AR9580:
+ case AR9300_DEVID_AR9462:
break;
default:
if (common->bus_ops->ath_bus_type == ATH_USB)
@@ -959,7 +969,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_conf *conf = &common->hw->conf;
const struct ath9k_channel *chan = ah->curchan;
- int acktimeout;
+ int acktimeout, ctstimeout;
int slottime;
int sifstime;
int rx_lat = 0, tx_lat = 0, eifs = 0;
@@ -974,7 +984,10 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
if (ah->misc_mode != 0)
REG_SET_BIT(ah, AR_PCU_MISC, ah->misc_mode);
- rx_lat = 37;
+ if (IS_CHAN_A_FAST_CLOCK(ah, chan))
+ rx_lat = 41;
+ else
+ rx_lat = 37;
tx_lat = 54;
if (IS_CHAN_HALF_RATE(chan)) {
@@ -988,7 +1001,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
sifstime = 32;
} else if (IS_CHAN_QUARTER_RATE(chan)) {
eifs = 340;
- rx_lat *= 4;
+ rx_lat = (rx_lat * 4) - 1;
tx_lat *= 4;
if (IS_CHAN_A_FAST_CLOCK(ah, chan))
tx_lat += 22;
@@ -996,8 +1009,14 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
slottime = 21;
sifstime = 64;
} else {
- eifs = REG_READ(ah, AR_D_GBL_IFS_EIFS);
- reg = REG_READ(ah, AR_USEC);
+ if (AR_SREV_9287(ah) && AR_SREV_9287_13_OR_LATER(ah)) {
+ eifs = AR_D_GBL_IFS_EIFS_ASYNC_FIFO;
+ reg = AR_USEC_ASYNC_FIFO;
+ } else {
+ eifs = REG_READ(ah, AR_D_GBL_IFS_EIFS)/
+ common->clockrate;
+ reg = REG_READ(ah, AR_USEC);
+ }
rx_lat = MS(reg, AR_USEC_RX_LAT);
tx_lat = MS(reg, AR_USEC_TX_LAT);
@@ -1010,6 +1029,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
/* As defined by IEEE 802.11-2007 17.3.8.6 */
acktimeout = slottime + sifstime + 3 * ah->coverage_class;
+ ctstimeout = acktimeout;
/*
* Workaround for early ACK timeouts, add an offset to match the
@@ -1024,7 +1044,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
ath9k_hw_set_sifs_time(ah, sifstime);
ath9k_hw_setslottime(ah, slottime);
ath9k_hw_set_ack_timeout(ah, acktimeout);
- ath9k_hw_set_cts_timeout(ah, acktimeout);
+ ath9k_hw_set_cts_timeout(ah, ctstimeout);
if (ah->globaltxtimeout != (u32) -1)
ath9k_hw_set_global_txtimeout(ah, ah->globaltxtimeout);
@@ -1329,6 +1349,7 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
{
+
if (AR_SREV_9300_20_OR_LATER(ah)) {
REG_WRITE(ah, AR_WA, ah->WARegVal);
udelay(10);
@@ -1370,11 +1391,17 @@ static bool ath9k_hw_chip_reset(struct ath_hw *ah,
static bool ath9k_hw_channel_change(struct ath_hw *ah,
struct ath9k_channel *chan)
{
- struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
struct ath_common *common = ath9k_hw_common(ah);
- struct ieee80211_channel *channel = chan->chan;
u32 qnum;
int r;
+ bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
+ bool band_switch, mode_diff;
+ u8 ini_reloaded;
+
+ band_switch = (chan->channelFlags & (CHANNEL_2GHZ | CHANNEL_5GHZ)) !=
+ (ah->curchan->channelFlags & (CHANNEL_2GHZ |
+ CHANNEL_5GHZ));
+ mode_diff = (chan->chanmode != ah->curchan->chanmode);
for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
if (ath9k_hw_numtxpending(ah, qnum)) {
@@ -1389,6 +1416,18 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
return false;
}
+ if (edma && (band_switch || mode_diff)) {
+ ath9k_hw_mark_phy_inactive(ah);
+ udelay(5);
+
+ ath9k_hw_init_pll(ah, NULL);
+
+ if (ath9k_hw_fast_chan_change(ah, chan, &ini_reloaded)) {
+ ath_err(common, "Failed to do fast channel change\n");
+ return false;
+ }
+ }
+
ath9k_hw_set_channel_regs(ah, chan);
r = ath9k_hw_rf_set_freq(ah, chan);
@@ -1397,14 +1436,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
return false;
}
ath9k_hw_set_clockrate(ah);
-
- ah->eep_ops->set_txpower(ah, chan,
- ath9k_regd_get_ctl(regulatory, chan),
- channel->max_antenna_gain * 2,
- channel->max_power * 2,
- min((u32) MAX_RATE_POWER,
- (u32) regulatory->power_limit), false);
-
+ ath9k_hw_apply_txpower(ah, chan);
ath9k_hw_rfbus_done(ah);
if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
@@ -1412,6 +1444,18 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
ath9k_hw_spur_mitigate_freq(ah, chan);
+ if (edma && (band_switch || mode_diff)) {
+ ah->ah_flags |= AH_FASTCC;
+ if (band_switch || ini_reloaded)
+ ah->eep_ops->set_board_values(ah, chan);
+
+ ath9k_hw_init_bb(ah, chan);
+
+ if (band_switch || ini_reloaded)
+ ath9k_hw_init_cal(ah, chan);
+ ah->ah_flags &= ~AH_FASTCC;
+ }
+
return true;
}
@@ -1467,9 +1511,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
u32 macStaId1;
u64 tsf = 0;
int i, r;
-
- ah->txchainmask = common->tx_chainmask;
- ah->rxchainmask = common->rx_chainmask;
+ bool allow_fbs = false;
if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
return -EIO;
@@ -1486,15 +1528,24 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
memset(caldata, 0, sizeof(*caldata));
ath9k_init_nfcal_hist_buffer(ah, chan);
}
+ ah->noise = ath9k_hw_getchan_noise(ah, chan);
+
+ if (AR_SREV_9280(ah) && common->bus_ops->ath_bus_type == ATH_PCI)
+ bChannelChange = false;
+
+ if (caldata &&
+ caldata->done_txiqcal_once &&
+ caldata->done_txclcal_once &&
+ caldata->rtt_hist.num_readings)
+ allow_fbs = true;
if (bChannelChange &&
(ah->chip_fullsleep != true) &&
(ah->curchan != NULL) &&
(chan->channel != ah->curchan->channel) &&
- ((chan->channelFlags & CHANNEL_ALL) ==
- (ah->curchan->channelFlags & CHANNEL_ALL)) &&
- (!AR_SREV_9280(ah) || AR_DEVID_7010(ah))) {
-
+ (allow_fbs ||
+ ((chan->channelFlags & CHANNEL_ALL) ==
+ (ah->curchan->channelFlags & CHANNEL_ALL)))) {
if (ath9k_hw_channel_change(ah, chan)) {
ath9k_hw_loadnf(ah, ah->curchan);
ath9k_hw_start_nfcal(ah, true);
@@ -1665,6 +1716,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_init_bb(ah, chan);
+ 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;
@@ -1734,25 +1790,40 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
{
REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
if (setChip) {
+ if (AR_SREV_9462(ah)) {
+ REG_WRITE(ah, AR_TIMER_MODE,
+ REG_READ(ah, AR_TIMER_MODE) & 0xFFFFFF00);
+ REG_WRITE(ah, AR_NDP2_TIMER_MODE, REG_READ(ah,
+ AR_NDP2_TIMER_MODE) & 0xFFFFFF00);
+ REG_WRITE(ah, AR_SLP32_INC,
+ REG_READ(ah, AR_SLP32_INC) & 0xFFF00000);
+ /* xxx Required for WLAN only case ? */
+ REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0);
+ udelay(100);
+ }
+
/*
* Clear the RTC force wake bit to allow the
* mac to go to sleep.
*/
- REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
- AR_RTC_FORCE_WAKE_EN);
+ REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);
+
+ if (AR_SREV_9462(ah))
+ udelay(100);
+
if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah))
REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
/* Shutdown chip. Active low */
- if (!AR_SREV_5416(ah) && !AR_SREV_9271(ah))
- REG_CLR_BIT(ah, (AR_RTC_RESET),
- AR_RTC_RESET_EN);
+ if (!AR_SREV_5416(ah) &&
+ !AR_SREV_9271(ah) && !AR_SREV_9462_10(ah)) {
+ REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN);
+ udelay(2);
+ }
}
/* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */
- if (AR_SREV_9300_20_OR_LATER(ah))
- REG_WRITE(ah, AR_WA,
- ah->WARegVal & ~AR_WA_D3_L1_DISABLE);
+ REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE);
}
/*
@@ -1762,6 +1833,8 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
*/
static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip)
{
+ u32 val;
+
REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
if (setChip) {
struct ath9k_hw_capabilities *pCap = &ah->caps;
@@ -1771,12 +1844,30 @@ static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip)
REG_WRITE(ah, AR_RTC_FORCE_WAKE,
AR_RTC_FORCE_WAKE_ON_INT);
} else {
+
+ /* When chip goes into network sleep, it could be waken
+ * up by MCI_INT interrupt caused by BT's HW messages
+ * (LNA_xxx, CONT_xxx) which chould be in a very fast
+ * rate (~100us). This will cause chip to leave and
+ * re-enter network sleep mode frequently, which in
+ * consequence will have WLAN MCI HW to generate lots of
+ * SYS_WAKING and SYS_SLEEPING messages which will make
+ * BT CPU to busy to process.
+ */
+ if (AR_SREV_9462(ah)) {
+ val = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_EN) &
+ ~AR_MCI_INTERRUPT_RX_HW_MSG_MASK;
+ REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, val);
+ }
/*
* Clear the RTC force wake bit to allow the
* mac to go to sleep.
*/
REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
AR_RTC_FORCE_WAKE_EN);
+
+ if (AR_SREV_9462(ah))
+ udelay(30);
}
}
@@ -2027,11 +2118,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0);
regulatory->current_rd = eeval;
- eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_1);
- if (AR_SREV_9285_12_OR_LATER(ah))
- eeval |= AR9285_RDEXT_DEFAULT;
- regulatory->current_rd_ext = eeval;
-
if (ah->opmode != NL80211_IFTYPE_AP &&
ah->hw_version.subvendorid == AR_SUBVENDOR_ID_NEW_A) {
if (regulatory->current_rd == 0x64 ||
@@ -2083,6 +2169,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->tx_chainmask = fixup_chainmask(chip_chainmask, pCap->tx_chainmask);
pCap->rx_chainmask = fixup_chainmask(chip_chainmask, pCap->rx_chainmask);
+ ah->txchainmask = pCap->tx_chainmask;
+ ah->rxchainmask = pCap->rx_chainmask;
ah->misc_mode |= AR_PCU_MIC_NEW_LOC_ENA;
@@ -2101,6 +2189,10 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->num_gpio_pins = AR9271_NUM_GPIO;
else if (AR_DEVID_7010(ah))
pCap->num_gpio_pins = AR7010_NUM_GPIO;
+ else if (AR_SREV_9300_20_OR_LATER(ah))
+ pCap->num_gpio_pins = AR9300_NUM_GPIO;
+ else if (AR_SREV_9287_11_OR_LATER(ah))
+ pCap->num_gpio_pins = AR9287_NUM_GPIO;
else if (AR_SREV_9285_12_OR_LATER(ah))
pCap->num_gpio_pins = AR9285_NUM_GPIO;
else if (AR_SREV_9280_20_OR_LATER(ah))
@@ -2233,6 +2325,14 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
rx_chainmask >>= 1;
}
+ if (AR_SREV_9300_20_OR_LATER(ah)) {
+ ah->enabled_cals |= TX_IQ_CAL;
+ if (!AR_SREV_9330(ah))
+ ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
+ }
+ if (AR_SREV_9462(ah))
+ pCap->hw_caps |= ATH9K_HW_CAP_RTT;
+
return 0;
}
@@ -2393,6 +2493,9 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
ENABLE_REGWRITE_BUFFER(ah);
+ if (AR_SREV_9462(ah))
+ bits |= ATH9K_RX_FILTER_CONTROL_WRAPPER;
+
REG_WRITE(ah, AR_RX_FILTER, bits);
phybits = 0;
@@ -2434,20 +2537,56 @@ bool ath9k_hw_disable(struct ath_hw *ah)
}
EXPORT_SYMBOL(ath9k_hw_disable);
+static int get_antenna_gain(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+ enum eeprom_param gain_param;
+
+ if (IS_CHAN_2GHZ(chan))
+ gain_param = EEP_ANTENNA_GAIN_2G;
+ else
+ gain_param = EEP_ANTENNA_GAIN_5G;
+
+ return ah->eep_ops->get_eeprom(ah, gain_param);
+}
+
+void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+ struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
+ struct ieee80211_channel *channel;
+ int chan_pwr, new_pwr, max_gain;
+ int ant_gain, ant_reduction = 0;
+
+ if (!chan)
+ return;
+
+ channel = chan->chan;
+ chan_pwr = min_t(int, channel->max_power * 2, MAX_RATE_POWER);
+ new_pwr = min_t(int, chan_pwr, reg->power_limit);
+ max_gain = chan_pwr - new_pwr + channel->max_antenna_gain * 2;
+
+ ant_gain = get_antenna_gain(ah, chan);
+ if (ant_gain > max_gain)
+ ant_reduction = ant_gain - max_gain;
+
+ ah->eep_ops->set_txpower(ah, chan,
+ ath9k_regd_get_ctl(reg, chan),
+ ant_reduction, new_pwr, false);
+}
+
void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test)
{
- struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
struct ath9k_channel *chan = ah->curchan;
struct ieee80211_channel *channel = chan->chan;
- regulatory->power_limit = min(limit, (u32) MAX_RATE_POWER);
+ reg->power_limit = min_t(int, limit, MAX_RATE_POWER);
+ if (test)
+ channel->max_power = MAX_RATE_POWER / 2;
- ah->eep_ops->set_txpower(ah, chan,
- ath9k_regd_get_ctl(regulatory, chan),
- channel->max_antenna_gain * 2,
- channel->max_power * 2,
- min((u32) MAX_RATE_POWER,
- (u32) regulatory->power_limit), test);
+ ath9k_hw_apply_txpower(ah, chan);
+
+ if (test)
+ channel->max_power = DIV_ROUND_UP(reg->max_power_level, 2);
}
EXPORT_SYMBOL(ath9k_hw_set_txpowerlimit);
@@ -2646,6 +2785,20 @@ void ath9k_hw_gen_timer_start(struct ath_hw *ah,
REG_SET_BIT(ah, gen_tmr_configuration[timer->index].mode_addr,
gen_tmr_configuration[timer->index].mode_mask);
+ if (AR_SREV_9462(ah)) {
+ /*
+ * Starting from AR9462, each generic timer can select which tsf
+ * to use. But we still follow the old rule, 0 - 7 use tsf and
+ * 8 - 15 use tsf2.
+ */
+ if ((timer->index < AR_GEN_TIMER_BANK_1_LEN))
+ REG_CLR_BIT(ah, AR_MAC_PCU_GEN_TIMER_TSF_SEL,
+ (1 << timer->index));
+ else
+ REG_SET_BIT(ah, AR_MAC_PCU_GEN_TIMER_TSF_SEL,
+ (1 << timer->index));
+ }
+
/* Enable both trigger and thresh interrupt masks */
REG_SET_BIT(ah, AR_IMR_S5,
(SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) |
@@ -2749,7 +2902,9 @@ static struct {
{ AR_SREV_VERSION_9271, "9271" },
{ AR_SREV_VERSION_9300, "9300" },
{ AR_SREV_VERSION_9330, "9330" },
+ { AR_SREV_VERSION_9340, "9340" },
{ AR_SREV_VERSION_9485, "9485" },
+ { AR_SREV_VERSION_9462, "9462" },
};
/* For devices with external radios */
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index c79889036ec4..f389b3c93cf3 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -45,6 +45,8 @@
#define AR9300_DEVID_PCIE 0x0030
#define AR9300_DEVID_AR9340 0x0031
#define AR9300_DEVID_AR9485_PCIE 0x0032
+#define AR9300_DEVID_AR9580 0x0033
+#define AR9300_DEVID_AR9462 0x0034
#define AR9300_DEVID_AR9330 0x0035
#define AR5416_AR9100_DEVID 0x000b
@@ -93,6 +95,12 @@
(_ah)->reg_ops.write_flush((_ah)); \
} while (0)
+#define PR_EEP(_s, _val) \
+ do { \
+ len += snprintf(buf + len, size - len, "%20s : %10d\n", \
+ _s, (_val)); \
+ } while (0)
+
#define SM(_v, _f) (((_v) << _f##_S) & _f)
#define MS(_v, _f) (((_v) & _f) >> _f##_S)
#define REG_RMW_FIELD(_a, _r, _f, _v) \
@@ -194,6 +202,7 @@ enum ath9k_hw_caps {
ATH9K_HW_CAP_2GHZ = BIT(13),
ATH9K_HW_CAP_5GHZ = BIT(14),
ATH9K_HW_CAP_APM = BIT(15),
+ ATH9K_HW_CAP_RTT = BIT(16),
};
struct ath9k_hw_capabilities {
@@ -329,6 +338,16 @@ enum ath9k_int {
CHANNEL_HT40PLUS | \
CHANNEL_HT40MINUS)
+#define MAX_RTT_TABLE_ENTRY 6
+#define RTT_HIST_MAX 3
+struct ath9k_rtt_hist {
+ u32 table[AR9300_MAX_CHAINS][RTT_HIST_MAX][MAX_RTT_TABLE_ENTRY];
+ u8 num_readings;
+};
+
+#define MAX_IQCAL_MEASUREMENT 8
+#define MAX_CL_TAB_ENTRY 16
+
struct ath9k_hw_cal_data {
u16 channel;
u32 channelFlags;
@@ -338,9 +357,15 @@ struct ath9k_hw_cal_data {
bool paprd_done;
bool nfcal_pending;
bool nfcal_interference;
+ bool done_txiqcal_once;
+ bool done_txclcal_once;
u16 small_signal_gain[AR9300_MAX_CHAINS];
u32 pa_table[AR9300_MAX_CHAINS][PAPRD_TABLE_SZ];
+ u32 num_measures[AR9300_MAX_CHAINS];
+ int tx_corr_coeff[MAX_IQCAL_MEASUREMENT][AR9300_MAX_CHAINS];
+ u32 tx_clcal[AR9300_MAX_CHAINS][MAX_CL_TAB_ENTRY];
struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
+ struct ath9k_rtt_hist rtt_hist;
};
struct ath9k_channel {
@@ -382,14 +407,6 @@ enum ath9k_power_mode {
ATH9K_PM_UNDEFINED
};
-enum ath9k_tp_scale {
- ATH9K_TP_SCALE_MAX = 0,
- ATH9K_TP_SCALE_50,
- ATH9K_TP_SCALE_25,
- ATH9K_TP_SCALE_12,
- ATH9K_TP_SCALE_MIN
-};
-
enum ser_reg_mode {
SER_REG_MODE_OFF = 0,
SER_REG_MODE_ON = 1,
@@ -438,7 +455,6 @@ struct ath9k_hw_version {
u16 phyRev;
u16 analog5GhzRev;
u16 analog2GhzRev;
- u16 subsysid;
enum ath_usb_dev usbdev;
};
@@ -577,7 +593,6 @@ struct ath_hw_private_ops {
bool (*rfbus_req)(struct ath_hw *ah);
void (*rfbus_done)(struct ath_hw *ah);
void (*restore_chainmask)(struct ath_hw *ah);
- void (*set_diversity)(struct ath_hw *ah, bool value);
u32 (*compute_pll_control)(struct ath_hw *ah,
struct ath9k_channel *chan);
bool (*ani_control)(struct ath_hw *ah, enum ath9k_ani_cmd cmd,
@@ -585,6 +600,8 @@ struct ath_hw_private_ops {
void (*do_getnf)(struct ath_hw *ah, int16_t nfarray[NUM_NF_READINGS]);
void (*set_radar_params)(struct ath_hw *ah,
struct ath_hw_radar_conf *conf);
+ int (*fast_chan_change)(struct ath_hw *ah, struct ath9k_channel *chan,
+ u8 *ini_reloaded);
/* ANI */
void (*ani_cache_ini_regs)(struct ath_hw *ah);
@@ -601,8 +618,7 @@ struct ath_hw_private_ops {
*/
struct ath_hw_ops {
void (*config_pci_powersave)(struct ath_hw *ah,
- int restore,
- int power_off);
+ bool power_off);
void (*rx_enable)(struct ath_hw *ah);
void (*set_desc_link)(void *ds, u32 link);
bool (*calibrate)(struct ath_hw *ah,
@@ -610,30 +626,10 @@ struct ath_hw_ops {
u8 rxchainmask,
bool longcal);
bool (*get_isr)(struct ath_hw *ah, enum ath9k_int *masked);
- void (*fill_txdesc)(struct ath_hw *ah, void *ds, u32 seglen,
- bool is_firstseg, bool is_is_lastseg,
- const void *ds0, dma_addr_t buf_addr,
- unsigned int qcu);
+ void (*set_txdesc)(struct ath_hw *ah, void *ds,
+ struct ath_tx_info *i);
int (*proc_txdesc)(struct ath_hw *ah, void *ds,
struct ath_tx_status *ts);
- void (*set11n_txdesc)(struct ath_hw *ah, void *ds,
- u32 pktLen, enum ath9k_pkt_type type,
- u32 txPower, u32 keyIx,
- enum ath9k_key_type keyType,
- u32 flags);
- void (*set11n_ratescenario)(struct ath_hw *ah, void *ds,
- void *lastds,
- u32 durUpdateEn, u32 rtsctsRate,
- u32 rtsctsDuration,
- struct ath9k_11n_rate_series series[],
- u32 nseries, u32 flags);
- void (*set11n_aggr_first)(struct ath_hw *ah, void *ds,
- u32 aggrLen);
- void (*set11n_aggr_middle)(struct ath_hw *ah, void *ds,
- u32 numDelims);
- void (*set11n_aggr_last)(struct ath_hw *ah, void *ds);
- void (*clr11n_aggr)(struct ath_hw *ah, void *ds);
- void (*set_clrdmask)(struct ath_hw *ah, void *ds, bool val);
void (*antdiv_comb_conf_get)(struct ath_hw *ah,
struct ath_hw_antcomb_conf *antconf);
void (*antdiv_comb_conf_set)(struct ath_hw *ah,
@@ -647,9 +643,16 @@ struct ath_nf_limits {
s16 nominal;
};
+enum ath_cal_list {
+ TX_IQ_CAL = BIT(0),
+ TX_IQ_ON_AGC_CAL = BIT(1),
+ TX_CL_CAL = BIT(2),
+};
+
/* ah_flags */
#define AH_USE_EEPROM 0x1
#define AH_UNPLUGGED 0x2 /* The card has been physically removed. */
+#define AH_FASTCC 0x4
struct ath_hw {
struct ath_ops reg_ops;
@@ -690,6 +693,7 @@ struct ath_hw {
enum nl80211_iftype opmode;
enum ath9k_power_mode power_mode;
+ s8 noise;
struct ath9k_hw_cal_data *caldata;
struct ath9k_pacal_info pacal_info;
struct ar5416Stats stats;
@@ -703,8 +707,10 @@ struct ath_hw {
u32 txdesc_interrupt_mask;
u32 txeol_interrupt_mask;
u32 txurn_interrupt_mask;
+ atomic_t intr_ref_cnt;
bool chip_fullsleep;
u32 atim_window;
+ u32 modes_index;
/* Calibration */
u32 supp_cals;
@@ -743,6 +749,7 @@ struct ath_hw {
int32_t sign[AR5416_MAX_CHAINS];
} meas3;
u16 cal_samples;
+ u8 enabled_cals;
u32 sta_id1_defaults;
u32 misc_mode;
@@ -820,11 +827,14 @@ struct ath_hw {
struct ar5416IniArray iniModes_9271_1_0_only;
struct ar5416IniArray iniCckfirNormal;
struct ar5416IniArray iniCckfirJapan2484;
+ struct ar5416IniArray ini_japan2484;
struct ar5416IniArray iniCommon_normal_cck_fir_coeff_9271;
struct ar5416IniArray iniCommon_japan_2484_cck_fir_coeff_9271;
struct ar5416IniArray iniModes_9271_ANI_reg;
struct ar5416IniArray iniModes_high_power_tx_gain_9271;
struct ar5416IniArray iniModes_normal_power_tx_gain_9271;
+ struct ar5416IniArray ini_radio_post_sys2ant;
+ struct ar5416IniArray ini_BTCOEX_MAX_TXPWR;
struct ar5416IniArray iniMac[ATH_INI_NUM_SPLIT];
struct ar5416IniArray iniBB[ATH_INI_NUM_SPLIT];
@@ -978,6 +988,7 @@ void ath9k_hw_htc_resetinit(struct ath_hw *ah);
/* PHY */
void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled,
u32 *coef_mantissa, u32 *coef_exponent);
+void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan);
/*
* Code Specific to AR5008, AR9001 or AR9002,
@@ -1030,10 +1041,6 @@ 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);
-#define ATH_PCIE_CAP_LINK_CTRL 0x70
-#define ATH_PCIE_CAP_LINK_L0S 1
-#define ATH_PCIE_CAP_LINK_L1 2
-
#define ATH9K_CLOCK_RATE_CCK 22
#define ATH9K_CLOCK_RATE_5GHZ_OFDM 40
#define ATH9K_CLOCK_RATE_2GHZ_OFDM 44
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index aa0ff7e2c922..af1b32549531 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -270,8 +270,8 @@ static void setup_ht_cap(struct ath_softc *sc,
/* set up supported mcs set */
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
- tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, max_streams);
- rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, max_streams);
+ tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams);
+ rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams);
ath_dbg(common, ATH_DBG_CONFIG,
"TX streams %d, RX streams: %d\n",
@@ -404,31 +404,6 @@ fail:
return error;
}
-void ath9k_init_crypto(struct ath_softc *sc)
-{
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- int i = 0;
-
- /* Get the hardware key cache size. */
- common->keymax = AR_KEYTABLE_SIZE;
-
- /*
- * Reset the key cache since some parts do not
- * reset the contents on initial power up.
- */
- for (i = 0; i < common->keymax; i++)
- ath_hw_keyreset(common, (u16) i);
-
- /*
- * Check whether the separate key cache entries
- * are required to handle both tx+rx MIC keys.
- * With split mic keys the number of stations is limited
- * to 27 otherwise 59.
- */
- if (sc->sc_ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA)
- common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED;
-}
-
static int ath9k_init_btcoex(struct ath_softc *sc)
{
struct ath_txq *txq;
@@ -531,10 +506,6 @@ static void ath9k_init_misc(struct ath_softc *sc)
sc->sc_flags |= SC_OP_RXAGGR;
}
- common->tx_chainmask = sc->sc_ah->caps.tx_chainmask;
- common->rx_chainmask = sc->sc_ah->caps.rx_chainmask;
-
- ath9k_hw_set_diversity(sc->sc_ah, true);
sc->rx.defant = ath9k_hw_getdefantenna(sc->sc_ah);
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
@@ -548,7 +519,7 @@ static void ath9k_init_misc(struct ath_softc *sc)
sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT;
}
-static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
+static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
const struct ath_bus_ops *bus_ops)
{
struct ath9k_platform_data *pdata = sc->dev->platform_data;
@@ -563,10 +534,10 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
ah->hw = sc->hw;
ah->hw_version.devid = devid;
- ah->hw_version.subsysid = subsysid;
ah->reg_ops.read = ath9k_ioread32;
ah->reg_ops.write = ath9k_iowrite32;
ah->reg_ops.rmw = ath9k_reg_rmw;
+ atomic_set(&ah->intr_ref_cnt, -1);
sc->sc_ah = ah;
if (!pdata) {
@@ -597,6 +568,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
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
tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
@@ -630,7 +602,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
if (ret)
goto err_btcoex;
- ath9k_init_crypto(sc);
+ ath9k_cmn_init_crypto(sc->sc_ah);
ath9k_init_misc(sc);
return 0;
@@ -654,7 +626,6 @@ static void ath9k_init_band_txpower(struct ath_softc *sc, int band)
struct ieee80211_supported_band *sband;
struct ieee80211_channel *chan;
struct ath_hw *ah = sc->sc_ah;
- struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
int i;
sband = &sc->sbands[band];
@@ -663,17 +634,14 @@ static void ath9k_init_band_txpower(struct ath_softc *sc, int band)
ah->curchan = &ah->channels[chan->hw_value];
ath9k_cmn_update_ichannel(ah->curchan, chan, NL80211_CHAN_HT20);
ath9k_hw_set_txpowerlimit(ah, MAX_RATE_POWER, true);
- chan->max_power = reg->max_power_level / 2;
}
}
static void ath9k_init_txpower_limits(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath9k_channel *curchan = ah->curchan;
- ah->txchainmask = common->tx_chainmask;
if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
ath9k_init_band_txpower(sc, IEEE80211_BAND_2GHZ);
if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
@@ -682,9 +650,22 @@ static void ath9k_init_txpower_limits(struct ath_softc *sc)
ah->curchan = curchan;
}
+void ath9k_reload_chainmask_settings(struct ath_softc *sc)
+{
+ if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT))
+ return;
+
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
+ setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
+ setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
+}
+
+
void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
{
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
@@ -722,6 +703,16 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
hw->sta_data_size = sizeof(struct ath_node);
hw->vif_data_size = sizeof(struct ath_vif);
+ hw->wiphy->available_antennas_rx = BIT(ah->caps.max_rxchains) - 1;
+ hw->wiphy->available_antennas_tx = BIT(ah->caps.max_txchains) - 1;
+
+ /* single chain devices with rx diversity */
+ if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)
+ hw->wiphy->available_antennas_rx = BIT(0) | BIT(1);
+
+ sc->ant_rx = hw->wiphy->available_antennas_rx;
+ sc->ant_tx = hw->wiphy->available_antennas_tx;
+
#ifdef CONFIG_ATH9K_RATE_CONTROL
hw->rate_control_algorithm = "ath9k_rate_control";
#endif
@@ -733,17 +724,12 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
&sc->sbands[IEEE80211_BAND_5GHZ];
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
- setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
- setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
- }
+ ath9k_reload_chainmask_settings(sc);
SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
}
-int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
+int ath9k_init_device(u16 devid, struct ath_softc *sc,
const struct ath_bus_ops *bus_ops)
{
struct ieee80211_hw *hw = sc->hw;
@@ -753,7 +739,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
struct ath_regulatory *reg;
/* Bring up device */
- error = ath9k_init_softc(devid, sc, subsysid, bus_ops);
+ error = ath9k_init_softc(devid, sc, bus_ops);
if (error != 0)
goto error_init;
@@ -806,6 +792,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
goto error_world;
}
+ INIT_WORK(&sc->hw_reset_work, ath_reset_work);
INIT_WORK(&sc->hw_check_work, ath_hw_check);
INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index b6b523a897e5..6a8fdf33a527 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -62,18 +62,6 @@ void ath9k_hw_txstart(struct ath_hw *ah, u32 q)
}
EXPORT_SYMBOL(ath9k_hw_txstart);
-void ath9k_hw_cleartxdesc(struct ath_hw *ah, void *ds)
-{
- struct ar5416_desc *ads = AR5416DESC(ds);
-
- ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
- ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
- ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
- ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
- ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
-}
-EXPORT_SYMBOL(ath9k_hw_cleartxdesc);
-
u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q)
{
u32 npend;
@@ -345,21 +333,8 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
}
memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
qi->tqi_type = type;
- if (qinfo == NULL) {
- qi->tqi_qflags =
- TXQ_FLAG_TXOKINT_ENABLE
- | TXQ_FLAG_TXERRINT_ENABLE
- | TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE;
- qi->tqi_aifs = INIT_AIFS;
- qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
- qi->tqi_cwmax = INIT_CWMAX;
- qi->tqi_shretry = INIT_SH_RETRY;
- qi->tqi_lgretry = INIT_LG_RETRY;
- qi->tqi_physCompBuf = 0;
- } else {
- qi->tqi_physCompBuf = qinfo->tqi_physCompBuf;
- (void) ath9k_hw_set_txq_props(ah, q, qinfo);
- }
+ qi->tqi_physCompBuf = qinfo->tqi_physCompBuf;
+ (void) ath9k_hw_set_txq_props(ah, q, qinfo);
return q;
}
@@ -564,7 +539,7 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
EXPORT_SYMBOL(ath9k_hw_resettxqueue);
int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
- struct ath_rx_status *rs, u64 tsf)
+ struct ath_rx_status *rs)
{
struct ar5416_desc ads;
struct ar5416_desc *adsp = AR5416DESC(ds);
@@ -609,7 +584,7 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
else
rs->rs_keyix = ATH9K_RXKEYIX_INVALID;
- rs->rs_rate = RXSTATUS_RATE(ah, (&ads));
+ rs->rs_rate = MS(ads.ds_rxstatus0, AR_RxRate);
rs->rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;
rs->rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
@@ -645,8 +620,8 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
rs->rs_status |= ATH9K_RXERR_DECRYPT;
else if (ads.ds_rxstatus8 & AR_MichaelErr)
rs->rs_status |= ATH9K_RXERR_MIC;
- else if (ads.ds_rxstatus8 & AR_KeyMiss)
- rs->rs_status |= ATH9K_RXERR_DECRYPT;
+ if (ads.ds_rxstatus8 & AR_KeyMiss)
+ rs->rs_status |= ATH9K_RXERR_KEYMISS;
}
return 0;
@@ -800,6 +775,11 @@ void ath9k_hw_disable_interrupts(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
+ if (!(ah->imask & ATH9K_INT_GLOBAL))
+ atomic_set(&ah->intr_ref_cnt, -1);
+ else
+ atomic_dec(&ah->intr_ref_cnt);
+
ath_dbg(common, ATH_DBG_INTERRUPT, "disable IER\n");
REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
(void) REG_READ(ah, AR_IER);
@@ -821,6 +801,13 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah)
if (!(ah->imask & ATH9K_INT_GLOBAL))
return;
+ if (!atomic_inc_and_test(&ah->intr_ref_cnt)) {
+ ath_dbg(common, ATH_DBG_INTERRUPT,
+ "Do not enable IER ref count %d\n",
+ atomic_read(&ah->intr_ref_cnt));
+ return;
+ }
+
if (AR_SREV_9340(ah))
sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
@@ -840,9 +827,9 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah)
}
EXPORT_SYMBOL(ath9k_hw_enable_interrupts);
-void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
+void ath9k_hw_set_interrupts(struct ath_hw *ah)
{
- enum ath9k_int omask = ah->imask;
+ enum ath9k_int ints = ah->imask;
u32 mask, mask2;
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath_common *common = ath9k_hw_common(ah);
@@ -850,9 +837,8 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
if (!(ints & ATH9K_INT_GLOBAL))
ath9k_hw_disable_interrupts(ah);
- ath_dbg(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
+ ath_dbg(common, ATH_DBG_INTERRUPT, "New interrupt mask 0x%x\n", ints);
- /* TODO: global int Ref count */
mask = ints & ATH9K_INT_COMMON;
mask2 = 0;
@@ -929,9 +915,6 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
}
- if (ints & ATH9K_INT_GLOBAL)
- ath9k_hw_enable_interrupts(ah);
-
return;
}
EXPORT_SYMBOL(ath9k_hw_set_interrupts);
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index 8e848c4d16ba..11dbd1473a13 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -17,10 +17,6 @@
#ifndef MAC_H
#define MAC_H
-#define RXSTATUS_RATE(ah, ads) (AR_SREV_5416_20_OR_LATER(ah) ? \
- MS(ads->ds_rxstatus0, AR_RxRate) : \
- (ads->ds_rxstatus3 >> 2) & 0xFF)
-
#define set11nTries(_series, _index) \
(SM((_series)[_index].Tries, AR_XmitDataTries##_index))
@@ -79,9 +75,10 @@
#define ATH9K_TXERR_XTXOP 0x08
#define ATH9K_TXERR_TIMER_EXPIRED 0x10
#define ATH9K_TX_ACKED 0x20
+#define ATH9K_TX_FLUSH 0x40
#define ATH9K_TXERR_MASK \
(ATH9K_TXERR_XRETRY | ATH9K_TXERR_FILT | ATH9K_TXERR_FIFO | \
- ATH9K_TXERR_XTXOP | ATH9K_TXERR_TIMER_EXPIRED)
+ ATH9K_TXERR_XTXOP | ATH9K_TXERR_TIMER_EXPIRED | ATH9K_TX_FLUSH)
#define ATH9K_TX_BA 0x01
#define ATH9K_TX_PWRMGMT 0x02
@@ -146,6 +143,7 @@ struct ath_rx_status {
u8 rs_moreaggr;
u8 rs_num_delims;
u8 rs_flags;
+ bool is_mybeacon;
u32 evm0;
u32 evm1;
u32 evm2;
@@ -184,6 +182,7 @@ struct ath_htc_rx_status {
#define ATH9K_RXERR_FIFO 0x04
#define ATH9K_RXERR_DECRYPT 0x08
#define ATH9K_RXERR_MIC 0x10
+#define ATH9K_RXERR_KEYMISS 0x20
#define ATH9K_RX_MORE 0x01
#define ATH9K_RX_MORE_AGGR 0x02
@@ -194,7 +193,7 @@ struct ath_htc_rx_status {
#define ATH9K_RX_DECRYPT_BUSY 0x40
#define ATH9K_RXKEYIX_INVALID ((u8)-1)
-#define ATH9K_TXKEYIX_INVALID ((u32)-1)
+#define ATH9K_TXKEYIX_INVALID ((u8)-1)
enum ath9k_phyerr {
ATH9K_PHYERR_UNDERRUN = 0, /* Transmit underrun */
@@ -262,7 +261,11 @@ struct ath_desc {
#define ATH9K_TXDESC_VMF 0x0100
#define ATH9K_TXDESC_FRAG_IS_ON 0x0200
#define ATH9K_TXDESC_LOWRXCHAIN 0x0400
-#define ATH9K_TXDESC_LDPC 0x00010000
+#define ATH9K_TXDESC_LDPC 0x0800
+#define ATH9K_TXDESC_CLRDMASK 0x1000
+
+#define ATH9K_TXDESC_PAPRD 0x70000
+#define ATH9K_TXDESC_PAPRD_S 16
#define ATH9K_RXDESC_INTREQ 0x0020
@@ -643,6 +646,7 @@ enum ath9k_rx_filter {
ATH9K_RX_FILTER_PSPOLL = 0x00004000,
ATH9K_RX_FILTER_PHYRADAR = 0x00002000,
ATH9K_RX_FILTER_MCAST_BCAST_ALL = 0x00008000,
+ ATH9K_RX_FILTER_CONTROL_WRAPPER = 0x00080000,
};
#define ATH9K_RATESERIES_RTS_CTS 0x0001
@@ -658,6 +662,13 @@ struct ath9k_11n_rate_series {
u32 RateFlags;
};
+enum aggr_type {
+ AGGR_BUF_NONE,
+ AGGR_BUF_FIRST,
+ AGGR_BUF_MIDDLE,
+ AGGR_BUF_LAST,
+};
+
enum ath9k_key_type {
ATH9K_KEY_TYPE_CLEAR,
ATH9K_KEY_TYPE_WEP,
@@ -665,6 +676,33 @@ enum ath9k_key_type {
ATH9K_KEY_TYPE_TKIP,
};
+struct ath_tx_info {
+ u8 qcu;
+
+ bool is_first;
+ bool is_last;
+
+ enum aggr_type aggr;
+ u8 ndelim;
+ u16 aggr_len;
+
+ dma_addr_t link;
+ int pkt_len;
+ u32 flags;
+
+ dma_addr_t buf_addr[4];
+ int buf_len[4];
+
+ struct ath9k_11n_rate_series rates[4];
+ u8 rtscts_rate;
+ bool dur_update;
+
+ enum ath9k_pkt_type type;
+ enum ath9k_key_type keytype;
+ u8 keyix;
+ u8 txpower;
+};
+
struct ath_hw;
struct ath9k_channel;
enum ath9k_int;
@@ -672,7 +710,6 @@ enum ath9k_int;
u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q);
void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp);
void ath9k_hw_txstart(struct ath_hw *ah, u32 q);
-void ath9k_hw_cleartxdesc(struct ath_hw *ah, void *ds);
u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q);
bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel);
bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q);
@@ -687,7 +724,7 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q);
bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q);
int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
- struct ath_rx_status *rs, u64 tsf);
+ struct ath_rx_status *rs);
void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
u32 size, u32 flags);
bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set);
@@ -699,7 +736,7 @@ int ath9k_hw_beaconq_setup(struct ath_hw *ah);
/* Interrupt Handling */
bool ath9k_hw_intrpend(struct ath_hw *ah);
-void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints);
+void ath9k_hw_set_interrupts(struct ath_hw *ah);
void ath9k_hw_enable_interrupts(struct ath_hw *ah);
void ath9k_hw_disable_interrupts(struct ath_hw *ah);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 9098aaad97a9..93fbe6f40898 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -111,24 +111,29 @@ void ath9k_ps_wakeup(struct ath_softc *sc)
void ath9k_ps_restore(struct ath_softc *sc)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ enum ath9k_power_mode mode;
unsigned long flags;
spin_lock_irqsave(&sc->sc_pm_lock, flags);
if (--sc->ps_usecount != 0)
goto unlock;
- spin_lock(&common->cc_lock);
- ath_hw_cycle_counters_update(common);
- spin_unlock(&common->cc_lock);
-
if (sc->ps_idle)
- ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP);
+ mode = ATH9K_PM_FULL_SLEEP;
else if (sc->ps_enabled &&
!(sc->ps_flags & (PS_WAIT_FOR_BEACON |
PS_WAIT_FOR_CAB |
PS_WAIT_FOR_PSPOLL_DATA |
PS_WAIT_FOR_TX_ACK)))
- ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
+ mode = ATH9K_PM_NETWORK_SLEEP;
+ else
+ goto unlock;
+
+ spin_lock(&common->cc_lock);
+ ath_hw_cycle_counters_update(common);
+ spin_unlock(&common->cc_lock);
+
+ ath9k_hw_setpower(sc->sc_ah, mode);
unlock:
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
@@ -163,7 +168,7 @@ static void ath_update_survey_nf(struct ath_softc *sc, int channel)
if (chan->noisefloor) {
survey->filled |= SURVEY_INFO_NOISE_DBM;
- survey->noise = chan->noisefloor;
+ survey->noise = ath9k_hw_getchan_noise(ah, chan);
}
}
@@ -212,104 +217,168 @@ static int ath_update_survey_stats(struct ath_softc *sc)
return ret;
}
-/*
- * Set/change channels. If the channel is really being changed, it's done
- * by reseting the chip. To accomplish this we must first cleanup any pending
- * DMA, then restart stuff.
-*/
-static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
- struct ath9k_channel *hchan)
+static void __ath_cancel_work(struct ath_softc *sc)
{
- struct ath_hw *ah = sc->sc_ah;
- struct ath_common *common = ath9k_hw_common(ah);
- struct ieee80211_conf *conf = &common->hw->conf;
- bool fastcc = true, stopped;
- struct ieee80211_channel *channel = hw->conf.channel;
- struct ath9k_hw_cal_data *caldata = NULL;
- int r;
-
- if (sc->sc_flags & SC_OP_INVALID)
- return -EIO;
-
- sc->hw_busy_count = 0;
-
- del_timer_sync(&common->ani.timer);
cancel_work_sync(&sc->paprd_work);
cancel_work_sync(&sc->hw_check_work);
cancel_delayed_work_sync(&sc->tx_complete_work);
cancel_delayed_work_sync(&sc->hw_pll_work);
+}
- ath9k_ps_wakeup(sc);
+static void ath_cancel_work(struct ath_softc *sc)
+{
+ __ath_cancel_work(sc);
+ cancel_work_sync(&sc->hw_reset_work);
+}
- spin_lock_bh(&sc->sc_pcu_lock);
+static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ bool ret;
- /*
- * This is only performed if the channel settings have
- * actually changed.
- *
- * To switch channels clear any pending DMA operations;
- * wait long enough for the RX fifo to drain, reset the
- * hardware at the new frequency, and then re-enable
- * the relevant bits of the h/w.
- */
- ath9k_hw_disable_interrupts(ah);
- stopped = ath_drain_all_txq(sc, false);
+ ieee80211_stop_queues(sc->hw);
- if (!ath_stoprecv(sc))
- stopped = false;
+ sc->hw_busy_count = 0;
+ del_timer_sync(&common->ani.timer);
- if (!ath9k_hw_check_alive(ah))
- stopped = false;
+ ath9k_debug_samp_bb_mac(sc);
+ ath9k_hw_disable_interrupts(ah);
- /* XXX: do not flush receive queue here. We don't want
- * to flush data frames already in queue because of
- * changing channel. */
+ ret = ath_drain_all_txq(sc, retry_tx);
- if (!stopped || !(sc->sc_flags & SC_OP_OFFCHANNEL))
- fastcc = false;
+ if (!ath_stoprecv(sc))
+ ret = false;
- if (!(sc->sc_flags & SC_OP_OFFCHANNEL))
- caldata = &sc->caldata;
+ if (!flush) {
+ if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
+ ath_rx_tasklet(sc, 1, true);
+ ath_rx_tasklet(sc, 1, false);
+ } else {
+ ath_flushrecv(sc);
+ }
- ath_dbg(common, ATH_DBG_CONFIG,
- "(%u MHz) -> (%u MHz), conf_is_ht40: %d fastcc: %d\n",
- sc->sc_ah->curchan->channel,
- channel->center_freq, conf_is_ht40(conf),
- fastcc);
+ return ret;
+}
- r = ath9k_hw_reset(ah, hchan, caldata, fastcc);
- if (r) {
- ath_err(common,
- "Unable to reset channel (%u MHz), reset status %d\n",
- channel->center_freq, r);
- goto ps_restore;
- }
+static bool ath_complete_reset(struct ath_softc *sc, bool start)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
if (ath_startrecv(sc) != 0) {
ath_err(common, "Unable to restart recv logic\n");
- r = -EIO;
- goto ps_restore;
+ return false;
}
ath9k_cmn_update_txpow(ah, sc->curtxpow,
sc->config.txpowlimit, &sc->curtxpow);
- ath9k_hw_set_interrupts(ah, ah->imask);
+ ath9k_hw_set_interrupts(ah);
+ ath9k_hw_enable_interrupts(ah);
- if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) {
+ if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) && start) {
if (sc->sc_flags & SC_OP_BEACONS)
ath_set_beacon(sc);
+
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2);
if (!common->disable_ani)
ath_start_ani(common);
}
- ps_restore:
- ieee80211_wake_queues(hw);
+ if (ath9k_hw_ops(ah)->antdiv_comb_conf_get && sc->ant_rx != 3) {
+ struct ath_hw_antcomb_conf div_ant_conf;
+ u8 lna_conf;
+
+ ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf);
+
+ if (sc->ant_rx == 1)
+ lna_conf = ATH_ANT_DIV_COMB_LNA1;
+ else
+ lna_conf = ATH_ANT_DIV_COMB_LNA2;
+ div_ant_conf.main_lna_conf = lna_conf;
+ div_ant_conf.alt_lna_conf = lna_conf;
+
+ ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf);
+ }
+ ieee80211_wake_queues(sc->hw);
+
+ return true;
+}
+
+static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
+ bool retry_tx)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath9k_hw_cal_data *caldata = NULL;
+ bool fastcc = true;
+ bool flush = false;
+ int r;
+
+ __ath_cancel_work(sc);
+
+ spin_lock_bh(&sc->sc_pcu_lock);
+
+ if (!(sc->sc_flags & SC_OP_OFFCHANNEL)) {
+ fastcc = false;
+ caldata = &sc->caldata;
+ }
+
+ if (!hchan) {
+ fastcc = false;
+ flush = true;
+ hchan = ah->curchan;
+ }
+
+ if (fastcc && !ath9k_hw_check_alive(ah))
+ fastcc = false;
+
+ if (!ath_prepare_reset(sc, retry_tx, flush))
+ fastcc = false;
+
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Reset to %u MHz, HT40: %d fastcc: %d\n",
+ hchan->channel, !!(hchan->channelFlags & (CHANNEL_HT40MINUS |
+ CHANNEL_HT40PLUS)),
+ fastcc);
+
+ r = ath9k_hw_reset(ah, hchan, caldata, fastcc);
+ if (r) {
+ ath_err(common,
+ "Unable to reset channel, reset status %d\n", r);
+ goto out;
+ }
+
+ if (!ath_complete_reset(sc, true))
+ r = -EIO;
+
+out:
spin_unlock_bh(&sc->sc_pcu_lock);
+ return r;
+}
+
+
+/*
+ * Set/change channels. If the channel is really being changed, it's done
+ * by reseting the chip. To accomplish this we must first cleanup any pending
+ * DMA, then restart stuff.
+*/
+static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
+ struct ath9k_channel *hchan)
+{
+ int r;
+
+ 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;
}
@@ -317,7 +386,6 @@ static void ath_paprd_activate(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
struct ath9k_hw_cal_data *caldata = ah->caldata;
- struct ath_common *common = ath9k_hw_common(ah);
int chain;
if (!caldata || !caldata->paprd_done)
@@ -326,7 +394,7 @@ static void ath_paprd_activate(struct ath_softc *sc)
ath9k_ps_wakeup(sc);
ar9003_paprd_enable(ah, false);
for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
- if (!(common->tx_chainmask & BIT(chain)))
+ if (!(ah->txchainmask & BIT(chain)))
continue;
ar9003_paprd_populate_single_table(ah, caldata, chain);
@@ -413,7 +481,7 @@ void ath_paprd_calibrate(struct work_struct *work)
memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
- if (!(common->tx_chainmask & BIT(chain)))
+ if (!(ah->txchainmask & BIT(chain)))
continue;
chain_ok = 0;
@@ -534,7 +602,7 @@ void ath_ani_calibrate(unsigned long data)
if (longcal || shortcal) {
common->ani.caldone =
ath9k_hw_calibrate(ah, ah->curchan,
- common->rx_chainmask, longcal);
+ ah->rxchainmask, longcal);
}
ath9k_ps_restore(sc);
@@ -545,6 +613,7 @@ set_timer:
* The interval must be the shortest necessary to satisfy ANI,
* short calibration and long calibration.
*/
+ ath9k_debug_samp_bb_mac(sc);
cal_interval = ATH_LONG_CALINTERVAL;
if (sc->sc_ah->config.enable_ani)
cal_interval = min(cal_interval,
@@ -564,7 +633,6 @@ set_timer:
static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
{
struct ath_node *an;
- struct ath_hw *ah = sc->sc_ah;
an = (struct ath_node *)sta->drv_priv;
#ifdef CONFIG_ATH9K_DEBUGFS
@@ -573,9 +641,6 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
spin_unlock(&sc->nodes_lock);
an->sta = sta;
#endif
- if ((ah->caps.hw_caps) & ATH9K_HW_CAP_APM)
- sc->sc_flags |= SC_OP_ENABLE_APM;
-
if (sc->sc_flags & SC_OP_TXAGGR) {
ath_tx_node_init(sc, an);
an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
@@ -599,74 +664,6 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
ath_tx_node_cleanup(sc, an);
}
-void ath_hw_check(struct work_struct *work)
-{
- struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- unsigned long flags;
- int busy;
-
- ath9k_ps_wakeup(sc);
- if (ath9k_hw_check_alive(sc->sc_ah))
- goto out;
-
- spin_lock_irqsave(&common->cc_lock, flags);
- busy = ath_update_survey_stats(sc);
- spin_unlock_irqrestore(&common->cc_lock, flags);
-
- ath_dbg(common, ATH_DBG_RESET, "Possible baseband hang, "
- "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1);
- if (busy >= 99) {
- if (++sc->hw_busy_count >= 3) {
- spin_lock_bh(&sc->sc_pcu_lock);
- ath_reset(sc, true);
- spin_unlock_bh(&sc->sc_pcu_lock);
- }
- } else if (busy >= 0)
- sc->hw_busy_count = 0;
-
-out:
- ath9k_ps_restore(sc);
-}
-
-static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
-{
- static int count;
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-
- if (pll_sqsum >= 0x40000) {
- count++;
- if (count == 3) {
- /* Rx is hung for more than 500ms. Reset it */
- ath_dbg(common, ATH_DBG_RESET,
- "Possible RX hang, resetting");
- spin_lock_bh(&sc->sc_pcu_lock);
- ath_reset(sc, true);
- spin_unlock_bh(&sc->sc_pcu_lock);
- count = 0;
- }
- } else
- count = 0;
-}
-
-void ath_hw_pll_work(struct work_struct *work)
-{
- struct ath_softc *sc = container_of(work, struct ath_softc,
- hw_pll_work.work);
- u32 pll_sqsum;
-
- if (AR_SREV_9485(sc->sc_ah)) {
-
- ath9k_ps_wakeup(sc);
- pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
- ath9k_ps_restore(sc);
-
- ath_hw_pll_rx_hang_check(sc, pll_sqsum);
-
- ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5);
- }
-}
-
void ath9k_tasklet(unsigned long data)
{
@@ -677,16 +674,24 @@ void ath9k_tasklet(unsigned long data)
u32 status = sc->intrstatus;
u32 rxmask;
+ ath9k_ps_wakeup(sc);
+ spin_lock(&sc->sc_pcu_lock);
+
if ((status & ATH9K_INT_FATAL) ||
(status & ATH9K_INT_BB_WATCHDOG)) {
- spin_lock(&sc->sc_pcu_lock);
- ath_reset(sc, true);
- spin_unlock(&sc->sc_pcu_lock);
- return;
- }
+#ifdef CONFIG_ATH9K_DEBUGFS
+ enum ath_reset_type type;
- ath9k_ps_wakeup(sc);
- spin_lock(&sc->sc_pcu_lock);
+ if (status & ATH9K_INT_FATAL)
+ type = RESET_TYPE_FATAL_INT;
+ else
+ type = RESET_TYPE_BB_WATCHDOG;
+
+ RESET_STAT_INC(sc, type);
+#endif
+ ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
+ goto out;
+ }
/*
* Only run the baseband hang check if beacons stop working in AP or
@@ -706,8 +711,7 @@ void ath9k_tasklet(unsigned long data)
*/
ath_dbg(common, ATH_DBG_PS,
"TSFOOR - Sync with next Beacon\n");
- sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC |
- PS_TSFOOR_SYNC;
+ sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC;
}
if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
@@ -736,6 +740,7 @@ void ath9k_tasklet(unsigned long data)
if (status & ATH9K_INT_GENTIMER)
ath_gen_timer_isr(sc->sc_ah);
+out:
/* re-enable hardware interrupt */
ath9k_hw_enable_interrupts(ah);
@@ -826,11 +831,9 @@ irqreturn_t ath_isr(int irq, void *dev)
if (status & ATH9K_INT_TXURN)
ath9k_hw_updatetxtriglevel(ah, true);
- if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
- if (status & ATH9K_INT_RXEOL) {
- ah->imask &= ~(ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
- ath9k_hw_set_interrupts(ah, ah->imask);
- }
+ if (status & ATH9K_INT_RXEOL) {
+ ah->imask &= ~(ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
+ ath9k_hw_set_interrupts(ah);
}
if (status & ATH9K_INT_MIB) {
@@ -886,8 +889,9 @@ static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
ath9k_ps_wakeup(sc);
spin_lock_bh(&sc->sc_pcu_lock);
+ atomic_set(&ah->intr_ref_cnt, -1);
- ath9k_hw_configpcipowersave(ah, 0, 0);
+ ath9k_hw_configpcipowersave(ah, false);
if (!ah->curchan)
ah->curchan = ath9k_cmn_get_curchannel(sc->hw, ah);
@@ -899,27 +903,13 @@ static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
channel->center_freq, r);
}
- ath9k_cmn_update_txpow(ah, sc->curtxpow,
- sc->config.txpowlimit, &sc->curtxpow);
- if (ath_startrecv(sc) != 0) {
- ath_err(common, "Unable to restart recv logic\n");
- goto out;
- }
- if (sc->sc_flags & SC_OP_BEACONS)
- ath_set_beacon(sc); /* restart beacons */
-
- /* Re-Enable interrupts */
- ath9k_hw_set_interrupts(ah, ah->imask);
+ ath_complete_reset(sc, true);
/* Enable LED */
ath9k_hw_cfg_output(ah, ah->led_pin,
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
ath9k_hw_set_gpio(ah, ah->led_pin, 0);
- ieee80211_wake_queues(hw);
- ieee80211_queue_delayed_work(hw, &sc->hw_pll_work, HZ/2);
-
-out:
spin_unlock_bh(&sc->sc_pcu_lock);
ath9k_ps_restore(sc);
@@ -932,11 +922,10 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
int r;
ath9k_ps_wakeup(sc);
- cancel_delayed_work_sync(&sc->hw_pll_work);
- spin_lock_bh(&sc->sc_pcu_lock);
+ ath_cancel_work(sc);
- ieee80211_stop_queues(hw);
+ spin_lock_bh(&sc->sc_pcu_lock);
/*
* Keep the LED on when the radio is disabled
@@ -947,13 +936,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
}
- /* Disable interrupts */
- ath9k_hw_disable_interrupts(ah);
-
- ath_drain_all_txq(sc, false); /* clear pending tx frames */
-
- ath_stoprecv(sc); /* turn off frame recv */
- ath_flushrecv(sc); /* flush recv queue */
+ ath_prepare_reset(sc, false, true);
if (!ah->curchan)
ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
@@ -967,55 +950,19 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
ath9k_hw_phy_disable(ah);
- ath9k_hw_configpcipowersave(ah, 1, 1);
+ ath9k_hw_configpcipowersave(ah, true);
spin_unlock_bh(&sc->sc_pcu_lock);
ath9k_ps_restore(sc);
}
-int ath_reset(struct ath_softc *sc, bool retry_tx)
+static int ath_reset(struct ath_softc *sc, bool retry_tx)
{
- struct ath_hw *ah = sc->sc_ah;
- struct ath_common *common = ath9k_hw_common(ah);
- struct ieee80211_hw *hw = sc->hw;
int r;
- sc->hw_busy_count = 0;
-
- /* Stop ANI */
-
- del_timer_sync(&common->ani.timer);
-
ath9k_ps_wakeup(sc);
- ieee80211_stop_queues(hw);
-
- ath9k_hw_disable_interrupts(ah);
- ath_drain_all_txq(sc, retry_tx);
-
- ath_stoprecv(sc);
- ath_flushrecv(sc);
-
- r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
- if (r)
- ath_err(common,
- "Unable to reset hardware; reset status %d\n", r);
-
- if (ath_startrecv(sc) != 0)
- ath_err(common, "Unable to start recv logic\n");
-
- /*
- * We may be doing a reset in response to a request
- * that changes the channel so update any state that
- * might change as a result.
- */
- ath9k_cmn_update_txpow(ah, sc->curtxpow,
- sc->config.txpowlimit, &sc->curtxpow);
-
- if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL)))
- ath_set_beacon(sc); /* restart beacons */
-
- ath9k_hw_set_interrupts(ah, ah->imask);
+ r = ath_reset_internal(sc, NULL, retry_tx);
if (retry_tx) {
int i;
@@ -1028,15 +975,83 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
}
}
- ieee80211_wake_queues(hw);
+ ath9k_ps_restore(sc);
- /* Start ANI */
- if (!common->disable_ani)
- ath_start_ani(common);
+ return r;
+}
+
+void ath_reset_work(struct work_struct *work)
+{
+ struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work);
+
+ ath_reset(sc, true);
+}
+
+void ath_hw_check(struct work_struct *work)
+{
+ struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ unsigned long flags;
+ int busy;
+ ath9k_ps_wakeup(sc);
+ if (ath9k_hw_check_alive(sc->sc_ah))
+ goto out;
+
+ spin_lock_irqsave(&common->cc_lock, flags);
+ busy = ath_update_survey_stats(sc);
+ spin_unlock_irqrestore(&common->cc_lock, flags);
+
+ ath_dbg(common, ATH_DBG_RESET, "Possible baseband hang, "
+ "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1);
+ if (busy >= 99) {
+ if (++sc->hw_busy_count >= 3) {
+ RESET_STAT_INC(sc, RESET_TYPE_BB_HANG);
+ ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
+ }
+
+ } else if (busy >= 0)
+ sc->hw_busy_count = 0;
+
+out:
ath9k_ps_restore(sc);
+}
- return r;
+static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
+{
+ static int count;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ if (pll_sqsum >= 0x40000) {
+ count++;
+ if (count == 3) {
+ /* Rx is hung for more than 500ms. Reset it */
+ ath_dbg(common, ATH_DBG_RESET,
+ "Possible RX hang, resetting");
+ RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG);
+ ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
+ count = 0;
+ }
+ } else
+ count = 0;
+}
+
+void ath_hw_pll_work(struct work_struct *work)
+{
+ struct ath_softc *sc = container_of(work, struct ath_softc,
+ hw_pll_work.work);
+ u32 pll_sqsum;
+
+ if (AR_SREV_9485(sc->sc_ah)) {
+
+ ath9k_ps_wakeup(sc);
+ pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
+ ath9k_ps_restore(sc);
+
+ ath_hw_pll_rx_hang_check(sc, pll_sqsum);
+
+ ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5);
+ }
}
/**********************/
@@ -1066,7 +1081,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
init_channel = ath9k_cmn_get_curchannel(hw, ah);
/* Reset SERDES registers */
- ath9k_hw_configpcipowersave(ah, 0, 0);
+ ath9k_hw_configpcipowersave(ah, false);
/*
* The basic interface to setting the hardware in a good
@@ -1085,28 +1100,6 @@ static int ath9k_start(struct ieee80211_hw *hw)
goto mutex_unlock;
}
- /*
- * This is needed only to setup initial state
- * but it's best done after a reset.
- */
- ath9k_cmn_update_txpow(ah, sc->curtxpow,
- sc->config.txpowlimit, &sc->curtxpow);
-
- /*
- * Setup the hardware after reset:
- * The receive engine is set going.
- * Frame transmit is handled entirely
- * in the frame output path; there's nothing to do
- * here except setup the interrupt mask.
- */
- if (ath_startrecv(sc) != 0) {
- ath_err(common, "Unable to start recv logic\n");
- r = -EIO;
- spin_unlock_bh(&sc->sc_pcu_lock);
- goto mutex_unlock;
- }
- spin_unlock_bh(&sc->sc_pcu_lock);
-
/* Setup our intr mask. */
ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL |
ATH9K_INT_RXORN | ATH9K_INT_FATAL |
@@ -1129,11 +1122,14 @@ static int ath9k_start(struct ieee80211_hw *hw)
/* Disable BMISS interrupt when we're not associated */
ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
- ath9k_hw_set_interrupts(ah, ah->imask);
- ieee80211_wake_queues(hw);
+ if (!ath_complete_reset(sc, false)) {
+ r = -EIO;
+ spin_unlock_bh(&sc->sc_pcu_lock);
+ goto mutex_unlock;
+ }
- ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
+ spin_unlock_bh(&sc->sc_pcu_lock);
if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) &&
!ah->btcoex_hw.enabled) {
@@ -1141,8 +1137,6 @@ static int ath9k_start(struct ieee80211_hw *hw)
AR_STOMP_LOW_WLAN_WGHT);
ath9k_hw_btcoex_enable(ah);
- if (common->bus_ops->bt_coex_prep)
- common->bus_ops->bt_coex_prep(common);
if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
ath9k_btcoex_timer_resume(sc);
}
@@ -1228,10 +1222,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
mutex_lock(&sc->mutex);
- cancel_delayed_work_sync(&sc->tx_complete_work);
- cancel_delayed_work_sync(&sc->hw_pll_work);
- cancel_work_sync(&sc->paprd_work);
- cancel_work_sync(&sc->hw_check_work);
+ ath_cancel_work(sc);
if (sc->sc_flags & SC_OP_INVALID) {
ath_dbg(common, ATH_DBG_ANY, "Device not present\n");
@@ -1418,7 +1409,7 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
ah->imask &= ~ATH9K_INT_TSFOOR;
}
- ath9k_hw_set_interrupts(ah, ah->imask);
+ ath9k_hw_set_interrupts(ah);
/* Set up ANI */
if (iter_data.naps > 0) {
@@ -1593,7 +1584,7 @@ static void ath9k_enable_ps(struct ath_softc *sc)
if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
if ((ah->imask & ATH9K_INT_TIM_TIMER) == 0) {
ah->imask |= ATH9K_INT_TIM_TIMER;
- ath9k_hw_set_interrupts(ah, ah->imask);
+ ath9k_hw_set_interrupts(ah);
}
ath9k_hw_setrxabort(ah, 1);
}
@@ -1613,7 +1604,7 @@ static void ath9k_disable_ps(struct ath_softc *sc)
PS_WAIT_FOR_TX_ACK);
if (ah->imask & ATH9K_INT_TIM_TIMER) {
ah->imask &= ~ATH9K_INT_TIM_TIMER;
- ath9k_hw_set_interrupts(ah, ah->imask);
+ ath9k_hw_set_interrupts(ah);
}
}
@@ -1676,6 +1667,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
struct ieee80211_channel *curchan = hw->conf.channel;
+ struct ath9k_channel old_chan;
int pos = curchan->hw_value;
int old_pos = -1;
unsigned long flags;
@@ -1692,15 +1684,25 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
"Set channel: %d MHz type: %d\n",
curchan->center_freq, conf->channel_type);
- ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos],
- curchan, conf->channel_type);
-
/* update survey stats for the old channel before switching */
spin_lock_irqsave(&common->cc_lock, flags);
ath_update_survey_stats(sc);
spin_unlock_irqrestore(&common->cc_lock, flags);
/*
+ * Preserve the current channel values, before updating
+ * the same channel
+ */
+ if (old_pos == pos) {
+ memcpy(&old_chan, &sc->sc_ah->channels[pos],
+ sizeof(struct ath9k_channel));
+ ah->curchan = &old_chan;
+ }
+
+ ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos],
+ curchan, conf->channel_type);
+
+ /*
* If the operating channel changes, change the survey in-use flags
* along with it.
* Reset the survey data for the new channel, unless we're switching
@@ -1844,8 +1846,7 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw,
switch (cmd) {
case STA_NOTIFY_SLEEP:
an->sleeping = true;
- if (ath_tx_aggr_sleep(sc, an))
- ieee80211_sta_set_tim(sta);
+ ath_tx_aggr_sleep(sta, sc, an);
break;
case STA_NOTIFY_AWAKE:
an->sleeping = false;
@@ -1854,7 +1855,8 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw,
}
}
-static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
+static int ath9k_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct ath_softc *sc = hw->priv;
@@ -2032,6 +2034,7 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif)
/* Stop ANI */
sc->sc_flags &= ~SC_OP_ANI_RUN;
del_timer_sync(&common->ani.timer);
+ memset(&sc->caldata, 0, sizeof(sc->caldata));
}
}
@@ -2153,7 +2156,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
ath9k_ps_restore(sc);
}
-static u64 ath9k_get_tsf(struct ieee80211_hw *hw)
+static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct ath_softc *sc = hw->priv;
u64 tsf;
@@ -2167,7 +2170,9 @@ static u64 ath9k_get_tsf(struct ieee80211_hw *hw)
return tsf;
}
-static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+static void ath9k_set_tsf(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ u64 tsf)
{
struct ath_softc *sc = hw->priv;
@@ -2178,7 +2183,7 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
mutex_unlock(&sc->mutex);
}
-static void ath9k_reset_tsf(struct ieee80211_hw *hw)
+static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct ath_softc *sc = hw->priv;
@@ -2283,7 +2288,11 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
mutex_lock(&sc->mutex);
ah->coverage_class = coverage_class;
+
+ ath9k_ps_wakeup(sc);
ath9k_hw_init_global_settings(ah);
+ ath9k_ps_restore(sc);
+
mutex_unlock(&sc->mutex);
}
@@ -2299,6 +2308,12 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
mutex_lock(&sc->mutex);
cancel_delayed_work_sync(&sc->tx_complete_work);
+ if (ah->ah_flags & AH_UNPLUGGED) {
+ ath_dbg(common, ATH_DBG_ANY, "Device has been unplugged!\n");
+ mutex_unlock(&sc->mutex);
+ return;
+ }
+
if (sc->sc_flags & SC_OP_INVALID) {
ath_dbg(common, ATH_DBG_ANY, "Device not present\n");
mutex_unlock(&sc->mutex);
@@ -2331,9 +2346,11 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
ath9k_ps_wakeup(sc);
spin_lock_bh(&sc->sc_pcu_lock);
drain_txq = ath_drain_all_txq(sc, false);
+ spin_unlock_bh(&sc->sc_pcu_lock);
+
if (!drain_txq)
ath_reset(sc, false);
- spin_unlock_bh(&sc->sc_pcu_lock);
+
ath9k_ps_restore(sc);
ieee80211_wake_queues(hw);
@@ -2396,6 +2413,73 @@ skip:
return sc->beacon.tx_last;
}
+static int ath9k_get_stats(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath9k_mib_stats *mib_stats = &ah->ah_mibStats;
+
+ stats->dot11ACKFailureCount = mib_stats->ackrcv_bad;
+ stats->dot11RTSFailureCount = mib_stats->rts_bad;
+ stats->dot11FCSErrorCount = mib_stats->fcs_bad;
+ stats->dot11RTSSuccessCount = mib_stats->rts_good;
+ return 0;
+}
+
+static u32 fill_chainmask(u32 cap, u32 new)
+{
+ u32 filled = 0;
+ int i;
+
+ for (i = 0; cap && new; i++, cap >>= 1) {
+ if (!(cap & BIT(0)))
+ continue;
+
+ if (new & BIT(0))
+ filled |= BIT(i);
+
+ new >>= 1;
+ }
+
+ return filled;
+}
+
+static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_hw *ah = sc->sc_ah;
+
+ if (!rx_ant || !tx_ant)
+ return -EINVAL;
+
+ sc->ant_rx = rx_ant;
+ sc->ant_tx = tx_ant;
+
+ if (ah->caps.rx_chainmask == 1)
+ return 0;
+
+ /* AR9100 runs into calibration issues if not all rx chains are enabled */
+ if (AR_SREV_9100(ah))
+ ah->rxchainmask = 0x7;
+ else
+ ah->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant);
+
+ ah->txchainmask = fill_chainmask(ah->caps.tx_chainmask, tx_ant);
+ ath9k_reload_chainmask_settings(sc);
+
+ return 0;
+}
+
+static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
+{
+ struct ath_softc *sc = hw->priv;
+
+ *tx_ant = sc->ant_tx;
+ *rx_ant = sc->ant_rx;
+ return 0;
+}
+
struct ieee80211_ops ath9k_ops = {
.tx = ath9k_tx,
.start = ath9k_start,
@@ -2420,5 +2504,8 @@ struct ieee80211_ops ath9k_ops = {
.set_coverage_class = ath9k_set_coverage_class,
.flush = ath9k_flush,
.tx_frames_pending = ath9k_tx_frames_pending,
- .tx_last_beacon = ath9k_tx_last_beacon,
+ .tx_last_beacon = ath9k_tx_last_beacon,
+ .get_stats = ath9k_get_stats,
+ .set_antenna = ath9k_set_antenna,
+ .get_antenna = ath9k_get_antenna,
};
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index be4ea1329813..edb0b4b3da3a 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -32,9 +32,12 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
{ PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */
{ PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E AR9300 */
{ PCI_VDEVICE(ATHEROS, 0x0032) }, /* PCI-E AR9485 */
+ { PCI_VDEVICE(ATHEROS, 0x0033) }, /* PCI-E AR9580 */
+ { PCI_VDEVICE(ATHEROS, 0x0034) }, /* PCI-E AR9462 */
{ 0 }
};
+
/* return bus cachesize in 4B word units */
static void ath_pci_read_cachesize(struct ath_common *common, int *csz)
{
@@ -88,23 +91,6 @@ static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data)
return true;
}
-/*
- * Bluetooth coexistance requires disabling ASPM.
- */
-static void ath_pci_bt_coex_prep(struct ath_common *common)
-{
- struct ath_softc *sc = (struct ath_softc *) common->priv;
- struct pci_dev *pdev = to_pci_dev(sc->dev);
- u8 aspm;
-
- if (!pci_is_pcie(pdev))
- return;
-
- pci_read_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, &aspm);
- aspm &= ~(ATH_PCIE_CAP_LINK_L0S | ATH_PCIE_CAP_LINK_L1);
- pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm);
-}
-
static void ath_pci_extn_synch_enable(struct ath_common *common)
{
struct ath_softc *sc = (struct ath_softc *) common->priv;
@@ -116,6 +102,7 @@ static void ath_pci_extn_synch_enable(struct ath_common *common)
pci_write_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, lnkctl);
}
+/* Need to be called after we discover btcoex capabilities */
static void ath_pci_aspm_init(struct ath_common *common)
{
struct ath_softc *sc = (struct ath_softc *) common->priv;
@@ -125,19 +112,38 @@ static void ath_pci_aspm_init(struct ath_common *common)
int pos;
u8 aspm;
- if (!pci_is_pcie(pdev))
+ pos = pci_pcie_cap(pdev);
+ if (!pos)
return;
parent = pdev->bus->self;
- if (WARN_ON(!parent))
+ if (!parent)
return;
+ if (ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) {
+ /* Bluetooth coexistance requires disabling ASPM. */
+ pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &aspm);
+ aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
+ pci_write_config_byte(pdev, pos + PCI_EXP_LNKCTL, aspm);
+
+ /*
+ * Both upstream and downstream PCIe components should
+ * have the same ASPM settings.
+ */
+ pos = pci_pcie_cap(parent);
+ pci_read_config_byte(parent, pos + PCI_EXP_LNKCTL, &aspm);
+ aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
+ pci_write_config_byte(parent, pos + PCI_EXP_LNKCTL, aspm);
+
+ return;
+ }
+
pos = pci_pcie_cap(parent);
pci_read_config_byte(parent, pos + PCI_EXP_LNKCTL, &aspm);
if (aspm & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) {
ah->aspm_enabled = true;
/* Initialize PCIe PM and SERDES registers. */
- ath9k_hw_configpcipowersave(ah, 0, 0);
+ ath9k_hw_configpcipowersave(ah, false);
}
}
@@ -145,7 +151,6 @@ static const struct ath_bus_ops ath_pci_bus_ops = {
.ath_bus_type = ATH_PCI,
.read_cachesize = ath_pci_read_cachesize,
.eeprom_read = ath_pci_eeprom_read,
- .bt_coex_prep = ath_pci_bt_coex_prep,
.extn_synch_en = ath_pci_extn_synch_enable,
.aspm_init = ath_pci_aspm_init,
};
@@ -156,7 +161,6 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
struct ath_softc *sc;
struct ieee80211_hw *hw;
u8 csz;
- u16 subsysid;
u32 val;
int ret = 0;
char hw_name[64];
@@ -250,8 +254,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sc->irq = pdev->irq;
- pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid);
- ret = ath9k_init_device(id->device, sc, subsysid, &ath_pci_bus_ops);
+ ret = ath9k_init_device(id->device, sc, &ath_pci_bus_ops);
if (ret) {
dev_err(&pdev->dev, "Failed to initialize device\n");
goto err_init;
@@ -330,17 +333,17 @@ static int ath_pci_resume(struct device *device)
if ((val & 0x0000ff00) != 0)
pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
+ ath9k_ps_wakeup(sc);
/* Enable LED */
ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
+ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
/*
* Reset key cache to sane defaults (all entries cleared) instead of
* semi-random values after suspend/resume.
*/
- ath9k_ps_wakeup(sc);
- ath9k_init_crypto(sc);
+ ath9k_cmn_init_crypto(sc->sc_ah);
ath9k_ps_restore(sc);
sc->ps_idle = true;
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index c04a6c3cac7f..8448281dd069 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -603,7 +603,8 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv,
static u8 ath_rc_get_highest_rix(struct ath_softc *sc,
struct ath_rate_priv *ath_rc_priv,
const struct ath_rate_table *rate_table,
- int *is_probing)
+ int *is_probing,
+ bool legacy)
{
u32 best_thruput, this_thruput, now_msec;
u8 rate, next_rate, best_rate, maxindex, minindex;
@@ -624,6 +625,8 @@ static u8 ath_rc_get_highest_rix(struct ath_softc *sc,
u8 per_thres;
rate = ath_rc_priv->valid_rate_index[index];
+ if (legacy && !(rate_table->info[rate].rate_flags & RC_LEGACY))
+ continue;
if (rate > ath_rc_priv->rate_max_phy)
continue;
@@ -767,7 +770,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
struct ieee80211_tx_rate *rates = tx_info->control.rates;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
__le16 fc = hdr->frame_control;
- u8 try_per_rate, i = 0, rix;
+ u8 try_per_rate, i = 0, rix, high_rix;
int is_probe = 0;
if (rate_control_send_low(sta, priv_sta, txrc))
@@ -786,7 +789,9 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
try_per_rate = 4;
rate_table = ath_rc_priv->rate_table;
- rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe);
+ rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table,
+ &is_probe, false);
+ high_rix = rix;
/*
* If we're in HT mode and both us and our peer supports LDPC.
@@ -822,10 +827,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
}
/* Fill in the other rates for multirate retry */
- for ( ; i < 4; i++) {
- /* Use twice the number of tries for the last MRR segment. */
- if (i + 1 == 4)
- try_per_rate = 8;
+ for ( ; i < 3; i++) {
ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
/* All other rates in the series have RTS enabled */
@@ -833,6 +835,24 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
try_per_rate, rix, 1);
}
+ /* Use twice the number of tries for the last MRR segment. */
+ try_per_rate = 8;
+
+ /*
+ * Use a legacy rate as last retry to ensure that the frame
+ * is tried in both MCS and legacy rates.
+ */
+ if ((rates[2].flags & IEEE80211_TX_RC_MCS) &&
+ (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU) ||
+ (ath_rc_priv->per[high_rix] > 45)))
+ rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table,
+ &is_probe, true);
+ else
+ ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
+
+ /* All other rates in the series have RTS enabled */
+ ath_rc_rate_set_series(rate_table, &rates[i], txrc,
+ try_per_rate, rix, 1);
/*
* NB:Change rate series to enable aggregation when operating
* at lower MCS rates. When first rate in series is MCS2
@@ -1342,12 +1362,6 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED)
return;
- if (!(tx_info->flags & IEEE80211_TX_STAT_AMPDU)) {
- tx_info->status.ampdu_ack_len =
- (tx_info->flags & IEEE80211_TX_STAT_ACK ? 1 : 0);
- tx_info->status.ampdu_len = 1;
- }
-
if (!(tx_info->flags & IEEE80211_TX_STAT_ACK))
tx_status = 1;
@@ -1484,7 +1498,7 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
if (rc->rate_table == NULL)
return 0;
- max = 80 + rc->rate_table->rate_cnt * 1024 + 1;
+ max = 80 + rc->rate_table_size * 1024 + 1;
buf = kmalloc(max, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
@@ -1494,7 +1508,7 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
"HT", "MCS", "Rate",
"Success", "Retries", "XRetries", "PER");
- for (i = 0; i < rc->rate_table->rate_cnt; i++) {
+ for (i = 0; i < rc->rate_table_size; i++) {
u32 ratekbps = rc->rate_table->info[i].ratekbps;
struct ath_rc_stats *stats = &rc->rcstats[i];
char mcs[5];
diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h
index c3d850207bee..b7a4bcd3eec7 100644
--- a/drivers/net/wireless/ath/ath9k/rc.h
+++ b/drivers/net/wireless/ath/ath9k/rc.h
@@ -221,12 +221,6 @@ struct ath_rate_priv {
struct ath_rc_stats rcstats[RATE_TABLE_SIZE];
};
-enum ath9k_internal_frame_type {
- ATH9K_IFT_NOT_INTERNAL,
- ATH9K_IFT_PAUSE,
- ATH9K_IFT_UNPAUSE
-};
-
#ifdef CONFIG_ATH9K_RATE_CONTROL
int ath_rate_control_register(void);
void ath_rate_control_unregister(void);
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 9a4850154fb2..67b862cdae6d 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -205,14 +205,22 @@ static void ath_rx_remove_buffer(struct ath_softc *sc,
static void ath_rx_edma_cleanup(struct ath_softc *sc)
{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath_buf *bf;
ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP);
ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP);
list_for_each_entry(bf, &sc->rx.rxbuf, list) {
- if (bf->bf_mpdu)
+ if (bf->bf_mpdu) {
+ dma_unmap_single(sc->dev, bf->bf_buf_addr,
+ common->rx_bufsize,
+ DMA_BIDIRECTIONAL);
dev_kfree_skb_any(bf->bf_mpdu);
+ bf->bf_buf_addr = 0;
+ bf->bf_mpdu = NULL;
+ }
}
INIT_LIST_HEAD(&sc->rx.rxbuf);
@@ -425,12 +433,9 @@ void ath_rx_cleanup(struct ath_softc *sc)
u32 ath_calcrxfilter(struct ath_softc *sc)
{
-#define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR)
-
u32 rfilt;
- rfilt = (ath9k_hw_getrxfilter(sc->sc_ah) & RX_FILTER_PRESERVE)
- | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST
+ rfilt = ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST
| ATH9K_RX_FILTER_MCAST;
if (sc->rx.rxfilter & FIF_PROBE_REQ)
@@ -578,22 +583,11 @@ static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
{
- struct ieee80211_mgmt *mgmt;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
if (skb->len < 24 + 8 + 2 + 2)
return;
- mgmt = (struct ieee80211_mgmt *)skb->data;
- if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0) {
- /* TODO: This doesn't work well if you have stations
- * associated to two different APs because curbssid
- * is just the last AP that any of the stations associated
- * with.
- */
- return; /* not from our current AP */
- }
-
sc->ps_flags &= ~PS_WAIT_FOR_BEACON;
if (sc->ps_flags & PS_BEACON_SYNC) {
@@ -601,7 +595,6 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
ath_dbg(common, ATH_DBG_PS,
"Reconfigure Beacon timers based on timestamp from the AP\n");
ath_set_beacon(sc);
- sc->ps_flags &= ~PS_TSFOOR_SYNC;
}
if (ath_beacon_dtim_pending_cab(skb)) {
@@ -630,7 +623,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
}
}
-static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
+static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb, bool mybeacon)
{
struct ieee80211_hdr *hdr;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -639,7 +632,7 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
/* Process Beacon and CAB receive in PS state */
if (((sc->ps_flags & PS_WAIT_FOR_BEACON) || ath9k_check_auto_sleep(sc))
- && ieee80211_is_beacon(hdr->frame_control))
+ && mybeacon)
ath_rx_ps_beacon(sc, skb);
else if ((sc->ps_flags & PS_WAIT_FOR_CAB) &&
(ieee80211_is_data(hdr->frame_control) ||
@@ -762,7 +755,7 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc,
* on. All this is necessary because of our use of
* a self-linked list to avoid rx overruns.
*/
- ret = ath9k_hw_rxprocdesc(ah, ds, rs, 0);
+ ret = ath9k_hw_rxprocdesc(ah, ds, rs);
if (ret == -EINPROGRESS) {
struct ath_rx_status trs;
struct ath_buf *tbf;
@@ -788,7 +781,7 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc,
*/
tds = tbf->bf_desc;
- ret = ath9k_hw_rxprocdesc(ah, tds, &trs, 0);
+ ret = ath9k_hw_rxprocdesc(ah, tds, &trs);
if (ret == -EINPROGRESS)
return NULL;
}
@@ -815,6 +808,7 @@ static bool ath9k_rx_accept(struct ath_common *common,
struct ath_rx_status *rx_stats,
bool *decrypt_error)
{
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
bool is_mc, is_valid_tkip, strip_mic, mic_error;
struct ath_hw *ah = common->ah;
__le16 fc;
@@ -825,8 +819,10 @@ static bool ath9k_rx_accept(struct ath_common *common,
is_mc = !!is_multicast_ether_addr(hdr->addr1);
is_valid_tkip = rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID &&
test_bit(rx_stats->rs_keyix, common->tkip_keymap);
- strip_mic = is_valid_tkip && !(rx_stats->rs_status &
- (ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC));
+ strip_mic = is_valid_tkip && ieee80211_is_data(fc) &&
+ !(rx_stats->rs_status &
+ (ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC |
+ ATH9K_RXERR_KEYMISS));
if (!rx_stats->rs_datalen)
return false;
@@ -854,6 +850,8 @@ static bool ath9k_rx_accept(struct ath_common *common,
* descriptors.
*/
if (rx_stats->rs_status != 0) {
+ u8 status_mask;
+
if (rx_stats->rs_status & ATH9K_RXERR_CRC) {
rxs->flag |= RX_FLAG_FAILED_FCS_CRC;
mic_error = false;
@@ -861,7 +859,8 @@ static bool ath9k_rx_accept(struct ath_common *common,
if (rx_stats->rs_status & ATH9K_RXERR_PHY)
return false;
- if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) {
+ if ((rx_stats->rs_status & ATH9K_RXERR_DECRYPT) ||
+ (!is_mc && (rx_stats->rs_status & ATH9K_RXERR_KEYMISS))) {
*decrypt_error = true;
mic_error = false;
}
@@ -871,17 +870,14 @@ static bool ath9k_rx_accept(struct ath_common *common,
* decryption and MIC failures. For monitor mode,
* we also ignore the CRC error.
*/
- if (ah->is_monitoring) {
- if (rx_stats->rs_status &
- ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
- ATH9K_RXERR_CRC))
- return false;
- } else {
- if (rx_stats->rs_status &
- ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
- return false;
- }
- }
+ status_mask = ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
+ ATH9K_RXERR_KEYMISS;
+
+ if (ah->is_monitoring && (sc->rx.rxfilter & FIF_FCSFAIL))
+ status_mask |= ATH9K_RXERR_CRC;
+
+ if (rx_stats->rs_status & ~status_mask)
+ return false;
}
/*
@@ -937,7 +933,7 @@ static int ath9k_process_rate(struct ath_common *common,
* No valid hardware bitrate found -- we should not get here
* because hardware has already validated this frame as OK.
*/
- ath_dbg(common, ATH_DBG_XMIT,
+ ath_dbg(common, ATH_DBG_ANY,
"unsupported hw bitrate detected 0x%02x using 1 Mbit\n",
rx_stats->rs_rate);
@@ -952,22 +948,11 @@ static void ath9k_process_rssi(struct ath_common *common,
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = common->ah;
int last_rssi;
- __le16 fc;
- if ((ah->opmode != NL80211_IFTYPE_STATION) &&
- (ah->opmode != NL80211_IFTYPE_ADHOC))
- return;
-
- fc = hdr->frame_control;
- if (!ieee80211_is_beacon(fc) ||
- compare_ether_addr(hdr->addr3, common->curbssid)) {
- /* TODO: This doesn't work well if you have stations
- * associated to two different APs because curbssid
- * is just the last AP that any of the stations associated
- * with.
- */
+ if (!rx_stats->is_mybeacon ||
+ ((ah->opmode != NL80211_IFTYPE_STATION) &&
+ (ah->opmode != NL80211_IFTYPE_ADHOC)))
return;
- }
if (rx_stats->rs_rssi != ATH9K_RSSI_BAD && !rx_stats->rs_moreaggr)
ATH_RSSI_LPF(sc->last_rssi, rx_stats->rs_rssi);
@@ -995,6 +980,8 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common,
struct ieee80211_rx_status *rx_status,
bool *decrypt_error)
{
+ struct ath_hw *ah = common->ah;
+
memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
/*
@@ -1015,7 +1002,7 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common,
rx_status->band = hw->conf.channel->band;
rx_status->freq = hw->conf.channel->center_freq;
- rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi;
+ rx_status->signal = ah->noise + rx_stats->rs_rssi;
rx_status->antenna = rx_stats->rs_antenna;
rx_status->flag |= RX_FLAG_MACTIME_MPDU;
@@ -1783,11 +1770,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
struct ieee80211_rx_status *rxs;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
- /*
- * The hw can technically differ from common->hw when using ath9k
- * virtual wiphy so to account for that we iterate over the active
- * wiphys and find the appropriate wiphy and therefore hw.
- */
struct ieee80211_hw *hw = sc->hw;
struct ieee80211_hdr *hdr;
int retval;
@@ -1841,6 +1823,11 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
hdr = (struct ieee80211_hdr *) (hdr_skb->data + rx_status_len);
rxs = IEEE80211_SKB_RXCB(hdr_skb);
+ if (ieee80211_is_beacon(hdr->frame_control) &&
+ !compare_ether_addr(hdr->addr3, common->curbssid))
+ rs.is_mybeacon = true;
+ else
+ rs.is_mybeacon = false;
ath_debug_stat_rx(sc, &rs);
@@ -1848,7 +1835,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
* If we're asked to flush receive queue, directly
* chain it back at the queue without processing it.
*/
- if (flush)
+ if (sc->sc_flags & SC_OP_RXFLUSH)
goto requeue_drop_frag;
retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs,
@@ -1953,13 +1940,13 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
spin_lock_irqsave(&sc->sc_pm_lock, flags);
if ((sc->ps_flags & (PS_WAIT_FOR_BEACON |
- PS_WAIT_FOR_CAB |
- PS_WAIT_FOR_PSPOLL_DATA)) ||
- ath9k_check_auto_sleep(sc))
- ath_rx_ps(sc, skb);
+ PS_WAIT_FOR_CAB |
+ PS_WAIT_FOR_PSPOLL_DATA)) ||
+ ath9k_check_auto_sleep(sc))
+ ath_rx_ps(sc, skb, rs.is_mybeacon);
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
- if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)
+ if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx == 3)
ath_ant_comb_scan(sc, &rs);
ieee80211_rx(hw, skb);
@@ -1976,11 +1963,17 @@ requeue:
} else {
list_move_tail(&bf->list, &sc->rx.rxbuf);
ath_rx_buf_link(sc, bf);
- ath9k_hw_rxena(ah);
+ if (!flush)
+ ath9k_hw_rxena(ah);
}
} while (1);
spin_unlock_bh(&sc->rx.rxbuflock);
+ if (!(ah->imask & ATH9K_INT_RXEOL)) {
+ ah->imask |= (ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
+ ath9k_hw_set_interrupts(ah);
+ }
+
return 0;
}
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index fa4c0bbce6b9..8fcb7e9e8399 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -619,6 +619,7 @@
#define AR_D_GBL_IFS_EIFS 0x10b0
#define AR_D_GBL_IFS_EIFS_M 0x0000FFFF
#define AR_D_GBL_IFS_EIFS_RESV0 0xFFFF0000
+#define AR_D_GBL_IFS_EIFS_ASYNC_FIFO 363
#define AR_D_GBL_IFS_MISC 0x10f0
#define AR_D_GBL_IFS_MISC_LFSR_SLICE_SEL 0x00000007
@@ -793,14 +794,15 @@
#define AR_SREV_REVISION_9485_10 0
#define AR_SREV_REVISION_9485_11 1
#define AR_SREV_VERSION_9340 0x300
+#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) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE))
-#define AR_SREV_5416_20_OR_LATER(_ah) \
- (((AR_SREV_5416(_ah)) && \
- ((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_20)) || \
- ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9100))
#define AR_SREV_5416_22_OR_LATER(_ah) \
(((AR_SREV_5416(_ah)) && \
((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_22)) || \
@@ -893,6 +895,33 @@
(AR_SREV_9285_12_OR_LATER(_ah) && \
((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1))
+#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))
+
+#define AR_SREV_9462_20_OR_LATER(_ah) \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \
+ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9462_20))
+
+#define AR_SREV_9580(_ah) \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9580) && \
+ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9580_10))
+
+#define AR_SREV_9580_10(_ah) \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9580) && \
+ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9580_10))
+
+/* NOTE: When adding chips newer than Peacock, add chip check here */
+#define AR_SREV_9580_10_OR_LATER(_ah) \
+ (AR_SREV_9580(_ah))
+
enum ath_usb_dev {
AR9280_USB = 1, /* AR7010 + AR9280, UB94 */
AR9287_USB = 2, /* AR7010 + AR9287, UB95 */
@@ -1117,7 +1146,7 @@ enum {
#define AR_INTR_PRIO_ASYNC_ENABLE (AR_SREV_9340(ah) ? 0x4094 : 0x40d4)
#define AR_ENT_OTP 0x40d8
#define AR_ENT_OTP_CHAIN2_DISABLE 0x00020000
-#define AR_ENT_OTP_MPSD 0x00800000
+#define AR_ENT_OTP_MIN_PKT_SIZE_DISABLE 0x00800000
#define AR_CH0_BB_DPLL1 0x16180
#define AR_CH0_BB_DPLL1_REFDIV 0xF8000000
@@ -1489,6 +1518,7 @@ enum {
#define AR_USEC_TX_LAT_S 14
#define AR_USEC_RX_LAT 0x1F800000
#define AR_USEC_RX_LAT_S 23
+#define AR_USEC_ASYNC_FIFO 0x12E00074
#define AR_RESET_TSF 0x8020
#define AR_RESET_TSF_ONCE 0x01000000
@@ -1763,6 +1793,7 @@ enum {
#define AR_TXOP_12_15 0x81fc
#define AR_NEXT_NDP2_TIMER 0x8180
+#define AR_GEN_TIMER_BANK_1_LEN 8
#define AR_FIRST_NDP_TIMER 7
#define AR_NDP2_PERIOD 0x81a0
#define AR_NDP2_TIMER_MODE 0x81c0
@@ -1851,9 +1882,10 @@ enum {
#define AR_PCU_MISC_MODE2_HWWAR2 0x02000000
#define AR_PCU_MISC_MODE2_RESERVED2 0xFFFE0000
-#define AR_MAC_PCU_ASYNC_FIFO_REG3 0x8358
-#define AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL 0x00000400
-#define AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET 0x80000000
+#define AR_MAC_PCU_ASYNC_FIFO_REG3 0x8358
+#define AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL 0x00000400
+#define AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET 0x80000000
+#define AR_MAC_PCU_GEN_TIMER_TSF_SEL 0x83d8
#define AR_AES_MUTE_MASK0 0x805c
@@ -1901,7 +1933,42 @@ enum {
#define AR_PHY_AGC_CONTROL_NO_UPDATE_NF 0x00020000 /* don't update noise floor automatically */
#define AR_PHY_AGC_CONTROL_EXT_NF_PWR_MEAS 0x00040000 /* extend noise floor power measurement */
#define AR_PHY_AGC_CONTROL_CLC_SUCCESS 0x00080000 /* carrier leak calibration done */
+#define AR_PHY_AGC_CONTROL_PKDET_CAL 0x00100000
#define AR_PHY_AGC_CONTROL_YCOK_MAX 0x000003c0
#define AR_PHY_AGC_CONTROL_YCOK_MAX_S 6
+/* MCI Registers */
+#define AR_MCI_INTERRUPT_RX_MSG_EN 0x183c
+#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET 0x00000001
+#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET_S 0
+#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL 0x00000002
+#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL_S 1
+#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK 0x00000004
+#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK_S 2
+#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO 0x00000008
+#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO_S 3
+#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST 0x00000010
+#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST_S 4
+#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO 0x00000020
+#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO_S 5
+#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT 0x00000040
+#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT_S 6
+#define AR_MCI_INTERRUPT_RX_MSG_GPM 0x00000100
+#define AR_MCI_INTERRUPT_RX_MSG_GPM_S 8
+#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO 0x00000200
+#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO_S 9
+#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING 0x00000400
+#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING_S 10
+#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING 0x00000800
+#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING_S 11
+#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE 0x00001000
+#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE_S 12
+#define AR_MCI_INTERRUPT_RX_HW_MSG_MASK (AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO | \
+ AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL| \
+ AR_MCI_INTERRUPT_RX_MSG_LNA_INFO | \
+ AR_MCI_INTERRUPT_RX_MSG_CONT_NACK | \
+ AR_MCI_INTERRUPT_RX_MSG_CONT_INFO | \
+ AR_MCI_INTERRUPT_RX_MSG_CONT_RST)
+
+
#endif
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index cc595712f518..03b0a651a591 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -48,19 +48,23 @@ static u16 bits_per_symbol[][2] = {
#define IS_HT_RATE(_rate) ((_rate) & 0x80)
static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
- struct ath_atx_tid *tid,
- struct list_head *bf_head);
+ struct ath_atx_tid *tid, struct sk_buff *skb);
+static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
+ int tx_flags, struct ath_txq *txq);
static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
struct ath_txq *txq, struct list_head *bf_q,
struct ath_tx_status *ts, int txok, int sendbar);
static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
struct list_head *head, bool internal);
-static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len);
static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
struct ath_tx_status *ts, int nframes, int nbad,
- int txok, bool update_rc);
+ int txok);
static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
int seqno);
+static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
+ struct ath_txq *txq,
+ struct ath_atx_tid *tid,
+ struct sk_buff *skb);
enum {
MCS_HT20,
@@ -129,7 +133,7 @@ static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
spin_lock_bh(&txq->axq_lock);
tid->paused = false;
- if (list_empty(&tid->buf_q))
+ if (skb_queue_empty(&tid->buf_q))
goto unlock;
ath_tx_queue_tid(txq, tid);
@@ -149,6 +153,7 @@ static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
{
struct ath_txq *txq = tid->ac->txq;
+ struct sk_buff *skb;
struct ath_buf *bf;
struct list_head bf_head;
struct ath_tx_status ts;
@@ -159,17 +164,17 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
memset(&ts, 0, sizeof(ts));
spin_lock_bh(&txq->axq_lock);
- while (!list_empty(&tid->buf_q)) {
- bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
- list_move_tail(&bf->list, &bf_head);
+ while ((skb = __skb_dequeue(&tid->buf_q))) {
+ fi = get_frame_info(skb);
+ bf = fi->bf;
spin_unlock_bh(&txq->axq_lock);
- fi = get_frame_info(bf->bf_mpdu);
- if (fi->retries) {
- ath_tx_update_baw(sc, tid, fi->seqno);
+ if (bf && fi->retries) {
+ list_add_tail(&bf->list, &bf_head);
+ ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 1);
} else {
- ath_tx_send_normal(sc, txq, NULL, &bf_head);
+ ath_tx_send_normal(sc, txq, NULL, skb);
}
spin_lock_bh(&txq->axq_lock);
}
@@ -219,6 +224,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid)
{
+ struct sk_buff *skb;
struct ath_buf *bf;
struct list_head bf_head;
struct ath_tx_status ts;
@@ -227,16 +233,21 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
memset(&ts, 0, sizeof(ts));
INIT_LIST_HEAD(&bf_head);
- for (;;) {
- if (list_empty(&tid->buf_q))
- break;
+ while ((skb = __skb_dequeue(&tid->buf_q))) {
+ fi = get_frame_info(skb);
+ bf = fi->bf;
- bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
- list_move_tail(&bf->list, &bf_head);
+ if (!bf) {
+ spin_unlock(&txq->axq_lock);
+ ath_tx_complete(sc, skb, ATH_TX_ERROR, txq);
+ spin_lock(&txq->axq_lock);
+ continue;
+ }
+
+ list_add_tail(&bf->list, &bf_head);
- fi = get_frame_info(bf->bf_mpdu);
if (fi->retries)
- ath_tx_update_baw(sc, tid, fi->seqno);
+ ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
spin_unlock(&txq->axq_lock);
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
@@ -251,6 +262,7 @@ static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
struct sk_buff *skb)
{
struct ath_frame_info *fi = get_frame_info(skb);
+ struct ath_buf *bf = fi->bf;
struct ieee80211_hdr *hdr;
TX_STAT_INC(txq->axq_qnum, a_retries);
@@ -259,6 +271,8 @@ static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
hdr = (struct ieee80211_hdr *)skb->data;
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY);
+ dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
+ sizeof(*hdr), DMA_TO_DEVICE);
}
static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
@@ -326,7 +340,7 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
while (bf) {
fi = get_frame_info(bf->bf_mpdu);
- ba_index = ATH_BA_INDEX(seq_st, fi->seqno);
+ ba_index = ATH_BA_INDEX(seq_st, bf->bf_state.seqno);
(*nframes)++;
if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
@@ -349,7 +363,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ieee80211_tx_info *tx_info;
struct ath_atx_tid *tid = NULL;
struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
- struct list_head bf_head, bf_pending;
+ struct list_head bf_head;
+ struct sk_buff_head bf_pending;
u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0;
u32 ba[WME_BA_BMP_SIZE >> 5];
int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
@@ -358,7 +373,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ath_frame_info *fi;
int nframes;
u8 tidno;
- bool clear_filter;
+ bool flush = !!(ts->ts_status & ATH9K_TX_FLUSH);
skb = bf->bf_mpdu;
hdr = (struct ieee80211_hdr *)skb->data;
@@ -377,11 +392,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
while (bf) {
bf_next = bf->bf_next;
- bf->bf_state.bf_type |= BUF_XRETRY;
if (!bf->bf_stale || bf_next != NULL)
list_move_tail(&bf->list, &bf_head);
- ath_tx_rc_status(sc, bf, ts, 1, 1, 0, false);
ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
0, 0);
@@ -422,11 +435,12 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
}
}
- INIT_LIST_HEAD(&bf_pending);
- INIT_LIST_HEAD(&bf_head);
+ __skb_queue_head_init(&bf_pending);
ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad);
while (bf) {
+ u16 seqno = bf->bf_state.seqno;
+
txfail = txpending = sendbar = 0;
bf_next = bf->bf_next;
@@ -434,7 +448,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
tx_info = IEEE80211_SKB_CB(skb);
fi = get_frame_info(skb);
- if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, fi->seqno))) {
+ if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, seqno))) {
/* transmit completion, subframe is
* acked by block ack */
acked_cnt++;
@@ -448,15 +462,14 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
* the un-acked sub-frames
*/
txfail = 1;
+ } else if (flush) {
+ txpending = 1;
} else if (fi->retries < ATH_MAX_SW_RETRIES) {
- if (!(ts->ts_status & ATH9K_TXERR_FILT) ||
- !an->sleeping)
+ if (txok || !an->sleeping)
ath_tx_set_retry(sc, txq, bf->bf_mpdu);
- clear_filter = true;
txpending = 1;
} else {
- bf->bf_state.bf_type |= BUF_XRETRY;
txfail = 1;
sendbar = 1;
txfail_cnt++;
@@ -467,10 +480,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
* Make sure the last desc is reclaimed if it
* not a holding desc.
*/
- if (!bf_last->bf_stale || bf_next != NULL)
+ INIT_LIST_HEAD(&bf_head);
+ if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ||
+ bf_next != NULL || !bf_last->bf_stale)
list_move_tail(&bf->list, &bf_head);
- else
- INIT_LIST_HEAD(&bf_head);
if (!txpending || (tid->state & AGGR_CLEANUP)) {
/*
@@ -478,22 +491,19 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
* block-ack window
*/
spin_lock_bh(&txq->axq_lock);
- ath_tx_update_baw(sc, tid, fi->seqno);
+ ath_tx_update_baw(sc, tid, seqno);
spin_unlock_bh(&txq->axq_lock);
if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
memcpy(tx_info->control.rates, rates, sizeof(rates));
- ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok, true);
+ ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok);
rc_update = false;
- } else {
- ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok, false);
}
ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
!txfail, sendbar);
} else {
/* retry the un-acked ones */
- ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, false);
if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
if (bf->bf_next == NULL && bf_last->bf_stale) {
struct ath_buf *tbf;
@@ -506,29 +516,17 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
*/
if (!tbf) {
spin_lock_bh(&txq->axq_lock);
- ath_tx_update_baw(sc, tid, fi->seqno);
+ ath_tx_update_baw(sc, tid, seqno);
spin_unlock_bh(&txq->axq_lock);
- bf->bf_state.bf_type |=
- BUF_XRETRY;
- ath_tx_rc_status(sc, bf, ts, nframes,
- nbad, 0, false);
ath_tx_complete_buf(sc, bf, txq,
&bf_head,
- ts, 0, 0);
+ ts, 0,
+ !flush);
break;
}
- ath9k_hw_cleartxdesc(sc->sc_ah,
- tbf->bf_desc);
- list_add_tail(&tbf->list, &bf_head);
- } else {
- /*
- * Clear descriptor status words for
- * software retry
- */
- ath9k_hw_cleartxdesc(sc->sc_ah,
- bf->bf_desc);
+ fi->bf = tbf;
}
}
@@ -536,22 +534,25 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
* Put this buffer to the temporary pending
* queue to retain ordering
*/
- list_splice_tail_init(&bf_head, &bf_pending);
+ __skb_queue_tail(&bf_pending, skb);
}
bf = bf_next;
}
/* prepend un-acked frames to the beginning of the pending frame queue */
- if (!list_empty(&bf_pending)) {
+ if (!skb_queue_empty(&bf_pending)) {
if (an->sleeping)
- ieee80211_sta_set_tim(sta);
+ ieee80211_sta_set_buffered(sta, tid->tidno, true);
spin_lock_bh(&txq->axq_lock);
- if (clear_filter)
- tid->ac->clear_ps_filter = true;
- list_splice(&bf_pending, &tid->buf_q);
- ath_tx_queue_tid(txq, tid);
+ skb_queue_splice(&bf_pending, &tid->buf_q);
+ if (!an->sleeping) {
+ ath_tx_queue_tid(txq, tid);
+
+ if (ts->ts_status & ATH9K_TXERR_FILT)
+ tid->ac->clear_ps_filter = true;
+ }
spin_unlock_bh(&txq->axq_lock);
}
@@ -566,8 +567,32 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
rcu_read_unlock();
- if (needreset)
- ath_reset(sc, false);
+ if (needreset) {
+ RESET_STAT_INC(sc, RESET_TYPE_TX_ERROR);
+ ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
+ }
+}
+
+static bool ath_lookup_legacy(struct ath_buf *bf)
+{
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *tx_info;
+ struct ieee80211_tx_rate *rates;
+ int i;
+
+ skb = bf->bf_mpdu;
+ tx_info = IEEE80211_SKB_CB(skb);
+ rates = tx_info->control.rates;
+
+ for (i = 0; i < 4; i++) {
+ if (!rates[i].count || rates[i].idx < 0)
+ break;
+
+ if (!(rates[i].flags & IEEE80211_TX_RC_MCS))
+ return true;
+ }
+
+ return false;
}
static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
@@ -643,8 +668,10 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
* meet the minimum required mpdudensity.
*/
static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
- struct ath_buf *bf, u16 frmlen)
+ struct ath_buf *bf, u16 frmlen,
+ bool first_subfrm)
{
+#define FIRST_DESC_NDELIMS 60
struct sk_buff *skb = bf->bf_mpdu;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
u32 nsymbits, nsymbols;
@@ -667,6 +694,14 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
ndelim += ATH_AGGR_ENCRYPTDELIM;
/*
+ * Add delimiter when using RTS/CTS with aggregation
+ * and non enterprise AR9003 card
+ */
+ if (first_subfrm && !AR_SREV_9580_10_OR_LATER(sc->sc_ah) &&
+ (sc->sc_ah->ent_mode & AR_ENT_OTP_MIN_PKT_SIZE_DISABLE))
+ ndelim = max(ndelim, FIRST_DESC_NDELIMS);
+
+ /*
* Convert desired mpdu density from microeconds to bytes based
* on highest rate in rate series (i.e. first rate) to determine
* required minimum length for subframe. Take into account
@@ -711,22 +746,33 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
int *aggr_len)
{
#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
- struct ath_buf *bf, *bf_first, *bf_prev = NULL;
+ struct ath_buf *bf, *bf_first = NULL, *bf_prev = NULL;
int rl = 0, nframes = 0, ndelim, prev_al = 0;
u16 aggr_limit = 0, al = 0, bpad = 0,
al_delta, h_baw = tid->baw_size / 2;
enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
struct ieee80211_tx_info *tx_info;
struct ath_frame_info *fi;
-
- bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
+ struct sk_buff *skb;
+ u16 seqno;
do {
- bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
- fi = get_frame_info(bf->bf_mpdu);
+ skb = skb_peek(&tid->buf_q);
+ fi = get_frame_info(skb);
+ bf = fi->bf;
+ if (!fi->bf)
+ bf = ath_tx_setup_buffer(sc, txq, tid, skb);
+
+ if (!bf)
+ continue;
+
+ bf->bf_state.bf_type = BUF_AMPDU | BUF_AGGR;
+ seqno = bf->bf_state.seqno;
+ if (!bf_first)
+ bf_first = bf;
/* do not step over block-ack window */
- if (!BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno)) {
+ if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
status = ATH_AGGR_BAW_CLOSED;
break;
}
@@ -740,14 +786,14 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
al_delta = ATH_AGGR_DELIM_SZ + fi->framelen;
if (nframes &&
- (aggr_limit < (al + bpad + al_delta + prev_al))) {
+ ((aggr_limit < (al + bpad + al_delta + prev_al)) ||
+ ath_lookup_legacy(bf))) {
status = ATH_AGGR_LIMITED;
break;
}
tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
- if (nframes && ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
- !(tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS)))
+ if (nframes && (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE))
break;
/* do not exceed subframe limit */
@@ -755,7 +801,6 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
status = ATH_AGGR_LIMITED;
break;
}
- nframes++;
/* add padding for previous frame to aggregation length */
al += bpad + al_delta;
@@ -764,25 +809,26 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
* Get the delimiters needed to meet the MPDU
* density for this node.
*/
- ndelim = ath_compute_num_delims(sc, tid, bf_first, fi->framelen);
+ ndelim = ath_compute_num_delims(sc, tid, bf_first, fi->framelen,
+ !nframes);
bpad = PADBYTES(al_delta) + (ndelim << 2);
+ nframes++;
bf->bf_next = NULL;
- ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
/* link buffers of this frame to the aggregate */
if (!fi->retries)
- ath_tx_addto_baw(sc, tid, fi->seqno);
- ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim);
- list_move_tail(&bf->list, bf_q);
- if (bf_prev) {
+ ath_tx_addto_baw(sc, tid, seqno);
+ bf->bf_state.ndelim = ndelim;
+
+ __skb_unlink(skb, &tid->buf_q);
+ list_add_tail(&bf->list, bf_q);
+ if (bf_prev)
bf_prev->bf_next = bf;
- ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc,
- bf->bf_daddr);
- }
+
bf_prev = bf;
- } while (!list_empty(&tid->buf_q));
+ } while (!skb_queue_empty(&tid->buf_q));
*aggr_len = al;
@@ -790,17 +836,236 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
#undef PADBYTES
}
+/*
+ * rix - rate index
+ * pktlen - total bytes (delims + data + fcs + pads + pad delims)
+ * width - 0 for 20 MHz, 1 for 40 MHz
+ * half_gi - to use 4us v/s 3.6 us for symbol time
+ */
+static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen,
+ int width, int half_gi, bool shortPreamble)
+{
+ u32 nbits, nsymbits, duration, nsymbols;
+ int streams;
+
+ /* find number of symbols: PLCP + data */
+ streams = HT_RC_2_STREAMS(rix);
+ nbits = (pktlen << 3) + OFDM_PLCP_BITS;
+ nsymbits = bits_per_symbol[rix % 8][width] * streams;
+ nsymbols = (nbits + nsymbits - 1) / nsymbits;
+
+ if (!half_gi)
+ duration = SYMBOL_TIME(nsymbols);
+ else
+ duration = SYMBOL_TIME_HALFGI(nsymbols);
+
+ /* addup duration for legacy/ht training and signal fields */
+ duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
+
+ return duration;
+}
+
+static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
+ struct ath_tx_info *info, int len)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *tx_info;
+ struct ieee80211_tx_rate *rates;
+ const struct ieee80211_rate *rate;
+ struct ieee80211_hdr *hdr;
+ int i;
+ u8 rix = 0;
+
+ skb = bf->bf_mpdu;
+ tx_info = IEEE80211_SKB_CB(skb);
+ rates = tx_info->control.rates;
+ hdr = (struct ieee80211_hdr *)skb->data;
+
+ /* set dur_update_en for l-sig computation except for PS-Poll frames */
+ info->dur_update = !ieee80211_is_pspoll(hdr->frame_control);
+
+ /*
+ * We check if Short Preamble is needed for the CTS rate by
+ * checking the BSS's global flag.
+ * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
+ */
+ rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
+ info->rtscts_rate = rate->hw_value;
+ if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
+ info->rtscts_rate |= rate->hw_value_short;
+
+ for (i = 0; i < 4; i++) {
+ bool is_40, is_sgi, is_sp;
+ int phy;
+
+ if (!rates[i].count || (rates[i].idx < 0))
+ continue;
+
+ rix = rates[i].idx;
+ info->rates[i].Tries = rates[i].count;
+
+ if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
+ info->rates[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
+ info->flags |= ATH9K_TXDESC_RTSENA;
+ } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+ info->rates[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
+ info->flags |= ATH9K_TXDESC_CTSENA;
+ }
+
+ if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ info->rates[i].RateFlags |= ATH9K_RATESERIES_2040;
+ if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
+ info->rates[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
+
+ is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
+ is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
+ is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
+
+ if (rates[i].flags & IEEE80211_TX_RC_MCS) {
+ /* MCS rates */
+ info->rates[i].Rate = rix | 0x80;
+ info->rates[i].ChSel = ath_txchainmask_reduction(sc,
+ ah->txchainmask, info->rates[i].Rate);
+ info->rates[i].PktDuration = ath_pkt_duration(sc, rix, len,
+ is_40, is_sgi, is_sp);
+ if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
+ info->rates[i].RateFlags |= ATH9K_RATESERIES_STBC;
+ continue;
+ }
+
+ /* legacy rates */
+ if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
+ !(rate->flags & IEEE80211_RATE_ERP_G))
+ phy = WLAN_RC_PHY_CCK;
+ else
+ phy = WLAN_RC_PHY_OFDM;
+
+ rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
+ info->rates[i].Rate = rate->hw_value;
+ if (rate->hw_value_short) {
+ if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
+ info->rates[i].Rate |= rate->hw_value_short;
+ } else {
+ is_sp = false;
+ }
+
+ if (bf->bf_state.bfs_paprd)
+ info->rates[i].ChSel = ah->txchainmask;
+ else
+ info->rates[i].ChSel = ath_txchainmask_reduction(sc,
+ ah->txchainmask, info->rates[i].Rate);
+
+ info->rates[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
+ phy, rate->bitrate * 100, len, rix, is_sp);
+ }
+
+ /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
+ if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit))
+ info->flags &= ~ATH9K_TXDESC_RTSENA;
+
+ /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
+ if (info->flags & ATH9K_TXDESC_RTSENA)
+ info->flags &= ~ATH9K_TXDESC_CTSENA;
+}
+
+static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr;
+ enum ath9k_pkt_type htype;
+ __le16 fc;
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ fc = hdr->frame_control;
+
+ if (ieee80211_is_beacon(fc))
+ htype = ATH9K_PKT_TYPE_BEACON;
+ else if (ieee80211_is_probe_resp(fc))
+ htype = ATH9K_PKT_TYPE_PROBE_RESP;
+ else if (ieee80211_is_atim(fc))
+ htype = ATH9K_PKT_TYPE_ATIM;
+ else if (ieee80211_is_pspoll(fc))
+ htype = ATH9K_PKT_TYPE_PSPOLL;
+ else
+ htype = ATH9K_PKT_TYPE_NORMAL;
+
+ return htype;
+}
+
+static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
+ struct ath_txq *txq, int len)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
+ struct ath_buf *bf_first = bf;
+ struct ath_tx_info info;
+ bool aggr = !!(bf->bf_state.bf_type & BUF_AGGR);
+
+ memset(&info, 0, sizeof(info));
+ info.is_first = true;
+ info.is_last = true;
+ info.txpower = MAX_RATE_POWER;
+ info.qcu = txq->axq_qnum;
+
+ info.flags = ATH9K_TXDESC_INTREQ;
+ if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
+ info.flags |= ATH9K_TXDESC_NOACK;
+ if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
+ info.flags |= ATH9K_TXDESC_LDPC;
+
+ ath_buf_set_rate(sc, bf, &info, len);
+
+ if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
+ info.flags |= ATH9K_TXDESC_CLRDMASK;
+
+ if (bf->bf_state.bfs_paprd)
+ info.flags |= (u32) bf->bf_state.bfs_paprd << ATH9K_TXDESC_PAPRD_S;
+
+
+ while (bf) {
+ struct sk_buff *skb = bf->bf_mpdu;
+ struct ath_frame_info *fi = get_frame_info(skb);
+
+ info.type = get_hw_packet_type(skb);
+ if (bf->bf_next)
+ info.link = bf->bf_next->bf_daddr;
+ else
+ info.link = 0;
+
+ info.buf_addr[0] = bf->bf_buf_addr;
+ info.buf_len[0] = skb->len;
+ info.pkt_len = fi->framelen;
+ info.keyix = fi->keyix;
+ info.keytype = fi->keytype;
+
+ if (aggr) {
+ if (bf == bf_first)
+ info.aggr = AGGR_BUF_FIRST;
+ else if (!bf->bf_next)
+ info.aggr = AGGR_BUF_LAST;
+ else
+ info.aggr = AGGR_BUF_MIDDLE;
+
+ info.ndelim = bf->bf_state.ndelim;
+ info.aggr_len = len;
+ }
+
+ ath9k_hw_set_txdesc(ah, bf->bf_desc, &info);
+ bf = bf->bf_next;
+ }
+}
+
static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid)
{
struct ath_buf *bf;
enum ATH_AGGR_STATUS status;
- struct ath_frame_info *fi;
+ struct ieee80211_tx_info *tx_info;
struct list_head bf_q;
int aggr_len;
do {
- if (list_empty(&tid->buf_q))
+ if (skb_queue_empty(&tid->buf_q))
return;
INIT_LIST_HEAD(&bf_q);
@@ -816,34 +1081,25 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
bf = list_first_entry(&bf_q, struct ath_buf, list);
bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
+ tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
if (tid->ac->clear_ps_filter) {
tid->ac->clear_ps_filter = false;
- ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
+ tx_info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
+ } else {
+ tx_info->flags &= ~IEEE80211_TX_CTL_CLEAR_PS_FILT;
}
/* if only one frame, send as non-aggregate */
if (bf == bf->bf_lastbf) {
- fi = get_frame_info(bf->bf_mpdu);
-
- bf->bf_state.bf_type &= ~BUF_AGGR;
- ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
- ath_buf_set_rate(sc, bf, fi->framelen);
- ath_tx_txqaddbuf(sc, txq, &bf_q, false);
- continue;
+ aggr_len = get_frame_info(bf->bf_mpdu)->framelen;
+ bf->bf_state.bf_type = BUF_AMPDU;
+ } else {
+ TX_STAT_INC(txq->axq_qnum, a_aggr);
}
- /* setup first desc of aggregate */
- bf->bf_state.bf_type |= BUF_AGGR;
- ath_buf_set_rate(sc, bf, aggr_len);
- ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, aggr_len);
-
- /* anchor last desc of aggregate */
- ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
-
+ ath_tx_fill_desc(sc, bf, txq, aggr_len);
ath_tx_txqaddbuf(sc, txq, &bf_q, false);
- TX_STAT_INC(txq->axq_qnum, a_aggr);
-
} while (txq->axq_ampdu_depth < ATH_AGGR_MIN_QDEPTH &&
status != ATH_AGGR_BAW_CLOSED);
}
@@ -902,12 +1158,13 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
ath_tx_flush_tid(sc, txtid);
}
-bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
+void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
+ struct ath_node *an)
{
struct ath_atx_tid *tid;
struct ath_atx_ac *ac;
struct ath_txq *txq;
- bool buffered = false;
+ bool buffered;
int tidno;
for (tidno = 0, tid = &an->tid[tidno];
@@ -921,8 +1178,7 @@ bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
spin_lock_bh(&txq->axq_lock);
- if (!list_empty(&tid->buf_q))
- buffered = true;
+ buffered = !skb_queue_empty(&tid->buf_q);
tid->sched = false;
list_del(&tid->list);
@@ -933,9 +1189,9 @@ bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
}
spin_unlock_bh(&txq->axq_lock);
- }
- return buffered;
+ ieee80211_sta_set_buffered(sta, tidno, buffered);
+ }
}
void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
@@ -954,7 +1210,7 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
spin_lock_bh(&txq->axq_lock);
ac->clear_ps_filter = true;
- if (!list_empty(&tid->buf_q) && !tid->paused) {
+ if (!skb_queue_empty(&tid->buf_q) && !tid->paused) {
ath_tx_queue_tid(txq, tid);
ath_txq_schedule(sc, txq);
}
@@ -1004,7 +1260,6 @@ static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
{
struct ath_hw *ah = sc->sc_ah;
- struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_tx_queue_info qi;
static const int subtype_txq_to_hwq[] = {
[WME_AC_BE] = ATH_TXQ_AC_BE,
@@ -1054,12 +1309,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
*/
return NULL;
}
- if (axq_qnum >= ARRAY_SIZE(sc->tx.txq)) {
- ath_err(common, "qnum %u out of range, max %zu!\n",
- axq_qnum, ARRAY_SIZE(sc->tx.txq));
- ath9k_hw_releasetxqueue(ah, axq_qnum);
- return NULL;
- }
if (!ATH_TXQ_SETUP(sc, axq_qnum)) {
struct ath_txq *txq = &sc->tx.txq[axq_qnum];
@@ -1156,6 +1405,7 @@ static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq,
struct ath_tx_status ts;
memset(&ts, 0, sizeof(ts));
+ ts.ts_status = ATH9K_TX_FLUSH;
INIT_LIST_HEAD(&bf_head);
while (!list_empty(list)) {
@@ -1222,7 +1472,8 @@ bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_txq *txq;
- int i, npend = 0;
+ int i;
+ u32 npend = 0;
if (sc->sc_flags & SC_OP_INVALID)
return true;
@@ -1234,11 +1485,12 @@ bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
if (!ATH_TXQ_SETUP(sc, i))
continue;
- npend += ath9k_hw_numtxpending(ah, sc->tx.txq[i].axq_qnum);
+ if (ath9k_hw_numtxpending(ah, sc->tx.txq[i].axq_qnum))
+ npend |= BIT(i);
}
if (npend)
- ath_err(common, "Failed to stop TX DMA!\n");
+ ath_err(common, "Failed to stop TX DMA, queues=0x%03x!\n", npend);
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
if (!ATH_TXQ_SETUP(sc, i))
@@ -1271,7 +1523,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
struct ath_atx_ac *ac, *ac_tmp, *last_ac;
struct ath_atx_tid *tid, *last_tid;
- if (list_empty(&txq->axq_acq) ||
+ if (work_pending(&sc->hw_reset_work) || list_empty(&txq->axq_acq) ||
txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
return;
@@ -1298,7 +1550,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
* add tid to round-robin queue if more frames
* are pending for the tid
*/
- if (!list_empty(&tid->buf_q))
+ if (!skb_queue_empty(&tid->buf_q))
ath_tx_queue_tid(txq, tid);
if (tid == last_tid ||
@@ -1390,12 +1642,11 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
}
static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
- struct ath_buf *bf, struct ath_tx_control *txctl)
+ struct sk_buff *skb, struct ath_tx_control *txctl)
{
- struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
+ struct ath_frame_info *fi = get_frame_info(skb);
struct list_head bf_head;
-
- bf->bf_state.bf_type |= BUF_AMPDU;
+ struct ath_buf *bf;
/*
* Do not queue to h/w when any of the following conditions is true:
@@ -1404,113 +1655,82 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
* - seqno is not within block-ack window
* - h/w queue depth exceeds low water mark
*/
- if (!list_empty(&tid->buf_q) || tid->paused ||
- !BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno) ||
+ if (!skb_queue_empty(&tid->buf_q) || tid->paused ||
+ !BAW_WITHIN(tid->seq_start, tid->baw_size, tid->seq_next) ||
txctl->txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) {
/*
* Add this frame to software queue for scheduling later
* for aggregation.
*/
TX_STAT_INC(txctl->txq->axq_qnum, a_queued_sw);
- list_add_tail(&bf->list, &tid->buf_q);
- ath_tx_queue_tid(txctl->txq, tid);
+ __skb_queue_tail(&tid->buf_q, skb);
+ if (!txctl->an || !txctl->an->sleeping)
+ ath_tx_queue_tid(txctl->txq, tid);
return;
}
+ bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb);
+ if (!bf)
+ return;
+
+ bf->bf_state.bf_type = BUF_AMPDU;
INIT_LIST_HEAD(&bf_head);
list_add(&bf->list, &bf_head);
/* Add sub-frame to BAW */
- if (!fi->retries)
- ath_tx_addto_baw(sc, tid, fi->seqno);
+ ath_tx_addto_baw(sc, tid, bf->bf_state.seqno);
/* Queue to h/w without aggregation */
TX_STAT_INC(txctl->txq->axq_qnum, a_queued_hw);
bf->bf_lastbf = bf;
- ath_buf_set_rate(sc, bf, fi->framelen);
+ ath_tx_fill_desc(sc, bf, txctl->txq, fi->framelen);
ath_tx_txqaddbuf(sc, txctl->txq, &bf_head, false);
}
static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
- struct ath_atx_tid *tid,
- struct list_head *bf_head)
+ struct ath_atx_tid *tid, struct sk_buff *skb)
{
- struct ath_frame_info *fi;
+ struct ath_frame_info *fi = get_frame_info(skb);
+ struct list_head bf_head;
struct ath_buf *bf;
- bf = list_first_entry(bf_head, struct ath_buf, list);
- bf->bf_state.bf_type &= ~BUF_AMPDU;
+ bf = fi->bf;
+ if (!bf)
+ bf = ath_tx_setup_buffer(sc, txq, tid, skb);
+
+ if (!bf)
+ return;
+
+ INIT_LIST_HEAD(&bf_head);
+ list_add_tail(&bf->list, &bf_head);
+ bf->bf_state.bf_type = 0;
/* update starting sequence number for subsequent ADDBA request */
if (tid)
INCR(tid->seq_start, IEEE80211_SEQ_MAX);
bf->bf_lastbf = bf;
- fi = get_frame_info(bf->bf_mpdu);
- ath_buf_set_rate(sc, bf, fi->framelen);
- ath_tx_txqaddbuf(sc, txq, bf_head, false);
+ ath_tx_fill_desc(sc, bf, txq, fi->framelen);
+ ath_tx_txqaddbuf(sc, txq, &bf_head, false);
TX_STAT_INC(txq->axq_qnum, queued);
}
-static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
-{
- struct ieee80211_hdr *hdr;
- enum ath9k_pkt_type htype;
- __le16 fc;
-
- hdr = (struct ieee80211_hdr *)skb->data;
- fc = hdr->frame_control;
-
- if (ieee80211_is_beacon(fc))
- htype = ATH9K_PKT_TYPE_BEACON;
- else if (ieee80211_is_probe_resp(fc))
- htype = ATH9K_PKT_TYPE_PROBE_RESP;
- else if (ieee80211_is_atim(fc))
- htype = ATH9K_PKT_TYPE_ATIM;
- else if (ieee80211_is_pspoll(fc))
- htype = ATH9K_PKT_TYPE_PSPOLL;
- else
- htype = ATH9K_PKT_TYPE_NORMAL;
-
- return htype;
-}
-
static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
int framelen)
{
- struct ath_softc *sc = hw->priv;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_sta *sta = tx_info->control.sta;
struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ath_frame_info *fi = get_frame_info(skb);
struct ath_node *an = NULL;
- struct ath_atx_tid *tid;
enum ath9k_key_type keytype;
- u16 seqno = 0;
- u8 tidno;
keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
if (sta)
an = (struct ath_node *) sta->drv_priv;
- hdr = (struct ieee80211_hdr *)skb->data;
- if (an && ieee80211_is_data_qos(hdr->frame_control) &&
- conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) {
-
- tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
-
- /*
- * Override seqno set by upper layer with the one
- * in tx aggregation state.
- */
- tid = ATH_AN_2_TID(an, tidno);
- seqno = tid->seq_next;
- hdr->seq_ctrl = cpu_to_le16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
- INCR(tid->seq_next, IEEE80211_SEQ_MAX);
- }
-
memset(fi, 0, sizeof(*fi));
if (hw_key)
fi->keyix = hw_key->hw_key_idx;
@@ -1520,199 +1740,50 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
fi->keyix = ATH9K_TXKEYIX_INVALID;
fi->keytype = keytype;
fi->framelen = framelen;
- fi->seqno = seqno;
-}
-
-static int setup_tx_flags(struct sk_buff *skb)
-{
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- int flags = 0;
-
- flags |= ATH9K_TXDESC_INTREQ;
-
- if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
- flags |= ATH9K_TXDESC_NOACK;
-
- if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
- flags |= ATH9K_TXDESC_LDPC;
-
- return flags;
-}
-
-/*
- * rix - rate index
- * pktlen - total bytes (delims + data + fcs + pads + pad delims)
- * width - 0 for 20 MHz, 1 for 40 MHz
- * half_gi - to use 4us v/s 3.6 us for symbol time
- */
-static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen,
- int width, int half_gi, bool shortPreamble)
-{
- u32 nbits, nsymbits, duration, nsymbols;
- int streams;
-
- /* find number of symbols: PLCP + data */
- streams = HT_RC_2_STREAMS(rix);
- nbits = (pktlen << 3) + OFDM_PLCP_BITS;
- nsymbits = bits_per_symbol[rix % 8][width] * streams;
- nsymbols = (nbits + nsymbits - 1) / nsymbits;
-
- if (!half_gi)
- duration = SYMBOL_TIME(nsymbols);
- else
- duration = SYMBOL_TIME_HALFGI(nsymbols);
-
- /* addup duration for legacy/ht training and signal fields */
- duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
-
- return duration;
}
u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate)
{
struct ath_hw *ah = sc->sc_ah;
struct ath9k_channel *curchan = ah->curchan;
- if ((sc->sc_flags & SC_OP_ENABLE_APM) &&
- (curchan->channelFlags & CHANNEL_5GHZ) &&
- (chainmask == 0x7) && (rate < 0x90))
+ if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) &&
+ (curchan->channelFlags & CHANNEL_5GHZ) &&
+ (chainmask == 0x7) && (rate < 0x90))
return 0x3;
else
return chainmask;
}
-static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
-{
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- struct ath9k_11n_rate_series series[4];
- struct sk_buff *skb;
- struct ieee80211_tx_info *tx_info;
- struct ieee80211_tx_rate *rates;
- const struct ieee80211_rate *rate;
- struct ieee80211_hdr *hdr;
- int i, flags = 0;
- u8 rix = 0, ctsrate = 0;
- bool is_pspoll;
-
- memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
-
- skb = bf->bf_mpdu;
- tx_info = IEEE80211_SKB_CB(skb);
- rates = tx_info->control.rates;
- hdr = (struct ieee80211_hdr *)skb->data;
- is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
-
- /*
- * We check if Short Preamble is needed for the CTS rate by
- * checking the BSS's global flag.
- * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
- */
- rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
- ctsrate = rate->hw_value;
- if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
- ctsrate |= rate->hw_value_short;
-
- for (i = 0; i < 4; i++) {
- bool is_40, is_sgi, is_sp;
- int phy;
-
- if (!rates[i].count || (rates[i].idx < 0))
- continue;
-
- rix = rates[i].idx;
- series[i].Tries = rates[i].count;
-
- if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
- series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
- flags |= ATH9K_TXDESC_RTSENA;
- } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
- series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
- flags |= ATH9K_TXDESC_CTSENA;
- }
-
- if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
- series[i].RateFlags |= ATH9K_RATESERIES_2040;
- if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
- series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
-
- is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
- is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
- is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
-
- if (rates[i].flags & IEEE80211_TX_RC_MCS) {
- /* MCS rates */
- series[i].Rate = rix | 0x80;
- series[i].ChSel = ath_txchainmask_reduction(sc,
- common->tx_chainmask, series[i].Rate);
- series[i].PktDuration = ath_pkt_duration(sc, rix, len,
- is_40, is_sgi, is_sp);
- if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
- series[i].RateFlags |= ATH9K_RATESERIES_STBC;
- continue;
- }
-
- /* legacy rates */
- if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
- !(rate->flags & IEEE80211_RATE_ERP_G))
- phy = WLAN_RC_PHY_CCK;
- else
- phy = WLAN_RC_PHY_OFDM;
-
- rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
- series[i].Rate = rate->hw_value;
- if (rate->hw_value_short) {
- if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
- series[i].Rate |= rate->hw_value_short;
- } else {
- is_sp = false;
- }
-
- if (bf->bf_state.bfs_paprd)
- series[i].ChSel = common->tx_chainmask;
- else
- series[i].ChSel = ath_txchainmask_reduction(sc,
- common->tx_chainmask, series[i].Rate);
-
- series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
- phy, rate->bitrate * 100, len, rix, is_sp);
- }
-
- /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
- if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit))
- flags &= ~ATH9K_TXDESC_RTSENA;
-
- /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
- if (flags & ATH9K_TXDESC_RTSENA)
- flags &= ~ATH9K_TXDESC_CTSENA;
-
- /* set dur_update_en for l-sig computation except for PS-Poll frames */
- ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
- bf->bf_lastbf->bf_desc,
- !is_pspoll, ctsrate,
- 0, series, 4, flags);
-
-}
-
-static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
+/*
+ * Assign a descriptor (and sequence number if necessary,
+ * and map buffer for DMA. Frees skb on error
+ */
+static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
struct ath_txq *txq,
+ struct ath_atx_tid *tid,
struct sk_buff *skb)
{
- struct ath_softc *sc = hw->priv;
- struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_frame_info *fi = get_frame_info(skb);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ath_buf *bf;
- struct ath_desc *ds;
- int frm_type;
+ u16 seqno;
bf = ath_tx_get_buffer(sc);
if (!bf) {
ath_dbg(common, ATH_DBG_XMIT, "TX buffers are full\n");
- return NULL;
+ goto error;
}
ATH_TXBUF_RESET(bf);
- bf->bf_flags = setup_tx_flags(skb);
+ if (tid) {
+ seqno = tid->seq_next;
+ hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
+ INCR(tid->seq_next, IEEE80211_SEQ_MAX);
+ bf->bf_state.seqno = seqno;
+ }
+
bf->bf_mpdu = skb;
bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
@@ -1723,38 +1794,26 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
ath_err(ath9k_hw_common(sc->sc_ah),
"dma_mapping_error() on TX\n");
ath_tx_return_buffer(sc, bf);
- return NULL;
+ goto error;
}
- frm_type = get_hw_packet_type(skb);
-
- ds = bf->bf_desc;
- ath9k_hw_set_desc_link(ah, ds, 0);
-
- ath9k_hw_set11n_txdesc(ah, ds, fi->framelen, frm_type, MAX_RATE_POWER,
- fi->keyix, fi->keytype, bf->bf_flags);
-
- ath9k_hw_filltxdesc(ah, ds,
- skb->len, /* segment length */
- true, /* first segment */
- true, /* last segment */
- ds, /* first descriptor */
- bf->bf_buf_addr,
- txq->axq_qnum);
-
+ fi->bf = bf;
return bf;
+
+error:
+ dev_kfree_skb_any(skb);
+ return NULL;
}
/* FIXME: tx power */
-static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
+static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb,
struct ath_tx_control *txctl)
{
- struct sk_buff *skb = bf->bf_mpdu;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- struct list_head bf_head;
struct ath_atx_tid *tid = NULL;
+ struct ath_buf *bf;
u8 tidno;
spin_lock_bh(&txctl->txq->axq_lock);
@@ -1772,27 +1831,21 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
* Try aggregation if it's a unicast data frame
* and the destination is HT capable.
*/
- ath_tx_send_ampdu(sc, tid, bf, txctl);
+ ath_tx_send_ampdu(sc, tid, skb, txctl);
} else {
- INIT_LIST_HEAD(&bf_head);
- list_add_tail(&bf->list, &bf_head);
+ bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb);
+ if (!bf)
+ goto out;
- bf->bf_state.bfs_ftype = txctl->frame_type;
bf->bf_state.bfs_paprd = txctl->paprd;
- if (bf->bf_state.bfs_paprd)
- ar9003_hw_set_paprd_txdesc(sc->sc_ah, bf->bf_desc,
- bf->bf_state.bfs_paprd);
-
if (txctl->paprd)
bf->bf_state.bfs_paprd_timestamp = jiffies;
- if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
- ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
-
- ath_tx_send_normal(sc, txctl->txq, tid, &bf_head);
+ ath_tx_send_normal(sc, txctl->txq, tid, skb);
}
+out:
spin_unlock_bh(&txctl->txq->axq_lock);
}
@@ -1806,7 +1859,6 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ieee80211_vif *vif = info->control.vif;
struct ath_softc *sc = hw->priv;
struct ath_txq *txq = txctl->txq;
- struct ath_buf *bf;
int padpos, padsize;
int frmlen = skb->len + FCS_LEN;
int q;
@@ -1839,6 +1891,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
skb_push(skb, padsize);
memmove(skb->data, skb->data + padsize, padpos);
+ hdr = (struct ieee80211_hdr *) skb->data;
}
if ((vif && vif->type != NL80211_IFTYPE_AP &&
@@ -1853,10 +1906,6 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
* info are no longer valid (overwritten by the ath_frame_info data.
*/
- bf = ath_tx_setup_buffer(hw, txctl->txq, skb);
- if (unlikely(!bf))
- return -ENOMEM;
-
q = skb_get_queue_mapping(skb);
spin_lock_bh(&txq->axq_lock);
if (txq == sc->tx.txq_map[q] &&
@@ -1866,8 +1915,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
}
spin_unlock_bh(&txq->axq_lock);
- ath_tx_start_dma(sc, bf, txctl);
-
+ ath_tx_start_dma(sc, skb, txctl);
return 0;
}
@@ -1876,7 +1924,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
/*****************/
static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
- int tx_flags, int ftype, struct ath_txq *txq)
+ int tx_flags, struct ath_txq *txq)
{
struct ieee80211_hw *hw = sc->hw;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
@@ -1889,10 +1937,9 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
if (tx_flags & ATH_TX_BAR)
tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
- if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
+ if (!(tx_flags & ATH_TX_ERROR))
/* Frame was ACKed */
tx_info->flags |= IEEE80211_TX_STAT_ACK;
- }
padpos = ath9k_cmn_padpos(hdr->frame_control);
padsize = padpos & 3;
@@ -1936,18 +1983,18 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
struct ath_tx_status *ts, int txok, int sendbar)
{
struct sk_buff *skb = bf->bf_mpdu;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
unsigned long flags;
int tx_flags = 0;
if (sendbar)
tx_flags = ATH_TX_BAR;
- if (!txok) {
+ if (!txok)
tx_flags |= ATH_TX_ERROR;
- if (bf_isxretried(bf))
- tx_flags |= ATH_TX_XRETRY;
- }
+ if (ts->ts_status & ATH9K_TXERR_FILT)
+ tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE);
bf->bf_buf_addr = 0;
@@ -1960,9 +2007,8 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
else
complete(&sc->paprd_complete);
} else {
- ath_debug_stat_tx(sc, bf, ts, txq);
- ath_tx_complete(sc, skb, tx_flags,
- bf->bf_state.bfs_ftype, txq);
+ ath_debug_stat_tx(sc, bf, ts, txq, tx_flags);
+ ath_tx_complete(sc, skb, tx_flags, txq);
}
/* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
* accidentally reference it later.
@@ -1979,7 +2025,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
struct ath_tx_status *ts, int nframes, int nbad,
- int txok, bool update_rc)
+ int txok)
{
struct sk_buff *skb = bf->bf_mpdu;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
@@ -1994,19 +2040,16 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
tx_rateindex = ts->ts_rateindex;
WARN_ON(tx_rateindex >= hw->max_rates);
- if (ts->ts_status & ATH9K_TXERR_FILT)
- tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
- if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) {
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
BUG_ON(nbad > nframes);
-
- tx_info->status.ampdu_len = nframes;
- tx_info->status.ampdu_ack_len = nframes - nbad;
}
+ tx_info->status.ampdu_len = nframes;
+ tx_info->status.ampdu_ack_len = nframes - nbad;
if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
- (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
+ (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) == 0) {
/*
* If an underrun error is seen assume it as an excessive
* retry only if max frame trigger level has been reached
@@ -2019,9 +2062,9 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
* successfully by eventually preferring slower rates.
* This itself should also alleviate congestion on the bus.
*/
- if (ieee80211_is_data(hdr->frame_control) &&
- (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN |
- ATH9K_TX_DELIM_UNDERRUN)) &&
+ if (unlikely(ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN |
+ ATH9K_TX_DELIM_UNDERRUN)) &&
+ ieee80211_is_data(hdr->frame_control) &&
ah->tx_trig_level >= sc->sc_ah->config.max_txtrig_level)
tx_info->status.rates[tx_rateindex].count =
hw->max_rate_tries;
@@ -2052,13 +2095,7 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
spin_unlock_bh(&txq->axq_lock);
if (!bf_isampdu(bf)) {
- /*
- * This frame is sent out as a single frame.
- * Use hardware retry status for this frame.
- */
- if (ts->ts_status & ATH9K_TXERR_XRETRY)
- bf->bf_state.bf_type |= BUF_XRETRY;
- ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok, true);
+ ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok, 0);
} else
ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok, true);
@@ -2085,6 +2122,9 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
spin_lock_bh(&txq->axq_lock);
for (;;) {
+ if (work_pending(&sc->hw_reset_work))
+ break;
+
if (list_empty(&txq->axq_q)) {
txq->axq_link = NULL;
if (sc->sc_flags & SC_OP_TXAGGR)
@@ -2172,9 +2212,8 @@ static void ath_tx_complete_poll_work(struct work_struct *work)
if (needreset) {
ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
"tx hung, resetting the chip\n");
- spin_lock_bh(&sc->sc_pcu_lock);
- ath_reset(sc, true);
- spin_unlock_bh(&sc->sc_pcu_lock);
+ RESET_STAT_INC(sc, RESET_TYPE_TX_HANG);
+ ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
}
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
@@ -2207,6 +2246,9 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
int status;
for (;;) {
+ if (work_pending(&sc->hw_reset_work))
+ break;
+
status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts);
if (status == -EINPROGRESS)
break;
@@ -2361,7 +2403,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
tid->sched = false;
tid->paused = false;
tid->state &= ~AGGR_CLEANUP;
- INIT_LIST_HEAD(&tid->buf_q);
+ __skb_queue_head_init(&tid->buf_q);
acno = TID_TO_WME_AC(tidno);
tid->ac = &an->ac[acno];
tid->state &= ~AGGR_ADDBA_COMPLETE;
diff --git a/drivers/net/wireless/ath/carl9170/Kconfig b/drivers/net/wireless/ath/carl9170/Kconfig
index 2d1b821b440d..267d5dcf82dc 100644
--- a/drivers/net/wireless/ath/carl9170/Kconfig
+++ b/drivers/net/wireless/ath/carl9170/Kconfig
@@ -39,3 +39,17 @@ config CARL9170_WPC
bool
depends on CARL9170 && (INPUT = y || INPUT = CARL9170)
default y
+
+config CARL9170_HWRNG
+ bool "Random number generator"
+ depends on CARL9170 && (HW_RANDOM = y || HW_RANDOM = CARL9170)
+ default n
+ help
+ Provides a hardware random number generator to the kernel.
+
+ SECURITY WARNING: It's relatively easy to eavesdrop all
+ generated random numbers from the transport stream with
+ usbmon [software] or special usb sniffer hardware.
+
+ Say N, unless your setup[i.e.: embedded system] has no
+ other rng source and you can afford to take the risk.
diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
index c5427a72a1e2..6cfbb419e2f6 100644
--- a/drivers/net/wireless/ath/carl9170/carl9170.h
+++ b/drivers/net/wireless/ath/carl9170/carl9170.h
@@ -43,6 +43,7 @@
#include <linux/firmware.h>
#include <linux/completion.h>
#include <linux/spinlock.h>
+#include <linux/hw_random.h>
#include <net/cfg80211.h>
#include <net/mac80211.h>
#include <linux/usb.h>
@@ -151,6 +152,7 @@ struct carl9170_sta_tid {
#define CARL9170_TX_TIMEOUT 2500
#define CARL9170_JANITOR_DELAY 128
#define CARL9170_QUEUE_STUCK_TIMEOUT 5500
+#define CARL9170_STAT_WORK 30000
#define CARL9170_NUM_TX_AGG_MAX 30
@@ -282,6 +284,7 @@ struct ar9170 {
bool rx_stream;
bool tx_stream;
bool rx_filter;
+ bool hw_counters;
unsigned int mem_blocks;
unsigned int mem_block_size;
unsigned int rx_size;
@@ -331,11 +334,21 @@ struct ar9170 {
/* PHY */
struct ieee80211_channel *channel;
+ unsigned int num_channels;
int noise[4];
unsigned int chan_fail;
unsigned int total_chan_fail;
u8 heavy_clip;
u8 ht_settings;
+ struct {
+ u64 active; /* usec */
+ u64 cca; /* usec */
+ u64 tx_time; /* usec */
+ u64 rx_total;
+ u64 rx_overrun;
+ } tally;
+ struct delayed_work stat_work;
+ struct survey_info *survey;
/* power calibration data */
u8 power_5G_leg[4];
@@ -437,6 +450,17 @@ struct ar9170 {
unsigned int off_override;
bool state;
} ps;
+
+#ifdef CONFIG_CARL9170_HWRNG
+# define CARL9170_HWRNG_CACHE_SIZE CARL9170_MAX_CMD_PAYLOAD_LEN
+ struct {
+ struct hwrng rng;
+ bool initialized;
+ char name[30 + 1];
+ u16 cache[CARL9170_HWRNG_CACHE_SIZE / sizeof(u16)];
+ unsigned int cache_idx;
+ } rng;
+#endif /* CONFIG_CARL9170_HWRNG */
};
enum carl9170_ps_off_override_reasons {
diff --git a/drivers/net/wireless/ath/carl9170/cmd.c b/drivers/net/wireless/ath/carl9170/cmd.c
index cdfc94c371b4..195dc6538110 100644
--- a/drivers/net/wireless/ath/carl9170/cmd.c
+++ b/drivers/net/wireless/ath/carl9170/cmd.c
@@ -36,6 +36,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <asm/div64.h>
#include "carl9170.h"
#include "cmd.h"
@@ -165,6 +166,39 @@ int carl9170_bcn_ctrl(struct ar9170 *ar, const unsigned int vif_id,
return __carl9170_exec_cmd(ar, cmd, true);
}
+int carl9170_collect_tally(struct ar9170 *ar)
+{
+ struct carl9170_tally_rsp tally;
+ struct survey_info *info;
+ unsigned int tick;
+ int err;
+
+ err = carl9170_exec_cmd(ar, CARL9170_CMD_TALLY, 0, NULL,
+ sizeof(tally), (u8 *)&tally);
+ if (err)
+ return err;
+
+ tick = le32_to_cpu(tally.tick);
+ if (tick) {
+ ar->tally.active += le32_to_cpu(tally.active) / tick;
+ ar->tally.cca += le32_to_cpu(tally.cca) / tick;
+ ar->tally.tx_time += le32_to_cpu(tally.tx_time) / tick;
+ ar->tally.rx_total += le32_to_cpu(tally.rx_total);
+ ar->tally.rx_overrun += le32_to_cpu(tally.rx_overrun);
+
+ if (ar->channel) {
+ info = &ar->survey[ar->channel->hw_value];
+ info->channel_time = ar->tally.active;
+ info->channel_time_busy = ar->tally.cca;
+ info->channel_time_tx = ar->tally.tx_time;
+ do_div(info->channel_time, 1000);
+ do_div(info->channel_time_busy, 1000);
+ do_div(info->channel_time_tx, 1000);
+ }
+ }
+ return 0;
+}
+
int carl9170_powersave(struct ar9170 *ar, const bool ps)
{
struct carl9170_cmd *cmd;
diff --git a/drivers/net/wireless/ath/carl9170/cmd.h b/drivers/net/wireless/ath/carl9170/cmd.h
index d5f95bdc75c1..885c42778b8b 100644
--- a/drivers/net/wireless/ath/carl9170/cmd.h
+++ b/drivers/net/wireless/ath/carl9170/cmd.h
@@ -50,6 +50,7 @@ int carl9170_echo_test(struct ar9170 *ar, u32 v);
int carl9170_reboot(struct ar9170 *ar);
int carl9170_mac_reset(struct ar9170 *ar);
int carl9170_powersave(struct ar9170 *ar, const bool power_on);
+int carl9170_collect_tally(struct ar9170 *ar);
int carl9170_bcn_ctrl(struct ar9170 *ar, const unsigned int vif_id,
const u32 mode, const u32 addr, const u32 len);
diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c
index 39ddea5794f7..f4cae1cccbff 100644
--- a/drivers/net/wireless/ath/carl9170/fw.c
+++ b/drivers/net/wireless/ath/carl9170/fw.c
@@ -266,6 +266,9 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
FIF_PROMISC_IN_BSS;
}
+ if (SUPP(CARL9170FW_HW_COUNTERS))
+ ar->fw.hw_counters = true;
+
if (SUPP(CARL9170FW_WOL))
device_set_wakeup_enable(&ar->udev->dev, true);
diff --git a/drivers/net/wireless/ath/carl9170/fwcmd.h b/drivers/net/wireless/ath/carl9170/fwcmd.h
index 0a6dec529b59..9443c802b25b 100644
--- a/drivers/net/wireless/ath/carl9170/fwcmd.h
+++ b/drivers/net/wireless/ath/carl9170/fwcmd.h
@@ -55,6 +55,7 @@ enum carl9170_cmd_oids {
CARL9170_CMD_READ_TSF = 0x06,
CARL9170_CMD_RX_FILTER = 0x07,
CARL9170_CMD_WOL = 0x08,
+ CARL9170_CMD_TALLY = 0x09,
/* CAM */
CARL9170_CMD_EKEY = 0x10,
@@ -286,6 +287,15 @@ struct carl9170_tsf_rsp {
} __packed;
#define CARL9170_TSF_RSP_SIZE 8
+struct carl9170_tally_rsp {
+ __le32 active;
+ __le32 cca;
+ __le32 tx_time;
+ __le32 rx_total;
+ __le32 rx_overrun;
+ __le32 tick;
+} __packed;
+
struct carl9170_rsp {
struct carl9170_cmd_head hdr;
@@ -300,6 +310,7 @@ struct carl9170_rsp {
struct carl9170_gpio gpio;
struct carl9170_tsf_rsp tsf;
struct carl9170_psm psm;
+ struct carl9170_tally_rsp tally;
u8 data[CARL9170_MAX_CMD_PAYLOAD_LEN];
} __packed;
} __packed __aligned(4);
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index 0122930b14c7..f06e0695d412 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -413,6 +413,9 @@ static int carl9170_op_start(struct ieee80211_hw *hw)
carl9170_set_state_when(ar, CARL9170_IDLE, CARL9170_STARTED);
+ ieee80211_queue_delayed_work(ar->hw, &ar->stat_work,
+ round_jiffies(msecs_to_jiffies(CARL9170_STAT_WORK)));
+
ieee80211_wake_queues(ar->hw);
err = 0;
@@ -423,6 +426,7 @@ out:
static void carl9170_cancel_worker(struct ar9170 *ar)
{
+ cancel_delayed_work_sync(&ar->stat_work);
cancel_delayed_work_sync(&ar->tx_janitor);
#ifdef CONFIG_CARL9170_LEDS
cancel_delayed_work_sync(&ar->led_work);
@@ -794,6 +798,43 @@ static void carl9170_ps_work(struct work_struct *work)
mutex_unlock(&ar->mutex);
}
+static int carl9170_update_survey(struct ar9170 *ar, bool flush, bool noise)
+{
+ int err;
+
+ if (noise) {
+ err = carl9170_get_noisefloor(ar);
+ if (err)
+ return err;
+ }
+
+ if (ar->fw.hw_counters) {
+ err = carl9170_collect_tally(ar);
+ if (err)
+ return err;
+ }
+
+ if (flush)
+ memset(&ar->tally, 0, sizeof(ar->tally));
+
+ return 0;
+}
+
+static void carl9170_stat_work(struct work_struct *work)
+{
+ struct ar9170 *ar = container_of(work, struct ar9170, stat_work.work);
+ int err;
+
+ mutex_lock(&ar->mutex);
+ err = carl9170_update_survey(ar, false, true);
+ mutex_unlock(&ar->mutex);
+
+ if (err)
+ return;
+
+ ieee80211_queue_delayed_work(ar->hw, &ar->stat_work,
+ round_jiffies(msecs_to_jiffies(CARL9170_STAT_WORK)));
+}
static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed)
{
@@ -828,11 +869,19 @@ static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed)
if (err)
goto out;
+ err = carl9170_update_survey(ar, true, false);
+ if (err)
+ goto out;
+
err = carl9170_set_channel(ar, hw->conf.channel,
hw->conf.channel_type, CARL9170_RFI_NONE);
if (err)
goto out;
+ err = carl9170_update_survey(ar, false, true);
+ if (err)
+ goto out;
+
err = carl9170_set_dyn_sifs_ack(ar);
if (err)
goto out;
@@ -1029,7 +1078,8 @@ out:
mutex_unlock(&ar->mutex);
}
-static u64 carl9170_op_get_tsf(struct ieee80211_hw *hw)
+static u64 carl9170_op_get_tsf(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
{
struct ar9170 *ar = hw->priv;
struct carl9170_tsf_rsp tsf;
@@ -1066,8 +1116,10 @@ static int carl9170_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
* the high througput speed in 802.11n networks.
*/
- if (!is_main_vif(ar, vif))
+ if (!is_main_vif(ar, vif)) {
+ mutex_lock(&ar->mutex);
goto err_softw;
+ }
/*
* While the hardware supports *catch-all* key, for offloading
@@ -1253,7 +1305,8 @@ static int carl9170_op_sta_remove(struct ieee80211_hw *hw,
return 0;
}
-static int carl9170_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
+static int carl9170_op_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *param)
{
struct ar9170 *ar = hw->priv;
@@ -1419,24 +1472,159 @@ static int carl9170_register_wps_button(struct ar9170 *ar)
}
#endif /* CONFIG_CARL9170_WPC */
-static int carl9170_op_get_survey(struct ieee80211_hw *hw, int idx,
- struct survey_info *survey)
+#ifdef CONFIG_CARL9170_HWRNG
+static int carl9170_rng_get(struct ar9170 *ar)
{
- struct ar9170 *ar = hw->priv;
+
+#define RW (CARL9170_MAX_CMD_PAYLOAD_LEN / sizeof(u32))
+#define RB (CARL9170_MAX_CMD_PAYLOAD_LEN)
+
+ static const __le32 rng_load[RW] = {
+ [0 ... (RW - 1)] = cpu_to_le32(AR9170_RAND_REG_NUM)};
+
+ u32 buf[RW];
+
+ unsigned int i, off = 0, transfer, count;
int err;
- if (idx != 0)
- return -ENOENT;
+ BUILD_BUG_ON(RB > CARL9170_MAX_CMD_PAYLOAD_LEN);
+
+ if (!IS_ACCEPTING_CMD(ar) || !ar->rng.initialized)
+ return -EAGAIN;
+
+ count = ARRAY_SIZE(ar->rng.cache);
+ while (count) {
+ err = carl9170_exec_cmd(ar, CARL9170_CMD_RREG,
+ RB, (u8 *) rng_load,
+ RB, (u8 *) buf);
+ if (err)
+ return err;
+
+ transfer = min_t(unsigned int, count, RW);
+ for (i = 0; i < transfer; i++)
+ ar->rng.cache[off + i] = buf[i];
+
+ off += transfer;
+ count -= transfer;
+ }
+
+ ar->rng.cache_idx = 0;
+
+#undef RW
+#undef RB
+ return 0;
+}
+
+static int carl9170_rng_read(struct hwrng *rng, u32 *data)
+{
+ struct ar9170 *ar = (struct ar9170 *)rng->priv;
+ int ret = -EIO;
mutex_lock(&ar->mutex);
- err = carl9170_get_noisefloor(ar);
+ if (ar->rng.cache_idx >= ARRAY_SIZE(ar->rng.cache)) {
+ ret = carl9170_rng_get(ar);
+ if (ret) {
+ mutex_unlock(&ar->mutex);
+ return ret;
+ }
+ }
+
+ *data = ar->rng.cache[ar->rng.cache_idx++];
mutex_unlock(&ar->mutex);
- if (err)
+
+ return sizeof(u16);
+}
+
+static void carl9170_unregister_hwrng(struct ar9170 *ar)
+{
+ if (ar->rng.initialized) {
+ hwrng_unregister(&ar->rng.rng);
+ ar->rng.initialized = false;
+ }
+}
+
+static int carl9170_register_hwrng(struct ar9170 *ar)
+{
+ int err;
+
+ snprintf(ar->rng.name, ARRAY_SIZE(ar->rng.name),
+ "%s_%s", KBUILD_MODNAME, wiphy_name(ar->hw->wiphy));
+ ar->rng.rng.name = ar->rng.name;
+ ar->rng.rng.data_read = carl9170_rng_read;
+ ar->rng.rng.priv = (unsigned long)ar;
+
+ if (WARN_ON(ar->rng.initialized))
+ return -EALREADY;
+
+ err = hwrng_register(&ar->rng.rng);
+ if (err) {
+ dev_err(&ar->udev->dev, "Failed to register the random "
+ "number generator (%d)\n", err);
return err;
+ }
+
+ ar->rng.initialized = true;
+
+ err = carl9170_rng_get(ar);
+ if (err) {
+ carl9170_unregister_hwrng(ar);
+ return err;
+ }
- survey->channel = ar->channel;
+ return 0;
+}
+#endif /* CONFIG_CARL9170_HWRNG */
+
+static int carl9170_op_get_survey(struct ieee80211_hw *hw, int idx,
+ struct survey_info *survey)
+{
+ struct ar9170 *ar = hw->priv;
+ struct ieee80211_channel *chan;
+ struct ieee80211_supported_band *band;
+ int err, b, i;
+
+ chan = ar->channel;
+ if (!chan)
+ return -ENODEV;
+
+ if (idx == chan->hw_value) {
+ mutex_lock(&ar->mutex);
+ err = carl9170_update_survey(ar, false, true);
+ mutex_unlock(&ar->mutex);
+ if (err)
+ return err;
+ }
+
+ for (b = 0; b < IEEE80211_NUM_BANDS; b++) {
+ band = ar->hw->wiphy->bands[b];
+
+ if (!band)
+ continue;
+
+ for (i = 0; i < band->n_channels; i++) {
+ if (band->channels[i].hw_value == idx) {
+ chan = &band->channels[i];
+ goto found;
+ }
+ }
+ }
+ return -ENOENT;
+
+found:
+ memcpy(survey, &ar->survey[idx], sizeof(*survey));
+
+ survey->channel = chan;
survey->filled = SURVEY_INFO_NOISE_DBM;
- survey->noise = ar->noise[0];
+
+ if (ar->channel == chan)
+ survey->filled |= SURVEY_INFO_IN_USE;
+
+ if (ar->fw.hw_counters) {
+ survey->filled |= SURVEY_INFO_CHANNEL_TIME |
+ SURVEY_INFO_CHANNEL_TIME_BUSY |
+ SURVEY_INFO_CHANNEL_TIME_TX;
+ }
+
return 0;
}
@@ -1569,6 +1757,7 @@ void *carl9170_alloc(size_t priv_size)
INIT_WORK(&ar->ping_work, carl9170_ping_work);
INIT_WORK(&ar->restart_work, carl9170_restart_work);
INIT_WORK(&ar->ampdu_work, carl9170_ampdu_work);
+ INIT_DELAYED_WORK(&ar->stat_work, carl9170_stat_work);
INIT_DELAYED_WORK(&ar->tx_janitor, carl9170_tx_janitor);
INIT_LIST_HEAD(&ar->tx_ampdu_list);
rcu_assign_pointer(ar->tx_ampdu_iter,
@@ -1652,6 +1841,7 @@ static int carl9170_parse_eeprom(struct ar9170 *ar)
struct ath_regulatory *regulatory = &ar->common.regulatory;
unsigned int rx_streams, tx_streams, tx_params = 0;
int bands = 0;
+ int chans = 0;
if (ar->eeprom.length == cpu_to_le16(0xffff))
return -ENODATA;
@@ -1675,14 +1865,24 @@ static int carl9170_parse_eeprom(struct ar9170 *ar)
if (ar->eeprom.operating_flags & AR9170_OPFLAG_2GHZ) {
ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
&carl9170_band_2GHz;
+ chans += carl9170_band_2GHz.n_channels;
bands++;
}
if (ar->eeprom.operating_flags & AR9170_OPFLAG_5GHZ) {
ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
&carl9170_band_5GHz;
+ chans += carl9170_band_5GHz.n_channels;
bands++;
}
+ if (!bands)
+ return -EINVAL;
+
+ ar->survey = kzalloc(sizeof(struct survey_info) * chans, GFP_KERNEL);
+ if (!ar->survey)
+ return -ENOMEM;
+ ar->num_channels = chans;
+
/*
* I measured this, a bandswitch takes roughly
* 135 ms and a frequency switch about 80.
@@ -1696,12 +1896,11 @@ static int carl9170_parse_eeprom(struct ar9170 *ar)
ar->hw->channel_change_time = 80 * 1000;
regulatory->current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]);
- regulatory->current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]);
/* second part of wiphy init */
SET_IEEE80211_PERM_ADDR(ar->hw, ar->eeprom.mac_address);
- return bands ? 0 : -EINVAL;
+ return 0;
}
static int carl9170_reg_notifier(struct wiphy *wiphy,
@@ -1785,6 +1984,12 @@ int carl9170_register(struct ar9170 *ar)
goto err_unreg;
#endif /* CONFIG_CARL9170_WPC */
+#ifdef CONFIG_CARL9170_HWRNG
+ err = carl9170_register_hwrng(ar);
+ if (err)
+ goto err_unreg;
+#endif /* CONFIG_CARL9170_HWRNG */
+
dev_info(&ar->udev->dev, "Atheros AR9170 is registered as '%s'\n",
wiphy_name(ar->hw->wiphy));
@@ -1817,6 +2022,10 @@ void carl9170_unregister(struct ar9170 *ar)
}
#endif /* CONFIG_CARL9170_WPC */
+#ifdef CONFIG_CARL9170_HWRNG
+ carl9170_unregister_hwrng(ar);
+#endif /* CONFIG_CARL9170_HWRNG */
+
carl9170_cancel_worker(ar);
cancel_work_sync(&ar->restart_work);
@@ -1834,6 +2043,9 @@ void carl9170_free(struct ar9170 *ar)
kfree(ar->mem_bitmap);
ar->mem_bitmap = NULL;
+ kfree(ar->survey);
+ ar->survey = NULL;
+
mutex_destroy(&ar->mutex);
ieee80211_free_hw(ar->hw);
diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c
index aa147a9120b6..472efc7e3402 100644
--- a/drivers/net/wireless/ath/carl9170/phy.c
+++ b/drivers/net/wireless/ath/carl9170/phy.c
@@ -578,11 +578,10 @@ static int carl9170_init_phy(struct ar9170 *ar, enum ieee80211_band band)
if (err)
return err;
- /* XXX: remove magic! */
- if (is_2ghz)
- err = carl9170_write_reg(ar, AR9170_PWR_REG_PLL_ADDAC, 0x5163);
- else
- err = carl9170_write_reg(ar, AR9170_PWR_REG_PLL_ADDAC, 0x5143);
+ if (!ar->fw.hw_counters) {
+ err = carl9170_write_reg(ar, AR9170_PWR_REG_PLL_ADDAC,
+ is_2ghz ? 0x5163 : 0x5143);
+ }
return err;
}
@@ -1574,6 +1573,9 @@ int carl9170_get_noisefloor(struct ar9170 *ar)
AR9170_PHY_EXT_CCA_MIN_PWR, phy_res[i + 2]), 8);
}
+ if (ar->channel)
+ ar->survey[ar->channel->hw_value].noise = ar->noise[0];
+
return 0;
}
@@ -1766,10 +1768,6 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
ar->chan_fail = 0;
}
- err = carl9170_get_noisefloor(ar);
- if (err)
- return err;
-
if (ar->heavy_clip) {
err = carl9170_write_reg(ar, AR9170_PHY_REG_HEAVY_CLIP_ENABLE,
0x200 | ar->heavy_clip);
diff --git a/drivers/net/wireless/ath/carl9170/version.h b/drivers/net/wireless/ath/carl9170/version.h
index 64703778cfea..e651db856344 100644
--- a/drivers/net/wireless/ath/carl9170/version.h
+++ b/drivers/net/wireless/ath/carl9170/version.h
@@ -1,7 +1,7 @@
#ifndef __CARL9170_SHARED_VERSION_H
#define __CARL9170_SHARED_VERSION_H
#define CARL9170FW_VERSION_YEAR 11
-#define CARL9170FW_VERSION_MONTH 6
-#define CARL9170FW_VERSION_DAY 30
+#define CARL9170FW_VERSION_MONTH 8
+#define CARL9170FW_VERSION_DAY 15
#define CARL9170FW_VERSION_GIT "1.9.4"
#endif /* __CARL9170_SHARED_VERSION_H */
diff --git a/drivers/net/wireless/ath/main.c b/drivers/net/wireless/ath/main.c
index c325202fdc5f..d9218fe02036 100644
--- a/drivers/net/wireless/ath/main.c
+++ b/drivers/net/wireless/ath/main.c
@@ -57,22 +57,18 @@ struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
}
EXPORT_SYMBOL(ath_rxbuf_alloc);
-int ath_printk(const char *level, struct ath_common *common,
- const char *fmt, ...)
+void ath_printk(const char *level, const char *fmt, ...)
{
struct va_format vaf;
va_list args;
- int rtn;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
- rtn = printk("%sath: %pV", level, &vaf);
+ printk("%sath: %pV", level, &vaf);
va_end(args);
-
- return rtn;
}
EXPORT_SYMBOL(ath_printk);
diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h
index 172f63f671cf..03a8268ccf21 100644
--- a/drivers/net/wireless/ath/regd.h
+++ b/drivers/net/wireless/ath/regd.h
@@ -101,7 +101,7 @@ enum CountryCode {
CTRY_GERMANY = 276,
CTRY_GREECE = 300,
CTRY_GREENLAND = 304,
- CTRY_GRENEDA = 308,
+ CTRY_GRENADA = 308,
CTRY_GUAM = 316,
CTRY_GUATEMALA = 320,
CTRY_HAITI = 332,
diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h
index 24b53839fc3a..bdd2b4d61f2f 100644
--- a/drivers/net/wireless/ath/regd_common.h
+++ b/drivers/net/wireless/ath/regd_common.h
@@ -332,7 +332,7 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_GERMANY, ETSI1_WORLD, "DE"},
{CTRY_GREECE, ETSI1_WORLD, "GR"},
{CTRY_GREENLAND, ETSI1_WORLD, "GL"},
- {CTRY_GRENEDA, FCC3_FCCA, "GD"},
+ {CTRY_GRENADA, FCC3_FCCA, "GD"},
{CTRY_GUAM, FCC1_FCCA, "GU"},
{CTRY_GUATEMALA, FCC1_FCCA, "GT"},
{CTRY_HAITI, ETSI1_WORLD, "HT"},
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
index 3cab843afb05..b97a40ed5fff 100644
--- a/drivers/net/wireless/b43/Kconfig
+++ b/drivers/net/wireless/b43/Kconfig
@@ -114,22 +114,22 @@ config B43_PHY_N
affect other devices support and may provide support for basic needs.
config B43_PHY_LP
- bool "Support for low-power (LP-PHY) devices (EXPERIMENTAL)"
- depends on B43 && EXPERIMENTAL
+ bool "Support for low-power (LP-PHY) devices"
+ depends on B43
default y
---help---
Support for the LP-PHY.
The LP-PHY is a low-power PHY built into some notebooks
- and embedded devices. It supports 802.11a/g
+ and embedded devices. It supports 802.11a/b/g
(802.11a support is optional, and currently disabled).
config B43_PHY_HT
- bool "Support for HT-PHY devices (BROKEN)"
- depends on B43 && BROKEN
+ bool "Support for HT-PHY (high throughput) devices (EXPERIMENTAL)"
+ depends on B43 && EXPERIMENTAL
---help---
Support for the HT-PHY.
- Say N, this is BROKEN and crashes driver.
+ Enables support for BCM4331 and possibly other chipsets with that PHY.
config B43_PHY_LCN
bool "Support for LCN-PHY devices (BROKEN)"
@@ -169,13 +169,3 @@ config B43_DEBUG
Say N, if you are a distributor or user building a release kernel
for production use.
Only say Y, if you are debugging a problem in the b43 driver sourcecode.
-
-config B43_FORCE_PIO
- bool "Force usage of PIO instead of DMA"
- depends on B43 && B43_DEBUG
- ---help---
- This will disable DMA and always enable PIO instead.
-
- Say N!
- This is only for debugging the PIO engine code. You do
- _NOT_ want to enable this.
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index c818b0bc88ec..447a2307c9d9 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -17,11 +17,6 @@
#include "phy_common.h"
-/* The unique identifier of the firmware that's officially supported by
- * this driver version. */
-#define B43_SUPPORTED_FIRMWARE_ID "FW13"
-
-
#ifdef CONFIG_B43_DEBUG
# define B43_DEBUG 1
#else
@@ -112,21 +107,61 @@
#define B43_MMIO_RADIO_HWENABLED_LO 0x49A
#define B43_MMIO_GPIO_CONTROL 0x49C
#define B43_MMIO_GPIO_MASK 0x49E
+#define B43_MMIO_TXE0_CTL 0x500
+#define B43_MMIO_TXE0_AUX 0x502
+#define B43_MMIO_TXE0_TS_LOC 0x504
+#define B43_MMIO_TXE0_TIME_OUT 0x506
+#define B43_MMIO_TXE0_WM_0 0x508
+#define B43_MMIO_TXE0_WM_1 0x50A
+#define B43_MMIO_TXE0_PHYCTL 0x50C
+#define B43_MMIO_TXE0_STATUS 0x50E
+#define B43_MMIO_TXE0_MMPLCP0 0x510
+#define B43_MMIO_TXE0_MMPLCP1 0x512
+#define B43_MMIO_TXE0_PHYCTL1 0x514
+#define B43_MMIO_XMTFIFODEF 0x520
+#define B43_MMIO_XMTFIFO_FRAME_CNT 0x522 /* core rev>= 16 only */
+#define B43_MMIO_XMTFIFO_BYTE_CNT 0x524 /* core rev>= 16 only */
+#define B43_MMIO_XMTFIFO_HEAD 0x526 /* core rev>= 16 only */
+#define B43_MMIO_XMTFIFO_RD_PTR 0x528 /* core rev>= 16 only */
+#define B43_MMIO_XMTFIFO_WR_PTR 0x52A /* core rev>= 16 only */
+#define B43_MMIO_XMTFIFODEF1 0x52C /* core rev>= 16 only */
+#define B43_MMIO_XMTFIFOCMD 0x540
+#define B43_MMIO_XMTFIFOFLUSH 0x542
+#define B43_MMIO_XMTFIFOTHRESH 0x544
+#define B43_MMIO_XMTFIFORDY 0x546
+#define B43_MMIO_XMTFIFOPRIRDY 0x548
+#define B43_MMIO_XMTFIFORQPRI 0x54A
+#define B43_MMIO_XMTTPLATETXPTR 0x54C
+#define B43_MMIO_XMTTPLATEPTR 0x550
+#define B43_MMIO_SMPL_CLCT_STRPTR 0x552 /* core rev>= 22 only */
+#define B43_MMIO_SMPL_CLCT_STPPTR 0x554 /* core rev>= 22 only */
+#define B43_MMIO_SMPL_CLCT_CURPTR 0x556 /* core rev>= 22 only */
+#define B43_MMIO_XMTTPLATEDATALO 0x560
+#define B43_MMIO_XMTTPLATEDATAHI 0x562
+#define B43_MMIO_XMTSEL 0x568
+#define B43_MMIO_XMTTXCNT 0x56A
+#define B43_MMIO_XMTTXSHMADDR 0x56C
#define B43_MMIO_TSF_CFP_START_LOW 0x604
#define B43_MMIO_TSF_CFP_START_HIGH 0x606
#define B43_MMIO_TSF_CFP_PRETBTT 0x612
+#define B43_MMIO_TSF_CLK_FRAC_LOW 0x62E
+#define B43_MMIO_TSF_CLK_FRAC_HIGH 0x630
#define B43_MMIO_TSF_0 0x632 /* core rev < 3 only */
#define B43_MMIO_TSF_1 0x634 /* core rev < 3 only */
#define B43_MMIO_TSF_2 0x636 /* core rev < 3 only */
#define B43_MMIO_TSF_3 0x638 /* core rev < 3 only */
#define B43_MMIO_RNG 0x65A
#define B43_MMIO_IFSSLOT 0x684 /* Interframe slot time */
-#define B43_MMIO_IFSCTL 0x688 /* Interframe space control */
+#define B43_MMIO_IFSCTL 0x688 /* Interframe space control */
+#define B43_MMIO_IFSSTAT 0x690
+#define B43_MMIO_IFSMEDBUSYCTL 0x692
+#define B43_MMIO_IFTXDUR 0x694
#define B43_MMIO_IFSCTL_USE_EDCF 0x0004
#define B43_MMIO_POWERUP_DELAY 0x6A8
#define B43_MMIO_BTCOEX_CTL 0x6B4 /* Bluetooth Coexistence Control */
#define B43_MMIO_BTCOEX_STAT 0x6B6 /* Bluetooth Coexistence Status */
#define B43_MMIO_BTCOEX_TXCTL 0x6B8 /* Bluetooth Coexistence Transmit Control */
+#define B43_MMIO_WEPCTL 0x7C0
/* SPROM boardflags_lo values */
#define B43_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */
@@ -594,6 +629,7 @@ struct b43_dma {
struct b43_dmaring *rx_ring;
u32 translation; /* Routing bits */
+ bool translation_in_low; /* Should translation bit go into low addr? */
bool parity; /* Check for parity */
};
@@ -694,6 +730,12 @@ struct b43_firmware_file {
enum b43_firmware_file_type type;
};
+enum b43_firmware_hdr_format {
+ B43_FW_HDR_598,
+ B43_FW_HDR_410,
+ B43_FW_HDR_351,
+};
+
/* Pointers to the firmware data and meta information about it. */
struct b43_firmware {
/* Microcode */
@@ -710,6 +752,9 @@ struct b43_firmware {
/* Firmware patchlevel */
u16 patch;
+ /* Format of header used by firmware */
+ enum b43_firmware_hdr_format hdr_format;
+
/* Set to true, if we are using an opensource firmware.
* Use this to check for proprietary vs opensource. */
bool opensource;
@@ -875,7 +920,7 @@ struct b43_wl {
struct b43_leds leds;
/* Kmalloc'ed scratch space for PIO TX/RX. Protected by wl->mutex. */
- u8 pio_scratchspace[110] __attribute__((__aligned__(8)));
+ u8 pio_scratchspace[118] __attribute__((__aligned__(8)));
u8 pio_tailspace[4] __attribute__((__aligned__(8)));
};
@@ -965,12 +1010,6 @@ static inline bool b43_using_pio_transfers(struct b43_wldev *dev)
return dev->__using_pio_transfers;
}
-#ifdef CONFIG_B43_FORCE_PIO
-# define B43_PIO_DEFAULT 1
-#else
-# define B43_PIO_DEFAULT 0
-#endif
-
/* Message printing */
void b43info(struct b43_wl *wl, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
diff --git a/drivers/net/wireless/b43/bus.c b/drivers/net/wireless/b43/bus.c
index 05f6c7bff6ab..424692df239d 100644
--- a/drivers/net/wireless/b43/bus.c
+++ b/drivers/net/wireless/b43/bus.c
@@ -3,6 +3,8 @@
Broadcom B43 wireless driver
Bus abstraction layer
+ Copyright (c) 2011 Rafał Miłecki <zajec5@gmail.com>
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 481e534534eb..5e45604f0f5d 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -47,6 +47,38 @@
* into separate slots. */
#define TX_SLOTS_PER_FRAME 2
+static u32 b43_dma_address(struct b43_dma *dma, dma_addr_t dmaaddr,
+ enum b43_addrtype addrtype)
+{
+ u32 uninitialized_var(addr);
+
+ switch (addrtype) {
+ case B43_DMA_ADDR_LOW:
+ addr = lower_32_bits(dmaaddr);
+ if (dma->translation_in_low) {
+ addr &= ~SSB_DMA_TRANSLATION_MASK;
+ addr |= dma->translation;
+ }
+ break;
+ case B43_DMA_ADDR_HIGH:
+ addr = upper_32_bits(dmaaddr);
+ if (!dma->translation_in_low) {
+ addr &= ~SSB_DMA_TRANSLATION_MASK;
+ addr |= dma->translation;
+ }
+ break;
+ case B43_DMA_ADDR_EXT:
+ if (dma->translation_in_low)
+ addr = lower_32_bits(dmaaddr);
+ else
+ addr = upper_32_bits(dmaaddr);
+ addr &= SSB_DMA_TRANSLATION_MASK;
+ addr >>= SSB_DMA_TRANSLATION_SHIFT;
+ break;
+ }
+
+ return addr;
+}
/* 32bit DMA ops. */
static
@@ -77,10 +109,9 @@ static void op32_fill_descriptor(struct b43_dmaring *ring,
slot = (int)(&(desc->dma32) - descbase);
B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
- addr = (u32) (dmaaddr & ~SSB_DMA_TRANSLATION_MASK);
- addrext = (u32) (dmaaddr & SSB_DMA_TRANSLATION_MASK)
- >> SSB_DMA_TRANSLATION_SHIFT;
- addr |= ring->dev->dma.translation;
+ addr = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_LOW);
+ addrext = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_EXT);
+
ctl = bufsize & B43_DMA32_DCTL_BYTECNT;
if (slot == ring->nr_slots - 1)
ctl |= B43_DMA32_DCTL_DTABLEEND;
@@ -170,11 +201,10 @@ static void op64_fill_descriptor(struct b43_dmaring *ring,
slot = (int)(&(desc->dma64) - descbase);
B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
- addrlo = (u32) (dmaaddr & 0xFFFFFFFF);
- addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
- addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
- >> SSB_DMA_TRANSLATION_SHIFT;
- addrhi |= ring->dev->dma.translation;
+ addrlo = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_LOW);
+ addrhi = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_HIGH);
+ addrext = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_EXT);
+
if (slot == ring->nr_slots - 1)
ctl0 |= B43_DMA64_DCTL0_DTABLEEND;
if (start)
@@ -389,33 +419,34 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
gfp_t flags = GFP_KERNEL;
/* The specs call for 4K buffers for 30- and 32-bit DMA with 4K
- * alignment and 8K buffers for 64-bit DMA with 8K alignment. Testing
- * has shown that 4K is sufficient for the latter as long as the buffer
- * does not cross an 8K boundary.
- *
- * For unknown reasons - possibly a hardware error - the BCM4311 rev
- * 02, which uses 64-bit DMA, needs the ring buffer in very low memory,
- * which accounts for the GFP_DMA flag below.
- *
- * The flags here must match the flags in free_ringmemory below!
+ * alignment and 8K buffers for 64-bit DMA with 8K alignment.
+ * In practice we could use smaller buffers for the latter, but the
+ * alignment is really important because of the hardware bug. If bit
+ * 0x00001000 is used in DMA address, some hardware (like BCM4331)
+ * copies that bit into B43_DMA64_RXSTATUS and we get false values from
+ * B43_DMA64_RXSTATDPTR. Let's just use 8K buffers even if we don't use
+ * more than 256 slots for ring.
*/
- if (ring->type == B43_DMA_64BIT)
- flags |= GFP_DMA;
+ u16 ring_mem_size = (ring->type == B43_DMA_64BIT) ?
+ B43_DMA64_RINGMEMSIZE : B43_DMA32_RINGMEMSIZE;
+
ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev,
- B43_DMA_RINGMEMSIZE,
- &(ring->dmabase), flags);
+ ring_mem_size, &(ring->dmabase),
+ flags);
if (!ring->descbase) {
b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
return -ENOMEM;
}
- memset(ring->descbase, 0, B43_DMA_RINGMEMSIZE);
+ memset(ring->descbase, 0, ring_mem_size);
return 0;
}
static void free_ringmemory(struct b43_dmaring *ring)
{
- dma_free_coherent(ring->dev->dev->dma_dev, B43_DMA_RINGMEMSIZE,
+ u16 ring_mem_size = (ring->type == B43_DMA_64BIT) ?
+ B43_DMA64_RINGMEMSIZE : B43_DMA32_RINGMEMSIZE;
+ dma_free_coherent(ring->dev->dev->dma_dev, ring_mem_size,
ring->descbase, ring->dmabase);
}
@@ -658,41 +689,37 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
int err = 0;
u32 value;
u32 addrext;
- u32 trans = ring->dev->dma.translation;
bool parity = ring->dev->dma.parity;
+ u32 addrlo;
+ u32 addrhi;
if (ring->tx) {
if (ring->type == B43_DMA_64BIT) {
u64 ringbase = (u64) (ring->dmabase);
+ addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT);
+ addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW);
+ addrhi = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_HIGH);
- addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
- >> SSB_DMA_TRANSLATION_SHIFT;
value = B43_DMA64_TXENABLE;
value |= (addrext << B43_DMA64_TXADDREXT_SHIFT)
& B43_DMA64_TXADDREXT_MASK;
if (!parity)
value |= B43_DMA64_TXPARITYDISABLE;
b43_dma_write(ring, B43_DMA64_TXCTL, value);
- b43_dma_write(ring, B43_DMA64_TXRINGLO,
- (ringbase & 0xFFFFFFFF));
- b43_dma_write(ring, B43_DMA64_TXRINGHI,
- ((ringbase >> 32) &
- ~SSB_DMA_TRANSLATION_MASK)
- | trans);
+ b43_dma_write(ring, B43_DMA64_TXRINGLO, addrlo);
+ b43_dma_write(ring, B43_DMA64_TXRINGHI, addrhi);
} else {
u32 ringbase = (u32) (ring->dmabase);
+ addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT);
+ addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW);
- addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
- >> SSB_DMA_TRANSLATION_SHIFT;
value = B43_DMA32_TXENABLE;
value |= (addrext << B43_DMA32_TXADDREXT_SHIFT)
& B43_DMA32_TXADDREXT_MASK;
if (!parity)
value |= B43_DMA32_TXPARITYDISABLE;
b43_dma_write(ring, B43_DMA32_TXCTL, value);
- b43_dma_write(ring, B43_DMA32_TXRING,
- (ringbase & ~SSB_DMA_TRANSLATION_MASK)
- | trans);
+ b43_dma_write(ring, B43_DMA32_TXRING, addrlo);
}
} else {
err = alloc_initial_descbuffers(ring);
@@ -700,9 +727,10 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
goto out;
if (ring->type == B43_DMA_64BIT) {
u64 ringbase = (u64) (ring->dmabase);
+ addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT);
+ addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW);
+ addrhi = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_HIGH);
- addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
- >> SSB_DMA_TRANSLATION_SHIFT;
value = (ring->frameoffset << B43_DMA64_RXFROFF_SHIFT);
value |= B43_DMA64_RXENABLE;
value |= (addrext << B43_DMA64_RXADDREXT_SHIFT)
@@ -710,19 +738,15 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
if (!parity)
value |= B43_DMA64_RXPARITYDISABLE;
b43_dma_write(ring, B43_DMA64_RXCTL, value);
- b43_dma_write(ring, B43_DMA64_RXRINGLO,
- (ringbase & 0xFFFFFFFF));
- b43_dma_write(ring, B43_DMA64_RXRINGHI,
- ((ringbase >> 32) &
- ~SSB_DMA_TRANSLATION_MASK)
- | trans);
+ b43_dma_write(ring, B43_DMA64_RXRINGLO, addrlo);
+ b43_dma_write(ring, B43_DMA64_RXRINGHI, addrhi);
b43_dma_write(ring, B43_DMA64_RXINDEX, ring->nr_slots *
sizeof(struct b43_dmadesc64));
} else {
u32 ringbase = (u32) (ring->dmabase);
+ addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT);
+ addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW);
- addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
- >> SSB_DMA_TRANSLATION_SHIFT;
value = (ring->frameoffset << B43_DMA32_RXFROFF_SHIFT);
value |= B43_DMA32_RXENABLE;
value |= (addrext << B43_DMA32_RXADDREXT_SHIFT)
@@ -730,9 +754,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
if (!parity)
value |= B43_DMA32_RXPARITYDISABLE;
b43_dma_write(ring, B43_DMA32_RXCTL, value);
- b43_dma_write(ring, B43_DMA32_RXRING,
- (ringbase & ~SSB_DMA_TRANSLATION_MASK)
- | trans);
+ b43_dma_write(ring, B43_DMA32_RXRING, addrlo);
b43_dma_write(ring, B43_DMA32_RXINDEX, ring->nr_slots *
sizeof(struct b43_dmadesc32));
}
@@ -872,8 +894,17 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
ring->current_slot = -1;
} else {
if (ring->index == 0) {
- ring->rx_buffersize = B43_DMA0_RX_BUFFERSIZE;
- ring->frameoffset = B43_DMA0_RX_FRAMEOFFSET;
+ switch (dev->fw.hdr_format) {
+ case B43_FW_HDR_598:
+ ring->rx_buffersize = B43_DMA0_RX_FW598_BUFSIZE;
+ ring->frameoffset = B43_DMA0_RX_FW598_FO;
+ break;
+ case B43_FW_HDR_410:
+ case B43_FW_HDR_351:
+ ring->rx_buffersize = B43_DMA0_RX_FW351_BUFSIZE;
+ ring->frameoffset = B43_DMA0_RX_FW351_FO;
+ break;
+ }
} else
B43_WARN_ON(1);
}
@@ -1066,6 +1097,25 @@ static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask)
return 0;
}
+/* Some hardware with 64-bit DMA seems to be bugged and looks for translation
+ * bit in low address word instead of high one.
+ */
+static bool b43_dma_translation_in_low_word(struct b43_wldev *dev,
+ enum b43_dmatype type)
+{
+ if (type != B43_DMA_64BIT)
+ return 1;
+
+#ifdef CONFIG_B43_SSB
+ if (dev->dev->bus_type == B43_BUS_SSB &&
+ dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI &&
+ !(dev->dev->sdev->bus->host_pci->is_pcie &&
+ ssb_read32(dev->dev->sdev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64))
+ return 1;
+#endif
+ return 0;
+}
+
int b43_dma_init(struct b43_wldev *dev)
{
struct b43_dma *dma = &dev->dma;
@@ -1091,6 +1141,7 @@ int b43_dma_init(struct b43_wldev *dev)
break;
#endif
}
+ dma->translation_in_low = b43_dma_translation_in_low_word(dev, type);
dma->parity = true;
#ifdef CONFIG_B43_BCMA
diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h
index cdf87094efe8..315b96ed1d90 100644
--- a/drivers/net/wireless/b43/dma.h
+++ b/drivers/net/wireless/b43/dma.h
@@ -161,13 +161,17 @@ struct b43_dmadesc_generic {
} __packed;
/* Misc DMA constants */
-#define B43_DMA_RINGMEMSIZE PAGE_SIZE
-#define B43_DMA0_RX_FRAMEOFFSET 30
+#define B43_DMA32_RINGMEMSIZE 4096
+#define B43_DMA64_RINGMEMSIZE 8192
+/* Offset of frame with actual data */
+#define B43_DMA0_RX_FW598_FO 38
+#define B43_DMA0_RX_FW351_FO 30
/* DMA engine tuning knobs */
#define B43_TXRING_SLOTS 256
#define B43_RXRING_SLOTS 64
-#define B43_DMA0_RX_BUFFERSIZE (B43_DMA0_RX_FRAMEOFFSET + IEEE80211_MAX_FRAME_LEN)
+#define B43_DMA0_RX_FW598_BUFSIZE (B43_DMA0_RX_FW598_FO + IEEE80211_MAX_FRAME_LEN)
+#define B43_DMA0_RX_FW351_BUFSIZE (B43_DMA0_RX_FW351_FO + IEEE80211_MAX_FRAME_LEN)
/* Pointer poison */
#define B43_DMA_PTR_POISON ((void *)ERR_PTR(-ENOMEM))
@@ -212,6 +216,12 @@ enum b43_dmatype {
B43_DMA_64BIT = 64,
};
+enum b43_addrtype {
+ B43_DMA_ADDR_LOW,
+ B43_DMA_ADDR_HIGH,
+ B43_DMA_ADDR_EXT,
+};
+
struct b43_dmaring {
/* Lowlevel DMA ops. */
const struct b43_dma_ops *ops;
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 26f1ab840cc7..7cf4125a1624 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -7,6 +7,7 @@
Copyright (c) 2005-2009 Michael Buesch <m@bues.ch>
Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ Copyright (c) 2010-2011 Rafał Miłecki <zajec5@gmail.com>
SDIO support
Copyright (c) 2009 Albert Herranz <albert_herranz@yahoo.es>
@@ -37,7 +38,6 @@
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
#include <linux/firmware.h>
-#include <linux/wireless.h>
#include <linux/workqueue.h>
#include <linux/skbuff.h>
#include <linux/io.h>
@@ -65,9 +65,9 @@ MODULE_AUTHOR("Martin Langer");
MODULE_AUTHOR("Stefano Brivio");
MODULE_AUTHOR("Michael Buesch");
MODULE_AUTHOR("Gábor Stefanik");
+MODULE_AUTHOR("Rafał Miłecki");
MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(B43_SUPPORTED_FIRMWARE_ID);
MODULE_FIRMWARE("b43/ucode11.fw");
MODULE_FIRMWARE("b43/ucode13.fw");
MODULE_FIRMWARE("b43/ucode14.fw");
@@ -109,12 +109,13 @@ int b43_modparam_verbose = B43_VERBOSITY_DEFAULT;
module_param_named(verbose, b43_modparam_verbose, int, 0644);
MODULE_PARM_DESC(verbose, "Log message verbosity: 0=error, 1=warn, 2=info(default), 3=debug");
-static int b43_modparam_pio = B43_PIO_DEFAULT;
+static int b43_modparam_pio = 0;
module_param_named(pio, b43_modparam_pio, int, 0644);
MODULE_PARM_DESC(pio, "Use PIO accesses by default: 0=DMA, 1=PIO");
#ifdef CONFIG_B43_BCMA
static const struct bcma_device_id b43_bcma_tbl[] = {
+ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x11, BCMA_ANY_CLASS),
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x17, BCMA_ANY_CLASS),
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x18, BCMA_ANY_CLASS),
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x1D, BCMA_ANY_CLASS),
@@ -320,6 +321,10 @@ static void b43_wireless_core_exit(struct b43_wldev *dev);
static int b43_wireless_core_init(struct b43_wldev *dev);
static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev);
static int b43_wireless_core_start(struct b43_wldev *dev);
+static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *conf,
+ u32 changed);
static int b43_ratelimit(struct b43_wl *wl)
{
@@ -724,52 +729,59 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on)
for (i = 0; i < 5; i++)
b43_ram_write(dev, i * 4, buffer[i]);
- b43_write16(dev, 0x0568, 0x0000);
+ b43_write16(dev, B43_MMIO_XMTSEL, 0x0000);
+
if (dev->dev->core_rev < 11)
- b43_write16(dev, 0x07C0, 0x0000);
+ b43_write16(dev, B43_MMIO_WEPCTL, 0x0000);
else
- b43_write16(dev, 0x07C0, 0x0100);
+ b43_write16(dev, B43_MMIO_WEPCTL, 0x0100);
+
value = (ofdm ? 0x41 : 0x40);
- b43_write16(dev, 0x050C, value);
- if ((phy->type == B43_PHYTYPE_N) || (phy->type == B43_PHYTYPE_LP))
- b43_write16(dev, 0x0514, 0x1A02);
- b43_write16(dev, 0x0508, 0x0000);
- b43_write16(dev, 0x050A, 0x0000);
- b43_write16(dev, 0x054C, 0x0000);
- b43_write16(dev, 0x056A, 0x0014);
- b43_write16(dev, 0x0568, 0x0826);
- b43_write16(dev, 0x0500, 0x0000);
- if (!pa_on && (phy->type == B43_PHYTYPE_N)) {
- //SPEC TODO
- }
+ b43_write16(dev, B43_MMIO_TXE0_PHYCTL, value);
+ if (phy->type == B43_PHYTYPE_N || phy->type == B43_PHYTYPE_LP ||
+ phy->type == B43_PHYTYPE_LCN)
+ b43_write16(dev, B43_MMIO_TXE0_PHYCTL1, 0x1A02);
+
+ b43_write16(dev, B43_MMIO_TXE0_WM_0, 0x0000);
+ b43_write16(dev, B43_MMIO_TXE0_WM_1, 0x0000);
+
+ b43_write16(dev, B43_MMIO_XMTTPLATETXPTR, 0x0000);
+ b43_write16(dev, B43_MMIO_XMTTXCNT, 0x0014);
+ b43_write16(dev, B43_MMIO_XMTSEL, 0x0826);
+ b43_write16(dev, B43_MMIO_TXE0_CTL, 0x0000);
+
+ if (!pa_on && phy->type == B43_PHYTYPE_N)
+ ; /*b43_nphy_pa_override(dev, false) */
switch (phy->type) {
case B43_PHYTYPE_N:
- b43_write16(dev, 0x0502, 0x00D0);
+ case B43_PHYTYPE_LCN:
+ b43_write16(dev, B43_MMIO_TXE0_AUX, 0x00D0);
break;
case B43_PHYTYPE_LP:
- b43_write16(dev, 0x0502, 0x0050);
+ b43_write16(dev, B43_MMIO_TXE0_AUX, 0x0050);
break;
default:
- b43_write16(dev, 0x0502, 0x0030);
+ b43_write16(dev, B43_MMIO_TXE0_AUX, 0x0030);
}
+ b43_read16(dev, B43_MMIO_TXE0_AUX);
if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
b43_radio_write16(dev, 0x0051, 0x0017);
for (i = 0x00; i < max_loop; i++) {
- value = b43_read16(dev, 0x050E);
+ value = b43_read16(dev, B43_MMIO_TXE0_STATUS);
if (value & 0x0080)
break;
udelay(10);
}
for (i = 0x00; i < 0x0A; i++) {
- value = b43_read16(dev, 0x050E);
+ value = b43_read16(dev, B43_MMIO_TXE0_STATUS);
if (value & 0x0400)
break;
udelay(10);
}
for (i = 0x00; i < 0x19; i++) {
- value = b43_read16(dev, 0x0690);
+ value = b43_read16(dev, B43_MMIO_IFSSTAT);
if (!(value & 0x0100))
break;
udelay(10);
@@ -1632,7 +1644,8 @@ static void handle_irq_beacon(struct b43_wldev *dev)
u32 cmd, beacon0_valid, beacon1_valid;
if (!b43_is_mode(wl, NL80211_IFTYPE_AP) &&
- !b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT))
+ !b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) &&
+ !b43_is_mode(wl, NL80211_IFTYPE_ADHOC))
return;
/* This is the bottom half of the asynchronous beacon update. */
@@ -2510,6 +2523,12 @@ static int b43_upload_microcode(struct b43_wldev *dev)
}
dev->fw.rev = fwrev;
dev->fw.patch = fwpatch;
+ if (dev->fw.rev >= 598)
+ dev->fw.hdr_format = B43_FW_HDR_598;
+ else if (dev->fw.rev >= 410)
+ dev->fw.hdr_format = B43_FW_HDR_410;
+ else
+ dev->fw.hdr_format = B43_FW_HDR_351;
dev->fw.opensource = (fwdate == 0xFFFF);
/* Default to use-all-queues. */
@@ -2557,7 +2576,7 @@ static int b43_upload_microcode(struct b43_wldev *dev)
dev->fw.rev, dev->fw.patch);
wiphy->hw_version = dev->dev->core_id;
- if (b43_is_old_txhdr_format(dev)) {
+ if (dev->fw.hdr_format == B43_FW_HDR_351) {
/* We're over the deadline, but we keep support for old fw
* until it turns out to be in major conflict with something new. */
b43warn(dev->wl, "You are using an old firmware image. "
@@ -2943,6 +2962,8 @@ static void b43_rate_memory_init(struct b43_wldev *dev)
case B43_PHYTYPE_G:
case B43_PHYTYPE_N:
case B43_PHYTYPE_LP:
+ case B43_PHYTYPE_HT:
+ case B43_PHYTYPE_LCN:
b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1);
b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1);
b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1);
@@ -3538,7 +3559,8 @@ static void b43_qos_init(struct b43_wldev *dev)
b43dbg(dev->wl, "QoS enabled\n");
}
-static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue,
+static int b43_op_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 _queue,
const struct ieee80211_tx_queue_params *params)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
@@ -3585,7 +3607,7 @@ static int b43_op_get_stats(struct ieee80211_hw *hw,
return 0;
}
-static u64 b43_op_get_tsf(struct ieee80211_hw *hw)
+static u64 b43_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
struct b43_wldev *dev;
@@ -3604,7 +3626,8 @@ static u64 b43_op_get_tsf(struct ieee80211_hw *hw)
return tsf;
}
-static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+static void b43_op_set_tsf(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u64 tsf)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
struct b43_wldev *dev;
@@ -3778,14 +3801,24 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
struct ieee80211_conf *conf = &hw->conf;
int antenna;
int err = 0;
+ bool reload_bss = false;
mutex_lock(&wl->mutex);
+ dev = wl->current_dev;
+
/* Switch the band (if necessary). This might change the active core. */
err = b43_switch_band(wl, conf->channel);
if (err)
goto out_unlock_mutex;
- dev = wl->current_dev;
+
+ /* Need to reload all settings if the core changed */
+ if (dev != wl->current_dev) {
+ dev = wl->current_dev;
+ changed = ~0;
+ reload_bss = true;
+ }
+
phy = &dev->phy;
if (conf_is_ht(conf))
@@ -3846,6 +3879,9 @@ out_mac_enable:
out_unlock_mutex:
mutex_unlock(&wl->mutex);
+ if (wl->vif && reload_bss)
+ b43_op_bss_info_changed(hw, wl->vif, &wl->vif->bss_conf, ~0);
+
return err;
}
@@ -3934,7 +3970,8 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_BEACON_INT &&
(b43_is_mode(wl, NL80211_IFTYPE_AP) ||
b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) ||
- b43_is_mode(wl, NL80211_IFTYPE_ADHOC)))
+ b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) &&
+ conf->beacon_int)
b43_set_beacon_int(dev, conf->beacon_int);
if (changed & BSS_CHANGED_BASIC_RATES)
@@ -4107,10 +4144,13 @@ out_unlock:
* because the core might be gone away while we unlocked the mutex. */
static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev)
{
- struct b43_wl *wl = dev->wl;
+ struct b43_wl *wl;
struct b43_wldev *orig_dev;
u32 mask;
+ if (!dev)
+ return NULL;
+ wl = dev->wl;
redo:
if (!dev || b43_status(dev) < B43_STAT_STARTED)
return dev;
@@ -4629,8 +4669,13 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
if (b43_bus_host_is_pcmcia(dev->dev) ||
- b43_bus_host_is_sdio(dev->dev) ||
- dev->use_pio) {
+ b43_bus_host_is_sdio(dev->dev)) {
+ dev->__using_pio_transfers = 1;
+ err = b43_pio_init(dev);
+ } else if (dev->use_pio) {
+ b43warn(dev->wl, "Forced PIO by use_pio module parameter. "
+ "This should not be needed and will result in lower "
+ "performance.\n");
dev->__using_pio_transfers = 1;
err = b43_pio_init(dev);
} else {
@@ -4702,6 +4747,9 @@ static int b43_op_add_interface(struct ieee80211_hw *hw,
out_mutex_unlock:
mutex_unlock(&wl->mutex);
+ if (err == 0)
+ b43_op_bss_info_changed(hw, vif, &vif->bss_conf, ~0);
+
return err;
}
@@ -4772,6 +4820,9 @@ static int b43_op_start(struct ieee80211_hw *hw)
out_mutex_unlock:
mutex_unlock(&wl->mutex);
+ /* reload configuration */
+ b43_op_config(hw, ~0);
+
return err;
}
@@ -4928,10 +4979,18 @@ out:
if (err)
wl->current_dev = NULL; /* Failed to init the dev. */
mutex_unlock(&wl->mutex);
- if (err)
+
+ if (err) {
b43err(wl, "Controller restart FAILED\n");
- else
- b43info(wl, "Controller restarted\n");
+ return;
+ }
+
+ /* reload configuration */
+ b43_op_config(wl->hw, ~0);
+ if (wl->vif)
+ b43_op_bss_info_changed(wl->hw, wl->vif, &wl->vif->bss_conf, ~0);
+
+ b43info(wl, "Controller restarted\n");
}
static int b43_setup_bands(struct b43_wldev *dev,
@@ -5416,8 +5475,7 @@ static void b43_print_driverinfo(void)
feat_sdio = "S";
#endif
printk(KERN_INFO "Broadcom 43xx driver loaded "
- "[ Features: %s%s%s%s%s, Firmware-ID: "
- B43_SUPPORTED_FIRMWARE_ID " ]\n",
+ "[ Features: %s%s%s%s%s ]\n",
feat_pci, feat_pcmcia, feat_nphy,
feat_leds, feat_sdio);
}
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c
index 07f009ff5ee2..3ea44bb03684 100644
--- a/drivers/net/wireless/b43/phy_common.c
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -448,6 +448,38 @@ bool b43_channel_type_is_40mhz(enum nl80211_channel_type channel_type)
channel_type == NL80211_CHAN_HT40PLUS);
}
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */
+void b43_phy_force_clock(struct b43_wldev *dev, bool force)
+{
+ u32 tmp;
+
+ WARN_ON(dev->phy.type != B43_PHYTYPE_N &&
+ dev->phy.type != B43_PHYTYPE_HT);
+
+ switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+ case B43_BUS_BCMA:
+ tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
+ if (force)
+ tmp |= BCMA_IOCTL_FGC;
+ else
+ tmp &= ~BCMA_IOCTL_FGC;
+ bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
+ break;
+#endif
+#ifdef CONFIG_B43_SSB
+ case B43_BUS_SSB:
+ tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
+ if (force)
+ tmp |= SSB_TMSLOW_FGC;
+ else
+ tmp &= ~SSB_TMSLOW_FGC;
+ ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
+ break;
+#endif
+ }
+}
+
/* http://bcm-v4.sipsolutions.net/802.11/PHY/Cordic */
struct b43_c32 b43_cordic(int theta)
{
diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h
index aa77ba612a92..9233b13fc16d 100644
--- a/drivers/net/wireless/b43/phy_common.h
+++ b/drivers/net/wireless/b43/phy_common.h
@@ -444,6 +444,8 @@ void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on);
bool b43_channel_type_is_40mhz(enum nl80211_channel_type channel_type);
+void b43_phy_force_clock(struct b43_wldev *dev, bool force);
+
struct b43_c32 b43_cordic(int theta);
#endif /* LINUX_B43_PHY_COMMON_H_ */
diff --git a/drivers/net/wireless/b43/phy_ht.c b/drivers/net/wireless/b43/phy_ht.c
index 7c40919651a7..7416c5e9154d 100644
--- a/drivers/net/wireless/b43/phy_ht.c
+++ b/drivers/net/wireless/b43/phy_ht.c
@@ -3,6 +3,8 @@
Broadcom B43 wireless driver
IEEE 802.11n HT-PHY support
+ Copyright (c) 2011 Rafał Miłecki <zajec5@gmail.com>
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -152,6 +154,92 @@ static void b43_radio_2059_init(struct b43_wldev *dev)
}
/**************************************************
+ * Various PHY ops
+ **************************************************/
+
+static void b43_phy_ht_zero_extg(struct b43_wldev *dev)
+{
+ u8 i, j;
+ u16 base[] = { 0x40, 0x60, 0x80 };
+
+ for (i = 0; i < ARRAY_SIZE(base); i++) {
+ for (j = 0; j < 4; j++)
+ b43_phy_write(dev, B43_PHY_EXTG(base[i] + j), 0);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(base); i++)
+ b43_phy_write(dev, B43_PHY_EXTG(base[i] + 0xc), 0);
+}
+
+/* Some unknown AFE (Analog Frondned) op */
+static void b43_phy_ht_afe_unk1(struct b43_wldev *dev)
+{
+ u8 i;
+
+ const u16 ctl_regs[3][2] = {
+ { B43_PHY_HT_AFE_CTL1, B43_PHY_HT_AFE_CTL2 },
+ { B43_PHY_HT_AFE_CTL3, B43_PHY_HT_AFE_CTL4 },
+ { B43_PHY_HT_AFE_CTL5, B43_PHY_HT_AFE_CTL6},
+ };
+
+ for (i = 0; i < 3; i++) {
+ /* TODO: verify masks&sets */
+ b43_phy_set(dev, ctl_regs[i][1], 0x4);
+ b43_phy_set(dev, ctl_regs[i][0], 0x4);
+ b43_phy_mask(dev, ctl_regs[i][1], ~0x1);
+ b43_phy_set(dev, ctl_regs[i][0], 0x1);
+ b43_httab_write(dev, B43_HTTAB16(8, 5 + (i * 0x10)), 0);
+ b43_phy_mask(dev, ctl_regs[i][0], ~0x4);
+ }
+}
+
+static void b43_phy_ht_force_rf_sequence(struct b43_wldev *dev, u16 rf_seq)
+{
+ u8 i;
+
+ u16 save_seq_mode = b43_phy_read(dev, B43_PHY_HT_RF_SEQ_MODE);
+ b43_phy_set(dev, B43_PHY_HT_RF_SEQ_MODE, 0x3);
+
+ b43_phy_set(dev, B43_PHY_HT_RF_SEQ_TRIG, rf_seq);
+ for (i = 0; i < 200; i++) {
+ if (!(b43_phy_read(dev, B43_PHY_HT_RF_SEQ_STATUS) & rf_seq)) {
+ i = 0;
+ break;
+ }
+ msleep(1);
+ }
+ if (i)
+ b43err(dev->wl, "Forcing RF sequence timeout\n");
+
+ b43_phy_write(dev, B43_PHY_HT_RF_SEQ_MODE, save_seq_mode);
+}
+
+static void b43_phy_ht_read_clip_detection(struct b43_wldev *dev, u16 *clip_st)
+{
+ clip_st[0] = b43_phy_read(dev, B43_PHY_HT_C1_CLIP1THRES);
+ clip_st[1] = b43_phy_read(dev, B43_PHY_HT_C2_CLIP1THRES);
+ clip_st[2] = b43_phy_read(dev, B43_PHY_HT_C3_CLIP1THRES);
+}
+
+static void b43_phy_ht_bphy_init(struct b43_wldev *dev)
+{
+ unsigned int i;
+ u16 val;
+
+ val = 0x1E1F;
+ for (i = 0; i < 16; i++) {
+ b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val);
+ val -= 0x202;
+ }
+ val = 0x3E3F;
+ for (i = 0; i < 16; i++) {
+ b43_phy_write(dev, B43_PHY_N_BMODE(0x98 + i), val);
+ val -= 0x202;
+ }
+ b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668);
+}
+
+/**************************************************
* Channel switching ops.
**************************************************/
@@ -255,8 +343,125 @@ static void b43_phy_ht_op_prepare_structs(struct b43_wldev *dev)
static int b43_phy_ht_op_init(struct b43_wldev *dev)
{
+ u16 tmp;
+ u16 clip_state[3];
+
b43_phy_ht_tables_init(dev);
+ b43_phy_mask(dev, 0x0be, ~0x2);
+ b43_phy_set(dev, 0x23f, 0x7ff);
+ b43_phy_set(dev, 0x240, 0x7ff);
+ b43_phy_set(dev, 0x241, 0x7ff);
+
+ b43_phy_ht_zero_extg(dev);
+
+ b43_phy_mask(dev, B43_PHY_EXTG(0), ~0x3);
+
+ b43_phy_write(dev, B43_PHY_HT_AFE_CTL1, 0);
+ b43_phy_write(dev, B43_PHY_HT_AFE_CTL3, 0);
+ b43_phy_write(dev, B43_PHY_HT_AFE_CTL5, 0);
+
+ b43_phy_write(dev, B43_PHY_EXTG(0x103), 0x20);
+ b43_phy_write(dev, B43_PHY_EXTG(0x101), 0x20);
+ b43_phy_write(dev, 0x20d, 0xb8);
+ b43_phy_write(dev, B43_PHY_EXTG(0x14f), 0xc8);
+ b43_phy_write(dev, 0x70, 0x50);
+ b43_phy_write(dev, 0x1ff, 0x30);
+
+ if (0) /* TODO: condition */
+ ; /* TODO: PHY op on reg 0x217 */
+
+ b43_phy_read(dev, 0xb0); /* TODO: what for? */
+ b43_phy_set(dev, 0xb0, 0x1);
+
+ b43_phy_set(dev, 0xb1, 0x91);
+ b43_phy_write(dev, 0x32f, 0x0003);
+ b43_phy_write(dev, 0x077, 0x0010);
+ b43_phy_write(dev, 0x0b4, 0x0258);
+ b43_phy_mask(dev, 0x17e, ~0x4000);
+
+ b43_phy_write(dev, 0x0b9, 0x0072);
+
+ b43_httab_write_few(dev, B43_HTTAB16(7, 0x14e), 2, 0x010f, 0x010f);
+ b43_httab_write_few(dev, B43_HTTAB16(7, 0x15e), 2, 0x010f, 0x010f);
+ b43_httab_write_few(dev, B43_HTTAB16(7, 0x16e), 2, 0x010f, 0x010f);
+
+ b43_phy_ht_afe_unk1(dev);
+
+ b43_httab_write_few(dev, B43_HTTAB16(7, 0x130), 9, 0x777, 0x111, 0x111,
+ 0x777, 0x111, 0x111, 0x777, 0x111, 0x111);
+
+ b43_httab_write(dev, B43_HTTAB16(7, 0x120), 0x0777);
+ b43_httab_write(dev, B43_HTTAB16(7, 0x124), 0x0777);
+
+ b43_httab_write(dev, B43_HTTAB16(8, 0x00), 0x02);
+ b43_httab_write(dev, B43_HTTAB16(8, 0x10), 0x02);
+ b43_httab_write(dev, B43_HTTAB16(8, 0x20), 0x02);
+
+ b43_httab_write_few(dev, B43_HTTAB16(8, 0x08), 4,
+ 0x8e, 0x96, 0x96, 0x96);
+ b43_httab_write_few(dev, B43_HTTAB16(8, 0x18), 4,
+ 0x8f, 0x9f, 0x9f, 0x9f);
+ b43_httab_write_few(dev, B43_HTTAB16(8, 0x28), 4,
+ 0x8f, 0x9f, 0x9f, 0x9f);
+
+ b43_httab_write_few(dev, B43_HTTAB16(8, 0x0c), 4, 0x2, 0x2, 0x2, 0x2);
+ b43_httab_write_few(dev, B43_HTTAB16(8, 0x1c), 4, 0x2, 0x2, 0x2, 0x2);
+ b43_httab_write_few(dev, B43_HTTAB16(8, 0x2c), 4, 0x2, 0x2, 0x2, 0x2);
+
+ b43_phy_maskset(dev, 0x0280, 0xff00, 0x3e);
+ b43_phy_maskset(dev, 0x0283, 0xff00, 0x3e);
+ b43_phy_maskset(dev, B43_PHY_OFDM(0x0141), 0xff00, 0x46);
+ b43_phy_maskset(dev, 0x0283, 0xff00, 0x40);
+
+ b43_httab_write_few(dev, B43_HTTAB16(00, 0x8), 4,
+ 0x09, 0x0e, 0x13, 0x18);
+ b43_httab_write_few(dev, B43_HTTAB16(01, 0x8), 4,
+ 0x09, 0x0e, 0x13, 0x18);
+ /* TODO: Did wl mean 2 instead of 40? */
+ b43_httab_write_few(dev, B43_HTTAB16(40, 0x8), 4,
+ 0x09, 0x0e, 0x13, 0x18);
+
+ b43_phy_maskset(dev, B43_PHY_OFDM(0x24), 0x3f, 0xd);
+ b43_phy_maskset(dev, B43_PHY_OFDM(0x64), 0x3f, 0xd);
+ b43_phy_maskset(dev, B43_PHY_OFDM(0xa4), 0x3f, 0xd);
+
+ b43_phy_set(dev, B43_PHY_EXTG(0x060), 0x1);
+ b43_phy_set(dev, B43_PHY_EXTG(0x064), 0x1);
+ b43_phy_set(dev, B43_PHY_EXTG(0x080), 0x1);
+ b43_phy_set(dev, B43_PHY_EXTG(0x084), 0x1);
+
+ /* Copy some tables entries */
+ tmp = b43_httab_read(dev, B43_HTTAB16(7, 0x144));
+ b43_httab_write(dev, B43_HTTAB16(7, 0x14a), tmp);
+ tmp = b43_httab_read(dev, B43_HTTAB16(7, 0x154));
+ b43_httab_write(dev, B43_HTTAB16(7, 0x15a), tmp);
+ tmp = b43_httab_read(dev, B43_HTTAB16(7, 0x164));
+ b43_httab_write(dev, B43_HTTAB16(7, 0x16a), tmp);
+
+ /* Reset CCA */
+ b43_phy_force_clock(dev, true);
+ tmp = b43_phy_read(dev, B43_PHY_HT_BBCFG);
+ b43_phy_write(dev, B43_PHY_HT_BBCFG, tmp | B43_PHY_HT_BBCFG_RSTCCA);
+ b43_phy_write(dev, B43_PHY_HT_BBCFG, tmp & ~B43_PHY_HT_BBCFG_RSTCCA);
+ b43_phy_force_clock(dev, false);
+
+ b43_mac_phy_clock_set(dev, true);
+
+ b43_phy_ht_force_rf_sequence(dev, B43_PHY_HT_RF_SEQ_TRIG_RX2TX);
+ b43_phy_ht_force_rf_sequence(dev, B43_PHY_HT_RF_SEQ_TRIG_RST2RX);
+
+ /* TODO: PHY op on reg 0xb0 */
+
+ /* TODO: Should we restore it? Or store it in global PHY info? */
+ b43_phy_ht_read_clip_detection(dev, clip_state);
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ b43_phy_ht_bphy_init(dev);
+
+ b43_httab_write_bulk(dev, B43_HTTAB32(0x1a, 0xc0),
+ B43_HTTAB_1A_C0_LATE_SIZE, b43_httab_0x1a_0xc0_late);
+
return 0;
}
diff --git a/drivers/net/wireless/b43/phy_ht.h b/drivers/net/wireless/b43/phy_ht.h
index 7ad7affc8df0..6544c4293b34 100644
--- a/drivers/net/wireless/b43/phy_ht.h
+++ b/drivers/net/wireless/b43/phy_ht.h
@@ -4,7 +4,11 @@
#include "phy_common.h"
+#define B43_PHY_HT_BBCFG 0x001 /* BB config */
+#define B43_PHY_HT_BBCFG_RSTCCA 0x4000 /* Reset CCA */
+#define B43_PHY_HT_BBCFG_RSTRX 0x8000 /* Reset RX */
#define B43_PHY_HT_BANDCTL 0x009 /* Band control */
+#define B43_PHY_HT_BANDCTL_5GHZ 0x0001 /* Use the 5GHz band */
#define B43_PHY_HT_TABLE_ADDR 0x072 /* Table address */
#define B43_PHY_HT_TABLE_DATALO 0x073 /* Table data low */
#define B43_PHY_HT_TABLE_DATAHI 0x074 /* Table data high */
@@ -15,6 +19,21 @@
#define B43_PHY_HT_BW5 0x1D2
#define B43_PHY_HT_BW6 0x1D3
+#define B43_PHY_HT_C1_CLIP1THRES B43_PHY_OFDM(0x00E)
+#define B43_PHY_HT_C2_CLIP1THRES B43_PHY_OFDM(0x04E)
+#define B43_PHY_HT_C3_CLIP1THRES B43_PHY_OFDM(0x08E)
+
+#define B43_PHY_HT_RF_SEQ_MODE B43_PHY_EXTG(0x000)
+#define B43_PHY_HT_RF_SEQ_TRIG B43_PHY_EXTG(0x003)
+#define B43_PHY_HT_RF_SEQ_TRIG_RX2TX 0x0001 /* RX2TX */
+#define B43_PHY_HT_RF_SEQ_TRIG_TX2RX 0x0002 /* TX2RX */
+#define B43_PHY_HT_RF_SEQ_TRIG_UPGH 0x0004 /* Update gain H */
+#define B43_PHY_HT_RF_SEQ_TRIG_UPGL 0x0008 /* Update gain L */
+#define B43_PHY_HT_RF_SEQ_TRIG_UPGU 0x0010 /* Update gain U */
+#define B43_PHY_HT_RF_SEQ_TRIG_RST2RX 0x0020 /* Reset to RX */
+#define B43_PHY_HT_RF_SEQ_STATUS B43_PHY_EXTG(0x004)
+/* Values for the status are the same as for the trigger */
+
#define B43_PHY_HT_RF_CTL1 B43_PHY_EXTG(0x010)
#define B43_PHY_HT_AFE_CTL1 B43_PHY_EXTG(0x110)
diff --git a/drivers/net/wireless/b43/phy_lcn.c b/drivers/net/wireless/b43/phy_lcn.c
index 9f7dbbd5ced6..a13e28ef6246 100644
--- a/drivers/net/wireless/b43/phy_lcn.c
+++ b/drivers/net/wireless/b43/phy_lcn.c
@@ -3,6 +3,8 @@
Broadcom B43 wireless driver
IEEE 802.11n LCN-PHY support
+ Copyright (c) 2011 Rafał Miłecki <zajec5@gmail.com>
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -18,6 +20,14 @@
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
Boston, MA 02110-1301, USA.
+ This file incorporates work covered by the following copyright and
+ permission notice:
+
+ Copyright (c) 2010 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.
*/
#include <linux/slab.h>
@@ -27,12 +37,852 @@
#include "tables_phy_lcn.h"
#include "main.h"
+struct lcn_tx_gains {
+ u16 gm_gain;
+ u16 pga_gain;
+ u16 pad_gain;
+ u16 dac_gain;
+};
+
+struct lcn_tx_iir_filter {
+ u8 type;
+ u16 values[16];
+};
+
+enum lcn_sense_type {
+ B43_SENSE_TEMP,
+ B43_SENSE_VBAT,
+};
+
+/* In theory it's PHY common function, move if needed */
+/* brcms_b_switch_macfreq */
+static void b43_phy_switch_macfreq(struct b43_wldev *dev, u8 spurmode)
+{
+ if (dev->dev->chip_id == 43224 || dev->dev->chip_id == 43225) {
+ switch (spurmode) {
+ case 2: /* 126 Mhz */
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x2082);
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
+ break;
+ case 1: /* 123 Mhz */
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x5341);
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
+ break;
+ default: /* 120 Mhz */
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x8889);
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
+ break;
+ }
+ } else if (dev->phy.type == B43_PHYTYPE_LCN) {
+ switch (spurmode) {
+ case 1: /* 82 Mhz */
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x7CE0);
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0xC);
+ break;
+ default: /* 80 Mhz */
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0xCCCD);
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0xC);
+ break;
+ }
+ }
+}
+
+/**************************************************
+ * Radio 2064.
+ **************************************************/
+
+/* wlc_lcnphy_radio_2064_channel_tune_4313 */
+static void b43_radio_2064_channel_setup(struct b43_wldev *dev)
+{
+ u16 save[2];
+
+ b43_radio_set(dev, 0x09d, 0x4);
+ b43_radio_write(dev, 0x09e, 0xf);
+
+ /* Channel specific values in theory, in practice always the same */
+ b43_radio_write(dev, 0x02a, 0xb);
+ b43_radio_maskset(dev, 0x030, ~0x3, 0xa);
+ b43_radio_maskset(dev, 0x091, ~0x3, 0);
+ b43_radio_maskset(dev, 0x038, ~0xf, 0x7);
+ b43_radio_maskset(dev, 0x030, ~0xc, 0x8);
+ b43_radio_maskset(dev, 0x05e, ~0xf, 0x8);
+ b43_radio_maskset(dev, 0x05e, ~0xf0, 0x80);
+ b43_radio_write(dev, 0x06c, 0x80);
+
+ save[0] = b43_radio_read(dev, 0x044);
+ save[1] = b43_radio_read(dev, 0x12b);
+
+ b43_radio_set(dev, 0x044, 0x7);
+ b43_radio_set(dev, 0x12b, 0xe);
+
+ /* TODO */
+
+ b43_radio_write(dev, 0x040, 0xfb);
+
+ b43_radio_write(dev, 0x041, 0x9a);
+ b43_radio_write(dev, 0x042, 0xa3);
+ b43_radio_write(dev, 0x043, 0x0c);
+
+ /* TODO */
+
+ b43_radio_set(dev, 0x044, 0x0c);
+ udelay(1);
+
+ b43_radio_write(dev, 0x044, save[0]);
+ b43_radio_write(dev, 0x12b, save[1]);
+
+ if (dev->phy.rev == 1) {
+ /* brcmsmac uses outdated 0x3 for 0x038 */
+ b43_radio_write(dev, 0x038, 0x0);
+ b43_radio_write(dev, 0x091, 0x7);
+ }
+}
+
+/* wlc_radio_2064_init */
+static void b43_radio_2064_init(struct b43_wldev *dev)
+{
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ b43_radio_write(dev, 0x09c, 0x0020);
+ b43_radio_write(dev, 0x105, 0x0008);
+ } else {
+ /* TODO */
+ }
+ b43_radio_write(dev, 0x032, 0x0062);
+ b43_radio_write(dev, 0x033, 0x0019);
+ b43_radio_write(dev, 0x090, 0x0010);
+ b43_radio_write(dev, 0x010, 0x0000);
+ if (dev->phy.rev == 1) {
+ b43_radio_write(dev, 0x060, 0x007f);
+ b43_radio_write(dev, 0x061, 0x0072);
+ b43_radio_write(dev, 0x062, 0x007f);
+ }
+ b43_radio_write(dev, 0x01d, 0x0002);
+ b43_radio_write(dev, 0x01e, 0x0006);
+
+ b43_phy_write(dev, 0x4ea, 0x4688);
+ b43_phy_maskset(dev, 0x4eb, ~0x7, 0x2);
+ b43_phy_mask(dev, 0x4eb, ~0x01c0);
+ b43_phy_maskset(dev, 0x46a, 0xff00, 0x19);
+
+ b43_lcntab_write(dev, B43_LCNTAB16(0x00, 0x55), 0);
+
+ b43_radio_mask(dev, 0x05b, (u16) ~0xff02);
+ b43_radio_set(dev, 0x004, 0x40);
+ b43_radio_set(dev, 0x120, 0x10);
+ b43_radio_set(dev, 0x078, 0x80);
+ b43_radio_set(dev, 0x129, 0x2);
+ b43_radio_set(dev, 0x057, 0x1);
+ b43_radio_set(dev, 0x05b, 0x2);
+
+ /* TODO: wait for some bit to be set */
+ b43_radio_read(dev, 0x05c);
+
+ b43_radio_mask(dev, 0x05b, (u16) ~0xff02);
+ b43_radio_mask(dev, 0x057, (u16) ~0xff01);
+
+ b43_phy_write(dev, 0x933, 0x2d6b);
+ b43_phy_write(dev, 0x934, 0x2d6b);
+ b43_phy_write(dev, 0x935, 0x2d6b);
+ b43_phy_write(dev, 0x936, 0x2d6b);
+ b43_phy_write(dev, 0x937, 0x016b);
+
+ b43_radio_mask(dev, 0x057, (u16) ~0xff02);
+ b43_radio_write(dev, 0x0c2, 0x006f);
+}
+
+/**************************************************
+ * Various PHY ops
+ **************************************************/
+
+/* wlc_lcnphy_toggle_afe_pwdn */
+static void b43_phy_lcn_afe_set_unset(struct b43_wldev *dev)
+{
+ u16 afe_ctl2 = b43_phy_read(dev, B43_PHY_LCN_AFE_CTL2);
+ u16 afe_ctl1 = b43_phy_read(dev, B43_PHY_LCN_AFE_CTL1);
+
+ b43_phy_write(dev, B43_PHY_LCN_AFE_CTL2, afe_ctl2 | 0x1);
+ b43_phy_write(dev, B43_PHY_LCN_AFE_CTL1, afe_ctl1 | 0x1);
+
+ b43_phy_write(dev, B43_PHY_LCN_AFE_CTL2, afe_ctl2 & ~0x1);
+ b43_phy_write(dev, B43_PHY_LCN_AFE_CTL1, afe_ctl1 & ~0x1);
+
+ b43_phy_write(dev, B43_PHY_LCN_AFE_CTL2, afe_ctl2);
+ b43_phy_write(dev, B43_PHY_LCN_AFE_CTL1, afe_ctl1);
+}
+
+/* wlc_lcnphy_get_pa_gain */
+static u16 b43_phy_lcn_get_pa_gain(struct b43_wldev *dev)
+{
+ return (b43_phy_read(dev, 0x4fb) & 0x7f00) >> 8;
+}
+
+/* wlc_lcnphy_set_dac_gain */
+static void b43_phy_lcn_set_dac_gain(struct b43_wldev *dev, u16 dac_gain)
+{
+ u16 dac_ctrl;
+
+ dac_ctrl = b43_phy_read(dev, 0x439);
+ dac_ctrl = dac_ctrl & 0xc7f;
+ dac_ctrl = dac_ctrl | (dac_gain << 7);
+ b43_phy_maskset(dev, 0x439, ~0xfff, dac_ctrl);
+}
+
+/* wlc_lcnphy_set_bbmult */
+static void b43_phy_lcn_set_bbmult(struct b43_wldev *dev, u8 m0)
+{
+ b43_lcntab_write(dev, B43_LCNTAB16(0x00, 0x57), m0 << 8);
+}
+
+/* wlc_lcnphy_clear_tx_power_offsets */
+static void b43_phy_lcn_clear_tx_power_offsets(struct b43_wldev *dev)
+{
+ u8 i;
+
+ if (1) { /* FIXME */
+ b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, (0x7 << 10) | 0x340);
+ for (i = 0; i < 30; i++) {
+ b43_phy_write(dev, B43_PHY_LCN_TABLE_DATAHI, 0);
+ b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, 0);
+ }
+ }
+
+ b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, (0x7 << 10) | 0x80);
+ for (i = 0; i < 64; i++) {
+ b43_phy_write(dev, B43_PHY_LCN_TABLE_DATAHI, 0);
+ b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, 0);
+ }
+}
+
+/* wlc_lcnphy_rev0_baseband_init */
+static void b43_phy_lcn_rev0_baseband_init(struct b43_wldev *dev)
+{
+ b43_radio_write(dev, 0x11c, 0);
+
+ b43_phy_write(dev, 0x43b, 0);
+ b43_phy_write(dev, 0x43c, 0);
+ b43_phy_write(dev, 0x44c, 0);
+ b43_phy_write(dev, 0x4e6, 0);
+ b43_phy_write(dev, 0x4f9, 0);
+ b43_phy_write(dev, 0x4b0, 0);
+ b43_phy_write(dev, 0x938, 0);
+ b43_phy_write(dev, 0x4b0, 0);
+ b43_phy_write(dev, 0x44e, 0);
+
+ b43_phy_set(dev, 0x567, 0x03);
+
+ b43_phy_set(dev, 0x44a, 0x44);
+ b43_phy_write(dev, 0x44a, 0x80);
+
+ if (!(dev->dev->bus_sprom->boardflags_lo & B43_BFL_FEM))
+ ; /* TODO */
+ b43_phy_maskset(dev, 0x634, ~0xff, 0xc);
+ if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_FEM) {
+ b43_phy_maskset(dev, 0x634, ~0xff, 0xa);
+ b43_phy_write(dev, 0x910, 0x1);
+ }
+
+ b43_phy_write(dev, 0x910, 0x1);
+
+ b43_phy_maskset(dev, 0x448, ~0x300, 0x100);
+ b43_phy_maskset(dev, 0x608, ~0xff, 0x17);
+ b43_phy_maskset(dev, 0x604, ~0x7ff, 0x3ea);
+}
+
+/* wlc_lcnphy_bu_tweaks */
+static void b43_phy_lcn_bu_tweaks(struct b43_wldev *dev)
+{
+ b43_phy_set(dev, 0x805, 0x1);
+
+ b43_phy_maskset(dev, 0x42f, ~0x7, 0x3);
+ b43_phy_maskset(dev, 0x030, ~0x7, 0x3);
+
+ b43_phy_write(dev, 0x414, 0x1e10);
+ b43_phy_write(dev, 0x415, 0x0640);
+
+ b43_phy_maskset(dev, 0x4df, (u16) ~0xff00, 0xf700);
+
+ b43_phy_set(dev, 0x44a, 0x44);
+ b43_phy_write(dev, 0x44a, 0x80);
+
+ b43_phy_maskset(dev, 0x434, ~0xff, 0xfd);
+ b43_phy_maskset(dev, 0x420, ~0xff, 0x10);
+
+ if (dev->dev->bus_sprom->board_rev >= 0x1204)
+ b43_radio_set(dev, 0x09b, 0xf0);
+
+ b43_phy_write(dev, 0x7d6, 0x0902);
+
+ b43_phy_maskset(dev, 0x429, ~0xf, 0x9);
+ b43_phy_maskset(dev, 0x429, ~(0x3f << 4), 0xe << 4);
+
+ if (dev->phy.rev == 1) {
+ b43_phy_maskset(dev, 0x423, ~0xff, 0x46);
+ b43_phy_maskset(dev, 0x411, ~0xff, 1);
+ b43_phy_set(dev, 0x434, 0xff); /* FIXME: update to wl */
+
+ /* TODO: wl operates on PHY 0x416, brcmsmac is outdated here */
+
+ b43_phy_maskset(dev, 0x656, ~0xf, 2);
+ b43_phy_set(dev, 0x44d, 4);
+
+ b43_radio_set(dev, 0x0f7, 0x4);
+ b43_radio_mask(dev, 0x0f1, ~0x3);
+ b43_radio_maskset(dev, 0x0f2, ~0xf8, 0x90);
+ b43_radio_maskset(dev, 0x0f3, ~0x3, 0x2);
+ b43_radio_maskset(dev, 0x0f3, ~0xf0, 0xa0);
+
+ b43_radio_set(dev, 0x11f, 0x2);
+
+ b43_phy_lcn_clear_tx_power_offsets(dev);
+
+ /* TODO: something more? */
+ }
+}
+
+/* wlc_lcnphy_vbat_temp_sense_setup */
+static void b43_phy_lcn_sense_setup(struct b43_wldev *dev,
+ enum lcn_sense_type sense_type)
+{
+ u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain;
+ u16 auxpga_vmid;
+ u8 tx_pwr_idx;
+ u8 i;
+
+ u16 save_radio_regs[6][2] = {
+ { 0x007, 0 }, { 0x0ff, 0 }, { 0x11f, 0 }, { 0x005, 0 },
+ { 0x025, 0 }, { 0x112, 0 },
+ };
+ u16 save_phy_regs[14][2] = {
+ { 0x503, 0 }, { 0x4a4, 0 }, { 0x4d0, 0 }, { 0x4d9, 0 },
+ { 0x4da, 0 }, { 0x4a6, 0 }, { 0x938, 0 }, { 0x939, 0 },
+ { 0x4d8, 0 }, { 0x4d0, 0 }, { 0x4d7, 0 }, { 0x4a5, 0 },
+ { 0x40d, 0 }, { 0x4a2, 0 },
+ };
+ u16 save_radio_4a4;
+
+ msleep(1);
+
+ /* Save */
+ for (i = 0; i < 6; i++)
+ save_radio_regs[i][1] = b43_radio_read(dev,
+ save_radio_regs[i][0]);
+ for (i = 0; i < 14; i++)
+ save_phy_regs[i][1] = b43_phy_read(dev, save_phy_regs[i][0]);
+ b43_mac_suspend(dev);
+ save_radio_4a4 = b43_radio_read(dev, 0x4a4);
+ /* wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); */
+ tx_pwr_idx = dev->phy.lcn->tx_pwr_curr_idx;
+
+ /* Setup */
+ /* TODO: wlc_lcnphy_set_tx_pwr_by_index(pi, 127); */
+ b43_radio_set(dev, 0x007, 0x1);
+ b43_radio_set(dev, 0x0ff, 0x10);
+ b43_radio_set(dev, 0x11f, 0x4);
+
+ b43_phy_mask(dev, 0x503, ~0x1);
+ b43_phy_mask(dev, 0x503, ~0x4);
+ b43_phy_mask(dev, 0x4a4, ~0x4000);
+ b43_phy_mask(dev, 0x4a4, (u16) ~0x8000);
+ b43_phy_mask(dev, 0x4d0, ~0x20);
+ b43_phy_set(dev, 0x4a5, 0xff);
+ b43_phy_maskset(dev, 0x4a5, ~0x7000, 0x5000);
+ b43_phy_mask(dev, 0x4a5, ~0x700);
+ b43_phy_maskset(dev, 0x40d, ~0xff, 64);
+ b43_phy_maskset(dev, 0x40d, ~0x700, 0x600);
+ b43_phy_maskset(dev, 0x4a2, ~0xff, 64);
+ b43_phy_maskset(dev, 0x4a2, ~0x700, 0x600);
+ b43_phy_maskset(dev, 0x4d9, ~0x70, 0x20);
+ b43_phy_maskset(dev, 0x4d9, ~0x700, 0x300);
+ b43_phy_maskset(dev, 0x4d9, ~0x7000, 0x1000);
+ b43_phy_mask(dev, 0x4da, ~0x1000);
+ b43_phy_set(dev, 0x4da, 0x2000);
+ b43_phy_set(dev, 0x4a6, 0x8000);
+
+ b43_radio_write(dev, 0x025, 0xc);
+ b43_radio_set(dev, 0x005, 0x8);
+ b43_phy_set(dev, 0x938, 0x4);
+ b43_phy_set(dev, 0x939, 0x4);
+ b43_phy_set(dev, 0x4a4, 0x1000);
+
+ /* FIXME: don't hardcode */
+ b43_lcntab_write(dev, B43_LCNTAB16(0x8, 0x6), 0x640);
+
+ switch (sense_type) {
+ case B43_SENSE_TEMP:
+ b43_phy_set(dev, 0x4d7, 0x8);
+ b43_phy_maskset(dev, 0x4d7, ~0x7000, 0x1000);
+ auxpga_vmidcourse = 8;
+ auxpga_vmidfine = 0x4;
+ auxpga_gain = 2;
+ b43_radio_set(dev, 0x082, 0x20);
+ break;
+ case B43_SENSE_VBAT:
+ b43_phy_set(dev, 0x4d7, 0x8);
+ b43_phy_maskset(dev, 0x4d7, ~0x7000, 0x3000);
+ auxpga_vmidcourse = 7;
+ auxpga_vmidfine = 0xa;
+ auxpga_gain = 2;
+ break;
+ }
+ auxpga_vmid = (0x200 | (auxpga_vmidcourse << 4) | auxpga_vmidfine);
+
+ b43_phy_set(dev, 0x4d8, 0x1);
+ b43_phy_maskset(dev, 0x4d8, ~(0x3ff << 2), auxpga_vmid << 2);
+ b43_phy_set(dev, 0x4d8, 0x2);
+ b43_phy_maskset(dev, 0x4d8, ~(0x7 << 12), auxpga_gain << 12);
+ b43_phy_set(dev, 0x4d0, 0x20);
+ b43_radio_write(dev, 0x112, 0x6);
+
+ b43_dummy_transmission(dev, true, false);
+ /* Wait if not done */
+ if (!(b43_phy_read(dev, 0x476) & 0x8000))
+ udelay(10);
+
+ /* Restore */
+ for (i = 0; i < 6; i++)
+ b43_radio_write(dev, save_radio_regs[i][0],
+ save_radio_regs[i][1]);
+ for (i = 0; i < 14; i++)
+ b43_phy_write(dev, save_phy_regs[i][0], save_phy_regs[i][1]);
+ /* TODO: wlc_lcnphy_set_tx_pwr_by_index(tx_pwr_idx) */
+ b43_radio_write(dev, 0x4a4, save_radio_4a4);
+
+ b43_mac_enable(dev);
+
+ msleep(1);
+}
+
+static bool b43_phy_lcn_load_tx_iir_cck_filter(struct b43_wldev *dev,
+ u8 filter_type)
+{
+ int i, j;
+ u16 phy_regs[] = { 0x910, 0x91e, 0x91f, 0x924, 0x925, 0x926, 0x920,
+ 0x921, 0x927, 0x928, 0x929, 0x922, 0x923, 0x930,
+ 0x931, 0x932 };
+ /* Table is from brcmsmac, values for type 25 were outdated, probably
+ * others need updating too */
+ struct lcn_tx_iir_filter tx_iir_filters_cck[] = {
+ { 0, { 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778,
+ 1582, 64, 128, 64 } },
+ { 1, { 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608,
+ 1863, 93, 167, 93 } },
+ { 2, { 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192,
+ 778, 1582, 64, 128, 64 } },
+ { 3, { 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205,
+ 754, 1760, 170, 340, 170 } },
+ { 20, { 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205,
+ 767, 1760, 256, 185, 256 } },
+ { 21, { 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205,
+ 767, 1760, 256, 273, 256 } },
+ { 22, { 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205,
+ 767, 1760, 256, 352, 256 } },
+ { 23, { 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205,
+ 767, 1760, 128, 233, 128 } },
+ { 24, { 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766,
+ 1760, 256, 1881, 256 } },
+ { 25, { 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765,
+ 1760, 262, 1878, 262 } },
+ /* brcmsmac version { 25, { 1, 299, 1884, 51, 64, 51, 736, 1720,
+ * 256, 471, 256, 765, 1760, 256, 1881, 256 } }, */
+ { 26, { 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614,
+ 1864, 128, 384, 288 } },
+ { 27, { 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576,
+ 613, 1864, 128, 384, 288 } },
+ { 30, { 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205,
+ 754, 1760, 170, 340, 170 } },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(tx_iir_filters_cck); i++) {
+ if (tx_iir_filters_cck[i].type == filter_type) {
+ for (j = 0; j < 16; j++)
+ b43_phy_write(dev, phy_regs[j],
+ tx_iir_filters_cck[i].values[j]);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool b43_phy_lcn_load_tx_iir_ofdm_filter(struct b43_wldev *dev,
+ u8 filter_type)
+{
+ int i, j;
+ u16 phy_regs[] = { 0x90f, 0x900, 0x901, 0x906, 0x907, 0x908, 0x902,
+ 0x903, 0x909, 0x90a, 0x90b, 0x904, 0x905, 0x90c,
+ 0x90d, 0x90e };
+ struct lcn_tx_iir_filter tx_iir_filters_ofdm[] = {
+ { 0, { 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0,
+ 0x0, 0x278, 0xfea0, 0x80, 0x100, 0x80 } },
+ { 1, { 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50, 750,
+ 0xFE2B, 212, 0xFFCE, 212 } },
+ { 2, { 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748,
+ 0xFEF2, 128, 0xFFE2, 128 } },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(tx_iir_filters_ofdm); i++) {
+ if (tx_iir_filters_ofdm[i].type == filter_type) {
+ for (j = 0; j < 16; j++)
+ b43_phy_write(dev, phy_regs[j],
+ tx_iir_filters_ofdm[i].values[j]);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* wlc_lcnphy_set_tx_gain_override */
+static void b43_phy_lcn_set_tx_gain_override(struct b43_wldev *dev, bool enable)
+{
+ b43_phy_maskset(dev, 0x4b0, ~(0x1 << 7), enable << 7);
+ b43_phy_maskset(dev, 0x4b0, ~(0x1 << 14), enable << 14);
+ b43_phy_maskset(dev, 0x43b, ~(0x1 << 6), enable << 6);
+}
+
+/* wlc_lcnphy_set_tx_gain */
+static void b43_phy_lcn_set_tx_gain(struct b43_wldev *dev,
+ struct lcn_tx_gains *target_gains)
+{
+ u16 pa_gain = b43_phy_lcn_get_pa_gain(dev);
+
+ b43_phy_write(dev, 0x4b5,
+ (target_gains->gm_gain | (target_gains->pga_gain << 8)));
+ b43_phy_maskset(dev, 0x4fb, ~0x7fff,
+ (target_gains->pad_gain | (pa_gain << 8)));
+ b43_phy_write(dev, 0x4fc,
+ (target_gains->gm_gain | (target_gains->pga_gain << 8)));
+ b43_phy_maskset(dev, 0x4fd, ~0x7fff,
+ (target_gains->pad_gain | (pa_gain << 8)));
+
+ b43_phy_lcn_set_dac_gain(dev, target_gains->dac_gain);
+ b43_phy_lcn_set_tx_gain_override(dev, true);
+}
+
+/* wlc_lcnphy_tx_pwr_ctrl_init */
+static void b43_phy_lcn_tx_pwr_ctl_init(struct b43_wldev *dev)
+{
+ struct lcn_tx_gains tx_gains;
+ u8 bbmult;
+
+ b43_mac_suspend(dev);
+
+ if (!dev->phy.lcn->hw_pwr_ctl_capable) {
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ tx_gains.gm_gain = 4;
+ tx_gains.pga_gain = 12;
+ tx_gains.pad_gain = 12;
+ tx_gains.dac_gain = 0;
+ bbmult = 150;
+ } else {
+ tx_gains.gm_gain = 7;
+ tx_gains.pga_gain = 15;
+ tx_gains.pad_gain = 14;
+ tx_gains.dac_gain = 0;
+ bbmult = 150;
+ }
+ b43_phy_lcn_set_tx_gain(dev, &tx_gains);
+ b43_phy_lcn_set_bbmult(dev, bbmult);
+ b43_phy_lcn_sense_setup(dev, B43_SENSE_TEMP);
+ } else {
+ b43err(dev->wl, "TX power control not supported for this HW\n");
+ }
+
+ b43_mac_enable(dev);
+}
+
+/* wlc_lcnphy_txrx_spur_avoidance_mode */
+static void b43_phy_lcn_txrx_spur_avoidance_mode(struct b43_wldev *dev,
+ bool enable)
+{
+ if (enable) {
+ b43_phy_write(dev, 0x942, 0x7);
+ b43_phy_write(dev, 0x93b, ((1 << 13) + 23));
+ b43_phy_write(dev, 0x93c, ((1 << 13) + 1989));
+
+ b43_phy_write(dev, 0x44a, 0x084);
+ b43_phy_write(dev, 0x44a, 0x080);
+ b43_phy_write(dev, 0x6d3, 0x2222);
+ b43_phy_write(dev, 0x6d3, 0x2220);
+ } else {
+ b43_phy_write(dev, 0x942, 0x0);
+ b43_phy_write(dev, 0x93b, ((0 << 13) + 23));
+ b43_phy_write(dev, 0x93c, ((0 << 13) + 1989));
+ }
+ b43_phy_switch_macfreq(dev, enable);
+}
+
+/**************************************************
+ * Channel switching ops.
+ **************************************************/
+
+/* wlc_lcnphy_set_chanspec_tweaks */
+static void b43_phy_lcn_set_channel_tweaks(struct b43_wldev *dev, int channel)
+{
+ struct bcma_drv_cc *cc = &dev->dev->bdev->bus->drv_cc;
+
+ b43_phy_maskset(dev, 0x448, ~0x300, (channel == 14) ? 0x200 : 0x100);
+
+ if (channel == 1 || channel == 2 || channel == 3 || channel == 4 ||
+ channel == 9 || channel == 10 || channel == 11 || channel == 12) {
+ bcma_chipco_pll_write(cc, 0x2, 0x03000c04);
+ bcma_chipco_pll_maskset(cc, 0x3, 0x00ffffff, 0x0);
+ bcma_chipco_pll_write(cc, 0x4, 0x200005c0);
+
+ bcma_cc_set32(cc, BCMA_CC_PMU_CTL, 0x400);
+
+ b43_phy_write(dev, 0x942, 0);
+
+ b43_phy_lcn_txrx_spur_avoidance_mode(dev, false);
+ b43_phy_maskset(dev, 0x424, (u16) ~0xff00, 0x1b00);
+ b43_phy_write(dev, 0x425, 0x5907);
+ } else {
+ bcma_chipco_pll_write(cc, 0x2, 0x03140c04);
+ bcma_chipco_pll_maskset(cc, 0x3, 0x00ffffff, 0x333333);
+ bcma_chipco_pll_write(cc, 0x4, 0x202c2820);
+
+ bcma_cc_set32(cc, BCMA_CC_PMU_CTL, 0x400);
+
+ b43_phy_write(dev, 0x942, 0);
+
+ b43_phy_lcn_txrx_spur_avoidance_mode(dev, true);
+ b43_phy_maskset(dev, 0x424, (u16) ~0xff00, 0x1f00);
+ b43_phy_write(dev, 0x425, 0x590a);
+ }
+
+ b43_phy_set(dev, 0x44a, 0x44);
+ b43_phy_write(dev, 0x44a, 0x80);
+}
+
+/* wlc_phy_chanspec_set_lcnphy */
+static int b43_phy_lcn_set_channel(struct b43_wldev *dev,
+ struct ieee80211_channel *channel,
+ enum nl80211_channel_type channel_type)
+{
+ static const u16 sfo_cfg[14][2] = {
+ {965, 1087}, {967, 1085}, {969, 1082}, {971, 1080}, {973, 1078},
+ {975, 1076}, {977, 1073}, {979, 1071}, {981, 1069}, {983, 1067},
+ {985, 1065}, {987, 1063}, {989, 1060}, {994, 1055},
+ };
+
+ b43_phy_lcn_set_channel_tweaks(dev, channel->hw_value);
+
+ b43_phy_set(dev, 0x44a, 0x44);
+ b43_phy_write(dev, 0x44a, 0x80);
+
+ b43_radio_2064_channel_setup(dev);
+ mdelay(1);
+
+ b43_phy_lcn_afe_set_unset(dev);
+
+ b43_phy_write(dev, 0x657, sfo_cfg[channel->hw_value - 1][0]);
+ b43_phy_write(dev, 0x658, sfo_cfg[channel->hw_value - 1][1]);
+
+ if (channel->hw_value == 14) {
+ b43_phy_maskset(dev, 0x448, ~(0x3 << 8), (2) << 8);
+ b43_phy_lcn_load_tx_iir_cck_filter(dev, 3);
+ } else {
+ b43_phy_maskset(dev, 0x448, ~(0x3 << 8), (1) << 8);
+ /* brcmsmac uses filter_type 2, we follow wl with 25 */
+ b43_phy_lcn_load_tx_iir_cck_filter(dev, 25);
+ }
+ /* brcmsmac uses filter_type 2, we follow wl with 0 */
+ b43_phy_lcn_load_tx_iir_ofdm_filter(dev, 0);
+
+ b43_phy_maskset(dev, 0x4eb, ~(0x7 << 3), 0x1 << 3);
+
+ return 0;
+}
+
+/**************************************************
+ * Basic PHY ops.
+ **************************************************/
+
+static int b43_phy_lcn_op_allocate(struct b43_wldev *dev)
+{
+ struct b43_phy_lcn *phy_lcn;
+
+ phy_lcn = kzalloc(sizeof(*phy_lcn), GFP_KERNEL);
+ if (!phy_lcn)
+ return -ENOMEM;
+ dev->phy.lcn = phy_lcn;
+
+ return 0;
+}
+
+static void b43_phy_lcn_op_free(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_phy_lcn *phy_lcn = phy->lcn;
+
+ kfree(phy_lcn);
+ phy->lcn = NULL;
+}
+
+static void b43_phy_lcn_op_prepare_structs(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_phy_lcn *phy_lcn = phy->lcn;
+
+ memset(phy_lcn, 0, sizeof(*phy_lcn));
+}
+
+/* wlc_phy_init_lcnphy */
+static int b43_phy_lcn_op_init(struct b43_wldev *dev)
+{
+ struct bcma_drv_cc *cc = &dev->dev->bdev->bus->drv_cc;
+
+ b43_phy_set(dev, 0x44a, 0x80);
+ b43_phy_mask(dev, 0x44a, 0x7f);
+ b43_phy_set(dev, 0x6d1, 0x80);
+ b43_phy_write(dev, 0x6d0, 0x7);
+
+ b43_phy_lcn_afe_set_unset(dev);
+
+ b43_phy_write(dev, 0x60a, 0xa0);
+ b43_phy_write(dev, 0x46a, 0x19);
+ b43_phy_maskset(dev, 0x663, 0xFF00, 0x64);
+
+ b43_phy_lcn_tables_init(dev);
+
+ b43_phy_lcn_rev0_baseband_init(dev);
+ b43_phy_lcn_bu_tweaks(dev);
+
+ if (dev->phy.radio_ver == 0x2064)
+ b43_radio_2064_init(dev);
+ else
+ B43_WARN_ON(1);
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ b43_phy_lcn_tx_pwr_ctl_init(dev);
+
+ b43_switch_channel(dev, dev->phy.channel);
+
+ bcma_chipco_regctl_maskset(cc, 0, 0xf, 0x9);
+ bcma_chipco_chipctl_maskset(cc, 0, 0, 0x03cddddd);
+
+ /* TODO */
+
+ b43_phy_set(dev, 0x448, 0x4000);
+ udelay(100);
+ b43_phy_mask(dev, 0x448, ~0x4000);
+
+ /* TODO */
+
+ return 0;
+}
+
+static void b43_phy_lcn_op_software_rfkill(struct b43_wldev *dev,
+ bool blocked)
+{
+ if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED)
+ b43err(dev->wl, "MAC not suspended\n");
+
+ if (blocked) {
+ b43_phy_mask(dev, B43_PHY_LCN_RF_CTL2, ~0x7c00);
+ b43_phy_set(dev, B43_PHY_LCN_RF_CTL1, 0x1f00);
+
+ b43_phy_mask(dev, B43_PHY_LCN_RF_CTL5, ~0x7f00);
+ b43_phy_mask(dev, B43_PHY_LCN_RF_CTL4, ~0x2);
+ b43_phy_set(dev, B43_PHY_LCN_RF_CTL3, 0x808);
+
+ b43_phy_mask(dev, B43_PHY_LCN_RF_CTL7, ~0x8);
+ b43_phy_set(dev, B43_PHY_LCN_RF_CTL6, 0x8);
+ } else {
+ b43_phy_mask(dev, B43_PHY_LCN_RF_CTL1, ~0x1f00);
+ b43_phy_mask(dev, B43_PHY_LCN_RF_CTL3, ~0x808);
+ b43_phy_mask(dev, B43_PHY_LCN_RF_CTL6, ~0x8);
+ }
+}
+
+static void b43_phy_lcn_op_switch_analog(struct b43_wldev *dev, bool on)
+{
+ if (on) {
+ b43_phy_mask(dev, B43_PHY_LCN_AFE_CTL1, ~0x7);
+ } else {
+ b43_phy_set(dev, B43_PHY_LCN_AFE_CTL2, 0x7);
+ b43_phy_set(dev, B43_PHY_LCN_AFE_CTL1, 0x7);
+ }
+}
+
+static int b43_phy_lcn_op_switch_channel(struct b43_wldev *dev,
+ unsigned int new_channel)
+{
+ struct ieee80211_channel *channel = dev->wl->hw->conf.channel;
+ enum nl80211_channel_type channel_type = dev->wl->hw->conf.channel_type;
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ if ((new_channel < 1) || (new_channel > 14))
+ return -EINVAL;
+ } else {
+ return -EINVAL;
+ }
+
+ return b43_phy_lcn_set_channel(dev, channel, channel_type);
+}
+
+static unsigned int b43_phy_lcn_op_get_default_chan(struct b43_wldev *dev)
+{
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ return 1;
+ return 36;
+}
+
+static enum b43_txpwr_result
+b43_phy_lcn_op_recalc_txpower(struct b43_wldev *dev, bool ignore_tssi)
+{
+ return B43_TXPWR_RES_DONE;
+}
+
+static void b43_phy_lcn_op_adjust_txpower(struct b43_wldev *dev)
+{
+}
+
+/**************************************************
+ * R/W ops.
+ **************************************************/
+
+static u16 b43_phy_lcn_op_read(struct b43_wldev *dev, u16 reg)
+{
+ b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+ return b43_read16(dev, B43_MMIO_PHY_DATA);
+}
+
+static void b43_phy_lcn_op_write(struct b43_wldev *dev, u16 reg, u16 value)
+{
+ b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16(dev, B43_MMIO_PHY_DATA, value);
+}
+
+static void b43_phy_lcn_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
+ u16 set)
+{
+ b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16(dev, B43_MMIO_PHY_DATA,
+ (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
+}
+
+static u16 b43_phy_lcn_op_radio_read(struct b43_wldev *dev, u16 reg)
+{
+ /* LCN-PHY needs 0x200 for read access */
+ reg |= 0x200;
+
+ b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
+ return b43_read16(dev, B43_MMIO_RADIO24_DATA);
+}
+
+static void b43_phy_lcn_op_radio_write(struct b43_wldev *dev, u16 reg,
+ u16 value)
+{
+ b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
+ b43_write16(dev, B43_MMIO_RADIO24_DATA, value);
+}
+
/**************************************************
* PHY ops struct.
**************************************************/
const struct b43_phy_operations b43_phyops_lcn = {
- /*
.allocate = b43_phy_lcn_op_allocate,
.free = b43_phy_lcn_op_free,
.prepare_structs = b43_phy_lcn_op_prepare_structs,
@@ -48,5 +898,4 @@ const struct b43_phy_operations b43_phyops_lcn = {
.get_default_chan = b43_phy_lcn_op_get_default_chan,
.recalc_txpower = b43_phy_lcn_op_recalc_txpower,
.adjust_txpower = b43_phy_lcn_op_adjust_txpower,
- */
};
diff --git a/drivers/net/wireless/b43/phy_lcn.h b/drivers/net/wireless/b43/phy_lcn.h
index c046c2a6cab4..6a7092e13fff 100644
--- a/drivers/net/wireless/b43/phy_lcn.h
+++ b/drivers/net/wireless/b43/phy_lcn.h
@@ -4,11 +4,28 @@
#include "phy_common.h"
+#define B43_PHY_LCN_AFE_CTL1 B43_PHY_OFDM(0x03B)
+#define B43_PHY_LCN_AFE_CTL2 B43_PHY_OFDM(0x03C)
+#define B43_PHY_LCN_RF_CTL1 B43_PHY_OFDM(0x04C)
+#define B43_PHY_LCN_RF_CTL2 B43_PHY_OFDM(0x04D)
+#define B43_PHY_LCN_TABLE_ADDR B43_PHY_OFDM(0x055) /* Table address */
+#define B43_PHY_LCN_TABLE_DATALO B43_PHY_OFDM(0x056) /* Table data low */
+#define B43_PHY_LCN_TABLE_DATAHI B43_PHY_OFDM(0x057) /* Table data high */
+#define B43_PHY_LCN_RF_CTL3 B43_PHY_OFDM(0x0B0)
+#define B43_PHY_LCN_RF_CTL4 B43_PHY_OFDM(0x0B1)
+#define B43_PHY_LCN_RF_CTL5 B43_PHY_OFDM(0x0B7)
+#define B43_PHY_LCN_RF_CTL6 B43_PHY_OFDM(0x0F9)
+#define B43_PHY_LCN_RF_CTL7 B43_PHY_OFDM(0x0FA)
+
+
struct b43_phy_lcn {
+ bool hw_pwr_ctl;
+ bool hw_pwr_ctl_capable;
+ u8 tx_pwr_curr_idx;
};
struct b43_phy_operations;
extern const struct b43_phy_operations b43_phyops_lcn;
-#endif /* B43_PHY_LCN_H_ */ \ No newline at end of file
+#endif /* B43_PHY_LCN_H_ */
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c
index 3b46360da99b..b17d9b6c33a5 100644
--- a/drivers/net/wireless/b43/phy_n.c
+++ b/drivers/net/wireless/b43/phy_n.c
@@ -4,6 +4,7 @@
IEEE 802.11n PHY support
Copyright (c) 2008 Michael Buesch <m@bues.ch>
+ Copyright (c) 2010-2011 Rafał Miłecki <zajec5@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -77,6 +78,7 @@ enum b43_nphy_rssi_type {
B43_NPHY_RSSI_TBD,
};
+/* TODO: reorder functions */
static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev,
bool enable);
static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd,
@@ -87,6 +89,14 @@ static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field,
u16 value, u8 core, bool off);
static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field,
u16 value, u8 core);
+static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev);
+
+static inline bool b43_nphy_ipa(struct b43_wldev *dev)
+{
+ enum ieee80211_band band = b43_current_band(dev->wl);
+ return ((dev->phy.n->ipa2g_on && band == IEEE80211_BAND_2GHZ) ||
+ (dev->phy.n->ipa5g_on && band == IEEE80211_BAND_5GHZ));
+}
void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
{//TODO
@@ -248,15 +258,25 @@ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable)
{
struct b43_phy_n *nphy = dev->phy.n;
u8 i;
- u16 tmp;
+ u16 bmask, val, tmp;
+ enum ieee80211_band band = b43_current_band(dev->wl);
if (nphy->hang_avoid)
b43_nphy_stay_in_carrier_search(dev, 1);
nphy->txpwrctrl = enable;
if (!enable) {
- if (dev->phy.rev >= 3)
- ; /* TODO */
+ if (dev->phy.rev >= 3 &&
+ (b43_phy_read(dev, B43_NPHY_TXPCTL_CMD) &
+ (B43_NPHY_TXPCTL_CMD_COEFF |
+ B43_NPHY_TXPCTL_CMD_HWPCTLEN |
+ B43_NPHY_TXPCTL_CMD_PCTLEN))) {
+ /* We disable enabled TX pwr ctl, save it's state */
+ nphy->tx_pwr_idx[0] = b43_phy_read(dev,
+ B43_NPHY_C1_TXPCTL_STAT) & 0x7f;
+ nphy->tx_pwr_idx[1] = b43_phy_read(dev,
+ B43_NPHY_C2_TXPCTL_STAT) & 0x7f;
+ }
b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x6840);
for (i = 0; i < 84; i++)
@@ -285,10 +305,67 @@ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable)
b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
~B43_NPHY_BPHY_CTL3_SCALE, 0x5A);
- if (dev->phy.rev < 2 && 0)
- ; /* TODO */
+ if (dev->phy.rev < 2 && dev->phy.is_40mhz)
+ b43_hf_write(dev, b43_hf_read(dev) | B43_HF_TSSIRPSMW);
} else {
- b43err(dev->wl, "enabling tx pwr ctrl not implemented yet\n");
+ b43_ntab_write_bulk(dev, B43_NTAB16(26, 64), 84,
+ nphy->adj_pwr_tbl);
+ b43_ntab_write_bulk(dev, B43_NTAB16(27, 64), 84,
+ nphy->adj_pwr_tbl);
+
+ bmask = B43_NPHY_TXPCTL_CMD_COEFF |
+ B43_NPHY_TXPCTL_CMD_HWPCTLEN;
+ /* wl does useless check for "enable" param here */
+ val = B43_NPHY_TXPCTL_CMD_COEFF | B43_NPHY_TXPCTL_CMD_HWPCTLEN;
+ if (dev->phy.rev >= 3) {
+ bmask |= B43_NPHY_TXPCTL_CMD_PCTLEN;
+ if (val)
+ val |= B43_NPHY_TXPCTL_CMD_PCTLEN;
+ }
+ b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD, ~(bmask), val);
+
+ if (band == IEEE80211_BAND_5GHZ) {
+ b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD,
+ ~B43_NPHY_TXPCTL_CMD_INIT, 0x64);
+ if (dev->phy.rev > 1)
+ b43_phy_maskset(dev, B43_NPHY_TXPCTL_INIT,
+ ~B43_NPHY_TXPCTL_INIT_PIDXI1,
+ 0x64);
+ }
+
+ if (dev->phy.rev >= 3) {
+ if (nphy->tx_pwr_idx[0] != 128 &&
+ nphy->tx_pwr_idx[1] != 128) {
+ /* Recover TX pwr ctl state */
+ b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD,
+ ~B43_NPHY_TXPCTL_CMD_INIT,
+ nphy->tx_pwr_idx[0]);
+ if (dev->phy.rev > 1)
+ b43_phy_maskset(dev,
+ B43_NPHY_TXPCTL_INIT,
+ ~0xff, nphy->tx_pwr_idx[1]);
+ }
+ }
+
+ if (dev->phy.rev >= 3) {
+ b43_phy_mask(dev, B43_NPHY_AFECTL_OVER1, ~0x100);
+ b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, ~0x100);
+ } else {
+ b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, ~0x4000);
+ }
+
+ if (dev->phy.rev == 2)
+ b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, ~0xFF, 0x3b);
+ else if (dev->phy.rev < 2)
+ b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, ~0xFF, 0x40);
+
+ if (dev->phy.rev < 2 && dev->phy.is_40mhz)
+ b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_TSSIRPSMW);
+
+ if (b43_nphy_ipa(dev)) {
+ b43_phy_mask(dev, B43_NPHY_PAPD_EN0, ~0x4);
+ b43_phy_mask(dev, B43_NPHY_PAPD_EN1, ~0x4);
+ }
}
if (nphy->hang_avoid)
@@ -369,22 +446,23 @@ static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
else
b43_phy_write(dev, B43_NPHY_AFECTL_DACGAIN2, dac_gain);
- b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D10 + i);
- b43_phy_write(dev, B43_NPHY_TABLE_DATALO, radio_gain);
-
- b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x3C57);
- tmp = b43_phy_read(dev, B43_NPHY_TABLE_DATALO);
+ b43_ntab_write(dev, B43_NTAB16(0x7, 0x110 + i), radio_gain);
+ tmp = b43_ntab_read(dev, B43_NTAB16(0xF, 0x57));
if (i == 0)
tmp = (tmp & 0x00FF) | (bbmult << 8);
else
tmp = (tmp & 0xFF00) | bbmult;
-
- b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x3C57);
- b43_phy_write(dev, B43_NPHY_TABLE_DATALO, tmp);
-
- if (0)
- ; /* TODO */
+ b43_ntab_write(dev, B43_NTAB16(0xF, 0x57), tmp);
+
+ if (b43_nphy_ipa(dev)) {
+ u32 tmp32;
+ u16 reg = (i == 0) ?
+ B43_NPHY_PAPD_EN0 : B43_NPHY_PAPD_EN1;
+ tmp32 = b43_ntab_read(dev, B43_NTAB32(26 + i, txpi[i]));
+ b43_phy_maskset(dev, reg, 0xE00F, (u32) tmp32 << 4);
+ b43_phy_set(dev, reg, 0x4);
+ }
}
b43_phy_mask(dev, B43_NPHY_BPHY_CTL2, ~B43_NPHY_BPHY_CTL2_LUT);
@@ -393,6 +471,57 @@ static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
b43_nphy_stay_in_carrier_search(dev, 0);
}
+static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ const u32 *table = NULL;
+#if 0
+ TODO: b43_ntab_papd_pga_gain_delta_ipa_2*
+ u32 rfpwr_offset;
+ u8 pga_gain;
+ int i;
+#endif
+
+ if (phy->rev >= 3) {
+ if (b43_nphy_ipa(dev)) {
+ table = b43_nphy_get_ipa_gain_table(dev);
+ } else {
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+ if (phy->rev == 3)
+ table = b43_ntab_tx_gain_rev3_5ghz;
+ if (phy->rev == 4)
+ table = b43_ntab_tx_gain_rev4_5ghz;
+ else
+ table = b43_ntab_tx_gain_rev5plus_5ghz;
+ } else {
+ table = b43_ntab_tx_gain_rev3plus_2ghz;
+ }
+ }
+ } else {
+ table = b43_ntab_tx_gain_rev0_1_2;
+ }
+ b43_ntab_write_bulk(dev, B43_NTAB32(26, 192), 128, table);
+ b43_ntab_write_bulk(dev, B43_NTAB32(27, 192), 128, table);
+
+ if (phy->rev >= 3) {
+#if 0
+ nphy->gmval = (table[0] >> 16) & 0x7000;
+
+ for (i = 0; i < 128; i++) {
+ pga_gain = (table[i] >> 24) & 0xF;
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ rfpwr_offset = b43_ntab_papd_pga_gain_delta_ipa_2g[pga_gain];
+ else
+ rfpwr_offset = b43_ntab_papd_pga_gain_delta_ipa_5g[pga_gain];
+ b43_ntab_write(dev, B43_NTAB32(26, 576 + i),
+ rfpwr_offset);
+ b43_ntab_write(dev, B43_NTAB32(27, 576 + i),
+ rfpwr_offset);
+ }
+#endif
+ }
+}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/Radio/2055Setup */
static void b43_radio_2055_setup(struct b43_wldev *dev,
@@ -581,14 +710,10 @@ static void b43_nphy_pa_override(struct b43_wldev *dev, bool enable)
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxLpFbw */
static void b43_nphy_tx_lp_fbw(struct b43_wldev *dev)
{
- struct b43_phy_n *nphy = dev->phy.n;
u16 tmp;
- enum ieee80211_band band = b43_current_band(dev->wl);
- bool ipa = (nphy->ipa2g_on && band == IEEE80211_BAND_2GHZ) ||
- (nphy->ipa5g_on && band == IEEE80211_BAND_5GHZ);
if (dev->phy.rev >= 3) {
- if (ipa) {
+ if (b43_nphy_ipa(dev)) {
tmp = 4;
b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S2,
(((((tmp << 3) | tmp) << 3) | tmp) << 3) | tmp);
@@ -600,49 +725,17 @@ static void b43_nphy_tx_lp_fbw(struct b43_wldev *dev)
}
}
-/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */
-static void b43_nphy_bmac_clock_fgc(struct b43_wldev *dev, bool force)
-{
- u32 tmp;
-
- if (dev->phy.type != B43_PHYTYPE_N)
- return;
-
- switch (dev->dev->bus_type) {
-#ifdef CONFIG_B43_BCMA
- case B43_BUS_BCMA:
- tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
- if (force)
- tmp |= BCMA_IOCTL_FGC;
- else
- tmp &= ~BCMA_IOCTL_FGC;
- bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
- break;
-#endif
-#ifdef CONFIG_B43_SSB
- case B43_BUS_SSB:
- tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
- if (force)
- tmp |= SSB_TMSLOW_FGC;
- else
- tmp &= ~SSB_TMSLOW_FGC;
- ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
- break;
-#endif
- }
-}
-
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CCA */
static void b43_nphy_reset_cca(struct b43_wldev *dev)
{
u16 bbcfg;
- b43_nphy_bmac_clock_fgc(dev, 1);
+ b43_phy_force_clock(dev, 1);
bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG);
b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg | B43_NPHY_BBCFG_RSTCCA);
udelay(1);
b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg & ~B43_NPHY_BBCFG_RSTCCA);
- b43_nphy_bmac_clock_fgc(dev, 0);
+ b43_phy_force_clock(dev, 0);
b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
}
@@ -931,11 +1024,7 @@ static void b43_nphy_calc_rx_iq_comp(struct b43_wldev *dev, u8 mask)
static void b43_nphy_tx_iq_workaround(struct b43_wldev *dev)
{
u16 array[4];
- int i;
-
- b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x3C50);
- for (i = 0; i < 4; i++)
- array[i] = b43_phy_read(dev, B43_NPHY_TABLE_DATALO);
+ b43_ntab_read_bulk(dev, B43_NTAB16(0xF, 0x50), 4, array);
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW0, array[0]);
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW1, array[1]);
@@ -1398,180 +1487,220 @@ static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev)
}
}
-/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Workarounds */
-static void b43_nphy_workarounds(struct b43_wldev *dev)
+static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
{
+ struct b43_phy_n *nphy = dev->phy.n;
struct ssb_sprom *sprom = dev->dev->bus_sprom;
- struct b43_phy *phy = &dev->phy;
- struct b43_phy_n *nphy = phy->n;
-
- u8 events1[7] = { 0x0, 0x1, 0x2, 0x8, 0x4, 0x5, 0x3 };
- u8 delays1[7] = { 0x8, 0x6, 0x6, 0x2, 0x4, 0x3C, 0x1 };
- u8 events2[7] = { 0x0, 0x3, 0x5, 0x4, 0x2, 0x1, 0x8 };
- u8 delays2[7] = { 0x8, 0x6, 0x2, 0x4, 0x4, 0x6, 0x1 };
+ /* TX to RX */
+ u8 tx2rx_events[9] = { 0x4, 0x3, 0x6, 0x5, 0x2, 0x1, 0x8, 0x1F };
+ u8 tx2rx_delays[9] = { 8, 4, 2, 2, 4, 4, 6, 1 };
+ /* RX to TX */
+ u8 rx2tx_events_ipa[9] = { 0x0, 0x1, 0x2, 0x8, 0x5, 0x6, 0xF, 0x3,
+ 0x1F };
+ u8 rx2tx_delays_ipa[9] = { 8, 6, 6, 4, 4, 16, 43, 1, 1 };
+ u8 rx2tx_events[9] = { 0x0, 0x1, 0x2, 0x8, 0x5, 0x6, 0x3, 0x4, 0x1F };
+ u8 rx2tx_delays[9] = { 8, 6, 6, 4, 4, 18, 42, 1, 1 };
u16 tmp16;
u32 tmp32;
- if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
- b43_nphy_classifier(dev, 1, 0);
- else
- b43_nphy_classifier(dev, 1, 1);
+ tmp32 = b43_ntab_read(dev, B43_NTAB32(30, 0));
+ tmp32 &= 0xffffff;
+ b43_ntab_write(dev, B43_NTAB32(30, 0), tmp32);
+
+ b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x0125);
+ b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x01B3);
+ b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x0105);
+ b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x016E);
+ b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0x00CD);
+ b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x0020);
+
+ b43_phy_write(dev, B43_NPHY_C2_CLIP1_MEDGAIN, 0x000C);
+ b43_phy_write(dev, 0x2AE, 0x000C);
+
+ /* TX to RX */
+ b43_nphy_set_rf_sequence(dev, 1, tx2rx_events, tx2rx_delays, 9);
+
+ /* RX to TX */
+ if (b43_nphy_ipa(dev))
+ b43_nphy_set_rf_sequence(dev, 1, rx2tx_events_ipa,
+ rx2tx_delays_ipa, 9);
+ if (nphy->hw_phyrxchain != 3 &&
+ nphy->hw_phyrxchain != nphy->hw_phytxchain) {
+ if (b43_nphy_ipa(dev)) {
+ rx2tx_delays[5] = 59;
+ rx2tx_delays[6] = 1;
+ rx2tx_events[7] = 0x1F;
+ }
+ b43_nphy_set_rf_sequence(dev, 1, rx2tx_events, rx2tx_delays, 9);
+ }
- if (nphy->hang_avoid)
- b43_nphy_stay_in_carrier_search(dev, 1);
+ tmp16 = (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) ?
+ 0x2 : 0x9C40;
+ b43_phy_write(dev, B43_NPHY_ENDROP_TLEN, tmp16);
- b43_phy_set(dev, B43_NPHY_IQFLIP,
- B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2);
+ b43_phy_maskset(dev, 0x294, 0xF0FF, 0x0700);
- if (dev->phy.rev >= 3) {
- tmp32 = b43_ntab_read(dev, B43_NTAB32(30, 0));
- tmp32 &= 0xffffff;
- b43_ntab_write(dev, B43_NTAB32(30, 0), tmp32);
+ b43_ntab_write(dev, B43_NTAB32(16, 3), 0x18D);
+ b43_ntab_write(dev, B43_NTAB32(16, 127), 0x18D);
- b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x0125);
- b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x01B3);
- b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x0105);
- b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x016E);
- b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0x00CD);
- b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x0020);
+ b43_nphy_gain_ctrl_workarounds(dev);
- b43_phy_write(dev, B43_NPHY_C2_CLIP1_MEDGAIN, 0x000C);
- b43_phy_write(dev, 0x2AE, 0x000C);
+ b43_ntab_write(dev, B43_NTAB32(8, 0), 2);
+ b43_ntab_write(dev, B43_NTAB32(8, 16), 2);
- /* TODO */
+ /* TODO */
- tmp16 = (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) ?
- 0x2 : 0x9C40;
- b43_phy_write(dev, B43_NPHY_ENDROP_TLEN, tmp16);
+ b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXA_MAST_BIAS, 0x00);
+ b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXA_MAST_BIAS, 0x00);
+ b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXA_BIAS_MAIN, 0x06);
+ b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXA_BIAS_MAIN, 0x06);
+ b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXA_BIAS_AUX, 0x07);
+ b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXA_BIAS_AUX, 0x07);
+ b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXA_LOB_BIAS, 0x88);
+ b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXA_LOB_BIAS, 0x88);
+ b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXG_CMFB_IDAC, 0x00);
+ b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXG_CMFB_IDAC, 0x00);
+
+ /* N PHY WAR TX Chain Update with hw_phytxchain as argument */
+
+ if ((sprom->boardflags2_lo & B43_BFL2_APLL_WAR &&
+ b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ||
+ (sprom->boardflags2_lo & B43_BFL2_GPLL_WAR &&
+ b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ))
+ tmp32 = 0x00088888;
+ else
+ tmp32 = 0x88888888;
+ b43_ntab_write(dev, B43_NTAB32(30, 1), tmp32);
+ b43_ntab_write(dev, B43_NTAB32(30, 2), tmp32);
+ b43_ntab_write(dev, B43_NTAB32(30, 3), tmp32);
+
+ if (dev->phy.rev == 4 &&
+ b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+ b43_radio_write(dev, B2056_TX0 | B2056_TX_GMBB_IDAC,
+ 0x70);
+ b43_radio_write(dev, B2056_TX1 | B2056_TX_GMBB_IDAC,
+ 0x70);
+ }
- b43_phy_maskset(dev, 0x294, 0xF0FF, 0x0700);
+ b43_phy_write(dev, 0x224, 0x039C);
+ b43_phy_write(dev, 0x225, 0x0357);
+ b43_phy_write(dev, 0x226, 0x0317);
+ b43_phy_write(dev, 0x227, 0x02D7);
+ b43_phy_write(dev, 0x228, 0x039C);
+ b43_phy_write(dev, 0x229, 0x0357);
+ b43_phy_write(dev, 0x22A, 0x0317);
+ b43_phy_write(dev, 0x22B, 0x02D7);
+ b43_phy_write(dev, 0x22C, 0x039C);
+ b43_phy_write(dev, 0x22D, 0x0357);
+ b43_phy_write(dev, 0x22E, 0x0317);
+ b43_phy_write(dev, 0x22F, 0x02D7);
+}
- b43_ntab_write(dev, B43_NTAB32(16, 3), 0x18D);
- b43_ntab_write(dev, B43_NTAB32(16, 127), 0x18D);
+static void b43_nphy_workarounds_rev1_2(struct b43_wldev *dev)
+{
+ struct ssb_sprom *sprom = dev->dev->bus_sprom;
+ struct b43_phy *phy = &dev->phy;
+ struct b43_phy_n *nphy = phy->n;
- b43_nphy_gain_ctrl_workarounds(dev);
+ u8 events1[7] = { 0x0, 0x1, 0x2, 0x8, 0x4, 0x5, 0x3 };
+ u8 delays1[7] = { 0x8, 0x6, 0x6, 0x2, 0x4, 0x3C, 0x1 };
- b43_ntab_write(dev, B43_NTAB32(8, 0), 2);
- b43_ntab_write(dev, B43_NTAB32(8, 16), 2);
+ u8 events2[7] = { 0x0, 0x3, 0x5, 0x4, 0x2, 0x1, 0x8 };
+ u8 delays2[7] = { 0x8, 0x6, 0x2, 0x4, 0x4, 0x6, 0x1 };
- /* TODO */
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ &&
+ nphy->band5g_pwrgain) {
+ b43_radio_mask(dev, B2055_C1_TX_RF_SPARE, ~0x8);
+ b43_radio_mask(dev, B2055_C2_TX_RF_SPARE, ~0x8);
+ } else {
+ b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8);
+ b43_radio_set(dev, B2055_C2_TX_RF_SPARE, 0x8);
+ }
- b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXA_MAST_BIAS, 0x00);
- b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXA_MAST_BIAS, 0x00);
- b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXA_BIAS_MAIN, 0x06);
- b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXA_BIAS_MAIN, 0x06);
- b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXA_BIAS_AUX, 0x07);
- b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXA_BIAS_AUX, 0x07);
- b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXA_LOB_BIAS, 0x88);
- b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXA_LOB_BIAS, 0x88);
- b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXG_CMFB_IDAC, 0x00);
- b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXG_CMFB_IDAC, 0x00);
-
- /* N PHY WAR TX Chain Update with hw_phytxchain as argument */
-
- if ((sprom->boardflags2_lo & B43_BFL2_APLL_WAR &&
- b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ||
- (sprom->boardflags2_lo & B43_BFL2_GPLL_WAR &&
- b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ))
- tmp32 = 0x00088888;
- else
- tmp32 = 0x88888888;
- b43_ntab_write(dev, B43_NTAB32(30, 1), tmp32);
- b43_ntab_write(dev, B43_NTAB32(30, 2), tmp32);
- b43_ntab_write(dev, B43_NTAB32(30, 3), tmp32);
-
- if (dev->phy.rev == 4 &&
- b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
- b43_radio_write(dev, B2056_TX0 | B2056_TX_GMBB_IDAC,
- 0x70);
- b43_radio_write(dev, B2056_TX1 | B2056_TX_GMBB_IDAC,
- 0x70);
- }
+ b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0x000A);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0x000A);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA);
- b43_phy_write(dev, 0x224, 0x039C);
- b43_phy_write(dev, 0x225, 0x0357);
- b43_phy_write(dev, 0x226, 0x0317);
- b43_phy_write(dev, 0x227, 0x02D7);
- b43_phy_write(dev, 0x228, 0x039C);
- b43_phy_write(dev, 0x229, 0x0357);
- b43_phy_write(dev, 0x22A, 0x0317);
- b43_phy_write(dev, 0x22B, 0x02D7);
- b43_phy_write(dev, 0x22C, 0x039C);
- b43_phy_write(dev, 0x22D, 0x0357);
- b43_phy_write(dev, 0x22E, 0x0317);
- b43_phy_write(dev, 0x22F, 0x02D7);
- } else {
- if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ &&
- nphy->band5g_pwrgain) {
- b43_radio_mask(dev, B2055_C1_TX_RF_SPARE, ~0x8);
- b43_radio_mask(dev, B2055_C2_TX_RF_SPARE, ~0x8);
- } else {
- b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8);
- b43_radio_set(dev, B2055_C2_TX_RF_SPARE, 0x8);
- }
+ if (dev->phy.rev < 2) {
+ b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0x0000);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x18), 0x0000);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x07), 0x7AAB);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x17), 0x7AAB);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x06), 0x0800);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x16), 0x0800);
+ }
- b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0x000A);
- b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0x000A);
- b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA);
- b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA);
+ b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8);
+ b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301);
+ b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
+ b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
- if (dev->phy.rev < 2) {
- b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0x0000);
- b43_ntab_write(dev, B43_NTAB16(8, 0x18), 0x0000);
- b43_ntab_write(dev, B43_NTAB16(8, 0x07), 0x7AAB);
- b43_ntab_write(dev, B43_NTAB16(8, 0x17), 0x7AAB);
- b43_ntab_write(dev, B43_NTAB16(8, 0x06), 0x0800);
- b43_ntab_write(dev, B43_NTAB16(8, 0x16), 0x0800);
- }
+ if (sprom->boardflags2_lo & B43_BFL2_SKWRKFEM_BRD &&
+ dev->dev->board_type == 0x8B) {
+ delays1[0] = 0x1;
+ delays1[5] = 0x14;
+ }
+ b43_nphy_set_rf_sequence(dev, 0, events1, delays1, 7);
+ b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7);
- b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8);
- b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301);
- b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
- b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
+ b43_nphy_gain_ctrl_workarounds(dev);
- if (sprom->boardflags2_lo & 0x100 &&
- dev->dev->board_type == 0x8B) {
- delays1[0] = 0x1;
- delays1[5] = 0x14;
- }
- b43_nphy_set_rf_sequence(dev, 0, events1, delays1, 7);
- b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7);
+ if (dev->phy.rev < 2) {
+ if (b43_phy_read(dev, B43_NPHY_RXCTL) & 0x2)
+ b43_hf_write(dev, b43_hf_read(dev) |
+ B43_HF_MLADVW);
+ } else if (dev->phy.rev == 2) {
+ b43_phy_write(dev, B43_NPHY_CRSCHECK2, 0);
+ b43_phy_write(dev, B43_NPHY_CRSCHECK3, 0);
+ }
- b43_nphy_gain_ctrl_workarounds(dev);
+ if (dev->phy.rev < 2)
+ b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL,
+ ~B43_NPHY_SCRAM_SIGCTL_SCM);
+
+ /* Set phase track alpha and beta */
+ b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125);
+ b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3);
+ b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105);
+ b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E);
+ b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD);
+ b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
+
+ b43_phy_mask(dev, B43_NPHY_PIL_DW1,
+ ~B43_NPHY_PIL_DW_64QAM & 0xFFFF);
+ b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B1, 0xB5);
+ b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B2, 0xA4);
+ b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B3, 0x00);
+
+ if (dev->phy.rev == 2)
+ b43_phy_set(dev, B43_NPHY_FINERX2_CGC,
+ B43_NPHY_FINERX2_CGC_DECGC);
+}
- if (dev->phy.rev < 2) {
- if (b43_phy_read(dev, B43_NPHY_RXCTL) & 0x2)
- b43_hf_write(dev, b43_hf_read(dev) |
- B43_HF_MLADVW);
- } else if (dev->phy.rev == 2) {
- b43_phy_write(dev, B43_NPHY_CRSCHECK2, 0);
- b43_phy_write(dev, B43_NPHY_CRSCHECK3, 0);
- }
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Workarounds */
+static void b43_nphy_workarounds(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_phy_n *nphy = phy->n;
- if (dev->phy.rev < 2)
- b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL,
- ~B43_NPHY_SCRAM_SIGCTL_SCM);
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
+ b43_nphy_classifier(dev, 1, 0);
+ else
+ b43_nphy_classifier(dev, 1, 1);
- /* Set phase track alpha and beta */
- b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125);
- b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3);
- b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105);
- b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E);
- b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD);
- b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
+ if (nphy->hang_avoid)
+ b43_nphy_stay_in_carrier_search(dev, 1);
- b43_phy_mask(dev, B43_NPHY_PIL_DW1,
- ~B43_NPHY_PIL_DW_64QAM & 0xFFFF);
- b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B1, 0xB5);
- b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B2, 0xA4);
- b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B3, 0x00);
+ b43_phy_set(dev, B43_NPHY_IQFLIP,
+ B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2);
- if (dev->phy.rev == 2)
- b43_phy_set(dev, B43_NPHY_FINERX2_CGC,
- B43_NPHY_FINERX2_CGC_DECGC);
- }
+ if (dev->phy.rev >= 3)
+ b43_nphy_workarounds_rev3plus(dev);
+ else
+ b43_nphy_workarounds_rev1_2(dev);
if (nphy->hang_avoid)
b43_nphy_stay_in_carrier_search(dev, 0);
@@ -2167,7 +2296,6 @@ static void b43_nphy_rev2_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
{
- struct b43_phy_n *nphy = dev->phy.n;
u8 i;
u16 reg, val;
@@ -2231,10 +2359,7 @@ static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
enum ieee80211_band band =
b43_current_band(dev->wl);
- if ((nphy->ipa2g_on &&
- band == IEEE80211_BAND_2GHZ) ||
- (nphy->ipa5g_on &&
- band == IEEE80211_BAND_5GHZ))
+ if (b43_nphy_ipa(dev))
val = (band == IEEE80211_BAND_5GHZ) ? 0xC : 0xE;
else
val = 0x11;
@@ -2609,8 +2734,8 @@ static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev)
{
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
if (dev->phy.rev >= 6) {
- /* TODO If the chip is 47162
- return txpwrctrl_tx_gain_ipa_rev5 */
+ if (dev->dev->chip_id == 47162)
+ return txpwrctrl_tx_gain_ipa_rev5;
return txpwrctrl_tx_gain_ipa_rev6;
} else if (dev->phy.rev >= 5) {
return txpwrctrl_tx_gain_ipa_rev5;
@@ -2860,10 +2985,7 @@ static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev)
enum ieee80211_band band =
b43_current_band(dev->wl);
- if ((nphy->ipa2g_on &&
- band == IEEE80211_BAND_2GHZ) ||
- (nphy->ipa5g_on &&
- band == IEEE80211_BAND_5GHZ)) {
+ if (b43_nphy_ipa(dev)) {
table = b43_nphy_get_ipa_gain_table(dev);
} else {
if (band == IEEE80211_BAND_5GHZ) {
@@ -3680,7 +3802,7 @@ int b43_phy_initn(struct b43_wldev *dev)
b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20);
b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20);
- if (sprom->boardflags2_lo & 0x100 ||
+ if (sprom->boardflags2_lo & B43_BFL2_SKWRKFEM_BRD ||
(dev->dev->board_vendor == PCI_VENDOR_ID_APPLE &&
dev->dev->board_type == 0x8B))
b43_phy_write(dev, B43_NPHY_TXREALFD, 0xA0);
@@ -3699,8 +3821,7 @@ int b43_phy_initn(struct b43_wldev *dev)
}
tmp2 = b43_current_band(dev->wl);
- if ((nphy->ipa2g_on && tmp2 == IEEE80211_BAND_2GHZ) ||
- (nphy->ipa5g_on && tmp2 == IEEE80211_BAND_5GHZ)) {
+ if (b43_nphy_ipa(dev)) {
b43_phy_set(dev, B43_NPHY_PAPD_EN0, 0x1);
b43_phy_maskset(dev, B43_NPHY_EPS_TABLE_ADJ0, 0x007F,
nphy->papd_epsilon_offset[0] << 7);
@@ -3715,11 +3836,11 @@ int b43_phy_initn(struct b43_wldev *dev)
b43_nphy_workarounds(dev);
/* Reset CCA, in init code it differs a little from standard way */
- b43_nphy_bmac_clock_fgc(dev, 1);
+ b43_phy_force_clock(dev, 1);
tmp = b43_phy_read(dev, B43_NPHY_BBCFG);
b43_phy_write(dev, B43_NPHY_BBCFG, tmp | B43_NPHY_BBCFG_RSTCCA);
b43_phy_write(dev, B43_NPHY_BBCFG, tmp & ~B43_NPHY_BBCFG_RSTCCA);
- b43_nphy_bmac_clock_fgc(dev, 0);
+ b43_phy_force_clock(dev, 0);
b43_mac_phy_clock_set(dev, true);
@@ -3738,15 +3859,7 @@ int b43_phy_initn(struct b43_wldev *dev)
b43_nphy_tx_power_fix(dev);
/* TODO N PHY TX Power Control Idle TSSI */
/* TODO N PHY TX Power Control Setup */
-
- if (phy->rev >= 3) {
- /* TODO */
- } else {
- b43_ntab_write_bulk(dev, B43_NTAB32(26, 192), 128,
- b43_ntab_tx_gain_rev0_1_2);
- b43_ntab_write_bulk(dev, B43_NTAB32(27, 192), 128,
- b43_ntab_tx_gain_rev0_1_2);
- }
+ b43_nphy_tx_gain_table_upload(dev);
if (nphy->phyrxchain != 3)
b43_nphy_set_rx_core_state(dev, nphy->phyrxchain);
@@ -3950,6 +4063,10 @@ static void b43_nphy_op_prepare_structs(struct b43_wldev *dev)
nphy->txrx_chain = 2; /* sth different than 0 and 1 for now */
nphy->phyrxchain = 3; /* to avoid b43_nphy_set_rx_core_state like wl */
nphy->perical = 2; /* avoid additional rssi cal on init (like wl) */
+ /* 128 can mean disabled-by-default state of TX pwr ctl. Max value is
+ * 0x7f == 127 and we check for 128 when restoring TX pwr ctl. */
+ nphy->tx_pwr_idx[0] = 128;
+ nphy->tx_pwr_idx[1] = 128;
}
static void b43_nphy_op_free(struct b43_wldev *dev)
diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h
index e789a89f1047..fbf520285bd1 100644
--- a/drivers/net/wireless/b43/phy_n.h
+++ b/drivers/net/wireless/b43/phy_n.h
@@ -764,6 +764,8 @@ struct b43_phy_n {
u8 cal_orig_pwr_idx[2];
u8 measure_hold;
u8 phyrxchain;
+ u8 hw_phyrxchain;
+ u8 hw_phytxchain;
u8 perical;
u32 deaf_count;
u32 rxcalparams;
@@ -783,6 +785,8 @@ struct b43_phy_n {
u16 mphase_txcal_bestcoeffs[11];
bool txpwrctrl;
+ u8 tx_pwr_idx[2];
+ u16 adj_pwr_tbl[84];
u16 txcal_bbmult;
u16 txiqlocal_bestc[11];
bool txiqlocal_coeffsvalid;
diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c
index 6e4228c3ed1b..fcff923b3c18 100644
--- a/drivers/net/wireless/b43/pio.c
+++ b/drivers/net/wireless/b43/pio.c
@@ -611,7 +611,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q)
struct b43_wldev *dev = q->dev;
struct b43_wl *wl = dev->wl;
u16 len;
- u32 macstat;
+ u32 macstat = 0;
unsigned int i, padding;
struct sk_buff *skb;
const char *err_msg = NULL;
@@ -676,7 +676,15 @@ data_ready:
goto rx_error;
}
- macstat = le32_to_cpu(rxhdr->mac_status);
+ switch (dev->fw.hdr_format) {
+ case B43_FW_HDR_598:
+ macstat = le32_to_cpu(rxhdr->format_598.mac_status);
+ break;
+ case B43_FW_HDR_410:
+ case B43_FW_HDR_351:
+ macstat = le32_to_cpu(rxhdr->format_351.mac_status);
+ break;
+ }
if (macstat & B43_RX_MAC_FCSERR) {
if (!(q->dev->wl->filter_flags & FIF_FCSFAIL)) {
/* Drop frames with failed FCS. */
diff --git a/drivers/net/wireless/b43/radio_2055.c b/drivers/net/wireless/b43/radio_2055.c
index 93643f18c2b3..5289a18ddd8c 100644
--- a/drivers/net/wireless/b43/radio_2055.c
+++ b/drivers/net/wireless/b43/radio_2055.c
@@ -4,6 +4,7 @@
IEEE 802.11n PHY and radio device data tables
Copyright (c) 2008 Michael Buesch <m@bues.ch>
+ Copyright (c) 2010 Rafał Miłecki <zajec5@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/drivers/net/wireless/b43/radio_2056.c b/drivers/net/wireless/b43/radio_2056.c
index 8890df067029..a01f776ca4de 100644
--- a/drivers/net/wireless/b43/radio_2056.c
+++ b/drivers/net/wireless/b43/radio_2056.c
@@ -3,6 +3,8 @@
Broadcom B43 wireless driver
IEEE 802.11n 2056 radio device data tables
+ Copyright (c) 2010 Rafał Miłecki <zajec5@gmail.com>
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
diff --git a/drivers/net/wireless/b43/radio_2056.h b/drivers/net/wireless/b43/radio_2056.h
index d52df6be705a..a7159d8578be 100644
--- a/drivers/net/wireless/b43/radio_2056.h
+++ b/drivers/net/wireless/b43/radio_2056.h
@@ -1,29 +1,3 @@
-/*
-
- Broadcom B43 wireless driver
-
- Copyright (c) 2010 Rafał Miłecki <zajec5@gmail.com>
-
- Some parts of the code in this file are derived from the brcm80211
- driver Copyright (c) 2010 Broadcom Corporation
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
- Boston, MA 02110-1301, USA.
-
-*/
-
#ifndef B43_RADIO_2056_H_
#define B43_RADIO_2056_H_
diff --git a/drivers/net/wireless/b43/radio_2059.c b/drivers/net/wireless/b43/radio_2059.c
index f029f6e1f5d1..d4ce8a12ff9a 100644
--- a/drivers/net/wireless/b43/radio_2059.c
+++ b/drivers/net/wireless/b43/radio_2059.c
@@ -3,6 +3,8 @@
Broadcom B43 wireless driver
IEEE 802.11n 2059 radio device data tables
+ Copyright (c) 2011 Rafał Miłecki <zajec5@gmail.com>
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c
index 916f238a71df..7b326f2efdc9 100644
--- a/drivers/net/wireless/b43/tables_nphy.c
+++ b/drivers/net/wireless/b43/tables_nphy.c
@@ -4,6 +4,7 @@
IEEE 802.11n PHY data tables
Copyright (c) 2008 Michael Buesch <m@bues.ch>
+ Copyright (c) 2010 Rafał Miłecki <zajec5@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/drivers/net/wireless/b43/tables_phy_ht.c b/drivers/net/wireless/b43/tables_phy_ht.c
index 603938657b15..176c49d74ef4 100644
--- a/drivers/net/wireless/b43/tables_phy_ht.c
+++ b/drivers/net/wireless/b43/tables_phy_ht.c
@@ -3,6 +3,8 @@
Broadcom B43 wireless driver
IEEE 802.11n HT-PHY data tables
+ Copyright (c) 2011 Rafał Miłecki <zajec5@gmail.com>
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -574,6 +576,42 @@ static const u32 b43_httab_0x24[] = {
0x005d0582, 0x005805d6, 0x0053062e, 0x004e068c,
};
+/* Some late-init table */
+const u32 b43_httab_0x1a_0xc0_late[] = {
+ 0x10f90040, 0x10e10040, 0x10e1003c, 0x10c9003d,
+ 0x10b9003c, 0x10a9003d, 0x10a1003c, 0x1099003b,
+ 0x1091003b, 0x1089003a, 0x1081003a, 0x10790039,
+ 0x10710039, 0x1069003a, 0x1061003b, 0x1059003d,
+ 0x1051003f, 0x10490042, 0x1049003e, 0x1049003b,
+ 0x1041003e, 0x1041003b, 0x1039003e, 0x1039003b,
+ 0x10390038, 0x10390035, 0x1031003a, 0x10310036,
+ 0x10310033, 0x1029003a, 0x10290037, 0x10290034,
+ 0x10290031, 0x10210039, 0x10210036, 0x10210033,
+ 0x10210030, 0x1019003c, 0x10190039, 0x10190036,
+ 0x10190033, 0x10190030, 0x1019002d, 0x1019002b,
+ 0x10190028, 0x1011003a, 0x10110036, 0x10110033,
+ 0x10110030, 0x1011002e, 0x1011002b, 0x10110029,
+ 0x10110027, 0x10110024, 0x10110022, 0x10110020,
+ 0x1011001f, 0x1011001d, 0x1009003a, 0x10090037,
+ 0x10090034, 0x10090031, 0x1009002e, 0x1009002c,
+ 0x10090029, 0x10090027, 0x10090025, 0x10090023,
+ 0x10090021, 0x1009001f, 0x1009001d, 0x1009001b,
+ 0x1009001a, 0x10090018, 0x10090017, 0x10090016,
+ 0x10090015, 0x10090013, 0x10090012, 0x10090011,
+ 0x10090010, 0x1009000f, 0x1009000f, 0x1009000e,
+ 0x1009000d, 0x1009000c, 0x1009000c, 0x1009000b,
+ 0x1009000a, 0x1009000a, 0x10090009, 0x10090009,
+ 0x10090008, 0x10090008, 0x10090007, 0x10090007,
+ 0x10090007, 0x10090006, 0x10090006, 0x10090005,
+ 0x10090005, 0x10090005, 0x10090005, 0x10090004,
+ 0x10090004, 0x10090004, 0x10090004, 0x10090003,
+ 0x10090003, 0x10090003, 0x10090003, 0x10090003,
+ 0x10090003, 0x10090002, 0x10090002, 0x10090002,
+ 0x10090002, 0x10090002, 0x10090002, 0x10090002,
+ 0x10090002, 0x10090002, 0x10090001, 0x10090001,
+ 0x10090001, 0x10090001, 0x10090001, 0x10090001,
+};
+
/**************************************************
* R/W ops.
**************************************************/
@@ -674,6 +712,51 @@ void b43_httab_write(struct b43_wldev *dev, u32 offset, u32 value)
return;
}
+void b43_httab_write_few(struct b43_wldev *dev, u32 offset, size_t num, ...)
+{
+ va_list args;
+ u32 type, value;
+ unsigned int i;
+
+ type = offset & B43_HTTAB_TYPEMASK;
+ offset &= 0xFFFF;
+
+ va_start(args, num);
+ switch (type) {
+ case B43_HTTAB_8BIT:
+ b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, offset);
+ for (i = 0; i < num; i++) {
+ value = va_arg(args, int);
+ B43_WARN_ON(value & ~0xFF);
+ b43_phy_write(dev, B43_PHY_HT_TABLE_DATALO, value);
+ }
+ break;
+ case B43_HTTAB_16BIT:
+ b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, offset);
+ for (i = 0; i < num; i++) {
+ value = va_arg(args, int);
+ B43_WARN_ON(value & ~0xFFFF);
+ b43_phy_write(dev, B43_PHY_HT_TABLE_DATALO, value);
+ }
+ break;
+ case B43_HTTAB_32BIT:
+ b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, offset);
+ for (i = 0; i < num; i++) {
+ value = va_arg(args, int);
+ b43_phy_write(dev, B43_PHY_HT_TABLE_DATAHI,
+ value >> 16);
+ b43_phy_write(dev, B43_PHY_HT_TABLE_DATALO,
+ value & 0xFFFF);
+ }
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ va_end(args);
+
+ return;
+}
+
void b43_httab_write_bulk(struct b43_wldev *dev, u32 offset,
unsigned int nr_elements, const void *_data)
{
@@ -723,6 +806,9 @@ void b43_httab_write_bulk(struct b43_wldev *dev, u32 offset,
} while (0)
void b43_phy_ht_tables_init(struct b43_wldev *dev)
{
+ BUILD_BUG_ON(ARRAY_SIZE(b43_httab_0x1a_0xc0_late) !=
+ B43_HTTAB_1A_C0_LATE_SIZE);
+
httab_upload(dev, B43_HTTAB16(0x12, 0), b43_httab_0x12);
httab_upload(dev, B43_HTTAB16(0x27, 0), b43_httab_0x27);
httab_upload(dev, B43_HTTAB16(0x26, 0), b43_httab_0x26);
diff --git a/drivers/net/wireless/b43/tables_phy_ht.h b/drivers/net/wireless/b43/tables_phy_ht.h
index ea3be382c894..1b5ef2bc770c 100644
--- a/drivers/net/wireless/b43/tables_phy_ht.h
+++ b/drivers/net/wireless/b43/tables_phy_ht.h
@@ -14,9 +14,13 @@ u32 b43_httab_read(struct b43_wldev *dev, u32 offset);
void b43_httab_read_bulk(struct b43_wldev *dev, u32 offset,
unsigned int nr_elements, void *_data);
void b43_httab_write(struct b43_wldev *dev, u32 offset, u32 value);
+void b43_httab_write_few(struct b43_wldev *dev, u32 offset, size_t num, ...);
void b43_httab_write_bulk(struct b43_wldev *dev, u32 offset,
unsigned int nr_elements, const void *_data);
void b43_phy_ht_tables_init(struct b43_wldev *dev);
+#define B43_HTTAB_1A_C0_LATE_SIZE 128
+extern const u32 b43_httab_0x1a_0xc0_late[];
+
#endif /* B43_TABLES_PHY_HT_H_ */
diff --git a/drivers/net/wireless/b43/tables_phy_lcn.c b/drivers/net/wireless/b43/tables_phy_lcn.c
index 40c1d0915dd3..5176363cadf2 100644
--- a/drivers/net/wireless/b43/tables_phy_lcn.c
+++ b/drivers/net/wireless/b43/tables_phy_lcn.c
@@ -3,6 +3,8 @@
Broadcom B43 wireless driver
IEEE 802.11n LCN-PHY data tables
+ Copyright (c) 2011 Rafał Miłecki <zajec5@gmail.com>
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -25,10 +27,698 @@
#include "phy_common.h"
#include "phy_lcn.h"
+struct b43_lcntab_tx_gain_tbl_entry {
+ u8 gm;
+ u8 pga;
+ u8 pad;
+ u8 dac;
+ u8 bb_mult;
+};
+
+/**************************************************
+ * Static tables.
+ **************************************************/
+
+static const u16 b43_lcntab_0x02[] = {
+ 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d,
+ 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d,
+ 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d,
+ 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d,
+ 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d,
+ 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d,
+ 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d,
+ 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d,
+ 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d,
+ 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d,
+ 0x014d, 0x014d, 0x014d, 0x014d,
+};
+
+static const u16 b43_lcntab_0x01[] = {
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static const u32 b43_lcntab_0x0b[] = {
+ 0x000141f8, 0x000021f8, 0x000021fb, 0x000041fb,
+ 0x0001fedb, 0x0000217b, 0x00002133, 0x000040eb,
+ 0x0001fea3, 0x0000024b,
+};
+
+static const u32 b43_lcntab_0x0c[] = {
+ 0x00100001, 0x00200010, 0x00300001, 0x00400010,
+ 0x00500022, 0x00600122, 0x00700222, 0x00800322,
+ 0x00900422, 0x00a00522, 0x00b00622, 0x00c00722,
+ 0x00d00822, 0x00f00922, 0x00100a22, 0x00200b22,
+ 0x00300c22, 0x00400d22, 0x00500e22, 0x00600f22,
+};
+
+static const u32 b43_lcntab_0x0d[] = {
+ 0x00000000, 0x00000000, 0x10000000, 0x00000000,
+ 0x20000000, 0x00000000, 0x30000000, 0x00000000,
+ 0x40000000, 0x00000000, 0x50000000, 0x00000000,
+ 0x60000000, 0x00000000, 0x70000000, 0x00000000,
+ 0x80000000, 0x00000000, 0x90000000, 0x00000008,
+ 0xa0000000, 0x00000008, 0xb0000000, 0x00000008,
+ 0xc0000000, 0x00000008, 0xd0000000, 0x00000008,
+ 0xe0000000, 0x00000008, 0xf0000000, 0x00000008,
+ 0x00000000, 0x00000009, 0x10000000, 0x00000009,
+ 0x20000000, 0x00000019, 0x30000000, 0x00000019,
+ 0x40000000, 0x00000019, 0x50000000, 0x00000019,
+ 0x60000000, 0x00000019, 0x70000000, 0x00000019,
+ 0x80000000, 0x00000019, 0x90000000, 0x00000019,
+ 0xa0000000, 0x00000019, 0xb0000000, 0x00000019,
+ 0xc0000000, 0x00000019, 0xd0000000, 0x00000019,
+ 0xe0000000, 0x00000019, 0xf0000000, 0x00000019,
+ 0x00000000, 0x0000001a, 0x10000000, 0x0000001a,
+ 0x20000000, 0x0000001a, 0x30000000, 0x0000001a,
+ 0x40000000, 0x0000001a, 0x50000000, 0x00000002,
+ 0x60000000, 0x00000002, 0x70000000, 0x00000002,
+ 0x80000000, 0x00000002, 0x90000000, 0x00000002,
+ 0xa0000000, 0x00000002, 0xb0000000, 0x00000002,
+ 0xc0000000, 0x0000000a, 0xd0000000, 0x0000000a,
+ 0xe0000000, 0x0000000a, 0xf0000000, 0x0000000a,
+ 0x00000000, 0x0000000b, 0x10000000, 0x0000000b,
+ 0x20000000, 0x0000000b, 0x30000000, 0x0000000b,
+ 0x40000000, 0x0000000b, 0x50000000, 0x0000001b,
+ 0x60000000, 0x0000001b, 0x70000000, 0x0000001b,
+ 0x80000000, 0x0000001b, 0x90000000, 0x0000001b,
+ 0xa0000000, 0x0000001b, 0xb0000000, 0x0000001b,
+ 0xc0000000, 0x0000001b, 0xd0000000, 0x0000001b,
+ 0xe0000000, 0x0000001b, 0xf0000000, 0x0000001b,
+ 0x00000000, 0x0000001c, 0x10000000, 0x0000001c,
+ 0x20000000, 0x0000001c, 0x30000000, 0x0000001c,
+ 0x40000000, 0x0000001c, 0x50000000, 0x0000001c,
+ 0x60000000, 0x0000001c, 0x70000000, 0x0000001c,
+ 0x80000000, 0x0000001c, 0x90000000, 0x0000001c,
+};
+
+static const u16 b43_lcntab_0x0e[] = {
+ 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406,
+ 0x0407, 0x0408, 0x0409, 0x040a, 0x058b, 0x058c,
+ 0x058d, 0x058e, 0x058f, 0x0090, 0x0091, 0x0092,
+ 0x0193, 0x0194, 0x0195, 0x0196, 0x0197, 0x0198,
+ 0x0199, 0x019a, 0x019b, 0x019c, 0x019d, 0x019e,
+ 0x019f, 0x01a0, 0x01a1, 0x01a2, 0x01a3, 0x01a4,
+ 0x01a5, 0x0000,
+};
+
+static const u16 b43_lcntab_0x0f[] = {
+ 0x000a, 0x0009, 0x0006, 0x0005, 0x000a, 0x0009,
+ 0x0006, 0x0005, 0x000a, 0x0009, 0x0006, 0x0005,
+ 0x000a, 0x0009, 0x0006, 0x0005, 0x000a, 0x0009,
+ 0x0006, 0x0005, 0x000a, 0x0009, 0x0006, 0x0005,
+ 0x000a, 0x0009, 0x0006, 0x0005, 0x000a, 0x0009,
+ 0x0006, 0x0005, 0x000a, 0x0009, 0x0006, 0x0005,
+ 0x000a, 0x0009, 0x0006, 0x0005, 0x000a, 0x0009,
+ 0x0006, 0x0005, 0x000a, 0x0009, 0x0006, 0x0005,
+ 0x000a, 0x0009, 0x0006, 0x0005, 0x000a, 0x0009,
+ 0x0006, 0x0005, 0x000a, 0x0009, 0x0006, 0x0005,
+ 0x000a, 0x0009, 0x0006, 0x0005,
+};
+
+static const u16 b43_lcntab_0x10[] = {
+ 0x005f, 0x0036, 0x0029, 0x001f, 0x005f, 0x0036,
+ 0x0029, 0x001f, 0x005f, 0x0036, 0x0029, 0x001f,
+ 0x005f, 0x0036, 0x0029, 0x001f,
+};
+
+static const u16 b43_lcntab_0x11[] = {
+ 0x0009, 0x000f, 0x0014, 0x0018, 0x00fe, 0x0007,
+ 0x000b, 0x000f, 0x00fb, 0x00fe, 0x0001, 0x0005,
+ 0x0008, 0x000b, 0x000e, 0x0011, 0x0014, 0x0017,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0003, 0x0006, 0x0009, 0x000c, 0x000f,
+ 0x0012, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0003,
+ 0x0006, 0x0009, 0x000c, 0x000f, 0x0012, 0x0015,
+ 0x0018, 0x001b, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0003, 0x00eb, 0x0000, 0x0000,
+};
+
+static const u32 b43_lcntab_0x12[] = {
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000004, 0x00000000, 0x00000004, 0x00000008,
+ 0x00000001, 0x00000005, 0x00000009, 0x0000000d,
+ 0x0000004d, 0x0000008d, 0x0000000d, 0x0000004d,
+ 0x0000008d, 0x000000cd, 0x0000004f, 0x0000008f,
+ 0x000000cf, 0x000000d3, 0x00000113, 0x00000513,
+ 0x00000913, 0x00000953, 0x00000d53, 0x00001153,
+ 0x00001193, 0x00005193, 0x00009193, 0x0000d193,
+ 0x00011193, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000004,
+ 0x00000000, 0x00000004, 0x00000008, 0x00000001,
+ 0x00000005, 0x00000009, 0x0000000d, 0x0000004d,
+ 0x0000008d, 0x0000000d, 0x0000004d, 0x0000008d,
+ 0x000000cd, 0x0000004f, 0x0000008f, 0x000000cf,
+ 0x000000d3, 0x00000113, 0x00000513, 0x00000913,
+ 0x00000953, 0x00000d53, 0x00001153, 0x00005153,
+ 0x00009153, 0x0000d153, 0x00011153, 0x00015153,
+ 0x00019153, 0x0001d153, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static const u16 b43_lcntab_0x14[] = {
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x0002, 0x0003, 0x0001, 0x0003, 0x0002, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0002, 0x0003,
+ 0x0001, 0x0003, 0x0002, 0x0001, 0x0001, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+ 0x0001, 0x0001,
+};
+
+static const u16 b43_lcntab_0x17[] = {
+ 0x001a, 0x0034, 0x004e, 0x0068, 0x009c, 0x00d0,
+ 0x00ea, 0x0104, 0x0034, 0x0068, 0x009c, 0x00d0,
+ 0x0138, 0x01a0, 0x01d4, 0x0208, 0x004e, 0x009c,
+ 0x00ea, 0x0138, 0x01d4, 0x0270, 0x02be, 0x030c,
+ 0x0068, 0x00d0, 0x0138, 0x01a0, 0x0270, 0x0340,
+ 0x03a8, 0x0410, 0x0018, 0x009c, 0x00d0, 0x0104,
+ 0x00ea, 0x0138, 0x0186, 0x00d0, 0x0104, 0x0104,
+ 0x0138, 0x016c, 0x016c, 0x01a0, 0x0138, 0x0186,
+ 0x0186, 0x01d4, 0x0222, 0x0222, 0x0270, 0x0104,
+ 0x0138, 0x016c, 0x0138, 0x016c, 0x01a0, 0x01d4,
+ 0x01a0, 0x01d4, 0x0208, 0x0208, 0x023c, 0x0186,
+ 0x01d4, 0x0222, 0x01d4, 0x0222, 0x0270, 0x02be,
+ 0x0270, 0x02be, 0x030c, 0x030c, 0x035a, 0x0036,
+ 0x006c, 0x00a2, 0x00d8, 0x0144, 0x01b0, 0x01e6,
+ 0x021c, 0x006c, 0x00d8, 0x0144, 0x01b0, 0x0288,
+ 0x0360, 0x03cc, 0x0438, 0x00a2, 0x0144, 0x01e6,
+ 0x0288, 0x03cc, 0x0510, 0x05b2, 0x0654, 0x00d8,
+ 0x01b0, 0x0288, 0x0360, 0x0510, 0x06c0, 0x0798,
+ 0x0870, 0x0018, 0x0144, 0x01b0, 0x021c, 0x01e6,
+ 0x0288, 0x032a, 0x01b0, 0x021c, 0x021c, 0x0288,
+ 0x02f4, 0x02f4, 0x0360, 0x0288, 0x032a, 0x032a,
+ 0x03cc, 0x046e, 0x046e, 0x0510, 0x021c, 0x0288,
+ 0x02f4, 0x0288, 0x02f4, 0x0360, 0x03cc, 0x0360,
+ 0x03cc, 0x0438, 0x0438, 0x04a4, 0x032a, 0x03cc,
+ 0x046e, 0x03cc, 0x046e, 0x0510, 0x05b2, 0x0510,
+ 0x05b2, 0x0654, 0x0654, 0x06f6,
+};
+
+static const u16 b43_lcntab_0x00[] = {
+ 0x0200, 0x0300, 0x0400, 0x0600, 0x0800, 0x0b00,
+ 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005,
+ 0x1006, 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0200, 0x0300, 0x0400, 0x0600,
+ 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002, 0x1003,
+ 0x1004, 0x1005, 0x1006, 0x1007, 0x1707, 0x2007,
+ 0x2d07, 0x4007, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x4000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static const u32 b43_lcntab_0x18[] = {
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+ 0x00080000, 0x00080000, 0x00080000, 0x00080000,
+};
+
+/**************************************************
+ * TX gain.
+ **************************************************/
+
+const struct b43_lcntab_tx_gain_tbl_entry
+ b43_lcntab_tx_gain_tbl_2ghz_ext_pa_rev0[B43_LCNTAB_TX_GAIN_SIZE] = {
+ { 0x03, 0x00, 0x1f, 0x0, 0x48 },
+ { 0x03, 0x00, 0x1f, 0x0, 0x46 },
+ { 0x03, 0x00, 0x1f, 0x0, 0x44 },
+ { 0x03, 0x00, 0x1e, 0x0, 0x43 },
+ { 0x03, 0x00, 0x1d, 0x0, 0x44 },
+ { 0x03, 0x00, 0x1c, 0x0, 0x44 },
+ { 0x03, 0x00, 0x1b, 0x0, 0x45 },
+ { 0x03, 0x00, 0x1a, 0x0, 0x46 },
+ { 0x03, 0x00, 0x19, 0x0, 0x46 },
+ { 0x03, 0x00, 0x18, 0x0, 0x47 },
+ { 0x03, 0x00, 0x17, 0x0, 0x48 },
+ { 0x03, 0x00, 0x17, 0x0, 0x46 },
+ { 0x03, 0x00, 0x16, 0x0, 0x47 },
+ { 0x03, 0x00, 0x15, 0x0, 0x48 },
+ { 0x03, 0x00, 0x15, 0x0, 0x46 },
+ { 0x03, 0x00, 0x15, 0x0, 0x44 },
+ { 0x03, 0x00, 0x15, 0x0, 0x42 },
+ { 0x03, 0x00, 0x15, 0x0, 0x40 },
+ { 0x03, 0x00, 0x15, 0x0, 0x3f },
+ { 0x03, 0x00, 0x14, 0x0, 0x40 },
+ { 0x03, 0x00, 0x13, 0x0, 0x41 },
+ { 0x03, 0x00, 0x13, 0x0, 0x40 },
+ { 0x03, 0x00, 0x12, 0x0, 0x41 },
+ { 0x03, 0x00, 0x12, 0x0, 0x40 },
+ { 0x03, 0x00, 0x11, 0x0, 0x41 },
+ { 0x03, 0x00, 0x11, 0x0, 0x40 },
+ { 0x03, 0x00, 0x10, 0x0, 0x41 },
+ { 0x03, 0x00, 0x10, 0x0, 0x40 },
+ { 0x03, 0x00, 0x10, 0x0, 0x3e },
+ { 0x03, 0x00, 0x10, 0x0, 0x3c },
+ { 0x03, 0x00, 0x10, 0x0, 0x3a },
+ { 0x03, 0x00, 0x0f, 0x0, 0x3d },
+ { 0x03, 0x00, 0x0f, 0x0, 0x3b },
+ { 0x03, 0x00, 0x0e, 0x0, 0x3d },
+ { 0x03, 0x00, 0x0e, 0x0, 0x3c },
+ { 0x03, 0x00, 0x0e, 0x0, 0x3a },
+ { 0x03, 0x00, 0x0d, 0x0, 0x3c },
+ { 0x03, 0x00, 0x0d, 0x0, 0x3b },
+ { 0x03, 0x00, 0x0c, 0x0, 0x3e },
+ { 0x03, 0x00, 0x0c, 0x0, 0x3c },
+ { 0x03, 0x00, 0x0c, 0x0, 0x3a },
+ { 0x03, 0x00, 0x0b, 0x0, 0x3e },
+ { 0x03, 0x00, 0x0b, 0x0, 0x3c },
+ { 0x03, 0x00, 0x0b, 0x0, 0x3b },
+ { 0x03, 0x00, 0x0b, 0x0, 0x39 },
+ { 0x03, 0x00, 0x0a, 0x0, 0x3d },
+ { 0x03, 0x00, 0x0a, 0x0, 0x3b },
+ { 0x03, 0x00, 0x0a, 0x0, 0x39 },
+ { 0x03, 0x00, 0x09, 0x0, 0x3e },
+ { 0x03, 0x00, 0x09, 0x0, 0x3c },
+ { 0x03, 0x00, 0x09, 0x0, 0x3a },
+ { 0x03, 0x00, 0x09, 0x0, 0x39 },
+ { 0x03, 0x00, 0x08, 0x0, 0x3e },
+ { 0x03, 0x00, 0x08, 0x0, 0x3c },
+ { 0x03, 0x00, 0x08, 0x0, 0x3a },
+ { 0x03, 0x00, 0x08, 0x0, 0x39 },
+ { 0x03, 0x00, 0x08, 0x0, 0x37 },
+ { 0x03, 0x00, 0x07, 0x0, 0x3d },
+ { 0x03, 0x00, 0x07, 0x0, 0x3c },
+ { 0x03, 0x00, 0x07, 0x0, 0x3a },
+ { 0x03, 0x00, 0x07, 0x0, 0x38 },
+ { 0x03, 0x00, 0x07, 0x0, 0x37 },
+ { 0x03, 0x00, 0x06, 0x0, 0x3e },
+ { 0x03, 0x00, 0x06, 0x0, 0x3c },
+ { 0x03, 0x00, 0x06, 0x0, 0x3a },
+ { 0x03, 0x00, 0x06, 0x0, 0x39 },
+ { 0x03, 0x00, 0x06, 0x0, 0x37 },
+ { 0x03, 0x00, 0x06, 0x0, 0x36 },
+ { 0x03, 0x00, 0x06, 0x0, 0x34 },
+ { 0x03, 0x00, 0x05, 0x0, 0x3d },
+ { 0x03, 0x00, 0x05, 0x0, 0x3b },
+ { 0x03, 0x00, 0x05, 0x0, 0x39 },
+ { 0x03, 0x00, 0x05, 0x0, 0x38 },
+ { 0x03, 0x00, 0x05, 0x0, 0x36 },
+ { 0x03, 0x00, 0x05, 0x0, 0x35 },
+ { 0x03, 0x00, 0x05, 0x0, 0x33 },
+ { 0x03, 0x00, 0x04, 0x0, 0x3e },
+ { 0x03, 0x00, 0x04, 0x0, 0x3c },
+ { 0x03, 0x00, 0x04, 0x0, 0x3a },
+ { 0x03, 0x00, 0x04, 0x0, 0x39 },
+ { 0x03, 0x00, 0x04, 0x0, 0x37 },
+ { 0x03, 0x00, 0x04, 0x0, 0x36 },
+ { 0x03, 0x00, 0x04, 0x0, 0x34 },
+ { 0x03, 0x00, 0x04, 0x0, 0x33 },
+ { 0x03, 0x00, 0x04, 0x0, 0x31 },
+ { 0x03, 0x00, 0x04, 0x0, 0x30 },
+ { 0x03, 0x00, 0x04, 0x0, 0x2e },
+ { 0x03, 0x00, 0x03, 0x0, 0x3c },
+ { 0x03, 0x00, 0x03, 0x0, 0x3a },
+ { 0x03, 0x00, 0x03, 0x0, 0x39 },
+ { 0x03, 0x00, 0x03, 0x0, 0x37 },
+ { 0x03, 0x00, 0x03, 0x0, 0x36 },
+ { 0x03, 0x00, 0x03, 0x0, 0x34 },
+ { 0x03, 0x00, 0x03, 0x0, 0x33 },
+ { 0x03, 0x00, 0x03, 0x0, 0x31 },
+ { 0x03, 0x00, 0x03, 0x0, 0x30 },
+ { 0x03, 0x00, 0x03, 0x0, 0x2e },
+ { 0x03, 0x00, 0x03, 0x0, 0x2d },
+ { 0x03, 0x00, 0x03, 0x0, 0x2c },
+ { 0x03, 0x00, 0x03, 0x0, 0x2b },
+ { 0x03, 0x00, 0x03, 0x0, 0x29 },
+ { 0x03, 0x00, 0x02, 0x0, 0x3d },
+ { 0x03, 0x00, 0x02, 0x0, 0x3b },
+ { 0x03, 0x00, 0x02, 0x0, 0x39 },
+ { 0x03, 0x00, 0x02, 0x0, 0x38 },
+ { 0x03, 0x00, 0x02, 0x0, 0x36 },
+ { 0x03, 0x00, 0x02, 0x0, 0x35 },
+ { 0x03, 0x00, 0x02, 0x0, 0x33 },
+ { 0x03, 0x00, 0x02, 0x0, 0x32 },
+ { 0x03, 0x00, 0x02, 0x0, 0x30 },
+ { 0x03, 0x00, 0x02, 0x0, 0x2f },
+ { 0x03, 0x00, 0x02, 0x0, 0x2e },
+ { 0x03, 0x00, 0x02, 0x0, 0x2c },
+ { 0x03, 0x00, 0x02, 0x0, 0x2b },
+ { 0x03, 0x00, 0x02, 0x0, 0x2a },
+ { 0x03, 0x00, 0x02, 0x0, 0x29 },
+ { 0x03, 0x00, 0x02, 0x0, 0x27 },
+ { 0x03, 0x00, 0x02, 0x0, 0x26 },
+ { 0x03, 0x00, 0x02, 0x0, 0x25 },
+ { 0x03, 0x00, 0x02, 0x0, 0x24 },
+ { 0x03, 0x00, 0x02, 0x0, 0x23 },
+ { 0x03, 0x00, 0x02, 0x0, 0x22 },
+ { 0x03, 0x00, 0x02, 0x0, 0x21 },
+ { 0x03, 0x00, 0x02, 0x0, 0x20 },
+ { 0x03, 0x00, 0x01, 0x0, 0x3f },
+ { 0x03, 0x00, 0x01, 0x0, 0x3d },
+ { 0x03, 0x00, 0x01, 0x0, 0x3b },
+ { 0x03, 0x00, 0x01, 0x0, 0x39 },
+};
+
+/**************************************************
+ * SW control.
+ **************************************************/
+
+const u16 b43_lcntab_sw_ctl_4313_epa_rev0[] = {
+ 0x0002, 0x0008, 0x0004, 0x0001, 0x0002, 0x0008,
+ 0x0004, 0x0001, 0x0002, 0x0008, 0x0004, 0x0001,
+ 0x0002, 0x0008, 0x0004, 0x0001, 0x0002, 0x0008,
+ 0x0004, 0x0001, 0x0002, 0x0008, 0x0004, 0x0001,
+ 0x0002, 0x0008, 0x0004, 0x0001, 0x0002, 0x0008,
+ 0x0004, 0x0001, 0x0002, 0x0008, 0x0004, 0x0001,
+ 0x0002, 0x0008, 0x0004, 0x0001, 0x0002, 0x0008,
+ 0x0004, 0x0001, 0x0002, 0x0008, 0x0004, 0x0001,
+ 0x0002, 0x0008, 0x0004, 0x0001, 0x0002, 0x0008,
+ 0x0004, 0x0001, 0x0002, 0x0008, 0x0004, 0x0001,
+ 0x0002, 0x0008, 0x0004, 0x0001,
+};
+
+/**************************************************
+ * R/W ops.
+ **************************************************/
+
+u32 b43_lcntab_read(struct b43_wldev *dev, u32 offset)
+{
+ u32 type, value;
+
+ type = offset & B43_LCNTAB_TYPEMASK;
+ offset &= ~B43_LCNTAB_TYPEMASK;
+ B43_WARN_ON(offset > 0xFFFF);
+
+ switch (type) {
+ case B43_LCNTAB_8BIT:
+ b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset);
+ value = b43_phy_read(dev, B43_PHY_LCN_TABLE_DATALO) & 0xFF;
+ break;
+ case B43_LCNTAB_16BIT:
+ b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset);
+ value = b43_phy_read(dev, B43_PHY_LCN_TABLE_DATALO);
+ break;
+ case B43_LCNTAB_32BIT:
+ b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset);
+ value = b43_phy_read(dev, B43_PHY_LCN_TABLE_DATALO);
+ value |= (b43_phy_read(dev, B43_PHY_LCN_TABLE_DATAHI) << 16);
+ break;
+ default:
+ B43_WARN_ON(1);
+ value = 0;
+ }
+
+ return value;
+}
+
+void b43_lcntab_read_bulk(struct b43_wldev *dev, u32 offset,
+ unsigned int nr_elements, void *_data)
+{
+ u32 type;
+ u8 *data = _data;
+ unsigned int i;
+
+ type = offset & B43_LCNTAB_TYPEMASK;
+ offset &= ~B43_LCNTAB_TYPEMASK;
+ B43_WARN_ON(offset > 0xFFFF);
+
+ b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset);
+
+ for (i = 0; i < nr_elements; i++) {
+ switch (type) {
+ case B43_LCNTAB_8BIT:
+ *data = b43_phy_read(dev,
+ B43_PHY_LCN_TABLE_DATALO) & 0xFF;
+ data++;
+ break;
+ case B43_LCNTAB_16BIT:
+ *((u16 *)data) = b43_phy_read(dev,
+ B43_PHY_LCN_TABLE_DATALO);
+ data += 2;
+ break;
+ case B43_LCNTAB_32BIT:
+ *((u32 *)data) = b43_phy_read(dev,
+ B43_PHY_LCN_TABLE_DATALO);
+ *((u32 *)data) |= (b43_phy_read(dev,
+ B43_PHY_LCN_TABLE_DATAHI) << 16);
+ data += 4;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ }
+}
+
+void b43_lcntab_write(struct b43_wldev *dev, u32 offset, u32 value)
+{
+ u32 type;
+
+ type = offset & B43_LCNTAB_TYPEMASK;
+ offset &= 0xFFFF;
+
+ switch (type) {
+ case B43_LCNTAB_8BIT:
+ B43_WARN_ON(value & ~0xFF);
+ b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset);
+ b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, value);
+ break;
+ case B43_LCNTAB_16BIT:
+ B43_WARN_ON(value & ~0xFFFF);
+ b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset);
+ b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, value);
+ break;
+ case B43_LCNTAB_32BIT:
+ b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset);
+ b43_phy_write(dev, B43_PHY_LCN_TABLE_DATAHI, value >> 16);
+ b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, value & 0xFFFF);
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+
+ return;
+}
+
+void b43_lcntab_write_bulk(struct b43_wldev *dev, u32 offset,
+ unsigned int nr_elements, const void *_data)
+{
+ u32 type, value;
+ const u8 *data = _data;
+ unsigned int i;
+
+ type = offset & B43_LCNTAB_TYPEMASK;
+ offset &= ~B43_LCNTAB_TYPEMASK;
+ B43_WARN_ON(offset > 0xFFFF);
+
+ b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset);
+
+ for (i = 0; i < nr_elements; i++) {
+ switch (type) {
+ case B43_LCNTAB_8BIT:
+ value = *data;
+ data++;
+ B43_WARN_ON(value & ~0xFF);
+ b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, value);
+ break;
+ case B43_LCNTAB_16BIT:
+ value = *((u16 *)data);
+ data += 2;
+ B43_WARN_ON(value & ~0xFFFF);
+ b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, value);
+ break;
+ case B43_LCNTAB_32BIT:
+ value = *((u32 *)data);
+ data += 4;
+ b43_phy_write(dev, B43_PHY_LCN_TABLE_DATAHI,
+ value >> 16);
+ b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO,
+ value & 0xFFFF);
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ }
+}
+
/**************************************************
* Tables ops.
**************************************************/
+#define lcntab_upload(dev, offset, data) do { \
+ b43_lcntab_write_bulk(dev, offset, ARRAY_SIZE(data), data); \
+ } while (0)
+static void b43_phy_lcn_upload_static_tables(struct b43_wldev *dev)
+{
+ lcntab_upload(dev, B43_LCNTAB16(0x02, 0), b43_lcntab_0x02);
+ lcntab_upload(dev, B43_LCNTAB16(0x01, 0), b43_lcntab_0x01);
+ lcntab_upload(dev, B43_LCNTAB32(0x0b, 0), b43_lcntab_0x0b);
+ lcntab_upload(dev, B43_LCNTAB32(0x0c, 0), b43_lcntab_0x0c);
+ lcntab_upload(dev, B43_LCNTAB32(0x0d, 0), b43_lcntab_0x0d);
+ lcntab_upload(dev, B43_LCNTAB16(0x0e, 0), b43_lcntab_0x0e);
+ lcntab_upload(dev, B43_LCNTAB16(0x0f, 0), b43_lcntab_0x0f);
+ lcntab_upload(dev, B43_LCNTAB16(0x10, 0), b43_lcntab_0x10);
+ lcntab_upload(dev, B43_LCNTAB16(0x11, 0), b43_lcntab_0x11);
+ lcntab_upload(dev, B43_LCNTAB32(0x12, 0), b43_lcntab_0x12);
+ lcntab_upload(dev, B43_LCNTAB16(0x14, 0), b43_lcntab_0x14);
+ lcntab_upload(dev, B43_LCNTAB16(0x17, 0), b43_lcntab_0x17);
+ lcntab_upload(dev, B43_LCNTAB16(0x00, 0), b43_lcntab_0x00);
+ lcntab_upload(dev, B43_LCNTAB32(0x18, 0), b43_lcntab_0x18);
+}
+
+void b43_phy_lcn_load_tx_gain_tab(struct b43_wldev *dev,
+ const struct b43_lcntab_tx_gain_tbl_entry *gain_table)
+{
+ u32 i;
+ u32 val;
+
+ u16 pa_gain = 0x70;
+ if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_FEM)
+ pa_gain = 0x10;
+
+ for (i = 0; i < B43_LCNTAB_TX_GAIN_SIZE; i++) {
+ val = ((pa_gain << 24) |
+ (gain_table[i].pad << 16) |
+ (gain_table[i].pga << 8) |
+ gain_table[i].gm);
+ b43_lcntab_write(dev, B43_LCNTAB32(0x7, 0xc0 + i), val);
+
+ /* brcmsmac doesn't maskset, we follow newer wl here */
+ val = b43_lcntab_read(dev, B43_LCNTAB32(0x7, 0x140 + i));
+ val &= 0x000fffff;
+ val |= ((gain_table[i].dac << 28) |
+ (gain_table[i].bb_mult << 20));
+ b43_lcntab_write(dev, B43_LCNTAB32(0x7, 0x140 + i), val);
+ }
+}
+
+/* wlc_lcnphy_load_rfpower */
+static void b43_phy_lcn_load_rfpower(struct b43_wldev *dev)
+{
+ u32 bbmult, rfgain;
+ u8 i;
+
+ for (i = 0; i < 128; i++) {
+ bbmult = b43_lcntab_read(dev, B43_LCNTAB32(0x7, 0x140 + i));
+ bbmult >>= 20;
+ rfgain = b43_lcntab_read(dev, B43_LCNTAB32(0x7, 0xc0 + i));
+
+ /* TODO: calculate value for 0x240 + i table offset
+ * b43_lcntab_write(dev, B43_LCNTAB32(0x7, 0x240 + i), val);
+ */
+ }
+}
+
+/* Not implemented in brcmsmac, noticed in wl in MMIO dump */
+static void b43_phy_lcn_rewrite_rfpower_table(struct b43_wldev *dev)
+{
+ int i;
+ u32 tmp;
+ for (i = 0; i < 128; i++) {
+ tmp = b43_lcntab_read(dev, B43_LCNTAB32(0x7, 0x240 + i));
+ b43_lcntab_write(dev, B43_LCNTAB32(0x7, 0x240 + i), tmp);
+ }
+}
+
+/* wlc_lcnphy_clear_papd_comptable */
+static void b43_phy_lcn_clean_papd_comp_table(struct b43_wldev *dev)
+{
+ u8 i;
+
+ for (i = 0; i < 0x80; i++)
+ b43_lcntab_write(dev, B43_LCNTAB32(0x18, i), 0x80000);
+}
+
+/* wlc_lcnphy_tbl_init */
void b43_phy_lcn_tables_init(struct b43_wldev *dev)
{
+ struct ssb_sprom *sprom = dev->dev->bus_sprom;
+
+ b43_phy_lcn_upload_static_tables(dev);
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ if (sprom->boardflags_lo & B43_BFL_FEM)
+ b43_phy_lcn_load_tx_gain_tab(dev,
+ b43_lcntab_tx_gain_tbl_2ghz_ext_pa_rev0);
+ else
+ b43err(dev->wl,
+ "TX gain table unknown for this card\n");
+ }
+
+ if (sprom->boardflags_lo & B43_BFL_FEM &&
+ !(sprom->boardflags_hi & B43_BFH_FEM_BT))
+ b43_lcntab_write_bulk(dev, B43_LCNTAB16(0xf, 0),
+ ARRAY_SIZE(b43_lcntab_sw_ctl_4313_epa_rev0),
+ b43_lcntab_sw_ctl_4313_epa_rev0);
+ else
+ b43err(dev->wl, "SW ctl table is unknown for this card\n");
+
+ b43_phy_lcn_load_rfpower(dev);
+ b43_phy_lcn_rewrite_rfpower_table(dev);
+ b43_phy_lcn_clean_papd_comp_table(dev);
}
diff --git a/drivers/net/wireless/b43/tables_phy_lcn.h b/drivers/net/wireless/b43/tables_phy_lcn.h
index 5e31b15b81ec..caff9db6831f 100644
--- a/drivers/net/wireless/b43/tables_phy_lcn.h
+++ b/drivers/net/wireless/b43/tables_phy_lcn.h
@@ -1,6 +1,24 @@
#ifndef B43_TABLES_PHY_LCN_H_
#define B43_TABLES_PHY_LCN_H_
+/* The LCN-PHY tables. */
+#define B43_LCNTAB_TYPEMASK 0xF0000000
+#define B43_LCNTAB_8BIT 0x10000000
+#define B43_LCNTAB_16BIT 0x20000000
+#define B43_LCNTAB_32BIT 0x30000000
+#define B43_LCNTAB8(table, offset) (((table) << 10) | (offset) | B43_LCNTAB_8BIT)
+#define B43_LCNTAB16(table, offset) (((table) << 10) | (offset) | B43_LCNTAB_16BIT)
+#define B43_LCNTAB32(table, offset) (((table) << 10) | (offset) | B43_LCNTAB_32BIT)
+
+#define B43_LCNTAB_TX_GAIN_SIZE 128
+
+u32 b43_lcntab_read(struct b43_wldev *dev, u32 offset);
+void b43_lcntab_read_bulk(struct b43_wldev *dev, u32 offset,
+ unsigned int nr_elements, void *_data);
+void b43_lcntab_write(struct b43_wldev *dev, u32 offset, u32 value);
+void b43_lcntab_write_bulk(struct b43_wldev *dev, u32 offset,
+ unsigned int nr_elements, const void *_data);
+
void b43_phy_lcn_tables_init(struct b43_wldev *dev);
#endif /* B43_TABLES_PHY_LCN_H_ */
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
index b74f25ec1ab4..c73e8600d218 100644
--- a/drivers/net/wireless/b43/xmit.c
+++ b/drivers/net/wireless/b43/xmit.c
@@ -337,12 +337,19 @@ int b43_generate_txhdr(struct b43_wldev *dev,
memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
}
}
- if (b43_is_old_txhdr_format(dev)) {
- b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp),
+ switch (dev->fw.hdr_format) {
+ case B43_FW_HDR_598:
+ b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->format_598.plcp),
plcp_fragment_len, rate);
- } else {
- b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->new_format.plcp),
+ break;
+ case B43_FW_HDR_351:
+ b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->format_351.plcp),
+ plcp_fragment_len, rate);
+ break;
+ case B43_FW_HDR_410:
+ b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->format_410.plcp),
plcp_fragment_len, rate);
+ break;
}
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb),
plcp_fragment_len, rate_fb);
@@ -415,10 +422,10 @@ int b43_generate_txhdr(struct b43_wldev *dev,
if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
(rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) {
unsigned int len;
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr *uninitialized_var(hdr);
int rts_rate, rts_rate_fb;
int rts_rate_ofdm, rts_rate_fb_ofdm;
- struct b43_plcp_hdr6 *plcp;
+ struct b43_plcp_hdr6 *uninitialized_var(plcp);
struct ieee80211_rate *rts_cts_rate;
rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info);
@@ -429,14 +436,21 @@ int b43_generate_txhdr(struct b43_wldev *dev,
rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
- struct ieee80211_cts *cts;
+ struct ieee80211_cts *uninitialized_var(cts);
- if (b43_is_old_txhdr_format(dev)) {
+ switch (dev->fw.hdr_format) {
+ case B43_FW_HDR_598:
cts = (struct ieee80211_cts *)
- (txhdr->old_format.rts_frame);
- } else {
+ (txhdr->format_598.rts_frame);
+ break;
+ case B43_FW_HDR_351:
cts = (struct ieee80211_cts *)
- (txhdr->new_format.rts_frame);
+ (txhdr->format_351.rts_frame);
+ break;
+ case B43_FW_HDR_410:
+ cts = (struct ieee80211_cts *)
+ (txhdr->format_410.rts_frame);
+ break;
}
ieee80211_ctstoself_get(dev->wl->hw, info->control.vif,
fragment_data, fragment_len,
@@ -444,14 +458,21 @@ int b43_generate_txhdr(struct b43_wldev *dev,
mac_ctl |= B43_TXH_MAC_SENDCTS;
len = sizeof(struct ieee80211_cts);
} else {
- struct ieee80211_rts *rts;
+ struct ieee80211_rts *uninitialized_var(rts);
- if (b43_is_old_txhdr_format(dev)) {
+ switch (dev->fw.hdr_format) {
+ case B43_FW_HDR_598:
rts = (struct ieee80211_rts *)
- (txhdr->old_format.rts_frame);
- } else {
+ (txhdr->format_598.rts_frame);
+ break;
+ case B43_FW_HDR_351:
rts = (struct ieee80211_rts *)
- (txhdr->new_format.rts_frame);
+ (txhdr->format_351.rts_frame);
+ break;
+ case B43_FW_HDR_410:
+ rts = (struct ieee80211_rts *)
+ (txhdr->format_410.rts_frame);
+ break;
}
ieee80211_rts_get(dev->wl->hw, info->control.vif,
fragment_data, fragment_len,
@@ -462,22 +483,36 @@ int b43_generate_txhdr(struct b43_wldev *dev,
len += FCS_LEN;
/* Generate the PLCP headers for the RTS/CTS frame */
- if (b43_is_old_txhdr_format(dev))
- plcp = &txhdr->old_format.rts_plcp;
- else
- plcp = &txhdr->new_format.rts_plcp;
+ switch (dev->fw.hdr_format) {
+ case B43_FW_HDR_598:
+ plcp = &txhdr->format_598.rts_plcp;
+ break;
+ case B43_FW_HDR_351:
+ plcp = &txhdr->format_351.rts_plcp;
+ break;
+ case B43_FW_HDR_410:
+ plcp = &txhdr->format_410.rts_plcp;
+ break;
+ }
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp,
len, rts_rate);
plcp = &txhdr->rts_plcp_fb;
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp,
len, rts_rate_fb);
- if (b43_is_old_txhdr_format(dev)) {
+ switch (dev->fw.hdr_format) {
+ case B43_FW_HDR_598:
hdr = (struct ieee80211_hdr *)
- (&txhdr->old_format.rts_frame);
- } else {
+ (&txhdr->format_598.rts_frame);
+ break;
+ case B43_FW_HDR_351:
hdr = (struct ieee80211_hdr *)
- (&txhdr->new_format.rts_frame);
+ (&txhdr->format_351.rts_frame);
+ break;
+ case B43_FW_HDR_410:
+ hdr = (struct ieee80211_hdr *)
+ (&txhdr->format_410.rts_frame);
+ break;
}
txhdr->rts_dur_fb = hdr->duration_id;
@@ -505,10 +540,17 @@ int b43_generate_txhdr(struct b43_wldev *dev,
}
/* Magic cookie */
- if (b43_is_old_txhdr_format(dev))
- txhdr->old_format.cookie = cpu_to_le16(cookie);
- else
- txhdr->new_format.cookie = cpu_to_le16(cookie);
+ switch (dev->fw.hdr_format) {
+ case B43_FW_HDR_598:
+ txhdr->format_598.cookie = cpu_to_le16(cookie);
+ break;
+ case B43_FW_HDR_351:
+ txhdr->format_351.cookie = cpu_to_le16(cookie);
+ break;
+ case B43_FW_HDR_410:
+ txhdr->format_410.cookie = cpu_to_le16(cookie);
+ break;
+ }
if (phy->type == B43_PHYTYPE_N) {
txhdr->phy_ctl1 =
@@ -611,8 +653,9 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
struct ieee80211_hdr *wlhdr;
const struct b43_rxhdr_fw4 *rxhdr = _rxhdr;
__le16 fctl;
- u16 phystat0, phystat3, chanstat, mactime;
- u32 macstat;
+ u16 phystat0, phystat3;
+ u16 uninitialized_var(chanstat), uninitialized_var(mactime);
+ u32 uninitialized_var(macstat);
u16 chanid;
u16 phytype;
int padding;
@@ -622,9 +665,19 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
/* Get metadata about the frame from the header. */
phystat0 = le16_to_cpu(rxhdr->phy_status0);
phystat3 = le16_to_cpu(rxhdr->phy_status3);
- macstat = le32_to_cpu(rxhdr->mac_status);
- mactime = le16_to_cpu(rxhdr->mac_time);
- chanstat = le16_to_cpu(rxhdr->channel);
+ switch (dev->fw.hdr_format) {
+ case B43_FW_HDR_598:
+ macstat = le32_to_cpu(rxhdr->format_598.mac_status);
+ mactime = le16_to_cpu(rxhdr->format_598.mac_time);
+ chanstat = le16_to_cpu(rxhdr->format_598.channel);
+ break;
+ case B43_FW_HDR_410:
+ case B43_FW_HDR_351:
+ macstat = le32_to_cpu(rxhdr->format_351.mac_status);
+ mactime = le16_to_cpu(rxhdr->format_351.mac_time);
+ chanstat = le16_to_cpu(rxhdr->format_351.channel);
+ break;
+ }
phytype = chanstat & B43_RX_CHAN_PHYTYPE;
if (unlikely(macstat & B43_RX_MAC_FCSERR)) {
@@ -682,16 +735,22 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
}
/* Link quality statistics */
- if ((chanstat & B43_RX_CHAN_PHYTYPE) == B43_PHYTYPE_N) {
-// s8 rssi = max(rxhdr->power0, rxhdr->power1);
- //TODO: Find out what the rssi value is (dBm or percentage?)
- // and also find out what the maximum possible value is.
- // Fill status.ssi and status.signal fields.
- } else {
+ switch (chanstat & B43_RX_CHAN_PHYTYPE) {
+ case B43_PHYTYPE_N:
+ if (rxhdr->power0 == 16 || rxhdr->power0 == 32)
+ status.signal = max(rxhdr->power1, rxhdr->power2);
+ else
+ status.signal = max(rxhdr->power0, rxhdr->power1);
+ break;
+ case B43_PHYTYPE_A:
+ case B43_PHYTYPE_B:
+ case B43_PHYTYPE_G:
+ case B43_PHYTYPE_LP:
status.signal = b43_rssi_postprocess(dev, rxhdr->jssi,
(phystat0 & B43_RX_PHYST0_OFDM),
(phystat0 & B43_RX_PHYST0_GAINCTL),
(phystat3 & B43_RX_PHYST3_TRSTATE));
+ break;
}
if (phystat0 & B43_RX_PHYST0_OFDM)
@@ -744,6 +803,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
break;
case B43_PHYTYPE_N:
case B43_PHYTYPE_LP:
+ case B43_PHYTYPE_HT:
/* chanid is the SHM channel cookie. Which is the plain
* channel number in b43. */
if (chanstat & B43_RX_CHAN_5GHZ) {
diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h
index 42debb5cd6fa..16c514d54afa 100644
--- a/drivers/net/wireless/b43/xmit.h
+++ b/drivers/net/wireless/b43/xmit.h
@@ -46,7 +46,24 @@ struct b43_txhdr {
__le32 timeout; /* Timeout */
union {
- /* The new r410 format. */
+ /* Tested with 598.314, 644.1001 and 666.2 */
+ struct {
+ __le16 mimo_antenna; /* MIMO antenna select */
+ __le16 preload_size; /* Preload size */
+ PAD_BYTES(2);
+ __le16 cookie; /* TX frame cookie */
+ __le16 tx_status; /* TX status */
+ __le16 max_n_mpdus;
+ __le16 max_a_bytes_mrt;
+ __le16 max_a_bytes_fbr;
+ __le16 min_m_bytes;
+ struct b43_plcp_hdr6 rts_plcp; /* RTS PLCP header */
+ __u8 rts_frame[16]; /* The RTS frame (if used) */
+ PAD_BYTES(2);
+ struct b43_plcp_hdr6 plcp; /* Main PLCP header */
+ } format_598 __packed;
+
+ /* Tested with 410.2160, 478.104 and 508.* */
struct {
__le16 mimo_antenna; /* MIMO antenna select */
__le16 preload_size; /* Preload size */
@@ -57,9 +74,9 @@ struct b43_txhdr {
__u8 rts_frame[16]; /* The RTS frame (if used) */
PAD_BYTES(2);
struct b43_plcp_hdr6 plcp; /* Main PLCP header */
- } new_format __packed;
+ } format_410 __packed;
- /* The old r351 format. */
+ /* Tested with 351.126 */
struct {
PAD_BYTES(2);
__le16 cookie; /* TX frame cookie */
@@ -68,7 +85,7 @@ struct b43_txhdr {
__u8 rts_frame[16]; /* The RTS frame (if used) */
PAD_BYTES(2);
struct b43_plcp_hdr6 plcp; /* Main PLCP header */
- } old_format __packed;
+ } format_351 __packed;
} __packed;
} __packed;
@@ -166,19 +183,18 @@ struct b43_tx_legacy_rate_phy_ctl_entry {
#define B43_TXH_PHY1_MODUL_QAM256 0x2000 /* QAM256 */
-/* r351 firmware compatibility stuff. */
-static inline
-bool b43_is_old_txhdr_format(struct b43_wldev *dev)
-{
- return (dev->fw.rev <= 351);
-}
-
static inline
size_t b43_txhdr_size(struct b43_wldev *dev)
{
- if (b43_is_old_txhdr_format(dev))
+ switch (dev->fw.hdr_format) {
+ case B43_FW_HDR_598:
+ return 112 + sizeof(struct b43_plcp_hdr6);
+ case B43_FW_HDR_410:
+ return 104 + sizeof(struct b43_plcp_hdr6);
+ case B43_FW_HDR_351:
return 100 + sizeof(struct b43_plcp_hdr6);
- return 104 + sizeof(struct b43_plcp_hdr6);
+ }
+ return 0;
}
@@ -232,11 +248,33 @@ struct b43_rxhdr_fw4 {
__s8 power1; /* PHY RX Status 1: Power 1 */
} __packed;
} __packed;
- __le16 phy_status2; /* PHY RX Status 2 */
+ union {
+ /* RSSI for N-PHYs */
+ struct {
+ __s8 power2;
+ PAD_BYTES(1);
+ } __packed;
+
+ __le16 phy_status2; /* PHY RX Status 2 */
+ } __packed;
__le16 phy_status3; /* PHY RX Status 3 */
- __le32 mac_status; /* MAC RX status */
- __le16 mac_time;
- __le16 channel;
+ union {
+ /* Tested with 598.314, 644.1001 and 666.2 */
+ struct {
+ __le16 phy_status4; /* PHY RX Status 4 */
+ __le16 phy_status5; /* PHY RX Status 5 */
+ __le32 mac_status; /* MAC RX status */
+ __le16 mac_time;
+ __le16 channel;
+ } format_598 __packed;
+
+ /* Tested with 351.126, 410.2160, 478.104 and 508.* */
+ struct {
+ __le32 mac_status; /* MAC RX status */
+ __le16 mac_time;
+ __le16 channel;
+ } format_351 __packed;
+ } __packed;
} __packed;
/* PHY RX Status 0 */
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
index a610a352102a..12b518251581 100644
--- a/drivers/net/wireless/b43legacy/b43legacy.h
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -14,7 +14,6 @@
#include <linux/ssb/ssb.h>
#include <linux/ssb/ssb_driver_chipcommon.h>
-#include <linux/wireless.h>
#include <net/mac80211.h>
#include "debugfs.h"
@@ -23,10 +22,6 @@
#include "phy.h"
-/* The unique identifier of the firmware that's officially supported by this
- * driver version. */
-#define B43legacy_SUPPORTED_FIRMWARE_ID "FW10"
-
#define B43legacy_IRQWAIT_MAX_RETRIES 20
/* MMIO offsets */
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
index 5010c477abdf..c5535adf6991 100644
--- a/drivers/net/wireless/b43legacy/dma.c
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -42,10 +42,9 @@
/* 32bit DMA ops. */
static
-struct b43legacy_dmadesc_generic *op32_idx2desc(
- struct b43legacy_dmaring *ring,
- int slot,
- struct b43legacy_dmadesc_meta **meta)
+struct b43legacy_dmadesc32 *op32_idx2desc(struct b43legacy_dmaring *ring,
+ int slot,
+ struct b43legacy_dmadesc_meta **meta)
{
struct b43legacy_dmadesc32 *desc;
@@ -53,11 +52,11 @@ struct b43legacy_dmadesc_generic *op32_idx2desc(
desc = ring->descbase;
desc = &(desc[slot]);
- return (struct b43legacy_dmadesc_generic *)desc;
+ return (struct b43legacy_dmadesc32 *)desc;
}
static void op32_fill_descriptor(struct b43legacy_dmaring *ring,
- struct b43legacy_dmadesc_generic *desc,
+ struct b43legacy_dmadesc32 *desc,
dma_addr_t dmaaddr, u16 bufsize,
int start, int end, int irq)
{
@@ -67,7 +66,7 @@ static void op32_fill_descriptor(struct b43legacy_dmaring *ring,
u32 addr;
u32 addrext;
- slot = (int)(&(desc->dma32) - descbase);
+ slot = (int)(desc - descbase);
B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
addr = (u32)(dmaaddr & ~SSB_DMA_TRANSLATION_MASK);
@@ -87,8 +86,8 @@ static void op32_fill_descriptor(struct b43legacy_dmaring *ring,
ctl |= (addrext << B43legacy_DMA32_DCTL_ADDREXT_SHIFT)
& B43legacy_DMA32_DCTL_ADDREXT_MASK;
- desc->dma32.control = cpu_to_le32(ctl);
- desc->dma32.address = cpu_to_le32(addr);
+ desc->control = cpu_to_le32(ctl);
+ desc->address = cpu_to_le32(addr);
}
static void op32_poke_tx(struct b43legacy_dmaring *ring, int slot)
@@ -128,121 +127,6 @@ static void op32_set_current_rxslot(struct b43legacy_dmaring *ring,
(u32)(slot * sizeof(struct b43legacy_dmadesc32)));
}
-static const struct b43legacy_dma_ops dma32_ops = {
- .idx2desc = op32_idx2desc,
- .fill_descriptor = op32_fill_descriptor,
- .poke_tx = op32_poke_tx,
- .tx_suspend = op32_tx_suspend,
- .tx_resume = op32_tx_resume,
- .get_current_rxslot = op32_get_current_rxslot,
- .set_current_rxslot = op32_set_current_rxslot,
-};
-
-/* 64bit DMA ops. */
-static
-struct b43legacy_dmadesc_generic *op64_idx2desc(
- struct b43legacy_dmaring *ring,
- int slot,
- struct b43legacy_dmadesc_meta
- **meta)
-{
- struct b43legacy_dmadesc64 *desc;
-
- *meta = &(ring->meta[slot]);
- desc = ring->descbase;
- desc = &(desc[slot]);
-
- return (struct b43legacy_dmadesc_generic *)desc;
-}
-
-static void op64_fill_descriptor(struct b43legacy_dmaring *ring,
- struct b43legacy_dmadesc_generic *desc,
- dma_addr_t dmaaddr, u16 bufsize,
- int start, int end, int irq)
-{
- struct b43legacy_dmadesc64 *descbase = ring->descbase;
- int slot;
- u32 ctl0 = 0;
- u32 ctl1 = 0;
- u32 addrlo;
- u32 addrhi;
- u32 addrext;
-
- slot = (int)(&(desc->dma64) - descbase);
- B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
-
- addrlo = (u32)(dmaaddr & 0xFFFFFFFF);
- addrhi = (((u64)dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
- addrext = (((u64)dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
- >> SSB_DMA_TRANSLATION_SHIFT;
- addrhi |= ring->dev->dma.translation;
- if (slot == ring->nr_slots - 1)
- ctl0 |= B43legacy_DMA64_DCTL0_DTABLEEND;
- if (start)
- ctl0 |= B43legacy_DMA64_DCTL0_FRAMESTART;
- if (end)
- ctl0 |= B43legacy_DMA64_DCTL0_FRAMEEND;
- if (irq)
- ctl0 |= B43legacy_DMA64_DCTL0_IRQ;
- ctl1 |= (bufsize - ring->frameoffset)
- & B43legacy_DMA64_DCTL1_BYTECNT;
- ctl1 |= (addrext << B43legacy_DMA64_DCTL1_ADDREXT_SHIFT)
- & B43legacy_DMA64_DCTL1_ADDREXT_MASK;
-
- desc->dma64.control0 = cpu_to_le32(ctl0);
- desc->dma64.control1 = cpu_to_le32(ctl1);
- desc->dma64.address_low = cpu_to_le32(addrlo);
- desc->dma64.address_high = cpu_to_le32(addrhi);
-}
-
-static void op64_poke_tx(struct b43legacy_dmaring *ring, int slot)
-{
- b43legacy_dma_write(ring, B43legacy_DMA64_TXINDEX,
- (u32)(slot * sizeof(struct b43legacy_dmadesc64)));
-}
-
-static void op64_tx_suspend(struct b43legacy_dmaring *ring)
-{
- b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL,
- b43legacy_dma_read(ring, B43legacy_DMA64_TXCTL)
- | B43legacy_DMA64_TXSUSPEND);
-}
-
-static void op64_tx_resume(struct b43legacy_dmaring *ring)
-{
- b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL,
- b43legacy_dma_read(ring, B43legacy_DMA64_TXCTL)
- & ~B43legacy_DMA64_TXSUSPEND);
-}
-
-static int op64_get_current_rxslot(struct b43legacy_dmaring *ring)
-{
- u32 val;
-
- val = b43legacy_dma_read(ring, B43legacy_DMA64_RXSTATUS);
- val &= B43legacy_DMA64_RXSTATDPTR;
-
- return (val / sizeof(struct b43legacy_dmadesc64));
-}
-
-static void op64_set_current_rxslot(struct b43legacy_dmaring *ring,
- int slot)
-{
- b43legacy_dma_write(ring, B43legacy_DMA64_RXINDEX,
- (u32)(slot * sizeof(struct b43legacy_dmadesc64)));
-}
-
-static const struct b43legacy_dma_ops dma64_ops = {
- .idx2desc = op64_idx2desc,
- .fill_descriptor = op64_fill_descriptor,
- .poke_tx = op64_poke_tx,
- .tx_suspend = op64_tx_suspend,
- .tx_resume = op64_tx_resume,
- .get_current_rxslot = op64_get_current_rxslot,
- .set_current_rxslot = op64_set_current_rxslot,
-};
-
-
static inline int free_slots(struct b43legacy_dmaring *ring)
{
return (ring->nr_slots - ring->used_slots);
@@ -358,14 +242,6 @@ return 0;
static u16 b43legacy_dmacontroller_base(enum b43legacy_dmatype type,
int controller_idx)
{
- static const u16 map64[] = {
- B43legacy_MMIO_DMA64_BASE0,
- B43legacy_MMIO_DMA64_BASE1,
- B43legacy_MMIO_DMA64_BASE2,
- B43legacy_MMIO_DMA64_BASE3,
- B43legacy_MMIO_DMA64_BASE4,
- B43legacy_MMIO_DMA64_BASE5,
- };
static const u16 map32[] = {
B43legacy_MMIO_DMA32_BASE0,
B43legacy_MMIO_DMA32_BASE1,
@@ -375,11 +251,6 @@ static u16 b43legacy_dmacontroller_base(enum b43legacy_dmatype type,
B43legacy_MMIO_DMA32_BASE5,
};
- if (type == B43legacy_DMA_64BIT) {
- B43legacy_WARN_ON(!(controller_idx >= 0 &&
- controller_idx < ARRAY_SIZE(map64)));
- return map64[controller_idx];
- }
B43legacy_WARN_ON(!(controller_idx >= 0 &&
controller_idx < ARRAY_SIZE(map32)));
return map32[controller_idx];
@@ -491,25 +362,15 @@ static int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
might_sleep();
- offset = (type == B43legacy_DMA_64BIT) ?
- B43legacy_DMA64_RXCTL : B43legacy_DMA32_RXCTL;
+ offset = B43legacy_DMA32_RXCTL;
b43legacy_write32(dev, mmio_base + offset, 0);
for (i = 0; i < 10; i++) {
- offset = (type == B43legacy_DMA_64BIT) ?
- B43legacy_DMA64_RXSTATUS : B43legacy_DMA32_RXSTATUS;
+ offset = B43legacy_DMA32_RXSTATUS;
value = b43legacy_read32(dev, mmio_base + offset);
- if (type == B43legacy_DMA_64BIT) {
- value &= B43legacy_DMA64_RXSTAT;
- if (value == B43legacy_DMA64_RXSTAT_DISABLED) {
- i = -1;
- break;
- }
- } else {
- value &= B43legacy_DMA32_RXSTATE;
- if (value == B43legacy_DMA32_RXSTAT_DISABLED) {
- i = -1;
- break;
- }
+ value &= B43legacy_DMA32_RXSTATE;
+ if (value == B43legacy_DMA32_RXSTAT_DISABLED) {
+ i = -1;
+ break;
}
msleep(1);
}
@@ -533,43 +394,24 @@ static int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
might_sleep();
for (i = 0; i < 10; i++) {
- offset = (type == B43legacy_DMA_64BIT) ?
- B43legacy_DMA64_TXSTATUS : B43legacy_DMA32_TXSTATUS;
+ offset = B43legacy_DMA32_TXSTATUS;
value = b43legacy_read32(dev, mmio_base + offset);
- if (type == B43legacy_DMA_64BIT) {
- value &= B43legacy_DMA64_TXSTAT;
- if (value == B43legacy_DMA64_TXSTAT_DISABLED ||
- value == B43legacy_DMA64_TXSTAT_IDLEWAIT ||
- value == B43legacy_DMA64_TXSTAT_STOPPED)
- break;
- } else {
- value &= B43legacy_DMA32_TXSTATE;
- if (value == B43legacy_DMA32_TXSTAT_DISABLED ||
- value == B43legacy_DMA32_TXSTAT_IDLEWAIT ||
- value == B43legacy_DMA32_TXSTAT_STOPPED)
- break;
- }
+ value &= B43legacy_DMA32_TXSTATE;
+ if (value == B43legacy_DMA32_TXSTAT_DISABLED ||
+ value == B43legacy_DMA32_TXSTAT_IDLEWAIT ||
+ value == B43legacy_DMA32_TXSTAT_STOPPED)
+ break;
msleep(1);
}
- offset = (type == B43legacy_DMA_64BIT) ? B43legacy_DMA64_TXCTL :
- B43legacy_DMA32_TXCTL;
+ offset = B43legacy_DMA32_TXCTL;
b43legacy_write32(dev, mmio_base + offset, 0);
for (i = 0; i < 10; i++) {
- offset = (type == B43legacy_DMA_64BIT) ?
- B43legacy_DMA64_TXSTATUS : B43legacy_DMA32_TXSTATUS;
+ offset = B43legacy_DMA32_TXSTATUS;
value = b43legacy_read32(dev, mmio_base + offset);
- if (type == B43legacy_DMA_64BIT) {
- value &= B43legacy_DMA64_TXSTAT;
- if (value == B43legacy_DMA64_TXSTAT_DISABLED) {
- i = -1;
- break;
- }
- } else {
- value &= B43legacy_DMA32_TXSTATE;
- if (value == B43legacy_DMA32_TXSTAT_DISABLED) {
- i = -1;
- break;
- }
+ value &= B43legacy_DMA32_TXSTATE;
+ if (value == B43legacy_DMA32_TXSTAT_DISABLED) {
+ i = -1;
+ break;
}
msleep(1);
}
@@ -601,9 +443,6 @@ static bool b43legacy_dma_mapping_error(struct b43legacy_dmaring *ring,
if ((u64)addr + buffersize > (1ULL << 32))
goto address_error;
break;
- case B43legacy_DMA_64BIT:
- /* Currently we can't have addresses beyond 64 bits in the kernel. */
- break;
}
/* The address is OK. */
@@ -617,7 +456,7 @@ address_error:
}
static int setup_rx_descbuffer(struct b43legacy_dmaring *ring,
- struct b43legacy_dmadesc_generic *desc,
+ struct b43legacy_dmadesc32 *desc,
struct b43legacy_dmadesc_meta *meta,
gfp_t gfp_flags)
{
@@ -653,8 +492,7 @@ static int setup_rx_descbuffer(struct b43legacy_dmaring *ring,
meta->skb = skb;
meta->dmaaddr = dmaaddr;
- ring->ops->fill_descriptor(ring, desc, dmaaddr,
- ring->rx_buffersize, 0, 0, 0);
+ op32_fill_descriptor(ring, desc, dmaaddr, ring->rx_buffersize, 0, 0, 0);
rxhdr = (struct b43legacy_rxhdr_fw3 *)(skb->data);
rxhdr->frame_len = 0;
@@ -671,11 +509,11 @@ static int alloc_initial_descbuffers(struct b43legacy_dmaring *ring)
{
int i;
int err = -ENOMEM;
- struct b43legacy_dmadesc_generic *desc;
+ struct b43legacy_dmadesc32 *desc;
struct b43legacy_dmadesc_meta *meta;
for (i = 0; i < ring->nr_slots; i++) {
- desc = ring->ops->idx2desc(ring, i, &meta);
+ desc = op32_idx2desc(ring, i, &meta);
err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL);
if (err) {
@@ -692,7 +530,7 @@ out:
err_unwind:
for (i--; i >= 0; i--) {
- desc = ring->ops->idx2desc(ring, i, &meta);
+ desc = op32_idx2desc(ring, i, &meta);
unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0);
dev_kfree_skb(meta->skb);
@@ -710,83 +548,35 @@ static int dmacontroller_setup(struct b43legacy_dmaring *ring)
u32 value;
u32 addrext;
u32 trans = ring->dev->dma.translation;
+ u32 ringbase = (u32)(ring->dmabase);
if (ring->tx) {
- if (ring->type == B43legacy_DMA_64BIT) {
- u64 ringbase = (u64)(ring->dmabase);
-
- addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
- >> SSB_DMA_TRANSLATION_SHIFT;
- value = B43legacy_DMA64_TXENABLE;
- value |= (addrext << B43legacy_DMA64_TXADDREXT_SHIFT)
- & B43legacy_DMA64_TXADDREXT_MASK;
- b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL,
- value);
- b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO,
- (ringbase & 0xFFFFFFFF));
- b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI,
- ((ringbase >> 32)
- & ~SSB_DMA_TRANSLATION_MASK)
- | trans);
- } else {
- u32 ringbase = (u32)(ring->dmabase);
-
- addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
- >> SSB_DMA_TRANSLATION_SHIFT;
- value = B43legacy_DMA32_TXENABLE;
- value |= (addrext << B43legacy_DMA32_TXADDREXT_SHIFT)
- & B43legacy_DMA32_TXADDREXT_MASK;
- b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL,
- value);
- b43legacy_dma_write(ring, B43legacy_DMA32_TXRING,
- (ringbase &
- ~SSB_DMA_TRANSLATION_MASK)
- | trans);
- }
+ addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ value = B43legacy_DMA32_TXENABLE;
+ value |= (addrext << B43legacy_DMA32_TXADDREXT_SHIFT)
+ & B43legacy_DMA32_TXADDREXT_MASK;
+ b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL, value);
+ b43legacy_dma_write(ring, B43legacy_DMA32_TXRING,
+ (ringbase & ~SSB_DMA_TRANSLATION_MASK)
+ | trans);
} else {
err = alloc_initial_descbuffers(ring);
if (err)
goto out;
- if (ring->type == B43legacy_DMA_64BIT) {
- u64 ringbase = (u64)(ring->dmabase);
-
- addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
- >> SSB_DMA_TRANSLATION_SHIFT;
- value = (ring->frameoffset <<
- B43legacy_DMA64_RXFROFF_SHIFT);
- value |= B43legacy_DMA64_RXENABLE;
- value |= (addrext << B43legacy_DMA64_RXADDREXT_SHIFT)
- & B43legacy_DMA64_RXADDREXT_MASK;
- b43legacy_dma_write(ring, B43legacy_DMA64_RXCTL,
- value);
- b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO,
- (ringbase & 0xFFFFFFFF));
- b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI,
- ((ringbase >> 32) &
- ~SSB_DMA_TRANSLATION_MASK) |
- trans);
- b43legacy_dma_write(ring, B43legacy_DMA64_RXINDEX,
- 200);
- } else {
- u32 ringbase = (u32)(ring->dmabase);
-
- addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
- >> SSB_DMA_TRANSLATION_SHIFT;
- value = (ring->frameoffset <<
- B43legacy_DMA32_RXFROFF_SHIFT);
- value |= B43legacy_DMA32_RXENABLE;
- value |= (addrext <<
- B43legacy_DMA32_RXADDREXT_SHIFT)
- & B43legacy_DMA32_RXADDREXT_MASK;
- b43legacy_dma_write(ring, B43legacy_DMA32_RXCTL,
- value);
- b43legacy_dma_write(ring, B43legacy_DMA32_RXRING,
- (ringbase &
- ~SSB_DMA_TRANSLATION_MASK)
- | trans);
- b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX,
- 200);
- }
+
+ addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ value = (ring->frameoffset <<
+ B43legacy_DMA32_RXFROFF_SHIFT);
+ value |= B43legacy_DMA32_RXENABLE;
+ value |= (addrext << B43legacy_DMA32_RXADDREXT_SHIFT)
+ & B43legacy_DMA32_RXADDREXT_MASK;
+ b43legacy_dma_write(ring, B43legacy_DMA32_RXCTL, value);
+ b43legacy_dma_write(ring, B43legacy_DMA32_RXRING,
+ (ringbase & ~SSB_DMA_TRANSLATION_MASK)
+ | trans);
+ b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX, 200);
}
out:
@@ -799,19 +589,11 @@ static void dmacontroller_cleanup(struct b43legacy_dmaring *ring)
if (ring->tx) {
b43legacy_dmacontroller_tx_reset(ring->dev, ring->mmio_base,
ring->type);
- if (ring->type == B43legacy_DMA_64BIT) {
- b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO, 0);
- b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI, 0);
- } else
- b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, 0);
+ b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, 0);
} else {
b43legacy_dmacontroller_rx_reset(ring->dev, ring->mmio_base,
ring->type);
- if (ring->type == B43legacy_DMA_64BIT) {
- b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO, 0);
- b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI, 0);
- } else
- b43legacy_dma_write(ring, B43legacy_DMA32_RXRING, 0);
+ b43legacy_dma_write(ring, B43legacy_DMA32_RXRING, 0);
}
}
@@ -823,7 +605,7 @@ static void free_all_descbuffers(struct b43legacy_dmaring *ring)
if (!ring->used_slots)
return;
for (i = 0; i < ring->nr_slots; i++) {
- ring->ops->idx2desc(ring, i, &meta);
+ op32_idx2desc(ring, i, &meta);
if (!meta->skb) {
B43legacy_WARN_ON(!ring->tx);
@@ -844,9 +626,6 @@ static u64 supported_dma_mask(struct b43legacy_wldev *dev)
u32 tmp;
u16 mmio_base;
- tmp = b43legacy_read32(dev, SSB_TMSHIGH);
- if (tmp & SSB_TMSHIGH_DMA64)
- return DMA_BIT_MASK(64);
mmio_base = b43legacy_dmacontroller_base(0, 0);
b43legacy_write32(dev,
mmio_base + B43legacy_DMA32_TXCTL,
@@ -865,8 +644,6 @@ static enum b43legacy_dmatype dma_mask_to_engine_type(u64 dmamask)
return B43legacy_DMA_30BIT;
if (dmamask == DMA_BIT_MASK(32))
return B43legacy_DMA_32BIT;
- if (dmamask == DMA_BIT_MASK(64))
- return B43legacy_DMA_64BIT;
B43legacy_WARN_ON(1);
return B43legacy_DMA_30BIT;
}
@@ -937,10 +714,6 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
ring->nr_slots = nr_slots;
ring->mmio_base = b43legacy_dmacontroller_base(type, controller_index);
ring->index = controller_index;
- if (type == B43legacy_DMA_64BIT)
- ring->ops = &dma64_ops;
- else
- ring->ops = &dma32_ops;
if (for_tx) {
ring->tx = 1;
ring->current_slot = -1;
@@ -1247,12 +1020,11 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
struct sk_buff **in_skb)
{
struct sk_buff *skb = *in_skb;
- const struct b43legacy_dma_ops *ops = ring->ops;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
u8 *header;
int slot, old_top_slot, old_used_slots;
int err;
- struct b43legacy_dmadesc_generic *desc;
+ struct b43legacy_dmadesc32 *desc;
struct b43legacy_dmadesc_meta *meta;
struct b43legacy_dmadesc_meta *meta_hdr;
struct sk_buff *bounce_skb;
@@ -1265,7 +1037,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
/* Get a slot for the header. */
slot = request_slot(ring);
- desc = ops->idx2desc(ring, slot, &meta_hdr);
+ desc = op32_idx2desc(ring, slot, &meta_hdr);
memset(meta_hdr, 0, sizeof(*meta_hdr));
header = &(ring->txhdr_cache[slot * sizeof(
@@ -1287,12 +1059,12 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
ring->used_slots = old_used_slots;
return -EIO;
}
- ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr,
+ op32_fill_descriptor(ring, desc, meta_hdr->dmaaddr,
sizeof(struct b43legacy_txhdr_fw3), 1, 0, 0);
/* Get a slot for the payload. */
slot = request_slot(ring);
- desc = ops->idx2desc(ring, slot, &meta);
+ desc = op32_idx2desc(ring, slot, &meta);
memset(meta, 0, sizeof(*meta));
meta->skb = skb;
@@ -1328,12 +1100,12 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
}
}
- ops->fill_descriptor(ring, desc, meta->dmaaddr,
+ op32_fill_descriptor(ring, desc, meta->dmaaddr,
skb->len, 0, 1, 1);
wmb(); /* previous stuff MUST be done */
/* Now transfer the whole frame. */
- ops->poke_tx(ring, next_slot(ring, slot));
+ op32_poke_tx(ring, next_slot(ring, slot));
return 0;
out_free_bounce:
@@ -1429,7 +1201,6 @@ out_unlock:
void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
const struct b43legacy_txstatus *status)
{
- const struct b43legacy_dma_ops *ops;
struct b43legacy_dmaring *ring;
struct b43legacy_dmadesc_meta *meta;
int retry_limit;
@@ -1442,10 +1213,9 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
spin_lock(&ring->lock);
B43legacy_WARN_ON(!ring->tx);
- ops = ring->ops;
while (1) {
B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
- ops->idx2desc(ring, slot, &meta);
+ op32_idx2desc(ring, slot, &meta);
if (meta->skb)
unmap_descbuffer(ring, meta->dmaaddr,
@@ -1528,8 +1298,7 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
static void dma_rx(struct b43legacy_dmaring *ring,
int *slot)
{
- const struct b43legacy_dma_ops *ops = ring->ops;
- struct b43legacy_dmadesc_generic *desc;
+ struct b43legacy_dmadesc32 *desc;
struct b43legacy_dmadesc_meta *meta;
struct b43legacy_rxhdr_fw3 *rxhdr;
struct sk_buff *skb;
@@ -1537,7 +1306,7 @@ static void dma_rx(struct b43legacy_dmaring *ring,
int err;
dma_addr_t dmaaddr;
- desc = ops->idx2desc(ring, *slot, &meta);
+ desc = op32_idx2desc(ring, *slot, &meta);
sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);
skb = meta->skb;
@@ -1589,7 +1358,7 @@ static void dma_rx(struct b43legacy_dmaring *ring,
s32 tmp = len;
while (1) {
- desc = ops->idx2desc(ring, *slot, &meta);
+ desc = op32_idx2desc(ring, *slot, &meta);
/* recycle the descriptor buffer. */
sync_descbuffer_for_device(ring, meta->dmaaddr,
ring->rx_buffersize);
@@ -1626,13 +1395,12 @@ drop:
void b43legacy_dma_rx(struct b43legacy_dmaring *ring)
{
- const struct b43legacy_dma_ops *ops = ring->ops;
int slot;
int current_slot;
int used_slots = 0;
B43legacy_WARN_ON(ring->tx);
- current_slot = ops->get_current_rxslot(ring);
+ current_slot = op32_get_current_rxslot(ring);
B43legacy_WARN_ON(!(current_slot >= 0 && current_slot <
ring->nr_slots));
@@ -1641,7 +1409,7 @@ void b43legacy_dma_rx(struct b43legacy_dmaring *ring)
dma_rx(ring, &slot);
update_max_used_slots(ring, ++used_slots);
}
- ops->set_current_rxslot(ring, slot);
+ op32_set_current_rxslot(ring, slot);
ring->current_slot = slot;
}
@@ -1651,7 +1419,7 @@ static void b43legacy_dma_tx_suspend_ring(struct b43legacy_dmaring *ring)
spin_lock_irqsave(&ring->lock, flags);
B43legacy_WARN_ON(!ring->tx);
- ring->ops->tx_suspend(ring);
+ op32_tx_suspend(ring);
spin_unlock_irqrestore(&ring->lock, flags);
}
@@ -1661,7 +1429,7 @@ static void b43legacy_dma_tx_resume_ring(struct b43legacy_dmaring *ring)
spin_lock_irqsave(&ring->lock, flags);
B43legacy_WARN_ON(!ring->tx);
- ring->ops->tx_resume(ring);
+ op32_tx_resume(ring);
spin_unlock_irqrestore(&ring->lock, flags);
}
diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h
index 686941c242fc..504a58767e95 100644
--- a/drivers/net/wireless/b43legacy/dma.h
+++ b/drivers/net/wireless/b43legacy/dma.h
@@ -82,90 +82,6 @@ struct b43legacy_dmadesc32 {
#define B43legacy_DMA32_DCTL_FRAMESTART 0x80000000
-
-/*** 64-bit DMA Engine. ***/
-
-/* 64-bit DMA controller registers. */
-#define B43legacy_DMA64_TXCTL 0x00
-#define B43legacy_DMA64_TXENABLE 0x00000001
-#define B43legacy_DMA64_TXSUSPEND 0x00000002
-#define B43legacy_DMA64_TXLOOPBACK 0x00000004
-#define B43legacy_DMA64_TXFLUSH 0x00000010
-#define B43legacy_DMA64_TXADDREXT_MASK 0x00030000
-#define B43legacy_DMA64_TXADDREXT_SHIFT 16
-#define B43legacy_DMA64_TXINDEX 0x04
-#define B43legacy_DMA64_TXRINGLO 0x08
-#define B43legacy_DMA64_TXRINGHI 0x0C
-#define B43legacy_DMA64_TXSTATUS 0x10
-#define B43legacy_DMA64_TXSTATDPTR 0x00001FFF
-#define B43legacy_DMA64_TXSTAT 0xF0000000
-#define B43legacy_DMA64_TXSTAT_DISABLED 0x00000000
-#define B43legacy_DMA64_TXSTAT_ACTIVE 0x10000000
-#define B43legacy_DMA64_TXSTAT_IDLEWAIT 0x20000000
-#define B43legacy_DMA64_TXSTAT_STOPPED 0x30000000
-#define B43legacy_DMA64_TXSTAT_SUSP 0x40000000
-#define B43legacy_DMA64_TXERROR 0x14
-#define B43legacy_DMA64_TXERRDPTR 0x0001FFFF
-#define B43legacy_DMA64_TXERR 0xF0000000
-#define B43legacy_DMA64_TXERR_NOERR 0x00000000
-#define B43legacy_DMA64_TXERR_PROT 0x10000000
-#define B43legacy_DMA64_TXERR_UNDERRUN 0x20000000
-#define B43legacy_DMA64_TXERR_TRANSFER 0x30000000
-#define B43legacy_DMA64_TXERR_DESCREAD 0x40000000
-#define B43legacy_DMA64_TXERR_CORE 0x50000000
-#define B43legacy_DMA64_RXCTL 0x20
-#define B43legacy_DMA64_RXENABLE 0x00000001
-#define B43legacy_DMA64_RXFROFF_MASK 0x000000FE
-#define B43legacy_DMA64_RXFROFF_SHIFT 1
-#define B43legacy_DMA64_RXDIRECTFIFO 0x00000100
-#define B43legacy_DMA64_RXADDREXT_MASK 0x00030000
-#define B43legacy_DMA64_RXADDREXT_SHIFT 16
-#define B43legacy_DMA64_RXINDEX 0x24
-#define B43legacy_DMA64_RXRINGLO 0x28
-#define B43legacy_DMA64_RXRINGHI 0x2C
-#define B43legacy_DMA64_RXSTATUS 0x30
-#define B43legacy_DMA64_RXSTATDPTR 0x00001FFF
-#define B43legacy_DMA64_RXSTAT 0xF0000000
-#define B43legacy_DMA64_RXSTAT_DISABLED 0x00000000
-#define B43legacy_DMA64_RXSTAT_ACTIVE 0x10000000
-#define B43legacy_DMA64_RXSTAT_IDLEWAIT 0x20000000
-#define B43legacy_DMA64_RXSTAT_STOPPED 0x30000000
-#define B43legacy_DMA64_RXSTAT_SUSP 0x40000000
-#define B43legacy_DMA64_RXERROR 0x34
-#define B43legacy_DMA64_RXERRDPTR 0x0001FFFF
-#define B43legacy_DMA64_RXERR 0xF0000000
-#define B43legacy_DMA64_RXERR_NOERR 0x00000000
-#define B43legacy_DMA64_RXERR_PROT 0x10000000
-#define B43legacy_DMA64_RXERR_UNDERRUN 0x20000000
-#define B43legacy_DMA64_RXERR_TRANSFER 0x30000000
-#define B43legacy_DMA64_RXERR_DESCREAD 0x40000000
-#define B43legacy_DMA64_RXERR_CORE 0x50000000
-
-/* 64-bit DMA descriptor. */
-struct b43legacy_dmadesc64 {
- __le32 control0;
- __le32 control1;
- __le32 address_low;
- __le32 address_high;
-} __packed;
-#define B43legacy_DMA64_DCTL0_DTABLEEND 0x10000000
-#define B43legacy_DMA64_DCTL0_IRQ 0x20000000
-#define B43legacy_DMA64_DCTL0_FRAMEEND 0x40000000
-#define B43legacy_DMA64_DCTL0_FRAMESTART 0x80000000
-#define B43legacy_DMA64_DCTL1_BYTECNT 0x00001FFF
-#define B43legacy_DMA64_DCTL1_ADDREXT_MASK 0x00030000
-#define B43legacy_DMA64_DCTL1_ADDREXT_SHIFT 16
-
-
-
-struct b43legacy_dmadesc_generic {
- union {
- struct b43legacy_dmadesc32 dma32;
- struct b43legacy_dmadesc64 dma64;
- } __packed;
-} __packed;
-
-
/* Misc DMA constants */
#define B43legacy_DMA_RINGMEMSIZE PAGE_SIZE
#define B43legacy_DMA0_RX_FRAMEOFFSET 30
@@ -197,35 +113,12 @@ struct b43legacy_dmadesc_meta {
bool is_last_fragment;
};
-struct b43legacy_dmaring;
-
-/* Lowlevel DMA operations that differ between 32bit and 64bit DMA. */
-struct b43legacy_dma_ops {
- struct b43legacy_dmadesc_generic * (*idx2desc)
- (struct b43legacy_dmaring *ring,
- int slot,
- struct b43legacy_dmadesc_meta
- **meta);
- void (*fill_descriptor)(struct b43legacy_dmaring *ring,
- struct b43legacy_dmadesc_generic *desc,
- dma_addr_t dmaaddr, u16 bufsize,
- int start, int end, int irq);
- void (*poke_tx)(struct b43legacy_dmaring *ring, int slot);
- void (*tx_suspend)(struct b43legacy_dmaring *ring);
- void (*tx_resume)(struct b43legacy_dmaring *ring);
- int (*get_current_rxslot)(struct b43legacy_dmaring *ring);
- void (*set_current_rxslot)(struct b43legacy_dmaring *ring, int slot);
-};
-
enum b43legacy_dmatype {
B43legacy_DMA_30BIT = 30,
B43legacy_DMA_32BIT = 32,
- B43legacy_DMA_64BIT = 64,
};
struct b43legacy_dmaring {
- /* Lowlevel DMA ops. */
- const struct b43legacy_dma_ops *ops;
/* Kernel virtual base address of the ring memory. */
void *descbase;
/* Meta data about all descriptors. */
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 04c03b212a5e..a3b72cd72c66 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -35,7 +35,6 @@
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
#include <linux/firmware.h>
-#include <linux/wireless.h>
#include <linux/workqueue.h>
#include <linux/sched.h>
#include <linux/skbuff.h>
@@ -61,7 +60,6 @@ MODULE_AUTHOR("Stefano Brivio");
MODULE_AUTHOR("Michael Buesch");
MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(B43legacy_SUPPORTED_FIRMWARE_ID);
MODULE_FIRMWARE("b43legacy/ucode2.fw");
MODULE_FIRMWARE("b43legacy/ucode4.fw");
@@ -2468,7 +2466,8 @@ out:
}
}
-static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
+static int b43legacy_op_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
return 0;
@@ -3785,7 +3784,8 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
INIT_WORK(&wl->beacon_update_trigger, b43legacy_beacon_update_trigger_work);
ssb_set_devtypedata(dev, wl);
- b43legacyinfo(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id);
+ b43legacyinfo(wl, "Broadcom %04X WLAN found (core revision %u)\n",
+ dev->bus->chip_id, dev->id.revision);
err = 0;
out:
return err;
@@ -3947,8 +3947,7 @@ static void b43legacy_print_driverinfo(void)
feat_dma = "D";
#endif
printk(KERN_INFO "Broadcom 43xx-legacy driver loaded "
- "[ Features: %s%s%s%s, Firmware-ID: "
- B43legacy_SUPPORTED_FIRMWARE_ID " ]\n",
+ "[ Features: %s%s%s%s ]\n",
feat_pci, feat_leds, feat_pio, feat_dma);
}
diff --git a/drivers/net/wireless/brcm80211/Kconfig b/drivers/net/wireless/brcm80211/Kconfig
new file mode 100644
index 000000000000..2069fc8f7ad1
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/Kconfig
@@ -0,0 +1,35 @@
+config BRCMUTIL
+ tristate
+
+config BRCMSMAC
+ tristate "Broadcom IEEE802.11n PCIe SoftMAC WLAN driver"
+ depends on PCI
+ depends on MAC80211
+ depends on BCMA=n
+ select BRCMUTIL
+ select FW_LOADER
+ select CRC_CCITT
+ select CRC8
+ select CORDIC
+ ---help---
+ This module adds support for PCIe wireless adapters based on Broadcom
+ IEEE802.11n SoftMAC chipsets. If you choose to build a module, it'll
+ be called brcmsmac.ko.
+
+config BRCMFMAC
+ tristate "Broadcom IEEE802.11n embedded FullMAC WLAN driver"
+ depends on MMC
+ depends on CFG80211
+ select BRCMUTIL
+ select FW_LOADER
+ ---help---
+ This module adds support for embedded wireless adapters based on
+ Broadcom IEEE802.11n FullMAC chipsets. This driver uses the kernel's
+ wireless extensions subsystem. If you choose to build a module,
+ it'll be called brcmfmac.ko.
+
+config BRCMDBG
+ bool "Broadcom driver debug functions"
+ depends on BRCMSMAC || BRCMFMAC
+ ---help---
+ Selecting this enables additional code for debug purposes.
diff --git a/drivers/net/wireless/brcm80211/Makefile b/drivers/net/wireless/brcm80211/Makefile
new file mode 100644
index 000000000000..f41c047eca82
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/Makefile
@@ -0,0 +1,23 @@
+#
+# Makefile fragment for Broadcom 802.11n Networking Device Driver
+#
+# Copyright (c) 2010 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.
+
+# common flags
+subdir-ccflags-$(CONFIG_BRCMDBG) += -DBCMDBG
+
+obj-$(CONFIG_BRCMUTIL) += brcmutil/
+obj-$(CONFIG_BRCMFMAC) += brcmfmac/
+obj-$(CONFIG_BRCMSMAC) += brcmsmac/
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
new file mode 100644
index 000000000000..b44e3094588a
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
@@ -0,0 +1,33 @@
+#
+# Makefile fragment for Broadcom 802.11n Networking Device Driver
+#
+# Copyright (c) 2010 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.
+
+ccflags-y += \
+ -Idrivers/net/wireless/brcm80211/brcmfmac \
+ -Idrivers/net/wireless/brcm80211/include
+
+DHDOFILES = \
+ wl_cfg80211.o \
+ dhd_cdc.o \
+ dhd_common.o \
+ dhd_sdio.o \
+ dhd_linux.o \
+ bcmsdh.o \
+ bcmsdh_sdmmc.o
+
+obj-$(CONFIG_BRCMFMAC) += brcmfmac.o
+brcmfmac-objs += $(DHDOFILES)
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmchip.h b/drivers/net/wireless/brcm80211/brcmfmac/bcmchip.h
new file mode 100644
index 000000000000..d7d3afd5a10f
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmchip.h
@@ -0,0 +1,32 @@
+/*
+ * 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 _bcmchip_h_
+#define _bcmchip_h_
+
+/* bcm4329 */
+/* SDIO device core, ID 0x829 */
+#define BCM4329_CORE_BUS_BASE 0x18011000
+/* internal memory core, ID 0x80e */
+#define BCM4329_CORE_SOCRAM_BASE 0x18003000
+/* ARM Cortex M3 core, ID 0x82a */
+#define BCM4329_CORE_ARM_BASE 0x18002000
+#define BCM4329_RAMSIZE 0x48000
+/* firmware name */
+#define BCM4329_FW_NAME "brcm/bcm4329-fullmac-4.bin"
+#define BCM4329_NV_NAME "brcm/bcm4329-fullmac-4.txt"
+
+#endif /* _bcmchip_h_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
new file mode 100644
index 000000000000..bff9dcd6fadc
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2010 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/* ****************** SDIO CARD Interface Functions **************************/
+
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/sched.h>
+#include <linux/completion.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/card.h>
+
+#include <defs.h>
+#include <brcm_hw_ids.h>
+#include <brcmu_utils.h>
+#include <brcmu_wifi.h>
+#include <soc.h>
+#include "dhd.h"
+#include "dhd_bus.h"
+#include "dhd_dbg.h"
+#include "sdio_host.h"
+
+#define SDIOH_API_ACCESS_RETRY_LIMIT 2
+
+static void brcmf_sdioh_irqhandler(struct sdio_func *func)
+{
+ struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev);
+
+ brcmf_dbg(TRACE, "***IRQHandler\n");
+
+ sdio_release_host(func);
+
+ brcmf_sdbrcm_isr(sdiodev->bus);
+
+ sdio_claim_host(func);
+}
+
+int brcmf_sdcard_intr_reg(struct brcmf_sdio_dev *sdiodev)
+{
+ brcmf_dbg(TRACE, "Entering\n");
+
+ sdio_claim_host(sdiodev->func[1]);
+ sdio_claim_irq(sdiodev->func[1], brcmf_sdioh_irqhandler);
+ sdio_release_host(sdiodev->func[1]);
+
+ return 0;
+}
+
+int brcmf_sdcard_intr_dereg(struct brcmf_sdio_dev *sdiodev)
+{
+ brcmf_dbg(TRACE, "Entering\n");
+
+ sdio_claim_host(sdiodev->func[1]);
+ sdio_release_irq(sdiodev->func[1]);
+ sdio_release_host(sdiodev->func[1]);
+
+ return 0;
+}
+
+u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr,
+ int *err)
+{
+ int status;
+ s32 retry = 0;
+ u8 data = 0;
+
+ do {
+ if (retry) /* wait for 1 ms till bus get settled down */
+ udelay(1000);
+ status = brcmf_sdioh_request_byte(sdiodev, SDIOH_READ, fnc_num,
+ addr, (u8 *) &data);
+ } while (status != 0
+ && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
+ if (err)
+ *err = status;
+
+ brcmf_dbg(INFO, "fun = %d, addr = 0x%x, u8data = 0x%x\n",
+ fnc_num, addr, data);
+
+ return data;
+}
+
+void
+brcmf_sdcard_cfg_write(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr,
+ u8 data, int *err)
+{
+ int status;
+ s32 retry = 0;
+
+ do {
+ if (retry) /* wait for 1 ms till bus get settled down */
+ udelay(1000);
+ status = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, fnc_num,
+ addr, (u8 *) &data);
+ } while (status != 0
+ && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
+ if (err)
+ *err = status;
+
+ brcmf_dbg(INFO, "fun = %d, addr = 0x%x, u8data = 0x%x\n",
+ fnc_num, addr, data);
+}
+
+int
+brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
+{
+ int err = 0;
+ brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
+ (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
+ if (!err)
+ brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_SBADDRMID,
+ (address >> 16) & SBSDIO_SBADDRMID_MASK,
+ &err);
+ if (!err)
+ brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_SBADDRHIGH,
+ (address >> 24) & SBSDIO_SBADDRHIGH_MASK,
+ &err);
+
+ return err;
+}
+
+u32 brcmf_sdcard_reg_read(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size)
+{
+ int status;
+ u32 word = 0;
+ uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
+
+ brcmf_dbg(INFO, "fun = 1, addr = 0x%x\n", addr);
+
+ if (bar0 != sdiodev->sbwad) {
+ if (brcmf_sdcard_set_sbaddr_window(sdiodev, bar0))
+ return 0xFFFFFFFF;
+
+ sdiodev->sbwad = bar0;
+ }
+
+ addr &= SBSDIO_SB_OFT_ADDR_MASK;
+ if (size == 4)
+ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
+
+ status = brcmf_sdioh_request_word(sdiodev, SDIOH_READ, SDIO_FUNC_1,
+ addr, &word, size);
+
+ sdiodev->regfail = (status != 0);
+
+ brcmf_dbg(INFO, "u32data = 0x%x\n", word);
+
+ /* if ok, return appropriately masked word */
+ if (status == 0) {
+ switch (size) {
+ case sizeof(u8):
+ return word & 0xff;
+ case sizeof(u16):
+ return word & 0xffff;
+ case sizeof(u32):
+ return word;
+ default:
+ sdiodev->regfail = true;
+
+ }
+ }
+
+ /* otherwise, bad sdio access or invalid size */
+ brcmf_dbg(ERROR, "error reading addr 0x%04x size %d\n", addr, size);
+ return 0xFFFFFFFF;
+}
+
+u32 brcmf_sdcard_reg_write(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size,
+ u32 data)
+{
+ int status;
+ uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
+ int err = 0;
+
+ brcmf_dbg(INFO, "fun = 1, addr = 0x%x, uint%ddata = 0x%x\n",
+ addr, size * 8, data);
+
+ if (bar0 != sdiodev->sbwad) {
+ err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
+ if (err)
+ return err;
+
+ sdiodev->sbwad = bar0;
+ }
+
+ addr &= SBSDIO_SB_OFT_ADDR_MASK;
+ if (size == 4)
+ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
+ status =
+ brcmf_sdioh_request_word(sdiodev, SDIOH_WRITE, SDIO_FUNC_1,
+ addr, &data, size);
+ sdiodev->regfail = (status != 0);
+
+ if (status == 0)
+ return 0;
+
+ brcmf_dbg(ERROR, "error writing 0x%08x to addr 0x%04x size %d\n",
+ data, addr, size);
+ return 0xFFFFFFFF;
+}
+
+bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev)
+{
+ return sdiodev->regfail;
+}
+
+int
+brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
+ uint flags,
+ u8 *buf, uint nbytes, struct sk_buff *pkt)
+{
+ int status;
+ uint incr_fix;
+ uint width;
+ uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
+ int err = 0;
+
+ brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", fn, addr, nbytes);
+
+ /* Async not implemented yet */
+ if (flags & SDIO_REQ_ASYNC)
+ return -ENOTSUPP;
+
+ if (bar0 != sdiodev->sbwad) {
+ err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
+ if (err)
+ return err;
+
+ sdiodev->sbwad = bar0;
+ }
+
+ addr &= SBSDIO_SB_OFT_ADDR_MASK;
+
+ incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
+ width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
+ if (width == 4)
+ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
+
+ status = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_READ,
+ fn, addr, width, nbytes, buf, pkt);
+
+ return status;
+}
+
+int
+brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
+ uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt)
+{
+ uint incr_fix;
+ uint width;
+ uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
+ int err = 0;
+
+ brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", fn, addr, nbytes);
+
+ /* Async not implemented yet */
+ if (flags & SDIO_REQ_ASYNC)
+ return -ENOTSUPP;
+
+ if (bar0 != sdiodev->sbwad) {
+ err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
+ if (err)
+ return err;
+
+ sdiodev->sbwad = bar0;
+ }
+
+ addr &= SBSDIO_SB_OFT_ADDR_MASK;
+
+ incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
+ width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
+ if (width == 4)
+ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
+
+ return brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_WRITE, fn,
+ addr, width, nbytes, buf, pkt);
+}
+
+int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr,
+ u8 *buf, uint nbytes)
+{
+ addr &= SBSDIO_SB_OFT_ADDR_MASK;
+ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
+
+ return brcmf_sdioh_request_buffer(sdiodev, SDIOH_DATA_INC,
+ (rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1,
+ addr, 4, nbytes, buf, NULL);
+}
+
+int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
+{
+ char t_func = (char)fn;
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* issue abort cmd52 command through F0 */
+ brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0,
+ SDIO_CCCR_ABORT, &t_func);
+
+ brcmf_dbg(TRACE, "Exit\n");
+ return 0;
+}
+
+int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
+{
+ u32 regs = 0;
+ int ret = 0;
+
+ ret = brcmf_sdioh_attach(sdiodev);
+ if (ret)
+ goto out;
+
+ regs = SI_ENUM_BASE;
+
+ /* Report the BAR, to fix if needed */
+ sdiodev->sbwad = SI_ENUM_BASE;
+
+ /* try to attach to the target device */
+ sdiodev->bus = brcmf_sdbrcm_probe(0, 0, 0, 0, regs, sdiodev);
+ if (!sdiodev->bus) {
+ brcmf_dbg(ERROR, "device attach failed\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+out:
+ if (ret)
+ brcmf_sdio_remove(sdiodev);
+
+ return ret;
+}
+EXPORT_SYMBOL(brcmf_sdio_probe);
+
+int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev)
+{
+ if (sdiodev->bus) {
+ brcmf_sdbrcm_disconnect(sdiodev->bus);
+ sdiodev->bus = NULL;
+ }
+
+ brcmf_sdioh_detach(sdiodev);
+
+ sdiodev->sbwad = 0;
+
+ return 0;
+}
+EXPORT_SYMBOL(brcmf_sdio_remove);
+
+void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, bool enable)
+{
+ if (enable)
+ brcmf_sdbrcm_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
+ else
+ brcmf_sdbrcm_wd_timer(sdiodev->bus, 0);
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
new file mode 100644
index 000000000000..bbaeb2d5c93a
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
@@ -0,0 +1,626 @@
+/*
+ * Copyright (c) 2010 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/types.h>
+#include <linux/netdevice.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/core.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/card.h>
+#include <linux/suspend.h>
+#include <linux/errno.h>
+#include <linux/sched.h> /* request_irq() */
+#include <linux/module.h>
+#include <net/cfg80211.h>
+
+#include <defs.h>
+#include <brcm_hw_ids.h>
+#include <brcmu_utils.h>
+#include <brcmu_wifi.h>
+#include "sdio_host.h"
+#include "dhd.h"
+#include "dhd_dbg.h"
+#include "wl_cfg80211.h"
+
+#define SDIO_VENDOR_ID_BROADCOM 0x02d0
+
+#define DMA_ALIGN_MASK 0x03
+
+#define SDIO_DEVICE_ID_BROADCOM_4329 0x4329
+
+#define SDIO_FUNC1_BLOCKSIZE 64
+#define SDIO_FUNC2_BLOCKSIZE 512
+
+/* devices we support, null terminated */
+static const struct sdio_device_id brcmf_sdmmc_ids[] = {
+ {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)},
+ { /* end: all zeroes */ },
+};
+MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
+
+static bool
+brcmf_pm_resume_error(struct brcmf_sdio_dev *sdiodev)
+{
+ bool is_err = false;
+#ifdef CONFIG_PM_SLEEP
+ is_err = atomic_read(&sdiodev->suspend);
+#endif
+ return is_err;
+}
+
+static void
+brcmf_pm_resume_wait(struct brcmf_sdio_dev *sdiodev, wait_queue_head_t *wq)
+{
+#ifdef CONFIG_PM_SLEEP
+ int retry = 0;
+ while (atomic_read(&sdiodev->suspend) && retry++ != 30)
+ wait_event_timeout(*wq, false, HZ/100);
+#endif
+}
+
+static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev,
+ uint regaddr, u8 *byte)
+{
+ struct sdio_func *sdfunc = sdiodev->func[0];
+ int err_ret;
+
+ /*
+ * Can only directly write to some F0 registers.
+ * Handle F2 enable/disable and Abort command
+ * as a special case.
+ */
+ if (regaddr == SDIO_CCCR_IOEx) {
+ sdfunc = sdiodev->func[2];
+ if (sdfunc) {
+ sdio_claim_host(sdfunc);
+ if (*byte & SDIO_FUNC_ENABLE_2) {
+ /* Enable Function 2 */
+ err_ret = sdio_enable_func(sdfunc);
+ if (err_ret)
+ brcmf_dbg(ERROR,
+ "enable F2 failed:%d\n",
+ err_ret);
+ } else {
+ /* Disable Function 2 */
+ err_ret = sdio_disable_func(sdfunc);
+ if (err_ret)
+ brcmf_dbg(ERROR,
+ "Disable F2 failed:%d\n",
+ err_ret);
+ }
+ sdio_release_host(sdfunc);
+ }
+ } else if (regaddr == SDIO_CCCR_ABORT) {
+ sdio_claim_host(sdfunc);
+ sdio_writeb(sdfunc, *byte, regaddr, &err_ret);
+ sdio_release_host(sdfunc);
+ } else if (regaddr < 0xF0) {
+ brcmf_dbg(ERROR, "F0 Wr:0x%02x: write disallowed\n", regaddr);
+ err_ret = -EPERM;
+ } else {
+ sdio_claim_host(sdfunc);
+ sdio_f0_writeb(sdfunc, *byte, regaddr, &err_ret);
+ sdio_release_host(sdfunc);
+ }
+
+ return err_ret;
+}
+
+int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint func,
+ uint regaddr, u8 *byte)
+{
+ int err_ret;
+
+ brcmf_dbg(INFO, "rw=%d, func=%d, addr=0x%05x\n", rw, func, regaddr);
+
+ brcmf_pm_resume_wait(sdiodev, &sdiodev->request_byte_wait);
+ if (brcmf_pm_resume_error(sdiodev))
+ return -EIO;
+
+ if (rw && func == 0) {
+ /* handle F0 separately */
+ err_ret = brcmf_sdioh_f0_write_byte(sdiodev, regaddr, byte);
+ } else {
+ sdio_claim_host(sdiodev->func[func]);
+ if (rw) /* CMD52 Write */
+ sdio_writeb(sdiodev->func[func], *byte, regaddr,
+ &err_ret);
+ else if (func == 0) {
+ *byte = sdio_f0_readb(sdiodev->func[func], regaddr,
+ &err_ret);
+ } else {
+ *byte = sdio_readb(sdiodev->func[func], regaddr,
+ &err_ret);
+ }
+ sdio_release_host(sdiodev->func[func]);
+ }
+
+ if (err_ret)
+ brcmf_dbg(ERROR, "Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
+ rw ? "write" : "read", func, regaddr, *byte, err_ret);
+
+ return err_ret;
+}
+
+int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev,
+ uint rw, uint func, uint addr, u32 *word,
+ uint nbytes)
+{
+ int err_ret = -EIO;
+
+ if (func == 0) {
+ brcmf_dbg(ERROR, "Only CMD52 allowed to F0\n");
+ return -EINVAL;
+ }
+
+ brcmf_dbg(INFO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
+ rw, func, addr, nbytes);
+
+ brcmf_pm_resume_wait(sdiodev, &sdiodev->request_word_wait);
+ if (brcmf_pm_resume_error(sdiodev))
+ return -EIO;
+ /* Claim host controller */
+ sdio_claim_host(sdiodev->func[func]);
+
+ if (rw) { /* CMD52 Write */
+ if (nbytes == 4)
+ sdio_writel(sdiodev->func[func], *word, addr,
+ &err_ret);
+ else if (nbytes == 2)
+ sdio_writew(sdiodev->func[func], (*word & 0xFFFF),
+ addr, &err_ret);
+ else
+ brcmf_dbg(ERROR, "Invalid nbytes: %d\n", nbytes);
+ } else { /* CMD52 Read */
+ if (nbytes == 4)
+ *word = sdio_readl(sdiodev->func[func], addr, &err_ret);
+ else if (nbytes == 2)
+ *word = sdio_readw(sdiodev->func[func], addr,
+ &err_ret) & 0xFFFF;
+ else
+ brcmf_dbg(ERROR, "Invalid nbytes: %d\n", nbytes);
+ }
+
+ /* Release host controller */
+ sdio_release_host(sdiodev->func[func]);
+
+ if (err_ret)
+ brcmf_dbg(ERROR, "Failed to %s word, Err: 0x%08x\n",
+ rw ? "write" : "read", err_ret);
+
+ return err_ret;
+}
+
+static int
+brcmf_sdioh_request_packet(struct brcmf_sdio_dev *sdiodev, uint fix_inc,
+ uint write, uint func, uint addr,
+ struct sk_buff *pkt)
+{
+ bool fifo = (fix_inc == SDIOH_DATA_FIX);
+ u32 SGCount = 0;
+ int err_ret = 0;
+
+ struct sk_buff *pnext;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ brcmf_pm_resume_wait(sdiodev, &sdiodev->request_packet_wait);
+ if (brcmf_pm_resume_error(sdiodev))
+ return -EIO;
+
+ /* Claim host controller */
+ sdio_claim_host(sdiodev->func[func]);
+ for (pnext = pkt; pnext; pnext = pnext->next) {
+ uint pkt_len = pnext->len;
+ pkt_len += 3;
+ pkt_len &= 0xFFFFFFFC;
+
+ if ((write) && (!fifo)) {
+ err_ret = sdio_memcpy_toio(sdiodev->func[func], addr,
+ ((u8 *) (pnext->data)),
+ pkt_len);
+ } else if (write) {
+ err_ret = sdio_memcpy_toio(sdiodev->func[func], addr,
+ ((u8 *) (pnext->data)),
+ pkt_len);
+ } else if (fifo) {
+ err_ret = sdio_readsb(sdiodev->func[func],
+ ((u8 *) (pnext->data)),
+ addr, pkt_len);
+ } else {
+ err_ret = sdio_memcpy_fromio(sdiodev->func[func],
+ ((u8 *) (pnext->data)),
+ addr, pkt_len);
+ }
+
+ if (err_ret) {
+ brcmf_dbg(ERROR, "%s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
+ write ? "TX" : "RX", pnext, SGCount, addr,
+ pkt_len, err_ret);
+ } else {
+ brcmf_dbg(TRACE, "%s xfr'd %p[%d], addr=0x%05x, len=%d\n",
+ write ? "TX" : "RX", pnext, SGCount, addr,
+ pkt_len);
+ }
+
+ if (!fifo)
+ addr += pkt_len;
+ SGCount++;
+
+ }
+
+ /* Release host controller */
+ sdio_release_host(sdiodev->func[func]);
+
+ brcmf_dbg(TRACE, "Exit\n");
+ return err_ret;
+}
+
+/*
+ * This function takes a buffer or packet, and fixes everything up
+ * so that in the end, a DMA-able packet is created.
+ *
+ * A buffer does not have an associated packet pointer,
+ * and may or may not be aligned.
+ * A packet may consist of a single packet, or a packet chain.
+ * If it is a packet chain, then all the packets in the chain
+ * must be properly aligned.
+ *
+ * If the packet data is not aligned, then there may only be
+ * one packet, and in this case, it is copied to a new
+ * aligned packet.
+ *
+ */
+int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev,
+ uint fix_inc, uint write, uint func, uint addr,
+ uint reg_width, uint buflen_u, u8 *buffer,
+ struct sk_buff *pkt)
+{
+ int Status;
+ struct sk_buff *mypkt = NULL;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
+ if (brcmf_pm_resume_error(sdiodev))
+ return -EIO;
+ /* Case 1: we don't have a packet. */
+ if (pkt == NULL) {
+ brcmf_dbg(DATA, "Creating new %s Packet, len=%d\n",
+ write ? "TX" : "RX", buflen_u);
+ mypkt = brcmu_pkt_buf_get_skb(buflen_u);
+ if (!mypkt) {
+ brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
+ buflen_u);
+ return -EIO;
+ }
+
+ /* For a write, copy the buffer data into the packet. */
+ if (write)
+ memcpy(mypkt->data, buffer, buflen_u);
+
+ Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write,
+ func, addr, mypkt);
+
+ /* For a read, copy the packet data back to the buffer. */
+ if (!write)
+ memcpy(buffer, mypkt->data, buflen_u);
+
+ brcmu_pkt_buf_free_skb(mypkt);
+ } else if (((ulong) (pkt->data) & DMA_ALIGN_MASK) != 0) {
+ /*
+ * Case 2: We have a packet, but it is unaligned.
+ * In this case, we cannot have a chain (pkt->next == NULL)
+ */
+ brcmf_dbg(DATA, "Creating aligned %s Packet, len=%d\n",
+ write ? "TX" : "RX", pkt->len);
+ mypkt = brcmu_pkt_buf_get_skb(pkt->len);
+ if (!mypkt) {
+ brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
+ pkt->len);
+ return -EIO;
+ }
+
+ /* For a write, copy the buffer data into the packet. */
+ if (write)
+ memcpy(mypkt->data, pkt->data, pkt->len);
+
+ Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write,
+ func, addr, mypkt);
+
+ /* For a read, copy the packet data back to the buffer. */
+ if (!write)
+ memcpy(pkt->data, mypkt->data, mypkt->len);
+
+ brcmu_pkt_buf_free_skb(mypkt);
+ } else { /* case 3: We have a packet and
+ it is aligned. */
+ brcmf_dbg(DATA, "Aligned %s Packet, direct DMA\n",
+ write ? "Tx" : "Rx");
+ Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write,
+ func, addr, pkt);
+ }
+
+ return Status;
+}
+
+/* Read client card reg */
+static int
+brcmf_sdioh_card_regread(struct brcmf_sdio_dev *sdiodev, int func, u32 regaddr,
+ int regsize, u32 *data)
+{
+
+ if ((func == 0) || (regsize == 1)) {
+ u8 temp = 0;
+
+ brcmf_sdioh_request_byte(sdiodev, SDIOH_READ, func, regaddr,
+ &temp);
+ *data = temp;
+ *data &= 0xff;
+ brcmf_dbg(DATA, "byte read data=0x%02x\n", *data);
+ } else {
+ brcmf_sdioh_request_word(sdiodev, SDIOH_READ, func, regaddr,
+ data, regsize);
+ if (regsize == 2)
+ *data &= 0xffff;
+
+ brcmf_dbg(DATA, "word read data=0x%08x\n", *data);
+ }
+
+ return SUCCESS;
+}
+
+static int brcmf_sdioh_get_cisaddr(struct brcmf_sdio_dev *sdiodev, u32 regaddr)
+{
+ /* read 24 bits and return valid 17 bit addr */
+ int i;
+ u32 scratch, regdata;
+ __le32 scratch_le;
+ u8 *ptr = (u8 *)&scratch_le;
+
+ for (i = 0; i < 3; i++) {
+ if ((brcmf_sdioh_card_regread(sdiodev, 0, regaddr, 1,
+ &regdata)) != SUCCESS)
+ brcmf_dbg(ERROR, "Can't read!\n");
+
+ *ptr++ = (u8) regdata;
+ regaddr++;
+ }
+
+ /* Only the lower 17-bits are valid */
+ scratch = le32_to_cpu(scratch_le);
+ scratch &= 0x0001FFFF;
+ return scratch;
+}
+
+static int brcmf_sdioh_enablefuncs(struct brcmf_sdio_dev *sdiodev)
+{
+ int err_ret;
+ u32 fbraddr;
+ u8 func;
+
+ brcmf_dbg(TRACE, "\n");
+
+ /* Get the Card's common CIS address */
+ sdiodev->func_cis_ptr[0] = brcmf_sdioh_get_cisaddr(sdiodev,
+ SDIO_CCCR_CIS);
+ brcmf_dbg(INFO, "Card's Common CIS Ptr = 0x%x\n",
+ sdiodev->func_cis_ptr[0]);
+
+ /* Get the Card's function CIS (for each function) */
+ for (fbraddr = SDIO_FBR_BASE(1), func = 1;
+ func <= sdiodev->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) {
+ sdiodev->func_cis_ptr[func] =
+ brcmf_sdioh_get_cisaddr(sdiodev, SDIO_FBR_CIS + fbraddr);
+ brcmf_dbg(INFO, "Function %d CIS Ptr = 0x%x\n",
+ func, sdiodev->func_cis_ptr[func]);
+ }
+
+ /* Enable Function 1 */
+ sdio_claim_host(sdiodev->func[1]);
+ err_ret = sdio_enable_func(sdiodev->func[1]);
+ sdio_release_host(sdiodev->func[1]);
+ if (err_ret)
+ brcmf_dbg(ERROR, "Failed to enable F1 Err: 0x%08x\n", err_ret);
+
+ return false;
+}
+
+/*
+ * Public entry points & extern's
+ */
+int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)
+{
+ int err_ret = 0;
+
+ brcmf_dbg(TRACE, "\n");
+
+ sdiodev->num_funcs = 2;
+
+ sdio_claim_host(sdiodev->func[1]);
+ err_ret = sdio_set_block_size(sdiodev->func[1], SDIO_FUNC1_BLOCKSIZE);
+ sdio_release_host(sdiodev->func[1]);
+ if (err_ret) {
+ brcmf_dbg(ERROR, "Failed to set F1 blocksize\n");
+ goto out;
+ }
+
+ sdio_claim_host(sdiodev->func[2]);
+ err_ret = sdio_set_block_size(sdiodev->func[2], SDIO_FUNC2_BLOCKSIZE);
+ sdio_release_host(sdiodev->func[2]);
+ if (err_ret) {
+ brcmf_dbg(ERROR, "Failed to set F2 blocksize\n");
+ goto out;
+ }
+
+ brcmf_sdioh_enablefuncs(sdiodev);
+
+out:
+ brcmf_dbg(TRACE, "Done\n");
+ return err_ret;
+}
+
+void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev)
+{
+ brcmf_dbg(TRACE, "\n");
+
+ /* Disable Function 2 */
+ sdio_claim_host(sdiodev->func[2]);
+ sdio_disable_func(sdiodev->func[2]);
+ sdio_release_host(sdiodev->func[2]);
+
+ /* Disable Function 1 */
+ sdio_claim_host(sdiodev->func[1]);
+ sdio_disable_func(sdiodev->func[1]);
+ sdio_release_host(sdiodev->func[1]);
+
+}
+
+static int brcmf_ops_sdio_probe(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ int ret = 0;
+ struct brcmf_sdio_dev *sdiodev;
+ brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(TRACE, "func->class=%x\n", func->class);
+ brcmf_dbg(TRACE, "sdio_vendor: 0x%04x\n", func->vendor);
+ brcmf_dbg(TRACE, "sdio_device: 0x%04x\n", func->device);
+ brcmf_dbg(TRACE, "Function#: 0x%04x\n", func->num);
+
+ if (func->num == 1) {
+ if (dev_get_drvdata(&func->card->dev)) {
+ brcmf_dbg(ERROR, "card private drvdata occupied\n");
+ return -ENXIO;
+ }
+ sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL);
+ if (!sdiodev)
+ return -ENOMEM;
+ sdiodev->func[0] = func->card->sdio_func[0];
+ sdiodev->func[1] = func;
+ dev_set_drvdata(&func->card->dev, sdiodev);
+
+ atomic_set(&sdiodev->suspend, false);
+ init_waitqueue_head(&sdiodev->request_byte_wait);
+ init_waitqueue_head(&sdiodev->request_word_wait);
+ init_waitqueue_head(&sdiodev->request_packet_wait);
+ init_waitqueue_head(&sdiodev->request_buffer_wait);
+ }
+
+ if (func->num == 2) {
+ sdiodev = dev_get_drvdata(&func->card->dev);
+ if ((!sdiodev) || (sdiodev->func[1]->card != func->card))
+ return -ENODEV;
+ sdiodev->func[2] = func;
+
+ brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_probe...\n");
+ ret = brcmf_sdio_probe(sdiodev);
+ }
+
+ return ret;
+}
+
+static void brcmf_ops_sdio_remove(struct sdio_func *func)
+{
+ struct brcmf_sdio_dev *sdiodev;
+ brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(INFO, "func->class=%x\n", func->class);
+ brcmf_dbg(INFO, "sdio_vendor: 0x%04x\n", func->vendor);
+ brcmf_dbg(INFO, "sdio_device: 0x%04x\n", func->device);
+ brcmf_dbg(INFO, "Function#: 0x%04x\n", func->num);
+
+ if (func->num == 2) {
+ sdiodev = dev_get_drvdata(&func->card->dev);
+ brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_remove...\n");
+ brcmf_sdio_remove(sdiodev);
+ dev_set_drvdata(&func->card->dev, NULL);
+ kfree(sdiodev);
+ }
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int brcmf_sdio_suspend(struct device *dev)
+{
+ mmc_pm_flag_t sdio_flags;
+ struct brcmf_sdio_dev *sdiodev;
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ int ret = 0;
+
+ brcmf_dbg(TRACE, "\n");
+
+ sdiodev = dev_get_drvdata(&func->card->dev);
+
+ atomic_set(&sdiodev->suspend, true);
+
+ sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]);
+ if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
+ brcmf_dbg(ERROR, "Host can't keep power while suspended\n");
+ return -EINVAL;
+ }
+
+ ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER);
+ if (ret) {
+ brcmf_dbg(ERROR, "Failed to set pm_flags\n");
+ return ret;
+ }
+
+ brcmf_sdio_wdtmr_enable(sdiodev, false);
+
+ return ret;
+}
+
+static int brcmf_sdio_resume(struct device *dev)
+{
+ struct brcmf_sdio_dev *sdiodev;
+ struct sdio_func *func = dev_to_sdio_func(dev);
+
+ sdiodev = dev_get_drvdata(&func->card->dev);
+ brcmf_sdio_wdtmr_enable(sdiodev, true);
+ atomic_set(&sdiodev->suspend, false);
+ return 0;
+}
+
+static const struct dev_pm_ops brcmf_sdio_pm_ops = {
+ .suspend = brcmf_sdio_suspend,
+ .resume = brcmf_sdio_resume,
+};
+#endif /* CONFIG_PM_SLEEP */
+
+static struct sdio_driver brcmf_sdmmc_driver = {
+ .probe = brcmf_ops_sdio_probe,
+ .remove = brcmf_ops_sdio_remove,
+ .name = "brcmfmac",
+ .id_table = brcmf_sdmmc_ids,
+#ifdef CONFIG_PM_SLEEP
+ .drv = {
+ .pm = &brcmf_sdio_pm_ops,
+ },
+#endif /* CONFIG_PM_SLEEP */
+};
+
+/* bus register interface */
+int brcmf_bus_register(void)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ return sdio_register_driver(&brcmf_sdmmc_driver);
+}
+
+void brcmf_bus_unregister(void)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ sdio_unregister_driver(&brcmf_sdmmc_driver);
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
new file mode 100644
index 000000000000..4645766b4070
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
@@ -0,0 +1,776 @@
+/*
+ * Copyright (c) 2010 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.
+ */
+
+/****************
+ * Common types *
+ */
+
+#ifndef _BRCMF_H_
+#define _BRCMF_H_
+
+#define BRCMF_VERSION_STR "4.218.248.5"
+
+/*******************************************************************************
+ * IO codes that are interpreted by dongle firmware
+ ******************************************************************************/
+#define BRCMF_C_UP 2
+#define BRCMF_C_SET_PROMISC 10
+#define BRCMF_C_GET_RATE 12
+#define BRCMF_C_GET_INFRA 19
+#define BRCMF_C_SET_INFRA 20
+#define BRCMF_C_GET_AUTH 21
+#define BRCMF_C_SET_AUTH 22
+#define BRCMF_C_GET_BSSID 23
+#define BRCMF_C_GET_SSID 25
+#define BRCMF_C_SET_SSID 26
+#define BRCMF_C_GET_CHANNEL 29
+#define BRCMF_C_GET_SRL 31
+#define BRCMF_C_GET_LRL 33
+#define BRCMF_C_GET_RADIO 37
+#define BRCMF_C_SET_RADIO 38
+#define BRCMF_C_GET_PHYTYPE 39
+#define BRCMF_C_SET_KEY 45
+#define BRCMF_C_SET_PASSIVE_SCAN 49
+#define BRCMF_C_SCAN 50
+#define BRCMF_C_SCAN_RESULTS 51
+#define BRCMF_C_DISASSOC 52
+#define BRCMF_C_REASSOC 53
+#define BRCMF_C_SET_ROAM_TRIGGER 55
+#define BRCMF_C_SET_ROAM_DELTA 57
+#define BRCMF_C_GET_DTIMPRD 77
+#define BRCMF_C_SET_COUNTRY 84
+#define BRCMF_C_GET_PM 85
+#define BRCMF_C_SET_PM 86
+#define BRCMF_C_GET_AP 117
+#define BRCMF_C_SET_AP 118
+#define BRCMF_C_GET_RSSI 127
+#define BRCMF_C_GET_WSEC 133
+#define BRCMF_C_SET_WSEC 134
+#define BRCMF_C_GET_PHY_NOISE 135
+#define BRCMF_C_GET_BSS_INFO 136
+#define BRCMF_C_SET_SCAN_CHANNEL_TIME 185
+#define BRCMF_C_SET_SCAN_UNASSOC_TIME 187
+#define BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON 201
+#define BRCMF_C_GET_VALID_CHANNELS 217
+#define BRCMF_C_GET_KEY_PRIMARY 235
+#define BRCMF_C_SET_KEY_PRIMARY 236
+#define BRCMF_C_SET_SCAN_PASSIVE_TIME 258
+#define BRCMF_C_GET_VAR 262
+#define BRCMF_C_SET_VAR 263
+
+/* phy types (returned by WLC_GET_PHYTPE) */
+#define WLC_PHY_TYPE_A 0
+#define WLC_PHY_TYPE_B 1
+#define WLC_PHY_TYPE_G 2
+#define WLC_PHY_TYPE_N 4
+#define WLC_PHY_TYPE_LP 5
+#define WLC_PHY_TYPE_SSN 6
+#define WLC_PHY_TYPE_HT 7
+#define WLC_PHY_TYPE_LCN 8
+#define WLC_PHY_TYPE_NULL 0xf
+
+#define BRCMF_EVENTING_MASK_LEN 16
+
+#define TOE_TX_CSUM_OL 0x00000001
+#define TOE_RX_CSUM_OL 0x00000002
+
+#define BRCMF_BSS_INFO_VERSION 108 /* current ver of brcmf_bss_info struct */
+
+/* size of brcmf_scan_params not including variable length array */
+#define BRCMF_SCAN_PARAMS_FIXED_SIZE 64
+
+/* masks for channel and ssid count */
+#define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff
+#define BRCMF_SCAN_PARAMS_NSSID_SHIFT 16
+
+#define BRCMF_SCAN_ACTION_START 1
+#define BRCMF_SCAN_ACTION_CONTINUE 2
+#define WL_SCAN_ACTION_ABORT 3
+
+#define BRCMF_ISCAN_REQ_VERSION 1
+
+/* brcmf_iscan_results status values */
+#define BRCMF_SCAN_RESULTS_SUCCESS 0
+#define BRCMF_SCAN_RESULTS_PARTIAL 1
+#define BRCMF_SCAN_RESULTS_PENDING 2
+#define BRCMF_SCAN_RESULTS_ABORTED 3
+#define BRCMF_SCAN_RESULTS_NO_MEM 4
+
+/* Indicates this key is using soft encrypt */
+#define WL_SOFT_KEY (1 << 0)
+/* primary (ie tx) key */
+#define BRCMF_PRIMARY_KEY (1 << 1)
+/* Reserved for backward compat */
+#define WL_KF_RES_4 (1 << 4)
+/* Reserved for backward compat */
+#define WL_KF_RES_5 (1 << 5)
+/* Indicates a group key for a IBSS PEER */
+#define WL_IBSS_PEER_GROUP_KEY (1 << 6)
+
+/* For supporting multiple interfaces */
+#define BRCMF_MAX_IFS 16
+#define BRCMF_DEL_IF -0xe
+#define BRCMF_BAD_IF -0xf
+
+#define DOT11_BSSTYPE_ANY 2
+#define DOT11_MAX_DEFAULT_KEYS 4
+
+#define BRCMF_EVENT_MSG_LINK 0x01
+#define BRCMF_EVENT_MSG_FLUSHTXQ 0x02
+#define BRCMF_EVENT_MSG_GROUP 0x04
+
+struct brcmf_event_msg {
+ __be16 version;
+ __be16 flags;
+ __be32 event_type;
+ __be32 status;
+ __be32 reason;
+ __be32 auth_type;
+ __be32 datalen;
+ u8 addr[ETH_ALEN];
+ char ifname[IFNAMSIZ];
+} __packed;
+
+struct brcm_ethhdr {
+ u16 subtype;
+ u16 length;
+ u8 version;
+ u8 oui[3];
+ u16 usr_subtype;
+} __packed;
+
+struct brcmf_event {
+ struct ethhdr eth;
+ struct brcm_ethhdr hdr;
+ struct brcmf_event_msg msg;
+} __packed;
+
+struct dngl_stats {
+ unsigned long rx_packets; /* total packets received */
+ unsigned long tx_packets; /* total packets transmitted */
+ unsigned long rx_bytes; /* total bytes received */
+ unsigned long tx_bytes; /* total bytes transmitted */
+ unsigned long rx_errors; /* bad packets received */
+ unsigned long tx_errors; /* packet transmit problems */
+ unsigned long rx_dropped; /* packets dropped by dongle */
+ unsigned long tx_dropped; /* packets dropped by dongle */
+ unsigned long multicast; /* multicast packets received */
+};
+
+/* event codes sent by the dongle to this driver */
+#define BRCMF_E_SET_SSID 0
+#define BRCMF_E_JOIN 1
+#define BRCMF_E_START 2
+#define BRCMF_E_AUTH 3
+#define BRCMF_E_AUTH_IND 4
+#define BRCMF_E_DEAUTH 5
+#define BRCMF_E_DEAUTH_IND 6
+#define BRCMF_E_ASSOC 7
+#define BRCMF_E_ASSOC_IND 8
+#define BRCMF_E_REASSOC 9
+#define BRCMF_E_REASSOC_IND 10
+#define BRCMF_E_DISASSOC 11
+#define BRCMF_E_DISASSOC_IND 12
+#define BRCMF_E_QUIET_START 13
+#define BRCMF_E_QUIET_END 14
+#define BRCMF_E_BEACON_RX 15
+#define BRCMF_E_LINK 16
+#define BRCMF_E_MIC_ERROR 17
+#define BRCMF_E_NDIS_LINK 18
+#define BRCMF_E_ROAM 19
+#define BRCMF_E_TXFAIL 20
+#define BRCMF_E_PMKID_CACHE 21
+#define BRCMF_E_RETROGRADE_TSF 22
+#define BRCMF_E_PRUNE 23
+#define BRCMF_E_AUTOAUTH 24
+#define BRCMF_E_EAPOL_MSG 25
+#define BRCMF_E_SCAN_COMPLETE 26
+#define BRCMF_E_ADDTS_IND 27
+#define BRCMF_E_DELTS_IND 28
+#define BRCMF_E_BCNSENT_IND 29
+#define BRCMF_E_BCNRX_MSG 30
+#define BRCMF_E_BCNLOST_MSG 31
+#define BRCMF_E_ROAM_PREP 32
+#define BRCMF_E_PFN_NET_FOUND 33
+#define BRCMF_E_PFN_NET_LOST 34
+#define BRCMF_E_RESET_COMPLETE 35
+#define BRCMF_E_JOIN_START 36
+#define BRCMF_E_ROAM_START 37
+#define BRCMF_E_ASSOC_START 38
+#define BRCMF_E_IBSS_ASSOC 39
+#define BRCMF_E_RADIO 40
+#define BRCMF_E_PSM_WATCHDOG 41
+#define BRCMF_E_PROBREQ_MSG 44
+#define BRCMF_E_SCAN_CONFIRM_IND 45
+#define BRCMF_E_PSK_SUP 46
+#define BRCMF_E_COUNTRY_CODE_CHANGED 47
+#define BRCMF_E_EXCEEDED_MEDIUM_TIME 48
+#define BRCMF_E_ICV_ERROR 49
+#define BRCMF_E_UNICAST_DECODE_ERROR 50
+#define BRCMF_E_MULTICAST_DECODE_ERROR 51
+#define BRCMF_E_TRACE 52
+#define BRCMF_E_IF 54
+#define BRCMF_E_RSSI 56
+#define BRCMF_E_PFN_SCAN_COMPLETE 57
+#define BRCMF_E_EXTLOG_MSG 58
+#define BRCMF_E_ACTION_FRAME 59
+#define BRCMF_E_ACTION_FRAME_COMPLETE 60
+#define BRCMF_E_PRE_ASSOC_IND 61
+#define BRCMF_E_PRE_REASSOC_IND 62
+#define BRCMF_E_CHANNEL_ADOPTED 63
+#define BRCMF_E_AP_STARTED 64
+#define BRCMF_E_DFS_AP_STOP 65
+#define BRCMF_E_DFS_AP_RESUME 66
+#define BRCMF_E_RESERVED1 67
+#define BRCMF_E_RESERVED2 68
+#define BRCMF_E_ESCAN_RESULT 69
+#define BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70
+#define BRCMF_E_DCS_REQUEST 73
+
+#define BRCMF_E_FIFO_CREDIT_MAP 74
+
+#define BRCMF_E_LAST 75
+
+#define BRCMF_E_STATUS_SUCCESS 0
+#define BRCMF_E_STATUS_FAIL 1
+#define BRCMF_E_STATUS_TIMEOUT 2
+#define BRCMF_E_STATUS_NO_NETWORKS 3
+#define BRCMF_E_STATUS_ABORT 4
+#define BRCMF_E_STATUS_NO_ACK 5
+#define BRCMF_E_STATUS_UNSOLICITED 6
+#define BRCMF_E_STATUS_ATTEMPT 7
+#define BRCMF_E_STATUS_PARTIAL 8
+#define BRCMF_E_STATUS_NEWSCAN 9
+#define BRCMF_E_STATUS_NEWASSOC 10
+#define BRCMF_E_STATUS_11HQUIET 11
+#define BRCMF_E_STATUS_SUPPRESS 12
+#define BRCMF_E_STATUS_NOCHANS 13
+#define BRCMF_E_STATUS_CS_ABORT 15
+#define BRCMF_E_STATUS_ERROR 16
+
+#define BRCMF_E_REASON_INITIAL_ASSOC 0
+#define BRCMF_E_REASON_LOW_RSSI 1
+#define BRCMF_E_REASON_DEAUTH 2
+#define BRCMF_E_REASON_DISASSOC 3
+#define BRCMF_E_REASON_BCNS_LOST 4
+#define BRCMF_E_REASON_MINTXRATE 9
+#define BRCMF_E_REASON_TXFAIL 10
+
+#define BRCMF_E_REASON_FAST_ROAM_FAILED 5
+#define BRCMF_E_REASON_DIRECTED_ROAM 6
+#define BRCMF_E_REASON_TSPEC_REJECTED 7
+#define BRCMF_E_REASON_BETTER_AP 8
+
+#define BRCMF_E_PRUNE_ENCR_MISMATCH 1
+#define BRCMF_E_PRUNE_BCAST_BSSID 2
+#define BRCMF_E_PRUNE_MAC_DENY 3
+#define BRCMF_E_PRUNE_MAC_NA 4
+#define BRCMF_E_PRUNE_REG_PASSV 5
+#define BRCMF_E_PRUNE_SPCT_MGMT 6
+#define BRCMF_E_PRUNE_RADAR 7
+#define BRCMF_E_RSN_MISMATCH 8
+#define BRCMF_E_PRUNE_NO_COMMON_RATES 9
+#define BRCMF_E_PRUNE_BASIC_RATES 10
+#define BRCMF_E_PRUNE_CIPHER_NA 12
+#define BRCMF_E_PRUNE_KNOWN_STA 13
+#define BRCMF_E_PRUNE_WDS_PEER 15
+#define BRCMF_E_PRUNE_QBSS_LOAD 16
+#define BRCMF_E_PRUNE_HOME_AP 17
+
+#define BRCMF_E_SUP_OTHER 0
+#define BRCMF_E_SUP_DECRYPT_KEY_DATA 1
+#define BRCMF_E_SUP_BAD_UCAST_WEP128 2
+#define BRCMF_E_SUP_BAD_UCAST_WEP40 3
+#define BRCMF_E_SUP_UNSUP_KEY_LEN 4
+#define BRCMF_E_SUP_PW_KEY_CIPHER 5
+#define BRCMF_E_SUP_MSG3_TOO_MANY_IE 6
+#define BRCMF_E_SUP_MSG3_IE_MISMATCH 7
+#define BRCMF_E_SUP_NO_INSTALL_FLAG 8
+#define BRCMF_E_SUP_MSG3_NO_GTK 9
+#define BRCMF_E_SUP_GRP_KEY_CIPHER 10
+#define BRCMF_E_SUP_GRP_MSG1_NO_GTK 11
+#define BRCMF_E_SUP_GTK_DECRYPT_FAIL 12
+#define BRCMF_E_SUP_SEND_FAIL 13
+#define BRCMF_E_SUP_DEAUTH 14
+
+#define BRCMF_E_IF_ADD 1
+#define BRCMF_E_IF_DEL 2
+#define BRCMF_E_IF_CHANGE 3
+
+#define BRCMF_E_IF_ROLE_STA 0
+#define BRCMF_E_IF_ROLE_AP 1
+#define BRCMF_E_IF_ROLE_WDS 2
+
+#define BRCMF_E_LINK_BCN_LOSS 1
+#define BRCMF_E_LINK_DISASSOC 2
+#define BRCMF_E_LINK_ASSOC_REC 3
+#define BRCMF_E_LINK_BSSCFG_DIS 4
+
+/* The level of bus communication with the dongle */
+enum brcmf_bus_state {
+ BRCMF_BUS_DOWN, /* Not ready for frame transfers */
+ BRCMF_BUS_LOAD, /* Download access only (CPU reset) */
+ BRCMF_BUS_DATA /* Ready for frame transfers */
+};
+
+/* Pattern matching filter. Specifies an offset within received packets to
+ * start matching, the pattern to match, the size of the pattern, and a bitmask
+ * that indicates which bits within the pattern should be matched.
+ */
+struct brcmf_pkt_filter_pattern_le {
+ /*
+ * Offset within received packet to start pattern matching.
+ * Offset '0' is the first byte of the ethernet header.
+ */
+ __le32 offset;
+ /* Size of the pattern. Bitmask must be the same size.*/
+ __le32 size_bytes;
+ /*
+ * Variable length mask and pattern data. mask starts at offset 0.
+ * Pattern immediately follows mask.
+ */
+ u8 mask_and_pattern[1];
+};
+
+/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */
+struct brcmf_pkt_filter_le {
+ __le32 id; /* Unique filter id, specified by app. */
+ __le32 type; /* Filter type (WL_PKT_FILTER_TYPE_xxx). */
+ __le32 negate_match; /* Negate the result of filter matches */
+ union { /* Filter definitions */
+ struct brcmf_pkt_filter_pattern_le pattern; /* Filter pattern */
+ } u;
+};
+
+/* IOVAR "pkt_filter_enable" parameter. */
+struct brcmf_pkt_filter_enable_le {
+ __le32 id; /* Unique filter id */
+ __le32 enable; /* Enable/disable bool */
+};
+
+/* BSS info structure
+ * Applications MUST CHECK ie_offset field and length field to access IEs and
+ * next bss_info structure in a vector (in struct brcmf_scan_results)
+ */
+struct brcmf_bss_info {
+ __le32 version; /* version field */
+ __le32 length; /* byte length of data in this record,
+ * starting at version and including IEs
+ */
+ u8 BSSID[ETH_ALEN];
+ __le16 beacon_period; /* units are Kusec */
+ __le16 capability; /* Capability information */
+ u8 SSID_len;
+ u8 SSID[32];
+ struct {
+ __le32 count; /* # rates in this set */
+ u8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */
+ } rateset; /* supported rates */
+ __le16 chanspec; /* chanspec for bss */
+ __le16 atim_window; /* units are Kusec */
+ u8 dtim_period; /* DTIM period */
+ __le16 RSSI; /* receive signal strength (in dBm) */
+ s8 phy_noise; /* noise (in dBm) */
+
+ u8 n_cap; /* BSS is 802.11N Capable */
+ /* 802.11N BSS Capabilities (based on HT_CAP_*): */
+ __le32 nbss_cap;
+ u8 ctl_ch; /* 802.11N BSS control channel number */
+ __le32 reserved32[1]; /* Reserved for expansion of BSS properties */
+ u8 flags; /* flags */
+ u8 reserved[3]; /* Reserved for expansion of BSS properties */
+ u8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */
+
+ __le16 ie_offset; /* offset at which IEs start, from beginning */
+ __le32 ie_length; /* byte length of Information Elements */
+ __le16 SNR; /* average SNR of during frame reception */
+ /* Add new fields here */
+ /* variable length Information Elements */
+};
+
+struct brcm_rateset_le {
+ /* # rates in this set */
+ __le32 count;
+ /* rates in 500kbps units w/hi bit set if basic */
+ u8 rates[WL_NUMRATES];
+};
+
+struct brcmf_ssid {
+ u32 SSID_len;
+ unsigned char SSID[32];
+};
+
+struct brcmf_ssid_le {
+ __le32 SSID_len;
+ unsigned char SSID[32];
+};
+
+struct brcmf_scan_params_le {
+ struct brcmf_ssid_le ssid_le; /* default: {0, ""} */
+ u8 bssid[ETH_ALEN]; /* default: bcast */
+ s8 bss_type; /* default: any,
+ * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT
+ */
+ u8 scan_type; /* flags, 0 use default */
+ __le32 nprobes; /* -1 use default, number of probes per channel */
+ __le32 active_time; /* -1 use default, dwell time per channel for
+ * active scanning
+ */
+ __le32 passive_time; /* -1 use default, dwell time per channel
+ * for passive scanning
+ */
+ __le32 home_time; /* -1 use default, dwell time for the
+ * home channel between channel scans
+ */
+ __le32 channel_num; /* count of channels and ssids that follow
+ *
+ * low half is count of channels in
+ * channel_list, 0 means default (use all
+ * available channels)
+ *
+ * high half is entries in struct brcmf_ssid
+ * array that follows channel_list, aligned for
+ * s32 (4 bytes) meaning an odd channel count
+ * implies a 2-byte pad between end of
+ * channel_list and first ssid
+ *
+ * if ssid count is zero, single ssid in the
+ * fixed parameter portion is assumed, otherwise
+ * ssid in the fixed portion is ignored
+ */
+ __le16 channel_list[1]; /* list of chanspecs */
+};
+
+/* incremental scan struct */
+struct brcmf_iscan_params_le {
+ __le32 version;
+ __le16 action;
+ __le16 scan_duration;
+ struct brcmf_scan_params_le params_le;
+};
+
+struct brcmf_scan_results {
+ u32 buflen;
+ u32 version;
+ u32 count;
+ struct brcmf_bss_info bss_info[1];
+};
+
+struct brcmf_scan_results_le {
+ __le32 buflen;
+ __le32 version;
+ __le32 count;
+ struct brcmf_bss_info bss_info[1];
+};
+
+/* used for association with a specific BSSID and chanspec list */
+struct brcmf_assoc_params_le {
+ /* 00:00:00:00:00:00: broadcast scan */
+ u8 bssid[ETH_ALEN];
+ /* 0: all available channels, otherwise count of chanspecs in
+ * chanspec_list */
+ __le32 chanspec_num;
+ /* list of chanspecs */
+ __le16 chanspec_list[1];
+};
+
+/* used for join with or without a specific bssid and channel list */
+struct brcmf_join_params {
+ struct brcmf_ssid_le ssid_le;
+ struct brcmf_assoc_params_le params_le;
+};
+
+/* size of brcmf_scan_results not including variable length array */
+#define BRCMF_SCAN_RESULTS_FIXED_SIZE \
+ (sizeof(struct brcmf_scan_results) - sizeof(struct brcmf_bss_info))
+
+/* incremental scan results struct */
+struct brcmf_iscan_results {
+ union {
+ u32 status;
+ __le32 status_le;
+ };
+ union {
+ struct brcmf_scan_results results;
+ struct brcmf_scan_results_le results_le;
+ };
+};
+
+/* size of brcmf_iscan_results not including variable length array */
+#define BRCMF_ISCAN_RESULTS_FIXED_SIZE \
+ (BRCMF_SCAN_RESULTS_FIXED_SIZE + \
+ offsetof(struct brcmf_iscan_results, results))
+
+struct brcmf_wsec_key {
+ u32 index; /* key index */
+ u32 len; /* key length */
+ u8 data[WLAN_MAX_KEY_LEN]; /* key data */
+ u32 pad_1[18];
+ u32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */
+ u32 flags; /* misc flags */
+ u32 pad_2[3];
+ u32 iv_initialized; /* has IV been initialized already? */
+ u32 pad_3;
+ /* Rx IV */
+ struct {
+ u32 hi; /* upper 32 bits of IV */
+ u16 lo; /* lower 16 bits of IV */
+ } rxiv;
+ u32 pad_4[2];
+ u8 ea[ETH_ALEN]; /* per station */
+};
+
+/*
+ * dongle requires same struct as above but with fields in little endian order
+ */
+struct brcmf_wsec_key_le {
+ __le32 index; /* key index */
+ __le32 len; /* key length */
+ u8 data[WLAN_MAX_KEY_LEN]; /* key data */
+ __le32 pad_1[18];
+ __le32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */
+ __le32 flags; /* misc flags */
+ __le32 pad_2[3];
+ __le32 iv_initialized; /* has IV been initialized already? */
+ __le32 pad_3;
+ /* Rx IV */
+ struct {
+ __le32 hi; /* upper 32 bits of IV */
+ __le16 lo; /* lower 16 bits of IV */
+ } rxiv;
+ __le32 pad_4[2];
+ u8 ea[ETH_ALEN]; /* per station */
+};
+
+/* Used to get specific STA parameters */
+struct brcmf_scb_val_le {
+ __le32 val;
+ u8 ea[ETH_ALEN];
+};
+
+/* channel encoding */
+struct brcmf_channel_info_le {
+ __le32 hw_channel;
+ __le32 target_channel;
+ __le32 scan_channel;
+};
+
+/* Bus independent dongle command */
+struct brcmf_dcmd {
+ uint cmd; /* common dongle cmd definition */
+ void *buf; /* pointer to user buffer */
+ uint len; /* length of user buffer */
+ u8 set; /* get or set request (optional) */
+ uint used; /* bytes read or written (optional) */
+ uint needed; /* bytes needed (optional) */
+};
+
+/* Forward decls for struct brcmf_pub (see below) */
+struct brcmf_bus; /* device bus info */
+struct brcmf_proto; /* device communication protocol info */
+struct brcmf_info; /* device driver info */
+struct brcmf_cfg80211_dev; /* cfg80211 device info */
+
+/* Common structure for module and instance linkage */
+struct brcmf_pub {
+ /* Linkage ponters */
+ struct brcmf_bus *bus;
+ struct brcmf_proto *prot;
+ struct brcmf_info *info;
+ struct brcmf_cfg80211_dev *config;
+
+ /* Internal brcmf items */
+ bool up; /* Driver up/down (to OS) */
+ bool txoff; /* Transmit flow-controlled */
+ enum brcmf_bus_state busstate;
+ uint hdrlen; /* Total BRCMF header length (proto + bus) */
+ uint maxctl; /* Max size rxctl request from proto to bus */
+ uint rxsz; /* Rx buffer size bus module should use */
+ u8 wme_dp; /* wme discard priority */
+
+ /* Dongle media info */
+ bool iswl; /* Dongle-resident driver is wl */
+ unsigned long drv_version; /* Version of dongle-resident driver */
+ u8 mac[ETH_ALEN]; /* MAC address obtained from dongle */
+ struct dngl_stats dstats; /* Stats for dongle-based data */
+
+ /* Additional stats for the bus level */
+
+ /* Data packets sent to dongle */
+ unsigned long tx_packets;
+ /* Multicast data packets sent to dongle */
+ unsigned long tx_multicast;
+ /* Errors in sending data to dongle */
+ unsigned long tx_errors;
+ /* Control packets sent to dongle */
+ unsigned long tx_ctlpkts;
+ /* Errors sending control frames to dongle */
+ unsigned long tx_ctlerrs;
+ /* Packets sent up the network interface */
+ unsigned long rx_packets;
+ /* Multicast packets sent up the network interface */
+ unsigned long rx_multicast;
+ /* Errors processing rx data packets */
+ unsigned long rx_errors;
+ /* Control frames processed from dongle */
+ unsigned long rx_ctlpkts;
+
+ /* Errors in processing rx control frames */
+ unsigned long rx_ctlerrs;
+ /* Packets dropped locally (no memory) */
+ unsigned long rx_dropped;
+ /* Packets flushed due to unscheduled sendup thread */
+ unsigned long rx_flushed;
+ /* Number of times dpc scheduled by watchdog timer */
+ unsigned long wd_dpc_sched;
+
+ /* Number of packets where header read-ahead was used. */
+ unsigned long rx_readahead_cnt;
+ /* Number of tx packets we had to realloc for headroom */
+ unsigned long tx_realloc;
+ /* Number of flow control pkts recvd */
+ unsigned long fc_packets;
+
+ /* Last error return */
+ int bcmerror;
+ uint tickcnt;
+
+ /* Last error from dongle */
+ int dongle_error;
+
+ /* Suspend disable flag flag */
+ int suspend_disable_flag; /* "1" to disable all extra powersaving
+ during suspend */
+ int in_suspend; /* flag set to 1 when early suspend called */
+ int dtim_skip; /* dtim skip , default 0 means wake each dtim */
+
+ /* Pkt filter defination */
+ char *pktfilter[100];
+ int pktfilter_count;
+
+ u8 country_code[BRCM_CNTRY_BUF_SZ];
+ char eventmask[BRCMF_EVENTING_MASK_LEN];
+
+};
+
+struct brcmf_if_event {
+ u8 ifidx;
+ u8 action;
+ u8 flags;
+ u8 bssidx;
+};
+
+struct bcmevent_name {
+ uint event;
+ const char *name;
+};
+
+extern const struct bcmevent_name bcmevent_names[];
+
+extern uint brcmf_c_mkiovar(char *name, char *data, uint datalen,
+ char *buf, uint len);
+
+/* Indication from bus module regarding presence/insertion of dongle.
+ * Return struct brcmf_pub pointer, used as handle to OS module in later calls.
+ * Returned structure should have bus and prot pointers filled in.
+ * bus_hdrlen specifies required headroom for bus module header.
+ */
+extern struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus,
+ uint bus_hdrlen);
+extern int brcmf_net_attach(struct brcmf_pub *drvr, int idx);
+extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev);
+
+extern s32 brcmf_exec_dcmd(struct net_device *dev, u32 cmd, void *arg, u32 len);
+
+/* Indication from bus module regarding removal/absence of dongle */
+extern void brcmf_detach(struct brcmf_pub *drvr);
+
+/* Indication from bus module to change flow-control state */
+extern void brcmf_txflowcontrol(struct brcmf_pub *drvr, int ifidx, bool on);
+
+extern bool brcmf_c_prec_enq(struct brcmf_pub *drvr, struct pktq *q,
+ struct sk_buff *pkt, int prec);
+
+/* Receive frame for delivery to OS. Callee disposes of rxp. */
+extern void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx,
+ struct sk_buff *rxp, int numpkt);
+
+/* Return pointer to interface name */
+extern char *brcmf_ifname(struct brcmf_pub *drvr, int idx);
+
+/* Notify tx completion */
+extern void brcmf_txcomplete(struct brcmf_pub *drvr, struct sk_buff *txp,
+ bool success);
+
+/* Query dongle */
+extern int brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx,
+ uint cmd, void *buf, uint len);
+
+/* OS independent layer functions */
+extern int brcmf_os_proto_block(struct brcmf_pub *drvr);
+extern int brcmf_os_proto_unblock(struct brcmf_pub *drvr);
+#ifdef BCMDBG
+extern int brcmf_write_to_file(struct brcmf_pub *drvr, const u8 *buf, int size);
+#endif /* BCMDBG */
+
+extern int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name);
+extern int brcmf_c_host_event(struct brcmf_info *drvr_priv, int *idx,
+ void *pktdata, struct brcmf_event_msg *,
+ void **data_ptr);
+
+extern void brcmf_c_init(void);
+
+extern int brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx,
+ struct net_device *ndev, char *name, u8 *mac_addr,
+ u32 flags, u8 bssidx);
+extern void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx);
+
+/* Send packet to dongle via data channel */
+extern int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx,\
+ struct sk_buff *pkt);
+
+extern int brcmf_bus_start(struct brcmf_pub *drvr);
+
+extern void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg);
+extern void brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg,
+ int enable, int master_mode);
+
+#define BRCMF_DCMD_SMLEN 256 /* "small" cmd buffer required */
+#define BRCMF_DCMD_MEDLEN 1536 /* "med" cmd buffer required */
+#define BRCMF_DCMD_MAXLEN 8192 /* max length cmd buffer required */
+
+/* message levels */
+#define BRCMF_ERROR_VAL 0x0001
+#define BRCMF_TRACE_VAL 0x0002
+#define BRCMF_INFO_VAL 0x0004
+#define BRCMF_DATA_VAL 0x0008
+#define BRCMF_CTL_VAL 0x0010
+#define BRCMF_TIMER_VAL 0x0020
+#define BRCMF_HDRS_VAL 0x0040
+#define BRCMF_BYTES_VAL 0x0080
+#define BRCMF_INTR_VAL 0x0100
+#define BRCMF_GLOM_VAL 0x0400
+#define BRCMF_EVENT_VAL 0x0800
+#define BRCMF_BTA_VAL 0x1000
+#define BRCMF_ISCAN_VAL 0x2000
+
+/* Enter idle immediately (no timeout) */
+#define BRCMF_IDLE_IMMEDIATE (-1)
+#define BRCMF_IDLE_ACTIVE 0 /* Do not request any SD clock change
+ when idle */
+#define BRCMF_IDLE_INTERVAL 1
+
+#endif /* _BRCMF_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
new file mode 100644
index 000000000000..a249407c9a1b
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2010 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 _BRCMF_BUS_H_
+#define _BRCMF_BUS_H_
+
+/* Packet alignment for most efficient SDIO (can change based on platform) */
+#define BRCMF_SDALIGN (1 << 6)
+
+/* watchdog polling interval in ms */
+#define BRCMF_WD_POLL_MS 10
+
+/*
+ * Exported from brcmf bus module (brcmf_usb, brcmf_sdio)
+ */
+
+/* Indicate (dis)interest in finding dongles. */
+extern int brcmf_bus_register(void);
+extern void brcmf_bus_unregister(void);
+
+/* obtain linux device object providing bus function */
+extern struct device *brcmf_bus_get_device(struct brcmf_bus *bus);
+
+/* Stop bus module: clear pending frames, disable data flow */
+extern void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus);
+
+/* Initialize bus module: prepare for communication w/dongle */
+extern int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr);
+
+/* Send a data frame to the dongle. Callee disposes of txp. */
+extern int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *txp);
+
+/* Send/receive a control message to/from the dongle.
+ * Expects caller to enforce a single outstanding transaction.
+ */
+extern int
+brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen);
+
+extern int
+brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen);
+
+extern void brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick);
+
+#endif /* _BRCMF_BUS_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
new file mode 100644
index 000000000000..e34c5c3d1d55
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) 2010 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.
+ */
+
+/*******************************************************************************
+ * Communicates with the dongle by using dcmd codes.
+ * For certain dcmd codes, the dongle interprets string data from the host.
+ ******************************************************************************/
+
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/sched.h>
+#include <defs.h>
+
+#include <brcmu_utils.h>
+#include <brcmu_wifi.h>
+
+#include "dhd.h"
+#include "dhd_proto.h"
+#include "dhd_bus.h"
+#include "dhd_dbg.h"
+
+struct brcmf_proto_cdc_dcmd {
+ __le32 cmd; /* dongle command value */
+ __le32 len; /* lower 16: output buflen;
+ * upper 16: input buflen (excludes header) */
+ __le32 flags; /* flag defns given below */
+ __le32 status; /* status code returned from the device */
+};
+
+/* Max valid buffer size that can be sent to the dongle */
+#define CDC_MAX_MSG_SIZE (ETH_FRAME_LEN+ETH_FCS_LEN)
+
+/* CDC flag definitions */
+#define CDC_DCMD_ERROR 0x01 /* 1=cmd failed */
+#define CDC_DCMD_SET 0x02 /* 0=get, 1=set cmd */
+#define CDC_DCMD_IF_MASK 0xF000 /* I/F index */
+#define CDC_DCMD_IF_SHIFT 12
+#define CDC_DCMD_ID_MASK 0xFFFF0000 /* id an cmd pairing */
+#define CDC_DCMD_ID_SHIFT 16 /* ID Mask shift bits */
+#define CDC_DCMD_ID(flags) \
+ (((flags) & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT)
+
+/*
+ * BDC header - Broadcom specific extension of CDC.
+ * Used on data packets to convey priority across USB.
+ */
+#define BDC_HEADER_LEN 4
+#define BDC_PROTO_VER 1 /* Protocol version */
+#define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */
+#define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */
+#define BDC_FLAG_SUM_GOOD 0x04 /* Good RX checksums */
+#define BDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums */
+#define BDC_PRIORITY_MASK 0x7
+#define BDC_FLAG2_IF_MASK 0x0f /* packet rx interface in APSTA */
+#define BDC_FLAG2_IF_SHIFT 0
+
+#define BDC_GET_IF_IDX(hdr) \
+ ((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT))
+#define BDC_SET_IF_IDX(hdr, idx) \
+ ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | \
+ ((idx) << BDC_FLAG2_IF_SHIFT)))
+
+struct brcmf_proto_bdc_header {
+ u8 flags;
+ u8 priority; /* 802.1d Priority, 4:7 flow control info for usb */
+ u8 flags2;
+ u8 rssi;
+};
+
+
+#define RETRIES 2 /* # of retries to retrieve matching dcmd response */
+#define BUS_HEADER_LEN (16+BRCMF_SDALIGN) /* Must be atleast SDPCM_RESERVE
+ * (amount of header tha might be added)
+ * plus any space that might be needed
+ * for alignment padding.
+ */
+#define ROUND_UP_MARGIN 2048 /* Biggest SDIO block size possible for
+ * round off at the end of buffer
+ */
+
+struct brcmf_proto {
+ u16 reqid;
+ u8 pending;
+ u32 lastcmd;
+ u8 bus_header[BUS_HEADER_LEN];
+ struct brcmf_proto_cdc_dcmd msg;
+ unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN];
+};
+
+static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr)
+{
+ struct brcmf_proto *prot = drvr->prot;
+ int len = le32_to_cpu(prot->msg.len) +
+ sizeof(struct brcmf_proto_cdc_dcmd);
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* NOTE : cdc->msg.len holds the desired length of the buffer to be
+ * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area
+ * is actually sent to the dongle
+ */
+ if (len > CDC_MAX_MSG_SIZE)
+ len = CDC_MAX_MSG_SIZE;
+
+ /* Send request */
+ return brcmf_sdbrcm_bus_txctl(drvr->bus, (unsigned char *)&prot->msg,
+ len);
+}
+
+static int brcmf_proto_cdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len)
+{
+ int ret;
+ struct brcmf_proto *prot = drvr->prot;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ do {
+ ret = brcmf_sdbrcm_bus_rxctl(drvr->bus,
+ (unsigned char *)&prot->msg,
+ len + sizeof(struct brcmf_proto_cdc_dcmd));
+ if (ret < 0)
+ break;
+ } while (CDC_DCMD_ID(le32_to_cpu(prot->msg.flags)) != id);
+
+ return ret;
+}
+
+int
+brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
+ void *buf, uint len)
+{
+ struct brcmf_proto *prot = drvr->prot;
+ struct brcmf_proto_cdc_dcmd *msg = &prot->msg;
+ void *info;
+ int ret = 0, retries = 0;
+ u32 id, flags;
+
+ brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(CTL, "cmd %d len %d\n", cmd, len);
+
+ /* Respond "bcmerror" and "bcmerrorstr" with local cache */
+ if (cmd == BRCMF_C_GET_VAR && buf) {
+ if (!strcmp((char *)buf, "bcmerrorstr")) {
+ strncpy((char *)buf, "bcm_error",
+ BCME_STRLEN);
+ goto done;
+ } else if (!strcmp((char *)buf, "bcmerror")) {
+ *(int *)buf = drvr->dongle_error;
+ goto done;
+ }
+ }
+
+ memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd));
+
+ msg->cmd = cpu_to_le32(cmd);
+ msg->len = cpu_to_le32(len);
+ flags = (++prot->reqid << CDC_DCMD_ID_SHIFT);
+ flags = (flags & ~CDC_DCMD_IF_MASK) |
+ (ifidx << CDC_DCMD_IF_SHIFT);
+ msg->flags = cpu_to_le32(flags);
+
+ if (buf)
+ memcpy(prot->buf, buf, len);
+
+ ret = brcmf_proto_cdc_msg(drvr);
+ if (ret < 0) {
+ brcmf_dbg(ERROR, "brcmf_proto_cdc_msg failed w/status %d\n",
+ ret);
+ goto done;
+ }
+
+retry:
+ /* wait for interrupt and get first fragment */
+ ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len);
+ if (ret < 0)
+ goto done;
+
+ flags = le32_to_cpu(msg->flags);
+ id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT;
+
+ if ((id < prot->reqid) && (++retries < RETRIES))
+ goto retry;
+ if (id != prot->reqid) {
+ brcmf_dbg(ERROR, "%s: unexpected request id %d (expected %d)\n",
+ brcmf_ifname(drvr, ifidx), id, prot->reqid);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Check info buffer */
+ info = (void *)&msg[1];
+
+ /* Copy info buffer */
+ if (buf) {
+ if (ret < (int)len)
+ len = ret;
+ memcpy(buf, info, len);
+ }
+
+ /* Check the ERROR flag */
+ if (flags & CDC_DCMD_ERROR) {
+ ret = le32_to_cpu(msg->status);
+ /* Cache error from dongle */
+ drvr->dongle_error = ret;
+ }
+
+done:
+ return ret;
+}
+
+int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
+ void *buf, uint len)
+{
+ struct brcmf_proto *prot = drvr->prot;
+ struct brcmf_proto_cdc_dcmd *msg = &prot->msg;
+ int ret = 0;
+ u32 flags, id;
+
+ brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(CTL, "cmd %d len %d\n", cmd, len);
+
+ memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd));
+
+ msg->cmd = cpu_to_le32(cmd);
+ msg->len = cpu_to_le32(len);
+ flags = (++prot->reqid << CDC_DCMD_ID_SHIFT) | CDC_DCMD_SET;
+ flags = (flags & ~CDC_DCMD_IF_MASK) |
+ (ifidx << CDC_DCMD_IF_SHIFT);
+ msg->flags = cpu_to_le32(flags);
+
+ if (buf)
+ memcpy(prot->buf, buf, len);
+
+ ret = brcmf_proto_cdc_msg(drvr);
+ if (ret < 0)
+ goto done;
+
+ ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len);
+ if (ret < 0)
+ goto done;
+
+ flags = le32_to_cpu(msg->flags);
+ id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT;
+
+ if (id != prot->reqid) {
+ brcmf_dbg(ERROR, "%s: unexpected request id %d (expected %d)\n",
+ brcmf_ifname(drvr, ifidx), id, prot->reqid);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Check the ERROR flag */
+ if (flags & CDC_DCMD_ERROR) {
+ ret = le32_to_cpu(msg->status);
+ /* Cache error from dongle */
+ drvr->dongle_error = ret;
+ }
+
+done:
+ return ret;
+}
+
+int
+brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx, struct brcmf_dcmd *dcmd,
+ int len)
+{
+ struct brcmf_proto *prot = drvr->prot;
+ int ret = -1;
+
+ if (drvr->busstate == BRCMF_BUS_DOWN) {
+ brcmf_dbg(ERROR, "bus is down. we have nothing to do.\n");
+ return ret;
+ }
+ brcmf_os_proto_block(drvr);
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (len > BRCMF_DCMD_MAXLEN)
+ goto done;
+
+ if (prot->pending == true) {
+ brcmf_dbg(TRACE, "CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n",
+ dcmd->cmd, (unsigned long)dcmd->cmd, prot->lastcmd,
+ (unsigned long)prot->lastcmd);
+ if (dcmd->cmd == BRCMF_C_SET_VAR ||
+ dcmd->cmd == BRCMF_C_GET_VAR)
+ brcmf_dbg(TRACE, "iovar cmd=%s\n", (char *)dcmd->buf);
+
+ goto done;
+ }
+
+ prot->pending = true;
+ prot->lastcmd = dcmd->cmd;
+ if (dcmd->set)
+ ret = brcmf_proto_cdc_set_dcmd(drvr, ifidx, dcmd->cmd,
+ dcmd->buf, len);
+ else {
+ ret = brcmf_proto_cdc_query_dcmd(drvr, ifidx, dcmd->cmd,
+ dcmd->buf, len);
+ if (ret > 0)
+ dcmd->used = ret -
+ sizeof(struct brcmf_proto_cdc_dcmd);
+ }
+
+ if (ret >= 0)
+ ret = 0;
+ else {
+ struct brcmf_proto_cdc_dcmd *msg = &prot->msg;
+ /* len == needed when set/query fails from dongle */
+ dcmd->needed = le32_to_cpu(msg->len);
+ }
+
+ /* Intercept the wme_dp dongle cmd here */
+ if (!ret && dcmd->cmd == BRCMF_C_SET_VAR &&
+ !strcmp(dcmd->buf, "wme_dp")) {
+ int slen;
+ __le32 val = 0;
+
+ slen = strlen("wme_dp") + 1;
+ if (len >= (int)(slen + sizeof(int)))
+ memcpy(&val, (char *)dcmd->buf + slen, sizeof(int));
+ drvr->wme_dp = (u8) le32_to_cpu(val);
+ }
+
+ prot->pending = false;
+
+done:
+ brcmf_os_proto_unblock(drvr);
+
+ return ret;
+}
+
+static bool pkt_sum_needed(struct sk_buff *skb)
+{
+ return skb->ip_summed == CHECKSUM_PARTIAL;
+}
+
+static void pkt_set_sum_good(struct sk_buff *skb, bool x)
+{
+ skb->ip_summed = (x ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE);
+}
+
+void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx,
+ struct sk_buff *pktbuf)
+{
+ struct brcmf_proto_bdc_header *h;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Push BDC header used to convey priority for buses that don't */
+
+ skb_push(pktbuf, BDC_HEADER_LEN);
+
+ h = (struct brcmf_proto_bdc_header *)(pktbuf->data);
+
+ h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT);
+ if (pkt_sum_needed(pktbuf))
+ h->flags |= BDC_FLAG_SUM_NEEDED;
+
+ h->priority = (pktbuf->priority & BDC_PRIORITY_MASK);
+ h->flags2 = 0;
+ h->rssi = 0;
+ BDC_SET_IF_IDX(h, ifidx);
+}
+
+int brcmf_proto_hdrpull(struct brcmf_pub *drvr, int *ifidx,
+ struct sk_buff *pktbuf)
+{
+ struct brcmf_proto_bdc_header *h;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Pop BDC header used to convey priority for buses that don't */
+
+ if (pktbuf->len < BDC_HEADER_LEN) {
+ brcmf_dbg(ERROR, "rx data too short (%d < %d)\n",
+ pktbuf->len, BDC_HEADER_LEN);
+ return -EBADE;
+ }
+
+ h = (struct brcmf_proto_bdc_header *)(pktbuf->data);
+
+ *ifidx = BDC_GET_IF_IDX(h);
+ if (*ifidx >= BRCMF_MAX_IFS) {
+ brcmf_dbg(ERROR, "rx data ifnum out of range (%d)\n", *ifidx);
+ return -EBADE;
+ }
+
+ if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) !=
+ BDC_PROTO_VER) {
+ brcmf_dbg(ERROR, "%s: non-BDC packet received, flags 0x%x\n",
+ brcmf_ifname(drvr, *ifidx), h->flags);
+ return -EBADE;
+ }
+
+ if (h->flags & BDC_FLAG_SUM_GOOD) {
+ brcmf_dbg(INFO, "%s: BDC packet received with good rx-csum, flags 0x%x\n",
+ brcmf_ifname(drvr, *ifidx), h->flags);
+ pkt_set_sum_good(pktbuf, true);
+ }
+
+ pktbuf->priority = h->priority & BDC_PRIORITY_MASK;
+
+ skb_pull(pktbuf, BDC_HEADER_LEN);
+
+ return 0;
+}
+
+int brcmf_proto_attach(struct brcmf_pub *drvr)
+{
+ struct brcmf_proto *cdc;
+
+ cdc = kzalloc(sizeof(struct brcmf_proto), GFP_ATOMIC);
+ if (!cdc)
+ goto fail;
+
+ /* ensure that the msg buf directly follows the cdc msg struct */
+ if ((unsigned long)(&cdc->msg + 1) != (unsigned long)cdc->buf) {
+ brcmf_dbg(ERROR, "struct brcmf_proto is not correctly defined\n");
+ goto fail;
+ }
+
+ drvr->prot = cdc;
+ drvr->hdrlen += BDC_HEADER_LEN;
+ drvr->maxctl = BRCMF_DCMD_MAXLEN +
+ sizeof(struct brcmf_proto_cdc_dcmd) + ROUND_UP_MARGIN;
+ return 0;
+
+fail:
+ kfree(cdc);
+ return -ENOMEM;
+}
+
+/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */
+void brcmf_proto_detach(struct brcmf_pub *drvr)
+{
+ kfree(drvr->prot);
+ drvr->prot = NULL;
+}
+
+void brcmf_proto_dstats(struct brcmf_pub *drvr)
+{
+ /* No stats from dongle added yet, copy bus stats */
+ drvr->dstats.tx_packets = drvr->tx_packets;
+ drvr->dstats.tx_errors = drvr->tx_errors;
+ drvr->dstats.rx_packets = drvr->rx_packets;
+ drvr->dstats.rx_errors = drvr->rx_errors;
+ drvr->dstats.rx_dropped = drvr->rx_dropped;
+ drvr->dstats.multicast = drvr->rx_multicast;
+ return;
+}
+
+int brcmf_proto_init(struct brcmf_pub *drvr)
+{
+ int ret = 0;
+ char buf[128];
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ brcmf_os_proto_block(drvr);
+
+ /* Get the device MAC address */
+ strcpy(buf, "cur_etheraddr");
+ ret = brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR,
+ buf, sizeof(buf));
+ if (ret < 0) {
+ brcmf_os_proto_unblock(drvr);
+ return ret;
+ }
+ memcpy(drvr->mac, buf, ETH_ALEN);
+
+ brcmf_os_proto_unblock(drvr);
+
+ ret = brcmf_c_preinit_dcmds(drvr);
+
+ /* Always assumes wl for now */
+ drvr->iswl = true;
+
+ return ret;
+}
+
+void brcmf_proto_stop(struct brcmf_pub *drvr)
+{
+ /* Nothing to do for CDC */
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
new file mode 100644
index 000000000000..891826197f96
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
@@ -0,0 +1,895 @@
+/*
+ * Copyright (c) 2010 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/kernel.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/netdevice.h>
+#include <asm/unaligned.h>
+#include <defs.h>
+#include <brcmu_wifi.h>
+#include <brcmu_utils.h>
+#include "dhd.h"
+#include "dhd_bus.h"
+#include "dhd_proto.h"
+#include "dhd_dbg.h"
+
+#define BRCM_OUI "\x00\x10\x18"
+#define DOT11_OUI_LEN 3
+#define BCMILCP_BCM_SUBTYPE_EVENT 1
+#define PKTFILTER_BUF_SIZE 2048
+#define BRCMF_ARPOL_MODE 0xb /* agent|snoop|peer_autoreply */
+
+int brcmf_msg_level;
+
+#define MSGTRACE_VERSION 1
+
+#define BRCMF_PKT_FILTER_FIXED_LEN offsetof(struct brcmf_pkt_filter_le, u)
+#define BRCMF_PKT_FILTER_PATTERN_FIXED_LEN \
+ offsetof(struct brcmf_pkt_filter_pattern_le, mask_and_pattern)
+
+#ifdef BCMDBG
+static const char brcmf_version[] =
+ "Dongle Host Driver, version " BRCMF_VERSION_STR "\nCompiled on "
+ __DATE__ " at " __TIME__;
+#else
+static const char brcmf_version[] =
+ "Dongle Host Driver, version " BRCMF_VERSION_STR;
+#endif
+
+/* Message trace header */
+struct msgtrace_hdr {
+ u8 version;
+ u8 spare;
+ __be16 len; /* Len of the trace */
+ __be32 seqnum; /* Sequence number of message. Useful
+ * if the messsage has been lost
+ * because of DMA error or a bus reset
+ * (ex: SDIO Func2)
+ */
+ __be32 discarded_bytes; /* Number of discarded bytes because of
+ trace overflow */
+ __be32 discarded_printf; /* Number of discarded printf
+ because of trace overflow */
+} __packed;
+
+
+uint
+brcmf_c_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
+{
+ uint len;
+
+ len = strlen(name) + 1;
+
+ if ((len + datalen) > buflen)
+ return 0;
+
+ strncpy(buf, name, buflen);
+
+ /* append data onto the end of the name string */
+ memcpy(&buf[len], data, datalen);
+ len += datalen;
+
+ return len;
+}
+
+void brcmf_c_init(void)
+{
+ /* Init global variables at run-time, not as part of the declaration.
+ * This is required to support init/de-init of the driver.
+ * Initialization
+ * of globals as part of the declaration results in non-deterministic
+ * behaviour since the value of the globals may be different on the
+ * first time that the driver is initialized vs subsequent
+ * initializations.
+ */
+ brcmf_msg_level = BRCMF_ERROR_VAL;
+}
+
+bool brcmf_c_prec_enq(struct brcmf_pub *drvr, struct pktq *q,
+ struct sk_buff *pkt, int prec)
+{
+ struct sk_buff *p;
+ int eprec = -1; /* precedence to evict from */
+ bool discard_oldest;
+
+ /* Fast case, precedence queue is not full and we are also not
+ * exceeding total queue length
+ */
+ if (!pktq_pfull(q, prec) && !pktq_full(q)) {
+ brcmu_pktq_penq(q, prec, pkt);
+ return true;
+ }
+
+ /* Determine precedence from which to evict packet, if any */
+ if (pktq_pfull(q, prec))
+ eprec = prec;
+ else if (pktq_full(q)) {
+ p = brcmu_pktq_peek_tail(q, &eprec);
+ if (eprec > prec)
+ return false;
+ }
+
+ /* Evict if needed */
+ if (eprec >= 0) {
+ /* Detect queueing to unconfigured precedence */
+ discard_oldest = ac_bitmap_tst(drvr->wme_dp, eprec);
+ if (eprec == prec && !discard_oldest)
+ return false; /* refuse newer (incoming) packet */
+ /* Evict packet according to discard policy */
+ p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) :
+ brcmu_pktq_pdeq_tail(q, eprec);
+ if (p == NULL)
+ brcmf_dbg(ERROR, "brcmu_pktq_penq() failed, oldest %d\n",
+ discard_oldest);
+
+ brcmu_pkt_buf_free_skb(p);
+ }
+
+ /* Enqueue */
+ p = brcmu_pktq_penq(q, prec, pkt);
+ if (p == NULL)
+ brcmf_dbg(ERROR, "brcmu_pktq_penq() failed\n");
+
+ return p != NULL;
+}
+
+#ifdef BCMDBG
+static void
+brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data)
+{
+ uint i, status, reason;
+ bool group = false, flush_txq = false, link = false;
+ char *auth_str, *event_name;
+ unsigned char *buf;
+ char err_msg[256], eabuf[ETHER_ADDR_STR_LEN];
+ static struct {
+ uint event;
+ char *event_name;
+ } event_names[] = {
+ {
+ BRCMF_E_SET_SSID, "SET_SSID"}, {
+ BRCMF_E_JOIN, "JOIN"}, {
+ BRCMF_E_START, "START"}, {
+ BRCMF_E_AUTH, "AUTH"}, {
+ BRCMF_E_AUTH_IND, "AUTH_IND"}, {
+ BRCMF_E_DEAUTH, "DEAUTH"}, {
+ BRCMF_E_DEAUTH_IND, "DEAUTH_IND"}, {
+ BRCMF_E_ASSOC, "ASSOC"}, {
+ BRCMF_E_ASSOC_IND, "ASSOC_IND"}, {
+ BRCMF_E_REASSOC, "REASSOC"}, {
+ BRCMF_E_REASSOC_IND, "REASSOC_IND"}, {
+ BRCMF_E_DISASSOC, "DISASSOC"}, {
+ BRCMF_E_DISASSOC_IND, "DISASSOC_IND"}, {
+ BRCMF_E_QUIET_START, "START_QUIET"}, {
+ BRCMF_E_QUIET_END, "END_QUIET"}, {
+ BRCMF_E_BEACON_RX, "BEACON_RX"}, {
+ BRCMF_E_LINK, "LINK"}, {
+ BRCMF_E_MIC_ERROR, "MIC_ERROR"}, {
+ BRCMF_E_NDIS_LINK, "NDIS_LINK"}, {
+ BRCMF_E_ROAM, "ROAM"}, {
+ BRCMF_E_TXFAIL, "TXFAIL"}, {
+ BRCMF_E_PMKID_CACHE, "PMKID_CACHE"}, {
+ BRCMF_E_RETROGRADE_TSF, "RETROGRADE_TSF"}, {
+ BRCMF_E_PRUNE, "PRUNE"}, {
+ BRCMF_E_AUTOAUTH, "AUTOAUTH"}, {
+ BRCMF_E_EAPOL_MSG, "EAPOL_MSG"}, {
+ BRCMF_E_SCAN_COMPLETE, "SCAN_COMPLETE"}, {
+ BRCMF_E_ADDTS_IND, "ADDTS_IND"}, {
+ BRCMF_E_DELTS_IND, "DELTS_IND"}, {
+ BRCMF_E_BCNSENT_IND, "BCNSENT_IND"}, {
+ BRCMF_E_BCNRX_MSG, "BCNRX_MSG"}, {
+ BRCMF_E_BCNLOST_MSG, "BCNLOST_MSG"}, {
+ BRCMF_E_ROAM_PREP, "ROAM_PREP"}, {
+ BRCMF_E_PFN_NET_FOUND, "PNO_NET_FOUND"}, {
+ BRCMF_E_PFN_NET_LOST, "PNO_NET_LOST"}, {
+ BRCMF_E_RESET_COMPLETE, "RESET_COMPLETE"}, {
+ BRCMF_E_JOIN_START, "JOIN_START"}, {
+ BRCMF_E_ROAM_START, "ROAM_START"}, {
+ BRCMF_E_ASSOC_START, "ASSOC_START"}, {
+ BRCMF_E_IBSS_ASSOC, "IBSS_ASSOC"}, {
+ BRCMF_E_RADIO, "RADIO"}, {
+ BRCMF_E_PSM_WATCHDOG, "PSM_WATCHDOG"}, {
+ BRCMF_E_PROBREQ_MSG, "PROBREQ_MSG"}, {
+ BRCMF_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND"}, {
+ BRCMF_E_PSK_SUP, "PSK_SUP"}, {
+ BRCMF_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED"}, {
+ BRCMF_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME"}, {
+ BRCMF_E_ICV_ERROR, "ICV_ERROR"}, {
+ BRCMF_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR"}, {
+ BRCMF_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR"}, {
+ BRCMF_E_TRACE, "TRACE"}, {
+ BRCMF_E_ACTION_FRAME, "ACTION FRAME"}, {
+ BRCMF_E_ACTION_FRAME_COMPLETE, "ACTION FRAME TX COMPLETE"}, {
+ BRCMF_E_IF, "IF"}, {
+ BRCMF_E_RSSI, "RSSI"}, {
+ BRCMF_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE"}
+ };
+ uint event_type, flags, auth_type, datalen;
+ static u32 seqnum_prev;
+ struct msgtrace_hdr hdr;
+ u32 nblost;
+ char *s, *p;
+
+ event_type = be32_to_cpu(event->event_type);
+ flags = be16_to_cpu(event->flags);
+ status = be32_to_cpu(event->status);
+ reason = be32_to_cpu(event->reason);
+ auth_type = be32_to_cpu(event->auth_type);
+ datalen = be32_to_cpu(event->datalen);
+ /* debug dump of event messages */
+ sprintf(eabuf, "%pM", event->addr);
+
+ event_name = "UNKNOWN";
+ for (i = 0; i < ARRAY_SIZE(event_names); i++) {
+ if (event_names[i].event == event_type)
+ event_name = event_names[i].event_name;
+ }
+
+ brcmf_dbg(EVENT, "EVENT: %s, event ID = %d\n", event_name, event_type);
+ brcmf_dbg(EVENT, "flags 0x%04x, status %d, reason %d, auth_type %d MAC %s\n",
+ flags, status, reason, auth_type, eabuf);
+
+ if (flags & BRCMF_EVENT_MSG_LINK)
+ link = true;
+ if (flags & BRCMF_EVENT_MSG_GROUP)
+ group = true;
+ if (flags & BRCMF_EVENT_MSG_FLUSHTXQ)
+ flush_txq = true;
+
+ switch (event_type) {
+ case BRCMF_E_START:
+ case BRCMF_E_DEAUTH:
+ case BRCMF_E_DISASSOC:
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf);
+ break;
+
+ case BRCMF_E_ASSOC_IND:
+ case BRCMF_E_REASSOC_IND:
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf);
+ break;
+
+ case BRCMF_E_ASSOC:
+ case BRCMF_E_REASSOC:
+ if (status == BRCMF_E_STATUS_SUCCESS)
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, SUCCESS\n",
+ event_name, eabuf);
+ else if (status == BRCMF_E_STATUS_TIMEOUT)
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, TIMEOUT\n",
+ event_name, eabuf);
+ else if (status == BRCMF_E_STATUS_FAIL)
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, FAILURE, reason %d\n",
+ event_name, eabuf, (int)reason);
+ else
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, unexpected status %d\n",
+ event_name, eabuf, (int)status);
+ break;
+
+ case BRCMF_E_DEAUTH_IND:
+ case BRCMF_E_DISASSOC_IND:
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, reason %d\n",
+ event_name, eabuf, (int)reason);
+ break;
+
+ case BRCMF_E_AUTH:
+ case BRCMF_E_AUTH_IND:
+ if (auth_type == WLAN_AUTH_OPEN)
+ auth_str = "Open System";
+ else if (auth_type == WLAN_AUTH_SHARED_KEY)
+ auth_str = "Shared Key";
+ else {
+ sprintf(err_msg, "AUTH unknown: %d", (int)auth_type);
+ auth_str = err_msg;
+ }
+ if (event_type == BRCMF_E_AUTH_IND)
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s\n",
+ event_name, eabuf, auth_str);
+ else if (status == BRCMF_E_STATUS_SUCCESS)
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, SUCCESS\n",
+ event_name, eabuf, auth_str);
+ else if (status == BRCMF_E_STATUS_TIMEOUT)
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, TIMEOUT\n",
+ event_name, eabuf, auth_str);
+ else if (status == BRCMF_E_STATUS_FAIL) {
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n",
+ event_name, eabuf, auth_str, (int)reason);
+ }
+
+ break;
+
+ case BRCMF_E_JOIN:
+ case BRCMF_E_ROAM:
+ case BRCMF_E_SET_SSID:
+ if (status == BRCMF_E_STATUS_SUCCESS)
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n",
+ event_name, eabuf);
+ else if (status == BRCMF_E_STATUS_FAIL)
+ brcmf_dbg(EVENT, "MACEVENT: %s, failed\n", event_name);
+ else if (status == BRCMF_E_STATUS_NO_NETWORKS)
+ brcmf_dbg(EVENT, "MACEVENT: %s, no networks found\n",
+ event_name);
+ else
+ brcmf_dbg(EVENT, "MACEVENT: %s, unexpected status %d\n",
+ event_name, (int)status);
+ break;
+
+ case BRCMF_E_BEACON_RX:
+ if (status == BRCMF_E_STATUS_SUCCESS)
+ brcmf_dbg(EVENT, "MACEVENT: %s, SUCCESS\n", event_name);
+ else if (status == BRCMF_E_STATUS_FAIL)
+ brcmf_dbg(EVENT, "MACEVENT: %s, FAIL\n", event_name);
+ else
+ brcmf_dbg(EVENT, "MACEVENT: %s, status %d\n",
+ event_name, status);
+ break;
+
+ case BRCMF_E_LINK:
+ brcmf_dbg(EVENT, "MACEVENT: %s %s\n",
+ event_name, link ? "UP" : "DOWN");
+ break;
+
+ case BRCMF_E_MIC_ERROR:
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, Group %d, Flush %d\n",
+ event_name, eabuf, group, flush_txq);
+ break;
+
+ case BRCMF_E_ICV_ERROR:
+ case BRCMF_E_UNICAST_DECODE_ERROR:
+ case BRCMF_E_MULTICAST_DECODE_ERROR:
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf);
+ break;
+
+ case BRCMF_E_TXFAIL:
+ brcmf_dbg(EVENT, "MACEVENT: %s, RA %s\n", event_name, eabuf);
+ break;
+
+ case BRCMF_E_SCAN_COMPLETE:
+ case BRCMF_E_PMKID_CACHE:
+ brcmf_dbg(EVENT, "MACEVENT: %s\n", event_name);
+ break;
+
+ case BRCMF_E_PFN_NET_FOUND:
+ case BRCMF_E_PFN_NET_LOST:
+ case BRCMF_E_PFN_SCAN_COMPLETE:
+ brcmf_dbg(EVENT, "PNOEVENT: %s\n", event_name);
+ break;
+
+ case BRCMF_E_PSK_SUP:
+ case BRCMF_E_PRUNE:
+ brcmf_dbg(EVENT, "MACEVENT: %s, status %d, reason %d\n",
+ event_name, (int)status, (int)reason);
+ break;
+
+ case BRCMF_E_TRACE:
+ buf = (unsigned char *) event_data;
+ memcpy(&hdr, buf, sizeof(struct msgtrace_hdr));
+
+ if (hdr.version != MSGTRACE_VERSION) {
+ brcmf_dbg(ERROR,
+ "MACEVENT: %s [unsupported version --> brcmf"
+ " version:%d dongle version:%d]\n",
+ event_name, MSGTRACE_VERSION, hdr.version);
+ /* Reset datalen to avoid display below */
+ datalen = 0;
+ break;
+ }
+
+ /* There are 2 bytes available at the end of data */
+ *(buf + sizeof(struct msgtrace_hdr)
+ + be16_to_cpu(hdr.len)) = '\0';
+
+ if (be32_to_cpu(hdr.discarded_bytes)
+ || be32_to_cpu(hdr.discarded_printf))
+ brcmf_dbg(ERROR,
+ "WLC_E_TRACE: [Discarded traces in dongle -->"
+ " discarded_bytes %d discarded_printf %d]\n",
+ be32_to_cpu(hdr.discarded_bytes),
+ be32_to_cpu(hdr.discarded_printf));
+
+ nblost = be32_to_cpu(hdr.seqnum) - seqnum_prev - 1;
+ if (nblost > 0)
+ brcmf_dbg(ERROR, "WLC_E_TRACE: [Event lost --> seqnum "
+ " %d nblost %d\n", be32_to_cpu(hdr.seqnum),
+ nblost);
+ seqnum_prev = be32_to_cpu(hdr.seqnum);
+
+ /* Display the trace buffer. Advance from \n to \n to
+ * avoid display big
+ * printf (issue with Linux printk )
+ */
+ p = (char *)&buf[sizeof(struct msgtrace_hdr)];
+ while ((s = strstr(p, "\n")) != NULL) {
+ *s = '\0';
+ printk(KERN_DEBUG"%s\n", p);
+ p = s + 1;
+ }
+ printk(KERN_DEBUG "%s\n", p);
+
+ /* Reset datalen to avoid display below */
+ datalen = 0;
+ break;
+
+ case BRCMF_E_RSSI:
+ brcmf_dbg(EVENT, "MACEVENT: %s %d\n",
+ event_name, be32_to_cpu(*((__be32 *)event_data)));
+ break;
+
+ default:
+ brcmf_dbg(EVENT,
+ "MACEVENT: %s %d, MAC %s, status %d, reason %d, "
+ "auth %d\n", event_name, event_type, eabuf,
+ (int)status, (int)reason, (int)auth_type);
+ break;
+ }
+
+ /* show any appended data */
+ if (datalen) {
+ buf = (unsigned char *) event_data;
+ brcmf_dbg(EVENT, " data (%d) : ", datalen);
+ for (i = 0; i < datalen; i++)
+ brcmf_dbg(EVENT, " 0x%02x ", *buf++);
+ brcmf_dbg(EVENT, "\n");
+ }
+}
+#endif /* BCMDBG */
+
+int
+brcmf_c_host_event(struct brcmf_info *drvr_priv, int *ifidx, void *pktdata,
+ struct brcmf_event_msg *event, void **data_ptr)
+{
+ /* check whether packet is a BRCM event pkt */
+ struct brcmf_event *pvt_data = (struct brcmf_event *) pktdata;
+ struct brcmf_if_event *ifevent;
+ char *event_data;
+ u32 type, status;
+ u16 flags;
+ int evlen;
+
+ if (memcmp(BRCM_OUI, &pvt_data->hdr.oui[0], DOT11_OUI_LEN)) {
+ brcmf_dbg(ERROR, "mismatched OUI, bailing\n");
+ return -EBADE;
+ }
+
+ /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */
+ if (get_unaligned_be16(&pvt_data->hdr.usr_subtype) !=
+ BCMILCP_BCM_SUBTYPE_EVENT) {
+ brcmf_dbg(ERROR, "mismatched subtype, bailing\n");
+ return -EBADE;
+ }
+
+ *data_ptr = &pvt_data[1];
+ event_data = *data_ptr;
+
+ /* memcpy since BRCM event pkt may be unaligned. */
+ memcpy(event, &pvt_data->msg, sizeof(struct brcmf_event_msg));
+
+ type = get_unaligned_be32(&event->event_type);
+ flags = get_unaligned_be16(&event->flags);
+ status = get_unaligned_be32(&event->status);
+ evlen = get_unaligned_be32(&event->datalen) +
+ sizeof(struct brcmf_event);
+
+ switch (type) {
+ case BRCMF_E_IF:
+ ifevent = (struct brcmf_if_event *) event_data;
+ brcmf_dbg(TRACE, "if event\n");
+
+ if (ifevent->ifidx > 0 && ifevent->ifidx < BRCMF_MAX_IFS) {
+ if (ifevent->action == BRCMF_E_IF_ADD)
+ brcmf_add_if(drvr_priv, ifevent->ifidx, NULL,
+ event->ifname,
+ pvt_data->eth.h_dest,
+ ifevent->flags, ifevent->bssidx);
+ else
+ brcmf_del_if(drvr_priv, ifevent->ifidx);
+ } else {
+ brcmf_dbg(ERROR, "Invalid ifidx %d for %s\n",
+ ifevent->ifidx, event->ifname);
+ }
+
+ /* send up the if event: btamp user needs it */
+ *ifidx = brcmf_ifname2idx(drvr_priv, event->ifname);
+ break;
+
+ /* These are what external supplicant/authenticator wants */
+ case BRCMF_E_LINK:
+ case BRCMF_E_ASSOC_IND:
+ case BRCMF_E_REASSOC_IND:
+ case BRCMF_E_DISASSOC_IND:
+ case BRCMF_E_MIC_ERROR:
+ default:
+ /* Fall through: this should get _everything_ */
+
+ *ifidx = brcmf_ifname2idx(drvr_priv, event->ifname);
+ brcmf_dbg(TRACE, "MAC event %d, flags %x, status %x\n",
+ type, flags, status);
+
+ /* put it back to BRCMF_E_NDIS_LINK */
+ if (type == BRCMF_E_NDIS_LINK) {
+ u32 temp1;
+ __be32 temp2;
+
+ temp1 = get_unaligned_be32(&event->event_type);
+ brcmf_dbg(TRACE, "Converted to WLC_E_LINK type %d\n",
+ temp1);
+
+ temp2 = cpu_to_be32(BRCMF_E_NDIS_LINK);
+ memcpy((void *)(&pvt_data->msg.event_type), &temp2,
+ sizeof(pvt_data->msg.event_type));
+ }
+ break;
+ }
+
+#ifdef BCMDBG
+ brcmf_c_show_host_event(event, event_data);
+#endif /* BCMDBG */
+
+ return 0;
+}
+
+/* Convert user's input in hex pattern to byte-size mask */
+static int brcmf_c_pattern_atoh(char *src, char *dst)
+{
+ int i;
+ if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) {
+ brcmf_dbg(ERROR, "Mask invalid format. Needs to start with 0x\n");
+ return -EINVAL;
+ }
+ src = src + 2; /* Skip past 0x */
+ if (strlen(src) % 2 != 0) {
+ brcmf_dbg(ERROR, "Mask invalid format. Length must be even.\n");
+ return -EINVAL;
+ }
+ for (i = 0; *src != '\0'; i++) {
+ unsigned long res;
+ char num[3];
+ strncpy(num, src, 2);
+ num[2] = '\0';
+ if (kstrtoul(num, 16, &res))
+ return -EINVAL;
+ dst[i] = (u8)res;
+ src += 2;
+ }
+ return i;
+}
+
+void
+brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg, int enable,
+ int master_mode)
+{
+ unsigned long res;
+ char *argv[8];
+ int i = 0;
+ const char *str;
+ int buf_len;
+ int str_len;
+ char *arg_save = NULL, *arg_org = NULL;
+ int rc;
+ char buf[128];
+ struct brcmf_pkt_filter_enable_le enable_parm;
+ struct brcmf_pkt_filter_enable_le *pkt_filterp;
+ __le32 mmode_le;
+
+ arg_save = kmalloc(strlen(arg) + 1, GFP_ATOMIC);
+ if (!arg_save)
+ goto fail;
+
+ arg_org = arg_save;
+ memcpy(arg_save, arg, strlen(arg) + 1);
+
+ argv[i] = strsep(&arg_save, " ");
+
+ i = 0;
+ if (NULL == argv[i]) {
+ brcmf_dbg(ERROR, "No args provided\n");
+ goto fail;
+ }
+
+ str = "pkt_filter_enable";
+ str_len = strlen(str);
+ strncpy(buf, str, str_len);
+ buf[str_len] = '\0';
+ buf_len = str_len + 1;
+
+ pkt_filterp = (struct brcmf_pkt_filter_enable_le *) (buf + str_len + 1);
+
+ /* Parse packet filter id. */
+ enable_parm.id = 0;
+ if (!kstrtoul(argv[i], 0, &res))
+ enable_parm.id = cpu_to_le32((u32)res);
+
+ /* Parse enable/disable value. */
+ enable_parm.enable = cpu_to_le32(enable);
+
+ buf_len += sizeof(enable_parm);
+ memcpy((char *)pkt_filterp, &enable_parm, sizeof(enable_parm));
+
+ /* Enable/disable the specified filter. */
+ rc = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, buf, buf_len);
+ rc = rc >= 0 ? 0 : rc;
+ if (rc)
+ brcmf_dbg(TRACE, "failed to add pktfilter %s, retcode = %d\n",
+ arg, rc);
+ else
+ brcmf_dbg(TRACE, "successfully added pktfilter %s\n", arg);
+
+ /* Contorl the master mode */
+ mmode_le = cpu_to_le32(master_mode);
+ brcmf_c_mkiovar("pkt_filter_mode", (char *)&mmode_le, 4, buf,
+ sizeof(buf));
+ rc = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, buf,
+ sizeof(buf));
+ rc = rc >= 0 ? 0 : rc;
+ if (rc)
+ brcmf_dbg(TRACE, "failed to add pktfilter %s, retcode = %d\n",
+ arg, rc);
+
+fail:
+ kfree(arg_org);
+}
+
+void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg)
+{
+ const char *str;
+ struct brcmf_pkt_filter_le pkt_filter;
+ struct brcmf_pkt_filter_le *pkt_filterp;
+ unsigned long res;
+ int buf_len;
+ int str_len;
+ int rc;
+ u32 mask_size;
+ u32 pattern_size;
+ char *argv[8], *buf = NULL;
+ int i = 0;
+ char *arg_save = NULL, *arg_org = NULL;
+
+ arg_save = kstrdup(arg, GFP_ATOMIC);
+ if (!arg_save)
+ goto fail;
+
+ arg_org = arg_save;
+
+ buf = kmalloc(PKTFILTER_BUF_SIZE, GFP_ATOMIC);
+ if (!buf)
+ goto fail;
+
+ argv[i] = strsep(&arg_save, " ");
+ while (argv[i++])
+ argv[i] = strsep(&arg_save, " ");
+
+ i = 0;
+ if (NULL == argv[i]) {
+ brcmf_dbg(ERROR, "No args provided\n");
+ goto fail;
+ }
+
+ str = "pkt_filter_add";
+ strcpy(buf, str);
+ str_len = strlen(str);
+ buf_len = str_len + 1;
+
+ pkt_filterp = (struct brcmf_pkt_filter_le *) (buf + str_len + 1);
+
+ /* Parse packet filter id. */
+ pkt_filter.id = 0;
+ if (!kstrtoul(argv[i], 0, &res))
+ pkt_filter.id = cpu_to_le32((u32)res);
+
+ if (NULL == argv[++i]) {
+ brcmf_dbg(ERROR, "Polarity not provided\n");
+ goto fail;
+ }
+
+ /* Parse filter polarity. */
+ pkt_filter.negate_match = 0;
+ if (!kstrtoul(argv[i], 0, &res))
+ pkt_filter.negate_match = cpu_to_le32((u32)res);
+
+ if (NULL == argv[++i]) {
+ brcmf_dbg(ERROR, "Filter type not provided\n");
+ goto fail;
+ }
+
+ /* Parse filter type. */
+ pkt_filter.type = 0;
+ if (!kstrtoul(argv[i], 0, &res))
+ pkt_filter.type = cpu_to_le32((u32)res);
+
+ if (NULL == argv[++i]) {
+ brcmf_dbg(ERROR, "Offset not provided\n");
+ goto fail;
+ }
+
+ /* Parse pattern filter offset. */
+ pkt_filter.u.pattern.offset = 0;
+ if (!kstrtoul(argv[i], 0, &res))
+ pkt_filter.u.pattern.offset = cpu_to_le32((u32)res);
+
+ if (NULL == argv[++i]) {
+ brcmf_dbg(ERROR, "Bitmask not provided\n");
+ goto fail;
+ }
+
+ /* Parse pattern filter mask. */
+ mask_size =
+ brcmf_c_pattern_atoh
+ (argv[i], (char *)pkt_filterp->u.pattern.mask_and_pattern);
+
+ if (NULL == argv[++i]) {
+ brcmf_dbg(ERROR, "Pattern not provided\n");
+ goto fail;
+ }
+
+ /* Parse pattern filter pattern. */
+ pattern_size =
+ brcmf_c_pattern_atoh(argv[i],
+ (char *)&pkt_filterp->u.pattern.
+ mask_and_pattern[mask_size]);
+
+ if (mask_size != pattern_size) {
+ brcmf_dbg(ERROR, "Mask and pattern not the same size\n");
+ goto fail;
+ }
+
+ pkt_filter.u.pattern.size_bytes = cpu_to_le32(mask_size);
+ buf_len += BRCMF_PKT_FILTER_FIXED_LEN;
+ buf_len += (BRCMF_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
+
+ /* Keep-alive attributes are set in local
+ * variable (keep_alive_pkt), and
+ ** then memcpy'ed into buffer (keep_alive_pktp) since there is no
+ ** guarantee that the buffer is properly aligned.
+ */
+ memcpy((char *)pkt_filterp,
+ &pkt_filter,
+ BRCMF_PKT_FILTER_FIXED_LEN + BRCMF_PKT_FILTER_PATTERN_FIXED_LEN);
+
+ rc = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, buf, buf_len);
+ rc = rc >= 0 ? 0 : rc;
+
+ if (rc)
+ brcmf_dbg(TRACE, "failed to add pktfilter %s, retcode = %d\n",
+ arg, rc);
+ else
+ brcmf_dbg(TRACE, "successfully added pktfilter %s\n", arg);
+
+fail:
+ kfree(arg_org);
+
+ kfree(buf);
+}
+
+static void brcmf_c_arp_offload_set(struct brcmf_pub *drvr, int arp_mode)
+{
+ char iovbuf[32];
+ int retcode;
+
+ brcmf_c_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf));
+ retcode = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR,
+ iovbuf, sizeof(iovbuf));
+ retcode = retcode >= 0 ? 0 : retcode;
+ if (retcode)
+ brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, retcode = %d\n",
+ arp_mode, retcode);
+ else
+ brcmf_dbg(TRACE, "successfully set ARP offload mode to 0x%x\n",
+ arp_mode);
+}
+
+static void brcmf_c_arp_offload_enable(struct brcmf_pub *drvr, int arp_enable)
+{
+ char iovbuf[32];
+ int retcode;
+
+ brcmf_c_mkiovar("arpoe", (char *)&arp_enable, 4,
+ iovbuf, sizeof(iovbuf));
+ retcode = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR,
+ iovbuf, sizeof(iovbuf));
+ retcode = retcode >= 0 ? 0 : retcode;
+ if (retcode)
+ brcmf_dbg(TRACE, "failed to enable ARP offload to %d, retcode = %d\n",
+ arp_enable, retcode);
+ else
+ brcmf_dbg(TRACE, "successfully enabled ARP offload to %d\n",
+ arp_enable);
+}
+
+int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr)
+{
+ char iovbuf[BRCMF_EVENTING_MASK_LEN + 12]; /* Room for
+ "event_msgs" + '\0' + bitvec */
+ uint up = 0;
+ char buf[128], *ptr;
+ u32 dongle_align = BRCMF_SDALIGN;
+ u32 glom = 0;
+ u32 roaming = 1;
+ uint bcn_timeout = 3;
+ int scan_assoc_time = 40;
+ int scan_unassoc_time = 40;
+ int i;
+
+ brcmf_os_proto_block(drvr);
+
+ /* Set Country code */
+ if (drvr->country_code[0] != 0) {
+ if (brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_COUNTRY,
+ drvr->country_code,
+ sizeof(drvr->country_code)) < 0)
+ brcmf_dbg(ERROR, "country code setting failed\n");
+ }
+
+ /* query for 'ver' to get version info from firmware */
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ brcmf_c_mkiovar("ver", NULL, 0, buf, sizeof(buf));
+ brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, buf, sizeof(buf));
+ strsep(&ptr, "\n");
+ /* Print fw version info */
+ brcmf_dbg(ERROR, "Firmware version = %s\n", buf);
+
+ /* Match Host and Dongle rx alignment */
+ brcmf_c_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf,
+ sizeof(iovbuf));
+ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
+ sizeof(iovbuf));
+
+ /* disable glom option per default */
+ brcmf_c_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
+ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
+ sizeof(iovbuf));
+
+ /* Setup timeout if Beacons are lost and roam is off to report
+ link down */
+ brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf,
+ sizeof(iovbuf));
+ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
+ sizeof(iovbuf));
+
+ /* Enable/Disable build-in roaming to allowed ext supplicant to take
+ of romaing */
+ brcmf_c_mkiovar("roam_off", (char *)&roaming, 4,
+ iovbuf, sizeof(iovbuf));
+ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
+ sizeof(iovbuf));
+
+ /* Force STA UP */
+ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_UP, (char *)&up, sizeof(up));
+
+ /* Setup event_msgs */
+ brcmf_c_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN,
+ iovbuf, sizeof(iovbuf));
+ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
+ sizeof(iovbuf));
+
+ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_SCAN_CHANNEL_TIME,
+ (char *)&scan_assoc_time, sizeof(scan_assoc_time));
+ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_SCAN_UNASSOC_TIME,
+ (char *)&scan_unassoc_time, sizeof(scan_unassoc_time));
+
+ /* Set and enable ARP offload feature */
+ brcmf_c_arp_offload_set(drvr, BRCMF_ARPOL_MODE);
+ brcmf_c_arp_offload_enable(drvr, true);
+
+ /* Set up pkt filter */
+ for (i = 0; i < drvr->pktfilter_count; i++) {
+ brcmf_c_pktfilter_offload_set(drvr, drvr->pktfilter[i]);
+ brcmf_c_pktfilter_offload_enable(drvr, drvr->pktfilter[i],
+ 0, true);
+ }
+
+ brcmf_os_proto_unblock(drvr);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
new file mode 100644
index 000000000000..7467922f0536
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2010 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 _BRCMF_DBG_H_
+#define _BRCMF_DBG_H_
+
+#if defined(BCMDBG)
+
+#define brcmf_dbg(level, fmt, ...) \
+do { \
+ if (BRCMF_ERROR_VAL == BRCMF_##level##_VAL) { \
+ if (brcmf_msg_level & BRCMF_##level##_VAL) { \
+ if (net_ratelimit()) \
+ printk(KERN_DEBUG "%s: " fmt, \
+ __func__, ##__VA_ARGS__); \
+ } \
+ } else { \
+ if (brcmf_msg_level & BRCMF_##level##_VAL) { \
+ printk(KERN_DEBUG "%s: " fmt, \
+ __func__, ##__VA_ARGS__); \
+ } \
+ } \
+} while (0)
+
+#define BRCMF_DATA_ON() (brcmf_msg_level & BRCMF_DATA_VAL)
+#define BRCMF_CTL_ON() (brcmf_msg_level & BRCMF_CTL_VAL)
+#define BRCMF_HDRS_ON() (brcmf_msg_level & BRCMF_HDRS_VAL)
+#define BRCMF_BYTES_ON() (brcmf_msg_level & BRCMF_BYTES_VAL)
+#define BRCMF_GLOM_ON() (brcmf_msg_level & BRCMF_GLOM_VAL)
+
+#else /* (defined BCMDBG) || (defined BCMDBG) */
+
+#define brcmf_dbg(level, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
+
+#define BRCMF_DATA_ON() 0
+#define BRCMF_CTL_ON() 0
+#define BRCMF_HDRS_ON() 0
+#define BRCMF_BYTES_ON() 0
+#define BRCMF_GLOM_ON() 0
+
+#endif /* defined(BCMDBG) */
+
+extern int brcmf_msg_level;
+
+#endif /* _BRCMF_DBG_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
new file mode 100644
index 000000000000..4acbac5a74c6
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
@@ -0,0 +1,1356 @@
+/*
+ * Copyright (c) 2010 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/kthread.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/random.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/fcntl.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/hardirq.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+#include <net/cfg80211.h>
+#include <net/rtnetlink.h>
+#include <defs.h>
+#include <brcmu_utils.h>
+#include <brcmu_wifi.h>
+
+#include "dhd.h"
+#include "dhd_bus.h"
+#include "dhd_proto.h"
+#include "dhd_dbg.h"
+#include "wl_cfg80211.h"
+#include "bcmchip.h"
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac driver.");
+MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN fullmac cards");
+MODULE_LICENSE("Dual BSD/GPL");
+
+
+/* Interface control information */
+struct brcmf_if {
+ struct brcmf_info *info; /* back pointer to brcmf_info */
+ /* OS/stack specifics */
+ struct net_device *ndev;
+ struct net_device_stats stats;
+ int idx; /* iface idx in dongle */
+ int state; /* interface state */
+ u8 mac_addr[ETH_ALEN]; /* assigned MAC address */
+};
+
+/* Local private structure (extension of pub) */
+struct brcmf_info {
+ struct brcmf_pub pub;
+
+ /* OS/stack specifics */
+ struct brcmf_if *iflist[BRCMF_MAX_IFS];
+
+ struct mutex proto_block;
+
+ struct work_struct setmacaddr_work;
+ struct work_struct multicast_work;
+ u8 macvalue[ETH_ALEN];
+ atomic_t pend_8021x_cnt;
+};
+
+/* Error bits */
+module_param(brcmf_msg_level, int, 0);
+
+
+static int brcmf_net2idx(struct brcmf_info *drvr_priv, struct net_device *ndev)
+{
+ int i = 0;
+
+ while (i < BRCMF_MAX_IFS) {
+ if (drvr_priv->iflist[i] && drvr_priv->iflist[i]->ndev == ndev)
+ return i;
+ i++;
+ }
+
+ return BRCMF_BAD_IF;
+}
+
+int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name)
+{
+ int i = BRCMF_MAX_IFS;
+ struct brcmf_if *ifp;
+
+ if (name == NULL || *name == '\0')
+ return 0;
+
+ while (--i > 0) {
+ ifp = drvr_priv->iflist[i];
+ if (ifp && !strncmp(ifp->ndev->name, name, IFNAMSIZ))
+ break;
+ }
+
+ brcmf_dbg(TRACE, "return idx %d for \"%s\"\n", i, name);
+
+ return i; /* default - the primary interface */
+}
+
+char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)
+{
+ struct brcmf_info *drvr_priv = drvr->info;
+
+ if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) {
+ brcmf_dbg(ERROR, "ifidx %d out of range\n", ifidx);
+ return "<if_bad>";
+ }
+
+ if (drvr_priv->iflist[ifidx] == NULL) {
+ brcmf_dbg(ERROR, "null i/f %d\n", ifidx);
+ return "<if_null>";
+ }
+
+ if (drvr_priv->iflist[ifidx]->ndev)
+ return drvr_priv->iflist[ifidx]->ndev->name;
+
+ return "<if_none>";
+}
+
+static void _brcmf_set_multicast_list(struct work_struct *work)
+{
+ struct net_device *ndev;
+ struct netdev_hw_addr *ha;
+ u32 dcmd_value, cnt;
+ __le32 cnt_le;
+ __le32 dcmd_le_value;
+
+ struct brcmf_dcmd dcmd;
+ char *buf, *bufp;
+ uint buflen;
+ int ret;
+
+ struct brcmf_info *drvr_priv = container_of(work, struct brcmf_info,
+ multicast_work);
+
+ ndev = drvr_priv->iflist[0]->ndev;
+ cnt = netdev_mc_count(ndev);
+
+ /* Determine initial value of allmulti flag */
+ dcmd_value = (ndev->flags & IFF_ALLMULTI) ? true : false;
+
+ /* Send down the multicast list first. */
+
+ buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETH_ALEN);
+ bufp = buf = kmalloc(buflen, GFP_ATOMIC);
+ if (!bufp)
+ return;
+
+ strcpy(bufp, "mcast_list");
+ bufp += strlen("mcast_list") + 1;
+
+ cnt_le = cpu_to_le32(cnt);
+ memcpy(bufp, &cnt_le, sizeof(cnt));
+ bufp += sizeof(cnt_le);
+
+ netdev_for_each_mc_addr(ha, ndev) {
+ if (!cnt)
+ break;
+ memcpy(bufp, ha->addr, ETH_ALEN);
+ bufp += ETH_ALEN;
+ cnt--;
+ }
+
+ memset(&dcmd, 0, sizeof(dcmd));
+ dcmd.cmd = BRCMF_C_SET_VAR;
+ dcmd.buf = buf;
+ dcmd.len = buflen;
+ dcmd.set = true;
+
+ ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len);
+ if (ret < 0) {
+ brcmf_dbg(ERROR, "%s: set mcast_list failed, cnt %d\n",
+ brcmf_ifname(&drvr_priv->pub, 0), cnt);
+ dcmd_value = cnt ? true : dcmd_value;
+ }
+
+ kfree(buf);
+
+ /* Now send the allmulti setting. This is based on the setting in the
+ * net_device flags, but might be modified above to be turned on if we
+ * were trying to set some addresses and dongle rejected it...
+ */
+
+ buflen = sizeof("allmulti") + sizeof(dcmd_value);
+ buf = kmalloc(buflen, GFP_ATOMIC);
+ if (!buf)
+ return;
+
+ dcmd_le_value = cpu_to_le32(dcmd_value);
+
+ if (!brcmf_c_mkiovar
+ ("allmulti", (void *)&dcmd_le_value,
+ sizeof(dcmd_le_value), buf, buflen)) {
+ brcmf_dbg(ERROR, "%s: mkiovar failed for allmulti, datalen %d buflen %u\n",
+ brcmf_ifname(&drvr_priv->pub, 0),
+ (int)sizeof(dcmd_value), buflen);
+ kfree(buf);
+ return;
+ }
+
+ memset(&dcmd, 0, sizeof(dcmd));
+ dcmd.cmd = BRCMF_C_SET_VAR;
+ dcmd.buf = buf;
+ dcmd.len = buflen;
+ dcmd.set = true;
+
+ ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len);
+ if (ret < 0) {
+ brcmf_dbg(ERROR, "%s: set allmulti %d failed\n",
+ brcmf_ifname(&drvr_priv->pub, 0),
+ le32_to_cpu(dcmd_le_value));
+ }
+
+ kfree(buf);
+
+ /* Finally, pick up the PROMISC flag as well, like the NIC
+ driver does */
+
+ dcmd_value = (ndev->flags & IFF_PROMISC) ? true : false;
+ dcmd_le_value = cpu_to_le32(dcmd_value);
+
+ memset(&dcmd, 0, sizeof(dcmd));
+ dcmd.cmd = BRCMF_C_SET_PROMISC;
+ dcmd.buf = &dcmd_le_value;
+ dcmd.len = sizeof(dcmd_le_value);
+ dcmd.set = true;
+
+ ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len);
+ if (ret < 0) {
+ brcmf_dbg(ERROR, "%s: set promisc %d failed\n",
+ brcmf_ifname(&drvr_priv->pub, 0),
+ le32_to_cpu(dcmd_le_value));
+ }
+}
+
+static void
+_brcmf_set_mac_address(struct work_struct *work)
+{
+ char buf[32];
+ struct brcmf_dcmd dcmd;
+ int ret;
+
+ struct brcmf_info *drvr_priv = container_of(work, struct brcmf_info,
+ setmacaddr_work);
+
+ brcmf_dbg(TRACE, "enter\n");
+ if (!brcmf_c_mkiovar("cur_etheraddr", (char *)drvr_priv->macvalue,
+ ETH_ALEN, buf, 32)) {
+ brcmf_dbg(ERROR, "%s: mkiovar failed for cur_etheraddr\n",
+ brcmf_ifname(&drvr_priv->pub, 0));
+ return;
+ }
+ memset(&dcmd, 0, sizeof(dcmd));
+ dcmd.cmd = BRCMF_C_SET_VAR;
+ dcmd.buf = buf;
+ dcmd.len = 32;
+ dcmd.set = true;
+
+ ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len);
+ if (ret < 0)
+ brcmf_dbg(ERROR, "%s: set cur_etheraddr failed\n",
+ brcmf_ifname(&drvr_priv->pub, 0));
+ else
+ memcpy(drvr_priv->iflist[0]->ndev->dev_addr,
+ drvr_priv->macvalue, ETH_ALEN);
+
+ return;
+}
+
+static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
+{
+ struct brcmf_info *drvr_priv = *(struct brcmf_info **)
+ netdev_priv(ndev);
+ struct sockaddr *sa = (struct sockaddr *)addr;
+ int ifidx;
+
+ ifidx = brcmf_net2idx(drvr_priv, ndev);
+ if (ifidx == BRCMF_BAD_IF)
+ return -1;
+
+ memcpy(&drvr_priv->macvalue, sa->sa_data, ETH_ALEN);
+ schedule_work(&drvr_priv->setmacaddr_work);
+ return 0;
+}
+
+static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
+{
+ struct brcmf_info *drvr_priv = *(struct brcmf_info **)
+ netdev_priv(ndev);
+ int ifidx;
+
+ ifidx = brcmf_net2idx(drvr_priv, ndev);
+ if (ifidx == BRCMF_BAD_IF)
+ return;
+
+ schedule_work(&drvr_priv->multicast_work);
+}
+
+int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf)
+{
+ struct brcmf_info *drvr_priv = drvr->info;
+
+ /* Reject if down */
+ if (!drvr->up || (drvr->busstate == BRCMF_BUS_DOWN))
+ return -ENODEV;
+
+ /* Update multicast statistic */
+ if (pktbuf->len >= ETH_ALEN) {
+ u8 *pktdata = (u8 *) (pktbuf->data);
+ struct ethhdr *eh = (struct ethhdr *)pktdata;
+
+ if (is_multicast_ether_addr(eh->h_dest))
+ drvr->tx_multicast++;
+ if (ntohs(eh->h_proto) == ETH_P_PAE)
+ atomic_inc(&drvr_priv->pend_8021x_cnt);
+ }
+
+ /* If the protocol uses a data header, apply it */
+ brcmf_proto_hdrpush(drvr, ifidx, pktbuf);
+
+ /* Use bus module to send data frame */
+ return brcmf_sdbrcm_bus_txdata(drvr->bus, pktbuf);
+}
+
+static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ int ret;
+ struct brcmf_info *drvr_priv = *(struct brcmf_info **)
+ netdev_priv(ndev);
+ int ifidx;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Reject if down */
+ if (!drvr_priv->pub.up || (drvr_priv->pub.busstate == BRCMF_BUS_DOWN)) {
+ brcmf_dbg(ERROR, "xmit rejected pub.up=%d busstate=%d\n",
+ drvr_priv->pub.up, drvr_priv->pub.busstate);
+ netif_stop_queue(ndev);
+ return -ENODEV;
+ }
+
+ ifidx = brcmf_net2idx(drvr_priv, ndev);
+ if (ifidx == BRCMF_BAD_IF) {
+ brcmf_dbg(ERROR, "bad ifidx %d\n", ifidx);
+ netif_stop_queue(ndev);
+ return -ENODEV;
+ }
+
+ /* Make sure there's enough room for any header */
+ if (skb_headroom(skb) < drvr_priv->pub.hdrlen) {
+ struct sk_buff *skb2;
+
+ brcmf_dbg(INFO, "%s: insufficient headroom\n",
+ brcmf_ifname(&drvr_priv->pub, ifidx));
+ drvr_priv->pub.tx_realloc++;
+ skb2 = skb_realloc_headroom(skb, drvr_priv->pub.hdrlen);
+ dev_kfree_skb(skb);
+ skb = skb2;
+ if (skb == NULL) {
+ brcmf_dbg(ERROR, "%s: skb_realloc_headroom failed\n",
+ brcmf_ifname(&drvr_priv->pub, ifidx));
+ ret = -ENOMEM;
+ goto done;
+ }
+ }
+
+ ret = brcmf_sendpkt(&drvr_priv->pub, ifidx, skb);
+
+done:
+ if (ret)
+ drvr_priv->pub.dstats.tx_dropped++;
+ else
+ drvr_priv->pub.tx_packets++;
+
+ /* Return ok: we always eat the packet */
+ return 0;
+}
+
+void brcmf_txflowcontrol(struct brcmf_pub *drvr, int ifidx, bool state)
+{
+ struct net_device *ndev;
+ struct brcmf_info *drvr_priv = drvr->info;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ drvr->txoff = state;
+ ndev = drvr_priv->iflist[ifidx]->ndev;
+ if (state == ON)
+ netif_stop_queue(ndev);
+ else
+ netif_wake_queue(ndev);
+}
+
+static int brcmf_host_event(struct brcmf_info *drvr_priv, int *ifidx,
+ void *pktdata, struct brcmf_event_msg *event,
+ void **data)
+{
+ int bcmerror = 0;
+
+ bcmerror = brcmf_c_host_event(drvr_priv, ifidx, pktdata, event, data);
+ if (bcmerror != 0)
+ return bcmerror;
+
+ if (drvr_priv->iflist[*ifidx]->ndev)
+ brcmf_cfg80211_event(drvr_priv->iflist[*ifidx]->ndev,
+ event, *data);
+
+ return bcmerror;
+}
+
+void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb,
+ int numpkt)
+{
+ struct brcmf_info *drvr_priv = drvr->info;
+ unsigned char *eth;
+ uint len;
+ void *data;
+ struct sk_buff *pnext, *save_pktbuf;
+ int i;
+ struct brcmf_if *ifp;
+ struct brcmf_event_msg event;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ save_pktbuf = skb;
+
+ for (i = 0; skb && i < numpkt; i++, skb = pnext) {
+
+ pnext = skb->next;
+ skb->next = NULL;
+
+ /* Get the protocol, maintain skb around eth_type_trans()
+ * The main reason for this hack is for the limitation of
+ * Linux 2.4 where 'eth_type_trans' uses the
+ * 'net->hard_header_len'
+ * to perform skb_pull inside vs ETH_HLEN. Since to avoid
+ * coping of the packet coming from the network stack to add
+ * BDC, Hardware header etc, during network interface
+ * registration
+ * we set the 'net->hard_header_len' to ETH_HLEN + extra space
+ * required
+ * for BDC, Hardware header etc. and not just the ETH_HLEN
+ */
+ eth = skb->data;
+ len = skb->len;
+
+ ifp = drvr_priv->iflist[ifidx];
+ if (ifp == NULL)
+ ifp = drvr_priv->iflist[0];
+
+ skb->dev = ifp->ndev;
+ skb->protocol = eth_type_trans(skb, skb->dev);
+
+ if (skb->pkt_type == PACKET_MULTICAST)
+ drvr_priv->pub.rx_multicast++;
+
+ skb->data = eth;
+ skb->len = len;
+
+ /* Strip header, count, deliver upward */
+ skb_pull(skb, ETH_HLEN);
+
+ /* Process special event packets and then discard them */
+ if (ntohs(skb->protocol) == ETH_P_LINK_CTL)
+ brcmf_host_event(drvr_priv, &ifidx,
+ skb_mac_header(skb),
+ &event, &data);
+
+ if (drvr_priv->iflist[ifidx] &&
+ !drvr_priv->iflist[ifidx]->state)
+ ifp = drvr_priv->iflist[ifidx];
+
+ if (ifp->ndev)
+ ifp->ndev->last_rx = jiffies;
+
+ drvr->dstats.rx_bytes += skb->len;
+ drvr->rx_packets++; /* Local count */
+
+ if (in_interrupt())
+ netif_rx(skb);
+ else
+ /* If the receive is not processed inside an ISR,
+ * the softirqd must be woken explicitly to service
+ * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled
+ * by netif_rx_ni(), but in earlier kernels, we need
+ * to do it manually.
+ */
+ netif_rx_ni(skb);
+ }
+}
+
+void brcmf_txcomplete(struct brcmf_pub *drvr, struct sk_buff *txp, bool success)
+{
+ uint ifidx;
+ struct brcmf_info *drvr_priv = drvr->info;
+ struct ethhdr *eh;
+ u16 type;
+
+ brcmf_proto_hdrpull(drvr, &ifidx, txp);
+
+ eh = (struct ethhdr *)(txp->data);
+ type = ntohs(eh->h_proto);
+
+ if (type == ETH_P_PAE)
+ atomic_dec(&drvr_priv->pend_8021x_cnt);
+
+}
+
+static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
+{
+ struct brcmf_info *drvr_priv = *(struct brcmf_info **)
+ netdev_priv(ndev);
+ struct brcmf_if *ifp;
+ int ifidx;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ ifidx = brcmf_net2idx(drvr_priv, ndev);
+ if (ifidx == BRCMF_BAD_IF)
+ return NULL;
+
+ ifp = drvr_priv->iflist[ifidx];
+
+ if (drvr_priv->pub.up)
+ /* Use the protocol to get dongle stats */
+ brcmf_proto_dstats(&drvr_priv->pub);
+
+ /* Copy dongle stats to net device stats */
+ ifp->stats.rx_packets = drvr_priv->pub.dstats.rx_packets;
+ ifp->stats.tx_packets = drvr_priv->pub.dstats.tx_packets;
+ ifp->stats.rx_bytes = drvr_priv->pub.dstats.rx_bytes;
+ ifp->stats.tx_bytes = drvr_priv->pub.dstats.tx_bytes;
+ ifp->stats.rx_errors = drvr_priv->pub.dstats.rx_errors;
+ ifp->stats.tx_errors = drvr_priv->pub.dstats.tx_errors;
+ ifp->stats.rx_dropped = drvr_priv->pub.dstats.rx_dropped;
+ ifp->stats.tx_dropped = drvr_priv->pub.dstats.tx_dropped;
+ ifp->stats.multicast = drvr_priv->pub.dstats.multicast;
+
+ return &ifp->stats;
+}
+
+/* Retrieve current toe component enables, which are kept
+ as a bitmap in toe_ol iovar */
+static int brcmf_toe_get(struct brcmf_info *drvr_priv, int ifidx, u32 *toe_ol)
+{
+ struct brcmf_dcmd dcmd;
+ __le32 toe_le;
+ char buf[32];
+ int ret;
+
+ memset(&dcmd, 0, sizeof(dcmd));
+
+ dcmd.cmd = BRCMF_C_GET_VAR;
+ dcmd.buf = buf;
+ dcmd.len = (uint) sizeof(buf);
+ dcmd.set = false;
+
+ strcpy(buf, "toe_ol");
+ ret = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, dcmd.len);
+ if (ret < 0) {
+ /* Check for older dongle image that doesn't support toe_ol */
+ if (ret == -EIO) {
+ brcmf_dbg(ERROR, "%s: toe not supported by device\n",
+ brcmf_ifname(&drvr_priv->pub, ifidx));
+ return -EOPNOTSUPP;
+ }
+
+ brcmf_dbg(INFO, "%s: could not get toe_ol: ret=%d\n",
+ brcmf_ifname(&drvr_priv->pub, ifidx), ret);
+ return ret;
+ }
+
+ memcpy(&toe_le, buf, sizeof(u32));
+ *toe_ol = le32_to_cpu(toe_le);
+ return 0;
+}
+
+/* Set current toe component enables in toe_ol iovar,
+ and set toe global enable iovar */
+static int brcmf_toe_set(struct brcmf_info *drvr_priv, int ifidx, u32 toe_ol)
+{
+ struct brcmf_dcmd dcmd;
+ char buf[32];
+ int ret;
+ __le32 toe_le = cpu_to_le32(toe_ol);
+
+ memset(&dcmd, 0, sizeof(dcmd));
+
+ dcmd.cmd = BRCMF_C_SET_VAR;
+ dcmd.buf = buf;
+ dcmd.len = (uint) sizeof(buf);
+ dcmd.set = true;
+
+ /* Set toe_ol as requested */
+ strcpy(buf, "toe_ol");
+ memcpy(&buf[sizeof("toe_ol")], &toe_le, sizeof(u32));
+
+ ret = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, dcmd.len);
+ if (ret < 0) {
+ brcmf_dbg(ERROR, "%s: could not set toe_ol: ret=%d\n",
+ brcmf_ifname(&drvr_priv->pub, ifidx), ret);
+ return ret;
+ }
+
+ /* Enable toe globally only if any components are enabled. */
+ toe_le = cpu_to_le32(toe_ol != 0);
+
+ strcpy(buf, "toe");
+ memcpy(&buf[sizeof("toe")], &toe_le, sizeof(u32));
+
+ ret = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, dcmd.len);
+ if (ret < 0) {
+ brcmf_dbg(ERROR, "%s: could not set toe: ret=%d\n",
+ brcmf_ifname(&drvr_priv->pub, ifidx), ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
+ struct ethtool_drvinfo *info)
+{
+ struct brcmf_info *drvr_priv = *(struct brcmf_info **)
+ netdev_priv(ndev);
+
+ sprintf(info->driver, KBUILD_MODNAME);
+ sprintf(info->version, "%lu", drvr_priv->pub.drv_version);
+ sprintf(info->fw_version, "%s", BCM4329_FW_NAME);
+ sprintf(info->bus_info, "%s",
+ dev_name(brcmf_bus_get_device(drvr_priv->pub.bus)));
+}
+
+static struct ethtool_ops brcmf_ethtool_ops = {
+ .get_drvinfo = brcmf_ethtool_get_drvinfo
+};
+
+static int brcmf_ethtool(struct brcmf_info *drvr_priv, void __user *uaddr)
+{
+ struct ethtool_drvinfo info;
+ char drvname[sizeof(info.driver)];
+ u32 cmd;
+ struct ethtool_value edata;
+ u32 toe_cmpnt, csum_dir;
+ int ret;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* all ethtool calls start with a cmd word */
+ if (copy_from_user(&cmd, uaddr, sizeof(u32)))
+ return -EFAULT;
+
+ switch (cmd) {
+ case ETHTOOL_GDRVINFO:
+ /* Copy out any request driver name */
+ if (copy_from_user(&info, uaddr, sizeof(info)))
+ return -EFAULT;
+ strncpy(drvname, info.driver, sizeof(info.driver));
+ drvname[sizeof(info.driver) - 1] = '\0';
+
+ /* clear struct for return */
+ memset(&info, 0, sizeof(info));
+ info.cmd = cmd;
+
+ /* if requested, identify ourselves */
+ if (strcmp(drvname, "?dhd") == 0) {
+ sprintf(info.driver, "dhd");
+ strcpy(info.version, BRCMF_VERSION_STR);
+ }
+
+ /* otherwise, require dongle to be up */
+ else if (!drvr_priv->pub.up) {
+ brcmf_dbg(ERROR, "dongle is not up\n");
+ return -ENODEV;
+ }
+
+ /* finally, report dongle driver type */
+ else if (drvr_priv->pub.iswl)
+ sprintf(info.driver, "wl");
+ else
+ sprintf(info.driver, "xx");
+
+ sprintf(info.version, "%lu", drvr_priv->pub.drv_version);
+ if (copy_to_user(uaddr, &info, sizeof(info)))
+ return -EFAULT;
+ brcmf_dbg(CTL, "given %*s, returning %s\n",
+ (int)sizeof(drvname), drvname, info.driver);
+ break;
+
+ /* Get toe offload components from dongle */
+ case ETHTOOL_GRXCSUM:
+ case ETHTOOL_GTXCSUM:
+ ret = brcmf_toe_get(drvr_priv, 0, &toe_cmpnt);
+ if (ret < 0)
+ return ret;
+
+ csum_dir =
+ (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
+
+ edata.cmd = cmd;
+ edata.data = (toe_cmpnt & csum_dir) ? 1 : 0;
+
+ if (copy_to_user(uaddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ break;
+
+ /* Set toe offload components in dongle */
+ case ETHTOOL_SRXCSUM:
+ case ETHTOOL_STXCSUM:
+ if (copy_from_user(&edata, uaddr, sizeof(edata)))
+ return -EFAULT;
+
+ /* Read the current settings, update and write back */
+ ret = brcmf_toe_get(drvr_priv, 0, &toe_cmpnt);
+ if (ret < 0)
+ return ret;
+
+ csum_dir =
+ (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
+
+ if (edata.data != 0)
+ toe_cmpnt |= csum_dir;
+ else
+ toe_cmpnt &= ~csum_dir;
+
+ ret = brcmf_toe_set(drvr_priv, 0, toe_cmpnt);
+ if (ret < 0)
+ return ret;
+
+ /* If setting TX checksum mode, tell Linux the new mode */
+ if (cmd == ETHTOOL_STXCSUM) {
+ if (edata.data)
+ drvr_priv->iflist[0]->ndev->features |=
+ NETIF_F_IP_CSUM;
+ else
+ drvr_priv->iflist[0]->ndev->features &=
+ ~NETIF_F_IP_CSUM;
+ }
+
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,
+ int cmd)
+{
+ struct brcmf_info *drvr_priv = *(struct brcmf_info **)
+ netdev_priv(ndev);
+ int ifidx;
+
+ ifidx = brcmf_net2idx(drvr_priv, ndev);
+ brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifidx, cmd);
+
+ if (ifidx == BRCMF_BAD_IF)
+ return -1;
+
+ if (cmd == SIOCETHTOOL)
+ return brcmf_ethtool(drvr_priv, ifr->ifr_data);
+
+ return -EOPNOTSUPP;
+}
+
+/* called only from within this driver. Sends a command to the dongle. */
+s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len)
+{
+ struct brcmf_dcmd dcmd;
+ s32 err = 0;
+ int buflen = 0;
+ bool is_set_key_cmd;
+ struct brcmf_info *drvr_priv = *(struct brcmf_info **)
+ netdev_priv(ndev);
+ int ifidx;
+
+ memset(&dcmd, 0, sizeof(dcmd));
+ dcmd.cmd = cmd;
+ dcmd.buf = arg;
+ dcmd.len = len;
+
+ ifidx = brcmf_net2idx(drvr_priv, ndev);
+
+ if (dcmd.buf != NULL)
+ buflen = min_t(uint, dcmd.len, BRCMF_DCMD_MAXLEN);
+
+ /* send to dongle (must be up, and wl) */
+ if ((drvr_priv->pub.busstate != BRCMF_BUS_DATA)) {
+ brcmf_dbg(ERROR, "DONGLE_DOWN\n");
+ err = -EIO;
+ goto done;
+ }
+
+ if (!drvr_priv->pub.iswl) {
+ err = -EIO;
+ goto done;
+ }
+
+ /*
+ * Intercept BRCMF_C_SET_KEY CMD - serialize M4 send and
+ * set key CMD to prevent M4 encryption.
+ */
+ is_set_key_cmd = ((dcmd.cmd == BRCMF_C_SET_KEY) ||
+ ((dcmd.cmd == BRCMF_C_SET_VAR) &&
+ !(strncmp("wsec_key", dcmd.buf, 9))) ||
+ ((dcmd.cmd == BRCMF_C_SET_VAR) &&
+ !(strncmp("bsscfg:wsec_key", dcmd.buf, 15))));
+ if (is_set_key_cmd)
+ brcmf_netdev_wait_pend8021x(ndev);
+
+ err = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, buflen);
+
+done:
+ if (err > 0)
+ err = 0;
+
+ return err;
+}
+
+static int brcmf_netdev_stop(struct net_device *ndev)
+{
+ struct brcmf_pub *drvr = *(struct brcmf_pub **) netdev_priv(ndev);
+
+ brcmf_dbg(TRACE, "Enter\n");
+ brcmf_cfg80211_down(drvr->config);
+ if (drvr->up == 0)
+ return 0;
+
+ /* Set state and stop OS transmissions */
+ drvr->up = 0;
+ netif_stop_queue(ndev);
+
+ return 0;
+}
+
+static int brcmf_netdev_open(struct net_device *ndev)
+{
+ struct brcmf_info *drvr_priv = *(struct brcmf_info **)
+ netdev_priv(ndev);
+ u32 toe_ol;
+ int ifidx = brcmf_net2idx(drvr_priv, ndev);
+ s32 ret = 0;
+
+ brcmf_dbg(TRACE, "ifidx %d\n", ifidx);
+
+ if (ifidx == 0) { /* do it only for primary eth0 */
+
+ /* try to bring up bus */
+ ret = brcmf_bus_start(&drvr_priv->pub);
+ if (ret != 0) {
+ brcmf_dbg(ERROR, "failed with code %d\n", ret);
+ return -1;
+ }
+ atomic_set(&drvr_priv->pend_8021x_cnt, 0);
+
+ memcpy(ndev->dev_addr, drvr_priv->pub.mac, ETH_ALEN);
+
+ /* Get current TOE mode from dongle */
+ if (brcmf_toe_get(drvr_priv, ifidx, &toe_ol) >= 0
+ && (toe_ol & TOE_TX_CSUM_OL) != 0)
+ drvr_priv->iflist[ifidx]->ndev->features |=
+ NETIF_F_IP_CSUM;
+ else
+ drvr_priv->iflist[ifidx]->ndev->features &=
+ ~NETIF_F_IP_CSUM;
+ }
+ /* Allow transmit calls */
+ netif_start_queue(ndev);
+ drvr_priv->pub.up = 1;
+ if (brcmf_cfg80211_up(drvr_priv->pub.config)) {
+ brcmf_dbg(ERROR, "failed to bring up cfg80211\n");
+ return -1;
+ }
+
+ return ret;
+}
+
+int
+brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, struct net_device *ndev,
+ char *name, u8 *mac_addr, u32 flags, u8 bssidx)
+{
+ struct brcmf_if *ifp;
+ int ret = 0, err = 0;
+
+ brcmf_dbg(TRACE, "idx %d, handle->%p\n", ifidx, ndev);
+
+ ifp = drvr_priv->iflist[ifidx];
+ if (!ifp) {
+ ifp = kmalloc(sizeof(struct brcmf_if), GFP_ATOMIC);
+ if (!ifp)
+ return -ENOMEM;
+ }
+
+ memset(ifp, 0, sizeof(struct brcmf_if));
+ ifp->info = drvr_priv;
+ drvr_priv->iflist[ifidx] = ifp;
+ if (mac_addr != NULL)
+ memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN);
+
+ if (ndev == NULL) {
+ ifp->state = BRCMF_E_IF_ADD;
+ ifp->idx = ifidx;
+ /*
+ * Delete the existing interface before overwriting it
+ * in case we missed the BRCMF_E_IF_DEL event.
+ */
+ if (ifp->ndev != NULL) {
+ brcmf_dbg(ERROR, "ERROR: netdev:%s already exists, try free & unregister\n",
+ ifp->ndev->name);
+ netif_stop_queue(ifp->ndev);
+ unregister_netdev(ifp->ndev);
+ free_netdev(ifp->ndev);
+ }
+
+ /* Allocate netdev, including space for private structure */
+ ifp->ndev = alloc_netdev(sizeof(drvr_priv), "wlan%d",
+ ether_setup);
+ if (!ifp->ndev) {
+ brcmf_dbg(ERROR, "OOM - alloc_netdev\n");
+ ret = -ENOMEM;
+ }
+
+ if (ret == 0) {
+ memcpy(netdev_priv(ifp->ndev), &drvr_priv,
+ sizeof(drvr_priv));
+ err = brcmf_net_attach(&drvr_priv->pub, ifp->idx);
+ if (err != 0) {
+ brcmf_dbg(ERROR, "brcmf_net_attach failed, err %d\n",
+ err);
+ ret = -EOPNOTSUPP;
+ } else {
+ brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n",
+ current->pid, ifp->ndev->name);
+ ifp->state = 0;
+ }
+ }
+
+ if (ret < 0) {
+ if (ifp->ndev)
+ free_netdev(ifp->ndev);
+
+ drvr_priv->iflist[ifp->idx] = NULL;
+ kfree(ifp);
+ }
+ } else
+ ifp->ndev = ndev;
+
+ return 0;
+}
+
+void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx)
+{
+ struct brcmf_if *ifp;
+
+ brcmf_dbg(TRACE, "idx %d\n", ifidx);
+
+ ifp = drvr_priv->iflist[ifidx];
+ if (!ifp) {
+ brcmf_dbg(ERROR, "Null interface\n");
+ return;
+ }
+
+ ifp->state = BRCMF_E_IF_DEL;
+ ifp->idx = ifidx;
+ if (ifp->ndev != NULL) {
+ netif_stop_queue(ifp->ndev);
+ unregister_netdev(ifp->ndev);
+ free_netdev(ifp->ndev);
+ drvr_priv->iflist[ifidx] = NULL;
+ kfree(ifp);
+ }
+}
+
+struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen)
+{
+ struct brcmf_info *drvr_priv = NULL;
+ struct net_device *ndev;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Allocate netdev, including space for private structure */
+ ndev = alloc_netdev(sizeof(drvr_priv), "wlan%d", ether_setup);
+ if (!ndev) {
+ brcmf_dbg(ERROR, "OOM - alloc_netdev\n");
+ goto fail;
+ }
+
+ /* Allocate primary brcmf_info */
+ drvr_priv = kzalloc(sizeof(struct brcmf_info), GFP_ATOMIC);
+ if (!drvr_priv)
+ goto fail;
+
+ /*
+ * Save the brcmf_info into the priv
+ */
+ memcpy(netdev_priv(ndev), &drvr_priv, sizeof(drvr_priv));
+
+ if (brcmf_add_if(drvr_priv, 0, ndev, ndev->name, NULL, 0, 0) ==
+ BRCMF_BAD_IF)
+ goto fail;
+
+ ndev->netdev_ops = NULL;
+ mutex_init(&drvr_priv->proto_block);
+
+ /* Link to info module */
+ drvr_priv->pub.info = drvr_priv;
+
+ /* Link to bus module */
+ drvr_priv->pub.bus = bus;
+ drvr_priv->pub.hdrlen = bus_hdrlen;
+
+ /* Attach and link in the protocol */
+ if (brcmf_proto_attach(&drvr_priv->pub) != 0) {
+ brcmf_dbg(ERROR, "brcmf_prot_attach failed\n");
+ goto fail;
+ }
+
+ /* Attach and link in the cfg80211 */
+ drvr_priv->pub.config =
+ brcmf_cfg80211_attach(ndev,
+ brcmf_bus_get_device(bus),
+ &drvr_priv->pub);
+ if (drvr_priv->pub.config == NULL) {
+ brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n");
+ goto fail;
+ }
+
+ INIT_WORK(&drvr_priv->setmacaddr_work, _brcmf_set_mac_address);
+ INIT_WORK(&drvr_priv->multicast_work, _brcmf_set_multicast_list);
+
+ /*
+ * Save the brcmf_info into the priv
+ */
+ memcpy(netdev_priv(ndev), &drvr_priv, sizeof(drvr_priv));
+
+ return &drvr_priv->pub;
+
+fail:
+ if (ndev)
+ free_netdev(ndev);
+ if (drvr_priv)
+ brcmf_detach(&drvr_priv->pub);
+
+ return NULL;
+}
+
+int brcmf_bus_start(struct brcmf_pub *drvr)
+{
+ int ret = -1;
+ struct brcmf_info *drvr_priv = drvr->info;
+ /* Room for "event_msgs" + '\0' + bitvec */
+ char iovbuf[BRCMF_EVENTING_MASK_LEN + 12];
+
+ brcmf_dbg(TRACE, "\n");
+
+ /* Bring up the bus */
+ ret = brcmf_sdbrcm_bus_init(&drvr_priv->pub);
+ if (ret != 0) {
+ brcmf_dbg(ERROR, "brcmf_sdbrcm_bus_init failed %d\n", ret);
+ return ret;
+ }
+
+ /* If bus is not ready, can't come up */
+ if (drvr_priv->pub.busstate != 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,
+ sizeof(iovbuf));
+ memcpy(drvr->eventmask, iovbuf, BRCMF_EVENTING_MASK_LEN);
+
+ setbit(drvr->eventmask, BRCMF_E_SET_SSID);
+ setbit(drvr->eventmask, BRCMF_E_PRUNE);
+ setbit(drvr->eventmask, BRCMF_E_AUTH);
+ setbit(drvr->eventmask, BRCMF_E_REASSOC);
+ setbit(drvr->eventmask, BRCMF_E_REASSOC_IND);
+ setbit(drvr->eventmask, BRCMF_E_DEAUTH_IND);
+ setbit(drvr->eventmask, BRCMF_E_DISASSOC_IND);
+ setbit(drvr->eventmask, BRCMF_E_DISASSOC);
+ setbit(drvr->eventmask, BRCMF_E_JOIN);
+ setbit(drvr->eventmask, BRCMF_E_ASSOC_IND);
+ setbit(drvr->eventmask, BRCMF_E_PSK_SUP);
+ setbit(drvr->eventmask, BRCMF_E_LINK);
+ setbit(drvr->eventmask, BRCMF_E_NDIS_LINK);
+ setbit(drvr->eventmask, BRCMF_E_MIC_ERROR);
+ setbit(drvr->eventmask, BRCMF_E_PMKID_CACHE);
+ setbit(drvr->eventmask, BRCMF_E_TXFAIL);
+ setbit(drvr->eventmask, BRCMF_E_JOIN_START);
+ setbit(drvr->eventmask, BRCMF_E_SCAN_COMPLETE);
+
+/* enable dongle roaming event */
+
+ drvr->pktfilter_count = 1;
+ /* Setup filter to allow only unicast */
+ drvr->pktfilter[0] = "100 0 0 0 0x01 0x00";
+
+ /* Bus is ready, do any protocol initialization */
+ ret = brcmf_proto_init(&drvr_priv->pub);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct net_device_ops brcmf_netdev_ops_pri = {
+ .ndo_open = brcmf_netdev_open,
+ .ndo_stop = brcmf_netdev_stop,
+ .ndo_get_stats = brcmf_netdev_get_stats,
+ .ndo_do_ioctl = brcmf_netdev_ioctl_entry,
+ .ndo_start_xmit = brcmf_netdev_start_xmit,
+ .ndo_set_mac_address = brcmf_netdev_set_mac_address,
+ .ndo_set_rx_mode = brcmf_netdev_set_multicast_list
+};
+
+int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx)
+{
+ struct brcmf_info *drvr_priv = drvr->info;
+ struct net_device *ndev;
+ u8 temp_addr[ETH_ALEN] = {
+ 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33};
+
+ brcmf_dbg(TRACE, "ifidx %d\n", ifidx);
+
+ ndev = drvr_priv->iflist[ifidx]->ndev;
+ ndev->netdev_ops = &brcmf_netdev_ops_pri;
+
+ /*
+ * We have to use the primary MAC for virtual interfaces
+ */
+ if (ifidx != 0) {
+ /* for virtual interfaces use the primary MAC */
+ memcpy(temp_addr, drvr_priv->pub.mac, ETH_ALEN);
+
+ }
+
+ if (ifidx == 1) {
+ brcmf_dbg(TRACE, "ACCESS POINT MAC:\n");
+ /* ACCESSPOINT INTERFACE CASE */
+ temp_addr[0] |= 0X02; /* set bit 2 ,
+ - Locally Administered address */
+
+ }
+ ndev->hard_header_len = ETH_HLEN + drvr_priv->pub.hdrlen;
+ ndev->ethtool_ops = &brcmf_ethtool_ops;
+
+ drvr_priv->pub.rxsz = ndev->mtu + ndev->hard_header_len +
+ drvr_priv->pub.hdrlen;
+
+ memcpy(ndev->dev_addr, temp_addr, ETH_ALEN);
+
+ if (register_netdev(ndev) != 0) {
+ brcmf_dbg(ERROR, "couldn't register the net device\n");
+ goto fail;
+ }
+
+ brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
+
+ return 0;
+
+fail:
+ ndev->netdev_ops = NULL;
+ return -EBADE;
+}
+
+static void brcmf_bus_detach(struct brcmf_pub *drvr)
+{
+ struct brcmf_info *drvr_priv;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (drvr) {
+ drvr_priv = drvr->info;
+ if (drvr_priv) {
+ /* Stop the protocol module */
+ brcmf_proto_stop(&drvr_priv->pub);
+
+ /* Stop the bus module */
+ brcmf_sdbrcm_bus_stop(drvr_priv->pub.bus);
+ }
+ }
+}
+
+void brcmf_detach(struct brcmf_pub *drvr)
+{
+ struct brcmf_info *drvr_priv;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (drvr) {
+ drvr_priv = drvr->info;
+ if (drvr_priv) {
+ struct brcmf_if *ifp;
+ int i;
+
+ for (i = 1; i < BRCMF_MAX_IFS; i++)
+ if (drvr_priv->iflist[i])
+ brcmf_del_if(drvr_priv, i);
+
+ ifp = drvr_priv->iflist[0];
+ if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
+ rtnl_lock();
+ brcmf_netdev_stop(ifp->ndev);
+ rtnl_unlock();
+ unregister_netdev(ifp->ndev);
+ }
+
+ cancel_work_sync(&drvr_priv->setmacaddr_work);
+ cancel_work_sync(&drvr_priv->multicast_work);
+
+ brcmf_bus_detach(drvr);
+
+ if (drvr->prot)
+ brcmf_proto_detach(drvr);
+
+ brcmf_cfg80211_detach(drvr->config);
+
+ free_netdev(ifp->ndev);
+ kfree(ifp);
+ kfree(drvr_priv);
+ }
+ }
+}
+
+static void __exit brcmf_module_cleanup(void)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ brcmf_bus_unregister();
+}
+
+static int __init brcmf_module_init(void)
+{
+ int error;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ error = brcmf_bus_register();
+
+ if (error) {
+ brcmf_dbg(ERROR, "brcmf_bus_register failed\n");
+ goto failed;
+ }
+ return 0;
+
+failed:
+ return -EINVAL;
+}
+
+module_init(brcmf_module_init);
+module_exit(brcmf_module_cleanup);
+
+int brcmf_os_proto_block(struct brcmf_pub *drvr)
+{
+ struct brcmf_info *drvr_priv = drvr->info;
+
+ if (drvr_priv) {
+ mutex_lock(&drvr_priv->proto_block);
+ return 1;
+ }
+ return 0;
+}
+
+int brcmf_os_proto_unblock(struct brcmf_pub *drvr)
+{
+ struct brcmf_info *drvr_priv = drvr->info;
+
+ if (drvr_priv) {
+ mutex_unlock(&drvr_priv->proto_block);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int brcmf_get_pend_8021x_cnt(struct brcmf_info *drvr_priv)
+{
+ return atomic_read(&drvr_priv->pend_8021x_cnt);
+}
+
+#define MAX_WAIT_FOR_8021X_TX 10
+
+int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
+{
+ struct brcmf_info *drvr_priv = *(struct brcmf_info **)netdev_priv(ndev);
+ int timeout = 10 * HZ / 1000;
+ int ntimes = MAX_WAIT_FOR_8021X_TX;
+ int pend = brcmf_get_pend_8021x_cnt(drvr_priv);
+
+ while (ntimes && pend) {
+ if (pend) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(timeout);
+ set_current_state(TASK_RUNNING);
+ ntimes--;
+ }
+ pend = brcmf_get_pend_8021x_cnt(drvr_priv);
+ }
+ return pend;
+}
+
+#ifdef BCMDBG
+int brcmf_write_to_file(struct brcmf_pub *drvr, const u8 *buf, int size)
+{
+ int ret = 0;
+ struct file *fp;
+ mm_segment_t old_fs;
+ loff_t pos = 0;
+
+ /* change to KERNEL_DS address limit */
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ /* open file to write */
+ fp = filp_open("/tmp/mem_dump", O_WRONLY | O_CREAT, 0640);
+ if (!fp) {
+ brcmf_dbg(ERROR, "open file error\n");
+ ret = -1;
+ goto exit;
+ }
+
+ /* Write buf to file */
+ fp->f_op->write(fp, (char __user *)buf, size, &pos);
+
+exit:
+ /* free buf before return */
+ kfree(buf);
+ /* close file before return */
+ if (fp)
+ filp_close(fp, current->files);
+ /* restore previous address limit */
+ set_fs(old_fs);
+
+ return ret;
+}
+#endif /* BCMDBG */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h
new file mode 100644
index 000000000000..4ee1ea846f6d
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2010 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 _BRCMF_PROTO_H_
+#define _BRCMF_PROTO_H_
+
+/*
+ * Exported from the brcmf protocol module (brcmf_cdc)
+ */
+
+/* Linkage, sets prot link and updates hdrlen in pub */
+extern int brcmf_proto_attach(struct brcmf_pub *drvr);
+
+/* Unlink, frees allocated protocol memory (including brcmf_proto) */
+extern void brcmf_proto_detach(struct brcmf_pub *drvr);
+
+/* Initialize protocol: sync w/dongle state.
+ * Sets dongle media info (iswl, drv_version, mac address).
+ */
+extern int brcmf_proto_init(struct brcmf_pub *drvr);
+
+/* Stop protocol: sync w/dongle state. */
+extern void brcmf_proto_stop(struct brcmf_pub *drvr);
+
+/* Add any protocol-specific data header.
+ * Caller must reserve prot_hdrlen prepend space.
+ */
+extern void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx,
+ struct sk_buff *txp);
+
+/* Remove any protocol-specific data header. */
+extern int brcmf_proto_hdrpull(struct brcmf_pub *, int *ifidx,
+ struct sk_buff *rxp);
+
+/* Use protocol to issue command to dongle */
+extern int brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx,
+ struct brcmf_dcmd *dcmd, int len);
+
+/* Update local copy of dongle statistics */
+extern void brcmf_proto_dstats(struct brcmf_pub *drvr);
+
+extern int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr);
+
+extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx,
+ uint cmd, void *buf, uint len);
+
+#endif /* _BRCMF_PROTO_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
new file mode 100644
index 000000000000..313b8bf592d1
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -0,0 +1,4591 @@
+/*
+ * Copyright (c) 2010 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/types.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/printk.h>
+#include <linux/pci_ids.h>
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/card.h>
+#include <linux/semaphore.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <asm/unaligned.h>
+#include <defs.h>
+#include <brcmu_wifi.h>
+#include <brcmu_utils.h>
+#include <brcm_hw_ids.h>
+#include <soc.h>
+#include "sdio_host.h"
+
+#define DCMD_RESP_TIMEOUT 2000 /* In milli second */
+
+#ifdef BCMDBG
+
+#define BRCMF_TRAP_INFO_SIZE 80
+
+#define CBUF_LEN (128)
+
+struct rte_log_le {
+ __le32 buf; /* Can't be pointer on (64-bit) hosts */
+ __le32 buf_size;
+ __le32 idx;
+ char *_buf_compat; /* Redundant pointer for backward compat. */
+};
+
+struct rte_console {
+ /* Virtual UART
+ * When there is no UART (e.g. Quickturn),
+ * the host should write a complete
+ * input line directly into cbuf and then write
+ * the length into vcons_in.
+ * This may also be used when there is a real UART
+ * (at risk of conflicting with
+ * the real UART). vcons_out is currently unused.
+ */
+ uint vcons_in;
+ uint vcons_out;
+
+ /* Output (logging) buffer
+ * Console output is written to a ring buffer log_buf at index log_idx.
+ * The host may read the output when it sees log_idx advance.
+ * Output will be lost if the output wraps around faster than the host
+ * polls.
+ */
+ struct rte_log_le log_le;
+
+ /* Console input line buffer
+ * Characters are read one at a time into cbuf
+ * until <CR> is received, then
+ * the buffer is processed as a command line.
+ * Also used for virtual UART.
+ */
+ uint cbuf_idx;
+ char cbuf[CBUF_LEN];
+};
+
+#endif /* BCMDBG */
+#include <chipcommon.h>
+
+#include "dhd.h"
+#include "dhd_bus.h"
+#include "dhd_proto.h"
+#include "dhd_dbg.h"
+#include <bcmchip.h>
+
+#define TXQLEN 2048 /* bulk tx queue length */
+#define TXHI (TXQLEN - 256) /* turn on flow control above TXHI */
+#define TXLOW (TXHI - 256) /* turn off flow control below TXLOW */
+#define PRIOMASK 7
+
+#define TXRETRIES 2 /* # of retries for tx frames */
+
+#define BRCMF_RXBOUND 50 /* Default for max rx frames in
+ one scheduling */
+
+#define BRCMF_TXBOUND 20 /* Default for max tx frames in
+ one scheduling */
+
+#define BRCMF_TXMINMAX 1 /* Max tx frames if rx still pending */
+
+#define MEMBLOCK 2048 /* Block size used for downloading
+ of dongle image */
+#define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold
+ biggest possible glom */
+
+#define BRCMF_FIRSTREAD (1 << 6)
+
+
+/* SBSDIO_DEVICE_CTL */
+
+/* 1: device will assert busy signal when receiving CMD53 */
+#define SBSDIO_DEVCTL_SETBUSY 0x01
+/* 1: assertion of sdio interrupt is synchronous to the sdio clock */
+#define SBSDIO_DEVCTL_SPI_INTR_SYNC 0x02
+/* 1: mask all interrupts to host except the chipActive (rev 8) */
+#define SBSDIO_DEVCTL_CA_INT_ONLY 0x04
+/* 1: isolate internal sdio signals, put external pads in tri-state; requires
+ * sdio bus power cycle to clear (rev 9) */
+#define SBSDIO_DEVCTL_PADS_ISO 0x08
+/* Force SD->SB reset mapping (rev 11) */
+#define SBSDIO_DEVCTL_SB_RST_CTL 0x30
+/* Determined by CoreControl bit */
+#define SBSDIO_DEVCTL_RST_CORECTL 0x00
+/* Force backplane reset */
+#define SBSDIO_DEVCTL_RST_BPRESET 0x10
+/* Force no backplane reset */
+#define SBSDIO_DEVCTL_RST_NOBPRESET 0x20
+
+/* SBSDIO_FUNC1_CHIPCLKCSR */
+
+/* Force ALP request to backplane */
+#define SBSDIO_FORCE_ALP 0x01
+/* Force HT request to backplane */
+#define SBSDIO_FORCE_HT 0x02
+/* Force ILP request to backplane */
+#define SBSDIO_FORCE_ILP 0x04
+/* Make ALP ready (power up xtal) */
+#define SBSDIO_ALP_AVAIL_REQ 0x08
+/* Make HT ready (power up PLL) */
+#define SBSDIO_HT_AVAIL_REQ 0x10
+/* Squelch clock requests from HW */
+#define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20
+/* Status: ALP is ready */
+#define SBSDIO_ALP_AVAIL 0x40
+/* Status: HT is ready */
+#define SBSDIO_HT_AVAIL 0x80
+
+#define SBSDIO_AVBITS (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL)
+#define SBSDIO_ALPAV(regval) ((regval) & SBSDIO_AVBITS)
+#define SBSDIO_HTAV(regval) (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS)
+#define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval))
+
+#define SBSDIO_CLKAV(regval, alponly) \
+ (SBSDIO_ALPAV(regval) && (alponly ? 1 : SBSDIO_HTAV(regval)))
+
+/* direct(mapped) cis space */
+
+/* MAPPED common CIS address */
+#define SBSDIO_CIS_BASE_COMMON 0x1000
+/* maximum bytes in one CIS */
+#define SBSDIO_CIS_SIZE_LIMIT 0x200
+/* cis offset addr is < 17 bits */
+#define SBSDIO_CIS_OFT_ADDR_MASK 0x1FFFF
+
+/* manfid tuple length, include tuple, link bytes */
+#define SBSDIO_CIS_MANFID_TUPLE_LEN 6
+
+/* intstatus */
+#define I_SMB_SW0 (1 << 0) /* To SB Mail S/W interrupt 0 */
+#define I_SMB_SW1 (1 << 1) /* To SB Mail S/W interrupt 1 */
+#define I_SMB_SW2 (1 << 2) /* To SB Mail S/W interrupt 2 */
+#define I_SMB_SW3 (1 << 3) /* To SB Mail S/W interrupt 3 */
+#define I_SMB_SW_MASK 0x0000000f /* To SB Mail S/W interrupts mask */
+#define I_SMB_SW_SHIFT 0 /* To SB Mail S/W interrupts shift */
+#define I_HMB_SW0 (1 << 4) /* To Host Mail S/W interrupt 0 */
+#define I_HMB_SW1 (1 << 5) /* To Host Mail S/W interrupt 1 */
+#define I_HMB_SW2 (1 << 6) /* To Host Mail S/W interrupt 2 */
+#define I_HMB_SW3 (1 << 7) /* To Host Mail S/W interrupt 3 */
+#define I_HMB_SW_MASK 0x000000f0 /* To Host Mail S/W interrupts mask */
+#define I_HMB_SW_SHIFT 4 /* To Host Mail S/W interrupts shift */
+#define I_WR_OOSYNC (1 << 8) /* Write Frame Out Of Sync */
+#define I_RD_OOSYNC (1 << 9) /* Read Frame Out Of Sync */
+#define I_PC (1 << 10) /* descriptor error */
+#define I_PD (1 << 11) /* data error */
+#define I_DE (1 << 12) /* Descriptor protocol Error */
+#define I_RU (1 << 13) /* Receive descriptor Underflow */
+#define I_RO (1 << 14) /* Receive fifo Overflow */
+#define I_XU (1 << 15) /* Transmit fifo Underflow */
+#define I_RI (1 << 16) /* Receive Interrupt */
+#define I_BUSPWR (1 << 17) /* SDIO Bus Power Change (rev 9) */
+#define I_XMTDATA_AVAIL (1 << 23) /* bits in fifo */
+#define I_XI (1 << 24) /* Transmit Interrupt */
+#define I_RF_TERM (1 << 25) /* Read Frame Terminate */
+#define I_WF_TERM (1 << 26) /* Write Frame Terminate */
+#define I_PCMCIA_XU (1 << 27) /* PCMCIA Transmit FIFO Underflow */
+#define I_SBINT (1 << 28) /* sbintstatus Interrupt */
+#define I_CHIPACTIVE (1 << 29) /* chip from doze to active state */
+#define I_SRESET (1 << 30) /* CCCR RES interrupt */
+#define I_IOE2 (1U << 31) /* CCCR IOE2 Bit Changed */
+#define I_ERRORS (I_PC | I_PD | I_DE | I_RU | I_RO | I_XU)
+#define I_DMA (I_RI | I_XI | I_ERRORS)
+
+/* corecontrol */
+#define CC_CISRDY (1 << 0) /* CIS Ready */
+#define CC_BPRESEN (1 << 1) /* CCCR RES signal */
+#define CC_F2RDY (1 << 2) /* set CCCR IOR2 bit */
+#define CC_CLRPADSISO (1 << 3) /* clear SDIO pads isolation */
+#define CC_XMTDATAAVAIL_MODE (1 << 4)
+#define CC_XMTDATAAVAIL_CTRL (1 << 5)
+
+/* SDA_FRAMECTRL */
+#define SFC_RF_TERM (1 << 0) /* Read Frame Terminate */
+#define SFC_WF_TERM (1 << 1) /* Write Frame Terminate */
+#define SFC_CRC4WOOS (1 << 2) /* CRC error for write out of sync */
+#define SFC_ABORTALL (1 << 3) /* Abort all in-progress frames */
+
+/* HW frame tag */
+#define SDPCM_FRAMETAG_LEN 4 /* 2 bytes len, 2 bytes check val */
+
+/* Total length of frame header for dongle protocol */
+#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
+#define SDPCM_RESERVE (SDPCM_HDRLEN + BRCMF_SDALIGN)
+
+/*
+ * Software allocation of To SB Mailbox resources
+ */
+
+/* tosbmailbox bits corresponding to intstatus bits */
+#define SMB_NAK (1 << 0) /* Frame NAK */
+#define SMB_INT_ACK (1 << 1) /* Host Interrupt ACK */
+#define SMB_USE_OOB (1 << 2) /* Use OOB Wakeup */
+#define SMB_DEV_INT (1 << 3) /* Miscellaneous Interrupt */
+
+/* tosbmailboxdata */
+#define SMB_DATA_VERSION_SHIFT 16 /* host protocol version */
+
+/*
+ * Software allocation of To Host Mailbox resources
+ */
+
+/* intstatus bits */
+#define I_HMB_FC_STATE I_HMB_SW0 /* Flow Control State */
+#define I_HMB_FC_CHANGE I_HMB_SW1 /* Flow Control State Changed */
+#define I_HMB_FRAME_IND I_HMB_SW2 /* Frame Indication */
+#define I_HMB_HOST_INT I_HMB_SW3 /* Miscellaneous Interrupt */
+
+/* tohostmailboxdata */
+#define HMB_DATA_NAKHANDLED 1 /* retransmit NAK'd frame */
+#define HMB_DATA_DEVREADY 2 /* talk to host after enable */
+#define HMB_DATA_FC 4 /* per prio flowcontrol update flag */
+#define HMB_DATA_FWREADY 8 /* fw ready for protocol activity */
+
+#define HMB_DATA_FCDATA_MASK 0xff000000
+#define HMB_DATA_FCDATA_SHIFT 24
+
+#define HMB_DATA_VERSION_MASK 0x00ff0000
+#define HMB_DATA_VERSION_SHIFT 16
+
+/*
+ * Software-defined protocol header
+ */
+
+/* Current protocol version */
+#define SDPCM_PROT_VERSION 4
+
+/* SW frame header */
+#define SDPCM_PACKET_SEQUENCE(p) (((u8 *)p)[0] & 0xff)
+
+#define SDPCM_CHANNEL_MASK 0x00000f00
+#define SDPCM_CHANNEL_SHIFT 8
+#define SDPCM_PACKET_CHANNEL(p) (((u8 *)p)[1] & 0x0f)
+
+#define SDPCM_NEXTLEN_OFFSET 2
+
+/* Data Offset from SOF (HW Tag, SW Tag, Pad) */
+#define SDPCM_DOFFSET_OFFSET 3 /* Data Offset */
+#define SDPCM_DOFFSET_VALUE(p) (((u8 *)p)[SDPCM_DOFFSET_OFFSET] & 0xff)
+#define SDPCM_DOFFSET_MASK 0xff000000
+#define SDPCM_DOFFSET_SHIFT 24
+#define SDPCM_FCMASK_OFFSET 4 /* Flow control */
+#define SDPCM_FCMASK_VALUE(p) (((u8 *)p)[SDPCM_FCMASK_OFFSET] & 0xff)
+#define SDPCM_WINDOW_OFFSET 5 /* Credit based fc */
+#define SDPCM_WINDOW_VALUE(p) (((u8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff)
+
+#define SDPCM_SWHEADER_LEN 8 /* SW header is 64 bits */
+
+/* logical channel numbers */
+#define SDPCM_CONTROL_CHANNEL 0 /* Control channel Id */
+#define SDPCM_EVENT_CHANNEL 1 /* Asyc Event Indication Channel Id */
+#define SDPCM_DATA_CHANNEL 2 /* Data Xmit/Recv Channel Id */
+#define SDPCM_GLOM_CHANNEL 3 /* For coalesced packets */
+#define SDPCM_TEST_CHANNEL 15 /* Reserved for test/debug packets */
+
+#define SDPCM_SEQUENCE_WRAP 256 /* wrap-around val for 8bit frame seq */
+
+#define SDPCM_GLOMDESC(p) (((u8 *)p)[1] & 0x80)
+
+/*
+ * Shared structure between dongle and the host.
+ * The structure contains pointers to trap or assert information.
+ */
+#define SDPCM_SHARED_VERSION 0x0002
+#define SDPCM_SHARED_VERSION_MASK 0x00FF
+#define SDPCM_SHARED_ASSERT_BUILT 0x0100
+#define SDPCM_SHARED_ASSERT 0x0200
+#define SDPCM_SHARED_TRAP 0x0400
+
+/* Space for header read, limit for data packets */
+#define MAX_HDR_READ (1 << 6)
+#define MAX_RX_DATASZ 2048
+
+/* Maximum milliseconds to wait for F2 to come up */
+#define BRCMF_WAIT_F2RDY 3000
+
+/* Bump up limit on waiting for HT to account for first startup;
+ * if the image is doing a CRC calculation before programming the PMU
+ * for HT availability, it could take a couple hundred ms more, so
+ * max out at a 1 second (1000000us).
+ */
+#undef PMU_MAX_TRANSITION_DLY
+#define PMU_MAX_TRANSITION_DLY 1000000
+
+/* Value for ChipClockCSR during initial setup */
+#define BRCMF_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | \
+ SBSDIO_ALP_AVAIL_REQ)
+
+/* Flags for SDH calls */
+#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
+
+/* sbimstate */
+#define SBIM_IBE 0x20000 /* inbanderror */
+#define SBIM_TO 0x40000 /* timeout */
+#define SBIM_BY 0x01800000 /* busy (sonics >= 2.3) */
+#define SBIM_RJ 0x02000000 /* reject (sonics >= 2.3) */
+
+/* sbtmstatelow */
+
+/* reset */
+#define SBTML_RESET 0x0001
+/* reject field */
+#define SBTML_REJ_MASK 0x0006
+/* reject */
+#define SBTML_REJ 0x0002
+/* temporary reject, for error recovery */
+#define SBTML_TMPREJ 0x0004
+
+/* Shift to locate the SI control flags in sbtml */
+#define SBTML_SICF_SHIFT 16
+
+/* sbtmstatehigh */
+#define SBTMH_SERR 0x0001 /* serror */
+#define SBTMH_INT 0x0002 /* interrupt */
+#define SBTMH_BUSY 0x0004 /* busy */
+#define SBTMH_TO 0x0020 /* timeout (sonics >= 2.3) */
+
+/* Shift to locate the SI status flags in sbtmh */
+#define SBTMH_SISF_SHIFT 16
+
+/* sbidlow */
+#define SBIDL_INIT 0x80 /* initiator */
+
+/* sbidhigh */
+#define SBIDH_RC_MASK 0x000f /* revision code */
+#define SBIDH_RCE_MASK 0x7000 /* revision code extension field */
+#define SBIDH_RCE_SHIFT 8
+#define SBCOREREV(sbidh) \
+ ((((sbidh) & SBIDH_RCE_MASK) >> SBIDH_RCE_SHIFT) | \
+ ((sbidh) & SBIDH_RC_MASK))
+#define SBIDH_CC_MASK 0x8ff0 /* core code */
+#define SBIDH_CC_SHIFT 4
+#define SBIDH_VC_MASK 0xffff0000 /* vendor code */
+#define SBIDH_VC_SHIFT 16
+
+/*
+ * Conversion of 802.1D priority to precedence level
+ */
+static uint prio2prec(u32 prio)
+{
+ return (prio == PRIO_8021D_NONE || prio == PRIO_8021D_BE) ?
+ (prio^2) : prio;
+}
+
+/*
+ * Core reg address translation.
+ * Both macro's returns a 32 bits byte address on the backplane bus.
+ */
+#define CORE_CC_REG(base, field) \
+ (base + offsetof(struct chipcregs, field))
+#define CORE_BUS_REG(base, field) \
+ (base + offsetof(struct sdpcmd_regs, field))
+#define CORE_SB(base, field) \
+ (base + SBCONFIGOFF + offsetof(struct sbconfig, field))
+
+/* core registers */
+struct sdpcmd_regs {
+ u32 corecontrol; /* 0x00, rev8 */
+ u32 corestatus; /* rev8 */
+ u32 PAD[1];
+ u32 biststatus; /* rev8 */
+
+ /* PCMCIA access */
+ u16 pcmciamesportaladdr; /* 0x010, rev8 */
+ u16 PAD[1];
+ u16 pcmciamesportalmask; /* rev8 */
+ u16 PAD[1];
+ u16 pcmciawrframebc; /* rev8 */
+ u16 PAD[1];
+ u16 pcmciaunderflowtimer; /* rev8 */
+ u16 PAD[1];
+
+ /* interrupt */
+ u32 intstatus; /* 0x020, rev8 */
+ u32 hostintmask; /* rev8 */
+ u32 intmask; /* rev8 */
+ u32 sbintstatus; /* rev8 */
+ u32 sbintmask; /* rev8 */
+ u32 funcintmask; /* rev4 */
+ u32 PAD[2];
+ u32 tosbmailbox; /* 0x040, rev8 */
+ u32 tohostmailbox; /* rev8 */
+ u32 tosbmailboxdata; /* rev8 */
+ u32 tohostmailboxdata; /* rev8 */
+
+ /* synchronized access to registers in SDIO clock domain */
+ u32 sdioaccess; /* 0x050, rev8 */
+ u32 PAD[3];
+
+ /* PCMCIA frame control */
+ u8 pcmciaframectrl; /* 0x060, rev8 */
+ u8 PAD[3];
+ u8 pcmciawatermark; /* rev8 */
+ u8 PAD[155];
+
+ /* interrupt batching control */
+ u32 intrcvlazy; /* 0x100, rev8 */
+ u32 PAD[3];
+
+ /* counters */
+ u32 cmd52rd; /* 0x110, rev8 */
+ u32 cmd52wr; /* rev8 */
+ u32 cmd53rd; /* rev8 */
+ u32 cmd53wr; /* rev8 */
+ u32 abort; /* rev8 */
+ u32 datacrcerror; /* rev8 */
+ u32 rdoutofsync; /* rev8 */
+ u32 wroutofsync; /* rev8 */
+ u32 writebusy; /* rev8 */
+ u32 readwait; /* rev8 */
+ u32 readterm; /* rev8 */
+ u32 writeterm; /* rev8 */
+ u32 PAD[40];
+ u32 clockctlstatus; /* rev8 */
+ u32 PAD[7];
+
+ u32 PAD[128]; /* DMA engines */
+
+ /* SDIO/PCMCIA CIS region */
+ char cis[512]; /* 0x400-0x5ff, rev6 */
+
+ /* PCMCIA function control registers */
+ char pcmciafcr[256]; /* 0x600-6ff, rev6 */
+ u16 PAD[55];
+
+ /* PCMCIA backplane access */
+ u16 backplanecsr; /* 0x76E, rev6 */
+ u16 backplaneaddr0; /* rev6 */
+ u16 backplaneaddr1; /* rev6 */
+ u16 backplaneaddr2; /* rev6 */
+ u16 backplaneaddr3; /* rev6 */
+ u16 backplanedata0; /* rev6 */
+ u16 backplanedata1; /* rev6 */
+ u16 backplanedata2; /* rev6 */
+ u16 backplanedata3; /* rev6 */
+ u16 PAD[31];
+
+ /* sprom "size" & "blank" info */
+ u16 spromstatus; /* 0x7BE, rev2 */
+ u32 PAD[464];
+
+ u16 PAD[0x80];
+};
+
+#ifdef BCMDBG
+/* Device console log buffer state */
+struct brcmf_console {
+ uint count; /* Poll interval msec counter */
+ uint log_addr; /* Log struct address (fixed) */
+ struct rte_log_le log_le; /* Log struct (host copy) */
+ uint bufsize; /* Size of log buffer */
+ u8 *buf; /* Log buffer (host copy) */
+ uint last; /* Last buffer read index */
+};
+#endif /* BCMDBG */
+
+struct sdpcm_shared {
+ u32 flags;
+ u32 trap_addr;
+ u32 assert_exp_addr;
+ u32 assert_file_addr;
+ u32 assert_line;
+ u32 console_addr; /* Address of struct rte_console */
+ u32 msgtrace_addr;
+ u8 tag[32];
+};
+
+struct sdpcm_shared_le {
+ __le32 flags;
+ __le32 trap_addr;
+ __le32 assert_exp_addr;
+ __le32 assert_file_addr;
+ __le32 assert_line;
+ __le32 console_addr; /* Address of struct rte_console */
+ __le32 msgtrace_addr;
+ u8 tag[32];
+};
+
+
+/* misc chip info needed by some of the routines */
+struct chip_info {
+ u32 chip;
+ u32 chiprev;
+ u32 cccorebase;
+ u32 ccrev;
+ u32 cccaps;
+ u32 buscorebase; /* 32 bits backplane bus address */
+ u32 buscorerev;
+ u32 buscoretype;
+ u32 ramcorebase;
+ u32 armcorebase;
+ u32 pmurev;
+ u32 ramsize;
+};
+
+/* Private data for SDIO bus interaction */
+struct brcmf_bus {
+ struct brcmf_pub *drvr;
+
+ struct brcmf_sdio_dev *sdiodev; /* sdio device handler */
+ struct chip_info *ci; /* Chip info struct */
+ char *vars; /* Variables (from CIS and/or other) */
+ uint varsz; /* Size of variables buffer */
+
+ u32 ramsize; /* Size of RAM in SOCRAM (bytes) */
+
+ u32 hostintmask; /* Copy of Host Interrupt Mask */
+ u32 intstatus; /* Intstatus bits (events) pending */
+ bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */
+ bool fcstate; /* State of dongle flow-control */
+
+ uint blocksize; /* Block size of SDIO transfers */
+ uint roundup; /* Max roundup limit */
+
+ struct pktq txq; /* Queue length used for flow-control */
+ u8 flowcontrol; /* per prio flow control bitmask */
+ u8 tx_seq; /* Transmit sequence number (next) */
+ u8 tx_max; /* Maximum transmit sequence allowed */
+
+ u8 hdrbuf[MAX_HDR_READ + BRCMF_SDALIGN];
+ u8 *rxhdr; /* Header of current rx frame (in hdrbuf) */
+ u16 nextlen; /* Next Read Len from last header */
+ u8 rx_seq; /* Receive sequence number (expected) */
+ bool rxskip; /* Skip receive (awaiting NAK ACK) */
+
+ uint rxbound; /* Rx frames to read before resched */
+ uint txbound; /* Tx frames to send before resched */
+ uint txminmax;
+
+ struct sk_buff *glomd; /* Packet containing glomming descriptor */
+ struct sk_buff *glom; /* Packet chain for glommed superframe */
+ uint glomerr; /* Glom packet read errors */
+
+ u8 *rxbuf; /* Buffer for receiving control packets */
+ uint rxblen; /* Allocated length of rxbuf */
+ u8 *rxctl; /* Aligned pointer into rxbuf */
+ u8 *databuf; /* Buffer for receiving big glom packet */
+ u8 *dataptr; /* Aligned pointer into databuf */
+ uint rxlen; /* Length of valid data in buffer */
+
+ u8 sdpcm_ver; /* Bus protocol reported by dongle */
+
+ bool intr; /* Use interrupts */
+ bool poll; /* Use polling */
+ bool ipend; /* Device interrupt is pending */
+ uint intrcount; /* Count of device interrupt callbacks */
+ uint lastintrs; /* Count as of last watchdog timer */
+ uint spurious; /* Count of spurious interrupts */
+ uint pollrate; /* Ticks between device polls */
+ uint polltick; /* Tick counter */
+ uint pollcnt; /* Count of active polls */
+
+#ifdef BCMDBG
+ uint console_interval;
+ struct brcmf_console console; /* Console output polling support */
+ uint console_addr; /* Console address from shared struct */
+#endif /* BCMDBG */
+
+ uint regfails; /* Count of R_REG failures */
+
+ uint clkstate; /* State of sd and backplane clock(s) */
+ bool activity; /* Activity flag for clock down */
+ s32 idletime; /* Control for activity timeout */
+ s32 idlecount; /* Activity timeout counter */
+ s32 idleclock; /* How to set bus driver when idle */
+ s32 sd_rxchain;
+ bool use_rxchain; /* If brcmf should use PKT chains */
+ bool sleeping; /* Is SDIO bus sleeping? */
+ bool rxflow_mode; /* Rx flow control mode */
+ bool rxflow; /* Is rx flow control on */
+ bool alp_only; /* Don't use HT clock (ALP only) */
+/* Field to decide if rx of control frames happen in rxbuf or lb-pool */
+ bool usebufpool;
+
+ /* Some additional counters */
+ uint tx_sderrs; /* Count of tx attempts with sd errors */
+ uint fcqueued; /* Tx packets that got queued */
+ uint rxrtx; /* Count of rtx requests (NAK to dongle) */
+ uint rx_toolong; /* Receive frames too long to receive */
+ uint rxc_errors; /* SDIO errors when reading control frames */
+ uint rx_hdrfail; /* SDIO errors on header reads */
+ uint rx_badhdr; /* Bad received headers (roosync?) */
+ uint rx_badseq; /* Mismatched rx sequence number */
+ uint fc_rcvd; /* Number of flow-control events received */
+ uint fc_xoff; /* Number which turned on flow-control */
+ uint fc_xon; /* Number which turned off flow-control */
+ uint rxglomfail; /* Failed deglom attempts */
+ uint rxglomframes; /* Number of glom frames (superframes) */
+ uint rxglompkts; /* Number of packets from glom frames */
+ uint f2rxhdrs; /* Number of header reads */
+ uint f2rxdata; /* Number of frame data reads */
+ uint f2txdata; /* Number of f2 frame writes */
+ uint f1regdata; /* Number of f1 register accesses */
+
+ u8 *ctrl_frame_buf;
+ u32 ctrl_frame_len;
+ bool ctrl_frame_stat;
+
+ spinlock_t txqlock;
+ wait_queue_head_t ctrl_wait;
+ wait_queue_head_t dcmd_resp_wait;
+
+ struct timer_list timer;
+ struct completion watchdog_wait;
+ struct task_struct *watchdog_tsk;
+ bool wd_timer_valid;
+ uint save_ms;
+
+ struct task_struct *dpc_tsk;
+ struct completion dpc_wait;
+
+ struct semaphore sdsem;
+
+ const char *fw_name;
+ const struct firmware *firmware;
+ const char *nv_name;
+ u32 fw_ptr;
+};
+
+struct sbconfig {
+ u32 PAD[2];
+ u32 sbipsflag; /* initiator port ocp slave flag */
+ u32 PAD[3];
+ u32 sbtpsflag; /* target port ocp slave flag */
+ u32 PAD[11];
+ u32 sbtmerrloga; /* (sonics >= 2.3) */
+ u32 PAD;
+ u32 sbtmerrlog; /* (sonics >= 2.3) */
+ u32 PAD[3];
+ u32 sbadmatch3; /* address match3 */
+ u32 PAD;
+ u32 sbadmatch2; /* address match2 */
+ u32 PAD;
+ u32 sbadmatch1; /* address match1 */
+ u32 PAD[7];
+ u32 sbimstate; /* initiator agent state */
+ u32 sbintvec; /* interrupt mask */
+ u32 sbtmstatelow; /* target state */
+ u32 sbtmstatehigh; /* target state */
+ u32 sbbwa0; /* bandwidth allocation table0 */
+ u32 PAD;
+ u32 sbimconfiglow; /* initiator configuration */
+ u32 sbimconfighigh; /* initiator configuration */
+ u32 sbadmatch0; /* address match0 */
+ u32 PAD;
+ u32 sbtmconfiglow; /* target configuration */
+ u32 sbtmconfighigh; /* target configuration */
+ u32 sbbconfig; /* broadcast configuration */
+ u32 PAD;
+ u32 sbbstate; /* broadcast state */
+ u32 PAD[3];
+ u32 sbactcnfg; /* activate configuration */
+ u32 PAD[3];
+ u32 sbflagst; /* current sbflags */
+ u32 PAD[3];
+ u32 sbidlow; /* identification */
+ u32 sbidhigh; /* identification */
+};
+
+/* clkstate */
+#define CLK_NONE 0
+#define CLK_SDONLY 1
+#define CLK_PENDING 2 /* Not used yet */
+#define CLK_AVAIL 3
+
+#ifdef BCMDBG
+static int qcount[NUMPRIO];
+static int tx_packets[NUMPRIO];
+#endif /* BCMDBG */
+
+#define SDIO_DRIVE_STRENGTH 6 /* in milliamps */
+
+#define RETRYCHAN(chan) ((chan) == SDPCM_EVENT_CHANNEL)
+
+/* Retry count for register access failures */
+static const uint retry_limit = 2;
+
+/* Limit on rounding up frames */
+static const uint max_roundup = 512;
+
+#define ALIGNMENT 4
+
+static void pkt_align(struct sk_buff *p, int len, int align)
+{
+ uint datalign;
+ datalign = (unsigned long)(p->data);
+ datalign = roundup(datalign, (align)) - datalign;
+ if (datalign)
+ skb_pull(p, datalign);
+ __skb_trim(p, len);
+}
+
+/* To check if there's window offered */
+static bool data_ok(struct brcmf_bus *bus)
+{
+ return (u8)(bus->tx_max - bus->tx_seq) != 0 &&
+ ((u8)(bus->tx_max - bus->tx_seq) & 0x80) == 0;
+}
+
+/*
+ * Reads a register in the SDIO hardware block. This block occupies a series of
+ * adresses on the 32 bit backplane bus.
+ */
+static void
+r_sdreg32(struct brcmf_bus *bus, u32 *regvar, u32 reg_offset, u32 *retryvar)
+{
+ *retryvar = 0;
+ do {
+ *regvar = brcmf_sdcard_reg_read(bus->sdiodev,
+ bus->ci->buscorebase + reg_offset, sizeof(u32));
+ } while (brcmf_sdcard_regfail(bus->sdiodev) &&
+ (++(*retryvar) <= retry_limit));
+ if (*retryvar) {
+ bus->regfails += (*retryvar-1);
+ if (*retryvar > retry_limit) {
+ brcmf_dbg(ERROR, "FAILED READ %Xh\n", reg_offset);
+ *regvar = 0;
+ }
+ }
+}
+
+static void
+w_sdreg32(struct brcmf_bus *bus, u32 regval, u32 reg_offset, u32 *retryvar)
+{
+ *retryvar = 0;
+ do {
+ brcmf_sdcard_reg_write(bus->sdiodev,
+ bus->ci->buscorebase + reg_offset,
+ sizeof(u32), regval);
+ } while (brcmf_sdcard_regfail(bus->sdiodev) &&
+ (++(*retryvar) <= retry_limit));
+ if (*retryvar) {
+ bus->regfails += (*retryvar-1);
+ if (*retryvar > retry_limit)
+ brcmf_dbg(ERROR, "FAILED REGISTER WRITE %Xh\n",
+ reg_offset);
+ }
+}
+
+#define PKT_AVAILABLE() (intstatus & I_HMB_FRAME_IND)
+
+#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
+
+/* Packet free applicable unconditionally for sdio and sdspi.
+ * Conditional if bufpool was present for gspi bus.
+ */
+static void brcmf_sdbrcm_pktfree2(struct brcmf_bus *bus, struct sk_buff *pkt)
+{
+ if (bus->usebufpool)
+ brcmu_pkt_buf_free_skb(pkt);
+}
+
+/* Turn backplane clock on or off */
+static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok)
+{
+ int err;
+ u8 clkctl, clkreq, devctl;
+ unsigned long timeout;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ clkctl = 0;
+
+ if (on) {
+ /* Request HT Avail */
+ clkreq =
+ bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
+
+ if ((bus->ci->chip == BCM4329_CHIP_ID)
+ && (bus->ci->chiprev == 0))
+ clkreq |= SBSDIO_FORCE_ALP;
+
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
+ if (err) {
+ brcmf_dbg(ERROR, "HT Avail request error: %d\n", err);
+ return -EBADE;
+ }
+
+ if (pendok && ((bus->ci->buscoretype == PCMCIA_CORE_ID)
+ && (bus->ci->buscorerev == 9))) {
+ u32 dummy, retries;
+ r_sdreg32(bus, &dummy,
+ offsetof(struct sdpcmd_regs, clockctlstatus),
+ &retries);
+ }
+
+ /* Check current status */
+ clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, &err);
+ if (err) {
+ brcmf_dbg(ERROR, "HT Avail read error: %d\n", err);
+ return -EBADE;
+ }
+
+ /* Go to pending and await interrupt if appropriate */
+ if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
+ /* Allow only clock-available interrupt */
+ devctl = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
+ SBSDIO_DEVICE_CTL, &err);
+ if (err) {
+ brcmf_dbg(ERROR, "Devctl error setting CA: %d\n",
+ err);
+ return -EBADE;
+ }
+
+ devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_DEVICE_CTL, devctl, &err);
+ brcmf_dbg(INFO, "CLKCTL: set PENDING\n");
+ bus->clkstate = CLK_PENDING;
+
+ return 0;
+ } else if (bus->clkstate == CLK_PENDING) {
+ /* Cancel CA-only interrupt filter */
+ devctl =
+ brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_DEVICE_CTL, &err);
+ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_DEVICE_CTL, devctl, &err);
+ }
+
+ /* Otherwise, wait here (polling) for HT Avail */
+ timeout = jiffies +
+ msecs_to_jiffies(PMU_MAX_TRANSITION_DLY/1000);
+ while (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
+ clkctl = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR,
+ &err);
+ if (time_after(jiffies, timeout))
+ break;
+ else
+ usleep_range(5000, 10000);
+ }
+ if (err) {
+ brcmf_dbg(ERROR, "HT Avail request error: %d\n", err);
+ return -EBADE;
+ }
+ if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
+ brcmf_dbg(ERROR, "HT Avail timeout (%d): clkctl 0x%02x\n",
+ PMU_MAX_TRANSITION_DLY, clkctl);
+ return -EBADE;
+ }
+
+ /* Mark clock available */
+ bus->clkstate = CLK_AVAIL;
+ brcmf_dbg(INFO, "CLKCTL: turned ON\n");
+
+#if defined(BCMDBG)
+ if (bus->alp_only != true) {
+ if (SBSDIO_ALPONLY(clkctl))
+ brcmf_dbg(ERROR, "HT Clock should be on\n");
+ }
+#endif /* defined (BCMDBG) */
+
+ bus->activity = true;
+ } else {
+ clkreq = 0;
+
+ if (bus->clkstate == CLK_PENDING) {
+ /* Cancel CA-only interrupt filter */
+ devctl = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
+ SBSDIO_DEVICE_CTL, &err);
+ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_DEVICE_CTL, devctl, &err);
+ }
+
+ bus->clkstate = CLK_SDONLY;
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
+ brcmf_dbg(INFO, "CLKCTL: turned OFF\n");
+ if (err) {
+ brcmf_dbg(ERROR, "Failed access turning clock off: %d\n",
+ err);
+ return -EBADE;
+ }
+ }
+ return 0;
+}
+
+/* Change idle/active SD state */
+static int brcmf_sdbrcm_sdclk(struct brcmf_bus *bus, bool on)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (on)
+ bus->clkstate = CLK_SDONLY;
+ else
+ bus->clkstate = CLK_NONE;
+
+ return 0;
+}
+
+/* Transition SD and backplane clock readiness */
+static int brcmf_sdbrcm_clkctl(struct brcmf_bus *bus, uint target, bool pendok)
+{
+#ifdef BCMDBG
+ uint oldstate = bus->clkstate;
+#endif /* BCMDBG */
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Early exit if we're already there */
+ if (bus->clkstate == target) {
+ if (target == CLK_AVAIL) {
+ brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
+ bus->activity = true;
+ }
+ return 0;
+ }
+
+ switch (target) {
+ case CLK_AVAIL:
+ /* Make sure SD clock is available */
+ if (bus->clkstate == CLK_NONE)
+ brcmf_sdbrcm_sdclk(bus, true);
+ /* Now request HT Avail on the backplane */
+ brcmf_sdbrcm_htclk(bus, true, pendok);
+ brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
+ bus->activity = true;
+ break;
+
+ case CLK_SDONLY:
+ /* Remove HT request, or bring up SD clock */
+ if (bus->clkstate == CLK_NONE)
+ brcmf_sdbrcm_sdclk(bus, true);
+ else if (bus->clkstate == CLK_AVAIL)
+ brcmf_sdbrcm_htclk(bus, false, false);
+ else
+ brcmf_dbg(ERROR, "request for %d -> %d\n",
+ bus->clkstate, target);
+ brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
+ break;
+
+ case CLK_NONE:
+ /* Make sure to remove HT request */
+ if (bus->clkstate == CLK_AVAIL)
+ brcmf_sdbrcm_htclk(bus, false, false);
+ /* Now remove the SD clock */
+ brcmf_sdbrcm_sdclk(bus, false);
+ brcmf_sdbrcm_wd_timer(bus, 0);
+ break;
+ }
+#ifdef BCMDBG
+ brcmf_dbg(INFO, "%d -> %d\n", oldstate, bus->clkstate);
+#endif /* BCMDBG */
+
+ return 0;
+}
+
+static int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep)
+{
+ uint retries = 0;
+
+ brcmf_dbg(INFO, "request %s (currently %s)\n",
+ sleep ? "SLEEP" : "WAKE",
+ bus->sleeping ? "SLEEP" : "WAKE");
+
+ /* Done if we're already in the requested state */
+ if (sleep == bus->sleeping)
+ return 0;
+
+ /* Going to sleep: set the alarm and turn off the lights... */
+ if (sleep) {
+ /* Don't sleep if something is pending */
+ if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
+ return -EBUSY;
+
+ /* Make sure the controller has the bus up */
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+
+ /* Tell device to start using OOB wakeup */
+ w_sdreg32(bus, SMB_USE_OOB,
+ offsetof(struct sdpcmd_regs, tosbmailbox), &retries);
+ if (retries > retry_limit)
+ brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n");
+
+ /* Turn off our contribution to the HT clock request */
+ brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
+
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR,
+ SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
+
+ /* Isolate the bus */
+ if (bus->ci->chip != BCM4329_CHIP_ID) {
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_DEVICE_CTL,
+ SBSDIO_DEVCTL_PADS_ISO, NULL);
+ }
+
+ /* Change state */
+ bus->sleeping = true;
+
+ } else {
+ /* Waking up: bus power up is ok, set local state */
+
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
+
+ /* Force pad isolation off if possible
+ (in case power never toggled) */
+ if ((bus->ci->buscoretype == PCMCIA_CORE_ID)
+ && (bus->ci->buscorerev >= 10))
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_DEVICE_CTL, 0, NULL);
+
+ /* Make sure the controller has the bus up */
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+
+ /* Send misc interrupt to indicate OOB not needed */
+ w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, tosbmailboxdata),
+ &retries);
+ if (retries <= retry_limit)
+ w_sdreg32(bus, SMB_DEV_INT,
+ offsetof(struct sdpcmd_regs, tosbmailbox),
+ &retries);
+
+ if (retries > retry_limit)
+ brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP TO CLEAR OOB!!\n");
+
+ /* Make sure we have SD bus access */
+ brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
+
+ /* Change state */
+ bus->sleeping = false;
+ }
+
+ return 0;
+}
+
+static void bus_wake(struct brcmf_bus *bus)
+{
+ if (bus->sleeping)
+ brcmf_sdbrcm_bussleep(bus, false);
+}
+
+static u32 brcmf_sdbrcm_hostmail(struct brcmf_bus *bus)
+{
+ u32 intstatus = 0;
+ u32 hmb_data;
+ u8 fcbits;
+ uint retries = 0;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Read mailbox data and ack that we did so */
+ r_sdreg32(bus, &hmb_data,
+ offsetof(struct sdpcmd_regs, tohostmailboxdata), &retries);
+
+ if (retries <= retry_limit)
+ w_sdreg32(bus, SMB_INT_ACK,
+ offsetof(struct sdpcmd_regs, tosbmailbox), &retries);
+ bus->f1regdata += 2;
+
+ /* Dongle recomposed rx frames, accept them again */
+ if (hmb_data & HMB_DATA_NAKHANDLED) {
+ brcmf_dbg(INFO, "Dongle reports NAK handled, expect rtx of %d\n",
+ bus->rx_seq);
+ if (!bus->rxskip)
+ brcmf_dbg(ERROR, "unexpected NAKHANDLED!\n");
+
+ bus->rxskip = false;
+ intstatus |= I_HMB_FRAME_IND;
+ }
+
+ /*
+ * DEVREADY does not occur with gSPI.
+ */
+ if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
+ bus->sdpcm_ver =
+ (hmb_data & HMB_DATA_VERSION_MASK) >>
+ HMB_DATA_VERSION_SHIFT;
+ if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
+ brcmf_dbg(ERROR, "Version mismatch, dongle reports %d, "
+ "expecting %d\n",
+ bus->sdpcm_ver, SDPCM_PROT_VERSION);
+ else
+ brcmf_dbg(INFO, "Dongle ready, protocol version %d\n",
+ bus->sdpcm_ver);
+ }
+
+ /*
+ * Flow Control has been moved into the RX headers and this out of band
+ * method isn't used any more.
+ * remaining backward compatible with older dongles.
+ */
+ if (hmb_data & HMB_DATA_FC) {
+ fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >>
+ HMB_DATA_FCDATA_SHIFT;
+
+ if (fcbits & ~bus->flowcontrol)
+ bus->fc_xoff++;
+
+ if (bus->flowcontrol & ~fcbits)
+ bus->fc_xon++;
+
+ bus->fc_rcvd++;
+ bus->flowcontrol = fcbits;
+ }
+
+ /* Shouldn't be any others */
+ if (hmb_data & ~(HMB_DATA_DEVREADY |
+ HMB_DATA_NAKHANDLED |
+ HMB_DATA_FC |
+ HMB_DATA_FWREADY |
+ HMB_DATA_FCDATA_MASK | HMB_DATA_VERSION_MASK))
+ brcmf_dbg(ERROR, "Unknown mailbox data content: 0x%02x\n",
+ hmb_data);
+
+ return intstatus;
+}
+
+static void brcmf_sdbrcm_rxfail(struct brcmf_bus *bus, bool abort, bool rtx)
+{
+ uint retries = 0;
+ u16 lastrbc;
+ u8 hi, lo;
+ int err;
+
+ brcmf_dbg(ERROR, "%sterminate frame%s\n",
+ abort ? "abort command, " : "",
+ rtx ? ", send NAK" : "");
+
+ if (abort)
+ brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
+
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_FRAMECTRL,
+ SFC_RF_TERM, &err);
+ bus->f1regdata++;
+
+ /* Wait until the packet has been flushed (device/FIFO stable) */
+ for (lastrbc = retries = 0xffff; retries > 0; retries--) {
+ hi = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_RFRAMEBCHI, NULL);
+ lo = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_RFRAMEBCLO, NULL);
+ bus->f1regdata += 2;
+
+ if ((hi == 0) && (lo == 0))
+ break;
+
+ if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
+ brcmf_dbg(ERROR, "count growing: last 0x%04x now 0x%04x\n",
+ lastrbc, (hi << 8) + lo);
+ }
+ lastrbc = (hi << 8) + lo;
+ }
+
+ if (!retries)
+ brcmf_dbg(ERROR, "count never zeroed: last 0x%04x\n", lastrbc);
+ else
+ brcmf_dbg(INFO, "flush took %d iterations\n", 0xffff - retries);
+
+ if (rtx) {
+ bus->rxrtx++;
+ w_sdreg32(bus, SMB_NAK,
+ offsetof(struct sdpcmd_regs, tosbmailbox), &retries);
+
+ bus->f1regdata++;
+ if (retries <= retry_limit)
+ bus->rxskip = true;
+ }
+
+ /* Clear partial in any case */
+ bus->nextlen = 0;
+
+ /* If we can't reach the device, signal failure */
+ if (err || brcmf_sdcard_regfail(bus->sdiodev))
+ bus->drvr->busstate = BRCMF_BUS_DOWN;
+}
+
+static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
+{
+ u16 dlen, totlen;
+ u8 *dptr, num = 0;
+
+ u16 sublen, check;
+ struct sk_buff *pfirst, *plast, *pnext, *save_pfirst;
+
+ int errcode;
+ u8 chan, seq, doff, sfdoff;
+ u8 txmax;
+
+ int ifidx = 0;
+ bool usechain = bus->use_rxchain;
+
+ /* If packets, issue read(s) and send up packet chain */
+ /* Return sequence numbers consumed? */
+
+ brcmf_dbg(TRACE, "start: glomd %p glom %p\n", bus->glomd, bus->glom);
+
+ /* If there's a descriptor, generate the packet chain */
+ if (bus->glomd) {
+ pfirst = plast = pnext = NULL;
+ dlen = (u16) (bus->glomd->len);
+ dptr = bus->glomd->data;
+ if (!dlen || (dlen & 1)) {
+ brcmf_dbg(ERROR, "bad glomd len(%d), ignore descriptor\n",
+ dlen);
+ dlen = 0;
+ }
+
+ for (totlen = num = 0; dlen; num++) {
+ /* Get (and move past) next length */
+ sublen = get_unaligned_le16(dptr);
+ dlen -= sizeof(u16);
+ dptr += sizeof(u16);
+ if ((sublen < SDPCM_HDRLEN) ||
+ ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
+ brcmf_dbg(ERROR, "descriptor len %d bad: %d\n",
+ num, sublen);
+ pnext = NULL;
+ break;
+ }
+ if (sublen % BRCMF_SDALIGN) {
+ brcmf_dbg(ERROR, "sublen %d not multiple of %d\n",
+ sublen, BRCMF_SDALIGN);
+ usechain = false;
+ }
+ totlen += sublen;
+
+ /* For last frame, adjust read len so total
+ is a block multiple */
+ if (!dlen) {
+ sublen +=
+ (roundup(totlen, bus->blocksize) - totlen);
+ totlen = roundup(totlen, bus->blocksize);
+ }
+
+ /* Allocate/chain packet for next subframe */
+ pnext = brcmu_pkt_buf_get_skb(sublen + BRCMF_SDALIGN);
+ if (pnext == NULL) {
+ brcmf_dbg(ERROR, "bcm_pkt_buf_get_skb failed, num %d len %d\n",
+ num, sublen);
+ break;
+ }
+ if (!pfirst) {
+ pfirst = plast = pnext;
+ } else {
+ plast->next = pnext;
+ plast = pnext;
+ }
+
+ /* Adhere to start alignment requirements */
+ pkt_align(pnext, sublen, BRCMF_SDALIGN);
+ }
+
+ /* If all allocations succeeded, save packet chain
+ in bus structure */
+ if (pnext) {
+ brcmf_dbg(GLOM, "allocated %d-byte packet chain for %d subframes\n",
+ totlen, num);
+ if (BRCMF_GLOM_ON() && bus->nextlen &&
+ totlen != bus->nextlen) {
+ brcmf_dbg(GLOM, "glomdesc mismatch: nextlen %d glomdesc %d rxseq %d\n",
+ bus->nextlen, totlen, rxseq);
+ }
+ bus->glom = pfirst;
+ pfirst = pnext = NULL;
+ } else {
+ if (pfirst)
+ brcmu_pkt_buf_free_skb(pfirst);
+ bus->glom = NULL;
+ num = 0;
+ }
+
+ /* Done with descriptor packet */
+ brcmu_pkt_buf_free_skb(bus->glomd);
+ bus->glomd = NULL;
+ bus->nextlen = 0;
+ }
+
+ /* Ok -- either we just generated a packet chain,
+ or had one from before */
+ if (bus->glom) {
+ if (BRCMF_GLOM_ON()) {
+ brcmf_dbg(GLOM, "try superframe read, packet chain:\n");
+ for (pnext = bus->glom; pnext; pnext = pnext->next) {
+ brcmf_dbg(GLOM, " %p: %p len 0x%04x (%d)\n",
+ pnext, (u8 *) (pnext->data),
+ pnext->len, pnext->len);
+ }
+ }
+
+ pfirst = bus->glom;
+ dlen = (u16) brcmu_pkttotlen(pfirst);
+
+ /* Do an SDIO read for the superframe. Configurable iovar to
+ * read directly into the chained packet, or allocate a large
+ * packet and and copy into the chain.
+ */
+ if (usechain) {
+ errcode = brcmf_sdcard_recv_buf(bus->sdiodev,
+ bus->sdiodev->sbwad,
+ SDIO_FUNC_2,
+ F2SYNC, (u8 *) pfirst->data, dlen,
+ pfirst);
+ } else if (bus->dataptr) {
+ errcode = brcmf_sdcard_recv_buf(bus->sdiodev,
+ bus->sdiodev->sbwad,
+ SDIO_FUNC_2,
+ F2SYNC, bus->dataptr, dlen,
+ NULL);
+ sublen = (u16) brcmu_pktfrombuf(pfirst, 0, dlen,
+ bus->dataptr);
+ if (sublen != dlen) {
+ brcmf_dbg(ERROR, "FAILED TO COPY, dlen %d sublen %d\n",
+ dlen, sublen);
+ errcode = -1;
+ }
+ pnext = NULL;
+ } else {
+ brcmf_dbg(ERROR, "COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n",
+ dlen);
+ errcode = -1;
+ }
+ bus->f2rxdata++;
+
+ /* On failure, kill the superframe, allow a couple retries */
+ if (errcode < 0) {
+ brcmf_dbg(ERROR, "glom read of %d bytes failed: %d\n",
+ dlen, errcode);
+ bus->drvr->rx_errors++;
+
+ if (bus->glomerr++ < 3) {
+ brcmf_sdbrcm_rxfail(bus, true, true);
+ } else {
+ bus->glomerr = 0;
+ brcmf_sdbrcm_rxfail(bus, true, false);
+ brcmu_pkt_buf_free_skb(bus->glom);
+ bus->rxglomfail++;
+ bus->glom = NULL;
+ }
+ return 0;
+ }
+#ifdef BCMDBG
+ if (BRCMF_GLOM_ON()) {
+ printk(KERN_DEBUG "SUPERFRAME:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ pfirst->data, min_t(int, pfirst->len, 48));
+ }
+#endif
+
+ /* Validate the superframe header */
+ dptr = (u8 *) (pfirst->data);
+ sublen = get_unaligned_le16(dptr);
+ check = get_unaligned_le16(dptr + sizeof(u16));
+
+ chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
+ seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
+ bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
+ if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
+ brcmf_dbg(INFO, "nextlen too large (%d) seq %d\n",
+ bus->nextlen, seq);
+ bus->nextlen = 0;
+ }
+ doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
+ txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
+
+ errcode = 0;
+ if ((u16)~(sublen ^ check)) {
+ brcmf_dbg(ERROR, "(superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
+ sublen, check);
+ errcode = -1;
+ } else if (roundup(sublen, bus->blocksize) != dlen) {
+ brcmf_dbg(ERROR, "(superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
+ sublen, roundup(sublen, bus->blocksize),
+ dlen);
+ errcode = -1;
+ } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) !=
+ SDPCM_GLOM_CHANNEL) {
+ brcmf_dbg(ERROR, "(superframe): bad channel %d\n",
+ SDPCM_PACKET_CHANNEL(
+ &dptr[SDPCM_FRAMETAG_LEN]));
+ errcode = -1;
+ } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
+ brcmf_dbg(ERROR, "(superframe): got 2nd descriptor?\n");
+ errcode = -1;
+ } else if ((doff < SDPCM_HDRLEN) ||
+ (doff > (pfirst->len - SDPCM_HDRLEN))) {
+ brcmf_dbg(ERROR, "(superframe): Bad data offset %d: HW %d pkt %d min %d\n",
+ doff, sublen, pfirst->len, SDPCM_HDRLEN);
+ errcode = -1;
+ }
+
+ /* Check sequence number of superframe SW header */
+ if (rxseq != seq) {
+ brcmf_dbg(INFO, "(superframe) rx_seq %d, expected %d\n",
+ seq, rxseq);
+ bus->rx_badseq++;
+ rxseq = seq;
+ }
+
+ /* Check window for sanity */
+ if ((u8) (txmax - bus->tx_seq) > 0x40) {
+ brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n",
+ txmax, bus->tx_seq);
+ txmax = bus->tx_seq + 2;
+ }
+ bus->tx_max = txmax;
+
+ /* Remove superframe header, remember offset */
+ skb_pull(pfirst, doff);
+ sfdoff = doff;
+
+ /* Validate all the subframe headers */
+ for (num = 0, pnext = pfirst; pnext && !errcode;
+ num++, pnext = pnext->next) {
+ dptr = (u8 *) (pnext->data);
+ dlen = (u16) (pnext->len);
+ sublen = get_unaligned_le16(dptr);
+ check = get_unaligned_le16(dptr + sizeof(u16));
+ chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
+ doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
+#ifdef BCMDBG
+ if (BRCMF_GLOM_ON()) {
+ printk(KERN_DEBUG "subframe:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ dptr, 32);
+ }
+#endif
+
+ if ((u16)~(sublen ^ check)) {
+ brcmf_dbg(ERROR, "(subframe %d): HW hdr error: len/check 0x%04x/0x%04x\n",
+ num, sublen, check);
+ errcode = -1;
+ } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
+ brcmf_dbg(ERROR, "(subframe %d): length mismatch: len 0x%04x, expect 0x%04x\n",
+ num, sublen, dlen);
+ errcode = -1;
+ } else if ((chan != SDPCM_DATA_CHANNEL) &&
+ (chan != SDPCM_EVENT_CHANNEL)) {
+ brcmf_dbg(ERROR, "(subframe %d): bad channel %d\n",
+ num, chan);
+ errcode = -1;
+ } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
+ brcmf_dbg(ERROR, "(subframe %d): Bad data offset %d: HW %d min %d\n",
+ num, doff, sublen, SDPCM_HDRLEN);
+ errcode = -1;
+ }
+ }
+
+ if (errcode) {
+ /* Terminate frame on error, request
+ a couple retries */
+ if (bus->glomerr++ < 3) {
+ /* Restore superframe header space */
+ skb_push(pfirst, sfdoff);
+ brcmf_sdbrcm_rxfail(bus, true, true);
+ } else {
+ bus->glomerr = 0;
+ brcmf_sdbrcm_rxfail(bus, true, false);
+ brcmu_pkt_buf_free_skb(bus->glom);
+ bus->rxglomfail++;
+ bus->glom = NULL;
+ }
+ bus->nextlen = 0;
+ return 0;
+ }
+
+ /* Basic SD framing looks ok - process each packet (header) */
+ save_pfirst = pfirst;
+ bus->glom = NULL;
+ plast = NULL;
+
+ for (num = 0; pfirst; rxseq++, pfirst = pnext) {
+ pnext = pfirst->next;
+ pfirst->next = NULL;
+
+ dptr = (u8 *) (pfirst->data);
+ sublen = get_unaligned_le16(dptr);
+ chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
+ seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
+ doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
+
+ brcmf_dbg(GLOM, "Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
+ num, pfirst, pfirst->data,
+ pfirst->len, sublen, chan, seq);
+
+ /* precondition: chan == SDPCM_DATA_CHANNEL ||
+ chan == SDPCM_EVENT_CHANNEL */
+
+ if (rxseq != seq) {
+ brcmf_dbg(GLOM, "rx_seq %d, expected %d\n",
+ seq, rxseq);
+ bus->rx_badseq++;
+ rxseq = seq;
+ }
+#ifdef BCMDBG
+ if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) {
+ printk(KERN_DEBUG "Rx Subframe Data:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ dptr, dlen);
+ }
+#endif
+
+ __skb_trim(pfirst, sublen);
+ skb_pull(pfirst, doff);
+
+ if (pfirst->len == 0) {
+ brcmu_pkt_buf_free_skb(pfirst);
+ if (plast)
+ plast->next = pnext;
+ else
+ save_pfirst = pnext;
+
+ continue;
+ } else if (brcmf_proto_hdrpull(bus->drvr, &ifidx,
+ pfirst) != 0) {
+ brcmf_dbg(ERROR, "rx protocol error\n");
+ bus->drvr->rx_errors++;
+ brcmu_pkt_buf_free_skb(pfirst);
+ if (plast)
+ plast->next = pnext;
+ else
+ save_pfirst = pnext;
+
+ continue;
+ }
+
+ /* this packet will go up, link back into
+ chain and count it */
+ pfirst->next = pnext;
+ plast = pfirst;
+ num++;
+
+#ifdef BCMDBG
+ if (BRCMF_GLOM_ON()) {
+ brcmf_dbg(GLOM, "subframe %d to stack, %p (%p/%d) nxt/lnk %p/%p\n",
+ num, pfirst, pfirst->data,
+ pfirst->len, pfirst->next,
+ pfirst->prev);
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ pfirst->data,
+ min_t(int, pfirst->len, 32));
+ }
+#endif /* BCMDBG */
+ }
+ if (num) {
+ up(&bus->sdsem);
+ brcmf_rx_frame(bus->drvr, ifidx, save_pfirst, num);
+ down(&bus->sdsem);
+ }
+
+ bus->rxglomframes++;
+ bus->rxglompkts += num;
+ }
+ return num;
+}
+
+static int brcmf_sdbrcm_dcmd_resp_wait(struct brcmf_bus *bus, uint *condition,
+ bool *pending)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ int timeout = msecs_to_jiffies(DCMD_RESP_TIMEOUT);
+
+ /* Wait until control frame is available */
+ add_wait_queue(&bus->dcmd_resp_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ while (!(*condition) && (!signal_pending(current) && timeout))
+ timeout = schedule_timeout(timeout);
+
+ if (signal_pending(current))
+ *pending = true;
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&bus->dcmd_resp_wait, &wait);
+
+ return timeout;
+}
+
+static int brcmf_sdbrcm_dcmd_resp_wake(struct brcmf_bus *bus)
+{
+ if (waitqueue_active(&bus->dcmd_resp_wait))
+ wake_up_interruptible(&bus->dcmd_resp_wait);
+
+ return 0;
+}
+static void
+brcmf_sdbrcm_read_control(struct brcmf_bus *bus, u8 *hdr, uint len, uint doff)
+{
+ uint rdlen, pad;
+
+ int sdret;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Set rxctl for frame (w/optional alignment) */
+ bus->rxctl = bus->rxbuf;
+ bus->rxctl += BRCMF_FIRSTREAD;
+ pad = ((unsigned long)bus->rxctl % BRCMF_SDALIGN);
+ if (pad)
+ bus->rxctl += (BRCMF_SDALIGN - pad);
+ bus->rxctl -= BRCMF_FIRSTREAD;
+
+ /* Copy the already-read portion over */
+ memcpy(bus->rxctl, hdr, BRCMF_FIRSTREAD);
+ if (len <= BRCMF_FIRSTREAD)
+ goto gotpkt;
+
+ /* Raise rdlen to next SDIO block to avoid tail command */
+ rdlen = len - BRCMF_FIRSTREAD;
+ if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
+ pad = bus->blocksize - (rdlen % bus->blocksize);
+ if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
+ ((len + pad) < bus->drvr->maxctl))
+ rdlen += pad;
+ } else if (rdlen % BRCMF_SDALIGN) {
+ rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN);
+ }
+
+ /* Satisfy length-alignment requirements */
+ if (rdlen & (ALIGNMENT - 1))
+ rdlen = roundup(rdlen, ALIGNMENT);
+
+ /* Drop if the read is too big or it exceeds our maximum */
+ if ((rdlen + BRCMF_FIRSTREAD) > bus->drvr->maxctl) {
+ brcmf_dbg(ERROR, "%d-byte control read exceeds %d-byte buffer\n",
+ rdlen, bus->drvr->maxctl);
+ bus->drvr->rx_errors++;
+ brcmf_sdbrcm_rxfail(bus, false, false);
+ goto done;
+ }
+
+ if ((len - doff) > bus->drvr->maxctl) {
+ brcmf_dbg(ERROR, "%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
+ len, len - doff, bus->drvr->maxctl);
+ bus->drvr->rx_errors++;
+ bus->rx_toolong++;
+ brcmf_sdbrcm_rxfail(bus, false, false);
+ goto done;
+ }
+
+ /* Read remainder of frame body into the rxctl buffer */
+ sdret = brcmf_sdcard_recv_buf(bus->sdiodev,
+ bus->sdiodev->sbwad,
+ SDIO_FUNC_2,
+ F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen,
+ NULL);
+ bus->f2rxdata++;
+
+ /* Control frame failures need retransmission */
+ if (sdret < 0) {
+ brcmf_dbg(ERROR, "read %d control bytes failed: %d\n",
+ rdlen, sdret);
+ bus->rxc_errors++;
+ brcmf_sdbrcm_rxfail(bus, true, true);
+ goto done;
+ }
+
+gotpkt:
+
+#ifdef BCMDBG
+ if (BRCMF_BYTES_ON() && BRCMF_CTL_ON()) {
+ printk(KERN_DEBUG "RxCtrl:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, bus->rxctl, len);
+ }
+#endif
+
+ /* Point to valid data and indicate its length */
+ bus->rxctl += doff;
+ bus->rxlen = len - doff;
+
+done:
+ /* Awake any waiters */
+ brcmf_sdbrcm_dcmd_resp_wake(bus);
+}
+
+/* Pad read to blocksize for efficiency */
+static void brcmf_pad(struct brcmf_bus *bus, u16 *pad, u16 *rdlen)
+{
+ if (bus->roundup && bus->blocksize && *rdlen > bus->blocksize) {
+ *pad = bus->blocksize - (*rdlen % bus->blocksize);
+ if (*pad <= bus->roundup && *pad < bus->blocksize &&
+ *rdlen + *pad + BRCMF_FIRSTREAD < MAX_RX_DATASZ)
+ *rdlen += *pad;
+ } else if (*rdlen % BRCMF_SDALIGN) {
+ *rdlen += BRCMF_SDALIGN - (*rdlen % BRCMF_SDALIGN);
+ }
+}
+
+static void
+brcmf_alloc_pkt_and_read(struct brcmf_bus *bus, u16 rdlen,
+ struct sk_buff **pkt, u8 **rxbuf)
+{
+ int sdret; /* Return code from calls */
+
+ *pkt = brcmu_pkt_buf_get_skb(rdlen + BRCMF_SDALIGN);
+ if (*pkt == NULL)
+ return;
+
+ pkt_align(*pkt, rdlen, BRCMF_SDALIGN);
+ *rxbuf = (u8 *) ((*pkt)->data);
+ /* Read the entire frame */
+ sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad,
+ SDIO_FUNC_2, F2SYNC,
+ *rxbuf, rdlen, *pkt);
+ bus->f2rxdata++;
+
+ if (sdret < 0) {
+ brcmf_dbg(ERROR, "(nextlen): read %d bytes failed: %d\n",
+ rdlen, sdret);
+ brcmu_pkt_buf_free_skb(*pkt);
+ bus->drvr->rx_errors++;
+ /* Force retry w/normal header read.
+ * Don't attempt NAK for
+ * gSPI
+ */
+ brcmf_sdbrcm_rxfail(bus, true, true);
+ *pkt = NULL;
+ }
+}
+
+/* Checks the header */
+static int
+brcmf_check_rxbuf(struct brcmf_bus *bus, struct sk_buff *pkt, u8 *rxbuf,
+ u8 rxseq, u16 nextlen, u16 *len)
+{
+ u16 check;
+ bool len_consistent; /* Result of comparing readahead len and
+ len from hw-hdr */
+
+ memcpy(bus->rxhdr, rxbuf, SDPCM_HDRLEN);
+
+ /* Extract hardware header fields */
+ *len = get_unaligned_le16(bus->rxhdr);
+ check = get_unaligned_le16(bus->rxhdr + sizeof(u16));
+
+ /* All zeros means readahead info was bad */
+ if (!(*len | check)) {
+ brcmf_dbg(INFO, "(nextlen): read zeros in HW header???\n");
+ goto fail;
+ }
+
+ /* Validate check bytes */
+ if ((u16)~(*len ^ check)) {
+ brcmf_dbg(ERROR, "(nextlen): HW hdr error: nextlen/len/check 0x%04x/0x%04x/0x%04x\n",
+ nextlen, *len, check);
+ bus->rx_badhdr++;
+ brcmf_sdbrcm_rxfail(bus, false, false);
+ goto fail;
+ }
+
+ /* Validate frame length */
+ if (*len < SDPCM_HDRLEN) {
+ brcmf_dbg(ERROR, "(nextlen): HW hdr length invalid: %d\n",
+ *len);
+ goto fail;
+ }
+
+ /* Check for consistency with readahead info */
+ len_consistent = (nextlen != (roundup(*len, 16) >> 4));
+ if (len_consistent) {
+ /* Mismatch, force retry w/normal
+ header (may be >4K) */
+ brcmf_dbg(ERROR, "(nextlen): mismatch, nextlen %d len %d rnd %d; expected rxseq %d\n",
+ nextlen, *len, roundup(*len, 16),
+ rxseq);
+ brcmf_sdbrcm_rxfail(bus, true, true);
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ brcmf_sdbrcm_pktfree2(bus, pkt);
+ return -EINVAL;
+}
+
+/* Return true if there may be more frames to read */
+static uint
+brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
+{
+ u16 len, check; /* Extracted hardware header fields */
+ u8 chan, seq, doff; /* Extracted software header fields */
+ u8 fcbits; /* Extracted fcbits from software header */
+
+ struct sk_buff *pkt; /* Packet for event or data frames */
+ u16 pad; /* Number of pad bytes to read */
+ u16 rdlen; /* Total number of bytes to read */
+ u8 rxseq; /* Next sequence number to expect */
+ uint rxleft = 0; /* Remaining number of frames allowed */
+ int sdret; /* Return code from calls */
+ u8 txmax; /* Maximum tx sequence offered */
+ u8 *rxbuf;
+ int ifidx = 0;
+ uint rxcount = 0; /* Total frames read */
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Not finished unless we encounter no more frames indication */
+ *finished = false;
+
+ for (rxseq = bus->rx_seq, rxleft = maxframes;
+ !bus->rxskip && rxleft && bus->drvr->busstate != BRCMF_BUS_DOWN;
+ rxseq++, rxleft--) {
+
+ /* Handle glomming separately */
+ if (bus->glom || bus->glomd) {
+ u8 cnt;
+ brcmf_dbg(GLOM, "calling rxglom: glomd %p, glom %p\n",
+ bus->glomd, bus->glom);
+ cnt = brcmf_sdbrcm_rxglom(bus, rxseq);
+ brcmf_dbg(GLOM, "rxglom returned %d\n", cnt);
+ rxseq += cnt - 1;
+ rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
+ continue;
+ }
+
+ /* Try doing single read if we can */
+ if (bus->nextlen) {
+ u16 nextlen = bus->nextlen;
+ bus->nextlen = 0;
+
+ rdlen = len = nextlen << 4;
+ brcmf_pad(bus, &pad, &rdlen);
+
+ /*
+ * After the frame is received we have to
+ * distinguish whether it is data
+ * or non-data frame.
+ */
+ brcmf_alloc_pkt_and_read(bus, rdlen, &pkt, &rxbuf);
+ if (pkt == NULL) {
+ /* Give up on data, request rtx of events */
+ brcmf_dbg(ERROR, "(nextlen): brcmf_alloc_pkt_and_read failed: len %d rdlen %d expected rxseq %d\n",
+ len, rdlen, rxseq);
+ continue;
+ }
+
+ if (brcmf_check_rxbuf(bus, pkt, rxbuf, rxseq, nextlen,
+ &len) < 0)
+ continue;
+
+ /* Extract software header fields */
+ chan = SDPCM_PACKET_CHANNEL(
+ &bus->rxhdr[SDPCM_FRAMETAG_LEN]);
+ seq = SDPCM_PACKET_SEQUENCE(
+ &bus->rxhdr[SDPCM_FRAMETAG_LEN]);
+ doff = SDPCM_DOFFSET_VALUE(
+ &bus->rxhdr[SDPCM_FRAMETAG_LEN]);
+ txmax = SDPCM_WINDOW_VALUE(
+ &bus->rxhdr[SDPCM_FRAMETAG_LEN]);
+
+ bus->nextlen =
+ bus->rxhdr[SDPCM_FRAMETAG_LEN +
+ SDPCM_NEXTLEN_OFFSET];
+ if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
+ brcmf_dbg(INFO, "(nextlen): got frame w/nextlen too large (%d), seq %d\n",
+ bus->nextlen, seq);
+ bus->nextlen = 0;
+ }
+
+ bus->drvr->rx_readahead_cnt++;
+
+ /* Handle Flow Control */
+ fcbits = SDPCM_FCMASK_VALUE(
+ &bus->rxhdr[SDPCM_FRAMETAG_LEN]);
+
+ if (bus->flowcontrol != fcbits) {
+ if (~bus->flowcontrol & fcbits)
+ bus->fc_xoff++;
+
+ if (bus->flowcontrol & ~fcbits)
+ bus->fc_xon++;
+
+ bus->fc_rcvd++;
+ bus->flowcontrol = fcbits;
+ }
+
+ /* Check and update sequence number */
+ if (rxseq != seq) {
+ brcmf_dbg(INFO, "(nextlen): rx_seq %d, expected %d\n",
+ seq, rxseq);
+ bus->rx_badseq++;
+ rxseq = seq;
+ }
+
+ /* Check window for sanity */
+ if ((u8) (txmax - bus->tx_seq) > 0x40) {
+ brcmf_dbg(ERROR, "got unlikely tx max %d with tx_seq %d\n",
+ txmax, bus->tx_seq);
+ txmax = bus->tx_seq + 2;
+ }
+ bus->tx_max = txmax;
+
+#ifdef BCMDBG
+ if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) {
+ printk(KERN_DEBUG "Rx Data:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ rxbuf, len);
+ } else if (BRCMF_HDRS_ON()) {
+ printk(KERN_DEBUG "RxHdr:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ bus->rxhdr, SDPCM_HDRLEN);
+ }
+#endif
+
+ if (chan == SDPCM_CONTROL_CHANNEL) {
+ brcmf_dbg(ERROR, "(nextlen): readahead on control packet %d?\n",
+ seq);
+ /* Force retry w/normal header read */
+ bus->nextlen = 0;
+ brcmf_sdbrcm_rxfail(bus, false, true);
+ brcmf_sdbrcm_pktfree2(bus, pkt);
+ continue;
+ }
+
+ /* Validate data offset */
+ if ((doff < SDPCM_HDRLEN) || (doff > len)) {
+ brcmf_dbg(ERROR, "(nextlen): bad data offset %d: HW len %d min %d\n",
+ doff, len, SDPCM_HDRLEN);
+ brcmf_sdbrcm_rxfail(bus, false, false);
+ brcmf_sdbrcm_pktfree2(bus, pkt);
+ continue;
+ }
+
+ /* All done with this one -- now deliver the packet */
+ goto deliver;
+ }
+
+ /* Read frame header (hardware and software) */
+ sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad,
+ SDIO_FUNC_2, F2SYNC, bus->rxhdr,
+ BRCMF_FIRSTREAD, NULL);
+ bus->f2rxhdrs++;
+
+ if (sdret < 0) {
+ brcmf_dbg(ERROR, "RXHEADER FAILED: %d\n", sdret);
+ bus->rx_hdrfail++;
+ brcmf_sdbrcm_rxfail(bus, true, true);
+ continue;
+ }
+#ifdef BCMDBG
+ if (BRCMF_BYTES_ON() || BRCMF_HDRS_ON()) {
+ printk(KERN_DEBUG "RxHdr:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ bus->rxhdr, SDPCM_HDRLEN);
+ }
+#endif
+
+ /* Extract hardware header fields */
+ len = get_unaligned_le16(bus->rxhdr);
+ check = get_unaligned_le16(bus->rxhdr + sizeof(u16));
+
+ /* All zeros means no more frames */
+ if (!(len | check)) {
+ *finished = true;
+ break;
+ }
+
+ /* Validate check bytes */
+ if ((u16) ~(len ^ check)) {
+ brcmf_dbg(ERROR, "HW hdr err: len/check 0x%04x/0x%04x\n",
+ len, check);
+ bus->rx_badhdr++;
+ brcmf_sdbrcm_rxfail(bus, false, false);
+ continue;
+ }
+
+ /* Validate frame length */
+ if (len < SDPCM_HDRLEN) {
+ brcmf_dbg(ERROR, "HW hdr length invalid: %d\n", len);
+ continue;
+ }
+
+ /* Extract software header fields */
+ chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
+ seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
+ doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
+ txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
+
+ /* Validate data offset */
+ if ((doff < SDPCM_HDRLEN) || (doff > len)) {
+ brcmf_dbg(ERROR, "Bad data offset %d: HW len %d, min %d seq %d\n",
+ doff, len, SDPCM_HDRLEN, seq);
+ bus->rx_badhdr++;
+ brcmf_sdbrcm_rxfail(bus, false, false);
+ continue;
+ }
+
+ /* Save the readahead length if there is one */
+ bus->nextlen =
+ bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
+ if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
+ brcmf_dbg(INFO, "(nextlen): got frame w/nextlen too large (%d), seq %d\n",
+ bus->nextlen, seq);
+ bus->nextlen = 0;
+ }
+
+ /* Handle Flow Control */
+ fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
+
+ if (bus->flowcontrol != fcbits) {
+ if (~bus->flowcontrol & fcbits)
+ bus->fc_xoff++;
+
+ if (bus->flowcontrol & ~fcbits)
+ bus->fc_xon++;
+
+ bus->fc_rcvd++;
+ bus->flowcontrol = fcbits;
+ }
+
+ /* Check and update sequence number */
+ if (rxseq != seq) {
+ brcmf_dbg(INFO, "rx_seq %d, expected %d\n", seq, rxseq);
+ bus->rx_badseq++;
+ rxseq = seq;
+ }
+
+ /* Check window for sanity */
+ if ((u8) (txmax - bus->tx_seq) > 0x40) {
+ brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n",
+ txmax, bus->tx_seq);
+ txmax = bus->tx_seq + 2;
+ }
+ bus->tx_max = txmax;
+
+ /* Call a separate function for control frames */
+ if (chan == SDPCM_CONTROL_CHANNEL) {
+ brcmf_sdbrcm_read_control(bus, bus->rxhdr, len, doff);
+ continue;
+ }
+
+ /* precondition: chan is either SDPCM_DATA_CHANNEL,
+ SDPCM_EVENT_CHANNEL, SDPCM_TEST_CHANNEL or
+ SDPCM_GLOM_CHANNEL */
+
+ /* Length to read */
+ rdlen = (len > BRCMF_FIRSTREAD) ? (len - BRCMF_FIRSTREAD) : 0;
+
+ /* May pad read to blocksize for efficiency */
+ if (bus->roundup && bus->blocksize &&
+ (rdlen > bus->blocksize)) {
+ pad = bus->blocksize - (rdlen % bus->blocksize);
+ if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
+ ((rdlen + pad + BRCMF_FIRSTREAD) < MAX_RX_DATASZ))
+ rdlen += pad;
+ } else if (rdlen % BRCMF_SDALIGN) {
+ rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN);
+ }
+
+ /* Satisfy length-alignment requirements */
+ if (rdlen & (ALIGNMENT - 1))
+ rdlen = roundup(rdlen, ALIGNMENT);
+
+ if ((rdlen + BRCMF_FIRSTREAD) > MAX_RX_DATASZ) {
+ /* Too long -- skip this frame */
+ brcmf_dbg(ERROR, "too long: len %d rdlen %d\n",
+ len, rdlen);
+ bus->drvr->rx_errors++;
+ bus->rx_toolong++;
+ brcmf_sdbrcm_rxfail(bus, false, false);
+ continue;
+ }
+
+ pkt = brcmu_pkt_buf_get_skb(rdlen +
+ BRCMF_FIRSTREAD + BRCMF_SDALIGN);
+ if (!pkt) {
+ /* Give up on data, request rtx of events */
+ brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: rdlen %d chan %d\n",
+ rdlen, chan);
+ bus->drvr->rx_dropped++;
+ brcmf_sdbrcm_rxfail(bus, false, RETRYCHAN(chan));
+ continue;
+ }
+
+ /* Leave room for what we already read, and align remainder */
+ skb_pull(pkt, BRCMF_FIRSTREAD);
+ pkt_align(pkt, rdlen, BRCMF_SDALIGN);
+
+ /* Read the remaining frame data */
+ sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad,
+ SDIO_FUNC_2, F2SYNC, ((u8 *) (pkt->data)),
+ rdlen, pkt);
+ bus->f2rxdata++;
+
+ if (sdret < 0) {
+ brcmf_dbg(ERROR, "read %d %s bytes failed: %d\n", rdlen,
+ ((chan == SDPCM_EVENT_CHANNEL) ? "event"
+ : ((chan == SDPCM_DATA_CHANNEL) ? "data"
+ : "test")), sdret);
+ brcmu_pkt_buf_free_skb(pkt);
+ bus->drvr->rx_errors++;
+ brcmf_sdbrcm_rxfail(bus, true, RETRYCHAN(chan));
+ continue;
+ }
+
+ /* Copy the already-read portion */
+ skb_push(pkt, BRCMF_FIRSTREAD);
+ memcpy(pkt->data, bus->rxhdr, BRCMF_FIRSTREAD);
+
+#ifdef BCMDBG
+ if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) {
+ printk(KERN_DEBUG "Rx Data:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ pkt->data, len);
+ }
+#endif
+
+deliver:
+ /* Save superframe descriptor and allocate packet frame */
+ if (chan == SDPCM_GLOM_CHANNEL) {
+ if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
+ brcmf_dbg(GLOM, "glom descriptor, %d bytes:\n",
+ len);
+#ifdef BCMDBG
+ if (BRCMF_GLOM_ON()) {
+ printk(KERN_DEBUG "Glom Data:\n");
+ print_hex_dump_bytes("",
+ DUMP_PREFIX_OFFSET,
+ pkt->data, len);
+ }
+#endif
+ __skb_trim(pkt, len);
+ skb_pull(pkt, SDPCM_HDRLEN);
+ bus->glomd = pkt;
+ } else {
+ brcmf_dbg(ERROR, "%s: glom superframe w/o "
+ "descriptor!\n", __func__);
+ brcmf_sdbrcm_rxfail(bus, false, false);
+ }
+ continue;
+ }
+
+ /* Fill in packet len and prio, deliver upward */
+ __skb_trim(pkt, len);
+ skb_pull(pkt, doff);
+
+ if (pkt->len == 0) {
+ brcmu_pkt_buf_free_skb(pkt);
+ continue;
+ } else if (brcmf_proto_hdrpull(bus->drvr, &ifidx, pkt) != 0) {
+ brcmf_dbg(ERROR, "rx protocol error\n");
+ brcmu_pkt_buf_free_skb(pkt);
+ bus->drvr->rx_errors++;
+ continue;
+ }
+
+ /* Unlock during rx call */
+ up(&bus->sdsem);
+ brcmf_rx_frame(bus->drvr, ifidx, pkt, 1);
+ down(&bus->sdsem);
+ }
+ rxcount = maxframes - rxleft;
+#ifdef BCMDBG
+ /* Message if we hit the limit */
+ if (!rxleft)
+ brcmf_dbg(DATA, "hit rx limit of %d frames\n",
+ maxframes);
+ else
+#endif /* BCMDBG */
+ brcmf_dbg(DATA, "processed %d frames\n", rxcount);
+ /* Back off rxseq if awaiting rtx, update rx_seq */
+ if (bus->rxskip)
+ rxseq--;
+ bus->rx_seq = rxseq;
+
+ return rxcount;
+}
+
+static int
+brcmf_sdbrcm_send_buf(struct brcmf_bus *bus, u32 addr, uint fn, uint flags,
+ u8 *buf, uint nbytes, struct sk_buff *pkt)
+{
+ return brcmf_sdcard_send_buf
+ (bus->sdiodev, addr, fn, flags, buf, nbytes, pkt);
+}
+
+static void
+brcmf_sdbrcm_wait_for_event(struct brcmf_bus *bus, bool *lockvar)
+{
+ up(&bus->sdsem);
+ wait_event_interruptible_timeout(bus->ctrl_wait,
+ (*lockvar == false), HZ * 2);
+ down(&bus->sdsem);
+ return;
+}
+
+static void
+brcmf_sdbrcm_wait_event_wakeup(struct brcmf_bus *bus)
+{
+ if (waitqueue_active(&bus->ctrl_wait))
+ wake_up_interruptible(&bus->ctrl_wait);
+ return;
+}
+
+/* Writes a HW/SW header into the packet and sends it. */
+/* Assumes: (a) header space already there, (b) caller holds lock */
+static int brcmf_sdbrcm_txpkt(struct brcmf_bus *bus, struct sk_buff *pkt,
+ uint chan, bool free_pkt)
+{
+ int ret;
+ u8 *frame;
+ u16 len, pad = 0;
+ u32 swheader;
+ struct sk_buff *new;
+ int i;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ frame = (u8 *) (pkt->data);
+
+ /* Add alignment padding, allocate new packet if needed */
+ pad = ((unsigned long)frame % BRCMF_SDALIGN);
+ if (pad) {
+ if (skb_headroom(pkt) < pad) {
+ brcmf_dbg(INFO, "insufficient headroom %d for %d pad\n",
+ skb_headroom(pkt), pad);
+ bus->drvr->tx_realloc++;
+ new = brcmu_pkt_buf_get_skb(pkt->len + BRCMF_SDALIGN);
+ if (!new) {
+ brcmf_dbg(ERROR, "couldn't allocate new %d-byte packet\n",
+ pkt->len + BRCMF_SDALIGN);
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pkt_align(new, pkt->len, BRCMF_SDALIGN);
+ memcpy(new->data, pkt->data, pkt->len);
+ if (free_pkt)
+ brcmu_pkt_buf_free_skb(pkt);
+ /* free the pkt if canned one is not used */
+ free_pkt = true;
+ pkt = new;
+ frame = (u8 *) (pkt->data);
+ /* precondition: (frame % BRCMF_SDALIGN) == 0) */
+ pad = 0;
+ } else {
+ skb_push(pkt, pad);
+ frame = (u8 *) (pkt->data);
+ /* precondition: pad + SDPCM_HDRLEN <= pkt->len */
+ memset(frame, 0, pad + SDPCM_HDRLEN);
+ }
+ }
+ /* precondition: pad < BRCMF_SDALIGN */
+
+ /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
+ len = (u16) (pkt->len);
+ *(__le16 *) frame = cpu_to_le16(len);
+ *(((__le16 *) frame) + 1) = cpu_to_le16(~len);
+
+ /* Software tag: channel, sequence number, data offset */
+ swheader =
+ ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
+ (((pad +
+ SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
+
+ put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN);
+ put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
+
+#ifdef BCMDBG
+ tx_packets[pkt->priority]++;
+ if (BRCMF_BYTES_ON() &&
+ (((BRCMF_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
+ (BRCMF_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
+ printk(KERN_DEBUG "Tx Frame:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, frame, len);
+ } else if (BRCMF_HDRS_ON()) {
+ printk(KERN_DEBUG "TxHdr:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ frame, min_t(u16, len, 16));
+ }
+#endif
+
+ /* Raise len to next SDIO block to eliminate tail command */
+ if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
+ u16 pad = bus->blocksize - (len % bus->blocksize);
+ if ((pad <= bus->roundup) && (pad < bus->blocksize))
+ len += pad;
+ } else if (len % BRCMF_SDALIGN) {
+ len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN);
+ }
+
+ /* Some controllers have trouble with odd bytes -- round to even */
+ if (len & (ALIGNMENT - 1))
+ len = roundup(len, ALIGNMENT);
+
+ ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad,
+ SDIO_FUNC_2, F2SYNC, frame,
+ len, pkt);
+ bus->f2txdata++;
+
+ if (ret < 0) {
+ /* On failure, abort the command and terminate the frame */
+ brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
+ ret);
+ bus->tx_sderrs++;
+
+ brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM,
+ NULL);
+ bus->f1regdata++;
+
+ for (i = 0; i < 3; i++) {
+ u8 hi, lo;
+ hi = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
+ SBSDIO_FUNC1_WFRAMEBCHI,
+ NULL);
+ lo = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
+ SBSDIO_FUNC1_WFRAMEBCLO,
+ NULL);
+ bus->f1regdata += 2;
+ if ((hi == 0) && (lo == 0))
+ break;
+ }
+
+ }
+ if (ret == 0)
+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
+
+done:
+ /* restore pkt buffer pointer before calling tx complete routine */
+ skb_pull(pkt, SDPCM_HDRLEN + pad);
+ up(&bus->sdsem);
+ brcmf_txcomplete(bus->drvr, pkt, ret != 0);
+ down(&bus->sdsem);
+
+ if (free_pkt)
+ brcmu_pkt_buf_free_skb(pkt);
+
+ return ret;
+}
+
+static uint brcmf_sdbrcm_sendfromq(struct brcmf_bus *bus, uint maxframes)
+{
+ struct sk_buff *pkt;
+ u32 intstatus = 0;
+ uint retries = 0;
+ int ret = 0, prec_out;
+ uint cnt = 0;
+ uint datalen;
+ u8 tx_prec_map;
+
+ struct brcmf_pub *drvr = bus->drvr;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ tx_prec_map = ~bus->flowcontrol;
+
+ /* Send frames until the limit or some other event */
+ for (cnt = 0; (cnt < maxframes) && data_ok(bus); cnt++) {
+ spin_lock_bh(&bus->txqlock);
+ pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
+ if (pkt == NULL) {
+ spin_unlock_bh(&bus->txqlock);
+ break;
+ }
+ spin_unlock_bh(&bus->txqlock);
+ datalen = pkt->len - SDPCM_HDRLEN;
+
+ ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true);
+ if (ret)
+ bus->drvr->tx_errors++;
+ else
+ bus->drvr->dstats.tx_bytes += datalen;
+
+ /* In poll mode, need to check for other events */
+ if (!bus->intr && cnt) {
+ /* Check device status, signal pending interrupt */
+ r_sdreg32(bus, &intstatus,
+ offsetof(struct sdpcmd_regs, intstatus),
+ &retries);
+ bus->f2txdata++;
+ if (brcmf_sdcard_regfail(bus->sdiodev))
+ break;
+ if (intstatus & bus->hostintmask)
+ bus->ipend = true;
+ }
+ }
+
+ /* Deflow-control stack if needed */
+ if (drvr->up && (drvr->busstate == BRCMF_BUS_DATA) &&
+ drvr->txoff && (pktq_len(&bus->txq) < TXLOW))
+ brcmf_txflowcontrol(drvr, 0, OFF);
+
+ return cnt;
+}
+
+static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus)
+{
+ u32 intstatus, newstatus = 0;
+ uint retries = 0;
+ uint rxlimit = bus->rxbound; /* Rx frames to read before resched */
+ uint txlimit = bus->txbound; /* Tx frames to send before resched */
+ uint framecnt = 0; /* Temporary counter of tx/rx frames */
+ bool rxdone = true; /* Flag for no more read data */
+ bool resched = false; /* Flag indicating resched wanted */
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Start with leftover status bits */
+ intstatus = bus->intstatus;
+
+ down(&bus->sdsem);
+
+ /* If waiting for HTAVAIL, check status */
+ if (bus->clkstate == CLK_PENDING) {
+ int err;
+ u8 clkctl, devctl = 0;
+
+#ifdef BCMDBG
+ /* Check for inconsistent device control */
+ devctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_DEVICE_CTL, &err);
+ if (err) {
+ brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err);
+ bus->drvr->busstate = BRCMF_BUS_DOWN;
+ }
+#endif /* BCMDBG */
+
+ /* Read CSR, if clock on switch to AVAIL, else ignore */
+ clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, &err);
+ if (err) {
+ brcmf_dbg(ERROR, "error reading CSR: %d\n",
+ err);
+ bus->drvr->busstate = BRCMF_BUS_DOWN;
+ }
+
+ brcmf_dbg(INFO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n",
+ devctl, clkctl);
+
+ if (SBSDIO_HTAV(clkctl)) {
+ devctl = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
+ SBSDIO_DEVICE_CTL, &err);
+ if (err) {
+ brcmf_dbg(ERROR, "error reading DEVCTL: %d\n",
+ err);
+ bus->drvr->busstate = BRCMF_BUS_DOWN;
+ }
+ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_DEVICE_CTL, devctl, &err);
+ if (err) {
+ brcmf_dbg(ERROR, "error writing DEVCTL: %d\n",
+ err);
+ bus->drvr->busstate = BRCMF_BUS_DOWN;
+ }
+ bus->clkstate = CLK_AVAIL;
+ } else {
+ goto clkwait;
+ }
+ }
+
+ bus_wake(bus);
+
+ /* Make sure backplane clock is on */
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, true);
+ if (bus->clkstate == CLK_PENDING)
+ goto clkwait;
+
+ /* Pending interrupt indicates new device status */
+ if (bus->ipend) {
+ bus->ipend = false;
+ r_sdreg32(bus, &newstatus,
+ offsetof(struct sdpcmd_regs, intstatus), &retries);
+ bus->f1regdata++;
+ if (brcmf_sdcard_regfail(bus->sdiodev))
+ newstatus = 0;
+ newstatus &= bus->hostintmask;
+ bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
+ if (newstatus) {
+ w_sdreg32(bus, newstatus,
+ offsetof(struct sdpcmd_regs, intstatus),
+ &retries);
+ bus->f1regdata++;
+ }
+ }
+
+ /* Merge new bits with previous */
+ intstatus |= newstatus;
+ bus->intstatus = 0;
+
+ /* Handle flow-control change: read new state in case our ack
+ * crossed another change interrupt. If change still set, assume
+ * FC ON for safety, let next loop through do the debounce.
+ */
+ if (intstatus & I_HMB_FC_CHANGE) {
+ intstatus &= ~I_HMB_FC_CHANGE;
+ w_sdreg32(bus, I_HMB_FC_CHANGE,
+ offsetof(struct sdpcmd_regs, intstatus), &retries);
+
+ r_sdreg32(bus, &newstatus,
+ offsetof(struct sdpcmd_regs, intstatus), &retries);
+ bus->f1regdata += 2;
+ bus->fcstate =
+ !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
+ intstatus |= (newstatus & bus->hostintmask);
+ }
+
+ /* Handle host mailbox indication */
+ if (intstatus & I_HMB_HOST_INT) {
+ intstatus &= ~I_HMB_HOST_INT;
+ intstatus |= brcmf_sdbrcm_hostmail(bus);
+ }
+
+ /* Generally don't ask for these, can get CRC errors... */
+ if (intstatus & I_WR_OOSYNC) {
+ brcmf_dbg(ERROR, "Dongle reports WR_OOSYNC\n");
+ intstatus &= ~I_WR_OOSYNC;
+ }
+
+ if (intstatus & I_RD_OOSYNC) {
+ brcmf_dbg(ERROR, "Dongle reports RD_OOSYNC\n");
+ intstatus &= ~I_RD_OOSYNC;
+ }
+
+ if (intstatus & I_SBINT) {
+ brcmf_dbg(ERROR, "Dongle reports SBINT\n");
+ intstatus &= ~I_SBINT;
+ }
+
+ /* Would be active due to wake-wlan in gSPI */
+ if (intstatus & I_CHIPACTIVE) {
+ brcmf_dbg(INFO, "Dongle reports CHIPACTIVE\n");
+ intstatus &= ~I_CHIPACTIVE;
+ }
+
+ /* Ignore frame indications if rxskip is set */
+ if (bus->rxskip)
+ intstatus &= ~I_HMB_FRAME_IND;
+
+ /* On frame indication, read available frames */
+ if (PKT_AVAILABLE()) {
+ framecnt = brcmf_sdbrcm_readframes(bus, rxlimit, &rxdone);
+ if (rxdone || bus->rxskip)
+ intstatus &= ~I_HMB_FRAME_IND;
+ rxlimit -= min(framecnt, rxlimit);
+ }
+
+ /* Keep still-pending events for next scheduling */
+ bus->intstatus = intstatus;
+
+clkwait:
+ if (data_ok(bus) && bus->ctrl_frame_stat &&
+ (bus->clkstate == CLK_AVAIL)) {
+ int ret, i;
+
+ ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad,
+ SDIO_FUNC_2, F2SYNC, (u8 *) bus->ctrl_frame_buf,
+ (u32) bus->ctrl_frame_len, NULL);
+
+ if (ret < 0) {
+ /* On failure, abort the command and
+ terminate the frame */
+ brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
+ ret);
+ bus->tx_sderrs++;
+
+ brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
+
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM,
+ NULL);
+ bus->f1regdata++;
+
+ for (i = 0; i < 3; i++) {
+ u8 hi, lo;
+ hi = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
+ SBSDIO_FUNC1_WFRAMEBCHI,
+ NULL);
+ lo = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
+ SBSDIO_FUNC1_WFRAMEBCLO,
+ NULL);
+ bus->f1regdata += 2;
+ if ((hi == 0) && (lo == 0))
+ break;
+ }
+
+ }
+ if (ret == 0)
+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
+
+ brcmf_dbg(INFO, "Return_dpc value is : %d\n", ret);
+ bus->ctrl_frame_stat = false;
+ brcmf_sdbrcm_wait_event_wakeup(bus);
+ }
+ /* Send queued frames (limit 1 if rx may still be pending) */
+ else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
+ brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit
+ && data_ok(bus)) {
+ framecnt = rxdone ? txlimit : min(txlimit, bus->txminmax);
+ framecnt = brcmf_sdbrcm_sendfromq(bus, framecnt);
+ txlimit -= framecnt;
+ }
+
+ /* Resched if events or tx frames are pending,
+ else await next interrupt */
+ /* On failed register access, all bets are off:
+ no resched or interrupts */
+ if ((bus->drvr->busstate == BRCMF_BUS_DOWN) ||
+ brcmf_sdcard_regfail(bus->sdiodev)) {
+ brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation %d\n",
+ brcmf_sdcard_regfail(bus->sdiodev));
+ bus->drvr->busstate = BRCMF_BUS_DOWN;
+ bus->intstatus = 0;
+ } else if (bus->clkstate == CLK_PENDING) {
+ brcmf_dbg(INFO, "rescheduled due to CLK_PENDING awaiting I_CHIPACTIVE interrupt\n");
+ resched = true;
+ } else if (bus->intstatus || bus->ipend ||
+ (!bus->fcstate && brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol)
+ && data_ok(bus)) || PKT_AVAILABLE()) {
+ resched = true;
+ }
+
+ bus->dpc_sched = resched;
+
+ /* If we're done for now, turn off clock request. */
+ if ((bus->clkstate != CLK_PENDING)
+ && bus->idletime == BRCMF_IDLE_IMMEDIATE) {
+ bus->activity = false;
+ brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
+ }
+
+ up(&bus->sdsem);
+
+ return resched;
+}
+
+static int brcmf_sdbrcm_dpc_thread(void *data)
+{
+ struct brcmf_bus *bus = (struct brcmf_bus *) data;
+
+ allow_signal(SIGTERM);
+ /* Run until signal received */
+ while (1) {
+ if (kthread_should_stop())
+ break;
+ if (!wait_for_completion_interruptible(&bus->dpc_wait)) {
+ /* Call bus dpc unless it indicated down
+ (then clean stop) */
+ if (bus->drvr->busstate != BRCMF_BUS_DOWN) {
+ if (brcmf_sdbrcm_dpc(bus))
+ complete(&bus->dpc_wait);
+ } else {
+ /* after stopping the bus, exit thread */
+ brcmf_sdbrcm_bus_stop(bus);
+ bus->dpc_tsk = NULL;
+ break;
+ }
+ } else
+ break;
+ }
+ return 0;
+}
+
+int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *pkt)
+{
+ int ret = -EBADE;
+ uint datalen, prec;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ datalen = pkt->len;
+
+ /* Add space for the header */
+ skb_push(pkt, SDPCM_HDRLEN);
+ /* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */
+
+ prec = prio2prec((pkt->priority & PRIOMASK));
+
+ /* Check for existing queue, current flow-control,
+ pending event, or pending clock */
+ brcmf_dbg(TRACE, "deferring pktq len %d\n", pktq_len(&bus->txq));
+ bus->fcqueued++;
+
+ /* Priority based enq */
+ spin_lock_bh(&bus->txqlock);
+ if (brcmf_c_prec_enq(bus->drvr, &bus->txq, pkt, prec) == false) {
+ skb_pull(pkt, SDPCM_HDRLEN);
+ brcmf_txcomplete(bus->drvr, pkt, false);
+ brcmu_pkt_buf_free_skb(pkt);
+ brcmf_dbg(ERROR, "out of bus->txq !!!\n");
+ ret = -ENOSR;
+ } else {
+ ret = 0;
+ }
+ spin_unlock_bh(&bus->txqlock);
+
+ if (pktq_len(&bus->txq) >= TXHI)
+ brcmf_txflowcontrol(bus->drvr, 0, ON);
+
+#ifdef BCMDBG
+ if (pktq_plen(&bus->txq, prec) > qcount[prec])
+ qcount[prec] = pktq_plen(&bus->txq, prec);
+#endif
+ /* Schedule DPC if needed to send queued packet(s) */
+ if (!bus->dpc_sched) {
+ bus->dpc_sched = true;
+ if (bus->dpc_tsk)
+ complete(&bus->dpc_wait);
+ }
+
+ return ret;
+}
+
+static int
+brcmf_sdbrcm_membytes(struct brcmf_bus *bus, bool write, u32 address, u8 *data,
+ uint size)
+{
+ int bcmerror = 0;
+ u32 sdaddr;
+ uint dsize;
+
+ /* Determine initial transfer parameters */
+ sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
+ if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
+ dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
+ else
+ dsize = size;
+
+ /* Set the backplane window to include the start address */
+ bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev, address);
+ if (bcmerror) {
+ brcmf_dbg(ERROR, "window change failed\n");
+ goto xfer_done;
+ }
+
+ /* Do the transfer(s) */
+ while (size) {
+ brcmf_dbg(INFO, "%s %d bytes at offset 0x%08x in window 0x%08x\n",
+ write ? "write" : "read", dsize,
+ sdaddr, address & SBSDIO_SBWINDOW_MASK);
+ bcmerror = brcmf_sdcard_rwdata(bus->sdiodev, write,
+ sdaddr, data, dsize);
+ if (bcmerror) {
+ brcmf_dbg(ERROR, "membytes transfer failed\n");
+ break;
+ }
+
+ /* Adjust for next transfer (if any) */
+ size -= dsize;
+ if (size) {
+ data += dsize;
+ address += dsize;
+ bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev,
+ address);
+ if (bcmerror) {
+ brcmf_dbg(ERROR, "window change failed\n");
+ break;
+ }
+ sdaddr = 0;
+ dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size);
+ }
+ }
+
+xfer_done:
+ /* Return the window to backplane enumeration space for core access */
+ if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, bus->sdiodev->sbwad))
+ brcmf_dbg(ERROR, "FAILED to set window back to 0x%x\n",
+ bus->sdiodev->sbwad);
+
+ return bcmerror;
+}
+
+#ifdef BCMDBG
+#define CONSOLE_LINE_MAX 192
+
+static int brcmf_sdbrcm_readconsole(struct brcmf_bus *bus)
+{
+ struct brcmf_console *c = &bus->console;
+ u8 line[CONSOLE_LINE_MAX], ch;
+ u32 n, idx, addr;
+ int rv;
+
+ /* Don't do anything until FWREADY updates console address */
+ if (bus->console_addr == 0)
+ return 0;
+
+ /* Read console log struct */
+ addr = bus->console_addr + offsetof(struct rte_console, log_le);
+ rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&c->log_le,
+ sizeof(c->log_le));
+ if (rv < 0)
+ return rv;
+
+ /* Allocate console buffer (one time only) */
+ if (c->buf == NULL) {
+ c->bufsize = le32_to_cpu(c->log_le.buf_size);
+ c->buf = kmalloc(c->bufsize, GFP_ATOMIC);
+ if (c->buf == NULL)
+ return -ENOMEM;
+ }
+
+ idx = le32_to_cpu(c->log_le.idx);
+
+ /* Protect against corrupt value */
+ if (idx > c->bufsize)
+ return -EBADE;
+
+ /* Skip reading the console buffer if the index pointer
+ has not moved */
+ if (idx == c->last)
+ return 0;
+
+ /* Read the console buffer */
+ addr = le32_to_cpu(c->log_le.buf);
+ rv = brcmf_sdbrcm_membytes(bus, false, addr, c->buf, c->bufsize);
+ if (rv < 0)
+ return rv;
+
+ while (c->last != idx) {
+ for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
+ if (c->last == idx) {
+ /* This would output a partial line.
+ * Instead, back up
+ * the buffer pointer and output this
+ * line next time around.
+ */
+ if (c->last >= n)
+ c->last -= n;
+ else
+ c->last = c->bufsize - n;
+ goto break2;
+ }
+ ch = c->buf[c->last];
+ c->last = (c->last + 1) % c->bufsize;
+ if (ch == '\n')
+ break;
+ line[n] = ch;
+ }
+
+ if (n > 0) {
+ if (line[n - 1] == '\r')
+ n--;
+ line[n] = 0;
+ printk(KERN_DEBUG "CONSOLE: %s\n", line);
+ }
+ }
+break2:
+
+ return 0;
+}
+#endif /* BCMDBG */
+
+static int brcmf_tx_frame(struct brcmf_bus *bus, u8 *frame, u16 len)
+{
+ int i;
+ int ret;
+
+ bus->ctrl_frame_stat = false;
+ ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad,
+ SDIO_FUNC_2, F2SYNC, frame, len, NULL);
+
+ if (ret < 0) {
+ /* On failure, abort the command and terminate the frame */
+ brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
+ ret);
+ bus->tx_sderrs++;
+
+ brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
+
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_FRAMECTRL,
+ SFC_WF_TERM, NULL);
+ bus->f1regdata++;
+
+ for (i = 0; i < 3; i++) {
+ u8 hi, lo;
+ hi = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_WFRAMEBCHI,
+ NULL);
+ lo = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_WFRAMEBCLO,
+ NULL);
+ bus->f1regdata += 2;
+ if (hi == 0 && lo == 0)
+ break;
+ }
+ return ret;
+ }
+
+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
+
+ return ret;
+}
+
+int
+brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen)
+{
+ u8 *frame;
+ u16 len;
+ u32 swheader;
+ uint retries = 0;
+ u8 doff = 0;
+ int ret = -1;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Back the pointer to make a room for bus header */
+ frame = msg - SDPCM_HDRLEN;
+ len = (msglen += SDPCM_HDRLEN);
+
+ /* Add alignment padding (optional for ctl frames) */
+ doff = ((unsigned long)frame % BRCMF_SDALIGN);
+ if (doff) {
+ frame -= doff;
+ len += doff;
+ msglen += doff;
+ memset(frame, 0, doff + SDPCM_HDRLEN);
+ }
+ /* precondition: doff < BRCMF_SDALIGN */
+ doff += SDPCM_HDRLEN;
+
+ /* Round send length to next SDIO block */
+ if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
+ u16 pad = bus->blocksize - (len % bus->blocksize);
+ if ((pad <= bus->roundup) && (pad < bus->blocksize))
+ len += pad;
+ } else if (len % BRCMF_SDALIGN) {
+ len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN);
+ }
+
+ /* Satisfy length-alignment requirements */
+ if (len & (ALIGNMENT - 1))
+ len = roundup(len, ALIGNMENT);
+
+ /* precondition: IS_ALIGNED((unsigned long)frame, 2) */
+
+ /* Need to lock here to protect txseq and SDIO tx calls */
+ down(&bus->sdsem);
+
+ bus_wake(bus);
+
+ /* Make sure backplane clock is on */
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+
+ /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
+ *(__le16 *) frame = cpu_to_le16((u16) msglen);
+ *(((__le16 *) frame) + 1) = cpu_to_le16(~msglen);
+
+ /* Software tag: channel, sequence number, data offset */
+ swheader =
+ ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) &
+ SDPCM_CHANNEL_MASK)
+ | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) &
+ SDPCM_DOFFSET_MASK);
+ put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN);
+ put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
+
+ if (!data_ok(bus)) {
+ brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n",
+ bus->tx_max, bus->tx_seq);
+ bus->ctrl_frame_stat = true;
+ /* Send from dpc */
+ bus->ctrl_frame_buf = frame;
+ bus->ctrl_frame_len = len;
+
+ brcmf_sdbrcm_wait_for_event(bus, &bus->ctrl_frame_stat);
+
+ if (bus->ctrl_frame_stat == false) {
+ brcmf_dbg(INFO, "ctrl_frame_stat == false\n");
+ ret = 0;
+ } else {
+ brcmf_dbg(INFO, "ctrl_frame_stat == true\n");
+ ret = -1;
+ }
+ }
+
+ if (ret == -1) {
+#ifdef BCMDBG
+ if (BRCMF_BYTES_ON() && BRCMF_CTL_ON()) {
+ printk(KERN_DEBUG "Tx Frame:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ frame, len);
+ } else if (BRCMF_HDRS_ON()) {
+ printk(KERN_DEBUG "TxHdr:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ frame, min_t(u16, len, 16));
+ }
+#endif
+
+ do {
+ ret = brcmf_tx_frame(bus, frame, len);
+ } while (ret < 0 && retries++ < TXRETRIES);
+ }
+
+ if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) && !bus->dpc_sched) {
+ bus->activity = false;
+ brcmf_sdbrcm_clkctl(bus, CLK_NONE, true);
+ }
+
+ up(&bus->sdsem);
+
+ if (ret)
+ bus->drvr->tx_ctlerrs++;
+ else
+ bus->drvr->tx_ctlpkts++;
+
+ return ret ? -EIO : 0;
+}
+
+int
+brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen)
+{
+ int timeleft;
+ uint rxlen = 0;
+ bool pending;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Wait until control frame is available */
+ timeleft = brcmf_sdbrcm_dcmd_resp_wait(bus, &bus->rxlen, &pending);
+
+ down(&bus->sdsem);
+ rxlen = bus->rxlen;
+ memcpy(msg, bus->rxctl, min(msglen, rxlen));
+ bus->rxlen = 0;
+ up(&bus->sdsem);
+
+ if (rxlen) {
+ brcmf_dbg(CTL, "resumed on rxctl frame, got %d expected %d\n",
+ rxlen, msglen);
+ } else if (timeleft == 0) {
+ brcmf_dbg(ERROR, "resumed on timeout\n");
+ } else if (pending == true) {
+ brcmf_dbg(CTL, "cancelled\n");
+ return -ERESTARTSYS;
+ } else {
+ brcmf_dbg(CTL, "resumed for unknown reason?\n");
+ }
+
+ if (rxlen)
+ bus->drvr->rx_ctlpkts++;
+ else
+ bus->drvr->rx_ctlerrs++;
+
+ return rxlen ? (int)rxlen : -ETIMEDOUT;
+}
+
+static int brcmf_sdbrcm_downloadvars(struct brcmf_bus *bus, void *arg, int len)
+{
+ int bcmerror = 0;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Basic sanity checks */
+ if (bus->drvr->up) {
+ bcmerror = -EISCONN;
+ goto err;
+ }
+ if (!len) {
+ bcmerror = -EOVERFLOW;
+ goto err;
+ }
+
+ /* Free the old ones and replace with passed variables */
+ kfree(bus->vars);
+
+ bus->vars = kmalloc(len, GFP_ATOMIC);
+ bus->varsz = bus->vars ? len : 0;
+ if (bus->vars == NULL) {
+ bcmerror = -ENOMEM;
+ goto err;
+ }
+
+ /* Copy the passed variables, which should include the
+ terminating double-null */
+ memcpy(bus->vars, arg, bus->varsz);
+err:
+ return bcmerror;
+}
+
+static int brcmf_sdbrcm_write_vars(struct brcmf_bus *bus)
+{
+ int bcmerror = 0;
+ u32 varsize;
+ u32 varaddr;
+ u8 *vbuffer;
+ u32 varsizew;
+ __le32 varsizew_le;
+#ifdef BCMDBG
+ char *nvram_ularray;
+#endif /* BCMDBG */
+
+ /* Even if there are no vars are to be written, we still
+ need to set the ramsize. */
+ varsize = bus->varsz ? roundup(bus->varsz, 4) : 0;
+ varaddr = (bus->ramsize - 4) - varsize;
+
+ if (bus->vars) {
+ vbuffer = kzalloc(varsize, GFP_ATOMIC);
+ if (!vbuffer)
+ return -ENOMEM;
+
+ memcpy(vbuffer, bus->vars, bus->varsz);
+
+ /* Write the vars list */
+ bcmerror =
+ brcmf_sdbrcm_membytes(bus, true, varaddr, vbuffer, varsize);
+#ifdef BCMDBG
+ /* Verify NVRAM bytes */
+ brcmf_dbg(INFO, "Compare NVRAM dl & ul; varsize=%d\n", varsize);
+ nvram_ularray = kmalloc(varsize, GFP_ATOMIC);
+ if (!nvram_ularray)
+ return -ENOMEM;
+
+ /* Upload image to verify downloaded contents. */
+ memset(nvram_ularray, 0xaa, varsize);
+
+ /* Read the vars list to temp buffer for comparison */
+ bcmerror =
+ brcmf_sdbrcm_membytes(bus, false, varaddr, nvram_ularray,
+ varsize);
+ if (bcmerror) {
+ brcmf_dbg(ERROR, "error %d on reading %d nvram bytes at 0x%08x\n",
+ bcmerror, varsize, varaddr);
+ }
+ /* Compare the org NVRAM with the one read from RAM */
+ if (memcmp(vbuffer, nvram_ularray, varsize))
+ brcmf_dbg(ERROR, "Downloaded NVRAM image is corrupted\n");
+ else
+ brcmf_dbg(ERROR, "Download/Upload/Compare of NVRAM ok\n");
+
+ kfree(nvram_ularray);
+#endif /* BCMDBG */
+
+ kfree(vbuffer);
+ }
+
+ /* adjust to the user specified RAM */
+ brcmf_dbg(INFO, "Physical memory size: %d\n", bus->ramsize);
+ brcmf_dbg(INFO, "Vars are at %d, orig varsize is %d\n",
+ varaddr, varsize);
+ varsize = ((bus->ramsize - 4) - varaddr);
+
+ /*
+ * Determine the length token:
+ * Varsize, converted to words, in lower 16-bits, checksum
+ * in upper 16-bits.
+ */
+ if (bcmerror) {
+ varsizew = 0;
+ varsizew_le = cpu_to_le32(0);
+ } else {
+ varsizew = varsize / 4;
+ varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
+ varsizew_le = cpu_to_le32(varsizew);
+ }
+
+ brcmf_dbg(INFO, "New varsize is %d, length token=0x%08x\n",
+ varsize, varsizew);
+
+ /* Write the length token to the last word */
+ bcmerror = brcmf_sdbrcm_membytes(bus, true, (bus->ramsize - 4),
+ (u8 *)&varsizew_le, 4);
+
+ return bcmerror;
+}
+
+static void
+brcmf_sdbrcm_chip_disablecore(struct brcmf_sdio_dev *sdiodev, u32 corebase)
+{
+ u32 regdata;
+
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatelow), 4);
+ if (regdata & SBTML_RESET)
+ return;
+
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatelow), 4);
+ if ((regdata & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) != 0) {
+ /*
+ * set target reject and spin until busy is clear
+ * (preserve core-specific bits)
+ */
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatelow), 4);
+ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow),
+ 4, regdata | SBTML_REJ);
+
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatelow), 4);
+ udelay(1);
+ SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatehigh), 4) &
+ SBTMH_BUSY), 100000);
+
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatehigh), 4);
+ if (regdata & SBTMH_BUSY)
+ brcmf_dbg(ERROR, "ARM core still busy\n");
+
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbidlow), 4);
+ if (regdata & SBIDL_INIT) {
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbimstate), 4) |
+ SBIM_RJ;
+ brcmf_sdcard_reg_write(sdiodev,
+ CORE_SB(corebase, sbimstate), 4,
+ regdata);
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbimstate), 4);
+ udelay(1);
+ SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbimstate), 4) &
+ SBIM_BY), 100000);
+ }
+
+ /* set reset and reject while enabling the clocks */
+ brcmf_sdcard_reg_write(sdiodev,
+ CORE_SB(corebase, sbtmstatelow), 4,
+ (((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
+ SBTML_REJ | SBTML_RESET));
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatelow), 4);
+ udelay(10);
+
+ /* clear the initiator reject bit */
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbidlow), 4);
+ if (regdata & SBIDL_INIT) {
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbimstate), 4) &
+ ~SBIM_RJ;
+ brcmf_sdcard_reg_write(sdiodev,
+ CORE_SB(corebase, sbimstate), 4,
+ regdata);
+ }
+ }
+
+ /* leave reset and reject asserted */
+ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
+ (SBTML_REJ | SBTML_RESET));
+ udelay(1);
+}
+
+static void
+brcmf_sdbrcm_chip_resetcore(struct brcmf_sdio_dev *sdiodev, u32 corebase)
+{
+ u32 regdata;
+
+ /*
+ * Must do the disable sequence first to work for
+ * arbitrary current core state.
+ */
+ brcmf_sdbrcm_chip_disablecore(sdiodev, corebase);
+
+ /*
+ * Now do the initialization sequence.
+ * set reset while enabling the clock and
+ * forcing them on throughout the core
+ */
+ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
+ ((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
+ SBTML_RESET);
+ udelay(1);
+
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatehigh), 4);
+ if (regdata & SBTMH_SERR)
+ brcmf_sdcard_reg_write(sdiodev,
+ CORE_SB(corebase, sbtmstatehigh), 4, 0);
+
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbimstate), 4);
+ if (regdata & (SBIM_IBE | SBIM_TO))
+ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbimstate), 4,
+ regdata & ~(SBIM_IBE | SBIM_TO));
+
+ /* clear reset and allow it to propagate throughout the core */
+ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
+ (SICF_FGC << SBTML_SICF_SHIFT) |
+ (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
+ udelay(1);
+
+ /* leave clock enabled */
+ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
+ (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
+ udelay(1);
+}
+
+static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter)
+{
+ uint retries;
+ u32 regdata;
+ int bcmerror = 0;
+
+ /* To enter download state, disable ARM and reset SOCRAM.
+ * To exit download state, simply reset ARM (default is RAM boot).
+ */
+ if (enter) {
+ bus->alp_only = true;
+
+ brcmf_sdbrcm_chip_disablecore(bus->sdiodev,
+ bus->ci->armcorebase);
+
+ brcmf_sdbrcm_chip_resetcore(bus->sdiodev, bus->ci->ramcorebase);
+
+ /* Clear the top bit of memory */
+ if (bus->ramsize) {
+ u32 zeros = 0;
+ brcmf_sdbrcm_membytes(bus, true, bus->ramsize - 4,
+ (u8 *)&zeros, 4);
+ }
+ } else {
+ regdata = brcmf_sdcard_reg_read(bus->sdiodev,
+ CORE_SB(bus->ci->ramcorebase, sbtmstatelow), 4);
+ regdata &= (SBTML_RESET | SBTML_REJ_MASK |
+ (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
+ if ((SICF_CLOCK_EN << SBTML_SICF_SHIFT) != regdata) {
+ brcmf_dbg(ERROR, "SOCRAM core is down after reset?\n");
+ bcmerror = -EBADE;
+ goto fail;
+ }
+
+ bcmerror = brcmf_sdbrcm_write_vars(bus);
+ if (bcmerror) {
+ brcmf_dbg(ERROR, "no vars written to RAM\n");
+ bcmerror = 0;
+ }
+
+ w_sdreg32(bus, 0xFFFFFFFF,
+ offsetof(struct sdpcmd_regs, intstatus), &retries);
+
+ brcmf_sdbrcm_chip_resetcore(bus->sdiodev, bus->ci->armcorebase);
+
+ /* Allow HT Clock now that the ARM is running. */
+ bus->alp_only = false;
+
+ bus->drvr->busstate = BRCMF_BUS_LOAD;
+ }
+fail:
+ return bcmerror;
+}
+
+static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_bus *bus)
+{
+ if (bus->firmware->size < bus->fw_ptr + len)
+ len = bus->firmware->size - bus->fw_ptr;
+
+ memcpy(buf, &bus->firmware->data[bus->fw_ptr], len);
+ bus->fw_ptr += len;
+ return len;
+}
+
+MODULE_FIRMWARE(BCM4329_FW_NAME);
+MODULE_FIRMWARE(BCM4329_NV_NAME);
+
+static int brcmf_sdbrcm_download_code_file(struct brcmf_bus *bus)
+{
+ int offset = 0;
+ uint len;
+ u8 *memblock = NULL, *memptr;
+ int ret;
+
+ brcmf_dbg(INFO, "Enter\n");
+
+ bus->fw_name = BCM4329_FW_NAME;
+ ret = request_firmware(&bus->firmware, bus->fw_name,
+ &bus->sdiodev->func[2]->dev);
+ if (ret) {
+ brcmf_dbg(ERROR, "Fail to request firmware %d\n", ret);
+ return ret;
+ }
+ bus->fw_ptr = 0;
+
+ memptr = memblock = kmalloc(MEMBLOCK + BRCMF_SDALIGN, GFP_ATOMIC);
+ if (memblock == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ if ((u32)(unsigned long)memblock % BRCMF_SDALIGN)
+ memptr += (BRCMF_SDALIGN -
+ ((u32)(unsigned long)memblock % BRCMF_SDALIGN));
+
+ /* Download image */
+ while ((len =
+ brcmf_sdbrcm_get_image((char *)memptr, MEMBLOCK, bus))) {
+ ret = brcmf_sdbrcm_membytes(bus, true, offset, memptr, len);
+ if (ret) {
+ brcmf_dbg(ERROR, "error %d on writing %d membytes at 0x%08x\n",
+ ret, MEMBLOCK, offset);
+ goto err;
+ }
+
+ offset += MEMBLOCK;
+ }
+
+err:
+ kfree(memblock);
+
+ release_firmware(bus->firmware);
+ bus->fw_ptr = 0;
+
+ return ret;
+}
+
+/*
+ * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file
+ * and ending in a NUL.
+ * Removes carriage returns, empty lines, comment lines, and converts
+ * newlines to NULs.
+ * Shortens buffer as needed and pads with NULs. End of buffer is marked
+ * by two NULs.
+*/
+
+static uint brcmf_process_nvram_vars(char *varbuf, uint len)
+{
+ char *dp;
+ bool findNewline;
+ int column;
+ uint buf_len, n;
+
+ dp = varbuf;
+
+ findNewline = false;
+ column = 0;
+
+ for (n = 0; n < len; n++) {
+ if (varbuf[n] == 0)
+ break;
+ if (varbuf[n] == '\r')
+ continue;
+ if (findNewline && varbuf[n] != '\n')
+ continue;
+ findNewline = false;
+ if (varbuf[n] == '#') {
+ findNewline = true;
+ continue;
+ }
+ if (varbuf[n] == '\n') {
+ if (column == 0)
+ continue;
+ *dp++ = 0;
+ column = 0;
+ continue;
+ }
+ *dp++ = varbuf[n];
+ column++;
+ }
+ buf_len = dp - varbuf;
+
+ while (dp < varbuf + n)
+ *dp++ = 0;
+
+ return buf_len;
+}
+
+static int brcmf_sdbrcm_download_nvram(struct brcmf_bus *bus)
+{
+ uint len;
+ char *memblock = NULL;
+ char *bufp;
+ int ret;
+
+ bus->nv_name = BCM4329_NV_NAME;
+ ret = request_firmware(&bus->firmware, bus->nv_name,
+ &bus->sdiodev->func[2]->dev);
+ if (ret) {
+ brcmf_dbg(ERROR, "Fail to request nvram %d\n", ret);
+ return ret;
+ }
+ bus->fw_ptr = 0;
+
+ memblock = kmalloc(MEMBLOCK, GFP_ATOMIC);
+ if (memblock == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ len = brcmf_sdbrcm_get_image(memblock, MEMBLOCK, bus);
+
+ if (len > 0 && len < MEMBLOCK) {
+ bufp = (char *)memblock;
+ bufp[len] = 0;
+ len = brcmf_process_nvram_vars(bufp, len);
+ bufp += len;
+ *bufp++ = 0;
+ if (len)
+ ret = brcmf_sdbrcm_downloadvars(bus, memblock, len + 1);
+ if (ret)
+ brcmf_dbg(ERROR, "error downloading vars: %d\n", ret);
+ } else {
+ brcmf_dbg(ERROR, "error reading nvram file: %d\n", len);
+ ret = -EIO;
+ }
+
+err:
+ kfree(memblock);
+
+ release_firmware(bus->firmware);
+ bus->fw_ptr = 0;
+
+ return ret;
+}
+
+static int _brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus)
+{
+ int bcmerror = -1;
+
+ /* Keep arm in reset */
+ if (brcmf_sdbrcm_download_state(bus, true)) {
+ brcmf_dbg(ERROR, "error placing ARM core in reset\n");
+ goto err;
+ }
+
+ /* External image takes precedence if specified */
+ if (brcmf_sdbrcm_download_code_file(bus)) {
+ brcmf_dbg(ERROR, "dongle image file download failed\n");
+ goto err;
+ }
+
+ /* External nvram takes precedence if specified */
+ if (brcmf_sdbrcm_download_nvram(bus))
+ brcmf_dbg(ERROR, "dongle nvram file download failed\n");
+
+ /* Take arm out of reset */
+ if (brcmf_sdbrcm_download_state(bus, false)) {
+ brcmf_dbg(ERROR, "error getting out of ARM core reset\n");
+ goto err;
+ }
+
+ bcmerror = 0;
+
+err:
+ return bcmerror;
+}
+
+static bool
+brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus)
+{
+ bool ret;
+
+ /* Download the firmware */
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+
+ ret = _brcmf_sdbrcm_download_firmware(bus) == 0;
+
+ brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
+
+ return ret;
+}
+
+void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus)
+{
+ u32 local_hostintmask;
+ u8 saveclk;
+ uint retries;
+ int err;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (bus->watchdog_tsk) {
+ send_sig(SIGTERM, bus->watchdog_tsk, 1);
+ kthread_stop(bus->watchdog_tsk);
+ bus->watchdog_tsk = NULL;
+ }
+
+ if (bus->dpc_tsk && bus->dpc_tsk != current) {
+ send_sig(SIGTERM, bus->dpc_tsk, 1);
+ kthread_stop(bus->dpc_tsk);
+ bus->dpc_tsk = NULL;
+ }
+
+ down(&bus->sdsem);
+
+ bus_wake(bus);
+
+ /* Enable clock for device interrupts */
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+
+ /* Disable and clear interrupts at the chip level also */
+ w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask), &retries);
+ local_hostintmask = bus->hostintmask;
+ bus->hostintmask = 0;
+
+ /* Change our idea of bus state */
+ bus->drvr->busstate = BRCMF_BUS_DOWN;
+
+ /* Force clocks on backplane to be sure F2 interrupt propagates */
+ saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, &err);
+ if (!err) {
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR,
+ (saveclk | SBSDIO_FORCE_HT), &err);
+ }
+ if (err)
+ brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err);
+
+ /* Turn off the bus (F2), free any pending packets */
+ brcmf_dbg(INTR, "disable SDIO interrupts\n");
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
+ SDIO_FUNC_ENABLE_1, NULL);
+
+ /* Clear any pending interrupts now that F2 is disabled */
+ w_sdreg32(bus, local_hostintmask,
+ offsetof(struct sdpcmd_regs, intstatus), &retries);
+
+ /* Turn off the backplane clock (only) */
+ brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
+
+ /* Clear the data packet queues */
+ brcmu_pktq_flush(&bus->txq, true, NULL, NULL);
+
+ /* Clear any held glomming stuff */
+ if (bus->glomd)
+ brcmu_pkt_buf_free_skb(bus->glomd);
+
+ if (bus->glom)
+ brcmu_pkt_buf_free_skb(bus->glom);
+
+ bus->glom = bus->glomd = NULL;
+
+ /* Clear rx control and wake any waiters */
+ bus->rxlen = 0;
+ brcmf_sdbrcm_dcmd_resp_wake(bus);
+
+ /* Reset some F2 state stuff */
+ bus->rxskip = false;
+ bus->tx_seq = bus->rx_seq = 0;
+
+ up(&bus->sdsem);
+}
+
+int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr)
+{
+ struct brcmf_bus *bus = drvr->bus;
+ unsigned long timeout;
+ uint retries = 0;
+ u8 ready, enable;
+ int err, ret = 0;
+ u8 saveclk;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* try to download image and nvram to the dongle */
+ if (drvr->busstate == BRCMF_BUS_DOWN) {
+ if (!(brcmf_sdbrcm_download_firmware(bus)))
+ return -1;
+ }
+
+ if (!bus->drvr)
+ return 0;
+
+ /* Start the watchdog timer */
+ bus->drvr->tickcnt = 0;
+ brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
+
+ down(&bus->sdsem);
+
+ /* Make sure backplane clock is on, needed to generate F2 interrupt */
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+ if (bus->clkstate != CLK_AVAIL)
+ goto exit;
+
+ /* Force clocks on backplane to be sure F2 interrupt propagates */
+ saveclk =
+ brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, &err);
+ if (!err) {
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR,
+ (saveclk | SBSDIO_FORCE_HT), &err);
+ }
+ if (err) {
+ brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err);
+ goto exit;
+ }
+
+ /* Enable function 2 (frame transfers) */
+ w_sdreg32(bus, SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT,
+ offsetof(struct sdpcmd_regs, tosbmailboxdata), &retries);
+ enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
+
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
+ enable, NULL);
+
+ timeout = jiffies + msecs_to_jiffies(BRCMF_WAIT_F2RDY);
+ ready = 0;
+ while (enable != ready) {
+ ready = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_0,
+ SDIO_CCCR_IORx, NULL);
+ if (time_after(jiffies, timeout))
+ break;
+ else if (time_after(jiffies, timeout - BRCMF_WAIT_F2RDY + 50))
+ /* prevent busy waiting if it takes too long */
+ msleep_interruptible(20);
+ }
+
+ brcmf_dbg(INFO, "enable 0x%02x, ready 0x%02x\n", enable, ready);
+
+ /* If F2 successfully enabled, set core and enable interrupts */
+ if (ready == enable) {
+ /* Set up the interrupt mask and enable interrupts */
+ bus->hostintmask = HOSTINTMASK;
+ w_sdreg32(bus, bus->hostintmask,
+ offsetof(struct sdpcmd_regs, hostintmask), &retries);
+
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_WATERMARK, 8, &err);
+
+ /* Set bus state according to enable result */
+ drvr->busstate = BRCMF_BUS_DATA;
+ }
+
+ else {
+ /* Disable F2 again */
+ enable = SDIO_FUNC_ENABLE_1;
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0,
+ SDIO_CCCR_IOEx, enable, NULL);
+ }
+
+ /* Restore previous clock setting */
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
+
+ /* If we didn't come up, turn off backplane clock */
+ if (drvr->busstate != BRCMF_BUS_DATA)
+ brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
+
+exit:
+ up(&bus->sdsem);
+
+ return ret;
+}
+
+void brcmf_sdbrcm_isr(void *arg)
+{
+ struct brcmf_bus *bus = (struct brcmf_bus *) arg;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (!bus) {
+ brcmf_dbg(ERROR, "bus is null pointer, exiting\n");
+ return;
+ }
+
+ if (bus->drvr->busstate == BRCMF_BUS_DOWN) {
+ brcmf_dbg(ERROR, "bus is down. we have nothing to do\n");
+ return;
+ }
+ /* Count the interrupt call */
+ bus->intrcount++;
+ bus->ipend = true;
+
+ /* Shouldn't get this interrupt if we're sleeping? */
+ if (bus->sleeping) {
+ brcmf_dbg(ERROR, "INTERRUPT WHILE SLEEPING??\n");
+ return;
+ }
+
+ /* Disable additional interrupts (is this needed now)? */
+ if (!bus->intr)
+ brcmf_dbg(ERROR, "isr w/o interrupt configured!\n");
+
+ bus->dpc_sched = true;
+ if (bus->dpc_tsk)
+ complete(&bus->dpc_wait);
+}
+
+static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_pub *drvr)
+{
+ struct brcmf_bus *bus;
+
+ brcmf_dbg(TIMER, "Enter\n");
+
+ bus = drvr->bus;
+
+ /* Ignore the timer if simulating bus down */
+ if (bus->sleeping)
+ return false;
+
+ down(&bus->sdsem);
+
+ /* Poll period: check device if appropriate. */
+ if (bus->poll && (++bus->polltick >= bus->pollrate)) {
+ u32 intstatus = 0;
+
+ /* Reset poll tick */
+ bus->polltick = 0;
+
+ /* Check device if no interrupts */
+ if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
+
+ if (!bus->dpc_sched) {
+ u8 devpend;
+ devpend = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_0, SDIO_CCCR_INTx,
+ NULL);
+ intstatus =
+ devpend & (INTR_STATUS_FUNC1 |
+ INTR_STATUS_FUNC2);
+ }
+
+ /* If there is something, make like the ISR and
+ schedule the DPC */
+ if (intstatus) {
+ bus->pollcnt++;
+ bus->ipend = true;
+
+ bus->dpc_sched = true;
+ if (bus->dpc_tsk)
+ complete(&bus->dpc_wait);
+ }
+ }
+
+ /* Update interrupt tracking */
+ bus->lastintrs = bus->intrcount;
+ }
+#ifdef BCMDBG
+ /* Poll for console output periodically */
+ if (drvr->busstate == BRCMF_BUS_DATA && bus->console_interval != 0) {
+ bus->console.count += BRCMF_WD_POLL_MS;
+ if (bus->console.count >= bus->console_interval) {
+ bus->console.count -= bus->console_interval;
+ /* Make sure backplane clock is on */
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+ if (brcmf_sdbrcm_readconsole(bus) < 0)
+ /* stop on error */
+ bus->console_interval = 0;
+ }
+ }
+#endif /* BCMDBG */
+
+ /* On idle timeout clear activity flag and/or turn off clock */
+ if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
+ if (++bus->idlecount >= bus->idletime) {
+ bus->idlecount = 0;
+ if (bus->activity) {
+ bus->activity = false;
+ brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
+ } else {
+ brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
+ }
+ }
+ }
+
+ up(&bus->sdsem);
+
+ return bus->ipend;
+}
+
+static bool brcmf_sdbrcm_chipmatch(u16 chipid)
+{
+ if (chipid == BCM4329_CHIP_ID)
+ return true;
+ return false;
+}
+
+static void brcmf_sdbrcm_release_malloc(struct brcmf_bus *bus)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ kfree(bus->rxbuf);
+ bus->rxctl = bus->rxbuf = NULL;
+ bus->rxlen = 0;
+
+ kfree(bus->databuf);
+ bus->databuf = NULL;
+}
+
+static bool brcmf_sdbrcm_probe_malloc(struct brcmf_bus *bus)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (bus->drvr->maxctl) {
+ bus->rxblen =
+ roundup((bus->drvr->maxctl + SDPCM_HDRLEN),
+ ALIGNMENT) + BRCMF_SDALIGN;
+ bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC);
+ if (!(bus->rxbuf))
+ goto fail;
+ }
+
+ /* Allocate buffer to receive glomed packet */
+ bus->databuf = kmalloc(MAX_DATA_BUF, GFP_ATOMIC);
+ if (!(bus->databuf)) {
+ /* release rxbuf which was already located as above */
+ if (!bus->rxblen)
+ kfree(bus->rxbuf);
+ goto fail;
+ }
+
+ /* Align the buffer */
+ if ((unsigned long)bus->databuf % BRCMF_SDALIGN)
+ bus->dataptr = bus->databuf + (BRCMF_SDALIGN -
+ ((unsigned long)bus->databuf % BRCMF_SDALIGN));
+ else
+ bus->dataptr = bus->databuf;
+
+ return true;
+
+fail:
+ return false;
+}
+
+/* SDIO Pad drive strength to select value mappings */
+struct sdiod_drive_str {
+ u8 strength; /* Pad Drive Strength in mA */
+ u8 sel; /* Chip-specific select value */
+};
+
+/* SDIO Drive Strength to sel value table for PMU Rev 1 */
+static const struct sdiod_drive_str sdiod_drive_strength_tab1[] = {
+ {
+ 4, 0x2}, {
+ 2, 0x3}, {
+ 1, 0x0}, {
+ 0, 0x0}
+ };
+
+/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */
+static const struct sdiod_drive_str sdiod_drive_strength_tab2[] = {
+ {
+ 12, 0x7}, {
+ 10, 0x6}, {
+ 8, 0x5}, {
+ 6, 0x4}, {
+ 4, 0x2}, {
+ 2, 0x1}, {
+ 0, 0x0}
+ };
+
+/* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */
+static const struct sdiod_drive_str sdiod_drive_strength_tab3[] = {
+ {
+ 32, 0x7}, {
+ 26, 0x6}, {
+ 22, 0x5}, {
+ 16, 0x4}, {
+ 12, 0x3}, {
+ 8, 0x2}, {
+ 4, 0x1}, {
+ 0, 0x0}
+ };
+
+#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
+
+static char *brcmf_chipname(uint chipid, char *buf, uint len)
+{
+ const char *fmt;
+
+ fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
+ snprintf(buf, len, fmt, chipid);
+ return buf;
+}
+
+static void brcmf_sdbrcm_sdiod_drive_strength_init(struct brcmf_bus *bus,
+ u32 drivestrength) {
+ struct sdiod_drive_str *str_tab = NULL;
+ u32 str_mask = 0;
+ u32 str_shift = 0;
+ char chn[8];
+
+ if (!(bus->ci->cccaps & CC_CAP_PMU))
+ return;
+
+ switch (SDIOD_DRVSTR_KEY(bus->ci->chip, bus->ci->pmurev)) {
+ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1):
+ str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab1;
+ str_mask = 0x30000000;
+ str_shift = 28;
+ break;
+ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2):
+ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3):
+ str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab2;
+ str_mask = 0x00003800;
+ str_shift = 11;
+ break;
+ case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8):
+ str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab3;
+ str_mask = 0x00003800;
+ str_shift = 11;
+ break;
+ default:
+ brcmf_dbg(ERROR, "No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
+ brcmf_chipname(bus->ci->chip, chn, 8),
+ bus->ci->chiprev, bus->ci->pmurev);
+ break;
+ }
+
+ if (str_tab != NULL) {
+ u32 drivestrength_sel = 0;
+ u32 cc_data_temp;
+ int i;
+
+ for (i = 0; str_tab[i].strength != 0; i++) {
+ if (drivestrength >= str_tab[i].strength) {
+ drivestrength_sel = str_tab[i].sel;
+ break;
+ }
+ }
+
+ brcmf_sdcard_reg_write(bus->sdiodev,
+ CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr),
+ 4, 1);
+ cc_data_temp = brcmf_sdcard_reg_read(bus->sdiodev,
+ CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr), 4);
+ cc_data_temp &= ~str_mask;
+ drivestrength_sel <<= str_shift;
+ cc_data_temp |= drivestrength_sel;
+ brcmf_sdcard_reg_write(bus->sdiodev,
+ CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr),
+ 4, cc_data_temp);
+
+ brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n",
+ drivestrength, cc_data_temp);
+ }
+}
+
+static int
+brcmf_sdbrcm_chip_recognition(struct brcmf_sdio_dev *sdiodev,
+ struct chip_info *ci, u32 regs)
+{
+ u32 regdata;
+
+ /*
+ * Get CC core rev
+ * Chipid is assume to be at offset 0 from regs arg
+ * For different chiptypes or old sdio hosts w/o chipcommon,
+ * other ways of recognition should be added here.
+ */
+ ci->cccorebase = regs;
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_CC_REG(ci->cccorebase, chipid), 4);
+ ci->chip = regdata & CID_ID_MASK;
+ ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
+
+ brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev);
+
+ /* Address of cores for new chips should be added here */
+ switch (ci->chip) {
+ case BCM4329_CHIP_ID:
+ ci->buscorebase = BCM4329_CORE_BUS_BASE;
+ ci->ramcorebase = BCM4329_CORE_SOCRAM_BASE;
+ ci->armcorebase = BCM4329_CORE_ARM_BASE;
+ ci->ramsize = BCM4329_RAMSIZE;
+ break;
+ default:
+ brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip);
+ return -ENODEV;
+ }
+
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(ci->cccorebase, sbidhigh), 4);
+ ci->ccrev = SBCOREREV(regdata);
+
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_CC_REG(ci->cccorebase, pmucapabilities), 4);
+ ci->pmurev = regdata & PCAP_REV_MASK;
+
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(ci->buscorebase, sbidhigh), 4);
+ ci->buscorerev = SBCOREREV(regdata);
+ ci->buscoretype = (regdata & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT;
+
+ brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
+ ci->ccrev, ci->pmurev, ci->buscorerev, ci->buscoretype);
+
+ /* get chipcommon capabilites */
+ ci->cccaps = brcmf_sdcard_reg_read(sdiodev,
+ CORE_CC_REG(ci->cccorebase, capabilities), 4);
+
+ return 0;
+}
+
+static int
+brcmf_sdbrcm_chip_attach(struct brcmf_bus *bus, u32 regs)
+{
+ struct chip_info *ci;
+ int err;
+ u8 clkval, clkset;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* alloc chip_info_t */
+ ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC);
+ if (NULL == ci)
+ return -ENOMEM;
+
+ /* bus/core/clk setup for register access */
+ /* Try forcing SDIO core to do ALPAvail request only */
+ clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
+ if (err) {
+ brcmf_dbg(ERROR, "error writing for HT off\n");
+ goto fail;
+ }
+
+ /* If register supported, wait for ALPAvail and then force ALP */
+ /* This may take up to 15 milliseconds */
+ clkval = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, NULL);
+ if ((clkval & ~SBSDIO_AVBITS) == clkset) {
+ SPINWAIT(((clkval =
+ brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR,
+ NULL)),
+ !SBSDIO_ALPAV(clkval)),
+ PMU_MAX_TRANSITION_DLY);
+ if (!SBSDIO_ALPAV(clkval)) {
+ brcmf_dbg(ERROR, "timeout on ALPAV wait, clkval 0x%02x\n",
+ clkval);
+ err = -EBUSY;
+ goto fail;
+ }
+ clkset = SBSDIO_FORCE_HW_CLKREQ_OFF |
+ SBSDIO_FORCE_ALP;
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR,
+ clkset, &err);
+ udelay(65);
+ } else {
+ brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
+ clkset, clkval);
+ err = -EACCES;
+ goto fail;
+ }
+
+ /* Also, disable the extra SDIO pull-ups */
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
+
+ err = brcmf_sdbrcm_chip_recognition(bus->sdiodev, ci, regs);
+ if (err)
+ goto fail;
+
+ /*
+ * Make sure any on-chip ARM is off (in case strapping is wrong),
+ * or downloaded code was already running.
+ */
+ brcmf_sdbrcm_chip_disablecore(bus->sdiodev, ci->armcorebase);
+
+ brcmf_sdcard_reg_write(bus->sdiodev,
+ CORE_CC_REG(ci->cccorebase, gpiopullup), 4, 0);
+ brcmf_sdcard_reg_write(bus->sdiodev,
+ CORE_CC_REG(ci->cccorebase, gpiopulldown), 4, 0);
+
+ /* Disable F2 to clear any intermediate frame state on the dongle */
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
+ SDIO_FUNC_ENABLE_1, NULL);
+
+ /* WAR: cmd52 backplane read so core HW will drop ALPReq */
+ clkval = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ 0, NULL);
+
+ /* Done with backplane-dependent accesses, can drop clock... */
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
+
+ bus->ci = ci;
+ return 0;
+fail:
+ bus->ci = NULL;
+ kfree(ci);
+ return err;
+}
+
+static bool
+brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
+{
+ u8 clkctl = 0;
+ int err = 0;
+ int reg_addr;
+ u32 reg_val;
+
+ bus->alp_only = true;
+
+ /* Return the window to backplane enumeration space for core access */
+ if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, SI_ENUM_BASE))
+ brcmf_dbg(ERROR, "FAILED to return to SI_ENUM_BASE\n");
+
+#ifdef BCMDBG
+ printk(KERN_DEBUG "F1 signature read @0x18000000=0x%4x\n",
+ brcmf_sdcard_reg_read(bus->sdiodev, SI_ENUM_BASE, 4));
+
+#endif /* BCMDBG */
+
+ /*
+ * Force PLL off until brcmf_sdbrcm_chip_attach()
+ * programs PLL control regs
+ */
+
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR,
+ BRCMF_INIT_CLKCTL1, &err);
+ if (!err)
+ clkctl =
+ brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, &err);
+
+ if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) {
+ brcmf_dbg(ERROR, "ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
+ err, BRCMF_INIT_CLKCTL1, clkctl);
+ goto fail;
+ }
+
+ if (brcmf_sdbrcm_chip_attach(bus, regsva)) {
+ brcmf_dbg(ERROR, "brcmf_sdbrcm_chip_attach failed!\n");
+ goto fail;
+ }
+
+ if (!brcmf_sdbrcm_chipmatch((u16) bus->ci->chip)) {
+ brcmf_dbg(ERROR, "unsupported chip: 0x%04x\n", bus->ci->chip);
+ goto fail;
+ }
+
+ brcmf_sdbrcm_sdiod_drive_strength_init(bus, SDIO_DRIVE_STRENGTH);
+
+ /* Get info on the ARM and SOCRAM cores... */
+ brcmf_sdcard_reg_read(bus->sdiodev,
+ CORE_SB(bus->ci->armcorebase, sbidhigh), 4);
+ bus->ramsize = bus->ci->ramsize;
+ if (!(bus->ramsize)) {
+ brcmf_dbg(ERROR, "failed to find SOCRAM memory!\n");
+ goto fail;
+ }
+
+ /* Set core control so an SDIO reset does a backplane reset */
+ reg_addr = bus->ci->buscorebase +
+ offsetof(struct sdpcmd_regs, corecontrol);
+ reg_val = brcmf_sdcard_reg_read(bus->sdiodev, reg_addr, sizeof(u32));
+ brcmf_sdcard_reg_write(bus->sdiodev, reg_addr, sizeof(u32),
+ reg_val | CC_BPRESEN);
+
+ brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
+
+ /* Locate an appropriately-aligned portion of hdrbuf */
+ bus->rxhdr = (u8 *) roundup((unsigned long)&bus->hdrbuf[0],
+ BRCMF_SDALIGN);
+
+ /* Set the poll and/or interrupt flags */
+ bus->intr = true;
+ bus->poll = false;
+ if (bus->poll)
+ bus->pollrate = 1;
+
+ return true;
+
+fail:
+ return false;
+}
+
+static bool brcmf_sdbrcm_probe_init(struct brcmf_bus *bus)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Disable F2 to clear any intermediate frame state on the dongle */
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
+ SDIO_FUNC_ENABLE_1, NULL);
+
+ bus->drvr->busstate = BRCMF_BUS_DOWN;
+ bus->sleeping = false;
+ bus->rxflow = false;
+
+ /* Done with backplane-dependent accesses, can drop clock... */
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
+
+ /* ...and initialize clock/power states */
+ bus->clkstate = CLK_SDONLY;
+ bus->idletime = BRCMF_IDLE_INTERVAL;
+ bus->idleclock = BRCMF_IDLE_ACTIVE;
+
+ /* Query the F2 block size, set roundup accordingly */
+ bus->blocksize = bus->sdiodev->func[2]->cur_blksize;
+ bus->roundup = min(max_roundup, bus->blocksize);
+
+ /* bus module does not support packet chaining */
+ bus->use_rxchain = false;
+ bus->sd_rxchain = false;
+
+ return true;
+}
+
+static int
+brcmf_sdbrcm_watchdog_thread(void *data)
+{
+ struct brcmf_bus *bus = (struct brcmf_bus *)data;
+
+ allow_signal(SIGTERM);
+ /* Run until signal received */
+ while (1) {
+ if (kthread_should_stop())
+ break;
+ if (!wait_for_completion_interruptible(&bus->watchdog_wait)) {
+ brcmf_sdbrcm_bus_watchdog(bus->drvr);
+ /* Count the tick for reference */
+ bus->drvr->tickcnt++;
+ } else
+ break;
+ }
+ return 0;
+}
+
+static void
+brcmf_sdbrcm_watchdog(unsigned long data)
+{
+ struct brcmf_bus *bus = (struct brcmf_bus *)data;
+
+ if (bus->watchdog_tsk) {
+ complete(&bus->watchdog_wait);
+ /* Reschedule the watchdog */
+ if (bus->wd_timer_valid)
+ mod_timer(&bus->timer,
+ jiffies + BRCMF_WD_POLL_MS * HZ / 1000);
+ }
+}
+
+static void
+brcmf_sdbrcm_chip_detach(struct brcmf_bus *bus)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ kfree(bus->ci);
+ bus->ci = NULL;
+}
+
+static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (bus->ci) {
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+ brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
+ brcmf_sdbrcm_chip_detach(bus);
+ if (bus->vars && bus->varsz)
+ kfree(bus->vars);
+ bus->vars = NULL;
+ }
+
+ brcmf_dbg(TRACE, "Disconnected\n");
+}
+
+/* Detach and free everything */
+static void brcmf_sdbrcm_release(struct brcmf_bus *bus)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (bus) {
+ /* De-register interrupt handler */
+ brcmf_sdcard_intr_dereg(bus->sdiodev);
+
+ if (bus->drvr) {
+ brcmf_detach(bus->drvr);
+ brcmf_sdbrcm_release_dongle(bus);
+ bus->drvr = NULL;
+ }
+
+ brcmf_sdbrcm_release_malloc(bus);
+
+ kfree(bus);
+ }
+
+ brcmf_dbg(TRACE, "Disconnected\n");
+}
+
+void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype,
+ u32 regsva, struct brcmf_sdio_dev *sdiodev)
+{
+ int ret;
+ struct brcmf_bus *bus;
+
+ /* Init global variables at run-time, not as part of the declaration.
+ * This is required to support init/de-init of the driver.
+ * Initialization
+ * of globals as part of the declaration results in non-deterministic
+ * behavior since the value of the globals may be different on the
+ * first time that the driver is initialized vs subsequent
+ * initializations.
+ */
+ brcmf_c_init();
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* We make an assumption about address window mappings:
+ * regsva == SI_ENUM_BASE*/
+
+ /* Allocate private bus interface state */
+ bus = kzalloc(sizeof(struct brcmf_bus), GFP_ATOMIC);
+ if (!bus)
+ goto fail;
+
+ bus->sdiodev = sdiodev;
+ sdiodev->bus = bus;
+ bus->txbound = BRCMF_TXBOUND;
+ bus->rxbound = BRCMF_RXBOUND;
+ bus->txminmax = BRCMF_TXMINMAX;
+ bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
+ bus->usebufpool = false; /* Use bufpool if allocated,
+ else use locally malloced rxbuf */
+
+ /* attempt to attach to the dongle */
+ if (!(brcmf_sdbrcm_probe_attach(bus, regsva))) {
+ brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_attach failed\n");
+ goto fail;
+ }
+
+ spin_lock_init(&bus->txqlock);
+ init_waitqueue_head(&bus->ctrl_wait);
+ init_waitqueue_head(&bus->dcmd_resp_wait);
+
+ /* Set up the watchdog timer */
+ init_timer(&bus->timer);
+ bus->timer.data = (unsigned long)bus;
+ bus->timer.function = brcmf_sdbrcm_watchdog;
+
+ /* Initialize thread based operation and lock */
+ sema_init(&bus->sdsem, 1);
+
+ /* Initialize watchdog thread */
+ init_completion(&bus->watchdog_wait);
+ bus->watchdog_tsk = kthread_run(brcmf_sdbrcm_watchdog_thread,
+ bus, "brcmf_watchdog");
+ if (IS_ERR(bus->watchdog_tsk)) {
+ printk(KERN_WARNING
+ "brcmf_watchdog thread failed to start\n");
+ bus->watchdog_tsk = NULL;
+ }
+ /* Initialize DPC thread */
+ init_completion(&bus->dpc_wait);
+ bus->dpc_tsk = kthread_run(brcmf_sdbrcm_dpc_thread,
+ bus, "brcmf_dpc");
+ if (IS_ERR(bus->dpc_tsk)) {
+ printk(KERN_WARNING
+ "brcmf_dpc thread failed to start\n");
+ bus->dpc_tsk = NULL;
+ }
+
+ /* Attach to the brcmf/OS/network interface */
+ bus->drvr = brcmf_attach(bus, SDPCM_RESERVE);
+ if (!bus->drvr) {
+ brcmf_dbg(ERROR, "brcmf_attach failed\n");
+ goto fail;
+ }
+
+ /* Allocate buffers */
+ if (!(brcmf_sdbrcm_probe_malloc(bus))) {
+ brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_malloc failed\n");
+ goto fail;
+ }
+
+ if (!(brcmf_sdbrcm_probe_init(bus))) {
+ brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_init failed\n");
+ goto fail;
+ }
+
+ /* Register interrupt callback, but mask it (not operational yet). */
+ brcmf_dbg(INTR, "disable SDIO interrupts (not interested yet)\n");
+ ret = brcmf_sdcard_intr_reg(bus->sdiodev);
+ if (ret != 0) {
+ brcmf_dbg(ERROR, "FAILED: sdcard_intr_reg returned %d\n", ret);
+ goto fail;
+ }
+ brcmf_dbg(INTR, "registered SDIO interrupt function ok\n");
+
+ brcmf_dbg(INFO, "completed!!\n");
+
+ /* if firmware path present try to download and bring up bus */
+ ret = brcmf_bus_start(bus->drvr);
+ if (ret != 0) {
+ if (ret == -ENOLINK) {
+ brcmf_dbg(ERROR, "dongle is not responding\n");
+ goto fail;
+ }
+ }
+ /* Ok, have the per-port tell the stack we're open for business */
+ if (brcmf_net_attach(bus->drvr, 0) != 0) {
+ brcmf_dbg(ERROR, "Net attach failed!!\n");
+ goto fail;
+ }
+
+ return bus;
+
+fail:
+ brcmf_sdbrcm_release(bus);
+ return NULL;
+}
+
+void brcmf_sdbrcm_disconnect(void *ptr)
+{
+ struct brcmf_bus *bus = (struct brcmf_bus *)ptr;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (bus)
+ brcmf_sdbrcm_release(bus);
+
+ brcmf_dbg(TRACE, "Disconnected\n");
+}
+
+struct device *brcmf_bus_get_device(struct brcmf_bus *bus)
+{
+ return &bus->sdiodev->func[2]->dev;
+}
+
+void
+brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick)
+{
+ /* don't start the wd until fw is loaded */
+ if (bus->drvr->busstate == BRCMF_BUS_DOWN)
+ return;
+
+ /* Totally stop the timer */
+ if (!wdtick && bus->wd_timer_valid == true) {
+ del_timer_sync(&bus->timer);
+ bus->wd_timer_valid = false;
+ bus->save_ms = wdtick;
+ return;
+ }
+
+ if (wdtick) {
+ if (bus->save_ms != BRCMF_WD_POLL_MS) {
+ if (bus->wd_timer_valid == true)
+ /* Stop timer and restart at new value */
+ del_timer_sync(&bus->timer);
+
+ /* Create timer again when watchdog period is
+ dynamically changed or in the first instance
+ */
+ bus->timer.expires =
+ jiffies + BRCMF_WD_POLL_MS * HZ / 1000;
+ add_timer(&bus->timer);
+
+ } else {
+ /* Re arm the timer, at last watchdog period */
+ mod_timer(&bus->timer,
+ jiffies + BRCMF_WD_POLL_MS * HZ / 1000);
+ }
+
+ bus->wd_timer_valid = true;
+ bus->save_ms = wdtick;
+ }
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
new file mode 100644
index 000000000000..726fa8981113
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_SDH_H_
+#define _BRCM_SDH_H_
+
+#include <linux/skbuff.h>
+
+#define SDIO_FUNC_0 0
+#define SDIO_FUNC_1 1
+#define SDIO_FUNC_2 2
+
+#define SDIOD_FBR_SIZE 0x100
+
+/* io_en */
+#define SDIO_FUNC_ENABLE_1 0x02
+#define SDIO_FUNC_ENABLE_2 0x04
+
+/* io_rdys */
+#define SDIO_FUNC_READY_1 0x02
+#define SDIO_FUNC_READY_2 0x04
+
+/* intr_status */
+#define INTR_STATUS_FUNC1 0x2
+#define INTR_STATUS_FUNC2 0x4
+
+/* Maximum number of I/O funcs */
+#define SDIOD_MAX_IOFUNCS 7
+
+/* as of sdiod rev 0, supports 3 functions */
+#define SBSDIO_NUM_FUNCTION 3
+
+/* function 1 miscellaneous registers */
+
+/* sprom command and status */
+#define SBSDIO_SPROM_CS 0x10000
+/* sprom info register */
+#define SBSDIO_SPROM_INFO 0x10001
+/* sprom indirect access data byte 0 */
+#define SBSDIO_SPROM_DATA_LOW 0x10002
+/* sprom indirect access data byte 1 */
+#define SBSDIO_SPROM_DATA_HIGH 0x10003
+/* sprom indirect access addr byte 0 */
+#define SBSDIO_SPROM_ADDR_LOW 0x10004
+/* sprom indirect access addr byte 0 */
+#define SBSDIO_SPROM_ADDR_HIGH 0x10005
+/* xtal_pu (gpio) output */
+#define SBSDIO_CHIP_CTRL_DATA 0x10006
+/* xtal_pu (gpio) enable */
+#define SBSDIO_CHIP_CTRL_EN 0x10007
+/* rev < 7, watermark for sdio device */
+#define SBSDIO_WATERMARK 0x10008
+/* control busy signal generation */
+#define SBSDIO_DEVICE_CTL 0x10009
+
+/* SB Address Window Low (b15) */
+#define SBSDIO_FUNC1_SBADDRLOW 0x1000A
+/* SB Address Window Mid (b23:b16) */
+#define SBSDIO_FUNC1_SBADDRMID 0x1000B
+/* SB Address Window High (b31:b24) */
+#define SBSDIO_FUNC1_SBADDRHIGH 0x1000C
+/* Frame Control (frame term/abort) */
+#define SBSDIO_FUNC1_FRAMECTRL 0x1000D
+/* ChipClockCSR (ALP/HT ctl/status) */
+#define SBSDIO_FUNC1_CHIPCLKCSR 0x1000E
+/* SdioPullUp (on cmd, d0-d2) */
+#define SBSDIO_FUNC1_SDIOPULLUP 0x1000F
+/* Write Frame Byte Count Low */
+#define SBSDIO_FUNC1_WFRAMEBCLO 0x10019
+/* Write Frame Byte Count High */
+#define SBSDIO_FUNC1_WFRAMEBCHI 0x1001A
+/* Read Frame Byte Count Low */
+#define SBSDIO_FUNC1_RFRAMEBCLO 0x1001B
+/* Read Frame Byte Count High */
+#define SBSDIO_FUNC1_RFRAMEBCHI 0x1001C
+
+#define SBSDIO_FUNC1_MISC_REG_START 0x10000 /* f1 misc register start */
+#define SBSDIO_FUNC1_MISC_REG_LIMIT 0x1001C /* f1 misc register end */
+
+/* function 1 OCP space */
+
+/* sb offset addr is <= 15 bits, 32k */
+#define SBSDIO_SB_OFT_ADDR_MASK 0x07FFF
+#define SBSDIO_SB_OFT_ADDR_LIMIT 0x08000
+/* with b15, maps to 32-bit SB access */
+#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x08000
+
+/* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */
+
+#define SBSDIO_SBADDRLOW_MASK 0x80 /* Valid bits in SBADDRLOW */
+#define SBSDIO_SBADDRMID_MASK 0xff /* Valid bits in SBADDRMID */
+#define SBSDIO_SBADDRHIGH_MASK 0xffU /* Valid bits in SBADDRHIGH */
+/* Address bits from SBADDR regs */
+#define SBSDIO_SBWINDOW_MASK 0xffff8000
+
+#define SDIOH_READ 0 /* Read request */
+#define SDIOH_WRITE 1 /* Write request */
+
+#define SDIOH_DATA_FIX 0 /* Fixed addressing */
+#define SDIOH_DATA_INC 1 /* Incremental addressing */
+
+/* internal return code */
+#define SUCCESS 0
+#define ERROR 1
+
+struct brcmf_sdreg {
+ int func;
+ int offset;
+ int value;
+};
+
+struct brcmf_sdio_dev {
+ struct sdio_func *func[SDIO_MAX_FUNCS];
+ u8 num_funcs; /* Supported funcs on client */
+ u32 func_cis_ptr[SDIOD_MAX_IOFUNCS];
+ u32 sbwad; /* Save backplane window address */
+ bool regfail; /* status of last reg_r/w call */
+ void *bus;
+ atomic_t suspend; /* suspend flag */
+ wait_queue_head_t request_byte_wait;
+ wait_queue_head_t request_word_wait;
+ wait_queue_head_t request_packet_wait;
+ wait_queue_head_t request_buffer_wait;
+
+};
+
+/* Register/deregister device interrupt handler. */
+extern int
+brcmf_sdcard_intr_reg(struct brcmf_sdio_dev *sdiodev);
+
+extern int brcmf_sdcard_intr_dereg(struct brcmf_sdio_dev *sdiodev);
+
+/* Access SDIO address space (e.g. CCCR) using CMD52 (single-byte interface).
+ * fn: function number
+ * addr: unmodified SDIO-space address
+ * data: data byte to write
+ * err: pointer to error code (or NULL)
+ */
+extern u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_dev *sdiodev, uint func,
+ u32 addr, int *err);
+extern void brcmf_sdcard_cfg_write(struct brcmf_sdio_dev *sdiodev, uint func,
+ u32 addr, u8 data, int *err);
+
+/* Synchronous access to device (client) core registers via CMD53 to F1.
+ * addr: backplane address (i.e. >= regsva from attach)
+ * size: register width in bytes (2 or 4)
+ * data: data for register write
+ */
+extern u32
+brcmf_sdcard_reg_read(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size);
+
+extern u32
+brcmf_sdcard_reg_write(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size,
+ u32 data);
+
+/* Indicate if last reg read/write failed */
+extern bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev);
+
+/* Buffer transfer to/from device (client) core via cmd53.
+ * fn: function number
+ * addr: backplane address (i.e. >= regsva from attach)
+ * flags: backplane width, address increment, sync/async
+ * buf: pointer to memory data buffer
+ * nbytes: number of bytes to transfer to/from buf
+ * pkt: pointer to packet associated with buf (if any)
+ * complete: callback function for command completion (async only)
+ * handle: handle for completion callback (first arg in callback)
+ * Returns 0 or error code.
+ * NOTE: Async operation is not currently supported.
+ */
+extern int
+brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
+ uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt);
+extern int
+brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
+ uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt);
+
+/* Flags bits */
+
+/* Four-byte target (backplane) width (vs. two-byte) */
+#define SDIO_REQ_4BYTE 0x1
+/* Fixed address (FIFO) (vs. incrementing address) */
+#define SDIO_REQ_FIXED 0x2
+/* Async request (vs. sync request) */
+#define SDIO_REQ_ASYNC 0x4
+
+/* Read/write to memory block (F1, no FIFO) via CMD53 (sync only).
+ * rw: read or write (0/1)
+ * addr: direct SDIO address
+ * buf: pointer to memory data buffer
+ * nbytes: number of bytes to transfer to/from buf
+ * Returns 0 or error code.
+ */
+extern int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw,
+ u32 addr, u8 *buf, uint nbytes);
+
+/* Issue an abort to the specified function */
+extern int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn);
+
+/* platform specific/high level functions */
+extern int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev);
+extern int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev);
+
+extern int brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev,
+ u32 address);
+
+/* attach, return handler on success, NULL if failed.
+ * The handler shall be provided by all subsequent calls. No local cache
+ * cfghdl points to the starting address of pci device mapped memory
+ */
+extern int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev);
+extern void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev);
+
+/* read or write one byte using cmd52 */
+extern int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw,
+ uint fnc, uint addr, u8 *byte);
+
+/* read or write 2/4 bytes using cmd53 */
+extern int
+brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev,
+ uint rw, uint fnc, uint addr,
+ u32 *word, uint nbyte);
+
+/* read or write any buffer using cmd53 */
+extern int
+brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev,
+ uint fix_inc, uint rw, uint fnc_num,
+ u32 addr, uint regwidth,
+ u32 buflen, u8 *buffer, struct sk_buff *pkt);
+
+/* Watchdog timer interface for pm ops */
+extern void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev,
+ bool enable);
+
+extern void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype,
+ u32 regsva, struct brcmf_sdio_dev *sdiodev);
+extern void brcmf_sdbrcm_disconnect(void *ptr);
+extern void brcmf_sdbrcm_isr(void *arg);
+#endif /* _BRCM_SDH_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
new file mode 100644
index 000000000000..5eddabe5228a
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -0,0 +1,3868 @@
+/*
+ * Copyright (c) 2010 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.
+ */
+
+/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
+
+#include <linux/kernel.h>
+#include <linux/if_arp.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#include <linux/bitops.h>
+#include <linux/etherdevice.h>
+#include <linux/ieee80211.h>
+#include <linux/uaccess.h>
+#include <net/cfg80211.h>
+
+#include <brcmu_utils.h>
+#include <defs.h>
+#include <brcmu_wifi.h>
+#include "dhd.h"
+#include "wl_cfg80211.h"
+
+#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
+ (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
+
+static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255};
+
+static u32 brcmf_dbg_level = WL_DBG_ERR;
+
+static void brcmf_set_drvdata(struct brcmf_cfg80211_dev *dev, void *data)
+{
+ dev->driver_data = data;
+}
+
+static void *brcmf_get_drvdata(struct brcmf_cfg80211_dev *dev)
+{
+ void *data = NULL;
+
+ if (dev)
+ data = dev->driver_data;
+ return data;
+}
+
+static
+struct brcmf_cfg80211_priv *brcmf_priv_get(struct brcmf_cfg80211_dev *cfg_dev)
+{
+ struct brcmf_cfg80211_iface *ci = brcmf_get_drvdata(cfg_dev);
+ return ci->cfg_priv;
+}
+
+static bool check_sys_up(struct wiphy *wiphy)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
+ if (!test_bit(WL_STATUS_READY, &cfg_priv->status)) {
+ WL_INFO("device is not ready : status (%d)\n",
+ (int)cfg_priv->status);
+ return false;
+ }
+ return true;
+}
+
+#define CHAN2G(_channel, _freq, _flags) { \
+ .band = IEEE80211_BAND_2GHZ, \
+ .center_freq = (_freq), \
+ .hw_value = (_channel), \
+ .flags = (_flags), \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+}
+
+#define CHAN5G(_channel, _flags) { \
+ .band = IEEE80211_BAND_5GHZ, \
+ .center_freq = 5000 + (5 * (_channel)), \
+ .hw_value = (_channel), \
+ .flags = (_flags), \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+}
+
+#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
+#define RATETAB_ENT(_rateid, _flags) \
+ { \
+ .bitrate = RATE_TO_BASE100KBPS(_rateid), \
+ .hw_value = (_rateid), \
+ .flags = (_flags), \
+ }
+
+static struct ieee80211_rate __wl_rates[] = {
+ RATETAB_ENT(BRCM_RATE_1M, 0),
+ RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATETAB_ENT(BRCM_RATE_6M, 0),
+ RATETAB_ENT(BRCM_RATE_9M, 0),
+ RATETAB_ENT(BRCM_RATE_12M, 0),
+ RATETAB_ENT(BRCM_RATE_18M, 0),
+ RATETAB_ENT(BRCM_RATE_24M, 0),
+ RATETAB_ENT(BRCM_RATE_36M, 0),
+ RATETAB_ENT(BRCM_RATE_48M, 0),
+ RATETAB_ENT(BRCM_RATE_54M, 0),
+};
+
+#define wl_a_rates (__wl_rates + 4)
+#define wl_a_rates_size 8
+#define wl_g_rates (__wl_rates + 0)
+#define wl_g_rates_size 12
+
+static struct ieee80211_channel __wl_2ghz_channels[] = {
+ CHAN2G(1, 2412, 0),
+ CHAN2G(2, 2417, 0),
+ CHAN2G(3, 2422, 0),
+ CHAN2G(4, 2427, 0),
+ CHAN2G(5, 2432, 0),
+ CHAN2G(6, 2437, 0),
+ CHAN2G(7, 2442, 0),
+ CHAN2G(8, 2447, 0),
+ CHAN2G(9, 2452, 0),
+ CHAN2G(10, 2457, 0),
+ CHAN2G(11, 2462, 0),
+ CHAN2G(12, 2467, 0),
+ CHAN2G(13, 2472, 0),
+ CHAN2G(14, 2484, 0),
+};
+
+static struct ieee80211_channel __wl_5ghz_a_channels[] = {
+ CHAN5G(34, 0), CHAN5G(36, 0),
+ CHAN5G(38, 0), CHAN5G(40, 0),
+ CHAN5G(42, 0), CHAN5G(44, 0),
+ CHAN5G(46, 0), CHAN5G(48, 0),
+ CHAN5G(52, 0), CHAN5G(56, 0),
+ CHAN5G(60, 0), CHAN5G(64, 0),
+ CHAN5G(100, 0), CHAN5G(104, 0),
+ CHAN5G(108, 0), CHAN5G(112, 0),
+ CHAN5G(116, 0), CHAN5G(120, 0),
+ CHAN5G(124, 0), CHAN5G(128, 0),
+ CHAN5G(132, 0), CHAN5G(136, 0),
+ CHAN5G(140, 0), CHAN5G(149, 0),
+ CHAN5G(153, 0), CHAN5G(157, 0),
+ CHAN5G(161, 0), CHAN5G(165, 0),
+ CHAN5G(184, 0), CHAN5G(188, 0),
+ CHAN5G(192, 0), CHAN5G(196, 0),
+ CHAN5G(200, 0), CHAN5G(204, 0),
+ CHAN5G(208, 0), CHAN5G(212, 0),
+ CHAN5G(216, 0),
+};
+
+static struct ieee80211_channel __wl_5ghz_n_channels[] = {
+ CHAN5G(32, 0), CHAN5G(34, 0),
+ CHAN5G(36, 0), CHAN5G(38, 0),
+ CHAN5G(40, 0), CHAN5G(42, 0),
+ CHAN5G(44, 0), CHAN5G(46, 0),
+ CHAN5G(48, 0), CHAN5G(50, 0),
+ CHAN5G(52, 0), CHAN5G(54, 0),
+ CHAN5G(56, 0), CHAN5G(58, 0),
+ CHAN5G(60, 0), CHAN5G(62, 0),
+ CHAN5G(64, 0), CHAN5G(66, 0),
+ CHAN5G(68, 0), CHAN5G(70, 0),
+ CHAN5G(72, 0), CHAN5G(74, 0),
+ CHAN5G(76, 0), CHAN5G(78, 0),
+ CHAN5G(80, 0), CHAN5G(82, 0),
+ CHAN5G(84, 0), CHAN5G(86, 0),
+ CHAN5G(88, 0), CHAN5G(90, 0),
+ CHAN5G(92, 0), CHAN5G(94, 0),
+ CHAN5G(96, 0), CHAN5G(98, 0),
+ CHAN5G(100, 0), CHAN5G(102, 0),
+ CHAN5G(104, 0), CHAN5G(106, 0),
+ CHAN5G(108, 0), CHAN5G(110, 0),
+ CHAN5G(112, 0), CHAN5G(114, 0),
+ CHAN5G(116, 0), CHAN5G(118, 0),
+ CHAN5G(120, 0), CHAN5G(122, 0),
+ CHAN5G(124, 0), CHAN5G(126, 0),
+ CHAN5G(128, 0), CHAN5G(130, 0),
+ CHAN5G(132, 0), CHAN5G(134, 0),
+ CHAN5G(136, 0), CHAN5G(138, 0),
+ CHAN5G(140, 0), CHAN5G(142, 0),
+ CHAN5G(144, 0), CHAN5G(145, 0),
+ CHAN5G(146, 0), CHAN5G(147, 0),
+ CHAN5G(148, 0), CHAN5G(149, 0),
+ CHAN5G(150, 0), CHAN5G(151, 0),
+ CHAN5G(152, 0), CHAN5G(153, 0),
+ CHAN5G(154, 0), CHAN5G(155, 0),
+ CHAN5G(156, 0), CHAN5G(157, 0),
+ CHAN5G(158, 0), CHAN5G(159, 0),
+ CHAN5G(160, 0), CHAN5G(161, 0),
+ CHAN5G(162, 0), CHAN5G(163, 0),
+ CHAN5G(164, 0), CHAN5G(165, 0),
+ CHAN5G(166, 0), CHAN5G(168, 0),
+ CHAN5G(170, 0), CHAN5G(172, 0),
+ CHAN5G(174, 0), CHAN5G(176, 0),
+ CHAN5G(178, 0), CHAN5G(180, 0),
+ CHAN5G(182, 0), CHAN5G(184, 0),
+ CHAN5G(186, 0), CHAN5G(188, 0),
+ CHAN5G(190, 0), CHAN5G(192, 0),
+ CHAN5G(194, 0), CHAN5G(196, 0),
+ CHAN5G(198, 0), CHAN5G(200, 0),
+ CHAN5G(202, 0), CHAN5G(204, 0),
+ CHAN5G(206, 0), CHAN5G(208, 0),
+ CHAN5G(210, 0), CHAN5G(212, 0),
+ CHAN5G(214, 0), CHAN5G(216, 0),
+ CHAN5G(218, 0), CHAN5G(220, 0),
+ CHAN5G(222, 0), CHAN5G(224, 0),
+ CHAN5G(226, 0), CHAN5G(228, 0),
+};
+
+static struct ieee80211_supported_band __wl_band_2ghz = {
+ .band = IEEE80211_BAND_2GHZ,
+ .channels = __wl_2ghz_channels,
+ .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
+ .bitrates = wl_g_rates,
+ .n_bitrates = wl_g_rates_size,
+};
+
+static struct ieee80211_supported_band __wl_band_5ghz_a = {
+ .band = IEEE80211_BAND_5GHZ,
+ .channels = __wl_5ghz_a_channels,
+ .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
+ .bitrates = wl_a_rates,
+ .n_bitrates = wl_a_rates_size,
+};
+
+static struct ieee80211_supported_band __wl_band_5ghz_n = {
+ .band = IEEE80211_BAND_5GHZ,
+ .channels = __wl_5ghz_n_channels,
+ .n_channels = ARRAY_SIZE(__wl_5ghz_n_channels),
+ .bitrates = wl_a_rates,
+ .n_bitrates = wl_a_rates_size,
+};
+
+static const u32 __wl_cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+ WLAN_CIPHER_SUITE_AES_CMAC,
+};
+
+/* tag_ID/length/value_buffer tuple */
+struct brcmf_tlv {
+ u8 id;
+ u8 len;
+ u8 data[1];
+};
+
+/* Quarter dBm units to mW
+ * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
+ * Table is offset so the last entry is largest mW value that fits in
+ * a u16.
+ */
+
+#define QDBM_OFFSET 153 /* Offset for first entry */
+#define QDBM_TABLE_LEN 40 /* Table size */
+
+/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
+ * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
+ */
+#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
+
+/* Largest mW value that will round down to the last table entry,
+ * QDBM_OFFSET + QDBM_TABLE_LEN-1.
+ * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
+ * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
+ */
+#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
+
+static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
+/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
+/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
+/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
+/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
+/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
+/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
+};
+
+static u16 brcmf_qdbm_to_mw(u8 qdbm)
+{
+ uint factor = 1;
+ int idx = qdbm - QDBM_OFFSET;
+
+ if (idx >= QDBM_TABLE_LEN)
+ /* clamp to max u16 mW value */
+ return 0xFFFF;
+
+ /* scale the qdBm index up to the range of the table 0-40
+ * where an offset of 40 qdBm equals a factor of 10 mW.
+ */
+ while (idx < 0) {
+ idx += 40;
+ factor *= 10;
+ }
+
+ /* return the mW value scaled down to the correct factor of 10,
+ * adding in factor/2 to get proper rounding.
+ */
+ return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
+}
+
+static u8 brcmf_mw_to_qdbm(u16 mw)
+{
+ u8 qdbm;
+ int offset;
+ uint mw_uint = mw;
+ uint boundary;
+
+ /* handle boundary case */
+ if (mw_uint <= 1)
+ return 0;
+
+ offset = QDBM_OFFSET;
+
+ /* move mw into the range of the table */
+ while (mw_uint < QDBM_TABLE_LOW_BOUND) {
+ mw_uint *= 10;
+ offset -= 40;
+ }
+
+ for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
+ boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
+ nqdBm_to_mW_map[qdbm]) / 2;
+ if (mw_uint < boundary)
+ break;
+ }
+
+ qdbm += (u8) offset;
+
+ return qdbm;
+}
+
+/* function for reading/writing a single u32 from/to the dongle */
+static int
+brcmf_exec_dcmd_u32(struct net_device *ndev, u32 cmd, u32 *par)
+{
+ int err;
+ __le32 par_le = cpu_to_le32(*par);
+
+ err = brcmf_exec_dcmd(ndev, cmd, &par_le, sizeof(__le32));
+ *par = le32_to_cpu(par_le);
+
+ return err;
+}
+
+static void convert_key_from_CPU(struct brcmf_wsec_key *key,
+ struct brcmf_wsec_key_le *key_le)
+{
+ key_le->index = cpu_to_le32(key->index);
+ key_le->len = cpu_to_le32(key->len);
+ key_le->algo = cpu_to_le32(key->algo);
+ key_le->flags = cpu_to_le32(key->flags);
+ key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
+ key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
+ key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
+ memcpy(key_le->data, key->data, sizeof(key->data));
+ memcpy(key_le->ea, key->ea, sizeof(key->ea));
+}
+
+static int send_key_to_dongle(struct net_device *ndev,
+ struct brcmf_wsec_key *key)
+{
+ int err;
+ struct brcmf_wsec_key_le key_le;
+
+ convert_key_from_CPU(key, &key_le);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_KEY, &key_le, sizeof(key_le));
+ if (err)
+ WL_ERR("WLC_SET_KEY error (%d)\n", err);
+ return err;
+}
+
+static s32
+brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
+ struct wireless_dev *wdev;
+ s32 infra = 0;
+ s32 err = 0;
+
+ WL_TRACE("Enter\n");
+ if (!check_sys_up(wiphy))
+ return -EIO;
+
+ switch (type) {
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_WDS:
+ WL_ERR("type (%d) : currently we do not support this type\n",
+ type);
+ return -EOPNOTSUPP;
+ case NL80211_IFTYPE_ADHOC:
+ cfg_priv->conf->mode = WL_MODE_IBSS;
+ infra = 0;
+ break;
+ case NL80211_IFTYPE_STATION:
+ cfg_priv->conf->mode = WL_MODE_BSS;
+ infra = 1;
+ break;
+ default:
+ err = -EINVAL;
+ goto done;
+ }
+
+ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra);
+ if (err) {
+ WL_ERR("WLC_SET_INFRA error (%d)\n", err);
+ err = -EAGAIN;
+ } else {
+ wdev = ndev->ieee80211_ptr;
+ wdev->iftype = type;
+ }
+
+ WL_INFO("IF Type = %s\n",
+ (cfg_priv->conf->mode == WL_MODE_IBSS) ? "Adhoc" : "Infra");
+
+done:
+ WL_TRACE("Exit\n");
+
+ return err;
+}
+
+static s32 brcmf_dev_intvar_set(struct net_device *ndev, s8 *name, s32 val)
+{
+ s8 buf[BRCMF_DCMD_SMLEN];
+ u32 len;
+ s32 err = 0;
+ __le32 val_le;
+
+ val_le = cpu_to_le32(val);
+ len = brcmf_c_mkiovar(name, (char *)(&val_le), sizeof(val_le), buf,
+ sizeof(buf));
+ BUG_ON(!len);
+
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, buf, len);
+ if (err)
+ WL_ERR("error (%d)\n", err);
+
+ return err;
+}
+
+static s32
+brcmf_dev_intvar_get(struct net_device *ndev, s8 *name, s32 *retval)
+{
+ union {
+ s8 buf[BRCMF_DCMD_SMLEN];
+ __le32 val;
+ } var;
+ u32 len;
+ u32 data_null;
+ s32 err = 0;
+
+ len =
+ brcmf_c_mkiovar(name, (char *)(&data_null), 0, (char *)(&var),
+ sizeof(var.buf));
+ BUG_ON(!len);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, &var, len);
+ if (err)
+ WL_ERR("error (%d)\n", err);
+
+ *retval = le32_to_cpu(var.val);
+
+ return err;
+}
+
+static void brcmf_set_mpc(struct net_device *ndev, int mpc)
+{
+ s32 err = 0;
+ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
+
+ if (test_bit(WL_STATUS_READY, &cfg_priv->status)) {
+ err = brcmf_dev_intvar_set(ndev, "mpc", mpc);
+ if (err) {
+ WL_ERR("fail to set mpc\n");
+ return;
+ }
+ WL_INFO("MPC : %d\n", mpc);
+ }
+}
+
+static void wl_iscan_prep(struct brcmf_scan_params_le *params_le,
+ struct brcmf_ssid *ssid)
+{
+ memcpy(params_le->bssid, ether_bcast, ETH_ALEN);
+ params_le->bss_type = DOT11_BSSTYPE_ANY;
+ params_le->scan_type = 0;
+ params_le->channel_num = 0;
+ params_le->nprobes = cpu_to_le32(-1);
+ params_le->active_time = cpu_to_le32(-1);
+ params_le->passive_time = cpu_to_le32(-1);
+ params_le->home_time = cpu_to_le32(-1);
+ if (ssid && ssid->SSID_len)
+ memcpy(&params_le->ssid_le, ssid, sizeof(struct brcmf_ssid));
+}
+
+static s32
+brcmf_dev_iovar_setbuf(struct net_device *ndev, s8 * iovar, void *param,
+ s32 paramlen, void *bufptr, s32 buflen)
+{
+ s32 iolen;
+
+ iolen = brcmf_c_mkiovar(iovar, param, paramlen, bufptr, buflen);
+ BUG_ON(!iolen);
+
+ return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, bufptr, iolen);
+}
+
+static s32
+brcmf_dev_iovar_getbuf(struct net_device *ndev, s8 * iovar, void *param,
+ s32 paramlen, void *bufptr, s32 buflen)
+{
+ s32 iolen;
+
+ iolen = brcmf_c_mkiovar(iovar, param, paramlen, bufptr, buflen);
+ BUG_ON(!iolen);
+
+ return brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, bufptr, buflen);
+}
+
+static s32
+brcmf_run_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan,
+ struct brcmf_ssid *ssid, u16 action)
+{
+ s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
+ offsetof(struct brcmf_iscan_params_le, params_le);
+ struct brcmf_iscan_params_le *params;
+ s32 err = 0;
+
+ if (ssid && ssid->SSID_len)
+ params_size += sizeof(struct brcmf_ssid);
+ params = kzalloc(params_size, GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+ BUG_ON(params_size >= BRCMF_DCMD_SMLEN);
+
+ wl_iscan_prep(&params->params_le, ssid);
+
+ params->version = cpu_to_le32(BRCMF_ISCAN_REQ_VERSION);
+ params->action = cpu_to_le16(action);
+ params->scan_duration = cpu_to_le16(0);
+
+ err = brcmf_dev_iovar_setbuf(iscan->ndev, "iscan", params, params_size,
+ iscan->dcmd_buf, BRCMF_DCMD_SMLEN);
+ if (err) {
+ if (err == -EBUSY)
+ WL_INFO("system busy : iscan canceled\n");
+ else
+ WL_ERR("error (%d)\n", err);
+ }
+
+ kfree(params);
+ return err;
+}
+
+static s32 brcmf_do_iscan(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv);
+ struct net_device *ndev = cfg_to_ndev(cfg_priv);
+ struct brcmf_ssid ssid;
+ __le32 passive_scan;
+ s32 err = 0;
+
+ /* Broadcast scan by default */
+ memset(&ssid, 0, sizeof(ssid));
+
+ iscan->state = WL_ISCAN_STATE_SCANING;
+
+ passive_scan = cfg_priv->active_scan ? 0 : cpu_to_le32(1);
+ err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCMF_C_SET_PASSIVE_SCAN,
+ &passive_scan, sizeof(passive_scan));
+ if (err) {
+ WL_ERR("error (%d)\n", err);
+ return err;
+ }
+ brcmf_set_mpc(ndev, 0);
+ cfg_priv->iscan_kickstart = true;
+ err = brcmf_run_iscan(iscan, &ssid, BRCMF_SCAN_ACTION_START);
+ if (err) {
+ brcmf_set_mpc(ndev, 1);
+ cfg_priv->iscan_kickstart = false;
+ return err;
+ }
+ mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
+ iscan->timer_on = 1;
+ return err;
+}
+
+static s32
+__brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_scan_request *request,
+ struct cfg80211_ssid *this_ssid)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
+ struct cfg80211_ssid *ssids;
+ struct brcmf_cfg80211_scan_req *sr = cfg_priv->scan_req_int;
+ __le32 passive_scan;
+ bool iscan_req;
+ bool spec_scan;
+ s32 err = 0;
+ u32 SSID_len;
+
+ if (test_bit(WL_STATUS_SCANNING, &cfg_priv->status)) {
+ WL_ERR("Scanning already : status (%lu)\n", cfg_priv->status);
+ return -EAGAIN;
+ }
+ if (test_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status)) {
+ WL_ERR("Scanning being aborted : status (%lu)\n",
+ cfg_priv->status);
+ return -EAGAIN;
+ }
+ if (test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) {
+ WL_ERR("Connecting : status (%lu)\n",
+ cfg_priv->status);
+ return -EAGAIN;
+ }
+
+ iscan_req = false;
+ spec_scan = false;
+ if (request) {
+ /* scan bss */
+ ssids = request->ssids;
+ if (cfg_priv->iscan_on && (!ssids || !ssids->ssid_len))
+ iscan_req = true;
+ } else {
+ /* scan in ibss */
+ /* we don't do iscan in ibss */
+ ssids = this_ssid;
+ }
+
+ cfg_priv->scan_request = request;
+ set_bit(WL_STATUS_SCANNING, &cfg_priv->status);
+ if (iscan_req) {
+ err = brcmf_do_iscan(cfg_priv);
+ if (!err)
+ return err;
+ else
+ goto scan_out;
+ } else {
+ WL_SCAN("ssid \"%s\", ssid_len (%d)\n",
+ ssids->ssid, ssids->ssid_len);
+ memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
+ SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
+ sr->ssid_le.SSID_len = cpu_to_le32(0);
+ if (SSID_len) {
+ memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
+ sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
+ spec_scan = true;
+ } else {
+ WL_SCAN("Broadcast scan\n");
+ }
+
+ passive_scan = cfg_priv->active_scan ? 0 : cpu_to_le32(1);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN,
+ &passive_scan, sizeof(passive_scan));
+ if (err) {
+ WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
+ goto scan_out;
+ }
+ brcmf_set_mpc(ndev, 0);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN, &sr->ssid_le,
+ sizeof(sr->ssid_le));
+ if (err) {
+ if (err == -EBUSY)
+ WL_INFO("system busy : scan for \"%s\" "
+ "canceled\n", sr->ssid_le.SSID);
+ else
+ WL_ERR("WLC_SCAN error (%d)\n", err);
+
+ brcmf_set_mpc(ndev, 1);
+ goto scan_out;
+ }
+ }
+
+ return 0;
+
+scan_out:
+ clear_bit(WL_STATUS_SCANNING, &cfg_priv->status);
+ cfg_priv->scan_request = NULL;
+ return err;
+}
+
+static s32
+brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_scan_request *request)
+{
+ s32 err = 0;
+
+ WL_TRACE("Enter\n");
+
+ if (!check_sys_up(wiphy))
+ return -EIO;
+
+ err = __brcmf_cfg80211_scan(wiphy, ndev, request, NULL);
+ if (err)
+ WL_ERR("scan error (%d)\n", err);
+
+ WL_TRACE("Exit\n");
+ return err;
+}
+
+static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
+{
+ s32 err = 0;
+
+ err = brcmf_dev_intvar_set(ndev, "rtsthresh", rts_threshold);
+ if (err)
+ WL_ERR("Error (%d)\n", err);
+
+ return err;
+}
+
+static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
+{
+ s32 err = 0;
+
+ err = brcmf_dev_intvar_set(ndev, "fragthresh", frag_threshold);
+ if (err)
+ WL_ERR("Error (%d)\n", err);
+
+ return err;
+}
+
+static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
+{
+ s32 err = 0;
+ u32 cmd = (l ? BRCM_SET_LRL : BRCM_SET_SRL);
+
+ err = brcmf_exec_dcmd_u32(ndev, cmd, &retry);
+ if (err) {
+ WL_ERR("cmd (%d) , error (%d)\n", cmd, err);
+ return err;
+ }
+ return err;
+}
+
+static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
+ struct net_device *ndev = cfg_to_ndev(cfg_priv);
+ s32 err = 0;
+
+ WL_TRACE("Enter\n");
+ if (!check_sys_up(wiphy))
+ return -EIO;
+
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
+ (cfg_priv->conf->rts_threshold != wiphy->rts_threshold)) {
+ cfg_priv->conf->rts_threshold = wiphy->rts_threshold;
+ err = brcmf_set_rts(ndev, cfg_priv->conf->rts_threshold);
+ if (!err)
+ goto done;
+ }
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
+ (cfg_priv->conf->frag_threshold != wiphy->frag_threshold)) {
+ cfg_priv->conf->frag_threshold = wiphy->frag_threshold;
+ err = brcmf_set_frag(ndev, cfg_priv->conf->frag_threshold);
+ if (!err)
+ goto done;
+ }
+ if (changed & WIPHY_PARAM_RETRY_LONG
+ && (cfg_priv->conf->retry_long != wiphy->retry_long)) {
+ cfg_priv->conf->retry_long = wiphy->retry_long;
+ err = brcmf_set_retry(ndev, cfg_priv->conf->retry_long, true);
+ if (!err)
+ goto done;
+ }
+ if (changed & WIPHY_PARAM_RETRY_SHORT
+ && (cfg_priv->conf->retry_short != wiphy->retry_short)) {
+ cfg_priv->conf->retry_short = wiphy->retry_short;
+ err = brcmf_set_retry(ndev, cfg_priv->conf->retry_short, false);
+ if (!err)
+ goto done;
+ }
+
+done:
+ WL_TRACE("Exit\n");
+ return err;
+}
+
+static void *brcmf_read_prof(struct brcmf_cfg80211_priv *cfg_priv, s32 item)
+{
+ switch (item) {
+ case WL_PROF_SEC:
+ return &cfg_priv->profile->sec;
+ case WL_PROF_BSSID:
+ return &cfg_priv->profile->bssid;
+ case WL_PROF_SSID:
+ return &cfg_priv->profile->ssid;
+ }
+ WL_ERR("invalid item (%d)\n", item);
+ return NULL;
+}
+
+static s32
+brcmf_update_prof(struct brcmf_cfg80211_priv *cfg_priv,
+ const struct brcmf_event_msg *e, void *data, s32 item)
+{
+ s32 err = 0;
+ struct brcmf_ssid *ssid;
+
+ switch (item) {
+ case WL_PROF_SSID:
+ ssid = (struct brcmf_ssid *) data;
+ memset(cfg_priv->profile->ssid.SSID, 0,
+ sizeof(cfg_priv->profile->ssid.SSID));
+ memcpy(cfg_priv->profile->ssid.SSID,
+ ssid->SSID, ssid->SSID_len);
+ cfg_priv->profile->ssid.SSID_len = ssid->SSID_len;
+ break;
+ case WL_PROF_BSSID:
+ if (data)
+ memcpy(cfg_priv->profile->bssid, data, ETH_ALEN);
+ else
+ memset(cfg_priv->profile->bssid, 0, ETH_ALEN);
+ break;
+ case WL_PROF_SEC:
+ memcpy(&cfg_priv->profile->sec, data,
+ sizeof(cfg_priv->profile->sec));
+ break;
+ case WL_PROF_BEACONINT:
+ cfg_priv->profile->beacon_interval = *(u16 *)data;
+ break;
+ case WL_PROF_DTIMPERIOD:
+ cfg_priv->profile->dtim_period = *(u8 *)data;
+ break;
+ default:
+ WL_ERR("unsupported item (%d)\n", item);
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ return err;
+}
+
+static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
+{
+ memset(prof, 0, sizeof(*prof));
+}
+
+static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params,
+ size_t *join_params_size)
+{
+ u16 chanspec = 0;
+
+ if (ch != 0) {
+ if (ch <= CH_MAX_2G_CHANNEL)
+ chanspec |= WL_CHANSPEC_BAND_2G;
+ else
+ chanspec |= WL_CHANSPEC_BAND_5G;
+
+ chanspec |= WL_CHANSPEC_BW_20;
+ chanspec |= WL_CHANSPEC_CTL_SB_NONE;
+
+ *join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE +
+ sizeof(u16);
+
+ chanspec |= (ch & WL_CHANSPEC_CHAN_MASK);
+ join_params->params_le.chanspec_list[0] = cpu_to_le16(chanspec);
+ join_params->params_le.chanspec_num = cpu_to_le32(1);
+
+ WL_CONN("join_params->params.chanspec_list[0]= %#X,"
+ "channel %d, chanspec %#X\n",
+ chanspec, ch, chanspec);
+ }
+}
+
+static void brcmf_link_down(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct net_device *ndev = NULL;
+ s32 err = 0;
+
+ WL_TRACE("Enter\n");
+
+ if (cfg_priv->link_up) {
+ ndev = cfg_to_ndev(cfg_priv);
+ WL_INFO("Call WLC_DISASSOC to stop excess roaming\n ");
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, NULL, 0);
+ if (err)
+ WL_ERR("WLC_DISASSOC failed (%d)\n", err);
+ cfg_priv->link_up = false;
+ }
+ WL_TRACE("Exit\n");
+}
+
+static s32
+brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_ibss_params *params)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
+ struct brcmf_join_params join_params;
+ size_t join_params_size = 0;
+ s32 err = 0;
+ s32 wsec = 0;
+ s32 bcnprd;
+ struct brcmf_ssid ssid;
+
+ WL_TRACE("Enter\n");
+ if (!check_sys_up(wiphy))
+ return -EIO;
+
+ if (params->ssid)
+ WL_CONN("SSID: %s\n", params->ssid);
+ else {
+ WL_CONN("SSID: NULL, Not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ set_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
+
+ if (params->bssid)
+ WL_CONN("BSSID: %02X %02X %02X %02X %02X %02X\n",
+ params->bssid[0], params->bssid[1], params->bssid[2],
+ params->bssid[3], params->bssid[4], params->bssid[5]);
+ else
+ WL_CONN("No BSSID specified\n");
+
+ if (params->channel)
+ WL_CONN("channel: %d\n", params->channel->center_freq);
+ else
+ WL_CONN("no channel specified\n");
+
+ if (params->channel_fixed)
+ WL_CONN("fixed channel required\n");
+ else
+ WL_CONN("no fixed channel required\n");
+
+ if (params->ie && params->ie_len)
+ WL_CONN("ie len: %d\n", params->ie_len);
+ else
+ WL_CONN("no ie specified\n");
+
+ if (params->beacon_interval)
+ WL_CONN("beacon interval: %d\n", params->beacon_interval);
+ else
+ WL_CONN("no beacon interval specified\n");
+
+ if (params->basic_rates)
+ WL_CONN("basic rates: %08X\n", params->basic_rates);
+ else
+ WL_CONN("no basic rates specified\n");
+
+ if (params->privacy)
+ WL_CONN("privacy required\n");
+ else
+ WL_CONN("no privacy required\n");
+
+ /* Configure Privacy for starter */
+ if (params->privacy)
+ wsec |= WEP_ENABLED;
+
+ err = brcmf_dev_intvar_set(ndev, "wsec", wsec);
+ if (err) {
+ WL_ERR("wsec failed (%d)\n", err);
+ goto done;
+ }
+
+ /* Configure Beacon Interval for starter */
+ if (params->beacon_interval)
+ bcnprd = params->beacon_interval;
+ else
+ bcnprd = 100;
+
+ err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_BCNPRD, &bcnprd);
+ if (err) {
+ WL_ERR("WLC_SET_BCNPRD failed (%d)\n", err);
+ goto done;
+ }
+
+ /* Configure required join parameter */
+ memset(&join_params, 0, sizeof(struct brcmf_join_params));
+
+ /* SSID */
+ ssid.SSID_len = min_t(u32, params->ssid_len, 32);
+ memcpy(ssid.SSID, params->ssid, ssid.SSID_len);
+ memcpy(join_params.ssid_le.SSID, params->ssid, ssid.SSID_len);
+ join_params.ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len);
+ join_params_size = sizeof(join_params.ssid_le);
+ brcmf_update_prof(cfg_priv, NULL, &ssid, WL_PROF_SSID);
+
+ /* BSSID */
+ if (params->bssid) {
+ memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
+ join_params_size = sizeof(join_params.ssid_le) +
+ BRCMF_ASSOC_PARAMS_FIXED_SIZE;
+ } else {
+ memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN);
+ }
+
+ brcmf_update_prof(cfg_priv, NULL,
+ &join_params.params_le.bssid, WL_PROF_BSSID);
+
+ /* Channel */
+ if (params->channel) {
+ u32 target_channel;
+
+ cfg_priv->channel =
+ ieee80211_frequency_to_channel(
+ params->channel->center_freq);
+ if (params->channel_fixed) {
+ /* adding chanspec */
+ brcmf_ch_to_chanspec(cfg_priv->channel,
+ &join_params, &join_params_size);
+ }
+
+ /* set channel for starter */
+ target_channel = cfg_priv->channel;
+ err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_CHANNEL,
+ &target_channel);
+ if (err) {
+ WL_ERR("WLC_SET_CHANNEL failed (%d)\n", err);
+ goto done;
+ }
+ } else
+ cfg_priv->channel = 0;
+
+ cfg_priv->ibss_starter = false;
+
+
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID,
+ &join_params, join_params_size);
+ if (err) {
+ WL_ERR("WLC_SET_SSID failed (%d)\n", err);
+ goto done;
+ }
+
+done:
+ if (err)
+ clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
+ WL_TRACE("Exit\n");
+ return err;
+}
+
+static s32
+brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
+ s32 err = 0;
+
+ WL_TRACE("Enter\n");
+ if (!check_sys_up(wiphy))
+ return -EIO;
+
+ brcmf_link_down(cfg_priv);
+
+ WL_TRACE("Exit\n");
+
+ return err;
+}
+
+static s32 brcmf_set_wpa_version(struct net_device *ndev,
+ struct cfg80211_connect_params *sme)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
+ struct brcmf_cfg80211_security *sec;
+ s32 val = 0;
+ s32 err = 0;
+
+ if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
+ else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
+ else
+ val = WPA_AUTH_DISABLED;
+ WL_CONN("setting wpa_auth to 0x%0x\n", val);
+ err = brcmf_dev_intvar_set(ndev, "wpa_auth", val);
+ if (err) {
+ WL_ERR("set wpa_auth failed (%d)\n", err);
+ return err;
+ }
+ sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC);
+ sec->wpa_versions = sme->crypto.wpa_versions;
+ return err;
+}
+
+static s32 brcmf_set_auth_type(struct net_device *ndev,
+ struct cfg80211_connect_params *sme)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
+ struct brcmf_cfg80211_security *sec;
+ s32 val = 0;
+ s32 err = 0;
+
+ switch (sme->auth_type) {
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+ val = 0;
+ WL_CONN("open system\n");
+ break;
+ case NL80211_AUTHTYPE_SHARED_KEY:
+ val = 1;
+ WL_CONN("shared key\n");
+ break;
+ case NL80211_AUTHTYPE_AUTOMATIC:
+ val = 2;
+ WL_CONN("automatic\n");
+ break;
+ case NL80211_AUTHTYPE_NETWORK_EAP:
+ WL_CONN("network eap\n");
+ default:
+ val = 2;
+ WL_ERR("invalid auth type (%d)\n", sme->auth_type);
+ break;
+ }
+
+ err = brcmf_dev_intvar_set(ndev, "auth", val);
+ if (err) {
+ WL_ERR("set auth failed (%d)\n", err);
+ return err;
+ }
+ sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC);
+ sec->auth_type = sme->auth_type;
+ return err;
+}
+
+static s32
+brcmf_set_set_cipher(struct net_device *ndev,
+ struct cfg80211_connect_params *sme)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
+ struct brcmf_cfg80211_security *sec;
+ s32 pval = 0;
+ s32 gval = 0;
+ s32 err = 0;
+
+ if (sme->crypto.n_ciphers_pairwise) {
+ switch (sme->crypto.ciphers_pairwise[0]) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ pval = WEP_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ pval = TKIP_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ pval = AES_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ pval = AES_ENABLED;
+ break;
+ default:
+ WL_ERR("invalid cipher pairwise (%d)\n",
+ sme->crypto.ciphers_pairwise[0]);
+ return -EINVAL;
+ }
+ }
+ if (sme->crypto.cipher_group) {
+ switch (sme->crypto.cipher_group) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ gval = WEP_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ gval = TKIP_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ gval = AES_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ gval = AES_ENABLED;
+ break;
+ default:
+ WL_ERR("invalid cipher group (%d)\n",
+ sme->crypto.cipher_group);
+ return -EINVAL;
+ }
+ }
+
+ WL_CONN("pval (%d) gval (%d)\n", pval, gval);
+ err = brcmf_dev_intvar_set(ndev, "wsec", pval | gval);
+ if (err) {
+ WL_ERR("error (%d)\n", err);
+ return err;
+ }
+
+ sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC);
+ sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
+ sec->cipher_group = sme->crypto.cipher_group;
+
+ return err;
+}
+
+static s32
+brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
+ struct brcmf_cfg80211_security *sec;
+ s32 val = 0;
+ s32 err = 0;
+
+ if (sme->crypto.n_akm_suites) {
+ err = brcmf_dev_intvar_get(ndev, "wpa_auth", &val);
+ if (err) {
+ WL_ERR("could not get wpa_auth (%d)\n", err);
+ return err;
+ }
+ if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
+ switch (sme->crypto.akm_suites[0]) {
+ case WLAN_AKM_SUITE_8021X:
+ val = WPA_AUTH_UNSPECIFIED;
+ break;
+ case WLAN_AKM_SUITE_PSK:
+ val = WPA_AUTH_PSK;
+ break;
+ default:
+ WL_ERR("invalid cipher group (%d)\n",
+ sme->crypto.cipher_group);
+ return -EINVAL;
+ }
+ } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
+ switch (sme->crypto.akm_suites[0]) {
+ case WLAN_AKM_SUITE_8021X:
+ val = WPA2_AUTH_UNSPECIFIED;
+ break;
+ case WLAN_AKM_SUITE_PSK:
+ val = WPA2_AUTH_PSK;
+ break;
+ default:
+ WL_ERR("invalid cipher group (%d)\n",
+ sme->crypto.cipher_group);
+ return -EINVAL;
+ }
+ }
+
+ WL_CONN("setting wpa_auth to %d\n", val);
+ err = brcmf_dev_intvar_set(ndev, "wpa_auth", val);
+ if (err) {
+ WL_ERR("could not set wpa_auth (%d)\n", err);
+ return err;
+ }
+ }
+ sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC);
+ sec->wpa_auth = sme->crypto.akm_suites[0];
+
+ return err;
+}
+
+static s32
+brcmf_set_wep_sharedkey(struct net_device *ndev,
+ struct cfg80211_connect_params *sme)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
+ struct brcmf_cfg80211_security *sec;
+ struct brcmf_wsec_key key;
+ s32 val;
+ s32 err = 0;
+
+ WL_CONN("key len (%d)\n", sme->key_len);
+
+ if (sme->key_len == 0)
+ return 0;
+
+ sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC);
+ WL_CONN("wpa_versions 0x%x cipher_pairwise 0x%x\n",
+ sec->wpa_versions, sec->cipher_pairwise);
+
+ if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
+ return 0;
+
+ if (sec->cipher_pairwise &
+ (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)) {
+ memset(&key, 0, sizeof(key));
+ key.len = (u32) sme->key_len;
+ key.index = (u32) sme->key_idx;
+ if (key.len > sizeof(key.data)) {
+ WL_ERR("Too long key length (%u)\n", key.len);
+ return -EINVAL;
+ }
+ memcpy(key.data, sme->key, key.len);
+ key.flags = BRCMF_PRIMARY_KEY;
+ switch (sec->cipher_pairwise) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ key.algo = CRYPTO_ALGO_WEP1;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ key.algo = CRYPTO_ALGO_WEP128;
+ break;
+ default:
+ WL_ERR("Invalid algorithm (%d)\n",
+ sme->crypto.ciphers_pairwise[0]);
+ return -EINVAL;
+ }
+ /* Set the new key/index */
+ WL_CONN("key length (%d) key index (%d) algo (%d)\n",
+ key.len, key.index, key.algo);
+ WL_CONN("key \"%s\"\n", key.data);
+ err = send_key_to_dongle(ndev, &key);
+ if (err)
+ return err;
+
+ if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) {
+ WL_CONN("set auth_type to shared key\n");
+ val = 1; /* shared key */
+ err = brcmf_dev_intvar_set(ndev, "auth", val);
+ if (err) {
+ WL_ERR("set auth failed (%d)\n", err);
+ return err;
+ }
+ }
+ }
+ return err;
+}
+
+static s32
+brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_connect_params *sme)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
+ struct ieee80211_channel *chan = sme->channel;
+ struct brcmf_join_params join_params;
+ size_t join_params_size;
+ struct brcmf_ssid ssid;
+
+ s32 err = 0;
+
+ WL_TRACE("Enter\n");
+ if (!check_sys_up(wiphy))
+ return -EIO;
+
+ if (!sme->ssid) {
+ WL_ERR("Invalid ssid\n");
+ return -EOPNOTSUPP;
+ }
+
+ set_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
+
+ if (chan) {
+ cfg_priv->channel =
+ ieee80211_frequency_to_channel(chan->center_freq);
+ WL_CONN("channel (%d), center_req (%d)\n",
+ cfg_priv->channel, chan->center_freq);
+ } else
+ cfg_priv->channel = 0;
+
+ WL_INFO("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
+
+ err = brcmf_set_wpa_version(ndev, sme);
+ if (err) {
+ WL_ERR("wl_set_wpa_version failed (%d)\n", err);
+ goto done;
+ }
+
+ err = brcmf_set_auth_type(ndev, sme);
+ if (err) {
+ WL_ERR("wl_set_auth_type failed (%d)\n", err);
+ goto done;
+ }
+
+ err = brcmf_set_set_cipher(ndev, sme);
+ if (err) {
+ WL_ERR("wl_set_set_cipher failed (%d)\n", err);
+ goto done;
+ }
+
+ err = brcmf_set_key_mgmt(ndev, sme);
+ if (err) {
+ WL_ERR("wl_set_key_mgmt failed (%d)\n", err);
+ goto done;
+ }
+
+ err = brcmf_set_wep_sharedkey(ndev, sme);
+ if (err) {
+ WL_ERR("brcmf_set_wep_sharedkey failed (%d)\n", err);
+ goto done;
+ }
+
+ 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);
+ 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);
+ brcmf_update_prof(cfg_priv, NULL, &ssid, WL_PROF_SSID);
+
+ memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN);
+
+ if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN)
+ WL_CONN("ssid \"%s\", len (%d)\n",
+ ssid.SSID, ssid.SSID_len);
+
+ brcmf_ch_to_chanspec(cfg_priv->channel,
+ &join_params, &join_params_size);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID,
+ &join_params, join_params_size);
+ if (err)
+ WL_ERR("WLC_SET_SSID failed (%d)\n", err);
+
+done:
+ if (err)
+ clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
+ WL_TRACE("Exit\n");
+ return err;
+}
+
+static s32
+brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
+ u16 reason_code)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
+ struct brcmf_scb_val_le scbval;
+ s32 err = 0;
+
+ WL_TRACE("Enter. Reason code = %d\n", reason_code);
+ if (!check_sys_up(wiphy))
+ return -EIO;
+
+ clear_bit(WL_STATUS_CONNECTED, &cfg_priv->status);
+
+ memcpy(&scbval.ea, brcmf_read_prof(cfg_priv, WL_PROF_BSSID), ETH_ALEN);
+ scbval.val = cpu_to_le32(reason_code);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, &scbval,
+ sizeof(struct brcmf_scb_val_le));
+ if (err)
+ WL_ERR("error (%d)\n", err);
+
+ cfg_priv->link_up = false;
+
+ WL_TRACE("Exit\n");
+ return err;
+}
+
+static s32
+brcmf_cfg80211_set_tx_power(struct wiphy *wiphy,
+ enum nl80211_tx_power_setting type, s32 dbm)
+{
+
+ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
+ struct net_device *ndev = cfg_to_ndev(cfg_priv);
+ u16 txpwrmw;
+ s32 err = 0;
+ s32 disable = 0;
+
+ WL_TRACE("Enter\n");
+ if (!check_sys_up(wiphy))
+ return -EIO;
+
+ switch (type) {
+ case NL80211_TX_POWER_AUTOMATIC:
+ break;
+ case NL80211_TX_POWER_LIMITED:
+ if (dbm < 0) {
+ WL_ERR("TX_POWER_LIMITED - dbm is negative\n");
+ err = -EINVAL;
+ goto done;
+ }
+ break;
+ case NL80211_TX_POWER_FIXED:
+ if (dbm < 0) {
+ WL_ERR("TX_POWER_FIXED - dbm is negative\n");
+ err = -EINVAL;
+ goto done;
+ }
+ break;
+ }
+ /* Make sure radio is off or on as far as software is concerned */
+ disable = WL_RADIO_SW_DISABLE << 16;
+ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_RADIO, &disable);
+ if (err)
+ WL_ERR("WLC_SET_RADIO error (%d)\n", err);
+
+ if (dbm > 0xffff)
+ txpwrmw = 0xffff;
+ else
+ txpwrmw = (u16) dbm;
+ err = brcmf_dev_intvar_set(ndev, "qtxpower",
+ (s32) (brcmf_mw_to_qdbm(txpwrmw)));
+ if (err)
+ WL_ERR("qtxpower error (%d)\n", err);
+ cfg_priv->conf->tx_power = dbm;
+
+done:
+ WL_TRACE("Exit\n");
+ return err;
+}
+
+static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
+ struct net_device *ndev = cfg_to_ndev(cfg_priv);
+ s32 txpwrdbm;
+ u8 result;
+ s32 err = 0;
+
+ WL_TRACE("Enter\n");
+ if (!check_sys_up(wiphy))
+ return -EIO;
+
+ err = brcmf_dev_intvar_get(ndev, "qtxpower", &txpwrdbm);
+ if (err) {
+ WL_ERR("error (%d)\n", err);
+ goto done;
+ }
+
+ result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
+ *dbm = (s32) brcmf_qdbm_to_mw(result);
+
+done:
+ WL_TRACE("Exit\n");
+ return err;
+}
+
+static s32
+brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_idx, bool unicast, bool multicast)
+{
+ u32 index;
+ u32 wsec;
+ s32 err = 0;
+
+ WL_TRACE("Enter\n");
+ WL_CONN("key index (%d)\n", key_idx);
+ if (!check_sys_up(wiphy))
+ return -EIO;
+
+ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_WSEC, &wsec);
+ if (err) {
+ WL_ERR("WLC_GET_WSEC error (%d)\n", err);
+ goto done;
+ }
+
+ if (wsec & WEP_ENABLED) {
+ /* Just select a new current key */
+ index = key_idx;
+ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_KEY_PRIMARY,
+ &index);
+ if (err)
+ WL_ERR("error (%d)\n", err);
+ }
+done:
+ WL_TRACE("Exit\n");
+ return err;
+}
+
+static s32
+brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_idx, const u8 *mac_addr, struct key_params *params)
+{
+ struct brcmf_wsec_key key;
+ struct brcmf_wsec_key_le key_le;
+ s32 err = 0;
+
+ memset(&key, 0, sizeof(key));
+ key.index = (u32) key_idx;
+ /* Instead of bcast for ea address for default wep keys,
+ driver needs it to be Null */
+ if (!is_multicast_ether_addr(mac_addr))
+ memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
+ key.len = (u32) params->key_len;
+ /* check for key index change */
+ if (key.len == 0) {
+ /* key delete */
+ err = send_key_to_dongle(ndev, &key);
+ if (err)
+ return err;
+ } else {
+ if (key.len > sizeof(key.data)) {
+ WL_ERR("Invalid key length (%d)\n", key.len);
+ return -EINVAL;
+ }
+
+ WL_CONN("Setting the key index %d\n", key.index);
+ memcpy(key.data, params->key, key.len);
+
+ if (params->cipher == WLAN_CIPHER_SUITE_TKIP) {
+ u8 keybuf[8];
+ memcpy(keybuf, &key.data[24], sizeof(keybuf));
+ memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
+ memcpy(&key.data[16], keybuf, sizeof(keybuf));
+ }
+
+ /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
+ if (params->seq && params->seq_len == 6) {
+ /* rx iv */
+ u8 *ivptr;
+ ivptr = (u8 *) params->seq;
+ key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
+ (ivptr[3] << 8) | ivptr[2];
+ key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
+ key.iv_initialized = true;
+ }
+
+ switch (params->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ key.algo = CRYPTO_ALGO_WEP1;
+ WL_CONN("WLAN_CIPHER_SUITE_WEP40\n");
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ key.algo = CRYPTO_ALGO_WEP128;
+ WL_CONN("WLAN_CIPHER_SUITE_WEP104\n");
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ key.algo = CRYPTO_ALGO_TKIP;
+ WL_CONN("WLAN_CIPHER_SUITE_TKIP\n");
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ key.algo = CRYPTO_ALGO_AES_CCM;
+ WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n");
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ key.algo = CRYPTO_ALGO_AES_CCM;
+ WL_CONN("WLAN_CIPHER_SUITE_CCMP\n");
+ break;
+ default:
+ WL_ERR("Invalid cipher (0x%x)\n", params->cipher);
+ return -EINVAL;
+ }
+ convert_key_from_CPU(&key, &key_le);
+
+ brcmf_netdev_wait_pend8021x(ndev);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_KEY, &key_le,
+ sizeof(key_le));
+ if (err) {
+ WL_ERR("WLC_SET_KEY error (%d)\n", err);
+ return err;
+ }
+ }
+ return err;
+}
+
+static s32
+brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_idx, bool pairwise, const u8 *mac_addr,
+ struct key_params *params)
+{
+ struct brcmf_wsec_key key;
+ s32 val;
+ s32 wsec;
+ s32 err = 0;
+ u8 keybuf[8];
+
+ WL_TRACE("Enter\n");
+ WL_CONN("key index (%d)\n", key_idx);
+ if (!check_sys_up(wiphy))
+ return -EIO;
+
+ if (mac_addr) {
+ WL_TRACE("Exit");
+ return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
+ }
+ memset(&key, 0, sizeof(key));
+
+ key.len = (u32) params->key_len;
+ key.index = (u32) key_idx;
+
+ if (key.len > sizeof(key.data)) {
+ WL_ERR("Too long key length (%u)\n", key.len);
+ err = -EINVAL;
+ goto done;
+ }
+ memcpy(key.data, params->key, key.len);
+
+ key.flags = BRCMF_PRIMARY_KEY;
+ switch (params->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ key.algo = CRYPTO_ALGO_WEP1;
+ WL_CONN("WLAN_CIPHER_SUITE_WEP40\n");
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ key.algo = CRYPTO_ALGO_WEP128;
+ WL_CONN("WLAN_CIPHER_SUITE_WEP104\n");
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ memcpy(keybuf, &key.data[24], sizeof(keybuf));
+ memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
+ memcpy(&key.data[16], keybuf, sizeof(keybuf));
+ key.algo = CRYPTO_ALGO_TKIP;
+ WL_CONN("WLAN_CIPHER_SUITE_TKIP\n");
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ key.algo = CRYPTO_ALGO_AES_CCM;
+ WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n");
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ key.algo = CRYPTO_ALGO_AES_CCM;
+ WL_CONN("WLAN_CIPHER_SUITE_CCMP\n");
+ break;
+ default:
+ WL_ERR("Invalid cipher (0x%x)\n", params->cipher);
+ err = -EINVAL;
+ goto done;
+ }
+
+ err = send_key_to_dongle(ndev, &key); /* Set the new key/index */
+ if (err)
+ goto done;
+
+ val = WEP_ENABLED;
+ err = brcmf_dev_intvar_get(ndev, "wsec", &wsec);
+ if (err) {
+ WL_ERR("get wsec error (%d)\n", err);
+ goto done;
+ }
+ wsec &= ~(WEP_ENABLED);
+ wsec |= val;
+ err = brcmf_dev_intvar_set(ndev, "wsec", wsec);
+ if (err) {
+ WL_ERR("set wsec error (%d)\n", err);
+ goto done;
+ }
+
+ val = 1; /* assume shared key. otherwise 0 */
+ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AUTH, &val);
+ if (err)
+ WL_ERR("WLC_SET_AUTH error (%d)\n", err);
+done:
+ WL_TRACE("Exit\n");
+ return err;
+}
+
+static s32
+brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_idx, bool pairwise, const u8 *mac_addr)
+{
+ struct brcmf_wsec_key key;
+ s32 err = 0;
+ s32 val;
+ s32 wsec;
+
+ WL_TRACE("Enter\n");
+ if (!check_sys_up(wiphy))
+ return -EIO;
+
+ memset(&key, 0, sizeof(key));
+
+ key.index = (u32) key_idx;
+ key.flags = BRCMF_PRIMARY_KEY;
+ key.algo = CRYPTO_ALGO_OFF;
+
+ WL_CONN("key index (%d)\n", key_idx);
+
+ /* Set the new key/index */
+ err = send_key_to_dongle(ndev, &key);
+ if (err) {
+ if (err == -EINVAL) {
+ if (key.index >= DOT11_MAX_DEFAULT_KEYS)
+ /* we ignore this key index in this case */
+ WL_ERR("invalid key index (%d)\n", key_idx);
+ }
+ /* Ignore this error, may happen during DISASSOC */
+ err = -EAGAIN;
+ goto done;
+ }
+
+ val = 0;
+ err = brcmf_dev_intvar_get(ndev, "wsec", &wsec);
+ if (err) {
+ WL_ERR("get wsec error (%d)\n", err);
+ /* Ignore this error, may happen during DISASSOC */
+ err = -EAGAIN;
+ goto done;
+ }
+ wsec &= ~(WEP_ENABLED);
+ wsec |= val;
+ err = brcmf_dev_intvar_set(ndev, "wsec", wsec);
+ if (err) {
+ WL_ERR("set wsec error (%d)\n", err);
+ /* Ignore this error, may happen during DISASSOC */
+ err = -EAGAIN;
+ goto done;
+ }
+
+ val = 0; /* assume open key. otherwise 1 */
+ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AUTH, &val);
+ if (err) {
+ WL_ERR("WLC_SET_AUTH error (%d)\n", err);
+ /* Ignore this error, may happen during DISASSOC */
+ err = -EAGAIN;
+ }
+done:
+ WL_TRACE("Exit\n");
+ return err;
+}
+
+static s32
+brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
+ void (*callback) (void *cookie, struct key_params * params))
+{
+ struct key_params params;
+ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
+ struct brcmf_cfg80211_security *sec;
+ s32 wsec;
+ s32 err = 0;
+
+ WL_TRACE("Enter\n");
+ WL_CONN("key index (%d)\n", key_idx);
+ if (!check_sys_up(wiphy))
+ return -EIO;
+
+ memset(&params, 0, sizeof(params));
+
+ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_WSEC, &wsec);
+ if (err) {
+ WL_ERR("WLC_GET_WSEC error (%d)\n", err);
+ /* Ignore this error, may happen during DISASSOC */
+ err = -EAGAIN;
+ goto done;
+ }
+ switch (wsec) {
+ case WEP_ENABLED:
+ sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC);
+ if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
+ params.cipher = WLAN_CIPHER_SUITE_WEP40;
+ WL_CONN("WLAN_CIPHER_SUITE_WEP40\n");
+ } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
+ params.cipher = WLAN_CIPHER_SUITE_WEP104;
+ WL_CONN("WLAN_CIPHER_SUITE_WEP104\n");
+ }
+ break;
+ case TKIP_ENABLED:
+ params.cipher = WLAN_CIPHER_SUITE_TKIP;
+ WL_CONN("WLAN_CIPHER_SUITE_TKIP\n");
+ break;
+ case AES_ENABLED:
+ params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
+ WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n");
+ break;
+ default:
+ WL_ERR("Invalid algo (0x%x)\n", wsec);
+ err = -EINVAL;
+ goto done;
+ }
+ callback(cookie, &params);
+
+done:
+ WL_TRACE("Exit\n");
+ return err;
+}
+
+static s32
+brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
+ struct net_device *ndev, u8 key_idx)
+{
+ WL_INFO("Not supported\n");
+
+ return -EOPNOTSUPP;
+}
+
+static s32
+brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
+ u8 *mac, struct station_info *sinfo)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
+ struct brcmf_scb_val_le scb_val;
+ int rssi;
+ s32 rate;
+ s32 err = 0;
+ u8 *bssid = brcmf_read_prof(cfg_priv, WL_PROF_BSSID);
+
+ WL_TRACE("Enter\n");
+ if (!check_sys_up(wiphy))
+ return -EIO;
+
+ if (memcmp(mac, bssid, ETH_ALEN)) {
+ WL_ERR("Wrong Mac address cfg_mac-%X:%X:%X:%X:%X:%X"
+ "wl_bssid-%X:%X:%X:%X:%X:%X\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+ bssid[0], bssid[1], bssid[2], bssid[3],
+ bssid[4], bssid[5]);
+ err = -ENOENT;
+ goto done;
+ }
+
+ /* Report the current tx rate */
+ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_RATE, &rate);
+ if (err) {
+ WL_ERR("Could not get rate (%d)\n", err);
+ } else {
+ sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->txrate.legacy = rate * 5;
+ WL_CONN("Rate %d Mbps\n", rate / 2);
+ }
+
+ if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status)) {
+ scb_val.val = cpu_to_le32(0);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_RSSI, &scb_val,
+ sizeof(struct brcmf_scb_val_le));
+ if (err)
+ WL_ERR("Could not get rssi (%d)\n", err);
+
+ rssi = le32_to_cpu(scb_val.val);
+ sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->signal = rssi;
+ WL_CONN("RSSI %d dBm\n", rssi);
+ }
+
+done:
+ WL_TRACE("Exit\n");
+ return err;
+}
+
+static s32
+brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
+ bool enabled, s32 timeout)
+{
+ s32 pm;
+ s32 err = 0;
+ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
+
+ WL_TRACE("Enter\n");
+
+ /*
+ * Powersave enable/disable request is coming from the
+ * cfg80211 even before the interface is up. In that
+ * scenario, driver will be storing the power save
+ * preference in cfg_priv struct to apply this to
+ * FW later while initializing the dongle
+ */
+ cfg_priv->pwr_save = enabled;
+ if (!test_bit(WL_STATUS_READY, &cfg_priv->status)) {
+
+ WL_INFO("Device is not ready,"
+ "storing the value in cfg_priv struct\n");
+ goto done;
+ }
+
+ pm = enabled ? PM_FAST : PM_OFF;
+ WL_INFO("power save %s\n", (pm ? "enabled" : "disabled"));
+
+ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &pm);
+ if (err) {
+ if (err == -ENODEV)
+ WL_ERR("net_device is not ready yet\n");
+ else
+ WL_ERR("error (%d)\n", err);
+ }
+done:
+ WL_TRACE("Exit\n");
+ return err;
+}
+
+static s32
+brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev,
+ const u8 *addr,
+ const struct cfg80211_bitrate_mask *mask)
+{
+ struct brcm_rateset_le rateset_le;
+ s32 rate;
+ s32 val;
+ s32 err_bg;
+ s32 err_a;
+ u32 legacy;
+ s32 err = 0;
+
+ WL_TRACE("Enter\n");
+ if (!check_sys_up(wiphy))
+ return -EIO;
+
+ /* addr param is always NULL. ignore it */
+ /* Get current rateset */
+ err = brcmf_exec_dcmd(ndev, BRCM_GET_CURR_RATESET, &rateset_le,
+ sizeof(rateset_le));
+ if (err) {
+ WL_ERR("could not get current rateset (%d)\n", err);
+ goto done;
+ }
+
+ legacy = ffs(mask->control[IEEE80211_BAND_2GHZ].legacy & 0xFFFF);
+ if (!legacy)
+ legacy = ffs(mask->control[IEEE80211_BAND_5GHZ].legacy &
+ 0xFFFF);
+
+ val = wl_g_rates[legacy - 1].bitrate * 100000;
+
+ if (val < le32_to_cpu(rateset_le.count))
+ /* Select rate by rateset index */
+ rate = rateset_le.rates[val] & 0x7f;
+ else
+ /* Specified rate in bps */
+ rate = val / 500000;
+
+ WL_CONN("rate %d mbps\n", rate / 2);
+
+ /*
+ *
+ * Set rate override,
+ * Since the is a/b/g-blind, both a/bg_rate are enforced.
+ */
+ err_bg = brcmf_dev_intvar_set(ndev, "bg_rate", rate);
+ err_a = brcmf_dev_intvar_set(ndev, "a_rate", rate);
+ if (err_bg && err_a) {
+ WL_ERR("could not set fixed rate (%d) (%d)\n", err_bg, err_a);
+ err = err_bg | err_a;
+ }
+
+done:
+ WL_TRACE("Exit\n");
+ return err;
+}
+
+static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv,
+ struct brcmf_bss_info *bi)
+{
+ struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
+ struct ieee80211_channel *notify_channel;
+ struct cfg80211_bss *bss;
+ struct ieee80211_supported_band *band;
+ s32 err = 0;
+ u16 channel;
+ u32 freq;
+ u64 notify_timestamp;
+ u16 notify_capability;
+ u16 notify_interval;
+ u8 *notify_ie;
+ size_t notify_ielen;
+ s32 notify_signal;
+
+ if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
+ WL_ERR("Bss info is larger than buffer. Discarding\n");
+ return 0;
+ }
+
+ channel = bi->ctl_ch ? bi->ctl_ch :
+ CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
+
+ if (channel <= CH_MAX_2G_CHANNEL)
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
+ else
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
+
+ freq = ieee80211_channel_to_frequency(channel, band->band);
+ notify_channel = ieee80211_get_channel(wiphy, freq);
+
+ notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */
+ notify_capability = le16_to_cpu(bi->capability);
+ notify_interval = le16_to_cpu(bi->beacon_period);
+ notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
+ notify_ielen = le32_to_cpu(bi->ie_length);
+ notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
+
+ WL_CONN("bssid: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
+ bi->BSSID[0], bi->BSSID[1], bi->BSSID[2],
+ bi->BSSID[3], bi->BSSID[4], bi->BSSID[5]);
+ WL_CONN("Channel: %d(%d)\n", channel, freq);
+ WL_CONN("Capability: %X\n", notify_capability);
+ WL_CONN("Beacon interval: %d\n", notify_interval);
+ WL_CONN("Signal: %d\n", notify_signal);
+ WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp);
+
+ bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
+ notify_timestamp, notify_capability, notify_interval, notify_ie,
+ notify_ielen, notify_signal, GFP_KERNEL);
+
+ if (!bss) {
+ WL_ERR("cfg80211_inform_bss_frame error\n");
+ return -EINVAL;
+ }
+
+ return err;
+}
+
+static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct brcmf_scan_results *bss_list;
+ struct brcmf_bss_info *bi = NULL; /* must be initialized */
+ s32 err = 0;
+ int i;
+
+ bss_list = cfg_priv->bss_list;
+ if (bss_list->version != BRCMF_BSS_INFO_VERSION) {
+ WL_ERR("Version %d != WL_BSS_INFO_VERSION\n",
+ bss_list->version);
+ return -EOPNOTSUPP;
+ }
+ WL_SCAN("scanned AP count (%d)\n", bss_list->count);
+ for (i = 0; i < bss_list->count && i < WL_AP_MAX; i++) {
+ bi = next_bss(bss_list, bi);
+ err = brcmf_inform_single_bss(cfg_priv, bi);
+ if (err)
+ break;
+ }
+ return err;
+}
+
+static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv,
+ struct net_device *ndev, const u8 *bssid)
+{
+ struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
+ struct ieee80211_channel *notify_channel;
+ struct brcmf_bss_info *bi = NULL;
+ struct ieee80211_supported_band *band;
+ u8 *buf = NULL;
+ s32 err = 0;
+ u16 channel;
+ u32 freq;
+ u64 notify_timestamp;
+ u16 notify_capability;
+ u16 notify_interval;
+ u8 *notify_ie;
+ size_t notify_ielen;
+ s32 notify_signal;
+
+ WL_TRACE("Enter\n");
+
+ buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
+ if (buf == NULL) {
+ err = -ENOMEM;
+ goto CleanUp;
+ }
+
+ *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
+
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_BSS_INFO, buf, WL_BSS_INFO_MAX);
+ if (err) {
+ WL_ERR("WLC_GET_BSS_INFO failed: %d\n", err);
+ goto CleanUp;
+ }
+
+ bi = (struct brcmf_bss_info *)(buf + 4);
+
+ channel = bi->ctl_ch ? bi->ctl_ch :
+ CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
+
+ if (channel <= CH_MAX_2G_CHANNEL)
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
+ else
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
+
+ freq = ieee80211_channel_to_frequency(channel, band->band);
+ notify_channel = ieee80211_get_channel(wiphy, freq);
+
+ notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */
+ notify_capability = le16_to_cpu(bi->capability);
+ notify_interval = le16_to_cpu(bi->beacon_period);
+ notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
+ notify_ielen = le32_to_cpu(bi->ie_length);
+ notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
+
+ WL_CONN("channel: %d(%d)\n", channel, freq);
+ WL_CONN("capability: %X\n", notify_capability);
+ WL_CONN("beacon interval: %d\n", notify_interval);
+ WL_CONN("signal: %d\n", notify_signal);
+ WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp);
+
+ cfg80211_inform_bss(wiphy, notify_channel, bssid,
+ notify_timestamp, notify_capability, notify_interval,
+ notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
+
+CleanUp:
+
+ kfree(buf);
+
+ WL_TRACE("Exit\n");
+
+ return err;
+}
+
+static bool brcmf_is_ibssmode(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ return cfg_priv->conf->mode == WL_MODE_IBSS;
+}
+
+/*
+ * Traverse a string of 1-byte tag/1-byte length/variable-length value
+ * triples, returning a pointer to the substring whose first element
+ * matches tag
+ */
+static struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
+{
+ struct brcmf_tlv *elt;
+ int totlen;
+
+ elt = (struct brcmf_tlv *) buf;
+ totlen = buflen;
+
+ /* find tagged parameter */
+ while (totlen >= 2) {
+ int len = elt->len;
+
+ /* validate remaining totlen */
+ if ((elt->id == key) && (totlen >= (len + 2)))
+ return elt;
+
+ elt = (struct brcmf_tlv *) ((u8 *) elt + (len + 2));
+ totlen -= (len + 2);
+ }
+
+ return NULL;
+}
+
+static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct brcmf_bss_info *bi;
+ struct brcmf_ssid *ssid;
+ struct brcmf_tlv *tim;
+ u16 beacon_interval;
+ u8 dtim_period;
+ size_t ie_len;
+ u8 *ie;
+ s32 err = 0;
+
+ WL_TRACE("Enter\n");
+ if (brcmf_is_ibssmode(cfg_priv))
+ return err;
+
+ ssid = (struct brcmf_ssid *)brcmf_read_prof(cfg_priv, WL_PROF_SSID);
+
+ *(__le32 *)cfg_priv->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
+ err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCMF_C_GET_BSS_INFO,
+ cfg_priv->extra_buf, WL_EXTRA_BUF_MAX);
+ if (err) {
+ WL_ERR("Could not get bss info %d\n", err);
+ goto update_bss_info_out;
+ }
+
+ bi = (struct brcmf_bss_info *)(cfg_priv->extra_buf + 4);
+ err = brcmf_inform_single_bss(cfg_priv, bi);
+ if (err)
+ goto update_bss_info_out;
+
+ ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
+ ie_len = le32_to_cpu(bi->ie_length);
+ beacon_interval = le16_to_cpu(bi->beacon_period);
+
+ tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
+ if (tim)
+ dtim_period = tim->data[1];
+ else {
+ /*
+ * active scan was done so we could not get dtim
+ * information out of probe response.
+ * so we speficially query dtim information to dongle.
+ */
+ u32 var;
+ err = brcmf_dev_intvar_get(cfg_to_ndev(cfg_priv),
+ "dtim_assoc", &var);
+ if (err) {
+ WL_ERR("wl dtim_assoc failed (%d)\n", err);
+ goto update_bss_info_out;
+ }
+ dtim_period = (u8)var;
+ }
+
+ brcmf_update_prof(cfg_priv, NULL, &beacon_interval, WL_PROF_BEACONINT);
+ brcmf_update_prof(cfg_priv, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
+
+update_bss_info_out:
+ WL_TRACE("Exit");
+ return err;
+}
+
+static void brcmf_term_iscan(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv);
+ struct brcmf_ssid ssid;
+
+ if (cfg_priv->iscan_on) {
+ iscan->state = WL_ISCAN_STATE_IDLE;
+
+ if (iscan->timer_on) {
+ del_timer_sync(&iscan->timer);
+ iscan->timer_on = 0;
+ }
+
+ cancel_work_sync(&iscan->work);
+
+ /* Abort iscan running in FW */
+ memset(&ssid, 0, sizeof(ssid));
+ brcmf_run_iscan(iscan, &ssid, WL_SCAN_ACTION_ABORT);
+ }
+}
+
+static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan,
+ bool aborted)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan);
+ struct net_device *ndev = cfg_to_ndev(cfg_priv);
+
+ if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg_priv->status)) {
+ WL_ERR("Scan complete while device not scanning\n");
+ return;
+ }
+ if (cfg_priv->scan_request) {
+ WL_SCAN("ISCAN Completed scan: %s\n",
+ aborted ? "Aborted" : "Done");
+ cfg80211_scan_done(cfg_priv->scan_request, aborted);
+ brcmf_set_mpc(ndev, 1);
+ cfg_priv->scan_request = NULL;
+ }
+ cfg_priv->iscan_kickstart = false;
+}
+
+static s32 brcmf_wakeup_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan)
+{
+ if (iscan->state != WL_ISCAN_STATE_IDLE) {
+ WL_SCAN("wake up iscan\n");
+ schedule_work(&iscan->work);
+ return 0;
+ }
+
+ return -EIO;
+}
+
+static s32
+brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan, u32 *status,
+ struct brcmf_scan_results **bss_list)
+{
+ struct brcmf_iscan_results list;
+ struct brcmf_scan_results *results;
+ struct brcmf_scan_results_le *results_le;
+ struct brcmf_iscan_results *list_buf;
+ s32 err = 0;
+
+ memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX);
+ list_buf = (struct brcmf_iscan_results *)iscan->scan_buf;
+ results = &list_buf->results;
+ results_le = &list_buf->results_le;
+ results->buflen = BRCMF_ISCAN_RESULTS_FIXED_SIZE;
+ results->version = 0;
+ results->count = 0;
+
+ memset(&list, 0, sizeof(list));
+ list.results_le.buflen = cpu_to_le32(WL_ISCAN_BUF_MAX);
+ err = brcmf_dev_iovar_getbuf(iscan->ndev, "iscanresults", &list,
+ BRCMF_ISCAN_RESULTS_FIXED_SIZE,
+ iscan->scan_buf, WL_ISCAN_BUF_MAX);
+ if (err) {
+ WL_ERR("error (%d)\n", err);
+ return err;
+ }
+ results->buflen = le32_to_cpu(results_le->buflen);
+ results->version = le32_to_cpu(results_le->version);
+ results->count = le32_to_cpu(results_le->count);
+ WL_SCAN("results->count = %d\n", results_le->count);
+ WL_SCAN("results->buflen = %d\n", results_le->buflen);
+ *status = le32_to_cpu(list_buf->status_le);
+ WL_SCAN("status = %d\n", *status);
+ *bss_list = results;
+
+ return err;
+}
+
+static s32 brcmf_iscan_done(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan;
+ s32 err = 0;
+
+ iscan->state = WL_ISCAN_STATE_IDLE;
+ brcmf_inform_bss(cfg_priv);
+ brcmf_notify_iscan_complete(iscan, false);
+
+ return err;
+}
+
+static s32 brcmf_iscan_pending(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan;
+ s32 err = 0;
+
+ /* Reschedule the timer */
+ mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
+ iscan->timer_on = 1;
+
+ return err;
+}
+
+static s32 brcmf_iscan_inprogress(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan;
+ s32 err = 0;
+
+ brcmf_inform_bss(cfg_priv);
+ brcmf_run_iscan(iscan, NULL, BRCMF_SCAN_ACTION_CONTINUE);
+ /* Reschedule the timer */
+ mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
+ iscan->timer_on = 1;
+
+ return err;
+}
+
+static s32 brcmf_iscan_aborted(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan;
+ s32 err = 0;
+
+ iscan->state = WL_ISCAN_STATE_IDLE;
+ brcmf_notify_iscan_complete(iscan, true);
+
+ return err;
+}
+
+static void brcmf_cfg80211_iscan_handler(struct work_struct *work)
+{
+ struct brcmf_cfg80211_iscan_ctrl *iscan =
+ container_of(work, struct brcmf_cfg80211_iscan_ctrl,
+ work);
+ struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan);
+ struct brcmf_cfg80211_iscan_eloop *el = &iscan->el;
+ u32 status = BRCMF_SCAN_RESULTS_PARTIAL;
+
+ if (iscan->timer_on) {
+ del_timer_sync(&iscan->timer);
+ iscan->timer_on = 0;
+ }
+
+ if (brcmf_get_iscan_results(iscan, &status, &cfg_priv->bss_list)) {
+ status = BRCMF_SCAN_RESULTS_ABORTED;
+ WL_ERR("Abort iscan\n");
+ }
+
+ el->handler[status](cfg_priv);
+}
+
+static void brcmf_iscan_timer(unsigned long data)
+{
+ struct brcmf_cfg80211_iscan_ctrl *iscan =
+ (struct brcmf_cfg80211_iscan_ctrl *)data;
+
+ if (iscan) {
+ iscan->timer_on = 0;
+ WL_SCAN("timer expired\n");
+ brcmf_wakeup_iscan(iscan);
+ }
+}
+
+static s32 brcmf_invoke_iscan(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv);
+
+ if (cfg_priv->iscan_on) {
+ iscan->state = WL_ISCAN_STATE_IDLE;
+ INIT_WORK(&iscan->work, brcmf_cfg80211_iscan_handler);
+ }
+
+ return 0;
+}
+
+static void brcmf_init_iscan_eloop(struct brcmf_cfg80211_iscan_eloop *el)
+{
+ memset(el, 0, sizeof(*el));
+ el->handler[BRCMF_SCAN_RESULTS_SUCCESS] = brcmf_iscan_done;
+ el->handler[BRCMF_SCAN_RESULTS_PARTIAL] = brcmf_iscan_inprogress;
+ el->handler[BRCMF_SCAN_RESULTS_PENDING] = brcmf_iscan_pending;
+ el->handler[BRCMF_SCAN_RESULTS_ABORTED] = brcmf_iscan_aborted;
+ el->handler[BRCMF_SCAN_RESULTS_NO_MEM] = brcmf_iscan_aborted;
+}
+
+static s32 brcmf_init_iscan(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv);
+ int err = 0;
+
+ if (cfg_priv->iscan_on) {
+ iscan->ndev = cfg_to_ndev(cfg_priv);
+ brcmf_init_iscan_eloop(&iscan->el);
+ iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS;
+ init_timer(&iscan->timer);
+ iscan->timer.data = (unsigned long) iscan;
+ iscan->timer.function = brcmf_iscan_timer;
+ err = brcmf_invoke_iscan(cfg_priv);
+ if (!err)
+ iscan->data = cfg_priv;
+ }
+
+ return err;
+}
+
+static void brcmf_delay(u32 ms)
+{
+ if (ms < 1000 / HZ) {
+ cond_resched();
+ mdelay(ms);
+ } else {
+ msleep(ms);
+ }
+}
+
+static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
+
+ /*
+ * Check for WL_STATUS_READY before any function call which
+ * could result is bus access. Don't block the resume for
+ * any driver error conditions
+ */
+ WL_TRACE("Enter\n");
+
+ if (test_bit(WL_STATUS_READY, &cfg_priv->status))
+ brcmf_invoke_iscan(wiphy_to_cfg(wiphy));
+
+ WL_TRACE("Exit\n");
+ return 0;
+}
+
+static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
+ struct cfg80211_wowlan *wow)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
+ struct net_device *ndev = cfg_to_ndev(cfg_priv);
+
+ WL_TRACE("Enter\n");
+
+ /*
+ * Check for WL_STATUS_READY before any function call which
+ * could result is bus access. Don't block the suspend for
+ * any driver error conditions
+ */
+
+ /*
+ * While going to suspend if associated with AP disassociate
+ * from AP to save power while system is in suspended state
+ */
+ if ((test_bit(WL_STATUS_CONNECTED, &cfg_priv->status) ||
+ test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) &&
+ test_bit(WL_STATUS_READY, &cfg_priv->status)) {
+ WL_INFO("Disassociating from AP"
+ " while entering suspend state\n");
+ brcmf_link_down(cfg_priv);
+
+ /*
+ * Make sure WPA_Supplicant receives all the event
+ * generated due to DISASSOC call to the fw to keep
+ * the state fw and WPA_Supplicant state consistent
+ */
+ brcmf_delay(500);
+ }
+
+ set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
+ if (test_bit(WL_STATUS_READY, &cfg_priv->status))
+ brcmf_term_iscan(cfg_priv);
+
+ if (cfg_priv->scan_request) {
+ /* Indidate scan abort to cfg80211 layer */
+ WL_INFO("Terminating scan in progress\n");
+ cfg80211_scan_done(cfg_priv->scan_request, true);
+ cfg_priv->scan_request = NULL;
+ }
+ clear_bit(WL_STATUS_SCANNING, &cfg_priv->status);
+ clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
+
+ /* Turn off watchdog timer */
+ if (test_bit(WL_STATUS_READY, &cfg_priv->status)) {
+ WL_INFO("Enable MPC\n");
+ brcmf_set_mpc(ndev, 1);
+ }
+
+ WL_TRACE("Exit\n");
+
+ return 0;
+}
+
+static __used s32
+brcmf_dev_bufvar_set(struct net_device *ndev, s8 *name, s8 *buf, s32 len)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
+ u32 buflen;
+
+ buflen = brcmf_c_mkiovar(name, buf, len, cfg_priv->dcmd_buf,
+ WL_DCMD_LEN_MAX);
+ BUG_ON(!buflen);
+
+ return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, cfg_priv->dcmd_buf,
+ buflen);
+}
+
+static s32
+brcmf_dev_bufvar_get(struct net_device *ndev, s8 *name, s8 *buf,
+ s32 buf_len)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
+ u32 len;
+ s32 err = 0;
+
+ len = brcmf_c_mkiovar(name, NULL, 0, cfg_priv->dcmd_buf,
+ WL_DCMD_LEN_MAX);
+ BUG_ON(!len);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, cfg_priv->dcmd_buf,
+ WL_DCMD_LEN_MAX);
+ if (err) {
+ WL_ERR("error (%d)\n", err);
+ return err;
+ }
+ memcpy(buf, cfg_priv->dcmd_buf, buf_len);
+
+ return err;
+}
+
+static __used s32
+brcmf_update_pmklist(struct net_device *ndev,
+ struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
+{
+ int i, j;
+ int pmkid_len;
+
+ pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
+
+ WL_CONN("No of elements %d\n", pmkid_len);
+ for (i = 0; i < pmkid_len; i++) {
+ WL_CONN("PMKID[%d]: %pM =\n", i,
+ &pmk_list->pmkids.pmkid[i].BSSID);
+ for (j = 0; j < WLAN_PMKID_LEN; j++)
+ WL_CONN("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]);
+ }
+
+ if (!err)
+ brcmf_dev_bufvar_set(ndev, "pmkid_info", (char *)pmk_list,
+ sizeof(*pmk_list));
+
+ return err;
+}
+
+static s32
+brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_pmksa *pmksa)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
+ struct pmkid_list *pmkids = &cfg_priv->pmk_list->pmkids;
+ s32 err = 0;
+ int i;
+ int pmkid_len;
+
+ WL_TRACE("Enter\n");
+ if (!check_sys_up(wiphy))
+ return -EIO;
+
+ pmkid_len = le32_to_cpu(pmkids->npmkid);
+ for (i = 0; i < pmkid_len; i++)
+ if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
+ break;
+ if (i < WL_NUM_PMKIDS_MAX) {
+ memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
+ memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
+ if (i == pmkid_len) {
+ pmkid_len++;
+ pmkids->npmkid = cpu_to_le32(pmkid_len);
+ }
+ } else
+ err = -EINVAL;
+
+ WL_CONN("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
+ pmkids->pmkid[pmkid_len].BSSID);
+ for (i = 0; i < WLAN_PMKID_LEN; i++)
+ WL_CONN("%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
+
+ err = brcmf_update_pmklist(ndev, cfg_priv->pmk_list, err);
+
+ WL_TRACE("Exit\n");
+ return err;
+}
+
+static s32
+brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_pmksa *pmksa)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
+ struct pmkid_list pmkid;
+ s32 err = 0;
+ int i, pmkid_len;
+
+ WL_TRACE("Enter\n");
+ if (!check_sys_up(wiphy))
+ return -EIO;
+
+ memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
+ memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
+
+ WL_CONN("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
+ &pmkid.pmkid[0].BSSID);
+ for (i = 0; i < WLAN_PMKID_LEN; i++)
+ WL_CONN("%02x\n", pmkid.pmkid[0].PMKID[i]);
+
+ pmkid_len = le32_to_cpu(cfg_priv->pmk_list->pmkids.npmkid);
+ for (i = 0; i < pmkid_len; i++)
+ if (!memcmp
+ (pmksa->bssid, &cfg_priv->pmk_list->pmkids.pmkid[i].BSSID,
+ ETH_ALEN))
+ break;
+
+ if ((pmkid_len > 0)
+ && (i < pmkid_len)) {
+ memset(&cfg_priv->pmk_list->pmkids.pmkid[i], 0,
+ sizeof(struct pmkid));
+ for (; i < (pmkid_len - 1); i++) {
+ memcpy(&cfg_priv->pmk_list->pmkids.pmkid[i].BSSID,
+ &cfg_priv->pmk_list->pmkids.pmkid[i + 1].BSSID,
+ ETH_ALEN);
+ memcpy(&cfg_priv->pmk_list->pmkids.pmkid[i].PMKID,
+ &cfg_priv->pmk_list->pmkids.pmkid[i + 1].PMKID,
+ WLAN_PMKID_LEN);
+ }
+ cfg_priv->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
+ } else
+ err = -EINVAL;
+
+ err = brcmf_update_pmklist(ndev, cfg_priv->pmk_list, err);
+
+ WL_TRACE("Exit\n");
+ return err;
+
+}
+
+static s32
+brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
+ s32 err = 0;
+
+ WL_TRACE("Enter\n");
+ if (!check_sys_up(wiphy))
+ return -EIO;
+
+ memset(cfg_priv->pmk_list, 0, sizeof(*cfg_priv->pmk_list));
+ err = brcmf_update_pmklist(ndev, cfg_priv->pmk_list, err);
+
+ WL_TRACE("Exit\n");
+ return err;
+
+}
+
+static struct cfg80211_ops wl_cfg80211_ops = {
+ .change_virtual_intf = brcmf_cfg80211_change_iface,
+ .scan = brcmf_cfg80211_scan,
+ .set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
+ .join_ibss = brcmf_cfg80211_join_ibss,
+ .leave_ibss = brcmf_cfg80211_leave_ibss,
+ .get_station = brcmf_cfg80211_get_station,
+ .set_tx_power = brcmf_cfg80211_set_tx_power,
+ .get_tx_power = brcmf_cfg80211_get_tx_power,
+ .add_key = brcmf_cfg80211_add_key,
+ .del_key = brcmf_cfg80211_del_key,
+ .get_key = brcmf_cfg80211_get_key,
+ .set_default_key = brcmf_cfg80211_config_default_key,
+ .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
+ .set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
+ .set_bitrate_mask = brcmf_cfg80211_set_bitrate_mask,
+ .connect = brcmf_cfg80211_connect,
+ .disconnect = brcmf_cfg80211_disconnect,
+ .suspend = brcmf_cfg80211_suspend,
+ .resume = brcmf_cfg80211_resume,
+ .set_pmksa = brcmf_cfg80211_set_pmksa,
+ .del_pmksa = brcmf_cfg80211_del_pmksa,
+ .flush_pmksa = brcmf_cfg80211_flush_pmksa
+};
+
+static s32 brcmf_mode_to_nl80211_iftype(s32 mode)
+{
+ s32 err = 0;
+
+ switch (mode) {
+ case WL_MODE_BSS:
+ return NL80211_IFTYPE_STATION;
+ case WL_MODE_IBSS:
+ return NL80211_IFTYPE_ADHOC;
+ default:
+ return NL80211_IFTYPE_UNSPECIFIED;
+ }
+
+ return err;
+}
+
+static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface,
+ struct device *ndev)
+{
+ struct wireless_dev *wdev;
+ s32 err = 0;
+
+ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
+ if (!wdev)
+ return ERR_PTR(-ENOMEM);
+
+ wdev->wiphy =
+ wiphy_new(&wl_cfg80211_ops,
+ sizeof(struct brcmf_cfg80211_priv) + sizeof_iface);
+ if (!wdev->wiphy) {
+ WL_ERR("Couldn not allocate wiphy device\n");
+ err = -ENOMEM;
+ goto wiphy_new_out;
+ }
+ set_wiphy_dev(wdev->wiphy, ndev);
+ wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
+ wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
+ wdev->wiphy->interface_modes =
+ BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
+ wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
+ wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set
+ * it as 11a by default.
+ * This will be updated with
+ * 11n phy tables in
+ * "ifconfig up"
+ * if phy has 11n capability
+ */
+ wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ wdev->wiphy->cipher_suites = __wl_cipher_suites;
+ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
+ wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power
+ * save mode
+ * by default
+ */
+ err = wiphy_register(wdev->wiphy);
+ if (err < 0) {
+ WL_ERR("Couldn not register wiphy device (%d)\n", err);
+ goto wiphy_register_out;
+ }
+ return wdev;
+
+wiphy_register_out:
+ wiphy_free(wdev->wiphy);
+
+wiphy_new_out:
+ kfree(wdev);
+
+ return ERR_PTR(err);
+}
+
+static void brcmf_free_wdev(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct wireless_dev *wdev = cfg_priv->wdev;
+
+ if (!wdev) {
+ WL_ERR("wdev is invalid\n");
+ return;
+ }
+ wiphy_unregister(wdev->wiphy);
+ wiphy_free(wdev->wiphy);
+ kfree(wdev);
+ cfg_priv->wdev = NULL;
+}
+
+static bool brcmf_is_linkup(struct brcmf_cfg80211_priv *cfg_priv,
+ const struct brcmf_event_msg *e)
+{
+ u32 event = be32_to_cpu(e->event_type);
+ u32 status = be32_to_cpu(e->status);
+
+ if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
+ WL_CONN("Processing set ssid\n");
+ cfg_priv->link_up = true;
+ return true;
+ }
+
+ return false;
+}
+
+static bool brcmf_is_linkdown(struct brcmf_cfg80211_priv *cfg_priv,
+ const struct brcmf_event_msg *e)
+{
+ u32 event = be32_to_cpu(e->event_type);
+ u16 flags = be16_to_cpu(e->flags);
+
+ if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
+ WL_CONN("Processing link down\n");
+ return true;
+ }
+ return false;
+}
+
+static bool brcmf_is_nonetwork(struct brcmf_cfg80211_priv *cfg_priv,
+ const struct brcmf_event_msg *e)
+{
+ u32 event = be32_to_cpu(e->event_type);
+ u32 status = be32_to_cpu(e->status);
+
+ if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
+ WL_CONN("Processing Link %s & no network found\n",
+ be16_to_cpu(e->flags) & BRCMF_EVENT_MSG_LINK ?
+ "up" : "down");
+ return true;
+ }
+
+ if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
+ WL_CONN("Processing connecting & no network found\n");
+ return true;
+ }
+
+ return false;
+}
+
+static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv);
+
+ kfree(conn_info->req_ie);
+ conn_info->req_ie = NULL;
+ conn_info->req_ie_len = 0;
+ kfree(conn_info->resp_ie);
+ conn_info->resp_ie = NULL;
+ conn_info->resp_ie_len = 0;
+}
+
+static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct net_device *ndev = cfg_to_ndev(cfg_priv);
+ struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
+ struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv);
+ u32 req_len;
+ u32 resp_len;
+ s32 err = 0;
+
+ brcmf_clear_assoc_ies(cfg_priv);
+
+ err = brcmf_dev_bufvar_get(ndev, "assoc_info", cfg_priv->extra_buf,
+ WL_ASSOC_INFO_MAX);
+ if (err) {
+ WL_ERR("could not get assoc info (%d)\n", err);
+ return err;
+ }
+ assoc_info =
+ (struct brcmf_cfg80211_assoc_ielen_le *)cfg_priv->extra_buf;
+ req_len = le32_to_cpu(assoc_info->req_len);
+ resp_len = le32_to_cpu(assoc_info->resp_len);
+ if (req_len) {
+ err = brcmf_dev_bufvar_get(ndev, "assoc_req_ies",
+ cfg_priv->extra_buf,
+ WL_ASSOC_INFO_MAX);
+ if (err) {
+ WL_ERR("could not get assoc req (%d)\n", err);
+ return err;
+ }
+ conn_info->req_ie_len = req_len;
+ conn_info->req_ie =
+ kmemdup(cfg_priv->extra_buf, conn_info->req_ie_len,
+ GFP_KERNEL);
+ } else {
+ conn_info->req_ie_len = 0;
+ conn_info->req_ie = NULL;
+ }
+ if (resp_len) {
+ err = brcmf_dev_bufvar_get(ndev, "assoc_resp_ies",
+ cfg_priv->extra_buf,
+ WL_ASSOC_INFO_MAX);
+ if (err) {
+ WL_ERR("could not get assoc resp (%d)\n", err);
+ return err;
+ }
+ conn_info->resp_ie_len = resp_len;
+ conn_info->resp_ie =
+ kmemdup(cfg_priv->extra_buf, conn_info->resp_ie_len,
+ GFP_KERNEL);
+ } else {
+ conn_info->resp_ie_len = 0;
+ conn_info->resp_ie = NULL;
+ }
+ WL_CONN("req len (%d) resp len (%d)\n",
+ conn_info->req_ie_len, conn_info->resp_ie_len);
+
+ return err;
+}
+
+static s32
+brcmf_bss_roaming_done(struct brcmf_cfg80211_priv *cfg_priv,
+ struct net_device *ndev,
+ const struct brcmf_event_msg *e)
+{
+ struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv);
+ struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
+ struct brcmf_channel_info_le channel_le;
+ struct ieee80211_channel *notify_channel;
+ struct ieee80211_supported_band *band;
+ u32 freq;
+ s32 err = 0;
+ u32 target_channel;
+
+ WL_TRACE("Enter\n");
+
+ brcmf_get_assoc_ies(cfg_priv);
+ brcmf_update_prof(cfg_priv, NULL, &e->addr, WL_PROF_BSSID);
+ brcmf_update_bss_info(cfg_priv);
+
+ brcmf_exec_dcmd(ndev, BRCMF_C_GET_CHANNEL, &channel_le,
+ sizeof(channel_le));
+
+ target_channel = le32_to_cpu(channel_le.target_channel);
+ WL_CONN("Roamed to channel %d\n", target_channel);
+
+ if (target_channel <= CH_MAX_2G_CHANNEL)
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
+ else
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
+
+ freq = ieee80211_channel_to_frequency(target_channel, band->band);
+ notify_channel = ieee80211_get_channel(wiphy, freq);
+
+ cfg80211_roamed(ndev, notify_channel,
+ (u8 *)brcmf_read_prof(cfg_priv, WL_PROF_BSSID),
+ conn_info->req_ie, conn_info->req_ie_len,
+ conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
+ WL_CONN("Report roaming result\n");
+
+ set_bit(WL_STATUS_CONNECTED, &cfg_priv->status);
+ WL_TRACE("Exit\n");
+ return err;
+}
+
+static s32
+brcmf_bss_connect_done(struct brcmf_cfg80211_priv *cfg_priv,
+ struct net_device *ndev, const struct brcmf_event_msg *e,
+ bool completed)
+{
+ struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv);
+ s32 err = 0;
+
+ WL_TRACE("Enter\n");
+
+ if (test_and_clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) {
+ if (completed) {
+ brcmf_get_assoc_ies(cfg_priv);
+ brcmf_update_prof(cfg_priv, NULL, &e->addr,
+ WL_PROF_BSSID);
+ brcmf_update_bss_info(cfg_priv);
+ }
+ cfg80211_connect_result(ndev,
+ (u8 *)brcmf_read_prof(cfg_priv,
+ WL_PROF_BSSID),
+ conn_info->req_ie,
+ conn_info->req_ie_len,
+ conn_info->resp_ie,
+ conn_info->resp_ie_len,
+ completed ? WLAN_STATUS_SUCCESS :
+ WLAN_STATUS_AUTH_TIMEOUT,
+ GFP_KERNEL);
+ if (completed)
+ set_bit(WL_STATUS_CONNECTED, &cfg_priv->status);
+ WL_CONN("Report connect result - connection %s\n",
+ completed ? "succeeded" : "failed");
+ }
+ WL_TRACE("Exit\n");
+ return err;
+}
+
+static s32
+brcmf_notify_connect_status(struct brcmf_cfg80211_priv *cfg_priv,
+ struct net_device *ndev,
+ const struct brcmf_event_msg *e, void *data)
+{
+ s32 err = 0;
+
+ if (brcmf_is_linkup(cfg_priv, e)) {
+ WL_CONN("Linkup\n");
+ if (brcmf_is_ibssmode(cfg_priv)) {
+ brcmf_update_prof(cfg_priv, NULL, (void *)e->addr,
+ WL_PROF_BSSID);
+ wl_inform_ibss(cfg_priv, ndev, e->addr);
+ cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
+ clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
+ set_bit(WL_STATUS_CONNECTED, &cfg_priv->status);
+ } else
+ brcmf_bss_connect_done(cfg_priv, ndev, e, true);
+ } else if (brcmf_is_linkdown(cfg_priv, e)) {
+ WL_CONN("Linkdown\n");
+ if (brcmf_is_ibssmode(cfg_priv)) {
+ clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
+ if (test_and_clear_bit(WL_STATUS_CONNECTED,
+ &cfg_priv->status))
+ brcmf_link_down(cfg_priv);
+ } else {
+ brcmf_bss_connect_done(cfg_priv, ndev, e, false);
+ if (test_and_clear_bit(WL_STATUS_CONNECTED,
+ &cfg_priv->status)) {
+ cfg80211_disconnected(ndev, 0, NULL, 0,
+ GFP_KERNEL);
+ brcmf_link_down(cfg_priv);
+ }
+ }
+ brcmf_init_prof(cfg_priv->profile);
+ } else if (brcmf_is_nonetwork(cfg_priv, e)) {
+ if (brcmf_is_ibssmode(cfg_priv))
+ clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
+ else
+ brcmf_bss_connect_done(cfg_priv, ndev, e, false);
+ }
+
+ return err;
+}
+
+static s32
+brcmf_notify_roaming_status(struct brcmf_cfg80211_priv *cfg_priv,
+ struct net_device *ndev,
+ const struct brcmf_event_msg *e, void *data)
+{
+ s32 err = 0;
+ u32 event = be32_to_cpu(e->event_type);
+ u32 status = be32_to_cpu(e->status);
+
+ if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
+ if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status))
+ brcmf_bss_roaming_done(cfg_priv, ndev, e);
+ else
+ brcmf_bss_connect_done(cfg_priv, ndev, e, true);
+ }
+
+ return err;
+}
+
+static s32
+brcmf_notify_mic_status(struct brcmf_cfg80211_priv *cfg_priv,
+ struct net_device *ndev,
+ const struct brcmf_event_msg *e, void *data)
+{
+ u16 flags = be16_to_cpu(e->flags);
+ enum nl80211_key_type key_type;
+
+ if (flags & BRCMF_EVENT_MSG_GROUP)
+ key_type = NL80211_KEYTYPE_GROUP;
+ else
+ key_type = NL80211_KEYTYPE_PAIRWISE;
+
+ cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1,
+ NULL, GFP_KERNEL);
+
+ return 0;
+}
+
+static s32
+brcmf_notify_scan_status(struct brcmf_cfg80211_priv *cfg_priv,
+ struct net_device *ndev,
+ const struct brcmf_event_msg *e, void *data)
+{
+ struct brcmf_channel_info_le channel_inform_le;
+ struct brcmf_scan_results_le *bss_list_le;
+ u32 len = WL_SCAN_BUF_MAX;
+ s32 err = 0;
+ bool scan_abort = false;
+ u32 scan_channel;
+
+ WL_TRACE("Enter\n");
+
+ if (cfg_priv->iscan_on && cfg_priv->iscan_kickstart) {
+ WL_TRACE("Exit\n");
+ return brcmf_wakeup_iscan(cfg_to_iscan(cfg_priv));
+ }
+
+ if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg_priv->status)) {
+ WL_ERR("Scan complete while device not scanning\n");
+ scan_abort = true;
+ err = -EINVAL;
+ goto scan_done_out;
+ }
+
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_CHANNEL, &channel_inform_le,
+ sizeof(channel_inform_le));
+ if (err) {
+ WL_ERR("scan busy (%d)\n", err);
+ scan_abort = true;
+ goto scan_done_out;
+ }
+ scan_channel = le32_to_cpu(channel_inform_le.scan_channel);
+ if (scan_channel)
+ WL_CONN("channel_inform.scan_channel (%d)\n", scan_channel);
+ cfg_priv->bss_list = cfg_priv->scan_results;
+ bss_list_le = (struct brcmf_scan_results_le *) cfg_priv->bss_list;
+
+ memset(cfg_priv->scan_results, 0, len);
+ bss_list_le->buflen = cpu_to_le32(len);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN_RESULTS,
+ cfg_priv->scan_results, len);
+ if (err) {
+ WL_ERR("%s Scan_results error (%d)\n", ndev->name, err);
+ err = -EINVAL;
+ scan_abort = true;
+ goto scan_done_out;
+ }
+ cfg_priv->scan_results->buflen = le32_to_cpu(bss_list_le->buflen);
+ cfg_priv->scan_results->version = le32_to_cpu(bss_list_le->version);
+ cfg_priv->scan_results->count = le32_to_cpu(bss_list_le->count);
+
+ err = brcmf_inform_bss(cfg_priv);
+ if (err) {
+ scan_abort = true;
+ goto scan_done_out;
+ }
+
+scan_done_out:
+ if (cfg_priv->scan_request) {
+ WL_SCAN("calling cfg80211_scan_done\n");
+ cfg80211_scan_done(cfg_priv->scan_request, scan_abort);
+ brcmf_set_mpc(ndev, 1);
+ cfg_priv->scan_request = NULL;
+ }
+
+ WL_TRACE("Exit\n");
+
+ return err;
+}
+
+static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
+{
+ conf->mode = (u32)-1;
+ conf->frag_threshold = (u32)-1;
+ conf->rts_threshold = (u32)-1;
+ conf->retry_short = (u32)-1;
+ conf->retry_long = (u32)-1;
+ conf->tx_power = -1;
+}
+
+static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el)
+{
+ memset(el, 0, sizeof(*el));
+ el->handler[BRCMF_E_SCAN_COMPLETE] = brcmf_notify_scan_status;
+ el->handler[BRCMF_E_LINK] = brcmf_notify_connect_status;
+ el->handler[BRCMF_E_ROAM] = brcmf_notify_roaming_status;
+ el->handler[BRCMF_E_MIC_ERROR] = brcmf_notify_mic_status;
+ el->handler[BRCMF_E_SET_SSID] = brcmf_notify_connect_status;
+}
+
+static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ kfree(cfg_priv->scan_results);
+ cfg_priv->scan_results = NULL;
+ kfree(cfg_priv->bss_info);
+ cfg_priv->bss_info = NULL;
+ kfree(cfg_priv->conf);
+ cfg_priv->conf = NULL;
+ kfree(cfg_priv->profile);
+ cfg_priv->profile = NULL;
+ kfree(cfg_priv->scan_req_int);
+ cfg_priv->scan_req_int = NULL;
+ kfree(cfg_priv->dcmd_buf);
+ cfg_priv->dcmd_buf = NULL;
+ kfree(cfg_priv->extra_buf);
+ cfg_priv->extra_buf = NULL;
+ kfree(cfg_priv->iscan);
+ cfg_priv->iscan = NULL;
+ kfree(cfg_priv->pmk_list);
+ cfg_priv->pmk_list = NULL;
+}
+
+static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ cfg_priv->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL);
+ if (!cfg_priv->scan_results)
+ goto init_priv_mem_out;
+ cfg_priv->conf = kzalloc(sizeof(*cfg_priv->conf), GFP_KERNEL);
+ if (!cfg_priv->conf)
+ goto init_priv_mem_out;
+ cfg_priv->profile = kzalloc(sizeof(*cfg_priv->profile), GFP_KERNEL);
+ if (!cfg_priv->profile)
+ goto init_priv_mem_out;
+ cfg_priv->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
+ if (!cfg_priv->bss_info)
+ goto init_priv_mem_out;
+ cfg_priv->scan_req_int = kzalloc(sizeof(*cfg_priv->scan_req_int),
+ GFP_KERNEL);
+ if (!cfg_priv->scan_req_int)
+ goto init_priv_mem_out;
+ cfg_priv->dcmd_buf = kzalloc(WL_DCMD_LEN_MAX, GFP_KERNEL);
+ if (!cfg_priv->dcmd_buf)
+ goto init_priv_mem_out;
+ cfg_priv->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
+ if (!cfg_priv->extra_buf)
+ goto init_priv_mem_out;
+ cfg_priv->iscan = kzalloc(sizeof(*cfg_priv->iscan), GFP_KERNEL);
+ if (!cfg_priv->iscan)
+ goto init_priv_mem_out;
+ cfg_priv->pmk_list = kzalloc(sizeof(*cfg_priv->pmk_list), GFP_KERNEL);
+ if (!cfg_priv->pmk_list)
+ goto init_priv_mem_out;
+
+ return 0;
+
+init_priv_mem_out:
+ brcmf_deinit_priv_mem(cfg_priv);
+
+ return -ENOMEM;
+}
+
+/*
+* retrieve first queued event from head
+*/
+
+static struct brcmf_cfg80211_event_q *brcmf_deq_event(
+ struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct brcmf_cfg80211_event_q *e = NULL;
+
+ spin_lock_irq(&cfg_priv->evt_q_lock);
+ if (!list_empty(&cfg_priv->evt_q_list)) {
+ e = list_first_entry(&cfg_priv->evt_q_list,
+ struct brcmf_cfg80211_event_q, evt_q_list);
+ list_del(&e->evt_q_list);
+ }
+ spin_unlock_irq(&cfg_priv->evt_q_lock);
+
+ return e;
+}
+
+/*
+** push event to tail of the queue
+*/
+
+static s32
+brcmf_enq_event(struct brcmf_cfg80211_priv *cfg_priv, u32 event,
+ const struct brcmf_event_msg *msg)
+{
+ struct brcmf_cfg80211_event_q *e;
+ s32 err = 0;
+
+ e = kzalloc(sizeof(struct brcmf_cfg80211_event_q), GFP_KERNEL);
+ if (!e)
+ return -ENOMEM;
+
+ e->etype = event;
+ memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg));
+
+ spin_lock_irq(&cfg_priv->evt_q_lock);
+ list_add_tail(&e->evt_q_list, &cfg_priv->evt_q_list);
+ spin_unlock_irq(&cfg_priv->evt_q_lock);
+
+ return err;
+}
+
+static void brcmf_put_event(struct brcmf_cfg80211_event_q *e)
+{
+ kfree(e);
+}
+
+static void brcmf_cfg80211_event_handler(struct work_struct *work)
+{
+ struct brcmf_cfg80211_priv *cfg_priv =
+ container_of(work, struct brcmf_cfg80211_priv,
+ event_work);
+ struct brcmf_cfg80211_event_q *e;
+
+ e = brcmf_deq_event(cfg_priv);
+ if (unlikely(!e)) {
+ WL_ERR("event queue empty...\n");
+ return;
+ }
+
+ do {
+ WL_INFO("event type (%d)\n", e->etype);
+ if (cfg_priv->el.handler[e->etype])
+ cfg_priv->el.handler[e->etype](cfg_priv,
+ cfg_to_ndev(cfg_priv),
+ &e->emsg, e->edata);
+ else
+ WL_INFO("Unknown Event (%d): ignoring\n", e->etype);
+ brcmf_put_event(e);
+ } while ((e = brcmf_deq_event(cfg_priv)));
+
+}
+
+static void brcmf_init_eq(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ spin_lock_init(&cfg_priv->evt_q_lock);
+ INIT_LIST_HEAD(&cfg_priv->evt_q_list);
+}
+
+static void brcmf_flush_eq(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct brcmf_cfg80211_event_q *e;
+
+ spin_lock_irq(&cfg_priv->evt_q_lock);
+ while (!list_empty(&cfg_priv->evt_q_list)) {
+ e = list_first_entry(&cfg_priv->evt_q_list,
+ struct brcmf_cfg80211_event_q, evt_q_list);
+ list_del(&e->evt_q_list);
+ kfree(e);
+ }
+ spin_unlock_irq(&cfg_priv->evt_q_lock);
+}
+
+static s32 wl_init_priv(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ s32 err = 0;
+
+ cfg_priv->scan_request = NULL;
+ cfg_priv->pwr_save = true;
+ cfg_priv->iscan_on = true; /* iscan on & off switch.
+ we enable iscan per default */
+ cfg_priv->roam_on = true; /* roam on & off switch.
+ we enable roam per default */
+
+ cfg_priv->iscan_kickstart = false;
+ cfg_priv->active_scan = true; /* we do active scan for
+ specific scan per default */
+ cfg_priv->dongle_up = false; /* dongle is not up yet */
+ brcmf_init_eq(cfg_priv);
+ err = brcmf_init_priv_mem(cfg_priv);
+ if (err)
+ return err;
+ INIT_WORK(&cfg_priv->event_work, brcmf_cfg80211_event_handler);
+ brcmf_init_eloop_handler(&cfg_priv->el);
+ mutex_init(&cfg_priv->usr_sync);
+ err = brcmf_init_iscan(cfg_priv);
+ if (err)
+ return err;
+ brcmf_init_conf(cfg_priv->conf);
+ brcmf_init_prof(cfg_priv->profile);
+ brcmf_link_down(cfg_priv);
+
+ return err;
+}
+
+static void wl_deinit_priv(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ cancel_work_sync(&cfg_priv->event_work);
+ cfg_priv->dongle_up = false; /* dongle down */
+ brcmf_flush_eq(cfg_priv);
+ brcmf_link_down(cfg_priv);
+ brcmf_term_iscan(cfg_priv);
+ brcmf_deinit_priv_mem(cfg_priv);
+}
+
+struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev,
+ struct device *busdev,
+ void *data)
+{
+ struct wireless_dev *wdev;
+ struct brcmf_cfg80211_priv *cfg_priv;
+ struct brcmf_cfg80211_iface *ci;
+ struct brcmf_cfg80211_dev *cfg_dev;
+ s32 err = 0;
+
+ if (!ndev) {
+ WL_ERR("ndev is invalid\n");
+ return NULL;
+ }
+ cfg_dev = kzalloc(sizeof(struct brcmf_cfg80211_dev), GFP_KERNEL);
+ if (!cfg_dev)
+ return NULL;
+
+ wdev = brcmf_alloc_wdev(sizeof(struct brcmf_cfg80211_iface), busdev);
+ if (IS_ERR(wdev)) {
+ kfree(cfg_dev);
+ return NULL;
+ }
+
+ wdev->iftype = brcmf_mode_to_nl80211_iftype(WL_MODE_BSS);
+ cfg_priv = wdev_to_cfg(wdev);
+ cfg_priv->wdev = wdev;
+ cfg_priv->pub = data;
+ ci = (struct brcmf_cfg80211_iface *)&cfg_priv->ci;
+ ci->cfg_priv = cfg_priv;
+ ndev->ieee80211_ptr = wdev;
+ SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
+ wdev->netdev = ndev;
+ err = wl_init_priv(cfg_priv);
+ if (err) {
+ WL_ERR("Failed to init iwm_priv (%d)\n", err);
+ goto cfg80211_attach_out;
+ }
+ brcmf_set_drvdata(cfg_dev, ci);
+
+ return cfg_dev;
+
+cfg80211_attach_out:
+ brcmf_free_wdev(cfg_priv);
+ kfree(cfg_dev);
+ return NULL;
+}
+
+void brcmf_cfg80211_detach(struct brcmf_cfg80211_dev *cfg_dev)
+{
+ struct brcmf_cfg80211_priv *cfg_priv;
+
+ cfg_priv = brcmf_priv_get(cfg_dev);
+
+ wl_deinit_priv(cfg_priv);
+ brcmf_free_wdev(cfg_priv);
+ brcmf_set_drvdata(cfg_dev, NULL);
+ kfree(cfg_dev);
+}
+
+void
+brcmf_cfg80211_event(struct net_device *ndev,
+ const struct brcmf_event_msg *e, void *data)
+{
+ u32 event_type = be32_to_cpu(e->event_type);
+ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
+
+ if (!brcmf_enq_event(cfg_priv, event_type, e))
+ schedule_work(&cfg_priv->event_work);
+}
+
+static s32 brcmf_dongle_mode(struct net_device *ndev, s32 iftype)
+{
+ s32 infra = 0;
+ s32 err = 0;
+
+ switch (iftype) {
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_WDS:
+ WL_ERR("type (%d) : currently we do not support this mode\n",
+ iftype);
+ err = -EINVAL;
+ return err;
+ case NL80211_IFTYPE_ADHOC:
+ infra = 0;
+ break;
+ case NL80211_IFTYPE_STATION:
+ infra = 1;
+ break;
+ default:
+ err = -EINVAL;
+ WL_ERR("invalid type (%d)\n", iftype);
+ return err;
+ }
+ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra);
+ if (err) {
+ WL_ERR("WLC_SET_INFRA error (%d)\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static s32 brcmf_dongle_eventmsg(struct net_device *ndev)
+{
+ /* Room for "event_msgs" + '\0' + bitvec */
+ s8 iovbuf[BRCMF_EVENTING_MASK_LEN + 12];
+ s8 eventmask[BRCMF_EVENTING_MASK_LEN];
+ s32 err = 0;
+
+ WL_TRACE("Enter\n");
+
+ /* Setup event_msgs */
+ brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN,
+ iovbuf, sizeof(iovbuf));
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, iovbuf, sizeof(iovbuf));
+ if (err) {
+ WL_ERR("Get event_msgs error (%d)\n", err);
+ goto dongle_eventmsg_out;
+ }
+ memcpy(eventmask, iovbuf, BRCMF_EVENTING_MASK_LEN);
+
+ setbit(eventmask, BRCMF_E_SET_SSID);
+ setbit(eventmask, BRCMF_E_ROAM);
+ setbit(eventmask, BRCMF_E_PRUNE);
+ setbit(eventmask, BRCMF_E_AUTH);
+ setbit(eventmask, BRCMF_E_REASSOC);
+ setbit(eventmask, BRCMF_E_REASSOC_IND);
+ setbit(eventmask, BRCMF_E_DEAUTH_IND);
+ setbit(eventmask, BRCMF_E_DISASSOC_IND);
+ setbit(eventmask, BRCMF_E_DISASSOC);
+ setbit(eventmask, BRCMF_E_JOIN);
+ setbit(eventmask, BRCMF_E_ASSOC_IND);
+ setbit(eventmask, BRCMF_E_PSK_SUP);
+ setbit(eventmask, BRCMF_E_LINK);
+ setbit(eventmask, BRCMF_E_NDIS_LINK);
+ setbit(eventmask, BRCMF_E_MIC_ERROR);
+ setbit(eventmask, BRCMF_E_PMKID_CACHE);
+ setbit(eventmask, BRCMF_E_TXFAIL);
+ setbit(eventmask, BRCMF_E_JOIN_START);
+ setbit(eventmask, BRCMF_E_SCAN_COMPLETE);
+
+ brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN,
+ iovbuf, sizeof(iovbuf));
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf));
+ if (err) {
+ WL_ERR("Set event_msgs error (%d)\n", err);
+ goto dongle_eventmsg_out;
+ }
+
+dongle_eventmsg_out:
+ WL_TRACE("Exit\n");
+ return err;
+}
+
+static s32
+brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
+{
+ s8 iovbuf[32];
+ s32 err = 0;
+ __le32 roamtrigger[2];
+ __le32 roam_delta[2];
+ __le32 bcn_to_le;
+ __le32 roamvar_le;
+
+ /*
+ * Setup timeout if Beacons are lost and roam is
+ * off to report link down
+ */
+ if (roamvar) {
+ bcn_to_le = cpu_to_le32(bcn_timeout);
+ brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_to_le,
+ sizeof(bcn_to_le), iovbuf, sizeof(iovbuf));
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR,
+ iovbuf, sizeof(iovbuf));
+ if (err) {
+ WL_ERR("bcn_timeout error (%d)\n", err);
+ goto dongle_rom_out;
+ }
+ }
+
+ /*
+ * Enable/Disable built-in roaming to allow supplicant
+ * to take care of roaming
+ */
+ WL_INFO("Internal Roaming = %s\n", roamvar ? "Off" : "On");
+ roamvar_le = cpu_to_le32(roamvar);
+ brcmf_c_mkiovar("roam_off", (char *)&roamvar_le,
+ sizeof(roamvar_le), iovbuf, sizeof(iovbuf));
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf));
+ if (err) {
+ WL_ERR("roam_off error (%d)\n", err);
+ goto dongle_rom_out;
+ }
+
+ roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
+ roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_ROAM_TRIGGER,
+ (void *)roamtrigger, sizeof(roamtrigger));
+ if (err) {
+ WL_ERR("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
+ goto dongle_rom_out;
+ }
+
+ roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
+ roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_ROAM_DELTA,
+ (void *)roam_delta, sizeof(roam_delta));
+ if (err) {
+ WL_ERR("WLC_SET_ROAM_DELTA error (%d)\n", err);
+ goto dongle_rom_out;
+ }
+
+dongle_rom_out:
+ return err;
+}
+
+static s32
+brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
+ s32 scan_unassoc_time, s32 scan_passive_time)
+{
+ s32 err = 0;
+ __le32 scan_assoc_tm_le = cpu_to_le32(scan_assoc_time);
+ __le32 scan_unassoc_tm_le = cpu_to_le32(scan_unassoc_time);
+ __le32 scan_passive_tm_le = cpu_to_le32(scan_passive_time);
+
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_CHANNEL_TIME,
+ &scan_assoc_tm_le, sizeof(scan_assoc_tm_le));
+ if (err) {
+ if (err == -EOPNOTSUPP)
+ WL_INFO("Scan assoc time is not supported\n");
+ else
+ WL_ERR("Scan assoc time error (%d)\n", err);
+ goto dongle_scantime_out;
+ }
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_UNASSOC_TIME,
+ &scan_unassoc_tm_le, sizeof(scan_unassoc_tm_le));
+ if (err) {
+ if (err == -EOPNOTSUPP)
+ WL_INFO("Scan unassoc time is not supported\n");
+ else
+ WL_ERR("Scan unassoc time error (%d)\n", err);
+ goto dongle_scantime_out;
+ }
+
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_PASSIVE_TIME,
+ &scan_passive_tm_le, sizeof(scan_passive_tm_le));
+ if (err) {
+ if (err == -EOPNOTSUPP)
+ WL_INFO("Scan passive time is not supported\n");
+ else
+ WL_ERR("Scan passive time error (%d)\n", err);
+ goto dongle_scantime_out;
+ }
+
+dongle_scantime_out:
+ return err;
+}
+
+static s32 wl_update_wiphybands(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct wiphy *wiphy;
+ s32 phy_list;
+ s8 phy;
+ s32 err = 0;
+
+ err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCM_GET_PHYLIST,
+ &phy_list, sizeof(phy_list));
+ if (err) {
+ WL_ERR("error (%d)\n", err);
+ return err;
+ }
+
+ phy = ((char *)&phy_list)[1];
+ WL_INFO("%c phy\n", phy);
+ if (phy == 'n' || phy == 'a') {
+ wiphy = cfg_to_wiphy(cfg_priv);
+ wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
+ }
+
+ return err;
+}
+
+static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ return wl_update_wiphybands(cfg_priv);
+}
+
+static s32 brcmf_config_dongle(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct net_device *ndev;
+ struct wireless_dev *wdev;
+ s32 power_mode;
+ s32 err = 0;
+
+ if (cfg_priv->dongle_up)
+ return err;
+
+ ndev = cfg_to_ndev(cfg_priv);
+ wdev = ndev->ieee80211_ptr;
+
+ brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME,
+ WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
+
+ err = brcmf_dongle_eventmsg(ndev);
+ if (err)
+ goto default_conf_out;
+
+ power_mode = cfg_priv->pwr_save ? PM_FAST : PM_OFF;
+ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &power_mode);
+ if (err)
+ goto default_conf_out;
+ WL_INFO("power save set to %s\n",
+ (power_mode ? "enabled" : "disabled"));
+
+ err = brcmf_dongle_roam(ndev, (cfg_priv->roam_on ? 0 : 1),
+ WL_BEACON_TIMEOUT);
+ if (err)
+ goto default_conf_out;
+ err = brcmf_dongle_mode(ndev, wdev->iftype);
+ if (err && err != -EINPROGRESS)
+ goto default_conf_out;
+ err = brcmf_dongle_probecap(cfg_priv);
+ if (err)
+ goto default_conf_out;
+
+ /* -EINPROGRESS: Call commit handler */
+
+default_conf_out:
+
+ cfg_priv->dongle_up = true;
+
+ return err;
+
+}
+
+static int brcmf_debugfs_add_netdev_params(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ char buf[10+IFNAMSIZ];
+ struct dentry *fd;
+ s32 err = 0;
+
+ sprintf(buf, "netdev:%s", cfg_to_ndev(cfg_priv)->name);
+ cfg_priv->debugfsdir = debugfs_create_dir(buf,
+ cfg_to_wiphy(cfg_priv)->debugfsdir);
+
+ fd = debugfs_create_u16("beacon_int", S_IRUGO, cfg_priv->debugfsdir,
+ (u16 *)&cfg_priv->profile->beacon_interval);
+ if (!fd) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ fd = debugfs_create_u8("dtim_period", S_IRUGO, cfg_priv->debugfsdir,
+ (u8 *)&cfg_priv->profile->dtim_period);
+ if (!fd) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+err_out:
+ return err;
+}
+
+static void brcmf_debugfs_remove_netdev(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ debugfs_remove_recursive(cfg_priv->debugfsdir);
+ cfg_priv->debugfsdir = NULL;
+}
+
+static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ s32 err = 0;
+
+ set_bit(WL_STATUS_READY, &cfg_priv->status);
+
+ brcmf_debugfs_add_netdev_params(cfg_priv);
+
+ err = brcmf_config_dongle(cfg_priv);
+ if (err)
+ return err;
+
+ brcmf_invoke_iscan(cfg_priv);
+
+ return err;
+}
+
+static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ /*
+ * While going down, if associated with AP disassociate
+ * from AP to save power
+ */
+ if ((test_bit(WL_STATUS_CONNECTED, &cfg_priv->status) ||
+ test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) &&
+ test_bit(WL_STATUS_READY, &cfg_priv->status)) {
+ WL_INFO("Disassociating from AP");
+ brcmf_link_down(cfg_priv);
+
+ /* Make sure WPA_Supplicant receives all the event
+ generated due to DISASSOC call to the fw to keep
+ the state fw and WPA_Supplicant state consistent
+ */
+ brcmf_delay(500);
+ }
+
+ set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
+ brcmf_term_iscan(cfg_priv);
+ if (cfg_priv->scan_request) {
+ cfg80211_scan_done(cfg_priv->scan_request, true);
+ /* May need to perform this to cover rmmod */
+ /* wl_set_mpc(cfg_to_ndev(wl), 1); */
+ cfg_priv->scan_request = NULL;
+ }
+ clear_bit(WL_STATUS_READY, &cfg_priv->status);
+ clear_bit(WL_STATUS_SCANNING, &cfg_priv->status);
+ clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
+
+ brcmf_debugfs_remove_netdev(cfg_priv);
+
+ return 0;
+}
+
+s32 brcmf_cfg80211_up(struct brcmf_cfg80211_dev *cfg_dev)
+{
+ struct brcmf_cfg80211_priv *cfg_priv;
+ s32 err = 0;
+
+ cfg_priv = brcmf_priv_get(cfg_dev);
+ mutex_lock(&cfg_priv->usr_sync);
+ err = __brcmf_cfg80211_up(cfg_priv);
+ mutex_unlock(&cfg_priv->usr_sync);
+
+ return err;
+}
+
+s32 brcmf_cfg80211_down(struct brcmf_cfg80211_dev *cfg_dev)
+{
+ struct brcmf_cfg80211_priv *cfg_priv;
+ s32 err = 0;
+
+ cfg_priv = brcmf_priv_get(cfg_dev);
+ mutex_lock(&cfg_priv->usr_sync);
+ err = __brcmf_cfg80211_down(cfg_priv);
+ mutex_unlock(&cfg_priv->usr_sync);
+
+ return err;
+}
+
+static __used s32 brcmf_add_ie(struct brcmf_cfg80211_priv *cfg_priv,
+ u8 t, u8 l, u8 *v)
+{
+ struct brcmf_cfg80211_ie *ie = &cfg_priv->ie;
+ s32 err = 0;
+
+ if (ie->offset + l + 2 > WL_TLV_INFO_MAX) {
+ WL_ERR("ei crosses buffer boundary\n");
+ return -ENOSPC;
+ }
+ ie->buf[ie->offset] = t;
+ ie->buf[ie->offset + 1] = l;
+ memcpy(&ie->buf[ie->offset + 2], v, l);
+ ie->offset += l + 2;
+
+ return err;
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
new file mode 100644
index 000000000000..62dc46144ede
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2010 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 _wl_cfg80211_h_
+#define _wl_cfg80211_h_
+
+struct brcmf_cfg80211_conf;
+struct brcmf_cfg80211_iface;
+struct brcmf_cfg80211_priv;
+struct brcmf_cfg80211_security;
+struct brcmf_cfg80211_ibss;
+
+#define WL_DBG_NONE 0
+#define WL_DBG_CONN (1 << 5)
+#define WL_DBG_SCAN (1 << 4)
+#define WL_DBG_TRACE (1 << 3)
+#define WL_DBG_INFO (1 << 1)
+#define WL_DBG_ERR (1 << 0)
+#define WL_DBG_MASK ((WL_DBG_INFO | WL_DBG_ERR | WL_DBG_TRACE) | \
+ (WL_DBG_SCAN) | (WL_DBG_CONN))
+
+#define WL_ERR(fmt, args...) \
+do { \
+ if (brcmf_dbg_level & WL_DBG_ERR) { \
+ if (net_ratelimit()) { \
+ printk(KERN_ERR "ERROR @%s : " fmt, \
+ __func__, ##args); \
+ } \
+ } \
+} while (0)
+
+#if (defined BCMDBG)
+#define WL_INFO(fmt, args...) \
+do { \
+ if (brcmf_dbg_level & WL_DBG_INFO) { \
+ if (net_ratelimit()) { \
+ printk(KERN_ERR "INFO @%s : " fmt, \
+ __func__, ##args); \
+ } \
+ } \
+} while (0)
+
+#define WL_TRACE(fmt, args...) \
+do { \
+ if (brcmf_dbg_level & WL_DBG_TRACE) { \
+ if (net_ratelimit()) { \
+ printk(KERN_ERR "TRACE @%s : " fmt, \
+ __func__, ##args); \
+ } \
+ } \
+} while (0)
+
+#define WL_SCAN(fmt, args...) \
+do { \
+ if (brcmf_dbg_level & WL_DBG_SCAN) { \
+ if (net_ratelimit()) { \
+ printk(KERN_ERR "SCAN @%s : " fmt, \
+ __func__, ##args); \
+ } \
+ } \
+} while (0)
+
+#define WL_CONN(fmt, args...) \
+do { \
+ if (brcmf_dbg_level & WL_DBG_CONN) { \
+ if (net_ratelimit()) { \
+ printk(KERN_ERR "CONN @%s : " fmt, \
+ __func__, ##args); \
+ } \
+ } \
+} while (0)
+
+#else /* (defined BCMDBG) */
+#define WL_INFO(fmt, args...)
+#define WL_TRACE(fmt, args...)
+#define WL_SCAN(fmt, args...)
+#define WL_CONN(fmt, args...)
+#endif /* (defined BCMDBG) */
+
+#define WL_NUM_SCAN_MAX 1
+#define WL_NUM_PMKIDS_MAX MAXPMKID /* will be used
+ * for 2.6.33 kernel
+ * or later
+ */
+#define WL_SCAN_BUF_MAX (1024 * 8)
+#define WL_TLV_INFO_MAX 1024
+#define WL_BSS_INFO_MAX 2048
+#define WL_ASSOC_INFO_MAX 512 /*
+ * needs to grab assoc info from dongle to
+ * report it to cfg80211 through "connect"
+ * event
+ */
+#define WL_DCMD_LEN_MAX 1024
+#define WL_EXTRA_BUF_MAX 2048
+#define WL_ISCAN_BUF_MAX 2048 /*
+ * the buf length can be BRCMF_DCMD_MAXLEN
+ * to reduce iteration
+ */
+#define WL_ISCAN_TIMER_INTERVAL_MS 3000
+#define WL_SCAN_ERSULTS_LAST (BRCMF_SCAN_RESULTS_NO_MEM+1)
+#define WL_AP_MAX 256 /* virtually unlimitted as long
+ * as kernel memory allows
+ */
+
+#define WL_ROAM_TRIGGER_LEVEL -75
+#define WL_ROAM_DELTA 20
+#define WL_BEACON_TIMEOUT 3
+
+#define WL_SCAN_CHANNEL_TIME 40
+#define WL_SCAN_UNASSOC_TIME 40
+#define WL_SCAN_PASSIVE_TIME 120
+
+/* dongle status */
+enum wl_status {
+ WL_STATUS_READY,
+ WL_STATUS_SCANNING,
+ WL_STATUS_SCAN_ABORTING,
+ WL_STATUS_CONNECTING,
+ WL_STATUS_CONNECTED
+};
+
+/* wi-fi mode */
+enum wl_mode {
+ WL_MODE_BSS,
+ WL_MODE_IBSS,
+ WL_MODE_AP
+};
+
+/* dongle profile list */
+enum wl_prof_list {
+ WL_PROF_MODE,
+ WL_PROF_SSID,
+ WL_PROF_SEC,
+ WL_PROF_IBSS,
+ WL_PROF_BAND,
+ WL_PROF_BSSID,
+ WL_PROF_ACT,
+ WL_PROF_BEACONINT,
+ WL_PROF_DTIMPERIOD
+};
+
+/* dongle iscan state */
+enum wl_iscan_state {
+ WL_ISCAN_STATE_IDLE,
+ WL_ISCAN_STATE_SCANING
+};
+
+/* dongle configuration */
+struct brcmf_cfg80211_conf {
+ u32 mode; /* adhoc , infrastructure or ap */
+ u32 frag_threshold;
+ u32 rts_threshold;
+ u32 retry_short;
+ u32 retry_long;
+ s32 tx_power;
+ struct ieee80211_channel channel;
+};
+
+/* cfg80211 main event loop */
+struct brcmf_cfg80211_event_loop {
+ s32(*handler[BRCMF_E_LAST]) (struct brcmf_cfg80211_priv *cfg_priv,
+ struct net_device *ndev,
+ const struct brcmf_event_msg *e,
+ void *data);
+};
+
+/* representing interface of cfg80211 plane */
+struct brcmf_cfg80211_iface {
+ struct brcmf_cfg80211_priv *cfg_priv;
+};
+
+struct brcmf_cfg80211_dev {
+ void *driver_data; /* to store cfg80211 object information */
+};
+
+/* basic structure of scan request */
+struct brcmf_cfg80211_scan_req {
+ struct brcmf_ssid_le ssid_le;
+};
+
+/* basic structure of information element */
+struct brcmf_cfg80211_ie {
+ u16 offset;
+ u8 buf[WL_TLV_INFO_MAX];
+};
+
+/* event queue for cfg80211 main event */
+struct brcmf_cfg80211_event_q {
+ struct list_head evt_q_list;
+ u32 etype;
+ struct brcmf_event_msg emsg;
+ s8 edata[1];
+};
+
+/* security information with currently associated ap */
+struct brcmf_cfg80211_security {
+ u32 wpa_versions;
+ u32 auth_type;
+ u32 cipher_pairwise;
+ u32 cipher_group;
+ u32 wpa_auth;
+};
+
+/* ibss information for currently joined ibss network */
+struct brcmf_cfg80211_ibss {
+ u8 beacon_interval; /* in millisecond */
+ u8 atim; /* in millisecond */
+ s8 join_only;
+ u8 band;
+ u8 channel;
+};
+
+/* dongle profile */
+struct brcmf_cfg80211_profile {
+ u32 mode;
+ struct brcmf_ssid ssid;
+ u8 bssid[ETH_ALEN];
+ u16 beacon_interval;
+ u8 dtim_period;
+ struct brcmf_cfg80211_security sec;
+ struct brcmf_cfg80211_ibss ibss;
+ s32 band;
+};
+
+/* dongle iscan event loop */
+struct brcmf_cfg80211_iscan_eloop {
+ s32 (*handler[WL_SCAN_ERSULTS_LAST])
+ (struct brcmf_cfg80211_priv *cfg_priv);
+};
+
+/* dongle iscan controller */
+struct brcmf_cfg80211_iscan_ctrl {
+ struct net_device *ndev;
+ struct timer_list timer;
+ u32 timer_ms;
+ u32 timer_on;
+ s32 state;
+ struct work_struct work;
+ struct brcmf_cfg80211_iscan_eloop el;
+ void *data;
+ s8 dcmd_buf[BRCMF_DCMD_SMLEN];
+ s8 scan_buf[WL_ISCAN_BUF_MAX];
+};
+
+/* association inform */
+struct brcmf_cfg80211_connect_info {
+ u8 *req_ie;
+ s32 req_ie_len;
+ u8 *resp_ie;
+ s32 resp_ie_len;
+};
+
+/* assoc ie length */
+struct brcmf_cfg80211_assoc_ielen_le {
+ __le32 req_len;
+ __le32 resp_len;
+};
+
+/* wpa2 pmk list */
+struct brcmf_cfg80211_pmk_list {
+ struct pmkid_list pmkids;
+ struct pmkid foo[MAXPMKID - 1];
+};
+
+/* dongle private data of cfg80211 interface */
+struct brcmf_cfg80211_priv {
+ struct wireless_dev *wdev; /* representing wl cfg80211 device */
+ struct brcmf_cfg80211_conf *conf; /* dongle configuration */
+ struct cfg80211_scan_request *scan_request; /* scan request
+ object */
+ struct brcmf_cfg80211_event_loop el; /* main event loop */
+ struct list_head evt_q_list; /* used for event queue */
+ spinlock_t evt_q_lock; /* for event queue synchronization */
+ struct mutex usr_sync; /* maily for dongle up/down synchronization */
+ struct brcmf_scan_results *bss_list; /* bss_list holding scanned
+ ap information */
+ struct brcmf_scan_results *scan_results;
+ struct brcmf_cfg80211_scan_req *scan_req_int; /* scan request object
+ for internal purpose */
+ struct wl_cfg80211_bss_info *bss_info; /* bss information for
+ cfg80211 layer */
+ struct brcmf_cfg80211_ie ie; /* information element object for
+ internal purpose */
+ struct brcmf_cfg80211_profile *profile; /* holding dongle profile */
+ struct brcmf_cfg80211_iscan_ctrl *iscan; /* iscan controller */
+ struct brcmf_cfg80211_connect_info conn_info; /* association info */
+ struct brcmf_cfg80211_pmk_list *pmk_list; /* wpa2 pmk list */
+ struct work_struct event_work; /* event handler work struct */
+ unsigned long status; /* current dongle status */
+ void *pub;
+ u32 channel; /* current channel */
+ bool iscan_on; /* iscan on/off switch */
+ bool iscan_kickstart; /* indicate iscan already started */
+ bool active_scan; /* current scan mode */
+ bool ibss_starter; /* indicates this sta is ibss starter */
+ bool link_up; /* link/connection up flag */
+ bool pwr_save; /* indicate whether dongle to support
+ power save mode */
+ bool dongle_up; /* indicate whether dongle up or not */
+ bool roam_on; /* on/off switch for dongle self-roaming */
+ bool scan_tried; /* indicates if first scan attempted */
+ u8 *dcmd_buf; /* dcmd buffer */
+ u8 *extra_buf; /* maily to grab assoc information */
+ struct dentry *debugfsdir;
+ u8 ci[0] __aligned(NETDEV_ALIGN);
+};
+
+static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_priv *w)
+{
+ return w->wdev->wiphy;
+}
+
+static inline struct brcmf_cfg80211_priv *wiphy_to_cfg(struct wiphy *w)
+{
+ return (struct brcmf_cfg80211_priv *)(wiphy_priv(w));
+}
+
+static inline struct brcmf_cfg80211_priv *wdev_to_cfg(struct wireless_dev *wd)
+{
+ return (struct brcmf_cfg80211_priv *)(wdev_priv(wd));
+}
+
+static inline struct net_device *cfg_to_ndev(struct brcmf_cfg80211_priv *cfg)
+{
+ return cfg->wdev->netdev;
+}
+
+static inline struct brcmf_cfg80211_priv *ndev_to_cfg(struct net_device *ndev)
+{
+ return wdev_to_cfg(ndev->ieee80211_ptr);
+}
+
+#define iscan_to_cfg(i) ((struct brcmf_cfg80211_priv *)(i->data))
+#define cfg_to_iscan(w) (w->iscan)
+
+static inline struct
+brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_priv *cfg)
+{
+ return &cfg->conn_info;
+}
+
+static inline struct brcmf_bss_info *next_bss(struct brcmf_scan_results *list,
+ struct brcmf_bss_info *bss)
+{
+ return bss = bss ?
+ (struct brcmf_bss_info *)((unsigned long)bss +
+ le32_to_cpu(bss->length)) :
+ list->bss_info;
+}
+
+extern struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev,
+ struct device *busdev,
+ void *data);
+extern void brcmf_cfg80211_detach(struct brcmf_cfg80211_dev *cfg);
+
+/* event handler from dongle */
+extern void brcmf_cfg80211_event(struct net_device *ndev,
+ const struct brcmf_event_msg *e, void *data);
+extern s32 brcmf_cfg80211_up(struct brcmf_cfg80211_dev *cfg_dev);
+extern s32 brcmf_cfg80211_down(struct brcmf_cfg80211_dev *cfg_dev);
+
+#endif /* _wl_cfg80211_h_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/Makefile b/drivers/net/wireless/brcm80211/brcmsmac/Makefile
new file mode 100644
index 000000000000..c2eb2d0af386
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/Makefile
@@ -0,0 +1,51 @@
+#
+# Makefile fragment for Broadcom 802.11n Networking Device Driver
+#
+# Copyright (c) 2010 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.
+
+ccflags-y := \
+ -D__CHECK_ENDIAN__ \
+ -Idrivers/net/wireless/brcm80211/brcmsmac \
+ -Idrivers/net/wireless/brcm80211/brcmsmac/phy \
+ -Idrivers/net/wireless/brcm80211/include
+
+BRCMSMAC_OFILES := \
+ mac80211_if.o \
+ ucode_loader.o \
+ ampdu.o \
+ antsel.o \
+ channel.o \
+ main.o \
+ phy_shim.o \
+ pmu.o \
+ rate.o \
+ stf.o \
+ aiutils.o \
+ phy/phy_cmn.o \
+ phy/phy_lcn.o \
+ phy/phy_n.o \
+ phy/phytbl_lcn.o \
+ phy/phytbl_n.o \
+ phy/phy_qmath.o \
+ otp.o \
+ srom.o \
+ dma.o \
+ nicpci.o \
+ brcms_trace_events.o
+
+MODULEPFX := brcmsmac
+
+obj-$(CONFIG_BRCMSMAC) += $(MODULEPFX).o
+$(MODULEPFX)-objs = $(BRCMSMAC_OFILES)
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
new file mode 100644
index 000000000000..025fa0eb6f47
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
@@ -0,0 +1,2079 @@
+/*
+ * Copyright (c) 2010 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.
+ *
+ * File contents: support functions for PCI/PCIe
+ */
+
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include <defs.h>
+#include <chipcommon.h>
+#include <brcmu_utils.h>
+#include <brcm_hw_ids.h>
+#include <soc.h>
+#include "types.h"
+#include "pub.h"
+#include "pmu.h"
+#include "srom.h"
+#include "nicpci.h"
+#include "aiutils.h"
+
+/* slow_clk_ctl */
+ /* slow clock source mask */
+#define SCC_SS_MASK 0x00000007
+ /* source of slow clock is LPO */
+#define SCC_SS_LPO 0x00000000
+ /* source of slow clock is crystal */
+#define SCC_SS_XTAL 0x00000001
+ /* source of slow clock is PCI */
+#define SCC_SS_PCI 0x00000002
+ /* LPOFreqSel, 1: 160Khz, 0: 32KHz */
+#define SCC_LF 0x00000200
+ /* LPOPowerDown, 1: LPO is disabled, 0: LPO is enabled */
+#define SCC_LP 0x00000400
+ /* ForceSlowClk, 1: sb/cores running on slow clock, 0: power logic control */
+#define SCC_FS 0x00000800
+ /* IgnorePllOffReq, 1/0:
+ * power logic ignores/honors PLL clock disable requests from core
+ */
+#define SCC_IP 0x00001000
+ /* XtalControlEn, 1/0:
+ * power logic does/doesn't disable crystal when appropriate
+ */
+#define SCC_XC 0x00002000
+ /* XtalPU (RO), 1/0: crystal running/disabled */
+#define SCC_XP 0x00004000
+ /* ClockDivider (SlowClk = 1/(4+divisor)) */
+#define SCC_CD_MASK 0xffff0000
+#define SCC_CD_SHIFT 16
+
+/* system_clk_ctl */
+ /* ILPen: Enable Idle Low Power */
+#define SYCC_IE 0x00000001
+ /* ALPen: Enable Active Low Power */
+#define SYCC_AE 0x00000002
+ /* ForcePLLOn */
+#define SYCC_FP 0x00000004
+ /* Force ALP (or HT if ALPen is not set */
+#define SYCC_AR 0x00000008
+ /* Force HT */
+#define SYCC_HR 0x00000010
+ /* ClkDiv (ILP = 1/(4 * (divisor + 1)) */
+#define SYCC_CD_MASK 0xffff0000
+#define SYCC_CD_SHIFT 16
+
+#define CST4329_SPROM_OTP_SEL_MASK 0x00000003
+ /* OTP is powered up, use def. CIS, no SPROM */
+#define CST4329_DEFCIS_SEL 0
+ /* OTP is powered up, SPROM is present */
+#define CST4329_SPROM_SEL 1
+ /* OTP is powered up, no SPROM */
+#define CST4329_OTP_SEL 2
+ /* OTP is powered down, SPROM is present */
+#define CST4329_OTP_PWRDN 3
+
+#define CST4329_SPI_SDIO_MODE_MASK 0x00000004
+#define CST4329_SPI_SDIO_MODE_SHIFT 2
+
+/* 43224 chip-specific ChipControl register bits */
+#define CCTRL43224_GPIO_TOGGLE 0x8000
+ /* 12 mA drive strength */
+#define CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0
+ /* 12 mA drive strength for later 43224s */
+#define CCTRL_43224B0_12MA_LED_DRIVE 0xF0
+
+/* 43236 Chip specific ChipStatus register bits */
+#define CST43236_SFLASH_MASK 0x00000040
+#define CST43236_OTP_MASK 0x00000080
+#define CST43236_HSIC_MASK 0x00000100 /* USB/HSIC */
+#define CST43236_BP_CLK 0x00000200 /* 120/96Mbps */
+#define CST43236_BOOT_MASK 0x00001800
+#define CST43236_BOOT_SHIFT 11
+#define CST43236_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */
+#define CST43236_BOOT_FROM_ROM 1 /* boot from ROM */
+#define CST43236_BOOT_FROM_FLASH 2 /* boot from FLASH */
+#define CST43236_BOOT_FROM_INVALID 3
+
+/* 4331 chip-specific ChipControl register bits */
+ /* 0 disable */
+#define CCTRL4331_BT_COEXIST (1<<0)
+ /* 0 SECI is disabled (JTAG functional) */
+#define CCTRL4331_SECI (1<<1)
+ /* 0 disable */
+#define CCTRL4331_EXT_LNA (1<<2)
+ /* sprom/gpio13-15 mux */
+#define CCTRL4331_SPROM_GPIO13_15 (1<<3)
+ /* 0 ext pa disable, 1 ext pa enabled */
+#define CCTRL4331_EXTPA_EN (1<<4)
+ /* set drive out GPIO_CLK on sprom_cs pin */
+#define CCTRL4331_GPIOCLK_ON_SPROMCS (1<<5)
+ /* use sprom_cs pin as PCIE mdio interface */
+#define CCTRL4331_PCIE_MDIO_ON_SPROMCS (1<<6)
+ /* aband extpa will be at gpio2/5 and sprom_dout */
+#define CCTRL4331_EXTPA_ON_GPIO2_5 (1<<7)
+ /* override core control on pipe_AuxClkEnable */
+#define CCTRL4331_OVR_PIPEAUXCLKEN (1<<8)
+ /* override core control on pipe_AuxPowerDown */
+#define CCTRL4331_OVR_PIPEAUXPWRDOWN (1<<9)
+ /* pcie_auxclkenable */
+#define CCTRL4331_PCIE_AUXCLKEN (1<<10)
+ /* pcie_pipe_pllpowerdown */
+#define CCTRL4331_PCIE_PIPE_PLLDOWN (1<<11)
+ /* enable bt_shd0 at gpio4 */
+#define CCTRL4331_BT_SHD0_ON_GPIO4 (1<<16)
+ /* enable bt_shd1 at gpio5 */
+#define CCTRL4331_BT_SHD1_ON_GPIO5 (1<<17)
+
+/* 4331 Chip specific ChipStatus register bits */
+ /* crystal frequency 20/40Mhz */
+#define CST4331_XTAL_FREQ 0x00000001
+#define CST4331_SPROM_PRESENT 0x00000002
+#define CST4331_OTP_PRESENT 0x00000004
+#define CST4331_LDO_RF 0x00000008
+#define CST4331_LDO_PAR 0x00000010
+
+/* 4319 chip-specific ChipStatus register bits */
+#define CST4319_SPI_CPULESSUSB 0x00000001
+#define CST4319_SPI_CLK_POL 0x00000002
+#define CST4319_SPI_CLK_PH 0x00000008
+ /* gpio [7:6], SDIO CIS selection */
+#define CST4319_SPROM_OTP_SEL_MASK 0x000000c0
+#define CST4319_SPROM_OTP_SEL_SHIFT 6
+ /* use default CIS, OTP is powered up */
+#define CST4319_DEFCIS_SEL 0x00000000
+ /* use SPROM, OTP is powered up */
+#define CST4319_SPROM_SEL 0x00000040
+ /* use OTP, OTP is powered up */
+#define CST4319_OTP_SEL 0x00000080
+ /* use SPROM, OTP is powered down */
+#define CST4319_OTP_PWRDN 0x000000c0
+ /* gpio [8], sdio/usb mode */
+#define CST4319_SDIO_USB_MODE 0x00000100
+#define CST4319_REMAP_SEL_MASK 0x00000600
+#define CST4319_ILPDIV_EN 0x00000800
+#define CST4319_XTAL_PD_POL 0x00001000
+#define CST4319_LPO_SEL 0x00002000
+#define CST4319_RES_INIT_MODE 0x0000c000
+ /* PALDO is configured with external PNP */
+#define CST4319_PALDO_EXTPNP 0x00010000
+#define CST4319_CBUCK_MODE_MASK 0x00060000
+#define CST4319_CBUCK_MODE_BURST 0x00020000
+#define CST4319_CBUCK_MODE_LPBURST 0x00060000
+#define CST4319_RCAL_VALID 0x01000000
+#define CST4319_RCAL_VALUE_MASK 0x3e000000
+#define CST4319_RCAL_VALUE_SHIFT 25
+
+/* 4336 chip-specific ChipStatus register bits */
+#define CST4336_SPI_MODE_MASK 0x00000001
+#define CST4336_SPROM_PRESENT 0x00000002
+#define CST4336_OTP_PRESENT 0x00000004
+#define CST4336_ARMREMAP_0 0x00000008
+#define CST4336_ILPDIV_EN_MASK 0x00000010
+#define CST4336_ILPDIV_EN_SHIFT 4
+#define CST4336_XTAL_PD_POL_MASK 0x00000020
+#define CST4336_XTAL_PD_POL_SHIFT 5
+#define CST4336_LPO_SEL_MASK 0x00000040
+#define CST4336_LPO_SEL_SHIFT 6
+#define CST4336_RES_INIT_MODE_MASK 0x00000180
+#define CST4336_RES_INIT_MODE_SHIFT 7
+#define CST4336_CBUCK_MODE_MASK 0x00000600
+#define CST4336_CBUCK_MODE_SHIFT 9
+
+/* 4313 chip-specific ChipStatus register bits */
+#define CST4313_SPROM_PRESENT 1
+#define CST4313_OTP_PRESENT 2
+#define CST4313_SPROM_OTP_SEL_MASK 0x00000002
+#define CST4313_SPROM_OTP_SEL_SHIFT 0
+
+/* 4313 Chip specific ChipControl register bits */
+ /* 12 mA drive strengh for later 4313 */
+#define CCTRL_4313_12MA_LED_DRIVE 0x00000007
+
+/* Manufacturer Ids */
+#define MFGID_ARM 0x43b
+#define MFGID_BRCM 0x4bf
+#define MFGID_MIPS 0x4a7
+
+/* Enumeration ROM registers */
+#define ER_EROMENTRY 0x000
+#define ER_REMAPCONTROL 0xe00
+#define ER_REMAPSELECT 0xe04
+#define ER_MASTERSELECT 0xe10
+#define ER_ITCR 0xf00
+#define ER_ITIP 0xf04
+
+/* Erom entries */
+#define ER_TAG 0xe
+#define ER_TAG1 0x6
+#define ER_VALID 1
+#define ER_CI 0
+#define ER_MP 2
+#define ER_ADD 4
+#define ER_END 0xe
+#define ER_BAD 0xffffffff
+
+/* EROM CompIdentA */
+#define CIA_MFG_MASK 0xfff00000
+#define CIA_MFG_SHIFT 20
+#define CIA_CID_MASK 0x000fff00
+#define CIA_CID_SHIFT 8
+#define CIA_CCL_MASK 0x000000f0
+#define CIA_CCL_SHIFT 4
+
+/* EROM CompIdentB */
+#define CIB_REV_MASK 0xff000000
+#define CIB_REV_SHIFT 24
+#define CIB_NSW_MASK 0x00f80000
+#define CIB_NSW_SHIFT 19
+#define CIB_NMW_MASK 0x0007c000
+#define CIB_NMW_SHIFT 14
+#define CIB_NSP_MASK 0x00003e00
+#define CIB_NSP_SHIFT 9
+#define CIB_NMP_MASK 0x000001f0
+#define CIB_NMP_SHIFT 4
+
+/* EROM AddrDesc */
+#define AD_ADDR_MASK 0xfffff000
+#define AD_SP_MASK 0x00000f00
+#define AD_SP_SHIFT 8
+#define AD_ST_MASK 0x000000c0
+#define AD_ST_SHIFT 6
+#define AD_ST_SLAVE 0x00000000
+#define AD_ST_BRIDGE 0x00000040
+#define AD_ST_SWRAP 0x00000080
+#define AD_ST_MWRAP 0x000000c0
+#define AD_SZ_MASK 0x00000030
+#define AD_SZ_SHIFT 4
+#define AD_SZ_4K 0x00000000
+#define AD_SZ_8K 0x00000010
+#define AD_SZ_16K 0x00000020
+#define AD_SZ_SZD 0x00000030
+#define AD_AG32 0x00000008
+#define AD_ADDR_ALIGN 0x00000fff
+#define AD_SZ_BASE 0x00001000 /* 4KB */
+
+/* EROM SizeDesc */
+#define SD_SZ_MASK 0xfffff000
+#define SD_SG32 0x00000008
+#define SD_SZ_ALIGN 0x00000fff
+
+/* PCI config space bit 4 for 4306c0 slow clock source */
+#define PCI_CFG_GPIO_SCS 0x10
+/* PCI config space GPIO 14 for Xtal power-up */
+#define PCI_CFG_GPIO_XTAL 0x40
+/* PCI config space GPIO 15 for PLL power-down */
+#define PCI_CFG_GPIO_PLL 0x80
+
+/* power control defines */
+#define PLL_DELAY 150 /* us pll on delay */
+#define FREF_DELAY 200 /* us fref change delay */
+#define XTAL_ON_DELAY 1000 /* us crystal power-on delay */
+
+/* resetctrl */
+#define AIRC_RESET 1
+
+#define NOREV -1 /* Invalid rev */
+
+/* GPIO Based LED powersave defines */
+#define DEFAULT_GPIO_ONTIME 10 /* Default: 10% on */
+#define DEFAULT_GPIO_OFFTIME 90 /* Default: 10% on */
+
+/* When Srom support present, fields in sromcontrol */
+#define SRC_START 0x80000000
+#define SRC_BUSY 0x80000000
+#define SRC_OPCODE 0x60000000
+#define SRC_OP_READ 0x00000000
+#define SRC_OP_WRITE 0x20000000
+#define SRC_OP_WRDIS 0x40000000
+#define SRC_OP_WREN 0x60000000
+#define SRC_OTPSEL 0x00000010
+#define SRC_LOCK 0x00000008
+#define SRC_SIZE_MASK 0x00000006
+#define SRC_SIZE_1K 0x00000000
+#define SRC_SIZE_4K 0x00000002
+#define SRC_SIZE_16K 0x00000004
+#define SRC_SIZE_SHIFT 1
+#define SRC_PRESENT 0x00000001
+
+/* External PA enable mask */
+#define GPIO_CTRL_EPA_EN_MASK 0x40
+
+#define DEFAULT_GPIOTIMERVAL \
+ ((DEFAULT_GPIO_ONTIME << GPIO_ONTIME_SHIFT) | DEFAULT_GPIO_OFFTIME)
+
+#define BADIDX (SI_MAXCORES + 1)
+
+/* Newer chips can access PCI/PCIE and CC core without requiring to change
+ * PCI BAR0 WIN
+ */
+#define SI_FAST(si) (((si)->pub.buscoretype == PCIE_CORE_ID) || \
+ (((si)->pub.buscoretype == PCI_CORE_ID) && \
+ (si)->pub.buscorerev >= 13))
+
+#define CCREGS_FAST(si) (((char __iomem *)((si)->curmap) + \
+ PCI_16KB0_CCREGS_OFFSET))
+
+#define IS_SIM(chippkg) \
+ ((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID))
+
+/*
+ * Macros to disable/restore function core(D11, ENET, ILINE20, etc) interrupts
+ * before after core switching to avoid invalid register accesss inside ISR.
+ */
+#define INTR_OFF(si, intr_val) \
+ if ((si)->intrsoff_fn && \
+ (si)->coreid[(si)->curidx] == (si)->dev_coreid) \
+ intr_val = (*(si)->intrsoff_fn)((si)->intr_arg)
+
+#define INTR_RESTORE(si, intr_val) \
+ if ((si)->intrsrestore_fn && \
+ (si)->coreid[(si)->curidx] == (si)->dev_coreid) \
+ (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val)
+
+#define PCI(si) ((si)->pub.buscoretype == PCI_CORE_ID)
+#define PCIE(si) ((si)->pub.buscoretype == PCIE_CORE_ID)
+
+#define PCI_FORCEHT(si) (PCIE(si) && (si->pub.chip == BCM4716_CHIP_ID))
+
+#ifdef BCMDBG
+#define SI_MSG(args) printk args
+#else
+#define SI_MSG(args)
+#endif /* BCMDBG */
+
+#define GOODCOREADDR(x, b) \
+ (((x) >= (b)) && ((x) < ((b) + SI_MAXCORES * SI_CORE_SIZE)) && \
+ IS_ALIGNED((x), SI_CORE_SIZE))
+
+#define PCIEREGS(si) ((__iomem char *)((si)->curmap) + \
+ PCI_16KB0_PCIREGS_OFFSET)
+
+struct aidmp {
+ u32 oobselina30; /* 0x000 */
+ u32 oobselina74; /* 0x004 */
+ u32 PAD[6];
+ u32 oobselinb30; /* 0x020 */
+ u32 oobselinb74; /* 0x024 */
+ u32 PAD[6];
+ u32 oobselinc30; /* 0x040 */
+ u32 oobselinc74; /* 0x044 */
+ u32 PAD[6];
+ u32 oobselind30; /* 0x060 */
+ u32 oobselind74; /* 0x064 */
+ u32 PAD[38];
+ u32 oobselouta30; /* 0x100 */
+ u32 oobselouta74; /* 0x104 */
+ u32 PAD[6];
+ u32 oobseloutb30; /* 0x120 */
+ u32 oobseloutb74; /* 0x124 */
+ u32 PAD[6];
+ u32 oobseloutc30; /* 0x140 */
+ u32 oobseloutc74; /* 0x144 */
+ u32 PAD[6];
+ u32 oobseloutd30; /* 0x160 */
+ u32 oobseloutd74; /* 0x164 */
+ u32 PAD[38];
+ u32 oobsynca; /* 0x200 */
+ u32 oobseloutaen; /* 0x204 */
+ u32 PAD[6];
+ u32 oobsyncb; /* 0x220 */
+ u32 oobseloutben; /* 0x224 */
+ u32 PAD[6];
+ u32 oobsyncc; /* 0x240 */
+ u32 oobseloutcen; /* 0x244 */
+ u32 PAD[6];
+ u32 oobsyncd; /* 0x260 */
+ u32 oobseloutden; /* 0x264 */
+ u32 PAD[38];
+ u32 oobaextwidth; /* 0x300 */
+ u32 oobainwidth; /* 0x304 */
+ u32 oobaoutwidth; /* 0x308 */
+ u32 PAD[5];
+ u32 oobbextwidth; /* 0x320 */
+ u32 oobbinwidth; /* 0x324 */
+ u32 oobboutwidth; /* 0x328 */
+ u32 PAD[5];
+ u32 oobcextwidth; /* 0x340 */
+ u32 oobcinwidth; /* 0x344 */
+ u32 oobcoutwidth; /* 0x348 */
+ u32 PAD[5];
+ u32 oobdextwidth; /* 0x360 */
+ u32 oobdinwidth; /* 0x364 */
+ u32 oobdoutwidth; /* 0x368 */
+ u32 PAD[37];
+ u32 ioctrlset; /* 0x400 */
+ u32 ioctrlclear; /* 0x404 */
+ u32 ioctrl; /* 0x408 */
+ u32 PAD[61];
+ u32 iostatus; /* 0x500 */
+ u32 PAD[127];
+ u32 ioctrlwidth; /* 0x700 */
+ u32 iostatuswidth; /* 0x704 */
+ u32 PAD[62];
+ u32 resetctrl; /* 0x800 */
+ u32 resetstatus; /* 0x804 */
+ u32 resetreadid; /* 0x808 */
+ u32 resetwriteid; /* 0x80c */
+ u32 PAD[60];
+ u32 errlogctrl; /* 0x900 */
+ u32 errlogdone; /* 0x904 */
+ u32 errlogstatus; /* 0x908 */
+ u32 errlogaddrlo; /* 0x90c */
+ u32 errlogaddrhi; /* 0x910 */
+ u32 errlogid; /* 0x914 */
+ u32 errloguser; /* 0x918 */
+ u32 errlogflags; /* 0x91c */
+ u32 PAD[56];
+ u32 intstatus; /* 0xa00 */
+ u32 PAD[127];
+ u32 config; /* 0xe00 */
+ u32 PAD[63];
+ u32 itcr; /* 0xf00 */
+ u32 PAD[3];
+ u32 itipooba; /* 0xf10 */
+ u32 itipoobb; /* 0xf14 */
+ u32 itipoobc; /* 0xf18 */
+ u32 itipoobd; /* 0xf1c */
+ u32 PAD[4];
+ u32 itipoobaout; /* 0xf30 */
+ u32 itipoobbout; /* 0xf34 */
+ u32 itipoobcout; /* 0xf38 */
+ u32 itipoobdout; /* 0xf3c */
+ u32 PAD[4];
+ u32 itopooba; /* 0xf50 */
+ u32 itopoobb; /* 0xf54 */
+ u32 itopoobc; /* 0xf58 */
+ u32 itopoobd; /* 0xf5c */
+ u32 PAD[4];
+ u32 itopoobain; /* 0xf70 */
+ u32 itopoobbin; /* 0xf74 */
+ u32 itopoobcin; /* 0xf78 */
+ u32 itopoobdin; /* 0xf7c */
+ u32 PAD[4];
+ u32 itopreset; /* 0xf90 */
+ u32 PAD[15];
+ u32 peripherialid4; /* 0xfd0 */
+ u32 peripherialid5; /* 0xfd4 */
+ u32 peripherialid6; /* 0xfd8 */
+ u32 peripherialid7; /* 0xfdc */
+ u32 peripherialid0; /* 0xfe0 */
+ u32 peripherialid1; /* 0xfe4 */
+ u32 peripherialid2; /* 0xfe8 */
+ u32 peripherialid3; /* 0xfec */
+ u32 componentid0; /* 0xff0 */
+ u32 componentid1; /* 0xff4 */
+ u32 componentid2; /* 0xff8 */
+ u32 componentid3; /* 0xffc */
+};
+
+/* EROM parsing */
+
+static u32
+get_erom_ent(struct si_pub *sih, u32 __iomem **eromptr, u32 mask, u32 match)
+{
+ u32 ent;
+ uint inv = 0, nom = 0;
+
+ while (true) {
+ ent = R_REG(*eromptr);
+ (*eromptr)++;
+
+ if (mask == 0)
+ break;
+
+ if ((ent & ER_VALID) == 0) {
+ inv++;
+ continue;
+ }
+
+ if (ent == (ER_END | ER_VALID))
+ break;
+
+ if ((ent & mask) == match)
+ break;
+
+ nom++;
+ }
+
+ return ent;
+}
+
+static u32
+get_asd(struct si_pub *sih, u32 __iomem **eromptr, uint sp, uint ad, uint st,
+ u32 *addrl, u32 *addrh, u32 *sizel, u32 *sizeh)
+{
+ u32 asd, sz, szd;
+
+ asd = get_erom_ent(sih, eromptr, ER_VALID, ER_VALID);
+ if (((asd & ER_TAG1) != ER_ADD) ||
+ (((asd & AD_SP_MASK) >> AD_SP_SHIFT) != sp) ||
+ ((asd & AD_ST_MASK) != st)) {
+ /* This is not what we want, "push" it back */
+ (*eromptr)--;
+ return 0;
+ }
+ *addrl = asd & AD_ADDR_MASK;
+ if (asd & AD_AG32)
+ *addrh = get_erom_ent(sih, eromptr, 0, 0);
+ else
+ *addrh = 0;
+ *sizeh = 0;
+ sz = asd & AD_SZ_MASK;
+ if (sz == AD_SZ_SZD) {
+ szd = get_erom_ent(sih, eromptr, 0, 0);
+ *sizel = szd & SD_SZ_MASK;
+ if (szd & SD_SG32)
+ *sizeh = get_erom_ent(sih, eromptr, 0, 0);
+ } else
+ *sizel = AD_SZ_BASE << (sz >> AD_SZ_SHIFT);
+
+ return asd;
+}
+
+static void ai_hwfixup(struct si_info *sii)
+{
+}
+
+/* parse the enumeration rom to identify all cores */
+static void ai_scan(struct si_pub *sih, struct chipcregs __iomem *cc)
+{
+ struct si_info *sii = (struct si_info *)sih;
+
+ u32 erombase;
+ u32 __iomem *eromptr, *eromlim;
+ void __iomem *regs = cc;
+
+ erombase = R_REG(&cc->eromptr);
+
+ /* Set wrappers address */
+ sii->curwrap = (void *)((unsigned long)cc + SI_CORE_SIZE);
+
+ /* Now point the window at the erom */
+ pci_write_config_dword(sii->pbus, PCI_BAR0_WIN, erombase);
+ eromptr = regs;
+ eromlim = eromptr + (ER_REMAPCONTROL / sizeof(u32));
+
+ while (eromptr < eromlim) {
+ u32 cia, cib, cid, mfg, crev, nmw, nsw, nmp, nsp;
+ u32 mpd, asd, addrl, addrh, sizel, sizeh;
+ u32 __iomem *base;
+ uint i, j, idx;
+ bool br;
+
+ br = false;
+
+ /* Grok a component */
+ cia = get_erom_ent(sih, &eromptr, ER_TAG, ER_CI);
+ if (cia == (ER_END | ER_VALID)) {
+ /* Found END of erom */
+ ai_hwfixup(sii);
+ return;
+ }
+ base = eromptr - 1;
+ cib = get_erom_ent(sih, &eromptr, 0, 0);
+
+ if ((cib & ER_TAG) != ER_CI) {
+ /* CIA not followed by CIB */
+ goto error;
+ }
+
+ cid = (cia & CIA_CID_MASK) >> CIA_CID_SHIFT;
+ mfg = (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT;
+ crev = (cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
+ nmw = (cib & CIB_NMW_MASK) >> CIB_NMW_SHIFT;
+ nsw = (cib & CIB_NSW_MASK) >> CIB_NSW_SHIFT;
+ nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT;
+ nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT;
+
+ if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || (nsp == 0))
+ continue;
+ if ((nmw + nsw == 0)) {
+ /* A component which is not a core */
+ if (cid == OOB_ROUTER_CORE_ID) {
+ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE,
+ &addrl, &addrh, &sizel, &sizeh);
+ if (asd != 0)
+ sii->oob_router = addrl;
+ }
+ continue;
+ }
+
+ idx = sii->numcores;
+/* sii->eromptr[idx] = base; */
+ sii->cia[idx] = cia;
+ sii->cib[idx] = cib;
+ sii->coreid[idx] = cid;
+
+ for (i = 0; i < nmp; i++) {
+ mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID);
+ if ((mpd & ER_TAG) != ER_MP) {
+ /* Not enough MP entries for component */
+ goto error;
+ }
+ }
+
+ /* First Slave Address Descriptor should be port 0:
+ * the main register space for the core
+ */
+ asd =
+ get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh,
+ &sizel, &sizeh);
+ if (asd == 0) {
+ /* Try again to see if it is a bridge */
+ asd =
+ get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl,
+ &addrh, &sizel, &sizeh);
+ if (asd != 0)
+ br = true;
+ else if ((addrh != 0) || (sizeh != 0)
+ || (sizel != SI_CORE_SIZE)) {
+ /* First Slave ASD for core malformed */
+ goto error;
+ }
+ }
+ sii->coresba[idx] = addrl;
+ sii->coresba_size[idx] = sizel;
+ /* Get any more ASDs in port 0 */
+ j = 1;
+ do {
+ asd =
+ get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl,
+ &addrh, &sizel, &sizeh);
+ if ((asd != 0) && (j == 1) && (sizel == SI_CORE_SIZE)) {
+ sii->coresba2[idx] = addrl;
+ sii->coresba2_size[idx] = sizel;
+ }
+ j++;
+ } while (asd != 0);
+
+ /* Go through the ASDs for other slave ports */
+ for (i = 1; i < nsp; i++) {
+ j = 0;
+ do {
+ asd =
+ get_asd(sih, &eromptr, i, j++, AD_ST_SLAVE,
+ &addrl, &addrh, &sizel, &sizeh);
+ } while (asd != 0);
+ if (j == 0) {
+ /* SP has no address descriptors */
+ goto error;
+ }
+ }
+
+ /* Now get master wrappers */
+ for (i = 0; i < nmw; i++) {
+ asd =
+ get_asd(sih, &eromptr, i, 0, AD_ST_MWRAP, &addrl,
+ &addrh, &sizel, &sizeh);
+ if (asd == 0) {
+ /* Missing descriptor for MW */
+ goto error;
+ }
+ if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) {
+ /* Master wrapper %d is not 4KB */
+ goto error;
+ }
+ if (i == 0)
+ sii->wrapba[idx] = addrl;
+ }
+
+ /* And finally slave wrappers */
+ for (i = 0; i < nsw; i++) {
+ uint fwp = (nsp == 1) ? 0 : 1;
+ asd =
+ get_asd(sih, &eromptr, fwp + i, 0, AD_ST_SWRAP,
+ &addrl, &addrh, &sizel, &sizeh);
+ if (asd == 0) {
+ /* Missing descriptor for SW */
+ goto error;
+ }
+ if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) {
+ /* Slave wrapper is not 4KB */
+ goto error;
+ }
+ if ((nmw == 0) && (i == 0))
+ sii->wrapba[idx] = addrl;
+ }
+
+ /* Don't record bridges */
+ if (br)
+ continue;
+
+ /* Done with core */
+ sii->numcores++;
+ }
+
+ error:
+ /* Reached end of erom without finding END */
+ sii->numcores = 0;
+ return;
+}
+
+/*
+ * This function changes the logical "focus" to the indicated core.
+ * Return the current core's virtual address. Since each core starts with the
+ * same set of registers (BIST, clock control, etc), the returned address
+ * contains the first register of this 'common' register block (not to be
+ * confused with 'common core').
+ */
+void __iomem *ai_setcoreidx(struct si_pub *sih, uint coreidx)
+{
+ struct si_info *sii = (struct si_info *)sih;
+ u32 addr = sii->coresba[coreidx];
+ u32 wrap = sii->wrapba[coreidx];
+
+ if (coreidx >= sii->numcores)
+ return NULL;
+
+ /* point bar0 window */
+ pci_write_config_dword(sii->pbus, PCI_BAR0_WIN, addr);
+ /* point bar0 2nd 4KB window */
+ pci_write_config_dword(sii->pbus, PCI_BAR0_WIN2, wrap);
+ sii->curidx = coreidx;
+
+ return sii->curmap;
+}
+
+/* Return the number of address spaces in current core */
+int ai_numaddrspaces(struct si_pub *sih)
+{
+ return 2;
+}
+
+/* Return the address of the nth address space in the current core */
+u32 ai_addrspace(struct si_pub *sih, uint asidx)
+{
+ struct si_info *sii;
+ uint cidx;
+
+ sii = (struct si_info *)sih;
+ cidx = sii->curidx;
+
+ if (asidx == 0)
+ return sii->coresba[cidx];
+ else if (asidx == 1)
+ return sii->coresba2[cidx];
+ else {
+ /* Need to parse the erom again to find addr space */
+ return 0;
+ }
+}
+
+/* Return the size of the nth address space in the current core */
+u32 ai_addrspacesize(struct si_pub *sih, uint asidx)
+{
+ struct si_info *sii;
+ uint cidx;
+
+ sii = (struct si_info *)sih;
+ cidx = sii->curidx;
+
+ if (asidx == 0)
+ return sii->coresba_size[cidx];
+ else if (asidx == 1)
+ return sii->coresba2_size[cidx];
+ else {
+ /* Need to parse the erom again to find addr */
+ return 0;
+ }
+}
+
+uint ai_flag(struct si_pub *sih)
+{
+ struct si_info *sii;
+ struct aidmp *ai;
+
+ sii = (struct si_info *)sih;
+ ai = sii->curwrap;
+
+ return R_REG(&ai->oobselouta30) & 0x1f;
+}
+
+void ai_setint(struct si_pub *sih, int siflag)
+{
+}
+
+uint ai_corevendor(struct si_pub *sih)
+{
+ struct si_info *sii;
+ u32 cia;
+
+ sii = (struct si_info *)sih;
+ cia = sii->cia[sii->curidx];
+ return (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT;
+}
+
+uint ai_corerev(struct si_pub *sih)
+{
+ struct si_info *sii;
+ u32 cib;
+
+ sii = (struct si_info *)sih;
+ cib = sii->cib[sii->curidx];
+ return (cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
+}
+
+bool ai_iscoreup(struct si_pub *sih)
+{
+ struct si_info *sii;
+ struct aidmp *ai;
+
+ sii = (struct si_info *)sih;
+ ai = sii->curwrap;
+
+ return (((R_REG(&ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) ==
+ SICF_CLOCK_EN)
+ && ((R_REG(&ai->resetctrl) & AIRC_RESET) == 0));
+}
+
+void ai_core_cflags_wo(struct si_pub *sih, u32 mask, u32 val)
+{
+ struct si_info *sii;
+ struct aidmp *ai;
+ u32 w;
+
+ sii = (struct si_info *)sih;
+
+ ai = sii->curwrap;
+
+ if (mask || val) {
+ w = ((R_REG(&ai->ioctrl) & ~mask) | val);
+ W_REG(&ai->ioctrl, w);
+ }
+}
+
+u32 ai_core_cflags(struct si_pub *sih, u32 mask, u32 val)
+{
+ struct si_info *sii;
+ struct aidmp *ai;
+ u32 w;
+
+ sii = (struct si_info *)sih;
+ ai = sii->curwrap;
+
+ if (mask || val) {
+ w = ((R_REG(&ai->ioctrl) & ~mask) | val);
+ W_REG(&ai->ioctrl, w);
+ }
+
+ return R_REG(&ai->ioctrl);
+}
+
+/* return true if PCIE capability exists in the pci config space */
+static bool ai_ispcie(struct si_info *sii)
+{
+ u8 cap_ptr;
+
+ cap_ptr =
+ pcicore_find_pci_capability(sii->pbus, PCI_CAP_ID_EXP, NULL,
+ NULL);
+ if (!cap_ptr)
+ return false;
+
+ return true;
+}
+
+static bool ai_buscore_prep(struct si_info *sii)
+{
+ /* kludge to enable the clock on the 4306 which lacks a slowclock */
+ if (!ai_ispcie(sii))
+ ai_clkctl_xtal(&sii->pub, XTAL | PLL, ON);
+ return true;
+}
+
+u32 ai_core_sflags(struct si_pub *sih, u32 mask, u32 val)
+{
+ struct si_info *sii;
+ struct aidmp *ai;
+ u32 w;
+
+ sii = (struct si_info *)sih;
+ ai = sii->curwrap;
+
+ if (mask || val) {
+ w = ((R_REG(&ai->iostatus) & ~mask) | val);
+ W_REG(&ai->iostatus, w);
+ }
+
+ return R_REG(&ai->iostatus);
+}
+
+static bool
+ai_buscore_setup(struct si_info *sii, u32 savewin, uint *origidx)
+{
+ bool pci, pcie;
+ uint i;
+ uint pciidx, pcieidx, pcirev, pcierev;
+ struct chipcregs __iomem *cc;
+
+ cc = ai_setcoreidx(&sii->pub, SI_CC_IDX);
+
+ /* get chipcommon rev */
+ sii->pub.ccrev = (int)ai_corerev(&sii->pub);
+
+ /* get chipcommon chipstatus */
+ if (sii->pub.ccrev >= 11)
+ sii->pub.chipst = R_REG(&cc->chipstatus);
+
+ /* get chipcommon capabilites */
+ sii->pub.cccaps = R_REG(&cc->capabilities);
+ /* get chipcommon extended capabilities */
+
+ if (sii->pub.ccrev >= 35)
+ sii->pub.cccaps_ext = R_REG(&cc->capabilities_ext);
+
+ /* get pmu rev and caps */
+ if (sii->pub.cccaps & CC_CAP_PMU) {
+ sii->pub.pmucaps = R_REG(&cc->pmucapabilities);
+ sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK;
+ }
+
+ /* figure out bus/orignal core idx */
+ sii->pub.buscoretype = NODEV_CORE_ID;
+ sii->pub.buscorerev = NOREV;
+ sii->pub.buscoreidx = BADIDX;
+
+ pci = pcie = false;
+ pcirev = pcierev = NOREV;
+ pciidx = pcieidx = BADIDX;
+
+ for (i = 0; i < sii->numcores; i++) {
+ uint cid, crev;
+
+ ai_setcoreidx(&sii->pub, i);
+ cid = ai_coreid(&sii->pub);
+ crev = ai_corerev(&sii->pub);
+
+ if (cid == PCI_CORE_ID) {
+ pciidx = i;
+ pcirev = crev;
+ pci = true;
+ } else if (cid == PCIE_CORE_ID) {
+ pcieidx = i;
+ pcierev = crev;
+ pcie = true;
+ }
+
+ /* find the core idx before entering this func. */
+ if ((savewin && (savewin == sii->coresba[i])) ||
+ (cc == sii->regs[i]))
+ *origidx = i;
+ }
+
+ if (pci && pcie) {
+ if (ai_ispcie(sii))
+ pci = false;
+ else
+ pcie = false;
+ }
+ if (pci) {
+ sii->pub.buscoretype = PCI_CORE_ID;
+ sii->pub.buscorerev = pcirev;
+ sii->pub.buscoreidx = pciidx;
+ } else if (pcie) {
+ sii->pub.buscoretype = PCIE_CORE_ID;
+ sii->pub.buscorerev = pcierev;
+ sii->pub.buscoreidx = pcieidx;
+ }
+
+ /* fixup necessary chip/core configurations */
+ if (SI_FAST(sii)) {
+ if (!sii->pch) {
+ sii->pch = pcicore_init(&sii->pub, sii->pbus,
+ (__iomem void *)PCIEREGS(sii));
+ if (sii->pch == NULL)
+ return false;
+ }
+ }
+ if (ai_pci_fixcfg(&sii->pub)) {
+ /* si_doattach: si_pci_fixcfg failed */
+ return false;
+ }
+
+ /* return to the original core */
+ ai_setcoreidx(&sii->pub, *origidx);
+
+ return true;
+}
+
+/*
+ * get boardtype and boardrev
+ */
+static __used void ai_nvram_process(struct si_info *sii)
+{
+ uint w = 0;
+
+ /* do a pci config read to get subsystem id and subvendor id */
+ pci_read_config_dword(sii->pbus, PCI_SUBSYSTEM_VENDOR_ID, &w);
+
+ sii->pub.boardvendor = w & 0xffff;
+ sii->pub.boardtype = (w >> 16) & 0xffff;
+ sii->pub.boardflags = getintvar(&sii->pub, BRCMS_SROM_BOARDFLAGS);
+}
+
+static struct si_info *ai_doattach(struct si_info *sii,
+ void __iomem *regs, struct pci_dev *pbus)
+{
+ struct si_pub *sih = &sii->pub;
+ u32 w, savewin;
+ struct chipcregs __iomem *cc;
+ uint socitype;
+ uint origidx;
+
+ memset((unsigned char *) sii, 0, sizeof(struct si_info));
+
+ savewin = 0;
+
+ sih->buscoreidx = BADIDX;
+
+ sii->curmap = regs;
+ sii->pbus = pbus;
+
+ /* find Chipcommon address */
+ pci_read_config_dword(sii->pbus, PCI_BAR0_WIN, &savewin);
+ if (!GOODCOREADDR(savewin, SI_ENUM_BASE))
+ savewin = SI_ENUM_BASE;
+
+ pci_write_config_dword(sii->pbus, PCI_BAR0_WIN,
+ SI_ENUM_BASE);
+ cc = (struct chipcregs __iomem *) regs;
+
+ /* bus/core/clk setup for register access */
+ if (!ai_buscore_prep(sii))
+ return NULL;
+
+ /*
+ * ChipID recognition.
+ * We assume we can read chipid at offset 0 from the regs arg.
+ * If we add other chiptypes (or if we need to support old sdio
+ * hosts w/o chipcommon), some way of recognizing them needs to
+ * be added here.
+ */
+ w = R_REG(&cc->chipid);
+ socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
+ /* Might as wll fill in chip id rev & pkg */
+ sih->chip = w & CID_ID_MASK;
+ sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT;
+ sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT;
+
+ sih->issim = false;
+
+ /* scan for cores */
+ if (socitype == SOCI_AI) {
+ SI_MSG(("Found chip type AI (0x%08x)\n", w));
+ /* pass chipc address instead of original core base */
+ ai_scan(&sii->pub, cc);
+ } else {
+ /* Found chip of unknown type */
+ return NULL;
+ }
+ /* no cores found, bail out */
+ if (sii->numcores == 0)
+ return NULL;
+
+ /* bus/core/clk setup */
+ origidx = SI_CC_IDX;
+ if (!ai_buscore_setup(sii, savewin, &origidx))
+ goto exit;
+
+ /* Init nvram from sprom/otp if they exist */
+ if (srom_var_init(&sii->pub, cc))
+ goto exit;
+
+ ai_nvram_process(sii);
+
+ /* === NVRAM, clock is ready === */
+ cc = (struct chipcregs __iomem *) ai_setcore(sih, CC_CORE_ID, 0);
+ W_REG(&cc->gpiopullup, 0);
+ W_REG(&cc->gpiopulldown, 0);
+ ai_setcoreidx(sih, origidx);
+
+ /* PMU specific initializations */
+ if (sih->cccaps & CC_CAP_PMU) {
+ u32 xtalfreq;
+ si_pmu_init(sih);
+ si_pmu_chip_init(sih);
+
+ xtalfreq = si_pmu_measure_alpclk(sih);
+ si_pmu_pll_init(sih, xtalfreq);
+ si_pmu_res_init(sih);
+ si_pmu_swreg_init(sih);
+ }
+
+ /* setup the GPIO based LED powersave register */
+ w = getintvar(sih, BRCMS_SROM_LEDDC);
+ if (w == 0)
+ w = DEFAULT_GPIOTIMERVAL;
+ ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, gpiotimerval),
+ ~0, w);
+
+ if (PCIE(sii))
+ pcicore_attach(sii->pch, SI_DOATTACH);
+
+ if (sih->chip == BCM43224_CHIP_ID) {
+ /*
+ * enable 12 mA drive strenth for 43224 and
+ * set chipControl register bit 15
+ */
+ if (sih->chiprev == 0) {
+ SI_MSG(("Applying 43224A0 WARs\n"));
+ ai_corereg(sih, SI_CC_IDX,
+ offsetof(struct chipcregs, chipcontrol),
+ CCTRL43224_GPIO_TOGGLE,
+ CCTRL43224_GPIO_TOGGLE);
+ si_pmu_chipcontrol(sih, 0, CCTRL_43224A0_12MA_LED_DRIVE,
+ CCTRL_43224A0_12MA_LED_DRIVE);
+ }
+ if (sih->chiprev >= 1) {
+ SI_MSG(("Applying 43224B0+ WARs\n"));
+ si_pmu_chipcontrol(sih, 0, CCTRL_43224B0_12MA_LED_DRIVE,
+ CCTRL_43224B0_12MA_LED_DRIVE);
+ }
+ }
+
+ if (sih->chip == BCM4313_CHIP_ID) {
+ /*
+ * enable 12 mA drive strenth for 4313 and
+ * set chipControl register bit 1
+ */
+ SI_MSG(("Applying 4313 WARs\n"));
+ si_pmu_chipcontrol(sih, 0, CCTRL_4313_12MA_LED_DRIVE,
+ CCTRL_4313_12MA_LED_DRIVE);
+ }
+
+ return sii;
+
+ exit:
+ if (sii->pch)
+ pcicore_deinit(sii->pch);
+ sii->pch = NULL;
+
+ return NULL;
+}
+
+/*
+ * Allocate a si handle.
+ * devid - pci device id (used to determine chip#)
+ * osh - opaque OS handle
+ * regs - virtual address of initial core registers
+ */
+struct si_pub *
+ai_attach(void __iomem *regs, struct pci_dev *sdh)
+{
+ struct si_info *sii;
+
+ /* alloc struct si_info */
+ sii = kmalloc(sizeof(struct si_info), GFP_ATOMIC);
+ if (sii == NULL)
+ return NULL;
+
+ if (ai_doattach(sii, regs, sdh) == NULL) {
+ kfree(sii);
+ return NULL;
+ }
+
+ return (struct si_pub *) sii;
+}
+
+/* may be called with core in reset */
+void ai_detach(struct si_pub *sih)
+{
+ struct si_info *sii;
+
+ struct si_pub *si_local = NULL;
+ memcpy(&si_local, &sih, sizeof(struct si_pub **));
+
+ sii = (struct si_info *)sih;
+
+ if (sii == NULL)
+ return;
+
+ if (sii->pch)
+ pcicore_deinit(sii->pch);
+ sii->pch = NULL;
+
+ srom_free_vars(sih);
+ kfree(sii);
+}
+
+/* register driver interrupt disabling and restoring callback functions */
+void
+ai_register_intr_callback(struct si_pub *sih, void *intrsoff_fn,
+ void *intrsrestore_fn,
+ void *intrsenabled_fn, void *intr_arg)
+{
+ struct si_info *sii;
+
+ sii = (struct si_info *)sih;
+ sii->intr_arg = intr_arg;
+ sii->intrsoff_fn = (u32 (*)(void *)) intrsoff_fn;
+ sii->intrsrestore_fn = (void (*) (void *, u32)) intrsrestore_fn;
+ sii->intrsenabled_fn = (bool (*)(void *)) intrsenabled_fn;
+ /* save current core id. when this function called, the current core
+ * must be the core which provides driver functions(il, et, wl, etc.)
+ */
+ sii->dev_coreid = sii->coreid[sii->curidx];
+}
+
+void ai_deregister_intr_callback(struct si_pub *sih)
+{
+ struct si_info *sii;
+
+ sii = (struct si_info *)sih;
+ sii->intrsoff_fn = NULL;
+}
+
+uint ai_coreid(struct si_pub *sih)
+{
+ struct si_info *sii;
+
+ sii = (struct si_info *)sih;
+ return sii->coreid[sii->curidx];
+}
+
+uint ai_coreidx(struct si_pub *sih)
+{
+ struct si_info *sii;
+
+ sii = (struct si_info *)sih;
+ return sii->curidx;
+}
+
+bool ai_backplane64(struct si_pub *sih)
+{
+ return (sih->cccaps & CC_CAP_BKPLN64) != 0;
+}
+
+/* return index of coreid or BADIDX if not found */
+uint ai_findcoreidx(struct si_pub *sih, uint coreid, uint coreunit)
+{
+ struct si_info *sii;
+ uint found;
+ uint i;
+
+ sii = (struct si_info *)sih;
+
+ found = 0;
+
+ for (i = 0; i < sii->numcores; i++)
+ if (sii->coreid[i] == coreid) {
+ if (found == coreunit)
+ return i;
+ found++;
+ }
+
+ return BADIDX;
+}
+
+/*
+ * This function changes logical "focus" to the indicated core;
+ * must be called with interrupts off.
+ * Moreover, callers should keep interrupts off during switching
+ * out of and back to d11 core.
+ */
+void __iomem *ai_setcore(struct si_pub *sih, uint coreid, uint coreunit)
+{
+ uint idx;
+
+ idx = ai_findcoreidx(sih, coreid, coreunit);
+ if (idx >= SI_MAXCORES)
+ return NULL;
+
+ return ai_setcoreidx(sih, idx);
+}
+
+/* Turn off interrupt as required by ai_setcore, before switch core */
+void __iomem *ai_switch_core(struct si_pub *sih, uint coreid, uint *origidx,
+ uint *intr_val)
+{
+ void __iomem *cc;
+ struct si_info *sii;
+
+ sii = (struct si_info *)sih;
+
+ if (SI_FAST(sii)) {
+ /* Overloading the origidx variable to remember the coreid,
+ * this works because the core ids cannot be confused with
+ * core indices.
+ */
+ *origidx = coreid;
+ if (coreid == CC_CORE_ID)
+ return CCREGS_FAST(sii);
+ else if (coreid == sih->buscoretype)
+ return PCIEREGS(sii);
+ }
+ INTR_OFF(sii, *intr_val);
+ *origidx = sii->curidx;
+ cc = ai_setcore(sih, coreid, 0);
+ return cc;
+}
+
+/* restore coreidx and restore interrupt */
+void ai_restore_core(struct si_pub *sih, uint coreid, uint intr_val)
+{
+ struct si_info *sii;
+
+ sii = (struct si_info *)sih;
+ if (SI_FAST(sii)
+ && ((coreid == CC_CORE_ID) || (coreid == sih->buscoretype)))
+ return;
+
+ ai_setcoreidx(sih, coreid);
+ INTR_RESTORE(sii, intr_val);
+}
+
+void ai_write_wrapperreg(struct si_pub *sih, u32 offset, u32 val)
+{
+ struct si_info *sii = (struct si_info *)sih;
+ u32 *w = (u32 *) sii->curwrap;
+ W_REG(w + (offset / 4), val);
+ return;
+}
+
+/*
+ * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set
+ * operation, switch back to the original core, and return the new value.
+ *
+ * When using the silicon backplane, no fiddling with interrupts or core
+ * switches is needed.
+ *
+ * Also, when using pci/pcie, we can optimize away the core switching for pci
+ * registers and (on newer pci cores) chipcommon registers.
+ */
+uint ai_corereg(struct si_pub *sih, uint coreidx, uint regoff, uint mask,
+ uint val)
+{
+ uint origidx = 0;
+ u32 __iomem *r = NULL;
+ uint w;
+ uint intr_val = 0;
+ bool fast = false;
+ struct si_info *sii;
+
+ sii = (struct si_info *)sih;
+
+ if (coreidx >= SI_MAXCORES)
+ return 0;
+
+ /*
+ * If pci/pcie, we can get at pci/pcie regs
+ * and on newer cores to chipc
+ */
+ if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) {
+ /* Chipc registers are mapped at 12KB */
+ fast = true;
+ r = (u32 __iomem *)((__iomem char *)sii->curmap +
+ PCI_16KB0_CCREGS_OFFSET + regoff);
+ } else if (sii->pub.buscoreidx == coreidx) {
+ /*
+ * pci registers are at either in the last 2KB of
+ * an 8KB window or, in pcie and pci rev 13 at 8KB
+ */
+ fast = true;
+ if (SI_FAST(sii))
+ r = (u32 __iomem *)((__iomem char *)sii->curmap +
+ PCI_16KB0_PCIREGS_OFFSET + regoff);
+ else
+ r = (u32 __iomem *)((__iomem char *)sii->curmap +
+ ((regoff >= SBCONFIGOFF) ?
+ PCI_BAR0_PCISBR_OFFSET :
+ PCI_BAR0_PCIREGS_OFFSET) + regoff);
+ }
+
+ if (!fast) {
+ INTR_OFF(sii, intr_val);
+
+ /* save current core index */
+ origidx = ai_coreidx(&sii->pub);
+
+ /* switch core */
+ r = (u32 __iomem *) ((unsigned char __iomem *)
+ ai_setcoreidx(&sii->pub, coreidx) + regoff);
+ }
+
+ /* mask and set */
+ if (mask || val) {
+ w = (R_REG(r) & ~mask) | val;
+ W_REG(r, w);
+ }
+
+ /* readback */
+ w = R_REG(r);
+
+ if (!fast) {
+ /* restore core index */
+ if (origidx != coreidx)
+ ai_setcoreidx(&sii->pub, origidx);
+
+ INTR_RESTORE(sii, intr_val);
+ }
+
+ return w;
+}
+
+void ai_core_disable(struct si_pub *sih, u32 bits)
+{
+ struct si_info *sii;
+ u32 dummy;
+ struct aidmp *ai;
+
+ sii = (struct si_info *)sih;
+
+ ai = sii->curwrap;
+
+ /* if core is already in reset, just return */
+ if (R_REG(&ai->resetctrl) & AIRC_RESET)
+ return;
+
+ W_REG(&ai->ioctrl, bits);
+ dummy = R_REG(&ai->ioctrl);
+ udelay(10);
+
+ W_REG(&ai->resetctrl, AIRC_RESET);
+ udelay(1);
+}
+
+/* reset and re-enable a core
+ * inputs:
+ * bits - core specific bits that are set during and after reset sequence
+ * resetbits - core specific bits that are set only during reset sequence
+ */
+void ai_core_reset(struct si_pub *sih, u32 bits, u32 resetbits)
+{
+ struct si_info *sii;
+ struct aidmp *ai;
+ u32 dummy;
+
+ sii = (struct si_info *)sih;
+ ai = sii->curwrap;
+
+ /*
+ * Must do the disable sequence first to work
+ * for arbitrary current core state.
+ */
+ ai_core_disable(sih, (bits | resetbits));
+
+ /*
+ * Now do the initialization sequence.
+ */
+ W_REG(&ai->ioctrl, (bits | SICF_FGC | SICF_CLOCK_EN));
+ dummy = R_REG(&ai->ioctrl);
+ W_REG(&ai->resetctrl, 0);
+ udelay(1);
+
+ W_REG(&ai->ioctrl, (bits | SICF_CLOCK_EN));
+ dummy = R_REG(&ai->ioctrl);
+ udelay(1);
+}
+
+/* return the slow clock source - LPO, XTAL, or PCI */
+static uint ai_slowclk_src(struct si_info *sii)
+{
+ struct chipcregs __iomem *cc;
+ u32 val;
+
+ if (sii->pub.ccrev < 6) {
+ pci_read_config_dword(sii->pbus, PCI_GPIO_OUT,
+ &val);
+ if (val & PCI_CFG_GPIO_SCS)
+ return SCC_SS_PCI;
+ return SCC_SS_XTAL;
+ } else if (sii->pub.ccrev < 10) {
+ cc = (struct chipcregs __iomem *)
+ ai_setcoreidx(&sii->pub, sii->curidx);
+ return R_REG(&cc->slow_clk_ctl) & SCC_SS_MASK;
+ } else /* Insta-clock */
+ return SCC_SS_XTAL;
+}
+
+/*
+* return the ILP (slowclock) min or max frequency
+* precondition: we've established the chip has dynamic clk control
+*/
+static uint ai_slowclk_freq(struct si_info *sii, bool max_freq,
+ struct chipcregs __iomem *cc)
+{
+ u32 slowclk;
+ uint div;
+
+ slowclk = ai_slowclk_src(sii);
+ if (sii->pub.ccrev < 6) {
+ if (slowclk == SCC_SS_PCI)
+ return max_freq ? (PCIMAXFREQ / 64)
+ : (PCIMINFREQ / 64);
+ else
+ return max_freq ? (XTALMAXFREQ / 32)
+ : (XTALMINFREQ / 32);
+ } else if (sii->pub.ccrev < 10) {
+ div = 4 *
+ (((R_REG(&cc->slow_clk_ctl) & SCC_CD_MASK) >>
+ SCC_CD_SHIFT) + 1);
+ if (slowclk == SCC_SS_LPO)
+ return max_freq ? LPOMAXFREQ : LPOMINFREQ;
+ else if (slowclk == SCC_SS_XTAL)
+ return max_freq ? (XTALMAXFREQ / div)
+ : (XTALMINFREQ / div);
+ else if (slowclk == SCC_SS_PCI)
+ return max_freq ? (PCIMAXFREQ / div)
+ : (PCIMINFREQ / div);
+ } else {
+ /* Chipc rev 10 is InstaClock */
+ div = R_REG(&cc->system_clk_ctl) >> SYCC_CD_SHIFT;
+ div = 4 * (div + 1);
+ return max_freq ? XTALMAXFREQ : (XTALMINFREQ / div);
+ }
+ return 0;
+}
+
+static void
+ai_clkctl_setdelay(struct si_info *sii, struct chipcregs __iomem *cc)
+{
+ uint slowmaxfreq, pll_delay, slowclk;
+ uint pll_on_delay, fref_sel_delay;
+
+ pll_delay = PLL_DELAY;
+
+ /*
+ * If the slow clock is not sourced by the xtal then
+ * add the xtal_on_delay since the xtal will also be
+ * powered down by dynamic clk control logic.
+ */
+
+ slowclk = ai_slowclk_src(sii);
+ if (slowclk != SCC_SS_XTAL)
+ pll_delay += XTAL_ON_DELAY;
+
+ /* Starting with 4318 it is ILP that is used for the delays */
+ slowmaxfreq =
+ ai_slowclk_freq(sii, (sii->pub.ccrev >= 10) ? false : true, cc);
+
+ pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000;
+ fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000;
+
+ W_REG(&cc->pll_on_delay, pll_on_delay);
+ W_REG(&cc->fref_sel_delay, fref_sel_delay);
+}
+
+/* initialize power control delay registers */
+void ai_clkctl_init(struct si_pub *sih)
+{
+ struct si_info *sii;
+ uint origidx = 0;
+ struct chipcregs __iomem *cc;
+ bool fast;
+
+ if (!(sih->cccaps & CC_CAP_PWR_CTL))
+ return;
+
+ sii = (struct si_info *)sih;
+ fast = SI_FAST(sii);
+ if (!fast) {
+ origidx = sii->curidx;
+ cc = (struct chipcregs __iomem *)
+ ai_setcore(sih, CC_CORE_ID, 0);
+ if (cc == NULL)
+ return;
+ } else {
+ cc = (struct chipcregs __iomem *) CCREGS_FAST(sii);
+ if (cc == NULL)
+ return;
+ }
+
+ /* set all Instaclk chip ILP to 1 MHz */
+ if (sih->ccrev >= 10)
+ SET_REG(&cc->system_clk_ctl, SYCC_CD_MASK,
+ (ILP_DIV_1MHZ << SYCC_CD_SHIFT));
+
+ ai_clkctl_setdelay(sii, cc);
+
+ if (!fast)
+ ai_setcoreidx(sih, origidx);
+}
+
+/*
+ * return the value suitable for writing to the
+ * dot11 core FAST_PWRUP_DELAY register
+ */
+u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih)
+{
+ struct si_info *sii;
+ uint origidx = 0;
+ struct chipcregs __iomem *cc;
+ uint slowminfreq;
+ u16 fpdelay;
+ uint intr_val = 0;
+ bool fast;
+
+ sii = (struct si_info *)sih;
+ if (sih->cccaps & CC_CAP_PMU) {
+ INTR_OFF(sii, intr_val);
+ fpdelay = si_pmu_fast_pwrup_delay(sih);
+ INTR_RESTORE(sii, intr_val);
+ return fpdelay;
+ }
+
+ if (!(sih->cccaps & CC_CAP_PWR_CTL))
+ return 0;
+
+ fast = SI_FAST(sii);
+ fpdelay = 0;
+ if (!fast) {
+ origidx = sii->curidx;
+ INTR_OFF(sii, intr_val);
+ cc = (struct chipcregs __iomem *)
+ ai_setcore(sih, CC_CORE_ID, 0);
+ if (cc == NULL)
+ goto done;
+ } else {
+ cc = (struct chipcregs __iomem *) CCREGS_FAST(sii);
+ if (cc == NULL)
+ goto done;
+ }
+
+ slowminfreq = ai_slowclk_freq(sii, false, cc);
+ fpdelay = (((R_REG(&cc->pll_on_delay) + 2) * 1000000) +
+ (slowminfreq - 1)) / slowminfreq;
+
+ done:
+ if (!fast) {
+ ai_setcoreidx(sih, origidx);
+ INTR_RESTORE(sii, intr_val);
+ }
+ return fpdelay;
+}
+
+/* turn primary xtal and/or pll off/on */
+int ai_clkctl_xtal(struct si_pub *sih, uint what, bool on)
+{
+ struct si_info *sii;
+ u32 in, out, outen;
+
+ sii = (struct si_info *)sih;
+
+ /* pcie core doesn't have any mapping to control the xtal pu */
+ if (PCIE(sii))
+ return -1;
+
+ pci_read_config_dword(sii->pbus, PCI_GPIO_IN, &in);
+ pci_read_config_dword(sii->pbus, PCI_GPIO_OUT, &out);
+ pci_read_config_dword(sii->pbus, PCI_GPIO_OUTEN, &outen);
+
+ /*
+ * Avoid glitching the clock if GPRS is already using it.
+ * We can't actually read the state of the PLLPD so we infer it
+ * by the value of XTAL_PU which *is* readable via gpioin.
+ */
+ if (on && (in & PCI_CFG_GPIO_XTAL))
+ return 0;
+
+ if (what & XTAL)
+ outen |= PCI_CFG_GPIO_XTAL;
+ if (what & PLL)
+ outen |= PCI_CFG_GPIO_PLL;
+
+ if (on) {
+ /* turn primary xtal on */
+ if (what & XTAL) {
+ out |= PCI_CFG_GPIO_XTAL;
+ if (what & PLL)
+ out |= PCI_CFG_GPIO_PLL;
+ pci_write_config_dword(sii->pbus,
+ PCI_GPIO_OUT, out);
+ pci_write_config_dword(sii->pbus,
+ PCI_GPIO_OUTEN, outen);
+ udelay(XTAL_ON_DELAY);
+ }
+
+ /* turn pll on */
+ if (what & PLL) {
+ out &= ~PCI_CFG_GPIO_PLL;
+ pci_write_config_dword(sii->pbus,
+ PCI_GPIO_OUT, out);
+ mdelay(2);
+ }
+ } else {
+ if (what & XTAL)
+ out &= ~PCI_CFG_GPIO_XTAL;
+ if (what & PLL)
+ out |= PCI_CFG_GPIO_PLL;
+ pci_write_config_dword(sii->pbus,
+ PCI_GPIO_OUT, out);
+ pci_write_config_dword(sii->pbus,
+ PCI_GPIO_OUTEN, outen);
+ }
+
+ return 0;
+}
+
+/* clk control mechanism through chipcommon, no policy checking */
+static bool _ai_clkctl_cc(struct si_info *sii, uint mode)
+{
+ uint origidx = 0;
+ struct chipcregs __iomem *cc;
+ u32 scc;
+ uint intr_val = 0;
+ bool fast = SI_FAST(sii);
+
+ /* chipcommon cores prior to rev6 don't support dynamic clock control */
+ if (sii->pub.ccrev < 6)
+ return false;
+
+ if (!fast) {
+ INTR_OFF(sii, intr_val);
+ origidx = sii->curidx;
+ cc = (struct chipcregs __iomem *)
+ ai_setcore(&sii->pub, CC_CORE_ID, 0);
+ } else {
+ cc = (struct chipcregs __iomem *) CCREGS_FAST(sii);
+ if (cc == NULL)
+ goto done;
+ }
+
+ if (!(sii->pub.cccaps & CC_CAP_PWR_CTL) && (sii->pub.ccrev < 20))
+ goto done;
+
+ switch (mode) {
+ case CLK_FAST: /* FORCEHT, fast (pll) clock */
+ if (sii->pub.ccrev < 10) {
+ /*
+ * don't forget to force xtal back
+ * on before we clear SCC_DYN_XTAL..
+ */
+ ai_clkctl_xtal(&sii->pub, XTAL, ON);
+ SET_REG(&cc->slow_clk_ctl,
+ (SCC_XC | SCC_FS | SCC_IP), SCC_IP);
+ } else if (sii->pub.ccrev < 20) {
+ OR_REG(&cc->system_clk_ctl, SYCC_HR);
+ } else {
+ OR_REG(&cc->clk_ctl_st, CCS_FORCEHT);
+ }
+
+ /* wait for the PLL */
+ if (sii->pub.cccaps & CC_CAP_PMU) {
+ u32 htavail = CCS_HTAVAIL;
+ SPINWAIT(((R_REG(&cc->clk_ctl_st) & htavail)
+ == 0), PMU_MAX_TRANSITION_DLY);
+ } else {
+ udelay(PLL_DELAY);
+ }
+ break;
+
+ case CLK_DYNAMIC: /* enable dynamic clock control */
+ if (sii->pub.ccrev < 10) {
+ scc = R_REG(&cc->slow_clk_ctl);
+ scc &= ~(SCC_FS | SCC_IP | SCC_XC);
+ if ((scc & SCC_SS_MASK) != SCC_SS_XTAL)
+ scc |= SCC_XC;
+ W_REG(&cc->slow_clk_ctl, scc);
+
+ /*
+ * for dynamic control, we have to
+ * release our xtal_pu "force on"
+ */
+ if (scc & SCC_XC)
+ ai_clkctl_xtal(&sii->pub, XTAL, OFF);
+ } else if (sii->pub.ccrev < 20) {
+ /* Instaclock */
+ AND_REG(&cc->system_clk_ctl, ~SYCC_HR);
+ } else {
+ AND_REG(&cc->clk_ctl_st, ~CCS_FORCEHT);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ done:
+ if (!fast) {
+ ai_setcoreidx(&sii->pub, origidx);
+ INTR_RESTORE(sii, intr_val);
+ }
+ return mode == CLK_FAST;
+}
+
+/*
+ * clock control policy function throught chipcommon
+ *
+ * set dynamic clk control mode (forceslow, forcefast, dynamic)
+ * returns true if we are forcing fast clock
+ * this is a wrapper over the next internal function
+ * to allow flexible policy settings for outside caller
+ */
+bool ai_clkctl_cc(struct si_pub *sih, uint mode)
+{
+ struct si_info *sii;
+
+ sii = (struct si_info *)sih;
+
+ /* chipcommon cores prior to rev6 don't support dynamic clock control */
+ if (sih->ccrev < 6)
+ return false;
+
+ if (PCI_FORCEHT(sii))
+ return mode == CLK_FAST;
+
+ return _ai_clkctl_cc(sii, mode);
+}
+
+/* Build device path */
+int ai_devpath(struct si_pub *sih, char *path, int size)
+{
+ int slen;
+
+ if (!path || size <= 0)
+ return -1;
+
+ slen = snprintf(path, (size_t) size, "pci/%u/%u/",
+ ((struct si_info *)sih)->pbus->bus->number,
+ PCI_SLOT(((struct pci_dev *)
+ (((struct si_info *)(sih))->pbus))->devfn));
+
+ if (slen < 0 || slen >= size) {
+ path[0] = '\0';
+ return -1;
+ }
+
+ return 0;
+}
+
+void ai_pci_up(struct si_pub *sih)
+{
+ struct si_info *sii;
+
+ sii = (struct si_info *)sih;
+
+ if (PCI_FORCEHT(sii))
+ _ai_clkctl_cc(sii, CLK_FAST);
+
+ if (PCIE(sii))
+ pcicore_up(sii->pch, SI_PCIUP);
+
+}
+
+/* Unconfigure and/or apply various WARs when system is going to sleep mode */
+void ai_pci_sleep(struct si_pub *sih)
+{
+ struct si_info *sii;
+
+ sii = (struct si_info *)sih;
+
+ pcicore_sleep(sii->pch);
+}
+
+/* Unconfigure and/or apply various WARs when going down */
+void ai_pci_down(struct si_pub *sih)
+{
+ struct si_info *sii;
+
+ sii = (struct si_info *)sih;
+
+ /* release FORCEHT since chip is going to "down" state */
+ if (PCI_FORCEHT(sii))
+ _ai_clkctl_cc(sii, CLK_DYNAMIC);
+
+ pcicore_down(sii->pch, SI_PCIDOWN);
+}
+
+/*
+ * Configure the pci core for pci client (NIC) action
+ * coremask is the bitvec of cores by index to be enabled.
+ */
+void ai_pci_setup(struct si_pub *sih, uint coremask)
+{
+ struct si_info *sii;
+ struct sbpciregs __iomem *regs = NULL;
+ u32 siflag = 0, w;
+ uint idx = 0;
+
+ sii = (struct si_info *)sih;
+
+ if (PCI(sii)) {
+ /* get current core index */
+ idx = sii->curidx;
+
+ /* we interrupt on this backplane flag number */
+ siflag = ai_flag(sih);
+
+ /* switch over to pci core */
+ regs = ai_setcoreidx(sih, sii->pub.buscoreidx);
+ }
+
+ /*
+ * Enable sb->pci interrupts. Assume
+ * PCI rev 2.3 support was added in pci core rev 6 and things changed..
+ */
+ if (PCIE(sii) || (PCI(sii) && ((sii->pub.buscorerev) >= 6))) {
+ /* pci config write to set this core bit in PCIIntMask */
+ pci_read_config_dword(sii->pbus, PCI_INT_MASK, &w);
+ w |= (coremask << PCI_SBIM_SHIFT);
+ pci_write_config_dword(sii->pbus, PCI_INT_MASK, w);
+ } else {
+ /* set sbintvec bit for our flag number */
+ ai_setint(sih, siflag);
+ }
+
+ if (PCI(sii)) {
+ pcicore_pci_setup(sii->pch, regs);
+
+ /* switch back to previous core */
+ ai_setcoreidx(sih, idx);
+ }
+}
+
+/*
+ * Fixup SROMless PCI device's configuration.
+ * The current core may be changed upon return.
+ */
+int ai_pci_fixcfg(struct si_pub *sih)
+{
+ uint origidx;
+ void __iomem *regs = NULL;
+ struct si_info *sii = (struct si_info *)sih;
+
+ /* Fixup PI in SROM shadow area to enable the correct PCI core access */
+ /* save the current index */
+ origidx = ai_coreidx(&sii->pub);
+
+ /* check 'pi' is correct and fix it if not */
+ regs = ai_setcore(&sii->pub, sii->pub.buscoretype, 0);
+ if (sii->pub.buscoretype == PCIE_CORE_ID)
+ pcicore_fixcfg_pcie(sii->pch,
+ (struct sbpcieregs __iomem *)regs);
+ else if (sii->pub.buscoretype == PCI_CORE_ID)
+ pcicore_fixcfg_pci(sii->pch, (struct sbpciregs __iomem *)regs);
+
+ /* restore the original index */
+ ai_setcoreidx(&sii->pub, origidx);
+
+ pcicore_hwup(sii->pch);
+ return 0;
+}
+
+/* mask&set gpiocontrol bits */
+u32 ai_gpiocontrol(struct si_pub *sih, u32 mask, u32 val, u8 priority)
+{
+ uint regoff;
+
+ regoff = offsetof(struct chipcregs, gpiocontrol);
+ return ai_corereg(sih, SI_CC_IDX, regoff, mask, val);
+}
+
+void ai_chipcontrl_epa4331(struct si_pub *sih, bool on)
+{
+ struct si_info *sii;
+ struct chipcregs __iomem *cc;
+ uint origidx;
+ u32 val;
+
+ sii = (struct si_info *)sih;
+ origidx = ai_coreidx(sih);
+
+ cc = (struct chipcregs __iomem *) ai_setcore(sih, CC_CORE_ID, 0);
+
+ val = R_REG(&cc->chipcontrol);
+
+ if (on) {
+ if (sih->chippkg == 9 || sih->chippkg == 0xb)
+ /* Ext PA Controls for 4331 12x9 Package */
+ W_REG(&cc->chipcontrol, val |
+ CCTRL4331_EXTPA_EN |
+ CCTRL4331_EXTPA_ON_GPIO2_5);
+ else
+ /* Ext PA Controls for 4331 12x12 Package */
+ W_REG(&cc->chipcontrol,
+ val | CCTRL4331_EXTPA_EN);
+ } else {
+ val &= ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5);
+ W_REG(&cc->chipcontrol, val);
+ }
+
+ ai_setcoreidx(sih, origidx);
+}
+
+/* Enable BT-COEX & Ex-PA for 4313 */
+void ai_epa_4313war(struct si_pub *sih)
+{
+ struct si_info *sii;
+ struct chipcregs __iomem *cc;
+ uint origidx;
+
+ sii = (struct si_info *)sih;
+ origidx = ai_coreidx(sih);
+
+ cc = ai_setcore(sih, CC_CORE_ID, 0);
+
+ /* EPA Fix */
+ W_REG(&cc->gpiocontrol,
+ R_REG(&cc->gpiocontrol) | GPIO_CTRL_EPA_EN_MASK);
+
+ ai_setcoreidx(sih, origidx);
+}
+
+/* check if the device is removed */
+bool ai_deviceremoved(struct si_pub *sih)
+{
+ u32 w;
+ struct si_info *sii;
+
+ sii = (struct si_info *)sih;
+
+ pci_read_config_dword(sii->pbus, PCI_VENDOR_ID, &w);
+ if ((w & 0xFFFF) != PCI_VENDOR_ID_BROADCOM)
+ return true;
+
+ return false;
+}
+
+bool ai_is_sprom_available(struct si_pub *sih)
+{
+ if (sih->ccrev >= 31) {
+ struct si_info *sii;
+ uint origidx;
+ struct chipcregs __iomem *cc;
+ u32 sromctrl;
+
+ if ((sih->cccaps & CC_CAP_SROM) == 0)
+ return false;
+
+ sii = (struct si_info *)sih;
+ origidx = sii->curidx;
+ cc = ai_setcoreidx(sih, SI_CC_IDX);
+ sromctrl = R_REG(&cc->sromcontrol);
+ ai_setcoreidx(sih, origidx);
+ return sromctrl & SRC_PRESENT;
+ }
+
+ switch (sih->chip) {
+ case BCM4313_CHIP_ID:
+ return (sih->chipst & CST4313_SPROM_PRESENT) != 0;
+ default:
+ return true;
+ }
+}
+
+bool ai_is_otp_disabled(struct si_pub *sih)
+{
+ switch (sih->chip) {
+ case BCM4313_CHIP_ID:
+ return (sih->chipst & CST4313_OTP_PRESENT) == 0;
+ /* These chips always have their OTP on */
+ case BCM43224_CHIP_ID:
+ case BCM43225_CHIP_ID:
+ default:
+ return false;
+ }
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h
new file mode 100644
index 000000000000..106a7424a7cd
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h
@@ -0,0 +1,378 @@
+/*
+ * 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 _BRCM_AIUTILS_H_
+#define _BRCM_AIUTILS_H_
+
+#include "types.h"
+
+/*
+ * SOC Interconnect Address Map.
+ * All regions may not exist on all chips.
+ */
+/* each core gets 4Kbytes for registers */
+#define SI_CORE_SIZE 0x1000
+/*
+ * Max cores (this is arbitrary, for software
+ * convenience and could be changed if we
+ * make any larger chips
+ */
+#define SI_MAXCORES 16
+
+/* Client Mode sb2pcitranslation2 size in bytes */
+#define SI_PCI_DMA_SZ 0x40000000
+
+/* PCIE Client Mode sb2pcitranslation2 (2 ZettaBytes), high 32 bits */
+#define SI_PCIE_DMA_H32 0x80000000
+
+/* core codes */
+#define NODEV_CORE_ID 0x700 /* Invalid coreid */
+#define CC_CORE_ID 0x800 /* chipcommon core */
+#define ILINE20_CORE_ID 0x801 /* iline20 core */
+#define SRAM_CORE_ID 0x802 /* sram core */
+#define SDRAM_CORE_ID 0x803 /* sdram core */
+#define PCI_CORE_ID 0x804 /* pci core */
+#define MIPS_CORE_ID 0x805 /* mips core */
+#define ENET_CORE_ID 0x806 /* enet mac core */
+#define CODEC_CORE_ID 0x807 /* v90 codec core */
+#define USB_CORE_ID 0x808 /* usb 1.1 host/device core */
+#define ADSL_CORE_ID 0x809 /* ADSL core */
+#define ILINE100_CORE_ID 0x80a /* iline100 core */
+#define IPSEC_CORE_ID 0x80b /* ipsec core */
+#define UTOPIA_CORE_ID 0x80c /* utopia core */
+#define PCMCIA_CORE_ID 0x80d /* pcmcia core */
+#define SOCRAM_CORE_ID 0x80e /* internal memory core */
+#define MEMC_CORE_ID 0x80f /* memc sdram core */
+#define OFDM_CORE_ID 0x810 /* OFDM phy core */
+#define EXTIF_CORE_ID 0x811 /* external interface core */
+#define D11_CORE_ID 0x812 /* 802.11 MAC core */
+#define APHY_CORE_ID 0x813 /* 802.11a phy core */
+#define BPHY_CORE_ID 0x814 /* 802.11b phy core */
+#define GPHY_CORE_ID 0x815 /* 802.11g phy core */
+#define MIPS33_CORE_ID 0x816 /* mips3302 core */
+#define USB11H_CORE_ID 0x817 /* usb 1.1 host core */
+#define USB11D_CORE_ID 0x818 /* usb 1.1 device core */
+#define USB20H_CORE_ID 0x819 /* usb 2.0 host core */
+#define USB20D_CORE_ID 0x81a /* usb 2.0 device core */
+#define SDIOH_CORE_ID 0x81b /* sdio host core */
+#define ROBO_CORE_ID 0x81c /* roboswitch core */
+#define ATA100_CORE_ID 0x81d /* parallel ATA core */
+#define SATAXOR_CORE_ID 0x81e /* serial ATA & XOR DMA core */
+#define GIGETH_CORE_ID 0x81f /* gigabit ethernet core */
+#define PCIE_CORE_ID 0x820 /* pci express core */
+#define NPHY_CORE_ID 0x821 /* 802.11n 2x2 phy core */
+#define SRAMC_CORE_ID 0x822 /* SRAM controller core */
+#define MINIMAC_CORE_ID 0x823 /* MINI MAC/phy core */
+#define ARM11_CORE_ID 0x824 /* ARM 1176 core */
+#define ARM7S_CORE_ID 0x825 /* ARM7tdmi-s core */
+#define LPPHY_CORE_ID 0x826 /* 802.11a/b/g phy core */
+#define PMU_CORE_ID 0x827 /* PMU core */
+#define SSNPHY_CORE_ID 0x828 /* 802.11n single-stream phy core */
+#define SDIOD_CORE_ID 0x829 /* SDIO device core */
+#define ARMCM3_CORE_ID 0x82a /* ARM Cortex M3 core */
+#define HTPHY_CORE_ID 0x82b /* 802.11n 4x4 phy core */
+#define MIPS74K_CORE_ID 0x82c /* mips 74k core */
+#define GMAC_CORE_ID 0x82d /* Gigabit MAC core */
+#define DMEMC_CORE_ID 0x82e /* DDR1/2 memory controller core */
+#define PCIERC_CORE_ID 0x82f /* PCIE Root Complex core */
+#define OCP_CORE_ID 0x830 /* OCP2OCP bridge core */
+#define SC_CORE_ID 0x831 /* shared common core */
+#define AHB_CORE_ID 0x832 /* OCP2AHB bridge core */
+#define SPIH_CORE_ID 0x833 /* SPI host core */
+#define I2S_CORE_ID 0x834 /* I2S core */
+#define DMEMS_CORE_ID 0x835 /* SDR/DDR1 memory controller core */
+#define DEF_SHIM_COMP 0x837 /* SHIM component in ubus/6362 */
+#define OOB_ROUTER_CORE_ID 0x367 /* OOB router core ID */
+#define DEF_AI_COMP 0xfff /* Default component, in ai chips it
+ * maps all unused address ranges
+ */
+
+/* chipcommon being the first core: */
+#define SI_CC_IDX 0
+
+/* SOC Interconnect types (aka chip types) */
+#define SOCI_AI 1
+
+/* Common core control flags */
+#define SICF_BIST_EN 0x8000
+#define SICF_PME_EN 0x4000
+#define SICF_CORE_BITS 0x3ffc
+#define SICF_FGC 0x0002
+#define SICF_CLOCK_EN 0x0001
+
+/* Common core status flags */
+#define SISF_BIST_DONE 0x8000
+#define SISF_BIST_ERROR 0x4000
+#define SISF_GATED_CLK 0x2000
+#define SISF_DMA64 0x1000
+#define SISF_CORE_BITS 0x0fff
+
+/* A register that is common to all cores to
+ * communicate w/PMU regarding clock control.
+ */
+#define SI_CLK_CTL_ST 0x1e0 /* clock control and status */
+
+/* clk_ctl_st register */
+#define CCS_FORCEALP 0x00000001 /* force ALP request */
+#define CCS_FORCEHT 0x00000002 /* force HT request */
+#define CCS_FORCEILP 0x00000004 /* force ILP request */
+#define CCS_ALPAREQ 0x00000008 /* ALP Avail Request */
+#define CCS_HTAREQ 0x00000010 /* HT Avail Request */
+#define CCS_FORCEHWREQOFF 0x00000020 /* Force HW Clock Request Off */
+#define CCS_ERSRC_REQ_MASK 0x00000700 /* external resource requests */
+#define CCS_ERSRC_REQ_SHIFT 8
+#define CCS_ALPAVAIL 0x00010000 /* ALP is available */
+#define CCS_HTAVAIL 0x00020000 /* HT is available */
+#define CCS_BP_ON_APL 0x00040000 /* RO: running on ALP clock */
+#define CCS_BP_ON_HT 0x00080000 /* RO: running on HT clock */
+#define CCS_ERSRC_STS_MASK 0x07000000 /* external resource status */
+#define CCS_ERSRC_STS_SHIFT 24
+
+/* HT avail in chipc and pcmcia on 4328a0 */
+#define CCS0_HTAVAIL 0x00010000
+/* ALP avail in chipc and pcmcia on 4328a0 */
+#define CCS0_ALPAVAIL 0x00020000
+
+/* Not really related to SOC Interconnect, but a couple of software
+ * conventions for the use the flash space:
+ */
+
+/* Minumum amount of flash we support */
+#define FLASH_MIN 0x00020000 /* Minimum flash size */
+
+#define CC_SROM_OTP 0x800 /* SROM/OTP address space */
+
+/* gpiotimerval */
+#define GPIO_ONTIME_SHIFT 16
+
+/* Fields in clkdiv */
+#define CLKD_OTP 0x000f0000
+#define CLKD_OTP_SHIFT 16
+
+/* Package IDs */
+#define BCM4717_PKG_ID 9 /* 4717 package id */
+#define BCM4718_PKG_ID 10 /* 4718 package id */
+#define BCM43224_FAB_SMIC 0xa /* the chip is manufactured by SMIC */
+
+/* these are router chips */
+#define BCM4716_CHIP_ID 0x4716 /* 4716 chipcommon chipid */
+#define BCM47162_CHIP_ID 47162 /* 47162 chipcommon chipid */
+#define BCM4748_CHIP_ID 0x4748 /* 4716 chipcommon chipid (OTP, RBBU) */
+
+/* dynamic clock control defines */
+#define LPOMINFREQ 25000 /* low power oscillator min */
+#define LPOMAXFREQ 43000 /* low power oscillator max */
+#define XTALMINFREQ 19800000 /* 20 MHz - 1% */
+#define XTALMAXFREQ 20200000 /* 20 MHz + 1% */
+#define PCIMINFREQ 25000000 /* 25 MHz */
+#define PCIMAXFREQ 34000000 /* 33 MHz + fudge */
+
+#define ILP_DIV_5MHZ 0 /* ILP = 5 MHz */
+#define ILP_DIV_1MHZ 4 /* ILP = 1 MHz */
+
+/* clkctl xtal what flags */
+#define XTAL 0x1 /* primary crystal oscillator (2050) */
+#define PLL 0x2 /* main chip pll */
+
+/* clkctl clk mode */
+#define CLK_FAST 0 /* force fast (pll) clock */
+#define CLK_DYNAMIC 2 /* enable dynamic clock control */
+
+/* GPIO usage priorities */
+#define GPIO_DRV_PRIORITY 0 /* Driver */
+#define GPIO_APP_PRIORITY 1 /* Application */
+#define GPIO_HI_PRIORITY 2 /* Highest priority. Ignore GPIO
+ * reservation
+ */
+
+/* GPIO pull up/down */
+#define GPIO_PULLUP 0
+#define GPIO_PULLDN 1
+
+/* GPIO event regtype */
+#define GPIO_REGEVT 0 /* GPIO register event */
+#define GPIO_REGEVT_INTMSK 1 /* GPIO register event int mask */
+#define GPIO_REGEVT_INTPOL 2 /* GPIO register event int polarity */
+
+/* device path */
+#define SI_DEVPATH_BUFSZ 16 /* min buffer size in bytes */
+
+/* SI routine enumeration: to be used by update function with multiple hooks */
+#define SI_DOATTACH 1
+#define SI_PCIDOWN 2
+#define SI_PCIUP 3
+
+/*
+ * Data structure to export all chip specific common variables
+ * public (read-only) portion of aiutils handle returned by si_attach()
+ */
+struct si_pub {
+ uint buscoretype; /* PCI_CORE_ID, PCIE_CORE_ID, PCMCIA_CORE_ID */
+ uint buscorerev; /* buscore rev */
+ uint buscoreidx; /* buscore index */
+ int ccrev; /* chip common core rev */
+ u32 cccaps; /* chip common capabilities */
+ u32 cccaps_ext; /* chip common capabilities extension */
+ int pmurev; /* pmu core rev */
+ u32 pmucaps; /* pmu capabilities */
+ uint boardtype; /* board type */
+ uint boardvendor; /* board vendor */
+ uint boardflags; /* board flags */
+ uint boardflags2; /* board flags2 */
+ uint chip; /* chip number */
+ uint chiprev; /* chip revision */
+ uint chippkg; /* chip package option */
+ u32 chipst; /* chip status */
+ bool issim; /* chip is in simulation or emulation */
+ uint socirev; /* SOC interconnect rev */
+ bool pci_pr32414;
+
+};
+
+struct pci_dev;
+
+struct gpioh_item {
+ void *arg;
+ bool level;
+ void (*handler) (u32 stat, void *arg);
+ u32 event;
+ struct gpioh_item *next;
+};
+
+/* misc si info needed by some of the routines */
+struct si_info {
+ struct si_pub pub; /* back plane public state (must be first) */
+ struct pci_dev *pbus; /* handle to pci bus */
+ uint dev_coreid; /* the core provides driver functions */
+ void *intr_arg; /* interrupt callback function arg */
+ u32 (*intrsoff_fn) (void *intr_arg); /* turns chip interrupts off */
+ /* restore chip interrupts */
+ void (*intrsrestore_fn) (void *intr_arg, u32 arg);
+ /* check if interrupts are enabled */
+ bool (*intrsenabled_fn) (void *intr_arg);
+
+ struct pcicore_info *pch; /* PCI/E core handle */
+
+ struct list_head var_list; /* list of srom variables */
+
+ void __iomem *curmap; /* current regs va */
+ void __iomem *regs[SI_MAXCORES]; /* other regs va */
+
+ uint curidx; /* current core index */
+ uint numcores; /* # discovered cores */
+ uint coreid[SI_MAXCORES]; /* id of each core */
+ u32 coresba[SI_MAXCORES]; /* backplane address of each core */
+ void *regs2[SI_MAXCORES]; /* 2nd virtual address per core (usbh20) */
+ u32 coresba2[SI_MAXCORES]; /* 2nd phys address per core (usbh20) */
+ u32 coresba_size[SI_MAXCORES]; /* backplane address space size */
+ u32 coresba2_size[SI_MAXCORES]; /* second address space size */
+
+ void *curwrap; /* current wrapper va */
+ void *wrappers[SI_MAXCORES]; /* other cores wrapper va */
+ u32 wrapba[SI_MAXCORES]; /* address of controlling wrapper */
+
+ u32 cia[SI_MAXCORES]; /* erom cia entry for each core */
+ u32 cib[SI_MAXCORES]; /* erom cia entry for each core */
+ u32 oob_router; /* oob router registers for axi */
+};
+
+/*
+ * Many of the routines below take an 'sih' handle as their first arg.
+ * Allocate this by calling si_attach(). Free it by calling si_detach().
+ * At any one time, the sih is logically focused on one particular si core
+ * (the "current core").
+ * Use si_setcore() or si_setcoreidx() to change the association to another core
+ */
+
+
+/* AMBA Interconnect exported externs */
+extern uint ai_flag(struct si_pub *sih);
+extern void ai_setint(struct si_pub *sih, int siflag);
+extern uint ai_coreidx(struct si_pub *sih);
+extern uint ai_corevendor(struct si_pub *sih);
+extern uint ai_corerev(struct si_pub *sih);
+extern bool ai_iscoreup(struct si_pub *sih);
+extern u32 ai_core_cflags(struct si_pub *sih, u32 mask, u32 val);
+extern void ai_core_cflags_wo(struct si_pub *sih, u32 mask, u32 val);
+extern u32 ai_core_sflags(struct si_pub *sih, u32 mask, u32 val);
+extern uint ai_corereg(struct si_pub *sih, uint coreidx, uint regoff, uint mask,
+ uint val);
+extern void ai_core_reset(struct si_pub *sih, u32 bits, u32 resetbits);
+extern void ai_core_disable(struct si_pub *sih, u32 bits);
+extern int ai_numaddrspaces(struct si_pub *sih);
+extern u32 ai_addrspace(struct si_pub *sih, uint asidx);
+extern u32 ai_addrspacesize(struct si_pub *sih, uint asidx);
+extern void ai_write_wrap_reg(struct si_pub *sih, u32 offset, u32 val);
+
+/* === exported functions === */
+extern struct si_pub *ai_attach(void __iomem *regs, struct pci_dev *sdh);
+extern void ai_detach(struct si_pub *sih);
+extern uint ai_coreid(struct si_pub *sih);
+extern uint ai_corerev(struct si_pub *sih);
+extern uint ai_corereg(struct si_pub *sih, uint coreidx, uint regoff, uint mask,
+ uint val);
+extern void ai_write_wrapperreg(struct si_pub *sih, u32 offset, u32 val);
+extern u32 ai_core_cflags(struct si_pub *sih, u32 mask, u32 val);
+extern u32 ai_core_sflags(struct si_pub *sih, u32 mask, u32 val);
+extern bool ai_iscoreup(struct si_pub *sih);
+extern uint ai_findcoreidx(struct si_pub *sih, uint coreid, uint coreunit);
+extern void __iomem *ai_setcoreidx(struct si_pub *sih, uint coreidx);
+extern void __iomem *ai_setcore(struct si_pub *sih, uint coreid, uint coreunit);
+extern void __iomem *ai_switch_core(struct si_pub *sih, uint coreid,
+ uint *origidx, uint *intr_val);
+extern void ai_restore_core(struct si_pub *sih, uint coreid, uint intr_val);
+extern void ai_core_reset(struct si_pub *sih, u32 bits, u32 resetbits);
+extern void ai_core_disable(struct si_pub *sih, u32 bits);
+extern u32 ai_alp_clock(struct si_pub *sih);
+extern u32 ai_ilp_clock(struct si_pub *sih);
+extern void ai_pci_setup(struct si_pub *sih, uint coremask);
+extern void ai_setint(struct si_pub *sih, int siflag);
+extern bool ai_backplane64(struct si_pub *sih);
+extern void ai_register_intr_callback(struct si_pub *sih, void *intrsoff_fn,
+ void *intrsrestore_fn,
+ void *intrsenabled_fn, void *intr_arg);
+extern void ai_deregister_intr_callback(struct si_pub *sih);
+extern void ai_clkctl_init(struct si_pub *sih);
+extern u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih);
+extern bool ai_clkctl_cc(struct si_pub *sih, uint mode);
+extern int ai_clkctl_xtal(struct si_pub *sih, uint what, bool on);
+extern bool ai_deviceremoved(struct si_pub *sih);
+extern u32 ai_gpiocontrol(struct si_pub *sih, u32 mask, u32 val,
+ u8 priority);
+
+/* OTP status */
+extern bool ai_is_otp_disabled(struct si_pub *sih);
+
+/* SPROM availability */
+extern bool ai_is_sprom_available(struct si_pub *sih);
+
+/*
+ * Build device path. Path size must be >= SI_DEVPATH_BUFSZ.
+ * The returned path is NULL terminated and has trailing '/'.
+ * Return 0 on success, nonzero otherwise.
+ */
+extern int ai_devpath(struct si_pub *sih, char *path, int size);
+
+extern void ai_pci_sleep(struct si_pub *sih);
+extern void ai_pci_down(struct si_pub *sih);
+extern void ai_pci_up(struct si_pub *sih);
+extern int ai_pci_fixcfg(struct si_pub *sih);
+
+extern void ai_chipcontrl_epa4331(struct si_pub *sih, bool on);
+/* Enable Ex-PA for 4313 */
+extern void ai_epa_4313war(struct si_pub *sih);
+
+#endif /* _BRCM_AIUTILS_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
new file mode 100644
index 000000000000..7f27dbdb6b60
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
@@ -0,0 +1,1241 @@
+/*
+ * Copyright (c) 2010 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 <net/mac80211.h>
+
+#include "rate.h"
+#include "scb.h"
+#include "phy/phy_hal.h"
+#include "antsel.h"
+#include "main.h"
+#include "ampdu.h"
+
+/* max number of mpdus in an ampdu */
+#define AMPDU_MAX_MPDU 32
+/* max number of mpdus in an ampdu to a legacy */
+#define AMPDU_NUM_MPDU_LEGACY 16
+/* max Tx ba window size (in pdu) */
+#define AMPDU_TX_BA_MAX_WSIZE 64
+/* default Tx ba window size (in pdu) */
+#define AMPDU_TX_BA_DEF_WSIZE 64
+/* default Rx ba window size (in pdu) */
+#define AMPDU_RX_BA_DEF_WSIZE 64
+/* max Rx ba window size (in pdu) */
+#define AMPDU_RX_BA_MAX_WSIZE 64
+/* max dur of tx ampdu (in msec) */
+#define AMPDU_MAX_DUR 5
+/* default tx retry limit */
+#define AMPDU_DEF_RETRY_LIMIT 5
+/* default tx retry limit at reg rate */
+#define AMPDU_DEF_RR_RETRY_LIMIT 2
+/* default weight of ampdu in txfifo */
+#define AMPDU_DEF_TXPKT_WEIGHT 2
+/* default ffpld reserved bytes */
+#define AMPDU_DEF_FFPLD_RSVD 2048
+/* # of inis to be freed on detach */
+#define AMPDU_INI_FREE 10
+/* max # of mpdus released at a time */
+#define AMPDU_SCB_MAX_RELEASE 20
+
+#define NUM_FFPLD_FIFO 4 /* number of fifo concerned by pre-loading */
+#define FFPLD_TX_MAX_UNFL 200 /* default value of the average number of ampdu
+ * without underflows
+ */
+#define FFPLD_MPDU_SIZE 1800 /* estimate of maximum mpdu size */
+#define FFPLD_MAX_MCS 23 /* we don't deal with mcs 32 */
+#define FFPLD_PLD_INCR 1000 /* increments in bytes */
+#define FFPLD_MAX_AMPDU_CNT 5000 /* maximum number of ampdu we
+ * accumulate between resets.
+ */
+
+#define AMPDU_DELIMITER_LEN 4
+
+/* max allowed number of mpdus in an ampdu (2 streams) */
+#define AMPDU_NUM_MPDU 16
+
+#define TX_SEQ_TO_INDEX(seq) ((seq) % AMPDU_TX_BA_MAX_WSIZE)
+
+/* max possible overhead per mpdu in the ampdu; 3 is for roundup if needed */
+#define AMPDU_MAX_MPDU_OVERHEAD (FCS_LEN + DOT11_ICV_AES_LEN +\
+ AMPDU_DELIMITER_LEN + 3\
+ + DOT11_A4_HDR_LEN + DOT11_QOS_LEN + DOT11_IV_MAX_LEN)
+
+/* modulo add/sub, bound = 2^k */
+#define MODADD_POW2(x, y, bound) (((x) + (y)) & ((bound) - 1))
+#define MODSUB_POW2(x, y, bound) (((x) - (y)) & ((bound) - 1))
+
+/* structure to hold tx fifo information and pre-loading state
+ * counters specific to tx underflows of ampdus
+ * some counters might be redundant with the ones in wlc or ampdu structures.
+ * This allows to maintain a specific state independently of
+ * how often and/or when the wlc counters are updated.
+ *
+ * ampdu_pld_size: number of bytes to be pre-loaded
+ * mcs2ampdu_table: per-mcs max # of mpdus in an ampdu
+ * prev_txfunfl: num of underflows last read from the HW macstats counter
+ * accum_txfunfl: num of underflows since we modified pld params
+ * accum_txampdu: num of tx ampdu since we modified pld params
+ * prev_txampdu: previous reading of tx ampdu
+ * dmaxferrate: estimated dma avg xfer rate in kbits/sec
+ */
+struct brcms_fifo_info {
+ u16 ampdu_pld_size;
+ u8 mcs2ampdu_table[FFPLD_MAX_MCS + 1];
+ u16 prev_txfunfl;
+ u32 accum_txfunfl;
+ u32 accum_txampdu;
+ u32 prev_txampdu;
+ u32 dmaxferrate;
+};
+
+/* AMPDU module specific state
+ *
+ * wlc: pointer to main wlc structure
+ * scb_handle: scb cubby handle to retrieve data from scb
+ * ini_enable: per-tid initiator enable/disable of ampdu
+ * ba_tx_wsize: Tx ba window size (in pdu)
+ * ba_rx_wsize: Rx ba window size (in pdu)
+ * retry_limit: mpdu transmit retry limit
+ * rr_retry_limit: mpdu transmit retry limit at regular rate
+ * retry_limit_tid: per-tid mpdu transmit retry limit
+ * rr_retry_limit_tid: per-tid mpdu transmit retry limit at regular rate
+ * mpdu_density: min mpdu spacing (0-7) ==> 2^(x-1)/8 usec
+ * max_pdu: max pdus allowed in ampdu
+ * dur: max duration of an ampdu (in msec)
+ * txpkt_weight: weight of ampdu in txfifo; reduces rate lag
+ * rx_factor: maximum rx ampdu factor (0-3) ==> 2^(13+x) bytes
+ * ffpld_rsvd: number of bytes to reserve for preload
+ * max_txlen: max size of ampdu per mcs, bw and sgi
+ * mfbr: enable multiple fallback rate
+ * tx_max_funl: underflows should be kept such that
+ * (tx_max_funfl*underflows) < tx frames
+ * fifo_tb: table of fifo infos
+ */
+struct ampdu_info {
+ struct brcms_c_info *wlc;
+ int scb_handle;
+ u8 ini_enable[AMPDU_MAX_SCB_TID];
+ u8 ba_tx_wsize;
+ u8 ba_rx_wsize;
+ u8 retry_limit;
+ u8 rr_retry_limit;
+ u8 retry_limit_tid[AMPDU_MAX_SCB_TID];
+ u8 rr_retry_limit_tid[AMPDU_MAX_SCB_TID];
+ u8 mpdu_density;
+ s8 max_pdu;
+ u8 dur;
+ u8 txpkt_weight;
+ u8 rx_factor;
+ u32 ffpld_rsvd;
+ u32 max_txlen[MCS_TABLE_SIZE][2][2];
+ bool mfbr;
+ u32 tx_max_funl;
+ struct brcms_fifo_info fifo_tb[NUM_FFPLD_FIFO];
+};
+
+/* used for flushing ampdu packets */
+struct cb_del_ampdu_pars {
+ struct ieee80211_sta *sta;
+ u16 tid;
+};
+
+static void brcms_c_scb_ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur)
+{
+ u32 rate, mcs;
+
+ for (mcs = 0; mcs < MCS_TABLE_SIZE; mcs++) {
+ /* rate is in Kbps; dur is in msec ==> len = (rate * dur) / 8 */
+ /* 20MHz, No SGI */
+ rate = mcs_2_rate(mcs, false, false);
+ ampdu->max_txlen[mcs][0][0] = (rate * dur) >> 3;
+ /* 40 MHz, No SGI */
+ rate = mcs_2_rate(mcs, true, false);
+ ampdu->max_txlen[mcs][1][0] = (rate * dur) >> 3;
+ /* 20MHz, SGI */
+ rate = mcs_2_rate(mcs, false, true);
+ ampdu->max_txlen[mcs][0][1] = (rate * dur) >> 3;
+ /* 40 MHz, SGI */
+ rate = mcs_2_rate(mcs, true, true);
+ ampdu->max_txlen[mcs][1][1] = (rate * dur) >> 3;
+ }
+}
+
+static bool brcms_c_ampdu_cap(struct ampdu_info *ampdu)
+{
+ if (BRCMS_PHY_11N_CAP(ampdu->wlc->band))
+ return true;
+ else
+ return false;
+}
+
+static int brcms_c_ampdu_set(struct ampdu_info *ampdu, bool on)
+{
+ struct brcms_c_info *wlc = ampdu->wlc;
+
+ wlc->pub->_ampdu = false;
+
+ if (on) {
+ if (!(wlc->pub->_n_enab & SUPPORT_11N)) {
+ wiphy_err(ampdu->wlc->wiphy, "wl%d: driver not "
+ "nmode enabled\n", wlc->pub->unit);
+ return -ENOTSUPP;
+ }
+ if (!brcms_c_ampdu_cap(ampdu)) {
+ wiphy_err(ampdu->wlc->wiphy, "wl%d: device not "
+ "ampdu capable\n", wlc->pub->unit);
+ return -ENOTSUPP;
+ }
+ wlc->pub->_ampdu = on;
+ }
+
+ return 0;
+}
+
+static void brcms_c_ffpld_init(struct ampdu_info *ampdu)
+{
+ int i, j;
+ struct brcms_fifo_info *fifo;
+
+ for (j = 0; j < NUM_FFPLD_FIFO; j++) {
+ fifo = (ampdu->fifo_tb + j);
+ fifo->ampdu_pld_size = 0;
+ for (i = 0; i <= FFPLD_MAX_MCS; i++)
+ fifo->mcs2ampdu_table[i] = 255;
+ fifo->dmaxferrate = 0;
+ fifo->accum_txampdu = 0;
+ fifo->prev_txfunfl = 0;
+ fifo->accum_txfunfl = 0;
+
+ }
+}
+
+struct ampdu_info *brcms_c_ampdu_attach(struct brcms_c_info *wlc)
+{
+ struct ampdu_info *ampdu;
+ int i;
+
+ ampdu = kzalloc(sizeof(struct ampdu_info), GFP_ATOMIC);
+ if (!ampdu)
+ return NULL;
+
+ ampdu->wlc = wlc;
+
+ for (i = 0; i < AMPDU_MAX_SCB_TID; i++)
+ ampdu->ini_enable[i] = true;
+ /* Disable ampdu for VO by default */
+ ampdu->ini_enable[PRIO_8021D_VO] = false;
+ ampdu->ini_enable[PRIO_8021D_NC] = false;
+
+ /* Disable ampdu for BK by default since not enough fifo space */
+ ampdu->ini_enable[PRIO_8021D_NONE] = false;
+ ampdu->ini_enable[PRIO_8021D_BK] = false;
+
+ ampdu->ba_tx_wsize = AMPDU_TX_BA_DEF_WSIZE;
+ ampdu->ba_rx_wsize = AMPDU_RX_BA_DEF_WSIZE;
+ ampdu->mpdu_density = AMPDU_DEF_MPDU_DENSITY;
+ ampdu->max_pdu = AUTO;
+ ampdu->dur = AMPDU_MAX_DUR;
+ ampdu->txpkt_weight = AMPDU_DEF_TXPKT_WEIGHT;
+
+ ampdu->ffpld_rsvd = AMPDU_DEF_FFPLD_RSVD;
+ /*
+ * bump max ampdu rcv size to 64k for all 11n
+ * devices except 4321A0 and 4321A1
+ */
+ if (BRCMS_ISNPHY(wlc->band) && NREV_LT(wlc->band->phyrev, 2))
+ ampdu->rx_factor = IEEE80211_HT_MAX_AMPDU_32K;
+ else
+ ampdu->rx_factor = IEEE80211_HT_MAX_AMPDU_64K;
+ ampdu->retry_limit = AMPDU_DEF_RETRY_LIMIT;
+ ampdu->rr_retry_limit = AMPDU_DEF_RR_RETRY_LIMIT;
+
+ for (i = 0; i < AMPDU_MAX_SCB_TID; i++) {
+ ampdu->retry_limit_tid[i] = ampdu->retry_limit;
+ ampdu->rr_retry_limit_tid[i] = ampdu->rr_retry_limit;
+ }
+
+ brcms_c_scb_ampdu_update_max_txlen(ampdu, ampdu->dur);
+ ampdu->mfbr = false;
+ /* try to set ampdu to the default value */
+ brcms_c_ampdu_set(ampdu, wlc->pub->_ampdu);
+
+ ampdu->tx_max_funl = FFPLD_TX_MAX_UNFL;
+ brcms_c_ffpld_init(ampdu);
+
+ return ampdu;
+}
+
+void brcms_c_ampdu_detach(struct ampdu_info *ampdu)
+{
+ kfree(ampdu);
+}
+
+static void brcms_c_scb_ampdu_update_config(struct ampdu_info *ampdu,
+ struct scb *scb)
+{
+ struct scb_ampdu *scb_ampdu = &scb->scb_ampdu;
+ int i;
+
+ scb_ampdu->max_pdu = AMPDU_NUM_MPDU;
+
+ /* go back to legacy size if some preloading is occurring */
+ for (i = 0; i < NUM_FFPLD_FIFO; i++) {
+ if (ampdu->fifo_tb[i].ampdu_pld_size > FFPLD_PLD_INCR)
+ scb_ampdu->max_pdu = AMPDU_NUM_MPDU_LEGACY;
+ }
+
+ /* apply user override */
+ if (ampdu->max_pdu != AUTO)
+ scb_ampdu->max_pdu = (u8) ampdu->max_pdu;
+
+ scb_ampdu->release = min_t(u8, scb_ampdu->max_pdu,
+ AMPDU_SCB_MAX_RELEASE);
+
+ if (scb_ampdu->max_rx_ampdu_bytes)
+ scb_ampdu->release = min_t(u8, scb_ampdu->release,
+ scb_ampdu->max_rx_ampdu_bytes / 1600);
+
+ scb_ampdu->release = min(scb_ampdu->release,
+ ampdu->fifo_tb[TX_AC_BE_FIFO].
+ mcs2ampdu_table[FFPLD_MAX_MCS]);
+}
+
+static void brcms_c_scb_ampdu_update_config_all(struct ampdu_info *ampdu)
+{
+ brcms_c_scb_ampdu_update_config(ampdu, &ampdu->wlc->pri_scb);
+}
+
+static void brcms_c_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f)
+{
+ int i;
+ u32 phy_rate, dma_rate, tmp;
+ u8 max_mpdu;
+ struct brcms_fifo_info *fifo = (ampdu->fifo_tb + f);
+
+ /* recompute the dma rate */
+ /* note : we divide/multiply by 100 to avoid integer overflows */
+ max_mpdu = min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS],
+ AMPDU_NUM_MPDU_LEGACY);
+ phy_rate = mcs_2_rate(FFPLD_MAX_MCS, true, false);
+ dma_rate =
+ (((phy_rate / 100) *
+ (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
+ / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
+ fifo->dmaxferrate = dma_rate;
+
+ /* fill up the mcs2ampdu table; do not recalc the last mcs */
+ dma_rate = dma_rate >> 7;
+ for (i = 0; i < FFPLD_MAX_MCS; i++) {
+ /* shifting to keep it within integer range */
+ phy_rate = mcs_2_rate(i, true, false) >> 7;
+ if (phy_rate > dma_rate) {
+ tmp = ((fifo->ampdu_pld_size * phy_rate) /
+ ((phy_rate - dma_rate) * FFPLD_MPDU_SIZE)) + 1;
+ tmp = min_t(u32, tmp, 255);
+ fifo->mcs2ampdu_table[i] = (u8) tmp;
+ }
+ }
+}
+
+/* evaluate the dma transfer rate using the tx underflows as feedback.
+ * If necessary, increase tx fifo preloading. If not enough,
+ * decrease maximum ampdu size for each mcs till underflows stop
+ * Return 1 if pre-loading not active, -1 if not an underflow event,
+ * 0 if pre-loading module took care of the event.
+ */
+static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int fid)
+{
+ struct ampdu_info *ampdu = wlc->ampdu;
+ u32 phy_rate = mcs_2_rate(FFPLD_MAX_MCS, true, false);
+ u32 txunfl_ratio;
+ u8 max_mpdu;
+ u32 current_ampdu_cnt = 0;
+ u16 max_pld_size;
+ u32 new_txunfl;
+ struct brcms_fifo_info *fifo = (ampdu->fifo_tb + fid);
+ uint xmtfifo_sz;
+ u16 cur_txunfl;
+
+ /* return if we got here for a different reason than underflows */
+ cur_txunfl = brcms_b_read_shm(wlc->hw,
+ M_UCODE_MACSTAT +
+ offsetof(struct macstat, txfunfl[fid]));
+ new_txunfl = (u16) (cur_txunfl - fifo->prev_txfunfl);
+ if (new_txunfl == 0) {
+ BCMMSG(wlc->wiphy, "TX status FRAG set but no tx underflows\n");
+ return -1;
+ }
+ fifo->prev_txfunfl = cur_txunfl;
+
+ if (!ampdu->tx_max_funl)
+ return 1;
+
+ /* check if fifo is big enough */
+ if (brcms_b_xmtfifo_sz_get(wlc->hw, fid, &xmtfifo_sz))
+ return -1;
+
+ if ((TXFIFO_SIZE_UNIT * (u32) xmtfifo_sz) <= ampdu->ffpld_rsvd)
+ return 1;
+
+ max_pld_size = TXFIFO_SIZE_UNIT * xmtfifo_sz - ampdu->ffpld_rsvd;
+ fifo->accum_txfunfl += new_txunfl;
+
+ /* we need to wait for at least 10 underflows */
+ if (fifo->accum_txfunfl < 10)
+ return 0;
+
+ BCMMSG(wlc->wiphy, "ampdu_count %d tx_underflows %d\n",
+ current_ampdu_cnt, fifo->accum_txfunfl);
+
+ /*
+ compute the current ratio of tx unfl per ampdu.
+ When the current ampdu count becomes too
+ big while the ratio remains small, we reset
+ the current count in order to not
+ introduce too big of a latency in detecting a
+ large amount of tx underflows later.
+ */
+
+ txunfl_ratio = current_ampdu_cnt / fifo->accum_txfunfl;
+
+ if (txunfl_ratio > ampdu->tx_max_funl) {
+ if (current_ampdu_cnt >= FFPLD_MAX_AMPDU_CNT)
+ fifo->accum_txfunfl = 0;
+
+ return 0;
+ }
+ max_mpdu = min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS],
+ AMPDU_NUM_MPDU_LEGACY);
+
+ /* In case max value max_pdu is already lower than
+ the fifo depth, there is nothing more we can do.
+ */
+
+ if (fifo->ampdu_pld_size >= max_mpdu * FFPLD_MPDU_SIZE) {
+ fifo->accum_txfunfl = 0;
+ return 0;
+ }
+
+ if (fifo->ampdu_pld_size < max_pld_size) {
+
+ /* increment by TX_FIFO_PLD_INC bytes */
+ fifo->ampdu_pld_size += FFPLD_PLD_INCR;
+ if (fifo->ampdu_pld_size > max_pld_size)
+ fifo->ampdu_pld_size = max_pld_size;
+
+ /* update scb release size */
+ brcms_c_scb_ampdu_update_config_all(ampdu);
+
+ /*
+ * compute a new dma xfer rate for max_mpdu @ max mcs.
+ * This is the minimum dma rate that can achieve no
+ * underflow condition for the current mpdu size.
+ *
+ * note : we divide/multiply by 100 to avoid integer overflows
+ */
+ fifo->dmaxferrate =
+ (((phy_rate / 100) *
+ (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
+ / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
+
+ BCMMSG(wlc->wiphy, "DMA estimated transfer rate %d; "
+ "pre-load size %d\n",
+ fifo->dmaxferrate, fifo->ampdu_pld_size);
+ } else {
+
+ /* decrease ampdu size */
+ if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] > 1) {
+ if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] == 255)
+ fifo->mcs2ampdu_table[FFPLD_MAX_MCS] =
+ AMPDU_NUM_MPDU_LEGACY - 1;
+ else
+ fifo->mcs2ampdu_table[FFPLD_MAX_MCS] -= 1;
+
+ /* recompute the table */
+ brcms_c_ffpld_calc_mcs2ampdu_table(ampdu, fid);
+
+ /* update scb release size */
+ brcms_c_scb_ampdu_update_config_all(ampdu);
+ }
+ }
+ fifo->accum_txfunfl = 0;
+ return 0;
+}
+
+void
+brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid,
+ u8 ba_wsize, /* negotiated ba window size (in pdu) */
+ uint max_rx_ampdu_bytes) /* from ht_cap in beacon */
+{
+ struct scb_ampdu *scb_ampdu;
+ struct scb_ampdu_tid_ini *ini;
+ struct ampdu_info *ampdu = wlc->ampdu;
+ struct scb *scb = &wlc->pri_scb;
+ scb_ampdu = &scb->scb_ampdu;
+
+ if (!ampdu->ini_enable[tid]) {
+ wiphy_err(ampdu->wlc->wiphy, "%s: Rejecting tid %d\n",
+ __func__, tid);
+ return;
+ }
+
+ ini = &scb_ampdu->ini[tid];
+ ini->tid = tid;
+ ini->scb = scb_ampdu->scb;
+ ini->ba_wsize = ba_wsize;
+ scb_ampdu->max_rx_ampdu_bytes = max_rx_ampdu_bytes;
+}
+
+int
+brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
+ struct sk_buff **pdu, int prec)
+{
+ struct brcms_c_info *wlc;
+ struct sk_buff *p, *pkt[AMPDU_MAX_MPDU];
+ u8 tid, ndelim;
+ int err = 0;
+ u8 preamble_type = BRCMS_GF_PREAMBLE;
+ u8 fbr_preamble_type = BRCMS_GF_PREAMBLE;
+ u8 rts_preamble_type = BRCMS_LONG_PREAMBLE;
+ u8 rts_fbr_preamble_type = BRCMS_LONG_PREAMBLE;
+
+ bool rr = true, fbr = false;
+ uint i, count = 0, fifo, seg_cnt = 0;
+ u16 plen, len, seq = 0, mcl, mch, index, frameid, dma_len = 0;
+ u32 ampdu_len, max_ampdu_bytes = 0;
+ struct d11txh *txh = NULL;
+ u8 *plcp;
+ struct ieee80211_hdr *h;
+ struct scb *scb;
+ struct scb_ampdu *scb_ampdu;
+ struct scb_ampdu_tid_ini *ini;
+ u8 mcs = 0;
+ bool use_rts = false, use_cts = false;
+ u32 rspec = 0, rspec_fallback = 0;
+ u32 rts_rspec = 0, rts_rspec_fallback = 0;
+ u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
+ struct ieee80211_rts *rts;
+ u8 rr_retry_limit;
+ struct brcms_fifo_info *f;
+ bool fbr_iscck;
+ struct ieee80211_tx_info *tx_info;
+ u16 qlen;
+ struct wiphy *wiphy;
+
+ wlc = ampdu->wlc;
+ wiphy = wlc->wiphy;
+ p = *pdu;
+
+ tid = (u8) (p->priority);
+
+ f = ampdu->fifo_tb + prio2fifo[tid];
+
+ scb = &wlc->pri_scb;
+ scb_ampdu = &scb->scb_ampdu;
+ ini = &scb_ampdu->ini[tid];
+
+ /* Let pressure continue to build ... */
+ qlen = pktq_plen(&qi->q, prec);
+ if (ini->tx_in_transit > 0 &&
+ qlen < min(scb_ampdu->max_pdu, ini->ba_wsize))
+ /* Collect multiple MPDU's to be sent in the next AMPDU */
+ return -EBUSY;
+
+ /* at this point we intend to transmit an AMPDU */
+ rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
+ ampdu_len = 0;
+ dma_len = 0;
+ while (p) {
+ struct ieee80211_tx_rate *txrate;
+
+ tx_info = IEEE80211_SKB_CB(p);
+ txrate = tx_info->status.rates;
+
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+ err = brcms_c_prep_pdu(wlc, p, &fifo);
+ } else {
+ wiphy_err(wiphy, "%s: AMPDU flag is off!\n", __func__);
+ *pdu = NULL;
+ err = 0;
+ break;
+ }
+
+ if (err) {
+ if (err == -EBUSY) {
+ wiphy_err(wiphy, "wl%d: sendampdu: "
+ "prep_xdu retry; seq 0x%x\n",
+ wlc->pub->unit, seq);
+ *pdu = p;
+ break;
+ }
+
+ /* error in the packet; reject it */
+ wiphy_err(wiphy, "wl%d: sendampdu: prep_xdu "
+ "rejected; seq 0x%x\n", wlc->pub->unit, seq);
+ *pdu = NULL;
+ break;
+ }
+
+ /* pkt is good to be aggregated */
+ txh = (struct d11txh *) p->data;
+ plcp = (u8 *) (txh + 1);
+ h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN);
+ seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT;
+ index = TX_SEQ_TO_INDEX(seq);
+
+ /* check mcl fields and test whether it can be agg'd */
+ mcl = le16_to_cpu(txh->MacTxControlLow);
+ mcl &= ~TXC_AMPDU_MASK;
+ fbr_iscck = !(le16_to_cpu(txh->XtraFrameTypes) & 0x3);
+ txh->PreloadSize = 0; /* always default to 0 */
+
+ /* Handle retry limits */
+ if (txrate[0].count <= rr_retry_limit) {
+ txrate[0].count++;
+ rr = true;
+ fbr = false;
+ } else {
+ fbr = true;
+ rr = false;
+ txrate[1].count++;
+ }
+
+ /* extract the length info */
+ len = fbr_iscck ? BRCMS_GET_CCK_PLCP_LEN(txh->FragPLCPFallback)
+ : BRCMS_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
+
+ /* retrieve null delimiter count */
+ ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
+ seg_cnt += 1;
+
+ BCMMSG(wlc->wiphy, "wl%d: mpdu %d plcp_len %d\n",
+ wlc->pub->unit, count, len);
+
+ /*
+ * aggregateable mpdu. For ucode/hw agg,
+ * test whether need to break or change the epoch
+ */
+ if (count == 0) {
+ mcl |= (TXC_AMPDU_FIRST << TXC_AMPDU_SHIFT);
+ /* refill the bits since might be a retx mpdu */
+ mcl |= TXC_STARTMSDU;
+ rts = (struct ieee80211_rts *)&txh->rts_frame;
+
+ if (ieee80211_is_rts(rts->frame_control)) {
+ mcl |= TXC_SENDRTS;
+ use_rts = true;
+ }
+ if (ieee80211_is_cts(rts->frame_control)) {
+ mcl |= TXC_SENDCTS;
+ use_cts = true;
+ }
+ } else {
+ mcl |= (TXC_AMPDU_MIDDLE << TXC_AMPDU_SHIFT);
+ mcl &= ~(TXC_STARTMSDU | TXC_SENDRTS | TXC_SENDCTS);
+ }
+
+ len = roundup(len, 4);
+ ampdu_len += (len + (ndelim + 1) * AMPDU_DELIMITER_LEN);
+
+ dma_len += (u16) brcmu_pkttotlen(p);
+
+ BCMMSG(wlc->wiphy, "wl%d: ampdu_len %d"
+ " seg_cnt %d null delim %d\n",
+ wlc->pub->unit, ampdu_len, seg_cnt, ndelim);
+
+ txh->MacTxControlLow = cpu_to_le16(mcl);
+
+ /* this packet is added */
+ pkt[count++] = p;
+
+ /* patch the first MPDU */
+ if (count == 1) {
+ u8 plcp0, plcp3, is40, sgi;
+ struct ieee80211_sta *sta;
+
+ sta = tx_info->control.sta;
+
+ if (rr) {
+ plcp0 = plcp[0];
+ plcp3 = plcp[3];
+ } else {
+ plcp0 = txh->FragPLCPFallback[0];
+ plcp3 = txh->FragPLCPFallback[3];
+
+ }
+ is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0;
+ sgi = plcp3_issgi(plcp3) ? 1 : 0;
+ mcs = plcp0 & ~MIMO_PLCP_40MHZ;
+ max_ampdu_bytes =
+ min(scb_ampdu->max_rx_ampdu_bytes,
+ ampdu->max_txlen[mcs][is40][sgi]);
+
+ if (is40)
+ mimo_ctlchbw =
+ CHSPEC_SB_UPPER(wlc_phy_chanspec_get(
+ wlc->band->pi))
+ ? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ;
+
+ /* rebuild the rspec and rspec_fallback */
+ rspec = RSPEC_MIMORATE;
+ rspec |= plcp[0] & ~MIMO_PLCP_40MHZ;
+ if (plcp[0] & MIMO_PLCP_40MHZ)
+ rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT);
+
+ if (fbr_iscck) /* CCK */
+ rspec_fallback = cck_rspec(cck_phy2mac_rate
+ (txh->FragPLCPFallback[0]));
+ else { /* MIMO */
+ rspec_fallback = RSPEC_MIMORATE;
+ rspec_fallback |=
+ txh->FragPLCPFallback[0] & ~MIMO_PLCP_40MHZ;
+ if (txh->FragPLCPFallback[0] & MIMO_PLCP_40MHZ)
+ rspec_fallback |=
+ (PHY_TXC1_BW_40MHZ <<
+ RSPEC_BW_SHIFT);
+ }
+
+ if (use_rts || use_cts) {
+ rts_rspec =
+ brcms_c_rspec_to_rts_rspec(wlc,
+ rspec, false, mimo_ctlchbw);
+ rts_rspec_fallback =
+ brcms_c_rspec_to_rts_rspec(wlc,
+ rspec_fallback, false, mimo_ctlchbw);
+ }
+ }
+
+ /* if (first mpdu for host agg) */
+ /* test whether to add more */
+ if ((mcs_2_rate(mcs, true, false) >= f->dmaxferrate) &&
+ (count == f->mcs2ampdu_table[mcs])) {
+ BCMMSG(wlc->wiphy, "wl%d: PR 37644: stopping"
+ " ampdu at %d for mcs %d\n",
+ wlc->pub->unit, count, mcs);
+ break;
+ }
+
+ if (count == scb_ampdu->max_pdu)
+ break;
+
+ /*
+ * check to see if the next pkt is
+ * a candidate for aggregation
+ */
+ p = pktq_ppeek(&qi->q, prec);
+ /* tx_info must be checked with current p */
+ tx_info = IEEE80211_SKB_CB(p);
+
+ if (p) {
+ if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
+ ((u8) (p->priority) == tid)) {
+
+ plen = brcmu_pkttotlen(p) +
+ AMPDU_MAX_MPDU_OVERHEAD;
+ plen = max(scb_ampdu->min_len, plen);
+
+ if ((plen + ampdu_len) > max_ampdu_bytes) {
+ p = NULL;
+ continue;
+ }
+
+ /*
+ * check if there are enough
+ * descriptors available
+ */
+ if (*wlc->core->txavail[fifo] <= seg_cnt + 1) {
+ wiphy_err(wiphy, "%s: No fifo space "
+ "!!\n", __func__);
+ p = NULL;
+ continue;
+ }
+ p = brcmu_pktq_pdeq(&qi->q, prec);
+ } else {
+ p = NULL;
+ }
+ }
+ } /* end while(p) */
+
+ ini->tx_in_transit += count;
+
+ if (count) {
+ /* patch up the last txh */
+ txh = (struct d11txh *) pkt[count - 1]->data;
+ mcl = le16_to_cpu(txh->MacTxControlLow);
+ mcl &= ~TXC_AMPDU_MASK;
+ mcl |= (TXC_AMPDU_LAST << TXC_AMPDU_SHIFT);
+ txh->MacTxControlLow = cpu_to_le16(mcl);
+
+ /* remove the null delimiter after last mpdu */
+ ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
+ txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] = 0;
+ ampdu_len -= ndelim * AMPDU_DELIMITER_LEN;
+
+ /* remove the pad len from last mpdu */
+ fbr_iscck = ((le16_to_cpu(txh->XtraFrameTypes) & 0x3) == 0);
+ len = fbr_iscck ? BRCMS_GET_CCK_PLCP_LEN(txh->FragPLCPFallback)
+ : BRCMS_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
+ ampdu_len -= roundup(len, 4) - len;
+
+ /* patch up the first txh & plcp */
+ txh = (struct d11txh *) pkt[0]->data;
+ plcp = (u8 *) (txh + 1);
+
+ BRCMS_SET_MIMO_PLCP_LEN(plcp, ampdu_len);
+ /* mark plcp to indicate ampdu */
+ BRCMS_SET_MIMO_PLCP_AMPDU(plcp);
+
+ /* reset the mixed mode header durations */
+ if (txh->MModeLen) {
+ u16 mmodelen =
+ brcms_c_calc_lsig_len(wlc, rspec, ampdu_len);
+ txh->MModeLen = cpu_to_le16(mmodelen);
+ preamble_type = BRCMS_MM_PREAMBLE;
+ }
+ if (txh->MModeFbrLen) {
+ u16 mmfbrlen =
+ brcms_c_calc_lsig_len(wlc, rspec_fallback,
+ ampdu_len);
+ txh->MModeFbrLen = cpu_to_le16(mmfbrlen);
+ fbr_preamble_type = BRCMS_MM_PREAMBLE;
+ }
+
+ /* set the preload length */
+ if (mcs_2_rate(mcs, true, false) >= f->dmaxferrate) {
+ dma_len = min(dma_len, f->ampdu_pld_size);
+ txh->PreloadSize = cpu_to_le16(dma_len);
+ } else
+ txh->PreloadSize = 0;
+
+ mch = le16_to_cpu(txh->MacTxControlHigh);
+
+ /* update RTS dur fields */
+ if (use_rts || use_cts) {
+ u16 durid;
+ rts = (struct ieee80211_rts *)&txh->rts_frame;
+ if ((mch & TXC_PREAMBLE_RTS_MAIN_SHORT) ==
+ TXC_PREAMBLE_RTS_MAIN_SHORT)
+ rts_preamble_type = BRCMS_SHORT_PREAMBLE;
+
+ if ((mch & TXC_PREAMBLE_RTS_FB_SHORT) ==
+ TXC_PREAMBLE_RTS_FB_SHORT)
+ rts_fbr_preamble_type = BRCMS_SHORT_PREAMBLE;
+
+ durid =
+ brcms_c_compute_rtscts_dur(wlc, use_cts, rts_rspec,
+ rspec, rts_preamble_type,
+ preamble_type, ampdu_len,
+ true);
+ rts->duration = cpu_to_le16(durid);
+ durid = brcms_c_compute_rtscts_dur(wlc, use_cts,
+ rts_rspec_fallback,
+ rspec_fallback,
+ rts_fbr_preamble_type,
+ fbr_preamble_type,
+ ampdu_len, true);
+ txh->RTSDurFallback = cpu_to_le16(durid);
+ /* set TxFesTimeNormal */
+ txh->TxFesTimeNormal = rts->duration;
+ /* set fallback rate version of TxFesTimeNormal */
+ txh->TxFesTimeFallback = txh->RTSDurFallback;
+ }
+
+ /* set flag and plcp for fallback rate */
+ if (fbr) {
+ mch |= TXC_AMPDU_FBR;
+ txh->MacTxControlHigh = cpu_to_le16(mch);
+ BRCMS_SET_MIMO_PLCP_AMPDU(plcp);
+ BRCMS_SET_MIMO_PLCP_AMPDU(txh->FragPLCPFallback);
+ }
+
+ BCMMSG(wlc->wiphy, "wl%d: count %d ampdu_len %d\n",
+ wlc->pub->unit, count, ampdu_len);
+
+ /* inform rate_sel if it this is a rate probe pkt */
+ frameid = le16_to_cpu(txh->TxFrameID);
+ if (frameid & TXFID_RATE_PROBE_MASK)
+ wiphy_err(wiphy, "%s: XXX what to do with "
+ "TXFID_RATE_PROBE_MASK!?\n", __func__);
+
+ for (i = 0; i < count; i++)
+ brcms_c_txfifo(wlc, fifo, pkt[i], i == (count - 1),
+ ampdu->txpkt_weight);
+
+ }
+ /* endif (count) */
+ return err;
+}
+
+static void
+brcms_c_ampdu_rate_status(struct brcms_c_info *wlc,
+ struct ieee80211_tx_info *tx_info,
+ struct tx_status *txs, u8 mcs)
+{
+ struct ieee80211_tx_rate *txrate = tx_info->status.rates;
+ int i;
+
+ /* clear the rest of the rates */
+ for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) {
+ txrate[i].idx = -1;
+ txrate[i].count = 0;
+ }
+}
+
+static void
+brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
+ struct sk_buff *p, struct tx_status *txs,
+ u32 s1, u32 s2)
+{
+ struct scb_ampdu *scb_ampdu;
+ struct brcms_c_info *wlc = ampdu->wlc;
+ struct scb_ampdu_tid_ini *ini;
+ u8 bitmap[8], queue, tid;
+ struct d11txh *txh;
+ u8 *plcp;
+ struct ieee80211_hdr *h;
+ u16 seq, start_seq = 0, bindex, index, mcl;
+ u8 mcs = 0;
+ bool ba_recd = false, ack_recd = false;
+ u8 suc_mpdu = 0, tot_mpdu = 0;
+ uint supr_status;
+ bool update_rate = true, retry = true, tx_error = false;
+ u16 mimoantsel = 0;
+ u8 antselid = 0;
+ u8 retry_limit, rr_retry_limit;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(p);
+ struct wiphy *wiphy = wlc->wiphy;
+
+#ifdef BCMDBG
+ u8 hole[AMPDU_MAX_MPDU];
+ memset(hole, 0, sizeof(hole));
+#endif
+
+ scb_ampdu = &scb->scb_ampdu;
+ tid = (u8) (p->priority);
+
+ ini = &scb_ampdu->ini[tid];
+ retry_limit = ampdu->retry_limit_tid[tid];
+ rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
+ memset(bitmap, 0, sizeof(bitmap));
+ queue = txs->frameid & TXFID_QUEUE_MASK;
+ supr_status = txs->status & TX_STATUS_SUPR_MASK;
+
+ if (txs->status & TX_STATUS_ACK_RCV) {
+ if (TX_STATUS_SUPR_UF == supr_status)
+ update_rate = false;
+
+ WARN_ON(!(txs->status & TX_STATUS_INTERMEDIATE));
+ start_seq = txs->sequence >> SEQNUM_SHIFT;
+ bitmap[0] = (txs->status & TX_STATUS_BA_BMAP03_MASK) >>
+ TX_STATUS_BA_BMAP03_SHIFT;
+
+ WARN_ON(s1 & TX_STATUS_INTERMEDIATE);
+ WARN_ON(!(s1 & TX_STATUS_AMPDU));
+
+ bitmap[0] |=
+ (s1 & TX_STATUS_BA_BMAP47_MASK) <<
+ TX_STATUS_BA_BMAP47_SHIFT;
+ bitmap[1] = (s1 >> 8) & 0xff;
+ bitmap[2] = (s1 >> 16) & 0xff;
+ bitmap[3] = (s1 >> 24) & 0xff;
+
+ bitmap[4] = s2 & 0xff;
+ bitmap[5] = (s2 >> 8) & 0xff;
+ bitmap[6] = (s2 >> 16) & 0xff;
+ bitmap[7] = (s2 >> 24) & 0xff;
+
+ ba_recd = true;
+ } else {
+ 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",
+ __func__, CHSPEC_CHANNEL(
+ wlc->default_bss->chanspec));
+ } else {
+ if (supr_status != TX_STATUS_SUPR_FRAG)
+ wiphy_err(wiphy, "%s:"
+ "supr_status 0x%x\n",
+ __func__, supr_status);
+ }
+ /* no need to retry for badch; will fail again */
+ if (supr_status == TX_STATUS_SUPR_BADCH ||
+ supr_status == TX_STATUS_SUPR_EXPTIME) {
+ retry = false;
+ } else if (supr_status == TX_STATUS_SUPR_EXPTIME) {
+ /* TX underflow:
+ * try tuning pre-loading or ampdu size
+ */
+ } else if (supr_status == TX_STATUS_SUPR_FRAG) {
+ /*
+ * if there were underflows, but pre-loading
+ * is not active, notify rate adaptation.
+ */
+ if (brcms_c_ffpld_check_txfunfl(wlc,
+ prio2fifo[tid]) > 0)
+ tx_error = true;
+ }
+ } else if (txs->phyerr) {
+ update_rate = false;
+ wiphy_err(wiphy, "wl%d: ampdu tx phy "
+ "error (0x%x)\n", wlc->pub->unit,
+ txs->phyerr);
+
+ if (brcm_msg_level & LOG_ERROR_VAL) {
+ brcmu_prpkt("txpkt (AMPDU)", p);
+ brcms_c_print_txdesc((struct d11txh *) p->data);
+ }
+ brcms_c_print_txstatus(txs);
+ }
+ }
+
+ /* loop through all pkts and retry if not acked */
+ while (p) {
+ tx_info = IEEE80211_SKB_CB(p);
+ txh = (struct d11txh *) p->data;
+ mcl = le16_to_cpu(txh->MacTxControlLow);
+ plcp = (u8 *) (txh + 1);
+ h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN);
+ seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT;
+
+ if (tot_mpdu == 0) {
+ mcs = plcp[0] & MIMO_PLCP_MCS_MASK;
+ mimoantsel = le16_to_cpu(txh->ABI_MimoAntSel);
+ }
+
+ index = TX_SEQ_TO_INDEX(seq);
+ 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);
+ /* if acked then clear bit and free packet */
+ if ((bindex < AMPDU_TX_BA_MAX_WSIZE)
+ && isset(bitmap, bindex)) {
+ ini->tx_in_transit--;
+ ini->txretry[index] = 0;
+
+ /*
+ * ampdu_ack_len:
+ * number of acked aggregated frames
+ */
+ /* ampdu_len: number of aggregated frames */
+ brcms_c_ampdu_rate_status(wlc, tx_info, txs,
+ mcs);
+ tx_info->flags |= IEEE80211_TX_STAT_ACK;
+ tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
+ tx_info->status.ampdu_ack_len =
+ tx_info->status.ampdu_len = 1;
+
+ skb_pull(p, D11_PHY_HDR_LEN);
+ skb_pull(p, D11_TXH_LEN);
+
+ ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
+ p);
+ ack_recd = true;
+ suc_mpdu++;
+ }
+ }
+ /* either retransmit or send bar if ack not recd */
+ if (!ack_recd) {
+ struct ieee80211_tx_rate *txrate =
+ tx_info->status.rates;
+ if (retry && (txrate[0].count < (int)retry_limit)) {
+ ini->txretry[index]++;
+ ini->tx_in_transit--;
+ /*
+ * Use high prededence for retransmit to
+ * give some punch
+ */
+ /* brcms_c_txq_enq(wlc, scb, p,
+ * BRCMS_PRIO_TO_PREC(tid)); */
+ brcms_c_txq_enq(wlc, scb, p,
+ BRCMS_PRIO_TO_HI_PREC(tid));
+ } else {
+ /* Retry timeout */
+ ini->tx_in_transit--;
+ ieee80211_tx_info_clear_status(tx_info);
+ tx_info->status.ampdu_ack_len = 0;
+ tx_info->status.ampdu_len = 1;
+ tx_info->flags |=
+ IEEE80211_TX_STAT_AMPDU_NO_BACK;
+ skb_pull(p, D11_PHY_HDR_LEN);
+ skb_pull(p, D11_TXH_LEN);
+ wiphy_err(wiphy, "%s: BA Timeout, seq %d, in_"
+ "transit %d\n", "AMPDU status", seq,
+ ini->tx_in_transit);
+ ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
+ p);
+ }
+ }
+ tot_mpdu++;
+
+ /* break out if last packet of ampdu */
+ if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) ==
+ TXC_AMPDU_LAST)
+ break;
+
+ p = dma_getnexttxp(wlc->hw->di[queue], DMA_RANGE_TRANSMITTED);
+ }
+ brcms_c_send_q(wlc);
+
+ /* update rate state */
+ antselid = brcms_c_antsel_antsel2id(wlc->asi, mimoantsel);
+
+ brcms_c_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
+}
+
+void
+brcms_c_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb,
+ struct sk_buff *p, struct tx_status *txs)
+{
+ struct scb_ampdu *scb_ampdu;
+ struct brcms_c_info *wlc = ampdu->wlc;
+ struct scb_ampdu_tid_ini *ini;
+ u32 s1 = 0, s2 = 0;
+ struct ieee80211_tx_info *tx_info;
+
+ tx_info = IEEE80211_SKB_CB(p);
+
+ /* BMAC_NOTE: For the split driver, second level txstatus comes later
+ * So if the ACK was received then wait for the second level else just
+ * call the first one
+ */
+ if (txs->status & TX_STATUS_ACK_RCV) {
+ u8 status_delay = 0;
+
+ /* wait till the next 8 bytes of txstatus is available */
+ while (((s1 = R_REG(&wlc->regs->frmtxstatus)) & TXS_V) == 0) {
+ udelay(1);
+ status_delay++;
+ if (status_delay > 10)
+ return; /* error condition */
+ }
+
+ s2 = R_REG(&wlc->regs->frmtxstatus2);
+ }
+
+ if (scb) {
+ scb_ampdu = &scb->scb_ampdu;
+ ini = &scb_ampdu->ini[p->priority];
+ brcms_c_ampdu_dotxstatus_complete(ampdu, scb, p, txs, s1, s2);
+ } else {
+ /* loop through all pkts and free */
+ u8 queue = txs->frameid & TXFID_QUEUE_MASK;
+ struct d11txh *txh;
+ u16 mcl;
+ while (p) {
+ tx_info = IEEE80211_SKB_CB(p);
+ txh = (struct d11txh *) p->data;
+ mcl = le16_to_cpu(txh->MacTxControlLow);
+ brcmu_pkt_buf_free_skb(p);
+ /* break out if last packet of ampdu */
+ if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) ==
+ TXC_AMPDU_LAST)
+ break;
+ p = dma_getnexttxp(wlc->hw->di[queue],
+ DMA_RANGE_TRANSMITTED);
+ }
+ brcms_c_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
+ }
+}
+
+void brcms_c_ampdu_macaddr_upd(struct brcms_c_info *wlc)
+{
+ char template[T_RAM_ACCESS_SZ * 2];
+
+ /* driver needs to write the ta in the template; ta is at offset 16 */
+ memset(template, 0, sizeof(template));
+ memcpy(template, wlc->pub->cur_etheraddr, ETH_ALEN);
+ brcms_b_write_template_ram(wlc->hw, (T_BA_TPL_BASE + 16),
+ (T_RAM_ACCESS_SZ * 2),
+ template);
+}
+
+bool brcms_c_aggregatable(struct brcms_c_info *wlc, u8 tid)
+{
+ return wlc->ampdu->ini_enable[tid];
+}
+
+void brcms_c_ampdu_shm_upd(struct ampdu_info *ampdu)
+{
+ struct brcms_c_info *wlc = ampdu->wlc;
+
+ /*
+ * Extend ucode internal watchdog timer to
+ * match larger received frames
+ */
+ if ((ampdu->rx_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) ==
+ IEEE80211_HT_MAX_AMPDU_64K) {
+ brcms_b_write_shm(wlc->hw, M_MIMO_MAXSYM, MIMO_MAXSYM_MAX);
+ brcms_b_write_shm(wlc->hw, M_WATCHDOG_8TU, WATCHDOG_8TU_MAX);
+ } else {
+ brcms_b_write_shm(wlc->hw, M_MIMO_MAXSYM, MIMO_MAXSYM_DEF);
+ brcms_b_write_shm(wlc->hw, M_WATCHDOG_8TU, WATCHDOG_8TU_DEF);
+ }
+}
+
+/*
+ * callback function that helps flushing ampdu packets from a priority queue
+ */
+static bool cb_del_ampdu_pkt(struct sk_buff *mpdu, void *arg_a)
+{
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(mpdu);
+ struct cb_del_ampdu_pars *ampdu_pars =
+ (struct cb_del_ampdu_pars *)arg_a;
+ bool rc;
+
+ rc = tx_info->flags & IEEE80211_TX_CTL_AMPDU ? true : false;
+ rc = rc && (tx_info->control.sta == NULL || ampdu_pars->sta == NULL ||
+ tx_info->control.sta == ampdu_pars->sta);
+ rc = rc && ((u8)(mpdu->priority) == ampdu_pars->tid);
+ return rc;
+}
+
+/*
+ * callback function that helps invalidating ampdu packets in a DMA queue
+ */
+static void dma_cb_fn_ampdu(void *txi, void *arg_a)
+{
+ struct ieee80211_sta *sta = arg_a;
+ struct ieee80211_tx_info *tx_info = (struct ieee80211_tx_info *)txi;
+
+ if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
+ (tx_info->control.sta == sta || sta == NULL))
+ tx_info->control.sta = NULL;
+}
+
+/*
+ * When a remote party is no longer available for ampdu communication, any
+ * pending tx ampdu packets in the driver have to be flushed.
+ */
+void brcms_c_ampdu_flush(struct brcms_c_info *wlc,
+ struct ieee80211_sta *sta, u16 tid)
+{
+ struct brcms_txq_info *qi = wlc->pkt_queue;
+ struct pktq *pq = &qi->q;
+ int prec;
+ struct cb_del_ampdu_pars ampdu_pars;
+
+ ampdu_pars.sta = sta;
+ ampdu_pars.tid = tid;
+ for (prec = 0; prec < pq->num_prec; prec++)
+ brcmu_pktq_pflush(pq, prec, true, cb_del_ampdu_pkt,
+ (void *)&ampdu_pars);
+ brcms_c_inval_dma_pkts(wlc->hw, sta, dma_cb_fn_ampdu);
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.h b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.h
new file mode 100644
index 000000000000..421f4ba7c63c
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_AMPDU_H_
+#define _BRCM_AMPDU_H_
+
+extern struct ampdu_info *brcms_c_ampdu_attach(struct brcms_c_info *wlc);
+extern void brcms_c_ampdu_detach(struct ampdu_info *ampdu);
+extern int brcms_c_sendampdu(struct ampdu_info *ampdu,
+ struct brcms_txq_info *qi,
+ struct sk_buff **aggp, int prec);
+extern void brcms_c_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb,
+ struct sk_buff *p, struct tx_status *txs);
+extern void brcms_c_ampdu_macaddr_upd(struct brcms_c_info *wlc);
+extern void brcms_c_ampdu_shm_upd(struct ampdu_info *ampdu);
+
+#endif /* _BRCM_AMPDU_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/antsel.c b/drivers/net/wireless/brcm80211/brcmsmac/antsel.c
new file mode 100644
index 000000000000..a47ce25cb9a2
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/antsel.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2010 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/slab.h>
+#include <net/mac80211.h>
+
+#include "types.h"
+#include "main.h"
+#include "phy_shim.h"
+#include "antsel.h"
+
+#define ANT_SELCFG_AUTO 0x80 /* bit indicates antenna sel AUTO */
+#define ANT_SELCFG_MASK 0x33 /* antenna configuration mask */
+#define ANT_SELCFG_TX_UNICAST 0 /* unicast tx antenna configuration */
+#define ANT_SELCFG_RX_UNICAST 1 /* unicast rx antenna configuration */
+#define ANT_SELCFG_TX_DEF 2 /* default tx antenna configuration */
+#define ANT_SELCFG_RX_DEF 3 /* default rx antenna configuration */
+
+/* useful macros */
+#define BRCMS_ANTSEL_11N_0(ant) ((((ant) & ANT_SELCFG_MASK) >> 4) & 0xf)
+#define BRCMS_ANTSEL_11N_1(ant) (((ant) & ANT_SELCFG_MASK) & 0xf)
+#define BRCMS_ANTIDX_11N(ant) (((BRCMS_ANTSEL_11N_0(ant)) << 2) +\
+ (BRCMS_ANTSEL_11N_1(ant)))
+#define BRCMS_ANT_ISAUTO_11N(ant) (((ant) & ANT_SELCFG_AUTO) == ANT_SELCFG_AUTO)
+#define BRCMS_ANTSEL_11N(ant) ((ant) & ANT_SELCFG_MASK)
+
+/* antenna switch */
+/* defines for no boardlevel antenna diversity */
+#define ANT_SELCFG_DEF_2x2 0x01 /* default antenna configuration */
+
+/* 2x3 antdiv defines and tables for GPIO communication */
+#define ANT_SELCFG_NUM_2x3 3
+#define ANT_SELCFG_DEF_2x3 0x01 /* default antenna configuration */
+
+/* 2x4 antdiv rev4 defines and tables for GPIO communication */
+#define ANT_SELCFG_NUM_2x4 4
+#define ANT_SELCFG_DEF_2x4 0x02 /* default antenna configuration */
+
+static const u16 mimo_2x4_div_antselpat_tbl[] = {
+ 0, 0, 0x9, 0xa, /* ant0: 0 ant1: 2,3 */
+ 0, 0, 0x5, 0x6, /* ant0: 1 ant1: 2,3 */
+ 0, 0, 0, 0, /* n.a. */
+ 0, 0, 0, 0 /* n.a. */
+};
+
+static const u8 mimo_2x4_div_antselid_tbl[16] = {
+ 0, 0, 0, 0, 0, 2, 3, 0,
+ 0, 0, 1, 0, 0, 0, 0, 0 /* pat to antselid */
+};
+
+static const u16 mimo_2x3_div_antselpat_tbl[] = {
+ 16, 0, 1, 16, /* ant0: 0 ant1: 1,2 */
+ 16, 16, 16, 16, /* n.a. */
+ 16, 2, 16, 16, /* ant0: 2 ant1: 1 */
+ 16, 16, 16, 16 /* n.a. */
+};
+
+static const u8 mimo_2x3_div_antselid_tbl[16] = {
+ 0, 1, 2, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 /* pat to antselid */
+};
+
+/* boardlevel antenna selection: init antenna selection structure */
+static void
+brcms_c_antsel_init_cfg(struct antsel_info *asi, struct brcms_antselcfg *antsel,
+ bool auto_sel)
+{
+ if (asi->antsel_type == ANTSEL_2x3) {
+ u8 antcfg_def = ANT_SELCFG_DEF_2x3 |
+ ((asi->antsel_avail && auto_sel) ? ANT_SELCFG_AUTO : 0);
+ antsel->ant_config[ANT_SELCFG_TX_DEF] = antcfg_def;
+ antsel->ant_config[ANT_SELCFG_TX_UNICAST] = antcfg_def;
+ antsel->ant_config[ANT_SELCFG_RX_DEF] = antcfg_def;
+ antsel->ant_config[ANT_SELCFG_RX_UNICAST] = antcfg_def;
+ antsel->num_antcfg = ANT_SELCFG_NUM_2x3;
+
+ } else if (asi->antsel_type == ANTSEL_2x4) {
+
+ antsel->ant_config[ANT_SELCFG_TX_DEF] = ANT_SELCFG_DEF_2x4;
+ antsel->ant_config[ANT_SELCFG_TX_UNICAST] = ANT_SELCFG_DEF_2x4;
+ antsel->ant_config[ANT_SELCFG_RX_DEF] = ANT_SELCFG_DEF_2x4;
+ antsel->ant_config[ANT_SELCFG_RX_UNICAST] = ANT_SELCFG_DEF_2x4;
+ antsel->num_antcfg = ANT_SELCFG_NUM_2x4;
+
+ } else { /* no antenna selection available */
+
+ antsel->ant_config[ANT_SELCFG_TX_DEF] = ANT_SELCFG_DEF_2x2;
+ antsel->ant_config[ANT_SELCFG_TX_UNICAST] = ANT_SELCFG_DEF_2x2;
+ antsel->ant_config[ANT_SELCFG_RX_DEF] = ANT_SELCFG_DEF_2x2;
+ antsel->ant_config[ANT_SELCFG_RX_UNICAST] = ANT_SELCFG_DEF_2x2;
+ antsel->num_antcfg = 0;
+ }
+}
+
+struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc)
+{
+ struct antsel_info *asi;
+ struct si_pub *sih = wlc->hw->sih;
+
+ asi = kzalloc(sizeof(struct antsel_info), GFP_ATOMIC);
+ if (!asi)
+ return NULL;
+
+ asi->wlc = wlc;
+ asi->pub = wlc->pub;
+ asi->antsel_type = ANTSEL_NA;
+ asi->antsel_avail = false;
+ asi->antsel_antswitch = (u8) getintvar(sih, BRCMS_SROM_ANTSWITCH);
+
+ if ((asi->pub->sromrev >= 4) && (asi->antsel_antswitch != 0)) {
+ switch (asi->antsel_antswitch) {
+ case ANTSWITCH_TYPE_1:
+ case ANTSWITCH_TYPE_2:
+ case ANTSWITCH_TYPE_3:
+ /* 4321/2 board with 2x3 switch logic */
+ asi->antsel_type = ANTSEL_2x3;
+ /* Antenna selection availability */
+ if (((u16) getintvar(sih, BRCMS_SROM_AA2G) == 7) ||
+ ((u16) getintvar(sih, BRCMS_SROM_AA5G) == 7)) {
+ asi->antsel_avail = true;
+ } else if (
+ (u16) getintvar(sih, BRCMS_SROM_AA2G) == 3 ||
+ (u16) getintvar(sih, BRCMS_SROM_AA5G) == 3) {
+ asi->antsel_avail = false;
+ } else {
+ asi->antsel_avail = false;
+ wiphy_err(wlc->wiphy, "antsel_attach: 2o3 "
+ "board cfg invalid\n");
+ }
+
+ break;
+ default:
+ break;
+ }
+ } else if ((asi->pub->sromrev == 4) &&
+ ((u16) getintvar(sih, BRCMS_SROM_AA2G) == 7) &&
+ ((u16) getintvar(sih, BRCMS_SROM_AA5G) == 0)) {
+ /* hack to match old 4321CB2 cards with 2of3 antenna switch */
+ asi->antsel_type = ANTSEL_2x3;
+ asi->antsel_avail = true;
+ } else if (asi->pub->boardflags2 & BFL2_2X4_DIV) {
+ asi->antsel_type = ANTSEL_2x4;
+ asi->antsel_avail = true;
+ }
+
+ /* Set the antenna selection type for the low driver */
+ brcms_b_antsel_type_set(wlc->hw, asi->antsel_type);
+
+ /* Init (auto/manual) antenna selection */
+ brcms_c_antsel_init_cfg(asi, &asi->antcfg_11n, true);
+ brcms_c_antsel_init_cfg(asi, &asi->antcfg_cur, true);
+
+ return asi;
+}
+
+void brcms_c_antsel_detach(struct antsel_info *asi)
+{
+ kfree(asi);
+}
+
+/*
+ * boardlevel antenna selection:
+ * convert ant_cfg to mimo_antsel (ucode interface)
+ */
+static u16 brcms_c_antsel_antcfg2antsel(struct antsel_info *asi, u8 ant_cfg)
+{
+ u8 idx = BRCMS_ANTIDX_11N(BRCMS_ANTSEL_11N(ant_cfg));
+ u16 mimo_antsel = 0;
+
+ if (asi->antsel_type == ANTSEL_2x4) {
+ /* 2x4 antenna diversity board, 4 cfgs: 0-2 0-3 1-2 1-3 */
+ mimo_antsel = (mimo_2x4_div_antselpat_tbl[idx] & 0xf);
+ return mimo_antsel;
+
+ } else if (asi->antsel_type == ANTSEL_2x3) {
+ /* 2x3 antenna selection, 3 cfgs: 0-1 0-2 2-1 */
+ mimo_antsel = (mimo_2x3_div_antselpat_tbl[idx] & 0xf);
+ return mimo_antsel;
+ }
+
+ return mimo_antsel;
+}
+
+/* boardlevel antenna selection: ucode interface control */
+static int brcms_c_antsel_cfgupd(struct antsel_info *asi,
+ struct brcms_antselcfg *antsel)
+{
+ struct brcms_c_info *wlc = asi->wlc;
+ u8 ant_cfg;
+ u16 mimo_antsel;
+
+ /* 1) Update TX antconfig for all frames that are not unicast data
+ * (aka default TX)
+ */
+ ant_cfg = antsel->ant_config[ANT_SELCFG_TX_DEF];
+ mimo_antsel = brcms_c_antsel_antcfg2antsel(asi, ant_cfg);
+ brcms_b_write_shm(wlc->hw, M_MIMO_ANTSEL_TXDFLT, mimo_antsel);
+ /*
+ * Update driver stats for currently selected
+ * default tx/rx antenna config
+ */
+ asi->antcfg_cur.ant_config[ANT_SELCFG_TX_DEF] = ant_cfg;
+
+ /* 2) Update RX antconfig for all frames that are not unicast data
+ * (aka default RX)
+ */
+ ant_cfg = antsel->ant_config[ANT_SELCFG_RX_DEF];
+ mimo_antsel = brcms_c_antsel_antcfg2antsel(asi, ant_cfg);
+ brcms_b_write_shm(wlc->hw, M_MIMO_ANTSEL_RXDFLT, mimo_antsel);
+ /*
+ * Update driver stats for currently selected
+ * default tx/rx antenna config
+ */
+ asi->antcfg_cur.ant_config[ANT_SELCFG_RX_DEF] = ant_cfg;
+
+ return 0;
+}
+
+void brcms_c_antsel_init(struct antsel_info *asi)
+{
+ if ((asi->antsel_type == ANTSEL_2x3) ||
+ (asi->antsel_type == ANTSEL_2x4))
+ brcms_c_antsel_cfgupd(asi, &asi->antcfg_11n);
+}
+
+/* boardlevel antenna selection: convert id to ant_cfg */
+static u8 brcms_c_antsel_id2antcfg(struct antsel_info *asi, u8 id)
+{
+ u8 antcfg = ANT_SELCFG_DEF_2x2;
+
+ if (asi->antsel_type == ANTSEL_2x4) {
+ /* 2x4 antenna diversity board, 4 cfgs: 0-2 0-3 1-2 1-3 */
+ antcfg = (((id & 0x2) << 3) | ((id & 0x1) + 2));
+ return antcfg;
+
+ } else if (asi->antsel_type == ANTSEL_2x3) {
+ /* 2x3 antenna selection, 3 cfgs: 0-1 0-2 2-1 */
+ antcfg = (((id & 0x02) << 4) | ((id & 0x1) + 1));
+ return antcfg;
+ }
+
+ return antcfg;
+}
+
+void
+brcms_c_antsel_antcfg_get(struct antsel_info *asi, bool usedef, bool sel,
+ u8 antselid, u8 fbantselid, u8 *antcfg,
+ u8 *fbantcfg)
+{
+ u8 ant;
+
+ /* if use default, assign it and return */
+ if (usedef) {
+ *antcfg = asi->antcfg_11n.ant_config[ANT_SELCFG_TX_DEF];
+ *fbantcfg = *antcfg;
+ return;
+ }
+
+ if (!sel) {
+ *antcfg = asi->antcfg_11n.ant_config[ANT_SELCFG_TX_UNICAST];
+ *fbantcfg = *antcfg;
+
+ } else {
+ ant = asi->antcfg_11n.ant_config[ANT_SELCFG_TX_UNICAST];
+ if ((ant & ANT_SELCFG_AUTO) == ANT_SELCFG_AUTO) {
+ *antcfg = brcms_c_antsel_id2antcfg(asi, antselid);
+ *fbantcfg = brcms_c_antsel_id2antcfg(asi, fbantselid);
+ } else {
+ *antcfg =
+ asi->antcfg_11n.ant_config[ANT_SELCFG_TX_UNICAST];
+ *fbantcfg = *antcfg;
+ }
+ }
+ return;
+}
+
+/* boardlevel antenna selection: convert mimo_antsel (ucode interface) to id */
+u8 brcms_c_antsel_antsel2id(struct antsel_info *asi, u16 antsel)
+{
+ u8 antselid = 0;
+
+ if (asi->antsel_type == ANTSEL_2x4) {
+ /* 2x4 antenna diversity board, 4 cfgs: 0-2 0-3 1-2 1-3 */
+ antselid = mimo_2x4_div_antselid_tbl[(antsel & 0xf)];
+ return antselid;
+
+ } else if (asi->antsel_type == ANTSEL_2x3) {
+ /* 2x3 antenna selection, 3 cfgs: 0-1 0-2 2-1 */
+ antselid = mimo_2x3_div_antselid_tbl[(antsel & 0xf)];
+ return antselid;
+ }
+
+ return antselid;
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/antsel.h b/drivers/net/wireless/brcm80211/brcmsmac/antsel.h
new file mode 100644
index 000000000000..97ea3881a8ec
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/antsel.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_ANTSEL_H_
+#define _BRCM_ANTSEL_H_
+
+extern struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc);
+extern void brcms_c_antsel_detach(struct antsel_info *asi);
+extern void brcms_c_antsel_init(struct antsel_info *asi);
+extern void brcms_c_antsel_antcfg_get(struct antsel_info *asi, bool usedef,
+ bool sel,
+ u8 id, u8 fbid, u8 *antcfg,
+ u8 *fbantcfg);
+extern u8 brcms_c_antsel_antsel2id(struct antsel_info *asi, u16 antsel);
+
+#endif /* _BRCM_ANTSEL_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.c b/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.c
new file mode 100644
index 000000000000..52fc9eeb5fa5
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/module.h> /* bug in tracepoint.h, it should include this */
+
+#ifndef __CHECKER__
+#include "mac80211_if.h"
+#define CREATE_TRACE_POINTS
+#include "brcms_trace_events.h"
+#endif
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.h b/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.h
new file mode 100644
index 000000000000..27dd73eef56d
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.h
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM brcmsmac
+
+#if !defined(__TRACE_BRCMSMAC_H) || defined(TRACE_HEADER_MULTI_READ)
+
+#define __TRACE_BRCMSMAC_H
+
+#include <linux/tracepoint.h>
+#include "mac80211_if.h"
+
+#ifndef CONFIG_BRCMDBG
+#undef TRACE_EVENT
+#define TRACE_EVENT(name, proto, ...) \
+static inline void trace_ ## name(proto) {}
+#endif
+
+/*
+ * We define a tracepoint, its arguments, its printk format and its
+ * 'fast binary record' layout.
+ */
+TRACE_EVENT(brcms_timer,
+ /* TPPROTO is the prototype of the function called by this tracepoint */
+ TP_PROTO(struct brcms_timer *t),
+ /*
+ * TPARGS(firstarg, p) are the parameters names, same as found in the
+ * prototype.
+ */
+ TP_ARGS(t),
+ /*
+ * Fast binary tracing: define the trace record via TP_STRUCT__entry().
+ * You can think about it like a regular C structure local variable
+ * definition.
+ */
+ TP_STRUCT__entry(
+ __field(uint, ms)
+ __field(uint, set)
+ __field(uint, periodic)
+ ),
+ TP_fast_assign(
+ __entry->ms = t->ms;
+ __entry->set = t->set;
+ __entry->periodic = t->periodic;
+ ),
+ TP_printk(
+ "ms=%u set=%u periodic=%u",
+ __entry->ms, __entry->set, __entry->periodic
+ )
+);
+
+TRACE_EVENT(brcms_dpc,
+ TP_PROTO(unsigned long data),
+ TP_ARGS(data),
+ TP_STRUCT__entry(
+ __field(unsigned long, data)
+ ),
+ TP_fast_assign(
+ __entry->data = data;
+ ),
+ TP_printk(
+ "data=%p",
+ (void *)__entry->data
+ )
+);
+
+#endif /* __TRACE_BRCMSMAC_H */
+
+#ifdef CONFIG_BRCMDBG
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE brcms_trace_events
+
+#include <trace/define_trace.h>
+
+#endif /* CONFIG_BRCMDBG */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
new file mode 100644
index 000000000000..89ad1b7dab8f
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
@@ -0,0 +1,1591 @@
+/*
+ * Copyright (c) 2010 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/types.h>
+#include <net/mac80211.h>
+
+#include <defs.h>
+#include "pub.h"
+#include "phy/phy_hal.h"
+#include "main.h"
+#include "stf.h"
+#include "channel.h"
+
+/* QDB() macro takes a dB value and converts to a quarter dB value */
+#define QDB(n) ((n) * BRCMS_TXPWR_DB_FACTOR)
+
+#define LOCALE_CHAN_01_11 (1<<0)
+#define LOCALE_CHAN_12_13 (1<<1)
+#define LOCALE_CHAN_14 (1<<2)
+#define LOCALE_SET_5G_LOW_JP1 (1<<3) /* 34-48, step 2 */
+#define LOCALE_SET_5G_LOW_JP2 (1<<4) /* 34-46, step 4 */
+#define LOCALE_SET_5G_LOW1 (1<<5) /* 36-48, step 4 */
+#define LOCALE_SET_5G_LOW2 (1<<6) /* 52 */
+#define LOCALE_SET_5G_LOW3 (1<<7) /* 56-64, step 4 */
+#define LOCALE_SET_5G_MID1 (1<<8) /* 100-116, step 4 */
+#define LOCALE_SET_5G_MID2 (1<<9) /* 120-124, step 4 */
+#define LOCALE_SET_5G_MID3 (1<<10) /* 128 */
+#define LOCALE_SET_5G_HIGH1 (1<<11) /* 132-140, step 4 */
+#define LOCALE_SET_5G_HIGH2 (1<<12) /* 149-161, step 4 */
+#define LOCALE_SET_5G_HIGH3 (1<<13) /* 165 */
+#define LOCALE_CHAN_52_140_ALL (1<<14)
+#define LOCALE_SET_5G_HIGH4 (1<<15) /* 184-216 */
+
+#define LOCALE_CHAN_36_64 (LOCALE_SET_5G_LOW1 | \
+ LOCALE_SET_5G_LOW2 | \
+ LOCALE_SET_5G_LOW3)
+#define LOCALE_CHAN_52_64 (LOCALE_SET_5G_LOW2 | LOCALE_SET_5G_LOW3)
+#define LOCALE_CHAN_100_124 (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2)
+#define LOCALE_CHAN_100_140 (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2 | \
+ LOCALE_SET_5G_MID3 | LOCALE_SET_5G_HIGH1)
+#define LOCALE_CHAN_149_165 (LOCALE_SET_5G_HIGH2 | LOCALE_SET_5G_HIGH3)
+#define LOCALE_CHAN_184_216 LOCALE_SET_5G_HIGH4
+
+#define LOCALE_CHAN_01_14 (LOCALE_CHAN_01_11 | \
+ LOCALE_CHAN_12_13 | \
+ LOCALE_CHAN_14)
+
+#define LOCALE_RADAR_SET_NONE 0
+#define LOCALE_RADAR_SET_1 1
+
+#define LOCALE_RESTRICTED_NONE 0
+#define LOCALE_RESTRICTED_SET_2G_SHORT 1
+#define LOCALE_RESTRICTED_CHAN_165 2
+#define LOCALE_CHAN_ALL_5G 3
+#define LOCALE_RESTRICTED_JAPAN_LEGACY 4
+#define LOCALE_RESTRICTED_11D_2G 5
+#define LOCALE_RESTRICTED_11D_5G 6
+#define LOCALE_RESTRICTED_LOW_HI 7
+#define LOCALE_RESTRICTED_12_13_14 8
+
+#define LOCALE_2G_IDX_i 0
+#define LOCALE_5G_IDX_11 0
+#define LOCALE_MIMO_IDX_bn 0
+#define LOCALE_MIMO_IDX_11n 0
+
+/* max of BAND_5G_PWR_LVLS and 6 for 2.4 GHz */
+#define BRCMS_MAXPWR_TBL_SIZE 6
+/* max of BAND_5G_PWR_LVLS and 14 for 2.4 GHz */
+#define BRCMS_MAXPWR_MIMO_TBL_SIZE 14
+
+/* power level in group of 2.4GHz band channels:
+ * maxpwr[0] - CCK channels [1]
+ * maxpwr[1] - CCK channels [2-10]
+ * maxpwr[2] - CCK channels [11-14]
+ * maxpwr[3] - OFDM channels [1]
+ * maxpwr[4] - OFDM channels [2-10]
+ * maxpwr[5] - OFDM channels [11-14]
+ */
+
+/* maxpwr mapping to 5GHz band channels:
+ * maxpwr[0] - channels [34-48]
+ * maxpwr[1] - channels [52-60]
+ * maxpwr[2] - channels [62-64]
+ * maxpwr[3] - channels [100-140]
+ * maxpwr[4] - channels [149-165]
+ */
+#define BAND_5G_PWR_LVLS 5 /* 5 power levels for 5G */
+
+#define LC(id) LOCALE_MIMO_IDX_ ## id
+
+#define LC_2G(id) LOCALE_2G_IDX_ ## id
+
+#define LC_5G(id) LOCALE_5G_IDX_ ## id
+
+#define LOCALES(band2, band5, mimo2, mimo5) \
+ {LC_2G(band2), LC_5G(band5), LC(mimo2), LC(mimo5)}
+
+/* macro to get 2.4 GHz channel group index for tx power */
+#define CHANNEL_POWER_IDX_2G_CCK(c) (((c) < 2) ? 0 : (((c) < 11) ? 1 : 2))
+#define CHANNEL_POWER_IDX_2G_OFDM(c) (((c) < 2) ? 3 : (((c) < 11) ? 4 : 5))
+
+/* macro to get 5 GHz channel group index for tx power */
+#define CHANNEL_POWER_IDX_5G(c) (((c) < 52) ? 0 : \
+ (((c) < 62) ? 1 : \
+ (((c) < 100) ? 2 : \
+ (((c) < 149) ? 3 : 4))))
+
+#define ISDFS_EU(fl) (((fl) & BRCMS_DFS_EU) == BRCMS_DFS_EU)
+
+struct brcms_cm_band {
+ /* struct locale_info flags */
+ u8 locale_flags;
+ /* List of valid channels in the country */
+ struct brcms_chanvec valid_channels;
+ /* List of restricted use channels */
+ const struct brcms_chanvec *restricted_channels;
+ /* List of radar sensitive channels */
+ const struct brcms_chanvec *radar_channels;
+ u8 PAD[8];
+};
+
+ /* locale per-channel tx power limits for MIMO frames
+ * maxpwr arrays are index by channel for 2.4 GHz limits, and
+ * by sub-band for 5 GHz limits using CHANNEL_POWER_IDX_5G(channel)
+ */
+struct locale_mimo_info {
+ /* tx 20 MHz power limits, qdBm units */
+ s8 maxpwr20[BRCMS_MAXPWR_MIMO_TBL_SIZE];
+ /* tx 40 MHz power limits, qdBm units */
+ s8 maxpwr40[BRCMS_MAXPWR_MIMO_TBL_SIZE];
+ u8 flags;
+};
+
+/* Country names and abbreviations with locale defined from ISO 3166 */
+struct country_info {
+ const u8 locale_2G; /* 2.4G band locale */
+ const u8 locale_5G; /* 5G band locale */
+ const u8 locale_mimo_2G; /* 2.4G mimo info */
+ const u8 locale_mimo_5G; /* 5G mimo info */
+};
+
+struct brcms_cm_info {
+ struct brcms_pub *pub;
+ struct brcms_c_info *wlc;
+ char srom_ccode[BRCM_CNTRY_BUF_SZ]; /* Country Code in SROM */
+ uint srom_regrev; /* Regulatory Rev for the SROM ccode */
+ const struct country_info *country; /* current country def */
+ char ccode[BRCM_CNTRY_BUF_SZ]; /* current internal Country Code */
+ uint regrev; /* current Regulatory Revision */
+ char country_abbrev[BRCM_CNTRY_BUF_SZ]; /* current advertised ccode */
+ /* per-band state (one per phy/radio) */
+ struct brcms_cm_band bandstate[MAXBANDS];
+ /* quiet channels currently for radar sensitivity or 11h support */
+ /* channels on which we cannot transmit */
+ struct brcms_chanvec quiet_channels;
+};
+
+/* locale channel and power info. */
+struct locale_info {
+ u32 valid_channels;
+ /* List of radar sensitive channels */
+ u8 radar_channels;
+ /* List of channels used only if APs are detected */
+ u8 restricted_channels;
+ /* Max tx pwr in qdBm for each sub-band */
+ s8 maxpwr[BRCMS_MAXPWR_TBL_SIZE];
+ /* Country IE advertised max tx pwr in dBm per sub-band */
+ s8 pub_maxpwr[BAND_5G_PWR_LVLS];
+ u8 flags;
+};
+
+/* Regulatory Matrix Spreadsheet (CLM) MIMO v3.7.9 */
+
+/*
+ * Some common channel sets
+ */
+
+/* No channels */
+static const struct brcms_chanvec chanvec_none = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+/* All 2.4 GHz HW channels */
+static const struct brcms_chanvec chanvec_all_2G = {
+ {0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+/* All 5 GHz HW channels */
+static const struct brcms_chanvec chanvec_all_5G = {
+ {0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x11, 0x11,
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x20, 0x22, 0x22, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x11, 0x01}
+};
+
+/*
+ * Radar channel sets
+ */
+
+/* Channels 52 - 64, 100 - 140 */
+static const struct brcms_chanvec radar_set1 = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, /* 52 - 60 */
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11, /* 64, 100 - 124 */
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 128 - 140 */
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+/*
+ * Restricted channel sets
+ */
+
+/* Channels 34, 38, 42, 46 */
+static const struct brcms_chanvec restricted_set_japan_legacy = {
+ {0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+/* Channels 12, 13 */
+static const struct brcms_chanvec restricted_set_2g_short = {
+ {0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+/* Channel 165 */
+static const struct brcms_chanvec restricted_chan_165 = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+/* Channels 36 - 48 & 149 - 165 */
+static const struct brcms_chanvec restricted_low_hi = {
+ {0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x22, 0x22, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+/* Channels 12 - 14 */
+static const struct brcms_chanvec restricted_set_12_13_14 = {
+ {0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+/* global memory to provide working buffer for expanded locale */
+
+static const struct brcms_chanvec *g_table_radar_set[] = {
+ &chanvec_none,
+ &radar_set1
+};
+
+static const struct brcms_chanvec *g_table_restricted_chan[] = {
+ &chanvec_none, /* restricted_set_none */
+ &restricted_set_2g_short,
+ &restricted_chan_165,
+ &chanvec_all_5G,
+ &restricted_set_japan_legacy,
+ &chanvec_all_2G, /* restricted_set_11d_2G */
+ &chanvec_all_5G, /* restricted_set_11d_5G */
+ &restricted_low_hi,
+ &restricted_set_12_13_14
+};
+
+static const struct brcms_chanvec locale_2g_01_11 = {
+ {0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+static const struct brcms_chanvec locale_2g_12_13 = {
+ {0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+static const struct brcms_chanvec locale_2g_14 = {
+ {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+static const struct brcms_chanvec locale_5g_LOW_JP1 = {
+ {0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+static const struct brcms_chanvec locale_5g_LOW_JP2 = {
+ {0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+static const struct brcms_chanvec locale_5g_LOW1 = {
+ {0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+static const struct brcms_chanvec locale_5g_LOW2 = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+static const struct brcms_chanvec locale_5g_LOW3 = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+static const struct brcms_chanvec locale_5g_MID1 = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+static const struct brcms_chanvec locale_5g_MID2 = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+static const struct brcms_chanvec locale_5g_MID3 = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+static const struct brcms_chanvec locale_5g_HIGH1 = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+static const struct brcms_chanvec locale_5g_HIGH2 = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x22, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+static const struct brcms_chanvec locale_5g_HIGH3 = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+static const struct brcms_chanvec locale_5g_52_140_ALL = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11,
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}
+};
+
+static const struct brcms_chanvec locale_5g_HIGH4 = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x11, 0x11}
+};
+
+static const struct brcms_chanvec *g_table_locale_base[] = {
+ &locale_2g_01_11,
+ &locale_2g_12_13,
+ &locale_2g_14,
+ &locale_5g_LOW_JP1,
+ &locale_5g_LOW_JP2,
+ &locale_5g_LOW1,
+ &locale_5g_LOW2,
+ &locale_5g_LOW3,
+ &locale_5g_MID1,
+ &locale_5g_MID2,
+ &locale_5g_MID3,
+ &locale_5g_HIGH1,
+ &locale_5g_HIGH2,
+ &locale_5g_HIGH3,
+ &locale_5g_52_140_ALL,
+ &locale_5g_HIGH4
+};
+
+static void brcms_c_locale_add_channels(struct brcms_chanvec *target,
+ const struct brcms_chanvec *channels)
+{
+ u8 i;
+ for (i = 0; i < sizeof(struct brcms_chanvec); i++)
+ target->vec[i] |= channels->vec[i];
+}
+
+static void brcms_c_locale_get_channels(const struct locale_info *locale,
+ struct brcms_chanvec *channels)
+{
+ u8 i;
+
+ memset(channels, 0, sizeof(struct brcms_chanvec));
+
+ for (i = 0; i < ARRAY_SIZE(g_table_locale_base); i++) {
+ if (locale->valid_channels & (1 << i))
+ brcms_c_locale_add_channels(channels,
+ g_table_locale_base[i]);
+ }
+}
+
+/*
+ * Locale Definitions - 2.4 GHz
+ */
+static const struct locale_info locale_i = { /* locale i. channel 1 - 13 */
+ LOCALE_CHAN_01_11 | LOCALE_CHAN_12_13,
+ LOCALE_RADAR_SET_NONE,
+ LOCALE_RESTRICTED_SET_2G_SHORT,
+ {QDB(19), QDB(19), QDB(19),
+ QDB(19), QDB(19), QDB(19)},
+ {20, 20, 20, 0},
+ BRCMS_EIRP
+};
+
+/*
+ * Locale Definitions - 5 GHz
+ */
+static const struct locale_info locale_11 = {
+ /* locale 11. channel 36 - 48, 52 - 64, 100 - 140, 149 - 165 */
+ LOCALE_CHAN_36_64 | LOCALE_CHAN_100_140 | LOCALE_CHAN_149_165,
+ LOCALE_RADAR_SET_1,
+ LOCALE_RESTRICTED_NONE,
+ {QDB(21), QDB(21), QDB(21), QDB(21), QDB(21)},
+ {23, 23, 23, 30, 30},
+ BRCMS_EIRP | BRCMS_DFS_EU
+};
+
+static const struct locale_info *g_locale_2g_table[] = {
+ &locale_i
+};
+
+static const struct locale_info *g_locale_5g_table[] = {
+ &locale_11
+};
+
+/*
+ * MIMO Locale Definitions - 2.4 GHz
+ */
+static const struct locale_mimo_info locale_bn = {
+ {QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
+ QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
+ QDB(13), QDB(13), QDB(13)},
+ {0, 0, QDB(13), QDB(13), QDB(13),
+ QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
+ QDB(13), 0, 0},
+ 0
+};
+
+static const struct locale_mimo_info *g_mimo_2g_table[] = {
+ &locale_bn
+};
+
+/*
+ * MIMO Locale Definitions - 5 GHz
+ */
+static const struct locale_mimo_info locale_11n = {
+ { /* 12.5 dBm */ 50, 50, 50, QDB(15), QDB(15)},
+ {QDB(14), QDB(15), QDB(15), QDB(15), QDB(15)},
+ 0
+};
+
+static const struct locale_mimo_info *g_mimo_5g_table[] = {
+ &locale_11n
+};
+
+static const struct {
+ char abbrev[BRCM_CNTRY_BUF_SZ]; /* country abbreviation */
+ struct country_info country;
+} cntry_locales[] = {
+ {
+ "X2", LOCALES(i, 11, bn, 11n)}, /* Worldwide RoW 2 */
+};
+
+#ifdef SUPPORT_40MHZ
+/* 20MHz channel info for 40MHz pairing support */
+struct chan20_info {
+ u8 sb;
+ u8 adj_sbs;
+};
+
+/* indicates adjacent channels that are allowed for a 40 Mhz channel and
+ * those that permitted by the HT
+ */
+struct chan20_info chan20_info[] = {
+ /* 11b/11g */
+/* 0 */ {1, (CH_UPPER_SB | CH_EWA_VALID)},
+/* 1 */ {2, (CH_UPPER_SB | CH_EWA_VALID)},
+/* 2 */ {3, (CH_UPPER_SB | CH_EWA_VALID)},
+/* 3 */ {4, (CH_UPPER_SB | CH_EWA_VALID)},
+/* 4 */ {5, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
+/* 5 */ {6, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
+/* 6 */ {7, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
+/* 7 */ {8, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
+/* 8 */ {9, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
+/* 9 */ {10, (CH_LOWER_SB | CH_EWA_VALID)},
+/* 10 */ {11, (CH_LOWER_SB | CH_EWA_VALID)},
+/* 11 */ {12, (CH_LOWER_SB)},
+/* 12 */ {13, (CH_LOWER_SB)},
+/* 13 */ {14, (CH_LOWER_SB)},
+
+/* 11a japan high */
+/* 14 */ {34, (CH_UPPER_SB)},
+/* 15 */ {38, (CH_LOWER_SB)},
+/* 16 */ {42, (CH_LOWER_SB)},
+/* 17 */ {46, (CH_LOWER_SB)},
+
+/* 11a usa low */
+/* 18 */ {36, (CH_UPPER_SB | CH_EWA_VALID)},
+/* 19 */ {40, (CH_LOWER_SB | CH_EWA_VALID)},
+/* 20 */ {44, (CH_UPPER_SB | CH_EWA_VALID)},
+/* 21 */ {48, (CH_LOWER_SB | CH_EWA_VALID)},
+/* 22 */ {52, (CH_UPPER_SB | CH_EWA_VALID)},
+/* 23 */ {56, (CH_LOWER_SB | CH_EWA_VALID)},
+/* 24 */ {60, (CH_UPPER_SB | CH_EWA_VALID)},
+/* 25 */ {64, (CH_LOWER_SB | CH_EWA_VALID)},
+
+/* 11a Europe */
+/* 26 */ {100, (CH_UPPER_SB | CH_EWA_VALID)},
+/* 27 */ {104, (CH_LOWER_SB | CH_EWA_VALID)},
+/* 28 */ {108, (CH_UPPER_SB | CH_EWA_VALID)},
+/* 29 */ {112, (CH_LOWER_SB | CH_EWA_VALID)},
+/* 30 */ {116, (CH_UPPER_SB | CH_EWA_VALID)},
+/* 31 */ {120, (CH_LOWER_SB | CH_EWA_VALID)},
+/* 32 */ {124, (CH_UPPER_SB | CH_EWA_VALID)},
+/* 33 */ {128, (CH_LOWER_SB | CH_EWA_VALID)},
+/* 34 */ {132, (CH_UPPER_SB | CH_EWA_VALID)},
+/* 35 */ {136, (CH_LOWER_SB | CH_EWA_VALID)},
+/* 36 */ {140, (CH_LOWER_SB)},
+
+/* 11a usa high, ref5 only */
+/* The 0x80 bit in pdiv means these are REF5, other entries are REF20 */
+/* 37 */ {149, (CH_UPPER_SB | CH_EWA_VALID)},
+/* 38 */ {153, (CH_LOWER_SB | CH_EWA_VALID)},
+/* 39 */ {157, (CH_UPPER_SB | CH_EWA_VALID)},
+/* 40 */ {161, (CH_LOWER_SB | CH_EWA_VALID)},
+/* 41 */ {165, (CH_LOWER_SB)},
+
+/* 11a japan */
+/* 42 */ {184, (CH_UPPER_SB)},
+/* 43 */ {188, (CH_LOWER_SB)},
+/* 44 */ {192, (CH_UPPER_SB)},
+/* 45 */ {196, (CH_LOWER_SB)},
+/* 46 */ {200, (CH_UPPER_SB)},
+/* 47 */ {204, (CH_LOWER_SB)},
+/* 48 */ {208, (CH_UPPER_SB)},
+/* 49 */ {212, (CH_LOWER_SB)},
+/* 50 */ {216, (CH_LOWER_SB)}
+};
+#endif /* SUPPORT_40MHZ */
+
+static const struct locale_info *brcms_c_get_locale_2g(u8 locale_idx)
+{
+ if (locale_idx >= ARRAY_SIZE(g_locale_2g_table))
+ return NULL; /* error condition */
+
+ return g_locale_2g_table[locale_idx];
+}
+
+static const struct locale_info *brcms_c_get_locale_5g(u8 locale_idx)
+{
+ if (locale_idx >= ARRAY_SIZE(g_locale_5g_table))
+ return NULL; /* error condition */
+
+ return g_locale_5g_table[locale_idx];
+}
+
+static const struct locale_mimo_info *brcms_c_get_mimo_2g(u8 locale_idx)
+{
+ if (locale_idx >= ARRAY_SIZE(g_mimo_2g_table))
+ return NULL;
+
+ return g_mimo_2g_table[locale_idx];
+}
+
+static const struct locale_mimo_info *brcms_c_get_mimo_5g(u8 locale_idx)
+{
+ if (locale_idx >= ARRAY_SIZE(g_mimo_5g_table))
+ return NULL;
+
+ return g_mimo_5g_table[locale_idx];
+}
+
+static int
+brcms_c_country_aggregate_map(struct brcms_cm_info *wlc_cm, const char *ccode,
+ char *mapped_ccode, uint *mapped_regrev)
+{
+ return false;
+}
+
+/* Lookup a country info structure from a null terminated country
+ * abbreviation and regrev directly with no translation.
+ */
+static const struct country_info *
+brcms_c_country_lookup_direct(const char *ccode, uint regrev)
+{
+ uint size, i;
+
+ /* Should just return 0 for single locale driver. */
+ /* Keep it this way in case we add more locales. (for now anyway) */
+
+ /*
+ * all other country def arrays are for regrev == 0, so if
+ * regrev is non-zero, fail
+ */
+ if (regrev > 0)
+ return NULL;
+
+ /* find matched table entry from country code */
+ size = ARRAY_SIZE(cntry_locales);
+ for (i = 0; i < size; i++) {
+ if (strcmp(ccode, cntry_locales[i].abbrev) == 0)
+ return &cntry_locales[i].country;
+ }
+ return NULL;
+}
+
+static const struct country_info *
+brcms_c_countrycode_map(struct brcms_cm_info *wlc_cm, const char *ccode,
+ char *mapped_ccode, uint *mapped_regrev)
+{
+ struct brcms_c_info *wlc = wlc_cm->wlc;
+ const struct country_info *country;
+ uint srom_regrev = wlc_cm->srom_regrev;
+ const char *srom_ccode = wlc_cm->srom_ccode;
+ int mapped;
+
+ /* check for currently supported ccode size */
+ if (strlen(ccode) > (BRCM_CNTRY_BUF_SZ - 1)) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: ccode \"%s\" too long for "
+ "match\n", wlc->pub->unit, __func__, ccode);
+ return NULL;
+ }
+
+ /* default mapping is the given ccode and regrev 0 */
+ strncpy(mapped_ccode, ccode, BRCM_CNTRY_BUF_SZ);
+ *mapped_regrev = 0;
+
+ /* If the desired country code matches the srom country code,
+ * then the mapped country is the srom regulatory rev.
+ * Otherwise look for an aggregate mapping.
+ */
+ if (!strcmp(srom_ccode, ccode)) {
+ *mapped_regrev = srom_regrev;
+ mapped = 0;
+ wiphy_err(wlc->wiphy, "srom_code == ccode %s\n", __func__);
+ } else {
+ mapped =
+ brcms_c_country_aggregate_map(wlc_cm, ccode, mapped_ccode,
+ mapped_regrev);
+ }
+
+ /* find the matching built-in country definition */
+ country = brcms_c_country_lookup_direct(mapped_ccode, *mapped_regrev);
+
+ /* if there is not an exact rev match, default to rev zero */
+ if (country == NULL && *mapped_regrev != 0) {
+ *mapped_regrev = 0;
+ country =
+ brcms_c_country_lookup_direct(mapped_ccode, *mapped_regrev);
+ }
+
+ return country;
+}
+
+/* Lookup a country info structure from a null terminated country code
+ * The lookup is case sensitive.
+ */
+static const struct country_info *
+brcms_c_country_lookup(struct brcms_c_info *wlc, const char *ccode)
+{
+ const struct country_info *country;
+ char mapped_ccode[BRCM_CNTRY_BUF_SZ];
+ uint mapped_regrev;
+
+ /*
+ * map the country code to a built-in country code, regrev, and
+ * country_info struct
+ */
+ country = brcms_c_countrycode_map(wlc->cmi, ccode, mapped_ccode,
+ &mapped_regrev);
+
+ return country;
+}
+
+/*
+ * reset the quiet channels vector to the union
+ * of the restricted and radar channel sets
+ */
+static void brcms_c_quiet_channels_reset(struct brcms_cm_info *wlc_cm)
+{
+ struct brcms_c_info *wlc = wlc_cm->wlc;
+ uint i, j;
+ struct brcms_band *band;
+ const struct brcms_chanvec *chanvec;
+
+ memset(&wlc_cm->quiet_channels, 0, sizeof(struct brcms_chanvec));
+
+ band = wlc->band;
+ for (i = 0; i < wlc->pub->_nbands;
+ i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) {
+
+ /* initialize quiet channels for restricted channels */
+ chanvec = wlc_cm->bandstate[band->bandunit].restricted_channels;
+ for (j = 0; j < sizeof(struct brcms_chanvec); j++)
+ wlc_cm->quiet_channels.vec[j] |= chanvec->vec[j];
+
+ }
+}
+
+/* Is the channel valid for the current locale and current band? */
+static bool brcms_c_valid_channel20(struct brcms_cm_info *wlc_cm, uint val)
+{
+ struct brcms_c_info *wlc = wlc_cm->wlc;
+
+ return ((val < MAXCHANNEL) &&
+ isset(wlc_cm->bandstate[wlc->band->bandunit].valid_channels.vec,
+ val));
+}
+
+/* Is the channel valid for the current locale and specified band? */
+static bool brcms_c_valid_channel20_in_band(struct brcms_cm_info *wlc_cm,
+ uint bandunit, uint val)
+{
+ return ((val < MAXCHANNEL)
+ && isset(wlc_cm->bandstate[bandunit].valid_channels.vec, val));
+}
+
+/* Is the channel valid for the current locale? (but don't consider channels not
+ * available due to bandlocking)
+ */
+static bool brcms_c_valid_channel20_db(struct brcms_cm_info *wlc_cm, uint val)
+{
+ struct brcms_c_info *wlc = wlc_cm->wlc;
+
+ return brcms_c_valid_channel20(wlc->cmi, val) ||
+ (!wlc->bandlocked
+ && brcms_c_valid_channel20_in_band(wlc->cmi,
+ OTHERBANDUNIT(wlc), val));
+}
+
+/* JP, J1 - J10 are Japan ccodes */
+static bool brcms_c_japan_ccode(const char *ccode)
+{
+ return (ccode[0] == 'J' &&
+ (ccode[1] == 'P' || (ccode[1] >= '1' && ccode[1] <= '9')));
+}
+
+/* Returns true if currently set country is Japan or variant */
+static bool brcms_c_japan(struct brcms_c_info *wlc)
+{
+ return brcms_c_japan_ccode(wlc->cmi->country_abbrev);
+}
+
+static void
+brcms_c_channel_min_txpower_limits_with_local_constraint(
+ struct brcms_cm_info *wlc_cm, struct txpwr_limits *txpwr,
+ u8 local_constraint_qdbm)
+{
+ int j;
+
+ /* CCK Rates */
+ for (j = 0; j < WL_TX_POWER_CCK_NUM; j++)
+ txpwr->cck[j] = min(txpwr->cck[j], local_constraint_qdbm);
+
+ /* 20 MHz Legacy OFDM SISO */
+ for (j = 0; j < WL_TX_POWER_OFDM_NUM; j++)
+ txpwr->ofdm[j] = min(txpwr->ofdm[j], local_constraint_qdbm);
+
+ /* 20 MHz Legacy OFDM CDD */
+ for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++)
+ txpwr->ofdm_cdd[j] =
+ min(txpwr->ofdm_cdd[j], local_constraint_qdbm);
+
+ /* 40 MHz Legacy OFDM SISO */
+ for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++)
+ txpwr->ofdm_40_siso[j] =
+ min(txpwr->ofdm_40_siso[j], local_constraint_qdbm);
+
+ /* 40 MHz Legacy OFDM CDD */
+ for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++)
+ txpwr->ofdm_40_cdd[j] =
+ min(txpwr->ofdm_40_cdd[j], local_constraint_qdbm);
+
+ /* 20MHz MCS 0-7 SISO */
+ for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
+ txpwr->mcs_20_siso[j] =
+ min(txpwr->mcs_20_siso[j], local_constraint_qdbm);
+
+ /* 20MHz MCS 0-7 CDD */
+ for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
+ txpwr->mcs_20_cdd[j] =
+ min(txpwr->mcs_20_cdd[j], local_constraint_qdbm);
+
+ /* 20MHz MCS 0-7 STBC */
+ for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
+ txpwr->mcs_20_stbc[j] =
+ min(txpwr->mcs_20_stbc[j], local_constraint_qdbm);
+
+ /* 20MHz MCS 8-15 MIMO */
+ for (j = 0; j < BRCMS_NUM_RATES_MCS_2_STREAM; j++)
+ txpwr->mcs_20_mimo[j] =
+ min(txpwr->mcs_20_mimo[j], local_constraint_qdbm);
+
+ /* 40MHz MCS 0-7 SISO */
+ for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
+ txpwr->mcs_40_siso[j] =
+ min(txpwr->mcs_40_siso[j], local_constraint_qdbm);
+
+ /* 40MHz MCS 0-7 CDD */
+ for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
+ txpwr->mcs_40_cdd[j] =
+ min(txpwr->mcs_40_cdd[j], local_constraint_qdbm);
+
+ /* 40MHz MCS 0-7 STBC */
+ for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
+ txpwr->mcs_40_stbc[j] =
+ min(txpwr->mcs_40_stbc[j], local_constraint_qdbm);
+
+ /* 40MHz MCS 8-15 MIMO */
+ for (j = 0; j < BRCMS_NUM_RATES_MCS_2_STREAM; j++)
+ txpwr->mcs_40_mimo[j] =
+ min(txpwr->mcs_40_mimo[j], local_constraint_qdbm);
+
+ /* 40MHz MCS 32 */
+ txpwr->mcs32 = min(txpwr->mcs32, local_constraint_qdbm);
+
+}
+
+/* Update the radio state (enable/disable) and tx power targets
+ * based on a new set of channel/regulatory information
+ */
+static void brcms_c_channels_commit(struct brcms_cm_info *wlc_cm)
+{
+ struct brcms_c_info *wlc = wlc_cm->wlc;
+ uint chan;
+ struct txpwr_limits txpwr;
+
+ /* search for the existence of any valid channel */
+ for (chan = 0; chan < MAXCHANNEL; chan++) {
+ if (brcms_c_valid_channel20_db(wlc->cmi, chan))
+ break;
+ }
+ if (chan == MAXCHANNEL)
+ chan = INVCHANNEL;
+
+ /*
+ * based on the channel search above, set or
+ * clear WL_RADIO_COUNTRY_DISABLE.
+ */
+ if (chan == INVCHANNEL) {
+ /*
+ * country/locale with no valid channels, set
+ * the radio disable bit
+ */
+ mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
+ wiphy_err(wlc->wiphy, "wl%d: %s: no valid channel for \"%s\" "
+ "nbands %d bandlocked %d\n", wlc->pub->unit,
+ __func__, wlc_cm->country_abbrev, wlc->pub->_nbands,
+ wlc->bandlocked);
+ } else if (mboolisset(wlc->pub->radio_disabled,
+ WL_RADIO_COUNTRY_DISABLE)) {
+ /*
+ * country/locale with valid channel, clear
+ * the radio disable bit
+ */
+ mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
+ }
+
+ /*
+ * Now that the country abbreviation is set, if the radio supports 2G,
+ * then set channel 14 restrictions based on the new locale.
+ */
+ if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G)
+ wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi,
+ brcms_c_japan(wlc) ? true :
+ false);
+
+ if (wlc->pub->up && chan != INVCHANNEL) {
+ brcms_c_channel_reg_limits(wlc_cm, wlc->chanspec, &txpwr);
+ brcms_c_channel_min_txpower_limits_with_local_constraint(wlc_cm,
+ &txpwr, BRCMS_TXPWR_MAX);
+ wlc_phy_txpower_limit_set(wlc->band->pi, &txpwr, wlc->chanspec);
+ }
+}
+
+static int
+brcms_c_channels_init(struct brcms_cm_info *wlc_cm,
+ const struct country_info *country)
+{
+ struct brcms_c_info *wlc = wlc_cm->wlc;
+ uint i, j;
+ struct brcms_band *band;
+ const struct locale_info *li;
+ struct brcms_chanvec sup_chan;
+ const struct locale_mimo_info *li_mimo;
+
+ band = wlc->band;
+ for (i = 0; i < wlc->pub->_nbands;
+ i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) {
+
+ li = (band->bandtype == BRCM_BAND_5G) ?
+ brcms_c_get_locale_5g(country->locale_5G) :
+ brcms_c_get_locale_2g(country->locale_2G);
+ wlc_cm->bandstate[band->bandunit].locale_flags = li->flags;
+ li_mimo = (band->bandtype == BRCM_BAND_5G) ?
+ brcms_c_get_mimo_5g(country->locale_mimo_5G) :
+ brcms_c_get_mimo_2g(country->locale_mimo_2G);
+
+ /* merge the mimo non-mimo locale flags */
+ wlc_cm->bandstate[band->bandunit].locale_flags |=
+ li_mimo->flags;
+
+ wlc_cm->bandstate[band->bandunit].restricted_channels =
+ g_table_restricted_chan[li->restricted_channels];
+ wlc_cm->bandstate[band->bandunit].radar_channels =
+ g_table_radar_set[li->radar_channels];
+
+ /*
+ * set the channel availability, masking out the channels
+ * that may not be supported on this phy.
+ */
+ wlc_phy_chanspec_band_validch(band->pi, band->bandtype,
+ &sup_chan);
+ brcms_c_locale_get_channels(li,
+ &wlc_cm->bandstate[band->bandunit].
+ valid_channels);
+ for (j = 0; j < sizeof(struct brcms_chanvec); j++)
+ wlc_cm->bandstate[band->bandunit].valid_channels.
+ vec[j] &= sup_chan.vec[j];
+ }
+
+ brcms_c_quiet_channels_reset(wlc_cm);
+ brcms_c_channels_commit(wlc_cm);
+
+ return 0;
+}
+
+/*
+ * set the driver's current country and regulatory information
+ * using a country code as the source. Look up built in country
+ * information found with the country code.
+ */
+static void
+brcms_c_set_country_common(struct brcms_cm_info *wlc_cm,
+ const char *country_abbrev,
+ const char *ccode, uint regrev,
+ const struct country_info *country)
+{
+ const struct locale_info *locale;
+ struct brcms_c_info *wlc = wlc_cm->wlc;
+ char prev_country_abbrev[BRCM_CNTRY_BUF_SZ];
+
+ /* save current country state */
+ wlc_cm->country = country;
+
+ memset(&prev_country_abbrev, 0, BRCM_CNTRY_BUF_SZ);
+ strncpy(prev_country_abbrev, wlc_cm->country_abbrev,
+ BRCM_CNTRY_BUF_SZ - 1);
+
+ strncpy(wlc_cm->country_abbrev, country_abbrev, BRCM_CNTRY_BUF_SZ - 1);
+ strncpy(wlc_cm->ccode, ccode, BRCM_CNTRY_BUF_SZ - 1);
+ wlc_cm->regrev = regrev;
+
+ if ((wlc->pub->_n_enab & SUPPORT_11N) !=
+ wlc->protection->nmode_user)
+ brcms_c_set_nmode(wlc);
+
+ brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]);
+ brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]);
+ /* set or restore gmode as required by regulatory */
+ locale = brcms_c_get_locale_2g(country->locale_2G);
+ if (locale && (locale->flags & BRCMS_NO_OFDM))
+ brcms_c_set_gmode(wlc, GMODE_LEGACY_B, false);
+ else
+ brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);
+
+ brcms_c_channels_init(wlc_cm, country);
+
+ return;
+}
+
+static int
+brcms_c_set_countrycode_rev(struct brcms_cm_info *wlc_cm,
+ const char *country_abbrev,
+ const char *ccode, int regrev)
+{
+ const struct country_info *country;
+ char mapped_ccode[BRCM_CNTRY_BUF_SZ];
+ uint mapped_regrev;
+
+ /* if regrev is -1, lookup the mapped country code,
+ * otherwise use the ccode and regrev directly
+ */
+ if (regrev == -1) {
+ /*
+ * map the country code to a built-in country
+ * code, regrev, and country_info
+ */
+ country =
+ brcms_c_countrycode_map(wlc_cm, ccode, mapped_ccode,
+ &mapped_regrev);
+ } else {
+ /* find the matching built-in country definition */
+ country = brcms_c_country_lookup_direct(ccode, regrev);
+ strncpy(mapped_ccode, ccode, BRCM_CNTRY_BUF_SZ);
+ mapped_regrev = regrev;
+ }
+
+ if (country == NULL)
+ return -EINVAL;
+
+ /* set the driver state for the country */
+ brcms_c_set_country_common(wlc_cm, country_abbrev, mapped_ccode,
+ mapped_regrev, country);
+
+ return 0;
+}
+
+/*
+ * set the driver's current country and regulatory information using
+ * a country code as the source. Lookup built in country information
+ * found with the country code.
+ */
+static int
+brcms_c_set_countrycode(struct brcms_cm_info *wlc_cm, const char *ccode)
+{
+ char country_abbrev[BRCM_CNTRY_BUF_SZ];
+ strncpy(country_abbrev, ccode, BRCM_CNTRY_BUF_SZ);
+ return brcms_c_set_countrycode_rev(wlc_cm, country_abbrev, ccode, -1);
+}
+
+struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
+{
+ struct brcms_cm_info *wlc_cm;
+ char country_abbrev[BRCM_CNTRY_BUF_SZ];
+ const struct country_info *country;
+ struct brcms_pub *pub = wlc->pub;
+ char *ccode;
+
+ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+
+ wlc_cm = kzalloc(sizeof(struct brcms_cm_info), GFP_ATOMIC);
+ if (wlc_cm == NULL)
+ return NULL;
+ wlc_cm->pub = pub;
+ wlc_cm->wlc = wlc;
+ wlc->cmi = wlc_cm;
+
+ /* store the country code for passing up as a regulatory hint */
+ ccode = getvar(wlc->hw->sih, BRCMS_SROM_CCODE);
+ if (ccode)
+ strncpy(wlc->pub->srom_ccode, ccode, BRCM_CNTRY_BUF_SZ - 1);
+
+ /*
+ * internal country information which must match
+ * regulatory constraints in firmware
+ */
+ memset(country_abbrev, 0, BRCM_CNTRY_BUF_SZ);
+ strncpy(country_abbrev, "X2", sizeof(country_abbrev) - 1);
+ country = brcms_c_country_lookup(wlc, country_abbrev);
+
+ /* save default country for exiting 11d regulatory mode */
+ strncpy(wlc->country_default, country_abbrev, BRCM_CNTRY_BUF_SZ - 1);
+
+ /* initialize autocountry_default to driver default */
+ strncpy(wlc->autocountry_default, "X2", BRCM_CNTRY_BUF_SZ - 1);
+
+ brcms_c_set_countrycode(wlc_cm, country_abbrev);
+
+ return wlc_cm;
+}
+
+void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm)
+{
+ kfree(wlc_cm);
+}
+
+u8
+brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm,
+ uint bandunit)
+{
+ return wlc_cm->bandstate[bandunit].locale_flags;
+}
+
+static bool
+brcms_c_quiet_chanspec(struct brcms_cm_info *wlc_cm, u16 chspec)
+{
+ return (wlc_cm->wlc->pub->_n_enab & SUPPORT_11N) &&
+ CHSPEC_IS40(chspec) ?
+ (isset(wlc_cm->quiet_channels.vec,
+ lower_20_sb(CHSPEC_CHANNEL(chspec))) ||
+ isset(wlc_cm->quiet_channels.vec,
+ upper_20_sb(CHSPEC_CHANNEL(chspec)))) :
+ isset(wlc_cm->quiet_channels.vec, CHSPEC_CHANNEL(chspec));
+}
+
+void
+brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
+ u8 local_constraint_qdbm)
+{
+ struct brcms_c_info *wlc = wlc_cm->wlc;
+ struct txpwr_limits txpwr;
+
+ brcms_c_channel_reg_limits(wlc_cm, chanspec, &txpwr);
+
+ brcms_c_channel_min_txpower_limits_with_local_constraint(
+ wlc_cm, &txpwr, local_constraint_qdbm
+ );
+
+ brcms_b_set_chanspec(wlc->hw, chanspec,
+ (brcms_c_quiet_chanspec(wlc_cm, chanspec) != 0),
+ &txpwr);
+}
+
+#ifdef POWER_DBG
+static void wlc_phy_txpower_limits_dump(struct txpwr_limits *txpwr)
+{
+ int i;
+ char buf[80];
+ char fraction[4][4] = { " ", ".25", ".5 ", ".75" };
+
+ sprintf(buf, "CCK ");
+ for (i = 0; i < BRCMS_NUM_RATES_CCK; i++)
+ sprintf(buf[strlen(buf)], " %2d%s",
+ txpwr->cck[i] / BRCMS_TXPWR_DB_FACTOR,
+ fraction[txpwr->cck[i] % BRCMS_TXPWR_DB_FACTOR]);
+ printk(KERN_DEBUG "%s\n", buf);
+
+ sprintf(buf, "20 MHz OFDM SISO ");
+ for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
+ sprintf(buf[strlen(buf)], " %2d%s",
+ txpwr->ofdm[i] / BRCMS_TXPWR_DB_FACTOR,
+ fraction[txpwr->ofdm[i] % BRCMS_TXPWR_DB_FACTOR]);
+ printk(KERN_DEBUG "%s\n", buf);
+
+ sprintf(buf, "20 MHz OFDM CDD ");
+ for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
+ sprintf(buf[strlen(buf)], " %2d%s",
+ txpwr->ofdm_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
+ fraction[txpwr->ofdm_cdd[i] % BRCMS_TXPWR_DB_FACTOR]);
+ printk(KERN_DEBUG "%s\n", buf);
+
+ sprintf(buf, "40 MHz OFDM SISO ");
+ for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
+ sprintf(buf[strlen(buf)], " %2d%s",
+ txpwr->ofdm_40_siso[i] / BRCMS_TXPWR_DB_FACTOR,
+ fraction[txpwr->ofdm_40_siso[i] %
+ BRCMS_TXPWR_DB_FACTOR]);
+ printk(KERN_DEBUG "%s\n", buf);
+
+ sprintf(buf, "40 MHz OFDM CDD ");
+ for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
+ sprintf(buf[strlen(buf)], " %2d%s",
+ txpwr->ofdm_40_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
+ fraction[txpwr->ofdm_40_cdd[i] %
+ BRCMS_TXPWR_DB_FACTOR]);
+ printk(KERN_DEBUG "%s\n", buf);
+
+ sprintf(buf, "20 MHz MCS0-7 SISO ");
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
+ sprintf(buf[strlen(buf)], " %2d%s",
+ txpwr->mcs_20_siso[i] / BRCMS_TXPWR_DB_FACTOR,
+ fraction[txpwr->mcs_20_siso[i] %
+ BRCMS_TXPWR_DB_FACTOR]);
+ printk(KERN_DEBUG "%s\n", buf);
+
+ sprintf(buf, "20 MHz MCS0-7 CDD ");
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
+ sprintf(buf[strlen(buf)], " %2d%s",
+ txpwr->mcs_20_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
+ fraction[txpwr->mcs_20_cdd[i] %
+ BRCMS_TXPWR_DB_FACTOR]);
+ printk(KERN_DEBUG "%s\n", buf);
+
+ sprintf(buf, "20 MHz MCS0-7 STBC ");
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
+ sprintf(buf[strlen(buf)], " %2d%s",
+ txpwr->mcs_20_stbc[i] / BRCMS_TXPWR_DB_FACTOR,
+ fraction[txpwr->mcs_20_stbc[i] %
+ BRCMS_TXPWR_DB_FACTOR]);
+ printk(KERN_DEBUG "%s\n", buf);
+
+ sprintf(buf, "20 MHz MCS8-15 SDM ");
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++)
+ sprintf(buf[strlen(buf)], " %2d%s",
+ txpwr->mcs_20_mimo[i] / BRCMS_TXPWR_DB_FACTOR,
+ fraction[txpwr->mcs_20_mimo[i] %
+ BRCMS_TXPWR_DB_FACTOR]);
+ printk(KERN_DEBUG "%s\n", buf);
+
+ sprintf(buf, "40 MHz MCS0-7 SISO ");
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
+ sprintf(buf[strlen(buf)], " %2d%s",
+ txpwr->mcs_40_siso[i] / BRCMS_TXPWR_DB_FACTOR,
+ fraction[txpwr->mcs_40_siso[i] %
+ BRCMS_TXPWR_DB_FACTOR]);
+ printk(KERN_DEBUG "%s\n", buf);
+
+ sprintf(buf, "40 MHz MCS0-7 CDD ");
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
+ sprintf(buf[strlen(buf)], " %2d%s",
+ txpwr->mcs_40_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
+ fraction[txpwr->mcs_40_cdd[i] %
+ BRCMS_TXPWR_DB_FACTOR]);
+ printk(KERN_DEBUG "%s\n", buf);
+
+ sprintf(buf, "40 MHz MCS0-7 STBC ");
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
+ sprintf(buf[strlen(buf)], " %2d%s",
+ txpwr->mcs_40_stbc[i] / BRCMS_TXPWR_DB_FACTOR,
+ fraction[txpwr->mcs_40_stbc[i] %
+ BRCMS_TXPWR_DB_FACTOR]);
+ printk(KERN_DEBUG "%s\n", buf);
+
+ sprintf(buf, "40 MHz MCS8-15 SDM ");
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++)
+ sprintf(buf[strlen(buf)], " %2d%s",
+ txpwr->mcs_40_mimo[i] / BRCMS_TXPWR_DB_FACTOR,
+ fraction[txpwr->mcs_40_mimo[i] %
+ BRCMS_TXPWR_DB_FACTOR]);
+ }
+ printk(KERN_DEBUG "%s\n", buf);
+
+ printk(KERN_DEBUG "MCS32 %2d%s\n",
+ txpwr->mcs32 / BRCMS_TXPWR_DB_FACTOR,
+ fraction[txpwr->mcs32 % BRCMS_TXPWR_DB_FACTOR]);
+}
+#endif /* POWER_DBG */
+
+void
+brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
+ struct txpwr_limits *txpwr)
+{
+ struct brcms_c_info *wlc = wlc_cm->wlc;
+ uint i;
+ uint chan;
+ int maxpwr;
+ int delta;
+ const struct country_info *country;
+ struct brcms_band *band;
+ const struct locale_info *li;
+ int conducted_max = BRCMS_TXPWR_MAX;
+ int conducted_ofdm_max = BRCMS_TXPWR_MAX;
+ const struct locale_mimo_info *li_mimo;
+ int maxpwr20, maxpwr40;
+ int maxpwr_idx;
+ uint j;
+
+ memset(txpwr, 0, sizeof(struct txpwr_limits));
+
+ if (!brcms_c_valid_chanspec_db(wlc_cm, chanspec)) {
+ country = brcms_c_country_lookup(wlc, wlc->autocountry_default);
+ if (country == NULL)
+ return;
+ } else {
+ country = wlc_cm->country;
+ }
+
+ chan = CHSPEC_CHANNEL(chanspec);
+ band = wlc->bandstate[chspec_bandunit(chanspec)];
+ li = (band->bandtype == BRCM_BAND_5G) ?
+ brcms_c_get_locale_5g(country->locale_5G) :
+ brcms_c_get_locale_2g(country->locale_2G);
+
+ li_mimo = (band->bandtype == BRCM_BAND_5G) ?
+ brcms_c_get_mimo_5g(country->locale_mimo_5G) :
+ brcms_c_get_mimo_2g(country->locale_mimo_2G);
+
+ if (li->flags & BRCMS_EIRP) {
+ delta = band->antgain;
+ } else {
+ delta = 0;
+ if (band->antgain > QDB(6))
+ delta = band->antgain - QDB(6); /* Excess over 6 dB */
+ }
+
+ if (li == &locale_i) {
+ conducted_max = QDB(22);
+ conducted_ofdm_max = QDB(22);
+ }
+
+ /* CCK txpwr limits for 2.4G band */
+ if (band->bandtype == BRCM_BAND_2G) {
+ maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_CCK(chan)];
+
+ maxpwr = maxpwr - delta;
+ maxpwr = max(maxpwr, 0);
+ maxpwr = min(maxpwr, conducted_max);
+
+ for (i = 0; i < BRCMS_NUM_RATES_CCK; i++)
+ txpwr->cck[i] = (u8) maxpwr;
+ }
+
+ /* OFDM txpwr limits for 2.4G or 5G bands */
+ if (band->bandtype == BRCM_BAND_2G)
+ maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_OFDM(chan)];
+ else
+ maxpwr = li->maxpwr[CHANNEL_POWER_IDX_5G(chan)];
+
+ maxpwr = maxpwr - delta;
+ maxpwr = max(maxpwr, 0);
+ maxpwr = min(maxpwr, conducted_ofdm_max);
+
+ /* Keep OFDM lmit below CCK limit */
+ if (band->bandtype == BRCM_BAND_2G)
+ maxpwr = min_t(int, maxpwr, txpwr->cck[0]);
+
+ for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
+ txpwr->ofdm[i] = (u8) maxpwr;
+
+ for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {
+ /*
+ * OFDM 40 MHz SISO has the same power as the corresponding
+ * MCS0-7 rate unless overriden by the locale specific code.
+ * We set this value to 0 as a flag (presumably 0 dBm isn't
+ * a possibility) and then copy the MCS0-7 value to the 40 MHz
+ * value if it wasn't explicitly set.
+ */
+ txpwr->ofdm_40_siso[i] = 0;
+
+ txpwr->ofdm_cdd[i] = (u8) maxpwr;
+
+ txpwr->ofdm_40_cdd[i] = 0;
+ }
+
+ /* MIMO/HT specific limits */
+ if (li_mimo->flags & BRCMS_EIRP) {
+ delta = band->antgain;
+ } else {
+ delta = 0;
+ if (band->antgain > QDB(6))
+ delta = band->antgain - QDB(6); /* Excess over 6 dB */
+ }
+
+ if (band->bandtype == BRCM_BAND_2G)
+ maxpwr_idx = (chan - 1);
+ else
+ maxpwr_idx = CHANNEL_POWER_IDX_5G(chan);
+
+ maxpwr20 = li_mimo->maxpwr20[maxpwr_idx];
+ maxpwr40 = li_mimo->maxpwr40[maxpwr_idx];
+
+ maxpwr20 = maxpwr20 - delta;
+ maxpwr20 = max(maxpwr20, 0);
+ maxpwr40 = maxpwr40 - delta;
+ maxpwr40 = max(maxpwr40, 0);
+
+ /* Fill in the MCS 0-7 (SISO) rates */
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
+
+ /*
+ * 20 MHz has the same power as the corresponding OFDM rate
+ * unless overriden by the locale specific code.
+ */
+ txpwr->mcs_20_siso[i] = txpwr->ofdm[i];
+ txpwr->mcs_40_siso[i] = 0;
+ }
+
+ /* Fill in the MCS 0-7 CDD rates */
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
+ txpwr->mcs_20_cdd[i] = (u8) maxpwr20;
+ txpwr->mcs_40_cdd[i] = (u8) maxpwr40;
+ }
+
+ /*
+ * These locales have SISO expressed in the
+ * table and override CDD later
+ */
+ if (li_mimo == &locale_bn) {
+ if (li_mimo == &locale_bn) {
+ maxpwr20 = QDB(16);
+ maxpwr40 = 0;
+
+ if (chan >= 3 && chan <= 11)
+ maxpwr40 = QDB(16);
+ }
+
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
+ txpwr->mcs_20_siso[i] = (u8) maxpwr20;
+ txpwr->mcs_40_siso[i] = (u8) maxpwr40;
+ }
+ }
+
+ /* Fill in the MCS 0-7 STBC rates */
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
+ txpwr->mcs_20_stbc[i] = 0;
+ txpwr->mcs_40_stbc[i] = 0;
+ }
+
+ /* Fill in the MCS 8-15 SDM rates */
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++) {
+ txpwr->mcs_20_mimo[i] = (u8) maxpwr20;
+ txpwr->mcs_40_mimo[i] = (u8) maxpwr40;
+ }
+
+ /* Fill in MCS32 */
+ txpwr->mcs32 = (u8) maxpwr40;
+
+ for (i = 0, j = 0; i < BRCMS_NUM_RATES_OFDM; i++, j++) {
+ if (txpwr->ofdm_40_cdd[i] == 0)
+ txpwr->ofdm_40_cdd[i] = txpwr->mcs_40_cdd[j];
+ if (i == 0) {
+ i = i + 1;
+ if (txpwr->ofdm_40_cdd[i] == 0)
+ txpwr->ofdm_40_cdd[i] = txpwr->mcs_40_cdd[j];
+ }
+ }
+
+ /*
+ * Copy the 40 MHZ MCS 0-7 CDD value to the 40 MHZ MCS 0-7 SISO
+ * value if it wasn't provided explicitly.
+ */
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
+ if (txpwr->mcs_40_siso[i] == 0)
+ txpwr->mcs_40_siso[i] = txpwr->mcs_40_cdd[i];
+ }
+
+ for (i = 0, j = 0; i < BRCMS_NUM_RATES_OFDM; i++, j++) {
+ if (txpwr->ofdm_40_siso[i] == 0)
+ txpwr->ofdm_40_siso[i] = txpwr->mcs_40_siso[j];
+ if (i == 0) {
+ i = i + 1;
+ if (txpwr->ofdm_40_siso[i] == 0)
+ txpwr->ofdm_40_siso[i] = txpwr->mcs_40_siso[j];
+ }
+ }
+
+ /*
+ * Copy the 20 and 40 MHz MCS0-7 CDD values to the corresponding
+ * STBC values if they weren't provided explicitly.
+ */
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
+ if (txpwr->mcs_20_stbc[i] == 0)
+ txpwr->mcs_20_stbc[i] = txpwr->mcs_20_cdd[i];
+
+ if (txpwr->mcs_40_stbc[i] == 0)
+ txpwr->mcs_40_stbc[i] = txpwr->mcs_40_cdd[i];
+ }
+
+#ifdef POWER_DBG
+ wlc_phy_txpower_limits_dump(txpwr);
+#endif
+ return;
+}
+
+/*
+ * Verify the chanspec is using a legal set of parameters, i.e. that the
+ * chanspec specified a band, bw, ctl_sb and channel and that the
+ * combination could be legal given any set of circumstances.
+ * RETURNS: true is the chanspec is malformed, false if it looks good.
+ */
+static bool brcms_c_chspec_malformed(u16 chanspec)
+{
+ /* must be 2G or 5G band */
+ if (!CHSPEC_IS5G(chanspec) && !CHSPEC_IS2G(chanspec))
+ return true;
+ /* must be 20 or 40 bandwidth */
+ if (!CHSPEC_IS40(chanspec) && !CHSPEC_IS20(chanspec))
+ return true;
+
+ /* 20MHZ b/w must have no ctl sb, 40 must have a ctl sb */
+ if (CHSPEC_IS20(chanspec)) {
+ if (!CHSPEC_SB_NONE(chanspec))
+ return true;
+ } else if (!CHSPEC_SB_UPPER(chanspec) && !CHSPEC_SB_LOWER(chanspec)) {
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Validate the chanspec for this locale, for 40MHZ we need to also
+ * check that the sidebands are valid 20MZH channels in this locale
+ * and they are also a legal HT combination
+ */
+static bool
+brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec,
+ bool dualband)
+{
+ struct brcms_c_info *wlc = wlc_cm->wlc;
+ u8 channel = CHSPEC_CHANNEL(chspec);
+
+ /* check the chanspec */
+ if (brcms_c_chspec_malformed(chspec)) {
+ wiphy_err(wlc->wiphy, "wl%d: malformed chanspec 0x%x\n",
+ wlc->pub->unit, chspec);
+ return false;
+ }
+
+ if (CHANNEL_BANDUNIT(wlc_cm->wlc, channel) !=
+ chspec_bandunit(chspec))
+ return false;
+
+ /* Check a 20Mhz channel */
+ if (CHSPEC_IS20(chspec)) {
+ if (dualband)
+ return brcms_c_valid_channel20_db(wlc_cm->wlc->cmi,
+ channel);
+ else
+ return brcms_c_valid_channel20(wlc_cm->wlc->cmi,
+ channel);
+ }
+#ifdef SUPPORT_40MHZ
+ /*
+ * We know we are now checking a 40MHZ channel, so we should
+ * only be here for NPHYS
+ */
+ if (BRCMS_ISNPHY(wlc->band) || BRCMS_ISSSLPNPHY(wlc->band)) {
+ u8 upper_sideband = 0, idx;
+ u8 num_ch20_entries =
+ sizeof(chan20_info) / sizeof(struct chan20_info);
+
+ if (!VALID_40CHANSPEC_IN_BAND(wlc, chspec_bandunit(chspec)))
+ return false;
+
+ if (dualband) {
+ if (!brcms_c_valid_channel20_db(wlc->cmi,
+ lower_20_sb(channel)) ||
+ !brcms_c_valid_channel20_db(wlc->cmi,
+ upper_20_sb(channel)))
+ return false;
+ } else {
+ if (!brcms_c_valid_channel20(wlc->cmi,
+ lower_20_sb(channel)) ||
+ !brcms_c_valid_channel20(wlc->cmi,
+ upper_20_sb(channel)))
+ return false;
+ }
+
+ /* find the lower sideband info in the sideband array */
+ for (idx = 0; idx < num_ch20_entries; idx++) {
+ if (chan20_info[idx].sb == lower_20_sb(channel))
+ upper_sideband = chan20_info[idx].adj_sbs;
+ }
+ /* check that the lower sideband allows an upper sideband */
+ if ((upper_sideband & (CH_UPPER_SB | CH_EWA_VALID)) ==
+ (CH_UPPER_SB | CH_EWA_VALID))
+ return true;
+ return false;
+ }
+#endif /* 40 MHZ */
+
+ return false;
+}
+
+bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, u16 chspec)
+{
+ return brcms_c_valid_chanspec_ext(wlc_cm, chspec, true);
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.h b/drivers/net/wireless/brcm80211/brcmsmac/channel.h
new file mode 100644
index 000000000000..808cb4fbfbe7
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_CHANNEL_H_
+#define _BRCM_CHANNEL_H_
+
+/* conversion for phy txpwr calculations that use .25 dB units */
+#define BRCMS_TXPWR_DB_FACTOR 4
+
+/* bits for locale_info flags */
+#define BRCMS_PEAK_CONDUCTED 0x00 /* Peak for locals */
+#define BRCMS_EIRP 0x01 /* Flag for EIRP */
+#define BRCMS_DFS_TPC 0x02 /* Flag for DFS TPC */
+#define BRCMS_NO_OFDM 0x04 /* Flag for No OFDM */
+#define BRCMS_NO_40MHZ 0x08 /* Flag for No MIMO 40MHz */
+#define BRCMS_NO_MIMO 0x10 /* Flag for No MIMO, 20 or 40 MHz */
+#define BRCMS_RADAR_TYPE_EU 0x20 /* Flag for EU */
+#define BRCMS_DFS_FCC BRCMS_DFS_TPC /* Flag for DFS FCC */
+
+#define BRCMS_DFS_EU (BRCMS_DFS_TPC | BRCMS_RADAR_TYPE_EU) /* Flag for DFS EU */
+
+extern struct brcms_cm_info *
+brcms_c_channel_mgr_attach(struct brcms_c_info *wlc);
+
+extern void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm);
+
+extern u8 brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm,
+ uint bandunit);
+
+extern bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm,
+ u16 chspec);
+
+extern void brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm,
+ u16 chanspec,
+ struct txpwr_limits *txpwr);
+extern void brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm,
+ u16 chanspec,
+ u8 local_constraint_qdbm);
+
+#endif /* _WLC_CHANNEL_H */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/d11.h b/drivers/net/wireless/brcm80211/brcmsmac/d11.h
new file mode 100644
index 000000000000..ed51616abc85
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/d11.h
@@ -0,0 +1,1898 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_D11_H_
+#define _BRCM_D11_H_
+
+#include <linux/ieee80211.h>
+
+#include <defs.h>
+#include "pub.h"
+#include "dma.h"
+
+/* RX FIFO numbers */
+#define RX_FIFO 0 /* data and ctl frames */
+#define RX_TXSTATUS_FIFO 3 /* RX fifo for tx status packages */
+
+/* TX FIFO numbers using WME Access Category */
+#define TX_AC_BK_FIFO 0 /* Background TX FIFO */
+#define TX_AC_BE_FIFO 1 /* Best-Effort TX FIFO */
+#define TX_AC_VI_FIFO 2 /* Video TX FIFO */
+#define TX_AC_VO_FIFO 3 /* Voice TX FIFO */
+#define TX_BCMC_FIFO 4 /* Broadcast/Multicast TX FIFO */
+#define TX_ATIM_FIFO 5 /* TX fifo for ATIM window info */
+
+/* Addr is byte address used by SW; offset is word offset used by uCode */
+
+/* Per AC TX limit settings */
+#define M_AC_TXLMT_BASE_ADDR (0x180 * 2)
+#define M_AC_TXLMT_ADDR(_ac) (M_AC_TXLMT_BASE_ADDR + (2 * (_ac)))
+
+/* Legacy TX FIFO numbers */
+#define TX_DATA_FIFO TX_AC_BE_FIFO
+#define TX_CTL_FIFO TX_AC_VO_FIFO
+
+#define WL_RSSI_ANT_MAX 4 /* max possible rx antennas */
+
+struct intctrlregs {
+ u32 intstatus;
+ u32 intmask;
+};
+
+/* PIO structure,
+ * support two PIO format: 2 bytes access and 4 bytes access
+ * basic FIFO register set is per channel(transmit or receive)
+ * a pair of channels is defined for convenience
+ */
+/* 2byte-wide pio register set per channel(xmt or rcv) */
+struct pio2regs {
+ u16 fifocontrol;
+ u16 fifodata;
+ u16 fifofree; /* only valid in xmt channel, not in rcv channel */
+ u16 PAD;
+};
+
+/* a pair of pio channels(tx and rx) */
+struct pio2regp {
+ struct pio2regs tx;
+ struct pio2regs rx;
+};
+
+/* 4byte-wide pio register set per channel(xmt or rcv) */
+struct pio4regs {
+ u32 fifocontrol;
+ u32 fifodata;
+};
+
+/* a pair of pio channels(tx and rx) */
+struct pio4regp {
+ struct pio4regs tx;
+ struct pio4regs rx;
+};
+
+/* read: 32-bit register that can be read as 32-bit or as 2 16-bit
+ * write: only low 16b-it half can be written
+ */
+union pmqreg {
+ u32 pmqhostdata; /* read only! */
+ struct {
+ u16 pmqctrlstatus; /* read/write */
+ u16 PAD;
+ } w;
+};
+
+struct fifo64 {
+ struct dma64regs dmaxmt; /* dma tx */
+ struct pio4regs piotx; /* pio tx */
+ struct dma64regs dmarcv; /* dma rx */
+ struct pio4regs piorx; /* pio rx */
+};
+
+/*
+ * Host Interface Registers
+ */
+struct d11regs {
+ /* Device Control ("semi-standard host registers") */
+ u32 PAD[3]; /* 0x0 - 0x8 */
+ u32 biststatus; /* 0xC */
+ u32 biststatus2; /* 0x10 */
+ u32 PAD; /* 0x14 */
+ u32 gptimer; /* 0x18 */
+ u32 usectimer; /* 0x1c *//* for corerev >= 26 */
+
+ /* Interrupt Control *//* 0x20 */
+ struct intctrlregs intctrlregs[8];
+
+ u32 PAD[40]; /* 0x60 - 0xFC */
+
+ u32 intrcvlazy[4]; /* 0x100 - 0x10C */
+
+ u32 PAD[4]; /* 0x110 - 0x11c */
+
+ u32 maccontrol; /* 0x120 */
+ u32 maccommand; /* 0x124 */
+ u32 macintstatus; /* 0x128 */
+ u32 macintmask; /* 0x12C */
+
+ /* Transmit Template Access */
+ u32 tplatewrptr; /* 0x130 */
+ u32 tplatewrdata; /* 0x134 */
+ u32 PAD[2]; /* 0x138 - 0x13C */
+
+ /* PMQ registers */
+ union pmqreg pmqreg; /* 0x140 */
+ u32 pmqpatl; /* 0x144 */
+ u32 pmqpath; /* 0x148 */
+ u32 PAD; /* 0x14C */
+
+ u32 chnstatus; /* 0x150 */
+ u32 psmdebug; /* 0x154 */
+ u32 phydebug; /* 0x158 */
+ u32 machwcap; /* 0x15C */
+
+ /* Extended Internal Objects */
+ u32 objaddr; /* 0x160 */
+ u32 objdata; /* 0x164 */
+ u32 PAD[2]; /* 0x168 - 0x16c */
+
+ u32 frmtxstatus; /* 0x170 */
+ u32 frmtxstatus2; /* 0x174 */
+ u32 PAD[2]; /* 0x178 - 0x17c */
+
+ /* TSF host access */
+ u32 tsf_timerlow; /* 0x180 */
+ u32 tsf_timerhigh; /* 0x184 */
+ u32 tsf_cfprep; /* 0x188 */
+ u32 tsf_cfpstart; /* 0x18c */
+ u32 tsf_cfpmaxdur32; /* 0x190 */
+ u32 PAD[3]; /* 0x194 - 0x19c */
+
+ u32 maccontrol1; /* 0x1a0 */
+ u32 machwcap1; /* 0x1a4 */
+ u32 PAD[14]; /* 0x1a8 - 0x1dc */
+
+ /* Clock control and hardware workarounds*/
+ u32 clk_ctl_st; /* 0x1e0 */
+ u32 hw_war;
+ u32 d11_phypllctl; /* the phypll request/avail bits are
+ * moved to clk_ctl_st
+ */
+ u32 PAD[5]; /* 0x1ec - 0x1fc */
+
+ /* 0x200-0x37F dma/pio registers */
+ struct fifo64 fifo64regs[6];
+
+ /* FIFO diagnostic port access */
+ struct dma32diag dmafifo; /* 0x380 - 0x38C */
+
+ u32 aggfifocnt; /* 0x390 */
+ u32 aggfifodata; /* 0x394 */
+ u32 PAD[16]; /* 0x398 - 0x3d4 */
+ u16 radioregaddr; /* 0x3d8 */
+ u16 radioregdata; /* 0x3da */
+
+ /*
+ * time delay between the change on rf disable input and
+ * radio shutdown
+ */
+ u32 rfdisabledly; /* 0x3DC */
+
+ /* PHY register access */
+ u16 phyversion; /* 0x3e0 - 0x0 */
+ u16 phybbconfig; /* 0x3e2 - 0x1 */
+ u16 phyadcbias; /* 0x3e4 - 0x2 Bphy only */
+ u16 phyanacore; /* 0x3e6 - 0x3 pwwrdwn on aphy */
+ u16 phyrxstatus0; /* 0x3e8 - 0x4 */
+ u16 phyrxstatus1; /* 0x3ea - 0x5 */
+ u16 phycrsth; /* 0x3ec - 0x6 */
+ u16 phytxerror; /* 0x3ee - 0x7 */
+ u16 phychannel; /* 0x3f0 - 0x8 */
+ u16 PAD[1]; /* 0x3f2 - 0x9 */
+ u16 phytest; /* 0x3f4 - 0xa */
+ u16 phy4waddr; /* 0x3f6 - 0xb */
+ u16 phy4wdatahi; /* 0x3f8 - 0xc */
+ u16 phy4wdatalo; /* 0x3fa - 0xd */
+ u16 phyregaddr; /* 0x3fc - 0xe */
+ u16 phyregdata; /* 0x3fe - 0xf */
+
+ /* IHR *//* 0x400 - 0x7FE */
+
+ /* RXE Block */
+ u16 PAD[3]; /* 0x400 - 0x406 */
+ u16 rcv_fifo_ctl; /* 0x406 */
+ u16 PAD; /* 0x408 - 0x40a */
+ u16 rcv_frm_cnt; /* 0x40a */
+ u16 PAD[4]; /* 0x40a - 0x414 */
+ u16 rssi; /* 0x414 */
+ u16 PAD[5]; /* 0x414 - 0x420 */
+ u16 rcm_ctl; /* 0x420 */
+ u16 rcm_mat_data; /* 0x422 */
+ u16 rcm_mat_mask; /* 0x424 */
+ u16 rcm_mat_dly; /* 0x426 */
+ u16 rcm_cond_mask_l; /* 0x428 */
+ u16 rcm_cond_mask_h; /* 0x42A */
+ u16 rcm_cond_dly; /* 0x42C */
+ u16 PAD[1]; /* 0x42E */
+ u16 ext_ihr_addr; /* 0x430 */
+ u16 ext_ihr_data; /* 0x432 */
+ u16 rxe_phyrs_2; /* 0x434 */
+ u16 rxe_phyrs_3; /* 0x436 */
+ u16 phy_mode; /* 0x438 */
+ u16 rcmta_ctl; /* 0x43a */
+ u16 rcmta_size; /* 0x43c */
+ u16 rcmta_addr0; /* 0x43e */
+ u16 rcmta_addr1; /* 0x440 */
+ u16 rcmta_addr2; /* 0x442 */
+ u16 PAD[30]; /* 0x444 - 0x480 */
+
+ /* PSM Block *//* 0x480 - 0x500 */
+
+ u16 PAD; /* 0x480 */
+ u16 psm_maccontrol_h; /* 0x482 */
+ u16 psm_macintstatus_l; /* 0x484 */
+ u16 psm_macintstatus_h; /* 0x486 */
+ u16 psm_macintmask_l; /* 0x488 */
+ u16 psm_macintmask_h; /* 0x48A */
+ u16 PAD; /* 0x48C */
+ u16 psm_maccommand; /* 0x48E */
+ u16 psm_brc; /* 0x490 */
+ u16 psm_phy_hdr_param; /* 0x492 */
+ u16 psm_postcard; /* 0x494 */
+ u16 psm_pcard_loc_l; /* 0x496 */
+ u16 psm_pcard_loc_h; /* 0x498 */
+ u16 psm_gpio_in; /* 0x49A */
+ u16 psm_gpio_out; /* 0x49C */
+ u16 psm_gpio_oe; /* 0x49E */
+
+ u16 psm_bred_0; /* 0x4A0 */
+ u16 psm_bred_1; /* 0x4A2 */
+ u16 psm_bred_2; /* 0x4A4 */
+ u16 psm_bred_3; /* 0x4A6 */
+ u16 psm_brcl_0; /* 0x4A8 */
+ u16 psm_brcl_1; /* 0x4AA */
+ u16 psm_brcl_2; /* 0x4AC */
+ u16 psm_brcl_3; /* 0x4AE */
+ u16 psm_brpo_0; /* 0x4B0 */
+ u16 psm_brpo_1; /* 0x4B2 */
+ u16 psm_brpo_2; /* 0x4B4 */
+ u16 psm_brpo_3; /* 0x4B6 */
+ u16 psm_brwk_0; /* 0x4B8 */
+ u16 psm_brwk_1; /* 0x4BA */
+ u16 psm_brwk_2; /* 0x4BC */
+ u16 psm_brwk_3; /* 0x4BE */
+
+ u16 psm_base_0; /* 0x4C0 */
+ u16 psm_base_1; /* 0x4C2 */
+ u16 psm_base_2; /* 0x4C4 */
+ u16 psm_base_3; /* 0x4C6 */
+ u16 psm_base_4; /* 0x4C8 */
+ u16 psm_base_5; /* 0x4CA */
+ u16 psm_base_6; /* 0x4CC */
+ u16 psm_pc_reg_0; /* 0x4CE */
+ u16 psm_pc_reg_1; /* 0x4D0 */
+ u16 psm_pc_reg_2; /* 0x4D2 */
+ u16 psm_pc_reg_3; /* 0x4D4 */
+ u16 PAD[0xD]; /* 0x4D6 - 0x4DE */
+ u16 psm_corectlsts; /* 0x4f0 *//* Corerev >= 13 */
+ u16 PAD[0x7]; /* 0x4f2 - 0x4fE */
+
+ /* TXE0 Block *//* 0x500 - 0x580 */
+ u16 txe_ctl; /* 0x500 */
+ u16 txe_aux; /* 0x502 */
+ u16 txe_ts_loc; /* 0x504 */
+ u16 txe_time_out; /* 0x506 */
+ u16 txe_wm_0; /* 0x508 */
+ u16 txe_wm_1; /* 0x50A */
+ u16 txe_phyctl; /* 0x50C */
+ u16 txe_status; /* 0x50E */
+ u16 txe_mmplcp0; /* 0x510 */
+ u16 txe_mmplcp1; /* 0x512 */
+ u16 txe_phyctl1; /* 0x514 */
+
+ u16 PAD[0x05]; /* 0x510 - 0x51E */
+
+ /* Transmit control */
+ u16 xmtfifodef; /* 0x520 */
+ u16 xmtfifo_frame_cnt; /* 0x522 *//* Corerev >= 16 */
+ u16 xmtfifo_byte_cnt; /* 0x524 *//* Corerev >= 16 */
+ u16 xmtfifo_head; /* 0x526 *//* Corerev >= 16 */
+ u16 xmtfifo_rd_ptr; /* 0x528 *//* Corerev >= 16 */
+ u16 xmtfifo_wr_ptr; /* 0x52A *//* Corerev >= 16 */
+ u16 xmtfifodef1; /* 0x52C *//* Corerev >= 16 */
+
+ u16 PAD[0x09]; /* 0x52E - 0x53E */
+
+ u16 xmtfifocmd; /* 0x540 */
+ u16 xmtfifoflush; /* 0x542 */
+ u16 xmtfifothresh; /* 0x544 */
+ u16 xmtfifordy; /* 0x546 */
+ u16 xmtfifoprirdy; /* 0x548 */
+ u16 xmtfiforqpri; /* 0x54A */
+ u16 xmttplatetxptr; /* 0x54C */
+ u16 PAD; /* 0x54E */
+ u16 xmttplateptr; /* 0x550 */
+ u16 smpl_clct_strptr; /* 0x552 *//* Corerev >= 22 */
+ u16 smpl_clct_stpptr; /* 0x554 *//* Corerev >= 22 */
+ u16 smpl_clct_curptr; /* 0x556 *//* Corerev >= 22 */
+ u16 PAD[0x04]; /* 0x558 - 0x55E */
+ u16 xmttplatedatalo; /* 0x560 */
+ u16 xmttplatedatahi; /* 0x562 */
+
+ u16 PAD[2]; /* 0x564 - 0x566 */
+
+ u16 xmtsel; /* 0x568 */
+ u16 xmttxcnt; /* 0x56A */
+ u16 xmttxshmaddr; /* 0x56C */
+
+ u16 PAD[0x09]; /* 0x56E - 0x57E */
+
+ /* TXE1 Block */
+ u16 PAD[0x40]; /* 0x580 - 0x5FE */
+
+ /* TSF Block */
+ u16 PAD[0X02]; /* 0x600 - 0x602 */
+ u16 tsf_cfpstrt_l; /* 0x604 */
+ u16 tsf_cfpstrt_h; /* 0x606 */
+ u16 PAD[0X05]; /* 0x608 - 0x610 */
+ u16 tsf_cfppretbtt; /* 0x612 */
+ u16 PAD[0XD]; /* 0x614 - 0x62C */
+ u16 tsf_clk_frac_l; /* 0x62E */
+ u16 tsf_clk_frac_h; /* 0x630 */
+ u16 PAD[0X14]; /* 0x632 - 0x658 */
+ u16 tsf_random; /* 0x65A */
+ u16 PAD[0x05]; /* 0x65C - 0x664 */
+ /* GPTimer 2 registers */
+ u16 tsf_gpt2_stat; /* 0x666 */
+ u16 tsf_gpt2_ctr_l; /* 0x668 */
+ u16 tsf_gpt2_ctr_h; /* 0x66A */
+ u16 tsf_gpt2_val_l; /* 0x66C */
+ u16 tsf_gpt2_val_h; /* 0x66E */
+ u16 tsf_gptall_stat; /* 0x670 */
+ u16 PAD[0x07]; /* 0x672 - 0x67E */
+
+ /* IFS Block */
+ u16 ifs_sifs_rx_tx_tx; /* 0x680 */
+ u16 ifs_sifs_nav_tx; /* 0x682 */
+ u16 ifs_slot; /* 0x684 */
+ u16 PAD; /* 0x686 */
+ u16 ifs_ctl; /* 0x688 */
+ u16 PAD[0x3]; /* 0x68a - 0x68F */
+ u16 ifsstat; /* 0x690 */
+ u16 ifsmedbusyctl; /* 0x692 */
+ u16 iftxdur; /* 0x694 */
+ u16 PAD[0x3]; /* 0x696 - 0x69b */
+ /* EDCF support in dot11macs */
+ u16 ifs_aifsn; /* 0x69c */
+ u16 ifs_ctl1; /* 0x69e */
+
+ /* slow clock registers */
+ u16 scc_ctl; /* 0x6a0 */
+ u16 scc_timer_l; /* 0x6a2 */
+ u16 scc_timer_h; /* 0x6a4 */
+ u16 scc_frac; /* 0x6a6 */
+ u16 scc_fastpwrup_dly; /* 0x6a8 */
+ u16 scc_per; /* 0x6aa */
+ u16 scc_per_frac; /* 0x6ac */
+ u16 scc_cal_timer_l; /* 0x6ae */
+ u16 scc_cal_timer_h; /* 0x6b0 */
+ u16 PAD; /* 0x6b2 */
+
+ u16 PAD[0x26];
+
+ /* NAV Block */
+ u16 nav_ctl; /* 0x700 */
+ u16 navstat; /* 0x702 */
+ u16 PAD[0x3e]; /* 0x702 - 0x77E */
+
+ /* WEP/PMQ Block *//* 0x780 - 0x7FE */
+ u16 PAD[0x20]; /* 0x780 - 0x7BE */
+
+ u16 wepctl; /* 0x7C0 */
+ u16 wepivloc; /* 0x7C2 */
+ u16 wepivkey; /* 0x7C4 */
+ u16 wepwkey; /* 0x7C6 */
+
+ u16 PAD[4]; /* 0x7C8 - 0x7CE */
+ u16 pcmctl; /* 0X7D0 */
+ u16 pcmstat; /* 0X7D2 */
+ u16 PAD[6]; /* 0x7D4 - 0x7DE */
+
+ u16 pmqctl; /* 0x7E0 */
+ u16 pmqstatus; /* 0x7E2 */
+ u16 pmqpat0; /* 0x7E4 */
+ u16 pmqpat1; /* 0x7E6 */
+ u16 pmqpat2; /* 0x7E8 */
+
+ u16 pmqdat; /* 0x7EA */
+ u16 pmqdator; /* 0x7EC */
+ u16 pmqhst; /* 0x7EE */
+ u16 pmqpath0; /* 0x7F0 */
+ u16 pmqpath1; /* 0x7F2 */
+ u16 pmqpath2; /* 0x7F4 */
+ u16 pmqdath; /* 0x7F6 */
+
+ u16 PAD[0x04]; /* 0x7F8 - 0x7FE */
+
+ /* SHM *//* 0x800 - 0xEFE */
+ u16 PAD[0x380]; /* 0x800 - 0xEFE */
+};
+
+#define PIHR_BASE 0x0400 /* byte address of packed IHR region */
+
+/* biststatus */
+#define BT_DONE (1U << 31) /* bist done */
+#define BT_B2S (1 << 30) /* bist2 ram summary bit */
+
+/* intstatus and intmask */
+#define I_PC (1 << 10) /* pci descriptor error */
+#define I_PD (1 << 11) /* pci data error */
+#define I_DE (1 << 12) /* descriptor protocol error */
+#define I_RU (1 << 13) /* receive descriptor underflow */
+#define I_RO (1 << 14) /* receive fifo overflow */
+#define I_XU (1 << 15) /* transmit fifo underflow */
+#define I_RI (1 << 16) /* receive interrupt */
+#define I_XI (1 << 24) /* transmit interrupt */
+
+/* interrupt receive lazy */
+#define IRL_TO_MASK 0x00ffffff /* timeout */
+#define IRL_FC_MASK 0xff000000 /* frame count */
+#define IRL_FC_SHIFT 24 /* frame count */
+
+/*== maccontrol register ==*/
+#define MCTL_GMODE (1U << 31)
+#define MCTL_DISCARD_PMQ (1 << 30)
+#define MCTL_WAKE (1 << 26)
+#define MCTL_HPS (1 << 25)
+#define MCTL_PROMISC (1 << 24)
+#define MCTL_KEEPBADFCS (1 << 23)
+#define MCTL_KEEPCONTROL (1 << 22)
+#define MCTL_PHYLOCK (1 << 21)
+#define MCTL_BCNS_PROMISC (1 << 20)
+#define MCTL_LOCK_RADIO (1 << 19)
+#define MCTL_AP (1 << 18)
+#define MCTL_INFRA (1 << 17)
+#define MCTL_BIGEND (1 << 16)
+#define MCTL_GPOUT_SEL_MASK (3 << 14)
+#define MCTL_GPOUT_SEL_SHIFT 14
+#define MCTL_EN_PSMDBG (1 << 13)
+#define MCTL_IHR_EN (1 << 10)
+#define MCTL_SHM_UPPER (1 << 9)
+#define MCTL_SHM_EN (1 << 8)
+#define MCTL_PSM_JMP_0 (1 << 2)
+#define MCTL_PSM_RUN (1 << 1)
+#define MCTL_EN_MAC (1 << 0)
+
+/*== maccommand register ==*/
+#define MCMD_BCN0VLD (1 << 0)
+#define MCMD_BCN1VLD (1 << 1)
+#define MCMD_DIRFRMQVAL (1 << 2)
+#define MCMD_CCA (1 << 3)
+#define MCMD_BG_NOISE (1 << 4)
+#define MCMD_SKIP_SHMINIT (1 << 5) /* only used for simulation */
+#define MCMD_SAMPLECOLL MCMD_SKIP_SHMINIT /* reuse for sample collect */
+
+/*== macintstatus/macintmask ==*/
+/* gracefully suspended */
+#define MI_MACSSPNDD (1 << 0)
+/* beacon template available */
+#define MI_BCNTPL (1 << 1)
+/* TBTT indication */
+#define MI_TBTT (1 << 2)
+/* beacon successfully tx'd */
+#define MI_BCNSUCCESS (1 << 3)
+/* beacon canceled (IBSS) */
+#define MI_BCNCANCLD (1 << 4)
+/* end of ATIM-window (IBSS) */
+#define MI_ATIMWINEND (1 << 5)
+/* PMQ entries available */
+#define MI_PMQ (1 << 6)
+/* non-specific gen-stat bits that are set by PSM */
+#define MI_NSPECGEN_0 (1 << 7)
+/* non-specific gen-stat bits that are set by PSM */
+#define MI_NSPECGEN_1 (1 << 8)
+/* MAC level Tx error */
+#define MI_MACTXERR (1 << 9)
+/* non-specific gen-stat bits that are set by PSM */
+#define MI_NSPECGEN_3 (1 << 10)
+/* PHY Tx error */
+#define MI_PHYTXERR (1 << 11)
+/* Power Management Event */
+#define MI_PME (1 << 12)
+/* General-purpose timer0 */
+#define MI_GP0 (1 << 13)
+/* General-purpose timer1 */
+#define MI_GP1 (1 << 14)
+/* (ORed) DMA-interrupts */
+#define MI_DMAINT (1 << 15)
+/* MAC has completed a TX FIFO Suspend/Flush */
+#define MI_TXSTOP (1 << 16)
+/* MAC has completed a CCA measurement */
+#define MI_CCA (1 << 17)
+/* MAC has collected background noise samples */
+#define MI_BG_NOISE (1 << 18)
+/* MBSS DTIM TBTT indication */
+#define MI_DTIM_TBTT (1 << 19)
+/* Probe response queue needs attention */
+#define MI_PRQ (1 << 20)
+/* Radio/PHY has been powered back up. */
+#define MI_PWRUP (1 << 21)
+#define MI_RESERVED3 (1 << 22)
+#define MI_RESERVED2 (1 << 23)
+#define MI_RESERVED1 (1 << 25)
+/* MAC detected change on RF Disable input*/
+#define MI_RFDISABLE (1 << 28)
+/* MAC has completed a TX */
+#define MI_TFS (1 << 29)
+/* A phy status change wrt G mode */
+#define MI_PHYCHANGED (1 << 30)
+/* general purpose timeout */
+#define MI_TO (1U << 31)
+
+/* Mac capabilities registers */
+/*== machwcap ==*/
+#define MCAP_TKIPMIC 0x80000000 /* TKIP MIC hardware present */
+
+/*== pmqhost data ==*/
+/* data entry of head pmq entry */
+#define PMQH_DATA_MASK 0xffff0000
+/* PM entry for BSS config */
+#define PMQH_BSSCFG 0x00100000
+/* PM Mode OFF: power save off */
+#define PMQH_PMOFF 0x00010000
+/* PM Mode ON: power save on */
+#define PMQH_PMON 0x00020000
+/* Dis-associated or De-authenticated */
+#define PMQH_DASAT 0x00040000
+/* ATIM not acknowledged */
+#define PMQH_ATIMFAIL 0x00080000
+/* delete head entry */
+#define PMQH_DEL_ENTRY 0x00000001
+/* delete head entry to cur read pointer -1 */
+#define PMQH_DEL_MULT 0x00000002
+/* pmq overflow indication */
+#define PMQH_OFLO 0x00000004
+/* entries are present in pmq */
+#define PMQH_NOT_EMPTY 0x00000008
+
+/*== phydebug ==*/
+/* phy is asserting carrier sense */
+#define PDBG_CRS (1 << 0)
+/* phy is taking xmit byte from mac this cycle */
+#define PDBG_TXA (1 << 1)
+/* mac is instructing the phy to transmit a frame */
+#define PDBG_TXF (1 << 2)
+/* phy is signalling a transmit Error to the mac */
+#define PDBG_TXE (1 << 3)
+/* phy detected the end of a valid frame preamble */
+#define PDBG_RXF (1 << 4)
+/* phy detected the end of a valid PLCP header */
+#define PDBG_RXS (1 << 5)
+/* rx start not asserted */
+#define PDBG_RXFRG (1 << 6)
+/* mac is taking receive byte from phy this cycle */
+#define PDBG_RXV (1 << 7)
+/* RF portion of the radio is disabled */
+#define PDBG_RFD (1 << 16)
+
+/*== objaddr register ==*/
+#define OBJADDR_SEL_MASK 0x000F0000
+#define OBJADDR_UCM_SEL 0x00000000
+#define OBJADDR_SHM_SEL 0x00010000
+#define OBJADDR_SCR_SEL 0x00020000
+#define OBJADDR_IHR_SEL 0x00030000
+#define OBJADDR_RCMTA_SEL 0x00040000
+#define OBJADDR_SRCHM_SEL 0x00060000
+#define OBJADDR_WINC 0x01000000
+#define OBJADDR_RINC 0x02000000
+#define OBJADDR_AUTO_INC 0x03000000
+
+#define WEP_PCMADDR 0x07d4
+#define WEP_PCMDATA 0x07d6
+
+/*== frmtxstatus ==*/
+#define TXS_V (1 << 0) /* valid bit */
+#define TXS_STATUS_MASK 0xffff
+#define TXS_FID_MASK 0xffff0000
+#define TXS_FID_SHIFT 16
+
+/*== frmtxstatus2 ==*/
+#define TXS_SEQ_MASK 0xffff
+#define TXS_PTX_MASK 0xff0000
+#define TXS_PTX_SHIFT 16
+#define TXS_MU_MASK 0x01000000
+#define TXS_MU_SHIFT 24
+
+/*== clk_ctl_st ==*/
+#define CCS_ERSRC_REQ_D11PLL 0x00000100 /* d11 core pll request */
+#define CCS_ERSRC_REQ_PHYPLL 0x00000200 /* PHY pll request */
+#define CCS_ERSRC_AVAIL_D11PLL 0x01000000 /* d11 core pll available */
+#define CCS_ERSRC_AVAIL_PHYPLL 0x02000000 /* PHY pll available */
+
+/* HT Cloclk Ctrl and Clock Avail for 4313 */
+#define CCS_ERSRC_REQ_HT 0x00000010 /* HT avail request */
+#define CCS_ERSRC_AVAIL_HT 0x00020000 /* HT clock available */
+
+/* tsf_cfprep register */
+#define CFPREP_CBI_MASK 0xffffffc0
+#define CFPREP_CBI_SHIFT 6
+#define CFPREP_CFPP 0x00000001
+
+/* tx fifo sizes values are in terms of 256 byte blocks */
+#define TXFIFOCMD_RESET_MASK (1 << 15) /* reset */
+#define TXFIFOCMD_FIFOSEL_SHIFT 8 /* fifo */
+#define TXFIFO_FIFOTOP_SHIFT 8 /* fifo start */
+
+#define TXFIFO_START_BLK16 65 /* Base address + 32 * 512 B/P */
+#define TXFIFO_START_BLK 6 /* Base address + 6 * 256 B */
+#define TXFIFO_SIZE_UNIT 256 /* one unit corresponds to 256 bytes */
+#define MBSS16_TEMPLMEM_MINBLKS 65 /* one unit corresponds to 256 bytes */
+
+/*== phy versions (PhyVersion:Revision field) ==*/
+/* analog block version */
+#define PV_AV_MASK 0xf000
+/* analog block version bitfield offset */
+#define PV_AV_SHIFT 12
+/* phy type */
+#define PV_PT_MASK 0x0f00
+/* phy type bitfield offset */
+#define PV_PT_SHIFT 8
+/* phy version */
+#define PV_PV_MASK 0x000f
+#define PHY_TYPE(v) ((v & PV_PT_MASK) >> PV_PT_SHIFT)
+
+/*== phy types (PhyVersion:PhyType field) ==*/
+#define PHY_TYPE_N 4 /* N-Phy value */
+#define PHY_TYPE_SSN 6 /* SSLPN-Phy value */
+#define PHY_TYPE_LCN 8 /* LCN-Phy value */
+#define PHY_TYPE_LCNXN 9 /* LCNXN-Phy value */
+#define PHY_TYPE_NULL 0xf /* Invalid Phy value */
+
+/*== analog types (PhyVersion:AnalogType field) ==*/
+#define ANA_11N_013 5
+
+/* 802.11a PLCP header def */
+struct ofdm_phy_hdr {
+ u8 rlpt[3]; /* rate, length, parity, tail */
+ u16 service;
+ u8 pad;
+} __packed;
+
+#define D11A_PHY_HDR_GRATE(phdr) ((phdr)->rlpt[0] & 0x0f)
+#define D11A_PHY_HDR_GRES(phdr) (((phdr)->rlpt[0] >> 4) & 0x01)
+#define D11A_PHY_HDR_GLENGTH(phdr) (((u32 *)((phdr)->rlpt) >> 5) & 0x0fff)
+#define D11A_PHY_HDR_GPARITY(phdr) (((phdr)->rlpt[3] >> 1) & 0x01)
+#define D11A_PHY_HDR_GTAIL(phdr) (((phdr)->rlpt[3] >> 2) & 0x3f)
+
+/* rate encoded per 802.11a-1999 sec 17.3.4.1 */
+#define D11A_PHY_HDR_SRATE(phdr, rate) \
+ ((phdr)->rlpt[0] = ((phdr)->rlpt[0] & 0xf0) | ((rate) & 0xf))
+/* set reserved field to zero */
+#define D11A_PHY_HDR_SRES(phdr) ((phdr)->rlpt[0] &= 0xef)
+/* length is number of octets in PSDU */
+#define D11A_PHY_HDR_SLENGTH(phdr, length) \
+ (*(u32 *)((phdr)->rlpt) = *(u32 *)((phdr)->rlpt) | \
+ (((length) & 0x0fff) << 5))
+/* set the tail to all zeros */
+#define D11A_PHY_HDR_STAIL(phdr) ((phdr)->rlpt[3] &= 0x03)
+
+#define D11A_PHY_HDR_LEN_L 3 /* low-rate part of PLCP header */
+#define D11A_PHY_HDR_LEN_R 2 /* high-rate part of PLCP header */
+
+#define D11A_PHY_TX_DELAY (2) /* 2.1 usec */
+
+#define D11A_PHY_HDR_TIME (4) /* low-rate part of PLCP header */
+#define D11A_PHY_PRE_TIME (16)
+#define D11A_PHY_PREHDR_TIME (D11A_PHY_PRE_TIME + D11A_PHY_HDR_TIME)
+
+/* 802.11b PLCP header def */
+struct cck_phy_hdr {
+ u8 signal;
+ u8 service;
+ u16 length;
+ u16 crc;
+} __packed;
+
+#define D11B_PHY_HDR_LEN 6
+
+#define D11B_PHY_TX_DELAY (3) /* 3.4 usec */
+
+#define D11B_PHY_LHDR_TIME (D11B_PHY_HDR_LEN << 3)
+#define D11B_PHY_LPRE_TIME (144)
+#define D11B_PHY_LPREHDR_TIME (D11B_PHY_LPRE_TIME + D11B_PHY_LHDR_TIME)
+
+#define D11B_PHY_SHDR_TIME (D11B_PHY_LHDR_TIME >> 1)
+#define D11B_PHY_SPRE_TIME (D11B_PHY_LPRE_TIME >> 1)
+#define D11B_PHY_SPREHDR_TIME (D11B_PHY_SPRE_TIME + D11B_PHY_SHDR_TIME)
+
+#define D11B_PLCP_SIGNAL_LOCKED (1 << 2)
+#define D11B_PLCP_SIGNAL_LE (1 << 7)
+
+#define MIMO_PLCP_MCS_MASK 0x7f /* mcs index */
+#define MIMO_PLCP_40MHZ 0x80 /* 40 Hz frame */
+#define MIMO_PLCP_AMPDU 0x08 /* ampdu */
+
+#define BRCMS_GET_CCK_PLCP_LEN(plcp) (plcp[4] + (plcp[5] << 8))
+#define BRCMS_GET_MIMO_PLCP_LEN(plcp) (plcp[1] + (plcp[2] << 8))
+#define BRCMS_SET_MIMO_PLCP_LEN(plcp, len) \
+ do { \
+ plcp[1] = len & 0xff; \
+ plcp[2] = ((len >> 8) & 0xff); \
+ } while (0);
+
+#define BRCMS_SET_MIMO_PLCP_AMPDU(plcp) (plcp[3] |= MIMO_PLCP_AMPDU)
+#define BRCMS_CLR_MIMO_PLCP_AMPDU(plcp) (plcp[3] &= ~MIMO_PLCP_AMPDU)
+#define BRCMS_IS_MIMO_PLCP_AMPDU(plcp) (plcp[3] & MIMO_PLCP_AMPDU)
+
+/*
+ * The dot11a PLCP header is 5 bytes. To simplify the software (so that we
+ * don't need e.g. different tx DMA headers for 11a and 11b), the PLCP header
+ * has padding added in the ucode.
+ */
+#define D11_PHY_HDR_LEN 6
+
+/* TX DMA buffer header */
+struct d11txh {
+ __le16 MacTxControlLow; /* 0x0 */
+ __le16 MacTxControlHigh; /* 0x1 */
+ __le16 MacFrameControl; /* 0x2 */
+ __le16 TxFesTimeNormal; /* 0x3 */
+ __le16 PhyTxControlWord; /* 0x4 */
+ __le16 PhyTxControlWord_1; /* 0x5 */
+ __le16 PhyTxControlWord_1_Fbr; /* 0x6 */
+ __le16 PhyTxControlWord_1_Rts; /* 0x7 */
+ __le16 PhyTxControlWord_1_FbrRts; /* 0x8 */
+ __le16 MainRates; /* 0x9 */
+ __le16 XtraFrameTypes; /* 0xa */
+ u8 IV[16]; /* 0x0b - 0x12 */
+ u8 TxFrameRA[6]; /* 0x13 - 0x15 */
+ __le16 TxFesTimeFallback; /* 0x16 */
+ u8 RTSPLCPFallback[6]; /* 0x17 - 0x19 */
+ __le16 RTSDurFallback; /* 0x1a */
+ u8 FragPLCPFallback[6]; /* 0x1b - 1d */
+ __le16 FragDurFallback; /* 0x1e */
+ __le16 MModeLen; /* 0x1f */
+ __le16 MModeFbrLen; /* 0x20 */
+ __le16 TstampLow; /* 0x21 */
+ __le16 TstampHigh; /* 0x22 */
+ __le16 ABI_MimoAntSel; /* 0x23 */
+ __le16 PreloadSize; /* 0x24 */
+ __le16 AmpduSeqCtl; /* 0x25 */
+ __le16 TxFrameID; /* 0x26 */
+ __le16 TxStatus; /* 0x27 */
+ __le16 MaxNMpdus; /* 0x28 */
+ __le16 MaxABytes_MRT; /* 0x29 */
+ __le16 MaxABytes_FBR; /* 0x2a */
+ __le16 MinMBytes; /* 0x2b */
+ u8 RTSPhyHeader[D11_PHY_HDR_LEN]; /* 0x2c - 0x2e */
+ struct ieee80211_rts rts_frame; /* 0x2f - 0x36 */
+ u16 PAD; /* 0x37 */
+} __packed;
+
+#define D11_TXH_LEN 112 /* bytes */
+
+/* Frame Types */
+#define FT_CCK 0
+#define FT_OFDM 1
+#define FT_HT 2
+#define FT_N 3
+
+/*
+ * Position of MPDU inside A-MPDU; indicated with bits 10:9
+ * of MacTxControlLow
+ */
+#define TXC_AMPDU_SHIFT 9 /* shift for ampdu settings */
+#define TXC_AMPDU_NONE 0 /* Regular MPDU, not an A-MPDU */
+#define TXC_AMPDU_FIRST 1 /* first MPDU of an A-MPDU */
+#define TXC_AMPDU_MIDDLE 2 /* intermediate MPDU of an A-MPDU */
+#define TXC_AMPDU_LAST 3 /* last (or single) MPDU of an A-MPDU */
+
+/*== MacTxControlLow ==*/
+#define TXC_AMIC 0x8000
+#define TXC_SENDCTS 0x0800
+#define TXC_AMPDU_MASK 0x0600
+#define TXC_BW_40 0x0100
+#define TXC_FREQBAND_5G 0x0080
+#define TXC_DFCS 0x0040
+#define TXC_IGNOREPMQ 0x0020
+#define TXC_HWSEQ 0x0010
+#define TXC_STARTMSDU 0x0008
+#define TXC_SENDRTS 0x0004
+#define TXC_LONGFRAME 0x0002
+#define TXC_IMMEDACK 0x0001
+
+/*== MacTxControlHigh ==*/
+/* RTS fallback preamble type 1 = SHORT 0 = LONG */
+#define TXC_PREAMBLE_RTS_FB_SHORT 0x8000
+/* RTS main rate preamble type 1 = SHORT 0 = LONG */
+#define TXC_PREAMBLE_RTS_MAIN_SHORT 0x4000
+/*
+ * Main fallback rate preamble type
+ * 1 = SHORT for OFDM/GF for MIMO
+ * 0 = LONG for CCK/MM for MIMO
+ */
+#define TXC_PREAMBLE_DATA_FB_SHORT 0x2000
+
+/* TXC_PREAMBLE_DATA_MAIN is in PhyTxControl bit 5 */
+/* use fallback rate for this AMPDU */
+#define TXC_AMPDU_FBR 0x1000
+#define TXC_SECKEY_MASK 0x0FF0
+#define TXC_SECKEY_SHIFT 4
+/* Use alternate txpwr defined at loc. M_ALT_TXPWR_IDX */
+#define TXC_ALT_TXPWR 0x0008
+#define TXC_SECTYPE_MASK 0x0007
+#define TXC_SECTYPE_SHIFT 0
+
+/* Null delimiter for Fallback rate */
+#define AMPDU_FBR_NULL_DELIM 5 /* Location of Null delimiter count for AMPDU */
+
+/* PhyTxControl for Mimophy */
+#define PHY_TXC_PWR_MASK 0xFC00
+#define PHY_TXC_PWR_SHIFT 10
+#define PHY_TXC_ANT_MASK 0x03C0 /* bit 6, 7, 8, 9 */
+#define PHY_TXC_ANT_SHIFT 6
+#define PHY_TXC_ANT_0_1 0x00C0 /* auto, last rx */
+#define PHY_TXC_LCNPHY_ANT_LAST 0x0000
+#define PHY_TXC_ANT_3 0x0200 /* virtual antenna 3 */
+#define PHY_TXC_ANT_2 0x0100 /* virtual antenna 2 */
+#define PHY_TXC_ANT_1 0x0080 /* virtual antenna 1 */
+#define PHY_TXC_ANT_0 0x0040 /* virtual antenna 0 */
+#define PHY_TXC_SHORT_HDR 0x0010
+
+#define PHY_TXC_OLD_ANT_0 0x0000
+#define PHY_TXC_OLD_ANT_1 0x0100
+#define PHY_TXC_OLD_ANT_LAST 0x0300
+
+/* PhyTxControl_1 for Mimophy */
+#define PHY_TXC1_BW_MASK 0x0007
+#define PHY_TXC1_BW_10MHZ 0
+#define PHY_TXC1_BW_10MHZ_UP 1
+#define PHY_TXC1_BW_20MHZ 2
+#define PHY_TXC1_BW_20MHZ_UP 3
+#define PHY_TXC1_BW_40MHZ 4
+#define PHY_TXC1_BW_40MHZ_DUP 5
+#define PHY_TXC1_MODE_SHIFT 3
+#define PHY_TXC1_MODE_MASK 0x0038
+#define PHY_TXC1_MODE_SISO 0
+#define PHY_TXC1_MODE_CDD 1
+#define PHY_TXC1_MODE_STBC 2
+#define PHY_TXC1_MODE_SDM 3
+
+/* PhyTxControl for HTphy that are different from Mimophy */
+#define PHY_TXC_HTANT_MASK 0x3fC0 /* bits 6-13 */
+
+/* XtraFrameTypes */
+#define XFTS_RTS_FT_SHIFT 2
+#define XFTS_FBRRTS_FT_SHIFT 4
+#define XFTS_CHANNEL_SHIFT 8
+
+/* Antenna diversity bit in ant_wr_settle */
+#define PHY_AWS_ANTDIV 0x2000
+
+/* IFS ctl */
+#define IFS_USEEDCF (1 << 2)
+
+/* IFS ctl1 */
+#define IFS_CTL1_EDCRS (1 << 3)
+#define IFS_CTL1_EDCRS_20L (1 << 4)
+#define IFS_CTL1_EDCRS_40 (1 << 5)
+
+/* ABI_MimoAntSel */
+#define ABI_MAS_ADDR_BMP_IDX_MASK 0x0f00
+#define ABI_MAS_ADDR_BMP_IDX_SHIFT 8
+#define ABI_MAS_FBR_ANT_PTN_MASK 0x00f0
+#define ABI_MAS_FBR_ANT_PTN_SHIFT 4
+#define ABI_MAS_MRT_ANT_PTN_MASK 0x000f
+
+/* tx status packet */
+struct tx_status {
+ u16 framelen;
+ u16 PAD;
+ u16 frameid;
+ u16 status;
+ u16 lasttxtime;
+ u16 sequence;
+ u16 phyerr;
+ u16 ackphyrxsh;
+} __packed;
+
+#define TXSTATUS_LEN 16
+
+/* status field bit definitions */
+#define TX_STATUS_FRM_RTX_MASK 0xF000
+#define TX_STATUS_FRM_RTX_SHIFT 12
+#define TX_STATUS_RTS_RTX_MASK 0x0F00
+#define TX_STATUS_RTS_RTX_SHIFT 8
+#define TX_STATUS_MASK 0x00FE
+#define TX_STATUS_PMINDCTD (1 << 7) /* PM mode indicated to AP */
+#define TX_STATUS_INTERMEDIATE (1 << 6) /* intermediate or 1st ampdu pkg */
+#define TX_STATUS_AMPDU (1 << 5) /* AMPDU status */
+#define TX_STATUS_SUPR_MASK 0x1C /* suppress status bits (4:2) */
+#define TX_STATUS_SUPR_SHIFT 2
+#define TX_STATUS_ACK_RCV (1 << 1) /* ACK received */
+#define TX_STATUS_VALID (1 << 0) /* Tx status valid */
+#define TX_STATUS_NO_ACK 0
+
+/* suppress status reason codes */
+#define TX_STATUS_SUPR_PMQ (1 << 2) /* PMQ entry */
+#define TX_STATUS_SUPR_FLUSH (2 << 2) /* flush request */
+#define TX_STATUS_SUPR_FRAG (3 << 2) /* previous frag failure */
+#define TX_STATUS_SUPR_TBTT (3 << 2) /* SHARED: Probe resp supr for TBTT */
+#define TX_STATUS_SUPR_BADCH (4 << 2) /* channel mismatch */
+#define TX_STATUS_SUPR_EXPTIME (5 << 2) /* lifetime expiry */
+#define TX_STATUS_SUPR_UF (6 << 2) /* underflow */
+
+/* Unexpected tx status for rate update */
+#define TX_STATUS_UNEXP(status) \
+ ((((status) & TX_STATUS_INTERMEDIATE) != 0) && \
+ TX_STATUS_UNEXP_AMPDU(status))
+
+/* Unexpected tx status for A-MPDU rate update */
+#define TX_STATUS_UNEXP_AMPDU(status) \
+ ((((status) & TX_STATUS_SUPR_MASK) != 0) && \
+ (((status) & TX_STATUS_SUPR_MASK) != TX_STATUS_SUPR_EXPTIME))
+
+#define TX_STATUS_BA_BMAP03_MASK 0xF000 /* ba bitmap 0:3 in 1st pkg */
+#define TX_STATUS_BA_BMAP03_SHIFT 12 /* ba bitmap 0:3 in 1st pkg */
+#define TX_STATUS_BA_BMAP47_MASK 0x001E /* ba bitmap 4:7 in 2nd pkg */
+#define TX_STATUS_BA_BMAP47_SHIFT 3 /* ba bitmap 4:7 in 2nd pkg */
+
+/* RXE (Receive Engine) */
+
+/* RCM_CTL */
+#define RCM_INC_MASK_H 0x0080
+#define RCM_INC_MASK_L 0x0040
+#define RCM_INC_DATA 0x0020
+#define RCM_INDEX_MASK 0x001F
+#define RCM_SIZE 15
+
+#define RCM_MAC_OFFSET 0 /* current MAC address */
+#define RCM_BSSID_OFFSET 3 /* current BSSID address */
+#define RCM_F_BSSID_0_OFFSET 6 /* foreign BSS CFP tracking */
+#define RCM_F_BSSID_1_OFFSET 9 /* foreign BSS CFP tracking */
+#define RCM_F_BSSID_2_OFFSET 12 /* foreign BSS CFP tracking */
+
+#define RCM_WEP_TA0_OFFSET 16
+#define RCM_WEP_TA1_OFFSET 19
+#define RCM_WEP_TA2_OFFSET 22
+#define RCM_WEP_TA3_OFFSET 25
+
+/* PSM Block */
+
+/* psm_phy_hdr_param bits */
+#define MAC_PHY_RESET 1
+#define MAC_PHY_CLOCK_EN 2
+#define MAC_PHY_FORCE_CLK 4
+
+/* WEP Block */
+
+/* WEP_WKEY */
+#define WKEY_START (1 << 8)
+#define WKEY_SEL_MASK 0x1F
+
+/* WEP data formats */
+
+/* the number of RCMTA entries */
+#define RCMTA_SIZE 50
+
+#define M_ADDR_BMP_BLK (0x37e * 2)
+#define M_ADDR_BMP_BLK_SZ 12
+
+#define ADDR_BMP_RA (1 << 0) /* Receiver Address (RA) */
+#define ADDR_BMP_TA (1 << 1) /* Transmitter Address (TA) */
+#define ADDR_BMP_BSSID (1 << 2) /* BSSID */
+#define ADDR_BMP_AP (1 << 3) /* Infra-BSS Access Point */
+#define ADDR_BMP_STA (1 << 4) /* Infra-BSS Station */
+#define ADDR_BMP_RESERVED1 (1 << 5)
+#define ADDR_BMP_RESERVED2 (1 << 6)
+#define ADDR_BMP_RESERVED3 (1 << 7)
+#define ADDR_BMP_BSS_IDX_MASK (3 << 8) /* BSS control block index */
+#define ADDR_BMP_BSS_IDX_SHIFT 8
+
+#define WSEC_MAX_RCMTA_KEYS 54
+
+/* max keys in M_TKMICKEYS_BLK */
+#define WSEC_MAX_TKMIC_ENGINE_KEYS 12 /* 8 + 4 default */
+
+/* max RXE match registers */
+#define WSEC_MAX_RXE_KEYS 4
+
+/* SECKINDXALGO (Security Key Index & Algorithm Block) word format */
+/* SKL (Security Key Lookup) */
+#define SKL_ALGO_MASK 0x0007
+#define SKL_ALGO_SHIFT 0
+#define SKL_KEYID_MASK 0x0008
+#define SKL_KEYID_SHIFT 3
+#define SKL_INDEX_MASK 0x03F0
+#define SKL_INDEX_SHIFT 4
+#define SKL_GRP_ALGO_MASK 0x1c00
+#define SKL_GRP_ALGO_SHIFT 10
+
+/* additional bits defined for IBSS group key support */
+#define SKL_IBSS_INDEX_MASK 0x01F0
+#define SKL_IBSS_INDEX_SHIFT 4
+#define SKL_IBSS_KEYID1_MASK 0x0600
+#define SKL_IBSS_KEYID1_SHIFT 9
+#define SKL_IBSS_KEYID2_MASK 0x1800
+#define SKL_IBSS_KEYID2_SHIFT 11
+#define SKL_IBSS_KEYALGO_MASK 0xE000
+#define SKL_IBSS_KEYALGO_SHIFT 13
+
+#define WSEC_MODE_OFF 0
+#define WSEC_MODE_HW 1
+#define WSEC_MODE_SW 2
+
+#define WSEC_ALGO_OFF 0
+#define WSEC_ALGO_WEP1 1
+#define WSEC_ALGO_TKIP 2
+#define WSEC_ALGO_AES 3
+#define WSEC_ALGO_WEP128 4
+#define WSEC_ALGO_AES_LEGACY 5
+#define WSEC_ALGO_NALG 6
+
+#define AES_MODE_NONE 0
+#define AES_MODE_CCM 1
+
+/* WEP_CTL (Rev 0) */
+#define WECR0_KEYREG_SHIFT 0
+#define WECR0_KEYREG_MASK 0x7
+#define WECR0_DECRYPT (1 << 3)
+#define WECR0_IVINLINE (1 << 4)
+#define WECR0_WEPALG_SHIFT 5
+#define WECR0_WEPALG_MASK (0x7 << 5)
+#define WECR0_WKEYSEL_SHIFT 8
+#define WECR0_WKEYSEL_MASK (0x7 << 8)
+#define WECR0_WKEYSTART (1 << 11)
+#define WECR0_WEPINIT (1 << 14)
+#define WECR0_ICVERR (1 << 15)
+
+/* Frame template map byte offsets */
+#define T_ACTS_TPL_BASE (0)
+#define T_NULL_TPL_BASE (0xc * 2)
+#define T_QNULL_TPL_BASE (0x1c * 2)
+#define T_RR_TPL_BASE (0x2c * 2)
+#define T_BCN0_TPL_BASE (0x34 * 2)
+#define T_PRS_TPL_BASE (0x134 * 2)
+#define T_BCN1_TPL_BASE (0x234 * 2)
+#define T_TX_FIFO_TXRAM_BASE (T_ACTS_TPL_BASE + \
+ (TXFIFO_START_BLK * TXFIFO_SIZE_UNIT))
+
+#define T_BA_TPL_BASE T_QNULL_TPL_BASE /* template area for BA */
+
+#define T_RAM_ACCESS_SZ 4 /* template ram is 4 byte access only */
+
+/* Shared Mem byte offsets */
+
+/* Location where the ucode expects the corerev */
+#define M_MACHW_VER (0x00b * 2)
+
+/* Location where the ucode expects the MAC capabilities */
+#define M_MACHW_CAP_L (0x060 * 2)
+#define M_MACHW_CAP_H (0x061 * 2)
+
+/* WME shared memory */
+#define M_EDCF_STATUS_OFF (0x007 * 2)
+#define M_TXF_CUR_INDEX (0x018 * 2)
+#define M_EDCF_QINFO (0x120 * 2)
+
+/* PS-mode related parameters */
+#define M_DOT11_SLOT (0x008 * 2)
+#define M_DOT11_DTIMPERIOD (0x009 * 2)
+#define M_NOSLPZNATDTIM (0x026 * 2)
+
+/* Beacon-related parameters */
+#define M_BCN0_FRM_BYTESZ (0x00c * 2) /* Bcn 0 template length */
+#define M_BCN1_FRM_BYTESZ (0x00d * 2) /* Bcn 1 template length */
+#define M_BCN_TXTSF_OFFSET (0x00e * 2)
+#define M_TIMBPOS_INBEACON (0x00f * 2)
+#define M_SFRMTXCNTFBRTHSD (0x022 * 2)
+#define M_LFRMTXCNTFBRTHSD (0x023 * 2)
+#define M_BCN_PCTLWD (0x02a * 2)
+#define M_BCN_LI (0x05b * 2) /* beacon listen interval */
+
+/* MAX Rx Frame len */
+#define M_MAXRXFRM_LEN (0x010 * 2)
+
+/* ACK/CTS related params */
+#define M_RSP_PCTLWD (0x011 * 2)
+
+/* Hardware Power Control */
+#define M_TXPWR_N (0x012 * 2)
+#define M_TXPWR_TARGET (0x013 * 2)
+#define M_TXPWR_MAX (0x014 * 2)
+#define M_TXPWR_CUR (0x019 * 2)
+
+/* Rx-related parameters */
+#define M_RX_PAD_DATA_OFFSET (0x01a * 2)
+
+/* WEP Shared mem data */
+#define M_SEC_DEFIVLOC (0x01e * 2)
+#define M_SEC_VALNUMSOFTMCHTA (0x01f * 2)
+#define M_PHYVER (0x028 * 2)
+#define M_PHYTYPE (0x029 * 2)
+#define M_SECRXKEYS_PTR (0x02b * 2)
+#define M_TKMICKEYS_PTR (0x059 * 2)
+#define M_SECKINDXALGO_BLK (0x2ea * 2)
+#define M_SECKINDXALGO_BLK_SZ 54
+#define M_SECPSMRXTAMCH_BLK (0x2fa * 2)
+#define M_TKIP_TSC_TTAK (0x18c * 2)
+#define D11_MAX_KEY_SIZE 16
+
+#define M_MAX_ANTCNT (0x02e * 2) /* antenna swap threshold */
+
+/* Probe response related parameters */
+#define M_SSIDLEN (0x024 * 2)
+#define M_PRB_RESP_FRM_LEN (0x025 * 2)
+#define M_PRS_MAXTIME (0x03a * 2)
+#define M_SSID (0xb0 * 2)
+#define M_CTXPRS_BLK (0xc0 * 2)
+#define C_CTX_PCTLWD_POS (0x4 * 2)
+
+/* Delta between OFDM and CCK power in CCK power boost mode */
+#define M_OFDM_OFFSET (0x027 * 2)
+
+/* TSSI for last 4 11b/g CCK packets transmitted */
+#define M_B_TSSI_0 (0x02c * 2)
+#define M_B_TSSI_1 (0x02d * 2)
+
+/* Host flags to turn on ucode options */
+#define M_HOST_FLAGS1 (0x02f * 2)
+#define M_HOST_FLAGS2 (0x030 * 2)
+#define M_HOST_FLAGS3 (0x031 * 2)
+#define M_HOST_FLAGS4 (0x03c * 2)
+#define M_HOST_FLAGS5 (0x06a * 2)
+#define M_HOST_FLAGS_SZ 16
+
+#define M_RADAR_REG (0x033 * 2)
+
+/* TSSI for last 4 11a OFDM packets transmitted */
+#define M_A_TSSI_0 (0x034 * 2)
+#define M_A_TSSI_1 (0x035 * 2)
+
+/* noise interference measurement */
+#define M_NOISE_IF_COUNT (0x034 * 2)
+#define M_NOISE_IF_TIMEOUT (0x035 * 2)
+
+#define M_RF_RX_SP_REG1 (0x036 * 2)
+
+/* TSSI for last 4 11g OFDM packets transmitted */
+#define M_G_TSSI_0 (0x038 * 2)
+#define M_G_TSSI_1 (0x039 * 2)
+
+/* Background noise measure */
+#define M_JSSI_0 (0x44 * 2)
+#define M_JSSI_1 (0x45 * 2)
+#define M_JSSI_AUX (0x46 * 2)
+
+#define M_CUR_2050_RADIOCODE (0x47 * 2)
+
+/* TX fifo sizes */
+#define M_FIFOSIZE0 (0x4c * 2)
+#define M_FIFOSIZE1 (0x4d * 2)
+#define M_FIFOSIZE2 (0x4e * 2)
+#define M_FIFOSIZE3 (0x4f * 2)
+#define D11_MAX_TX_FRMS 32 /* max frames allowed in tx fifo */
+
+/* Current channel number plus upper bits */
+#define M_CURCHANNEL (0x50 * 2)
+#define D11_CURCHANNEL_5G 0x0100;
+#define D11_CURCHANNEL_40 0x0200;
+#define D11_CURCHANNEL_MAX 0x00FF;
+
+/* last posted frameid on the bcmc fifo */
+#define M_BCMC_FID (0x54 * 2)
+#define INVALIDFID 0xffff
+
+/* extended beacon phyctl bytes for 11N */
+#define M_BCN_PCTL1WD (0x058 * 2)
+
+/* idle busy ratio to duty_cycle requirement */
+#define M_TX_IDLE_BUSY_RATIO_X_16_CCK (0x52 * 2)
+#define M_TX_IDLE_BUSY_RATIO_X_16_OFDM (0x5A * 2)
+
+/* CW RSSI for LCNPHY */
+#define M_LCN_RSSI_0 0x1332
+#define M_LCN_RSSI_1 0x1338
+#define M_LCN_RSSI_2 0x133e
+#define M_LCN_RSSI_3 0x1344
+
+/* SNR for LCNPHY */
+#define M_LCN_SNR_A_0 0x1334
+#define M_LCN_SNR_B_0 0x1336
+
+#define M_LCN_SNR_A_1 0x133a
+#define M_LCN_SNR_B_1 0x133c
+
+#define M_LCN_SNR_A_2 0x1340
+#define M_LCN_SNR_B_2 0x1342
+
+#define M_LCN_SNR_A_3 0x1346
+#define M_LCN_SNR_B_3 0x1348
+
+#define M_LCN_LAST_RESET (81*2)
+#define M_LCN_LAST_LOC (63*2)
+#define M_LCNPHY_RESET_STATUS (4902)
+#define M_LCNPHY_DSC_TIME (0x98d*2)
+#define M_LCNPHY_RESET_CNT_DSC (0x98b*2)
+#define M_LCNPHY_RESET_CNT (0x98c*2)
+
+/* Rate table offsets */
+#define M_RT_DIRMAP_A (0xe0 * 2)
+#define M_RT_BBRSMAP_A (0xf0 * 2)
+#define M_RT_DIRMAP_B (0x100 * 2)
+#define M_RT_BBRSMAP_B (0x110 * 2)
+
+/* Rate table entry offsets */
+#define M_RT_PRS_PLCP_POS 10
+#define M_RT_PRS_DUR_POS 16
+#define M_RT_OFDM_PCTL1_POS 18
+
+#define M_20IN40_IQ (0x380 * 2)
+
+/* SHM locations where ucode stores the current power index */
+#define M_CURR_IDX1 (0x384 * 2)
+#define M_CURR_IDX2 (0x387 * 2)
+
+#define M_BSCALE_ANT0 (0x5e * 2)
+#define M_BSCALE_ANT1 (0x5f * 2)
+
+/* Antenna Diversity Testing */
+#define M_MIMO_ANTSEL_RXDFLT (0x63 * 2)
+#define M_ANTSEL_CLKDIV (0x61 * 2)
+#define M_MIMO_ANTSEL_TXDFLT (0x64 * 2)
+
+#define M_MIMO_MAXSYM (0x5d * 2)
+#define MIMO_MAXSYM_DEF 0x8000 /* 32k */
+#define MIMO_MAXSYM_MAX 0xffff /* 64k */
+
+#define M_WATCHDOG_8TU (0x1e * 2)
+#define WATCHDOG_8TU_DEF 5
+#define WATCHDOG_8TU_MAX 10
+
+/* Manufacturing Test Variables */
+/* PER test mode */
+#define M_PKTENG_CTRL (0x6c * 2)
+/* IFS for TX mode */
+#define M_PKTENG_IFS (0x6d * 2)
+/* Lower word of tx frmcnt/rx lostcnt */
+#define M_PKTENG_FRMCNT_LO (0x6e * 2)
+/* Upper word of tx frmcnt/rx lostcnt */
+#define M_PKTENG_FRMCNT_HI (0x6f * 2)
+
+/* Index variation in vbat ripple */
+#define M_LCN_PWR_IDX_MAX (0x67 * 2) /* highest index read by ucode */
+#define M_LCN_PWR_IDX_MIN (0x66 * 2) /* lowest index read by ucode */
+
+/* M_PKTENG_CTRL bit definitions */
+#define M_PKTENG_MODE_TX 0x0001
+#define M_PKTENG_MODE_TX_RIFS 0x0004
+#define M_PKTENG_MODE_TX_CTS 0x0008
+#define M_PKTENG_MODE_RX 0x0002
+#define M_PKTENG_MODE_RX_WITH_ACK 0x0402
+#define M_PKTENG_MODE_MASK 0x0003
+/* TX frames indicated in the frmcnt reg */
+#define M_PKTENG_FRMCNT_VLD 0x0100
+
+/* Sample Collect parameters (bitmap and type) */
+/* Trigger bitmap for sample collect */
+#define M_SMPL_COL_BMP (0x37d * 2)
+/* Sample collect type */
+#define M_SMPL_COL_CTL (0x3b2 * 2)
+
+#define ANTSEL_CLKDIV_4MHZ 6
+#define MIMO_ANTSEL_BUSY 0x4000 /* bit 14 (busy) */
+#define MIMO_ANTSEL_SEL 0x8000 /* bit 15 write the value */
+#define MIMO_ANTSEL_WAIT 50 /* 50us wait */
+#define MIMO_ANTSEL_OVERRIDE 0x8000 /* flag */
+
+struct shm_acparams {
+ u16 txop;
+ u16 cwmin;
+ u16 cwmax;
+ u16 cwcur;
+ u16 aifs;
+ u16 bslots;
+ u16 reggap;
+ u16 status;
+ u16 rsvd[8];
+} __packed;
+#define M_EDCF_QLEN (16 * 2)
+
+#define WME_STATUS_NEWAC (1 << 8)
+
+/* M_HOST_FLAGS */
+#define MHFMAX 5 /* Number of valid hostflag half-word (u16) */
+#define MHF1 0 /* Hostflag 1 index */
+#define MHF2 1 /* Hostflag 2 index */
+#define MHF3 2 /* Hostflag 3 index */
+#define MHF4 3 /* Hostflag 4 index */
+#define MHF5 4 /* Hostflag 5 index */
+
+/* Flags in M_HOST_FLAGS */
+/* Enable ucode antenna diversity help */
+#define MHF1_ANTDIV 0x0001
+/* Enable EDCF access control */
+#define MHF1_EDCF 0x0100
+#define MHF1_IQSWAP_WAR 0x0200
+/* Disable Slow clock request, for corerev < 11 */
+#define MHF1_FORCEFASTCLK 0x0400
+
+/* Flags in M_HOST_FLAGS2 */
+
+/* Flush BCMC FIFO immediately */
+#define MHF2_TXBCMC_NOW 0x0040
+/* Enable ucode/hw power control */
+#define MHF2_HWPWRCTL 0x0080
+#define MHF2_NPHY40MHZ_WAR 0x0800
+
+/* Flags in M_HOST_FLAGS3 */
+/* enabled mimo antenna selection */
+#define MHF3_ANTSEL_EN 0x0001
+/* antenna selection mode: 0: 2x3, 1: 2x4 */
+#define MHF3_ANTSEL_MODE 0x0002
+#define MHF3_RESERVED1 0x0004
+#define MHF3_RESERVED2 0x0008
+#define MHF3_NPHY_MLADV_WAR 0x0010
+
+/* Flags in M_HOST_FLAGS4 */
+/* force bphy Tx on core 0 (board level WAR) */
+#define MHF4_BPHY_TXCORE0 0x0080
+/* for 4313A0 FEM boards */
+#define MHF4_EXTPA_ENABLE 0x4000
+
+/* Flags in M_HOST_FLAGS5 */
+#define MHF5_4313_GPIOCTRL 0x0001
+#define MHF5_RESERVED1 0x0002
+#define MHF5_RESERVED2 0x0004
+/* Radio power setting for ucode */
+#define M_RADIO_PWR (0x32 * 2)
+
+/* phy noise recorded by ucode right after tx */
+#define M_PHY_NOISE (0x037 * 2)
+#define PHY_NOISE_MASK 0x00ff
+
+/*
+ * Receive Frame Data Header for 802.11b DCF-only frames
+ *
+ * RxFrameSize: Actual byte length of the frame data received
+ * PAD: padding (not used)
+ * PhyRxStatus_0: PhyRxStatus 15:0
+ * PhyRxStatus_1: PhyRxStatus 31:16
+ * PhyRxStatus_2: PhyRxStatus 47:32
+ * PhyRxStatus_3: PhyRxStatus 63:48
+ * PhyRxStatus_4: PhyRxStatus 79:64
+ * PhyRxStatus_5: PhyRxStatus 95:80
+ * RxStatus1: MAC Rx Status
+ * RxStatus2: extended MAC Rx status
+ * RxTSFTime: RxTSFTime time of first MAC symbol + M_PHY_PLCPRX_DLY
+ * RxChan: gain code, channel radio code, and phy type
+ */
+struct d11rxhdr_le {
+ __le16 RxFrameSize;
+ u16 PAD;
+ __le16 PhyRxStatus_0;
+ __le16 PhyRxStatus_1;
+ __le16 PhyRxStatus_2;
+ __le16 PhyRxStatus_3;
+ __le16 PhyRxStatus_4;
+ __le16 PhyRxStatus_5;
+ __le16 RxStatus1;
+ __le16 RxStatus2;
+ __le16 RxTSFTime;
+ __le16 RxChan;
+} __packed;
+
+struct d11rxhdr {
+ u16 RxFrameSize;
+ u16 PAD;
+ u16 PhyRxStatus_0;
+ u16 PhyRxStatus_1;
+ u16 PhyRxStatus_2;
+ u16 PhyRxStatus_3;
+ u16 PhyRxStatus_4;
+ u16 PhyRxStatus_5;
+ u16 RxStatus1;
+ u16 RxStatus2;
+ u16 RxTSFTime;
+ u16 RxChan;
+} __packed;
+
+/* PhyRxStatus_0: */
+/* NPHY only: CCK, OFDM, preN, N */
+#define PRXS0_FT_MASK 0x0003
+/* NPHY only: clip count adjustment steps by AGC */
+#define PRXS0_CLIP_MASK 0x000C
+#define PRXS0_CLIP_SHIFT 2
+/* PHY received a frame with unsupported rate */
+#define PRXS0_UNSRATE 0x0010
+/* GPHY: rx ant, NPHY: upper sideband */
+#define PRXS0_RXANT_UPSUBBAND 0x0020
+/* CCK frame only: lost crs during cck frame reception */
+#define PRXS0_LCRS 0x0040
+/* Short Preamble */
+#define PRXS0_SHORTH 0x0080
+/* PLCP violation */
+#define PRXS0_PLCPFV 0x0100
+/* PLCP header integrity check failed */
+#define PRXS0_PLCPHCF 0x0200
+/* legacy PHY gain control */
+#define PRXS0_GAIN_CTL 0x4000
+/* NPHY: Antennas used for received frame, bitmask */
+#define PRXS0_ANTSEL_MASK 0xF000
+#define PRXS0_ANTSEL_SHIFT 0x12
+
+/* subfield PRXS0_FT_MASK */
+#define PRXS0_CCK 0x0000
+/* valid only for G phy, use rxh->RxChan for A phy */
+#define PRXS0_OFDM 0x0001
+#define PRXS0_PREN 0x0002
+#define PRXS0_STDN 0x0003
+
+/* subfield PRXS0_ANTSEL_MASK */
+#define PRXS0_ANTSEL_0 0x0 /* antenna 0 is used */
+#define PRXS0_ANTSEL_1 0x2 /* antenna 1 is used */
+#define PRXS0_ANTSEL_2 0x4 /* antenna 2 is used */
+#define PRXS0_ANTSEL_3 0x8 /* antenna 3 is used */
+
+/* PhyRxStatus_1: */
+#define PRXS1_JSSI_MASK 0x00FF
+#define PRXS1_JSSI_SHIFT 0
+#define PRXS1_SQ_MASK 0xFF00
+#define PRXS1_SQ_SHIFT 8
+
+/* nphy PhyRxStatus_1: */
+#define PRXS1_nphy_PWR0_MASK 0x00FF
+#define PRXS1_nphy_PWR1_MASK 0xFF00
+
+/* HTPHY Rx Status defines */
+/* htphy PhyRxStatus_0: those bit are overlapped with PhyRxStatus_0 */
+#define PRXS0_BAND 0x0400 /* 0 = 2.4G, 1 = 5G */
+#define PRXS0_RSVD 0x0800 /* reserved; set to 0 */
+#define PRXS0_UNUSED 0xF000 /* unused and not defined; set to 0 */
+
+/* htphy PhyRxStatus_1: */
+/* core enables for {3..0}, 0=disabled, 1=enabled */
+#define PRXS1_HTPHY_CORE_MASK 0x000F
+/* antenna configation */
+#define PRXS1_HTPHY_ANTCFG_MASK 0x00F0
+/* Mixmode PLCP Length low byte mask */
+#define PRXS1_HTPHY_MMPLCPLenL_MASK 0xFF00
+
+/* htphy PhyRxStatus_2: */
+/* Mixmode PLCP Length high byte maskw */
+#define PRXS2_HTPHY_MMPLCPLenH_MASK 0x000F
+/* Mixmode PLCP rate mask */
+#define PRXS2_HTPHY_MMPLCH_RATE_MASK 0x00F0
+/* Rx power on core 0 */
+#define PRXS2_HTPHY_RXPWR_ANT0 0xFF00
+
+/* htphy PhyRxStatus_3: */
+/* Rx power on core 1 */
+#define PRXS3_HTPHY_RXPWR_ANT1 0x00FF
+/* Rx power on core 2 */
+#define PRXS3_HTPHY_RXPWR_ANT2 0xFF00
+
+/* htphy PhyRxStatus_4: */
+/* Rx power on core 3 */
+#define PRXS4_HTPHY_RXPWR_ANT3 0x00FF
+/* Coarse frequency offset */
+#define PRXS4_HTPHY_CFO 0xFF00
+
+/* htphy PhyRxStatus_5: */
+/* Fine frequency offset */
+#define PRXS5_HTPHY_FFO 0x00FF
+/* Advance Retard */
+#define PRXS5_HTPHY_AR 0xFF00
+
+#define HTPHY_MMPLCPLen(rxs) \
+ ((((rxs)->PhyRxStatus_1 & PRXS1_HTPHY_MMPLCPLenL_MASK) >> 8) | \
+ (((rxs)->PhyRxStatus_2 & PRXS2_HTPHY_MMPLCPLenH_MASK) << 8))
+/* Get Rx power on core 0 */
+#define HTPHY_RXPWR_ANT0(rxs) \
+ ((((rxs)->PhyRxStatus_2) & PRXS2_HTPHY_RXPWR_ANT0) >> 8)
+/* Get Rx power on core 1 */
+#define HTPHY_RXPWR_ANT1(rxs) \
+ (((rxs)->PhyRxStatus_3) & PRXS3_HTPHY_RXPWR_ANT1)
+/* Get Rx power on core 2 */
+#define HTPHY_RXPWR_ANT2(rxs) \
+ ((((rxs)->PhyRxStatus_3) & PRXS3_HTPHY_RXPWR_ANT2) >> 8)
+
+/* ucode RxStatus1: */
+#define RXS_BCNSENT 0x8000
+#define RXS_SECKINDX_MASK 0x07e0
+#define RXS_SECKINDX_SHIFT 5
+#define RXS_DECERR (1 << 4)
+#define RXS_DECATMPT (1 << 3)
+/* PAD bytes to make IP data 4 bytes aligned */
+#define RXS_PBPRES (1 << 2)
+#define RXS_RESPFRAMETX (1 << 1)
+#define RXS_FCSERR (1 << 0)
+
+/* ucode RxStatus2: */
+#define RXS_AMSDU_MASK 1
+#define RXS_AGGTYPE_MASK 0x6
+#define RXS_AGGTYPE_SHIFT 1
+#define RXS_PHYRXST_VALID (1 << 8)
+#define RXS_RXANT_MASK 0x3
+#define RXS_RXANT_SHIFT 12
+
+/* RxChan */
+#define RXS_CHAN_40 0x1000
+#define RXS_CHAN_5G 0x0800
+#define RXS_CHAN_ID_MASK 0x07f8
+#define RXS_CHAN_ID_SHIFT 3
+#define RXS_CHAN_PHYTYPE_MASK 0x0007
+#define RXS_CHAN_PHYTYPE_SHIFT 0
+
+/* Index of attenuations used during ucode power control. */
+#define M_PWRIND_BLKS (0x184 * 2)
+#define M_PWRIND_MAP0 (M_PWRIND_BLKS + 0x0)
+#define M_PWRIND_MAP1 (M_PWRIND_BLKS + 0x2)
+#define M_PWRIND_MAP2 (M_PWRIND_BLKS + 0x4)
+#define M_PWRIND_MAP3 (M_PWRIND_BLKS + 0x6)
+/* M_PWRIND_MAP(core) macro */
+#define M_PWRIND_MAP(core) (M_PWRIND_BLKS + ((core)<<1))
+
+/* PSM SHM variable offsets */
+#define M_PSM_SOFT_REGS 0x0
+#define M_BOM_REV_MAJOR (M_PSM_SOFT_REGS + 0x0)
+#define M_BOM_REV_MINOR (M_PSM_SOFT_REGS + 0x2)
+#define M_UCODE_DBGST (M_PSM_SOFT_REGS + 0x40) /* ucode debug status code */
+#define M_UCODE_MACSTAT (M_PSM_SOFT_REGS + 0xE0) /* macstat counters */
+
+#define M_AGING_THRSH (0x3e * 2) /* max time waiting for medium before tx */
+#define M_MBURST_SIZE (0x40 * 2) /* max frames in a frameburst */
+#define M_MBURST_TXOP (0x41 * 2) /* max frameburst TXOP in unit of us */
+#define M_SYNTHPU_DLY (0x4a * 2) /* pre-wakeup for synthpu, default: 500 */
+#define M_PRETBTT (0x4b * 2)
+
+/* offset to the target txpwr */
+#define M_ALT_TXPWR_IDX (M_PSM_SOFT_REGS + (0x3b * 2))
+#define M_PHY_TX_FLT_PTR (M_PSM_SOFT_REGS + (0x3d * 2))
+#define M_CTS_DURATION (M_PSM_SOFT_REGS + (0x5c * 2))
+#define M_LP_RCCAL_OVR (M_PSM_SOFT_REGS + (0x6b * 2))
+
+/* PKTENG Rx Stats Block */
+#define M_RXSTATS_BLK_PTR (M_PSM_SOFT_REGS + (0x65 * 2))
+
+/* ucode debug status codes */
+/* not valid really */
+#define DBGST_INACTIVE 0
+/* after zeroing SHM, before suspending at init */
+#define DBGST_INIT 1
+/* "normal" state */
+#define DBGST_ACTIVE 2
+/* suspended */
+#define DBGST_SUSPENDED 3
+/* asleep (PS mode) */
+#define DBGST_ASLEEP 4
+
+/* Scratch Reg defs */
+enum _ePsmScratchPadRegDefinitions {
+ S_RSV0 = 0,
+ S_RSV1,
+ S_RSV2,
+
+ /* offset 0x03: scratch registers for Dot11-contants */
+ S_DOT11_CWMIN, /* CW-minimum */
+ S_DOT11_CWMAX, /* CW-maximum */
+ S_DOT11_CWCUR, /* CW-current */
+ S_DOT11_SRC_LMT, /* short retry count limit */
+ S_DOT11_LRC_LMT, /* long retry count limit */
+ S_DOT11_DTIMCOUNT, /* DTIM-count */
+
+ /* offset 0x09: Tx-side scratch registers */
+ S_SEQ_NUM, /* hardware sequence number reg */
+ S_SEQ_NUM_FRAG, /* seq num for frags (at the start of MSDU) */
+ S_FRMRETX_CNT, /* frame retx count */
+ S_SSRC, /* Station short retry count */
+ S_SLRC, /* Station long retry count */
+ S_EXP_RSP, /* Expected response frame */
+ S_OLD_BREM, /* Remaining backoff ctr */
+ S_OLD_CWWIN, /* saved-off CW-cur */
+ S_TXECTL, /* TXE-Ctl word constructed in scr-pad */
+ S_CTXTST, /* frm type-subtype as read from Tx-descr */
+
+ /* offset 0x13: Rx-side scratch registers */
+ S_RXTST, /* Type and subtype in Rxframe */
+
+ /* Global state register */
+ S_STREG, /* state storage actual bit maps below */
+
+ S_TXPWR_SUM, /* Tx power control: accumulator */
+ S_TXPWR_ITER, /* Tx power control: iteration */
+ S_RX_FRMTYPE, /* Rate and PHY type for frames */
+ S_THIS_AGG, /* Size of this AGG (A-MSDU) */
+
+ S_KEYINDX,
+ S_RXFRMLEN, /* Receive MPDU length in bytes */
+
+ /* offset 0x1B: Receive TSF time stored in SCR */
+ S_RXTSFTMRVAL_WD3, /* TSF value at the start of rx */
+ S_RXTSFTMRVAL_WD2, /* TSF value at the start of rx */
+ S_RXTSFTMRVAL_WD1, /* TSF value at the start of rx */
+ S_RXTSFTMRVAL_WD0, /* TSF value at the start of rx */
+ S_RXSSN, /* Received start seq number for A-MPDU BA */
+ S_RXQOSFLD, /* Rx-QoS field (if present) */
+
+ /* offset 0x21: Scratch pad regs used in microcode as temp storage */
+ S_TMP0, /* stmp0 */
+ S_TMP1, /* stmp1 */
+ S_TMP2, /* stmp2 */
+ S_TMP3, /* stmp3 */
+ S_TMP4, /* stmp4 */
+ S_TMP5, /* stmp5 */
+ S_PRQPENALTY_CTR, /* Probe response queue penalty counter */
+ S_ANTCNT, /* unsuccessful attempts on current ant. */
+ S_SYMBOL, /* flag for possible symbol ctl frames */
+ S_RXTP, /* rx frame type */
+ S_STREG2, /* extra state storage */
+ S_STREG3, /* even more extra state storage */
+ S_STREG4, /* ... */
+ S_STREG5, /* remember to initialize it to zero */
+
+ S_ADJPWR_IDX,
+ S_CUR_PTR, /* Temp pointer for A-MPDU re-Tx SHM table */
+ S_REVID4, /* 0x33 */
+ S_INDX, /* 0x34 */
+ S_ADDR0, /* 0x35 */
+ S_ADDR1, /* 0x36 */
+ S_ADDR2, /* 0x37 */
+ S_ADDR3, /* 0x38 */
+ S_ADDR4, /* 0x39 */
+ S_ADDR5, /* 0x3A */
+ S_TMP6, /* 0x3B */
+ S_KEYINDX_BU, /* Backup for Key index */
+ S_MFGTEST_TMP0, /* Temp regs used for RX test calculations */
+ S_RXESN, /* Received end sequence number for A-MPDU BA */
+ S_STREG6, /* 0x3F */
+};
+
+#define S_BEACON_INDX S_OLD_BREM
+#define S_PRS_INDX S_OLD_CWWIN
+#define S_PHYTYPE S_SSRC
+#define S_PHYVER S_SLRC
+
+/* IHR SLOW_CTRL values */
+#define SLOW_CTRL_PDE (1 << 0)
+#define SLOW_CTRL_FD (1 << 8)
+
+/* ucode mac statistic counters in shared memory */
+struct macstat {
+ u16 txallfrm; /* 0x80 */
+ u16 txrtsfrm; /* 0x82 */
+ u16 txctsfrm; /* 0x84 */
+ u16 txackfrm; /* 0x86 */
+ u16 txdnlfrm; /* 0x88 */
+ u16 txbcnfrm; /* 0x8a */
+ u16 txfunfl[8]; /* 0x8c - 0x9b */
+ u16 txtplunfl; /* 0x9c */
+ u16 txphyerr; /* 0x9e */
+ u16 pktengrxducast; /* 0xa0 */
+ u16 pktengrxdmcast; /* 0xa2 */
+ u16 rxfrmtoolong; /* 0xa4 */
+ u16 rxfrmtooshrt; /* 0xa6 */
+ u16 rxinvmachdr; /* 0xa8 */
+ u16 rxbadfcs; /* 0xaa */
+ u16 rxbadplcp; /* 0xac */
+ u16 rxcrsglitch; /* 0xae */
+ u16 rxstrt; /* 0xb0 */
+ u16 rxdfrmucastmbss; /* 0xb2 */
+ u16 rxmfrmucastmbss; /* 0xb4 */
+ u16 rxcfrmucast; /* 0xb6 */
+ u16 rxrtsucast; /* 0xb8 */
+ u16 rxctsucast; /* 0xba */
+ u16 rxackucast; /* 0xbc */
+ u16 rxdfrmocast; /* 0xbe */
+ u16 rxmfrmocast; /* 0xc0 */
+ u16 rxcfrmocast; /* 0xc2 */
+ u16 rxrtsocast; /* 0xc4 */
+ u16 rxctsocast; /* 0xc6 */
+ u16 rxdfrmmcast; /* 0xc8 */
+ u16 rxmfrmmcast; /* 0xca */
+ u16 rxcfrmmcast; /* 0xcc */
+ u16 rxbeaconmbss; /* 0xce */
+ u16 rxdfrmucastobss; /* 0xd0 */
+ u16 rxbeaconobss; /* 0xd2 */
+ u16 rxrsptmout; /* 0xd4 */
+ u16 bcntxcancl; /* 0xd6 */
+ u16 PAD;
+ u16 rxf0ovfl; /* 0xda */
+ u16 rxf1ovfl; /* 0xdc */
+ u16 rxf2ovfl; /* 0xde */
+ u16 txsfovfl; /* 0xe0 */
+ u16 pmqovfl; /* 0xe2 */
+ u16 rxcgprqfrm; /* 0xe4 */
+ u16 rxcgprsqovfl; /* 0xe6 */
+ u16 txcgprsfail; /* 0xe8 */
+ u16 txcgprssuc; /* 0xea */
+ u16 prs_timeout; /* 0xec */
+ u16 rxnack;
+ u16 frmscons;
+ u16 txnack;
+ u16 txglitch_nack;
+ u16 txburst; /* 0xf6 # tx bursts */
+ u16 bphy_rxcrsglitch; /* bphy rx crs glitch */
+ u16 phywatchdog; /* 0xfa # of phy watchdog events */
+ u16 PAD;
+ u16 bphy_badplcp; /* bphy bad plcp */
+};
+
+/* dot11 core-specific control flags */
+#define SICF_PCLKE 0x0004 /* PHY clock enable */
+#define SICF_PRST 0x0008 /* PHY reset */
+#define SICF_MPCLKE 0x0010 /* MAC PHY clockcontrol enable */
+#define SICF_FREF 0x0020 /* PLL FreqRefSelect */
+/* NOTE: the following bw bits only apply when the core is attached
+ * to a NPHY
+ */
+#define SICF_BWMASK 0x00c0 /* phy clock mask (b6 & b7) */
+#define SICF_BW40 0x0080 /* 40MHz BW (160MHz phyclk) */
+#define SICF_BW20 0x0040 /* 20MHz BW (80MHz phyclk) */
+#define SICF_BW10 0x0000 /* 10MHz BW (40MHz phyclk) */
+#define SICF_GMODE 0x2000 /* gmode enable */
+
+/* dot11 core-specific status flags */
+#define SISF_2G_PHY 0x0001 /* 2.4G capable phy */
+#define SISF_5G_PHY 0x0002 /* 5G capable phy */
+#define SISF_FCLKA 0x0004 /* FastClkAvailable */
+#define SISF_DB_PHY 0x0008 /* Dualband phy */
+
+/* === End of MAC reg, Beginning of PHY(b/a/g/n) reg === */
+/* radio and LPPHY regs are separated */
+
+#define BPHY_REG_OFT_BASE 0x0
+/* offsets for indirect access to bphy registers */
+#define BPHY_BB_CONFIG 0x01
+#define BPHY_ADCBIAS 0x02
+#define BPHY_ANACORE 0x03
+#define BPHY_PHYCRSTH 0x06
+#define BPHY_TEST 0x0a
+#define BPHY_PA_TX_TO 0x10
+#define BPHY_SYNTH_DC_TO 0x11
+#define BPHY_PA_TX_TIME_UP 0x12
+#define BPHY_RX_FLTR_TIME_UP 0x13
+#define BPHY_TX_POWER_OVERRIDE 0x14
+#define BPHY_RF_OVERRIDE 0x15
+#define BPHY_RF_TR_LOOKUP1 0x16
+#define BPHY_RF_TR_LOOKUP2 0x17
+#define BPHY_COEFFS 0x18
+#define BPHY_PLL_OUT 0x19
+#define BPHY_REFRESH_MAIN 0x1a
+#define BPHY_REFRESH_TO0 0x1b
+#define BPHY_REFRESH_TO1 0x1c
+#define BPHY_RSSI_TRESH 0x20
+#define BPHY_IQ_TRESH_HH 0x21
+#define BPHY_IQ_TRESH_H 0x22
+#define BPHY_IQ_TRESH_L 0x23
+#define BPHY_IQ_TRESH_LL 0x24
+#define BPHY_GAIN 0x25
+#define BPHY_LNA_GAIN_RANGE 0x26
+#define BPHY_JSSI 0x27
+#define BPHY_TSSI_CTL 0x28
+#define BPHY_TSSI 0x29
+#define BPHY_TR_LOSS_CTL 0x2a
+#define BPHY_LO_LEAKAGE 0x2b
+#define BPHY_LO_RSSI_ACC 0x2c
+#define BPHY_LO_IQMAG_ACC 0x2d
+#define BPHY_TX_DC_OFF1 0x2e
+#define BPHY_TX_DC_OFF2 0x2f
+#define BPHY_PEAK_CNT_THRESH 0x30
+#define BPHY_FREQ_OFFSET 0x31
+#define BPHY_DIVERSITY_CTL 0x32
+#define BPHY_PEAK_ENERGY_LO 0x33
+#define BPHY_PEAK_ENERGY_HI 0x34
+#define BPHY_SYNC_CTL 0x35
+#define BPHY_TX_PWR_CTRL 0x36
+#define BPHY_TX_EST_PWR 0x37
+#define BPHY_STEP 0x38
+#define BPHY_WARMUP 0x39
+#define BPHY_LMS_CFF_READ 0x3a
+#define BPHY_LMS_COEFF_I 0x3b
+#define BPHY_LMS_COEFF_Q 0x3c
+#define BPHY_SIG_POW 0x3d
+#define BPHY_RFDC_CANCEL_CTL 0x3e
+#define BPHY_HDR_TYPE 0x40
+#define BPHY_SFD_TO 0x41
+#define BPHY_SFD_CTL 0x42
+#define BPHY_DEBUG 0x43
+#define BPHY_RX_DELAY_COMP 0x44
+#define BPHY_CRS_DROP_TO 0x45
+#define BPHY_SHORT_SFD_NZEROS 0x46
+#define BPHY_DSSS_COEFF1 0x48
+#define BPHY_DSSS_COEFF2 0x49
+#define BPHY_CCK_COEFF1 0x4a
+#define BPHY_CCK_COEFF2 0x4b
+#define BPHY_TR_CORR 0x4c
+#define BPHY_ANGLE_SCALE 0x4d
+#define BPHY_TX_PWR_BASE_IDX 0x4e
+#define BPHY_OPTIONAL_MODES2 0x4f
+#define BPHY_CCK_LMS_STEP 0x50
+#define BPHY_BYPASS 0x51
+#define BPHY_CCK_DELAY_LONG 0x52
+#define BPHY_CCK_DELAY_SHORT 0x53
+#define BPHY_PPROC_CHAN_DELAY 0x54
+#define BPHY_DDFS_ENABLE 0x58
+#define BPHY_PHASE_SCALE 0x59
+#define BPHY_FREQ_CONTROL 0x5a
+#define BPHY_LNA_GAIN_RANGE_10 0x5b
+#define BPHY_LNA_GAIN_RANGE_32 0x5c
+#define BPHY_OPTIONAL_MODES 0x5d
+#define BPHY_RX_STATUS2 0x5e
+#define BPHY_RX_STATUS3 0x5f
+#define BPHY_DAC_CONTROL 0x60
+#define BPHY_ANA11G_FILT_CTRL 0x62
+#define BPHY_REFRESH_CTRL 0x64
+#define BPHY_RF_OVERRIDE2 0x65
+#define BPHY_SPUR_CANCEL_CTRL 0x66
+#define BPHY_FINE_DIGIGAIN_CTRL 0x67
+#define BPHY_RSSI_LUT 0x88
+#define BPHY_RSSI_LUT_END 0xa7
+#define BPHY_TSSI_LUT 0xa8
+#define BPHY_TSSI_LUT_END 0xc7
+#define BPHY_TSSI2PWR_LUT 0x380
+#define BPHY_TSSI2PWR_LUT_END 0x39f
+#define BPHY_LOCOMP_LUT 0x3a0
+#define BPHY_LOCOMP_LUT_END 0x3bf
+#define BPHY_TXGAIN_LUT 0x3c0
+#define BPHY_TXGAIN_LUT_END 0x3ff
+
+/* Bits in BB_CONFIG: */
+#define PHY_BBC_ANT_MASK 0x0180
+#define PHY_BBC_ANT_SHIFT 7
+#define BB_DARWIN 0x1000
+#define BBCFG_RESETCCA 0x4000
+#define BBCFG_RESETRX 0x8000
+
+/* Bits in phytest(0x0a): */
+#define TST_DDFS 0x2000
+#define TST_TXFILT1 0x0800
+#define TST_UNSCRAM 0x0400
+#define TST_CARR_SUPP 0x0200
+#define TST_DC_COMP_LOOP 0x0100
+#define TST_LOOPBACK 0x0080
+#define TST_TXFILT0 0x0040
+#define TST_TXTEST_ENABLE 0x0020
+#define TST_TXTEST_RATE 0x0018
+#define TST_TXTEST_PHASE 0x0007
+
+/* phytest txTestRate values */
+#define TST_TXTEST_RATE_1MBPS 0
+#define TST_TXTEST_RATE_2MBPS 1
+#define TST_TXTEST_RATE_5_5MBPS 2
+#define TST_TXTEST_RATE_11MBPS 3
+#define TST_TXTEST_RATE_SHIFT 3
+
+#define SHM_BYT_CNT 0x2 /* IHR location */
+#define MAX_BYT_CNT 0x600 /* Maximum frame len */
+
+struct d11cnt {
+ u32 txfrag;
+ u32 txmulti;
+ u32 txfail;
+ u32 txretry;
+ u32 txretrie;
+ u32 rxdup;
+ u32 txrts;
+ u32 txnocts;
+ u32 txnoack;
+ u32 rxfrag;
+ u32 rxmulti;
+ u32 rxcrc;
+ u32 txfrmsnt;
+ u32 rxundec;
+};
+
+#endif /* _BRCM_D11_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/brcm80211/brcmsmac/dma.c
new file mode 100644
index 000000000000..b56a30297c26
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.c
@@ -0,0 +1,1425 @@
+/*
+ * Copyright (c) 2010 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/slab.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include <brcmu_utils.h>
+#include <aiutils.h>
+#include "types.h"
+#include "dma.h"
+
+/*
+ * DMA hardware requires each descriptor ring to be 8kB aligned, and fit within
+ * a contiguous 8kB physical address.
+ */
+#define D64RINGALIGN_BITS 13
+#define D64MAXRINGSZ (1 << D64RINGALIGN_BITS)
+#define D64RINGALIGN (1 << D64RINGALIGN_BITS)
+
+#define D64MAXDD (D64MAXRINGSZ / sizeof(struct dma64desc))
+
+/* transmit channel control */
+#define D64_XC_XE 0x00000001 /* transmit enable */
+#define D64_XC_SE 0x00000002 /* transmit suspend request */
+#define D64_XC_LE 0x00000004 /* loopback enable */
+#define D64_XC_FL 0x00000010 /* flush request */
+#define D64_XC_PD 0x00000800 /* parity check disable */
+#define D64_XC_AE 0x00030000 /* address extension bits */
+#define D64_XC_AE_SHIFT 16
+
+/* transmit descriptor table pointer */
+#define D64_XP_LD_MASK 0x00000fff /* last valid descriptor */
+
+/* transmit channel status */
+#define D64_XS0_CD_MASK 0x00001fff /* current descriptor pointer */
+#define D64_XS0_XS_MASK 0xf0000000 /* transmit state */
+#define D64_XS0_XS_SHIFT 28
+#define D64_XS0_XS_DISABLED 0x00000000 /* disabled */
+#define D64_XS0_XS_ACTIVE 0x10000000 /* active */
+#define D64_XS0_XS_IDLE 0x20000000 /* idle wait */
+#define D64_XS0_XS_STOPPED 0x30000000 /* stopped */
+#define D64_XS0_XS_SUSP 0x40000000 /* suspend pending */
+
+#define D64_XS1_AD_MASK 0x00001fff /* active descriptor */
+#define D64_XS1_XE_MASK 0xf0000000 /* transmit errors */
+#define D64_XS1_XE_SHIFT 28
+#define D64_XS1_XE_NOERR 0x00000000 /* no error */
+#define D64_XS1_XE_DPE 0x10000000 /* descriptor protocol error */
+#define D64_XS1_XE_DFU 0x20000000 /* data fifo underrun */
+#define D64_XS1_XE_DTE 0x30000000 /* data transfer error */
+#define D64_XS1_XE_DESRE 0x40000000 /* descriptor read error */
+#define D64_XS1_XE_COREE 0x50000000 /* core error */
+
+/* receive channel control */
+/* receive enable */
+#define D64_RC_RE 0x00000001
+/* receive frame offset */
+#define D64_RC_RO_MASK 0x000000fe
+#define D64_RC_RO_SHIFT 1
+/* direct fifo receive (pio) mode */
+#define D64_RC_FM 0x00000100
+/* separate rx header descriptor enable */
+#define D64_RC_SH 0x00000200
+/* overflow continue */
+#define D64_RC_OC 0x00000400
+/* parity check disable */
+#define D64_RC_PD 0x00000800
+/* address extension bits */
+#define D64_RC_AE 0x00030000
+#define D64_RC_AE_SHIFT 16
+
+/* flags for dma controller */
+/* partity enable */
+#define DMA_CTRL_PEN (1 << 0)
+/* rx overflow continue */
+#define DMA_CTRL_ROC (1 << 1)
+/* allow rx scatter to multiple descriptors */
+#define DMA_CTRL_RXMULTI (1 << 2)
+/* Unframed Rx/Tx data */
+#define DMA_CTRL_UNFRAMED (1 << 3)
+
+/* receive descriptor table pointer */
+#define D64_RP_LD_MASK 0x00000fff /* last valid descriptor */
+
+/* receive channel status */
+#define D64_RS0_CD_MASK 0x00001fff /* current descriptor pointer */
+#define D64_RS0_RS_MASK 0xf0000000 /* receive state */
+#define D64_RS0_RS_SHIFT 28
+#define D64_RS0_RS_DISABLED 0x00000000 /* disabled */
+#define D64_RS0_RS_ACTIVE 0x10000000 /* active */
+#define D64_RS0_RS_IDLE 0x20000000 /* idle wait */
+#define D64_RS0_RS_STOPPED 0x30000000 /* stopped */
+#define D64_RS0_RS_SUSP 0x40000000 /* suspend pending */
+
+#define D64_RS1_AD_MASK 0x0001ffff /* active descriptor */
+#define D64_RS1_RE_MASK 0xf0000000 /* receive errors */
+#define D64_RS1_RE_SHIFT 28
+#define D64_RS1_RE_NOERR 0x00000000 /* no error */
+#define D64_RS1_RE_DPO 0x10000000 /* descriptor protocol error */
+#define D64_RS1_RE_DFU 0x20000000 /* data fifo overflow */
+#define D64_RS1_RE_DTE 0x30000000 /* data transfer error */
+#define D64_RS1_RE_DESRE 0x40000000 /* descriptor read error */
+#define D64_RS1_RE_COREE 0x50000000 /* core error */
+
+/* fifoaddr */
+#define D64_FA_OFF_MASK 0xffff /* offset */
+#define D64_FA_SEL_MASK 0xf0000 /* select */
+#define D64_FA_SEL_SHIFT 16
+#define D64_FA_SEL_XDD 0x00000 /* transmit dma data */
+#define D64_FA_SEL_XDP 0x10000 /* transmit dma pointers */
+#define D64_FA_SEL_RDD 0x40000 /* receive dma data */
+#define D64_FA_SEL_RDP 0x50000 /* receive dma pointers */
+#define D64_FA_SEL_XFD 0x80000 /* transmit fifo data */
+#define D64_FA_SEL_XFP 0x90000 /* transmit fifo pointers */
+#define D64_FA_SEL_RFD 0xc0000 /* receive fifo data */
+#define D64_FA_SEL_RFP 0xd0000 /* receive fifo pointers */
+#define D64_FA_SEL_RSD 0xe0000 /* receive frame status data */
+#define D64_FA_SEL_RSP 0xf0000 /* receive frame status pointers */
+
+/* descriptor control flags 1 */
+#define D64_CTRL_COREFLAGS 0x0ff00000 /* core specific flags */
+#define D64_CTRL1_EOT ((u32)1 << 28) /* end of descriptor table */
+#define D64_CTRL1_IOC ((u32)1 << 29) /* interrupt on completion */
+#define D64_CTRL1_EOF ((u32)1 << 30) /* end of frame */
+#define D64_CTRL1_SOF ((u32)1 << 31) /* start of frame */
+
+/* descriptor control flags 2 */
+/* buffer byte count. real data len must <= 16KB */
+#define D64_CTRL2_BC_MASK 0x00007fff
+/* address extension bits */
+#define D64_CTRL2_AE 0x00030000
+#define D64_CTRL2_AE_SHIFT 16
+/* parity bit */
+#define D64_CTRL2_PARITY 0x00040000
+
+/* control flags in the range [27:20] are core-specific and not defined here */
+#define D64_CTRL_CORE_MASK 0x0ff00000
+
+#define D64_RX_FRM_STS_LEN 0x0000ffff /* frame length mask */
+#define D64_RX_FRM_STS_OVFL 0x00800000 /* RxOverFlow */
+#define D64_RX_FRM_STS_DSCRCNT 0x0f000000 /* no. of descriptors used - 1 */
+#define D64_RX_FRM_STS_DATATYPE 0xf0000000 /* core-dependent data type */
+
+/*
+ * packet headroom necessary to accommodate the largest header
+ * in the system, (i.e TXOFF). By doing, we avoid the need to
+ * allocate an extra buffer for the header when bridging to WL.
+ * There is a compile time check in wlc.c which ensure that this
+ * value is at least as big as TXOFF. This value is used in
+ * dma_rxfill().
+ */
+
+#define BCMEXTRAHDROOM 172
+
+/* debug/trace */
+#ifdef BCMDBG
+#define DMA_ERROR(args) \
+ do { \
+ if (!(*di->msg_level & 1)) \
+ ; \
+ else \
+ printk args; \
+ } while (0)
+#define DMA_TRACE(args) \
+ do { \
+ if (!(*di->msg_level & 2)) \
+ ; \
+ else \
+ printk args; \
+ } while (0)
+#else
+#define DMA_ERROR(args)
+#define DMA_TRACE(args)
+#endif /* BCMDBG */
+
+#define DMA_NONE(args)
+
+#define MAXNAMEL 8 /* 8 char names */
+
+/* macros to convert between byte offsets and indexes */
+#define B2I(bytes, type) ((bytes) / sizeof(type))
+#define I2B(index, type) ((index) * sizeof(type))
+
+#define PCI32ADDR_HIGH 0xc0000000 /* address[31:30] */
+#define PCI32ADDR_HIGH_SHIFT 30 /* address[31:30] */
+
+#define PCI64ADDR_HIGH 0x80000000 /* address[63] */
+#define PCI64ADDR_HIGH_SHIFT 31 /* address[63] */
+
+/*
+ * DMA Descriptor
+ * Descriptors are only read by the hardware, never written back.
+ */
+struct dma64desc {
+ __le32 ctrl1; /* misc control bits & bufcount */
+ __le32 ctrl2; /* buffer count and address extension */
+ __le32 addrlow; /* memory address of the date buffer, bits 31:0 */
+ __le32 addrhigh; /* memory address of the date buffer, bits 63:32 */
+};
+
+/* dma engine software state */
+struct dma_info {
+ struct dma_pub dma; /* exported structure */
+ uint *msg_level; /* message level pointer */
+ char name[MAXNAMEL]; /* callers name for diag msgs */
+
+ struct pci_dev *pbus; /* bus handle */
+
+ bool dma64; /* this dma engine is operating in 64-bit mode */
+ bool addrext; /* this dma engine supports DmaExtendedAddrChanges */
+
+ /* 64-bit dma tx engine registers */
+ struct dma64regs __iomem *d64txregs;
+ /* 64-bit dma rx engine registers */
+ struct dma64regs __iomem *d64rxregs;
+ /* pointer to dma64 tx descriptor ring */
+ struct dma64desc *txd64;
+ /* pointer to dma64 rx descriptor ring */
+ struct dma64desc *rxd64;
+
+ u16 dmadesc_align; /* alignment requirement for dma descriptors */
+
+ u16 ntxd; /* # tx descriptors tunable */
+ u16 txin; /* index of next descriptor to reclaim */
+ u16 txout; /* index of next descriptor to post */
+ /* pointer to parallel array of pointers to packets */
+ struct sk_buff **txp;
+ /* Aligned physical address of descriptor ring */
+ dma_addr_t txdpa;
+ /* Original physical address of descriptor ring */
+ dma_addr_t txdpaorig;
+ u16 txdalign; /* #bytes added to alloc'd mem to align txd */
+ u32 txdalloc; /* #bytes allocated for the ring */
+ u32 xmtptrbase; /* When using unaligned descriptors, the ptr register
+ * is not just an index, it needs all 13 bits to be
+ * an offset from the addr register.
+ */
+
+ u16 nrxd; /* # rx descriptors tunable */
+ u16 rxin; /* index of next descriptor to reclaim */
+ u16 rxout; /* index of next descriptor to post */
+ /* pointer to parallel array of pointers to packets */
+ struct sk_buff **rxp;
+ /* Aligned physical address of descriptor ring */
+ dma_addr_t rxdpa;
+ /* Original physical address of descriptor ring */
+ dma_addr_t rxdpaorig;
+ u16 rxdalign; /* #bytes added to alloc'd mem to align rxd */
+ u32 rxdalloc; /* #bytes allocated for the ring */
+ u32 rcvptrbase; /* Base for ptr reg when using unaligned descriptors */
+
+ /* tunables */
+ unsigned int rxbufsize; /* rx buffer size in bytes, not including
+ * the extra headroom
+ */
+ uint rxextrahdrroom; /* extra rx headroom, reverseved to assist upper
+ * stack, e.g. some rx pkt buffers will be
+ * bridged to tx side without byte copying.
+ * The extra headroom needs to be large enough
+ * to fit txheader needs. Some dongle driver may
+ * not need it.
+ */
+ uint nrxpost; /* # rx buffers to keep posted */
+ unsigned int rxoffset; /* rxcontrol offset */
+ /* add to get dma address of descriptor ring, low 32 bits */
+ uint ddoffsetlow;
+ /* high 32 bits */
+ uint ddoffsethigh;
+ /* add to get dma address of data buffer, low 32 bits */
+ uint dataoffsetlow;
+ /* high 32 bits */
+ uint dataoffsethigh;
+ /* descriptor base need to be aligned or not */
+ bool aligndesc_4k;
+};
+
+/*
+ * default dma message level (if input msg_level
+ * pointer is null in dma_attach())
+ */
+static uint dma_msg_level;
+
+/* Check for odd number of 1's */
+static u32 parity32(__le32 data)
+{
+ /* no swap needed for counting 1's */
+ u32 par_data = *(u32 *)&data;
+
+ par_data ^= par_data >> 16;
+ par_data ^= par_data >> 8;
+ par_data ^= par_data >> 4;
+ par_data ^= par_data >> 2;
+ par_data ^= par_data >> 1;
+
+ return par_data & 1;
+}
+
+static bool dma64_dd_parity(struct dma64desc *dd)
+{
+ return parity32(dd->addrlow ^ dd->addrhigh ^ dd->ctrl1 ^ dd->ctrl2);
+}
+
+/* descriptor bumping functions */
+
+static uint xxd(uint x, uint n)
+{
+ return x & (n - 1); /* faster than %, but n must be power of 2 */
+}
+
+static uint txd(struct dma_info *di, uint x)
+{
+ return xxd(x, di->ntxd);
+}
+
+static uint rxd(struct dma_info *di, uint x)
+{
+ return xxd(x, di->nrxd);
+}
+
+static uint nexttxd(struct dma_info *di, uint i)
+{
+ return txd(di, i + 1);
+}
+
+static uint prevtxd(struct dma_info *di, uint i)
+{
+ return txd(di, i - 1);
+}
+
+static uint nextrxd(struct dma_info *di, uint i)
+{
+ return txd(di, i + 1);
+}
+
+static uint ntxdactive(struct dma_info *di, uint h, uint t)
+{
+ return txd(di, t-h);
+}
+
+static uint nrxdactive(struct dma_info *di, uint h, uint t)
+{
+ return rxd(di, t-h);
+}
+
+static uint _dma_ctrlflags(struct dma_info *di, uint mask, uint flags)
+{
+ uint dmactrlflags = di->dma.dmactrlflags;
+
+ if (di == NULL) {
+ DMA_ERROR(("%s: _dma_ctrlflags: NULL dma handle\n", di->name));
+ return 0;
+ }
+
+ dmactrlflags &= ~mask;
+ dmactrlflags |= flags;
+
+ /* If trying to enable parity, check if parity is actually supported */
+ if (dmactrlflags & DMA_CTRL_PEN) {
+ u32 control;
+
+ control = R_REG(&di->d64txregs->control);
+ W_REG(&di->d64txregs->control,
+ control | D64_XC_PD);
+ if (R_REG(&di->d64txregs->control) & D64_XC_PD)
+ /* We *can* disable it so it is supported,
+ * restore control register
+ */
+ W_REG(&di->d64txregs->control,
+ control);
+ else
+ /* Not supported, don't allow it to be enabled */
+ dmactrlflags &= ~DMA_CTRL_PEN;
+ }
+
+ di->dma.dmactrlflags = dmactrlflags;
+
+ return dmactrlflags;
+}
+
+static bool _dma64_addrext(struct dma64regs __iomem *dma64regs)
+{
+ u32 w;
+ OR_REG(&dma64regs->control, D64_XC_AE);
+ w = R_REG(&dma64regs->control);
+ AND_REG(&dma64regs->control, ~D64_XC_AE);
+ return (w & D64_XC_AE) == D64_XC_AE;
+}
+
+/*
+ * return true if this dma engine supports DmaExtendedAddrChanges,
+ * otherwise false
+ */
+static bool _dma_isaddrext(struct dma_info *di)
+{
+ /* DMA64 supports full 32- or 64-bit operation. AE is always valid */
+
+ /* not all tx or rx channel are available */
+ if (di->d64txregs != NULL) {
+ if (!_dma64_addrext(di->d64txregs))
+ DMA_ERROR(("%s: _dma_isaddrext: DMA64 tx doesn't have "
+ "AE set\n", di->name));
+ return true;
+ } else if (di->d64rxregs != NULL) {
+ if (!_dma64_addrext(di->d64rxregs))
+ DMA_ERROR(("%s: _dma_isaddrext: DMA64 rx doesn't have "
+ "AE set\n", di->name));
+ return true;
+ }
+
+ return false;
+}
+
+static bool _dma_descriptor_align(struct dma_info *di)
+{
+ u32 addrl;
+
+ /* Check to see if the descriptors need to be aligned on 4K/8K or not */
+ if (di->d64txregs != NULL) {
+ W_REG(&di->d64txregs->addrlow, 0xff0);
+ addrl = R_REG(&di->d64txregs->addrlow);
+ if (addrl != 0)
+ return false;
+ } else if (di->d64rxregs != NULL) {
+ W_REG(&di->d64rxregs->addrlow, 0xff0);
+ addrl = R_REG(&di->d64rxregs->addrlow);
+ if (addrl != 0)
+ return false;
+ }
+ return true;
+}
+
+/*
+ * Descriptor table must start at the DMA hardware dictated alignment, so
+ * allocated memory must be large enough to support this requirement.
+ */
+static void *dma_alloc_consistent(struct pci_dev *pdev, uint size,
+ u16 align_bits, uint *alloced,
+ dma_addr_t *pap)
+{
+ if (align_bits) {
+ u16 align = (1 << align_bits);
+ if (!IS_ALIGNED(PAGE_SIZE, align))
+ size += align;
+ *alloced = size;
+ }
+ return pci_alloc_consistent(pdev, size, pap);
+}
+
+static
+u8 dma_align_sizetobits(uint size)
+{
+ u8 bitpos = 0;
+ while (size >>= 1)
+ bitpos++;
+ return bitpos;
+}
+
+/* This function ensures that the DMA descriptor ring will not get allocated
+ * across Page boundary. If the allocation is done across the page boundary
+ * at the first time, then it is freed and the allocation is done at
+ * descriptor ring size aligned location. This will ensure that the ring will
+ * not cross page boundary
+ */
+static void *dma_ringalloc(struct dma_info *di, u32 boundary, uint size,
+ u16 *alignbits, uint *alloced,
+ dma_addr_t *descpa)
+{
+ void *va;
+ u32 desc_strtaddr;
+ u32 alignbytes = 1 << *alignbits;
+
+ va = dma_alloc_consistent(di->pbus, size, *alignbits, alloced, descpa);
+
+ if (NULL == va)
+ return NULL;
+
+ desc_strtaddr = (u32) roundup((unsigned long)va, alignbytes);
+ if (((desc_strtaddr + size - 1) & boundary) != (desc_strtaddr
+ & boundary)) {
+ *alignbits = dma_align_sizetobits(size);
+ pci_free_consistent(di->pbus, size, va, *descpa);
+ va = dma_alloc_consistent(di->pbus, size, *alignbits,
+ alloced, descpa);
+ }
+ return va;
+}
+
+static bool dma64_alloc(struct dma_info *di, uint direction)
+{
+ u16 size;
+ uint ddlen;
+ void *va;
+ uint alloced = 0;
+ u16 align;
+ u16 align_bits;
+
+ ddlen = sizeof(struct dma64desc);
+
+ size = (direction == DMA_TX) ? (di->ntxd * ddlen) : (di->nrxd * ddlen);
+ align_bits = di->dmadesc_align;
+ align = (1 << align_bits);
+
+ if (direction == DMA_TX) {
+ va = dma_ringalloc(di, D64RINGALIGN, size, &align_bits,
+ &alloced, &di->txdpaorig);
+ if (va == NULL) {
+ DMA_ERROR(("%s: dma64_alloc: DMA_ALLOC_CONSISTENT(ntxd)"
+ " failed\n", di->name));
+ return false;
+ }
+ align = (1 << align_bits);
+ di->txd64 = (struct dma64desc *)
+ roundup((unsigned long)va, align);
+ di->txdalign = (uint) ((s8 *)di->txd64 - (s8 *) va);
+ di->txdpa = di->txdpaorig + di->txdalign;
+ di->txdalloc = alloced;
+ } else {
+ va = dma_ringalloc(di, D64RINGALIGN, size, &align_bits,
+ &alloced, &di->rxdpaorig);
+ if (va == NULL) {
+ DMA_ERROR(("%s: dma64_alloc: DMA_ALLOC_CONSISTENT(nrxd)"
+ " failed\n", di->name));
+ return false;
+ }
+ align = (1 << align_bits);
+ di->rxd64 = (struct dma64desc *)
+ roundup((unsigned long)va, align);
+ di->rxdalign = (uint) ((s8 *)di->rxd64 - (s8 *) va);
+ di->rxdpa = di->rxdpaorig + di->rxdalign;
+ di->rxdalloc = alloced;
+ }
+
+ return true;
+}
+
+static bool _dma_alloc(struct dma_info *di, uint direction)
+{
+ return dma64_alloc(di, direction);
+}
+
+struct dma_pub *dma_attach(char *name, struct si_pub *sih,
+ void __iomem *dmaregstx, void __iomem *dmaregsrx,
+ uint ntxd, uint nrxd,
+ uint rxbufsize, int rxextheadroom,
+ uint nrxpost, uint rxoffset, uint *msg_level)
+{
+ struct dma_info *di;
+ uint size;
+
+ /* allocate private info structure */
+ di = kzalloc(sizeof(struct dma_info), GFP_ATOMIC);
+ if (di == NULL)
+ return NULL;
+
+ di->msg_level = msg_level ? msg_level : &dma_msg_level;
+
+
+ di->dma64 = ((ai_core_sflags(sih, 0, 0) & SISF_DMA64) == SISF_DMA64);
+
+ /* init dma reg pointer */
+ di->d64txregs = (struct dma64regs __iomem *) dmaregstx;
+ di->d64rxregs = (struct dma64regs __iomem *) dmaregsrx;
+
+ /*
+ * Default flags (which can be changed by the driver calling
+ * dma_ctrlflags before enable): For backwards compatibility
+ * both Rx Overflow Continue and Parity are DISABLED.
+ */
+ _dma_ctrlflags(di, DMA_CTRL_ROC | DMA_CTRL_PEN, 0);
+
+ DMA_TRACE(("%s: dma_attach: %s flags 0x%x ntxd %d nrxd %d "
+ "rxbufsize %d rxextheadroom %d nrxpost %d rxoffset %d "
+ "dmaregstx %p dmaregsrx %p\n", name, "DMA64",
+ di->dma.dmactrlflags, ntxd, nrxd, rxbufsize,
+ rxextheadroom, nrxpost, rxoffset, dmaregstx, dmaregsrx));
+
+ /* make a private copy of our callers name */
+ strncpy(di->name, name, MAXNAMEL);
+ di->name[MAXNAMEL - 1] = '\0';
+
+ di->pbus = ((struct si_info *)sih)->pbus;
+
+ /* save tunables */
+ di->ntxd = (u16) ntxd;
+ di->nrxd = (u16) nrxd;
+
+ /* the actual dma size doesn't include the extra headroom */
+ di->rxextrahdrroom =
+ (rxextheadroom == -1) ? BCMEXTRAHDROOM : rxextheadroom;
+ if (rxbufsize > BCMEXTRAHDROOM)
+ di->rxbufsize = (u16) (rxbufsize - di->rxextrahdrroom);
+ else
+ di->rxbufsize = (u16) rxbufsize;
+
+ di->nrxpost = (u16) nrxpost;
+ di->rxoffset = (u8) rxoffset;
+
+ /*
+ * figure out the DMA physical address offset for dd and data
+ * PCI/PCIE: they map silicon backplace address to zero
+ * based memory, need offset
+ * Other bus: use zero SI_BUS BIGENDIAN kludge: use sdram
+ * swapped region for data buffer, not descriptor
+ */
+ di->ddoffsetlow = 0;
+ di->dataoffsetlow = 0;
+ /* add offset for pcie with DMA64 bus */
+ di->ddoffsetlow = 0;
+ di->ddoffsethigh = SI_PCIE_DMA_H32;
+ di->dataoffsetlow = di->ddoffsetlow;
+ di->dataoffsethigh = di->ddoffsethigh;
+ /* WAR64450 : DMACtl.Addr ext fields are not supported in SDIOD core. */
+ if ((ai_coreid(sih) == SDIOD_CORE_ID)
+ && ((ai_corerev(sih) > 0) && (ai_corerev(sih) <= 2)))
+ di->addrext = 0;
+ else if ((ai_coreid(sih) == I2S_CORE_ID) &&
+ ((ai_corerev(sih) == 0) || (ai_corerev(sih) == 1)))
+ di->addrext = 0;
+ else
+ di->addrext = _dma_isaddrext(di);
+
+ /* does the descriptor need to be aligned and if yes, on 4K/8K or not */
+ di->aligndesc_4k = _dma_descriptor_align(di);
+ if (di->aligndesc_4k) {
+ di->dmadesc_align = D64RINGALIGN_BITS;
+ if ((ntxd < D64MAXDD / 2) && (nrxd < D64MAXDD / 2))
+ /* for smaller dd table, HW relax alignment reqmnt */
+ di->dmadesc_align = D64RINGALIGN_BITS - 1;
+ } else {
+ di->dmadesc_align = 4; /* 16 byte alignment */
+ }
+
+ DMA_NONE(("DMA descriptor align_needed %d, align %d\n",
+ di->aligndesc_4k, di->dmadesc_align));
+
+ /* allocate tx packet pointer vector */
+ if (ntxd) {
+ size = ntxd * sizeof(void *);
+ di->txp = kzalloc(size, GFP_ATOMIC);
+ if (di->txp == NULL)
+ goto fail;
+ }
+
+ /* allocate rx packet pointer vector */
+ if (nrxd) {
+ size = nrxd * sizeof(void *);
+ di->rxp = kzalloc(size, GFP_ATOMIC);
+ if (di->rxp == NULL)
+ goto fail;
+ }
+
+ /*
+ * allocate transmit descriptor ring, only need ntxd descriptors
+ * but it must be aligned
+ */
+ if (ntxd) {
+ if (!_dma_alloc(di, DMA_TX))
+ goto fail;
+ }
+
+ /*
+ * allocate receive descriptor ring, only need nrxd descriptors
+ * but it must be aligned
+ */
+ if (nrxd) {
+ if (!_dma_alloc(di, DMA_RX))
+ goto fail;
+ }
+
+ if ((di->ddoffsetlow != 0) && !di->addrext) {
+ if (di->txdpa > SI_PCI_DMA_SZ) {
+ DMA_ERROR(("%s: dma_attach: txdpa 0x%x: addrext not "
+ "supported\n", di->name, (u32)di->txdpa));
+ goto fail;
+ }
+ if (di->rxdpa > SI_PCI_DMA_SZ) {
+ DMA_ERROR(("%s: dma_attach: rxdpa 0x%x: addrext not "
+ "supported\n", di->name, (u32)di->rxdpa));
+ goto fail;
+ }
+ }
+
+ DMA_TRACE(("ddoffsetlow 0x%x ddoffsethigh 0x%x dataoffsetlow 0x%x "
+ "dataoffsethigh " "0x%x addrext %d\n", di->ddoffsetlow,
+ di->ddoffsethigh, di->dataoffsetlow, di->dataoffsethigh,
+ di->addrext));
+
+ return (struct dma_pub *) di;
+
+ fail:
+ dma_detach((struct dma_pub *)di);
+ return NULL;
+}
+
+static inline void
+dma64_dd_upd(struct dma_info *di, struct dma64desc *ddring,
+ dma_addr_t pa, uint outidx, u32 *flags, u32 bufcount)
+{
+ u32 ctrl2 = bufcount & D64_CTRL2_BC_MASK;
+
+ /* PCI bus with big(>1G) physical address, use address extension */
+ if ((di->dataoffsetlow == 0) || !(pa & PCI32ADDR_HIGH)) {
+ ddring[outidx].addrlow = cpu_to_le32(pa + di->dataoffsetlow);
+ ddring[outidx].addrhigh = cpu_to_le32(di->dataoffsethigh);
+ ddring[outidx].ctrl1 = cpu_to_le32(*flags);
+ ddring[outidx].ctrl2 = cpu_to_le32(ctrl2);
+ } else {
+ /* address extension for 32-bit PCI */
+ u32 ae;
+
+ ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT;
+ pa &= ~PCI32ADDR_HIGH;
+
+ ctrl2 |= (ae << D64_CTRL2_AE_SHIFT) & D64_CTRL2_AE;
+ ddring[outidx].addrlow = cpu_to_le32(pa + di->dataoffsetlow);
+ ddring[outidx].addrhigh = cpu_to_le32(di->dataoffsethigh);
+ ddring[outidx].ctrl1 = cpu_to_le32(*flags);
+ ddring[outidx].ctrl2 = cpu_to_le32(ctrl2);
+ }
+ if (di->dma.dmactrlflags & DMA_CTRL_PEN) {
+ if (dma64_dd_parity(&ddring[outidx]))
+ ddring[outidx].ctrl2 =
+ cpu_to_le32(ctrl2 | D64_CTRL2_PARITY);
+ }
+}
+
+/* !! may be called with core in reset */
+void dma_detach(struct dma_pub *pub)
+{
+ struct dma_info *di = (struct dma_info *)pub;
+
+ DMA_TRACE(("%s: dma_detach\n", di->name));
+
+ /* free dma descriptor rings */
+ if (di->txd64)
+ pci_free_consistent(di->pbus, di->txdalloc,
+ ((s8 *)di->txd64 - di->txdalign),
+ (di->txdpaorig));
+ if (di->rxd64)
+ pci_free_consistent(di->pbus, di->rxdalloc,
+ ((s8 *)di->rxd64 - di->rxdalign),
+ (di->rxdpaorig));
+
+ /* free packet pointer vectors */
+ kfree(di->txp);
+ kfree(di->rxp);
+
+ /* free our private info structure */
+ kfree(di);
+
+}
+
+/* initialize descriptor table base address */
+static void
+_dma_ddtable_init(struct dma_info *di, uint direction, dma_addr_t pa)
+{
+ if (!di->aligndesc_4k) {
+ if (direction == DMA_TX)
+ di->xmtptrbase = pa;
+ else
+ di->rcvptrbase = pa;
+ }
+
+ if ((di->ddoffsetlow == 0)
+ || !(pa & PCI32ADDR_HIGH)) {
+ if (direction == DMA_TX) {
+ W_REG(&di->d64txregs->addrlow, pa + di->ddoffsetlow);
+ W_REG(&di->d64txregs->addrhigh, di->ddoffsethigh);
+ } else {
+ W_REG(&di->d64rxregs->addrlow, pa + di->ddoffsetlow);
+ W_REG(&di->d64rxregs->addrhigh, di->ddoffsethigh);
+ }
+ } else {
+ /* DMA64 32bits address extension */
+ u32 ae;
+
+ /* shift the high bit(s) from pa to ae */
+ ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT;
+ pa &= ~PCI32ADDR_HIGH;
+
+ if (direction == DMA_TX) {
+ W_REG(&di->d64txregs->addrlow, pa + di->ddoffsetlow);
+ W_REG(&di->d64txregs->addrhigh, di->ddoffsethigh);
+ SET_REG(&di->d64txregs->control,
+ D64_XC_AE, (ae << D64_XC_AE_SHIFT));
+ } else {
+ W_REG(&di->d64rxregs->addrlow, pa + di->ddoffsetlow);
+ W_REG(&di->d64rxregs->addrhigh, di->ddoffsethigh);
+ SET_REG(&di->d64rxregs->control,
+ D64_RC_AE, (ae << D64_RC_AE_SHIFT));
+ }
+ }
+}
+
+static void _dma_rxenable(struct dma_info *di)
+{
+ uint dmactrlflags = di->dma.dmactrlflags;
+ u32 control;
+
+ DMA_TRACE(("%s: dma_rxenable\n", di->name));
+
+ control =
+ (R_REG(&di->d64rxregs->control) & D64_RC_AE) |
+ D64_RC_RE;
+
+ if ((dmactrlflags & DMA_CTRL_PEN) == 0)
+ control |= D64_RC_PD;
+
+ if (dmactrlflags & DMA_CTRL_ROC)
+ control |= D64_RC_OC;
+
+ W_REG(&di->d64rxregs->control,
+ ((di->rxoffset << D64_RC_RO_SHIFT) | control));
+}
+
+void dma_rxinit(struct dma_pub *pub)
+{
+ struct dma_info *di = (struct dma_info *)pub;
+
+ DMA_TRACE(("%s: dma_rxinit\n", di->name));
+
+ if (di->nrxd == 0)
+ return;
+
+ di->rxin = di->rxout = 0;
+
+ /* clear rx descriptor ring */
+ memset(di->rxd64, '\0', di->nrxd * sizeof(struct dma64desc));
+
+ /* DMA engine with out alignment requirement requires table to be inited
+ * before enabling the engine
+ */
+ if (!di->aligndesc_4k)
+ _dma_ddtable_init(di, DMA_RX, di->rxdpa);
+
+ _dma_rxenable(di);
+
+ if (di->aligndesc_4k)
+ _dma_ddtable_init(di, DMA_RX, di->rxdpa);
+}
+
+static struct sk_buff *dma64_getnextrxp(struct dma_info *di, bool forceall)
+{
+ uint i, curr;
+ struct sk_buff *rxp;
+ dma_addr_t pa;
+
+ i = di->rxin;
+
+ /* return if no packets posted */
+ if (i == di->rxout)
+ return NULL;
+
+ curr =
+ B2I(((R_REG(&di->d64rxregs->status0) & D64_RS0_CD_MASK) -
+ di->rcvptrbase) & D64_RS0_CD_MASK, struct dma64desc);
+
+ /* ignore curr if forceall */
+ if (!forceall && (i == curr))
+ return NULL;
+
+ /* get the packet pointer that corresponds to the rx descriptor */
+ rxp = di->rxp[i];
+ di->rxp[i] = NULL;
+
+ pa = le32_to_cpu(di->rxd64[i].addrlow) - di->dataoffsetlow;
+
+ /* clear this packet from the descriptor ring */
+ pci_unmap_single(di->pbus, pa, di->rxbufsize, PCI_DMA_FROMDEVICE);
+
+ di->rxd64[i].addrlow = cpu_to_le32(0xdeadbeef);
+ di->rxd64[i].addrhigh = cpu_to_le32(0xdeadbeef);
+
+ di->rxin = nextrxd(di, i);
+
+ return rxp;
+}
+
+static struct sk_buff *_dma_getnextrxp(struct dma_info *di, bool forceall)
+{
+ if (di->nrxd == 0)
+ return NULL;
+
+ return dma64_getnextrxp(di, forceall);
+}
+
+/*
+ * !! rx entry routine
+ * returns a pointer to the next frame received, or NULL if there are no more
+ * if DMA_CTRL_RXMULTI is defined, DMA scattering(multiple buffers) is
+ * supported with pkts chain
+ * otherwise, it's treated as giant pkt and will be tossed.
+ * The DMA scattering starts with normal DMA header, followed by first
+ * buffer data. After it reaches the max size of buffer, the data continues
+ * in next DMA descriptor buffer WITHOUT DMA header
+ */
+struct sk_buff *dma_rx(struct dma_pub *pub)
+{
+ struct dma_info *di = (struct dma_info *)pub;
+ struct sk_buff *p, *head, *tail;
+ uint len;
+ uint pkt_len;
+ int resid = 0;
+
+ next_frame:
+ head = _dma_getnextrxp(di, false);
+ if (head == NULL)
+ return NULL;
+
+ len = le16_to_cpu(*(__le16 *) (head->data));
+ DMA_TRACE(("%s: dma_rx len %d\n", di->name, len));
+ dma_spin_for_len(len, head);
+
+ /* set actual length */
+ pkt_len = min((di->rxoffset + len), di->rxbufsize);
+ __skb_trim(head, pkt_len);
+ resid = len - (di->rxbufsize - di->rxoffset);
+
+ /* check for single or multi-buffer rx */
+ if (resid > 0) {
+ tail = head;
+ while ((resid > 0) && (p = _dma_getnextrxp(di, false))) {
+ tail->next = p;
+ pkt_len = min_t(uint, resid, di->rxbufsize);
+ __skb_trim(p, pkt_len);
+
+ tail = p;
+ resid -= di->rxbufsize;
+ }
+
+#ifdef BCMDBG
+ if (resid > 0) {
+ uint cur;
+ cur =
+ B2I(((R_REG(&di->d64rxregs->status0) &
+ D64_RS0_CD_MASK) -
+ di->rcvptrbase) & D64_RS0_CD_MASK,
+ struct dma64desc);
+ DMA_ERROR(("dma_rx, rxin %d rxout %d, hw_curr %d\n",
+ di->rxin, di->rxout, cur));
+ }
+#endif /* BCMDBG */
+
+ if ((di->dma.dmactrlflags & DMA_CTRL_RXMULTI) == 0) {
+ DMA_ERROR(("%s: dma_rx: bad frame length (%d)\n",
+ di->name, len));
+ brcmu_pkt_buf_free_skb(head);
+ di->dma.rxgiants++;
+ goto next_frame;
+ }
+ }
+
+ return head;
+}
+
+static bool dma64_rxidle(struct dma_info *di)
+{
+ DMA_TRACE(("%s: dma_rxidle\n", di->name));
+
+ if (di->nrxd == 0)
+ return true;
+
+ return ((R_REG(&di->d64rxregs->status0) & D64_RS0_CD_MASK) ==
+ (R_REG(&di->d64rxregs->ptr) & D64_RS0_CD_MASK));
+}
+
+/*
+ * post receive buffers
+ * return false is refill failed completely and ring is empty this will stall
+ * the rx dma and user might want to call rxfill again asap. This unlikely
+ * happens on memory-rich NIC, but often on memory-constrained dongle
+ */
+bool dma_rxfill(struct dma_pub *pub)
+{
+ struct dma_info *di = (struct dma_info *)pub;
+ struct sk_buff *p;
+ u16 rxin, rxout;
+ u32 flags = 0;
+ uint n;
+ uint i;
+ dma_addr_t pa;
+ uint extra_offset = 0;
+ bool ring_empty;
+
+ ring_empty = false;
+
+ /*
+ * Determine how many receive buffers we're lacking
+ * from the full complement, allocate, initialize,
+ * and post them, then update the chip rx lastdscr.
+ */
+
+ rxin = di->rxin;
+ rxout = di->rxout;
+
+ n = di->nrxpost - nrxdactive(di, rxin, rxout);
+
+ DMA_TRACE(("%s: dma_rxfill: post %d\n", di->name, n));
+
+ if (di->rxbufsize > BCMEXTRAHDROOM)
+ extra_offset = di->rxextrahdrroom;
+
+ for (i = 0; i < n; i++) {
+ /*
+ * the di->rxbufsize doesn't include the extra headroom,
+ * we need to add it to the size to be allocated
+ */
+ p = brcmu_pkt_buf_get_skb(di->rxbufsize + extra_offset);
+
+ if (p == NULL) {
+ DMA_ERROR(("%s: dma_rxfill: out of rxbufs\n",
+ di->name));
+ if (i == 0 && dma64_rxidle(di)) {
+ DMA_ERROR(("%s: rxfill64: ring is empty !\n",
+ di->name));
+ ring_empty = true;
+ }
+ di->dma.rxnobuf++;
+ break;
+ }
+ /* reserve an extra headroom, if applicable */
+ if (extra_offset)
+ skb_pull(p, extra_offset);
+
+ /* Do a cached write instead of uncached write since DMA_MAP
+ * will flush the cache.
+ */
+ *(u32 *) (p->data) = 0;
+
+ pa = pci_map_single(di->pbus, p->data,
+ di->rxbufsize, PCI_DMA_FROMDEVICE);
+
+ /* save the free packet pointer */
+ di->rxp[rxout] = p;
+
+ /* reset flags for each descriptor */
+ flags = 0;
+ if (rxout == (di->nrxd - 1))
+ flags = D64_CTRL1_EOT;
+
+ dma64_dd_upd(di, di->rxd64, pa, rxout, &flags,
+ di->rxbufsize);
+ rxout = nextrxd(di, rxout);
+ }
+
+ di->rxout = rxout;
+
+ /* update the chip lastdscr pointer */
+ W_REG(&di->d64rxregs->ptr,
+ di->rcvptrbase + I2B(rxout, struct dma64desc));
+
+ return ring_empty;
+}
+
+void dma_rxreclaim(struct dma_pub *pub)
+{
+ struct dma_info *di = (struct dma_info *)pub;
+ struct sk_buff *p;
+
+ DMA_TRACE(("%s: dma_rxreclaim\n", di->name));
+
+ while ((p = _dma_getnextrxp(di, true)))
+ brcmu_pkt_buf_free_skb(p);
+}
+
+void dma_counterreset(struct dma_pub *pub)
+{
+ /* reset all software counters */
+ pub->rxgiants = 0;
+ pub->rxnobuf = 0;
+ pub->txnobuf = 0;
+}
+
+/* get the address of the var in order to change later */
+unsigned long dma_getvar(struct dma_pub *pub, const char *name)
+{
+ struct dma_info *di = (struct dma_info *)pub;
+
+ if (!strcmp(name, "&txavail"))
+ return (unsigned long)&(di->dma.txavail);
+ return 0;
+}
+
+/* 64-bit DMA functions */
+
+void dma_txinit(struct dma_pub *pub)
+{
+ struct dma_info *di = (struct dma_info *)pub;
+ u32 control = D64_XC_XE;
+
+ DMA_TRACE(("%s: dma_txinit\n", di->name));
+
+ if (di->ntxd == 0)
+ return;
+
+ di->txin = di->txout = 0;
+ di->dma.txavail = di->ntxd - 1;
+
+ /* clear tx descriptor ring */
+ memset(di->txd64, '\0', (di->ntxd * sizeof(struct dma64desc)));
+
+ /* DMA engine with out alignment requirement requires table to be inited
+ * before enabling the engine
+ */
+ if (!di->aligndesc_4k)
+ _dma_ddtable_init(di, DMA_TX, di->txdpa);
+
+ if ((di->dma.dmactrlflags & DMA_CTRL_PEN) == 0)
+ control |= D64_XC_PD;
+ OR_REG(&di->d64txregs->control, control);
+
+ /* DMA engine with alignment requirement requires table to be inited
+ * before enabling the engine
+ */
+ if (di->aligndesc_4k)
+ _dma_ddtable_init(di, DMA_TX, di->txdpa);
+}
+
+void dma_txsuspend(struct dma_pub *pub)
+{
+ struct dma_info *di = (struct dma_info *)pub;
+
+ DMA_TRACE(("%s: dma_txsuspend\n", di->name));
+
+ if (di->ntxd == 0)
+ return;
+
+ OR_REG(&di->d64txregs->control, D64_XC_SE);
+}
+
+void dma_txresume(struct dma_pub *pub)
+{
+ struct dma_info *di = (struct dma_info *)pub;
+
+ DMA_TRACE(("%s: dma_txresume\n", di->name));
+
+ if (di->ntxd == 0)
+ return;
+
+ AND_REG(&di->d64txregs->control, ~D64_XC_SE);
+}
+
+bool dma_txsuspended(struct dma_pub *pub)
+{
+ struct dma_info *di = (struct dma_info *)pub;
+
+ return (di->ntxd == 0) ||
+ ((R_REG(&di->d64txregs->control) & D64_XC_SE) ==
+ D64_XC_SE);
+}
+
+void dma_txreclaim(struct dma_pub *pub, enum txd_range range)
+{
+ struct dma_info *di = (struct dma_info *)pub;
+ struct sk_buff *p;
+
+ DMA_TRACE(("%s: dma_txreclaim %s\n", di->name,
+ (range == DMA_RANGE_ALL) ? "all" :
+ ((range ==
+ DMA_RANGE_TRANSMITTED) ? "transmitted" :
+ "transferred")));
+
+ if (di->txin == di->txout)
+ return;
+
+ while ((p = dma_getnexttxp(pub, range))) {
+ /* For unframed data, we don't have any packets to free */
+ if (!(di->dma.dmactrlflags & DMA_CTRL_UNFRAMED))
+ brcmu_pkt_buf_free_skb(p);
+ }
+}
+
+bool dma_txreset(struct dma_pub *pub)
+{
+ struct dma_info *di = (struct dma_info *)pub;
+ u32 status;
+
+ if (di->ntxd == 0)
+ return true;
+
+ /* suspend tx DMA first */
+ W_REG(&di->d64txregs->control, D64_XC_SE);
+ SPINWAIT(((status =
+ (R_REG(&di->d64txregs->status0) & D64_XS0_XS_MASK))
+ != D64_XS0_XS_DISABLED) && (status != D64_XS0_XS_IDLE)
+ && (status != D64_XS0_XS_STOPPED), 10000);
+
+ W_REG(&di->d64txregs->control, 0);
+ SPINWAIT(((status =
+ (R_REG(&di->d64txregs->status0) & D64_XS0_XS_MASK))
+ != D64_XS0_XS_DISABLED), 10000);
+
+ /* wait for the last transaction to complete */
+ udelay(300);
+
+ return status == D64_XS0_XS_DISABLED;
+}
+
+bool dma_rxreset(struct dma_pub *pub)
+{
+ struct dma_info *di = (struct dma_info *)pub;
+ u32 status;
+
+ if (di->nrxd == 0)
+ return true;
+
+ W_REG(&di->d64rxregs->control, 0);
+ SPINWAIT(((status =
+ (R_REG(&di->d64rxregs->status0) & D64_RS0_RS_MASK))
+ != D64_RS0_RS_DISABLED), 10000);
+
+ return status == D64_RS0_RS_DISABLED;
+}
+
+/*
+ * !! tx entry routine
+ * WARNING: call must check the return value for error.
+ * the error(toss frames) could be fatal and cause many subsequent hard
+ * to debug problems
+ */
+int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit)
+{
+ struct dma_info *di = (struct dma_info *)pub;
+ struct sk_buff *p, *next;
+ unsigned char *data;
+ uint len;
+ u16 txout;
+ u32 flags = 0;
+ dma_addr_t pa;
+
+ DMA_TRACE(("%s: dma_txfast\n", di->name));
+
+ txout = di->txout;
+
+ /*
+ * Walk the chain of packet buffers
+ * allocating and initializing transmit descriptor entries.
+ */
+ for (p = p0; p; p = next) {
+ data = p->data;
+ len = p->len;
+ next = p->next;
+
+ /* return nonzero if out of tx descriptors */
+ if (nexttxd(di, txout) == di->txin)
+ goto outoftxd;
+
+ if (len == 0)
+ continue;
+
+ /* get physical address of buffer start */
+ pa = pci_map_single(di->pbus, data, len, PCI_DMA_TODEVICE);
+
+ flags = 0;
+ if (p == p0)
+ flags |= D64_CTRL1_SOF;
+
+ /* With a DMA segment list, Descriptor table is filled
+ * using the segment list instead of looping over
+ * buffers in multi-chain DMA. Therefore, EOF for SGLIST
+ * is when end of segment list is reached.
+ */
+ if (next == NULL)
+ flags |= (D64_CTRL1_IOC | D64_CTRL1_EOF);
+ if (txout == (di->ntxd - 1))
+ flags |= D64_CTRL1_EOT;
+
+ dma64_dd_upd(di, di->txd64, pa, txout, &flags, len);
+
+ txout = nexttxd(di, txout);
+ }
+
+ /* if last txd eof not set, fix it */
+ if (!(flags & D64_CTRL1_EOF))
+ di->txd64[prevtxd(di, txout)].ctrl1 =
+ cpu_to_le32(flags | D64_CTRL1_IOC | D64_CTRL1_EOF);
+
+ /* save the packet */
+ di->txp[prevtxd(di, txout)] = p0;
+
+ /* bump the tx descriptor index */
+ di->txout = txout;
+
+ /* kick the chip */
+ if (commit)
+ W_REG(&di->d64txregs->ptr,
+ di->xmtptrbase + I2B(txout, struct dma64desc));
+
+ /* tx flow control */
+ di->dma.txavail = di->ntxd - ntxdactive(di, di->txin, di->txout) - 1;
+
+ return 0;
+
+ outoftxd:
+ DMA_ERROR(("%s: dma_txfast: out of txds !!!\n", di->name));
+ brcmu_pkt_buf_free_skb(p0);
+ di->dma.txavail = 0;
+ di->dma.txnobuf++;
+ return -1;
+}
+
+/*
+ * Reclaim next completed txd (txds if using chained buffers) in the range
+ * specified and return associated packet.
+ * If range is DMA_RANGE_TRANSMITTED, reclaim descriptors that have be
+ * transmitted as noted by the hardware "CurrDescr" pointer.
+ * If range is DMA_RANGE_TRANSFERED, reclaim descriptors that have be
+ * transferred by the DMA as noted by the hardware "ActiveDescr" pointer.
+ * If range is DMA_RANGE_ALL, reclaim all txd(s) posted to the ring and
+ * return associated packet regardless of the value of hardware pointers.
+ */
+struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range)
+{
+ struct dma_info *di = (struct dma_info *)pub;
+ u16 start, end, i;
+ u16 active_desc;
+ struct sk_buff *txp;
+
+ DMA_TRACE(("%s: dma_getnexttxp %s\n", di->name,
+ (range == DMA_RANGE_ALL) ? "all" :
+ ((range ==
+ DMA_RANGE_TRANSMITTED) ? "transmitted" :
+ "transferred")));
+
+ if (di->ntxd == 0)
+ return NULL;
+
+ txp = NULL;
+
+ start = di->txin;
+ if (range == DMA_RANGE_ALL)
+ end = di->txout;
+ else {
+ struct dma64regs __iomem *dregs = di->d64txregs;
+
+ end = (u16) (B2I(((R_REG(&dregs->status0) &
+ D64_XS0_CD_MASK) -
+ di->xmtptrbase) & D64_XS0_CD_MASK,
+ struct dma64desc));
+
+ if (range == DMA_RANGE_TRANSFERED) {
+ active_desc =
+ (u16) (R_REG(&dregs->status1) &
+ D64_XS1_AD_MASK);
+ active_desc =
+ (active_desc - di->xmtptrbase) & D64_XS0_CD_MASK;
+ active_desc = B2I(active_desc, struct dma64desc);
+ if (end != active_desc)
+ end = prevtxd(di, active_desc);
+ }
+ }
+
+ if ((start == 0) && (end > di->txout))
+ goto bogus;
+
+ for (i = start; i != end && !txp; i = nexttxd(di, i)) {
+ dma_addr_t pa;
+ uint size;
+
+ pa = le32_to_cpu(di->txd64[i].addrlow) - di->dataoffsetlow;
+
+ size =
+ (le32_to_cpu(di->txd64[i].ctrl2) &
+ D64_CTRL2_BC_MASK);
+
+ di->txd64[i].addrlow = cpu_to_le32(0xdeadbeef);
+ di->txd64[i].addrhigh = cpu_to_le32(0xdeadbeef);
+
+ txp = di->txp[i];
+ di->txp[i] = NULL;
+
+ pci_unmap_single(di->pbus, pa, size, PCI_DMA_TODEVICE);
+ }
+
+ di->txin = i;
+
+ /* tx flow control */
+ di->dma.txavail = di->ntxd - ntxdactive(di, di->txin, di->txout) - 1;
+
+ return txp;
+
+ bogus:
+ DMA_NONE(("dma_getnexttxp: bogus curr: start %d end %d txout %d "
+ "force %d\n", start, end, di->txout, forceall));
+ return NULL;
+}
+
+/*
+ * Mac80211 initiated actions sometimes require packets in the DMA queue to be
+ * modified. The modified portion of the packet is not under control of the DMA
+ * engine. This function calls a caller-supplied function for each packet in
+ * the caller specified dma chain.
+ */
+void dma_walk_packets(struct dma_pub *dmah, void (*callback_fnc)
+ (void *pkt, void *arg_a), void *arg_a)
+{
+ struct dma_info *di = (struct dma_info *) dmah;
+ uint i = di->txin;
+ uint end = di->txout;
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *tx_info;
+
+ while (i != end) {
+ skb = (struct sk_buff *)di->txp[i];
+ if (skb != NULL) {
+ tx_info = (struct ieee80211_tx_info *)skb->cb;
+ (callback_fnc)(tx_info, arg_a);
+ }
+ i = nexttxd(di, i);
+ }
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.h b/drivers/net/wireless/brcm80211/brcmsmac/dma.h
new file mode 100644
index 000000000000..ebc5bc546f3b
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_DMA_H_
+#define _BRCM_DMA_H_
+
+#include <linux/delay.h>
+#include "types.h" /* forward structure declarations */
+
+/* map/unmap direction */
+#define DMA_TX 1 /* TX direction for DMA */
+#define DMA_RX 2 /* RX direction for DMA */
+
+/* DMA structure:
+ * support two DMA engines: 32 bits address or 64 bit addressing
+ * basic DMA register set is per channel(transmit or receive)
+ * a pair of channels is defined for convenience
+ */
+
+/* 32 bits addressing */
+
+struct dma32diag { /* diag access */
+ u32 fifoaddr; /* diag address */
+ u32 fifodatalow; /* low 32bits of data */
+ u32 fifodatahigh; /* high 32bits of data */
+ u32 pad; /* reserved */
+};
+
+/* 64 bits addressing */
+
+/* dma registers per channel(xmt or rcv) */
+struct dma64regs {
+ u32 control; /* enable, et al */
+ u32 ptr; /* last descriptor posted to chip */
+ u32 addrlow; /* desc ring base address low 32-bits (8K aligned) */
+ u32 addrhigh; /* desc ring base address bits 63:32 (8K aligned) */
+ u32 status0; /* current descriptor, xmt state */
+ u32 status1; /* active descriptor, xmt error */
+};
+
+/* range param for dma_getnexttxp() and dma_txreclaim */
+enum txd_range {
+ DMA_RANGE_ALL = 1,
+ DMA_RANGE_TRANSMITTED,
+ DMA_RANGE_TRANSFERED
+};
+
+/*
+ * Exported data structure (read-only)
+ */
+/* export structure */
+struct dma_pub {
+ uint txavail; /* # free tx descriptors */
+ uint dmactrlflags; /* dma control flags */
+
+ /* rx error counters */
+ uint rxgiants; /* rx giant frames */
+ uint rxnobuf; /* rx out of dma descriptors */
+ /* tx error counters */
+ uint txnobuf; /* tx out of dma descriptors */
+};
+
+extern struct dma_pub *dma_attach(char *name, struct si_pub *sih,
+ void __iomem *dmaregstx, void __iomem *dmaregsrx,
+ uint ntxd, uint nrxd,
+ uint rxbufsize, int rxextheadroom,
+ uint nrxpost, uint rxoffset, uint *msg_level);
+
+void dma_rxinit(struct dma_pub *pub);
+struct sk_buff *dma_rx(struct dma_pub *pub);
+bool dma_rxfill(struct dma_pub *pub);
+bool dma_rxreset(struct dma_pub *pub);
+bool dma_txreset(struct dma_pub *pub);
+void dma_txinit(struct dma_pub *pub);
+int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit);
+void dma_txsuspend(struct dma_pub *pub);
+bool dma_txsuspended(struct dma_pub *pub);
+void dma_txresume(struct dma_pub *pub);
+void dma_txreclaim(struct dma_pub *pub, enum txd_range range);
+void dma_rxreclaim(struct dma_pub *pub);
+void dma_detach(struct dma_pub *pub);
+unsigned long dma_getvar(struct dma_pub *pub, const char *name);
+struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range);
+void dma_counterreset(struct dma_pub *pub);
+
+void dma_walk_packets(struct dma_pub *dmah, void (*callback_fnc)
+ (void *pkt, void *arg_a), void *arg_a);
+
+/*
+ * DMA(Bug) on bcm47xx chips seems to declare that the packet is ready, but
+ * the packet length is not updated yet (by DMA) on the expected time.
+ * Workaround is to hold processor till DMA updates the length, and stay off
+ * the bus to allow DMA update the length in buffer
+ */
+static inline void dma_spin_for_len(uint len, struct sk_buff *head)
+{
+#if defined(CONFIG_BCM47XX)
+ if (!len) {
+ while (!(len = *(u16 *) KSEG1ADDR(head->data)))
+ udelay(1);
+
+ *(u16 *) (head->data) = cpu_to_le16((u16) len);
+ }
+#endif /* defined(CONFIG_BCM47XX) */
+}
+
+#endif /* _BRCM_DMA_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
new file mode 100644
index 000000000000..ac8d02bd34f2
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -0,0 +1,1696 @@
+/*
+ * Copyright (c) 2010 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define __UNDEF_NO_VERSION__
+
+#include <linux/etherdevice.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <net/mac80211.h>
+#include <defs.h>
+#include "nicpci.h"
+#include "phy/phy_int.h"
+#include "d11.h"
+#include "channel.h"
+#include "scb.h"
+#include "pub.h"
+#include "ucode_loader.h"
+#include "mac80211_if.h"
+#include "main.h"
+
+#define N_TX_QUEUES 4 /* #tx queues on mac80211<->driver interface */
+
+/* Flags we support */
+#define MAC_FILTERS (FIF_PROMISC_IN_BSS | \
+ FIF_ALLMULTI | \
+ FIF_FCSFAIL | \
+ FIF_PLCPFAIL | \
+ FIF_CONTROL | \
+ FIF_OTHER_BSS | \
+ FIF_BCN_PRBRESP_PROMISC)
+
+#define CHAN2GHZ(channel, freqency, chflags) { \
+ .band = IEEE80211_BAND_2GHZ, \
+ .center_freq = (freqency), \
+ .hw_value = (channel), \
+ .flags = chflags, \
+ .max_antenna_gain = 0, \
+ .max_power = 19, \
+}
+
+#define CHAN5GHZ(channel, chflags) { \
+ .band = IEEE80211_BAND_5GHZ, \
+ .center_freq = 5000 + 5*(channel), \
+ .hw_value = (channel), \
+ .flags = chflags, \
+ .max_antenna_gain = 0, \
+ .max_power = 21, \
+}
+
+#define RATE(rate100m, _flags) { \
+ .bitrate = (rate100m), \
+ .flags = (_flags), \
+ .hw_value = (rate100m / 5), \
+}
+
+struct firmware_hdr {
+ __le32 offset;
+ __le32 len;
+ __le32 idx;
+};
+
+static const char * const brcms_firmwares[MAX_FW_IMAGES] = {
+ "brcm/bcm43xx",
+ NULL
+};
+
+static int n_adapters_found;
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver.");
+MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards");
+MODULE_LICENSE("Dual BSD/GPL");
+
+/* recognized PCI IDs */
+static DEFINE_PCI_DEVICE_TABLE(brcms_pci_id_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) }, /* 43225 2G */
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) }, /* 43224 DUAL */
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) }, /* 4313 DUAL */
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) }, /* 43224 Ven */
+ {0}
+};
+
+MODULE_DEVICE_TABLE(pci, brcms_pci_id_table);
+
+#ifdef BCMDBG
+static int msglevel = 0xdeadbeef;
+module_param(msglevel, int, 0);
+#endif /* BCMDBG */
+
+static struct ieee80211_channel brcms_2ghz_chantable[] = {
+ CHAN2GHZ(1, 2412, IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN2GHZ(2, 2417, IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN2GHZ(3, 2422, IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN2GHZ(4, 2427, IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN2GHZ(5, 2432, 0),
+ CHAN2GHZ(6, 2437, 0),
+ CHAN2GHZ(7, 2442, 0),
+ CHAN2GHZ(8, 2447, IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN2GHZ(9, 2452, IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN2GHZ(10, 2457, IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN2GHZ(11, 2462, IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN2GHZ(12, 2467,
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN2GHZ(13, 2472,
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN2GHZ(14, 2484,
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS)
+};
+
+static struct ieee80211_channel brcms_5ghz_nphy_chantable[] = {
+ /* UNII-1 */
+ CHAN5GHZ(36, IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN5GHZ(40, IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN5GHZ(44, IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN5GHZ(48, IEEE80211_CHAN_NO_HT40PLUS),
+ /* UNII-2 */
+ CHAN5GHZ(52,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN5GHZ(56,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN5GHZ(60,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN5GHZ(64,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+ /* MID */
+ CHAN5GHZ(100,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN5GHZ(104,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN5GHZ(108,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN5GHZ(112,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN5GHZ(116,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN5GHZ(120,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN5GHZ(124,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN5GHZ(128,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN5GHZ(132,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN5GHZ(136,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN5GHZ(140,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS |
+ IEEE80211_CHAN_NO_HT40MINUS),
+ /* UNII-3 */
+ CHAN5GHZ(149, IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN5GHZ(153, IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN5GHZ(157, IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN5GHZ(161, IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN5GHZ(165, IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS)
+};
+
+/*
+ * The rate table is used for both 2.4G and 5G rates. The
+ * latter being a subset as it does not support CCK rates.
+ */
+static struct ieee80211_rate legacy_ratetable[] = {
+ RATE(10, 0),
+ RATE(20, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATE(55, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATE(110, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATE(60, 0),
+ RATE(90, 0),
+ RATE(120, 0),
+ RATE(180, 0),
+ RATE(240, 0),
+ RATE(360, 0),
+ RATE(480, 0),
+ RATE(540, 0),
+};
+
+static const struct ieee80211_supported_band brcms_band_2GHz_nphy_template = {
+ .band = IEEE80211_BAND_2GHZ,
+ .channels = brcms_2ghz_chantable,
+ .n_channels = ARRAY_SIZE(brcms_2ghz_chantable),
+ .bitrates = legacy_ratetable,
+ .n_bitrates = ARRAY_SIZE(legacy_ratetable),
+ .ht_cap = {
+ /* from include/linux/ieee80211.h */
+ .cap = IEEE80211_HT_CAP_GRN_FLD |
+ IEEE80211_HT_CAP_SGI_20 |
+ IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT,
+ .ht_supported = true,
+ .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
+ .ampdu_density = AMPDU_DEF_MPDU_DENSITY,
+ .mcs = {
+ /* placeholders for now */
+ .rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0},
+ .rx_highest = cpu_to_le16(500),
+ .tx_params = IEEE80211_HT_MCS_TX_DEFINED}
+ }
+};
+
+static const struct ieee80211_supported_band brcms_band_5GHz_nphy_template = {
+ .band = IEEE80211_BAND_5GHZ,
+ .channels = brcms_5ghz_nphy_chantable,
+ .n_channels = ARRAY_SIZE(brcms_5ghz_nphy_chantable),
+ .bitrates = legacy_ratetable + BRCMS_LEGACY_5G_RATE_OFFSET,
+ .n_bitrates = ARRAY_SIZE(legacy_ratetable) -
+ BRCMS_LEGACY_5G_RATE_OFFSET,
+ .ht_cap = {
+ .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 |
+ IEEE80211_HT_CAP_SGI_40 |
+ IEEE80211_HT_CAP_40MHZ_INTOLERANT, /* No 40 mhz yet */
+ .ht_supported = true,
+ .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
+ .ampdu_density = AMPDU_DEF_MPDU_DENSITY,
+ .mcs = {
+ /* placeholders for now */
+ .rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0},
+ .rx_highest = cpu_to_le16(500),
+ .tx_params = IEEE80211_HT_MCS_TX_DEFINED}
+ }
+};
+
+/* flags the given rate in rateset as requested */
+static void brcms_set_basic_rate(struct brcm_rateset *rs, u16 rate, bool is_br)
+{
+ u32 i;
+
+ for (i = 0; i < rs->count; i++) {
+ if (rate != (rs->rates[i] & 0x7f))
+ continue;
+
+ if (is_br)
+ rs->rates[i] |= BRCMS_RATE_FLAG;
+ else
+ rs->rates[i] &= BRCMS_RATE_MASK;
+ return;
+ }
+}
+
+static void brcms_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+ struct brcms_info *wl = hw->priv;
+
+ spin_lock_bh(&wl->lock);
+ if (!wl->pub->up) {
+ wiphy_err(wl->wiphy, "ops->tx called while down\n");
+ kfree_skb(skb);
+ goto done;
+ }
+ brcms_c_sendpkt_mac80211(wl->wlc, skb, hw);
+ done:
+ spin_unlock_bh(&wl->lock);
+}
+
+static int brcms_ops_start(struct ieee80211_hw *hw)
+{
+ struct brcms_info *wl = hw->priv;
+ bool blocked;
+
+ ieee80211_wake_queues(hw);
+ spin_lock_bh(&wl->lock);
+ blocked = brcms_rfkill_set_hw_state(wl);
+ spin_unlock_bh(&wl->lock);
+ if (!blocked)
+ wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
+
+ return 0;
+}
+
+static void brcms_ops_stop(struct ieee80211_hw *hw)
+{
+ ieee80211_stop_queues(hw);
+}
+
+static int
+brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+ struct brcms_info *wl;
+ int err;
+
+ /* Just STA for now */
+ if (vif->type != NL80211_IFTYPE_AP &&
+ vif->type != NL80211_IFTYPE_MESH_POINT &&
+ vif->type != NL80211_IFTYPE_STATION &&
+ vif->type != NL80211_IFTYPE_WDS &&
+ vif->type != NL80211_IFTYPE_ADHOC) {
+ wiphy_err(hw->wiphy, "%s: Attempt to add type %d, only"
+ " STA for now\n", __func__, vif->type);
+ return -EOPNOTSUPP;
+ }
+
+ wl = hw->priv;
+ spin_lock_bh(&wl->lock);
+ if (!wl->pub->up)
+ err = brcms_up(wl);
+ else
+ err = -ENODEV;
+ spin_unlock_bh(&wl->lock);
+
+ if (err != 0)
+ wiphy_err(hw->wiphy, "%s: brcms_up() returned %d\n", __func__,
+ err);
+
+ return err;
+}
+
+static void
+brcms_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+ struct brcms_info *wl;
+
+ wl = hw->priv;
+
+ /* put driver in down state */
+ spin_lock_bh(&wl->lock);
+ brcms_down(wl);
+ spin_unlock_bh(&wl->lock);
+}
+
+static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
+{
+ struct ieee80211_conf *conf = &hw->conf;
+ struct brcms_info *wl = hw->priv;
+ int err = 0;
+ int new_int;
+ struct wiphy *wiphy = hw->wiphy;
+
+ spin_lock_bh(&wl->lock);
+ if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {
+ brcms_c_set_beacon_listen_interval(wl->wlc,
+ conf->listen_interval);
+ }
+ if (changed & IEEE80211_CONF_CHANGE_MONITOR)
+ wiphy_err(wiphy, "%s: change monitor mode: %s (implement)\n",
+ __func__, conf->flags & IEEE80211_CONF_MONITOR ?
+ "true" : "false");
+ if (changed & IEEE80211_CONF_CHANGE_PS)
+ wiphy_err(wiphy, "%s: change power-save mode: %s (implement)\n",
+ __func__, conf->flags & IEEE80211_CONF_PS ?
+ "true" : "false");
+
+ if (changed & IEEE80211_CONF_CHANGE_POWER) {
+ err = brcms_c_set_tx_power(wl->wlc, conf->power_level);
+ if (err < 0) {
+ wiphy_err(wiphy, "%s: Error setting power_level\n",
+ __func__);
+ goto config_out;
+ }
+ new_int = brcms_c_get_tx_power(wl->wlc);
+ if (new_int != conf->power_level)
+ wiphy_err(wiphy, "%s: Power level req != actual, %d %d"
+ "\n", __func__, conf->power_level,
+ new_int);
+ }
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ if (conf->channel_type == NL80211_CHAN_HT20 ||
+ conf->channel_type == NL80211_CHAN_NO_HT)
+ err = brcms_c_set_channel(wl->wlc,
+ conf->channel->hw_value);
+ else
+ err = -ENOTSUPP;
+ }
+ if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+ err = brcms_c_set_rate_limit(wl->wlc,
+ conf->short_frame_max_tx_count,
+ conf->long_frame_max_tx_count);
+
+ config_out:
+ spin_unlock_bh(&wl->lock);
+ return err;
+}
+
+static void
+brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info, u32 changed)
+{
+ struct brcms_info *wl = hw->priv;
+ struct wiphy *wiphy = hw->wiphy;
+
+ if (changed & BSS_CHANGED_ASSOC) {
+ /* association status changed (associated/disassociated)
+ * also implies a change in the AID.
+ */
+ wiphy_err(wiphy, "%s: %s: %sassociated\n", KBUILD_MODNAME,
+ __func__, info->assoc ? "" : "dis");
+ spin_lock_bh(&wl->lock);
+ brcms_c_associate_upd(wl->wlc, info->assoc);
+ spin_unlock_bh(&wl->lock);
+ }
+ if (changed & BSS_CHANGED_ERP_SLOT) {
+ s8 val;
+
+ /* slot timing changed */
+ if (info->use_short_slot)
+ val = 1;
+ else
+ val = 0;
+ spin_lock_bh(&wl->lock);
+ brcms_c_set_shortslot_override(wl->wlc, val);
+ spin_unlock_bh(&wl->lock);
+ }
+
+ if (changed & BSS_CHANGED_HT) {
+ /* 802.11n parameters changed */
+ u16 mode = info->ht_operation_mode;
+
+ spin_lock_bh(&wl->lock);
+ brcms_c_protection_upd(wl->wlc, BRCMS_PROT_N_CFG,
+ mode & IEEE80211_HT_OP_MODE_PROTECTION);
+ brcms_c_protection_upd(wl->wlc, BRCMS_PROT_N_NONGF,
+ mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
+ brcms_c_protection_upd(wl->wlc, BRCMS_PROT_N_OBSS,
+ mode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT);
+ spin_unlock_bh(&wl->lock);
+ }
+ if (changed & BSS_CHANGED_BASIC_RATES) {
+ struct ieee80211_supported_band *bi;
+ u32 br_mask, i;
+ u16 rate;
+ struct brcm_rateset rs;
+ int error;
+
+ /* retrieve the current rates */
+ spin_lock_bh(&wl->lock);
+ brcms_c_get_current_rateset(wl->wlc, &rs);
+ spin_unlock_bh(&wl->lock);
+
+ br_mask = info->basic_rates;
+ bi = hw->wiphy->bands[brcms_c_get_curband(wl->wlc)];
+ for (i = 0; i < bi->n_bitrates; i++) {
+ /* convert to internal rate value */
+ rate = (bi->bitrates[i].bitrate << 1) / 10;
+
+ /* set/clear basic rate flag */
+ brcms_set_basic_rate(&rs, rate, br_mask & 1);
+ br_mask >>= 1;
+ }
+
+ /* update the rate set */
+ spin_lock_bh(&wl->lock);
+ error = brcms_c_set_rateset(wl->wlc, &rs);
+ spin_unlock_bh(&wl->lock);
+ if (error)
+ wiphy_err(wiphy, "changing basic rates failed: %d\n",
+ error);
+ }
+ if (changed & BSS_CHANGED_BEACON_INT) {
+ /* Beacon interval changed */
+ spin_lock_bh(&wl->lock);
+ brcms_c_set_beacon_period(wl->wlc, info->beacon_int);
+ spin_unlock_bh(&wl->lock);
+ }
+ if (changed & BSS_CHANGED_BSSID) {
+ /* BSSID changed, for whatever reason (IBSS and managed mode) */
+ spin_lock_bh(&wl->lock);
+ brcms_c_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET, info->bssid);
+ spin_unlock_bh(&wl->lock);
+ }
+ if (changed & BSS_CHANGED_BEACON)
+ /* Beacon data changed, retrieve new beacon (beaconing modes) */
+ wiphy_err(wiphy, "%s: beacon changed\n", __func__);
+
+ if (changed & BSS_CHANGED_BEACON_ENABLED) {
+ /* Beaconing should be enabled/disabled (beaconing modes) */
+ wiphy_err(wiphy, "%s: Beacon enabled: %s\n", __func__,
+ info->enable_beacon ? "true" : "false");
+ }
+
+ if (changed & BSS_CHANGED_CQM) {
+ /* Connection quality monitor config changed */
+ wiphy_err(wiphy, "%s: cqm change: threshold %d, hys %d "
+ " (implement)\n", __func__, info->cqm_rssi_thold,
+ info->cqm_rssi_hyst);
+ }
+
+ if (changed & BSS_CHANGED_IBSS) {
+ /* IBSS join status changed */
+ wiphy_err(wiphy, "%s: IBSS joined: %s (implement)\n", __func__,
+ info->ibss_joined ? "true" : "false");
+ }
+
+ if (changed & BSS_CHANGED_ARP_FILTER) {
+ /* Hardware ARP filter address list or state changed */
+ wiphy_err(wiphy, "%s: arp filtering: enabled %s, count %d"
+ " (implement)\n", __func__, info->arp_filter_enabled ?
+ "true" : "false", info->arp_addr_cnt);
+ }
+
+ if (changed & BSS_CHANGED_QOS) {
+ /*
+ * QoS for this association was enabled/disabled.
+ * Note that it is only ever disabled for station mode.
+ */
+ wiphy_err(wiphy, "%s: qos enabled: %s (implement)\n", __func__,
+ info->qos ? "true" : "false");
+ }
+ return;
+}
+
+static void
+brcms_ops_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags, u64 multicast)
+{
+ struct brcms_info *wl = hw->priv;
+ struct wiphy *wiphy = hw->wiphy;
+
+ changed_flags &= MAC_FILTERS;
+ *total_flags &= MAC_FILTERS;
+ if (changed_flags & FIF_PROMISC_IN_BSS)
+ wiphy_err(wiphy, "FIF_PROMISC_IN_BSS\n");
+ if (changed_flags & FIF_ALLMULTI)
+ wiphy_err(wiphy, "FIF_ALLMULTI\n");
+ if (changed_flags & FIF_FCSFAIL)
+ wiphy_err(wiphy, "FIF_FCSFAIL\n");
+ if (changed_flags & FIF_PLCPFAIL)
+ wiphy_err(wiphy, "FIF_PLCPFAIL\n");
+ if (changed_flags & FIF_CONTROL)
+ wiphy_err(wiphy, "FIF_CONTROL\n");
+ if (changed_flags & FIF_OTHER_BSS)
+ wiphy_err(wiphy, "FIF_OTHER_BSS\n");
+ if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+ spin_lock_bh(&wl->lock);
+ if (*total_flags & FIF_BCN_PRBRESP_PROMISC) {
+ wl->pub->mac80211_state |= MAC80211_PROMISC_BCNS;
+ brcms_c_mac_bcn_promisc_change(wl->wlc, 1);
+ } else {
+ brcms_c_mac_bcn_promisc_change(wl->wlc, 0);
+ wl->pub->mac80211_state &= ~MAC80211_PROMISC_BCNS;
+ }
+ spin_unlock_bh(&wl->lock);
+ }
+ return;
+}
+
+static void brcms_ops_sw_scan_start(struct ieee80211_hw *hw)
+{
+ struct brcms_info *wl = hw->priv;
+ spin_lock_bh(&wl->lock);
+ brcms_c_scan_start(wl->wlc);
+ spin_unlock_bh(&wl->lock);
+ return;
+}
+
+static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw)
+{
+ struct brcms_info *wl = hw->priv;
+ spin_lock_bh(&wl->lock);
+ brcms_c_scan_stop(wl->wlc);
+ spin_unlock_bh(&wl->lock);
+ return;
+}
+
+static int
+brcms_ops_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct brcms_info *wl = hw->priv;
+
+ spin_lock_bh(&wl->lock);
+ brcms_c_wme_setparams(wl->wlc, queue, params, true);
+ spin_unlock_bh(&wl->lock);
+
+ return 0;
+}
+
+static int
+brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct brcms_info *wl = hw->priv;
+ struct scb *scb = &wl->wlc->pri_scb;
+
+ brcms_c_init_scb(scb);
+
+ wl->pub->global_ampdu = &(scb->scb_ampdu);
+ wl->pub->global_ampdu->scb = scb;
+ wl->pub->global_ampdu->max_pdu = 16;
+
+ sta->ht_cap.ht_supported = true;
+ sta->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+ sta->ht_cap.ampdu_density = AMPDU_DEF_MPDU_DENSITY;
+ sta->ht_cap.cap = IEEE80211_HT_CAP_GRN_FLD |
+ IEEE80211_HT_CAP_SGI_20 |
+ IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT;
+
+ /*
+ * minstrel_ht initiates addBA on our behalf by calling
+ * ieee80211_start_tx_ba_session()
+ */
+ return 0;
+}
+
+static int
+brcms_ops_ampdu_action(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum ieee80211_ampdu_mlme_action action,
+ struct ieee80211_sta *sta, u16 tid, u16 *ssn,
+ u8 buf_size)
+{
+ struct brcms_info *wl = hw->priv;
+ struct scb *scb = &wl->wlc->pri_scb;
+ int status;
+
+ if (WARN_ON(scb->magic != SCB_MAGIC))
+ return -EIDRM;
+ switch (action) {
+ case IEEE80211_AMPDU_RX_START:
+ break;
+ case IEEE80211_AMPDU_RX_STOP:
+ break;
+ case IEEE80211_AMPDU_TX_START:
+ spin_lock_bh(&wl->lock);
+ status = brcms_c_aggregatable(wl->wlc, tid);
+ spin_unlock_bh(&wl->lock);
+ if (!status) {
+ wiphy_err(wl->wiphy, "START: tid %d is not agg\'able\n",
+ tid);
+ return -EINVAL;
+ }
+ ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ break;
+
+ case IEEE80211_AMPDU_TX_STOP:
+ spin_lock_bh(&wl->lock);
+ brcms_c_ampdu_flush(wl->wlc, sta, tid);
+ spin_unlock_bh(&wl->lock);
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ break;
+ case IEEE80211_AMPDU_TX_OPERATIONAL:
+ /*
+ * BA window size from ADDBA response ('buf_size') defines how
+ * many outstanding MPDUs are allowed for the BA stream by
+ * recipient and traffic class. 'ampdu_factor' gives maximum
+ * AMPDU size.
+ */
+ spin_lock_bh(&wl->lock);
+ brcms_c_ampdu_tx_operational(wl->wlc, tid, buf_size,
+ (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
+ sta->ht_cap.ampdu_factor)) - 1);
+ spin_unlock_bh(&wl->lock);
+ /* Power save wakeup */
+ break;
+ default:
+ wiphy_err(wl->wiphy, "%s: Invalid command, ignoring\n",
+ __func__);
+ }
+
+ return 0;
+}
+
+static void brcms_ops_rfkill_poll(struct ieee80211_hw *hw)
+{
+ struct brcms_info *wl = hw->priv;
+ bool blocked;
+
+ spin_lock_bh(&wl->lock);
+ blocked = brcms_c_check_radio_disabled(wl->wlc);
+ spin_unlock_bh(&wl->lock);
+
+ wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked);
+}
+
+static void brcms_ops_flush(struct ieee80211_hw *hw, bool drop)
+{
+ struct brcms_info *wl = hw->priv;
+
+ no_printk("%s: drop = %s\n", __func__, drop ? "true" : "false");
+
+ /* wait for packet queue and dma fifos to run empty */
+ spin_lock_bh(&wl->lock);
+ brcms_c_wait_for_tx_completion(wl->wlc, drop);
+ spin_unlock_bh(&wl->lock);
+}
+
+static const struct ieee80211_ops brcms_ops = {
+ .tx = brcms_ops_tx,
+ .start = brcms_ops_start,
+ .stop = brcms_ops_stop,
+ .add_interface = brcms_ops_add_interface,
+ .remove_interface = brcms_ops_remove_interface,
+ .config = brcms_ops_config,
+ .bss_info_changed = brcms_ops_bss_info_changed,
+ .configure_filter = brcms_ops_configure_filter,
+ .sw_scan_start = brcms_ops_sw_scan_start,
+ .sw_scan_complete = brcms_ops_sw_scan_complete,
+ .conf_tx = brcms_ops_conf_tx,
+ .sta_add = brcms_ops_sta_add,
+ .ampdu_action = brcms_ops_ampdu_action,
+ .rfkill_poll = brcms_ops_rfkill_poll,
+ .flush = brcms_ops_flush,
+};
+
+/*
+ * is called in brcms_pci_probe() context, therefore no locking required.
+ */
+static int brcms_set_hint(struct brcms_info *wl, char *abbrev)
+{
+ return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev);
+}
+
+void brcms_dpc(unsigned long data)
+{
+ struct brcms_info *wl;
+
+ wl = (struct brcms_info *) data;
+
+ spin_lock_bh(&wl->lock);
+
+ /* call the common second level interrupt handler */
+ if (wl->pub->up) {
+ if (wl->resched) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&wl->isr_lock, flags);
+ brcms_c_intrsupd(wl->wlc);
+ spin_unlock_irqrestore(&wl->isr_lock, flags);
+ }
+
+ wl->resched = brcms_c_dpc(wl->wlc, true);
+ }
+
+ /* brcms_c_dpc() may bring the driver down */
+ if (!wl->pub->up)
+ goto done;
+
+ /* re-schedule dpc */
+ if (wl->resched)
+ tasklet_schedule(&wl->tasklet);
+ else
+ /* re-enable interrupts */
+ brcms_intrson(wl);
+
+ done:
+ spin_unlock_bh(&wl->lock);
+}
+
+/*
+ * Precondition: Since this function is called in brcms_pci_probe() context,
+ * no locking is required.
+ */
+static int brcms_request_fw(struct brcms_info *wl, struct pci_dev *pdev)
+{
+ int status;
+ struct device *device = &pdev->dev;
+ char fw_name[100];
+ int i;
+
+ memset(&wl->fw, 0, sizeof(struct brcms_firmware));
+ for (i = 0; i < MAX_FW_IMAGES; i++) {
+ if (brcms_firmwares[i] == NULL)
+ break;
+ sprintf(fw_name, "%s-%d.fw", brcms_firmwares[i],
+ UCODE_LOADER_API_VER);
+ status = request_firmware(&wl->fw.fw_bin[i], fw_name, device);
+ if (status) {
+ wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n",
+ KBUILD_MODNAME, fw_name);
+ return status;
+ }
+ sprintf(fw_name, "%s_hdr-%d.fw", brcms_firmwares[i],
+ UCODE_LOADER_API_VER);
+ status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device);
+ if (status) {
+ wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n",
+ KBUILD_MODNAME, fw_name);
+ return status;
+ }
+ wl->fw.hdr_num_entries[i] =
+ wl->fw.fw_hdr[i]->size / (sizeof(struct firmware_hdr));
+ }
+ wl->fw.fw_cnt = i;
+ return brcms_ucode_data_init(wl, &wl->ucode);
+}
+
+/*
+ * Precondition: Since this function is called in brcms_pci_probe() context,
+ * no locking is required.
+ */
+static void brcms_release_fw(struct brcms_info *wl)
+{
+ int i;
+ for (i = 0; i < MAX_FW_IMAGES; i++) {
+ release_firmware(wl->fw.fw_bin[i]);
+ release_firmware(wl->fw.fw_hdr[i]);
+ }
+}
+
+/**
+ * This function frees the WL per-device resources.
+ *
+ * This function frees resources owned by the WL device pointed to
+ * by the wl parameter.
+ *
+ * precondition: can both be called locked and unlocked
+ *
+ */
+static void brcms_free(struct brcms_info *wl)
+{
+ struct brcms_timer *t, *next;
+
+ /* free ucode data */
+ if (wl->fw.fw_cnt)
+ brcms_ucode_data_free(&wl->ucode);
+ if (wl->irq)
+ free_irq(wl->irq, wl);
+
+ /* kill dpc */
+ tasklet_kill(&wl->tasklet);
+
+ if (wl->pub)
+ brcms_c_module_unregister(wl->pub, "linux", wl);
+
+ /* free common resources */
+ if (wl->wlc) {
+ brcms_c_detach(wl->wlc);
+ wl->wlc = NULL;
+ wl->pub = NULL;
+ }
+
+ /* virtual interface deletion is deferred so we cannot spinwait */
+
+ /* wait for all pending callbacks to complete */
+ while (atomic_read(&wl->callbacks) > 0)
+ schedule();
+
+ /* free timers */
+ for (t = wl->timers; t; t = next) {
+ next = t->next;
+#ifdef BCMDBG
+ kfree(t->name);
+#endif
+ kfree(t);
+ }
+
+ /*
+ * unregister_netdev() calls get_stats() which may read chip
+ * registers so we cannot unmap the chip registers until
+ * after calling unregister_netdev() .
+ */
+ if (wl->regsva)
+ iounmap(wl->regsva);
+
+ wl->regsva = NULL;
+}
+
+/*
+* called from both kernel as from this kernel module.
+* precondition: perimeter lock is not acquired.
+*/
+static void brcms_remove(struct pci_dev *pdev)
+{
+ struct brcms_info *wl;
+ struct ieee80211_hw *hw;
+ int status;
+
+ hw = pci_get_drvdata(pdev);
+ wl = hw->priv;
+ if (!wl) {
+ pr_err("wl: brcms_remove: pci_get_drvdata failed\n");
+ return;
+ }
+
+ spin_lock_bh(&wl->lock);
+ status = brcms_c_chipmatch(pdev->vendor, pdev->device);
+ spin_unlock_bh(&wl->lock);
+ if (!status) {
+ wiphy_err(wl->wiphy, "wl: brcms_remove: chipmatch "
+ "failed\n");
+ return;
+ }
+ if (wl->wlc) {
+ wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false);
+ wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
+ ieee80211_unregister_hw(hw);
+ spin_lock_bh(&wl->lock);
+ brcms_down(wl);
+ spin_unlock_bh(&wl->lock);
+ }
+ pci_disable_device(pdev);
+
+ brcms_free(wl);
+
+ pci_set_drvdata(pdev, NULL);
+ ieee80211_free_hw(hw);
+}
+
+static irqreturn_t brcms_isr(int irq, void *dev_id)
+{
+ struct brcms_info *wl;
+ bool ours, wantdpc;
+
+ wl = (struct brcms_info *) dev_id;
+
+ spin_lock(&wl->isr_lock);
+
+ /* call common first level interrupt handler */
+ ours = brcms_c_isr(wl->wlc, &wantdpc);
+ if (ours) {
+ /* if more to do... */
+ if (wantdpc) {
+
+ /* ...and call the second level interrupt handler */
+ /* schedule dpc */
+ tasklet_schedule(&wl->tasklet);
+ }
+ }
+
+ spin_unlock(&wl->isr_lock);
+
+ return IRQ_RETVAL(ours);
+}
+
+/*
+ * is called in brcms_pci_probe() context, therefore no locking required.
+ */
+static int ieee_hw_rate_init(struct ieee80211_hw *hw)
+{
+ struct brcms_info *wl = hw->priv;
+ struct brcms_c_info *wlc = wl->wlc;
+ struct ieee80211_supported_band *band;
+ int has_5g = 0;
+ u16 phy_type;
+
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
+ hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
+
+ phy_type = brcms_c_get_phy_type(wl->wlc, 0);
+ if (phy_type == PHY_TYPE_N || phy_type == PHY_TYPE_LCN) {
+ band = &wlc->bandstate[BAND_2G_INDEX]->band;
+ *band = brcms_band_2GHz_nphy_template;
+ if (phy_type == PHY_TYPE_LCN) {
+ /* Single stream */
+ band->ht_cap.mcs.rx_mask[1] = 0;
+ band->ht_cap.mcs.rx_highest = cpu_to_le16(72);
+ }
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = band;
+ } else {
+ return -EPERM;
+ }
+
+ /* Assume all bands use the same phy. True for 11n devices. */
+ if (wl->pub->_nbands > 1) {
+ has_5g++;
+ if (phy_type == PHY_TYPE_N || phy_type == PHY_TYPE_LCN) {
+ band = &wlc->bandstate[BAND_5G_INDEX]->band;
+ *band = brcms_band_5GHz_nphy_template;
+ hw->wiphy->bands[IEEE80211_BAND_5GHZ] = band;
+ } else {
+ return -EPERM;
+ }
+ }
+ return 0;
+}
+
+/*
+ * is called in brcms_pci_probe() context, therefore no locking required.
+ */
+static int ieee_hw_init(struct ieee80211_hw *hw)
+{
+ hw->flags = IEEE80211_HW_SIGNAL_DBM
+ /* | IEEE80211_HW_CONNECTION_MONITOR What is this? */
+ | IEEE80211_HW_REPORTS_TX_ACK_STATUS
+ | IEEE80211_HW_AMPDU_AGGREGATION;
+
+ hw->extra_tx_headroom = brcms_c_get_header_len();
+ hw->queues = N_TX_QUEUES;
+ hw->max_rates = 2; /* Primary rate and 1 fallback rate */
+
+ /* channel change time is dependent on chip and band */
+ hw->channel_change_time = 7 * 1000;
+ hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+
+ hw->rate_control_algorithm = "minstrel_ht";
+
+ hw->sta_data_size = 0;
+ return ieee_hw_rate_init(hw);
+}
+
+/**
+ * attach to the WL device.
+ *
+ * Attach to the WL device identified by vendor and device parameters.
+ * regs is a host accessible memory address pointing to WL device registers.
+ *
+ * brcms_attach is not defined as static because in the case where no bus
+ * is defined, wl_attach will never be called, and thus, gcc will issue
+ * a warning that this function is defined but not used if we declare
+ * it as static.
+ *
+ *
+ * is called in brcms_pci_probe() context, therefore no locking required.
+ */
+static struct brcms_info *brcms_attach(u16 vendor, u16 device,
+ resource_size_t regs,
+ struct pci_dev *btparam, uint irq)
+{
+ struct brcms_info *wl = NULL;
+ int unit, err;
+ struct ieee80211_hw *hw;
+ u8 perm[ETH_ALEN];
+
+ unit = n_adapters_found;
+ err = 0;
+
+ if (unit < 0)
+ return NULL;
+
+ /* allocate private info */
+ hw = pci_get_drvdata(btparam); /* btparam == pdev */
+ if (hw != NULL)
+ wl = hw->priv;
+ if (WARN_ON(hw == NULL) || WARN_ON(wl == NULL))
+ return NULL;
+ wl->wiphy = hw->wiphy;
+
+ atomic_set(&wl->callbacks, 0);
+
+ /* setup the bottom half handler */
+ tasklet_init(&wl->tasklet, brcms_dpc, (unsigned long) wl);
+
+ wl->regsva = ioremap_nocache(regs, PCI_BAR0_WINSZ);
+ if (wl->regsva == NULL) {
+ wiphy_err(wl->wiphy, "wl%d: ioremap() failed\n", unit);
+ goto fail;
+ }
+ spin_lock_init(&wl->lock);
+ spin_lock_init(&wl->isr_lock);
+
+ /* prepare ucode */
+ if (brcms_request_fw(wl, btparam) < 0) {
+ wiphy_err(wl->wiphy, "%s: Failed to find firmware usually in "
+ "%s\n", KBUILD_MODNAME, "/lib/firmware/brcm");
+ brcms_release_fw(wl);
+ brcms_remove(btparam);
+ return NULL;
+ }
+
+ /* common load-time initialization */
+ wl->wlc = brcms_c_attach(wl, vendor, device, unit, false,
+ wl->regsva, btparam, &err);
+ brcms_release_fw(wl);
+ if (!wl->wlc) {
+ wiphy_err(wl->wiphy, "%s: attach() failed with code %d\n",
+ KBUILD_MODNAME, err);
+ goto fail;
+ }
+ wl->pub = brcms_c_pub(wl->wlc);
+
+ wl->pub->ieee_hw = hw;
+
+ /* disable mpc */
+ brcms_c_set_radio_mpc(wl->wlc, false);
+
+ /* register our interrupt handler */
+ if (request_irq(irq, brcms_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) {
+ wiphy_err(wl->wiphy, "wl%d: request_irq() failed\n", unit);
+ goto fail;
+ }
+ wl->irq = irq;
+
+ /* register module */
+ brcms_c_module_register(wl->pub, "linux", wl, NULL);
+
+ if (ieee_hw_init(hw)) {
+ wiphy_err(wl->wiphy, "wl%d: %s: ieee_hw_init failed!\n", unit,
+ __func__);
+ goto fail;
+ }
+
+ memcpy(perm, &wl->pub->cur_etheraddr, ETH_ALEN);
+ if (WARN_ON(!is_valid_ether_addr(perm)))
+ goto fail;
+ SET_IEEE80211_PERM_ADDR(hw, perm);
+
+ err = ieee80211_register_hw(hw);
+ if (err)
+ wiphy_err(wl->wiphy, "%s: ieee80211_register_hw failed, status"
+ "%d\n", __func__, err);
+
+ if (wl->pub->srom_ccode[0])
+ err = brcms_set_hint(wl, wl->pub->srom_ccode);
+ else
+ err = brcms_set_hint(wl, "US");
+ if (err)
+ wiphy_err(wl->wiphy, "%s: regulatory_hint failed, status %d\n",
+ __func__, err);
+
+ n_adapters_found++;
+ return wl;
+
+fail:
+ brcms_free(wl);
+ return NULL;
+}
+
+
+
+/**
+ * determines if a device is a WL device, and if so, attaches it.
+ *
+ * This function determines if a device pointed to by pdev is a WL device,
+ * and if so, performs a brcms_attach() on it.
+ *
+ * Perimeter lock is initialized in the course of this function.
+ */
+static int __devinit
+brcms_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int rc;
+ struct brcms_info *wl;
+ struct ieee80211_hw *hw;
+ u32 val;
+
+ dev_info(&pdev->dev, "bus %d slot %d func %d irq %d\n",
+ pdev->bus->number, PCI_SLOT(pdev->devfn),
+ PCI_FUNC(pdev->devfn), pdev->irq);
+
+ if ((pdev->vendor != PCI_VENDOR_ID_BROADCOM) ||
+ ((pdev->device != 0x0576) &&
+ ((pdev->device & 0xff00) != 0x4300) &&
+ ((pdev->device & 0xff00) != 0x4700) &&
+ ((pdev->device < 43000) || (pdev->device > 43999))))
+ return -ENODEV;
+
+ rc = pci_enable_device(pdev);
+ if (rc) {
+ pr_err("%s: Cannot enable device %d-%d_%d\n",
+ __func__, pdev->bus->number, PCI_SLOT(pdev->devfn),
+ PCI_FUNC(pdev->devfn));
+ return -ENODEV;
+ }
+ pci_set_master(pdev);
+
+ pci_read_config_dword(pdev, 0x40, &val);
+ if ((val & 0x0000ff00) != 0)
+ pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
+
+ hw = ieee80211_alloc_hw(sizeof(struct brcms_info), &brcms_ops);
+ if (!hw) {
+ pr_err("%s: ieee80211_alloc_hw failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ SET_IEEE80211_DEV(hw, &pdev->dev);
+
+ pci_set_drvdata(pdev, hw);
+
+ memset(hw->priv, 0, sizeof(*wl));
+
+ wl = brcms_attach(pdev->vendor, pdev->device,
+ pci_resource_start(pdev, 0), pdev,
+ pdev->irq);
+
+ if (!wl) {
+ pr_err("%s: %s: brcms_attach failed!\n", KBUILD_MODNAME,
+ __func__);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int brcms_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct brcms_info *wl;
+ struct ieee80211_hw *hw;
+
+ hw = pci_get_drvdata(pdev);
+ wl = hw->priv;
+ if (!wl) {
+ wiphy_err(wl->wiphy,
+ "brcms_suspend: pci_get_drvdata failed\n");
+ return -ENODEV;
+ }
+
+ /* only need to flag hw is down for proper resume */
+ spin_lock_bh(&wl->lock);
+ wl->pub->hw_up = false;
+ spin_unlock_bh(&wl->lock);
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ return pci_set_power_state(pdev, PCI_D3hot);
+}
+
+static int brcms_resume(struct pci_dev *pdev)
+{
+ struct brcms_info *wl;
+ struct ieee80211_hw *hw;
+ int err = 0;
+ u32 val;
+
+ hw = pci_get_drvdata(pdev);
+ wl = hw->priv;
+ if (!wl) {
+ wiphy_err(wl->wiphy,
+ "wl: brcms_resume: pci_get_drvdata failed\n");
+ return -ENODEV;
+ }
+
+ err = pci_set_power_state(pdev, PCI_D0);
+ if (err)
+ return err;
+
+ pci_restore_state(pdev);
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+
+ pci_set_master(pdev);
+
+ pci_read_config_dword(pdev, 0x40, &val);
+ if ((val & 0x0000ff00) != 0)
+ pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
+
+ /*
+ * done. driver will be put in up state
+ * in brcms_ops_add_interface() call.
+ */
+ return err;
+}
+
+static struct pci_driver brcms_pci_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = brcms_pci_probe,
+ .suspend = brcms_suspend,
+ .resume = brcms_resume,
+ .remove = __devexit_p(brcms_remove),
+ .id_table = brcms_pci_id_table,
+};
+
+/**
+ * This is the main entry point for the WL driver.
+ *
+ * This function determines if a device pointed to by pdev is a WL device,
+ * and if so, performs a brcms_attach() on it.
+ *
+ */
+static int __init brcms_module_init(void)
+{
+ int error = -ENODEV;
+
+#ifdef BCMDBG
+ if (msglevel != 0xdeadbeef)
+ brcm_msg_level = msglevel;
+#endif /* BCMDBG */
+
+ error = pci_register_driver(&brcms_pci_driver);
+ if (!error)
+ return 0;
+
+
+
+ return error;
+}
+
+/**
+ * This function unloads the WL driver from the system.
+ *
+ * This function unconditionally unloads the WL driver module from the
+ * system.
+ *
+ */
+static void __exit brcms_module_exit(void)
+{
+ pci_unregister_driver(&brcms_pci_driver);
+
+}
+
+module_init(brcms_module_init);
+module_exit(brcms_module_exit);
+
+/*
+ * precondition: perimeter lock has been acquired
+ */
+void brcms_txflowcontrol(struct brcms_info *wl, struct brcms_if *wlif,
+ bool state, int prio)
+{
+ wiphy_err(wl->wiphy, "Shouldn't be here %s\n", __func__);
+}
+
+/*
+ * precondition: perimeter lock has been acquired
+ */
+void brcms_init(struct brcms_info *wl)
+{
+ BCMMSG(wl->pub->ieee_hw->wiphy, "wl%d\n", wl->pub->unit);
+ brcms_reset(wl);
+
+ brcms_c_init(wl->wlc);
+}
+
+/*
+ * precondition: perimeter lock has been acquired
+ */
+uint brcms_reset(struct brcms_info *wl)
+{
+ BCMMSG(wl->pub->ieee_hw->wiphy, "wl%d\n", wl->pub->unit);
+ brcms_c_reset(wl->wlc);
+
+ /* dpc will not be rescheduled */
+ wl->resched = 0;
+
+ return 0;
+}
+
+/*
+ * These are interrupt on/off entry points. Disable interrupts
+ * during interrupt state transition.
+ */
+void brcms_intrson(struct brcms_info *wl)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wl->isr_lock, flags);
+ brcms_c_intrson(wl->wlc);
+ spin_unlock_irqrestore(&wl->isr_lock, flags);
+}
+
+u32 brcms_intrsoff(struct brcms_info *wl)
+{
+ unsigned long flags;
+ u32 status;
+
+ spin_lock_irqsave(&wl->isr_lock, flags);
+ status = brcms_c_intrsoff(wl->wlc);
+ spin_unlock_irqrestore(&wl->isr_lock, flags);
+ return status;
+}
+
+void brcms_intrsrestore(struct brcms_info *wl, u32 macintmask)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wl->isr_lock, flags);
+ brcms_c_intrsrestore(wl->wlc, macintmask);
+ spin_unlock_irqrestore(&wl->isr_lock, flags);
+}
+
+/*
+ * precondition: perimeter lock has been acquired
+ */
+int brcms_up(struct brcms_info *wl)
+{
+ int error = 0;
+
+ if (wl->pub->up)
+ return 0;
+
+ error = brcms_c_up(wl->wlc);
+
+ return error;
+}
+
+/*
+ * precondition: perimeter lock has been acquired
+ */
+void brcms_down(struct brcms_info *wl)
+{
+ uint callbacks, ret_val = 0;
+
+ /* call common down function */
+ ret_val = brcms_c_down(wl->wlc);
+ callbacks = atomic_read(&wl->callbacks) - ret_val;
+
+ /* wait for down callbacks to complete */
+ spin_unlock_bh(&wl->lock);
+
+ /* For HIGH_only driver, it's important to actually schedule other work,
+ * not just spin wait since everything runs at schedule level
+ */
+ SPINWAIT((atomic_read(&wl->callbacks) > callbacks), 100 * 1000);
+
+ spin_lock_bh(&wl->lock);
+}
+
+/*
+* precondition: perimeter lock is not acquired
+ */
+static void _brcms_timer(struct work_struct *work)
+{
+ struct brcms_timer *t = container_of(work, struct brcms_timer,
+ dly_wrk.work);
+
+ spin_lock_bh(&t->wl->lock);
+
+ if (t->set) {
+ if (t->periodic) {
+ atomic_inc(&t->wl->callbacks);
+ ieee80211_queue_delayed_work(t->wl->pub->ieee_hw,
+ &t->dly_wrk,
+ msecs_to_jiffies(t->ms));
+ } else {
+ t->set = false;
+ }
+
+ t->fn(t->arg);
+ }
+
+ atomic_dec(&t->wl->callbacks);
+
+ spin_unlock_bh(&t->wl->lock);
+}
+
+/*
+ * Adds a timer to the list. Caller supplies a timer function.
+ * Is called from wlc.
+ *
+ * precondition: perimeter lock has been acquired
+ */
+struct brcms_timer *brcms_init_timer(struct brcms_info *wl,
+ void (*fn) (void *arg),
+ void *arg, const char *name)
+{
+ struct brcms_timer *t;
+
+ t = kzalloc(sizeof(struct brcms_timer), GFP_ATOMIC);
+ if (!t)
+ return NULL;
+
+ INIT_DELAYED_WORK(&t->dly_wrk, _brcms_timer);
+ t->wl = wl;
+ t->fn = fn;
+ t->arg = arg;
+ t->next = wl->timers;
+ wl->timers = t;
+
+#ifdef BCMDBG
+ t->name = kmalloc(strlen(name) + 1, GFP_ATOMIC);
+ if (t->name)
+ strcpy(t->name, name);
+#endif
+
+ return t;
+}
+
+/*
+ * adds only the kernel timer since it's going to be more accurate
+ * as well as it's easier to make it periodic
+ *
+ * precondition: perimeter lock has been acquired
+ */
+void brcms_add_timer(struct brcms_timer *t, uint ms, int periodic)
+{
+ struct ieee80211_hw *hw = t->wl->pub->ieee_hw;
+
+#ifdef BCMDBG
+ if (t->set)
+ wiphy_err(hw->wiphy, "%s: Already set. Name: %s, per %d\n",
+ __func__, t->name, periodic);
+#endif
+ t->ms = ms;
+ t->periodic = (bool) periodic;
+ t->set = true;
+
+ atomic_inc(&t->wl->callbacks);
+
+ ieee80211_queue_delayed_work(hw, &t->dly_wrk, msecs_to_jiffies(ms));
+}
+
+/*
+ * return true if timer successfully deleted, false if still pending
+ *
+ * precondition: perimeter lock has been acquired
+ */
+bool brcms_del_timer(struct brcms_timer *t)
+{
+ if (t->set) {
+ t->set = false;
+ if (!cancel_delayed_work(&t->dly_wrk))
+ return false;
+
+ atomic_dec(&t->wl->callbacks);
+ }
+
+ return true;
+}
+
+/*
+ * precondition: perimeter lock has been acquired
+ */
+void brcms_free_timer(struct brcms_timer *t)
+{
+ struct brcms_info *wl = t->wl;
+ struct brcms_timer *tmp;
+
+ /* delete the timer in case it is active */
+ brcms_del_timer(t);
+
+ if (wl->timers == t) {
+ wl->timers = wl->timers->next;
+#ifdef BCMDBG
+ kfree(t->name);
+#endif
+ kfree(t);
+ return;
+
+ }
+
+ tmp = wl->timers;
+ while (tmp) {
+ if (tmp->next == t) {
+ tmp->next = t->next;
+#ifdef BCMDBG
+ kfree(t->name);
+#endif
+ kfree(t);
+ return;
+ }
+ tmp = tmp->next;
+ }
+
+}
+
+/*
+ * precondition: perimeter lock has been acquired
+ */
+int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, u32 idx)
+{
+ int i, entry;
+ const u8 *pdata;
+ struct firmware_hdr *hdr;
+ for (i = 0; i < wl->fw.fw_cnt; i++) {
+ hdr = (struct firmware_hdr *)wl->fw.fw_hdr[i]->data;
+ for (entry = 0; entry < wl->fw.hdr_num_entries[i];
+ entry++, hdr++) {
+ u32 len = le32_to_cpu(hdr->len);
+ if (le32_to_cpu(hdr->idx) == idx) {
+ pdata = wl->fw.fw_bin[i]->data +
+ le32_to_cpu(hdr->offset);
+ *pbuf = kmalloc(len, GFP_ATOMIC);
+ if (*pbuf == NULL)
+ goto fail;
+
+ memcpy(*pbuf, pdata, len);
+ return 0;
+ }
+ }
+ }
+ wiphy_err(wl->wiphy, "ERROR: ucode buf tag:%d can not be found!\n",
+ idx);
+ *pbuf = NULL;
+fail:
+ return -ENODATA;
+}
+
+/*
+ * Precondition: Since this function is called in brcms_pci_probe() context,
+ * no locking is required.
+ */
+int brcms_ucode_init_uint(struct brcms_info *wl, size_t *n_bytes, u32 idx)
+{
+ int i, entry;
+ const u8 *pdata;
+ struct firmware_hdr *hdr;
+ for (i = 0; i < wl->fw.fw_cnt; i++) {
+ hdr = (struct firmware_hdr *)wl->fw.fw_hdr[i]->data;
+ for (entry = 0; entry < wl->fw.hdr_num_entries[i];
+ entry++, hdr++) {
+ if (le32_to_cpu(hdr->idx) == idx) {
+ pdata = wl->fw.fw_bin[i]->data +
+ le32_to_cpu(hdr->offset);
+ if (le32_to_cpu(hdr->len) != 4) {
+ wiphy_err(wl->wiphy,
+ "ERROR: fw hdr len\n");
+ return -ENOMSG;
+ }
+ *n_bytes = le32_to_cpu(*((__le32 *) pdata));
+ return 0;
+ }
+ }
+ }
+ wiphy_err(wl->wiphy, "ERROR: ucode tag:%d can not be found!\n", idx);
+ return -ENOMSG;
+}
+
+/*
+ * precondition: can both be called locked and unlocked
+ */
+void brcms_ucode_free_buf(void *p)
+{
+ kfree(p);
+}
+
+/*
+ * checks validity of all firmware images loaded from user space
+ *
+ * Precondition: Since this function is called in brcms_pci_probe() context,
+ * no locking is required.
+ */
+int brcms_check_firmwares(struct brcms_info *wl)
+{
+ int i;
+ int entry;
+ int rc = 0;
+ const struct firmware *fw;
+ const struct firmware *fw_hdr;
+ struct firmware_hdr *ucode_hdr;
+ for (i = 0; i < MAX_FW_IMAGES && rc == 0; i++) {
+ fw = wl->fw.fw_bin[i];
+ fw_hdr = wl->fw.fw_hdr[i];
+ if (fw == NULL && fw_hdr == NULL) {
+ break;
+ } else if (fw == NULL || fw_hdr == NULL) {
+ wiphy_err(wl->wiphy, "%s: invalid bin/hdr fw\n",
+ __func__);
+ rc = -EBADF;
+ } else if (fw_hdr->size % sizeof(struct firmware_hdr)) {
+ wiphy_err(wl->wiphy, "%s: non integral fw hdr file "
+ "size %zu/%zu\n", __func__, fw_hdr->size,
+ sizeof(struct firmware_hdr));
+ rc = -EBADF;
+ } else if (fw->size < MIN_FW_SIZE || fw->size > MAX_FW_SIZE) {
+ wiphy_err(wl->wiphy, "%s: out of bounds fw file size "
+ "%zu\n", __func__, fw->size);
+ rc = -EBADF;
+ } else {
+ /* check if ucode section overruns firmware image */
+ ucode_hdr = (struct firmware_hdr *)fw_hdr->data;
+ for (entry = 0; entry < wl->fw.hdr_num_entries[i] &&
+ !rc; entry++, ucode_hdr++) {
+ if (le32_to_cpu(ucode_hdr->offset) +
+ le32_to_cpu(ucode_hdr->len) >
+ fw->size) {
+ wiphy_err(wl->wiphy,
+ "%s: conflicting bin/hdr\n",
+ __func__);
+ rc = -EBADF;
+ }
+ }
+ }
+ }
+ if (rc == 0 && wl->fw.fw_cnt != i) {
+ wiphy_err(wl->wiphy, "%s: invalid fw_cnt=%d\n", __func__,
+ wl->fw.fw_cnt);
+ rc = -EBADF;
+ }
+ return rc;
+}
+
+/*
+ * precondition: perimeter lock has been acquired
+ */
+bool brcms_rfkill_set_hw_state(struct brcms_info *wl)
+{
+ bool blocked = brcms_c_check_radio_disabled(wl->wlc);
+
+ spin_unlock_bh(&wl->lock);
+ wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked);
+ if (blocked)
+ wiphy_rfkill_start_polling(wl->pub->ieee_hw->wiphy);
+ spin_lock_bh(&wl->lock);
+ return blocked;
+}
+
+/*
+ * precondition: perimeter lock has been acquired
+ */
+void brcms_msleep(struct brcms_info *wl, uint ms)
+{
+ spin_unlock_bh(&wl->lock);
+ msleep(ms);
+ spin_lock_bh(&wl->lock);
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h
new file mode 100644
index 000000000000..177f0e44e4b6
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_MAC80211_IF_H_
+#define _BRCM_MAC80211_IF_H_
+
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+
+#include "ucode_loader.h"
+/*
+ * Starting index for 5G rates in the
+ * legacy rate table.
+ */
+#define BRCMS_LEGACY_5G_RATE_OFFSET 4
+
+/* softmac ioctl definitions */
+#define BRCMS_SET_SHORTSLOT_OVERRIDE 146
+
+struct brcms_timer {
+ struct delayed_work dly_wrk;
+ struct brcms_info *wl;
+ void (*fn) (void *); /* function called upon expiration */
+ void *arg; /* fixed argument provided to called function */
+ uint ms;
+ bool periodic;
+ bool set; /* indicates if timer is active */
+ struct brcms_timer *next; /* for freeing on unload */
+#ifdef BCMDBG
+ char *name; /* Description of the timer */
+#endif
+};
+
+struct brcms_if {
+ uint subunit; /* WDS/BSS unit */
+ struct pci_dev *pci_dev;
+};
+
+#define MAX_FW_IMAGES 4
+struct brcms_firmware {
+ u32 fw_cnt;
+ const struct firmware *fw_bin[MAX_FW_IMAGES];
+ const struct firmware *fw_hdr[MAX_FW_IMAGES];
+ u32 hdr_num_entries[MAX_FW_IMAGES];
+};
+
+struct brcms_info {
+ struct brcms_pub *pub; /* pointer to public wlc state */
+ struct brcms_c_info *wlc; /* pointer to private common data */
+ u32 magic;
+
+ int irq;
+
+ spinlock_t lock; /* per-device perimeter lock */
+ spinlock_t isr_lock; /* per-device ISR synchronization lock */
+
+ /* regsva for unmap in brcms_free() */
+ void __iomem *regsva; /* opaque chip registers virtual address */
+
+ /* timer related fields */
+ atomic_t callbacks; /* # outstanding callback functions */
+ struct brcms_timer *timers; /* timer cleanup queue */
+
+ struct tasklet_struct tasklet; /* dpc tasklet */
+ bool resched; /* dpc needs to be and is rescheduled */
+ struct brcms_firmware fw;
+ struct wiphy *wiphy;
+ struct brcms_ucode ucode;
+};
+
+/* misc callbacks */
+extern void brcms_init(struct brcms_info *wl);
+extern uint brcms_reset(struct brcms_info *wl);
+extern void brcms_intrson(struct brcms_info *wl);
+extern u32 brcms_intrsoff(struct brcms_info *wl);
+extern void brcms_intrsrestore(struct brcms_info *wl, u32 macintmask);
+extern int brcms_up(struct brcms_info *wl);
+extern void brcms_down(struct brcms_info *wl);
+extern void brcms_txflowcontrol(struct brcms_info *wl, struct brcms_if *wlif,
+ bool state, int prio);
+extern bool brcms_rfkill_set_hw_state(struct brcms_info *wl);
+
+/* timer functions */
+extern struct brcms_timer *brcms_init_timer(struct brcms_info *wl,
+ void (*fn) (void *arg), void *arg,
+ const char *name);
+extern void brcms_free_timer(struct brcms_timer *timer);
+extern void brcms_add_timer(struct brcms_timer *timer, uint ms, int periodic);
+extern bool brcms_del_timer(struct brcms_timer *timer);
+extern void brcms_msleep(struct brcms_info *wl, uint ms);
+extern void brcms_dpc(unsigned long data);
+extern void brcms_timer(struct brcms_timer *t);
+
+#endif /* _BRCM_MAC80211_IF_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c
new file mode 100644
index 000000000000..510e9bb52287
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
@@ -0,0 +1,8775 @@
+/*
+ * Copyright (c) 2010 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/pci_ids.h>
+#include <linux/if_ether.h>
+#include <net/mac80211.h>
+#include <brcm_hw_ids.h>
+#include <aiutils.h>
+#include <chipcommon.h>
+#include "rate.h"
+#include "scb.h"
+#include "phy/phy_hal.h"
+#include "channel.h"
+#include "antsel.h"
+#include "stf.h"
+#include "ampdu.h"
+#include "mac80211_if.h"
+#include "ucode_loader.h"
+#include "main.h"
+
+/*
+ * Indication for txflowcontrol that all priority bits in
+ * TXQ_STOP_FOR_PRIOFC_MASK are to be considered.
+ */
+#define ALLPRIO -1
+
+/*
+ * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL.
+ */
+#define SSID_FMT_BUF_LEN ((4 * IEEE80211_MAX_SSID_LEN) + 1)
+
+/* watchdog timer, in unit of ms */
+#define TIMER_INTERVAL_WATCHDOG 1000
+/* radio monitor timer, in unit of ms */
+#define TIMER_INTERVAL_RADIOCHK 800
+
+/* Max MPC timeout, in unit of watchdog */
+#ifndef BRCMS_MPC_MAX_DELAYCNT
+#define BRCMS_MPC_MAX_DELAYCNT 10
+#endif
+
+/* Min MPC timeout, in unit of watchdog */
+#define BRCMS_MPC_MIN_DELAYCNT 1
+#define BRCMS_MPC_THRESHOLD 3 /* MPC count threshold level */
+
+/* beacon interval, in unit of 1024TU */
+#define BEACON_INTERVAL_DEFAULT 100
+/* DTIM interval, in unit of beacon interval */
+#define DTIM_INTERVAL_DEFAULT 3
+
+/* Scale down delays to accommodate QT slow speed */
+/* beacon interval, in unit of 1024TU */
+#define BEACON_INTERVAL_DEF_QT 20
+/* DTIM interval, in unit of beacon interval */
+#define DTIM_INTERVAL_DEF_QT 1
+
+#define TBTT_ALIGN_LEEWAY_US 100 /* min leeway before first TBTT in us */
+
+/* n-mode support capability */
+/* 2x2 includes both 1x1 & 2x2 devices
+ * reserved #define 2 for future when we want to separate 1x1 & 2x2 and
+ * control it independently
+ */
+#define WL_11N_2x2 1
+#define WL_11N_3x3 3
+#define WL_11N_4x4 4
+
+/* define 11n feature disable flags */
+#define WLFEATURE_DISABLE_11N 0x00000001
+#define WLFEATURE_DISABLE_11N_STBC_TX 0x00000002
+#define WLFEATURE_DISABLE_11N_STBC_RX 0x00000004
+#define WLFEATURE_DISABLE_11N_SGI_TX 0x00000008
+#define WLFEATURE_DISABLE_11N_SGI_RX 0x00000010
+#define WLFEATURE_DISABLE_11N_AMPDU_TX 0x00000020
+#define WLFEATURE_DISABLE_11N_AMPDU_RX 0x00000040
+#define WLFEATURE_DISABLE_11N_GF 0x00000080
+
+#define EDCF_ACI_MASK 0x60
+#define EDCF_ACI_SHIFT 5
+#define EDCF_ECWMIN_MASK 0x0f
+#define EDCF_ECWMAX_SHIFT 4
+#define EDCF_AIFSN_MASK 0x0f
+#define EDCF_AIFSN_MAX 15
+#define EDCF_ECWMAX_MASK 0xf0
+
+#define EDCF_AC_BE_TXOP_STA 0x0000
+#define EDCF_AC_BK_TXOP_STA 0x0000
+#define EDCF_AC_VO_ACI_STA 0x62
+#define EDCF_AC_VO_ECW_STA 0x32
+#define EDCF_AC_VI_ACI_STA 0x42
+#define EDCF_AC_VI_ECW_STA 0x43
+#define EDCF_AC_BK_ECW_STA 0xA4
+#define EDCF_AC_VI_TXOP_STA 0x005e
+#define EDCF_AC_VO_TXOP_STA 0x002f
+#define EDCF_AC_BE_ACI_STA 0x03
+#define EDCF_AC_BE_ECW_STA 0xA4
+#define EDCF_AC_BK_ACI_STA 0x27
+#define EDCF_AC_VO_TXOP_AP 0x002f
+
+#define EDCF_TXOP2USEC(txop) ((txop) << 5)
+#define EDCF_ECW2CW(exp) ((1 << (exp)) - 1)
+
+#define APHY_SYMBOL_TIME 4
+#define APHY_PREAMBLE_TIME 16
+#define APHY_SIGNAL_TIME 4
+#define APHY_SIFS_TIME 16
+#define APHY_SERVICE_NBITS 16
+#define APHY_TAIL_NBITS 6
+#define BPHY_SIFS_TIME 10
+#define BPHY_PLCP_SHORT_TIME 96
+
+#define PREN_PREAMBLE 24
+#define PREN_MM_EXT 12
+#define PREN_PREAMBLE_EXT 4
+
+#define DOT11_MAC_HDR_LEN 24
+#define DOT11_ACK_LEN 10
+#define DOT11_BA_LEN 4
+#define DOT11_OFDM_SIGNAL_EXTENSION 6
+#define DOT11_MIN_FRAG_LEN 256
+#define DOT11_RTS_LEN 16
+#define DOT11_CTS_LEN 10
+#define DOT11_BA_BITMAP_LEN 128
+#define DOT11_MIN_BEACON_PERIOD 1
+#define DOT11_MAX_BEACON_PERIOD 0xFFFF
+#define DOT11_MAXNUMFRAGS 16
+#define DOT11_MAX_FRAG_LEN 2346
+
+#define BPHY_PLCP_TIME 192
+#define RIFS_11N_TIME 2
+
+#define WME_VER 1
+#define WME_SUBTYPE_PARAM_IE 1
+#define WME_TYPE 2
+#define WME_OUI "\x00\x50\xf2"
+
+#define AC_BE 0
+#define AC_BK 1
+#define AC_VI 2
+#define AC_VO 3
+
+#define BCN_TMPL_LEN 512 /* length of the BCN template area */
+
+/* brcms_bss_info flag bit values */
+#define BRCMS_BSS_HT 0x0020 /* BSS is HT (MIMO) capable */
+
+/* Flags used in brcms_c_txq_info.stopped */
+/* per prio flow control bits */
+#define TXQ_STOP_FOR_PRIOFC_MASK 0x000000FF
+/* stop txq enqueue for packet drain */
+#define TXQ_STOP_FOR_PKT_DRAIN 0x00000100
+/* stop txq enqueue for ampdu flow control */
+#define TXQ_STOP_FOR_AMPDU_FLOW_CNTRL 0x00000200
+
+#define BRCMS_HWRXOFF 38 /* chip rx buffer offset */
+
+/* Find basic rate for a given rate */
+static u8 brcms_basic_rate(struct brcms_c_info *wlc, u32 rspec)
+{
+ if (is_mcs_rate(rspec))
+ return wlc->band->basic_rate[mcs_table[rspec & RSPEC_RATE_MASK]
+ .leg_ofdm];
+ return wlc->band->basic_rate[rspec & RSPEC_RATE_MASK];
+}
+
+static u16 frametype(u32 rspec, u8 mimoframe)
+{
+ if (is_mcs_rate(rspec))
+ return mimoframe;
+ return is_cck_rate(rspec) ? FT_CCK : FT_OFDM;
+}
+
+/* rfdisable delay timer 500 ms, runs of ALP clock */
+#define RFDISABLE_DEFAULT 10000000
+
+#define BRCMS_TEMPSENSE_PERIOD 10 /* 10 second timeout */
+
+/* precedences numbers for wlc queues. These are twice as may levels as
+ * 802.1D priorities.
+ * Odd numbers are used for HI priority traffic at same precedence levels
+ * These constants are used ONLY by wlc_prio2prec_map. Do not use them
+ * elsewhere.
+ */
+#define _BRCMS_PREC_NONE 0 /* None = - */
+#define _BRCMS_PREC_BK 2 /* BK - Background */
+#define _BRCMS_PREC_BE 4 /* BE - Best-effort */
+#define _BRCMS_PREC_EE 6 /* EE - Excellent-effort */
+#define _BRCMS_PREC_CL 8 /* CL - Controlled Load */
+#define _BRCMS_PREC_VI 10 /* Vi - Video */
+#define _BRCMS_PREC_VO 12 /* Vo - Voice */
+#define _BRCMS_PREC_NC 14 /* NC - Network Control */
+
+/* The BSS is generating beacons in HW */
+#define BRCMS_BSSCFG_HW_BCN 0x20
+
+#define SYNTHPU_DLY_APHY_US 3700 /* a phy synthpu_dly time in us */
+#define SYNTHPU_DLY_BPHY_US 1050 /* b/g phy synthpu_dly time in us */
+#define SYNTHPU_DLY_NPHY_US 2048 /* n phy REV3 synthpu_dly time in us */
+#define SYNTHPU_DLY_LPPHY_US 300 /* lpphy synthpu_dly time in us */
+
+#define SYNTHPU_DLY_PHY_US_QT 100 /* QT synthpu_dly time in us */
+
+#define ANTCNT 10 /* vanilla M_MAX_ANTCNT value */
+
+/* Per-AC retry limit register definitions; uses defs.h bitfield macros */
+#define EDCF_SHORT_S 0
+#define EDCF_SFB_S 4
+#define EDCF_LONG_S 8
+#define EDCF_LFB_S 12
+#define EDCF_SHORT_M BITFIELD_MASK(4)
+#define EDCF_SFB_M BITFIELD_MASK(4)
+#define EDCF_LONG_M BITFIELD_MASK(4)
+#define EDCF_LFB_M BITFIELD_MASK(4)
+
+#define RETRY_SHORT_DEF 7 /* Default Short retry Limit */
+#define RETRY_SHORT_MAX 255 /* Maximum Short retry Limit */
+#define RETRY_LONG_DEF 4 /* Default Long retry count */
+#define RETRY_SHORT_FB 3 /* Short count for fallback rate */
+#define RETRY_LONG_FB 2 /* Long count for fallback rate */
+
+#define APHY_CWMIN 15
+#define PHY_CWMAX 1023
+
+#define EDCF_AIFSN_MIN 1
+
+#define FRAGNUM_MASK 0xF
+
+#define APHY_SLOT_TIME 9
+#define BPHY_SLOT_TIME 20
+
+#define WL_SPURAVOID_OFF 0
+#define WL_SPURAVOID_ON1 1
+#define WL_SPURAVOID_ON2 2
+
+/* invalid core flags, use the saved coreflags */
+#define BRCMS_USE_COREFLAGS 0xffffffff
+
+/* values for PLCPHdr_override */
+#define BRCMS_PLCP_AUTO -1
+#define BRCMS_PLCP_SHORT 0
+#define BRCMS_PLCP_LONG 1
+
+/* values for g_protection_override and n_protection_override */
+#define BRCMS_PROTECTION_AUTO -1
+#define BRCMS_PROTECTION_OFF 0
+#define BRCMS_PROTECTION_ON 1
+#define BRCMS_PROTECTION_MMHDR_ONLY 2
+#define BRCMS_PROTECTION_CTS_ONLY 3
+
+/* values for g_protection_control and n_protection_control */
+#define BRCMS_PROTECTION_CTL_OFF 0
+#define BRCMS_PROTECTION_CTL_LOCAL 1
+#define BRCMS_PROTECTION_CTL_OVERLAP 2
+
+/* values for n_protection */
+#define BRCMS_N_PROTECTION_OFF 0
+#define BRCMS_N_PROTECTION_OPTIONAL 1
+#define BRCMS_N_PROTECTION_20IN40 2
+#define BRCMS_N_PROTECTION_MIXEDMODE 3
+
+/* values for band specific 40MHz capabilities */
+#define BRCMS_N_BW_20ALL 0
+#define BRCMS_N_BW_40ALL 1
+#define BRCMS_N_BW_20IN2G_40IN5G 2
+
+/* bitflags for SGI support (sgi_rx iovar) */
+#define BRCMS_N_SGI_20 0x01
+#define BRCMS_N_SGI_40 0x02
+
+/* defines used by the nrate iovar */
+/* MSC in use,indicates b0-6 holds an mcs */
+#define NRATE_MCS_INUSE 0x00000080
+/* rate/mcs value */
+#define NRATE_RATE_MASK 0x0000007f
+/* stf mode mask: siso, cdd, stbc, sdm */
+#define NRATE_STF_MASK 0x0000ff00
+/* stf mode shift */
+#define NRATE_STF_SHIFT 8
+/* bit indicates override both rate & mode */
+#define NRATE_OVERRIDE 0x80000000
+/* bit indicate to override mcs only */
+#define NRATE_OVERRIDE_MCS_ONLY 0x40000000
+#define NRATE_SGI_MASK 0x00800000 /* sgi mode */
+#define NRATE_SGI_SHIFT 23 /* sgi mode */
+#define NRATE_LDPC_CODING 0x00400000 /* bit indicates adv coding in use */
+#define NRATE_LDPC_SHIFT 22 /* ldpc shift */
+
+#define NRATE_STF_SISO 0 /* stf mode SISO */
+#define NRATE_STF_CDD 1 /* stf mode CDD */
+#define NRATE_STF_STBC 2 /* stf mode STBC */
+#define NRATE_STF_SDM 3 /* stf mode SDM */
+
+#define MAX_DMA_SEGS 4
+
+/* Max # of entries in Tx FIFO based on 4kb page size */
+#define NTXD 256
+/* Max # of entries in Rx FIFO based on 4kb page size */
+#define NRXD 256
+
+/* try to keep this # rbufs posted to the chip */
+#define NRXBUFPOST 32
+
+/* data msg txq hiwat mark */
+#define BRCMS_DATAHIWAT 50
+
+/* bounded rx loops */
+#define RXBND 8 /* max # frames to process in brcms_c_recv() */
+#define TXSBND 8 /* max # tx status to process in wlc_txstatus() */
+
+/*
+ * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL.
+ */
+#define SSID_FMT_BUF_LEN ((4 * IEEE80211_MAX_SSID_LEN) + 1)
+
+/* brcmu_format_flags() bit description structure */
+struct brcms_c_bit_desc {
+ u32 bit;
+ const char *name;
+};
+
+/*
+ * The following table lists the buffer memory allocated to xmt fifos in HW.
+ * the size is in units of 256bytes(one block), total size is HW dependent
+ * ucode has default fifo partition, sw can overwrite if necessary
+ *
+ * This is documented in twiki under the topic UcodeTxFifo. Please ensure
+ * the twiki is updated before making changes.
+ */
+
+/* Starting corerev for the fifo size table */
+#define XMTFIFOTBL_STARTREV 20
+
+struct d11init {
+ __le16 addr;
+ __le16 size;
+ __le32 value;
+};
+
+struct edcf_acparam {
+ u8 ACI;
+ u8 ECW;
+ u16 TXOP;
+} __packed;
+
+const u8 prio2fifo[NUMPRIO] = {
+ TX_AC_BE_FIFO, /* 0 BE AC_BE Best Effort */
+ TX_AC_BK_FIFO, /* 1 BK AC_BK Background */
+ TX_AC_BK_FIFO, /* 2 -- AC_BK Background */
+ TX_AC_BE_FIFO, /* 3 EE AC_BE Best Effort */
+ TX_AC_VI_FIFO, /* 4 CL AC_VI Video */
+ TX_AC_VI_FIFO, /* 5 VI AC_VI Video */
+ TX_AC_VO_FIFO, /* 6 VO AC_VO Voice */
+ TX_AC_VO_FIFO /* 7 NC AC_VO Voice */
+};
+
+/* debug/trace */
+uint brcm_msg_level =
+#if defined(BCMDBG)
+ LOG_ERROR_VAL;
+#else
+ 0;
+#endif /* BCMDBG */
+
+/* TX FIFO number to WME/802.1E Access Category */
+static const u8 wme_fifo2ac[] = { AC_BK, AC_BE, AC_VI, AC_VO, AC_BE, AC_BE };
+
+/* WME/802.1E Access Category to TX FIFO number */
+static const u8 wme_ac2fifo[] = { 1, 0, 2, 3 };
+
+/* 802.1D Priority to precedence queue mapping */
+const u8 wlc_prio2prec_map[] = {
+ _BRCMS_PREC_BE, /* 0 BE - Best-effort */
+ _BRCMS_PREC_BK, /* 1 BK - Background */
+ _BRCMS_PREC_NONE, /* 2 None = - */
+ _BRCMS_PREC_EE, /* 3 EE - Excellent-effort */
+ _BRCMS_PREC_CL, /* 4 CL - Controlled Load */
+ _BRCMS_PREC_VI, /* 5 Vi - Video */
+ _BRCMS_PREC_VO, /* 6 Vo - Voice */
+ _BRCMS_PREC_NC, /* 7 NC - Network Control */
+};
+
+static const u16 xmtfifo_sz[][NFIFO] = {
+ /* corerev 20: 5120, 49152, 49152, 5376, 4352, 1280 */
+ {20, 192, 192, 21, 17, 5},
+ /* corerev 21: 2304, 14848, 5632, 3584, 3584, 1280 */
+ {9, 58, 22, 14, 14, 5},
+ /* corerev 22: 5120, 49152, 49152, 5376, 4352, 1280 */
+ {20, 192, 192, 21, 17, 5},
+ /* corerev 23: 5120, 49152, 49152, 5376, 4352, 1280 */
+ {20, 192, 192, 21, 17, 5},
+ /* corerev 24: 2304, 14848, 5632, 3584, 3584, 1280 */
+ {9, 58, 22, 14, 14, 5},
+};
+
+static const u8 acbitmap2maxprio[] = {
+ PRIO_8021D_BE, PRIO_8021D_BE, PRIO_8021D_BK, PRIO_8021D_BK,
+ PRIO_8021D_VI, PRIO_8021D_VI, PRIO_8021D_VI, PRIO_8021D_VI,
+ PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO,
+ PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO
+};
+
+#ifdef BCMDBG
+static const char * const fifo_names[] = {
+ "AC_BK", "AC_BE", "AC_VI", "AC_VO", "BCMC", "ATIM" };
+#else
+static const char fifo_names[6][0];
+#endif
+
+#ifdef BCMDBG
+/* pointer to most recently allocated wl/wlc */
+static struct brcms_c_info *wlc_info_dbg = (struct brcms_c_info *) (NULL);
+#endif
+
+/* currently the best mechanism for determining SIFS is the band in use */
+static u16 get_sifs(struct brcms_band *band)
+{
+ return band->bandtype == BRCM_BAND_5G ? APHY_SIFS_TIME :
+ BPHY_SIFS_TIME;
+}
+
+/*
+ * Detect Card removed.
+ * Even checking an sbconfig register read will not false trigger when the core
+ * is in reset it breaks CF address mechanism. Accessing gphy phyversion will
+ * cause SB error if aphy is in reset on 4306B0-DB. Need a simple accessible
+ * reg with fixed 0/1 pattern (some platforms return all 0).
+ * If clocks are present, call the sb routine which will figure out if the
+ * device is removed.
+ */
+static bool brcms_deviceremoved(struct brcms_c_info *wlc)
+{
+ if (!wlc->hw->clk)
+ return ai_deviceremoved(wlc->hw->sih);
+ return (R_REG(&wlc->hw->regs->maccontrol) &
+ (MCTL_PSM_JMP_0 | MCTL_IHR_EN)) != MCTL_IHR_EN;
+}
+
+/* sum the individual fifo tx pending packet counts */
+static s16 brcms_txpktpendtot(struct brcms_c_info *wlc)
+{
+ return wlc->core->txpktpend[0] + wlc->core->txpktpend[1] +
+ wlc->core->txpktpend[2] + wlc->core->txpktpend[3];
+}
+
+static bool brcms_is_mband_unlocked(struct brcms_c_info *wlc)
+{
+ return wlc->pub->_nbands > 1 && !wlc->bandlocked;
+}
+
+static int brcms_chspec_bw(u16 chanspec)
+{
+ if (CHSPEC_IS40(chanspec))
+ return BRCMS_40_MHZ;
+ if (CHSPEC_IS20(chanspec))
+ return BRCMS_20_MHZ;
+
+ return BRCMS_10_MHZ;
+}
+
+/*
+ * return true if Minimum Power Consumption should
+ * be entered, false otherwise
+ */
+static bool brcms_c_is_non_delay_mpc(struct brcms_c_info *wlc)
+{
+ return false;
+}
+
+static bool brcms_c_ismpc(struct brcms_c_info *wlc)
+{
+ return (wlc->mpc_delay_off == 0) && (brcms_c_is_non_delay_mpc(wlc));
+}
+
+static void brcms_c_bsscfg_mfree(struct brcms_bss_cfg *cfg)
+{
+ if (cfg == NULL)
+ return;
+
+ kfree(cfg->current_bss);
+ kfree(cfg);
+}
+
+static void brcms_c_detach_mfree(struct brcms_c_info *wlc)
+{
+ if (wlc == NULL)
+ return;
+
+ brcms_c_bsscfg_mfree(wlc->bsscfg);
+ kfree(wlc->pub);
+ kfree(wlc->modulecb);
+ kfree(wlc->default_bss);
+ kfree(wlc->protection);
+ kfree(wlc->stf);
+ kfree(wlc->bandstate[0]);
+ kfree(wlc->corestate->macstat_snapshot);
+ kfree(wlc->corestate);
+ kfree(wlc->hw->bandstate[0]);
+ kfree(wlc->hw);
+
+ /* free the wlc */
+ kfree(wlc);
+ wlc = NULL;
+}
+
+static struct brcms_bss_cfg *brcms_c_bsscfg_malloc(uint unit)
+{
+ struct brcms_bss_cfg *cfg;
+
+ cfg = kzalloc(sizeof(struct brcms_bss_cfg), GFP_ATOMIC);
+ if (cfg == NULL)
+ goto fail;
+
+ cfg->current_bss = kzalloc(sizeof(struct brcms_bss_info), GFP_ATOMIC);
+ if (cfg->current_bss == NULL)
+ goto fail;
+
+ return cfg;
+
+ fail:
+ brcms_c_bsscfg_mfree(cfg);
+ return NULL;
+}
+
+static struct brcms_c_info *
+brcms_c_attach_malloc(uint unit, uint *err, uint devid)
+{
+ struct brcms_c_info *wlc;
+
+ wlc = kzalloc(sizeof(struct brcms_c_info), GFP_ATOMIC);
+ if (wlc == NULL) {
+ *err = 1002;
+ goto fail;
+ }
+
+ /* allocate struct brcms_c_pub state structure */
+ wlc->pub = kzalloc(sizeof(struct brcms_pub), GFP_ATOMIC);
+ if (wlc->pub == NULL) {
+ *err = 1003;
+ goto fail;
+ }
+ wlc->pub->wlc = wlc;
+
+ /* allocate struct brcms_hardware state structure */
+
+ wlc->hw = kzalloc(sizeof(struct brcms_hardware), GFP_ATOMIC);
+ if (wlc->hw == NULL) {
+ *err = 1005;
+ goto fail;
+ }
+ wlc->hw->wlc = wlc;
+
+ wlc->hw->bandstate[0] =
+ kzalloc(sizeof(struct brcms_hw_band) * MAXBANDS, GFP_ATOMIC);
+ if (wlc->hw->bandstate[0] == NULL) {
+ *err = 1006;
+ goto fail;
+ } else {
+ int i;
+
+ for (i = 1; i < MAXBANDS; i++)
+ wlc->hw->bandstate[i] = (struct brcms_hw_band *)
+ ((unsigned long)wlc->hw->bandstate[0] +
+ (sizeof(struct brcms_hw_band) * i));
+ }
+
+ wlc->modulecb =
+ kzalloc(sizeof(struct modulecb) * BRCMS_MAXMODULES, GFP_ATOMIC);
+ if (wlc->modulecb == NULL) {
+ *err = 1009;
+ goto fail;
+ }
+
+ wlc->default_bss = kzalloc(sizeof(struct brcms_bss_info), GFP_ATOMIC);
+ if (wlc->default_bss == NULL) {
+ *err = 1010;
+ goto fail;
+ }
+
+ wlc->bsscfg = brcms_c_bsscfg_malloc(unit);
+ if (wlc->bsscfg == NULL) {
+ *err = 1011;
+ goto fail;
+ }
+
+ wlc->protection = kzalloc(sizeof(struct brcms_protection),
+ GFP_ATOMIC);
+ if (wlc->protection == NULL) {
+ *err = 1016;
+ goto fail;
+ }
+
+ wlc->stf = kzalloc(sizeof(struct brcms_stf), GFP_ATOMIC);
+ if (wlc->stf == NULL) {
+ *err = 1017;
+ goto fail;
+ }
+
+ wlc->bandstate[0] =
+ kzalloc(sizeof(struct brcms_band)*MAXBANDS, GFP_ATOMIC);
+ if (wlc->bandstate[0] == NULL) {
+ *err = 1025;
+ goto fail;
+ } else {
+ int i;
+
+ for (i = 1; i < MAXBANDS; i++)
+ wlc->bandstate[i] = (struct brcms_band *)
+ ((unsigned long)wlc->bandstate[0]
+ + (sizeof(struct brcms_band)*i));
+ }
+
+ wlc->corestate = kzalloc(sizeof(struct brcms_core), GFP_ATOMIC);
+ if (wlc->corestate == NULL) {
+ *err = 1026;
+ goto fail;
+ }
+
+ wlc->corestate->macstat_snapshot =
+ kzalloc(sizeof(struct macstat), GFP_ATOMIC);
+ if (wlc->corestate->macstat_snapshot == NULL) {
+ *err = 1027;
+ goto fail;
+ }
+
+ return wlc;
+
+ fail:
+ brcms_c_detach_mfree(wlc);
+ return NULL;
+}
+
+/*
+ * Update the slot timing for standard 11b/g (20us slots)
+ * or shortslot 11g (9us slots)
+ * The PSM needs to be suspended for this call.
+ */
+static void brcms_b_update_slot_timing(struct brcms_hardware *wlc_hw,
+ bool shortslot)
+{
+ struct d11regs __iomem *regs;
+
+ regs = wlc_hw->regs;
+
+ if (shortslot) {
+ /* 11g short slot: 11a timing */
+ W_REG(&regs->ifs_slot, 0x0207); /* APHY_SLOT_TIME */
+ brcms_b_write_shm(wlc_hw, M_DOT11_SLOT, APHY_SLOT_TIME);
+ } else {
+ /* 11g long slot: 11b timing */
+ W_REG(&regs->ifs_slot, 0x0212); /* BPHY_SLOT_TIME */
+ brcms_b_write_shm(wlc_hw, M_DOT11_SLOT, BPHY_SLOT_TIME);
+ }
+}
+
+/*
+ * calculate frame duration of a given rate and length, return
+ * time in usec unit
+ */
+uint
+brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec,
+ u8 preamble_type, uint mac_len)
+{
+ uint nsyms, dur = 0, Ndps, kNdps;
+ uint rate = rspec2rate(ratespec);
+
+ if (rate == 0) {
+ wiphy_err(wlc->wiphy, "wl%d: WAR: using rate of 1 mbps\n",
+ wlc->pub->unit);
+ rate = BRCM_RATE_1M;
+ }
+
+ BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, len%d\n",
+ wlc->pub->unit, ratespec, preamble_type, mac_len);
+
+ if (is_mcs_rate(ratespec)) {
+ uint mcs = ratespec & RSPEC_RATE_MASK;
+ int tot_streams = mcs_2_txstreams(mcs) + rspec_stc(ratespec);
+
+ dur = PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT);
+ if (preamble_type == BRCMS_MM_PREAMBLE)
+ dur += PREN_MM_EXT;
+ /* 1000Ndbps = kbps * 4 */
+ kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec),
+ rspec_issgi(ratespec)) * 4;
+
+ if (rspec_stc(ratespec) == 0)
+ nsyms =
+ CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
+ APHY_TAIL_NBITS) * 1000, kNdps);
+ else
+ /* STBC needs to have even number of symbols */
+ nsyms =
+ 2 *
+ CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
+ APHY_TAIL_NBITS) * 1000, 2 * kNdps);
+
+ dur += APHY_SYMBOL_TIME * nsyms;
+ if (wlc->band->bandtype == BRCM_BAND_2G)
+ dur += DOT11_OFDM_SIGNAL_EXTENSION;
+ } else if (is_ofdm_rate(rate)) {
+ dur = APHY_PREAMBLE_TIME;
+ dur += APHY_SIGNAL_TIME;
+ /* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */
+ Ndps = rate * 2;
+ /* NSyms = CEILING((SERVICE + 8*NBytes + TAIL) / Ndbps) */
+ nsyms =
+ CEIL((APHY_SERVICE_NBITS + 8 * mac_len + APHY_TAIL_NBITS),
+ Ndps);
+ dur += APHY_SYMBOL_TIME * nsyms;
+ if (wlc->band->bandtype == BRCM_BAND_2G)
+ dur += DOT11_OFDM_SIGNAL_EXTENSION;
+ } else {
+ /*
+ * calc # bits * 2 so factor of 2 in rate (1/2 mbps)
+ * will divide out
+ */
+ mac_len = mac_len * 8 * 2;
+ /* calc ceiling of bits/rate = microseconds of air time */
+ dur = (mac_len + rate - 1) / rate;
+ if (preamble_type & BRCMS_SHORT_PREAMBLE)
+ dur += BPHY_PLCP_SHORT_TIME;
+ else
+ dur += BPHY_PLCP_TIME;
+ }
+ return dur;
+}
+
+static void brcms_c_write_inits(struct brcms_hardware *wlc_hw,
+ const struct d11init *inits)
+{
+ int i;
+ u8 __iomem *base;
+ u8 __iomem *addr;
+ u16 size;
+ u32 value;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ base = (u8 __iomem *)wlc_hw->regs;
+
+ for (i = 0; inits[i].addr != cpu_to_le16(0xffff); i++) {
+ size = le16_to_cpu(inits[i].size);
+ addr = base + le16_to_cpu(inits[i].addr);
+ value = le32_to_cpu(inits[i].value);
+ if (size == 2)
+ W_REG((u16 __iomem *)addr, value);
+ else if (size == 4)
+ W_REG((u32 __iomem *)addr, value);
+ else
+ break;
+ }
+}
+
+static void brcms_c_write_mhf(struct brcms_hardware *wlc_hw, u16 *mhfs)
+{
+ u8 idx;
+ u16 addr[] = {
+ M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4,
+ M_HOST_FLAGS5
+ };
+
+ for (idx = 0; idx < MHFMAX; idx++)
+ brcms_b_write_shm(wlc_hw, addr[idx], mhfs[idx]);
+}
+
+static void brcms_c_ucode_bsinit(struct brcms_hardware *wlc_hw)
+{
+ struct wiphy *wiphy = wlc_hw->wlc->wiphy;
+ struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode;
+
+ /* init microcode host flags */
+ brcms_c_write_mhf(wlc_hw, wlc_hw->band->mhfs);
+
+ /* do band-specific ucode IHR, SHM, and SCR inits */
+ if (D11REV_IS(wlc_hw->corerev, 23)) {
+ if (BRCMS_ISNPHY(wlc_hw->band))
+ brcms_c_write_inits(wlc_hw, ucode->d11n0bsinitvals16);
+ else
+ wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev"
+ " %d\n", __func__, wlc_hw->unit,
+ wlc_hw->corerev);
+ } else {
+ if (D11REV_IS(wlc_hw->corerev, 24)) {
+ if (BRCMS_ISLCNPHY(wlc_hw->band))
+ brcms_c_write_inits(wlc_hw,
+ ucode->d11lcn0bsinitvals24);
+ else
+ wiphy_err(wiphy, "%s: wl%d: unsupported phy in"
+ " core rev %d\n", __func__,
+ wlc_hw->unit, wlc_hw->corerev);
+ } else {
+ wiphy_err(wiphy, "%s: wl%d: unsupported corerev %d\n",
+ __func__, wlc_hw->unit, wlc_hw->corerev);
+ }
+ }
+}
+
+static void brcms_b_core_phy_clk(struct brcms_hardware *wlc_hw, bool clk)
+{
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d: clk %d\n", wlc_hw->unit, clk);
+
+ wlc_hw->phyclk = clk;
+
+ if (OFF == clk) { /* clear gmode bit, put phy into reset */
+
+ ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC | SICF_GMODE),
+ (SICF_PRST | SICF_FGC));
+ udelay(1);
+ ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC), SICF_PRST);
+ udelay(1);
+
+ } else { /* take phy out of reset */
+
+ ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC), SICF_FGC);
+ udelay(1);
+ ai_core_cflags(wlc_hw->sih, (SICF_FGC), 0);
+ udelay(1);
+
+ }
+}
+
+/* low-level band switch utility routine */
+static void brcms_c_setxband(struct brcms_hardware *wlc_hw, uint bandunit)
+{
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
+ bandunit);
+
+ wlc_hw->band = wlc_hw->bandstate[bandunit];
+
+ /*
+ * BMAC_NOTE:
+ * until we eliminate need for wlc->band refs in low level code
+ */
+ wlc_hw->wlc->band = wlc_hw->wlc->bandstate[bandunit];
+
+ /* set gmode core flag */
+ if (wlc_hw->sbclk && !wlc_hw->noreset)
+ ai_core_cflags(wlc_hw->sih, SICF_GMODE,
+ ((bandunit == 0) ? SICF_GMODE : 0));
+}
+
+/* switch to new band but leave it inactive */
+static u32 brcms_c_setband_inact(struct brcms_c_info *wlc, uint bandunit)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ u32 macintmask;
+
+ BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ WARN_ON((R_REG(&wlc_hw->regs->maccontrol) & MCTL_EN_MAC) != 0);
+
+ /* disable interrupts */
+ macintmask = brcms_intrsoff(wlc->wl);
+
+ /* radio off */
+ wlc_phy_switch_radio(wlc_hw->band->pi, OFF);
+
+ brcms_b_core_phy_clk(wlc_hw, OFF);
+
+ brcms_c_setxband(wlc_hw, bandunit);
+
+ return macintmask;
+}
+
+/* process an individual struct tx_status */
+static bool
+brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
+{
+ struct sk_buff *p;
+ uint queue;
+ struct d11txh *txh;
+ struct scb *scb = NULL;
+ bool free_pdu;
+ int tx_rts, tx_frame_count, tx_rts_count;
+ uint totlen, supr_status;
+ bool lastframe;
+ struct ieee80211_hdr *h;
+ u16 mcl;
+ struct ieee80211_tx_info *tx_info;
+ struct ieee80211_tx_rate *txrate;
+ int i;
+
+ /* discard intermediate indications for ucode with one legitimate case:
+ * e.g. if "useRTS" is set. ucode did a successful rts/cts exchange,
+ * but the subsequent tx of DATA failed. so it will start rts/cts
+ * from the beginning (resetting the rts transmission count)
+ */
+ if (!(txs->status & TX_STATUS_AMPDU)
+ && (txs->status & TX_STATUS_INTERMEDIATE)) {
+ wiphy_err(wlc->wiphy, "%s: INTERMEDIATE but not AMPDU\n",
+ __func__);
+ return false;
+ }
+
+ queue = txs->frameid & TXFID_QUEUE_MASK;
+ if (queue >= NFIFO) {
+ p = NULL;
+ goto fatal;
+ }
+
+ p = dma_getnexttxp(wlc->hw->di[queue], DMA_RANGE_TRANSMITTED);
+ if (p == NULL)
+ goto fatal;
+
+ txh = (struct d11txh *) (p->data);
+ mcl = le16_to_cpu(txh->MacTxControlLow);
+
+ if (txs->phyerr) {
+ if (brcm_msg_level & LOG_ERROR_VAL) {
+ wiphy_err(wlc->wiphy, "phyerr 0x%x, rate 0x%x\n",
+ txs->phyerr, txh->MainRates);
+ brcms_c_print_txdesc(txh);
+ }
+ brcms_c_print_txstatus(txs);
+ }
+
+ if (txs->frameid != le16_to_cpu(txh->TxFrameID))
+ goto fatal;
+ tx_info = IEEE80211_SKB_CB(p);
+ h = (struct ieee80211_hdr *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN);
+
+ if (tx_info->control.sta)
+ scb = &wlc->pri_scb;
+
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+ brcms_c_ampdu_dotxstatus(wlc->ampdu, scb, p, txs);
+ return false;
+ }
+
+ supr_status = txs->status & TX_STATUS_SUPR_MASK;
+ if (supr_status == TX_STATUS_SUPR_BADCH)
+ BCMMSG(wlc->wiphy,
+ "%s: Pkt tx suppressed, possibly channel %d\n",
+ __func__, CHSPEC_CHANNEL(wlc->default_bss->chanspec));
+
+ tx_rts = le16_to_cpu(txh->MacTxControlLow) & TXC_SENDRTS;
+ tx_frame_count =
+ (txs->status & TX_STATUS_FRM_RTX_MASK) >> TX_STATUS_FRM_RTX_SHIFT;
+ tx_rts_count =
+ (txs->status & TX_STATUS_RTS_RTX_MASK) >> TX_STATUS_RTS_RTX_SHIFT;
+
+ lastframe = !ieee80211_has_morefrags(h->frame_control);
+
+ if (!lastframe) {
+ wiphy_err(wlc->wiphy, "Not last frame!\n");
+ } else {
+ /*
+ * Set information to be consumed by Minstrel ht.
+ *
+ * The "fallback limit" is the number of tx attempts a given
+ * MPDU is sent at the "primary" rate. Tx attempts beyond that
+ * limit are sent at the "secondary" rate.
+ * A 'short frame' does not exceed RTS treshold.
+ */
+ u16 sfbl, /* Short Frame Rate Fallback Limit */
+ lfbl, /* Long Frame Rate Fallback Limit */
+ fbl;
+
+ if (queue < AC_COUNT) {
+ sfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]],
+ EDCF_SFB);
+ lfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]],
+ EDCF_LFB);
+ } else {
+ sfbl = wlc->SFBL;
+ lfbl = wlc->LFBL;
+ }
+
+ txrate = tx_info->status.rates;
+ if (txrate[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
+ fbl = lfbl;
+ else
+ fbl = sfbl;
+
+ ieee80211_tx_info_clear_status(tx_info);
+
+ if ((tx_frame_count > fbl) && (txrate[1].idx >= 0)) {
+ /*
+ * rate selection requested a fallback rate
+ * and we used it
+ */
+ txrate[0].count = fbl;
+ txrate[1].count = tx_frame_count - fbl;
+ } else {
+ /*
+ * rate selection did not request fallback rate, or
+ * we didn't need it
+ */
+ txrate[0].count = tx_frame_count;
+ /*
+ * rc80211_minstrel.c:minstrel_tx_status() expects
+ * unused rates to be marked with idx = -1
+ */
+ txrate[1].idx = -1;
+ txrate[1].count = 0;
+ }
+
+ /* clear the rest of the rates */
+ for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) {
+ txrate[i].idx = -1;
+ txrate[i].count = 0;
+ }
+
+ if (txs->status & TX_STATUS_ACK_RCV)
+ tx_info->flags |= IEEE80211_TX_STAT_ACK;
+ }
+
+ totlen = brcmu_pkttotlen(p);
+ free_pdu = true;
+
+ brcms_c_txfifo_complete(wlc, queue, 1);
+
+ if (lastframe) {
+ p->next = NULL;
+ p->prev = NULL;
+ /* remove PLCP & Broadcom tx descriptor header */
+ skb_pull(p, D11_PHY_HDR_LEN);
+ skb_pull(p, D11_TXH_LEN);
+ ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, p);
+ } else {
+ wiphy_err(wlc->wiphy, "%s: Not last frame => not calling "
+ "tx_status\n", __func__);
+ }
+
+ return false;
+
+ fatal:
+ if (p)
+ brcmu_pkt_buf_free_skb(p);
+
+ return true;
+
+}
+
+/* process tx completion events in BMAC
+ * Return true if more tx status need to be processed. false otherwise.
+ */
+static bool
+brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal)
+{
+ bool morepending = false;
+ struct brcms_c_info *wlc = wlc_hw->wlc;
+ struct d11regs __iomem *regs;
+ struct tx_status txstatus, *txs;
+ u32 s1, s2;
+ uint n = 0;
+ /*
+ * Param 'max_tx_num' indicates max. # tx status to process before
+ * break out.
+ */
+ uint max_tx_num = bound ? TXSBND : -1;
+
+ BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ txs = &txstatus;
+ regs = wlc_hw->regs;
+ *fatal = false;
+ while (!(*fatal)
+ && (s1 = R_REG(&regs->frmtxstatus)) & TXS_V) {
+
+ if (s1 == 0xffffffff) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n",
+ wlc_hw->unit, __func__);
+ return morepending;
+ }
+
+ s2 = R_REG(&regs->frmtxstatus2);
+
+ txs->status = s1 & TXS_STATUS_MASK;
+ txs->frameid = (s1 & TXS_FID_MASK) >> TXS_FID_SHIFT;
+ txs->sequence = s2 & TXS_SEQ_MASK;
+ txs->phyerr = (s2 & TXS_PTX_MASK) >> TXS_PTX_SHIFT;
+ txs->lasttxtime = 0;
+
+ *fatal = brcms_c_dotxstatus(wlc_hw->wlc, txs);
+
+ /* !give others some time to run! */
+ if (++n >= max_tx_num)
+ break;
+ }
+
+ if (*fatal)
+ return 0;
+
+ if (n >= max_tx_num)
+ morepending = true;
+
+ if (!pktq_empty(&wlc->pkt_queue->q))
+ brcms_c_send_q(wlc);
+
+ return morepending;
+}
+
+static void brcms_c_tbtt(struct brcms_c_info *wlc)
+{
+ if (!wlc->bsscfg->BSS)
+ /*
+ * DirFrmQ is now valid...defer setting until end
+ * of ATIM window
+ */
+ wlc->qvalid |= MCMD_DIRFRMQVAL;
+}
+
+/* set initial host flags value */
+static void
+brcms_c_mhfdef(struct brcms_c_info *wlc, u16 *mhfs, u16 mhf2_init)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+
+ memset(mhfs, 0, MHFMAX * sizeof(u16));
+
+ mhfs[MHF2] |= mhf2_init;
+
+ /* prohibit use of slowclock on multifunction boards */
+ if (wlc_hw->boardflags & BFL_NOPLLDOWN)
+ mhfs[MHF1] |= MHF1_FORCEFASTCLK;
+
+ if (BRCMS_ISNPHY(wlc_hw->band) && NREV_LT(wlc_hw->band->phyrev, 2)) {
+ mhfs[MHF2] |= MHF2_NPHY40MHZ_WAR;
+ mhfs[MHF1] |= MHF1_IQSWAP_WAR;
+ }
+}
+
+static struct dma64regs __iomem *
+dmareg(struct brcms_hardware *hw, uint direction, uint fifonum)
+{
+ if (direction == DMA_TX)
+ return &(hw->regs->fifo64regs[fifonum].dmaxmt);
+ return &(hw->regs->fifo64regs[fifonum].dmarcv);
+}
+
+static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme)
+{
+ uint i;
+ char name[8];
+ /*
+ * ucode host flag 2 needed for pio mode, independent of band and fifo
+ */
+ u16 pio_mhf2 = 0;
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ uint unit = wlc_hw->unit;
+ struct wiphy *wiphy = wlc->wiphy;
+
+ /* name and offsets for dma_attach */
+ snprintf(name, sizeof(name), "wl%d", unit);
+
+ if (wlc_hw->di[0] == NULL) { /* Init FIFOs */
+ int dma_attach_err = 0;
+
+ /*
+ * FIFO 0
+ * TX: TX_AC_BK_FIFO (TX AC Background data packets)
+ * RX: RX_FIFO (RX data packets)
+ */
+ wlc_hw->di[0] = dma_attach(name, wlc_hw->sih,
+ (wme ? dmareg(wlc_hw, DMA_TX, 0) :
+ NULL), dmareg(wlc_hw, DMA_RX, 0),
+ (wme ? NTXD : 0), NRXD,
+ RXBUFSZ, -1, NRXBUFPOST,
+ BRCMS_HWRXOFF, &brcm_msg_level);
+ dma_attach_err |= (NULL == wlc_hw->di[0]);
+
+ /*
+ * FIFO 1
+ * TX: TX_AC_BE_FIFO (TX AC Best-Effort data packets)
+ * (legacy) TX_DATA_FIFO (TX data packets)
+ * RX: UNUSED
+ */
+ wlc_hw->di[1] = dma_attach(name, wlc_hw->sih,
+ dmareg(wlc_hw, DMA_TX, 1), NULL,
+ NTXD, 0, 0, -1, 0, 0,
+ &brcm_msg_level);
+ dma_attach_err |= (NULL == wlc_hw->di[1]);
+
+ /*
+ * FIFO 2
+ * TX: TX_AC_VI_FIFO (TX AC Video data packets)
+ * RX: UNUSED
+ */
+ wlc_hw->di[2] = dma_attach(name, wlc_hw->sih,
+ dmareg(wlc_hw, DMA_TX, 2), NULL,
+ NTXD, 0, 0, -1, 0, 0,
+ &brcm_msg_level);
+ dma_attach_err |= (NULL == wlc_hw->di[2]);
+ /*
+ * FIFO 3
+ * TX: TX_AC_VO_FIFO (TX AC Voice data packets)
+ * (legacy) TX_CTL_FIFO (TX control & mgmt packets)
+ */
+ wlc_hw->di[3] = dma_attach(name, wlc_hw->sih,
+ dmareg(wlc_hw, DMA_TX, 3),
+ NULL, NTXD, 0, 0, -1,
+ 0, 0, &brcm_msg_level);
+ dma_attach_err |= (NULL == wlc_hw->di[3]);
+/* Cleaner to leave this as if with AP defined */
+
+ if (dma_attach_err) {
+ wiphy_err(wiphy, "wl%d: wlc_attach: dma_attach failed"
+ "\n", unit);
+ return false;
+ }
+
+ /* get pointer to dma engine tx flow control variable */
+ for (i = 0; i < NFIFO; i++)
+ if (wlc_hw->di[i])
+ wlc_hw->txavail[i] =
+ (uint *) dma_getvar(wlc_hw->di[i],
+ "&txavail");
+ }
+
+ /* initial ucode host flags */
+ brcms_c_mhfdef(wlc, wlc_hw->band->mhfs, pio_mhf2);
+
+ return true;
+}
+
+static void brcms_b_detach_dmapio(struct brcms_hardware *wlc_hw)
+{
+ uint j;
+
+ for (j = 0; j < NFIFO; j++) {
+ if (wlc_hw->di[j]) {
+ dma_detach(wlc_hw->di[j]);
+ wlc_hw->di[j] = NULL;
+ }
+ }
+}
+
+/*
+ * Initialize brcms_c_info default values ...
+ * may get overrides later in this function
+ * BMAC_NOTES, move low out and resolve the dangling ones
+ */
+static void brcms_b_info_init(struct brcms_hardware *wlc_hw)
+{
+ struct brcms_c_info *wlc = wlc_hw->wlc;
+
+ /* set default sw macintmask value */
+ wlc->defmacintmask = DEF_MACINTMASK;
+
+ /* various 802.11g modes */
+ wlc_hw->shortslot = false;
+
+ wlc_hw->SFBL = RETRY_SHORT_FB;
+ wlc_hw->LFBL = RETRY_LONG_FB;
+
+ /* default mac retry limits */
+ wlc_hw->SRL = RETRY_SHORT_DEF;
+ wlc_hw->LRL = RETRY_LONG_DEF;
+ wlc_hw->chanspec = ch20mhz_chspec(1);
+}
+
+static void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw)
+{
+ /* delay before first read of ucode state */
+ udelay(40);
+
+ /* wait until ucode is no longer asleep */
+ SPINWAIT((brcms_b_read_shm(wlc_hw, M_UCODE_DBGST) ==
+ DBGST_ASLEEP), wlc_hw->wlc->fastpwrup_dly);
+}
+
+/* control chip clock to save power, enable dynamic clock or force fast clock */
+static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode)
+{
+ if (wlc_hw->sih->cccaps & CC_CAP_PMU) {
+ /* new chips with PMU, CCS_FORCEHT will distribute the HT clock
+ * on backplane, but mac core will still run on ALP(not HT) when
+ * it enters powersave mode, which means the FCA bit may not be
+ * set. Should wakeup mac if driver wants it to run on HT.
+ */
+
+ if (wlc_hw->clk) {
+ if (mode == CLK_FAST) {
+ OR_REG(&wlc_hw->regs->clk_ctl_st,
+ CCS_FORCEHT);
+
+ udelay(64);
+
+ SPINWAIT(((R_REG
+ (&wlc_hw->regs->
+ clk_ctl_st) & CCS_HTAVAIL) == 0),
+ PMU_MAX_TRANSITION_DLY);
+ WARN_ON(!(R_REG
+ (&wlc_hw->regs->
+ clk_ctl_st) & CCS_HTAVAIL));
+ } else {
+ if ((wlc_hw->sih->pmurev == 0) &&
+ (R_REG
+ (&wlc_hw->regs->
+ clk_ctl_st) & (CCS_FORCEHT | CCS_HTAREQ)))
+ SPINWAIT(((R_REG
+ (&wlc_hw->regs->
+ clk_ctl_st) & CCS_HTAVAIL)
+ == 0),
+ PMU_MAX_TRANSITION_DLY);
+ AND_REG(&wlc_hw->regs->clk_ctl_st,
+ ~CCS_FORCEHT);
+ }
+ }
+ wlc_hw->forcefastclk = (mode == CLK_FAST);
+ } else {
+
+ /* old chips w/o PMU, force HT through cc,
+ * then use FCA to verify mac is running fast clock
+ */
+
+ wlc_hw->forcefastclk = ai_clkctl_cc(wlc_hw->sih, mode);
+
+ /* check fast clock is available (if core is not in reset) */
+ if (wlc_hw->forcefastclk && wlc_hw->clk)
+ WARN_ON(!(ai_core_sflags(wlc_hw->sih, 0, 0) &
+ SISF_FCLKA));
+
+ /*
+ * keep the ucode wake bit on if forcefastclk is on since we
+ * do not want ucode to put us back to slow clock when it dozes
+ * for PM mode. Code below matches the wake override bit with
+ * current forcefastclk state. Only setting bit in wake_override
+ * instead of waking ucode immediately since old code had this
+ * behavior. Older code set wlc->forcefastclk but only had the
+ * wake happen if the wakup_ucode work (protected by an up
+ * check) was executed just below.
+ */
+ if (wlc_hw->forcefastclk)
+ mboolset(wlc_hw->wake_override,
+ BRCMS_WAKE_OVERRIDE_FORCEFAST);
+ else
+ mboolclr(wlc_hw->wake_override,
+ BRCMS_WAKE_OVERRIDE_FORCEFAST);
+ }
+}
+
+/* set or clear ucode host flag bits
+ * it has an optimization for no-change write
+ * it only writes through shared memory when the core has clock;
+ * pre-CLK changes should use wlc_write_mhf to get around the optimization
+ *
+ *
+ * bands values are: BRCM_BAND_AUTO <--- Current band only
+ * BRCM_BAND_5G <--- 5G band only
+ * BRCM_BAND_2G <--- 2G band only
+ * BRCM_BAND_ALL <--- All bands
+ */
+void
+brcms_b_mhf(struct brcms_hardware *wlc_hw, u8 idx, u16 mask, u16 val,
+ int bands)
+{
+ u16 save;
+ u16 addr[MHFMAX] = {
+ M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4,
+ M_HOST_FLAGS5
+ };
+ struct brcms_hw_band *band;
+
+ if ((val & ~mask) || idx >= MHFMAX)
+ return; /* error condition */
+
+ switch (bands) {
+ /* Current band only or all bands,
+ * then set the band to current band
+ */
+ case BRCM_BAND_AUTO:
+ case BRCM_BAND_ALL:
+ band = wlc_hw->band;
+ break;
+ case BRCM_BAND_5G:
+ band = wlc_hw->bandstate[BAND_5G_INDEX];
+ break;
+ case BRCM_BAND_2G:
+ band = wlc_hw->bandstate[BAND_2G_INDEX];
+ break;
+ default:
+ band = NULL; /* error condition */
+ }
+
+ if (band) {
+ save = band->mhfs[idx];
+ band->mhfs[idx] = (band->mhfs[idx] & ~mask) | val;
+
+ /* optimization: only write through if changed, and
+ * changed band is the current band
+ */
+ if (wlc_hw->clk && (band->mhfs[idx] != save)
+ && (band == wlc_hw->band))
+ brcms_b_write_shm(wlc_hw, addr[idx],
+ (u16) band->mhfs[idx]);
+ }
+
+ if (bands == BRCM_BAND_ALL) {
+ wlc_hw->bandstate[0]->mhfs[idx] =
+ (wlc_hw->bandstate[0]->mhfs[idx] & ~mask) | val;
+ wlc_hw->bandstate[1]->mhfs[idx] =
+ (wlc_hw->bandstate[1]->mhfs[idx] & ~mask) | val;
+ }
+}
+
+/* set the maccontrol register to desired reset state and
+ * initialize the sw cache of the register
+ */
+static void brcms_c_mctrl_reset(struct brcms_hardware *wlc_hw)
+{
+ /* IHR accesses are always enabled, PSM disabled, HPS off and WAKE on */
+ wlc_hw->maccontrol = 0;
+ wlc_hw->suspended_fifos = 0;
+ wlc_hw->wake_override = 0;
+ wlc_hw->mute_override = 0;
+ brcms_b_mctrl(wlc_hw, ~0, MCTL_IHR_EN | MCTL_WAKE);
+}
+
+/*
+ * write the software state of maccontrol and
+ * overrides to the maccontrol register
+ */
+static void brcms_c_mctrl_write(struct brcms_hardware *wlc_hw)
+{
+ u32 maccontrol = wlc_hw->maccontrol;
+
+ /* OR in the wake bit if overridden */
+ if (wlc_hw->wake_override)
+ maccontrol |= MCTL_WAKE;
+
+ /* set AP and INFRA bits for mute if needed */
+ if (wlc_hw->mute_override) {
+ maccontrol &= ~(MCTL_AP);
+ maccontrol |= MCTL_INFRA;
+ }
+
+ W_REG(&wlc_hw->regs->maccontrol, maccontrol);
+}
+
+/* set or clear maccontrol bits */
+void brcms_b_mctrl(struct brcms_hardware *wlc_hw, u32 mask, u32 val)
+{
+ u32 maccontrol;
+ u32 new_maccontrol;
+
+ if (val & ~mask)
+ return; /* error condition */
+ maccontrol = wlc_hw->maccontrol;
+ new_maccontrol = (maccontrol & ~mask) | val;
+
+ /* if the new maccontrol value is the same as the old, nothing to do */
+ if (new_maccontrol == maccontrol)
+ return;
+
+ /* something changed, cache the new value */
+ wlc_hw->maccontrol = new_maccontrol;
+
+ /* write the new values with overrides applied */
+ brcms_c_mctrl_write(wlc_hw);
+}
+
+void brcms_c_ucode_wake_override_set(struct brcms_hardware *wlc_hw,
+ u32 override_bit)
+{
+ if (wlc_hw->wake_override || (wlc_hw->maccontrol & MCTL_WAKE)) {
+ mboolset(wlc_hw->wake_override, override_bit);
+ return;
+ }
+
+ mboolset(wlc_hw->wake_override, override_bit);
+
+ brcms_c_mctrl_write(wlc_hw);
+ brcms_b_wait_for_wake(wlc_hw);
+}
+
+void brcms_c_ucode_wake_override_clear(struct brcms_hardware *wlc_hw,
+ u32 override_bit)
+{
+ mboolclr(wlc_hw->wake_override, override_bit);
+
+ if (wlc_hw->wake_override || (wlc_hw->maccontrol & MCTL_WAKE))
+ return;
+
+ brcms_c_mctrl_write(wlc_hw);
+}
+
+/* When driver needs ucode to stop beaconing, it has to make sure that
+ * MCTL_AP is clear and MCTL_INFRA is set
+ * Mode MCTL_AP MCTL_INFRA
+ * AP 1 1
+ * STA 0 1 <--- This will ensure no beacons
+ * IBSS 0 0
+ */
+static void brcms_c_ucode_mute_override_set(struct brcms_hardware *wlc_hw)
+{
+ wlc_hw->mute_override = 1;
+
+ /* if maccontrol already has AP == 0 and INFRA == 1 without this
+ * override, then there is no change to write
+ */
+ if ((wlc_hw->maccontrol & (MCTL_AP | MCTL_INFRA)) == MCTL_INFRA)
+ return;
+
+ brcms_c_mctrl_write(wlc_hw);
+}
+
+/* Clear the override on AP and INFRA bits */
+static void brcms_c_ucode_mute_override_clear(struct brcms_hardware *wlc_hw)
+{
+ if (wlc_hw->mute_override == 0)
+ return;
+
+ wlc_hw->mute_override = 0;
+
+ /* if maccontrol already has AP == 0 and INFRA == 1 without this
+ * override, then there is no change to write
+ */
+ if ((wlc_hw->maccontrol & (MCTL_AP | MCTL_INFRA)) == MCTL_INFRA)
+ return;
+
+ brcms_c_mctrl_write(wlc_hw);
+}
+
+/*
+ * Write a MAC address to the given match reg offset in the RXE match engine.
+ */
+static void
+brcms_b_set_addrmatch(struct brcms_hardware *wlc_hw, int match_reg_offset,
+ const u8 *addr)
+{
+ struct d11regs __iomem *regs;
+ u16 mac_l;
+ u16 mac_m;
+ u16 mac_h;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d: brcms_b_set_addrmatch\n",
+ wlc_hw->unit);
+
+ regs = wlc_hw->regs;
+ mac_l = addr[0] | (addr[1] << 8);
+ mac_m = addr[2] | (addr[3] << 8);
+ mac_h = addr[4] | (addr[5] << 8);
+
+ /* enter the MAC addr into the RXE match registers */
+ W_REG(&regs->rcm_ctl, RCM_INC_DATA | match_reg_offset);
+ W_REG(&regs->rcm_mat_data, mac_l);
+ W_REG(&regs->rcm_mat_data, mac_m);
+ W_REG(&regs->rcm_mat_data, mac_h);
+
+}
+
+void
+brcms_b_write_template_ram(struct brcms_hardware *wlc_hw, int offset, int len,
+ void *buf)
+{
+ struct d11regs __iomem *regs;
+ u32 word;
+ __le32 word_le;
+ __be32 word_be;
+ bool be_bit;
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ regs = wlc_hw->regs;
+ W_REG(&regs->tplatewrptr, offset);
+
+ /* if MCTL_BIGEND bit set in mac control register,
+ * the chip swaps data in fifo, as well as data in
+ * template ram
+ */
+ be_bit = (R_REG(&regs->maccontrol) & MCTL_BIGEND) != 0;
+
+ while (len > 0) {
+ memcpy(&word, buf, sizeof(u32));
+
+ if (be_bit) {
+ word_be = cpu_to_be32(word);
+ word = *(u32 *)&word_be;
+ } else {
+ word_le = cpu_to_le32(word);
+ word = *(u32 *)&word_le;
+ }
+
+ W_REG(&regs->tplatewrdata, word);
+
+ buf = (u8 *) buf + sizeof(u32);
+ len -= sizeof(u32);
+ }
+}
+
+static void brcms_b_set_cwmin(struct brcms_hardware *wlc_hw, u16 newmin)
+{
+ wlc_hw->band->CWmin = newmin;
+
+ W_REG(&wlc_hw->regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_CWMIN);
+ (void)R_REG(&wlc_hw->regs->objaddr);
+ W_REG(&wlc_hw->regs->objdata, newmin);
+}
+
+static void brcms_b_set_cwmax(struct brcms_hardware *wlc_hw, u16 newmax)
+{
+ wlc_hw->band->CWmax = newmax;
+
+ W_REG(&wlc_hw->regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_CWMAX);
+ (void)R_REG(&wlc_hw->regs->objaddr);
+ W_REG(&wlc_hw->regs->objdata, newmax);
+}
+
+void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw)
+{
+ bool fastclk;
+
+ /* request FAST clock if not on */
+ fastclk = wlc_hw->forcefastclk;
+ if (!fastclk)
+ brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
+
+ wlc_phy_bw_state_set(wlc_hw->band->pi, bw);
+
+ brcms_b_phy_reset(wlc_hw);
+ wlc_phy_init(wlc_hw->band->pi, wlc_phy_chanspec_get(wlc_hw->band->pi));
+
+ /* restore the clk */
+ if (!fastclk)
+ brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
+}
+
+static void brcms_b_upd_synthpu(struct brcms_hardware *wlc_hw)
+{
+ u16 v;
+ struct brcms_c_info *wlc = wlc_hw->wlc;
+ /* update SYNTHPU_DLY */
+
+ if (BRCMS_ISLCNPHY(wlc->band))
+ v = SYNTHPU_DLY_LPPHY_US;
+ else if (BRCMS_ISNPHY(wlc->band) && (NREV_GE(wlc->band->phyrev, 3)))
+ v = SYNTHPU_DLY_NPHY_US;
+ else
+ v = SYNTHPU_DLY_BPHY_US;
+
+ brcms_b_write_shm(wlc_hw, M_SYNTHPU_DLY, v);
+}
+
+static void brcms_c_ucode_txant_set(struct brcms_hardware *wlc_hw)
+{
+ u16 phyctl;
+ u16 phytxant = wlc_hw->bmac_phytxant;
+ u16 mask = PHY_TXC_ANT_MASK;
+
+ /* set the Probe Response frame phy control word */
+ phyctl = brcms_b_read_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS);
+ phyctl = (phyctl & ~mask) | phytxant;
+ brcms_b_write_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS, phyctl);
+
+ /* set the Response (ACK/CTS) frame phy control word */
+ phyctl = brcms_b_read_shm(wlc_hw, M_RSP_PCTLWD);
+ phyctl = (phyctl & ~mask) | phytxant;
+ brcms_b_write_shm(wlc_hw, M_RSP_PCTLWD, phyctl);
+}
+
+static u16 brcms_b_ofdm_ratetable_offset(struct brcms_hardware *wlc_hw,
+ u8 rate)
+{
+ uint i;
+ u8 plcp_rate = 0;
+ struct plcp_signal_rate_lookup {
+ u8 rate;
+ u8 signal_rate;
+ };
+ /* OFDM RATE sub-field of PLCP SIGNAL field, per 802.11 sec 17.3.4.1 */
+ const struct plcp_signal_rate_lookup rate_lookup[] = {
+ {BRCM_RATE_6M, 0xB},
+ {BRCM_RATE_9M, 0xF},
+ {BRCM_RATE_12M, 0xA},
+ {BRCM_RATE_18M, 0xE},
+ {BRCM_RATE_24M, 0x9},
+ {BRCM_RATE_36M, 0xD},
+ {BRCM_RATE_48M, 0x8},
+ {BRCM_RATE_54M, 0xC}
+ };
+
+ for (i = 0; i < ARRAY_SIZE(rate_lookup); i++) {
+ if (rate == rate_lookup[i].rate) {
+ plcp_rate = rate_lookup[i].signal_rate;
+ break;
+ }
+ }
+
+ /* Find the SHM pointer to the rate table entry by looking in the
+ * Direct-map Table
+ */
+ return 2 * brcms_b_read_shm(wlc_hw, M_RT_DIRMAP_A + (plcp_rate * 2));
+}
+
+static void brcms_upd_ofdm_pctl1_table(struct brcms_hardware *wlc_hw)
+{
+ u8 rate;
+ u8 rates[8] = {
+ BRCM_RATE_6M, BRCM_RATE_9M, BRCM_RATE_12M, BRCM_RATE_18M,
+ BRCM_RATE_24M, BRCM_RATE_36M, BRCM_RATE_48M, BRCM_RATE_54M
+ };
+ u16 entry_ptr;
+ u16 pctl1;
+ uint i;
+
+ if (!BRCMS_PHY_11N_CAP(wlc_hw->band))
+ return;
+
+ /* walk the phy rate table and update the entries */
+ for (i = 0; i < ARRAY_SIZE(rates); i++) {
+ rate = rates[i];
+
+ entry_ptr = brcms_b_ofdm_ratetable_offset(wlc_hw, rate);
+
+ /* read the SHM Rate Table entry OFDM PCTL1 values */
+ pctl1 =
+ brcms_b_read_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS);
+
+ /* modify the value */
+ pctl1 &= ~PHY_TXC1_MODE_MASK;
+ pctl1 |= (wlc_hw->hw_stf_ss_opmode << PHY_TXC1_MODE_SHIFT);
+
+ /* Update the SHM Rate Table entry OFDM PCTL1 values */
+ brcms_b_write_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS,
+ pctl1);
+ }
+}
+
+/* band-specific init */
+static void brcms_b_bsinit(struct brcms_c_info *wlc, u16 chanspec)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+
+ BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
+ wlc_hw->band->bandunit);
+
+ brcms_c_ucode_bsinit(wlc_hw);
+
+ wlc_phy_init(wlc_hw->band->pi, chanspec);
+
+ brcms_c_ucode_txant_set(wlc_hw);
+
+ /*
+ * cwmin is band-specific, update hardware
+ * with value for current band
+ */
+ brcms_b_set_cwmin(wlc_hw, wlc_hw->band->CWmin);
+ brcms_b_set_cwmax(wlc_hw, wlc_hw->band->CWmax);
+
+ brcms_b_update_slot_timing(wlc_hw,
+ wlc_hw->band->bandtype == BRCM_BAND_5G ?
+ true : wlc_hw->shortslot);
+
+ /* write phytype and phyvers */
+ brcms_b_write_shm(wlc_hw, M_PHYTYPE, (u16) wlc_hw->band->phytype);
+ brcms_b_write_shm(wlc_hw, M_PHYVER, (u16) wlc_hw->band->phyrev);
+
+ /*
+ * initialize the txphyctl1 rate table since
+ * shmem is shared between bands
+ */
+ brcms_upd_ofdm_pctl1_table(wlc_hw);
+
+ brcms_b_upd_synthpu(wlc_hw);
+}
+
+/* Perform a soft reset of the PHY PLL */
+void brcms_b_core_phypll_reset(struct brcms_hardware *wlc_hw)
+{
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ ai_corereg(wlc_hw->sih, SI_CC_IDX,
+ offsetof(struct chipcregs, chipcontrol_addr), ~0, 0);
+ udelay(1);
+ ai_corereg(wlc_hw->sih, SI_CC_IDX,
+ offsetof(struct chipcregs, chipcontrol_data), 0x4, 0);
+ udelay(1);
+ ai_corereg(wlc_hw->sih, SI_CC_IDX,
+ offsetof(struct chipcregs, chipcontrol_data), 0x4, 4);
+ udelay(1);
+ ai_corereg(wlc_hw->sih, SI_CC_IDX,
+ offsetof(struct chipcregs, chipcontrol_data), 0x4, 0);
+ udelay(1);
+}
+
+/* light way to turn on phy clock without reset for NPHY only
+ * refer to brcms_b_core_phy_clk for full version
+ */
+void brcms_b_phyclk_fgc(struct brcms_hardware *wlc_hw, bool clk)
+{
+ /* support(necessary for NPHY and HYPHY) only */
+ if (!BRCMS_ISNPHY(wlc_hw->band))
+ return;
+
+ if (ON == clk)
+ ai_core_cflags(wlc_hw->sih, SICF_FGC, SICF_FGC);
+ else
+ ai_core_cflags(wlc_hw->sih, SICF_FGC, 0);
+
+}
+
+void brcms_b_macphyclk_set(struct brcms_hardware *wlc_hw, bool clk)
+{
+ if (ON == clk)
+ ai_core_cflags(wlc_hw->sih, SICF_MPCLKE, SICF_MPCLKE);
+ else
+ ai_core_cflags(wlc_hw->sih, SICF_MPCLKE, 0);
+}
+
+void brcms_b_phy_reset(struct brcms_hardware *wlc_hw)
+{
+ struct brcms_phy_pub *pih = wlc_hw->band->pi;
+ u32 phy_bw_clkbits;
+ bool phy_in_reset = false;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ if (pih == NULL)
+ return;
+
+ phy_bw_clkbits = wlc_phy_clk_bwbits(wlc_hw->band->pi);
+
+ /* Specific reset sequence required for NPHY rev 3 and 4 */
+ if (BRCMS_ISNPHY(wlc_hw->band) && NREV_GE(wlc_hw->band->phyrev, 3) &&
+ NREV_LE(wlc_hw->band->phyrev, 4)) {
+ /* Set the PHY bandwidth */
+ ai_core_cflags(wlc_hw->sih, SICF_BWMASK, phy_bw_clkbits);
+
+ udelay(1);
+
+ /* Perform a soft reset of the PHY PLL */
+ brcms_b_core_phypll_reset(wlc_hw);
+
+ /* reset the PHY */
+ ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_PCLKE),
+ (SICF_PRST | SICF_PCLKE));
+ phy_in_reset = true;
+ } else {
+ ai_core_cflags(wlc_hw->sih,
+ (SICF_PRST | SICF_PCLKE | SICF_BWMASK),
+ (SICF_PRST | SICF_PCLKE | phy_bw_clkbits));
+ }
+
+ udelay(2);
+ brcms_b_core_phy_clk(wlc_hw, ON);
+
+ if (pih)
+ wlc_phy_anacore(pih, ON);
+}
+
+/* switch to and initialize new band */
+static void brcms_b_setband(struct brcms_hardware *wlc_hw, uint bandunit,
+ u16 chanspec) {
+ struct brcms_c_info *wlc = wlc_hw->wlc;
+ u32 macintmask;
+
+ /* Enable the d11 core before accessing it */
+ if (!ai_iscoreup(wlc_hw->sih)) {
+ ai_core_reset(wlc_hw->sih, 0, 0);
+ brcms_c_mctrl_reset(wlc_hw);
+ }
+
+ macintmask = brcms_c_setband_inact(wlc, bandunit);
+
+ if (!wlc_hw->up)
+ return;
+
+ brcms_b_core_phy_clk(wlc_hw, ON);
+
+ /* band-specific initializations */
+ brcms_b_bsinit(wlc, chanspec);
+
+ /*
+ * If there are any pending software interrupt bits,
+ * then replace these with a harmless nonzero value
+ * so brcms_c_dpc() will re-enable interrupts when done.
+ */
+ if (wlc->macintstatus)
+ wlc->macintstatus = MI_DMAINT;
+
+ /* restore macintmask */
+ brcms_intrsrestore(wlc->wl, macintmask);
+
+ /* ucode should still be suspended.. */
+ WARN_ON((R_REG(&wlc_hw->regs->maccontrol) & MCTL_EN_MAC) != 0);
+}
+
+static bool brcms_c_isgoodchip(struct brcms_hardware *wlc_hw)
+{
+
+ /* reject unsupported corerev */
+ if (!CONF_HAS(D11CONF, wlc_hw->corerev)) {
+ wiphy_err(wlc_hw->wlc->wiphy, "unsupported core rev %d\n",
+ wlc_hw->corerev);
+ return false;
+ }
+
+ return true;
+}
+
+/* Validate some board info parameters */
+static bool brcms_c_validboardtype(struct brcms_hardware *wlc_hw)
+{
+ uint boardrev = wlc_hw->boardrev;
+
+ /* 4 bits each for board type, major, minor, and tiny version */
+ uint brt = (boardrev & 0xf000) >> 12;
+ uint b0 = (boardrev & 0xf00) >> 8;
+ uint b1 = (boardrev & 0xf0) >> 4;
+ uint b2 = boardrev & 0xf;
+
+ /* voards from other vendors are always considered valid */
+ if (wlc_hw->sih->boardvendor != PCI_VENDOR_ID_BROADCOM)
+ return true;
+
+ /* do some boardrev sanity checks when boardvendor is Broadcom */
+ if (boardrev == 0)
+ return false;
+
+ if (boardrev <= 0xff)
+ return true;
+
+ if ((brt > 2) || (brt == 0) || (b0 > 9) || (b0 == 0) || (b1 > 9)
+ || (b2 > 9))
+ return false;
+
+ return true;
+}
+
+static char *brcms_c_get_macaddr(struct brcms_hardware *wlc_hw)
+{
+ enum brcms_srom_id var_id = BRCMS_SROM_MACADDR;
+ char *macaddr;
+
+ /* If macaddr exists, use it (Sromrev4, CIS, ...). */
+ macaddr = getvar(wlc_hw->sih, var_id);
+ if (macaddr != NULL)
+ return macaddr;
+
+ if (wlc_hw->_nbands > 1)
+ var_id = BRCMS_SROM_ET1MACADDR;
+ else
+ var_id = BRCMS_SROM_IL0MACADDR;
+
+ macaddr = getvar(wlc_hw->sih, var_id);
+ if (macaddr == NULL)
+ wiphy_err(wlc_hw->wlc->wiphy, "wl%d: wlc_get_macaddr: macaddr "
+ "getvar(%d) not found\n", wlc_hw->unit, var_id);
+
+ return macaddr;
+}
+
+/* power both the pll and external oscillator on/off */
+static void brcms_b_xtal(struct brcms_hardware *wlc_hw, bool want)
+{
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d: want %d\n", wlc_hw->unit, want);
+
+ /*
+ * dont power down if plldown is false or
+ * we must poll hw radio disable
+ */
+ if (!want && wlc_hw->pllreq)
+ return;
+
+ if (wlc_hw->sih)
+ ai_clkctl_xtal(wlc_hw->sih, XTAL | PLL, want);
+
+ wlc_hw->sbclk = want;
+ if (!wlc_hw->sbclk) {
+ wlc_hw->clk = false;
+ if (wlc_hw->band && wlc_hw->band->pi)
+ wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
+ }
+}
+
+/*
+ * Return true if radio is disabled, otherwise false.
+ * hw radio disable signal is an external pin, users activate it asynchronously
+ * this function could be called when driver is down and w/o clock
+ * it operates on different registers depending on corerev and boardflag.
+ */
+static bool brcms_b_radio_read_hwdisabled(struct brcms_hardware *wlc_hw)
+{
+ bool v, clk, xtal;
+ u32 resetbits = 0, flags = 0;
+
+ xtal = wlc_hw->sbclk;
+ if (!xtal)
+ brcms_b_xtal(wlc_hw, ON);
+
+ /* may need to take core out of reset first */
+ clk = wlc_hw->clk;
+ if (!clk) {
+ /*
+ * mac no longer enables phyclk automatically when driver
+ * accesses phyreg throughput mac. This can be skipped since
+ * only mac reg is accessed below
+ */
+ flags |= SICF_PCLKE;
+
+ /*
+ * AI chip doesn't restore bar0win2 on
+ * hibernation/resume, need sw fixup
+ */
+ if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) ||
+ (wlc_hw->sih->chip == BCM43225_CHIP_ID))
+ wlc_hw->regs = (struct d11regs __iomem *)
+ ai_setcore(wlc_hw->sih, D11_CORE_ID, 0);
+ ai_core_reset(wlc_hw->sih, flags, resetbits);
+ brcms_c_mctrl_reset(wlc_hw);
+ }
+
+ v = ((R_REG(&wlc_hw->regs->phydebug) & PDBG_RFD) != 0);
+
+ /* put core back into reset */
+ if (!clk)
+ ai_core_disable(wlc_hw->sih, 0);
+
+ if (!xtal)
+ brcms_b_xtal(wlc_hw, OFF);
+
+ return v;
+}
+
+static bool wlc_dma_rxreset(struct brcms_hardware *wlc_hw, uint fifo)
+{
+ struct dma_pub *di = wlc_hw->di[fifo];
+ return dma_rxreset(di);
+}
+
+/* d11 core reset
+ * ensure fask clock during reset
+ * reset dma
+ * reset d11(out of reset)
+ * reset phy(out of reset)
+ * clear software macintstatus for fresh new start
+ * one testing hack wlc_hw->noreset will bypass the d11/phy reset
+ */
+void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags)
+{
+ struct d11regs __iomem *regs;
+ uint i;
+ bool fastclk;
+ u32 resetbits = 0;
+
+ if (flags == BRCMS_USE_COREFLAGS)
+ flags = (wlc_hw->band->pi ? wlc_hw->band->core_flags : 0);
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ regs = wlc_hw->regs;
+
+ /* request FAST clock if not on */
+ fastclk = wlc_hw->forcefastclk;
+ if (!fastclk)
+ brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
+
+ /* reset the dma engines except first time thru */
+ if (ai_iscoreup(wlc_hw->sih)) {
+ for (i = 0; i < NFIFO; i++)
+ if ((wlc_hw->di[i]) && (!dma_txreset(wlc_hw->di[i])))
+ wiphy_err(wlc_hw->wlc->wiphy, "wl%d: %s: "
+ "dma_txreset[%d]: cannot stop dma\n",
+ wlc_hw->unit, __func__, i);
+
+ if ((wlc_hw->di[RX_FIFO])
+ && (!wlc_dma_rxreset(wlc_hw, RX_FIFO)))
+ wiphy_err(wlc_hw->wlc->wiphy, "wl%d: %s: dma_rxreset"
+ "[%d]: cannot stop dma\n",
+ wlc_hw->unit, __func__, RX_FIFO);
+ }
+ /* if noreset, just stop the psm and return */
+ if (wlc_hw->noreset) {
+ wlc_hw->wlc->macintstatus = 0; /* skip wl_dpc after down */
+ brcms_b_mctrl(wlc_hw, MCTL_PSM_RUN | MCTL_EN_MAC, 0);
+ return;
+ }
+
+ /*
+ * mac no longer enables phyclk automatically when driver accesses
+ * phyreg throughput mac, AND phy_reset is skipped at early stage when
+ * band->pi is invalid. need to enable PHY CLK
+ */
+ flags |= SICF_PCLKE;
+
+ /*
+ * reset the core
+ * In chips with PMU, the fastclk request goes through d11 core
+ * reg 0x1e0, which is cleared by the core_reset. have to re-request it.
+ *
+ * This adds some delay and we can optimize it by also requesting
+ * fastclk through chipcommon during this period if necessary. But
+ * that has to work coordinate with other driver like mips/arm since
+ * they may touch chipcommon as well.
+ */
+ wlc_hw->clk = false;
+ ai_core_reset(wlc_hw->sih, flags, resetbits);
+ wlc_hw->clk = true;
+ if (wlc_hw->band && wlc_hw->band->pi)
+ wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, true);
+
+ brcms_c_mctrl_reset(wlc_hw);
+
+ if (wlc_hw->sih->cccaps & CC_CAP_PMU)
+ brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
+
+ brcms_b_phy_reset(wlc_hw);
+
+ /* turn on PHY_PLL */
+ brcms_b_core_phypll_ctl(wlc_hw, true);
+
+ /* clear sw intstatus */
+ wlc_hw->wlc->macintstatus = 0;
+
+ /* restore the clk setting */
+ if (!fastclk)
+ brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
+}
+
+/* txfifo sizes needs to be modified(increased) since the newer cores
+ * have more memory.
+ */
+static void brcms_b_corerev_fifofixup(struct brcms_hardware *wlc_hw)
+{
+ struct d11regs __iomem *regs = wlc_hw->regs;
+ u16 fifo_nu;
+ u16 txfifo_startblk = TXFIFO_START_BLK, txfifo_endblk;
+ u16 txfifo_def, txfifo_def1;
+ u16 txfifo_cmd;
+
+ /* tx fifos start at TXFIFO_START_BLK from the Base address */
+ txfifo_startblk = TXFIFO_START_BLK;
+
+ /* sequence of operations: reset fifo, set fifo size, reset fifo */
+ for (fifo_nu = 0; fifo_nu < NFIFO; fifo_nu++) {
+
+ txfifo_endblk = txfifo_startblk + wlc_hw->xmtfifo_sz[fifo_nu];
+ txfifo_def = (txfifo_startblk & 0xff) |
+ (((txfifo_endblk - 1) & 0xff) << TXFIFO_FIFOTOP_SHIFT);
+ txfifo_def1 = ((txfifo_startblk >> 8) & 0x1) |
+ ((((txfifo_endblk -
+ 1) >> 8) & 0x1) << TXFIFO_FIFOTOP_SHIFT);
+ txfifo_cmd =
+ TXFIFOCMD_RESET_MASK | (fifo_nu << TXFIFOCMD_FIFOSEL_SHIFT);
+
+ W_REG(&regs->xmtfifocmd, txfifo_cmd);
+ W_REG(&regs->xmtfifodef, txfifo_def);
+ W_REG(&regs->xmtfifodef1, txfifo_def1);
+
+ W_REG(&regs->xmtfifocmd, txfifo_cmd);
+
+ txfifo_startblk += wlc_hw->xmtfifo_sz[fifo_nu];
+ }
+ /*
+ * need to propagate to shm location to be in sync since ucode/hw won't
+ * do this
+ */
+ brcms_b_write_shm(wlc_hw, M_FIFOSIZE0,
+ wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]);
+ brcms_b_write_shm(wlc_hw, M_FIFOSIZE1,
+ wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]);
+ brcms_b_write_shm(wlc_hw, M_FIFOSIZE2,
+ ((wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO] << 8) | wlc_hw->
+ xmtfifo_sz[TX_AC_BK_FIFO]));
+ brcms_b_write_shm(wlc_hw, M_FIFOSIZE3,
+ ((wlc_hw->xmtfifo_sz[TX_ATIM_FIFO] << 8) | wlc_hw->
+ xmtfifo_sz[TX_BCMC_FIFO]));
+}
+
+/* This function is used for changing the tsf frac register
+ * If spur avoidance mode is off, the mac freq will be 80/120/160Mhz
+ * If spur avoidance mode is on1, the mac freq will be 82/123/164Mhz
+ * If spur avoidance mode is on2, the mac freq will be 84/126/168Mhz
+ * HTPHY Formula is 2^26/freq(MHz) e.g.
+ * For spuron2 - 126MHz -> 2^26/126 = 532610.0
+ * - 532610 = 0x82082 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x2082
+ * For spuron: 123MHz -> 2^26/123 = 545600.5
+ * - 545601 = 0x85341 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x5341
+ * For spur off: 120MHz -> 2^26/120 = 559240.5
+ * - 559241 = 0x88889 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x8889
+ */
+
+void brcms_b_switch_macfreq(struct brcms_hardware *wlc_hw, u8 spurmode)
+{
+ struct d11regs __iomem *regs = wlc_hw->regs;
+
+ if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) ||
+ (wlc_hw->sih->chip == BCM43225_CHIP_ID)) {
+ if (spurmode == WL_SPURAVOID_ON2) { /* 126Mhz */
+ W_REG(&regs->tsf_clk_frac_l, 0x2082);
+ W_REG(&regs->tsf_clk_frac_h, 0x8);
+ } else if (spurmode == WL_SPURAVOID_ON1) { /* 123Mhz */
+ W_REG(&regs->tsf_clk_frac_l, 0x5341);
+ W_REG(&regs->tsf_clk_frac_h, 0x8);
+ } else { /* 120Mhz */
+ W_REG(&regs->tsf_clk_frac_l, 0x8889);
+ W_REG(&regs->tsf_clk_frac_h, 0x8);
+ }
+ } else if (BRCMS_ISLCNPHY(wlc_hw->band)) {
+ if (spurmode == WL_SPURAVOID_ON1) { /* 82Mhz */
+ W_REG(&regs->tsf_clk_frac_l, 0x7CE0);
+ W_REG(&regs->tsf_clk_frac_h, 0xC);
+ } else { /* 80Mhz */
+ W_REG(&regs->tsf_clk_frac_l, 0xCCCD);
+ W_REG(&regs->tsf_clk_frac_h, 0xC);
+ }
+ }
+}
+
+/* Initialize GPIOs that are controlled by D11 core */
+static void brcms_c_gpio_init(struct brcms_c_info *wlc)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ struct d11regs __iomem *regs;
+ u32 gc, gm;
+
+ regs = wlc_hw->regs;
+
+ /* use GPIO select 0 to get all gpio signals from the gpio out reg */
+ brcms_b_mctrl(wlc_hw, MCTL_GPOUT_SEL_MASK, 0);
+
+ /*
+ * Common GPIO setup:
+ * G0 = LED 0 = WLAN Activity
+ * G1 = LED 1 = WLAN 2.4 GHz Radio State
+ * G2 = LED 2 = WLAN 5 GHz Radio State
+ * G4 = radio disable input (HI enabled, LO disabled)
+ */
+
+ gc = gm = 0;
+
+ /* Allocate GPIOs for mimo antenna diversity feature */
+ if (wlc_hw->antsel_type == ANTSEL_2x3) {
+ /* Enable antenna diversity, use 2x3 mode */
+ brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_EN,
+ MHF3_ANTSEL_EN, BRCM_BAND_ALL);
+ brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_MODE,
+ MHF3_ANTSEL_MODE, BRCM_BAND_ALL);
+
+ /* init superswitch control */
+ wlc_phy_antsel_init(wlc_hw->band->pi, false);
+
+ } else if (wlc_hw->antsel_type == ANTSEL_2x4) {
+ gm |= gc |= (BOARD_GPIO_12 | BOARD_GPIO_13);
+ /*
+ * The board itself is powered by these GPIOs
+ * (when not sending pattern) so set them high
+ */
+ OR_REG(&regs->psm_gpio_oe,
+ (BOARD_GPIO_12 | BOARD_GPIO_13));
+ OR_REG(&regs->psm_gpio_out,
+ (BOARD_GPIO_12 | BOARD_GPIO_13));
+
+ /* Enable antenna diversity, use 2x4 mode */
+ brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_EN,
+ MHF3_ANTSEL_EN, BRCM_BAND_ALL);
+ brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_MODE, 0,
+ BRCM_BAND_ALL);
+
+ /* Configure the desired clock to be 4Mhz */
+ brcms_b_write_shm(wlc_hw, M_ANTSEL_CLKDIV,
+ ANTSEL_CLKDIV_4MHZ);
+ }
+
+ /*
+ * gpio 9 controls the PA. ucode is responsible
+ * for wiggling out and oe
+ */
+ if (wlc_hw->boardflags & BFL_PACTRL)
+ gm |= gc |= BOARD_GPIO_PACTRL;
+
+ /* apply to gpiocontrol register */
+ ai_gpiocontrol(wlc_hw->sih, gm, gc, GPIO_DRV_PRIORITY);
+}
+
+static void brcms_ucode_write(struct brcms_hardware *wlc_hw,
+ const __le32 ucode[], const size_t nbytes)
+{
+ struct d11regs __iomem *regs = wlc_hw->regs;
+ uint i;
+ uint count;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ count = (nbytes / sizeof(u32));
+
+ W_REG(&regs->objaddr, (OBJADDR_AUTO_INC | OBJADDR_UCM_SEL));
+ (void)R_REG(&regs->objaddr);
+ for (i = 0; i < count; i++)
+ W_REG(&regs->objdata, le32_to_cpu(ucode[i]));
+
+}
+
+static void brcms_ucode_download(struct brcms_hardware *wlc_hw)
+{
+ struct brcms_c_info *wlc;
+ struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode;
+
+ wlc = wlc_hw->wlc;
+
+ if (wlc_hw->ucode_loaded)
+ return;
+
+ if (D11REV_IS(wlc_hw->corerev, 23)) {
+ if (BRCMS_ISNPHY(wlc_hw->band)) {
+ brcms_ucode_write(wlc_hw, ucode->bcm43xx_16_mimo,
+ ucode->bcm43xx_16_mimosz);
+ wlc_hw->ucode_loaded = true;
+ } else
+ wiphy_err(wlc->wiphy, "%s: wl%d: unsupported phy in "
+ "corerev %d\n",
+ __func__, wlc_hw->unit, wlc_hw->corerev);
+ } else if (D11REV_IS(wlc_hw->corerev, 24)) {
+ if (BRCMS_ISLCNPHY(wlc_hw->band)) {
+ brcms_ucode_write(wlc_hw, ucode->bcm43xx_24_lcn,
+ ucode->bcm43xx_24_lcnsz);
+ wlc_hw->ucode_loaded = true;
+ } else {
+ wiphy_err(wlc->wiphy, "%s: wl%d: unsupported phy in "
+ "corerev %d\n",
+ __func__, wlc_hw->unit, wlc_hw->corerev);
+ }
+ }
+}
+
+void brcms_b_txant_set(struct brcms_hardware *wlc_hw, u16 phytxant)
+{
+ /* update sw state */
+ wlc_hw->bmac_phytxant = phytxant;
+
+ /* push to ucode if up */
+ if (!wlc_hw->up)
+ return;
+ brcms_c_ucode_txant_set(wlc_hw);
+
+}
+
+u16 brcms_b_get_txant(struct brcms_hardware *wlc_hw)
+{
+ return (u16) wlc_hw->wlc->stf->txant;
+}
+
+void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw, u8 antsel_type)
+{
+ wlc_hw->antsel_type = antsel_type;
+
+ /* Update the antsel type for phy module to use */
+ wlc_phy_antsel_type_set(wlc_hw->band->pi, antsel_type);
+}
+
+static void brcms_c_fatal_error(struct brcms_c_info *wlc)
+{
+ wiphy_err(wlc->wiphy, "wl%d: fatal error, reinitializing\n",
+ wlc->pub->unit);
+ brcms_init(wlc->wl);
+}
+
+static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw)
+{
+ bool fatal = false;
+ uint unit;
+ uint intstatus, idx;
+ struct d11regs __iomem *regs = wlc_hw->regs;
+ struct wiphy *wiphy = wlc_hw->wlc->wiphy;
+
+ unit = wlc_hw->unit;
+
+ for (idx = 0; idx < NFIFO; idx++) {
+ /* read intstatus register and ignore any non-error bits */
+ intstatus =
+ R_REG(&regs->intctrlregs[idx].intstatus) & I_ERRORS;
+ if (!intstatus)
+ continue;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d: intstatus%d 0x%x\n",
+ unit, idx, intstatus);
+
+ if (intstatus & I_RO) {
+ wiphy_err(wiphy, "wl%d: fifo %d: receive fifo "
+ "overflow\n", unit, idx);
+ fatal = true;
+ }
+
+ if (intstatus & I_PC) {
+ wiphy_err(wiphy, "wl%d: fifo %d: descriptor error\n",
+ unit, idx);
+ fatal = true;
+ }
+
+ if (intstatus & I_PD) {
+ wiphy_err(wiphy, "wl%d: fifo %d: data error\n", unit,
+ idx);
+ fatal = true;
+ }
+
+ if (intstatus & I_DE) {
+ wiphy_err(wiphy, "wl%d: fifo %d: descriptor protocol "
+ "error\n", unit, idx);
+ fatal = true;
+ }
+
+ if (intstatus & I_RU)
+ wiphy_err(wiphy, "wl%d: fifo %d: receive descriptor "
+ "underflow\n", idx, unit);
+
+ if (intstatus & I_XU) {
+ wiphy_err(wiphy, "wl%d: fifo %d: transmit fifo "
+ "underflow\n", idx, unit);
+ fatal = true;
+ }
+
+ if (fatal) {
+ brcms_c_fatal_error(wlc_hw->wlc); /* big hammer */
+ break;
+ } else
+ W_REG(&regs->intctrlregs[idx].intstatus,
+ intstatus);
+ }
+}
+
+void brcms_c_intrson(struct brcms_c_info *wlc)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ wlc->macintmask = wlc->defmacintmask;
+ W_REG(&wlc_hw->regs->macintmask, wlc->macintmask);
+}
+
+/*
+ * callback for siutils.c, which has only wlc handler, no wl they both check
+ * up, not only because there is no need to off/restore d11 interrupt but also
+ * because per-port code may require sync with valid interrupt.
+ */
+static u32 brcms_c_wlintrsoff(struct brcms_c_info *wlc)
+{
+ if (!wlc->hw->up)
+ return 0;
+
+ return brcms_intrsoff(wlc->wl);
+}
+
+static void brcms_c_wlintrsrestore(struct brcms_c_info *wlc, u32 macintmask)
+{
+ if (!wlc->hw->up)
+ return;
+
+ brcms_intrsrestore(wlc->wl, macintmask);
+}
+
+u32 brcms_c_intrsoff(struct brcms_c_info *wlc)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ u32 macintmask;
+
+ if (!wlc_hw->clk)
+ return 0;
+
+ macintmask = wlc->macintmask; /* isr can still happen */
+
+ W_REG(&wlc_hw->regs->macintmask, 0);
+ (void)R_REG(&wlc_hw->regs->macintmask); /* sync readback */
+ udelay(1); /* ensure int line is no longer driven */
+ wlc->macintmask = 0;
+
+ /* return previous macintmask; resolve race between us and our isr */
+ return wlc->macintstatus ? 0 : macintmask;
+}
+
+void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ if (!wlc_hw->clk)
+ return;
+
+ wlc->macintmask = macintmask;
+ W_REG(&wlc_hw->regs->macintmask, wlc->macintmask);
+}
+
+static void brcms_b_tx_fifo_suspend(struct brcms_hardware *wlc_hw,
+ uint tx_fifo)
+{
+ u8 fifo = 1 << tx_fifo;
+
+ /* Two clients of this code, 11h Quiet period and scanning. */
+
+ /* only suspend if not already suspended */
+ if ((wlc_hw->suspended_fifos & fifo) == fifo)
+ return;
+
+ /* force the core awake only if not already */
+ if (wlc_hw->suspended_fifos == 0)
+ brcms_c_ucode_wake_override_set(wlc_hw,
+ BRCMS_WAKE_OVERRIDE_TXFIFO);
+
+ wlc_hw->suspended_fifos |= fifo;
+
+ if (wlc_hw->di[tx_fifo]) {
+ /*
+ * Suspending AMPDU transmissions in the middle can cause
+ * underflow which may result in mismatch between ucode and
+ * driver so suspend the mac before suspending the FIFO
+ */
+ if (BRCMS_PHY_11N_CAP(wlc_hw->band))
+ brcms_c_suspend_mac_and_wait(wlc_hw->wlc);
+
+ dma_txsuspend(wlc_hw->di[tx_fifo]);
+
+ if (BRCMS_PHY_11N_CAP(wlc_hw->band))
+ brcms_c_enable_mac(wlc_hw->wlc);
+ }
+}
+
+static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw,
+ uint tx_fifo)
+{
+ /* BMAC_NOTE: BRCMS_TX_FIFO_ENAB is done in brcms_c_dpc() for DMA case
+ * but need to be done here for PIO otherwise the watchdog will catch
+ * the inconsistency and fire
+ */
+ /* Two clients of this code, 11h Quiet period and scanning. */
+ if (wlc_hw->di[tx_fifo])
+ dma_txresume(wlc_hw->di[tx_fifo]);
+
+ /* allow core to sleep again */
+ if (wlc_hw->suspended_fifos == 0)
+ return;
+ else {
+ wlc_hw->suspended_fifos &= ~(1 << tx_fifo);
+ if (wlc_hw->suspended_fifos == 0)
+ brcms_c_ucode_wake_override_clear(wlc_hw,
+ BRCMS_WAKE_OVERRIDE_TXFIFO);
+ }
+}
+
+static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool on, u32 flags)
+{
+ static const u8 null_ether_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
+
+ if (on) {
+ /* suspend tx fifos */
+ brcms_b_tx_fifo_suspend(wlc_hw, TX_DATA_FIFO);
+ brcms_b_tx_fifo_suspend(wlc_hw, TX_CTL_FIFO);
+ brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_BK_FIFO);
+ brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_VI_FIFO);
+
+ /* zero the address match register so we do not send ACKs */
+ brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET,
+ null_ether_addr);
+ } else {
+ /* resume tx fifos */
+ brcms_b_tx_fifo_resume(wlc_hw, TX_DATA_FIFO);
+ brcms_b_tx_fifo_resume(wlc_hw, TX_CTL_FIFO);
+ brcms_b_tx_fifo_resume(wlc_hw, TX_AC_BK_FIFO);
+ brcms_b_tx_fifo_resume(wlc_hw, TX_AC_VI_FIFO);
+
+ /* Restore address */
+ brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET,
+ wlc_hw->etheraddr);
+ }
+
+ wlc_phy_mute_upd(wlc_hw->band->pi, on, flags);
+
+ if (on)
+ brcms_c_ucode_mute_override_set(wlc_hw);
+ else
+ brcms_c_ucode_mute_override_clear(wlc_hw);
+}
+
+/*
+ * Read and clear macintmask and macintstatus and intstatus registers.
+ * This routine should be called with interrupts off
+ * Return:
+ * -1 if brcms_deviceremoved(wlc) evaluates to true;
+ * 0 if the interrupt is not for us, or we are in some special cases;
+ * device interrupt status bits otherwise.
+ */
+static inline u32 wlc_intstatus(struct brcms_c_info *wlc, bool in_isr)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ struct d11regs __iomem *regs = wlc_hw->regs;
+ u32 macintstatus;
+
+ /* macintstatus includes a DMA interrupt summary bit */
+ macintstatus = R_REG(&regs->macintstatus);
+
+ BCMMSG(wlc->wiphy, "wl%d: macintstatus: 0x%x\n", wlc_hw->unit,
+ macintstatus);
+
+ /* detect cardbus removed, in power down(suspend) and in reset */
+ if (brcms_deviceremoved(wlc))
+ return -1;
+
+ /* brcms_deviceremoved() succeeds even when the core is still resetting,
+ * handle that case here.
+ */
+ if (macintstatus == 0xffffffff)
+ return 0;
+
+ /* defer unsolicited interrupts */
+ macintstatus &= (in_isr ? wlc->macintmask : wlc->defmacintmask);
+
+ /* if not for us */
+ if (macintstatus == 0)
+ return 0;
+
+ /* interrupts are already turned off for CFE build
+ * Caution: For CFE Turning off the interrupts again has some undesired
+ * consequences
+ */
+ /* turn off the interrupts */
+ W_REG(&regs->macintmask, 0);
+ (void)R_REG(&regs->macintmask); /* sync readback */
+ wlc->macintmask = 0;
+
+ /* clear device interrupts */
+ W_REG(&regs->macintstatus, macintstatus);
+
+ /* MI_DMAINT is indication of non-zero intstatus */
+ if (macintstatus & MI_DMAINT)
+ /*
+ * only fifo interrupt enabled is I_RI in
+ * RX_FIFO. If MI_DMAINT is set, assume it
+ * is set and clear the interrupt.
+ */
+ W_REG(&regs->intctrlregs[RX_FIFO].intstatus,
+ DEF_RXINTMASK);
+
+ return macintstatus;
+}
+
+/* Update wlc->macintstatus and wlc->intstatus[]. */
+/* Return true if they are updated successfully. false otherwise */
+bool brcms_c_intrsupd(struct brcms_c_info *wlc)
+{
+ u32 macintstatus;
+
+ /* read and clear macintstatus and intstatus registers */
+ macintstatus = wlc_intstatus(wlc, false);
+
+ /* device is removed */
+ if (macintstatus == 0xffffffff)
+ return false;
+
+ /* update interrupt status in software */
+ wlc->macintstatus |= macintstatus;
+
+ return true;
+}
+
+/*
+ * First-level interrupt processing.
+ * Return true if this was our interrupt, false otherwise.
+ * *wantdpc will be set to true if further brcms_c_dpc() processing is required,
+ * false otherwise.
+ */
+bool brcms_c_isr(struct brcms_c_info *wlc, bool *wantdpc)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ u32 macintstatus;
+
+ *wantdpc = false;
+
+ if (!wlc_hw->up || !wlc->macintmask)
+ return false;
+
+ /* read and clear macintstatus and intstatus registers */
+ macintstatus = wlc_intstatus(wlc, true);
+
+ if (macintstatus == 0xffffffff)
+ wiphy_err(wlc->wiphy, "DEVICEREMOVED detected in the ISR code"
+ " path\n");
+
+ /* it is not for us */
+ if (macintstatus == 0)
+ return false;
+
+ *wantdpc = true;
+
+ /* save interrupt status bits */
+ wlc->macintstatus = macintstatus;
+
+ return true;
+
+}
+
+void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ struct d11regs __iomem *regs = wlc_hw->regs;
+ u32 mc, mi;
+ struct wiphy *wiphy = wlc->wiphy;
+
+ BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
+ wlc_hw->band->bandunit);
+
+ /*
+ * Track overlapping suspend requests
+ */
+ wlc_hw->mac_suspend_depth++;
+ if (wlc_hw->mac_suspend_depth > 1)
+ return;
+
+ /* force the core awake */
+ brcms_c_ucode_wake_override_set(wlc_hw, BRCMS_WAKE_OVERRIDE_MACSUSPEND);
+
+ mc = R_REG(&regs->maccontrol);
+
+ if (mc == 0xffffffff) {
+ wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
+ __func__);
+ brcms_down(wlc->wl);
+ return;
+ }
+ WARN_ON(mc & MCTL_PSM_JMP_0);
+ WARN_ON(!(mc & MCTL_PSM_RUN));
+ WARN_ON(!(mc & MCTL_EN_MAC));
+
+ mi = R_REG(&regs->macintstatus);
+ if (mi == 0xffffffff) {
+ wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
+ __func__);
+ brcms_down(wlc->wl);
+ return;
+ }
+ WARN_ON(mi & MI_MACSSPNDD);
+
+ brcms_b_mctrl(wlc_hw, MCTL_EN_MAC, 0);
+
+ SPINWAIT(!(R_REG(&regs->macintstatus) & MI_MACSSPNDD),
+ BRCMS_MAX_MAC_SUSPEND);
+
+ if (!(R_REG(&regs->macintstatus) & MI_MACSSPNDD)) {
+ wiphy_err(wiphy, "wl%d: wlc_suspend_mac_and_wait: waited %d uS"
+ " and MI_MACSSPNDD is still not on.\n",
+ wlc_hw->unit, BRCMS_MAX_MAC_SUSPEND);
+ wiphy_err(wiphy, "wl%d: psmdebug 0x%08x, phydebug 0x%08x, "
+ "psm_brc 0x%04x\n", wlc_hw->unit,
+ R_REG(&regs->psmdebug),
+ R_REG(&regs->phydebug),
+ R_REG(&regs->psm_brc));
+ }
+
+ mc = R_REG(&regs->maccontrol);
+ if (mc == 0xffffffff) {
+ wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
+ __func__);
+ brcms_down(wlc->wl);
+ return;
+ }
+ WARN_ON(mc & MCTL_PSM_JMP_0);
+ WARN_ON(!(mc & MCTL_PSM_RUN));
+ WARN_ON(mc & MCTL_EN_MAC);
+}
+
+void brcms_c_enable_mac(struct brcms_c_info *wlc)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ struct d11regs __iomem *regs = wlc_hw->regs;
+ u32 mc, mi;
+
+ BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
+ wlc->band->bandunit);
+
+ /*
+ * Track overlapping suspend requests
+ */
+ wlc_hw->mac_suspend_depth--;
+ if (wlc_hw->mac_suspend_depth > 0)
+ return;
+
+ mc = R_REG(&regs->maccontrol);
+ WARN_ON(mc & MCTL_PSM_JMP_0);
+ WARN_ON(mc & MCTL_EN_MAC);
+ WARN_ON(!(mc & MCTL_PSM_RUN));
+
+ brcms_b_mctrl(wlc_hw, MCTL_EN_MAC, MCTL_EN_MAC);
+ W_REG(&regs->macintstatus, MI_MACSSPNDD);
+
+ mc = R_REG(&regs->maccontrol);
+ WARN_ON(mc & MCTL_PSM_JMP_0);
+ WARN_ON(!(mc & MCTL_EN_MAC));
+ WARN_ON(!(mc & MCTL_PSM_RUN));
+
+ mi = R_REG(&regs->macintstatus);
+ WARN_ON(mi & MI_MACSSPNDD);
+
+ brcms_c_ucode_wake_override_clear(wlc_hw,
+ BRCMS_WAKE_OVERRIDE_MACSUSPEND);
+}
+
+void brcms_b_band_stf_ss_set(struct brcms_hardware *wlc_hw, u8 stf_mode)
+{
+ wlc_hw->hw_stf_ss_opmode = stf_mode;
+
+ if (wlc_hw->clk)
+ brcms_upd_ofdm_pctl1_table(wlc_hw);
+}
+
+static bool brcms_b_validate_chip_access(struct brcms_hardware *wlc_hw)
+{
+ struct d11regs __iomem *regs;
+ u32 w, val;
+ struct wiphy *wiphy = wlc_hw->wlc->wiphy;
+
+ BCMMSG(wiphy, "wl%d\n", wlc_hw->unit);
+
+ regs = wlc_hw->regs;
+
+ /* Validate dchip register access */
+
+ W_REG(&regs->objaddr, OBJADDR_SHM_SEL | 0);
+ (void)R_REG(&regs->objaddr);
+ w = R_REG(&regs->objdata);
+
+ /* Can we write and read back a 32bit register? */
+ W_REG(&regs->objaddr, OBJADDR_SHM_SEL | 0);
+ (void)R_REG(&regs->objaddr);
+ W_REG(&regs->objdata, (u32) 0xaa5555aa);
+
+ W_REG(&regs->objaddr, OBJADDR_SHM_SEL | 0);
+ (void)R_REG(&regs->objaddr);
+ val = R_REG(&regs->objdata);
+ if (val != (u32) 0xaa5555aa) {
+ wiphy_err(wiphy, "wl%d: validate_chip_access: SHM = 0x%x, "
+ "expected 0xaa5555aa\n", wlc_hw->unit, val);
+ return false;
+ }
+
+ W_REG(&regs->objaddr, OBJADDR_SHM_SEL | 0);
+ (void)R_REG(&regs->objaddr);
+ W_REG(&regs->objdata, (u32) 0x55aaaa55);
+
+ W_REG(&regs->objaddr, OBJADDR_SHM_SEL | 0);
+ (void)R_REG(&regs->objaddr);
+ val = R_REG(&regs->objdata);
+ if (val != (u32) 0x55aaaa55) {
+ wiphy_err(wiphy, "wl%d: validate_chip_access: SHM = 0x%x, "
+ "expected 0x55aaaa55\n", wlc_hw->unit, val);
+ return false;
+ }
+
+ W_REG(&regs->objaddr, OBJADDR_SHM_SEL | 0);
+ (void)R_REG(&regs->objaddr);
+ W_REG(&regs->objdata, w);
+
+ /* clear CFPStart */
+ W_REG(&regs->tsf_cfpstart, 0);
+
+ w = R_REG(&regs->maccontrol);
+ if ((w != (MCTL_IHR_EN | MCTL_WAKE)) &&
+ (w != (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE))) {
+ wiphy_err(wiphy, "wl%d: validate_chip_access: maccontrol = "
+ "0x%x, expected 0x%x or 0x%x\n", wlc_hw->unit, w,
+ (MCTL_IHR_EN | MCTL_WAKE),
+ (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE));
+ return false;
+ }
+
+ return true;
+}
+
+#define PHYPLL_WAIT_US 100000
+
+void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on)
+{
+ struct d11regs __iomem *regs;
+ u32 tmp;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ tmp = 0;
+ regs = wlc_hw->regs;
+
+ if (on) {
+ if ((wlc_hw->sih->chip == BCM4313_CHIP_ID)) {
+ OR_REG(&regs->clk_ctl_st,
+ (CCS_ERSRC_REQ_HT | CCS_ERSRC_REQ_D11PLL |
+ CCS_ERSRC_REQ_PHYPLL));
+ SPINWAIT((R_REG(&regs->clk_ctl_st) &
+ (CCS_ERSRC_AVAIL_HT)) != (CCS_ERSRC_AVAIL_HT),
+ PHYPLL_WAIT_US);
+
+ tmp = R_REG(&regs->clk_ctl_st);
+ if ((tmp & (CCS_ERSRC_AVAIL_HT)) !=
+ (CCS_ERSRC_AVAIL_HT))
+ wiphy_err(wlc_hw->wlc->wiphy, "%s: turn on PHY"
+ " PLL failed\n", __func__);
+ } else {
+ OR_REG(&regs->clk_ctl_st,
+ (CCS_ERSRC_REQ_D11PLL | CCS_ERSRC_REQ_PHYPLL));
+ SPINWAIT((R_REG(&regs->clk_ctl_st) &
+ (CCS_ERSRC_AVAIL_D11PLL |
+ CCS_ERSRC_AVAIL_PHYPLL)) !=
+ (CCS_ERSRC_AVAIL_D11PLL |
+ CCS_ERSRC_AVAIL_PHYPLL), PHYPLL_WAIT_US);
+
+ tmp = R_REG(&regs->clk_ctl_st);
+ if ((tmp &
+ (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL))
+ !=
+ (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL))
+ wiphy_err(wlc_hw->wlc->wiphy, "%s: turn on "
+ "PHY PLL failed\n", __func__);
+ }
+ } else {
+ /*
+ * Since the PLL may be shared, other cores can still
+ * be requesting it; so we'll deassert the request but
+ * not wait for status to comply.
+ */
+ AND_REG(&regs->clk_ctl_st, ~CCS_ERSRC_REQ_PHYPLL);
+ tmp = R_REG(&regs->clk_ctl_st);
+ }
+}
+
+static void brcms_c_coredisable(struct brcms_hardware *wlc_hw)
+{
+ bool dev_gone;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ dev_gone = brcms_deviceremoved(wlc_hw->wlc);
+
+ if (dev_gone)
+ return;
+
+ if (wlc_hw->noreset)
+ return;
+
+ /* radio off */
+ wlc_phy_switch_radio(wlc_hw->band->pi, OFF);
+
+ /* turn off analog core */
+ wlc_phy_anacore(wlc_hw->band->pi, OFF);
+
+ /* turn off PHYPLL to save power */
+ brcms_b_core_phypll_ctl(wlc_hw, false);
+
+ wlc_hw->clk = false;
+ ai_core_disable(wlc_hw->sih, 0);
+ wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
+}
+
+static void brcms_c_flushqueues(struct brcms_c_info *wlc)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ uint i;
+
+ /* free any posted tx packets */
+ for (i = 0; i < NFIFO; i++)
+ if (wlc_hw->di[i]) {
+ dma_txreclaim(wlc_hw->di[i], DMA_RANGE_ALL);
+ wlc->core->txpktpend[i] = 0;
+ BCMMSG(wlc->wiphy, "pktpend fifo %d clrd\n", i);
+ }
+
+ /* free any posted rx packets */
+ dma_rxreclaim(wlc_hw->di[RX_FIFO]);
+}
+
+static u16
+brcms_b_read_objmem(struct brcms_hardware *wlc_hw, uint offset, u32 sel)
+{
+ struct d11regs __iomem *regs = wlc_hw->regs;
+ u16 __iomem *objdata_lo = (u16 __iomem *)&regs->objdata;
+ u16 __iomem *objdata_hi = objdata_lo + 1;
+ u16 v;
+
+ W_REG(&regs->objaddr, sel | (offset >> 2));
+ (void)R_REG(&regs->objaddr);
+ if (offset & 2)
+ v = R_REG(objdata_hi);
+ else
+ v = R_REG(objdata_lo);
+
+ return v;
+}
+
+static void
+brcms_b_write_objmem(struct brcms_hardware *wlc_hw, uint offset, u16 v,
+ u32 sel)
+{
+ struct d11regs __iomem *regs = wlc_hw->regs;
+ u16 __iomem *objdata_lo = (u16 __iomem *)&regs->objdata;
+ u16 __iomem *objdata_hi = objdata_lo + 1;
+
+ W_REG(&regs->objaddr, sel | (offset >> 2));
+ (void)R_REG(&regs->objaddr);
+ if (offset & 2)
+ W_REG(objdata_hi, v);
+ else
+ W_REG(objdata_lo, v);
+}
+
+/*
+ * Read a single u16 from shared memory.
+ * SHM 'offset' needs to be an even address
+ */
+u16 brcms_b_read_shm(struct brcms_hardware *wlc_hw, uint offset)
+{
+ return brcms_b_read_objmem(wlc_hw, offset, OBJADDR_SHM_SEL);
+}
+
+/*
+ * Write a single u16 to shared memory.
+ * SHM 'offset' needs to be an even address
+ */
+void brcms_b_write_shm(struct brcms_hardware *wlc_hw, uint offset, u16 v)
+{
+ brcms_b_write_objmem(wlc_hw, offset, v, OBJADDR_SHM_SEL);
+}
+
+/*
+ * Copy a buffer to shared memory of specified type .
+ * SHM 'offset' needs to be an even address and
+ * Buffer length 'len' must be an even number of bytes
+ * 'sel' selects the type of memory
+ */
+void
+brcms_b_copyto_objmem(struct brcms_hardware *wlc_hw, uint offset,
+ const void *buf, int len, u32 sel)
+{
+ u16 v;
+ const u8 *p = (const u8 *)buf;
+ int i;
+
+ if (len <= 0 || (offset & 1) || (len & 1))
+ return;
+
+ for (i = 0; i < len; i += 2) {
+ v = p[i] | (p[i + 1] << 8);
+ brcms_b_write_objmem(wlc_hw, offset + i, v, sel);
+ }
+}
+
+/*
+ * Copy a piece of shared memory of specified type to a buffer .
+ * SHM 'offset' needs to be an even address and
+ * Buffer length 'len' must be an even number of bytes
+ * 'sel' selects the type of memory
+ */
+void
+brcms_b_copyfrom_objmem(struct brcms_hardware *wlc_hw, uint offset, void *buf,
+ int len, u32 sel)
+{
+ u16 v;
+ u8 *p = (u8 *) buf;
+ int i;
+
+ if (len <= 0 || (offset & 1) || (len & 1))
+ return;
+
+ for (i = 0; i < len; i += 2) {
+ v = brcms_b_read_objmem(wlc_hw, offset + i, sel);
+ p[i] = v & 0xFF;
+ p[i + 1] = (v >> 8) & 0xFF;
+ }
+}
+
+/* Copy a buffer to shared memory.
+ * SHM 'offset' needs to be an even address and
+ * Buffer length 'len' must be an even number of bytes
+ */
+static void brcms_c_copyto_shm(struct brcms_c_info *wlc, uint offset,
+ const void *buf, int len)
+{
+ brcms_b_copyto_objmem(wlc->hw, offset, buf, len, OBJADDR_SHM_SEL);
+}
+
+static void brcms_b_retrylimit_upd(struct brcms_hardware *wlc_hw,
+ u16 SRL, u16 LRL)
+{
+ wlc_hw->SRL = SRL;
+ wlc_hw->LRL = LRL;
+
+ /* write retry limit to SCR, shouldn't need to suspend */
+ if (wlc_hw->up) {
+ W_REG(&wlc_hw->regs->objaddr,
+ OBJADDR_SCR_SEL | S_DOT11_SRC_LMT);
+ (void)R_REG(&wlc_hw->regs->objaddr);
+ W_REG(&wlc_hw->regs->objdata, wlc_hw->SRL);
+ W_REG(&wlc_hw->regs->objaddr,
+ OBJADDR_SCR_SEL | S_DOT11_LRC_LMT);
+ (void)R_REG(&wlc_hw->regs->objaddr);
+ W_REG(&wlc_hw->regs->objdata, wlc_hw->LRL);
+ }
+}
+
+static void brcms_b_pllreq(struct brcms_hardware *wlc_hw, bool set, u32 req_bit)
+{
+ if (set) {
+ if (mboolisset(wlc_hw->pllreq, req_bit))
+ return;
+
+ mboolset(wlc_hw->pllreq, req_bit);
+
+ if (mboolisset(wlc_hw->pllreq, BRCMS_PLLREQ_FLIP)) {
+ if (!wlc_hw->sbclk)
+ brcms_b_xtal(wlc_hw, ON);
+ }
+ } else {
+ if (!mboolisset(wlc_hw->pllreq, req_bit))
+ return;
+
+ mboolclr(wlc_hw->pllreq, req_bit);
+
+ if (mboolisset(wlc_hw->pllreq, BRCMS_PLLREQ_FLIP)) {
+ if (wlc_hw->sbclk)
+ brcms_b_xtal(wlc_hw, OFF);
+ }
+ }
+}
+
+static void brcms_b_antsel_set(struct brcms_hardware *wlc_hw, u32 antsel_avail)
+{
+ wlc_hw->antsel_avail = antsel_avail;
+}
+
+/*
+ * conditions under which the PM bit should be set in outgoing frames
+ * and STAY_AWAKE is meaningful
+ */
+static bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
+{
+ struct brcms_bss_cfg *cfg = wlc->bsscfg;
+
+ /* disallow PS when one of the following global conditions meets */
+ if (!wlc->pub->associated)
+ return false;
+
+ /* disallow PS when one of these meets when not scanning */
+ if (wlc->monitor)
+ return false;
+
+ if (cfg->associated) {
+ /*
+ * disallow PS when one of the following
+ * bsscfg specific conditions meets
+ */
+ if (!cfg->BSS)
+ return false;
+
+ return false;
+ }
+
+ return true;
+}
+
+static void brcms_c_statsupd(struct brcms_c_info *wlc)
+{
+ int i;
+ struct macstat macstats;
+#ifdef BCMDBG
+ u16 delta;
+ u16 rxf0ovfl;
+ u16 txfunfl[NFIFO];
+#endif /* BCMDBG */
+
+ /* if driver down, make no sense to update stats */
+ if (!wlc->pub->up)
+ return;
+
+#ifdef BCMDBG
+ /* save last rx fifo 0 overflow count */
+ rxf0ovfl = wlc->core->macstat_snapshot->rxf0ovfl;
+
+ /* save last tx fifo underflow count */
+ for (i = 0; i < NFIFO; i++)
+ txfunfl[i] = wlc->core->macstat_snapshot->txfunfl[i];
+#endif /* BCMDBG */
+
+ /* Read mac stats from contiguous shared memory */
+ brcms_b_copyfrom_objmem(wlc->hw, M_UCODE_MACSTAT, &macstats,
+ sizeof(struct macstat), OBJADDR_SHM_SEL);
+
+#ifdef BCMDBG
+ /* check for rx fifo 0 overflow */
+ delta = (u16) (wlc->core->macstat_snapshot->rxf0ovfl - rxf0ovfl);
+ if (delta)
+ wiphy_err(wlc->wiphy, "wl%d: %u rx fifo 0 overflows!\n",
+ wlc->pub->unit, delta);
+
+ /* check for tx fifo underflows */
+ for (i = 0; i < NFIFO; i++) {
+ delta =
+ (u16) (wlc->core->macstat_snapshot->txfunfl[i] -
+ txfunfl[i]);
+ if (delta)
+ wiphy_err(wlc->wiphy, "wl%d: %u tx fifo %d underflows!"
+ "\n", wlc->pub->unit, delta, i);
+ }
+#endif /* BCMDBG */
+
+ /* merge counters from dma module */
+ for (i = 0; i < NFIFO; i++) {
+ if (wlc->hw->di[i])
+ dma_counterreset(wlc->hw->di[i]);
+ }
+}
+
+static void brcms_b_reset(struct brcms_hardware *wlc_hw)
+{
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ /* reset the core */
+ if (!brcms_deviceremoved(wlc_hw->wlc))
+ brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
+
+ /* purge the dma rings */
+ brcms_c_flushqueues(wlc_hw->wlc);
+}
+
+void brcms_c_reset(struct brcms_c_info *wlc)
+{
+ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+
+ /* slurp up hw mac counters before core reset */
+ brcms_c_statsupd(wlc);
+
+ /* reset our snapshot of macstat counters */
+ memset((char *)wlc->core->macstat_snapshot, 0,
+ sizeof(struct macstat));
+
+ brcms_b_reset(wlc->hw);
+}
+
+/* Return the channel the driver should initialize during brcms_c_init.
+ * the channel may have to be changed from the currently configured channel
+ * if other configurations are in conflict (bandlocked, 11n mode disabled,
+ * invalid channel for current country, etc.)
+ */
+static u16 brcms_c_init_chanspec(struct brcms_c_info *wlc)
+{
+ u16 chanspec =
+ 1 | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE |
+ WL_CHANSPEC_BAND_2G;
+
+ return chanspec;
+}
+
+void brcms_c_init_scb(struct scb *scb)
+{
+ int i;
+
+ memset(scb, 0, sizeof(struct scb));
+ scb->flags = SCB_WMECAP | SCB_HTCAP;
+ for (i = 0; i < NUMPRIO; i++) {
+ scb->seqnum[i] = 0;
+ scb->seqctl[i] = 0xFFFF;
+ }
+
+ scb->seqctl_nonqos = 0xFFFF;
+ scb->magic = SCB_MAGIC;
+}
+
+/* d11 core init
+ * reset PSM
+ * download ucode/PCM
+ * let ucode run to suspended
+ * download ucode inits
+ * config other core registers
+ * init dma
+ */
+static void brcms_b_coreinit(struct brcms_c_info *wlc)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ struct d11regs __iomem *regs;
+ u32 sflags;
+ uint bcnint_us;
+ uint i = 0;
+ bool fifosz_fixup = false;
+ int err = 0;
+ u16 buf[NFIFO];
+ struct wiphy *wiphy = wlc->wiphy;
+ struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode;
+
+ regs = wlc_hw->regs;
+
+ BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ /* reset PSM */
+ brcms_b_mctrl(wlc_hw, ~0, (MCTL_IHR_EN | MCTL_PSM_JMP_0 | MCTL_WAKE));
+
+ brcms_ucode_download(wlc_hw);
+ /*
+ * FIFOSZ fixup. driver wants to controls the fifo allocation.
+ */
+ fifosz_fixup = true;
+
+ /* let the PSM run to the suspended state, set mode to BSS STA */
+ W_REG(&regs->macintstatus, -1);
+ brcms_b_mctrl(wlc_hw, ~0,
+ (MCTL_IHR_EN | MCTL_INFRA | MCTL_PSM_RUN | MCTL_WAKE));
+
+ /* wait for ucode to self-suspend after auto-init */
+ SPINWAIT(((R_REG(&regs->macintstatus) & MI_MACSSPNDD) == 0),
+ 1000 * 1000);
+ if ((R_REG(&regs->macintstatus) & MI_MACSSPNDD) == 0)
+ wiphy_err(wiphy, "wl%d: wlc_coreinit: ucode did not self-"
+ "suspend!\n", wlc_hw->unit);
+
+ brcms_c_gpio_init(wlc);
+
+ sflags = ai_core_sflags(wlc_hw->sih, 0, 0);
+
+ if (D11REV_IS(wlc_hw->corerev, 23)) {
+ if (BRCMS_ISNPHY(wlc_hw->band))
+ brcms_c_write_inits(wlc_hw, ucode->d11n0initvals16);
+ else
+ wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev"
+ " %d\n", __func__, wlc_hw->unit,
+ wlc_hw->corerev);
+ } else if (D11REV_IS(wlc_hw->corerev, 24)) {
+ if (BRCMS_ISLCNPHY(wlc_hw->band))
+ brcms_c_write_inits(wlc_hw, ucode->d11lcn0initvals24);
+ else
+ wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev"
+ " %d\n", __func__, wlc_hw->unit,
+ wlc_hw->corerev);
+ } else {
+ wiphy_err(wiphy, "%s: wl%d: unsupported corerev %d\n",
+ __func__, wlc_hw->unit, wlc_hw->corerev);
+ }
+
+ /* For old ucode, txfifo sizes needs to be modified(increased) */
+ if (fifosz_fixup == true)
+ brcms_b_corerev_fifofixup(wlc_hw);
+
+ /* check txfifo allocations match between ucode and driver */
+ buf[TX_AC_BE_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE0);
+ if (buf[TX_AC_BE_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]) {
+ i = TX_AC_BE_FIFO;
+ err = -1;
+ }
+ buf[TX_AC_VI_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE1);
+ if (buf[TX_AC_VI_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]) {
+ i = TX_AC_VI_FIFO;
+ err = -1;
+ }
+ buf[TX_AC_BK_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE2);
+ buf[TX_AC_VO_FIFO] = (buf[TX_AC_BK_FIFO] >> 8) & 0xff;
+ buf[TX_AC_BK_FIFO] &= 0xff;
+ if (buf[TX_AC_BK_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BK_FIFO]) {
+ i = TX_AC_BK_FIFO;
+ err = -1;
+ }
+ if (buf[TX_AC_VO_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO]) {
+ i = TX_AC_VO_FIFO;
+ err = -1;
+ }
+ buf[TX_BCMC_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE3);
+ buf[TX_ATIM_FIFO] = (buf[TX_BCMC_FIFO] >> 8) & 0xff;
+ buf[TX_BCMC_FIFO] &= 0xff;
+ if (buf[TX_BCMC_FIFO] != wlc_hw->xmtfifo_sz[TX_BCMC_FIFO]) {
+ i = TX_BCMC_FIFO;
+ err = -1;
+ }
+ if (buf[TX_ATIM_FIFO] != wlc_hw->xmtfifo_sz[TX_ATIM_FIFO]) {
+ i = TX_ATIM_FIFO;
+ err = -1;
+ }
+ if (err != 0)
+ wiphy_err(wiphy, "wlc_coreinit: txfifo mismatch: ucode size %d"
+ " driver size %d index %d\n", buf[i],
+ wlc_hw->xmtfifo_sz[i], i);
+
+ /* make sure we can still talk to the mac */
+ WARN_ON(R_REG(&regs->maccontrol) == 0xffffffff);
+
+ /* band-specific inits done by wlc_bsinit() */
+
+ /* Set up frame burst size and antenna swap threshold init values */
+ brcms_b_write_shm(wlc_hw, M_MBURST_SIZE, MAXTXFRAMEBURST);
+ brcms_b_write_shm(wlc_hw, M_MAX_ANTCNT, ANTCNT);
+
+ /* enable one rx interrupt per received frame */
+ W_REG(&regs->intrcvlazy[0], (1 << IRL_FC_SHIFT));
+
+ /* set the station mode (BSS STA) */
+ brcms_b_mctrl(wlc_hw,
+ (MCTL_INFRA | MCTL_DISCARD_PMQ | MCTL_AP),
+ (MCTL_INFRA | MCTL_DISCARD_PMQ));
+
+ /* set up Beacon interval */
+ bcnint_us = 0x8000 << 10;
+ W_REG(&regs->tsf_cfprep, (bcnint_us << CFPREP_CBI_SHIFT));
+ W_REG(&regs->tsf_cfpstart, bcnint_us);
+ W_REG(&regs->macintstatus, MI_GP1);
+
+ /* write interrupt mask */
+ W_REG(&regs->intctrlregs[RX_FIFO].intmask, DEF_RXINTMASK);
+
+ /* allow the MAC to control the PHY clock (dynamic on/off) */
+ brcms_b_macphyclk_set(wlc_hw, ON);
+
+ /* program dynamic clock control fast powerup delay register */
+ wlc->fastpwrup_dly = ai_clkctl_fast_pwrup_delay(wlc_hw->sih);
+ W_REG(&regs->scc_fastpwrup_dly, wlc->fastpwrup_dly);
+
+ /* tell the ucode the corerev */
+ brcms_b_write_shm(wlc_hw, M_MACHW_VER, (u16) wlc_hw->corerev);
+
+ /* tell the ucode MAC capabilities */
+ brcms_b_write_shm(wlc_hw, M_MACHW_CAP_L,
+ (u16) (wlc_hw->machwcap & 0xffff));
+ brcms_b_write_shm(wlc_hw, M_MACHW_CAP_H,
+ (u16) ((wlc_hw->
+ machwcap >> 16) & 0xffff));
+
+ /* write retry limits to SCR, this done after PSM init */
+ W_REG(&regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_SRC_LMT);
+ (void)R_REG(&regs->objaddr);
+ W_REG(&regs->objdata, wlc_hw->SRL);
+ W_REG(&regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_LRC_LMT);
+ (void)R_REG(&regs->objaddr);
+ W_REG(&regs->objdata, wlc_hw->LRL);
+
+ /* write rate fallback retry limits */
+ brcms_b_write_shm(wlc_hw, M_SFRMTXCNTFBRTHSD, wlc_hw->SFBL);
+ brcms_b_write_shm(wlc_hw, M_LFRMTXCNTFBRTHSD, wlc_hw->LFBL);
+
+ AND_REG(&regs->ifs_ctl, 0x0FFF);
+ W_REG(&regs->ifs_aifsn, EDCF_AIFSN_MIN);
+
+ /* init the tx dma engines */
+ for (i = 0; i < NFIFO; i++) {
+ if (wlc_hw->di[i])
+ dma_txinit(wlc_hw->di[i]);
+ }
+
+ /* init the rx dma engine(s) and post receive buffers */
+ dma_rxinit(wlc_hw->di[RX_FIFO]);
+ dma_rxfill(wlc_hw->di[RX_FIFO]);
+}
+
+void
+static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec,
+ bool mute) {
+ u32 macintmask;
+ bool fastclk;
+ struct brcms_c_info *wlc = wlc_hw->wlc;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ /* request FAST clock if not on */
+ fastclk = wlc_hw->forcefastclk;
+ if (!fastclk)
+ brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
+
+ /* disable interrupts */
+ macintmask = brcms_intrsoff(wlc->wl);
+
+ /* set up the specified band and chanspec */
+ brcms_c_setxband(wlc_hw, chspec_bandunit(chanspec));
+ wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec);
+
+ /* do one-time phy inits and calibration */
+ wlc_phy_cal_init(wlc_hw->band->pi);
+
+ /* core-specific initialization */
+ brcms_b_coreinit(wlc);
+
+ /* suspend the tx fifos and mute the phy for preism cac time */
+ if (mute)
+ brcms_b_mute(wlc_hw, ON, PHY_MUTE_FOR_PREISM);
+
+ /* band-specific inits */
+ brcms_b_bsinit(wlc, chanspec);
+
+ /* restore macintmask */
+ brcms_intrsrestore(wlc->wl, macintmask);
+
+ /* seed wake_override with BRCMS_WAKE_OVERRIDE_MACSUSPEND since the mac
+ * is suspended and brcms_c_enable_mac() will clear this override bit.
+ */
+ mboolset(wlc_hw->wake_override, BRCMS_WAKE_OVERRIDE_MACSUSPEND);
+
+ /*
+ * initialize mac_suspend_depth to 1 to match ucode
+ * initial suspended state
+ */
+ wlc_hw->mac_suspend_depth = 1;
+
+ /* restore the clk */
+ if (!fastclk)
+ brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
+}
+
+static void brcms_c_set_phy_chanspec(struct brcms_c_info *wlc,
+ u16 chanspec)
+{
+ /* Save our copy of the chanspec */
+ wlc->chanspec = chanspec;
+
+ /* Set the chanspec and power limits for this locale */
+ brcms_c_channel_set_chanspec(wlc->cmi, chanspec, BRCMS_TXPWR_MAX);
+
+ if (wlc->stf->ss_algosel_auto)
+ brcms_c_stf_ss_algo_channel_get(wlc, &wlc->stf->ss_algo_channel,
+ chanspec);
+
+ brcms_c_stf_ss_update(wlc, wlc->band);
+}
+
+static void
+brcms_default_rateset(struct brcms_c_info *wlc, struct brcms_c_rateset *rs)
+{
+ brcms_c_rateset_default(rs, NULL, wlc->band->phytype,
+ wlc->band->bandtype, false, BRCMS_RATE_MASK_FULL,
+ (bool) (wlc->pub->_n_enab & SUPPORT_11N),
+ brcms_chspec_bw(wlc->default_bss->chanspec),
+ wlc->stf->txstreams);
+}
+
+/* derive wlc->band->basic_rate[] table from 'rateset' */
+static void brcms_c_rate_lookup_init(struct brcms_c_info *wlc,
+ struct brcms_c_rateset *rateset)
+{
+ u8 rate;
+ u8 mandatory;
+ u8 cck_basic = 0;
+ u8 ofdm_basic = 0;
+ u8 *br = wlc->band->basic_rate;
+ uint i;
+
+ /* incoming rates are in 500kbps units as in 802.11 Supported Rates */
+ memset(br, 0, BRCM_MAXRATE + 1);
+
+ /* For each basic rate in the rates list, make an entry in the
+ * best basic lookup.
+ */
+ for (i = 0; i < rateset->count; i++) {
+ /* only make an entry for a basic rate */
+ if (!(rateset->rates[i] & BRCMS_RATE_FLAG))
+ continue;
+
+ /* mask off basic bit */
+ rate = (rateset->rates[i] & BRCMS_RATE_MASK);
+
+ if (rate > BRCM_MAXRATE) {
+ wiphy_err(wlc->wiphy, "brcms_c_rate_lookup_init: "
+ "invalid rate 0x%X in rate set\n",
+ rateset->rates[i]);
+ continue;
+ }
+
+ br[rate] = rate;
+ }
+
+ /* The rate lookup table now has non-zero entries for each
+ * basic rate, equal to the basic rate: br[basicN] = basicN
+ *
+ * To look up the best basic rate corresponding to any
+ * particular rate, code can use the basic_rate table
+ * like this
+ *
+ * basic_rate = wlc->band->basic_rate[tx_rate]
+ *
+ * Make sure there is a best basic rate entry for
+ * every rate by walking up the table from low rates
+ * to high, filling in holes in the lookup table
+ */
+
+ for (i = 0; i < wlc->band->hw_rateset.count; i++) {
+ rate = wlc->band->hw_rateset.rates[i];
+
+ if (br[rate] != 0) {
+ /* This rate is a basic rate.
+ * Keep track of the best basic rate so far by
+ * modulation type.
+ */
+ if (is_ofdm_rate(rate))
+ ofdm_basic = rate;
+ else
+ cck_basic = rate;
+
+ continue;
+ }
+
+ /* This rate is not a basic rate so figure out the
+ * best basic rate less than this rate and fill in
+ * the hole in the table
+ */
+
+ br[rate] = is_ofdm_rate(rate) ? ofdm_basic : cck_basic;
+
+ if (br[rate] != 0)
+ continue;
+
+ if (is_ofdm_rate(rate)) {
+ /*
+ * In 11g and 11a, the OFDM mandatory rates
+ * are 6, 12, and 24 Mbps
+ */
+ if (rate >= BRCM_RATE_24M)
+ mandatory = BRCM_RATE_24M;
+ else if (rate >= BRCM_RATE_12M)
+ mandatory = BRCM_RATE_12M;
+ else
+ mandatory = BRCM_RATE_6M;
+ } else {
+ /* In 11b, all CCK rates are mandatory 1 - 11 Mbps */
+ mandatory = rate;
+ }
+
+ br[rate] = mandatory;
+ }
+}
+
+static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc,
+ u16 chanspec)
+{
+ struct brcms_c_rateset default_rateset;
+ uint parkband;
+ uint i, band_order[2];
+
+ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+ /*
+ * We might have been bandlocked during down and the chip
+ * power-cycled (hibernate). Figure out the right band to park on
+ */
+ if (wlc->bandlocked || wlc->pub->_nbands == 1) {
+ /* updated in brcms_c_bandlock() */
+ parkband = wlc->band->bandunit;
+ band_order[0] = band_order[1] = parkband;
+ } else {
+ /* park on the band of the specified chanspec */
+ parkband = chspec_bandunit(chanspec);
+
+ /* order so that parkband initialize last */
+ band_order[0] = parkband ^ 1;
+ band_order[1] = parkband;
+ }
+
+ /* make each band operational, software state init */
+ for (i = 0; i < wlc->pub->_nbands; i++) {
+ uint j = band_order[i];
+
+ wlc->band = wlc->bandstate[j];
+
+ brcms_default_rateset(wlc, &default_rateset);
+
+ /* fill in hw_rate */
+ brcms_c_rateset_filter(&default_rateset, &wlc->band->hw_rateset,
+ false, BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK,
+ (bool) (wlc->pub->_n_enab & SUPPORT_11N));
+
+ /* init basic rate lookup */
+ brcms_c_rate_lookup_init(wlc, &default_rateset);
+ }
+
+ /* sync up phy/radio chanspec */
+ brcms_c_set_phy_chanspec(wlc, chanspec);
+}
+
+static void brcms_c_mac_bcn_promisc(struct brcms_c_info *wlc)
+{
+ if (wlc->bcnmisc_monitor)
+ brcms_b_mctrl(wlc->hw, MCTL_BCNS_PROMISC, MCTL_BCNS_PROMISC);
+ else
+ brcms_b_mctrl(wlc->hw, MCTL_BCNS_PROMISC, 0);
+}
+
+void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, bool promisc)
+{
+ wlc->bcnmisc_monitor = promisc;
+ brcms_c_mac_bcn_promisc(wlc);
+}
+
+/* set or clear maccontrol bits MCTL_PROMISC and MCTL_KEEPCONTROL */
+static void brcms_c_mac_promisc(struct brcms_c_info *wlc)
+{
+ u32 promisc_bits = 0;
+
+ /*
+ * promiscuous mode just sets MCTL_PROMISC
+ * Note: APs get all BSS traffic without the need to set
+ * the MCTL_PROMISC bit since all BSS data traffic is
+ * directed at the AP
+ */
+ if (wlc->pub->promisc)
+ promisc_bits |= MCTL_PROMISC;
+
+ /* monitor mode needs both MCTL_PROMISC and MCTL_KEEPCONTROL
+ * Note: monitor mode also needs MCTL_BCNS_PROMISC, but that is
+ * handled in brcms_c_mac_bcn_promisc()
+ */
+ if (wlc->monitor)
+ promisc_bits |= MCTL_PROMISC | MCTL_KEEPCONTROL;
+
+ brcms_b_mctrl(wlc->hw, MCTL_PROMISC | MCTL_KEEPCONTROL, promisc_bits);
+}
+
+/*
+ * ucode, hwmac update
+ * Channel dependent updates for ucode and hw
+ */
+static void brcms_c_ucode_mac_upd(struct brcms_c_info *wlc)
+{
+ /* enable or disable any active IBSSs depending on whether or not
+ * we are on the home channel
+ */
+ if (wlc->home_chanspec == wlc_phy_chanspec_get(wlc->band->pi)) {
+ if (wlc->pub->associated) {
+ /*
+ * BMAC_NOTE: This is something that should be fixed
+ * in ucode inits. I think that the ucode inits set
+ * up the bcn templates and shm values with a bogus
+ * beacon. This should not be done in the inits. If
+ * ucode needs to set up a beacon for testing, the
+ * test routines should write it down, not expect the
+ * inits to populate a bogus beacon.
+ */
+ if (BRCMS_PHY_11N_CAP(wlc->band))
+ brcms_b_write_shm(wlc->hw,
+ M_BCN_TXTSF_OFFSET, 0);
+ }
+ } else {
+ /* disable an active IBSS if we are not on the home channel */
+ }
+
+ /* update the various promisc bits */
+ brcms_c_mac_bcn_promisc(wlc);
+ brcms_c_mac_promisc(wlc);
+}
+
+static void brcms_c_write_rate_shm(struct brcms_c_info *wlc, u8 rate,
+ u8 basic_rate)
+{
+ u8 phy_rate, index;
+ u8 basic_phy_rate, basic_index;
+ u16 dir_table, basic_table;
+ u16 basic_ptr;
+
+ /* Shared memory address for the table we are reading */
+ dir_table = is_ofdm_rate(basic_rate) ? M_RT_DIRMAP_A : M_RT_DIRMAP_B;
+
+ /* Shared memory address for the table we are writing */
+ basic_table = is_ofdm_rate(rate) ? M_RT_BBRSMAP_A : M_RT_BBRSMAP_B;
+
+ /*
+ * for a given rate, the LS-nibble of the PLCP SIGNAL field is
+ * the index into the rate table.
+ */
+ phy_rate = rate_info[rate] & BRCMS_RATE_MASK;
+ basic_phy_rate = rate_info[basic_rate] & BRCMS_RATE_MASK;
+ index = phy_rate & 0xf;
+ basic_index = basic_phy_rate & 0xf;
+
+ /* Find the SHM pointer to the ACK rate entry by looking in the
+ * Direct-map Table
+ */
+ basic_ptr = brcms_b_read_shm(wlc->hw, (dir_table + basic_index * 2));
+
+ /* Update the SHM BSS-basic-rate-set mapping table with the pointer
+ * to the correct basic rate for the given incoming rate
+ */
+ brcms_b_write_shm(wlc->hw, (basic_table + index * 2), basic_ptr);
+}
+
+static const struct brcms_c_rateset *
+brcms_c_rateset_get_hwrs(struct brcms_c_info *wlc)
+{
+ const struct brcms_c_rateset *rs_dflt;
+
+ if (BRCMS_PHY_11N_CAP(wlc->band)) {
+ if (wlc->band->bandtype == BRCM_BAND_5G)
+ rs_dflt = &ofdm_mimo_rates;
+ else
+ rs_dflt = &cck_ofdm_mimo_rates;
+ } else if (wlc->band->gmode)
+ rs_dflt = &cck_ofdm_rates;
+ else
+ rs_dflt = &cck_rates;
+
+ return rs_dflt;
+}
+
+static void brcms_c_set_ratetable(struct brcms_c_info *wlc)
+{
+ const struct brcms_c_rateset *rs_dflt;
+ struct brcms_c_rateset rs;
+ u8 rate, basic_rate;
+ uint i;
+
+ rs_dflt = brcms_c_rateset_get_hwrs(wlc);
+
+ brcms_c_rateset_copy(rs_dflt, &rs);
+ brcms_c_rateset_mcs_upd(&rs, wlc->stf->txstreams);
+
+ /* walk the phy rate table and update SHM basic rate lookup table */
+ for (i = 0; i < rs.count; i++) {
+ rate = rs.rates[i] & BRCMS_RATE_MASK;
+
+ /* for a given rate brcms_basic_rate returns the rate at
+ * which a response ACK/CTS should be sent.
+ */
+ basic_rate = brcms_basic_rate(wlc, rate);
+ if (basic_rate == 0)
+ /* This should only happen if we are using a
+ * restricted rateset.
+ */
+ basic_rate = rs.rates[0] & BRCMS_RATE_MASK;
+
+ brcms_c_write_rate_shm(wlc, rate, basic_rate);
+ }
+}
+
+/* band-specific init */
+static void brcms_c_bsinit(struct brcms_c_info *wlc)
+{
+ BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n",
+ wlc->pub->unit, wlc->band->bandunit);
+
+ /* write ucode ACK/CTS rate table */
+ brcms_c_set_ratetable(wlc);
+
+ /* update some band specific mac configuration */
+ brcms_c_ucode_mac_upd(wlc);
+
+ /* init antenna selection */
+ brcms_c_antsel_init(wlc->asi);
+
+}
+
+/* formula: IDLE_BUSY_RATIO_X_16 = (100-duty_cycle)/duty_cycle*16 */
+static int
+brcms_c_duty_cycle_set(struct brcms_c_info *wlc, int duty_cycle, bool isOFDM,
+ bool writeToShm)
+{
+ int idle_busy_ratio_x_16 = 0;
+ uint offset =
+ isOFDM ? M_TX_IDLE_BUSY_RATIO_X_16_OFDM :
+ M_TX_IDLE_BUSY_RATIO_X_16_CCK;
+ if (duty_cycle > 100 || duty_cycle < 0) {
+ wiphy_err(wlc->wiphy, "wl%d: duty cycle value off limit\n",
+ wlc->pub->unit);
+ return -EINVAL;
+ }
+ if (duty_cycle)
+ idle_busy_ratio_x_16 = (100 - duty_cycle) * 16 / duty_cycle;
+ /* Only write to shared memory when wl is up */
+ if (writeToShm)
+ brcms_b_write_shm(wlc->hw, offset, (u16) idle_busy_ratio_x_16);
+
+ if (isOFDM)
+ wlc->tx_duty_cycle_ofdm = (u16) duty_cycle;
+ else
+ wlc->tx_duty_cycle_cck = (u16) duty_cycle;
+
+ return 0;
+}
+
+/*
+ * Initialize the base precedence map for dequeueing
+ * from txq based on WME settings
+ */
+static void brcms_c_tx_prec_map_init(struct brcms_c_info *wlc)
+{
+ wlc->tx_prec_map = BRCMS_PREC_BMP_ALL;
+ memset(wlc->fifo2prec_map, 0, NFIFO * sizeof(u16));
+
+ wlc->fifo2prec_map[TX_AC_BK_FIFO] = BRCMS_PREC_BMP_AC_BK;
+ wlc->fifo2prec_map[TX_AC_BE_FIFO] = BRCMS_PREC_BMP_AC_BE;
+ wlc->fifo2prec_map[TX_AC_VI_FIFO] = BRCMS_PREC_BMP_AC_VI;
+ wlc->fifo2prec_map[TX_AC_VO_FIFO] = BRCMS_PREC_BMP_AC_VO;
+}
+
+static void
+brcms_c_txflowcontrol_signal(struct brcms_c_info *wlc,
+ struct brcms_txq_info *qi, bool on, int prio)
+{
+ /* transmit flowcontrol is not yet implemented */
+}
+
+static void brcms_c_txflowcontrol_reset(struct brcms_c_info *wlc)
+{
+ struct brcms_txq_info *qi;
+
+ for (qi = wlc->tx_queues; qi != NULL; qi = qi->next) {
+ if (qi->stopped) {
+ brcms_c_txflowcontrol_signal(wlc, qi, OFF, ALLPRIO);
+ qi->stopped = 0;
+ }
+ }
+}
+
+/* push sw hps and wake state through hardware */
+static void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc)
+{
+ u32 v1, v2;
+ bool hps;
+ bool awake_before;
+
+ hps = brcms_c_ps_allowed(wlc);
+
+ BCMMSG(wlc->wiphy, "wl%d: hps %d\n", wlc->pub->unit, hps);
+
+ v1 = R_REG(&wlc->regs->maccontrol);
+ v2 = MCTL_WAKE;
+ if (hps)
+ v2 |= MCTL_HPS;
+
+ brcms_b_mctrl(wlc->hw, MCTL_WAKE | MCTL_HPS, v2);
+
+ awake_before = ((v1 & MCTL_WAKE) || ((v1 & MCTL_HPS) == 0));
+
+ if (!awake_before)
+ brcms_b_wait_for_wake(wlc->hw);
+}
+
+/*
+ * Write this BSS config's MAC address to core.
+ * Updates RXE match engine.
+ */
+static int brcms_c_set_mac(struct brcms_bss_cfg *bsscfg)
+{
+ int err = 0;
+ struct brcms_c_info *wlc = bsscfg->wlc;
+
+ /* enter the MAC addr into the RXE match registers */
+ brcms_c_set_addrmatch(wlc, RCM_MAC_OFFSET, bsscfg->cur_etheraddr);
+
+ brcms_c_ampdu_macaddr_upd(wlc);
+
+ return err;
+}
+
+/* Write the BSS config's BSSID address to core (set_bssid in d11procs.tcl).
+ * Updates RXE match engine.
+ */
+static void brcms_c_set_bssid(struct brcms_bss_cfg *bsscfg)
+{
+ /* we need to update BSSID in RXE match registers */
+ brcms_c_set_addrmatch(bsscfg->wlc, RCM_BSSID_OFFSET, bsscfg->BSSID);
+}
+
+static void brcms_b_set_shortslot(struct brcms_hardware *wlc_hw, bool shortslot)
+{
+ wlc_hw->shortslot = shortslot;
+
+ if (wlc_hw->band->bandtype == BRCM_BAND_2G && wlc_hw->up) {
+ brcms_c_suspend_mac_and_wait(wlc_hw->wlc);
+ brcms_b_update_slot_timing(wlc_hw, shortslot);
+ brcms_c_enable_mac(wlc_hw->wlc);
+ }
+}
+
+/*
+ * Suspend the the MAC and update the slot timing
+ * for standard 11b/g (20us slots) or shortslot 11g (9us slots).
+ */
+static void brcms_c_switch_shortslot(struct brcms_c_info *wlc, bool shortslot)
+{
+ /* use the override if it is set */
+ if (wlc->shortslot_override != BRCMS_SHORTSLOT_AUTO)
+ shortslot = (wlc->shortslot_override == BRCMS_SHORTSLOT_ON);
+
+ if (wlc->shortslot == shortslot)
+ return;
+
+ wlc->shortslot = shortslot;
+
+ brcms_b_set_shortslot(wlc->hw, shortslot);
+}
+
+static void brcms_c_set_home_chanspec(struct brcms_c_info *wlc, u16 chanspec)
+{
+ if (wlc->home_chanspec != chanspec) {
+ wlc->home_chanspec = chanspec;
+
+ if (wlc->bsscfg->associated)
+ wlc->bsscfg->current_bss->chanspec = chanspec;
+ }
+}
+
+void
+brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec,
+ bool mute, struct txpwr_limits *txpwr)
+{
+ uint bandunit;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d: 0x%x\n", wlc_hw->unit, chanspec);
+
+ wlc_hw->chanspec = chanspec;
+
+ /* Switch bands if necessary */
+ if (wlc_hw->_nbands > 1) {
+ bandunit = chspec_bandunit(chanspec);
+ if (wlc_hw->band->bandunit != bandunit) {
+ /* brcms_b_setband disables other bandunit,
+ * use light band switch if not up yet
+ */
+ if (wlc_hw->up) {
+ wlc_phy_chanspec_radio_set(wlc_hw->
+ bandstate[bandunit]->
+ pi, chanspec);
+ brcms_b_setband(wlc_hw, bandunit, chanspec);
+ } else {
+ brcms_c_setxband(wlc_hw, bandunit);
+ }
+ }
+ }
+
+ wlc_phy_initcal_enable(wlc_hw->band->pi, !mute);
+
+ if (!wlc_hw->up) {
+ if (wlc_hw->clk)
+ wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr,
+ chanspec);
+ wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec);
+ } else {
+ wlc_phy_chanspec_set(wlc_hw->band->pi, chanspec);
+ wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr, chanspec);
+
+ /* Update muting of the channel */
+ brcms_b_mute(wlc_hw, mute, 0);
+ }
+}
+
+/* switch to and initialize new band */
+static void brcms_c_setband(struct brcms_c_info *wlc,
+ uint bandunit)
+{
+ wlc->band = wlc->bandstate[bandunit];
+
+ if (!wlc->pub->up)
+ return;
+
+ /* wait for at least one beacon before entering sleeping state */
+ brcms_c_set_ps_ctrl(wlc);
+
+ /* band-specific initializations */
+ brcms_c_bsinit(wlc);
+}
+
+static void brcms_c_set_chanspec(struct brcms_c_info *wlc, u16 chanspec)
+{
+ uint bandunit;
+ bool switchband = false;
+ u16 old_chanspec = wlc->chanspec;
+
+ if (!brcms_c_valid_chanspec_db(wlc->cmi, chanspec)) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: Bad channel %d\n",
+ wlc->pub->unit, __func__, CHSPEC_CHANNEL(chanspec));
+ return;
+ }
+
+ /* Switch bands if necessary */
+ if (wlc->pub->_nbands > 1) {
+ bandunit = chspec_bandunit(chanspec);
+ if (wlc->band->bandunit != bandunit || wlc->bandinit_pending) {
+ switchband = true;
+ if (wlc->bandlocked) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: chspec %d "
+ "band is locked!\n",
+ wlc->pub->unit, __func__,
+ CHSPEC_CHANNEL(chanspec));
+ return;
+ }
+ /*
+ * should the setband call come after the
+ * brcms_b_chanspec() ? if the setband updates
+ * (brcms_c_bsinit) use low level calls to inspect and
+ * set state, the state inspected may be from the wrong
+ * band, or the following brcms_b_set_chanspec() may
+ * undo the work.
+ */
+ brcms_c_setband(wlc, bandunit);
+ }
+ }
+
+ /* sync up phy/radio chanspec */
+ brcms_c_set_phy_chanspec(wlc, chanspec);
+
+ /* init antenna selection */
+ if (brcms_chspec_bw(old_chanspec) != brcms_chspec_bw(chanspec)) {
+ brcms_c_antsel_init(wlc->asi);
+
+ /* Fix the hardware rateset based on bw.
+ * Mainly add MCS32 for 40Mhz, remove MCS 32 for 20Mhz
+ */
+ brcms_c_rateset_bw_mcs_filter(&wlc->band->hw_rateset,
+ wlc->band->mimo_cap_40 ? brcms_chspec_bw(chanspec) : 0);
+ }
+
+ /* update some mac configuration since chanspec changed */
+ brcms_c_ucode_mac_upd(wlc);
+}
+
+/*
+ * This function changes the phytxctl for beacon based on current
+ * beacon ratespec AND txant setting as per this table:
+ * ratespec CCK ant = wlc->stf->txant
+ * OFDM ant = 3
+ */
+void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc,
+ u32 bcn_rspec)
+{
+ u16 phyctl;
+ u16 phytxant = wlc->stf->phytxant;
+ u16 mask = PHY_TXC_ANT_MASK;
+
+ /* for non-siso rates or default setting, use the available chains */
+ if (BRCMS_PHY_11N_CAP(wlc->band))
+ phytxant = brcms_c_stf_phytxchain_sel(wlc, bcn_rspec);
+
+ phyctl = brcms_b_read_shm(wlc->hw, M_BCN_PCTLWD);
+ phyctl = (phyctl & ~mask) | phytxant;
+ brcms_b_write_shm(wlc->hw, M_BCN_PCTLWD, phyctl);
+}
+
+/*
+ * centralized protection config change function to simplify debugging, no
+ * consistency checking this should be called only on changes to avoid overhead
+ * in periodic function
+ */
+void brcms_c_protection_upd(struct brcms_c_info *wlc, uint idx, int val)
+{
+ BCMMSG(wlc->wiphy, "idx %d, val %d\n", idx, val);
+
+ switch (idx) {
+ case BRCMS_PROT_G_SPEC:
+ wlc->protection->_g = (bool) val;
+ break;
+ case BRCMS_PROT_G_OVR:
+ wlc->protection->g_override = (s8) val;
+ break;
+ case BRCMS_PROT_G_USER:
+ wlc->protection->gmode_user = (u8) val;
+ break;
+ case BRCMS_PROT_OVERLAP:
+ wlc->protection->overlap = (s8) val;
+ break;
+ case BRCMS_PROT_N_USER:
+ wlc->protection->nmode_user = (s8) val;
+ break;
+ case BRCMS_PROT_N_CFG:
+ wlc->protection->n_cfg = (s8) val;
+ break;
+ case BRCMS_PROT_N_CFG_OVR:
+ wlc->protection->n_cfg_override = (s8) val;
+ break;
+ case BRCMS_PROT_N_NONGF:
+ wlc->protection->nongf = (bool) val;
+ break;
+ case BRCMS_PROT_N_NONGF_OVR:
+ wlc->protection->nongf_override = (s8) val;
+ break;
+ case BRCMS_PROT_N_PAM_OVR:
+ wlc->protection->n_pam_override = (s8) val;
+ break;
+ case BRCMS_PROT_N_OBSS:
+ wlc->protection->n_obss = (bool) val;
+ break;
+
+ default:
+ break;
+ }
+
+}
+
+static void brcms_c_ht_update_sgi_rx(struct brcms_c_info *wlc, int val)
+{
+ if (wlc->pub->up) {
+ brcms_c_update_beacon(wlc);
+ brcms_c_update_probe_resp(wlc, true);
+ }
+}
+
+static void brcms_c_ht_update_ldpc(struct brcms_c_info *wlc, s8 val)
+{
+ wlc->stf->ldpc = val;
+
+ if (wlc->pub->up) {
+ brcms_c_update_beacon(wlc);
+ brcms_c_update_probe_resp(wlc, true);
+ wlc_phy_ldpc_override_set(wlc->band->pi, (val ? true : false));
+ }
+}
+
+void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
+ const struct ieee80211_tx_queue_params *params,
+ bool suspend)
+{
+ int i;
+ struct shm_acparams acp_shm;
+ u16 *shm_entry;
+
+ /* Only apply params if the core is out of reset and has clocks */
+ if (!wlc->clk) {
+ wiphy_err(wlc->wiphy, "wl%d: %s : no-clock\n", wlc->pub->unit,
+ __func__);
+ return;
+ }
+
+ memset((char *)&acp_shm, 0, sizeof(struct shm_acparams));
+ /* fill in shm ac params struct */
+ acp_shm.txop = params->txop;
+ /* convert from units of 32us to us for ucode */
+ wlc->edcf_txop[aci & 0x3] = acp_shm.txop =
+ EDCF_TXOP2USEC(acp_shm.txop);
+ acp_shm.aifs = (params->aifs & EDCF_AIFSN_MASK);
+
+ if (aci == AC_VI && acp_shm.txop == 0
+ && acp_shm.aifs < EDCF_AIFSN_MAX)
+ acp_shm.aifs++;
+
+ if (acp_shm.aifs < EDCF_AIFSN_MIN
+ || acp_shm.aifs > EDCF_AIFSN_MAX) {
+ wiphy_err(wlc->wiphy, "wl%d: edcf_setparams: bad "
+ "aifs %d\n", wlc->pub->unit, acp_shm.aifs);
+ } else {
+ acp_shm.cwmin = params->cw_min;
+ acp_shm.cwmax = params->cw_max;
+ acp_shm.cwcur = acp_shm.cwmin;
+ acp_shm.bslots =
+ R_REG(&wlc->regs->tsf_random) & acp_shm.cwcur;
+ acp_shm.reggap = acp_shm.bslots + acp_shm.aifs;
+ /* Indicate the new params to the ucode */
+ acp_shm.status = brcms_b_read_shm(wlc->hw, (M_EDCF_QINFO +
+ wme_ac2fifo[aci] *
+ M_EDCF_QLEN +
+ M_EDCF_STATUS_OFF));
+ acp_shm.status |= WME_STATUS_NEWAC;
+
+ /* Fill in shm acparam table */
+ shm_entry = (u16 *) &acp_shm;
+ for (i = 0; i < (int)sizeof(struct shm_acparams); i += 2)
+ brcms_b_write_shm(wlc->hw,
+ M_EDCF_QINFO +
+ wme_ac2fifo[aci] * M_EDCF_QLEN + i,
+ *shm_entry++);
+ }
+
+ if (suspend) {
+ brcms_c_suspend_mac_and_wait(wlc);
+ brcms_c_enable_mac(wlc);
+ }
+}
+
+void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
+{
+ u16 aci;
+ int i_ac;
+ struct ieee80211_tx_queue_params txq_pars;
+ static const struct edcf_acparam default_edcf_acparams[] = {
+ {EDCF_AC_BE_ACI_STA, EDCF_AC_BE_ECW_STA, EDCF_AC_BE_TXOP_STA},
+ {EDCF_AC_BK_ACI_STA, EDCF_AC_BK_ECW_STA, EDCF_AC_BK_TXOP_STA},
+ {EDCF_AC_VI_ACI_STA, EDCF_AC_VI_ECW_STA, EDCF_AC_VI_TXOP_STA},
+ {EDCF_AC_VO_ACI_STA, EDCF_AC_VO_ECW_STA, EDCF_AC_VO_TXOP_STA}
+ }; /* ucode needs these parameters during its initialization */
+ const struct edcf_acparam *edcf_acp = &default_edcf_acparams[0];
+
+ for (i_ac = 0; i_ac < AC_COUNT; i_ac++, edcf_acp++) {
+ /* find out which ac this set of params applies to */
+ aci = (edcf_acp->ACI & EDCF_ACI_MASK) >> EDCF_ACI_SHIFT;
+
+ /* fill in shm ac params struct */
+ txq_pars.txop = edcf_acp->TXOP;
+ txq_pars.aifs = edcf_acp->ACI;
+
+ /* CWmin = 2^(ECWmin) - 1 */
+ txq_pars.cw_min = EDCF_ECW2CW(edcf_acp->ECW & EDCF_ECWMIN_MASK);
+ /* CWmax = 2^(ECWmax) - 1 */
+ txq_pars.cw_max = EDCF_ECW2CW((edcf_acp->ECW & EDCF_ECWMAX_MASK)
+ >> EDCF_ECWMAX_SHIFT);
+ brcms_c_wme_setparams(wlc, aci, &txq_pars, suspend);
+ }
+
+ if (suspend) {
+ brcms_c_suspend_mac_and_wait(wlc);
+ brcms_c_enable_mac(wlc);
+ }
+}
+
+/* maintain LED behavior in down state */
+static void brcms_c_down_led_upd(struct brcms_c_info *wlc)
+{
+ /*
+ * maintain LEDs while in down state, turn on sbclk if
+ * not available yet. Turn on sbclk if necessary
+ */
+ brcms_b_pllreq(wlc->hw, true, BRCMS_PLLREQ_FLIP);
+ brcms_b_pllreq(wlc->hw, false, BRCMS_PLLREQ_FLIP);
+}
+
+static void brcms_c_radio_monitor_start(struct brcms_c_info *wlc)
+{
+ /* Don't start the timer if HWRADIO feature is disabled */
+ if (wlc->radio_monitor)
+ return;
+
+ wlc->radio_monitor = true;
+ brcms_b_pllreq(wlc->hw, true, BRCMS_PLLREQ_RADIO_MON);
+ brcms_add_timer(wlc->radio_timer, TIMER_INTERVAL_RADIOCHK, true);
+}
+
+static void brcms_c_radio_disable(struct brcms_c_info *wlc)
+{
+ if (!wlc->pub->up) {
+ brcms_c_down_led_upd(wlc);
+ return;
+ }
+
+ brcms_c_radio_monitor_start(wlc);
+ brcms_down(wlc->wl);
+}
+
+static void brcms_c_radio_enable(struct brcms_c_info *wlc)
+{
+ if (wlc->pub->up)
+ return;
+
+ if (brcms_deviceremoved(wlc))
+ return;
+
+ brcms_up(wlc->wl);
+}
+
+static bool brcms_c_radio_monitor_stop(struct brcms_c_info *wlc)
+{
+ if (!wlc->radio_monitor)
+ return true;
+
+ wlc->radio_monitor = false;
+ brcms_b_pllreq(wlc->hw, false, BRCMS_PLLREQ_RADIO_MON);
+ return brcms_del_timer(wlc->radio_timer);
+}
+
+/* read hwdisable state and propagate to wlc flag */
+static void brcms_c_radio_hwdisable_upd(struct brcms_c_info *wlc)
+{
+ if (wlc->pub->hw_off)
+ return;
+
+ if (brcms_b_radio_read_hwdisabled(wlc->hw))
+ mboolset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE);
+ else
+ mboolclr(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE);
+}
+
+/*
+ * centralized radio disable/enable function,
+ * invoke radio enable/disable after updating hwradio status
+ */
+static void brcms_c_radio_upd(struct brcms_c_info *wlc)
+{
+ if (wlc->pub->radio_disabled)
+ brcms_c_radio_disable(wlc);
+ else
+ brcms_c_radio_enable(wlc);
+}
+
+/* update hwradio status and return it */
+bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc)
+{
+ brcms_c_radio_hwdisable_upd(wlc);
+
+ return mboolisset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE) ?
+ true : false;
+}
+
+/* periodical query hw radio button while driver is "down" */
+static void brcms_c_radio_timer(void *arg)
+{
+ struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
+
+ if (brcms_deviceremoved(wlc)) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit,
+ __func__);
+ brcms_down(wlc->wl);
+ return;
+ }
+
+ /* cap mpc off count */
+ if (wlc->mpc_offcnt < BRCMS_MPC_MAX_DELAYCNT)
+ wlc->mpc_offcnt++;
+
+ brcms_c_radio_hwdisable_upd(wlc);
+ brcms_c_radio_upd(wlc);
+}
+
+/* common low-level watchdog code */
+static void brcms_b_watchdog(void *arg)
+{
+ struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
+ struct brcms_hardware *wlc_hw = wlc->hw;
+
+ BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ if (!wlc_hw->up)
+ return;
+
+ /* increment second count */
+ wlc_hw->now++;
+
+ /* Check for FIFO error interrupts */
+ brcms_b_fifoerrors(wlc_hw);
+
+ /* make sure RX dma has buffers */
+ dma_rxfill(wlc->hw->di[RX_FIFO]);
+
+ wlc_phy_watchdog(wlc_hw->band->pi);
+}
+
+static void brcms_c_radio_mpc_upd(struct brcms_c_info *wlc)
+{
+ bool mpc_radio, radio_state;
+
+ /*
+ * Clear the WL_RADIO_MPC_DISABLE bit when mpc feature is disabled
+ * in case the WL_RADIO_MPC_DISABLE bit was set. Stop the radio
+ * monitor also when WL_RADIO_MPC_DISABLE is the only reason that
+ * the radio is going down.
+ */
+ if (!wlc->mpc) {
+ if (!wlc->pub->radio_disabled)
+ return;
+ mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE);
+ brcms_c_radio_upd(wlc);
+ if (!wlc->pub->radio_disabled)
+ brcms_c_radio_monitor_stop(wlc);
+ return;
+ }
+
+ /*
+ * sync ismpc logic with WL_RADIO_MPC_DISABLE bit in
+ * wlc->pub->radio_disabled to go ON, always call radio_upd
+ * synchronously to go OFF, postpone radio_upd to later when
+ * context is safe(e.g. watchdog)
+ */
+ radio_state =
+ (mboolisset(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE) ? OFF :
+ ON);
+ mpc_radio = (brcms_c_ismpc(wlc) == true) ? OFF : ON;
+
+ if (radio_state == ON && mpc_radio == OFF)
+ wlc->mpc_delay_off = wlc->mpc_dlycnt;
+ else if (radio_state == OFF && mpc_radio == ON) {
+ mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE);
+ brcms_c_radio_upd(wlc);
+ if (wlc->mpc_offcnt < BRCMS_MPC_THRESHOLD)
+ wlc->mpc_dlycnt = BRCMS_MPC_MAX_DELAYCNT;
+ else
+ wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT;
+ }
+ /*
+ * Below logic is meant to capture the transition from mpc off
+ * to mpc on for reasons other than wlc->mpc_delay_off keeping
+ * the mpc off. In that case reset wlc->mpc_delay_off to
+ * wlc->mpc_dlycnt, so that we restart the countdown of mpc_delay_off
+ */
+ if ((wlc->prev_non_delay_mpc == false) &&
+ (brcms_c_is_non_delay_mpc(wlc) == true) && wlc->mpc_delay_off)
+ wlc->mpc_delay_off = wlc->mpc_dlycnt;
+
+ wlc->prev_non_delay_mpc = brcms_c_is_non_delay_mpc(wlc);
+}
+
+/* common watchdog code */
+static void brcms_c_watchdog(void *arg)
+{
+ struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
+
+ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+
+ if (!wlc->pub->up)
+ return;
+
+ if (brcms_deviceremoved(wlc)) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit,
+ __func__);
+ brcms_down(wlc->wl);
+ return;
+ }
+
+ /* increment second count */
+ wlc->pub->now++;
+
+ /* delay radio disable */
+ if (wlc->mpc_delay_off) {
+ if (--wlc->mpc_delay_off == 0) {
+ mboolset(wlc->pub->radio_disabled,
+ WL_RADIO_MPC_DISABLE);
+ if (wlc->mpc && brcms_c_ismpc(wlc))
+ wlc->mpc_offcnt = 0;
+ }
+ }
+
+ /* mpc sync */
+ brcms_c_radio_mpc_upd(wlc);
+ /* radio sync: sw/hw/mpc --> radio_disable/radio_enable */
+ brcms_c_radio_hwdisable_upd(wlc);
+ brcms_c_radio_upd(wlc);
+ /* if radio is disable, driver may be down, quit here */
+ if (wlc->pub->radio_disabled)
+ return;
+
+ brcms_b_watchdog(wlc);
+
+ /*
+ * occasionally sample mac stat counters to
+ * detect 16-bit counter wrap
+ */
+ if ((wlc->pub->now % SW_TIMER_MAC_STAT_UPD) == 0)
+ brcms_c_statsupd(wlc);
+
+ if (BRCMS_ISNPHY(wlc->band) &&
+ ((wlc->pub->now - wlc->tempsense_lasttime) >=
+ BRCMS_TEMPSENSE_PERIOD)) {
+ wlc->tempsense_lasttime = wlc->pub->now;
+ brcms_c_tempsense_upd(wlc);
+ }
+}
+
+static void brcms_c_watchdog_by_timer(void *arg)
+{
+ brcms_c_watchdog(arg);
+}
+
+static bool brcms_c_timers_init(struct brcms_c_info *wlc, int unit)
+{
+ wlc->wdtimer = brcms_init_timer(wlc->wl, brcms_c_watchdog_by_timer,
+ wlc, "watchdog");
+ if (!wlc->wdtimer) {
+ wiphy_err(wlc->wiphy, "wl%d: wl_init_timer for wdtimer "
+ "failed\n", unit);
+ goto fail;
+ }
+
+ wlc->radio_timer = brcms_init_timer(wlc->wl, brcms_c_radio_timer,
+ wlc, "radio");
+ if (!wlc->radio_timer) {
+ wiphy_err(wlc->wiphy, "wl%d: wl_init_timer for radio_timer "
+ "failed\n", unit);
+ goto fail;
+ }
+
+ return true;
+
+ fail:
+ return false;
+}
+
+/*
+ * Initialize brcms_c_info default values ...
+ * may get overrides later in this function
+ */
+static void brcms_c_info_init(struct brcms_c_info *wlc, int unit)
+{
+ int i;
+
+ /* Save our copy of the chanspec */
+ wlc->chanspec = ch20mhz_chspec(1);
+
+ /* various 802.11g modes */
+ wlc->shortslot = false;
+ wlc->shortslot_override = BRCMS_SHORTSLOT_AUTO;
+
+ brcms_c_protection_upd(wlc, BRCMS_PROT_G_OVR, BRCMS_PROTECTION_AUTO);
+ brcms_c_protection_upd(wlc, BRCMS_PROT_G_SPEC, false);
+
+ brcms_c_protection_upd(wlc, BRCMS_PROT_N_CFG_OVR,
+ BRCMS_PROTECTION_AUTO);
+ brcms_c_protection_upd(wlc, BRCMS_PROT_N_CFG, BRCMS_N_PROTECTION_OFF);
+ brcms_c_protection_upd(wlc, BRCMS_PROT_N_NONGF_OVR,
+ BRCMS_PROTECTION_AUTO);
+ brcms_c_protection_upd(wlc, BRCMS_PROT_N_NONGF, false);
+ brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR, AUTO);
+
+ brcms_c_protection_upd(wlc, BRCMS_PROT_OVERLAP,
+ BRCMS_PROTECTION_CTL_OVERLAP);
+
+ /* 802.11g draft 4.0 NonERP elt advertisement */
+ wlc->include_legacy_erp = true;
+
+ wlc->stf->ant_rx_ovr = ANT_RX_DIV_DEF;
+ wlc->stf->txant = ANT_TX_DEF;
+
+ wlc->prb_resp_timeout = BRCMS_PRB_RESP_TIMEOUT;
+
+ wlc->usr_fragthresh = DOT11_DEFAULT_FRAG_LEN;
+ for (i = 0; i < NFIFO; i++)
+ wlc->fragthresh[i] = DOT11_DEFAULT_FRAG_LEN;
+ wlc->RTSThresh = DOT11_DEFAULT_RTS_LEN;
+
+ /* default rate fallback retry limits */
+ wlc->SFBL = RETRY_SHORT_FB;
+ wlc->LFBL = RETRY_LONG_FB;
+
+ /* default mac retry limits */
+ wlc->SRL = RETRY_SHORT_DEF;
+ wlc->LRL = RETRY_LONG_DEF;
+
+ /* WME QoS mode is Auto by default */
+ wlc->pub->_ampdu = AMPDU_AGG_HOST;
+ wlc->pub->bcmerror = 0;
+
+ /* initialize mpc delay */
+ wlc->mpc_delay_off = wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT;
+}
+
+static uint brcms_c_attach_module(struct brcms_c_info *wlc)
+{
+ uint err = 0;
+ uint unit;
+ unit = wlc->pub->unit;
+
+ wlc->asi = brcms_c_antsel_attach(wlc);
+ if (wlc->asi == NULL) {
+ wiphy_err(wlc->wiphy, "wl%d: attach: antsel_attach "
+ "failed\n", unit);
+ err = 44;
+ goto fail;
+ }
+
+ wlc->ampdu = brcms_c_ampdu_attach(wlc);
+ if (wlc->ampdu == NULL) {
+ wiphy_err(wlc->wiphy, "wl%d: attach: ampdu_attach "
+ "failed\n", unit);
+ err = 50;
+ goto fail;
+ }
+
+ if ((brcms_c_stf_attach(wlc) != 0)) {
+ wiphy_err(wlc->wiphy, "wl%d: attach: stf_attach "
+ "failed\n", unit);
+ err = 68;
+ goto fail;
+ }
+ fail:
+ return err;
+}
+
+struct brcms_pub *brcms_c_pub(struct brcms_c_info *wlc)
+{
+ return wlc->pub;
+}
+
+/* low level attach
+ * run backplane attach, init nvram
+ * run phy attach
+ * initialize software state for each core and band
+ * put the whole chip in reset(driver down state), no clock
+ */
+static int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device,
+ uint unit, bool piomode, void __iomem *regsva,
+ struct pci_dev *btparam)
+{
+ struct brcms_hardware *wlc_hw;
+ struct d11regs __iomem *regs;
+ char *macaddr = NULL;
+ uint err = 0;
+ uint j;
+ bool wme = false;
+ struct shared_phy_params sha_params;
+ struct wiphy *wiphy = wlc->wiphy;
+
+ BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit, vendor,
+ device);
+
+ wme = true;
+
+ wlc_hw = wlc->hw;
+ wlc_hw->wlc = wlc;
+ wlc_hw->unit = unit;
+ wlc_hw->band = wlc_hw->bandstate[0];
+ wlc_hw->_piomode = piomode;
+
+ /* populate struct brcms_hardware with default values */
+ brcms_b_info_init(wlc_hw);
+
+ /*
+ * Do the hardware portion of the attach. Also initialize software
+ * state that depends on the particular hardware we are running.
+ */
+ wlc_hw->sih = ai_attach(regsva, btparam);
+ if (wlc_hw->sih == NULL) {
+ wiphy_err(wiphy, "wl%d: brcms_b_attach: si_attach failed\n",
+ unit);
+ err = 11;
+ goto fail;
+ }
+
+ /* verify again the device is supported */
+ if (!brcms_c_chipmatch(vendor, device)) {
+ wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported "
+ "vendor/device (0x%x/0x%x)\n",
+ unit, vendor, device);
+ err = 12;
+ goto fail;
+ }
+
+ wlc_hw->vendorid = vendor;
+ wlc_hw->deviceid = device;
+
+ /* set bar0 window to point at D11 core */
+ wlc_hw->regs = (struct d11regs __iomem *)
+ ai_setcore(wlc_hw->sih, D11_CORE_ID, 0);
+ wlc_hw->corerev = ai_corerev(wlc_hw->sih);
+
+ regs = wlc_hw->regs;
+
+ wlc->regs = wlc_hw->regs;
+
+ /* validate chip, chiprev and corerev */
+ if (!brcms_c_isgoodchip(wlc_hw)) {
+ err = 13;
+ goto fail;
+ }
+
+ /* initialize power control registers */
+ ai_clkctl_init(wlc_hw->sih);
+
+ /* request fastclock and force fastclock for the rest of attach
+ * bring the d11 core out of reset.
+ * For PMU chips, the first wlc_clkctl_clk is no-op since core-clk
+ * is still false; But it will be called again inside wlc_corereset,
+ * after d11 is out of reset.
+ */
+ brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
+ brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
+
+ if (!brcms_b_validate_chip_access(wlc_hw)) {
+ wiphy_err(wiphy, "wl%d: brcms_b_attach: validate_chip_access "
+ "failed\n", unit);
+ err = 14;
+ goto fail;
+ }
+
+ /* get the board rev, used just below */
+ j = getintvar(wlc_hw->sih, BRCMS_SROM_BOARDREV);
+ /* promote srom boardrev of 0xFF to 1 */
+ if (j == BOARDREV_PROMOTABLE)
+ j = BOARDREV_PROMOTED;
+ wlc_hw->boardrev = (u16) j;
+ if (!brcms_c_validboardtype(wlc_hw)) {
+ wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported Broadcom "
+ "board type (0x%x)" " or revision level (0x%x)\n",
+ unit, wlc_hw->sih->boardtype, wlc_hw->boardrev);
+ err = 15;
+ goto fail;
+ }
+ wlc_hw->sromrev = (u8) getintvar(wlc_hw->sih, BRCMS_SROM_REV);
+ wlc_hw->boardflags = (u32) getintvar(wlc_hw->sih,
+ BRCMS_SROM_BOARDFLAGS);
+ wlc_hw->boardflags2 = (u32) getintvar(wlc_hw->sih,
+ BRCMS_SROM_BOARDFLAGS2);
+
+ if (wlc_hw->boardflags & BFL_NOPLLDOWN)
+ brcms_b_pllreq(wlc_hw, true, BRCMS_PLLREQ_SHARED);
+
+ /* check device id(srom, nvram etc.) to set bands */
+ if (wlc_hw->deviceid == BCM43224_D11N_ID ||
+ wlc_hw->deviceid == BCM43224_D11N_ID_VEN1)
+ /* Dualband boards */
+ wlc_hw->_nbands = 2;
+ else
+ wlc_hw->_nbands = 1;
+
+ if ((wlc_hw->sih->chip == BCM43225_CHIP_ID))
+ wlc_hw->_nbands = 1;
+
+ /* BMAC_NOTE: remove init of pub values when brcms_c_attach()
+ * unconditionally does the init of these values
+ */
+ wlc->vendorid = wlc_hw->vendorid;
+ wlc->deviceid = wlc_hw->deviceid;
+ wlc->pub->sih = wlc_hw->sih;
+ wlc->pub->corerev = wlc_hw->corerev;
+ wlc->pub->sromrev = wlc_hw->sromrev;
+ wlc->pub->boardrev = wlc_hw->boardrev;
+ wlc->pub->boardflags = wlc_hw->boardflags;
+ wlc->pub->boardflags2 = wlc_hw->boardflags2;
+ wlc->pub->_nbands = wlc_hw->_nbands;
+
+ wlc_hw->physhim = wlc_phy_shim_attach(wlc_hw, wlc->wl, wlc);
+
+ if (wlc_hw->physhim == NULL) {
+ wiphy_err(wiphy, "wl%d: brcms_b_attach: wlc_phy_shim_attach "
+ "failed\n", unit);
+ err = 25;
+ goto fail;
+ }
+
+ /* pass all the parameters to wlc_phy_shared_attach in one struct */
+ sha_params.sih = wlc_hw->sih;
+ sha_params.physhim = wlc_hw->physhim;
+ sha_params.unit = unit;
+ sha_params.corerev = wlc_hw->corerev;
+ sha_params.vid = wlc_hw->vendorid;
+ sha_params.did = wlc_hw->deviceid;
+ sha_params.chip = wlc_hw->sih->chip;
+ sha_params.chiprev = wlc_hw->sih->chiprev;
+ sha_params.chippkg = wlc_hw->sih->chippkg;
+ sha_params.sromrev = wlc_hw->sromrev;
+ sha_params.boardtype = wlc_hw->sih->boardtype;
+ sha_params.boardrev = wlc_hw->boardrev;
+ sha_params.boardvendor = wlc_hw->sih->boardvendor;
+ sha_params.boardflags = wlc_hw->boardflags;
+ sha_params.boardflags2 = wlc_hw->boardflags2;
+ sha_params.buscorerev = wlc_hw->sih->buscorerev;
+
+ /* alloc and save pointer to shared phy state area */
+ wlc_hw->phy_sh = wlc_phy_shared_attach(&sha_params);
+ if (!wlc_hw->phy_sh) {
+ err = 16;
+ goto fail;
+ }
+
+ /* initialize software state for each core and band */
+ for (j = 0; j < wlc_hw->_nbands; j++) {
+ /*
+ * band0 is always 2.4Ghz
+ * band1, if present, is 5Ghz
+ */
+
+ brcms_c_setxband(wlc_hw, j);
+
+ wlc_hw->band->bandunit = j;
+ wlc_hw->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G;
+ wlc->band->bandunit = j;
+ wlc->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G;
+ wlc->core->coreidx = ai_coreidx(wlc_hw->sih);
+
+ wlc_hw->machwcap = R_REG(&regs->machwcap);
+ wlc_hw->machwcap_backup = wlc_hw->machwcap;
+
+ /* init tx fifo size */
+ wlc_hw->xmtfifo_sz =
+ xmtfifo_sz[(wlc_hw->corerev - XMTFIFOTBL_STARTREV)];
+
+ /* Get a phy for this band */
+ wlc_hw->band->pi =
+ wlc_phy_attach(wlc_hw->phy_sh, regs,
+ wlc_hw->band->bandtype,
+ wlc->wiphy);
+ if (wlc_hw->band->pi == NULL) {
+ wiphy_err(wiphy, "wl%d: brcms_b_attach: wlc_phy_"
+ "attach failed\n", unit);
+ err = 17;
+ goto fail;
+ }
+
+ wlc_phy_machwcap_set(wlc_hw->band->pi, wlc_hw->machwcap);
+
+ wlc_phy_get_phyversion(wlc_hw->band->pi, &wlc_hw->band->phytype,
+ &wlc_hw->band->phyrev,
+ &wlc_hw->band->radioid,
+ &wlc_hw->band->radiorev);
+ wlc_hw->band->abgphy_encore =
+ wlc_phy_get_encore(wlc_hw->band->pi);
+ wlc->band->abgphy_encore = wlc_phy_get_encore(wlc_hw->band->pi);
+ wlc_hw->band->core_flags =
+ wlc_phy_get_coreflags(wlc_hw->band->pi);
+
+ /* verify good phy_type & supported phy revision */
+ if (BRCMS_ISNPHY(wlc_hw->band)) {
+ if (NCONF_HAS(wlc_hw->band->phyrev))
+ goto good_phy;
+ else
+ goto bad_phy;
+ } else if (BRCMS_ISLCNPHY(wlc_hw->band)) {
+ if (LCNCONF_HAS(wlc_hw->band->phyrev))
+ goto good_phy;
+ else
+ goto bad_phy;
+ } else {
+ bad_phy:
+ wiphy_err(wiphy, "wl%d: brcms_b_attach: unsupported "
+ "phy type/rev (%d/%d)\n", unit,
+ wlc_hw->band->phytype, wlc_hw->band->phyrev);
+ err = 18;
+ goto fail;
+ }
+
+ good_phy:
+ /*
+ * BMAC_NOTE: wlc->band->pi should not be set below and should
+ * be done in the high level attach. However we can not make
+ * that change until all low level access is changed to
+ * wlc_hw->band->pi. Instead do the wlc->band->pi init below,
+ * keeping wlc_hw->band->pi as well for incremental update of
+ * low level fns, and cut over low only init when all fns
+ * updated.
+ */
+ wlc->band->pi = wlc_hw->band->pi;
+ wlc->band->phytype = wlc_hw->band->phytype;
+ wlc->band->phyrev = wlc_hw->band->phyrev;
+ wlc->band->radioid = wlc_hw->band->radioid;
+ wlc->band->radiorev = wlc_hw->band->radiorev;
+
+ /* default contention windows size limits */
+ wlc_hw->band->CWmin = APHY_CWMIN;
+ wlc_hw->band->CWmax = PHY_CWMAX;
+
+ if (!brcms_b_attach_dmapio(wlc, j, wme)) {
+ err = 19;
+ goto fail;
+ }
+ }
+
+ /* disable core to match driver "down" state */
+ brcms_c_coredisable(wlc_hw);
+
+ /* Match driver "down" state */
+ ai_pci_down(wlc_hw->sih);
+
+ /* register sb interrupt callback functions */
+ ai_register_intr_callback(wlc_hw->sih, (void *)brcms_c_wlintrsoff,
+ (void *)brcms_c_wlintrsrestore, NULL, wlc);
+
+ /* turn off pll and xtal to match driver "down" state */
+ brcms_b_xtal(wlc_hw, OFF);
+
+ /* *******************************************************************
+ * The hardware is in the DOWN state at this point. D11 core
+ * or cores are in reset with clocks off, and the board PLLs
+ * are off if possible.
+ *
+ * Beyond this point, wlc->sbclk == false and chip registers
+ * should not be touched.
+ *********************************************************************
+ */
+
+ /* init etheraddr state variables */
+ macaddr = brcms_c_get_macaddr(wlc_hw);
+ if (macaddr == NULL) {
+ wiphy_err(wiphy, "wl%d: brcms_b_attach: macaddr not found\n",
+ unit);
+ err = 21;
+ goto fail;
+ }
+ if (!mac_pton(macaddr, wlc_hw->etheraddr) ||
+ is_broadcast_ether_addr(wlc_hw->etheraddr) ||
+ is_zero_ether_addr(wlc_hw->etheraddr)) {
+ wiphy_err(wiphy, "wl%d: brcms_b_attach: bad macaddr %s\n",
+ unit, macaddr);
+ err = 22;
+ goto fail;
+ }
+
+ BCMMSG(wlc->wiphy,
+ "deviceid 0x%x nbands %d board 0x%x macaddr: %s\n",
+ wlc_hw->deviceid, wlc_hw->_nbands,
+ wlc_hw->sih->boardtype, macaddr);
+
+ return err;
+
+ fail:
+ wiphy_err(wiphy, "wl%d: brcms_b_attach: failed with err %d\n", unit,
+ err);
+ return err;
+}
+
+static void brcms_c_attach_antgain_init(struct brcms_c_info *wlc)
+{
+ uint unit;
+ unit = wlc->pub->unit;
+
+ if ((wlc->band->antgain == -1) && (wlc->pub->sromrev == 1)) {
+ /* default antenna gain for srom rev 1 is 2 dBm (8 qdbm) */
+ wlc->band->antgain = 8;
+ } else if (wlc->band->antgain == -1) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in"
+ " srom, using 2dB\n", unit, __func__);
+ wlc->band->antgain = 8;
+ } else {
+ s8 gain, fract;
+ /* Older sroms specified gain in whole dbm only. In order
+ * be able to specify qdbm granularity and remain backward
+ * compatible the whole dbms are now encoded in only
+ * low 6 bits and remaining qdbms are encoded in the hi 2 bits.
+ * 6 bit signed number ranges from -32 - 31.
+ *
+ * Examples:
+ * 0x1 = 1 db,
+ * 0xc1 = 1.75 db (1 + 3 quarters),
+ * 0x3f = -1 (-1 + 0 quarters),
+ * 0x7f = -.75 (-1 + 1 quarters) = -3 qdbm.
+ * 0xbf = -.50 (-1 + 2 quarters) = -2 qdbm.
+ */
+ gain = wlc->band->antgain & 0x3f;
+ gain <<= 2; /* Sign extend */
+ gain >>= 2;
+ fract = (wlc->band->antgain & 0xc0) >> 6;
+ wlc->band->antgain = 4 * gain + fract;
+ }
+}
+
+static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc)
+{
+ int aa;
+ uint unit;
+ int bandtype;
+ struct si_pub *sih = wlc->hw->sih;
+
+ unit = wlc->pub->unit;
+ bandtype = wlc->band->bandtype;
+
+ /* get antennas available */
+ if (bandtype == BRCM_BAND_5G)
+ aa = (s8) getintvar(sih, BRCMS_SROM_AA5G);
+ else
+ aa = (s8) getintvar(sih, BRCMS_SROM_AA2G);
+
+ if ((aa < 1) || (aa > 15)) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in"
+ " srom (0x%x), using 3\n", unit, __func__, aa);
+ aa = 3;
+ }
+
+ /* reset the defaults if we have a single antenna */
+ if (aa == 1) {
+ wlc->stf->ant_rx_ovr = ANT_RX_DIV_FORCE_0;
+ wlc->stf->txant = ANT_TX_FORCE_0;
+ } else if (aa == 2) {
+ wlc->stf->ant_rx_ovr = ANT_RX_DIV_FORCE_1;
+ wlc->stf->txant = ANT_TX_FORCE_1;
+ } else {
+ }
+
+ /* Compute Antenna Gain */
+ if (bandtype == BRCM_BAND_5G)
+ wlc->band->antgain = (s8) getintvar(sih, BRCMS_SROM_AG1);
+ else
+ wlc->band->antgain = (s8) getintvar(sih, BRCMS_SROM_AG0);
+
+ brcms_c_attach_antgain_init(wlc);
+
+ return true;
+}
+
+static void brcms_c_bss_default_init(struct brcms_c_info *wlc)
+{
+ u16 chanspec;
+ struct brcms_band *band;
+ struct brcms_bss_info *bi = wlc->default_bss;
+
+ /* init default and target BSS with some sane initial values */
+ memset((char *)(bi), 0, sizeof(struct brcms_bss_info));
+ bi->beacon_period = BEACON_INTERVAL_DEFAULT;
+
+ /* fill the default channel as the first valid channel
+ * starting from the 2G channels
+ */
+ chanspec = ch20mhz_chspec(1);
+ wlc->home_chanspec = bi->chanspec = chanspec;
+
+ /* find the band of our default channel */
+ band = wlc->band;
+ if (wlc->pub->_nbands > 1 &&
+ band->bandunit != chspec_bandunit(chanspec))
+ band = wlc->bandstate[OTHERBANDUNIT(wlc)];
+
+ /* init bss rates to the band specific default rate set */
+ brcms_c_rateset_default(&bi->rateset, NULL, band->phytype,
+ band->bandtype, false, BRCMS_RATE_MASK_FULL,
+ (bool) (wlc->pub->_n_enab & SUPPORT_11N),
+ brcms_chspec_bw(chanspec), wlc->stf->txstreams);
+
+ if (wlc->pub->_n_enab & SUPPORT_11N)
+ bi->flags |= BRCMS_BSS_HT;
+}
+
+static struct brcms_txq_info *brcms_c_txq_alloc(struct brcms_c_info *wlc)
+{
+ struct brcms_txq_info *qi, *p;
+
+ qi = kzalloc(sizeof(struct brcms_txq_info), GFP_ATOMIC);
+ if (qi != NULL) {
+ /*
+ * Have enough room for control packets along with HI watermark
+ * Also, add room to txq for total psq packets if all the SCBs
+ * leave PS mode. The watermark for flowcontrol to OS packets
+ * will remain the same
+ */
+ brcmu_pktq_init(&qi->q, BRCMS_PREC_COUNT,
+ 2 * BRCMS_DATAHIWAT + PKTQ_LEN_DEFAULT);
+
+ /* add this queue to the the global list */
+ p = wlc->tx_queues;
+ if (p == NULL) {
+ wlc->tx_queues = qi;
+ } else {
+ while (p->next != NULL)
+ p = p->next;
+ p->next = qi;
+ }
+ }
+ return qi;
+}
+
+static void brcms_c_txq_free(struct brcms_c_info *wlc,
+ struct brcms_txq_info *qi)
+{
+ struct brcms_txq_info *p;
+
+ if (qi == NULL)
+ return;
+
+ /* remove the queue from the linked list */
+ p = wlc->tx_queues;
+ if (p == qi)
+ wlc->tx_queues = p->next;
+ else {
+ while (p != NULL && p->next != qi)
+ p = p->next;
+ if (p != NULL)
+ p->next = p->next->next;
+ }
+
+ kfree(qi);
+}
+
+static void brcms_c_update_mimo_band_bwcap(struct brcms_c_info *wlc, u8 bwcap)
+{
+ uint i;
+ struct brcms_band *band;
+
+ for (i = 0; i < wlc->pub->_nbands; i++) {
+ band = wlc->bandstate[i];
+ if (band->bandtype == BRCM_BAND_5G) {
+ if ((bwcap == BRCMS_N_BW_40ALL)
+ || (bwcap == BRCMS_N_BW_20IN2G_40IN5G))
+ band->mimo_cap_40 = true;
+ else
+ band->mimo_cap_40 = false;
+ } else {
+ if (bwcap == BRCMS_N_BW_40ALL)
+ band->mimo_cap_40 = true;
+ else
+ band->mimo_cap_40 = false;
+ }
+ }
+}
+
+static void brcms_c_timers_deinit(struct brcms_c_info *wlc)
+{
+ /* free timer state */
+ if (wlc->wdtimer) {
+ brcms_free_timer(wlc->wdtimer);
+ wlc->wdtimer = NULL;
+ }
+ if (wlc->radio_timer) {
+ brcms_free_timer(wlc->radio_timer);
+ wlc->radio_timer = NULL;
+ }
+}
+
+static void brcms_c_detach_module(struct brcms_c_info *wlc)
+{
+ if (wlc->asi) {
+ brcms_c_antsel_detach(wlc->asi);
+ wlc->asi = NULL;
+ }
+
+ if (wlc->ampdu) {
+ brcms_c_ampdu_detach(wlc->ampdu);
+ wlc->ampdu = NULL;
+ }
+
+ brcms_c_stf_detach(wlc);
+}
+
+/*
+ * low level detach
+ */
+static int brcms_b_detach(struct brcms_c_info *wlc)
+{
+ uint i;
+ struct brcms_hw_band *band;
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ int callbacks;
+
+ callbacks = 0;
+
+ if (wlc_hw->sih) {
+ /*
+ * detach interrupt sync mechanism since interrupt is disabled
+ * and per-port interrupt object may has been freed. this must
+ * be done before sb core switch
+ */
+ ai_deregister_intr_callback(wlc_hw->sih);
+ ai_pci_sleep(wlc_hw->sih);
+ }
+
+ brcms_b_detach_dmapio(wlc_hw);
+
+ band = wlc_hw->band;
+ for (i = 0; i < wlc_hw->_nbands; i++) {
+ if (band->pi) {
+ /* Detach this band's phy */
+ wlc_phy_detach(band->pi);
+ band->pi = NULL;
+ }
+ band = wlc_hw->bandstate[OTHERBANDUNIT(wlc)];
+ }
+
+ /* Free shared phy state */
+ kfree(wlc_hw->phy_sh);
+
+ wlc_phy_shim_detach(wlc_hw->physhim);
+
+ if (wlc_hw->sih) {
+ ai_detach(wlc_hw->sih);
+ wlc_hw->sih = NULL;
+ }
+
+ return callbacks;
+
+}
+
+/*
+ * Return a count of the number of driver callbacks still pending.
+ *
+ * General policy is that brcms_c_detach can only dealloc/free software states.
+ * It can NOT touch hardware registers since the d11core may be in reset and
+ * clock may not be available.
+ * One exception is sb register access, which is possible if crystal is turned
+ * on after "down" state, driver should avoid software timer with the exception
+ * of radio_monitor.
+ */
+uint brcms_c_detach(struct brcms_c_info *wlc)
+{
+ uint callbacks = 0;
+
+ if (wlc == NULL)
+ return 0;
+
+ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+
+ callbacks += brcms_b_detach(wlc);
+
+ /* delete software timers */
+ if (!brcms_c_radio_monitor_stop(wlc))
+ callbacks++;
+
+ brcms_c_channel_mgr_detach(wlc->cmi);
+
+ brcms_c_timers_deinit(wlc);
+
+ brcms_c_detach_module(wlc);
+
+
+ while (wlc->tx_queues != NULL)
+ brcms_c_txq_free(wlc, wlc->tx_queues);
+
+ brcms_c_detach_mfree(wlc);
+ return callbacks;
+}
+
+/* update state that depends on the current value of "ap" */
+static void brcms_c_ap_upd(struct brcms_c_info *wlc)
+{
+ /* STA-BSS; short capable */
+ wlc->PLCPHdr_override = BRCMS_PLCP_SHORT;
+
+ /* fixup mpc */
+ wlc->mpc = true;
+}
+
+/* Initialize just the hardware when coming out of POR or S3/S5 system states */
+static void brcms_b_hw_up(struct brcms_hardware *wlc_hw)
+{
+ if (wlc_hw->wlc->pub->hw_up)
+ return;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ /*
+ * Enable pll and xtal, initialize the power control registers,
+ * and force fastclock for the remainder of brcms_c_up().
+ */
+ brcms_b_xtal(wlc_hw, ON);
+ ai_clkctl_init(wlc_hw->sih);
+ brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
+
+ ai_pci_fixcfg(wlc_hw->sih);
+
+ /*
+ * AI chip doesn't restore bar0win2 on
+ * hibernation/resume, need sw fixup
+ */
+ if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) ||
+ (wlc_hw->sih->chip == BCM43225_CHIP_ID))
+ wlc_hw->regs = (struct d11regs __iomem *)
+ ai_setcore(wlc_hw->sih, D11_CORE_ID, 0);
+
+ /*
+ * Inform phy that a POR reset has occurred so
+ * it does a complete phy init
+ */
+ wlc_phy_por_inform(wlc_hw->band->pi);
+
+ wlc_hw->ucode_loaded = false;
+ wlc_hw->wlc->pub->hw_up = true;
+
+ if ((wlc_hw->boardflags & BFL_FEM)
+ && (wlc_hw->sih->chip == BCM4313_CHIP_ID)) {
+ if (!
+ (wlc_hw->boardrev >= 0x1250
+ && (wlc_hw->boardflags & BFL_FEM_BT)))
+ ai_epa_4313war(wlc_hw->sih);
+ }
+}
+
+static int brcms_b_up_prep(struct brcms_hardware *wlc_hw)
+{
+ uint coremask;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ /*
+ * Enable pll and xtal, initialize the power control registers,
+ * and force fastclock for the remainder of brcms_c_up().
+ */
+ brcms_b_xtal(wlc_hw, ON);
+ ai_clkctl_init(wlc_hw->sih);
+ brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
+
+ /*
+ * Configure pci/pcmcia here instead of in brcms_c_attach()
+ * to allow mfg hotswap: down, hotswap (chip power cycle), up.
+ */
+ coremask = (1 << wlc_hw->wlc->core->coreidx);
+
+ ai_pci_setup(wlc_hw->sih, coremask);
+
+ /*
+ * Need to read the hwradio status here to cover the case where the
+ * system is loaded with the hw radio disabled. We do not want to
+ * bring the driver up in this case.
+ */
+ if (brcms_b_radio_read_hwdisabled(wlc_hw)) {
+ /* put SB PCI in down state again */
+ ai_pci_down(wlc_hw->sih);
+ brcms_b_xtal(wlc_hw, OFF);
+ return -ENOMEDIUM;
+ }
+
+ ai_pci_up(wlc_hw->sih);
+
+ /* reset the d11 core */
+ brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
+
+ return 0;
+}
+
+static int brcms_b_up_finish(struct brcms_hardware *wlc_hw)
+{
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ wlc_hw->up = true;
+ wlc_phy_hw_state_upd(wlc_hw->band->pi, true);
+
+ /* FULLY enable dynamic power control and d11 core interrupt */
+ brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
+ brcms_intrson(wlc_hw->wlc->wl);
+ return 0;
+}
+
+/*
+ * Write WME tunable parameters for retransmit/max rate
+ * from wlc struct to ucode
+ */
+static void brcms_c_wme_retries_write(struct brcms_c_info *wlc)
+{
+ int ac;
+
+ /* Need clock to do this */
+ if (!wlc->clk)
+ return;
+
+ for (ac = 0; ac < AC_COUNT; ac++)
+ brcms_b_write_shm(wlc->hw, M_AC_TXLMT_ADDR(ac),
+ wlc->wme_retries[ac]);
+}
+
+/* make interface operational */
+int brcms_c_up(struct brcms_c_info *wlc)
+{
+ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+
+ /* HW is turned off so don't try to access it */
+ if (wlc->pub->hw_off || brcms_deviceremoved(wlc))
+ return -ENOMEDIUM;
+
+ if (!wlc->pub->hw_up) {
+ brcms_b_hw_up(wlc->hw);
+ wlc->pub->hw_up = true;
+ }
+
+ if ((wlc->pub->boardflags & BFL_FEM)
+ && (wlc->pub->sih->chip == BCM4313_CHIP_ID)) {
+ if (wlc->pub->boardrev >= 0x1250
+ && (wlc->pub->boardflags & BFL_FEM_BT))
+ brcms_b_mhf(wlc->hw, MHF5, MHF5_4313_GPIOCTRL,
+ MHF5_4313_GPIOCTRL, BRCM_BAND_ALL);
+ else
+ brcms_b_mhf(wlc->hw, MHF4, MHF4_EXTPA_ENABLE,
+ MHF4_EXTPA_ENABLE, BRCM_BAND_ALL);
+ }
+
+ /*
+ * Need to read the hwradio status here to cover the case where the
+ * system is loaded with the hw radio disabled. We do not want to bring
+ * the driver up in this case. If radio is disabled, abort up, lower
+ * power, start radio timer and return 0(for NDIS) don't call
+ * radio_update to avoid looping brcms_c_up.
+ *
+ * brcms_b_up_prep() returns either 0 or -BCME_RADIOOFF only
+ */
+ if (!wlc->pub->radio_disabled) {
+ int status = brcms_b_up_prep(wlc->hw);
+ if (status == -ENOMEDIUM) {
+ if (!mboolisset
+ (wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE)) {
+ struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
+ mboolset(wlc->pub->radio_disabled,
+ WL_RADIO_HW_DISABLE);
+
+ if (bsscfg->enable && bsscfg->BSS)
+ wiphy_err(wlc->wiphy, "wl%d: up"
+ ": rfdisable -> "
+ "bsscfg_disable()\n",
+ wlc->pub->unit);
+ }
+ }
+ }
+
+ if (wlc->pub->radio_disabled) {
+ brcms_c_radio_monitor_start(wlc);
+ return 0;
+ }
+
+ /* brcms_b_up_prep has done brcms_c_corereset(). so clk is on, set it */
+ wlc->clk = true;
+
+ brcms_c_radio_monitor_stop(wlc);
+
+ /* Set EDCF hostflags */
+ brcms_b_mhf(wlc->hw, MHF1, MHF1_EDCF, MHF1_EDCF, BRCM_BAND_ALL);
+
+ brcms_init(wlc->wl);
+ wlc->pub->up = true;
+
+ if (wlc->bandinit_pending) {
+ brcms_c_suspend_mac_and_wait(wlc);
+ brcms_c_set_chanspec(wlc, wlc->default_bss->chanspec);
+ wlc->bandinit_pending = false;
+ brcms_c_enable_mac(wlc);
+ }
+
+ brcms_b_up_finish(wlc->hw);
+
+ /* Program the TX wme params with the current settings */
+ brcms_c_wme_retries_write(wlc);
+
+ /* start one second watchdog timer */
+ brcms_add_timer(wlc->wdtimer, TIMER_INTERVAL_WATCHDOG, true);
+ wlc->WDarmed = true;
+
+ /* ensure antenna config is up to date */
+ brcms_c_stf_phy_txant_upd(wlc);
+ /* ensure LDPC config is in sync */
+ brcms_c_ht_update_ldpc(wlc, wlc->stf->ldpc);
+
+ return 0;
+}
+
+static uint brcms_c_down_del_timer(struct brcms_c_info *wlc)
+{
+ uint callbacks = 0;
+
+ return callbacks;
+}
+
+static int brcms_b_bmac_down_prep(struct brcms_hardware *wlc_hw)
+{
+ bool dev_gone;
+ uint callbacks = 0;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ if (!wlc_hw->up)
+ return callbacks;
+
+ dev_gone = brcms_deviceremoved(wlc_hw->wlc);
+
+ /* disable interrupts */
+ if (dev_gone)
+ wlc_hw->wlc->macintmask = 0;
+ else {
+ /* now disable interrupts */
+ brcms_intrsoff(wlc_hw->wlc->wl);
+
+ /* ensure we're running on the pll clock again */
+ brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
+ }
+ /* down phy at the last of this stage */
+ callbacks += wlc_phy_down(wlc_hw->band->pi);
+
+ return callbacks;
+}
+
+static int brcms_b_down_finish(struct brcms_hardware *wlc_hw)
+{
+ uint callbacks = 0;
+ bool dev_gone;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ if (!wlc_hw->up)
+ return callbacks;
+
+ wlc_hw->up = false;
+ wlc_phy_hw_state_upd(wlc_hw->band->pi, false);
+
+ dev_gone = brcms_deviceremoved(wlc_hw->wlc);
+
+ if (dev_gone) {
+ wlc_hw->sbclk = false;
+ wlc_hw->clk = false;
+ wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
+
+ /* reclaim any posted packets */
+ brcms_c_flushqueues(wlc_hw->wlc);
+ } else {
+
+ /* Reset and disable the core */
+ if (ai_iscoreup(wlc_hw->sih)) {
+ if (R_REG(&wlc_hw->regs->maccontrol) &
+ MCTL_EN_MAC)
+ brcms_c_suspend_mac_and_wait(wlc_hw->wlc);
+ callbacks += brcms_reset(wlc_hw->wlc->wl);
+ brcms_c_coredisable(wlc_hw);
+ }
+
+ /* turn off primary xtal and pll */
+ if (!wlc_hw->noreset) {
+ ai_pci_down(wlc_hw->sih);
+ brcms_b_xtal(wlc_hw, OFF);
+ }
+ }
+
+ return callbacks;
+}
+
+/*
+ * Mark the interface nonoperational, stop the software mechanisms,
+ * disable the hardware, free any transient buffer state.
+ * Return a count of the number of driver callbacks still pending.
+ */
+uint brcms_c_down(struct brcms_c_info *wlc)
+{
+
+ uint callbacks = 0;
+ int i;
+ bool dev_gone = false;
+ struct brcms_txq_info *qi;
+
+ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+
+ /* check if we are already in the going down path */
+ if (wlc->going_down) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: Driver going down so return"
+ "\n", wlc->pub->unit, __func__);
+ return 0;
+ }
+ if (!wlc->pub->up)
+ return callbacks;
+
+ /* in between, mpc could try to bring down again.. */
+ wlc->going_down = true;
+
+ callbacks += brcms_b_bmac_down_prep(wlc->hw);
+
+ dev_gone = brcms_deviceremoved(wlc);
+
+ /* Call any registered down handlers */
+ for (i = 0; i < BRCMS_MAXMODULES; i++) {
+ if (wlc->modulecb[i].down_fn)
+ callbacks +=
+ wlc->modulecb[i].down_fn(wlc->modulecb[i].hdl);
+ }
+
+ /* cancel the watchdog timer */
+ if (wlc->WDarmed) {
+ if (!brcms_del_timer(wlc->wdtimer))
+ callbacks++;
+ wlc->WDarmed = false;
+ }
+ /* cancel all other timers */
+ callbacks += brcms_c_down_del_timer(wlc);
+
+ wlc->pub->up = false;
+
+ wlc_phy_mute_upd(wlc->band->pi, false, PHY_MUTE_ALL);
+
+ /* clear txq flow control */
+ brcms_c_txflowcontrol_reset(wlc);
+
+ /* flush tx queues */
+ for (qi = wlc->tx_queues; qi != NULL; qi = qi->next)
+ brcmu_pktq_flush(&qi->q, true, NULL, NULL);
+
+ callbacks += brcms_b_down_finish(wlc->hw);
+
+ /* brcms_b_down_finish has done brcms_c_coredisable(). so clk is off */
+ wlc->clk = false;
+
+ wlc->going_down = false;
+ return callbacks;
+}
+
+/* Set the current gmode configuration */
+int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config)
+{
+ int ret = 0;
+ uint i;
+ struct brcms_c_rateset rs;
+ /* Default to 54g Auto */
+ /* Advertise and use shortslot (-1/0/1 Auto/Off/On) */
+ s8 shortslot = BRCMS_SHORTSLOT_AUTO;
+ bool shortslot_restrict = false; /* Restrict association to stations
+ * that support shortslot
+ */
+ bool ofdm_basic = false; /* Make 6, 12, and 24 basic rates */
+ /* Advertise and use short preambles (-1/0/1 Auto/Off/On) */
+ int preamble = BRCMS_PLCP_LONG;
+ bool preamble_restrict = false; /* Restrict association to stations
+ * that support short preambles
+ */
+ struct brcms_band *band;
+
+ /* if N-support is enabled, allow Gmode set as long as requested
+ * Gmode is not GMODE_LEGACY_B
+ */
+ if ((wlc->pub->_n_enab & SUPPORT_11N) && gmode == GMODE_LEGACY_B)
+ return -ENOTSUPP;
+
+ /* verify that we are dealing with 2G band and grab the band pointer */
+ if (wlc->band->bandtype == BRCM_BAND_2G)
+ band = wlc->band;
+ else if ((wlc->pub->_nbands > 1) &&
+ (wlc->bandstate[OTHERBANDUNIT(wlc)]->bandtype == BRCM_BAND_2G))
+ band = wlc->bandstate[OTHERBANDUNIT(wlc)];
+ else
+ return -EINVAL;
+
+ /* Legacy or bust when no OFDM is supported by regulatory */
+ if ((brcms_c_channel_locale_flags_in_band(wlc->cmi, band->bandunit) &
+ BRCMS_NO_OFDM) && (gmode != GMODE_LEGACY_B))
+ return -EINVAL;
+
+ /* update configuration value */
+ if (config == true)
+ brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode);
+
+ /* Clear rateset override */
+ memset(&rs, 0, sizeof(struct brcms_c_rateset));
+
+ switch (gmode) {
+ case GMODE_LEGACY_B:
+ shortslot = BRCMS_SHORTSLOT_OFF;
+ brcms_c_rateset_copy(&gphy_legacy_rates, &rs);
+
+ break;
+
+ case GMODE_LRS:
+ break;
+
+ case GMODE_AUTO:
+ /* Accept defaults */
+ break;
+
+ case GMODE_ONLY:
+ ofdm_basic = true;
+ preamble = BRCMS_PLCP_SHORT;
+ preamble_restrict = true;
+ break;
+
+ case GMODE_PERFORMANCE:
+ shortslot = BRCMS_SHORTSLOT_ON;
+ shortslot_restrict = true;
+ ofdm_basic = true;
+ preamble = BRCMS_PLCP_SHORT;
+ preamble_restrict = true;
+ break;
+
+ default:
+ /* Error */
+ wiphy_err(wlc->wiphy, "wl%d: %s: invalid gmode %d\n",
+ wlc->pub->unit, __func__, gmode);
+ return -ENOTSUPP;
+ }
+
+ band->gmode = gmode;
+
+ wlc->shortslot_override = shortslot;
+
+ /* Use the default 11g rateset */
+ if (!rs.count)
+ brcms_c_rateset_copy(&cck_ofdm_rates, &rs);
+
+ if (ofdm_basic) {
+ for (i = 0; i < rs.count; i++) {
+ if (rs.rates[i] == BRCM_RATE_6M
+ || rs.rates[i] == BRCM_RATE_12M
+ || rs.rates[i] == BRCM_RATE_24M)
+ rs.rates[i] |= BRCMS_RATE_FLAG;
+ }
+ }
+
+ /* Set default bss rateset */
+ wlc->default_bss->rateset.count = rs.count;
+ memcpy(wlc->default_bss->rateset.rates, rs.rates,
+ sizeof(wlc->default_bss->rateset.rates));
+
+ return ret;
+}
+
+int brcms_c_set_nmode(struct brcms_c_info *wlc)
+{
+ uint i;
+ s32 nmode = AUTO;
+
+ if (wlc->stf->txstreams == WL_11N_3x3)
+ nmode = WL_11N_3x3;
+ else
+ nmode = WL_11N_2x2;
+
+ /* force GMODE_AUTO if NMODE is ON */
+ brcms_c_set_gmode(wlc, GMODE_AUTO, true);
+ if (nmode == WL_11N_3x3)
+ wlc->pub->_n_enab = SUPPORT_HT;
+ else
+ wlc->pub->_n_enab = SUPPORT_11N;
+ wlc->default_bss->flags |= BRCMS_BSS_HT;
+ /* add the mcs rates to the default and hw ratesets */
+ brcms_c_rateset_mcs_build(&wlc->default_bss->rateset,
+ wlc->stf->txstreams);
+ for (i = 0; i < wlc->pub->_nbands; i++)
+ memcpy(wlc->bandstate[i]->hw_rateset.mcs,
+ wlc->default_bss->rateset.mcs, MCSSET_LEN);
+
+ return 0;
+}
+
+static int
+brcms_c_set_internal_rateset(struct brcms_c_info *wlc,
+ struct brcms_c_rateset *rs_arg)
+{
+ struct brcms_c_rateset rs, new;
+ uint bandunit;
+
+ memcpy(&rs, rs_arg, sizeof(struct brcms_c_rateset));
+
+ /* check for bad count value */
+ if ((rs.count == 0) || (rs.count > BRCMS_NUMRATES))
+ return -EINVAL;
+
+ /* try the current band */
+ bandunit = wlc->band->bandunit;
+ memcpy(&new, &rs, sizeof(struct brcms_c_rateset));
+ if (brcms_c_rate_hwrs_filter_sort_validate
+ (&new, &wlc->bandstate[bandunit]->hw_rateset, true,
+ wlc->stf->txstreams))
+ goto good;
+
+ /* try the other band */
+ if (brcms_is_mband_unlocked(wlc)) {
+ bandunit = OTHERBANDUNIT(wlc);
+ memcpy(&new, &rs, sizeof(struct brcms_c_rateset));
+ if (brcms_c_rate_hwrs_filter_sort_validate(&new,
+ &wlc->
+ bandstate[bandunit]->
+ hw_rateset, true,
+ wlc->stf->txstreams))
+ goto good;
+ }
+
+ return -EBADE;
+
+ good:
+ /* apply new rateset */
+ memcpy(&wlc->default_bss->rateset, &new,
+ sizeof(struct brcms_c_rateset));
+ memcpy(&wlc->bandstate[bandunit]->defrateset, &new,
+ sizeof(struct brcms_c_rateset));
+ return 0;
+}
+
+static void brcms_c_ofdm_rateset_war(struct brcms_c_info *wlc)
+{
+ u8 r;
+ bool war = false;
+
+ if (wlc->bsscfg->associated)
+ r = wlc->bsscfg->current_bss->rateset.rates[0];
+ else
+ r = wlc->default_bss->rateset.rates[0];
+
+ wlc_phy_ofdm_rateset_war(wlc->band->pi, war);
+}
+
+int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel)
+{
+ u16 chspec = ch20mhz_chspec(channel);
+
+ if (channel < 0 || channel > MAXCHANNEL)
+ return -EINVAL;
+
+ if (!brcms_c_valid_chanspec_db(wlc->cmi, chspec))
+ return -EINVAL;
+
+
+ if (!wlc->pub->up && brcms_is_mband_unlocked(wlc)) {
+ if (wlc->band->bandunit != chspec_bandunit(chspec))
+ wlc->bandinit_pending = true;
+ else
+ wlc->bandinit_pending = false;
+ }
+
+ wlc->default_bss->chanspec = chspec;
+ /* brcms_c_BSSinit() will sanitize the rateset before
+ * using it.. */
+ if (wlc->pub->up && (wlc_phy_chanspec_get(wlc->band->pi) != chspec)) {
+ brcms_c_set_home_chanspec(wlc, chspec);
+ brcms_c_suspend_mac_and_wait(wlc);
+ brcms_c_set_chanspec(wlc, chspec);
+ brcms_c_enable_mac(wlc);
+ }
+ return 0;
+}
+
+int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl)
+{
+ int ac;
+
+ if (srl < 1 || srl > RETRY_SHORT_MAX ||
+ lrl < 1 || lrl > RETRY_SHORT_MAX)
+ return -EINVAL;
+
+ wlc->SRL = srl;
+ wlc->LRL = lrl;
+
+ brcms_b_retrylimit_upd(wlc->hw, wlc->SRL, wlc->LRL);
+
+ for (ac = 0; ac < AC_COUNT; ac++) {
+ wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac],
+ EDCF_SHORT, wlc->SRL);
+ wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac],
+ EDCF_LONG, wlc->LRL);
+ }
+ brcms_c_wme_retries_write(wlc);
+
+ return 0;
+}
+
+void brcms_c_get_current_rateset(struct brcms_c_info *wlc,
+ struct brcm_rateset *currs)
+{
+ struct brcms_c_rateset *rs;
+
+ if (wlc->pub->associated)
+ rs = &wlc->bsscfg->current_bss->rateset;
+ else
+ rs = &wlc->default_bss->rateset;
+
+ /* Copy only legacy rateset section */
+ currs->count = rs->count;
+ memcpy(&currs->rates, &rs->rates, rs->count);
+}
+
+int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs)
+{
+ struct brcms_c_rateset internal_rs;
+ int bcmerror;
+
+ if (rs->count > BRCMS_NUMRATES)
+ return -ENOBUFS;
+
+ memset(&internal_rs, 0, sizeof(struct brcms_c_rateset));
+
+ /* Copy only legacy rateset section */
+ internal_rs.count = rs->count;
+ memcpy(&internal_rs.rates, &rs->rates, internal_rs.count);
+
+ /* merge rateset coming in with the current mcsset */
+ if (wlc->pub->_n_enab & SUPPORT_11N) {
+ struct brcms_bss_info *mcsset_bss;
+ if (wlc->bsscfg->associated)
+ mcsset_bss = wlc->bsscfg->current_bss;
+ else
+ mcsset_bss = wlc->default_bss;
+ memcpy(internal_rs.mcs, &mcsset_bss->rateset.mcs[0],
+ MCSSET_LEN);
+ }
+
+ bcmerror = brcms_c_set_internal_rateset(wlc, &internal_rs);
+ if (!bcmerror)
+ brcms_c_ofdm_rateset_war(wlc);
+
+ return bcmerror;
+}
+
+int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period)
+{
+ if (period < DOT11_MIN_BEACON_PERIOD ||
+ period > DOT11_MAX_BEACON_PERIOD)
+ return -EINVAL;
+
+ wlc->default_bss->beacon_period = period;
+ return 0;
+}
+
+u16 brcms_c_get_phy_type(struct brcms_c_info *wlc, int phyidx)
+{
+ return wlc->band->phytype;
+}
+
+void brcms_c_set_shortslot_override(struct brcms_c_info *wlc, s8 sslot_override)
+{
+ wlc->shortslot_override = sslot_override;
+
+ /*
+ * shortslot is an 11g feature, so no more work if we are
+ * currently on the 5G band
+ */
+ if (wlc->band->bandtype == BRCM_BAND_5G)
+ return;
+
+ if (wlc->pub->up && wlc->pub->associated) {
+ /* let watchdog or beacon processing update shortslot */
+ } else if (wlc->pub->up) {
+ /* unassociated shortslot is off */
+ brcms_c_switch_shortslot(wlc, false);
+ } else {
+ /* driver is down, so just update the brcms_c_info
+ * value */
+ if (wlc->shortslot_override == BRCMS_SHORTSLOT_AUTO)
+ wlc->shortslot = false;
+ else
+ wlc->shortslot =
+ (wlc->shortslot_override ==
+ BRCMS_SHORTSLOT_ON);
+ }
+}
+
+/*
+ * register watchdog and down handlers.
+ */
+int brcms_c_module_register(struct brcms_pub *pub,
+ const char *name, struct brcms_info *hdl,
+ int (*d_fn)(void *handle))
+{
+ struct brcms_c_info *wlc = (struct brcms_c_info *) pub->wlc;
+ int i;
+
+ /* find an empty entry and just add, no duplication check! */
+ for (i = 0; i < BRCMS_MAXMODULES; i++) {
+ if (wlc->modulecb[i].name[0] == '\0') {
+ strncpy(wlc->modulecb[i].name, name,
+ sizeof(wlc->modulecb[i].name) - 1);
+ wlc->modulecb[i].hdl = hdl;
+ wlc->modulecb[i].down_fn = d_fn;
+ return 0;
+ }
+ }
+
+ return -ENOSR;
+}
+
+/* unregister module callbacks */
+int brcms_c_module_unregister(struct brcms_pub *pub, const char *name,
+ struct brcms_info *hdl)
+{
+ struct brcms_c_info *wlc = (struct brcms_c_info *) pub->wlc;
+ int i;
+
+ if (wlc == NULL)
+ return -ENODATA;
+
+ for (i = 0; i < BRCMS_MAXMODULES; i++) {
+ if (!strcmp(wlc->modulecb[i].name, name) &&
+ (wlc->modulecb[i].hdl == hdl)) {
+ memset(&wlc->modulecb[i], 0, sizeof(struct modulecb));
+ return 0;
+ }
+ }
+
+ /* table not found! */
+ return -ENODATA;
+}
+
+#ifdef BCMDBG
+static const char * const supr_reason[] = {
+ "None", "PMQ Entry", "Flush request",
+ "Previous frag failure", "Channel mismatch",
+ "Lifetime Expiry", "Underflow"
+};
+
+static void brcms_c_print_txs_status(u16 s)
+{
+ printk(KERN_DEBUG "[15:12] %d frame attempts\n",
+ (s & TX_STATUS_FRM_RTX_MASK) >> TX_STATUS_FRM_RTX_SHIFT);
+ printk(KERN_DEBUG " [11:8] %d rts attempts\n",
+ (s & TX_STATUS_RTS_RTX_MASK) >> TX_STATUS_RTS_RTX_SHIFT);
+ printk(KERN_DEBUG " [7] %d PM mode indicated\n",
+ ((s & TX_STATUS_PMINDCTD) ? 1 : 0));
+ printk(KERN_DEBUG " [6] %d intermediate status\n",
+ ((s & TX_STATUS_INTERMEDIATE) ? 1 : 0));
+ printk(KERN_DEBUG " [5] %d AMPDU\n",
+ (s & TX_STATUS_AMPDU) ? 1 : 0);
+ printk(KERN_DEBUG " [4:2] %d Frame Suppressed Reason (%s)\n",
+ ((s & TX_STATUS_SUPR_MASK) >> TX_STATUS_SUPR_SHIFT),
+ supr_reason[(s & TX_STATUS_SUPR_MASK) >> TX_STATUS_SUPR_SHIFT]);
+ printk(KERN_DEBUG " [1] %d acked\n",
+ ((s & TX_STATUS_ACK_RCV) ? 1 : 0));
+}
+#endif /* BCMDBG */
+
+void brcms_c_print_txstatus(struct tx_status *txs)
+{
+#if defined(BCMDBG)
+ u16 s = txs->status;
+ u16 ackphyrxsh = txs->ackphyrxsh;
+
+ printk(KERN_DEBUG "\ntxpkt (MPDU) Complete\n");
+
+ printk(KERN_DEBUG "FrameID: %04x ", txs->frameid);
+ printk(KERN_DEBUG "TxStatus: %04x", s);
+ printk(KERN_DEBUG "\n");
+
+ brcms_c_print_txs_status(s);
+
+ printk(KERN_DEBUG "LastTxTime: %04x ", txs->lasttxtime);
+ printk(KERN_DEBUG "Seq: %04x ", txs->sequence);
+ printk(KERN_DEBUG "PHYTxStatus: %04x ", txs->phyerr);
+ printk(KERN_DEBUG "RxAckRSSI: %04x ",
+ (ackphyrxsh & PRXS1_JSSI_MASK) >> PRXS1_JSSI_SHIFT);
+ printk(KERN_DEBUG "RxAckSQ: %04x",
+ (ackphyrxsh & PRXS1_SQ_MASK) >> PRXS1_SQ_SHIFT);
+ printk(KERN_DEBUG "\n");
+#endif /* defined(BCMDBG) */
+}
+
+bool brcms_c_chipmatch(u16 vendor, u16 device)
+{
+ if (vendor != PCI_VENDOR_ID_BROADCOM) {
+ pr_err("chipmatch: unknown vendor id %04x\n", vendor);
+ return false;
+ }
+
+ if (device == BCM43224_D11N_ID_VEN1)
+ return true;
+ if ((device == BCM43224_D11N_ID) || (device == BCM43225_D11N2G_ID))
+ return true;
+ if (device == BCM4313_D11N2G_ID)
+ return true;
+ if ((device == BCM43236_D11N_ID) || (device == BCM43236_D11N2G_ID))
+ return true;
+
+ pr_err("chipmatch: unknown device id %04x\n", device);
+ return false;
+}
+
+#if defined(BCMDBG)
+void brcms_c_print_txdesc(struct d11txh *txh)
+{
+ u16 mtcl = le16_to_cpu(txh->MacTxControlLow);
+ u16 mtch = le16_to_cpu(txh->MacTxControlHigh);
+ u16 mfc = le16_to_cpu(txh->MacFrameControl);
+ u16 tfest = le16_to_cpu(txh->TxFesTimeNormal);
+ u16 ptcw = le16_to_cpu(txh->PhyTxControlWord);
+ u16 ptcw_1 = le16_to_cpu(txh->PhyTxControlWord_1);
+ u16 ptcw_1_Fbr = le16_to_cpu(txh->PhyTxControlWord_1_Fbr);
+ u16 ptcw_1_Rts = le16_to_cpu(txh->PhyTxControlWord_1_Rts);
+ u16 ptcw_1_FbrRts = le16_to_cpu(txh->PhyTxControlWord_1_FbrRts);
+ u16 mainrates = le16_to_cpu(txh->MainRates);
+ u16 xtraft = le16_to_cpu(txh->XtraFrameTypes);
+ u8 *iv = txh->IV;
+ u8 *ra = txh->TxFrameRA;
+ u16 tfestfb = le16_to_cpu(txh->TxFesTimeFallback);
+ u8 *rtspfb = txh->RTSPLCPFallback;
+ u16 rtsdfb = le16_to_cpu(txh->RTSDurFallback);
+ u8 *fragpfb = txh->FragPLCPFallback;
+ u16 fragdfb = le16_to_cpu(txh->FragDurFallback);
+ u16 mmodelen = le16_to_cpu(txh->MModeLen);
+ u16 mmodefbrlen = le16_to_cpu(txh->MModeFbrLen);
+ u16 tfid = le16_to_cpu(txh->TxFrameID);
+ u16 txs = le16_to_cpu(txh->TxStatus);
+ u16 mnmpdu = le16_to_cpu(txh->MaxNMpdus);
+ u16 mabyte = le16_to_cpu(txh->MaxABytes_MRT);
+ u16 mabyte_f = le16_to_cpu(txh->MaxABytes_FBR);
+ u16 mmbyte = le16_to_cpu(txh->MinMBytes);
+
+ u8 *rtsph = txh->RTSPhyHeader;
+ struct ieee80211_rts rts = txh->rts_frame;
+ char hexbuf[256];
+
+ /* add plcp header along with txh descriptor */
+ printk(KERN_DEBUG "Raw TxDesc + plcp header:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ txh, sizeof(struct d11txh) + 48);
+
+ printk(KERN_DEBUG "TxCtlLow: %04x ", mtcl);
+ printk(KERN_DEBUG "TxCtlHigh: %04x ", mtch);
+ printk(KERN_DEBUG "FC: %04x ", mfc);
+ printk(KERN_DEBUG "FES Time: %04x\n", tfest);
+ printk(KERN_DEBUG "PhyCtl: %04x%s ", ptcw,
+ (ptcw & PHY_TXC_SHORT_HDR) ? " short" : "");
+ printk(KERN_DEBUG "PhyCtl_1: %04x ", ptcw_1);
+ printk(KERN_DEBUG "PhyCtl_1_Fbr: %04x\n", ptcw_1_Fbr);
+ printk(KERN_DEBUG "PhyCtl_1_Rts: %04x ", ptcw_1_Rts);
+ printk(KERN_DEBUG "PhyCtl_1_Fbr_Rts: %04x\n", ptcw_1_FbrRts);
+ printk(KERN_DEBUG "MainRates: %04x ", mainrates);
+ printk(KERN_DEBUG "XtraFrameTypes: %04x ", xtraft);
+ printk(KERN_DEBUG "\n");
+
+ brcmu_format_hex(hexbuf, iv, sizeof(txh->IV));
+ printk(KERN_DEBUG "SecIV: %s\n", hexbuf);
+ brcmu_format_hex(hexbuf, ra, sizeof(txh->TxFrameRA));
+ printk(KERN_DEBUG "RA: %s\n", hexbuf);
+
+ printk(KERN_DEBUG "Fb FES Time: %04x ", tfestfb);
+ brcmu_format_hex(hexbuf, rtspfb, sizeof(txh->RTSPLCPFallback));
+ printk(KERN_DEBUG "RTS PLCP: %s ", hexbuf);
+ printk(KERN_DEBUG "RTS DUR: %04x ", rtsdfb);
+ brcmu_format_hex(hexbuf, fragpfb, sizeof(txh->FragPLCPFallback));
+ printk(KERN_DEBUG "PLCP: %s ", hexbuf);
+ printk(KERN_DEBUG "DUR: %04x", fragdfb);
+ printk(KERN_DEBUG "\n");
+
+ printk(KERN_DEBUG "MModeLen: %04x ", mmodelen);
+ printk(KERN_DEBUG "MModeFbrLen: %04x\n", mmodefbrlen);
+
+ printk(KERN_DEBUG "FrameID: %04x\n", tfid);
+ printk(KERN_DEBUG "TxStatus: %04x\n", txs);
+
+ printk(KERN_DEBUG "MaxNumMpdu: %04x\n", mnmpdu);
+ printk(KERN_DEBUG "MaxAggbyte: %04x\n", mabyte);
+ printk(KERN_DEBUG "MaxAggbyte_fb: %04x\n", mabyte_f);
+ printk(KERN_DEBUG "MinByte: %04x\n", mmbyte);
+
+ brcmu_format_hex(hexbuf, rtsph, sizeof(txh->RTSPhyHeader));
+ printk(KERN_DEBUG "RTS PLCP: %s ", hexbuf);
+ brcmu_format_hex(hexbuf, (u8 *) &rts, sizeof(txh->rts_frame));
+ printk(KERN_DEBUG "RTS Frame: %s", hexbuf);
+ printk(KERN_DEBUG "\n");
+}
+#endif /* defined(BCMDBG) */
+
+#if defined(BCMDBG)
+int
+brcms_c_format_flags(const struct brcms_c_bit_desc *bd, u32 flags, char *buf,
+ int len)
+{
+ int i;
+ char *p = buf;
+ char hexstr[16];
+ int slen = 0, nlen = 0;
+ u32 bit;
+ const char *name;
+
+ if (len < 2 || !buf)
+ return 0;
+
+ buf[0] = '\0';
+
+ for (i = 0; flags != 0; i++) {
+ bit = bd[i].bit;
+ name = bd[i].name;
+ if (bit == 0 && flags != 0) {
+ /* print any unnamed bits */
+ snprintf(hexstr, 16, "0x%X", flags);
+ name = hexstr;
+ flags = 0; /* exit loop */
+ } else if ((flags & bit) == 0)
+ continue;
+ flags &= ~bit;
+ nlen = strlen(name);
+ slen += nlen;
+ /* count btwn flag space */
+ if (flags != 0)
+ slen += 1;
+ /* need NULL char as well */
+ if (len <= slen)
+ break;
+ /* copy NULL char but don't count it */
+ strncpy(p, name, nlen + 1);
+ p += nlen;
+ /* copy btwn flag space and NULL char */
+ if (flags != 0)
+ p += snprintf(p, 2, " ");
+ len -= slen;
+ }
+
+ /* indicate the str was too short */
+ if (flags != 0) {
+ if (len < 2)
+ p -= 2 - len; /* overwrite last char */
+ p += snprintf(p, 2, ">");
+ }
+
+ return (int)(p - buf);
+}
+#endif /* defined(BCMDBG) */
+
+#if defined(BCMDBG)
+void brcms_c_print_rxh(struct d11rxhdr *rxh)
+{
+ u16 len = rxh->RxFrameSize;
+ u16 phystatus_0 = rxh->PhyRxStatus_0;
+ u16 phystatus_1 = rxh->PhyRxStatus_1;
+ u16 phystatus_2 = rxh->PhyRxStatus_2;
+ u16 phystatus_3 = rxh->PhyRxStatus_3;
+ u16 macstatus1 = rxh->RxStatus1;
+ u16 macstatus2 = rxh->RxStatus2;
+ char flagstr[64];
+ char lenbuf[20];
+ static const struct brcms_c_bit_desc macstat_flags[] = {
+ {RXS_FCSERR, "FCSErr"},
+ {RXS_RESPFRAMETX, "Reply"},
+ {RXS_PBPRES, "PADDING"},
+ {RXS_DECATMPT, "DeCr"},
+ {RXS_DECERR, "DeCrErr"},
+ {RXS_BCNSENT, "Bcn"},
+ {0, NULL}
+ };
+
+ printk(KERN_DEBUG "Raw RxDesc:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, rxh,
+ sizeof(struct d11rxhdr));
+
+ brcms_c_format_flags(macstat_flags, macstatus1, flagstr, 64);
+
+ snprintf(lenbuf, sizeof(lenbuf), "0x%x", len);
+
+ printk(KERN_DEBUG "RxFrameSize: %6s (%d)%s\n", lenbuf, len,
+ (rxh->PhyRxStatus_0 & PRXS0_SHORTH) ? " short preamble" : "");
+ printk(KERN_DEBUG "RxPHYStatus: %04x %04x %04x %04x\n",
+ phystatus_0, phystatus_1, phystatus_2, phystatus_3);
+ printk(KERN_DEBUG "RxMACStatus: %x %s\n", macstatus1, flagstr);
+ printk(KERN_DEBUG "RXMACaggtype: %x\n",
+ (macstatus2 & RXS_AGGTYPE_MASK));
+ printk(KERN_DEBUG "RxTSFTime: %04x\n", rxh->RxTSFTime);
+}
+#endif /* defined(BCMDBG) */
+
+u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate)
+{
+ u16 table_ptr;
+ u8 phy_rate, index;
+
+ /* get the phy specific rate encoding for the PLCP SIGNAL field */
+ if (is_ofdm_rate(rate))
+ table_ptr = M_RT_DIRMAP_A;
+ else
+ table_ptr = M_RT_DIRMAP_B;
+
+ /* for a given rate, the LS-nibble of the PLCP SIGNAL field is
+ * the index into the rate table.
+ */
+ phy_rate = rate_info[rate] & BRCMS_RATE_MASK;
+ index = phy_rate & 0xf;
+
+ /* Find the SHM pointer to the rate table entry by looking in the
+ * Direct-map Table
+ */
+ return 2 * brcms_b_read_shm(wlc_hw, table_ptr + (index * 2));
+}
+
+static bool
+brcms_c_prec_enq_head(struct brcms_c_info *wlc, struct pktq *q,
+ struct sk_buff *pkt, int prec, bool head)
+{
+ struct sk_buff *p;
+ int eprec = -1; /* precedence to evict from */
+
+ /* Determine precedence from which to evict packet, if any */
+ if (pktq_pfull(q, prec))
+ eprec = prec;
+ else if (pktq_full(q)) {
+ p = brcmu_pktq_peek_tail(q, &eprec);
+ if (eprec > prec) {
+ wiphy_err(wlc->wiphy, "%s: Failing: eprec %d > prec %d"
+ "\n", __func__, eprec, prec);
+ return false;
+ }
+ }
+
+ /* Evict if needed */
+ if (eprec >= 0) {
+ bool discard_oldest;
+
+ discard_oldest = ac_bitmap_tst(0, eprec);
+
+ /* Refuse newer packet unless configured to discard oldest */
+ if (eprec == prec && !discard_oldest) {
+ wiphy_err(wlc->wiphy, "%s: No where to go, prec == %d"
+ "\n", __func__, prec);
+ return false;
+ }
+
+ /* Evict packet according to discard policy */
+ p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) :
+ brcmu_pktq_pdeq_tail(q, eprec);
+ brcmu_pkt_buf_free_skb(p);
+ }
+
+ /* Enqueue */
+ if (head)
+ p = brcmu_pktq_penq_head(q, prec, pkt);
+ else
+ p = brcmu_pktq_penq(q, prec, pkt);
+
+ return true;
+}
+
+/*
+ * Attempts to queue a packet onto a multiple-precedence queue,
+ * if necessary evicting a lower precedence packet from the queue.
+ *
+ * 'prec' is the precedence number that has already been mapped
+ * from the packet priority.
+ *
+ * Returns true if packet consumed (queued), false if not.
+ */
+static bool brcms_c_prec_enq(struct brcms_c_info *wlc, struct pktq *q,
+ struct sk_buff *pkt, int prec)
+{
+ return brcms_c_prec_enq_head(wlc, q, pkt, prec, false);
+}
+
+void brcms_c_txq_enq(struct brcms_c_info *wlc, struct scb *scb,
+ struct sk_buff *sdu, uint prec)
+{
+ struct brcms_txq_info *qi = wlc->pkt_queue; /* Check me */
+ struct pktq *q = &qi->q;
+ int prio;
+
+ prio = sdu->priority;
+
+ if (!brcms_c_prec_enq(wlc, q, sdu, prec)) {
+ /*
+ * we might hit this condtion in case
+ * packet flooding from mac80211 stack
+ */
+ brcmu_pkt_buf_free_skb(sdu);
+ }
+}
+
+/*
+ * bcmc_fid_generate:
+ * Generate frame ID for a BCMC packet. The frag field is not used
+ * for MC frames so is used as part of the sequence number.
+ */
+static inline u16
+bcmc_fid_generate(struct brcms_c_info *wlc, struct brcms_bss_cfg *bsscfg,
+ struct d11txh *txh)
+{
+ u16 frameid;
+
+ frameid = le16_to_cpu(txh->TxFrameID) & ~(TXFID_SEQ_MASK |
+ TXFID_QUEUE_MASK);
+ frameid |=
+ (((wlc->
+ mc_fid_counter++) << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) |
+ TX_BCMC_FIFO;
+
+ return frameid;
+}
+
+static uint
+brcms_c_calc_ack_time(struct brcms_c_info *wlc, u32 rspec,
+ u8 preamble_type)
+{
+ uint dur = 0;
+
+ BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d\n",
+ wlc->pub->unit, rspec, preamble_type);
+ /*
+ * Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that
+ * is less than or equal to the rate of the immediately previous
+ * frame in the FES
+ */
+ rspec = brcms_basic_rate(wlc, rspec);
+ /* ACK frame len == 14 == 2(fc) + 2(dur) + 6(ra) + 4(fcs) */
+ dur =
+ brcms_c_calc_frame_time(wlc, rspec, preamble_type,
+ (DOT11_ACK_LEN + FCS_LEN));
+ return dur;
+}
+
+static uint
+brcms_c_calc_cts_time(struct brcms_c_info *wlc, u32 rspec,
+ u8 preamble_type)
+{
+ BCMMSG(wlc->wiphy, "wl%d: ratespec 0x%x, preamble_type %d\n",
+ wlc->pub->unit, rspec, preamble_type);
+ return brcms_c_calc_ack_time(wlc, rspec, preamble_type);
+}
+
+static uint
+brcms_c_calc_ba_time(struct brcms_c_info *wlc, u32 rspec,
+ u8 preamble_type)
+{
+ BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, "
+ "preamble_type %d\n", wlc->pub->unit, rspec, preamble_type);
+ /*
+ * Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that
+ * is less than or equal to the rate of the immediately previous
+ * frame in the FES
+ */
+ rspec = brcms_basic_rate(wlc, rspec);
+ /* BA len == 32 == 16(ctl hdr) + 4(ba len) + 8(bitmap) + 4(fcs) */
+ return brcms_c_calc_frame_time(wlc, rspec, preamble_type,
+ (DOT11_BA_LEN + DOT11_BA_BITMAP_LEN +
+ FCS_LEN));
+}
+
+/* brcms_c_compute_frame_dur()
+ *
+ * Calculate the 802.11 MAC header DUR field for MPDU
+ * DUR for a single frame = 1 SIFS + 1 ACK
+ * DUR for a frame with following frags = 3 SIFS + 2 ACK + next frag time
+ *
+ * rate MPDU rate in unit of 500kbps
+ * next_frag_len next MPDU length in bytes
+ * preamble_type use short/GF or long/MM PLCP header
+ */
+static u16
+brcms_c_compute_frame_dur(struct brcms_c_info *wlc, u32 rate,
+ u8 preamble_type, uint next_frag_len)
+{
+ u16 dur, sifs;
+
+ sifs = get_sifs(wlc->band);
+
+ dur = sifs;
+ dur += (u16) brcms_c_calc_ack_time(wlc, rate, preamble_type);
+
+ if (next_frag_len) {
+ /* Double the current DUR to get 2 SIFS + 2 ACKs */
+ dur *= 2;
+ /* add another SIFS and the frag time */
+ dur += sifs;
+ dur +=
+ (u16) brcms_c_calc_frame_time(wlc, rate, preamble_type,
+ next_frag_len);
+ }
+ return dur;
+}
+
+/* The opposite of brcms_c_calc_frame_time */
+static uint
+brcms_c_calc_frame_len(struct brcms_c_info *wlc, u32 ratespec,
+ u8 preamble_type, uint dur)
+{
+ uint nsyms, mac_len, Ndps, kNdps;
+ uint rate = rspec2rate(ratespec);
+
+ BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, dur %d\n",
+ wlc->pub->unit, ratespec, preamble_type, dur);
+
+ if (is_mcs_rate(ratespec)) {
+ uint mcs = ratespec & RSPEC_RATE_MASK;
+ int tot_streams = mcs_2_txstreams(mcs) + rspec_stc(ratespec);
+ dur -= PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT);
+ /* payload calculation matches that of regular ofdm */
+ if (wlc->band->bandtype == BRCM_BAND_2G)
+ dur -= DOT11_OFDM_SIGNAL_EXTENSION;
+ /* kNdbps = kbps * 4 */
+ kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec),
+ rspec_issgi(ratespec)) * 4;
+ nsyms = dur / APHY_SYMBOL_TIME;
+ mac_len =
+ ((nsyms * kNdps) -
+ ((APHY_SERVICE_NBITS + APHY_TAIL_NBITS) * 1000)) / 8000;
+ } else if (is_ofdm_rate(ratespec)) {
+ dur -= APHY_PREAMBLE_TIME;
+ dur -= APHY_SIGNAL_TIME;
+ /* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */
+ Ndps = rate * 2;
+ nsyms = dur / APHY_SYMBOL_TIME;
+ mac_len =
+ ((nsyms * Ndps) -
+ (APHY_SERVICE_NBITS + APHY_TAIL_NBITS)) / 8;
+ } else {
+ if (preamble_type & BRCMS_SHORT_PREAMBLE)
+ dur -= BPHY_PLCP_SHORT_TIME;
+ else
+ dur -= BPHY_PLCP_TIME;
+ mac_len = dur * rate;
+ /* divide out factor of 2 in rate (1/2 mbps) */
+ mac_len = mac_len / 8 / 2;
+ }
+ return mac_len;
+}
+
+/*
+ * Return true if the specified rate is supported by the specified band.
+ * BRCM_BAND_AUTO indicates the current band.
+ */
+static bool brcms_c_valid_rate(struct brcms_c_info *wlc, u32 rspec, int band,
+ bool verbose)
+{
+ struct brcms_c_rateset *hw_rateset;
+ uint i;
+
+ if ((band == BRCM_BAND_AUTO) || (band == wlc->band->bandtype))
+ hw_rateset = &wlc->band->hw_rateset;
+ else if (wlc->pub->_nbands > 1)
+ hw_rateset = &wlc->bandstate[OTHERBANDUNIT(wlc)]->hw_rateset;
+ else
+ /* other band specified and we are a single band device */
+ return false;
+
+ /* check if this is a mimo rate */
+ if (is_mcs_rate(rspec)) {
+ if ((rspec & RSPEC_RATE_MASK) >= MCS_TABLE_SIZE)
+ goto error;
+
+ return isset(hw_rateset->mcs, (rspec & RSPEC_RATE_MASK));
+ }
+
+ for (i = 0; i < hw_rateset->count; i++)
+ if (hw_rateset->rates[i] == rspec2rate(rspec))
+ return true;
+ error:
+ if (verbose)
+ wiphy_err(wlc->wiphy, "wl%d: valid_rate: rate spec 0x%x "
+ "not in hw_rateset\n", wlc->pub->unit, rspec);
+
+ return false;
+}
+
+static u32
+mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band,
+ u32 int_val)
+{
+ u8 stf = (int_val & NRATE_STF_MASK) >> NRATE_STF_SHIFT;
+ u8 rate = int_val & NRATE_RATE_MASK;
+ u32 rspec;
+ bool ismcs = ((int_val & NRATE_MCS_INUSE) == NRATE_MCS_INUSE);
+ bool issgi = ((int_val & NRATE_SGI_MASK) >> NRATE_SGI_SHIFT);
+ bool override_mcs_only = ((int_val & NRATE_OVERRIDE_MCS_ONLY)
+ == NRATE_OVERRIDE_MCS_ONLY);
+ int bcmerror = 0;
+
+ if (!ismcs)
+ return (u32) rate;
+
+ /* validate the combination of rate/mcs/stf is allowed */
+ if ((wlc->pub->_n_enab & SUPPORT_11N) && ismcs) {
+ /* mcs only allowed when nmode */
+ if (stf > PHY_TXC1_MODE_SDM) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: Invalid stf\n",
+ wlc->pub->unit, __func__);
+ bcmerror = -EINVAL;
+ goto done;
+ }
+
+ /* mcs 32 is a special case, DUP mode 40 only */
+ if (rate == 32) {
+ if (!CHSPEC_IS40(wlc->home_chanspec) ||
+ ((stf != PHY_TXC1_MODE_SISO)
+ && (stf != PHY_TXC1_MODE_CDD))) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: Invalid mcs "
+ "32\n", wlc->pub->unit, __func__);
+ bcmerror = -EINVAL;
+ goto done;
+ }
+ /* mcs > 7 must use stf SDM */
+ } else if (rate > HIGHEST_SINGLE_STREAM_MCS) {
+ /* mcs > 7 must use stf SDM */
+ if (stf != PHY_TXC1_MODE_SDM) {
+ BCMMSG(wlc->wiphy, "wl%d: enabling "
+ "SDM mode for mcs %d\n",
+ wlc->pub->unit, rate);
+ stf = PHY_TXC1_MODE_SDM;
+ }
+ } else {
+ /*
+ * MCS 0-7 may use SISO, CDD, and for
+ * phy_rev >= 3 STBC
+ */
+ if ((stf > PHY_TXC1_MODE_STBC) ||
+ (!BRCMS_STBC_CAP_PHY(wlc)
+ && (stf == PHY_TXC1_MODE_STBC))) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: Invalid STBC"
+ "\n", wlc->pub->unit, __func__);
+ bcmerror = -EINVAL;
+ goto done;
+ }
+ }
+ } else if (is_ofdm_rate(rate)) {
+ if ((stf != PHY_TXC1_MODE_CDD) && (stf != PHY_TXC1_MODE_SISO)) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: Invalid OFDM\n",
+ wlc->pub->unit, __func__);
+ bcmerror = -EINVAL;
+ goto done;
+ }
+ } else if (is_cck_rate(rate)) {
+ if ((cur_band->bandtype != BRCM_BAND_2G)
+ || (stf != PHY_TXC1_MODE_SISO)) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: Invalid CCK\n",
+ wlc->pub->unit, __func__);
+ bcmerror = -EINVAL;
+ goto done;
+ }
+ } else {
+ wiphy_err(wlc->wiphy, "wl%d: %s: Unknown rate type\n",
+ wlc->pub->unit, __func__);
+ bcmerror = -EINVAL;
+ goto done;
+ }
+ /* make sure multiple antennae are available for non-siso rates */
+ if ((stf != PHY_TXC1_MODE_SISO) && (wlc->stf->txstreams == 1)) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: SISO antenna but !SISO "
+ "request\n", wlc->pub->unit, __func__);
+ bcmerror = -EINVAL;
+ goto done;
+ }
+
+ rspec = rate;
+ if (ismcs) {
+ rspec |= RSPEC_MIMORATE;
+ /* For STBC populate the STC field of the ratespec */
+ if (stf == PHY_TXC1_MODE_STBC) {
+ u8 stc;
+ stc = 1; /* Nss for single stream is always 1 */
+ rspec |= (stc << RSPEC_STC_SHIFT);
+ }
+ }
+
+ rspec |= (stf << RSPEC_STF_SHIFT);
+
+ if (override_mcs_only)
+ rspec |= RSPEC_OVERRIDE_MCS_ONLY;
+
+ if (issgi)
+ rspec |= RSPEC_SHORT_GI;
+
+ if ((rate != 0)
+ && !brcms_c_valid_rate(wlc, rspec, cur_band->bandtype, true))
+ return rate;
+
+ return rspec;
+done:
+ return rate;
+}
+
+/*
+ * Compute PLCP, but only requires actual rate and length of pkt.
+ * Rate is given in the driver standard multiple of 500 kbps.
+ * le is set for 11 Mbps rate if necessary.
+ * Broken out for PRQ.
+ */
+
+static void brcms_c_cck_plcp_set(struct brcms_c_info *wlc, int rate_500,
+ uint length, u8 *plcp)
+{
+ u16 usec = 0;
+ u8 le = 0;
+
+ switch (rate_500) {
+ case BRCM_RATE_1M:
+ usec = length << 3;
+ break;
+ case BRCM_RATE_2M:
+ usec = length << 2;
+ break;
+ case BRCM_RATE_5M5:
+ usec = (length << 4) / 11;
+ if ((length << 4) - (usec * 11) > 0)
+ usec++;
+ break;
+ case BRCM_RATE_11M:
+ usec = (length << 3) / 11;
+ if ((length << 3) - (usec * 11) > 0) {
+ usec++;
+ if ((usec * 11) - (length << 3) >= 8)
+ le = D11B_PLCP_SIGNAL_LE;
+ }
+ break;
+
+ default:
+ wiphy_err(wlc->wiphy,
+ "brcms_c_cck_plcp_set: unsupported rate %d\n",
+ rate_500);
+ rate_500 = BRCM_RATE_1M;
+ usec = length << 3;
+ break;
+ }
+ /* PLCP signal byte */
+ plcp[0] = rate_500 * 5; /* r (500kbps) * 5 == r (100kbps) */
+ /* PLCP service byte */
+ plcp[1] = (u8) (le | D11B_PLCP_SIGNAL_LOCKED);
+ /* PLCP length u16, little endian */
+ plcp[2] = usec & 0xff;
+ plcp[3] = (usec >> 8) & 0xff;
+ /* PLCP CRC16 */
+ plcp[4] = 0;
+ plcp[5] = 0;
+}
+
+/* Rate: 802.11 rate code, length: PSDU length in octets */
+static void brcms_c_compute_mimo_plcp(u32 rspec, uint length, u8 *plcp)
+{
+ u8 mcs = (u8) (rspec & RSPEC_RATE_MASK);
+ plcp[0] = mcs;
+ if (rspec_is40mhz(rspec) || (mcs == 32))
+ plcp[0] |= MIMO_PLCP_40MHZ;
+ BRCMS_SET_MIMO_PLCP_LEN(plcp, length);
+ plcp[3] = rspec_mimoplcp3(rspec); /* rspec already holds this byte */
+ plcp[3] |= 0x7; /* set smoothing, not sounding ppdu & reserved */
+ plcp[4] = 0; /* number of extension spatial streams bit 0 & 1 */
+ plcp[5] = 0;
+}
+
+/* Rate: 802.11 rate code, length: PSDU length in octets */
+static void
+brcms_c_compute_ofdm_plcp(u32 rspec, u32 length, u8 *plcp)
+{
+ u8 rate_signal;
+ u32 tmp = 0;
+ int rate = rspec2rate(rspec);
+
+ /*
+ * encode rate per 802.11a-1999 sec 17.3.4.1, with lsb
+ * transmitted first
+ */
+ rate_signal = rate_info[rate] & BRCMS_RATE_MASK;
+ memset(plcp, 0, D11_PHY_HDR_LEN);
+ D11A_PHY_HDR_SRATE((struct ofdm_phy_hdr *) plcp, rate_signal);
+
+ tmp = (length & 0xfff) << 5;
+ plcp[2] |= (tmp >> 16) & 0xff;
+ plcp[1] |= (tmp >> 8) & 0xff;
+ plcp[0] |= tmp & 0xff;
+}
+
+/* Rate: 802.11 rate code, length: PSDU length in octets */
+static void brcms_c_compute_cck_plcp(struct brcms_c_info *wlc, u32 rspec,
+ uint length, u8 *plcp)
+{
+ int rate = rspec2rate(rspec);
+
+ brcms_c_cck_plcp_set(wlc, rate, length, plcp);
+}
+
+static void
+brcms_c_compute_plcp(struct brcms_c_info *wlc, u32 rspec,
+ uint length, u8 *plcp)
+{
+ if (is_mcs_rate(rspec))
+ brcms_c_compute_mimo_plcp(rspec, length, plcp);
+ else if (is_ofdm_rate(rspec))
+ brcms_c_compute_ofdm_plcp(rspec, length, plcp);
+ else
+ brcms_c_compute_cck_plcp(wlc, rspec, length, plcp);
+}
+
+/* brcms_c_compute_rtscts_dur()
+ *
+ * Calculate the 802.11 MAC header DUR field for an RTS or CTS frame
+ * DUR for normal RTS/CTS w/ frame = 3 SIFS + 1 CTS + next frame time + 1 ACK
+ * DUR for CTS-TO-SELF w/ frame = 2 SIFS + next frame time + 1 ACK
+ *
+ * cts cts-to-self or rts/cts
+ * rts_rate rts or cts rate in unit of 500kbps
+ * rate next MPDU rate in unit of 500kbps
+ * frame_len next MPDU frame length in bytes
+ */
+u16
+brcms_c_compute_rtscts_dur(struct brcms_c_info *wlc, bool cts_only,
+ u32 rts_rate,
+ u32 frame_rate, u8 rts_preamble_type,
+ u8 frame_preamble_type, uint frame_len, bool ba)
+{
+ u16 dur, sifs;
+
+ sifs = get_sifs(wlc->band);
+
+ if (!cts_only) {
+ /* RTS/CTS */
+ dur = 3 * sifs;
+ dur +=
+ (u16) brcms_c_calc_cts_time(wlc, rts_rate,
+ rts_preamble_type);
+ } else {
+ /* CTS-TO-SELF */
+ dur = 2 * sifs;
+ }
+
+ dur +=
+ (u16) brcms_c_calc_frame_time(wlc, frame_rate, frame_preamble_type,
+ frame_len);
+ if (ba)
+ dur +=
+ (u16) brcms_c_calc_ba_time(wlc, frame_rate,
+ BRCMS_SHORT_PREAMBLE);
+ else
+ dur +=
+ (u16) brcms_c_calc_ack_time(wlc, frame_rate,
+ frame_preamble_type);
+ return dur;
+}
+
+static u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, u32 rspec)
+{
+ u16 phyctl1 = 0;
+ u16 bw;
+
+ if (BRCMS_ISLCNPHY(wlc->band)) {
+ bw = PHY_TXC1_BW_20MHZ;
+ } else {
+ bw = rspec_get_bw(rspec);
+ /* 10Mhz is not supported yet */
+ if (bw < PHY_TXC1_BW_20MHZ) {
+ wiphy_err(wlc->wiphy, "phytxctl1_calc: bw %d is "
+ "not supported yet, set to 20L\n", bw);
+ bw = PHY_TXC1_BW_20MHZ;
+ }
+ }
+
+ if (is_mcs_rate(rspec)) {
+ uint mcs = rspec & RSPEC_RATE_MASK;
+
+ /* bw, stf, coding-type is part of rspec_phytxbyte2 returns */
+ phyctl1 = rspec_phytxbyte2(rspec);
+ /* set the upper byte of phyctl1 */
+ phyctl1 |= (mcs_table[mcs].tx_phy_ctl3 << 8);
+ } else if (is_cck_rate(rspec) && !BRCMS_ISLCNPHY(wlc->band)
+ && !BRCMS_ISSSLPNPHY(wlc->band)) {
+ /*
+ * In CCK mode LPPHY overloads OFDM Modulation bits with CCK
+ * Data Rate. Eventually MIMOPHY would also be converted to
+ * this format
+ */
+ /* 0 = 1Mbps; 1 = 2Mbps; 2 = 5.5Mbps; 3 = 11Mbps */
+ phyctl1 = (bw | (rspec_stf(rspec) << PHY_TXC1_MODE_SHIFT));
+ } else { /* legacy OFDM/CCK */
+ s16 phycfg;
+ /* get the phyctl byte from rate phycfg table */
+ phycfg = brcms_c_rate_legacy_phyctl(rspec2rate(rspec));
+ if (phycfg == -1) {
+ wiphy_err(wlc->wiphy, "phytxctl1_calc: wrong "
+ "legacy OFDM/CCK rate\n");
+ phycfg = 0;
+ }
+ /* set the upper byte of phyctl1 */
+ phyctl1 =
+ (bw | (phycfg << 8) |
+ (rspec_stf(rspec) << PHY_TXC1_MODE_SHIFT));
+ }
+ return phyctl1;
+}
+
+/*
+ * Add struct d11txh, struct cck_phy_hdr.
+ *
+ * 'p' data must start with 802.11 MAC header
+ * 'p' must allow enough bytes of local headers to be "pushed" onto the packet
+ *
+ * headroom == D11_PHY_HDR_LEN + D11_TXH_LEN (D11_TXH_LEN is now 104 bytes)
+ *
+ */
+static u16
+brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
+ struct sk_buff *p, struct scb *scb, uint frag,
+ uint nfrags, uint queue, uint next_frag_len)
+{
+ struct ieee80211_hdr *h;
+ struct d11txh *txh;
+ u8 *plcp, plcp_fallback[D11_PHY_HDR_LEN];
+ int len, phylen, rts_phylen;
+ u16 mch, phyctl, xfts, mainrates;
+ u16 seq = 0, mcl = 0, status = 0, frameid = 0;
+ u32 rspec[2] = { BRCM_RATE_1M, BRCM_RATE_1M };
+ u32 rts_rspec[2] = { BRCM_RATE_1M, BRCM_RATE_1M };
+ bool use_rts = false;
+ bool use_cts = false;
+ bool use_rifs = false;
+ bool short_preamble[2] = { false, false };
+ u8 preamble_type[2] = { BRCMS_LONG_PREAMBLE, BRCMS_LONG_PREAMBLE };
+ u8 rts_preamble_type[2] = { BRCMS_LONG_PREAMBLE, BRCMS_LONG_PREAMBLE };
+ u8 *rts_plcp, rts_plcp_fallback[D11_PHY_HDR_LEN];
+ struct ieee80211_rts *rts = NULL;
+ bool qos;
+ uint ac;
+ bool hwtkmic = false;
+ u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
+#define ANTCFG_NONE 0xFF
+ u8 antcfg = ANTCFG_NONE;
+ u8 fbantcfg = ANTCFG_NONE;
+ uint phyctl1_stf = 0;
+ u16 durid = 0;
+ struct ieee80211_tx_rate *txrate[2];
+ int k;
+ struct ieee80211_tx_info *tx_info;
+ bool is_mcs;
+ u16 mimo_txbw;
+ u8 mimo_preamble_type;
+
+ /* locate 802.11 MAC header */
+ h = (struct ieee80211_hdr *)(p->data);
+ qos = ieee80211_is_data_qos(h->frame_control);
+
+ /* compute length of frame in bytes for use in PLCP computations */
+ len = brcmu_pkttotlen(p);
+ phylen = len + FCS_LEN;
+
+ /* Get tx_info */
+ tx_info = IEEE80211_SKB_CB(p);
+
+ /* add PLCP */
+ plcp = skb_push(p, D11_PHY_HDR_LEN);
+
+ /* add Broadcom tx descriptor header */
+ txh = (struct d11txh *) skb_push(p, D11_TXH_LEN);
+ memset(txh, 0, D11_TXH_LEN);
+
+ /* setup frameid */
+ if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+ /* non-AP STA should never use BCMC queue */
+ if (queue == TX_BCMC_FIFO) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: ASSERT queue == "
+ "TX_BCMC!\n", wlc->pub->unit, __func__);
+ frameid = bcmc_fid_generate(wlc, NULL, txh);
+ } else {
+ /* Increment the counter for first fragment */
+ if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+ scb->seqnum[p->priority]++;
+
+ /* extract fragment number from frame first */
+ seq = le16_to_cpu(h->seq_ctrl) & FRAGNUM_MASK;
+ seq |= (scb->seqnum[p->priority] << SEQNUM_SHIFT);
+ h->seq_ctrl = cpu_to_le16(seq);
+
+ frameid = ((seq << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) |
+ (queue & TXFID_QUEUE_MASK);
+ }
+ }
+ frameid |= queue & TXFID_QUEUE_MASK;
+
+ /* set the ignpmq bit for all pkts tx'd in PS mode and for beacons */
+ if (ieee80211_is_beacon(h->frame_control))
+ mcl |= TXC_IGNOREPMQ;
+
+ txrate[0] = tx_info->control.rates;
+ txrate[1] = txrate[0] + 1;
+
+ /*
+ * if rate control algorithm didn't give us a fallback
+ * rate, use the primary rate
+ */
+ if (txrate[1]->idx < 0)
+ txrate[1] = txrate[0];
+
+ for (k = 0; k < hw->max_rates; k++) {
+ is_mcs = txrate[k]->flags & IEEE80211_TX_RC_MCS ? true : false;
+ if (!is_mcs) {
+ if ((txrate[k]->idx >= 0)
+ && (txrate[k]->idx <
+ hw->wiphy->bands[tx_info->band]->n_bitrates)) {
+ rspec[k] =
+ hw->wiphy->bands[tx_info->band]->
+ bitrates[txrate[k]->idx].hw_value;
+ short_preamble[k] =
+ txrate[k]->
+ flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE ?
+ true : false;
+ } else {
+ rspec[k] = BRCM_RATE_1M;
+ }
+ } else {
+ rspec[k] = mac80211_wlc_set_nrate(wlc, wlc->band,
+ NRATE_MCS_INUSE | txrate[k]->idx);
+ }
+
+ /*
+ * Currently only support same setting for primay and
+ * fallback rates. Unify flags for each rate into a
+ * single value for the frame
+ */
+ use_rts |=
+ txrate[k]->
+ flags & IEEE80211_TX_RC_USE_RTS_CTS ? true : false;
+ use_cts |=
+ txrate[k]->
+ flags & IEEE80211_TX_RC_USE_CTS_PROTECT ? true : false;
+
+
+ /*
+ * (1) RATE:
+ * determine and validate primary rate
+ * and fallback rates
+ */
+ if (!rspec_active(rspec[k])) {
+ rspec[k] = BRCM_RATE_1M;
+ } else {
+ if (!is_multicast_ether_addr(h->addr1)) {
+ /* set tx antenna config */
+ brcms_c_antsel_antcfg_get(wlc->asi, false,
+ false, 0, 0, &antcfg, &fbantcfg);
+ }
+ }
+ }
+
+ phyctl1_stf = wlc->stf->ss_opmode;
+
+ if (wlc->pub->_n_enab & SUPPORT_11N) {
+ for (k = 0; k < hw->max_rates; k++) {
+ /*
+ * apply siso/cdd to single stream mcs's or ofdm
+ * if rspec is auto selected
+ */
+ if (((is_mcs_rate(rspec[k]) &&
+ is_single_stream(rspec[k] & RSPEC_RATE_MASK)) ||
+ is_ofdm_rate(rspec[k]))
+ && ((rspec[k] & RSPEC_OVERRIDE_MCS_ONLY)
+ || !(rspec[k] & RSPEC_OVERRIDE))) {
+ rspec[k] &= ~(RSPEC_STF_MASK | RSPEC_STC_MASK);
+
+ /* For SISO MCS use STBC if possible */
+ if (is_mcs_rate(rspec[k])
+ && BRCMS_STF_SS_STBC_TX(wlc, scb)) {
+ u8 stc;
+
+ /* Nss for single stream is always 1 */
+ stc = 1;
+ rspec[k] |= (PHY_TXC1_MODE_STBC <<
+ RSPEC_STF_SHIFT) |
+ (stc << RSPEC_STC_SHIFT);
+ } else
+ rspec[k] |=
+ (phyctl1_stf << RSPEC_STF_SHIFT);
+ }
+
+ /*
+ * Is the phy configured to use 40MHZ frames? If
+ * so then pick the desired txbw
+ */
+ if (brcms_chspec_bw(wlc->chanspec) == BRCMS_40_MHZ) {
+ /* default txbw is 20in40 SB */
+ mimo_ctlchbw = mimo_txbw =
+ CHSPEC_SB_UPPER(wlc_phy_chanspec_get(
+ wlc->band->pi))
+ ? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ;
+
+ if (is_mcs_rate(rspec[k])) {
+ /* mcs 32 must be 40b/w DUP */
+ if ((rspec[k] & RSPEC_RATE_MASK)
+ == 32) {
+ mimo_txbw =
+ PHY_TXC1_BW_40MHZ_DUP;
+ /* use override */
+ } else if (wlc->mimo_40txbw != AUTO)
+ mimo_txbw = wlc->mimo_40txbw;
+ /* else check if dst is using 40 Mhz */
+ else if (scb->flags & SCB_IS40)
+ mimo_txbw = PHY_TXC1_BW_40MHZ;
+ } else if (is_ofdm_rate(rspec[k])) {
+ if (wlc->ofdm_40txbw != AUTO)
+ mimo_txbw = wlc->ofdm_40txbw;
+ } else if (wlc->cck_40txbw != AUTO) {
+ mimo_txbw = wlc->cck_40txbw;
+ }
+ } else {
+ /*
+ * mcs32 is 40 b/w only.
+ * This is possible for probe packets on
+ * a STA during SCAN
+ */
+ if ((rspec[k] & RSPEC_RATE_MASK) == 32)
+ /* mcs 0 */
+ rspec[k] = RSPEC_MIMORATE;
+
+ mimo_txbw = PHY_TXC1_BW_20MHZ;
+ }
+
+ /* Set channel width */
+ rspec[k] &= ~RSPEC_BW_MASK;
+ if ((k == 0) || ((k > 0) && is_mcs_rate(rspec[k])))
+ rspec[k] |= (mimo_txbw << RSPEC_BW_SHIFT);
+ else
+ rspec[k] |= (mimo_ctlchbw << RSPEC_BW_SHIFT);
+
+ /* Disable short GI, not supported yet */
+ rspec[k] &= ~RSPEC_SHORT_GI;
+
+ mimo_preamble_type = BRCMS_MM_PREAMBLE;
+ if (txrate[k]->flags & IEEE80211_TX_RC_GREEN_FIELD)
+ mimo_preamble_type = BRCMS_GF_PREAMBLE;
+
+ if ((txrate[k]->flags & IEEE80211_TX_RC_MCS)
+ && (!is_mcs_rate(rspec[k]))) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: IEEE80211_TX_"
+ "RC_MCS != is_mcs_rate(rspec)\n",
+ wlc->pub->unit, __func__);
+ }
+
+ if (is_mcs_rate(rspec[k])) {
+ preamble_type[k] = mimo_preamble_type;
+
+ /*
+ * if SGI is selected, then forced mm
+ * for single stream
+ */
+ if ((rspec[k] & RSPEC_SHORT_GI)
+ && is_single_stream(rspec[k] &
+ RSPEC_RATE_MASK))
+ preamble_type[k] = BRCMS_MM_PREAMBLE;
+ }
+
+ /* should be better conditionalized */
+ if (!is_mcs_rate(rspec[0])
+ && (tx_info->control.rates[0].
+ flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE))
+ preamble_type[k] = BRCMS_SHORT_PREAMBLE;
+ }
+ } else {
+ for (k = 0; k < hw->max_rates; k++) {
+ /* Set ctrlchbw as 20Mhz */
+ rspec[k] &= ~RSPEC_BW_MASK;
+ rspec[k] |= (PHY_TXC1_BW_20MHZ << RSPEC_BW_SHIFT);
+
+ /* for nphy, stf of ofdm frames must follow policies */
+ if (BRCMS_ISNPHY(wlc->band) && is_ofdm_rate(rspec[k])) {
+ rspec[k] &= ~RSPEC_STF_MASK;
+ rspec[k] |= phyctl1_stf << RSPEC_STF_SHIFT;
+ }
+ }
+ }
+
+ /* Reset these for use with AMPDU's */
+ txrate[0]->count = 0;
+ txrate[1]->count = 0;
+
+ /* (2) PROTECTION, may change rspec */
+ if ((ieee80211_is_data(h->frame_control) ||
+ ieee80211_is_mgmt(h->frame_control)) &&
+ (phylen > wlc->RTSThresh) && !is_multicast_ether_addr(h->addr1))
+ use_rts = true;
+
+ /* (3) PLCP: determine PLCP header and MAC duration,
+ * fill struct d11txh */
+ brcms_c_compute_plcp(wlc, rspec[0], phylen, plcp);
+ brcms_c_compute_plcp(wlc, rspec[1], phylen, plcp_fallback);
+ memcpy(&txh->FragPLCPFallback,
+ plcp_fallback, sizeof(txh->FragPLCPFallback));
+
+ /* Length field now put in CCK FBR CRC field */
+ if (is_cck_rate(rspec[1])) {
+ txh->FragPLCPFallback[4] = phylen & 0xff;
+ txh->FragPLCPFallback[5] = (phylen & 0xff00) >> 8;
+ }
+
+ /* MIMO-RATE: need validation ?? */
+ mainrates = is_ofdm_rate(rspec[0]) ?
+ D11A_PHY_HDR_GRATE((struct ofdm_phy_hdr *) plcp) :
+ plcp[0];
+
+ /* DUR field for main rate */
+ if (!ieee80211_is_pspoll(h->frame_control) &&
+ !is_multicast_ether_addr(h->addr1) && !use_rifs) {
+ durid =
+ brcms_c_compute_frame_dur(wlc, rspec[0], preamble_type[0],
+ next_frag_len);
+ h->duration_id = cpu_to_le16(durid);
+ } else if (use_rifs) {
+ /* NAV protect to end of next max packet size */
+ durid =
+ (u16) brcms_c_calc_frame_time(wlc, rspec[0],
+ preamble_type[0],
+ DOT11_MAX_FRAG_LEN);
+ durid += RIFS_11N_TIME;
+ h->duration_id = cpu_to_le16(durid);
+ }
+
+ /* DUR field for fallback rate */
+ if (ieee80211_is_pspoll(h->frame_control))
+ txh->FragDurFallback = h->duration_id;
+ else if (is_multicast_ether_addr(h->addr1) || use_rifs)
+ txh->FragDurFallback = 0;
+ else {
+ durid = brcms_c_compute_frame_dur(wlc, rspec[1],
+ preamble_type[1], next_frag_len);
+ txh->FragDurFallback = cpu_to_le16(durid);
+ }
+
+ /* (4) MAC-HDR: MacTxControlLow */
+ if (frag == 0)
+ mcl |= TXC_STARTMSDU;
+
+ if (!is_multicast_ether_addr(h->addr1))
+ mcl |= TXC_IMMEDACK;
+
+ if (wlc->band->bandtype == BRCM_BAND_5G)
+ mcl |= TXC_FREQBAND_5G;
+
+ if (CHSPEC_IS40(wlc_phy_chanspec_get(wlc->band->pi)))
+ mcl |= TXC_BW_40;
+
+ /* set AMIC bit if using hardware TKIP MIC */
+ if (hwtkmic)
+ mcl |= TXC_AMIC;
+
+ txh->MacTxControlLow = cpu_to_le16(mcl);
+
+ /* MacTxControlHigh */
+ mch = 0;
+
+ /* Set fallback rate preamble type */
+ if ((preamble_type[1] == BRCMS_SHORT_PREAMBLE) ||
+ (preamble_type[1] == BRCMS_GF_PREAMBLE)) {
+ if (rspec2rate(rspec[1]) != BRCM_RATE_1M)
+ mch |= TXC_PREAMBLE_DATA_FB_SHORT;
+ }
+
+ /* MacFrameControl */
+ memcpy(&txh->MacFrameControl, &h->frame_control, sizeof(u16));
+ txh->TxFesTimeNormal = cpu_to_le16(0);
+
+ txh->TxFesTimeFallback = cpu_to_le16(0);
+
+ /* TxFrameRA */
+ memcpy(&txh->TxFrameRA, &h->addr1, ETH_ALEN);
+
+ /* TxFrameID */
+ txh->TxFrameID = cpu_to_le16(frameid);
+
+ /*
+ * TxStatus, Note the case of recreating the first frag of a suppressed
+ * frame then we may need to reset the retry cnt's via the status reg
+ */
+ txh->TxStatus = cpu_to_le16(status);
+
+ /*
+ * extra fields for ucode AMPDU aggregation, the new fields are added to
+ * the END of previous structure so that it's compatible in driver.
+ */
+ txh->MaxNMpdus = cpu_to_le16(0);
+ txh->MaxABytes_MRT = cpu_to_le16(0);
+ txh->MaxABytes_FBR = cpu_to_le16(0);
+ txh->MinMBytes = cpu_to_le16(0);
+
+ /* (5) RTS/CTS: determine RTS/CTS PLCP header and MAC duration,
+ * furnish struct d11txh */
+ /* RTS PLCP header and RTS frame */
+ if (use_rts || use_cts) {
+ if (use_rts && use_cts)
+ use_cts = false;
+
+ for (k = 0; k < 2; k++) {
+ rts_rspec[k] = brcms_c_rspec_to_rts_rspec(wlc, rspec[k],
+ false,
+ mimo_ctlchbw);
+ }
+
+ if (!is_ofdm_rate(rts_rspec[0]) &&
+ !((rspec2rate(rts_rspec[0]) == BRCM_RATE_1M) ||
+ (wlc->PLCPHdr_override == BRCMS_PLCP_LONG))) {
+ rts_preamble_type[0] = BRCMS_SHORT_PREAMBLE;
+ mch |= TXC_PREAMBLE_RTS_MAIN_SHORT;
+ }
+
+ if (!is_ofdm_rate(rts_rspec[1]) &&
+ !((rspec2rate(rts_rspec[1]) == BRCM_RATE_1M) ||
+ (wlc->PLCPHdr_override == BRCMS_PLCP_LONG))) {
+ rts_preamble_type[1] = BRCMS_SHORT_PREAMBLE;
+ mch |= TXC_PREAMBLE_RTS_FB_SHORT;
+ }
+
+ /* RTS/CTS additions to MacTxControlLow */
+ if (use_cts) {
+ txh->MacTxControlLow |= cpu_to_le16(TXC_SENDCTS);
+ } else {
+ txh->MacTxControlLow |= cpu_to_le16(TXC_SENDRTS);
+ txh->MacTxControlLow |= cpu_to_le16(TXC_LONGFRAME);
+ }
+
+ /* RTS PLCP header */
+ rts_plcp = txh->RTSPhyHeader;
+ if (use_cts)
+ rts_phylen = DOT11_CTS_LEN + FCS_LEN;
+ else
+ rts_phylen = DOT11_RTS_LEN + FCS_LEN;
+
+ brcms_c_compute_plcp(wlc, rts_rspec[0], rts_phylen, rts_plcp);
+
+ /* fallback rate version of RTS PLCP header */
+ brcms_c_compute_plcp(wlc, rts_rspec[1], rts_phylen,
+ rts_plcp_fallback);
+ memcpy(&txh->RTSPLCPFallback, rts_plcp_fallback,
+ sizeof(txh->RTSPLCPFallback));
+
+ /* RTS frame fields... */
+ rts = (struct ieee80211_rts *)&txh->rts_frame;
+
+ durid = brcms_c_compute_rtscts_dur(wlc, use_cts, rts_rspec[0],
+ rspec[0], rts_preamble_type[0],
+ preamble_type[0], phylen, false);
+ rts->duration = cpu_to_le16(durid);
+ /* fallback rate version of RTS DUR field */
+ durid = brcms_c_compute_rtscts_dur(wlc, use_cts,
+ rts_rspec[1], rspec[1],
+ rts_preamble_type[1],
+ preamble_type[1], phylen, false);
+ txh->RTSDurFallback = cpu_to_le16(durid);
+
+ if (use_cts) {
+ rts->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
+ IEEE80211_STYPE_CTS);
+
+ memcpy(&rts->ra, &h->addr2, ETH_ALEN);
+ } else {
+ rts->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
+ IEEE80211_STYPE_RTS);
+
+ memcpy(&rts->ra, &h->addr1, 2 * ETH_ALEN);
+ }
+
+ /* mainrate
+ * low 8 bits: main frag rate/mcs,
+ * high 8 bits: rts/cts rate/mcs
+ */
+ mainrates |= (is_ofdm_rate(rts_rspec[0]) ?
+ D11A_PHY_HDR_GRATE(
+ (struct ofdm_phy_hdr *) rts_plcp) :
+ rts_plcp[0]) << 8;
+ } else {
+ memset((char *)txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN);
+ memset((char *)&txh->rts_frame, 0,
+ sizeof(struct ieee80211_rts));
+ memset((char *)txh->RTSPLCPFallback, 0,
+ sizeof(txh->RTSPLCPFallback));
+ txh->RTSDurFallback = 0;
+ }
+
+#ifdef SUPPORT_40MHZ
+ /* add null delimiter count */
+ if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && is_mcs_rate(rspec))
+ txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] =
+ brcm_c_ampdu_null_delim_cnt(wlc->ampdu, scb, rspec, phylen);
+
+#endif
+
+ /*
+ * Now that RTS/RTS FB preamble types are updated, write
+ * the final value
+ */
+ txh->MacTxControlHigh = cpu_to_le16(mch);
+
+ /*
+ * MainRates (both the rts and frag plcp rates have
+ * been calculated now)
+ */
+ txh->MainRates = cpu_to_le16(mainrates);
+
+ /* XtraFrameTypes */
+ xfts = frametype(rspec[1], wlc->mimoft);
+ xfts |= (frametype(rts_rspec[0], wlc->mimoft) << XFTS_RTS_FT_SHIFT);
+ xfts |= (frametype(rts_rspec[1], wlc->mimoft) << XFTS_FBRRTS_FT_SHIFT);
+ xfts |= CHSPEC_CHANNEL(wlc_phy_chanspec_get(wlc->band->pi)) <<
+ XFTS_CHANNEL_SHIFT;
+ txh->XtraFrameTypes = cpu_to_le16(xfts);
+
+ /* PhyTxControlWord */
+ phyctl = frametype(rspec[0], wlc->mimoft);
+ if ((preamble_type[0] == BRCMS_SHORT_PREAMBLE) ||
+ (preamble_type[0] == BRCMS_GF_PREAMBLE)) {
+ if (rspec2rate(rspec[0]) != BRCM_RATE_1M)
+ phyctl |= PHY_TXC_SHORT_HDR;
+ }
+
+ /* phytxant is properly bit shifted */
+ phyctl |= brcms_c_stf_d11hdrs_phyctl_txant(wlc, rspec[0]);
+ txh->PhyTxControlWord = cpu_to_le16(phyctl);
+
+ /* PhyTxControlWord_1 */
+ if (BRCMS_PHY_11N_CAP(wlc->band)) {
+ u16 phyctl1 = 0;
+
+ phyctl1 = brcms_c_phytxctl1_calc(wlc, rspec[0]);
+ txh->PhyTxControlWord_1 = cpu_to_le16(phyctl1);
+ phyctl1 = brcms_c_phytxctl1_calc(wlc, rspec[1]);
+ txh->PhyTxControlWord_1_Fbr = cpu_to_le16(phyctl1);
+
+ if (use_rts || use_cts) {
+ phyctl1 = brcms_c_phytxctl1_calc(wlc, rts_rspec[0]);
+ txh->PhyTxControlWord_1_Rts = cpu_to_le16(phyctl1);
+ phyctl1 = brcms_c_phytxctl1_calc(wlc, rts_rspec[1]);
+ txh->PhyTxControlWord_1_FbrRts = cpu_to_le16(phyctl1);
+ }
+
+ /*
+ * For mcs frames, if mixedmode(overloaded with long preamble)
+ * is going to be set, fill in non-zero MModeLen and/or
+ * MModeFbrLen it will be unnecessary if they are separated
+ */
+ if (is_mcs_rate(rspec[0]) &&
+ (preamble_type[0] == BRCMS_MM_PREAMBLE)) {
+ u16 mmodelen =
+ brcms_c_calc_lsig_len(wlc, rspec[0], phylen);
+ txh->MModeLen = cpu_to_le16(mmodelen);
+ }
+
+ if (is_mcs_rate(rspec[1]) &&
+ (preamble_type[1] == BRCMS_MM_PREAMBLE)) {
+ u16 mmodefbrlen =
+ brcms_c_calc_lsig_len(wlc, rspec[1], phylen);
+ txh->MModeFbrLen = cpu_to_le16(mmodefbrlen);
+ }
+ }
+
+ ac = skb_get_queue_mapping(p);
+ if ((scb->flags & SCB_WMECAP) && qos && wlc->edcf_txop[ac]) {
+ uint frag_dur, dur, dur_fallback;
+
+ /* WME: Update TXOP threshold */
+ if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU) && frag == 0) {
+ frag_dur =
+ brcms_c_calc_frame_time(wlc, rspec[0],
+ preamble_type[0], phylen);
+
+ if (rts) {
+ /* 1 RTS or CTS-to-self frame */
+ dur =
+ brcms_c_calc_cts_time(wlc, rts_rspec[0],
+ rts_preamble_type[0]);
+ dur_fallback =
+ brcms_c_calc_cts_time(wlc, rts_rspec[1],
+ rts_preamble_type[1]);
+ /* (SIFS + CTS) + SIFS + frame + SIFS + ACK */
+ dur += le16_to_cpu(rts->duration);
+ dur_fallback +=
+ le16_to_cpu(txh->RTSDurFallback);
+ } else if (use_rifs) {
+ dur = frag_dur;
+ dur_fallback = 0;
+ } else {
+ /* frame + SIFS + ACK */
+ dur = frag_dur;
+ dur +=
+ brcms_c_compute_frame_dur(wlc, rspec[0],
+ preamble_type[0], 0);
+
+ dur_fallback =
+ brcms_c_calc_frame_time(wlc, rspec[1],
+ preamble_type[1],
+ phylen);
+ dur_fallback +=
+ brcms_c_compute_frame_dur(wlc, rspec[1],
+ preamble_type[1], 0);
+ }
+ /* NEED to set TxFesTimeNormal (hard) */
+ txh->TxFesTimeNormal = cpu_to_le16((u16) dur);
+ /*
+ * NEED to set fallback rate version of
+ * TxFesTimeNormal (hard)
+ */
+ txh->TxFesTimeFallback =
+ cpu_to_le16((u16) dur_fallback);
+
+ /*
+ * update txop byte threshold (txop minus intraframe
+ * overhead)
+ */
+ if (wlc->edcf_txop[ac] >= (dur - frag_dur)) {
+ uint newfragthresh;
+
+ newfragthresh =
+ brcms_c_calc_frame_len(wlc,
+ rspec[0], preamble_type[0],
+ (wlc->edcf_txop[ac] -
+ (dur - frag_dur)));
+ /* range bound the fragthreshold */
+ if (newfragthresh < DOT11_MIN_FRAG_LEN)
+ newfragthresh =
+ DOT11_MIN_FRAG_LEN;
+ else if (newfragthresh >
+ wlc->usr_fragthresh)
+ newfragthresh =
+ wlc->usr_fragthresh;
+ /* update the fragthresh and do txc update */
+ if (wlc->fragthresh[queue] !=
+ (u16) newfragthresh)
+ wlc->fragthresh[queue] =
+ (u16) newfragthresh;
+ } else {
+ wiphy_err(wlc->wiphy, "wl%d: %s txop invalid "
+ "for rate %d\n",
+ wlc->pub->unit, fifo_names[queue],
+ rspec2rate(rspec[0]));
+ }
+
+ if (dur > wlc->edcf_txop[ac])
+ wiphy_err(wlc->wiphy, "wl%d: %s: %s txop "
+ "exceeded phylen %d/%d dur %d/%d\n",
+ wlc->pub->unit, __func__,
+ fifo_names[queue],
+ phylen, wlc->fragthresh[queue],
+ dur, wlc->edcf_txop[ac]);
+ }
+ }
+
+ return 0;
+}
+
+void brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, struct sk_buff *sdu,
+ struct ieee80211_hw *hw)
+{
+ u8 prio;
+ uint fifo;
+ struct scb *scb = &wlc->pri_scb;
+ struct ieee80211_hdr *d11_header = (struct ieee80211_hdr *)(sdu->data);
+
+ /*
+ * 802.11 standard requires management traffic
+ * to go at highest priority
+ */
+ prio = ieee80211_is_data(d11_header->frame_control) ? sdu->priority :
+ MAXPRIO;
+ fifo = prio2fifo[prio];
+ if (brcms_c_d11hdrs_mac80211(wlc, hw, sdu, scb, 0, 1, fifo, 0))
+ return;
+ brcms_c_txq_enq(wlc, scb, sdu, BRCMS_PRIO_TO_PREC(prio));
+ brcms_c_send_q(wlc);
+}
+
+void brcms_c_send_q(struct brcms_c_info *wlc)
+{
+ struct sk_buff *pkt[DOT11_MAXNUMFRAGS];
+ int prec;
+ u16 prec_map;
+ int err = 0, i, count;
+ uint fifo;
+ struct brcms_txq_info *qi = wlc->pkt_queue;
+ struct pktq *q = &qi->q;
+ struct ieee80211_tx_info *tx_info;
+
+ prec_map = wlc->tx_prec_map;
+
+ /* Send all the enq'd pkts that we can.
+ * Dequeue packets with precedence with empty HW fifo only
+ */
+ while (prec_map && (pkt[0] = brcmu_pktq_mdeq(q, prec_map, &prec))) {
+ tx_info = IEEE80211_SKB_CB(pkt[0]);
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+ err = brcms_c_sendampdu(wlc->ampdu, qi, pkt, prec);
+ } else {
+ count = 1;
+ err = brcms_c_prep_pdu(wlc, pkt[0], &fifo);
+ if (!err) {
+ for (i = 0; i < count; i++)
+ brcms_c_txfifo(wlc, fifo, pkt[i], true,
+ 1);
+ }
+ }
+
+ if (err == -EBUSY) {
+ brcmu_pktq_penq_head(q, prec, pkt[0]);
+ /*
+ * If send failed due to any other reason than a
+ * change in HW FIFO condition, quit. Otherwise,
+ * read the new prec_map!
+ */
+ if (prec_map == wlc->tx_prec_map)
+ break;
+ prec_map = wlc->tx_prec_map;
+ }
+ }
+}
+
+void
+brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p,
+ bool commit, s8 txpktpend)
+{
+ u16 frameid = INVALIDFID;
+ struct d11txh *txh;
+
+ txh = (struct d11txh *) (p->data);
+
+ /* When a BC/MC frame is being committed to the BCMC fifo
+ * via DMA (NOT PIO), update ucode or BSS info as appropriate.
+ */
+ if (fifo == TX_BCMC_FIFO)
+ frameid = le16_to_cpu(txh->TxFrameID);
+
+ /*
+ * Bump up pending count for if not using rpc. If rpc is
+ * used, this will be handled in brcms_b_txfifo()
+ */
+ if (commit) {
+ wlc->core->txpktpend[fifo] += txpktpend;
+ BCMMSG(wlc->wiphy, "pktpend inc %d to %d\n",
+ txpktpend, wlc->core->txpktpend[fifo]);
+ }
+
+ /* Commit BCMC sequence number in the SHM frame ID location */
+ if (frameid != INVALIDFID) {
+ /*
+ * To inform the ucode of the last mcast frame posted
+ * so that it can clear moredata bit
+ */
+ brcms_b_write_shm(wlc->hw, M_BCMC_FID, frameid);
+ }
+
+ if (dma_txfast(wlc->hw->di[fifo], p, commit) < 0)
+ wiphy_err(wlc->wiphy, "txfifo: fatal, toss frames !!!\n");
+}
+
+u32
+brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, u32 rspec,
+ bool use_rspec, u16 mimo_ctlchbw)
+{
+ u32 rts_rspec = 0;
+
+ if (use_rspec)
+ /* use frame rate as rts rate */
+ rts_rspec = rspec;
+ else if (wlc->band->gmode && wlc->protection->_g && !is_cck_rate(rspec))
+ /* Use 11Mbps as the g protection RTS target rate and fallback.
+ * Use the brcms_basic_rate() lookup to find the best basic rate
+ * under the target in case 11 Mbps is not Basic.
+ * 6 and 9 Mbps are not usually selected by rate selection, but
+ * even if the OFDM rate we are protecting is 6 or 9 Mbps, 11
+ * is more robust.
+ */
+ rts_rspec = brcms_basic_rate(wlc, BRCM_RATE_11M);
+ else
+ /* calculate RTS rate and fallback rate based on the frame rate
+ * RTS must be sent at a basic rate since it is a
+ * control frame, sec 9.6 of 802.11 spec
+ */
+ rts_rspec = brcms_basic_rate(wlc, rspec);
+
+ if (BRCMS_PHY_11N_CAP(wlc->band)) {
+ /* set rts txbw to correct side band */
+ rts_rspec &= ~RSPEC_BW_MASK;
+
+ /*
+ * if rspec/rspec_fallback is 40MHz, then send RTS on both
+ * 20MHz channel (DUP), otherwise send RTS on control channel
+ */
+ if (rspec_is40mhz(rspec) && !is_cck_rate(rts_rspec))
+ rts_rspec |= (PHY_TXC1_BW_40MHZ_DUP << RSPEC_BW_SHIFT);
+ else
+ rts_rspec |= (mimo_ctlchbw << RSPEC_BW_SHIFT);
+
+ /* pick siso/cdd as default for ofdm */
+ if (is_ofdm_rate(rts_rspec)) {
+ rts_rspec &= ~RSPEC_STF_MASK;
+ rts_rspec |= (wlc->stf->ss_opmode << RSPEC_STF_SHIFT);
+ }
+ }
+ return rts_rspec;
+}
+
+void
+brcms_c_txfifo_complete(struct brcms_c_info *wlc, uint fifo, s8 txpktpend)
+{
+ wlc->core->txpktpend[fifo] -= txpktpend;
+ BCMMSG(wlc->wiphy, "pktpend dec %d to %d\n", txpktpend,
+ wlc->core->txpktpend[fifo]);
+
+ /* There is more room; mark precedences related to this FIFO sendable */
+ wlc->tx_prec_map |= wlc->fifo2prec_map[fifo];
+
+ /* figure out which bsscfg is being worked on... */
+}
+
+/* Update beacon listen interval in shared memory */
+static void brcms_c_bcn_li_upd(struct brcms_c_info *wlc)
+{
+ /* wake up every DTIM is the default */
+ if (wlc->bcn_li_dtim == 1)
+ brcms_b_write_shm(wlc->hw, M_BCN_LI, 0);
+ else
+ brcms_b_write_shm(wlc->hw, M_BCN_LI,
+ (wlc->bcn_li_dtim << 8) | wlc->bcn_li_bcn);
+}
+
+static void
+brcms_b_read_tsf(struct brcms_hardware *wlc_hw, u32 *tsf_l_ptr,
+ u32 *tsf_h_ptr)
+{
+ struct d11regs __iomem *regs = wlc_hw->regs;
+
+ /* read the tsf timer low, then high to get an atomic read */
+ *tsf_l_ptr = R_REG(&regs->tsf_timerlow);
+ *tsf_h_ptr = R_REG(&regs->tsf_timerhigh);
+}
+
+/*
+ * recover 64bit TSF value from the 16bit TSF value in the rx header
+ * given the assumption that the TSF passed in header is within 65ms
+ * of the current tsf.
+ *
+ * 6 5 4 4 3 2 1
+ * 3.......6.......8.......0.......2.......4.......6.......8......0
+ * |<---------- tsf_h ----------->||<--- tsf_l -->||<-RxTSFTime ->|
+ *
+ * The RxTSFTime are the lowest 16 bits and provided by the ucode. The
+ * tsf_l is filled in by brcms_b_recv, which is done earlier in the
+ * receive call sequence after rx interrupt. Only the higher 16 bits
+ * are used. Finally, the tsf_h is read from the tsf register.
+ */
+static u64 brcms_c_recover_tsf64(struct brcms_c_info *wlc,
+ struct d11rxhdr *rxh)
+{
+ u32 tsf_h, tsf_l;
+ u16 rx_tsf_0_15, rx_tsf_16_31;
+
+ brcms_b_read_tsf(wlc->hw, &tsf_l, &tsf_h);
+
+ rx_tsf_16_31 = (u16)(tsf_l >> 16);
+ rx_tsf_0_15 = rxh->RxTSFTime;
+
+ /*
+ * a greater tsf time indicates the low 16 bits of
+ * tsf_l wrapped, so decrement the high 16 bits.
+ */
+ if ((u16)tsf_l < rx_tsf_0_15) {
+ rx_tsf_16_31 -= 1;
+ if (rx_tsf_16_31 == 0xffff)
+ tsf_h -= 1;
+ }
+
+ return ((u64)tsf_h << 32) | (((u32)rx_tsf_16_31 << 16) + rx_tsf_0_15);
+}
+
+static void
+prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
+ struct sk_buff *p,
+ struct ieee80211_rx_status *rx_status)
+{
+ int preamble;
+ int channel;
+ u32 rspec;
+ unsigned char *plcp;
+
+ /* fill in TSF and flag its presence */
+ rx_status->mactime = brcms_c_recover_tsf64(wlc, rxh);
+ rx_status->flag |= RX_FLAG_MACTIME_MPDU;
+
+ channel = BRCMS_CHAN_CHANNEL(rxh->RxChan);
+
+ if (channel > 14) {
+ rx_status->band = IEEE80211_BAND_5GHZ;
+ rx_status->freq = ieee80211_ofdm_chan_to_freq(
+ WF_CHAN_FACTOR_5_G/2, channel);
+
+ } else {
+ rx_status->band = IEEE80211_BAND_2GHZ;
+ rx_status->freq = ieee80211_dsss_chan_to_freq(channel);
+ }
+
+ rx_status->signal = wlc_phy_rssi_compute(wlc->hw->band->pi, rxh);
+
+ /* noise */
+ /* qual */
+ rx_status->antenna =
+ (rxh->PhyRxStatus_0 & PRXS0_RXANT_UPSUBBAND) ? 1 : 0;
+
+ plcp = p->data;
+
+ rspec = brcms_c_compute_rspec(rxh, plcp);
+ if (is_mcs_rate(rspec)) {
+ rx_status->rate_idx = rspec & RSPEC_RATE_MASK;
+ rx_status->flag |= RX_FLAG_HT;
+ if (rspec_is40mhz(rspec))
+ rx_status->flag |= RX_FLAG_40MHZ;
+ } else {
+ switch (rspec2rate(rspec)) {
+ case BRCM_RATE_1M:
+ rx_status->rate_idx = 0;
+ break;
+ case BRCM_RATE_2M:
+ rx_status->rate_idx = 1;
+ break;
+ case BRCM_RATE_5M5:
+ rx_status->rate_idx = 2;
+ break;
+ case BRCM_RATE_11M:
+ rx_status->rate_idx = 3;
+ break;
+ case BRCM_RATE_6M:
+ rx_status->rate_idx = 4;
+ break;
+ case BRCM_RATE_9M:
+ rx_status->rate_idx = 5;
+ break;
+ case BRCM_RATE_12M:
+ rx_status->rate_idx = 6;
+ break;
+ case BRCM_RATE_18M:
+ rx_status->rate_idx = 7;
+ break;
+ case BRCM_RATE_24M:
+ rx_status->rate_idx = 8;
+ break;
+ case BRCM_RATE_36M:
+ rx_status->rate_idx = 9;
+ break;
+ case BRCM_RATE_48M:
+ rx_status->rate_idx = 10;
+ break;
+ case BRCM_RATE_54M:
+ rx_status->rate_idx = 11;
+ break;
+ default:
+ wiphy_err(wlc->wiphy, "%s: Unknown rate\n", __func__);
+ }
+
+ /*
+ * For 5GHz, we should decrease the index as it is
+ * a subset of the 2.4G rates. See bitrates field
+ * of brcms_band_5GHz_nphy (in mac80211_if.c).
+ */
+ if (rx_status->band == IEEE80211_BAND_5GHZ)
+ rx_status->rate_idx -= BRCMS_LEGACY_5G_RATE_OFFSET;
+
+ /* Determine short preamble and rate_idx */
+ preamble = 0;
+ if (is_cck_rate(rspec)) {
+ if (rxh->PhyRxStatus_0 & PRXS0_SHORTH)
+ rx_status->flag |= RX_FLAG_SHORTPRE;
+ } else if (is_ofdm_rate(rspec)) {
+ rx_status->flag |= RX_FLAG_SHORTPRE;
+ } else {
+ wiphy_err(wlc->wiphy, "%s: Unknown modulation\n",
+ __func__);
+ }
+ }
+
+ if (plcp3_issgi(plcp[3]))
+ rx_status->flag |= RX_FLAG_SHORT_GI;
+
+ if (rxh->RxStatus1 & RXS_DECERR) {
+ rx_status->flag |= RX_FLAG_FAILED_PLCP_CRC;
+ wiphy_err(wlc->wiphy, "%s: RX_FLAG_FAILED_PLCP_CRC\n",
+ __func__);
+ }
+ if (rxh->RxStatus1 & RXS_FCSERR) {
+ rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+ wiphy_err(wlc->wiphy, "%s: RX_FLAG_FAILED_FCS_CRC\n",
+ __func__);
+ }
+}
+
+static void
+brcms_c_recvctl(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
+ struct sk_buff *p)
+{
+ int len_mpdu;
+ struct ieee80211_rx_status rx_status;
+
+ memset(&rx_status, 0, sizeof(rx_status));
+ prep_mac80211_status(wlc, rxh, p, &rx_status);
+
+ /* mac header+body length, exclude CRC and plcp header */
+ len_mpdu = p->len - D11_PHY_HDR_LEN - FCS_LEN;
+ skb_pull(p, D11_PHY_HDR_LEN);
+ __skb_trim(p, len_mpdu);
+
+ memcpy(IEEE80211_SKB_RXCB(p), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(wlc->pub->ieee_hw, p);
+}
+
+/* calculate frame duration for Mixed-mode L-SIG spoofing, return
+ * number of bytes goes in the length field
+ *
+ * Formula given by HT PHY Spec v 1.13
+ * len = 3(nsyms + nstream + 3) - 3
+ */
+u16
+brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec,
+ uint mac_len)
+{
+ uint nsyms, len = 0, kNdps;
+
+ BCMMSG(wlc->wiphy, "wl%d: rate %d, len%d\n",
+ wlc->pub->unit, rspec2rate(ratespec), mac_len);
+
+ if (is_mcs_rate(ratespec)) {
+ uint mcs = ratespec & RSPEC_RATE_MASK;
+ int tot_streams = (mcs_2_txstreams(mcs) + 1) +
+ rspec_stc(ratespec);
+
+ /*
+ * the payload duration calculation matches that
+ * of regular ofdm
+ */
+ /* 1000Ndbps = kbps * 4 */
+ kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec),
+ rspec_issgi(ratespec)) * 4;
+
+ if (rspec_stc(ratespec) == 0)
+ nsyms =
+ CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
+ APHY_TAIL_NBITS) * 1000, kNdps);
+ else
+ /* STBC needs to have even number of symbols */
+ nsyms =
+ 2 *
+ CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
+ APHY_TAIL_NBITS) * 1000, 2 * kNdps);
+
+ /* (+3) account for HT-SIG(2) and HT-STF(1) */
+ nsyms += (tot_streams + 3);
+ /*
+ * 3 bytes/symbol @ legacy 6Mbps rate
+ * (-3) excluding service bits and tail bits
+ */
+ len = (3 * nsyms) - 3;
+ }
+
+ return (u16) len;
+}
+
+static void
+brcms_c_mod_prb_rsp_rate_table(struct brcms_c_info *wlc, uint frame_len)
+{
+ const struct brcms_c_rateset *rs_dflt;
+ struct brcms_c_rateset rs;
+ u8 rate;
+ u16 entry_ptr;
+ u8 plcp[D11_PHY_HDR_LEN];
+ u16 dur, sifs;
+ uint i;
+
+ sifs = get_sifs(wlc->band);
+
+ rs_dflt = brcms_c_rateset_get_hwrs(wlc);
+
+ brcms_c_rateset_copy(rs_dflt, &rs);
+ brcms_c_rateset_mcs_upd(&rs, wlc->stf->txstreams);
+
+ /*
+ * walk the phy rate table and update MAC core SHM
+ * basic rate table entries
+ */
+ for (i = 0; i < rs.count; i++) {
+ rate = rs.rates[i] & BRCMS_RATE_MASK;
+
+ entry_ptr = brcms_b_rate_shm_offset(wlc->hw, rate);
+
+ /* Calculate the Probe Response PLCP for the given rate */
+ brcms_c_compute_plcp(wlc, rate, frame_len, plcp);
+
+ /*
+ * Calculate the duration of the Probe Response
+ * frame plus SIFS for the MAC
+ */
+ dur = (u16) brcms_c_calc_frame_time(wlc, rate,
+ BRCMS_LONG_PREAMBLE, frame_len);
+ dur += sifs;
+
+ /* Update the SHM Rate Table entry Probe Response values */
+ brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_PLCP_POS,
+ (u16) (plcp[0] + (plcp[1] << 8)));
+ brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_PLCP_POS + 2,
+ (u16) (plcp[2] + (plcp[3] << 8)));
+ brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_DUR_POS, dur);
+ }
+}
+
+/* Max buffering needed for beacon template/prb resp template is 142 bytes.
+ *
+ * PLCP header is 6 bytes.
+ * 802.11 A3 header is 24 bytes.
+ * Max beacon frame body template length is 112 bytes.
+ * Max probe resp frame body template length is 110 bytes.
+ *
+ * *len on input contains the max length of the packet available.
+ *
+ * The *len value is set to the number of bytes in buf used, and starts
+ * with the PLCP and included up to, but not including, the 4 byte FCS.
+ */
+static void
+brcms_c_bcn_prb_template(struct brcms_c_info *wlc, u16 type,
+ u32 bcn_rspec,
+ struct brcms_bss_cfg *cfg, u16 *buf, int *len)
+{
+ static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255};
+ struct cck_phy_hdr *plcp;
+ struct ieee80211_mgmt *h;
+ int hdr_len, body_len;
+
+ hdr_len = D11_PHY_HDR_LEN + DOT11_MAC_HDR_LEN;
+
+ /* calc buffer size provided for frame body */
+ body_len = *len - hdr_len;
+ /* return actual size */
+ *len = hdr_len + body_len;
+
+ /* format PHY and MAC headers */
+ memset((char *)buf, 0, hdr_len);
+
+ plcp = (struct cck_phy_hdr *) buf;
+
+ /*
+ * PLCP for Probe Response frames are filled in from
+ * core's rate table
+ */
+ if (type == IEEE80211_STYPE_BEACON)
+ /* fill in PLCP */
+ brcms_c_compute_plcp(wlc, bcn_rspec,
+ (DOT11_MAC_HDR_LEN + body_len + FCS_LEN),
+ (u8 *) plcp);
+
+ /* "Regular" and 16 MBSS but not for 4 MBSS */
+ /* Update the phytxctl for the beacon based on the rspec */
+ brcms_c_beacon_phytxctl_txant_upd(wlc, bcn_rspec);
+
+ h = (struct ieee80211_mgmt *)&plcp[1];
+
+ /* fill in 802.11 header */
+ h->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | type);
+
+ /* DUR is 0 for multicast bcn, or filled in by MAC for prb resp */
+ /* A1 filled in by MAC for prb resp, broadcast for bcn */
+ if (type == IEEE80211_STYPE_BEACON)
+ memcpy(&h->da, &ether_bcast, ETH_ALEN);
+ memcpy(&h->sa, &cfg->cur_etheraddr, ETH_ALEN);
+ memcpy(&h->bssid, &cfg->BSSID, ETH_ALEN);
+
+ /* SEQ filled in by MAC */
+}
+
+int brcms_c_get_header_len(void)
+{
+ return TXOFF;
+}
+
+/*
+ * Update all beacons for the system.
+ */
+void brcms_c_update_beacon(struct brcms_c_info *wlc)
+{
+ struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
+
+ if (bsscfg->up && !bsscfg->BSS)
+ /* Clear the soft intmask */
+ wlc->defmacintmask &= ~MI_BCNTPL;
+}
+
+/* Write ssid into shared memory */
+static void
+brcms_c_shm_ssid_upd(struct brcms_c_info *wlc, struct brcms_bss_cfg *cfg)
+{
+ u8 *ssidptr = cfg->SSID;
+ u16 base = M_SSID;
+ u8 ssidbuf[IEEE80211_MAX_SSID_LEN];
+
+ /* padding the ssid with zero and copy it into shm */
+ memset(ssidbuf, 0, IEEE80211_MAX_SSID_LEN);
+ memcpy(ssidbuf, ssidptr, cfg->SSID_len);
+
+ brcms_c_copyto_shm(wlc, base, ssidbuf, IEEE80211_MAX_SSID_LEN);
+ brcms_b_write_shm(wlc->hw, M_SSIDLEN, (u16) cfg->SSID_len);
+}
+
+static void
+brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc,
+ struct brcms_bss_cfg *cfg,
+ bool suspend)
+{
+ u16 prb_resp[BCN_TMPL_LEN / 2];
+ int len = BCN_TMPL_LEN;
+
+ /*
+ * write the probe response to hardware, or save in
+ * the config structure
+ */
+
+ /* create the probe response template */
+ brcms_c_bcn_prb_template(wlc, IEEE80211_STYPE_PROBE_RESP, 0,
+ cfg, prb_resp, &len);
+
+ if (suspend)
+ brcms_c_suspend_mac_and_wait(wlc);
+
+ /* write the probe response into the template region */
+ brcms_b_write_template_ram(wlc->hw, T_PRS_TPL_BASE,
+ (len + 3) & ~3, prb_resp);
+
+ /* write the length of the probe response frame (+PLCP/-FCS) */
+ brcms_b_write_shm(wlc->hw, M_PRB_RESP_FRM_LEN, (u16) len);
+
+ /* write the SSID and SSID length */
+ brcms_c_shm_ssid_upd(wlc, cfg);
+
+ /*
+ * Write PLCP headers and durations for probe response frames
+ * at all rates. Use the actual frame length covered by the
+ * PLCP header for the call to brcms_c_mod_prb_rsp_rate_table()
+ * by subtracting the PLCP len and adding the FCS.
+ */
+ len += (-D11_PHY_HDR_LEN + FCS_LEN);
+ brcms_c_mod_prb_rsp_rate_table(wlc, (u16) len);
+
+ if (suspend)
+ brcms_c_enable_mac(wlc);
+}
+
+void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend)
+{
+ struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
+
+ /* update AP or IBSS probe responses */
+ if (bsscfg->up && !bsscfg->BSS)
+ brcms_c_bss_update_probe_resp(wlc, bsscfg, suspend);
+}
+
+/* prepares pdu for transmission. returns BCM error codes */
+int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu, uint *fifop)
+{
+ uint fifo;
+ struct d11txh *txh;
+ struct ieee80211_hdr *h;
+ struct scb *scb;
+
+ txh = (struct d11txh *) (pdu->data);
+ h = (struct ieee80211_hdr *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN);
+
+ /* get the pkt queue info. This was put at brcms_c_sendctl or
+ * brcms_c_send for PDU */
+ fifo = le16_to_cpu(txh->TxFrameID) & TXFID_QUEUE_MASK;
+
+ scb = NULL;
+
+ *fifop = fifo;
+
+ /* return if insufficient dma resources */
+ if (*wlc->core->txavail[fifo] < MAX_DMA_SEGS) {
+ /* Mark precedences related to this FIFO, unsendable */
+ /* A fifo is full. Clear precedences related to that FIFO */
+ wlc->tx_prec_map &= ~(wlc->fifo2prec_map[fifo]);
+ return -EBUSY;
+ }
+ return 0;
+}
+
+int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo,
+ uint *blocks)
+{
+ if (fifo >= NFIFO)
+ return -EINVAL;
+
+ *blocks = wlc_hw->xmtfifo_sz[fifo];
+
+ return 0;
+}
+
+void
+brcms_c_set_addrmatch(struct brcms_c_info *wlc, int match_reg_offset,
+ const u8 *addr)
+{
+ brcms_b_set_addrmatch(wlc->hw, match_reg_offset, addr);
+ if (match_reg_offset == RCM_BSSID_OFFSET)
+ memcpy(wlc->bsscfg->BSSID, addr, ETH_ALEN);
+}
+
+/*
+ * Flag 'scan in progress' to withhold dynamic phy calibration
+ */
+void brcms_c_scan_start(struct brcms_c_info *wlc)
+{
+ wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, true);
+}
+
+void brcms_c_scan_stop(struct brcms_c_info *wlc)
+{
+ wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, false);
+}
+
+void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state)
+{
+ wlc->pub->associated = state;
+ wlc->bsscfg->associated = state;
+}
+
+/*
+ * When a remote STA/AP is removed by Mac80211, or when it can no longer accept
+ * AMPDU traffic, packets pending in hardware have to be invalidated so that
+ * when later on hardware releases them, they can be handled appropriately.
+ */
+void brcms_c_inval_dma_pkts(struct brcms_hardware *hw,
+ struct ieee80211_sta *sta,
+ void (*dma_callback_fn))
+{
+ struct dma_pub *dmah;
+ int i;
+ for (i = 0; i < NFIFO; i++) {
+ dmah = hw->di[i];
+ if (dmah != NULL)
+ dma_walk_packets(dmah, dma_callback_fn, sta);
+ }
+}
+
+int brcms_c_get_curband(struct brcms_c_info *wlc)
+{
+ return wlc->band->bandunit;
+}
+
+void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, bool drop)
+{
+ /* flush packet queue when requested */
+ if (drop)
+ brcmu_pktq_flush(&wlc->pkt_queue->q, false, NULL, NULL);
+
+ /* wait for queue and DMA fifos to run dry */
+ while (!pktq_empty(&wlc->pkt_queue->q) || brcms_txpktpendtot(wlc) > 0)
+ brcms_msleep(wlc->wl, 1);
+}
+
+void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval)
+{
+ wlc->bcn_li_bcn = interval;
+ if (wlc->pub->up)
+ brcms_c_bcn_li_upd(wlc);
+}
+
+int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr)
+{
+ uint qdbm;
+
+ /* Remove override bit and clip to max qdbm value */
+ qdbm = min_t(uint, txpwr * BRCMS_TXPWR_DB_FACTOR, 0xff);
+ return wlc_phy_txpower_set(wlc->band->pi, qdbm, false);
+}
+
+int brcms_c_get_tx_power(struct brcms_c_info *wlc)
+{
+ uint qdbm;
+ bool override;
+
+ wlc_phy_txpower_get(wlc->band->pi, &qdbm, &override);
+
+ /* Return qdbm units */
+ return (int)(qdbm / BRCMS_TXPWR_DB_FACTOR);
+}
+
+void brcms_c_set_radio_mpc(struct brcms_c_info *wlc, bool mpc)
+{
+ wlc->mpc = mpc;
+ brcms_c_radio_mpc_upd(wlc);
+}
+
+/* Process received frames */
+/*
+ * Return true if more frames need to be processed. false otherwise.
+ * Param 'bound' indicates max. # frames to process before break out.
+ */
+static void brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p)
+{
+ struct d11rxhdr *rxh;
+ struct ieee80211_hdr *h;
+ uint len;
+ bool is_amsdu;
+
+ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+
+ /* frame starts with rxhdr */
+ rxh = (struct d11rxhdr *) (p->data);
+
+ /* strip off rxhdr */
+ skb_pull(p, BRCMS_HWRXOFF);
+
+ /* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU subframes */
+ if (rxh->RxStatus1 & RXS_PBPRES) {
+ if (p->len < 2) {
+ wiphy_err(wlc->wiphy, "wl%d: recv: rcvd runt of "
+ "len %d\n", wlc->pub->unit, p->len);
+ goto toss;
+ }
+ skb_pull(p, 2);
+ }
+
+ h = (struct ieee80211_hdr *)(p->data + D11_PHY_HDR_LEN);
+ len = p->len;
+
+ if (rxh->RxStatus1 & RXS_FCSERR) {
+ if (wlc->pub->mac80211_state & MAC80211_PROMISC_BCNS) {
+ wiphy_err(wlc->wiphy, "FCSERR while scanning******* -"
+ " tossing\n");
+ goto toss;
+ } else {
+ wiphy_err(wlc->wiphy, "RCSERR!!!\n");
+ goto toss;
+ }
+ }
+
+ /* check received pkt has at least frame control field */
+ if (len < D11_PHY_HDR_LEN + sizeof(h->frame_control))
+ goto toss;
+
+ /* not supporting A-MSDU */
+ is_amsdu = rxh->RxStatus2 & RXS_AMSDU_MASK;
+ if (is_amsdu)
+ goto toss;
+
+ brcms_c_recvctl(wlc, rxh, p);
+ return;
+
+ toss:
+ brcmu_pkt_buf_free_skb(p);
+}
+
+/* Process received frames */
+/*
+ * Return true if more frames need to be processed. false otherwise.
+ * Param 'bound' indicates max. # frames to process before break out.
+ */
+static bool
+brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound)
+{
+ struct sk_buff *p;
+ struct sk_buff *head = NULL;
+ struct sk_buff *tail = NULL;
+ uint n = 0;
+ uint bound_limit = bound ? RXBND : -1;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+ /* gather received frames */
+ while ((p = dma_rx(wlc_hw->di[fifo]))) {
+
+ if (!tail)
+ head = tail = p;
+ else {
+ tail->prev = p;
+ tail = p;
+ }
+
+ /* !give others some time to run! */
+ if (++n >= bound_limit)
+ break;
+ }
+
+ /* post more rbufs */
+ dma_rxfill(wlc_hw->di[fifo]);
+
+ /* process each frame */
+ while ((p = head) != NULL) {
+ struct d11rxhdr_le *rxh_le;
+ struct d11rxhdr *rxh;
+ head = head->prev;
+ p->prev = NULL;
+
+ rxh_le = (struct d11rxhdr_le *)p->data;
+ rxh = (struct d11rxhdr *)p->data;
+
+ /* fixup rx header endianness */
+ rxh->RxFrameSize = le16_to_cpu(rxh_le->RxFrameSize);
+ rxh->PhyRxStatus_0 = le16_to_cpu(rxh_le->PhyRxStatus_0);
+ rxh->PhyRxStatus_1 = le16_to_cpu(rxh_le->PhyRxStatus_1);
+ rxh->PhyRxStatus_2 = le16_to_cpu(rxh_le->PhyRxStatus_2);
+ rxh->PhyRxStatus_3 = le16_to_cpu(rxh_le->PhyRxStatus_3);
+ rxh->PhyRxStatus_4 = le16_to_cpu(rxh_le->PhyRxStatus_4);
+ rxh->PhyRxStatus_5 = le16_to_cpu(rxh_le->PhyRxStatus_5);
+ rxh->RxStatus1 = le16_to_cpu(rxh_le->RxStatus1);
+ rxh->RxStatus2 = le16_to_cpu(rxh_le->RxStatus2);
+ rxh->RxTSFTime = le16_to_cpu(rxh_le->RxTSFTime);
+ rxh->RxChan = le16_to_cpu(rxh_le->RxChan);
+
+ brcms_c_recv(wlc_hw->wlc, p);
+ }
+
+ return n >= bound_limit;
+}
+
+/* second-level interrupt processing
+ * Return true if another dpc needs to be re-scheduled. false otherwise.
+ * Param 'bounded' indicates if applicable loops should be bounded.
+ */
+bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
+{
+ u32 macintstatus;
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ struct d11regs __iomem *regs = wlc_hw->regs;
+ struct wiphy *wiphy = wlc->wiphy;
+
+ if (brcms_deviceremoved(wlc)) {
+ wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
+ __func__);
+ brcms_down(wlc->wl);
+ return false;
+ }
+
+ /* grab and clear the saved software intstatus bits */
+ macintstatus = wlc->macintstatus;
+ wlc->macintstatus = 0;
+
+ BCMMSG(wlc->wiphy, "wl%d: macintstatus 0x%x\n",
+ wlc_hw->unit, macintstatus);
+
+ WARN_ON(macintstatus & MI_PRQ); /* PRQ Interrupt in non-MBSS */
+
+ /* tx status */
+ if (macintstatus & MI_TFS) {
+ bool fatal;
+ if (brcms_b_txstatus(wlc->hw, bounded, &fatal))
+ wlc->macintstatus |= MI_TFS;
+ if (fatal) {
+ wiphy_err(wiphy, "MI_TFS: fatal\n");
+ goto fatal;
+ }
+ }
+
+ if (macintstatus & (MI_TBTT | MI_DTIM_TBTT))
+ brcms_c_tbtt(wlc);
+
+ /* ATIM window end */
+ if (macintstatus & MI_ATIMWINEND) {
+ BCMMSG(wlc->wiphy, "end of ATIM window\n");
+ OR_REG(&regs->maccommand, wlc->qvalid);
+ wlc->qvalid = 0;
+ }
+
+ /*
+ * received data or control frame, MI_DMAINT is
+ * indication of RX_FIFO interrupt
+ */
+ if (macintstatus & MI_DMAINT)
+ if (brcms_b_recv(wlc_hw, RX_FIFO, bounded))
+ wlc->macintstatus |= MI_DMAINT;
+
+ /* noise sample collected */
+ if (macintstatus & MI_BG_NOISE)
+ wlc_phy_noise_sample_intr(wlc_hw->band->pi);
+
+ if (macintstatus & MI_GP0) {
+ wiphy_err(wiphy, "wl%d: PSM microcode watchdog fired at %d "
+ "(seconds). Resetting.\n", wlc_hw->unit, wlc_hw->now);
+
+ printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n",
+ __func__, wlc_hw->sih->chip,
+ wlc_hw->sih->chiprev);
+ /* big hammer */
+ brcms_init(wlc->wl);
+ }
+
+ /* gptimer timeout */
+ if (macintstatus & MI_TO)
+ W_REG(&regs->gptimer, 0);
+
+ if (macintstatus & MI_RFDISABLE) {
+ BCMMSG(wlc->wiphy, "wl%d: BMAC Detected a change on the"
+ " RF Disable Input\n", wlc_hw->unit);
+ brcms_rfkill_set_hw_state(wlc->wl);
+ }
+
+ /* send any enq'd tx packets. Just makes sure to jump start tx */
+ if (!pktq_empty(&wlc->pkt_queue->q))
+ brcms_c_send_q(wlc);
+
+ /* it isn't done and needs to be resched if macintstatus is non-zero */
+ return wlc->macintstatus != 0;
+
+ fatal:
+ brcms_init(wlc->wl);
+ return wlc->macintstatus != 0;
+}
+
+void brcms_c_init(struct brcms_c_info *wlc)
+{
+ struct d11regs __iomem *regs;
+ u16 chanspec;
+ bool mute = false;
+
+ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+
+ regs = wlc->regs;
+
+ /*
+ * This will happen if a big-hammer was executed. In
+ * that case, we want to go back to the channel that
+ * we were on and not new channel
+ */
+ if (wlc->pub->associated)
+ chanspec = wlc->home_chanspec;
+ else
+ chanspec = brcms_c_init_chanspec(wlc);
+
+ brcms_b_init(wlc->hw, chanspec, mute);
+
+ /* update beacon listen interval */
+ brcms_c_bcn_li_upd(wlc);
+
+ /* write ethernet address to core */
+ brcms_c_set_mac(wlc->bsscfg);
+ brcms_c_set_bssid(wlc->bsscfg);
+
+ /* Update tsf_cfprep if associated and up */
+ if (wlc->pub->associated && wlc->bsscfg->up) {
+ u32 bi;
+
+ /* get beacon period and convert to uS */
+ bi = wlc->bsscfg->current_bss->beacon_period << 10;
+ /*
+ * update since init path would reset
+ * to default value
+ */
+ W_REG(&regs->tsf_cfprep,
+ (bi << CFPREP_CBI_SHIFT));
+
+ /* Update maccontrol PM related bits */
+ brcms_c_set_ps_ctrl(wlc);
+ }
+
+ brcms_c_bandinit_ordered(wlc, chanspec);
+
+ /* init probe response timeout */
+ brcms_b_write_shm(wlc->hw, M_PRS_MAXTIME, wlc->prb_resp_timeout);
+
+ /* init max burst txop (framebursting) */
+ brcms_b_write_shm(wlc->hw, M_MBURST_TXOP,
+ (wlc->
+ _rifs ? (EDCF_AC_VO_TXOP_AP << 5) : MAXFRAMEBURST_TXOP));
+
+ /* initialize maximum allowed duty cycle */
+ brcms_c_duty_cycle_set(wlc, wlc->tx_duty_cycle_ofdm, true, true);
+ brcms_c_duty_cycle_set(wlc, wlc->tx_duty_cycle_cck, false, true);
+
+ /*
+ * Update some shared memory locations related to
+ * max AMPDU size allowed to received
+ */
+ brcms_c_ampdu_shm_upd(wlc->ampdu);
+
+ /* band-specific inits */
+ brcms_c_bsinit(wlc);
+
+ /* Enable EDCF mode (while the MAC is suspended) */
+ OR_REG(&regs->ifs_ctl, IFS_USEEDCF);
+ brcms_c_edcf_setparams(wlc, false);
+
+ /* Init precedence maps for empty FIFOs */
+ brcms_c_tx_prec_map_init(wlc);
+
+ /* read the ucode version if we have not yet done so */
+ if (wlc->ucode_rev == 0) {
+ wlc->ucode_rev =
+ brcms_b_read_shm(wlc->hw, M_BOM_REV_MAJOR) << NBITS(u16);
+ wlc->ucode_rev |= brcms_b_read_shm(wlc->hw, M_BOM_REV_MINOR);
+ }
+
+ /* ..now really unleash hell (allow the MAC out of suspend) */
+ brcms_c_enable_mac(wlc);
+
+ /* clear tx flow control */
+ brcms_c_txflowcontrol_reset(wlc);
+
+ /* enable the RF Disable Delay timer */
+ W_REG(&wlc->regs->rfdisabledly, RFDISABLE_DEFAULT);
+
+ /* initialize mpc delay */
+ wlc->mpc_delay_off = wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT;
+
+ /*
+ * Initialize WME parameters; if they haven't been set by some other
+ * mechanism (IOVar, etc) then read them from the hardware.
+ */
+ if (GFIELD(wlc->wme_retries[0], EDCF_SHORT) == 0) {
+ /* Uninitialized; read from HW */
+ int ac;
+
+ for (ac = 0; ac < AC_COUNT; ac++)
+ wlc->wme_retries[ac] =
+ brcms_b_read_shm(wlc->hw, M_AC_TXLMT_ADDR(ac));
+ }
+}
+
+/*
+ * The common driver entry routine. Error codes should be unique
+ */
+struct brcms_c_info *
+brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit,
+ bool piomode, void __iomem *regsva, struct pci_dev *btparam,
+ uint *perr)
+{
+ struct brcms_c_info *wlc;
+ uint err = 0;
+ uint i, j;
+ struct brcms_pub *pub;
+
+ /* allocate struct brcms_c_info state and its substructures */
+ wlc = (struct brcms_c_info *) brcms_c_attach_malloc(unit, &err, device);
+ if (wlc == NULL)
+ goto fail;
+ wlc->wiphy = wl->wiphy;
+ pub = wlc->pub;
+
+#if defined(BCMDBG)
+ wlc_info_dbg = wlc;
+#endif
+
+ wlc->band = wlc->bandstate[0];
+ wlc->core = wlc->corestate;
+ wlc->wl = wl;
+ pub->unit = unit;
+ pub->_piomode = piomode;
+ wlc->bandinit_pending = false;
+
+ /* populate struct brcms_c_info with default values */
+ brcms_c_info_init(wlc, unit);
+
+ /* update sta/ap related parameters */
+ brcms_c_ap_upd(wlc);
+
+ /*
+ * low level attach steps(all hw accesses go
+ * inside, no more in rest of the attach)
+ */
+ err = brcms_b_attach(wlc, vendor, device, unit, piomode, regsva,
+ btparam);
+ if (err)
+ goto fail;
+
+ brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR, OFF);
+
+ pub->phy_11ncapable = BRCMS_PHY_11N_CAP(wlc->band);
+
+ /* disable allowed duty cycle */
+ wlc->tx_duty_cycle_ofdm = 0;
+ wlc->tx_duty_cycle_cck = 0;
+
+ brcms_c_stf_phy_chain_calc(wlc);
+
+ /* txchain 1: txant 0, txchain 2: txant 1 */
+ if (BRCMS_ISNPHY(wlc->band) && (wlc->stf->txstreams == 1))
+ wlc->stf->txant = wlc->stf->hw_txchain - 1;
+
+ /* push to BMAC driver */
+ wlc_phy_stf_chain_init(wlc->band->pi, wlc->stf->hw_txchain,
+ wlc->stf->hw_rxchain);
+
+ /* pull up some info resulting from the low attach */
+ for (i = 0; i < NFIFO; i++)
+ wlc->core->txavail[i] = wlc->hw->txavail[i];
+
+ memcpy(&wlc->perm_etheraddr, &wlc->hw->etheraddr, ETH_ALEN);
+ memcpy(&pub->cur_etheraddr, &wlc->hw->etheraddr, ETH_ALEN);
+
+ for (j = 0; j < wlc->pub->_nbands; j++) {
+ wlc->band = wlc->bandstate[j];
+
+ if (!brcms_c_attach_stf_ant_init(wlc)) {
+ err = 24;
+ goto fail;
+ }
+
+ /* default contention windows size limits */
+ wlc->band->CWmin = APHY_CWMIN;
+ wlc->band->CWmax = PHY_CWMAX;
+
+ /* init gmode value */
+ if (wlc->band->bandtype == BRCM_BAND_2G) {
+ wlc->band->gmode = GMODE_AUTO;
+ brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER,
+ wlc->band->gmode);
+ }
+
+ /* init _n_enab supported mode */
+ if (BRCMS_PHY_11N_CAP(wlc->band)) {
+ pub->_n_enab = SUPPORT_11N;
+ brcms_c_protection_upd(wlc, BRCMS_PROT_N_USER,
+ ((pub->_n_enab ==
+ SUPPORT_11N) ? WL_11N_2x2 :
+ WL_11N_3x3));
+ }
+
+ /* init per-band default rateset, depend on band->gmode */
+ brcms_default_rateset(wlc, &wlc->band->defrateset);
+
+ /* fill in hw_rateset */
+ brcms_c_rateset_filter(&wlc->band->defrateset,
+ &wlc->band->hw_rateset, false,
+ BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK,
+ (bool) (wlc->pub->_n_enab & SUPPORT_11N));
+ }
+
+ /*
+ * update antenna config due to
+ * wlc->stf->txant/txchain/ant_rx_ovr change
+ */
+ brcms_c_stf_phy_txant_upd(wlc);
+
+ /* attach each modules */
+ err = brcms_c_attach_module(wlc);
+ if (err != 0)
+ goto fail;
+
+ if (!brcms_c_timers_init(wlc, unit)) {
+ wiphy_err(wl->wiphy, "wl%d: %s: init_timer failed\n", unit,
+ __func__);
+ err = 32;
+ goto fail;
+ }
+
+ /* depend on rateset, gmode */
+ wlc->cmi = brcms_c_channel_mgr_attach(wlc);
+ if (!wlc->cmi) {
+ wiphy_err(wl->wiphy, "wl%d: %s: channel_mgr_attach failed"
+ "\n", unit, __func__);
+ err = 33;
+ goto fail;
+ }
+
+ /* init default when all parameters are ready, i.e. ->rateset */
+ brcms_c_bss_default_init(wlc);
+
+ /*
+ * Complete the wlc default state initializations..
+ */
+
+ /* allocate our initial queue */
+ wlc->pkt_queue = brcms_c_txq_alloc(wlc);
+ if (wlc->pkt_queue == NULL) {
+ wiphy_err(wl->wiphy, "wl%d: %s: failed to malloc tx queue\n",
+ unit, __func__);
+ err = 100;
+ goto fail;
+ }
+
+ wlc->bsscfg->wlc = wlc;
+
+ wlc->mimoft = FT_HT;
+ wlc->mimo_40txbw = AUTO;
+ wlc->ofdm_40txbw = AUTO;
+ wlc->cck_40txbw = AUTO;
+ brcms_c_update_mimo_band_bwcap(wlc, BRCMS_N_BW_20IN2G_40IN5G);
+
+ /* Set default values of SGI */
+ if (BRCMS_SGI_CAP_PHY(wlc)) {
+ brcms_c_ht_update_sgi_rx(wlc, (BRCMS_N_SGI_20 |
+ BRCMS_N_SGI_40));
+ } else if (BRCMS_ISSSLPNPHY(wlc->band)) {
+ brcms_c_ht_update_sgi_rx(wlc, (BRCMS_N_SGI_20 |
+ BRCMS_N_SGI_40));
+ } else {
+ brcms_c_ht_update_sgi_rx(wlc, 0);
+ }
+
+ /* initialize radio_mpc_disable according to wlc->mpc */
+ brcms_c_radio_mpc_upd(wlc);
+ brcms_b_antsel_set(wlc->hw, wlc->asi->antsel_avail);
+
+ if (perr)
+ *perr = 0;
+
+ return wlc;
+
+ fail:
+ wiphy_err(wl->wiphy, "wl%d: %s: failed with err %d\n",
+ unit, __func__, err);
+ if (wlc)
+ brcms_c_detach(wlc);
+
+ if (perr)
+ *perr = err;
+ return NULL;
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.h b/drivers/net/wireless/brcm80211/brcmsmac/main.h
new file mode 100644
index 000000000000..c0e0fcfdfaf8
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h
@@ -0,0 +1,735 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_MAIN_H_
+#define _BRCM_MAIN_H_
+
+#include <linux/etherdevice.h>
+
+#include <brcmu_utils.h>
+#include "types.h"
+#include "d11.h"
+#include "scb.h"
+
+#define INVCHANNEL 255 /* invalid channel */
+
+/* max # brcms_c_module_register() calls */
+#define BRCMS_MAXMODULES 22
+
+#define SEQNUM_SHIFT 4
+#define SEQNUM_MAX 0x1000
+
+#define NTXRATE 64 /* # tx MPDUs rate is reported for */
+
+/* Maximum wait time for a MAC suspend */
+/* uS: 83mS is max packet time (64KB ampdu @ 6Mbps) */
+#define BRCMS_MAX_MAC_SUSPEND 83000
+
+/* responses for probe requests older that this are tossed, zero to disable */
+#define BRCMS_PRB_RESP_TIMEOUT 0 /* Disable probe response timeout */
+
+/* transmit buffer max headroom for protocol headers */
+#define TXOFF (D11_TXH_LEN + D11_PHY_HDR_LEN)
+
+#define AC_COUNT 4
+
+/* Macros for doing definition and get/set of bitfields
+ * Usage example, e.g. a three-bit field (bits 4-6):
+ * #define <NAME>_M BITFIELD_MASK(3)
+ * #define <NAME>_S 4
+ * ...
+ * regval = R_REG(osh, &regs->regfoo);
+ * field = GFIELD(regval, <NAME>);
+ * regval = SFIELD(regval, <NAME>, 1);
+ * W_REG(osh, &regs->regfoo, regval);
+ */
+#define BITFIELD_MASK(width) \
+ (((unsigned)1 << (width)) - 1)
+#define GFIELD(val, field) \
+ (((val) >> field ## _S) & field ## _M)
+#define SFIELD(val, field, bits) \
+ (((val) & (~(field ## _M << field ## _S))) | \
+ ((unsigned)(bits) << field ## _S))
+
+#define SW_TIMER_MAC_STAT_UPD 30 /* periodic MAC stats update */
+
+/* max # supported core revisions (0 .. MAXCOREREV - 1) */
+#define MAXCOREREV 28
+
+/* Double check that unsupported cores are not enabled */
+#if CONF_MSK(D11CONF, 0x4f) || CONF_GE(D11CONF, MAXCOREREV)
+#error "Configuration for D11CONF includes unsupported versions."
+#endif /* Bad versions */
+
+/* values for shortslot_override */
+#define BRCMS_SHORTSLOT_AUTO -1 /* Driver will manage Shortslot setting */
+#define BRCMS_SHORTSLOT_OFF 0 /* Turn off short slot */
+#define BRCMS_SHORTSLOT_ON 1 /* Turn on short slot */
+
+/* value for short/long and mixmode/greenfield preamble */
+#define BRCMS_LONG_PREAMBLE (0)
+#define BRCMS_SHORT_PREAMBLE (1 << 0)
+#define BRCMS_GF_PREAMBLE (1 << 1)
+#define BRCMS_MM_PREAMBLE (1 << 2)
+#define BRCMS_IS_MIMO_PREAMBLE(_pre) (((_pre) == BRCMS_GF_PREAMBLE) || \
+ ((_pre) == BRCMS_MM_PREAMBLE))
+
+/* TxFrameID */
+/* seq and frag bits: SEQNUM_SHIFT, FRAGNUM_MASK (802.11.h) */
+/* rate epoch bits: TXFID_RATE_SHIFT, TXFID_RATE_MASK ((wlc_rate.c) */
+#define TXFID_QUEUE_MASK 0x0007 /* Bits 0-2 */
+#define TXFID_SEQ_MASK 0x7FE0 /* Bits 5-15 */
+#define TXFID_SEQ_SHIFT 5 /* Number of bit shifts */
+#define TXFID_RATE_PROBE_MASK 0x8000 /* Bit 15 for rate probe */
+#define TXFID_RATE_MASK 0x0018 /* Mask for bits 3 and 4 */
+#define TXFID_RATE_SHIFT 3 /* Shift 3 bits for rate mask */
+
+/* promote boardrev */
+#define BOARDREV_PROMOTABLE 0xFF /* from */
+#define BOARDREV_PROMOTED 1 /* to */
+
+#define DATA_BLOCK_TX_SUPR (1 << 4)
+
+/* 802.1D Priority to TX FIFO number for wme */
+extern const u8 prio2fifo[];
+
+/* Ucode MCTL_WAKE override bits */
+#define BRCMS_WAKE_OVERRIDE_CLKCTL 0x01
+#define BRCMS_WAKE_OVERRIDE_PHYREG 0x02
+#define BRCMS_WAKE_OVERRIDE_MACSUSPEND 0x04
+#define BRCMS_WAKE_OVERRIDE_TXFIFO 0x08
+#define BRCMS_WAKE_OVERRIDE_FORCEFAST 0x10
+
+/* stuff pulled in from wlc.c */
+
+/* Interrupt bit error summary. Don't include I_RU: we refill DMA at other
+ * times; and if we run out, constant I_RU interrupts may cause lockup. We
+ * will still get error counts from rx0ovfl.
+ */
+#define I_ERRORS (I_PC | I_PD | I_DE | I_RO | I_XU)
+/* default software intmasks */
+#define DEF_RXINTMASK (I_RI) /* enable rx int on rxfifo only */
+#define DEF_MACINTMASK (MI_TXSTOP | MI_TBTT | MI_ATIMWINEND | MI_PMQ | \
+ MI_PHYTXERR | MI_DMAINT | MI_TFS | MI_BG_NOISE | \
+ MI_CCA | MI_TO | MI_GP0 | MI_RFDISABLE | MI_PWRUP)
+
+#define MAXTXPKTS 6 /* max # pkts pending */
+
+/* frameburst */
+#define MAXTXFRAMEBURST 8 /* vanilla xpress mode: max frames/burst */
+#define MAXFRAMEBURST_TXOP 10000 /* Frameburst TXOP in usec */
+
+#define NFIFO 6 /* # tx/rx fifopairs */
+
+/* PLL requests */
+
+/* pll is shared on old chips */
+#define BRCMS_PLLREQ_SHARED 0x1
+/* hold pll for radio monitor register checking */
+#define BRCMS_PLLREQ_RADIO_MON 0x2
+/* hold/release pll for some short operation */
+#define BRCMS_PLLREQ_FLIP 0x4
+
+#define CHANNEL_BANDUNIT(wlc, ch) \
+ (((ch) <= CH_MAX_2G_CHANNEL) ? BAND_2G_INDEX : BAND_5G_INDEX)
+
+#define OTHERBANDUNIT(wlc) \
+ ((uint)((wlc)->band->bandunit ? BAND_2G_INDEX : BAND_5G_INDEX))
+
+/*
+ * 802.11 protection information
+ *
+ * _g: use g spec protection, driver internal.
+ * g_override: override for use of g spec protection.
+ * gmode_user: user config gmode, operating band->gmode is different.
+ * overlap: Overlap BSS/IBSS protection for both 11g and 11n.
+ * nmode_user: user config nmode, operating pub->nmode is different.
+ * n_cfg: use OFDM protection on MIMO frames.
+ * n_cfg_override: override for use of N protection.
+ * nongf: non-GF present protection.
+ * nongf_override: override for use of GF protection.
+ * n_pam_override: override for preamble: MM or GF.
+ * n_obss: indicated OBSS Non-HT STA present.
+*/
+struct brcms_protection {
+ bool _g;
+ s8 g_override;
+ u8 gmode_user;
+ s8 overlap;
+ s8 nmode_user;
+ s8 n_cfg;
+ s8 n_cfg_override;
+ bool nongf;
+ s8 nongf_override;
+ s8 n_pam_override;
+ bool n_obss;
+};
+
+/*
+ * anything affecting the single/dual streams/antenna operation
+ *
+ * hw_txchain: HW txchain bitmap cfg.
+ * txchain: txchain bitmap being used.
+ * txstreams: number of txchains being used.
+ * hw_rxchain: HW rxchain bitmap cfg.
+ * rxchain: rxchain bitmap being used.
+ * rxstreams: number of rxchains being used.
+ * ant_rx_ovr: rx antenna override.
+ * txant: userTx antenna setting.
+ * phytxant: phyTx antenna setting in txheader.
+ * ss_opmode: singlestream Operational mode, 0:siso; 1:cdd.
+ * ss_algosel_auto: if true, use wlc->stf->ss_algo_channel;
+ * else use wlc->band->stf->ss_mode_band.
+ * ss_algo_channel: ss based on per-channel algo: 0: SISO, 1: CDD 2: STBC.
+ * rxchain_restore_delay: delay time to restore default rxchain.
+ * ldpc: AUTO/ON/OFF ldpc cap supported.
+ * txcore[MAX_STREAMS_SUPPORTED + 1]: bitmap of selected core for each Nsts.
+ * spatial_policy:
+ */
+struct brcms_stf {
+ u8 hw_txchain;
+ u8 txchain;
+ u8 txstreams;
+ u8 hw_rxchain;
+ u8 rxchain;
+ u8 rxstreams;
+ u8 ant_rx_ovr;
+ s8 txant;
+ u16 phytxant;
+ u8 ss_opmode;
+ bool ss_algosel_auto;
+ u16 ss_algo_channel;
+ u8 rxchain_restore_delay;
+ s8 ldpc;
+ u8 txcore[MAX_STREAMS_SUPPORTED + 1];
+ s8 spatial_policy;
+};
+
+#define BRCMS_STF_SS_STBC_TX(wlc, scb) \
+ (((wlc)->stf->txstreams > 1) && (((wlc)->band->band_stf_stbc_tx == ON) \
+ || (((scb)->flags & SCB_STBCCAP) && \
+ (wlc)->band->band_stf_stbc_tx == AUTO && \
+ isset(&((wlc)->stf->ss_algo_channel), PHY_TXC1_MODE_STBC))))
+
+#define BRCMS_STBC_CAP_PHY(wlc) (BRCMS_ISNPHY(wlc->band) && \
+ NREV_GE(wlc->band->phyrev, 3))
+
+#define BRCMS_SGI_CAP_PHY(wlc) ((BRCMS_ISNPHY(wlc->band) && \
+ NREV_GE(wlc->band->phyrev, 3)) || \
+ BRCMS_ISLCNPHY(wlc->band))
+
+#define BRCMS_CHAN_PHYTYPE(x) (((x) & RXS_CHAN_PHYTYPE_MASK) \
+ >> RXS_CHAN_PHYTYPE_SHIFT)
+#define BRCMS_CHAN_CHANNEL(x) (((x) & RXS_CHAN_ID_MASK) \
+ >> RXS_CHAN_ID_SHIFT)
+
+/*
+ * core state (mac)
+ */
+struct brcms_core {
+ uint coreidx; /* # sb enumerated core */
+
+ /* fifo */
+ uint *txavail[NFIFO]; /* # tx descriptors available */
+ s16 txpktpend[NFIFO]; /* tx admission control */
+
+ struct macstat *macstat_snapshot; /* mac hw prev read values */
+};
+
+/*
+ * band state (phy+ana+radio)
+ */
+struct brcms_band {
+ int bandtype; /* BRCM_BAND_2G, BRCM_BAND_5G */
+ uint bandunit; /* bandstate[] index */
+
+ u16 phytype; /* phytype */
+ u16 phyrev;
+ u16 radioid;
+ u16 radiorev;
+ struct brcms_phy_pub *pi; /* pointer to phy specific information */
+ bool abgphy_encore;
+
+ u8 gmode; /* currently active gmode */
+
+ struct scb *hwrs_scb; /* permanent scb for hw rateset */
+
+ /* band-specific copy of default_bss.rateset */
+ struct brcms_c_rateset defrateset;
+
+ u8 band_stf_ss_mode; /* Configured STF type, 0:siso; 1:cdd */
+ s8 band_stf_stbc_tx; /* STBC TX 0:off; 1:force on; -1:auto */
+ /* rates supported by chip (phy-specific) */
+ struct brcms_c_rateset hw_rateset;
+ u8 basic_rate[BRCM_MAXRATE + 1]; /* basic rates indexed by rate */
+ bool mimo_cap_40; /* 40 MHz cap enabled on this band */
+ s8 antgain; /* antenna gain from srom */
+
+ u16 CWmin; /* minimum size of contention window, in unit of aSlotTime */
+ u16 CWmax; /* maximum size of contention window, in unit of aSlotTime */
+ struct ieee80211_supported_band band;
+};
+
+/* module control blocks */
+struct modulecb {
+ /* module name : NULL indicates empty array member */
+ char name[32];
+ /* handle passed when handler 'doiovar' is called */
+ struct brcms_info *hdl;
+
+ int (*down_fn)(void *handle); /* down handler. Note: the int returned
+ * by the down function is a count of the
+ * number of timers that could not be
+ * freed.
+ */
+
+};
+
+struct brcms_hw_band {
+ int bandtype; /* BRCM_BAND_2G, BRCM_BAND_5G */
+ uint bandunit; /* bandstate[] index */
+ u16 mhfs[MHFMAX]; /* MHF array shadow */
+ u8 bandhw_stf_ss_mode; /* HW configured STF type, 0:siso; 1:cdd */
+ u16 CWmin;
+ u16 CWmax;
+ u32 core_flags;
+
+ u16 phytype; /* phytype */
+ u16 phyrev;
+ u16 radioid;
+ u16 radiorev;
+ struct brcms_phy_pub *pi; /* pointer to phy specific information */
+ bool abgphy_encore;
+};
+
+struct brcms_hardware {
+ bool _piomode; /* true if pio mode */
+ struct brcms_c_info *wlc;
+
+ /* fifo */
+ struct dma_pub *di[NFIFO]; /* dma handles, per fifo */
+
+ uint unit; /* device instance number */
+
+ /* version info */
+ u16 vendorid; /* PCI vendor id */
+ u16 deviceid; /* PCI device id */
+ uint corerev; /* core revision */
+ u8 sromrev; /* version # of the srom */
+ u16 boardrev; /* version # of particular board */
+ u32 boardflags; /* Board specific flags from srom */
+ u32 boardflags2; /* More board flags if sromrev >= 4 */
+ u32 machwcap; /* MAC capabilities */
+ u32 machwcap_backup; /* backup of machwcap */
+
+ struct si_pub *sih; /* SI handle (cookie for siutils calls) */
+ struct d11regs __iomem *regs; /* pointer to device registers */
+ struct phy_shim_info *physhim; /* phy shim layer handler */
+ struct shared_phy *phy_sh; /* pointer to shared phy state */
+ struct brcms_hw_band *band;/* pointer to active per-band state */
+ /* band state per phy/radio */
+ struct brcms_hw_band *bandstate[MAXBANDS];
+ u16 bmac_phytxant; /* cache of high phytxant state */
+ bool shortslot; /* currently using 11g ShortSlot timing */
+ u16 SRL; /* 802.11 dot11ShortRetryLimit */
+ u16 LRL; /* 802.11 dot11LongRetryLimit */
+ u16 SFBL; /* Short Frame Rate Fallback Limit */
+ u16 LFBL; /* Long Frame Rate Fallback Limit */
+
+ bool up; /* d11 hardware up and running */
+ uint now; /* # elapsed seconds */
+ uint _nbands; /* # bands supported */
+ u16 chanspec; /* bmac chanspec shadow */
+
+ uint *txavail[NFIFO]; /* # tx descriptors available */
+ const u16 *xmtfifo_sz; /* fifo size in 256B for each xmt fifo */
+
+ u32 pllreq; /* pll requests to keep PLL on */
+
+ u8 suspended_fifos; /* Which TX fifo to remain awake for */
+ u32 maccontrol; /* Cached value of maccontrol */
+ uint mac_suspend_depth; /* current depth of mac_suspend levels */
+ u32 wake_override; /* bit flags to force MAC to WAKE mode */
+ u32 mute_override; /* Prevent ucode from sending beacons */
+ u8 etheraddr[ETH_ALEN]; /* currently configured ethernet address */
+ bool noreset; /* true= do not reset hw, used by WLC_OUT */
+ bool forcefastclk; /* true if h/w is forcing to use fast clk */
+ bool clk; /* core is out of reset and has clock */
+ bool sbclk; /* sb has clock */
+ bool phyclk; /* phy is out of reset and has clock */
+
+ bool ucode_loaded; /* true after ucode downloaded */
+
+
+ u8 hw_stf_ss_opmode; /* STF single stream operation mode */
+ u8 antsel_type; /* Type of boardlevel mimo antenna switch-logic
+ * 0 = N/A, 1 = 2x4 board, 2 = 2x3 CB2 board
+ */
+ u32 antsel_avail; /*
+ * put struct antsel_info here if more info is
+ * needed
+ */
+};
+
+/* TX Queue information
+ *
+ * Each flow of traffic out of the device has a TX Queue with independent
+ * flow control. Several interfaces may be associated with a single TX Queue
+ * if they belong to the same flow of traffic from the device. For multi-channel
+ * operation there are independent TX Queues for each channel.
+ */
+struct brcms_txq_info {
+ struct brcms_txq_info *next;
+ struct pktq q;
+ uint stopped; /* tx flow control bits */
+};
+
+/*
+ * Principal common driver data structure.
+ *
+ * pub: pointer to driver public state.
+ * wl: pointer to specific private state.
+ * regs: pointer to device registers.
+ * hw: HW related state.
+ * clkreq_override: setting for clkreq for PCIE : Auto, 0, 1.
+ * fastpwrup_dly: time in us needed to bring up d11 fast clock.
+ * macintstatus: bit channel between isr and dpc.
+ * macintmask: sw runtime master macintmask value.
+ * defmacintmask: default "on" macintmask value.
+ * clk: core is out of reset and has clock.
+ * core: pointer to active io core.
+ * band: pointer to active per-band state.
+ * corestate: per-core state (one per hw core).
+ * bandstate: per-band state (one per phy/radio).
+ * qvalid: DirFrmQValid and BcMcFrmQValid.
+ * ampdu: ampdu module handler.
+ * asi: antsel module handler.
+ * cmi: channel manager module handler.
+ * vendorid: PCI vendor id.
+ * deviceid: PCI device id.
+ * ucode_rev: microcode revision.
+ * machwcap: MAC capabilities, BMAC shadow.
+ * perm_etheraddr: original sprom local ethernet address.
+ * bandlocked: disable auto multi-band switching.
+ * bandinit_pending: track band init in auto band.
+ * radio_monitor: radio timer is running.
+ * going_down: down path intermediate variable.
+ * mpc: enable minimum power consumption.
+ * mpc_dlycnt: # of watchdog cnt before turn disable radio.
+ * mpc_offcnt: # of watchdog cnt that radio is disabled.
+ * mpc_delay_off: delay radio disable by # of watchdog cnt.
+ * prev_non_delay_mpc: prev state brcms_c_is_non_delay_mpc.
+ * wdtimer: timer for watchdog routine.
+ * radio_timer: timer for hw radio button monitor routine.
+ * monitor: monitor (MPDU sniffing) mode.
+ * bcnmisc_monitor: bcns promisc mode override for monitor.
+ * _rifs: enable per-packet rifs.
+ * bcn_li_bcn: beacon listen interval in # beacons.
+ * bcn_li_dtim: beacon listen interval in # dtims.
+ * WDarmed: watchdog timer is armed.
+ * WDlast: last time wlc_watchdog() was called.
+ * edcf_txop[AC_COUNT]: current txop for each ac.
+ * wme_retries: per-AC retry limits.
+ * tx_prec_map: Precedence map based on HW FIFO space.
+ * fifo2prec_map[NFIFO]: pointer to fifo2_prec map based on WME.
+ * bsscfg: set of BSS configurations, idx 0 is default and always valid.
+ * cfg: the primary bsscfg (can be AP or STA).
+ * tx_queues: common TX Queue list.
+ * modulecb:
+ * mimoft: SIGN or 11N.
+ * cck_40txbw: 11N, cck tx b/w override when in 40MHZ mode.
+ * ofdm_40txbw: 11N, ofdm tx b/w override when in 40MHZ mode.
+ * mimo_40txbw: 11N, mimo tx b/w override when in 40MHZ mode.
+ * default_bss: configured BSS parameters.
+ * mc_fid_counter: BC/MC FIFO frame ID counter.
+ * country_default: saved country for leaving 802.11d auto-country mode.
+ * autocountry_default: initial country for 802.11d auto-country mode.
+ * prb_resp_timeout: do not send prb resp if request older
+ * than this, 0 = disable.
+ * home_chanspec: shared home chanspec.
+ * chanspec: target operational channel.
+ * usr_fragthresh: user configured fragmentation threshold.
+ * fragthresh[NFIFO]: per-fifo fragmentation thresholds.
+ * RTSThresh: 802.11 dot11RTSThreshold.
+ * SRL: 802.11 dot11ShortRetryLimit.
+ * LRL: 802.11 dot11LongRetryLimit.
+ * SFBL: Short Frame Rate Fallback Limit.
+ * LFBL: Long Frame Rate Fallback Limit.
+ * shortslot: currently using 11g ShortSlot timing.
+ * shortslot_override: 11g ShortSlot override.
+ * include_legacy_erp: include Legacy ERP info elt ID 47 as well as g ID 42.
+ * PLCPHdr_override: 802.11b Preamble Type override.
+ * stf:
+ * bcn_rspec: save bcn ratespec purpose.
+ * tempsense_lasttime;
+ * tx_duty_cycle_ofdm: maximum allowed duty cycle for OFDM.
+ * tx_duty_cycle_cck: maximum allowed duty cycle for CCK.
+ * pkt_queue: txq for transmit packets.
+ * wiphy:
+ * pri_scb: primary Station Control Block
+ */
+struct brcms_c_info {
+ struct brcms_pub *pub;
+ struct brcms_info *wl;
+ struct d11regs __iomem *regs;
+ struct brcms_hardware *hw;
+
+ /* clock */
+ u16 fastpwrup_dly;
+
+ /* interrupt */
+ u32 macintstatus;
+ u32 macintmask;
+ u32 defmacintmask;
+
+ bool clk;
+
+ /* multiband */
+ struct brcms_core *core;
+ struct brcms_band *band;
+ struct brcms_core *corestate;
+ struct brcms_band *bandstate[MAXBANDS];
+
+ /* packet queue */
+ uint qvalid;
+
+ struct ampdu_info *ampdu;
+ struct antsel_info *asi;
+ struct brcms_cm_info *cmi;
+
+ u16 vendorid;
+ u16 deviceid;
+ uint ucode_rev;
+
+ u8 perm_etheraddr[ETH_ALEN];
+
+ bool bandlocked;
+ bool bandinit_pending;
+
+ bool radio_monitor;
+ bool going_down;
+
+ bool mpc;
+ u8 mpc_dlycnt;
+ u8 mpc_offcnt;
+ u8 mpc_delay_off;
+ u8 prev_non_delay_mpc;
+
+ struct brcms_timer *wdtimer;
+ struct brcms_timer *radio_timer;
+
+ /* promiscuous */
+ bool monitor;
+ bool bcnmisc_monitor;
+
+ /* driver feature */
+ bool _rifs;
+
+ /* AP-STA synchronization, power save */
+ u8 bcn_li_bcn;
+ u8 bcn_li_dtim;
+
+ bool WDarmed;
+ u32 WDlast;
+
+ /* WME */
+ u16 edcf_txop[AC_COUNT];
+
+ u16 wme_retries[AC_COUNT];
+ u16 tx_prec_map;
+ u16 fifo2prec_map[NFIFO];
+
+ struct brcms_bss_cfg *bsscfg;
+
+ /* tx queue */
+ struct brcms_txq_info *tx_queues;
+
+ struct modulecb *modulecb;
+
+ u8 mimoft;
+ s8 cck_40txbw;
+ s8 ofdm_40txbw;
+ s8 mimo_40txbw;
+
+ struct brcms_bss_info *default_bss;
+
+ u16 mc_fid_counter;
+
+ char country_default[BRCM_CNTRY_BUF_SZ];
+ char autocountry_default[BRCM_CNTRY_BUF_SZ];
+ u16 prb_resp_timeout;
+
+ u16 home_chanspec;
+
+ /* PHY parameters */
+ u16 chanspec;
+ u16 usr_fragthresh;
+ u16 fragthresh[NFIFO];
+ u16 RTSThresh;
+ u16 SRL;
+ u16 LRL;
+ u16 SFBL;
+ u16 LFBL;
+
+ /* network config */
+ bool shortslot;
+ s8 shortslot_override;
+ bool include_legacy_erp;
+
+ struct brcms_protection *protection;
+ s8 PLCPHdr_override;
+
+ struct brcms_stf *stf;
+
+ u32 bcn_rspec;
+
+ uint tempsense_lasttime;
+
+ u16 tx_duty_cycle_ofdm;
+ u16 tx_duty_cycle_cck;
+
+ struct brcms_txq_info *pkt_queue;
+ struct wiphy *wiphy;
+ struct scb pri_scb;
+};
+
+/* antsel module specific state */
+struct antsel_info {
+ struct brcms_c_info *wlc; /* pointer to main wlc structure */
+ struct brcms_pub *pub; /* pointer to public fn */
+ u8 antsel_type; /* Type of boardlevel mimo antenna switch-logic
+ * 0 = N/A, 1 = 2x4 board, 2 = 2x3 CB2 board
+ */
+ u8 antsel_antswitch; /* board level antenna switch type */
+ bool antsel_avail; /* Ant selection availability (SROM based) */
+ struct brcms_antselcfg antcfg_11n; /* antenna configuration */
+ struct brcms_antselcfg antcfg_cur; /* current antenna config (auto) */
+};
+
+/*
+ * BSS configuration state
+ *
+ * wlc: wlc to which this bsscfg belongs to.
+ * up: is this configuration up operational
+ * enable: is this configuration enabled
+ * associated: is BSS in ASSOCIATED state
+ * BSS: infraustructure or adhoc
+ * SSID_len: the length of SSID
+ * SSID: SSID string
+ *
+ *
+ * BSSID: BSSID (associated)
+ * cur_etheraddr: h/w address
+ * flags: BSSCFG flags; see below
+ *
+ * current_bss: BSS parms in ASSOCIATED state
+ *
+ *
+ * ID: 'unique' ID of this bsscfg, assigned at bsscfg allocation
+ */
+struct brcms_bss_cfg {
+ struct brcms_c_info *wlc;
+ bool up;
+ bool enable;
+ bool associated;
+ bool BSS;
+ u8 SSID_len;
+ u8 SSID[IEEE80211_MAX_SSID_LEN];
+ u8 BSSID[ETH_ALEN];
+ u8 cur_etheraddr[ETH_ALEN];
+ struct brcms_bss_info *current_bss;
+};
+
+extern void brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo,
+ struct sk_buff *p,
+ bool commit, s8 txpktpend);
+extern void brcms_c_txfifo_complete(struct brcms_c_info *wlc, uint fifo,
+ s8 txpktpend);
+extern void brcms_c_txq_enq(struct brcms_c_info *wlc, struct scb *scb,
+ struct sk_buff *sdu, uint prec);
+extern void brcms_c_print_txstatus(struct tx_status *txs);
+extern int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo,
+ uint *blocks);
+
+#if defined(BCMDBG)
+extern void brcms_c_print_txdesc(struct d11txh *txh);
+#else
+#define brcms_c_print_txdesc(a)
+#endif
+
+extern int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config);
+extern void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc,
+ bool promisc);
+extern void brcms_c_send_q(struct brcms_c_info *wlc);
+extern int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu,
+ uint *fifo);
+extern u16 brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec,
+ uint mac_len);
+extern u32 brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc,
+ u32 rspec,
+ bool use_rspec, u16 mimo_ctlchbw);
+extern u16 brcms_c_compute_rtscts_dur(struct brcms_c_info *wlc, bool cts_only,
+ u32 rts_rate,
+ u32 frame_rate,
+ u8 rts_preamble_type,
+ u8 frame_preamble_type, uint frame_len,
+ bool ba);
+extern void brcms_c_inval_dma_pkts(struct brcms_hardware *hw,
+ struct ieee80211_sta *sta,
+ void (*dma_callback_fn));
+extern void brcms_c_update_beacon(struct brcms_c_info *wlc);
+extern void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend);
+extern int brcms_c_set_nmode(struct brcms_c_info *wlc);
+extern void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc,
+ u32 bcn_rate);
+extern void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw,
+ u8 antsel_type);
+extern void brcms_b_set_chanspec(struct brcms_hardware *wlc_hw,
+ u16 chanspec,
+ bool mute, struct txpwr_limits *txpwr);
+extern void brcms_b_write_shm(struct brcms_hardware *wlc_hw, uint offset,
+ u16 v);
+extern u16 brcms_b_read_shm(struct brcms_hardware *wlc_hw, uint offset);
+extern void brcms_b_mhf(struct brcms_hardware *wlc_hw, u8 idx, u16 mask,
+ u16 val, int bands);
+extern void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags);
+extern void brcms_b_mctrl(struct brcms_hardware *wlc_hw, u32 mask, u32 val);
+extern void brcms_b_phy_reset(struct brcms_hardware *wlc_hw);
+extern void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw);
+extern void brcms_b_core_phypll_reset(struct brcms_hardware *wlc_hw);
+extern void brcms_c_ucode_wake_override_set(struct brcms_hardware *wlc_hw,
+ u32 override_bit);
+extern void brcms_c_ucode_wake_override_clear(struct brcms_hardware *wlc_hw,
+ u32 override_bit);
+extern void brcms_b_write_template_ram(struct brcms_hardware *wlc_hw,
+ int offset, int len, void *buf);
+extern u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate);
+extern void brcms_b_copyto_objmem(struct brcms_hardware *wlc_hw,
+ uint offset, const void *buf, int len,
+ u32 sel);
+extern void brcms_b_copyfrom_objmem(struct brcms_hardware *wlc_hw, uint offset,
+ void *buf, int len, u32 sel);
+extern void brcms_b_switch_macfreq(struct brcms_hardware *wlc_hw, u8 spurmode);
+extern u16 brcms_b_get_txant(struct brcms_hardware *wlc_hw);
+extern void brcms_b_phyclk_fgc(struct brcms_hardware *wlc_hw, bool clk);
+extern void brcms_b_macphyclk_set(struct brcms_hardware *wlc_hw, bool clk);
+extern void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on);
+extern void brcms_b_txant_set(struct brcms_hardware *wlc_hw, u16 phytxant);
+extern void brcms_b_band_stf_ss_set(struct brcms_hardware *wlc_hw,
+ u8 stf_mode);
+extern void brcms_c_init_scb(struct scb *scb);
+
+#endif /* _BRCM_MAIN_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/nicpci.c b/drivers/net/wireless/brcm80211/brcmsmac/nicpci.c
new file mode 100644
index 000000000000..0bcb26792046
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/nicpci.c
@@ -0,0 +1,835 @@
+/*
+ * Copyright (c) 2010 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/slab.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include <defs.h>
+#include <soc.h>
+#include <chipcommon.h>
+#include "aiutils.h"
+#include "pub.h"
+#include "nicpci.h"
+
+/* SPROM offsets */
+#define SRSH_ASPM_OFFSET 4 /* word 4 */
+#define SRSH_ASPM_ENB 0x18 /* bit 3, 4 */
+#define SRSH_ASPM_L1_ENB 0x10 /* bit 4 */
+#define SRSH_ASPM_L0s_ENB 0x8 /* bit 3 */
+
+#define SRSH_PCIE_MISC_CONFIG 5 /* word 5 */
+#define SRSH_L23READY_EXIT_NOPERST 0x8000 /* bit 15 */
+#define SRSH_CLKREQ_OFFSET_REV5 20 /* word 20 for srom rev <= 5 */
+#define SRSH_CLKREQ_ENB 0x0800 /* bit 11 */
+#define SRSH_BD_OFFSET 6 /* word 6 */
+
+/* chipcontrol */
+#define CHIPCTRL_4321_PLL_DOWN 0x800000/* serdes PLL down override */
+
+/* MDIO control */
+#define MDIOCTL_DIVISOR_MASK 0x7f /* clock to be used on MDIO */
+#define MDIOCTL_DIVISOR_VAL 0x2
+#define MDIOCTL_PREAM_EN 0x80 /* Enable preamble sequnce */
+#define MDIOCTL_ACCESS_DONE 0x100 /* Transaction complete */
+
+/* MDIO Data */
+#define MDIODATA_MASK 0x0000ffff /* data 2 bytes */
+#define MDIODATA_TA 0x00020000 /* Turnaround */
+
+#define MDIODATA_REGADDR_SHF 18 /* Regaddr shift */
+#define MDIODATA_REGADDR_MASK 0x007c0000 /* Regaddr Mask */
+#define MDIODATA_DEVADDR_SHF 23 /* Physmedia devaddr shift */
+#define MDIODATA_DEVADDR_MASK 0x0f800000
+ /* Physmedia devaddr Mask */
+
+/* MDIO Data for older revisions < 10 */
+#define MDIODATA_REGADDR_SHF_OLD 18 /* Regaddr shift */
+#define MDIODATA_REGADDR_MASK_OLD 0x003c0000
+ /* Regaddr Mask */
+#define MDIODATA_DEVADDR_SHF_OLD 22 /* Physmedia devaddr shift */
+#define MDIODATA_DEVADDR_MASK_OLD 0x0fc00000
+ /* Physmedia devaddr Mask */
+
+/* Transactions flags */
+#define MDIODATA_WRITE 0x10000000
+#define MDIODATA_READ 0x20000000
+#define MDIODATA_START 0x40000000
+
+#define MDIODATA_DEV_ADDR 0x0 /* dev address for serdes */
+#define MDIODATA_BLK_ADDR 0x1F /* blk address for serdes */
+
+/* serdes regs (rev < 10) */
+#define MDIODATA_DEV_PLL 0x1d /* SERDES PLL Dev */
+#define MDIODATA_DEV_TX 0x1e /* SERDES TX Dev */
+#define MDIODATA_DEV_RX 0x1f /* SERDES RX Dev */
+
+/* SERDES RX registers */
+#define SERDES_RX_CTRL 1 /* Rx cntrl */
+#define SERDES_RX_TIMER1 2 /* Rx Timer1 */
+#define SERDES_RX_CDR 6 /* CDR */
+#define SERDES_RX_CDRBW 7 /* CDR BW */
+/* SERDES RX control register */
+#define SERDES_RX_CTRL_FORCE 0x80 /* rxpolarity_force */
+#define SERDES_RX_CTRL_POLARITY 0x40 /* rxpolarity_value */
+
+/* SERDES PLL registers */
+#define SERDES_PLL_CTRL 1 /* PLL control reg */
+#define PLL_CTRL_FREQDET_EN 0x4000 /* bit 14 is FREQDET on */
+
+/* Linkcontrol reg offset in PCIE Cap */
+#define PCIE_CAP_LINKCTRL_OFFSET 16 /* offset in pcie cap */
+#define PCIE_CAP_LCREG_ASPML0s 0x01 /* ASPM L0s in linkctrl */
+#define PCIE_CAP_LCREG_ASPML1 0x02 /* ASPM L1 in linkctrl */
+#define PCIE_CLKREQ_ENAB 0x100 /* CLKREQ Enab in linkctrl */
+
+#define PCIE_ASPM_ENAB 3 /* ASPM L0s & L1 in linkctrl */
+#define PCIE_ASPM_L1_ENAB 2 /* ASPM L0s & L1 in linkctrl */
+#define PCIE_ASPM_L0s_ENAB 1 /* ASPM L0s & L1 in linkctrl */
+#define PCIE_ASPM_DISAB 0 /* ASPM L0s & L1 in linkctrl */
+
+/* Power management threshold */
+#define PCIE_L1THRESHOLDTIME_MASK 0xFF00 /* bits 8 - 15 */
+#define PCIE_L1THRESHOLDTIME_SHIFT 8 /* PCIE_L1THRESHOLDTIME_SHIFT */
+#define PCIE_L1THRESHOLD_WARVAL 0x72 /* WAR value */
+#define PCIE_ASPMTIMER_EXTEND 0x01000000
+ /* > rev7:
+ * enable extend ASPM timer
+ */
+
+/* different register spaces to access thru pcie indirect access */
+#define PCIE_CONFIGREGS 1 /* Access to config space */
+#define PCIE_PCIEREGS 2 /* Access to pcie registers */
+
+/* PCIE protocol PHY diagnostic registers */
+#define PCIE_PLP_STATUSREG 0x204 /* Status */
+
+/* Status reg PCIE_PLP_STATUSREG */
+#define PCIE_PLP_POLARITYINV_STAT 0x10
+
+/* PCIE protocol DLLP diagnostic registers */
+#define PCIE_DLLP_LCREG 0x100 /* Link Control */
+#define PCIE_DLLP_PMTHRESHREG 0x128 /* Power Management Threshold */
+
+/* PCIE protocol TLP diagnostic registers */
+#define PCIE_TLP_WORKAROUNDSREG 0x004 /* TLP Workarounds */
+
+/* Sonics to PCI translation types */
+#define SBTOPCI_PREF 0x4 /* prefetch enable */
+#define SBTOPCI_BURST 0x8 /* burst enable */
+#define SBTOPCI_RC_READMULTI 0x20 /* memory read multiple */
+
+#define PCI_CLKRUN_DSBL 0x8000 /* Bit 15 forceClkrun */
+
+/* PCI core index in SROM shadow area */
+#define SRSH_PI_OFFSET 0 /* first word */
+#define SRSH_PI_MASK 0xf000 /* bit 15:12 */
+#define SRSH_PI_SHIFT 12 /* bit 15:12 */
+
+/* Sonics side: PCI core and host control registers */
+struct sbpciregs {
+ u32 control; /* PCI control */
+ u32 PAD[3];
+ u32 arbcontrol; /* PCI arbiter control */
+ u32 clkrun; /* Clkrun Control (>=rev11) */
+ u32 PAD[2];
+ u32 intstatus; /* Interrupt status */
+ u32 intmask; /* Interrupt mask */
+ u32 sbtopcimailbox; /* Sonics to PCI mailbox */
+ u32 PAD[9];
+ u32 bcastaddr; /* Sonics broadcast address */
+ u32 bcastdata; /* Sonics broadcast data */
+ u32 PAD[2];
+ u32 gpioin; /* ro: gpio input (>=rev2) */
+ u32 gpioout; /* rw: gpio output (>=rev2) */
+ u32 gpioouten; /* rw: gpio output enable (>= rev2) */
+ u32 gpiocontrol; /* rw: gpio control (>= rev2) */
+ u32 PAD[36];
+ u32 sbtopci0; /* Sonics to PCI translation 0 */
+ u32 sbtopci1; /* Sonics to PCI translation 1 */
+ u32 sbtopci2; /* Sonics to PCI translation 2 */
+ u32 PAD[189];
+ u32 pcicfg[4][64]; /* 0x400 - 0x7FF, PCI Cfg Space (>=rev8) */
+ u16 sprom[36]; /* SPROM shadow Area */
+ u32 PAD[46];
+};
+
+/* SB side: PCIE core and host control registers */
+struct sbpcieregs {
+ u32 control; /* host mode only */
+ u32 PAD[2];
+ u32 biststatus; /* bist Status: 0x00C */
+ u32 gpiosel; /* PCIE gpio sel: 0x010 */
+ u32 gpioouten; /* PCIE gpio outen: 0x14 */
+ u32 PAD[2];
+ u32 intstatus; /* Interrupt status: 0x20 */
+ u32 intmask; /* Interrupt mask: 0x24 */
+ u32 sbtopcimailbox; /* sb to pcie mailbox: 0x028 */
+ u32 PAD[53];
+ u32 sbtopcie0; /* sb to pcie translation 0: 0x100 */
+ u32 sbtopcie1; /* sb to pcie translation 1: 0x104 */
+ u32 sbtopcie2; /* sb to pcie translation 2: 0x108 */
+ u32 PAD[5];
+
+ /* pcie core supports in direct access to config space */
+ u32 configaddr; /* pcie config space access: Address field: 0x120 */
+ u32 configdata; /* pcie config space access: Data field: 0x124 */
+
+ /* mdio access to serdes */
+ u32 mdiocontrol; /* controls the mdio access: 0x128 */
+ u32 mdiodata; /* Data to the mdio access: 0x12c */
+
+ /* pcie protocol phy/dllp/tlp register indirect access mechanism */
+ u32 pcieindaddr; /* indirect access to
+ * the internal register: 0x130
+ */
+ u32 pcieinddata; /* Data to/from the internal regsiter: 0x134 */
+
+ u32 clkreqenctrl; /* >= rev 6, Clkreq rdma control : 0x138 */
+ u32 PAD[177];
+ u32 pciecfg[4][64]; /* 0x400 - 0x7FF, PCIE Cfg Space */
+ u16 sprom[64]; /* SPROM shadow Area */
+};
+
+struct pcicore_info {
+ union {
+ struct sbpcieregs __iomem *pcieregs;
+ struct sbpciregs __iomem *pciregs;
+ } regs; /* Memory mapped register to the core */
+
+ struct si_pub *sih; /* System interconnect handle */
+ struct pci_dev *dev;
+ u8 pciecap_lcreg_offset;/* PCIE capability LCreg offset
+ * in the config space
+ */
+ bool pcie_pr42767;
+ u8 pcie_polarity;
+ u8 pcie_war_aspm_ovr; /* Override ASPM/Clkreq settings */
+
+ u8 pmecap_offset; /* PM Capability offset in the config space */
+ bool pmecap; /* Capable of generating PME */
+};
+
+#define PCIE_ASPM(sih) \
+ (((sih)->buscoretype == PCIE_CORE_ID) && \
+ (((sih)->buscorerev >= 3) && \
+ ((sih)->buscorerev <= 5)))
+
+
+/* delay needed between the mdio control/ mdiodata register data access */
+static void pr28829_delay(void)
+{
+ udelay(10);
+}
+
+/* Initialize the PCI core.
+ * It's caller's responsibility to make sure that this is done only once
+ */
+struct pcicore_info *pcicore_init(struct si_pub *sih, struct pci_dev *pdev,
+ void __iomem *regs)
+{
+ struct pcicore_info *pi;
+
+ /* alloc struct pcicore_info */
+ pi = kzalloc(sizeof(struct pcicore_info), GFP_ATOMIC);
+ if (pi == NULL)
+ return NULL;
+
+ pi->sih = sih;
+ pi->dev = pdev;
+
+ if (sih->buscoretype == PCIE_CORE_ID) {
+ u8 cap_ptr;
+ pi->regs.pcieregs = regs;
+ cap_ptr = pcicore_find_pci_capability(pi->dev, PCI_CAP_ID_EXP,
+ NULL, NULL);
+ pi->pciecap_lcreg_offset = cap_ptr + PCIE_CAP_LINKCTRL_OFFSET;
+ } else
+ pi->regs.pciregs = regs;
+
+ return pi;
+}
+
+void pcicore_deinit(struct pcicore_info *pch)
+{
+ kfree(pch);
+}
+
+/* return cap_offset if requested capability exists in the PCI config space */
+/* Note that it's caller's responsibility to make sure it's a pci bus */
+u8
+pcicore_find_pci_capability(struct pci_dev *dev, u8 req_cap_id,
+ unsigned char *buf, u32 *buflen)
+{
+ u8 cap_id;
+ u8 cap_ptr = 0;
+ u32 bufsize;
+ u8 byte_val;
+
+ /* check for Header type 0 */
+ pci_read_config_byte(dev, PCI_HEADER_TYPE, &byte_val);
+ if ((byte_val & 0x7f) != PCI_HEADER_TYPE_NORMAL)
+ goto end;
+
+ /* check if the capability pointer field exists */
+ pci_read_config_byte(dev, PCI_STATUS, &byte_val);
+ if (!(byte_val & PCI_STATUS_CAP_LIST))
+ goto end;
+
+ pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &cap_ptr);
+ /* check if the capability pointer is 0x00 */
+ if (cap_ptr == 0x00)
+ goto end;
+
+ /* loop thru the capability list
+ * and see if the pcie capability exists
+ */
+
+ pci_read_config_byte(dev, cap_ptr, &cap_id);
+
+ while (cap_id != req_cap_id) {
+ pci_read_config_byte(dev, cap_ptr + 1, &cap_ptr);
+ if (cap_ptr == 0x00)
+ break;
+ pci_read_config_byte(dev, cap_ptr, &cap_id);
+ }
+ if (cap_id != req_cap_id)
+ goto end;
+
+ /* found the caller requested capability */
+ if (buf != NULL && buflen != NULL) {
+ u8 cap_data;
+
+ bufsize = *buflen;
+ if (!bufsize)
+ goto end;
+ *buflen = 0;
+ /* copy the capability data excluding cap ID and next ptr */
+ cap_data = cap_ptr + 2;
+ if ((bufsize + cap_data) > PCI_SZPCR)
+ bufsize = PCI_SZPCR - cap_data;
+ *buflen = bufsize;
+ while (bufsize--) {
+ pci_read_config_byte(dev, cap_data, buf);
+ cap_data++;
+ buf++;
+ }
+ }
+end:
+ return cap_ptr;
+}
+
+/* ***** Register Access API */
+static uint
+pcie_readreg(struct sbpcieregs __iomem *pcieregs, uint addrtype, uint offset)
+{
+ uint retval = 0xFFFFFFFF;
+
+ switch (addrtype) {
+ case PCIE_CONFIGREGS:
+ W_REG(&pcieregs->configaddr, offset);
+ (void)R_REG((&pcieregs->configaddr));
+ retval = R_REG(&pcieregs->configdata);
+ break;
+ case PCIE_PCIEREGS:
+ W_REG(&pcieregs->pcieindaddr, offset);
+ (void)R_REG(&pcieregs->pcieindaddr);
+ retval = R_REG(&pcieregs->pcieinddata);
+ break;
+ }
+
+ return retval;
+}
+
+static uint pcie_writereg(struct sbpcieregs __iomem *pcieregs, uint addrtype,
+ uint offset, uint val)
+{
+ switch (addrtype) {
+ case PCIE_CONFIGREGS:
+ W_REG((&pcieregs->configaddr), offset);
+ W_REG((&pcieregs->configdata), val);
+ break;
+ case PCIE_PCIEREGS:
+ W_REG((&pcieregs->pcieindaddr), offset);
+ W_REG((&pcieregs->pcieinddata), val);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static bool pcie_mdiosetblock(struct pcicore_info *pi, uint blk)
+{
+ struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs;
+ uint mdiodata, i = 0;
+ uint pcie_serdes_spinwait = 200;
+
+ mdiodata = (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA |
+ (MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) |
+ (MDIODATA_BLK_ADDR << MDIODATA_REGADDR_SHF) |
+ (blk << 4));
+ W_REG(&pcieregs->mdiodata, mdiodata);
+
+ pr28829_delay();
+ /* retry till the transaction is complete */
+ while (i < pcie_serdes_spinwait) {
+ if (R_REG(&pcieregs->mdiocontrol) & MDIOCTL_ACCESS_DONE)
+ break;
+
+ udelay(1000);
+ i++;
+ }
+
+ if (i >= pcie_serdes_spinwait)
+ return false;
+
+ return true;
+}
+
+static int
+pcie_mdioop(struct pcicore_info *pi, uint physmedia, uint regaddr, bool write,
+ uint *val)
+{
+ struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs;
+ uint mdiodata;
+ uint i = 0;
+ uint pcie_serdes_spinwait = 10;
+
+ /* enable mdio access to SERDES */
+ W_REG(&pcieregs->mdiocontrol, MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL);
+
+ if (pi->sih->buscorerev >= 10) {
+ /* new serdes is slower in rw,
+ * using two layers of reg address mapping
+ */
+ if (!pcie_mdiosetblock(pi, physmedia))
+ return 1;
+ mdiodata = ((MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) |
+ (regaddr << MDIODATA_REGADDR_SHF));
+ pcie_serdes_spinwait *= 20;
+ } else {
+ mdiodata = ((physmedia << MDIODATA_DEVADDR_SHF_OLD) |
+ (regaddr << MDIODATA_REGADDR_SHF_OLD));
+ }
+
+ if (!write)
+ mdiodata |= (MDIODATA_START | MDIODATA_READ | MDIODATA_TA);
+ else
+ mdiodata |= (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA |
+ *val);
+
+ W_REG(&pcieregs->mdiodata, mdiodata);
+
+ pr28829_delay();
+
+ /* retry till the transaction is complete */
+ while (i < pcie_serdes_spinwait) {
+ if (R_REG(&pcieregs->mdiocontrol) & MDIOCTL_ACCESS_DONE) {
+ if (!write) {
+ pr28829_delay();
+ *val = (R_REG(&pcieregs->mdiodata) &
+ MDIODATA_MASK);
+ }
+ /* Disable mdio access to SERDES */
+ W_REG(&pcieregs->mdiocontrol, 0);
+ return 0;
+ }
+ udelay(1000);
+ i++;
+ }
+
+ /* Timed out. Disable mdio access to SERDES. */
+ W_REG(&pcieregs->mdiocontrol, 0);
+ return 1;
+}
+
+/* use the mdio interface to read from mdio slaves */
+static int
+pcie_mdioread(struct pcicore_info *pi, uint physmedia, uint regaddr,
+ uint *regval)
+{
+ return pcie_mdioop(pi, physmedia, regaddr, false, regval);
+}
+
+/* use the mdio interface to write to mdio slaves */
+static int
+pcie_mdiowrite(struct pcicore_info *pi, uint physmedia, uint regaddr, uint val)
+{
+ return pcie_mdioop(pi, physmedia, regaddr, true, &val);
+}
+
+/* ***** Support functions ***** */
+static u8 pcie_clkreq(struct pcicore_info *pi, u32 mask, u32 val)
+{
+ u32 reg_val;
+ u8 offset;
+
+ offset = pi->pciecap_lcreg_offset;
+ if (!offset)
+ return 0;
+
+ pci_read_config_dword(pi->dev, offset, &reg_val);
+ /* set operation */
+ if (mask) {
+ if (val)
+ reg_val |= PCIE_CLKREQ_ENAB;
+ else
+ reg_val &= ~PCIE_CLKREQ_ENAB;
+ pci_write_config_dword(pi->dev, offset, reg_val);
+ pci_read_config_dword(pi->dev, offset, &reg_val);
+ }
+ if (reg_val & PCIE_CLKREQ_ENAB)
+ return 1;
+ else
+ return 0;
+}
+
+static void pcie_extendL1timer(struct pcicore_info *pi, bool extend)
+{
+ u32 w;
+ struct si_pub *sih = pi->sih;
+ struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs;
+
+ if (sih->buscoretype != PCIE_CORE_ID || sih->buscorerev < 7)
+ return;
+
+ w = pcie_readreg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG);
+ if (extend)
+ w |= PCIE_ASPMTIMER_EXTEND;
+ else
+ w &= ~PCIE_ASPMTIMER_EXTEND;
+ pcie_writereg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG, w);
+ w = pcie_readreg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG);
+}
+
+/* centralized clkreq control policy */
+static void pcie_clkreq_upd(struct pcicore_info *pi, uint state)
+{
+ struct si_pub *sih = pi->sih;
+
+ switch (state) {
+ case SI_DOATTACH:
+ if (PCIE_ASPM(sih))
+ pcie_clkreq(pi, 1, 0);
+ break;
+ case SI_PCIDOWN:
+ if (sih->buscorerev == 6) { /* turn on serdes PLL down */
+ ai_corereg(sih, SI_CC_IDX,
+ offsetof(struct chipcregs, chipcontrol_addr),
+ ~0, 0);
+ ai_corereg(sih, SI_CC_IDX,
+ offsetof(struct chipcregs, chipcontrol_data),
+ ~0x40, 0);
+ } else if (pi->pcie_pr42767) {
+ pcie_clkreq(pi, 1, 1);
+ }
+ break;
+ case SI_PCIUP:
+ if (sih->buscorerev == 6) { /* turn off serdes PLL down */
+ ai_corereg(sih, SI_CC_IDX,
+ offsetof(struct chipcregs, chipcontrol_addr),
+ ~0, 0);
+ ai_corereg(sih, SI_CC_IDX,
+ offsetof(struct chipcregs, chipcontrol_data),
+ ~0x40, 0x40);
+ } else if (PCIE_ASPM(sih)) { /* disable clkreq */
+ pcie_clkreq(pi, 1, 0);
+ }
+ break;
+ }
+}
+
+/* ***** PCI core WARs ***** */
+/* Done only once at attach time */
+static void pcie_war_polarity(struct pcicore_info *pi)
+{
+ u32 w;
+
+ if (pi->pcie_polarity != 0)
+ return;
+
+ w = pcie_readreg(pi->regs.pcieregs, PCIE_PCIEREGS, PCIE_PLP_STATUSREG);
+
+ /* Detect the current polarity at attach and force that polarity and
+ * disable changing the polarity
+ */
+ if ((w & PCIE_PLP_POLARITYINV_STAT) == 0)
+ pi->pcie_polarity = SERDES_RX_CTRL_FORCE;
+ else
+ pi->pcie_polarity = (SERDES_RX_CTRL_FORCE |
+ SERDES_RX_CTRL_POLARITY);
+}
+
+/* enable ASPM and CLKREQ if srom doesn't have it */
+/* Needs to happen when update to shadow SROM is needed
+ * : Coming out of 'standby'/'hibernate'
+ * : If pcie_war_aspm_ovr state changed
+ */
+static void pcie_war_aspm_clkreq(struct pcicore_info *pi)
+{
+ struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs;
+ struct si_pub *sih = pi->sih;
+ u16 val16;
+ u16 __iomem *reg16;
+ u32 w;
+
+ if (!PCIE_ASPM(sih))
+ return;
+
+ /* bypass this on QT or VSIM */
+ reg16 = &pcieregs->sprom[SRSH_ASPM_OFFSET];
+ val16 = R_REG(reg16);
+
+ val16 &= ~SRSH_ASPM_ENB;
+ if (pi->pcie_war_aspm_ovr == PCIE_ASPM_ENAB)
+ val16 |= SRSH_ASPM_ENB;
+ else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L1_ENAB)
+ val16 |= SRSH_ASPM_L1_ENB;
+ else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L0s_ENAB)
+ val16 |= SRSH_ASPM_L0s_ENB;
+
+ W_REG(reg16, val16);
+
+ pci_read_config_dword(pi->dev, pi->pciecap_lcreg_offset, &w);
+ w &= ~PCIE_ASPM_ENAB;
+ w |= pi->pcie_war_aspm_ovr;
+ pci_write_config_dword(pi->dev, pi->pciecap_lcreg_offset, w);
+
+ reg16 = &pcieregs->sprom[SRSH_CLKREQ_OFFSET_REV5];
+ val16 = R_REG(reg16);
+
+ if (pi->pcie_war_aspm_ovr != PCIE_ASPM_DISAB) {
+ val16 |= SRSH_CLKREQ_ENB;
+ pi->pcie_pr42767 = true;
+ } else
+ val16 &= ~SRSH_CLKREQ_ENB;
+
+ W_REG(reg16, val16);
+}
+
+/* Apply the polarity determined at the start */
+/* Needs to happen when coming out of 'standby'/'hibernate' */
+static void pcie_war_serdes(struct pcicore_info *pi)
+{
+ u32 w = 0;
+
+ if (pi->pcie_polarity != 0)
+ pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CTRL,
+ pi->pcie_polarity);
+
+ pcie_mdioread(pi, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, &w);
+ if (w & PLL_CTRL_FREQDET_EN) {
+ w &= ~PLL_CTRL_FREQDET_EN;
+ pcie_mdiowrite(pi, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, w);
+ }
+}
+
+/* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */
+/* Needs to happen when coming out of 'standby'/'hibernate' */
+static void pcie_misc_config_fixup(struct pcicore_info *pi)
+{
+ struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs;
+ u16 val16;
+ u16 __iomem *reg16;
+
+ reg16 = &pcieregs->sprom[SRSH_PCIE_MISC_CONFIG];
+ val16 = R_REG(reg16);
+
+ if ((val16 & SRSH_L23READY_EXIT_NOPERST) == 0) {
+ val16 |= SRSH_L23READY_EXIT_NOPERST;
+ W_REG(reg16, val16);
+ }
+}
+
+/* quick hack for testing */
+/* Needs to happen when coming out of 'standby'/'hibernate' */
+static void pcie_war_noplldown(struct pcicore_info *pi)
+{
+ struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs;
+ u16 __iomem *reg16;
+
+ /* turn off serdes PLL down */
+ ai_corereg(pi->sih, SI_CC_IDX, offsetof(struct chipcregs, chipcontrol),
+ CHIPCTRL_4321_PLL_DOWN, CHIPCTRL_4321_PLL_DOWN);
+
+ /* clear srom shadow backdoor */
+ reg16 = &pcieregs->sprom[SRSH_BD_OFFSET];
+ W_REG(reg16, 0);
+}
+
+/* Needs to happen when coming out of 'standby'/'hibernate' */
+static void pcie_war_pci_setup(struct pcicore_info *pi)
+{
+ struct si_pub *sih = pi->sih;
+ struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs;
+ u32 w;
+
+ if (sih->buscorerev == 0 || sih->buscorerev == 1) {
+ w = pcie_readreg(pcieregs, PCIE_PCIEREGS,
+ PCIE_TLP_WORKAROUNDSREG);
+ w |= 0x8;
+ pcie_writereg(pcieregs, PCIE_PCIEREGS,
+ PCIE_TLP_WORKAROUNDSREG, w);
+ }
+
+ if (sih->buscorerev == 1) {
+ w = pcie_readreg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_LCREG);
+ w |= 0x40;
+ pcie_writereg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_LCREG, w);
+ }
+
+ if (sih->buscorerev == 0) {
+ pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_TIMER1, 0x8128);
+ pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDR, 0x0100);
+ pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDRBW, 0x1466);
+ } else if (PCIE_ASPM(sih)) {
+ /* Change the L1 threshold for better performance */
+ w = pcie_readreg(pcieregs, PCIE_PCIEREGS,
+ PCIE_DLLP_PMTHRESHREG);
+ w &= ~PCIE_L1THRESHOLDTIME_MASK;
+ w |= PCIE_L1THRESHOLD_WARVAL << PCIE_L1THRESHOLDTIME_SHIFT;
+ pcie_writereg(pcieregs, PCIE_PCIEREGS,
+ PCIE_DLLP_PMTHRESHREG, w);
+
+ pcie_war_serdes(pi);
+
+ pcie_war_aspm_clkreq(pi);
+ } else if (pi->sih->buscorerev == 7)
+ pcie_war_noplldown(pi);
+
+ /* Note that the fix is actually in the SROM,
+ * that's why this is open-ended
+ */
+ if (pi->sih->buscorerev >= 6)
+ pcie_misc_config_fixup(pi);
+}
+
+/* ***** Functions called during driver state changes ***** */
+void pcicore_attach(struct pcicore_info *pi, int state)
+{
+ struct si_pub *sih = pi->sih;
+ u32 bfl2 = (u32)getintvar(sih, BRCMS_SROM_BOARDFLAGS2);
+
+ /* Determine if this board needs override */
+ if (PCIE_ASPM(sih)) {
+ if (bfl2 & BFL2_PCIEWAR_OVR)
+ pi->pcie_war_aspm_ovr = PCIE_ASPM_DISAB;
+ else
+ pi->pcie_war_aspm_ovr = PCIE_ASPM_ENAB;
+ }
+
+ /* These need to happen in this order only */
+ pcie_war_polarity(pi);
+
+ pcie_war_serdes(pi);
+
+ pcie_war_aspm_clkreq(pi);
+
+ pcie_clkreq_upd(pi, state);
+
+}
+
+void pcicore_hwup(struct pcicore_info *pi)
+{
+ if (!pi || pi->sih->buscoretype != PCIE_CORE_ID)
+ return;
+
+ pcie_war_pci_setup(pi);
+}
+
+void pcicore_up(struct pcicore_info *pi, int state)
+{
+ if (!pi || pi->sih->buscoretype != PCIE_CORE_ID)
+ return;
+
+ /* Restore L1 timer for better performance */
+ pcie_extendL1timer(pi, true);
+
+ pcie_clkreq_upd(pi, state);
+}
+
+/* When the device is going to enter D3 state
+ * (or the system is going to enter S3/S4 states)
+ */
+void pcicore_sleep(struct pcicore_info *pi)
+{
+ u32 w;
+
+ if (!pi || !PCIE_ASPM(pi->sih))
+ return;
+
+ pci_read_config_dword(pi->dev, pi->pciecap_lcreg_offset, &w);
+ w &= ~PCIE_CAP_LCREG_ASPML1;
+ pci_write_config_dword(pi->dev, pi->pciecap_lcreg_offset, w);
+
+ pi->pcie_pr42767 = false;
+}
+
+void pcicore_down(struct pcicore_info *pi, int state)
+{
+ if (!pi || pi->sih->buscoretype != PCIE_CORE_ID)
+ return;
+
+ pcie_clkreq_upd(pi, state);
+
+ /* Reduce L1 timer for better power savings */
+ pcie_extendL1timer(pi, false);
+}
+
+/* precondition: current core is sii->buscoretype */
+static void pcicore_fixcfg(struct pcicore_info *pi, u16 __iomem *reg16)
+{
+ struct si_info *sii = (struct si_info *)(pi->sih);
+ u16 val16;
+ uint pciidx;
+
+ pciidx = ai_coreidx(&sii->pub);
+ val16 = R_REG(reg16);
+ if (((val16 & SRSH_PI_MASK) >> SRSH_PI_SHIFT) != (u16)pciidx) {
+ val16 = (u16)(pciidx << SRSH_PI_SHIFT) |
+ (val16 & ~SRSH_PI_MASK);
+ W_REG(reg16, val16);
+ }
+}
+
+void
+pcicore_fixcfg_pci(struct pcicore_info *pi, struct sbpciregs __iomem *pciregs)
+{
+ pcicore_fixcfg(pi, &pciregs->sprom[SRSH_PI_OFFSET]);
+}
+
+void pcicore_fixcfg_pcie(struct pcicore_info *pi,
+ struct sbpcieregs __iomem *pcieregs)
+{
+ pcicore_fixcfg(pi, &pcieregs->sprom[SRSH_PI_OFFSET]);
+}
+
+/* precondition: current core is pci core */
+void
+pcicore_pci_setup(struct pcicore_info *pi, struct sbpciregs __iomem *pciregs)
+{
+ u32 w;
+
+ OR_REG(&pciregs->sbtopci2, SBTOPCI_PREF | SBTOPCI_BURST);
+
+ if (((struct si_info *)(pi->sih))->pub.buscorerev >= 11) {
+ OR_REG(&pciregs->sbtopci2, SBTOPCI_RC_READMULTI);
+ w = R_REG(&pciregs->clkrun);
+ W_REG(&pciregs->clkrun, w | PCI_CLKRUN_DSBL);
+ w = R_REG(&pciregs->clkrun);
+ }
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/nicpci.h b/drivers/net/wireless/brcm80211/brcmsmac/nicpci.h
new file mode 100644
index 000000000000..58aa80dc3329
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/nicpci.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_NICPCI_H_
+#define _BRCM_NICPCI_H_
+
+#include "types.h"
+
+/* PCI configuration address space size */
+#define PCI_SZPCR 256
+
+/* Brcm PCI configuration registers */
+/* backplane address space accessed by BAR0 */
+#define PCI_BAR0_WIN 0x80
+/* sprom property control */
+#define PCI_SPROM_CONTROL 0x88
+/* mask of PCI and other cores interrupts */
+#define PCI_INT_MASK 0x94
+/* backplane core interrupt mask bits offset */
+#define PCI_SBIM_SHIFT 8
+/* backplane address space accessed by second 4KB of BAR0 */
+#define PCI_BAR0_WIN2 0xac
+/* pci config space gpio input (>=rev3) */
+#define PCI_GPIO_IN 0xb0
+/* pci config space gpio output (>=rev3) */
+#define PCI_GPIO_OUT 0xb4
+/* pci config space gpio output enable (>=rev3) */
+#define PCI_GPIO_OUTEN 0xb8
+
+/* bar0 + 4K accesses external sprom */
+#define PCI_BAR0_SPROM_OFFSET (4 * 1024)
+/* bar0 + 6K accesses pci core registers */
+#define PCI_BAR0_PCIREGS_OFFSET (6 * 1024)
+/*
+ * pci core SB registers are at the end of the
+ * 8KB window, so their address is the "regular"
+ * address plus 4K
+ */
+#define PCI_BAR0_PCISBR_OFFSET (4 * 1024)
+/* bar0 window size Match with corerev 13 */
+#define PCI_BAR0_WINSZ (16 * 1024)
+/* On pci corerev >= 13 and all pcie, the bar0 is now 16KB and it maps: */
+/* bar0 + 8K accesses pci/pcie core registers */
+#define PCI_16KB0_PCIREGS_OFFSET (8 * 1024)
+/* bar0 + 12K accesses chipc core registers */
+#define PCI_16KB0_CCREGS_OFFSET (12 * 1024)
+
+struct sbpciregs;
+struct sbpcieregs;
+
+extern struct pcicore_info *pcicore_init(struct si_pub *sih,
+ struct pci_dev *pdev,
+ void __iomem *regs);
+extern void pcicore_deinit(struct pcicore_info *pch);
+extern void pcicore_attach(struct pcicore_info *pch, int state);
+extern void pcicore_hwup(struct pcicore_info *pch);
+extern void pcicore_up(struct pcicore_info *pch, int state);
+extern void pcicore_sleep(struct pcicore_info *pch);
+extern void pcicore_down(struct pcicore_info *pch, int state);
+extern u8 pcicore_find_pci_capability(struct pci_dev *dev, u8 req_cap_id,
+ unsigned char *buf, u32 *buflen);
+extern void pcicore_fixcfg_pci(struct pcicore_info *pch,
+ struct sbpciregs __iomem *pciregs);
+extern void pcicore_fixcfg_pcie(struct pcicore_info *pch,
+ struct sbpcieregs __iomem *pciregs);
+extern void pcicore_pci_setup(struct pcicore_info *pch,
+ struct sbpciregs __iomem *pciregs);
+
+#endif /* _BRCM_NICPCI_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/otp.c b/drivers/net/wireless/brcm80211/brcmsmac/otp.c
new file mode 100644
index 000000000000..edf551561fd8
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/otp.c
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2010 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/io.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+
+#include <brcm_hw_ids.h>
+#include <chipcommon.h>
+#include "aiutils.h"
+#include "otp.h"
+
+#define OTPS_GUP_MASK 0x00000f00
+#define OTPS_GUP_SHIFT 8
+/* h/w subregion is programmed */
+#define OTPS_GUP_HW 0x00000100
+/* s/w subregion is programmed */
+#define OTPS_GUP_SW 0x00000200
+/* chipid/pkgopt subregion is programmed */
+#define OTPS_GUP_CI 0x00000400
+/* fuse subregion is programmed */
+#define OTPS_GUP_FUSE 0x00000800
+
+/* Fields in otpprog in rev >= 21 */
+#define OTPP_COL_MASK 0x000000ff
+#define OTPP_COL_SHIFT 0
+#define OTPP_ROW_MASK 0x0000ff00
+#define OTPP_ROW_SHIFT 8
+#define OTPP_OC_MASK 0x0f000000
+#define OTPP_OC_SHIFT 24
+#define OTPP_READERR 0x10000000
+#define OTPP_VALUE_MASK 0x20000000
+#define OTPP_VALUE_SHIFT 29
+#define OTPP_START_BUSY 0x80000000
+#define OTPP_READ 0x40000000
+
+/* Opcodes for OTPP_OC field */
+#define OTPPOC_READ 0
+#define OTPPOC_BIT_PROG 1
+#define OTPPOC_VERIFY 3
+#define OTPPOC_INIT 4
+#define OTPPOC_SET 5
+#define OTPPOC_RESET 6
+#define OTPPOC_OCST 7
+#define OTPPOC_ROW_LOCK 8
+#define OTPPOC_PRESCN_TEST 9
+
+#define OTPTYPE_IPX(ccrev) ((ccrev) == 21 || (ccrev) >= 23)
+
+#define OTPP_TRIES 10000000 /* # of tries for OTPP */
+
+#define MAXNUMRDES 9 /* Maximum OTP redundancy entries */
+
+/* Fixed size subregions sizes in words */
+#define OTPGU_CI_SZ 2
+
+struct otpinfo;
+
+/* OTP function struct */
+struct otp_fn_s {
+ int (*init)(struct si_pub *sih, struct otpinfo *oi);
+ int (*read_region)(struct otpinfo *oi, int region, u16 *data,
+ uint *wlen);
+};
+
+struct otpinfo {
+ uint ccrev; /* chipc revision */
+ const struct otp_fn_s *fn; /* OTP functions */
+ struct si_pub *sih; /* Saved sb handle */
+
+ /* IPX OTP section */
+ u16 wsize; /* Size of otp in words */
+ u16 rows; /* Geometry */
+ u16 cols; /* Geometry */
+ u32 status; /* Flag bits (lock/prog/rv).
+ * (Reflected only when OTP is power cycled)
+ */
+ u16 hwbase; /* hardware subregion offset */
+ u16 hwlim; /* hardware subregion boundary */
+ u16 swbase; /* software subregion offset */
+ u16 swlim; /* software subregion boundary */
+ u16 fbase; /* fuse subregion offset */
+ u16 flim; /* fuse subregion boundary */
+ int otpgu_base; /* offset to General Use Region */
+};
+
+/* OTP layout */
+/* CC revs 21, 24 and 27 OTP General Use Region word offset */
+#define REVA4_OTPGU_BASE 12
+
+/* CC revs 23, 25, 26, 28 and above OTP General Use Region word offset */
+#define REVB8_OTPGU_BASE 20
+
+/* CC rev 36 OTP General Use Region word offset */
+#define REV36_OTPGU_BASE 12
+
+/* Subregion word offsets in General Use region */
+#define OTPGU_HSB_OFF 0
+#define OTPGU_SFB_OFF 1
+#define OTPGU_CI_OFF 2
+#define OTPGU_P_OFF 3
+#define OTPGU_SROM_OFF 4
+
+/* Flag bit offsets in General Use region */
+#define OTPGU_HWP_OFF 60
+#define OTPGU_SWP_OFF 61
+#define OTPGU_CIP_OFF 62
+#define OTPGU_FUSEP_OFF 63
+#define OTPGU_CIP_MSK 0x4000
+#define OTPGU_P_MSK 0xf000
+#define OTPGU_P_SHIFT (OTPGU_HWP_OFF % 16)
+
+/* OTP Size */
+#define OTP_SZ_FU_324 ((roundup(324, 8))/8) /* 324 bits */
+#define OTP_SZ_FU_288 (288/8) /* 288 bits */
+#define OTP_SZ_FU_216 (216/8) /* 216 bits */
+#define OTP_SZ_FU_72 (72/8) /* 72 bits */
+#define OTP_SZ_CHECKSUM (16/8) /* 16 bits */
+#define OTP4315_SWREG_SZ 178 /* 178 bytes */
+#define OTP_SZ_FU_144 (144/8) /* 144 bits */
+
+static u16
+ipxotp_otpr(struct otpinfo *oi, struct chipcregs __iomem *cc, uint wn)
+{
+ return R_REG(&cc->sromotp[wn]);
+}
+
+/*
+ * Calculate max HW/SW region byte size by subtracting fuse region
+ * and checksum size, osizew is oi->wsize (OTP size - GU size) in words
+ */
+static int ipxotp_max_rgnsz(struct si_pub *sih, int osizew)
+{
+ int ret = 0;
+
+ switch (sih->chip) {
+ case BCM43224_CHIP_ID:
+ case BCM43225_CHIP_ID:
+ ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM;
+ break;
+ case BCM4313_CHIP_ID:
+ ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM;
+ break;
+ default:
+ break; /* Don't know about this chip */
+ }
+
+ return ret;
+}
+
+static void _ipxotp_init(struct otpinfo *oi, struct chipcregs __iomem *cc)
+{
+ uint k;
+ u32 otpp, st;
+
+ /*
+ * record word offset of General Use Region
+ * for various chipcommon revs
+ */
+ if (oi->sih->ccrev == 21 || oi->sih->ccrev == 24
+ || oi->sih->ccrev == 27) {
+ oi->otpgu_base = REVA4_OTPGU_BASE;
+ } else if (oi->sih->ccrev == 36) {
+ /*
+ * OTP size greater than equal to 2KB (128 words),
+ * otpgu_base is similar to rev23
+ */
+ if (oi->wsize >= 128)
+ oi->otpgu_base = REVB8_OTPGU_BASE;
+ else
+ oi->otpgu_base = REV36_OTPGU_BASE;
+ } else if (oi->sih->ccrev == 23 || oi->sih->ccrev >= 25) {
+ oi->otpgu_base = REVB8_OTPGU_BASE;
+ }
+
+ /* First issue an init command so the status is up to date */
+ otpp =
+ OTPP_START_BUSY | ((OTPPOC_INIT << OTPP_OC_SHIFT) & OTPP_OC_MASK);
+
+ W_REG(&cc->otpprog, otpp);
+ for (k = 0;
+ ((st = R_REG(&cc->otpprog)) & OTPP_START_BUSY)
+ && (k < OTPP_TRIES); k++)
+ ;
+ if (k >= OTPP_TRIES)
+ return;
+
+ /* Read OTP lock bits and subregion programmed indication bits */
+ oi->status = R_REG(&cc->otpstatus);
+
+ if ((oi->sih->chip == BCM43224_CHIP_ID)
+ || (oi->sih->chip == BCM43225_CHIP_ID)) {
+ u32 p_bits;
+ p_bits =
+ (ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_P_OFF) &
+ OTPGU_P_MSK)
+ >> OTPGU_P_SHIFT;
+ oi->status |= (p_bits << OTPS_GUP_SHIFT);
+ }
+
+ /*
+ * h/w region base and fuse region limit are fixed to
+ * the top and the bottom of the general use region.
+ * Everything else can be flexible.
+ */
+ oi->hwbase = oi->otpgu_base + OTPGU_SROM_OFF;
+ oi->hwlim = oi->wsize;
+ if (oi->status & OTPS_GUP_HW) {
+ oi->hwlim =
+ ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_HSB_OFF) / 16;
+ oi->swbase = oi->hwlim;
+ } else
+ oi->swbase = oi->hwbase;
+
+ /* subtract fuse and checksum from beginning */
+ oi->swlim = ipxotp_max_rgnsz(oi->sih, oi->wsize) / 2;
+
+ if (oi->status & OTPS_GUP_SW) {
+ oi->swlim =
+ ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_SFB_OFF) / 16;
+ oi->fbase = oi->swlim;
+ } else
+ oi->fbase = oi->swbase;
+
+ oi->flim = oi->wsize;
+}
+
+static int ipxotp_init(struct si_pub *sih, struct otpinfo *oi)
+{
+ uint idx;
+ struct chipcregs __iomem *cc;
+
+ /* Make sure we're running IPX OTP */
+ if (!OTPTYPE_IPX(sih->ccrev))
+ return -EBADE;
+
+ /* Make sure OTP is not disabled */
+ if (ai_is_otp_disabled(sih))
+ return -EBADE;
+
+ /* Check for otp size */
+ switch ((sih->cccaps & CC_CAP_OTPSIZE) >> CC_CAP_OTPSIZE_SHIFT) {
+ case 0:
+ /* Nothing there */
+ return -EBADE;
+ case 1: /* 32x64 */
+ oi->rows = 32;
+ oi->cols = 64;
+ oi->wsize = 128;
+ break;
+ case 2: /* 64x64 */
+ oi->rows = 64;
+ oi->cols = 64;
+ oi->wsize = 256;
+ break;
+ case 5: /* 96x64 */
+ oi->rows = 96;
+ oi->cols = 64;
+ oi->wsize = 384;
+ break;
+ case 7: /* 16x64 *//* 1024 bits */
+ oi->rows = 16;
+ oi->cols = 64;
+ oi->wsize = 64;
+ break;
+ default:
+ /* Don't know the geometry */
+ return -EBADE;
+ }
+
+ /* Retrieve OTP region info */
+ idx = ai_coreidx(sih);
+ cc = ai_setcoreidx(sih, SI_CC_IDX);
+
+ _ipxotp_init(oi, cc);
+
+ ai_setcoreidx(sih, idx);
+
+ return 0;
+}
+
+static int
+ipxotp_read_region(struct otpinfo *oi, int region, u16 *data, uint *wlen)
+{
+ uint idx;
+ struct chipcregs __iomem *cc;
+ uint base, i, sz;
+
+ /* Validate region selection */
+ switch (region) {
+ case OTP_HW_RGN:
+ sz = (uint) oi->hwlim - oi->hwbase;
+ if (!(oi->status & OTPS_GUP_HW)) {
+ *wlen = sz;
+ return -ENODATA;
+ }
+ if (*wlen < sz) {
+ *wlen = sz;
+ return -EOVERFLOW;
+ }
+ base = oi->hwbase;
+ break;
+ case OTP_SW_RGN:
+ sz = ((uint) oi->swlim - oi->swbase);
+ if (!(oi->status & OTPS_GUP_SW)) {
+ *wlen = sz;
+ return -ENODATA;
+ }
+ if (*wlen < sz) {
+ *wlen = sz;
+ return -EOVERFLOW;
+ }
+ base = oi->swbase;
+ break;
+ case OTP_CI_RGN:
+ sz = OTPGU_CI_SZ;
+ if (!(oi->status & OTPS_GUP_CI)) {
+ *wlen = sz;
+ return -ENODATA;
+ }
+ if (*wlen < sz) {
+ *wlen = sz;
+ return -EOVERFLOW;
+ }
+ base = oi->otpgu_base + OTPGU_CI_OFF;
+ break;
+ case OTP_FUSE_RGN:
+ sz = (uint) oi->flim - oi->fbase;
+ if (!(oi->status & OTPS_GUP_FUSE)) {
+ *wlen = sz;
+ return -ENODATA;
+ }
+ if (*wlen < sz) {
+ *wlen = sz;
+ return -EOVERFLOW;
+ }
+ base = oi->fbase;
+ break;
+ case OTP_ALL_RGN:
+ sz = ((uint) oi->flim - oi->hwbase);
+ if (!(oi->status & (OTPS_GUP_HW | OTPS_GUP_SW))) {
+ *wlen = sz;
+ return -ENODATA;
+ }
+ if (*wlen < sz) {
+ *wlen = sz;
+ return -EOVERFLOW;
+ }
+ base = oi->hwbase;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ idx = ai_coreidx(oi->sih);
+ cc = ai_setcoreidx(oi->sih, SI_CC_IDX);
+
+ /* Read the data */
+ for (i = 0; i < sz; i++)
+ data[i] = ipxotp_otpr(oi, cc, base + i);
+
+ ai_setcoreidx(oi->sih, idx);
+ *wlen = sz;
+ return 0;
+}
+
+static const struct otp_fn_s ipxotp_fn = {
+ (int (*)(struct si_pub *, struct otpinfo *)) ipxotp_init,
+ (int (*)(struct otpinfo *, int, u16 *, uint *)) ipxotp_read_region,
+};
+
+static int otp_init(struct si_pub *sih, struct otpinfo *oi)
+{
+
+ int ret;
+
+ memset(oi, 0, sizeof(struct otpinfo));
+
+ oi->ccrev = sih->ccrev;
+
+ if (OTPTYPE_IPX(oi->ccrev))
+ oi->fn = &ipxotp_fn;
+
+ if (oi->fn == NULL)
+ return -EBADE;
+
+ oi->sih = sih;
+
+ ret = (oi->fn->init) (sih, oi);
+
+ return ret;
+}
+
+int
+otp_read_region(struct si_pub *sih, int region, u16 *data, uint *wlen) {
+ struct otpinfo otpinfo;
+ struct otpinfo *oi = &otpinfo;
+ int err = 0;
+
+ if (ai_is_otp_disabled(sih)) {
+ err = -EPERM;
+ goto out;
+ }
+
+ err = otp_init(sih, oi);
+ if (err)
+ goto out;
+
+ err = ((oi)->fn->read_region)(oi, region, data, wlen);
+
+ out:
+ return err;
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/otp.h b/drivers/net/wireless/brcm80211/brcmsmac/otp.h
new file mode 100644
index 000000000000..6b6d31cf9569
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/otp.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_OTP_H_
+#define _BRCM_OTP_H_
+
+#include "types.h"
+
+/* OTP regions */
+#define OTP_HW_RGN 1
+#define OTP_SW_RGN 2
+#define OTP_CI_RGN 4
+#define OTP_FUSE_RGN 8
+/* From h/w region to end of OTP including checksum */
+#define OTP_ALL_RGN 0xf
+
+/* OTP Size */
+#define OTP_SZ_MAX (6144/8) /* maximum bytes in one CIS */
+
+extern int otp_read_region(struct si_pub *sih, int region, u16 *data,
+ uint *wlen);
+
+#endif /* _BRCM_OTP_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c
new file mode 100644
index 000000000000..a3149254cbcd
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c
@@ -0,0 +1,2988 @@
+/*
+ * Copyright (c) 2010 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/kernel.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+
+#include <brcm_hw_ids.h>
+#include <chipcommon.h>
+#include <aiutils.h>
+#include <d11.h>
+#include <phy_shim.h>
+#include "phy_hal.h"
+#include "phy_int.h"
+#include "phy_radio.h"
+#include "phy_lcn.h"
+#include "phyreg_n.h"
+
+#define VALID_N_RADIO(radioid) ((radioid == BCM2055_ID) || \
+ (radioid == BCM2056_ID) || \
+ (radioid == BCM2057_ID))
+
+#define VALID_LCN_RADIO(radioid) (radioid == BCM2064_ID)
+
+#define VALID_RADIO(pi, radioid) ( \
+ (ISNPHY(pi) ? VALID_N_RADIO(radioid) : false) || \
+ (ISLCNPHY(pi) ? VALID_LCN_RADIO(radioid) : false))
+
+/* basic mux operation - can be optimized on several architectures */
+#define MUX(pred, true, false) ((pred) ? (true) : (false))
+
+/* modulo inc/dec - assumes x E [0, bound - 1] */
+#define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1)
+
+/* modulo inc/dec, bound = 2^k */
+#define MODDEC_POW2(x, bound) (((x) - 1) & ((bound) - 1))
+#define MODINC_POW2(x, bound) (((x) + 1) & ((bound) - 1))
+
+struct chan_info_basic {
+ u16 chan;
+ u16 freq;
+};
+
+static const struct chan_info_basic chan_info_all[] = {
+ {1, 2412},
+ {2, 2417},
+ {3, 2422},
+ {4, 2427},
+ {5, 2432},
+ {6, 2437},
+ {7, 2442},
+ {8, 2447},
+ {9, 2452},
+ {10, 2457},
+ {11, 2462},
+ {12, 2467},
+ {13, 2472},
+ {14, 2484},
+
+ {34, 5170},
+ {38, 5190},
+ {42, 5210},
+ {46, 5230},
+
+ {36, 5180},
+ {40, 5200},
+ {44, 5220},
+ {48, 5240},
+ {52, 5260},
+ {56, 5280},
+ {60, 5300},
+ {64, 5320},
+
+ {100, 5500},
+ {104, 5520},
+ {108, 5540},
+ {112, 5560},
+ {116, 5580},
+ {120, 5600},
+ {124, 5620},
+ {128, 5640},
+ {132, 5660},
+ {136, 5680},
+ {140, 5700},
+
+ {149, 5745},
+ {153, 5765},
+ {157, 5785},
+ {161, 5805},
+ {165, 5825},
+
+ {184, 4920},
+ {188, 4940},
+ {192, 4960},
+ {196, 4980},
+ {200, 5000},
+ {204, 5020},
+ {208, 5040},
+ {212, 5060},
+ {216, 50800}
+};
+
+const u8 ofdm_rate_lookup[] = {
+
+ BRCM_RATE_48M,
+ BRCM_RATE_24M,
+ BRCM_RATE_12M,
+ BRCM_RATE_6M,
+ BRCM_RATE_54M,
+ BRCM_RATE_36M,
+ BRCM_RATE_18M,
+ BRCM_RATE_9M
+};
+
+#define PHY_WREG_LIMIT 24
+
+void wlc_phyreg_enter(struct brcms_phy_pub *pih)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+ wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim);
+}
+
+void wlc_phyreg_exit(struct brcms_phy_pub *pih)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+ wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim);
+}
+
+void wlc_radioreg_enter(struct brcms_phy_pub *pih)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+ wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO);
+
+ udelay(10);
+}
+
+void wlc_radioreg_exit(struct brcms_phy_pub *pih)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+ u16 dummy;
+
+ dummy = R_REG(&pi->regs->phyversion);
+ pi->phy_wreg = 0;
+ wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, 0);
+}
+
+u16 read_radio_reg(struct brcms_phy *pi, u16 addr)
+{
+ u16 data;
+
+ if ((addr == RADIO_IDCODE))
+ return 0xffff;
+
+ switch (pi->pubpi.phy_type) {
+ case PHY_TYPE_N:
+ if (!CONF_HAS(PHYTYPE, PHY_TYPE_N))
+ break;
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ addr |= RADIO_2057_READ_OFF;
+ else
+ addr |= RADIO_2055_READ_OFF;
+ break;
+
+ case PHY_TYPE_LCN:
+ if (!CONF_HAS(PHYTYPE, PHY_TYPE_LCN))
+ break;
+ addr |= RADIO_2064_READ_OFF;
+ break;
+
+ default:
+ break;
+ }
+
+ if ((D11REV_GE(pi->sh->corerev, 24)) ||
+ (D11REV_IS(pi->sh->corerev, 22)
+ && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
+ W_REG_FLUSH(&pi->regs->radioregaddr, addr);
+ data = R_REG(&pi->regs->radioregdata);
+ } else {
+ W_REG_FLUSH(&pi->regs->phy4waddr, addr);
+
+#ifdef __ARM_ARCH_4T__
+ __asm__(" .align 4 ");
+ __asm__(" nop ");
+ data = R_REG(&pi->regs->phy4wdatalo);
+#else
+ data = R_REG(&pi->regs->phy4wdatalo);
+#endif
+
+ }
+ pi->phy_wreg = 0;
+
+ return data;
+}
+
+void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)
+{
+ if ((D11REV_GE(pi->sh->corerev, 24)) ||
+ (D11REV_IS(pi->sh->corerev, 22)
+ && (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
+
+ W_REG_FLUSH(&pi->regs->radioregaddr, addr);
+ W_REG(&pi->regs->radioregdata, val);
+ } else {
+ W_REG_FLUSH(&pi->regs->phy4waddr, addr);
+ W_REG(&pi->regs->phy4wdatalo, val);
+ }
+
+ if (++pi->phy_wreg >= pi->phy_wreg_limit) {
+ (void)R_REG(&pi->regs->maccontrol);
+ pi->phy_wreg = 0;
+ }
+}
+
+static u32 read_radio_id(struct brcms_phy *pi)
+{
+ u32 id;
+
+ if (D11REV_GE(pi->sh->corerev, 24)) {
+ u32 b0, b1, b2;
+
+ W_REG_FLUSH(&pi->regs->radioregaddr, 0);
+ b0 = (u32) R_REG(&pi->regs->radioregdata);
+ W_REG_FLUSH(&pi->regs->radioregaddr, 1);
+ b1 = (u32) R_REG(&pi->regs->radioregdata);
+ W_REG_FLUSH(&pi->regs->radioregaddr, 2);
+ b2 = (u32) R_REG(&pi->regs->radioregdata);
+
+ id = ((b0 & 0xf) << 28) | (((b2 << 8) | b1) << 12) | ((b0 >> 4)
+ & 0xf);
+ } else {
+ W_REG_FLUSH(&pi->regs->phy4waddr, RADIO_IDCODE);
+ id = (u32) R_REG(&pi->regs->phy4wdatalo);
+ id |= (u32) R_REG(&pi->regs->phy4wdatahi) << 16;
+ }
+ pi->phy_wreg = 0;
+ return id;
+}
+
+void and_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)
+{
+ u16 rval;
+
+ rval = read_radio_reg(pi, addr);
+ write_radio_reg(pi, addr, (rval & val));
+}
+
+void or_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)
+{
+ u16 rval;
+
+ rval = read_radio_reg(pi, addr);
+ write_radio_reg(pi, addr, (rval | val));
+}
+
+void xor_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask)
+{
+ u16 rval;
+
+ rval = read_radio_reg(pi, addr);
+ write_radio_reg(pi, addr, (rval ^ mask));
+}
+
+void mod_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val)
+{
+ u16 rval;
+
+ rval = read_radio_reg(pi, addr);
+ write_radio_reg(pi, addr, (rval & ~mask) | (val & mask));
+}
+
+void write_phy_channel_reg(struct brcms_phy *pi, uint val)
+{
+ W_REG(&pi->regs->phychannel, val);
+}
+
+u16 read_phy_reg(struct brcms_phy *pi, u16 addr)
+{
+ struct d11regs __iomem *regs;
+
+ regs = pi->regs;
+
+ W_REG_FLUSH(&regs->phyregaddr, addr);
+
+ pi->phy_wreg = 0;
+ return R_REG(&regs->phyregdata);
+}
+
+void write_phy_reg(struct brcms_phy *pi, u16 addr, u16 val)
+{
+ struct d11regs __iomem *regs;
+
+ regs = pi->regs;
+
+#ifdef CONFIG_BCM47XX
+ W_REG_FLUSH(&regs->phyregaddr, addr);
+ W_REG(&regs->phyregdata, val);
+ if (addr == 0x72)
+ (void)R_REG(&regs->phyregdata);
+#else
+ W_REG((u32 __iomem *)(&regs->phyregaddr), addr | (val << 16));
+ if (++pi->phy_wreg >= pi->phy_wreg_limit) {
+ pi->phy_wreg = 0;
+ (void)R_REG(&regs->phyversion);
+ }
+#endif
+}
+
+void and_phy_reg(struct brcms_phy *pi, u16 addr, u16 val)
+{
+ struct d11regs __iomem *regs;
+
+ regs = pi->regs;
+
+ W_REG_FLUSH(&regs->phyregaddr, addr);
+
+ W_REG(&regs->phyregdata, (R_REG(&regs->phyregdata) & val));
+ pi->phy_wreg = 0;
+}
+
+void or_phy_reg(struct brcms_phy *pi, u16 addr, u16 val)
+{
+ struct d11regs __iomem *regs;
+
+ regs = pi->regs;
+
+ W_REG_FLUSH(&regs->phyregaddr, addr);
+
+ W_REG(&regs->phyregdata, (R_REG(&regs->phyregdata) | val));
+ pi->phy_wreg = 0;
+}
+
+void mod_phy_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val)
+{
+ struct d11regs __iomem *regs;
+
+ regs = pi->regs;
+
+ W_REG_FLUSH(&regs->phyregaddr, addr);
+
+ W_REG(&regs->phyregdata,
+ ((R_REG(&regs->phyregdata) & ~mask) | (val & mask)));
+ pi->phy_wreg = 0;
+}
+
+static void wlc_set_phy_uninitted(struct brcms_phy *pi)
+{
+ int i, j;
+
+ pi->initialized = false;
+
+ pi->tx_vos = 0xffff;
+ pi->nrssi_table_delta = 0x7fffffff;
+ pi->rc_cal = 0xffff;
+ pi->mintxbias = 0xffff;
+ pi->txpwridx = -1;
+ if (ISNPHY(pi)) {
+ pi->phy_spuravoid = SPURAVOID_DISABLE;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)
+ && NREV_LT(pi->pubpi.phy_rev, 7))
+ pi->phy_spuravoid = SPURAVOID_AUTO;
+
+ pi->nphy_papd_skip = 0;
+ pi->nphy_papd_epsilon_offset[0] = 0xf588;
+ pi->nphy_papd_epsilon_offset[1] = 0xf588;
+ pi->nphy_txpwr_idx[0] = 128;
+ pi->nphy_txpwr_idx[1] = 128;
+ pi->nphy_txpwrindex[0].index_internal = 40;
+ pi->nphy_txpwrindex[1].index_internal = 40;
+ pi->phy_pabias = 0;
+ } else {
+ pi->phy_spuravoid = SPURAVOID_AUTO;
+ }
+ pi->radiopwr = 0xffff;
+ for (i = 0; i < STATIC_NUM_RF; i++) {
+ for (j = 0; j < STATIC_NUM_BB; j++)
+ pi->stats_11b_txpower[i][j] = -1;
+ }
+}
+
+struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp)
+{
+ struct shared_phy *sh;
+
+ sh = kzalloc(sizeof(struct shared_phy), GFP_ATOMIC);
+ if (sh == NULL)
+ return NULL;
+
+ sh->sih = shp->sih;
+ sh->physhim = shp->physhim;
+ sh->unit = shp->unit;
+ sh->corerev = shp->corerev;
+
+ sh->vid = shp->vid;
+ sh->did = shp->did;
+ sh->chip = shp->chip;
+ sh->chiprev = shp->chiprev;
+ sh->chippkg = shp->chippkg;
+ sh->sromrev = shp->sromrev;
+ sh->boardtype = shp->boardtype;
+ sh->boardrev = shp->boardrev;
+ sh->boardvendor = shp->boardvendor;
+ sh->boardflags = shp->boardflags;
+ sh->boardflags2 = shp->boardflags2;
+ sh->buscorerev = shp->buscorerev;
+
+ sh->fast_timer = PHY_SW_TIMER_FAST;
+ sh->slow_timer = PHY_SW_TIMER_SLOW;
+ sh->glacial_timer = PHY_SW_TIMER_GLACIAL;
+
+ sh->rssi_mode = RSSI_ANT_MERGE_MAX;
+
+ return sh;
+}
+
+static void wlc_phy_timercb_phycal(struct brcms_phy *pi)
+{
+ uint delay = 5;
+
+ if (PHY_PERICAL_MPHASE_PENDING(pi)) {
+ if (!pi->sh->up) {
+ wlc_phy_cal_perical_mphase_reset(pi);
+ return;
+ }
+
+ if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) {
+
+ delay = 1000;
+ wlc_phy_cal_perical_mphase_restart(pi);
+ } else
+ wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO);
+ wlapi_add_timer(pi->phycal_timer, delay, 0);
+ return;
+ }
+
+}
+
+static u32 wlc_phy_get_radio_ver(struct brcms_phy *pi)
+{
+ u32 ver;
+
+ ver = read_radio_id(pi);
+
+ return ver;
+}
+
+struct brcms_phy_pub *
+wlc_phy_attach(struct shared_phy *sh, struct d11regs __iomem *regs,
+ int bandtype, struct wiphy *wiphy)
+{
+ struct brcms_phy *pi;
+ u32 sflags = 0;
+ uint phyversion;
+ u32 idcode;
+ int i;
+
+ if (D11REV_IS(sh->corerev, 4))
+ sflags = SISF_2G_PHY | SISF_5G_PHY;
+ else
+ sflags = ai_core_sflags(sh->sih, 0, 0);
+
+ if (bandtype == BRCM_BAND_5G) {
+ if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0)
+ return NULL;
+ }
+
+ pi = sh->phy_head;
+ if ((sflags & SISF_DB_PHY) && pi) {
+ wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
+ pi->refcnt++;
+ return &pi->pubpi_ro;
+ }
+
+ pi = kzalloc(sizeof(struct brcms_phy), GFP_ATOMIC);
+ if (pi == NULL)
+ return NULL;
+ pi->wiphy = wiphy;
+ pi->regs = regs;
+ pi->sh = sh;
+ pi->phy_init_por = true;
+ pi->phy_wreg_limit = PHY_WREG_LIMIT;
+
+ pi->txpwr_percent = 100;
+
+ pi->do_initcal = true;
+
+ pi->phycal_tempdelta = 0;
+
+ if (bandtype == BRCM_BAND_2G && (sflags & SISF_2G_PHY))
+ pi->pubpi.coreflags = SICF_GMODE;
+
+ wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
+ phyversion = R_REG(&pi->regs->phyversion);
+
+ pi->pubpi.phy_type = PHY_TYPE(phyversion);
+ pi->pubpi.phy_rev = phyversion & PV_PV_MASK;
+
+ if (pi->pubpi.phy_type == PHY_TYPE_LCNXN) {
+ pi->pubpi.phy_type = PHY_TYPE_N;
+ pi->pubpi.phy_rev += LCNXN_BASEREV;
+ }
+ pi->pubpi.phy_corenum = PHY_CORE_NUM_2;
+ pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT;
+
+ if (!pi->pubpi.phy_type == PHY_TYPE_N &&
+ !pi->pubpi.phy_type == PHY_TYPE_LCN)
+ goto err;
+
+ if (bandtype == BRCM_BAND_5G) {
+ if (!ISNPHY(pi))
+ goto err;
+ } else if (!ISNPHY(pi) && !ISLCNPHY(pi)) {
+ goto err;
+ }
+
+ wlc_phy_anacore((struct brcms_phy_pub *) pi, ON);
+
+ idcode = wlc_phy_get_radio_ver(pi);
+ pi->pubpi.radioid =
+ (idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT;
+ pi->pubpi.radiorev =
+ (idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT;
+ pi->pubpi.radiover =
+ (idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT;
+ if (!VALID_RADIO(pi, pi->pubpi.radioid))
+ goto err;
+
+ wlc_phy_switch_radio((struct brcms_phy_pub *) pi, OFF);
+
+ wlc_set_phy_uninitted(pi);
+
+ pi->bw = WL_CHANSPEC_BW_20;
+ pi->radio_chanspec = (bandtype == BRCM_BAND_2G) ?
+ ch20mhz_chspec(1) : ch20mhz_chspec(36);
+
+ pi->rxiq_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
+ pi->rxiq_antsel = ANT_RX_DIV_DEF;
+
+ pi->watchdog_override = true;
+
+ pi->cal_type_override = PHY_PERICAL_AUTO;
+
+ pi->nphy_saved_noisevars.bufcount = 0;
+
+ if (ISNPHY(pi))
+ pi->min_txpower = PHY_TXPWR_MIN_NPHY;
+ else
+ pi->min_txpower = PHY_TXPWR_MIN;
+
+ pi->sh->phyrxchain = 0x3;
+
+ pi->rx2tx_biasentry = -1;
+
+ pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
+ pi->phy_txcore_enable_temp =
+ PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP;
+ pi->phy_tempsense_offset = 0;
+ pi->phy_txcore_heatedup = false;
+
+ pi->nphy_lastcal_temp = -50;
+
+ pi->phynoise_polling = true;
+ if (ISNPHY(pi) || ISLCNPHY(pi))
+ pi->phynoise_polling = false;
+
+ for (i = 0; i < TXP_NUM_RATES; i++) {
+ pi->txpwr_limit[i] = BRCMS_TXPWR_MAX;
+ pi->txpwr_env_limit[i] = BRCMS_TXPWR_MAX;
+ pi->tx_user_target[i] = BRCMS_TXPWR_MAX;
+ }
+
+ pi->radiopwr_override = RADIOPWR_OVERRIDE_DEF;
+
+ pi->user_txpwr_at_rfport = false;
+
+ if (ISNPHY(pi)) {
+
+ pi->phycal_timer = wlapi_init_timer(pi->sh->physhim,
+ wlc_phy_timercb_phycal,
+ pi, "phycal");
+ if (!pi->phycal_timer)
+ goto err;
+
+ if (!wlc_phy_attach_nphy(pi))
+ goto err;
+
+ } else if (ISLCNPHY(pi)) {
+ if (!wlc_phy_attach_lcnphy(pi))
+ goto err;
+
+ }
+
+ pi->refcnt++;
+ pi->next = pi->sh->phy_head;
+ sh->phy_head = pi;
+
+ memcpy(&pi->pubpi_ro, &pi->pubpi, sizeof(struct brcms_phy_pub));
+
+ return &pi->pubpi_ro;
+
+err:
+ kfree(pi);
+ return NULL;
+}
+
+void wlc_phy_detach(struct brcms_phy_pub *pih)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+
+ if (pih) {
+ if (--pi->refcnt)
+ return;
+
+ if (pi->phycal_timer) {
+ wlapi_free_timer(pi->phycal_timer);
+ pi->phycal_timer = NULL;
+ }
+
+ if (pi->sh->phy_head == pi)
+ pi->sh->phy_head = pi->next;
+ else if (pi->sh->phy_head->next == pi)
+ pi->sh->phy_head->next = NULL;
+
+ if (pi->pi_fptr.detach)
+ (pi->pi_fptr.detach)(pi);
+
+ kfree(pi);
+ }
+}
+
+bool
+wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype, u16 *phyrev,
+ u16 *radioid, u16 *radiover)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+ *phytype = (u16) pi->pubpi.phy_type;
+ *phyrev = (u16) pi->pubpi.phy_rev;
+ *radioid = pi->pubpi.radioid;
+ *radiover = pi->pubpi.radiorev;
+
+ return true;
+}
+
+bool wlc_phy_get_encore(struct brcms_phy_pub *pih)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+ return pi->pubpi.abgphy_encore;
+}
+
+u32 wlc_phy_get_coreflags(struct brcms_phy_pub *pih)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+ return pi->pubpi.coreflags;
+}
+
+void wlc_phy_anacore(struct brcms_phy_pub *pih, bool on)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+
+ if (ISNPHY(pi)) {
+ if (on) {
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ write_phy_reg(pi, 0xa6, 0x0d);
+ write_phy_reg(pi, 0x8f, 0x0);
+ write_phy_reg(pi, 0xa7, 0x0d);
+ write_phy_reg(pi, 0xa5, 0x0);
+ } else {
+ write_phy_reg(pi, 0xa5, 0x0);
+ }
+ } else {
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ write_phy_reg(pi, 0x8f, 0x07ff);
+ write_phy_reg(pi, 0xa6, 0x0fd);
+ write_phy_reg(pi, 0xa5, 0x07ff);
+ write_phy_reg(pi, 0xa7, 0x0fd);
+ } else {
+ write_phy_reg(pi, 0xa5, 0x7fff);
+ }
+ }
+ } else if (ISLCNPHY(pi)) {
+ if (on) {
+ and_phy_reg(pi, 0x43b,
+ ~((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
+ } else {
+ or_phy_reg(pi, 0x43c,
+ (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
+ or_phy_reg(pi, 0x43b,
+ (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
+ }
+ }
+}
+
+u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+
+ u32 phy_bw_clkbits = 0;
+
+ if (pi && (ISNPHY(pi) || ISLCNPHY(pi))) {
+ switch (pi->bw) {
+ case WL_CHANSPEC_BW_10:
+ phy_bw_clkbits = SICF_BW10;
+ break;
+ case WL_CHANSPEC_BW_20:
+ phy_bw_clkbits = SICF_BW20;
+ break;
+ case WL_CHANSPEC_BW_40:
+ phy_bw_clkbits = SICF_BW40;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return phy_bw_clkbits;
+}
+
+void wlc_phy_por_inform(struct brcms_phy_pub *ppi)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+
+ pi->phy_init_por = true;
+}
+
+void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+
+ pi->edcrs_threshold_lock = lock;
+
+ write_phy_reg(pi, 0x22c, 0x46b);
+ write_phy_reg(pi, 0x22d, 0x46b);
+ write_phy_reg(pi, 0x22e, 0x3c0);
+ write_phy_reg(pi, 0x22f, 0x3c0);
+}
+
+void wlc_phy_initcal_enable(struct brcms_phy_pub *pih, bool initcal)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+
+ pi->do_initcal = initcal;
+}
+
+void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *pih, bool newstate)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+
+ if (!pi || !pi->sh)
+ return;
+
+ pi->sh->clk = newstate;
+}
+
+void wlc_phy_hw_state_upd(struct brcms_phy_pub *pih, bool newstate)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+
+ if (!pi || !pi->sh)
+ return;
+
+ pi->sh->up = newstate;
+}
+
+void wlc_phy_init(struct brcms_phy_pub *pih, u16 chanspec)
+{
+ u32 mc;
+ void (*phy_init)(struct brcms_phy *) = NULL;
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+
+ if (pi->init_in_progress)
+ return;
+
+ pi->init_in_progress = true;
+
+ pi->radio_chanspec = chanspec;
+
+ mc = R_REG(&pi->regs->maccontrol);
+ if (WARN(mc & MCTL_EN_MAC, "HW error MAC running on init"))
+ return;
+
+ if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN))
+ pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC;
+
+ if (WARN(!(ai_core_sflags(pi->sh->sih, 0, 0) & SISF_FCLKA),
+ "HW error SISF_FCLKA\n"))
+ return;
+
+ phy_init = pi->pi_fptr.init;
+
+ if (phy_init == NULL)
+ return;
+
+ wlc_phy_anacore(pih, ON);
+
+ if (CHSPEC_BW(pi->radio_chanspec) != pi->bw)
+ wlapi_bmac_bw_set(pi->sh->physhim,
+ CHSPEC_BW(pi->radio_chanspec));
+
+ pi->nphy_gain_boost = true;
+
+ wlc_phy_switch_radio((struct brcms_phy_pub *) pi, ON);
+
+ (*phy_init)(pi);
+
+ pi->phy_init_por = false;
+
+ if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
+ wlc_phy_do_dummy_tx(pi, true, OFF);
+
+ if (!(ISNPHY(pi)))
+ wlc_phy_txpower_update_shm(pi);
+
+ wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi, pi->sh->rx_antdiv);
+
+ pi->init_in_progress = false;
+}
+
+void wlc_phy_cal_init(struct brcms_phy_pub *pih)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+ void (*cal_init)(struct brcms_phy *) = NULL;
+
+ if (WARN((R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC) != 0,
+ "HW error: MAC enabled during phy cal\n"))
+ return;
+
+ if (!pi->initialized) {
+ cal_init = pi->pi_fptr.calinit;
+ if (cal_init)
+ (*cal_init)(pi);
+
+ pi->initialized = true;
+ }
+}
+
+int wlc_phy_down(struct brcms_phy_pub *pih)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+ int callbacks = 0;
+
+ if (pi->phycal_timer
+ && !wlapi_del_timer(pi->phycal_timer))
+ callbacks++;
+
+ pi->nphy_iqcal_chanspec_2G = 0;
+ pi->nphy_iqcal_chanspec_5G = 0;
+
+ return callbacks;
+}
+
+void
+wlc_phy_table_addr(struct brcms_phy *pi, uint tbl_id, uint tbl_offset,
+ u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
+{
+ write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
+
+ pi->tbl_data_hi = tblDataHi;
+ pi->tbl_data_lo = tblDataLo;
+
+ if (pi->sh->chip == BCM43224_CHIP_ID &&
+ pi->sh->chiprev == 1) {
+ pi->tbl_addr = tblAddr;
+ pi->tbl_save_id = tbl_id;
+ pi->tbl_save_offset = tbl_offset;
+ }
+}
+
+void wlc_phy_table_data_write(struct brcms_phy *pi, uint width, u32 val)
+{
+ if ((pi->sh->chip == BCM43224_CHIP_ID) &&
+ (pi->sh->chiprev == 1) &&
+ (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
+ read_phy_reg(pi, pi->tbl_data_lo);
+
+ write_phy_reg(pi, pi->tbl_addr,
+ (pi->tbl_save_id << 10) | pi->tbl_save_offset);
+ pi->tbl_save_offset++;
+ }
+
+ if (width == 32) {
+ write_phy_reg(pi, pi->tbl_data_hi, (u16) (val >> 16));
+ write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
+ } else {
+ write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
+ }
+}
+
+void
+wlc_phy_write_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info,
+ u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
+{
+ uint idx;
+ uint tbl_id = ptbl_info->tbl_id;
+ uint tbl_offset = ptbl_info->tbl_offset;
+ uint tbl_width = ptbl_info->tbl_width;
+ const u8 *ptbl_8b = (const u8 *)ptbl_info->tbl_ptr;
+ const u16 *ptbl_16b = (const u16 *)ptbl_info->tbl_ptr;
+ const u32 *ptbl_32b = (const u32 *)ptbl_info->tbl_ptr;
+
+ write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
+
+ for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
+
+ if ((pi->sh->chip == BCM43224_CHIP_ID) &&
+ (pi->sh->chiprev == 1) &&
+ (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) {
+ read_phy_reg(pi, tblDataLo);
+
+ write_phy_reg(pi, tblAddr,
+ (tbl_id << 10) | (tbl_offset + idx));
+ }
+
+ if (tbl_width == 32) {
+ write_phy_reg(pi, tblDataHi,
+ (u16) (ptbl_32b[idx] >> 16));
+ write_phy_reg(pi, tblDataLo, (u16) ptbl_32b[idx]);
+ } else if (tbl_width == 16) {
+ write_phy_reg(pi, tblDataLo, ptbl_16b[idx]);
+ } else {
+ write_phy_reg(pi, tblDataLo, ptbl_8b[idx]);
+ }
+ }
+}
+
+void
+wlc_phy_read_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info,
+ u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
+{
+ uint idx;
+ uint tbl_id = ptbl_info->tbl_id;
+ uint tbl_offset = ptbl_info->tbl_offset;
+ uint tbl_width = ptbl_info->tbl_width;
+ u8 *ptbl_8b = (u8 *)ptbl_info->tbl_ptr;
+ u16 *ptbl_16b = (u16 *)ptbl_info->tbl_ptr;
+ u32 *ptbl_32b = (u32 *)ptbl_info->tbl_ptr;
+
+ write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset);
+
+ for (idx = 0; idx < ptbl_info->tbl_len; idx++) {
+
+ if ((pi->sh->chip == BCM43224_CHIP_ID) &&
+ (pi->sh->chiprev == 1)) {
+ (void)read_phy_reg(pi, tblDataLo);
+
+ write_phy_reg(pi, tblAddr,
+ (tbl_id << 10) | (tbl_offset + idx));
+ }
+
+ if (tbl_width == 32) {
+ ptbl_32b[idx] = read_phy_reg(pi, tblDataLo);
+ ptbl_32b[idx] |= (read_phy_reg(pi, tblDataHi) << 16);
+ } else if (tbl_width == 16) {
+ ptbl_16b[idx] = read_phy_reg(pi, tblDataLo);
+ } else {
+ ptbl_8b[idx] = (u8) read_phy_reg(pi, tblDataLo);
+ }
+ }
+}
+
+uint
+wlc_phy_init_radio_regs_allbands(struct brcms_phy *pi,
+ struct radio_20xx_regs *radioregs)
+{
+ uint i = 0;
+
+ do {
+ if (radioregs[i].do_init)
+ write_radio_reg(pi, radioregs[i].address,
+ (u16) radioregs[i].init);
+
+ i++;
+ } while (radioregs[i].address != 0xffff);
+
+ return i;
+}
+
+uint
+wlc_phy_init_radio_regs(struct brcms_phy *pi,
+ const struct radio_regs *radioregs,
+ u16 core_offset)
+{
+ uint i = 0;
+ uint count = 0;
+
+ do {
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ if (radioregs[i].do_init_a) {
+ write_radio_reg(pi,
+ radioregs[i].
+ address | core_offset,
+ (u16) radioregs[i].init_a);
+ if (ISNPHY(pi) && (++count % 4 == 0))
+ BRCMS_PHY_WAR_PR51571(pi);
+ }
+ } else {
+ if (radioregs[i].do_init_g) {
+ write_radio_reg(pi,
+ radioregs[i].
+ address | core_offset,
+ (u16) radioregs[i].init_g);
+ if (ISNPHY(pi) && (++count % 4 == 0))
+ BRCMS_PHY_WAR_PR51571(pi);
+ }
+ }
+
+ i++;
+ } while (radioregs[i].address != 0xffff);
+
+ return i;
+}
+
+void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on)
+{
+#define DUMMY_PKT_LEN 20
+ struct d11regs __iomem *regs = pi->regs;
+ int i, count;
+ u8 ofdmpkt[DUMMY_PKT_LEN] = {
+ 0xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
+ };
+ u8 cckpkt[DUMMY_PKT_LEN] = {
+ 0x6e, 0x84, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
+ };
+ u32 *dummypkt;
+
+ dummypkt = (u32 *) (ofdm ? ofdmpkt : cckpkt);
+ wlapi_bmac_write_template_ram(pi->sh->physhim, 0, DUMMY_PKT_LEN,
+ dummypkt);
+
+ W_REG(&regs->xmtsel, 0);
+
+ if (D11REV_GE(pi->sh->corerev, 11))
+ W_REG(&regs->wepctl, 0x100);
+ else
+ W_REG(&regs->wepctl, 0);
+
+ W_REG(&regs->txe_phyctl, (ofdm ? 1 : 0) | PHY_TXC_ANT_0);
+ if (ISNPHY(pi) || ISLCNPHY(pi))
+ W_REG(&regs->txe_phyctl1, 0x1A02);
+
+ W_REG(&regs->txe_wm_0, 0);
+ W_REG(&regs->txe_wm_1, 0);
+
+ W_REG(&regs->xmttplatetxptr, 0);
+ W_REG(&regs->xmttxcnt, DUMMY_PKT_LEN);
+
+ W_REG(&regs->xmtsel, ((8 << 8) | (1 << 5) | (1 << 2) | 2));
+
+ W_REG(&regs->txe_ctl, 0);
+
+ if (!pa_on) {
+ if (ISNPHY(pi))
+ wlc_phy_pa_override_nphy(pi, OFF);
+ }
+
+ if (ISNPHY(pi) || ISLCNPHY(pi))
+ W_REG(&regs->txe_aux, 0xD0);
+ else
+ W_REG(&regs->txe_aux, ((1 << 5) | (1 << 4)));
+
+ (void)R_REG(&regs->txe_aux);
+
+ i = 0;
+ count = ofdm ? 30 : 250;
+ while ((i++ < count)
+ && (R_REG(&regs->txe_status) & (1 << 7)))
+ udelay(10);
+
+ i = 0;
+
+ while ((i++ < 10)
+ && ((R_REG(&regs->txe_status) & (1 << 10)) == 0))
+ udelay(10);
+
+ i = 0;
+
+ while ((i++ < 10) && ((R_REG(&regs->ifsstat) & (1 << 8))))
+ udelay(10);
+
+ if (!pa_on) {
+ if (ISNPHY(pi))
+ wlc_phy_pa_override_nphy(pi, ON);
+ }
+}
+
+void wlc_phy_hold_upd(struct brcms_phy_pub *pih, u32 id, bool set)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+
+ if (set)
+ mboolset(pi->measure_hold, id);
+ else
+ mboolclr(pi->measure_hold, id);
+
+ return;
+}
+
+void wlc_phy_mute_upd(struct brcms_phy_pub *pih, bool mute, u32 flags)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+
+ if (mute)
+ mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE);
+ else
+ mboolclr(pi->measure_hold, PHY_HOLD_FOR_MUTE);
+
+ if (!mute && (flags & PHY_MUTE_FOR_PREISM))
+ pi->nphy_perical_last = pi->sh->now - pi->sh->glacial_timer;
+ return;
+}
+
+void wlc_phy_clear_tssi(struct brcms_phy_pub *pih)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+
+ if (ISNPHY(pi)) {
+ return;
+ } else {
+ wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_0, NULL_TSSI_W);
+ wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_1, NULL_TSSI_W);
+ wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_0, NULL_TSSI_W);
+ wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_1, NULL_TSSI_W);
+ }
+}
+
+static bool wlc_phy_cal_txpower_recalc_sw(struct brcms_phy *pi)
+{
+ return false;
+}
+
+void wlc_phy_switch_radio(struct brcms_phy_pub *pih, bool on)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+ (void)R_REG(&pi->regs->maccontrol);
+
+ if (ISNPHY(pi)) {
+ wlc_phy_switch_radio_nphy(pi, on);
+ } else if (ISLCNPHY(pi)) {
+ if (on) {
+ and_phy_reg(pi, 0x44c,
+ ~((0x1 << 8) |
+ (0x1 << 9) |
+ (0x1 << 10) | (0x1 << 11) | (0x1 << 12)));
+ and_phy_reg(pi, 0x4b0, ~((0x1 << 3) | (0x1 << 11)));
+ and_phy_reg(pi, 0x4f9, ~(0x1 << 3));
+ } else {
+ and_phy_reg(pi, 0x44d,
+ ~((0x1 << 10) |
+ (0x1 << 11) |
+ (0x1 << 12) | (0x1 << 13) | (0x1 << 14)));
+ or_phy_reg(pi, 0x44c,
+ (0x1 << 8) |
+ (0x1 << 9) |
+ (0x1 << 10) | (0x1 << 11) | (0x1 << 12));
+
+ and_phy_reg(pi, 0x4b7, ~((0x7f << 8)));
+ and_phy_reg(pi, 0x4b1, ~((0x1 << 13)));
+ or_phy_reg(pi, 0x4b0, (0x1 << 3) | (0x1 << 11));
+ and_phy_reg(pi, 0x4fa, ~((0x1 << 3)));
+ or_phy_reg(pi, 0x4f9, (0x1 << 3));
+ }
+ }
+}
+
+u16 wlc_phy_bw_state_get(struct brcms_phy_pub *ppi)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+
+ return pi->bw;
+}
+
+void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+
+ pi->bw = bw;
+}
+
+void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi, u16 newch)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ pi->radio_chanspec = newch;
+
+}
+
+u16 wlc_phy_chanspec_get(struct brcms_phy_pub *ppi)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+
+ return pi->radio_chanspec;
+}
+
+void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, u16 chanspec)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ u16 m_cur_channel;
+ void (*chanspec_set)(struct brcms_phy *, u16) = NULL;
+ m_cur_channel = CHSPEC_CHANNEL(chanspec);
+ if (CHSPEC_IS5G(chanspec))
+ m_cur_channel |= D11_CURCHANNEL_5G;
+ if (CHSPEC_IS40(chanspec))
+ m_cur_channel |= D11_CURCHANNEL_40;
+ wlapi_bmac_write_shm(pi->sh->physhim, M_CURCHANNEL, m_cur_channel);
+
+ chanspec_set = pi->pi_fptr.chanset;
+ if (chanspec_set)
+ (*chanspec_set)(pi, chanspec);
+
+}
+
+int wlc_phy_chanspec_freq2bandrange_lpssn(uint freq)
+{
+ int range = -1;
+
+ if (freq < 2500)
+ range = WL_CHAN_FREQ_RANGE_2G;
+ else if (freq <= 5320)
+ range = WL_CHAN_FREQ_RANGE_5GL;
+ else if (freq <= 5700)
+ range = WL_CHAN_FREQ_RANGE_5GM;
+ else
+ range = WL_CHAN_FREQ_RANGE_5GH;
+
+ return range;
+}
+
+int wlc_phy_chanspec_bandrange_get(struct brcms_phy *pi, u16 chanspec)
+{
+ int range = -1;
+ uint channel = CHSPEC_CHANNEL(chanspec);
+ uint freq = wlc_phy_channel2freq(channel);
+
+ if (ISNPHY(pi))
+ range = wlc_phy_get_chan_freq_range_nphy(pi, channel);
+ else if (ISLCNPHY(pi))
+ range = wlc_phy_chanspec_freq2bandrange_lpssn(freq);
+
+ return range;
+}
+
+void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi,
+ bool wide_filter)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+
+ pi->channel_14_wide_filter = wide_filter;
+
+}
+
+int wlc_phy_channel2freq(uint channel)
+{
+ uint i;
+
+ for (i = 0; i < ARRAY_SIZE(chan_info_all); i++)
+ if (chan_info_all[i].chan == channel)
+ return chan_info_all[i].freq;
+ return 0;
+}
+
+void
+wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band,
+ struct brcms_chanvec *channels)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ uint i;
+ uint channel;
+
+ memset(channels, 0, sizeof(struct brcms_chanvec));
+
+ for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
+ channel = chan_info_all[i].chan;
+
+ if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
+ && (channel <= LAST_REF5_CHANNUM))
+ continue;
+
+ if ((band == BRCM_BAND_2G && channel <= CH_MAX_2G_CHANNEL) ||
+ (band == BRCM_BAND_5G && channel > CH_MAX_2G_CHANNEL))
+ setbit(channels->vec, channel);
+ }
+}
+
+u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ uint i;
+ uint channel;
+ u16 chspec;
+
+ for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
+ channel = chan_info_all[i].chan;
+
+ if (ISNPHY(pi) && pi->bw == WL_CHANSPEC_BW_40) {
+ uint j;
+
+ for (j = 0; j < ARRAY_SIZE(chan_info_all); j++) {
+ if (chan_info_all[j].chan ==
+ channel + CH_10MHZ_APART)
+ break;
+ }
+
+ if (j == ARRAY_SIZE(chan_info_all))
+ continue;
+
+ channel = upper_20_sb(channel);
+ chspec = channel | WL_CHANSPEC_BW_40 |
+ WL_CHANSPEC_CTL_SB_LOWER;
+ if (band == BRCM_BAND_2G)
+ chspec |= WL_CHANSPEC_BAND_2G;
+ else
+ chspec |= WL_CHANSPEC_BAND_5G;
+ } else
+ chspec = ch20mhz_chspec(channel);
+
+ if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
+ && (channel <= LAST_REF5_CHANNUM))
+ continue;
+
+ if ((band == BRCM_BAND_2G && channel <= CH_MAX_2G_CHANNEL) ||
+ (band == BRCM_BAND_5G && channel > CH_MAX_2G_CHANNEL))
+ return chspec;
+ }
+
+ return (u16) INVCHANSPEC;
+}
+
+int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, bool *override)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+
+ *qdbm = pi->tx_user_target[0];
+ if (override != NULL)
+ *override = pi->txpwroverride;
+ return 0;
+}
+
+void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi,
+ struct txpwr_limits *txpwr)
+{
+ bool mac_enabled = false;
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+
+ memcpy(&pi->tx_user_target[TXP_FIRST_CCK],
+ &txpwr->cck[0], BRCMS_NUM_RATES_CCK);
+
+ memcpy(&pi->tx_user_target[TXP_FIRST_OFDM],
+ &txpwr->ofdm[0], BRCMS_NUM_RATES_OFDM);
+ memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_20_CDD],
+ &txpwr->ofdm_cdd[0], BRCMS_NUM_RATES_OFDM);
+
+ memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_SISO],
+ &txpwr->ofdm_40_siso[0], BRCMS_NUM_RATES_OFDM);
+ memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_CDD],
+ &txpwr->ofdm_40_cdd[0], BRCMS_NUM_RATES_OFDM);
+
+ memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SISO],
+ &txpwr->mcs_20_siso[0], BRCMS_NUM_RATES_MCS_1_STREAM);
+ memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_CDD],
+ &txpwr->mcs_20_cdd[0], BRCMS_NUM_RATES_MCS_1_STREAM);
+ memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_STBC],
+ &txpwr->mcs_20_stbc[0], BRCMS_NUM_RATES_MCS_1_STREAM);
+ memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SDM],
+ &txpwr->mcs_20_mimo[0], BRCMS_NUM_RATES_MCS_2_STREAM);
+
+ memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SISO],
+ &txpwr->mcs_40_siso[0], BRCMS_NUM_RATES_MCS_1_STREAM);
+ memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_CDD],
+ &txpwr->mcs_40_cdd[0], BRCMS_NUM_RATES_MCS_1_STREAM);
+ memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_STBC],
+ &txpwr->mcs_40_stbc[0], BRCMS_NUM_RATES_MCS_1_STREAM);
+ memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SDM],
+ &txpwr->mcs_40_mimo[0], BRCMS_NUM_RATES_MCS_2_STREAM);
+
+ if (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)
+ mac_enabled = true;
+
+ if (mac_enabled)
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+
+ wlc_phy_txpower_recalc_target(pi);
+ wlc_phy_cal_txpower_recalc_sw(pi);
+
+ if (mac_enabled)
+ wlapi_enable_mac(pi->sh->physhim);
+}
+
+int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, bool override)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ int i;
+
+ if (qdbm > 127)
+ return -EINVAL;
+
+ for (i = 0; i < TXP_NUM_RATES; i++)
+ pi->tx_user_target[i] = (u8) qdbm;
+
+ pi->txpwroverride = false;
+
+ if (pi->sh->up) {
+ if (!SCAN_INPROG_PHY(pi)) {
+ bool suspend;
+
+ suspend = (0 == (R_REG(&pi->regs->maccontrol) &
+ MCTL_EN_MAC));
+
+ if (!suspend)
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+
+ wlc_phy_txpower_recalc_target(pi);
+ wlc_phy_cal_txpower_recalc_sw(pi);
+
+ if (!suspend)
+ wlapi_enable_mac(pi->sh->physhim);
+ }
+ }
+ return 0;
+}
+
+void
+wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint channel, u8 *min_pwr,
+ u8 *max_pwr, int txp_rate_idx)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ uint i;
+
+ *min_pwr = pi->min_txpower * BRCMS_TXPWR_DB_FACTOR;
+
+ if (ISNPHY(pi)) {
+ if (txp_rate_idx < 0)
+ txp_rate_idx = TXP_FIRST_CCK;
+ wlc_phy_txpower_sromlimit_get_nphy(pi, channel, max_pwr,
+ (u8) txp_rate_idx);
+
+ } else if ((channel <= CH_MAX_2G_CHANNEL)) {
+ if (txp_rate_idx < 0)
+ txp_rate_idx = TXP_FIRST_CCK;
+ *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx];
+ } else {
+
+ *max_pwr = BRCMS_TXPWR_MAX;
+
+ if (txp_rate_idx < 0)
+ txp_rate_idx = TXP_FIRST_OFDM;
+
+ for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
+ if (channel == chan_info_all[i].chan)
+ break;
+ }
+
+ if (pi->hwtxpwr) {
+ *max_pwr = pi->hwtxpwr[i];
+ } else {
+
+ if ((i >= FIRST_MID_5G_CHAN) && (i <= LAST_MID_5G_CHAN))
+ *max_pwr =
+ pi->tx_srom_max_rate_5g_mid[txp_rate_idx];
+ if ((i >= FIRST_HIGH_5G_CHAN)
+ && (i <= LAST_HIGH_5G_CHAN))
+ *max_pwr =
+ pi->tx_srom_max_rate_5g_hi[txp_rate_idx];
+ if ((i >= FIRST_LOW_5G_CHAN) && (i <= LAST_LOW_5G_CHAN))
+ *max_pwr =
+ pi->tx_srom_max_rate_5g_low[txp_rate_idx];
+ }
+ }
+}
+
+void
+wlc_phy_txpower_sromlimit_max_get(struct brcms_phy_pub *ppi, uint chan,
+ u8 *max_txpwr, u8 *min_txpwr)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ u8 tx_pwr_max = 0;
+ u8 tx_pwr_min = 255;
+ u8 max_num_rate;
+ u8 maxtxpwr, mintxpwr, rate, pactrl;
+
+ pactrl = 0;
+
+ max_num_rate = ISNPHY(pi) ? TXP_NUM_RATES :
+ ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 +
+ 1) : (TXP_LAST_OFDM + 1);
+
+ for (rate = 0; rate < max_num_rate; rate++) {
+
+ wlc_phy_txpower_sromlimit(ppi, chan, &mintxpwr, &maxtxpwr,
+ rate);
+
+ maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
+
+ maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
+
+ tx_pwr_max = max(tx_pwr_max, maxtxpwr);
+ tx_pwr_min = min(tx_pwr_min, maxtxpwr);
+ }
+ *max_txpwr = tx_pwr_max;
+ *min_txpwr = tx_pwr_min;
+}
+
+void
+wlc_phy_txpower_boardlimit_band(struct brcms_phy_pub *ppi, uint bandunit,
+ s32 *max_pwr, s32 *min_pwr, u32 *step_pwr)
+{
+ return;
+}
+
+u8 wlc_phy_txpower_get_target_min(struct brcms_phy_pub *ppi)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+
+ return pi->tx_power_min;
+}
+
+u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+
+ return pi->tx_power_max;
+}
+
+static s8 wlc_phy_env_measure_vbat(struct brcms_phy *pi)
+{
+ if (ISLCNPHY(pi))
+ return wlc_lcnphy_vbatsense(pi, 0);
+ else
+ return 0;
+}
+
+static s8 wlc_phy_env_measure_temperature(struct brcms_phy *pi)
+{
+ if (ISLCNPHY(pi))
+ return wlc_lcnphy_tempsense_degree(pi, 0);
+ else
+ return 0;
+}
+
+static void wlc_phy_upd_env_txpwr_rate_limits(struct brcms_phy *pi, u32 band)
+{
+ u8 i;
+ s8 temp, vbat;
+
+ for (i = 0; i < TXP_NUM_RATES; i++)
+ pi->txpwr_env_limit[i] = BRCMS_TXPWR_MAX;
+
+ vbat = wlc_phy_env_measure_vbat(pi);
+ temp = wlc_phy_env_measure_temperature(pi);
+
+}
+
+static s8
+wlc_user_txpwr_antport_to_rfport(struct brcms_phy *pi, uint chan, u32 band,
+ u8 rate)
+{
+ s8 offset = 0;
+
+ if (!pi->user_txpwr_at_rfport)
+ return offset;
+ return offset;
+}
+
+void wlc_phy_txpower_recalc_target(struct brcms_phy *pi)
+{
+ u8 maxtxpwr, mintxpwr, rate, pactrl;
+ uint target_chan;
+ u8 tx_pwr_target[TXP_NUM_RATES];
+ u8 tx_pwr_max = 0;
+ u8 tx_pwr_min = 255;
+ u8 tx_pwr_max_rate_ind = 0;
+ u8 max_num_rate;
+ u8 start_rate = 0;
+ u16 chspec;
+ u32 band = CHSPEC2BAND(pi->radio_chanspec);
+ void (*txpwr_recalc_fn)(struct brcms_phy *) = NULL;
+
+ chspec = pi->radio_chanspec;
+ if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE)
+ target_chan = CHSPEC_CHANNEL(chspec);
+ else if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER)
+ target_chan = upper_20_sb(CHSPEC_CHANNEL(chspec));
+ else
+ target_chan = lower_20_sb(CHSPEC_CHANNEL(chspec));
+
+ pactrl = 0;
+ if (ISLCNPHY(pi)) {
+ u32 offset_mcs, i;
+
+ if (CHSPEC_IS40(pi->radio_chanspec)) {
+ offset_mcs = pi->mcs40_po;
+ for (i = TXP_FIRST_SISO_MCS_20;
+ i <= TXP_LAST_SISO_MCS_20; i++) {
+ pi->tx_srom_max_rate_2g[i - 8] =
+ pi->tx_srom_max_2g -
+ ((offset_mcs & 0xf) * 2);
+ offset_mcs >>= 4;
+ }
+ } else {
+ offset_mcs = pi->mcs20_po;
+ for (i = TXP_FIRST_SISO_MCS_20;
+ i <= TXP_LAST_SISO_MCS_20; i++) {
+ pi->tx_srom_max_rate_2g[i - 8] =
+ pi->tx_srom_max_2g -
+ ((offset_mcs & 0xf) * 2);
+ offset_mcs >>= 4;
+ }
+ }
+ }
+
+ max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
+ ((ISLCNPHY(pi)) ?
+ (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1)));
+
+ wlc_phy_upd_env_txpwr_rate_limits(pi, band);
+
+ for (rate = start_rate; rate < max_num_rate; rate++) {
+
+ tx_pwr_target[rate] = pi->tx_user_target[rate];
+
+ if (pi->user_txpwr_at_rfport)
+ tx_pwr_target[rate] +=
+ wlc_user_txpwr_antport_to_rfport(pi,
+ target_chan,
+ band,
+ rate);
+
+ wlc_phy_txpower_sromlimit((struct brcms_phy_pub *) pi,
+ target_chan,
+ &mintxpwr, &maxtxpwr, rate);
+
+ maxtxpwr = min(maxtxpwr, pi->txpwr_limit[rate]);
+
+ maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
+
+ maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
+
+ maxtxpwr = min(maxtxpwr, tx_pwr_target[rate]);
+
+ if (pi->txpwr_percent <= 100)
+ maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100;
+
+ tx_pwr_target[rate] = max(maxtxpwr, mintxpwr);
+
+ tx_pwr_target[rate] =
+ min(tx_pwr_target[rate], pi->txpwr_env_limit[rate]);
+
+ if (tx_pwr_target[rate] > tx_pwr_max)
+ tx_pwr_max_rate_ind = rate;
+
+ tx_pwr_max = max(tx_pwr_max, tx_pwr_target[rate]);
+ tx_pwr_min = min(tx_pwr_min, tx_pwr_target[rate]);
+ }
+
+ memset(pi->tx_power_offset, 0, sizeof(pi->tx_power_offset));
+ pi->tx_power_max = tx_pwr_max;
+ pi->tx_power_min = tx_pwr_min;
+ pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind;
+ for (rate = 0; rate < max_num_rate; rate++) {
+
+ pi->tx_power_target[rate] = tx_pwr_target[rate];
+
+ if (!pi->hwpwrctrl || ISNPHY(pi))
+ pi->tx_power_offset[rate] =
+ pi->tx_power_max - pi->tx_power_target[rate];
+ else
+ pi->tx_power_offset[rate] =
+ pi->tx_power_target[rate] - pi->tx_power_min;
+ }
+
+ txpwr_recalc_fn = pi->pi_fptr.txpwrrecalc;
+ if (txpwr_recalc_fn)
+ (*txpwr_recalc_fn)(pi);
+}
+
+static void
+wlc_phy_txpower_reg_limit_calc(struct brcms_phy *pi, struct txpwr_limits *txpwr,
+ u16 chanspec)
+{
+ u8 tmp_txpwr_limit[2 * BRCMS_NUM_RATES_OFDM];
+ u8 *txpwr_ptr1 = NULL, *txpwr_ptr2 = NULL;
+ int rate_start_index = 0, rate1, rate2, k;
+
+ for (rate1 = WL_TX_POWER_CCK_FIRST, rate2 = 0;
+ rate2 < WL_TX_POWER_CCK_NUM; rate1++, rate2++)
+ pi->txpwr_limit[rate1] = txpwr->cck[rate2];
+
+ for (rate1 = WL_TX_POWER_OFDM_FIRST, rate2 = 0;
+ rate2 < WL_TX_POWER_OFDM_NUM; rate1++, rate2++)
+ pi->txpwr_limit[rate1] = txpwr->ofdm[rate2];
+
+ if (ISNPHY(pi)) {
+
+ for (k = 0; k < 4; k++) {
+ switch (k) {
+ case 0:
+
+ txpwr_ptr1 = txpwr->mcs_20_siso;
+ txpwr_ptr2 = txpwr->ofdm;
+ rate_start_index = WL_TX_POWER_OFDM_FIRST;
+ break;
+ case 1:
+
+ txpwr_ptr1 = txpwr->mcs_20_cdd;
+ txpwr_ptr2 = txpwr->ofdm_cdd;
+ rate_start_index = WL_TX_POWER_OFDM20_CDD_FIRST;
+ break;
+ case 2:
+
+ txpwr_ptr1 = txpwr->mcs_40_siso;
+ txpwr_ptr2 = txpwr->ofdm_40_siso;
+ rate_start_index =
+ WL_TX_POWER_OFDM40_SISO_FIRST;
+ break;
+ case 3:
+
+ txpwr_ptr1 = txpwr->mcs_40_cdd;
+ txpwr_ptr2 = txpwr->ofdm_40_cdd;
+ rate_start_index = WL_TX_POWER_OFDM40_CDD_FIRST;
+ break;
+ }
+
+ for (rate2 = 0; rate2 < BRCMS_NUM_RATES_OFDM;
+ rate2++) {
+ tmp_txpwr_limit[rate2] = 0;
+ tmp_txpwr_limit[BRCMS_NUM_RATES_OFDM + rate2] =
+ txpwr_ptr1[rate2];
+ }
+ wlc_phy_mcs_to_ofdm_powers_nphy(
+ tmp_txpwr_limit, 0,
+ BRCMS_NUM_RATES_OFDM -
+ 1, BRCMS_NUM_RATES_OFDM);
+ for (rate1 = rate_start_index, rate2 = 0;
+ rate2 < BRCMS_NUM_RATES_OFDM; rate1++, rate2++)
+ pi->txpwr_limit[rate1] =
+ min(txpwr_ptr2[rate2],
+ tmp_txpwr_limit[rate2]);
+ }
+
+ for (k = 0; k < 4; k++) {
+ switch (k) {
+ case 0:
+
+ txpwr_ptr1 = txpwr->ofdm;
+ txpwr_ptr2 = txpwr->mcs_20_siso;
+ rate_start_index = WL_TX_POWER_MCS20_SISO_FIRST;
+ break;
+ case 1:
+
+ txpwr_ptr1 = txpwr->ofdm_cdd;
+ txpwr_ptr2 = txpwr->mcs_20_cdd;
+ rate_start_index = WL_TX_POWER_MCS20_CDD_FIRST;
+ break;
+ case 2:
+
+ txpwr_ptr1 = txpwr->ofdm_40_siso;
+ txpwr_ptr2 = txpwr->mcs_40_siso;
+ rate_start_index = WL_TX_POWER_MCS40_SISO_FIRST;
+ break;
+ case 3:
+
+ txpwr_ptr1 = txpwr->ofdm_40_cdd;
+ txpwr_ptr2 = txpwr->mcs_40_cdd;
+ rate_start_index = WL_TX_POWER_MCS40_CDD_FIRST;
+ break;
+ }
+ for (rate2 = 0; rate2 < BRCMS_NUM_RATES_OFDM;
+ rate2++) {
+ tmp_txpwr_limit[rate2] = 0;
+ tmp_txpwr_limit[BRCMS_NUM_RATES_OFDM + rate2] =
+ txpwr_ptr1[rate2];
+ }
+ wlc_phy_ofdm_to_mcs_powers_nphy(
+ tmp_txpwr_limit, 0,
+ BRCMS_NUM_RATES_OFDM -
+ 1, BRCMS_NUM_RATES_OFDM);
+ for (rate1 = rate_start_index, rate2 = 0;
+ rate2 < BRCMS_NUM_RATES_MCS_1_STREAM;
+ rate1++, rate2++)
+ pi->txpwr_limit[rate1] =
+ min(txpwr_ptr2[rate2],
+ tmp_txpwr_limit[rate2]);
+ }
+
+ for (k = 0; k < 2; k++) {
+ switch (k) {
+ case 0:
+
+ rate_start_index = WL_TX_POWER_MCS20_STBC_FIRST;
+ txpwr_ptr1 = txpwr->mcs_20_stbc;
+ break;
+ case 1:
+
+ rate_start_index = WL_TX_POWER_MCS40_STBC_FIRST;
+ txpwr_ptr1 = txpwr->mcs_40_stbc;
+ break;
+ }
+ for (rate1 = rate_start_index, rate2 = 0;
+ rate2 < BRCMS_NUM_RATES_MCS_1_STREAM;
+ rate1++, rate2++)
+ pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
+ }
+
+ for (k = 0; k < 2; k++) {
+ switch (k) {
+ case 0:
+
+ rate_start_index = WL_TX_POWER_MCS20_SDM_FIRST;
+ txpwr_ptr1 = txpwr->mcs_20_mimo;
+ break;
+ case 1:
+
+ rate_start_index = WL_TX_POWER_MCS40_SDM_FIRST;
+ txpwr_ptr1 = txpwr->mcs_40_mimo;
+ break;
+ }
+ for (rate1 = rate_start_index, rate2 = 0;
+ rate2 < BRCMS_NUM_RATES_MCS_2_STREAM;
+ rate1++, rate2++)
+ pi->txpwr_limit[rate1] = txpwr_ptr1[rate2];
+ }
+
+ pi->txpwr_limit[WL_TX_POWER_MCS_32] = txpwr->mcs32;
+
+ pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST] =
+ min(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST],
+ pi->txpwr_limit[WL_TX_POWER_MCS_32]);
+ pi->txpwr_limit[WL_TX_POWER_MCS_32] =
+ pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST];
+ }
+}
+
+void wlc_phy_txpwr_percent_set(struct brcms_phy_pub *ppi, u8 txpwr_percent)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+
+ pi->txpwr_percent = txpwr_percent;
+}
+
+void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+
+ pi->sh->machwcap = machwcap;
+}
+
+void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ u16 rxc;
+ rxc = 0;
+
+ if (start_end == ON) {
+ if (!ISNPHY(pi))
+ return;
+
+ if (NREV_IS(pi->pubpi.phy_rev, 3)
+ || NREV_IS(pi->pubpi.phy_rev, 4)) {
+ W_REG(&pi->regs->phyregaddr, 0xa0);
+ (void)R_REG(&pi->regs->phyregaddr);
+ rxc = R_REG(&pi->regs->phyregdata);
+ W_REG(&pi->regs->phyregdata,
+ (0x1 << 15) | rxc);
+ }
+ } else {
+ if (NREV_IS(pi->pubpi.phy_rev, 3)
+ || NREV_IS(pi->pubpi.phy_rev, 4)) {
+ W_REG(&pi->regs->phyregaddr, 0xa0);
+ (void)R_REG(&pi->regs->phyregaddr);
+ W_REG(&pi->regs->phyregdata, rxc);
+ }
+
+ wlc_phy_por_inform(ppi);
+ }
+}
+
+void
+wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr,
+ u16 chanspec)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+
+ wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec);
+
+ if (ISLCNPHY(pi)) {
+ int i, j;
+ for (i = TXP_FIRST_OFDM_20_CDD, j = 0;
+ j < BRCMS_NUM_RATES_MCS_1_STREAM; i++, j++) {
+ if (txpwr->mcs_20_siso[j])
+ pi->txpwr_limit[i] = txpwr->mcs_20_siso[j];
+ else
+ pi->txpwr_limit[i] = txpwr->ofdm[j];
+ }
+ }
+
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+
+ wlc_phy_txpower_recalc_target(pi);
+ wlc_phy_cal_txpower_recalc_sw(pi);
+ wlapi_enable_mac(pi->sh->physhim);
+}
+
+void wlc_phy_ofdm_rateset_war(struct brcms_phy_pub *pih, bool war)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+
+ pi->ofdm_rateset_war = war;
+}
+
+void wlc_phy_bf_preempt_enable(struct brcms_phy_pub *pih, bool bf_preempt)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+
+ pi->bf_preempt_4306 = bf_preempt;
+}
+
+void wlc_phy_txpower_update_shm(struct brcms_phy *pi)
+{
+ int j;
+ if (ISNPHY(pi))
+ return;
+
+ if (!pi->sh->clk)
+ return;
+
+ if (pi->hwpwrctrl) {
+ u16 offset;
+
+ wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_MAX, 63);
+ wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_N,
+ 1 << NUM_TSSI_FRAMES);
+
+ wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_TARGET,
+ pi->tx_power_min << NUM_TSSI_FRAMES);
+
+ wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_CUR,
+ pi->hwpwr_txcur);
+
+ for (j = TXP_FIRST_OFDM; j <= TXP_LAST_OFDM; j++) {
+ const u8 ucode_ofdm_rates[] = {
+ 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c
+ };
+ offset = wlapi_bmac_rate_shm_offset(
+ pi->sh->physhim,
+ ucode_ofdm_rates[j - TXP_FIRST_OFDM]);
+ wlapi_bmac_write_shm(pi->sh->physhim, offset + 6,
+ pi->tx_power_offset[j]);
+ wlapi_bmac_write_shm(pi->sh->physhim, offset + 14,
+ -(pi->tx_power_offset[j] / 2));
+ }
+
+ wlapi_bmac_mhf(pi->sh->physhim, MHF2, MHF2_HWPWRCTL,
+ MHF2_HWPWRCTL, BRCM_BAND_ALL);
+ } else {
+ int i;
+
+ for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++)
+ pi->tx_power_offset[i] =
+ (u8) roundup(pi->tx_power_offset[i], 8);
+ wlapi_bmac_write_shm(pi->sh->physhim, M_OFDM_OFFSET,
+ (u16)
+ ((pi->tx_power_offset[TXP_FIRST_OFDM]
+ + 7) >> 3));
+ }
+}
+
+bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+
+ if (ISNPHY(pi))
+ return pi->nphy_txpwrctrl;
+ else
+ return pi->hwpwrctrl;
+}
+
+void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, bool hwpwrctrl)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ bool suspend;
+
+ if (!pi->hwpwrctrl_capable)
+ return;
+
+ pi->hwpwrctrl = hwpwrctrl;
+ pi->nphy_txpwrctrl = hwpwrctrl;
+ pi->txpwrctrl = hwpwrctrl;
+
+ if (ISNPHY(pi)) {
+ suspend = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
+ if (!suspend)
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+
+ wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl);
+ if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF)
+ wlc_phy_txpwr_fixpower_nphy(pi);
+ else
+ mod_phy_reg(pi, 0x1e7, (0x7f << 0),
+ pi->saved_txpwr_idx);
+
+ if (!suspend)
+ wlapi_enable_mac(pi->sh->physhim);
+ }
+}
+
+void wlc_phy_txpower_ipa_upd(struct brcms_phy *pi)
+{
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ pi->ipa2g_on = (pi->srom_fem2g.extpagain == 2);
+ pi->ipa5g_on = (pi->srom_fem5g.extpagain == 2);
+ } else {
+ pi->ipa2g_on = false;
+ pi->ipa5g_on = false;
+ }
+}
+
+static u32 wlc_phy_txpower_est_power_nphy(struct brcms_phy *pi)
+{
+ s16 tx0_status, tx1_status;
+ u16 estPower1, estPower2;
+ u8 pwr0, pwr1, adj_pwr0, adj_pwr1;
+ u32 est_pwr;
+
+ estPower1 = read_phy_reg(pi, 0x118);
+ estPower2 = read_phy_reg(pi, 0x119);
+
+ if ((estPower1 & (0x1 << 8)) == (0x1 << 8))
+ pwr0 = (u8) (estPower1 & (0xff << 0)) >> 0;
+ else
+ pwr0 = 0x80;
+
+ if ((estPower2 & (0x1 << 8)) == (0x1 << 8))
+ pwr1 = (u8) (estPower2 & (0xff << 0)) >> 0;
+ else
+ pwr1 = 0x80;
+
+ tx0_status = read_phy_reg(pi, 0x1ed);
+ tx1_status = read_phy_reg(pi, 0x1ee);
+
+ if ((tx0_status & (0x1 << 15)) == (0x1 << 15))
+ adj_pwr0 = (u8) (tx0_status & (0xff << 0)) >> 0;
+ else
+ adj_pwr0 = 0x80;
+ if ((tx1_status & (0x1 << 15)) == (0x1 << 15))
+ adj_pwr1 = (u8) (tx1_status & (0xff << 0)) >> 0;
+ else
+ adj_pwr1 = 0x80;
+
+ est_pwr = (u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) |
+ adj_pwr1);
+
+ return est_pwr;
+}
+
+void
+wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, struct tx_power *power,
+ uint channel)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ uint rate, num_rates;
+ u8 min_pwr, max_pwr;
+
+#if WL_TX_POWER_RATES != TXP_NUM_RATES
+#error "struct tx_power out of sync with this fn"
+#endif
+
+ if (ISNPHY(pi)) {
+ power->rf_cores = 2;
+ power->flags |= (WL_TX_POWER_F_MIMO);
+ if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON)
+ power->flags |=
+ (WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW);
+ } else if (ISLCNPHY(pi)) {
+ power->rf_cores = 1;
+ power->flags |= (WL_TX_POWER_F_SISO);
+ if (pi->radiopwr_override == RADIOPWR_OVERRIDE_DEF)
+ power->flags |= WL_TX_POWER_F_ENABLED;
+ if (pi->hwpwrctrl)
+ power->flags |= WL_TX_POWER_F_HW;
+ }
+
+ num_rates = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
+ ((ISLCNPHY(pi)) ?
+ (TXP_LAST_OFDM_20_CDD + 1) : (TXP_LAST_OFDM + 1)));
+
+ for (rate = 0; rate < num_rates; rate++) {
+ power->user_limit[rate] = pi->tx_user_target[rate];
+ wlc_phy_txpower_sromlimit(ppi, channel, &min_pwr, &max_pwr,
+ rate);
+ power->board_limit[rate] = (u8) max_pwr;
+ power->target[rate] = pi->tx_power_target[rate];
+ }
+
+ if (ISNPHY(pi)) {
+ u32 est_pout;
+
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+ wlc_phyreg_enter((struct brcms_phy_pub *) pi);
+ est_pout = wlc_phy_txpower_est_power_nphy(pi);
+ wlc_phyreg_exit((struct brcms_phy_pub *) pi);
+ wlapi_enable_mac(pi->sh->physhim);
+
+ power->est_Pout[0] = (est_pout >> 8) & 0xff;
+ power->est_Pout[1] = est_pout & 0xff;
+
+ power->est_Pout_act[0] = est_pout >> 24;
+ power->est_Pout_act[1] = (est_pout >> 16) & 0xff;
+
+ if (power->est_Pout[0] == 0x80)
+ power->est_Pout[0] = 0;
+ if (power->est_Pout[1] == 0x80)
+ power->est_Pout[1] = 0;
+
+ if (power->est_Pout_act[0] == 0x80)
+ power->est_Pout_act[0] = 0;
+ if (power->est_Pout_act[1] == 0x80)
+ power->est_Pout_act[1] = 0;
+
+ power->est_Pout_cck = 0;
+
+ power->tx_power_max[0] = pi->tx_power_max;
+ power->tx_power_max[1] = pi->tx_power_max;
+
+ power->tx_power_max_rate_ind[0] = pi->tx_power_max_rate_ind;
+ power->tx_power_max_rate_ind[1] = pi->tx_power_max_rate_ind;
+ } else if (pi->hwpwrctrl && pi->sh->up) {
+
+ wlc_phyreg_enter(ppi);
+ if (ISLCNPHY(pi)) {
+
+ power->tx_power_max[0] = pi->tx_power_max;
+ power->tx_power_max[1] = pi->tx_power_max;
+
+ power->tx_power_max_rate_ind[0] =
+ pi->tx_power_max_rate_ind;
+ power->tx_power_max_rate_ind[1] =
+ pi->tx_power_max_rate_ind;
+
+ if (wlc_phy_tpc_isenabled_lcnphy(pi))
+ power->flags |=
+ (WL_TX_POWER_F_HW |
+ WL_TX_POWER_F_ENABLED);
+ else
+ power->flags &=
+ ~(WL_TX_POWER_F_HW |
+ WL_TX_POWER_F_ENABLED);
+
+ wlc_lcnphy_get_tssi(pi, (s8 *) &power->est_Pout[0],
+ (s8 *) &power->est_Pout_cck);
+ }
+ wlc_phyreg_exit(ppi);
+ }
+}
+
+void wlc_phy_antsel_type_set(struct brcms_phy_pub *ppi, u8 antsel_type)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+
+ pi->antsel_type = antsel_type;
+}
+
+bool wlc_phy_test_ison(struct brcms_phy_pub *ppi)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+
+ return pi->phytest_on;
+}
+
+void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ bool suspend;
+
+ pi->sh->rx_antdiv = val;
+
+ if (!(ISNPHY(pi) && D11REV_IS(pi->sh->corerev, 16))) {
+ if (val > ANT_RX_DIV_FORCE_1)
+ wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV,
+ MHF1_ANTDIV, BRCM_BAND_ALL);
+ else
+ wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 0,
+ BRCM_BAND_ALL);
+ }
+
+ if (ISNPHY(pi))
+ return;
+
+ if (!pi->sh->clk)
+ return;
+
+ suspend = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
+ if (!suspend)
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+
+ if (ISLCNPHY(pi)) {
+ if (val > ANT_RX_DIV_FORCE_1) {
+ mod_phy_reg(pi, 0x410, (0x1 << 1), 0x01 << 1);
+ mod_phy_reg(pi, 0x410,
+ (0x1 << 0),
+ ((ANT_RX_DIV_START_1 == val) ? 1 : 0) << 0);
+ } else {
+ mod_phy_reg(pi, 0x410, (0x1 << 1), 0x00 << 1);
+ mod_phy_reg(pi, 0x410, (0x1 << 0), (u16) val << 0);
+ }
+ }
+
+ if (!suspend)
+ wlapi_enable_mac(pi->sh->physhim);
+
+ return;
+}
+
+static bool
+wlc_phy_noise_calc_phy(struct brcms_phy *pi, u32 *cmplx_pwr, s8 *pwr_ant)
+{
+ s8 cmplx_pwr_dbm[PHY_CORE_MAX];
+ u8 i;
+
+ memset((u8 *) cmplx_pwr_dbm, 0, sizeof(cmplx_pwr_dbm));
+ wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum);
+
+ for (i = 0; i < pi->pubpi.phy_corenum; i++) {
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
+ cmplx_pwr_dbm[i] += (s8) PHY_NOISE_OFFSETFACT_4322;
+ else
+
+ cmplx_pwr_dbm[i] += (s8) (16 - (15) * 3 - 70);
+ }
+
+ for (i = 0; i < pi->pubpi.phy_corenum; i++) {
+ pi->nphy_noise_win[i][pi->nphy_noise_index] = cmplx_pwr_dbm[i];
+ pwr_ant[i] = cmplx_pwr_dbm[i];
+ }
+ pi->nphy_noise_index =
+ MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
+ return true;
+}
+
+static void wlc_phy_noise_cb(struct brcms_phy *pi, u8 channel, s8 noise_dbm)
+{
+ if (!pi->phynoise_state)
+ return;
+
+ if (pi->phynoise_state & PHY_NOISE_STATE_MON) {
+ if (pi->phynoise_chan_watchdog == channel) {
+ pi->sh->phy_noise_window[pi->sh->phy_noise_index] =
+ noise_dbm;
+ pi->sh->phy_noise_index =
+ MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ);
+ }
+ pi->phynoise_state &= ~PHY_NOISE_STATE_MON;
+ }
+
+ if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL)
+ pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL;
+
+}
+
+static s8 wlc_phy_noise_read_shmem(struct brcms_phy *pi)
+{
+ u32 cmplx_pwr[PHY_CORE_MAX];
+ s8 noise_dbm_ant[PHY_CORE_MAX];
+ u16 lo, hi;
+ u32 cmplx_pwr_tot = 0;
+ s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
+ u8 idx, core;
+
+ memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
+ memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
+
+ for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2,
+ core++) {
+ lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx));
+ hi = wlapi_bmac_read_shm(pi->sh->physhim,
+ M_PWRIND_MAP(idx + 1));
+ cmplx_pwr[core] = (hi << 16) + lo;
+ cmplx_pwr_tot += cmplx_pwr[core];
+ if (cmplx_pwr[core] == 0)
+ noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY;
+ else
+ cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE;
+ }
+
+ if (cmplx_pwr_tot != 0)
+ wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
+
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+ pi->nphy_noise_win[core][pi->nphy_noise_index] =
+ noise_dbm_ant[core];
+
+ if (noise_dbm_ant[core] > noise_dbm)
+ noise_dbm = noise_dbm_ant[core];
+ }
+ pi->nphy_noise_index =
+ MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
+
+ return noise_dbm;
+
+}
+
+void wlc_phy_noise_sample_intr(struct brcms_phy_pub *pih)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+ u16 jssi_aux;
+ u8 channel = 0;
+ s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
+
+ if (ISLCNPHY(pi)) {
+ u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1;
+ u16 lo, hi;
+ s32 pwr_offset_dB, gain_dB;
+ u16 status_0, status_1;
+
+ jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
+ channel = jssi_aux & D11_CURCHANNEL_MAX;
+
+ lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0);
+ hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1);
+ cmplx_pwr0 = (hi << 16) + lo;
+
+ lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2);
+ hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3);
+ cmplx_pwr1 = (hi << 16) + lo;
+ cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6;
+
+ status_0 = 0x44;
+ status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0);
+ if ((cmplx_pwr > 0 && cmplx_pwr < 500)
+ && ((status_1 & 0xc000) == 0x4000)) {
+
+ wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm,
+ pi->pubpi.phy_corenum);
+ pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF);
+ if (pwr_offset_dB > 127)
+ pwr_offset_dB -= 256;
+
+ noise_dbm += (s8) (pwr_offset_dB - 30);
+
+ gain_dB = (status_0 & 0x1ff);
+ noise_dbm -= (s8) (gain_dB);
+ } else {
+ noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY;
+ }
+ } else if (ISNPHY(pi)) {
+
+ jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
+ channel = jssi_aux & D11_CURCHANNEL_MAX;
+
+ noise_dbm = wlc_phy_noise_read_shmem(pi);
+ }
+
+ wlc_phy_noise_cb(pi, channel, noise_dbm);
+
+}
+
+static void
+wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason, u8 ch)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+ s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
+ bool sampling_in_progress = (pi->phynoise_state != 0);
+ bool wait_for_intr = true;
+
+ switch (reason) {
+ case PHY_NOISE_SAMPLE_MON:
+ pi->phynoise_chan_watchdog = ch;
+ pi->phynoise_state |= PHY_NOISE_STATE_MON;
+ break;
+
+ case PHY_NOISE_SAMPLE_EXTERNAL:
+ pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL;
+ break;
+
+ default:
+ break;
+ }
+
+ if (sampling_in_progress)
+ return;
+
+ pi->phynoise_now = pi->sh->now;
+
+ if (pi->phy_fixed_noise) {
+ if (ISNPHY(pi)) {
+ pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] =
+ PHY_NOISE_FIXED_VAL_NPHY;
+ pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] =
+ PHY_NOISE_FIXED_VAL_NPHY;
+ pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
+ PHY_NOISE_WINDOW_SZ);
+ noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
+ } else {
+ noise_dbm = PHY_NOISE_FIXED_VAL;
+ }
+
+ wait_for_intr = false;
+ goto done;
+ }
+
+ if (ISLCNPHY(pi)) {
+ if (!pi->phynoise_polling
+ || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
+ wlapi_bmac_write_shm(pi->sh->physhim, M_JSSI_0, 0);
+ wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
+ wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
+ wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
+ wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
+
+ OR_REG(&pi->regs->maccommand,
+ MCMD_BG_NOISE);
+ } else {
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+ wlc_lcnphy_deaf_mode(pi, (bool) 0);
+ noise_dbm = (s8) wlc_lcnphy_rx_signal_power(pi, 20);
+ wlc_lcnphy_deaf_mode(pi, (bool) 1);
+ wlapi_enable_mac(pi->sh->physhim);
+ wait_for_intr = false;
+ }
+ } else if (ISNPHY(pi)) {
+ if (!pi->phynoise_polling
+ || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) {
+
+ wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0);
+ wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0);
+ wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0);
+ wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0);
+
+ OR_REG(&pi->regs->maccommand,
+ MCMD_BG_NOISE);
+ } else {
+ struct phy_iq_est est[PHY_CORE_MAX];
+ u32 cmplx_pwr[PHY_CORE_MAX];
+ s8 noise_dbm_ant[PHY_CORE_MAX];
+ u16 log_num_samps, num_samps, classif_state = 0;
+ u8 wait_time = 32;
+ u8 wait_crs = 0;
+ u8 i;
+
+ memset((u8 *) est, 0, sizeof(est));
+ memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
+ memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
+
+ log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
+ num_samps = 1 << log_num_samps;
+
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+ classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
+ wlc_phy_classifier_nphy(pi, 3, 0);
+ wlc_phy_rx_iq_est_nphy(pi, est, num_samps, wait_time,
+ wait_crs);
+ wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);
+ wlapi_enable_mac(pi->sh->physhim);
+
+ for (i = 0; i < pi->pubpi.phy_corenum; i++)
+ cmplx_pwr[i] = (est[i].i_pwr + est[i].q_pwr) >>
+ log_num_samps;
+
+ wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
+
+ for (i = 0; i < pi->pubpi.phy_corenum; i++) {
+ pi->nphy_noise_win[i][pi->nphy_noise_index] =
+ noise_dbm_ant[i];
+
+ if (noise_dbm_ant[i] > noise_dbm)
+ noise_dbm = noise_dbm_ant[i];
+ }
+ pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
+ PHY_NOISE_WINDOW_SZ);
+
+ wait_for_intr = false;
+ }
+ }
+
+done:
+
+ if (!wait_for_intr)
+ wlc_phy_noise_cb(pi, ch, noise_dbm);
+
+}
+
+void wlc_phy_noise_sample_request_external(struct brcms_phy_pub *pih)
+{
+ u8 channel;
+
+ channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih));
+
+ wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel);
+}
+
+static const s8 lcnphy_gain_index_offset_for_pkt_rssi[] = {
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 8,
+ 9,
+ 10,
+ 8,
+ 8,
+ 7,
+ 7,
+ 1,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_cmplx_pwr_dB, u8 core)
+{
+ u8 msb, secondmsb, i;
+ u32 tmp;
+
+ for (i = 0; i < core; i++) {
+ secondmsb = 0;
+ tmp = cmplx_pwr[i];
+ msb = fls(tmp);
+ if (msb)
+ secondmsb = (u8) ((tmp >> (--msb - 1)) & 1);
+ p_cmplx_pwr_dB[i] = (s8) (3 * msb + 2 * secondmsb);
+ }
+}
+
+int wlc_phy_rssi_compute(struct brcms_phy_pub *pih,
+ struct d11rxhdr *rxh)
+{
+ int rssi = rxh->PhyRxStatus_1 & PRXS1_JSSI_MASK;
+ uint radioid = pih->radioid;
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+
+ if ((pi->sh->corerev >= 11)
+ && !(rxh->RxStatus2 & RXS_PHYRXST_VALID)) {
+ rssi = BRCMS_RSSI_INVALID;
+ goto end;
+ }
+
+ if (ISLCNPHY(pi)) {
+ u8 gidx = (rxh->PhyRxStatus_2 & 0xFC00) >> 10;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ if (rssi > 127)
+ rssi -= 256;
+
+ rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx];
+ if ((rssi > -46) && (gidx > 18))
+ rssi = rssi + 7;
+
+ rssi = rssi + pi_lcn->lcnphy_pkteng_rssi_slope;
+
+ rssi = rssi + 2;
+
+ }
+
+ if (ISLCNPHY(pi)) {
+ if (rssi > 127)
+ rssi -= 256;
+ } else if (radioid == BCM2055_ID || radioid == BCM2056_ID
+ || radioid == BCM2057_ID) {
+ rssi = wlc_phy_rssi_compute_nphy(pi, rxh);
+ }
+
+end:
+ return rssi;
+}
+
+void wlc_phy_freqtrack_start(struct brcms_phy_pub *pih)
+{
+ return;
+}
+
+void wlc_phy_freqtrack_end(struct brcms_phy_pub *pih)
+{
+ return;
+}
+
+void wlc_phy_set_deaf(struct brcms_phy_pub *ppi, bool user_flag)
+{
+ struct brcms_phy *pi;
+ pi = (struct brcms_phy *) ppi;
+
+ if (ISLCNPHY(pi))
+ wlc_lcnphy_deaf_mode(pi, true);
+ else if (ISNPHY(pi))
+ wlc_nphy_deaf_mode(pi, true);
+}
+
+void wlc_phy_watchdog(struct brcms_phy_pub *pih)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+ bool delay_phy_cal = false;
+ pi->sh->now++;
+
+ if (!pi->watchdog_override)
+ return;
+
+ if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)))
+ wlc_phy_noise_sample_request((struct brcms_phy_pub *) pi,
+ PHY_NOISE_SAMPLE_MON,
+ CHSPEC_CHANNEL(pi->
+ radio_chanspec));
+
+ if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5)
+ pi->phynoise_state = 0;
+
+ if ((!pi->phycal_txpower) ||
+ ((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) {
+
+ if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi))
+ pi->phycal_txpower = pi->sh->now;
+ }
+
+ if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
+ || ASSOC_INPROG_PHY(pi)))
+ return;
+
+ if (ISNPHY(pi) && !pi->disable_percal && !delay_phy_cal) {
+
+ if ((pi->nphy_perical != PHY_PERICAL_DISABLE) &&
+ (pi->nphy_perical != PHY_PERICAL_MANUAL) &&
+ ((pi->sh->now - pi->nphy_perical_last) >=
+ pi->sh->glacial_timer))
+ wlc_phy_cal_perical((struct brcms_phy_pub *) pi,
+ PHY_PERICAL_WATCHDOG);
+
+ wlc_phy_txpwr_papd_cal_nphy(pi);
+ }
+
+ if (ISLCNPHY(pi)) {
+ if (pi->phy_forcecal ||
+ ((pi->sh->now - pi->phy_lastcal) >=
+ pi->sh->glacial_timer)) {
+ if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi)))
+ wlc_lcnphy_calib_modes(
+ pi,
+ LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
+ if (!
+ (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
+ || ASSOC_INPROG_PHY(pi)
+ || pi->carrier_suppr_disable
+ || pi->disable_percal))
+ wlc_lcnphy_calib_modes(pi,
+ PHY_PERICAL_WATCHDOG);
+ }
+ }
+}
+
+void wlc_phy_BSSinit(struct brcms_phy_pub *pih, bool bonlyap, int rssi)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+ uint i;
+ uint k;
+
+ for (i = 0; i < MA_WINDOW_SZ; i++)
+ pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff);
+ if (ISLCNPHY(pi)) {
+ for (i = 0; i < MA_WINDOW_SZ; i++)
+ pi->sh->phy_noise_window[i] =
+ PHY_NOISE_FIXED_VAL_LCNPHY;
+ }
+ pi->sh->phy_noise_index = 0;
+
+ for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) {
+ for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++)
+ pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY;
+ }
+ pi->nphy_noise_index = 0;
+}
+
+void
+wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag)
+{
+ *eps_imag = (epsilon >> 13);
+ if (*eps_imag > 0xfff)
+ *eps_imag -= 0x2000;
+
+ *eps_real = (epsilon & 0x1fff);
+ if (*eps_real > 0xfff)
+ *eps_real -= 0x2000;
+}
+
+void wlc_phy_cal_perical_mphase_reset(struct brcms_phy *pi)
+{
+ wlapi_del_timer(pi->phycal_timer);
+
+ pi->cal_type_override = PHY_PERICAL_AUTO;
+ pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE;
+ pi->mphase_txcal_cmdidx = 0;
+}
+
+static void
+wlc_phy_cal_perical_mphase_schedule(struct brcms_phy *pi, uint delay)
+{
+
+ if ((pi->nphy_perical != PHY_PERICAL_MPHASE) &&
+ (pi->nphy_perical != PHY_PERICAL_MANUAL))
+ return;
+
+ wlapi_del_timer(pi->phycal_timer);
+
+ pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
+ wlapi_add_timer(pi->phycal_timer, delay, 0);
+}
+
+void wlc_phy_cal_perical(struct brcms_phy_pub *pih, u8 reason)
+{
+ s16 nphy_currtemp = 0;
+ s16 delta_temp = 0;
+ bool do_periodic_cal = true;
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+
+ if (!ISNPHY(pi))
+ return;
+
+ if ((pi->nphy_perical == PHY_PERICAL_DISABLE) ||
+ (pi->nphy_perical == PHY_PERICAL_MANUAL))
+ return;
+
+ switch (reason) {
+ case PHY_PERICAL_DRIVERUP:
+ break;
+
+ case PHY_PERICAL_PHYINIT:
+ if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
+ if (PHY_PERICAL_MPHASE_PENDING(pi))
+ wlc_phy_cal_perical_mphase_reset(pi);
+
+ wlc_phy_cal_perical_mphase_schedule(
+ pi,
+ PHY_PERICAL_INIT_DELAY);
+ }
+ break;
+
+ case PHY_PERICAL_JOIN_BSS:
+ case PHY_PERICAL_START_IBSS:
+ case PHY_PERICAL_UP_BSS:
+ if ((pi->nphy_perical == PHY_PERICAL_MPHASE) &&
+ PHY_PERICAL_MPHASE_PENDING(pi))
+ wlc_phy_cal_perical_mphase_reset(pi);
+
+ pi->first_cal_after_assoc = true;
+
+ pi->cal_type_override = PHY_PERICAL_FULL;
+
+ if (pi->phycal_tempdelta)
+ pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi);
+
+ wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL);
+ break;
+
+ case PHY_PERICAL_WATCHDOG:
+ if (pi->phycal_tempdelta) {
+ nphy_currtemp = wlc_phy_tempsense_nphy(pi);
+ delta_temp =
+ (nphy_currtemp > pi->nphy_lastcal_temp) ?
+ nphy_currtemp - pi->nphy_lastcal_temp :
+ pi->nphy_lastcal_temp - nphy_currtemp;
+
+ if ((delta_temp < (s16) pi->phycal_tempdelta) &&
+ (pi->nphy_txiqlocal_chanspec ==
+ pi->radio_chanspec))
+ do_periodic_cal = false;
+ else
+ pi->nphy_lastcal_temp = nphy_currtemp;
+ }
+
+ if (do_periodic_cal) {
+ if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
+ if (!PHY_PERICAL_MPHASE_PENDING(pi))
+ wlc_phy_cal_perical_mphase_schedule(
+ pi,
+ PHY_PERICAL_WDOG_DELAY);
+ } else if (pi->nphy_perical == PHY_PERICAL_SPHASE)
+ wlc_phy_cal_perical_nphy_run(pi,
+ PHY_PERICAL_AUTO);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void wlc_phy_cal_perical_mphase_restart(struct brcms_phy *pi)
+{
+ pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
+ pi->mphase_txcal_cmdidx = 0;
+}
+
+u8 wlc_phy_nbits(s32 value)
+{
+ s32 abs_val;
+ u8 nbits = 0;
+
+ abs_val = abs(value);
+ while ((abs_val >> nbits) > 0)
+ nbits++;
+
+ return nbits;
+}
+
+void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+
+ pi->sh->hw_phytxchain = txchain;
+ pi->sh->hw_phyrxchain = rxchain;
+ pi->sh->phytxchain = txchain;
+ pi->sh->phyrxchain = rxchain;
+ pi->pubpi.phy_corenum = (u8)hweight8(pi->sh->phyrxchain);
+}
+
+void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+
+ pi->sh->phytxchain = txchain;
+
+ if (ISNPHY(pi))
+ wlc_phy_rxcore_setstate_nphy(pih, rxchain);
+
+ pi->pubpi.phy_corenum = (u8)hweight8(pi->sh->phyrxchain);
+}
+
+void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain, u8 *rxchain)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+
+ *txchain = pi->sh->phytxchain;
+ *rxchain = pi->sh->phyrxchain;
+}
+
+u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih)
+{
+ s16 nphy_currtemp;
+ u8 active_bitmap;
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+
+ active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33;
+
+ if (!pi->watchdog_override)
+ return active_bitmap;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 6)) {
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+ nphy_currtemp = wlc_phy_tempsense_nphy(pi);
+ wlapi_enable_mac(pi->sh->physhim);
+
+ if (!pi->phy_txcore_heatedup) {
+ if (nphy_currtemp >= pi->phy_txcore_disable_temp) {
+ active_bitmap &= 0xFD;
+ pi->phy_txcore_heatedup = true;
+ }
+ } else {
+ if (nphy_currtemp <= pi->phy_txcore_enable_temp) {
+ active_bitmap |= 0x2;
+ pi->phy_txcore_heatedup = false;
+ }
+ }
+ }
+
+ return active_bitmap;
+}
+
+s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, u16 chanspec)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+ u8 siso_mcs_id, cdd_mcs_id;
+
+ siso_mcs_id =
+ (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO :
+ TXP_FIRST_MCS_20_SISO;
+ cdd_mcs_id =
+ (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD :
+ TXP_FIRST_MCS_20_CDD;
+
+ if (pi->tx_power_target[siso_mcs_id] >
+ (pi->tx_power_target[cdd_mcs_id] + 12))
+ return PHY_TXC1_MODE_SISO;
+ else
+ return PHY_TXC1_MODE_CDD;
+}
+
+const u8 *wlc_phy_get_ofdm_rate_lookup(void)
+{
+ return ofdm_rate_lookup;
+}
+
+void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode)
+{
+ if ((pi->sh->chip == BCM4313_CHIP_ID) &&
+ (pi->sh->boardflags & BFL_FEM)) {
+ if (mode) {
+ u16 txant = 0;
+ txant = wlapi_bmac_get_txant(pi->sh->physhim);
+ if (txant == 1) {
+ mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
+
+ mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2);
+
+ }
+ ai_corereg(pi->sh->sih, SI_CC_IDX,
+ offsetof(struct chipcregs, gpiocontrol),
+ ~0x0, 0x0);
+ ai_corereg(pi->sh->sih, SI_CC_IDX,
+ offsetof(struct chipcregs, gpioout), 0x40,
+ 0x40);
+ ai_corereg(pi->sh->sih, SI_CC_IDX,
+ offsetof(struct chipcregs, gpioouten), 0x40,
+ 0x40);
+ } else {
+ mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2);
+
+ mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2);
+
+ ai_corereg(pi->sh->sih, SI_CC_IDX,
+ offsetof(struct chipcregs, gpioout), 0x40,
+ 0x00);
+ ai_corereg(pi->sh->sih, SI_CC_IDX,
+ offsetof(struct chipcregs, gpioouten), 0x40,
+ 0x0);
+ ai_corereg(pi->sh->sih, SI_CC_IDX,
+ offsetof(struct chipcregs, gpiocontrol),
+ ~0x0, 0x40);
+ }
+ }
+}
+
+void wlc_phy_ldpc_override_set(struct brcms_phy_pub *ppi, bool ldpc)
+{
+ return;
+}
+
+void
+wlc_phy_get_pwrdet_offsets(struct brcms_phy *pi, s8 *cckoffset, s8 *ofdmoffset)
+{
+ *cckoffset = 0;
+ *ofdmoffset = 0;
+}
+
+s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi, u16 chanspec)
+{
+
+ return rssi;
+}
+
+bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *ppi)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+
+ if (ISNPHY(pi))
+ return wlc_phy_n_txpower_ipa_ison(pi);
+ else
+ return 0;
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_hal.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_hal.h
new file mode 100644
index 000000000000..96e15163222b
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_hal.h
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2010 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.
+ */
+
+/*
+ * phy_hal.h: functionality exported from the phy to higher layers
+ */
+
+#ifndef _BRCM_PHY_HAL_H_
+#define _BRCM_PHY_HAL_H_
+
+#include <brcmu_utils.h>
+#include <brcmu_wifi.h>
+#include <phy_shim.h>
+
+#define IDCODE_VER_MASK 0x0000000f
+#define IDCODE_VER_SHIFT 0
+#define IDCODE_MFG_MASK 0x00000fff
+#define IDCODE_MFG_SHIFT 0
+#define IDCODE_ID_MASK 0x0ffff000
+#define IDCODE_ID_SHIFT 12
+#define IDCODE_REV_MASK 0xf0000000
+#define IDCODE_REV_SHIFT 28
+
+#define NORADIO_ID 0xe4f5
+#define NORADIO_IDCODE 0x4e4f5246
+
+#define BCM2055_ID 0x2055
+#define BCM2055_IDCODE 0x02055000
+#define BCM2055A0_IDCODE 0x1205517f
+
+#define BCM2056_ID 0x2056
+#define BCM2056_IDCODE 0x02056000
+#define BCM2056A0_IDCODE 0x1205617f
+
+#define BCM2057_ID 0x2057
+#define BCM2057_IDCODE 0x02057000
+#define BCM2057A0_IDCODE 0x1205717f
+
+#define BCM2064_ID 0x2064
+#define BCM2064_IDCODE 0x02064000
+#define BCM2064A0_IDCODE 0x0206417f
+
+#define PHY_TPC_HW_OFF false
+#define PHY_TPC_HW_ON true
+
+#define PHY_PERICAL_DRIVERUP 1
+#define PHY_PERICAL_WATCHDOG 2
+#define PHY_PERICAL_PHYINIT 3
+#define PHY_PERICAL_JOIN_BSS 4
+#define PHY_PERICAL_START_IBSS 5
+#define PHY_PERICAL_UP_BSS 6
+#define PHY_PERICAL_CHAN 7
+#define PHY_FULLCAL 8
+
+#define PHY_PERICAL_DISABLE 0
+#define PHY_PERICAL_SPHASE 1
+#define PHY_PERICAL_MPHASE 2
+#define PHY_PERICAL_MANUAL 3
+
+#define PHY_HOLD_FOR_ASSOC 1
+#define PHY_HOLD_FOR_SCAN 2
+#define PHY_HOLD_FOR_RM 4
+#define PHY_HOLD_FOR_PLT 8
+#define PHY_HOLD_FOR_MUTE 16
+#define PHY_HOLD_FOR_NOT_ASSOC 0x20
+
+#define PHY_MUTE_FOR_PREISM 1
+#define PHY_MUTE_ALL 0xffffffff
+
+#define PHY_NOISE_FIXED_VAL (-95)
+#define PHY_NOISE_FIXED_VAL_NPHY (-92)
+#define PHY_NOISE_FIXED_VAL_LCNPHY (-92)
+
+#define PHY_MODE_CAL 0x0002
+#define PHY_MODE_NOISEM 0x0004
+
+#define BRCMS_TXPWR_DB_FACTOR 4
+
+/* a large TX Power as an init value to factor out of min() calculations,
+ * keep low enough to fit in an s8, units are .25 dBm
+ */
+#define BRCMS_TXPWR_MAX (127) /* ~32 dBm = 1,500 mW */
+
+#define BRCMS_NUM_RATES_CCK 4
+#define BRCMS_NUM_RATES_OFDM 8
+#define BRCMS_NUM_RATES_MCS_1_STREAM 8
+#define BRCMS_NUM_RATES_MCS_2_STREAM 8
+#define BRCMS_NUM_RATES_MCS_3_STREAM 8
+#define BRCMS_NUM_RATES_MCS_4_STREAM 8
+
+#define BRCMS_RSSI_INVALID 0 /* invalid RSSI value */
+
+struct d11regs;
+struct phy_shim_info;
+
+struct txpwr_limits {
+ u8 cck[BRCMS_NUM_RATES_CCK];
+ u8 ofdm[BRCMS_NUM_RATES_OFDM];
+
+ u8 ofdm_cdd[BRCMS_NUM_RATES_OFDM];
+
+ u8 ofdm_40_siso[BRCMS_NUM_RATES_OFDM];
+ u8 ofdm_40_cdd[BRCMS_NUM_RATES_OFDM];
+
+ u8 mcs_20_siso[BRCMS_NUM_RATES_MCS_1_STREAM];
+ u8 mcs_20_cdd[BRCMS_NUM_RATES_MCS_1_STREAM];
+ u8 mcs_20_stbc[BRCMS_NUM_RATES_MCS_1_STREAM];
+ u8 mcs_20_mimo[BRCMS_NUM_RATES_MCS_2_STREAM];
+
+ u8 mcs_40_siso[BRCMS_NUM_RATES_MCS_1_STREAM];
+ u8 mcs_40_cdd[BRCMS_NUM_RATES_MCS_1_STREAM];
+ u8 mcs_40_stbc[BRCMS_NUM_RATES_MCS_1_STREAM];
+ u8 mcs_40_mimo[BRCMS_NUM_RATES_MCS_2_STREAM];
+ u8 mcs32;
+};
+
+struct tx_power {
+ u32 flags;
+ u16 chanspec; /* txpwr report for this channel */
+ u16 local_chanspec; /* channel on which we are associated */
+ u8 local_max; /* local max according to the AP */
+ u8 local_constraint; /* local constraint according to the AP */
+ s8 antgain[2]; /* Ant gain for each band - from SROM */
+ u8 rf_cores; /* count of RF Cores being reported */
+ u8 est_Pout[4]; /* Latest tx power out estimate per RF chain */
+ u8 est_Pout_act[4]; /* Latest tx power out estimate per RF chain
+ * without adjustment */
+ u8 est_Pout_cck; /* Latest CCK tx power out estimate */
+ u8 tx_power_max[4]; /* Maximum target power among all rates */
+ /* Index of the rate with the max target power */
+ u8 tx_power_max_rate_ind[4];
+ /* User limit */
+ u8 user_limit[WL_TX_POWER_RATES];
+ /* Regulatory power limit */
+ u8 reg_limit[WL_TX_POWER_RATES];
+ /* Max power board can support (SROM) */
+ u8 board_limit[WL_TX_POWER_RATES];
+ /* Latest target power */
+ u8 target[WL_TX_POWER_RATES];
+};
+
+struct tx_inst_power {
+ u8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */
+ u8 txpwr_est_Pout_gofdm; /* Pwr estimate for 2.4 OFDM */
+};
+
+struct brcms_chanvec {
+ u8 vec[MAXCHANNEL / NBBY];
+};
+
+struct shared_phy_params {
+ struct si_pub *sih;
+ struct phy_shim_info *physhim;
+ uint unit;
+ uint corerev;
+ uint buscorerev;
+ u16 vid;
+ u16 did;
+ uint chip;
+ uint chiprev;
+ uint chippkg;
+ uint sromrev;
+ uint boardtype;
+ uint boardrev;
+ uint boardvendor;
+ u32 boardflags;
+ u32 boardflags2;
+};
+
+
+extern struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp);
+extern struct brcms_phy_pub *wlc_phy_attach(struct shared_phy *sh,
+ struct d11regs __iomem *regs,
+ int bandtype, struct wiphy *wiphy);
+extern void wlc_phy_detach(struct brcms_phy_pub *ppi);
+
+extern bool wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype,
+ u16 *phyrev, u16 *radioid,
+ u16 *radiover);
+extern bool wlc_phy_get_encore(struct brcms_phy_pub *pih);
+extern u32 wlc_phy_get_coreflags(struct brcms_phy_pub *pih);
+
+extern void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *ppi, bool newstate);
+extern void wlc_phy_hw_state_upd(struct brcms_phy_pub *ppi, bool newstate);
+extern void wlc_phy_init(struct brcms_phy_pub *ppi, u16 chanspec);
+extern void wlc_phy_watchdog(struct brcms_phy_pub *ppi);
+extern int wlc_phy_down(struct brcms_phy_pub *ppi);
+extern u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih);
+extern void wlc_phy_cal_init(struct brcms_phy_pub *ppi);
+extern void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init);
+
+extern void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi,
+ u16 chanspec);
+extern u16 wlc_phy_chanspec_get(struct brcms_phy_pub *ppi);
+extern void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi,
+ u16 newch);
+extern u16 wlc_phy_bw_state_get(struct brcms_phy_pub *ppi);
+extern void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw);
+
+extern int wlc_phy_rssi_compute(struct brcms_phy_pub *pih,
+ struct d11rxhdr *rxh);
+extern void wlc_phy_por_inform(struct brcms_phy_pub *ppi);
+extern void wlc_phy_noise_sample_intr(struct brcms_phy_pub *ppi);
+extern bool wlc_phy_bist_check_phy(struct brcms_phy_pub *ppi);
+
+extern void wlc_phy_set_deaf(struct brcms_phy_pub *ppi, bool user_flag);
+
+extern void wlc_phy_switch_radio(struct brcms_phy_pub *ppi, bool on);
+extern void wlc_phy_anacore(struct brcms_phy_pub *ppi, bool on);
+
+
+extern void wlc_phy_BSSinit(struct brcms_phy_pub *ppi, bool bonlyap, int rssi);
+
+extern void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi,
+ bool wide_filter);
+extern void wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band,
+ struct brcms_chanvec *channels);
+extern u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi,
+ uint band);
+
+extern void wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint chan,
+ u8 *_min_, u8 *_max_, int rate);
+extern void wlc_phy_txpower_sromlimit_max_get(struct brcms_phy_pub *ppi,
+ uint chan, u8 *_max_, u8 *_min_);
+extern void wlc_phy_txpower_boardlimit_band(struct brcms_phy_pub *ppi,
+ uint band, s32 *, s32 *, u32 *);
+extern void wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi,
+ struct txpwr_limits *,
+ u16 chanspec);
+extern int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm,
+ bool *override);
+extern int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm,
+ bool override);
+extern void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi,
+ struct txpwr_limits *);
+extern bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi);
+extern void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi,
+ bool hwpwrctrl);
+extern u8 wlc_phy_txpower_get_target_min(struct brcms_phy_pub *ppi);
+extern u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi);
+extern bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *pih);
+
+extern void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain,
+ u8 rxchain);
+extern void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain,
+ u8 rxchain);
+extern void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain,
+ u8 *rxchain);
+extern u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih);
+extern s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih,
+ u16 chanspec);
+extern void wlc_phy_ldpc_override_set(struct brcms_phy_pub *ppi, bool val);
+
+extern void wlc_phy_cal_perical(struct brcms_phy_pub *ppi, u8 reason);
+extern void wlc_phy_noise_sample_request_external(struct brcms_phy_pub *ppi);
+extern void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock);
+extern void wlc_phy_cal_papd_recal(struct brcms_phy_pub *ppi);
+
+extern void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val);
+extern void wlc_phy_clear_tssi(struct brcms_phy_pub *ppi);
+extern void wlc_phy_hold_upd(struct brcms_phy_pub *ppi, u32 id, bool val);
+extern void wlc_phy_mute_upd(struct brcms_phy_pub *ppi, bool val, u32 flags);
+
+extern void wlc_phy_antsel_type_set(struct brcms_phy_pub *ppi, u8 antsel_type);
+
+extern void wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi,
+ struct tx_power *power, uint channel);
+
+extern void wlc_phy_initcal_enable(struct brcms_phy_pub *pih, bool initcal);
+extern bool wlc_phy_test_ison(struct brcms_phy_pub *ppi);
+extern void wlc_phy_txpwr_percent_set(struct brcms_phy_pub *ppi,
+ u8 txpwr_percent);
+extern void wlc_phy_ofdm_rateset_war(struct brcms_phy_pub *pih, bool war);
+extern void wlc_phy_bf_preempt_enable(struct brcms_phy_pub *pih,
+ bool bf_preempt);
+extern void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap);
+
+extern void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end);
+
+extern void wlc_phy_freqtrack_start(struct brcms_phy_pub *ppi);
+extern void wlc_phy_freqtrack_end(struct brcms_phy_pub *ppi);
+
+extern const u8 *wlc_phy_get_ofdm_rate_lookup(void);
+
+extern s8 wlc_phy_get_tx_power_offset_by_mcs(struct brcms_phy_pub *ppi,
+ u8 mcs_offset);
+extern s8 wlc_phy_get_tx_power_offset(struct brcms_phy_pub *ppi, u8 tbl_offset);
+#endif /* _BRCM_PHY_HAL_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h
new file mode 100644
index 000000000000..bea85241a244
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h
@@ -0,0 +1,1169 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_PHY_INT_H_
+#define _BRCM_PHY_INT_H_
+
+#include <types.h>
+#include <brcmu_utils.h>
+#include <brcmu_wifi.h>
+
+#define PHY_VERSION { 1, 82, 8, 0 }
+
+#define LCNXN_BASEREV 16
+
+struct phy_shim_info;
+
+struct brcms_phy_srom_fem {
+ /* TSSI positive slope, 1: positive, 0: negative */
+ u8 tssipos;
+ /* Ext PA gain-type: full-gain: 0, pa-lite: 1, no_pa: 2 */
+ u8 extpagain;
+ /* support 32 combinations of different Pdet dynamic ranges */
+ u8 pdetrange;
+ /* TR switch isolation */
+ u8 triso;
+ /* antswctrl lookup table configuration: 32 possible choices */
+ u8 antswctrllut;
+};
+
+#define ISNPHY(pi) PHYTYPE_IS((pi)->pubpi.phy_type, PHY_TYPE_N)
+#define ISLCNPHY(pi) PHYTYPE_IS((pi)->pubpi.phy_type, PHY_TYPE_LCN)
+
+#define PHY_GET_RFATTN(rfgain) ((rfgain) & 0x0f)
+#define PHY_GET_PADMIX(rfgain) (((rfgain) & 0x10) >> 4)
+#define PHY_GET_RFGAINID(rfattn, padmix, width) ((rfattn) + ((padmix)*(width)))
+#define PHY_SAT(x, n) ((x) > ((1<<((n)-1))-1) ? ((1<<((n)-1))-1) : \
+ ((x) < -(1<<((n)-1)) ? -(1<<((n)-1)) : (x)))
+#define PHY_SHIFT_ROUND(x, n) ((x) >= 0 ? ((x)+(1<<((n)-1)))>>(n) : (x)>>(n))
+#define PHY_HW_ROUND(x, s) ((x >> s) + ((x >> (s-1)) & (s != 0)))
+
+#define CH_5G_GROUP 3
+#define A_LOW_CHANS 0
+#define A_MID_CHANS 1
+#define A_HIGH_CHANS 2
+#define CH_2G_GROUP 1
+#define G_ALL_CHANS 0
+
+#define FIRST_REF5_CHANNUM 149
+#define LAST_REF5_CHANNUM 165
+#define FIRST_5G_CHAN 14
+#define LAST_5G_CHAN 50
+#define FIRST_MID_5G_CHAN 14
+#define LAST_MID_5G_CHAN 35
+#define FIRST_HIGH_5G_CHAN 36
+#define LAST_HIGH_5G_CHAN 41
+#define FIRST_LOW_5G_CHAN 42
+#define LAST_LOW_5G_CHAN 50
+
+#define BASE_LOW_5G_CHAN 4900
+#define BASE_MID_5G_CHAN 5100
+#define BASE_HIGH_5G_CHAN 5500
+
+#define CHAN5G_FREQ(chan) (5000 + chan*5)
+#define CHAN2G_FREQ(chan) (2407 + chan*5)
+
+#define TXP_FIRST_CCK 0
+#define TXP_LAST_CCK 3
+#define TXP_FIRST_OFDM 4
+#define TXP_LAST_OFDM 11
+#define TXP_FIRST_OFDM_20_CDD 12
+#define TXP_LAST_OFDM_20_CDD 19
+#define TXP_FIRST_MCS_20_SISO 20
+#define TXP_LAST_MCS_20_SISO 27
+#define TXP_FIRST_MCS_20_CDD 28
+#define TXP_LAST_MCS_20_CDD 35
+#define TXP_FIRST_MCS_20_STBC 36
+#define TXP_LAST_MCS_20_STBC 43
+#define TXP_FIRST_MCS_20_SDM 44
+#define TXP_LAST_MCS_20_SDM 51
+#define TXP_FIRST_OFDM_40_SISO 52
+#define TXP_LAST_OFDM_40_SISO 59
+#define TXP_FIRST_OFDM_40_CDD 60
+#define TXP_LAST_OFDM_40_CDD 67
+#define TXP_FIRST_MCS_40_SISO 68
+#define TXP_LAST_MCS_40_SISO 75
+#define TXP_FIRST_MCS_40_CDD 76
+#define TXP_LAST_MCS_40_CDD 83
+#define TXP_FIRST_MCS_40_STBC 84
+#define TXP_LAST_MCS_40_STBC 91
+#define TXP_FIRST_MCS_40_SDM 92
+#define TXP_LAST_MCS_40_SDM 99
+#define TXP_MCS_32 100
+#define TXP_NUM_RATES 101
+#define ADJ_PWR_TBL_LEN 84
+
+#define TXP_FIRST_SISO_MCS_20 20
+#define TXP_LAST_SISO_MCS_20 27
+
+#define PHY_CORE_NUM_1 1
+#define PHY_CORE_NUM_2 2
+#define PHY_CORE_NUM_3 3
+#define PHY_CORE_NUM_4 4
+#define PHY_CORE_MAX PHY_CORE_NUM_4
+#define PHY_CORE_0 0
+#define PHY_CORE_1 1
+#define PHY_CORE_2 2
+#define PHY_CORE_3 3
+
+#define MA_WINDOW_SZ 8
+
+#define PHY_NOISE_SAMPLE_MON 1
+#define PHY_NOISE_SAMPLE_EXTERNAL 2
+#define PHY_NOISE_WINDOW_SZ 16
+#define PHY_NOISE_GLITCH_INIT_MA 10
+#define PHY_NOISE_GLITCH_INIT_MA_BADPlCP 10
+#define PHY_NOISE_STATE_MON 0x1
+#define PHY_NOISE_STATE_EXTERNAL 0x2
+#define PHY_NOISE_SAMPLE_LOG_NUM_NPHY 10
+#define PHY_NOISE_SAMPLE_LOG_NUM_UCODE 9
+
+#define PHY_NOISE_OFFSETFACT_4322 (-103)
+#define PHY_NOISE_MA_WINDOW_SZ 2
+
+#define PHY_RSSI_TABLE_SIZE 64
+#define RSSI_ANT_MERGE_MAX 0
+#define RSSI_ANT_MERGE_MIN 1
+#define RSSI_ANT_MERGE_AVG 2
+
+#define PHY_TSSI_TABLE_SIZE 64
+#define APHY_TSSI_TABLE_SIZE 256
+#define TX_GAIN_TABLE_LENGTH 64
+#define DEFAULT_11A_TXP_IDX 24
+#define NUM_TSSI_FRAMES 4
+#define NULL_TSSI 0x7f
+#define NULL_TSSI_W 0x7f7f
+
+#define PHY_PAPD_EPS_TBL_SIZE_LCNPHY 64
+
+#define LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL 9
+
+#define PHY_TXPWR_MIN 10
+#define PHY_TXPWR_MIN_NPHY 8
+#define RADIOPWR_OVERRIDE_DEF (-1)
+
+#define PWRTBL_NUM_COEFF 3
+
+#define SPURAVOID_DISABLE 0
+#define SPURAVOID_AUTO 1
+#define SPURAVOID_FORCEON 2
+#define SPURAVOID_FORCEON2 3
+
+#define PHY_SW_TIMER_FAST 15
+#define PHY_SW_TIMER_SLOW 60
+#define PHY_SW_TIMER_GLACIAL 120
+
+#define PHY_PERICAL_AUTO 0
+#define PHY_PERICAL_FULL 1
+#define PHY_PERICAL_PARTIAL 2
+
+#define PHY_PERICAL_NODELAY 0
+#define PHY_PERICAL_INIT_DELAY 5
+#define PHY_PERICAL_ASSOC_DELAY 5
+#define PHY_PERICAL_WDOG_DELAY 5
+
+#define MPHASE_TXCAL_NUMCMDS 2
+
+#define PHY_PERICAL_MPHASE_PENDING(pi) \
+ (pi->mphase_cal_phase_id > MPHASE_CAL_STATE_IDLE)
+
+enum {
+ MPHASE_CAL_STATE_IDLE = 0,
+ MPHASE_CAL_STATE_INIT = 1,
+ MPHASE_CAL_STATE_TXPHASE0,
+ MPHASE_CAL_STATE_TXPHASE1,
+ MPHASE_CAL_STATE_TXPHASE2,
+ MPHASE_CAL_STATE_TXPHASE3,
+ MPHASE_CAL_STATE_TXPHASE4,
+ MPHASE_CAL_STATE_TXPHASE5,
+ MPHASE_CAL_STATE_PAPDCAL,
+ MPHASE_CAL_STATE_RXCAL,
+ MPHASE_CAL_STATE_RSSICAL,
+ MPHASE_CAL_STATE_IDLETSSI
+};
+
+enum phy_cal_mode {
+ CAL_FULL,
+ CAL_RECAL,
+ CAL_CURRECAL,
+ CAL_DIGCAL,
+ CAL_GCTRL,
+ CAL_SOFT,
+ CAL_DIGLO
+};
+
+#define RDR_NTIERS 1
+#define RDR_TIER_SIZE 64
+#define RDR_LIST_SIZE (512/3)
+#define RDR_EPOCH_SIZE 40
+#define RDR_NANTENNAS 2
+#define RDR_NTIER_SIZE RDR_LIST_SIZE
+#define RDR_LP_BUFFER_SIZE 64
+#define LP_LEN_HIS_SIZE 10
+
+#define STATIC_NUM_RF 32
+#define STATIC_NUM_BB 9
+
+#define BB_MULT_MASK 0x0000ffff
+#define BB_MULT_VALID_MASK 0x80000000
+
+#define CORDIC_AG 39797
+#define CORDIC_NI 18
+#define FIXED(X) ((s32)((X) << 16))
+
+#define FLOAT(X) \
+ (((X) >= 0) ? ((((X) >> 15) + 1) >> 1) : -((((-(X)) >> 15) + 1) >> 1))
+
+#define PHY_CHAIN_TX_DISABLE_TEMP 115
+#define PHY_HYSTERESIS_DELTATEMP 5
+
+#define SCAN_INPROG_PHY(pi) \
+ (mboolisset(pi->measure_hold, PHY_HOLD_FOR_SCAN))
+
+#define PLT_INPROG_PHY(pi) (mboolisset(pi->measure_hold, PHY_HOLD_FOR_PLT))
+
+#define ASSOC_INPROG_PHY(pi) \
+ (mboolisset(pi->measure_hold, PHY_HOLD_FOR_ASSOC))
+
+#define SCAN_RM_IN_PROGRESS(pi) \
+ (mboolisset(pi->measure_hold, PHY_HOLD_FOR_SCAN | PHY_HOLD_FOR_RM))
+
+#define PHY_MUTED(pi) \
+ (mboolisset(pi->measure_hold, PHY_HOLD_FOR_MUTE))
+
+#define PUB_NOT_ASSOC(pi) \
+ (mboolisset(pi->measure_hold, PHY_HOLD_FOR_NOT_ASSOC))
+
+struct phy_table_info {
+ uint table;
+ int q;
+ uint max;
+};
+
+struct phytbl_info {
+ const void *tbl_ptr;
+ u32 tbl_len;
+ u32 tbl_id;
+ u32 tbl_offset;
+ u32 tbl_width;
+};
+
+struct interference_info {
+ u8 curr_home_channel;
+ u16 crsminpwrthld_40_stored;
+ u16 crsminpwrthld_20L_stored;
+ u16 crsminpwrthld_20U_stored;
+ u16 init_gain_code_core1_stored;
+ u16 init_gain_code_core2_stored;
+ u16 init_gain_codeb_core1_stored;
+ u16 init_gain_codeb_core2_stored;
+ u16 init_gain_table_stored[4];
+
+ u16 clip1_hi_gain_code_core1_stored;
+ u16 clip1_hi_gain_code_core2_stored;
+ u16 clip1_hi_gain_codeb_core1_stored;
+ u16 clip1_hi_gain_codeb_core2_stored;
+ u16 nb_clip_thresh_core1_stored;
+ u16 nb_clip_thresh_core2_stored;
+ u16 init_ofdmlna2gainchange_stored[4];
+ u16 init_ccklna2gainchange_stored[4];
+ u16 clip1_lo_gain_code_core1_stored;
+ u16 clip1_lo_gain_code_core2_stored;
+ u16 clip1_lo_gain_codeb_core1_stored;
+ u16 clip1_lo_gain_codeb_core2_stored;
+ u16 w1_clip_thresh_core1_stored;
+ u16 w1_clip_thresh_core2_stored;
+ u16 radio_2056_core1_rssi_gain_stored;
+ u16 radio_2056_core2_rssi_gain_stored;
+ u16 energy_drop_timeout_len_stored;
+
+ u16 ed_crs40_assertthld0_stored;
+ u16 ed_crs40_assertthld1_stored;
+ u16 ed_crs40_deassertthld0_stored;
+ u16 ed_crs40_deassertthld1_stored;
+ u16 ed_crs20L_assertthld0_stored;
+ u16 ed_crs20L_assertthld1_stored;
+ u16 ed_crs20L_deassertthld0_stored;
+ u16 ed_crs20L_deassertthld1_stored;
+ u16 ed_crs20U_assertthld0_stored;
+ u16 ed_crs20U_assertthld1_stored;
+ u16 ed_crs20U_deassertthld0_stored;
+ u16 ed_crs20U_deassertthld1_stored;
+
+ u16 badplcp_ma;
+ u16 badplcp_ma_previous;
+ u16 badplcp_ma_total;
+ u16 badplcp_ma_list[MA_WINDOW_SZ];
+ int badplcp_ma_index;
+ s16 pre_badplcp_cnt;
+ s16 bphy_pre_badplcp_cnt;
+
+ u16 init_gain_core1;
+ u16 init_gain_core2;
+ u16 init_gainb_core1;
+ u16 init_gainb_core2;
+ u16 init_gain_rfseq[4];
+
+ u16 crsminpwr0;
+ u16 crsminpwrl0;
+ u16 crsminpwru0;
+
+ s16 crsminpwr_index;
+
+ u16 radio_2057_core1_rssi_wb1a_gc_stored;
+ u16 radio_2057_core2_rssi_wb1a_gc_stored;
+ u16 radio_2057_core1_rssi_wb1g_gc_stored;
+ u16 radio_2057_core2_rssi_wb1g_gc_stored;
+ u16 radio_2057_core1_rssi_wb2_gc_stored;
+ u16 radio_2057_core2_rssi_wb2_gc_stored;
+ u16 radio_2057_core1_rssi_nb_gc_stored;
+ u16 radio_2057_core2_rssi_nb_gc_stored;
+};
+
+struct aci_save_gphy {
+ u16 rc_cal_ovr;
+ u16 phycrsth1;
+ u16 phycrsth2;
+ u16 init_n1p1_gain;
+ u16 p1_p2_gain;
+ u16 n1_n2_gain;
+ u16 n1_p1_gain;
+ u16 div_search_gain;
+ u16 div_p1_p2_gain;
+ u16 div_search_gn_change;
+ u16 table_7_2;
+ u16 table_7_3;
+ u16 cckshbits_gnref;
+ u16 clip_thresh;
+ u16 clip2_thresh;
+ u16 clip3_thresh;
+ u16 clip_p2_thresh;
+ u16 clip_pwdn_thresh;
+ u16 clip_n1p1_thresh;
+ u16 clip_n1_pwdn_thresh;
+ u16 bbconfig;
+ u16 cthr_sthr_shdin;
+ u16 energy;
+ u16 clip_p1_p2_thresh;
+ u16 threshold;
+ u16 reg15;
+ u16 reg16;
+ u16 reg17;
+ u16 div_srch_idx;
+ u16 div_srch_p1_p2;
+ u16 div_srch_gn_back;
+ u16 ant_dwell;
+ u16 ant_wr_settle;
+};
+
+struct lo_complex_abgphy_info {
+ s8 i;
+ s8 q;
+};
+
+struct nphy_iq_comp {
+ s16 a0;
+ s16 b0;
+ s16 a1;
+ s16 b1;
+};
+
+struct nphy_txpwrindex {
+ s8 index;
+ s8 index_internal;
+ s8 index_internal_save;
+ u16 AfectrlOverride;
+ u16 AfeCtrlDacGain;
+ u16 rad_gain;
+ u8 bbmult;
+ u16 iqcomp_a;
+ u16 iqcomp_b;
+ u16 locomp;
+};
+
+struct txiqcal_cache {
+
+ u16 txcal_coeffs_2G[8];
+ u16 txcal_radio_regs_2G[8];
+ struct nphy_iq_comp rxcal_coeffs_2G;
+
+ u16 txcal_coeffs_5G[8];
+ u16 txcal_radio_regs_5G[8];
+ struct nphy_iq_comp rxcal_coeffs_5G;
+};
+
+struct nphy_pwrctrl {
+ s8 max_pwr_2g;
+ s8 idle_targ_2g;
+ s16 pwrdet_2g_a1;
+ s16 pwrdet_2g_b0;
+ s16 pwrdet_2g_b1;
+ s8 max_pwr_5gm;
+ s8 idle_targ_5gm;
+ s8 max_pwr_5gh;
+ s8 max_pwr_5gl;
+ s16 pwrdet_5gm_a1;
+ s16 pwrdet_5gm_b0;
+ s16 pwrdet_5gm_b1;
+ s16 pwrdet_5gl_a1;
+ s16 pwrdet_5gl_b0;
+ s16 pwrdet_5gl_b1;
+ s16 pwrdet_5gh_a1;
+ s16 pwrdet_5gh_b0;
+ s16 pwrdet_5gh_b1;
+ s8 idle_targ_5gl;
+ s8 idle_targ_5gh;
+ s8 idle_tssi_2g;
+ s8 idle_tssi_5g;
+ s8 idle_tssi;
+ s16 a1;
+ s16 b0;
+ s16 b1;
+};
+
+struct nphy_txgains {
+ u16 txlpf[2];
+ u16 txgm[2];
+ u16 pga[2];
+ u16 pad[2];
+ u16 ipa[2];
+};
+
+#define PHY_NOISEVAR_BUFSIZE 10
+
+struct nphy_noisevar_buf {
+ int bufcount;
+ int tone_id[PHY_NOISEVAR_BUFSIZE];
+ u32 noise_vars[PHY_NOISEVAR_BUFSIZE];
+ u32 min_noise_vars[PHY_NOISEVAR_BUFSIZE];
+};
+
+struct rssical_cache {
+ u16 rssical_radio_regs_2G[2];
+ u16 rssical_phyregs_2G[12];
+
+ u16 rssical_radio_regs_5G[2];
+ u16 rssical_phyregs_5G[12];
+};
+
+struct lcnphy_cal_results {
+
+ u16 txiqlocal_a;
+ u16 txiqlocal_b;
+ u16 txiqlocal_didq;
+ u8 txiqlocal_ei0;
+ u8 txiqlocal_eq0;
+ u8 txiqlocal_fi0;
+ u8 txiqlocal_fq0;
+
+ u16 txiqlocal_bestcoeffs[11];
+ u16 txiqlocal_bestcoeffs_valid;
+
+ u32 papd_eps_tbl[PHY_PAPD_EPS_TBL_SIZE_LCNPHY];
+ u16 analog_gain_ref;
+ u16 lut_begin;
+ u16 lut_end;
+ u16 lut_step;
+ u16 rxcompdbm;
+ u16 papdctrl;
+ u16 sslpnCalibClkEnCtrl;
+
+ u16 rxiqcal_coeff_a0;
+ u16 rxiqcal_coeff_b0;
+};
+
+struct shared_phy {
+ struct brcms_phy *phy_head;
+ uint unit;
+ struct si_pub *sih;
+ struct phy_shim_info *physhim;
+ uint corerev;
+ u32 machwcap;
+ bool up;
+ bool clk;
+ uint now;
+ u16 vid;
+ u16 did;
+ uint chip;
+ uint chiprev;
+ uint chippkg;
+ uint sromrev;
+ uint boardtype;
+ uint boardrev;
+ uint boardvendor;
+ u32 boardflags;
+ u32 boardflags2;
+ uint buscorerev;
+ uint fast_timer;
+ uint slow_timer;
+ uint glacial_timer;
+ u8 rx_antdiv;
+ s8 phy_noise_window[MA_WINDOW_SZ];
+ uint phy_noise_index;
+ u8 hw_phytxchain;
+ u8 hw_phyrxchain;
+ u8 phytxchain;
+ u8 phyrxchain;
+ u8 rssi_mode;
+ bool _rifs_phy;
+};
+
+struct brcms_phy_pub {
+ uint phy_type;
+ uint phy_rev;
+ u8 phy_corenum;
+ u16 radioid;
+ u8 radiorev;
+ u8 radiover;
+
+ uint coreflags;
+ uint ana_rev;
+ bool abgphy_encore;
+};
+
+struct phy_func_ptr {
+ void (*init)(struct brcms_phy *);
+ void (*calinit)(struct brcms_phy *);
+ void (*chanset)(struct brcms_phy *, u16 chanspec);
+ void (*txpwrrecalc)(struct brcms_phy *);
+ int (*longtrn)(struct brcms_phy *, int);
+ void (*txiqccget)(struct brcms_phy *, u16 *, u16 *);
+ void (*txiqccset)(struct brcms_phy *, u16, u16);
+ u16 (*txloccget)(struct brcms_phy *);
+ void (*radioloftget)(struct brcms_phy *, u8 *, u8 *, u8 *, u8 *);
+ void (*carrsuppr)(struct brcms_phy *);
+ s32 (*rxsigpwr)(struct brcms_phy *, s32);
+ void (*detach)(struct brcms_phy *);
+};
+
+struct brcms_phy {
+ struct brcms_phy_pub pubpi_ro;
+ struct shared_phy *sh;
+ struct phy_func_ptr pi_fptr;
+
+ union {
+ struct brcms_phy_lcnphy *pi_lcnphy;
+ } u;
+ bool user_txpwr_at_rfport;
+
+ struct d11regs __iomem *regs;
+ struct brcms_phy *next;
+ struct brcms_phy_pub pubpi;
+
+ bool do_initcal;
+ bool phytest_on;
+ bool ofdm_rateset_war;
+ bool bf_preempt_4306;
+ u16 radio_chanspec;
+ u8 antsel_type;
+ u16 bw;
+ u8 txpwr_percent;
+ bool phy_init_por;
+
+ bool init_in_progress;
+ bool initialized;
+ bool sbtml_gm;
+ uint refcnt;
+ bool watchdog_override;
+ u8 phynoise_state;
+ uint phynoise_now;
+ int phynoise_chan_watchdog;
+ bool phynoise_polling;
+ bool disable_percal;
+ u32 measure_hold;
+
+ s16 txpa_2g[PWRTBL_NUM_COEFF];
+ s16 txpa_2g_low_temp[PWRTBL_NUM_COEFF];
+ s16 txpa_2g_high_temp[PWRTBL_NUM_COEFF];
+ s16 txpa_5g_low[PWRTBL_NUM_COEFF];
+ s16 txpa_5g_mid[PWRTBL_NUM_COEFF];
+ s16 txpa_5g_hi[PWRTBL_NUM_COEFF];
+
+ u8 tx_srom_max_2g;
+ u8 tx_srom_max_5g_low;
+ u8 tx_srom_max_5g_mid;
+ u8 tx_srom_max_5g_hi;
+ u8 tx_srom_max_rate_2g[TXP_NUM_RATES];
+ u8 tx_srom_max_rate_5g_low[TXP_NUM_RATES];
+ u8 tx_srom_max_rate_5g_mid[TXP_NUM_RATES];
+ u8 tx_srom_max_rate_5g_hi[TXP_NUM_RATES];
+ u8 tx_user_target[TXP_NUM_RATES];
+ s8 tx_power_offset[TXP_NUM_RATES];
+ u8 tx_power_target[TXP_NUM_RATES];
+
+ struct brcms_phy_srom_fem srom_fem2g;
+ struct brcms_phy_srom_fem srom_fem5g;
+
+ u8 tx_power_max;
+ u8 tx_power_max_rate_ind;
+ bool hwpwrctrl;
+ u8 nphy_txpwrctrl;
+ s8 nphy_txrx_chain;
+ bool phy_5g_pwrgain;
+
+ u16 phy_wreg;
+ u16 phy_wreg_limit;
+
+ s8 n_preamble_override;
+ u8 antswitch;
+ u8 aa2g, aa5g;
+
+ s8 idle_tssi[CH_5G_GROUP];
+ s8 target_idle_tssi;
+ s8 txpwr_est_Pout;
+ u8 tx_power_min;
+ u8 txpwr_limit[TXP_NUM_RATES];
+ u8 txpwr_env_limit[TXP_NUM_RATES];
+ u8 adj_pwr_tbl_nphy[ADJ_PWR_TBL_LEN];
+
+ bool channel_14_wide_filter;
+
+ bool txpwroverride;
+ bool txpwridx_override_aphy;
+ s16 radiopwr_override;
+ u16 hwpwr_txcur;
+ u8 saved_txpwr_idx;
+
+ bool edcrs_threshold_lock;
+
+ u32 tr_R_gain_val;
+ u32 tr_T_gain_val;
+
+ s16 ofdm_analog_filt_bw_override;
+ s16 cck_analog_filt_bw_override;
+ s16 ofdm_rccal_override;
+ s16 cck_rccal_override;
+ u16 extlna_type;
+
+ uint interference_mode_crs_time;
+ u16 crsglitch_prev;
+ bool interference_mode_crs;
+
+ u32 phy_tx_tone_freq;
+ uint phy_lastcal;
+ bool phy_forcecal;
+ bool phy_fixed_noise;
+ u32 xtalfreq;
+ u8 pdiv;
+ s8 carrier_suppr_disable;
+
+ bool phy_bphy_evm;
+ bool phy_bphy_rfcs;
+ s8 phy_scraminit;
+ u8 phy_gpiosel;
+
+ s16 phy_txcore_disable_temp;
+ s16 phy_txcore_enable_temp;
+ s8 phy_tempsense_offset;
+ bool phy_txcore_heatedup;
+
+ u16 radiopwr;
+ u16 bb_atten;
+ u16 txctl1;
+
+ u16 mintxbias;
+ u16 mintxmag;
+ struct lo_complex_abgphy_info gphy_locomp_iq
+ [STATIC_NUM_RF][STATIC_NUM_BB];
+ s8 stats_11b_txpower[STATIC_NUM_RF][STATIC_NUM_BB];
+ u16 gain_table[TX_GAIN_TABLE_LENGTH];
+ bool loopback_gain;
+ s16 max_lpback_gain_hdB;
+ s16 trsw_rx_gain_hdB;
+ u8 power_vec[8];
+
+ u16 rc_cal;
+ int nrssi_table_delta;
+ int nrssi_slope_scale;
+ int nrssi_slope_offset;
+ int min_rssi;
+ int max_rssi;
+
+ s8 txpwridx;
+ u8 min_txpower;
+
+ u8 a_band_high_disable;
+
+ u16 tx_vos;
+ u16 global_tx_bb_dc_bias_loft;
+
+ int rf_max;
+ int bb_max;
+ int rf_list_size;
+ int bb_list_size;
+ u16 *rf_attn_list;
+ u16 *bb_attn_list;
+ u16 padmix_mask;
+ u16 padmix_reg;
+ u16 *txmag_list;
+ uint txmag_len;
+ bool txmag_enable;
+
+ s8 *a_tssi_to_dbm;
+ s8 *m_tssi_to_dbm;
+ s8 *l_tssi_to_dbm;
+ s8 *h_tssi_to_dbm;
+ u8 *hwtxpwr;
+
+ u16 freqtrack_saved_regs[2];
+ int cur_interference_mode;
+ bool hwpwrctrl_capable;
+ bool temppwrctrl_capable;
+
+ uint phycal_nslope;
+ uint phycal_noffset;
+ uint phycal_mlo;
+ uint phycal_txpower;
+
+ u8 phy_aa2g;
+
+ bool nphy_tableloaded;
+ s8 nphy_rssisel;
+ u32 nphy_bb_mult_save;
+ u16 nphy_txiqlocal_bestc[11];
+ bool nphy_txiqlocal_coeffsvalid;
+ struct nphy_txpwrindex nphy_txpwrindex[PHY_CORE_NUM_2];
+ struct nphy_pwrctrl nphy_pwrctrl_info[PHY_CORE_NUM_2];
+ u16 cck2gpo;
+ u32 ofdm2gpo;
+ u32 ofdm5gpo;
+ u32 ofdm5glpo;
+ u32 ofdm5ghpo;
+ u8 bw402gpo;
+ u8 bw405gpo;
+ u8 bw405glpo;
+ u8 bw405ghpo;
+ u8 cdd2gpo;
+ u8 cdd5gpo;
+ u8 cdd5glpo;
+ u8 cdd5ghpo;
+ u8 stbc2gpo;
+ u8 stbc5gpo;
+ u8 stbc5glpo;
+ u8 stbc5ghpo;
+ u8 bwdup2gpo;
+ u8 bwdup5gpo;
+ u8 bwdup5glpo;
+ u8 bwdup5ghpo;
+ u16 mcs2gpo[8];
+ u16 mcs5gpo[8];
+ u16 mcs5glpo[8];
+ u16 mcs5ghpo[8];
+ u32 nphy_rxcalparams;
+
+ u8 phy_spuravoid;
+ bool phy_isspuravoid;
+
+ u8 phy_pabias;
+ u8 nphy_papd_skip;
+ u8 nphy_tssi_slope;
+
+ s16 nphy_noise_win[PHY_CORE_MAX][PHY_NOISE_WINDOW_SZ];
+ u8 nphy_noise_index;
+
+ u8 nphy_txpid2g[PHY_CORE_NUM_2];
+ u8 nphy_txpid5g[PHY_CORE_NUM_2];
+ u8 nphy_txpid5gl[PHY_CORE_NUM_2];
+ u8 nphy_txpid5gh[PHY_CORE_NUM_2];
+
+ bool nphy_gain_boost;
+ bool nphy_elna_gain_config;
+ u16 old_bphy_test;
+ u16 old_bphy_testcontrol;
+
+ bool phyhang_avoid;
+
+ bool rssical_nphy;
+ u8 nphy_perical;
+ uint nphy_perical_last;
+ u8 cal_type_override;
+ u8 mphase_cal_phase_id;
+ u8 mphase_txcal_cmdidx;
+ u8 mphase_txcal_numcmds;
+ u16 mphase_txcal_bestcoeffs[11];
+ u16 nphy_txiqlocal_chanspec;
+ u16 nphy_iqcal_chanspec_2G;
+ u16 nphy_iqcal_chanspec_5G;
+ u16 nphy_rssical_chanspec_2G;
+ u16 nphy_rssical_chanspec_5G;
+ struct wlapi_timer *phycal_timer;
+ bool use_int_tx_iqlo_cal_nphy;
+ bool internal_tx_iqlo_cal_tapoff_intpa_nphy;
+ s16 nphy_lastcal_temp;
+
+ struct txiqcal_cache calibration_cache;
+ struct rssical_cache rssical_cache;
+
+ u8 nphy_txpwr_idx[2];
+ u8 nphy_papd_cal_type;
+ uint nphy_papd_last_cal;
+ u16 nphy_papd_tx_gain_at_last_cal[2];
+ u8 nphy_papd_cal_gain_index[2];
+ s16 nphy_papd_epsilon_offset[2];
+ bool nphy_papd_recal_enable;
+ u32 nphy_papd_recal_counter;
+ bool nphy_force_papd_cal;
+ bool nphy_papdcomp;
+ bool ipa2g_on;
+ bool ipa5g_on;
+
+ u16 classifier_state;
+ u16 clip_state[2];
+ uint nphy_deaf_count;
+ u8 rxiq_samps;
+ u8 rxiq_antsel;
+
+ u16 rfctrlIntc1_save;
+ u16 rfctrlIntc2_save;
+ bool first_cal_after_assoc;
+ u16 tx_rx_cal_radio_saveregs[22];
+ u16 tx_rx_cal_phy_saveregs[15];
+
+ u8 nphy_cal_orig_pwr_idx[2];
+ u8 nphy_txcal_pwr_idx[2];
+ u8 nphy_rxcal_pwr_idx[2];
+ u16 nphy_cal_orig_tx_gain[2];
+ struct nphy_txgains nphy_cal_target_gain;
+ u16 nphy_txcal_bbmult;
+ u16 nphy_gmval;
+
+ u16 nphy_saved_bbconf;
+
+ bool nphy_gband_spurwar_en;
+ bool nphy_gband_spurwar2_en;
+ bool nphy_aband_spurwar_en;
+ u16 nphy_rccal_value;
+ u16 nphy_crsminpwr[3];
+ struct nphy_noisevar_buf nphy_saved_noisevars;
+ bool nphy_anarxlpf_adjusted;
+ bool nphy_crsminpwr_adjusted;
+ bool nphy_noisevars_adjusted;
+
+ bool nphy_rxcal_active;
+ u16 radar_percal_mask;
+ bool dfs_lp_buffer_nphy;
+
+ u16 nphy_fineclockgatecontrol;
+
+ s8 rx2tx_biasentry;
+
+ u16 crsminpwr0;
+ u16 crsminpwrl0;
+ u16 crsminpwru0;
+ s16 noise_crsminpwr_index;
+ u16 init_gain_core1;
+ u16 init_gain_core2;
+ u16 init_gainb_core1;
+ u16 init_gainb_core2;
+ u8 aci_noise_curr_channel;
+ u16 init_gain_rfseq[4];
+
+ bool radio_is_on;
+
+ bool nphy_sample_play_lpf_bw_ctl_ovr;
+
+ u16 tbl_data_hi;
+ u16 tbl_data_lo;
+ u16 tbl_addr;
+
+ uint tbl_save_id;
+ uint tbl_save_offset;
+
+ u8 txpwrctrl;
+ s8 txpwrindex[PHY_CORE_MAX];
+
+ u8 phycal_tempdelta;
+ u32 mcs20_po;
+ u32 mcs40_po;
+ struct wiphy *wiphy;
+};
+
+struct cs32 {
+ s32 q;
+ s32 i;
+};
+
+struct radio_regs {
+ u16 address;
+ u32 init_a;
+ u32 init_g;
+ u8 do_init_a;
+ u8 do_init_g;
+};
+
+struct radio_20xx_regs {
+ u16 address;
+ u8 init;
+ u8 do_init;
+};
+
+struct lcnphy_radio_regs {
+ u16 address;
+ u8 init_a;
+ u8 init_g;
+ u8 do_init_a;
+ u8 do_init_g;
+};
+
+extern u16 read_phy_reg(struct brcms_phy *pi, u16 addr);
+extern void write_phy_reg(struct brcms_phy *pi, u16 addr, u16 val);
+extern void and_phy_reg(struct brcms_phy *pi, u16 addr, u16 val);
+extern void or_phy_reg(struct brcms_phy *pi, u16 addr, u16 val);
+extern void mod_phy_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val);
+
+extern u16 read_radio_reg(struct brcms_phy *pi, u16 addr);
+extern void or_radio_reg(struct brcms_phy *pi, u16 addr, u16 val);
+extern void and_radio_reg(struct brcms_phy *pi, u16 addr, u16 val);
+extern void mod_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask,
+ u16 val);
+extern void xor_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask);
+
+extern void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val);
+
+extern void wlc_phyreg_enter(struct brcms_phy_pub *pih);
+extern void wlc_phyreg_exit(struct brcms_phy_pub *pih);
+extern void wlc_radioreg_enter(struct brcms_phy_pub *pih);
+extern void wlc_radioreg_exit(struct brcms_phy_pub *pih);
+
+extern void wlc_phy_read_table(struct brcms_phy *pi,
+ const struct phytbl_info *ptbl_info,
+ u16 tblAddr, u16 tblDataHi,
+ u16 tblDatalo);
+extern void wlc_phy_write_table(struct brcms_phy *pi,
+ const struct phytbl_info *ptbl_info,
+ u16 tblAddr, u16 tblDataHi, u16 tblDatalo);
+extern void wlc_phy_table_addr(struct brcms_phy *pi, uint tbl_id,
+ uint tbl_offset, u16 tblAddr, u16 tblDataHi,
+ u16 tblDataLo);
+extern void wlc_phy_table_data_write(struct brcms_phy *pi, uint width, u32 val);
+
+extern void write_phy_channel_reg(struct brcms_phy *pi, uint val);
+extern void wlc_phy_txpower_update_shm(struct brcms_phy *pi);
+
+extern u8 wlc_phy_nbits(s32 value);
+extern void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_dB, u8 core);
+
+extern uint wlc_phy_init_radio_regs_allbands(struct brcms_phy *pi,
+ struct radio_20xx_regs *radioregs);
+extern uint wlc_phy_init_radio_regs(struct brcms_phy *pi,
+ const struct radio_regs *radioregs,
+ u16 core_offset);
+
+extern void wlc_phy_txpower_ipa_upd(struct brcms_phy *pi);
+
+extern void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on);
+extern void wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real,
+ s32 *eps_imag);
+
+extern void wlc_phy_cal_perical_mphase_reset(struct brcms_phy *pi);
+extern void wlc_phy_cal_perical_mphase_restart(struct brcms_phy *pi);
+
+extern bool wlc_phy_attach_nphy(struct brcms_phy *pi);
+extern bool wlc_phy_attach_lcnphy(struct brcms_phy *pi);
+
+extern void wlc_phy_detach_lcnphy(struct brcms_phy *pi);
+
+extern void wlc_phy_init_nphy(struct brcms_phy *pi);
+extern void wlc_phy_init_lcnphy(struct brcms_phy *pi);
+
+extern void wlc_phy_cal_init_nphy(struct brcms_phy *pi);
+extern void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi);
+
+extern void wlc_phy_chanspec_set_nphy(struct brcms_phy *pi,
+ u16 chanspec);
+extern void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi,
+ u16 chanspec);
+extern void wlc_phy_chanspec_set_fixup_lcnphy(struct brcms_phy *pi,
+ u16 chanspec);
+extern int wlc_phy_channel2freq(uint channel);
+extern int wlc_phy_chanspec_freq2bandrange_lpssn(uint);
+extern int wlc_phy_chanspec_bandrange_get(struct brcms_phy *, u16 chanspec);
+
+extern void wlc_lcnphy_set_tx_pwr_ctrl(struct brcms_phy *pi, u16 mode);
+extern s8 wlc_lcnphy_get_current_tx_pwr_idx(struct brcms_phy *pi);
+
+extern void wlc_phy_txpower_recalc_target_nphy(struct brcms_phy *pi);
+extern void wlc_lcnphy_txpower_recalc_target(struct brcms_phy *pi);
+extern void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi);
+
+extern void wlc_lcnphy_set_tx_pwr_by_index(struct brcms_phy *pi, int index);
+extern void wlc_lcnphy_tx_pu(struct brcms_phy *pi, bool bEnable);
+extern void wlc_lcnphy_stop_tx_tone(struct brcms_phy *pi);
+extern void wlc_lcnphy_start_tx_tone(struct brcms_phy *pi, s32 f_kHz,
+ u16 max_val, bool iqcalmode);
+
+extern void wlc_phy_txpower_sromlimit_get_nphy(struct brcms_phy *pi, uint chan,
+ u8 *max_pwr, u8 rate_id);
+extern void wlc_phy_ofdm_to_mcs_powers_nphy(u8 *power, u8 rate_mcs_start,
+ u8 rate_mcs_end,
+ u8 rate_ofdm_start);
+extern void wlc_phy_mcs_to_ofdm_powers_nphy(u8 *power,
+ u8 rate_ofdm_start,
+ u8 rate_ofdm_end,
+ u8 rate_mcs_start);
+
+extern u16 wlc_lcnphy_tempsense(struct brcms_phy *pi, bool mode);
+extern s16 wlc_lcnphy_tempsense_new(struct brcms_phy *pi, bool mode);
+extern s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode);
+extern s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode);
+extern void wlc_phy_carrier_suppress_lcnphy(struct brcms_phy *pi);
+extern void wlc_lcnphy_crsuprs(struct brcms_phy *pi, int channel);
+extern void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode);
+extern void wlc_2064_vco_cal(struct brcms_phy *pi);
+
+extern void wlc_phy_txpower_recalc_target(struct brcms_phy *pi);
+
+#define LCNPHY_TBL_ID_PAPDCOMPDELTATBL 0x18
+#define LCNPHY_TX_POWER_TABLE_SIZE 128
+#define LCNPHY_MAX_TX_POWER_INDEX (LCNPHY_TX_POWER_TABLE_SIZE - 1)
+#define LCNPHY_TBL_ID_TXPWRCTL 0x07
+#define LCNPHY_TX_PWR_CTRL_OFF 0
+#define LCNPHY_TX_PWR_CTRL_SW (0x1 << 15)
+#define LCNPHY_TX_PWR_CTRL_HW ((0x1 << 15) | \
+ (0x1 << 14) | \
+ (0x1 << 13))
+
+#define LCNPHY_TX_PWR_CTRL_TEMPBASED 0xE001
+
+extern void wlc_lcnphy_write_table(struct brcms_phy *pi,
+ const struct phytbl_info *pti);
+extern void wlc_lcnphy_read_table(struct brcms_phy *pi,
+ struct phytbl_info *pti);
+extern void wlc_lcnphy_set_tx_iqcc(struct brcms_phy *pi, u16 a, u16 b);
+extern void wlc_lcnphy_set_tx_locc(struct brcms_phy *pi, u16 didq);
+extern void wlc_lcnphy_get_tx_iqcc(struct brcms_phy *pi, u16 *a, u16 *b);
+extern u16 wlc_lcnphy_get_tx_locc(struct brcms_phy *pi);
+extern void wlc_lcnphy_get_radio_loft(struct brcms_phy *pi, u8 *ei0,
+ u8 *eq0, u8 *fi0, u8 *fq0);
+extern void wlc_lcnphy_calib_modes(struct brcms_phy *pi, uint mode);
+extern void wlc_lcnphy_deaf_mode(struct brcms_phy *pi, bool mode);
+extern bool wlc_phy_tpc_isenabled_lcnphy(struct brcms_phy *pi);
+extern void wlc_lcnphy_tx_pwr_update_npt(struct brcms_phy *pi);
+extern s32 wlc_lcnphy_tssi2dbm(s32 tssi, s32 a1, s32 b0, s32 b1);
+extern void wlc_lcnphy_get_tssi(struct brcms_phy *pi, s8 *ofdm_pwr,
+ s8 *cck_pwr);
+extern void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi);
+
+extern s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index);
+
+#define NPHY_MAX_HPVGA1_INDEX 10
+#define NPHY_DEF_HPVGA1_INDEXLIMIT 7
+
+struct phy_iq_est {
+ s32 iq_prod;
+ u32 i_pwr;
+ u32 q_pwr;
+};
+
+extern void wlc_phy_stay_in_carriersearch_nphy(struct brcms_phy *pi,
+ bool enable);
+extern void wlc_nphy_deaf_mode(struct brcms_phy *pi, bool mode);
+
+#define wlc_phy_write_table_nphy(pi, pti) \
+ wlc_phy_write_table(pi, pti, 0x72, 0x74, 0x73)
+
+#define wlc_phy_read_table_nphy(pi, pti) \
+ wlc_phy_read_table(pi, pti, 0x72, 0x74, 0x73)
+
+#define wlc_nphy_table_addr(pi, id, off) \
+ wlc_phy_table_addr((pi), (id), (off), 0x72, 0x74, 0x73)
+
+#define wlc_nphy_table_data_write(pi, w, v) \
+ wlc_phy_table_data_write((pi), (w), (v))
+
+extern void wlc_phy_table_read_nphy(struct brcms_phy *pi, u32, u32 l, u32 o,
+ u32 w, void *d);
+extern void wlc_phy_table_write_nphy(struct brcms_phy *pi, u32, u32, u32,
+ u32, const void *);
+
+#define PHY_IPA(pi) \
+ ((pi->ipa2g_on && CHSPEC_IS2G(pi->radio_chanspec)) || \
+ (pi->ipa5g_on && CHSPEC_IS5G(pi->radio_chanspec)))
+
+#define BRCMS_PHY_WAR_PR51571(pi) \
+ if (NREV_LT((pi)->pubpi.phy_rev, 3)) \
+ (void)R_REG(&(pi)->regs->maccontrol)
+
+extern void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype);
+extern void wlc_phy_aci_reset_nphy(struct brcms_phy *pi);
+extern void wlc_phy_pa_override_nphy(struct brcms_phy *pi, bool en);
+
+extern u8 wlc_phy_get_chan_freq_range_nphy(struct brcms_phy *pi, uint chan);
+extern void wlc_phy_switch_radio_nphy(struct brcms_phy *pi, bool on);
+
+extern void wlc_phy_stf_chain_upd_nphy(struct brcms_phy *pi);
+
+extern void wlc_phy_force_rfseq_nphy(struct brcms_phy *pi, u8 cmd);
+extern s16 wlc_phy_tempsense_nphy(struct brcms_phy *pi);
+
+extern u16 wlc_phy_classifier_nphy(struct brcms_phy *pi, u16 mask, u16 val);
+
+extern void wlc_phy_rx_iq_est_nphy(struct brcms_phy *pi, struct phy_iq_est *est,
+ u16 num_samps, u8 wait_time,
+ u8 wait_for_crs);
+
+extern void wlc_phy_rx_iq_coeffs_nphy(struct brcms_phy *pi, u8 write,
+ struct nphy_iq_comp *comp);
+extern void wlc_phy_aci_and_noise_reduction_nphy(struct brcms_phy *pi);
+
+extern void wlc_phy_rxcore_setstate_nphy(struct brcms_phy_pub *pih,
+ u8 rxcore_bitmask);
+extern u8 wlc_phy_rxcore_getstate_nphy(struct brcms_phy_pub *pih);
+
+extern void wlc_phy_txpwrctrl_enable_nphy(struct brcms_phy *pi, u8 ctrl_type);
+extern void wlc_phy_txpwr_fixpower_nphy(struct brcms_phy *pi);
+extern void wlc_phy_txpwr_apply_nphy(struct brcms_phy *pi);
+extern void wlc_phy_txpwr_papd_cal_nphy(struct brcms_phy *pi);
+extern u16 wlc_phy_txpwr_idx_get_nphy(struct brcms_phy *pi);
+
+extern struct nphy_txgains wlc_phy_get_tx_gain_nphy(struct brcms_phy *pi);
+extern int wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi,
+ struct nphy_txgains target_gain,
+ bool full, bool m);
+extern int wlc_phy_cal_rxiq_nphy(struct brcms_phy *pi,
+ struct nphy_txgains target_gain,
+ u8 type, bool d);
+extern void wlc_phy_txpwr_index_nphy(struct brcms_phy *pi, u8 core_mask,
+ s8 txpwrindex, bool res);
+extern void wlc_phy_rssisel_nphy(struct brcms_phy *pi, u8 core, u8 rssi_type);
+extern int wlc_phy_poll_rssi_nphy(struct brcms_phy *pi, u8 rssi_type,
+ s32 *rssi_buf, u8 nsamps);
+extern void wlc_phy_rssi_cal_nphy(struct brcms_phy *pi);
+extern int wlc_phy_aci_scan_nphy(struct brcms_phy *pi);
+extern void wlc_phy_cal_txgainctrl_nphy(struct brcms_phy *pi,
+ s32 dBm_targetpower, bool debug);
+extern int wlc_phy_tx_tone_nphy(struct brcms_phy *pi, u32 f_kHz, u16 max_val,
+ u8 mode, u8, bool);
+extern void wlc_phy_stopplayback_nphy(struct brcms_phy *pi);
+extern void wlc_phy_est_tonepwr_nphy(struct brcms_phy *pi, s32 *qdBm_pwrbuf,
+ u8 num_samps);
+extern void wlc_phy_radio205x_vcocal_nphy(struct brcms_phy *pi);
+
+extern int wlc_phy_rssi_compute_nphy(struct brcms_phy *pi,
+ struct d11rxhdr *rxh);
+
+#define NPHY_TESTPATTERN_BPHY_EVM 0
+#define NPHY_TESTPATTERN_BPHY_RFCS 1
+
+extern void wlc_phy_nphy_tkip_rifs_war(struct brcms_phy *pi, u8 rifs);
+
+void wlc_phy_get_pwrdet_offsets(struct brcms_phy *pi, s8 *cckoffset,
+ s8 *ofdmoffset);
+extern s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi,
+ u16 chanspec);
+
+extern bool wlc_phy_n_txpower_ipa_ison(struct brcms_phy *pih);
+#endif /* _BRCM_PHY_INT_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
new file mode 100644
index 000000000000..a63aa99d9810
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
@@ -0,0 +1,5154 @@
+/*
+ * Copyright (c) 2010 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/kernel.h>
+#include <linux/delay.h>
+#include <linux/cordic.h>
+
+#include <pmu.h>
+#include <d11.h>
+#include <phy_shim.h>
+#include "phy_qmath.h"
+#include "phy_hal.h"
+#include "phy_radio.h"
+#include "phytbl_lcn.h"
+#include "phy_lcn.h"
+
+#define PLL_2064_NDIV 90
+#define PLL_2064_LOW_END_VCO 3000
+#define PLL_2064_LOW_END_KVCO 27
+#define PLL_2064_HIGH_END_VCO 4200
+#define PLL_2064_HIGH_END_KVCO 68
+#define PLL_2064_LOOP_BW_DOUBLER 200
+#define PLL_2064_D30_DOUBLER 10500
+#define PLL_2064_LOOP_BW 260
+#define PLL_2064_D30 8000
+#define PLL_2064_CAL_REF_TO 8
+#define PLL_2064_MHZ 1000000
+#define PLL_2064_OPEN_LOOP_DELAY 5
+
+#define TEMPSENSE 1
+#define VBATSENSE 2
+
+#define NOISE_IF_UPD_CHK_INTERVAL 1
+#define NOISE_IF_UPD_RST_INTERVAL 60
+#define NOISE_IF_UPD_THRESHOLD_CNT 1
+#define NOISE_IF_UPD_TRHRESHOLD 50
+#define NOISE_IF_UPD_TIMEOUT 1000
+#define NOISE_IF_OFF 0
+#define NOISE_IF_CHK 1
+#define NOISE_IF_ON 2
+
+#define PAPD_BLANKING_PROFILE 3
+#define PAPD2LUT 0
+#define PAPD_CORR_NORM 0
+#define PAPD_BLANKING_THRESHOLD 0
+#define PAPD_STOP_AFTER_LAST_UPDATE 0
+
+#define LCN_TARGET_PWR 60
+
+#define LCN_VBAT_OFFSET_433X 34649679
+#define LCN_VBAT_SLOPE_433X 8258032
+
+#define LCN_VBAT_SCALE_NOM 53
+#define LCN_VBAT_SCALE_DEN 432
+
+#define LCN_TEMPSENSE_OFFSET 80812
+#define LCN_TEMPSENSE_DEN 2647
+
+#define LCN_BW_LMT 200
+#define LCN_CUR_LMT 1250
+#define LCN_MULT 1
+#define LCN_VCO_DIV 30
+#define LCN_OFFSET 680
+#define LCN_FACT 490
+#define LCN_CUR_DIV 2640
+
+#define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT \
+ (0 + 8)
+#define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK \
+ (0x7f << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT)
+
+#define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT \
+ (0 + 8)
+#define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK \
+ (0x7f << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT)
+
+#define wlc_lcnphy_enable_tx_gain_override(pi) \
+ wlc_lcnphy_set_tx_gain_override(pi, true)
+#define wlc_lcnphy_disable_tx_gain_override(pi) \
+ wlc_lcnphy_set_tx_gain_override(pi, false)
+
+#define wlc_lcnphy_iqcal_active(pi) \
+ (read_phy_reg((pi), 0x451) & \
+ ((0x1 << 15) | (0x1 << 14)))
+
+#define txpwrctrl_off(pi) (0x7 != ((read_phy_reg(pi, 0x4a4) & 0xE000) >> 13))
+#define wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) \
+ (pi->temppwrctrl_capable)
+#define wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) \
+ (pi->hwpwrctrl_capable)
+
+#define SWCTRL_BT_TX 0x18
+#define SWCTRL_OVR_DISABLE 0x40
+
+#define AFE_CLK_INIT_MODE_TXRX2X 1
+#define AFE_CLK_INIT_MODE_PAPD 0
+
+#define LCNPHY_TBL_ID_IQLOCAL 0x00
+
+#define LCNPHY_TBL_ID_RFSEQ 0x08
+#define LCNPHY_TBL_ID_GAIN_IDX 0x0d
+#define LCNPHY_TBL_ID_SW_CTRL 0x0f
+#define LCNPHY_TBL_ID_GAIN_TBL 0x12
+#define LCNPHY_TBL_ID_SPUR 0x14
+#define LCNPHY_TBL_ID_SAMPLEPLAY 0x15
+#define LCNPHY_TBL_ID_SAMPLEPLAY1 0x16
+
+#define LCNPHY_TX_PWR_CTRL_RATE_OFFSET 832
+#define LCNPHY_TX_PWR_CTRL_MAC_OFFSET 128
+#define LCNPHY_TX_PWR_CTRL_GAIN_OFFSET 192
+#define LCNPHY_TX_PWR_CTRL_IQ_OFFSET 320
+#define LCNPHY_TX_PWR_CTRL_LO_OFFSET 448
+#define LCNPHY_TX_PWR_CTRL_PWR_OFFSET 576
+
+#define LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313 140
+
+#define LCNPHY_TX_PWR_CTRL_START_NPT 1
+#define LCNPHY_TX_PWR_CTRL_MAX_NPT 7
+
+#define LCNPHY_NOISE_SAMPLES_DEFAULT 5000
+
+#define LCNPHY_ACI_DETECT_START 1
+#define LCNPHY_ACI_DETECT_PROGRESS 2
+#define LCNPHY_ACI_DETECT_STOP 3
+
+#define LCNPHY_ACI_CRSHIFRMLO_TRSH 100
+#define LCNPHY_ACI_GLITCH_TRSH 2000
+#define LCNPHY_ACI_TMOUT 250
+#define LCNPHY_ACI_DETECT_TIMEOUT 2
+#define LCNPHY_ACI_START_DELAY 0
+
+#define wlc_lcnphy_tx_gain_override_enabled(pi) \
+ (0 != (read_phy_reg((pi), 0x43b) & (0x1 << 6)))
+
+#define wlc_lcnphy_total_tx_frames(pi) \
+ wlapi_bmac_read_shm((pi)->sh->physhim, M_UCODE_MACSTAT + \
+ offsetof(struct macstat, txallfrm))
+
+struct lcnphy_txgains {
+ u16 gm_gain;
+ u16 pga_gain;
+ u16 pad_gain;
+ u16 dac_gain;
+};
+
+enum lcnphy_cal_mode {
+ LCNPHY_CAL_FULL,
+ LCNPHY_CAL_RECAL,
+ LCNPHY_CAL_CURRECAL,
+ LCNPHY_CAL_DIGCAL,
+ LCNPHY_CAL_GCTRL
+};
+
+struct lcnphy_rx_iqcomp {
+ u8 chan;
+ s16 a;
+ s16 b;
+};
+
+struct lcnphy_spb_tone {
+ s16 re;
+ s16 im;
+};
+
+struct lcnphy_unsign16_struct {
+ u16 re;
+ u16 im;
+};
+
+struct lcnphy_iq_est {
+ u32 iq_prod;
+ u32 i_pwr;
+ u32 q_pwr;
+};
+
+struct lcnphy_sfo_cfg {
+ u16 ptcentreTs20;
+ u16 ptcentreFactor;
+};
+
+enum lcnphy_papd_cal_type {
+ LCNPHY_PAPD_CAL_CW,
+ LCNPHY_PAPD_CAL_OFDM
+};
+
+typedef u16 iqcal_gain_params_lcnphy[9];
+
+static const iqcal_gain_params_lcnphy tbl_iqcal_gainparams_lcnphy_2G[] = {
+ {0, 0, 0, 0, 0, 0, 0, 0, 0},
+};
+
+static const iqcal_gain_params_lcnphy *tbl_iqcal_gainparams_lcnphy[1] = {
+ tbl_iqcal_gainparams_lcnphy_2G,
+};
+
+static const u16 iqcal_gainparams_numgains_lcnphy[1] = {
+ sizeof(tbl_iqcal_gainparams_lcnphy_2G) /
+ sizeof(*tbl_iqcal_gainparams_lcnphy_2G),
+};
+
+static const struct lcnphy_sfo_cfg lcnphy_sfo_cfg[] = {
+ {965, 1087},
+ {967, 1085},
+ {969, 1082},
+ {971, 1080},
+ {973, 1078},
+ {975, 1076},
+ {977, 1073},
+ {979, 1071},
+ {981, 1069},
+ {983, 1067},
+ {985, 1065},
+ {987, 1063},
+ {989, 1060},
+ {994, 1055}
+};
+
+static const
+u16 lcnphy_iqcal_loft_gainladder[] = {
+ ((2 << 8) | 0),
+ ((3 << 8) | 0),
+ ((4 << 8) | 0),
+ ((6 << 8) | 0),
+ ((8 << 8) | 0),
+ ((11 << 8) | 0),
+ ((16 << 8) | 0),
+ ((16 << 8) | 1),
+ ((16 << 8) | 2),
+ ((16 << 8) | 3),
+ ((16 << 8) | 4),
+ ((16 << 8) | 5),
+ ((16 << 8) | 6),
+ ((16 << 8) | 7),
+ ((23 << 8) | 7),
+ ((32 << 8) | 7),
+ ((45 << 8) | 7),
+ ((64 << 8) | 7),
+ ((91 << 8) | 7),
+ ((128 << 8) | 7)
+};
+
+static const
+u16 lcnphy_iqcal_ir_gainladder[] = {
+ ((1 << 8) | 0),
+ ((2 << 8) | 0),
+ ((4 << 8) | 0),
+ ((6 << 8) | 0),
+ ((8 << 8) | 0),
+ ((11 << 8) | 0),
+ ((16 << 8) | 0),
+ ((23 << 8) | 0),
+ ((32 << 8) | 0),
+ ((45 << 8) | 0),
+ ((64 << 8) | 0),
+ ((64 << 8) | 1),
+ ((64 << 8) | 2),
+ ((64 << 8) | 3),
+ ((64 << 8) | 4),
+ ((64 << 8) | 5),
+ ((64 << 8) | 6),
+ ((64 << 8) | 7),
+ ((91 << 8) | 7),
+ ((128 << 8) | 7)
+};
+
+static const
+struct lcnphy_spb_tone lcnphy_spb_tone_3750[] = {
+ {88, 0},
+ {73, 49},
+ {34, 81},
+ {-17, 86},
+ {-62, 62},
+ {-86, 17},
+ {-81, -34},
+ {-49, -73},
+ {0, -88},
+ {49, -73},
+ {81, -34},
+ {86, 17},
+ {62, 62},
+ {17, 86},
+ {-34, 81},
+ {-73, 49},
+ {-88, 0},
+ {-73, -49},
+ {-34, -81},
+ {17, -86},
+ {62, -62},
+ {86, -17},
+ {81, 34},
+ {49, 73},
+ {0, 88},
+ {-49, 73},
+ {-81, 34},
+ {-86, -17},
+ {-62, -62},
+ {-17, -86},
+ {34, -81},
+ {73, -49},
+};
+
+static const
+u16 iqlo_loopback_rf_regs[20] = {
+ RADIO_2064_REG036,
+ RADIO_2064_REG11A,
+ RADIO_2064_REG03A,
+ RADIO_2064_REG025,
+ RADIO_2064_REG028,
+ RADIO_2064_REG005,
+ RADIO_2064_REG112,
+ RADIO_2064_REG0FF,
+ RADIO_2064_REG11F,
+ RADIO_2064_REG00B,
+ RADIO_2064_REG113,
+ RADIO_2064_REG007,
+ RADIO_2064_REG0FC,
+ RADIO_2064_REG0FD,
+ RADIO_2064_REG012,
+ RADIO_2064_REG057,
+ RADIO_2064_REG059,
+ RADIO_2064_REG05C,
+ RADIO_2064_REG078,
+ RADIO_2064_REG092,
+};
+
+static const
+u16 tempsense_phy_regs[14] = {
+ 0x503,
+ 0x4a4,
+ 0x4d0,
+ 0x4d9,
+ 0x4da,
+ 0x4a6,
+ 0x938,
+ 0x939,
+ 0x4d8,
+ 0x4d0,
+ 0x4d7,
+ 0x4a5,
+ 0x40d,
+ 0x4a2,
+};
+
+static const
+u16 rxiq_cal_rf_reg[11] = {
+ RADIO_2064_REG098,
+ RADIO_2064_REG116,
+ RADIO_2064_REG12C,
+ RADIO_2064_REG06A,
+ RADIO_2064_REG00B,
+ RADIO_2064_REG01B,
+ RADIO_2064_REG113,
+ RADIO_2064_REG01D,
+ RADIO_2064_REG114,
+ RADIO_2064_REG02E,
+ RADIO_2064_REG12A,
+};
+
+static const
+struct lcnphy_rx_iqcomp lcnphy_rx_iqcomp_table_rev0[] = {
+ {1, 0, 0},
+ {2, 0, 0},
+ {3, 0, 0},
+ {4, 0, 0},
+ {5, 0, 0},
+ {6, 0, 0},
+ {7, 0, 0},
+ {8, 0, 0},
+ {9, 0, 0},
+ {10, 0, 0},
+ {11, 0, 0},
+ {12, 0, 0},
+ {13, 0, 0},
+ {14, 0, 0},
+ {34, 0, 0},
+ {38, 0, 0},
+ {42, 0, 0},
+ {46, 0, 0},
+ {36, 0, 0},
+ {40, 0, 0},
+ {44, 0, 0},
+ {48, 0, 0},
+ {52, 0, 0},
+ {56, 0, 0},
+ {60, 0, 0},
+ {64, 0, 0},
+ {100, 0, 0},
+ {104, 0, 0},
+ {108, 0, 0},
+ {112, 0, 0},
+ {116, 0, 0},
+ {120, 0, 0},
+ {124, 0, 0},
+ {128, 0, 0},
+ {132, 0, 0},
+ {136, 0, 0},
+ {140, 0, 0},
+ {149, 0, 0},
+ {153, 0, 0},
+ {157, 0, 0},
+ {161, 0, 0},
+ {165, 0, 0},
+ {184, 0, 0},
+ {188, 0, 0},
+ {192, 0, 0},
+ {196, 0, 0},
+ {200, 0, 0},
+ {204, 0, 0},
+ {208, 0, 0},
+ {212, 0, 0},
+ {216, 0, 0},
+};
+
+static const u32 lcnphy_23bitgaincode_table[] = {
+ 0x200100,
+ 0x200200,
+ 0x200004,
+ 0x200014,
+ 0x200024,
+ 0x200034,
+ 0x200134,
+ 0x200234,
+ 0x200334,
+ 0x200434,
+ 0x200037,
+ 0x200137,
+ 0x200237,
+ 0x200337,
+ 0x200437,
+ 0x000035,
+ 0x000135,
+ 0x000235,
+ 0x000037,
+ 0x000137,
+ 0x000237,
+ 0x000337,
+ 0x00013f,
+ 0x00023f,
+ 0x00033f,
+ 0x00034f,
+ 0x00044f,
+ 0x00144f,
+ 0x00244f,
+ 0x00254f,
+ 0x00354f,
+ 0x00454f,
+ 0x00464f,
+ 0x01464f,
+ 0x02464f,
+ 0x03464f,
+ 0x04464f,
+};
+
+static const s8 lcnphy_gain_table[] = {
+ -16,
+ -13,
+ 10,
+ 7,
+ 4,
+ 0,
+ 3,
+ 6,
+ 9,
+ 12,
+ 15,
+ 18,
+ 21,
+ 24,
+ 27,
+ 30,
+ 33,
+ 36,
+ 39,
+ 42,
+ 45,
+ 48,
+ 50,
+ 53,
+ 56,
+ 59,
+ 62,
+ 65,
+ 68,
+ 71,
+ 74,
+ 77,
+ 80,
+ 83,
+ 86,
+ 89,
+ 92,
+};
+
+static const s8 lcnphy_gain_index_offset_for_rssi[] = {
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 7,
+ 8,
+ 7,
+ 7,
+ 6,
+ 7,
+ 7,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 4,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 3,
+ 4,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ 2,
+ -1,
+ -2,
+ -2,
+ -2
+};
+
+struct chan_info_2064_lcnphy {
+ uint chan;
+ uint freq;
+ u8 logen_buftune;
+ u8 logen_rccr_tx;
+ u8 txrf_mix_tune_ctrl;
+ u8 pa_input_tune_g;
+ u8 logen_rccr_rx;
+ u8 pa_rxrf_lna1_freq_tune;
+ u8 pa_rxrf_lna2_freq_tune;
+ u8 rxrf_rxrf_spare1;
+};
+
+static const struct chan_info_2064_lcnphy chan_info_2064_lcnphy[] = {
+ {1, 2412, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
+ {2, 2417, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
+ {3, 2422, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
+ {4, 2427, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
+ {5, 2432, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
+ {6, 2437, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
+ {7, 2442, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
+ {8, 2447, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
+ {9, 2452, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
+ {10, 2457, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
+ {11, 2462, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
+ {12, 2467, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
+ {13, 2472, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
+ {14, 2484, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
+};
+
+static const struct lcnphy_radio_regs lcnphy_radio_regs_2064[] = {
+ {0x00, 0, 0, 0, 0},
+ {0x01, 0x64, 0x64, 0, 0},
+ {0x02, 0x20, 0x20, 0, 0},
+ {0x03, 0x66, 0x66, 0, 0},
+ {0x04, 0xf8, 0xf8, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0x10, 0x10, 0, 0},
+ {0x07, 0, 0, 0, 0},
+ {0x08, 0, 0, 0, 0},
+ {0x09, 0, 0, 0, 0},
+ {0x0A, 0x37, 0x37, 0, 0},
+ {0x0B, 0x6, 0x6, 0, 0},
+ {0x0C, 0x55, 0x55, 0, 0},
+ {0x0D, 0x8b, 0x8b, 0, 0},
+ {0x0E, 0, 0, 0, 0},
+ {0x0F, 0x5, 0x5, 0, 0},
+ {0x10, 0, 0, 0, 0},
+ {0x11, 0xe, 0xe, 0, 0},
+ {0x12, 0, 0, 0, 0},
+ {0x13, 0xb, 0xb, 0, 0},
+ {0x14, 0x2, 0x2, 0, 0},
+ {0x15, 0x12, 0x12, 0, 0},
+ {0x16, 0x12, 0x12, 0, 0},
+ {0x17, 0xc, 0xc, 0, 0},
+ {0x18, 0xc, 0xc, 0, 0},
+ {0x19, 0xc, 0xc, 0, 0},
+ {0x1A, 0x8, 0x8, 0, 0},
+ {0x1B, 0x2, 0x2, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0x1, 0x1, 0, 0},
+ {0x1E, 0x12, 0x12, 0, 0},
+ {0x1F, 0x6e, 0x6e, 0, 0},
+ {0x20, 0x2, 0x2, 0, 0},
+ {0x21, 0x23, 0x23, 0, 0},
+ {0x22, 0x8, 0x8, 0, 0},
+ {0x23, 0, 0, 0, 0},
+ {0x24, 0, 0, 0, 0},
+ {0x25, 0xc, 0xc, 0, 0},
+ {0x26, 0x33, 0x33, 0, 0},
+ {0x27, 0x55, 0x55, 0, 0},
+ {0x28, 0, 0, 0, 0},
+ {0x29, 0x30, 0x30, 0, 0},
+ {0x2A, 0xb, 0xb, 0, 0},
+ {0x2B, 0x1b, 0x1b, 0, 0},
+ {0x2C, 0x3, 0x3, 0, 0},
+ {0x2D, 0x1b, 0x1b, 0, 0},
+ {0x2E, 0, 0, 0, 0},
+ {0x2F, 0x20, 0x20, 0, 0},
+ {0x30, 0xa, 0xa, 0, 0},
+ {0x31, 0, 0, 0, 0},
+ {0x32, 0x62, 0x62, 0, 0},
+ {0x33, 0x19, 0x19, 0, 0},
+ {0x34, 0x33, 0x33, 0, 0},
+ {0x35, 0x77, 0x77, 0, 0},
+ {0x36, 0, 0, 0, 0},
+ {0x37, 0x70, 0x70, 0, 0},
+ {0x38, 0x3, 0x3, 0, 0},
+ {0x39, 0xf, 0xf, 0, 0},
+ {0x3A, 0x6, 0x6, 0, 0},
+ {0x3B, 0xcf, 0xcf, 0, 0},
+ {0x3C, 0x1a, 0x1a, 0, 0},
+ {0x3D, 0x6, 0x6, 0, 0},
+ {0x3E, 0x42, 0x42, 0, 0},
+ {0x3F, 0, 0, 0, 0},
+ {0x40, 0xfb, 0xfb, 0, 0},
+ {0x41, 0x9a, 0x9a, 0, 0},
+ {0x42, 0x7a, 0x7a, 0, 0},
+ {0x43, 0x29, 0x29, 0, 0},
+ {0x44, 0, 0, 0, 0},
+ {0x45, 0x8, 0x8, 0, 0},
+ {0x46, 0xce, 0xce, 0, 0},
+ {0x47, 0x27, 0x27, 0, 0},
+ {0x48, 0x62, 0x62, 0, 0},
+ {0x49, 0x6, 0x6, 0, 0},
+ {0x4A, 0x58, 0x58, 0, 0},
+ {0x4B, 0xf7, 0xf7, 0, 0},
+ {0x4C, 0, 0, 0, 0},
+ {0x4D, 0xb3, 0xb3, 0, 0},
+ {0x4E, 0, 0, 0, 0},
+ {0x4F, 0x2, 0x2, 0, 0},
+ {0x50, 0, 0, 0, 0},
+ {0x51, 0x9, 0x9, 0, 0},
+ {0x52, 0x5, 0x5, 0, 0},
+ {0x53, 0x17, 0x17, 0, 0},
+ {0x54, 0x38, 0x38, 0, 0},
+ {0x55, 0, 0, 0, 0},
+ {0x56, 0, 0, 0, 0},
+ {0x57, 0xb, 0xb, 0, 0},
+ {0x58, 0, 0, 0, 0},
+ {0x59, 0, 0, 0, 0},
+ {0x5A, 0, 0, 0, 0},
+ {0x5B, 0, 0, 0, 0},
+ {0x5C, 0, 0, 0, 0},
+ {0x5D, 0, 0, 0, 0},
+ {0x5E, 0x88, 0x88, 0, 0},
+ {0x5F, 0xcc, 0xcc, 0, 0},
+ {0x60, 0x74, 0x74, 0, 0},
+ {0x61, 0x74, 0x74, 0, 0},
+ {0x62, 0x74, 0x74, 0, 0},
+ {0x63, 0x44, 0x44, 0, 0},
+ {0x64, 0x77, 0x77, 0, 0},
+ {0x65, 0x44, 0x44, 0, 0},
+ {0x66, 0x77, 0x77, 0, 0},
+ {0x67, 0x55, 0x55, 0, 0},
+ {0x68, 0x77, 0x77, 0, 0},
+ {0x69, 0x77, 0x77, 0, 0},
+ {0x6A, 0, 0, 0, 0},
+ {0x6B, 0x7f, 0x7f, 0, 0},
+ {0x6C, 0x8, 0x8, 0, 0},
+ {0x6D, 0, 0, 0, 0},
+ {0x6E, 0x88, 0x88, 0, 0},
+ {0x6F, 0x66, 0x66, 0, 0},
+ {0x70, 0x66, 0x66, 0, 0},
+ {0x71, 0x28, 0x28, 0, 0},
+ {0x72, 0x55, 0x55, 0, 0},
+ {0x73, 0x4, 0x4, 0, 0},
+ {0x74, 0, 0, 0, 0},
+ {0x75, 0, 0, 0, 0},
+ {0x76, 0, 0, 0, 0},
+ {0x77, 0x1, 0x1, 0, 0},
+ {0x78, 0xd6, 0xd6, 0, 0},
+ {0x79, 0, 0, 0, 0},
+ {0x7A, 0, 0, 0, 0},
+ {0x7B, 0, 0, 0, 0},
+ {0x7C, 0, 0, 0, 0},
+ {0x7D, 0, 0, 0, 0},
+ {0x7E, 0, 0, 0, 0},
+ {0x7F, 0, 0, 0, 0},
+ {0x80, 0, 0, 0, 0},
+ {0x81, 0, 0, 0, 0},
+ {0x82, 0, 0, 0, 0},
+ {0x83, 0xb4, 0xb4, 0, 0},
+ {0x84, 0x1, 0x1, 0, 0},
+ {0x85, 0x20, 0x20, 0, 0},
+ {0x86, 0x5, 0x5, 0, 0},
+ {0x87, 0xff, 0xff, 0, 0},
+ {0x88, 0x7, 0x7, 0, 0},
+ {0x89, 0x77, 0x77, 0, 0},
+ {0x8A, 0x77, 0x77, 0, 0},
+ {0x8B, 0x77, 0x77, 0, 0},
+ {0x8C, 0x77, 0x77, 0, 0},
+ {0x8D, 0x8, 0x8, 0, 0},
+ {0x8E, 0xa, 0xa, 0, 0},
+ {0x8F, 0x8, 0x8, 0, 0},
+ {0x90, 0x18, 0x18, 0, 0},
+ {0x91, 0x5, 0x5, 0, 0},
+ {0x92, 0x1f, 0x1f, 0, 0},
+ {0x93, 0x10, 0x10, 0, 0},
+ {0x94, 0x3, 0x3, 0, 0},
+ {0x95, 0, 0, 0, 0},
+ {0x96, 0, 0, 0, 0},
+ {0x97, 0xaa, 0xaa, 0, 0},
+ {0x98, 0, 0, 0, 0},
+ {0x99, 0x23, 0x23, 0, 0},
+ {0x9A, 0x7, 0x7, 0, 0},
+ {0x9B, 0xf, 0xf, 0, 0},
+ {0x9C, 0x10, 0x10, 0, 0},
+ {0x9D, 0x3, 0x3, 0, 0},
+ {0x9E, 0x4, 0x4, 0, 0},
+ {0x9F, 0x20, 0x20, 0, 0},
+ {0xA0, 0, 0, 0, 0},
+ {0xA1, 0, 0, 0, 0},
+ {0xA2, 0, 0, 0, 0},
+ {0xA3, 0, 0, 0, 0},
+ {0xA4, 0x1, 0x1, 0, 0},
+ {0xA5, 0x77, 0x77, 0, 0},
+ {0xA6, 0x77, 0x77, 0, 0},
+ {0xA7, 0x77, 0x77, 0, 0},
+ {0xA8, 0x77, 0x77, 0, 0},
+ {0xA9, 0x8c, 0x8c, 0, 0},
+ {0xAA, 0x88, 0x88, 0, 0},
+ {0xAB, 0x78, 0x78, 0, 0},
+ {0xAC, 0x57, 0x57, 0, 0},
+ {0xAD, 0x88, 0x88, 0, 0},
+ {0xAE, 0, 0, 0, 0},
+ {0xAF, 0x8, 0x8, 0, 0},
+ {0xB0, 0x88, 0x88, 0, 0},
+ {0xB1, 0, 0, 0, 0},
+ {0xB2, 0x1b, 0x1b, 0, 0},
+ {0xB3, 0x3, 0x3, 0, 0},
+ {0xB4, 0x24, 0x24, 0, 0},
+ {0xB5, 0x3, 0x3, 0, 0},
+ {0xB6, 0x1b, 0x1b, 0, 0},
+ {0xB7, 0x24, 0x24, 0, 0},
+ {0xB8, 0x3, 0x3, 0, 0},
+ {0xB9, 0, 0, 0, 0},
+ {0xBA, 0xaa, 0xaa, 0, 0},
+ {0xBB, 0, 0, 0, 0},
+ {0xBC, 0x4, 0x4, 0, 0},
+ {0xBD, 0, 0, 0, 0},
+ {0xBE, 0x8, 0x8, 0, 0},
+ {0xBF, 0x11, 0x11, 0, 0},
+ {0xC0, 0, 0, 0, 0},
+ {0xC1, 0, 0, 0, 0},
+ {0xC2, 0x62, 0x62, 0, 0},
+ {0xC3, 0x1e, 0x1e, 0, 0},
+ {0xC4, 0x33, 0x33, 0, 0},
+ {0xC5, 0x37, 0x37, 0, 0},
+ {0xC6, 0, 0, 0, 0},
+ {0xC7, 0x70, 0x70, 0, 0},
+ {0xC8, 0x1e, 0x1e, 0, 0},
+ {0xC9, 0x6, 0x6, 0, 0},
+ {0xCA, 0x4, 0x4, 0, 0},
+ {0xCB, 0x2f, 0x2f, 0, 0},
+ {0xCC, 0xf, 0xf, 0, 0},
+ {0xCD, 0, 0, 0, 0},
+ {0xCE, 0xff, 0xff, 0, 0},
+ {0xCF, 0x8, 0x8, 0, 0},
+ {0xD0, 0x3f, 0x3f, 0, 0},
+ {0xD1, 0x3f, 0x3f, 0, 0},
+ {0xD2, 0x3f, 0x3f, 0, 0},
+ {0xD3, 0, 0, 0, 0},
+ {0xD4, 0, 0, 0, 0},
+ {0xD5, 0, 0, 0, 0},
+ {0xD6, 0xcc, 0xcc, 0, 0},
+ {0xD7, 0, 0, 0, 0},
+ {0xD8, 0x8, 0x8, 0, 0},
+ {0xD9, 0x8, 0x8, 0, 0},
+ {0xDA, 0x8, 0x8, 0, 0},
+ {0xDB, 0x11, 0x11, 0, 0},
+ {0xDC, 0, 0, 0, 0},
+ {0xDD, 0x87, 0x87, 0, 0},
+ {0xDE, 0x88, 0x88, 0, 0},
+ {0xDF, 0x8, 0x8, 0, 0},
+ {0xE0, 0x8, 0x8, 0, 0},
+ {0xE1, 0x8, 0x8, 0, 0},
+ {0xE2, 0, 0, 0, 0},
+ {0xE3, 0, 0, 0, 0},
+ {0xE4, 0, 0, 0, 0},
+ {0xE5, 0xf5, 0xf5, 0, 0},
+ {0xE6, 0x30, 0x30, 0, 0},
+ {0xE7, 0x1, 0x1, 0, 0},
+ {0xE8, 0, 0, 0, 0},
+ {0xE9, 0xff, 0xff, 0, 0},
+ {0xEA, 0, 0, 0, 0},
+ {0xEB, 0, 0, 0, 0},
+ {0xEC, 0x22, 0x22, 0, 0},
+ {0xED, 0, 0, 0, 0},
+ {0xEE, 0, 0, 0, 0},
+ {0xEF, 0, 0, 0, 0},
+ {0xF0, 0x3, 0x3, 0, 0},
+ {0xF1, 0x1, 0x1, 0, 0},
+ {0xF2, 0, 0, 0, 0},
+ {0xF3, 0, 0, 0, 0},
+ {0xF4, 0, 0, 0, 0},
+ {0xF5, 0, 0, 0, 0},
+ {0xF6, 0, 0, 0, 0},
+ {0xF7, 0x6, 0x6, 0, 0},
+ {0xF8, 0, 0, 0, 0},
+ {0xF9, 0, 0, 0, 0},
+ {0xFA, 0x40, 0x40, 0, 0},
+ {0xFB, 0, 0, 0, 0},
+ {0xFC, 0x1, 0x1, 0, 0},
+ {0xFD, 0x80, 0x80, 0, 0},
+ {0xFE, 0x2, 0x2, 0, 0},
+ {0xFF, 0x10, 0x10, 0, 0},
+ {0x100, 0x2, 0x2, 0, 0},
+ {0x101, 0x1e, 0x1e, 0, 0},
+ {0x102, 0x1e, 0x1e, 0, 0},
+ {0x103, 0, 0, 0, 0},
+ {0x104, 0x1f, 0x1f, 0, 0},
+ {0x105, 0, 0x8, 0, 1},
+ {0x106, 0x2a, 0x2a, 0, 0},
+ {0x107, 0xf, 0xf, 0, 0},
+ {0x108, 0, 0, 0, 0},
+ {0x109, 0, 0, 0, 0},
+ {0x10A, 0, 0, 0, 0},
+ {0x10B, 0, 0, 0, 0},
+ {0x10C, 0, 0, 0, 0},
+ {0x10D, 0, 0, 0, 0},
+ {0x10E, 0, 0, 0, 0},
+ {0x10F, 0, 0, 0, 0},
+ {0x110, 0, 0, 0, 0},
+ {0x111, 0, 0, 0, 0},
+ {0x112, 0, 0, 0, 0},
+ {0x113, 0, 0, 0, 0},
+ {0x114, 0, 0, 0, 0},
+ {0x115, 0, 0, 0, 0},
+ {0x116, 0, 0, 0, 0},
+ {0x117, 0, 0, 0, 0},
+ {0x118, 0, 0, 0, 0},
+ {0x119, 0, 0, 0, 0},
+ {0x11A, 0, 0, 0, 0},
+ {0x11B, 0, 0, 0, 0},
+ {0x11C, 0x1, 0x1, 0, 0},
+ {0x11D, 0, 0, 0, 0},
+ {0x11E, 0, 0, 0, 0},
+ {0x11F, 0, 0, 0, 0},
+ {0x120, 0, 0, 0, 0},
+ {0x121, 0, 0, 0, 0},
+ {0x122, 0x80, 0x80, 0, 0},
+ {0x123, 0, 0, 0, 0},
+ {0x124, 0xf8, 0xf8, 0, 0},
+ {0x125, 0, 0, 0, 0},
+ {0x126, 0, 0, 0, 0},
+ {0x127, 0, 0, 0, 0},
+ {0x128, 0, 0, 0, 0},
+ {0x129, 0, 0, 0, 0},
+ {0x12A, 0, 0, 0, 0},
+ {0x12B, 0, 0, 0, 0},
+ {0x12C, 0, 0, 0, 0},
+ {0x12D, 0, 0, 0, 0},
+ {0x12E, 0, 0, 0, 0},
+ {0x12F, 0, 0, 0, 0},
+ {0x130, 0, 0, 0, 0},
+ {0xFFFF, 0, 0, 0, 0}
+};
+
+#define LCNPHY_NUM_DIG_FILT_COEFFS 16
+#define LCNPHY_NUM_TX_DIG_FILTERS_CCK 13
+
+static const u16 LCNPHY_txdigfiltcoeffs_cck[LCNPHY_NUM_TX_DIG_FILTERS_CCK]
+ [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
+ {0, 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778, 1582, 64,
+ 128, 64,},
+ {1, 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608, 1863, 93,
+ 167, 93,},
+ {2, 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192, 778, 1582, 64,
+ 128, 64,},
+ {3, 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205, 754, 1760,
+ 170, 340, 170,},
+ {20, 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205, 767, 1760,
+ 256, 185, 256,},
+ {21, 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205, 767, 1760,
+ 256, 273, 256,},
+ {22, 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205, 767, 1760,
+ 256, 352, 256,},
+ {23, 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205, 767, 1760,
+ 128, 233, 128,},
+ {24, 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766, 1760, 256,
+ 1881, 256,},
+ {25, 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765, 1760, 256,
+ 1881, 256,},
+ {26, 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614, 1864, 128,
+ 384, 288,},
+ {27, 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576, 613, 1864,
+ 128, 384, 288,},
+ {30, 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205, 754, 1760,
+ 170, 340, 170,},
+};
+
+#define LCNPHY_NUM_TX_DIG_FILTERS_OFDM 3
+static const u16 LCNPHY_txdigfiltcoeffs_ofdm[LCNPHY_NUM_TX_DIG_FILTERS_OFDM]
+ [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
+ {0, 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0, 0x0,
+ 0x278, 0xfea0, 0x80, 0x100, 0x80,},
+ {1, 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50,
+ 750, 0xFE2B, 212, 0xFFCE, 212,},
+ {2, 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748,
+ 0xFEF2, 128, 0xFFE2, 128}
+};
+
+#define wlc_lcnphy_set_start_tx_pwr_idx(pi, idx) \
+ mod_phy_reg(pi, 0x4a4, \
+ (0x1ff << 0), \
+ (u16)(idx) << 0)
+
+#define wlc_lcnphy_set_tx_pwr_npt(pi, npt) \
+ mod_phy_reg(pi, 0x4a5, \
+ (0x7 << 8), \
+ (u16)(npt) << 8)
+
+#define wlc_lcnphy_get_tx_pwr_ctrl(pi) \
+ (read_phy_reg((pi), 0x4a4) & \
+ ((0x1 << 15) | \
+ (0x1 << 14) | \
+ (0x1 << 13)))
+
+#define wlc_lcnphy_get_tx_pwr_npt(pi) \
+ ((read_phy_reg(pi, 0x4a5) & \
+ (0x7 << 8)) >> \
+ 8)
+
+#define wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi) \
+ (read_phy_reg(pi, 0x473) & 0x1ff)
+
+#define wlc_lcnphy_get_target_tx_pwr(pi) \
+ ((read_phy_reg(pi, 0x4a7) & \
+ (0xff << 0)) >> \
+ 0)
+
+#define wlc_lcnphy_set_target_tx_pwr(pi, target) \
+ mod_phy_reg(pi, 0x4a7, \
+ (0xff << 0), \
+ (u16)(target) << 0)
+
+#define wlc_radio_2064_rcal_done(pi) \
+ (0 != (read_radio_reg(pi, RADIO_2064_REG05C) & 0x20))
+
+#define tempsense_done(pi) \
+ (0x8000 == (read_phy_reg(pi, 0x476) & 0x8000))
+
+#define LCNPHY_IQLOCC_READ(val) \
+ ((u8)(-(s8)(((val) & 0xf0) >> 4) + (s8)((val) & 0x0f)))
+
+#define FIXED_TXPWR 78
+#define LCNPHY_TEMPSENSE(val) ((s16)((val > 255) ? (val - 512) : val))
+
+void wlc_lcnphy_write_table(struct brcms_phy *pi, const struct phytbl_info *pti)
+{
+ wlc_phy_write_table(pi, pti, 0x455, 0x457, 0x456);
+}
+
+void wlc_lcnphy_read_table(struct brcms_phy *pi, struct phytbl_info *pti)
+{
+ wlc_phy_read_table(pi, pti, 0x455, 0x457, 0x456);
+}
+
+static void
+wlc_lcnphy_common_read_table(struct brcms_phy *pi, u32 tbl_id,
+ const u16 *tbl_ptr, u32 tbl_len,
+ u32 tbl_width, u32 tbl_offset)
+{
+ struct phytbl_info tab;
+ tab.tbl_id = tbl_id;
+ tab.tbl_ptr = tbl_ptr;
+ tab.tbl_len = tbl_len;
+ tab.tbl_width = tbl_width;
+ tab.tbl_offset = tbl_offset;
+ wlc_lcnphy_read_table(pi, &tab);
+}
+
+static void
+wlc_lcnphy_common_write_table(struct brcms_phy *pi, u32 tbl_id,
+ const u16 *tbl_ptr, u32 tbl_len,
+ u32 tbl_width, u32 tbl_offset)
+{
+
+ struct phytbl_info tab;
+ tab.tbl_id = tbl_id;
+ tab.tbl_ptr = tbl_ptr;
+ tab.tbl_len = tbl_len;
+ tab.tbl_width = tbl_width;
+ tab.tbl_offset = tbl_offset;
+ wlc_lcnphy_write_table(pi, &tab);
+}
+
+static u32
+wlc_lcnphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
+{
+ u32 quotient, remainder, roundup, rbit;
+
+ quotient = dividend / divisor;
+ remainder = dividend % divisor;
+ rbit = divisor & 1;
+ roundup = (divisor >> 1) + rbit;
+
+ while (precision--) {
+ quotient <<= 1;
+ if (remainder >= roundup) {
+ quotient++;
+ remainder = ((remainder - roundup) << 1) + rbit;
+ } else {
+ remainder <<= 1;
+ }
+ }
+
+ if (remainder >= roundup)
+ quotient++;
+
+ return quotient;
+}
+
+static int wlc_lcnphy_calc_floor(s16 coeff_x, int type)
+{
+ int k;
+ k = 0;
+ if (type == 0) {
+ if (coeff_x < 0)
+ k = (coeff_x - 1) / 2;
+ else
+ k = coeff_x / 2;
+ }
+
+ if (type == 1) {
+ if ((coeff_x + 1) < 0)
+ k = (coeff_x) / 2;
+ else
+ k = (coeff_x + 1) / 2;
+ }
+ return k;
+}
+
+static void
+wlc_lcnphy_get_tx_gain(struct brcms_phy *pi, struct lcnphy_txgains *gains)
+{
+ u16 dac_gain, rfgain0, rfgain1;
+
+ dac_gain = read_phy_reg(pi, 0x439) >> 0;
+ gains->dac_gain = (dac_gain & 0x380) >> 7;
+
+ rfgain0 = (read_phy_reg(pi, 0x4b5) & (0xffff << 0)) >> 0;
+ rfgain1 = (read_phy_reg(pi, 0x4fb) & (0x7fff << 0)) >> 0;
+
+ gains->gm_gain = rfgain0 & 0xff;
+ gains->pga_gain = (rfgain0 >> 8) & 0xff;
+ gains->pad_gain = rfgain1 & 0xff;
+}
+
+
+static void wlc_lcnphy_set_dac_gain(struct brcms_phy *pi, u16 dac_gain)
+{
+ u16 dac_ctrl;
+
+ dac_ctrl = (read_phy_reg(pi, 0x439) >> 0);
+ dac_ctrl = dac_ctrl & 0xc7f;
+ dac_ctrl = dac_ctrl | (dac_gain << 7);
+ mod_phy_reg(pi, 0x439, (0xfff << 0), (dac_ctrl) << 0);
+
+}
+
+static void wlc_lcnphy_set_tx_gain_override(struct brcms_phy *pi, bool bEnable)
+{
+ u16 bit = bEnable ? 1 : 0;
+
+ mod_phy_reg(pi, 0x4b0, (0x1 << 7), bit << 7);
+
+ mod_phy_reg(pi, 0x4b0, (0x1 << 14), bit << 14);
+
+ mod_phy_reg(pi, 0x43b, (0x1 << 6), bit << 6);
+}
+
+static void
+wlc_lcnphy_rx_gain_override_enable(struct brcms_phy *pi, bool enable)
+{
+ u16 ebit = enable ? 1 : 0;
+
+ mod_phy_reg(pi, 0x4b0, (0x1 << 8), ebit << 8);
+
+ mod_phy_reg(pi, 0x44c, (0x1 << 0), ebit << 0);
+
+ if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
+ mod_phy_reg(pi, 0x44c, (0x1 << 4), ebit << 4);
+ mod_phy_reg(pi, 0x44c, (0x1 << 6), ebit << 6);
+ mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
+ mod_phy_reg(pi, 0x4b0, (0x1 << 6), ebit << 6);
+ } else {
+ mod_phy_reg(pi, 0x4b0, (0x1 << 12), ebit << 12);
+ mod_phy_reg(pi, 0x4b0, (0x1 << 13), ebit << 13);
+ mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
+ }
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ mod_phy_reg(pi, 0x4b0, (0x1 << 10), ebit << 10);
+ mod_phy_reg(pi, 0x4e5, (0x1 << 3), ebit << 3);
+ }
+}
+
+static void
+wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi,
+ u16 trsw,
+ u16 ext_lna,
+ u16 biq2,
+ u16 biq1,
+ u16 tia, u16 lna2, u16 lna1)
+{
+ u16 gain0_15, gain16_19;
+
+ gain16_19 = biq2 & 0xf;
+ gain0_15 = ((biq1 & 0xf) << 12) |
+ ((tia & 0xf) << 8) |
+ ((lna2 & 0x3) << 6) |
+ ((lna2 &
+ 0x3) << 4) | ((lna1 & 0x3) << 2) | ((lna1 & 0x3) << 0);
+
+ mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
+ mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
+ mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
+
+ if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
+ mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
+ mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
+ } else {
+ mod_phy_reg(pi, 0x4b1, (0x1 << 10), 0 << 10);
+
+ mod_phy_reg(pi, 0x4b1, (0x1 << 15), 0 << 15);
+
+ mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
+ }
+
+ mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0);
+
+}
+
+static void wlc_lcnphy_set_trsw_override(struct brcms_phy *pi, bool tx, bool rx)
+{
+
+ mod_phy_reg(pi, 0x44d,
+ (0x1 << 1) |
+ (0x1 << 0), (tx ? (0x1 << 1) : 0) | (rx ? (0x1 << 0) : 0));
+
+ or_phy_reg(pi, 0x44c, (0x1 << 1) | (0x1 << 0));
+}
+
+static void wlc_lcnphy_clear_trsw_override(struct brcms_phy *pi)
+{
+
+ and_phy_reg(pi, 0x44c, (u16) ~((0x1 << 1) | (0x1 << 0)));
+}
+
+static void wlc_lcnphy_set_rx_iq_comp(struct brcms_phy *pi, u16 a, u16 b)
+{
+ mod_phy_reg(pi, 0x645, (0x3ff << 0), (a) << 0);
+
+ mod_phy_reg(pi, 0x646, (0x3ff << 0), (b) << 0);
+
+ mod_phy_reg(pi, 0x647, (0x3ff << 0), (a) << 0);
+
+ mod_phy_reg(pi, 0x648, (0x3ff << 0), (b) << 0);
+
+ mod_phy_reg(pi, 0x649, (0x3ff << 0), (a) << 0);
+
+ mod_phy_reg(pi, 0x64a, (0x3ff << 0), (b) << 0);
+
+}
+
+static bool
+wlc_lcnphy_rx_iq_est(struct brcms_phy *pi,
+ u16 num_samps,
+ u8 wait_time, struct lcnphy_iq_est *iq_est)
+{
+ int wait_count = 0;
+ bool result = true;
+ u8 phybw40;
+ phybw40 = CHSPEC_IS40(pi->radio_chanspec);
+
+ mod_phy_reg(pi, 0x6da, (0x1 << 5), (1) << 5);
+
+ mod_phy_reg(pi, 0x410, (0x1 << 3), (0) << 3);
+
+ mod_phy_reg(pi, 0x482, (0xffff << 0), (num_samps) << 0);
+
+ mod_phy_reg(pi, 0x481, (0xff << 0), ((u16) wait_time) << 0);
+
+ mod_phy_reg(pi, 0x481, (0x1 << 8), (0) << 8);
+
+ mod_phy_reg(pi, 0x481, (0x1 << 9), (1) << 9);
+
+ while (read_phy_reg(pi, 0x481) & (0x1 << 9)) {
+
+ if (wait_count > (10 * 500)) {
+ result = false;
+ goto cleanup;
+ }
+ udelay(100);
+ wait_count++;
+ }
+
+ iq_est->iq_prod = ((u32) read_phy_reg(pi, 0x483) << 16) |
+ (u32) read_phy_reg(pi, 0x484);
+ iq_est->i_pwr = ((u32) read_phy_reg(pi, 0x485) << 16) |
+ (u32) read_phy_reg(pi, 0x486);
+ iq_est->q_pwr = ((u32) read_phy_reg(pi, 0x487) << 16) |
+ (u32) read_phy_reg(pi, 0x488);
+
+cleanup:
+ mod_phy_reg(pi, 0x410, (0x1 << 3), (1) << 3);
+
+ mod_phy_reg(pi, 0x6da, (0x1 << 5), (0) << 5);
+
+ return result;
+}
+
+static bool wlc_lcnphy_calc_rx_iq_comp(struct brcms_phy *pi, u16 num_samps)
+{
+#define LCNPHY_MIN_RXIQ_PWR 2
+ bool result;
+ u16 a0_new, b0_new;
+ struct lcnphy_iq_est iq_est = { 0, 0, 0 };
+ s32 a, b, temp;
+ s16 iq_nbits, qq_nbits, arsh, brsh;
+ s32 iq;
+ u32 ii, qq;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ a0_new = ((read_phy_reg(pi, 0x645) & (0x3ff << 0)) >> 0);
+ b0_new = ((read_phy_reg(pi, 0x646) & (0x3ff << 0)) >> 0);
+ mod_phy_reg(pi, 0x6d1, (0x1 << 2), (0) << 2);
+
+ mod_phy_reg(pi, 0x64b, (0x1 << 6), (1) << 6);
+
+ wlc_lcnphy_set_rx_iq_comp(pi, 0, 0);
+
+ result = wlc_lcnphy_rx_iq_est(pi, num_samps, 32, &iq_est);
+ if (!result)
+ goto cleanup;
+
+ iq = (s32) iq_est.iq_prod;
+ ii = iq_est.i_pwr;
+ qq = iq_est.q_pwr;
+
+ if ((ii + qq) < LCNPHY_MIN_RXIQ_PWR) {
+ result = false;
+ goto cleanup;
+ }
+
+ iq_nbits = wlc_phy_nbits(iq);
+ qq_nbits = wlc_phy_nbits(qq);
+
+ arsh = 10 - (30 - iq_nbits);
+ if (arsh >= 0) {
+ a = (-(iq << (30 - iq_nbits)) + (ii >> (1 + arsh)));
+ temp = (s32) (ii >> arsh);
+ if (temp == 0)
+ return false;
+ } else {
+ a = (-(iq << (30 - iq_nbits)) + (ii << (-1 - arsh)));
+ temp = (s32) (ii << -arsh);
+ if (temp == 0)
+ return false;
+ }
+ a /= temp;
+ brsh = qq_nbits - 31 + 20;
+ if (brsh >= 0) {
+ b = (qq << (31 - qq_nbits));
+ temp = (s32) (ii >> brsh);
+ if (temp == 0)
+ return false;
+ } else {
+ b = (qq << (31 - qq_nbits));
+ temp = (s32) (ii << -brsh);
+ if (temp == 0)
+ return false;
+ }
+ b /= temp;
+ b -= a * a;
+ b = (s32) int_sqrt((unsigned long) b);
+ b -= (1 << 10);
+ a0_new = (u16) (a & 0x3ff);
+ b0_new = (u16) (b & 0x3ff);
+cleanup:
+
+ wlc_lcnphy_set_rx_iq_comp(pi, a0_new, b0_new);
+
+ mod_phy_reg(pi, 0x64b, (0x1 << 0), (1) << 0);
+
+ mod_phy_reg(pi, 0x64b, (0x1 << 3), (1) << 3);
+
+ pi_lcn->lcnphy_cal_results.rxiqcal_coeff_a0 = a0_new;
+ pi_lcn->lcnphy_cal_results.rxiqcal_coeff_b0 = b0_new;
+
+ return result;
+}
+
+static u32 wlc_lcnphy_measure_digital_power(struct brcms_phy *pi, u16 nsamples)
+{
+ struct lcnphy_iq_est iq_est = { 0, 0, 0 };
+
+ if (!wlc_lcnphy_rx_iq_est(pi, nsamples, 32, &iq_est))
+ return 0;
+ return (iq_est.i_pwr + iq_est.q_pwr) / nsamples;
+}
+
+static bool
+wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,
+ const struct lcnphy_rx_iqcomp *iqcomp,
+ int iqcomp_sz, bool tx_switch, bool rx_switch, int module,
+ int tx_gain_idx)
+{
+ struct lcnphy_txgains old_gains;
+ u16 tx_pwr_ctrl;
+ u8 tx_gain_index_old = 0;
+ bool result = false, tx_gain_override_old = false;
+ u16 i, Core1TxControl_old, RFOverride0_old,
+ RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old,
+ rfoverride3_old, rfoverride3val_old, rfoverride4_old,
+ rfoverride4val_old, afectrlovr_old, afectrlovrval_old;
+ int tia_gain;
+ u32 received_power, rx_pwr_threshold;
+ u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;
+ u16 values_to_save[11];
+ s16 *ptr;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC);
+ if (NULL == ptr)
+ return false;
+ if (module == 2) {
+ while (iqcomp_sz--) {
+ if (iqcomp[iqcomp_sz].chan ==
+ CHSPEC_CHANNEL(pi->radio_chanspec)) {
+ wlc_lcnphy_set_rx_iq_comp(pi,
+ (u16)
+ iqcomp[iqcomp_sz].a,
+ (u16)
+ iqcomp[iqcomp_sz].b);
+ result = true;
+ break;
+ }
+ }
+ goto cal_done;
+ }
+
+ if (module == 1) {
+
+ tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
+ wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
+
+ for (i = 0; i < 11; i++)
+ values_to_save[i] =
+ read_radio_reg(pi, rxiq_cal_rf_reg[i]);
+ Core1TxControl_old = read_phy_reg(pi, 0x631);
+
+ or_phy_reg(pi, 0x631, 0x0015);
+
+ RFOverride0_old = read_phy_reg(pi, 0x44c);
+ RFOverrideVal0_old = read_phy_reg(pi, 0x44d);
+ rfoverride2_old = read_phy_reg(pi, 0x4b0);
+ rfoverride2val_old = read_phy_reg(pi, 0x4b1);
+ rfoverride3_old = read_phy_reg(pi, 0x4f9);
+ rfoverride3val_old = read_phy_reg(pi, 0x4fa);
+ rfoverride4_old = read_phy_reg(pi, 0x938);
+ rfoverride4val_old = read_phy_reg(pi, 0x939);
+ afectrlovr_old = read_phy_reg(pi, 0x43b);
+ afectrlovrval_old = read_phy_reg(pi, 0x43c);
+ old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
+ old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
+
+ tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
+ if (tx_gain_override_old) {
+ wlc_lcnphy_get_tx_gain(pi, &old_gains);
+ tx_gain_index_old = pi_lcn->lcnphy_current_index;
+ }
+
+ wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);
+
+ mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
+ mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
+
+ mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
+ mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
+
+ write_radio_reg(pi, RADIO_2064_REG116, 0x06);
+ write_radio_reg(pi, RADIO_2064_REG12C, 0x07);
+ write_radio_reg(pi, RADIO_2064_REG06A, 0xd3);
+ write_radio_reg(pi, RADIO_2064_REG098, 0x03);
+ write_radio_reg(pi, RADIO_2064_REG00B, 0x7);
+ mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4);
+ write_radio_reg(pi, RADIO_2064_REG01D, 0x01);
+ write_radio_reg(pi, RADIO_2064_REG114, 0x01);
+ write_radio_reg(pi, RADIO_2064_REG02E, 0x10);
+ write_radio_reg(pi, RADIO_2064_REG12A, 0x08);
+
+ mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0);
+ mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0);
+ mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1);
+ mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1);
+ mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2);
+ mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2);
+ mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3);
+ mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3);
+ mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5);
+ mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5);
+
+ mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
+ mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
+
+ wlc_lcnphy_start_tx_tone(pi, 2000, 120, 0);
+ write_phy_reg(pi, 0x6da, 0xffff);
+ or_phy_reg(pi, 0x6db, 0x3);
+ wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch);
+ wlc_lcnphy_rx_gain_override_enable(pi, true);
+
+ tia_gain = 8;
+ rx_pwr_threshold = 950;
+ while (tia_gain > 0) {
+ tia_gain -= 1;
+ wlc_lcnphy_set_rx_gain_by_distribution(pi,
+ 0, 0, 2, 2,
+ (u16)
+ tia_gain, 1, 0);
+ udelay(500);
+
+ received_power =
+ wlc_lcnphy_measure_digital_power(pi, 2000);
+ if (received_power < rx_pwr_threshold)
+ break;
+ }
+ result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff);
+
+ wlc_lcnphy_stop_tx_tone(pi);
+
+ write_phy_reg(pi, 0x631, Core1TxControl_old);
+
+ write_phy_reg(pi, 0x44c, RFOverrideVal0_old);
+ write_phy_reg(pi, 0x44d, RFOverrideVal0_old);
+ write_phy_reg(pi, 0x4b0, rfoverride2_old);
+ write_phy_reg(pi, 0x4b1, rfoverride2val_old);
+ write_phy_reg(pi, 0x4f9, rfoverride3_old);
+ write_phy_reg(pi, 0x4fa, rfoverride3val_old);
+ write_phy_reg(pi, 0x938, rfoverride4_old);
+ write_phy_reg(pi, 0x939, rfoverride4val_old);
+ write_phy_reg(pi, 0x43b, afectrlovr_old);
+ write_phy_reg(pi, 0x43c, afectrlovrval_old);
+ write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
+ write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl);
+
+ wlc_lcnphy_clear_trsw_override(pi);
+
+ mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2);
+
+ for (i = 0; i < 11; i++)
+ write_radio_reg(pi, rxiq_cal_rf_reg[i],
+ values_to_save[i]);
+
+ if (tx_gain_override_old)
+ wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old);
+ else
+ wlc_lcnphy_disable_tx_gain_override(pi);
+
+ wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl);
+ wlc_lcnphy_rx_gain_override_enable(pi, false);
+ }
+
+cal_done:
+ kfree(ptr);
+ return result;
+}
+
+s8 wlc_lcnphy_get_current_tx_pwr_idx(struct brcms_phy *pi)
+{
+ s8 index;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ if (txpwrctrl_off(pi))
+ index = pi_lcn->lcnphy_current_index;
+ else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
+ index = (s8) (wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(
+ pi) / 2);
+ else
+ index = pi_lcn->lcnphy_current_index;
+ return index;
+}
+
+void wlc_lcnphy_crsuprs(struct brcms_phy *pi, int channel)
+{
+ u16 afectrlovr, afectrlovrval;
+ afectrlovr = read_phy_reg(pi, 0x43b);
+ afectrlovrval = read_phy_reg(pi, 0x43c);
+ if (channel != 0) {
+ mod_phy_reg(pi, 0x43b, (0x1 << 1), (1) << 1);
+
+ mod_phy_reg(pi, 0x43c, (0x1 << 1), (0) << 1);
+
+ mod_phy_reg(pi, 0x43b, (0x1 << 4), (1) << 4);
+
+ mod_phy_reg(pi, 0x43c, (0x1 << 6), (0) << 6);
+
+ write_phy_reg(pi, 0x44b, 0xffff);
+ wlc_lcnphy_tx_pu(pi, 1);
+
+ mod_phy_reg(pi, 0x634, (0xff << 8), (0) << 8);
+
+ or_phy_reg(pi, 0x6da, 0x0080);
+
+ or_phy_reg(pi, 0x00a, 0x228);
+ } else {
+ and_phy_reg(pi, 0x00a, ~(0x228));
+
+ and_phy_reg(pi, 0x6da, 0xFF7F);
+ write_phy_reg(pi, 0x43b, afectrlovr);
+ write_phy_reg(pi, 0x43c, afectrlovrval);
+ }
+}
+
+static void wlc_lcnphy_toggle_afe_pwdn(struct brcms_phy *pi)
+{
+ u16 save_AfeCtrlOvrVal, save_AfeCtrlOvr;
+
+ save_AfeCtrlOvrVal = read_phy_reg(pi, 0x43c);
+ save_AfeCtrlOvr = read_phy_reg(pi, 0x43b);
+
+ write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal | 0x1);
+ write_phy_reg(pi, 0x43b, save_AfeCtrlOvr | 0x1);
+
+ write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal & 0xfffe);
+ write_phy_reg(pi, 0x43b, save_AfeCtrlOvr & 0xfffe);
+
+ write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal);
+ write_phy_reg(pi, 0x43b, save_AfeCtrlOvr);
+}
+
+static void
+wlc_lcnphy_txrx_spur_avoidance_mode(struct brcms_phy *pi, bool enable)
+{
+ if (enable) {
+ write_phy_reg(pi, 0x942, 0x7);
+ write_phy_reg(pi, 0x93b, ((1 << 13) + 23));
+ write_phy_reg(pi, 0x93c, ((1 << 13) + 1989));
+
+ write_phy_reg(pi, 0x44a, 0x084);
+ write_phy_reg(pi, 0x44a, 0x080);
+ write_phy_reg(pi, 0x6d3, 0x2222);
+ write_phy_reg(pi, 0x6d3, 0x2220);
+ } else {
+ write_phy_reg(pi, 0x942, 0x0);
+ write_phy_reg(pi, 0x93b, ((0 << 13) + 23));
+ write_phy_reg(pi, 0x93c, ((0 << 13) + 1989));
+ }
+ wlapi_switch_macfreq(pi->sh->physhim, enable);
+}
+
+static void
+wlc_lcnphy_set_chanspec_tweaks(struct brcms_phy *pi, u16 chanspec)
+{
+ u8 channel = CHSPEC_CHANNEL(chanspec);
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ if (channel == 14)
+ mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
+ else
+ mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
+
+ pi_lcn->lcnphy_bandedge_corr = 2;
+ if (channel == 1)
+ pi_lcn->lcnphy_bandedge_corr = 4;
+
+ if (channel == 1 || channel == 2 || channel == 3 ||
+ channel == 4 || channel == 9 ||
+ channel == 10 || channel == 11 || channel == 12) {
+ si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03000c04);
+ si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x0);
+ si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x200005c0);
+
+ si_pmu_pllupd(pi->sh->sih);
+ write_phy_reg(pi, 0x942, 0);
+ wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
+ pi_lcn->lcnphy_spurmod = 0;
+ mod_phy_reg(pi, 0x424, (0xff << 8), (0x1b) << 8);
+
+ write_phy_reg(pi, 0x425, 0x5907);
+ } else {
+ si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03140c04);
+ si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x333333);
+ si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x202c2820);
+
+ si_pmu_pllupd(pi->sh->sih);
+ write_phy_reg(pi, 0x942, 0);
+ wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
+
+ pi_lcn->lcnphy_spurmod = 0;
+ mod_phy_reg(pi, 0x424, (0xff << 8), (0x1f) << 8);
+
+ write_phy_reg(pi, 0x425, 0x590a);
+ }
+
+ or_phy_reg(pi, 0x44a, 0x44);
+ write_phy_reg(pi, 0x44a, 0x80);
+}
+
+static void
+wlc_lcnphy_radio_2064_channel_tune_4313(struct brcms_phy *pi, u8 channel)
+{
+ uint i;
+ const struct chan_info_2064_lcnphy *ci;
+ u8 rfpll_doubler = 0;
+ u8 pll_pwrup, pll_pwrup_ovr;
+ s32 qFxtal, qFref, qFvco, qFcal;
+ u8 d15, d16, f16, e44, e45;
+ u32 div_int, div_frac, fvco3, fpfd, fref3, fcal_div;
+ u16 loop_bw, d30, setCount;
+
+ u8 h29, h28_ten, e30, h30_ten, cp_current;
+ u16 g30, d28;
+
+ ci = &chan_info_2064_lcnphy[0];
+ rfpll_doubler = 1;
+
+ mod_radio_reg(pi, RADIO_2064_REG09D, 0x4, 0x1 << 2);
+
+ write_radio_reg(pi, RADIO_2064_REG09E, 0xf);
+ if (!rfpll_doubler) {
+ loop_bw = PLL_2064_LOOP_BW;
+ d30 = PLL_2064_D30;
+ } else {
+ loop_bw = PLL_2064_LOOP_BW_DOUBLER;
+ d30 = PLL_2064_D30_DOUBLER;
+ }
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ for (i = 0; i < ARRAY_SIZE(chan_info_2064_lcnphy); i++)
+ if (chan_info_2064_lcnphy[i].chan == channel)
+ break;
+
+ if (i >= ARRAY_SIZE(chan_info_2064_lcnphy))
+ return;
+
+ ci = &chan_info_2064_lcnphy[i];
+ }
+
+ write_radio_reg(pi, RADIO_2064_REG02A, ci->logen_buftune);
+
+ mod_radio_reg(pi, RADIO_2064_REG030, 0x3, ci->logen_rccr_tx);
+
+ mod_radio_reg(pi, RADIO_2064_REG091, 0x3, ci->txrf_mix_tune_ctrl);
+
+ mod_radio_reg(pi, RADIO_2064_REG038, 0xf, ci->pa_input_tune_g);
+
+ mod_radio_reg(pi, RADIO_2064_REG030, 0x3 << 2,
+ (ci->logen_rccr_rx) << 2);
+
+ mod_radio_reg(pi, RADIO_2064_REG05E, 0xf, ci->pa_rxrf_lna1_freq_tune);
+
+ mod_radio_reg(pi, RADIO_2064_REG05E, (0xf) << 4,
+ (ci->pa_rxrf_lna2_freq_tune) << 4);
+
+ write_radio_reg(pi, RADIO_2064_REG06C, ci->rxrf_rxrf_spare1);
+
+ pll_pwrup = (u8) read_radio_reg(pi, RADIO_2064_REG044);
+ pll_pwrup_ovr = (u8) read_radio_reg(pi, RADIO_2064_REG12B);
+
+ or_radio_reg(pi, RADIO_2064_REG044, 0x07);
+
+ or_radio_reg(pi, RADIO_2064_REG12B, (0x07) << 1);
+ e44 = 0;
+ e45 = 0;
+
+ fpfd = rfpll_doubler ? (pi->xtalfreq << 1) : (pi->xtalfreq);
+ if (pi->xtalfreq > 26000000)
+ e44 = 1;
+ if (pi->xtalfreq > 52000000)
+ e45 = 1;
+ if (e44 == 0)
+ fcal_div = 1;
+ else if (e45 == 0)
+ fcal_div = 2;
+ else
+ fcal_div = 4;
+ fvco3 = (ci->freq * 3);
+ fref3 = 2 * fpfd;
+
+ qFxtal = wlc_lcnphy_qdiv_roundup(pi->xtalfreq, PLL_2064_MHZ, 16);
+ qFref = wlc_lcnphy_qdiv_roundup(fpfd, PLL_2064_MHZ, 16);
+ qFcal = pi->xtalfreq * fcal_div / PLL_2064_MHZ;
+ qFvco = wlc_lcnphy_qdiv_roundup(fvco3, 2, 16);
+
+ write_radio_reg(pi, RADIO_2064_REG04F, 0x02);
+
+ d15 = (pi->xtalfreq * fcal_div * 4 / 5) / PLL_2064_MHZ - 1;
+ write_radio_reg(pi, RADIO_2064_REG052, (0x07 & (d15 >> 2)));
+ write_radio_reg(pi, RADIO_2064_REG053, (d15 & 0x3) << 5);
+
+ d16 = (qFcal * 8 / (d15 + 1)) - 1;
+ write_radio_reg(pi, RADIO_2064_REG051, d16);
+
+ f16 = ((d16 + 1) * (d15 + 1)) / qFcal;
+ setCount = f16 * 3 * (ci->freq) / 32 - 1;
+ mod_radio_reg(pi, RADIO_2064_REG053, (0x0f << 0),
+ (u8) (setCount >> 8));
+
+ or_radio_reg(pi, RADIO_2064_REG053, 0x10);
+ write_radio_reg(pi, RADIO_2064_REG054, (u8) (setCount & 0xff));
+
+ div_int = ((fvco3 * (PLL_2064_MHZ >> 4)) / fref3) << 4;
+
+ div_frac = ((fvco3 * (PLL_2064_MHZ >> 4)) % fref3) << 4;
+ while (div_frac >= fref3) {
+ div_int++;
+ div_frac -= fref3;
+ }
+ div_frac = wlc_lcnphy_qdiv_roundup(div_frac, fref3, 20);
+
+ mod_radio_reg(pi, RADIO_2064_REG045, (0x1f << 0),
+ (u8) (div_int >> 4));
+ mod_radio_reg(pi, RADIO_2064_REG046, (0x1f << 4),
+ (u8) (div_int << 4));
+ mod_radio_reg(pi, RADIO_2064_REG046, (0x0f << 0),
+ (u8) (div_frac >> 16));
+ write_radio_reg(pi, RADIO_2064_REG047, (u8) (div_frac >> 8) & 0xff);
+ write_radio_reg(pi, RADIO_2064_REG048, (u8) div_frac & 0xff);
+
+ write_radio_reg(pi, RADIO_2064_REG040, 0xfb);
+
+ write_radio_reg(pi, RADIO_2064_REG041, 0x9A);
+ write_radio_reg(pi, RADIO_2064_REG042, 0xA3);
+ write_radio_reg(pi, RADIO_2064_REG043, 0x0C);
+
+ h29 = LCN_BW_LMT / loop_bw;
+ d28 = (((PLL_2064_HIGH_END_KVCO - PLL_2064_LOW_END_KVCO) *
+ (fvco3 / 2 - PLL_2064_LOW_END_VCO)) /
+ (PLL_2064_HIGH_END_VCO - PLL_2064_LOW_END_VCO))
+ + PLL_2064_LOW_END_KVCO;
+ h28_ten = (d28 * 10) / LCN_VCO_DIV;
+ e30 = (d30 - LCN_OFFSET) / LCN_FACT;
+ g30 = LCN_OFFSET + (e30 * LCN_FACT);
+ h30_ten = (g30 * 10) / LCN_CUR_DIV;
+ cp_current = ((LCN_CUR_LMT * h29 * LCN_MULT * 100) / h28_ten) / h30_ten;
+ mod_radio_reg(pi, RADIO_2064_REG03C, 0x3f, cp_current);
+
+ if (channel >= 1 && channel <= 5)
+ write_radio_reg(pi, RADIO_2064_REG03C, 0x8);
+ else
+ write_radio_reg(pi, RADIO_2064_REG03C, 0x7);
+ write_radio_reg(pi, RADIO_2064_REG03D, 0x3);
+
+ mod_radio_reg(pi, RADIO_2064_REG044, 0x0c, 0x0c);
+ udelay(1);
+
+ wlc_2064_vco_cal(pi);
+
+ write_radio_reg(pi, RADIO_2064_REG044, pll_pwrup);
+ write_radio_reg(pi, RADIO_2064_REG12B, pll_pwrup_ovr);
+ if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
+ write_radio_reg(pi, RADIO_2064_REG038, 3);
+ write_radio_reg(pi, RADIO_2064_REG091, 7);
+ }
+}
+
+static int
+wlc_lcnphy_load_tx_iir_filter(struct brcms_phy *pi, bool is_ofdm, s16 filt_type)
+{
+ s16 filt_index = -1;
+ int j;
+
+ u16 addr[] = {
+ 0x910,
+ 0x91e,
+ 0x91f,
+ 0x924,
+ 0x925,
+ 0x926,
+ 0x920,
+ 0x921,
+ 0x927,
+ 0x928,
+ 0x929,
+ 0x922,
+ 0x923,
+ 0x930,
+ 0x931,
+ 0x932
+ };
+
+ u16 addr_ofdm[] = {
+ 0x90f,
+ 0x900,
+ 0x901,
+ 0x906,
+ 0x907,
+ 0x908,
+ 0x902,
+ 0x903,
+ 0x909,
+ 0x90a,
+ 0x90b,
+ 0x904,
+ 0x905,
+ 0x90c,
+ 0x90d,
+ 0x90e
+ };
+
+ if (!is_ofdm) {
+ for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_CCK; j++) {
+ if (filt_type == LCNPHY_txdigfiltcoeffs_cck[j][0]) {
+ filt_index = (s16) j;
+ break;
+ }
+ }
+
+ if (filt_index != -1) {
+ for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++)
+ write_phy_reg(pi, addr[j],
+ LCNPHY_txdigfiltcoeffs_cck
+ [filt_index][j + 1]);
+ }
+ } else {
+ for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_OFDM; j++) {
+ if (filt_type == LCNPHY_txdigfiltcoeffs_ofdm[j][0]) {
+ filt_index = (s16) j;
+ break;
+ }
+ }
+
+ if (filt_index != -1) {
+ for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++)
+ write_phy_reg(pi, addr_ofdm[j],
+ LCNPHY_txdigfiltcoeffs_ofdm
+ [filt_index][j + 1]);
+ }
+ }
+
+ return (filt_index != -1) ? 0 : -1;
+}
+
+void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec)
+{
+ u8 channel = CHSPEC_CHANNEL(chanspec);
+
+ wlc_phy_chanspec_radio_set((struct brcms_phy_pub *) pi, chanspec);
+
+ wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec);
+
+ or_phy_reg(pi, 0x44a, 0x44);
+ write_phy_reg(pi, 0x44a, 0x80);
+
+ wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel);
+ udelay(1000);
+
+ wlc_lcnphy_toggle_afe_pwdn(pi);
+
+ write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20);
+ write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor);
+
+ if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) {
+ mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
+
+ wlc_lcnphy_load_tx_iir_filter(pi, false, 3);
+ } else {
+ mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
+
+ wlc_lcnphy_load_tx_iir_filter(pi, false, 2);
+ }
+
+ wlc_lcnphy_load_tx_iir_filter(pi, true, 0);
+
+ mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3);
+
+}
+
+static u16 wlc_lcnphy_get_pa_gain(struct brcms_phy *pi)
+{
+ u16 pa_gain;
+
+ pa_gain = (read_phy_reg(pi, 0x4fb) &
+ LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK) >>
+ LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT;
+
+ return pa_gain;
+}
+
+static void wlc_lcnphy_set_tx_gain(struct brcms_phy *pi,
+ struct lcnphy_txgains *target_gains)
+{
+ u16 pa_gain = wlc_lcnphy_get_pa_gain(pi);
+
+ mod_phy_reg(
+ pi, 0x4b5,
+ (0xffff << 0),
+ ((target_gains->gm_gain) |
+ (target_gains->pga_gain << 8)) <<
+ 0);
+ mod_phy_reg(pi, 0x4fb,
+ (0x7fff << 0),
+ ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
+
+ mod_phy_reg(
+ pi, 0x4fc,
+ (0xffff << 0),
+ ((target_gains->gm_gain) |
+ (target_gains->pga_gain << 8)) <<
+ 0);
+ mod_phy_reg(pi, 0x4fd,
+ (0x7fff << 0),
+ ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
+
+ wlc_lcnphy_set_dac_gain(pi, target_gains->dac_gain);
+
+ wlc_lcnphy_enable_tx_gain_override(pi);
+}
+
+static void wlc_lcnphy_set_bbmult(struct brcms_phy *pi, u8 m0)
+{
+ u16 m0m1 = (u16) m0 << 8;
+ struct phytbl_info tab;
+
+ tab.tbl_ptr = &m0m1;
+ tab.tbl_len = 1;
+ tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
+ tab.tbl_offset = 87;
+ tab.tbl_width = 16;
+ wlc_lcnphy_write_table(pi, &tab);
+}
+
+static void wlc_lcnphy_clear_tx_power_offsets(struct brcms_phy *pi)
+{
+ u32 data_buf[64];
+ struct phytbl_info tab;
+
+ memset(data_buf, 0, sizeof(data_buf));
+
+ tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
+ tab.tbl_width = 32;
+ tab.tbl_ptr = data_buf;
+
+ if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
+
+ tab.tbl_len = 30;
+ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
+ wlc_lcnphy_write_table(pi, &tab);
+ }
+
+ tab.tbl_len = 64;
+ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_MAC_OFFSET;
+ wlc_lcnphy_write_table(pi, &tab);
+}
+
+enum lcnphy_tssi_mode {
+ LCNPHY_TSSI_PRE_PA,
+ LCNPHY_TSSI_POST_PA,
+ LCNPHY_TSSI_EXT
+};
+
+static void
+wlc_lcnphy_set_tssi_mux(struct brcms_phy *pi, enum lcnphy_tssi_mode pos)
+{
+ mod_phy_reg(pi, 0x4d7, (0x1 << 0), (0x1) << 0);
+
+ mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1) << 6);
+
+ if (LCNPHY_TSSI_POST_PA == pos) {
+ mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0) << 2);
+
+ mod_phy_reg(pi, 0x4d9, (0x1 << 3), (1) << 3);
+
+ if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
+ mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
+ } else {
+ mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1);
+ mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
+ }
+ } else {
+ mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2);
+
+ mod_phy_reg(pi, 0x4d9, (0x1 << 3), (0) << 3);
+
+ if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
+ mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
+ } else {
+ mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
+ mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
+ }
+ }
+ mod_phy_reg(pi, 0x637, (0x3 << 14), (0) << 14);
+
+ if (LCNPHY_TSSI_EXT == pos) {
+ write_radio_reg(pi, RADIO_2064_REG07F, 1);
+ mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 0x2);
+ mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 0x1 << 7);
+ mod_radio_reg(pi, RADIO_2064_REG028, 0x1f, 0x3);
+ }
+}
+
+static u16 wlc_lcnphy_rfseq_tbl_adc_pwrup(struct brcms_phy *pi)
+{
+ u16 N1, N2, N3, N4, N5, N6, N;
+ N1 = ((read_phy_reg(pi, 0x4a5) & (0xff << 0))
+ >> 0);
+ N2 = 1 << ((read_phy_reg(pi, 0x4a5) & (0x7 << 12))
+ >> 12);
+ N3 = ((read_phy_reg(pi, 0x40d) & (0xff << 0))
+ >> 0);
+ N4 = 1 << ((read_phy_reg(pi, 0x40d) & (0x7 << 8))
+ >> 8);
+ N5 = ((read_phy_reg(pi, 0x4a2) & (0xff << 0))
+ >> 0);
+ N6 = 1 << ((read_phy_reg(pi, 0x4a2) & (0x7 << 8))
+ >> 8);
+ N = 2 * (N1 + N2 + N3 + N4 + 2 * (N5 + N6)) + 80;
+ if (N < 1600)
+ N = 1600;
+ return N;
+}
+
+static void wlc_lcnphy_pwrctrl_rssiparams(struct brcms_phy *pi)
+{
+ u16 auxpga_vmid, auxpga_vmid_temp, auxpga_gain_temp;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ auxpga_vmid = (2 << 8) |
+ (pi_lcn->lcnphy_rssi_vc << 4) | pi_lcn->lcnphy_rssi_vf;
+ auxpga_vmid_temp = (2 << 8) | (8 << 4) | 4;
+ auxpga_gain_temp = 2;
+
+ mod_phy_reg(pi, 0x4d8, (0x1 << 0), (0) << 0);
+
+ mod_phy_reg(pi, 0x4d8, (0x1 << 1), (0) << 1);
+
+ mod_phy_reg(pi, 0x4d7, (0x1 << 3), (0) << 3);
+
+ mod_phy_reg(pi, 0x4db,
+ (0x3ff << 0) |
+ (0x7 << 12),
+ (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
+
+ mod_phy_reg(pi, 0x4dc,
+ (0x3ff << 0) |
+ (0x7 << 12),
+ (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
+
+ mod_phy_reg(pi, 0x40a,
+ (0x3ff << 0) |
+ (0x7 << 12),
+ (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
+
+ mod_phy_reg(pi, 0x40b,
+ (0x3ff << 0) |
+ (0x7 << 12),
+ (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
+
+ mod_phy_reg(pi, 0x40c,
+ (0x3ff << 0) |
+ (0x7 << 12),
+ (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
+
+ mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5));
+}
+
+static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)
+{
+ struct phytbl_info tab;
+ u32 rfseq, ind;
+
+ tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
+ tab.tbl_width = 32;
+ tab.tbl_ptr = &ind;
+ tab.tbl_len = 1;
+ tab.tbl_offset = 0;
+ for (ind = 0; ind < 128; ind++) {
+ wlc_lcnphy_write_table(pi, &tab);
+ tab.tbl_offset++;
+ }
+ tab.tbl_offset = 704;
+ for (ind = 0; ind < 128; ind++) {
+ wlc_lcnphy_write_table(pi, &tab);
+ tab.tbl_offset++;
+ }
+ mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
+
+ mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
+
+ mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4);
+
+ wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT);
+ mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
+
+ mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15);
+
+ mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
+
+ mod_phy_reg(pi, 0x4a4, (0x1ff << 0), (0) << 0);
+
+ mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
+
+ mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
+
+ mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
+
+ mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
+
+ mod_phy_reg(pi, 0x40d, (0x7 << 8), (4) << 8);
+
+ mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
+
+ mod_phy_reg(pi, 0x4a2, (0x7 << 8), (4) << 8);
+
+ mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (0) << 6);
+
+ mod_phy_reg(pi, 0x4a8, (0xff << 0), (0x1) << 0);
+
+ wlc_lcnphy_clear_tx_power_offsets(pi);
+
+ mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
+
+ mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (0xff) << 0);
+
+ mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0);
+
+ if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
+ mod_radio_reg(pi, RADIO_2064_REG028, 0xf, 0xe);
+ mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
+ } else {
+ mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
+ mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3);
+ }
+
+ write_radio_reg(pi, RADIO_2064_REG025, 0xc);
+
+ if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
+ mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
+ } else {
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
+ else
+ mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 0 << 1);
+ }
+
+ if (LCNREV_IS(pi->pubpi.phy_rev, 2))
+ mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
+ else
+ mod_radio_reg(pi, RADIO_2064_REG03A, 0x4, 1 << 2);
+
+ mod_radio_reg(pi, RADIO_2064_REG11A, 0x1, 1 << 0);
+
+ mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 1 << 3);
+
+ if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
+ mod_phy_reg(pi, 0x4d7,
+ (0x1 << 3) | (0x7 << 12), 0 << 3 | 2 << 12);
+
+ rfseq = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
+ tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
+ tab.tbl_width = 16;
+ tab.tbl_ptr = &rfseq;
+ tab.tbl_len = 1;
+ tab.tbl_offset = 6;
+ wlc_lcnphy_write_table(pi, &tab);
+
+ mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
+
+ mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
+
+ mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
+
+ mod_phy_reg(pi, 0x4d7, (0x1 << 2), (1) << 2);
+
+ mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8);
+
+ wlc_lcnphy_pwrctrl_rssiparams(pi);
+}
+
+void wlc_lcnphy_tx_pwr_update_npt(struct brcms_phy *pi)
+{
+ u16 tx_cnt, tx_total, npt;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ tx_total = wlc_lcnphy_total_tx_frames(pi);
+ tx_cnt = tx_total - pi_lcn->lcnphy_tssi_tx_cnt;
+ npt = wlc_lcnphy_get_tx_pwr_npt(pi);
+
+ if (tx_cnt > (1 << npt)) {
+
+ pi_lcn->lcnphy_tssi_tx_cnt = tx_total;
+
+ pi_lcn->lcnphy_tssi_idx = wlc_lcnphy_get_current_tx_pwr_idx(pi);
+ pi_lcn->lcnphy_tssi_npt = npt;
+
+ }
+}
+
+s32 wlc_lcnphy_tssi2dbm(s32 tssi, s32 a1, s32 b0, s32 b1)
+{
+ s32 a, b, p;
+
+ a = 32768 + (a1 * tssi);
+ b = (1024 * b0) + (64 * b1 * tssi);
+ p = ((2 * b) + a) / (2 * a);
+
+ return p;
+}
+
+static void wlc_lcnphy_txpower_reset_npt(struct brcms_phy *pi)
+{
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+ if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
+ return;
+
+ pi_lcn->lcnphy_tssi_idx = LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313;
+ pi_lcn->lcnphy_tssi_npt = LCNPHY_TX_PWR_CTRL_START_NPT;
+}
+
+void wlc_lcnphy_txpower_recalc_target(struct brcms_phy *pi)
+{
+ struct phytbl_info tab;
+ u32 rate_table[BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM +
+ BRCMS_NUM_RATES_MCS_1_STREAM];
+ uint i, j;
+ if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
+ return;
+
+ for (i = 0, j = 0; i < ARRAY_SIZE(rate_table); i++, j++) {
+
+ if (i == BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM)
+ j = TXP_FIRST_MCS_20_SISO;
+
+ rate_table[i] = (u32) ((s32) (-pi->tx_power_offset[j]));
+ }
+
+ tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
+ tab.tbl_width = 32;
+ tab.tbl_len = ARRAY_SIZE(rate_table);
+ tab.tbl_ptr = rate_table;
+ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
+ wlc_lcnphy_write_table(pi, &tab);
+
+ if (wlc_lcnphy_get_target_tx_pwr(pi) != pi->tx_power_min) {
+ wlc_lcnphy_set_target_tx_pwr(pi, pi->tx_power_min);
+
+ wlc_lcnphy_txpower_reset_npt(pi);
+ }
+}
+
+static void wlc_lcnphy_set_tx_pwr_soft_ctrl(struct brcms_phy *pi, s8 index)
+{
+ u32 cck_offset[4] = { 22, 22, 22, 22 };
+ u32 ofdm_offset, reg_offset_cck;
+ int i;
+ u16 index2;
+ struct phytbl_info tab;
+
+ if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
+ return;
+
+ mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
+
+ mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x0) << 14);
+
+ or_phy_reg(pi, 0x6da, 0x0040);
+
+ reg_offset_cck = 0;
+ for (i = 0; i < 4; i++)
+ cck_offset[i] -= reg_offset_cck;
+ tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
+ tab.tbl_width = 32;
+ tab.tbl_len = 4;
+ tab.tbl_ptr = cck_offset;
+ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
+ wlc_lcnphy_write_table(pi, &tab);
+ ofdm_offset = 0;
+ tab.tbl_len = 1;
+ tab.tbl_ptr = &ofdm_offset;
+ for (i = 836; i < 862; i++) {
+ tab.tbl_offset = i;
+ wlc_lcnphy_write_table(pi, &tab);
+ }
+
+ mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0x1) << 15);
+
+ mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
+
+ mod_phy_reg(pi, 0x4a4, (0x1 << 13), (0x1) << 13);
+
+ mod_phy_reg(pi, 0x4b0, (0x1 << 7), (0) << 7);
+
+ mod_phy_reg(pi, 0x43b, (0x1 << 6), (0) << 6);
+
+ mod_phy_reg(pi, 0x4a9, (0x1 << 15), (1) << 15);
+
+ index2 = (u16) (index * 2);
+ mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
+
+ mod_phy_reg(pi, 0x6a3, (0x1 << 4), (0) << 4);
+
+}
+
+static s8 wlc_lcnphy_tempcompensated_txpwrctrl(struct brcms_phy *pi)
+{
+ s8 index, delta_brd, delta_temp, new_index, tempcorrx;
+ s16 manp, meas_temp, temp_diff;
+ bool neg = 0;
+ u16 temp;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
+ return pi_lcn->lcnphy_current_index;
+
+ index = FIXED_TXPWR;
+
+ if (pi_lcn->lcnphy_tempsense_slope == 0)
+ return index;
+
+ temp = (u16) wlc_lcnphy_tempsense(pi, 0);
+ meas_temp = LCNPHY_TEMPSENSE(temp);
+
+ if (pi->tx_power_min != 0)
+ delta_brd = (pi_lcn->lcnphy_measPower - pi->tx_power_min);
+ else
+ delta_brd = 0;
+
+ manp = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_rawtempsense);
+ temp_diff = manp - meas_temp;
+ if (temp_diff < 0) {
+ neg = 1;
+ temp_diff = -temp_diff;
+ }
+
+ delta_temp = (s8) wlc_lcnphy_qdiv_roundup((u32) (temp_diff * 192),
+ (u32) (pi_lcn->
+ lcnphy_tempsense_slope
+ * 10), 0);
+ if (neg)
+ delta_temp = -delta_temp;
+
+ if (pi_lcn->lcnphy_tempsense_option == 3
+ && LCNREV_IS(pi->pubpi.phy_rev, 0))
+ delta_temp = 0;
+ if (pi_lcn->lcnphy_tempcorrx > 31)
+ tempcorrx = (s8) (pi_lcn->lcnphy_tempcorrx - 64);
+ else
+ tempcorrx = (s8) pi_lcn->lcnphy_tempcorrx;
+ if (LCNREV_IS(pi->pubpi.phy_rev, 1))
+ tempcorrx = 4;
+ new_index =
+ index + delta_brd + delta_temp - pi_lcn->lcnphy_bandedge_corr;
+ new_index += tempcorrx;
+
+ if (LCNREV_IS(pi->pubpi.phy_rev, 1))
+ index = 127;
+
+ if (new_index < 0 || new_index > 126)
+ return index;
+
+ return new_index;
+}
+
+static u16 wlc_lcnphy_set_tx_pwr_ctrl_mode(struct brcms_phy *pi, u16 mode)
+{
+
+ u16 current_mode = mode;
+ if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
+ mode == LCNPHY_TX_PWR_CTRL_HW)
+ current_mode = LCNPHY_TX_PWR_CTRL_TEMPBASED;
+ if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
+ mode == LCNPHY_TX_PWR_CTRL_TEMPBASED)
+ current_mode = LCNPHY_TX_PWR_CTRL_HW;
+ return current_mode;
+}
+
+void wlc_lcnphy_set_tx_pwr_ctrl(struct brcms_phy *pi, u16 mode)
+{
+ u16 old_mode = wlc_lcnphy_get_tx_pwr_ctrl(pi);
+ s8 index;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, mode);
+ old_mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, old_mode);
+
+ mod_phy_reg(pi, 0x6da, (0x1 << 6),
+ ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 1 : 0) << 6);
+
+ mod_phy_reg(pi, 0x6a3, (0x1 << 4),
+ ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 0 : 1) << 4);
+
+ if (old_mode != mode) {
+ if (LCNPHY_TX_PWR_CTRL_HW == old_mode) {
+
+ wlc_lcnphy_tx_pwr_update_npt(pi);
+
+ wlc_lcnphy_clear_tx_power_offsets(pi);
+ }
+ if (LCNPHY_TX_PWR_CTRL_HW == mode) {
+
+ wlc_lcnphy_txpower_recalc_target(pi);
+
+ wlc_lcnphy_set_start_tx_pwr_idx(pi,
+ pi_lcn->
+ lcnphy_tssi_idx);
+ wlc_lcnphy_set_tx_pwr_npt(pi, pi_lcn->lcnphy_tssi_npt);
+ mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0);
+
+ pi_lcn->lcnphy_tssi_tx_cnt =
+ wlc_lcnphy_total_tx_frames(pi);
+
+ wlc_lcnphy_disable_tx_gain_override(pi);
+ pi_lcn->lcnphy_tx_power_idx_override = -1;
+ } else
+ wlc_lcnphy_enable_tx_gain_override(pi);
+
+ mod_phy_reg(pi, 0x4a4,
+ ((0x1 << 15) | (0x1 << 14) | (0x1 << 13)), mode);
+ if (mode == LCNPHY_TX_PWR_CTRL_TEMPBASED) {
+ index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
+ wlc_lcnphy_set_tx_pwr_soft_ctrl(pi, index);
+ pi_lcn->lcnphy_current_index = (s8)
+ ((read_phy_reg(pi,
+ 0x4a9) &
+ 0xFF) / 2);
+ }
+ }
+}
+
+static void
+wlc_lcnphy_tx_iqlo_loopback(struct brcms_phy *pi, u16 *values_to_save)
+{
+ u16 vmid;
+ int i;
+ for (i = 0; i < 20; i++)
+ values_to_save[i] =
+ read_radio_reg(pi, iqlo_loopback_rf_regs[i]);
+
+ mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
+ mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
+
+ mod_phy_reg(pi, 0x44c, (0x1 << 11), 1 << 11);
+ mod_phy_reg(pi, 0x44d, (0x1 << 13), 0 << 13);
+
+ mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
+ mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
+
+ mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
+ mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
+
+ if (LCNREV_IS(pi->pubpi.phy_rev, 2))
+ and_radio_reg(pi, RADIO_2064_REG03A, 0xFD);
+ else
+ and_radio_reg(pi, RADIO_2064_REG03A, 0xF9);
+ or_radio_reg(pi, RADIO_2064_REG11A, 0x1);
+
+ or_radio_reg(pi, RADIO_2064_REG036, 0x01);
+ or_radio_reg(pi, RADIO_2064_REG11A, 0x18);
+ udelay(20);
+
+ if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
+ if (CHSPEC_IS5G(pi->radio_chanspec))
+ mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
+ else
+ or_radio_reg(pi, RADIO_2064_REG03A, 1);
+ } else {
+ if (CHSPEC_IS5G(pi->radio_chanspec))
+ mod_radio_reg(pi, RADIO_2064_REG03A, 3, 1);
+ else
+ or_radio_reg(pi, RADIO_2064_REG03A, 0x3);
+ }
+
+ udelay(20);
+
+ write_radio_reg(pi, RADIO_2064_REG025, 0xF);
+ if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
+ if (CHSPEC_IS5G(pi->radio_chanspec))
+ mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x4);
+ else
+ mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x6);
+ } else {
+ if (CHSPEC_IS5G(pi->radio_chanspec))
+ mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x4 << 1);
+ else
+ mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x6 << 1);
+ }
+
+ udelay(20);
+
+ write_radio_reg(pi, RADIO_2064_REG005, 0x8);
+ or_radio_reg(pi, RADIO_2064_REG112, 0x80);
+ udelay(20);
+
+ or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
+ or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
+ udelay(20);
+
+ or_radio_reg(pi, RADIO_2064_REG00B, 0x7);
+ or_radio_reg(pi, RADIO_2064_REG113, 0x10);
+ udelay(20);
+
+ write_radio_reg(pi, RADIO_2064_REG007, 0x1);
+ udelay(20);
+
+ vmid = 0x2A6;
+ mod_radio_reg(pi, RADIO_2064_REG0FC, 0x3 << 0, (vmid >> 8) & 0x3);
+ write_radio_reg(pi, RADIO_2064_REG0FD, (vmid & 0xff));
+ or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
+ udelay(20);
+
+ or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
+ udelay(20);
+ write_radio_reg(pi, RADIO_2064_REG012, 0x02);
+ or_radio_reg(pi, RADIO_2064_REG112, 0x06);
+ write_radio_reg(pi, RADIO_2064_REG036, 0x11);
+ write_radio_reg(pi, RADIO_2064_REG059, 0xcc);
+ write_radio_reg(pi, RADIO_2064_REG05C, 0x2e);
+ write_radio_reg(pi, RADIO_2064_REG078, 0xd7);
+ write_radio_reg(pi, RADIO_2064_REG092, 0x15);
+}
+
+static bool wlc_lcnphy_iqcal_wait(struct brcms_phy *pi)
+{
+ uint delay_count = 0;
+
+ while (wlc_lcnphy_iqcal_active(pi)) {
+ udelay(100);
+ delay_count++;
+
+ if (delay_count > (10 * 500))
+ break;
+ }
+
+ return (0 == wlc_lcnphy_iqcal_active(pi));
+}
+
+static void
+wlc_lcnphy_tx_iqlo_loopback_cleanup(struct brcms_phy *pi, u16 *values_to_save)
+{
+ int i;
+
+ and_phy_reg(pi, 0x44c, 0x0 >> 11);
+
+ and_phy_reg(pi, 0x43b, 0xC);
+
+ for (i = 0; i < 20; i++)
+ write_radio_reg(pi, iqlo_loopback_rf_regs[i],
+ values_to_save[i]);
+}
+
+static void
+wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi,
+ struct lcnphy_txgains *target_gains,
+ enum lcnphy_cal_mode cal_mode, bool keep_tone)
+{
+
+ struct lcnphy_txgains cal_gains, temp_gains;
+ u16 hash;
+ u8 band_idx;
+ int j;
+ u16 ncorr_override[5];
+ u16 syst_coeffs[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000};
+
+ u16 commands_fullcal[] = {
+ 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234
+ };
+
+ u16 commands_recal[] = {
+ 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234
+ };
+
+ u16 command_nums_fullcal[] = {
+ 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97
+ };
+
+ u16 command_nums_recal[] = {
+ 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97
+ };
+ u16 *command_nums = command_nums_fullcal;
+
+ u16 *start_coeffs = NULL, *cal_cmds = NULL, cal_type, diq_start;
+ u16 tx_pwr_ctrl_old, save_txpwrctrlrfctrl2;
+ u16 save_sslpnCalibClkEnCtrl, save_sslpnRxFeClkEnCtrl;
+ bool tx_gain_override_old;
+ struct lcnphy_txgains old_gains;
+ uint i, n_cal_cmds = 0, n_cal_start = 0;
+ u16 *values_to_save;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ values_to_save = kmalloc(sizeof(u16) * 20, GFP_ATOMIC);
+ if (NULL == values_to_save)
+ return;
+
+ save_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
+ save_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
+
+ or_phy_reg(pi, 0x6da, 0x40);
+ or_phy_reg(pi, 0x6db, 0x3);
+
+ switch (cal_mode) {
+ case LCNPHY_CAL_FULL:
+ start_coeffs = syst_coeffs;
+ cal_cmds = commands_fullcal;
+ n_cal_cmds = ARRAY_SIZE(commands_fullcal);
+ break;
+
+ case LCNPHY_CAL_RECAL:
+ start_coeffs = syst_coeffs;
+ cal_cmds = commands_recal;
+ n_cal_cmds = ARRAY_SIZE(commands_recal);
+ command_nums = command_nums_recal;
+ break;
+
+ default:
+ break;
+ }
+
+ wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
+ start_coeffs, 11, 16, 64);
+
+ write_phy_reg(pi, 0x6da, 0xffff);
+ mod_phy_reg(pi, 0x503, (0x1 << 3), (1) << 3);
+
+ tx_pwr_ctrl_old = wlc_lcnphy_get_tx_pwr_ctrl(pi);
+
+ mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
+
+ wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
+
+ save_txpwrctrlrfctrl2 = read_phy_reg(pi, 0x4db);
+
+ mod_phy_reg(pi, 0x4db, (0x3ff << 0), (0x2a6) << 0);
+
+ mod_phy_reg(pi, 0x4db, (0x7 << 12), (2) << 12);
+
+ wlc_lcnphy_tx_iqlo_loopback(pi, values_to_save);
+
+ tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
+ if (tx_gain_override_old)
+ wlc_lcnphy_get_tx_gain(pi, &old_gains);
+
+ if (!target_gains) {
+ if (!tx_gain_override_old)
+ wlc_lcnphy_set_tx_pwr_by_index(pi,
+ pi_lcn->lcnphy_tssi_idx);
+ wlc_lcnphy_get_tx_gain(pi, &temp_gains);
+ target_gains = &temp_gains;
+ }
+
+ hash = (target_gains->gm_gain << 8) |
+ (target_gains->pga_gain << 4) | (target_gains->pad_gain);
+
+ band_idx = (CHSPEC_IS5G(pi->radio_chanspec) ? 1 : 0);
+
+ cal_gains = *target_gains;
+ memset(ncorr_override, 0, sizeof(ncorr_override));
+ for (j = 0; j < iqcal_gainparams_numgains_lcnphy[band_idx]; j++) {
+ if (hash == tbl_iqcal_gainparams_lcnphy[band_idx][j][0]) {
+ cal_gains.gm_gain =
+ tbl_iqcal_gainparams_lcnphy[band_idx][j][1];
+ cal_gains.pga_gain =
+ tbl_iqcal_gainparams_lcnphy[band_idx][j][2];
+ cal_gains.pad_gain =
+ tbl_iqcal_gainparams_lcnphy[band_idx][j][3];
+ memcpy(ncorr_override,
+ &tbl_iqcal_gainparams_lcnphy[band_idx][j][3],
+ sizeof(ncorr_override));
+ break;
+ }
+ }
+
+ wlc_lcnphy_set_tx_gain(pi, &cal_gains);
+
+ write_phy_reg(pi, 0x453, 0xaa9);
+ write_phy_reg(pi, 0x93d, 0xc0);
+
+ wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
+ lcnphy_iqcal_loft_gainladder,
+ ARRAY_SIZE(lcnphy_iqcal_loft_gainladder),
+ 16, 0);
+
+ wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
+ lcnphy_iqcal_ir_gainladder,
+ ARRAY_SIZE(
+ lcnphy_iqcal_ir_gainladder), 16,
+ 32);
+
+ if (pi->phy_tx_tone_freq) {
+
+ wlc_lcnphy_stop_tx_tone(pi);
+ udelay(5);
+ wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
+ } else {
+ wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
+ }
+
+ write_phy_reg(pi, 0x6da, 0xffff);
+
+ for (i = n_cal_start; i < n_cal_cmds; i++) {
+ u16 zero_diq = 0;
+ u16 best_coeffs[11];
+ u16 command_num;
+
+ cal_type = (cal_cmds[i] & 0x0f00) >> 8;
+
+ command_num = command_nums[i];
+ if (ncorr_override[cal_type])
+ command_num =
+ ncorr_override[cal_type] << 8 | (command_num &
+ 0xff);
+
+ write_phy_reg(pi, 0x452, command_num);
+
+ if ((cal_type == 3) || (cal_type == 4)) {
+ wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
+ &diq_start, 1, 16, 69);
+
+ wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
+ &zero_diq, 1, 16, 69);
+ }
+
+ write_phy_reg(pi, 0x451, cal_cmds[i]);
+
+ if (!wlc_lcnphy_iqcal_wait(pi))
+ goto cleanup;
+
+ wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
+ best_coeffs,
+ ARRAY_SIZE(best_coeffs), 16, 96);
+ wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
+ best_coeffs,
+ ARRAY_SIZE(best_coeffs), 16, 64);
+
+ if ((cal_type == 3) || (cal_type == 4))
+ wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
+ &diq_start, 1, 16, 69);
+ wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
+ pi_lcn->lcnphy_cal_results.
+ txiqlocal_bestcoeffs,
+ ARRAY_SIZE(pi_lcn->
+ lcnphy_cal_results.
+ txiqlocal_bestcoeffs),
+ 16, 96);
+ }
+
+ wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
+ pi_lcn->lcnphy_cal_results.
+ txiqlocal_bestcoeffs,
+ ARRAY_SIZE(pi_lcn->lcnphy_cal_results.
+ txiqlocal_bestcoeffs), 16, 96);
+ pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid = true;
+
+ wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
+ &pi_lcn->lcnphy_cal_results.
+ txiqlocal_bestcoeffs[0], 4, 16, 80);
+
+ wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
+ &pi_lcn->lcnphy_cal_results.
+ txiqlocal_bestcoeffs[5], 2, 16, 85);
+
+cleanup:
+ wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, values_to_save);
+ kfree(values_to_save);
+
+ if (!keep_tone)
+ wlc_lcnphy_stop_tx_tone(pi);
+
+ write_phy_reg(pi, 0x4db, save_txpwrctrlrfctrl2);
+
+ write_phy_reg(pi, 0x453, 0);
+
+ if (tx_gain_override_old)
+ wlc_lcnphy_set_tx_gain(pi, &old_gains);
+ wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl_old);
+
+ write_phy_reg(pi, 0x6da, save_sslpnCalibClkEnCtrl);
+ write_phy_reg(pi, 0x6db, save_sslpnRxFeClkEnCtrl);
+
+}
+
+static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)
+{
+ bool suspend, tx_gain_override_old;
+ struct lcnphy_txgains old_gains;
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ u16 idleTssi, idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB,
+ idleTssi0_regvalue_2C;
+ u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
+ u16 SAVE_lpfgain = read_radio_reg(pi, RADIO_2064_REG112);
+ u16 SAVE_jtag_bb_afe_switch =
+ read_radio_reg(pi, RADIO_2064_REG007) & 1;
+ u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10;
+ u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4;
+ idleTssi = read_phy_reg(pi, 0x4ab);
+ suspend =
+ (0 ==
+ (R_REG(&((struct brcms_phy *) pi)->regs->maccontrol) &
+ MCTL_EN_MAC));
+ if (!suspend)
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+ wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
+
+ tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
+ wlc_lcnphy_get_tx_gain(pi, &old_gains);
+
+ wlc_lcnphy_enable_tx_gain_override(pi);
+ wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
+ write_radio_reg(pi, RADIO_2064_REG112, 0x6);
+ mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 1);
+ mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4);
+ mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2);
+ wlc_lcnphy_tssi_setup(pi);
+ wlc_phy_do_dummy_tx(pi, true, OFF);
+ idleTssi = ((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
+ >> 0);
+
+ idleTssi0_2C = ((read_phy_reg(pi, 0x63e) & (0x1ff << 0))
+ >> 0);
+
+ if (idleTssi0_2C >= 256)
+ idleTssi0_OB = idleTssi0_2C - 256;
+ else
+ idleTssi0_OB = idleTssi0_2C + 256;
+
+ idleTssi0_regvalue_OB = idleTssi0_OB;
+ if (idleTssi0_regvalue_OB >= 256)
+ idleTssi0_regvalue_2C = idleTssi0_regvalue_OB - 256;
+ else
+ idleTssi0_regvalue_2C = idleTssi0_regvalue_OB + 256;
+ mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (idleTssi0_regvalue_2C) << 0);
+
+ mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12);
+
+ wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old);
+ wlc_lcnphy_set_tx_gain(pi, &old_gains);
+ wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
+
+ write_radio_reg(pi, RADIO_2064_REG112, SAVE_lpfgain);
+ mod_radio_reg(pi, RADIO_2064_REG007, 0x1, SAVE_jtag_bb_afe_switch);
+ mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, SAVE_jtag_auxpga);
+ mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, SAVE_iqadc_aux_en);
+ mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1 << 7);
+ if (!suspend)
+ wlapi_enable_mac(pi->sh->physhim);
+}
+
+static void wlc_lcnphy_vbat_temp_sense_setup(struct brcms_phy *pi, u8 mode)
+{
+ bool suspend;
+ u16 save_txpwrCtrlEn;
+ u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain;
+ u16 auxpga_vmid;
+ struct phytbl_info tab;
+ u32 val;
+ u8 save_reg007, save_reg0FF, save_reg11F, save_reg005, save_reg025,
+ save_reg112;
+ u16 values_to_save[14];
+ s8 index;
+ int i;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+ udelay(999);
+
+ save_reg007 = (u8) read_radio_reg(pi, RADIO_2064_REG007);
+ save_reg0FF = (u8) read_radio_reg(pi, RADIO_2064_REG0FF);
+ save_reg11F = (u8) read_radio_reg(pi, RADIO_2064_REG11F);
+ save_reg005 = (u8) read_radio_reg(pi, RADIO_2064_REG005);
+ save_reg025 = (u8) read_radio_reg(pi, RADIO_2064_REG025);
+ save_reg112 = (u8) read_radio_reg(pi, RADIO_2064_REG112);
+
+ for (i = 0; i < 14; i++)
+ values_to_save[i] = read_phy_reg(pi, tempsense_phy_regs[i]);
+ suspend = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
+ if (!suspend)
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+ save_txpwrCtrlEn = read_radio_reg(pi, 0x4a4);
+
+ wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
+ index = pi_lcn->lcnphy_current_index;
+ wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
+ mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 0x1);
+ mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 0x1 << 4);
+ mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0x1 << 2);
+ mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
+
+ mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
+
+ mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
+
+ mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0) << 15);
+
+ mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
+
+ mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
+
+ mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
+
+ mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
+
+ mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
+
+ mod_phy_reg(pi, 0x40d, (0x7 << 8), (6) << 8);
+
+ mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
+
+ mod_phy_reg(pi, 0x4a2, (0x7 << 8), (6) << 8);
+
+ mod_phy_reg(pi, 0x4d9, (0x7 << 4), (2) << 4);
+
+ mod_phy_reg(pi, 0x4d9, (0x7 << 8), (3) << 8);
+
+ mod_phy_reg(pi, 0x4d9, (0x7 << 12), (1) << 12);
+
+ mod_phy_reg(pi, 0x4da, (0x1 << 12), (0) << 12);
+
+ mod_phy_reg(pi, 0x4da, (0x1 << 13), (1) << 13);
+
+ mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
+
+ write_radio_reg(pi, RADIO_2064_REG025, 0xC);
+
+ mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 0x1 << 3);
+
+ mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
+
+ mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
+
+ mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
+
+ val = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
+ tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
+ tab.tbl_width = 16;
+ tab.tbl_len = 1;
+ tab.tbl_ptr = &val;
+ tab.tbl_offset = 6;
+ wlc_lcnphy_write_table(pi, &tab);
+ if (mode == TEMPSENSE) {
+ mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
+
+ mod_phy_reg(pi, 0x4d7, (0x7 << 12), (1) << 12);
+
+ auxpga_vmidcourse = 8;
+ auxpga_vmidfine = 0x4;
+ auxpga_gain = 2;
+ mod_radio_reg(pi, RADIO_2064_REG082, 0x20, 1 << 5);
+ } else {
+ mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
+
+ mod_phy_reg(pi, 0x4d7, (0x7 << 12), (3) << 12);
+
+ auxpga_vmidcourse = 7;
+ auxpga_vmidfine = 0xa;
+ auxpga_gain = 2;
+ }
+ auxpga_vmid =
+ (u16) ((2 << 8) | (auxpga_vmidcourse << 4) | auxpga_vmidfine);
+ mod_phy_reg(pi, 0x4d8, (0x1 << 0), (1) << 0);
+
+ mod_phy_reg(pi, 0x4d8, (0x3ff << 2), (auxpga_vmid) << 2);
+
+ mod_phy_reg(pi, 0x4d8, (0x1 << 1), (1) << 1);
+
+ mod_phy_reg(pi, 0x4d8, (0x7 << 12), (auxpga_gain) << 12);
+
+ mod_phy_reg(pi, 0x4d0, (0x1 << 5), (1) << 5);
+
+ write_radio_reg(pi, RADIO_2064_REG112, 0x6);
+
+ wlc_phy_do_dummy_tx(pi, true, OFF);
+ if (!tempsense_done(pi))
+ udelay(10);
+
+ write_radio_reg(pi, RADIO_2064_REG007, (u16) save_reg007);
+ write_radio_reg(pi, RADIO_2064_REG0FF, (u16) save_reg0FF);
+ write_radio_reg(pi, RADIO_2064_REG11F, (u16) save_reg11F);
+ write_radio_reg(pi, RADIO_2064_REG005, (u16) save_reg005);
+ write_radio_reg(pi, RADIO_2064_REG025, (u16) save_reg025);
+ write_radio_reg(pi, RADIO_2064_REG112, (u16) save_reg112);
+ for (i = 0; i < 14; i++)
+ write_phy_reg(pi, tempsense_phy_regs[i], values_to_save[i]);
+ wlc_lcnphy_set_tx_pwr_by_index(pi, (int)index);
+
+ write_radio_reg(pi, 0x4a4, save_txpwrCtrlEn);
+ if (!suspend)
+ wlapi_enable_mac(pi->sh->physhim);
+ udelay(999);
+}
+
+static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi)
+{
+ struct lcnphy_txgains tx_gains;
+ u8 bbmult;
+ struct phytbl_info tab;
+ s32 a1, b0, b1;
+ s32 tssi, pwr, maxtargetpwr, mintargetpwr;
+ bool suspend;
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+
+ suspend =
+ (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
+ if (!suspend)
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+
+ if (!pi->hwpwrctrl_capable) {
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ tx_gains.gm_gain = 4;
+ tx_gains.pga_gain = 12;
+ tx_gains.pad_gain = 12;
+ tx_gains.dac_gain = 0;
+
+ bbmult = 150;
+ } else {
+ tx_gains.gm_gain = 7;
+ tx_gains.pga_gain = 15;
+ tx_gains.pad_gain = 14;
+ tx_gains.dac_gain = 0;
+
+ bbmult = 150;
+ }
+ wlc_lcnphy_set_tx_gain(pi, &tx_gains);
+ wlc_lcnphy_set_bbmult(pi, bbmult);
+ wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
+ } else {
+
+ wlc_lcnphy_idle_tssi_est(ppi);
+
+ wlc_lcnphy_clear_tx_power_offsets(pi);
+
+ b0 = pi->txpa_2g[0];
+ b1 = pi->txpa_2g[1];
+ a1 = pi->txpa_2g[2];
+ maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
+ mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
+
+ tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
+ tab.tbl_width = 32;
+ tab.tbl_ptr = &pwr;
+ tab.tbl_len = 1;
+ tab.tbl_offset = 0;
+ for (tssi = 0; tssi < 128; tssi++) {
+ pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
+
+ pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
+ wlc_lcnphy_write_table(pi, &tab);
+ tab.tbl_offset++;
+ }
+
+ mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7);
+
+ write_phy_reg(pi, 0x4a8, 10);
+
+ wlc_lcnphy_set_target_tx_pwr(pi, LCN_TARGET_PWR);
+
+ wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
+ }
+ if (!suspend)
+ wlapi_enable_mac(pi->sh->physhim);
+}
+
+static u8 wlc_lcnphy_get_bbmult(struct brcms_phy *pi)
+{
+ u16 m0m1;
+ struct phytbl_info tab;
+
+ tab.tbl_ptr = &m0m1;
+ tab.tbl_len = 1;
+ tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
+ tab.tbl_offset = 87;
+ tab.tbl_width = 16;
+ wlc_lcnphy_read_table(pi, &tab);
+
+ return (u8) ((m0m1 & 0xff00) >> 8);
+}
+
+static void wlc_lcnphy_set_pa_gain(struct brcms_phy *pi, u16 gain)
+{
+ mod_phy_reg(pi, 0x4fb,
+ LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK,
+ gain << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT);
+ mod_phy_reg(pi, 0x4fd,
+ LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK,
+ gain << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT);
+}
+
+void
+wlc_lcnphy_get_radio_loft(struct brcms_phy *pi,
+ u8 *ei0, u8 *eq0, u8 *fi0, u8 *fq0)
+{
+ *ei0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG089));
+ *eq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08A));
+ *fi0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08B));
+ *fq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08C));
+}
+
+void wlc_lcnphy_set_tx_iqcc(struct brcms_phy *pi, u16 a, u16 b)
+{
+ struct phytbl_info tab;
+ u16 iqcc[2];
+
+ iqcc[0] = a;
+ iqcc[1] = b;
+
+ tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
+ tab.tbl_width = 16;
+ tab.tbl_ptr = iqcc;
+ tab.tbl_len = 2;
+ tab.tbl_offset = 80;
+ wlc_lcnphy_write_table(pi, &tab);
+}
+
+void wlc_lcnphy_set_tx_locc(struct brcms_phy *pi, u16 didq)
+{
+ struct phytbl_info tab;
+
+ tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
+ tab.tbl_width = 16;
+ tab.tbl_ptr = &didq;
+ tab.tbl_len = 1;
+ tab.tbl_offset = 85;
+ wlc_lcnphy_write_table(pi, &tab);
+}
+
+void wlc_lcnphy_set_tx_pwr_by_index(struct brcms_phy *pi, int index)
+{
+ struct phytbl_info tab;
+ u16 a, b;
+ u8 bb_mult;
+ u32 bbmultiqcomp, txgain, locoeffs, rfpower;
+ struct lcnphy_txgains gains;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ pi_lcn->lcnphy_tx_power_idx_override = (s8) index;
+ pi_lcn->lcnphy_current_index = (u8) index;
+
+ tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
+ tab.tbl_width = 32;
+ tab.tbl_len = 1;
+
+ wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
+
+ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
+ tab.tbl_ptr = &bbmultiqcomp;
+ wlc_lcnphy_read_table(pi, &tab);
+
+ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
+ tab.tbl_width = 32;
+ tab.tbl_ptr = &txgain;
+ wlc_lcnphy_read_table(pi, &tab);
+
+ gains.gm_gain = (u16) (txgain & 0xff);
+ gains.pga_gain = (u16) (txgain >> 8) & 0xff;
+ gains.pad_gain = (u16) (txgain >> 16) & 0xff;
+ gains.dac_gain = (u16) (bbmultiqcomp >> 28) & 0x07;
+ wlc_lcnphy_set_tx_gain(pi, &gains);
+ wlc_lcnphy_set_pa_gain(pi, (u16) (txgain >> 24) & 0x7f);
+
+ bb_mult = (u8) ((bbmultiqcomp >> 20) & 0xff);
+ wlc_lcnphy_set_bbmult(pi, bb_mult);
+
+ wlc_lcnphy_enable_tx_gain_override(pi);
+
+ if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
+
+ a = (u16) ((bbmultiqcomp >> 10) & 0x3ff);
+ b = (u16) (bbmultiqcomp & 0x3ff);
+ wlc_lcnphy_set_tx_iqcc(pi, a, b);
+
+ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + index;
+ tab.tbl_ptr = &locoeffs;
+ wlc_lcnphy_read_table(pi, &tab);
+
+ wlc_lcnphy_set_tx_locc(pi, (u16) locoeffs);
+
+ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
+ tab.tbl_ptr = &rfpower;
+ wlc_lcnphy_read_table(pi, &tab);
+ mod_phy_reg(pi, 0x6a6, (0x1fff << 0), (rfpower * 8) << 0);
+
+ }
+}
+
+static void wlc_lcnphy_clear_papd_comptable(struct brcms_phy *pi)
+{
+ u32 j;
+ struct phytbl_info tab;
+ u32 temp_offset[128];
+ tab.tbl_ptr = temp_offset;
+ tab.tbl_len = 128;
+ tab.tbl_id = LCNPHY_TBL_ID_PAPDCOMPDELTATBL;
+ tab.tbl_width = 32;
+ tab.tbl_offset = 0;
+
+ memset(temp_offset, 0, sizeof(temp_offset));
+ for (j = 1; j < 128; j += 2)
+ temp_offset[j] = 0x80000;
+
+ wlc_lcnphy_write_table(pi, &tab);
+ return;
+}
+
+void wlc_lcnphy_tx_pu(struct brcms_phy *pi, bool bEnable)
+{
+ if (!bEnable) {
+
+ and_phy_reg(pi, 0x43b, ~(u16) ((0x1 << 1) | (0x1 << 4)));
+
+ mod_phy_reg(pi, 0x43c, (0x1 << 1), 1 << 1);
+
+ and_phy_reg(pi, 0x44c,
+ ~(u16) ((0x1 << 3) |
+ (0x1 << 5) |
+ (0x1 << 12) |
+ (0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
+
+ and_phy_reg(pi, 0x44d,
+ ~(u16) ((0x1 << 3) | (0x1 << 5) | (0x1 << 14)));
+ mod_phy_reg(pi, 0x44d, (0x1 << 2), 1 << 2);
+
+ mod_phy_reg(pi, 0x44d, (0x1 << 1) | (0x1 << 0), (0x1 << 0));
+
+ and_phy_reg(pi, 0x4f9,
+ ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
+
+ and_phy_reg(pi, 0x4fa,
+ ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
+ } else {
+
+ mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
+ mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
+
+ mod_phy_reg(pi, 0x43b, (0x1 << 4), 1 << 4);
+ mod_phy_reg(pi, 0x43c, (0x1 << 6), 0 << 6);
+
+ mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
+ mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
+
+ wlc_lcnphy_set_trsw_override(pi, true, false);
+
+ mod_phy_reg(pi, 0x44d, (0x1 << 2), 0 << 2);
+ mod_phy_reg(pi, 0x44c, (0x1 << 2), 1 << 2);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+
+ mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
+ mod_phy_reg(pi, 0x44d, (0x1 << 3), 1 << 3);
+
+ mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
+ mod_phy_reg(pi, 0x44d, (0x1 << 5), 0 << 5);
+
+ mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
+ mod_phy_reg(pi, 0x4fa, (0x1 << 1), 1 << 1);
+
+ mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
+ mod_phy_reg(pi, 0x4fa, (0x1 << 2), 1 << 2);
+
+ mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
+ mod_phy_reg(pi, 0x4fa, (0x1 << 0), 1 << 0);
+ } else {
+
+ mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
+ mod_phy_reg(pi, 0x44d, (0x1 << 3), 0 << 3);
+
+ mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
+ mod_phy_reg(pi, 0x44d, (0x1 << 5), 1 << 5);
+
+ mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
+ mod_phy_reg(pi, 0x4fa, (0x1 << 1), 0 << 1);
+
+ mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
+ mod_phy_reg(pi, 0x4fa, (0x1 << 2), 0 << 2);
+
+ mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
+ mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
+ }
+ }
+}
+
+static void
+wlc_lcnphy_run_samples(struct brcms_phy *pi,
+ u16 num_samps,
+ u16 num_loops, u16 wait, bool iqcalmode)
+{
+
+ or_phy_reg(pi, 0x6da, 0x8080);
+
+ mod_phy_reg(pi, 0x642, (0x7f << 0), (num_samps - 1) << 0);
+ if (num_loops != 0xffff)
+ num_loops--;
+ mod_phy_reg(pi, 0x640, (0xffff << 0), num_loops << 0);
+
+ mod_phy_reg(pi, 0x641, (0xffff << 0), wait << 0);
+
+ if (iqcalmode) {
+
+ and_phy_reg(pi, 0x453, (u16) ~(0x1 << 15));
+ or_phy_reg(pi, 0x453, (0x1 << 15));
+ } else {
+ write_phy_reg(pi, 0x63f, 1);
+ wlc_lcnphy_tx_pu(pi, 1);
+ }
+
+ or_radio_reg(pi, RADIO_2064_REG112, 0x6);
+}
+
+void wlc_lcnphy_deaf_mode(struct brcms_phy *pi, bool mode)
+{
+
+ u8 phybw40;
+ phybw40 = CHSPEC_IS40(pi->radio_chanspec);
+
+ if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
+ mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
+ mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
+ } else {
+ mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
+ mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
+ }
+
+ if (phybw40 == 0) {
+ mod_phy_reg((pi), 0x410,
+ (0x1 << 6) |
+ (0x1 << 5),
+ ((CHSPEC_IS2G(
+ pi->radio_chanspec)) ? (!mode) : 0) <<
+ 6 | (!mode) << 5);
+ mod_phy_reg(pi, 0x410, (0x1 << 7), (mode) << 7);
+ }
+}
+
+void
+wlc_lcnphy_start_tx_tone(struct brcms_phy *pi, s32 f_kHz, u16 max_val,
+ bool iqcalmode)
+{
+ u8 phy_bw;
+ u16 num_samps, t, k;
+ u32 bw;
+ s32 theta = 0, rot = 0;
+ struct cordic_iq tone_samp;
+ u32 data_buf[64];
+ u16 i_samp, q_samp;
+ struct phytbl_info tab;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ pi->phy_tx_tone_freq = f_kHz;
+
+ wlc_lcnphy_deaf_mode(pi, true);
+
+ phy_bw = 40;
+ if (pi_lcn->lcnphy_spurmod) {
+ write_phy_reg(pi, 0x942, 0x2);
+ write_phy_reg(pi, 0x93b, 0x0);
+ write_phy_reg(pi, 0x93c, 0x0);
+ wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
+ }
+
+ if (f_kHz) {
+ k = 1;
+ do {
+ bw = phy_bw * 1000 * k;
+ num_samps = bw / abs(f_kHz);
+ k++;
+ } while ((num_samps * (u32) (abs(f_kHz))) != bw);
+ } else
+ num_samps = 2;
+
+ rot = ((f_kHz * 36) / phy_bw) / 100;
+ theta = 0;
+
+ for (t = 0; t < num_samps; t++) {
+
+ tone_samp = cordic_calc_iq(theta);
+
+ theta += rot;
+
+ i_samp = (u16) (FLOAT(tone_samp.i * max_val) & 0x3ff);
+ q_samp = (u16) (FLOAT(tone_samp.q * max_val) & 0x3ff);
+ data_buf[t] = (i_samp << 10) | q_samp;
+ }
+
+ mod_phy_reg(pi, 0x6d6, (0x3 << 0), 0 << 0);
+
+ mod_phy_reg(pi, 0x6da, (0x1 << 3), 1 << 3);
+
+ tab.tbl_ptr = data_buf;
+ tab.tbl_len = num_samps;
+ tab.tbl_id = LCNPHY_TBL_ID_SAMPLEPLAY;
+ tab.tbl_offset = 0;
+ tab.tbl_width = 32;
+ wlc_lcnphy_write_table(pi, &tab);
+
+ wlc_lcnphy_run_samples(pi, num_samps, 0xffff, 0, iqcalmode);
+}
+
+void wlc_lcnphy_stop_tx_tone(struct brcms_phy *pi)
+{
+ s16 playback_status;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ pi->phy_tx_tone_freq = 0;
+ if (pi_lcn->lcnphy_spurmod) {
+ write_phy_reg(pi, 0x942, 0x7);
+ write_phy_reg(pi, 0x93b, 0x2017);
+ write_phy_reg(pi, 0x93c, 0x27c5);
+ wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
+ }
+
+ playback_status = read_phy_reg(pi, 0x644);
+ if (playback_status & (0x1 << 0)) {
+ wlc_lcnphy_tx_pu(pi, 0);
+ mod_phy_reg(pi, 0x63f, (0x1 << 1), 1 << 1);
+ } else if (playback_status & (0x1 << 1))
+ mod_phy_reg(pi, 0x453, (0x1 << 15), 0 << 15);
+
+ mod_phy_reg(pi, 0x6d6, (0x3 << 0), 1 << 0);
+
+ mod_phy_reg(pi, 0x6da, (0x1 << 3), 0 << 3);
+
+ mod_phy_reg(pi, 0x6da, (0x1 << 7), 0 << 7);
+
+ and_radio_reg(pi, RADIO_2064_REG112, 0xFFF9);
+
+ wlc_lcnphy_deaf_mode(pi, false);
+}
+
+static void
+wlc_lcnphy_set_cc(struct brcms_phy *pi, int cal_type, s16 coeff_x, s16 coeff_y)
+{
+ u16 di0dq0;
+ u16 x, y, data_rf;
+ int k;
+ switch (cal_type) {
+ case 0:
+ wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y);
+ break;
+ case 2:
+ di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff);
+ wlc_lcnphy_set_tx_locc(pi, di0dq0);
+ break;
+ case 3:
+ k = wlc_lcnphy_calc_floor(coeff_x, 0);
+ y = 8 + k;
+ k = wlc_lcnphy_calc_floor(coeff_x, 1);
+ x = 8 - k;
+ data_rf = (x * 16 + y);
+ write_radio_reg(pi, RADIO_2064_REG089, data_rf);
+ k = wlc_lcnphy_calc_floor(coeff_y, 0);
+ y = 8 + k;
+ k = wlc_lcnphy_calc_floor(coeff_y, 1);
+ x = 8 - k;
+ data_rf = (x * 16 + y);
+ write_radio_reg(pi, RADIO_2064_REG08A, data_rf);
+ break;
+ case 4:
+ k = wlc_lcnphy_calc_floor(coeff_x, 0);
+ y = 8 + k;
+ k = wlc_lcnphy_calc_floor(coeff_x, 1);
+ x = 8 - k;
+ data_rf = (x * 16 + y);
+ write_radio_reg(pi, RADIO_2064_REG08B, data_rf);
+ k = wlc_lcnphy_calc_floor(coeff_y, 0);
+ y = 8 + k;
+ k = wlc_lcnphy_calc_floor(coeff_y, 1);
+ x = 8 - k;
+ data_rf = (x * 16 + y);
+ write_radio_reg(pi, RADIO_2064_REG08C, data_rf);
+ break;
+ }
+}
+
+static struct lcnphy_unsign16_struct
+wlc_lcnphy_get_cc(struct brcms_phy *pi, int cal_type)
+{
+ u16 a, b, didq;
+ u8 di0, dq0, ei, eq, fi, fq;
+ struct lcnphy_unsign16_struct cc;
+ cc.re = 0;
+ cc.im = 0;
+ switch (cal_type) {
+ case 0:
+ wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
+ cc.re = a;
+ cc.im = b;
+ break;
+ case 2:
+ didq = wlc_lcnphy_get_tx_locc(pi);
+ di0 = (((didq & 0xff00) << 16) >> 24);
+ dq0 = (((didq & 0x00ff) << 24) >> 24);
+ cc.re = (u16) di0;
+ cc.im = (u16) dq0;
+ break;
+ case 3:
+ wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
+ cc.re = (u16) ei;
+ cc.im = (u16) eq;
+ break;
+ case 4:
+ wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
+ cc.re = (u16) fi;
+ cc.im = (u16) fq;
+ break;
+ }
+ return cc;
+}
+
+static void
+wlc_lcnphy_samp_cap(struct brcms_phy *pi, int clip_detect_algo, u16 thresh,
+ s16 *ptr, int mode)
+{
+ u32 curval1, curval2, stpptr, curptr, strptr, val;
+ u16 sslpnCalibClkEnCtrl, timer;
+ u16 old_sslpnCalibClkEnCtrl;
+ s16 imag, real;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ timer = 0;
+ old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
+
+ curval1 = R_REG(&pi->regs->psm_corectlsts);
+ ptr[130] = 0;
+ W_REG(&pi->regs->psm_corectlsts, ((1 << 6) | curval1));
+
+ W_REG(&pi->regs->smpl_clct_strptr, 0x7E00);
+ W_REG(&pi->regs->smpl_clct_stpptr, 0x8000);
+ udelay(20);
+ curval2 = R_REG(&pi->regs->psm_phy_hdr_param);
+ W_REG(&pi->regs->psm_phy_hdr_param, curval2 | 0x30);
+
+ write_phy_reg(pi, 0x555, 0x0);
+ write_phy_reg(pi, 0x5a6, 0x5);
+
+ write_phy_reg(pi, 0x5a2, (u16) (mode | mode << 6));
+ write_phy_reg(pi, 0x5cf, 3);
+ write_phy_reg(pi, 0x5a5, 0x3);
+ write_phy_reg(pi, 0x583, 0x0);
+ write_phy_reg(pi, 0x584, 0x0);
+ write_phy_reg(pi, 0x585, 0x0fff);
+ write_phy_reg(pi, 0x586, 0x0000);
+
+ write_phy_reg(pi, 0x580, 0x4501);
+
+ sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
+ write_phy_reg(pi, 0x6da, (u32) (sslpnCalibClkEnCtrl | 0x2008));
+ stpptr = R_REG(&pi->regs->smpl_clct_stpptr);
+ curptr = R_REG(&pi->regs->smpl_clct_curptr);
+ do {
+ udelay(10);
+ curptr = R_REG(&pi->regs->smpl_clct_curptr);
+ timer++;
+ } while ((curptr != stpptr) && (timer < 500));
+
+ W_REG(&pi->regs->psm_phy_hdr_param, 0x2);
+ strptr = 0x7E00;
+ W_REG(&pi->regs->tplatewrptr, strptr);
+ while (strptr < 0x8000) {
+ val = R_REG(&pi->regs->tplatewrdata);
+ imag = ((val >> 16) & 0x3ff);
+ real = ((val) & 0x3ff);
+ if (imag > 511)
+ imag -= 1024;
+
+ if (real > 511)
+ real -= 1024;
+
+ if (pi_lcn->lcnphy_iqcal_swp_dis)
+ ptr[(strptr - 0x7E00) / 4] = real;
+ else
+ ptr[(strptr - 0x7E00) / 4] = imag;
+
+ if (clip_detect_algo) {
+ if (imag > thresh || imag < -thresh) {
+ strptr = 0x8000;
+ ptr[130] = 1;
+ }
+ }
+
+ strptr += 4;
+ }
+
+ write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
+ W_REG(&pi->regs->psm_phy_hdr_param, curval2);
+ W_REG(&pi->regs->psm_corectlsts, curval1);
+}
+
+static void
+wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type, int num_levels,
+ int step_size_lg2)
+{
+ const struct lcnphy_spb_tone *phy_c1;
+ struct lcnphy_spb_tone phy_c2;
+ struct lcnphy_unsign16_struct phy_c3;
+ int phy_c4, phy_c5, k, l, j, phy_c6;
+ u16 phy_c7, phy_c8, phy_c9;
+ s16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16;
+ s16 *ptr, phy_c17;
+ s32 phy_c18, phy_c19;
+ u32 phy_c20, phy_c21;
+ bool phy_c22, phy_c23, phy_c24, phy_c25;
+ u16 phy_c26, phy_c27;
+ u16 phy_c28, phy_c29, phy_c30;
+ u16 phy_c31;
+ u16 *phy_c32;
+ phy_c21 = 0;
+ phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0;
+ ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC);
+ if (NULL == ptr)
+ return;
+
+ phy_c32 = kmalloc(sizeof(u16) * 20, GFP_ATOMIC);
+ if (NULL == phy_c32) {
+ kfree(ptr);
+ return;
+ }
+ phy_c26 = read_phy_reg(pi, 0x6da);
+ phy_c27 = read_phy_reg(pi, 0x6db);
+ phy_c31 = read_radio_reg(pi, RADIO_2064_REG026);
+ write_phy_reg(pi, 0x93d, 0xC0);
+
+ wlc_lcnphy_start_tx_tone(pi, 3750, 88, 0);
+ write_phy_reg(pi, 0x6da, 0xffff);
+ or_phy_reg(pi, 0x6db, 0x3);
+
+ wlc_lcnphy_tx_iqlo_loopback(pi, phy_c32);
+ udelay(500);
+ phy_c28 = read_phy_reg(pi, 0x938);
+ phy_c29 = read_phy_reg(pi, 0x4d7);
+ phy_c30 = read_phy_reg(pi, 0x4d8);
+ or_phy_reg(pi, 0x938, 0x1 << 2);
+ or_phy_reg(pi, 0x4d7, 0x1 << 2);
+ or_phy_reg(pi, 0x4d7, 0x1 << 3);
+ mod_phy_reg(pi, 0x4d7, (0x7 << 12), 0x2 << 12);
+ or_phy_reg(pi, 0x4d8, 1 << 0);
+ or_phy_reg(pi, 0x4d8, 1 << 1);
+ mod_phy_reg(pi, 0x4d8, (0x3ff << 2), 0x23A << 2);
+ mod_phy_reg(pi, 0x4d8, (0x7 << 12), 0x7 << 12);
+ phy_c1 = &lcnphy_spb_tone_3750[0];
+ phy_c4 = 32;
+
+ if (num_levels == 0) {
+ if (cal_type != 0)
+ num_levels = 4;
+ else
+ num_levels = 9;
+ }
+ if (step_size_lg2 == 0) {
+ if (cal_type != 0)
+ step_size_lg2 = 3;
+ else
+ step_size_lg2 = 8;
+ }
+
+ phy_c7 = (1 << step_size_lg2);
+ phy_c3 = wlc_lcnphy_get_cc(pi, cal_type);
+ phy_c15 = (s16) phy_c3.re;
+ phy_c16 = (s16) phy_c3.im;
+ if (cal_type == 2) {
+ if (phy_c3.re > 127)
+ phy_c15 = phy_c3.re - 256;
+ if (phy_c3.im > 127)
+ phy_c16 = phy_c3.im - 256;
+ }
+ wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
+ udelay(20);
+ for (phy_c8 = 0; phy_c7 != 0 && phy_c8 < num_levels; phy_c8++) {
+ phy_c23 = 1;
+ phy_c22 = 0;
+ switch (cal_type) {
+ case 0:
+ phy_c10 = 511;
+ break;
+ case 2:
+ phy_c10 = 127;
+ break;
+ case 3:
+ phy_c10 = 15;
+ break;
+ case 4:
+ phy_c10 = 15;
+ break;
+ }
+
+ phy_c9 = read_phy_reg(pi, 0x93d);
+ phy_c9 = 2 * phy_c9;
+ phy_c24 = 0;
+ phy_c5 = 7;
+ phy_c25 = 1;
+ while (1) {
+ write_radio_reg(pi, RADIO_2064_REG026,
+ (phy_c5 & 0x7) | ((phy_c5 & 0x7) << 4));
+ udelay(50);
+ phy_c22 = 0;
+ ptr[130] = 0;
+ wlc_lcnphy_samp_cap(pi, 1, phy_c9, &ptr[0], 2);
+ if (ptr[130] == 1)
+ phy_c22 = 1;
+ if (phy_c22)
+ phy_c5 -= 1;
+ if ((phy_c22 != phy_c24) && (!phy_c25))
+ break;
+ if (!phy_c22)
+ phy_c5 += 1;
+ if (phy_c5 <= 0 || phy_c5 >= 7)
+ break;
+ phy_c24 = phy_c22;
+ phy_c25 = 0;
+ }
+
+ if (phy_c5 < 0)
+ phy_c5 = 0;
+ else if (phy_c5 > 7)
+ phy_c5 = 7;
+
+ for (k = -phy_c7; k <= phy_c7; k += phy_c7) {
+ for (l = -phy_c7; l <= phy_c7; l += phy_c7) {
+ phy_c11 = phy_c15 + k;
+ phy_c12 = phy_c16 + l;
+
+ if (phy_c11 < -phy_c10)
+ phy_c11 = -phy_c10;
+ else if (phy_c11 > phy_c10)
+ phy_c11 = phy_c10;
+ if (phy_c12 < -phy_c10)
+ phy_c12 = -phy_c10;
+ else if (phy_c12 > phy_c10)
+ phy_c12 = phy_c10;
+ wlc_lcnphy_set_cc(pi, cal_type, phy_c11,
+ phy_c12);
+ udelay(20);
+ wlc_lcnphy_samp_cap(pi, 0, 0, ptr, 2);
+
+ phy_c18 = 0;
+ phy_c19 = 0;
+ for (j = 0; j < 128; j++) {
+ if (cal_type != 0)
+ phy_c6 = j % phy_c4;
+ else
+ phy_c6 = (2 * j) % phy_c4;
+
+ phy_c2.re = phy_c1[phy_c6].re;
+ phy_c2.im = phy_c1[phy_c6].im;
+ phy_c17 = ptr[j];
+ phy_c18 = phy_c18 + phy_c17 * phy_c2.re;
+ phy_c19 = phy_c19 + phy_c17 * phy_c2.im;
+ }
+
+ phy_c18 = phy_c18 >> 10;
+ phy_c19 = phy_c19 >> 10;
+ phy_c20 = ((phy_c18 * phy_c18) +
+ (phy_c19 * phy_c19));
+
+ if (phy_c23 || phy_c20 < phy_c21) {
+ phy_c21 = phy_c20;
+ phy_c13 = phy_c11;
+ phy_c14 = phy_c12;
+ }
+ phy_c23 = 0;
+ }
+ }
+ phy_c23 = 1;
+ phy_c15 = phy_c13;
+ phy_c16 = phy_c14;
+ phy_c7 = phy_c7 >> 1;
+ wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
+ udelay(20);
+ }
+ goto cleanup;
+cleanup:
+ wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, phy_c32);
+ wlc_lcnphy_stop_tx_tone(pi);
+ write_phy_reg(pi, 0x6da, phy_c26);
+ write_phy_reg(pi, 0x6db, phy_c27);
+ write_phy_reg(pi, 0x938, phy_c28);
+ write_phy_reg(pi, 0x4d7, phy_c29);
+ write_phy_reg(pi, 0x4d8, phy_c30);
+ write_radio_reg(pi, RADIO_2064_REG026, phy_c31);
+
+ kfree(phy_c32);
+ kfree(ptr);
+}
+
+void wlc_lcnphy_get_tx_iqcc(struct brcms_phy *pi, u16 *a, u16 *b)
+{
+ u16 iqcc[2];
+ struct phytbl_info tab;
+
+ tab.tbl_ptr = iqcc;
+ tab.tbl_len = 2;
+ tab.tbl_id = 0;
+ tab.tbl_offset = 80;
+ tab.tbl_width = 16;
+ wlc_lcnphy_read_table(pi, &tab);
+
+ *a = iqcc[0];
+ *b = iqcc[1];
+}
+
+static void wlc_lcnphy_tx_iqlo_soft_cal_full(struct brcms_phy *pi)
+{
+ struct lcnphy_unsign16_struct iqcc0, locc2, locc3, locc4;
+
+ wlc_lcnphy_set_cc(pi, 0, 0, 0);
+ wlc_lcnphy_set_cc(pi, 2, 0, 0);
+ wlc_lcnphy_set_cc(pi, 3, 0, 0);
+ wlc_lcnphy_set_cc(pi, 4, 0, 0);
+
+ wlc_lcnphy_a1(pi, 4, 0, 0);
+ wlc_lcnphy_a1(pi, 3, 0, 0);
+ wlc_lcnphy_a1(pi, 2, 3, 2);
+ wlc_lcnphy_a1(pi, 0, 5, 8);
+ wlc_lcnphy_a1(pi, 2, 2, 1);
+ wlc_lcnphy_a1(pi, 0, 4, 3);
+
+ iqcc0 = wlc_lcnphy_get_cc(pi, 0);
+ locc2 = wlc_lcnphy_get_cc(pi, 2);
+ locc3 = wlc_lcnphy_get_cc(pi, 3);
+ locc4 = wlc_lcnphy_get_cc(pi, 4);
+}
+
+u16 wlc_lcnphy_get_tx_locc(struct brcms_phy *pi)
+{
+ struct phytbl_info tab;
+ u16 didq;
+
+ tab.tbl_id = 0;
+ tab.tbl_width = 16;
+ tab.tbl_ptr = &didq;
+ tab.tbl_len = 1;
+ tab.tbl_offset = 85;
+ wlc_lcnphy_read_table(pi, &tab);
+
+ return didq;
+}
+
+static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)
+{
+
+ struct lcnphy_txgains target_gains, old_gains;
+ u8 save_bb_mult;
+ u16 a, b, didq, save_pa_gain = 0;
+ uint idx, SAVE_txpwrindex = 0xFF;
+ u32 val;
+ u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
+ struct phytbl_info tab;
+ u8 ei0, eq0, fi0, fq0;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ wlc_lcnphy_get_tx_gain(pi, &old_gains);
+ save_pa_gain = wlc_lcnphy_get_pa_gain(pi);
+
+ save_bb_mult = wlc_lcnphy_get_bbmult(pi);
+
+ if (SAVE_txpwrctrl == LCNPHY_TX_PWR_CTRL_OFF)
+ SAVE_txpwrindex = wlc_lcnphy_get_current_tx_pwr_idx(pi);
+
+ wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
+
+ target_gains.gm_gain = 7;
+ target_gains.pga_gain = 0;
+ target_gains.pad_gain = 21;
+ target_gains.dac_gain = 0;
+ wlc_lcnphy_set_tx_gain(pi, &target_gains);
+ wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
+
+ if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) {
+
+ wlc_lcnphy_set_tx_pwr_by_index(pi, 30);
+
+ wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
+ (pi_lcn->
+ lcnphy_recal ? LCNPHY_CAL_RECAL :
+ LCNPHY_CAL_FULL), false);
+ } else {
+ wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
+ }
+
+ wlc_lcnphy_get_radio_loft(pi, &ei0, &eq0, &fi0, &fq0);
+ if ((abs((s8) fi0) == 15) && (abs((s8) fq0) == 15)) {
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ target_gains.gm_gain = 255;
+ target_gains.pga_gain = 255;
+ target_gains.pad_gain = 0xf0;
+ target_gains.dac_gain = 0;
+ } else {
+ target_gains.gm_gain = 7;
+ target_gains.pga_gain = 45;
+ target_gains.pad_gain = 186;
+ target_gains.dac_gain = 0;
+ }
+
+ if (LCNREV_IS(pi->pubpi.phy_rev, 1)
+ || pi_lcn->lcnphy_hw_iqcal_en) {
+
+ target_gains.pga_gain = 0;
+ target_gains.pad_gain = 30;
+ wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
+ wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
+ LCNPHY_CAL_FULL, false);
+ } else {
+ wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
+ }
+ }
+
+ wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
+
+ didq = wlc_lcnphy_get_tx_locc(pi);
+
+ tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
+ tab.tbl_width = 32;
+ tab.tbl_ptr = &val;
+
+ tab.tbl_len = 1;
+ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
+
+ for (idx = 0; idx < 128; idx++) {
+ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + idx;
+
+ wlc_lcnphy_read_table(pi, &tab);
+ val = (val & 0xfff00000) |
+ ((u32) (a & 0x3FF) << 10) | (b & 0x3ff);
+ wlc_lcnphy_write_table(pi, &tab);
+
+ val = didq;
+ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + idx;
+ wlc_lcnphy_write_table(pi, &tab);
+ }
+
+ pi_lcn->lcnphy_cal_results.txiqlocal_a = a;
+ pi_lcn->lcnphy_cal_results.txiqlocal_b = b;
+ pi_lcn->lcnphy_cal_results.txiqlocal_didq = didq;
+ pi_lcn->lcnphy_cal_results.txiqlocal_ei0 = ei0;
+ pi_lcn->lcnphy_cal_results.txiqlocal_eq0 = eq0;
+ pi_lcn->lcnphy_cal_results.txiqlocal_fi0 = fi0;
+ pi_lcn->lcnphy_cal_results.txiqlocal_fq0 = fq0;
+
+ wlc_lcnphy_set_bbmult(pi, save_bb_mult);
+ wlc_lcnphy_set_pa_gain(pi, save_pa_gain);
+ wlc_lcnphy_set_tx_gain(pi, &old_gains);
+
+ if (SAVE_txpwrctrl != LCNPHY_TX_PWR_CTRL_OFF)
+ wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
+ else
+ wlc_lcnphy_set_tx_pwr_by_index(pi, SAVE_txpwrindex);
+}
+
+s16 wlc_lcnphy_tempsense_new(struct brcms_phy *pi, bool mode)
+{
+ u16 tempsenseval1, tempsenseval2;
+ s16 avg = 0;
+ bool suspend = 0;
+
+ if (mode == 1) {
+ suspend =
+ (0 ==
+ (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
+ if (!suspend)
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+ wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
+ }
+ tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
+ tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
+
+ if (tempsenseval1 > 255)
+ avg = (s16) (tempsenseval1 - 512);
+ else
+ avg = (s16) tempsenseval1;
+
+ if (tempsenseval2 > 255)
+ avg += (s16) (tempsenseval2 - 512);
+ else
+ avg += (s16) tempsenseval2;
+
+ avg /= 2;
+
+ if (mode == 1) {
+
+ mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
+
+ udelay(100);
+ mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
+
+ if (!suspend)
+ wlapi_enable_mac(pi->sh->physhim);
+ }
+ return avg;
+}
+
+u16 wlc_lcnphy_tempsense(struct brcms_phy *pi, bool mode)
+{
+ u16 tempsenseval1, tempsenseval2;
+ s32 avg = 0;
+ bool suspend = 0;
+ u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ if (mode == 1) {
+ suspend =
+ (0 ==
+ (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
+ if (!suspend)
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+ wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
+ }
+ tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
+ tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
+
+ if (tempsenseval1 > 255)
+ avg = (int)(tempsenseval1 - 512);
+ else
+ avg = (int)tempsenseval1;
+
+ if (pi_lcn->lcnphy_tempsense_option == 1 || pi->hwpwrctrl_capable) {
+ if (tempsenseval2 > 255)
+ avg = (int)(avg - tempsenseval2 + 512);
+ else
+ avg = (int)(avg - tempsenseval2);
+ } else {
+ if (tempsenseval2 > 255)
+ avg = (int)(avg + tempsenseval2 - 512);
+ else
+ avg = (int)(avg + tempsenseval2);
+ avg = avg / 2;
+ }
+ if (avg < 0)
+ avg = avg + 512;
+
+ if (pi_lcn->lcnphy_tempsense_option == 2)
+ avg = tempsenseval1;
+
+ if (mode)
+ wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
+
+ if (mode == 1) {
+
+ mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
+
+ udelay(100);
+ mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
+
+ if (!suspend)
+ wlapi_enable_mac(pi->sh->physhim);
+ }
+ return (u16) avg;
+}
+
+s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode)
+{
+ s32 degree = wlc_lcnphy_tempsense_new(pi, mode);
+ degree =
+ ((degree <<
+ 10) + LCN_TEMPSENSE_OFFSET + (LCN_TEMPSENSE_DEN >> 1))
+ / LCN_TEMPSENSE_DEN;
+ return (s8) degree;
+}
+
+s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode)
+{
+ u16 vbatsenseval;
+ s32 avg = 0;
+ bool suspend = 0;
+
+ if (mode == 1) {
+ suspend =
+ (0 ==
+ (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
+ if (!suspend)
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+ wlc_lcnphy_vbat_temp_sense_setup(pi, VBATSENSE);
+ }
+
+ vbatsenseval = read_phy_reg(pi, 0x475) & 0x1FF;
+
+ if (vbatsenseval > 255)
+ avg = (s32) (vbatsenseval - 512);
+ else
+ avg = (s32) vbatsenseval;
+
+ avg = (avg * LCN_VBAT_SCALE_NOM +
+ (LCN_VBAT_SCALE_DEN >> 1)) / LCN_VBAT_SCALE_DEN;
+
+ if (mode == 1) {
+ if (!suspend)
+ wlapi_enable_mac(pi->sh->physhim);
+ }
+ return (s8) avg;
+}
+
+static void wlc_lcnphy_afe_clk_init(struct brcms_phy *pi, u8 mode)
+{
+ u8 phybw40;
+ phybw40 = CHSPEC_IS40(pi->radio_chanspec);
+
+ mod_phy_reg(pi, 0x6d1, (0x1 << 7), (1) << 7);
+
+ if (((mode == AFE_CLK_INIT_MODE_PAPD) && (phybw40 == 0)) ||
+ (mode == AFE_CLK_INIT_MODE_TXRX2X))
+ write_phy_reg(pi, 0x6d0, 0x7);
+
+ wlc_lcnphy_toggle_afe_pwdn(pi);
+}
+
+static void wlc_lcnphy_temp_adj(struct brcms_phy *pi)
+{
+}
+
+static void wlc_lcnphy_glacial_timer_based_cal(struct brcms_phy *pi)
+{
+ bool suspend;
+ s8 index;
+ u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+ suspend =
+ (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
+ if (!suspend)
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+ wlc_lcnphy_deaf_mode(pi, true);
+ pi->phy_lastcal = pi->sh->now;
+ pi->phy_forcecal = false;
+ index = pi_lcn->lcnphy_current_index;
+
+ wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
+
+ wlc_lcnphy_set_tx_pwr_by_index(pi, index);
+ wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
+ wlc_lcnphy_deaf_mode(pi, false);
+ if (!suspend)
+ wlapi_enable_mac(pi->sh->physhim);
+
+}
+
+static void wlc_lcnphy_periodic_cal(struct brcms_phy *pi)
+{
+ bool suspend, full_cal;
+ const struct lcnphy_rx_iqcomp *rx_iqcomp;
+ int rx_iqcomp_sz;
+ u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
+ s8 index;
+ struct phytbl_info tab;
+ s32 a1, b0, b1;
+ s32 tssi, pwr, maxtargetpwr, mintargetpwr;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ pi->phy_lastcal = pi->sh->now;
+ pi->phy_forcecal = false;
+ full_cal =
+ (pi_lcn->lcnphy_full_cal_channel !=
+ CHSPEC_CHANNEL(pi->radio_chanspec));
+ pi_lcn->lcnphy_full_cal_channel = CHSPEC_CHANNEL(pi->radio_chanspec);
+ index = pi_lcn->lcnphy_current_index;
+
+ suspend =
+ (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
+ if (!suspend) {
+ wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000);
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+ }
+
+ wlc_lcnphy_deaf_mode(pi, true);
+
+ wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
+
+ rx_iqcomp = lcnphy_rx_iqcomp_table_rev0;
+ rx_iqcomp_sz = ARRAY_SIZE(lcnphy_rx_iqcomp_table_rev0);
+
+ if (LCNREV_IS(pi->pubpi.phy_rev, 1))
+ wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 40);
+ else
+ wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 127);
+
+ if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
+
+ wlc_lcnphy_idle_tssi_est((struct brcms_phy_pub *) pi);
+
+ b0 = pi->txpa_2g[0];
+ b1 = pi->txpa_2g[1];
+ a1 = pi->txpa_2g[2];
+ maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
+ mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
+
+ tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
+ tab.tbl_width = 32;
+ tab.tbl_ptr = &pwr;
+ tab.tbl_len = 1;
+ tab.tbl_offset = 0;
+ for (tssi = 0; tssi < 128; tssi++) {
+ pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
+ pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
+ wlc_lcnphy_write_table(pi, &tab);
+ tab.tbl_offset++;
+ }
+ }
+
+ wlc_lcnphy_set_tx_pwr_by_index(pi, index);
+ wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
+ wlc_lcnphy_deaf_mode(pi, false);
+ if (!suspend)
+ wlapi_enable_mac(pi->sh->physhim);
+}
+
+void wlc_lcnphy_calib_modes(struct brcms_phy *pi, uint mode)
+{
+ u16 temp_new;
+ int temp1, temp2, temp_diff;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ switch (mode) {
+ case PHY_PERICAL_CHAN:
+ break;
+ case PHY_FULLCAL:
+ wlc_lcnphy_periodic_cal(pi);
+ break;
+ case PHY_PERICAL_PHYINIT:
+ wlc_lcnphy_periodic_cal(pi);
+ break;
+ case PHY_PERICAL_WATCHDOG:
+ if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
+ temp_new = wlc_lcnphy_tempsense(pi, 0);
+ temp1 = LCNPHY_TEMPSENSE(temp_new);
+ temp2 = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_cal_temper);
+ temp_diff = temp1 - temp2;
+ if ((pi_lcn->lcnphy_cal_counter > 90) ||
+ (temp_diff > 60) || (temp_diff < -60)) {
+ wlc_lcnphy_glacial_timer_based_cal(pi);
+ wlc_2064_vco_cal(pi);
+ pi_lcn->lcnphy_cal_temper = temp_new;
+ pi_lcn->lcnphy_cal_counter = 0;
+ } else
+ pi_lcn->lcnphy_cal_counter++;
+ }
+ break;
+ case LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL:
+ if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
+ wlc_lcnphy_tx_power_adjustment(
+ (struct brcms_phy_pub *) pi);
+ break;
+ }
+}
+
+void wlc_lcnphy_get_tssi(struct brcms_phy *pi, s8 *ofdm_pwr, s8 *cck_pwr)
+{
+ s8 cck_offset;
+ u16 status;
+ status = (read_phy_reg(pi, 0x4ab));
+ if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
+ (status & (0x1 << 15))) {
+ *ofdm_pwr = (s8) (((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
+ >> 0) >> 1);
+
+ if (wlc_phy_tpc_isenabled_lcnphy(pi))
+ cck_offset = pi->tx_power_offset[TXP_FIRST_CCK];
+ else
+ cck_offset = 0;
+
+ *cck_pwr = *ofdm_pwr + cck_offset;
+ } else {
+ *cck_pwr = 0;
+ *ofdm_pwr = 0;
+ }
+}
+
+void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi)
+{
+ return;
+
+}
+
+void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi)
+{
+ s8 index;
+ u16 index2;
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+ u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
+ if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
+ SAVE_txpwrctrl) {
+ index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
+ index2 = (u16) (index * 2);
+ mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
+
+ pi_lcn->lcnphy_current_index =
+ (s8)((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
+ }
+}
+
+static void
+wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi,
+ const struct lcnphy_tx_gain_tbl_entry *gain_table)
+{
+ u32 j;
+ struct phytbl_info tab;
+ u32 val;
+ u16 pa_gain;
+ u16 gm_gain;
+
+ if (CHSPEC_IS5G(pi->radio_chanspec))
+ pa_gain = 0x70;
+ else
+ pa_gain = 0x70;
+
+ if (pi->sh->boardflags & BFL_FEM)
+ pa_gain = 0x10;
+ tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
+ tab.tbl_width = 32;
+ tab.tbl_len = 1;
+ tab.tbl_ptr = &val;
+
+ for (j = 0; j < 128; j++) {
+ gm_gain = gain_table[j].gm;
+ val = (((u32) pa_gain << 24) |
+ (gain_table[j].pad << 16) |
+ (gain_table[j].pga << 8) | gm_gain);
+
+ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + j;
+ wlc_lcnphy_write_table(pi, &tab);
+
+ val = (gain_table[j].dac << 28) | (gain_table[j].bb_mult << 20);
+ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + j;
+ wlc_lcnphy_write_table(pi, &tab);
+ }
+}
+
+static void wlc_lcnphy_load_rfpower(struct brcms_phy *pi)
+{
+ struct phytbl_info tab;
+ u32 val, bbmult, rfgain;
+ u8 index;
+ u8 scale_factor = 1;
+ s16 temp, temp1, temp2, qQ, qQ1, qQ2, shift;
+
+ tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
+ tab.tbl_width = 32;
+ tab.tbl_len = 1;
+
+ for (index = 0; index < 128; index++) {
+ tab.tbl_ptr = &bbmult;
+ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
+ wlc_lcnphy_read_table(pi, &tab);
+ bbmult = bbmult >> 20;
+
+ tab.tbl_ptr = &rfgain;
+ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
+ wlc_lcnphy_read_table(pi, &tab);
+
+ qm_log10((s32) (bbmult), 0, &temp1, &qQ1);
+ qm_log10((s32) (1 << 6), 0, &temp2, &qQ2);
+
+ if (qQ1 < qQ2) {
+ temp2 = qm_shr16(temp2, qQ2 - qQ1);
+ qQ = qQ1;
+ } else {
+ temp1 = qm_shr16(temp1, qQ1 - qQ2);
+ qQ = qQ2;
+ }
+ temp = qm_sub16(temp1, temp2);
+
+ if (qQ >= 4)
+ shift = qQ - 4;
+ else
+ shift = 4 - qQ;
+
+ val = (((index << shift) + (5 * temp) +
+ (1 << (scale_factor + shift - 3))) >> (scale_factor +
+ shift - 2));
+
+ tab.tbl_ptr = &val;
+ tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
+ wlc_lcnphy_write_table(pi, &tab);
+ }
+}
+
+static void wlc_lcnphy_bu_tweaks(struct brcms_phy *pi)
+{
+ or_phy_reg(pi, 0x805, 0x1);
+
+ mod_phy_reg(pi, 0x42f, (0x7 << 0), (0x3) << 0);
+
+ mod_phy_reg(pi, 0x030, (0x7 << 0), (0x3) << 0);
+
+ write_phy_reg(pi, 0x414, 0x1e10);
+ write_phy_reg(pi, 0x415, 0x0640);
+
+ mod_phy_reg(pi, 0x4df, (0xff << 8), -9 << 8);
+
+ or_phy_reg(pi, 0x44a, 0x44);
+ write_phy_reg(pi, 0x44a, 0x80);
+ mod_phy_reg(pi, 0x434, (0xff << 0), (0xFD) << 0);
+
+ mod_phy_reg(pi, 0x420, (0xff << 0), (16) << 0);
+
+ if (!(pi->sh->boardrev < 0x1204))
+ mod_radio_reg(pi, RADIO_2064_REG09B, 0xF0, 0xF0);
+
+ write_phy_reg(pi, 0x7d6, 0x0902);
+ mod_phy_reg(pi, 0x429, (0xf << 0), (0x9) << 0);
+
+ mod_phy_reg(pi, 0x429, (0x3f << 4), (0xe) << 4);
+
+ if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
+ mod_phy_reg(pi, 0x423, (0xff << 0), (0x46) << 0);
+
+ mod_phy_reg(pi, 0x411, (0xff << 0), (1) << 0);
+
+ mod_phy_reg(pi, 0x434, (0xff << 0), (0xFF) << 0);
+
+ mod_phy_reg(pi, 0x656, (0xf << 0), (2) << 0);
+
+ mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
+
+ mod_radio_reg(pi, RADIO_2064_REG0F7, 0x4, 0x4);
+ mod_radio_reg(pi, RADIO_2064_REG0F1, 0x3, 0);
+ mod_radio_reg(pi, RADIO_2064_REG0F2, 0xF8, 0x90);
+ mod_radio_reg(pi, RADIO_2064_REG0F3, 0x3, 0x2);
+ mod_radio_reg(pi, RADIO_2064_REG0F3, 0xf0, 0xa0);
+
+ mod_radio_reg(pi, RADIO_2064_REG11F, 0x2, 0x2);
+
+ wlc_lcnphy_clear_tx_power_offsets(pi);
+ mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (10) << 6);
+
+ }
+}
+
+static void wlc_lcnphy_rcal(struct brcms_phy *pi)
+{
+ u8 rcal_value;
+
+ and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
+
+ or_radio_reg(pi, RADIO_2064_REG004, 0x40);
+ or_radio_reg(pi, RADIO_2064_REG120, 0x10);
+
+ or_radio_reg(pi, RADIO_2064_REG078, 0x80);
+ or_radio_reg(pi, RADIO_2064_REG129, 0x02);
+
+ or_radio_reg(pi, RADIO_2064_REG057, 0x01);
+
+ or_radio_reg(pi, RADIO_2064_REG05B, 0x02);
+ mdelay(5);
+ SPINWAIT(!wlc_radio_2064_rcal_done(pi), 10 * 1000 * 1000);
+
+ if (wlc_radio_2064_rcal_done(pi)) {
+ rcal_value = (u8) read_radio_reg(pi, RADIO_2064_REG05C);
+ rcal_value = rcal_value & 0x1f;
+ }
+
+ and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
+
+ and_radio_reg(pi, RADIO_2064_REG057, 0xFE);
+}
+
+static void wlc_lcnphy_rc_cal(struct brcms_phy *pi)
+{
+ u8 dflt_rc_cal_val;
+ u16 flt_val;
+
+ dflt_rc_cal_val = 7;
+ if (LCNREV_IS(pi->pubpi.phy_rev, 1))
+ dflt_rc_cal_val = 11;
+ flt_val =
+ (dflt_rc_cal_val << 10) | (dflt_rc_cal_val << 5) |
+ (dflt_rc_cal_val);
+ write_phy_reg(pi, 0x933, flt_val);
+ write_phy_reg(pi, 0x934, flt_val);
+ write_phy_reg(pi, 0x935, flt_val);
+ write_phy_reg(pi, 0x936, flt_val);
+ write_phy_reg(pi, 0x937, (flt_val & 0x1FF));
+
+ return;
+}
+
+static void wlc_radio_2064_init(struct brcms_phy *pi)
+{
+ u32 i;
+ const struct lcnphy_radio_regs *lcnphyregs = NULL;
+
+ lcnphyregs = lcnphy_radio_regs_2064;
+
+ for (i = 0; lcnphyregs[i].address != 0xffff; i++)
+ if (CHSPEC_IS5G(pi->radio_chanspec) && lcnphyregs[i].do_init_a)
+ write_radio_reg(pi,
+ ((lcnphyregs[i].address & 0x3fff) |
+ RADIO_DEFAULT_CORE),
+ (u16) lcnphyregs[i].init_a);
+ else if (lcnphyregs[i].do_init_g)
+ write_radio_reg(pi,
+ ((lcnphyregs[i].address & 0x3fff) |
+ RADIO_DEFAULT_CORE),
+ (u16) lcnphyregs[i].init_g);
+
+ write_radio_reg(pi, RADIO_2064_REG032, 0x62);
+ write_radio_reg(pi, RADIO_2064_REG033, 0x19);
+
+ write_radio_reg(pi, RADIO_2064_REG090, 0x10);
+
+ write_radio_reg(pi, RADIO_2064_REG010, 0x00);
+
+ if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
+
+ write_radio_reg(pi, RADIO_2064_REG060, 0x7f);
+ write_radio_reg(pi, RADIO_2064_REG061, 0x72);
+ write_radio_reg(pi, RADIO_2064_REG062, 0x7f);
+ }
+
+ write_radio_reg(pi, RADIO_2064_REG01D, 0x02);
+ write_radio_reg(pi, RADIO_2064_REG01E, 0x06);
+
+ mod_phy_reg(pi, 0x4ea, (0x7 << 0), 0 << 0);
+
+ mod_phy_reg(pi, 0x4ea, (0x7 << 3), 1 << 3);
+
+ mod_phy_reg(pi, 0x4ea, (0x7 << 6), 2 << 6);
+
+ mod_phy_reg(pi, 0x4ea, (0x7 << 9), 3 << 9);
+
+ mod_phy_reg(pi, 0x4ea, (0x7 << 12), 4 << 12);
+
+ write_phy_reg(pi, 0x4ea, 0x4688);
+
+ mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
+
+ mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6);
+
+ mod_phy_reg(pi, 0x46a, (0xffff << 0), 25 << 0);
+
+ wlc_lcnphy_set_tx_locc(pi, 0);
+
+ wlc_lcnphy_rcal(pi);
+
+ wlc_lcnphy_rc_cal(pi);
+}
+
+static void wlc_lcnphy_radio_init(struct brcms_phy *pi)
+{
+ wlc_radio_2064_init(pi);
+}
+
+static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)
+{
+ uint idx;
+ u8 phybw40;
+ struct phytbl_info tab;
+ u32 val;
+
+ phybw40 = CHSPEC_IS40(pi->radio_chanspec);
+
+ for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++)
+ wlc_lcnphy_write_table(pi, &dot11lcnphytbl_info_rev0[idx]);
+
+ if (pi->sh->boardflags & BFL_FEM_BT) {
+ tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
+ tab.tbl_width = 16;
+ tab.tbl_ptr = &val;
+ tab.tbl_len = 1;
+ val = 100;
+ tab.tbl_offset = 4;
+ wlc_lcnphy_write_table(pi, &tab);
+ }
+
+ tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
+ tab.tbl_width = 16;
+ tab.tbl_ptr = &val;
+ tab.tbl_len = 1;
+
+ val = 114;
+ tab.tbl_offset = 0;
+ wlc_lcnphy_write_table(pi, &tab);
+
+ val = 130;
+ tab.tbl_offset = 1;
+ wlc_lcnphy_write_table(pi, &tab);
+
+ val = 6;
+ tab.tbl_offset = 8;
+ wlc_lcnphy_write_table(pi, &tab);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if (pi->sh->boardflags & BFL_FEM)
+ wlc_lcnphy_load_tx_gain_table(
+ pi,
+ dot11lcnphy_2GHz_extPA_gaintable_rev0);
+ else
+ wlc_lcnphy_load_tx_gain_table(
+ pi,
+ dot11lcnphy_2GHz_gaintable_rev0);
+ }
+
+ if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
+ const struct phytbl_info *tb;
+ int l;
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ l = dot11lcnphytbl_rx_gain_info_2G_rev2_sz;
+ if (pi->sh->boardflags & BFL_EXTLNA)
+ tb = dot11lcnphytbl_rx_gain_info_extlna_2G_rev2;
+ else
+ tb = dot11lcnphytbl_rx_gain_info_2G_rev2;
+ } else {
+ l = dot11lcnphytbl_rx_gain_info_5G_rev2_sz;
+ if (pi->sh->boardflags & BFL_EXTLNA_5GHz)
+ tb = dot11lcnphytbl_rx_gain_info_extlna_5G_rev2;
+ else
+ tb = dot11lcnphytbl_rx_gain_info_5G_rev2;
+ }
+
+ for (idx = 0; idx < l; idx++)
+ wlc_lcnphy_write_table(pi, &tb[idx]);
+ }
+
+ if ((pi->sh->boardflags & BFL_FEM)
+ && !(pi->sh->boardflags & BFL_FEM_BT))
+ wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313_epa);
+ else if (pi->sh->boardflags & BFL_FEM_BT) {
+ if (pi->sh->boardrev < 0x1250)
+ wlc_lcnphy_write_table(
+ pi,
+ &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa);
+ else
+ wlc_lcnphy_write_table(
+ pi,
+ &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250);
+ } else
+ wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313);
+
+ wlc_lcnphy_load_rfpower(pi);
+
+ wlc_lcnphy_clear_papd_comptable(pi);
+}
+
+static void wlc_lcnphy_rev0_baseband_init(struct brcms_phy *pi)
+{
+ u16 afectrl1;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ write_radio_reg(pi, RADIO_2064_REG11C, 0x0);
+
+ write_phy_reg(pi, 0x43b, 0x0);
+ write_phy_reg(pi, 0x43c, 0x0);
+ write_phy_reg(pi, 0x44c, 0x0);
+ write_phy_reg(pi, 0x4e6, 0x0);
+ write_phy_reg(pi, 0x4f9, 0x0);
+ write_phy_reg(pi, 0x4b0, 0x0);
+ write_phy_reg(pi, 0x938, 0x0);
+ write_phy_reg(pi, 0x4b0, 0x0);
+ write_phy_reg(pi, 0x44e, 0);
+
+ or_phy_reg(pi, 0x567, 0x03);
+
+ or_phy_reg(pi, 0x44a, 0x44);
+ write_phy_reg(pi, 0x44a, 0x80);
+
+ if (!(pi->sh->boardflags & BFL_FEM))
+ wlc_lcnphy_set_tx_pwr_by_index(pi, 52);
+
+ if (0) {
+ afectrl1 = 0;
+ afectrl1 = (u16) ((pi_lcn->lcnphy_rssi_vf) |
+ (pi_lcn->lcnphy_rssi_vc << 4) |
+ (pi_lcn->lcnphy_rssi_gs << 10));
+ write_phy_reg(pi, 0x43e, afectrl1);
+ }
+
+ mod_phy_reg(pi, 0x634, (0xff << 0), 0xC << 0);
+ if (pi->sh->boardflags & BFL_FEM) {
+ mod_phy_reg(pi, 0x634, (0xff << 0), 0xA << 0);
+
+ write_phy_reg(pi, 0x910, 0x1);
+ }
+
+ mod_phy_reg(pi, 0x448, (0x3 << 8), 1 << 8);
+ mod_phy_reg(pi, 0x608, (0xff << 0), 0x17 << 0);
+ mod_phy_reg(pi, 0x604, (0x7ff << 0), 0x3EA << 0);
+
+}
+
+static void wlc_lcnphy_rev2_baseband_init(struct brcms_phy *pi)
+{
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ mod_phy_reg(pi, 0x416, (0xff << 0), 80 << 0);
+ mod_phy_reg(pi, 0x416, (0xff << 8), 80 << 8);
+ }
+}
+
+static void wlc_lcnphy_agc_temp_init(struct brcms_phy *pi)
+{
+ s16 temp;
+ struct phytbl_info tab;
+ u32 tableBuffer[2];
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ temp = (s16) read_phy_reg(pi, 0x4df);
+ pi_lcn->lcnphy_ofdmgainidxtableoffset = (temp & (0xff << 0)) >> 0;
+
+ if (pi_lcn->lcnphy_ofdmgainidxtableoffset > 127)
+ pi_lcn->lcnphy_ofdmgainidxtableoffset -= 256;
+
+ pi_lcn->lcnphy_dsssgainidxtableoffset = (temp & (0xff << 8)) >> 8;
+
+ if (pi_lcn->lcnphy_dsssgainidxtableoffset > 127)
+ pi_lcn->lcnphy_dsssgainidxtableoffset -= 256;
+
+ tab.tbl_ptr = tableBuffer;
+ tab.tbl_len = 2;
+ tab.tbl_id = 17;
+ tab.tbl_offset = 59;
+ tab.tbl_width = 32;
+ wlc_lcnphy_read_table(pi, &tab);
+
+ if (tableBuffer[0] > 63)
+ tableBuffer[0] -= 128;
+ pi_lcn->lcnphy_tr_R_gain_val = tableBuffer[0];
+
+ if (tableBuffer[1] > 63)
+ tableBuffer[1] -= 128;
+ pi_lcn->lcnphy_tr_T_gain_val = tableBuffer[1];
+
+ temp = (s16) (read_phy_reg(pi, 0x434) & (0xff << 0));
+ if (temp > 127)
+ temp -= 256;
+ pi_lcn->lcnphy_input_pwr_offset_db = (s8) temp;
+
+ pi_lcn->lcnphy_Med_Low_Gain_db =
+ (read_phy_reg(pi, 0x424) & (0xff << 8)) >> 8;
+ pi_lcn->lcnphy_Very_Low_Gain_db =
+ (read_phy_reg(pi, 0x425) & (0xff << 0)) >> 0;
+
+ tab.tbl_ptr = tableBuffer;
+ tab.tbl_len = 2;
+ tab.tbl_id = LCNPHY_TBL_ID_GAIN_IDX;
+ tab.tbl_offset = 28;
+ tab.tbl_width = 32;
+ wlc_lcnphy_read_table(pi, &tab);
+
+ pi_lcn->lcnphy_gain_idx_14_lowword = tableBuffer[0];
+ pi_lcn->lcnphy_gain_idx_14_hiword = tableBuffer[1];
+
+}
+
+static void wlc_lcnphy_baseband_init(struct brcms_phy *pi)
+{
+
+ wlc_lcnphy_tbl_init(pi);
+ wlc_lcnphy_rev0_baseband_init(pi);
+ if (LCNREV_IS(pi->pubpi.phy_rev, 2))
+ wlc_lcnphy_rev2_baseband_init(pi);
+ wlc_lcnphy_bu_tweaks(pi);
+}
+
+void wlc_phy_init_lcnphy(struct brcms_phy *pi)
+{
+ u8 phybw40;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+ phybw40 = CHSPEC_IS40(pi->radio_chanspec);
+
+ pi_lcn->lcnphy_cal_counter = 0;
+ pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense;
+
+ or_phy_reg(pi, 0x44a, 0x80);
+ and_phy_reg(pi, 0x44a, 0x7f);
+
+ wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X);
+
+ write_phy_reg(pi, 0x60a, 160);
+
+ write_phy_reg(pi, 0x46a, 25);
+
+ wlc_lcnphy_baseband_init(pi);
+
+ wlc_lcnphy_radio_init(pi);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ wlc_lcnphy_tx_pwr_ctrl_init((struct brcms_phy_pub *) pi);
+
+ wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec);
+
+ si_pmu_regcontrol(pi->sh->sih, 0, 0xf, 0x9);
+
+ si_pmu_chipcontrol(pi->sh->sih, 0, 0xffffffff, 0x03CDDDDD);
+
+ if ((pi->sh->boardflags & BFL_FEM)
+ && wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
+ wlc_lcnphy_set_tx_pwr_by_index(pi, FIXED_TXPWR);
+
+ wlc_lcnphy_agc_temp_init(pi);
+
+ wlc_lcnphy_temp_adj(pi);
+
+ mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
+
+ udelay(100);
+ mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
+
+ wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
+ pi_lcn->lcnphy_noise_samples = LCNPHY_NOISE_SAMPLES_DEFAULT;
+ wlc_lcnphy_calib_modes(pi, PHY_PERICAL_PHYINIT);
+}
+
+static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
+{
+ s8 txpwr = 0;
+ int i;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+ struct phy_shim_info *shim = pi->sh->physhim;
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ u16 cckpo = 0;
+ u32 offset_ofdm, offset_mcs;
+
+ pi_lcn->lcnphy_tr_isolation_mid =
+ (u8)wlapi_getintvar(shim, BRCMS_SROM_TRISO2G);
+
+ pi_lcn->lcnphy_rx_power_offset =
+ (u8)wlapi_getintvar(shim, BRCMS_SROM_RXPO2G);
+
+ pi->txpa_2g[0] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B0);
+ pi->txpa_2g[1] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B1);
+ pi->txpa_2g[2] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B2);
+
+ pi_lcn->lcnphy_rssi_vf =
+ (u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISMF2G);
+ pi_lcn->lcnphy_rssi_vc =
+ (u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISMC2G);
+ pi_lcn->lcnphy_rssi_gs =
+ (u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISAV2G);
+
+ pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf;
+ pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc;
+ pi_lcn->lcnphy_rssi_gs_lowtemp = pi_lcn->lcnphy_rssi_gs;
+
+ pi_lcn->lcnphy_rssi_vf_hightemp = pi_lcn->lcnphy_rssi_vf;
+ pi_lcn->lcnphy_rssi_vc_hightemp = pi_lcn->lcnphy_rssi_vc;
+ pi_lcn->lcnphy_rssi_gs_hightemp = pi_lcn->lcnphy_rssi_gs;
+
+ txpwr = (s8)wlapi_getintvar(shim, BRCMS_SROM_MAXP2GA0);
+ pi->tx_srom_max_2g = txpwr;
+
+ for (i = 0; i < PWRTBL_NUM_COEFF; i++) {
+ pi->txpa_2g_low_temp[i] = pi->txpa_2g[i];
+ pi->txpa_2g_high_temp[i] = pi->txpa_2g[i];
+ }
+
+ cckpo = (u16)wlapi_getintvar(shim, BRCMS_SROM_CCK2GPO);
+ offset_ofdm = (u32)wlapi_getintvar(shim, BRCMS_SROM_OFDM2GPO);
+ if (cckpo) {
+ uint max_pwr_chan = txpwr;
+
+ for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {
+ pi->tx_srom_max_rate_2g[i] =
+ max_pwr_chan - ((cckpo & 0xf) * 2);
+ cckpo >>= 4;
+ }
+
+ for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
+ pi->tx_srom_max_rate_2g[i] =
+ max_pwr_chan -
+ ((offset_ofdm & 0xf) * 2);
+ offset_ofdm >>= 4;
+ }
+ } else {
+ u8 opo = 0;
+
+ opo = (u8)wlapi_getintvar(shim, BRCMS_SROM_OPO);
+
+ for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++)
+ pi->tx_srom_max_rate_2g[i] = txpwr;
+
+ for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
+ pi->tx_srom_max_rate_2g[i] = txpwr -
+ ((offset_ofdm & 0xf) * 2);
+ offset_ofdm >>= 4;
+ }
+ offset_mcs =
+ wlapi_getintvar(shim,
+ BRCMS_SROM_MCS2GPO1) << 16;
+ offset_mcs |=
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS2GPO0);
+ pi_lcn->lcnphy_mcs20_po = offset_mcs;
+ for (i = TXP_FIRST_SISO_MCS_20;
+ i <= TXP_LAST_SISO_MCS_20; i++) {
+ pi->tx_srom_max_rate_2g[i] =
+ txpwr - ((offset_mcs & 0xf) * 2);
+ offset_mcs >>= 4;
+ }
+ }
+
+ pi_lcn->lcnphy_rawtempsense =
+ (u16)wlapi_getintvar(shim, BRCMS_SROM_RAWTEMPSENSE);
+ pi_lcn->lcnphy_measPower =
+ (u8)wlapi_getintvar(shim, BRCMS_SROM_MEASPOWER);
+ pi_lcn->lcnphy_tempsense_slope =
+ (u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPSENSE_SLOPE);
+ pi_lcn->lcnphy_hw_iqcal_en =
+ (bool)wlapi_getintvar(shim, BRCMS_SROM_HW_IQCAL_EN);
+ pi_lcn->lcnphy_iqcal_swp_dis =
+ (bool)wlapi_getintvar(shim, BRCMS_SROM_IQCAL_SWP_DIS);
+ pi_lcn->lcnphy_tempcorrx =
+ (u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPCORRX);
+ pi_lcn->lcnphy_tempsense_option =
+ (u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPSENSE_OPTION);
+ pi_lcn->lcnphy_freqoffset_corr =
+ (u8)wlapi_getintvar(shim, BRCMS_SROM_FREQOFFSET_CORR);
+ if ((u8)wlapi_getintvar(shim, BRCMS_SROM_AA2G) > 1)
+ wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi,
+ (u8) wlapi_getintvar(shim, BRCMS_SROM_AA2G));
+ }
+ pi_lcn->lcnphy_cck_dig_filt_type = -1;
+
+ return true;
+}
+
+void wlc_2064_vco_cal(struct brcms_phy *pi)
+{
+ u8 calnrst;
+
+ mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 1 << 3);
+ calnrst = (u8) read_radio_reg(pi, RADIO_2064_REG056) & 0xf8;
+ write_radio_reg(pi, RADIO_2064_REG056, calnrst);
+ udelay(1);
+ write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x03);
+ udelay(1);
+ write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x07);
+ udelay(300);
+ mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 0);
+}
+
+bool wlc_phy_tpc_isenabled_lcnphy(struct brcms_phy *pi)
+{
+ if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
+ return 0;
+ else
+ return (LCNPHY_TX_PWR_CTRL_HW ==
+ wlc_lcnphy_get_tx_pwr_ctrl((pi)));
+}
+
+void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi)
+{
+ u16 pwr_ctrl;
+ if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
+ wlc_lcnphy_calib_modes(pi, LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
+ } else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
+ pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
+ wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
+ wlc_lcnphy_txpower_recalc_target(pi);
+ wlc_lcnphy_set_tx_pwr_ctrl(pi, pwr_ctrl);
+ }
+}
+
+void wlc_phy_detach_lcnphy(struct brcms_phy *pi)
+{
+ kfree(pi->u.pi_lcnphy);
+}
+
+bool wlc_phy_attach_lcnphy(struct brcms_phy *pi)
+{
+ struct brcms_phy_lcnphy *pi_lcn;
+
+ pi->u.pi_lcnphy = kzalloc(sizeof(struct brcms_phy_lcnphy), GFP_ATOMIC);
+ if (pi->u.pi_lcnphy == NULL)
+ return false;
+
+ pi_lcn = pi->u.pi_lcnphy;
+
+ if (0 == (pi->sh->boardflags & BFL_NOPA)) {
+ pi->hwpwrctrl = true;
+ pi->hwpwrctrl_capable = true;
+ }
+
+ pi->xtalfreq = si_pmu_alp_clock(pi->sh->sih);
+ pi_lcn->lcnphy_papd_rxGnCtrl_init = 0;
+
+ pi->pi_fptr.init = wlc_phy_init_lcnphy;
+ pi->pi_fptr.calinit = wlc_phy_cal_init_lcnphy;
+ pi->pi_fptr.chanset = wlc_phy_chanspec_set_lcnphy;
+ pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_lcnphy;
+ pi->pi_fptr.txiqccget = wlc_lcnphy_get_tx_iqcc;
+ pi->pi_fptr.txiqccset = wlc_lcnphy_set_tx_iqcc;
+ pi->pi_fptr.txloccget = wlc_lcnphy_get_tx_locc;
+ pi->pi_fptr.radioloftget = wlc_lcnphy_get_radio_loft;
+ pi->pi_fptr.detach = wlc_phy_detach_lcnphy;
+
+ if (!wlc_phy_txpwr_srom_read_lcnphy(pi))
+ return false;
+
+ if ((pi->sh->boardflags & BFL_FEM) &&
+ (LCNREV_IS(pi->pubpi.phy_rev, 1))) {
+ if (pi_lcn->lcnphy_tempsense_option == 3) {
+ pi->hwpwrctrl = true;
+ pi->hwpwrctrl_capable = true;
+ pi->temppwrctrl_capable = false;
+ } else {
+ pi->hwpwrctrl = false;
+ pi->hwpwrctrl_capable = false;
+ pi->temppwrctrl_capable = true;
+ }
+ }
+
+ return true;
+}
+
+static void wlc_lcnphy_set_rx_gain(struct brcms_phy *pi, u32 gain)
+{
+ u16 trsw, ext_lna, lna1, lna2, tia, biq0, biq1, gain0_15, gain16_19;
+
+ trsw = (gain & ((u32) 1 << 28)) ? 0 : 1;
+ ext_lna = (u16) (gain >> 29) & 0x01;
+ lna1 = (u16) (gain >> 0) & 0x0f;
+ lna2 = (u16) (gain >> 4) & 0x0f;
+ tia = (u16) (gain >> 8) & 0xf;
+ biq0 = (u16) (gain >> 12) & 0xf;
+ biq1 = (u16) (gain >> 16) & 0xf;
+
+ gain0_15 = (u16) ((lna1 & 0x3) | ((lna1 & 0x3) << 2) |
+ ((lna2 & 0x3) << 4) | ((lna2 & 0x3) << 6) |
+ ((tia & 0xf) << 8) | ((biq0 & 0xf) << 12));
+ gain16_19 = biq1;
+
+ mod_phy_reg(pi, 0x44d, (0x1 << 0), trsw << 0);
+ mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
+ mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
+ mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
+ mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
+ mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3);
+ }
+ wlc_lcnphy_rx_gain_override_enable(pi, true);
+}
+
+static u32 wlc_lcnphy_get_receive_power(struct brcms_phy *pi, s32 *gain_index)
+{
+ u32 received_power = 0;
+ s32 max_index = 0;
+ u32 gain_code = 0;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ max_index = 36;
+ if (*gain_index >= 0)
+ gain_code = lcnphy_23bitgaincode_table[*gain_index];
+
+ if (-1 == *gain_index) {
+ *gain_index = 0;
+ while ((*gain_index <= (s32) max_index)
+ && (received_power < 700)) {
+ wlc_lcnphy_set_rx_gain(pi,
+ lcnphy_23bitgaincode_table
+ [*gain_index]);
+ received_power =
+ wlc_lcnphy_measure_digital_power(
+ pi,
+ pi_lcn->
+ lcnphy_noise_samples);
+ (*gain_index)++;
+ }
+ (*gain_index)--;
+ } else {
+ wlc_lcnphy_set_rx_gain(pi, gain_code);
+ received_power =
+ wlc_lcnphy_measure_digital_power(pi,
+ pi_lcn->
+ lcnphy_noise_samples);
+ }
+
+ return received_power;
+}
+
+s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index)
+{
+ s32 gain = 0;
+ s32 nominal_power_db;
+ s32 log_val, gain_mismatch, desired_gain, input_power_offset_db,
+ input_power_db;
+ s32 received_power, temperature;
+ u32 power;
+ u32 msb1, msb2, val1, val2, diff1, diff2;
+ uint freq;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ received_power = wlc_lcnphy_get_receive_power(pi, &gain_index);
+
+ gain = lcnphy_gain_table[gain_index];
+
+ nominal_power_db = read_phy_reg(pi, 0x425) >> 8;
+
+ power = (received_power * 16);
+ msb1 = ffs(power) - 1;
+ msb2 = msb1 + 1;
+ val1 = 1 << msb1;
+ val2 = 1 << msb2;
+ diff1 = (power - val1);
+ diff2 = (val2 - power);
+ if (diff1 < diff2)
+ log_val = msb1;
+ else
+ log_val = msb2;
+
+ log_val = log_val * 3;
+
+ gain_mismatch = (nominal_power_db / 2) - (log_val);
+
+ desired_gain = gain + gain_mismatch;
+
+ input_power_offset_db = read_phy_reg(pi, 0x434) & 0xFF;
+
+ if (input_power_offset_db > 127)
+ input_power_offset_db -= 256;
+
+ input_power_db = input_power_offset_db - desired_gain;
+
+ input_power_db =
+ input_power_db + lcnphy_gain_index_offset_for_rssi[gain_index];
+
+ freq = wlc_phy_channel2freq(CHSPEC_CHANNEL(pi->radio_chanspec));
+ if ((freq > 2427) && (freq <= 2467))
+ input_power_db = input_power_db - 1;
+
+ temperature = pi_lcn->lcnphy_lastsensed_temperature;
+
+ if ((temperature - 15) < -30)
+ input_power_db =
+ input_power_db +
+ (((temperature - 10 - 25) * 286) >> 12) -
+ 7;
+ else if ((temperature - 15) < 4)
+ input_power_db =
+ input_power_db +
+ (((temperature - 10 - 25) * 286) >> 12) -
+ 3;
+ else
+ input_power_db = input_power_db +
+ (((temperature - 10 - 25) * 286) >> 12);
+
+ wlc_lcnphy_rx_gain_override_enable(pi, 0);
+
+ return input_power_db;
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.h
new file mode 100644
index 000000000000..f4a8ab09da43
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_PHY_LCN_H_
+#define _BRCM_PHY_LCN_H_
+
+#include <types.h>
+
+struct brcms_phy_lcnphy {
+ int lcnphy_txrf_sp_9_override;
+ u8 lcnphy_full_cal_channel;
+ u8 lcnphy_cal_counter;
+ u16 lcnphy_cal_temper;
+ bool lcnphy_recal;
+
+ u8 lcnphy_rc_cap;
+ u32 lcnphy_mcs20_po;
+
+ u8 lcnphy_tr_isolation_mid;
+ u8 lcnphy_tr_isolation_low;
+ u8 lcnphy_tr_isolation_hi;
+
+ u8 lcnphy_bx_arch;
+ u8 lcnphy_rx_power_offset;
+ u8 lcnphy_rssi_vf;
+ u8 lcnphy_rssi_vc;
+ u8 lcnphy_rssi_gs;
+ u8 lcnphy_tssi_val;
+ u8 lcnphy_rssi_vf_lowtemp;
+ u8 lcnphy_rssi_vc_lowtemp;
+ u8 lcnphy_rssi_gs_lowtemp;
+
+ u8 lcnphy_rssi_vf_hightemp;
+ u8 lcnphy_rssi_vc_hightemp;
+ u8 lcnphy_rssi_gs_hightemp;
+
+ s16 lcnphy_pa0b0;
+ s16 lcnphy_pa0b1;
+ s16 lcnphy_pa0b2;
+
+ u16 lcnphy_rawtempsense;
+ u8 lcnphy_measPower;
+ u8 lcnphy_tempsense_slope;
+ u8 lcnphy_freqoffset_corr;
+ u8 lcnphy_tempsense_option;
+ u8 lcnphy_tempcorrx;
+ bool lcnphy_iqcal_swp_dis;
+ bool lcnphy_hw_iqcal_en;
+ uint lcnphy_bandedge_corr;
+ bool lcnphy_spurmod;
+ u16 lcnphy_tssi_tx_cnt;
+ u16 lcnphy_tssi_idx;
+ u16 lcnphy_tssi_npt;
+
+ u16 lcnphy_target_tx_freq;
+ s8 lcnphy_tx_power_idx_override;
+ u16 lcnphy_noise_samples;
+
+ u32 lcnphy_papdRxGnIdx;
+ u32 lcnphy_papd_rxGnCtrl_init;
+
+ u32 lcnphy_gain_idx_14_lowword;
+ u32 lcnphy_gain_idx_14_hiword;
+ u32 lcnphy_gain_idx_27_lowword;
+ u32 lcnphy_gain_idx_27_hiword;
+ s16 lcnphy_ofdmgainidxtableoffset;
+ s16 lcnphy_dsssgainidxtableoffset;
+ u32 lcnphy_tr_R_gain_val;
+ u32 lcnphy_tr_T_gain_val;
+ s8 lcnphy_input_pwr_offset_db;
+ u16 lcnphy_Med_Low_Gain_db;
+ u16 lcnphy_Very_Low_Gain_db;
+ s8 lcnphy_lastsensed_temperature;
+ s8 lcnphy_pkteng_rssi_slope;
+ u8 lcnphy_saved_tx_user_target[TXP_NUM_RATES];
+ u8 lcnphy_volt_winner;
+ u8 lcnphy_volt_low;
+ u8 lcnphy_54_48_36_24mbps_backoff;
+ u8 lcnphy_11n_backoff;
+ u8 lcnphy_lowerofdm;
+ u8 lcnphy_cck;
+ u8 lcnphy_psat_2pt3_detected;
+ s32 lcnphy_lowest_Re_div_Im;
+ s8 lcnphy_final_papd_cal_idx;
+ u16 lcnphy_extstxctrl4;
+ u16 lcnphy_extstxctrl0;
+ u16 lcnphy_extstxctrl1;
+ s16 lcnphy_cck_dig_filt_type;
+ s16 lcnphy_ofdm_dig_filt_type;
+ struct lcnphy_cal_results lcnphy_cal_results;
+
+ u8 lcnphy_psat_pwr;
+ u8 lcnphy_psat_indx;
+ s32 lcnphy_min_phase;
+ u8 lcnphy_final_idx;
+ u8 lcnphy_start_idx;
+ u8 lcnphy_current_index;
+ u16 lcnphy_logen_buf_1;
+ u16 lcnphy_local_ovr_2;
+ u16 lcnphy_local_oval_6;
+ u16 lcnphy_local_oval_5;
+ u16 lcnphy_logen_mixer_1;
+
+ u8 lcnphy_aci_stat;
+ uint lcnphy_aci_start_time;
+ s8 lcnphy_tx_power_offset[TXP_NUM_RATES];
+};
+#endif /* _BRCM_PHY_LCN_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
new file mode 100644
index 000000000000..cd19c2f7a347
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
@@ -0,0 +1,28876 @@
+/*
+ * Copyright (c) 2010 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/kernel.h>
+#include <linux/delay.h>
+#include <linux/cordic.h>
+
+#include <brcm_hw_ids.h>
+#include <aiutils.h>
+#include <chipcommon.h>
+#include <pmu.h>
+#include <d11.h>
+#include <phy_shim.h>
+#include "phy_int.h"
+#include "phy_hal.h"
+#include "phy_radio.h"
+#include "phyreg_n.h"
+#include "phytbl_n.h"
+
+#define READ_RADIO_REG2(pi, radio_type, jspace, core, reg_name) \
+ read_radio_reg(pi, radio_type##_##jspace##_##reg_name | \
+ ((core == PHY_CORE_0) ? \
+ radio_type##_##jspace##0 : \
+ radio_type##_##jspace##1))
+
+#define WRITE_RADIO_REG2(pi, radio_type, jspace, core, reg_name, value) \
+ write_radio_reg(pi, radio_type##_##jspace##_##reg_name | \
+ ((core == PHY_CORE_0) ? \
+ radio_type##_##jspace##0 : \
+ radio_type##_##jspace##1), value)
+
+#define WRITE_RADIO_SYN(pi, radio_type, reg_name, value) \
+ write_radio_reg(pi, radio_type##_##SYN##_##reg_name, value)
+
+#define READ_RADIO_REG3(pi, radio_type, jspace, core, reg_name) \
+ read_radio_reg(pi, ((core == PHY_CORE_0) ? \
+ radio_type##_##jspace##0##_##reg_name : \
+ radio_type##_##jspace##1##_##reg_name))
+
+#define WRITE_RADIO_REG3(pi, radio_type, jspace, core, reg_name, value) \
+ write_radio_reg(pi, ((core == PHY_CORE_0) ? \
+ radio_type##_##jspace##0##_##reg_name : \
+ radio_type##_##jspace##1##_##reg_name), \
+ value)
+
+#define READ_RADIO_REG4(pi, radio_type, jspace, core, reg_name) \
+ read_radio_reg(pi, ((core == PHY_CORE_0) ? \
+ radio_type##_##reg_name##_##jspace##0 : \
+ radio_type##_##reg_name##_##jspace##1))
+
+#define WRITE_RADIO_REG4(pi, radio_type, jspace, core, reg_name, value) \
+ write_radio_reg(pi, ((core == PHY_CORE_0) ? \
+ radio_type##_##reg_name##_##jspace##0 : \
+ radio_type##_##reg_name##_##jspace##1), \
+ value)
+
+#define NPHY_ACI_MAX_UNDETECT_WINDOW_SZ 40
+#define NPHY_ACI_CHANNEL_DELTA 5
+#define NPHY_ACI_CHANNEL_SKIP 4
+#define NPHY_ACI_40MHZ_CHANNEL_DELTA 6
+#define NPHY_ACI_40MHZ_CHANNEL_SKIP 5
+#define NPHY_ACI_40MHZ_CHANNEL_DELTA_GE_REV3 6
+#define NPHY_ACI_40MHZ_CHANNEL_SKIP_GE_REV3 5
+#define NPHY_ACI_CHANNEL_DELTA_GE_REV3 4
+#define NPHY_ACI_CHANNEL_SKIP_GE_REV3 3
+
+#define NPHY_NOISE_NOASSOC_GLITCH_TH_UP 2
+
+#define NPHY_NOISE_NOASSOC_GLITCH_TH_DN 8
+
+#define NPHY_NOISE_ASSOC_GLITCH_TH_UP 2
+
+#define NPHY_NOISE_ASSOC_GLITCH_TH_DN 8
+
+#define NPHY_NOISE_ASSOC_ACI_GLITCH_TH_UP 2
+
+#define NPHY_NOISE_ASSOC_ACI_GLITCH_TH_DN 8
+
+#define NPHY_NOISE_NOASSOC_ENTER_TH 400
+
+#define NPHY_NOISE_ASSOC_ENTER_TH 400
+
+#define NPHY_NOISE_ASSOC_RX_GLITCH_BADPLCP_ENTER_TH 400
+
+#define NPHY_NOISE_CRSMINPWR_ARRAY_MAX_INDEX 44
+#define NPHY_NOISE_CRSMINPWR_ARRAY_MAX_INDEX_REV_7 56
+
+#define NPHY_NOISE_NOASSOC_CRSIDX_INCR 16
+
+#define NPHY_NOISE_ASSOC_CRSIDX_INCR 8
+
+#define NPHY_IS_SROM_REINTERPRET NREV_GE(pi->pubpi.phy_rev, 5)
+
+#define NPHY_RSSICAL_MAXREAD 31
+
+#define NPHY_RSSICAL_NPOLL 8
+#define NPHY_RSSICAL_MAXD (1<<20)
+#define NPHY_MIN_RXIQ_PWR 2
+
+#define NPHY_RSSICAL_W1_TARGET 25
+#define NPHY_RSSICAL_W2_TARGET NPHY_RSSICAL_W1_TARGET
+#define NPHY_RSSICAL_NB_TARGET 0
+
+#define NPHY_RSSICAL_W1_TARGET_REV3 29
+#define NPHY_RSSICAL_W2_TARGET_REV3 NPHY_RSSICAL_W1_TARGET_REV3
+
+#define NPHY_CALSANITY_RSSI_NB_MAX_POS 9
+#define NPHY_CALSANITY_RSSI_NB_MAX_NEG -9
+#define NPHY_CALSANITY_RSSI_W1_MAX_POS 12
+#define NPHY_CALSANITY_RSSI_W1_MAX_NEG (NPHY_RSSICAL_W1_TARGET - \
+ NPHY_RSSICAL_MAXREAD)
+#define NPHY_CALSANITY_RSSI_W2_MAX_POS NPHY_CALSANITY_RSSI_W1_MAX_POS
+#define NPHY_CALSANITY_RSSI_W2_MAX_NEG (NPHY_RSSICAL_W2_TARGET - \
+ NPHY_RSSICAL_MAXREAD)
+#define NPHY_RSSI_SXT(x) ((s8) (-((x) & 0x20) + ((x) & 0x1f)))
+#define NPHY_RSSI_NB_VIOL(x) (((x) > NPHY_CALSANITY_RSSI_NB_MAX_POS) || \
+ ((x) < NPHY_CALSANITY_RSSI_NB_MAX_NEG))
+#define NPHY_RSSI_W1_VIOL(x) (((x) > NPHY_CALSANITY_RSSI_W1_MAX_POS) || \
+ ((x) < NPHY_CALSANITY_RSSI_W1_MAX_NEG))
+#define NPHY_RSSI_W2_VIOL(x) (((x) > NPHY_CALSANITY_RSSI_W2_MAX_POS) || \
+ ((x) < NPHY_CALSANITY_RSSI_W2_MAX_NEG))
+
+#define NPHY_IQCAL_NUMGAINS 9
+#define NPHY_N_GCTL 0x66
+
+#define NPHY_PAPD_EPS_TBL_SIZE 64
+#define NPHY_PAPD_SCL_TBL_SIZE 64
+#define NPHY_NUM_DIG_FILT_COEFFS 15
+
+#define NPHY_PAPD_COMP_OFF 0
+#define NPHY_PAPD_COMP_ON 1
+
+#define NPHY_SROM_TEMPSHIFT 32
+#define NPHY_SROM_MAXTEMPOFFSET 16
+#define NPHY_SROM_MINTEMPOFFSET -16
+
+#define NPHY_CAL_MAXTEMPDELTA 64
+
+#define NPHY_NOISEVAR_TBLLEN40 256
+#define NPHY_NOISEVAR_TBLLEN20 128
+
+#define NPHY_ANARXLPFBW_REDUCTIONFACT 7
+
+#define NPHY_ADJUSTED_MINCRSPOWER 0x1e
+
+/* 5357 Chip specific ChipControl register bits */
+#define CCTRL5357_EXTPA (1<<14) /* extPA in ChipControl 1, bit 14 */
+#define CCTRL5357_ANT_MUX_2o3 (1<<15) /* 2o3 in ChipControl 1, bit 15 */
+
+#define NPHY_CAL_TSSISAMPS 64
+#define NPHY_TEST_TONE_FREQ_40MHz 4000
+#define NPHY_TEST_TONE_FREQ_20MHz 2500
+
+#define MAX_205x_RCAL_WAITLOOPS 10000
+
+#define NPHY_RXCAL_TONEAMP 181
+#define NPHY_RXCAL_TONEFREQ_40MHz 4000
+#define NPHY_RXCAL_TONEFREQ_20MHz 2000
+
+#define TXFILT_SHAPING_OFDM20 0
+#define TXFILT_SHAPING_OFDM40 1
+#define TXFILT_SHAPING_CCK 2
+#define TXFILT_DEFAULT_OFDM20 3
+#define TXFILT_DEFAULT_OFDM40 4
+
+struct nphy_iqcal_params {
+ u16 txlpf;
+ u16 txgm;
+ u16 pga;
+ u16 pad;
+ u16 ipa;
+ u16 cal_gain;
+ u16 ncorr[5];
+};
+
+struct nphy_txiqcal_ladder {
+ u8 percent;
+ u8 g_env;
+};
+
+struct nphy_ipa_txcalgains {
+ struct nphy_txgains gains;
+ bool useindex;
+ u8 index;
+};
+
+struct nphy_papd_restore_state {
+ u16 fbmix[2];
+ u16 vga_master[2];
+ u16 intpa_master[2];
+ u16 afectrl[2];
+ u16 afeoverride[2];
+ u16 pwrup[2];
+ u16 atten[2];
+ u16 mm;
+};
+
+struct nphy_ipa_txrxgain {
+ u16 hpvga;
+ u16 lpf_biq1;
+ u16 lpf_biq0;
+ u16 lna2;
+ u16 lna1;
+ s8 txpwrindex;
+};
+
+#define NPHY_IPA_RXCAL_MAXGAININDEX (6 - 1)
+
+static const struct nphy_ipa_txrxgain nphy_ipa_rxcal_gaintbl_5GHz[] = {
+ {0, 0, 0, 0, 0, 100},
+ {0, 0, 0, 0, 0, 50},
+ {0, 0, 0, 0, 0, -1},
+ {0, 0, 0, 3, 0, -1},
+ {0, 0, 3, 3, 0, -1},
+ {0, 2, 3, 3, 0, -1}
+};
+
+static const struct nphy_ipa_txrxgain nphy_ipa_rxcal_gaintbl_2GHz[] = {
+ {0, 0, 0, 0, 0, 128},
+ {0, 0, 0, 0, 0, 70},
+ {0, 0, 0, 0, 0, 20},
+ {0, 0, 0, 3, 0, 20},
+ {0, 0, 3, 3, 0, 20},
+ {0, 2, 3, 3, 0, 20}
+};
+
+static const struct nphy_ipa_txrxgain nphy_ipa_rxcal_gaintbl_5GHz_rev7[] = {
+ {0, 0, 0, 0, 0, 100},
+ {0, 0, 0, 0, 0, 50},
+ {0, 0, 0, 0, 0, -1},
+ {0, 0, 0, 3, 0, -1},
+ {0, 0, 3, 3, 0, -1},
+ {0, 0, 5, 3, 0, -1}
+};
+
+static const struct nphy_ipa_txrxgain nphy_ipa_rxcal_gaintbl_2GHz_rev7[] = {
+ {0, 0, 0, 0, 0, 10},
+ {0, 0, 0, 1, 0, 10},
+ {0, 0, 1, 2, 0, 10},
+ {0, 0, 1, 3, 0, 10},
+ {0, 0, 4, 3, 0, 10},
+ {0, 0, 6, 3, 0, 10}
+};
+
+enum {
+ NPHY_RXCAL_GAIN_INIT = 0,
+ NPHY_RXCAL_GAIN_UP,
+ NPHY_RXCAL_GAIN_DOWN
+};
+
+#define wlc_phy_get_papd_nphy(pi) \
+ (read_phy_reg((pi), 0x1e7) & \
+ ((0x1 << 15) | \
+ (0x1 << 14) | \
+ (0x1 << 13)))
+
+static const u16 NPHY_IPA_REV4_txdigi_filtcoeffs[][NPHY_NUM_DIG_FILT_COEFFS] = {
+ {-377, 137, -407, 208, -1527, 956, 93, 186, 93,
+ 230, -44, 230, 201, -191, 201},
+ {-77, 20, -98, 49, -93, 60, 56, 111, 56, 26, -5,
+ 26, 34, -32, 34},
+ {-360, 164, -376, 164, -1533, 576, 308, -314, 308,
+ 121, -73, 121, 91, 124, 91},
+ {-295, 200, -363, 142, -1391, 826, 151, 301, 151,
+ 151, 301, 151, 602, -752, 602},
+ {-92, 58, -96, 49, -104, 44, 17, 35, 17,
+ 12, 25, 12, 13, 27, 13},
+ {-375, 136, -399, 209, -1479, 949, 130, 260, 130,
+ 230, -44, 230, 201, -191, 201},
+ {0xed9, 0xc8, 0xe95, 0x8e, 0xa91, 0x33a, 0x97, 0x12d, 0x97,
+ 0x97, 0x12d, 0x97, 0x25a, 0xd10, 0x25a}
+};
+
+struct chan_info_nphy_2055 {
+ u16 chan;
+ u16 freq;
+ uint unknown;
+ u8 RF_pll_ref;
+ u8 RF_rf_pll_mod1;
+ u8 RF_rf_pll_mod0;
+ u8 RF_vco_cap_tail;
+ u8 RF_vco_cal1;
+ u8 RF_vco_cal2;
+ u8 RF_pll_lf_c1;
+ u8 RF_pll_lf_r1;
+ u8 RF_pll_lf_c2;
+ u8 RF_lgbuf_cen_buf;
+ u8 RF_lgen_tune1;
+ u8 RF_lgen_tune2;
+ u8 RF_core1_lgbuf_a_tune;
+ u8 RF_core1_lgbuf_g_tune;
+ u8 RF_core1_rxrf_reg1;
+ u8 RF_core1_tx_pga_pad_tn;
+ u8 RF_core1_tx_mx_bgtrim;
+ u8 RF_core2_lgbuf_a_tune;
+ u8 RF_core2_lgbuf_g_tune;
+ u8 RF_core2_rxrf_reg1;
+ u8 RF_core2_tx_pga_pad_tn;
+ u8 RF_core2_tx_mx_bgtrim;
+ u16 PHY_BW1a;
+ u16 PHY_BW2;
+ u16 PHY_BW3;
+ u16 PHY_BW4;
+ u16 PHY_BW5;
+ u16 PHY_BW6;
+};
+
+struct chan_info_nphy_radio205x {
+ u16 chan;
+ u16 freq;
+ u8 RF_SYN_pll_vcocal1;
+ u8 RF_SYN_pll_vcocal2;
+ u8 RF_SYN_pll_refdiv;
+ u8 RF_SYN_pll_mmd2;
+ u8 RF_SYN_pll_mmd1;
+ u8 RF_SYN_pll_loopfilter1;
+ u8 RF_SYN_pll_loopfilter2;
+ u8 RF_SYN_pll_loopfilter3;
+ u8 RF_SYN_pll_loopfilter4;
+ u8 RF_SYN_pll_loopfilter5;
+ u8 RF_SYN_reserved_addr27;
+ u8 RF_SYN_reserved_addr28;
+ u8 RF_SYN_reserved_addr29;
+ u8 RF_SYN_logen_VCOBUF1;
+ u8 RF_SYN_logen_MIXER2;
+ u8 RF_SYN_logen_BUF3;
+ u8 RF_SYN_logen_BUF4;
+ u8 RF_RX0_lnaa_tune;
+ u8 RF_RX0_lnag_tune;
+ u8 RF_TX0_intpaa_boost_tune;
+ u8 RF_TX0_intpag_boost_tune;
+ u8 RF_TX0_pada_boost_tune;
+ u8 RF_TX0_padg_boost_tune;
+ u8 RF_TX0_pgaa_boost_tune;
+ u8 RF_TX0_pgag_boost_tune;
+ u8 RF_TX0_mixa_boost_tune;
+ u8 RF_TX0_mixg_boost_tune;
+ u8 RF_RX1_lnaa_tune;
+ u8 RF_RX1_lnag_tune;
+ u8 RF_TX1_intpaa_boost_tune;
+ u8 RF_TX1_intpag_boost_tune;
+ u8 RF_TX1_pada_boost_tune;
+ u8 RF_TX1_padg_boost_tune;
+ u8 RF_TX1_pgaa_boost_tune;
+ u8 RF_TX1_pgag_boost_tune;
+ u8 RF_TX1_mixa_boost_tune;
+ u8 RF_TX1_mixg_boost_tune;
+ u16 PHY_BW1a;
+ u16 PHY_BW2;
+ u16 PHY_BW3;
+ u16 PHY_BW4;
+ u16 PHY_BW5;
+ u16 PHY_BW6;
+};
+
+struct chan_info_nphy_radio2057 {
+ u16 chan;
+ u16 freq;
+ u8 RF_vcocal_countval0;
+ u8 RF_vcocal_countval1;
+ u8 RF_rfpll_refmaster_sparextalsize;
+ u8 RF_rfpll_loopfilter_r1;
+ u8 RF_rfpll_loopfilter_c2;
+ u8 RF_rfpll_loopfilter_c1;
+ u8 RF_cp_kpd_idac;
+ u8 RF_rfpll_mmd0;
+ u8 RF_rfpll_mmd1;
+ u8 RF_vcobuf_tune;
+ u8 RF_logen_mx2g_tune;
+ u8 RF_logen_mx5g_tune;
+ u8 RF_logen_indbuf2g_tune;
+ u8 RF_logen_indbuf5g_tune;
+ u8 RF_txmix2g_tune_boost_pu_core0;
+ u8 RF_pad2g_tune_pus_core0;
+ u8 RF_pga_boost_tune_core0;
+ u8 RF_txmix5g_boost_tune_core0;
+ u8 RF_pad5g_tune_misc_pus_core0;
+ u8 RF_lna2g_tune_core0;
+ u8 RF_lna5g_tune_core0;
+ u8 RF_txmix2g_tune_boost_pu_core1;
+ u8 RF_pad2g_tune_pus_core1;
+ u8 RF_pga_boost_tune_core1;
+ u8 RF_txmix5g_boost_tune_core1;
+ u8 RF_pad5g_tune_misc_pus_core1;
+ u8 RF_lna2g_tune_core1;
+ u8 RF_lna5g_tune_core1;
+ u16 PHY_BW1a;
+ u16 PHY_BW2;
+ u16 PHY_BW3;
+ u16 PHY_BW4;
+ u16 PHY_BW5;
+ u16 PHY_BW6;
+};
+
+struct chan_info_nphy_radio2057_rev5 {
+ u16 chan;
+ u16 freq;
+ u8 RF_vcocal_countval0;
+ u8 RF_vcocal_countval1;
+ u8 RF_rfpll_refmaster_sparextalsize;
+ u8 RF_rfpll_loopfilter_r1;
+ u8 RF_rfpll_loopfilter_c2;
+ u8 RF_rfpll_loopfilter_c1;
+ u8 RF_cp_kpd_idac;
+ u8 RF_rfpll_mmd0;
+ u8 RF_rfpll_mmd1;
+ u8 RF_vcobuf_tune;
+ u8 RF_logen_mx2g_tune;
+ u8 RF_logen_indbuf2g_tune;
+ u8 RF_txmix2g_tune_boost_pu_core0;
+ u8 RF_pad2g_tune_pus_core0;
+ u8 RF_lna2g_tune_core0;
+ u8 RF_txmix2g_tune_boost_pu_core1;
+ u8 RF_pad2g_tune_pus_core1;
+ u8 RF_lna2g_tune_core1;
+ u16 PHY_BW1a;
+ u16 PHY_BW2;
+ u16 PHY_BW3;
+ u16 PHY_BW4;
+ u16 PHY_BW5;
+ u16 PHY_BW6;
+};
+
+struct nphy_sfo_cfg {
+ u16 PHY_BW1a;
+ u16 PHY_BW2;
+ u16 PHY_BW3;
+ u16 PHY_BW4;
+ u16 PHY_BW5;
+ u16 PHY_BW6;
+};
+
+static const struct chan_info_nphy_2055 chan_info_nphy_2055[] = {
+ {
+ 184, 4920, 3280, 0x71, 0x01, 0xEC, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F,
+ 0x0F, 0x8F, 0x7B4, 0x7B0, 0x7AC, 0x214, 0x215, 0x216},
+ {
+ 186, 4930, 3287, 0x71, 0x01, 0xED, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F,
+ 0x0F, 0x8F, 0x7B8, 0x7B4, 0x7B0, 0x213, 0x214, 0x215},
+ {
+ 188, 4940, 3293, 0x71, 0x01, 0xEE, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F,
+ 0x0F, 0x8F, 0x7BC, 0x7B8, 0x7B4, 0x212, 0x213, 0x214},
+ {
+ 190, 4950, 3300, 0x71, 0x01, 0xEF, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F,
+ 0x0F, 0x8F, 0x7C0, 0x7BC, 0x7B8, 0x211, 0x212, 0x213},
+ {
+ 192, 4960, 3307, 0x71, 0x01, 0xF0, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F,
+ 0x0F, 0x8F, 0x7C4, 0x7C0, 0x7BC, 0x20F, 0x211, 0x212},
+ {
+ 194, 4970, 3313, 0x71, 0x01, 0xF1, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F,
+ 0x0F, 0x8F, 0x7C8, 0x7C4, 0x7C0, 0x20E, 0x20F, 0x211},
+ {
+ 196, 4980, 3320, 0x71, 0x01, 0xF2, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F,
+ 0x0F, 0x8F, 0x7CC, 0x7C8, 0x7C4, 0x20D, 0x20E, 0x20F},
+ {
+ 198, 4990, 3327, 0x71, 0x01, 0xF3, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F,
+ 0x0F, 0x8F, 0x7D0, 0x7CC, 0x7C8, 0x20C, 0x20D, 0x20E},
+ {
+ 200, 5000, 3333, 0x71, 0x01, 0xF4, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F,
+ 0x0F, 0x8F, 0x7D4, 0x7D0, 0x7CC, 0x20B, 0x20C, 0x20D},
+ {
+ 202, 5010, 3340, 0x71, 0x01, 0xF5, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F,
+ 0x0F, 0x8F, 0x7D8, 0x7D4, 0x7D0, 0x20A, 0x20B, 0x20C},
+ {
+ 204, 5020, 3347, 0x71, 0x01, 0xF6, 0x0E, 0xF7, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F,
+ 0x0F, 0x8F, 0x7DC, 0x7D8, 0x7D4, 0x209, 0x20A, 0x20B},
+ {
+ 206, 5030, 3353, 0x71, 0x01, 0xF7, 0x0E, 0xF7, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F,
+ 0x0F, 0x8F, 0x7E0, 0x7DC, 0x7D8, 0x208, 0x209, 0x20A},
+ {
+ 208, 5040, 3360, 0x71, 0x01, 0xF8, 0x0D, 0xEF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F,
+ 0x0F, 0x8F, 0x7E4, 0x7E0, 0x7DC, 0x207, 0x208, 0x209},
+ {
+ 210, 5050, 3367, 0x71, 0x01, 0xF9, 0x0D, 0xEF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F,
+ 0x0F, 0x8F, 0x7E8, 0x7E4, 0x7E0, 0x206, 0x207, 0x208},
+ {
+ 212, 5060, 3373, 0x71, 0x01, 0xFA, 0x0D, 0xE6, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F, 0x8E, 0xFF, 0x00, 0x0E,
+ 0x0F, 0x8E, 0x7EC, 0x7E8, 0x7E4, 0x205, 0x206, 0x207},
+ {
+ 214, 5070, 3380, 0x71, 0x01, 0xFB, 0x0D, 0xE6, 0x01, 0x04, 0x0A,
+ 0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F, 0x8E, 0xFF, 0x00, 0x0E,
+ 0x0F, 0x8E, 0x7F0, 0x7EC, 0x7E8, 0x204, 0x205, 0x206},
+ {
+ 216, 5080, 3387, 0x71, 0x01, 0xFC, 0x0D, 0xDE, 0x01, 0x04, 0x0A,
+ 0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F, 0x8D, 0xEE, 0x00, 0x0E,
+ 0x0F, 0x8D, 0x7F4, 0x7F0, 0x7EC, 0x203, 0x204, 0x205},
+ {
+ 218, 5090, 3393, 0x71, 0x01, 0xFD, 0x0D, 0xDE, 0x01, 0x04, 0x0A,
+ 0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F, 0x8D, 0xEE, 0x00, 0x0E,
+ 0x0F, 0x8D, 0x7F8, 0x7F4, 0x7F0, 0x202, 0x203, 0x204},
+ {
+ 220, 5100, 3400, 0x71, 0x01, 0xFE, 0x0C, 0xD6, 0x01, 0x04, 0x0A,
+ 0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F, 0x8D, 0xEE, 0x00, 0x0D,
+ 0x0F, 0x8D, 0x7FC, 0x7F8, 0x7F4, 0x201, 0x202, 0x203},
+ {
+ 222, 5110, 3407, 0x71, 0x01, 0xFF, 0x0C, 0xD6, 0x01, 0x04, 0x0A,
+ 0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F, 0x8D, 0xEE, 0x00, 0x0D,
+ 0x0F, 0x8D, 0x800, 0x7FC, 0x7F8, 0x200, 0x201, 0x202},
+ {
+ 224, 5120, 3413, 0x71, 0x02, 0x00, 0x0C, 0xCE, 0x01, 0x04, 0x0A,
+ 0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F, 0x8C, 0xDD, 0x00, 0x0D,
+ 0x0F, 0x8C, 0x804, 0x800, 0x7FC, 0x1FF, 0x200, 0x201},
+ {
+ 226, 5130, 3420, 0x71, 0x02, 0x01, 0x0C, 0xCE, 0x01, 0x04, 0x0A,
+ 0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F, 0x8C, 0xDD, 0x00, 0x0D,
+ 0x0F, 0x8C, 0x808, 0x804, 0x800, 0x1FE, 0x1FF, 0x200},
+ {
+ 228, 5140, 3427, 0x71, 0x02, 0x02, 0x0C, 0xC6, 0x01, 0x04, 0x0A,
+ 0x00, 0x8D, 0x99, 0x99, 0xDD, 0x00, 0x0C, 0x0E, 0x8B, 0xDD, 0x00, 0x0C,
+ 0x0E, 0x8B, 0x80C, 0x808, 0x804, 0x1FD, 0x1FE, 0x1FF},
+ {
+ 32, 5160, 3440, 0x71, 0x02, 0x04, 0x0B, 0xBE, 0x01, 0x04, 0x0A,
+ 0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D, 0x8A, 0xCC, 0x00, 0x0B,
+ 0x0D, 0x8A, 0x814, 0x810, 0x80C, 0x1FB, 0x1FC, 0x1FD},
+ {
+ 34, 5170, 3447, 0x71, 0x02, 0x05, 0x0B, 0xBE, 0x01, 0x04, 0x0A,
+ 0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D, 0x8A, 0xCC, 0x00, 0x0B,
+ 0x0D, 0x8A, 0x818, 0x814, 0x810, 0x1FA, 0x1FB, 0x1FC},
+ {
+ 36, 5180, 3453, 0x71, 0x02, 0x06, 0x0B, 0xB6, 0x01, 0x04, 0x0A,
+ 0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C, 0x89, 0xCC, 0x00, 0x0B,
+ 0x0C, 0x89, 0x81C, 0x818, 0x814, 0x1F9, 0x1FA, 0x1FB},
+ {
+ 38, 5190, 3460, 0x71, 0x02, 0x07, 0x0B, 0xB6, 0x01, 0x04, 0x0A,
+ 0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C, 0x89, 0xCC, 0x00, 0x0B,
+ 0x0C, 0x89, 0x820, 0x81C, 0x818, 0x1F8, 0x1F9, 0x1FA},
+ {
+ 40, 5200, 3467, 0x71, 0x02, 0x08, 0x0B, 0xAF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B, 0x89, 0xBB, 0x00, 0x0A,
+ 0x0B, 0x89, 0x824, 0x820, 0x81C, 0x1F7, 0x1F8, 0x1F9},
+ {
+ 42, 5210, 3473, 0x71, 0x02, 0x09, 0x0B, 0xAF, 0x01, 0x04, 0x0A,
+ 0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B, 0x89, 0xBB, 0x00, 0x0A,
+ 0x0B, 0x89, 0x828, 0x824, 0x820, 0x1F6, 0x1F7, 0x1F8},
+ {
+ 44, 5220, 3480, 0x71, 0x02, 0x0A, 0x0A, 0xA7, 0x01, 0x04, 0x0A,
+ 0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A, 0x88, 0xBB, 0x00, 0x09,
+ 0x0A, 0x88, 0x82C, 0x828, 0x824, 0x1F5, 0x1F6, 0x1F7},
+ {
+ 46, 5230, 3487, 0x71, 0x02, 0x0B, 0x0A, 0xA7, 0x01, 0x04, 0x0A,
+ 0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A, 0x88, 0xBB, 0x00, 0x09,
+ 0x0A, 0x88, 0x830, 0x82C, 0x828, 0x1F4, 0x1F5, 0x1F6},
+ {
+ 48, 5240, 3493, 0x71, 0x02, 0x0C, 0x0A, 0xA0, 0x01, 0x04, 0x0A,
+ 0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A, 0x87, 0xAA, 0x00, 0x09,
+ 0x0A, 0x87, 0x834, 0x830, 0x82C, 0x1F3, 0x1F4, 0x1F5},
+ {
+ 50, 5250, 3500, 0x71, 0x02, 0x0D, 0x0A, 0xA0, 0x01, 0x04, 0x0A,
+ 0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A, 0x87, 0xAA, 0x00, 0x09,
+ 0x0A, 0x87, 0x838, 0x834, 0x830, 0x1F2, 0x1F3, 0x1F4},
+ {
+ 52, 5260, 3507, 0x71, 0x02, 0x0E, 0x0A, 0x98, 0x01, 0x04, 0x0A,
+ 0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09, 0x87, 0xAA, 0x00, 0x08,
+ 0x09, 0x87, 0x83C, 0x838, 0x834, 0x1F1, 0x1F2, 0x1F3},
+ {
+ 54, 5270, 3513, 0x71, 0x02, 0x0F, 0x0A, 0x98, 0x01, 0x04, 0x0A,
+ 0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09, 0x87, 0xAA, 0x00, 0x08,
+ 0x09, 0x87, 0x840, 0x83C, 0x838, 0x1F0, 0x1F1, 0x1F2},
+ {
+ 56, 5280, 3520, 0x71, 0x02, 0x10, 0x09, 0x91, 0x01, 0x04, 0x0A,
+ 0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08, 0x86, 0x99, 0x00, 0x08,
+ 0x08, 0x86, 0x844, 0x840, 0x83C, 0x1F0, 0x1F0, 0x1F1},
+ {
+ 58, 5290, 3527, 0x71, 0x02, 0x11, 0x09, 0x91, 0x01, 0x04, 0x0A,
+ 0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08, 0x86, 0x99, 0x00, 0x08,
+ 0x08, 0x86, 0x848, 0x844, 0x840, 0x1EF, 0x1F0, 0x1F0},
+ {
+ 60, 5300, 3533, 0x71, 0x02, 0x12, 0x09, 0x8A, 0x01, 0x04, 0x0A,
+ 0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07, 0x85, 0x99, 0x00, 0x08,
+ 0x07, 0x85, 0x84C, 0x848, 0x844, 0x1EE, 0x1EF, 0x1F0},
+ {
+ 62, 5310, 3540, 0x71, 0x02, 0x13, 0x09, 0x8A, 0x01, 0x04, 0x0A,
+ 0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07, 0x85, 0x99, 0x00, 0x08,
+ 0x07, 0x85, 0x850, 0x84C, 0x848, 0x1ED, 0x1EE, 0x1EF},
+ {
+ 64, 5320, 3547, 0x71, 0x02, 0x14, 0x09, 0x83, 0x01, 0x04, 0x0A,
+ 0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07, 0x84, 0x88, 0x00, 0x07,
+ 0x07, 0x84, 0x854, 0x850, 0x84C, 0x1EC, 0x1ED, 0x1EE},
+ {
+ 66, 5330, 3553, 0x71, 0x02, 0x15, 0x09, 0x83, 0x01, 0x04, 0x0A,
+ 0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07, 0x84, 0x88, 0x00, 0x07,
+ 0x07, 0x84, 0x858, 0x854, 0x850, 0x1EB, 0x1EC, 0x1ED},
+ {
+ 68, 5340, 3560, 0x71, 0x02, 0x16, 0x08, 0x7C, 0x01, 0x04, 0x0A,
+ 0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06, 0x84, 0x88, 0x00, 0x07,
+ 0x06, 0x84, 0x85C, 0x858, 0x854, 0x1EA, 0x1EB, 0x1EC},
+ {
+ 70, 5350, 3567, 0x71, 0x02, 0x17, 0x08, 0x7C, 0x01, 0x04, 0x0A,
+ 0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06, 0x84, 0x88, 0x00, 0x07,
+ 0x06, 0x84, 0x860, 0x85C, 0x858, 0x1E9, 0x1EA, 0x1EB},
+ {
+ 72, 5360, 3573, 0x71, 0x02, 0x18, 0x08, 0x75, 0x01, 0x04, 0x0A,
+ 0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05, 0x83, 0x77, 0x00, 0x06,
+ 0x05, 0x83, 0x864, 0x860, 0x85C, 0x1E8, 0x1E9, 0x1EA},
+ {
+ 74, 5370, 3580, 0x71, 0x02, 0x19, 0x08, 0x75, 0x01, 0x04, 0x0A,
+ 0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05, 0x83, 0x77, 0x00, 0x06,
+ 0x05, 0x83, 0x868, 0x864, 0x860, 0x1E7, 0x1E8, 0x1E9},
+ {
+ 76, 5380, 3587, 0x71, 0x02, 0x1A, 0x08, 0x6E, 0x01, 0x04, 0x0A,
+ 0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04, 0x82, 0x77, 0x00, 0x06,
+ 0x04, 0x82, 0x86C, 0x868, 0x864, 0x1E6, 0x1E7, 0x1E8},
+ {
+ 78, 5390, 3593, 0x71, 0x02, 0x1B, 0x08, 0x6E, 0x01, 0x04, 0x0A,
+ 0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04, 0x82, 0x77, 0x00, 0x06,
+ 0x04, 0x82, 0x870, 0x86C, 0x868, 0x1E5, 0x1E6, 0x1E7},
+ {
+ 80, 5400, 3600, 0x71, 0x02, 0x1C, 0x07, 0x67, 0x01, 0x04, 0x0A,
+ 0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04, 0x81, 0x66, 0x00, 0x05,
+ 0x04, 0x81, 0x874, 0x870, 0x86C, 0x1E5, 0x1E5, 0x1E6},
+ {
+ 82, 5410, 3607, 0x71, 0x02, 0x1D, 0x07, 0x67, 0x01, 0x04, 0x0A,
+ 0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04, 0x81, 0x66, 0x00, 0x05,
+ 0x04, 0x81, 0x878, 0x874, 0x870, 0x1E4, 0x1E5, 0x1E5},
+ {
+ 84, 5420, 3613, 0x71, 0x02, 0x1E, 0x07, 0x61, 0x01, 0x04, 0x0A,
+ 0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03, 0x80, 0x66, 0x00, 0x05,
+ 0x03, 0x80, 0x87C, 0x878, 0x874, 0x1E3, 0x1E4, 0x1E5},
+ {
+ 86, 5430, 3620, 0x71, 0x02, 0x1F, 0x07, 0x61, 0x01, 0x04, 0x0A,
+ 0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03, 0x80, 0x66, 0x00, 0x05,
+ 0x03, 0x80, 0x880, 0x87C, 0x878, 0x1E2, 0x1E3, 0x1E4},
+ {
+ 88, 5440, 3627, 0x71, 0x02, 0x20, 0x07, 0x5A, 0x01, 0x04, 0x0A,
+ 0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02, 0x80, 0x55, 0x00, 0x04,
+ 0x02, 0x80, 0x884, 0x880, 0x87C, 0x1E1, 0x1E2, 0x1E3},
+ {
+ 90, 5450, 3633, 0x71, 0x02, 0x21, 0x07, 0x5A, 0x01, 0x04, 0x0A,
+ 0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02, 0x80, 0x55, 0x00, 0x04,
+ 0x02, 0x80, 0x888, 0x884, 0x880, 0x1E0, 0x1E1, 0x1E2},
+ {
+ 92, 5460, 3640, 0x71, 0x02, 0x22, 0x06, 0x53, 0x01, 0x04, 0x0A,
+ 0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01, 0x80, 0x55, 0x00, 0x04,
+ 0x01, 0x80, 0x88C, 0x888, 0x884, 0x1DF, 0x1E0, 0x1E1},
+ {
+ 94, 5470, 3647, 0x71, 0x02, 0x23, 0x06, 0x53, 0x01, 0x04, 0x0A,
+ 0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01, 0x80, 0x55, 0x00, 0x04,
+ 0x01, 0x80, 0x890, 0x88C, 0x888, 0x1DE, 0x1DF, 0x1E0},
+ {
+ 96, 5480, 3653, 0x71, 0x02, 0x24, 0x06, 0x4D, 0x01, 0x04, 0x0A,
+ 0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00, 0x80, 0x44, 0x00, 0x03,
+ 0x00, 0x80, 0x894, 0x890, 0x88C, 0x1DD, 0x1DE, 0x1DF},
+ {
+ 98, 5490, 3660, 0x71, 0x02, 0x25, 0x06, 0x4D, 0x01, 0x04, 0x0A,
+ 0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00, 0x80, 0x44, 0x00, 0x03,
+ 0x00, 0x80, 0x898, 0x894, 0x890, 0x1DD, 0x1DD, 0x1DE},
+ {
+ 100, 5500, 3667, 0x71, 0x02, 0x26, 0x06, 0x47, 0x01, 0x04, 0x0A,
+ 0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00, 0x80, 0x44, 0x00, 0x03,
+ 0x00, 0x80, 0x89C, 0x898, 0x894, 0x1DC, 0x1DD, 0x1DD},
+ {
+ 102, 5510, 3673, 0x71, 0x02, 0x27, 0x06, 0x47, 0x01, 0x04, 0x0A,
+ 0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00, 0x80, 0x44, 0x00, 0x03,
+ 0x00, 0x80, 0x8A0, 0x89C, 0x898, 0x1DB, 0x1DC, 0x1DD},
+ {
+ 104, 5520, 3680, 0x71, 0x02, 0x28, 0x05, 0x40, 0x01, 0x04, 0x0A,
+ 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, 0x80, 0x33, 0x00, 0x02,
+ 0x00, 0x80, 0x8A4, 0x8A0, 0x89C, 0x1DA, 0x1DB, 0x1DC},
+ {
+ 106, 5530, 3687, 0x71, 0x02, 0x29, 0x05, 0x40, 0x01, 0x04, 0x0A,
+ 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, 0x80, 0x33, 0x00, 0x02,
+ 0x00, 0x80, 0x8A8, 0x8A4, 0x8A0, 0x1D9, 0x1DA, 0x1DB},
+ {
+ 108, 5540, 3693, 0x71, 0x02, 0x2A, 0x05, 0x3A, 0x01, 0x04, 0x0A,
+ 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, 0x80, 0x33, 0x00, 0x02,
+ 0x00, 0x80, 0x8AC, 0x8A8, 0x8A4, 0x1D8, 0x1D9, 0x1DA},
+ {
+ 110, 5550, 3700, 0x71, 0x02, 0x2B, 0x05, 0x3A, 0x01, 0x04, 0x0A,
+ 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, 0x80, 0x33, 0x00, 0x02,
+ 0x00, 0x80, 0x8B0, 0x8AC, 0x8A8, 0x1D7, 0x1D8, 0x1D9},
+ {
+ 112, 5560, 3707, 0x71, 0x02, 0x2C, 0x05, 0x34, 0x01, 0x04, 0x0A,
+ 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, 0x80, 0x22, 0x00, 0x01,
+ 0x00, 0x80, 0x8B4, 0x8B0, 0x8AC, 0x1D7, 0x1D7, 0x1D8},
+ {
+ 114, 5570, 3713, 0x71, 0x02, 0x2D, 0x05, 0x34, 0x01, 0x04, 0x0A,
+ 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, 0x80, 0x22, 0x00, 0x01,
+ 0x00, 0x80, 0x8B8, 0x8B4, 0x8B0, 0x1D6, 0x1D7, 0x1D7},
+ {
+ 116, 5580, 3720, 0x71, 0x02, 0x2E, 0x04, 0x2E, 0x01, 0x04, 0x0A,
+ 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, 0x80, 0x22, 0x00, 0x01,
+ 0x00, 0x80, 0x8BC, 0x8B8, 0x8B4, 0x1D5, 0x1D6, 0x1D7},
+ {
+ 118, 5590, 3727, 0x71, 0x02, 0x2F, 0x04, 0x2E, 0x01, 0x04, 0x0A,
+ 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, 0x80, 0x22, 0x00, 0x01,
+ 0x00, 0x80, 0x8C0, 0x8BC, 0x8B8, 0x1D4, 0x1D5, 0x1D6},
+ {
+ 120, 5600, 3733, 0x71, 0x02, 0x30, 0x04, 0x28, 0x01, 0x04, 0x0A,
+ 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00, 0x80, 0x11, 0x00, 0x01,
+ 0x00, 0x80, 0x8C4, 0x8C0, 0x8BC, 0x1D3, 0x1D4, 0x1D5},
+ {
+ 122, 5610, 3740, 0x71, 0x02, 0x31, 0x04, 0x28, 0x01, 0x04, 0x0A,
+ 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00, 0x80, 0x11, 0x00, 0x01,
+ 0x00, 0x80, 0x8C8, 0x8C4, 0x8C0, 0x1D2, 0x1D3, 0x1D4},
+ {
+ 124, 5620, 3747, 0x71, 0x02, 0x32, 0x04, 0x21, 0x01, 0x04, 0x0A,
+ 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00,
+ 0x00, 0x80, 0x8CC, 0x8C8, 0x8C4, 0x1D2, 0x1D2, 0x1D3},
+ {
+ 126, 5630, 3753, 0x71, 0x02, 0x33, 0x04, 0x21, 0x01, 0x04, 0x0A,
+ 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00,
+ 0x00, 0x80, 0x8D0, 0x8CC, 0x8C8, 0x1D1, 0x1D2, 0x1D2},
+ {
+ 128, 5640, 3760, 0x71, 0x02, 0x34, 0x03, 0x1C, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x8D4, 0x8D0, 0x8CC, 0x1D0, 0x1D1, 0x1D2},
+ {
+ 130, 5650, 3767, 0x71, 0x02, 0x35, 0x03, 0x1C, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x8D8, 0x8D4, 0x8D0, 0x1CF, 0x1D0, 0x1D1},
+ {
+ 132, 5660, 3773, 0x71, 0x02, 0x36, 0x03, 0x16, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x8DC, 0x8D8, 0x8D4, 0x1CE, 0x1CF, 0x1D0},
+ {
+ 134, 5670, 3780, 0x71, 0x02, 0x37, 0x03, 0x16, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x8E0, 0x8DC, 0x8D8, 0x1CE, 0x1CE, 0x1CF},
+ {
+ 136, 5680, 3787, 0x71, 0x02, 0x38, 0x03, 0x10, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x8E4, 0x8E0, 0x8DC, 0x1CD, 0x1CE, 0x1CE},
+ {
+ 138, 5690, 3793, 0x71, 0x02, 0x39, 0x03, 0x10, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x8E8, 0x8E4, 0x8E0, 0x1CC, 0x1CD, 0x1CE},
+ {
+ 140, 5700, 3800, 0x71, 0x02, 0x3A, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x8EC, 0x8E8, 0x8E4, 0x1CB, 0x1CC, 0x1CD},
+ {
+ 142, 5710, 3807, 0x71, 0x02, 0x3B, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x8F0, 0x8EC, 0x8E8, 0x1CA, 0x1CB, 0x1CC},
+ {
+ 144, 5720, 3813, 0x71, 0x02, 0x3C, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x8F4, 0x8F0, 0x8EC, 0x1C9, 0x1CA, 0x1CB},
+ {
+ 145, 5725, 3817, 0x72, 0x04, 0x79, 0x02, 0x03, 0x01, 0x03, 0x14,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x8F6, 0x8F2, 0x8EE, 0x1C9, 0x1CA, 0x1CB},
+ {
+ 146, 5730, 3820, 0x71, 0x02, 0x3D, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x8F8, 0x8F4, 0x8F0, 0x1C9, 0x1C9, 0x1CA},
+ {
+ 147, 5735, 3823, 0x72, 0x04, 0x7B, 0x02, 0x03, 0x01, 0x03, 0x14,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x8FA, 0x8F6, 0x8F2, 0x1C8, 0x1C9, 0x1CA},
+ {
+ 148, 5740, 3827, 0x71, 0x02, 0x3E, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x8FC, 0x8F8, 0x8F4, 0x1C8, 0x1C9, 0x1C9},
+ {
+ 149, 5745, 3830, 0x72, 0x04, 0x7D, 0x02, 0xFE, 0x00, 0x03, 0x14,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x8FE, 0x8FA, 0x8F6, 0x1C8, 0x1C8, 0x1C9},
+ {
+ 150, 5750, 3833, 0x71, 0x02, 0x3F, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x900, 0x8FC, 0x8F8, 0x1C7, 0x1C8, 0x1C9},
+ {
+ 151, 5755, 3837, 0x72, 0x04, 0x7F, 0x02, 0xFE, 0x00, 0x03, 0x14,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x902, 0x8FE, 0x8FA, 0x1C7, 0x1C8, 0x1C8},
+ {
+ 152, 5760, 3840, 0x71, 0x02, 0x40, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x904, 0x900, 0x8FC, 0x1C6, 0x1C7, 0x1C8},
+ {
+ 153, 5765, 3843, 0x72, 0x04, 0x81, 0x02, 0xF8, 0x00, 0x03, 0x14,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x906, 0x902, 0x8FE, 0x1C6, 0x1C7, 0x1C8},
+ {
+ 154, 5770, 3847, 0x71, 0x02, 0x41, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x908, 0x904, 0x900, 0x1C6, 0x1C6, 0x1C7},
+ {
+ 155, 5775, 3850, 0x72, 0x04, 0x83, 0x02, 0xF8, 0x00, 0x03, 0x14,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x90A, 0x906, 0x902, 0x1C5, 0x1C6, 0x1C7},
+ {
+ 156, 5780, 3853, 0x71, 0x02, 0x42, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x90C, 0x908, 0x904, 0x1C5, 0x1C6, 0x1C6},
+ {
+ 157, 5785, 3857, 0x72, 0x04, 0x85, 0x02, 0xF2, 0x00, 0x03, 0x14,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x90E, 0x90A, 0x906, 0x1C4, 0x1C5, 0x1C6},
+ {
+ 158, 5790, 3860, 0x71, 0x02, 0x43, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x910, 0x90C, 0x908, 0x1C4, 0x1C5, 0x1C6},
+ {
+ 159, 5795, 3863, 0x72, 0x04, 0x87, 0x02, 0xF2, 0x00, 0x03, 0x14,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x912, 0x90E, 0x90A, 0x1C4, 0x1C4, 0x1C5},
+ {
+ 160, 5800, 3867, 0x71, 0x02, 0x44, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x914, 0x910, 0x90C, 0x1C3, 0x1C4, 0x1C5},
+ {
+ 161, 5805, 3870, 0x72, 0x04, 0x89, 0x01, 0xED, 0x00, 0x03, 0x14,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x916, 0x912, 0x90E, 0x1C3, 0x1C4, 0x1C4},
+ {
+ 162, 5810, 3873, 0x71, 0x02, 0x45, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x918, 0x914, 0x910, 0x1C2, 0x1C3, 0x1C4},
+ {
+ 163, 5815, 3877, 0x72, 0x04, 0x8B, 0x01, 0xED, 0x00, 0x03, 0x14,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x91A, 0x916, 0x912, 0x1C2, 0x1C3, 0x1C4},
+ {
+ 164, 5820, 3880, 0x71, 0x02, 0x46, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x91C, 0x918, 0x914, 0x1C2, 0x1C2, 0x1C3},
+ {
+ 165, 5825, 3883, 0x72, 0x04, 0x8D, 0x01, 0xED, 0x00, 0x03, 0x14,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x91E, 0x91A, 0x916, 0x1C1, 0x1C2, 0x1C3},
+ {
+ 166, 5830, 3887, 0x71, 0x02, 0x47, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x920, 0x91C, 0x918, 0x1C1, 0x1C2, 0x1C2},
+ {
+ 168, 5840, 3893, 0x71, 0x02, 0x48, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x924, 0x920, 0x91C, 0x1C0, 0x1C1, 0x1C2},
+ {
+ 170, 5850, 3900, 0x71, 0x02, 0x49, 0x01, 0xE0, 0x00, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x928, 0x924, 0x920, 0x1BF, 0x1C0, 0x1C1},
+ {
+ 172, 5860, 3907, 0x71, 0x02, 0x4A, 0x01, 0xDE, 0x00, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x92C, 0x928, 0x924, 0x1BF, 0x1BF, 0x1C0},
+ {
+ 174, 5870, 3913, 0x71, 0x02, 0x4B, 0x00, 0xDB, 0x00, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x930, 0x92C, 0x928, 0x1BE, 0x1BF, 0x1BF},
+ {
+ 176, 5880, 3920, 0x71, 0x02, 0x4C, 0x00, 0xD8, 0x00, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x934, 0x930, 0x92C, 0x1BD, 0x1BE, 0x1BF},
+ {
+ 178, 5890, 3927, 0x71, 0x02, 0x4D, 0x00, 0xD6, 0x00, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x938, 0x934, 0x930, 0x1BC, 0x1BD, 0x1BE},
+ {
+ 180, 5900, 3933, 0x71, 0x02, 0x4E, 0x00, 0xD3, 0x00, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x93C, 0x938, 0x934, 0x1BC, 0x1BC, 0x1BD},
+ {
+ 182, 5910, 3940, 0x71, 0x02, 0x4F, 0x00, 0xD6, 0x00, 0x04, 0x0A,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x940, 0x93C, 0x938, 0x1BB, 0x1BC, 0x1BC},
+ {
+ 1, 2412, 3216, 0x73, 0x09, 0x6C, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0D, 0x0C, 0x80, 0xFF, 0x88, 0x0D,
+ 0x0C, 0x80, 0x3C9, 0x3C5, 0x3C1, 0x43A, 0x43F, 0x443},
+ {
+ 2, 2417, 3223, 0x73, 0x09, 0x71, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0B, 0x80, 0xFF, 0x88, 0x0C,
+ 0x0B, 0x80, 0x3CB, 0x3C7, 0x3C3, 0x438, 0x43D, 0x441},
+ {
+ 3, 2422, 3229, 0x73, 0x09, 0x76, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A, 0x80, 0xFF, 0x88, 0x0C,
+ 0x0A, 0x80, 0x3CD, 0x3C9, 0x3C5, 0x436, 0x43A, 0x43F},
+ {
+ 4, 2427, 3236, 0x73, 0x09, 0x7B, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A, 0x80, 0xFF, 0x88, 0x0C,
+ 0x0A, 0x80, 0x3CF, 0x3CB, 0x3C7, 0x434, 0x438, 0x43D},
+ {
+ 5, 2432, 3243, 0x73, 0x09, 0x80, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x09, 0x80, 0xFF, 0x88, 0x0C,
+ 0x09, 0x80, 0x3D1, 0x3CD, 0x3C9, 0x431, 0x436, 0x43A},
+ {
+ 6, 2437, 3249, 0x73, 0x09, 0x85, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0B, 0x08, 0x80, 0xFF, 0x88, 0x0B,
+ 0x08, 0x80, 0x3D3, 0x3CF, 0x3CB, 0x42F, 0x434, 0x438},
+ {
+ 7, 2442, 3256, 0x73, 0x09, 0x8A, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x07, 0x80, 0xFF, 0x88, 0x0A,
+ 0x07, 0x80, 0x3D5, 0x3D1, 0x3CD, 0x42D, 0x431, 0x436},
+ {
+ 8, 2447, 3263, 0x73, 0x09, 0x8F, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x06, 0x80, 0xFF, 0x88, 0x0A,
+ 0x06, 0x80, 0x3D7, 0x3D3, 0x3CF, 0x42B, 0x42F, 0x434},
+ {
+ 9, 2452, 3269, 0x73, 0x09, 0x94, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x09, 0x06, 0x80, 0xFF, 0x88, 0x09,
+ 0x06, 0x80, 0x3D9, 0x3D5, 0x3D1, 0x429, 0x42D, 0x431},
+ {
+ 10, 2457, 3276, 0x73, 0x09, 0x99, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x05, 0x80, 0xFF, 0x88, 0x08,
+ 0x05, 0x80, 0x3DB, 0x3D7, 0x3D3, 0x427, 0x42B, 0x42F},
+ {
+ 11, 2462, 3283, 0x73, 0x09, 0x9E, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x04, 0x80, 0xFF, 0x88, 0x08,
+ 0x04, 0x80, 0x3DD, 0x3D9, 0x3D5, 0x424, 0x429, 0x42D},
+ {
+ 12, 2467, 3289, 0x73, 0x09, 0xA3, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x03, 0x80, 0xFF, 0x88, 0x08,
+ 0x03, 0x80, 0x3DF, 0x3DB, 0x3D7, 0x422, 0x427, 0x42B},
+ {
+ 13, 2472, 3296, 0x73, 0x09, 0xA8, 0x0F, 0x00, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x03, 0x80, 0xFF, 0x88, 0x07,
+ 0x03, 0x80, 0x3E1, 0x3DD, 0x3D9, 0x420, 0x424, 0x429},
+ {
+ 14, 2484, 3312, 0x73, 0x09, 0xB4, 0x0F, 0xFF, 0x01, 0x07, 0x15,
+ 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x01, 0x80, 0xFF, 0x88, 0x07,
+ 0x01, 0x80, 0x3E6, 0x3E2, 0x3DE, 0x41B, 0x41F, 0x424}
+};
+
+static const struct chan_info_nphy_radio205x chan_info_nphyrev3_2056[] = {
+ {
+ 184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216},
+ {
+ 186, 4930, 0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215},
+ {
+ 188, 4940, 0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214},
+ {
+ 190, 4950, 0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213},
+ {
+ 192, 4960, 0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212},
+ {
+ 194, 4970, 0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211},
+ {
+ 196, 4980, 0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f},
+ {
+ 198, 4990, 0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e},
+ {
+ 200, 5000, 0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d},
+ {
+ 202, 5010, 0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c},
+ {
+ 204, 5020, 0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b},
+ {
+ 206, 5030, 0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a},
+ {
+ 208, 5040, 0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209},
+ {
+ 210, 5050, 0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208},
+ {
+ 212, 5060, 0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207},
+ {
+ 214, 5070, 0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206},
+ {
+ 216, 5080, 0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205},
+ {
+ 218, 5090, 0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204},
+ {
+ 220, 5100, 0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xff, 0x00, 0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203},
+ {
+ 222, 5110, 0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xfc, 0x00, 0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202},
+ {
+ 224, 5120, 0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xfc, 0x00, 0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201},
+ {
+ 226, 5130, 0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xfc, 0x00, 0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200},
+ {
+ 228, 5140, 0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xfc, 0x00, 0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff},
+ {
+ 32, 5160, 0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xfc, 0x00, 0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd},
+ {
+ 34, 5170, 0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xfc, 0x00, 0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc},
+ {
+ 36, 5180, 0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xef, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xef, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xfc, 0x00, 0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb},
+ {
+ 38, 5190, 0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xef, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xef, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xfc, 0x00, 0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa},
+ {
+ 40, 5200, 0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xef, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xef, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xfc, 0x00, 0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9},
+ {
+ 42, 5210, 0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xdf, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xfc, 0x00, 0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8},
+ {
+ 44, 5220, 0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xdf, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xfc, 0x00, 0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7},
+ {
+ 46, 5230, 0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xdf, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xfc, 0x00, 0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6},
+ {
+ 48, 5240, 0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xfc, 0x00, 0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5},
+ {
+ 50, 5250, 0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xfc, 0x00, 0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4},
+ {
+ 52, 5260, 0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xfc, 0x00, 0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3},
+ {
+ 54, 5270, 0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xfc, 0x00, 0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2},
+ {
+ 56, 5280, 0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xbf, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xfc, 0x00, 0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1},
+ {
+ 58, 5290, 0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xbf, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xfc, 0x00, 0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0},
+ {
+ 60, 5300, 0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xbf, 0x00, 0x05, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xfc, 0x00, 0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0},
+ {
+ 62, 5310, 0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xbf, 0x00, 0x05, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xfa, 0x00, 0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef},
+ {
+ 64, 5320, 0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xbf, 0x00, 0x05, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xfa, 0x00, 0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee},
+ {
+ 66, 5330, 0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xaf, 0x00, 0x05, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xfa, 0x00, 0xaf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xfa, 0x00, 0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed},
+ {
+ 68, 5340, 0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xaf, 0x00, 0x05, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xfa, 0x00, 0xaf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xfa, 0x00, 0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec},
+ {
+ 70, 5350, 0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x05, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xfa, 0x00, 0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb},
+ {
+ 72, 5360, 0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x05, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xfa, 0x00, 0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea},
+ {
+ 74, 5370, 0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x05, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xfa, 0x00, 0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9},
+ {
+ 76, 5380, 0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x05, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xfa, 0x00, 0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8},
+ {
+ 78, 5390, 0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x8f, 0x00, 0x05, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xfa, 0x00, 0x8f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xfa, 0x00, 0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7},
+ {
+ 80, 5400, 0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8f, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x08, 0x00, 0xfa, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08,
+ 0x00, 0xfa, 0x00, 0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6},
+ {
+ 82, 5410, 0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8f, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x08, 0x00, 0xfa, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08,
+ 0x00, 0xfa, 0x00, 0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5},
+ {
+ 84, 5420, 0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8e, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x08, 0x00, 0xfa, 0x00, 0x8e, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08,
+ 0x00, 0xfa, 0x00, 0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5},
+ {
+ 86, 5430, 0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8e, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x08, 0x00, 0xfa, 0x00, 0x8e, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08,
+ 0x00, 0xfa, 0x00, 0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4},
+ {
+ 88, 5440, 0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x7e, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x08, 0x00, 0xfa, 0x00, 0x7e, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08,
+ 0x00, 0xfa, 0x00, 0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3},
+ {
+ 90, 5450, 0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x7d, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x08, 0x00, 0xfa, 0x00, 0x7d, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08,
+ 0x00, 0xfa, 0x00, 0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2},
+ {
+ 92, 5460, 0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x6d, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x08, 0x00, 0xf8, 0x00, 0x6d, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08,
+ 0x00, 0xf8, 0x00, 0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1},
+ {
+ 94, 5470, 0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x6d, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x08, 0x00, 0xf8, 0x00, 0x6d, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08,
+ 0x00, 0xf8, 0x00, 0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0},
+ {
+ 96, 5480, 0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x5d, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x08, 0x00, 0xf8, 0x00, 0x5d, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08,
+ 0x00, 0xf8, 0x00, 0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df},
+ {
+ 98, 5490, 0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x5c, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x08, 0x00, 0xf8, 0x00, 0x5c, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08,
+ 0x00, 0xf8, 0x00, 0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de},
+ {
+ 100, 5500, 0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x5c, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x5c, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd},
+ {
+ 102, 5510, 0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x4c, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x4c, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd},
+ {
+ 104, 5520, 0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x4c, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x4c, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc},
+ {
+ 106, 5530, 0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x3b, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x3b, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db},
+ {
+ 108, 5540, 0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x3b, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x3b, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da},
+ {
+ 110, 5550, 0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x3b, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x3b, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9},
+ {
+ 112, 5560, 0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x2b, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x2b, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8},
+ {
+ 114, 5570, 0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x2a, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x2a, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7},
+ {
+ 116, 5580, 0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x1a, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x1a, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7},
+ {
+ 118, 5590, 0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x1a, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x1a, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6},
+ {
+ 120, 5600, 0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x1a, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x1a, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5},
+ {
+ 122, 5610, 0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x19, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x19, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4},
+ {
+ 124, 5620, 0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x19, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x19, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3},
+ {
+ 126, 5630, 0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x09, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x09, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2},
+ {
+ 128, 5640, 0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x09, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x09, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2},
+ {
+ 130, 5650, 0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf8, 0x00, 0x08, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf8, 0x00, 0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1},
+ {
+ 132, 5660, 0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf6, 0x00, 0x08, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf6, 0x00, 0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0},
+ {
+ 134, 5670, 0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf6, 0x00, 0x08, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf6, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf},
+ {
+ 136, 5680, 0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf6, 0x00, 0x08, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf6, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce},
+ {
+ 138, 5690, 0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x07, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf6, 0x00, 0x07, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf6, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce},
+ {
+ 140, 5700, 0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x07, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf6, 0x00, 0x07, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf6, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd},
+ {
+ 142, 5710, 0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x07, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x07, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc},
+ {
+ 144, 5720, 0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x07, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x07, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb},
+ {
+ 145, 5725, 0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb},
+ {
+ 146, 5730, 0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca},
+ {
+ 147, 5735, 0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca},
+ {
+ 148, 5740, 0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9},
+ {
+ 149, 5745, 0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9},
+ {
+ 150, 5750, 0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9},
+ {
+ 151, 5755, 0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8},
+ {
+ 152, 5760, 0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8},
+ {
+ 153, 5765, 0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8},
+ {
+ 154, 5770, 0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7},
+ {
+ 155, 5775, 0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7},
+ {
+ 156, 5780, 0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6},
+ {
+ 157, 5785, 0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x04, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6},
+ {
+ 158, 5790, 0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x04, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6},
+ {
+ 159, 5795, 0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x04, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5},
+ {
+ 160, 5800, 0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5},
+ {
+ 161, 5805, 0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4},
+ {
+ 162, 5810, 0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4},
+ {
+ 163, 5815, 0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4},
+ {
+ 164, 5820, 0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3},
+ {
+ 165, 5825, 0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3},
+ {
+ 166, 5830, 0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2},
+ {
+ 168, 5840, 0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2},
+ {
+ 170, 5850, 0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf4, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1},
+ {
+ 172, 5860, 0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf2, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf2, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0},
+ {
+ 174, 5870, 0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf2, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf2, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf},
+ {
+ 176, 5880, 0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf2, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf2, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf},
+ {
+ 178, 5890, 0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x06, 0x00, 0xf2, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06,
+ 0x00, 0xf2, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be},
+ {
+ 180, 5900, 0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x05, 0x00, 0xf2, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x05,
+ 0x00, 0xf2, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd},
+ {
+ 182, 5910, 0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x05, 0x00, 0xf2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x05,
+ 0x00, 0xf2, 0x00, 0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc},
+ {
+ 1, 2412, 0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xff, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xff, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0f, 0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443},
+ {
+ 2, 2417, 0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xff, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xff, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0f, 0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441},
+ {
+ 3, 2422, 0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xff, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xff, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0f, 0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f},
+ {
+ 4, 2427, 0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xfd, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0f, 0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d},
+ {
+ 5, 2432, 0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xfb, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0f, 0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a},
+ {
+ 6, 2437, 0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xfa, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0f, 0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438},
+ {
+ 7, 2442, 0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0f, 0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436},
+ {
+ 8, 2447, 0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xf7, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0f, 0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434},
+ {
+ 9, 2452, 0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xf6, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0f, 0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431},
+ {
+ 10, 2457, 0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0xf5, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0d, 0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f},
+ {
+ 11, 2462, 0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0d, 0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d},
+ {
+ 12, 2467, 0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf3, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0xf3, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0d, 0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b},
+ {
+ 13, 2472, 0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf2, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0d, 0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429},
+ {
+ 14, 2484, 0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x05, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0xf0, 0x00, 0x05, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0d, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424}
+};
+
+static const struct chan_info_nphy_radio205x chan_info_nphyrev4_2056_A1[] = {
+ {
+ 184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216},
+ {
+ 186, 4930, 0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215},
+ {
+ 188, 4940, 0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214},
+ {
+ 190, 4950, 0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213},
+ {
+ 192, 4960, 0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212},
+ {
+ 194, 4970, 0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211},
+ {
+ 196, 4980, 0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f},
+ {
+ 198, 4990, 0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e},
+ {
+ 200, 5000, 0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d},
+ {
+ 202, 5010, 0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c},
+ {
+ 204, 5020, 0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b},
+ {
+ 206, 5030, 0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a},
+ {
+ 208, 5040, 0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209},
+ {
+ 210, 5050, 0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208},
+ {
+ 212, 5060, 0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207},
+ {
+ 214, 5070, 0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206},
+ {
+ 216, 5080, 0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205},
+ {
+ 218, 5090, 0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xff, 0x00, 0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204},
+ {
+ 220, 5100, 0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfe, 0x00, 0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203},
+ {
+ 222, 5110, 0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfe, 0x00, 0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202},
+ {
+ 224, 5120, 0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfe, 0x00, 0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201},
+ {
+ 226, 5130, 0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfe, 0x00, 0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200},
+ {
+ 228, 5140, 0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfe, 0x00, 0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff},
+ {
+ 32, 5160, 0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfe, 0x00, 0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd},
+ {
+ 34, 5170, 0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfe, 0x00, 0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc},
+ {
+ 36, 5180, 0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xef, 0x00, 0x0c, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xef, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfe, 0x00, 0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb},
+ {
+ 38, 5190, 0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xef, 0x00, 0x0c, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xef, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfe, 0x00, 0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa},
+ {
+ 40, 5200, 0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xef, 0x00, 0x0a, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xef, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfc, 0x00, 0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9},
+ {
+ 42, 5210, 0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xdf, 0x00, 0x0a, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfc, 0x00, 0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8},
+ {
+ 44, 5220, 0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xdf, 0x00, 0x0a, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfc, 0x00, 0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7},
+ {
+ 46, 5230, 0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xdf, 0x00, 0x0a, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfc, 0x00, 0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6},
+ {
+ 48, 5240, 0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x0a, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfc, 0x00, 0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5},
+ {
+ 50, 5250, 0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x0a, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfc, 0x00, 0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4},
+ {
+ 52, 5260, 0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x0a, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfc, 0x00, 0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3},
+ {
+ 54, 5270, 0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x0a, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfc, 0x00, 0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2},
+ {
+ 56, 5280, 0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xbf, 0x00, 0x0a, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfc, 0x00, 0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1},
+ {
+ 58, 5290, 0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xbf, 0x00, 0x0a, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfc, 0x00, 0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0},
+ {
+ 60, 5300, 0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xbf, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfa, 0x00, 0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0},
+ {
+ 62, 5310, 0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xbf, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfa, 0x00, 0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef},
+ {
+ 64, 5320, 0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xbf, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfa, 0x00, 0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee},
+ {
+ 66, 5330, 0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xaf, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfa, 0x00, 0xaf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfa, 0x00, 0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed},
+ {
+ 68, 5340, 0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xaf, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfa, 0x00, 0xaf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfa, 0x00, 0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec},
+ {
+ 70, 5350, 0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfa, 0x00, 0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb},
+ {
+ 72, 5360, 0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfa, 0x00, 0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea},
+ {
+ 74, 5370, 0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfa, 0x00, 0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9},
+ {
+ 76, 5380, 0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfa, 0x00, 0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8},
+ {
+ 78, 5390, 0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x8f, 0x00, 0x08, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xfa, 0x00, 0x8f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xfa, 0x00, 0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7},
+ {
+ 80, 5400, 0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8f, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x8f, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xf8, 0x00, 0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6},
+ {
+ 82, 5410, 0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8f, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x8f, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xf8, 0x00, 0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5},
+ {
+ 84, 5420, 0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8e, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x8e, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xf8, 0x00, 0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5},
+ {
+ 86, 5430, 0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8e, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x8e, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xf8, 0x00, 0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4},
+ {
+ 88, 5440, 0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x7e, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x7e, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xf8, 0x00, 0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3},
+ {
+ 90, 5450, 0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x7d, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x7d, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xf8, 0x00, 0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2},
+ {
+ 92, 5460, 0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x6d, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x6d, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xf8, 0x00, 0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1},
+ {
+ 94, 5470, 0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x6d, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x6d, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xf8, 0x00, 0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0},
+ {
+ 96, 5480, 0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x5d, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x5d, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xf8, 0x00, 0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df},
+ {
+ 98, 5490, 0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x5c, 0x00, 0x07, 0x00, 0x7f,
+ 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x5c, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f,
+ 0x00, 0xf8, 0x00, 0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de},
+ {
+ 100, 5500, 0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x5c, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x5c, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d,
+ 0x00, 0xf6, 0x00, 0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd},
+ {
+ 102, 5510, 0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x4c, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x4c, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d,
+ 0x00, 0xf6, 0x00, 0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd},
+ {
+ 104, 5520, 0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x4c, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x4c, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d,
+ 0x00, 0xf6, 0x00, 0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc},
+ {
+ 106, 5530, 0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x3b, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x3b, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d,
+ 0x00, 0xf6, 0x00, 0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db},
+ {
+ 108, 5540, 0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x3b, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x3b, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d,
+ 0x00, 0xf6, 0x00, 0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da},
+ {
+ 110, 5550, 0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x3b, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x3b, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d,
+ 0x00, 0xf6, 0x00, 0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9},
+ {
+ 112, 5560, 0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x2b, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x2b, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d,
+ 0x00, 0xf6, 0x00, 0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8},
+ {
+ 114, 5570, 0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x2a, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x2a, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d,
+ 0x00, 0xf6, 0x00, 0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7},
+ {
+ 116, 5580, 0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x1a, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x1a, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d,
+ 0x00, 0xf6, 0x00, 0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7},
+ {
+ 118, 5590, 0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x1a, 0x00, 0x06, 0x00, 0x7f,
+ 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x1a, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d,
+ 0x00, 0xf6, 0x00, 0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6},
+ {
+ 120, 5600, 0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x1a, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x1a, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xf4, 0x00, 0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5},
+ {
+ 122, 5610, 0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x19, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x19, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xf4, 0x00, 0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4},
+ {
+ 124, 5620, 0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x19, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x19, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xf4, 0x00, 0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3},
+ {
+ 126, 5630, 0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x09, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x09, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xf4, 0x00, 0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2},
+ {
+ 128, 5640, 0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x09, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x09, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xf4, 0x00, 0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2},
+ {
+ 130, 5650, 0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x08, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xf4, 0x00, 0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1},
+ {
+ 132, 5660, 0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x08, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xf4, 0x00, 0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0},
+ {
+ 134, 5670, 0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x08, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xf4, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf},
+ {
+ 136, 5680, 0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x08, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xf4, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce},
+ {
+ 138, 5690, 0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x07, 0x00, 0x04, 0x00, 0x7f,
+ 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x07, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b,
+ 0x00, 0xf4, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce},
+ {
+ 140, 5700, 0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x07, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x07, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd},
+ {
+ 142, 5710, 0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x07, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x07, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc},
+ {
+ 144, 5720, 0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x07, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x07, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb},
+ {
+ 145, 5725, 0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb},
+ {
+ 146, 5730, 0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca},
+ {
+ 147, 5735, 0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca},
+ {
+ 148, 5740, 0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9},
+ {
+ 149, 5745, 0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9},
+ {
+ 150, 5750, 0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9},
+ {
+ 151, 5755, 0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8},
+ {
+ 152, 5760, 0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8},
+ {
+ 153, 5765, 0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8},
+ {
+ 154, 5770, 0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7},
+ {
+ 155, 5775, 0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7},
+ {
+ 156, 5780, 0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6},
+ {
+ 157, 5785, 0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x04, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x04, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6},
+ {
+ 158, 5790, 0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x04, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x04, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6},
+ {
+ 159, 5795, 0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x04, 0x00, 0x03, 0x00, 0x7f,
+ 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x04, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a,
+ 0x00, 0xf2, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5},
+ {
+ 160, 5800, 0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5},
+ {
+ 161, 5805, 0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4},
+ {
+ 162, 5810, 0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4},
+ {
+ 163, 5815, 0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4},
+ {
+ 164, 5820, 0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3},
+ {
+ 165, 5825, 0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3},
+ {
+ 166, 5830, 0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2},
+ {
+ 168, 5840, 0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2},
+ {
+ 170, 5850, 0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1},
+ {
+ 172, 5860, 0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0},
+ {
+ 174, 5870, 0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x02, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x02, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf},
+ {
+ 176, 5880, 0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x02, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x02, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf},
+ {
+ 178, 5890, 0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x02, 0x00, 0x02, 0x00, 0x7f,
+ 0x00, 0x09, 0x00, 0xf0, 0x00, 0x02, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09,
+ 0x00, 0xf0, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be},
+ {
+ 180, 5900, 0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf0, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf0, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd},
+ {
+ 182, 5910, 0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x07, 0x00, 0xf0, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x07,
+ 0x00, 0xf0, 0x00, 0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc},
+ {
+ 1, 2412, 0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xff, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xff, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443},
+ {
+ 2, 2417, 0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xff, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xff, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441},
+ {
+ 3, 2422, 0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xff, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xff, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f},
+ {
+ 4, 2427, 0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xfd, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d},
+ {
+ 5, 2432, 0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xfb, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a},
+ {
+ 6, 2437, 0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438},
+ {
+ 7, 2442, 0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf8, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436},
+ {
+ 8, 2447, 0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf7, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434},
+ {
+ 9, 2452, 0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf6, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431},
+ {
+ 10, 2457, 0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf5, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f},
+ {
+ 11, 2462, 0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d},
+ {
+ 12, 2467, 0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf3, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf3, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b},
+ {
+ 13, 2472, 0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf2, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf2, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429},
+ {
+ 14, 2484, 0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x04, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf0, 0x00, 0x04, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0e, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424}
+};
+
+static const struct chan_info_nphy_radio205x chan_info_nphyrev5_2056v5[] = {
+ {
+ 184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70,
+ 0x00, 0x0f, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216},
+ {
+ 186, 4930, 0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70,
+ 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215},
+ {
+ 188, 4940, 0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70,
+ 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214},
+ {
+ 190, 4950, 0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70,
+ 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213},
+ {
+ 192, 4960, 0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212},
+ {
+ 194, 4970, 0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211},
+ {
+ 196, 4980, 0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f},
+ {
+ 198, 4990, 0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e},
+ {
+ 200, 5000, 0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d},
+ {
+ 202, 5010, 0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c},
+ {
+ 204, 5020, 0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x09, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b},
+ {
+ 206, 5030, 0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x09, 0x00, 0x70,
+ 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a},
+ {
+ 208, 5040, 0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x70,
+ 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209},
+ {
+ 210, 5050, 0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x70,
+ 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208},
+ {
+ 212, 5060, 0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x70,
+ 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207},
+ {
+ 214, 5070, 0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206},
+ {
+ 216, 5080, 0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205},
+ {
+ 218, 5090, 0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204},
+ {
+ 220, 5100, 0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203},
+ {
+ 222, 5110, 0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202},
+ {
+ 224, 5120, 0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201},
+ {
+ 226, 5130, 0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0a, 0x00, 0x9f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200},
+ {
+ 228, 5140, 0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x07, 0x00, 0x70,
+ 0x00, 0x0a, 0x00, 0x9f, 0x00, 0xfb, 0x00, 0x07, 0x00, 0x70, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff},
+ {
+ 32, 5160, 0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x07, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfb, 0x00, 0x07, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x6e, 0x00, 0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd},
+ {
+ 34, 5170, 0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfb, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x6e, 0x00, 0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc},
+ {
+ 36, 5180, 0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x6e, 0x00, 0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb},
+ {
+ 38, 5190, 0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x6e, 0x00, 0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa},
+ {
+ 40, 5200, 0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x6e, 0x00, 0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9},
+ {
+ 42, 5210, 0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x6e, 0x00, 0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8},
+ {
+ 44, 5220, 0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x6e, 0x00, 0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7},
+ {
+ 46, 5230, 0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xea, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x08, 0x00, 0x9e, 0x00, 0xea, 0x00, 0x06, 0x00, 0x70, 0x00, 0x08,
+ 0x00, 0x6e, 0x00, 0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6},
+ {
+ 48, 5240, 0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xe9, 0x00, 0x05, 0x00, 0x70,
+ 0x00, 0x08, 0x00, 0x9d, 0x00, 0xe9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08,
+ 0x00, 0x6d, 0x00, 0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5},
+ {
+ 50, 5250, 0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xe9, 0x00, 0x05, 0x00, 0x70,
+ 0x00, 0x08, 0x00, 0x9d, 0x00, 0xe9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08,
+ 0x00, 0x6d, 0x00, 0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4},
+ {
+ 52, 5260, 0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xd9, 0x00, 0x05, 0x00, 0x70,
+ 0x00, 0x08, 0x00, 0x9d, 0x00, 0xd9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08,
+ 0x00, 0x6d, 0x00, 0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3},
+ {
+ 54, 5270, 0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xd8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xd8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x6c, 0x00, 0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2},
+ {
+ 56, 5280, 0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xc8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x6c, 0x00, 0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1},
+ {
+ 58, 5290, 0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xc8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x6c, 0x00, 0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0},
+ {
+ 60, 5300, 0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xc8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x6c, 0x00, 0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0},
+ {
+ 62, 5310, 0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xc8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x6c, 0x00, 0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef},
+ {
+ 64, 5320, 0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xb8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xb8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x6c, 0x00, 0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee},
+ {
+ 66, 5330, 0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xb7, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x9b, 0x00, 0xb7, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x6b, 0x00, 0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed},
+ {
+ 68, 5340, 0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xb7, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x9b, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x6b, 0x00, 0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec},
+ {
+ 70, 5350, 0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xa7, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x9b, 0x00, 0xa7, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x6b, 0x00, 0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb},
+ {
+ 72, 5360, 0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xa6, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x9b, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x6b, 0x00, 0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea},
+ {
+ 74, 5370, 0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xa6, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x9b, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x5b, 0x00, 0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9},
+ {
+ 76, 5380, 0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x96, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x9a, 0x00, 0x96, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x5a, 0x00, 0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8},
+ {
+ 78, 5390, 0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x95, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x5a, 0x00, 0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7},
+ {
+ 80, 5400, 0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x95, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x5a, 0x00, 0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6},
+ {
+ 82, 5410, 0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x95, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x05, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x05,
+ 0x00, 0x5a, 0x00, 0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5},
+ {
+ 84, 5420, 0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x95, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x05, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x05,
+ 0x00, 0x5a, 0x00, 0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5},
+ {
+ 86, 5430, 0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x85, 0x00, 0x02, 0x00, 0x70,
+ 0x00, 0x05, 0x00, 0x99, 0x00, 0x85, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05,
+ 0x00, 0x59, 0x00, 0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4},
+ {
+ 88, 5440, 0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x84, 0x00, 0x02, 0x00, 0x70,
+ 0x00, 0x05, 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05,
+ 0x00, 0x59, 0x00, 0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3},
+ {
+ 90, 5450, 0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x84, 0x00, 0x02, 0x00, 0x70,
+ 0x00, 0x05, 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05,
+ 0x00, 0x59, 0x00, 0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2},
+ {
+ 92, 5460, 0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x84, 0x00, 0x02, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x69, 0x00, 0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1},
+ {
+ 94, 5470, 0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x74, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x99, 0x00, 0x74, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x69, 0x00, 0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0},
+ {
+ 96, 5480, 0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x73, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df},
+ {
+ 98, 5490, 0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x73, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de},
+ {
+ 100, 5500, 0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x73, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x78, 0x00, 0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd},
+ {
+ 102, 5510, 0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x73, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x78, 0x00, 0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd},
+ {
+ 104, 5520, 0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x73, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x78, 0x00, 0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc},
+ {
+ 106, 5530, 0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x63, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x03, 0x00, 0x98, 0x00, 0x63, 0x00, 0x01, 0x00, 0x70, 0x00, 0x03,
+ 0x00, 0x78, 0x00, 0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db},
+ {
+ 108, 5540, 0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x62, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x03, 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03,
+ 0x00, 0x77, 0x00, 0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da},
+ {
+ 110, 5550, 0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x62, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x03, 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03,
+ 0x00, 0x77, 0x00, 0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9},
+ {
+ 112, 5560, 0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x62, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x03, 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03,
+ 0x00, 0x77, 0x00, 0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8},
+ {
+ 114, 5570, 0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x52, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x96, 0x00, 0x52, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x76, 0x00, 0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7},
+ {
+ 116, 5580, 0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x52, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x96, 0x00, 0x52, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x76, 0x00, 0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7},
+ {
+ 118, 5590, 0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x76, 0x00, 0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6},
+ {
+ 120, 5600, 0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x76, 0x00, 0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5},
+ {
+ 122, 5610, 0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x76, 0x00, 0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4},
+ {
+ 124, 5620, 0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x76, 0x00, 0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3},
+ {
+ 126, 5630, 0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x76, 0x00, 0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2},
+ {
+ 128, 5640, 0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x95, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x75, 0x00, 0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2},
+ {
+ 130, 5650, 0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x50, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x95, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x75, 0x00, 0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1},
+ {
+ 132, 5660, 0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x50, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x95, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x75, 0x00, 0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0},
+ {
+ 134, 5670, 0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x74, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf},
+ {
+ 136, 5680, 0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x74, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce},
+ {
+ 138, 5690, 0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x74, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce},
+ {
+ 140, 5700, 0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x74, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd},
+ {
+ 142, 5710, 0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x74, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc},
+ {
+ 144, 5720, 0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x74, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb},
+ {
+ 145, 5725, 0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x74, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb},
+ {
+ 146, 5730, 0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x94, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x84, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca},
+ {
+ 147, 5735, 0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x83, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca},
+ {
+ 148, 5740, 0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x83, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9},
+ {
+ 149, 5745, 0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x83, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9},
+ {
+ 150, 5750, 0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x83, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9},
+ {
+ 151, 5755, 0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x83, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8},
+ {
+ 152, 5760, 0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x20, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x93, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x83, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8},
+ {
+ 153, 5765, 0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x20, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x82, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8},
+ {
+ 154, 5770, 0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x20, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x82, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7},
+ {
+ 155, 5775, 0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x20, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x82, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7},
+ {
+ 156, 5780, 0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x82, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6},
+ {
+ 157, 5785, 0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x82, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6},
+ {
+ 158, 5790, 0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x82, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6},
+ {
+ 159, 5795, 0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x82, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5},
+ {
+ 160, 5800, 0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x82, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5},
+ {
+ 161, 5805, 0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x82, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4},
+ {
+ 162, 5810, 0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x82, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4},
+ {
+ 163, 5815, 0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x82, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4},
+ {
+ 164, 5820, 0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x82, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3},
+ {
+ 165, 5825, 0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x82, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3},
+ {
+ 166, 5830, 0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x72, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2},
+ {
+ 168, 5840, 0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x72, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2},
+ {
+ 170, 5850, 0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x72, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1},
+ {
+ 172, 5860, 0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x72, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0},
+ {
+ 174, 5870, 0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x71, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf},
+ {
+ 176, 5880, 0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x71, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf},
+ {
+ 178, 5890, 0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x71, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be},
+ {
+ 180, 5900, 0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x71, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd},
+ {
+ 182, 5910, 0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x71, 0x00, 0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc},
+ {
+ 1, 2412, 0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x1f, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0b, 0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443},
+ {
+ 2, 2417, 0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x1f, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0a, 0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441},
+ {
+ 3, 2422, 0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0a, 0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f},
+ {
+ 4, 2427, 0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x0a, 0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d},
+ {
+ 5, 2432, 0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x0a, 0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a},
+ {
+ 6, 2437, 0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x0a, 0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438},
+ {
+ 7, 2442, 0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x0a, 0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436},
+ {
+ 8, 2447, 0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x09, 0x00, 0x08, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x09, 0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434},
+ {
+ 9, 2452, 0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x07, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x09, 0x00, 0x07, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x09, 0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431},
+ {
+ 10, 2457, 0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x06, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x06, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0d, 0x00, 0x09, 0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f},
+ {
+ 11, 2462, 0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x05, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0d, 0x00, 0x09, 0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d},
+ {
+ 12, 2467, 0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x04, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0d, 0x00, 0x08, 0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b},
+ {
+ 13, 2472, 0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x03, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0d, 0x00, 0x08, 0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429},
+ {
+ 14, 2484, 0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0d, 0x00, 0x08, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424}
+};
+
+static const struct chan_info_nphy_radio205x chan_info_nphyrev6_2056v6[] = {
+ {
+ 184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216},
+ {
+ 186, 4930, 0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215},
+ {
+ 188, 4940, 0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214},
+ {
+ 190, 4950, 0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213},
+ {
+ 192, 4960, 0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212},
+ {
+ 194, 4970, 0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211},
+ {
+ 196, 4980, 0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f},
+ {
+ 198, 4990, 0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e},
+ {
+ 200, 5000, 0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d},
+ {
+ 202, 5010, 0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c},
+ {
+ 204, 5020, 0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b},
+ {
+ 206, 5030, 0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a},
+ {
+ 208, 5040, 0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209},
+ {
+ 210, 5050, 0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208},
+ {
+ 212, 5060, 0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207},
+ {
+ 214, 5070, 0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206},
+ {
+ 216, 5080, 0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205},
+ {
+ 218, 5090, 0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204},
+ {
+ 220, 5100, 0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203},
+ {
+ 222, 5110, 0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202},
+ {
+ 224, 5120, 0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201},
+ {
+ 226, 5130, 0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200},
+ {
+ 228, 5140, 0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff},
+ {
+ 32, 5160, 0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd},
+ {
+ 34, 5170, 0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc},
+ {
+ 36, 5180, 0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb},
+ {
+ 38, 5190, 0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa},
+ {
+ 40, 5200, 0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9},
+ {
+ 42, 5210, 0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8},
+ {
+ 44, 5220, 0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xfe, 0xd8, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7},
+ {
+ 46, 5230, 0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xd8, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6},
+ {
+ 48, 5240, 0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xc8, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5},
+ {
+ 50, 5250, 0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xed, 0xc7, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4},
+ {
+ 52, 5260, 0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8e, 0x0e, 0x00, 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3},
+ {
+ 54, 5270, 0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8e, 0x0e, 0x00, 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2},
+ {
+ 56, 5280, 0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1},
+ {
+ 58, 5290, 0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0},
+ {
+ 60, 5300, 0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0},
+ {
+ 62, 5310, 0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef},
+ {
+ 64, 5320, 0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdb, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee},
+ {
+ 66, 5330, 0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xcb, 0xa6, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed},
+ {
+ 68, 5340, 0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec},
+ {
+ 70, 5350, 0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb},
+ {
+ 72, 5360, 0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea},
+ {
+ 74, 5370, 0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9},
+ {
+ 76, 5380, 0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x95, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8},
+ {
+ 78, 5390, 0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7},
+ {
+ 80, 5400, 0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6},
+ {
+ 82, 5410, 0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb7, 0x84, 0x00, 0x02, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5},
+ {
+ 84, 5420, 0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xa7, 0x84, 0x00, 0x02, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5},
+ {
+ 86, 5430, 0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0b, 0x00, 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4},
+ {
+ 88, 5440, 0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3},
+ {
+ 90, 5450, 0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x01, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2},
+ {
+ 92, 5460, 0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x01, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1},
+ {
+ 94, 5470, 0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x94, 0x73, 0x00, 0x01, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0},
+ {
+ 96, 5480, 0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x84, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df},
+ {
+ 98, 5490, 0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x83, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de},
+ {
+ 100, 5500, 0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd},
+ {
+ 102, 5510, 0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd},
+ {
+ 104, 5520, 0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x72, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc},
+ {
+ 106, 5530, 0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x72, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db},
+ {
+ 108, 5540, 0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x71, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da},
+ {
+ 110, 5550, 0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9},
+ {
+ 112, 5560, 0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8},
+ {
+ 114, 5570, 0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x62, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7},
+ {
+ 116, 5580, 0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x60, 0x62, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08,
+ 0x00, 0x6f, 0x00, 0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7},
+ {
+ 118, 5590, 0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x50, 0x61, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x61, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08,
+ 0x00, 0x6f, 0x00, 0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6},
+ {
+ 120, 5600, 0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08,
+ 0x00, 0x6f, 0x00, 0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5},
+ {
+ 122, 5610, 0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08,
+ 0x00, 0x6f, 0x00, 0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4},
+ {
+ 124, 5620, 0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07,
+ 0x00, 0x6f, 0x00, 0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3},
+ {
+ 126, 5630, 0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07,
+ 0x00, 0x6f, 0x00, 0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2},
+ {
+ 128, 5640, 0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x50, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07,
+ 0x00, 0x6f, 0x00, 0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2},
+ {
+ 130, 5650, 0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07,
+ 0x00, 0x6f, 0x00, 0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1},
+ {
+ 132, 5660, 0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6f, 0x00, 0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0},
+ {
+ 134, 5670, 0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6f, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf},
+ {
+ 136, 5680, 0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6f, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce},
+ {
+ 138, 5690, 0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6f, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce},
+ {
+ 140, 5700, 0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd},
+ {
+ 142, 5710, 0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc},
+ {
+ 144, 5720, 0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb},
+ {
+ 145, 5725, 0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb},
+ {
+ 146, 5730, 0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca},
+ {
+ 147, 5735, 0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6d, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca},
+ {
+ 148, 5740, 0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6d, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9},
+ {
+ 149, 5745, 0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6d, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9},
+ {
+ 150, 5750, 0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6d, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6d, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9},
+ {
+ 151, 5755, 0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6c, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8},
+ {
+ 152, 5760, 0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6c, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8},
+ {
+ 153, 5765, 0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6c, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8},
+ {
+ 154, 5770, 0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7},
+ {
+ 155, 5775, 0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7},
+ {
+ 156, 5780, 0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6},
+ {
+ 157, 5785, 0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6},
+ {
+ 158, 5790, 0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6},
+ {
+ 159, 5795, 0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5},
+ {
+ 160, 5800, 0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5},
+ {
+ 161, 5805, 0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6a, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4},
+ {
+ 162, 5810, 0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6a, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4},
+ {
+ 163, 5815, 0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6a, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4},
+ {
+ 164, 5820, 0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6a, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3},
+ {
+ 165, 5825, 0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x69, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3},
+ {
+ 166, 5830, 0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x69, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2},
+ {
+ 168, 5840, 0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x69, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2},
+ {
+ 170, 5850, 0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x69, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1},
+ {
+ 172, 5860, 0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x69, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0},
+ {
+ 174, 5870, 0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf},
+ {
+ 176, 5880, 0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf},
+ {
+ 178, 5890, 0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be},
+ {
+ 180, 5900, 0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd},
+ {
+ 182, 5910, 0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc},
+ {
+ 1, 2412, 0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0b, 0x00, 0x0a, 0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443},
+ {
+ 2, 2417, 0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0b, 0x00, 0x0a, 0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441},
+ {
+ 3, 2422, 0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x67, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x67, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0b, 0x00, 0x0a, 0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f},
+ {
+ 4, 2427, 0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x57, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x57, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x0a, 0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d},
+ {
+ 5, 2432, 0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x56, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x56, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x0a, 0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a},
+ {
+ 6, 2437, 0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x46, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x46, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x0a, 0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438},
+ {
+ 7, 2442, 0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x45, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x45, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x0a, 0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436},
+ {
+ 8, 2447, 0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x34, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x34, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x09, 0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434},
+ {
+ 9, 2452, 0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x23, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x23, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x09, 0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431},
+ {
+ 10, 2457, 0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x12, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x12, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x09, 0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f},
+ {
+ 11, 2462, 0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x02, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x09, 0x00, 0x09, 0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d},
+ {
+ 12, 2467, 0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x01, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x09, 0x00, 0x09, 0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b},
+ {
+ 13, 2472, 0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x01, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x09, 0x00, 0x09, 0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429},
+ {
+ 14, 2484, 0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x07, 0x07, 0x07, 0x8f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x09, 0x00, 0x09, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424}
+};
+
+static const struct chan_info_nphy_radio205x chan_info_nphyrev5n6_2056v7[] = {
+ {
+ 184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70,
+ 0x00, 0x0f, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216},
+ {
+ 186, 4930, 0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70,
+ 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215},
+ {
+ 188, 4940, 0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70,
+ 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214},
+ {
+ 190, 4950, 0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70,
+ 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213},
+ {
+ 192, 4960, 0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212},
+ {
+ 194, 4970, 0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211},
+ {
+ 196, 4980, 0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f},
+ {
+ 198, 4990, 0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e},
+ {
+ 200, 5000, 0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d},
+ {
+ 202, 5010, 0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c},
+ {
+ 204, 5020, 0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x09, 0x00, 0x70,
+ 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b},
+ {
+ 206, 5030, 0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x09, 0x00, 0x70,
+ 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a},
+ {
+ 208, 5040, 0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x70,
+ 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209},
+ {
+ 210, 5050, 0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x70,
+ 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208},
+ {
+ 212, 5060, 0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x70,
+ 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207},
+ {
+ 214, 5070, 0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206},
+ {
+ 216, 5080, 0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205},
+ {
+ 218, 5090, 0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204},
+ {
+ 220, 5100, 0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203},
+ {
+ 222, 5110, 0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202},
+ {
+ 224, 5120, 0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201},
+ {
+ 226, 5130, 0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x08, 0x00, 0x70,
+ 0x00, 0x0a, 0x00, 0x9f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200},
+ {
+ 228, 5140, 0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x07, 0x00, 0x70,
+ 0x00, 0x0a, 0x00, 0x9f, 0x00, 0xfb, 0x00, 0x07, 0x00, 0x70, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff},
+ {
+ 32, 5160, 0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x07, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfb, 0x00, 0x07, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x6e, 0x00, 0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd},
+ {
+ 34, 5170, 0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfb, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x6e, 0x00, 0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc},
+ {
+ 36, 5180, 0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x6e, 0x00, 0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb},
+ {
+ 38, 5190, 0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x6e, 0x00, 0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa},
+ {
+ 40, 5200, 0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x6e, 0x00, 0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9},
+ {
+ 42, 5210, 0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x6e, 0x00, 0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8},
+ {
+ 44, 5220, 0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xfe, 0xfa, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09,
+ 0x00, 0x6e, 0x00, 0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7},
+ {
+ 46, 5230, 0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xea, 0x00, 0x06, 0x00, 0x70,
+ 0x00, 0x08, 0x00, 0x9e, 0x00, 0xea, 0x00, 0x06, 0x00, 0x70, 0x00, 0x08,
+ 0x00, 0x6e, 0x00, 0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6},
+ {
+ 48, 5240, 0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xe9, 0x00, 0x05, 0x00, 0x70,
+ 0x00, 0x08, 0x00, 0x9d, 0x00, 0xe9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08,
+ 0x00, 0x6d, 0x00, 0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5},
+ {
+ 50, 5250, 0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xed, 0xe9, 0x00, 0x05, 0x00, 0x70,
+ 0x00, 0x08, 0x00, 0x9d, 0x00, 0xe9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08,
+ 0x00, 0x6d, 0x00, 0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4},
+ {
+ 52, 5260, 0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8e, 0x0e, 0x00, 0xed, 0xd9, 0x00, 0x05, 0x00, 0x70,
+ 0x00, 0x08, 0x00, 0x9d, 0x00, 0xd9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08,
+ 0x00, 0x6d, 0x00, 0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3},
+ {
+ 54, 5270, 0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8e, 0x0e, 0x00, 0xed, 0xd8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xd8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x6c, 0x00, 0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2},
+ {
+ 56, 5280, 0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xc8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x6c, 0x00, 0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1},
+ {
+ 58, 5290, 0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xc8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x6c, 0x00, 0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0},
+ {
+ 60, 5300, 0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xc8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x6c, 0x00, 0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0},
+ {
+ 62, 5310, 0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xc8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x6c, 0x00, 0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef},
+ {
+ 64, 5320, 0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdb, 0xb8, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x9c, 0x00, 0xb8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x6c, 0x00, 0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee},
+ {
+ 66, 5330, 0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xcb, 0xb7, 0x00, 0x04, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x9b, 0x00, 0xb7, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x6b, 0x00, 0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed},
+ {
+ 68, 5340, 0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xca, 0xb7, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x07, 0x00, 0x9b, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x70, 0x00, 0x07,
+ 0x00, 0x6b, 0x00, 0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec},
+ {
+ 70, 5350, 0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xca, 0xa7, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x9b, 0x00, 0xa7, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x6b, 0x00, 0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb},
+ {
+ 72, 5360, 0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0xa6, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x9b, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x6b, 0x00, 0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea},
+ {
+ 74, 5370, 0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0xa6, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x9b, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x7b, 0x00, 0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9},
+ {
+ 76, 5380, 0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x96, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x9a, 0x00, 0x96, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x7a, 0x00, 0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8},
+ {
+ 78, 5390, 0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x95, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x7a, 0x00, 0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7},
+ {
+ 80, 5400, 0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x95, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x06, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06,
+ 0x00, 0x7a, 0x00, 0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6},
+ {
+ 82, 5410, 0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb7, 0x95, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x05, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x05,
+ 0x00, 0x7a, 0x00, 0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5},
+ {
+ 84, 5420, 0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xa7, 0x95, 0x00, 0x03, 0x00, 0x70,
+ 0x00, 0x05, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x05,
+ 0x00, 0x7a, 0x00, 0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5},
+ {
+ 86, 5430, 0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0b, 0x00, 0xa6, 0x85, 0x00, 0x02, 0x00, 0x70,
+ 0x00, 0x05, 0x00, 0x99, 0x00, 0x85, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05,
+ 0x00, 0x79, 0x00, 0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4},
+ {
+ 88, 5440, 0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0xa6, 0x84, 0x00, 0x02, 0x00, 0x70,
+ 0x00, 0x05, 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05,
+ 0x00, 0x79, 0x00, 0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3},
+ {
+ 90, 5450, 0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x02, 0x00, 0x70,
+ 0x00, 0x05, 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05,
+ 0x00, 0x79, 0x00, 0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2},
+ {
+ 92, 5460, 0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x02, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x79, 0x00, 0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1},
+ {
+ 94, 5470, 0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x94, 0x74, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x99, 0x00, 0x74, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x79, 0x00, 0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0},
+ {
+ 96, 5480, 0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x84, 0x73, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x78, 0x00, 0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df},
+ {
+ 98, 5490, 0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x83, 0x73, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x78, 0x00, 0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de},
+ {
+ 100, 5500, 0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x78, 0x00, 0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd},
+ {
+ 102, 5510, 0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x78, 0x00, 0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd},
+ {
+ 104, 5520, 0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x72, 0x73, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04,
+ 0x00, 0x78, 0x00, 0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc},
+ {
+ 106, 5530, 0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x72, 0x63, 0x00, 0x01, 0x00, 0x70,
+ 0x00, 0x03, 0x00, 0x98, 0x00, 0x63, 0x00, 0x01, 0x00, 0x70, 0x00, 0x03,
+ 0x00, 0x78, 0x00, 0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db},
+ {
+ 108, 5540, 0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x71, 0x62, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x03, 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03,
+ 0x00, 0x77, 0x00, 0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da},
+ {
+ 110, 5550, 0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x62, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x03, 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03,
+ 0x00, 0x77, 0x00, 0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9},
+ {
+ 112, 5560, 0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x62, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x03, 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03,
+ 0x00, 0x77, 0x00, 0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8},
+ {
+ 114, 5570, 0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x52, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x96, 0x00, 0x52, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x76, 0x00, 0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7},
+ {
+ 116, 5580, 0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x60, 0x52, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x96, 0x00, 0x52, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x86, 0x00, 0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7},
+ {
+ 118, 5590, 0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x86, 0x00, 0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6},
+ {
+ 120, 5600, 0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x86, 0x00, 0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5},
+ {
+ 122, 5610, 0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x86, 0x00, 0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4},
+ {
+ 124, 5620, 0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x86, 0x00, 0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3},
+ {
+ 126, 5630, 0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x86, 0x00, 0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2},
+ {
+ 128, 5640, 0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x51, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x02, 0x00, 0x95, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x85, 0x00, 0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2},
+ {
+ 130, 5650, 0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x50, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x95, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x85, 0x00, 0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1},
+ {
+ 132, 5660, 0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x50, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x95, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x85, 0x00, 0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0},
+ {
+ 134, 5670, 0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x84, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf},
+ {
+ 136, 5680, 0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x84, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce},
+ {
+ 138, 5690, 0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x94, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce},
+ {
+ 140, 5700, 0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x94, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd},
+ {
+ 142, 5710, 0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x94, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc},
+ {
+ 144, 5720, 0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x94, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb},
+ {
+ 145, 5725, 0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x40, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x94, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb},
+ {
+ 146, 5730, 0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x01, 0x00, 0x94, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01,
+ 0x00, 0x94, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca},
+ {
+ 147, 5735, 0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x93, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca},
+ {
+ 148, 5740, 0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x93, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9},
+ {
+ 149, 5745, 0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x93, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9},
+ {
+ 150, 5750, 0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x93, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9},
+ {
+ 151, 5755, 0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x10, 0x30, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x93, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8},
+ {
+ 152, 5760, 0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x93, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x93, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8},
+ {
+ 153, 5765, 0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8},
+ {
+ 154, 5770, 0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7},
+ {
+ 155, 5775, 0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7},
+ {
+ 156, 5780, 0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6},
+ {
+ 157, 5785, 0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6},
+ {
+ 158, 5790, 0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6},
+ {
+ 159, 5795, 0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5},
+ {
+ 160, 5800, 0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5},
+ {
+ 161, 5805, 0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4},
+ {
+ 162, 5810, 0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4},
+ {
+ 163, 5815, 0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4},
+ {
+ 164, 5820, 0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3},
+ {
+ 165, 5825, 0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3},
+ {
+ 166, 5830, 0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2},
+ {
+ 168, 5840, 0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2},
+ {
+ 170, 5850, 0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1},
+ {
+ 172, 5860, 0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x92, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0},
+ {
+ 174, 5870, 0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x91, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf},
+ {
+ 176, 5880, 0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x91, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf},
+ {
+ 178, 5890, 0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x91, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be},
+ {
+ 180, 5900, 0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x91, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd},
+ {
+ 182, 5910, 0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x91, 0x00, 0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc},
+ {
+ 1, 2412, 0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x89, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0b, 0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443},
+ {
+ 2, 2417, 0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x89, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0a, 0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441},
+ {
+ 3, 2422, 0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x89, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0f, 0x00, 0x0a, 0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f},
+ {
+ 4, 2427, 0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x0a, 0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d},
+ {
+ 5, 2432, 0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x77, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x0a, 0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a},
+ {
+ 6, 2437, 0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x76, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x76, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x0a, 0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438},
+ {
+ 7, 2442, 0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x66, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x66, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x0a, 0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436},
+ {
+ 8, 2447, 0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x55, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x09, 0x00, 0x55, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x09, 0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434},
+ {
+ 9, 2452, 0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x45, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0e, 0x00, 0x09, 0x00, 0x45, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0e, 0x00, 0x09, 0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431},
+ {
+ 10, 2457, 0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x34, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x34, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0d, 0x00, 0x09, 0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f},
+ {
+ 11, 2462, 0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x33, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0d, 0x00, 0x09, 0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d},
+ {
+ 12, 2467, 0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x22, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x22, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0d, 0x00, 0x08, 0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b},
+ {
+ 13, 2472, 0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x11, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0d, 0x00, 0x08, 0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429},
+ {
+ 14, 2484, 0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x07, 0x07, 0x07, 0x8f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0d, 0x00, 0x08, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424}
+};
+
+static const struct chan_info_nphy_radio205x chan_info_nphyrev6_2056v8[] = {
+ {
+ 184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216},
+ {
+ 186, 4930, 0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215},
+ {
+ 188, 4940, 0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214},
+ {
+ 190, 4950, 0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213},
+ {
+ 192, 4960, 0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212},
+ {
+ 194, 4970, 0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211},
+ {
+ 196, 4980, 0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f},
+ {
+ 198, 4990, 0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e},
+ {
+ 200, 5000, 0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d},
+ {
+ 202, 5010, 0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c},
+ {
+ 204, 5020, 0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b},
+ {
+ 206, 5030, 0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a},
+ {
+ 208, 5040, 0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209},
+ {
+ 210, 5050, 0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208},
+ {
+ 212, 5060, 0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207},
+ {
+ 214, 5070, 0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206},
+ {
+ 216, 5080, 0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205},
+ {
+ 218, 5090, 0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204},
+ {
+ 220, 5100, 0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203},
+ {
+ 222, 5110, 0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202},
+ {
+ 224, 5120, 0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201},
+ {
+ 226, 5130, 0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200},
+ {
+ 228, 5140, 0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff},
+ {
+ 32, 5160, 0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd},
+ {
+ 34, 5170, 0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc},
+ {
+ 36, 5180, 0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb},
+ {
+ 38, 5190, 0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa},
+ {
+ 40, 5200, 0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9},
+ {
+ 42, 5210, 0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8},
+ {
+ 44, 5220, 0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xfe, 0xd8, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7},
+ {
+ 46, 5230, 0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xd8, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6},
+ {
+ 48, 5240, 0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xc8, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5},
+ {
+ 50, 5250, 0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xed, 0xc7, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4},
+ {
+ 52, 5260, 0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8e, 0x0e, 0x00, 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3},
+ {
+ 54, 5270, 0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8e, 0x0e, 0x00, 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2},
+ {
+ 56, 5280, 0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1},
+ {
+ 58, 5290, 0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0},
+ {
+ 60, 5300, 0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0},
+ {
+ 62, 5310, 0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef},
+ {
+ 64, 5320, 0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdb, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee},
+ {
+ 66, 5330, 0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xcb, 0xa6, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed},
+ {
+ 68, 5340, 0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec},
+ {
+ 70, 5350, 0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb},
+ {
+ 72, 5360, 0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea},
+ {
+ 74, 5370, 0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9},
+ {
+ 76, 5380, 0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x95, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8},
+ {
+ 78, 5390, 0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7},
+ {
+ 80, 5400, 0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6},
+ {
+ 82, 5410, 0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb7, 0x84, 0x00, 0x02, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5},
+ {
+ 84, 5420, 0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xa7, 0x84, 0x00, 0x02, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5},
+ {
+ 86, 5430, 0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0b, 0x00, 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4},
+ {
+ 88, 5440, 0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3},
+ {
+ 90, 5450, 0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x01, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2},
+ {
+ 92, 5460, 0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x01, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1},
+ {
+ 94, 5470, 0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x94, 0x73, 0x00, 0x01, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0},
+ {
+ 96, 5480, 0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x84, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df},
+ {
+ 98, 5490, 0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x83, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de},
+ {
+ 100, 5500, 0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd},
+ {
+ 102, 5510, 0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd},
+ {
+ 104, 5520, 0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x72, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc},
+ {
+ 106, 5530, 0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x72, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db},
+ {
+ 108, 5540, 0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x71, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da},
+ {
+ 110, 5550, 0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9},
+ {
+ 112, 5560, 0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8},
+ {
+ 114, 5570, 0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x62, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7},
+ {
+ 116, 5580, 0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x60, 0x62, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08,
+ 0x00, 0x6f, 0x00, 0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7},
+ {
+ 118, 5590, 0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x50, 0x61, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x61, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08,
+ 0x00, 0x6f, 0x00, 0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6},
+ {
+ 120, 5600, 0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08,
+ 0x00, 0x6f, 0x00, 0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5},
+ {
+ 122, 5610, 0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08,
+ 0x00, 0x6f, 0x00, 0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4},
+ {
+ 124, 5620, 0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07,
+ 0x00, 0x6f, 0x00, 0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3},
+ {
+ 126, 5630, 0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07,
+ 0x00, 0x6f, 0x00, 0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2},
+ {
+ 128, 5640, 0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x50, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07,
+ 0x00, 0x6f, 0x00, 0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2},
+ {
+ 130, 5650, 0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07,
+ 0x00, 0x6f, 0x00, 0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1},
+ {
+ 132, 5660, 0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6f, 0x00, 0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0},
+ {
+ 134, 5670, 0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6f, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf},
+ {
+ 136, 5680, 0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6f, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce},
+ {
+ 138, 5690, 0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6f, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce},
+ {
+ 140, 5700, 0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd},
+ {
+ 142, 5710, 0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc},
+ {
+ 144, 5720, 0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb},
+ {
+ 145, 5725, 0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb},
+ {
+ 146, 5730, 0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca},
+ {
+ 147, 5735, 0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6d, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca},
+ {
+ 148, 5740, 0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6d, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9},
+ {
+ 149, 5745, 0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6d, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9},
+ {
+ 150, 5750, 0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6d, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6d, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9},
+ {
+ 151, 5755, 0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6c, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8},
+ {
+ 152, 5760, 0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6c, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8},
+ {
+ 153, 5765, 0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6c, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8},
+ {
+ 154, 5770, 0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7},
+ {
+ 155, 5775, 0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7},
+ {
+ 156, 5780, 0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6},
+ {
+ 157, 5785, 0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6},
+ {
+ 158, 5790, 0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6},
+ {
+ 159, 5795, 0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5},
+ {
+ 160, 5800, 0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5},
+ {
+ 161, 5805, 0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6a, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4},
+ {
+ 162, 5810, 0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6a, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4},
+ {
+ 163, 5815, 0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6a, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4},
+ {
+ 164, 5820, 0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6a, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3},
+ {
+ 165, 5825, 0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, 0x10, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x69, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3},
+ {
+ 166, 5830, 0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x69, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2},
+ {
+ 168, 5840, 0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x69, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2},
+ {
+ 170, 5850, 0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x69, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1},
+ {
+ 172, 5860, 0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x69, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0},
+ {
+ 174, 5870, 0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf},
+ {
+ 176, 5880, 0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf},
+ {
+ 178, 5890, 0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be},
+ {
+ 180, 5900, 0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd},
+ {
+ 182, 5910, 0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc},
+ {
+ 1, 2412, 0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0b, 0x00, 0x0a, 0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443},
+ {
+ 2, 2417, 0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0b, 0x00, 0x0a, 0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441},
+ {
+ 3, 2422, 0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x67, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0b, 0x00, 0x0a, 0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f},
+ {
+ 4, 2427, 0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x57, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x0a, 0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d},
+ {
+ 5, 2432, 0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x56, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x77, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x0a, 0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a},
+ {
+ 6, 2437, 0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x46, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x76, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x0a, 0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438},
+ {
+ 7, 2442, 0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x45, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x66, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x0a, 0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436},
+ {
+ 8, 2447, 0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x34, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x55, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x09, 0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434},
+ {
+ 9, 2452, 0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x23, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x45, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x09, 0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431},
+ {
+ 10, 2457, 0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x12, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x34, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x09, 0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f},
+ {
+ 11, 2462, 0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x33, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x09, 0x00, 0x09, 0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d},
+ {
+ 12, 2467, 0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x22, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x09, 0x00, 0x09, 0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b},
+ {
+ 13, 2472, 0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x11, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x09, 0x00, 0x09, 0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429},
+ {
+ 14, 2484, 0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, 0x16, 0x01,
+ 0x07, 0x07, 0x07, 0x8f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x09, 0x00, 0x09, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424}
+};
+
+static const struct chan_info_nphy_radio205x chan_info_nphyrev6_2056v11[] = {
+ {
+ 184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216},
+ {
+ 186, 4930, 0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215},
+ {
+ 188, 4940, 0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214},
+ {
+ 190, 4950, 0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213},
+ {
+ 192, 4960, 0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212},
+ {
+ 194, 4970, 0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211},
+ {
+ 196, 4980, 0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f},
+ {
+ 198, 4990, 0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e},
+ {
+ 200, 5000, 0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d},
+ {
+ 202, 5010, 0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c},
+ {
+ 204, 5020, 0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b},
+ {
+ 206, 5030, 0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a},
+ {
+ 208, 5040, 0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209},
+ {
+ 210, 5050, 0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208},
+ {
+ 212, 5060, 0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207},
+ {
+ 214, 5070, 0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206},
+ {
+ 216, 5080, 0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205},
+ {
+ 218, 5090, 0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204},
+ {
+ 220, 5100, 0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203},
+ {
+ 222, 5110, 0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202},
+ {
+ 224, 5120, 0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201},
+ {
+ 226, 5130, 0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200},
+ {
+ 228, 5140, 0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x08, 0x00, 0x77,
+ 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f,
+ 0x00, 0x6f, 0x00, 0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff},
+ {
+ 32, 5160, 0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd},
+ {
+ 34, 5170, 0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc},
+ {
+ 36, 5180, 0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77,
+ 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0e,
+ 0x00, 0x6f, 0x00, 0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb},
+ {
+ 38, 5190, 0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa},
+ {
+ 40, 5200, 0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9},
+ {
+ 42, 5210, 0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8},
+ {
+ 44, 5220, 0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xfe, 0xd8, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7},
+ {
+ 46, 5230, 0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xd8, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6},
+ {
+ 48, 5240, 0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xc8, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5},
+ {
+ 50, 5250, 0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xed, 0xc7, 0x00, 0x05, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4},
+ {
+ 52, 5260, 0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x02, 0x02, 0x02, 0x8e, 0x0e, 0x00, 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77,
+ 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0d,
+ 0x00, 0x6f, 0x00, 0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3},
+ {
+ 54, 5270, 0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8e, 0x0e, 0x00, 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2},
+ {
+ 56, 5280, 0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1},
+ {
+ 58, 5290, 0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0},
+ {
+ 60, 5300, 0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0},
+ {
+ 62, 5310, 0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef},
+ {
+ 64, 5320, 0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdb, 0xb7, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c,
+ 0x00, 0x6f, 0x00, 0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee},
+ {
+ 66, 5330, 0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xcb, 0xa6, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed},
+ {
+ 68, 5340, 0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec},
+ {
+ 70, 5350, 0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b,
+ 0x00, 0x6f, 0x00, 0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb},
+ {
+ 72, 5360, 0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea},
+ {
+ 74, 5370, 0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9},
+ {
+ 76, 5380, 0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x95, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8},
+ {
+ 78, 5390, 0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7},
+ {
+ 80, 5400, 0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6},
+ {
+ 82, 5410, 0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb7, 0x84, 0x00, 0x02, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5},
+ {
+ 84, 5420, 0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xa7, 0x84, 0x00, 0x02, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5},
+ {
+ 86, 5430, 0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x03, 0x03, 0x03, 0x8c, 0x0b, 0x00, 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77,
+ 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a,
+ 0x00, 0x6f, 0x00, 0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4},
+ {
+ 88, 5440, 0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3},
+ {
+ 90, 5450, 0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x01, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2},
+ {
+ 92, 5460, 0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x01, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1},
+ {
+ 94, 5470, 0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x94, 0x73, 0x00, 0x01, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0},
+ {
+ 96, 5480, 0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x84, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df},
+ {
+ 98, 5490, 0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x83, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de},
+ {
+ 100, 5500, 0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd},
+ {
+ 102, 5510, 0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd},
+ {
+ 104, 5520, 0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x72, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc},
+ {
+ 106, 5530, 0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x72, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db},
+ {
+ 108, 5540, 0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x71, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da},
+ {
+ 110, 5550, 0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9},
+ {
+ 112, 5560, 0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8},
+ {
+ 114, 5570, 0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x62, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x09, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09,
+ 0x00, 0x6f, 0x00, 0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7},
+ {
+ 116, 5580, 0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x60, 0x62, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08,
+ 0x00, 0x6f, 0x00, 0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7},
+ {
+ 118, 5590, 0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x50, 0x61, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x61, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08,
+ 0x00, 0x6f, 0x00, 0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6},
+ {
+ 120, 5600, 0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08,
+ 0x00, 0x6f, 0x00, 0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5},
+ {
+ 122, 5610, 0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x08, 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08,
+ 0x00, 0x6f, 0x00, 0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4},
+ {
+ 124, 5620, 0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07,
+ 0x00, 0x6f, 0x00, 0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3},
+ {
+ 126, 5630, 0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07,
+ 0x00, 0x6f, 0x00, 0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2},
+ {
+ 128, 5640, 0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x50, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07,
+ 0x00, 0x6f, 0x00, 0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2},
+ {
+ 130, 5650, 0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x07, 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07,
+ 0x00, 0x6f, 0x00, 0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1},
+ {
+ 132, 5660, 0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6f, 0x00, 0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0},
+ {
+ 134, 5670, 0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6f, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf},
+ {
+ 136, 5680, 0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6f, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce},
+ {
+ 138, 5690, 0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6f, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce},
+ {
+ 140, 5700, 0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd},
+ {
+ 142, 5710, 0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc},
+ {
+ 144, 5720, 0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb},
+ {
+ 145, 5725, 0x03, 0x01, 0x02, 0x04, 0x79, 0x05, 0x05, 0x02, 0x15, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb},
+ {
+ 146, 5730, 0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6e, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca},
+ {
+ 147, 5735, 0x03, 0x01, 0x02, 0x04, 0x7b, 0x05, 0x05, 0x02, 0x15, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6d, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca},
+ {
+ 148, 5740, 0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6d, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9},
+ {
+ 149, 5745, 0xfe, 0x00, 0x02, 0x04, 0x7d, 0x05, 0x05, 0x02, 0x15, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06,
+ 0x00, 0x6d, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9},
+ {
+ 150, 5750, 0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6d, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6d, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9},
+ {
+ 151, 5755, 0xfe, 0x00, 0x02, 0x04, 0x7f, 0x05, 0x05, 0x02, 0x15, 0x01,
+ 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6c, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8},
+ {
+ 152, 5760, 0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6c, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8},
+ {
+ 153, 5765, 0xf8, 0x00, 0x02, 0x04, 0x81, 0x05, 0x05, 0x02, 0x15, 0x01,
+ 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6c, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8},
+ {
+ 154, 5770, 0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7},
+ {
+ 155, 5775, 0xf8, 0x00, 0x02, 0x04, 0x83, 0x05, 0x05, 0x02, 0x15, 0x01,
+ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7},
+ {
+ 156, 5780, 0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6},
+ {
+ 157, 5785, 0xf2, 0x00, 0x02, 0x04, 0x85, 0x05, 0x05, 0x02, 0x15, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6},
+ {
+ 158, 5790, 0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6},
+ {
+ 159, 5795, 0xf2, 0x00, 0x02, 0x04, 0x87, 0x05, 0x05, 0x02, 0x15, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5},
+ {
+ 160, 5800, 0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6b, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5},
+ {
+ 161, 5805, 0xed, 0x00, 0x02, 0x04, 0x89, 0x05, 0x05, 0x02, 0x15, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6a, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4},
+ {
+ 162, 5810, 0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6a, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4},
+ {
+ 163, 5815, 0xed, 0x00, 0x02, 0x04, 0x8b, 0x05, 0x05, 0x02, 0x15, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6a, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4},
+ {
+ 164, 5820, 0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x6a, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3},
+ {
+ 165, 5825, 0xed, 0x00, 0x02, 0x04, 0x8d, 0x05, 0x05, 0x02, 0x15, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x69, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3},
+ {
+ 166, 5830, 0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x05, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05,
+ 0x00, 0x69, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2},
+ {
+ 168, 5840, 0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x69, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2},
+ {
+ 170, 5850, 0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x69, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1},
+ {
+ 172, 5860, 0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x69, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0},
+ {
+ 174, 5870, 0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf},
+ {
+ 176, 5880, 0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf},
+ {
+ 178, 5890, 0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be},
+ {
+ 180, 5900, 0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd},
+ {
+ 182, 5910, 0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x02, 0x0c, 0x01,
+ 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04,
+ 0x00, 0x68, 0x00, 0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc},
+ {
+ 1, 2412, 0x00, 0x01, 0x03, 0x09, 0x6c, 0x06, 0x06, 0x04, 0x2b, 0x01,
+ 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0b, 0x00, 0x0a, 0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443},
+ {
+ 2, 2417, 0x00, 0x01, 0x03, 0x09, 0x71, 0x06, 0x06, 0x04, 0x2b, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0b, 0x00, 0x0a, 0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441},
+ {
+ 3, 2422, 0x00, 0x01, 0x03, 0x09, 0x76, 0x06, 0x06, 0x04, 0x2b, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x67, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0b, 0x00, 0x0a, 0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f},
+ {
+ 4, 2427, 0x00, 0x01, 0x03, 0x09, 0x7b, 0x06, 0x06, 0x04, 0x2b, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x57, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x0a, 0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d},
+ {
+ 5, 2432, 0x00, 0x01, 0x03, 0x09, 0x80, 0x06, 0x06, 0x04, 0x2b, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x56, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x77, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x0a, 0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a},
+ {
+ 6, 2437, 0x00, 0x01, 0x03, 0x09, 0x85, 0x06, 0x06, 0x04, 0x2b, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x46, 0x00, 0x03, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x76, 0x00, 0x03, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x0a, 0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438},
+ {
+ 7, 2442, 0x00, 0x01, 0x03, 0x09, 0x8a, 0x06, 0x06, 0x04, 0x2b, 0x01,
+ 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x45, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x66, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x0a, 0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436},
+ {
+ 8, 2447, 0x00, 0x01, 0x03, 0x09, 0x8f, 0x06, 0x06, 0x04, 0x2b, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x34, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x55, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x09, 0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434},
+ {
+ 9, 2452, 0x00, 0x01, 0x03, 0x09, 0x94, 0x06, 0x06, 0x04, 0x2b, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x23, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x45, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x09, 0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431},
+ {
+ 10, 2457, 0x00, 0x01, 0x03, 0x09, 0x99, 0x06, 0x06, 0x04, 0x2b, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x12, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x34, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x0a, 0x00, 0x09, 0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f},
+ {
+ 11, 2462, 0x00, 0x01, 0x03, 0x09, 0x9e, 0x06, 0x06, 0x04, 0x2b, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x33, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x09, 0x00, 0x09, 0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d},
+ {
+ 12, 2467, 0x00, 0x01, 0x03, 0x09, 0xa3, 0x06, 0x06, 0x04, 0x2b, 0x01,
+ 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x22, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x09, 0x00, 0x09, 0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b},
+ {
+ 13, 2472, 0x00, 0x01, 0x03, 0x09, 0xa8, 0x06, 0x06, 0x04, 0x2b, 0x01,
+ 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x11, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x09, 0x00, 0x09, 0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429},
+ {
+ 14, 2484, 0xff, 0x01, 0x03, 0x09, 0xb4, 0x06, 0x06, 0x04, 0x2b, 0x01,
+ 0x07, 0x07, 0x07, 0x8f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00,
+ 0x09, 0x00, 0x09, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424}
+};
+
+static const struct chan_info_nphy_radio2057 chan_info_nphyrev7_2057_rev4[] = {
+ {
+ 184, 4920, 0x68, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xec, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00,
+ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07b4, 0x07b0, 0x07ac, 0x0214,
+ 0x0215,
+ 0x0216,
+ },
+ {
+ 186, 4930, 0x6b, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xed, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00,
+ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07b8, 0x07b4, 0x07b0, 0x0213,
+ 0x0214,
+ 0x0215,
+ },
+ {
+ 188, 4940, 0x6e, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xee, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00,
+ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07bc, 0x07b8, 0x07b4, 0x0212,
+ 0x0213,
+ 0x0214,
+ },
+ {
+ 190, 4950, 0x72, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xef, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00,
+ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07c0, 0x07bc, 0x07b8, 0x0211,
+ 0x0212,
+ 0x0213,
+ },
+ {
+ 192, 4960, 0x75, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf0, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00,
+ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07c4, 0x07c0, 0x07bc, 0x020f,
+ 0x0211,
+ 0x0212,
+ },
+ {
+ 194, 4970, 0x78, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf1, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00,
+ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07c8, 0x07c4, 0x07c0, 0x020e,
+ 0x020f,
+ 0x0211,
+ },
+ {
+ 196, 4980, 0x7c, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf2, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00,
+ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07cc, 0x07c8, 0x07c4, 0x020d,
+ 0x020e,
+ 0x020f,
+ },
+ {
+ 198, 4990, 0x7f, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf3, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00,
+ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07d0, 0x07cc, 0x07c8, 0x020c,
+ 0x020d,
+ 0x020e,
+ },
+ {
+ 200, 5000, 0x82, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf4, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00,
+ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07d4, 0x07d0, 0x07cc, 0x020b,
+ 0x020c,
+ 0x020d,
+ },
+ {
+ 202, 5010, 0x86, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf5, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00,
+ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07d8, 0x07d4, 0x07d0, 0x020a,
+ 0x020b,
+ 0x020c,
+ },
+ {
+ 204, 5020, 0x89, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf6, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00,
+ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07dc, 0x07d8, 0x07d4, 0x0209,
+ 0x020a,
+ 0x020b,
+ },
+ {
+ 206, 5030, 0x8c, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf7, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00,
+ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07e0, 0x07dc, 0x07d8, 0x0208,
+ 0x0209,
+ 0x020a,
+ },
+ {
+ 208, 5040, 0x90, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf8, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00,
+ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07e4, 0x07e0, 0x07dc, 0x0207,
+ 0x0208,
+ 0x0209,
+ },
+ {
+ 210, 5050, 0x93, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf9, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00,
+ 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07e8, 0x07e4, 0x07e0, 0x0206,
+ 0x0207,
+ 0x0208,
+ },
+ {
+ 212, 5060, 0x96, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfa, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xe3, 0x00, 0xef, 0x00,
+ 0x00, 0x0f, 0x0f, 0xe3, 0x00, 0xef, 0x07ec, 0x07e8, 0x07e4, 0x0205,
+ 0x0206,
+ 0x0207,
+ },
+ {
+ 214, 5070, 0x9a, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfb, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xef, 0x00,
+ 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xef, 0x07f0, 0x07ec, 0x07e8, 0x0204,
+ 0x0205,
+ 0x0206,
+ },
+ {
+ 216, 5080, 0x9d, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfc, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xef, 0x00,
+ 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xef, 0x07f4, 0x07f0, 0x07ec, 0x0203,
+ 0x0204,
+ 0x0205,
+ },
+ {
+ 218, 5090, 0xa0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfd, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x00,
+ 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x07f8, 0x07f4, 0x07f0, 0x0202,
+ 0x0203,
+ 0x0204,
+ },
+ {
+ 220, 5100, 0xa4, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfe, 0x01, 0x0d,
+ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x00,
+ 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x07fc, 0x07f8, 0x07f4, 0x0201,
+ 0x0202,
+ 0x0203,
+ },
+ {
+ 222, 5110, 0xa7, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xff, 0x01, 0x0d,
+ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x00,
+ 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x0800, 0x07fc, 0x07f8, 0x0200,
+ 0x0201,
+ 0x0202,
+ },
+ {
+ 224, 5120, 0xaa, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x00, 0x02, 0x0d,
+ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x00,
+ 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x0804, 0x0800, 0x07fc, 0x01ff,
+ 0x0200,
+ 0x0201,
+ },
+ {
+ 226, 5130, 0xae, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x01, 0x02, 0x0d,
+ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x00,
+ 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x0808, 0x0804, 0x0800, 0x01fe,
+ 0x01ff,
+ 0x0200,
+ },
+ {
+ 228, 5140, 0xb1, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x02, 0x02, 0x0d,
+ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0e, 0x0e, 0xe3, 0x00, 0xd6, 0x00,
+ 0x00, 0x0e, 0x0e, 0xe3, 0x00, 0xd6, 0x080c, 0x0808, 0x0804, 0x01fd,
+ 0x01fe,
+ 0x01ff,
+ },
+ {
+ 32, 5160, 0xb8, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x04, 0x02, 0x0d,
+ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0d, 0x0e, 0xe3, 0x00, 0xd6, 0x00,
+ 0x00, 0x0d, 0x0e, 0xe3, 0x00, 0xd6, 0x0814, 0x0810, 0x080c, 0x01fb,
+ 0x01fc,
+ 0x01fd,
+ },
+ {
+ 34, 5170, 0xbb, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x05, 0x02, 0x0d,
+ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0d, 0x0e, 0xe3, 0x00, 0xd6, 0x00,
+ 0x00, 0x0d, 0x0e, 0xe3, 0x00, 0xd6, 0x0818, 0x0814, 0x0810, 0x01fa,
+ 0x01fb,
+ 0x01fc,
+ },
+ {
+ 36, 5180, 0xbe, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x06, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x00,
+ 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x081c, 0x0818, 0x0814, 0x01f9,
+ 0x01fa,
+ 0x01fb,
+ },
+ {
+ 38, 5190, 0xc2, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x07, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x00,
+ 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x0820, 0x081c, 0x0818, 0x01f8,
+ 0x01f9,
+ 0x01fa,
+ },
+ {
+ 40, 5200, 0xc5, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x08, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x00,
+ 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x0824, 0x0820, 0x081c, 0x01f7,
+ 0x01f8,
+ 0x01f9,
+ },
+ {
+ 42, 5210, 0xc8, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x09, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x00,
+ 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x0828, 0x0824, 0x0820, 0x01f6,
+ 0x01f7,
+ 0x01f8,
+ },
+ {
+ 44, 5220, 0xcc, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0a, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x00,
+ 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x082c, 0x0828, 0x0824, 0x01f5,
+ 0x01f6,
+ 0x01f7,
+ },
+ {
+ 46, 5230, 0xcf, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0b, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x00,
+ 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x0830, 0x082c, 0x0828, 0x01f4,
+ 0x01f5,
+ 0x01f6,
+ },
+ {
+ 48, 5240, 0xd2, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0c, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x00,
+ 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x0834, 0x0830, 0x082c, 0x01f3,
+ 0x01f4,
+ 0x01f5,
+ },
+ {
+ 50, 5250, 0xd6, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0d, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x00,
+ 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x0838, 0x0834, 0x0830, 0x01f2,
+ 0x01f3,
+ 0x01f4,
+ },
+ {
+ 52, 5260, 0xd9, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0e, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0c, 0x0d, 0xd3, 0x00, 0xd6, 0x00,
+ 0x00, 0x0c, 0x0d, 0xd3, 0x00, 0xd6, 0x083c, 0x0838, 0x0834, 0x01f1,
+ 0x01f2,
+ 0x01f3,
+ },
+ {
+ 54, 5270, 0xdc, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0f, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0c, 0x0d, 0xd3, 0x00, 0xd6, 0x00,
+ 0x00, 0x0c, 0x0d, 0xd3, 0x00, 0xd6, 0x0840, 0x083c, 0x0838, 0x01f0,
+ 0x01f1,
+ 0x01f2,
+ },
+ {
+ 56, 5280, 0xe0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x10, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0c, 0x0c, 0xc3, 0x00, 0xd4, 0x00,
+ 0x00, 0x0c, 0x0c, 0xc3, 0x00, 0xd4, 0x0844, 0x0840, 0x083c, 0x01f0,
+ 0x01f0,
+ 0x01f1,
+ },
+ {
+ 58, 5290, 0xe3, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x11, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0c, 0x0c, 0xc3, 0x00, 0xd4, 0x00,
+ 0x00, 0x0c, 0x0c, 0xc3, 0x00, 0xd4, 0x0848, 0x0844, 0x0840, 0x01ef,
+ 0x01f0,
+ 0x01f0,
+ },
+ {
+ 60, 5300, 0xe6, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x12, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0c, 0x0c, 0xc3, 0x00, 0xd4, 0x00,
+ 0x00, 0x0c, 0x0c, 0xc3, 0x00, 0xd4, 0x084c, 0x0848, 0x0844, 0x01ee,
+ 0x01ef,
+ 0x01f0,
+ },
+ {
+ 62, 5310, 0xea, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x13, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0b, 0x0c, 0xc3, 0x00, 0xd4, 0x00,
+ 0x00, 0x0b, 0x0c, 0xc3, 0x00, 0xd4, 0x0850, 0x084c, 0x0848, 0x01ed,
+ 0x01ee,
+ 0x01ef,
+ },
+ {
+ 64, 5320, 0xed, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x14, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0b, 0x0c, 0xc3, 0x00, 0xd4, 0x00,
+ 0x00, 0x0b, 0x0c, 0xc3, 0x00, 0xd4, 0x0854, 0x0850, 0x084c, 0x01ec,
+ 0x01ed,
+ 0x01ee,
+ },
+ {
+ 66, 5330, 0xf0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x15, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0b, 0x0c, 0xc3, 0x00, 0xd4, 0x00,
+ 0x00, 0x0b, 0x0c, 0xc3, 0x00, 0xd4, 0x0858, 0x0854, 0x0850, 0x01eb,
+ 0x01ec,
+ 0x01ed,
+ },
+ {
+ 68, 5340, 0xf4, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x16, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0a, 0x0c, 0xc3, 0x00, 0xa1, 0x00,
+ 0x00, 0x0a, 0x0c, 0xc3, 0x00, 0xa1, 0x085c, 0x0858, 0x0854, 0x01ea,
+ 0x01eb,
+ 0x01ec,
+ },
+ {
+ 70, 5350, 0xf7, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x17, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x00,
+ 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x0860, 0x085c, 0x0858, 0x01e9,
+ 0x01ea,
+ 0x01eb,
+ },
+ {
+ 72, 5360, 0xfa, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x18, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x00,
+ 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x0864, 0x0860, 0x085c, 0x01e8,
+ 0x01e9,
+ 0x01ea,
+ },
+ {
+ 74, 5370, 0xfe, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x19, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x00,
+ 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x0868, 0x0864, 0x0860, 0x01e7,
+ 0x01e8,
+ 0x01e9,
+ },
+ {
+ 76, 5380, 0x01, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1a, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x00,
+ 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x086c, 0x0868, 0x0864, 0x01e6,
+ 0x01e7,
+ 0x01e8,
+ },
+ {
+ 78, 5390, 0x04, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1b, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0a, 0x0a, 0xa3, 0x00, 0xa1, 0x00,
+ 0x00, 0x0a, 0x0a, 0xa3, 0x00, 0xa1, 0x0870, 0x086c, 0x0868, 0x01e5,
+ 0x01e6,
+ 0x01e7,
+ },
+ {
+ 80, 5400, 0x08, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1c, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x09, 0x0a, 0xa3, 0x00, 0x90, 0x00,
+ 0x00, 0x09, 0x0a, 0xa3, 0x00, 0x90, 0x0874, 0x0870, 0x086c, 0x01e5,
+ 0x01e5,
+ 0x01e6,
+ },
+ {
+ 82, 5410, 0x0b, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1d, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x09, 0x0a, 0xa3, 0x00, 0x90, 0x00,
+ 0x00, 0x09, 0x0a, 0xa3, 0x00, 0x90, 0x0878, 0x0874, 0x0870, 0x01e4,
+ 0x01e5,
+ 0x01e5,
+ },
+ {
+ 84, 5420, 0x0e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1e, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x09, 0x09, 0xa3, 0x00, 0x90, 0x00,
+ 0x00, 0x09, 0x09, 0xa3, 0x00, 0x90, 0x087c, 0x0878, 0x0874, 0x01e3,
+ 0x01e4,
+ 0x01e5,
+ },
+ {
+ 86, 5430, 0x12, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1f, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x09, 0x09, 0x93, 0x00, 0x90, 0x00,
+ 0x00, 0x09, 0x09, 0x93, 0x00, 0x90, 0x0880, 0x087c, 0x0878, 0x01e2,
+ 0x01e3,
+ 0x01e4,
+ },
+ {
+ 88, 5440, 0x15, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x20, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x09, 0x09, 0x93, 0x00, 0x90, 0x00,
+ 0x00, 0x09, 0x09, 0x93, 0x00, 0x90, 0x0884, 0x0880, 0x087c, 0x01e1,
+ 0x01e2,
+ 0x01e3,
+ },
+ {
+ 90, 5450, 0x18, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x21, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x09, 0x09, 0x93, 0x00, 0x90, 0x00,
+ 0x00, 0x09, 0x09, 0x93, 0x00, 0x90, 0x0888, 0x0884, 0x0880, 0x01e0,
+ 0x01e1,
+ 0x01e2,
+ },
+ {
+ 92, 5460, 0x1c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x22, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x08, 0x08, 0x93, 0x00, 0x90, 0x00,
+ 0x00, 0x08, 0x08, 0x93, 0x00, 0x90, 0x088c, 0x0888, 0x0884, 0x01df,
+ 0x01e0,
+ 0x01e1,
+ },
+ {
+ 94, 5470, 0x1f, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x23, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x08, 0x08, 0x93, 0x00, 0x60, 0x00,
+ 0x00, 0x08, 0x08, 0x93, 0x00, 0x60, 0x0890, 0x088c, 0x0888, 0x01de,
+ 0x01df,
+ 0x01e0,
+ },
+ {
+ 96, 5480, 0x22, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x24, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x00,
+ 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x0894, 0x0890, 0x088c, 0x01dd,
+ 0x01de,
+ 0x01df,
+ },
+ {
+ 98, 5490, 0x26, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x25, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x00,
+ 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x0898, 0x0894, 0x0890, 0x01dd,
+ 0x01dd,
+ 0x01de,
+ },
+ {
+ 100, 5500, 0x29, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x26, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x00,
+ 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x089c, 0x0898, 0x0894, 0x01dc,
+ 0x01dd,
+ 0x01dd,
+ },
+ {
+ 102, 5510, 0x2c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x27, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x00,
+ 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x08a0, 0x089c, 0x0898, 0x01db,
+ 0x01dc,
+ 0x01dd,
+ },
+ {
+ 104, 5520, 0x30, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x28, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x08, 0x06, 0x93, 0x00, 0x60, 0x00,
+ 0x00, 0x08, 0x06, 0x93, 0x00, 0x60, 0x08a4, 0x08a0, 0x089c, 0x01da,
+ 0x01db,
+ 0x01dc,
+ },
+ {
+ 106, 5530, 0x33, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x29, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x08, 0x06, 0x93, 0x00, 0x60, 0x00,
+ 0x00, 0x08, 0x06, 0x93, 0x00, 0x60, 0x08a8, 0x08a4, 0x08a0, 0x01d9,
+ 0x01da,
+ 0x01db,
+ },
+ {
+ 108, 5540, 0x36, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2a, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x08, 0x06, 0x93, 0x00, 0x60, 0x00,
+ 0x00, 0x08, 0x06, 0x93, 0x00, 0x60, 0x08ac, 0x08a8, 0x08a4, 0x01d8,
+ 0x01d9,
+ 0x01da,
+ },
+ {
+ 110, 5550, 0x3a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2b, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x08, 0x05, 0x83, 0x00, 0x60, 0x00,
+ 0x00, 0x08, 0x05, 0x83, 0x00, 0x60, 0x08b0, 0x08ac, 0x08a8, 0x01d7,
+ 0x01d8,
+ 0x01d9,
+ },
+ {
+ 112, 5560, 0x3d, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2c, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x08, 0x05, 0x83, 0x00, 0x60, 0x00,
+ 0x00, 0x08, 0x05, 0x83, 0x00, 0x60, 0x08b4, 0x08b0, 0x08ac, 0x01d7,
+ 0x01d7,
+ 0x01d8,
+ },
+ {
+ 114, 5570, 0x40, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2d, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x08, 0x05, 0x83, 0x00, 0x60, 0x00,
+ 0x00, 0x08, 0x05, 0x83, 0x00, 0x60, 0x08b8, 0x08b4, 0x08b0, 0x01d6,
+ 0x01d7,
+ 0x01d7,
+ },
+ {
+ 116, 5580, 0x44, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2e, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x07, 0x05, 0x83, 0x00, 0x60, 0x00,
+ 0x00, 0x07, 0x05, 0x83, 0x00, 0x60, 0x08bc, 0x08b8, 0x08b4, 0x01d5,
+ 0x01d6,
+ 0x01d7,
+ },
+ {
+ 118, 5590, 0x47, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2f, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x07, 0x04, 0x83, 0x00, 0x60, 0x00,
+ 0x00, 0x07, 0x04, 0x83, 0x00, 0x60, 0x08c0, 0x08bc, 0x08b8, 0x01d4,
+ 0x01d5,
+ 0x01d6,
+ },
+ {
+ 120, 5600, 0x4a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x30, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x07, 0x04, 0x73, 0x00, 0x30, 0x00,
+ 0x00, 0x07, 0x04, 0x73, 0x00, 0x30, 0x08c4, 0x08c0, 0x08bc, 0x01d3,
+ 0x01d4,
+ 0x01d5,
+ },
+ {
+ 122, 5610, 0x4e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x31, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x00,
+ 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x08c8, 0x08c4, 0x08c0, 0x01d2,
+ 0x01d3,
+ 0x01d4,
+ },
+ {
+ 124, 5620, 0x51, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x32, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x00,
+ 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x08cc, 0x08c8, 0x08c4, 0x01d2,
+ 0x01d2,
+ 0x01d3,
+ },
+ {
+ 126, 5630, 0x54, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x33, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x00,
+ 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x08d0, 0x08cc, 0x08c8, 0x01d1,
+ 0x01d2,
+ 0x01d2,
+ },
+ {
+ 128, 5640, 0x58, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x34, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x00,
+ 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x08d4, 0x08d0, 0x08cc, 0x01d0,
+ 0x01d1,
+ 0x01d2,
+ },
+ {
+ 130, 5650, 0x5b, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x35, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x06, 0x03, 0x63, 0x00, 0x30, 0x00,
+ 0x00, 0x06, 0x03, 0x63, 0x00, 0x30, 0x08d8, 0x08d4, 0x08d0, 0x01cf,
+ 0x01d0,
+ 0x01d1,
+ },
+ {
+ 132, 5660, 0x5e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x36, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x06, 0x03, 0x63, 0x00, 0x30, 0x00,
+ 0x00, 0x06, 0x03, 0x63, 0x00, 0x30, 0x08dc, 0x08d8, 0x08d4, 0x01ce,
+ 0x01cf,
+ 0x01d0,
+ },
+ {
+ 134, 5670, 0x62, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x37, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x05, 0x03, 0x63, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x03, 0x63, 0x00, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce,
+ 0x01ce,
+ 0x01cf,
+ },
+ {
+ 136, 5680, 0x65, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x38, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd,
+ 0x01ce,
+ 0x01ce,
+ },
+ {
+ 138, 5690, 0x68, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x39, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc,
+ 0x01cd,
+ 0x01ce,
+ },
+ {
+ 140, 5700, 0x6c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3a, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb,
+ 0x01cc,
+ 0x01cd,
+ },
+ {
+ 142, 5710, 0x6f, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3b, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca,
+ 0x01cb,
+ 0x01cc,
+ },
+ {
+ 144, 5720, 0x72, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3c, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9,
+ 0x01ca,
+ 0x01cb,
+ },
+ {
+ 145, 5725, 0x74, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x79, 0x04, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x05, 0x01, 0x53, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x01, 0x53, 0x00, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9,
+ 0x01ca,
+ 0x01cb,
+ },
+ {
+ 146, 5730, 0x76, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3d, 0x02, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x00,
+ 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9,
+ 0x01c9,
+ 0x01ca,
+ },
+ {
+ 147, 5735, 0x77, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7b, 0x04, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x00,
+ 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8,
+ 0x01c9,
+ 0x01ca,
+ },
+ {
+ 148, 5740, 0x79, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3e, 0x02, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x00,
+ 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8,
+ 0x01c9,
+ 0x01c9,
+ },
+ {
+ 149, 5745, 0x7b, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7d, 0x04, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x00,
+ 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8,
+ 0x01c8,
+ 0x01c9,
+ },
+ {
+ 150, 5750, 0x7c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3f, 0x02, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x00,
+ 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7,
+ 0x01c8,
+ 0x01c9,
+ },
+ {
+ 151, 5755, 0x7e, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7f, 0x04, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x00,
+ 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7,
+ 0x01c8,
+ 0x01c8,
+ },
+ {
+ 152, 5760, 0x80, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x40, 0x02, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6,
+ 0x01c7,
+ 0x01c8,
+ },
+ {
+ 153, 5765, 0x81, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x81, 0x04, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6,
+ 0x01c7,
+ 0x01c8,
+ },
+ {
+ 154, 5770, 0x83, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x41, 0x02, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6,
+ 0x01c6,
+ 0x01c7,
+ },
+ {
+ 155, 5775, 0x85, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x83, 0x04, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5,
+ 0x01c6,
+ 0x01c7,
+ },
+ {
+ 156, 5780, 0x86, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x42, 0x02, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x03, 0x01, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x43, 0x00, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5,
+ 0x01c6,
+ 0x01c6,
+ },
+ {
+ 157, 5785, 0x88, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x85, 0x04, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4,
+ 0x01c5,
+ 0x01c6,
+ },
+ {
+ 158, 5790, 0x8a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x43, 0x02, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4,
+ 0x01c5,
+ 0x01c6,
+ },
+ {
+ 159, 5795, 0x8b, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x87, 0x04, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4,
+ 0x01c4,
+ 0x01c5,
+ },
+ {
+ 160, 5800, 0x8d, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x44, 0x02, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3,
+ 0x01c4,
+ 0x01c5,
+ },
+ {
+ 161, 5805, 0x8f, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x89, 0x04, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3,
+ 0x01c4,
+ 0x01c4,
+ },
+ {
+ 162, 5810, 0x90, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x45, 0x02, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2,
+ 0x01c3,
+ 0x01c4,
+ },
+ {
+ 163, 5815, 0x92, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x8b, 0x04, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2,
+ 0x01c3,
+ 0x01c4,
+ },
+ {
+ 164, 5820, 0x94, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x46, 0x02, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2,
+ 0x01c2,
+ 0x01c3,
+ },
+ {
+ 165, 5825, 0x95, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x8d, 0x04, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1,
+ 0x01c2,
+ 0x01c3,
+ },
+ {
+ 166, 5830, 0x97, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x47, 0x02, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1,
+ 0x01c2,
+ 0x01c2,
+ },
+ {
+ 168, 5840, 0x9a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x48, 0x02, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0,
+ 0x01c1,
+ 0x01c2,
+ },
+ {
+ 170, 5850, 0x9e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x49, 0x02, 0x04,
+ 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf,
+ 0x01c0,
+ 0x01c1,
+ },
+ {
+ 172, 5860, 0xa1, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4a, 0x02, 0x04,
+ 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf,
+ 0x01bf,
+ 0x01c0,
+ },
+ {
+ 174, 5870, 0xa4, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4b, 0x02, 0x04,
+ 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0930, 0x092c, 0x0928, 0x01be,
+ 0x01bf,
+ 0x01bf,
+ },
+ {
+ 176, 5880, 0xa8, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4c, 0x02, 0x03,
+ 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd,
+ 0x01be,
+ 0x01bf,
+ },
+ {
+ 178, 5890, 0xab, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4d, 0x02, 0x03,
+ 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc,
+ 0x01bd,
+ 0x01be,
+ },
+ {
+ 180, 5900, 0xae, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4e, 0x02, 0x03,
+ 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc,
+ 0x01bc,
+ 0x01bd,
+ },
+ {
+ 1, 2412, 0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, 0x09, 0x0f,
+ 0x0a, 0x00, 0x0a, 0x00, 0x71, 0xa3, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x71,
+ 0xa3, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03c9, 0x03c5, 0x03c1, 0x043a,
+ 0x043f,
+ 0x0443,
+ },
+ {
+ 2, 2417, 0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71, 0x09, 0x0f,
+ 0x0a, 0x00, 0x0a, 0x00, 0x71, 0xa3, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x71,
+ 0xa3, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cb, 0x03c7, 0x03c3, 0x0438,
+ 0x043d,
+ 0x0441,
+ },
+ {
+ 3, 2422, 0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76, 0x09, 0x0f,
+ 0x09, 0x00, 0x09, 0x00, 0x71, 0x93, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x71,
+ 0x93, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cd, 0x03c9, 0x03c5, 0x0436,
+ 0x043a,
+ 0x043f,
+ },
+ {
+ 4, 2427, 0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b, 0x09, 0x0f,
+ 0x09, 0x00, 0x09, 0x00, 0x71, 0x93, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x71,
+ 0x93, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cf, 0x03cb, 0x03c7, 0x0434,
+ 0x0438,
+ 0x043d,
+ },
+ {
+ 5, 2432, 0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80, 0x09, 0x0f,
+ 0x08, 0x00, 0x08, 0x00, 0x51, 0x83, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x51,
+ 0x83, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d1, 0x03cd, 0x03c9, 0x0431,
+ 0x0436,
+ 0x043a,
+ },
+ {
+ 6, 2437, 0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85, 0x09, 0x0f,
+ 0x08, 0x00, 0x08, 0x00, 0x51, 0x83, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x51,
+ 0x83, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d3, 0x03cf, 0x03cb, 0x042f,
+ 0x0434,
+ 0x0438,
+ },
+ {
+ 7, 2442, 0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a, 0x09, 0x0f,
+ 0x07, 0x00, 0x07, 0x00, 0x51, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x51,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d5, 0x03d1, 0x03cd, 0x042d,
+ 0x0431,
+ 0x0436,
+ },
+ {
+ 8, 2447, 0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f, 0x09, 0x0f,
+ 0x07, 0x00, 0x07, 0x00, 0x31, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x31,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d7, 0x03d3, 0x03cf, 0x042b,
+ 0x042f,
+ 0x0434,
+ },
+ {
+ 9, 2452, 0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94, 0x09, 0x0f,
+ 0x07, 0x00, 0x07, 0x00, 0x31, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x31,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d9, 0x03d5, 0x03d1, 0x0429,
+ 0x042d,
+ 0x0431,
+ },
+ {
+ 10, 2457, 0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99, 0x09, 0x0f,
+ 0x06, 0x00, 0x06, 0x00, 0x31, 0x63, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x31,
+ 0x63, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03db, 0x03d7, 0x03d3, 0x0427,
+ 0x042b,
+ 0x042f,
+ },
+ {
+ 11, 2462, 0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e, 0x09, 0x0f,
+ 0x06, 0x00, 0x06, 0x00, 0x31, 0x63, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x31,
+ 0x63, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03dd, 0x03d9, 0x03d5, 0x0424,
+ 0x0429,
+ 0x042d,
+ },
+ {
+ 12, 2467, 0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3, 0x09, 0x0f,
+ 0x05, 0x00, 0x05, 0x00, 0x11, 0x53, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x11,
+ 0x53, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03df, 0x03db, 0x03d7, 0x0422,
+ 0x0427,
+ 0x042b,
+ },
+ {
+ 13, 2472, 0x70, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa8, 0x09, 0x0f,
+ 0x05, 0x00, 0x05, 0x00, 0x11, 0x53, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x11,
+ 0x53, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03e1, 0x03dd, 0x03d9, 0x0420,
+ 0x0424,
+ 0x0429,
+ },
+ {
+ 14, 2484, 0x78, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xb4, 0x09, 0x0f,
+ 0x04, 0x00, 0x04, 0x00, 0x11, 0x43, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x11,
+ 0x43, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x03e6, 0x03e2, 0x03de, 0x041b,
+ 0x041f,
+ 0x0424}
+};
+
+static const struct chan_info_nphy_radio2057_rev5
+chan_info_nphyrev8_2057_rev5[] = {
+ {
+ 1, 2412, 0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, 0x09, 0x0d,
+ 0x08, 0x0e, 0x61, 0x03, 0xff, 0x61, 0x03, 0xff, 0x03c9, 0x03c5, 0x03c1,
+ 0x043a, 0x043f, 0x0443},
+ {
+ 2, 2417, 0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71, 0x09, 0x0d,
+ 0x08, 0x0e, 0x61, 0x03, 0xff, 0x61, 0x03, 0xff, 0x03cb, 0x03c7, 0x03c3,
+ 0x0438, 0x043d, 0x0441},
+ {
+ 3, 2422, 0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76, 0x09, 0x0d,
+ 0x08, 0x0e, 0x61, 0x03, 0xef, 0x61, 0x03, 0xef, 0x03cd, 0x03c9, 0x03c5,
+ 0x0436, 0x043a, 0x043f},
+ {
+ 4, 2427, 0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b, 0x09, 0x0c,
+ 0x08, 0x0e, 0x61, 0x03, 0xdf, 0x61, 0x03, 0xdf, 0x03cf, 0x03cb, 0x03c7,
+ 0x0434, 0x0438, 0x043d},
+ {
+ 5, 2432, 0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80, 0x09, 0x0c,
+ 0x07, 0x0d, 0x61, 0x03, 0xcf, 0x61, 0x03, 0xcf, 0x03d1, 0x03cd, 0x03c9,
+ 0x0431, 0x0436, 0x043a},
+ {
+ 6, 2437, 0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85, 0x09, 0x0c,
+ 0x07, 0x0d, 0x61, 0x03, 0xbf, 0x61, 0x03, 0xbf, 0x03d3, 0x03cf, 0x03cb,
+ 0x042f, 0x0434, 0x0438},
+ {
+ 7, 2442, 0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a, 0x09, 0x0b,
+ 0x07, 0x0d, 0x61, 0x03, 0xaf, 0x61, 0x03, 0xaf, 0x03d5, 0x03d1, 0x03cd,
+ 0x042d, 0x0431, 0x0436},
+ {
+ 8, 2447, 0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f, 0x09, 0x0b,
+ 0x07, 0x0d, 0x61, 0x03, 0x9f, 0x61, 0x03, 0x9f, 0x03d7, 0x03d3, 0x03cf,
+ 0x042b, 0x042f, 0x0434},
+ {
+ 9, 2452, 0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94, 0x09, 0x0b,
+ 0x07, 0x0d, 0x61, 0x03, 0x8f, 0x61, 0x03, 0x8f, 0x03d9, 0x03d5, 0x03d1,
+ 0x0429, 0x042d, 0x0431},
+ {
+ 10, 2457, 0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99, 0x09, 0x0b,
+ 0x07, 0x0c, 0x61, 0x03, 0x7f, 0x61, 0x03, 0x7f, 0x03db, 0x03d7, 0x03d3,
+ 0x0427, 0x042b, 0x042f},
+ {
+ 11, 2462, 0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e, 0x09, 0x0b,
+ 0x07, 0x0c, 0x61, 0x03, 0x6f, 0x61, 0x03, 0x6f, 0x03dd, 0x03d9, 0x03d5,
+ 0x0424, 0x0429, 0x042d},
+ {
+ 12, 2467, 0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3, 0x09, 0x0b,
+ 0x06, 0x0c, 0x61, 0x03, 0x5f, 0x61, 0x03, 0x5f, 0x03df, 0x03db, 0x03d7,
+ 0x0422, 0x0427, 0x042b},
+ {
+ 13, 2472, 0x70, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa8, 0x09, 0x0a,
+ 0x06, 0x0b, 0x61, 0x03, 0x4f, 0x61, 0x03, 0x4f, 0x03e1, 0x03dd, 0x03d9,
+ 0x0420, 0x0424, 0x0429},
+ {
+ 14, 2484, 0x78, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xb4, 0x09, 0x0a,
+ 0x06, 0x0b, 0x61, 0x03, 0x3f, 0x61, 0x03, 0x3f, 0x03e6, 0x03e2, 0x03de,
+ 0x041b, 0x041f, 0x0424}
+};
+
+static const struct chan_info_nphy_radio2057_rev5
+chan_info_nphyrev9_2057_rev5v1[] = {
+ {
+ 1, 2412, 0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, 0x09, 0x0d,
+ 0x08, 0x0e, 0x61, 0x03, 0xff, 0x61, 0x03, 0xff, 0x03c9, 0x03c5, 0x03c1,
+ 0x043a, 0x043f, 0x0443},
+ {
+ 2, 2417, 0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71, 0x09, 0x0d,
+ 0x08, 0x0e, 0x61, 0x03, 0xff, 0x61, 0x03, 0xff, 0x03cb, 0x03c7, 0x03c3,
+ 0x0438, 0x043d, 0x0441},
+ {
+ 3, 2422, 0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76, 0x09, 0x0d,
+ 0x08, 0x0e, 0x61, 0x03, 0xef, 0x61, 0x03, 0xef, 0x03cd, 0x03c9, 0x03c5,
+ 0x0436, 0x043a, 0x043f},
+ {
+ 4, 2427, 0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b, 0x09, 0x0c,
+ 0x08, 0x0e, 0x61, 0x03, 0xdf, 0x61, 0x03, 0xdf, 0x03cf, 0x03cb, 0x03c7,
+ 0x0434, 0x0438, 0x043d},
+ {
+ 5, 2432, 0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80, 0x09, 0x0c,
+ 0x07, 0x0d, 0x61, 0x03, 0xcf, 0x61, 0x03, 0xcf, 0x03d1, 0x03cd, 0x03c9,
+ 0x0431, 0x0436, 0x043a},
+ {
+ 6, 2437, 0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85, 0x09, 0x0c,
+ 0x07, 0x0d, 0x61, 0x03, 0xbf, 0x61, 0x03, 0xbf, 0x03d3, 0x03cf, 0x03cb,
+ 0x042f, 0x0434, 0x0438},
+ {
+ 7, 2442, 0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a, 0x09, 0x0b,
+ 0x07, 0x0d, 0x61, 0x03, 0xaf, 0x61, 0x03, 0xaf, 0x03d5, 0x03d1, 0x03cd,
+ 0x042d, 0x0431, 0x0436},
+ {
+ 8, 2447, 0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f, 0x09, 0x0b,
+ 0x07, 0x0d, 0x61, 0x03, 0x9f, 0x61, 0x03, 0x9f, 0x03d7, 0x03d3, 0x03cf,
+ 0x042b, 0x042f, 0x0434},
+ {
+ 9, 2452, 0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94, 0x09, 0x0b,
+ 0x07, 0x0d, 0x61, 0x03, 0x8f, 0x61, 0x03, 0x8f, 0x03d9, 0x03d5, 0x03d1,
+ 0x0429, 0x042d, 0x0431},
+ {
+ 10, 2457, 0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99, 0x09, 0x0b,
+ 0x07, 0x0c, 0x61, 0x03, 0x7f, 0x61, 0x03, 0x7f, 0x03db, 0x03d7, 0x03d3,
+ 0x0427, 0x042b, 0x042f},
+ {
+ 11, 2462, 0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e, 0x09, 0x0b,
+ 0x07, 0x0c, 0x61, 0x03, 0x6f, 0x61, 0x03, 0x6f, 0x03dd, 0x03d9, 0x03d5,
+ 0x0424, 0x0429, 0x042d},
+ {
+ 12, 2467, 0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3, 0x09, 0x0b,
+ 0x06, 0x0c, 0x61, 0x03, 0x5f, 0x61, 0x03, 0x5f, 0x03df, 0x03db, 0x03d7,
+ 0x0422, 0x0427, 0x042b},
+ {
+ 13, 2472, 0x70, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa8, 0x09, 0x0a,
+ 0x06, 0x0b, 0x61, 0x03, 0x4f, 0x61, 0x03, 0x4f, 0x03e1, 0x03dd, 0x03d9,
+ 0x0420, 0x0424, 0x0429},
+ {
+ 14, 2484, 0x78, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xb4, 0x09, 0x0a,
+ 0x06, 0x0b, 0x61, 0x03, 0x3f, 0x61, 0x03, 0x3f, 0x03e6, 0x03e2, 0x03de,
+ 0x041b, 0x041f, 0x0424}
+};
+
+static const struct chan_info_nphy_radio2057 chan_info_nphyrev8_2057_rev7[] = {
+ {
+ 184, 4920, 0x68, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xec, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xd3, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07b4, 0x07b0, 0x07ac, 0x0214,
+ 0x0215,
+ 0x0216},
+ {
+ 186, 4930, 0x6b, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xed, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xd3, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07b8, 0x07b4, 0x07b0, 0x0213,
+ 0x0214,
+ 0x0215},
+ {
+ 188, 4940, 0x6e, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xee, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xd3, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07bc, 0x07b8, 0x07b4, 0x0212,
+ 0x0213,
+ 0x0214},
+ {
+ 190, 4950, 0x72, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xef, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07c0, 0x07bc, 0x07b8, 0x0211,
+ 0x0212,
+ 0x0213},
+ {
+ 192, 4960, 0x75, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf0, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07c4, 0x07c0, 0x07bc, 0x020f,
+ 0x0211,
+ 0x0212},
+ {
+ 194, 4970, 0x78, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf1, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07c8, 0x07c4, 0x07c0, 0x020e,
+ 0x020f,
+ 0x0211},
+ {
+ 196, 4980, 0x7c, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf2, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07cc, 0x07c8, 0x07c4, 0x020d,
+ 0x020e,
+ 0x020f},
+ {
+ 198, 4990, 0x7f, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf3, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07d0, 0x07cc, 0x07c8, 0x020c,
+ 0x020d,
+ 0x020e},
+ {
+ 200, 5000, 0x82, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf4, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07d4, 0x07d0, 0x07cc, 0x020b,
+ 0x020c,
+ 0x020d},
+ {
+ 202, 5010, 0x86, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf5, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07d8, 0x07d4, 0x07d0, 0x020a,
+ 0x020b,
+ 0x020c},
+ {
+ 204, 5020, 0x89, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf6, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07dc, 0x07d8, 0x07d4, 0x0209,
+ 0x020a,
+ 0x020b},
+ {
+ 206, 5030, 0x8c, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf7, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07e0, 0x07dc, 0x07d8, 0x0208,
+ 0x0209,
+ 0x020a},
+ {
+ 208, 5040, 0x90, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf8, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07e4, 0x07e0, 0x07dc, 0x0207,
+ 0x0208,
+ 0x0209},
+ {
+ 210, 5050, 0x93, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf9, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07e8, 0x07e4, 0x07e0, 0x0206,
+ 0x0207,
+ 0x0208},
+ {
+ 212, 5060, 0x96, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfa, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07ec, 0x07e8, 0x07e4, 0x0205,
+ 0x0206,
+ 0x0207},
+ {
+ 214, 5070, 0x9a, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfb, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07f0, 0x07ec, 0x07e8, 0x0204,
+ 0x0205,
+ 0x0206},
+ {
+ 216, 5080, 0x9d, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfc, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07f4, 0x07f0, 0x07ec, 0x0203,
+ 0x0204,
+ 0x0205},
+ {
+ 218, 5090, 0xa0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfd, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07f8, 0x07f4, 0x07f0, 0x0202,
+ 0x0203,
+ 0x0204},
+ {
+ 220, 5100, 0xa4, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfe, 0x01, 0x0d,
+ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00,
+ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x07fc, 0x07f8, 0x07f4, 0x0201,
+ 0x0202,
+ 0x0203},
+ {
+ 222, 5110, 0xa7, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xff, 0x01, 0x0d,
+ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00,
+ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0800, 0x07fc, 0x07f8, 0x0200,
+ 0x0201,
+ 0x0202},
+ {
+ 224, 5120, 0xaa, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x00, 0x02, 0x0d,
+ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00,
+ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0804, 0x0800, 0x07fc, 0x01ff,
+ 0x0200,
+ 0x0201},
+ {
+ 226, 5130, 0xae, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x01, 0x02, 0x0d,
+ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00,
+ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0808, 0x0804, 0x0800, 0x01fe,
+ 0x01ff,
+ 0x0200},
+ {
+ 228, 5140, 0xb1, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x02, 0x02, 0x0d,
+ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00,
+ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x080c, 0x0808, 0x0804, 0x01fd,
+ 0x01fe,
+ 0x01ff},
+ {
+ 32, 5160, 0xb8, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x04, 0x02, 0x0d,
+ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00,
+ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0814, 0x0810, 0x080c, 0x01fb,
+ 0x01fc,
+ 0x01fd},
+ {
+ 34, 5170, 0xbb, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x05, 0x02, 0x0d,
+ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00,
+ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0818, 0x0814, 0x0810, 0x01fa,
+ 0x01fb,
+ 0x01fc},
+ {
+ 36, 5180, 0xbe, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x06, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00,
+ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x081c, 0x0818, 0x0814, 0x01f9,
+ 0x01fa,
+ 0x01fb},
+ {
+ 38, 5190, 0xc2, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x07, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00,
+ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0820, 0x081c, 0x0818, 0x01f8,
+ 0x01f9,
+ 0x01fa},
+ {
+ 40, 5200, 0xc5, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x08, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00,
+ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0824, 0x0820, 0x081c, 0x01f7,
+ 0x01f8,
+ 0x01f9},
+ {
+ 42, 5210, 0xc8, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x09, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00,
+ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0828, 0x0824, 0x0820, 0x01f6,
+ 0x01f7,
+ 0x01f8},
+ {
+ 44, 5220, 0xcc, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0a, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00,
+ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x082c, 0x0828, 0x0824, 0x01f5,
+ 0x01f6,
+ 0x01f7},
+ {
+ 46, 5230, 0xcf, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0b, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00,
+ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0830, 0x082c, 0x0828, 0x01f4,
+ 0x01f5,
+ 0x01f6},
+ {
+ 48, 5240, 0xd2, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0c, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00,
+ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0834, 0x0830, 0x082c, 0x01f3,
+ 0x01f4,
+ 0x01f5},
+ {
+ 50, 5250, 0xd6, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0d, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00,
+ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0838, 0x0834, 0x0830, 0x01f2,
+ 0x01f3,
+ 0x01f4},
+ {
+ 52, 5260, 0xd9, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0e, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00,
+ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x083c, 0x0838, 0x0834, 0x01f1,
+ 0x01f2,
+ 0x01f3},
+ {
+ 54, 5270, 0xdc, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0f, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00,
+ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0840, 0x083c, 0x0838, 0x01f0,
+ 0x01f1,
+ 0x01f2},
+ {
+ 56, 5280, 0xe0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x10, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00,
+ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0844, 0x0840, 0x083c, 0x01f0,
+ 0x01f0,
+ 0x01f1},
+ {
+ 58, 5290, 0xe3, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x11, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00,
+ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0848, 0x0844, 0x0840, 0x01ef,
+ 0x01f0,
+ 0x01f0},
+ {
+ 60, 5300, 0xe6, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x12, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00,
+ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x084c, 0x0848, 0x0844, 0x01ee,
+ 0x01ef,
+ 0x01f0},
+ {
+ 62, 5310, 0xea, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x13, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00,
+ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0850, 0x084c, 0x0848, 0x01ed,
+ 0x01ee,
+ 0x01ef},
+ {
+ 64, 5320, 0xed, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x14, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00,
+ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0854, 0x0850, 0x084c, 0x01ec,
+ 0x01ed,
+ 0x01ee},
+ {
+ 66, 5330, 0xf0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x15, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00,
+ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0858, 0x0854, 0x0850, 0x01eb,
+ 0x01ec,
+ 0x01ed},
+ {
+ 68, 5340, 0xf4, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x16, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00,
+ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x085c, 0x0858, 0x0854, 0x01ea,
+ 0x01eb,
+ 0x01ec},
+ {
+ 70, 5350, 0xf7, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x17, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00,
+ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0860, 0x085c, 0x0858, 0x01e9,
+ 0x01ea,
+ 0x01eb},
+ {
+ 72, 5360, 0xfa, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x18, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00,
+ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0864, 0x0860, 0x085c, 0x01e8,
+ 0x01e9,
+ 0x01ea},
+ {
+ 74, 5370, 0xfe, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x19, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00,
+ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0868, 0x0864, 0x0860, 0x01e7,
+ 0x01e8,
+ 0x01e9},
+ {
+ 76, 5380, 0x01, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1a, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00,
+ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x086c, 0x0868, 0x0864, 0x01e6,
+ 0x01e7,
+ 0x01e8},
+ {
+ 78, 5390, 0x04, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1b, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00,
+ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0870, 0x086c, 0x0868, 0x01e5,
+ 0x01e6,
+ 0x01e7},
+ {
+ 80, 5400, 0x08, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1c, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00,
+ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0874, 0x0870, 0x086c, 0x01e5,
+ 0x01e5,
+ 0x01e6},
+ {
+ 82, 5410, 0x0b, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1d, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00,
+ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0878, 0x0874, 0x0870, 0x01e4,
+ 0x01e5,
+ 0x01e5},
+ {
+ 84, 5420, 0x0e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1e, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00,
+ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x087c, 0x0878, 0x0874, 0x01e3,
+ 0x01e4,
+ 0x01e5},
+ {
+ 86, 5430, 0x12, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1f, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00,
+ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0880, 0x087c, 0x0878, 0x01e2,
+ 0x01e3,
+ 0x01e4},
+ {
+ 88, 5440, 0x15, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x20, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00,
+ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0884, 0x0880, 0x087c, 0x01e1,
+ 0x01e2,
+ 0x01e3},
+ {
+ 90, 5450, 0x18, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x21, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00,
+ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0888, 0x0884, 0x0880, 0x01e0,
+ 0x01e1,
+ 0x01e2},
+ {
+ 92, 5460, 0x1c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x22, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00,
+ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x088c, 0x0888, 0x0884, 0x01df,
+ 0x01e0,
+ 0x01e1},
+ {
+ 94, 5470, 0x1f, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x23, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00,
+ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0890, 0x088c, 0x0888, 0x01de,
+ 0x01df,
+ 0x01e0},
+ {
+ 96, 5480, 0x22, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x24, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00,
+ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0894, 0x0890, 0x088c, 0x01dd,
+ 0x01de,
+ 0x01df},
+ {
+ 98, 5490, 0x26, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x25, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00,
+ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0898, 0x0894, 0x0890, 0x01dd,
+ 0x01dd,
+ 0x01de},
+ {
+ 100, 5500, 0x29, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x26, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00,
+ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x089c, 0x0898, 0x0894, 0x01dc,
+ 0x01dd,
+ 0x01dd},
+ {
+ 102, 5510, 0x2c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x27, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00,
+ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08a0, 0x089c, 0x0898, 0x01db,
+ 0x01dc,
+ 0x01dd},
+ {
+ 104, 5520, 0x30, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x28, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00,
+ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08a4, 0x08a0, 0x089c, 0x01da,
+ 0x01db,
+ 0x01dc},
+ {
+ 106, 5530, 0x33, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x29, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00,
+ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08a8, 0x08a4, 0x08a0, 0x01d9,
+ 0x01da,
+ 0x01db},
+ {
+ 108, 5540, 0x36, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2a, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00,
+ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08ac, 0x08a8, 0x08a4, 0x01d8,
+ 0x01d9,
+ 0x01da},
+ {
+ 110, 5550, 0x3a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2b, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00,
+ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08b0, 0x08ac, 0x08a8, 0x01d7,
+ 0x01d8,
+ 0x01d9},
+ {
+ 112, 5560, 0x3d, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2c, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00,
+ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08b4, 0x08b0, 0x08ac, 0x01d7,
+ 0x01d7,
+ 0x01d8},
+ {
+ 114, 5570, 0x40, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2d, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00,
+ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08b8, 0x08b4, 0x08b0, 0x01d6,
+ 0x01d7,
+ 0x01d7},
+ {
+ 116, 5580, 0x44, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2e, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00,
+ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08bc, 0x08b8, 0x08b4, 0x01d5,
+ 0x01d6,
+ 0x01d7},
+ {
+ 118, 5590, 0x47, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2f, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00,
+ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08c0, 0x08bc, 0x08b8, 0x01d4,
+ 0x01d5,
+ 0x01d6},
+ {
+ 120, 5600, 0x4a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x30, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00,
+ 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08c4, 0x08c0, 0x08bc, 0x01d3,
+ 0x01d4,
+ 0x01d5},
+ {
+ 122, 5610, 0x4e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x31, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00,
+ 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08c8, 0x08c4, 0x08c0, 0x01d2,
+ 0x01d3,
+ 0x01d4},
+ {
+ 124, 5620, 0x51, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x32, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00,
+ 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08cc, 0x08c8, 0x08c4, 0x01d2,
+ 0x01d2,
+ 0x01d3},
+ {
+ 126, 5630, 0x54, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x33, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00,
+ 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08d0, 0x08cc, 0x08c8, 0x01d1,
+ 0x01d2,
+ 0x01d2},
+ {
+ 128, 5640, 0x58, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x34, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00,
+ 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08d4, 0x08d0, 0x08cc, 0x01d0,
+ 0x01d1,
+ 0x01d2},
+ {
+ 130, 5650, 0x5b, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x35, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x00,
+ 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x08d8, 0x08d4, 0x08d0, 0x01cf,
+ 0x01d0,
+ 0x01d1},
+ {
+ 132, 5660, 0x5e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x36, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x00,
+ 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x08dc, 0x08d8, 0x08d4, 0x01ce,
+ 0x01cf,
+ 0x01d0},
+ {
+ 134, 5670, 0x62, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x37, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x00,
+ 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x08e0, 0x08dc, 0x08d8, 0x01ce,
+ 0x01ce,
+ 0x01cf},
+ {
+ 136, 5680, 0x65, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x38, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x00,
+ 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x08e4, 0x08e0, 0x08dc, 0x01cd,
+ 0x01ce,
+ 0x01ce},
+ {
+ 138, 5690, 0x68, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x39, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x00,
+ 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x08e8, 0x08e4, 0x08e0, 0x01cc,
+ 0x01cd,
+ 0x01ce},
+ {
+ 140, 5700, 0x6c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3a, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08ec, 0x08e8, 0x08e4, 0x01cb,
+ 0x01cc,
+ 0x01cd},
+ {
+ 142, 5710, 0x6f, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3b, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f0, 0x08ec, 0x08e8, 0x01ca,
+ 0x01cb,
+ 0x01cc},
+ {
+ 144, 5720, 0x72, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3c, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f4, 0x08f0, 0x08ec, 0x01c9,
+ 0x01ca,
+ 0x01cb},
+ {
+ 145, 5725, 0x74, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x79, 0x04, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f6, 0x08f2, 0x08ee, 0x01c9,
+ 0x01ca,
+ 0x01cb},
+ {
+ 146, 5730, 0x76, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3d, 0x02, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f8, 0x08f4, 0x08f0, 0x01c9,
+ 0x01c9,
+ 0x01ca},
+ {
+ 147, 5735, 0x77, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7b, 0x04, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08fa, 0x08f6, 0x08f2, 0x01c8,
+ 0x01c9,
+ 0x01ca},
+ {
+ 148, 5740, 0x79, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3e, 0x02, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08fc, 0x08f8, 0x08f4, 0x01c8,
+ 0x01c9,
+ 0x01c9},
+ {
+ 149, 5745, 0x7b, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7d, 0x04, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08fe, 0x08fa, 0x08f6, 0x01c8,
+ 0x01c8,
+ 0x01c9},
+ {
+ 150, 5750, 0x7c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3f, 0x02, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7,
+ 0x01c8,
+ 0x01c9},
+ {
+ 151, 5755, 0x7e, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7f, 0x04, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7,
+ 0x01c8,
+ 0x01c8},
+ {
+ 152, 5760, 0x80, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x40, 0x02, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6,
+ 0x01c7,
+ 0x01c8},
+ {
+ 153, 5765, 0x81, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x81, 0x04, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6,
+ 0x01c7,
+ 0x01c8},
+ {
+ 154, 5770, 0x83, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x41, 0x02, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6,
+ 0x01c6,
+ 0x01c7},
+ {
+ 155, 5775, 0x85, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x83, 0x04, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5,
+ 0x01c6,
+ 0x01c7},
+ {
+ 156, 5780, 0x86, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x42, 0x02, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5,
+ 0x01c6,
+ 0x01c6},
+ {
+ 157, 5785, 0x88, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x85, 0x04, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4,
+ 0x01c5,
+ 0x01c6},
+ {
+ 158, 5790, 0x8a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x43, 0x02, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4,
+ 0x01c5,
+ 0x01c6},
+ {
+ 159, 5795, 0x8b, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x87, 0x04, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4,
+ 0x01c4,
+ 0x01c5},
+ {
+ 160, 5800, 0x8d, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x44, 0x02, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x01, 0x03, 0x00, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3,
+ 0x01c4,
+ 0x01c5},
+ {
+ 161, 5805, 0x8f, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x89, 0x04, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3,
+ 0x01c4,
+ 0x01c4},
+ {
+ 162, 5810, 0x90, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x45, 0x02, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2,
+ 0x01c3,
+ 0x01c4},
+ {
+ 163, 5815, 0x92, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x8b, 0x04, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2,
+ 0x01c3,
+ 0x01c4},
+ {
+ 164, 5820, 0x94, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x46, 0x02, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2,
+ 0x01c2,
+ 0x01c3},
+ {
+ 165, 5825, 0x95, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x8d, 0x04, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1,
+ 0x01c2,
+ 0x01c3},
+ {
+ 166, 5830, 0x97, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x47, 0x02, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1,
+ 0x01c2,
+ 0x01c2},
+ {
+ 168, 5840, 0x9a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x48, 0x02, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0,
+ 0x01c1,
+ 0x01c2},
+ {
+ 170, 5850, 0x9e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x49, 0x02, 0x04,
+ 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf,
+ 0x01c0,
+ 0x01c1},
+ {
+ 172, 5860, 0xa1, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4a, 0x02, 0x04,
+ 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf,
+ 0x01bf,
+ 0x01c0},
+ {
+ 174, 5870, 0xa4, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4b, 0x02, 0x04,
+ 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0930, 0x092c, 0x0928, 0x01be,
+ 0x01bf,
+ 0x01bf},
+ {
+ 176, 5880, 0xa8, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4c, 0x02, 0x03,
+ 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd,
+ 0x01be,
+ 0x01bf},
+ {
+ 178, 5890, 0xab, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4d, 0x02, 0x03,
+ 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc,
+ 0x01bd,
+ 0x01be},
+ {
+ 180, 5900, 0xae, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4e, 0x02, 0x03,
+ 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc,
+ 0x01bc,
+ 0x01bd},
+ {
+ 1, 2412, 0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, 0x09, 0x0f,
+ 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03c9, 0x03c5, 0x03c1, 0x043a,
+ 0x043f,
+ 0x0443},
+ {
+ 2, 2417, 0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71, 0x09, 0x0f,
+ 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cb, 0x03c7, 0x03c3, 0x0438,
+ 0x043d,
+ 0x0441},
+ {
+ 3, 2422, 0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76, 0x09, 0x0f,
+ 0x09, 0x00, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cd, 0x03c9, 0x03c5, 0x0436,
+ 0x043a,
+ 0x043f},
+ {
+ 4, 2427, 0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b, 0x09, 0x0f,
+ 0x09, 0x00, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cf, 0x03cb, 0x03c7, 0x0434,
+ 0x0438,
+ 0x043d},
+ {
+ 5, 2432, 0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80, 0x09, 0x0f,
+ 0x08, 0x00, 0x08, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d1, 0x03cd, 0x03c9, 0x0431,
+ 0x0436,
+ 0x043a},
+ {
+ 6, 2437, 0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85, 0x09, 0x0f,
+ 0x08, 0x00, 0x08, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d3, 0x03cf, 0x03cb, 0x042f,
+ 0x0434,
+ 0x0438},
+ {
+ 7, 2442, 0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a, 0x09, 0x0f,
+ 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d5, 0x03d1, 0x03cd, 0x042d,
+ 0x0431,
+ 0x0436},
+ {
+ 8, 2447, 0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f, 0x09, 0x0f,
+ 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d7, 0x03d3, 0x03cf, 0x042b,
+ 0x042f,
+ 0x0434},
+ {
+ 9, 2452, 0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94, 0x09, 0x0f,
+ 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d9, 0x03d5, 0x03d1, 0x0429,
+ 0x042d,
+ 0x0431},
+ {
+ 10, 2457, 0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99, 0x09, 0x0f,
+ 0x06, 0x00, 0x06, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03db, 0x03d7, 0x03d3, 0x0427,
+ 0x042b,
+ 0x042f},
+ {
+ 11, 2462, 0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e, 0x09, 0x0f,
+ 0x06, 0x00, 0x06, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03dd, 0x03d9, 0x03d5, 0x0424,
+ 0x0429,
+ 0x042d},
+ {
+ 12, 2467, 0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3, 0x09, 0x0f,
+ 0x05, 0x00, 0x05, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03df, 0x03db, 0x03d7, 0x0422,
+ 0x0427,
+ 0x042b},
+ {
+ 13, 2472, 0x70, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa8, 0x09, 0x0f,
+ 0x05, 0x00, 0x05, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03e1, 0x03dd, 0x03d9, 0x0420,
+ 0x0424,
+ 0x0429},
+ {
+ 14, 2484, 0x78, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xb4, 0x09, 0x0f,
+ 0x04, 0x00, 0x04, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x03e6, 0x03e2, 0x03de, 0x041b,
+ 0x041f,
+ 0x0424}
+};
+
+static const struct chan_info_nphy_radio2057 chan_info_nphyrev8_2057_rev8[] = {
+ {
+ 186, 4930, 0x6b, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xed, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xd3, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07b8, 0x07b4, 0x07b0, 0x0213,
+ 0x0214,
+ 0x0215},
+ {
+ 188, 4940, 0x6e, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xee, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0xd3, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07bc, 0x07b8, 0x07b4, 0x0212,
+ 0x0213,
+ 0x0214},
+ {
+ 190, 4950, 0x72, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xef, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07c0, 0x07bc, 0x07b8, 0x0211,
+ 0x0212,
+ 0x0213},
+ {
+ 192, 4960, 0x75, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf0, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07c4, 0x07c0, 0x07bc, 0x020f,
+ 0x0211,
+ 0x0212},
+ {
+ 194, 4970, 0x78, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf1, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07c8, 0x07c4, 0x07c0, 0x020e,
+ 0x020f,
+ 0x0211},
+ {
+ 196, 4980, 0x7c, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf2, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07cc, 0x07c8, 0x07c4, 0x020d,
+ 0x020e,
+ 0x020f},
+ {
+ 198, 4990, 0x7f, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf3, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07d0, 0x07cc, 0x07c8, 0x020c,
+ 0x020d,
+ 0x020e},
+ {
+ 200, 5000, 0x82, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf4, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07d4, 0x07d0, 0x07cc, 0x020b,
+ 0x020c,
+ 0x020d},
+ {
+ 202, 5010, 0x86, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf5, 0x01, 0x0f,
+ 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07d8, 0x07d4, 0x07d0, 0x020a,
+ 0x020b,
+ 0x020c},
+ {
+ 204, 5020, 0x89, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf6, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07dc, 0x07d8, 0x07d4, 0x0209,
+ 0x020a,
+ 0x020b},
+ {
+ 206, 5030, 0x8c, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf7, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07e0, 0x07dc, 0x07d8, 0x0208,
+ 0x0209,
+ 0x020a},
+ {
+ 208, 5040, 0x90, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf8, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07e4, 0x07e0, 0x07dc, 0x0207,
+ 0x0208,
+ 0x0209},
+ {
+ 210, 5050, 0x93, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf9, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07e8, 0x07e4, 0x07e0, 0x0206,
+ 0x0207,
+ 0x0208},
+ {
+ 212, 5060, 0x96, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfa, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07ec, 0x07e8, 0x07e4, 0x0205,
+ 0x0206,
+ 0x0207},
+ {
+ 214, 5070, 0x9a, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfb, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07f0, 0x07ec, 0x07e8, 0x0204,
+ 0x0205,
+ 0x0206},
+ {
+ 216, 5080, 0x9d, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfc, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07f4, 0x07f0, 0x07ec, 0x0203,
+ 0x0204,
+ 0x0205},
+ {
+ 218, 5090, 0xa0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfd, 0x01, 0x0e,
+ 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00,
+ 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07f8, 0x07f4, 0x07f0, 0x0202,
+ 0x0203,
+ 0x0204},
+ {
+ 220, 5100, 0xa4, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfe, 0x01, 0x0d,
+ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00,
+ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x07fc, 0x07f8, 0x07f4, 0x0201,
+ 0x0202,
+ 0x0203},
+ {
+ 222, 5110, 0xa7, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xff, 0x01, 0x0d,
+ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00,
+ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0800, 0x07fc, 0x07f8, 0x0200,
+ 0x0201,
+ 0x0202},
+ {
+ 224, 5120, 0xaa, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x00, 0x02, 0x0d,
+ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00,
+ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0804, 0x0800, 0x07fc, 0x01ff,
+ 0x0200,
+ 0x0201},
+ {
+ 226, 5130, 0xae, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x01, 0x02, 0x0d,
+ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00,
+ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0808, 0x0804, 0x0800, 0x01fe,
+ 0x01ff,
+ 0x0200},
+ {
+ 228, 5140, 0xb1, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x02, 0x02, 0x0d,
+ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00,
+ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x080c, 0x0808, 0x0804, 0x01fd,
+ 0x01fe,
+ 0x01ff},
+ {
+ 32, 5160, 0xb8, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x04, 0x02, 0x0d,
+ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00,
+ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0814, 0x0810, 0x080c, 0x01fb,
+ 0x01fc,
+ 0x01fd},
+ {
+ 34, 5170, 0xbb, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x05, 0x02, 0x0d,
+ 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00,
+ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0818, 0x0814, 0x0810, 0x01fa,
+ 0x01fb,
+ 0x01fc},
+ {
+ 36, 5180, 0xbe, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x06, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00,
+ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x081c, 0x0818, 0x0814, 0x01f9,
+ 0x01fa,
+ 0x01fb},
+ {
+ 38, 5190, 0xc2, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x07, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00,
+ 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0820, 0x081c, 0x0818, 0x01f8,
+ 0x01f9,
+ 0x01fa},
+ {
+ 40, 5200, 0xc5, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x08, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00,
+ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0824, 0x0820, 0x081c, 0x01f7,
+ 0x01f8,
+ 0x01f9},
+ {
+ 42, 5210, 0xc8, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x09, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00,
+ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0828, 0x0824, 0x0820, 0x01f6,
+ 0x01f7,
+ 0x01f8},
+ {
+ 44, 5220, 0xcc, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0a, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00,
+ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x082c, 0x0828, 0x0824, 0x01f5,
+ 0x01f6,
+ 0x01f7},
+ {
+ 46, 5230, 0xcf, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0b, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00,
+ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0830, 0x082c, 0x0828, 0x01f4,
+ 0x01f5,
+ 0x01f6},
+ {
+ 48, 5240, 0xd2, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0c, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00,
+ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0834, 0x0830, 0x082c, 0x01f3,
+ 0x01f4,
+ 0x01f5},
+ {
+ 50, 5250, 0xd6, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0d, 0x02, 0x0c,
+ 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00,
+ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0838, 0x0834, 0x0830, 0x01f2,
+ 0x01f3,
+ 0x01f4},
+ {
+ 52, 5260, 0xd9, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0e, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00,
+ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x083c, 0x0838, 0x0834, 0x01f1,
+ 0x01f2,
+ 0x01f3},
+ {
+ 54, 5270, 0xdc, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0f, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00,
+ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0840, 0x083c, 0x0838, 0x01f0,
+ 0x01f1,
+ 0x01f2},
+ {
+ 56, 5280, 0xe0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x10, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00,
+ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0844, 0x0840, 0x083c, 0x01f0,
+ 0x01f0,
+ 0x01f1},
+ {
+ 58, 5290, 0xe3, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x11, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00,
+ 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0848, 0x0844, 0x0840, 0x01ef,
+ 0x01f0,
+ 0x01f0},
+ {
+ 60, 5300, 0xe6, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x12, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00,
+ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x084c, 0x0848, 0x0844, 0x01ee,
+ 0x01ef,
+ 0x01f0},
+ {
+ 62, 5310, 0xea, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x13, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00,
+ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0850, 0x084c, 0x0848, 0x01ed,
+ 0x01ee,
+ 0x01ef},
+ {
+ 64, 5320, 0xed, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x14, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00,
+ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0854, 0x0850, 0x084c, 0x01ec,
+ 0x01ed,
+ 0x01ee},
+ {
+ 66, 5330, 0xf0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x15, 0x02, 0x0b,
+ 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00,
+ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0858, 0x0854, 0x0850, 0x01eb,
+ 0x01ec,
+ 0x01ed},
+ {
+ 68, 5340, 0xf4, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x16, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00,
+ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x085c, 0x0858, 0x0854, 0x01ea,
+ 0x01eb,
+ 0x01ec},
+ {
+ 70, 5350, 0xf7, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x17, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00,
+ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0860, 0x085c, 0x0858, 0x01e9,
+ 0x01ea,
+ 0x01eb},
+ {
+ 72, 5360, 0xfa, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x18, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00,
+ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0864, 0x0860, 0x085c, 0x01e8,
+ 0x01e9,
+ 0x01ea},
+ {
+ 74, 5370, 0xfe, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x19, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00,
+ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0868, 0x0864, 0x0860, 0x01e7,
+ 0x01e8,
+ 0x01e9},
+ {
+ 76, 5380, 0x01, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1a, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00,
+ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x086c, 0x0868, 0x0864, 0x01e6,
+ 0x01e7,
+ 0x01e8},
+ {
+ 78, 5390, 0x04, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1b, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00,
+ 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0870, 0x086c, 0x0868, 0x01e5,
+ 0x01e6,
+ 0x01e7},
+ {
+ 80, 5400, 0x08, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1c, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00,
+ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0874, 0x0870, 0x086c, 0x01e5,
+ 0x01e5,
+ 0x01e6},
+ {
+ 82, 5410, 0x0b, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1d, 0x02, 0x0a,
+ 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00,
+ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0878, 0x0874, 0x0870, 0x01e4,
+ 0x01e5,
+ 0x01e5},
+ {
+ 84, 5420, 0x0e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1e, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00,
+ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x087c, 0x0878, 0x0874, 0x01e3,
+ 0x01e4,
+ 0x01e5},
+ {
+ 86, 5430, 0x12, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1f, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00,
+ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0880, 0x087c, 0x0878, 0x01e2,
+ 0x01e3,
+ 0x01e4},
+ {
+ 88, 5440, 0x15, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x20, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00,
+ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0884, 0x0880, 0x087c, 0x01e1,
+ 0x01e2,
+ 0x01e3},
+ {
+ 90, 5450, 0x18, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x21, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00,
+ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0888, 0x0884, 0x0880, 0x01e0,
+ 0x01e1,
+ 0x01e2},
+ {
+ 92, 5460, 0x1c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x22, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00,
+ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x088c, 0x0888, 0x0884, 0x01df,
+ 0x01e0,
+ 0x01e1},
+ {
+ 94, 5470, 0x1f, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x23, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00,
+ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0890, 0x088c, 0x0888, 0x01de,
+ 0x01df,
+ 0x01e0},
+ {
+ 96, 5480, 0x22, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x24, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00,
+ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0894, 0x0890, 0x088c, 0x01dd,
+ 0x01de,
+ 0x01df},
+ {
+ 98, 5490, 0x26, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x25, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00,
+ 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0898, 0x0894, 0x0890, 0x01dd,
+ 0x01dd,
+ 0x01de},
+ {
+ 100, 5500, 0x29, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x26, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00,
+ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x089c, 0x0898, 0x0894, 0x01dc,
+ 0x01dd,
+ 0x01dd},
+ {
+ 102, 5510, 0x2c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x27, 0x02, 0x09,
+ 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00,
+ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08a0, 0x089c, 0x0898, 0x01db,
+ 0x01dc,
+ 0x01dd},
+ {
+ 104, 5520, 0x30, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x28, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00,
+ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08a4, 0x08a0, 0x089c, 0x01da,
+ 0x01db,
+ 0x01dc},
+ {
+ 106, 5530, 0x33, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x29, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00,
+ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08a8, 0x08a4, 0x08a0, 0x01d9,
+ 0x01da,
+ 0x01db},
+ {
+ 108, 5540, 0x36, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2a, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00,
+ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08ac, 0x08a8, 0x08a4, 0x01d8,
+ 0x01d9,
+ 0x01da},
+ {
+ 110, 5550, 0x3a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2b, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00,
+ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08b0, 0x08ac, 0x08a8, 0x01d7,
+ 0x01d8,
+ 0x01d9},
+ {
+ 112, 5560, 0x3d, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2c, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00,
+ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08b4, 0x08b0, 0x08ac, 0x01d7,
+ 0x01d7,
+ 0x01d8},
+ {
+ 114, 5570, 0x40, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2d, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00,
+ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08b8, 0x08b4, 0x08b0, 0x01d6,
+ 0x01d7,
+ 0x01d7},
+ {
+ 116, 5580, 0x44, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2e, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00,
+ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08bc, 0x08b8, 0x08b4, 0x01d5,
+ 0x01d6,
+ 0x01d7},
+ {
+ 118, 5590, 0x47, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2f, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00,
+ 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08c0, 0x08bc, 0x08b8, 0x01d4,
+ 0x01d5,
+ 0x01d6},
+ {
+ 120, 5600, 0x4a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x30, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00,
+ 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08c4, 0x08c0, 0x08bc, 0x01d3,
+ 0x01d4,
+ 0x01d5},
+ {
+ 122, 5610, 0x4e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x31, 0x02, 0x08,
+ 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00,
+ 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08c8, 0x08c4, 0x08c0, 0x01d2,
+ 0x01d3,
+ 0x01d4},
+ {
+ 124, 5620, 0x51, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x32, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00,
+ 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08cc, 0x08c8, 0x08c4, 0x01d2,
+ 0x01d2,
+ 0x01d3},
+ {
+ 126, 5630, 0x54, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x33, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00,
+ 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08d0, 0x08cc, 0x08c8, 0x01d1,
+ 0x01d2,
+ 0x01d2},
+ {
+ 128, 5640, 0x58, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x34, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00,
+ 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08d4, 0x08d0, 0x08cc, 0x01d0,
+ 0x01d1,
+ 0x01d2},
+ {
+ 130, 5650, 0x5b, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x35, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x00,
+ 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x08d8, 0x08d4, 0x08d0, 0x01cf,
+ 0x01d0,
+ 0x01d1},
+ {
+ 132, 5660, 0x5e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x36, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x00,
+ 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x08dc, 0x08d8, 0x08d4, 0x01ce,
+ 0x01cf,
+ 0x01d0},
+ {
+ 134, 5670, 0x62, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x37, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x00,
+ 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x08e0, 0x08dc, 0x08d8, 0x01ce,
+ 0x01ce,
+ 0x01cf},
+ {
+ 136, 5680, 0x65, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x38, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x00,
+ 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x08e4, 0x08e0, 0x08dc, 0x01cd,
+ 0x01ce,
+ 0x01ce},
+ {
+ 138, 5690, 0x68, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x39, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x00,
+ 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x08e8, 0x08e4, 0x08e0, 0x01cc,
+ 0x01cd,
+ 0x01ce},
+ {
+ 140, 5700, 0x6c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3a, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08ec, 0x08e8, 0x08e4, 0x01cb,
+ 0x01cc,
+ 0x01cd},
+ {
+ 142, 5710, 0x6f, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3b, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f0, 0x08ec, 0x08e8, 0x01ca,
+ 0x01cb,
+ 0x01cc},
+ {
+ 144, 5720, 0x72, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3c, 0x02, 0x07,
+ 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f4, 0x08f0, 0x08ec, 0x01c9,
+ 0x01ca,
+ 0x01cb},
+ {
+ 145, 5725, 0x74, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x79, 0x04, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f6, 0x08f2, 0x08ee, 0x01c9,
+ 0x01ca,
+ 0x01cb},
+ {
+ 146, 5730, 0x76, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3d, 0x02, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f8, 0x08f4, 0x08f0, 0x01c9,
+ 0x01c9,
+ 0x01ca},
+ {
+ 147, 5735, 0x77, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7b, 0x04, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08fa, 0x08f6, 0x08f2, 0x01c8,
+ 0x01c9,
+ 0x01ca},
+ {
+ 148, 5740, 0x79, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3e, 0x02, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08fc, 0x08f8, 0x08f4, 0x01c8,
+ 0x01c9,
+ 0x01c9},
+ {
+ 149, 5745, 0x7b, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7d, 0x04, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08fe, 0x08fa, 0x08f6, 0x01c8,
+ 0x01c8,
+ 0x01c9},
+ {
+ 150, 5750, 0x7c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3f, 0x02, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7,
+ 0x01c8,
+ 0x01c9},
+ {
+ 151, 5755, 0x7e, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7f, 0x04, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7,
+ 0x01c8,
+ 0x01c8},
+ {
+ 152, 5760, 0x80, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x40, 0x02, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6,
+ 0x01c7,
+ 0x01c8},
+ {
+ 153, 5765, 0x81, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x81, 0x04, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6,
+ 0x01c7,
+ 0x01c8},
+ {
+ 154, 5770, 0x83, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x41, 0x02, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6,
+ 0x01c6,
+ 0x01c7},
+ {
+ 155, 5775, 0x85, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x83, 0x04, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5,
+ 0x01c6,
+ 0x01c7},
+ {
+ 156, 5780, 0x86, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x42, 0x02, 0x06,
+ 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5,
+ 0x01c6,
+ 0x01c6},
+ {
+ 157, 5785, 0x88, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x85, 0x04, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4,
+ 0x01c5,
+ 0x01c6},
+ {
+ 158, 5790, 0x8a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x43, 0x02, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4,
+ 0x01c5,
+ 0x01c6},
+ {
+ 159, 5795, 0x8b, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x87, 0x04, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4,
+ 0x01c4,
+ 0x01c5},
+ {
+ 160, 5800, 0x8d, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x44, 0x02, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x01, 0x03, 0x00, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3,
+ 0x01c4,
+ 0x01c5},
+ {
+ 161, 5805, 0x8f, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x89, 0x04, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3,
+ 0x01c4,
+ 0x01c4},
+ {
+ 162, 5810, 0x90, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x45, 0x02, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2,
+ 0x01c3,
+ 0x01c4},
+ {
+ 163, 5815, 0x92, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x8b, 0x04, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2,
+ 0x01c3,
+ 0x01c4},
+ {
+ 164, 5820, 0x94, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x46, 0x02, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2,
+ 0x01c2,
+ 0x01c3},
+ {
+ 165, 5825, 0x95, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x8d, 0x04, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1,
+ 0x01c2,
+ 0x01c3},
+ {
+ 166, 5830, 0x97, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x47, 0x02, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1,
+ 0x01c2,
+ 0x01c2},
+ {
+ 168, 5840, 0x9a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x48, 0x02, 0x05,
+ 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0,
+ 0x01c1,
+ 0x01c2},
+ {
+ 170, 5850, 0x9e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x49, 0x02, 0x04,
+ 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf,
+ 0x01c0,
+ 0x01c1},
+ {
+ 172, 5860, 0xa1, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4a, 0x02, 0x04,
+ 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf,
+ 0x01bf,
+ 0x01c0},
+ {
+ 174, 5870, 0xa4, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4b, 0x02, 0x04,
+ 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0930, 0x092c, 0x0928, 0x01be,
+ 0x01bf,
+ 0x01bf},
+ {
+ 176, 5880, 0xa8, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4c, 0x02, 0x03,
+ 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd,
+ 0x01be,
+ 0x01bf},
+ {
+ 178, 5890, 0xab, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4d, 0x02, 0x03,
+ 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc,
+ 0x01bd,
+ 0x01be},
+ {
+ 180, 5900, 0xae, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4e, 0x02, 0x03,
+ 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc,
+ 0x01bc,
+ 0x01bd},
+ {
+ 1, 2412, 0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, 0x09, 0x0f,
+ 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03c9, 0x03c5, 0x03c1, 0x043a,
+ 0x043f,
+ 0x0443},
+ {
+ 2, 2417, 0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71, 0x09, 0x0f,
+ 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cb, 0x03c7, 0x03c3, 0x0438,
+ 0x043d,
+ 0x0441},
+ {
+ 3, 2422, 0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76, 0x09, 0x0f,
+ 0x09, 0x00, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cd, 0x03c9, 0x03c5, 0x0436,
+ 0x043a,
+ 0x043f},
+ {
+ 4, 2427, 0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b, 0x09, 0x0f,
+ 0x09, 0x00, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cf, 0x03cb, 0x03c7, 0x0434,
+ 0x0438,
+ 0x043d},
+ {
+ 5, 2432, 0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80, 0x09, 0x0f,
+ 0x08, 0x00, 0x08, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d1, 0x03cd, 0x03c9, 0x0431,
+ 0x0436,
+ 0x043a},
+ {
+ 6, 2437, 0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85, 0x09, 0x0f,
+ 0x08, 0x00, 0x08, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d3, 0x03cf, 0x03cb, 0x042f,
+ 0x0434,
+ 0x0438},
+ {
+ 7, 2442, 0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a, 0x09, 0x0f,
+ 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d5, 0x03d1, 0x03cd, 0x042d,
+ 0x0431,
+ 0x0436},
+ {
+ 8, 2447, 0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f, 0x09, 0x0f,
+ 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d7, 0x03d3, 0x03cf, 0x042b,
+ 0x042f,
+ 0x0434},
+ {
+ 9, 2452, 0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94, 0x09, 0x0f,
+ 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d9, 0x03d5, 0x03d1, 0x0429,
+ 0x042d,
+ 0x0431},
+ {
+ 10, 2457, 0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99, 0x09, 0x0f,
+ 0x06, 0x00, 0x06, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03db, 0x03d7, 0x03d3, 0x0427,
+ 0x042b,
+ 0x042f},
+ {
+ 11, 2462, 0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e, 0x09, 0x0f,
+ 0x06, 0x00, 0x06, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03dd, 0x03d9, 0x03d5, 0x0424,
+ 0x0429,
+ 0x042d},
+ {
+ 12, 2467, 0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3, 0x09, 0x0f,
+ 0x05, 0x00, 0x05, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03df, 0x03db, 0x03d7, 0x0422,
+ 0x0427,
+ 0x042b},
+ {
+ 13, 2472, 0x70, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa8, 0x09, 0x0f,
+ 0x05, 0x00, 0x05, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03e1, 0x03dd, 0x03d9, 0x0420,
+ 0x0424,
+ 0x0429},
+ {
+ 14, 2484, 0x78, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xb4, 0x09, 0x0f,
+ 0x04, 0x00, 0x04, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x61,
+ 0x73, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x03e6, 0x03e2, 0x03de, 0x041b,
+ 0x041f,
+ 0x0424}
+};
+
+static struct radio_regs regs_2055[] = {
+ {0x02, 0x80, 0x80, 0, 0},
+ {0x03, 0, 0, 0, 0},
+ {0x04, 0x27, 0x27, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0x27, 0x27, 0, 0},
+ {0x07, 0x7f, 0x7f, 1, 1},
+ {0x08, 0x7, 0x7, 1, 1},
+ {0x09, 0x7f, 0x7f, 1, 1},
+ {0x0A, 0x7, 0x7, 1, 1},
+ {0x0B, 0x15, 0x15, 0, 0},
+ {0x0C, 0x15, 0x15, 0, 0},
+ {0x0D, 0x4f, 0x4f, 1, 1},
+ {0x0E, 0x5, 0x5, 1, 1},
+ {0x0F, 0x4f, 0x4f, 1, 1},
+ {0x10, 0x5, 0x5, 1, 1},
+ {0x11, 0xd0, 0xd0, 0, 0},
+ {0x12, 0x2, 0x2, 0, 0},
+ {0x13, 0, 0, 0, 0},
+ {0x14, 0x40, 0x40, 0, 0},
+ {0x15, 0, 0, 0, 0},
+ {0x16, 0, 0, 0, 0},
+ {0x17, 0, 0, 0, 0},
+ {0x18, 0, 0, 0, 0},
+ {0x19, 0, 0, 0, 0},
+ {0x1A, 0, 0, 0, 0},
+ {0x1B, 0, 0, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0xc0, 0xc0, 0, 0},
+ {0x1E, 0xff, 0xff, 0, 0},
+ {0x1F, 0xc0, 0xc0, 0, 0},
+ {0x20, 0xff, 0xff, 0, 0},
+ {0x21, 0xc0, 0xc0, 0, 0},
+ {0x22, 0, 0, 0, 0},
+ {0x23, 0x2c, 0x2c, 0, 0},
+ {0x24, 0, 0, 0, 0},
+ {0x25, 0, 0, 0, 0},
+ {0x26, 0, 0, 0, 0},
+ {0x27, 0, 0, 0, 0},
+ {0x28, 0, 0, 0, 0},
+ {0x29, 0, 0, 0, 0},
+ {0x2A, 0, 0, 0, 0},
+ {0x2B, 0, 0, 0, 0},
+ {0x2C, 0, 0, 0, 0},
+ {0x2D, 0xa4, 0xa4, 0, 0},
+ {0x2E, 0x38, 0x38, 0, 0},
+ {0x2F, 0, 0, 0, 0},
+ {0x30, 0x4, 0x4, 1, 1},
+ {0x31, 0, 0, 0, 0},
+ {0x32, 0xa, 0xa, 0, 0},
+ {0x33, 0x87, 0x87, 0, 0},
+ {0x34, 0x9, 0x9, 0, 0},
+ {0x35, 0x70, 0x70, 0, 0},
+ {0x36, 0x11, 0x11, 0, 0},
+ {0x37, 0x18, 0x18, 1, 1},
+ {0x38, 0x6, 0x6, 0, 0},
+ {0x39, 0x4, 0x4, 1, 1},
+ {0x3A, 0x6, 0x6, 0, 0},
+ {0x3B, 0x9e, 0x9e, 0, 0},
+ {0x3C, 0x9, 0x9, 0, 0},
+ {0x3D, 0xc8, 0xc8, 1, 1},
+ {0x3E, 0x88, 0x88, 0, 0},
+ {0x3F, 0, 0, 0, 0},
+ {0x40, 0, 0, 0, 0},
+ {0x41, 0, 0, 0, 0},
+ {0x42, 0x1, 0x1, 0, 0},
+ {0x43, 0x2, 0x2, 0, 0},
+ {0x44, 0x96, 0x96, 0, 0},
+ {0x45, 0x3e, 0x3e, 0, 0},
+ {0x46, 0x3e, 0x3e, 0, 0},
+ {0x47, 0x13, 0x13, 0, 0},
+ {0x48, 0x2, 0x2, 0, 0},
+ {0x49, 0x15, 0x15, 0, 0},
+ {0x4A, 0x7, 0x7, 0, 0},
+ {0x4B, 0, 0, 0, 0},
+ {0x4C, 0, 0, 0, 0},
+ {0x4D, 0, 0, 0, 0},
+ {0x4E, 0, 0, 0, 0},
+ {0x4F, 0, 0, 0, 0},
+ {0x50, 0x8, 0x8, 0, 0},
+ {0x51, 0x8, 0x8, 0, 0},
+ {0x52, 0x6, 0x6, 0, 0},
+ {0x53, 0x84, 0x84, 1, 1},
+ {0x54, 0xc3, 0xc3, 0, 0},
+ {0x55, 0x8f, 0x8f, 0, 0},
+ {0x56, 0xff, 0xff, 0, 0},
+ {0x57, 0xff, 0xff, 0, 0},
+ {0x58, 0x88, 0x88, 0, 0},
+ {0x59, 0x88, 0x88, 0, 0},
+ {0x5A, 0, 0, 0, 0},
+ {0x5B, 0xcc, 0xcc, 0, 0},
+ {0x5C, 0x6, 0x6, 0, 0},
+ {0x5D, 0x80, 0x80, 0, 0},
+ {0x5E, 0x80, 0x80, 0, 0},
+ {0x5F, 0xf8, 0xf8, 0, 0},
+ {0x60, 0x88, 0x88, 0, 0},
+ {0x61, 0x88, 0x88, 0, 0},
+ {0x62, 0x88, 0x8, 1, 1},
+ {0x63, 0x88, 0x88, 0, 0},
+ {0x64, 0, 0, 0, 0},
+ {0x65, 0x1, 0x1, 1, 1},
+ {0x66, 0x8a, 0x8a, 0, 0},
+ {0x67, 0x8, 0x8, 0, 0},
+ {0x68, 0x83, 0x83, 0, 0},
+ {0x69, 0x6, 0x6, 0, 0},
+ {0x6A, 0xa0, 0xa0, 0, 0},
+ {0x6B, 0xa, 0xa, 0, 0},
+ {0x6C, 0x87, 0x87, 1, 1},
+ {0x6D, 0x2a, 0x2a, 0, 0},
+ {0x6E, 0x2a, 0x2a, 0, 0},
+ {0x6F, 0x2a, 0x2a, 0, 0},
+ {0x70, 0x2a, 0x2a, 0, 0},
+ {0x71, 0x18, 0x18, 0, 0},
+ {0x72, 0x6a, 0x6a, 1, 1},
+ {0x73, 0xab, 0xab, 1, 1},
+ {0x74, 0x13, 0x13, 1, 1},
+ {0x75, 0xc1, 0xc1, 1, 1},
+ {0x76, 0xaa, 0xaa, 1, 1},
+ {0x77, 0x87, 0x87, 1, 1},
+ {0x78, 0, 0, 0, 0},
+ {0x79, 0x6, 0x6, 0, 0},
+ {0x7A, 0x7, 0x7, 0, 0},
+ {0x7B, 0x7, 0x7, 0, 0},
+ {0x7C, 0x15, 0x15, 0, 0},
+ {0x7D, 0x55, 0x55, 0, 0},
+ {0x7E, 0x97, 0x97, 1, 1},
+ {0x7F, 0x8, 0x8, 0, 0},
+ {0x80, 0x14, 0x14, 1, 1},
+ {0x81, 0x33, 0x33, 0, 0},
+ {0x82, 0x88, 0x88, 0, 0},
+ {0x83, 0x6, 0x6, 0, 0},
+ {0x84, 0x3, 0x3, 1, 1},
+ {0x85, 0xa, 0xa, 0, 0},
+ {0x86, 0x3, 0x3, 1, 1},
+ {0x87, 0x2a, 0x2a, 0, 0},
+ {0x88, 0xa4, 0xa4, 0, 0},
+ {0x89, 0x18, 0x18, 0, 0},
+ {0x8A, 0x28, 0x28, 0, 0},
+ {0x8B, 0, 0, 0, 0},
+ {0x8C, 0x4a, 0x4a, 0, 0},
+ {0x8D, 0, 0, 0, 0},
+ {0x8E, 0xf8, 0xf8, 0, 0},
+ {0x8F, 0x88, 0x88, 0, 0},
+ {0x90, 0x88, 0x88, 0, 0},
+ {0x91, 0x88, 0x8, 1, 1},
+ {0x92, 0x88, 0x88, 0, 0},
+ {0x93, 0, 0, 0, 0},
+ {0x94, 0x1, 0x1, 1, 1},
+ {0x95, 0x8a, 0x8a, 0, 0},
+ {0x96, 0x8, 0x8, 0, 0},
+ {0x97, 0x83, 0x83, 0, 0},
+ {0x98, 0x6, 0x6, 0, 0},
+ {0x99, 0xa0, 0xa0, 0, 0},
+ {0x9A, 0xa, 0xa, 0, 0},
+ {0x9B, 0x87, 0x87, 1, 1},
+ {0x9C, 0x2a, 0x2a, 0, 0},
+ {0x9D, 0x2a, 0x2a, 0, 0},
+ {0x9E, 0x2a, 0x2a, 0, 0},
+ {0x9F, 0x2a, 0x2a, 0, 0},
+ {0xA0, 0x18, 0x18, 0, 0},
+ {0xA1, 0x6a, 0x6a, 1, 1},
+ {0xA2, 0xab, 0xab, 1, 1},
+ {0xA3, 0x13, 0x13, 1, 1},
+ {0xA4, 0xc1, 0xc1, 1, 1},
+ {0xA5, 0xaa, 0xaa, 1, 1},
+ {0xA6, 0x87, 0x87, 1, 1},
+ {0xA7, 0, 0, 0, 0},
+ {0xA8, 0x6, 0x6, 0, 0},
+ {0xA9, 0x7, 0x7, 0, 0},
+ {0xAA, 0x7, 0x7, 0, 0},
+ {0xAB, 0x15, 0x15, 0, 0},
+ {0xAC, 0x55, 0x55, 0, 0},
+ {0xAD, 0x97, 0x97, 1, 1},
+ {0xAE, 0x8, 0x8, 0, 0},
+ {0xAF, 0x14, 0x14, 1, 1},
+ {0xB0, 0x33, 0x33, 0, 0},
+ {0xB1, 0x88, 0x88, 0, 0},
+ {0xB2, 0x6, 0x6, 0, 0},
+ {0xB3, 0x3, 0x3, 1, 1},
+ {0xB4, 0xa, 0xa, 0, 0},
+ {0xB5, 0x3, 0x3, 1, 1},
+ {0xB6, 0x2a, 0x2a, 0, 0},
+ {0xB7, 0xa4, 0xa4, 0, 0},
+ {0xB8, 0x18, 0x18, 0, 0},
+ {0xB9, 0x28, 0x28, 0, 0},
+ {0xBA, 0, 0, 0, 0},
+ {0xBB, 0x4a, 0x4a, 0, 0},
+ {0xBC, 0, 0, 0, 0},
+ {0xBD, 0x71, 0x71, 0, 0},
+ {0xBE, 0x72, 0x72, 0, 0},
+ {0xBF, 0x73, 0x73, 0, 0},
+ {0xC0, 0x74, 0x74, 0, 0},
+ {0xC1, 0x75, 0x75, 0, 0},
+ {0xC2, 0x76, 0x76, 0, 0},
+ {0xC3, 0x77, 0x77, 0, 0},
+ {0xC4, 0x78, 0x78, 0, 0},
+ {0xC5, 0x79, 0x79, 0, 0},
+ {0xC6, 0x7a, 0x7a, 0, 0},
+ {0xC7, 0, 0, 0, 0},
+ {0xC8, 0, 0, 0, 0},
+ {0xC9, 0, 0, 0, 0},
+ {0xCA, 0, 0, 0, 0},
+ {0xCB, 0, 0, 0, 0},
+ {0xCC, 0, 0, 0, 0},
+ {0xCD, 0, 0, 0, 0},
+ {0xCE, 0x6, 0x6, 0, 0},
+ {0xCF, 0, 0, 0, 0},
+ {0xD0, 0, 0, 0, 0},
+ {0xD1, 0x18, 0x18, 0, 0},
+ {0xD2, 0x88, 0x88, 0, 0},
+ {0xD3, 0, 0, 0, 0},
+ {0xD4, 0, 0, 0, 0},
+ {0xD5, 0, 0, 0, 0},
+ {0xD6, 0, 0, 0, 0},
+ {0xD7, 0, 0, 0, 0},
+ {0xD8, 0, 0, 0, 0},
+ {0xD9, 0, 0, 0, 0},
+ {0xDA, 0x6, 0x6, 0, 0},
+ {0xDB, 0, 0, 0, 0},
+ {0xDC, 0, 0, 0, 0},
+ {0xDD, 0x18, 0x18, 0, 0},
+ {0xDE, 0x88, 0x88, 0, 0},
+ {0xDF, 0, 0, 0, 0},
+ {0xE0, 0, 0, 0, 0},
+ {0xE1, 0, 0, 0, 0},
+ {0xE2, 0, 0, 0, 0},
+ {0xFFFF, 0, 0, 0, 0},
+};
+
+static struct radio_regs regs_SYN_2056[] = {
+ {0x02, 0, 0, 0, 0},
+ {0x03, 0, 0, 0, 0},
+ {0x04, 0, 0, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0, 0, 0, 0},
+ {0x07, 0, 0, 0, 0},
+ {0x08, 0, 0, 0, 0},
+ {0x09, 0x1, 0x1, 0, 0},
+ {0x0A, 0, 0, 0, 0},
+ {0x0B, 0, 0, 0, 0},
+ {0x0C, 0, 0, 0, 0},
+ {0x0D, 0, 0, 0, 0},
+ {0x0E, 0, 0, 0, 0},
+ {0x0F, 0, 0, 0, 0},
+ {0x10, 0, 0, 0, 0},
+ {0x11, 0, 0, 0, 0},
+ {0x12, 0, 0, 0, 0},
+ {0x13, 0, 0, 0, 0},
+ {0x14, 0, 0, 0, 0},
+ {0x15, 0, 0, 0, 0},
+ {0x16, 0, 0, 0, 0},
+ {0x17, 0, 0, 0, 0},
+ {0x18, 0, 0, 0, 0},
+ {0x19, 0, 0, 0, 0},
+ {0x1A, 0, 0, 0, 0},
+ {0x1B, 0, 0, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0, 0, 0, 0},
+ {0x1E, 0, 0, 0, 0},
+ {0x1F, 0, 0, 0, 0},
+ {0x20, 0, 0, 0, 0},
+ {0x21, 0, 0, 0, 0},
+ {0x22, 0x60, 0x60, 0, 0},
+ {0x23, 0x6, 0x6, 0, 0},
+ {0x24, 0xc, 0xc, 0, 0},
+ {0x25, 0, 0, 0, 0},
+ {0x26, 0, 0, 0, 0},
+ {0x27, 0, 0, 0, 0},
+ {0x28, 0x1, 0x1, 0, 0},
+ {0x29, 0, 0, 0, 0},
+ {0x2A, 0, 0, 0, 0},
+ {0x2B, 0, 0, 0, 0},
+ {0x2C, 0, 0, 0, 0},
+ {0x2D, 0, 0, 0, 0},
+ {0x2E, 0xd, 0xd, 0, 0},
+ {0x2F, 0x1f, 0x1f, 0, 0},
+ {0x30, 0x15, 0x15, 0, 0},
+ {0x31, 0xf, 0xf, 0, 0},
+ {0x32, 0, 0, 0, 0},
+ {0x33, 0, 0, 0, 0},
+ {0x34, 0, 0, 0, 0},
+ {0x35, 0, 0, 0, 0},
+ {0x36, 0, 0, 0, 0},
+ {0x37, 0, 0, 0, 0},
+ {0x38, 0, 0, 0, 0},
+ {0x39, 0, 0, 0, 0},
+ {0x3A, 0, 0, 0, 0},
+ {0x3B, 0, 0, 0, 0},
+ {0x3C, 0x13, 0x13, 0, 0},
+ {0x3D, 0xf, 0xf, 0, 0},
+ {0x3E, 0x18, 0x18, 0, 0},
+ {0x3F, 0, 0, 0, 0},
+ {0x40, 0, 0, 0, 0},
+ {0x41, 0x20, 0x20, 0, 0},
+ {0x42, 0x20, 0x20, 0, 0},
+ {0x43, 0, 0, 0, 0},
+ {0x44, 0x77, 0x77, 0, 0},
+ {0x45, 0x7, 0x7, 0, 0},
+ {0x46, 0x1, 0x1, 0, 0},
+ {0x47, 0x4, 0x4, 0, 0},
+ {0x48, 0xf, 0xf, 0, 0},
+ {0x49, 0x30, 0x30, 0, 0},
+ {0x4A, 0x32, 0x32, 0, 0},
+ {0x4B, 0xd, 0xd, 0, 0},
+ {0x4C, 0xd, 0xd, 0, 0},
+ {0x4D, 0x4, 0x4, 0, 0},
+ {0x4E, 0x6, 0x6, 0, 0},
+ {0x4F, 0x1, 0x1, 0, 0},
+ {0x50, 0x1c, 0x1c, 0, 0},
+ {0x51, 0x2, 0x2, 0, 0},
+ {0x52, 0x2, 0x2, 0, 0},
+ {0x53, 0xf7, 0xf7, 1, 1},
+ {0x54, 0xb4, 0xb4, 0, 0},
+ {0x55, 0xd2, 0xd2, 0, 0},
+ {0x56, 0, 0, 0, 0},
+ {0x57, 0, 0, 0, 0},
+ {0x58, 0x4, 0x4, 0, 0},
+ {0x59, 0x96, 0x96, 0, 0},
+ {0x5A, 0x3e, 0x3e, 0, 0},
+ {0x5B, 0x3e, 0x3e, 0, 0},
+ {0x5C, 0x13, 0x13, 0, 0},
+ {0x5D, 0x2, 0x2, 0, 0},
+ {0x5E, 0, 0, 0, 0},
+ {0x5F, 0x7, 0x7, 0, 0},
+ {0x60, 0x7, 0x7, 1, 1},
+ {0x61, 0x8, 0x8, 0, 0},
+ {0x62, 0x3, 0x3, 0, 0},
+ {0x63, 0, 0, 0, 0},
+ {0x64, 0, 0, 0, 0},
+ {0x65, 0, 0, 0, 0},
+ {0x66, 0, 0, 0, 0},
+ {0x67, 0, 0, 0, 0},
+ {0x68, 0x40, 0x40, 0, 0},
+ {0x69, 0, 0, 0, 0},
+ {0x6A, 0, 0, 0, 0},
+ {0x6B, 0, 0, 0, 0},
+ {0x6C, 0, 0, 0, 0},
+ {0x6D, 0x1, 0x1, 0, 0},
+ {0x6E, 0, 0, 0, 0},
+ {0x6F, 0, 0, 0, 0},
+ {0x70, 0x60, 0x60, 0, 0},
+ {0x71, 0x66, 0x66, 0, 0},
+ {0x72, 0xc, 0xc, 0, 0},
+ {0x73, 0x66, 0x66, 0, 0},
+ {0x74, 0x8f, 0x8f, 1, 1},
+ {0x75, 0, 0, 0, 0},
+ {0x76, 0xcc, 0xcc, 0, 0},
+ {0x77, 0x1, 0x1, 0, 0},
+ {0x78, 0x66, 0x66, 0, 0},
+ {0x79, 0x66, 0x66, 0, 0},
+ {0x7A, 0, 0, 0, 0},
+ {0x7B, 0, 0, 0, 0},
+ {0x7C, 0, 0, 0, 0},
+ {0x7D, 0, 0, 0, 0},
+ {0x7E, 0, 0, 0, 0},
+ {0x7F, 0, 0, 0, 0},
+ {0x80, 0, 0, 0, 0},
+ {0x81, 0, 0, 0, 0},
+ {0x82, 0, 0, 0, 0},
+ {0x83, 0, 0, 0, 0},
+ {0x84, 0, 0, 0, 0},
+ {0x85, 0xff, 0xff, 0, 0},
+ {0x86, 0, 0, 0, 0},
+ {0x87, 0, 0, 0, 0},
+ {0x88, 0, 0, 0, 0},
+ {0x89, 0, 0, 0, 0},
+ {0x8A, 0, 0, 0, 0},
+ {0x8B, 0, 0, 0, 0},
+ {0x8C, 0, 0, 0, 0},
+ {0x8D, 0, 0, 0, 0},
+ {0x8E, 0, 0, 0, 0},
+ {0x8F, 0, 0, 0, 0},
+ {0x90, 0, 0, 0, 0},
+ {0x91, 0, 0, 0, 0},
+ {0x92, 0, 0, 0, 0},
+ {0x93, 0, 0, 0, 0},
+ {0x94, 0, 0, 0, 0},
+ {0x95, 0, 0, 0, 0},
+ {0x96, 0, 0, 0, 0},
+ {0x97, 0, 0, 0, 0},
+ {0x98, 0, 0, 0, 0},
+ {0x99, 0, 0, 0, 0},
+ {0x9A, 0, 0, 0, 0},
+ {0x9B, 0, 0, 0, 0},
+ {0x9C, 0, 0, 0, 0},
+ {0x9D, 0, 0, 0, 0},
+ {0x9E, 0, 0, 0, 0},
+ {0x9F, 0x6, 0x6, 0, 0},
+ {0xA0, 0x66, 0x66, 0, 0},
+ {0xA1, 0x66, 0x66, 0, 0},
+ {0xA2, 0x66, 0x66, 0, 0},
+ {0xA3, 0x66, 0x66, 0, 0},
+ {0xA4, 0x66, 0x66, 0, 0},
+ {0xA5, 0x66, 0x66, 0, 0},
+ {0xA6, 0x66, 0x66, 0, 0},
+ {0xA7, 0x66, 0x66, 0, 0},
+ {0xA8, 0x66, 0x66, 0, 0},
+ {0xA9, 0x66, 0x66, 0, 0},
+ {0xAA, 0x66, 0x66, 0, 0},
+ {0xAB, 0x66, 0x66, 0, 0},
+ {0xAC, 0x66, 0x66, 0, 0},
+ {0xAD, 0x66, 0x66, 0, 0},
+ {0xAE, 0x66, 0x66, 0, 0},
+ {0xAF, 0x66, 0x66, 0, 0},
+ {0xB0, 0x66, 0x66, 0, 0},
+ {0xB1, 0x66, 0x66, 0, 0},
+ {0xB2, 0x66, 0x66, 0, 0},
+ {0xB3, 0xa, 0xa, 0, 0},
+ {0xB4, 0, 0, 0, 0},
+ {0xB5, 0, 0, 0, 0},
+ {0xB6, 0, 0, 0, 0},
+ {0xFFFF, 0, 0, 0, 0}
+};
+
+static struct radio_regs regs_TX_2056[] = {
+ {0x02, 0, 0, 0, 0},
+ {0x03, 0, 0, 0, 0},
+ {0x04, 0, 0, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0, 0, 0, 0},
+ {0x07, 0, 0, 0, 0},
+ {0x08, 0, 0, 0, 0},
+ {0x09, 0, 0, 0, 0},
+ {0x0A, 0, 0, 0, 0},
+ {0x0B, 0, 0, 0, 0},
+ {0x0C, 0, 0, 0, 0},
+ {0x0D, 0, 0, 0, 0},
+ {0x0E, 0, 0, 0, 0},
+ {0x0F, 0, 0, 0, 0},
+ {0x10, 0, 0, 0, 0},
+ {0x11, 0, 0, 0, 0},
+ {0x12, 0, 0, 0, 0},
+ {0x13, 0, 0, 0, 0},
+ {0x14, 0, 0, 0, 0},
+ {0x15, 0, 0, 0, 0},
+ {0x16, 0, 0, 0, 0},
+ {0x17, 0, 0, 0, 0},
+ {0x18, 0, 0, 0, 0},
+ {0x19, 0, 0, 0, 0},
+ {0x1A, 0, 0, 0, 0},
+ {0x1B, 0, 0, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0, 0, 0, 0},
+ {0x1E, 0, 0, 0, 0},
+ {0x1F, 0, 0, 0, 0},
+ {0x20, 0, 0, 0, 0},
+ {0x21, 0x88, 0x88, 0, 0},
+ {0x22, 0x88, 0x88, 0, 0},
+ {0x23, 0x88, 0x88, 0, 0},
+ {0x24, 0x88, 0x88, 0, 0},
+ {0x25, 0xc, 0xc, 0, 0},
+ {0x26, 0, 0, 0, 0},
+ {0x27, 0x3, 0x3, 0, 0},
+ {0x28, 0, 0, 0, 0},
+ {0x29, 0x3, 0x3, 0, 0},
+ {0x2A, 0x37, 0x37, 0, 0},
+ {0x2B, 0x3, 0x3, 0, 0},
+ {0x2C, 0, 0, 0, 0},
+ {0x2D, 0, 0, 0, 0},
+ {0x2E, 0x1, 0x1, 0, 0},
+ {0x2F, 0x1, 0x1, 0, 0},
+ {0x30, 0, 0, 0, 0},
+ {0x31, 0, 0, 0, 0},
+ {0x32, 0, 0, 0, 0},
+ {0x33, 0x11, 0x11, 0, 0},
+ {0x34, 0x11, 0x11, 0, 0},
+ {0x35, 0, 0, 0, 0},
+ {0x36, 0, 0, 0, 0},
+ {0x37, 0x3, 0x3, 0, 0},
+ {0x38, 0xf, 0xf, 0, 0},
+ {0x39, 0, 0, 0, 0},
+ {0x3A, 0x2d, 0x2d, 0, 0},
+ {0x3B, 0, 0, 0, 0},
+ {0x3C, 0x6e, 0x6e, 0, 0},
+ {0x3D, 0xf0, 0xf0, 1, 1},
+ {0x3E, 0, 0, 0, 0},
+ {0x3F, 0, 0, 0, 0},
+ {0x40, 0, 0, 0, 0},
+ {0x41, 0x3, 0x3, 0, 0},
+ {0x42, 0x3, 0x3, 0, 0},
+ {0x43, 0, 0, 0, 0},
+ {0x44, 0x1e, 0x1e, 0, 0},
+ {0x45, 0, 0, 0, 0},
+ {0x46, 0x6e, 0x6e, 0, 0},
+ {0x47, 0xf0, 0xf0, 1, 1},
+ {0x48, 0, 0, 0, 0},
+ {0x49, 0x2, 0x2, 0, 0},
+ {0x4A, 0xff, 0xff, 1, 1},
+ {0x4B, 0xc, 0xc, 0, 0},
+ {0x4C, 0, 0, 0, 0},
+ {0x4D, 0x38, 0x38, 0, 0},
+ {0x4E, 0x70, 0x70, 1, 1},
+ {0x4F, 0x2, 0x2, 0, 0},
+ {0x50, 0x88, 0x88, 0, 0},
+ {0x51, 0xc, 0xc, 0, 0},
+ {0x52, 0, 0, 0, 0},
+ {0x53, 0x8, 0x8, 0, 0},
+ {0x54, 0x70, 0x70, 1, 1},
+ {0x55, 0x2, 0x2, 0, 0},
+ {0x56, 0xff, 0xff, 1, 1},
+ {0x57, 0, 0, 0, 0},
+ {0x58, 0x83, 0x83, 0, 0},
+ {0x59, 0x77, 0x77, 1, 1},
+ {0x5A, 0, 0, 0, 0},
+ {0x5B, 0x2, 0x2, 0, 0},
+ {0x5C, 0x88, 0x88, 0, 0},
+ {0x5D, 0, 0, 0, 0},
+ {0x5E, 0x8, 0x8, 0, 0},
+ {0x5F, 0x77, 0x77, 1, 1},
+ {0x60, 0x1, 0x1, 0, 0},
+ {0x61, 0, 0, 0, 0},
+ {0x62, 0x7, 0x7, 0, 0},
+ {0x63, 0, 0, 0, 0},
+ {0x64, 0x7, 0x7, 0, 0},
+ {0x65, 0, 0, 0, 0},
+ {0x66, 0, 0, 0, 0},
+ {0x67, 0x74, 0x74, 1, 1},
+ {0x68, 0, 0, 0, 0},
+ {0x69, 0xa, 0xa, 0, 0},
+ {0x6A, 0, 0, 0, 0},
+ {0x6B, 0, 0, 0, 0},
+ {0x6C, 0, 0, 0, 0},
+ {0x6D, 0, 0, 0, 0},
+ {0x6E, 0, 0, 0, 0},
+ {0x6F, 0, 0, 0, 0},
+ {0x70, 0, 0, 0, 0},
+ {0x71, 0x2, 0x2, 0, 0},
+ {0x72, 0, 0, 0, 0},
+ {0x73, 0, 0, 0, 0},
+ {0x74, 0xe, 0xe, 0, 0},
+ {0x75, 0xe, 0xe, 0, 0},
+ {0x76, 0xe, 0xe, 0, 0},
+ {0x77, 0x13, 0x13, 0, 0},
+ {0x78, 0x13, 0x13, 0, 0},
+ {0x79, 0x1b, 0x1b, 0, 0},
+ {0x7A, 0x1b, 0x1b, 0, 0},
+ {0x7B, 0x55, 0x55, 0, 0},
+ {0x7C, 0x5b, 0x5b, 0, 0},
+ {0x7D, 0, 0, 0, 0},
+ {0x7E, 0, 0, 0, 0},
+ {0x7F, 0, 0, 0, 0},
+ {0x80, 0, 0, 0, 0},
+ {0x81, 0, 0, 0, 0},
+ {0x82, 0, 0, 0, 0},
+ {0x83, 0, 0, 0, 0},
+ {0x84, 0, 0, 0, 0},
+ {0x85, 0, 0, 0, 0},
+ {0x86, 0, 0, 0, 0},
+ {0x87, 0, 0, 0, 0},
+ {0x88, 0, 0, 0, 0},
+ {0x89, 0, 0, 0, 0},
+ {0x8A, 0, 0, 0, 0},
+ {0x8B, 0, 0, 0, 0},
+ {0x8C, 0, 0, 0, 0},
+ {0x8D, 0, 0, 0, 0},
+ {0x8E, 0, 0, 0, 0},
+ {0x8F, 0, 0, 0, 0},
+ {0x90, 0, 0, 0, 0},
+ {0x91, 0, 0, 0, 0},
+ {0x92, 0, 0, 0, 0},
+ {0xFFFF, 0, 0, 0, 0}
+};
+
+static struct radio_regs regs_RX_2056[] = {
+ {0x02, 0, 0, 0, 0},
+ {0x03, 0, 0, 0, 0},
+ {0x04, 0, 0, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0, 0, 0, 0},
+ {0x07, 0, 0, 0, 0},
+ {0x08, 0, 0, 0, 0},
+ {0x09, 0, 0, 0, 0},
+ {0x0A, 0, 0, 0, 0},
+ {0x0B, 0, 0, 0, 0},
+ {0x0C, 0, 0, 0, 0},
+ {0x0D, 0, 0, 0, 0},
+ {0x0E, 0, 0, 0, 0},
+ {0x0F, 0, 0, 0, 0},
+ {0x10, 0, 0, 0, 0},
+ {0x11, 0, 0, 0, 0},
+ {0x12, 0, 0, 0, 0},
+ {0x13, 0, 0, 0, 0},
+ {0x14, 0, 0, 0, 0},
+ {0x15, 0, 0, 0, 0},
+ {0x16, 0, 0, 0, 0},
+ {0x17, 0, 0, 0, 0},
+ {0x18, 0, 0, 0, 0},
+ {0x19, 0, 0, 0, 0},
+ {0x1A, 0, 0, 0, 0},
+ {0x1B, 0, 0, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0, 0, 0, 0},
+ {0x1E, 0, 0, 0, 0},
+ {0x1F, 0, 0, 0, 0},
+ {0x20, 0x3, 0x3, 0, 0},
+ {0x21, 0, 0, 0, 0},
+ {0x22, 0, 0, 0, 0},
+ {0x23, 0x90, 0x90, 0, 0},
+ {0x24, 0x55, 0x55, 0, 0},
+ {0x25, 0x15, 0x15, 0, 0},
+ {0x26, 0x5, 0x5, 0, 0},
+ {0x27, 0x15, 0x15, 0, 0},
+ {0x28, 0x5, 0x5, 0, 0},
+ {0x29, 0x20, 0x20, 0, 0},
+ {0x2A, 0x11, 0x11, 0, 0},
+ {0x2B, 0x90, 0x90, 0, 0},
+ {0x2C, 0, 0, 0, 0},
+ {0x2D, 0x88, 0x88, 0, 0},
+ {0x2E, 0x32, 0x32, 0, 0},
+ {0x2F, 0x77, 0x77, 0, 0},
+ {0x30, 0x17, 0x17, 1, 1},
+ {0x31, 0xff, 0xff, 1, 1},
+ {0x32, 0x20, 0x20, 0, 0},
+ {0x33, 0, 0, 0, 0},
+ {0x34, 0x88, 0x88, 0, 0},
+ {0x35, 0x32, 0x32, 0, 0},
+ {0x36, 0x77, 0x77, 0, 0},
+ {0x37, 0x17, 0x17, 1, 1},
+ {0x38, 0xf0, 0xf0, 1, 1},
+ {0x39, 0x20, 0x20, 0, 0},
+ {0x3A, 0x8, 0x8, 0, 0},
+ {0x3B, 0x99, 0x99, 0, 0},
+ {0x3C, 0, 0, 0, 0},
+ {0x3D, 0x44, 0x44, 1, 1},
+ {0x3E, 0, 0, 0, 0},
+ {0x3F, 0x44, 0x44, 0, 0},
+ {0x40, 0xf, 0xf, 1, 1},
+ {0x41, 0x6, 0x6, 0, 0},
+ {0x42, 0x4, 0x4, 0, 0},
+ {0x43, 0x50, 0x50, 1, 1},
+ {0x44, 0x8, 0x8, 0, 0},
+ {0x45, 0x99, 0x99, 0, 0},
+ {0x46, 0, 0, 0, 0},
+ {0x47, 0x11, 0x11, 0, 0},
+ {0x48, 0, 0, 0, 0},
+ {0x49, 0x44, 0x44, 0, 0},
+ {0x4A, 0x7, 0x7, 0, 0},
+ {0x4B, 0x6, 0x6, 0, 0},
+ {0x4C, 0x4, 0x4, 0, 0},
+ {0x4D, 0, 0, 0, 0},
+ {0x4E, 0, 0, 0, 0},
+ {0x4F, 0x66, 0x66, 0, 0},
+ {0x50, 0x66, 0x66, 0, 0},
+ {0x51, 0x57, 0x57, 0, 0},
+ {0x52, 0x57, 0x57, 0, 0},
+ {0x53, 0x44, 0x44, 0, 0},
+ {0x54, 0, 0, 0, 0},
+ {0x55, 0, 0, 0, 0},
+ {0x56, 0x8, 0x8, 0, 0},
+ {0x57, 0x8, 0x8, 0, 0},
+ {0x58, 0x7, 0x7, 0, 0},
+ {0x59, 0x22, 0x22, 0, 0},
+ {0x5A, 0x22, 0x22, 0, 0},
+ {0x5B, 0x2, 0x2, 0, 0},
+ {0x5C, 0x23, 0x23, 0, 0},
+ {0x5D, 0x7, 0x7, 0, 0},
+ {0x5E, 0x55, 0x55, 0, 0},
+ {0x5F, 0x23, 0x23, 0, 0},
+ {0x60, 0x41, 0x41, 0, 0},
+ {0x61, 0x1, 0x1, 0, 0},
+ {0x62, 0xa, 0xa, 0, 0},
+ {0x63, 0, 0, 0, 0},
+ {0x64, 0, 0, 0, 0},
+ {0x65, 0, 0, 0, 0},
+ {0x66, 0, 0, 0, 0},
+ {0x67, 0, 0, 0, 0},
+ {0x68, 0, 0, 0, 0},
+ {0x69, 0, 0, 0, 0},
+ {0x6A, 0, 0, 0, 0},
+ {0x6B, 0xc, 0xc, 0, 0},
+ {0x6C, 0, 0, 0, 0},
+ {0x6D, 0, 0, 0, 0},
+ {0x6E, 0, 0, 0, 0},
+ {0x6F, 0, 0, 0, 0},
+ {0x70, 0, 0, 0, 0},
+ {0x71, 0, 0, 0, 0},
+ {0x72, 0x22, 0x22, 0, 0},
+ {0x73, 0x22, 0x22, 0, 0},
+ {0x74, 0x2, 0x2, 0, 0},
+ {0x75, 0xa, 0xa, 0, 0},
+ {0x76, 0x1, 0x1, 0, 0},
+ {0x77, 0x22, 0x22, 0, 0},
+ {0x78, 0x30, 0x30, 0, 0},
+ {0x79, 0, 0, 0, 0},
+ {0x7A, 0, 0, 0, 0},
+ {0x7B, 0, 0, 0, 0},
+ {0x7C, 0, 0, 0, 0},
+ {0x7D, 0, 0, 0, 0},
+ {0x7E, 0, 0, 0, 0},
+ {0x7F, 0, 0, 0, 0},
+ {0x80, 0, 0, 0, 0},
+ {0x81, 0, 0, 0, 0},
+ {0x82, 0, 0, 0, 0},
+ {0x83, 0, 0, 0, 0},
+ {0x84, 0, 0, 0, 0},
+ {0x85, 0, 0, 0, 0},
+ {0x86, 0, 0, 0, 0},
+ {0x87, 0, 0, 0, 0},
+ {0x88, 0, 0, 0, 0},
+ {0x89, 0, 0, 0, 0},
+ {0x8A, 0, 0, 0, 0},
+ {0x8B, 0, 0, 0, 0},
+ {0x8C, 0, 0, 0, 0},
+ {0x8D, 0, 0, 0, 0},
+ {0x8E, 0, 0, 0, 0},
+ {0x8F, 0, 0, 0, 0},
+ {0x90, 0, 0, 0, 0},
+ {0x91, 0, 0, 0, 0},
+ {0x92, 0, 0, 0, 0},
+ {0x93, 0, 0, 0, 0},
+ {0x94, 0, 0, 0, 0},
+ {0xFFFF, 0, 0, 0, 0}
+};
+
+static struct radio_regs regs_SYN_2056_A1[] = {
+ {0x02, 0, 0, 0, 0},
+ {0x03, 0, 0, 0, 0},
+ {0x04, 0, 0, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0, 0, 0, 0},
+ {0x07, 0, 0, 0, 0},
+ {0x08, 0, 0, 0, 0},
+ {0x09, 0x1, 0x1, 0, 0},
+ {0x0A, 0, 0, 0, 0},
+ {0x0B, 0, 0, 0, 0},
+ {0x0C, 0, 0, 0, 0},
+ {0x0D, 0, 0, 0, 0},
+ {0x0E, 0, 0, 0, 0},
+ {0x0F, 0, 0, 0, 0},
+ {0x10, 0, 0, 0, 0},
+ {0x11, 0, 0, 0, 0},
+ {0x12, 0, 0, 0, 0},
+ {0x13, 0, 0, 0, 0},
+ {0x14, 0, 0, 0, 0},
+ {0x15, 0, 0, 0, 0},
+ {0x16, 0, 0, 0, 0},
+ {0x17, 0, 0, 0, 0},
+ {0x18, 0, 0, 0, 0},
+ {0x19, 0, 0, 0, 0},
+ {0x1A, 0, 0, 0, 0},
+ {0x1B, 0, 0, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0, 0, 0, 0},
+ {0x1E, 0, 0, 0, 0},
+ {0x1F, 0, 0, 0, 0},
+ {0x20, 0, 0, 0, 0},
+ {0x21, 0, 0, 0, 0},
+ {0x22, 0x60, 0x60, 0, 0},
+ {0x23, 0x6, 0x6, 0, 0},
+ {0x24, 0xc, 0xc, 0, 0},
+ {0x25, 0, 0, 0, 0},
+ {0x26, 0, 0, 0, 0},
+ {0x27, 0, 0, 0, 0},
+ {0x28, 0x1, 0x1, 0, 0},
+ {0x29, 0, 0, 0, 0},
+ {0x2A, 0, 0, 0, 0},
+ {0x2B, 0, 0, 0, 0},
+ {0x2C, 0, 0, 0, 0},
+ {0x2D, 0, 0, 0, 0},
+ {0x2E, 0xd, 0xd, 0, 0},
+ {0x2F, 0x1f, 0x1f, 0, 0},
+ {0x30, 0x15, 0x15, 0, 0},
+ {0x31, 0xf, 0xf, 0, 0},
+ {0x32, 0, 0, 0, 0},
+ {0x33, 0, 0, 0, 0},
+ {0x34, 0, 0, 0, 0},
+ {0x35, 0, 0, 0, 0},
+ {0x36, 0, 0, 0, 0},
+ {0x37, 0, 0, 0, 0},
+ {0x38, 0, 0, 0, 0},
+ {0x39, 0, 0, 0, 0},
+ {0x3A, 0, 0, 0, 0},
+ {0x3B, 0, 0, 0, 0},
+ {0x3C, 0x13, 0x13, 0, 0},
+ {0x3D, 0xf, 0xf, 0, 0},
+ {0x3E, 0x18, 0x18, 0, 0},
+ {0x3F, 0, 0, 0, 0},
+ {0x40, 0, 0, 0, 0},
+ {0x41, 0x20, 0x20, 0, 0},
+ {0x42, 0x20, 0x20, 0, 0},
+ {0x43, 0, 0, 0, 0},
+ {0x44, 0x77, 0x77, 0, 0},
+ {0x45, 0x7, 0x7, 0, 0},
+ {0x46, 0x1, 0x1, 0, 0},
+ {0x47, 0x4, 0x4, 0, 0},
+ {0x48, 0xf, 0xf, 0, 0},
+ {0x49, 0x30, 0x30, 0, 0},
+ {0x4A, 0x32, 0x32, 0, 0},
+ {0x4B, 0xd, 0xd, 0, 0},
+ {0x4C, 0xd, 0xd, 0, 0},
+ {0x4D, 0x4, 0x4, 0, 0},
+ {0x4E, 0x6, 0x6, 0, 0},
+ {0x4F, 0x1, 0x1, 0, 0},
+ {0x50, 0x1c, 0x1c, 0, 0},
+ {0x51, 0x2, 0x2, 0, 0},
+ {0x52, 0x2, 0x2, 0, 0},
+ {0x53, 0xf7, 0xf7, 1, 1},
+ {0x54, 0xb4, 0xb4, 0, 0},
+ {0x55, 0xd2, 0xd2, 0, 0},
+ {0x56, 0, 0, 0, 0},
+ {0x57, 0, 0, 0, 0},
+ {0x58, 0x4, 0x4, 0, 0},
+ {0x59, 0x96, 0x96, 0, 0},
+ {0x5A, 0x3e, 0x3e, 0, 0},
+ {0x5B, 0x3e, 0x3e, 0, 0},
+ {0x5C, 0x13, 0x13, 0, 0},
+ {0x5D, 0x2, 0x2, 0, 0},
+ {0x5E, 0, 0, 0, 0},
+ {0x5F, 0x7, 0x7, 0, 0},
+ {0x60, 0x7, 0x7, 1, 1},
+ {0x61, 0x8, 0x8, 0, 0},
+ {0x62, 0x3, 0x3, 0, 0},
+ {0x63, 0, 0, 0, 0},
+ {0x64, 0, 0, 0, 0},
+ {0x65, 0, 0, 0, 0},
+ {0x66, 0, 0, 0, 0},
+ {0x67, 0, 0, 0, 0},
+ {0x68, 0x40, 0x40, 0, 0},
+ {0x69, 0, 0, 0, 0},
+ {0x6A, 0, 0, 0, 0},
+ {0x6B, 0, 0, 0, 0},
+ {0x6C, 0, 0, 0, 0},
+ {0x6D, 0x1, 0x1, 0, 0},
+ {0x6E, 0, 0, 0, 0},
+ {0x6F, 0, 0, 0, 0},
+ {0x70, 0x60, 0x60, 0, 0},
+ {0x71, 0x66, 0x66, 0, 0},
+ {0x72, 0xc, 0xc, 0, 0},
+ {0x73, 0x66, 0x66, 0, 0},
+ {0x74, 0x8f, 0x8f, 1, 1},
+ {0x75, 0, 0, 0, 0},
+ {0x76, 0xcc, 0xcc, 0, 0},
+ {0x77, 0x1, 0x1, 0, 0},
+ {0x78, 0x66, 0x66, 0, 0},
+ {0x79, 0x66, 0x66, 0, 0},
+ {0x7A, 0, 0, 0, 0},
+ {0x7B, 0, 0, 0, 0},
+ {0x7C, 0, 0, 0, 0},
+ {0x7D, 0, 0, 0, 0},
+ {0x7E, 0, 0, 0, 0},
+ {0x7F, 0, 0, 0, 0},
+ {0x80, 0, 0, 0, 0},
+ {0x81, 0, 0, 0, 0},
+ {0x82, 0, 0, 0, 0},
+ {0x83, 0, 0, 0, 0},
+ {0x84, 0, 0, 0, 0},
+ {0x85, 0xff, 0xff, 0, 0},
+ {0x86, 0, 0, 0, 0},
+ {0x87, 0, 0, 0, 0},
+ {0x88, 0, 0, 0, 0},
+ {0x89, 0, 0, 0, 0},
+ {0x8A, 0, 0, 0, 0},
+ {0x8B, 0, 0, 0, 0},
+ {0x8C, 0, 0, 0, 0},
+ {0x8D, 0, 0, 0, 0},
+ {0x8E, 0, 0, 0, 0},
+ {0x8F, 0, 0, 0, 0},
+ {0x90, 0, 0, 0, 0},
+ {0x91, 0, 0, 0, 0},
+ {0x92, 0, 0, 0, 0},
+ {0x93, 0, 0, 0, 0},
+ {0x94, 0, 0, 0, 0},
+ {0x95, 0, 0, 0, 0},
+ {0x96, 0, 0, 0, 0},
+ {0x97, 0, 0, 0, 0},
+ {0x98, 0, 0, 0, 0},
+ {0x99, 0, 0, 0, 0},
+ {0x9A, 0, 0, 0, 0},
+ {0x9B, 0, 0, 0, 0},
+ {0x9C, 0, 0, 0, 0},
+ {0x9D, 0, 0, 0, 0},
+ {0x9E, 0, 0, 0, 0},
+ {0x9F, 0x6, 0x6, 0, 0},
+ {0xA0, 0x66, 0x66, 0, 0},
+ {0xA1, 0x66, 0x66, 0, 0},
+ {0xA2, 0x66, 0x66, 0, 0},
+ {0xA3, 0x66, 0x66, 0, 0},
+ {0xA4, 0x66, 0x66, 0, 0},
+ {0xA5, 0x66, 0x66, 0, 0},
+ {0xA6, 0x66, 0x66, 0, 0},
+ {0xA7, 0x66, 0x66, 0, 0},
+ {0xA8, 0x66, 0x66, 0, 0},
+ {0xA9, 0x66, 0x66, 0, 0},
+ {0xAA, 0x66, 0x66, 0, 0},
+ {0xAB, 0x66, 0x66, 0, 0},
+ {0xAC, 0x66, 0x66, 0, 0},
+ {0xAD, 0x66, 0x66, 0, 0},
+ {0xAE, 0x66, 0x66, 0, 0},
+ {0xAF, 0x66, 0x66, 0, 0},
+ {0xB0, 0x66, 0x66, 0, 0},
+ {0xB1, 0x66, 0x66, 0, 0},
+ {0xB2, 0x66, 0x66, 0, 0},
+ {0xB3, 0xa, 0xa, 0, 0},
+ {0xB4, 0, 0, 0, 0},
+ {0xB5, 0, 0, 0, 0},
+ {0xB6, 0, 0, 0, 0},
+ {0xFFFF, 0, 0, 0, 0}
+};
+
+static struct radio_regs regs_TX_2056_A1[] = {
+ {0x02, 0, 0, 0, 0},
+ {0x03, 0, 0, 0, 0},
+ {0x04, 0, 0, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0, 0, 0, 0},
+ {0x07, 0, 0, 0, 0},
+ {0x08, 0, 0, 0, 0},
+ {0x09, 0, 0, 0, 0},
+ {0x0A, 0, 0, 0, 0},
+ {0x0B, 0, 0, 0, 0},
+ {0x0C, 0, 0, 0, 0},
+ {0x0D, 0, 0, 0, 0},
+ {0x0E, 0, 0, 0, 0},
+ {0x0F, 0, 0, 0, 0},
+ {0x10, 0, 0, 0, 0},
+ {0x11, 0, 0, 0, 0},
+ {0x12, 0, 0, 0, 0},
+ {0x13, 0, 0, 0, 0},
+ {0x14, 0, 0, 0, 0},
+ {0x15, 0, 0, 0, 0},
+ {0x16, 0, 0, 0, 0},
+ {0x17, 0, 0, 0, 0},
+ {0x18, 0, 0, 0, 0},
+ {0x19, 0, 0, 0, 0},
+ {0x1A, 0, 0, 0, 0},
+ {0x1B, 0, 0, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0, 0, 0, 0},
+ {0x1E, 0, 0, 0, 0},
+ {0x1F, 0, 0, 0, 0},
+ {0x20, 0, 0, 0, 0},
+ {0x21, 0x88, 0x88, 0, 0},
+ {0x22, 0x88, 0x88, 0, 0},
+ {0x23, 0x88, 0x88, 0, 0},
+ {0x24, 0x88, 0x88, 0, 0},
+ {0x25, 0xc, 0xc, 0, 0},
+ {0x26, 0, 0, 0, 0},
+ {0x27, 0x3, 0x3, 0, 0},
+ {0x28, 0, 0, 0, 0},
+ {0x29, 0x3, 0x3, 0, 0},
+ {0x2A, 0x37, 0x37, 0, 0},
+ {0x2B, 0x3, 0x3, 0, 0},
+ {0x2C, 0, 0, 0, 0},
+ {0x2D, 0, 0, 0, 0},
+ {0x2E, 0x1, 0x1, 0, 0},
+ {0x2F, 0x1, 0x1, 0, 0},
+ {0x30, 0, 0, 0, 0},
+ {0x31, 0, 0, 0, 0},
+ {0x32, 0, 0, 0, 0},
+ {0x33, 0x11, 0x11, 0, 0},
+ {0x34, 0x11, 0x11, 0, 0},
+ {0x35, 0, 0, 0, 0},
+ {0x36, 0, 0, 0, 0},
+ {0x37, 0x3, 0x3, 0, 0},
+ {0x38, 0xf, 0xf, 0, 0},
+ {0x39, 0, 0, 0, 0},
+ {0x3A, 0x2d, 0x2d, 0, 0},
+ {0x3B, 0, 0, 0, 0},
+ {0x3C, 0x6e, 0x6e, 0, 0},
+ {0x3D, 0xf0, 0xf0, 1, 1},
+ {0x3E, 0, 0, 0, 0},
+ {0x3F, 0, 0, 0, 0},
+ {0x40, 0, 0, 0, 0},
+ {0x41, 0x3, 0x3, 0, 0},
+ {0x42, 0x3, 0x3, 0, 0},
+ {0x43, 0, 0, 0, 0},
+ {0x44, 0x1e, 0x1e, 0, 0},
+ {0x45, 0, 0, 0, 0},
+ {0x46, 0x6e, 0x6e, 0, 0},
+ {0x47, 0xf0, 0xf0, 1, 1},
+ {0x48, 0, 0, 0, 0},
+ {0x49, 0x2, 0x2, 0, 0},
+ {0x4A, 0xff, 0xff, 1, 1},
+ {0x4B, 0xc, 0xc, 0, 0},
+ {0x4C, 0, 0, 0, 0},
+ {0x4D, 0x38, 0x38, 0, 0},
+ {0x4E, 0x70, 0x70, 1, 1},
+ {0x4F, 0x2, 0x2, 0, 0},
+ {0x50, 0x88, 0x88, 0, 0},
+ {0x51, 0xc, 0xc, 0, 0},
+ {0x52, 0, 0, 0, 0},
+ {0x53, 0x8, 0x8, 0, 0},
+ {0x54, 0x70, 0x70, 1, 1},
+ {0x55, 0x2, 0x2, 0, 0},
+ {0x56, 0xff, 0xff, 1, 1},
+ {0x57, 0, 0, 0, 0},
+ {0x58, 0x83, 0x83, 0, 0},
+ {0x59, 0x77, 0x77, 1, 1},
+ {0x5A, 0, 0, 0, 0},
+ {0x5B, 0x2, 0x2, 0, 0},
+ {0x5C, 0x88, 0x88, 0, 0},
+ {0x5D, 0, 0, 0, 0},
+ {0x5E, 0x8, 0x8, 0, 0},
+ {0x5F, 0x77, 0x77, 1, 1},
+ {0x60, 0x1, 0x1, 0, 0},
+ {0x61, 0, 0, 0, 0},
+ {0x62, 0x7, 0x7, 0, 0},
+ {0x63, 0, 0, 0, 0},
+ {0x64, 0x7, 0x7, 0, 0},
+ {0x65, 0, 0, 0, 0},
+ {0x66, 0, 0, 0, 0},
+ {0x67, 0x72, 0x72, 1, 1},
+ {0x68, 0, 0, 0, 0},
+ {0x69, 0xa, 0xa, 0, 0},
+ {0x6A, 0, 0, 0, 0},
+ {0x6B, 0, 0, 0, 0},
+ {0x6C, 0, 0, 0, 0},
+ {0x6D, 0, 0, 0, 0},
+ {0x6E, 0, 0, 0, 0},
+ {0x6F, 0, 0, 0, 0},
+ {0x70, 0, 0, 0, 0},
+ {0x71, 0x2, 0x2, 0, 0},
+ {0x72, 0, 0, 0, 0},
+ {0x73, 0, 0, 0, 0},
+ {0x74, 0xe, 0xe, 0, 0},
+ {0x75, 0xe, 0xe, 0, 0},
+ {0x76, 0xe, 0xe, 0, 0},
+ {0x77, 0x13, 0x13, 0, 0},
+ {0x78, 0x13, 0x13, 0, 0},
+ {0x79, 0x1b, 0x1b, 0, 0},
+ {0x7A, 0x1b, 0x1b, 0, 0},
+ {0x7B, 0x55, 0x55, 0, 0},
+ {0x7C, 0x5b, 0x5b, 0, 0},
+ {0x7D, 0, 0, 0, 0},
+ {0x7E, 0, 0, 0, 0},
+ {0x7F, 0, 0, 0, 0},
+ {0x80, 0, 0, 0, 0},
+ {0x81, 0, 0, 0, 0},
+ {0x82, 0, 0, 0, 0},
+ {0x83, 0, 0, 0, 0},
+ {0x84, 0, 0, 0, 0},
+ {0x85, 0, 0, 0, 0},
+ {0x86, 0, 0, 0, 0},
+ {0x87, 0, 0, 0, 0},
+ {0x88, 0, 0, 0, 0},
+ {0x89, 0, 0, 0, 0},
+ {0x8A, 0, 0, 0, 0},
+ {0x8B, 0, 0, 0, 0},
+ {0x8C, 0, 0, 0, 0},
+ {0x8D, 0, 0, 0, 0},
+ {0x8E, 0, 0, 0, 0},
+ {0x8F, 0, 0, 0, 0},
+ {0x90, 0, 0, 0, 0},
+ {0x91, 0, 0, 0, 0},
+ {0x92, 0, 0, 0, 0},
+ {0xFFFF, 0, 0, 0, 0}
+};
+
+static struct radio_regs regs_RX_2056_A1[] = {
+ {0x02, 0, 0, 0, 0},
+ {0x03, 0, 0, 0, 0},
+ {0x04, 0, 0, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0, 0, 0, 0},
+ {0x07, 0, 0, 0, 0},
+ {0x08, 0, 0, 0, 0},
+ {0x09, 0, 0, 0, 0},
+ {0x0A, 0, 0, 0, 0},
+ {0x0B, 0, 0, 0, 0},
+ {0x0C, 0, 0, 0, 0},
+ {0x0D, 0, 0, 0, 0},
+ {0x0E, 0, 0, 0, 0},
+ {0x0F, 0, 0, 0, 0},
+ {0x10, 0, 0, 0, 0},
+ {0x11, 0, 0, 0, 0},
+ {0x12, 0, 0, 0, 0},
+ {0x13, 0, 0, 0, 0},
+ {0x14, 0, 0, 0, 0},
+ {0x15, 0, 0, 0, 0},
+ {0x16, 0, 0, 0, 0},
+ {0x17, 0, 0, 0, 0},
+ {0x18, 0, 0, 0, 0},
+ {0x19, 0, 0, 0, 0},
+ {0x1A, 0, 0, 0, 0},
+ {0x1B, 0, 0, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0, 0, 0, 0},
+ {0x1E, 0, 0, 0, 0},
+ {0x1F, 0, 0, 0, 0},
+ {0x20, 0x3, 0x3, 0, 0},
+ {0x21, 0, 0, 0, 0},
+ {0x22, 0, 0, 0, 0},
+ {0x23, 0x90, 0x90, 0, 0},
+ {0x24, 0x55, 0x55, 0, 0},
+ {0x25, 0x15, 0x15, 0, 0},
+ {0x26, 0x5, 0x5, 0, 0},
+ {0x27, 0x15, 0x15, 0, 0},
+ {0x28, 0x5, 0x5, 0, 0},
+ {0x29, 0x20, 0x20, 0, 0},
+ {0x2A, 0x11, 0x11, 0, 0},
+ {0x2B, 0x90, 0x90, 0, 0},
+ {0x2C, 0, 0, 0, 0},
+ {0x2D, 0x88, 0x88, 0, 0},
+ {0x2E, 0x32, 0x32, 0, 0},
+ {0x2F, 0x77, 0x77, 0, 0},
+ {0x30, 0x17, 0x17, 1, 1},
+ {0x31, 0xff, 0xff, 1, 1},
+ {0x32, 0x20, 0x20, 0, 0},
+ {0x33, 0, 0, 0, 0},
+ {0x34, 0x88, 0x88, 0, 0},
+ {0x35, 0x32, 0x32, 0, 0},
+ {0x36, 0x77, 0x77, 0, 0},
+ {0x37, 0x17, 0x17, 1, 1},
+ {0x38, 0xf0, 0xf0, 1, 1},
+ {0x39, 0x20, 0x20, 0, 0},
+ {0x3A, 0x8, 0x8, 0, 0},
+ {0x3B, 0x55, 0x55, 1, 1},
+ {0x3C, 0, 0, 0, 0},
+ {0x3D, 0x44, 0x44, 1, 1},
+ {0x3E, 0, 0, 0, 0},
+ {0x3F, 0x44, 0x44, 0, 0},
+ {0x40, 0xf, 0xf, 1, 1},
+ {0x41, 0x6, 0x6, 0, 0},
+ {0x42, 0x4, 0x4, 0, 0},
+ {0x43, 0x50, 0x50, 1, 1},
+ {0x44, 0x8, 0x8, 0, 0},
+ {0x45, 0x55, 0x55, 1, 1},
+ {0x46, 0, 0, 0, 0},
+ {0x47, 0x11, 0x11, 0, 0},
+ {0x48, 0, 0, 0, 0},
+ {0x49, 0x44, 0x44, 0, 0},
+ {0x4A, 0x7, 0x7, 0, 0},
+ {0x4B, 0x6, 0x6, 0, 0},
+ {0x4C, 0x4, 0x4, 0, 0},
+ {0x4D, 0, 0, 0, 0},
+ {0x4E, 0, 0, 0, 0},
+ {0x4F, 0x26, 0x26, 1, 1},
+ {0x50, 0x26, 0x26, 1, 1},
+ {0x51, 0xf, 0xf, 1, 1},
+ {0x52, 0xf, 0xf, 1, 1},
+ {0x53, 0x44, 0x44, 0, 0},
+ {0x54, 0, 0, 0, 0},
+ {0x55, 0, 0, 0, 0},
+ {0x56, 0x8, 0x8, 0, 0},
+ {0x57, 0x8, 0x8, 0, 0},
+ {0x58, 0x7, 0x7, 0, 0},
+ {0x59, 0x22, 0x22, 0, 0},
+ {0x5A, 0x22, 0x22, 0, 0},
+ {0x5B, 0x2, 0x2, 0, 0},
+ {0x5C, 0x2f, 0x2f, 1, 1},
+ {0x5D, 0x7, 0x7, 0, 0},
+ {0x5E, 0x55, 0x55, 0, 0},
+ {0x5F, 0x23, 0x23, 0, 0},
+ {0x60, 0x41, 0x41, 0, 0},
+ {0x61, 0x1, 0x1, 0, 0},
+ {0x62, 0xa, 0xa, 0, 0},
+ {0x63, 0, 0, 0, 0},
+ {0x64, 0, 0, 0, 0},
+ {0x65, 0, 0, 0, 0},
+ {0x66, 0, 0, 0, 0},
+ {0x67, 0, 0, 0, 0},
+ {0x68, 0, 0, 0, 0},
+ {0x69, 0, 0, 0, 0},
+ {0x6A, 0, 0, 0, 0},
+ {0x6B, 0xc, 0xc, 0, 0},
+ {0x6C, 0, 0, 0, 0},
+ {0x6D, 0, 0, 0, 0},
+ {0x6E, 0, 0, 0, 0},
+ {0x6F, 0, 0, 0, 0},
+ {0x70, 0, 0, 0, 0},
+ {0x71, 0, 0, 0, 0},
+ {0x72, 0x22, 0x22, 0, 0},
+ {0x73, 0x22, 0x22, 0, 0},
+ {0x74, 0, 0, 1, 1},
+ {0x75, 0xa, 0xa, 0, 0},
+ {0x76, 0x1, 0x1, 0, 0},
+ {0x77, 0x22, 0x22, 0, 0},
+ {0x78, 0x30, 0x30, 0, 0},
+ {0x79, 0, 0, 0, 0},
+ {0x7A, 0, 0, 0, 0},
+ {0x7B, 0, 0, 0, 0},
+ {0x7C, 0, 0, 0, 0},
+ {0x7D, 0, 0, 0, 0},
+ {0x7E, 0, 0, 0, 0},
+ {0x7F, 0, 0, 0, 0},
+ {0x80, 0, 0, 0, 0},
+ {0x81, 0, 0, 0, 0},
+ {0x82, 0, 0, 0, 0},
+ {0x83, 0, 0, 0, 0},
+ {0x84, 0, 0, 0, 0},
+ {0x85, 0, 0, 0, 0},
+ {0x86, 0, 0, 0, 0},
+ {0x87, 0, 0, 0, 0},
+ {0x88, 0, 0, 0, 0},
+ {0x89, 0, 0, 0, 0},
+ {0x8A, 0, 0, 0, 0},
+ {0x8B, 0, 0, 0, 0},
+ {0x8C, 0, 0, 0, 0},
+ {0x8D, 0, 0, 0, 0},
+ {0x8E, 0, 0, 0, 0},
+ {0x8F, 0, 0, 0, 0},
+ {0x90, 0, 0, 0, 0},
+ {0x91, 0, 0, 0, 0},
+ {0x92, 0, 0, 0, 0},
+ {0x93, 0, 0, 0, 0},
+ {0x94, 0, 0, 0, 0},
+ {0xFFFF, 0, 0, 0, 0}
+};
+
+static struct radio_regs regs_SYN_2056_rev5[] = {
+ {0x02, 0, 0, 0, 0},
+ {0x03, 0, 0, 0, 0},
+ {0x04, 0, 0, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0, 0, 0, 0},
+ {0x07, 0, 0, 0, 0},
+ {0x08, 0, 0, 0, 0},
+ {0x09, 0x1, 0x1, 0, 0},
+ {0x0A, 0, 0, 0, 0},
+ {0x0B, 0, 0, 0, 0},
+ {0x0C, 0, 0, 0, 0},
+ {0x0D, 0, 0, 0, 0},
+ {0x0E, 0, 0, 0, 0},
+ {0x0F, 0, 0, 0, 0},
+ {0x10, 0, 0, 0, 0},
+ {0x11, 0, 0, 0, 0},
+ {0x12, 0, 0, 0, 0},
+ {0x13, 0, 0, 0, 0},
+ {0x14, 0, 0, 0, 0},
+ {0x15, 0, 0, 0, 0},
+ {0x16, 0, 0, 0, 0},
+ {0x17, 0, 0, 0, 0},
+ {0x18, 0, 0, 0, 0},
+ {0x19, 0, 0, 0, 0},
+ {0x1A, 0, 0, 0, 0},
+ {0x1B, 0, 0, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0, 0, 0, 0},
+ {0x1E, 0, 0, 0, 0},
+ {0x1F, 0, 0, 0, 0},
+ {0x20, 0, 0, 0, 0},
+ {0x21, 0, 0, 0, 0},
+ {0x22, 0x60, 0x60, 0, 0},
+ {0x23, 0x6, 0x6, 0, 0},
+ {0x24, 0xc, 0xc, 0, 0},
+ {0x25, 0, 0, 0, 0},
+ {0x26, 0, 0, 0, 0},
+ {0x27, 0, 0, 0, 0},
+ {0x28, 0x1, 0x1, 0, 0},
+ {0x29, 0, 0, 0, 0},
+ {0x2A, 0, 0, 0, 0},
+ {0x2B, 0, 0, 0, 0},
+ {0x2C, 0, 0, 0, 0},
+ {0x2D, 0, 0, 0, 0},
+ {0x2E, 0, 0, 0, 0},
+ {0x2F, 0x1f, 0x1f, 0, 0},
+ {0x30, 0x15, 0x15, 0, 0},
+ {0x31, 0xf, 0xf, 0, 0},
+ {0x32, 0, 0, 0, 0},
+ {0x33, 0, 0, 0, 0},
+ {0x34, 0, 0, 0, 0},
+ {0x35, 0, 0, 0, 0},
+ {0x36, 0, 0, 0, 0},
+ {0x37, 0, 0, 0, 0},
+ {0x38, 0, 0, 0, 0},
+ {0x39, 0, 0, 0, 0},
+ {0x3A, 0, 0, 0, 0},
+ {0x3B, 0, 0, 0, 0},
+ {0x3C, 0x13, 0x13, 0, 0},
+ {0x3D, 0xf, 0xf, 0, 0},
+ {0x3E, 0x18, 0x18, 0, 0},
+ {0x3F, 0, 0, 0, 0},
+ {0x40, 0, 0, 0, 0},
+ {0x41, 0x20, 0x20, 0, 0},
+ {0x42, 0x20, 0x20, 0, 0},
+ {0x43, 0, 0, 0, 0},
+ {0x44, 0x77, 0x77, 0, 0},
+ {0x45, 0x7, 0x7, 0, 0},
+ {0x46, 0x1, 0x1, 0, 0},
+ {0x47, 0x4, 0x4, 0, 0},
+ {0x48, 0xf, 0xf, 0, 0},
+ {0x49, 0x30, 0x30, 0, 0},
+ {0x4A, 0x32, 0x32, 0, 0},
+ {0x4B, 0xd, 0xd, 0, 0},
+ {0x4C, 0xd, 0xd, 0, 0},
+ {0x4D, 0x4, 0x4, 0, 0},
+ {0x4E, 0x6, 0x6, 0, 0},
+ {0x4F, 0x1, 0x1, 0, 0},
+ {0x50, 0x1c, 0x1c, 0, 0},
+ {0x51, 0x2, 0x2, 0, 0},
+ {0x52, 0x2, 0x2, 0, 0},
+ {0x53, 0xf7, 0xf7, 1, 1},
+ {0x54, 0xb4, 0xb4, 0, 0},
+ {0x55, 0xd2, 0xd2, 0, 0},
+ {0x56, 0, 0, 0, 0},
+ {0x57, 0, 0, 0, 0},
+ {0x58, 0x4, 0x4, 0, 0},
+ {0x59, 0x96, 0x96, 0, 0},
+ {0x5A, 0x3e, 0x3e, 0, 0},
+ {0x5B, 0x3e, 0x3e, 0, 0},
+ {0x5C, 0x13, 0x13, 0, 0},
+ {0x5D, 0x2, 0x2, 0, 0},
+ {0x5E, 0, 0, 0, 0},
+ {0x5F, 0x7, 0x7, 0, 0},
+ {0x60, 0x7, 0x7, 1, 1},
+ {0x61, 0x8, 0x8, 0, 0},
+ {0x62, 0x3, 0x3, 0, 0},
+ {0x63, 0, 0, 0, 0},
+ {0x64, 0, 0, 0, 0},
+ {0x65, 0, 0, 0, 0},
+ {0x66, 0, 0, 0, 0},
+ {0x67, 0, 0, 0, 0},
+ {0x68, 0x40, 0x40, 0, 0},
+ {0x69, 0, 0, 0, 0},
+ {0x6A, 0, 0, 0, 0},
+ {0x6B, 0, 0, 0, 0},
+ {0x6C, 0, 0, 0, 0},
+ {0x6D, 0x1, 0x1, 0, 0},
+ {0x6E, 0, 0, 0, 0},
+ {0x6F, 0, 0, 0, 0},
+ {0x70, 0x60, 0x60, 0, 0},
+ {0x71, 0x66, 0x66, 0, 0},
+ {0x72, 0xc, 0xc, 0, 0},
+ {0x73, 0x66, 0x66, 0, 0},
+ {0x74, 0x8f, 0x8f, 1, 1},
+ {0x75, 0, 0, 0, 0},
+ {0x76, 0xcc, 0xcc, 0, 0},
+ {0x77, 0x1, 0x1, 0, 0},
+ {0x78, 0x66, 0x66, 0, 0},
+ {0x79, 0x66, 0x66, 0, 0},
+ {0x7A, 0, 0, 0, 0},
+ {0x7B, 0, 0, 0, 0},
+ {0x7C, 0, 0, 0, 0},
+ {0x7D, 0, 0, 0, 0},
+ {0x7E, 0, 0, 0, 0},
+ {0x7F, 0, 0, 0, 0},
+ {0x80, 0, 0, 0, 0},
+ {0x81, 0, 0, 0, 0},
+ {0x82, 0, 0, 0, 0},
+ {0x83, 0, 0, 0, 0},
+ {0x84, 0, 0, 0, 0},
+ {0x85, 0xff, 0xff, 0, 0},
+ {0x86, 0, 0, 0, 0},
+ {0x87, 0, 0, 0, 0},
+ {0x88, 0, 0, 0, 0},
+ {0x89, 0, 0, 0, 0},
+ {0x8A, 0, 0, 0, 0},
+ {0x8B, 0, 0, 0, 0},
+ {0x8C, 0, 0, 0, 0},
+ {0x8D, 0, 0, 0, 0},
+ {0x8E, 0, 0, 0, 0},
+ {0x8F, 0, 0, 0, 0},
+ {0x90, 0, 0, 0, 0},
+ {0x91, 0, 0, 0, 0},
+ {0x92, 0, 0, 0, 0},
+ {0x93, 0, 0, 0, 0},
+ {0x94, 0, 0, 0, 0},
+ {0x95, 0, 0, 0, 0},
+ {0x96, 0, 0, 0, 0},
+ {0x97, 0, 0, 0, 0},
+ {0x98, 0, 0, 0, 0},
+ {0x99, 0, 0, 0, 0},
+ {0x9A, 0, 0, 0, 0},
+ {0x9B, 0, 0, 0, 0},
+ {0x9C, 0, 0, 0, 0},
+ {0x9D, 0, 0, 0, 0},
+ {0x9E, 0, 0, 0, 0},
+ {0x9F, 0x6, 0x6, 0, 0},
+ {0xA0, 0x66, 0x66, 0, 0},
+ {0xA1, 0x66, 0x66, 0, 0},
+ {0xA2, 0x66, 0x66, 0, 0},
+ {0xA3, 0x66, 0x66, 0, 0},
+ {0xA4, 0x66, 0x66, 0, 0},
+ {0xA5, 0x66, 0x66, 0, 0},
+ {0xA6, 0x66, 0x66, 0, 0},
+ {0xA7, 0x66, 0x66, 0, 0},
+ {0xA8, 0x66, 0x66, 0, 0},
+ {0xA9, 0x66, 0x66, 0, 0},
+ {0xAA, 0x66, 0x66, 0, 0},
+ {0xAB, 0x66, 0x66, 0, 0},
+ {0xAC, 0x66, 0x66, 0, 0},
+ {0xAD, 0x66, 0x66, 0, 0},
+ {0xAE, 0x66, 0x66, 0, 0},
+ {0xAF, 0x66, 0x66, 0, 0},
+ {0xB0, 0x66, 0x66, 0, 0},
+ {0xB1, 0x66, 0x66, 0, 0},
+ {0xB2, 0x66, 0x66, 0, 0},
+ {0xB3, 0xa, 0xa, 0, 0},
+ {0xB4, 0, 0, 0, 0},
+ {0xB5, 0, 0, 0, 0},
+ {0xB6, 0, 0, 0, 0},
+ {0xFFFF, 0, 0, 0, 0}
+};
+
+static struct radio_regs regs_TX_2056_rev5[] = {
+ {0x02, 0, 0, 0, 0},
+ {0x03, 0, 0, 0, 0},
+ {0x04, 0, 0, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0, 0, 0, 0},
+ {0x07, 0, 0, 0, 0},
+ {0x08, 0, 0, 0, 0},
+ {0x09, 0, 0, 0, 0},
+ {0x0A, 0, 0, 0, 0},
+ {0x0B, 0, 0, 0, 0},
+ {0x0C, 0, 0, 0, 0},
+ {0x0D, 0, 0, 0, 0},
+ {0x0E, 0, 0, 0, 0},
+ {0x0F, 0, 0, 0, 0},
+ {0x10, 0, 0, 0, 0},
+ {0x11, 0, 0, 0, 0},
+ {0x12, 0, 0, 0, 0},
+ {0x13, 0, 0, 0, 0},
+ {0x14, 0, 0, 0, 0},
+ {0x15, 0, 0, 0, 0},
+ {0x16, 0, 0, 0, 0},
+ {0x17, 0, 0, 0, 0},
+ {0x18, 0, 0, 0, 0},
+ {0x19, 0, 0, 0, 0},
+ {0x1A, 0, 0, 0, 0},
+ {0x1B, 0, 0, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0, 0, 0, 0},
+ {0x1E, 0, 0, 0, 0},
+ {0x1F, 0, 0, 0, 0},
+ {0x20, 0, 0, 0, 0},
+ {0x21, 0x88, 0x88, 0, 0},
+ {0x22, 0x88, 0x88, 0, 0},
+ {0x23, 0x88, 0x88, 0, 0},
+ {0x24, 0x88, 0x88, 0, 0},
+ {0x25, 0xc, 0xc, 0, 0},
+ {0x26, 0, 0, 0, 0},
+ {0x27, 0x3, 0x3, 0, 0},
+ {0x28, 0, 0, 0, 0},
+ {0x29, 0x3, 0x3, 0, 0},
+ {0x2A, 0x37, 0x37, 0, 0},
+ {0x2B, 0x3, 0x3, 0, 0},
+ {0x2C, 0, 0, 0, 0},
+ {0x2D, 0, 0, 0, 0},
+ {0x2E, 0x1, 0x1, 0, 0},
+ {0x2F, 0x1, 0x1, 0, 0},
+ {0x30, 0, 0, 0, 0},
+ {0x31, 0, 0, 0, 0},
+ {0x32, 0, 0, 0, 0},
+ {0x33, 0x11, 0x11, 0, 0},
+ {0x34, 0x11, 0x11, 0, 0},
+ {0x35, 0, 0, 0, 0},
+ {0x36, 0, 0, 0, 0},
+ {0x37, 0x3, 0x3, 0, 0},
+ {0x38, 0xf, 0xf, 0, 0},
+ {0x39, 0, 0, 0, 0},
+ {0x3A, 0x2d, 0x2d, 0, 0},
+ {0x3B, 0, 0, 0, 0},
+ {0x3C, 0x6e, 0x6e, 0, 0},
+ {0x3D, 0xf0, 0xf0, 1, 1},
+ {0x3E, 0, 0, 0, 0},
+ {0x3F, 0, 0, 0, 0},
+ {0x40, 0, 0, 0, 0},
+ {0x41, 0x3, 0x3, 0, 0},
+ {0x42, 0x3, 0x3, 0, 0},
+ {0x43, 0, 0, 0, 0},
+ {0x44, 0x1e, 0x1e, 0, 0},
+ {0x45, 0, 0, 0, 0},
+ {0x46, 0x6e, 0x6e, 0, 0},
+ {0x47, 0xf0, 0xf0, 1, 1},
+ {0x48, 0, 0, 0, 0},
+ {0x49, 0x2, 0x2, 0, 0},
+ {0x4A, 0xff, 0xff, 1, 1},
+ {0x4B, 0xc, 0xc, 0, 0},
+ {0x4C, 0, 0, 0, 0},
+ {0x4D, 0x38, 0x38, 0, 0},
+ {0x4E, 0x70, 0x70, 1, 1},
+ {0x4F, 0x2, 0x2, 0, 0},
+ {0x50, 0x88, 0x88, 0, 0},
+ {0x51, 0xc, 0xc, 0, 0},
+ {0x52, 0, 0, 0, 0},
+ {0x53, 0x8, 0x8, 0, 0},
+ {0x54, 0x70, 0x70, 1, 1},
+ {0x55, 0x2, 0x2, 0, 0},
+ {0x56, 0xff, 0xff, 1, 1},
+ {0x57, 0, 0, 0, 0},
+ {0x58, 0x83, 0x83, 0, 0},
+ {0x59, 0x77, 0x77, 1, 1},
+ {0x5A, 0, 0, 0, 0},
+ {0x5B, 0x2, 0x2, 0, 0},
+ {0x5C, 0x88, 0x88, 0, 0},
+ {0x5D, 0, 0, 0, 0},
+ {0x5E, 0x8, 0x8, 0, 0},
+ {0x5F, 0x77, 0x77, 1, 1},
+ {0x60, 0x1, 0x1, 0, 0},
+ {0x61, 0, 0, 0, 0},
+ {0x62, 0x7, 0x7, 0, 0},
+ {0x63, 0, 0, 0, 0},
+ {0x64, 0x7, 0x7, 0, 0},
+ {0x65, 0, 0, 0, 0},
+ {0x66, 0, 0, 0, 0},
+ {0x67, 0, 0, 1, 1},
+ {0x68, 0, 0, 0, 0},
+ {0x69, 0xa, 0xa, 0, 0},
+ {0x6A, 0, 0, 0, 0},
+ {0x6B, 0, 0, 0, 0},
+ {0x6C, 0, 0, 0, 0},
+ {0x6D, 0, 0, 0, 0},
+ {0x6E, 0, 0, 0, 0},
+ {0x6F, 0, 0, 0, 0},
+ {0x70, 0, 0, 0, 0},
+ {0x71, 0x2, 0x2, 0, 0},
+ {0x72, 0, 0, 0, 0},
+ {0x73, 0, 0, 0, 0},
+ {0x74, 0xe, 0xe, 0, 0},
+ {0x75, 0xe, 0xe, 0, 0},
+ {0x76, 0xe, 0xe, 0, 0},
+ {0x77, 0x13, 0x13, 0, 0},
+ {0x78, 0x13, 0x13, 0, 0},
+ {0x79, 0x1b, 0x1b, 0, 0},
+ {0x7A, 0x1b, 0x1b, 0, 0},
+ {0x7B, 0x55, 0x55, 0, 0},
+ {0x7C, 0x5b, 0x5b, 0, 0},
+ {0x7D, 0, 0, 0, 0},
+ {0x7E, 0, 0, 0, 0},
+ {0x7F, 0, 0, 0, 0},
+ {0x80, 0, 0, 0, 0},
+ {0x81, 0, 0, 0, 0},
+ {0x82, 0, 0, 0, 0},
+ {0x83, 0, 0, 0, 0},
+ {0x84, 0, 0, 0, 0},
+ {0x85, 0, 0, 0, 0},
+ {0x86, 0, 0, 0, 0},
+ {0x87, 0, 0, 0, 0},
+ {0x88, 0, 0, 0, 0},
+ {0x89, 0, 0, 0, 0},
+ {0x8A, 0, 0, 0, 0},
+ {0x8B, 0, 0, 0, 0},
+ {0x8C, 0, 0, 0, 0},
+ {0x8D, 0, 0, 0, 0},
+ {0x8E, 0, 0, 0, 0},
+ {0x8F, 0, 0, 0, 0},
+ {0x90, 0, 0, 0, 0},
+ {0x91, 0, 0, 0, 0},
+ {0x92, 0, 0, 0, 0},
+ {0x93, 0x70, 0x70, 0, 0},
+ {0x94, 0x70, 0x70, 0, 0},
+ {0x95, 0x71, 0x71, 1, 1},
+ {0x96, 0x71, 0x71, 1, 1},
+ {0x97, 0x72, 0x72, 1, 1},
+ {0x98, 0x73, 0x73, 1, 1},
+ {0x99, 0x74, 0x74, 1, 1},
+ {0x9A, 0x75, 0x75, 1, 1},
+ {0xFFFF, 0, 0, 0, 0}
+};
+
+static struct radio_regs regs_RX_2056_rev5[] = {
+ {0x02, 0, 0, 0, 0},
+ {0x03, 0, 0, 0, 0},
+ {0x04, 0, 0, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0, 0, 0, 0},
+ {0x07, 0, 0, 0, 0},
+ {0x08, 0, 0, 0, 0},
+ {0x09, 0, 0, 0, 0},
+ {0x0A, 0, 0, 0, 0},
+ {0x0B, 0, 0, 0, 0},
+ {0x0C, 0, 0, 0, 0},
+ {0x0D, 0, 0, 0, 0},
+ {0x0E, 0, 0, 0, 0},
+ {0x0F, 0, 0, 0, 0},
+ {0x10, 0, 0, 0, 0},
+ {0x11, 0, 0, 0, 0},
+ {0x12, 0, 0, 0, 0},
+ {0x13, 0, 0, 0, 0},
+ {0x14, 0, 0, 0, 0},
+ {0x15, 0, 0, 0, 0},
+ {0x16, 0, 0, 0, 0},
+ {0x17, 0, 0, 0, 0},
+ {0x18, 0, 0, 0, 0},
+ {0x19, 0, 0, 0, 0},
+ {0x1A, 0, 0, 0, 0},
+ {0x1B, 0, 0, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0, 0, 0, 0},
+ {0x1E, 0, 0, 0, 0},
+ {0x1F, 0, 0, 0, 0},
+ {0x20, 0x3, 0x3, 0, 0},
+ {0x21, 0, 0, 0, 0},
+ {0x22, 0, 0, 0, 0},
+ {0x23, 0x90, 0x90, 0, 0},
+ {0x24, 0x55, 0x55, 0, 0},
+ {0x25, 0x15, 0x15, 0, 0},
+ {0x26, 0x5, 0x5, 0, 0},
+ {0x27, 0x15, 0x15, 0, 0},
+ {0x28, 0x5, 0x5, 0, 0},
+ {0x29, 0x20, 0x20, 0, 0},
+ {0x2A, 0x11, 0x11, 0, 0},
+ {0x2B, 0x90, 0x90, 0, 0},
+ {0x2C, 0, 0, 0, 0},
+ {0x2D, 0x88, 0x88, 0, 0},
+ {0x2E, 0x32, 0x32, 0, 0},
+ {0x2F, 0x77, 0x77, 0, 0},
+ {0x30, 0x17, 0x17, 1, 1},
+ {0x31, 0xff, 0xff, 1, 1},
+ {0x32, 0x20, 0x20, 0, 0},
+ {0x33, 0, 0, 0, 0},
+ {0x34, 0x88, 0x88, 0, 0},
+ {0x35, 0x32, 0x32, 0, 0},
+ {0x36, 0x77, 0x77, 0, 0},
+ {0x37, 0x17, 0x17, 1, 1},
+ {0x38, 0xf0, 0xf0, 1, 1},
+ {0x39, 0x20, 0x20, 0, 0},
+ {0x3A, 0x8, 0x8, 0, 0},
+ {0x3B, 0x55, 0x55, 1, 1},
+ {0x3C, 0, 0, 0, 0},
+ {0x3D, 0x88, 0x88, 1, 1},
+ {0x3E, 0, 0, 0, 0},
+ {0x3F, 0, 0, 1, 1},
+ {0x40, 0x7, 0x7, 1, 1},
+ {0x41, 0x6, 0x6, 0, 0},
+ {0x42, 0x4, 0x4, 0, 0},
+ {0x43, 0, 0, 0, 0},
+ {0x44, 0x8, 0x8, 0, 0},
+ {0x45, 0x55, 0x55, 1, 1},
+ {0x46, 0, 0, 0, 0},
+ {0x47, 0x11, 0x11, 0, 0},
+ {0x48, 0, 0, 0, 0},
+ {0x49, 0, 0, 1, 1},
+ {0x4A, 0x7, 0x7, 0, 0},
+ {0x4B, 0x6, 0x6, 0, 0},
+ {0x4C, 0x4, 0x4, 0, 0},
+ {0x4D, 0, 0, 0, 0},
+ {0x4E, 0, 0, 0, 0},
+ {0x4F, 0x26, 0x26, 1, 1},
+ {0x50, 0x26, 0x26, 1, 1},
+ {0x51, 0xf, 0xf, 1, 1},
+ {0x52, 0xf, 0xf, 1, 1},
+ {0x53, 0x44, 0x44, 0, 0},
+ {0x54, 0, 0, 0, 0},
+ {0x55, 0, 0, 0, 0},
+ {0x56, 0x8, 0x8, 0, 0},
+ {0x57, 0x8, 0x8, 0, 0},
+ {0x58, 0x7, 0x7, 0, 0},
+ {0x59, 0x22, 0x22, 0, 0},
+ {0x5A, 0x22, 0x22, 0, 0},
+ {0x5B, 0x2, 0x2, 0, 0},
+ {0x5C, 0x4, 0x4, 1, 1},
+ {0x5D, 0x7, 0x7, 0, 0},
+ {0x5E, 0x55, 0x55, 0, 0},
+ {0x5F, 0x23, 0x23, 0, 0},
+ {0x60, 0x41, 0x41, 0, 0},
+ {0x61, 0x1, 0x1, 0, 0},
+ {0x62, 0xa, 0xa, 0, 0},
+ {0x63, 0, 0, 0, 0},
+ {0x64, 0, 0, 0, 0},
+ {0x65, 0, 0, 0, 0},
+ {0x66, 0, 0, 0, 0},
+ {0x67, 0, 0, 0, 0},
+ {0x68, 0, 0, 0, 0},
+ {0x69, 0, 0, 0, 0},
+ {0x6A, 0, 0, 0, 0},
+ {0x6B, 0xc, 0xc, 0, 0},
+ {0x6C, 0, 0, 0, 0},
+ {0x6D, 0, 0, 0, 0},
+ {0x6E, 0, 0, 0, 0},
+ {0x6F, 0, 0, 0, 0},
+ {0x70, 0, 0, 0, 0},
+ {0x71, 0, 0, 0, 0},
+ {0x72, 0x22, 0x22, 0, 0},
+ {0x73, 0x22, 0x22, 0, 0},
+ {0x74, 0, 0, 1, 1},
+ {0x75, 0xa, 0xa, 0, 0},
+ {0x76, 0x1, 0x1, 0, 0},
+ {0x77, 0x22, 0x22, 0, 0},
+ {0x78, 0x30, 0x30, 0, 0},
+ {0x79, 0, 0, 0, 0},
+ {0x7A, 0, 0, 0, 0},
+ {0x7B, 0, 0, 0, 0},
+ {0x7C, 0, 0, 0, 0},
+ {0x7D, 0, 0, 0, 0},
+ {0x7E, 0, 0, 0, 0},
+ {0x7F, 0, 0, 0, 0},
+ {0x80, 0, 0, 0, 0},
+ {0x81, 0, 0, 0, 0},
+ {0x82, 0, 0, 0, 0},
+ {0x83, 0, 0, 0, 0},
+ {0x84, 0, 0, 0, 0},
+ {0x85, 0, 0, 0, 0},
+ {0x86, 0, 0, 0, 0},
+ {0x87, 0, 0, 0, 0},
+ {0x88, 0, 0, 0, 0},
+ {0x89, 0, 0, 0, 0},
+ {0x8A, 0, 0, 0, 0},
+ {0x8B, 0, 0, 0, 0},
+ {0x8C, 0, 0, 0, 0},
+ {0x8D, 0, 0, 0, 0},
+ {0x8E, 0, 0, 0, 0},
+ {0x8F, 0, 0, 0, 0},
+ {0x90, 0, 0, 0, 0},
+ {0x91, 0, 0, 0, 0},
+ {0x92, 0, 0, 0, 0},
+ {0x93, 0, 0, 0, 0},
+ {0x94, 0, 0, 0, 0},
+ {0xFFFF, 0, 0, 0, 0}
+};
+
+static struct radio_regs regs_SYN_2056_rev6[] = {
+ {0x02, 0, 0, 0, 0},
+ {0x03, 0, 0, 0, 0},
+ {0x04, 0, 0, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0, 0, 0, 0},
+ {0x07, 0, 0, 0, 0},
+ {0x08, 0, 0, 0, 0},
+ {0x09, 0x1, 0x1, 0, 0},
+ {0x0A, 0, 0, 0, 0},
+ {0x0B, 0, 0, 0, 0},
+ {0x0C, 0, 0, 0, 0},
+ {0x0D, 0, 0, 0, 0},
+ {0x0E, 0, 0, 0, 0},
+ {0x0F, 0, 0, 0, 0},
+ {0x10, 0, 0, 0, 0},
+ {0x11, 0, 0, 0, 0},
+ {0x12, 0, 0, 0, 0},
+ {0x13, 0, 0, 0, 0},
+ {0x14, 0, 0, 0, 0},
+ {0x15, 0, 0, 0, 0},
+ {0x16, 0, 0, 0, 0},
+ {0x17, 0, 0, 0, 0},
+ {0x18, 0, 0, 0, 0},
+ {0x19, 0, 0, 0, 0},
+ {0x1A, 0, 0, 0, 0},
+ {0x1B, 0, 0, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0, 0, 0, 0},
+ {0x1E, 0, 0, 0, 0},
+ {0x1F, 0, 0, 0, 0},
+ {0x20, 0, 0, 0, 0},
+ {0x21, 0, 0, 0, 0},
+ {0x22, 0x60, 0x60, 0, 0},
+ {0x23, 0x6, 0x6, 0, 0},
+ {0x24, 0xc, 0xc, 0, 0},
+ {0x25, 0, 0, 0, 0},
+ {0x26, 0, 0, 0, 0},
+ {0x27, 0, 0, 0, 0},
+ {0x28, 0x1, 0x1, 0, 0},
+ {0x29, 0, 0, 0, 0},
+ {0x2A, 0, 0, 0, 0},
+ {0x2B, 0, 0, 0, 0},
+ {0x2C, 0, 0, 0, 0},
+ {0x2D, 0, 0, 0, 0},
+ {0x2E, 0, 0, 0, 0},
+ {0x2F, 0x1f, 0x1f, 0, 0},
+ {0x30, 0x15, 0x15, 0, 0},
+ {0x31, 0xf, 0xf, 0, 0},
+ {0x32, 0, 0, 0, 0},
+ {0x33, 0, 0, 0, 0},
+ {0x34, 0, 0, 0, 0},
+ {0x35, 0, 0, 0, 0},
+ {0x36, 0, 0, 0, 0},
+ {0x37, 0, 0, 0, 0},
+ {0x38, 0, 0, 0, 0},
+ {0x39, 0, 0, 0, 0},
+ {0x3A, 0, 0, 0, 0},
+ {0x3B, 0, 0, 0, 0},
+ {0x3C, 0x13, 0x13, 0, 0},
+ {0x3D, 0xf, 0xf, 0, 0},
+ {0x3E, 0x18, 0x18, 0, 0},
+ {0x3F, 0, 0, 0, 0},
+ {0x40, 0, 0, 0, 0},
+ {0x41, 0x20, 0x20, 0, 0},
+ {0x42, 0x20, 0x20, 0, 0},
+ {0x43, 0, 0, 0, 0},
+ {0x44, 0x77, 0x77, 0, 0},
+ {0x45, 0x7, 0x7, 0, 0},
+ {0x46, 0x1, 0x1, 0, 0},
+ {0x47, 0x4, 0x4, 0, 0},
+ {0x48, 0xf, 0xf, 0, 0},
+ {0x49, 0x30, 0x30, 0, 0},
+ {0x4A, 0x32, 0x32, 0, 0},
+ {0x4B, 0xd, 0xd, 0, 0},
+ {0x4C, 0xd, 0xd, 0, 0},
+ {0x4D, 0x4, 0x4, 0, 0},
+ {0x4E, 0x6, 0x6, 0, 0},
+ {0x4F, 0x1, 0x1, 0, 0},
+ {0x50, 0x1c, 0x1c, 0, 0},
+ {0x51, 0x2, 0x2, 0, 0},
+ {0x52, 0x2, 0x2, 0, 0},
+ {0x53, 0xf7, 0xf7, 1, 1},
+ {0x54, 0xb4, 0xb4, 0, 0},
+ {0x55, 0xd2, 0xd2, 0, 0},
+ {0x56, 0, 0, 0, 0},
+ {0x57, 0, 0, 0, 0},
+ {0x58, 0x4, 0x4, 0, 0},
+ {0x59, 0x96, 0x96, 0, 0},
+ {0x5A, 0x3e, 0x3e, 0, 0},
+ {0x5B, 0x3e, 0x3e, 0, 0},
+ {0x5C, 0x13, 0x13, 0, 0},
+ {0x5D, 0x2, 0x2, 0, 0},
+ {0x5E, 0, 0, 0, 0},
+ {0x5F, 0x7, 0x7, 0, 0},
+ {0x60, 0x7, 0x7, 1, 1},
+ {0x61, 0x8, 0x8, 0, 0},
+ {0x62, 0x3, 0x3, 0, 0},
+ {0x63, 0, 0, 0, 0},
+ {0x64, 0, 0, 0, 0},
+ {0x65, 0, 0, 0, 0},
+ {0x66, 0, 0, 0, 0},
+ {0x67, 0, 0, 0, 0},
+ {0x68, 0x40, 0x40, 0, 0},
+ {0x69, 0, 0, 0, 0},
+ {0x6A, 0, 0, 0, 0},
+ {0x6B, 0, 0, 0, 0},
+ {0x6C, 0, 0, 0, 0},
+ {0x6D, 0x1, 0x1, 0, 0},
+ {0x6E, 0, 0, 0, 0},
+ {0x6F, 0, 0, 0, 0},
+ {0x70, 0x60, 0x60, 0, 0},
+ {0x71, 0x66, 0x66, 0, 0},
+ {0x72, 0xc, 0xc, 0, 0},
+ {0x73, 0x66, 0x66, 0, 0},
+ {0x74, 0x8f, 0x8f, 1, 1},
+ {0x75, 0, 0, 0, 0},
+ {0x76, 0xcc, 0xcc, 0, 0},
+ {0x77, 0x1, 0x1, 0, 0},
+ {0x78, 0x66, 0x66, 0, 0},
+ {0x79, 0x66, 0x66, 0, 0},
+ {0x7A, 0, 0, 0, 0},
+ {0x7B, 0, 0, 0, 0},
+ {0x7C, 0, 0, 0, 0},
+ {0x7D, 0, 0, 0, 0},
+ {0x7E, 0, 0, 0, 0},
+ {0x7F, 0, 0, 0, 0},
+ {0x80, 0, 0, 0, 0},
+ {0x81, 0, 0, 0, 0},
+ {0x82, 0, 0, 0, 0},
+ {0x83, 0, 0, 0, 0},
+ {0x84, 0, 0, 0, 0},
+ {0x85, 0xff, 0xff, 0, 0},
+ {0x86, 0, 0, 0, 0},
+ {0x87, 0, 0, 0, 0},
+ {0x88, 0, 0, 0, 0},
+ {0x89, 0, 0, 0, 0},
+ {0x8A, 0, 0, 0, 0},
+ {0x8B, 0, 0, 0, 0},
+ {0x8C, 0, 0, 0, 0},
+ {0x8D, 0, 0, 0, 0},
+ {0x8E, 0, 0, 0, 0},
+ {0x8F, 0, 0, 0, 0},
+ {0x90, 0, 0, 0, 0},
+ {0x91, 0, 0, 0, 0},
+ {0x92, 0, 0, 0, 0},
+ {0x93, 0, 0, 0, 0},
+ {0x94, 0, 0, 0, 0},
+ {0x95, 0, 0, 0, 0},
+ {0x96, 0, 0, 0, 0},
+ {0x97, 0, 0, 0, 0},
+ {0x98, 0, 0, 0, 0},
+ {0x99, 0, 0, 0, 0},
+ {0x9A, 0, 0, 0, 0},
+ {0x9B, 0, 0, 0, 0},
+ {0x9C, 0, 0, 0, 0},
+ {0x9D, 0, 0, 0, 0},
+ {0x9E, 0, 0, 0, 0},
+ {0x9F, 0x6, 0x6, 0, 0},
+ {0xA0, 0x66, 0x66, 0, 0},
+ {0xA1, 0x66, 0x66, 0, 0},
+ {0xA2, 0x66, 0x66, 0, 0},
+ {0xA3, 0x66, 0x66, 0, 0},
+ {0xA4, 0x66, 0x66, 0, 0},
+ {0xA5, 0x66, 0x66, 0, 0},
+ {0xA6, 0x66, 0x66, 0, 0},
+ {0xA7, 0x66, 0x66, 0, 0},
+ {0xA8, 0x66, 0x66, 0, 0},
+ {0xA9, 0x66, 0x66, 0, 0},
+ {0xAA, 0x66, 0x66, 0, 0},
+ {0xAB, 0x66, 0x66, 0, 0},
+ {0xAC, 0x66, 0x66, 0, 0},
+ {0xAD, 0x66, 0x66, 0, 0},
+ {0xAE, 0x66, 0x66, 0, 0},
+ {0xAF, 0x66, 0x66, 0, 0},
+ {0xB0, 0x66, 0x66, 0, 0},
+ {0xB1, 0x66, 0x66, 0, 0},
+ {0xB2, 0x66, 0x66, 0, 0},
+ {0xB3, 0xa, 0xa, 0, 0},
+ {0xB4, 0, 0, 0, 0},
+ {0xB5, 0, 0, 0, 0},
+ {0xB6, 0, 0, 0, 0},
+ {0xFFFF, 0, 0, 0, 0}
+};
+
+static struct radio_regs regs_TX_2056_rev6[] = {
+ {0x02, 0, 0, 0, 0},
+ {0x03, 0, 0, 0, 0},
+ {0x04, 0, 0, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0, 0, 0, 0},
+ {0x07, 0, 0, 0, 0},
+ {0x08, 0, 0, 0, 0},
+ {0x09, 0, 0, 0, 0},
+ {0x0A, 0, 0, 0, 0},
+ {0x0B, 0, 0, 0, 0},
+ {0x0C, 0, 0, 0, 0},
+ {0x0D, 0, 0, 0, 0},
+ {0x0E, 0, 0, 0, 0},
+ {0x0F, 0, 0, 0, 0},
+ {0x10, 0, 0, 0, 0},
+ {0x11, 0, 0, 0, 0},
+ {0x12, 0, 0, 0, 0},
+ {0x13, 0, 0, 0, 0},
+ {0x14, 0, 0, 0, 0},
+ {0x15, 0, 0, 0, 0},
+ {0x16, 0, 0, 0, 0},
+ {0x17, 0, 0, 0, 0},
+ {0x18, 0, 0, 0, 0},
+ {0x19, 0, 0, 0, 0},
+ {0x1A, 0, 0, 0, 0},
+ {0x1B, 0, 0, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0, 0, 0, 0},
+ {0x1E, 0, 0, 0, 0},
+ {0x1F, 0, 0, 0, 0},
+ {0x20, 0, 0, 0, 0},
+ {0x21, 0x88, 0x88, 0, 0},
+ {0x22, 0x88, 0x88, 0, 0},
+ {0x23, 0x88, 0x88, 0, 0},
+ {0x24, 0x88, 0x88, 0, 0},
+ {0x25, 0xc, 0xc, 0, 0},
+ {0x26, 0, 0, 0, 0},
+ {0x27, 0x3, 0x3, 0, 0},
+ {0x28, 0, 0, 0, 0},
+ {0x29, 0x3, 0x3, 0, 0},
+ {0x2A, 0x37, 0x37, 0, 0},
+ {0x2B, 0x3, 0x3, 0, 0},
+ {0x2C, 0, 0, 0, 0},
+ {0x2D, 0, 0, 0, 0},
+ {0x2E, 0x1, 0x1, 0, 0},
+ {0x2F, 0x1, 0x1, 0, 0},
+ {0x30, 0, 0, 0, 0},
+ {0x31, 0, 0, 0, 0},
+ {0x32, 0, 0, 0, 0},
+ {0x33, 0x11, 0x11, 0, 0},
+ {0x34, 0xee, 0xee, 1, 1},
+ {0x35, 0, 0, 0, 0},
+ {0x36, 0, 0, 0, 0},
+ {0x37, 0x3, 0x3, 0, 0},
+ {0x38, 0x50, 0x50, 1, 1},
+ {0x39, 0, 0, 0, 0},
+ {0x3A, 0x50, 0x50, 1, 1},
+ {0x3B, 0, 0, 0, 0},
+ {0x3C, 0x6e, 0x6e, 0, 0},
+ {0x3D, 0xf0, 0xf0, 1, 1},
+ {0x3E, 0, 0, 0, 0},
+ {0x3F, 0, 0, 0, 0},
+ {0x40, 0, 0, 0, 0},
+ {0x41, 0x3, 0x3, 0, 0},
+ {0x42, 0x3, 0x3, 0, 0},
+ {0x43, 0, 0, 0, 0},
+ {0x44, 0x1e, 0x1e, 0, 0},
+ {0x45, 0, 0, 0, 0},
+ {0x46, 0x6e, 0x6e, 0, 0},
+ {0x47, 0xf0, 0xf0, 1, 1},
+ {0x48, 0, 0, 0, 0},
+ {0x49, 0x2, 0x2, 0, 0},
+ {0x4A, 0xff, 0xff, 1, 1},
+ {0x4B, 0xc, 0xc, 0, 0},
+ {0x4C, 0, 0, 0, 0},
+ {0x4D, 0x38, 0x38, 0, 0},
+ {0x4E, 0x70, 0x70, 1, 1},
+ {0x4F, 0x2, 0x2, 0, 0},
+ {0x50, 0x88, 0x88, 0, 0},
+ {0x51, 0xc, 0xc, 0, 0},
+ {0x52, 0, 0, 0, 0},
+ {0x53, 0x8, 0x8, 0, 0},
+ {0x54, 0x70, 0x70, 1, 1},
+ {0x55, 0x2, 0x2, 0, 0},
+ {0x56, 0xff, 0xff, 1, 1},
+ {0x57, 0, 0, 0, 0},
+ {0x58, 0x83, 0x83, 0, 0},
+ {0x59, 0x77, 0x77, 1, 1},
+ {0x5A, 0, 0, 0, 0},
+ {0x5B, 0x2, 0x2, 0, 0},
+ {0x5C, 0x88, 0x88, 0, 0},
+ {0x5D, 0, 0, 0, 0},
+ {0x5E, 0x8, 0x8, 0, 0},
+ {0x5F, 0x77, 0x77, 1, 1},
+ {0x60, 0x1, 0x1, 0, 0},
+ {0x61, 0, 0, 0, 0},
+ {0x62, 0x7, 0x7, 0, 0},
+ {0x63, 0, 0, 0, 0},
+ {0x64, 0x7, 0x7, 0, 0},
+ {0x65, 0, 0, 0, 0},
+ {0x66, 0, 0, 0, 0},
+ {0x67, 0, 0, 1, 1},
+ {0x68, 0, 0, 0, 0},
+ {0x69, 0xa, 0xa, 0, 0},
+ {0x6A, 0, 0, 0, 0},
+ {0x6B, 0, 0, 0, 0},
+ {0x6C, 0, 0, 0, 0},
+ {0x6D, 0, 0, 0, 0},
+ {0x6E, 0, 0, 0, 0},
+ {0x6F, 0, 0, 0, 0},
+ {0x70, 0, 0, 0, 0},
+ {0x71, 0x2, 0x2, 0, 0},
+ {0x72, 0, 0, 0, 0},
+ {0x73, 0, 0, 0, 0},
+ {0x74, 0xe, 0xe, 0, 0},
+ {0x75, 0xe, 0xe, 0, 0},
+ {0x76, 0xe, 0xe, 0, 0},
+ {0x77, 0x13, 0x13, 0, 0},
+ {0x78, 0x13, 0x13, 0, 0},
+ {0x79, 0x1b, 0x1b, 0, 0},
+ {0x7A, 0x1b, 0x1b, 0, 0},
+ {0x7B, 0x55, 0x55, 0, 0},
+ {0x7C, 0x5b, 0x5b, 0, 0},
+ {0x7D, 0x30, 0x30, 1, 1},
+ {0x7E, 0, 0, 0, 0},
+ {0x7F, 0, 0, 0, 0},
+ {0x80, 0, 0, 0, 0},
+ {0x81, 0, 0, 0, 0},
+ {0x82, 0, 0, 0, 0},
+ {0x83, 0, 0, 0, 0},
+ {0x84, 0, 0, 0, 0},
+ {0x85, 0, 0, 0, 0},
+ {0x86, 0, 0, 0, 0},
+ {0x87, 0, 0, 0, 0},
+ {0x88, 0, 0, 0, 0},
+ {0x89, 0, 0, 0, 0},
+ {0x8A, 0, 0, 0, 0},
+ {0x8B, 0, 0, 0, 0},
+ {0x8C, 0, 0, 0, 0},
+ {0x8D, 0, 0, 0, 0},
+ {0x8E, 0, 0, 0, 0},
+ {0x8F, 0, 0, 0, 0},
+ {0x90, 0, 0, 0, 0},
+ {0x91, 0, 0, 0, 0},
+ {0x92, 0, 0, 0, 0},
+ {0x93, 0x70, 0x70, 0, 0},
+ {0x94, 0x70, 0x70, 0, 0},
+ {0x95, 0x70, 0x70, 0, 0},
+ {0x96, 0x70, 0x70, 0, 0},
+ {0x97, 0x70, 0x70, 0, 0},
+ {0x98, 0x70, 0x70, 0, 0},
+ {0x99, 0x70, 0x70, 0, 0},
+ {0x9A, 0x70, 0x70, 0, 0},
+ {0xFFFF, 0, 0, 0, 0}
+};
+
+static struct radio_regs regs_RX_2056_rev6[] = {
+ {0x02, 0, 0, 0, 0},
+ {0x03, 0, 0, 0, 0},
+ {0x04, 0, 0, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0, 0, 0, 0},
+ {0x07, 0, 0, 0, 0},
+ {0x08, 0, 0, 0, 0},
+ {0x09, 0, 0, 0, 0},
+ {0x0A, 0, 0, 0, 0},
+ {0x0B, 0, 0, 0, 0},
+ {0x0C, 0, 0, 0, 0},
+ {0x0D, 0, 0, 0, 0},
+ {0x0E, 0, 0, 0, 0},
+ {0x0F, 0, 0, 0, 0},
+ {0x10, 0, 0, 0, 0},
+ {0x11, 0, 0, 0, 0},
+ {0x12, 0, 0, 0, 0},
+ {0x13, 0, 0, 0, 0},
+ {0x14, 0, 0, 0, 0},
+ {0x15, 0, 0, 0, 0},
+ {0x16, 0, 0, 0, 0},
+ {0x17, 0, 0, 0, 0},
+ {0x18, 0, 0, 0, 0},
+ {0x19, 0, 0, 0, 0},
+ {0x1A, 0, 0, 0, 0},
+ {0x1B, 0, 0, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0, 0, 0, 0},
+ {0x1E, 0, 0, 0, 0},
+ {0x1F, 0, 0, 0, 0},
+ {0x20, 0x3, 0x3, 0, 0},
+ {0x21, 0, 0, 0, 0},
+ {0x22, 0, 0, 0, 0},
+ {0x23, 0x90, 0x90, 0, 0},
+ {0x24, 0x55, 0x55, 0, 0},
+ {0x25, 0x15, 0x15, 0, 0},
+ {0x26, 0x5, 0x5, 0, 0},
+ {0x27, 0x15, 0x15, 0, 0},
+ {0x28, 0x5, 0x5, 0, 0},
+ {0x29, 0x20, 0x20, 0, 0},
+ {0x2A, 0x11, 0x11, 0, 0},
+ {0x2B, 0x90, 0x90, 0, 0},
+ {0x2C, 0, 0, 0, 0},
+ {0x2D, 0x88, 0x88, 0, 0},
+ {0x2E, 0x32, 0x32, 0, 0},
+ {0x2F, 0x77, 0x77, 0, 0},
+ {0x30, 0x17, 0x17, 1, 1},
+ {0x31, 0xff, 0xff, 1, 1},
+ {0x32, 0x20, 0x20, 0, 0},
+ {0x33, 0, 0, 0, 0},
+ {0x34, 0x88, 0x88, 0, 0},
+ {0x35, 0x32, 0x32, 0, 0},
+ {0x36, 0x77, 0x77, 0, 0},
+ {0x37, 0x17, 0x17, 1, 1},
+ {0x38, 0xf0, 0xf0, 1, 1},
+ {0x39, 0x20, 0x20, 0, 0},
+ {0x3A, 0x8, 0x8, 0, 0},
+ {0x3B, 0x55, 0x55, 1, 1},
+ {0x3C, 0, 0, 0, 0},
+ {0x3D, 0x88, 0x88, 1, 1},
+ {0x3E, 0, 0, 0, 0},
+ {0x3F, 0x44, 0x44, 0, 0},
+ {0x40, 0x7, 0x7, 1, 1},
+ {0x41, 0x6, 0x6, 0, 0},
+ {0x42, 0x4, 0x4, 0, 0},
+ {0x43, 0, 0, 0, 0},
+ {0x44, 0x8, 0x8, 0, 0},
+ {0x45, 0x55, 0x55, 1, 1},
+ {0x46, 0, 0, 0, 0},
+ {0x47, 0x11, 0x11, 0, 0},
+ {0x48, 0, 0, 0, 0},
+ {0x49, 0x44, 0x44, 0, 0},
+ {0x4A, 0x7, 0x7, 0, 0},
+ {0x4B, 0x6, 0x6, 0, 0},
+ {0x4C, 0x4, 0x4, 0, 0},
+ {0x4D, 0, 0, 0, 0},
+ {0x4E, 0, 0, 0, 0},
+ {0x4F, 0x26, 0x26, 1, 1},
+ {0x50, 0x26, 0x26, 1, 1},
+ {0x51, 0xf, 0xf, 1, 1},
+ {0x52, 0xf, 0xf, 1, 1},
+ {0x53, 0x44, 0x44, 0, 0},
+ {0x54, 0, 0, 0, 0},
+ {0x55, 0, 0, 0, 0},
+ {0x56, 0x8, 0x8, 0, 0},
+ {0x57, 0x8, 0x8, 0, 0},
+ {0x58, 0x7, 0x7, 0, 0},
+ {0x59, 0x22, 0x22, 0, 0},
+ {0x5A, 0x22, 0x22, 0, 0},
+ {0x5B, 0x2, 0x2, 0, 0},
+ {0x5C, 0x4, 0x4, 1, 1},
+ {0x5D, 0x7, 0x7, 0, 0},
+ {0x5E, 0x55, 0x55, 0, 0},
+ {0x5F, 0x23, 0x23, 0, 0},
+ {0x60, 0x41, 0x41, 0, 0},
+ {0x61, 0x1, 0x1, 0, 0},
+ {0x62, 0xa, 0xa, 0, 0},
+ {0x63, 0, 0, 0, 0},
+ {0x64, 0, 0, 0, 0},
+ {0x65, 0, 0, 0, 0},
+ {0x66, 0, 0, 0, 0},
+ {0x67, 0, 0, 0, 0},
+ {0x68, 0, 0, 0, 0},
+ {0x69, 0, 0, 0, 0},
+ {0x6A, 0, 0, 0, 0},
+ {0x6B, 0xc, 0xc, 0, 0},
+ {0x6C, 0, 0, 0, 0},
+ {0x6D, 0, 0, 0, 0},
+ {0x6E, 0, 0, 0, 0},
+ {0x6F, 0, 0, 0, 0},
+ {0x70, 0, 0, 0, 0},
+ {0x71, 0, 0, 0, 0},
+ {0x72, 0x22, 0x22, 0, 0},
+ {0x73, 0x22, 0x22, 0, 0},
+ {0x74, 0, 0, 1, 1},
+ {0x75, 0xa, 0xa, 0, 0},
+ {0x76, 0x1, 0x1, 0, 0},
+ {0x77, 0x22, 0x22, 0, 0},
+ {0x78, 0x30, 0x30, 0, 0},
+ {0x79, 0, 0, 0, 0},
+ {0x7A, 0, 0, 0, 0},
+ {0x7B, 0, 0, 0, 0},
+ {0x7C, 0, 0, 0, 0},
+ {0x7D, 0x5, 0x5, 1, 1},
+ {0x7E, 0, 0, 0, 0},
+ {0x7F, 0, 0, 0, 0},
+ {0x80, 0, 0, 0, 0},
+ {0x81, 0, 0, 0, 0},
+ {0x82, 0, 0, 0, 0},
+ {0x83, 0, 0, 0, 0},
+ {0x84, 0, 0, 0, 0},
+ {0x85, 0, 0, 0, 0},
+ {0x86, 0, 0, 0, 0},
+ {0x87, 0, 0, 0, 0},
+ {0x88, 0, 0, 0, 0},
+ {0x89, 0, 0, 0, 0},
+ {0x8A, 0, 0, 0, 0},
+ {0x8B, 0, 0, 0, 0},
+ {0x8C, 0, 0, 0, 0},
+ {0x8D, 0, 0, 0, 0},
+ {0x8E, 0, 0, 0, 0},
+ {0x8F, 0, 0, 0, 0},
+ {0x90, 0, 0, 0, 0},
+ {0x91, 0, 0, 0, 0},
+ {0x92, 0, 0, 0, 0},
+ {0x93, 0, 0, 0, 0},
+ {0x94, 0, 0, 0, 0},
+ {0xFFFF, 0, 0, 0, 0}
+};
+
+static struct radio_regs regs_SYN_2056_rev7[] = {
+ {0x02, 0, 0, 0, 0},
+ {0x03, 0, 0, 0, 0},
+ {0x04, 0, 0, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0, 0, 0, 0},
+ {0x07, 0, 0, 0, 0},
+ {0x08, 0, 0, 0, 0},
+ {0x09, 0x1, 0x1, 0, 0},
+ {0x0A, 0, 0, 0, 0},
+ {0x0B, 0, 0, 0, 0},
+ {0x0C, 0, 0, 0, 0},
+ {0x0D, 0, 0, 0, 0},
+ {0x0E, 0, 0, 0, 0},
+ {0x0F, 0, 0, 0, 0},
+ {0x10, 0, 0, 0, 0},
+ {0x11, 0, 0, 0, 0},
+ {0x12, 0, 0, 0, 0},
+ {0x13, 0, 0, 0, 0},
+ {0x14, 0, 0, 0, 0},
+ {0x15, 0, 0, 0, 0},
+ {0x16, 0, 0, 0, 0},
+ {0x17, 0, 0, 0, 0},
+ {0x18, 0, 0, 0, 0},
+ {0x19, 0, 0, 0, 0},
+ {0x1A, 0, 0, 0, 0},
+ {0x1B, 0, 0, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0, 0, 0, 0},
+ {0x1E, 0, 0, 0, 0},
+ {0x1F, 0, 0, 0, 0},
+ {0x20, 0, 0, 0, 0},
+ {0x21, 0, 0, 0, 0},
+ {0x22, 0x60, 0x60, 0, 0},
+ {0x23, 0x6, 0x6, 0, 0},
+ {0x24, 0xc, 0xc, 0, 0},
+ {0x25, 0, 0, 0, 0},
+ {0x26, 0, 0, 0, 0},
+ {0x27, 0, 0, 0, 0},
+ {0x28, 0x1, 0x1, 0, 0},
+ {0x29, 0, 0, 0, 0},
+ {0x2A, 0, 0, 0, 0},
+ {0x2B, 0, 0, 0, 0},
+ {0x2C, 0, 0, 0, 0},
+ {0x2D, 0, 0, 0, 0},
+ {0x2E, 0, 0, 0, 0},
+ {0x2F, 0x1f, 0x1f, 0, 0},
+ {0x30, 0x15, 0x15, 0, 0},
+ {0x31, 0xf, 0xf, 0, 0},
+ {0x32, 0, 0, 0, 0},
+ {0x33, 0, 0, 0, 0},
+ {0x34, 0, 0, 0, 0},
+ {0x35, 0, 0, 0, 0},
+ {0x36, 0, 0, 0, 0},
+ {0x37, 0, 0, 0, 0},
+ {0x38, 0, 0, 0, 0},
+ {0x39, 0, 0, 0, 0},
+ {0x3A, 0, 0, 0, 0},
+ {0x3B, 0, 0, 0, 0},
+ {0x3C, 0x13, 0x13, 0, 0},
+ {0x3D, 0xf, 0xf, 0, 0},
+ {0x3E, 0x18, 0x18, 0, 0},
+ {0x3F, 0, 0, 0, 0},
+ {0x40, 0, 0, 0, 0},
+ {0x41, 0x20, 0x20, 0, 0},
+ {0x42, 0x20, 0x20, 0, 0},
+ {0x43, 0, 0, 0, 0},
+ {0x44, 0x77, 0x77, 0, 0},
+ {0x45, 0x7, 0x7, 0, 0},
+ {0x46, 0x1, 0x1, 0, 0},
+ {0x47, 0x4, 0x4, 0, 0},
+ {0x48, 0xf, 0xf, 0, 0},
+ {0x49, 0x30, 0x30, 0, 0},
+ {0x4A, 0x32, 0x32, 0, 0},
+ {0x4B, 0xd, 0xd, 0, 0},
+ {0x4C, 0xd, 0xd, 0, 0},
+ {0x4D, 0x4, 0x4, 0, 0},
+ {0x4E, 0x6, 0x6, 0, 0},
+ {0x4F, 0x1, 0x1, 0, 0},
+ {0x50, 0x1c, 0x1c, 0, 0},
+ {0x51, 0x2, 0x2, 0, 0},
+ {0x52, 0x2, 0x2, 0, 0},
+ {0x53, 0xf7, 0xf7, 1, 1},
+ {0x54, 0xb4, 0xb4, 0, 0},
+ {0x55, 0xd2, 0xd2, 0, 0},
+ {0x56, 0, 0, 0, 0},
+ {0x57, 0, 0, 0, 0},
+ {0x58, 0x4, 0x4, 0, 0},
+ {0x59, 0x96, 0x96, 0, 0},
+ {0x5A, 0x3e, 0x3e, 0, 0},
+ {0x5B, 0x3e, 0x3e, 0, 0},
+ {0x5C, 0x13, 0x13, 0, 0},
+ {0x5D, 0x2, 0x2, 0, 0},
+ {0x5E, 0, 0, 0, 0},
+ {0x5F, 0x7, 0x7, 0, 0},
+ {0x60, 0x7, 0x7, 1, 1},
+ {0x61, 0x8, 0x8, 0, 0},
+ {0x62, 0x3, 0x3, 0, 0},
+ {0x63, 0, 0, 0, 0},
+ {0x64, 0, 0, 0, 0},
+ {0x65, 0, 0, 0, 0},
+ {0x66, 0, 0, 0, 0},
+ {0x67, 0, 0, 0, 0},
+ {0x68, 0x40, 0x40, 0, 0},
+ {0x69, 0, 0, 0, 0},
+ {0x6A, 0, 0, 0, 0},
+ {0x6B, 0, 0, 0, 0},
+ {0x6C, 0, 0, 0, 0},
+ {0x6D, 0x1, 0x1, 0, 0},
+ {0x6E, 0, 0, 0, 0},
+ {0x6F, 0, 0, 0, 0},
+ {0x70, 0x60, 0x60, 0, 0},
+ {0x71, 0x66, 0x66, 0, 0},
+ {0x72, 0xc, 0xc, 0, 0},
+ {0x73, 0x66, 0x66, 0, 0},
+ {0x74, 0x8f, 0x8f, 1, 1},
+ {0x75, 0, 0, 0, 0},
+ {0x76, 0xcc, 0xcc, 0, 0},
+ {0x77, 0x1, 0x1, 0, 0},
+ {0x78, 0x66, 0x66, 0, 0},
+ {0x79, 0x66, 0x66, 0, 0},
+ {0x7A, 0, 0, 0, 0},
+ {0x7B, 0, 0, 0, 0},
+ {0x7C, 0, 0, 0, 0},
+ {0x7D, 0, 0, 0, 0},
+ {0x7E, 0, 0, 0, 0},
+ {0x7F, 0, 0, 0, 0},
+ {0x80, 0, 0, 0, 0},
+ {0x81, 0, 0, 0, 0},
+ {0x82, 0, 0, 0, 0},
+ {0x83, 0, 0, 0, 0},
+ {0x84, 0, 0, 0, 0},
+ {0x85, 0xff, 0xff, 0, 0},
+ {0x86, 0, 0, 0, 0},
+ {0x87, 0, 0, 0, 0},
+ {0x88, 0, 0, 0, 0},
+ {0x89, 0, 0, 0, 0},
+ {0x8A, 0, 0, 0, 0},
+ {0x8B, 0, 0, 0, 0},
+ {0x8C, 0, 0, 0, 0},
+ {0x8D, 0, 0, 0, 0},
+ {0x8E, 0, 0, 0, 0},
+ {0x8F, 0, 0, 0, 0},
+ {0x90, 0, 0, 0, 0},
+ {0x91, 0, 0, 0, 0},
+ {0x92, 0, 0, 0, 0},
+ {0x93, 0, 0, 0, 0},
+ {0x94, 0, 0, 0, 0},
+ {0x95, 0, 0, 0, 0},
+ {0x96, 0, 0, 0, 0},
+ {0x97, 0, 0, 0, 0},
+ {0x98, 0, 0, 0, 0},
+ {0x99, 0, 0, 0, 0},
+ {0x9A, 0, 0, 0, 0},
+ {0x9B, 0, 0, 0, 0},
+ {0x9C, 0, 0, 0, 0},
+ {0x9D, 0, 0, 0, 0},
+ {0x9E, 0, 0, 0, 0},
+ {0x9F, 0x6, 0x6, 0, 0},
+ {0xA0, 0x66, 0x66, 0, 0},
+ {0xA1, 0x66, 0x66, 0, 0},
+ {0xA2, 0x66, 0x66, 0, 0},
+ {0xA3, 0x66, 0x66, 0, 0},
+ {0xA4, 0x66, 0x66, 0, 0},
+ {0xA5, 0x66, 0x66, 0, 0},
+ {0xA6, 0x66, 0x66, 0, 0},
+ {0xA7, 0x66, 0x66, 0, 0},
+ {0xA8, 0x66, 0x66, 0, 0},
+ {0xA9, 0x66, 0x66, 0, 0},
+ {0xAA, 0x66, 0x66, 0, 0},
+ {0xAB, 0x66, 0x66, 0, 0},
+ {0xAC, 0x66, 0x66, 0, 0},
+ {0xAD, 0x66, 0x66, 0, 0},
+ {0xAE, 0x66, 0x66, 0, 0},
+ {0xAF, 0x66, 0x66, 0, 0},
+ {0xB0, 0x66, 0x66, 0, 0},
+ {0xB1, 0x66, 0x66, 0, 0},
+ {0xB2, 0x66, 0x66, 0, 0},
+ {0xB3, 0xa, 0xa, 0, 0},
+ {0xB4, 0, 0, 0, 0},
+ {0xB5, 0, 0, 0, 0},
+ {0xB6, 0, 0, 0, 0},
+ {0xFFFF, 0, 0, 0, 0},
+};
+
+static struct radio_regs regs_TX_2056_rev7[] = {
+ {0x02, 0, 0, 0, 0},
+ {0x03, 0, 0, 0, 0},
+ {0x04, 0, 0, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0, 0, 0, 0},
+ {0x07, 0, 0, 0, 0},
+ {0x08, 0, 0, 0, 0},
+ {0x09, 0, 0, 0, 0},
+ {0x0A, 0, 0, 0, 0},
+ {0x0B, 0, 0, 0, 0},
+ {0x0C, 0, 0, 0, 0},
+ {0x0D, 0, 0, 0, 0},
+ {0x0E, 0, 0, 0, 0},
+ {0x0F, 0, 0, 0, 0},
+ {0x10, 0, 0, 0, 0},
+ {0x11, 0, 0, 0, 0},
+ {0x12, 0, 0, 0, 0},
+ {0x13, 0, 0, 0, 0},
+ {0x14, 0, 0, 0, 0},
+ {0x15, 0, 0, 0, 0},
+ {0x16, 0, 0, 0, 0},
+ {0x17, 0, 0, 0, 0},
+ {0x18, 0, 0, 0, 0},
+ {0x19, 0, 0, 0, 0},
+ {0x1A, 0, 0, 0, 0},
+ {0x1B, 0, 0, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0, 0, 0, 0},
+ {0x1E, 0, 0, 0, 0},
+ {0x1F, 0, 0, 0, 0},
+ {0x20, 0, 0, 0, 0},
+ {0x21, 0x88, 0x88, 0, 0},
+ {0x22, 0x88, 0x88, 0, 0},
+ {0x23, 0x88, 0x88, 0, 0},
+ {0x24, 0x88, 0x88, 0, 0},
+ {0x25, 0xc, 0xc, 0, 0},
+ {0x26, 0, 0, 0, 0},
+ {0x27, 0x3, 0x3, 0, 0},
+ {0x28, 0, 0, 0, 0},
+ {0x29, 0x3, 0x3, 0, 0},
+ {0x2A, 0x37, 0x37, 0, 0},
+ {0x2B, 0x3, 0x3, 0, 0},
+ {0x2C, 0, 0, 0, 0},
+ {0x2D, 0, 0, 0, 0},
+ {0x2E, 0x1, 0x1, 0, 0},
+ {0x2F, 0x1, 0x1, 0, 0},
+ {0x30, 0, 0, 0, 0},
+ {0x31, 0, 0, 0, 0},
+ {0x32, 0, 0, 0, 0},
+ {0x33, 0x11, 0x11, 0, 0},
+ {0x34, 0xee, 0xee, 1, 1},
+ {0x35, 0, 0, 0, 0},
+ {0x36, 0, 0, 0, 0},
+ {0x37, 0x3, 0x3, 0, 0},
+ {0x38, 0x50, 0x50, 1, 1},
+ {0x39, 0, 0, 0, 0},
+ {0x3A, 0x50, 0x50, 1, 1},
+ {0x3B, 0, 0, 0, 0},
+ {0x3C, 0x6e, 0x6e, 0, 0},
+ {0x3D, 0xf0, 0xf0, 1, 1},
+ {0x3E, 0, 0, 0, 0},
+ {0x3F, 0, 0, 0, 0},
+ {0x40, 0, 0, 0, 0},
+ {0x41, 0x3, 0x3, 0, 0},
+ {0x42, 0x3, 0x3, 0, 0},
+ {0x43, 0, 0, 0, 0},
+ {0x44, 0x1e, 0x1e, 0, 0},
+ {0x45, 0, 0, 0, 0},
+ {0x46, 0x6e, 0x6e, 0, 0},
+ {0x47, 0xf0, 0xf0, 1, 1},
+ {0x48, 0, 0, 0, 0},
+ {0x49, 0x2, 0x2, 0, 0},
+ {0x4A, 0xff, 0xff, 1, 1},
+ {0x4B, 0xc, 0xc, 0, 0},
+ {0x4C, 0, 0, 0, 0},
+ {0x4D, 0x38, 0x38, 0, 0},
+ {0x4E, 0x70, 0x70, 1, 1},
+ {0x4F, 0x2, 0x2, 0, 0},
+ {0x50, 0x88, 0x88, 0, 0},
+ {0x51, 0xc, 0xc, 0, 0},
+ {0x52, 0, 0, 0, 0},
+ {0x53, 0x8, 0x8, 0, 0},
+ {0x54, 0x70, 0x70, 1, 1},
+ {0x55, 0x2, 0x2, 0, 0},
+ {0x56, 0xff, 0xff, 1, 1},
+ {0x57, 0, 0, 0, 0},
+ {0x58, 0x83, 0x83, 0, 0},
+ {0x59, 0x77, 0x77, 1, 1},
+ {0x5A, 0, 0, 0, 0},
+ {0x5B, 0x2, 0x2, 0, 0},
+ {0x5C, 0x88, 0x88, 0, 0},
+ {0x5D, 0, 0, 0, 0},
+ {0x5E, 0x8, 0x8, 0, 0},
+ {0x5F, 0x77, 0x77, 1, 1},
+ {0x60, 0x1, 0x1, 0, 0},
+ {0x61, 0, 0, 0, 0},
+ {0x62, 0x7, 0x7, 0, 0},
+ {0x63, 0, 0, 0, 0},
+ {0x64, 0x7, 0x7, 0, 0},
+ {0x65, 0, 0, 0, 0},
+ {0x66, 0, 0, 0, 0},
+ {0x67, 0, 0, 1, 1},
+ {0x68, 0, 0, 0, 0},
+ {0x69, 0xa, 0xa, 0, 0},
+ {0x6A, 0, 0, 0, 0},
+ {0x6B, 0, 0, 0, 0},
+ {0x6C, 0, 0, 0, 0},
+ {0x6D, 0, 0, 0, 0},
+ {0x6E, 0, 0, 0, 0},
+ {0x6F, 0, 0, 0, 0},
+ {0x70, 0, 0, 0, 0},
+ {0x71, 0x2, 0x2, 0, 0},
+ {0x72, 0, 0, 0, 0},
+ {0x73, 0, 0, 0, 0},
+ {0x74, 0xe, 0xe, 0, 0},
+ {0x75, 0xe, 0xe, 0, 0},
+ {0x76, 0xe, 0xe, 0, 0},
+ {0x77, 0x13, 0x13, 0, 0},
+ {0x78, 0x13, 0x13, 0, 0},
+ {0x79, 0x1b, 0x1b, 0, 0},
+ {0x7A, 0x1b, 0x1b, 0, 0},
+ {0x7B, 0x55, 0x55, 0, 0},
+ {0x7C, 0x5b, 0x5b, 0, 0},
+ {0x7D, 0x30, 0x30, 1, 1},
+ {0x7E, 0, 0, 0, 0},
+ {0x7F, 0, 0, 0, 0},
+ {0x80, 0, 0, 0, 0},
+ {0x81, 0, 0, 0, 0},
+ {0x82, 0, 0, 0, 0},
+ {0x83, 0, 0, 0, 0},
+ {0x84, 0, 0, 0, 0},
+ {0x85, 0, 0, 0, 0},
+ {0x86, 0, 0, 0, 0},
+ {0x87, 0, 0, 0, 0},
+ {0x88, 0, 0, 0, 0},
+ {0x89, 0, 0, 0, 0},
+ {0x8A, 0, 0, 0, 0},
+ {0x8B, 0, 0, 0, 0},
+ {0x8C, 0, 0, 0, 0},
+ {0x8D, 0, 0, 0, 0},
+ {0x8E, 0, 0, 0, 0},
+ {0x8F, 0, 0, 0, 0},
+ {0x90, 0, 0, 0, 0},
+ {0x91, 0, 0, 0, 0},
+ {0x92, 0, 0, 0, 0},
+ {0x93, 0x70, 0x70, 0, 0},
+ {0x94, 0x70, 0x70, 0, 0},
+ {0x95, 0x71, 0x71, 1, 1},
+ {0x96, 0x71, 0x71, 1, 1},
+ {0x97, 0x72, 0x72, 1, 1},
+ {0x98, 0x73, 0x73, 1, 1},
+ {0x99, 0x74, 0x74, 1, 1},
+ {0x9A, 0x75, 0x75, 1, 1},
+ {0xFFFF, 0, 0, 0, 0},
+};
+
+static struct radio_regs regs_RX_2056_rev7[] = {
+ {0x02, 0, 0, 0, 0},
+ {0x03, 0, 0, 0, 0},
+ {0x04, 0, 0, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0, 0, 0, 0},
+ {0x07, 0, 0, 0, 0},
+ {0x08, 0, 0, 0, 0},
+ {0x09, 0, 0, 0, 0},
+ {0x0A, 0, 0, 0, 0},
+ {0x0B, 0, 0, 0, 0},
+ {0x0C, 0, 0, 0, 0},
+ {0x0D, 0, 0, 0, 0},
+ {0x0E, 0, 0, 0, 0},
+ {0x0F, 0, 0, 0, 0},
+ {0x10, 0, 0, 0, 0},
+ {0x11, 0, 0, 0, 0},
+ {0x12, 0, 0, 0, 0},
+ {0x13, 0, 0, 0, 0},
+ {0x14, 0, 0, 0, 0},
+ {0x15, 0, 0, 0, 0},
+ {0x16, 0, 0, 0, 0},
+ {0x17, 0, 0, 0, 0},
+ {0x18, 0, 0, 0, 0},
+ {0x19, 0, 0, 0, 0},
+ {0x1A, 0, 0, 0, 0},
+ {0x1B, 0, 0, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0, 0, 0, 0},
+ {0x1E, 0, 0, 0, 0},
+ {0x1F, 0, 0, 0, 0},
+ {0x20, 0x3, 0x3, 0, 0},
+ {0x21, 0, 0, 0, 0},
+ {0x22, 0, 0, 0, 0},
+ {0x23, 0x90, 0x90, 0, 0},
+ {0x24, 0x55, 0x55, 0, 0},
+ {0x25, 0x15, 0x15, 0, 0},
+ {0x26, 0x5, 0x5, 0, 0},
+ {0x27, 0x15, 0x15, 0, 0},
+ {0x28, 0x5, 0x5, 0, 0},
+ {0x29, 0x20, 0x20, 0, 0},
+ {0x2A, 0x11, 0x11, 0, 0},
+ {0x2B, 0x90, 0x90, 0, 0},
+ {0x2C, 0, 0, 0, 0},
+ {0x2D, 0x88, 0x88, 0, 0},
+ {0x2E, 0x32, 0x32, 0, 0},
+ {0x2F, 0x77, 0x77, 0, 0},
+ {0x30, 0x17, 0x17, 1, 1},
+ {0x31, 0xff, 0xff, 1, 1},
+ {0x32, 0x20, 0x20, 0, 0},
+ {0x33, 0, 0, 0, 0},
+ {0x34, 0x88, 0x88, 0, 0},
+ {0x35, 0x32, 0x32, 0, 0},
+ {0x36, 0x77, 0x77, 0, 0},
+ {0x37, 0x17, 0x17, 1, 1},
+ {0x38, 0xf0, 0xf0, 1, 1},
+ {0x39, 0x20, 0x20, 0, 0},
+ {0x3A, 0x8, 0x8, 0, 0},
+ {0x3B, 0x55, 0x55, 1, 1},
+ {0x3C, 0, 0, 0, 0},
+ {0x3D, 0x88, 0x88, 1, 1},
+ {0x3E, 0, 0, 0, 0},
+ {0x3F, 0, 0, 1, 1},
+ {0x40, 0x7, 0x7, 1, 1},
+ {0x41, 0x6, 0x6, 0, 0},
+ {0x42, 0x4, 0x4, 0, 0},
+ {0x43, 0, 0, 0, 0},
+ {0x44, 0x8, 0x8, 0, 0},
+ {0x45, 0x55, 0x55, 1, 1},
+ {0x46, 0, 0, 0, 0},
+ {0x47, 0x11, 0x11, 0, 0},
+ {0x48, 0, 0, 0, 0},
+ {0x49, 0, 0, 1, 1},
+ {0x4A, 0x7, 0x7, 0, 0},
+ {0x4B, 0x6, 0x6, 0, 0},
+ {0x4C, 0x4, 0x4, 0, 0},
+ {0x4D, 0, 0, 0, 0},
+ {0x4E, 0, 0, 0, 0},
+ {0x4F, 0x26, 0x26, 1, 1},
+ {0x50, 0x26, 0x26, 1, 1},
+ {0x51, 0xf, 0xf, 1, 1},
+ {0x52, 0xf, 0xf, 1, 1},
+ {0x53, 0x44, 0x44, 0, 0},
+ {0x54, 0, 0, 0, 0},
+ {0x55, 0, 0, 0, 0},
+ {0x56, 0x8, 0x8, 0, 0},
+ {0x57, 0x8, 0x8, 0, 0},
+ {0x58, 0x7, 0x7, 0, 0},
+ {0x59, 0x22, 0x22, 0, 0},
+ {0x5A, 0x22, 0x22, 0, 0},
+ {0x5B, 0x2, 0x2, 0, 0},
+ {0x5C, 0x4, 0x4, 1, 1},
+ {0x5D, 0x7, 0x7, 0, 0},
+ {0x5E, 0x55, 0x55, 0, 0},
+ {0x5F, 0x23, 0x23, 0, 0},
+ {0x60, 0x41, 0x41, 0, 0},
+ {0x61, 0x1, 0x1, 0, 0},
+ {0x62, 0xa, 0xa, 0, 0},
+ {0x63, 0, 0, 0, 0},
+ {0x64, 0, 0, 0, 0},
+ {0x65, 0, 0, 0, 0},
+ {0x66, 0, 0, 0, 0},
+ {0x67, 0, 0, 0, 0},
+ {0x68, 0, 0, 0, 0},
+ {0x69, 0, 0, 0, 0},
+ {0x6A, 0, 0, 0, 0},
+ {0x6B, 0xc, 0xc, 0, 0},
+ {0x6C, 0, 0, 0, 0},
+ {0x6D, 0, 0, 0, 0},
+ {0x6E, 0, 0, 0, 0},
+ {0x6F, 0, 0, 0, 0},
+ {0x70, 0, 0, 0, 0},
+ {0x71, 0, 0, 0, 0},
+ {0x72, 0x22, 0x22, 0, 0},
+ {0x73, 0x22, 0x22, 0, 0},
+ {0x74, 0, 0, 1, 1},
+ {0x75, 0xa, 0xa, 0, 0},
+ {0x76, 0x1, 0x1, 0, 0},
+ {0x77, 0x22, 0x22, 0, 0},
+ {0x78, 0x30, 0x30, 0, 0},
+ {0x79, 0, 0, 0, 0},
+ {0x7A, 0, 0, 0, 0},
+ {0x7B, 0, 0, 0, 0},
+ {0x7C, 0, 0, 0, 0},
+ {0x7D, 0, 0, 0, 0},
+ {0x7E, 0, 0, 0, 0},
+ {0x7F, 0, 0, 0, 0},
+ {0x80, 0, 0, 0, 0},
+ {0x81, 0, 0, 0, 0},
+ {0x82, 0, 0, 0, 0},
+ {0x83, 0, 0, 0, 0},
+ {0x84, 0, 0, 0, 0},
+ {0x85, 0, 0, 0, 0},
+ {0x86, 0, 0, 0, 0},
+ {0x87, 0, 0, 0, 0},
+ {0x88, 0, 0, 0, 0},
+ {0x89, 0, 0, 0, 0},
+ {0x8A, 0, 0, 0, 0},
+ {0x8B, 0, 0, 0, 0},
+ {0x8C, 0, 0, 0, 0},
+ {0x8D, 0, 0, 0, 0},
+ {0x8E, 0, 0, 0, 0},
+ {0x8F, 0, 0, 0, 0},
+ {0x90, 0, 0, 0, 0},
+ {0x91, 0, 0, 0, 0},
+ {0x92, 0, 0, 0, 0},
+ {0x93, 0, 0, 0, 0},
+ {0x94, 0, 0, 0, 0},
+ {0xFFFF, 0, 0, 0, 0},
+};
+
+static struct radio_regs regs_SYN_2056_rev8[] = {
+ {0x02, 0, 0, 0, 0},
+ {0x03, 0, 0, 0, 0},
+ {0x04, 0, 0, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0, 0, 0, 0},
+ {0x07, 0, 0, 0, 0},
+ {0x08, 0, 0, 0, 0},
+ {0x09, 0x1, 0x1, 0, 0},
+ {0x0A, 0, 0, 0, 0},
+ {0x0B, 0, 0, 0, 0},
+ {0x0C, 0, 0, 0, 0},
+ {0x0D, 0, 0, 0, 0},
+ {0x0E, 0, 0, 0, 0},
+ {0x0F, 0, 0, 0, 0},
+ {0x10, 0, 0, 0, 0},
+ {0x11, 0, 0, 0, 0},
+ {0x12, 0, 0, 0, 0},
+ {0x13, 0, 0, 0, 0},
+ {0x14, 0, 0, 0, 0},
+ {0x15, 0, 0, 0, 0},
+ {0x16, 0, 0, 0, 0},
+ {0x17, 0, 0, 0, 0},
+ {0x18, 0, 0, 0, 0},
+ {0x19, 0, 0, 0, 0},
+ {0x1A, 0, 0, 0, 0},
+ {0x1B, 0, 0, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0, 0, 0, 0},
+ {0x1E, 0, 0, 0, 0},
+ {0x1F, 0, 0, 0, 0},
+ {0x20, 0, 0, 0, 0},
+ {0x21, 0, 0, 0, 0},
+ {0x22, 0x60, 0x60, 0, 0},
+ {0x23, 0x6, 0x6, 0, 0},
+ {0x24, 0xc, 0xc, 0, 0},
+ {0x25, 0, 0, 0, 0},
+ {0x26, 0, 0, 0, 0},
+ {0x27, 0, 0, 0, 0},
+ {0x28, 0x1, 0x1, 0, 0},
+ {0x29, 0, 0, 0, 0},
+ {0x2A, 0, 0, 0, 0},
+ {0x2B, 0, 0, 0, 0},
+ {0x2C, 0, 0, 0, 0},
+ {0x2D, 0, 0, 0, 0},
+ {0x2E, 0, 0, 0, 0},
+ {0x2F, 0x1f, 0x1f, 0, 0},
+ {0x30, 0x15, 0x15, 0, 0},
+ {0x31, 0xf, 0xf, 0, 0},
+ {0x32, 0, 0, 0, 0},
+ {0x33, 0, 0, 0, 0},
+ {0x34, 0, 0, 0, 0},
+ {0x35, 0, 0, 0, 0},
+ {0x36, 0, 0, 0, 0},
+ {0x37, 0, 0, 0, 0},
+ {0x38, 0, 0, 0, 0},
+ {0x39, 0, 0, 0, 0},
+ {0x3A, 0, 0, 0, 0},
+ {0x3B, 0, 0, 0, 0},
+ {0x3C, 0x13, 0x13, 0, 0},
+ {0x3D, 0xf, 0xf, 0, 0},
+ {0x3E, 0x18, 0x18, 0, 0},
+ {0x3F, 0, 0, 0, 0},
+ {0x40, 0, 0, 0, 0},
+ {0x41, 0x20, 0x20, 0, 0},
+ {0x42, 0x20, 0x20, 0, 0},
+ {0x43, 0, 0, 0, 0},
+ {0x44, 0x77, 0x77, 0, 0},
+ {0x45, 0x7, 0x7, 0, 0},
+ {0x46, 0x1, 0x1, 0, 0},
+ {0x47, 0x4, 0x4, 0, 0},
+ {0x48, 0xf, 0xf, 0, 0},
+ {0x49, 0x30, 0x30, 0, 0},
+ {0x4A, 0x32, 0x32, 0, 0},
+ {0x4B, 0xd, 0xd, 0, 0},
+ {0x4C, 0xd, 0xd, 0, 0},
+ {0x4D, 0x4, 0x4, 0, 0},
+ {0x4E, 0x6, 0x6, 0, 0},
+ {0x4F, 0x1, 0x1, 0, 0},
+ {0x50, 0x1c, 0x1c, 0, 0},
+ {0x51, 0x2, 0x2, 0, 0},
+ {0x52, 0x2, 0x2, 0, 0},
+ {0x53, 0xf7, 0xf7, 1, 1},
+ {0x54, 0xb4, 0xb4, 0, 0},
+ {0x55, 0xd2, 0xd2, 0, 0},
+ {0x56, 0, 0, 0, 0},
+ {0x57, 0, 0, 0, 0},
+ {0x58, 0x4, 0x4, 0, 0},
+ {0x59, 0x96, 0x96, 0, 0},
+ {0x5A, 0x3e, 0x3e, 0, 0},
+ {0x5B, 0x3e, 0x3e, 0, 0},
+ {0x5C, 0x13, 0x13, 0, 0},
+ {0x5D, 0x2, 0x2, 0, 0},
+ {0x5E, 0, 0, 0, 0},
+ {0x5F, 0x7, 0x7, 0, 0},
+ {0x60, 0x7, 0x7, 1, 1},
+ {0x61, 0x8, 0x8, 0, 0},
+ {0x62, 0x3, 0x3, 0, 0},
+ {0x63, 0, 0, 0, 0},
+ {0x64, 0, 0, 0, 0},
+ {0x65, 0, 0, 0, 0},
+ {0x66, 0, 0, 0, 0},
+ {0x67, 0, 0, 0, 0},
+ {0x68, 0x40, 0x40, 0, 0},
+ {0x69, 0, 0, 0, 0},
+ {0x6A, 0, 0, 0, 0},
+ {0x6B, 0, 0, 0, 0},
+ {0x6C, 0, 0, 0, 0},
+ {0x6D, 0x1, 0x1, 0, 0},
+ {0x6E, 0, 0, 0, 0},
+ {0x6F, 0, 0, 0, 0},
+ {0x70, 0x60, 0x60, 0, 0},
+ {0x71, 0x66, 0x66, 0, 0},
+ {0x72, 0xc, 0xc, 0, 0},
+ {0x73, 0x66, 0x66, 0, 0},
+ {0x74, 0x8f, 0x8f, 1, 1},
+ {0x75, 0, 0, 0, 0},
+ {0x76, 0xcc, 0xcc, 0, 0},
+ {0x77, 0x1, 0x1, 0, 0},
+ {0x78, 0x66, 0x66, 0, 0},
+ {0x79, 0x66, 0x66, 0, 0},
+ {0x7A, 0, 0, 0, 0},
+ {0x7B, 0, 0, 0, 0},
+ {0x7C, 0, 0, 0, 0},
+ {0x7D, 0, 0, 0, 0},
+ {0x7E, 0, 0, 0, 0},
+ {0x7F, 0, 0, 0, 0},
+ {0x80, 0, 0, 0, 0},
+ {0x81, 0, 0, 0, 0},
+ {0x82, 0, 0, 0, 0},
+ {0x83, 0, 0, 0, 0},
+ {0x84, 0, 0, 0, 0},
+ {0x85, 0xff, 0xff, 0, 0},
+ {0x86, 0, 0, 0, 0},
+ {0x87, 0, 0, 0, 0},
+ {0x88, 0, 0, 0, 0},
+ {0x89, 0, 0, 0, 0},
+ {0x8A, 0, 0, 0, 0},
+ {0x8B, 0, 0, 0, 0},
+ {0x8C, 0, 0, 0, 0},
+ {0x8D, 0, 0, 0, 0},
+ {0x8E, 0, 0, 0, 0},
+ {0x8F, 0, 0, 0, 0},
+ {0x90, 0, 0, 0, 0},
+ {0x91, 0, 0, 0, 0},
+ {0x92, 0, 0, 0, 0},
+ {0x93, 0, 0, 0, 0},
+ {0x94, 0, 0, 0, 0},
+ {0x95, 0, 0, 0, 0},
+ {0x96, 0, 0, 0, 0},
+ {0x97, 0, 0, 0, 0},
+ {0x98, 0, 0, 0, 0},
+ {0x99, 0, 0, 0, 0},
+ {0x9A, 0, 0, 0, 0},
+ {0x9B, 0, 0, 0, 0},
+ {0x9C, 0, 0, 0, 0},
+ {0x9D, 0, 0, 0, 0},
+ {0x9E, 0, 0, 0, 0},
+ {0x9F, 0x6, 0x6, 0, 0},
+ {0xA0, 0x66, 0x66, 0, 0},
+ {0xA1, 0x66, 0x66, 0, 0},
+ {0xA2, 0x66, 0x66, 0, 0},
+ {0xA3, 0x66, 0x66, 0, 0},
+ {0xA4, 0x66, 0x66, 0, 0},
+ {0xA5, 0x66, 0x66, 0, 0},
+ {0xA6, 0x66, 0x66, 0, 0},
+ {0xA7, 0x66, 0x66, 0, 0},
+ {0xA8, 0x66, 0x66, 0, 0},
+ {0xA9, 0x66, 0x66, 0, 0},
+ {0xAA, 0x66, 0x66, 0, 0},
+ {0xAB, 0x66, 0x66, 0, 0},
+ {0xAC, 0x66, 0x66, 0, 0},
+ {0xAD, 0x66, 0x66, 0, 0},
+ {0xAE, 0x66, 0x66, 0, 0},
+ {0xAF, 0x66, 0x66, 0, 0},
+ {0xB0, 0x66, 0x66, 0, 0},
+ {0xB1, 0x66, 0x66, 0, 0},
+ {0xB2, 0x66, 0x66, 0, 0},
+ {0xB3, 0xa, 0xa, 0, 0},
+ {0xB4, 0, 0, 0, 0},
+ {0xB5, 0, 0, 0, 0},
+ {0xB6, 0, 0, 0, 0},
+ {0xFFFF, 0, 0, 0, 0},
+};
+
+static struct radio_regs regs_TX_2056_rev8[] = {
+ {0x02, 0, 0, 0, 0},
+ {0x03, 0, 0, 0, 0},
+ {0x04, 0, 0, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0, 0, 0, 0},
+ {0x07, 0, 0, 0, 0},
+ {0x08, 0, 0, 0, 0},
+ {0x09, 0, 0, 0, 0},
+ {0x0A, 0, 0, 0, 0},
+ {0x0B, 0, 0, 0, 0},
+ {0x0C, 0, 0, 0, 0},
+ {0x0D, 0, 0, 0, 0},
+ {0x0E, 0, 0, 0, 0},
+ {0x0F, 0, 0, 0, 0},
+ {0x10, 0, 0, 0, 0},
+ {0x11, 0, 0, 0, 0},
+ {0x12, 0, 0, 0, 0},
+ {0x13, 0, 0, 0, 0},
+ {0x14, 0, 0, 0, 0},
+ {0x15, 0, 0, 0, 0},
+ {0x16, 0, 0, 0, 0},
+ {0x17, 0, 0, 0, 0},
+ {0x18, 0, 0, 0, 0},
+ {0x19, 0, 0, 0, 0},
+ {0x1A, 0, 0, 0, 0},
+ {0x1B, 0, 0, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0, 0, 0, 0},
+ {0x1E, 0, 0, 0, 0},
+ {0x1F, 0, 0, 0, 0},
+ {0x20, 0, 0, 0, 0},
+ {0x21, 0x88, 0x88, 0, 0},
+ {0x22, 0x88, 0x88, 0, 0},
+ {0x23, 0x88, 0x88, 0, 0},
+ {0x24, 0x88, 0x88, 0, 0},
+ {0x25, 0xc, 0xc, 0, 0},
+ {0x26, 0, 0, 0, 0},
+ {0x27, 0x3, 0x3, 0, 0},
+ {0x28, 0, 0, 0, 0},
+ {0x29, 0x3, 0x3, 0, 0},
+ {0x2A, 0x37, 0x37, 0, 0},
+ {0x2B, 0x3, 0x3, 0, 0},
+ {0x2C, 0, 0, 0, 0},
+ {0x2D, 0, 0, 0, 0},
+ {0x2E, 0x1, 0x1, 0, 0},
+ {0x2F, 0x1, 0x1, 0, 0},
+ {0x30, 0, 0, 0, 0},
+ {0x31, 0, 0, 0, 0},
+ {0x32, 0, 0, 0, 0},
+ {0x33, 0x11, 0x11, 0, 0},
+ {0x34, 0xee, 0xee, 1, 1},
+ {0x35, 0, 0, 0, 0},
+ {0x36, 0, 0, 0, 0},
+ {0x37, 0x3, 0x3, 0, 0},
+ {0x38, 0x50, 0x50, 1, 1},
+ {0x39, 0, 0, 0, 0},
+ {0x3A, 0x50, 0x50, 1, 1},
+ {0x3B, 0, 0, 0, 0},
+ {0x3C, 0x6e, 0x6e, 0, 0},
+ {0x3D, 0xf0, 0xf0, 1, 1},
+ {0x3E, 0, 0, 0, 0},
+ {0x3F, 0, 0, 0, 0},
+ {0x40, 0, 0, 0, 0},
+ {0x41, 0x3, 0x3, 0, 0},
+ {0x42, 0x3, 0x3, 0, 0},
+ {0x43, 0, 0, 0, 0},
+ {0x44, 0x1e, 0x1e, 0, 0},
+ {0x45, 0, 0, 0, 0},
+ {0x46, 0x6e, 0x6e, 0, 0},
+ {0x47, 0xf0, 0xf0, 1, 1},
+ {0x48, 0, 0, 0, 0},
+ {0x49, 0x2, 0x2, 0, 0},
+ {0x4A, 0xff, 0xff, 1, 1},
+ {0x4B, 0xc, 0xc, 0, 0},
+ {0x4C, 0, 0, 0, 0},
+ {0x4D, 0x38, 0x38, 0, 0},
+ {0x4E, 0x70, 0x70, 1, 1},
+ {0x4F, 0x2, 0x2, 0, 0},
+ {0x50, 0x88, 0x88, 0, 0},
+ {0x51, 0xc, 0xc, 0, 0},
+ {0x52, 0, 0, 0, 0},
+ {0x53, 0x8, 0x8, 0, 0},
+ {0x54, 0x70, 0x70, 1, 1},
+ {0x55, 0x2, 0x2, 0, 0},
+ {0x56, 0xff, 0xff, 1, 1},
+ {0x57, 0, 0, 0, 0},
+ {0x58, 0x83, 0x83, 0, 0},
+ {0x59, 0x77, 0x77, 1, 1},
+ {0x5A, 0, 0, 0, 0},
+ {0x5B, 0x2, 0x2, 0, 0},
+ {0x5C, 0x88, 0x88, 0, 0},
+ {0x5D, 0, 0, 0, 0},
+ {0x5E, 0x8, 0x8, 0, 0},
+ {0x5F, 0x77, 0x77, 1, 1},
+ {0x60, 0x1, 0x1, 0, 0},
+ {0x61, 0, 0, 0, 0},
+ {0x62, 0x7, 0x7, 0, 0},
+ {0x63, 0, 0, 0, 0},
+ {0x64, 0x7, 0x7, 0, 0},
+ {0x65, 0, 0, 0, 0},
+ {0x66, 0, 0, 0, 0},
+ {0x67, 0, 0, 1, 1},
+ {0x68, 0, 0, 0, 0},
+ {0x69, 0xa, 0xa, 0, 0},
+ {0x6A, 0, 0, 0, 0},
+ {0x6B, 0, 0, 0, 0},
+ {0x6C, 0, 0, 0, 0},
+ {0x6D, 0, 0, 0, 0},
+ {0x6E, 0, 0, 0, 0},
+ {0x6F, 0, 0, 0, 0},
+ {0x70, 0, 0, 0, 0},
+ {0x71, 0x2, 0x2, 0, 0},
+ {0x72, 0, 0, 0, 0},
+ {0x73, 0, 0, 0, 0},
+ {0x74, 0xe, 0xe, 0, 0},
+ {0x75, 0xe, 0xe, 0, 0},
+ {0x76, 0xe, 0xe, 0, 0},
+ {0x77, 0x13, 0x13, 0, 0},
+ {0x78, 0x13, 0x13, 0, 0},
+ {0x79, 0x1b, 0x1b, 0, 0},
+ {0x7A, 0x1b, 0x1b, 0, 0},
+ {0x7B, 0x55, 0x55, 0, 0},
+ {0x7C, 0x5b, 0x5b, 0, 0},
+ {0x7D, 0x30, 0x30, 1, 1},
+ {0x7E, 0, 0, 0, 0},
+ {0x7F, 0, 0, 0, 0},
+ {0x80, 0, 0, 0, 0},
+ {0x81, 0, 0, 0, 0},
+ {0x82, 0, 0, 0, 0},
+ {0x83, 0, 0, 0, 0},
+ {0x84, 0, 0, 0, 0},
+ {0x85, 0, 0, 0, 0},
+ {0x86, 0, 0, 0, 0},
+ {0x87, 0, 0, 0, 0},
+ {0x88, 0, 0, 0, 0},
+ {0x89, 0, 0, 0, 0},
+ {0x8A, 0, 0, 0, 0},
+ {0x8B, 0, 0, 0, 0},
+ {0x8C, 0, 0, 0, 0},
+ {0x8D, 0, 0, 0, 0},
+ {0x8E, 0, 0, 0, 0},
+ {0x8F, 0, 0, 0, 0},
+ {0x90, 0, 0, 0, 0},
+ {0x91, 0, 0, 0, 0},
+ {0x92, 0, 0, 0, 0},
+ {0x93, 0x70, 0x70, 0, 0},
+ {0x94, 0x70, 0x70, 0, 0},
+ {0x95, 0x70, 0x70, 0, 0},
+ {0x96, 0x70, 0x70, 0, 0},
+ {0x97, 0x70, 0x70, 0, 0},
+ {0x98, 0x70, 0x70, 0, 0},
+ {0x99, 0x70, 0x70, 0, 0},
+ {0x9A, 0x70, 0x70, 0, 0},
+ {0xFFFF, 0, 0, 0, 0},
+};
+
+static struct radio_regs regs_RX_2056_rev8[] = {
+ {0x02, 0, 0, 0, 0},
+ {0x03, 0, 0, 0, 0},
+ {0x04, 0, 0, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0, 0, 0, 0},
+ {0x07, 0, 0, 0, 0},
+ {0x08, 0, 0, 0, 0},
+ {0x09, 0, 0, 0, 0},
+ {0x0A, 0, 0, 0, 0},
+ {0x0B, 0, 0, 0, 0},
+ {0x0C, 0, 0, 0, 0},
+ {0x0D, 0, 0, 0, 0},
+ {0x0E, 0, 0, 0, 0},
+ {0x0F, 0, 0, 0, 0},
+ {0x10, 0, 0, 0, 0},
+ {0x11, 0, 0, 0, 0},
+ {0x12, 0, 0, 0, 0},
+ {0x13, 0, 0, 0, 0},
+ {0x14, 0, 0, 0, 0},
+ {0x15, 0, 0, 0, 0},
+ {0x16, 0, 0, 0, 0},
+ {0x17, 0, 0, 0, 0},
+ {0x18, 0, 0, 0, 0},
+ {0x19, 0, 0, 0, 0},
+ {0x1A, 0, 0, 0, 0},
+ {0x1B, 0, 0, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0, 0, 0, 0},
+ {0x1E, 0, 0, 0, 0},
+ {0x1F, 0, 0, 0, 0},
+ {0x20, 0x3, 0x3, 0, 0},
+ {0x21, 0, 0, 0, 0},
+ {0x22, 0, 0, 0, 0},
+ {0x23, 0x90, 0x90, 0, 0},
+ {0x24, 0x55, 0x55, 0, 0},
+ {0x25, 0x15, 0x15, 0, 0},
+ {0x26, 0x5, 0x5, 0, 0},
+ {0x27, 0x15, 0x15, 0, 0},
+ {0x28, 0x5, 0x5, 0, 0},
+ {0x29, 0x20, 0x20, 0, 0},
+ {0x2A, 0x11, 0x11, 0, 0},
+ {0x2B, 0x90, 0x90, 0, 0},
+ {0x2C, 0, 0, 0, 0},
+ {0x2D, 0x88, 0x88, 0, 0},
+ {0x2E, 0x32, 0x32, 0, 0},
+ {0x2F, 0x77, 0x77, 0, 0},
+ {0x30, 0x17, 0x17, 1, 1},
+ {0x31, 0xff, 0xff, 1, 1},
+ {0x32, 0x20, 0x20, 0, 0},
+ {0x33, 0, 0, 0, 0},
+ {0x34, 0x88, 0x88, 0, 0},
+ {0x35, 0x32, 0x32, 0, 0},
+ {0x36, 0x77, 0x77, 0, 0},
+ {0x37, 0x17, 0x17, 1, 1},
+ {0x38, 0xf0, 0xf0, 1, 1},
+ {0x39, 0x20, 0x20, 0, 0},
+ {0x3A, 0x8, 0x8, 0, 0},
+ {0x3B, 0x55, 0x55, 1, 1},
+ {0x3C, 0, 0, 0, 0},
+ {0x3D, 0x88, 0x88, 1, 1},
+ {0x3E, 0, 0, 0, 0},
+ {0x3F, 0x44, 0x44, 0, 0},
+ {0x40, 0x7, 0x7, 1, 1},
+ {0x41, 0x6, 0x6, 0, 0},
+ {0x42, 0x4, 0x4, 0, 0},
+ {0x43, 0, 0, 0, 0},
+ {0x44, 0x8, 0x8, 0, 0},
+ {0x45, 0x55, 0x55, 1, 1},
+ {0x46, 0, 0, 0, 0},
+ {0x47, 0x11, 0x11, 0, 0},
+ {0x48, 0, 0, 0, 0},
+ {0x49, 0x44, 0x44, 0, 0},
+ {0x4A, 0x7, 0x7, 0, 0},
+ {0x4B, 0x6, 0x6, 0, 0},
+ {0x4C, 0x4, 0x4, 0, 0},
+ {0x4D, 0, 0, 0, 0},
+ {0x4E, 0, 0, 0, 0},
+ {0x4F, 0x26, 0x26, 1, 1},
+ {0x50, 0x26, 0x26, 1, 1},
+ {0x51, 0xf, 0xf, 1, 1},
+ {0x52, 0xf, 0xf, 1, 1},
+ {0x53, 0x44, 0x44, 0, 0},
+ {0x54, 0, 0, 0, 0},
+ {0x55, 0, 0, 0, 0},
+ {0x56, 0x8, 0x8, 0, 0},
+ {0x57, 0x8, 0x8, 0, 0},
+ {0x58, 0x7, 0x7, 0, 0},
+ {0x59, 0x22, 0x22, 0, 0},
+ {0x5A, 0x22, 0x22, 0, 0},
+ {0x5B, 0x2, 0x2, 0, 0},
+ {0x5C, 0x4, 0x4, 1, 1},
+ {0x5D, 0x7, 0x7, 0, 0},
+ {0x5E, 0x55, 0x55, 0, 0},
+ {0x5F, 0x23, 0x23, 0, 0},
+ {0x60, 0x41, 0x41, 0, 0},
+ {0x61, 0x1, 0x1, 0, 0},
+ {0x62, 0xa, 0xa, 0, 0},
+ {0x63, 0, 0, 0, 0},
+ {0x64, 0, 0, 0, 0},
+ {0x65, 0, 0, 0, 0},
+ {0x66, 0, 0, 0, 0},
+ {0x67, 0, 0, 0, 0},
+ {0x68, 0, 0, 0, 0},
+ {0x69, 0, 0, 0, 0},
+ {0x6A, 0, 0, 0, 0},
+ {0x6B, 0xc, 0xc, 0, 0},
+ {0x6C, 0, 0, 0, 0},
+ {0x6D, 0, 0, 0, 0},
+ {0x6E, 0, 0, 0, 0},
+ {0x6F, 0, 0, 0, 0},
+ {0x70, 0, 0, 0, 0},
+ {0x71, 0, 0, 0, 0},
+ {0x72, 0x22, 0x22, 0, 0},
+ {0x73, 0x22, 0x22, 0, 0},
+ {0x74, 0, 0, 1, 1},
+ {0x75, 0xa, 0xa, 0, 0},
+ {0x76, 0x1, 0x1, 0, 0},
+ {0x77, 0x22, 0x22, 0, 0},
+ {0x78, 0x30, 0x30, 0, 0},
+ {0x79, 0, 0, 0, 0},
+ {0x7A, 0, 0, 0, 0},
+ {0x7B, 0, 0, 0, 0},
+ {0x7C, 0, 0, 0, 0},
+ {0x7D, 0x5, 0x5, 1, 1},
+ {0x7E, 0, 0, 0, 0},
+ {0x7F, 0, 0, 0, 0},
+ {0x80, 0, 0, 0, 0},
+ {0x81, 0, 0, 0, 0},
+ {0x82, 0, 0, 0, 0},
+ {0x83, 0, 0, 0, 0},
+ {0x84, 0, 0, 0, 0},
+ {0x85, 0, 0, 0, 0},
+ {0x86, 0, 0, 0, 0},
+ {0x87, 0, 0, 0, 0},
+ {0x88, 0, 0, 0, 0},
+ {0x89, 0, 0, 0, 0},
+ {0x8A, 0, 0, 0, 0},
+ {0x8B, 0, 0, 0, 0},
+ {0x8C, 0, 0, 0, 0},
+ {0x8D, 0, 0, 0, 0},
+ {0x8E, 0, 0, 0, 0},
+ {0x8F, 0, 0, 0, 0},
+ {0x90, 0, 0, 0, 0},
+ {0x91, 0, 0, 0, 0},
+ {0x92, 0, 0, 0, 0},
+ {0x93, 0, 0, 0, 0},
+ {0x94, 0, 0, 0, 0},
+ {0xFFFF, 0, 0, 0, 0},
+};
+
+static const struct radio_regs regs_SYN_2056_rev11[] = {
+ {0x02, 0, 0, 0, 0},
+ {0x03, 0, 0, 0, 0},
+ {0x04, 0, 0, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0, 0, 0, 0},
+ {0x07, 0, 0, 0, 0},
+ {0x08, 0, 0, 0, 0},
+ {0x09, 0x1, 0x1, 0, 0},
+ {0x0A, 0, 0, 0, 0},
+ {0x0B, 0, 0, 0, 0},
+ {0x0C, 0, 0, 0, 0},
+ {0x0D, 0, 0, 0, 0},
+ {0x0E, 0, 0, 0, 0},
+ {0x0F, 0, 0, 0, 0},
+ {0x10, 0, 0, 0, 0},
+ {0x11, 0, 0, 0, 0},
+ {0x12, 0, 0, 0, 0},
+ {0x13, 0, 0, 0, 0},
+ {0x14, 0, 0, 0, 0},
+ {0x15, 0, 0, 0, 0},
+ {0x16, 0, 0, 0, 0},
+ {0x17, 0, 0, 0, 0},
+ {0x18, 0, 0, 0, 0},
+ {0x19, 0, 0, 0, 0},
+ {0x1A, 0, 0, 0, 0},
+ {0x1B, 0, 0, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0, 0, 0, 0},
+ {0x1E, 0, 0, 0, 0},
+ {0x1F, 0, 0, 0, 0},
+ {0x20, 0, 0, 0, 0},
+ {0x21, 0, 0, 0, 0},
+ {0x22, 0x60, 0x60, 0, 0},
+ {0x23, 0x6, 0x6, 0, 0},
+ {0x24, 0xc, 0xc, 0, 0},
+ {0x25, 0, 0, 0, 0},
+ {0x26, 0, 0, 0, 0},
+ {0x27, 0, 0, 0, 0},
+ {0x28, 0x1, 0x1, 0, 0},
+ {0x29, 0, 0, 0, 0},
+ {0x2A, 0, 0, 0, 0},
+ {0x2B, 0, 0, 0, 0},
+ {0x2C, 0, 0, 0, 0},
+ {0x2D, 0, 0, 0, 0},
+ {0x2E, 0, 0, 0, 0},
+ {0x2F, 0x1f, 0x1f, 0, 0},
+ {0x30, 0x15, 0x15, 0, 0},
+ {0x31, 0xf, 0xf, 0, 0},
+ {0x32, 0, 0, 0, 0},
+ {0x33, 0, 0, 0, 0},
+ {0x34, 0, 0, 0, 0},
+ {0x35, 0, 0, 0, 0},
+ {0x36, 0, 0, 0, 0},
+ {0x37, 0, 0, 0, 0},
+ {0x38, 0, 0, 0, 0},
+ {0x39, 0, 0, 0, 0},
+ {0x3A, 0, 0, 0, 0},
+ {0x3B, 0, 0, 0, 0},
+ {0x3C, 0x13, 0x13, 0, 0},
+ {0x3D, 0xf, 0xf, 0, 0},
+ {0x3E, 0x18, 0x18, 0, 0},
+ {0x3F, 0, 0, 0, 0},
+ {0x40, 0, 0, 0, 0},
+ {0x41, 0x20, 0x20, 0, 0},
+ {0x42, 0x20, 0x20, 0, 0},
+ {0x43, 0, 0, 0, 0},
+ {0x44, 0x77, 0x77, 0, 0},
+ {0x45, 0x7, 0x7, 0, 0},
+ {0x46, 0x1, 0x1, 0, 0},
+ {0x47, 0x6, 0x6, 1, 1},
+ {0x48, 0xf, 0xf, 0, 0},
+ {0x49, 0x3f, 0x3f, 1, 1},
+ {0x4A, 0x32, 0x32, 0, 0},
+ {0x4B, 0x6, 0x6, 1, 1},
+ {0x4C, 0x6, 0x6, 1, 1},
+ {0x4D, 0x4, 0x4, 0, 0},
+ {0x4E, 0x2b, 0x2b, 1, 1},
+ {0x4F, 0x1, 0x1, 0, 0},
+ {0x50, 0x1c, 0x1c, 0, 0},
+ {0x51, 0x2, 0x2, 0, 0},
+ {0x52, 0x2, 0x2, 0, 0},
+ {0x53, 0xf7, 0xf7, 1, 1},
+ {0x54, 0xb4, 0xb4, 0, 0},
+ {0x55, 0xd2, 0xd2, 0, 0},
+ {0x56, 0, 0, 0, 0},
+ {0x57, 0, 0, 0, 0},
+ {0x58, 0x4, 0x4, 0, 0},
+ {0x59, 0x96, 0x96, 0, 0},
+ {0x5A, 0x3e, 0x3e, 0, 0},
+ {0x5B, 0x3e, 0x3e, 0, 0},
+ {0x5C, 0x13, 0x13, 0, 0},
+ {0x5D, 0x2, 0x2, 0, 0},
+ {0x5E, 0, 0, 0, 0},
+ {0x5F, 0x7, 0x7, 0, 0},
+ {0x60, 0x7, 0x7, 1, 1},
+ {0x61, 0x8, 0x8, 0, 0},
+ {0x62, 0x3, 0x3, 0, 0},
+ {0x63, 0, 0, 0, 0},
+ {0x64, 0, 0, 0, 0},
+ {0x65, 0, 0, 0, 0},
+ {0x66, 0, 0, 0, 0},
+ {0x67, 0, 0, 0, 0},
+ {0x68, 0x40, 0x40, 0, 0},
+ {0x69, 0, 0, 0, 0},
+ {0x6A, 0, 0, 0, 0},
+ {0x6B, 0, 0, 0, 0},
+ {0x6C, 0, 0, 0, 0},
+ {0x6D, 0x1, 0x1, 0, 0},
+ {0x6E, 0, 0, 0, 0},
+ {0x6F, 0, 0, 0, 0},
+ {0x70, 0x60, 0x60, 0, 0},
+ {0x71, 0x66, 0x66, 0, 0},
+ {0x72, 0xc, 0xc, 0, 0},
+ {0x73, 0x66, 0x66, 0, 0},
+ {0x74, 0x8f, 0x8f, 1, 1},
+ {0x75, 0, 0, 0, 0},
+ {0x76, 0xcc, 0xcc, 0, 0},
+ {0x77, 0x1, 0x1, 0, 0},
+ {0x78, 0x66, 0x66, 0, 0},
+ {0x79, 0x66, 0x66, 0, 0},
+ {0x7A, 0, 0, 0, 0},
+ {0x7B, 0, 0, 0, 0},
+ {0x7C, 0, 0, 0, 0},
+ {0x7D, 0, 0, 0, 0},
+ {0x7E, 0, 0, 0, 0},
+ {0x7F, 0, 0, 0, 0},
+ {0x80, 0, 0, 0, 0},
+ {0x81, 0, 0, 0, 0},
+ {0x82, 0, 0, 0, 0},
+ {0x83, 0, 0, 0, 0},
+ {0x84, 0, 0, 0, 0},
+ {0x85, 0xff, 0xff, 0, 0},
+ {0x86, 0, 0, 0, 0},
+ {0x87, 0, 0, 0, 0},
+ {0x88, 0, 0, 0, 0},
+ {0x89, 0, 0, 0, 0},
+ {0x8A, 0, 0, 0, 0},
+ {0x8B, 0, 0, 0, 0},
+ {0x8C, 0, 0, 0, 0},
+ {0x8D, 0, 0, 0, 0},
+ {0x8E, 0, 0, 0, 0},
+ {0x8F, 0, 0, 0, 0},
+ {0x90, 0, 0, 0, 0},
+ {0x91, 0, 0, 0, 0},
+ {0x92, 0, 0, 0, 0},
+ {0x93, 0, 0, 0, 0},
+ {0x94, 0, 0, 0, 0},
+ {0x95, 0, 0, 0, 0},
+ {0x96, 0, 0, 0, 0},
+ {0x97, 0, 0, 0, 0},
+ {0x98, 0, 0, 0, 0},
+ {0x99, 0, 0, 0, 0},
+ {0x9A, 0, 0, 0, 0},
+ {0x9B, 0, 0, 0, 0},
+ {0x9C, 0, 0, 0, 0},
+ {0x9D, 0, 0, 0, 0},
+ {0x9E, 0, 0, 0, 0},
+ {0x9F, 0x6, 0x6, 0, 0},
+ {0xA0, 0x66, 0x66, 0, 0},
+ {0xA1, 0x66, 0x66, 0, 0},
+ {0xA2, 0x66, 0x66, 0, 0},
+ {0xA3, 0x66, 0x66, 0, 0},
+ {0xA4, 0x66, 0x66, 0, 0},
+ {0xA5, 0x66, 0x66, 0, 0},
+ {0xA6, 0x66, 0x66, 0, 0},
+ {0xA7, 0x66, 0x66, 0, 0},
+ {0xA8, 0x66, 0x66, 0, 0},
+ {0xA9, 0x66, 0x66, 0, 0},
+ {0xAA, 0x66, 0x66, 0, 0},
+ {0xAB, 0x66, 0x66, 0, 0},
+ {0xAC, 0x66, 0x66, 0, 0},
+ {0xAD, 0x66, 0x66, 0, 0},
+ {0xAE, 0x66, 0x66, 0, 0},
+ {0xAF, 0x66, 0x66, 0, 0},
+ {0xB0, 0x66, 0x66, 0, 0},
+ {0xB1, 0x66, 0x66, 0, 0},
+ {0xB2, 0x66, 0x66, 0, 0},
+ {0xB3, 0xa, 0xa, 0, 0},
+ {0xB4, 0, 0, 0, 0},
+ {0xB5, 0, 0, 0, 0},
+ {0xB6, 0, 0, 0, 0},
+ {0xFFFF, 0, 0, 0, 0},
+};
+
+static const struct radio_regs regs_TX_2056_rev11[] = {
+ {0x02, 0, 0, 0, 0},
+ {0x03, 0, 0, 0, 0},
+ {0x04, 0, 0, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0, 0, 0, 0},
+ {0x07, 0, 0, 0, 0},
+ {0x08, 0, 0, 0, 0},
+ {0x09, 0, 0, 0, 0},
+ {0x0A, 0, 0, 0, 0},
+ {0x0B, 0, 0, 0, 0},
+ {0x0C, 0, 0, 0, 0},
+ {0x0D, 0, 0, 0, 0},
+ {0x0E, 0, 0, 0, 0},
+ {0x0F, 0, 0, 0, 0},
+ {0x10, 0, 0, 0, 0},
+ {0x11, 0, 0, 0, 0},
+ {0x12, 0, 0, 0, 0},
+ {0x13, 0, 0, 0, 0},
+ {0x14, 0, 0, 0, 0},
+ {0x15, 0, 0, 0, 0},
+ {0x16, 0, 0, 0, 0},
+ {0x17, 0, 0, 0, 0},
+ {0x18, 0, 0, 0, 0},
+ {0x19, 0, 0, 0, 0},
+ {0x1A, 0, 0, 0, 0},
+ {0x1B, 0, 0, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0, 0, 0, 0},
+ {0x1E, 0, 0, 0, 0},
+ {0x1F, 0, 0, 0, 0},
+ {0x20, 0, 0, 0, 0},
+ {0x21, 0x88, 0x88, 0, 0},
+ {0x22, 0x88, 0x88, 0, 0},
+ {0x23, 0x88, 0x88, 0, 0},
+ {0x24, 0x88, 0x88, 0, 0},
+ {0x25, 0xc, 0xc, 0, 0},
+ {0x26, 0, 0, 0, 0},
+ {0x27, 0x3, 0x3, 0, 0},
+ {0x28, 0, 0, 0, 0},
+ {0x29, 0x3, 0x3, 0, 0},
+ {0x2A, 0x37, 0x37, 0, 0},
+ {0x2B, 0x3, 0x3, 0, 0},
+ {0x2C, 0, 0, 0, 0},
+ {0x2D, 0, 0, 0, 0},
+ {0x2E, 0x1, 0x1, 0, 0},
+ {0x2F, 0x1, 0x1, 0, 0},
+ {0x30, 0, 0, 0, 0},
+ {0x31, 0, 0, 0, 0},
+ {0x32, 0, 0, 0, 0},
+ {0x33, 0x11, 0x11, 0, 0},
+ {0x34, 0xee, 0xee, 1, 1},
+ {0x35, 0, 0, 0, 0},
+ {0x36, 0, 0, 0, 0},
+ {0x37, 0x3, 0x3, 0, 0},
+ {0x38, 0x50, 0x50, 1, 1},
+ {0x39, 0, 0, 0, 0},
+ {0x3A, 0x50, 0x50, 1, 1},
+ {0x3B, 0, 0, 0, 0},
+ {0x3C, 0x6e, 0x6e, 0, 0},
+ {0x3D, 0xf0, 0xf0, 1, 1},
+ {0x3E, 0, 0, 0, 0},
+ {0x3F, 0, 0, 0, 0},
+ {0x40, 0, 0, 0, 0},
+ {0x41, 0x3, 0x3, 0, 0},
+ {0x42, 0x3, 0x3, 0, 0},
+ {0x43, 0, 0, 0, 0},
+ {0x44, 0x1e, 0x1e, 0, 0},
+ {0x45, 0, 0, 0, 0},
+ {0x46, 0x6e, 0x6e, 0, 0},
+ {0x47, 0xf0, 0xf0, 1, 1},
+ {0x48, 0, 0, 0, 0},
+ {0x49, 0x2, 0x2, 0, 0},
+ {0x4A, 0xff, 0xff, 1, 1},
+ {0x4B, 0xc, 0xc, 0, 0},
+ {0x4C, 0, 0, 0, 0},
+ {0x4D, 0x38, 0x38, 0, 0},
+ {0x4E, 0x70, 0x70, 1, 1},
+ {0x4F, 0x2, 0x2, 0, 0},
+ {0x50, 0x88, 0x88, 0, 0},
+ {0x51, 0xc, 0xc, 0, 0},
+ {0x52, 0, 0, 0, 0},
+ {0x53, 0x8, 0x8, 0, 0},
+ {0x54, 0x70, 0x70, 1, 1},
+ {0x55, 0x2, 0x2, 0, 0},
+ {0x56, 0xff, 0xff, 1, 1},
+ {0x57, 0, 0, 0, 0},
+ {0x58, 0x83, 0x83, 0, 0},
+ {0x59, 0x77, 0x77, 1, 1},
+ {0x5A, 0, 0, 0, 0},
+ {0x5B, 0x2, 0x2, 0, 0},
+ {0x5C, 0x88, 0x88, 0, 0},
+ {0x5D, 0, 0, 0, 0},
+ {0x5E, 0x8, 0x8, 0, 0},
+ {0x5F, 0x77, 0x77, 1, 1},
+ {0x60, 0x1, 0x1, 0, 0},
+ {0x61, 0, 0, 0, 0},
+ {0x62, 0x7, 0x7, 0, 0},
+ {0x63, 0, 0, 0, 0},
+ {0x64, 0x7, 0x7, 0, 0},
+ {0x65, 0, 0, 0, 0},
+ {0x66, 0, 0, 0, 0},
+ {0x67, 0, 0, 1, 1},
+ {0x68, 0, 0, 0, 0},
+ {0x69, 0xa, 0xa, 0, 0},
+ {0x6A, 0, 0, 0, 0},
+ {0x6B, 0, 0, 0, 0},
+ {0x6C, 0, 0, 0, 0},
+ {0x6D, 0, 0, 0, 0},
+ {0x6E, 0, 0, 0, 0},
+ {0x6F, 0, 0, 0, 0},
+ {0x70, 0, 0, 0, 0},
+ {0x71, 0x2, 0x2, 0, 0},
+ {0x72, 0, 0, 0, 0},
+ {0x73, 0, 0, 0, 0},
+ {0x74, 0xe, 0xe, 0, 0},
+ {0x75, 0xe, 0xe, 0, 0},
+ {0x76, 0xe, 0xe, 0, 0},
+ {0x77, 0x13, 0x13, 0, 0},
+ {0x78, 0x13, 0x13, 0, 0},
+ {0x79, 0x1b, 0x1b, 0, 0},
+ {0x7A, 0x1b, 0x1b, 0, 0},
+ {0x7B, 0x55, 0x55, 0, 0},
+ {0x7C, 0x5b, 0x5b, 0, 0},
+ {0x7D, 0x30, 0x30, 1, 1},
+ {0x7E, 0, 0, 0, 0},
+ {0x7F, 0, 0, 0, 0},
+ {0x80, 0, 0, 0, 0},
+ {0x81, 0, 0, 0, 0},
+ {0x82, 0, 0, 0, 0},
+ {0x83, 0, 0, 0, 0},
+ {0x84, 0, 0, 0, 0},
+ {0x85, 0, 0, 0, 0},
+ {0x86, 0, 0, 0, 0},
+ {0x87, 0, 0, 0, 0},
+ {0x88, 0, 0, 0, 0},
+ {0x89, 0, 0, 0, 0},
+ {0x8A, 0, 0, 0, 0},
+ {0x8B, 0, 0, 0, 0},
+ {0x8C, 0, 0, 0, 0},
+ {0x8D, 0, 0, 0, 0},
+ {0x8E, 0, 0, 0, 0},
+ {0x8F, 0, 0, 0, 0},
+ {0x90, 0, 0, 0, 0},
+ {0x91, 0, 0, 0, 0},
+ {0x92, 0, 0, 0, 0},
+ {0x93, 0x70, 0x70, 0, 0},
+ {0x94, 0x70, 0x70, 0, 0},
+ {0x95, 0x70, 0x70, 0, 0},
+ {0x96, 0x70, 0x70, 0, 0},
+ {0x97, 0x70, 0x70, 0, 0},
+ {0x98, 0x70, 0x70, 0, 0},
+ {0x99, 0x70, 0x70, 0, 0},
+ {0x9A, 0x70, 0x70, 0, 0},
+ {0xFFFF, 0, 0, 0, 0},
+};
+
+static const struct radio_regs regs_RX_2056_rev11[] = {
+ {0x02, 0, 0, 0, 0},
+ {0x03, 0, 0, 0, 0},
+ {0x04, 0, 0, 0, 0},
+ {0x05, 0, 0, 0, 0},
+ {0x06, 0, 0, 0, 0},
+ {0x07, 0, 0, 0, 0},
+ {0x08, 0, 0, 0, 0},
+ {0x09, 0, 0, 0, 0},
+ {0x0A, 0, 0, 0, 0},
+ {0x0B, 0, 0, 0, 0},
+ {0x0C, 0, 0, 0, 0},
+ {0x0D, 0, 0, 0, 0},
+ {0x0E, 0, 0, 0, 0},
+ {0x0F, 0, 0, 0, 0},
+ {0x10, 0, 0, 0, 0},
+ {0x11, 0, 0, 0, 0},
+ {0x12, 0, 0, 0, 0},
+ {0x13, 0, 0, 0, 0},
+ {0x14, 0, 0, 0, 0},
+ {0x15, 0, 0, 0, 0},
+ {0x16, 0, 0, 0, 0},
+ {0x17, 0, 0, 0, 0},
+ {0x18, 0, 0, 0, 0},
+ {0x19, 0, 0, 0, 0},
+ {0x1A, 0, 0, 0, 0},
+ {0x1B, 0, 0, 0, 0},
+ {0x1C, 0, 0, 0, 0},
+ {0x1D, 0, 0, 0, 0},
+ {0x1E, 0, 0, 0, 0},
+ {0x1F, 0, 0, 0, 0},
+ {0x20, 0x3, 0x3, 0, 0},
+ {0x21, 0, 0, 0, 0},
+ {0x22, 0, 0, 0, 0},
+ {0x23, 0x90, 0x90, 0, 0},
+ {0x24, 0x55, 0x55, 0, 0},
+ {0x25, 0x15, 0x15, 0, 0},
+ {0x26, 0x5, 0x5, 0, 0},
+ {0x27, 0x15, 0x15, 0, 0},
+ {0x28, 0x5, 0x5, 0, 0},
+ {0x29, 0x20, 0x20, 0, 0},
+ {0x2A, 0x11, 0x11, 0, 0},
+ {0x2B, 0x90, 0x90, 0, 0},
+ {0x2C, 0, 0, 0, 0},
+ {0x2D, 0x88, 0x88, 0, 0},
+ {0x2E, 0x32, 0x32, 0, 0},
+ {0x2F, 0x77, 0x77, 0, 0},
+ {0x30, 0x17, 0x17, 1, 1},
+ {0x31, 0xff, 0xff, 1, 1},
+ {0x32, 0x20, 0x20, 0, 0},
+ {0x33, 0, 0, 0, 0},
+ {0x34, 0x88, 0x88, 0, 0},
+ {0x35, 0x32, 0x32, 0, 0},
+ {0x36, 0x77, 0x77, 0, 0},
+ {0x37, 0x17, 0x17, 1, 1},
+ {0x38, 0xf0, 0xf0, 1, 1},
+ {0x39, 0x20, 0x20, 0, 0},
+ {0x3A, 0x8, 0x8, 0, 0},
+ {0x3B, 0x55, 0x55, 1, 1},
+ {0x3C, 0, 0, 0, 0},
+ {0x3D, 0x88, 0x88, 1, 1},
+ {0x3E, 0, 0, 0, 0},
+ {0x3F, 0x44, 0x44, 0, 0},
+ {0x40, 0x7, 0x7, 1, 1},
+ {0x41, 0x6, 0x6, 0, 0},
+ {0x42, 0x4, 0x4, 0, 0},
+ {0x43, 0, 0, 0, 0},
+ {0x44, 0x8, 0x8, 0, 0},
+ {0x45, 0x55, 0x55, 1, 1},
+ {0x46, 0, 0, 0, 0},
+ {0x47, 0x11, 0x11, 0, 0},
+ {0x48, 0, 0, 0, 0},
+ {0x49, 0x44, 0x44, 0, 0},
+ {0x4A, 0x7, 0x7, 0, 0},
+ {0x4B, 0x6, 0x6, 0, 0},
+ {0x4C, 0x4, 0x4, 0, 0},
+ {0x4D, 0, 0, 0, 0},
+ {0x4E, 0, 0, 0, 0},
+ {0x4F, 0x26, 0x26, 1, 1},
+ {0x50, 0x26, 0x26, 1, 1},
+ {0x51, 0xf, 0xf, 1, 1},
+ {0x52, 0xf, 0xf, 1, 1},
+ {0x53, 0x44, 0x44, 0, 0},
+ {0x54, 0, 0, 0, 0},
+ {0x55, 0, 0, 0, 0},
+ {0x56, 0x8, 0x8, 0, 0},
+ {0x57, 0x8, 0x8, 0, 0},
+ {0x58, 0x7, 0x7, 0, 0},
+ {0x59, 0x22, 0x22, 0, 0},
+ {0x5A, 0x22, 0x22, 0, 0},
+ {0x5B, 0x2, 0x2, 0, 0},
+ {0x5C, 0x4, 0x4, 1, 1},
+ {0x5D, 0x7, 0x7, 0, 0},
+ {0x5E, 0x55, 0x55, 0, 0},
+ {0x5F, 0x23, 0x23, 0, 0},
+ {0x60, 0x41, 0x41, 0, 0},
+ {0x61, 0x1, 0x1, 0, 0},
+ {0x62, 0xa, 0xa, 0, 0},
+ {0x63, 0, 0, 0, 0},
+ {0x64, 0, 0, 0, 0},
+ {0x65, 0, 0, 0, 0},
+ {0x66, 0, 0, 0, 0},
+ {0x67, 0, 0, 0, 0},
+ {0x68, 0, 0, 0, 0},
+ {0x69, 0, 0, 0, 0},
+ {0x6A, 0, 0, 0, 0},
+ {0x6B, 0xc, 0xc, 0, 0},
+ {0x6C, 0, 0, 0, 0},
+ {0x6D, 0, 0, 0, 0},
+ {0x6E, 0, 0, 0, 0},
+ {0x6F, 0, 0, 0, 0},
+ {0x70, 0, 0, 0, 0},
+ {0x71, 0, 0, 0, 0},
+ {0x72, 0x22, 0x22, 0, 0},
+ {0x73, 0x22, 0x22, 0, 0},
+ {0x74, 0, 0, 1, 1},
+ {0x75, 0xa, 0xa, 0, 0},
+ {0x76, 0x1, 0x1, 0, 0},
+ {0x77, 0x22, 0x22, 0, 0},
+ {0x78, 0x30, 0x30, 0, 0},
+ {0x79, 0, 0, 0, 0},
+ {0x7A, 0, 0, 0, 0},
+ {0x7B, 0, 0, 0, 0},
+ {0x7C, 0, 0, 0, 0},
+ {0x7D, 0x5, 0x5, 1, 1},
+ {0x7E, 0, 0, 0, 0},
+ {0x7F, 0, 0, 0, 0},
+ {0x80, 0, 0, 0, 0},
+ {0x81, 0, 0, 0, 0},
+ {0x82, 0, 0, 0, 0},
+ {0x83, 0, 0, 0, 0},
+ {0x84, 0, 0, 0, 0},
+ {0x85, 0, 0, 0, 0},
+ {0x86, 0, 0, 0, 0},
+ {0x87, 0, 0, 0, 0},
+ {0x88, 0, 0, 0, 0},
+ {0x89, 0, 0, 0, 0},
+ {0x8A, 0, 0, 0, 0},
+ {0x8B, 0, 0, 0, 0},
+ {0x8C, 0, 0, 0, 0},
+ {0x8D, 0, 0, 0, 0},
+ {0x8E, 0, 0, 0, 0},
+ {0x8F, 0, 0, 0, 0},
+ {0x90, 0, 0, 0, 0},
+ {0x91, 0, 0, 0, 0},
+ {0x92, 0, 0, 0, 0},
+ {0x93, 0, 0, 0, 0},
+ {0x94, 0, 0, 0, 0},
+ {0xFFFF, 0, 0, 0, 0},
+};
+
+static struct radio_20xx_regs regs_2057_rev4[] = {
+ {0x00, 0x84, 0},
+ {0x01, 0, 0},
+ {0x02, 0x60, 0},
+ {0x03, 0x1f, 0},
+ {0x04, 0x4, 0},
+ {0x05, 0x2, 0},
+ {0x06, 0x1, 0},
+ {0x07, 0x1, 0},
+ {0x08, 0x1, 0},
+ {0x09, 0x69, 0},
+ {0x0A, 0x66, 0},
+ {0x0B, 0x6, 0},
+ {0x0C, 0x18, 0},
+ {0x0D, 0x3, 0},
+ {0x0E, 0x20, 1},
+ {0x0F, 0x20, 0},
+ {0x10, 0, 0},
+ {0x11, 0x7c, 0},
+ {0x12, 0x42, 0},
+ {0x13, 0xbd, 0},
+ {0x14, 0x7, 0},
+ {0x15, 0xf7, 0},
+ {0x16, 0x8, 0},
+ {0x17, 0x17, 0},
+ {0x18, 0x7, 0},
+ {0x19, 0, 0},
+ {0x1A, 0x2, 0},
+ {0x1B, 0x13, 0},
+ {0x1C, 0x3e, 0},
+ {0x1D, 0x3e, 0},
+ {0x1E, 0x96, 0},
+ {0x1F, 0x4, 0},
+ {0x20, 0, 0},
+ {0x21, 0, 0},
+ {0x22, 0x17, 0},
+ {0x23, 0x4, 0},
+ {0x24, 0x1, 0},
+ {0x25, 0x6, 0},
+ {0x26, 0x4, 0},
+ {0x27, 0xd, 0},
+ {0x28, 0xd, 0},
+ {0x29, 0x30, 0},
+ {0x2A, 0x32, 0},
+ {0x2B, 0x8, 0},
+ {0x2C, 0x1c, 0},
+ {0x2D, 0x2, 0},
+ {0x2E, 0x4, 0},
+ {0x2F, 0x7f, 0},
+ {0x30, 0x27, 0},
+ {0x31, 0, 1},
+ {0x32, 0, 1},
+ {0x33, 0, 1},
+ {0x34, 0, 0},
+ {0x35, 0x26, 1},
+ {0x36, 0x18, 0},
+ {0x37, 0x7, 0},
+ {0x38, 0x66, 0},
+ {0x39, 0x66, 0},
+ {0x3A, 0x66, 0},
+ {0x3B, 0x66, 0},
+ {0x3C, 0xff, 1},
+ {0x3D, 0xff, 1},
+ {0x3E, 0xff, 1},
+ {0x3F, 0xff, 1},
+ {0x40, 0x16, 0},
+ {0x41, 0x7, 0},
+ {0x42, 0x19, 0},
+ {0x43, 0x7, 0},
+ {0x44, 0x6, 0},
+ {0x45, 0x3, 0},
+ {0x46, 0x1, 0},
+ {0x47, 0x7, 0},
+ {0x48, 0x33, 0},
+ {0x49, 0x5, 0},
+ {0x4A, 0x77, 0},
+ {0x4B, 0x66, 0},
+ {0x4C, 0x66, 0},
+ {0x4D, 0, 0},
+ {0x4E, 0x4, 0},
+ {0x4F, 0xc, 0},
+ {0x50, 0, 0},
+ {0x51, 0x75, 0},
+ {0x56, 0x7, 0},
+ {0x57, 0, 0},
+ {0x58, 0, 0},
+ {0x59, 0xa8, 0},
+ {0x5A, 0, 0},
+ {0x5B, 0x1f, 0},
+ {0x5C, 0x30, 0},
+ {0x5D, 0x1, 0},
+ {0x5E, 0x30, 0},
+ {0x5F, 0x70, 0},
+ {0x60, 0, 0},
+ {0x61, 0, 0},
+ {0x62, 0x33, 1},
+ {0x63, 0x19, 0},
+ {0x64, 0x62, 0},
+ {0x65, 0, 0},
+ {0x66, 0x11, 0},
+ {0x69, 0, 0},
+ {0x6A, 0x7e, 0},
+ {0x6B, 0x3f, 0},
+ {0x6C, 0x7f, 0},
+ {0x6D, 0x78, 0},
+ {0x6E, 0xc8, 0},
+ {0x6F, 0x88, 0},
+ {0x70, 0x8, 0},
+ {0x71, 0xf, 0},
+ {0x72, 0xbc, 0},
+ {0x73, 0x8, 0},
+ {0x74, 0x60, 0},
+ {0x75, 0x1e, 0},
+ {0x76, 0x70, 0},
+ {0x77, 0, 0},
+ {0x78, 0, 0},
+ {0x79, 0, 0},
+ {0x7A, 0x33, 0},
+ {0x7B, 0x1e, 0},
+ {0x7C, 0x62, 0},
+ {0x7D, 0x11, 0},
+ {0x80, 0x3c, 0},
+ {0x81, 0x9c, 0},
+ {0x82, 0xa, 0},
+ {0x83, 0x9d, 0},
+ {0x84, 0xa, 0},
+ {0x85, 0, 0},
+ {0x86, 0x40, 0},
+ {0x87, 0x40, 0},
+ {0x88, 0x88, 0},
+ {0x89, 0x10, 0},
+ {0x8A, 0xf0, 1},
+ {0x8B, 0x10, 1},
+ {0x8C, 0xf0, 1},
+ {0x8D, 0, 0},
+ {0x8E, 0, 0},
+ {0x8F, 0x10, 0},
+ {0x90, 0x55, 0},
+ {0x91, 0x3f, 1},
+ {0x92, 0x36, 1},
+ {0x93, 0, 0},
+ {0x94, 0, 0},
+ {0x95, 0, 0},
+ {0x96, 0x87, 0},
+ {0x97, 0x11, 0},
+ {0x98, 0, 0},
+ {0x99, 0x33, 0},
+ {0x9A, 0x88, 0},
+ {0x9B, 0, 0},
+ {0x9C, 0x87, 0},
+ {0x9D, 0x11, 0},
+ {0x9E, 0, 0},
+ {0x9F, 0x33, 0},
+ {0xA0, 0x88, 0},
+ {0xA1, 0xe1, 0},
+ {0xA2, 0x3f, 0},
+ {0xA3, 0x44, 0},
+ {0xA4, 0x8c, 1},
+ {0xA5, 0x6d, 0},
+ {0xA6, 0x22, 0},
+ {0xA7, 0xbe, 0},
+ {0xA8, 0x55, 1},
+ {0xA9, 0xc, 0},
+ {0xAA, 0xc, 0},
+ {0xAB, 0xaa, 0},
+ {0xAC, 0x2, 0},
+ {0xAD, 0, 0},
+ {0xAE, 0x10, 0},
+ {0xAF, 0x1, 1},
+ {0xB0, 0, 0},
+ {0xB1, 0, 0},
+ {0xB2, 0x80, 0},
+ {0xB3, 0x60, 0},
+ {0xB4, 0x44, 0},
+ {0xB5, 0x55, 0},
+ {0xB6, 0x1, 0},
+ {0xB7, 0x55, 0},
+ {0xB8, 0x1, 0},
+ {0xB9, 0x5, 0},
+ {0xBA, 0x55, 0},
+ {0xBB, 0x55, 0},
+ {0xC1, 0, 0},
+ {0xC2, 0, 0},
+ {0xC3, 0, 0},
+ {0xC4, 0, 0},
+ {0xC5, 0, 0},
+ {0xC6, 0, 0},
+ {0xC7, 0, 0},
+ {0xC8, 0, 0},
+ {0xC9, 0, 0},
+ {0xCA, 0, 0},
+ {0xCB, 0, 0},
+ {0xCC, 0, 0},
+ {0xCD, 0, 0},
+ {0xCE, 0x5e, 0},
+ {0xCF, 0xc, 0},
+ {0xD0, 0xc, 0},
+ {0xD1, 0xc, 0},
+ {0xD2, 0, 0},
+ {0xD3, 0x2b, 0},
+ {0xD4, 0xc, 0},
+ {0xD5, 0, 0},
+ {0xD6, 0x75, 0},
+ {0xDB, 0x7, 0},
+ {0xDC, 0, 0},
+ {0xDD, 0, 0},
+ {0xDE, 0xa8, 0},
+ {0xDF, 0, 0},
+ {0xE0, 0x1f, 0},
+ {0xE1, 0x30, 0},
+ {0xE2, 0x1, 0},
+ {0xE3, 0x30, 0},
+ {0xE4, 0x70, 0},
+ {0xE5, 0, 0},
+ {0xE6, 0, 0},
+ {0xE7, 0x33, 0},
+ {0xE8, 0x19, 0},
+ {0xE9, 0x62, 0},
+ {0xEA, 0, 0},
+ {0xEB, 0x11, 0},
+ {0xEE, 0, 0},
+ {0xEF, 0x7e, 0},
+ {0xF0, 0x3f, 0},
+ {0xF1, 0x7f, 0},
+ {0xF2, 0x78, 0},
+ {0xF3, 0xc8, 0},
+ {0xF4, 0x88, 0},
+ {0xF5, 0x8, 0},
+ {0xF6, 0xf, 0},
+ {0xF7, 0xbc, 0},
+ {0xF8, 0x8, 0},
+ {0xF9, 0x60, 0},
+ {0xFA, 0x1e, 0},
+ {0xFB, 0x70, 0},
+ {0xFC, 0, 0},
+ {0xFD, 0, 0},
+ {0xFE, 0, 0},
+ {0xFF, 0x33, 0},
+ {0x100, 0x1e, 0},
+ {0x101, 0x62, 0},
+ {0x102, 0x11, 0},
+ {0x105, 0x3c, 0},
+ {0x106, 0x9c, 0},
+ {0x107, 0xa, 0},
+ {0x108, 0x9d, 0},
+ {0x109, 0xa, 0},
+ {0x10A, 0, 0},
+ {0x10B, 0x40, 0},
+ {0x10C, 0x40, 0},
+ {0x10D, 0x88, 0},
+ {0x10E, 0x10, 0},
+ {0x10F, 0xf0, 1},
+ {0x110, 0x10, 1},
+ {0x111, 0xf0, 1},
+ {0x112, 0, 0},
+ {0x113, 0, 0},
+ {0x114, 0x10, 0},
+ {0x115, 0x55, 0},
+ {0x116, 0x3f, 1},
+ {0x117, 0x36, 1},
+ {0x118, 0, 0},
+ {0x119, 0, 0},
+ {0x11A, 0, 0},
+ {0x11B, 0x87, 0},
+ {0x11C, 0x11, 0},
+ {0x11D, 0, 0},
+ {0x11E, 0x33, 0},
+ {0x11F, 0x88, 0},
+ {0x120, 0, 0},
+ {0x121, 0x87, 0},
+ {0x122, 0x11, 0},
+ {0x123, 0, 0},
+ {0x124, 0x33, 0},
+ {0x125, 0x88, 0},
+ {0x126, 0xe1, 0},
+ {0x127, 0x3f, 0},
+ {0x128, 0x44, 0},
+ {0x129, 0x8c, 1},
+ {0x12A, 0x6d, 0},
+ {0x12B, 0x22, 0},
+ {0x12C, 0xbe, 0},
+ {0x12D, 0x55, 1},
+ {0x12E, 0xc, 0},
+ {0x12F, 0xc, 0},
+ {0x130, 0xaa, 0},
+ {0x131, 0x2, 0},
+ {0x132, 0, 0},
+ {0x133, 0x10, 0},
+ {0x134, 0x1, 1},
+ {0x135, 0, 0},
+ {0x136, 0, 0},
+ {0x137, 0x80, 0},
+ {0x138, 0x60, 0},
+ {0x139, 0x44, 0},
+ {0x13A, 0x55, 0},
+ {0x13B, 0x1, 0},
+ {0x13C, 0x55, 0},
+ {0x13D, 0x1, 0},
+ {0x13E, 0x5, 0},
+ {0x13F, 0x55, 0},
+ {0x140, 0x55, 0},
+ {0x146, 0, 0},
+ {0x147, 0, 0},
+ {0x148, 0, 0},
+ {0x149, 0, 0},
+ {0x14A, 0, 0},
+ {0x14B, 0, 0},
+ {0x14C, 0, 0},
+ {0x14D, 0, 0},
+ {0x14E, 0, 0},
+ {0x14F, 0, 0},
+ {0x150, 0, 0},
+ {0x151, 0, 0},
+ {0x152, 0, 0},
+ {0x153, 0, 0},
+ {0x154, 0xc, 0},
+ {0x155, 0xc, 0},
+ {0x156, 0xc, 0},
+ {0x157, 0, 0},
+ {0x158, 0x2b, 0},
+ {0x159, 0x84, 0},
+ {0x15A, 0x15, 0},
+ {0x15B, 0xf, 0},
+ {0x15C, 0, 0},
+ {0x15D, 0, 0},
+ {0x15E, 0, 1},
+ {0x15F, 0, 1},
+ {0x160, 0, 1},
+ {0x161, 0, 1},
+ {0x162, 0, 1},
+ {0x163, 0, 1},
+ {0x164, 0, 0},
+ {0x165, 0, 0},
+ {0x166, 0, 0},
+ {0x167, 0, 0},
+ {0x168, 0, 0},
+ {0x169, 0x2, 1},
+ {0x16A, 0, 1},
+ {0x16B, 0, 1},
+ {0x16C, 0, 1},
+ {0x16D, 0, 0},
+ {0x170, 0, 0},
+ {0x171, 0x77, 0},
+ {0x172, 0x77, 0},
+ {0x173, 0x77, 0},
+ {0x174, 0x77, 0},
+ {0x175, 0, 0},
+ {0x176, 0x3, 0},
+ {0x177, 0x37, 0},
+ {0x178, 0x3, 0},
+ {0x179, 0, 0},
+ {0x17A, 0x21, 0},
+ {0x17B, 0x21, 0},
+ {0x17C, 0, 0},
+ {0x17D, 0xaa, 0},
+ {0x17E, 0, 0},
+ {0x17F, 0xaa, 0},
+ {0x180, 0, 0},
+ {0x190, 0, 0},
+ {0x191, 0x77, 0},
+ {0x192, 0x77, 0},
+ {0x193, 0x77, 0},
+ {0x194, 0x77, 0},
+ {0x195, 0, 0},
+ {0x196, 0x3, 0},
+ {0x197, 0x37, 0},
+ {0x198, 0x3, 0},
+ {0x199, 0, 0},
+ {0x19A, 0x21, 0},
+ {0x19B, 0x21, 0},
+ {0x19C, 0, 0},
+ {0x19D, 0xaa, 0},
+ {0x19E, 0, 0},
+ {0x19F, 0xaa, 0},
+ {0x1A0, 0, 0},
+ {0x1A1, 0x2, 0},
+ {0x1A2, 0xf, 0},
+ {0x1A3, 0xf, 0},
+ {0x1A4, 0, 1},
+ {0x1A5, 0, 1},
+ {0x1A6, 0, 1},
+ {0x1A7, 0x2, 0},
+ {0x1A8, 0xf, 0},
+ {0x1A9, 0xf, 0},
+ {0x1AA, 0, 1},
+ {0x1AB, 0, 1},
+ {0x1AC, 0, 1},
+ {0xFFFF, 0, 0},
+};
+
+static struct radio_20xx_regs regs_2057_rev5[] = {
+ {0x00, 0, 1},
+ {0x01, 0x57, 1},
+ {0x02, 0x20, 1},
+ {0x03, 0x1f, 0},
+ {0x04, 0x4, 0},
+ {0x05, 0x2, 0},
+ {0x06, 0x1, 0},
+ {0x07, 0x1, 0},
+ {0x08, 0x1, 0},
+ {0x09, 0x69, 0},
+ {0x0A, 0x66, 0},
+ {0x0B, 0x6, 0},
+ {0x0C, 0x18, 0},
+ {0x0D, 0x3, 0},
+ {0x0E, 0x20, 0},
+ {0x0F, 0x20, 0},
+ {0x10, 0, 0},
+ {0x11, 0x7c, 0},
+ {0x12, 0x42, 0},
+ {0x13, 0xbd, 0},
+ {0x14, 0x7, 0},
+ {0x15, 0x87, 0},
+ {0x16, 0x8, 0},
+ {0x17, 0x17, 0},
+ {0x18, 0x7, 0},
+ {0x19, 0, 0},
+ {0x1A, 0x2, 0},
+ {0x1B, 0x13, 0},
+ {0x1C, 0x3e, 0},
+ {0x1D, 0x3e, 0},
+ {0x1E, 0x96, 0},
+ {0x1F, 0x4, 0},
+ {0x20, 0, 0},
+ {0x21, 0, 0},
+ {0x22, 0x17, 0},
+ {0x23, 0x6, 1},
+ {0x24, 0x1, 0},
+ {0x25, 0x6, 0},
+ {0x26, 0x4, 0},
+ {0x27, 0xd, 0},
+ {0x28, 0xd, 0},
+ {0x29, 0x30, 0},
+ {0x2A, 0x32, 0},
+ {0x2B, 0x8, 0},
+ {0x2C, 0x1c, 0},
+ {0x2D, 0x2, 0},
+ {0x2E, 0x4, 0},
+ {0x2F, 0x7f, 0},
+ {0x30, 0x27, 0},
+ {0x31, 0, 1},
+ {0x32, 0, 1},
+ {0x33, 0, 1},
+ {0x34, 0, 0},
+ {0x35, 0x20, 0},
+ {0x36, 0x18, 0},
+ {0x37, 0x7, 0},
+ {0x38, 0x66, 0},
+ {0x39, 0x66, 0},
+ {0x3C, 0xff, 0},
+ {0x3D, 0xff, 0},
+ {0x40, 0x16, 0},
+ {0x41, 0x7, 0},
+ {0x45, 0x3, 0},
+ {0x46, 0x1, 0},
+ {0x47, 0x7, 0},
+ {0x4B, 0x66, 0},
+ {0x4C, 0x66, 0},
+ {0x4D, 0, 0},
+ {0x4E, 0x4, 0},
+ {0x4F, 0xc, 0},
+ {0x50, 0, 0},
+ {0x51, 0x70, 1},
+ {0x56, 0x7, 0},
+ {0x57, 0, 0},
+ {0x58, 0, 0},
+ {0x59, 0x88, 1},
+ {0x5A, 0, 0},
+ {0x5B, 0x1f, 0},
+ {0x5C, 0x20, 1},
+ {0x5D, 0x1, 0},
+ {0x5E, 0x30, 0},
+ {0x5F, 0x70, 0},
+ {0x60, 0, 0},
+ {0x61, 0, 0},
+ {0x62, 0x33, 1},
+ {0x63, 0xf, 1},
+ {0x64, 0xf, 1},
+ {0x65, 0, 0},
+ {0x66, 0x11, 0},
+ {0x80, 0x3c, 0},
+ {0x81, 0x1, 1},
+ {0x82, 0xa, 0},
+ {0x85, 0, 0},
+ {0x86, 0x40, 0},
+ {0x87, 0x40, 0},
+ {0x88, 0x88, 0},
+ {0x89, 0x10, 0},
+ {0x8A, 0xf0, 0},
+ {0x8B, 0x10, 0},
+ {0x8C, 0xf0, 0},
+ {0x8F, 0x10, 0},
+ {0x90, 0x55, 0},
+ {0x91, 0x3f, 1},
+ {0x92, 0x36, 1},
+ {0x93, 0, 0},
+ {0x94, 0, 0},
+ {0x95, 0, 0},
+ {0x96, 0x87, 0},
+ {0x97, 0x11, 0},
+ {0x98, 0, 0},
+ {0x99, 0x33, 0},
+ {0x9A, 0x88, 0},
+ {0xA1, 0x20, 1},
+ {0xA2, 0x3f, 0},
+ {0xA3, 0x44, 0},
+ {0xA4, 0x8c, 0},
+ {0xA5, 0x6c, 0},
+ {0xA6, 0x22, 0},
+ {0xA7, 0xbe, 0},
+ {0xA8, 0x55, 0},
+ {0xAA, 0xc, 0},
+ {0xAB, 0xaa, 0},
+ {0xAC, 0x2, 0},
+ {0xAD, 0, 0},
+ {0xAE, 0x10, 0},
+ {0xAF, 0x1, 0},
+ {0xB0, 0, 0},
+ {0xB1, 0, 0},
+ {0xB2, 0x80, 0},
+ {0xB3, 0x60, 0},
+ {0xB4, 0x44, 0},
+ {0xB5, 0x55, 0},
+ {0xB6, 0x1, 0},
+ {0xB7, 0x55, 0},
+ {0xB8, 0x1, 0},
+ {0xB9, 0x5, 0},
+ {0xBA, 0x55, 0},
+ {0xBB, 0x55, 0},
+ {0xC3, 0, 0},
+ {0xC4, 0, 0},
+ {0xC5, 0, 0},
+ {0xC6, 0, 0},
+ {0xC7, 0, 0},
+ {0xC8, 0, 0},
+ {0xC9, 0, 0},
+ {0xCA, 0, 0},
+ {0xCB, 0, 0},
+ {0xCD, 0, 0},
+ {0xCE, 0x5e, 0},
+ {0xCF, 0xc, 0},
+ {0xD0, 0xc, 0},
+ {0xD1, 0xc, 0},
+ {0xD2, 0, 0},
+ {0xD3, 0x2b, 0},
+ {0xD4, 0xc, 0},
+ {0xD5, 0, 0},
+ {0xD6, 0x70, 1},
+ {0xDB, 0x7, 0},
+ {0xDC, 0, 0},
+ {0xDD, 0, 0},
+ {0xDE, 0x88, 1},
+ {0xDF, 0, 0},
+ {0xE0, 0x1f, 0},
+ {0xE1, 0x20, 1},
+ {0xE2, 0x1, 0},
+ {0xE3, 0x30, 0},
+ {0xE4, 0x70, 0},
+ {0xE5, 0, 0},
+ {0xE6, 0, 0},
+ {0xE7, 0x33, 0},
+ {0xE8, 0xf, 1},
+ {0xE9, 0xf, 1},
+ {0xEA, 0, 0},
+ {0xEB, 0x11, 0},
+ {0x105, 0x3c, 0},
+ {0x106, 0x1, 1},
+ {0x107, 0xa, 0},
+ {0x10A, 0, 0},
+ {0x10B, 0x40, 0},
+ {0x10C, 0x40, 0},
+ {0x10D, 0x88, 0},
+ {0x10E, 0x10, 0},
+ {0x10F, 0xf0, 0},
+ {0x110, 0x10, 0},
+ {0x111, 0xf0, 0},
+ {0x114, 0x10, 0},
+ {0x115, 0x55, 0},
+ {0x116, 0x3f, 1},
+ {0x117, 0x36, 1},
+ {0x118, 0, 0},
+ {0x119, 0, 0},
+ {0x11A, 0, 0},
+ {0x11B, 0x87, 0},
+ {0x11C, 0x11, 0},
+ {0x11D, 0, 0},
+ {0x11E, 0x33, 0},
+ {0x11F, 0x88, 0},
+ {0x126, 0x20, 1},
+ {0x127, 0x3f, 0},
+ {0x128, 0x44, 0},
+ {0x129, 0x8c, 0},
+ {0x12A, 0x6c, 0},
+ {0x12B, 0x22, 0},
+ {0x12C, 0xbe, 0},
+ {0x12D, 0x55, 0},
+ {0x12F, 0xc, 0},
+ {0x130, 0xaa, 0},
+ {0x131, 0x2, 0},
+ {0x132, 0, 0},
+ {0x133, 0x10, 0},
+ {0x134, 0x1, 0},
+ {0x135, 0, 0},
+ {0x136, 0, 0},
+ {0x137, 0x80, 0},
+ {0x138, 0x60, 0},
+ {0x139, 0x44, 0},
+ {0x13A, 0x55, 0},
+ {0x13B, 0x1, 0},
+ {0x13C, 0x55, 0},
+ {0x13D, 0x1, 0},
+ {0x13E, 0x5, 0},
+ {0x13F, 0x55, 0},
+ {0x140, 0x55, 0},
+ {0x148, 0, 0},
+ {0x149, 0, 0},
+ {0x14A, 0, 0},
+ {0x14B, 0, 0},
+ {0x14C, 0, 0},
+ {0x14D, 0, 0},
+ {0x14E, 0, 0},
+ {0x14F, 0, 0},
+ {0x150, 0, 0},
+ {0x154, 0xc, 0},
+ {0x155, 0xc, 0},
+ {0x156, 0xc, 0},
+ {0x157, 0, 0},
+ {0x158, 0x2b, 0},
+ {0x159, 0x84, 0},
+ {0x15A, 0x15, 0},
+ {0x15B, 0xf, 0},
+ {0x15C, 0, 0},
+ {0x15D, 0, 0},
+ {0x15E, 0, 1},
+ {0x15F, 0, 1},
+ {0x160, 0, 1},
+ {0x161, 0, 1},
+ {0x162, 0, 1},
+ {0x163, 0, 1},
+ {0x164, 0, 0},
+ {0x165, 0, 0},
+ {0x166, 0, 0},
+ {0x167, 0, 0},
+ {0x168, 0, 0},
+ {0x169, 0, 0},
+ {0x16A, 0, 1},
+ {0x16B, 0, 1},
+ {0x16C, 0, 1},
+ {0x16D, 0, 0},
+ {0x170, 0, 0},
+ {0x171, 0x77, 0},
+ {0x172, 0x77, 0},
+ {0x173, 0x77, 0},
+ {0x174, 0x77, 0},
+ {0x175, 0, 0},
+ {0x176, 0x3, 0},
+ {0x177, 0x37, 0},
+ {0x178, 0x3, 0},
+ {0x179, 0, 0},
+ {0x17B, 0x21, 0},
+ {0x17C, 0, 0},
+ {0x17D, 0xaa, 0},
+ {0x17E, 0, 0},
+ {0x190, 0, 0},
+ {0x191, 0x77, 0},
+ {0x192, 0x77, 0},
+ {0x193, 0x77, 0},
+ {0x194, 0x77, 0},
+ {0x195, 0, 0},
+ {0x196, 0x3, 0},
+ {0x197, 0x37, 0},
+ {0x198, 0x3, 0},
+ {0x199, 0, 0},
+ {0x19B, 0x21, 0},
+ {0x19C, 0, 0},
+ {0x19D, 0xaa, 0},
+ {0x19E, 0, 0},
+ {0x1A1, 0x2, 0},
+ {0x1A2, 0xf, 0},
+ {0x1A3, 0xf, 0},
+ {0x1A4, 0, 1},
+ {0x1A5, 0, 1},
+ {0x1A6, 0, 1},
+ {0x1A7, 0x2, 0},
+ {0x1A8, 0xf, 0},
+ {0x1A9, 0xf, 0},
+ {0x1AA, 0, 1},
+ {0x1AB, 0, 1},
+ {0x1AC, 0, 1},
+ {0x1AD, 0x84, 0},
+ {0x1AE, 0x60, 0},
+ {0x1AF, 0x47, 0},
+ {0x1B0, 0x47, 0},
+ {0x1B1, 0, 0},
+ {0x1B2, 0, 0},
+ {0x1B3, 0, 0},
+ {0x1B4, 0, 0},
+ {0x1B5, 0, 0},
+ {0x1B6, 0, 0},
+ {0x1B7, 0xc, 1},
+ {0x1B8, 0, 0},
+ {0x1B9, 0, 0},
+ {0x1BA, 0, 0},
+ {0x1BB, 0, 0},
+ {0x1BC, 0, 0},
+ {0x1BD, 0, 0},
+ {0x1BE, 0, 0},
+ {0x1BF, 0, 0},
+ {0x1C0, 0, 0},
+ {0x1C1, 0x1, 1},
+ {0x1C2, 0x80, 1},
+ {0x1C3, 0, 0},
+ {0x1C4, 0, 0},
+ {0x1C5, 0, 0},
+ {0x1C6, 0, 0},
+ {0x1C7, 0, 0},
+ {0x1C8, 0, 0},
+ {0x1C9, 0, 0},
+ {0x1CA, 0, 0},
+ {0xFFFF, 0, 0}
+};
+
+static struct radio_20xx_regs regs_2057_rev5v1[] = {
+ {0x00, 0x15, 1},
+ {0x01, 0x57, 1},
+ {0x02, 0x20, 1},
+ {0x03, 0x1f, 0},
+ {0x04, 0x4, 0},
+ {0x05, 0x2, 0},
+ {0x06, 0x1, 0},
+ {0x07, 0x1, 0},
+ {0x08, 0x1, 0},
+ {0x09, 0x69, 0},
+ {0x0A, 0x66, 0},
+ {0x0B, 0x6, 0},
+ {0x0C, 0x18, 0},
+ {0x0D, 0x3, 0},
+ {0x0E, 0x20, 0},
+ {0x0F, 0x20, 0},
+ {0x10, 0, 0},
+ {0x11, 0x7c, 0},
+ {0x12, 0x42, 0},
+ {0x13, 0xbd, 0},
+ {0x14, 0x7, 0},
+ {0x15, 0x87, 0},
+ {0x16, 0x8, 0},
+ {0x17, 0x17, 0},
+ {0x18, 0x7, 0},
+ {0x19, 0, 0},
+ {0x1A, 0x2, 0},
+ {0x1B, 0x13, 0},
+ {0x1C, 0x3e, 0},
+ {0x1D, 0x3e, 0},
+ {0x1E, 0x96, 0},
+ {0x1F, 0x4, 0},
+ {0x20, 0, 0},
+ {0x21, 0, 0},
+ {0x22, 0x17, 0},
+ {0x23, 0x6, 1},
+ {0x24, 0x1, 0},
+ {0x25, 0x6, 0},
+ {0x26, 0x4, 0},
+ {0x27, 0xd, 0},
+ {0x28, 0xd, 0},
+ {0x29, 0x30, 0},
+ {0x2A, 0x32, 0},
+ {0x2B, 0x8, 0},
+ {0x2C, 0x1c, 0},
+ {0x2D, 0x2, 0},
+ {0x2E, 0x4, 0},
+ {0x2F, 0x7f, 0},
+ {0x30, 0x27, 0},
+ {0x31, 0, 1},
+ {0x32, 0, 1},
+ {0x33, 0, 1},
+ {0x34, 0, 0},
+ {0x35, 0x20, 0},
+ {0x36, 0x18, 0},
+ {0x37, 0x7, 0},
+ {0x38, 0x66, 0},
+ {0x39, 0x66, 0},
+ {0x3C, 0xff, 0},
+ {0x3D, 0xff, 0},
+ {0x40, 0x16, 0},
+ {0x41, 0x7, 0},
+ {0x45, 0x3, 0},
+ {0x46, 0x1, 0},
+ {0x47, 0x7, 0},
+ {0x4B, 0x66, 0},
+ {0x4C, 0x66, 0},
+ {0x4D, 0, 0},
+ {0x4E, 0x4, 0},
+ {0x4F, 0xc, 0},
+ {0x50, 0, 0},
+ {0x51, 0x70, 1},
+ {0x56, 0x7, 0},
+ {0x57, 0, 0},
+ {0x58, 0, 0},
+ {0x59, 0x88, 1},
+ {0x5A, 0, 0},
+ {0x5B, 0x1f, 0},
+ {0x5C, 0x20, 1},
+ {0x5D, 0x1, 0},
+ {0x5E, 0x30, 0},
+ {0x5F, 0x70, 0},
+ {0x60, 0, 0},
+ {0x61, 0, 0},
+ {0x62, 0x33, 1},
+ {0x63, 0xf, 1},
+ {0x64, 0xf, 1},
+ {0x65, 0, 0},
+ {0x66, 0x11, 0},
+ {0x80, 0x3c, 0},
+ {0x81, 0x1, 1},
+ {0x82, 0xa, 0},
+ {0x85, 0, 0},
+ {0x86, 0x40, 0},
+ {0x87, 0x40, 0},
+ {0x88, 0x88, 0},
+ {0x89, 0x10, 0},
+ {0x8A, 0xf0, 0},
+ {0x8B, 0x10, 0},
+ {0x8C, 0xf0, 0},
+ {0x8F, 0x10, 0},
+ {0x90, 0x55, 0},
+ {0x91, 0x3f, 1},
+ {0x92, 0x36, 1},
+ {0x93, 0, 0},
+ {0x94, 0, 0},
+ {0x95, 0, 0},
+ {0x96, 0x87, 0},
+ {0x97, 0x11, 0},
+ {0x98, 0, 0},
+ {0x99, 0x33, 0},
+ {0x9A, 0x88, 0},
+ {0xA1, 0x20, 1},
+ {0xA2, 0x3f, 0},
+ {0xA3, 0x44, 0},
+ {0xA4, 0x8c, 0},
+ {0xA5, 0x6c, 0},
+ {0xA6, 0x22, 0},
+ {0xA7, 0xbe, 0},
+ {0xA8, 0x55, 0},
+ {0xAA, 0xc, 0},
+ {0xAB, 0xaa, 0},
+ {0xAC, 0x2, 0},
+ {0xAD, 0, 0},
+ {0xAE, 0x10, 0},
+ {0xAF, 0x1, 0},
+ {0xB0, 0, 0},
+ {0xB1, 0, 0},
+ {0xB2, 0x80, 0},
+ {0xB3, 0x60, 0},
+ {0xB4, 0x44, 0},
+ {0xB5, 0x55, 0},
+ {0xB6, 0x1, 0},
+ {0xB7, 0x55, 0},
+ {0xB8, 0x1, 0},
+ {0xB9, 0x5, 0},
+ {0xBA, 0x55, 0},
+ {0xBB, 0x55, 0},
+ {0xC3, 0, 0},
+ {0xC4, 0, 0},
+ {0xC5, 0, 0},
+ {0xC6, 0, 0},
+ {0xC7, 0, 0},
+ {0xC8, 0, 0},
+ {0xC9, 0x1, 1},
+ {0xCA, 0, 0},
+ {0xCB, 0, 0},
+ {0xCD, 0, 0},
+ {0xCE, 0x5e, 0},
+ {0xCF, 0xc, 0},
+ {0xD0, 0xc, 0},
+ {0xD1, 0xc, 0},
+ {0xD2, 0, 0},
+ {0xD3, 0x2b, 0},
+ {0xD4, 0xc, 0},
+ {0xD5, 0, 0},
+ {0xD6, 0x70, 1},
+ {0xDB, 0x7, 0},
+ {0xDC, 0, 0},
+ {0xDD, 0, 0},
+ {0xDE, 0x88, 1},
+ {0xDF, 0, 0},
+ {0xE0, 0x1f, 0},
+ {0xE1, 0x20, 1},
+ {0xE2, 0x1, 0},
+ {0xE3, 0x30, 0},
+ {0xE4, 0x70, 0},
+ {0xE5, 0, 0},
+ {0xE6, 0, 0},
+ {0xE7, 0x33, 0},
+ {0xE8, 0xf, 1},
+ {0xE9, 0xf, 1},
+ {0xEA, 0, 0},
+ {0xEB, 0x11, 0},
+ {0x105, 0x3c, 0},
+ {0x106, 0x1, 1},
+ {0x107, 0xa, 0},
+ {0x10A, 0, 0},
+ {0x10B, 0x40, 0},
+ {0x10C, 0x40, 0},
+ {0x10D, 0x88, 0},
+ {0x10E, 0x10, 0},
+ {0x10F, 0xf0, 0},
+ {0x110, 0x10, 0},
+ {0x111, 0xf0, 0},
+ {0x114, 0x10, 0},
+ {0x115, 0x55, 0},
+ {0x116, 0x3f, 1},
+ {0x117, 0x36, 1},
+ {0x118, 0, 0},
+ {0x119, 0, 0},
+ {0x11A, 0, 0},
+ {0x11B, 0x87, 0},
+ {0x11C, 0x11, 0},
+ {0x11D, 0, 0},
+ {0x11E, 0x33, 0},
+ {0x11F, 0x88, 0},
+ {0x126, 0x20, 1},
+ {0x127, 0x3f, 0},
+ {0x128, 0x44, 0},
+ {0x129, 0x8c, 0},
+ {0x12A, 0x6c, 0},
+ {0x12B, 0x22, 0},
+ {0x12C, 0xbe, 0},
+ {0x12D, 0x55, 0},
+ {0x12F, 0xc, 0},
+ {0x130, 0xaa, 0},
+ {0x131, 0x2, 0},
+ {0x132, 0, 0},
+ {0x133, 0x10, 0},
+ {0x134, 0x1, 0},
+ {0x135, 0, 0},
+ {0x136, 0, 0},
+ {0x137, 0x80, 0},
+ {0x138, 0x60, 0},
+ {0x139, 0x44, 0},
+ {0x13A, 0x55, 0},
+ {0x13B, 0x1, 0},
+ {0x13C, 0x55, 0},
+ {0x13D, 0x1, 0},
+ {0x13E, 0x5, 0},
+ {0x13F, 0x55, 0},
+ {0x140, 0x55, 0},
+ {0x148, 0, 0},
+ {0x149, 0, 0},
+ {0x14A, 0, 0},
+ {0x14B, 0, 0},
+ {0x14C, 0, 0},
+ {0x14D, 0, 0},
+ {0x14E, 0x1, 1},
+ {0x14F, 0, 0},
+ {0x150, 0, 0},
+ {0x154, 0xc, 0},
+ {0x155, 0xc, 0},
+ {0x156, 0xc, 0},
+ {0x157, 0, 0},
+ {0x158, 0x2b, 0},
+ {0x159, 0x84, 0},
+ {0x15A, 0x15, 0},
+ {0x15B, 0xf, 0},
+ {0x15C, 0, 0},
+ {0x15D, 0, 0},
+ {0x15E, 0, 1},
+ {0x15F, 0, 1},
+ {0x160, 0, 1},
+ {0x161, 0, 1},
+ {0x162, 0, 1},
+ {0x163, 0, 1},
+ {0x164, 0, 0},
+ {0x165, 0, 0},
+ {0x166, 0, 0},
+ {0x167, 0, 0},
+ {0x168, 0, 0},
+ {0x169, 0, 0},
+ {0x16A, 0, 1},
+ {0x16B, 0, 1},
+ {0x16C, 0, 1},
+ {0x16D, 0, 0},
+ {0x170, 0, 0},
+ {0x171, 0x77, 0},
+ {0x172, 0x77, 0},
+ {0x173, 0x77, 0},
+ {0x174, 0x77, 0},
+ {0x175, 0, 0},
+ {0x176, 0x3, 0},
+ {0x177, 0x37, 0},
+ {0x178, 0x3, 0},
+ {0x179, 0, 0},
+ {0x17B, 0x21, 0},
+ {0x17C, 0, 0},
+ {0x17D, 0xaa, 0},
+ {0x17E, 0, 0},
+ {0x190, 0, 0},
+ {0x191, 0x77, 0},
+ {0x192, 0x77, 0},
+ {0x193, 0x77, 0},
+ {0x194, 0x77, 0},
+ {0x195, 0, 0},
+ {0x196, 0x3, 0},
+ {0x197, 0x37, 0},
+ {0x198, 0x3, 0},
+ {0x199, 0, 0},
+ {0x19B, 0x21, 0},
+ {0x19C, 0, 0},
+ {0x19D, 0xaa, 0},
+ {0x19E, 0, 0},
+ {0x1A1, 0x2, 0},
+ {0x1A2, 0xf, 0},
+ {0x1A3, 0xf, 0},
+ {0x1A4, 0, 1},
+ {0x1A5, 0, 1},
+ {0x1A6, 0, 1},
+ {0x1A7, 0x2, 0},
+ {0x1A8, 0xf, 0},
+ {0x1A9, 0xf, 0},
+ {0x1AA, 0, 1},
+ {0x1AB, 0, 1},
+ {0x1AC, 0, 1},
+ {0x1AD, 0x84, 0},
+ {0x1AE, 0x60, 0},
+ {0x1AF, 0x47, 0},
+ {0x1B0, 0x47, 0},
+ {0x1B1, 0, 0},
+ {0x1B2, 0, 0},
+ {0x1B3, 0, 0},
+ {0x1B4, 0, 0},
+ {0x1B5, 0, 0},
+ {0x1B6, 0, 0},
+ {0x1B7, 0xc, 1},
+ {0x1B8, 0, 0},
+ {0x1B9, 0, 0},
+ {0x1BA, 0, 0},
+ {0x1BB, 0, 0},
+ {0x1BC, 0, 0},
+ {0x1BD, 0, 0},
+ {0x1BE, 0, 0},
+ {0x1BF, 0, 0},
+ {0x1C0, 0, 0},
+ {0x1C1, 0x1, 1},
+ {0x1C2, 0x80, 1},
+ {0x1C3, 0, 0},
+ {0x1C4, 0, 0},
+ {0x1C5, 0, 0},
+ {0x1C6, 0, 0},
+ {0x1C7, 0, 0},
+ {0x1C8, 0, 0},
+ {0x1C9, 0, 0},
+ {0x1CA, 0, 0},
+ {0xFFFF, 0, 0}
+};
+
+static struct radio_20xx_regs regs_2057_rev7[] = {
+ {0x00, 0, 1},
+ {0x01, 0x57, 1},
+ {0x02, 0x20, 1},
+ {0x03, 0x1f, 0},
+ {0x04, 0x4, 0},
+ {0x05, 0x2, 0},
+ {0x06, 0x1, 0},
+ {0x07, 0x1, 0},
+ {0x08, 0x1, 0},
+ {0x09, 0x69, 0},
+ {0x0A, 0x66, 0},
+ {0x0B, 0x6, 0},
+ {0x0C, 0x18, 0},
+ {0x0D, 0x3, 0},
+ {0x0E, 0x20, 0},
+ {0x0F, 0x20, 0},
+ {0x10, 0, 0},
+ {0x11, 0x7c, 0},
+ {0x12, 0x42, 0},
+ {0x13, 0xbd, 0},
+ {0x14, 0x7, 0},
+ {0x15, 0x87, 0},
+ {0x16, 0x8, 0},
+ {0x17, 0x17, 0},
+ {0x18, 0x7, 0},
+ {0x19, 0, 0},
+ {0x1A, 0x2, 0},
+ {0x1B, 0x13, 0},
+ {0x1C, 0x3e, 0},
+ {0x1D, 0x3e, 0},
+ {0x1E, 0x96, 0},
+ {0x1F, 0x4, 0},
+ {0x20, 0, 0},
+ {0x21, 0, 0},
+ {0x22, 0x17, 0},
+ {0x23, 0x6, 0},
+ {0x24, 0x1, 0},
+ {0x25, 0x6, 0},
+ {0x26, 0x4, 0},
+ {0x27, 0xd, 0},
+ {0x28, 0xd, 0},
+ {0x29, 0x30, 0},
+ {0x2A, 0x32, 0},
+ {0x2B, 0x8, 0},
+ {0x2C, 0x1c, 0},
+ {0x2D, 0x2, 0},
+ {0x2E, 0x4, 0},
+ {0x2F, 0x7f, 0},
+ {0x30, 0x27, 0},
+ {0x31, 0, 1},
+ {0x32, 0, 1},
+ {0x33, 0, 1},
+ {0x34, 0, 0},
+ {0x35, 0x20, 0},
+ {0x36, 0x18, 0},
+ {0x37, 0x7, 0},
+ {0x38, 0x66, 0},
+ {0x39, 0x66, 0},
+ {0x3A, 0x66, 0},
+ {0x3B, 0x66, 0},
+ {0x3C, 0xff, 0},
+ {0x3D, 0xff, 0},
+ {0x3E, 0xff, 0},
+ {0x3F, 0xff, 0},
+ {0x40, 0x16, 0},
+ {0x41, 0x7, 0},
+ {0x42, 0x19, 0},
+ {0x43, 0x7, 0},
+ {0x44, 0x6, 0},
+ {0x45, 0x3, 0},
+ {0x46, 0x1, 0},
+ {0x47, 0x7, 0},
+ {0x48, 0x33, 0},
+ {0x49, 0x5, 0},
+ {0x4A, 0x77, 0},
+ {0x4B, 0x66, 0},
+ {0x4C, 0x66, 0},
+ {0x4D, 0, 0},
+ {0x4E, 0x4, 0},
+ {0x4F, 0xc, 0},
+ {0x50, 0, 0},
+ {0x51, 0x70, 1},
+ {0x56, 0x7, 0},
+ {0x57, 0, 0},
+ {0x58, 0, 0},
+ {0x59, 0x88, 1},
+ {0x5A, 0, 0},
+ {0x5B, 0x1f, 0},
+ {0x5C, 0x20, 1},
+ {0x5D, 0x1, 0},
+ {0x5E, 0x30, 0},
+ {0x5F, 0x70, 0},
+ {0x60, 0, 0},
+ {0x61, 0, 0},
+ {0x62, 0x33, 1},
+ {0x63, 0xf, 1},
+ {0x64, 0x13, 1},
+ {0x65, 0, 0},
+ {0x66, 0xee, 1},
+ {0x69, 0, 0},
+ {0x6A, 0x7e, 0},
+ {0x6B, 0x3f, 0},
+ {0x6C, 0x7f, 0},
+ {0x6D, 0x78, 0},
+ {0x6E, 0x58, 1},
+ {0x6F, 0x88, 0},
+ {0x70, 0x8, 0},
+ {0x71, 0xf, 0},
+ {0x72, 0xbc, 0},
+ {0x73, 0x8, 0},
+ {0x74, 0x60, 0},
+ {0x75, 0x13, 1},
+ {0x76, 0x70, 0},
+ {0x77, 0, 0},
+ {0x78, 0, 0},
+ {0x79, 0, 0},
+ {0x7A, 0x33, 0},
+ {0x7B, 0x13, 1},
+ {0x7C, 0x14, 1},
+ {0x7D, 0xee, 1},
+ {0x80, 0x3c, 0},
+ {0x81, 0x1, 1},
+ {0x82, 0xa, 0},
+ {0x83, 0x9d, 0},
+ {0x84, 0xa, 0},
+ {0x85, 0, 0},
+ {0x86, 0x40, 0},
+ {0x87, 0x40, 0},
+ {0x88, 0x88, 0},
+ {0x89, 0x10, 0},
+ {0x8A, 0xf0, 0},
+ {0x8B, 0x10, 0},
+ {0x8C, 0xf0, 0},
+ {0x8D, 0, 0},
+ {0x8E, 0, 0},
+ {0x8F, 0x10, 0},
+ {0x90, 0x55, 0},
+ {0x91, 0x3f, 1},
+ {0x92, 0x36, 1},
+ {0x93, 0, 0},
+ {0x94, 0, 0},
+ {0x95, 0, 0},
+ {0x96, 0x87, 0},
+ {0x97, 0x11, 0},
+ {0x98, 0, 0},
+ {0x99, 0x33, 0},
+ {0x9A, 0x88, 0},
+ {0x9B, 0, 0},
+ {0x9C, 0x87, 0},
+ {0x9D, 0x11, 0},
+ {0x9E, 0, 0},
+ {0x9F, 0x33, 0},
+ {0xA0, 0x88, 0},
+ {0xA1, 0x20, 1},
+ {0xA2, 0x3f, 0},
+ {0xA3, 0x44, 0},
+ {0xA4, 0x8c, 0},
+ {0xA5, 0x6c, 0},
+ {0xA6, 0x22, 0},
+ {0xA7, 0xbe, 0},
+ {0xA8, 0x55, 0},
+ {0xAA, 0xc, 0},
+ {0xAB, 0xaa, 0},
+ {0xAC, 0x2, 0},
+ {0xAD, 0, 0},
+ {0xAE, 0x10, 0},
+ {0xAF, 0x1, 0},
+ {0xB0, 0, 0},
+ {0xB1, 0, 0},
+ {0xB2, 0x80, 0},
+ {0xB3, 0x60, 0},
+ {0xB4, 0x44, 0},
+ {0xB5, 0x55, 0},
+ {0xB6, 0x1, 0},
+ {0xB7, 0x55, 0},
+ {0xB8, 0x1, 0},
+ {0xB9, 0x5, 0},
+ {0xBA, 0x55, 0},
+ {0xBB, 0x55, 0},
+ {0xC1, 0, 0},
+ {0xC2, 0, 0},
+ {0xC3, 0, 0},
+ {0xC4, 0, 0},
+ {0xC5, 0, 0},
+ {0xC6, 0, 0},
+ {0xC7, 0, 0},
+ {0xC8, 0, 0},
+ {0xC9, 0, 0},
+ {0xCA, 0, 0},
+ {0xCB, 0, 0},
+ {0xCC, 0, 0},
+ {0xCD, 0, 0},
+ {0xCE, 0x5e, 0},
+ {0xCF, 0xc, 0},
+ {0xD0, 0xc, 0},
+ {0xD1, 0xc, 0},
+ {0xD2, 0, 0},
+ {0xD3, 0x2b, 0},
+ {0xD4, 0xc, 0},
+ {0xD5, 0, 0},
+ {0xD6, 0x70, 1},
+ {0xDB, 0x7, 0},
+ {0xDC, 0, 0},
+ {0xDD, 0, 0},
+ {0xDE, 0x88, 1},
+ {0xDF, 0, 0},
+ {0xE0, 0x1f, 0},
+ {0xE1, 0x20, 1},
+ {0xE2, 0x1, 0},
+ {0xE3, 0x30, 0},
+ {0xE4, 0x70, 0},
+ {0xE5, 0, 0},
+ {0xE6, 0, 0},
+ {0xE7, 0x33, 0},
+ {0xE8, 0xf, 1},
+ {0xE9, 0x13, 1},
+ {0xEA, 0, 0},
+ {0xEB, 0xee, 1},
+ {0xEE, 0, 0},
+ {0xEF, 0x7e, 0},
+ {0xF0, 0x3f, 0},
+ {0xF1, 0x7f, 0},
+ {0xF2, 0x78, 0},
+ {0xF3, 0x58, 1},
+ {0xF4, 0x88, 0},
+ {0xF5, 0x8, 0},
+ {0xF6, 0xf, 0},
+ {0xF7, 0xbc, 0},
+ {0xF8, 0x8, 0},
+ {0xF9, 0x60, 0},
+ {0xFA, 0x13, 1},
+ {0xFB, 0x70, 0},
+ {0xFC, 0, 0},
+ {0xFD, 0, 0},
+ {0xFE, 0, 0},
+ {0xFF, 0x33, 0},
+ {0x100, 0x13, 1},
+ {0x101, 0x14, 1},
+ {0x102, 0xee, 1},
+ {0x105, 0x3c, 0},
+ {0x106, 0x1, 1},
+ {0x107, 0xa, 0},
+ {0x108, 0x9d, 0},
+ {0x109, 0xa, 0},
+ {0x10A, 0, 0},
+ {0x10B, 0x40, 0},
+ {0x10C, 0x40, 0},
+ {0x10D, 0x88, 0},
+ {0x10E, 0x10, 0},
+ {0x10F, 0xf0, 0},
+ {0x110, 0x10, 0},
+ {0x111, 0xf0, 0},
+ {0x112, 0, 0},
+ {0x113, 0, 0},
+ {0x114, 0x10, 0},
+ {0x115, 0x55, 0},
+ {0x116, 0x3f, 1},
+ {0x117, 0x36, 1},
+ {0x118, 0, 0},
+ {0x119, 0, 0},
+ {0x11A, 0, 0},
+ {0x11B, 0x87, 0},
+ {0x11C, 0x11, 0},
+ {0x11D, 0, 0},
+ {0x11E, 0x33, 0},
+ {0x11F, 0x88, 0},
+ {0x120, 0, 0},
+ {0x121, 0x87, 0},
+ {0x122, 0x11, 0},
+ {0x123, 0, 0},
+ {0x124, 0x33, 0},
+ {0x125, 0x88, 0},
+ {0x126, 0x20, 1},
+ {0x127, 0x3f, 0},
+ {0x128, 0x44, 0},
+ {0x129, 0x8c, 0},
+ {0x12A, 0x6c, 0},
+ {0x12B, 0x22, 0},
+ {0x12C, 0xbe, 0},
+ {0x12D, 0x55, 0},
+ {0x12F, 0xc, 0},
+ {0x130, 0xaa, 0},
+ {0x131, 0x2, 0},
+ {0x132, 0, 0},
+ {0x133, 0x10, 0},
+ {0x134, 0x1, 0},
+ {0x135, 0, 0},
+ {0x136, 0, 0},
+ {0x137, 0x80, 0},
+ {0x138, 0x60, 0},
+ {0x139, 0x44, 0},
+ {0x13A, 0x55, 0},
+ {0x13B, 0x1, 0},
+ {0x13C, 0x55, 0},
+ {0x13D, 0x1, 0},
+ {0x13E, 0x5, 0},
+ {0x13F, 0x55, 0},
+ {0x140, 0x55, 0},
+ {0x146, 0, 0},
+ {0x147, 0, 0},
+ {0x148, 0, 0},
+ {0x149, 0, 0},
+ {0x14A, 0, 0},
+ {0x14B, 0, 0},
+ {0x14C, 0, 0},
+ {0x14D, 0, 0},
+ {0x14E, 0, 0},
+ {0x14F, 0, 0},
+ {0x150, 0, 0},
+ {0x151, 0, 0},
+ {0x154, 0xc, 0},
+ {0x155, 0xc, 0},
+ {0x156, 0xc, 0},
+ {0x157, 0, 0},
+ {0x158, 0x2b, 0},
+ {0x159, 0x84, 0},
+ {0x15A, 0x15, 0},
+ {0x15B, 0xf, 0},
+ {0x15C, 0, 0},
+ {0x15D, 0, 0},
+ {0x15E, 0, 1},
+ {0x15F, 0, 1},
+ {0x160, 0, 1},
+ {0x161, 0, 1},
+ {0x162, 0, 1},
+ {0x163, 0, 1},
+ {0x164, 0, 0},
+ {0x165, 0, 0},
+ {0x166, 0, 0},
+ {0x167, 0, 0},
+ {0x168, 0, 0},
+ {0x169, 0, 0},
+ {0x16A, 0, 1},
+ {0x16B, 0, 1},
+ {0x16C, 0, 1},
+ {0x16D, 0, 0},
+ {0x170, 0, 0},
+ {0x171, 0x77, 0},
+ {0x172, 0x77, 0},
+ {0x173, 0x77, 0},
+ {0x174, 0x77, 0},
+ {0x175, 0, 0},
+ {0x176, 0x3, 0},
+ {0x177, 0x37, 0},
+ {0x178, 0x3, 0},
+ {0x179, 0, 0},
+ {0x17A, 0x21, 0},
+ {0x17B, 0x21, 0},
+ {0x17C, 0, 0},
+ {0x17D, 0xaa, 0},
+ {0x17E, 0, 0},
+ {0x17F, 0xaa, 0},
+ {0x180, 0, 0},
+ {0x190, 0, 0},
+ {0x191, 0x77, 0},
+ {0x192, 0x77, 0},
+ {0x193, 0x77, 0},
+ {0x194, 0x77, 0},
+ {0x195, 0, 0},
+ {0x196, 0x3, 0},
+ {0x197, 0x37, 0},
+ {0x198, 0x3, 0},
+ {0x199, 0, 0},
+ {0x19A, 0x21, 0},
+ {0x19B, 0x21, 0},
+ {0x19C, 0, 0},
+ {0x19D, 0xaa, 0},
+ {0x19E, 0, 0},
+ {0x19F, 0xaa, 0},
+ {0x1A0, 0, 0},
+ {0x1A1, 0x2, 0},
+ {0x1A2, 0xf, 0},
+ {0x1A3, 0xf, 0},
+ {0x1A4, 0, 1},
+ {0x1A5, 0, 1},
+ {0x1A6, 0, 1},
+ {0x1A7, 0x2, 0},
+ {0x1A8, 0xf, 0},
+ {0x1A9, 0xf, 0},
+ {0x1AA, 0, 1},
+ {0x1AB, 0, 1},
+ {0x1AC, 0, 1},
+ {0x1AD, 0x84, 0},
+ {0x1AE, 0x60, 0},
+ {0x1AF, 0x47, 0},
+ {0x1B0, 0x47, 0},
+ {0x1B1, 0, 0},
+ {0x1B2, 0, 0},
+ {0x1B3, 0, 0},
+ {0x1B4, 0, 0},
+ {0x1B5, 0, 0},
+ {0x1B6, 0, 0},
+ {0x1B7, 0x5, 1},
+ {0x1B8, 0, 0},
+ {0x1B9, 0, 0},
+ {0x1BA, 0, 0},
+ {0x1BB, 0, 0},
+ {0x1BC, 0, 0},
+ {0x1BD, 0, 0},
+ {0x1BE, 0, 0},
+ {0x1BF, 0, 0},
+ {0x1C0, 0, 0},
+ {0x1C1, 0, 0},
+ {0x1C2, 0xa0, 1},
+ {0x1C3, 0, 0},
+ {0x1C4, 0, 0},
+ {0x1C5, 0, 0},
+ {0x1C6, 0, 0},
+ {0x1C7, 0, 0},
+ {0x1C8, 0, 0},
+ {0x1C9, 0, 0},
+ {0x1CA, 0, 0},
+ {0xFFFF, 0, 0}
+};
+
+static struct radio_20xx_regs regs_2057_rev8[] = {
+ {0x00, 0x8, 1},
+ {0x01, 0x57, 1},
+ {0x02, 0x20, 1},
+ {0x03, 0x1f, 0},
+ {0x04, 0x4, 0},
+ {0x05, 0x2, 0},
+ {0x06, 0x1, 0},
+ {0x07, 0x1, 0},
+ {0x08, 0x1, 0},
+ {0x09, 0x69, 0},
+ {0x0A, 0x66, 0},
+ {0x0B, 0x6, 0},
+ {0x0C, 0x18, 0},
+ {0x0D, 0x3, 0},
+ {0x0E, 0x20, 0},
+ {0x0F, 0x20, 0},
+ {0x10, 0, 0},
+ {0x11, 0x7c, 0},
+ {0x12, 0x42, 0},
+ {0x13, 0xbd, 0},
+ {0x14, 0x7, 0},
+ {0x15, 0x87, 0},
+ {0x16, 0x8, 0},
+ {0x17, 0x17, 0},
+ {0x18, 0x7, 0},
+ {0x19, 0, 0},
+ {0x1A, 0x2, 0},
+ {0x1B, 0x13, 0},
+ {0x1C, 0x3e, 0},
+ {0x1D, 0x3e, 0},
+ {0x1E, 0x96, 0},
+ {0x1F, 0x4, 0},
+ {0x20, 0, 0},
+ {0x21, 0, 0},
+ {0x22, 0x17, 0},
+ {0x23, 0x6, 0},
+ {0x24, 0x1, 0},
+ {0x25, 0x6, 0},
+ {0x26, 0x4, 0},
+ {0x27, 0xd, 0},
+ {0x28, 0xd, 0},
+ {0x29, 0x30, 0},
+ {0x2A, 0x32, 0},
+ {0x2B, 0x8, 0},
+ {0x2C, 0x1c, 0},
+ {0x2D, 0x2, 0},
+ {0x2E, 0x4, 0},
+ {0x2F, 0x7f, 0},
+ {0x30, 0x27, 0},
+ {0x31, 0, 1},
+ {0x32, 0, 1},
+ {0x33, 0, 1},
+ {0x34, 0, 0},
+ {0x35, 0x20, 0},
+ {0x36, 0x18, 0},
+ {0x37, 0x7, 0},
+ {0x38, 0x66, 0},
+ {0x39, 0x66, 0},
+ {0x3A, 0x66, 0},
+ {0x3B, 0x66, 0},
+ {0x3C, 0xff, 0},
+ {0x3D, 0xff, 0},
+ {0x3E, 0xff, 0},
+ {0x3F, 0xff, 0},
+ {0x40, 0x16, 0},
+ {0x41, 0x7, 0},
+ {0x42, 0x19, 0},
+ {0x43, 0x7, 0},
+ {0x44, 0x6, 0},
+ {0x45, 0x3, 0},
+ {0x46, 0x1, 0},
+ {0x47, 0x7, 0},
+ {0x48, 0x33, 0},
+ {0x49, 0x5, 0},
+ {0x4A, 0x77, 0},
+ {0x4B, 0x66, 0},
+ {0x4C, 0x66, 0},
+ {0x4D, 0, 0},
+ {0x4E, 0x4, 0},
+ {0x4F, 0xc, 0},
+ {0x50, 0, 0},
+ {0x51, 0x70, 1},
+ {0x56, 0x7, 0},
+ {0x57, 0, 0},
+ {0x58, 0, 0},
+ {0x59, 0x88, 1},
+ {0x5A, 0, 0},
+ {0x5B, 0x1f, 0},
+ {0x5C, 0x20, 1},
+ {0x5D, 0x1, 0},
+ {0x5E, 0x30, 0},
+ {0x5F, 0x70, 0},
+ {0x60, 0, 0},
+ {0x61, 0, 0},
+ {0x62, 0x33, 1},
+ {0x63, 0xf, 1},
+ {0x64, 0xf, 1},
+ {0x65, 0, 0},
+ {0x66, 0x11, 0},
+ {0x69, 0, 0},
+ {0x6A, 0x7e, 0},
+ {0x6B, 0x3f, 0},
+ {0x6C, 0x7f, 0},
+ {0x6D, 0x78, 0},
+ {0x6E, 0x58, 1},
+ {0x6F, 0x88, 0},
+ {0x70, 0x8, 0},
+ {0x71, 0xf, 0},
+ {0x72, 0xbc, 0},
+ {0x73, 0x8, 0},
+ {0x74, 0x60, 0},
+ {0x75, 0x13, 1},
+ {0x76, 0x70, 0},
+ {0x77, 0, 0},
+ {0x78, 0, 0},
+ {0x79, 0, 0},
+ {0x7A, 0x33, 0},
+ {0x7B, 0x13, 1},
+ {0x7C, 0xf, 1},
+ {0x7D, 0xee, 1},
+ {0x80, 0x3c, 0},
+ {0x81, 0x1, 1},
+ {0x82, 0xa, 0},
+ {0x83, 0x9d, 0},
+ {0x84, 0xa, 0},
+ {0x85, 0, 0},
+ {0x86, 0x40, 0},
+ {0x87, 0x40, 0},
+ {0x88, 0x88, 0},
+ {0x89, 0x10, 0},
+ {0x8A, 0xf0, 0},
+ {0x8B, 0x10, 0},
+ {0x8C, 0xf0, 0},
+ {0x8D, 0, 0},
+ {0x8E, 0, 0},
+ {0x8F, 0x10, 0},
+ {0x90, 0x55, 0},
+ {0x91, 0x3f, 1},
+ {0x92, 0x36, 1},
+ {0x93, 0, 0},
+ {0x94, 0, 0},
+ {0x95, 0, 0},
+ {0x96, 0x87, 0},
+ {0x97, 0x11, 0},
+ {0x98, 0, 0},
+ {0x99, 0x33, 0},
+ {0x9A, 0x88, 0},
+ {0x9B, 0, 0},
+ {0x9C, 0x87, 0},
+ {0x9D, 0x11, 0},
+ {0x9E, 0, 0},
+ {0x9F, 0x33, 0},
+ {0xA0, 0x88, 0},
+ {0xA1, 0x20, 1},
+ {0xA2, 0x3f, 0},
+ {0xA3, 0x44, 0},
+ {0xA4, 0x8c, 0},
+ {0xA5, 0x6c, 0},
+ {0xA6, 0x22, 0},
+ {0xA7, 0xbe, 0},
+ {0xA8, 0x55, 0},
+ {0xAA, 0xc, 0},
+ {0xAB, 0xaa, 0},
+ {0xAC, 0x2, 0},
+ {0xAD, 0, 0},
+ {0xAE, 0x10, 0},
+ {0xAF, 0x1, 0},
+ {0xB0, 0, 0},
+ {0xB1, 0, 0},
+ {0xB2, 0x80, 0},
+ {0xB3, 0x60, 0},
+ {0xB4, 0x44, 0},
+ {0xB5, 0x55, 0},
+ {0xB6, 0x1, 0},
+ {0xB7, 0x55, 0},
+ {0xB8, 0x1, 0},
+ {0xB9, 0x5, 0},
+ {0xBA, 0x55, 0},
+ {0xBB, 0x55, 0},
+ {0xC1, 0, 0},
+ {0xC2, 0, 0},
+ {0xC3, 0, 0},
+ {0xC4, 0, 0},
+ {0xC5, 0, 0},
+ {0xC6, 0, 0},
+ {0xC7, 0, 0},
+ {0xC8, 0, 0},
+ {0xC9, 0x1, 1},
+ {0xCA, 0, 0},
+ {0xCB, 0, 0},
+ {0xCC, 0, 0},
+ {0xCD, 0, 0},
+ {0xCE, 0x5e, 0},
+ {0xCF, 0xc, 0},
+ {0xD0, 0xc, 0},
+ {0xD1, 0xc, 0},
+ {0xD2, 0, 0},
+ {0xD3, 0x2b, 0},
+ {0xD4, 0xc, 0},
+ {0xD5, 0, 0},
+ {0xD6, 0x70, 1},
+ {0xDB, 0x7, 0},
+ {0xDC, 0, 0},
+ {0xDD, 0, 0},
+ {0xDE, 0x88, 1},
+ {0xDF, 0, 0},
+ {0xE0, 0x1f, 0},
+ {0xE1, 0x20, 1},
+ {0xE2, 0x1, 0},
+ {0xE3, 0x30, 0},
+ {0xE4, 0x70, 0},
+ {0xE5, 0, 0},
+ {0xE6, 0, 0},
+ {0xE7, 0x33, 0},
+ {0xE8, 0xf, 1},
+ {0xE9, 0xf, 1},
+ {0xEA, 0, 0},
+ {0xEB, 0x11, 0},
+ {0xEE, 0, 0},
+ {0xEF, 0x7e, 0},
+ {0xF0, 0x3f, 0},
+ {0xF1, 0x7f, 0},
+ {0xF2, 0x78, 0},
+ {0xF3, 0x58, 1},
+ {0xF4, 0x88, 0},
+ {0xF5, 0x8, 0},
+ {0xF6, 0xf, 0},
+ {0xF7, 0xbc, 0},
+ {0xF8, 0x8, 0},
+ {0xF9, 0x60, 0},
+ {0xFA, 0x13, 1},
+ {0xFB, 0x70, 0},
+ {0xFC, 0, 0},
+ {0xFD, 0, 0},
+ {0xFE, 0, 0},
+ {0xFF, 0x33, 0},
+ {0x100, 0x13, 1},
+ {0x101, 0xf, 1},
+ {0x102, 0xee, 1},
+ {0x105, 0x3c, 0},
+ {0x106, 0x1, 1},
+ {0x107, 0xa, 0},
+ {0x108, 0x9d, 0},
+ {0x109, 0xa, 0},
+ {0x10A, 0, 0},
+ {0x10B, 0x40, 0},
+ {0x10C, 0x40, 0},
+ {0x10D, 0x88, 0},
+ {0x10E, 0x10, 0},
+ {0x10F, 0xf0, 0},
+ {0x110, 0x10, 0},
+ {0x111, 0xf0, 0},
+ {0x112, 0, 0},
+ {0x113, 0, 0},
+ {0x114, 0x10, 0},
+ {0x115, 0x55, 0},
+ {0x116, 0x3f, 1},
+ {0x117, 0x36, 1},
+ {0x118, 0, 0},
+ {0x119, 0, 0},
+ {0x11A, 0, 0},
+ {0x11B, 0x87, 0},
+ {0x11C, 0x11, 0},
+ {0x11D, 0, 0},
+ {0x11E, 0x33, 0},
+ {0x11F, 0x88, 0},
+ {0x120, 0, 0},
+ {0x121, 0x87, 0},
+ {0x122, 0x11, 0},
+ {0x123, 0, 0},
+ {0x124, 0x33, 0},
+ {0x125, 0x88, 0},
+ {0x126, 0x20, 1},
+ {0x127, 0x3f, 0},
+ {0x128, 0x44, 0},
+ {0x129, 0x8c, 0},
+ {0x12A, 0x6c, 0},
+ {0x12B, 0x22, 0},
+ {0x12C, 0xbe, 0},
+ {0x12D, 0x55, 0},
+ {0x12F, 0xc, 0},
+ {0x130, 0xaa, 0},
+ {0x131, 0x2, 0},
+ {0x132, 0, 0},
+ {0x133, 0x10, 0},
+ {0x134, 0x1, 0},
+ {0x135, 0, 0},
+ {0x136, 0, 0},
+ {0x137, 0x80, 0},
+ {0x138, 0x60, 0},
+ {0x139, 0x44, 0},
+ {0x13A, 0x55, 0},
+ {0x13B, 0x1, 0},
+ {0x13C, 0x55, 0},
+ {0x13D, 0x1, 0},
+ {0x13E, 0x5, 0},
+ {0x13F, 0x55, 0},
+ {0x140, 0x55, 0},
+ {0x146, 0, 0},
+ {0x147, 0, 0},
+ {0x148, 0, 0},
+ {0x149, 0, 0},
+ {0x14A, 0, 0},
+ {0x14B, 0, 0},
+ {0x14C, 0, 0},
+ {0x14D, 0, 0},
+ {0x14E, 0x1, 1},
+ {0x14F, 0, 0},
+ {0x150, 0, 0},
+ {0x151, 0, 0},
+ {0x154, 0xc, 0},
+ {0x155, 0xc, 0},
+ {0x156, 0xc, 0},
+ {0x157, 0, 0},
+ {0x158, 0x2b, 0},
+ {0x159, 0x84, 0},
+ {0x15A, 0x15, 0},
+ {0x15B, 0xf, 0},
+ {0x15C, 0, 0},
+ {0x15D, 0, 0},
+ {0x15E, 0, 1},
+ {0x15F, 0, 1},
+ {0x160, 0, 1},
+ {0x161, 0, 1},
+ {0x162, 0, 1},
+ {0x163, 0, 1},
+ {0x164, 0, 0},
+ {0x165, 0, 0},
+ {0x166, 0, 0},
+ {0x167, 0, 0},
+ {0x168, 0, 0},
+ {0x169, 0, 0},
+ {0x16A, 0, 1},
+ {0x16B, 0, 1},
+ {0x16C, 0, 1},
+ {0x16D, 0, 0},
+ {0x170, 0, 0},
+ {0x171, 0x77, 0},
+ {0x172, 0x77, 0},
+ {0x173, 0x77, 0},
+ {0x174, 0x77, 0},
+ {0x175, 0, 0},
+ {0x176, 0x3, 0},
+ {0x177, 0x37, 0},
+ {0x178, 0x3, 0},
+ {0x179, 0, 0},
+ {0x17A, 0x21, 0},
+ {0x17B, 0x21, 0},
+ {0x17C, 0, 0},
+ {0x17D, 0xaa, 0},
+ {0x17E, 0, 0},
+ {0x17F, 0xaa, 0},
+ {0x180, 0, 0},
+ {0x190, 0, 0},
+ {0x191, 0x77, 0},
+ {0x192, 0x77, 0},
+ {0x193, 0x77, 0},
+ {0x194, 0x77, 0},
+ {0x195, 0, 0},
+ {0x196, 0x3, 0},
+ {0x197, 0x37, 0},
+ {0x198, 0x3, 0},
+ {0x199, 0, 0},
+ {0x19A, 0x21, 0},
+ {0x19B, 0x21, 0},
+ {0x19C, 0, 0},
+ {0x19D, 0xaa, 0},
+ {0x19E, 0, 0},
+ {0x19F, 0xaa, 0},
+ {0x1A0, 0, 0},
+ {0x1A1, 0x2, 0},
+ {0x1A2, 0xf, 0},
+ {0x1A3, 0xf, 0},
+ {0x1A4, 0, 1},
+ {0x1A5, 0, 1},
+ {0x1A6, 0, 1},
+ {0x1A7, 0x2, 0},
+ {0x1A8, 0xf, 0},
+ {0x1A9, 0xf, 0},
+ {0x1AA, 0, 1},
+ {0x1AB, 0, 1},
+ {0x1AC, 0, 1},
+ {0x1AD, 0x84, 0},
+ {0x1AE, 0x60, 0},
+ {0x1AF, 0x47, 0},
+ {0x1B0, 0x47, 0},
+ {0x1B1, 0, 0},
+ {0x1B2, 0, 0},
+ {0x1B3, 0, 0},
+ {0x1B4, 0, 0},
+ {0x1B5, 0, 0},
+ {0x1B6, 0, 0},
+ {0x1B7, 0x5, 1},
+ {0x1B8, 0, 0},
+ {0x1B9, 0, 0},
+ {0x1BA, 0, 0},
+ {0x1BB, 0, 0},
+ {0x1BC, 0, 0},
+ {0x1BD, 0, 0},
+ {0x1BE, 0, 0},
+ {0x1BF, 0, 0},
+ {0x1C0, 0, 0},
+ {0x1C1, 0, 0},
+ {0x1C2, 0xa0, 1},
+ {0x1C3, 0, 0},
+ {0x1C4, 0, 0},
+ {0x1C5, 0, 0},
+ {0x1C6, 0, 0},
+ {0x1C7, 0, 0},
+ {0x1C8, 0, 0},
+ {0x1C9, 0, 0},
+ {0x1CA, 0, 0},
+ {0xFFFF, 0, 0}
+};
+
+static s16 nphy_def_lnagains[] = { -2, 10, 19, 25 };
+
+static s32 nphy_lnagain_est0[] = { -315, 40370 };
+static s32 nphy_lnagain_est1[] = { -224, 23242 };
+
+static const u16 tbl_iqcal_gainparams_nphy[2][NPHY_IQCAL_NUMGAINS][8] = {
+ {
+ {0x000, 0, 0, 2, 0x69, 0x69, 0x69, 0x69},
+ {0x700, 7, 0, 0, 0x69, 0x69, 0x69, 0x69},
+ {0x710, 7, 1, 0, 0x68, 0x68, 0x68, 0x68},
+ {0x720, 7, 2, 0, 0x67, 0x67, 0x67, 0x67},
+ {0x730, 7, 3, 0, 0x66, 0x66, 0x66, 0x66},
+ {0x740, 7, 4, 0, 0x65, 0x65, 0x65, 0x65},
+ {0x741, 7, 4, 1, 0x65, 0x65, 0x65, 0x65},
+ {0x742, 7, 4, 2, 0x65, 0x65, 0x65, 0x65},
+ {0x743, 7, 4, 3, 0x65, 0x65, 0x65, 0x65}
+ },
+ {
+ {0x000, 7, 0, 0, 0x79, 0x79, 0x79, 0x79},
+ {0x700, 7, 0, 0, 0x79, 0x79, 0x79, 0x79},
+ {0x710, 7, 1, 0, 0x79, 0x79, 0x79, 0x79},
+ {0x720, 7, 2, 0, 0x78, 0x78, 0x78, 0x78},
+ {0x730, 7, 3, 0, 0x78, 0x78, 0x78, 0x78},
+ {0x740, 7, 4, 0, 0x78, 0x78, 0x78, 0x78},
+ {0x741, 7, 4, 1, 0x78, 0x78, 0x78, 0x78},
+ {0x742, 7, 4, 2, 0x78, 0x78, 0x78, 0x78},
+ {0x743, 7, 4, 3, 0x78, 0x78, 0x78, 0x78}
+ }
+};
+
+static const u32 nphy_tpc_txgain[] = {
+ 0x03cc2b44, 0x03cc2b42, 0x03cc2a44, 0x03cc2a42,
+ 0x03cc2944, 0x03c82b44, 0x03c82b42, 0x03c82a44,
+ 0x03c82a42, 0x03c82944, 0x03c82942, 0x03c82844,
+ 0x03c82842, 0x03c42b44, 0x03c42b42, 0x03c42a44,
+ 0x03c42a42, 0x03c42944, 0x03c42942, 0x03c42844,
+ 0x03c42842, 0x03c42744, 0x03c42742, 0x03c42644,
+ 0x03c42642, 0x03c42544, 0x03c42542, 0x03c42444,
+ 0x03c42442, 0x03c02b44, 0x03c02b42, 0x03c02a44,
+ 0x03c02a42, 0x03c02944, 0x03c02942, 0x03c02844,
+ 0x03c02842, 0x03c02744, 0x03c02742, 0x03b02b44,
+ 0x03b02b42, 0x03b02a44, 0x03b02a42, 0x03b02944,
+ 0x03b02942, 0x03b02844, 0x03b02842, 0x03b02744,
+ 0x03b02742, 0x03b02644, 0x03b02642, 0x03b02544,
+ 0x03b02542, 0x03a02b44, 0x03a02b42, 0x03a02a44,
+ 0x03a02a42, 0x03a02944, 0x03a02942, 0x03a02844,
+ 0x03a02842, 0x03a02744, 0x03a02742, 0x03902b44,
+ 0x03902b42, 0x03902a44, 0x03902a42, 0x03902944,
+ 0x03902942, 0x03902844, 0x03902842, 0x03902744,
+ 0x03902742, 0x03902644, 0x03902642, 0x03902544,
+ 0x03902542, 0x03802b44, 0x03802b42, 0x03802a44,
+ 0x03802a42, 0x03802944, 0x03802942, 0x03802844,
+ 0x03802842, 0x03802744, 0x03802742, 0x03802644,
+ 0x03802642, 0x03802544, 0x03802542, 0x03802444,
+ 0x03802442, 0x03802344, 0x03802342, 0x03802244,
+ 0x03802242, 0x03802144, 0x03802142, 0x03802044,
+ 0x03802042, 0x03801f44, 0x03801f42, 0x03801e44,
+ 0x03801e42, 0x03801d44, 0x03801d42, 0x03801c44,
+ 0x03801c42, 0x03801b44, 0x03801b42, 0x03801a44,
+ 0x03801a42, 0x03801944, 0x03801942, 0x03801844,
+ 0x03801842, 0x03801744, 0x03801742, 0x03801644,
+ 0x03801642, 0x03801544, 0x03801542, 0x03801444,
+ 0x03801442, 0x03801344, 0x03801342, 0x00002b00
+};
+
+static const u16 nphy_tpc_loscale[] = {
+ 256, 256, 271, 271, 287, 256, 256, 271,
+ 271, 287, 287, 304, 304, 256, 256, 271,
+ 271, 287, 287, 304, 304, 322, 322, 341,
+ 341, 362, 362, 383, 383, 256, 256, 271,
+ 271, 287, 287, 304, 304, 322, 322, 256,
+ 256, 271, 271, 287, 287, 304, 304, 322,
+ 322, 341, 341, 362, 362, 256, 256, 271,
+ 271, 287, 287, 304, 304, 322, 322, 256,
+ 256, 271, 271, 287, 287, 304, 304, 322,
+ 322, 341, 341, 362, 362, 256, 256, 271,
+ 271, 287, 287, 304, 304, 322, 322, 341,
+ 341, 362, 362, 383, 383, 406, 406, 430,
+ 430, 455, 455, 482, 482, 511, 511, 541,
+ 541, 573, 573, 607, 607, 643, 643, 681,
+ 681, 722, 722, 764, 764, 810, 810, 858,
+ 858, 908, 908, 962, 962, 1019, 1019, 256
+};
+
+static u32 nphy_tpc_txgain_ipa[] = {
+ 0x5ff7002d, 0x5ff7002b, 0x5ff7002a, 0x5ff70029,
+ 0x5ff70028, 0x5ff70027, 0x5ff70026, 0x5ff70025,
+ 0x5ef7002d, 0x5ef7002b, 0x5ef7002a, 0x5ef70029,
+ 0x5ef70028, 0x5ef70027, 0x5ef70026, 0x5ef70025,
+ 0x5df7002d, 0x5df7002b, 0x5df7002a, 0x5df70029,
+ 0x5df70028, 0x5df70027, 0x5df70026, 0x5df70025,
+ 0x5cf7002d, 0x5cf7002b, 0x5cf7002a, 0x5cf70029,
+ 0x5cf70028, 0x5cf70027, 0x5cf70026, 0x5cf70025,
+ 0x5bf7002d, 0x5bf7002b, 0x5bf7002a, 0x5bf70029,
+ 0x5bf70028, 0x5bf70027, 0x5bf70026, 0x5bf70025,
+ 0x5af7002d, 0x5af7002b, 0x5af7002a, 0x5af70029,
+ 0x5af70028, 0x5af70027, 0x5af70026, 0x5af70025,
+ 0x59f7002d, 0x59f7002b, 0x59f7002a, 0x59f70029,
+ 0x59f70028, 0x59f70027, 0x59f70026, 0x59f70025,
+ 0x58f7002d, 0x58f7002b, 0x58f7002a, 0x58f70029,
+ 0x58f70028, 0x58f70027, 0x58f70026, 0x58f70025,
+ 0x57f7002d, 0x57f7002b, 0x57f7002a, 0x57f70029,
+ 0x57f70028, 0x57f70027, 0x57f70026, 0x57f70025,
+ 0x56f7002d, 0x56f7002b, 0x56f7002a, 0x56f70029,
+ 0x56f70028, 0x56f70027, 0x56f70026, 0x56f70025,
+ 0x55f7002d, 0x55f7002b, 0x55f7002a, 0x55f70029,
+ 0x55f70028, 0x55f70027, 0x55f70026, 0x55f70025,
+ 0x54f7002d, 0x54f7002b, 0x54f7002a, 0x54f70029,
+ 0x54f70028, 0x54f70027, 0x54f70026, 0x54f70025,
+ 0x53f7002d, 0x53f7002b, 0x53f7002a, 0x53f70029,
+ 0x53f70028, 0x53f70027, 0x53f70026, 0x53f70025,
+ 0x52f7002d, 0x52f7002b, 0x52f7002a, 0x52f70029,
+ 0x52f70028, 0x52f70027, 0x52f70026, 0x52f70025,
+ 0x51f7002d, 0x51f7002b, 0x51f7002a, 0x51f70029,
+ 0x51f70028, 0x51f70027, 0x51f70026, 0x51f70025,
+ 0x50f7002d, 0x50f7002b, 0x50f7002a, 0x50f70029,
+ 0x50f70028, 0x50f70027, 0x50f70026, 0x50f70025
+};
+
+static u32 nphy_tpc_txgain_ipa_rev5[] = {
+ 0x1ff7002d, 0x1ff7002b, 0x1ff7002a, 0x1ff70029,
+ 0x1ff70028, 0x1ff70027, 0x1ff70026, 0x1ff70025,
+ 0x1ef7002d, 0x1ef7002b, 0x1ef7002a, 0x1ef70029,
+ 0x1ef70028, 0x1ef70027, 0x1ef70026, 0x1ef70025,
+ 0x1df7002d, 0x1df7002b, 0x1df7002a, 0x1df70029,
+ 0x1df70028, 0x1df70027, 0x1df70026, 0x1df70025,
+ 0x1cf7002d, 0x1cf7002b, 0x1cf7002a, 0x1cf70029,
+ 0x1cf70028, 0x1cf70027, 0x1cf70026, 0x1cf70025,
+ 0x1bf7002d, 0x1bf7002b, 0x1bf7002a, 0x1bf70029,
+ 0x1bf70028, 0x1bf70027, 0x1bf70026, 0x1bf70025,
+ 0x1af7002d, 0x1af7002b, 0x1af7002a, 0x1af70029,
+ 0x1af70028, 0x1af70027, 0x1af70026, 0x1af70025,
+ 0x19f7002d, 0x19f7002b, 0x19f7002a, 0x19f70029,
+ 0x19f70028, 0x19f70027, 0x19f70026, 0x19f70025,
+ 0x18f7002d, 0x18f7002b, 0x18f7002a, 0x18f70029,
+ 0x18f70028, 0x18f70027, 0x18f70026, 0x18f70025,
+ 0x17f7002d, 0x17f7002b, 0x17f7002a, 0x17f70029,
+ 0x17f70028, 0x17f70027, 0x17f70026, 0x17f70025,
+ 0x16f7002d, 0x16f7002b, 0x16f7002a, 0x16f70029,
+ 0x16f70028, 0x16f70027, 0x16f70026, 0x16f70025,
+ 0x15f7002d, 0x15f7002b, 0x15f7002a, 0x15f70029,
+ 0x15f70028, 0x15f70027, 0x15f70026, 0x15f70025,
+ 0x14f7002d, 0x14f7002b, 0x14f7002a, 0x14f70029,
+ 0x14f70028, 0x14f70027, 0x14f70026, 0x14f70025,
+ 0x13f7002d, 0x13f7002b, 0x13f7002a, 0x13f70029,
+ 0x13f70028, 0x13f70027, 0x13f70026, 0x13f70025,
+ 0x12f7002d, 0x12f7002b, 0x12f7002a, 0x12f70029,
+ 0x12f70028, 0x12f70027, 0x12f70026, 0x12f70025,
+ 0x11f7002d, 0x11f7002b, 0x11f7002a, 0x11f70029,
+ 0x11f70028, 0x11f70027, 0x11f70026, 0x11f70025,
+ 0x10f7002d, 0x10f7002b, 0x10f7002a, 0x10f70029,
+ 0x10f70028, 0x10f70027, 0x10f70026, 0x10f70025
+};
+
+static u32 nphy_tpc_txgain_ipa_rev6[] = {
+ 0x0ff7002d, 0x0ff7002b, 0x0ff7002a, 0x0ff70029,
+ 0x0ff70028, 0x0ff70027, 0x0ff70026, 0x0ff70025,
+ 0x0ef7002d, 0x0ef7002b, 0x0ef7002a, 0x0ef70029,
+ 0x0ef70028, 0x0ef70027, 0x0ef70026, 0x0ef70025,
+ 0x0df7002d, 0x0df7002b, 0x0df7002a, 0x0df70029,
+ 0x0df70028, 0x0df70027, 0x0df70026, 0x0df70025,
+ 0x0cf7002d, 0x0cf7002b, 0x0cf7002a, 0x0cf70029,
+ 0x0cf70028, 0x0cf70027, 0x0cf70026, 0x0cf70025,
+ 0x0bf7002d, 0x0bf7002b, 0x0bf7002a, 0x0bf70029,
+ 0x0bf70028, 0x0bf70027, 0x0bf70026, 0x0bf70025,
+ 0x0af7002d, 0x0af7002b, 0x0af7002a, 0x0af70029,
+ 0x0af70028, 0x0af70027, 0x0af70026, 0x0af70025,
+ 0x09f7002d, 0x09f7002b, 0x09f7002a, 0x09f70029,
+ 0x09f70028, 0x09f70027, 0x09f70026, 0x09f70025,
+ 0x08f7002d, 0x08f7002b, 0x08f7002a, 0x08f70029,
+ 0x08f70028, 0x08f70027, 0x08f70026, 0x08f70025,
+ 0x07f7002d, 0x07f7002b, 0x07f7002a, 0x07f70029,
+ 0x07f70028, 0x07f70027, 0x07f70026, 0x07f70025,
+ 0x06f7002d, 0x06f7002b, 0x06f7002a, 0x06f70029,
+ 0x06f70028, 0x06f70027, 0x06f70026, 0x06f70025,
+ 0x05f7002d, 0x05f7002b, 0x05f7002a, 0x05f70029,
+ 0x05f70028, 0x05f70027, 0x05f70026, 0x05f70025,
+ 0x04f7002d, 0x04f7002b, 0x04f7002a, 0x04f70029,
+ 0x04f70028, 0x04f70027, 0x04f70026, 0x04f70025,
+ 0x03f7002d, 0x03f7002b, 0x03f7002a, 0x03f70029,
+ 0x03f70028, 0x03f70027, 0x03f70026, 0x03f70025,
+ 0x02f7002d, 0x02f7002b, 0x02f7002a, 0x02f70029,
+ 0x02f70028, 0x02f70027, 0x02f70026, 0x02f70025,
+ 0x01f7002d, 0x01f7002b, 0x01f7002a, 0x01f70029,
+ 0x01f70028, 0x01f70027, 0x01f70026, 0x01f70025,
+ 0x00f7002d, 0x00f7002b, 0x00f7002a, 0x00f70029,
+ 0x00f70028, 0x00f70027, 0x00f70026, 0x00f70025
+};
+
+static u32 nphy_tpc_txgain_ipa_2g_2057rev3[] = {
+ 0x70ff0040, 0x70f7003e, 0x70ef003b, 0x70e70039,
+ 0x70df0037, 0x70d70036, 0x70cf0033, 0x70c70032,
+ 0x70bf0031, 0x70b7002f, 0x70af002e, 0x70a7002d,
+ 0x709f002d, 0x7097002c, 0x708f002c, 0x7087002c,
+ 0x707f002b, 0x7077002c, 0x706f002c, 0x7067002d,
+ 0x705f002e, 0x705f002b, 0x705f0029, 0x7057002a,
+ 0x70570028, 0x704f002a, 0x7047002c, 0x7047002a,
+ 0x70470028, 0x70470026, 0x70470024, 0x70470022,
+ 0x7047001f, 0x70370027, 0x70370024, 0x70370022,
+ 0x70370020, 0x7037001f, 0x7037001d, 0x7037001b,
+ 0x7037001a, 0x70370018, 0x70370017, 0x7027001e,
+ 0x7027001d, 0x7027001a, 0x701f0024, 0x701f0022,
+ 0x701f0020, 0x701f001f, 0x701f001d, 0x701f001b,
+ 0x701f001a, 0x701f0018, 0x701f0017, 0x701f0015,
+ 0x701f0014, 0x701f0013, 0x701f0012, 0x701f0011,
+ 0x70170019, 0x70170018, 0x70170016, 0x70170015,
+ 0x70170014, 0x70170013, 0x70170012, 0x70170010,
+ 0x70170010, 0x7017000f, 0x700f001d, 0x700f001b,
+ 0x700f001a, 0x700f0018, 0x700f0017, 0x700f0015,
+ 0x700f0015, 0x700f0013, 0x700f0013, 0x700f0011,
+ 0x700f0010, 0x700f0010, 0x700f000f, 0x700f000e,
+ 0x700f000d, 0x700f000c, 0x700f000b, 0x700f000b,
+ 0x700f000b, 0x700f000a, 0x700f0009, 0x700f0009,
+ 0x700f0009, 0x700f0008, 0x700f0007, 0x700f0007,
+ 0x700f0006, 0x700f0006, 0x700f0006, 0x700f0006,
+ 0x700f0005, 0x700f0005, 0x700f0005, 0x700f0004,
+ 0x700f0004, 0x700f0004, 0x700f0004, 0x700f0004,
+ 0x700f0004, 0x700f0003, 0x700f0003, 0x700f0003,
+ 0x700f0003, 0x700f0002, 0x700f0002, 0x700f0002,
+ 0x700f0002, 0x700f0002, 0x700f0002, 0x700f0001,
+ 0x700f0001, 0x700f0001, 0x700f0001, 0x700f0001,
+ 0x700f0001, 0x700f0001, 0x700f0001, 0x700f0001
+};
+
+static u32 nphy_tpc_txgain_ipa_2g_2057rev4n6[] = {
+ 0xf0ff0040, 0xf0f7003e, 0xf0ef003b, 0xf0e70039,
+ 0xf0df0037, 0xf0d70036, 0xf0cf0033, 0xf0c70032,
+ 0xf0bf0031, 0xf0b7002f, 0xf0af002e, 0xf0a7002d,
+ 0xf09f002d, 0xf097002c, 0xf08f002c, 0xf087002c,
+ 0xf07f002b, 0xf077002c, 0xf06f002c, 0xf067002d,
+ 0xf05f002e, 0xf05f002b, 0xf05f0029, 0xf057002a,
+ 0xf0570028, 0xf04f002a, 0xf047002c, 0xf047002a,
+ 0xf0470028, 0xf0470026, 0xf0470024, 0xf0470022,
+ 0xf047001f, 0xf0370027, 0xf0370024, 0xf0370022,
+ 0xf0370020, 0xf037001f, 0xf037001d, 0xf037001b,
+ 0xf037001a, 0xf0370018, 0xf0370017, 0xf027001e,
+ 0xf027001d, 0xf027001a, 0xf01f0024, 0xf01f0022,
+ 0xf01f0020, 0xf01f001f, 0xf01f001d, 0xf01f001b,
+ 0xf01f001a, 0xf01f0018, 0xf01f0017, 0xf01f0015,
+ 0xf01f0014, 0xf01f0013, 0xf01f0012, 0xf01f0011,
+ 0xf0170019, 0xf0170018, 0xf0170016, 0xf0170015,
+ 0xf0170014, 0xf0170013, 0xf0170012, 0xf0170010,
+ 0xf0170010, 0xf017000f, 0xf00f001d, 0xf00f001b,
+ 0xf00f001a, 0xf00f0018, 0xf00f0017, 0xf00f0015,
+ 0xf00f0015, 0xf00f0013, 0xf00f0013, 0xf00f0011,
+ 0xf00f0010, 0xf00f0010, 0xf00f000f, 0xf00f000e,
+ 0xf00f000d, 0xf00f000c, 0xf00f000b, 0xf00f000b,
+ 0xf00f000b, 0xf00f000a, 0xf00f0009, 0xf00f0009,
+ 0xf00f0009, 0xf00f0008, 0xf00f0007, 0xf00f0007,
+ 0xf00f0006, 0xf00f0006, 0xf00f0006, 0xf00f0006,
+ 0xf00f0005, 0xf00f0005, 0xf00f0005, 0xf00f0004,
+ 0xf00f0004, 0xf00f0004, 0xf00f0004, 0xf00f0004,
+ 0xf00f0004, 0xf00f0003, 0xf00f0003, 0xf00f0003,
+ 0xf00f0003, 0xf00f0002, 0xf00f0002, 0xf00f0002,
+ 0xf00f0002, 0xf00f0002, 0xf00f0002, 0xf00f0001,
+ 0xf00f0001, 0xf00f0001, 0xf00f0001, 0xf00f0001,
+ 0xf00f0001, 0xf00f0001, 0xf00f0001, 0xf00f0001
+};
+
+static u32 nphy_tpc_txgain_ipa_2g_2057rev5[] = {
+ 0x30ff0031, 0x30e70031, 0x30e7002e, 0x30cf002e,
+ 0x30bf002e, 0x30af002e, 0x309f002f, 0x307f0033,
+ 0x307f0031, 0x307f002e, 0x3077002e, 0x306f002e,
+ 0x3067002e, 0x305f002f, 0x30570030, 0x3057002d,
+ 0x304f002e, 0x30470031, 0x3047002e, 0x3047002c,
+ 0x30470029, 0x303f002c, 0x303f0029, 0x3037002d,
+ 0x3037002a, 0x30370028, 0x302f002c, 0x302f002a,
+ 0x302f0028, 0x302f0026, 0x3027002c, 0x30270029,
+ 0x30270027, 0x30270025, 0x30270023, 0x301f002c,
+ 0x301f002a, 0x301f0028, 0x301f0025, 0x301f0024,
+ 0x301f0022, 0x301f001f, 0x3017002d, 0x3017002b,
+ 0x30170028, 0x30170026, 0x30170024, 0x30170022,
+ 0x30170020, 0x3017001e, 0x3017001d, 0x3017001b,
+ 0x3017001a, 0x30170018, 0x30170017, 0x30170015,
+ 0x300f002c, 0x300f0029, 0x300f0027, 0x300f0024,
+ 0x300f0022, 0x300f0021, 0x300f001f, 0x300f001d,
+ 0x300f001b, 0x300f001a, 0x300f0018, 0x300f0017,
+ 0x300f0016, 0x300f0015, 0x300f0115, 0x300f0215,
+ 0x300f0315, 0x300f0415, 0x300f0515, 0x300f0615,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715
+};
+
+static u32 nphy_tpc_txgain_ipa_2g_2057rev7[] = {
+ 0x30ff0031, 0x30e70031, 0x30e7002e, 0x30cf002e,
+ 0x30bf002e, 0x30af002e, 0x309f002f, 0x307f0033,
+ 0x307f0031, 0x307f002e, 0x3077002e, 0x306f002e,
+ 0x3067002e, 0x305f002f, 0x30570030, 0x3057002d,
+ 0x304f002e, 0x30470031, 0x3047002e, 0x3047002c,
+ 0x30470029, 0x303f002c, 0x303f0029, 0x3037002d,
+ 0x3037002a, 0x30370028, 0x302f002c, 0x302f002a,
+ 0x302f0028, 0x302f0026, 0x3027002c, 0x30270029,
+ 0x30270027, 0x30270025, 0x30270023, 0x301f002c,
+ 0x301f002a, 0x301f0028, 0x301f0025, 0x301f0024,
+ 0x301f0022, 0x301f001f, 0x3017002d, 0x3017002b,
+ 0x30170028, 0x30170026, 0x30170024, 0x30170022,
+ 0x30170020, 0x3017001e, 0x3017001d, 0x3017001b,
+ 0x3017001a, 0x30170018, 0x30170017, 0x30170015,
+ 0x300f002c, 0x300f0029, 0x300f0027, 0x300f0024,
+ 0x300f0022, 0x300f0021, 0x300f001f, 0x300f001d,
+ 0x300f001b, 0x300f001a, 0x300f0018, 0x300f0017,
+ 0x300f0016, 0x300f0015, 0x300f0115, 0x300f0215,
+ 0x300f0315, 0x300f0415, 0x300f0515, 0x300f0615,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715,
+ 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715
+};
+
+static u32 nphy_tpc_txgain_ipa_5g[] = {
+ 0x7ff70035, 0x7ff70033, 0x7ff70032, 0x7ff70031,
+ 0x7ff7002f, 0x7ff7002e, 0x7ff7002d, 0x7ff7002b,
+ 0x7ff7002a, 0x7ff70029, 0x7ff70028, 0x7ff70027,
+ 0x7ff70026, 0x7ff70024, 0x7ff70023, 0x7ff70022,
+ 0x7ef70028, 0x7ef70027, 0x7ef70026, 0x7ef70025,
+ 0x7ef70024, 0x7ef70023, 0x7df70028, 0x7df70027,
+ 0x7df70026, 0x7df70025, 0x7df70024, 0x7df70023,
+ 0x7df70022, 0x7cf70029, 0x7cf70028, 0x7cf70027,
+ 0x7cf70026, 0x7cf70025, 0x7cf70023, 0x7cf70022,
+ 0x7bf70029, 0x7bf70028, 0x7bf70026, 0x7bf70025,
+ 0x7bf70024, 0x7bf70023, 0x7bf70022, 0x7bf70021,
+ 0x7af70029, 0x7af70028, 0x7af70027, 0x7af70026,
+ 0x7af70025, 0x7af70024, 0x7af70023, 0x7af70022,
+ 0x79f70029, 0x79f70028, 0x79f70027, 0x79f70026,
+ 0x79f70025, 0x79f70024, 0x79f70023, 0x79f70022,
+ 0x78f70029, 0x78f70028, 0x78f70027, 0x78f70026,
+ 0x78f70025, 0x78f70024, 0x78f70023, 0x78f70022,
+ 0x77f70029, 0x77f70028, 0x77f70027, 0x77f70026,
+ 0x77f70025, 0x77f70024, 0x77f70023, 0x77f70022,
+ 0x76f70029, 0x76f70028, 0x76f70027, 0x76f70026,
+ 0x76f70024, 0x76f70023, 0x76f70022, 0x76f70021,
+ 0x75f70029, 0x75f70028, 0x75f70027, 0x75f70026,
+ 0x75f70025, 0x75f70024, 0x75f70023, 0x74f70029,
+ 0x74f70028, 0x74f70026, 0x74f70025, 0x74f70024,
+ 0x74f70023, 0x74f70022, 0x73f70029, 0x73f70027,
+ 0x73f70026, 0x73f70025, 0x73f70024, 0x73f70023,
+ 0x73f70022, 0x72f70028, 0x72f70027, 0x72f70026,
+ 0x72f70025, 0x72f70024, 0x72f70023, 0x72f70022,
+ 0x71f70028, 0x71f70027, 0x71f70026, 0x71f70025,
+ 0x71f70024, 0x71f70023, 0x70f70028, 0x70f70027,
+ 0x70f70026, 0x70f70024, 0x70f70023, 0x70f70022,
+ 0x70f70021, 0x70f70020, 0x70f70020, 0x70f7001f
+};
+
+static u32 nphy_tpc_txgain_ipa_5g_2057[] = {
+ 0x7f7f0044, 0x7f7f0040, 0x7f7f003c, 0x7f7f0039,
+ 0x7f7f0036, 0x7e7f003c, 0x7e7f0038, 0x7e7f0035,
+ 0x7d7f003c, 0x7d7f0039, 0x7d7f0036, 0x7d7f0033,
+ 0x7c7f003b, 0x7c7f0037, 0x7c7f0034, 0x7b7f003a,
+ 0x7b7f0036, 0x7b7f0033, 0x7a7f003c, 0x7a7f0039,
+ 0x7a7f0036, 0x7a7f0033, 0x797f003b, 0x797f0038,
+ 0x797f0035, 0x797f0032, 0x787f003b, 0x787f0038,
+ 0x787f0035, 0x787f0032, 0x777f003a, 0x777f0037,
+ 0x777f0034, 0x777f0031, 0x767f003a, 0x767f0036,
+ 0x767f0033, 0x767f0031, 0x757f003a, 0x757f0037,
+ 0x757f0034, 0x747f003c, 0x747f0039, 0x747f0036,
+ 0x747f0033, 0x737f003b, 0x737f0038, 0x737f0035,
+ 0x737f0032, 0x727f0039, 0x727f0036, 0x727f0033,
+ 0x727f0030, 0x717f003a, 0x717f0037, 0x717f0034,
+ 0x707f003b, 0x707f0038, 0x707f0035, 0x707f0032,
+ 0x707f002f, 0x707f002d, 0x707f002a, 0x707f0028,
+ 0x707f0025, 0x707f0023, 0x707f0021, 0x707f0020,
+ 0x707f001e, 0x707f001c, 0x707f001b, 0x707f0019,
+ 0x707f0018, 0x707f0016, 0x707f0015, 0x707f0014,
+ 0x707f0013, 0x707f0012, 0x707f0011, 0x707f0010,
+ 0x707f000f, 0x707f000e, 0x707f000d, 0x707f000d,
+ 0x707f000c, 0x707f000b, 0x707f000b, 0x707f000a,
+ 0x707f0009, 0x707f0009, 0x707f0008, 0x707f0008,
+ 0x707f0007, 0x707f0007, 0x707f0007, 0x707f0006,
+ 0x707f0006, 0x707f0006, 0x707f0005, 0x707f0005,
+ 0x707f0005, 0x707f0004, 0x707f0004, 0x707f0004,
+ 0x707f0004, 0x707f0004, 0x707f0003, 0x707f0003,
+ 0x707f0003, 0x707f0003, 0x707f0003, 0x707f0003,
+ 0x707f0002, 0x707f0002, 0x707f0002, 0x707f0002,
+ 0x707f0002, 0x707f0002, 0x707f0002, 0x707f0002,
+ 0x707f0001, 0x707f0001, 0x707f0001, 0x707f0001,
+ 0x707f0001, 0x707f0001, 0x707f0001, 0x707f0001
+};
+
+static u32 nphy_tpc_txgain_ipa_5g_2057rev7[] = {
+ 0x6f7f0031, 0x6f7f002e, 0x6f7f002c, 0x6f7f002a,
+ 0x6f7f0027, 0x6e7f002e, 0x6e7f002c, 0x6e7f002a,
+ 0x6d7f0030, 0x6d7f002d, 0x6d7f002a, 0x6d7f0028,
+ 0x6c7f0030, 0x6c7f002d, 0x6c7f002b, 0x6b7f002e,
+ 0x6b7f002c, 0x6b7f002a, 0x6b7f0027, 0x6a7f002e,
+ 0x6a7f002c, 0x6a7f002a, 0x697f0030, 0x697f002e,
+ 0x697f002b, 0x697f0029, 0x687f002f, 0x687f002d,
+ 0x687f002a, 0x687f0027, 0x677f002f, 0x677f002d,
+ 0x677f002a, 0x667f0031, 0x667f002e, 0x667f002c,
+ 0x667f002a, 0x657f0030, 0x657f002e, 0x657f002b,
+ 0x657f0029, 0x647f0030, 0x647f002d, 0x647f002b,
+ 0x647f0029, 0x637f002f, 0x637f002d, 0x637f002a,
+ 0x627f0030, 0x627f002d, 0x627f002b, 0x627f0029,
+ 0x617f0030, 0x617f002e, 0x617f002b, 0x617f0029,
+ 0x607f002f, 0x607f002d, 0x607f002a, 0x607f0027,
+ 0x607f0026, 0x607f0023, 0x607f0021, 0x607f0020,
+ 0x607f001e, 0x607f001c, 0x607f001a, 0x607f0019,
+ 0x607f0018, 0x607f0016, 0x607f0015, 0x607f0014,
+ 0x607f0012, 0x607f0012, 0x607f0011, 0x607f000f,
+ 0x607f000f, 0x607f000e, 0x607f000d, 0x607f000c,
+ 0x607f000c, 0x607f000b, 0x607f000b, 0x607f000a,
+ 0x607f0009, 0x607f0009, 0x607f0008, 0x607f0008,
+ 0x607f0008, 0x607f0007, 0x607f0007, 0x607f0006,
+ 0x607f0006, 0x607f0005, 0x607f0005, 0x607f0005,
+ 0x607f0005, 0x607f0005, 0x607f0004, 0x607f0004,
+ 0x607f0004, 0x607f0004, 0x607f0003, 0x607f0003,
+ 0x607f0003, 0x607f0003, 0x607f0002, 0x607f0002,
+ 0x607f0002, 0x607f0002, 0x607f0002, 0x607f0002,
+ 0x607f0002, 0x607f0002, 0x607f0002, 0x607f0002,
+ 0x607f0002, 0x607f0002, 0x607f0002, 0x607f0002,
+ 0x607f0002, 0x607f0001, 0x607f0001, 0x607f0001,
+ 0x607f0001, 0x607f0001, 0x607f0001, 0x607f0001
+};
+
+static s8 nphy_papd_pga_gain_delta_ipa_2g[] = {
+ -114, -108, -98, -91, -84, -78, -70, -62,
+ -54, -46, -39, -31, -23, -15, -8, 0
+};
+
+static s8 nphy_papd_pga_gain_delta_ipa_5g[] = {
+ -100, -95, -89, -83, -77, -70, -63, -56,
+ -48, -41, -33, -25, -19, -12, -6, 0
+};
+
+static s16 nphy_papd_padgain_dlt_2g_2057rev3n4[] = {
+ -159, -113, -86, -72, -62, -54, -48, -43,
+ -39, -35, -31, -28, -25, -23, -20, -18,
+ -17, -15, -13, -11, -10, -8, -7, -6,
+ -5, -4, -3, -3, -2, -1, -1, 0
+};
+
+static s16 nphy_papd_padgain_dlt_2g_2057rev5[] = {
+ -109, -109, -82, -68, -58, -50, -44, -39,
+ -35, -31, -28, -26, -23, -21, -19, -17,
+ -16, -14, -13, -11, -10, -9, -8, -7,
+ -5, -5, -4, -3, -2, -1, -1, 0
+};
+
+static s16 nphy_papd_padgain_dlt_2g_2057rev7[] = {
+ -122, -122, -95, -80, -69, -61, -54, -49,
+ -43, -39, -35, -32, -28, -26, -23, -21,
+ -18, -16, -15, -13, -11, -10, -8, -7,
+ -6, -5, -4, -3, -2, -1, -1, 0
+};
+
+static s8 nphy_papd_pgagain_dlt_5g_2057[] = {
+ -107, -101, -92, -85, -78, -71, -62, -55,
+ -47, -39, -32, -24, -19, -12, -6, 0
+};
+
+static s8 nphy_papd_pgagain_dlt_5g_2057rev7[] = {
+ -110, -104, -95, -88, -81, -74, -66, -58,
+ -50, -44, -36, -28, -23, -15, -8, 0
+};
+
+static u8 pad_gain_codes_used_2057rev5[] = {
+ 20, 19, 18, 17, 16, 15, 14, 13, 12, 11,
+ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
+};
+
+static u8 pad_gain_codes_used_2057rev7[] = {
+ 15, 14, 13, 12, 11, 10, 9, 8, 7, 6,
+ 5, 4, 3, 2, 1
+};
+
+static u8 pad_all_gain_codes_2057[] = {
+ 31, 30, 29, 28, 27, 26, 25, 24, 23, 22,
+ 21, 20, 19, 18, 17, 16, 15, 14, 13, 12,
+ 11, 10, 9, 8, 7, 6, 5, 4, 3, 2,
+ 1, 0
+};
+
+static u8 pga_all_gain_codes_2057[] = {
+ 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
+};
+
+static u32 nphy_papd_scaltbl[] = {
+ 0x0ae2002f, 0x0a3b0032, 0x09a70035, 0x09220038,
+ 0x0887003c, 0x081f003f, 0x07a20043, 0x07340047,
+ 0x06d2004b, 0x067a004f, 0x06170054, 0x05bf0059,
+ 0x0571005e, 0x051e0064, 0x04d3006a, 0x04910070,
+ 0x044c0077, 0x040f007e, 0x03d90085, 0x03a1008d,
+ 0x036f0095, 0x033d009e, 0x030b00a8, 0x02e000b2,
+ 0x02b900bc, 0x029200c7, 0x026d00d3, 0x024900e0,
+ 0x022900ed, 0x020a00fb, 0x01ec010a, 0x01d0011a,
+ 0x01b7012a, 0x019e013c, 0x0187014f, 0x01720162,
+ 0x015d0177, 0x0149018e, 0x013701a5, 0x012601be,
+ 0x011501d9, 0x010501f5, 0x00f70212, 0x00e90232,
+ 0x00dc0253, 0x00d00276, 0x00c4029c, 0x00b902c3,
+ 0x00af02ed, 0x00a5031a, 0x009c0349, 0x0093037a,
+ 0x008b03af, 0x008303e7, 0x007c0422, 0x00750461,
+ 0x006e04a3, 0x006804ea, 0x00620534, 0x005d0583,
+ 0x005805d7, 0x0053062f, 0x004e068d, 0x004a06f1
+};
+
+static u32 nphy_tpc_txgain_rev3[] = {
+ 0x1f410044, 0x1f410042, 0x1f410040, 0x1f41003e,
+ 0x1f41003c, 0x1f41003b, 0x1f410039, 0x1f410037,
+ 0x1e410044, 0x1e410042, 0x1e410040, 0x1e41003e,
+ 0x1e41003c, 0x1e41003b, 0x1e410039, 0x1e410037,
+ 0x1d410044, 0x1d410042, 0x1d410040, 0x1d41003e,
+ 0x1d41003c, 0x1d41003b, 0x1d410039, 0x1d410037,
+ 0x1c410044, 0x1c410042, 0x1c410040, 0x1c41003e,
+ 0x1c41003c, 0x1c41003b, 0x1c410039, 0x1c410037,
+ 0x1b410044, 0x1b410042, 0x1b410040, 0x1b41003e,
+ 0x1b41003c, 0x1b41003b, 0x1b410039, 0x1b410037,
+ 0x1a410044, 0x1a410042, 0x1a410040, 0x1a41003e,
+ 0x1a41003c, 0x1a41003b, 0x1a410039, 0x1a410037,
+ 0x19410044, 0x19410042, 0x19410040, 0x1941003e,
+ 0x1941003c, 0x1941003b, 0x19410039, 0x19410037,
+ 0x18410044, 0x18410042, 0x18410040, 0x1841003e,
+ 0x1841003c, 0x1841003b, 0x18410039, 0x18410037,
+ 0x17410044, 0x17410042, 0x17410040, 0x1741003e,
+ 0x1741003c, 0x1741003b, 0x17410039, 0x17410037,
+ 0x16410044, 0x16410042, 0x16410040, 0x1641003e,
+ 0x1641003c, 0x1641003b, 0x16410039, 0x16410037,
+ 0x15410044, 0x15410042, 0x15410040, 0x1541003e,
+ 0x1541003c, 0x1541003b, 0x15410039, 0x15410037,
+ 0x14410044, 0x14410042, 0x14410040, 0x1441003e,
+ 0x1441003c, 0x1441003b, 0x14410039, 0x14410037,
+ 0x13410044, 0x13410042, 0x13410040, 0x1341003e,
+ 0x1341003c, 0x1341003b, 0x13410039, 0x13410037,
+ 0x12410044, 0x12410042, 0x12410040, 0x1241003e,
+ 0x1241003c, 0x1241003b, 0x12410039, 0x12410037,
+ 0x11410044, 0x11410042, 0x11410040, 0x1141003e,
+ 0x1141003c, 0x1141003b, 0x11410039, 0x11410037,
+ 0x10410044, 0x10410042, 0x10410040, 0x1041003e,
+ 0x1041003c, 0x1041003b, 0x10410039, 0x10410037
+};
+
+static u32 nphy_tpc_txgain_HiPwrEPA[] = {
+ 0x0f410044, 0x0f410042, 0x0f410040, 0x0f41003e,
+ 0x0f41003c, 0x0f41003b, 0x0f410039, 0x0f410037,
+ 0x0e410044, 0x0e410042, 0x0e410040, 0x0e41003e,
+ 0x0e41003c, 0x0e41003b, 0x0e410039, 0x0e410037,
+ 0x0d410044, 0x0d410042, 0x0d410040, 0x0d41003e,
+ 0x0d41003c, 0x0d41003b, 0x0d410039, 0x0d410037,
+ 0x0c410044, 0x0c410042, 0x0c410040, 0x0c41003e,
+ 0x0c41003c, 0x0c41003b, 0x0c410039, 0x0c410037,
+ 0x0b410044, 0x0b410042, 0x0b410040, 0x0b41003e,
+ 0x0b41003c, 0x0b41003b, 0x0b410039, 0x0b410037,
+ 0x0a410044, 0x0a410042, 0x0a410040, 0x0a41003e,
+ 0x0a41003c, 0x0a41003b, 0x0a410039, 0x0a410037,
+ 0x09410044, 0x09410042, 0x09410040, 0x0941003e,
+ 0x0941003c, 0x0941003b, 0x09410039, 0x09410037,
+ 0x08410044, 0x08410042, 0x08410040, 0x0841003e,
+ 0x0841003c, 0x0841003b, 0x08410039, 0x08410037,
+ 0x07410044, 0x07410042, 0x07410040, 0x0741003e,
+ 0x0741003c, 0x0741003b, 0x07410039, 0x07410037,
+ 0x06410044, 0x06410042, 0x06410040, 0x0641003e,
+ 0x0641003c, 0x0641003b, 0x06410039, 0x06410037,
+ 0x05410044, 0x05410042, 0x05410040, 0x0541003e,
+ 0x0541003c, 0x0541003b, 0x05410039, 0x05410037,
+ 0x04410044, 0x04410042, 0x04410040, 0x0441003e,
+ 0x0441003c, 0x0441003b, 0x04410039, 0x04410037,
+ 0x03410044, 0x03410042, 0x03410040, 0x0341003e,
+ 0x0341003c, 0x0341003b, 0x03410039, 0x03410037,
+ 0x02410044, 0x02410042, 0x02410040, 0x0241003e,
+ 0x0241003c, 0x0241003b, 0x02410039, 0x02410037,
+ 0x01410044, 0x01410042, 0x01410040, 0x0141003e,
+ 0x0141003c, 0x0141003b, 0x01410039, 0x01410037,
+ 0x00410044, 0x00410042, 0x00410040, 0x0041003e,
+ 0x0041003c, 0x0041003b, 0x00410039, 0x00410037
+};
+
+static u32 nphy_tpc_txgain_epa_2057rev3[] = {
+ 0x80f90040, 0x80e10040, 0x80e1003c, 0x80c9003d,
+ 0x80b9003c, 0x80a9003d, 0x80a1003c, 0x8099003b,
+ 0x8091003b, 0x8089003a, 0x8081003a, 0x80790039,
+ 0x80710039, 0x8069003a, 0x8061003b, 0x8059003d,
+ 0x8051003f, 0x80490042, 0x8049003e, 0x8049003b,
+ 0x8041003e, 0x8041003b, 0x8039003e, 0x8039003b,
+ 0x80390038, 0x80390035, 0x8031003a, 0x80310036,
+ 0x80310033, 0x8029003a, 0x80290037, 0x80290034,
+ 0x80290031, 0x80210039, 0x80210036, 0x80210033,
+ 0x80210030, 0x8019003c, 0x80190039, 0x80190036,
+ 0x80190033, 0x80190030, 0x8019002d, 0x8019002b,
+ 0x80190028, 0x8011003a, 0x80110036, 0x80110033,
+ 0x80110030, 0x8011002e, 0x8011002b, 0x80110029,
+ 0x80110027, 0x80110024, 0x80110022, 0x80110020,
+ 0x8011001f, 0x8011001d, 0x8009003a, 0x80090037,
+ 0x80090034, 0x80090031, 0x8009002e, 0x8009002c,
+ 0x80090029, 0x80090027, 0x80090025, 0x80090023,
+ 0x80090021, 0x8009001f, 0x8009001d, 0x8009011d,
+ 0x8009021d, 0x8009031d, 0x8009041d, 0x8009051d,
+ 0x8009061d, 0x8009071d, 0x8009071d, 0x8009071d,
+ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d,
+ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d,
+ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d,
+ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d,
+ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d,
+ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d,
+ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d,
+ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d,
+ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d,
+ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d,
+ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d,
+ 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d
+};
+
+static u32 nphy_tpc_txgain_epa_2057rev5[] = {
+ 0x10f90040, 0x10e10040, 0x10e1003c, 0x10c9003d,
+ 0x10b9003c, 0x10a9003d, 0x10a1003c, 0x1099003b,
+ 0x1091003b, 0x1089003a, 0x1081003a, 0x10790039,
+ 0x10710039, 0x1069003a, 0x1061003b, 0x1059003d,
+ 0x1051003f, 0x10490042, 0x1049003e, 0x1049003b,
+ 0x1041003e, 0x1041003b, 0x1039003e, 0x1039003b,
+ 0x10390038, 0x10390035, 0x1031003a, 0x10310036,
+ 0x10310033, 0x1029003a, 0x10290037, 0x10290034,
+ 0x10290031, 0x10210039, 0x10210036, 0x10210033,
+ 0x10210030, 0x1019003c, 0x10190039, 0x10190036,
+ 0x10190033, 0x10190030, 0x1019002d, 0x1019002b,
+ 0x10190028, 0x1011003a, 0x10110036, 0x10110033,
+ 0x10110030, 0x1011002e, 0x1011002b, 0x10110029,
+ 0x10110027, 0x10110024, 0x10110022, 0x10110020,
+ 0x1011001f, 0x1011001d, 0x1009003a, 0x10090037,
+ 0x10090034, 0x10090031, 0x1009002e, 0x1009002c,
+ 0x10090029, 0x10090027, 0x10090025, 0x10090023,
+ 0x10090021, 0x1009001f, 0x1009001d, 0x1009001b,
+ 0x1009001a, 0x10090018, 0x10090017, 0x10090016,
+ 0x10090015, 0x10090013, 0x10090012, 0x10090011,
+ 0x10090010, 0x1009000f, 0x1009000f, 0x1009000e,
+ 0x1009000d, 0x1009000c, 0x1009000c, 0x1009000b,
+ 0x1009000a, 0x1009000a, 0x10090009, 0x10090009,
+ 0x10090008, 0x10090008, 0x10090007, 0x10090007,
+ 0x10090007, 0x10090006, 0x10090006, 0x10090005,
+ 0x10090005, 0x10090005, 0x10090005, 0x10090004,
+ 0x10090004, 0x10090004, 0x10090004, 0x10090003,
+ 0x10090003, 0x10090003, 0x10090003, 0x10090003,
+ 0x10090003, 0x10090002, 0x10090002, 0x10090002,
+ 0x10090002, 0x10090002, 0x10090002, 0x10090002,
+ 0x10090002, 0x10090002, 0x10090001, 0x10090001,
+ 0x10090001, 0x10090001, 0x10090001, 0x10090001
+};
+
+static u32 nphy_tpc_5GHz_txgain_rev3[] = {
+ 0xcff70044, 0xcff70042, 0xcff70040, 0xcff7003e,
+ 0xcff7003c, 0xcff7003b, 0xcff70039, 0xcff70037,
+ 0xcef70044, 0xcef70042, 0xcef70040, 0xcef7003e,
+ 0xcef7003c, 0xcef7003b, 0xcef70039, 0xcef70037,
+ 0xcdf70044, 0xcdf70042, 0xcdf70040, 0xcdf7003e,
+ 0xcdf7003c, 0xcdf7003b, 0xcdf70039, 0xcdf70037,
+ 0xccf70044, 0xccf70042, 0xccf70040, 0xccf7003e,
+ 0xccf7003c, 0xccf7003b, 0xccf70039, 0xccf70037,
+ 0xcbf70044, 0xcbf70042, 0xcbf70040, 0xcbf7003e,
+ 0xcbf7003c, 0xcbf7003b, 0xcbf70039, 0xcbf70037,
+ 0xcaf70044, 0xcaf70042, 0xcaf70040, 0xcaf7003e,
+ 0xcaf7003c, 0xcaf7003b, 0xcaf70039, 0xcaf70037,
+ 0xc9f70044, 0xc9f70042, 0xc9f70040, 0xc9f7003e,
+ 0xc9f7003c, 0xc9f7003b, 0xc9f70039, 0xc9f70037,
+ 0xc8f70044, 0xc8f70042, 0xc8f70040, 0xc8f7003e,
+ 0xc8f7003c, 0xc8f7003b, 0xc8f70039, 0xc8f70037,
+ 0xc7f70044, 0xc7f70042, 0xc7f70040, 0xc7f7003e,
+ 0xc7f7003c, 0xc7f7003b, 0xc7f70039, 0xc7f70037,
+ 0xc6f70044, 0xc6f70042, 0xc6f70040, 0xc6f7003e,
+ 0xc6f7003c, 0xc6f7003b, 0xc6f70039, 0xc6f70037,
+ 0xc5f70044, 0xc5f70042, 0xc5f70040, 0xc5f7003e,
+ 0xc5f7003c, 0xc5f7003b, 0xc5f70039, 0xc5f70037,
+ 0xc4f70044, 0xc4f70042, 0xc4f70040, 0xc4f7003e,
+ 0xc4f7003c, 0xc4f7003b, 0xc4f70039, 0xc4f70037,
+ 0xc3f70044, 0xc3f70042, 0xc3f70040, 0xc3f7003e,
+ 0xc3f7003c, 0xc3f7003b, 0xc3f70039, 0xc3f70037,
+ 0xc2f70044, 0xc2f70042, 0xc2f70040, 0xc2f7003e,
+ 0xc2f7003c, 0xc2f7003b, 0xc2f70039, 0xc2f70037,
+ 0xc1f70044, 0xc1f70042, 0xc1f70040, 0xc1f7003e,
+ 0xc1f7003c, 0xc1f7003b, 0xc1f70039, 0xc1f70037,
+ 0xc0f70044, 0xc0f70042, 0xc0f70040, 0xc0f7003e,
+ 0xc0f7003c, 0xc0f7003b, 0xc0f70039, 0xc0f70037
+};
+
+static u32 nphy_tpc_5GHz_txgain_rev4[] = {
+ 0x2ff20044, 0x2ff20042, 0x2ff20040, 0x2ff2003e,
+ 0x2ff2003c, 0x2ff2003b, 0x2ff20039, 0x2ff20037,
+ 0x2ef20044, 0x2ef20042, 0x2ef20040, 0x2ef2003e,
+ 0x2ef2003c, 0x2ef2003b, 0x2ef20039, 0x2ef20037,
+ 0x2df20044, 0x2df20042, 0x2df20040, 0x2df2003e,
+ 0x2df2003c, 0x2df2003b, 0x2df20039, 0x2df20037,
+ 0x2cf20044, 0x2cf20042, 0x2cf20040, 0x2cf2003e,
+ 0x2cf2003c, 0x2cf2003b, 0x2cf20039, 0x2cf20037,
+ 0x2bf20044, 0x2bf20042, 0x2bf20040, 0x2bf2003e,
+ 0x2bf2003c, 0x2bf2003b, 0x2bf20039, 0x2bf20037,
+ 0x2af20044, 0x2af20042, 0x2af20040, 0x2af2003e,
+ 0x2af2003c, 0x2af2003b, 0x2af20039, 0x2af20037,
+ 0x29f20044, 0x29f20042, 0x29f20040, 0x29f2003e,
+ 0x29f2003c, 0x29f2003b, 0x29f20039, 0x29f20037,
+ 0x28f20044, 0x28f20042, 0x28f20040, 0x28f2003e,
+ 0x28f2003c, 0x28f2003b, 0x28f20039, 0x28f20037,
+ 0x27f20044, 0x27f20042, 0x27f20040, 0x27f2003e,
+ 0x27f2003c, 0x27f2003b, 0x27f20039, 0x27f20037,
+ 0x26f20044, 0x26f20042, 0x26f20040, 0x26f2003e,
+ 0x26f2003c, 0x26f2003b, 0x26f20039, 0x26f20037,
+ 0x25f20044, 0x25f20042, 0x25f20040, 0x25f2003e,
+ 0x25f2003c, 0x25f2003b, 0x25f20039, 0x25f20037,
+ 0x24f20044, 0x24f20042, 0x24f20040, 0x24f2003e,
+ 0x24f2003c, 0x24f2003b, 0x24f20039, 0x24f20038,
+ 0x23f20041, 0x23f20040, 0x23f2003f, 0x23f2003e,
+ 0x23f2003c, 0x23f2003b, 0x23f20039, 0x23f20037,
+ 0x22f20044, 0x22f20042, 0x22f20040, 0x22f2003e,
+ 0x22f2003c, 0x22f2003b, 0x22f20039, 0x22f20037,
+ 0x21f20044, 0x21f20042, 0x21f20040, 0x21f2003e,
+ 0x21f2003c, 0x21f2003b, 0x21f20039, 0x21f20037,
+ 0x20d20043, 0x20d20041, 0x20d2003e, 0x20d2003c,
+ 0x20d2003a, 0x20d20038, 0x20d20036, 0x20d20034
+};
+
+static u32 nphy_tpc_5GHz_txgain_rev5[] = {
+ 0x0f62004a, 0x0f620048, 0x0f620046, 0x0f620044,
+ 0x0f620042, 0x0f620040, 0x0f62003e, 0x0f62003c,
+ 0x0e620044, 0x0e620042, 0x0e620040, 0x0e62003e,
+ 0x0e62003c, 0x0e62003d, 0x0e62003b, 0x0e62003a,
+ 0x0d620043, 0x0d620041, 0x0d620040, 0x0d62003e,
+ 0x0d62003d, 0x0d62003c, 0x0d62003b, 0x0d62003a,
+ 0x0c620041, 0x0c620040, 0x0c62003f, 0x0c62003e,
+ 0x0c62003c, 0x0c62003b, 0x0c620039, 0x0c620037,
+ 0x0b620046, 0x0b620044, 0x0b620042, 0x0b620040,
+ 0x0b62003e, 0x0b62003c, 0x0b62003b, 0x0b62003a,
+ 0x0a620041, 0x0a620040, 0x0a62003e, 0x0a62003c,
+ 0x0a62003b, 0x0a62003a, 0x0a620039, 0x0a620038,
+ 0x0962003e, 0x0962003d, 0x0962003c, 0x0962003b,
+ 0x09620039, 0x09620037, 0x09620035, 0x09620033,
+ 0x08620044, 0x08620042, 0x08620040, 0x0862003e,
+ 0x0862003c, 0x0862003b, 0x0862003a, 0x08620039,
+ 0x07620043, 0x07620042, 0x07620040, 0x0762003f,
+ 0x0762003d, 0x0762003b, 0x0762003a, 0x07620039,
+ 0x0662003e, 0x0662003d, 0x0662003c, 0x0662003b,
+ 0x06620039, 0x06620037, 0x06620035, 0x06620033,
+ 0x05620046, 0x05620044, 0x05620042, 0x05620040,
+ 0x0562003e, 0x0562003c, 0x0562003b, 0x05620039,
+ 0x04620044, 0x04620042, 0x04620040, 0x0462003e,
+ 0x0462003c, 0x0462003b, 0x04620039, 0x04620038,
+ 0x0362003c, 0x0362003b, 0x0362003a, 0x03620039,
+ 0x03620038, 0x03620037, 0x03620035, 0x03620033,
+ 0x0262004c, 0x0262004a, 0x02620048, 0x02620047,
+ 0x02620046, 0x02620044, 0x02620043, 0x02620042,
+ 0x0162004a, 0x01620048, 0x01620046, 0x01620044,
+ 0x01620043, 0x01620042, 0x01620041, 0x01620040,
+ 0x00620042, 0x00620040, 0x0062003e, 0x0062003c,
+ 0x0062003b, 0x00620039, 0x00620037, 0x00620035
+};
+
+static u32 nphy_tpc_5GHz_txgain_HiPwrEPA[] = {
+ 0x2ff10044, 0x2ff10042, 0x2ff10040, 0x2ff1003e,
+ 0x2ff1003c, 0x2ff1003b, 0x2ff10039, 0x2ff10037,
+ 0x2ef10044, 0x2ef10042, 0x2ef10040, 0x2ef1003e,
+ 0x2ef1003c, 0x2ef1003b, 0x2ef10039, 0x2ef10037,
+ 0x2df10044, 0x2df10042, 0x2df10040, 0x2df1003e,
+ 0x2df1003c, 0x2df1003b, 0x2df10039, 0x2df10037,
+ 0x2cf10044, 0x2cf10042, 0x2cf10040, 0x2cf1003e,
+ 0x2cf1003c, 0x2cf1003b, 0x2cf10039, 0x2cf10037,
+ 0x2bf10044, 0x2bf10042, 0x2bf10040, 0x2bf1003e,
+ 0x2bf1003c, 0x2bf1003b, 0x2bf10039, 0x2bf10037,
+ 0x2af10044, 0x2af10042, 0x2af10040, 0x2af1003e,
+ 0x2af1003c, 0x2af1003b, 0x2af10039, 0x2af10037,
+ 0x29f10044, 0x29f10042, 0x29f10040, 0x29f1003e,
+ 0x29f1003c, 0x29f1003b, 0x29f10039, 0x29f10037,
+ 0x28f10044, 0x28f10042, 0x28f10040, 0x28f1003e,
+ 0x28f1003c, 0x28f1003b, 0x28f10039, 0x28f10037,
+ 0x27f10044, 0x27f10042, 0x27f10040, 0x27f1003e,
+ 0x27f1003c, 0x27f1003b, 0x27f10039, 0x27f10037,
+ 0x26f10044, 0x26f10042, 0x26f10040, 0x26f1003e,
+ 0x26f1003c, 0x26f1003b, 0x26f10039, 0x26f10037,
+ 0x25f10044, 0x25f10042, 0x25f10040, 0x25f1003e,
+ 0x25f1003c, 0x25f1003b, 0x25f10039, 0x25f10037,
+ 0x24f10044, 0x24f10042, 0x24f10040, 0x24f1003e,
+ 0x24f1003c, 0x24f1003b, 0x24f10039, 0x24f10038,
+ 0x23f10041, 0x23f10040, 0x23f1003f, 0x23f1003e,
+ 0x23f1003c, 0x23f1003b, 0x23f10039, 0x23f10037,
+ 0x22f10044, 0x22f10042, 0x22f10040, 0x22f1003e,
+ 0x22f1003c, 0x22f1003b, 0x22f10039, 0x22f10037,
+ 0x21f10044, 0x21f10042, 0x21f10040, 0x21f1003e,
+ 0x21f1003c, 0x21f1003b, 0x21f10039, 0x21f10037,
+ 0x20d10043, 0x20d10041, 0x20d1003e, 0x20d1003c,
+ 0x20d1003a, 0x20d10038, 0x20d10036, 0x20d10034
+};
+
+static u8 ant_sw_ctrl_tbl_rev8_2o3[] = { 0x14, 0x18 };
+static u8 ant_sw_ctrl_tbl_rev8[] = { 0x4, 0x8, 0x4, 0x8, 0x11, 0x12 };
+static u8 ant_sw_ctrl_tbl_rev8_2057v7_core0[] = {
+ 0x09, 0x0a, 0x15, 0x16, 0x09, 0x0a
+};
+static u8 ant_sw_ctrl_tbl_rev8_2057v7_core1[] = {
+ 0x09, 0x0a, 0x09, 0x0a, 0x15, 0x16
+};
+
+bool wlc_phy_bist_check_phy(struct brcms_phy_pub *pih)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+ u32 phybist0, phybist1, phybist2, phybist3, phybist4;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 16))
+ return true;
+
+ phybist0 = read_phy_reg(pi, 0x0e);
+ phybist1 = read_phy_reg(pi, 0x0f);
+ phybist2 = read_phy_reg(pi, 0xea);
+ phybist3 = read_phy_reg(pi, 0xeb);
+ phybist4 = read_phy_reg(pi, 0x156);
+
+ if ((phybist0 == 0) && (phybist1 == 0x4000) && (phybist2 == 0x1fe0) &&
+ (phybist3 == 0) && (phybist4 == 0))
+ return true;
+
+ return false;
+}
+
+static void wlc_phy_bphy_init_nphy(struct brcms_phy *pi)
+{
+ u16 addr, val;
+
+ val = 0x1e1f;
+ for (addr = (NPHY_TO_BPHY_OFF + BPHY_RSSI_LUT);
+ addr <= (NPHY_TO_BPHY_OFF + BPHY_RSSI_LUT_END); addr++) {
+ write_phy_reg(pi, addr, val);
+ if (addr == (NPHY_TO_BPHY_OFF + 0x97))
+ val = 0x3e3f;
+ else
+ val -= 0x0202;
+ }
+
+ write_phy_reg(pi, NPHY_TO_BPHY_OFF + BPHY_STEP, 0x668);
+}
+
+void
+wlc_phy_table_write_nphy(struct brcms_phy *pi, u32 id, u32 len, u32 offset,
+ u32 width, const void *data)
+{
+ struct phytbl_info tbl;
+
+ tbl.tbl_id = id;
+ tbl.tbl_len = len;
+ tbl.tbl_offset = offset;
+ tbl.tbl_width = width;
+ tbl.tbl_ptr = data;
+ wlc_phy_write_table_nphy(pi, &tbl);
+}
+
+void
+wlc_phy_table_read_nphy(struct brcms_phy *pi, u32 id, u32 len, u32 offset,
+ u32 width, void *data)
+{
+ struct phytbl_info tbl;
+
+ tbl.tbl_id = id;
+ tbl.tbl_len = len;
+ tbl.tbl_offset = offset;
+ tbl.tbl_width = width;
+ tbl.tbl_ptr = data;
+ wlc_phy_read_table_nphy(pi, &tbl);
+}
+
+static void
+wlc_phy_static_table_download_nphy(struct brcms_phy *pi)
+{
+ uint idx;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 16)) {
+ for (idx = 0; idx < mimophytbl_info_sz_rev16; idx++)
+ wlc_phy_write_table_nphy(pi,
+ &mimophytbl_info_rev16[idx]);
+ } else if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ for (idx = 0; idx < mimophytbl_info_sz_rev7; idx++)
+ wlc_phy_write_table_nphy(pi,
+ &mimophytbl_info_rev7[idx]);
+ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ for (idx = 0; idx < mimophytbl_info_sz_rev3; idx++)
+ wlc_phy_write_table_nphy(pi,
+ &mimophytbl_info_rev3[idx]);
+ } else {
+ for (idx = 0; idx < mimophytbl_info_sz_rev0; idx++)
+ wlc_phy_write_table_nphy(pi,
+ &mimophytbl_info_rev0[idx]);
+ }
+}
+
+static void wlc_phy_tbl_init_nphy(struct brcms_phy *pi)
+{
+ uint idx = 0;
+ u8 antswctrllut;
+
+ if (pi->phy_init_por)
+ wlc_phy_static_table_download_nphy(pi);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ antswctrllut = CHSPEC_IS2G(pi->radio_chanspec) ?
+ pi->srom_fem2g.antswctrllut : pi->srom_fem5g.
+ antswctrllut;
+
+ switch (antswctrllut) {
+ case 0:
+
+ break;
+
+ case 1:
+
+ if (pi->aa2g == 7)
+ wlc_phy_table_write_nphy(
+ pi,
+ NPHY_TBL_ID_ANTSWCTRLLUT,
+ 2, 0x21, 8,
+ &ant_sw_ctrl_tbl_rev8_2o3[0]);
+ else
+ wlc_phy_table_write_nphy(
+ pi,
+ NPHY_TBL_ID_ANTSWCTRLLUT,
+ 2, 0x21, 8,
+ &ant_sw_ctrl_tbl_rev8
+ [0]);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT,
+ 2, 0x25, 8,
+ &ant_sw_ctrl_tbl_rev8[2]);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT,
+ 2, 0x29, 8,
+ &ant_sw_ctrl_tbl_rev8[4]);
+ break;
+
+ case 2:
+
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_ANTSWCTRLLUT,
+ 2, 0x1, 8,
+ &ant_sw_ctrl_tbl_rev8_2057v7_core0[0]);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_ANTSWCTRLLUT,
+ 2, 0x5, 8,
+ &ant_sw_ctrl_tbl_rev8_2057v7_core0[2]);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_ANTSWCTRLLUT,
+ 2, 0x9, 8,
+ &ant_sw_ctrl_tbl_rev8_2057v7_core0[4]);
+
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_ANTSWCTRLLUT,
+ 2, 0x21, 8,
+ &ant_sw_ctrl_tbl_rev8_2057v7_core1[0]);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_ANTSWCTRLLUT,
+ 2, 0x25, 8,
+ &ant_sw_ctrl_tbl_rev8_2057v7_core1[2]);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_ANTSWCTRLLUT,
+ 2, 0x29, 8,
+ &ant_sw_ctrl_tbl_rev8_2057v7_core1[4]);
+ break;
+
+ default:
+ break;
+ }
+
+ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ for (idx = 0; idx < mimophytbl_info_sz_rev3_volatile; idx++) {
+
+ if (idx == ANT_SWCTRL_TBL_REV3_IDX) {
+ antswctrllut =
+ CHSPEC_IS2G(pi->radio_chanspec) ?
+ pi->srom_fem2g.antswctrllut :
+ pi->srom_fem5g.antswctrllut;
+ switch (antswctrllut) {
+ case 0:
+ wlc_phy_write_table_nphy(
+ pi,
+ &mimophytbl_info_rev3_volatile
+ [idx]);
+ break;
+ case 1:
+ wlc_phy_write_table_nphy(
+ pi,
+ &mimophytbl_info_rev3_volatile1
+ [idx]);
+ break;
+ case 2:
+ wlc_phy_write_table_nphy(
+ pi,
+ &mimophytbl_info_rev3_volatile2
+ [idx]);
+ break;
+ case 3:
+ wlc_phy_write_table_nphy(
+ pi,
+ &mimophytbl_info_rev3_volatile3
+ [idx]);
+ break;
+ default:
+ break;
+ }
+ } else {
+ wlc_phy_write_table_nphy(
+ pi,
+ &mimophytbl_info_rev3_volatile[idx]);
+ }
+ }
+ } else {
+ for (idx = 0; idx < mimophytbl_info_sz_rev0_volatile; idx++)
+ wlc_phy_write_table_nphy(pi,
+ &mimophytbl_info_rev0_volatile
+ [idx]);
+ }
+}
+
+static void
+wlc_phy_write_txmacreg_nphy(struct brcms_phy *pi, u16 holdoff, u16 delay)
+{
+ write_phy_reg(pi, 0x77, holdoff);
+ write_phy_reg(pi, 0xb4, delay);
+}
+
+void wlc_phy_nphy_tkip_rifs_war(struct brcms_phy *pi, u8 rifs)
+{
+ u16 holdoff, delay;
+
+ if (rifs) {
+
+ holdoff = 0x10;
+ delay = 0x258;
+ } else {
+
+ holdoff = 0x15;
+ delay = 0x320;
+ }
+
+ wlc_phy_write_txmacreg_nphy(pi, holdoff, delay);
+
+ if (pi && pi->sh && (pi->sh->_rifs_phy != rifs))
+ pi->sh->_rifs_phy = rifs;
+}
+
+static void wlc_phy_txpwrctrl_config_nphy(struct brcms_phy *pi)
+{
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ pi->nphy_txpwrctrl = PHY_TPC_HW_ON;
+ pi->phy_5g_pwrgain = true;
+ return;
+ }
+
+ pi->nphy_txpwrctrl = PHY_TPC_HW_OFF;
+ pi->phy_5g_pwrgain = false;
+
+ if ((pi->sh->boardflags2 & BFL2_TXPWRCTRL_EN) &&
+ NREV_GE(pi->pubpi.phy_rev, 2) && (pi->sh->sromrev >= 4))
+ pi->nphy_txpwrctrl = PHY_TPC_HW_ON;
+ else if ((pi->sh->sromrev >= 4)
+ && (pi->sh->boardflags2 & BFL2_5G_PWRGAIN))
+ pi->phy_5g_pwrgain = true;
+}
+
+static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
+{
+ u16 bw40po, cddpo, stbcpo, bwduppo;
+ uint band_num;
+ struct phy_shim_info *shim = pi->sh->physhim;
+
+ if (pi->sh->sromrev >= 9)
+ return;
+
+ bw40po = (u16) wlapi_getintvar(shim, BRCMS_SROM_BW40PO);
+ pi->bw402gpo = bw40po & 0xf;
+ pi->bw405gpo = (bw40po & 0xf0) >> 4;
+ pi->bw405glpo = (bw40po & 0xf00) >> 8;
+ pi->bw405ghpo = (bw40po & 0xf000) >> 12;
+
+ cddpo = (u16) wlapi_getintvar(shim, BRCMS_SROM_CDDPO);
+ pi->cdd2gpo = cddpo & 0xf;
+ pi->cdd5gpo = (cddpo & 0xf0) >> 4;
+ pi->cdd5glpo = (cddpo & 0xf00) >> 8;
+ pi->cdd5ghpo = (cddpo & 0xf000) >> 12;
+
+ stbcpo = (u16) wlapi_getintvar(shim, BRCMS_SROM_STBCPO);
+ pi->stbc2gpo = stbcpo & 0xf;
+ pi->stbc5gpo = (stbcpo & 0xf0) >> 4;
+ pi->stbc5glpo = (stbcpo & 0xf00) >> 8;
+ pi->stbc5ghpo = (stbcpo & 0xf000) >> 12;
+
+ bwduppo = (u16) wlapi_getintvar(shim, BRCMS_SROM_BWDUPPO);
+ pi->bwdup2gpo = bwduppo & 0xf;
+ pi->bwdup5gpo = (bwduppo & 0xf0) >> 4;
+ pi->bwdup5glpo = (bwduppo & 0xf00) >> 8;
+ pi->bwdup5ghpo = (bwduppo & 0xf000) >> 12;
+
+ for (band_num = 0; band_num < (CH_2G_GROUP + CH_5G_GROUP);
+ band_num++) {
+ switch (band_num) {
+ case 0:
+
+ pi->nphy_txpid2g[PHY_CORE_0] =
+ (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_TXPID2GA0);
+ pi->nphy_txpid2g[PHY_CORE_1] =
+ (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_TXPID2GA1);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_2g =
+ (s8) wlapi_getintvar(shim,
+ BRCMS_SROM_MAXP2GA0);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].max_pwr_2g =
+ (s8) wlapi_getintvar(shim,
+ BRCMS_SROM_MAXP2GA1);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_a1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA2GW0A0);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_a1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA2GW0A1);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_b0 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA2GW1A0);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_b0 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA2GW1A1);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_b1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA2GW2A0);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_b1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA2GW2A1);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].idle_targ_2g =
+ (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT2GA0);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].idle_targ_2g =
+ (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT2GA1);
+
+ pi->cck2gpo = (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_CCK2GPO);
+
+ pi->ofdm2gpo =
+ (u32) wlapi_getintvar(shim,
+ BRCMS_SROM_OFDM2GPO);
+
+ pi->mcs2gpo[0] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS2GPO0);
+ pi->mcs2gpo[1] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS2GPO1);
+ pi->mcs2gpo[2] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS2GPO2);
+ pi->mcs2gpo[3] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS2GPO3);
+ pi->mcs2gpo[4] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS2GPO4);
+ pi->mcs2gpo[5] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS2GPO5);
+ pi->mcs2gpo[6] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS2GPO6);
+ pi->mcs2gpo[7] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS2GPO7);
+ break;
+ case 1:
+
+ pi->nphy_txpid5g[PHY_CORE_0] =
+ (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_TXPID5GA0);
+ pi->nphy_txpid5g[PHY_CORE_1] =
+ (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_TXPID5GA1);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_5gm =
+ (s8) wlapi_getintvar(shim, BRCMS_SROM_MAXP5GA0);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].max_pwr_5gm =
+ (s8) wlapi_getintvar(shim,
+ BRCMS_SROM_MAXP5GA1);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_a1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GW0A0);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_a1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GW0A1);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_b0 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GW1A0);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_b0 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GW1A1);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_b1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GW2A0);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_b1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GW2A1);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].idle_targ_5gm =
+ (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT5GA0);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].idle_targ_5gm =
+ (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT5GA1);
+
+ pi->ofdm5gpo =
+ (u32) wlapi_getintvar(shim,
+ BRCMS_SROM_OFDM5GPO);
+
+ pi->mcs5gpo[0] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GPO0);
+ pi->mcs5gpo[1] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GPO1);
+ pi->mcs5gpo[2] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GPO2);
+ pi->mcs5gpo[3] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GPO3);
+ pi->mcs5gpo[4] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GPO4);
+ pi->mcs5gpo[5] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GPO5);
+ pi->mcs5gpo[6] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GPO6);
+ pi->mcs5gpo[7] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GPO7);
+ break;
+ case 2:
+
+ pi->nphy_txpid5gl[0] =
+ (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_TXPID5GLA0);
+ pi->nphy_txpid5gl[1] =
+ (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_TXPID5GLA1);
+ pi->nphy_pwrctrl_info[0].max_pwr_5gl =
+ (s8) wlapi_getintvar(shim,
+ BRCMS_SROM_MAXP5GLA0);
+ pi->nphy_pwrctrl_info[1].max_pwr_5gl =
+ (s8) wlapi_getintvar(shim,
+ BRCMS_SROM_MAXP5GLA1);
+ pi->nphy_pwrctrl_info[0].pwrdet_5gl_a1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GLW0A0);
+ pi->nphy_pwrctrl_info[1].pwrdet_5gl_a1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GLW0A1);
+ pi->nphy_pwrctrl_info[0].pwrdet_5gl_b0 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GLW1A0);
+ pi->nphy_pwrctrl_info[1].pwrdet_5gl_b0 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GLW1A1);
+ pi->nphy_pwrctrl_info[0].pwrdet_5gl_b1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GLW2A0);
+ pi->nphy_pwrctrl_info[1].pwrdet_5gl_b1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GLW2A1);
+ pi->nphy_pwrctrl_info[0].idle_targ_5gl = 0;
+ pi->nphy_pwrctrl_info[1].idle_targ_5gl = 0;
+
+ pi->ofdm5glpo =
+ (u32) wlapi_getintvar(shim,
+ BRCMS_SROM_OFDM5GLPO);
+
+ pi->mcs5glpo[0] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GLPO0);
+ pi->mcs5glpo[1] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GLPO1);
+ pi->mcs5glpo[2] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GLPO2);
+ pi->mcs5glpo[3] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GLPO3);
+ pi->mcs5glpo[4] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GLPO4);
+ pi->mcs5glpo[5] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GLPO5);
+ pi->mcs5glpo[6] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GLPO6);
+ pi->mcs5glpo[7] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GLPO7);
+ break;
+ case 3:
+
+ pi->nphy_txpid5gh[0] =
+ (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_TXPID5GHA0);
+ pi->nphy_txpid5gh[1] =
+ (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_TXPID5GHA1);
+ pi->nphy_pwrctrl_info[0].max_pwr_5gh =
+ (s8) wlapi_getintvar(shim,
+ BRCMS_SROM_MAXP5GHA0);
+ pi->nphy_pwrctrl_info[1].max_pwr_5gh =
+ (s8) wlapi_getintvar(shim,
+ BRCMS_SROM_MAXP5GHA1);
+ pi->nphy_pwrctrl_info[0].pwrdet_5gh_a1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GHW0A0);
+ pi->nphy_pwrctrl_info[1].pwrdet_5gh_a1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GHW0A1);
+ pi->nphy_pwrctrl_info[0].pwrdet_5gh_b0 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GHW1A0);
+ pi->nphy_pwrctrl_info[1].pwrdet_5gh_b0 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GHW1A1);
+ pi->nphy_pwrctrl_info[0].pwrdet_5gh_b1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GHW2A0);
+ pi->nphy_pwrctrl_info[1].pwrdet_5gh_b1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GHW2A1);
+ pi->nphy_pwrctrl_info[0].idle_targ_5gh = 0;
+ pi->nphy_pwrctrl_info[1].idle_targ_5gh = 0;
+
+ pi->ofdm5ghpo =
+ (u32) wlapi_getintvar(shim,
+ BRCMS_SROM_OFDM5GHPO);
+
+ pi->mcs5ghpo[0] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GHPO0);
+ pi->mcs5ghpo[1] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GHPO1);
+ pi->mcs5ghpo[2] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GHPO2);
+ pi->mcs5ghpo[3] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GHPO3);
+ pi->mcs5ghpo[4] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GHPO4);
+ pi->mcs5ghpo[5] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GHPO5);
+ pi->mcs5ghpo[6] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GHPO6);
+ pi->mcs5ghpo[7] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GHPO7);
+ break;
+ }
+ }
+
+ wlc_phy_txpwr_apply_nphy(pi);
+}
+
+static bool wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi)
+{
+ struct phy_shim_info *shim = pi->sh->physhim;
+
+ pi->antswitch = (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWITCH);
+ pi->aa2g = (u8) wlapi_getintvar(shim, BRCMS_SROM_AA2G);
+ pi->aa5g = (u8) wlapi_getintvar(shim, BRCMS_SROM_AA5G);
+
+ pi->srom_fem2g.tssipos = (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_TSSIPOS2G);
+ pi->srom_fem2g.extpagain = (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_EXTPAGAIN2G);
+ pi->srom_fem2g.pdetrange = (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_PDETRANGE2G);
+ pi->srom_fem2g.triso = (u8) wlapi_getintvar(shim, BRCMS_SROM_TRISO2G);
+ pi->srom_fem2g.antswctrllut =
+ (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL2G);
+
+ pi->srom_fem5g.tssipos = (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_TSSIPOS5G);
+ pi->srom_fem5g.extpagain = (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_EXTPAGAIN5G);
+ pi->srom_fem5g.pdetrange = (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_PDETRANGE5G);
+ pi->srom_fem5g.triso = (u8) wlapi_getintvar(shim, BRCMS_SROM_TRISO5G);
+ if (wlapi_getvar(shim, BRCMS_SROM_ANTSWCTL5G))
+ pi->srom_fem5g.antswctrllut =
+ (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL5G);
+ else
+ pi->srom_fem5g.antswctrllut =
+ (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL2G);
+
+ wlc_phy_txpower_ipa_upd(pi);
+
+ pi->phy_txcore_disable_temp =
+ (s16) wlapi_getintvar(shim, BRCMS_SROM_TEMPTHRESH);
+ if (pi->phy_txcore_disable_temp == 0)
+ pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
+
+ pi->phy_tempsense_offset = (s8) wlapi_getintvar(shim,
+ BRCMS_SROM_TEMPOFFSET);
+ if (pi->phy_tempsense_offset != 0) {
+ if (pi->phy_tempsense_offset >
+ (NPHY_SROM_TEMPSHIFT + NPHY_SROM_MAXTEMPOFFSET))
+ pi->phy_tempsense_offset = NPHY_SROM_MAXTEMPOFFSET;
+ else if (pi->phy_tempsense_offset < (NPHY_SROM_TEMPSHIFT +
+ NPHY_SROM_MINTEMPOFFSET))
+ pi->phy_tempsense_offset = NPHY_SROM_MINTEMPOFFSET;
+ else
+ pi->phy_tempsense_offset -= NPHY_SROM_TEMPSHIFT;
+ }
+
+ pi->phy_txcore_enable_temp =
+ pi->phy_txcore_disable_temp - PHY_HYSTERESIS_DELTATEMP;
+
+ pi->phycal_tempdelta =
+ (u8) wlapi_getintvar(shim, BRCMS_SROM_PHYCAL_TEMPDELTA);
+ if (pi->phycal_tempdelta > NPHY_CAL_MAXTEMPDELTA)
+ pi->phycal_tempdelta = 0;
+
+ wlc_phy_txpwr_srom_read_ppr_nphy(pi);
+
+ return true;
+}
+
+bool wlc_phy_attach_nphy(struct brcms_phy *pi)
+{
+ uint i;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 6))
+ pi->phyhang_avoid = true;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 7)) {
+ pi->nphy_gband_spurwar_en = true;
+ if (pi->sh->boardflags2 & BFL2_SPUR_WAR)
+ pi->nphy_aband_spurwar_en = true;
+ }
+ if (NREV_GE(pi->pubpi.phy_rev, 6) && NREV_LT(pi->pubpi.phy_rev, 7)) {
+ if (pi->sh->boardflags2 & BFL2_2G_SPUR_WAR)
+ pi->nphy_gband_spurwar2_en = true;
+ }
+
+ pi->n_preamble_override = AUTO;
+ if (NREV_IS(pi->pubpi.phy_rev, 3) || NREV_IS(pi->pubpi.phy_rev, 4))
+ pi->n_preamble_override = BRCMS_N_PREAMBLE_MIXEDMODE;
+
+ pi->nphy_txrx_chain = AUTO;
+ pi->phy_scraminit = AUTO;
+
+ pi->nphy_rxcalparams = 0x010100B5;
+
+ pi->nphy_perical = PHY_PERICAL_MPHASE;
+ pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE;
+ pi->mphase_txcal_numcmds = MPHASE_TXCAL_NUMCMDS;
+
+ pi->nphy_gain_boost = true;
+ pi->nphy_elna_gain_config = false;
+ pi->radio_is_on = false;
+
+ for (i = 0; i < pi->pubpi.phy_corenum; i++)
+ pi->nphy_txpwrindex[i].index = AUTO;
+
+ wlc_phy_txpwrctrl_config_nphy(pi);
+ if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON)
+ pi->hwpwrctrl_capable = true;
+
+ pi->pi_fptr.init = wlc_phy_init_nphy;
+ pi->pi_fptr.calinit = wlc_phy_cal_init_nphy;
+ pi->pi_fptr.chanset = wlc_phy_chanspec_set_nphy;
+ pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_nphy;
+
+ if (!wlc_phy_txpwr_srom_read_nphy(pi))
+ return false;
+
+ return true;
+}
+
+static s32 get_rf_pwr_offset(struct brcms_phy *pi, s16 pga_gn, s16 pad_gn)
+{
+ s32 rfpwr_offset = 0;
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if ((pi->pubpi.radiorev == 3) ||
+ (pi->pubpi.radiorev == 4) ||
+ (pi->pubpi.radiorev == 6))
+ rfpwr_offset = (s16)
+ nphy_papd_padgain_dlt_2g_2057rev3n4
+ [pad_gn];
+ else if (pi->pubpi.radiorev == 5)
+ rfpwr_offset = (s16)
+ nphy_papd_padgain_dlt_2g_2057rev5
+ [pad_gn];
+ else if ((pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev ==
+ 8))
+ rfpwr_offset = (s16)
+ nphy_papd_padgain_dlt_2g_2057rev7
+ [pad_gn];
+ } else {
+ if ((pi->pubpi.radiorev == 3) ||
+ (pi->pubpi.radiorev == 4) ||
+ (pi->pubpi.radiorev == 6))
+ rfpwr_offset = (s16)
+ nphy_papd_pgagain_dlt_5g_2057
+ [pga_gn];
+ else if ((pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev ==
+ 8))
+ rfpwr_offset = (s16)
+ nphy_papd_pgagain_dlt_5g_2057rev7
+ [pga_gn];
+ }
+ return rfpwr_offset;
+}
+
+static void wlc_phy_update_mimoconfig_nphy(struct brcms_phy *pi, s32 preamble)
+{
+ bool gf_preamble = false;
+ u16 val;
+
+ if (preamble == BRCMS_N_PREAMBLE_GF)
+ gf_preamble = true;
+
+ val = read_phy_reg(pi, 0xed);
+
+ val |= RX_GF_MM_AUTO;
+ val &= ~RX_GF_OR_MM;
+ if (gf_preamble)
+ val |= RX_GF_OR_MM;
+
+ write_phy_reg(pi, 0xed, val);
+}
+
+static void wlc_phy_ipa_set_tx_digi_filts_nphy(struct brcms_phy *pi)
+{
+ int j, type;
+ u16 addr_offset[] = { 0x186, 0x195, 0x2c5};
+
+ for (type = 0; type < 3; type++) {
+ for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++)
+ write_phy_reg(pi, addr_offset[type] + j,
+ NPHY_IPA_REV4_txdigi_filtcoeffs[type][j]);
+ }
+
+ if (pi->bw == WL_CHANSPEC_BW_40) {
+ for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++)
+ write_phy_reg(pi, 0x186 + j,
+ NPHY_IPA_REV4_txdigi_filtcoeffs[3][j]);
+ } else {
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++)
+ write_phy_reg(pi, 0x186 + j,
+ NPHY_IPA_REV4_txdigi_filtcoeffs[5][j]);
+ }
+
+ if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) {
+ for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++)
+ write_phy_reg(pi, 0x2c5 + j,
+ NPHY_IPA_REV4_txdigi_filtcoeffs[6][j]);
+ }
+ }
+}
+
+static void wlc_phy_ipa_restore_tx_digi_filts_nphy(struct brcms_phy *pi)
+{
+ int j;
+
+ if (pi->bw == WL_CHANSPEC_BW_40) {
+ for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++)
+ write_phy_reg(pi, 0x195 + j,
+ NPHY_IPA_REV4_txdigi_filtcoeffs[4][j]);
+ } else {
+ for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++)
+ write_phy_reg(pi, 0x186 + j,
+ NPHY_IPA_REV4_txdigi_filtcoeffs[3][j]);
+ }
+}
+
+static void
+wlc_phy_set_rfseq_nphy(struct brcms_phy *pi, u8 cmd, u8 *events, u8 *dlys,
+ u8 len)
+{
+ u32 t1_offset, t2_offset;
+ u8 ctr;
+ u8 end_event =
+ NREV_GE(pi->pubpi.phy_rev,
+ 3) ? NPHY_REV3_RFSEQ_CMD_END : NPHY_RFSEQ_CMD_END;
+ u8 end_dly = 1;
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ t1_offset = cmd << 4;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, len, t1_offset, 8,
+ events);
+ t2_offset = t1_offset + 0x080;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, len, t2_offset, 8,
+ dlys);
+
+ for (ctr = len; ctr < 16; ctr++) {
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 1,
+ t1_offset + ctr, 8, &end_event);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 1,
+ t2_offset + ctr, 8, &end_dly);
+ }
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+}
+
+static u16 wlc_phy_read_lpf_bw_ctl_nphy(struct brcms_phy *pi, u16 offset)
+{
+ u16 lpf_bw_ctl_val = 0;
+ u16 rx2tx_lpf_rc_lut_offset = 0;
+
+ if (offset == 0) {
+ if (CHSPEC_IS40(pi->radio_chanspec))
+ rx2tx_lpf_rc_lut_offset = 0x159;
+ else
+ rx2tx_lpf_rc_lut_offset = 0x154;
+ } else {
+ rx2tx_lpf_rc_lut_offset = offset;
+ }
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 1,
+ (u32) rx2tx_lpf_rc_lut_offset, 16,
+ &lpf_bw_ctl_val);
+
+ lpf_bw_ctl_val = lpf_bw_ctl_val & 0x7;
+
+ return lpf_bw_ctl_val;
+}
+
+static void
+wlc_phy_rfctrl_override_nphy_rev7(struct brcms_phy *pi, u16 field, u16 value,
+ u8 core_mask, u8 off, u8 override_id)
+{
+ u8 core_num;
+ u16 addr = 0, en_addr = 0, val_addr = 0, en_mask = 0, val_mask = 0;
+ u8 val_shift = 0;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ en_mask = field;
+ for (core_num = 0; core_num < 2; core_num++) {
+ if (override_id == NPHY_REV7_RFCTRLOVERRIDE_ID0) {
+
+ switch (field) {
+ case (0x1 << 2):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a :
+ 0x7d;
+ val_mask = (0x1 << 1);
+ val_shift = 1;
+ break;
+ case (0x1 << 3):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a :
+ 0x7d;
+ val_mask = (0x1 << 2);
+ val_shift = 2;
+ break;
+ case (0x1 << 4):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a :
+ 0x7d;
+ val_mask = (0x1 << 4);
+ val_shift = 4;
+ break;
+ case (0x1 << 5):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a :
+ 0x7d;
+ val_mask = (0x1 << 5);
+ val_shift = 5;
+ break;
+ case (0x1 << 6):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a :
+ 0x7d;
+ val_mask = (0x1 << 6);
+ val_shift = 6;
+ break;
+ case (0x1 << 7):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a :
+ 0x7d;
+ val_mask = (0x1 << 7);
+ val_shift = 7;
+ break;
+ case (0x1 << 10):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0xf8 :
+ 0xfa;
+ val_mask = (0x7 << 4);
+ val_shift = 4;
+ break;
+ case (0x1 << 11):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7b :
+ 0x7e;
+ val_mask = (0xffff << 0);
+ val_shift = 0;
+ break;
+ case (0x1 << 12):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7c :
+ 0x7f;
+ val_mask = (0xffff << 0);
+ val_shift = 0;
+ break;
+ case (0x3 << 13):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x348 :
+ 0x349;
+ val_mask = (0xff << 0);
+ val_shift = 0;
+ break;
+ case (0x1 << 13):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x348 :
+ 0x349;
+ val_mask = (0xf << 0);
+ val_shift = 0;
+ break;
+ default:
+ addr = 0xffff;
+ break;
+ }
+ } else if (override_id ==
+ NPHY_REV7_RFCTRLOVERRIDE_ID1) {
+
+ switch (field) {
+ case (0x1 << 1):
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x1 << 1);
+ val_shift = 1;
+ break;
+ case (0x1 << 3):
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x1 << 3);
+ val_shift = 3;
+ break;
+ case (0x1 << 5):
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x1 << 5);
+ val_shift = 5;
+ break;
+ case (0x1 << 4):
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x1 << 4);
+ val_shift = 4;
+ break;
+ case (0x1 << 2):
+
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x1 << 2);
+ val_shift = 2;
+ break;
+ case (0x1 << 7):
+
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x7 << 8);
+ val_shift = 8;
+ break;
+ case (0x1 << 11):
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x1 << 14);
+ val_shift = 14;
+ break;
+ case (0x1 << 10):
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x1 << 13);
+ val_shift = 13;
+ break;
+ case (0x1 << 9):
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x1 << 12);
+ val_shift = 12;
+ break;
+ case (0x1 << 8):
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x1 << 11);
+ val_shift = 11;
+ break;
+ case (0x1 << 6):
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x1 << 6);
+ val_shift = 6;
+ break;
+ case (0x1 << 0):
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x1 << 0);
+ val_shift = 0;
+ break;
+ default:
+ addr = 0xffff;
+ break;
+ }
+ } else if (override_id ==
+ NPHY_REV7_RFCTRLOVERRIDE_ID2) {
+
+ switch (field) {
+ case (0x1 << 3):
+ en_addr = (core_num == 0) ? 0x346 :
+ 0x347;
+ val_addr = (core_num == 0) ? 0x344 :
+ 0x345;
+ val_mask = (0x1 << 3);
+ val_shift = 3;
+ break;
+ case (0x1 << 1):
+ en_addr = (core_num == 0) ? 0x346 :
+ 0x347;
+ val_addr = (core_num == 0) ? 0x344 :
+ 0x345;
+ val_mask = (0x1 << 1);
+ val_shift = 1;
+ break;
+ case (0x1 << 0):
+ en_addr = (core_num == 0) ? 0x346 :
+ 0x347;
+ val_addr = (core_num == 0) ? 0x344 :
+ 0x345;
+ val_mask = (0x1 << 0);
+ val_shift = 0;
+ break;
+ case (0x1 << 2):
+ en_addr = (core_num == 0) ? 0x346 :
+ 0x347;
+ val_addr = (core_num == 0) ? 0x344 :
+ 0x345;
+ val_mask = (0x1 << 2);
+ val_shift = 2;
+ break;
+ case (0x1 << 4):
+ en_addr = (core_num == 0) ? 0x346 :
+ 0x347;
+ val_addr = (core_num == 0) ? 0x344 :
+ 0x345;
+ val_mask = (0x1 << 4);
+ val_shift = 4;
+ break;
+ default:
+ addr = 0xffff;
+ break;
+ }
+ }
+
+ if (off) {
+ and_phy_reg(pi, en_addr, ~en_mask);
+ and_phy_reg(pi, val_addr, ~val_mask);
+ } else {
+
+ if ((core_mask == 0)
+ || (core_mask & (1 << core_num))) {
+ or_phy_reg(pi, en_addr, en_mask);
+
+ if (addr != 0xffff)
+ mod_phy_reg(pi, val_addr,
+ val_mask,
+ (value <<
+ val_shift));
+ }
+ }
+ }
+ }
+}
+
+static void wlc_phy_adjust_lnagaintbl_nphy(struct brcms_phy *pi)
+{
+ uint core;
+ int ctr;
+ s16 gain_delta[2];
+ u8 curr_channel;
+ u16 minmax_gain[2];
+ u16 regval[4];
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ if (pi->nphy_gain_boost) {
+ if ((CHSPEC_IS2G(pi->radio_chanspec))) {
+
+ gain_delta[0] = 6;
+ gain_delta[1] = 6;
+ } else {
+
+ curr_channel = CHSPEC_CHANNEL(pi->radio_chanspec);
+ gain_delta[0] =
+ (s16)
+ PHY_HW_ROUND(((nphy_lnagain_est0[0] *
+ curr_channel) +
+ nphy_lnagain_est0[1]), 13);
+ gain_delta[1] =
+ (s16)
+ PHY_HW_ROUND(((nphy_lnagain_est1[0] *
+ curr_channel) +
+ nphy_lnagain_est1[1]), 13);
+ }
+ } else {
+
+ gain_delta[0] = 0;
+ gain_delta[1] = 0;
+ }
+
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+ if (pi->nphy_elna_gain_config) {
+
+ regval[0] = nphy_def_lnagains[2] + gain_delta[core];
+ regval[1] = nphy_def_lnagains[3] + gain_delta[core];
+ regval[2] = nphy_def_lnagains[3] + gain_delta[core];
+ regval[3] = nphy_def_lnagains[3] + gain_delta[core];
+ } else {
+ for (ctr = 0; ctr < 4; ctr++)
+ regval[ctr] =
+ nphy_def_lnagains[ctr] +
+ gain_delta[core];
+ }
+ wlc_phy_table_write_nphy(pi, core, 4, 8, 16, regval);
+
+ minmax_gain[core] =
+ (u16) (nphy_def_lnagains[2] + gain_delta[core] + 4);
+ }
+
+ mod_phy_reg(pi, 0x1e, (0xff << 0), (minmax_gain[0] << 0));
+ mod_phy_reg(pi, 0x34, (0xff << 0), (minmax_gain[1] << 0));
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+}
+
+static void
+wlc_phy_war_force_trsw_to_R_cliplo_nphy(struct brcms_phy *pi, u8 core)
+{
+ if (core == PHY_CORE_0) {
+ write_phy_reg(pi, 0x38, 0x4);
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ write_phy_reg(pi, 0x37, 0x0060);
+ else
+ write_phy_reg(pi, 0x37, 0x1080);
+ } else if (core == PHY_CORE_1) {
+ write_phy_reg(pi, 0x2ae, 0x4);
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ write_phy_reg(pi, 0x2ad, 0x0060);
+ else
+ write_phy_reg(pi, 0x2ad, 0x1080);
+ }
+}
+
+static void wlc_phy_war_txchain_upd_nphy(struct brcms_phy *pi, u8 txchain)
+{
+ u8 txchain0, txchain1;
+
+ txchain0 = txchain & 0x1;
+ txchain1 = (txchain & 0x2) >> 1;
+ if (!txchain0)
+ wlc_phy_war_force_trsw_to_R_cliplo_nphy(pi, PHY_CORE_0);
+
+ if (!txchain1)
+ wlc_phy_war_force_trsw_to_R_cliplo_nphy(pi, PHY_CORE_1);
+}
+
+static void wlc_phy_workarounds_nphy_gainctrl_2057_rev5(struct brcms_phy *pi)
+{
+ s8 lna1_gain_db[] = { 8, 13, 17, 22 };
+ s8 lna2_gain_db[] = { -2, 7, 11, 15 };
+ s8 tia_gain_db[] = { -4, -1, 2, 5, 5, 5, 5, 5, 5, 5 };
+ s8 tia_gainbits[] = {
+ 0x0, 0x01, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 };
+
+ mod_phy_reg(pi, 0x1c, (0x1 << 13), (1 << 13));
+ mod_phy_reg(pi, 0x32, (0x1 << 13), (1 << 13));
+
+ mod_phy_reg(pi, 0x289, (0xff << 0), (0x46 << 0));
+
+ mod_phy_reg(pi, 0x283, (0xff << 0), (0x3c << 0));
+ mod_phy_reg(pi, 0x280, (0xff << 0), (0x3c << 0));
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 0x8, 8,
+ lna1_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 0x8, 8,
+ lna1_gain_db);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 0x10, 8,
+ lna2_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 0x10, 8,
+ lna2_gain_db);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 10, 0x20, 8,
+ tia_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 10, 0x20, 8,
+ tia_gain_db);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS1, 10, 0x20, 8,
+ tia_gainbits);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS2, 10, 0x20, 8,
+ tia_gainbits);
+
+ write_phy_reg(pi, 0x37, 0x74);
+ write_phy_reg(pi, 0x2ad, 0x74);
+ write_phy_reg(pi, 0x38, 0x18);
+ write_phy_reg(pi, 0x2ae, 0x18);
+
+ write_phy_reg(pi, 0x2b, 0xe8);
+ write_phy_reg(pi, 0x41, 0xe8);
+
+ if (CHSPEC_IS20(pi->radio_chanspec)) {
+
+ mod_phy_reg(pi, 0x300, (0x3f << 0), (0x12 << 0));
+ mod_phy_reg(pi, 0x301, (0x3f << 0), (0x12 << 0));
+ } else {
+
+ mod_phy_reg(pi, 0x300, (0x3f << 0), (0x10 << 0));
+ mod_phy_reg(pi, 0x301, (0x3f << 0), (0x10 << 0));
+ }
+}
+
+static void wlc_phy_workarounds_nphy_gainctrl_2057_rev6(struct brcms_phy *pi)
+{
+ u16 currband;
+ s8 lna1G_gain_db_rev7[] = { 9, 14, 19, 24 };
+ s8 *lna1_gain_db = NULL;
+ s8 *lna1_gain_db_2 = NULL;
+ s8 *lna2_gain_db = NULL;
+ s8 tiaA_gain_db_rev7[] = { -9, -6, -3, 0, 3, 3, 3, 3, 3, 3 };
+ s8 *tia_gain_db;
+ s8 tiaA_gainbits_rev7[] = { 0, 1, 2, 3, 4, 4, 4, 4, 4, 4 };
+ s8 *tia_gainbits;
+ u16 rfseqA_init_gain_rev7[] = { 0x624f, 0x624f };
+ u16 *rfseq_init_gain;
+ u16 init_gaincode;
+ u16 clip1hi_gaincode;
+ u16 clip1md_gaincode = 0;
+ u16 clip1md_gaincode_B;
+ u16 clip1lo_gaincode;
+ u16 clip1lo_gaincode_B;
+ u8 crsminl_th = 0;
+ u8 crsminu_th;
+ u16 nbclip_th = 0;
+ u8 w1clip_th;
+ u16 freq;
+ s8 nvar_baseline_offset0 = 0, nvar_baseline_offset1 = 0;
+ u8 chg_nbclip_th = 0;
+
+ mod_phy_reg(pi, 0x1c, (0x1 << 13), (1 << 13));
+ mod_phy_reg(pi, 0x32, (0x1 << 13), (1 << 13));
+
+ currband = read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand;
+ if (currband == 0) {
+
+ lna1_gain_db = lna1G_gain_db_rev7;
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 8, 8,
+ lna1_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 8, 8,
+ lna1_gain_db);
+
+ mod_phy_reg(pi, 0x283, (0xff << 0), (0x40 << 0));
+
+ if (CHSPEC_IS40(pi->radio_chanspec)) {
+ mod_phy_reg(pi, 0x280, (0xff << 0), (0x3e << 0));
+ mod_phy_reg(pi, 0x283, (0xff << 0), (0x3e << 0));
+ }
+
+ mod_phy_reg(pi, 0x289, (0xff << 0), (0x46 << 0));
+
+ if (CHSPEC_IS20(pi->radio_chanspec)) {
+ mod_phy_reg(pi, 0x300, (0x3f << 0), (13 << 0));
+ mod_phy_reg(pi, 0x301, (0x3f << 0), (13 << 0));
+ }
+ } else {
+
+ init_gaincode = 0x9e;
+ clip1hi_gaincode = 0x9e;
+ clip1md_gaincode_B = 0x24;
+ clip1lo_gaincode = 0x8a;
+ clip1lo_gaincode_B = 8;
+ rfseq_init_gain = rfseqA_init_gain_rev7;
+
+ tia_gain_db = tiaA_gain_db_rev7;
+ tia_gainbits = tiaA_gainbits_rev7;
+
+ freq = CHAN5G_FREQ(CHSPEC_CHANNEL(pi->radio_chanspec));
+ if (CHSPEC_IS20(pi->radio_chanspec)) {
+
+ w1clip_th = 25;
+ clip1md_gaincode = 0x82;
+
+ if ((freq <= 5080) || (freq == 5825)) {
+
+ s8 lna1A_gain_db_rev7[] = { 11, 16, 20, 24 };
+ s8 lna1A_gain_db_2_rev7[] = {
+ 11, 17, 22, 25};
+ s8 lna2A_gain_db_rev7[] = { -1, 6, 10, 14 };
+
+ crsminu_th = 0x3e;
+ lna1_gain_db = lna1A_gain_db_rev7;
+ lna1_gain_db_2 = lna1A_gain_db_2_rev7;
+ lna2_gain_db = lna2A_gain_db_rev7;
+ } else if ((freq >= 5500) && (freq <= 5700)) {
+
+ s8 lna1A_gain_db_rev7[] = { 11, 17, 21, 25 };
+ s8 lna1A_gain_db_2_rev7[] = {
+ 12, 18, 22, 26};
+ s8 lna2A_gain_db_rev7[] = { 1, 8, 12, 16 };
+
+ crsminu_th = 0x45;
+ clip1md_gaincode_B = 0x14;
+ nbclip_th = 0xff;
+ chg_nbclip_th = 1;
+ lna1_gain_db = lna1A_gain_db_rev7;
+ lna1_gain_db_2 = lna1A_gain_db_2_rev7;
+ lna2_gain_db = lna2A_gain_db_rev7;
+ } else {
+
+ s8 lna1A_gain_db_rev7[] = { 12, 18, 22, 26 };
+ s8 lna1A_gain_db_2_rev7[] = {
+ 12, 18, 22, 26};
+ s8 lna2A_gain_db_rev7[] = { -1, 6, 10, 14 };
+
+ crsminu_th = 0x41;
+ lna1_gain_db = lna1A_gain_db_rev7;
+ lna1_gain_db_2 = lna1A_gain_db_2_rev7;
+ lna2_gain_db = lna2A_gain_db_rev7;
+ }
+
+ if (freq <= 4920) {
+ nvar_baseline_offset0 = 5;
+ nvar_baseline_offset1 = 5;
+ } else if ((freq > 4920) && (freq <= 5320)) {
+ nvar_baseline_offset0 = 3;
+ nvar_baseline_offset1 = 5;
+ } else if ((freq > 5320) && (freq <= 5700)) {
+ nvar_baseline_offset0 = 3;
+ nvar_baseline_offset1 = 2;
+ } else {
+ nvar_baseline_offset0 = 4;
+ nvar_baseline_offset1 = 0;
+ }
+ } else {
+
+ crsminu_th = 0x3a;
+ crsminl_th = 0x3a;
+ w1clip_th = 20;
+
+ if ((freq >= 4920) && (freq <= 5320)) {
+ nvar_baseline_offset0 = 4;
+ nvar_baseline_offset1 = 5;
+ } else if ((freq > 5320) && (freq <= 5550)) {
+ nvar_baseline_offset0 = 4;
+ nvar_baseline_offset1 = 2;
+ } else {
+ nvar_baseline_offset0 = 5;
+ nvar_baseline_offset1 = 3;
+ }
+ }
+
+ write_phy_reg(pi, 0x20, init_gaincode);
+ write_phy_reg(pi, 0x2a7, init_gaincode);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ,
+ pi->pubpi.phy_corenum, 0x106, 16,
+ rfseq_init_gain);
+
+ write_phy_reg(pi, 0x22, clip1hi_gaincode);
+ write_phy_reg(pi, 0x2a9, clip1hi_gaincode);
+
+ write_phy_reg(pi, 0x36, clip1md_gaincode_B);
+ write_phy_reg(pi, 0x2ac, clip1md_gaincode_B);
+
+ write_phy_reg(pi, 0x37, clip1lo_gaincode);
+ write_phy_reg(pi, 0x2ad, clip1lo_gaincode);
+ write_phy_reg(pi, 0x38, clip1lo_gaincode_B);
+ write_phy_reg(pi, 0x2ae, clip1lo_gaincode_B);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 10, 0x20, 8,
+ tia_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 10, 0x20, 8,
+ tia_gain_db);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS1, 10, 0x20, 8,
+ tia_gainbits);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS2, 10, 0x20, 8,
+ tia_gainbits);
+
+ mod_phy_reg(pi, 0x283, (0xff << 0), (crsminu_th << 0));
+
+ if (chg_nbclip_th == 1) {
+ write_phy_reg(pi, 0x2b, nbclip_th);
+ write_phy_reg(pi, 0x41, nbclip_th);
+ }
+
+ mod_phy_reg(pi, 0x300, (0x3f << 0), (w1clip_th << 0));
+ mod_phy_reg(pi, 0x301, (0x3f << 0), (w1clip_th << 0));
+
+ mod_phy_reg(pi, 0x2e4,
+ (0x3f << 0), (nvar_baseline_offset0 << 0));
+
+ mod_phy_reg(pi, 0x2e4,
+ (0x3f << 6), (nvar_baseline_offset1 << 6));
+
+ if (CHSPEC_IS20(pi->radio_chanspec)) {
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 8, 8,
+ lna1_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 8, 8,
+ lna1_gain_db_2);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 0x10,
+ 8, lna2_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 0x10,
+ 8, lna2_gain_db);
+
+ write_phy_reg(pi, 0x24, clip1md_gaincode);
+ write_phy_reg(pi, 0x2ab, clip1md_gaincode);
+ } else {
+ mod_phy_reg(pi, 0x280, (0xff << 0), (crsminl_th << 0));
+ }
+ }
+}
+
+static void wlc_phy_workarounds_nphy_gainctrl(struct brcms_phy *pi)
+{
+ u16 w1th, hpf_code, currband;
+ int ctr;
+ u8 rfseq_updategainu_events[] = {
+ NPHY_RFSEQ_CMD_RX_GAIN,
+ NPHY_RFSEQ_CMD_CLR_HIQ_DIS,
+ NPHY_RFSEQ_CMD_SET_HPF_BW
+ };
+ u8 rfseq_updategainu_dlys[] = { 10, 30, 1 };
+ s8 lna1G_gain_db[] = { 7, 11, 16, 23 };
+ s8 lna1G_gain_db_rev4[] = { 8, 12, 17, 25 };
+ s8 lna1G_gain_db_rev5[] = { 9, 13, 18, 26 };
+ s8 lna1G_gain_db_rev6[] = { 8, 13, 18, 25 };
+ s8 lna1G_gain_db_rev6_224B0[] = { 10, 14, 19, 27 };
+ s8 lna1A_gain_db[] = { 7, 11, 17, 23 };
+ s8 lna1A_gain_db_rev4[] = { 8, 12, 18, 23 };
+ s8 lna1A_gain_db_rev5[] = { 6, 10, 16, 21 };
+ s8 lna1A_gain_db_rev6[] = { 6, 10, 16, 21 };
+ s8 *lna1_gain_db = NULL;
+ s8 lna2G_gain_db[] = { -5, 6, 10, 14 };
+ s8 lna2G_gain_db_rev5[] = { -3, 7, 11, 16 };
+ s8 lna2G_gain_db_rev6[] = { -5, 6, 10, 14 };
+ s8 lna2G_gain_db_rev6_224B0[] = { -5, 6, 10, 15 };
+ s8 lna2A_gain_db[] = { -6, 2, 6, 10 };
+ s8 lna2A_gain_db_rev4[] = { -5, 2, 6, 10 };
+ s8 lna2A_gain_db_rev5[] = { -7, 0, 4, 8 };
+ s8 lna2A_gain_db_rev6[] = { -7, 0, 4, 8 };
+ s8 *lna2_gain_db = NULL;
+ s8 tiaG_gain_db[] = {
+ 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A };
+ s8 tiaA_gain_db[] = {
+ 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13 };
+ s8 tiaA_gain_db_rev4[] = {
+ 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d };
+ s8 tiaA_gain_db_rev5[] = {
+ 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d };
+ s8 tiaA_gain_db_rev6[] = {
+ 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d };
+ s8 *tia_gain_db;
+ s8 tiaG_gainbits[] = {
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 };
+ s8 tiaA_gainbits[] = {
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 };
+ s8 tiaA_gainbits_rev4[] = {
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 };
+ s8 tiaA_gainbits_rev5[] = {
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 };
+ s8 tiaA_gainbits_rev6[] = {
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 };
+ s8 *tia_gainbits;
+ s8 lpf_gain_db[] = { 0x00, 0x06, 0x0c, 0x12, 0x12, 0x12 };
+ s8 lpf_gainbits[] = { 0x00, 0x01, 0x02, 0x03, 0x03, 0x03 };
+ u16 rfseqG_init_gain[] = { 0x613f, 0x613f, 0x613f, 0x613f };
+ u16 rfseqG_init_gain_rev4[] = { 0x513f, 0x513f, 0x513f, 0x513f };
+ u16 rfseqG_init_gain_rev5[] = { 0x413f, 0x413f, 0x413f, 0x413f };
+ u16 rfseqG_init_gain_rev5_elna[] = {
+ 0x013f, 0x013f, 0x013f, 0x013f };
+ u16 rfseqG_init_gain_rev6[] = { 0x513f, 0x513f };
+ u16 rfseqG_init_gain_rev6_224B0[] = { 0x413f, 0x413f };
+ u16 rfseqG_init_gain_rev6_elna[] = { 0x113f, 0x113f };
+ u16 rfseqA_init_gain[] = { 0x516f, 0x516f, 0x516f, 0x516f };
+ u16 rfseqA_init_gain_rev4[] = { 0x614f, 0x614f, 0x614f, 0x614f };
+ u16 rfseqA_init_gain_rev4_elna[] = {
+ 0x314f, 0x314f, 0x314f, 0x314f };
+ u16 rfseqA_init_gain_rev5[] = { 0x714f, 0x714f, 0x714f, 0x714f };
+ u16 rfseqA_init_gain_rev6[] = { 0x714f, 0x714f };
+ u16 *rfseq_init_gain;
+ u16 initG_gaincode = 0x627e;
+ u16 initG_gaincode_rev4 = 0x527e;
+ u16 initG_gaincode_rev5 = 0x427e;
+ u16 initG_gaincode_rev5_elna = 0x027e;
+ u16 initG_gaincode_rev6 = 0x527e;
+ u16 initG_gaincode_rev6_224B0 = 0x427e;
+ u16 initG_gaincode_rev6_elna = 0x127e;
+ u16 initA_gaincode = 0x52de;
+ u16 initA_gaincode_rev4 = 0x629e;
+ u16 initA_gaincode_rev4_elna = 0x329e;
+ u16 initA_gaincode_rev5 = 0x729e;
+ u16 initA_gaincode_rev6 = 0x729e;
+ u16 init_gaincode;
+ u16 clip1hiG_gaincode = 0x107e;
+ u16 clip1hiG_gaincode_rev4 = 0x007e;
+ u16 clip1hiG_gaincode_rev5 = 0x1076;
+ u16 clip1hiG_gaincode_rev6 = 0x007e;
+ u16 clip1hiA_gaincode = 0x00de;
+ u16 clip1hiA_gaincode_rev4 = 0x029e;
+ u16 clip1hiA_gaincode_rev5 = 0x029e;
+ u16 clip1hiA_gaincode_rev6 = 0x029e;
+ u16 clip1hi_gaincode;
+ u16 clip1mdG_gaincode = 0x0066;
+ u16 clip1mdA_gaincode = 0x00ca;
+ u16 clip1mdA_gaincode_rev4 = 0x1084;
+ u16 clip1mdA_gaincode_rev5 = 0x2084;
+ u16 clip1mdA_gaincode_rev6 = 0x2084;
+ u16 clip1md_gaincode = 0;
+ u16 clip1loG_gaincode = 0x0074;
+ u16 clip1loG_gaincode_rev5[] = {
+ 0x0062, 0x0064, 0x006a, 0x106a, 0x106c, 0x1074, 0x107c, 0x207c
+ };
+ u16 clip1loG_gaincode_rev6[] = {
+ 0x106a, 0x106c, 0x1074, 0x107c, 0x007e, 0x107e, 0x207e, 0x307e
+ };
+ u16 clip1loG_gaincode_rev6_224B0 = 0x1074;
+ u16 clip1loA_gaincode = 0x00cc;
+ u16 clip1loA_gaincode_rev4 = 0x0086;
+ u16 clip1loA_gaincode_rev5 = 0x2086;
+ u16 clip1loA_gaincode_rev6 = 0x2086;
+ u16 clip1lo_gaincode;
+ u8 crsminG_th = 0x18;
+ u8 crsminG_th_rev5 = 0x18;
+ u8 crsminG_th_rev6 = 0x18;
+ u8 crsminA_th = 0x1e;
+ u8 crsminA_th_rev4 = 0x24;
+ u8 crsminA_th_rev5 = 0x24;
+ u8 crsminA_th_rev6 = 0x24;
+ u8 crsmin_th;
+ u8 crsminlG_th = 0x18;
+ u8 crsminlG_th_rev5 = 0x18;
+ u8 crsminlG_th_rev6 = 0x18;
+ u8 crsminlA_th = 0x1e;
+ u8 crsminlA_th_rev4 = 0x24;
+ u8 crsminlA_th_rev5 = 0x24;
+ u8 crsminlA_th_rev6 = 0x24;
+ u8 crsminl_th = 0;
+ u8 crsminuG_th = 0x18;
+ u8 crsminuG_th_rev5 = 0x18;
+ u8 crsminuG_th_rev6 = 0x18;
+ u8 crsminuA_th = 0x1e;
+ u8 crsminuA_th_rev4 = 0x24;
+ u8 crsminuA_th_rev5 = 0x24;
+ u8 crsminuA_th_rev6 = 0x24;
+ u8 crsminuA_th_rev6_224B0 = 0x2d;
+ u8 crsminu_th;
+ u16 nbclipG_th = 0x20d;
+ u16 nbclipG_th_rev4 = 0x1a1;
+ u16 nbclipG_th_rev5 = 0x1d0;
+ u16 nbclipG_th_rev6 = 0x1d0;
+ u16 nbclipA_th = 0x1a1;
+ u16 nbclipA_th_rev4 = 0x107;
+ u16 nbclipA_th_rev5 = 0x0a9;
+ u16 nbclipA_th_rev6 = 0x0f0;
+ u16 nbclip_th = 0;
+ u8 w1clipG_th = 5;
+ u8 w1clipG_th_rev5 = 9;
+ u8 w1clipG_th_rev6 = 5;
+ u8 w1clipA_th = 25, w1clip_th;
+ u8 rssi_gain_default = 0x50;
+ u8 rssiG_gain_rev6_224B0 = 0x50;
+ u8 rssiA_gain_rev5 = 0x90;
+ u8 rssiA_gain_rev6 = 0x90;
+ u8 rssi_gain;
+ u16 regval[21];
+ u8 triso;
+
+ triso = (CHSPEC_IS5G(pi->radio_chanspec)) ? pi->srom_fem5g.triso :
+ pi->srom_fem2g.triso;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (pi->pubpi.radiorev == 5) {
+ wlc_phy_workarounds_nphy_gainctrl_2057_rev5(pi);
+ } else if (pi->pubpi.radiorev == 7) {
+ wlc_phy_workarounds_nphy_gainctrl_2057_rev6(pi);
+
+ mod_phy_reg(pi, 0x283, (0xff << 0), (0x44 << 0));
+ mod_phy_reg(pi, 0x280, (0xff << 0), (0x44 << 0));
+
+ } else if ((pi->pubpi.radiorev == 3)
+ || (pi->pubpi.radiorev == 8)) {
+ wlc_phy_workarounds_nphy_gainctrl_2057_rev6(pi);
+
+ if (pi->pubpi.radiorev == 8) {
+ mod_phy_reg(pi, 0x283,
+ (0xff << 0), (0x44 << 0));
+ mod_phy_reg(pi, 0x280,
+ (0xff << 0), (0x44 << 0));
+ }
+ } else {
+ wlc_phy_workarounds_nphy_gainctrl_2057_rev6(pi);
+ }
+ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+
+ mod_phy_reg(pi, 0xa0, (0x1 << 6), (1 << 6));
+
+ mod_phy_reg(pi, 0x1c, (0x1 << 13), (1 << 13));
+ mod_phy_reg(pi, 0x32, (0x1 << 13), (1 << 13));
+
+ currband =
+ read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand;
+ if (currband == 0) {
+ if (NREV_GE(pi->pubpi.phy_rev, 6)) {
+ if (pi->pubpi.radiorev == 11) {
+ lna1_gain_db = lna1G_gain_db_rev6_224B0;
+ lna2_gain_db = lna2G_gain_db_rev6_224B0;
+ rfseq_init_gain =
+ rfseqG_init_gain_rev6_224B0;
+ init_gaincode =
+ initG_gaincode_rev6_224B0;
+ clip1hi_gaincode =
+ clip1hiG_gaincode_rev6;
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev6_224B0;
+ nbclip_th = nbclipG_th_rev6;
+ w1clip_th = w1clipG_th_rev6;
+ crsmin_th = crsminG_th_rev6;
+ crsminl_th = crsminlG_th_rev6;
+ crsminu_th = crsminuG_th_rev6;
+ rssi_gain = rssiG_gain_rev6_224B0;
+ } else {
+ lna1_gain_db = lna1G_gain_db_rev6;
+ lna2_gain_db = lna2G_gain_db_rev6;
+ if (pi->sh->boardflags & BFL_EXTLNA) {
+
+ rfseq_init_gain =
+ rfseqG_init_gain_rev6_elna;
+ init_gaincode =
+ initG_gaincode_rev6_elna;
+ } else {
+ rfseq_init_gain =
+ rfseqG_init_gain_rev6;
+ init_gaincode =
+ initG_gaincode_rev6;
+ }
+ clip1hi_gaincode =
+ clip1hiG_gaincode_rev6;
+ switch (triso) {
+ case 0:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev6
+ [0];
+ break;
+ case 1:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev6
+ [1];
+ break;
+ case 2:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev6
+ [2];
+ break;
+ case 3:
+ default:
+
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev6
+ [3];
+ break;
+ case 4:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev6
+ [4];
+ break;
+ case 5:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev6
+ [5];
+ break;
+ case 6:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev6
+ [6];
+ break;
+ case 7:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev6
+ [7];
+ break;
+ }
+ nbclip_th = nbclipG_th_rev6;
+ w1clip_th = w1clipG_th_rev6;
+ crsmin_th = crsminG_th_rev6;
+ crsminl_th = crsminlG_th_rev6;
+ crsminu_th = crsminuG_th_rev6;
+ rssi_gain = rssi_gain_default;
+ }
+ } else if (NREV_IS(pi->pubpi.phy_rev, 5)) {
+ lna1_gain_db = lna1G_gain_db_rev5;
+ lna2_gain_db = lna2G_gain_db_rev5;
+ if (pi->sh->boardflags & BFL_EXTLNA) {
+
+ rfseq_init_gain =
+ rfseqG_init_gain_rev5_elna;
+ init_gaincode =
+ initG_gaincode_rev5_elna;
+ } else {
+ rfseq_init_gain = rfseqG_init_gain_rev5;
+ init_gaincode = initG_gaincode_rev5;
+ }
+ clip1hi_gaincode = clip1hiG_gaincode_rev5;
+ switch (triso) {
+ case 0:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev5[0];
+ break;
+ case 1:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev5[1];
+ break;
+ case 2:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev5[2];
+ break;
+ case 3:
+
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev5[3];
+ break;
+ case 4:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev5[4];
+ break;
+ case 5:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev5[5];
+ break;
+ case 6:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev5[6];
+ break;
+ case 7:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev5[7];
+ break;
+ default:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev5[3];
+ break;
+ }
+ nbclip_th = nbclipG_th_rev5;
+ w1clip_th = w1clipG_th_rev5;
+ crsmin_th = crsminG_th_rev5;
+ crsminl_th = crsminlG_th_rev5;
+ crsminu_th = crsminuG_th_rev5;
+ rssi_gain = rssi_gain_default;
+ } else if (NREV_IS(pi->pubpi.phy_rev, 4)) {
+ lna1_gain_db = lna1G_gain_db_rev4;
+ lna2_gain_db = lna2G_gain_db;
+ rfseq_init_gain = rfseqG_init_gain_rev4;
+ init_gaincode = initG_gaincode_rev4;
+ clip1hi_gaincode = clip1hiG_gaincode_rev4;
+ clip1lo_gaincode = clip1loG_gaincode;
+ nbclip_th = nbclipG_th_rev4;
+ w1clip_th = w1clipG_th;
+ crsmin_th = crsminG_th;
+ crsminl_th = crsminlG_th;
+ crsminu_th = crsminuG_th;
+ rssi_gain = rssi_gain_default;
+ } else {
+ lna1_gain_db = lna1G_gain_db;
+ lna2_gain_db = lna2G_gain_db;
+ rfseq_init_gain = rfseqG_init_gain;
+ init_gaincode = initG_gaincode;
+ clip1hi_gaincode = clip1hiG_gaincode;
+ clip1lo_gaincode = clip1loG_gaincode;
+ nbclip_th = nbclipG_th;
+ w1clip_th = w1clipG_th;
+ crsmin_th = crsminG_th;
+ crsminl_th = crsminlG_th;
+ crsminu_th = crsminuG_th;
+ rssi_gain = rssi_gain_default;
+ }
+ tia_gain_db = tiaG_gain_db;
+ tia_gainbits = tiaG_gainbits;
+ clip1md_gaincode = clip1mdG_gaincode;
+ } else {
+ if (NREV_GE(pi->pubpi.phy_rev, 6)) {
+ lna1_gain_db = lna1A_gain_db_rev6;
+ lna2_gain_db = lna2A_gain_db_rev6;
+ tia_gain_db = tiaA_gain_db_rev6;
+ tia_gainbits = tiaA_gainbits_rev6;
+ rfseq_init_gain = rfseqA_init_gain_rev6;
+ init_gaincode = initA_gaincode_rev6;
+ clip1hi_gaincode = clip1hiA_gaincode_rev6;
+ clip1md_gaincode = clip1mdA_gaincode_rev6;
+ clip1lo_gaincode = clip1loA_gaincode_rev6;
+ crsmin_th = crsminA_th_rev6;
+ crsminl_th = crsminlA_th_rev6;
+ if ((pi->pubpi.radiorev == 11) &&
+ (CHSPEC_IS40(pi->radio_chanspec) == 0))
+ crsminu_th = crsminuA_th_rev6_224B0;
+ else
+ crsminu_th = crsminuA_th_rev6;
+
+ nbclip_th = nbclipA_th_rev6;
+ rssi_gain = rssiA_gain_rev6;
+ } else if (NREV_IS(pi->pubpi.phy_rev, 5)) {
+ lna1_gain_db = lna1A_gain_db_rev5;
+ lna2_gain_db = lna2A_gain_db_rev5;
+ tia_gain_db = tiaA_gain_db_rev5;
+ tia_gainbits = tiaA_gainbits_rev5;
+ rfseq_init_gain = rfseqA_init_gain_rev5;
+ init_gaincode = initA_gaincode_rev5;
+ clip1hi_gaincode = clip1hiA_gaincode_rev5;
+ clip1md_gaincode = clip1mdA_gaincode_rev5;
+ clip1lo_gaincode = clip1loA_gaincode_rev5;
+ crsmin_th = crsminA_th_rev5;
+ crsminl_th = crsminlA_th_rev5;
+ crsminu_th = crsminuA_th_rev5;
+ nbclip_th = nbclipA_th_rev5;
+ rssi_gain = rssiA_gain_rev5;
+ } else if (NREV_IS(pi->pubpi.phy_rev, 4)) {
+ lna1_gain_db = lna1A_gain_db_rev4;
+ lna2_gain_db = lna2A_gain_db_rev4;
+ tia_gain_db = tiaA_gain_db_rev4;
+ tia_gainbits = tiaA_gainbits_rev4;
+ if (pi->sh->boardflags & BFL_EXTLNA_5GHz) {
+
+ rfseq_init_gain =
+ rfseqA_init_gain_rev4_elna;
+ init_gaincode =
+ initA_gaincode_rev4_elna;
+ } else {
+ rfseq_init_gain = rfseqA_init_gain_rev4;
+ init_gaincode = initA_gaincode_rev4;
+ }
+ clip1hi_gaincode = clip1hiA_gaincode_rev4;
+ clip1md_gaincode = clip1mdA_gaincode_rev4;
+ clip1lo_gaincode = clip1loA_gaincode_rev4;
+ crsmin_th = crsminA_th_rev4;
+ crsminl_th = crsminlA_th_rev4;
+ crsminu_th = crsminuA_th_rev4;
+ nbclip_th = nbclipA_th_rev4;
+ rssi_gain = rssi_gain_default;
+ } else {
+ lna1_gain_db = lna1A_gain_db;
+ lna2_gain_db = lna2A_gain_db;
+ tia_gain_db = tiaA_gain_db;
+ tia_gainbits = tiaA_gainbits;
+ rfseq_init_gain = rfseqA_init_gain;
+ init_gaincode = initA_gaincode;
+ clip1hi_gaincode = clip1hiA_gaincode;
+ clip1md_gaincode = clip1mdA_gaincode;
+ clip1lo_gaincode = clip1loA_gaincode;
+ crsmin_th = crsminA_th;
+ crsminl_th = crsminlA_th;
+ crsminu_th = crsminuA_th;
+ nbclip_th = nbclipA_th;
+ rssi_gain = rssi_gain_default;
+ }
+ w1clip_th = w1clipA_th;
+ }
+
+ write_radio_reg(pi,
+ (RADIO_2056_RX_BIASPOLE_LNAG1_IDAC |
+ RADIO_2056_RX0), 0x17);
+ write_radio_reg(pi,
+ (RADIO_2056_RX_BIASPOLE_LNAG1_IDAC |
+ RADIO_2056_RX1), 0x17);
+
+ write_radio_reg(pi, (RADIO_2056_RX_LNAG2_IDAC | RADIO_2056_RX0),
+ 0xf0);
+ write_radio_reg(pi, (RADIO_2056_RX_LNAG2_IDAC | RADIO_2056_RX1),
+ 0xf0);
+
+ write_radio_reg(pi, (RADIO_2056_RX_RSSI_POLE | RADIO_2056_RX0),
+ 0x0);
+ write_radio_reg(pi, (RADIO_2056_RX_RSSI_POLE | RADIO_2056_RX1),
+ 0x0);
+
+ write_radio_reg(pi, (RADIO_2056_RX_RSSI_GAIN | RADIO_2056_RX0),
+ rssi_gain);
+ write_radio_reg(pi, (RADIO_2056_RX_RSSI_GAIN | RADIO_2056_RX1),
+ rssi_gain);
+
+ write_radio_reg(pi,
+ (RADIO_2056_RX_BIASPOLE_LNAA1_IDAC |
+ RADIO_2056_RX0), 0x17);
+ write_radio_reg(pi,
+ (RADIO_2056_RX_BIASPOLE_LNAA1_IDAC |
+ RADIO_2056_RX1), 0x17);
+
+ write_radio_reg(pi, (RADIO_2056_RX_LNAA2_IDAC | RADIO_2056_RX0),
+ 0xFF);
+ write_radio_reg(pi, (RADIO_2056_RX_LNAA2_IDAC | RADIO_2056_RX1),
+ 0xFF);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 8,
+ 8, lna1_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 8,
+ 8, lna1_gain_db);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 0x10,
+ 8, lna2_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 0x10,
+ 8, lna2_gain_db);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 10, 0x20,
+ 8, tia_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 10, 0x20,
+ 8, tia_gain_db);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS1, 10, 0x20,
+ 8, tia_gainbits);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS2, 10, 0x20,
+ 8, tia_gainbits);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 6, 0x40,
+ 8, &lpf_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 6, 0x40,
+ 8, &lpf_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS1, 6, 0x40,
+ 8, &lpf_gainbits);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS2, 6, 0x40,
+ 8, &lpf_gainbits);
+
+ write_phy_reg(pi, 0x20, init_gaincode);
+ write_phy_reg(pi, 0x2a7, init_gaincode);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ,
+ pi->pubpi.phy_corenum, 0x106, 16,
+ rfseq_init_gain);
+
+ write_phy_reg(pi, 0x22, clip1hi_gaincode);
+ write_phy_reg(pi, 0x2a9, clip1hi_gaincode);
+
+ write_phy_reg(pi, 0x24, clip1md_gaincode);
+ write_phy_reg(pi, 0x2ab, clip1md_gaincode);
+
+ write_phy_reg(pi, 0x37, clip1lo_gaincode);
+ write_phy_reg(pi, 0x2ad, clip1lo_gaincode);
+
+ mod_phy_reg(pi, 0x27d, (0xff << 0), (crsmin_th << 0));
+ mod_phy_reg(pi, 0x280, (0xff << 0), (crsminl_th << 0));
+ mod_phy_reg(pi, 0x283, (0xff << 0), (crsminu_th << 0));
+
+ write_phy_reg(pi, 0x2b, nbclip_th);
+ write_phy_reg(pi, 0x41, nbclip_th);
+
+ mod_phy_reg(pi, 0x27, (0x3f << 0), (w1clip_th << 0));
+ mod_phy_reg(pi, 0x3d, (0x3f << 0), (w1clip_th << 0));
+
+ write_phy_reg(pi, 0x150, 0x809c);
+
+ } else {
+
+ mod_phy_reg(pi, 0x1c, (0x1 << 13), (1 << 13));
+ mod_phy_reg(pi, 0x32, (0x1 << 13), (1 << 13));
+
+ write_phy_reg(pi, 0x2b, 0x84);
+ write_phy_reg(pi, 0x41, 0x84);
+
+ if (CHSPEC_IS20(pi->radio_chanspec)) {
+ write_phy_reg(pi, 0x6b, 0x2b);
+ write_phy_reg(pi, 0x6c, 0x2b);
+ write_phy_reg(pi, 0x6d, 0x9);
+ write_phy_reg(pi, 0x6e, 0x9);
+ }
+
+ w1th = NPHY_RSSICAL_W1_TARGET - 4;
+ mod_phy_reg(pi, 0x27, (0x3f << 0), (w1th << 0));
+ mod_phy_reg(pi, 0x3d, (0x3f << 0), (w1th << 0));
+
+ if (CHSPEC_IS20(pi->radio_chanspec)) {
+ mod_phy_reg(pi, 0x1c, (0x1f << 0), (0x1 << 0));
+ mod_phy_reg(pi, 0x32, (0x1f << 0), (0x1 << 0));
+
+ mod_phy_reg(pi, 0x1d, (0x1f << 0), (0x1 << 0));
+ mod_phy_reg(pi, 0x33, (0x1f << 0), (0x1 << 0));
+ }
+
+ write_phy_reg(pi, 0x150, 0x809c);
+
+ if (pi->nphy_gain_boost)
+ if ((CHSPEC_IS2G(pi->radio_chanspec)) &&
+ (CHSPEC_IS40(pi->radio_chanspec)))
+ hpf_code = 4;
+ else
+ hpf_code = 5;
+ else if (CHSPEC_IS40(pi->radio_chanspec))
+ hpf_code = 6;
+ else
+ hpf_code = 7;
+
+ mod_phy_reg(pi, 0x20, (0x1f << 7), (hpf_code << 7));
+ mod_phy_reg(pi, 0x36, (0x1f << 7), (hpf_code << 7));
+
+ for (ctr = 0; ctr < 4; ctr++)
+ regval[ctr] = (hpf_code << 8) | 0x7c;
+ wlc_phy_table_write_nphy(pi, 7, 4, 0x106, 16, regval);
+
+ wlc_phy_adjust_lnagaintbl_nphy(pi);
+
+ if (pi->nphy_elna_gain_config) {
+ regval[0] = 0;
+ regval[1] = 1;
+ regval[2] = 1;
+ regval[3] = 1;
+ wlc_phy_table_write_nphy(pi, 2, 4, 8, 16, regval);
+ wlc_phy_table_write_nphy(pi, 3, 4, 8, 16, regval);
+
+ for (ctr = 0; ctr < 4; ctr++)
+ regval[ctr] = (hpf_code << 8) | 0x74;
+ wlc_phy_table_write_nphy(pi, 7, 4, 0x106, 16, regval);
+ }
+
+ if (NREV_IS(pi->pubpi.phy_rev, 2)) {
+ for (ctr = 0; ctr < 21; ctr++)
+ regval[ctr] = 3 * ctr;
+ wlc_phy_table_write_nphy(pi, 0, 21, 32, 16, regval);
+ wlc_phy_table_write_nphy(pi, 1, 21, 32, 16, regval);
+
+ for (ctr = 0; ctr < 21; ctr++)
+ regval[ctr] = (u16) ctr;
+ wlc_phy_table_write_nphy(pi, 2, 21, 32, 16, regval);
+ wlc_phy_table_write_nphy(pi, 3, 21, 32, 16, regval);
+ }
+
+ wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_UPDATEGAINU,
+ rfseq_updategainu_events,
+ rfseq_updategainu_dlys,
+ sizeof(rfseq_updategainu_events) /
+ sizeof(rfseq_updategainu_events[0]));
+
+ mod_phy_reg(pi, 0x153, (0xff << 8), (90 << 8));
+
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ mod_phy_reg(pi,
+ (NPHY_TO_BPHY_OFF + BPHY_OPTIONAL_MODES),
+ 0x7f, 0x4);
+ }
+}
+
+static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
+{
+ u8 rfseq_rx2tx_events[] = {
+ NPHY_RFSEQ_CMD_NOP,
+ NPHY_RFSEQ_CMD_RXG_FBW,
+ NPHY_RFSEQ_CMD_TR_SWITCH,
+ NPHY_RFSEQ_CMD_CLR_HIQ_DIS,
+ NPHY_RFSEQ_CMD_RXPD_TXPD,
+ NPHY_RFSEQ_CMD_TX_GAIN,
+ NPHY_RFSEQ_CMD_EXT_PA
+ };
+ u8 rfseq_rx2tx_dlys[] = { 8, 6, 6, 2, 4, 60, 1 };
+ u8 rfseq_tx2rx_events[] = {
+ NPHY_RFSEQ_CMD_NOP,
+ NPHY_RFSEQ_CMD_EXT_PA,
+ NPHY_RFSEQ_CMD_TX_GAIN,
+ NPHY_RFSEQ_CMD_RXPD_TXPD,
+ NPHY_RFSEQ_CMD_TR_SWITCH,
+ NPHY_RFSEQ_CMD_RXG_FBW,
+ NPHY_RFSEQ_CMD_CLR_HIQ_DIS
+ };
+ u8 rfseq_tx2rx_dlys[] = { 8, 6, 2, 4, 4, 6, 1 };
+ u8 rfseq_tx2rx_events_rev3[] = {
+ NPHY_REV3_RFSEQ_CMD_EXT_PA,
+ NPHY_REV3_RFSEQ_CMD_INT_PA_PU,
+ NPHY_REV3_RFSEQ_CMD_TX_GAIN,
+ NPHY_REV3_RFSEQ_CMD_RXPD_TXPD,
+ NPHY_REV3_RFSEQ_CMD_TR_SWITCH,
+ NPHY_REV3_RFSEQ_CMD_RXG_FBW,
+ NPHY_REV3_RFSEQ_CMD_CLR_HIQ_DIS,
+ NPHY_REV3_RFSEQ_CMD_END
+ };
+ u8 rfseq_tx2rx_dlys_rev3[] = { 8, 4, 2, 2, 4, 4, 6, 1 };
+ u8 rfseq_rx2tx_events_rev3[] = {
+ NPHY_REV3_RFSEQ_CMD_NOP,
+ NPHY_REV3_RFSEQ_CMD_RXG_FBW,
+ NPHY_REV3_RFSEQ_CMD_TR_SWITCH,
+ NPHY_REV3_RFSEQ_CMD_CLR_HIQ_DIS,
+ NPHY_REV3_RFSEQ_CMD_RXPD_TXPD,
+ NPHY_REV3_RFSEQ_CMD_TX_GAIN,
+ NPHY_REV3_RFSEQ_CMD_INT_PA_PU,
+ NPHY_REV3_RFSEQ_CMD_EXT_PA,
+ NPHY_REV3_RFSEQ_CMD_END
+ };
+ u8 rfseq_rx2tx_dlys_rev3[] = { 8, 6, 6, 4, 4, 18, 42, 1, 1 };
+
+ u8 rfseq_rx2tx_events_rev3_ipa[] = {
+ NPHY_REV3_RFSEQ_CMD_NOP,
+ NPHY_REV3_RFSEQ_CMD_RXG_FBW,
+ NPHY_REV3_RFSEQ_CMD_TR_SWITCH,
+ NPHY_REV3_RFSEQ_CMD_CLR_HIQ_DIS,
+ NPHY_REV3_RFSEQ_CMD_RXPD_TXPD,
+ NPHY_REV3_RFSEQ_CMD_TX_GAIN,
+ NPHY_REV3_RFSEQ_CMD_CLR_RXRX_BIAS,
+ NPHY_REV3_RFSEQ_CMD_INT_PA_PU,
+ NPHY_REV3_RFSEQ_CMD_END
+ };
+ u8 rfseq_rx2tx_dlys_rev3_ipa[] = { 8, 6, 6, 4, 4, 16, 43, 1, 1 };
+ u16 rfseq_rx2tx_dacbufpu_rev7[] = { 0x10f, 0x10f };
+
+ s16 alpha0, alpha1, alpha2;
+ s16 beta0, beta1, beta2;
+ u32 leg_data_weights, ht_data_weights, nss1_data_weights,
+ stbc_data_weights;
+ u8 chan_freq_range = 0;
+ u16 dac_control = 0x0002;
+ u16 aux_adc_vmid_rev7_core0[] = { 0x8e, 0x96, 0x96, 0x96 };
+ u16 aux_adc_vmid_rev7_core1[] = { 0x8f, 0x9f, 0x9f, 0x96 };
+ u16 aux_adc_vmid_rev4[] = { 0xa2, 0xb4, 0xb4, 0x89 };
+ u16 aux_adc_vmid_rev3[] = { 0xa2, 0xb4, 0xb4, 0x89 };
+ u16 *aux_adc_vmid;
+ u16 aux_adc_gain_rev7[] = { 0x02, 0x02, 0x02, 0x02 };
+ u16 aux_adc_gain_rev4[] = { 0x02, 0x02, 0x02, 0x00 };
+ u16 aux_adc_gain_rev3[] = { 0x02, 0x02, 0x02, 0x00 };
+ u16 *aux_adc_gain;
+ u16 sk_adc_vmid[] = { 0xb4, 0xb4, 0xb4, 0x24 };
+ u16 sk_adc_gain[] = { 0x02, 0x02, 0x02, 0x02 };
+ s32 min_nvar_val = 0x18d;
+ s32 min_nvar_offset_6mbps = 20;
+ u8 pdetrange;
+ u8 triso;
+ u16 regval;
+ u16 afectrl_adc_ctrl1_rev7 = 0x20;
+ u16 afectrl_adc_ctrl2_rev7 = 0x0;
+ u16 rfseq_rx2tx_lpf_h_hpc_rev7 = 0x77;
+ u16 rfseq_tx2rx_lpf_h_hpc_rev7 = 0x77;
+ u16 rfseq_pktgn_lpf_h_hpc_rev7 = 0x77;
+ u16 rfseq_htpktgn_lpf_hpc_rev7[] = { 0x77, 0x11, 0x11 };
+ u16 rfseq_pktgn_lpf_hpc_rev7[] = { 0x11, 0x11 };
+ u16 rfseq_cckpktgn_lpf_hpc_rev7[] = { 0x11, 0x11 };
+ u16 ipalvlshift_3p3_war_en = 0;
+ u16 rccal_bcap_val, rccal_scap_val;
+ u16 rccal_tx20_11b_bcap = 0;
+ u16 rccal_tx20_11b_scap = 0;
+ u16 rccal_tx20_11n_bcap = 0;
+ u16 rccal_tx20_11n_scap = 0;
+ u16 rccal_tx40_11n_bcap = 0;
+ u16 rccal_tx40_11n_scap = 0;
+ u16 rx2tx_lpf_rc_lut_tx20_11b = 0;
+ u16 rx2tx_lpf_rc_lut_tx20_11n = 0;
+ u16 rx2tx_lpf_rc_lut_tx40_11n = 0;
+ u16 tx_lpf_bw_ofdm_20mhz = 0;
+ u16 tx_lpf_bw_ofdm_40mhz = 0;
+ u16 tx_lpf_bw_11b = 0;
+ u16 ipa2g_mainbias, ipa2g_casconv, ipa2g_biasfilt;
+ u16 txgm_idac_bleed = 0;
+ bool rccal_ovrd = false;
+ u16 freq;
+ int coreNum;
+
+ if (CHSPEC_IS5G(pi->radio_chanspec))
+ wlc_phy_classifier_nphy(pi, NPHY_ClassifierCtrl_cck_en, 0);
+ else
+ wlc_phy_classifier_nphy(pi, NPHY_ClassifierCtrl_cck_en, 1);
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ or_phy_reg(pi, 0xb1, NPHY_IQFlip_ADC1 | NPHY_IQFlip_ADC2);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ if (NREV_IS(pi->pubpi.phy_rev, 7)) {
+ mod_phy_reg(pi, 0x221, (0x1 << 4), (1 << 4));
+
+ mod_phy_reg(pi, 0x160, (0x7f << 0), (32 << 0));
+ mod_phy_reg(pi, 0x160, (0x7f << 8), (39 << 8));
+ mod_phy_reg(pi, 0x161, (0x7f << 0), (46 << 0));
+ mod_phy_reg(pi, 0x161, (0x7f << 8), (51 << 8));
+ mod_phy_reg(pi, 0x162, (0x7f << 0), (55 << 0));
+ mod_phy_reg(pi, 0x162, (0x7f << 8), (58 << 8));
+ mod_phy_reg(pi, 0x163, (0x7f << 0), (60 << 0));
+ mod_phy_reg(pi, 0x163, (0x7f << 8), (62 << 8));
+ mod_phy_reg(pi, 0x164, (0x7f << 0), (62 << 0));
+ mod_phy_reg(pi, 0x164, (0x7f << 8), (63 << 8));
+ mod_phy_reg(pi, 0x165, (0x7f << 0), (63 << 0));
+ mod_phy_reg(pi, 0x165, (0x7f << 8), (64 << 8));
+ mod_phy_reg(pi, 0x166, (0x7f << 0), (64 << 0));
+ mod_phy_reg(pi, 0x166, (0x7f << 8), (64 << 8));
+ mod_phy_reg(pi, 0x167, (0x7f << 0), (64 << 0));
+ mod_phy_reg(pi, 0x167, (0x7f << 8), (64 << 8));
+ }
+
+ if (NREV_LE(pi->pubpi.phy_rev, 8)) {
+ write_phy_reg(pi, 0x23f, 0x1b0);
+ write_phy_reg(pi, 0x240, 0x1b0);
+ }
+
+ if (NREV_GE(pi->pubpi.phy_rev, 8))
+ mod_phy_reg(pi, 0xbd, (0xff << 0), (114 << 0));
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x00, 16,
+ &dac_control);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x10, 16,
+ &dac_control);
+
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL,
+ 1, 0, 32, &leg_data_weights);
+ leg_data_weights = leg_data_weights & 0xffffff;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL,
+ 1, 0, 32, &leg_data_weights);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ,
+ 2, 0x15e, 16,
+ rfseq_rx2tx_dacbufpu_rev7);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x16e, 16,
+ rfseq_rx2tx_dacbufpu_rev7);
+
+ if (PHY_IPA(pi))
+ wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX,
+ rfseq_rx2tx_events_rev3_ipa,
+ rfseq_rx2tx_dlys_rev3_ipa,
+ sizeof
+ (rfseq_rx2tx_events_rev3_ipa) /
+ sizeof
+ (rfseq_rx2tx_events_rev3_ipa
+ [0]));
+
+ mod_phy_reg(pi, 0x299, (0x3 << 14), (0x1 << 14));
+ mod_phy_reg(pi, 0x29d, (0x3 << 14), (0x1 << 14));
+
+ tx_lpf_bw_ofdm_20mhz = wlc_phy_read_lpf_bw_ctl_nphy(pi, 0x154);
+ tx_lpf_bw_ofdm_40mhz = wlc_phy_read_lpf_bw_ctl_nphy(pi, 0x159);
+ tx_lpf_bw_11b = wlc_phy_read_lpf_bw_ctl_nphy(pi, 0x152);
+
+ if (PHY_IPA(pi)) {
+
+ if (((pi->pubpi.radiorev == 5)
+ && (CHSPEC_IS40(pi->radio_chanspec) == 1))
+ || (pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8)) {
+
+ rccal_bcap_val =
+ read_radio_reg(
+ pi,
+ RADIO_2057_RCCAL_BCAP_VAL);
+ rccal_scap_val =
+ read_radio_reg(
+ pi,
+ RADIO_2057_RCCAL_SCAP_VAL);
+
+ rccal_tx20_11b_bcap = rccal_bcap_val;
+ rccal_tx20_11b_scap = rccal_scap_val;
+
+ if ((pi->pubpi.radiorev == 5) &&
+ (CHSPEC_IS40(pi->radio_chanspec) == 1)) {
+
+ rccal_tx20_11n_bcap = rccal_bcap_val;
+ rccal_tx20_11n_scap = rccal_scap_val;
+ rccal_tx40_11n_bcap = 0xc;
+ rccal_tx40_11n_scap = 0xc;
+
+ rccal_ovrd = true;
+
+ } else if ((pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8)) {
+
+ tx_lpf_bw_ofdm_20mhz = 4;
+ tx_lpf_bw_11b = 1;
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ rccal_tx20_11n_bcap = 0xc;
+ rccal_tx20_11n_scap = 0xc;
+ rccal_tx40_11n_bcap = 0xa;
+ rccal_tx40_11n_scap = 0xa;
+ } else {
+ rccal_tx20_11n_bcap = 0x14;
+ rccal_tx20_11n_scap = 0x14;
+ rccal_tx40_11n_bcap = 0xf;
+ rccal_tx40_11n_scap = 0xf;
+ }
+
+ rccal_ovrd = true;
+ }
+ }
+
+ } else {
+
+ if (pi->pubpi.radiorev == 5) {
+
+ tx_lpf_bw_ofdm_20mhz = 1;
+ tx_lpf_bw_ofdm_40mhz = 3;
+
+ rccal_bcap_val =
+ read_radio_reg(
+ pi,
+ RADIO_2057_RCCAL_BCAP_VAL);
+ rccal_scap_val =
+ read_radio_reg(
+ pi,
+ RADIO_2057_RCCAL_SCAP_VAL);
+
+ rccal_tx20_11b_bcap = rccal_bcap_val;
+ rccal_tx20_11b_scap = rccal_scap_val;
+
+ rccal_tx20_11n_bcap = 0x13;
+ rccal_tx20_11n_scap = 0x11;
+ rccal_tx40_11n_bcap = 0x13;
+ rccal_tx40_11n_scap = 0x11;
+
+ rccal_ovrd = true;
+ }
+ }
+
+ if (rccal_ovrd) {
+
+ rx2tx_lpf_rc_lut_tx20_11b =
+ (rccal_tx20_11b_bcap << 8) |
+ (rccal_tx20_11b_scap << 3) |
+ tx_lpf_bw_11b;
+ rx2tx_lpf_rc_lut_tx20_11n =
+ (rccal_tx20_11n_bcap << 8) |
+ (rccal_tx20_11n_scap << 3) |
+ tx_lpf_bw_ofdm_20mhz;
+ rx2tx_lpf_rc_lut_tx40_11n =
+ (rccal_tx40_11n_bcap << 8) |
+ (rccal_tx40_11n_scap << 3) |
+ tx_lpf_bw_ofdm_40mhz;
+
+ for (coreNum = 0; coreNum <= 1; coreNum++) {
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_RFSEQ,
+ 1,
+ 0x152 + coreNum * 0x10,
+ 16,
+ &rx2tx_lpf_rc_lut_tx20_11b);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_RFSEQ,
+ 1,
+ 0x153 + coreNum * 0x10,
+ 16,
+ &rx2tx_lpf_rc_lut_tx20_11n);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_RFSEQ,
+ 1,
+ 0x154 + coreNum * 0x10,
+ 16,
+ &rx2tx_lpf_rc_lut_tx20_11n);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_RFSEQ,
+ 1,
+ 0x155 + coreNum * 0x10,
+ 16,
+ &rx2tx_lpf_rc_lut_tx40_11n);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_RFSEQ,
+ 1,
+ 0x156 + coreNum * 0x10,
+ 16,
+ &rx2tx_lpf_rc_lut_tx40_11n);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_RFSEQ,
+ 1,
+ 0x157 + coreNum * 0x10,
+ 16,
+ &rx2tx_lpf_rc_lut_tx40_11n);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_RFSEQ,
+ 1,
+ 0x158 + coreNum * 0x10,
+ 16,
+ &rx2tx_lpf_rc_lut_tx40_11n);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_RFSEQ,
+ 1,
+ 0x159 + coreNum * 0x10,
+ 16,
+ &rx2tx_lpf_rc_lut_tx40_11n);
+ }
+
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 4),
+ 1, 0x3, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID2);
+ }
+
+ write_phy_reg(pi, 0x32f, 0x3);
+
+ if ((pi->pubpi.radiorev == 4) || (pi->pubpi.radiorev == 6))
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 2),
+ 1, 0x3, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+
+ if ((pi->pubpi.radiorev == 3) || (pi->pubpi.radiorev == 4) ||
+ (pi->pubpi.radiorev == 6)) {
+ if ((pi->sh->sromrev >= 8)
+ && (pi->sh->boardflags2 & BFL2_IPALVLSHIFT_3P3))
+ ipalvlshift_3p3_war_en = 1;
+
+ if (ipalvlshift_3p3_war_en) {
+ write_radio_reg(pi, RADIO_2057_GPAIO_CONFIG,
+ 0x5);
+ write_radio_reg(pi, RADIO_2057_GPAIO_SEL1,
+ 0x30);
+ write_radio_reg(pi, RADIO_2057_GPAIO_SEL0, 0x0);
+ or_radio_reg(pi,
+ RADIO_2057_RXTXBIAS_CONFIG_CORE0,
+ 0x1);
+ or_radio_reg(pi,
+ RADIO_2057_RXTXBIAS_CONFIG_CORE1,
+ 0x1);
+
+ ipa2g_mainbias = 0x1f;
+
+ ipa2g_casconv = 0x6f;
+
+ ipa2g_biasfilt = 0xaa;
+ } else {
+
+ ipa2g_mainbias = 0x2b;
+
+ ipa2g_casconv = 0x7f;
+
+ ipa2g_biasfilt = 0xee;
+ }
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ for (coreNum = 0; coreNum <= 1; coreNum++) {
+ WRITE_RADIO_REG4(pi, RADIO_2057, CORE,
+ coreNum, IPA2G_IMAIN,
+ ipa2g_mainbias);
+ WRITE_RADIO_REG4(pi, RADIO_2057, CORE,
+ coreNum, IPA2G_CASCONV,
+ ipa2g_casconv);
+ WRITE_RADIO_REG4(pi, RADIO_2057, CORE,
+ coreNum,
+ IPA2G_BIAS_FILTER,
+ ipa2g_biasfilt);
+ }
+ }
+ }
+
+ if (PHY_IPA(pi)) {
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if ((pi->pubpi.radiorev == 3)
+ || (pi->pubpi.radiorev == 4)
+ || (pi->pubpi.radiorev == 6))
+ txgm_idac_bleed = 0x7f;
+
+ for (coreNum = 0; coreNum <= 1; coreNum++) {
+ if (txgm_idac_bleed != 0)
+ WRITE_RADIO_REG4(
+ pi, RADIO_2057,
+ CORE, coreNum,
+ TXGM_IDAC_BLEED,
+ txgm_idac_bleed);
+ }
+
+ if (pi->pubpi.radiorev == 5) {
+
+ for (coreNum = 0; coreNum <= 1;
+ coreNum++) {
+ WRITE_RADIO_REG4(pi, RADIO_2057,
+ CORE, coreNum,
+ IPA2G_CASCONV,
+ 0x13);
+ WRITE_RADIO_REG4(pi, RADIO_2057,
+ CORE, coreNum,
+ IPA2G_IMAIN,
+ 0x1f);
+ WRITE_RADIO_REG4(
+ pi, RADIO_2057,
+ CORE, coreNum,
+ IPA2G_BIAS_FILTER,
+ 0xee);
+ WRITE_RADIO_REG4(pi, RADIO_2057,
+ CORE, coreNum,
+ PAD2G_IDACS,
+ 0x8a);
+ WRITE_RADIO_REG4(
+ pi, RADIO_2057,
+ CORE, coreNum,
+ PAD_BIAS_FILTER_BWS,
+ 0x3e);
+ }
+
+ } else if ((pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8)) {
+
+ if (CHSPEC_IS40(pi->radio_chanspec) ==
+ 0) {
+ WRITE_RADIO_REG4(pi, RADIO_2057,
+ CORE, 0,
+ IPA2G_IMAIN,
+ 0x14);
+ WRITE_RADIO_REG4(pi, RADIO_2057,
+ CORE, 1,
+ IPA2G_IMAIN,
+ 0x12);
+ } else {
+ WRITE_RADIO_REG4(pi, RADIO_2057,
+ CORE, 0,
+ IPA2G_IMAIN,
+ 0x16);
+ WRITE_RADIO_REG4(pi, RADIO_2057,
+ CORE, 1,
+ IPA2G_IMAIN,
+ 0x16);
+ }
+ }
+
+ } else {
+ freq = CHAN5G_FREQ(CHSPEC_CHANNEL(
+ pi->radio_chanspec));
+ if (((freq >= 5180) && (freq <= 5230))
+ || ((freq >= 5745) && (freq <= 5805))) {
+ WRITE_RADIO_REG4(pi, RADIO_2057, CORE,
+ 0, IPA5G_BIAS_FILTER,
+ 0xff);
+ WRITE_RADIO_REG4(pi, RADIO_2057, CORE,
+ 1, IPA5G_BIAS_FILTER,
+ 0xff);
+ }
+ }
+ } else {
+
+ if (pi->pubpi.radiorev != 5) {
+ for (coreNum = 0; coreNum <= 1; coreNum++) {
+ WRITE_RADIO_REG4(pi, RADIO_2057, CORE,
+ coreNum,
+ TXMIX2G_TUNE_BOOST_PU,
+ 0x61);
+ WRITE_RADIO_REG4(pi, RADIO_2057, CORE,
+ coreNum,
+ TXGM_IDAC_BLEED, 0x70);
+ }
+ }
+ }
+
+ if (pi->pubpi.radiorev == 4) {
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1,
+ 0x05, 16,
+ &afectrl_adc_ctrl1_rev7);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1,
+ 0x15, 16,
+ &afectrl_adc_ctrl1_rev7);
+
+ for (coreNum = 0; coreNum <= 1; coreNum++) {
+ WRITE_RADIO_REG4(pi, RADIO_2057, CORE, coreNum,
+ AFE_VCM_CAL_MASTER, 0x0);
+ WRITE_RADIO_REG4(pi, RADIO_2057, CORE, coreNum,
+ AFE_SET_VCM_I, 0x3f);
+ WRITE_RADIO_REG4(pi, RADIO_2057, CORE, coreNum,
+ AFE_SET_VCM_Q, 0x3f);
+ }
+ } else {
+ mod_phy_reg(pi, 0xa6, (0x1 << 2), (0x1 << 2));
+ mod_phy_reg(pi, 0x8f, (0x1 << 2), (0x1 << 2));
+ mod_phy_reg(pi, 0xa7, (0x1 << 2), (0x1 << 2));
+ mod_phy_reg(pi, 0xa5, (0x1 << 2), (0x1 << 2));
+
+ mod_phy_reg(pi, 0xa6, (0x1 << 0), 0);
+ mod_phy_reg(pi, 0x8f, (0x1 << 0), (0x1 << 0));
+ mod_phy_reg(pi, 0xa7, (0x1 << 0), 0);
+ mod_phy_reg(pi, 0xa5, (0x1 << 0), (0x1 << 0));
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1,
+ 0x05, 16,
+ &afectrl_adc_ctrl2_rev7);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1,
+ 0x15, 16,
+ &afectrl_adc_ctrl2_rev7);
+
+ mod_phy_reg(pi, 0xa6, (0x1 << 2), 0);
+ mod_phy_reg(pi, 0x8f, (0x1 << 2), 0);
+ mod_phy_reg(pi, 0xa7, (0x1 << 2), 0);
+ mod_phy_reg(pi, 0xa5, (0x1 << 2), 0);
+ }
+
+ write_phy_reg(pi, 0x6a, 0x2);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, 256, 32,
+ &min_nvar_offset_6mbps);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x138, 16,
+ &rfseq_pktgn_lpf_hpc_rev7);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 1, 0x141, 16,
+ &rfseq_pktgn_lpf_h_hpc_rev7);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 3, 0x133, 16,
+ &rfseq_htpktgn_lpf_hpc_rev7);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x146, 16,
+ &rfseq_cckpktgn_lpf_hpc_rev7);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 1, 0x123, 16,
+ &rfseq_tx2rx_lpf_h_hpc_rev7);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 1, 0x12A, 16,
+ &rfseq_rx2tx_lpf_h_hpc_rev7);
+
+ if (CHSPEC_IS40(pi->radio_chanspec) == 0) {
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, 3,
+ 32, &min_nvar_val);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1,
+ 127, 32, &min_nvar_val);
+ } else {
+ min_nvar_val = noise_var_tbl_rev7[3];
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, 3,
+ 32, &min_nvar_val);
+
+ min_nvar_val = noise_var_tbl_rev7[127];
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1,
+ 127, 32, &min_nvar_val);
+ }
+
+ wlc_phy_workarounds_nphy_gainctrl(pi);
+
+ pdetrange =
+ (CHSPEC_IS5G(pi->radio_chanspec)) ? pi->srom_fem5g.
+ pdetrange : pi->srom_fem2g.pdetrange;
+
+ if (pdetrange == 0) {
+ chan_freq_range =
+ wlc_phy_get_chan_freq_range_nphy(pi, 0);
+ if (chan_freq_range != WL_CHAN_FREQ_RANGE_2G) {
+ aux_adc_vmid_rev7_core0[3] = 0x70;
+ aux_adc_vmid_rev7_core1[3] = 0x70;
+ aux_adc_gain_rev7[3] = 2;
+ } else {
+ aux_adc_vmid_rev7_core0[3] = 0x80;
+ aux_adc_vmid_rev7_core1[3] = 0x80;
+ aux_adc_gain_rev7[3] = 3;
+ }
+ } else if (pdetrange == 1) {
+ if (chan_freq_range != WL_CHAN_FREQ_RANGE_2G) {
+ aux_adc_vmid_rev7_core0[3] = 0x7c;
+ aux_adc_vmid_rev7_core1[3] = 0x7c;
+ aux_adc_gain_rev7[3] = 2;
+ } else {
+ aux_adc_vmid_rev7_core0[3] = 0x8c;
+ aux_adc_vmid_rev7_core1[3] = 0x8c;
+ aux_adc_gain_rev7[3] = 1;
+ }
+ } else if (pdetrange == 2) {
+ if (pi->pubpi.radioid == BCM2057_ID) {
+ if ((pi->pubpi.radiorev == 5)
+ || (pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8)) {
+ if (chan_freq_range ==
+ WL_CHAN_FREQ_RANGE_2G) {
+ aux_adc_vmid_rev7_core0[3] =
+ 0x8c;
+ aux_adc_vmid_rev7_core1[3] =
+ 0x8c;
+ aux_adc_gain_rev7[3] = 0;
+ } else {
+ aux_adc_vmid_rev7_core0[3] =
+ 0x96;
+ aux_adc_vmid_rev7_core1[3] =
+ 0x96;
+ aux_adc_gain_rev7[3] = 0;
+ }
+ }
+ }
+
+ } else if (pdetrange == 3) {
+ if (chan_freq_range == WL_CHAN_FREQ_RANGE_2G) {
+ aux_adc_vmid_rev7_core0[3] = 0x89;
+ aux_adc_vmid_rev7_core1[3] = 0x89;
+ aux_adc_gain_rev7[3] = 0;
+ }
+
+ } else if (pdetrange == 5) {
+
+ if (chan_freq_range != WL_CHAN_FREQ_RANGE_2G) {
+ aux_adc_vmid_rev7_core0[3] = 0x80;
+ aux_adc_vmid_rev7_core1[3] = 0x80;
+ aux_adc_gain_rev7[3] = 3;
+ } else {
+ aux_adc_vmid_rev7_core0[3] = 0x70;
+ aux_adc_vmid_rev7_core1[3] = 0x70;
+ aux_adc_gain_rev7[3] = 2;
+ }
+ }
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, 0x08, 16,
+ &aux_adc_vmid_rev7_core0);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, 0x18, 16,
+ &aux_adc_vmid_rev7_core1);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, 0x0c, 16,
+ &aux_adc_gain_rev7);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, 0x1c, 16,
+ &aux_adc_gain_rev7);
+
+ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+
+ write_phy_reg(pi, 0x23f, 0x1f8);
+ write_phy_reg(pi, 0x240, 0x1f8);
+
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL,
+ 1, 0, 32, &leg_data_weights);
+ leg_data_weights = leg_data_weights & 0xffffff;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL,
+ 1, 0, 32, &leg_data_weights);
+
+ alpha0 = 293;
+ alpha1 = 435;
+ alpha2 = 261;
+ beta0 = 366;
+ beta1 = 205;
+ beta2 = 32;
+ write_phy_reg(pi, 0x145, alpha0);
+ write_phy_reg(pi, 0x146, alpha1);
+ write_phy_reg(pi, 0x147, alpha2);
+ write_phy_reg(pi, 0x148, beta0);
+ write_phy_reg(pi, 0x149, beta1);
+ write_phy_reg(pi, 0x14a, beta2);
+
+ write_phy_reg(pi, 0x38, 0xC);
+ write_phy_reg(pi, 0x2ae, 0xC);
+
+ wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_TX2RX,
+ rfseq_tx2rx_events_rev3,
+ rfseq_tx2rx_dlys_rev3,
+ sizeof(rfseq_tx2rx_events_rev3) /
+ sizeof(rfseq_tx2rx_events_rev3[0]));
+
+ if (PHY_IPA(pi))
+ wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX,
+ rfseq_rx2tx_events_rev3_ipa,
+ rfseq_rx2tx_dlys_rev3_ipa,
+ sizeof
+ (rfseq_rx2tx_events_rev3_ipa) /
+ sizeof
+ (rfseq_rx2tx_events_rev3_ipa
+ [0]));
+
+ if ((pi->sh->hw_phyrxchain != 0x3) &&
+ (pi->sh->hw_phyrxchain != pi->sh->hw_phytxchain)) {
+
+ if (PHY_IPA(pi)) {
+ rfseq_rx2tx_dlys_rev3[5] = 59;
+ rfseq_rx2tx_dlys_rev3[6] = 1;
+ rfseq_rx2tx_events_rev3[7] =
+ NPHY_REV3_RFSEQ_CMD_END;
+ }
+
+ wlc_phy_set_rfseq_nphy(
+ pi, NPHY_RFSEQ_RX2TX,
+ rfseq_rx2tx_events_rev3,
+ rfseq_rx2tx_dlys_rev3,
+ sizeof(rfseq_rx2tx_events_rev3) /
+ sizeof(rfseq_rx2tx_events_rev3[0]));
+ }
+
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ write_phy_reg(pi, 0x6a, 0x2);
+ else
+ write_phy_reg(pi, 0x6a, 0x9c40);
+
+ mod_phy_reg(pi, 0x294, (0xf << 8), (7 << 8));
+
+ if (CHSPEC_IS40(pi->radio_chanspec) == 0) {
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, 3,
+ 32, &min_nvar_val);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1,
+ 127, 32, &min_nvar_val);
+ } else {
+ min_nvar_val = noise_var_tbl_rev3[3];
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, 3,
+ 32, &min_nvar_val);
+
+ min_nvar_val = noise_var_tbl_rev3[127];
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1,
+ 127, 32, &min_nvar_val);
+ }
+
+ wlc_phy_workarounds_nphy_gainctrl(pi);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x00, 16,
+ &dac_control);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x10, 16,
+ &dac_control);
+
+ pdetrange =
+ (CHSPEC_IS5G(pi->radio_chanspec)) ? pi->srom_fem5g.
+ pdetrange : pi->srom_fem2g.pdetrange;
+
+ if (pdetrange == 0) {
+ if (NREV_GE(pi->pubpi.phy_rev, 4)) {
+ aux_adc_vmid = aux_adc_vmid_rev4;
+ aux_adc_gain = aux_adc_gain_rev4;
+ } else {
+ aux_adc_vmid = aux_adc_vmid_rev3;
+ aux_adc_gain = aux_adc_gain_rev3;
+ }
+ chan_freq_range =
+ wlc_phy_get_chan_freq_range_nphy(pi, 0);
+ if (chan_freq_range != WL_CHAN_FREQ_RANGE_2G) {
+ switch (chan_freq_range) {
+ case WL_CHAN_FREQ_RANGE_5GL:
+ aux_adc_vmid[3] = 0x89;
+ aux_adc_gain[3] = 0;
+ break;
+ case WL_CHAN_FREQ_RANGE_5GM:
+ aux_adc_vmid[3] = 0x89;
+ aux_adc_gain[3] = 0;
+ break;
+ case WL_CHAN_FREQ_RANGE_5GH:
+ aux_adc_vmid[3] = 0x89;
+ aux_adc_gain[3] = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4,
+ 0x08, 16, aux_adc_vmid);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4,
+ 0x18, 16, aux_adc_vmid);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4,
+ 0x0c, 16, aux_adc_gain);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4,
+ 0x1c, 16, aux_adc_gain);
+ } else if (pdetrange == 1) {
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4,
+ 0x08, 16, sk_adc_vmid);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4,
+ 0x18, 16, sk_adc_vmid);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4,
+ 0x0c, 16, sk_adc_gain);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4,
+ 0x1c, 16, sk_adc_gain);
+ } else if (pdetrange == 2) {
+
+ u16 bcm_adc_vmid[] = { 0xa2, 0xb4, 0xb4, 0x74 };
+ u16 bcm_adc_gain[] = { 0x02, 0x02, 0x02, 0x04 };
+
+ if (NREV_GE(pi->pubpi.phy_rev, 6)) {
+ chan_freq_range =
+ wlc_phy_get_chan_freq_range_nphy(pi, 0);
+ if (chan_freq_range != WL_CHAN_FREQ_RANGE_2G) {
+ bcm_adc_vmid[3] = 0x8e;
+ bcm_adc_gain[3] = 0x03;
+ } else {
+ bcm_adc_vmid[3] = 0x94;
+ bcm_adc_gain[3] = 0x03;
+ }
+ } else if (NREV_IS(pi->pubpi.phy_rev, 5)) {
+ bcm_adc_vmid[3] = 0x84;
+ bcm_adc_gain[3] = 0x02;
+ }
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4,
+ 0x08, 16, bcm_adc_vmid);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4,
+ 0x18, 16, bcm_adc_vmid);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4,
+ 0x0c, 16, bcm_adc_gain);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4,
+ 0x1c, 16, bcm_adc_gain);
+ } else if (pdetrange == 3) {
+ chan_freq_range =
+ wlc_phy_get_chan_freq_range_nphy(pi, 0);
+ if ((NREV_GE(pi->pubpi.phy_rev, 4))
+ && (chan_freq_range == WL_CHAN_FREQ_RANGE_2G)) {
+
+ u16 auxadc_vmid[] = {
+ 0xa2, 0xb4, 0xb4, 0x270
+ };
+ u16 auxadc_gain[] = {
+ 0x02, 0x02, 0x02, 0x00
+ };
+
+ wlc_phy_table_write_nphy(pi,
+ NPHY_TBL_ID_AFECTRL, 4,
+ 0x08, 16, auxadc_vmid);
+ wlc_phy_table_write_nphy(pi,
+ NPHY_TBL_ID_AFECTRL, 4,
+ 0x18, 16, auxadc_vmid);
+ wlc_phy_table_write_nphy(pi,
+ NPHY_TBL_ID_AFECTRL, 4,
+ 0x0c, 16, auxadc_gain);
+ wlc_phy_table_write_nphy(pi,
+ NPHY_TBL_ID_AFECTRL, 4,
+ 0x1c, 16, auxadc_gain);
+ }
+ } else if ((pdetrange == 4) || (pdetrange == 5)) {
+ u16 bcm_adc_vmid[] = { 0xa2, 0xb4, 0xb4, 0x0 };
+ u16 bcm_adc_gain[] = { 0x02, 0x02, 0x02, 0x0 };
+ u16 Vmid[2], Av[2];
+
+ chan_freq_range =
+ wlc_phy_get_chan_freq_range_nphy(pi, 0);
+ if (chan_freq_range != WL_CHAN_FREQ_RANGE_2G) {
+ Vmid[0] = (pdetrange == 4) ? 0x8e : 0x89;
+ Vmid[1] = (pdetrange == 4) ? 0x96 : 0x89;
+ Av[0] = (pdetrange == 4) ? 2 : 0;
+ Av[1] = (pdetrange == 4) ? 2 : 0;
+ } else {
+ Vmid[0] = (pdetrange == 4) ? 0x89 : 0x74;
+ Vmid[1] = (pdetrange == 4) ? 0x8b : 0x70;
+ Av[0] = (pdetrange == 4) ? 2 : 0;
+ Av[1] = (pdetrange == 4) ? 2 : 0;
+ }
+
+ bcm_adc_vmid[3] = Vmid[0];
+ bcm_adc_gain[3] = Av[0];
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4,
+ 0x08, 16, bcm_adc_vmid);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4,
+ 0x0c, 16, bcm_adc_gain);
+
+ bcm_adc_vmid[3] = Vmid[1];
+ bcm_adc_gain[3] = Av[1];
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4,
+ 0x18, 16, bcm_adc_vmid);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4,
+ 0x1c, 16, bcm_adc_gain);
+ }
+
+ write_radio_reg(pi,
+ (RADIO_2056_RX_MIXA_MAST_BIAS | RADIO_2056_RX0),
+ 0x0);
+ write_radio_reg(pi,
+ (RADIO_2056_RX_MIXA_MAST_BIAS | RADIO_2056_RX1),
+ 0x0);
+
+ write_radio_reg(pi,
+ (RADIO_2056_RX_MIXA_BIAS_MAIN | RADIO_2056_RX0),
+ 0x6);
+ write_radio_reg(pi,
+ (RADIO_2056_RX_MIXA_BIAS_MAIN | RADIO_2056_RX1),
+ 0x6);
+
+ write_radio_reg(pi,
+ (RADIO_2056_RX_MIXA_BIAS_AUX | RADIO_2056_RX0),
+ 0x7);
+ write_radio_reg(pi,
+ (RADIO_2056_RX_MIXA_BIAS_AUX | RADIO_2056_RX1),
+ 0x7);
+
+ write_radio_reg(pi,
+ (RADIO_2056_RX_MIXA_LOB_BIAS | RADIO_2056_RX0),
+ 0x88);
+ write_radio_reg(pi,
+ (RADIO_2056_RX_MIXA_LOB_BIAS | RADIO_2056_RX1),
+ 0x88);
+
+ write_radio_reg(pi,
+ (RADIO_2056_RX_MIXA_CMFB_IDAC | RADIO_2056_RX0),
+ 0x0);
+ write_radio_reg(pi,
+ (RADIO_2056_RX_MIXA_CMFB_IDAC | RADIO_2056_RX1),
+ 0x0);
+
+ write_radio_reg(pi,
+ (RADIO_2056_RX_MIXG_CMFB_IDAC | RADIO_2056_RX0),
+ 0x0);
+ write_radio_reg(pi,
+ (RADIO_2056_RX_MIXG_CMFB_IDAC | RADIO_2056_RX1),
+ 0x0);
+
+ triso =
+ (CHSPEC_IS5G(pi->radio_chanspec)) ? pi->srom_fem5g.
+ triso : pi->srom_fem2g.triso;
+ if (triso == 7) {
+ wlc_phy_war_force_trsw_to_R_cliplo_nphy(pi, PHY_CORE_0);
+ wlc_phy_war_force_trsw_to_R_cliplo_nphy(pi, PHY_CORE_1);
+ }
+
+ wlc_phy_war_txchain_upd_nphy(pi, pi->sh->hw_phytxchain);
+
+ if (((pi->sh->boardflags2 & BFL2_APLL_WAR) &&
+ (CHSPEC_IS5G(pi->radio_chanspec))) ||
+ (((pi->sh->boardflags2 & BFL2_GPLL_WAR) ||
+ (pi->sh->boardflags2 & BFL2_GPLL_WAR2)) &&
+ (CHSPEC_IS2G(pi->radio_chanspec)))) {
+ nss1_data_weights = 0x00088888;
+ ht_data_weights = 0x00088888;
+ stbc_data_weights = 0x00088888;
+ } else {
+ nss1_data_weights = 0x88888888;
+ ht_data_weights = 0x88888888;
+ stbc_data_weights = 0x88888888;
+ }
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL,
+ 1, 1, 32, &nss1_data_weights);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL,
+ 1, 2, 32, &ht_data_weights);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL,
+ 1, 3, 32, &stbc_data_weights);
+
+ if (NREV_IS(pi->pubpi.phy_rev, 4)) {
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ write_radio_reg(pi,
+ RADIO_2056_TX_GMBB_IDAC |
+ RADIO_2056_TX0, 0x70);
+ write_radio_reg(pi,
+ RADIO_2056_TX_GMBB_IDAC |
+ RADIO_2056_TX1, 0x70);
+ }
+ }
+
+ if (!pi->edcrs_threshold_lock) {
+ write_phy_reg(pi, 0x224, 0x3eb);
+ write_phy_reg(pi, 0x225, 0x3eb);
+ write_phy_reg(pi, 0x226, 0x341);
+ write_phy_reg(pi, 0x227, 0x341);
+ write_phy_reg(pi, 0x228, 0x42b);
+ write_phy_reg(pi, 0x229, 0x42b);
+ write_phy_reg(pi, 0x22a, 0x381);
+ write_phy_reg(pi, 0x22b, 0x381);
+ write_phy_reg(pi, 0x22c, 0x42b);
+ write_phy_reg(pi, 0x22d, 0x42b);
+ write_phy_reg(pi, 0x22e, 0x381);
+ write_phy_reg(pi, 0x22f, 0x381);
+ }
+
+ if (NREV_GE(pi->pubpi.phy_rev, 6)) {
+
+ if (pi->sh->boardflags2 & BFL2_SINGLEANT_CCK)
+ wlapi_bmac_mhf(pi->sh->physhim, MHF4,
+ MHF4_BPHY_TXCORE0,
+ MHF4_BPHY_TXCORE0, BRCM_BAND_ALL);
+ }
+ } else {
+
+ if (pi->sh->boardflags2 & BFL2_SKWRKFEM_BRD ||
+ (pi->sh->boardtype == 0x8b)) {
+ uint i;
+ u8 war_dlys[] = { 1, 6, 6, 2, 4, 20, 1 };
+ for (i = 0; i < ARRAY_SIZE(rfseq_rx2tx_dlys); i++)
+ rfseq_rx2tx_dlys[i] = war_dlys[i];
+ }
+
+ if (CHSPEC_IS5G(pi->radio_chanspec) && pi->phy_5g_pwrgain) {
+ and_radio_reg(pi, RADIO_2055_CORE1_TX_RF_SPARE, 0xf7);
+ and_radio_reg(pi, RADIO_2055_CORE2_TX_RF_SPARE, 0xf7);
+ } else {
+ or_radio_reg(pi, RADIO_2055_CORE1_TX_RF_SPARE, 0x8);
+ or_radio_reg(pi, RADIO_2055_CORE2_TX_RF_SPARE, 0x8);
+ }
+
+ regval = 0x000a;
+ wlc_phy_table_write_nphy(pi, 8, 1, 0, 16, &regval);
+ wlc_phy_table_write_nphy(pi, 8, 1, 0x10, 16, &regval);
+
+ if (NREV_LT(pi->pubpi.phy_rev, 3)) {
+ regval = 0xcdaa;
+ wlc_phy_table_write_nphy(pi, 8, 1, 0x02, 16, &regval);
+ wlc_phy_table_write_nphy(pi, 8, 1, 0x12, 16, &regval);
+ }
+
+ if (NREV_LT(pi->pubpi.phy_rev, 2)) {
+ regval = 0x0000;
+ wlc_phy_table_write_nphy(pi, 8, 1, 0x08, 16, &regval);
+ wlc_phy_table_write_nphy(pi, 8, 1, 0x18, 16, &regval);
+
+ regval = 0x7aab;
+ wlc_phy_table_write_nphy(pi, 8, 1, 0x07, 16, &regval);
+ wlc_phy_table_write_nphy(pi, 8, 1, 0x17, 16, &regval);
+
+ regval = 0x0800;
+ wlc_phy_table_write_nphy(pi, 8, 1, 0x06, 16, &regval);
+ wlc_phy_table_write_nphy(pi, 8, 1, 0x16, 16, &regval);
+ }
+
+ write_phy_reg(pi, 0xf8, 0x02d8);
+ write_phy_reg(pi, 0xf9, 0x0301);
+ write_phy_reg(pi, 0xfa, 0x02d8);
+ write_phy_reg(pi, 0xfb, 0x0301);
+
+ wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX, rfseq_rx2tx_events,
+ rfseq_rx2tx_dlys,
+ sizeof(rfseq_rx2tx_events) /
+ sizeof(rfseq_rx2tx_events[0]));
+
+ wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_TX2RX, rfseq_tx2rx_events,
+ rfseq_tx2rx_dlys,
+ sizeof(rfseq_tx2rx_events) /
+ sizeof(rfseq_tx2rx_events[0]));
+
+ wlc_phy_workarounds_nphy_gainctrl(pi);
+
+ if (NREV_LT(pi->pubpi.phy_rev, 2)) {
+
+ if (read_phy_reg(pi, 0xa0) & NPHY_MLenable)
+ wlapi_bmac_mhf(pi->sh->physhim, MHF3,
+ MHF3_NPHY_MLADV_WAR,
+ MHF3_NPHY_MLADV_WAR,
+ BRCM_BAND_ALL);
+
+ } else if (NREV_IS(pi->pubpi.phy_rev, 2)) {
+ write_phy_reg(pi, 0x1e3, 0x0);
+ write_phy_reg(pi, 0x1e4, 0x0);
+ }
+
+ if (NREV_LT(pi->pubpi.phy_rev, 2))
+ mod_phy_reg(pi, 0x90, (0x1 << 7), 0);
+
+ alpha0 = 293;
+ alpha1 = 435;
+ alpha2 = 261;
+ beta0 = 366;
+ beta1 = 205;
+ beta2 = 32;
+ write_phy_reg(pi, 0x145, alpha0);
+ write_phy_reg(pi, 0x146, alpha1);
+ write_phy_reg(pi, 0x147, alpha2);
+ write_phy_reg(pi, 0x148, beta0);
+ write_phy_reg(pi, 0x149, beta1);
+ write_phy_reg(pi, 0x14a, beta2);
+
+ if (NREV_LT(pi->pubpi.phy_rev, 3)) {
+ mod_phy_reg(pi, 0x142, (0xf << 12), 0);
+
+ write_phy_reg(pi, 0x192, 0xb5);
+ write_phy_reg(pi, 0x193, 0xa4);
+ write_phy_reg(pi, 0x194, 0x0);
+ }
+
+ if (NREV_IS(pi->pubpi.phy_rev, 2))
+ mod_phy_reg(pi, 0x221,
+ NPHY_FORCESIG_DECODEGATEDCLKS,
+ NPHY_FORCESIG_DECODEGATEDCLKS);
+ }
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+}
+
+static void wlc_phy_extpa_set_tx_digi_filts_nphy(struct brcms_phy *pi)
+{
+ int j, type = 2;
+ u16 addr_offset = 0x2c5;
+
+ for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++)
+ write_phy_reg(pi, addr_offset + j,
+ NPHY_IPA_REV4_txdigi_filtcoeffs[type][j]);
+}
+
+static void wlc_phy_clip_det_nphy(struct brcms_phy *pi, u8 write, u16 *vals)
+{
+
+ if (write == 0) {
+ vals[0] = read_phy_reg(pi, 0x2c);
+ vals[1] = read_phy_reg(pi, 0x42);
+ } else {
+ write_phy_reg(pi, 0x2c, vals[0]);
+ write_phy_reg(pi, 0x42, vals[1]);
+ }
+}
+
+static void wlc_phy_ipa_internal_tssi_setup_nphy(struct brcms_phy *pi)
+{
+ u8 core;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TX_SSI_MASTER, 0x5);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TX_SSI_MUX, 0xe);
+
+ if (pi->pubpi.radiorev != 5)
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX,
+ core, TSSIA, 0);
+
+ if (!NREV_IS(pi->pubpi.phy_rev, 7))
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX,
+ core, TSSIG, 0x1);
+ else
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX,
+ core, TSSIG, 0x31);
+ } else {
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TX_SSI_MASTER, 0x9);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TX_SSI_MUX, 0xc);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TSSIG, 0);
+
+ if (pi->pubpi.radiorev != 5) {
+ if (!NREV_IS(pi->pubpi.phy_rev, 7))
+ WRITE_RADIO_REG3(pi, RADIO_2057,
+ TX, core,
+ TSSIA, 0x1);
+ else
+ WRITE_RADIO_REG3(pi, RADIO_2057,
+ TX, core,
+ TSSIA, 0x31);
+ }
+ }
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, IQCAL_VCM_HG,
+ 0);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, IQCAL_IDAC,
+ 0);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TSSI_VCM,
+ 0x3);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TSSI_MISC1,
+ 0x0);
+ }
+ } else {
+ WRITE_RADIO_SYN(pi, RADIO_2056, RESERVED_ADDR31,
+ (CHSPEC_IS2G(pi->radio_chanspec)) ? 0x128 :
+ 0x80);
+ WRITE_RADIO_SYN(pi, RADIO_2056, RESERVED_ADDR30, 0x0);
+ WRITE_RADIO_SYN(pi, RADIO_2056, GPIO_MASTER1, 0x29);
+
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, IQCAL_VCM_HG,
+ 0x0);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, IQCAL_IDAC,
+ 0x0);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TSSI_VCM,
+ 0x3);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TX_AMP_DET,
+ 0x0);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TSSI_MISC1,
+ 0x8);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TSSI_MISC2,
+ 0x0);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TSSI_MISC3,
+ 0x0);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ TX_SSI_MASTER, 0x5);
+
+ if (pi->pubpi.radiorev != 5)
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX,
+ core, TSSIA, 0x0);
+ if (NREV_GE(pi->pubpi.phy_rev, 5))
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX,
+ core, TSSIG, 0x31);
+ else
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX,
+ core, TSSIG, 0x11);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ TX_SSI_MUX, 0xe);
+ } else {
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ TX_SSI_MASTER, 0x9);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ TSSIA, 0x31);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ TSSIG, 0x0);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ TX_SSI_MUX, 0xc);
+ }
+ }
+ }
+}
+
+static void
+wlc_phy_rfctrl_override_nphy(struct brcms_phy *pi, u16 field, u16 value,
+ u8 core_mask, u8 off)
+{
+ u8 core_num;
+ u16 addr = 0, mask = 0, en_addr = 0, val_addr = 0, en_mask =
+ 0, val_mask = 0;
+ u8 shift = 0, val_shift = 0;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 7)) {
+
+ en_mask = field;
+ for (core_num = 0; core_num < 2; core_num++) {
+
+ switch (field) {
+ case (0x1 << 1):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a : 0x7d;
+ val_mask = (0x1 << 0);
+ val_shift = 0;
+ break;
+ case (0x1 << 2):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a : 0x7d;
+ val_mask = (0x1 << 1);
+ val_shift = 1;
+ break;
+ case (0x1 << 3):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a : 0x7d;
+ val_mask = (0x1 << 2);
+ val_shift = 2;
+ break;
+ case (0x1 << 4):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a : 0x7d;
+ val_mask = (0x1 << 4);
+ val_shift = 4;
+ break;
+ case (0x1 << 5):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a : 0x7d;
+ val_mask = (0x1 << 5);
+ val_shift = 5;
+ break;
+ case (0x1 << 6):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a : 0x7d;
+ val_mask = (0x1 << 6);
+ val_shift = 6;
+ break;
+ case (0x1 << 7):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a : 0x7d;
+ val_mask = (0x1 << 7);
+ val_shift = 7;
+ break;
+ case (0x1 << 8):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a : 0x7d;
+ val_mask = (0x7 << 8);
+ val_shift = 8;
+ break;
+ case (0x1 << 11):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a : 0x7d;
+ val_mask = (0x7 << 13);
+ val_shift = 13;
+ break;
+
+ case (0x1 << 9):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0xf8 : 0xfa;
+ val_mask = (0x7 << 0);
+ val_shift = 0;
+ break;
+
+ case (0x1 << 10):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0xf8 : 0xfa;
+ val_mask = (0x7 << 4);
+ val_shift = 4;
+ break;
+
+ case (0x1 << 12):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7b : 0x7e;
+ val_mask = (0xffff << 0);
+ val_shift = 0;
+ break;
+ case (0x1 << 13):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7c : 0x7f;
+ val_mask = (0xffff << 0);
+ val_shift = 0;
+ break;
+ case (0x1 << 14):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0xf9 : 0xfb;
+ val_mask = (0x3 << 6);
+ val_shift = 6;
+ break;
+ case (0x1 << 0):
+ en_addr = (core_num == 0) ? 0xe5 : 0xe6;
+ val_addr = (core_num == 0) ? 0xf9 : 0xfb;
+ val_mask = (0x1 << 15);
+ val_shift = 15;
+ break;
+ default:
+ addr = 0xffff;
+ break;
+ }
+
+ if (off) {
+ and_phy_reg(pi, en_addr, ~en_mask);
+ and_phy_reg(pi, val_addr, ~val_mask);
+ } else {
+
+ if ((core_mask == 0)
+ || (core_mask & (1 << core_num))) {
+ or_phy_reg(pi, en_addr, en_mask);
+
+ if (addr != 0xffff)
+ mod_phy_reg(pi, val_addr,
+ val_mask,
+ (value <<
+ val_shift));
+ }
+ }
+ }
+ } else {
+
+ if (off) {
+ and_phy_reg(pi, 0xec, ~field);
+ value = 0x0;
+ } else {
+ or_phy_reg(pi, 0xec, field);
+ }
+
+ for (core_num = 0; core_num < 2; core_num++) {
+
+ switch (field) {
+ case (0x1 << 1):
+ case (0x1 << 9):
+ case (0x1 << 12):
+ case (0x1 << 13):
+ case (0x1 << 14):
+ addr = 0x78;
+
+ core_mask = 0x1;
+ break;
+ case (0x1 << 2):
+ case (0x1 << 3):
+ case (0x1 << 4):
+ case (0x1 << 5):
+ case (0x1 << 6):
+ case (0x1 << 7):
+ case (0x1 << 8):
+ addr = (core_num == 0) ? 0x7a : 0x7d;
+ break;
+ case (0x1 << 10):
+ addr = (core_num == 0) ? 0x7b : 0x7e;
+ break;
+ case (0x1 << 11):
+ addr = (core_num == 0) ? 0x7c : 0x7f;
+ break;
+ default:
+ addr = 0xffff;
+ }
+
+ switch (field) {
+ case (0x1 << 1):
+ mask = (0x7 << 3);
+ shift = 3;
+ break;
+ case (0x1 << 9):
+ mask = (0x1 << 2);
+ shift = 2;
+ break;
+ case (0x1 << 12):
+ mask = (0x1 << 8);
+ shift = 8;
+ break;
+ case (0x1 << 13):
+ mask = (0x1 << 9);
+ shift = 9;
+ break;
+ case (0x1 << 14):
+ mask = (0xf << 12);
+ shift = 12;
+ break;
+ case (0x1 << 2):
+ mask = (0x1 << 0);
+ shift = 0;
+ break;
+ case (0x1 << 3):
+ mask = (0x1 << 1);
+ shift = 1;
+ break;
+ case (0x1 << 4):
+ mask = (0x1 << 2);
+ shift = 2;
+ break;
+ case (0x1 << 5):
+ mask = (0x3 << 4);
+ shift = 4;
+ break;
+ case (0x1 << 6):
+ mask = (0x3 << 6);
+ shift = 6;
+ break;
+ case (0x1 << 7):
+ mask = (0x1 << 8);
+ shift = 8;
+ break;
+ case (0x1 << 8):
+ mask = (0x1 << 9);
+ shift = 9;
+ break;
+ case (0x1 << 10):
+ mask = 0x1fff;
+ shift = 0x0;
+ break;
+ case (0x1 << 11):
+ mask = 0x1fff;
+ shift = 0x0;
+ break;
+ default:
+ mask = 0x0;
+ shift = 0x0;
+ break;
+ }
+
+ if ((addr != 0xffff) && (core_mask & (1 << core_num)))
+ mod_phy_reg(pi, addr, mask, (value << shift));
+ }
+
+ or_phy_reg(pi, 0xec, (0x1 << 0));
+ or_phy_reg(pi, 0x78, (0x1 << 0));
+ udelay(1);
+ and_phy_reg(pi, 0xec, ~(0x1 << 0));
+ }
+}
+
+static void wlc_phy_txpwrctrl_idle_tssi_nphy(struct brcms_phy *pi)
+{
+ s32 rssi_buf[4];
+ s32 int_val;
+
+ if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi) || PHY_MUTED(pi))
+
+ return;
+
+ if (PHY_IPA(pi))
+ wlc_phy_ipa_internal_tssi_setup_nphy(pi);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 12),
+ 0, 0x3, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ else if (NREV_GE(pi->pubpi.phy_rev, 3))
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 13), 0, 3, 0);
+
+ wlc_phy_stopplayback_nphy(pi);
+
+ wlc_phy_tx_tone_nphy(pi, 4000, 0, 0, 0, false);
+
+ udelay(20);
+ int_val =
+ wlc_phy_poll_rssi_nphy(pi, (u8) NPHY_RSSI_SEL_TSSI_2G, rssi_buf,
+ 1);
+ wlc_phy_stopplayback_nphy(pi);
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_OFF, 0);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 12),
+ 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ else if (NREV_GE(pi->pubpi.phy_rev, 3))
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 13), 0, 3, 1);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+
+ pi->nphy_pwrctrl_info[PHY_CORE_0].idle_tssi_2g =
+ (u8) ((int_val >> 24) & 0xff);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].idle_tssi_5g =
+ (u8) ((int_val >> 24) & 0xff);
+
+ pi->nphy_pwrctrl_info[PHY_CORE_1].idle_tssi_2g =
+ (u8) ((int_val >> 8) & 0xff);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].idle_tssi_5g =
+ (u8) ((int_val >> 8) & 0xff);
+ } else {
+ pi->nphy_pwrctrl_info[PHY_CORE_0].idle_tssi_2g =
+ (u8) ((int_val >> 24) & 0xff);
+
+ pi->nphy_pwrctrl_info[PHY_CORE_1].idle_tssi_2g =
+ (u8) ((int_val >> 8) & 0xff);
+
+ pi->nphy_pwrctrl_info[PHY_CORE_0].idle_tssi_5g =
+ (u8) ((int_val >> 16) & 0xff);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].idle_tssi_5g =
+ (u8) ((int_val) & 0xff);
+ }
+
+}
+
+static void wlc_phy_txpwr_limit_to_tbl_nphy(struct brcms_phy *pi)
+{
+ u8 idx, idx2, i, delta_ind;
+
+ for (idx = TXP_FIRST_CCK; idx <= TXP_LAST_CCK; idx++)
+ pi->adj_pwr_tbl_nphy[idx] = pi->tx_power_offset[idx];
+
+ for (i = 0; i < 4; i++) {
+ idx2 = 0;
+
+ delta_ind = 0;
+
+ switch (i) {
+ case 0:
+
+ if (CHSPEC_IS40(pi->radio_chanspec)
+ && NPHY_IS_SROM_REINTERPRET) {
+ idx = TXP_FIRST_MCS_40_SISO;
+ } else {
+ idx = (CHSPEC_IS40(pi->radio_chanspec)) ?
+ TXP_FIRST_OFDM_40_SISO : TXP_FIRST_OFDM;
+ delta_ind = 1;
+ }
+ break;
+
+ case 1:
+
+ idx = (CHSPEC_IS40(pi->radio_chanspec)) ?
+ TXP_FIRST_MCS_40_CDD : TXP_FIRST_MCS_20_CDD;
+ break;
+
+ case 2:
+
+ idx = (CHSPEC_IS40(pi->radio_chanspec)) ?
+ TXP_FIRST_MCS_40_STBC : TXP_FIRST_MCS_20_STBC;
+ break;
+
+ case 3:
+
+ idx = (CHSPEC_IS40(pi->radio_chanspec)) ?
+ TXP_FIRST_MCS_40_SDM : TXP_FIRST_MCS_20_SDM;
+ break;
+ }
+
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ idx = idx + delta_ind;
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx++];
+
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx++];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx++];
+
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx++];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx++];
+
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx++];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ idx = idx + 1 - delta_ind;
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ }
+}
+
+static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi)
+{
+ u32 idx;
+ s16 a1[2], b0[2], b1[2];
+ s8 target_pwr_qtrdbm[2];
+ s32 num, den, pwr_est;
+ u8 chan_freq_range;
+ u8 idle_tssi[2];
+ u32 tbl_id, tbl_len, tbl_offset;
+ u32 regval[64];
+ u8 core;
+
+ if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) {
+ wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, MCTL_PHYLOCK);
+ (void)R_REG(&pi->regs->maccontrol);
+ udelay(1);
+ }
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ or_phy_reg(pi, 0x122, (0x1 << 0));
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
+ and_phy_reg(pi, 0x1e7, (u16) (~(0x1 << 15)));
+ else
+ or_phy_reg(pi, 0x1e7, (0x1 << 15));
+
+ if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
+ wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, 0);
+
+ 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;
+ b0[1] = 5612;
+ b1[1] = -1393;
+ b1[0] = -1393;
+ } else {
+
+ chan_freq_range = wlc_phy_get_chan_freq_range_nphy(pi, 0);
+ switch (chan_freq_range) {
+ 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;
+ b0[1] = pi->nphy_pwrctrl_info[1].pwrdet_2g_b0;
+ b1[0] = pi->nphy_pwrctrl_info[0].pwrdet_2g_b1;
+ b1[1] = pi->nphy_pwrctrl_info[1].pwrdet_2g_b1;
+ break;
+ 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;
+ b0[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gl_b0;
+ b1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gl_b1;
+ b1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gl_b1;
+ break;
+ 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;
+ b0[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gm_b0;
+ b1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gm_b1;
+ b1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gm_b1;
+ break;
+ 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;
+ b0[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gh_b0;
+ b1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gh_b1;
+ b1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gh_b1;
+ break;
+ 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;
+ b0[1] = 5612;
+ b1[1] = -1393;
+ b1[0] = -1393;
+ break;
+ }
+ }
+
+ target_pwr_qtrdbm[0] = (s8) pi->tx_power_max;
+ target_pwr_qtrdbm[1] = (s8) pi->tx_power_max;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ if (pi->srom_fem2g.tssipos)
+ or_phy_reg(pi, 0x1e9, (0x1 << 14));
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ for (core = 0; core <= 1; core++) {
+ if (PHY_IPA(pi)) {
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ WRITE_RADIO_REG3(pi, RADIO_2057,
+ TX, core,
+ TX_SSI_MUX,
+ 0xe);
+ else
+ WRITE_RADIO_REG3(pi, RADIO_2057,
+ TX, core,
+ TX_SSI_MUX,
+ 0xc);
+ }
+ }
+ } else {
+ if (PHY_IPA(pi)) {
+
+ write_radio_reg(pi, RADIO_2056_TX_TX_SSI_MUX |
+ RADIO_2056_TX0,
+ (CHSPEC_IS5G
+ (pi->radio_chanspec)) ?
+ 0xc : 0xe);
+ write_radio_reg(pi,
+ RADIO_2056_TX_TX_SSI_MUX |
+ RADIO_2056_TX1,
+ (CHSPEC_IS5G
+ (pi->radio_chanspec)) ?
+ 0xc : 0xe);
+ } else {
+
+ write_radio_reg(pi, RADIO_2056_TX_TX_SSI_MUX |
+ RADIO_2056_TX0, 0x11);
+ write_radio_reg(pi, RADIO_2056_TX_TX_SSI_MUX |
+ RADIO_2056_TX1, 0x11);
+ }
+ }
+ }
+
+ if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) {
+ wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, MCTL_PHYLOCK);
+ (void)R_REG(&pi->regs->maccontrol);
+ udelay(1);
+ }
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ mod_phy_reg(pi, 0x1e7, (0x7f << 0),
+ (NPHY_TxPwrCtrlCmd_pwrIndex_init_rev7 << 0));
+ else
+ mod_phy_reg(pi, 0x1e7, (0x7f << 0),
+ (NPHY_TxPwrCtrlCmd_pwrIndex_init << 0));
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ mod_phy_reg(pi, 0x222, (0xff << 0),
+ (NPHY_TxPwrCtrlCmd_pwrIndex_init_rev7 << 0));
+ else if (NREV_GT(pi->pubpi.phy_rev, 1))
+ mod_phy_reg(pi, 0x222, (0xff << 0),
+ (NPHY_TxPwrCtrlCmd_pwrIndex_init << 0));
+
+ if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
+ wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, 0);
+
+ write_phy_reg(pi, 0x1e8, (0x3 << 8) | (240 << 0));
+
+ write_phy_reg(pi, 0x1e9,
+ (1 << 15) | (idle_tssi[0] << 0) | (idle_tssi[1] << 8));
+
+ write_phy_reg(pi, 0x1ea,
+ (target_pwr_qtrdbm[0] << 0) |
+ (target_pwr_qtrdbm[1] << 8));
+
+ tbl_len = 64;
+ tbl_offset = 0;
+ for (tbl_id = NPHY_TBL_ID_CORE1TXPWRCTL;
+ tbl_id <= NPHY_TBL_ID_CORE2TXPWRCTL; tbl_id++) {
+
+ for (idx = 0; idx < tbl_len; idx++) {
+ num = 8 *
+ (16 * b0[tbl_id - 26] + b1[tbl_id - 26] * idx);
+ den = 32768 + a1[tbl_id - 26] * idx;
+ pwr_est = max(((4 * num + den / 2) / den), -8);
+ if (NREV_LT(pi->pubpi.phy_rev, 3)) {
+ if (idx <=
+ (uint) (31 - idle_tssi[tbl_id - 26] + 1))
+ pwr_est =
+ max(pwr_est,
+ target_pwr_qtrdbm
+ [tbl_id - 26] + 1);
+ }
+ regval[idx] = (u32) pwr_est;
+ }
+ wlc_phy_table_write_nphy(pi, tbl_id, tbl_len, tbl_offset, 32,
+ regval);
+ }
+
+ wlc_phy_txpwr_limit_to_tbl_nphy(pi);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE1TXPWRCTL, 84, 64, 8,
+ pi->adj_pwr_tbl_nphy);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE2TXPWRCTL, 84, 64, 8,
+ pi->adj_pwr_tbl_nphy);
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+}
+
+static u32 *wlc_phy_get_ipa_gaintbl_nphy(struct brcms_phy *pi)
+{
+ u32 *tx_pwrctrl_tbl = NULL;
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if ((pi->pubpi.radiorev == 4)
+ || (pi->pubpi.radiorev == 6))
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_ipa_2g_2057rev4n6;
+ else if (pi->pubpi.radiorev == 3)
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_ipa_2g_2057rev3;
+ else if (pi->pubpi.radiorev == 5)
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_ipa_2g_2057rev5;
+ else if ((pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8))
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_ipa_2g_2057rev7;
+ } else if (NREV_IS(pi->pubpi.phy_rev, 6)) {
+ tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_rev6;
+ } else if (NREV_IS(pi->pubpi.phy_rev, 5)) {
+ tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_rev5;
+ } else {
+ tx_pwrctrl_tbl = nphy_tpc_txgain_ipa;
+ }
+ } else {
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if ((pi->pubpi.radiorev == 3) ||
+ (pi->pubpi.radiorev == 4) ||
+ (pi->pubpi.radiorev == 6))
+ tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_5g_2057;
+ else if ((pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8))
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_ipa_5g_2057rev7;
+ } else {
+ tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_5g;
+ }
+ }
+
+ return tx_pwrctrl_tbl;
+}
+
+static void wlc_phy_restore_rssical_nphy(struct brcms_phy *pi)
+{
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if (pi->nphy_rssical_chanspec_2G == 0)
+ return;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ mod_radio_reg(pi, RADIO_2057_NB_MASTER_CORE0,
+ RADIO_2057_VCM_MASK,
+ pi->rssical_cache.
+ rssical_radio_regs_2G[0]);
+ mod_radio_reg(pi, RADIO_2057_NB_MASTER_CORE1,
+ RADIO_2057_VCM_MASK,
+ pi->rssical_cache.
+ rssical_radio_regs_2G[1]);
+ } else {
+ mod_radio_reg(pi,
+ RADIO_2056_RX_RSSI_MISC | RADIO_2056_RX0,
+ RADIO_2056_VCM_MASK,
+ pi->rssical_cache.
+ rssical_radio_regs_2G[0]);
+ mod_radio_reg(pi,
+ RADIO_2056_RX_RSSI_MISC | RADIO_2056_RX1,
+ RADIO_2056_VCM_MASK,
+ pi->rssical_cache.
+ rssical_radio_regs_2G[1]);
+ }
+
+ write_phy_reg(pi, 0x1a6,
+ pi->rssical_cache.rssical_phyregs_2G[0]);
+ write_phy_reg(pi, 0x1ac,
+ pi->rssical_cache.rssical_phyregs_2G[1]);
+ write_phy_reg(pi, 0x1b2,
+ pi->rssical_cache.rssical_phyregs_2G[2]);
+ write_phy_reg(pi, 0x1b8,
+ pi->rssical_cache.rssical_phyregs_2G[3]);
+ write_phy_reg(pi, 0x1a4,
+ pi->rssical_cache.rssical_phyregs_2G[4]);
+ write_phy_reg(pi, 0x1aa,
+ pi->rssical_cache.rssical_phyregs_2G[5]);
+ write_phy_reg(pi, 0x1b0,
+ pi->rssical_cache.rssical_phyregs_2G[6]);
+ write_phy_reg(pi, 0x1b6,
+ pi->rssical_cache.rssical_phyregs_2G[7]);
+ write_phy_reg(pi, 0x1a5,
+ pi->rssical_cache.rssical_phyregs_2G[8]);
+ write_phy_reg(pi, 0x1ab,
+ pi->rssical_cache.rssical_phyregs_2G[9]);
+ write_phy_reg(pi, 0x1b1,
+ pi->rssical_cache.rssical_phyregs_2G[10]);
+ write_phy_reg(pi, 0x1b7,
+ pi->rssical_cache.rssical_phyregs_2G[11]);
+
+ } else {
+ if (pi->nphy_rssical_chanspec_5G == 0)
+ return;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ mod_radio_reg(pi, RADIO_2057_NB_MASTER_CORE0,
+ RADIO_2057_VCM_MASK,
+ pi->rssical_cache.
+ rssical_radio_regs_5G[0]);
+ mod_radio_reg(pi, RADIO_2057_NB_MASTER_CORE1,
+ RADIO_2057_VCM_MASK,
+ pi->rssical_cache.
+ rssical_radio_regs_5G[1]);
+ } else {
+ mod_radio_reg(pi,
+ RADIO_2056_RX_RSSI_MISC | RADIO_2056_RX0,
+ RADIO_2056_VCM_MASK,
+ pi->rssical_cache.
+ rssical_radio_regs_5G[0]);
+ mod_radio_reg(pi,
+ RADIO_2056_RX_RSSI_MISC | RADIO_2056_RX1,
+ RADIO_2056_VCM_MASK,
+ pi->rssical_cache.
+ rssical_radio_regs_5G[1]);
+ }
+
+ write_phy_reg(pi, 0x1a6,
+ pi->rssical_cache.rssical_phyregs_5G[0]);
+ write_phy_reg(pi, 0x1ac,
+ pi->rssical_cache.rssical_phyregs_5G[1]);
+ write_phy_reg(pi, 0x1b2,
+ pi->rssical_cache.rssical_phyregs_5G[2]);
+ write_phy_reg(pi, 0x1b8,
+ pi->rssical_cache.rssical_phyregs_5G[3]);
+ write_phy_reg(pi, 0x1a4,
+ pi->rssical_cache.rssical_phyregs_5G[4]);
+ write_phy_reg(pi, 0x1aa,
+ pi->rssical_cache.rssical_phyregs_5G[5]);
+ write_phy_reg(pi, 0x1b0,
+ pi->rssical_cache.rssical_phyregs_5G[6]);
+ write_phy_reg(pi, 0x1b6,
+ pi->rssical_cache.rssical_phyregs_5G[7]);
+ write_phy_reg(pi, 0x1a5,
+ pi->rssical_cache.rssical_phyregs_5G[8]);
+ write_phy_reg(pi, 0x1ab,
+ pi->rssical_cache.rssical_phyregs_5G[9]);
+ write_phy_reg(pi, 0x1b1,
+ pi->rssical_cache.rssical_phyregs_5G[10]);
+ write_phy_reg(pi, 0x1b7,
+ pi->rssical_cache.rssical_phyregs_5G[11]);
+ }
+}
+
+static void wlc_phy_internal_cal_txgain_nphy(struct brcms_phy *pi)
+{
+ u16 txcal_gain[2];
+
+ pi->nphy_txcal_pwr_idx[0] = pi->nphy_cal_orig_pwr_idx[0];
+ pi->nphy_txcal_pwr_idx[1] = pi->nphy_cal_orig_pwr_idx[0];
+ wlc_phy_txpwr_index_nphy(pi, 1, pi->nphy_cal_orig_pwr_idx[0], true);
+ wlc_phy_txpwr_index_nphy(pi, 2, pi->nphy_cal_orig_pwr_idx[1], true);
+
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16,
+ txcal_gain);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ txcal_gain[0] = (txcal_gain[0] & 0xF000) | 0x0F40;
+ txcal_gain[1] = (txcal_gain[1] & 0xF000) | 0x0F40;
+ } else {
+ txcal_gain[0] = (txcal_gain[0] & 0xF000) | 0x0F60;
+ txcal_gain[1] = (txcal_gain[1] & 0xF000) | 0x0F60;
+ }
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16,
+ txcal_gain);
+}
+
+static void wlc_phy_precal_txgain_nphy(struct brcms_phy *pi)
+{
+ bool save_bbmult = false;
+ u8 txcal_index_2057_rev5n7 = 0;
+ u8 txcal_index_2057_rev3n4n6 = 10;
+
+ if (pi->use_int_tx_iqlo_cal_nphy) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if ((pi->pubpi.radiorev == 3) ||
+ (pi->pubpi.radiorev == 4) ||
+ (pi->pubpi.radiorev == 6)) {
+
+ pi->nphy_txcal_pwr_idx[0] =
+ txcal_index_2057_rev3n4n6;
+ pi->nphy_txcal_pwr_idx[1] =
+ txcal_index_2057_rev3n4n6;
+ wlc_phy_txpwr_index_nphy(
+ pi, 3,
+ txcal_index_2057_rev3n4n6,
+ false);
+ } else {
+
+ pi->nphy_txcal_pwr_idx[0] =
+ txcal_index_2057_rev5n7;
+ pi->nphy_txcal_pwr_idx[1] =
+ txcal_index_2057_rev5n7;
+ wlc_phy_txpwr_index_nphy(
+ pi, 3,
+ txcal_index_2057_rev5n7,
+ false);
+ }
+ save_bbmult = true;
+
+ } else if (NREV_LT(pi->pubpi.phy_rev, 5)) {
+ wlc_phy_cal_txgainctrl_nphy(pi, 11, false);
+ if (pi->sh->hw_phytxchain != 3) {
+ pi->nphy_txcal_pwr_idx[1] =
+ pi->nphy_txcal_pwr_idx[0];
+ wlc_phy_txpwr_index_nphy(pi, 3,
+ pi->
+ nphy_txcal_pwr_idx[0],
+ true);
+ save_bbmult = true;
+ }
+
+ } else if (NREV_IS(pi->pubpi.phy_rev, 5)) {
+ if (PHY_IPA(pi)) {
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ wlc_phy_cal_txgainctrl_nphy(pi, 12,
+ false);
+ } else {
+ pi->nphy_txcal_pwr_idx[0] = 80;
+ pi->nphy_txcal_pwr_idx[1] = 80;
+ wlc_phy_txpwr_index_nphy(pi, 3, 80,
+ false);
+ save_bbmult = true;
+ }
+ } else {
+ wlc_phy_internal_cal_txgain_nphy(pi);
+ save_bbmult = true;
+ }
+
+ } else if (NREV_IS(pi->pubpi.phy_rev, 6)) {
+ if (PHY_IPA(pi)) {
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ wlc_phy_cal_txgainctrl_nphy(pi, 12,
+ false);
+ else
+ wlc_phy_cal_txgainctrl_nphy(pi, 14,
+ false);
+ } else {
+ wlc_phy_internal_cal_txgain_nphy(pi);
+ save_bbmult = true;
+ }
+ }
+
+ } else {
+ wlc_phy_cal_txgainctrl_nphy(pi, 10, false);
+ }
+
+ if (save_bbmult)
+ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16,
+ &pi->nphy_txcal_bbmult);
+}
+
+static void
+wlc_phy_rfctrlintc_override_nphy(struct brcms_phy *pi, u8 field, u16 value,
+ u8 core_code)
+{
+ u16 mask;
+ u16 val;
+ u8 core;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+ if (core_code == RADIO_MIMO_CORESEL_CORE1
+ && core == PHY_CORE_1)
+ continue;
+ else if (core_code == RADIO_MIMO_CORESEL_CORE2
+ && core == PHY_CORE_0)
+ continue;
+
+ if (NREV_LT(pi->pubpi.phy_rev, 7)) {
+
+ mask = (0x1 << 10);
+ val = 1 << 10;
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x91 :
+ 0x92, mask, val);
+ }
+
+ if (field == NPHY_RfctrlIntc_override_OFF) {
+
+ write_phy_reg(pi, (core == PHY_CORE_0) ? 0x91 :
+ 0x92, 0);
+
+ wlc_phy_force_rfseq_nphy(pi,
+ NPHY_RFSEQ_RESET2RX);
+ } else if (field == NPHY_RfctrlIntc_override_TRSW) {
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ mask = (0x1 << 6) | (0x1 << 7);
+
+ val = value << 6;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91 : 0x92,
+ mask, val);
+
+ or_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91 : 0x92,
+ (0x1 << 10));
+
+ and_phy_reg(pi, 0x2ff, (u16)
+ ~(0x3 << 14));
+ or_phy_reg(pi, 0x2ff, (0x1 << 13));
+ or_phy_reg(pi, 0x2ff, (0x1 << 0));
+ } else {
+
+ mask = (0x1 << 6) |
+ (0x1 << 7) |
+ (0x1 << 8) | (0x1 << 9);
+ val = value << 6;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91 : 0x92,
+ mask, val);
+
+ mask = (0x1 << 0);
+ val = 1 << 0;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0xe7 : 0xec,
+ mask, val);
+
+ mask = (core == PHY_CORE_0) ?
+ (0x1 << 0) : (0x1 << 1);
+ val = 1 << ((core == PHY_CORE_0) ?
+ 0 : 1);
+ mod_phy_reg(pi, 0x78, mask, val);
+
+ SPINWAIT(((read_phy_reg(pi, 0x78) & val)
+ != 0), 10000);
+ if (WARN(read_phy_reg(pi, 0x78) & val,
+ "HW error: override failed"))
+ return;
+
+ mask = (0x1 << 0);
+ val = 0 << 0;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0xe7 : 0xec,
+ mask, val);
+ }
+ } else if (field == NPHY_RfctrlIntc_override_PA) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ mask = (0x1 << 4) | (0x1 << 5);
+
+ if (CHSPEC_IS5G(pi->radio_chanspec))
+ val = value << 5;
+ else
+ val = value << 4;
+
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91 : 0x92,
+ mask, val);
+
+ or_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91 : 0x92,
+ (0x1 << 12));
+ } else {
+
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ mask = (0x1 << 5);
+ val = value << 5;
+ } else {
+ mask = (0x1 << 4);
+ val = value << 4;
+ }
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91 : 0x92,
+ mask, val);
+ }
+ } else if (field ==
+ NPHY_RfctrlIntc_override_EXT_LNA_PU) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+
+ mask = (0x1 << 0);
+ val = value << 0;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91
+ : 0x92, mask, val);
+
+ mask = (0x1 << 2);
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91
+ : 0x92, mask, 0);
+ } else {
+
+ mask = (0x1 << 2);
+ val = value << 2;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91
+ : 0x92, mask, val);
+
+ mask = (0x1 << 0);
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91
+ : 0x92, mask, 0);
+ }
+
+ mask = (0x1 << 11);
+ val = 1 << 11;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91 : 0x92,
+ mask, val);
+ } else {
+
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ mask = (0x1 << 0);
+ val = value << 0;
+ } else {
+ mask = (0x1 << 2);
+ val = value << 2;
+ }
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91 : 0x92,
+ mask, val);
+ }
+ } else if (field ==
+ NPHY_RfctrlIntc_override_EXT_LNA_GAIN) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+
+ mask = (0x1 << 1);
+ val = value << 1;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91
+ : 0x92, mask, val);
+
+ mask = (0x1 << 3);
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91
+ : 0x92, mask, 0);
+ } else {
+
+ mask = (0x1 << 3);
+ val = value << 3;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91
+ : 0x92, mask, val);
+
+ mask = (0x1 << 1);
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91
+ : 0x92, mask, 0);
+ }
+
+ mask = (0x1 << 11);
+ val = 1 << 11;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91 : 0x92,
+ mask, val);
+ } else {
+
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ mask = (0x1 << 1);
+ val = value << 1;
+ } else {
+ mask = (0x1 << 3);
+ val = value << 3;
+ }
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91 : 0x92,
+ mask, val);
+ }
+ }
+ }
+ }
+}
+
+void
+wlc_phy_cal_txgainctrl_nphy(struct brcms_phy *pi, s32 dBm_targetpower,
+ bool debug)
+{
+ int gainctrl_loopidx;
+ uint core;
+ u16 m0m1, curr_m0m1;
+ s32 delta_power;
+ s32 txpwrindex;
+ s32 qdBm_power[2];
+ u16 orig_BBConfig;
+ u16 phy_saveregs[4];
+ u32 freq_test;
+ u16 ampl_test = 250;
+ uint stepsize;
+ bool phyhang_avoid_state = false;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ stepsize = 2;
+ else
+ stepsize = 1;
+
+ if (CHSPEC_IS40(pi->radio_chanspec))
+ freq_test = 5000;
+ else
+ freq_test = 2500;
+
+ wlc_phy_txpwr_index_nphy(pi, 1, pi->nphy_cal_orig_pwr_idx[0], true);
+ wlc_phy_txpwr_index_nphy(pi, 2, pi->nphy_cal_orig_pwr_idx[1], true);
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ phyhang_avoid_state = pi->phyhang_avoid;
+ pi->phyhang_avoid = false;
+
+ phy_saveregs[0] = read_phy_reg(pi, 0x91);
+ phy_saveregs[1] = read_phy_reg(pi, 0x92);
+ phy_saveregs[2] = read_phy_reg(pi, 0xe7);
+ phy_saveregs[3] = read_phy_reg(pi, 0xec);
+ wlc_phy_rfctrlintc_override_nphy(pi, NPHY_RfctrlIntc_override_PA, 1,
+ RADIO_MIMO_CORESEL_CORE1 |
+ RADIO_MIMO_CORESEL_CORE2);
+
+ if (!debug) {
+ wlc_phy_rfctrlintc_override_nphy(pi,
+ NPHY_RfctrlIntc_override_TRSW,
+ 0x2, RADIO_MIMO_CORESEL_CORE1);
+ wlc_phy_rfctrlintc_override_nphy(pi,
+ NPHY_RfctrlIntc_override_TRSW,
+ 0x8, RADIO_MIMO_CORESEL_CORE2);
+ } else {
+ wlc_phy_rfctrlintc_override_nphy(pi,
+ NPHY_RfctrlIntc_override_TRSW,
+ 0x1, RADIO_MIMO_CORESEL_CORE1);
+ wlc_phy_rfctrlintc_override_nphy(pi,
+ NPHY_RfctrlIntc_override_TRSW,
+ 0x7, RADIO_MIMO_CORESEL_CORE2);
+ }
+
+ orig_BBConfig = read_phy_reg(pi, 0x01);
+ mod_phy_reg(pi, 0x01, (0x1 << 15), 0);
+
+ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &m0m1);
+
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+ txpwrindex = (s32) pi->nphy_cal_orig_pwr_idx[core];
+
+ for (gainctrl_loopidx = 0; gainctrl_loopidx < 2;
+ gainctrl_loopidx++) {
+ wlc_phy_tx_tone_nphy(pi, freq_test, ampl_test, 0, 0,
+ false);
+
+ if (core == PHY_CORE_0)
+ curr_m0m1 = m0m1 & 0xff00;
+ else
+ curr_m0m1 = m0m1 & 0x00ff;
+
+ wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &curr_m0m1);
+ wlc_phy_table_write_nphy(pi, 15, 1, 95, 16, &curr_m0m1);
+
+ udelay(50);
+
+ wlc_phy_est_tonepwr_nphy(pi, qdBm_power,
+ NPHY_CAL_TSSISAMPS);
+
+ pi->nphy_bb_mult_save = 0;
+ wlc_phy_stopplayback_nphy(pi);
+
+ delta_power = (dBm_targetpower * 4) - qdBm_power[core];
+
+ txpwrindex -= stepsize * delta_power;
+ if (txpwrindex < 0)
+ txpwrindex = 0;
+ else if (txpwrindex > 127)
+ txpwrindex = 127;
+
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ if (NREV_IS(pi->pubpi.phy_rev, 4) &&
+ (pi->srom_fem5g.extpagain == 3)) {
+ if (txpwrindex < 30)
+ txpwrindex = 30;
+ }
+ } else {
+ if (NREV_GE(pi->pubpi.phy_rev, 5) &&
+ (pi->srom_fem2g.extpagain == 3)) {
+ if (txpwrindex < 50)
+ txpwrindex = 50;
+ }
+ }
+
+ wlc_phy_txpwr_index_nphy(pi, (1 << core),
+ (u8) txpwrindex, true);
+ }
+
+ pi->nphy_txcal_pwr_idx[core] = (u8) txpwrindex;
+
+ if (debug) {
+ u16 radio_gain;
+ u16 dbg_m0m1;
+
+ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &dbg_m0m1);
+
+ wlc_phy_tx_tone_nphy(pi, freq_test, ampl_test, 0, 0,
+ false);
+
+ wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &dbg_m0m1);
+ wlc_phy_table_write_nphy(pi, 15, 1, 95, 16, &dbg_m0m1);
+
+ udelay(100);
+
+ wlc_phy_est_tonepwr_nphy(pi, qdBm_power,
+ NPHY_CAL_TSSISAMPS);
+
+ wlc_phy_table_read_nphy(pi, 7, 1, (0x110 + core), 16,
+ &radio_gain);
+
+ mdelay(4000);
+ pi->nphy_bb_mult_save = 0;
+ wlc_phy_stopplayback_nphy(pi);
+ }
+ }
+
+ wlc_phy_txpwr_index_nphy(pi, 1, pi->nphy_txcal_pwr_idx[0], true);
+ wlc_phy_txpwr_index_nphy(pi, 2, pi->nphy_txcal_pwr_idx[1], true);
+
+ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &pi->nphy_txcal_bbmult);
+
+ write_phy_reg(pi, 0x01, orig_BBConfig);
+
+ write_phy_reg(pi, 0x91, phy_saveregs[0]);
+ write_phy_reg(pi, 0x92, phy_saveregs[1]);
+ write_phy_reg(pi, 0xe7, phy_saveregs[2]);
+ write_phy_reg(pi, 0xec, phy_saveregs[3]);
+
+ pi->phyhang_avoid = phyhang_avoid_state;
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+}
+
+static void wlc_phy_savecal_nphy(struct brcms_phy *pi)
+{
+ void *tbl_ptr;
+ int coreNum;
+ u16 *txcal_radio_regs = NULL;
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+
+ wlc_phy_rx_iq_coeffs_nphy(pi, 0,
+ &pi->calibration_cache.
+ rxcal_coeffs_2G);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ txcal_radio_regs =
+ pi->calibration_cache.txcal_radio_regs_2G;
+ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+
+ pi->calibration_cache.txcal_radio_regs_2G[0] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_I |
+ RADIO_2056_TX0);
+ pi->calibration_cache.txcal_radio_regs_2G[1] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_Q |
+ RADIO_2056_TX0);
+ pi->calibration_cache.txcal_radio_regs_2G[2] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_I |
+ RADIO_2056_TX1);
+ pi->calibration_cache.txcal_radio_regs_2G[3] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_Q |
+ RADIO_2056_TX1);
+
+ pi->calibration_cache.txcal_radio_regs_2G[4] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_I |
+ RADIO_2056_TX0);
+ pi->calibration_cache.txcal_radio_regs_2G[5] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_Q |
+ RADIO_2056_TX0);
+ pi->calibration_cache.txcal_radio_regs_2G[6] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_I |
+ RADIO_2056_TX1);
+ pi->calibration_cache.txcal_radio_regs_2G[7] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_Q |
+ RADIO_2056_TX1);
+ } else {
+ pi->calibration_cache.txcal_radio_regs_2G[0] =
+ read_radio_reg(pi, RADIO_2055_CORE1_TX_VOS_CNCL);
+ pi->calibration_cache.txcal_radio_regs_2G[1] =
+ read_radio_reg(pi, RADIO_2055_CORE2_TX_VOS_CNCL);
+ pi->calibration_cache.txcal_radio_regs_2G[2] =
+ read_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM);
+ pi->calibration_cache.txcal_radio_regs_2G[3] =
+ read_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM);
+ }
+
+ pi->nphy_iqcal_chanspec_2G = pi->radio_chanspec;
+ tbl_ptr = pi->calibration_cache.txcal_coeffs_2G;
+ } else {
+
+ wlc_phy_rx_iq_coeffs_nphy(pi, 0,
+ &pi->calibration_cache.
+ rxcal_coeffs_5G);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ txcal_radio_regs =
+ pi->calibration_cache.txcal_radio_regs_5G;
+ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+
+ pi->calibration_cache.txcal_radio_regs_5G[0] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_I |
+ RADIO_2056_TX0);
+ pi->calibration_cache.txcal_radio_regs_5G[1] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_Q |
+ RADIO_2056_TX0);
+ pi->calibration_cache.txcal_radio_regs_5G[2] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_I |
+ RADIO_2056_TX1);
+ pi->calibration_cache.txcal_radio_regs_5G[3] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_Q |
+ RADIO_2056_TX1);
+
+ pi->calibration_cache.txcal_radio_regs_5G[4] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_I |
+ RADIO_2056_TX0);
+ pi->calibration_cache.txcal_radio_regs_5G[5] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_Q |
+ RADIO_2056_TX0);
+ pi->calibration_cache.txcal_radio_regs_5G[6] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_I |
+ RADIO_2056_TX1);
+ pi->calibration_cache.txcal_radio_regs_5G[7] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_Q |
+ RADIO_2056_TX1);
+ } else {
+ pi->calibration_cache.txcal_radio_regs_5G[0] =
+ read_radio_reg(pi, RADIO_2055_CORE1_TX_VOS_CNCL);
+ pi->calibration_cache.txcal_radio_regs_5G[1] =
+ read_radio_reg(pi, RADIO_2055_CORE2_TX_VOS_CNCL);
+ pi->calibration_cache.txcal_radio_regs_5G[2] =
+ read_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM);
+ pi->calibration_cache.txcal_radio_regs_5G[3] =
+ read_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM);
+ }
+
+ pi->nphy_iqcal_chanspec_5G = pi->radio_chanspec;
+ tbl_ptr = pi->calibration_cache.txcal_coeffs_5G;
+ }
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ for (coreNum = 0; coreNum <= 1; coreNum++) {
+
+ txcal_radio_regs[2 * coreNum] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
+ LOFT_FINE_I);
+ txcal_radio_regs[2 * coreNum + 1] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
+ LOFT_FINE_Q);
+
+ txcal_radio_regs[2 * coreNum + 4] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
+ LOFT_COARSE_I);
+ txcal_radio_regs[2 * coreNum + 5] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
+ LOFT_COARSE_Q);
+ }
+ }
+
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, 8, 80, 16, tbl_ptr);
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+}
+
+static void wlc_phy_tx_iq_war_nphy(struct brcms_phy *pi)
+{
+ struct nphy_iq_comp tx_comp;
+
+ wlc_phy_table_read_nphy(pi, 15, 4, 0x50, 16, &tx_comp);
+
+ wlapi_bmac_write_shm(pi->sh->physhim, M_20IN40_IQ, tx_comp.a0);
+ wlapi_bmac_write_shm(pi->sh->physhim, M_20IN40_IQ + 2, tx_comp.b0);
+ wlapi_bmac_write_shm(pi->sh->physhim, M_20IN40_IQ + 4, tx_comp.a1);
+ wlapi_bmac_write_shm(pi->sh->physhim, M_20IN40_IQ + 6, tx_comp.b1);
+}
+
+static void wlc_phy_restorecal_nphy(struct brcms_phy *pi)
+{
+ u16 *loft_comp;
+ u16 txcal_coeffs_bphy[4];
+ u16 *tbl_ptr;
+ int coreNum;
+ u16 *txcal_radio_regs = NULL;
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if (pi->nphy_iqcal_chanspec_2G == 0)
+ return;
+
+ tbl_ptr = pi->calibration_cache.txcal_coeffs_2G;
+ loft_comp = &pi->calibration_cache.txcal_coeffs_2G[5];
+ } else {
+ if (pi->nphy_iqcal_chanspec_5G == 0)
+ return;
+
+ tbl_ptr = pi->calibration_cache.txcal_coeffs_5G;
+ loft_comp = &pi->calibration_cache.txcal_coeffs_5G[5];
+ }
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 80, 16, tbl_ptr);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ txcal_coeffs_bphy[0] = tbl_ptr[0];
+ txcal_coeffs_bphy[1] = tbl_ptr[1];
+ txcal_coeffs_bphy[2] = tbl_ptr[2];
+ txcal_coeffs_bphy[3] = tbl_ptr[3];
+ } else {
+ txcal_coeffs_bphy[0] = 0;
+ txcal_coeffs_bphy[1] = 0;
+ txcal_coeffs_bphy[2] = 0;
+ txcal_coeffs_bphy[3] = 0;
+ }
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 88, 16,
+ txcal_coeffs_bphy);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 85, 16, loft_comp);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 93, 16, loft_comp);
+
+ if (NREV_LT(pi->pubpi.phy_rev, 2))
+ wlc_phy_tx_iq_war_nphy(pi);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ txcal_radio_regs =
+ pi->calibration_cache.txcal_radio_regs_2G;
+ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_I |
+ RADIO_2056_TX0,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[0]);
+ write_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_Q |
+ RADIO_2056_TX0,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[1]);
+ write_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_I |
+ RADIO_2056_TX1,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[2]);
+ write_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_Q |
+ RADIO_2056_TX1,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[3]);
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_I |
+ RADIO_2056_TX0,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[4]);
+ write_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_Q |
+ RADIO_2056_TX0,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[5]);
+ write_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_I |
+ RADIO_2056_TX1,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[6]);
+ write_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_Q |
+ RADIO_2056_TX1,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[7]);
+ } else {
+ write_radio_reg(pi, RADIO_2055_CORE1_TX_VOS_CNCL,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[0]);
+ write_radio_reg(pi, RADIO_2055_CORE2_TX_VOS_CNCL,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[1]);
+ write_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[2]);
+ write_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[3]);
+ }
+
+ wlc_phy_rx_iq_coeffs_nphy(pi, 1,
+ &pi->calibration_cache.
+ rxcal_coeffs_2G);
+ } else {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ txcal_radio_regs =
+ pi->calibration_cache.txcal_radio_regs_5G;
+ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_I |
+ RADIO_2056_TX0,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[0]);
+ write_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_Q |
+ RADIO_2056_TX0,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[1]);
+ write_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_I |
+ RADIO_2056_TX1,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[2]);
+ write_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_Q |
+ RADIO_2056_TX1,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[3]);
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_I |
+ RADIO_2056_TX0,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[4]);
+ write_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_Q |
+ RADIO_2056_TX0,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[5]);
+ write_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_I |
+ RADIO_2056_TX1,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[6]);
+ write_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_Q |
+ RADIO_2056_TX1,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[7]);
+ } else {
+ write_radio_reg(pi, RADIO_2055_CORE1_TX_VOS_CNCL,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[0]);
+ write_radio_reg(pi, RADIO_2055_CORE2_TX_VOS_CNCL,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[1]);
+ write_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[2]);
+ write_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[3]);
+ }
+
+ wlc_phy_rx_iq_coeffs_nphy(pi, 1,
+ &pi->calibration_cache.
+ rxcal_coeffs_5G);
+ }
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ for (coreNum = 0; coreNum <= 1; coreNum++) {
+
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
+ LOFT_FINE_I,
+ txcal_radio_regs[2 * coreNum]);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
+ LOFT_FINE_Q,
+ txcal_radio_regs[2 * coreNum + 1]);
+
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
+ LOFT_COARSE_I,
+ txcal_radio_regs[2 * coreNum + 4]);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
+ LOFT_COARSE_Q,
+ txcal_radio_regs[2 * coreNum + 5]);
+ }
+ }
+}
+
+static void wlc_phy_txpwrctrl_coeff_setup_nphy(struct brcms_phy *pi)
+{
+ u32 idx;
+ u16 iqloCalbuf[7];
+ u32 iqcomp, locomp, curr_locomp;
+ s8 locomp_i, locomp_q;
+ s8 curr_locomp_i, curr_locomp_q;
+ u32 tbl_id, tbl_len, tbl_offset;
+ u32 regval[128];
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ wlc_phy_table_read_nphy(pi, 15, 7, 80, 16, iqloCalbuf);
+
+ tbl_len = 128;
+ tbl_offset = 320;
+ for (tbl_id = NPHY_TBL_ID_CORE1TXPWRCTL;
+ tbl_id <= NPHY_TBL_ID_CORE2TXPWRCTL; tbl_id++) {
+ iqcomp =
+ (tbl_id ==
+ 26) ? (((u32) (iqloCalbuf[0] & 0x3ff)) << 10) |
+ (iqloCalbuf[1] & 0x3ff)
+ : (((u32) (iqloCalbuf[2] & 0x3ff)) << 10) |
+ (iqloCalbuf[3] & 0x3ff);
+
+ for (idx = 0; idx < tbl_len; idx++)
+ regval[idx] = iqcomp;
+ wlc_phy_table_write_nphy(pi, tbl_id, tbl_len, tbl_offset, 32,
+ regval);
+ }
+
+ tbl_offset = 448;
+ for (tbl_id = NPHY_TBL_ID_CORE1TXPWRCTL;
+ tbl_id <= NPHY_TBL_ID_CORE2TXPWRCTL; tbl_id++) {
+
+ locomp =
+ (u32) ((tbl_id == 26) ? iqloCalbuf[5] : iqloCalbuf[6]);
+ locomp_i = (s8) ((locomp >> 8) & 0xff);
+ locomp_q = (s8) ((locomp) & 0xff);
+ for (idx = 0; idx < tbl_len; idx++) {
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ curr_locomp_i = locomp_i;
+ curr_locomp_q = locomp_q;
+ } else {
+ curr_locomp_i = (s8) ((locomp_i *
+ nphy_tpc_loscale[idx] +
+ 128) >> 8);
+ curr_locomp_q =
+ (s8) ((locomp_q *
+ nphy_tpc_loscale[idx] +
+ 128) >> 8);
+ }
+ curr_locomp = (u32) ((curr_locomp_i & 0xff) << 8);
+ curr_locomp |= (u32) (curr_locomp_q & 0xff);
+ regval[idx] = curr_locomp;
+ }
+ wlc_phy_table_write_nphy(pi, tbl_id, tbl_len, tbl_offset, 32,
+ regval);
+ }
+
+ if (NREV_LT(pi->pubpi.phy_rev, 2)) {
+
+ wlapi_bmac_write_shm(pi->sh->physhim, M_CURR_IDX1, 0xFFFF);
+ wlapi_bmac_write_shm(pi->sh->physhim, M_CURR_IDX2, 0xFFFF);
+ }
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+}
+
+static void wlc_phy_txlpfbw_nphy(struct brcms_phy *pi)
+{
+ u8 tx_lpf_bw = 0;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 7)) {
+ if (CHSPEC_IS40(pi->radio_chanspec))
+ tx_lpf_bw = 3;
+ else
+ tx_lpf_bw = 1;
+
+ if (PHY_IPA(pi)) {
+ if (CHSPEC_IS40(pi->radio_chanspec))
+ tx_lpf_bw = 5;
+ else
+ tx_lpf_bw = 4;
+ }
+
+ write_phy_reg(pi, 0xe8,
+ (tx_lpf_bw << 0) |
+ (tx_lpf_bw << 3) |
+ (tx_lpf_bw << 6) | (tx_lpf_bw << 9));
+
+ if (PHY_IPA(pi)) {
+
+ if (CHSPEC_IS40(pi->radio_chanspec))
+ tx_lpf_bw = 4;
+ else
+ tx_lpf_bw = 1;
+
+ write_phy_reg(pi, 0xe9,
+ (tx_lpf_bw << 0) |
+ (tx_lpf_bw << 3) |
+ (tx_lpf_bw << 6) | (tx_lpf_bw << 9));
+ }
+ }
+}
+
+static void
+wlc_phy_adjust_rx_analpfbw_nphy(struct brcms_phy *pi, u16 reduction_factr)
+{
+ if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 7)) {
+ if ((CHSPEC_CHANNEL(pi->radio_chanspec) == 11) &&
+ CHSPEC_IS40(pi->radio_chanspec)) {
+ if (!pi->nphy_anarxlpf_adjusted) {
+ write_radio_reg(pi,
+ (RADIO_2056_RX_RXLPF_RCCAL_LPC |
+ RADIO_2056_RX0),
+ ((pi->nphy_rccal_value +
+ reduction_factr) | 0x80));
+
+ pi->nphy_anarxlpf_adjusted = true;
+ }
+ } else {
+ if (pi->nphy_anarxlpf_adjusted) {
+ write_radio_reg(pi,
+ (RADIO_2056_RX_RXLPF_RCCAL_LPC |
+ RADIO_2056_RX0),
+ (pi->nphy_rccal_value | 0x80));
+
+ pi->nphy_anarxlpf_adjusted = false;
+ }
+ }
+ }
+}
+
+static void
+wlc_phy_adjust_min_noisevar_nphy(struct brcms_phy *pi, int ntones,
+ int *tone_id_buf, u32 *noise_var_buf)
+{
+ int i;
+ u32 offset;
+ int tone_id;
+ int tbllen =
+ CHSPEC_IS40(pi->radio_chanspec) ?
+ NPHY_NOISEVAR_TBLLEN40 : NPHY_NOISEVAR_TBLLEN20;
+
+ if (pi->nphy_noisevars_adjusted) {
+ for (i = 0; i < pi->nphy_saved_noisevars.bufcount; i++) {
+ tone_id = pi->nphy_saved_noisevars.tone_id[i];
+ offset = (tone_id >= 0) ?
+ ((tone_id *
+ 2) + 1) : (tbllen + (tone_id * 2) + 1);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_NOISEVAR, 1,
+ offset, 32,
+ &pi->nphy_saved_noisevars.min_noise_vars[i]);
+ }
+
+ pi->nphy_saved_noisevars.bufcount = 0;
+ pi->nphy_noisevars_adjusted = false;
+ }
+
+ if ((noise_var_buf != NULL) && (tone_id_buf != NULL)) {
+ pi->nphy_saved_noisevars.bufcount = 0;
+
+ for (i = 0; i < ntones; i++) {
+ tone_id = tone_id_buf[i];
+ offset = (tone_id >= 0) ?
+ ((tone_id * 2) + 1) :
+ (tbllen + (tone_id * 2) + 1);
+ pi->nphy_saved_noisevars.tone_id[i] = tone_id;
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1,
+ offset, 32,
+ &pi->nphy_saved_noisevars.
+ min_noise_vars[i]);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1,
+ offset, 32, &noise_var_buf[i]);
+ pi->nphy_saved_noisevars.bufcount++;
+ }
+
+ pi->nphy_noisevars_adjusted = true;
+ }
+}
+
+static void wlc_phy_adjust_crsminpwr_nphy(struct brcms_phy *pi, u8 minpwr)
+{
+ u16 regval;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ if ((CHSPEC_CHANNEL(pi->radio_chanspec) == 11) &&
+ CHSPEC_IS40(pi->radio_chanspec)) {
+ if (!pi->nphy_crsminpwr_adjusted) {
+ regval = read_phy_reg(pi, 0x27d);
+ pi->nphy_crsminpwr[0] = regval & 0xff;
+ regval &= 0xff00;
+ regval |= (u16) minpwr;
+ write_phy_reg(pi, 0x27d, regval);
+
+ regval = read_phy_reg(pi, 0x280);
+ pi->nphy_crsminpwr[1] = regval & 0xff;
+ regval &= 0xff00;
+ regval |= (u16) minpwr;
+ write_phy_reg(pi, 0x280, regval);
+
+ regval = read_phy_reg(pi, 0x283);
+ pi->nphy_crsminpwr[2] = regval & 0xff;
+ regval &= 0xff00;
+ regval |= (u16) minpwr;
+ write_phy_reg(pi, 0x283, regval);
+
+ pi->nphy_crsminpwr_adjusted = true;
+ }
+ } else {
+ if (pi->nphy_crsminpwr_adjusted) {
+ regval = read_phy_reg(pi, 0x27d);
+ regval &= 0xff00;
+ regval |= pi->nphy_crsminpwr[0];
+ write_phy_reg(pi, 0x27d, regval);
+
+ regval = read_phy_reg(pi, 0x280);
+ regval &= 0xff00;
+ regval |= pi->nphy_crsminpwr[1];
+ write_phy_reg(pi, 0x280, regval);
+
+ regval = read_phy_reg(pi, 0x283);
+ regval &= 0xff00;
+ regval |= pi->nphy_crsminpwr[2];
+ write_phy_reg(pi, 0x283, regval);
+
+ pi->nphy_crsminpwr_adjusted = false;
+ }
+ }
+ }
+}
+
+static void wlc_phy_spurwar_nphy(struct brcms_phy *pi)
+{
+ u16 cur_channel = 0;
+ int nphy_adj_tone_id_buf[] = { 57, 58 };
+ u32 nphy_adj_noise_var_buf[] = { 0x3ff, 0x3ff };
+ bool isAdjustNoiseVar = false;
+ uint numTonesAdjust = 0;
+ u32 tempval = 0;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ cur_channel = CHSPEC_CHANNEL(pi->radio_chanspec);
+
+ if (pi->nphy_gband_spurwar_en) {
+
+ wlc_phy_adjust_rx_analpfbw_nphy(
+ pi,
+ NPHY_ANARXLPFBW_REDUCTIONFACT);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if ((cur_channel == 11)
+ && CHSPEC_IS40(pi->radio_chanspec))
+ wlc_phy_adjust_min_noisevar_nphy(
+ pi, 2,
+ nphy_adj_tone_id_buf,
+ nphy_adj_noise_var_buf);
+ else
+ wlc_phy_adjust_min_noisevar_nphy(pi, 0,
+ NULL,
+ NULL);
+ }
+
+ wlc_phy_adjust_crsminpwr_nphy(pi,
+ NPHY_ADJUSTED_MINCRSPOWER);
+ }
+
+ if ((pi->nphy_gband_spurwar2_en)
+ && CHSPEC_IS2G(pi->radio_chanspec)) {
+
+ if (CHSPEC_IS40(pi->radio_chanspec)) {
+ switch (cur_channel) {
+ case 3:
+ nphy_adj_tone_id_buf[0] = 57;
+ nphy_adj_tone_id_buf[1] = 58;
+ nphy_adj_noise_var_buf[0] = 0x22f;
+ nphy_adj_noise_var_buf[1] = 0x25f;
+ isAdjustNoiseVar = true;
+ break;
+ case 4:
+ nphy_adj_tone_id_buf[0] = 41;
+ nphy_adj_tone_id_buf[1] = 42;
+ nphy_adj_noise_var_buf[0] = 0x22f;
+ nphy_adj_noise_var_buf[1] = 0x25f;
+ isAdjustNoiseVar = true;
+ break;
+ case 5:
+ nphy_adj_tone_id_buf[0] = 25;
+ nphy_adj_tone_id_buf[1] = 26;
+ nphy_adj_noise_var_buf[0] = 0x24f;
+ nphy_adj_noise_var_buf[1] = 0x25f;
+ isAdjustNoiseVar = true;
+ break;
+ case 6:
+ nphy_adj_tone_id_buf[0] = 9;
+ nphy_adj_tone_id_buf[1] = 10;
+ nphy_adj_noise_var_buf[0] = 0x22f;
+ nphy_adj_noise_var_buf[1] = 0x24f;
+ isAdjustNoiseVar = true;
+ break;
+ case 7:
+ nphy_adj_tone_id_buf[0] = 121;
+ nphy_adj_tone_id_buf[1] = 122;
+ nphy_adj_noise_var_buf[0] = 0x18f;
+ nphy_adj_noise_var_buf[1] = 0x24f;
+ isAdjustNoiseVar = true;
+ break;
+ case 8:
+ nphy_adj_tone_id_buf[0] = 105;
+ nphy_adj_tone_id_buf[1] = 106;
+ nphy_adj_noise_var_buf[0] = 0x22f;
+ nphy_adj_noise_var_buf[1] = 0x25f;
+ isAdjustNoiseVar = true;
+ break;
+ case 9:
+ nphy_adj_tone_id_buf[0] = 89;
+ nphy_adj_tone_id_buf[1] = 90;
+ nphy_adj_noise_var_buf[0] = 0x22f;
+ nphy_adj_noise_var_buf[1] = 0x24f;
+ isAdjustNoiseVar = true;
+ break;
+ case 10:
+ nphy_adj_tone_id_buf[0] = 73;
+ nphy_adj_tone_id_buf[1] = 74;
+ nphy_adj_noise_var_buf[0] = 0x22f;
+ nphy_adj_noise_var_buf[1] = 0x24f;
+ isAdjustNoiseVar = true;
+ break;
+ default:
+ isAdjustNoiseVar = false;
+ break;
+ }
+ }
+
+ if (isAdjustNoiseVar) {
+ numTonesAdjust = sizeof(nphy_adj_tone_id_buf) /
+ sizeof(nphy_adj_tone_id_buf[0]);
+
+ wlc_phy_adjust_min_noisevar_nphy(
+ pi,
+ numTonesAdjust,
+ nphy_adj_tone_id_buf,
+ nphy_adj_noise_var_buf);
+
+ tempval = 0;
+
+ } else {
+ wlc_phy_adjust_min_noisevar_nphy(pi, 0, NULL,
+ NULL);
+ }
+ }
+
+ if ((pi->nphy_aband_spurwar_en) &&
+ (CHSPEC_IS5G(pi->radio_chanspec))) {
+ switch (cur_channel) {
+ case 54:
+ nphy_adj_tone_id_buf[0] = 32;
+ nphy_adj_noise_var_buf[0] = 0x25f;
+ break;
+ case 38:
+ case 102:
+ case 118:
+ nphy_adj_tone_id_buf[0] = 0;
+ nphy_adj_noise_var_buf[0] = 0x0;
+ break;
+ case 134:
+ nphy_adj_tone_id_buf[0] = 32;
+ nphy_adj_noise_var_buf[0] = 0x21f;
+ break;
+ case 151:
+ nphy_adj_tone_id_buf[0] = 16;
+ nphy_adj_noise_var_buf[0] = 0x23f;
+ break;
+ case 153:
+ case 161:
+ nphy_adj_tone_id_buf[0] = 48;
+ nphy_adj_noise_var_buf[0] = 0x23f;
+ break;
+ default:
+ nphy_adj_tone_id_buf[0] = 0;
+ nphy_adj_noise_var_buf[0] = 0x0;
+ break;
+ }
+
+ if (nphy_adj_tone_id_buf[0]
+ && nphy_adj_noise_var_buf[0])
+ wlc_phy_adjust_min_noisevar_nphy(
+ pi, 1,
+ nphy_adj_tone_id_buf,
+ nphy_adj_noise_var_buf);
+ else
+ wlc_phy_adjust_min_noisevar_nphy(pi, 0, NULL,
+ NULL);
+ }
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+ }
+}
+
+void wlc_phy_init_nphy(struct brcms_phy *pi)
+{
+ u16 val;
+ u16 clip1_ths[2];
+ struct nphy_txgains target_gain;
+ u8 tx_pwr_ctrl_state;
+ bool do_nphy_cal = false;
+ uint core;
+ uint origidx, intr_val;
+ struct d11regs __iomem *regs;
+ u32 d11_clk_ctl_st;
+ bool do_rssi_cal = false;
+
+ core = 0;
+
+ if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN))
+ pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC;
+
+ if ((ISNPHY(pi)) && (NREV_GE(pi->pubpi.phy_rev, 5)) &&
+ ((pi->sh->chippkg == BCM4717_PKG_ID) ||
+ (pi->sh->chippkg == BCM4718_PKG_ID))) {
+ if ((pi->sh->boardflags & BFL_EXTLNA) &&
+ (CHSPEC_IS2G(pi->radio_chanspec)))
+ ai_corereg(pi->sh->sih, SI_CC_IDX,
+ offsetof(struct chipcregs, chipcontrol),
+ 0x40, 0x40);
+ }
+
+ if ((pi->nphy_gband_spurwar2_en) && CHSPEC_IS2G(pi->radio_chanspec) &&
+ CHSPEC_IS40(pi->radio_chanspec)) {
+
+ regs = (struct d11regs __iomem *)
+ ai_switch_core(pi->sh->sih,
+ D11_CORE_ID, &origidx,
+ &intr_val);
+ d11_clk_ctl_st = R_REG(&regs->clk_ctl_st);
+ AND_REG(&regs->clk_ctl_st,
+ ~(CCS_FORCEHT | CCS_HTAREQ));
+
+ W_REG(&regs->clk_ctl_st, d11_clk_ctl_st);
+
+ ai_restore_core(pi->sh->sih, origidx, intr_val);
+ }
+
+ pi->use_int_tx_iqlo_cal_nphy =
+ (PHY_IPA(pi) ||
+ (NREV_GE(pi->pubpi.phy_rev, 7) ||
+ (NREV_GE(pi->pubpi.phy_rev, 5)
+ && pi->sh->boardflags2 & BFL2_INTERNDET_TXIQCAL)));
+
+ pi->internal_tx_iqlo_cal_tapoff_intpa_nphy = false;
+
+ pi->nphy_deaf_count = 0;
+
+ wlc_phy_tbl_init_nphy(pi);
+
+ pi->nphy_crsminpwr_adjusted = false;
+ pi->nphy_noisevars_adjusted = false;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ write_phy_reg(pi, 0xe7, 0);
+ write_phy_reg(pi, 0xec, 0);
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ write_phy_reg(pi, 0x342, 0);
+ write_phy_reg(pi, 0x343, 0);
+ write_phy_reg(pi, 0x346, 0);
+ write_phy_reg(pi, 0x347, 0);
+ }
+ write_phy_reg(pi, 0xe5, 0);
+ write_phy_reg(pi, 0xe6, 0);
+ } else {
+ write_phy_reg(pi, 0xec, 0);
+ }
+
+ write_phy_reg(pi, 0x91, 0);
+ write_phy_reg(pi, 0x92, 0);
+ if (NREV_LT(pi->pubpi.phy_rev, 6)) {
+ write_phy_reg(pi, 0x93, 0);
+ write_phy_reg(pi, 0x94, 0);
+ }
+
+ and_phy_reg(pi, 0xa1, ~3);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ write_phy_reg(pi, 0x8f, 0);
+ write_phy_reg(pi, 0xa5, 0);
+ } else {
+ write_phy_reg(pi, 0xa5, 0);
+ }
+
+ if (NREV_IS(pi->pubpi.phy_rev, 2))
+ mod_phy_reg(pi, 0xdc, 0x00ff, 0x3b);
+ else if (NREV_LT(pi->pubpi.phy_rev, 2))
+ mod_phy_reg(pi, 0xdc, 0x00ff, 0x40);
+
+ write_phy_reg(pi, 0x203, 32);
+ write_phy_reg(pi, 0x201, 32);
+
+ if (pi->sh->boardflags2 & BFL2_SKWRKFEM_BRD)
+ write_phy_reg(pi, 0x20d, 160);
+ else
+ write_phy_reg(pi, 0x20d, 184);
+
+ write_phy_reg(pi, 0x13a, 200);
+
+ write_phy_reg(pi, 0x70, 80);
+
+ write_phy_reg(pi, 0x1ff, 48);
+
+ if (NREV_LT(pi->pubpi.phy_rev, 8))
+ wlc_phy_update_mimoconfig_nphy(pi, pi->n_preamble_override);
+
+ wlc_phy_stf_chain_upd_nphy(pi);
+
+ if (NREV_LT(pi->pubpi.phy_rev, 2)) {
+ write_phy_reg(pi, 0x180, 0xaa8);
+ write_phy_reg(pi, 0x181, 0x9a4);
+ }
+
+ if (PHY_IPA(pi)) {
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (1) << 0);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x298 :
+ 0x29c, (0x1ff << 7),
+ (pi->nphy_papd_epsilon_offset[core]) << 7);
+
+ }
+
+ wlc_phy_ipa_set_tx_digi_filts_nphy(pi);
+ } else if (NREV_GE(pi->pubpi.phy_rev, 5)) {
+ wlc_phy_extpa_set_tx_digi_filts_nphy(pi);
+ }
+
+ wlc_phy_workarounds_nphy(pi);
+
+ wlapi_bmac_phyclk_fgc(pi->sh->physhim, ON);
+
+ val = read_phy_reg(pi, 0x01);
+ write_phy_reg(pi, 0x01, val | BBCFG_RESETCCA);
+ write_phy_reg(pi, 0x01, val & (~BBCFG_RESETCCA));
+ wlapi_bmac_phyclk_fgc(pi->sh->physhim, OFF);
+
+ wlapi_bmac_macphyclk_set(pi->sh->physhim, ON);
+
+ wlc_phy_pa_override_nphy(pi, OFF);
+ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX);
+ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX);
+ wlc_phy_pa_override_nphy(pi, ON);
+
+ wlc_phy_classifier_nphy(pi, 0, 0);
+ wlc_phy_clip_det_nphy(pi, 0, clip1_ths);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ wlc_phy_bphy_init_nphy(pi);
+
+ tx_pwr_ctrl_state = pi->nphy_txpwrctrl;
+ wlc_phy_txpwrctrl_enable_nphy(pi, PHY_TPC_HW_OFF);
+
+ wlc_phy_txpwr_fixpower_nphy(pi);
+
+ wlc_phy_txpwrctrl_idle_tssi_nphy(pi);
+
+ wlc_phy_txpwrctrl_pwr_setup_nphy(pi);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ u32 *tx_pwrctrl_tbl = NULL;
+ u16 idx;
+ s16 pga_gn = 0;
+ s16 pad_gn = 0;
+ s32 rfpwr_offset;
+
+ if (PHY_IPA(pi)) {
+ tx_pwrctrl_tbl = wlc_phy_get_ipa_gaintbl_nphy(pi);
+ } else {
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ if (NREV_IS(pi->pubpi.phy_rev, 3))
+ tx_pwrctrl_tbl =
+ nphy_tpc_5GHz_txgain_rev3;
+ else if (NREV_IS(pi->pubpi.phy_rev, 4))
+ tx_pwrctrl_tbl =
+ (pi->srom_fem5g.extpagain ==
+ 3) ?
+ nphy_tpc_5GHz_txgain_HiPwrEPA :
+ nphy_tpc_5GHz_txgain_rev4;
+ else
+ tx_pwrctrl_tbl =
+ nphy_tpc_5GHz_txgain_rev5;
+ } else {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (pi->pubpi.radiorev == 5)
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_epa_2057rev5;
+ else if (pi->pubpi.radiorev == 3)
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_epa_2057rev3;
+ } else {
+ if (NREV_GE(pi->pubpi.phy_rev, 5) &&
+ (pi->srom_fem2g.extpagain == 3))
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_HiPwrEPA;
+ else
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_rev3;
+ }
+ }
+ }
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE1TXPWRCTL, 128,
+ 192, 32, tx_pwrctrl_tbl);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE2TXPWRCTL, 128,
+ 192, 32, tx_pwrctrl_tbl);
+
+ pi->nphy_gmval = (u16) ((*tx_pwrctrl_tbl >> 16) & 0x7000);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ for (idx = 0; idx < 128; idx++) {
+ pga_gn = (tx_pwrctrl_tbl[idx] >> 24) & 0xf;
+ pad_gn = (tx_pwrctrl_tbl[idx] >> 19) & 0x1f;
+ rfpwr_offset = get_rf_pwr_offset(pi, pga_gn,
+ pad_gn);
+ wlc_phy_table_write_nphy(
+ pi,
+ NPHY_TBL_ID_CORE1TXPWRCTL,
+ 1, 576 + idx, 32,
+ &rfpwr_offset);
+ wlc_phy_table_write_nphy(
+ pi,
+ NPHY_TBL_ID_CORE2TXPWRCTL,
+ 1, 576 + idx, 32,
+ &rfpwr_offset);
+ }
+ } else {
+
+ for (idx = 0; idx < 128; idx++) {
+ pga_gn = (tx_pwrctrl_tbl[idx] >> 24) & 0xf;
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ rfpwr_offset = (s16)
+ nphy_papd_pga_gain_delta_ipa_2g
+ [pga_gn];
+ else
+ rfpwr_offset = (s16)
+ nphy_papd_pga_gain_delta_ipa_5g
+ [pga_gn];
+
+ wlc_phy_table_write_nphy(
+ pi,
+ NPHY_TBL_ID_CORE1TXPWRCTL,
+ 1, 576 + idx, 32,
+ &rfpwr_offset);
+ wlc_phy_table_write_nphy(
+ pi,
+ NPHY_TBL_ID_CORE2TXPWRCTL,
+ 1, 576 + idx, 32,
+ &rfpwr_offset);
+ }
+
+ }
+ } else {
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE1TXPWRCTL, 128,
+ 192, 32, nphy_tpc_txgain);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE2TXPWRCTL, 128,
+ 192, 32, nphy_tpc_txgain);
+ }
+
+ if (pi->sh->phyrxchain != 0x3)
+ wlc_phy_rxcore_setstate_nphy((struct brcms_phy_pub *) pi,
+ pi->sh->phyrxchain);
+
+ if (PHY_PERICAL_MPHASE_PENDING(pi))
+ wlc_phy_cal_perical_mphase_restart(pi);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ do_rssi_cal = (CHSPEC_IS2G(pi->radio_chanspec)) ?
+ (pi->nphy_rssical_chanspec_2G == 0) :
+ (pi->nphy_rssical_chanspec_5G == 0);
+
+ if (do_rssi_cal)
+ wlc_phy_rssi_cal_nphy(pi);
+ else
+ wlc_phy_restore_rssical_nphy(pi);
+ } else {
+ wlc_phy_rssi_cal_nphy(pi);
+ }
+
+ if (!SCAN_RM_IN_PROGRESS(pi))
+ do_nphy_cal = (CHSPEC_IS2G(pi->radio_chanspec)) ?
+ (pi->nphy_iqcal_chanspec_2G == 0) :
+ (pi->nphy_iqcal_chanspec_5G == 0);
+
+ if (!pi->do_initcal)
+ do_nphy_cal = false;
+
+ if (do_nphy_cal) {
+
+ target_gain = wlc_phy_get_tx_gain_nphy(pi);
+
+ if (pi->antsel_type == ANTSEL_2x3)
+ wlc_phy_antsel_init((struct brcms_phy_pub *) pi,
+ true);
+
+ if (pi->nphy_perical != PHY_PERICAL_MPHASE) {
+ wlc_phy_rssi_cal_nphy(pi);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ pi->nphy_cal_orig_pwr_idx[0] =
+ pi->nphy_txpwrindex[PHY_CORE_0]
+ .
+ index_internal;
+ pi->nphy_cal_orig_pwr_idx[1] =
+ pi->nphy_txpwrindex[PHY_CORE_1]
+ .
+ index_internal;
+
+ wlc_phy_precal_txgain_nphy(pi);
+ target_gain =
+ wlc_phy_get_tx_gain_nphy(pi);
+ }
+
+ if (wlc_phy_cal_txiqlo_nphy
+ (pi, target_gain, true,
+ false) == 0) {
+ if (wlc_phy_cal_rxiq_nphy
+ (pi, target_gain, 2,
+ false) == 0)
+ wlc_phy_savecal_nphy(pi);
+
+ }
+ } else if (pi->mphase_cal_phase_id ==
+ MPHASE_CAL_STATE_IDLE) {
+ wlc_phy_cal_perical((struct brcms_phy_pub *) pi,
+ PHY_PERICAL_PHYINIT);
+ }
+ } else {
+ wlc_phy_restorecal_nphy(pi);
+ }
+
+ wlc_phy_txpwrctrl_coeff_setup_nphy(pi);
+
+ wlc_phy_txpwrctrl_enable_nphy(pi, tx_pwr_ctrl_state);
+
+ wlc_phy_nphy_tkip_rifs_war(pi, pi->sh->_rifs_phy);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LE(pi->pubpi.phy_rev, 6))
+
+ write_phy_reg(pi, 0x70, 50);
+
+ wlc_phy_txlpfbw_nphy(pi);
+
+ wlc_phy_spurwar_nphy(pi);
+
+}
+
+static void wlc_phy_resetcca_nphy(struct brcms_phy *pi)
+{
+ u16 val;
+
+ wlapi_bmac_phyclk_fgc(pi->sh->physhim, ON);
+
+ val = read_phy_reg(pi, 0x01);
+ write_phy_reg(pi, 0x01, val | BBCFG_RESETCCA);
+ udelay(1);
+ write_phy_reg(pi, 0x01, val & (~BBCFG_RESETCCA));
+
+ wlapi_bmac_phyclk_fgc(pi->sh->physhim, OFF);
+
+ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX);
+}
+
+void wlc_phy_pa_override_nphy(struct brcms_phy *pi, bool en)
+{
+ u16 rfctrlintc_override_val;
+
+ if (!en) {
+
+ pi->rfctrlIntc1_save = read_phy_reg(pi, 0x91);
+ pi->rfctrlIntc2_save = read_phy_reg(pi, 0x92);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ rfctrlintc_override_val = 0x1480;
+ else if (NREV_GE(pi->pubpi.phy_rev, 3))
+ rfctrlintc_override_val =
+ CHSPEC_IS5G(pi->radio_chanspec) ? 0x600 : 0x480;
+ else
+ rfctrlintc_override_val =
+ CHSPEC_IS5G(pi->radio_chanspec) ? 0x180 : 0x120;
+
+ write_phy_reg(pi, 0x91, rfctrlintc_override_val);
+ write_phy_reg(pi, 0x92, rfctrlintc_override_val);
+ } else {
+ write_phy_reg(pi, 0x91, pi->rfctrlIntc1_save);
+ write_phy_reg(pi, 0x92, pi->rfctrlIntc2_save);
+ }
+
+}
+
+void wlc_phy_stf_chain_upd_nphy(struct brcms_phy *pi)
+{
+
+ u16 txrx_chain =
+ (NPHY_RfseqCoreActv_TxRxChain0 | NPHY_RfseqCoreActv_TxRxChain1);
+ bool CoreActv_override = false;
+
+ if (pi->nphy_txrx_chain == BRCMS_N_TXRX_CHAIN0) {
+ txrx_chain = NPHY_RfseqCoreActv_TxRxChain0;
+ CoreActv_override = true;
+
+ if (NREV_LE(pi->pubpi.phy_rev, 2))
+ and_phy_reg(pi, 0xa0, ~0x20);
+ } else if (pi->nphy_txrx_chain == BRCMS_N_TXRX_CHAIN1) {
+ txrx_chain = NPHY_RfseqCoreActv_TxRxChain1;
+ CoreActv_override = true;
+
+ if (NREV_LE(pi->pubpi.phy_rev, 2))
+ or_phy_reg(pi, 0xa0, 0x20);
+ }
+
+ mod_phy_reg(pi, 0xa2, ((0xf << 0) | (0xf << 4)), txrx_chain);
+
+ if (CoreActv_override) {
+ pi->nphy_perical = PHY_PERICAL_DISABLE;
+ or_phy_reg(pi, 0xa1, NPHY_RfseqMode_CoreActv_override);
+ } else {
+ pi->nphy_perical = PHY_PERICAL_MPHASE;
+ and_phy_reg(pi, 0xa1, ~NPHY_RfseqMode_CoreActv_override);
+ }
+}
+
+void wlc_phy_rxcore_setstate_nphy(struct brcms_phy_pub *pih, u8 rxcore_bitmask)
+{
+ u16 regval;
+ u16 tbl_buf[16];
+ uint i;
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+ u16 tbl_opcode;
+ bool suspend;
+
+ pi->sh->phyrxchain = rxcore_bitmask;
+
+ if (!pi->sh->clk)
+ return;
+
+ suspend = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
+ if (!suspend)
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ regval = read_phy_reg(pi, 0xa2);
+ regval &= ~(0xf << 4);
+ regval |= ((u16) (rxcore_bitmask & 0x3)) << 4;
+ write_phy_reg(pi, 0xa2, regval);
+
+ if ((rxcore_bitmask & 0x3) != 0x3) {
+
+ write_phy_reg(pi, 0x20e, 1);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ if (pi->rx2tx_biasentry == -1) {
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ,
+ ARRAY_SIZE(tbl_buf), 80,
+ 16, tbl_buf);
+
+ for (i = 0; i < ARRAY_SIZE(tbl_buf); i++) {
+ if (tbl_buf[i] ==
+ NPHY_REV3_RFSEQ_CMD_CLR_RXRX_BIAS) {
+ pi->rx2tx_biasentry = (u8) i;
+ tbl_opcode =
+ NPHY_REV3_RFSEQ_CMD_NOP;
+ wlc_phy_table_write_nphy(
+ pi,
+ NPHY_TBL_ID_RFSEQ,
+ 1, i,
+ 16,
+ &tbl_opcode);
+ break;
+ } else if (tbl_buf[i] ==
+ NPHY_REV3_RFSEQ_CMD_END)
+ break;
+ }
+ }
+ }
+ } else {
+
+ write_phy_reg(pi, 0x20e, 30);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ if (pi->rx2tx_biasentry != -1) {
+ tbl_opcode = NPHY_REV3_RFSEQ_CMD_CLR_RXRX_BIAS;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ,
+ 1, pi->rx2tx_biasentry,
+ 16, &tbl_opcode);
+ pi->rx2tx_biasentry = -1;
+ }
+ }
+ }
+
+ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX);
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+
+ if (!suspend)
+ wlapi_enable_mac(pi->sh->physhim);
+}
+
+u8 wlc_phy_rxcore_getstate_nphy(struct brcms_phy_pub *pih)
+{
+ u16 regval, rxen_bits;
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+
+ regval = read_phy_reg(pi, 0xa2);
+ rxen_bits = (regval >> 4) & 0xf;
+
+ return (u8) rxen_bits;
+}
+
+bool wlc_phy_n_txpower_ipa_ison(struct brcms_phy *pi)
+{
+ return PHY_IPA(pi);
+}
+
+void wlc_phy_cal_init_nphy(struct brcms_phy *pi)
+{
+}
+
+static void wlc_phy_radio_preinit_205x(struct brcms_phy *pi)
+{
+
+ and_phy_reg(pi, 0x78, ~RFCC_CHIP0_PU);
+ and_phy_reg(pi, 0x78, RFCC_OE_POR_FORCE);
+
+ or_phy_reg(pi, 0x78, ~RFCC_OE_POR_FORCE);
+ or_phy_reg(pi, 0x78, RFCC_CHIP0_PU);
+
+}
+
+static void wlc_phy_radio_init_2057(struct brcms_phy *pi)
+{
+ struct radio_20xx_regs *regs_2057_ptr = NULL;
+
+ if (NREV_IS(pi->pubpi.phy_rev, 7)) {
+ regs_2057_ptr = regs_2057_rev4;
+ } else if (NREV_IS(pi->pubpi.phy_rev, 8)
+ || NREV_IS(pi->pubpi.phy_rev, 9)) {
+ switch (pi->pubpi.radiorev) {
+ case 5:
+
+ if (pi->pubpi.radiover == 0x0)
+ regs_2057_ptr = regs_2057_rev5;
+ else if (pi->pubpi.radiover == 0x1)
+ regs_2057_ptr = regs_2057_rev5v1;
+ else
+ break;
+
+ case 7:
+
+ regs_2057_ptr = regs_2057_rev7;
+ break;
+
+ case 8:
+
+ regs_2057_ptr = regs_2057_rev8;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ wlc_phy_init_radio_regs_allbands(pi, regs_2057_ptr);
+}
+
+static u16 wlc_phy_radio205x_rcal(struct brcms_phy *pi)
+{
+ u16 rcal_reg = 0;
+ int i;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ if (pi->pubpi.radiorev == 5) {
+
+ and_phy_reg(pi, 0x342, ~(0x1 << 1));
+
+ udelay(10);
+
+ mod_radio_reg(pi, RADIO_2057_IQTEST_SEL_PU, 0x1, 0x1);
+ mod_radio_reg(pi, RADIO_2057v7_IQTEST_SEL_PU2, 0x2,
+ 0x1);
+ }
+ mod_radio_reg(pi, RADIO_2057_RCAL_CONFIG, 0x1, 0x1);
+
+ udelay(10);
+
+ mod_radio_reg(pi, RADIO_2057_RCAL_CONFIG, 0x3, 0x3);
+
+ for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) {
+ rcal_reg = read_radio_reg(pi, RADIO_2057_RCAL_STATUS);
+ if (rcal_reg & 0x1)
+ break;
+
+ udelay(100);
+ }
+
+ if (WARN(i == MAX_205x_RCAL_WAITLOOPS,
+ "HW error: radio calib2"))
+ return 0;
+
+ mod_radio_reg(pi, RADIO_2057_RCAL_CONFIG, 0x2, 0x0);
+
+ rcal_reg = read_radio_reg(pi, RADIO_2057_RCAL_STATUS) & 0x3e;
+
+ mod_radio_reg(pi, RADIO_2057_RCAL_CONFIG, 0x1, 0x0);
+ if (pi->pubpi.radiorev == 5) {
+
+ mod_radio_reg(pi, RADIO_2057_IQTEST_SEL_PU, 0x1, 0x0);
+ mod_radio_reg(pi, RADIO_2057v7_IQTEST_SEL_PU2, 0x2,
+ 0x0);
+ }
+
+ if ((pi->pubpi.radiorev <= 4) || (pi->pubpi.radiorev == 6)) {
+
+ mod_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG, 0x3c,
+ rcal_reg);
+ mod_radio_reg(pi, RADIO_2057_BANDGAP_RCAL_TRIM, 0xf0,
+ rcal_reg << 2);
+ }
+
+ } else if (NREV_IS(pi->pubpi.phy_rev, 3)) {
+ u16 savereg;
+
+ savereg =
+ read_radio_reg(
+ pi,
+ RADIO_2056_SYN_PLL_MAST2 |
+ RADIO_2056_SYN);
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_MAST2 | RADIO_2056_SYN,
+ savereg | 0x7);
+ udelay(10);
+
+ write_radio_reg(pi, RADIO_2056_SYN_RCAL_MASTER | RADIO_2056_SYN,
+ 0x1);
+ udelay(10);
+
+ write_radio_reg(pi, RADIO_2056_SYN_RCAL_MASTER | RADIO_2056_SYN,
+ 0x9);
+
+ for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) {
+ rcal_reg = read_radio_reg(
+ pi,
+ RADIO_2056_SYN_RCAL_CODE_OUT |
+ RADIO_2056_SYN);
+ if (rcal_reg & 0x80)
+ break;
+
+ udelay(100);
+ }
+
+ if (WARN(i == MAX_205x_RCAL_WAITLOOPS,
+ "HW error: radio calib3"))
+ return 0;
+
+ write_radio_reg(pi, RADIO_2056_SYN_RCAL_MASTER | RADIO_2056_SYN,
+ 0x1);
+
+ rcal_reg =
+ read_radio_reg(pi,
+ RADIO_2056_SYN_RCAL_CODE_OUT |
+ RADIO_2056_SYN);
+
+ write_radio_reg(pi, RADIO_2056_SYN_RCAL_MASTER | RADIO_2056_SYN,
+ 0x0);
+
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_MAST2 | RADIO_2056_SYN,
+ savereg);
+
+ return rcal_reg & 0x1f;
+ }
+ return rcal_reg & 0x3e;
+}
+
+static u16 wlc_phy_radio2057_rccal(struct brcms_phy *pi)
+{
+ u16 rccal_valid;
+ int i;
+ bool chip43226_6362A0;
+
+ chip43226_6362A0 = ((pi->pubpi.radiorev == 3)
+ || (pi->pubpi.radiorev == 4)
+ || (pi->pubpi.radiorev == 6));
+
+ rccal_valid = 0;
+ if (chip43226_6362A0) {
+ write_radio_reg(pi, RADIO_2057_RCCAL_MASTER, 0x61);
+ write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xc0);
+ } else {
+ write_radio_reg(pi, RADIO_2057v7_RCCAL_MASTER, 0x61);
+
+ write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xe9);
+ }
+ write_radio_reg(pi, RADIO_2057_RCCAL_X1, 0x6e);
+ write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x55);
+
+ for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) {
+ rccal_valid = read_radio_reg(pi, RADIO_2057_RCCAL_DONE_OSCCAP);
+ if (rccal_valid & 0x2)
+ break;
+
+ udelay(500);
+ }
+
+ write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x15);
+
+ rccal_valid = 0;
+ if (chip43226_6362A0) {
+ write_radio_reg(pi, RADIO_2057_RCCAL_MASTER, 0x69);
+ write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xb0);
+ } else {
+ write_radio_reg(pi, RADIO_2057v7_RCCAL_MASTER, 0x69);
+
+ write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xd5);
+ }
+ write_radio_reg(pi, RADIO_2057_RCCAL_X1, 0x6e);
+ write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x55);
+
+ for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) {
+ rccal_valid = read_radio_reg(pi, RADIO_2057_RCCAL_DONE_OSCCAP);
+ if (rccal_valid & 0x2)
+ break;
+
+ udelay(500);
+ }
+
+ write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x15);
+
+ rccal_valid = 0;
+ if (chip43226_6362A0) {
+ write_radio_reg(pi, RADIO_2057_RCCAL_MASTER, 0x73);
+
+ write_radio_reg(pi, RADIO_2057_RCCAL_X1, 0x28);
+ write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xb0);
+ } else {
+ write_radio_reg(pi, RADIO_2057v7_RCCAL_MASTER, 0x73);
+ write_radio_reg(pi, RADIO_2057_RCCAL_X1, 0x6e);
+ write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0x99);
+ }
+ write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x55);
+
+ for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) {
+ rccal_valid = read_radio_reg(pi, RADIO_2057_RCCAL_DONE_OSCCAP);
+ if (rccal_valid & 0x2)
+ break;
+
+ udelay(500);
+ }
+
+ if (WARN(!(rccal_valid & 0x2), "HW error: radio calib4"))
+ return 0;
+
+ write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x15);
+
+ return rccal_valid;
+}
+
+static void wlc_phy_radio_postinit_2057(struct brcms_phy *pi)
+{
+
+ mod_radio_reg(pi, RADIO_2057_XTALPUOVR_PINCTRL, 0x1, 0x1);
+
+ mod_radio_reg(pi, RADIO_2057_RFPLL_MISC_CAL_RESETN, 0x78, 0x78);
+ mod_radio_reg(pi, RADIO_2057_XTAL_CONFIG2, 0x80, 0x80);
+ mdelay(2);
+ mod_radio_reg(pi, RADIO_2057_RFPLL_MISC_CAL_RESETN, 0x78, 0x0);
+ mod_radio_reg(pi, RADIO_2057_XTAL_CONFIG2, 0x80, 0x0);
+
+ if (pi->phy_init_por) {
+ wlc_phy_radio205x_rcal(pi);
+ wlc_phy_radio2057_rccal(pi);
+ }
+
+ mod_radio_reg(pi, RADIO_2057_RFPLL_MASTER, 0x8, 0x0);
+}
+
+static void wlc_phy_radio_init_2056(struct brcms_phy *pi)
+{
+ const struct radio_regs *regs_SYN_2056_ptr = NULL;
+ const struct radio_regs *regs_TX_2056_ptr = NULL;
+ const struct radio_regs *regs_RX_2056_ptr = NULL;
+
+ if (NREV_IS(pi->pubpi.phy_rev, 3)) {
+ regs_SYN_2056_ptr = regs_SYN_2056;
+ regs_TX_2056_ptr = regs_TX_2056;
+ regs_RX_2056_ptr = regs_RX_2056;
+ } else if (NREV_IS(pi->pubpi.phy_rev, 4)) {
+ regs_SYN_2056_ptr = regs_SYN_2056_A1;
+ regs_TX_2056_ptr = regs_TX_2056_A1;
+ regs_RX_2056_ptr = regs_RX_2056_A1;
+ } else {
+ switch (pi->pubpi.radiorev) {
+ case 5:
+ regs_SYN_2056_ptr = regs_SYN_2056_rev5;
+ regs_TX_2056_ptr = regs_TX_2056_rev5;
+ regs_RX_2056_ptr = regs_RX_2056_rev5;
+ break;
+
+ case 6:
+ regs_SYN_2056_ptr = regs_SYN_2056_rev6;
+ regs_TX_2056_ptr = regs_TX_2056_rev6;
+ regs_RX_2056_ptr = regs_RX_2056_rev6;
+ break;
+
+ case 7:
+ case 9:
+ regs_SYN_2056_ptr = regs_SYN_2056_rev7;
+ regs_TX_2056_ptr = regs_TX_2056_rev7;
+ regs_RX_2056_ptr = regs_RX_2056_rev7;
+ break;
+
+ case 8:
+ regs_SYN_2056_ptr = regs_SYN_2056_rev8;
+ regs_TX_2056_ptr = regs_TX_2056_rev8;
+ regs_RX_2056_ptr = regs_RX_2056_rev8;
+ break;
+
+ case 11:
+ regs_SYN_2056_ptr = regs_SYN_2056_rev11;
+ regs_TX_2056_ptr = regs_TX_2056_rev11;
+ regs_RX_2056_ptr = regs_RX_2056_rev11;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ wlc_phy_init_radio_regs(pi, regs_SYN_2056_ptr, (u16) RADIO_2056_SYN);
+
+ wlc_phy_init_radio_regs(pi, regs_TX_2056_ptr, (u16) RADIO_2056_TX0);
+
+ wlc_phy_init_radio_regs(pi, regs_TX_2056_ptr, (u16) RADIO_2056_TX1);
+
+ wlc_phy_init_radio_regs(pi, regs_RX_2056_ptr, (u16) RADIO_2056_RX0);
+
+ wlc_phy_init_radio_regs(pi, regs_RX_2056_ptr, (u16) RADIO_2056_RX1);
+}
+
+static void wlc_phy_radio_postinit_2056(struct brcms_phy *pi)
+{
+ mod_radio_reg(pi, RADIO_2056_SYN_COM_CTRL, 0xb, 0xb);
+
+ mod_radio_reg(pi, RADIO_2056_SYN_COM_PU, 0x2, 0x2);
+ mod_radio_reg(pi, RADIO_2056_SYN_COM_RESET, 0x2, 0x2);
+ udelay(1000);
+ mod_radio_reg(pi, RADIO_2056_SYN_COM_RESET, 0x2, 0x0);
+
+ if ((pi->sh->boardflags2 & BFL2_LEGACY)
+ || (pi->sh->boardflags2 & BFL2_XTALBUFOUTEN))
+ mod_radio_reg(pi, RADIO_2056_SYN_PLL_MAST2, 0xf4, 0x0);
+ else
+ mod_radio_reg(pi, RADIO_2056_SYN_PLL_MAST2, 0xfc, 0x0);
+
+ mod_radio_reg(pi, RADIO_2056_SYN_RCCAL_CTRL0, 0x1, 0x0);
+
+ if (pi->phy_init_por)
+ wlc_phy_radio205x_rcal(pi);
+}
+
+static void wlc_phy_radio_preinit_2055(struct brcms_phy *pi)
+{
+
+ and_phy_reg(pi, 0x78, ~RFCC_POR_FORCE);
+ or_phy_reg(pi, 0x78, RFCC_CHIP0_PU | RFCC_OE_POR_FORCE);
+
+ or_phy_reg(pi, 0x78, RFCC_POR_FORCE);
+}
+
+static void wlc_phy_radio_init_2055(struct brcms_phy *pi)
+{
+ wlc_phy_init_radio_regs(pi, regs_2055, RADIO_DEFAULT_CORE);
+}
+
+static void wlc_phy_radio_postinit_2055(struct brcms_phy *pi)
+{
+
+ and_radio_reg(pi, RADIO_2055_MASTER_CNTRL1,
+ ~(RADIO_2055_JTAGCTRL_MASK | RADIO_2055_JTAGSYNC_MASK));
+
+ if (((pi->sh->sromrev >= 4)
+ && !(pi->sh->boardflags2 & BFL2_RXBB_INT_REG_DIS))
+ || ((pi->sh->sromrev < 4))) {
+ and_radio_reg(pi, RADIO_2055_CORE1_RXBB_REGULATOR, 0x7F);
+ and_radio_reg(pi, RADIO_2055_CORE2_RXBB_REGULATOR, 0x7F);
+ }
+
+ mod_radio_reg(pi, RADIO_2055_RRCCAL_N_OPT_SEL, 0x3F, 0x2C);
+ write_radio_reg(pi, RADIO_2055_CAL_MISC, 0x3C);
+
+ and_radio_reg(pi, RADIO_2055_CAL_MISC,
+ ~(RADIO_2055_RRCAL_START | RADIO_2055_RRCAL_RST_N));
+
+ or_radio_reg(pi, RADIO_2055_CAL_LPO_CNTRL, RADIO_2055_CAL_LPO_ENABLE);
+
+ or_radio_reg(pi, RADIO_2055_CAL_MISC, RADIO_2055_RRCAL_RST_N);
+
+ udelay(1000);
+
+ or_radio_reg(pi, RADIO_2055_CAL_MISC, RADIO_2055_RRCAL_START);
+
+ SPINWAIT(((read_radio_reg(pi, RADIO_2055_CAL_COUNTER_OUT2) &
+ RADIO_2055_RCAL_DONE) != RADIO_2055_RCAL_DONE), 2000);
+
+ if (WARN((read_radio_reg(pi, RADIO_2055_CAL_COUNTER_OUT2) &
+ RADIO_2055_RCAL_DONE) != RADIO_2055_RCAL_DONE,
+ "HW error: radio calibration1\n"))
+ return;
+
+ and_radio_reg(pi, RADIO_2055_CAL_LPO_CNTRL,
+ ~(RADIO_2055_CAL_LPO_ENABLE));
+
+ wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec);
+
+ write_radio_reg(pi, RADIO_2055_CORE1_RXBB_LPF, 9);
+ write_radio_reg(pi, RADIO_2055_CORE2_RXBB_LPF, 9);
+
+ write_radio_reg(pi, RADIO_2055_CORE1_RXBB_MIDAC_HIPAS, 0x83);
+ write_radio_reg(pi, RADIO_2055_CORE2_RXBB_MIDAC_HIPAS, 0x83);
+
+ mod_radio_reg(pi, RADIO_2055_CORE1_LNA_GAINBST,
+ RADIO_2055_GAINBST_VAL_MASK, RADIO_2055_GAINBST_CODE);
+ mod_radio_reg(pi, RADIO_2055_CORE2_LNA_GAINBST,
+ RADIO_2055_GAINBST_VAL_MASK, RADIO_2055_GAINBST_CODE);
+ if (pi->nphy_gain_boost) {
+ and_radio_reg(pi, RADIO_2055_CORE1_RXRF_SPC1,
+ ~(RADIO_2055_GAINBST_DISABLE));
+ and_radio_reg(pi, RADIO_2055_CORE2_RXRF_SPC1,
+ ~(RADIO_2055_GAINBST_DISABLE));
+ } else {
+ or_radio_reg(pi, RADIO_2055_CORE1_RXRF_SPC1,
+ RADIO_2055_GAINBST_DISABLE);
+ or_radio_reg(pi, RADIO_2055_CORE2_RXRF_SPC1,
+ RADIO_2055_GAINBST_DISABLE);
+ }
+
+ udelay(2);
+}
+
+void wlc_phy_switch_radio_nphy(struct brcms_phy *pi, bool on)
+{
+ if (on) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (!pi->radio_is_on) {
+ wlc_phy_radio_preinit_205x(pi);
+ wlc_phy_radio_init_2057(pi);
+ wlc_phy_radio_postinit_2057(pi);
+ }
+
+ wlc_phy_chanspec_set((struct brcms_phy_pub *) pi,
+ pi->radio_chanspec);
+ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ wlc_phy_radio_preinit_205x(pi);
+ wlc_phy_radio_init_2056(pi);
+ wlc_phy_radio_postinit_2056(pi);
+
+ wlc_phy_chanspec_set((struct brcms_phy_pub *) pi,
+ pi->radio_chanspec);
+ } else {
+ wlc_phy_radio_preinit_2055(pi);
+ wlc_phy_radio_init_2055(pi);
+ wlc_phy_radio_postinit_2055(pi);
+ }
+
+ pi->radio_is_on = true;
+
+ } else {
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)
+ && NREV_LT(pi->pubpi.phy_rev, 7)) {
+ and_phy_reg(pi, 0x78, ~RFCC_CHIP0_PU);
+ mod_radio_reg(pi, RADIO_2056_SYN_COM_PU, 0x2, 0x0);
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_PADA_BOOST_TUNE |
+ RADIO_2056_TX0, 0);
+ write_radio_reg(pi,
+ RADIO_2056_TX_PADG_BOOST_TUNE |
+ RADIO_2056_TX0, 0);
+ write_radio_reg(pi,
+ RADIO_2056_TX_PGAA_BOOST_TUNE |
+ RADIO_2056_TX0, 0);
+ write_radio_reg(pi,
+ RADIO_2056_TX_PGAG_BOOST_TUNE |
+ RADIO_2056_TX0, 0);
+ mod_radio_reg(pi,
+ RADIO_2056_TX_MIXA_BOOST_TUNE |
+ RADIO_2056_TX0, 0xf0, 0);
+ write_radio_reg(pi,
+ RADIO_2056_TX_MIXG_BOOST_TUNE |
+ RADIO_2056_TX0, 0);
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_PADA_BOOST_TUNE |
+ RADIO_2056_TX1, 0);
+ write_radio_reg(pi,
+ RADIO_2056_TX_PADG_BOOST_TUNE |
+ RADIO_2056_TX1, 0);
+ write_radio_reg(pi,
+ RADIO_2056_TX_PGAA_BOOST_TUNE |
+ RADIO_2056_TX1, 0);
+ write_radio_reg(pi,
+ RADIO_2056_TX_PGAG_BOOST_TUNE |
+ RADIO_2056_TX1, 0);
+ mod_radio_reg(pi,
+ RADIO_2056_TX_MIXA_BOOST_TUNE |
+ RADIO_2056_TX1, 0xf0, 0);
+ write_radio_reg(pi,
+ RADIO_2056_TX_MIXG_BOOST_TUNE |
+ RADIO_2056_TX1, 0);
+
+ pi->radio_is_on = false;
+ }
+
+ if (NREV_GE(pi->pubpi.phy_rev, 8)) {
+ and_phy_reg(pi, 0x78, ~RFCC_CHIP0_PU);
+ pi->radio_is_on = false;
+ }
+
+ }
+}
+
+static bool
+wlc_phy_chan2freq_nphy(struct brcms_phy *pi, uint channel, int *f,
+ const struct chan_info_nphy_radio2057 **t0,
+ const struct chan_info_nphy_radio205x **t1,
+ const struct chan_info_nphy_radio2057_rev5 **t2,
+ const struct chan_info_nphy_2055 **t3)
+{
+ uint i;
+ const struct chan_info_nphy_radio2057 *chan_info_tbl_p_0 = NULL;
+ const struct chan_info_nphy_radio205x *chan_info_tbl_p_1 = NULL;
+ const struct chan_info_nphy_radio2057_rev5 *chan_info_tbl_p_2 = NULL;
+ u32 tbl_len = 0;
+
+ int freq = 0;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ if (NREV_IS(pi->pubpi.phy_rev, 7)) {
+
+ chan_info_tbl_p_0 = chan_info_nphyrev7_2057_rev4;
+ tbl_len = ARRAY_SIZE(chan_info_nphyrev7_2057_rev4);
+
+ } else if (NREV_IS(pi->pubpi.phy_rev, 8)
+ || NREV_IS(pi->pubpi.phy_rev, 9)) {
+ switch (pi->pubpi.radiorev) {
+
+ case 5:
+
+ if (pi->pubpi.radiover == 0x0) {
+
+ chan_info_tbl_p_2 =
+ chan_info_nphyrev8_2057_rev5;
+ tbl_len = ARRAY_SIZE(
+ chan_info_nphyrev8_2057_rev5);
+
+ } else if (pi->pubpi.radiover == 0x1) {
+
+ chan_info_tbl_p_2 =
+ chan_info_nphyrev9_2057_rev5v1;
+ tbl_len = ARRAY_SIZE(
+ chan_info_nphyrev9_2057_rev5v1);
+
+ }
+ break;
+
+ case 7:
+ chan_info_tbl_p_0 =
+ chan_info_nphyrev8_2057_rev7;
+ tbl_len = ARRAY_SIZE(
+ chan_info_nphyrev8_2057_rev7);
+ break;
+
+ case 8:
+ chan_info_tbl_p_0 =
+ chan_info_nphyrev8_2057_rev8;
+ tbl_len = ARRAY_SIZE(
+ chan_info_nphyrev8_2057_rev8);
+ break;
+
+ default:
+ break;
+ }
+ } else if (NREV_IS(pi->pubpi.phy_rev, 16)) {
+
+ chan_info_tbl_p_0 = chan_info_nphyrev8_2057_rev8;
+ tbl_len = ARRAY_SIZE(chan_info_nphyrev8_2057_rev8);
+ } else {
+ goto fail;
+ }
+
+ for (i = 0; i < tbl_len; i++) {
+ if (pi->pubpi.radiorev == 5) {
+
+ if (chan_info_tbl_p_2[i].chan == channel)
+ break;
+ } else {
+
+ if (chan_info_tbl_p_0[i].chan == channel)
+ break;
+ }
+ }
+
+ if (i >= tbl_len)
+ goto fail;
+
+ if (pi->pubpi.radiorev == 5) {
+ *t2 = &chan_info_tbl_p_2[i];
+ freq = chan_info_tbl_p_2[i].freq;
+ } else {
+ *t0 = &chan_info_tbl_p_0[i];
+ freq = chan_info_tbl_p_0[i].freq;
+ }
+
+ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ if (NREV_IS(pi->pubpi.phy_rev, 3)) {
+ chan_info_tbl_p_1 = chan_info_nphyrev3_2056;
+ tbl_len = ARRAY_SIZE(chan_info_nphyrev3_2056);
+ } else if (NREV_IS(pi->pubpi.phy_rev, 4)) {
+ chan_info_tbl_p_1 = chan_info_nphyrev4_2056_A1;
+ tbl_len = ARRAY_SIZE(chan_info_nphyrev4_2056_A1);
+ } else if (NREV_IS(pi->pubpi.phy_rev, 5)
+ || NREV_IS(pi->pubpi.phy_rev, 6)) {
+ switch (pi->pubpi.radiorev) {
+ case 5:
+ chan_info_tbl_p_1 = chan_info_nphyrev5_2056v5;
+ tbl_len = ARRAY_SIZE(chan_info_nphyrev5_2056v5);
+ break;
+ case 6:
+ chan_info_tbl_p_1 = chan_info_nphyrev6_2056v6;
+ tbl_len = ARRAY_SIZE(chan_info_nphyrev6_2056v6);
+ break;
+ case 7:
+ case 9:
+ chan_info_tbl_p_1 = chan_info_nphyrev5n6_2056v7;
+ tbl_len =
+ ARRAY_SIZE(chan_info_nphyrev5n6_2056v7);
+ break;
+ case 8:
+ chan_info_tbl_p_1 = chan_info_nphyrev6_2056v8;
+ tbl_len = ARRAY_SIZE(chan_info_nphyrev6_2056v8);
+ break;
+ case 11:
+ chan_info_tbl_p_1 = chan_info_nphyrev6_2056v11;
+ tbl_len = ARRAY_SIZE(
+ chan_info_nphyrev6_2056v11);
+ break;
+ default:
+ break;
+ }
+ }
+
+ for (i = 0; i < tbl_len; i++) {
+ if (chan_info_tbl_p_1[i].chan == channel)
+ break;
+ }
+
+ if (i >= tbl_len)
+ goto fail;
+
+ *t1 = &chan_info_tbl_p_1[i];
+ freq = chan_info_tbl_p_1[i].freq;
+
+ } else {
+ for (i = 0; i < ARRAY_SIZE(chan_info_nphy_2055); i++)
+ if (chan_info_nphy_2055[i].chan == channel)
+ break;
+
+ if (i >= ARRAY_SIZE(chan_info_nphy_2055))
+ goto fail;
+
+ *t3 = &chan_info_nphy_2055[i];
+ freq = chan_info_nphy_2055[i].freq;
+ }
+
+ *f = freq;
+ return true;
+
+fail:
+ *f = WL_CHAN_FREQ_RANGE_2G;
+ return false;
+}
+
+u8 wlc_phy_get_chan_freq_range_nphy(struct brcms_phy *pi, uint channel)
+{
+ int freq;
+ const struct chan_info_nphy_radio2057 *t0 = NULL;
+ const struct chan_info_nphy_radio205x *t1 = NULL;
+ const struct chan_info_nphy_radio2057_rev5 *t2 = NULL;
+ const struct chan_info_nphy_2055 *t3 = NULL;
+
+ if (channel == 0)
+ channel = CHSPEC_CHANNEL(pi->radio_chanspec);
+
+ wlc_phy_chan2freq_nphy(pi, channel, &freq, &t0, &t1, &t2, &t3);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ return WL_CHAN_FREQ_RANGE_2G;
+
+ if ((freq >= BASE_LOW_5G_CHAN) && (freq < BASE_MID_5G_CHAN))
+ return WL_CHAN_FREQ_RANGE_5GL;
+ else if ((freq >= BASE_MID_5G_CHAN) && (freq < BASE_HIGH_5G_CHAN))
+ return WL_CHAN_FREQ_RANGE_5GM;
+ else
+ return WL_CHAN_FREQ_RANGE_5GH;
+}
+
+static void
+wlc_phy_chanspec_radio2055_setup(struct brcms_phy *pi,
+ const struct chan_info_nphy_2055 *ci)
+{
+
+ write_radio_reg(pi, RADIO_2055_PLL_REF, ci->RF_pll_ref);
+ write_radio_reg(pi, RADIO_2055_RF_PLL_MOD0, ci->RF_rf_pll_mod0);
+ write_radio_reg(pi, RADIO_2055_RF_PLL_MOD1, ci->RF_rf_pll_mod1);
+ write_radio_reg(pi, RADIO_2055_VCO_CAP_TAIL, ci->RF_vco_cap_tail);
+
+ BRCMS_PHY_WAR_PR51571(pi);
+
+ write_radio_reg(pi, RADIO_2055_VCO_CAL1, ci->RF_vco_cal1);
+ write_radio_reg(pi, RADIO_2055_VCO_CAL2, ci->RF_vco_cal2);
+ write_radio_reg(pi, RADIO_2055_PLL_LF_C1, ci->RF_pll_lf_c1);
+ write_radio_reg(pi, RADIO_2055_PLL_LF_R1, ci->RF_pll_lf_r1);
+
+ BRCMS_PHY_WAR_PR51571(pi);
+
+ write_radio_reg(pi, RADIO_2055_PLL_LF_C2, ci->RF_pll_lf_c2);
+ write_radio_reg(pi, RADIO_2055_LGBUF_CEN_BUF, ci->RF_lgbuf_cen_buf);
+ write_radio_reg(pi, RADIO_2055_LGEN_TUNE1, ci->RF_lgen_tune1);
+ write_radio_reg(pi, RADIO_2055_LGEN_TUNE2, ci->RF_lgen_tune2);
+
+ BRCMS_PHY_WAR_PR51571(pi);
+
+ write_radio_reg(pi, RADIO_2055_CORE1_LGBUF_A_TUNE,
+ ci->RF_core1_lgbuf_a_tune);
+ write_radio_reg(pi, RADIO_2055_CORE1_LGBUF_G_TUNE,
+ ci->RF_core1_lgbuf_g_tune);
+ write_radio_reg(pi, RADIO_2055_CORE1_RXRF_REG1, ci->RF_core1_rxrf_reg1);
+ write_radio_reg(pi, RADIO_2055_CORE1_TX_PGA_PAD_TN,
+ ci->RF_core1_tx_pga_pad_tn);
+
+ BRCMS_PHY_WAR_PR51571(pi);
+
+ write_radio_reg(pi, RADIO_2055_CORE1_TX_MX_BGTRIM,
+ ci->RF_core1_tx_mx_bgtrim);
+ write_radio_reg(pi, RADIO_2055_CORE2_LGBUF_A_TUNE,
+ ci->RF_core2_lgbuf_a_tune);
+ write_radio_reg(pi, RADIO_2055_CORE2_LGBUF_G_TUNE,
+ ci->RF_core2_lgbuf_g_tune);
+ write_radio_reg(pi, RADIO_2055_CORE2_RXRF_REG1, ci->RF_core2_rxrf_reg1);
+
+ BRCMS_PHY_WAR_PR51571(pi);
+
+ write_radio_reg(pi, RADIO_2055_CORE2_TX_PGA_PAD_TN,
+ ci->RF_core2_tx_pga_pad_tn);
+ write_radio_reg(pi, RADIO_2055_CORE2_TX_MX_BGTRIM,
+ ci->RF_core2_tx_mx_bgtrim);
+
+ udelay(50);
+
+ write_radio_reg(pi, RADIO_2055_VCO_CAL10, 0x05);
+ write_radio_reg(pi, RADIO_2055_VCO_CAL10, 0x45);
+
+ BRCMS_PHY_WAR_PR51571(pi);
+
+ write_radio_reg(pi, RADIO_2055_VCO_CAL10, 0x65);
+
+ udelay(300);
+}
+
+static void
+wlc_phy_chanspec_radio2056_setup(struct brcms_phy *pi,
+ const struct chan_info_nphy_radio205x *ci)
+{
+ const struct radio_regs *regs_SYN_2056_ptr = NULL;
+
+ write_radio_reg(pi,
+ RADIO_2056_SYN_PLL_VCOCAL1 | RADIO_2056_SYN,
+ ci->RF_SYN_pll_vcocal1);
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_VCOCAL2 | RADIO_2056_SYN,
+ ci->RF_SYN_pll_vcocal2);
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_REFDIV | RADIO_2056_SYN,
+ ci->RF_SYN_pll_refdiv);
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_MMD2 | RADIO_2056_SYN,
+ ci->RF_SYN_pll_mmd2);
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_MMD1 | RADIO_2056_SYN,
+ ci->RF_SYN_pll_mmd1);
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER1 | RADIO_2056_SYN,
+ ci->RF_SYN_pll_loopfilter1);
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER2 | RADIO_2056_SYN,
+ ci->RF_SYN_pll_loopfilter2);
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER3 | RADIO_2056_SYN,
+ ci->RF_SYN_pll_loopfilter3);
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER4 | RADIO_2056_SYN,
+ ci->RF_SYN_pll_loopfilter4);
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER5 | RADIO_2056_SYN,
+ ci->RF_SYN_pll_loopfilter5);
+ write_radio_reg(pi, RADIO_2056_SYN_RESERVED_ADDR27 | RADIO_2056_SYN,
+ ci->RF_SYN_reserved_addr27);
+ write_radio_reg(pi, RADIO_2056_SYN_RESERVED_ADDR28 | RADIO_2056_SYN,
+ ci->RF_SYN_reserved_addr28);
+ write_radio_reg(pi, RADIO_2056_SYN_RESERVED_ADDR29 | RADIO_2056_SYN,
+ ci->RF_SYN_reserved_addr29);
+ write_radio_reg(pi, RADIO_2056_SYN_LOGEN_VCOBUF1 | RADIO_2056_SYN,
+ ci->RF_SYN_logen_VCOBUF1);
+ write_radio_reg(pi, RADIO_2056_SYN_LOGEN_MIXER2 | RADIO_2056_SYN,
+ ci->RF_SYN_logen_MIXER2);
+ write_radio_reg(pi, RADIO_2056_SYN_LOGEN_BUF3 | RADIO_2056_SYN,
+ ci->RF_SYN_logen_BUF3);
+ write_radio_reg(pi, RADIO_2056_SYN_LOGEN_BUF4 | RADIO_2056_SYN,
+ ci->RF_SYN_logen_BUF4);
+
+ write_radio_reg(pi,
+ RADIO_2056_RX_LNAA_TUNE | RADIO_2056_RX0,
+ ci->RF_RX0_lnaa_tune);
+ write_radio_reg(pi, RADIO_2056_RX_LNAG_TUNE | RADIO_2056_RX0,
+ ci->RF_RX0_lnag_tune);
+ write_radio_reg(pi, RADIO_2056_TX_INTPAA_BOOST_TUNE | RADIO_2056_TX0,
+ ci->RF_TX0_intpaa_boost_tune);
+ write_radio_reg(pi, RADIO_2056_TX_INTPAG_BOOST_TUNE | RADIO_2056_TX0,
+ ci->RF_TX0_intpag_boost_tune);
+ write_radio_reg(pi, RADIO_2056_TX_PADA_BOOST_TUNE | RADIO_2056_TX0,
+ ci->RF_TX0_pada_boost_tune);
+ write_radio_reg(pi, RADIO_2056_TX_PADG_BOOST_TUNE | RADIO_2056_TX0,
+ ci->RF_TX0_padg_boost_tune);
+ write_radio_reg(pi, RADIO_2056_TX_PGAA_BOOST_TUNE | RADIO_2056_TX0,
+ ci->RF_TX0_pgaa_boost_tune);
+ write_radio_reg(pi, RADIO_2056_TX_PGAG_BOOST_TUNE | RADIO_2056_TX0,
+ ci->RF_TX0_pgag_boost_tune);
+ write_radio_reg(pi, RADIO_2056_TX_MIXA_BOOST_TUNE | RADIO_2056_TX0,
+ ci->RF_TX0_mixa_boost_tune);
+ write_radio_reg(pi, RADIO_2056_TX_MIXG_BOOST_TUNE | RADIO_2056_TX0,
+ ci->RF_TX0_mixg_boost_tune);
+
+ write_radio_reg(pi,
+ RADIO_2056_RX_LNAA_TUNE | RADIO_2056_RX1,
+ ci->RF_RX1_lnaa_tune);
+ write_radio_reg(pi, RADIO_2056_RX_LNAG_TUNE | RADIO_2056_RX1,
+ ci->RF_RX1_lnag_tune);
+ write_radio_reg(pi, RADIO_2056_TX_INTPAA_BOOST_TUNE | RADIO_2056_TX1,
+ ci->RF_TX1_intpaa_boost_tune);
+ write_radio_reg(pi, RADIO_2056_TX_INTPAG_BOOST_TUNE | RADIO_2056_TX1,
+ ci->RF_TX1_intpag_boost_tune);
+ write_radio_reg(pi, RADIO_2056_TX_PADA_BOOST_TUNE | RADIO_2056_TX1,
+ ci->RF_TX1_pada_boost_tune);
+ write_radio_reg(pi, RADIO_2056_TX_PADG_BOOST_TUNE | RADIO_2056_TX1,
+ ci->RF_TX1_padg_boost_tune);
+ write_radio_reg(pi, RADIO_2056_TX_PGAA_BOOST_TUNE | RADIO_2056_TX1,
+ ci->RF_TX1_pgaa_boost_tune);
+ write_radio_reg(pi, RADIO_2056_TX_PGAG_BOOST_TUNE | RADIO_2056_TX1,
+ ci->RF_TX1_pgag_boost_tune);
+ write_radio_reg(pi, RADIO_2056_TX_MIXA_BOOST_TUNE | RADIO_2056_TX1,
+ ci->RF_TX1_mixa_boost_tune);
+ write_radio_reg(pi, RADIO_2056_TX_MIXG_BOOST_TUNE | RADIO_2056_TX1,
+ ci->RF_TX1_mixg_boost_tune);
+
+ if (NREV_IS(pi->pubpi.phy_rev, 3))
+ regs_SYN_2056_ptr = regs_SYN_2056;
+ else if (NREV_IS(pi->pubpi.phy_rev, 4))
+ regs_SYN_2056_ptr = regs_SYN_2056_A1;
+ else {
+ switch (pi->pubpi.radiorev) {
+ case 5:
+ regs_SYN_2056_ptr = regs_SYN_2056_rev5;
+ break;
+ case 6:
+ regs_SYN_2056_ptr = regs_SYN_2056_rev6;
+ break;
+ case 7:
+ case 9:
+ regs_SYN_2056_ptr = regs_SYN_2056_rev7;
+ break;
+ case 8:
+ regs_SYN_2056_ptr = regs_SYN_2056_rev8;
+ break;
+ case 11:
+ regs_SYN_2056_ptr = regs_SYN_2056_rev11;
+ break;
+ }
+ }
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_CP2 |
+ RADIO_2056_SYN,
+ (u16) regs_SYN_2056_ptr[0x49 - 2].init_g);
+ else
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_CP2 |
+ RADIO_2056_SYN,
+ (u16) regs_SYN_2056_ptr[0x49 - 2].init_a);
+
+ if (pi->sh->boardflags2 & BFL2_GPLL_WAR) {
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER1 |
+ RADIO_2056_SYN, 0x1f);
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER2 |
+ RADIO_2056_SYN, 0x1f);
+
+ write_radio_reg(pi,
+ RADIO_2056_SYN_PLL_LOOPFILTER4 |
+ RADIO_2056_SYN, 0xb);
+ write_radio_reg(pi,
+ RADIO_2056_SYN_PLL_CP2 |
+ RADIO_2056_SYN, 0x14);
+ }
+ }
+
+ if ((pi->sh->boardflags2 & BFL2_GPLL_WAR2) &&
+ (CHSPEC_IS2G(pi->radio_chanspec))) {
+ write_radio_reg(pi,
+ RADIO_2056_SYN_PLL_LOOPFILTER1 | RADIO_2056_SYN,
+ 0x1f);
+ write_radio_reg(pi,
+ RADIO_2056_SYN_PLL_LOOPFILTER2 | RADIO_2056_SYN,
+ 0x1f);
+ write_radio_reg(pi,
+ RADIO_2056_SYN_PLL_LOOPFILTER4 | RADIO_2056_SYN,
+ 0xb);
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_CP2 | RADIO_2056_SYN,
+ 0x20);
+ }
+
+ if (pi->sh->boardflags2 & BFL2_APLL_WAR) {
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER1 |
+ RADIO_2056_SYN, 0x1f);
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER2 |
+ RADIO_2056_SYN, 0x1f);
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER4 |
+ RADIO_2056_SYN, 0x5);
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_CP2 |
+ RADIO_2056_SYN, 0xc);
+ }
+ }
+
+ if (PHY_IPA(pi) && CHSPEC_IS2G(pi->radio_chanspec)) {
+ u16 pag_boost_tune;
+ u16 padg_boost_tune;
+ u16 pgag_boost_tune;
+ u16 mixg_boost_tune;
+ u16 bias, cascbias;
+ uint core;
+
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+
+ if (NREV_GE(pi->pubpi.phy_rev, 5)) {
+
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ PADG_IDAC, 0xcc);
+
+ bias = 0x25;
+ cascbias = 0x20;
+
+ if ((pi->sh->chip ==
+ BCM43224_CHIP_ID)
+ || (pi->sh->chip ==
+ BCM43225_CHIP_ID)) {
+ if (pi->sh->chippkg ==
+ BCM43224_FAB_SMIC) {
+ bias = 0x2a;
+ cascbias = 0x38;
+ }
+ }
+
+ pag_boost_tune = 0x4;
+ pgag_boost_tune = 0x03;
+ padg_boost_tune = 0x77;
+ mixg_boost_tune = 0x65;
+
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAG_IMAIN_STAT, bias);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAG_IAUX_STAT, bias);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAG_CASCBIAS, cascbias);
+
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAG_BOOST_TUNE,
+ pag_boost_tune);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ PGAG_BOOST_TUNE,
+ pgag_boost_tune);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ PADG_BOOST_TUNE,
+ padg_boost_tune);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ MIXG_BOOST_TUNE,
+ mixg_boost_tune);
+ } else {
+
+ bias = (pi->bw == WL_CHANSPEC_BW_40) ?
+ 0x40 : 0x20;
+
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAG_IMAIN_STAT, bias);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAG_IAUX_STAT, bias);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAG_CASCBIAS, 0x30);
+ }
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, PA_SPARE1,
+ 0xee);
+ }
+ }
+
+ if (PHY_IPA(pi) && NREV_IS(pi->pubpi.phy_rev, 6)
+ && CHSPEC_IS5G(pi->radio_chanspec)) {
+ u16 paa_boost_tune;
+ u16 pada_boost_tune;
+ u16 pgaa_boost_tune;
+ u16 mixa_boost_tune;
+ u16 freq, pabias, cascbias;
+ uint core;
+
+ freq = CHAN5G_FREQ(CHSPEC_CHANNEL(pi->radio_chanspec));
+
+ if (freq < 5150) {
+
+ paa_boost_tune = 0xa;
+ pada_boost_tune = 0x77;
+ pgaa_boost_tune = 0xf;
+ mixa_boost_tune = 0xf;
+ } else if (freq < 5340) {
+
+ paa_boost_tune = 0x8;
+ pada_boost_tune = 0x77;
+ pgaa_boost_tune = 0xfb;
+ mixa_boost_tune = 0xf;
+ } else if (freq < 5650) {
+
+ paa_boost_tune = 0x0;
+ pada_boost_tune = 0x77;
+ pgaa_boost_tune = 0xb;
+ mixa_boost_tune = 0xf;
+ } else {
+
+ paa_boost_tune = 0x0;
+ pada_boost_tune = 0x77;
+ if (freq != 5825)
+ pgaa_boost_tune = -(int)(freq - 18) / 36 + 168;
+ else
+ pgaa_boost_tune = 6;
+
+ mixa_boost_tune = 0xf;
+ }
+
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAA_BOOST_TUNE, paa_boost_tune);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ PADA_BOOST_TUNE, pada_boost_tune);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ PGAA_BOOST_TUNE, pgaa_boost_tune);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ MIXA_BOOST_TUNE, mixa_boost_tune);
+
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ TXSPARE1, 0x30);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ PA_SPARE2, 0xee);
+
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ PADA_CASCBIAS, 0x3);
+
+ cascbias = 0x30;
+
+ if ((pi->sh->chip == BCM43224_CHIP_ID) ||
+ (pi->sh->chip == BCM43225_CHIP_ID)) {
+ if (pi->sh->chippkg == BCM43224_FAB_SMIC)
+ cascbias = 0x35;
+ }
+
+ pabias = (pi->phy_pabias == 0) ? 0x30 : pi->phy_pabias;
+
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAA_IAUX_STAT, pabias);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAA_IMAIN_STAT, pabias);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAA_CASCBIAS, cascbias);
+ }
+ }
+
+ udelay(50);
+
+ wlc_phy_radio205x_vcocal_nphy(pi);
+}
+
+void wlc_phy_radio205x_vcocal_nphy(struct brcms_phy *pi)
+{
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ mod_radio_reg(pi, RADIO_2057_RFPLL_MISC_EN, 0x01, 0x0);
+ mod_radio_reg(pi, RADIO_2057_RFPLL_MISC_CAL_RESETN, 0x04, 0x0);
+ mod_radio_reg(pi, RADIO_2057_RFPLL_MISC_CAL_RESETN, 0x04,
+ (1 << 2));
+ mod_radio_reg(pi, RADIO_2057_RFPLL_MISC_EN, 0x01, 0x01);
+ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_VCOCAL12, 0x0);
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_MAST3, 0x38);
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_MAST3, 0x18);
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_MAST3, 0x38);
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_MAST3, 0x39);
+ }
+
+ udelay(300);
+}
+
+static void
+wlc_phy_chanspec_radio2057_setup(
+ struct brcms_phy *pi,
+ const struct chan_info_nphy_radio2057 *ci,
+ const struct chan_info_nphy_radio2057_rev5 *
+ ci2)
+{
+ int coreNum;
+ u16 txmix2g_tune_boost_pu = 0;
+ u16 pad2g_tune_pus = 0;
+
+ if (pi->pubpi.radiorev == 5) {
+
+ write_radio_reg(pi,
+ RADIO_2057_VCOCAL_COUNTVAL0,
+ ci2->RF_vcocal_countval0);
+ write_radio_reg(pi, RADIO_2057_VCOCAL_COUNTVAL1,
+ ci2->RF_vcocal_countval1);
+ write_radio_reg(pi, RADIO_2057_RFPLL_REFMASTER_SPAREXTALSIZE,
+ ci2->RF_rfpll_refmaster_sparextalsize);
+ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_R1,
+ ci2->RF_rfpll_loopfilter_r1);
+ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C2,
+ ci2->RF_rfpll_loopfilter_c2);
+ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C1,
+ ci2->RF_rfpll_loopfilter_c1);
+ write_radio_reg(pi, RADIO_2057_CP_KPD_IDAC,
+ ci2->RF_cp_kpd_idac);
+ write_radio_reg(pi, RADIO_2057_RFPLL_MMD0, ci2->RF_rfpll_mmd0);
+ write_radio_reg(pi, RADIO_2057_RFPLL_MMD1, ci2->RF_rfpll_mmd1);
+ write_radio_reg(pi,
+ RADIO_2057_VCOBUF_TUNE, ci2->RF_vcobuf_tune);
+ write_radio_reg(pi,
+ RADIO_2057_LOGEN_MX2G_TUNE,
+ ci2->RF_logen_mx2g_tune);
+ write_radio_reg(pi, RADIO_2057_LOGEN_INDBUF2G_TUNE,
+ ci2->RF_logen_indbuf2g_tune);
+
+ write_radio_reg(pi,
+ RADIO_2057_TXMIX2G_TUNE_BOOST_PU_CORE0,
+ ci2->RF_txmix2g_tune_boost_pu_core0);
+ write_radio_reg(pi,
+ RADIO_2057_PAD2G_TUNE_PUS_CORE0,
+ ci2->RF_pad2g_tune_pus_core0);
+ write_radio_reg(pi, RADIO_2057_LNA2G_TUNE_CORE0,
+ ci2->RF_lna2g_tune_core0);
+
+ write_radio_reg(pi,
+ RADIO_2057_TXMIX2G_TUNE_BOOST_PU_CORE1,
+ ci2->RF_txmix2g_tune_boost_pu_core1);
+ write_radio_reg(pi,
+ RADIO_2057_PAD2G_TUNE_PUS_CORE1,
+ ci2->RF_pad2g_tune_pus_core1);
+ write_radio_reg(pi, RADIO_2057_LNA2G_TUNE_CORE1,
+ ci2->RF_lna2g_tune_core1);
+
+ } else {
+
+ write_radio_reg(pi,
+ RADIO_2057_VCOCAL_COUNTVAL0,
+ ci->RF_vcocal_countval0);
+ write_radio_reg(pi, RADIO_2057_VCOCAL_COUNTVAL1,
+ ci->RF_vcocal_countval1);
+ write_radio_reg(pi, RADIO_2057_RFPLL_REFMASTER_SPAREXTALSIZE,
+ ci->RF_rfpll_refmaster_sparextalsize);
+ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_R1,
+ ci->RF_rfpll_loopfilter_r1);
+ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C2,
+ ci->RF_rfpll_loopfilter_c2);
+ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C1,
+ ci->RF_rfpll_loopfilter_c1);
+ write_radio_reg(pi, RADIO_2057_CP_KPD_IDAC, ci->RF_cp_kpd_idac);
+ write_radio_reg(pi, RADIO_2057_RFPLL_MMD0, ci->RF_rfpll_mmd0);
+ write_radio_reg(pi, RADIO_2057_RFPLL_MMD1, ci->RF_rfpll_mmd1);
+ write_radio_reg(pi, RADIO_2057_VCOBUF_TUNE, ci->RF_vcobuf_tune);
+ write_radio_reg(pi,
+ RADIO_2057_LOGEN_MX2G_TUNE,
+ ci->RF_logen_mx2g_tune);
+ write_radio_reg(pi, RADIO_2057_LOGEN_MX5G_TUNE,
+ ci->RF_logen_mx5g_tune);
+ write_radio_reg(pi, RADIO_2057_LOGEN_INDBUF2G_TUNE,
+ ci->RF_logen_indbuf2g_tune);
+ write_radio_reg(pi, RADIO_2057_LOGEN_INDBUF5G_TUNE,
+ ci->RF_logen_indbuf5g_tune);
+
+ write_radio_reg(pi,
+ RADIO_2057_TXMIX2G_TUNE_BOOST_PU_CORE0,
+ ci->RF_txmix2g_tune_boost_pu_core0);
+ write_radio_reg(pi,
+ RADIO_2057_PAD2G_TUNE_PUS_CORE0,
+ ci->RF_pad2g_tune_pus_core0);
+ write_radio_reg(pi, RADIO_2057_PGA_BOOST_TUNE_CORE0,
+ ci->RF_pga_boost_tune_core0);
+ write_radio_reg(pi, RADIO_2057_TXMIX5G_BOOST_TUNE_CORE0,
+ ci->RF_txmix5g_boost_tune_core0);
+ write_radio_reg(pi, RADIO_2057_PAD5G_TUNE_MISC_PUS_CORE0,
+ ci->RF_pad5g_tune_misc_pus_core0);
+ write_radio_reg(pi, RADIO_2057_LNA2G_TUNE_CORE0,
+ ci->RF_lna2g_tune_core0);
+ write_radio_reg(pi, RADIO_2057_LNA5G_TUNE_CORE0,
+ ci->RF_lna5g_tune_core0);
+
+ write_radio_reg(pi,
+ RADIO_2057_TXMIX2G_TUNE_BOOST_PU_CORE1,
+ ci->RF_txmix2g_tune_boost_pu_core1);
+ write_radio_reg(pi,
+ RADIO_2057_PAD2G_TUNE_PUS_CORE1,
+ ci->RF_pad2g_tune_pus_core1);
+ write_radio_reg(pi, RADIO_2057_PGA_BOOST_TUNE_CORE1,
+ ci->RF_pga_boost_tune_core1);
+ write_radio_reg(pi, RADIO_2057_TXMIX5G_BOOST_TUNE_CORE1,
+ ci->RF_txmix5g_boost_tune_core1);
+ write_radio_reg(pi, RADIO_2057_PAD5G_TUNE_MISC_PUS_CORE1,
+ ci->RF_pad5g_tune_misc_pus_core1);
+ write_radio_reg(pi, RADIO_2057_LNA2G_TUNE_CORE1,
+ ci->RF_lna2g_tune_core1);
+ write_radio_reg(pi, RADIO_2057_LNA5G_TUNE_CORE1,
+ ci->RF_lna5g_tune_core1);
+ }
+
+ if ((pi->pubpi.radiorev <= 4) || (pi->pubpi.radiorev == 6)) {
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_R1,
+ 0x3f);
+ write_radio_reg(pi, RADIO_2057_CP_KPD_IDAC, 0x3f);
+ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C1,
+ 0x8);
+ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C2,
+ 0x8);
+ } else {
+ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_R1,
+ 0x1f);
+ write_radio_reg(pi, RADIO_2057_CP_KPD_IDAC, 0x3f);
+ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C1,
+ 0x8);
+ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C2,
+ 0x8);
+ }
+ } else if ((pi->pubpi.radiorev == 5) || (pi->pubpi.radiorev == 7) ||
+ (pi->pubpi.radiorev == 8)) {
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_R1,
+ 0x1b);
+ write_radio_reg(pi, RADIO_2057_CP_KPD_IDAC, 0x30);
+ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C1,
+ 0xa);
+ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C2,
+ 0xa);
+ } else {
+ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_R1,
+ 0x1f);
+ write_radio_reg(pi, RADIO_2057_CP_KPD_IDAC, 0x3f);
+ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C1,
+ 0x8);
+ write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C2,
+ 0x8);
+ }
+
+ }
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if (PHY_IPA(pi)) {
+ if (pi->pubpi.radiorev == 3)
+ txmix2g_tune_boost_pu = 0x6b;
+
+ if (pi->pubpi.radiorev == 5)
+ pad2g_tune_pus = 0x73;
+
+ } else {
+ if (pi->pubpi.radiorev != 5) {
+ pad2g_tune_pus = 0x3;
+
+ txmix2g_tune_boost_pu = 0x61;
+ }
+ }
+
+ for (coreNum = 0; coreNum <= 1; coreNum++) {
+
+ if (txmix2g_tune_boost_pu != 0)
+ WRITE_RADIO_REG4(pi, RADIO_2057, CORE, coreNum,
+ TXMIX2G_TUNE_BOOST_PU,
+ txmix2g_tune_boost_pu);
+
+ if (pad2g_tune_pus != 0)
+ WRITE_RADIO_REG4(pi, RADIO_2057, CORE, coreNum,
+ PAD2G_TUNE_PUS,
+ pad2g_tune_pus);
+ }
+ }
+
+ udelay(50);
+
+ wlc_phy_radio205x_vcocal_nphy(pi);
+}
+
+static void
+wlc_phy_chanspec_nphy_setup(struct brcms_phy *pi, u16 chanspec,
+ const struct nphy_sfo_cfg *ci)
+{
+ u16 val;
+
+ val = read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand;
+ if (CHSPEC_IS5G(chanspec) && !val) {
+
+ val = R_REG(&pi->regs->psm_phy_hdr_param);
+ W_REG(&pi->regs->psm_phy_hdr_param,
+ (val | MAC_PHY_FORCE_CLK));
+
+ or_phy_reg(pi, (NPHY_TO_BPHY_OFF + BPHY_BB_CONFIG),
+ (BBCFG_RESETCCA | BBCFG_RESETRX));
+
+ W_REG(&pi->regs->psm_phy_hdr_param, val);
+
+ or_phy_reg(pi, 0x09, NPHY_BandControl_currentBand);
+ } else if (!CHSPEC_IS5G(chanspec) && val) {
+
+ and_phy_reg(pi, 0x09, ~NPHY_BandControl_currentBand);
+
+ val = R_REG(&pi->regs->psm_phy_hdr_param);
+ W_REG(&pi->regs->psm_phy_hdr_param,
+ (val | MAC_PHY_FORCE_CLK));
+
+ and_phy_reg(pi, (NPHY_TO_BPHY_OFF + BPHY_BB_CONFIG),
+ (u16) (~(BBCFG_RESETCCA | BBCFG_RESETRX)));
+
+ W_REG(&pi->regs->psm_phy_hdr_param, val);
+ }
+
+ write_phy_reg(pi, 0x1ce, ci->PHY_BW1a);
+ write_phy_reg(pi, 0x1cf, ci->PHY_BW2);
+ write_phy_reg(pi, 0x1d0, ci->PHY_BW3);
+
+ write_phy_reg(pi, 0x1d1, ci->PHY_BW4);
+ write_phy_reg(pi, 0x1d2, ci->PHY_BW5);
+ write_phy_reg(pi, 0x1d3, ci->PHY_BW6);
+
+ if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) {
+ wlc_phy_classifier_nphy(pi, NPHY_ClassifierCtrl_ofdm_en, 0);
+
+ or_phy_reg(pi, NPHY_TO_BPHY_OFF + BPHY_TEST, 0x800);
+ } else {
+ wlc_phy_classifier_nphy(pi, NPHY_ClassifierCtrl_ofdm_en,
+ NPHY_ClassifierCtrl_ofdm_en);
+
+ if (CHSPEC_IS2G(chanspec))
+ and_phy_reg(pi, NPHY_TO_BPHY_OFF + BPHY_TEST, ~0x840);
+ }
+
+ if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF)
+ wlc_phy_txpwr_fixpower_nphy(pi);
+
+ if (NREV_LT(pi->pubpi.phy_rev, 3))
+ wlc_phy_adjust_lnagaintbl_nphy(pi);
+
+ wlc_phy_txlpfbw_nphy(pi);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)
+ && (pi->phy_spuravoid != SPURAVOID_DISABLE)) {
+ u8 spuravoid = 0;
+
+ val = CHSPEC_CHANNEL(chanspec);
+ if (!CHSPEC_IS40(pi->radio_chanspec)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if ((val == 13) || (val == 14) || (val == 153))
+ spuravoid = 1;
+ } else if (((val >= 5) && (val <= 8)) || (val == 13)
+ || (val == 14)) {
+ spuravoid = 1;
+ }
+ } else if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (val == 54)
+ spuravoid = 1;
+ } else {
+ if (pi->nphy_aband_spurwar_en &&
+ ((val == 38) || (val == 102)
+ || (val == 118)))
+ spuravoid = 1;
+ }
+
+ if (pi->phy_spuravoid == SPURAVOID_FORCEON)
+ spuravoid = 1;
+
+ wlapi_bmac_core_phypll_ctl(pi->sh->physhim, false);
+ si_pmu_spuravoid(pi->sh->sih, spuravoid);
+ wlapi_bmac_core_phypll_ctl(pi->sh->physhim, true);
+
+ if ((pi->sh->chip == BCM43224_CHIP_ID) ||
+ (pi->sh->chip == BCM43225_CHIP_ID)) {
+
+ if (spuravoid == 1) {
+
+ W_REG(&pi->regs->tsf_clk_frac_l,
+ 0x5341);
+ W_REG(&pi->regs->tsf_clk_frac_h,
+ 0x8);
+ } else {
+
+ W_REG(&pi->regs->tsf_clk_frac_l,
+ 0x8889);
+ W_REG(&pi->regs->tsf_clk_frac_h,
+ 0x8);
+ }
+ }
+
+ wlapi_bmac_core_phypll_reset(pi->sh->physhim);
+
+ mod_phy_reg(pi, 0x01, (0x1 << 15),
+ ((spuravoid > 0) ? (0x1 << 15) : 0));
+
+ wlc_phy_resetcca_nphy(pi);
+
+ pi->phy_isspuravoid = (spuravoid > 0);
+ }
+
+ if (NREV_LT(pi->pubpi.phy_rev, 7))
+ write_phy_reg(pi, 0x17e, 0x3830);
+
+ wlc_phy_spurwar_nphy(pi);
+}
+
+void wlc_phy_chanspec_set_nphy(struct brcms_phy *pi, u16 chanspec)
+{
+ int freq;
+ const struct chan_info_nphy_radio2057 *t0 = NULL;
+ const struct chan_info_nphy_radio205x *t1 = NULL;
+ const struct chan_info_nphy_radio2057_rev5 *t2 = NULL;
+ const struct chan_info_nphy_2055 *t3 = NULL;
+
+ if (!wlc_phy_chan2freq_nphy
+ (pi, CHSPEC_CHANNEL(chanspec), &freq, &t0, &t1, &t2, &t3))
+ return;
+
+ wlc_phy_chanspec_radio_set((struct brcms_phy_pub *) pi, chanspec);
+
+ if (CHSPEC_BW(chanspec) != pi->bw)
+ wlapi_bmac_bw_set(pi->sh->physhim, CHSPEC_BW(chanspec));
+
+ if (CHSPEC_IS40(chanspec)) {
+ if (CHSPEC_SB_UPPER(chanspec)) {
+ or_phy_reg(pi, 0xa0, BPHY_BAND_SEL_UP20);
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ or_phy_reg(pi, 0x310, PRIM_SEL_UP20);
+ } else {
+ and_phy_reg(pi, 0xa0, ~BPHY_BAND_SEL_UP20);
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ and_phy_reg(pi, 0x310,
+ (~PRIM_SEL_UP20 & 0xffff));
+ }
+ }
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ if ((pi->pubpi.radiorev <= 4)
+ || (pi->pubpi.radiorev == 6)) {
+ mod_radio_reg(pi, RADIO_2057_TIA_CONFIG_CORE0,
+ 0x2,
+ (CHSPEC_IS5G(chanspec) ? (1 << 1)
+ : 0));
+ mod_radio_reg(pi, RADIO_2057_TIA_CONFIG_CORE1,
+ 0x2,
+ (CHSPEC_IS5G(chanspec) ? (1 << 1)
+ : 0));
+ }
+
+ wlc_phy_chanspec_radio2057_setup(pi, t0, t2);
+ wlc_phy_chanspec_nphy_setup(pi, chanspec,
+ (pi->pubpi.radiorev == 5) ?
+ (const struct nphy_sfo_cfg *)&(t2->PHY_BW1a) :
+ (const struct nphy_sfo_cfg *)&(t0->PHY_BW1a));
+
+ } else {
+
+ mod_radio_reg(pi,
+ RADIO_2056_SYN_COM_CTRL | RADIO_2056_SYN,
+ 0x4,
+ (CHSPEC_IS5G(chanspec) ? (0x1 << 2) : 0));
+ wlc_phy_chanspec_radio2056_setup(pi, t1);
+
+ wlc_phy_chanspec_nphy_setup(pi, chanspec,
+ (const struct nphy_sfo_cfg *) &(t1->PHY_BW1a));
+ }
+
+ } else {
+
+ mod_radio_reg(pi, RADIO_2055_MASTER_CNTRL1, 0x70,
+ (CHSPEC_IS5G(chanspec) ? (0x02 << 4)
+ : (0x05 << 4)));
+
+ wlc_phy_chanspec_radio2055_setup(pi, t3);
+ wlc_phy_chanspec_nphy_setup(pi, chanspec,
+ (const struct nphy_sfo_cfg *)
+ &(t3->PHY_BW1a));
+ }
+
+}
+
+void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ u16 mask = 0xfc00;
+ u32 mc = 0;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ return;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ u16 v0 = 0x211, v1 = 0x222, v2 = 0x144, v3 = 0x188;
+
+ if (lut_init == false)
+ return;
+
+ if (pi->srom_fem2g.antswctrllut == 0) {
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT,
+ 1, 0x02, 16, &v0);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT,
+ 1, 0x03, 16, &v1);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT,
+ 1, 0x08, 16, &v2);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT,
+ 1, 0x0C, 16, &v3);
+ }
+
+ if (pi->srom_fem5g.antswctrllut == 0) {
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT,
+ 1, 0x12, 16, &v0);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT,
+ 1, 0x13, 16, &v1);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT,
+ 1, 0x18, 16, &v2);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT,
+ 1, 0x1C, 16, &v3);
+ }
+ } else {
+
+ write_phy_reg(pi, 0xc8, 0x0);
+ write_phy_reg(pi, 0xc9, 0x0);
+
+ ai_gpiocontrol(pi->sh->sih, mask, mask, GPIO_DRV_PRIORITY);
+
+ mc = R_REG(&pi->regs->maccontrol);
+ mc &= ~MCTL_GPOUT_SEL_MASK;
+ W_REG(&pi->regs->maccontrol, mc);
+
+ OR_REG(&pi->regs->psm_gpio_oe, mask);
+
+ AND_REG(&pi->regs->psm_gpio_out, ~mask);
+
+ if (lut_init) {
+ write_phy_reg(pi, 0xf8, 0x02d8);
+ write_phy_reg(pi, 0xf9, 0x0301);
+ write_phy_reg(pi, 0xfa, 0x02d8);
+ write_phy_reg(pi, 0xfb, 0x0301);
+ }
+ }
+}
+
+u16 wlc_phy_classifier_nphy(struct brcms_phy *pi, u16 mask, u16 val)
+{
+ u16 curr_ctl, new_ctl;
+ bool suspended = false;
+
+ if (D11REV_IS(pi->sh->corerev, 16)) {
+ suspended =
+ (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC) ?
+ false : true;
+ if (!suspended)
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+ }
+
+ curr_ctl = read_phy_reg(pi, 0xb0) & (0x7 << 0);
+
+ new_ctl = (curr_ctl & (~mask)) | (val & mask);
+
+ mod_phy_reg(pi, 0xb0, (0x7 << 0), new_ctl);
+
+ if (D11REV_IS(pi->sh->corerev, 16) && !suspended)
+ wlapi_enable_mac(pi->sh->physhim);
+
+ return new_ctl;
+}
+
+void wlc_phy_force_rfseq_nphy(struct brcms_phy *pi, u8 cmd)
+{
+ u16 trigger_mask, status_mask;
+ u16 orig_RfseqCoreActv;
+
+ switch (cmd) {
+ case NPHY_RFSEQ_RX2TX:
+ trigger_mask = NPHY_RfseqTrigger_rx2tx;
+ status_mask = NPHY_RfseqStatus_rx2tx;
+ break;
+ case NPHY_RFSEQ_TX2RX:
+ trigger_mask = NPHY_RfseqTrigger_tx2rx;
+ status_mask = NPHY_RfseqStatus_tx2rx;
+ break;
+ case NPHY_RFSEQ_RESET2RX:
+ trigger_mask = NPHY_RfseqTrigger_reset2rx;
+ status_mask = NPHY_RfseqStatus_reset2rx;
+ break;
+ case NPHY_RFSEQ_UPDATEGAINH:
+ trigger_mask = NPHY_RfseqTrigger_updategainh;
+ status_mask = NPHY_RfseqStatus_updategainh;
+ break;
+ case NPHY_RFSEQ_UPDATEGAINL:
+ trigger_mask = NPHY_RfseqTrigger_updategainl;
+ status_mask = NPHY_RfseqStatus_updategainl;
+ break;
+ case NPHY_RFSEQ_UPDATEGAINU:
+ trigger_mask = NPHY_RfseqTrigger_updategainu;
+ status_mask = NPHY_RfseqStatus_updategainu;
+ break;
+ default:
+ return;
+ }
+
+ orig_RfseqCoreActv = read_phy_reg(pi, 0xa1);
+ or_phy_reg(pi, 0xa1,
+ (NPHY_RfseqMode_CoreActv_override |
+ NPHY_RfseqMode_Trigger_override));
+ or_phy_reg(pi, 0xa3, trigger_mask);
+ SPINWAIT((read_phy_reg(pi, 0xa4) & status_mask), 200000);
+ write_phy_reg(pi, 0xa1, orig_RfseqCoreActv);
+ WARN(read_phy_reg(pi, 0xa4) & status_mask, "HW error in rf");
+}
+
+static void
+wlc_phy_rfctrl_override_1tomany_nphy(struct brcms_phy *pi, u16 cmd, u16 value,
+ u8 core_mask, u8 off)
+{
+ u16 rfmxgain = 0, lpfgain = 0;
+ u16 tgain = 0;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ switch (cmd) {
+ case NPHY_REV7_RfctrlOverride_cmd_rxrf_pu:
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 5),
+ value, core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 4), value,
+ core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 3), value,
+ core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ break;
+ case NPHY_REV7_RfctrlOverride_cmd_rx_pu:
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 2),
+ value, core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 1), value,
+ core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 0), value,
+ core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 1), value,
+ core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID2);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 11), 0,
+ core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ break;
+ case NPHY_REV7_RfctrlOverride_cmd_tx_pu:
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 2),
+ value, core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 1), value,
+ core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 0), value,
+ core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID2);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 2), value,
+ core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID2);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 11), 1,
+ core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ break;
+ case NPHY_REV7_RfctrlOverride_cmd_rxgain:
+ rfmxgain = value & 0x000ff;
+ lpfgain = value & 0x0ff00;
+ lpfgain = lpfgain >> 8;
+
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 11),
+ rfmxgain, core_mask,
+ off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x3 << 13),
+ lpfgain, core_mask,
+ off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ break;
+ case NPHY_REV7_RfctrlOverride_cmd_txgain:
+ tgain = value & 0x7fff;
+ lpfgain = value & 0x8000;
+ lpfgain = lpfgain >> 14;
+
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 12),
+ tgain, core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 13),
+ lpfgain, core_mask,
+ off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ break;
+ }
+ }
+}
+
+static void
+wlc_phy_scale_offset_rssi_nphy(struct brcms_phy *pi, u16 scale, s8 offset,
+ u8 coresel, u8 rail, u8 rssi_type)
+{
+ u16 valuetostuff;
+
+ offset = (offset > NPHY_RSSICAL_MAXREAD) ?
+ NPHY_RSSICAL_MAXREAD : offset;
+ offset = (offset < (-NPHY_RSSICAL_MAXREAD - 1)) ?
+ -NPHY_RSSICAL_MAXREAD - 1 : offset;
+
+ valuetostuff = ((scale & 0x3f) << 8) | (offset & 0x3f);
+
+ if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_NB))
+ write_phy_reg(pi, 0x1a6, valuetostuff);
+
+ if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_NB))
+ write_phy_reg(pi, 0x1ac, valuetostuff);
+
+ if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_NB))
+ write_phy_reg(pi, 0x1b2, valuetostuff);
+
+ if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_NB))
+ write_phy_reg(pi, 0x1b8, valuetostuff);
+
+ if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_W1))
+ write_phy_reg(pi, 0x1a4, valuetostuff);
+
+ if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_W1))
+ write_phy_reg(pi, 0x1aa, valuetostuff);
+
+ if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_W1))
+ write_phy_reg(pi, 0x1b0, valuetostuff);
+
+ if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_W1))
+ write_phy_reg(pi, 0x1b6, valuetostuff);
+
+ if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_W2))
+ write_phy_reg(pi, 0x1a5, valuetostuff);
+ if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_W2))
+ write_phy_reg(pi, 0x1ab, valuetostuff);
+
+ if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_W2))
+ write_phy_reg(pi, 0x1b1, valuetostuff);
+
+ if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_W2))
+ write_phy_reg(pi, 0x1b7, valuetostuff);
+
+ if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_TBD))
+ write_phy_reg(pi, 0x1a7, valuetostuff);
+ if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_TBD))
+ write_phy_reg(pi, 0x1ad, valuetostuff);
+ if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_TBD))
+ write_phy_reg(pi, 0x1b3, valuetostuff);
+ if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_TBD))
+ write_phy_reg(pi, 0x1b9, valuetostuff);
+
+ if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_IQ))
+ write_phy_reg(pi, 0x1a8, valuetostuff);
+
+ if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_IQ))
+ write_phy_reg(pi, 0x1ae, valuetostuff);
+
+ if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_IQ))
+ write_phy_reg(pi, 0x1b4, valuetostuff);
+
+ if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_IQ))
+ write_phy_reg(pi, 0x1ba, valuetostuff);
+
+ if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rssi_type == NPHY_RSSI_SEL_TSSI_2G))
+ write_phy_reg(pi, 0x1a9, valuetostuff);
+ if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rssi_type == NPHY_RSSI_SEL_TSSI_2G))
+ write_phy_reg(pi, 0x1b5, valuetostuff);
+
+ if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rssi_type == NPHY_RSSI_SEL_TSSI_5G))
+ write_phy_reg(pi, 0x1af, valuetostuff);
+
+ if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
+ (coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
+ (rssi_type == NPHY_RSSI_SEL_TSSI_5G))
+ write_phy_reg(pi, 0x1bb, valuetostuff);
+}
+
+static void brcms_phy_wr_tx_mux(struct brcms_phy *pi, u8 core)
+{
+ if (PHY_IPA(pi)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ write_radio_reg(pi,
+ ((core == PHY_CORE_0) ?
+ RADIO_2057_TX0_TX_SSI_MUX :
+ RADIO_2057_TX1_TX_SSI_MUX),
+ (CHSPEC_IS5G(pi->radio_chanspec) ?
+ 0xc : 0xe));
+ else
+ write_radio_reg(pi,
+ RADIO_2056_TX_TX_SSI_MUX |
+ ((core == PHY_CORE_0) ?
+ RADIO_2056_TX0 : RADIO_2056_TX1),
+ (CHSPEC_IS5G(pi->radio_chanspec) ?
+ 0xc : 0xe));
+ } else {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ write_radio_reg(pi,
+ ((core == PHY_CORE_0) ?
+ RADIO_2057_TX0_TX_SSI_MUX :
+ RADIO_2057_TX1_TX_SSI_MUX),
+ 0x11);
+
+ if (pi->pubpi.radioid == BCM2057_ID)
+ write_radio_reg(pi,
+ RADIO_2057_IQTEST_SEL_PU, 0x1);
+
+ } else {
+ write_radio_reg(pi,
+ RADIO_2056_TX_TX_SSI_MUX |
+ ((core == PHY_CORE_0) ?
+ RADIO_2056_TX0 : RADIO_2056_TX1),
+ 0x11);
+ }
+ }
+}
+
+void wlc_phy_rssisel_nphy(struct brcms_phy *pi, u8 core_code, u8 rssi_type)
+{
+ u16 mask, val;
+ u16 afectrlovr_rssi_val, rfctrlcmd_rxen_val, rfctrlcmd_coresel_val,
+ startseq;
+ u16 rfctrlovr_rssi_val, rfctrlovr_rxen_val, rfctrlovr_coresel_val,
+ rfctrlovr_trigger_val;
+ u16 afectrlovr_rssi_mask, rfctrlcmd_mask, rfctrlovr_mask;
+ u16 rfctrlcmd_val, rfctrlovr_val;
+ u8 core;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ if (core_code == RADIO_MIMO_CORESEL_OFF) {
+ mod_phy_reg(pi, 0x8f, (0x1 << 9), 0);
+ mod_phy_reg(pi, 0xa5, (0x1 << 9), 0);
+
+ mod_phy_reg(pi, 0xa6, (0x3 << 8), 0);
+ mod_phy_reg(pi, 0xa7, (0x3 << 8), 0);
+
+ mod_phy_reg(pi, 0xe5, (0x1 << 5), 0);
+ mod_phy_reg(pi, 0xe6, (0x1 << 5), 0);
+
+ mask = (0x1 << 2) |
+ (0x1 << 3) | (0x1 << 4) | (0x1 << 5);
+ mod_phy_reg(pi, 0xf9, mask, 0);
+ mod_phy_reg(pi, 0xfb, mask, 0);
+
+ } else {
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+ if (core_code == RADIO_MIMO_CORESEL_CORE1
+ && core == PHY_CORE_1)
+ continue;
+ else if (core_code == RADIO_MIMO_CORESEL_CORE2
+ && core == PHY_CORE_0)
+ continue;
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ?
+ 0x8f : 0xa5, (0x1 << 9), 1 << 9);
+
+ if (rssi_type == NPHY_RSSI_SEL_W1 ||
+ rssi_type == NPHY_RSSI_SEL_W2 ||
+ rssi_type == NPHY_RSSI_SEL_NB) {
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0xa6 : 0xa7,
+ (0x3 << 8), 0);
+
+ mask = (0x1 << 2) |
+ (0x1 << 3) |
+ (0x1 << 4) | (0x1 << 5);
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0xf9 : 0xfb,
+ mask, 0);
+
+ if (rssi_type == NPHY_RSSI_SEL_W1) {
+ if (CHSPEC_IS5G(
+ pi->radio_chanspec)) {
+ mask = (0x1 << 2);
+ val = 1 << 2;
+ } else {
+ mask = (0x1 << 3);
+ val = 1 << 3;
+ }
+ } else if (rssi_type ==
+ NPHY_RSSI_SEL_W2) {
+ mask = (0x1 << 4);
+ val = 1 << 4;
+ } else {
+ mask = (0x1 << 5);
+ val = 1 << 5;
+ }
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0xf9 : 0xfb,
+ mask, val);
+
+ mask = (0x1 << 5);
+ val = 1 << 5;
+ mod_phy_reg(pi, (core == PHY_CORE_0) ?
+ 0xe5 : 0xe6, mask, val);
+ } else {
+ if (rssi_type == NPHY_RSSI_SEL_TBD) {
+ mask = (0x3 << 8);
+ val = 1 << 8;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0xa6
+ : 0xa7, mask, val);
+ mask = (0x3 << 10);
+ val = 1 << 10;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0xa6
+ : 0xa7, mask, val);
+ } else if (rssi_type ==
+ NPHY_RSSI_SEL_IQ) {
+ mask = (0x3 << 8);
+ val = 2 << 8;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0xa6
+ : 0xa7, mask, val);
+ mask = (0x3 << 10);
+ val = 2 << 10;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0xa6
+ : 0xa7, mask, val);
+ } else {
+ mask = (0x3 << 8);
+ val = 3 << 8;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0xa6
+ : 0xa7, mask, val);
+ mask = (0x3 << 10);
+ val = 3 << 10;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0xa6
+ : 0xa7, mask, val);
+ brcms_phy_wr_tx_mux(pi, core);
+ afectrlovr_rssi_val = 1 << 9;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x8f
+ : 0xa5, (0x1 << 9),
+ afectrlovr_rssi_val);
+ }
+ }
+ }
+ }
+ } else {
+
+ if ((rssi_type == NPHY_RSSI_SEL_W1) ||
+ (rssi_type == NPHY_RSSI_SEL_W2) ||
+ (rssi_type == NPHY_RSSI_SEL_NB))
+ val = 0x0;
+ else if (rssi_type == NPHY_RSSI_SEL_TBD)
+ val = 0x1;
+ else if (rssi_type == NPHY_RSSI_SEL_IQ)
+ val = 0x2;
+ else
+ val = 0x3;
+
+ mask = ((0x3 << 12) | (0x3 << 14));
+ val = (val << 12) | (val << 14);
+ mod_phy_reg(pi, 0xa6, mask, val);
+ mod_phy_reg(pi, 0xa7, mask, val);
+
+ if ((rssi_type == NPHY_RSSI_SEL_W1) ||
+ (rssi_type == NPHY_RSSI_SEL_W2) ||
+ (rssi_type == NPHY_RSSI_SEL_NB)) {
+ if (rssi_type == NPHY_RSSI_SEL_W1)
+ val = 0x1;
+ if (rssi_type == NPHY_RSSI_SEL_W2)
+ val = 0x2;
+ if (rssi_type == NPHY_RSSI_SEL_NB)
+ val = 0x3;
+
+ mask = (0x3 << 4);
+ val = (val << 4);
+ mod_phy_reg(pi, 0x7a, mask, val);
+ mod_phy_reg(pi, 0x7d, mask, val);
+ }
+
+ if (core_code == RADIO_MIMO_CORESEL_OFF) {
+ afectrlovr_rssi_val = 0;
+ rfctrlcmd_rxen_val = 0;
+ rfctrlcmd_coresel_val = 0;
+ rfctrlovr_rssi_val = 0;
+ rfctrlovr_rxen_val = 0;
+ rfctrlovr_coresel_val = 0;
+ rfctrlovr_trigger_val = 0;
+ startseq = 0;
+ } else {
+ afectrlovr_rssi_val = 1;
+ rfctrlcmd_rxen_val = 1;
+ rfctrlcmd_coresel_val = core_code;
+ rfctrlovr_rssi_val = 1;
+ rfctrlovr_rxen_val = 1;
+ rfctrlovr_coresel_val = 1;
+ rfctrlovr_trigger_val = 1;
+ startseq = 1;
+ }
+
+ afectrlovr_rssi_mask = ((0x1 << 12) | (0x1 << 13));
+ afectrlovr_rssi_val = (afectrlovr_rssi_val <<
+ 12) | (afectrlovr_rssi_val << 13);
+ mod_phy_reg(pi, 0xa5, afectrlovr_rssi_mask,
+ afectrlovr_rssi_val);
+
+ if ((rssi_type == NPHY_RSSI_SEL_W1) ||
+ (rssi_type == NPHY_RSSI_SEL_W2) ||
+ (rssi_type == NPHY_RSSI_SEL_NB)) {
+ rfctrlcmd_mask = ((0x1 << 8) | (0x7 << 3));
+ rfctrlcmd_val = (rfctrlcmd_rxen_val << 8) |
+ (rfctrlcmd_coresel_val << 3);
+
+ rfctrlovr_mask = ((0x1 << 5) |
+ (0x1 << 12) |
+ (0x1 << 1) | (0x1 << 0));
+ rfctrlovr_val = (rfctrlovr_rssi_val <<
+ 5) |
+ (rfctrlovr_rxen_val << 12) |
+ (rfctrlovr_coresel_val << 1) |
+ (rfctrlovr_trigger_val << 0);
+
+ mod_phy_reg(pi, 0x78, rfctrlcmd_mask, rfctrlcmd_val);
+ mod_phy_reg(pi, 0xec, rfctrlovr_mask, rfctrlovr_val);
+
+ mod_phy_reg(pi, 0x78, (0x1 << 0), (startseq << 0));
+ udelay(20);
+
+ mod_phy_reg(pi, 0xec, (0x1 << 0), 0);
+ }
+ }
+}
+
+int
+wlc_phy_poll_rssi_nphy(struct brcms_phy *pi, u8 rssi_type, s32 *rssi_buf,
+ u8 nsamps)
+{
+ s16 rssi0, rssi1;
+ u16 afectrlCore1_save = 0;
+ u16 afectrlCore2_save = 0;
+ u16 afectrlOverride1_save = 0;
+ u16 afectrlOverride2_save = 0;
+ u16 rfctrlOverrideAux0_save = 0;
+ u16 rfctrlOverrideAux1_save = 0;
+ u16 rfctrlMiscReg1_save = 0;
+ u16 rfctrlMiscReg2_save = 0;
+ u16 rfctrlcmd_save = 0;
+ u16 rfctrloverride_save = 0;
+ u16 rfctrlrssiothers1_save = 0;
+ u16 rfctrlrssiothers2_save = 0;
+ s8 tmp_buf[4];
+ u8 ctr = 0, samp = 0;
+ s32 rssi_out_val;
+ u16 gpiosel_orig;
+
+ afectrlCore1_save = read_phy_reg(pi, 0xa6);
+ afectrlCore2_save = read_phy_reg(pi, 0xa7);
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ rfctrlMiscReg1_save = read_phy_reg(pi, 0xf9);
+ rfctrlMiscReg2_save = read_phy_reg(pi, 0xfb);
+ afectrlOverride1_save = read_phy_reg(pi, 0x8f);
+ afectrlOverride2_save = read_phy_reg(pi, 0xa5);
+ rfctrlOverrideAux0_save = read_phy_reg(pi, 0xe5);
+ rfctrlOverrideAux1_save = read_phy_reg(pi, 0xe6);
+ } else {
+ afectrlOverride1_save = read_phy_reg(pi, 0xa5);
+ rfctrlcmd_save = read_phy_reg(pi, 0x78);
+ rfctrloverride_save = read_phy_reg(pi, 0xec);
+ rfctrlrssiothers1_save = read_phy_reg(pi, 0x7a);
+ rfctrlrssiothers2_save = read_phy_reg(pi, 0x7d);
+ }
+
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_ALLRX, rssi_type);
+
+ gpiosel_orig = read_phy_reg(pi, 0xca);
+ if (NREV_LT(pi->pubpi.phy_rev, 2))
+ write_phy_reg(pi, 0xca, 5);
+
+ for (ctr = 0; ctr < 4; ctr++)
+ rssi_buf[ctr] = 0;
+
+ for (samp = 0; samp < nsamps; samp++) {
+ if (NREV_LT(pi->pubpi.phy_rev, 2)) {
+ rssi0 = read_phy_reg(pi, 0x1c9);
+ rssi1 = read_phy_reg(pi, 0x1ca);
+ } else {
+ rssi0 = read_phy_reg(pi, 0x219);
+ rssi1 = read_phy_reg(pi, 0x21a);
+ }
+
+ ctr = 0;
+ tmp_buf[ctr++] = ((s8) ((rssi0 & 0x3f) << 2)) >> 2;
+ tmp_buf[ctr++] = ((s8) (((rssi0 >> 8) & 0x3f) << 2)) >> 2;
+ tmp_buf[ctr++] = ((s8) ((rssi1 & 0x3f) << 2)) >> 2;
+ tmp_buf[ctr++] = ((s8) (((rssi1 >> 8) & 0x3f) << 2)) >> 2;
+
+ for (ctr = 0; ctr < 4; ctr++)
+ rssi_buf[ctr] += tmp_buf[ctr];
+
+ }
+
+ rssi_out_val = rssi_buf[3] & 0xff;
+ rssi_out_val |= (rssi_buf[2] & 0xff) << 8;
+ rssi_out_val |= (rssi_buf[1] & 0xff) << 16;
+ rssi_out_val |= (rssi_buf[0] & 0xff) << 24;
+
+ if (NREV_LT(pi->pubpi.phy_rev, 2))
+ write_phy_reg(pi, 0xca, gpiosel_orig);
+
+ write_phy_reg(pi, 0xa6, afectrlCore1_save);
+ write_phy_reg(pi, 0xa7, afectrlCore2_save);
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ write_phy_reg(pi, 0xf9, rfctrlMiscReg1_save);
+ write_phy_reg(pi, 0xfb, rfctrlMiscReg2_save);
+ write_phy_reg(pi, 0x8f, afectrlOverride1_save);
+ write_phy_reg(pi, 0xa5, afectrlOverride2_save);
+ write_phy_reg(pi, 0xe5, rfctrlOverrideAux0_save);
+ write_phy_reg(pi, 0xe6, rfctrlOverrideAux1_save);
+ } else {
+ write_phy_reg(pi, 0xa5, afectrlOverride1_save);
+ write_phy_reg(pi, 0x78, rfctrlcmd_save);
+ write_phy_reg(pi, 0xec, rfctrloverride_save);
+ write_phy_reg(pi, 0x7a, rfctrlrssiothers1_save);
+ write_phy_reg(pi, 0x7d, rfctrlrssiothers2_save);
+ }
+
+ return rssi_out_val;
+}
+
+s16 wlc_phy_tempsense_nphy(struct brcms_phy *pi)
+{
+ u16 core1_txrf_iqcal1_save, core1_txrf_iqcal2_save;
+ u16 core2_txrf_iqcal1_save, core2_txrf_iqcal2_save;
+ u16 pwrdet_rxtx_core1_save;
+ u16 pwrdet_rxtx_core2_save;
+ u16 afectrlCore1_save;
+ u16 afectrlCore2_save;
+ u16 afectrlOverride_save;
+ u16 afectrlOverride2_save;
+ u16 pd_pll_ts_save;
+ u16 gpioSel_save;
+ s32 radio_temp[4];
+ s32 radio_temp2[4];
+ u16 syn_tempprocsense_save;
+ s16 offset = 0;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ u16 auxADC_Vmid, auxADC_Av, auxADC_Vmid_save, auxADC_Av_save;
+ u16 auxADC_rssi_ctrlL_save, auxADC_rssi_ctrlH_save;
+ u16 auxADC_rssi_ctrlL, auxADC_rssi_ctrlH;
+ s32 auxADC_Vl;
+ u16 RfctrlOverride5_save, RfctrlOverride6_save;
+ u16 RfctrlMiscReg5_save, RfctrlMiscReg6_save;
+ u16 RSSIMultCoef0QPowerDet_save;
+ u16 tempsense_Rcal;
+
+ syn_tempprocsense_save =
+ read_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG);
+
+ afectrlCore1_save = read_phy_reg(pi, 0xa6);
+ afectrlCore2_save = read_phy_reg(pi, 0xa7);
+ afectrlOverride_save = read_phy_reg(pi, 0x8f);
+ afectrlOverride2_save = read_phy_reg(pi, 0xa5);
+ RSSIMultCoef0QPowerDet_save = read_phy_reg(pi, 0x1ae);
+ RfctrlOverride5_save = read_phy_reg(pi, 0x346);
+ RfctrlOverride6_save = read_phy_reg(pi, 0x347);
+ RfctrlMiscReg5_save = read_phy_reg(pi, 0x344);
+ RfctrlMiscReg6_save = read_phy_reg(pi, 0x345);
+
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0A, 16,
+ &auxADC_Vmid_save);
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0E, 16,
+ &auxADC_Av_save);
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x02, 16,
+ &auxADC_rssi_ctrlL_save);
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x03, 16,
+ &auxADC_rssi_ctrlH_save);
+
+ write_phy_reg(pi, 0x1ae, 0x0);
+
+ auxADC_rssi_ctrlL = 0x0;
+ auxADC_rssi_ctrlH = 0x20;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x02, 16,
+ &auxADC_rssi_ctrlL);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x03, 16,
+ &auxADC_rssi_ctrlH);
+
+ tempsense_Rcal = syn_tempprocsense_save & 0x1c;
+
+ write_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG,
+ tempsense_Rcal | 0x01);
+
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1),
+ 1, 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID2);
+ mod_phy_reg(pi, 0xa6, (0x1 << 7), 0);
+ mod_phy_reg(pi, 0xa7, (0x1 << 7), 0);
+ mod_phy_reg(pi, 0x8f, (0x1 << 7), (0x1 << 7));
+ mod_phy_reg(pi, 0xa5, (0x1 << 7), (0x1 << 7));
+
+ mod_phy_reg(pi, 0xa6, (0x1 << 2), (0x1 << 2));
+ mod_phy_reg(pi, 0xa7, (0x1 << 2), (0x1 << 2));
+ mod_phy_reg(pi, 0x8f, (0x1 << 2), (0x1 << 2));
+ mod_phy_reg(pi, 0xa5, (0x1 << 2), (0x1 << 2));
+ udelay(5);
+ mod_phy_reg(pi, 0xa6, (0x1 << 2), 0);
+ mod_phy_reg(pi, 0xa7, (0x1 << 2), 0);
+ mod_phy_reg(pi, 0xa6, (0x1 << 3), 0);
+ mod_phy_reg(pi, 0xa7, (0x1 << 3), 0);
+ mod_phy_reg(pi, 0x8f, (0x1 << 3), (0x1 << 3));
+ mod_phy_reg(pi, 0xa5, (0x1 << 3), (0x1 << 3));
+ mod_phy_reg(pi, 0xa6, (0x1 << 6), 0);
+ mod_phy_reg(pi, 0xa7, (0x1 << 6), 0);
+ mod_phy_reg(pi, 0x8f, (0x1 << 6), (0x1 << 6));
+ mod_phy_reg(pi, 0xa5, (0x1 << 6), (0x1 << 6));
+
+ auxADC_Vmid = 0xA3;
+ auxADC_Av = 0x0;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0A, 16,
+ &auxADC_Vmid);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0E, 16,
+ &auxADC_Av);
+
+ udelay(3);
+
+ wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp, 1);
+ write_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG,
+ tempsense_Rcal | 0x03);
+
+ udelay(5);
+ wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp2, 1);
+
+ auxADC_Av = 0x7;
+ if (radio_temp[1] + radio_temp2[1] < -30) {
+ auxADC_Vmid = 0x45;
+ auxADC_Vl = 263;
+ } else if (radio_temp[1] + radio_temp2[1] < -9) {
+ auxADC_Vmid = 0x200;
+ auxADC_Vl = 467;
+ } else if (radio_temp[1] + radio_temp2[1] < 11) {
+ auxADC_Vmid = 0x266;
+ auxADC_Vl = 634;
+ } else {
+ auxADC_Vmid = 0x2D5;
+ auxADC_Vl = 816;
+ }
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0A, 16,
+ &auxADC_Vmid);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0E, 16,
+ &auxADC_Av);
+
+ udelay(3);
+
+ wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp2, 1);
+ write_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG,
+ tempsense_Rcal | 0x01);
+
+ udelay(5);
+ wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp, 1);
+
+ write_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG,
+ syn_tempprocsense_save);
+
+ write_phy_reg(pi, 0xa6, afectrlCore1_save);
+ write_phy_reg(pi, 0xa7, afectrlCore2_save);
+ write_phy_reg(pi, 0x8f, afectrlOverride_save);
+ write_phy_reg(pi, 0xa5, afectrlOverride2_save);
+ write_phy_reg(pi, 0x1ae, RSSIMultCoef0QPowerDet_save);
+ write_phy_reg(pi, 0x346, RfctrlOverride5_save);
+ write_phy_reg(pi, 0x347, RfctrlOverride6_save);
+ write_phy_reg(pi, 0x344, RfctrlMiscReg5_save);
+ write_phy_reg(pi, 0x345, RfctrlMiscReg5_save);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0A, 16,
+ &auxADC_Vmid_save);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0E, 16,
+ &auxADC_Av_save);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x02, 16,
+ &auxADC_rssi_ctrlL_save);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x03, 16,
+ &auxADC_rssi_ctrlH_save);
+
+ radio_temp[0] = (179 * (radio_temp[1] + radio_temp2[1])
+ + 82 * (auxADC_Vl) - 28861 +
+ 128) / 256;
+
+ offset = (s16) pi->phy_tempsense_offset;
+
+ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ syn_tempprocsense_save =
+ read_radio_reg(pi, RADIO_2056_SYN_TEMPPROCSENSE);
+
+ afectrlCore1_save = read_phy_reg(pi, 0xa6);
+ afectrlCore2_save = read_phy_reg(pi, 0xa7);
+ afectrlOverride_save = read_phy_reg(pi, 0x8f);
+ afectrlOverride2_save = read_phy_reg(pi, 0xa5);
+ gpioSel_save = read_phy_reg(pi, 0xca);
+
+ write_radio_reg(pi, RADIO_2056_SYN_TEMPPROCSENSE, 0x01);
+
+ wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp, 1);
+ if (NREV_LT(pi->pubpi.phy_rev, 7))
+ write_radio_reg(pi, RADIO_2056_SYN_TEMPPROCSENSE, 0x05);
+
+ wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp2, 1);
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ write_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG, 0x01);
+ else
+ write_radio_reg(pi, RADIO_2056_SYN_TEMPPROCSENSE, 0x01);
+
+ radio_temp[0] =
+ (126 * (radio_temp[1] + radio_temp2[1]) + 3987) / 64;
+
+ write_radio_reg(pi, RADIO_2056_SYN_TEMPPROCSENSE,
+ syn_tempprocsense_save);
+
+ write_phy_reg(pi, 0xca, gpioSel_save);
+ write_phy_reg(pi, 0xa6, afectrlCore1_save);
+ write_phy_reg(pi, 0xa7, afectrlCore2_save);
+ write_phy_reg(pi, 0x8f, afectrlOverride_save);
+ write_phy_reg(pi, 0xa5, afectrlOverride2_save);
+
+ offset = (s16) pi->phy_tempsense_offset;
+ } else {
+
+ pwrdet_rxtx_core1_save =
+ read_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1);
+ pwrdet_rxtx_core2_save =
+ read_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2);
+ core1_txrf_iqcal1_save =
+ read_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1);
+ core1_txrf_iqcal2_save =
+ read_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2);
+ core2_txrf_iqcal1_save =
+ read_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1);
+ core2_txrf_iqcal2_save =
+ read_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2);
+ pd_pll_ts_save = read_radio_reg(pi, RADIO_2055_PD_PLL_TS);
+
+ afectrlCore1_save = read_phy_reg(pi, 0xa6);
+ afectrlCore2_save = read_phy_reg(pi, 0xa7);
+ afectrlOverride_save = read_phy_reg(pi, 0xa5);
+ gpioSel_save = read_phy_reg(pi, 0xca);
+
+ write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1, 0x01);
+ write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1, 0x01);
+ write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2, 0x08);
+ write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2, 0x08);
+ write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1, 0x04);
+ write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2, 0x04);
+ write_radio_reg(pi, RADIO_2055_PD_PLL_TS, 0x00);
+
+ wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp, 1);
+ xor_radio_reg(pi, RADIO_2055_CAL_TS, 0x80);
+
+ wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp, 1);
+ xor_radio_reg(pi, RADIO_2055_CAL_TS, 0x80);
+
+ wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp2, 1);
+ xor_radio_reg(pi, RADIO_2055_CAL_TS, 0x80);
+
+ radio_temp[0] = (radio_temp[0] + radio_temp2[0]);
+ radio_temp[1] = (radio_temp[1] + radio_temp2[1]);
+ radio_temp[2] = (radio_temp[2] + radio_temp2[2]);
+ radio_temp[3] = (radio_temp[3] + radio_temp2[3]);
+
+ radio_temp[0] =
+ (radio_temp[0] + radio_temp[1] + radio_temp[2] +
+ radio_temp[3]);
+
+ radio_temp[0] =
+ (radio_temp[0] +
+ (8 * 32)) * (950 - 350) / 63 + (350 * 8);
+
+ radio_temp[0] = (radio_temp[0] - (8 * 420)) / 38;
+
+ write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1,
+ pwrdet_rxtx_core1_save);
+ write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2,
+ pwrdet_rxtx_core2_save);
+ write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1,
+ core1_txrf_iqcal1_save);
+ write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1,
+ core2_txrf_iqcal1_save);
+ write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2,
+ core1_txrf_iqcal2_save);
+ write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2,
+ core2_txrf_iqcal2_save);
+ write_radio_reg(pi, RADIO_2055_PD_PLL_TS, pd_pll_ts_save);
+
+ write_phy_reg(pi, 0xca, gpioSel_save);
+ write_phy_reg(pi, 0xa6, afectrlCore1_save);
+ write_phy_reg(pi, 0xa7, afectrlCore2_save);
+ write_phy_reg(pi, 0xa5, afectrlOverride_save);
+ }
+
+ return (s16) radio_temp[0] + offset;
+}
+
+static void
+wlc_phy_set_rssi_2055_vcm(struct brcms_phy *pi, u8 rssi_type, u8 *vcm_buf)
+{
+ u8 core;
+
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+ if (rssi_type == NPHY_RSSI_SEL_NB) {
+ if (core == PHY_CORE_0) {
+ mod_radio_reg(pi,
+ RADIO_2055_CORE1_B0_NBRSSI_VCM,
+ RADIO_2055_NBRSSI_VCM_I_MASK,
+ vcm_buf[2 *
+ core] <<
+ RADIO_2055_NBRSSI_VCM_I_SHIFT);
+ mod_radio_reg(pi,
+ RADIO_2055_CORE1_RXBB_RSSI_CTRL5,
+ RADIO_2055_NBRSSI_VCM_Q_MASK,
+ vcm_buf[2 * core +
+ 1] <<
+ RADIO_2055_NBRSSI_VCM_Q_SHIFT);
+ } else {
+ mod_radio_reg(pi,
+ RADIO_2055_CORE2_B0_NBRSSI_VCM,
+ RADIO_2055_NBRSSI_VCM_I_MASK,
+ vcm_buf[2 *
+ core] <<
+ RADIO_2055_NBRSSI_VCM_I_SHIFT);
+ mod_radio_reg(pi,
+ RADIO_2055_CORE2_RXBB_RSSI_CTRL5,
+ RADIO_2055_NBRSSI_VCM_Q_MASK,
+ vcm_buf[2 * core +
+ 1] <<
+ RADIO_2055_NBRSSI_VCM_Q_SHIFT);
+ }
+ } else {
+ if (core == PHY_CORE_0)
+ mod_radio_reg(pi,
+ RADIO_2055_CORE1_RXBB_RSSI_CTRL5,
+ RADIO_2055_WBRSSI_VCM_IQ_MASK,
+ vcm_buf[2 *
+ core] <<
+ RADIO_2055_WBRSSI_VCM_IQ_SHIFT);
+ else
+ mod_radio_reg(pi,
+ RADIO_2055_CORE2_RXBB_RSSI_CTRL5,
+ RADIO_2055_WBRSSI_VCM_IQ_MASK,
+ vcm_buf[2 *
+ core] <<
+ RADIO_2055_WBRSSI_VCM_IQ_SHIFT);
+ }
+ }
+}
+
+static void wlc_phy_rssi_cal_nphy_rev3(struct brcms_phy *pi)
+{
+ u16 classif_state;
+ u16 clip_state[2];
+ u16 clip_off[] = { 0xffff, 0xffff };
+ s32 target_code;
+ u8 vcm, min_vcm;
+ u8 vcm_final = 0;
+ u8 result_idx;
+ s32 poll_results[8][4] = {
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0}
+ };
+ s32 poll_result_core[4] = { 0, 0, 0, 0 };
+ s32 min_d = NPHY_RSSICAL_MAXD, curr_d;
+ s32 fine_digital_offset[4];
+ s32 poll_results_min[4] = { 0, 0, 0, 0 };
+ s32 min_poll;
+ u8 vcm_level_max;
+ u8 core;
+ u8 wb_cnt;
+ u8 rssi_type;
+ u16 NPHY_Rfctrlintc1_save, NPHY_Rfctrlintc2_save;
+ u16 NPHY_AfectrlOverride1_save, NPHY_AfectrlOverride2_save;
+ u16 NPHY_AfectrlCore1_save, NPHY_AfectrlCore2_save;
+ u16 NPHY_RfctrlOverride0_save, NPHY_RfctrlOverride1_save;
+ u16 NPHY_RfctrlOverrideAux0_save, NPHY_RfctrlOverrideAux1_save;
+ u16 NPHY_RfctrlCmd_save;
+ u16 NPHY_RfctrlMiscReg1_save, NPHY_RfctrlMiscReg2_save;
+ u16 NPHY_RfctrlRSSIOTHERS1_save, NPHY_RfctrlRSSIOTHERS2_save;
+ u8 rxcore_state;
+ u16 NPHY_REV7_RfctrlOverride3_save, NPHY_REV7_RfctrlOverride4_save;
+ u16 NPHY_REV7_RfctrlOverride5_save, NPHY_REV7_RfctrlOverride6_save;
+ u16 NPHY_REV7_RfctrlMiscReg3_save, NPHY_REV7_RfctrlMiscReg4_save;
+ u16 NPHY_REV7_RfctrlMiscReg5_save, NPHY_REV7_RfctrlMiscReg6_save;
+
+ NPHY_REV7_RfctrlOverride3_save =
+ NPHY_REV7_RfctrlOverride4_save =
+ NPHY_REV7_RfctrlOverride5_save =
+ NPHY_REV7_RfctrlOverride6_save =
+ NPHY_REV7_RfctrlMiscReg3_save =
+ NPHY_REV7_RfctrlMiscReg4_save =
+ NPHY_REV7_RfctrlMiscReg5_save =
+ NPHY_REV7_RfctrlMiscReg6_save = 0;
+
+ classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
+ wlc_phy_classifier_nphy(pi, (0x7 << 0), 4);
+ wlc_phy_clip_det_nphy(pi, 0, clip_state);
+ wlc_phy_clip_det_nphy(pi, 1, clip_off);
+
+ NPHY_Rfctrlintc1_save = read_phy_reg(pi, 0x91);
+ NPHY_Rfctrlintc2_save = read_phy_reg(pi, 0x92);
+ NPHY_AfectrlOverride1_save = read_phy_reg(pi, 0x8f);
+ NPHY_AfectrlOverride2_save = read_phy_reg(pi, 0xa5);
+ NPHY_AfectrlCore1_save = read_phy_reg(pi, 0xa6);
+ NPHY_AfectrlCore2_save = read_phy_reg(pi, 0xa7);
+ NPHY_RfctrlOverride0_save = read_phy_reg(pi, 0xe7);
+ NPHY_RfctrlOverride1_save = read_phy_reg(pi, 0xec);
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ NPHY_REV7_RfctrlOverride3_save = read_phy_reg(pi, 0x342);
+ NPHY_REV7_RfctrlOverride4_save = read_phy_reg(pi, 0x343);
+ NPHY_REV7_RfctrlOverride5_save = read_phy_reg(pi, 0x346);
+ NPHY_REV7_RfctrlOverride6_save = read_phy_reg(pi, 0x347);
+ }
+ NPHY_RfctrlOverrideAux0_save = read_phy_reg(pi, 0xe5);
+ NPHY_RfctrlOverrideAux1_save = read_phy_reg(pi, 0xe6);
+ NPHY_RfctrlCmd_save = read_phy_reg(pi, 0x78);
+ NPHY_RfctrlMiscReg1_save = read_phy_reg(pi, 0xf9);
+ NPHY_RfctrlMiscReg2_save = read_phy_reg(pi, 0xfb);
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ NPHY_REV7_RfctrlMiscReg3_save = read_phy_reg(pi, 0x340);
+ NPHY_REV7_RfctrlMiscReg4_save = read_phy_reg(pi, 0x341);
+ NPHY_REV7_RfctrlMiscReg5_save = read_phy_reg(pi, 0x344);
+ NPHY_REV7_RfctrlMiscReg6_save = read_phy_reg(pi, 0x345);
+ }
+ NPHY_RfctrlRSSIOTHERS1_save = read_phy_reg(pi, 0x7a);
+ NPHY_RfctrlRSSIOTHERS2_save = read_phy_reg(pi, 0x7d);
+
+ wlc_phy_rfctrlintc_override_nphy(pi, NPHY_RfctrlIntc_override_OFF, 0,
+ RADIO_MIMO_CORESEL_ALLRXTX);
+ wlc_phy_rfctrlintc_override_nphy(pi, NPHY_RfctrlIntc_override_TRSW, 1,
+ RADIO_MIMO_CORESEL_ALLRXTX);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ wlc_phy_rfctrl_override_1tomany_nphy(
+ pi,
+ NPHY_REV7_RfctrlOverride_cmd_rxrf_pu,
+ 0, 0, 0);
+ else
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 0), 0, 0, 0);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ wlc_phy_rfctrl_override_1tomany_nphy(
+ pi,
+ NPHY_REV7_RfctrlOverride_cmd_rx_pu,
+ 1, 0, 0);
+ else
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 1), 1, 0, 0);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 7),
+ 1, 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 6), 1, 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ } else {
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 7), 1, 0, 0);
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 6), 1, 0, 0);
+ }
+
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 5),
+ 0, 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 4), 1, 0,
+ 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ } else {
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 5), 0, 0, 0);
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 4), 1, 0, 0);
+ }
+
+ } else {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 4),
+ 0, 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 5), 1, 0,
+ 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ } else {
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 4), 0, 0, 0);
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 5), 1, 0, 0);
+ }
+ }
+
+ rxcore_state = wlc_phy_rxcore_getstate_nphy(
+ (struct brcms_phy_pub *) pi);
+
+ vcm_level_max = 8;
+
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+
+ if ((rxcore_state & (1 << core)) == 0)
+ continue;
+
+ wlc_phy_scale_offset_rssi_nphy(pi, 0x0, 0x0,
+ core ==
+ PHY_CORE_0 ?
+ RADIO_MIMO_CORESEL_CORE1 :
+ RADIO_MIMO_CORESEL_CORE2,
+ NPHY_RAIL_I, NPHY_RSSI_SEL_NB);
+ wlc_phy_scale_offset_rssi_nphy(pi, 0x0, 0x0,
+ core ==
+ PHY_CORE_0 ?
+ RADIO_MIMO_CORESEL_CORE1 :
+ RADIO_MIMO_CORESEL_CORE2,
+ NPHY_RAIL_Q, NPHY_RSSI_SEL_NB);
+
+ for (vcm = 0; vcm < vcm_level_max; vcm++) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ mod_radio_reg(pi, (core == PHY_CORE_0) ?
+ RADIO_2057_NB_MASTER_CORE0 :
+ RADIO_2057_NB_MASTER_CORE1,
+ RADIO_2057_VCM_MASK, vcm);
+ else
+ mod_radio_reg(pi, RADIO_2056_RX_RSSI_MISC |
+ ((core ==
+ PHY_CORE_0) ? RADIO_2056_RX0 :
+ RADIO_2056_RX1),
+ RADIO_2056_VCM_MASK,
+ vcm << RADIO_2056_RSSI_VCM_SHIFT);
+
+ wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_NB,
+ &poll_results[vcm][0],
+ NPHY_RSSICAL_NPOLL);
+ }
+
+ for (result_idx = 0; result_idx < 4; result_idx++) {
+ if ((core == result_idx / 2) &&
+ (result_idx % 2 == 0)) {
+
+ min_d = NPHY_RSSICAL_MAXD;
+ min_vcm = 0;
+ min_poll =
+ NPHY_RSSICAL_MAXREAD *
+ NPHY_RSSICAL_NPOLL + 1;
+ for (vcm = 0; vcm < vcm_level_max; vcm++) {
+ curr_d =
+ poll_results[vcm][result_idx] *
+ poll_results[vcm][result_idx] +
+ poll_results[vcm][result_idx +
+ 1] *
+ poll_results[vcm][result_idx +
+ 1];
+ if (curr_d < min_d) {
+ min_d = curr_d;
+ min_vcm = vcm;
+ }
+ if (poll_results[vcm][result_idx] <
+ min_poll)
+ min_poll =
+ poll_results[vcm]
+ [result_idx];
+ }
+ vcm_final = min_vcm;
+ poll_results_min[result_idx] = min_poll;
+ }
+ }
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ mod_radio_reg(pi, (core == PHY_CORE_0) ?
+ RADIO_2057_NB_MASTER_CORE0 :
+ RADIO_2057_NB_MASTER_CORE1,
+ RADIO_2057_VCM_MASK, vcm_final);
+ else
+ mod_radio_reg(pi, RADIO_2056_RX_RSSI_MISC |
+ ((core ==
+ PHY_CORE_0) ? RADIO_2056_RX0 :
+ RADIO_2056_RX1), RADIO_2056_VCM_MASK,
+ vcm_final << RADIO_2056_RSSI_VCM_SHIFT);
+
+ for (result_idx = 0; result_idx < 4; result_idx++) {
+ if (core == result_idx / 2) {
+ fine_digital_offset[result_idx] =
+ (NPHY_RSSICAL_NB_TARGET *
+ NPHY_RSSICAL_NPOLL) -
+ poll_results[vcm_final][result_idx];
+ if (fine_digital_offset[result_idx] < 0) {
+ fine_digital_offset[result_idx] =
+ abs(fine_digital_offset
+ [result_idx]);
+ fine_digital_offset[result_idx] +=
+ (NPHY_RSSICAL_NPOLL / 2);
+ fine_digital_offset[result_idx] /=
+ NPHY_RSSICAL_NPOLL;
+ fine_digital_offset[result_idx] =
+ -fine_digital_offset[
+ result_idx];
+ } else {
+ fine_digital_offset[result_idx] +=
+ (NPHY_RSSICAL_NPOLL / 2);
+ fine_digital_offset[result_idx] /=
+ NPHY_RSSICAL_NPOLL;
+ }
+
+ if (poll_results_min[result_idx] ==
+ NPHY_RSSICAL_MAXREAD * NPHY_RSSICAL_NPOLL)
+ fine_digital_offset[result_idx] =
+ (NPHY_RSSICAL_NB_TARGET -
+ NPHY_RSSICAL_MAXREAD - 1);
+
+ wlc_phy_scale_offset_rssi_nphy(
+ pi, 0x0,
+ (s8)
+ fine_digital_offset
+ [result_idx],
+ (result_idx / 2 == 0) ?
+ RADIO_MIMO_CORESEL_CORE1 :
+ RADIO_MIMO_CORESEL_CORE2,
+ (result_idx % 2 == 0) ?
+ NPHY_RAIL_I : NPHY_RAIL_Q,
+ NPHY_RSSI_SEL_NB);
+ }
+ }
+
+ }
+
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+
+ if ((rxcore_state & (1 << core)) == 0)
+ continue;
+
+ for (wb_cnt = 0; wb_cnt < 2; wb_cnt++) {
+ if (wb_cnt == 0) {
+ rssi_type = NPHY_RSSI_SEL_W1;
+ target_code = NPHY_RSSICAL_W1_TARGET_REV3;
+ } else {
+ rssi_type = NPHY_RSSI_SEL_W2;
+ target_code = NPHY_RSSICAL_W2_TARGET_REV3;
+ }
+
+ wlc_phy_scale_offset_rssi_nphy(pi, 0x0, 0x0,
+ core ==
+ PHY_CORE_0 ?
+ RADIO_MIMO_CORESEL_CORE1
+ :
+ RADIO_MIMO_CORESEL_CORE2,
+ NPHY_RAIL_I, rssi_type);
+ wlc_phy_scale_offset_rssi_nphy(pi, 0x0, 0x0,
+ core ==
+ PHY_CORE_0 ?
+ RADIO_MIMO_CORESEL_CORE1
+ :
+ RADIO_MIMO_CORESEL_CORE2,
+ NPHY_RAIL_Q, rssi_type);
+
+ wlc_phy_poll_rssi_nphy(pi, rssi_type, poll_result_core,
+ NPHY_RSSICAL_NPOLL);
+
+ for (result_idx = 0; result_idx < 4; result_idx++) {
+ if (core == result_idx / 2) {
+ fine_digital_offset[result_idx] =
+ (target_code *
+ NPHY_RSSICAL_NPOLL) -
+ poll_result_core[result_idx];
+ if (fine_digital_offset[result_idx] <
+ 0) {
+ fine_digital_offset[result_idx]
+ = abs(
+ fine_digital_offset
+ [result_idx]);
+ fine_digital_offset[result_idx]
+ += (NPHY_RSSICAL_NPOLL
+ / 2);
+ fine_digital_offset[result_idx]
+ /= NPHY_RSSICAL_NPOLL;
+ fine_digital_offset[result_idx]
+ = -fine_digital_offset
+ [result_idx];
+ } else {
+ fine_digital_offset[result_idx]
+ += (NPHY_RSSICAL_NPOLL
+ / 2);
+ fine_digital_offset[result_idx]
+ /= NPHY_RSSICAL_NPOLL;
+ }
+
+ wlc_phy_scale_offset_rssi_nphy(
+ pi, 0x0,
+ (s8)
+ fine_digital_offset
+ [core *
+ 2],
+ (core == PHY_CORE_0) ?
+ RADIO_MIMO_CORESEL_CORE1 :
+ RADIO_MIMO_CORESEL_CORE2,
+ (result_idx % 2 == 0) ?
+ NPHY_RAIL_I :
+ NPHY_RAIL_Q,
+ rssi_type);
+ }
+ }
+
+ }
+ }
+
+ write_phy_reg(pi, 0x91, NPHY_Rfctrlintc1_save);
+ write_phy_reg(pi, 0x92, NPHY_Rfctrlintc2_save);
+
+ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX);
+
+ mod_phy_reg(pi, 0xe7, (0x1 << 0), 1 << 0);
+ mod_phy_reg(pi, 0x78, (0x1 << 0), 1 << 0);
+ mod_phy_reg(pi, 0xe7, (0x1 << 0), 0);
+
+ mod_phy_reg(pi, 0xec, (0x1 << 0), 1 << 0);
+ mod_phy_reg(pi, 0x78, (0x1 << 1), 1 << 1);
+ mod_phy_reg(pi, 0xec, (0x1 << 0), 0);
+
+ write_phy_reg(pi, 0x8f, NPHY_AfectrlOverride1_save);
+ write_phy_reg(pi, 0xa5, NPHY_AfectrlOverride2_save);
+ write_phy_reg(pi, 0xa6, NPHY_AfectrlCore1_save);
+ write_phy_reg(pi, 0xa7, NPHY_AfectrlCore2_save);
+ write_phy_reg(pi, 0xe7, NPHY_RfctrlOverride0_save);
+ write_phy_reg(pi, 0xec, NPHY_RfctrlOverride1_save);
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ write_phy_reg(pi, 0x342, NPHY_REV7_RfctrlOverride3_save);
+ write_phy_reg(pi, 0x343, NPHY_REV7_RfctrlOverride4_save);
+ write_phy_reg(pi, 0x346, NPHY_REV7_RfctrlOverride5_save);
+ write_phy_reg(pi, 0x347, NPHY_REV7_RfctrlOverride6_save);
+ }
+ write_phy_reg(pi, 0xe5, NPHY_RfctrlOverrideAux0_save);
+ write_phy_reg(pi, 0xe6, NPHY_RfctrlOverrideAux1_save);
+ write_phy_reg(pi, 0x78, NPHY_RfctrlCmd_save);
+ write_phy_reg(pi, 0xf9, NPHY_RfctrlMiscReg1_save);
+ write_phy_reg(pi, 0xfb, NPHY_RfctrlMiscReg2_save);
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ write_phy_reg(pi, 0x340, NPHY_REV7_RfctrlMiscReg3_save);
+ write_phy_reg(pi, 0x341, NPHY_REV7_RfctrlMiscReg4_save);
+ write_phy_reg(pi, 0x344, NPHY_REV7_RfctrlMiscReg5_save);
+ write_phy_reg(pi, 0x345, NPHY_REV7_RfctrlMiscReg6_save);
+ }
+ write_phy_reg(pi, 0x7a, NPHY_RfctrlRSSIOTHERS1_save);
+ write_phy_reg(pi, 0x7d, NPHY_RfctrlRSSIOTHERS2_save);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ pi->rssical_cache.rssical_radio_regs_2G[0] =
+ read_radio_reg(pi, RADIO_2057_NB_MASTER_CORE0);
+ pi->rssical_cache.rssical_radio_regs_2G[1] =
+ read_radio_reg(pi, RADIO_2057_NB_MASTER_CORE1);
+ } else {
+ pi->rssical_cache.rssical_radio_regs_2G[0] =
+ read_radio_reg(pi,
+ RADIO_2056_RX_RSSI_MISC |
+ RADIO_2056_RX0);
+ pi->rssical_cache.rssical_radio_regs_2G[1] =
+ read_radio_reg(pi,
+ RADIO_2056_RX_RSSI_MISC |
+ RADIO_2056_RX1);
+ }
+
+ pi->rssical_cache.rssical_phyregs_2G[0] =
+ read_phy_reg(pi, 0x1a6);
+ pi->rssical_cache.rssical_phyregs_2G[1] =
+ read_phy_reg(pi, 0x1ac);
+ pi->rssical_cache.rssical_phyregs_2G[2] =
+ read_phy_reg(pi, 0x1b2);
+ pi->rssical_cache.rssical_phyregs_2G[3] =
+ read_phy_reg(pi, 0x1b8);
+ pi->rssical_cache.rssical_phyregs_2G[4] =
+ read_phy_reg(pi, 0x1a4);
+ pi->rssical_cache.rssical_phyregs_2G[5] =
+ read_phy_reg(pi, 0x1aa);
+ pi->rssical_cache.rssical_phyregs_2G[6] =
+ read_phy_reg(pi, 0x1b0);
+ pi->rssical_cache.rssical_phyregs_2G[7] =
+ read_phy_reg(pi, 0x1b6);
+ pi->rssical_cache.rssical_phyregs_2G[8] =
+ read_phy_reg(pi, 0x1a5);
+ pi->rssical_cache.rssical_phyregs_2G[9] =
+ read_phy_reg(pi, 0x1ab);
+ pi->rssical_cache.rssical_phyregs_2G[10] =
+ read_phy_reg(pi, 0x1b1);
+ pi->rssical_cache.rssical_phyregs_2G[11] =
+ read_phy_reg(pi, 0x1b7);
+
+ pi->nphy_rssical_chanspec_2G = pi->radio_chanspec;
+ } else {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ pi->rssical_cache.rssical_radio_regs_5G[0] =
+ read_radio_reg(pi, RADIO_2057_NB_MASTER_CORE0);
+ pi->rssical_cache.rssical_radio_regs_5G[1] =
+ read_radio_reg(pi, RADIO_2057_NB_MASTER_CORE1);
+ } else {
+ pi->rssical_cache.rssical_radio_regs_5G[0] =
+ read_radio_reg(pi,
+ RADIO_2056_RX_RSSI_MISC |
+ RADIO_2056_RX0);
+ pi->rssical_cache.rssical_radio_regs_5G[1] =
+ read_radio_reg(pi,
+ RADIO_2056_RX_RSSI_MISC |
+ RADIO_2056_RX1);
+ }
+
+ pi->rssical_cache.rssical_phyregs_5G[0] =
+ read_phy_reg(pi, 0x1a6);
+ pi->rssical_cache.rssical_phyregs_5G[1] =
+ read_phy_reg(pi, 0x1ac);
+ pi->rssical_cache.rssical_phyregs_5G[2] =
+ read_phy_reg(pi, 0x1b2);
+ pi->rssical_cache.rssical_phyregs_5G[3] =
+ read_phy_reg(pi, 0x1b8);
+ pi->rssical_cache.rssical_phyregs_5G[4] =
+ read_phy_reg(pi, 0x1a4);
+ pi->rssical_cache.rssical_phyregs_5G[5] =
+ read_phy_reg(pi, 0x1aa);
+ pi->rssical_cache.rssical_phyregs_5G[6] =
+ read_phy_reg(pi, 0x1b0);
+ pi->rssical_cache.rssical_phyregs_5G[7] =
+ read_phy_reg(pi, 0x1b6);
+ pi->rssical_cache.rssical_phyregs_5G[8] =
+ read_phy_reg(pi, 0x1a5);
+ pi->rssical_cache.rssical_phyregs_5G[9] =
+ read_phy_reg(pi, 0x1ab);
+ pi->rssical_cache.rssical_phyregs_5G[10] =
+ read_phy_reg(pi, 0x1b1);
+ pi->rssical_cache.rssical_phyregs_5G[11] =
+ read_phy_reg(pi, 0x1b7);
+
+ pi->nphy_rssical_chanspec_5G = pi->radio_chanspec;
+ }
+
+ wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);
+ wlc_phy_clip_det_nphy(pi, 1, clip_state);
+}
+
+static void wlc_phy_rssi_cal_nphy_rev2(struct brcms_phy *pi, u8 rssi_type)
+{
+ s32 target_code;
+ u16 classif_state;
+ u16 clip_state[2];
+ u16 rssi_ctrl_state[2], pd_state[2];
+ u16 rfctrlintc_state[2], rfpdcorerxtx_state[2];
+ u16 rfctrlintc_override_val;
+ u16 clip_off[] = { 0xffff, 0xffff };
+ u16 rf_pd_val, pd_mask, rssi_ctrl_mask;
+ u8 vcm, min_vcm, vcm_tmp[4];
+ u8 vcm_final[4] = { 0, 0, 0, 0 };
+ u8 result_idx, ctr;
+ s32 poll_results[4][4] = {
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0}
+ };
+ s32 poll_miniq[4][2] = {
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0}
+ };
+ s32 min_d, curr_d;
+ s32 fine_digital_offset[4];
+ s32 poll_results_min[4] = { 0, 0, 0, 0 };
+ s32 min_poll;
+
+ switch (rssi_type) {
+ case NPHY_RSSI_SEL_NB:
+ target_code = NPHY_RSSICAL_NB_TARGET;
+ break;
+ case NPHY_RSSI_SEL_W1:
+ target_code = NPHY_RSSICAL_W1_TARGET;
+ break;
+ case NPHY_RSSI_SEL_W2:
+ target_code = NPHY_RSSICAL_W2_TARGET;
+ break;
+ default:
+ return;
+ break;
+ }
+
+ classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
+ wlc_phy_classifier_nphy(pi, (0x7 << 0), 4);
+ wlc_phy_clip_det_nphy(pi, 0, clip_state);
+ wlc_phy_clip_det_nphy(pi, 1, clip_off);
+
+ rf_pd_val = (rssi_type == NPHY_RSSI_SEL_NB) ? 0x6 : 0x4;
+ rfctrlintc_override_val =
+ CHSPEC_IS5G(pi->radio_chanspec) ? 0x140 : 0x110;
+
+ rfctrlintc_state[0] = read_phy_reg(pi, 0x91);
+ rfpdcorerxtx_state[0] = read_radio_reg(pi, RADIO_2055_PD_CORE1_RXTX);
+ write_phy_reg(pi, 0x91, rfctrlintc_override_val);
+ write_radio_reg(pi, RADIO_2055_PD_CORE1_RXTX, rf_pd_val);
+
+ rfctrlintc_state[1] = read_phy_reg(pi, 0x92);
+ rfpdcorerxtx_state[1] = read_radio_reg(pi, RADIO_2055_PD_CORE2_RXTX);
+ write_phy_reg(pi, 0x92, rfctrlintc_override_val);
+ write_radio_reg(pi, RADIO_2055_PD_CORE2_RXTX, rf_pd_val);
+
+ pd_mask = RADIO_2055_NBRSSI_PD | RADIO_2055_WBRSSI_G1_PD |
+ RADIO_2055_WBRSSI_G2_PD;
+ pd_state[0] =
+ read_radio_reg(pi, RADIO_2055_PD_CORE1_RSSI_MISC) & pd_mask;
+ pd_state[1] =
+ read_radio_reg(pi, RADIO_2055_PD_CORE2_RSSI_MISC) & pd_mask;
+ mod_radio_reg(pi, RADIO_2055_PD_CORE1_RSSI_MISC, pd_mask, 0);
+ mod_radio_reg(pi, RADIO_2055_PD_CORE2_RSSI_MISC, pd_mask, 0);
+ rssi_ctrl_mask = RADIO_2055_NBRSSI_SEL | RADIO_2055_WBRSSI_G1_SEL |
+ RADIO_2055_WBRSSI_G2_SEL;
+ rssi_ctrl_state[0] =
+ read_radio_reg(pi, RADIO_2055_SP_RSSI_CORE1) & rssi_ctrl_mask;
+ rssi_ctrl_state[1] =
+ read_radio_reg(pi, RADIO_2055_SP_RSSI_CORE2) & rssi_ctrl_mask;
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_ALLRX, rssi_type);
+
+ wlc_phy_scale_offset_rssi_nphy(pi, 0x0, 0x0, RADIO_MIMO_CORESEL_ALLRX,
+ NPHY_RAIL_I, rssi_type);
+ wlc_phy_scale_offset_rssi_nphy(pi, 0x0, 0x0, RADIO_MIMO_CORESEL_ALLRX,
+ NPHY_RAIL_Q, rssi_type);
+
+ for (vcm = 0; vcm < 4; vcm++) {
+
+ vcm_tmp[0] = vcm_tmp[1] = vcm_tmp[2] = vcm_tmp[3] = vcm;
+ if (rssi_type != NPHY_RSSI_SEL_W2)
+ wlc_phy_set_rssi_2055_vcm(pi, rssi_type, vcm_tmp);
+
+ wlc_phy_poll_rssi_nphy(pi, rssi_type, &poll_results[vcm][0],
+ NPHY_RSSICAL_NPOLL);
+
+ if ((rssi_type == NPHY_RSSI_SEL_W1)
+ || (rssi_type == NPHY_RSSI_SEL_W2)) {
+ for (ctr = 0; ctr < 2; ctr++)
+ poll_miniq[vcm][ctr] =
+ min(poll_results[vcm][ctr * 2 + 0],
+ poll_results[vcm][ctr * 2 + 1]);
+ }
+ }
+
+ for (result_idx = 0; result_idx < 4; result_idx++) {
+ min_d = NPHY_RSSICAL_MAXD;
+ min_vcm = 0;
+ min_poll = NPHY_RSSICAL_MAXREAD * NPHY_RSSICAL_NPOLL + 1;
+ for (vcm = 0; vcm < 4; vcm++) {
+ curr_d = abs(((rssi_type == NPHY_RSSI_SEL_NB) ?
+ poll_results[vcm][result_idx] :
+ poll_miniq[vcm][result_idx / 2]) -
+ (target_code * NPHY_RSSICAL_NPOLL));
+ if (curr_d < min_d) {
+ min_d = curr_d;
+ min_vcm = vcm;
+ }
+ if (poll_results[vcm][result_idx] < min_poll)
+ min_poll = poll_results[vcm][result_idx];
+ }
+ vcm_final[result_idx] = min_vcm;
+ poll_results_min[result_idx] = min_poll;
+ }
+
+ if (rssi_type != NPHY_RSSI_SEL_W2)
+ wlc_phy_set_rssi_2055_vcm(pi, rssi_type, vcm_final);
+
+ for (result_idx = 0; result_idx < 4; result_idx++) {
+ fine_digital_offset[result_idx] =
+ (target_code * NPHY_RSSICAL_NPOLL) -
+ poll_results[vcm_final[result_idx]][result_idx];
+ if (fine_digital_offset[result_idx] < 0) {
+ fine_digital_offset[result_idx] =
+ abs(fine_digital_offset[result_idx]);
+ fine_digital_offset[result_idx] +=
+ (NPHY_RSSICAL_NPOLL / 2);
+ fine_digital_offset[result_idx] /= NPHY_RSSICAL_NPOLL;
+ fine_digital_offset[result_idx] =
+ -fine_digital_offset[result_idx];
+ } else {
+ fine_digital_offset[result_idx] +=
+ (NPHY_RSSICAL_NPOLL / 2);
+ fine_digital_offset[result_idx] /= NPHY_RSSICAL_NPOLL;
+ }
+
+ if (poll_results_min[result_idx] ==
+ NPHY_RSSICAL_MAXREAD * NPHY_RSSICAL_NPOLL)
+ fine_digital_offset[result_idx] =
+ (target_code - NPHY_RSSICAL_MAXREAD - 1);
+
+ wlc_phy_scale_offset_rssi_nphy(pi, 0x0,
+ (s8)
+ fine_digital_offset[result_idx],
+ (result_idx / 2 ==
+ 0) ? RADIO_MIMO_CORESEL_CORE1 :
+ RADIO_MIMO_CORESEL_CORE2,
+ (result_idx % 2 ==
+ 0) ? NPHY_RAIL_I : NPHY_RAIL_Q,
+ rssi_type);
+ }
+
+ mod_radio_reg(pi, RADIO_2055_PD_CORE1_RSSI_MISC, pd_mask, pd_state[0]);
+ mod_radio_reg(pi, RADIO_2055_PD_CORE2_RSSI_MISC, pd_mask, pd_state[1]);
+ if (rssi_ctrl_state[0] == RADIO_2055_NBRSSI_SEL)
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE1,
+ NPHY_RSSI_SEL_NB);
+ else if (rssi_ctrl_state[0] == RADIO_2055_WBRSSI_G1_SEL)
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE1,
+ NPHY_RSSI_SEL_W1);
+ else if (rssi_ctrl_state[0] == RADIO_2055_WBRSSI_G2_SEL)
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE1,
+ NPHY_RSSI_SEL_W2);
+ else
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE1,
+ NPHY_RSSI_SEL_W2);
+ if (rssi_ctrl_state[1] == RADIO_2055_NBRSSI_SEL)
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE2,
+ NPHY_RSSI_SEL_NB);
+ else if (rssi_ctrl_state[1] == RADIO_2055_WBRSSI_G1_SEL)
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE2,
+ NPHY_RSSI_SEL_W1);
+ else if (rssi_ctrl_state[1] == RADIO_2055_WBRSSI_G2_SEL)
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE2,
+ NPHY_RSSI_SEL_W2);
+ else
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE2,
+ NPHY_RSSI_SEL_W2);
+
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_OFF, rssi_type);
+
+ write_phy_reg(pi, 0x91, rfctrlintc_state[0]);
+ write_radio_reg(pi, RADIO_2055_PD_CORE1_RXTX, rfpdcorerxtx_state[0]);
+ write_phy_reg(pi, 0x92, rfctrlintc_state[1]);
+ write_radio_reg(pi, RADIO_2055_PD_CORE2_RXTX, rfpdcorerxtx_state[1]);
+
+ wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);
+ wlc_phy_clip_det_nphy(pi, 1, clip_state);
+
+ wlc_phy_resetcca_nphy(pi);
+}
+
+void wlc_phy_rssi_cal_nphy(struct brcms_phy *pi)
+{
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ wlc_phy_rssi_cal_nphy_rev3(pi);
+ } else {
+ wlc_phy_rssi_cal_nphy_rev2(pi, NPHY_RSSI_SEL_NB);
+ wlc_phy_rssi_cal_nphy_rev2(pi, NPHY_RSSI_SEL_W1);
+ wlc_phy_rssi_cal_nphy_rev2(pi, NPHY_RSSI_SEL_W2);
+ }
+}
+
+int
+wlc_phy_rssi_compute_nphy(struct brcms_phy *pi, struct d11rxhdr *rxh)
+{
+ s16 rxpwr, rxpwr0, rxpwr1;
+ s16 phyRx0_l, phyRx2_l;
+
+ rxpwr = 0;
+ rxpwr0 = rxh->PhyRxStatus_1 & PRXS1_nphy_PWR0_MASK;
+ rxpwr1 = (rxh->PhyRxStatus_1 & PRXS1_nphy_PWR1_MASK) >> 8;
+
+ if (rxpwr0 > 127)
+ rxpwr0 -= 256;
+ if (rxpwr1 > 127)
+ rxpwr1 -= 256;
+
+ phyRx0_l = rxh->PhyRxStatus_0 & 0x00ff;
+ phyRx2_l = rxh->PhyRxStatus_2 & 0x00ff;
+ if (phyRx2_l > 127)
+ phyRx2_l -= 256;
+
+ if (((rxpwr0 == 16) || (rxpwr0 == 32))) {
+ rxpwr0 = rxpwr1;
+ rxpwr1 = phyRx2_l;
+ }
+
+ if (pi->sh->rssi_mode == RSSI_ANT_MERGE_MAX)
+ rxpwr = (rxpwr0 > rxpwr1) ? rxpwr0 : rxpwr1;
+ else if (pi->sh->rssi_mode == RSSI_ANT_MERGE_MIN)
+ rxpwr = (rxpwr0 < rxpwr1) ? rxpwr0 : rxpwr1;
+ else if (pi->sh->rssi_mode == RSSI_ANT_MERGE_AVG)
+ rxpwr = (rxpwr0 + rxpwr1) >> 1;
+
+ return rxpwr;
+}
+
+static void
+wlc_phy_loadsampletable_nphy(struct brcms_phy *pi, struct cordic_iq *tone_buf,
+ u16 num_samps)
+{
+ u16 t;
+ u32 *data_buf = NULL;
+
+ data_buf = kmalloc(sizeof(u32) * num_samps, GFP_ATOMIC);
+ if (data_buf == NULL)
+ return;
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ for (t = 0; t < num_samps; t++)
+ data_buf[t] = ((((unsigned int)tone_buf[t].i) & 0x3ff) << 10) |
+ (((unsigned int)tone_buf[t].q) & 0x3ff);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_SAMPLEPLAY, num_samps, 0, 32,
+ data_buf);
+
+ kfree(data_buf);
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+}
+
+static u16
+wlc_phy_gen_load_samples_nphy(struct brcms_phy *pi, u32 f_kHz, u16 max_val,
+ u8 dac_test_mode)
+{
+ u8 phy_bw, is_phybw40;
+ u16 num_samps, t, spur;
+ s32 theta = 0, rot = 0;
+ u32 tbl_len;
+ struct cordic_iq *tone_buf = NULL;
+
+ is_phybw40 = CHSPEC_IS40(pi->radio_chanspec);
+ phy_bw = (is_phybw40 == 1) ? 40 : 20;
+ tbl_len = (phy_bw << 3);
+
+ if (dac_test_mode == 1) {
+ spur = read_phy_reg(pi, 0x01);
+ spur = (spur >> 15) & 1;
+ phy_bw = (spur == 1) ? 82 : 80;
+ phy_bw = (is_phybw40 == 1) ? (phy_bw << 1) : phy_bw;
+
+ tbl_len = (phy_bw << 1);
+ }
+
+ tone_buf = kmalloc(sizeof(struct cordic_iq) * tbl_len, GFP_ATOMIC);
+ if (tone_buf == NULL)
+ return 0;
+
+ num_samps = (u16) tbl_len;
+ rot = ((f_kHz * 36) / phy_bw) / 100;
+ theta = 0;
+
+ for (t = 0; t < num_samps; t++) {
+
+ tone_buf[t] = cordic_calc_iq(theta);
+
+ theta += rot;
+
+ tone_buf[t].q = (s32) FLOAT(tone_buf[t].q * max_val);
+ tone_buf[t].i = (s32) FLOAT(tone_buf[t].i * max_val);
+ }
+
+ wlc_phy_loadsampletable_nphy(pi, tone_buf, num_samps);
+
+ kfree(tone_buf);
+
+ return num_samps;
+}
+
+static void
+wlc_phy_runsamples_nphy(struct brcms_phy *pi, u16 num_samps, u16 loops,
+ u16 wait, u8 iqmode, u8 dac_test_mode,
+ bool modify_bbmult)
+{
+ u16 bb_mult;
+ u8 phy_bw, sample_cmd;
+ u16 orig_RfseqCoreActv;
+ u16 lpf_bw_ctl_override3, lpf_bw_ctl_override4, lpf_bw_ctl_miscreg3,
+ lpf_bw_ctl_miscreg4;
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ phy_bw = 20;
+ if (CHSPEC_IS40(pi->radio_chanspec))
+ phy_bw = 40;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ lpf_bw_ctl_override3 = read_phy_reg(pi, 0x342) & (0x1 << 7);
+ lpf_bw_ctl_override4 = read_phy_reg(pi, 0x343) & (0x1 << 7);
+ if (lpf_bw_ctl_override3 | lpf_bw_ctl_override4) {
+ lpf_bw_ctl_miscreg3 = read_phy_reg(pi, 0x340) &
+ (0x7 << 8);
+ lpf_bw_ctl_miscreg4 = read_phy_reg(pi, 0x341) &
+ (0x7 << 8);
+ } else {
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi,
+ (0x1 << 7),
+ wlc_phy_read_lpf_bw_ctl_nphy
+ (pi,
+ 0), 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+
+ pi->nphy_sample_play_lpf_bw_ctl_ovr = true;
+
+ lpf_bw_ctl_miscreg3 = read_phy_reg(pi, 0x340) &
+ (0x7 << 8);
+ lpf_bw_ctl_miscreg4 = read_phy_reg(pi, 0x341) &
+ (0x7 << 8);
+ }
+ }
+
+ if ((pi->nphy_bb_mult_save & BB_MULT_VALID_MASK) == 0) {
+
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, 1, 87, 16,
+ &bb_mult);
+ pi->nphy_bb_mult_save =
+ BB_MULT_VALID_MASK | (bb_mult & BB_MULT_MASK);
+ }
+
+ if (modify_bbmult) {
+ bb_mult = (phy_bw == 20) ? 100 : 71;
+ bb_mult = (bb_mult << 8) + bb_mult;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 1, 87, 16,
+ &bb_mult);
+ }
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+
+ write_phy_reg(pi, 0xc6, num_samps - 1);
+
+ if (loops != 0xffff)
+ write_phy_reg(pi, 0xc4, loops - 1);
+ else
+ write_phy_reg(pi, 0xc4, loops);
+
+ write_phy_reg(pi, 0xc5, wait);
+
+ orig_RfseqCoreActv = read_phy_reg(pi, 0xa1);
+ or_phy_reg(pi, 0xa1, NPHY_RfseqMode_CoreActv_override);
+ if (iqmode) {
+
+ and_phy_reg(pi, 0xc2, 0x7FFF);
+
+ or_phy_reg(pi, 0xc2, 0x8000);
+ } else {
+
+ sample_cmd = (dac_test_mode == 1) ? 0x5 : 0x1;
+ write_phy_reg(pi, 0xc3, sample_cmd);
+ }
+
+ SPINWAIT(((read_phy_reg(pi, 0xa4) & 0x1) == 1), 1000);
+
+ write_phy_reg(pi, 0xa1, orig_RfseqCoreActv);
+}
+
+int
+wlc_phy_tx_tone_nphy(struct brcms_phy *pi, u32 f_kHz, u16 max_val,
+ u8 iqmode, u8 dac_test_mode, bool modify_bbmult)
+{
+ u16 num_samps;
+ u16 loops = 0xffff;
+ u16 wait = 0;
+
+ num_samps = wlc_phy_gen_load_samples_nphy(pi, f_kHz, max_val,
+ dac_test_mode);
+ if (num_samps == 0)
+ return -EBADE;
+
+ wlc_phy_runsamples_nphy(pi, num_samps, loops, wait, iqmode,
+ dac_test_mode, modify_bbmult);
+
+ return 0;
+}
+
+void wlc_phy_stopplayback_nphy(struct brcms_phy *pi)
+{
+ u16 playback_status;
+ u16 bb_mult;
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ playback_status = read_phy_reg(pi, 0xc7);
+ if (playback_status & 0x1)
+ or_phy_reg(pi, 0xc3, NPHY_sampleCmd_STOP);
+ else if (playback_status & 0x2)
+ and_phy_reg(pi, 0xc2,
+ (u16) ~NPHY_iqloCalCmdGctl_IQLO_CAL_EN);
+
+ and_phy_reg(pi, 0xc3, (u16) ~(0x1 << 2));
+
+ if ((pi->nphy_bb_mult_save & BB_MULT_VALID_MASK) != 0) {
+
+ bb_mult = pi->nphy_bb_mult_save & BB_MULT_MASK;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 1, 87, 16,
+ &bb_mult);
+
+ pi->nphy_bb_mult_save = 0;
+ }
+
+ if (NREV_IS(pi->pubpi.phy_rev, 7) || NREV_GE(pi->pubpi.phy_rev, 8)) {
+ if (pi->nphy_sample_play_lpf_bw_ctl_ovr) {
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi,
+ (0x1 << 7),
+ 0, 0, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ pi->nphy_sample_play_lpf_bw_ctl_ovr = false;
+ }
+ }
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+}
+
+static u32 *brcms_phy_get_tx_pwrctrl_tbl(struct brcms_phy *pi)
+{
+ u32 *tx_pwrctrl_tbl = NULL;
+ uint phyrev = pi->pubpi.phy_rev;
+
+ if (PHY_IPA(pi)) {
+ tx_pwrctrl_tbl =
+ wlc_phy_get_ipa_gaintbl_nphy(pi);
+ } else {
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ if (NREV_IS(phyrev, 3))
+ tx_pwrctrl_tbl = nphy_tpc_5GHz_txgain_rev3;
+ else if (NREV_IS(phyrev, 4))
+ tx_pwrctrl_tbl =
+ (pi->srom_fem5g.extpagain == 3) ?
+ nphy_tpc_5GHz_txgain_HiPwrEPA :
+ nphy_tpc_5GHz_txgain_rev4;
+ else
+ tx_pwrctrl_tbl = nphy_tpc_5GHz_txgain_rev5;
+ } else {
+ if (NREV_GE(phyrev, 7)) {
+ if (pi->pubpi.radiorev == 3)
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_epa_2057rev3;
+ else if (pi->pubpi.radiorev == 5)
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_epa_2057rev5;
+ } else {
+ if (NREV_GE(phyrev, 5) &&
+ (pi->srom_fem2g.extpagain == 3))
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_HiPwrEPA;
+ else
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_rev3;
+ }
+ }
+ }
+ return tx_pwrctrl_tbl;
+}
+
+struct nphy_txgains wlc_phy_get_tx_gain_nphy(struct brcms_phy *pi)
+{
+ u16 base_idx[2], curr_gain[2];
+ u8 core_no;
+ struct nphy_txgains target_gain;
+ u32 *tx_pwrctrl_tbl = NULL;
+
+ if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) {
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16,
+ curr_gain);
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+
+ for (core_no = 0; core_no < 2; core_no++) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ target_gain.ipa[core_no] =
+ curr_gain[core_no] & 0x0007;
+ target_gain.pad[core_no] =
+ ((curr_gain[core_no] & 0x00F8) >> 3);
+ target_gain.pga[core_no] =
+ ((curr_gain[core_no] & 0x0F00) >> 8);
+ target_gain.txgm[core_no] =
+ ((curr_gain[core_no] & 0x7000) >> 12);
+ target_gain.txlpf[core_no] =
+ ((curr_gain[core_no] & 0x8000) >> 15);
+ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ target_gain.ipa[core_no] =
+ curr_gain[core_no] & 0x000F;
+ target_gain.pad[core_no] =
+ ((curr_gain[core_no] & 0x00F0) >> 4);
+ target_gain.pga[core_no] =
+ ((curr_gain[core_no] & 0x0F00) >> 8);
+ target_gain.txgm[core_no] =
+ ((curr_gain[core_no] & 0x7000) >> 12);
+ } else {
+ target_gain.ipa[core_no] =
+ curr_gain[core_no] & 0x0003;
+ target_gain.pad[core_no] =
+ ((curr_gain[core_no] & 0x000C) >> 2);
+ target_gain.pga[core_no] =
+ ((curr_gain[core_no] & 0x0070) >> 4);
+ target_gain.txgm[core_no] =
+ ((curr_gain[core_no] & 0x0380) >> 7);
+ }
+ }
+ } else {
+ uint phyrev = pi->pubpi.phy_rev;
+
+ base_idx[0] = (read_phy_reg(pi, 0x1ed) >> 8) & 0x7f;
+ base_idx[1] = (read_phy_reg(pi, 0x1ee) >> 8) & 0x7f;
+ for (core_no = 0; core_no < 2; core_no++) {
+ if (NREV_GE(phyrev, 3)) {
+ tx_pwrctrl_tbl =
+ brcms_phy_get_tx_pwrctrl_tbl(pi);
+ if (NREV_GE(phyrev, 7)) {
+ target_gain.ipa[core_no] =
+ (tx_pwrctrl_tbl
+ [base_idx[core_no]]
+ >> 16) & 0x7;
+ target_gain.pad[core_no] =
+ (tx_pwrctrl_tbl
+ [base_idx[core_no]]
+ >> 19) & 0x1f;
+ target_gain.pga[core_no] =
+ (tx_pwrctrl_tbl
+ [base_idx[core_no]]
+ >> 24) & 0xf;
+ target_gain.txgm[core_no] =
+ (tx_pwrctrl_tbl
+ [base_idx[core_no]]
+ >> 28) & 0x7;
+ target_gain.txlpf[core_no] =
+ (tx_pwrctrl_tbl
+ [base_idx[core_no]]
+ >> 31) & 0x1;
+ } else {
+ target_gain.ipa[core_no] =
+ (tx_pwrctrl_tbl
+ [base_idx[core_no]]
+ >> 16) & 0xf;
+ target_gain.pad[core_no] =
+ (tx_pwrctrl_tbl
+ [base_idx[core_no]]
+ >> 20) & 0xf;
+ target_gain.pga[core_no] =
+ (tx_pwrctrl_tbl
+ [base_idx[core_no]]
+ >> 24) & 0xf;
+ target_gain.txgm[core_no] =
+ (tx_pwrctrl_tbl
+ [base_idx[core_no]]
+ >> 28) & 0x7;
+ }
+ } else {
+ target_gain.ipa[core_no] =
+ (nphy_tpc_txgain[base_idx[core_no]] >>
+ 16) & 0x3;
+ target_gain.pad[core_no] =
+ (nphy_tpc_txgain[base_idx[core_no]] >>
+ 18) & 0x3;
+ target_gain.pga[core_no] =
+ (nphy_tpc_txgain[base_idx[core_no]] >>
+ 20) & 0x7;
+ target_gain.txgm[core_no] =
+ (nphy_tpc_txgain[base_idx[core_no]] >>
+ 23) & 0x7;
+ }
+ }
+ }
+
+ return target_gain;
+}
+
+static void
+wlc_phy_iqcal_gainparams_nphy(struct brcms_phy *pi, u16 core_no,
+ struct nphy_txgains target_gain,
+ struct nphy_iqcal_params *params)
+{
+ u8 k;
+ int idx;
+ u16 gain_index;
+ u8 band_idx = (CHSPEC_IS5G(pi->radio_chanspec) ? 1 : 0);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ params->txlpf = target_gain.txlpf[core_no];
+
+ params->txgm = target_gain.txgm[core_no];
+ params->pga = target_gain.pga[core_no];
+ params->pad = target_gain.pad[core_no];
+ params->ipa = target_gain.ipa[core_no];
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ params->cal_gain =
+ ((params->txlpf << 15) | (params->txgm << 12) |
+ (params->pga << 8) |
+ (params->pad << 3) | (params->ipa));
+ else
+ params->cal_gain =
+ ((params->txgm << 12) | (params->pga << 8) |
+ (params->pad << 4) | (params->ipa));
+
+ params->ncorr[0] = 0x79;
+ params->ncorr[1] = 0x79;
+ params->ncorr[2] = 0x79;
+ params->ncorr[3] = 0x79;
+ params->ncorr[4] = 0x79;
+ } else {
+
+ gain_index = ((target_gain.pad[core_no] << 0) |
+ (target_gain.pga[core_no] << 4) |
+ (target_gain.txgm[core_no] << 8));
+
+ idx = -1;
+ for (k = 0; k < NPHY_IQCAL_NUMGAINS; k++) {
+ if (tbl_iqcal_gainparams_nphy[band_idx][k][0] ==
+ gain_index) {
+ idx = k;
+ break;
+ }
+ }
+
+ params->txgm = tbl_iqcal_gainparams_nphy[band_idx][k][1];
+ params->pga = tbl_iqcal_gainparams_nphy[band_idx][k][2];
+ params->pad = tbl_iqcal_gainparams_nphy[band_idx][k][3];
+ params->cal_gain = ((params->txgm << 7) | (params->pga << 4) |
+ (params->pad << 2));
+ params->ncorr[0] = tbl_iqcal_gainparams_nphy[band_idx][k][4];
+ params->ncorr[1] = tbl_iqcal_gainparams_nphy[band_idx][k][5];
+ params->ncorr[2] = tbl_iqcal_gainparams_nphy[band_idx][k][6];
+ params->ncorr[3] = tbl_iqcal_gainparams_nphy[band_idx][k][7];
+ }
+}
+
+static void wlc_phy_txcal_radio_setup_nphy(struct brcms_phy *pi)
+{
+ u16 jtag_core, core;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ for (core = 0; core <= 1; core++) {
+
+ pi->tx_rx_cal_radio_saveregs[(core * 11) + 0] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TX_SSI_MASTER);
+
+ pi->tx_rx_cal_radio_saveregs[(core * 11) + 1] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, core,
+ IQCAL_VCM_HG);
+
+ pi->tx_rx_cal_radio_saveregs[(core * 11) + 2] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, core,
+ IQCAL_IDAC);
+
+ pi->tx_rx_cal_radio_saveregs[(core * 11) + 3] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TSSI_VCM);
+
+ pi->tx_rx_cal_radio_saveregs[(core * 11) + 4] = 0;
+
+ pi->tx_rx_cal_radio_saveregs[(core * 11) + 5] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TX_SSI_MUX);
+
+ if (pi->pubpi.radiorev != 5)
+ pi->tx_rx_cal_radio_saveregs[(core * 11) + 6] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX,
+ core,
+ TSSIA);
+
+ pi->tx_rx_cal_radio_saveregs[(core * 11) + 7] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, core, TSSIG);
+
+ pi->tx_rx_cal_radio_saveregs[(core * 11) + 8] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TSSI_MISC1);
+
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TX_SSI_MASTER, 0x0a);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ IQCAL_VCM_HG, 0x43);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ IQCAL_IDAC, 0x55);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TSSI_VCM, 0x00);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TSSIG, 0x00);
+ if (pi->use_int_tx_iqlo_cal_nphy) {
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX,
+ core, TX_SSI_MUX, 0x4);
+ if (!(pi->
+ internal_tx_iqlo_cal_tapoff_intpa_nphy))
+ WRITE_RADIO_REG3(pi, RADIO_2057,
+ TX, core,
+ TSSIA, 0x31);
+ else
+ WRITE_RADIO_REG3(pi, RADIO_2057,
+ TX, core,
+ TSSIA, 0x21);
+ }
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TSSI_MISC1, 0x00);
+ } else {
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TX_SSI_MASTER, 0x06);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ IQCAL_VCM_HG, 0x43);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ IQCAL_IDAC, 0x55);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TSSI_VCM, 0x00);
+
+ if (pi->pubpi.radiorev != 5)
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX,
+ core, TSSIA, 0x00);
+ if (pi->use_int_tx_iqlo_cal_nphy) {
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX,
+ core, TX_SSI_MUX,
+ 0x06);
+ if (!(pi->
+ internal_tx_iqlo_cal_tapoff_intpa_nphy))
+ WRITE_RADIO_REG3(pi, RADIO_2057,
+ TX, core,
+ TSSIG, 0x31);
+ else
+ WRITE_RADIO_REG3(pi, RADIO_2057,
+ TX, core,
+ TSSIG, 0x21);
+ }
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TSSI_MISC1, 0x00);
+ }
+ }
+ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+
+ for (core = 0; core <= 1; core++) {
+ jtag_core =
+ (core ==
+ PHY_CORE_0) ? RADIO_2056_TX0 : RADIO_2056_TX1;
+
+ pi->tx_rx_cal_radio_saveregs[(core * 11) + 0] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_TX_SSI_MASTER |
+ jtag_core);
+
+ pi->tx_rx_cal_radio_saveregs[(core * 11) + 1] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_IQCAL_VCM_HG |
+ jtag_core);
+
+ pi->tx_rx_cal_radio_saveregs[(core * 11) + 2] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_IQCAL_IDAC |
+ jtag_core);
+
+ pi->tx_rx_cal_radio_saveregs[(core * 11) + 3] =
+ read_radio_reg(
+ pi,
+ RADIO_2056_TX_TSSI_VCM |
+ jtag_core);
+
+ pi->tx_rx_cal_radio_saveregs[(core * 11) + 4] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_TX_AMP_DET |
+ jtag_core);
+
+ pi->tx_rx_cal_radio_saveregs[(core * 11) + 5] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_TX_SSI_MUX |
+ jtag_core);
+
+ pi->tx_rx_cal_radio_saveregs[(core * 11) + 6] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_TSSIA | jtag_core);
+
+ pi->tx_rx_cal_radio_saveregs[(core * 11) + 7] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_TSSIG | jtag_core);
+
+ pi->tx_rx_cal_radio_saveregs[(core * 11) + 8] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_TSSI_MISC1 |
+ jtag_core);
+
+ pi->tx_rx_cal_radio_saveregs[(core * 11) + 9] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_TSSI_MISC2 |
+ jtag_core);
+
+ pi->tx_rx_cal_radio_saveregs[(core * 11) + 10] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_TSSI_MISC3 |
+ jtag_core);
+
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ write_radio_reg(pi,
+ RADIO_2056_TX_TX_SSI_MASTER |
+ jtag_core, 0x0a);
+ write_radio_reg(pi,
+ RADIO_2056_TX_IQCAL_VCM_HG |
+ jtag_core, 0x40);
+ write_radio_reg(pi,
+ RADIO_2056_TX_IQCAL_IDAC |
+ jtag_core, 0x55);
+ write_radio_reg(pi,
+ RADIO_2056_TX_TSSI_VCM |
+ jtag_core, 0x00);
+ write_radio_reg(pi,
+ RADIO_2056_TX_TX_AMP_DET |
+ jtag_core, 0x00);
+
+ if (PHY_IPA(pi)) {
+ write_radio_reg(
+ pi,
+ RADIO_2056_TX_TX_SSI_MUX
+ | jtag_core, 0x4);
+ write_radio_reg(pi,
+ RADIO_2056_TX_TSSIA |
+ jtag_core, 0x1);
+ } else {
+ write_radio_reg(
+ pi,
+ RADIO_2056_TX_TX_SSI_MUX
+ | jtag_core, 0x00);
+ write_radio_reg(pi,
+ RADIO_2056_TX_TSSIA |
+ jtag_core, 0x2f);
+ }
+ write_radio_reg(pi,
+ RADIO_2056_TX_TSSIG | jtag_core,
+ 0x00);
+ write_radio_reg(pi,
+ RADIO_2056_TX_TSSI_MISC1 |
+ jtag_core, 0x00);
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_TSSI_MISC2 |
+ jtag_core, 0x00);
+ write_radio_reg(pi,
+ RADIO_2056_TX_TSSI_MISC3 |
+ jtag_core, 0x00);
+ } else {
+ write_radio_reg(pi,
+ RADIO_2056_TX_TX_SSI_MASTER |
+ jtag_core, 0x06);
+ write_radio_reg(pi,
+ RADIO_2056_TX_IQCAL_VCM_HG |
+ jtag_core, 0x40);
+ write_radio_reg(pi,
+ RADIO_2056_TX_IQCAL_IDAC |
+ jtag_core, 0x55);
+ write_radio_reg(pi,
+ RADIO_2056_TX_TSSI_VCM |
+ jtag_core, 0x00);
+ write_radio_reg(pi,
+ RADIO_2056_TX_TX_AMP_DET |
+ jtag_core, 0x00);
+ write_radio_reg(pi,
+ RADIO_2056_TX_TSSIA | jtag_core,
+ 0x00);
+
+ if (PHY_IPA(pi)) {
+
+ write_radio_reg(
+ pi,
+ RADIO_2056_TX_TX_SSI_MUX
+ | jtag_core, 0x06);
+ if (NREV_LT(pi->pubpi.phy_rev, 5))
+ write_radio_reg(
+ pi,
+ RADIO_2056_TX_TSSIG
+ | jtag_core,
+ 0x11);
+ else
+ write_radio_reg(
+ pi,
+ RADIO_2056_TX_TSSIG
+ | jtag_core,
+ 0x1);
+ } else {
+ write_radio_reg(
+ pi,
+ RADIO_2056_TX_TX_SSI_MUX
+ | jtag_core, 0x00);
+ write_radio_reg(pi,
+ RADIO_2056_TX_TSSIG |
+ jtag_core, 0x20);
+ }
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_TSSI_MISC1 |
+ jtag_core, 0x00);
+ write_radio_reg(pi,
+ RADIO_2056_TX_TSSI_MISC2 |
+ jtag_core, 0x00);
+ write_radio_reg(pi,
+ RADIO_2056_TX_TSSI_MISC3 |
+ jtag_core, 0x00);
+ }
+ }
+ } else {
+
+ pi->tx_rx_cal_radio_saveregs[0] =
+ read_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1);
+ write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1, 0x29);
+ pi->tx_rx_cal_radio_saveregs[1] =
+ read_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2);
+ write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2, 0x54);
+
+ pi->tx_rx_cal_radio_saveregs[2] =
+ read_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1);
+ write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1, 0x29);
+ pi->tx_rx_cal_radio_saveregs[3] =
+ read_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2);
+ write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2, 0x54);
+
+ pi->tx_rx_cal_radio_saveregs[4] =
+ read_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1);
+ pi->tx_rx_cal_radio_saveregs[5] =
+ read_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2);
+
+ if ((read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand) ==
+ 0) {
+
+ write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1, 0x04);
+ write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2, 0x04);
+ } else {
+
+ write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1, 0x20);
+ write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2, 0x20);
+ }
+
+ if (NREV_LT(pi->pubpi.phy_rev, 2)) {
+
+ or_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM, 0x20);
+ or_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM, 0x20);
+ } else {
+
+ and_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM, 0xdf);
+ and_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM, 0xdf);
+ }
+ }
+}
+
+static void wlc_phy_txcal_radio_cleanup_nphy(struct brcms_phy *pi)
+{
+ u16 jtag_core, core;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ for (core = 0; core <= 1; core++) {
+
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TX_SSI_MASTER,
+ pi->
+ tx_rx_cal_radio_saveregs[(core * 11) +
+ 0]);
+
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, IQCAL_VCM_HG,
+ pi->
+ tx_rx_cal_radio_saveregs[(core * 11) +
+ 1]);
+
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, IQCAL_IDAC,
+ pi->
+ tx_rx_cal_radio_saveregs[(core * 11) +
+ 2]);
+
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TSSI_VCM,
+ pi->
+ tx_rx_cal_radio_saveregs[(core * 11) +
+ 3]);
+
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TX_SSI_MUX,
+ pi->
+ tx_rx_cal_radio_saveregs[(core * 11) +
+ 5]);
+
+ if (pi->pubpi.radiorev != 5)
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TSSIA,
+ pi->tx_rx_cal_radio_saveregs
+ [(core * 11) + 6]);
+
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TSSIG,
+ pi->
+ tx_rx_cal_radio_saveregs[(core * 11) +
+ 7]);
+
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TSSI_MISC1,
+ pi->
+ tx_rx_cal_radio_saveregs[(core * 11) +
+ 8]);
+ }
+ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ for (core = 0; core <= 1; core++) {
+ jtag_core = (core == PHY_CORE_0) ?
+ RADIO_2056_TX0 : RADIO_2056_TX1;
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_TX_SSI_MASTER | jtag_core,
+ pi->
+ tx_rx_cal_radio_saveregs[(core * 11) +
+ 0]);
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_IQCAL_VCM_HG | jtag_core,
+ pi->
+ tx_rx_cal_radio_saveregs[(core * 11) +
+ 1]);
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_IQCAL_IDAC | jtag_core,
+ pi->
+ tx_rx_cal_radio_saveregs[(core * 11) +
+ 2]);
+
+ write_radio_reg(pi, RADIO_2056_TX_TSSI_VCM | jtag_core,
+ pi->
+ tx_rx_cal_radio_saveregs[(core * 11) +
+ 3]);
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_TX_AMP_DET | jtag_core,
+ pi->
+ tx_rx_cal_radio_saveregs[(core * 11) +
+ 4]);
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_TX_SSI_MUX | jtag_core,
+ pi->
+ tx_rx_cal_radio_saveregs[(core * 11) +
+ 5]);
+
+ write_radio_reg(pi, RADIO_2056_TX_TSSIA | jtag_core,
+ pi->
+ tx_rx_cal_radio_saveregs[(core * 11) +
+ 6]);
+
+ write_radio_reg(pi, RADIO_2056_TX_TSSIG | jtag_core,
+ pi->
+ tx_rx_cal_radio_saveregs[(core * 11) +
+ 7]);
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_TSSI_MISC1 | jtag_core,
+ pi->
+ tx_rx_cal_radio_saveregs[(core * 11) +
+ 8]);
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_TSSI_MISC2 | jtag_core,
+ pi->
+ tx_rx_cal_radio_saveregs[(core * 11) +
+ 9]);
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_TSSI_MISC3 | jtag_core,
+ pi->
+ tx_rx_cal_radio_saveregs[(core * 11) +
+ 10]);
+ }
+ } else {
+
+ write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1,
+ pi->tx_rx_cal_radio_saveregs[0]);
+ write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2,
+ pi->tx_rx_cal_radio_saveregs[1]);
+ write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1,
+ pi->tx_rx_cal_radio_saveregs[2]);
+ write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2,
+ pi->tx_rx_cal_radio_saveregs[3]);
+ write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1,
+ pi->tx_rx_cal_radio_saveregs[4]);
+ write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2,
+ pi->tx_rx_cal_radio_saveregs[5]);
+ }
+}
+
+static void wlc_phy_txcal_physetup_nphy(struct brcms_phy *pi)
+{
+ u16 val, mask;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ pi->tx_rx_cal_phy_saveregs[0] = read_phy_reg(pi, 0xa6);
+ pi->tx_rx_cal_phy_saveregs[1] = read_phy_reg(pi, 0xa7);
+
+ mask = ((0x3 << 8) | (0x3 << 10));
+ val = (0x2 << 8);
+ val |= (0x2 << 10);
+ mod_phy_reg(pi, 0xa6, mask, val);
+ mod_phy_reg(pi, 0xa7, mask, val);
+
+ val = read_phy_reg(pi, 0x8f);
+ pi->tx_rx_cal_phy_saveregs[2] = val;
+ val |= ((0x1 << 9) | (0x1 << 10));
+ write_phy_reg(pi, 0x8f, val);
+
+ val = read_phy_reg(pi, 0xa5);
+ pi->tx_rx_cal_phy_saveregs[3] = val;
+ val |= ((0x1 << 9) | (0x1 << 10));
+ write_phy_reg(pi, 0xa5, val);
+
+ pi->tx_rx_cal_phy_saveregs[4] = read_phy_reg(pi, 0x01);
+ mod_phy_reg(pi, 0x01, (0x1 << 15), 0);
+
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 3, 16,
+ &val);
+ pi->tx_rx_cal_phy_saveregs[5] = val;
+ val = 0;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 3, 16,
+ &val);
+
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 19, 16,
+ &val);
+ pi->tx_rx_cal_phy_saveregs[6] = val;
+ val = 0;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 19, 16,
+ &val);
+
+ pi->tx_rx_cal_phy_saveregs[7] = read_phy_reg(pi, 0x91);
+ pi->tx_rx_cal_phy_saveregs[8] = read_phy_reg(pi, 0x92);
+
+ if (!(pi->use_int_tx_iqlo_cal_nphy))
+ wlc_phy_rfctrlintc_override_nphy(
+ pi,
+ NPHY_RfctrlIntc_override_PA,
+ 1,
+ RADIO_MIMO_CORESEL_CORE1
+ |
+ RADIO_MIMO_CORESEL_CORE2);
+ else
+ wlc_phy_rfctrlintc_override_nphy(
+ pi,
+ NPHY_RfctrlIntc_override_PA,
+ 0,
+ RADIO_MIMO_CORESEL_CORE1
+ |
+ RADIO_MIMO_CORESEL_CORE2);
+
+ wlc_phy_rfctrlintc_override_nphy(pi,
+ NPHY_RfctrlIntc_override_TRSW,
+ 0x2, RADIO_MIMO_CORESEL_CORE1);
+ wlc_phy_rfctrlintc_override_nphy(pi,
+ NPHY_RfctrlIntc_override_TRSW,
+ 0x8, RADIO_MIMO_CORESEL_CORE2);
+
+ pi->tx_rx_cal_phy_saveregs[9] = read_phy_reg(pi, 0x297);
+ pi->tx_rx_cal_phy_saveregs[10] = read_phy_reg(pi, 0x29b);
+ mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (0) << 0);
+
+ mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (0) << 0);
+
+ if (NREV_IS(pi->pubpi.phy_rev, 7)
+ || NREV_GE(pi->pubpi.phy_rev, 8))
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 7),
+ wlc_phy_read_lpf_bw_ctl_nphy
+ (pi,
+ 0), 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+
+ if (pi->use_int_tx_iqlo_cal_nphy
+ && !(pi->internal_tx_iqlo_cal_tapoff_intpa_nphy)) {
+
+ if (NREV_IS(pi->pubpi.phy_rev, 7)) {
+
+ mod_radio_reg(pi, RADIO_2057_OVR_REG0, 1 << 4,
+ 1 << 4);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ mod_radio_reg(
+ pi,
+ RADIO_2057_PAD2G_TUNE_PUS_CORE0,
+ 1, 0);
+ mod_radio_reg(
+ pi,
+ RADIO_2057_PAD2G_TUNE_PUS_CORE1,
+ 1, 0);
+ } else {
+ mod_radio_reg(
+ pi,
+ RADIO_2057_IPA5G_CASCOFFV_PU_CORE0,
+ 1, 0);
+ mod_radio_reg(
+ pi,
+ RADIO_2057_IPA5G_CASCOFFV_PU_CORE1,
+ 1, 0);
+ }
+ } else if (NREV_GE(pi->pubpi.phy_rev, 8)) {
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi,
+ (0x1 << 3), 0,
+ 0x3, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ }
+ }
+ } else {
+ pi->tx_rx_cal_phy_saveregs[0] = read_phy_reg(pi, 0xa6);
+ pi->tx_rx_cal_phy_saveregs[1] = read_phy_reg(pi, 0xa7);
+
+ mask = ((0x3 << 12) | (0x3 << 14));
+ val = (0x2 << 12);
+ val |= (0x2 << 14);
+ mod_phy_reg(pi, 0xa6, mask, val);
+ mod_phy_reg(pi, 0xa7, mask, val);
+
+ val = read_phy_reg(pi, 0xa5);
+ pi->tx_rx_cal_phy_saveregs[2] = val;
+ val |= ((0x1 << 12) | (0x1 << 13));
+ write_phy_reg(pi, 0xa5, val);
+
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 2, 16,
+ &val);
+ pi->tx_rx_cal_phy_saveregs[3] = val;
+ val |= 0x2000;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 2, 16,
+ &val);
+
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 18, 16,
+ &val);
+ pi->tx_rx_cal_phy_saveregs[4] = val;
+ val |= 0x2000;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 18, 16,
+ &val);
+
+ pi->tx_rx_cal_phy_saveregs[5] = read_phy_reg(pi, 0x91);
+ pi->tx_rx_cal_phy_saveregs[6] = read_phy_reg(pi, 0x92);
+ val = CHSPEC_IS5G(pi->radio_chanspec) ? 0x180 : 0x120;
+ write_phy_reg(pi, 0x91, val);
+ write_phy_reg(pi, 0x92, val);
+ }
+}
+
+static void wlc_phy_txcal_phycleanup_nphy(struct brcms_phy *pi)
+{
+ u16 mask;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ write_phy_reg(pi, 0xa6, pi->tx_rx_cal_phy_saveregs[0]);
+ write_phy_reg(pi, 0xa7, pi->tx_rx_cal_phy_saveregs[1]);
+ write_phy_reg(pi, 0x8f, pi->tx_rx_cal_phy_saveregs[2]);
+ write_phy_reg(pi, 0xa5, pi->tx_rx_cal_phy_saveregs[3]);
+ write_phy_reg(pi, 0x01, pi->tx_rx_cal_phy_saveregs[4]);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 3, 16,
+ &pi->tx_rx_cal_phy_saveregs[5]);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 19, 16,
+ &pi->tx_rx_cal_phy_saveregs[6]);
+
+ write_phy_reg(pi, 0x91, pi->tx_rx_cal_phy_saveregs[7]);
+ write_phy_reg(pi, 0x92, pi->tx_rx_cal_phy_saveregs[8]);
+
+ write_phy_reg(pi, 0x297, pi->tx_rx_cal_phy_saveregs[9]);
+ write_phy_reg(pi, 0x29b, pi->tx_rx_cal_phy_saveregs[10]);
+
+ if (NREV_IS(pi->pubpi.phy_rev, 7)
+ || NREV_GE(pi->pubpi.phy_rev, 8))
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 7), 0, 0,
+ 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+
+ wlc_phy_resetcca_nphy(pi);
+
+ if (pi->use_int_tx_iqlo_cal_nphy
+ && !(pi->internal_tx_iqlo_cal_tapoff_intpa_nphy)) {
+
+ if (NREV_IS(pi->pubpi.phy_rev, 7)) {
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ mod_radio_reg(
+ pi,
+ RADIO_2057_PAD2G_TUNE_PUS_CORE0,
+ 1, 1);
+ mod_radio_reg(
+ pi,
+ RADIO_2057_PAD2G_TUNE_PUS_CORE1,
+ 1, 1);
+ } else {
+ mod_radio_reg(
+ pi,
+ RADIO_2057_IPA5G_CASCOFFV_PU_CORE0,
+ 1, 1);
+ mod_radio_reg(
+ pi,
+ RADIO_2057_IPA5G_CASCOFFV_PU_CORE1,
+ 1, 1);
+ }
+
+ mod_radio_reg(pi, RADIO_2057_OVR_REG0, 1 << 4,
+ 0);
+ } else if (NREV_GE(pi->pubpi.phy_rev, 8)) {
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi,
+ (0x1 << 3), 0,
+ 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ }
+ }
+ } else {
+ mask = ((0x3 << 12) | (0x3 << 14));
+ mod_phy_reg(pi, 0xa6, mask, pi->tx_rx_cal_phy_saveregs[0]);
+ mod_phy_reg(pi, 0xa7, mask, pi->tx_rx_cal_phy_saveregs[1]);
+ write_phy_reg(pi, 0xa5, pi->tx_rx_cal_phy_saveregs[2]);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 2, 16,
+ &pi->tx_rx_cal_phy_saveregs[3]);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 18, 16,
+ &pi->tx_rx_cal_phy_saveregs[4]);
+
+ write_phy_reg(pi, 0x91, pi->tx_rx_cal_phy_saveregs[5]);
+ write_phy_reg(pi, 0x92, pi->tx_rx_cal_phy_saveregs[6]);
+ }
+}
+
+void
+wlc_phy_est_tonepwr_nphy(struct brcms_phy *pi, s32 *qdBm_pwrbuf, u8 num_samps)
+{
+ u16 tssi_reg;
+ s32 temp, pwrindex[2];
+ s32 idle_tssi[2];
+ s32 rssi_buf[4];
+ s32 tssival[2];
+ u8 tssi_type;
+
+ tssi_reg = read_phy_reg(pi, 0x1e9);
+
+ temp = (s32) (tssi_reg & 0x3f);
+ idle_tssi[0] = (temp <= 31) ? temp : (temp - 64);
+
+ temp = (s32) ((tssi_reg >> 8) & 0x3f);
+ idle_tssi[1] = (temp <= 31) ? temp : (temp - 64);
+
+ tssi_type =
+ CHSPEC_IS5G(pi->radio_chanspec) ?
+ (u8)NPHY_RSSI_SEL_TSSI_5G : (u8)NPHY_RSSI_SEL_TSSI_2G;
+
+ wlc_phy_poll_rssi_nphy(pi, tssi_type, rssi_buf, num_samps);
+
+ tssival[0] = rssi_buf[0] / ((s32) num_samps);
+ tssival[1] = rssi_buf[2] / ((s32) num_samps);
+
+ pwrindex[0] = idle_tssi[0] - tssival[0] + 64;
+ pwrindex[1] = idle_tssi[1] - tssival[1] + 64;
+
+ if (pwrindex[0] < 0)
+ pwrindex[0] = 0;
+ else if (pwrindex[0] > 63)
+ pwrindex[0] = 63;
+
+ if (pwrindex[1] < 0)
+ pwrindex[1] = 0;
+ else if (pwrindex[1] > 63)
+ pwrindex[1] = 63;
+
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_CORE1TXPWRCTL, 1,
+ (u32) pwrindex[0], 32, &qdBm_pwrbuf[0]);
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_CORE2TXPWRCTL, 1,
+ (u32) pwrindex[1], 32, &qdBm_pwrbuf[1]);
+}
+
+static void wlc_phy_update_txcal_ladder_nphy(struct brcms_phy *pi, u16 core)
+{
+ int index;
+ u32 bbmult_scale;
+ u16 bbmult;
+ u16 tblentry;
+
+ struct nphy_txiqcal_ladder ladder_lo[] = {
+ {3, 0}, {4, 0}, {6, 0}, {9, 0}, {13, 0}, {18, 0},
+ {25, 0}, {25, 1}, {25, 2}, {25, 3}, {25, 4}, {25, 5},
+ {25, 6}, {25, 7}, {35, 7}, {50, 7}, {71, 7}, {100, 7}
+ };
+
+ struct nphy_txiqcal_ladder ladder_iq[] = {
+ {3, 0}, {4, 0}, {6, 0}, {9, 0}, {13, 0}, {18, 0},
+ {25, 0}, {35, 0}, {50, 0}, {71, 0}, {100, 0}, {100, 1},
+ {100, 2}, {100, 3}, {100, 4}, {100, 5}, {100, 6}, {100, 7}
+ };
+
+ bbmult = (core == PHY_CORE_0) ?
+ ((pi->nphy_txcal_bbmult >> 8) & 0xff) :
+ (pi->nphy_txcal_bbmult & 0xff);
+
+ for (index = 0; index < 18; index++) {
+ bbmult_scale = ladder_lo[index].percent * bbmult;
+ bbmult_scale /= 100;
+
+ tblentry =
+ ((bbmult_scale & 0xff) << 8) | ladder_lo[index].g_env;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 1, index, 16,
+ &tblentry);
+
+ bbmult_scale = ladder_iq[index].percent * bbmult;
+ bbmult_scale /= 100;
+
+ tblentry =
+ ((bbmult_scale & 0xff) << 8) | ladder_iq[index].g_env;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 1, index + 32,
+ 16, &tblentry);
+ }
+}
+
+static u8 wlc_phy_txpwr_idx_cur_get_nphy(struct brcms_phy *pi, u8 core)
+{
+ u16 tmp;
+ tmp = read_phy_reg(pi, ((core == PHY_CORE_0) ? 0x1ed : 0x1ee));
+
+ tmp = (tmp & (0x7f << 8)) >> 8;
+ return (u8) tmp;
+}
+
+static void
+wlc_phy_txpwr_idx_cur_set_nphy(struct brcms_phy *pi, u8 idx0, u8 idx1)
+{
+ mod_phy_reg(pi, 0x1e7, (0x7f << 0), idx0);
+
+ if (NREV_GT(pi->pubpi.phy_rev, 1))
+ mod_phy_reg(pi, 0x222, (0xff << 0), idx1);
+}
+
+static u16 wlc_phy_ipa_get_bbmult_nphy(struct brcms_phy *pi)
+{
+ u16 m0m1;
+
+ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &m0m1);
+
+ return m0m1;
+}
+
+static void wlc_phy_ipa_set_bbmult_nphy(struct brcms_phy *pi, u8 m0, u8 m1)
+{
+ u16 m0m1 = (u16) ((m0 << 8) | m1);
+
+ wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &m0m1);
+ wlc_phy_table_write_nphy(pi, 15, 1, 95, 16, &m0m1);
+}
+
+static void
+wlc_phy_papd_cal_setup_nphy(struct brcms_phy *pi,
+ struct nphy_papd_restore_state *state, u8 core)
+{
+ s32 tone_freq;
+ u8 off_core;
+ u16 mixgain = 0;
+
+ off_core = core ^ 0x1;
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ if (NREV_IS(pi->pubpi.phy_rev, 7)
+ || NREV_GE(pi->pubpi.phy_rev, 8))
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 7),
+ wlc_phy_read_lpf_bw_ctl_nphy
+ (pi,
+ 0), 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if (pi->pubpi.radiorev == 5)
+ mixgain = (core == 0) ? 0x20 : 0x00;
+ else if ((pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8))
+ mixgain = 0x00;
+ else if ((pi->pubpi.radiorev <= 4)
+ || (pi->pubpi.radiorev == 6))
+ mixgain = 0x00;
+ } else {
+ if ((pi->pubpi.radiorev == 4) ||
+ (pi->pubpi.radiorev == 6))
+ mixgain = 0x50;
+ else if ((pi->pubpi.radiorev == 3)
+ || (pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8))
+ mixgain = 0x0;
+ }
+
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 11),
+ mixgain, (1 << core), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+
+ wlc_phy_rfctrl_override_1tomany_nphy(
+ pi,
+ NPHY_REV7_RfctrlOverride_cmd_tx_pu,
+ 1, (1 << core), 0);
+ wlc_phy_rfctrl_override_1tomany_nphy(
+ pi,
+ NPHY_REV7_RfctrlOverride_cmd_tx_pu,
+ 0, (1 << off_core), 0);
+
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3),
+ 0, 0x3, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 2), 1,
+ (1 << core), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 0), 0,
+ (1 << core), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1), 1,
+ (1 << core), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID2);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 8), 0,
+ (1 << core), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 9), 1,
+ (1 << core), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 10), 0,
+ (1 << core), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), 1,
+ (1 << core), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 5),
+ 0, (1 << core), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 4), 0,
+ (1 << core), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+
+ state->afectrl[core] = read_phy_reg(pi, (core == PHY_CORE_0) ?
+ 0xa6 : 0xa7);
+ state->afeoverride[core] =
+ read_phy_reg(pi, (core == PHY_CORE_0) ? 0x8f : 0xa5);
+ state->afectrl[off_core] =
+ read_phy_reg(pi, (core == PHY_CORE_0) ? 0xa7 : 0xa6);
+ state->afeoverride[off_core] =
+ read_phy_reg(pi, (core == PHY_CORE_0) ? 0xa5 : 0x8f);
+
+ mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0xa6 : 0xa7),
+ (0x1 << 2), 0);
+ mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0x8f :
+ 0xa5), (0x1 << 2), (0x1 << 2));
+
+ mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0xa7 : 0xa6),
+ (0x1 << 2), (0x1 << 2));
+ mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0xa5 :
+ 0x8f), (0x1 << 2), (0x1 << 2));
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ state->pwrup[core] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_2G_PWRUP);
+ state->atten[core] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_2G_ATTEN);
+ state->pwrup[off_core] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, off_core,
+ TXRXCOUPLE_2G_PWRUP);
+ state->atten[off_core] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, off_core,
+ TXRXCOUPLE_2G_ATTEN);
+
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_2G_PWRUP, 0xc);
+
+ if ((pi->pubpi.radiorev == 3) ||
+ (pi->pubpi.radiorev == 4) ||
+ (pi->pubpi.radiorev == 6))
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_2G_ATTEN, 0xf0);
+ else if (pi->pubpi.radiorev == 5)
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_2G_ATTEN,
+ (core == 0) ? 0xf7 : 0xf2);
+ else if ((pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8))
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_2G_ATTEN, 0xf0);
+
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, off_core,
+ TXRXCOUPLE_2G_PWRUP, 0x0);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, off_core,
+ TXRXCOUPLE_2G_ATTEN, 0xff);
+ } else {
+ state->pwrup[core] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_5G_PWRUP);
+ state->atten[core] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_5G_ATTEN);
+ state->pwrup[off_core] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, off_core,
+ TXRXCOUPLE_5G_PWRUP);
+ state->atten[off_core] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, off_core,
+ TXRXCOUPLE_5G_ATTEN);
+
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_5G_PWRUP, 0xc);
+
+ if ((pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8))
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_5G_ATTEN, 0xf4);
+
+ else
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_5G_ATTEN, 0xf0);
+
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, off_core,
+ TXRXCOUPLE_5G_PWRUP, 0x0);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, off_core,
+ TXRXCOUPLE_5G_ATTEN, 0xff);
+ }
+
+ tone_freq = 4000;
+
+ wlc_phy_tx_tone_nphy(pi, tone_freq, 181, 0, 0, false);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (NPHY_PAPD_COMP_ON) << 0);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 13), (1) << 13);
+
+ mod_phy_reg(pi, (off_core == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (NPHY_PAPD_COMP_OFF) << 0);
+
+ mod_phy_reg(pi, (off_core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 13), (0) << 13);
+
+ } else {
+
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 12), 0, 0x3, 0);
+
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 1, 0, 0);
+
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 0), 0, 0x3, 0);
+
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 2), 1, 0x3, 0);
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 1), 1, 0x3, 0);
+
+ state->afectrl[core] = read_phy_reg(pi, (core == PHY_CORE_0) ?
+ 0xa6 : 0xa7);
+ state->afeoverride[core] =
+ read_phy_reg(pi, (core == PHY_CORE_0) ? 0x8f : 0xa5);
+
+ mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0xa6 : 0xa7),
+ (0x1 << 0) | (0x1 << 1) | (0x1 << 2), 0);
+ mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0x8f :
+ 0xa5),
+ (0x1 << 0) |
+ (0x1 << 1) |
+ (0x1 << 2), (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
+
+ state->vga_master[core] =
+ READ_RADIO_REG2(pi, RADIO_2056, RX, core, VGA_MASTER);
+ WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, VGA_MASTER, 0x2b);
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ state->fbmix[core] =
+ READ_RADIO_REG2(pi, RADIO_2056, RX, core,
+ TXFBMIX_G);
+ state->intpa_master[core] =
+ READ_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAG_MASTER);
+
+ WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, TXFBMIX_G,
+ 0x03);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAG_MASTER, 0x04);
+ } else {
+ state->fbmix[core] =
+ READ_RADIO_REG2(pi, RADIO_2056, RX, core,
+ TXFBMIX_A);
+ state->intpa_master[core] =
+ READ_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAA_MASTER);
+
+ WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, TXFBMIX_A,
+ 0x03);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAA_MASTER, 0x04);
+
+ }
+
+ tone_freq = 4000;
+
+ wlc_phy_tx_tone_nphy(pi, tone_freq, 181, 0, 0, false);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (1) << 0);
+
+ mod_phy_reg(pi, (off_core == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (0) << 0);
+
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 0, 0x3, 0);
+ }
+}
+
+static void
+wlc_phy_papd_cal_cleanup_nphy(struct brcms_phy *pi,
+ struct nphy_papd_restore_state *state)
+{
+ u8 core;
+
+ wlc_phy_stopplayback_nphy(pi);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_2G_PWRUP, 0);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_2G_ATTEN,
+ state->atten[core]);
+ } else {
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_5G_PWRUP, 0);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_5G_ATTEN,
+ state->atten[core]);
+ }
+ }
+
+ if ((pi->pubpi.radiorev == 4) || (pi->pubpi.radiorev == 6))
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 2),
+ 1, 0x3, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ else
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 2),
+ 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1),
+ 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 0), 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID2);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 2), 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID2);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 11), 1, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 11), 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 12), 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 2), 1, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 0), 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1), 1, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID2);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 8), 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 9), 1, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 10), 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), 1, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 5), 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 4), 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+
+ write_phy_reg(pi, (core == PHY_CORE_0) ?
+ 0xa6 : 0xa7, state->afectrl[core]);
+ write_phy_reg(pi, (core == PHY_CORE_0) ? 0x8f :
+ 0xa5, state->afeoverride[core]);
+ }
+
+ wlc_phy_ipa_set_bbmult_nphy(pi, (state->mm >> 8) & 0xff,
+ (state->mm & 0xff));
+
+ if (NREV_IS(pi->pubpi.phy_rev, 7)
+ || NREV_GE(pi->pubpi.phy_rev, 8))
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 7), 0, 0,
+ 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ } else {
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 12), 0, 0x3, 1);
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 13), 0, 0x3, 1);
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 0), 0, 0x3, 1);
+
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 2), 0, 0x3, 1);
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 1), 0, 0x3, 1);
+
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+
+ WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, VGA_MASTER,
+ state->vga_master[core]);
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ WRITE_RADIO_REG2(pi, RADIO_2056, RX, core,
+ TXFBMIX_G, state->fbmix[core]);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAG_MASTER,
+ state->intpa_master[core]);
+ } else {
+ WRITE_RADIO_REG2(pi, RADIO_2056, RX, core,
+ TXFBMIX_A, state->fbmix[core]);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAA_MASTER,
+ state->intpa_master[core]);
+ }
+
+ write_phy_reg(pi, (core == PHY_CORE_0) ?
+ 0xa6 : 0xa7, state->afectrl[core]);
+ write_phy_reg(pi, (core == PHY_CORE_0) ? 0x8f :
+ 0xa5, state->afeoverride[core]);
+ }
+
+ wlc_phy_ipa_set_bbmult_nphy(pi, (state->mm >> 8) & 0xff,
+ (state->mm & 0xff));
+
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 0, 0x3, 1);
+ }
+}
+
+static void
+wlc_phy_a1_nphy(struct brcms_phy *pi, u8 core, u32 winsz, u32 start,
+ u32 end)
+{
+ u32 *buf, *src, *dst, sz;
+
+ sz = end - start + 1;
+
+ buf = kmalloc(2 * sizeof(u32) * NPHY_PAPD_EPS_TBL_SIZE, GFP_ATOMIC);
+ if (NULL == buf)
+ return;
+
+ src = buf;
+ dst = buf + NPHY_PAPD_EPS_TBL_SIZE;
+
+ wlc_phy_table_read_nphy(pi,
+ (core ==
+ PHY_CORE_0 ? NPHY_TBL_ID_EPSILONTBL0 :
+ NPHY_TBL_ID_EPSILONTBL1),
+ NPHY_PAPD_EPS_TBL_SIZE, 0, 32, src);
+
+ do {
+ u32 phy_a1, phy_a2;
+ s32 phy_a3, phy_a4, phy_a5, phy_a6, phy_a7;
+
+ phy_a1 = end - min(end, (winsz >> 1));
+ phy_a2 = min_t(u32, NPHY_PAPD_EPS_TBL_SIZE - 1,
+ end + (winsz >> 1));
+ phy_a3 = phy_a2 - phy_a1 + 1;
+ phy_a6 = 0;
+ phy_a7 = 0;
+
+ do {
+ wlc_phy_papd_decode_epsilon(src[phy_a2], &phy_a4,
+ &phy_a5);
+ phy_a6 += phy_a4;
+ phy_a7 += phy_a5;
+ } while (phy_a2-- != phy_a1);
+
+ phy_a6 /= phy_a3;
+ phy_a7 /= phy_a3;
+ dst[end] = ((u32) phy_a7 << 13) | ((u32) phy_a6 & 0x1fff);
+ } while (end-- != start);
+
+ wlc_phy_table_write_nphy(pi,
+ (core ==
+ PHY_CORE_0) ? NPHY_TBL_ID_EPSILONTBL0 :
+ NPHY_TBL_ID_EPSILONTBL1, sz, start, 32, dst);
+
+ kfree(buf);
+}
+
+static void
+wlc_phy_a2_nphy(struct brcms_phy *pi, struct nphy_ipa_txcalgains *txgains,
+ enum phy_cal_mode cal_mode, u8 core)
+{
+ u16 phy_a1, phy_a2, phy_a3;
+ u16 phy_a4, phy_a5;
+ bool phy_a6;
+ u8 phy_a7, m[2];
+ u32 phy_a8 = 0;
+ struct nphy_txgains phy_a9;
+
+ if (NREV_LT(pi->pubpi.phy_rev, 3))
+ return;
+
+ phy_a7 = (core == PHY_CORE_0) ? 1 : 0;
+
+ phy_a6 = ((cal_mode == CAL_GCTRL)
+ || (cal_mode == CAL_SOFT)) ? true : false;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ phy_a9 = wlc_phy_get_tx_gain_nphy(pi);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ phy_a5 = ((phy_a9.txlpf[core] << 15) |
+ (phy_a9.txgm[core] << 12) |
+ (phy_a9.pga[core] << 8) |
+ (txgains->gains.pad[core] << 3) |
+ (phy_a9.ipa[core]));
+ else
+ phy_a5 = ((phy_a9.txlpf[core] << 15) |
+ (phy_a9.txgm[core] << 12) |
+ (txgains->gains.pga[core] << 8) |
+ (phy_a9.pad[core] << 3) | (phy_a9.ipa[core]));
+
+ wlc_phy_rfctrl_override_1tomany_nphy(
+ pi,
+ NPHY_REV7_RfctrlOverride_cmd_txgain,
+ phy_a5, (1 << core), 0);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if ((pi->pubpi.radiorev <= 4)
+ || (pi->pubpi.radiorev == 6))
+ m[core] = (pi->bw == WL_CHANSPEC_BW_40) ?
+ 60 : 79;
+ else
+ m[core] = (pi->bw == WL_CHANSPEC_BW_40) ?
+ 45 : 64;
+ } else {
+ m[core] = (pi->bw == WL_CHANSPEC_BW_40) ? 75 : 107;
+ }
+
+ m[phy_a7] = 0;
+ wlc_phy_ipa_set_bbmult_nphy(pi, m[0], m[1]);
+
+ phy_a2 = 63;
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if ((pi->pubpi.radiorev == 4)
+ || (pi->pubpi.radiorev == 6)) {
+ phy_a1 = 30;
+ phy_a3 = 30;
+ } else {
+ phy_a1 = 25;
+ phy_a3 = 25;
+ }
+ } else {
+ if ((pi->pubpi.radiorev == 5)
+ || (pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8)) {
+ phy_a1 = 25;
+ phy_a3 = 25;
+ } else {
+ phy_a1 = 35;
+ phy_a3 = 35;
+ }
+ }
+
+ if (cal_mode == CAL_GCTRL) {
+ if ((pi->pubpi.radiorev == 5)
+ && (CHSPEC_IS2G(pi->radio_chanspec)))
+ phy_a1 = 55;
+ else if (((pi->pubpi.radiorev == 7) &&
+ (CHSPEC_IS2G(pi->radio_chanspec))) ||
+ ((pi->pubpi.radiorev == 8) &&
+ (CHSPEC_IS2G(pi->radio_chanspec))))
+ phy_a1 = 60;
+ else
+ phy_a1 = 63;
+
+ } else if ((cal_mode != CAL_FULL) && (cal_mode != CAL_SOFT)) {
+
+ phy_a1 = 35;
+ phy_a3 = 35;
+ }
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (1) << 0);
+
+ mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (0) << 0);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 13), (1) << 13);
+
+ mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 13), (0) << 13);
+
+ write_phy_reg(pi, 0x2a1, 0x80);
+ write_phy_reg(pi, 0x2a2, 0x100);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x7 << 4), (11) << 4);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x7 << 8), (11) << 8);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x7 << 0), (0x3) << 0);
+
+ write_phy_reg(pi, 0x2e5, 0x20);
+
+ mod_phy_reg(pi, 0x2a0, (0x3f << 0), (phy_a3) << 0);
+
+ mod_phy_reg(pi, 0x29f, (0x3f << 0), (phy_a1) << 0);
+
+ mod_phy_reg(pi, 0x29f, (0x3f << 8), (phy_a2) << 8);
+
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3),
+ 1, ((core == 0) ? 1 : 2), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3),
+ 0, ((core == 0) ? 2 : 1), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+
+ write_phy_reg(pi, 0x2be, 1);
+ SPINWAIT(read_phy_reg(pi, 0x2be), 10 * 1000 * 1000);
+
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3),
+ 0, 0x3, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+
+ wlc_phy_table_write_nphy(pi,
+ (core ==
+ PHY_CORE_0) ? NPHY_TBL_ID_EPSILONTBL0
+ : NPHY_TBL_ID_EPSILONTBL1, 1, phy_a3,
+ 32, &phy_a8);
+
+ if (cal_mode != CAL_GCTRL) {
+ if (CHSPEC_IS5G(pi->radio_chanspec))
+ wlc_phy_a1_nphy(pi, core, 5, 0, 35);
+ }
+
+ wlc_phy_rfctrl_override_1tomany_nphy(
+ pi,
+ NPHY_REV7_RfctrlOverride_cmd_txgain,
+ phy_a5, (1 << core), 1);
+
+ } else {
+
+ if (txgains) {
+ if (txgains->useindex) {
+ phy_a4 = 15 - ((txgains->index) >> 3);
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 6))
+ phy_a5 = 0x00f7 | (phy_a4 << 8);
+
+ else
+ if (NREV_IS(pi->pubpi.phy_rev, 5))
+ phy_a5 = 0x10f7 | (phy_a4 << 8);
+ else
+ phy_a5 = 0x50f7 | (phy_a4 << 8);
+ } else {
+ phy_a5 = 0x70f7 | (phy_a4 << 8);
+ }
+ wlc_phy_rfctrl_override_nphy(pi,
+ (0x1 << 13),
+ phy_a5,
+ (1 << core), 0);
+ } else {
+ wlc_phy_rfctrl_override_nphy(pi,
+ (0x1 << 13),
+ 0x5bf7,
+ (1 << core), 0);
+ }
+ }
+
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ m[core] = (pi->bw == WL_CHANSPEC_BW_40) ? 45 : 64;
+ else
+ m[core] = (pi->bw == WL_CHANSPEC_BW_40) ? 75 : 107;
+
+ m[phy_a7] = 0;
+ wlc_phy_ipa_set_bbmult_nphy(pi, m[0], m[1]);
+
+ phy_a2 = 63;
+
+ if (cal_mode == CAL_FULL) {
+ phy_a1 = 25;
+ phy_a3 = 25;
+ } else if (cal_mode == CAL_SOFT) {
+ phy_a1 = 25;
+ phy_a3 = 25;
+ } else if (cal_mode == CAL_GCTRL) {
+ phy_a1 = 63;
+ phy_a3 = 25;
+ } else {
+
+ phy_a1 = 25;
+ phy_a3 = 25;
+ }
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (1) << 0);
+
+ mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (0) << 0);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 6)) {
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 13), (1) << 13);
+
+ mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 13), (0) << 13);
+
+ write_phy_reg(pi, 0x2a1, 0x20);
+ write_phy_reg(pi, 0x2a2, 0x60);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0xf << 4), (9) << 4);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0xf << 8), (9) << 8);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0xf << 0), (0x2) << 0);
+
+ write_phy_reg(pi, 0x2e5, 0x20);
+ } else {
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 11), (1) << 11);
+
+ mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 11), (0) << 11);
+
+ write_phy_reg(pi, 0x2a1, 0x80);
+ write_phy_reg(pi, 0x2a2, 0x600);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x7 << 4), (0) << 4);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x7 << 8), (0) << 8);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x7 << 0), (0x3) << 0);
+
+ mod_phy_reg(pi, 0x2a0, (0x3f << 8), (0x20) << 8);
+
+ }
+
+ mod_phy_reg(pi, 0x2a0, (0x3f << 0), (phy_a3) << 0);
+
+ mod_phy_reg(pi, 0x29f, (0x3f << 0), (phy_a1) << 0);
+
+ mod_phy_reg(pi, 0x29f, (0x3f << 8), (phy_a2) << 8);
+
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 1, 0x3, 0);
+
+ write_phy_reg(pi, 0x2be, 1);
+ SPINWAIT(read_phy_reg(pi, 0x2be), 10 * 1000 * 1000);
+
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 0, 0x3, 0);
+
+ wlc_phy_table_write_nphy(pi,
+ (core ==
+ PHY_CORE_0) ? NPHY_TBL_ID_EPSILONTBL0
+ : NPHY_TBL_ID_EPSILONTBL1, 1, phy_a3,
+ 32, &phy_a8);
+
+ if (cal_mode != CAL_GCTRL)
+ wlc_phy_a1_nphy(pi, core, 5, 0, 40);
+ }
+}
+
+static u8 wlc_phy_a3_nphy(struct brcms_phy *pi, u8 start_gain, u8 core)
+{
+ int phy_a1;
+ int phy_a2;
+ bool phy_a3;
+ struct nphy_ipa_txcalgains phy_a4;
+ bool phy_a5 = false;
+ bool phy_a6 = true;
+ s32 phy_a7, phy_a8;
+ u32 phy_a9;
+ int phy_a10;
+ bool phy_a11 = false;
+ int phy_a12;
+ u8 phy_a13 = 0;
+ u8 phy_a14;
+ u8 *phy_a15 = NULL;
+
+ phy_a4.useindex = true;
+ phy_a12 = start_gain;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ phy_a2 = 20;
+ phy_a1 = 1;
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if (pi->pubpi.radiorev == 5) {
+
+ phy_a15 = pad_gain_codes_used_2057rev5;
+ phy_a13 =
+ sizeof(pad_gain_codes_used_2057rev5) /
+ sizeof(pad_gain_codes_used_2057rev5
+ [0]) - 1;
+
+ } else if ((pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8)) {
+
+ phy_a15 = pad_gain_codes_used_2057rev7;
+ phy_a13 =
+ sizeof(pad_gain_codes_used_2057rev7) /
+ sizeof(pad_gain_codes_used_2057rev7
+ [0]) - 1;
+
+ } else {
+
+ phy_a15 = pad_all_gain_codes_2057;
+ phy_a13 = sizeof(pad_all_gain_codes_2057) /
+ sizeof(pad_all_gain_codes_2057[0]) -
+ 1;
+ }
+
+ } else {
+
+ phy_a15 = pga_all_gain_codes_2057;
+ phy_a13 = sizeof(pga_all_gain_codes_2057) /
+ sizeof(pga_all_gain_codes_2057[0]) - 1;
+ }
+
+ phy_a14 = 0;
+
+ for (phy_a10 = 0; phy_a10 < phy_a2; phy_a10++) {
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ phy_a4.gains.pad[core] =
+ (u16) phy_a15[phy_a12];
+ else
+ phy_a4.gains.pga[core] =
+ (u16) phy_a15[phy_a12];
+
+ wlc_phy_a2_nphy(pi, &phy_a4, CAL_GCTRL, core);
+
+ wlc_phy_table_read_nphy(pi,
+ (core ==
+ PHY_CORE_0 ?
+ NPHY_TBL_ID_EPSILONTBL0 :
+ NPHY_TBL_ID_EPSILONTBL1), 1,
+ 63, 32, &phy_a9);
+
+ wlc_phy_papd_decode_epsilon(phy_a9, &phy_a7, &phy_a8);
+
+ phy_a3 = ((phy_a7 == 4095) || (phy_a7 == -4096) ||
+ (phy_a8 == 4095) || (phy_a8 == -4096));
+
+ if (!phy_a6 && (phy_a3 != phy_a5)) {
+ if (!phy_a3)
+ phy_a12 -= (u8) phy_a1;
+
+ phy_a11 = true;
+ break;
+ }
+
+ if (phy_a3)
+ phy_a12 += (u8) phy_a1;
+ else
+ phy_a12 -= (u8) phy_a1;
+
+ if ((phy_a12 < phy_a14) || (phy_a12 > phy_a13)) {
+ if (phy_a12 < phy_a14)
+ phy_a12 = phy_a14;
+ else
+ phy_a12 = phy_a13;
+
+ phy_a11 = true;
+ break;
+ }
+
+ phy_a6 = false;
+ phy_a5 = phy_a3;
+ }
+
+ } else {
+ phy_a2 = 10;
+ phy_a1 = 8;
+ for (phy_a10 = 0; phy_a10 < phy_a2; phy_a10++) {
+ phy_a4.index = (u8) phy_a12;
+ wlc_phy_a2_nphy(pi, &phy_a4, CAL_GCTRL, core);
+
+ wlc_phy_table_read_nphy(pi,
+ (core ==
+ PHY_CORE_0 ?
+ NPHY_TBL_ID_EPSILONTBL0 :
+ NPHY_TBL_ID_EPSILONTBL1), 1,
+ 63, 32, &phy_a9);
+
+ wlc_phy_papd_decode_epsilon(phy_a9, &phy_a7, &phy_a8);
+
+ phy_a3 = ((phy_a7 == 4095) || (phy_a7 == -4096) ||
+ (phy_a8 == 4095) || (phy_a8 == -4096));
+
+ if (!phy_a6 && (phy_a3 != phy_a5)) {
+ if (!phy_a3)
+ phy_a12 -= (u8) phy_a1;
+
+ phy_a11 = true;
+ break;
+ }
+
+ if (phy_a3)
+ phy_a12 += (u8) phy_a1;
+ else
+ phy_a12 -= (u8) phy_a1;
+
+ if ((phy_a12 < 0) || (phy_a12 > 127)) {
+ if (phy_a12 < 0)
+ phy_a12 = 0;
+ else
+ phy_a12 = 127;
+
+ phy_a11 = true;
+ break;
+ }
+
+ phy_a6 = false;
+ phy_a5 = phy_a3;
+ }
+
+ }
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ return (u8) phy_a15[phy_a12];
+ else
+ return (u8) phy_a12;
+
+}
+
+static void wlc_phy_a4(struct brcms_phy *pi, bool full_cal)
+{
+ struct nphy_ipa_txcalgains phy_b1[2];
+ struct nphy_papd_restore_state phy_b2;
+ bool phy_b3;
+ u8 phy_b4;
+ u8 phy_b5;
+ s16 phy_b6, phy_b7, phy_b8;
+ u16 phy_b9;
+ s16 phy_b10, phy_b11, phy_b12;
+
+ phy_b11 = 0;
+ phy_b12 = 0;
+ phy_b7 = 0;
+ phy_b8 = 0;
+ phy_b6 = 0;
+
+ if (pi->nphy_papd_skip == 1)
+ return;
+
+ phy_b3 = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
+ if (!phy_b3)
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ pi->nphy_force_papd_cal = false;
+
+ for (phy_b5 = 0; phy_b5 < pi->pubpi.phy_corenum; phy_b5++)
+ pi->nphy_papd_tx_gain_at_last_cal[phy_b5] =
+ wlc_phy_txpwr_idx_cur_get_nphy(pi, phy_b5);
+
+ pi->nphy_papd_last_cal = pi->sh->now;
+ pi->nphy_papd_recal_counter++;
+
+ phy_b4 = pi->nphy_txpwrctrl;
+ wlc_phy_txpwrctrl_enable_nphy(pi, PHY_TPC_HW_OFF);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_SCALARTBL0, 64, 0, 32,
+ nphy_papd_scaltbl);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_SCALARTBL1, 64, 0, 32,
+ nphy_papd_scaltbl);
+
+ phy_b9 = read_phy_reg(pi, 0x01);
+ mod_phy_reg(pi, 0x01, (0x1 << 15), 0);
+
+ for (phy_b5 = 0; phy_b5 < pi->pubpi.phy_corenum; phy_b5++) {
+ s32 i, val = 0;
+ for (i = 0; i < 64; i++)
+ wlc_phy_table_write_nphy(pi,
+ ((phy_b5 ==
+ PHY_CORE_0) ?
+ NPHY_TBL_ID_EPSILONTBL0 :
+ NPHY_TBL_ID_EPSILONTBL1), 1,
+ i, 32, &val);
+ }
+
+ wlc_phy_ipa_restore_tx_digi_filts_nphy(pi);
+
+ phy_b2.mm = wlc_phy_ipa_get_bbmult_nphy(pi);
+ for (phy_b5 = 0; phy_b5 < pi->pubpi.phy_corenum; phy_b5++) {
+ wlc_phy_papd_cal_setup_nphy(pi, &phy_b2, phy_b5);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if ((pi->pubpi.radiorev == 3)
+ || (pi->pubpi.radiorev == 4)
+ || (pi->pubpi.radiorev == 6)) {
+ pi->nphy_papd_cal_gain_index[phy_b5] =
+ 23;
+ } else if (pi->pubpi.radiorev == 5) {
+ pi->nphy_papd_cal_gain_index[phy_b5] =
+ 0;
+ pi->nphy_papd_cal_gain_index[phy_b5] =
+ wlc_phy_a3_nphy(
+ pi,
+ pi->
+ nphy_papd_cal_gain_index
+ [phy_b5],
+ phy_b5);
+
+ } else if ((pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8)) {
+
+ pi->nphy_papd_cal_gain_index[phy_b5] =
+ 0;
+ pi->nphy_papd_cal_gain_index[phy_b5] =
+ wlc_phy_a3_nphy(
+ pi,
+ pi->
+ nphy_papd_cal_gain_index
+ [phy_b5],
+ phy_b5);
+
+ }
+
+ phy_b1[phy_b5].gains.pad[phy_b5] =
+ pi->nphy_papd_cal_gain_index[phy_b5];
+
+ } else {
+ pi->nphy_papd_cal_gain_index[phy_b5] = 0;
+ pi->nphy_papd_cal_gain_index[phy_b5] =
+ wlc_phy_a3_nphy(
+ pi,
+ pi->
+ nphy_papd_cal_gain_index
+ [phy_b5], phy_b5);
+ phy_b1[phy_b5].gains.pga[phy_b5] =
+ pi->nphy_papd_cal_gain_index[phy_b5];
+ }
+ } else {
+ phy_b1[phy_b5].useindex = true;
+ phy_b1[phy_b5].index = 16;
+ phy_b1[phy_b5].index =
+ wlc_phy_a3_nphy(pi, phy_b1[phy_b5].index,
+ phy_b5);
+
+ pi->nphy_papd_cal_gain_index[phy_b5] =
+ 15 - ((phy_b1[phy_b5].index) >> 3);
+ }
+
+ switch (pi->nphy_papd_cal_type) {
+ case 0:
+ wlc_phy_a2_nphy(pi, &phy_b1[phy_b5], CAL_FULL, phy_b5);
+ break;
+ case 1:
+ wlc_phy_a2_nphy(pi, &phy_b1[phy_b5], CAL_SOFT, phy_b5);
+ break;
+ }
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ wlc_phy_papd_cal_cleanup_nphy(pi, &phy_b2);
+ }
+
+ if (NREV_LT(pi->pubpi.phy_rev, 7))
+ wlc_phy_papd_cal_cleanup_nphy(pi, &phy_b2);
+
+ for (phy_b5 = 0; phy_b5 < pi->pubpi.phy_corenum; phy_b5++) {
+ int eps_offset = 0;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if (pi->pubpi.radiorev == 3)
+ eps_offset = -2;
+ else if (pi->pubpi.radiorev == 5)
+ eps_offset = 3;
+ else
+ eps_offset = -1;
+ } else {
+ eps_offset = 2;
+ }
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ phy_b8 = phy_b1[phy_b5].gains.pad[phy_b5];
+ phy_b10 = 0;
+ if ((pi->pubpi.radiorev == 3) ||
+ (pi->pubpi.radiorev == 4) ||
+ (pi->pubpi.radiorev == 6)) {
+ phy_b12 = -(
+ nphy_papd_padgain_dlt_2g_2057rev3n4
+ [phy_b8] + 1) / 2;
+ phy_b10 = -1;
+ } else if (pi->pubpi.radiorev == 5) {
+ phy_b12 = -(
+ nphy_papd_padgain_dlt_2g_2057rev5
+ [phy_b8] + 1) / 2;
+ } else if ((pi->pubpi.radiorev == 7) ||
+ (pi->pubpi.radiorev == 8)) {
+ phy_b12 = -(
+ nphy_papd_padgain_dlt_2g_2057rev7
+ [phy_b8] + 1) / 2;
+ }
+ } else {
+ phy_b7 = phy_b1[phy_b5].gains.pga[phy_b5];
+ if ((pi->pubpi.radiorev == 3) ||
+ (pi->pubpi.radiorev == 4) ||
+ (pi->pubpi.radiorev == 6))
+ phy_b11 =
+ -(nphy_papd_pgagain_dlt_5g_2057
+ [phy_b7]
+ + 1) / 2;
+ else if ((pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8))
+ phy_b11 = -(
+ nphy_papd_pgagain_dlt_5g_2057rev7
+ [phy_b7] + 1) / 2;
+
+ phy_b10 = -9;
+ }
+
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ phy_b6 =
+ -60 + 27 + eps_offset + phy_b12 +
+ phy_b10;
+ else
+ phy_b6 =
+ -60 + 27 + eps_offset + phy_b11 +
+ phy_b10;
+
+ mod_phy_reg(pi, (phy_b5 == PHY_CORE_0) ? 0x298 :
+ 0x29c, (0x1ff << 7), (phy_b6) << 7);
+
+ pi->nphy_papd_epsilon_offset[phy_b5] = phy_b6;
+ } else {
+ if (NREV_LT(pi->pubpi.phy_rev, 5))
+ eps_offset = 4;
+ else
+ eps_offset = 2;
+
+ phy_b7 = 15 - ((phy_b1[phy_b5].index) >> 3);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ phy_b11 =
+ -(nphy_papd_pga_gain_delta_ipa_2g[
+ phy_b7] +
+ 1) / 2;
+ phy_b10 = 0;
+ } else {
+ phy_b11 =
+ -(nphy_papd_pga_gain_delta_ipa_5g[
+ phy_b7] +
+ 1) / 2;
+ phy_b10 = -9;
+ }
+
+ phy_b6 = -60 + 27 + eps_offset + phy_b11 + phy_b10;
+
+ mod_phy_reg(pi, (phy_b5 == PHY_CORE_0) ? 0x298 :
+ 0x29c, (0x1ff << 7), (phy_b6) << 7);
+
+ pi->nphy_papd_epsilon_offset[phy_b5] = phy_b6;
+ }
+ }
+
+ mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (NPHY_PAPD_COMP_ON) << 0);
+
+ mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (NPHY_PAPD_COMP_ON) << 0);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 6)) {
+ mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 13), (0) << 13);
+
+ mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 13), (0) << 13);
+
+ } else {
+ mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 11), (0) << 11);
+
+ mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 11), (0) << 11);
+
+ }
+ pi->nphy_papdcomp = NPHY_PAPD_COMP_ON;
+
+ write_phy_reg(pi, 0x01, phy_b9);
+
+ wlc_phy_ipa_set_tx_digi_filts_nphy(pi);
+
+ wlc_phy_txpwrctrl_enable_nphy(pi, phy_b4);
+ if (phy_b4 == PHY_TPC_HW_OFF) {
+ wlc_phy_txpwr_index_nphy(pi, (1 << 0),
+ (s8) (pi->nphy_txpwrindex[0].
+ index_internal), false);
+ wlc_phy_txpwr_index_nphy(pi, (1 << 1),
+ (s8) (pi->nphy_txpwrindex[1].
+ index_internal), false);
+ }
+
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+
+ if (!phy_b3)
+ wlapi_enable_mac(pi->sh->physhim);
+}
+
+void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype)
+{
+ struct nphy_txgains target_gain;
+ u8 tx_pwr_ctrl_state;
+ bool fullcal = true;
+ bool restore_tx_gain = false;
+ bool mphase;
+
+ if (PHY_MUTED(pi))
+ return;
+
+ if (caltype == PHY_PERICAL_AUTO)
+ fullcal = (pi->radio_chanspec != pi->nphy_txiqlocal_chanspec);
+ else if (caltype == PHY_PERICAL_PARTIAL)
+ fullcal = false;
+
+ if (pi->cal_type_override != PHY_PERICAL_AUTO)
+ fullcal =
+ (pi->cal_type_override ==
+ PHY_PERICAL_FULL) ? true : false;
+
+ if ((pi->mphase_cal_phase_id > MPHASE_CAL_STATE_INIT)) {
+ if (pi->nphy_txiqlocal_chanspec != pi->radio_chanspec)
+ wlc_phy_cal_perical_mphase_restart(pi);
+ }
+
+ if ((pi->mphase_cal_phase_id == MPHASE_CAL_STATE_RXCAL))
+ wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000);
+
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+
+ wlc_phyreg_enter((struct brcms_phy_pub *) pi);
+
+ if ((pi->mphase_cal_phase_id == MPHASE_CAL_STATE_IDLE) ||
+ (pi->mphase_cal_phase_id == MPHASE_CAL_STATE_INIT)) {
+ pi->nphy_cal_orig_pwr_idx[0] =
+ (u8) ((read_phy_reg(pi, 0x1ed) >> 8) & 0x7f);
+ pi->nphy_cal_orig_pwr_idx[1] =
+ (u8) ((read_phy_reg(pi, 0x1ee) >> 8) & 0x7f);
+
+ if (pi->nphy_txpwrctrl != PHY_TPC_HW_OFF) {
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2,
+ 0x110, 16,
+ pi->nphy_cal_orig_tx_gain);
+ } else {
+ pi->nphy_cal_orig_tx_gain[0] = 0;
+ pi->nphy_cal_orig_tx_gain[1] = 0;
+ }
+ }
+ target_gain = wlc_phy_get_tx_gain_nphy(pi);
+ tx_pwr_ctrl_state = pi->nphy_txpwrctrl;
+ wlc_phy_txpwrctrl_enable_nphy(pi, PHY_TPC_HW_OFF);
+
+ if (pi->antsel_type == ANTSEL_2x3)
+ wlc_phy_antsel_init((struct brcms_phy_pub *) pi, true);
+
+ mphase = (pi->mphase_cal_phase_id != MPHASE_CAL_STATE_IDLE);
+ if (!mphase) {
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ wlc_phy_precal_txgain_nphy(pi);
+ pi->nphy_cal_target_gain = wlc_phy_get_tx_gain_nphy(pi);
+ restore_tx_gain = true;
+
+ target_gain = pi->nphy_cal_target_gain;
+ }
+ if (0 ==
+ wlc_phy_cal_txiqlo_nphy(pi, target_gain, fullcal,
+ mphase)) {
+ if (PHY_IPA(pi))
+ wlc_phy_a4(pi, true);
+
+ wlc_phyreg_exit((struct brcms_phy_pub *) pi);
+ wlapi_enable_mac(pi->sh->physhim);
+ wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION,
+ 10000);
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+ wlc_phyreg_enter((struct brcms_phy_pub *) pi);
+
+ if (0 == wlc_phy_cal_rxiq_nphy(pi, target_gain,
+ (pi->first_cal_after_assoc ||
+ (pi->cal_type_override ==
+ PHY_PERICAL_FULL)) ? 2 : 0, false)) {
+ wlc_phy_savecal_nphy(pi);
+
+ wlc_phy_txpwrctrl_coeff_setup_nphy(pi);
+
+ pi->nphy_perical_last = pi->sh->now;
+ }
+ }
+ if (caltype != PHY_PERICAL_AUTO)
+ wlc_phy_rssi_cal_nphy(pi);
+
+ if (pi->first_cal_after_assoc
+ || (pi->cal_type_override == PHY_PERICAL_FULL)) {
+ pi->first_cal_after_assoc = false;
+ wlc_phy_txpwrctrl_idle_tssi_nphy(pi);
+ wlc_phy_txpwrctrl_pwr_setup_nphy(pi);
+ }
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
+ wlc_phy_radio205x_vcocal_nphy(pi);
+ } else {
+ switch (pi->mphase_cal_phase_id) {
+ case MPHASE_CAL_STATE_INIT:
+ pi->nphy_perical_last = pi->sh->now;
+ pi->nphy_txiqlocal_chanspec = pi->radio_chanspec;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
+ wlc_phy_precal_txgain_nphy(pi);
+
+ pi->nphy_cal_target_gain = wlc_phy_get_tx_gain_nphy(pi);
+ pi->mphase_cal_phase_id++;
+ break;
+
+ case MPHASE_CAL_STATE_TXPHASE0:
+ case MPHASE_CAL_STATE_TXPHASE1:
+ case MPHASE_CAL_STATE_TXPHASE2:
+ case MPHASE_CAL_STATE_TXPHASE3:
+ case MPHASE_CAL_STATE_TXPHASE4:
+ case MPHASE_CAL_STATE_TXPHASE5:
+ if ((pi->radar_percal_mask & 0x10) != 0)
+ pi->nphy_rxcal_active = true;
+
+ if (wlc_phy_cal_txiqlo_nphy
+ (pi, pi->nphy_cal_target_gain, fullcal,
+ true) != 0) {
+
+ wlc_phy_cal_perical_mphase_reset(pi);
+ break;
+ }
+
+ if (NREV_LE(pi->pubpi.phy_rev, 2) &&
+ (pi->mphase_cal_phase_id ==
+ MPHASE_CAL_STATE_TXPHASE4))
+ pi->mphase_cal_phase_id += 2;
+ else
+ pi->mphase_cal_phase_id++;
+ break;
+
+ case MPHASE_CAL_STATE_PAPDCAL:
+ if ((pi->radar_percal_mask & 0x2) != 0)
+ pi->nphy_rxcal_active = true;
+
+ if (PHY_IPA(pi))
+ wlc_phy_a4(pi, true);
+
+ pi->mphase_cal_phase_id++;
+ break;
+
+ case MPHASE_CAL_STATE_RXCAL:
+ if ((pi->radar_percal_mask & 0x1) != 0)
+ pi->nphy_rxcal_active = true;
+ if (wlc_phy_cal_rxiq_nphy(pi, target_gain,
+ (pi->first_cal_after_assoc ||
+ (pi->cal_type_override ==
+ PHY_PERICAL_FULL)) ? 2 : 0,
+ false) == 0)
+ wlc_phy_savecal_nphy(pi);
+
+ pi->mphase_cal_phase_id++;
+ break;
+
+ case MPHASE_CAL_STATE_RSSICAL:
+ if ((pi->radar_percal_mask & 0x4) != 0)
+ pi->nphy_rxcal_active = true;
+ wlc_phy_txpwrctrl_coeff_setup_nphy(pi);
+ wlc_phy_rssi_cal_nphy(pi);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
+ wlc_phy_radio205x_vcocal_nphy(pi);
+
+ restore_tx_gain = true;
+
+ if (pi->first_cal_after_assoc)
+ pi->mphase_cal_phase_id++;
+ else
+ wlc_phy_cal_perical_mphase_reset(pi);
+
+ break;
+
+ case MPHASE_CAL_STATE_IDLETSSI:
+ if ((pi->radar_percal_mask & 0x8) != 0)
+ pi->nphy_rxcal_active = true;
+
+ if (pi->first_cal_after_assoc) {
+ pi->first_cal_after_assoc = false;
+ wlc_phy_txpwrctrl_idle_tssi_nphy(pi);
+ wlc_phy_txpwrctrl_pwr_setup_nphy(pi);
+ }
+
+ wlc_phy_cal_perical_mphase_reset(pi);
+ break;
+
+ default:
+ wlc_phy_cal_perical_mphase_reset(pi);
+ break;
+ }
+ }
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ if (restore_tx_gain) {
+ if (tx_pwr_ctrl_state != PHY_TPC_HW_OFF) {
+
+ wlc_phy_txpwr_index_nphy(pi, 1,
+ pi->
+ nphy_cal_orig_pwr_idx
+ [0], false);
+ wlc_phy_txpwr_index_nphy(pi, 2,
+ pi->
+ nphy_cal_orig_pwr_idx
+ [1], false);
+
+ pi->nphy_txpwrindex[0].index = -1;
+ pi->nphy_txpwrindex[1].index = -1;
+ } else {
+ wlc_phy_txpwr_index_nphy(pi, (1 << 0),
+ (s8) (pi->
+ nphy_txpwrindex
+ [0].
+ index_internal),
+ false);
+ wlc_phy_txpwr_index_nphy(pi, (1 << 1),
+ (s8) (pi->
+ nphy_txpwrindex
+ [1].
+ index_internal),
+ false);
+ }
+ }
+ }
+
+ wlc_phy_txpwrctrl_enable_nphy(pi, tx_pwr_ctrl_state);
+ wlc_phyreg_exit((struct brcms_phy_pub *) pi);
+ wlapi_enable_mac(pi->sh->physhim);
+}
+
+int
+wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain,
+ bool fullcal, bool mphase)
+{
+ u16 val;
+ u16 tbl_buf[11];
+ u8 cal_cnt;
+ u16 cal_cmd;
+ u8 num_cals, max_cal_cmds;
+ u16 core_no, cal_type;
+ u16 diq_start = 0;
+ u8 phy_bw;
+ u16 max_val;
+ u16 tone_freq;
+ u16 gain_save[2];
+ u16 cal_gain[2];
+ struct nphy_iqcal_params cal_params[2];
+ u32 tbl_len;
+ void *tbl_ptr;
+ bool ladder_updated[2];
+ u8 mphase_cal_lastphase = 0;
+ int bcmerror = 0;
+ bool phyhang_avoid_state = false;
+
+ u16 tbl_tx_iqlo_cal_loft_ladder_20[] = {
+ 0x0300, 0x0500, 0x0700, 0x0900, 0x0d00, 0x1100, 0x1900, 0x1901,
+ 0x1902,
+ 0x1903, 0x1904, 0x1905, 0x1906, 0x1907, 0x2407, 0x3207, 0x4607,
+ 0x6407
+ };
+
+ u16 tbl_tx_iqlo_cal_iqimb_ladder_20[] = {
+ 0x0200, 0x0300, 0x0600, 0x0900, 0x0d00, 0x1100, 0x1900, 0x2400,
+ 0x3200,
+ 0x4600, 0x6400, 0x6401, 0x6402, 0x6403, 0x6404, 0x6405, 0x6406,
+ 0x6407
+ };
+
+ u16 tbl_tx_iqlo_cal_loft_ladder_40[] = {
+ 0x0200, 0x0300, 0x0400, 0x0700, 0x0900, 0x0c00, 0x1200, 0x1201,
+ 0x1202,
+ 0x1203, 0x1204, 0x1205, 0x1206, 0x1207, 0x1907, 0x2307, 0x3207,
+ 0x4707
+ };
+
+ u16 tbl_tx_iqlo_cal_iqimb_ladder_40[] = {
+ 0x0100, 0x0200, 0x0400, 0x0700, 0x0900, 0x0c00, 0x1200, 0x1900,
+ 0x2300,
+ 0x3200, 0x4700, 0x4701, 0x4702, 0x4703, 0x4704, 0x4705, 0x4706,
+ 0x4707
+ };
+
+ u16 tbl_tx_iqlo_cal_startcoefs[] = {
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000
+ };
+
+ u16 tbl_tx_iqlo_cal_cmds_fullcal[] = {
+ 0x8123, 0x8264, 0x8086, 0x8245, 0x8056,
+ 0x9123, 0x9264, 0x9086, 0x9245, 0x9056
+ };
+
+ u16 tbl_tx_iqlo_cal_cmds_recal[] = {
+ 0x8101, 0x8253, 0x8053, 0x8234, 0x8034,
+ 0x9101, 0x9253, 0x9053, 0x9234, 0x9034
+ };
+
+ u16 tbl_tx_iqlo_cal_startcoefs_nphyrev3[] = {
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000
+ };
+
+ u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[] = {
+ 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234,
+ 0x9434, 0x9334, 0x9084, 0x9267, 0x9056, 0x9234
+ };
+
+ u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[] = {
+ 0x8423, 0x8323, 0x8073, 0x8256, 0x8045, 0x8223,
+ 0x9423, 0x9323, 0x9073, 0x9256, 0x9045, 0x9223
+ };
+
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 4)) {
+ phyhang_avoid_state = pi->phyhang_avoid;
+ pi->phyhang_avoid = false;
+ }
+
+ if (CHSPEC_IS40(pi->radio_chanspec))
+ phy_bw = 40;
+ else
+ phy_bw = 20;
+
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, gain_save);
+
+ for (core_no = 0; core_no <= 1; core_no++) {
+ wlc_phy_iqcal_gainparams_nphy(pi, core_no, target_gain,
+ &cal_params[core_no]);
+ cal_gain[core_no] = cal_params[core_no].cal_gain;
+ }
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, cal_gain);
+
+ wlc_phy_txcal_radio_setup_nphy(pi);
+
+ wlc_phy_txcal_physetup_nphy(pi);
+
+ ladder_updated[0] = ladder_updated[1] = false;
+ if (!(NREV_GE(pi->pubpi.phy_rev, 6) ||
+ (NREV_IS(pi->pubpi.phy_rev, 5) && PHY_IPA(pi)
+ && (CHSPEC_IS2G(pi->radio_chanspec))))) {
+
+ if (phy_bw == 40) {
+ tbl_ptr = tbl_tx_iqlo_cal_loft_ladder_40;
+ tbl_len = ARRAY_SIZE(tbl_tx_iqlo_cal_loft_ladder_40);
+ } else {
+ tbl_ptr = tbl_tx_iqlo_cal_loft_ladder_20;
+ tbl_len = ARRAY_SIZE(tbl_tx_iqlo_cal_loft_ladder_20);
+ }
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, tbl_len, 0,
+ 16, tbl_ptr);
+
+ if (phy_bw == 40) {
+ tbl_ptr = tbl_tx_iqlo_cal_iqimb_ladder_40;
+ tbl_len = ARRAY_SIZE(tbl_tx_iqlo_cal_iqimb_ladder_40);
+ } else {
+ tbl_ptr = tbl_tx_iqlo_cal_iqimb_ladder_20;
+ tbl_len = ARRAY_SIZE(tbl_tx_iqlo_cal_iqimb_ladder_20);
+ }
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, tbl_len, 32,
+ 16, tbl_ptr);
+ }
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ write_phy_reg(pi, 0xc2, 0x8ad9);
+ else
+ write_phy_reg(pi, 0xc2, 0x8aa9);
+
+ max_val = 250;
+ tone_freq = (phy_bw == 20) ? 2500 : 5000;
+
+ if (pi->mphase_cal_phase_id > MPHASE_CAL_STATE_TXPHASE0) {
+ wlc_phy_runsamples_nphy(pi, phy_bw * 8, 0xffff, 0, 1, 0, false);
+ bcmerror = 0;
+ } else {
+ bcmerror =
+ wlc_phy_tx_tone_nphy(pi, tone_freq, max_val, 1, 0,
+ false);
+ }
+
+ if (bcmerror == 0) {
+
+ if (pi->mphase_cal_phase_id > MPHASE_CAL_STATE_TXPHASE0) {
+ tbl_ptr = pi->mphase_txcal_bestcoeffs;
+ tbl_len = ARRAY_SIZE(pi->mphase_txcal_bestcoeffs);
+ if (NREV_LT(pi->pubpi.phy_rev, 3))
+ tbl_len -= 2;
+ } else {
+ if ((!fullcal) && (pi->nphy_txiqlocal_coeffsvalid)) {
+
+ tbl_ptr = pi->nphy_txiqlocal_bestc;
+ tbl_len = ARRAY_SIZE(pi->nphy_txiqlocal_bestc);
+ if (NREV_LT(pi->pubpi.phy_rev, 3))
+ tbl_len -= 2;
+ } else {
+
+ fullcal = true;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ tbl_ptr =
+ tbl_tx_iqlo_cal_startcoefs_nphyrev3;
+ tbl_len = ARRAY_SIZE(
+ tbl_tx_iqlo_cal_startcoefs_nphyrev3);
+ } else {
+ tbl_ptr = tbl_tx_iqlo_cal_startcoefs;
+ tbl_len = ARRAY_SIZE(
+ tbl_tx_iqlo_cal_startcoefs);
+ }
+ }
+ }
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, tbl_len, 64,
+ 16, tbl_ptr);
+
+ if (fullcal) {
+ max_cal_cmds = (NREV_GE(pi->pubpi.phy_rev, 3)) ?
+ ARRAY_SIZE(
+ tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3) :
+ ARRAY_SIZE(tbl_tx_iqlo_cal_cmds_fullcal);
+ } else {
+ max_cal_cmds = (NREV_GE(pi->pubpi.phy_rev, 3)) ?
+ ARRAY_SIZE(
+ tbl_tx_iqlo_cal_cmds_recal_nphyrev3) :
+ ARRAY_SIZE(tbl_tx_iqlo_cal_cmds_recal);
+ }
+
+ if (mphase) {
+ cal_cnt = pi->mphase_txcal_cmdidx;
+ if ((cal_cnt + pi->mphase_txcal_numcmds) < max_cal_cmds)
+ num_cals = cal_cnt + pi->mphase_txcal_numcmds;
+ else
+ num_cals = max_cal_cmds;
+ } else {
+ cal_cnt = 0;
+ num_cals = max_cal_cmds;
+ }
+
+ for (; cal_cnt < num_cals; cal_cnt++) {
+
+ if (fullcal) {
+ cal_cmd = (NREV_GE(pi->pubpi.phy_rev, 3)) ?
+ tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3
+ [cal_cnt] :
+ tbl_tx_iqlo_cal_cmds_fullcal[cal_cnt];
+ } else {
+ cal_cmd = (NREV_GE(pi->pubpi.phy_rev, 3)) ?
+ tbl_tx_iqlo_cal_cmds_recal_nphyrev3[
+ cal_cnt]
+ : tbl_tx_iqlo_cal_cmds_recal[cal_cnt];
+ }
+
+ core_no = ((cal_cmd & 0x3000) >> 12);
+ cal_type = ((cal_cmd & 0x0F00) >> 8);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 6) ||
+ (NREV_IS(pi->pubpi.phy_rev, 5) &&
+ PHY_IPA(pi)
+ && (CHSPEC_IS2G(pi->radio_chanspec)))) {
+ if (!ladder_updated[core_no]) {
+ wlc_phy_update_txcal_ladder_nphy(
+ pi,
+ core_no);
+ ladder_updated[core_no] = true;
+ }
+ }
+
+ val =
+ (cal_params[core_no].
+ ncorr[cal_type] << 8) | NPHY_N_GCTL;
+ write_phy_reg(pi, 0xc1, val);
+
+ if ((cal_type == 1) || (cal_type == 3)
+ || (cal_type == 4)) {
+
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL,
+ 1, 69 + core_no, 16,
+ tbl_buf);
+
+ diq_start = tbl_buf[0];
+
+ tbl_buf[0] = 0;
+ wlc_phy_table_write_nphy(pi,
+ NPHY_TBL_ID_IQLOCAL, 1,
+ 69 + core_no, 16,
+ tbl_buf);
+ }
+
+ write_phy_reg(pi, 0xc0, cal_cmd);
+
+ SPINWAIT(((read_phy_reg(pi, 0xc0) & 0xc000) != 0),
+ 20000);
+ if (WARN(read_phy_reg(pi, 0xc0) & 0xc000,
+ "HW error: txiq calib"))
+ return -EIO;
+
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL,
+ tbl_len, 96, 16, tbl_buf);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL,
+ tbl_len, 64, 16, tbl_buf);
+
+ if ((cal_type == 1) || (cal_type == 3)
+ || (cal_type == 4)) {
+
+ tbl_buf[0] = diq_start;
+
+ }
+
+ }
+
+ if (mphase) {
+ pi->mphase_txcal_cmdidx = num_cals;
+ if (pi->mphase_txcal_cmdidx >= max_cal_cmds)
+ pi->mphase_txcal_cmdidx = 0;
+ }
+
+ mphase_cal_lastphase =
+ (NREV_LE(pi->pubpi.phy_rev, 2)) ?
+ MPHASE_CAL_STATE_TXPHASE4 : MPHASE_CAL_STATE_TXPHASE5;
+
+ if (!mphase
+ || (pi->mphase_cal_phase_id == mphase_cal_lastphase)) {
+
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 96,
+ 16, tbl_buf);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 80,
+ 16, tbl_buf);
+
+ if (NREV_LT(pi->pubpi.phy_rev, 2)) {
+
+ tbl_buf[0] = 0;
+ tbl_buf[1] = 0;
+ tbl_buf[2] = 0;
+ tbl_buf[3] = 0;
+
+ }
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 88,
+ 16, tbl_buf);
+
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 101,
+ 16, tbl_buf);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 85,
+ 16, tbl_buf);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 93,
+ 16, tbl_buf);
+
+ tbl_len = ARRAY_SIZE(pi->nphy_txiqlocal_bestc);
+ if (NREV_LT(pi->pubpi.phy_rev, 3))
+ tbl_len -= 2;
+
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL,
+ tbl_len, 96, 16,
+ pi->nphy_txiqlocal_bestc);
+
+ pi->nphy_txiqlocal_coeffsvalid = true;
+ pi->nphy_txiqlocal_chanspec = pi->radio_chanspec;
+ } else {
+ tbl_len = ARRAY_SIZE(pi->mphase_txcal_bestcoeffs);
+ if (NREV_LT(pi->pubpi.phy_rev, 3))
+ tbl_len -= 2;
+
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL,
+ tbl_len, 96, 16,
+ pi->mphase_txcal_bestcoeffs);
+ }
+
+ wlc_phy_stopplayback_nphy(pi);
+
+ write_phy_reg(pi, 0xc2, 0x0000);
+
+ }
+
+ wlc_phy_txcal_phycleanup_nphy(pi);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16,
+ gain_save);
+
+ wlc_phy_txcal_radio_cleanup_nphy(pi);
+
+ if (NREV_LT(pi->pubpi.phy_rev, 2)) {
+ if (!mphase
+ || (pi->mphase_cal_phase_id == mphase_cal_lastphase))
+ wlc_phy_tx_iq_war_nphy(pi);
+ }
+
+ if (NREV_GE(pi->pubpi.phy_rev, 4))
+ pi->phyhang_avoid = phyhang_avoid_state;
+
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+
+ return bcmerror;
+}
+
+static void wlc_phy_reapply_txcal_coeffs_nphy(struct brcms_phy *pi)
+{
+ u16 tbl_buf[7];
+
+ if ((pi->nphy_txiqlocal_chanspec == pi->radio_chanspec) &&
+ (pi->nphy_txiqlocal_coeffsvalid)) {
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL,
+ ARRAY_SIZE(tbl_buf), 80, 16, tbl_buf);
+
+ if ((pi->nphy_txiqlocal_bestc[0] != tbl_buf[0]) ||
+ (pi->nphy_txiqlocal_bestc[1] != tbl_buf[1]) ||
+ (pi->nphy_txiqlocal_bestc[2] != tbl_buf[2]) ||
+ (pi->nphy_txiqlocal_bestc[3] != tbl_buf[3])) {
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 80,
+ 16, pi->nphy_txiqlocal_bestc);
+
+ tbl_buf[0] = 0;
+ tbl_buf[1] = 0;
+ tbl_buf[2] = 0;
+ tbl_buf[3] = 0;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 88,
+ 16, tbl_buf);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 85,
+ 16,
+ &pi->nphy_txiqlocal_bestc[5]);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 93,
+ 16,
+ &pi->nphy_txiqlocal_bestc[5]);
+ }
+ }
+}
+
+void
+wlc_phy_rx_iq_coeffs_nphy(struct brcms_phy *pi, u8 write,
+ struct nphy_iq_comp *pcomp)
+{
+ if (write) {
+ write_phy_reg(pi, 0x9a, pcomp->a0);
+ write_phy_reg(pi, 0x9b, pcomp->b0);
+ write_phy_reg(pi, 0x9c, pcomp->a1);
+ write_phy_reg(pi, 0x9d, pcomp->b1);
+ } else {
+ pcomp->a0 = read_phy_reg(pi, 0x9a);
+ pcomp->b0 = read_phy_reg(pi, 0x9b);
+ pcomp->a1 = read_phy_reg(pi, 0x9c);
+ pcomp->b1 = read_phy_reg(pi, 0x9d);
+ }
+}
+
+void
+wlc_phy_rx_iq_est_nphy(struct brcms_phy *pi, struct phy_iq_est *est,
+ u16 num_samps, u8 wait_time, u8 wait_for_crs)
+{
+ u8 core;
+
+ write_phy_reg(pi, 0x12b, num_samps);
+ mod_phy_reg(pi, 0x12a, (0xff << 0), (wait_time << 0));
+ mod_phy_reg(pi, 0x129, NPHY_IqestCmd_iqMode,
+ (wait_for_crs) ? NPHY_IqestCmd_iqMode : 0);
+
+ mod_phy_reg(pi, 0x129, NPHY_IqestCmd_iqstart, NPHY_IqestCmd_iqstart);
+
+ SPINWAIT(((read_phy_reg(pi, 0x129) & NPHY_IqestCmd_iqstart) != 0),
+ 10000);
+ if (WARN(read_phy_reg(pi, 0x129) & NPHY_IqestCmd_iqstart,
+ "HW error: rxiq est"))
+ return;
+
+ if ((read_phy_reg(pi, 0x129) & NPHY_IqestCmd_iqstart) == 0) {
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+ est[core].i_pwr =
+ (read_phy_reg(pi,
+ NPHY_IqestipwrAccHi(core)) << 16)
+ | read_phy_reg(pi, NPHY_IqestipwrAccLo(core));
+ est[core].q_pwr =
+ (read_phy_reg(pi,
+ NPHY_IqestqpwrAccHi(core)) << 16)
+ | read_phy_reg(pi, NPHY_IqestqpwrAccLo(core));
+ est[core].iq_prod =
+ (read_phy_reg(pi,
+ NPHY_IqestIqAccHi(core)) << 16) |
+ read_phy_reg(pi, NPHY_IqestIqAccLo(core));
+ }
+ }
+}
+
+#define CAL_RETRY_CNT 2
+static void wlc_phy_calc_rx_iq_comp_nphy(struct brcms_phy *pi, u8 core_mask)
+{
+ u8 curr_core;
+ struct phy_iq_est est[PHY_CORE_MAX];
+ struct nphy_iq_comp old_comp, new_comp;
+ s32 iq = 0;
+ u32 ii = 0, qq = 0;
+ s16 iq_nbits, qq_nbits, brsh, arsh;
+ s32 a, b, temp;
+ int bcmerror = 0;
+ uint cal_retry = 0;
+
+ if (core_mask == 0x0)
+ return;
+
+ wlc_phy_rx_iq_coeffs_nphy(pi, 0, &old_comp);
+ new_comp.a0 = new_comp.b0 = new_comp.a1 = new_comp.b1 = 0x0;
+ wlc_phy_rx_iq_coeffs_nphy(pi, 1, &new_comp);
+
+cal_try:
+ wlc_phy_rx_iq_est_nphy(pi, est, 0x4000, 32, 0);
+
+ new_comp = old_comp;
+
+ for (curr_core = 0; curr_core < pi->pubpi.phy_corenum; curr_core++) {
+
+ if ((curr_core == PHY_CORE_0) && (core_mask & 0x1)) {
+ iq = est[curr_core].iq_prod;
+ ii = est[curr_core].i_pwr;
+ qq = est[curr_core].q_pwr;
+ } else if ((curr_core == PHY_CORE_1) && (core_mask & 0x2)) {
+ iq = est[curr_core].iq_prod;
+ ii = est[curr_core].i_pwr;
+ qq = est[curr_core].q_pwr;
+ } else {
+ continue;
+ }
+
+ if ((ii + qq) < NPHY_MIN_RXIQ_PWR) {
+ bcmerror = -EBADE;
+ break;
+ }
+
+ iq_nbits = wlc_phy_nbits(iq);
+ qq_nbits = wlc_phy_nbits(qq);
+
+ arsh = 10 - (30 - iq_nbits);
+ if (arsh >= 0) {
+ a = (-(iq << (30 - iq_nbits)) + (ii >> (1 + arsh)));
+ temp = (s32) (ii >> arsh);
+ if (temp == 0) {
+ bcmerror = -EBADE;
+ break;
+ }
+ } else {
+ a = (-(iq << (30 - iq_nbits)) + (ii << (-1 - arsh)));
+ temp = (s32) (ii << -arsh);
+ if (temp == 0) {
+ bcmerror = -EBADE;
+ break;
+ }
+ }
+
+ a /= temp;
+
+ brsh = qq_nbits - 31 + 20;
+ if (brsh >= 0) {
+ b = (qq << (31 - qq_nbits));
+ temp = (s32) (ii >> brsh);
+ if (temp == 0) {
+ bcmerror = -EBADE;
+ break;
+ }
+ } else {
+ b = (qq << (31 - qq_nbits));
+ temp = (s32) (ii << -brsh);
+ if (temp == 0) {
+ bcmerror = -EBADE;
+ break;
+ }
+ }
+ b /= temp;
+ b -= a * a;
+ b = (s32) int_sqrt((unsigned long) b);
+ b -= (1 << 10);
+
+ if ((curr_core == PHY_CORE_0) && (core_mask & 0x1)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ new_comp.a0 = (s16) a & 0x3ff;
+ new_comp.b0 = (s16) b & 0x3ff;
+ } else {
+
+ new_comp.a0 = (s16) b & 0x3ff;
+ new_comp.b0 = (s16) a & 0x3ff;
+ }
+ }
+ if ((curr_core == PHY_CORE_1) && (core_mask & 0x2)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ new_comp.a1 = (s16) a & 0x3ff;
+ new_comp.b1 = (s16) b & 0x3ff;
+ } else {
+
+ new_comp.a1 = (s16) b & 0x3ff;
+ new_comp.b1 = (s16) a & 0x3ff;
+ }
+ }
+ }
+
+ if (bcmerror != 0) {
+ printk(KERN_DEBUG "%s: Failed, cnt = %d\n", __func__,
+ cal_retry);
+
+ if (cal_retry < CAL_RETRY_CNT) {
+ cal_retry++;
+ goto cal_try;
+ }
+
+ new_comp = old_comp;
+ }
+
+ wlc_phy_rx_iq_coeffs_nphy(pi, 1, &new_comp);
+}
+
+static void wlc_phy_rxcal_radio_setup_nphy(struct brcms_phy *pi, u8 rx_core)
+{
+ u16 offtune_val;
+ u16 bias_g = 0;
+ u16 bias_a = 0;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (rx_core == PHY_CORE_0) {
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ pi->tx_rx_cal_radio_saveregs[0] =
+ read_radio_reg(pi,
+ RADIO_2057_TX0_TXRXCOUPLE_5G_PWRUP);
+ pi->tx_rx_cal_radio_saveregs[1] =
+ read_radio_reg(pi,
+ RADIO_2057_TX0_TXRXCOUPLE_5G_ATTEN);
+
+ write_radio_reg(pi,
+ RADIO_2057_TX0_TXRXCOUPLE_5G_PWRUP,
+ 0x3);
+ write_radio_reg(pi,
+ RADIO_2057_TX0_TXRXCOUPLE_5G_ATTEN,
+ 0xaf);
+
+ } else {
+ pi->tx_rx_cal_radio_saveregs[0] =
+ read_radio_reg(pi,
+ RADIO_2057_TX0_TXRXCOUPLE_2G_PWRUP);
+ pi->tx_rx_cal_radio_saveregs[1] =
+ read_radio_reg(pi,
+ RADIO_2057_TX0_TXRXCOUPLE_2G_ATTEN);
+
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX0_TXRXCOUPLE_2G_PWRUP,
+ 0x3);
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX0_TXRXCOUPLE_2G_ATTEN,
+ 0x7f);
+ }
+
+ } else {
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ pi->tx_rx_cal_radio_saveregs[0] =
+ read_radio_reg(pi,
+ RADIO_2057_TX1_TXRXCOUPLE_5G_PWRUP);
+ pi->tx_rx_cal_radio_saveregs[1] =
+ read_radio_reg(pi,
+ RADIO_2057_TX1_TXRXCOUPLE_5G_ATTEN);
+
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX1_TXRXCOUPLE_5G_PWRUP,
+ 0x3);
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX1_TXRXCOUPLE_5G_ATTEN,
+ 0xaf);
+
+ } else {
+ pi->tx_rx_cal_radio_saveregs[0] =
+ read_radio_reg(pi,
+ RADIO_2057_TX1_TXRXCOUPLE_2G_PWRUP);
+ pi->tx_rx_cal_radio_saveregs[1] =
+ read_radio_reg(pi,
+ RADIO_2057_TX1_TXRXCOUPLE_2G_ATTEN);
+
+ write_radio_reg(pi,
+ RADIO_2057_TX1_TXRXCOUPLE_2G_PWRUP,
+ 0x3);
+ write_radio_reg(pi,
+ RADIO_2057_TX1_TXRXCOUPLE_2G_ATTEN,
+ 0x7f);
+ }
+ }
+
+ } else {
+ if (rx_core == PHY_CORE_0) {
+ pi->tx_rx_cal_radio_saveregs[0] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_RXIQCAL_TXMUX |
+ RADIO_2056_TX1);
+ pi->tx_rx_cal_radio_saveregs[1] =
+ read_radio_reg(pi,
+ RADIO_2056_RX_RXIQCAL_RXMUX |
+ RADIO_2056_RX0);
+
+ if (pi->pubpi.radiorev >= 5) {
+ pi->tx_rx_cal_radio_saveregs[2] =
+ read_radio_reg(pi,
+ RADIO_2056_RX_RXSPARE2 |
+ RADIO_2056_RX0);
+ pi->tx_rx_cal_radio_saveregs[3] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_TXSPARE2 |
+ RADIO_2056_TX1);
+ }
+
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+
+ if (pi->pubpi.radiorev >= 5) {
+ pi->tx_rx_cal_radio_saveregs[4] =
+ read_radio_reg(pi,
+ RADIO_2056_RX_LNAA_MASTER
+ | RADIO_2056_RX0);
+
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAA_MASTER
+ | RADIO_2056_RX0, 0x40);
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_TXSPARE2 |
+ RADIO_2056_TX1, bias_a);
+
+ write_radio_reg(pi,
+ RADIO_2056_RX_RXSPARE2 |
+ RADIO_2056_RX0, bias_a);
+ } else {
+ pi->tx_rx_cal_radio_saveregs[4] =
+ read_radio_reg(pi,
+ RADIO_2056_RX_LNAA_TUNE
+ | RADIO_2056_RX0);
+
+ offtune_val =
+ (pi->tx_rx_cal_radio_saveregs
+ [2] & 0xF0) >> 8;
+ offtune_val =
+ (offtune_val <= 0x7) ? 0xF : 0;
+
+ mod_radio_reg(pi,
+ RADIO_2056_RX_LNAA_TUNE |
+ RADIO_2056_RX0, 0xF0,
+ (offtune_val << 8));
+ }
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_RXIQCAL_TXMUX |
+ RADIO_2056_TX1, 0x9);
+ write_radio_reg(pi,
+ RADIO_2056_RX_RXIQCAL_RXMUX |
+ RADIO_2056_RX0, 0x9);
+ } else {
+ if (pi->pubpi.radiorev >= 5) {
+ pi->tx_rx_cal_radio_saveregs[4] =
+ read_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAG_MASTER
+ | RADIO_2056_RX0);
+
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAG_MASTER
+ | RADIO_2056_RX0, 0x40);
+
+ write_radio_reg(
+ pi,
+ RADIO_2056_TX_TXSPARE2
+ |
+ RADIO_2056_TX1, bias_g);
+
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_RXSPARE2
+ |
+ RADIO_2056_RX0, bias_g);
+
+ } else {
+ pi->tx_rx_cal_radio_saveregs[4] =
+ read_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAG_TUNE
+ | RADIO_2056_RX0);
+
+ offtune_val =
+ (pi->
+ tx_rx_cal_radio_saveregs[2] &
+ 0xF0) >> 8;
+ offtune_val =
+ (offtune_val <= 0x7) ? 0xF : 0;
+
+ mod_radio_reg(pi,
+ RADIO_2056_RX_LNAG_TUNE |
+ RADIO_2056_RX0, 0xF0,
+ (offtune_val << 8));
+ }
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_RXIQCAL_TXMUX |
+ RADIO_2056_TX1, 0x6);
+ write_radio_reg(pi,
+ RADIO_2056_RX_RXIQCAL_RXMUX |
+ RADIO_2056_RX0, 0x6);
+ }
+
+ } else {
+ pi->tx_rx_cal_radio_saveregs[0] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_RXIQCAL_TXMUX |
+ RADIO_2056_TX0);
+ pi->tx_rx_cal_radio_saveregs[1] =
+ read_radio_reg(pi,
+ RADIO_2056_RX_RXIQCAL_RXMUX |
+ RADIO_2056_RX1);
+
+ if (pi->pubpi.radiorev >= 5) {
+ pi->tx_rx_cal_radio_saveregs[2] =
+ read_radio_reg(pi,
+ RADIO_2056_RX_RXSPARE2 |
+ RADIO_2056_RX1);
+ pi->tx_rx_cal_radio_saveregs[3] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_TXSPARE2 |
+ RADIO_2056_TX0);
+ }
+
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+
+ if (pi->pubpi.radiorev >= 5) {
+ pi->tx_rx_cal_radio_saveregs[4] =
+ read_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAA_MASTER
+ | RADIO_2056_RX1);
+
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAA_MASTER |
+ RADIO_2056_RX1, 0x40);
+
+ write_radio_reg(
+ pi,
+ RADIO_2056_TX_TXSPARE2
+ |
+ RADIO_2056_TX0, bias_a);
+
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_RXSPARE2
+ |
+ RADIO_2056_RX1, bias_a);
+ } else {
+ pi->tx_rx_cal_radio_saveregs[4] =
+ read_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAA_TUNE
+ | RADIO_2056_RX1);
+
+ offtune_val =
+ (pi->
+ tx_rx_cal_radio_saveregs[2] &
+ 0xF0) >> 8;
+ offtune_val =
+ (offtune_val <= 0x7) ? 0xF : 0;
+
+ mod_radio_reg(pi,
+ RADIO_2056_RX_LNAA_TUNE |
+ RADIO_2056_RX1, 0xF0,
+ (offtune_val << 8));
+ }
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_RXIQCAL_TXMUX |
+ RADIO_2056_TX0, 0x9);
+ write_radio_reg(pi,
+ RADIO_2056_RX_RXIQCAL_RXMUX |
+ RADIO_2056_RX1, 0x9);
+ } else {
+ if (pi->pubpi.radiorev >= 5) {
+ pi->tx_rx_cal_radio_saveregs[4] =
+ read_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAG_MASTER
+ | RADIO_2056_RX1);
+
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAG_MASTER
+ | RADIO_2056_RX1, 0x40);
+
+ write_radio_reg(
+ pi,
+ RADIO_2056_TX_TXSPARE2
+ |
+ RADIO_2056_TX0, bias_g);
+
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_RXSPARE2
+ |
+ RADIO_2056_RX1, bias_g);
+ } else {
+ pi->tx_rx_cal_radio_saveregs[4] =
+ read_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAG_TUNE
+ | RADIO_2056_RX1);
+
+ offtune_val =
+ (pi->
+ tx_rx_cal_radio_saveregs[2] &
+ 0xF0) >> 8;
+ offtune_val =
+ (offtune_val <= 0x7) ? 0xF : 0;
+
+ mod_radio_reg(pi,
+ RADIO_2056_RX_LNAG_TUNE |
+ RADIO_2056_RX1, 0xF0,
+ (offtune_val << 8));
+ }
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_RXIQCAL_TXMUX |
+ RADIO_2056_TX0, 0x6);
+ write_radio_reg(pi,
+ RADIO_2056_RX_RXIQCAL_RXMUX |
+ RADIO_2056_RX1, 0x6);
+ }
+ }
+ }
+}
+
+static void wlc_phy_rxcal_radio_cleanup_nphy(struct brcms_phy *pi, u8 rx_core)
+{
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (rx_core == PHY_CORE_0) {
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX0_TXRXCOUPLE_5G_PWRUP,
+ pi->
+ tx_rx_cal_radio_saveregs[0]);
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX0_TXRXCOUPLE_5G_ATTEN,
+ pi->
+ tx_rx_cal_radio_saveregs[1]);
+
+ } else {
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX0_TXRXCOUPLE_2G_PWRUP,
+ pi->
+ tx_rx_cal_radio_saveregs[0]);
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX0_TXRXCOUPLE_2G_ATTEN,
+ pi->
+ tx_rx_cal_radio_saveregs[1]);
+ }
+
+ } else {
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX1_TXRXCOUPLE_5G_PWRUP,
+ pi->
+ tx_rx_cal_radio_saveregs[0]);
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX1_TXRXCOUPLE_5G_ATTEN,
+ pi->
+ tx_rx_cal_radio_saveregs[1]);
+
+ } else {
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX1_TXRXCOUPLE_2G_PWRUP,
+ pi->
+ tx_rx_cal_radio_saveregs[0]);
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX1_TXRXCOUPLE_2G_ATTEN,
+ pi->
+ tx_rx_cal_radio_saveregs[1]);
+ }
+ }
+
+ } else {
+ if (rx_core == PHY_CORE_0) {
+ write_radio_reg(pi,
+ RADIO_2056_TX_RXIQCAL_TXMUX |
+ RADIO_2056_TX1,
+ pi->tx_rx_cal_radio_saveregs[0]);
+
+ write_radio_reg(pi,
+ RADIO_2056_RX_RXIQCAL_RXMUX |
+ RADIO_2056_RX0,
+ pi->tx_rx_cal_radio_saveregs[1]);
+
+ if (pi->pubpi.radiorev >= 5) {
+ write_radio_reg(pi,
+ RADIO_2056_RX_RXSPARE2 |
+ RADIO_2056_RX0,
+ pi->
+ tx_rx_cal_radio_saveregs[2]);
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_TXSPARE2 |
+ RADIO_2056_TX1,
+ pi->
+ tx_rx_cal_radio_saveregs[3]);
+ }
+
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ if (pi->pubpi.radiorev >= 5)
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAA_MASTER
+ | RADIO_2056_RX0,
+ pi->
+ tx_rx_cal_radio_saveregs
+ [4]);
+ else
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAA_TUNE
+ | RADIO_2056_RX0,
+ pi->
+ tx_rx_cal_radio_saveregs
+ [4]);
+ } else {
+ if (pi->pubpi.radiorev >= 5)
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAG_MASTER
+ | RADIO_2056_RX0,
+ pi->
+ tx_rx_cal_radio_saveregs
+ [4]);
+ else
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAG_TUNE
+ | RADIO_2056_RX0,
+ pi->
+ tx_rx_cal_radio_saveregs
+ [4]);
+ }
+
+ } else {
+ write_radio_reg(pi,
+ RADIO_2056_TX_RXIQCAL_TXMUX |
+ RADIO_2056_TX0,
+ pi->tx_rx_cal_radio_saveregs[0]);
+
+ write_radio_reg(pi,
+ RADIO_2056_RX_RXIQCAL_RXMUX |
+ RADIO_2056_RX1,
+ pi->tx_rx_cal_radio_saveregs[1]);
+
+ if (pi->pubpi.radiorev >= 5) {
+ write_radio_reg(pi,
+ RADIO_2056_RX_RXSPARE2 |
+ RADIO_2056_RX1,
+ pi->
+ tx_rx_cal_radio_saveregs[2]);
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_TXSPARE2 |
+ RADIO_2056_TX0,
+ pi->
+ tx_rx_cal_radio_saveregs[3]);
+ }
+
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ if (pi->pubpi.radiorev >= 5)
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAA_MASTER
+ | RADIO_2056_RX1,
+ pi->
+ tx_rx_cal_radio_saveregs
+ [4]);
+ else
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAA_TUNE
+ | RADIO_2056_RX1,
+ pi->
+ tx_rx_cal_radio_saveregs
+ [4]);
+ } else {
+ if (pi->pubpi.radiorev >= 5)
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAG_MASTER
+ | RADIO_2056_RX1,
+ pi->
+ tx_rx_cal_radio_saveregs
+ [4]);
+ else
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAG_TUNE
+ | RADIO_2056_RX1,
+ pi->
+ tx_rx_cal_radio_saveregs
+ [4]);
+ }
+ }
+ }
+}
+
+static void wlc_phy_rxcal_physetup_nphy(struct brcms_phy *pi, u8 rx_core)
+{
+ u8 tx_core;
+ u16 rx_antval, tx_antval;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ tx_core = rx_core;
+ else
+ tx_core = (rx_core == PHY_CORE_0) ? 1 : 0;
+
+ pi->tx_rx_cal_phy_saveregs[0] = read_phy_reg(pi, 0xa2);
+ pi->tx_rx_cal_phy_saveregs[1] =
+ read_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0xa6 : 0xa7);
+ pi->tx_rx_cal_phy_saveregs[2] =
+ read_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0x8f : 0xa5);
+ pi->tx_rx_cal_phy_saveregs[3] = read_phy_reg(pi, 0x91);
+ pi->tx_rx_cal_phy_saveregs[4] = read_phy_reg(pi, 0x92);
+ pi->tx_rx_cal_phy_saveregs[5] = read_phy_reg(pi, 0x7a);
+ pi->tx_rx_cal_phy_saveregs[6] = read_phy_reg(pi, 0x7d);
+ pi->tx_rx_cal_phy_saveregs[7] = read_phy_reg(pi, 0xe7);
+ pi->tx_rx_cal_phy_saveregs[8] = read_phy_reg(pi, 0xec);
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ pi->tx_rx_cal_phy_saveregs[11] = read_phy_reg(pi, 0x342);
+ pi->tx_rx_cal_phy_saveregs[12] = read_phy_reg(pi, 0x343);
+ pi->tx_rx_cal_phy_saveregs[13] = read_phy_reg(pi, 0x346);
+ pi->tx_rx_cal_phy_saveregs[14] = read_phy_reg(pi, 0x347);
+ }
+
+ pi->tx_rx_cal_phy_saveregs[9] = read_phy_reg(pi, 0x297);
+ pi->tx_rx_cal_phy_saveregs[10] = read_phy_reg(pi, 0x29b);
+ mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (0) << 0);
+
+ mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (0) << 0);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ mod_phy_reg(pi, 0xa2, (0xf << 0), (1 << tx_core) << 0);
+
+ mod_phy_reg(pi, 0xa2, (0xf << 12), (1 << (1 - rx_core)) << 12);
+
+ } else {
+
+ mod_phy_reg(pi, 0xa2, (0xf << 12), (1 << tx_core) << 12);
+ mod_phy_reg(pi, 0xa2, (0xf << 0), (1 << tx_core) << 0);
+ mod_phy_reg(pi, 0xa2, (0xf << 4), (1 << rx_core) << 4);
+ mod_phy_reg(pi, 0xa2, (0xf << 8), (1 << rx_core) << 8);
+ }
+
+ mod_phy_reg(pi, ((rx_core == PHY_CORE_0) ? 0xa6 : 0xa7), (0x1 << 2), 0);
+ mod_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0x8f : 0xa5,
+ (0x1 << 2), (0x1 << 2));
+ if (NREV_LT(pi->pubpi.phy_rev, 7)) {
+ mod_phy_reg(pi, ((rx_core == PHY_CORE_0) ? 0xa6 : 0xa7),
+ (0x1 << 0) | (0x1 << 1), 0);
+ mod_phy_reg(pi, (rx_core == PHY_CORE_0) ?
+ 0x8f : 0xa5,
+ (0x1 << 0) | (0x1 << 1), (0x1 << 0) | (0x1 << 1));
+ }
+
+ wlc_phy_rfctrlintc_override_nphy(pi, NPHY_RfctrlIntc_override_PA, 0,
+ RADIO_MIMO_CORESEL_CORE1 |
+ RADIO_MIMO_CORESEL_CORE2);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3),
+ 0, 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 9), 0, 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 10), 1, 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 0), 1, 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1), 1, 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID2);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 11), 0, 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ if (CHSPEC_IS40(pi->radio_chanspec))
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi,
+ (0x1 << 7),
+ 2, 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ else
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi,
+ (0x1 << 7),
+ 0, 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 7),
+ 0, 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 5), 0, 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ } else {
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 0, 3, 0);
+ }
+
+ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ wlc_phy_rfctrlintc_override_nphy(pi,
+ NPHY_RfctrlIntc_override_TRSW,
+ 0x1, rx_core + 1);
+ } else {
+
+ if (rx_core == PHY_CORE_0) {
+ rx_antval = 0x1;
+ tx_antval = 0x8;
+ } else {
+ rx_antval = 0x4;
+ tx_antval = 0x2;
+ }
+
+ wlc_phy_rfctrlintc_override_nphy(pi,
+ NPHY_RfctrlIntc_override_TRSW,
+ rx_antval, rx_core + 1);
+ wlc_phy_rfctrlintc_override_nphy(pi,
+ NPHY_RfctrlIntc_override_TRSW,
+ tx_antval, tx_core + 1);
+ }
+}
+
+static void wlc_phy_rxcal_phycleanup_nphy(struct brcms_phy *pi, u8 rx_core)
+{
+
+ write_phy_reg(pi, 0xa2, pi->tx_rx_cal_phy_saveregs[0]);
+ write_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0xa6 : 0xa7,
+ pi->tx_rx_cal_phy_saveregs[1]);
+ write_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0x8f : 0xa5,
+ pi->tx_rx_cal_phy_saveregs[2]);
+ write_phy_reg(pi, 0x91, pi->tx_rx_cal_phy_saveregs[3]);
+ write_phy_reg(pi, 0x92, pi->tx_rx_cal_phy_saveregs[4]);
+
+ write_phy_reg(pi, 0x7a, pi->tx_rx_cal_phy_saveregs[5]);
+ write_phy_reg(pi, 0x7d, pi->tx_rx_cal_phy_saveregs[6]);
+ write_phy_reg(pi, 0xe7, pi->tx_rx_cal_phy_saveregs[7]);
+ write_phy_reg(pi, 0xec, pi->tx_rx_cal_phy_saveregs[8]);
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ write_phy_reg(pi, 0x342, pi->tx_rx_cal_phy_saveregs[11]);
+ write_phy_reg(pi, 0x343, pi->tx_rx_cal_phy_saveregs[12]);
+ write_phy_reg(pi, 0x346, pi->tx_rx_cal_phy_saveregs[13]);
+ write_phy_reg(pi, 0x347, pi->tx_rx_cal_phy_saveregs[14]);
+ }
+
+ write_phy_reg(pi, 0x297, pi->tx_rx_cal_phy_saveregs[9]);
+ write_phy_reg(pi, 0x29b, pi->tx_rx_cal_phy_saveregs[10]);
+}
+
+static void
+wlc_phy_rxcal_gainctrl_nphy_rev5(struct brcms_phy *pi, u8 rx_core,
+ u16 *rxgain, u8 cal_type)
+{
+
+ u16 num_samps;
+ struct phy_iq_est est[PHY_CORE_MAX];
+ u8 tx_core;
+ struct nphy_iq_comp save_comp, zero_comp;
+ u32 i_pwr, q_pwr, curr_pwr, optim_pwr = 0, prev_pwr = 0,
+ thresh_pwr = 10000;
+ s16 desired_log2_pwr, actual_log2_pwr, delta_pwr;
+ bool gainctrl_done = false;
+ u8 mix_tia_gain = 3;
+ s8 optim_gaintbl_index = 0, prev_gaintbl_index = 0;
+ s8 curr_gaintbl_index = 3;
+ u8 gainctrl_dirn = NPHY_RXCAL_GAIN_INIT;
+ const struct nphy_ipa_txrxgain *nphy_rxcal_gaintbl;
+ u16 hpvga, lpf_biq1, lpf_biq0, lna2, lna1;
+ int fine_gain_idx;
+ s8 txpwrindex;
+ u16 nphy_rxcal_txgain[2];
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ tx_core = rx_core;
+ else
+ tx_core = 1 - rx_core;
+
+ num_samps = 1024;
+ desired_log2_pwr = (cal_type == 0) ? 13 : 13;
+
+ wlc_phy_rx_iq_coeffs_nphy(pi, 0, &save_comp);
+ zero_comp.a0 = zero_comp.b0 = zero_comp.a1 = zero_comp.b1 = 0x0;
+ wlc_phy_rx_iq_coeffs_nphy(pi, 1, &zero_comp);
+
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ mix_tia_gain = 3;
+ else if (NREV_GE(pi->pubpi.phy_rev, 4))
+ mix_tia_gain = 4;
+ else
+ mix_tia_gain = 6;
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ nphy_rxcal_gaintbl = nphy_ipa_rxcal_gaintbl_5GHz_rev7;
+ else
+ nphy_rxcal_gaintbl = nphy_ipa_rxcal_gaintbl_5GHz;
+ } else {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ nphy_rxcal_gaintbl = nphy_ipa_rxcal_gaintbl_2GHz_rev7;
+ else
+ nphy_rxcal_gaintbl = nphy_ipa_rxcal_gaintbl_2GHz;
+ }
+
+ do {
+
+ hpvga = (NREV_GE(pi->pubpi.phy_rev, 7)) ?
+ 0 : nphy_rxcal_gaintbl[curr_gaintbl_index].hpvga;
+ lpf_biq1 = nphy_rxcal_gaintbl[curr_gaintbl_index].lpf_biq1;
+ lpf_biq0 = nphy_rxcal_gaintbl[curr_gaintbl_index].lpf_biq0;
+ lna2 = nphy_rxcal_gaintbl[curr_gaintbl_index].lna2;
+ lna1 = nphy_rxcal_gaintbl[curr_gaintbl_index].lna1;
+ txpwrindex = nphy_rxcal_gaintbl[curr_gaintbl_index].txpwrindex;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ wlc_phy_rfctrl_override_1tomany_nphy(
+ pi,
+ NPHY_REV7_RfctrlOverride_cmd_rxgain,
+ ((lpf_biq1 << 12) |
+ (lpf_biq0 << 8) |
+ (mix_tia_gain << 4) | (lna2 << 2)
+ | lna1), 0x3, 0);
+ else
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 12),
+ ((hpvga << 12) |
+ (lpf_biq1 << 10) |
+ (lpf_biq0 << 8) |
+ (mix_tia_gain << 4) |
+ (lna2 << 2) | lna1), 0x3,
+ 0);
+
+ pi->nphy_rxcal_pwr_idx[tx_core] = txpwrindex;
+
+ if (txpwrindex == -1) {
+ nphy_rxcal_txgain[0] = 0x8ff0 | pi->nphy_gmval;
+ nphy_rxcal_txgain[1] = 0x8ff0 | pi->nphy_gmval;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ,
+ 2, 0x110, 16,
+ nphy_rxcal_txgain);
+ } else {
+ wlc_phy_txpwr_index_nphy(pi, tx_core + 1, txpwrindex,
+ false);
+ }
+
+ wlc_phy_tx_tone_nphy(pi, (CHSPEC_IS40(pi->radio_chanspec)) ?
+ NPHY_RXCAL_TONEFREQ_40MHz :
+ NPHY_RXCAL_TONEFREQ_20MHz,
+ NPHY_RXCAL_TONEAMP, 0, cal_type, false);
+
+ wlc_phy_rx_iq_est_nphy(pi, est, num_samps, 32, 0);
+ i_pwr = (est[rx_core].i_pwr + num_samps / 2) / num_samps;
+ q_pwr = (est[rx_core].q_pwr + num_samps / 2) / num_samps;
+ curr_pwr = i_pwr + q_pwr;
+
+ switch (gainctrl_dirn) {
+ case NPHY_RXCAL_GAIN_INIT:
+ if (curr_pwr > thresh_pwr) {
+ gainctrl_dirn = NPHY_RXCAL_GAIN_DOWN;
+ prev_gaintbl_index = curr_gaintbl_index;
+ curr_gaintbl_index--;
+ } else {
+ gainctrl_dirn = NPHY_RXCAL_GAIN_UP;
+ prev_gaintbl_index = curr_gaintbl_index;
+ curr_gaintbl_index++;
+ }
+ break;
+
+ case NPHY_RXCAL_GAIN_UP:
+ if (curr_pwr > thresh_pwr) {
+ gainctrl_done = true;
+ optim_pwr = prev_pwr;
+ optim_gaintbl_index = prev_gaintbl_index;
+ } else {
+ prev_gaintbl_index = curr_gaintbl_index;
+ curr_gaintbl_index++;
+ }
+ break;
+
+ case NPHY_RXCAL_GAIN_DOWN:
+ if (curr_pwr > thresh_pwr) {
+ prev_gaintbl_index = curr_gaintbl_index;
+ curr_gaintbl_index--;
+ } else {
+ gainctrl_done = true;
+ optim_pwr = curr_pwr;
+ optim_gaintbl_index = curr_gaintbl_index;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if ((curr_gaintbl_index < 0) ||
+ (curr_gaintbl_index > NPHY_IPA_RXCAL_MAXGAININDEX)) {
+ gainctrl_done = true;
+ optim_pwr = curr_pwr;
+ optim_gaintbl_index = prev_gaintbl_index;
+ } else {
+ prev_pwr = curr_pwr;
+ }
+
+ wlc_phy_stopplayback_nphy(pi);
+ } while (!gainctrl_done);
+
+ hpvga = nphy_rxcal_gaintbl[optim_gaintbl_index].hpvga;
+ lpf_biq1 = nphy_rxcal_gaintbl[optim_gaintbl_index].lpf_biq1;
+ lpf_biq0 = nphy_rxcal_gaintbl[optim_gaintbl_index].lpf_biq0;
+ lna2 = nphy_rxcal_gaintbl[optim_gaintbl_index].lna2;
+ lna1 = nphy_rxcal_gaintbl[optim_gaintbl_index].lna1;
+ txpwrindex = nphy_rxcal_gaintbl[optim_gaintbl_index].txpwrindex;
+
+ actual_log2_pwr = wlc_phy_nbits(optim_pwr);
+ delta_pwr = desired_log2_pwr - actual_log2_pwr;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ fine_gain_idx = (int)lpf_biq1 + delta_pwr;
+
+ if (fine_gain_idx + (int)lpf_biq0 > 10)
+ lpf_biq1 = 10 - lpf_biq0;
+ else
+ lpf_biq1 = (u16) max(fine_gain_idx, 0);
+
+ wlc_phy_rfctrl_override_1tomany_nphy(
+ pi,
+ NPHY_REV7_RfctrlOverride_cmd_rxgain,
+ ((lpf_biq1 << 12) |
+ (lpf_biq0 << 8) |
+ (mix_tia_gain << 4) |
+ (lna2 << 2) | lna1), 0x3,
+ 0);
+ } else {
+ hpvga = (u16) max(min(((int)hpvga) + delta_pwr, 10), 0);
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 12),
+ ((hpvga << 12) |
+ (lpf_biq1 << 10) |
+ (lpf_biq0 << 8) |
+ (mix_tia_gain << 4) |
+ (lna2 << 2) |
+ lna1), 0x3, 0);
+ }
+
+ if (rxgain != NULL) {
+ *rxgain++ = lna1;
+ *rxgain++ = lna2;
+ *rxgain++ = mix_tia_gain;
+ *rxgain++ = lpf_biq0;
+ *rxgain++ = lpf_biq1;
+ *rxgain = hpvga;
+ }
+
+ wlc_phy_rx_iq_coeffs_nphy(pi, 1, &save_comp);
+}
+
+static void
+wlc_phy_rxcal_gainctrl_nphy(struct brcms_phy *pi, u8 rx_core, u16 *rxgain,
+ u8 cal_type)
+{
+ wlc_phy_rxcal_gainctrl_nphy_rev5(pi, rx_core, rxgain, cal_type);
+}
+
+static u8
+wlc_phy_rc_sweep_nphy(struct brcms_phy *pi, u8 core_idx, u8 loopback_type)
+{
+ u32 target_bws[2] = { 9500, 21000 };
+ u32 ref_tones[2] = { 3000, 6000 };
+ u32 target_bw, ref_tone;
+
+ u32 target_pwr_ratios[2] = { 28606, 18468 };
+ u32 target_pwr_ratio, pwr_ratio, last_pwr_ratio = 0;
+
+ u16 start_rccal_ovr_val = 128;
+ u16 txlpf_rccal_lpc_ovr_val = 128;
+ u16 rxlpf_rccal_hpc_ovr_val = 159;
+
+ u16 orig_txlpf_rccal_lpc_ovr_val;
+ u16 orig_rxlpf_rccal_hpc_ovr_val;
+ u16 radio_addr_offset_rx;
+ u16 radio_addr_offset_tx;
+ u16 orig_dcBypass;
+ u16 orig_RxStrnFilt40Num[6];
+ u16 orig_RxStrnFilt40Den[4];
+ u16 orig_rfctrloverride[2];
+ u16 orig_rfctrlauxreg[2];
+ u16 orig_rfctrlrssiothers;
+ u16 tx_lpf_bw = 4;
+
+ u16 rx_lpf_bw, rx_lpf_bws[2] = { 2, 4 };
+ u16 lpf_hpc = 7, hpvga_hpc = 7;
+
+ s8 rccal_stepsize;
+ u16 rccal_val, last_rccal_val = 0, best_rccal_val = 0;
+ u32 ref_iq_vals = 0, target_iq_vals = 0;
+ u16 num_samps, log_num_samps = 10;
+ struct phy_iq_est est[PHY_CORE_MAX];
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ return 0;
+
+ num_samps = (1 << log_num_samps);
+
+ if (CHSPEC_IS40(pi->radio_chanspec)) {
+ target_bw = target_bws[1];
+ target_pwr_ratio = target_pwr_ratios[1];
+ ref_tone = ref_tones[1];
+ rx_lpf_bw = rx_lpf_bws[1];
+ } else {
+ target_bw = target_bws[0];
+ target_pwr_ratio = target_pwr_ratios[0];
+ ref_tone = ref_tones[0];
+ rx_lpf_bw = rx_lpf_bws[0];
+ }
+
+ if (core_idx == 0) {
+ radio_addr_offset_rx = RADIO_2056_RX0;
+ radio_addr_offset_tx =
+ (loopback_type == 0) ? RADIO_2056_TX0 : RADIO_2056_TX1;
+ } else {
+ radio_addr_offset_rx = RADIO_2056_RX1;
+ radio_addr_offset_tx =
+ (loopback_type == 0) ? RADIO_2056_TX1 : RADIO_2056_TX0;
+ }
+
+ orig_txlpf_rccal_lpc_ovr_val =
+ read_radio_reg(pi,
+ (RADIO_2056_TX_TXLPF_RCCAL |
+ radio_addr_offset_tx));
+ orig_rxlpf_rccal_hpc_ovr_val =
+ read_radio_reg(pi,
+ (RADIO_2056_RX_RXLPF_RCCAL_HPC |
+ radio_addr_offset_rx));
+
+ orig_dcBypass = ((read_phy_reg(pi, 0x48) >> 8) & 1);
+
+ orig_RxStrnFilt40Num[0] = read_phy_reg(pi, 0x267);
+ orig_RxStrnFilt40Num[1] = read_phy_reg(pi, 0x268);
+ orig_RxStrnFilt40Num[2] = read_phy_reg(pi, 0x269);
+ orig_RxStrnFilt40Den[0] = read_phy_reg(pi, 0x26a);
+ orig_RxStrnFilt40Den[1] = read_phy_reg(pi, 0x26b);
+ orig_RxStrnFilt40Num[3] = read_phy_reg(pi, 0x26c);
+ orig_RxStrnFilt40Num[4] = read_phy_reg(pi, 0x26d);
+ orig_RxStrnFilt40Num[5] = read_phy_reg(pi, 0x26e);
+ orig_RxStrnFilt40Den[2] = read_phy_reg(pi, 0x26f);
+ orig_RxStrnFilt40Den[3] = read_phy_reg(pi, 0x270);
+
+ orig_rfctrloverride[0] = read_phy_reg(pi, 0xe7);
+ orig_rfctrloverride[1] = read_phy_reg(pi, 0xec);
+ orig_rfctrlauxreg[0] = read_phy_reg(pi, 0xf8);
+ orig_rfctrlauxreg[1] = read_phy_reg(pi, 0xfa);
+ orig_rfctrlrssiothers = read_phy_reg(pi, (core_idx == 0) ? 0x7a : 0x7d);
+
+ write_radio_reg(pi, (RADIO_2056_TX_TXLPF_RCCAL | radio_addr_offset_tx),
+ txlpf_rccal_lpc_ovr_val);
+
+ write_radio_reg(pi,
+ (RADIO_2056_RX_RXLPF_RCCAL_HPC | radio_addr_offset_rx),
+ rxlpf_rccal_hpc_ovr_val);
+
+ mod_phy_reg(pi, 0x48, (0x1 << 8), (0x1 << 8));
+
+ write_phy_reg(pi, 0x267, 0x02d4);
+ write_phy_reg(pi, 0x268, 0x0000);
+ write_phy_reg(pi, 0x269, 0x0000);
+ write_phy_reg(pi, 0x26a, 0x0000);
+ write_phy_reg(pi, 0x26b, 0x0000);
+ write_phy_reg(pi, 0x26c, 0x02d4);
+ write_phy_reg(pi, 0x26d, 0x0000);
+ write_phy_reg(pi, 0x26e, 0x0000);
+ write_phy_reg(pi, 0x26f, 0x0000);
+ write_phy_reg(pi, 0x270, 0x0000);
+
+ or_phy_reg(pi, (core_idx == 0) ? 0xe7 : 0xec, (0x1 << 8));
+ or_phy_reg(pi, (core_idx == 0) ? 0xec : 0xe7, (0x1 << 15));
+ or_phy_reg(pi, (core_idx == 0) ? 0xe7 : 0xec, (0x1 << 9));
+ or_phy_reg(pi, (core_idx == 0) ? 0xe7 : 0xec, (0x1 << 10));
+
+ mod_phy_reg(pi, (core_idx == 0) ? 0xfa : 0xf8,
+ (0x7 << 10), (tx_lpf_bw << 10));
+ mod_phy_reg(pi, (core_idx == 0) ? 0xf8 : 0xfa,
+ (0x7 << 0), (hpvga_hpc << 0));
+ mod_phy_reg(pi, (core_idx == 0) ? 0xf8 : 0xfa,
+ (0x7 << 4), (lpf_hpc << 4));
+ mod_phy_reg(pi, (core_idx == 0) ? 0x7a : 0x7d,
+ (0x7 << 8), (rx_lpf_bw << 8));
+
+ rccal_stepsize = 16;
+ rccal_val = start_rccal_ovr_val + rccal_stepsize;
+
+ while (rccal_stepsize >= 0) {
+ write_radio_reg(pi,
+ (RADIO_2056_RX_RXLPF_RCCAL_LPC |
+ radio_addr_offset_rx), rccal_val);
+
+ if (rccal_stepsize == 16) {
+
+ wlc_phy_tx_tone_nphy(pi, ref_tone, NPHY_RXCAL_TONEAMP,
+ 0, 1, false);
+ udelay(2);
+
+ wlc_phy_rx_iq_est_nphy(pi, est, num_samps, 32, 0);
+
+ if (core_idx == 0)
+ ref_iq_vals =
+ max_t(u32, (est[0].i_pwr +
+ est[0].q_pwr) >>
+ (log_num_samps + 1),
+ 1);
+ else
+ ref_iq_vals =
+ max_t(u32, (est[1].i_pwr +
+ est[1].q_pwr) >>
+ (log_num_samps + 1),
+ 1);
+
+ wlc_phy_tx_tone_nphy(pi, target_bw, NPHY_RXCAL_TONEAMP,
+ 0, 1, false);
+ udelay(2);
+ }
+
+ wlc_phy_rx_iq_est_nphy(pi, est, num_samps, 32, 0);
+
+ if (core_idx == 0)
+ target_iq_vals = (est[0].i_pwr + est[0].q_pwr) >>
+ (log_num_samps + 1);
+ else
+ target_iq_vals =
+ (est[1].i_pwr +
+ est[1].q_pwr) >> (log_num_samps + 1);
+
+ pwr_ratio = (uint) ((target_iq_vals << 16) / ref_iq_vals);
+
+ if (rccal_stepsize == 0)
+ rccal_stepsize--;
+ else if (rccal_stepsize == 1) {
+ last_rccal_val = rccal_val;
+ rccal_val += (pwr_ratio > target_pwr_ratio) ? 1 : -1;
+ last_pwr_ratio = pwr_ratio;
+ rccal_stepsize--;
+ } else {
+ rccal_stepsize = (rccal_stepsize >> 1);
+ rccal_val += ((pwr_ratio > target_pwr_ratio) ?
+ rccal_stepsize : (-rccal_stepsize));
+ }
+
+ if (rccal_stepsize == -1) {
+ best_rccal_val =
+ (abs((int)last_pwr_ratio -
+ (int)target_pwr_ratio) <
+ abs((int)pwr_ratio -
+ (int)target_pwr_ratio)) ? last_rccal_val :
+ rccal_val;
+
+ if (CHSPEC_IS40(pi->radio_chanspec)) {
+ if ((best_rccal_val > 140)
+ || (best_rccal_val < 135))
+ best_rccal_val = 138;
+ } else {
+ if ((best_rccal_val > 142)
+ || (best_rccal_val < 137))
+ best_rccal_val = 140;
+ }
+
+ write_radio_reg(pi,
+ (RADIO_2056_RX_RXLPF_RCCAL_LPC |
+ radio_addr_offset_rx), best_rccal_val);
+ }
+ }
+
+ wlc_phy_stopplayback_nphy(pi);
+
+ write_radio_reg(pi, (RADIO_2056_TX_TXLPF_RCCAL | radio_addr_offset_tx),
+ orig_txlpf_rccal_lpc_ovr_val);
+ write_radio_reg(pi,
+ (RADIO_2056_RX_RXLPF_RCCAL_HPC | radio_addr_offset_rx),
+ orig_rxlpf_rccal_hpc_ovr_val);
+
+ mod_phy_reg(pi, 0x48, (0x1 << 8), (orig_dcBypass << 8));
+
+ write_phy_reg(pi, 0x267, orig_RxStrnFilt40Num[0]);
+ write_phy_reg(pi, 0x268, orig_RxStrnFilt40Num[1]);
+ write_phy_reg(pi, 0x269, orig_RxStrnFilt40Num[2]);
+ write_phy_reg(pi, 0x26a, orig_RxStrnFilt40Den[0]);
+ write_phy_reg(pi, 0x26b, orig_RxStrnFilt40Den[1]);
+ write_phy_reg(pi, 0x26c, orig_RxStrnFilt40Num[3]);
+ write_phy_reg(pi, 0x26d, orig_RxStrnFilt40Num[4]);
+ write_phy_reg(pi, 0x26e, orig_RxStrnFilt40Num[5]);
+ write_phy_reg(pi, 0x26f, orig_RxStrnFilt40Den[2]);
+ write_phy_reg(pi, 0x270, orig_RxStrnFilt40Den[3]);
+
+ write_phy_reg(pi, 0xe7, orig_rfctrloverride[0]);
+ write_phy_reg(pi, 0xec, orig_rfctrloverride[1]);
+ write_phy_reg(pi, 0xf8, orig_rfctrlauxreg[0]);
+ write_phy_reg(pi, 0xfa, orig_rfctrlauxreg[1]);
+ write_phy_reg(pi, (core_idx == 0) ? 0x7a : 0x7d, orig_rfctrlrssiothers);
+
+ pi->nphy_anarxlpf_adjusted = false;
+
+ return best_rccal_val - 0x80;
+}
+
+#define WAIT_FOR_SCOPE 4000
+static int wlc_phy_cal_rxiq_nphy_rev3(struct brcms_phy *pi,
+ struct nphy_txgains target_gain,
+ u8 cal_type, bool debug)
+{
+ u16 orig_BBConfig;
+ u8 core_no, rx_core;
+ u8 best_rccal[2];
+ u16 gain_save[2];
+ u16 cal_gain[2];
+ struct nphy_iqcal_params cal_params[2];
+ u8 rxcore_state;
+ s8 rxlpf_rccal_hpc, txlpf_rccal_lpc;
+ s8 txlpf_idac;
+ bool phyhang_avoid_state = false;
+ bool skip_rxiqcal = false;
+
+ orig_BBConfig = read_phy_reg(pi, 0x01);
+ mod_phy_reg(pi, 0x01, (0x1 << 15), 0);
+
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 4)) {
+ phyhang_avoid_state = pi->phyhang_avoid;
+ pi->phyhang_avoid = false;
+ }
+
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, gain_save);
+
+ for (core_no = 0; core_no <= 1; core_no++) {
+ wlc_phy_iqcal_gainparams_nphy(pi, core_no, target_gain,
+ &cal_params[core_no]);
+ cal_gain[core_no] = cal_params[core_no].cal_gain;
+ }
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, cal_gain);
+
+ rxcore_state = wlc_phy_rxcore_getstate_nphy(
+ (struct brcms_phy_pub *) pi);
+
+ for (rx_core = 0; rx_core < pi->pubpi.phy_corenum; rx_core++) {
+
+ skip_rxiqcal =
+ ((rxcore_state & (1 << rx_core)) == 0) ? true : false;
+
+ wlc_phy_rxcal_physetup_nphy(pi, rx_core);
+
+ wlc_phy_rxcal_radio_setup_nphy(pi, rx_core);
+
+ if ((!skip_rxiqcal) && ((cal_type == 0) || (cal_type == 2))) {
+
+ wlc_phy_rxcal_gainctrl_nphy(pi, rx_core, NULL, 0);
+
+ wlc_phy_tx_tone_nphy(pi,
+ (CHSPEC_IS40(
+ pi->radio_chanspec)) ?
+ NPHY_RXCAL_TONEFREQ_40MHz :
+ NPHY_RXCAL_TONEFREQ_20MHz,
+ NPHY_RXCAL_TONEAMP, 0, cal_type,
+ false);
+
+ if (debug)
+ mdelay(WAIT_FOR_SCOPE);
+
+ wlc_phy_calc_rx_iq_comp_nphy(pi, rx_core + 1);
+ wlc_phy_stopplayback_nphy(pi);
+ }
+
+ if (((cal_type == 1) || (cal_type == 2))
+ && NREV_LT(pi->pubpi.phy_rev, 7)) {
+
+ if (rx_core == PHY_CORE_1) {
+
+ if (rxcore_state == 1)
+ wlc_phy_rxcore_setstate_nphy(
+ (struct brcms_phy_pub *) pi, 3);
+
+ wlc_phy_rxcal_gainctrl_nphy(pi, rx_core, NULL,
+ 1);
+
+ best_rccal[rx_core] =
+ wlc_phy_rc_sweep_nphy(pi, rx_core, 1);
+ pi->nphy_rccal_value = best_rccal[rx_core];
+
+ if (rxcore_state == 1)
+ wlc_phy_rxcore_setstate_nphy(
+ (struct brcms_phy_pub *) pi,
+ rxcore_state);
+ }
+ }
+
+ wlc_phy_rxcal_radio_cleanup_nphy(pi, rx_core);
+
+ wlc_phy_rxcal_phycleanup_nphy(pi, rx_core);
+ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX);
+ }
+
+ if ((cal_type == 1) || (cal_type == 2)) {
+
+ best_rccal[0] = best_rccal[1];
+ write_radio_reg(pi,
+ (RADIO_2056_RX_RXLPF_RCCAL_LPC |
+ RADIO_2056_RX0), (best_rccal[0] | 0x80));
+
+ for (rx_core = 0; rx_core < pi->pubpi.phy_corenum; rx_core++) {
+ rxlpf_rccal_hpc =
+ (((int)best_rccal[rx_core] - 12) >> 1) + 10;
+ txlpf_rccal_lpc = ((int)best_rccal[rx_core] - 12) + 10;
+
+ if (PHY_IPA(pi)) {
+ txlpf_rccal_lpc +=
+ (pi->bw == WL_CHANSPEC_BW_40) ? 24 : 12;
+ txlpf_idac = (pi->bw == WL_CHANSPEC_BW_40) ?
+ 0x0e : 0x13;
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, rx_core,
+ TXLPF_IDAC_4, txlpf_idac);
+ }
+
+ rxlpf_rccal_hpc = max(min_t(u8, rxlpf_rccal_hpc, 31),
+ 0);
+ txlpf_rccal_lpc = max(min_t(u8, txlpf_rccal_lpc, 31),
+ 0);
+
+ write_radio_reg(pi, (RADIO_2056_RX_RXLPF_RCCAL_HPC |
+ ((rx_core ==
+ PHY_CORE_0) ? RADIO_2056_RX0 :
+ RADIO_2056_RX1)),
+ (rxlpf_rccal_hpc | 0x80));
+
+ write_radio_reg(pi, (RADIO_2056_TX_TXLPF_RCCAL |
+ ((rx_core ==
+ PHY_CORE_0) ? RADIO_2056_TX0 :
+ RADIO_2056_TX1)),
+ (txlpf_rccal_lpc | 0x80));
+ }
+ }
+
+ write_phy_reg(pi, 0x01, orig_BBConfig);
+
+ wlc_phy_resetcca_nphy(pi);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ wlc_phy_rfctrl_override_1tomany_nphy(
+ pi,
+ NPHY_REV7_RfctrlOverride_cmd_rxgain,
+ 0, 0x3, 1);
+ else
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 12), 0, 0x3, 1);
+
+ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16,
+ gain_save);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 4))
+ pi->phyhang_avoid = phyhang_avoid_state;
+
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+
+ return 0;
+}
+
+static int
+wlc_phy_cal_rxiq_nphy_rev2(struct brcms_phy *pi,
+ struct nphy_txgains target_gain, bool debug)
+{
+ struct phy_iq_est est[PHY_CORE_MAX];
+ u8 core_num, rx_core, tx_core;
+ u16 lna_vals[] = { 0x3, 0x3, 0x1 };
+ u16 hpf1_vals[] = { 0x7, 0x2, 0x0 };
+ u16 hpf2_vals[] = { 0x2, 0x0, 0x0 };
+ s16 curr_hpf1, curr_hpf2, curr_hpf, curr_lna;
+ s16 desired_log2_pwr, actual_log2_pwr, hpf_change;
+ u16 orig_RfseqCoreActv, orig_AfectrlCore, orig_AfectrlOverride;
+ u16 orig_RfctrlIntcRx, orig_RfctrlIntcTx;
+ u16 num_samps;
+ u32 i_pwr, q_pwr, tot_pwr[3];
+ u8 gain_pass, use_hpf_num;
+ u16 mask, val1, val2;
+ u16 core_no;
+ u16 gain_save[2];
+ u16 cal_gain[2];
+ struct nphy_iqcal_params cal_params[2];
+ u8 phy_bw;
+ int bcmerror = 0;
+ bool first_playtone = true;
+
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ if (NREV_LT(pi->pubpi.phy_rev, 2))
+ wlc_phy_reapply_txcal_coeffs_nphy(pi);
+
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, gain_save);
+
+ for (core_no = 0; core_no <= 1; core_no++) {
+ wlc_phy_iqcal_gainparams_nphy(pi, core_no, target_gain,
+ &cal_params[core_no]);
+ cal_gain[core_no] = cal_params[core_no].cal_gain;
+ }
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, cal_gain);
+
+ num_samps = 1024;
+ desired_log2_pwr = 13;
+
+ for (core_num = 0; core_num < 2; core_num++) {
+
+ rx_core = core_num;
+ tx_core = 1 - core_num;
+
+ orig_RfseqCoreActv = read_phy_reg(pi, 0xa2);
+ orig_AfectrlCore = read_phy_reg(pi, (rx_core == PHY_CORE_0) ?
+ 0xa6 : 0xa7);
+ orig_AfectrlOverride = read_phy_reg(pi, 0xa5);
+ orig_RfctrlIntcRx = read_phy_reg(pi, (rx_core == PHY_CORE_0) ?
+ 0x91 : 0x92);
+ orig_RfctrlIntcTx = read_phy_reg(pi, (tx_core == PHY_CORE_0) ?
+ 0x91 : 0x92);
+
+ mod_phy_reg(pi, 0xa2, (0xf << 12), (1 << tx_core) << 12);
+ mod_phy_reg(pi, 0xa2, (0xf << 0), (1 << tx_core) << 0);
+
+ or_phy_reg(pi, ((rx_core == PHY_CORE_0) ? 0xa6 : 0xa7),
+ ((0x1 << 1) | (0x1 << 2)));
+ or_phy_reg(pi, 0xa5, ((0x1 << 1) | (0x1 << 2)));
+
+ if (((pi->nphy_rxcalparams) & 0xff000000))
+ write_phy_reg(pi,
+ (rx_core == PHY_CORE_0) ? 0x91 : 0x92,
+ (CHSPEC_IS5G(pi->radio_chanspec) ?
+ 0x140 : 0x110));
+ else
+ write_phy_reg(pi,
+ (rx_core == PHY_CORE_0) ? 0x91 : 0x92,
+ (CHSPEC_IS5G(pi->radio_chanspec) ?
+ 0x180 : 0x120));
+
+ write_phy_reg(pi, (tx_core == PHY_CORE_0) ? 0x91 : 0x92,
+ (CHSPEC_IS5G(pi->radio_chanspec) ? 0x148 :
+ 0x114));
+
+ mask = RADIO_2055_COUPLE_RX_MASK | RADIO_2055_COUPLE_TX_MASK;
+ if (rx_core == PHY_CORE_0) {
+ val1 = RADIO_2055_COUPLE_RX_MASK;
+ val2 = RADIO_2055_COUPLE_TX_MASK;
+ } else {
+ val1 = RADIO_2055_COUPLE_TX_MASK;
+ val2 = RADIO_2055_COUPLE_RX_MASK;
+ }
+
+ if ((pi->nphy_rxcalparams & 0x10000)) {
+ mod_radio_reg(pi, RADIO_2055_CORE1_GEN_SPARE2, mask,
+ val1);
+ mod_radio_reg(pi, RADIO_2055_CORE2_GEN_SPARE2, mask,
+ val2);
+ }
+
+ for (gain_pass = 0; gain_pass < 4; gain_pass++) {
+
+ if (debug)
+ mdelay(WAIT_FOR_SCOPE);
+
+ if (gain_pass < 3) {
+ curr_lna = lna_vals[gain_pass];
+ curr_hpf1 = hpf1_vals[gain_pass];
+ curr_hpf2 = hpf2_vals[gain_pass];
+ } else {
+
+ if (tot_pwr[1] > 10000) {
+ curr_lna = lna_vals[2];
+ curr_hpf1 = hpf1_vals[2];
+ curr_hpf2 = hpf2_vals[2];
+ use_hpf_num = 1;
+ curr_hpf = curr_hpf1;
+ actual_log2_pwr =
+ wlc_phy_nbits(tot_pwr[2]);
+ } else {
+ if (tot_pwr[0] > 10000) {
+ curr_lna = lna_vals[1];
+ curr_hpf1 = hpf1_vals[1];
+ curr_hpf2 = hpf2_vals[1];
+ use_hpf_num = 1;
+ curr_hpf = curr_hpf1;
+ actual_log2_pwr =
+ wlc_phy_nbits(
+ tot_pwr[1]);
+ } else {
+ curr_lna = lna_vals[0];
+ curr_hpf1 = hpf1_vals[0];
+ curr_hpf2 = hpf2_vals[0];
+ use_hpf_num = 2;
+ curr_hpf = curr_hpf2;
+ actual_log2_pwr =
+ wlc_phy_nbits(
+ tot_pwr[0]);
+ }
+ }
+
+ hpf_change = desired_log2_pwr - actual_log2_pwr;
+ curr_hpf += hpf_change;
+ curr_hpf = max(min_t(u16, curr_hpf, 10), 0);
+ if (use_hpf_num == 1)
+ curr_hpf1 = curr_hpf;
+ else
+ curr_hpf2 = curr_hpf;
+ }
+
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 10),
+ ((curr_hpf2 << 8) |
+ (curr_hpf1 << 4) |
+ (curr_lna << 2)), 0x3, 0);
+ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX);
+
+ wlc_phy_stopplayback_nphy(pi);
+
+ if (first_playtone) {
+ bcmerror = wlc_phy_tx_tone_nphy(pi, 4000,
+ (u16) (pi->nphy_rxcalparams &
+ 0xffff), 0, 0, true);
+ first_playtone = false;
+ } else {
+ phy_bw = (CHSPEC_IS40(pi->radio_chanspec)) ?
+ 40 : 20;
+ wlc_phy_runsamples_nphy(pi, phy_bw * 8, 0xffff,
+ 0, 0, 0, true);
+ }
+
+ if (bcmerror == 0) {
+ if (gain_pass < 3) {
+
+ wlc_phy_rx_iq_est_nphy(pi, est,
+ num_samps, 32,
+ 0);
+ i_pwr = (est[rx_core].i_pwr +
+ num_samps / 2) / num_samps;
+ q_pwr = (est[rx_core].q_pwr +
+ num_samps / 2) / num_samps;
+ tot_pwr[gain_pass] = i_pwr + q_pwr;
+ } else {
+
+ wlc_phy_calc_rx_iq_comp_nphy(pi,
+ (1 <<
+ rx_core));
+ }
+
+ wlc_phy_stopplayback_nphy(pi);
+ }
+
+ if (bcmerror != 0)
+ break;
+ }
+
+ and_radio_reg(pi, RADIO_2055_CORE1_GEN_SPARE2, ~mask);
+ and_radio_reg(pi, RADIO_2055_CORE2_GEN_SPARE2, ~mask);
+
+ write_phy_reg(pi, (tx_core == PHY_CORE_0) ? 0x91 :
+ 0x92, orig_RfctrlIntcTx);
+ write_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0x91 :
+ 0x92, orig_RfctrlIntcRx);
+ write_phy_reg(pi, 0xa5, orig_AfectrlOverride);
+ write_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0xa6 :
+ 0xa7, orig_AfectrlCore);
+ write_phy_reg(pi, 0xa2, orig_RfseqCoreActv);
+
+ if (bcmerror != 0)
+ break;
+ }
+
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 10), 0, 0x3, 1);
+ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16,
+ gain_save);
+
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+
+ return bcmerror;
+}
+
+int
+wlc_phy_cal_rxiq_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain,
+ u8 cal_type, bool debug)
+{
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ cal_type = 0;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
+ return wlc_phy_cal_rxiq_nphy_rev3(pi, target_gain, cal_type,
+ debug);
+ else
+ return wlc_phy_cal_rxiq_nphy_rev2(pi, target_gain, debug);
+}
+
+void wlc_phy_txpwr_fixpower_nphy(struct brcms_phy *pi)
+{
+ uint core;
+ u32 txgain;
+ u16 rad_gain, dac_gain, bbmult, m1m2;
+ u8 txpi[2], chan_freq_range;
+ s32 rfpwr_offset;
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ if (pi->sh->sromrev < 4) {
+ txpi[0] = txpi[1] = 72;
+ } else {
+
+ chan_freq_range = wlc_phy_get_chan_freq_range_nphy(pi, 0);
+ switch (chan_freq_range) {
+ case WL_CHAN_FREQ_RANGE_2G:
+ txpi[0] = pi->nphy_txpid2g[0];
+ txpi[1] = pi->nphy_txpid2g[1];
+ break;
+ case WL_CHAN_FREQ_RANGE_5GL:
+ txpi[0] = pi->nphy_txpid5gl[0];
+ txpi[1] = pi->nphy_txpid5gl[1];
+ break;
+ case WL_CHAN_FREQ_RANGE_5GM:
+ txpi[0] = pi->nphy_txpid5g[0];
+ txpi[1] = pi->nphy_txpid5g[1];
+ break;
+ case WL_CHAN_FREQ_RANGE_5GH:
+ txpi[0] = pi->nphy_txpid5gh[0];
+ txpi[1] = pi->nphy_txpid5gh[1];
+ break;
+ default:
+ txpi[0] = txpi[1] = 91;
+ break;
+ }
+ }
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ txpi[0] = txpi[1] = 30;
+ else if (NREV_GE(pi->pubpi.phy_rev, 3))
+ txpi[0] = txpi[1] = 40;
+
+ if (NREV_LT(pi->pubpi.phy_rev, 7)) {
+
+ if ((txpi[0] < 40) || (txpi[0] > 100) ||
+ (txpi[1] < 40) || (txpi[1] > 100))
+ txpi[0] = txpi[1] = 91;
+ }
+
+ pi->nphy_txpwrindex[PHY_CORE_0].index_internal = txpi[0];
+ pi->nphy_txpwrindex[PHY_CORE_1].index_internal = txpi[1];
+ pi->nphy_txpwrindex[PHY_CORE_0].index_internal_save = txpi[0];
+ pi->nphy_txpwrindex[PHY_CORE_1].index_internal_save = txpi[1];
+
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+ uint phyrev = pi->pubpi.phy_rev;
+
+ if (NREV_GE(phyrev, 3)) {
+ if (PHY_IPA(pi)) {
+ u32 *tx_gaintbl =
+ wlc_phy_get_ipa_gaintbl_nphy(pi);
+ txgain = tx_gaintbl[txpi[core]];
+ } else {
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ if (NREV_IS(phyrev, 3)) {
+ txgain =
+ nphy_tpc_5GHz_txgain_rev3
+ [txpi[core]];
+ } else if (NREV_IS(phyrev, 4)) {
+ txgain = (
+ pi->srom_fem5g.extpagain ==
+ 3) ?
+ nphy_tpc_5GHz_txgain_HiPwrEPA
+ [txpi[core]] :
+ nphy_tpc_5GHz_txgain_rev4
+ [txpi[core]];
+ } else {
+ txgain =
+ nphy_tpc_5GHz_txgain_rev5
+ [txpi[core]];
+ }
+ } else {
+ if (NREV_GE(phyrev, 5) &&
+ (pi->srom_fem2g.extpagain == 3)) {
+ txgain =
+ nphy_tpc_txgain_HiPwrEPA
+ [txpi[core]];
+ } else {
+ txgain = nphy_tpc_txgain_rev3
+ [txpi[core]];
+ }
+ }
+ }
+ } else {
+ txgain = nphy_tpc_txgain[txpi[core]];
+ }
+
+ if (NREV_GE(phyrev, 3))
+ rad_gain = (txgain >> 16) & ((1 << (32 - 16 + 1)) - 1);
+ else
+ rad_gain = (txgain >> 16) & ((1 << (28 - 16 + 1)) - 1);
+
+ if (NREV_GE(phyrev, 7))
+ dac_gain = (txgain >> 8) & ((1 << (10 - 8 + 1)) - 1);
+ else
+ dac_gain = (txgain >> 8) & ((1 << (13 - 8 + 1)) - 1);
+
+ bbmult = (txgain >> 0) & ((1 << (7 - 0 + 1)) - 1);
+
+ if (NREV_GE(phyrev, 3))
+ mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0x8f :
+ 0xa5), (0x1 << 8), (0x1 << 8));
+ else
+ mod_phy_reg(pi, 0xa5, (0x1 << 14), (0x1 << 14));
+
+ write_phy_reg(pi, (core == PHY_CORE_0) ? 0xaa : 0xab, dac_gain);
+
+ wlc_phy_table_write_nphy(pi, 7, 1, (0x110 + core), 16,
+ &rad_gain);
+
+ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &m1m2);
+ m1m2 &= ((core == PHY_CORE_0) ? 0x00ff : 0xff00);
+ m1m2 |= ((core == PHY_CORE_0) ? (bbmult << 8) : (bbmult << 0));
+ wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &m1m2);
+
+ if (PHY_IPA(pi)) {
+ wlc_phy_table_read_nphy(pi,
+ (core ==
+ PHY_CORE_0 ?
+ NPHY_TBL_ID_CORE1TXPWRCTL :
+ NPHY_TBL_ID_CORE2TXPWRCTL), 1,
+ 576 + txpi[core], 32,
+ &rfpwr_offset);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1ff << 4),
+ ((s16) rfpwr_offset) << 4);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 2), (1) << 2);
+
+ }
+ }
+
+ and_phy_reg(pi, 0xbf, (u16) (~(0x1f << 0)));
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+}
+
+static void
+wlc_phy_txpwr_nphy_srom_convert(u8 *srom_max, u16 *pwr_offset,
+ u8 tmp_max_pwr, u8 rate_start,
+ u8 rate_end)
+{
+ u8 rate;
+ u8 word_num, nibble_num;
+ u8 tmp_nibble;
+
+ for (rate = rate_start; rate <= rate_end; rate++) {
+ word_num = (rate - rate_start) >> 2;
+ nibble_num = (rate - rate_start) & 0x3;
+ tmp_nibble = (pwr_offset[word_num] >> 4 * nibble_num) & 0xf;
+
+ srom_max[rate] = tmp_max_pwr - 2 * tmp_nibble;
+ }
+}
+
+static void
+wlc_phy_txpwr_nphy_po_apply(u8 *srom_max, u8 pwr_offset,
+ u8 rate_start, u8 rate_end)
+{
+ u8 rate;
+
+ for (rate = rate_start; rate <= rate_end; rate++)
+ srom_max[rate] -= 2 * pwr_offset;
+}
+
+void
+wlc_phy_ofdm_to_mcs_powers_nphy(u8 *power, u8 rate_mcs_start,
+ u8 rate_mcs_end, u8 rate_ofdm_start)
+{
+ u8 rate1, rate2;
+
+ rate2 = rate_ofdm_start;
+ for (rate1 = rate_mcs_start; rate1 <= rate_mcs_end - 1; rate1++) {
+ power[rate1] = power[rate2];
+ rate2 += (rate1 == rate_mcs_start) ? 2 : 1;
+ }
+ power[rate_mcs_end] = power[rate_mcs_end - 1];
+}
+
+void
+wlc_phy_mcs_to_ofdm_powers_nphy(u8 *power, u8 rate_ofdm_start,
+ u8 rate_ofdm_end, u8 rate_mcs_start)
+{
+ u8 rate1, rate2;
+
+ for (rate1 = rate_ofdm_start, rate2 = rate_mcs_start;
+ rate1 <= rate_ofdm_end; rate1++, rate2++) {
+ power[rate1] = power[rate2];
+ if (rate1 == rate_ofdm_start)
+ power[++rate1] = power[rate2];
+ }
+}
+
+void wlc_phy_txpwr_apply_nphy(struct brcms_phy *pi)
+{
+ uint rate1, rate2, band_num;
+ u8 tmp_bw40po = 0, tmp_cddpo = 0, tmp_stbcpo = 0;
+ u8 tmp_max_pwr = 0;
+ u16 pwr_offsets1[2], *pwr_offsets2 = NULL;
+ u8 *tx_srom_max_rate = NULL;
+
+ for (band_num = 0; band_num < (CH_2G_GROUP + CH_5G_GROUP);
+ band_num++) {
+ switch (band_num) {
+ case 0:
+
+ tmp_max_pwr = min(pi->nphy_pwrctrl_info[0].max_pwr_2g,
+ pi->nphy_pwrctrl_info[1].max_pwr_2g);
+
+ pwr_offsets1[0] = pi->cck2gpo;
+ wlc_phy_txpwr_nphy_srom_convert(pi->tx_srom_max_rate_2g,
+ pwr_offsets1,
+ tmp_max_pwr,
+ TXP_FIRST_CCK,
+ TXP_LAST_CCK);
+
+ pwr_offsets1[0] = (u16) (pi->ofdm2gpo & 0xffff);
+ pwr_offsets1[1] =
+ (u16) (pi->ofdm2gpo >> 16) & 0xffff;
+
+ pwr_offsets2 = pi->mcs2gpo;
+
+ tmp_cddpo = pi->cdd2gpo;
+ tmp_stbcpo = pi->stbc2gpo;
+ tmp_bw40po = pi->bw402gpo;
+
+ tx_srom_max_rate = pi->tx_srom_max_rate_2g;
+ break;
+ case 1:
+
+ tmp_max_pwr = min(pi->nphy_pwrctrl_info[0].max_pwr_5gm,
+ pi->nphy_pwrctrl_info[1].max_pwr_5gm);
+
+ pwr_offsets1[0] = (u16) (pi->ofdm5gpo & 0xffff);
+ pwr_offsets1[1] =
+ (u16) (pi->ofdm5gpo >> 16) & 0xffff;
+
+ pwr_offsets2 = pi->mcs5gpo;
+
+ tmp_cddpo = pi->cdd5gpo;
+ tmp_stbcpo = pi->stbc5gpo;
+ tmp_bw40po = pi->bw405gpo;
+
+ tx_srom_max_rate = pi->tx_srom_max_rate_5g_mid;
+ break;
+ case 2:
+
+ tmp_max_pwr = min(pi->nphy_pwrctrl_info[0].max_pwr_5gl,
+ pi->nphy_pwrctrl_info[1].max_pwr_5gl);
+
+ pwr_offsets1[0] = (u16) (pi->ofdm5glpo & 0xffff);
+ pwr_offsets1[1] =
+ (u16) (pi->ofdm5glpo >> 16) & 0xffff;
+
+ pwr_offsets2 = pi->mcs5glpo;
+
+ tmp_cddpo = pi->cdd5glpo;
+ tmp_stbcpo = pi->stbc5glpo;
+ tmp_bw40po = pi->bw405glpo;
+
+ tx_srom_max_rate = pi->tx_srom_max_rate_5g_low;
+ break;
+ case 3:
+
+ tmp_max_pwr = min(pi->nphy_pwrctrl_info[0].max_pwr_5gh,
+ pi->nphy_pwrctrl_info[1].max_pwr_5gh);
+
+ pwr_offsets1[0] = (u16) (pi->ofdm5ghpo & 0xffff);
+ pwr_offsets1[1] =
+ (u16) (pi->ofdm5ghpo >> 16) & 0xffff;
+
+ pwr_offsets2 = pi->mcs5ghpo;
+
+ tmp_cddpo = pi->cdd5ghpo;
+ tmp_stbcpo = pi->stbc5ghpo;
+ tmp_bw40po = pi->bw405ghpo;
+
+ tx_srom_max_rate = pi->tx_srom_max_rate_5g_hi;
+ break;
+ }
+
+ wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate, pwr_offsets1,
+ tmp_max_pwr, TXP_FIRST_OFDM,
+ TXP_LAST_OFDM);
+
+ wlc_phy_ofdm_to_mcs_powers_nphy(tx_srom_max_rate,
+ TXP_FIRST_MCS_20_SISO,
+ TXP_LAST_MCS_20_SISO,
+ TXP_FIRST_OFDM);
+
+ wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate, pwr_offsets2,
+ tmp_max_pwr,
+ TXP_FIRST_MCS_20_CDD,
+ TXP_LAST_MCS_20_CDD);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
+ wlc_phy_txpwr_nphy_po_apply(tx_srom_max_rate, tmp_cddpo,
+ TXP_FIRST_MCS_20_CDD,
+ TXP_LAST_MCS_20_CDD);
+
+ wlc_phy_mcs_to_ofdm_powers_nphy(tx_srom_max_rate,
+ TXP_FIRST_OFDM_20_CDD,
+ TXP_LAST_OFDM_20_CDD,
+ TXP_FIRST_MCS_20_CDD);
+
+ wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate, pwr_offsets2,
+ tmp_max_pwr,
+ TXP_FIRST_MCS_20_STBC,
+ TXP_LAST_MCS_20_STBC);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
+ wlc_phy_txpwr_nphy_po_apply(tx_srom_max_rate,
+ tmp_stbcpo,
+ TXP_FIRST_MCS_20_STBC,
+ TXP_LAST_MCS_20_STBC);
+
+ wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate,
+ &pwr_offsets2[2], tmp_max_pwr,
+ TXP_FIRST_MCS_20_SDM,
+ TXP_LAST_MCS_20_SDM);
+
+ if (NPHY_IS_SROM_REINTERPRET) {
+
+ wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate,
+ &pwr_offsets2[4],
+ tmp_max_pwr,
+ TXP_FIRST_MCS_40_SISO,
+ TXP_LAST_MCS_40_SISO);
+
+ wlc_phy_mcs_to_ofdm_powers_nphy(tx_srom_max_rate,
+ TXP_FIRST_OFDM_40_SISO,
+ TXP_LAST_OFDM_40_SISO,
+ TXP_FIRST_MCS_40_SISO);
+
+ wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate,
+ &pwr_offsets2[4],
+ tmp_max_pwr,
+ TXP_FIRST_MCS_40_CDD,
+ TXP_LAST_MCS_40_CDD);
+
+ wlc_phy_txpwr_nphy_po_apply(tx_srom_max_rate, tmp_cddpo,
+ TXP_FIRST_MCS_40_CDD,
+ TXP_LAST_MCS_40_CDD);
+
+ wlc_phy_mcs_to_ofdm_powers_nphy(tx_srom_max_rate,
+ TXP_FIRST_OFDM_40_CDD,
+ TXP_LAST_OFDM_40_CDD,
+ TXP_FIRST_MCS_40_CDD);
+
+ wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate,
+ &pwr_offsets2[4],
+ tmp_max_pwr,
+ TXP_FIRST_MCS_40_STBC,
+ TXP_LAST_MCS_40_STBC);
+
+ wlc_phy_txpwr_nphy_po_apply(tx_srom_max_rate,
+ tmp_stbcpo,
+ TXP_FIRST_MCS_40_STBC,
+ TXP_LAST_MCS_40_STBC);
+
+ wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate,
+ &pwr_offsets2[6],
+ tmp_max_pwr,
+ TXP_FIRST_MCS_40_SDM,
+ TXP_LAST_MCS_40_SDM);
+ } else {
+
+ for (rate1 = TXP_FIRST_OFDM_40_SISO, rate2 =
+ TXP_FIRST_OFDM;
+ rate1 <= TXP_LAST_MCS_40_SDM;
+ rate1++, rate2++)
+ tx_srom_max_rate[rate1] =
+ tx_srom_max_rate[rate2];
+ }
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
+ wlc_phy_txpwr_nphy_po_apply(tx_srom_max_rate,
+ tmp_bw40po,
+ TXP_FIRST_OFDM_40_SISO,
+ TXP_LAST_MCS_40_SDM);
+
+ tx_srom_max_rate[TXP_MCS_32] =
+ tx_srom_max_rate[TXP_FIRST_MCS_40_CDD];
+ }
+
+ return;
+}
+
+void wlc_phy_txpower_recalc_target_nphy(struct brcms_phy *pi)
+{
+ u8 tx_pwr_ctrl_state;
+ wlc_phy_txpwr_limit_to_tbl_nphy(pi);
+ wlc_phy_txpwrctrl_pwr_setup_nphy(pi);
+
+ tx_pwr_ctrl_state = pi->nphy_txpwrctrl;
+
+ if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) {
+ wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, MCTL_PHYLOCK);
+ (void)R_REG(&pi->regs->maccontrol);
+ udelay(1);
+ }
+
+ wlc_phy_txpwrctrl_enable_nphy(pi, tx_pwr_ctrl_state);
+
+ if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
+ wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, 0);
+}
+
+static bool wlc_phy_txpwr_ison_nphy(struct brcms_phy *pi)
+{
+ return read_phy_reg((pi), 0x1e7) & ((0x1 << 15) |
+ (0x1 << 14) | (0x1 << 13));
+}
+
+u16 wlc_phy_txpwr_idx_get_nphy(struct brcms_phy *pi)
+{
+ u16 tmp;
+ u16 pwr_idx[2];
+
+ if (wlc_phy_txpwr_ison_nphy(pi)) {
+ pwr_idx[0] = wlc_phy_txpwr_idx_cur_get_nphy(pi, PHY_CORE_0);
+ pwr_idx[1] = wlc_phy_txpwr_idx_cur_get_nphy(pi, PHY_CORE_1);
+
+ tmp = (pwr_idx[0] << 8) | pwr_idx[1];
+ } else {
+ tmp = ((pi->nphy_txpwrindex[PHY_CORE_0].index_internal & 0xff)
+ << 8) |
+ (pi->nphy_txpwrindex[PHY_CORE_1].index_internal & 0xff);
+ }
+
+ return tmp;
+}
+
+void wlc_phy_txpwr_papd_cal_nphy(struct brcms_phy *pi)
+{
+ if (PHY_IPA(pi)
+ && (pi->nphy_force_papd_cal
+ || (wlc_phy_txpwr_ison_nphy(pi)
+ &&
+ (((u32)
+ abs(wlc_phy_txpwr_idx_cur_get_nphy(pi, 0) -
+ pi->nphy_papd_tx_gain_at_last_cal[0]) >= 4)
+ || ((u32)
+ abs(wlc_phy_txpwr_idx_cur_get_nphy(pi, 1) -
+ pi->nphy_papd_tx_gain_at_last_cal[1]) >= 4)))))
+ wlc_phy_a4(pi, true);
+}
+
+void wlc_phy_txpwrctrl_enable_nphy(struct brcms_phy *pi, u8 ctrl_type)
+{
+ u16 mask = 0, val = 0, ishw = 0;
+ u8 ctr;
+ uint core;
+ u32 tbl_offset;
+ u32 tbl_len;
+ u16 regval[84];
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ switch (ctrl_type) {
+ case PHY_TPC_HW_OFF:
+ case PHY_TPC_HW_ON:
+ pi->nphy_txpwrctrl = ctrl_type;
+ break;
+ default:
+ break;
+ }
+
+ if (ctrl_type == PHY_TPC_HW_OFF) {
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+
+ if (wlc_phy_txpwr_ison_nphy(pi)) {
+ for (core = 0; core < pi->pubpi.phy_corenum;
+ core++)
+ pi->nphy_txpwr_idx[core] =
+ wlc_phy_txpwr_idx_cur_get_nphy(
+ pi,
+ (u8) core);
+ }
+
+ }
+
+ tbl_len = 84;
+ tbl_offset = 64;
+ for (ctr = 0; ctr < tbl_len; ctr++)
+ regval[ctr] = 0;
+ wlc_phy_table_write_nphy(pi, 26, tbl_len, tbl_offset, 16,
+ regval);
+ wlc_phy_table_write_nphy(pi, 27, tbl_len, tbl_offset, 16,
+ regval);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
+ and_phy_reg(pi, 0x1e7,
+ (u16) (~((0x1 << 15) |
+ (0x1 << 14) | (0x1 << 13))));
+ else
+ and_phy_reg(pi, 0x1e7,
+ (u16) (~((0x1 << 14) | (0x1 << 13))));
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ or_phy_reg(pi, 0x8f, (0x1 << 8));
+ or_phy_reg(pi, 0xa5, (0x1 << 8));
+ } else {
+ or_phy_reg(pi, 0xa5, (0x1 << 14));
+ }
+
+ if (NREV_IS(pi->pubpi.phy_rev, 2))
+ mod_phy_reg(pi, 0xdc, 0x00ff, 0x53);
+ else if (NREV_LT(pi->pubpi.phy_rev, 2))
+ mod_phy_reg(pi, 0xdc, 0x00ff, 0x5a);
+
+ if (NREV_LT(pi->pubpi.phy_rev, 2) &&
+ pi->bw == WL_CHANSPEC_BW_40)
+ wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_IQSWAP_WAR,
+ MHF1_IQSWAP_WAR, BRCM_BAND_ALL);
+
+ } else {
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE1TXPWRCTL, 84, 64,
+ 8, pi->adj_pwr_tbl_nphy);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE2TXPWRCTL, 84, 64,
+ 8, pi->adj_pwr_tbl_nphy);
+
+ ishw = (ctrl_type == PHY_TPC_HW_ON) ? 0x1 : 0x0;
+ mask = (0x1 << 14) | (0x1 << 13);
+ val = (ishw << 14) | (ishw << 13);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ mask |= (0x1 << 15);
+ val |= (ishw << 15);
+ }
+
+ mod_phy_reg(pi, 0x1e7, mask, val);
+
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ mod_phy_reg(pi, 0x1e7, (0x7f << 0), 0x32);
+ mod_phy_reg(pi, 0x222, (0xff << 0), 0x32);
+ } else {
+ mod_phy_reg(pi, 0x1e7, (0x7f << 0), 0x64);
+ if (NREV_GT(pi->pubpi.phy_rev, 1))
+ mod_phy_reg(pi, 0x222,
+ (0xff << 0), 0x64);
+ }
+ }
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ if ((pi->nphy_txpwr_idx[0] != 128)
+ && (pi->nphy_txpwr_idx[1] != 128))
+ wlc_phy_txpwr_idx_cur_set_nphy(pi,
+ pi->
+ nphy_txpwr_idx
+ [0],
+ pi->
+ nphy_txpwr_idx
+ [1]);
+ }
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ and_phy_reg(pi, 0x8f, ~(0x1 << 8));
+ and_phy_reg(pi, 0xa5, ~(0x1 << 8));
+ } else {
+ and_phy_reg(pi, 0xa5, ~(0x1 << 14));
+ }
+
+ if (NREV_IS(pi->pubpi.phy_rev, 2))
+ mod_phy_reg(pi, 0xdc, 0x00ff, 0x3b);
+ else if (NREV_LT(pi->pubpi.phy_rev, 2))
+ mod_phy_reg(pi, 0xdc, 0x00ff, 0x40);
+
+ if (NREV_LT(pi->pubpi.phy_rev, 2) &&
+ pi->bw == WL_CHANSPEC_BW_40)
+ wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_IQSWAP_WAR,
+ 0x0, BRCM_BAND_ALL);
+
+ if (PHY_IPA(pi)) {
+ mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 2), (0) << 2);
+
+ mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 2), (0) << 2);
+
+ }
+
+ }
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+}
+
+void
+wlc_phy_txpwr_index_nphy(struct brcms_phy *pi, u8 core_mask, s8 txpwrindex,
+ bool restore_cals)
+{
+ u8 core, txpwrctl_tbl;
+ u16 tx_ind0, iq_ind0, lo_ind0;
+ u16 m1m2;
+ u32 txgain;
+ u16 rad_gain, dac_gain;
+ u8 bbmult;
+ u32 iqcomp;
+ u16 iqcomp_a, iqcomp_b;
+ u32 locomp;
+ u16 tmpval;
+ u8 tx_pwr_ctrl_state;
+ s32 rfpwr_offset;
+ u16 regval[2];
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ tx_ind0 = 192;
+ iq_ind0 = 320;
+ lo_ind0 = 448;
+
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+
+ if ((core_mask & (1 << core)) == 0)
+ continue;
+
+ txpwrctl_tbl = (core == PHY_CORE_0) ? 26 : 27;
+
+ if (txpwrindex < 0) {
+ if (pi->nphy_txpwrindex[core].index < 0)
+ continue;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ mod_phy_reg(pi, 0x8f,
+ (0x1 << 8),
+ pi->nphy_txpwrindex[core].
+ AfectrlOverride);
+ mod_phy_reg(pi, 0xa5, (0x1 << 8),
+ pi->nphy_txpwrindex[core].
+ AfectrlOverride);
+ } else {
+ mod_phy_reg(pi, 0xa5,
+ (0x1 << 14),
+ pi->nphy_txpwrindex[core].
+ AfectrlOverride);
+ }
+
+ write_phy_reg(pi, (core == PHY_CORE_0) ?
+ 0xaa : 0xab,
+ pi->nphy_txpwrindex[core].AfeCtrlDacGain);
+
+ wlc_phy_table_write_nphy(pi, 7, 1, (0x110 + core), 16,
+ &pi->nphy_txpwrindex[core].
+ rad_gain);
+
+ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &m1m2);
+ m1m2 &= ((core == PHY_CORE_0) ? 0x00ff : 0xff00);
+ m1m2 |= ((core == PHY_CORE_0) ?
+ (pi->nphy_txpwrindex[core].bbmult << 8) :
+ (pi->nphy_txpwrindex[core].bbmult << 0));
+ wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &m1m2);
+
+ if (restore_cals) {
+ wlc_phy_table_write_nphy(
+ pi, 15, 2, (80 + 2 * core), 16,
+ &pi->nphy_txpwrindex[core].iqcomp_a);
+ wlc_phy_table_write_nphy(
+ pi, 15, 1, (85 + core), 16,
+ &pi->nphy_txpwrindex[core].locomp);
+ wlc_phy_table_write_nphy(
+ pi, 15, 1, (93 + core), 16,
+ &pi->nphy_txpwrindex[core].locomp);
+ }
+
+ wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl);
+
+ pi->nphy_txpwrindex[core].index_internal =
+ pi->nphy_txpwrindex[core].index_internal_save;
+ } else {
+
+ if (pi->nphy_txpwrindex[core].index < 0) {
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ mod_phy_reg(pi, 0x8f,
+ (0x1 << 8),
+ pi->nphy_txpwrindex[core].
+ AfectrlOverride);
+ mod_phy_reg(pi, 0xa5, (0x1 << 8),
+ pi->nphy_txpwrindex[core].
+ AfectrlOverride);
+ } else {
+ pi->nphy_txpwrindex[core].
+ AfectrlOverride =
+ read_phy_reg(pi, 0xa5);
+ }
+
+ pi->nphy_txpwrindex[core].AfeCtrlDacGain =
+ read_phy_reg(pi, (core == PHY_CORE_0) ?
+ 0xaa : 0xab);
+
+ wlc_phy_table_read_nphy(pi, 7, 1,
+ (0x110 + core), 16,
+ &pi->
+ nphy_txpwrindex[core].
+ rad_gain);
+
+ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16,
+ &tmpval);
+ tmpval >>= ((core == PHY_CORE_0) ? 8 : 0);
+ tmpval &= 0xff;
+ pi->nphy_txpwrindex[core].bbmult = (u8) tmpval;
+
+ wlc_phy_table_read_nphy(pi, 15, 2,
+ (80 + 2 * core), 16,
+ &pi->
+ nphy_txpwrindex[core].
+ iqcomp_a);
+
+ wlc_phy_table_read_nphy(pi, 15, 1, (85 + core),
+ 16,
+ &pi->
+ nphy_txpwrindex[core].
+ locomp);
+
+ pi->nphy_txpwrindex[core].index_internal_save =
+ pi->nphy_txpwrindex[core].
+ index_internal;
+ }
+
+ tx_pwr_ctrl_state = pi->nphy_txpwrctrl;
+ wlc_phy_txpwrctrl_enable_nphy(pi, PHY_TPC_HW_OFF);
+
+ if (NREV_IS(pi->pubpi.phy_rev, 1))
+ wlapi_bmac_phyclk_fgc(pi->sh->physhim, ON);
+
+ wlc_phy_table_read_nphy(pi, txpwrctl_tbl, 1,
+ (tx_ind0 + txpwrindex), 32,
+ &txgain);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
+ rad_gain = (txgain >> 16) &
+ ((1 << (32 - 16 + 1)) - 1);
+ else
+ rad_gain = (txgain >> 16) &
+ ((1 << (28 - 16 + 1)) - 1);
+
+ dac_gain = (txgain >> 8) & ((1 << (13 - 8 + 1)) - 1);
+ bbmult = (txgain >> 0) & ((1 << (7 - 0 + 1)) - 1);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
+ mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0x8f :
+ 0xa5), (0x1 << 8), (0x1 << 8));
+ else
+ mod_phy_reg(pi, 0xa5, (0x1 << 14), (0x1 << 14));
+
+ write_phy_reg(pi, (core == PHY_CORE_0) ?
+ 0xaa : 0xab, dac_gain);
+
+ wlc_phy_table_write_nphy(pi, 7, 1, (0x110 + core), 16,
+ &rad_gain);
+
+ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &m1m2);
+ m1m2 &= ((core == PHY_CORE_0) ? 0x00ff : 0xff00);
+ m1m2 |= ((core == PHY_CORE_0) ?
+ (bbmult << 8) : (bbmult << 0));
+
+ wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &m1m2);
+
+ wlc_phy_table_read_nphy(pi, txpwrctl_tbl, 1,
+ (iq_ind0 + txpwrindex), 32,
+ &iqcomp);
+ iqcomp_a = (iqcomp >> 10) & ((1 << (19 - 10 + 1)) - 1);
+ iqcomp_b = (iqcomp >> 0) & ((1 << (9 - 0 + 1)) - 1);
+
+ if (restore_cals) {
+ regval[0] = (u16) iqcomp_a;
+ regval[1] = (u16) iqcomp_b;
+ wlc_phy_table_write_nphy(pi, 15, 2,
+ (80 + 2 * core), 16,
+ regval);
+ }
+
+ wlc_phy_table_read_nphy(pi, txpwrctl_tbl, 1,
+ (lo_ind0 + txpwrindex), 32,
+ &locomp);
+ if (restore_cals)
+ wlc_phy_table_write_nphy(pi, 15, 1, (85 + core),
+ 16, &locomp);
+
+ if (NREV_IS(pi->pubpi.phy_rev, 1))
+ wlapi_bmac_phyclk_fgc(pi->sh->physhim, OFF);
+
+ if (PHY_IPA(pi)) {
+ wlc_phy_table_read_nphy(pi,
+ (core == PHY_CORE_0 ?
+ NPHY_TBL_ID_CORE1TXPWRCTL :
+ NPHY_TBL_ID_CORE2TXPWRCTL),
+ 1, 576 + txpwrindex, 32,
+ &rfpwr_offset);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1ff << 4),
+ ((s16) rfpwr_offset) << 4);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 2), (1) << 2);
+
+ }
+
+ wlc_phy_txpwrctrl_enable_nphy(pi, tx_pwr_ctrl_state);
+ }
+
+ pi->nphy_txpwrindex[core].index = txpwrindex;
+ }
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+}
+
+void
+wlc_phy_txpower_sromlimit_get_nphy(struct brcms_phy *pi, uint chan, u8 *max_pwr,
+ u8 txp_rate_idx)
+{
+ u8 chan_freq_range;
+
+ chan_freq_range = wlc_phy_get_chan_freq_range_nphy(pi, chan);
+ switch (chan_freq_range) {
+ case WL_CHAN_FREQ_RANGE_2G:
+ *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx];
+ break;
+ case WL_CHAN_FREQ_RANGE_5GM:
+ *max_pwr = pi->tx_srom_max_rate_5g_mid[txp_rate_idx];
+ break;
+ case WL_CHAN_FREQ_RANGE_5GL:
+ *max_pwr = pi->tx_srom_max_rate_5g_low[txp_rate_idx];
+ break;
+ case WL_CHAN_FREQ_RANGE_5GH:
+ *max_pwr = pi->tx_srom_max_rate_5g_hi[txp_rate_idx];
+ break;
+ default:
+ *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx];
+ break;
+ }
+
+ return;
+}
+
+void wlc_phy_stay_in_carriersearch_nphy(struct brcms_phy *pi, bool enable)
+{
+ u16 clip_off[] = { 0xffff, 0xffff };
+
+ if (enable) {
+ if (pi->nphy_deaf_count == 0) {
+ pi->classifier_state =
+ wlc_phy_classifier_nphy(pi, 0, 0);
+ wlc_phy_classifier_nphy(pi, (0x7 << 0), 4);
+ wlc_phy_clip_det_nphy(pi, 0, pi->clip_state);
+ wlc_phy_clip_det_nphy(pi, 1, clip_off);
+ }
+
+ pi->nphy_deaf_count++;
+
+ wlc_phy_resetcca_nphy(pi);
+
+ } else {
+ pi->nphy_deaf_count--;
+
+ if (pi->nphy_deaf_count == 0) {
+ wlc_phy_classifier_nphy(pi, (0x7 << 0),
+ pi->classifier_state);
+ wlc_phy_clip_det_nphy(pi, 1, pi->clip_state);
+ }
+ }
+}
+
+void wlc_nphy_deaf_mode(struct brcms_phy *pi, bool mode)
+{
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
+
+ if (mode) {
+ if (pi->nphy_deaf_count == 0)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+ } else if (pi->nphy_deaf_count > 0) {
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+ }
+
+ wlapi_enable_mac(pi->sh->physhim);
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.c
new file mode 100644
index 000000000000..faf1ebe76068
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2010 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 "phy_qmath.h"
+
+/*
+ * Description: This function make 16 bit unsigned multiplication.
+ * To fit the output into 16 bits the 32 bit multiplication result is right
+ * shifted by 16 bits.
+ */
+u16 qm_mulu16(u16 op1, u16 op2)
+{
+ return (u16) (((u32) op1 * (u32) op2) >> 16);
+}
+
+/*
+ * Description: This function make 16 bit multiplication and return the result
+ * in 16 bits. To fit the multiplication result into 16 bits the multiplication
+ * result is right shifted by 15 bits. Right shifting 15 bits instead of 16 bits
+ * is done to remove the extra sign bit formed due to the multiplication.
+ * When both the 16bit inputs are 0x8000 then the output is saturated to
+ * 0x7fffffff.
+ */
+s16 qm_muls16(s16 op1, s16 op2)
+{
+ s32 result;
+ if (op1 == (s16) 0x8000 && op2 == (s16) 0x8000)
+ result = 0x7fffffff;
+ else
+ result = ((s32) (op1) * (s32) (op2));
+
+ return (s16) (result >> 15);
+}
+
+/*
+ * Description: This function add two 32 bit numbers and return the 32bit
+ * result. If the result overflow 32 bits, the output will be saturated to
+ * 32bits.
+ */
+s32 qm_add32(s32 op1, s32 op2)
+{
+ s32 result;
+ result = op1 + op2;
+ if (op1 < 0 && op2 < 0 && result > 0)
+ result = 0x80000000;
+ else if (op1 > 0 && op2 > 0 && result < 0)
+ result = 0x7fffffff;
+
+ return result;
+}
+
+/*
+ * Description: This function add two 16 bit numbers and return the 16bit
+ * result. If the result overflow 16 bits, the output will be saturated to
+ * 16bits.
+ */
+s16 qm_add16(s16 op1, s16 op2)
+{
+ s16 result;
+ s32 temp = (s32) op1 + (s32) op2;
+ if (temp > (s32) 0x7fff)
+ result = (s16) 0x7fff;
+ else if (temp < (s32) 0xffff8000)
+ result = (s16) 0xffff8000;
+ else
+ result = (s16) temp;
+
+ return result;
+}
+
+/*
+ * Description: This function make 16 bit subtraction and return the 16bit
+ * result. If the result overflow 16 bits, the output will be saturated to
+ * 16bits.
+ */
+s16 qm_sub16(s16 op1, s16 op2)
+{
+ s16 result;
+ s32 temp = (s32) op1 - (s32) op2;
+ if (temp > (s32) 0x7fff)
+ result = (s16) 0x7fff;
+ else if (temp < (s32) 0xffff8000)
+ result = (s16) 0xffff8000;
+ else
+ result = (s16) temp;
+
+ return result;
+}
+
+/*
+ * Description: This function make a 32 bit saturated left shift when the
+ * specified shift is +ve. This function will make a 32 bit right shift when
+ * the specified shift is -ve. This function return the result after shifting
+ * operation.
+ */
+s32 qm_shl32(s32 op, int shift)
+{
+ int i;
+ s32 result;
+ result = op;
+ if (shift > 31)
+ shift = 31;
+ else if (shift < -31)
+ shift = -31;
+ if (shift >= 0) {
+ for (i = 0; i < shift; i++)
+ result = qm_add32(result, result);
+ } else {
+ result = result >> (-shift);
+ }
+
+ return result;
+}
+
+/*
+ * Description: This function make a 16 bit saturated left shift when the
+ * specified shift is +ve. This function will make a 16 bit right shift when
+ * the specified shift is -ve. This function return the result after shifting
+ * operation.
+ */
+s16 qm_shl16(s16 op, int shift)
+{
+ int i;
+ s16 result;
+ result = op;
+ if (shift > 15)
+ shift = 15;
+ else if (shift < -15)
+ shift = -15;
+ if (shift > 0) {
+ for (i = 0; i < shift; i++)
+ result = qm_add16(result, result);
+ } else {
+ result = result >> (-shift);
+ }
+
+ return result;
+}
+
+/*
+ * Description: This function make a 16 bit right shift when shift is +ve.
+ * This function make a 16 bit saturated left shift when shift is -ve. This
+ * function return the result of the shift operation.
+ */
+s16 qm_shr16(s16 op, int shift)
+{
+ return qm_shl16(op, -shift);
+}
+
+/*
+ * Description: This function return the number of redundant sign bits in a
+ * 32 bit number. Example: qm_norm32(0x00000080) = 23
+ */
+s16 qm_norm32(s32 op)
+{
+ u16 u16extraSignBits;
+ if (op == 0) {
+ return 31;
+ } else {
+ u16extraSignBits = 0;
+ while ((op >> 31) == (op >> 30)) {
+ u16extraSignBits++;
+ op = op << 1;
+ }
+ }
+ return u16extraSignBits;
+}
+
+/* This table is log2(1+(i/32)) where i=[0:1:31], in q.15 format */
+static const s16 log_table[] = {
+ 0,
+ 1455,
+ 2866,
+ 4236,
+ 5568,
+ 6863,
+ 8124,
+ 9352,
+ 10549,
+ 11716,
+ 12855,
+ 13968,
+ 15055,
+ 16117,
+ 17156,
+ 18173,
+ 19168,
+ 20143,
+ 21098,
+ 22034,
+ 22952,
+ 23852,
+ 24736,
+ 25604,
+ 26455,
+ 27292,
+ 28114,
+ 28922,
+ 29717,
+ 30498,
+ 31267,
+ 32024
+};
+
+#define LOG_TABLE_SIZE 32 /* log_table size */
+#define LOG2_LOG_TABLE_SIZE 5 /* log2(log_table size) */
+#define Q_LOG_TABLE 15 /* qformat of log_table */
+#define LOG10_2 19728 /* log10(2) in q.16 */
+
+/*
+ * Description:
+ * This routine takes the input number N and its q format qN and compute
+ * the log10(N). This routine first normalizes the input no N. Then N is in
+ * mag*(2^x) format. mag is any number in the range 2^30-(2^31 - 1).
+ * Then log2(mag * 2^x) = log2(mag) + x is computed. From that
+ * log10(mag * 2^x) = log2(mag * 2^x) * log10(2) is computed.
+ * This routine looks the log2 value in the table considering
+ * LOG2_LOG_TABLE_SIZE+1 MSBs. As the MSB is always 1, only next
+ * LOG2_OF_LOG_TABLE_SIZE MSBs are used for table lookup. Next 16 MSBs are used
+ * for interpolation.
+ * Inputs:
+ * N - number to which log10 has to be found.
+ * qN - q format of N
+ * log10N - address where log10(N) will be written.
+ * qLog10N - address where log10N qformat will be written.
+ * Note/Problem:
+ * For accurate results input should be in normalized or near normalized form.
+ */
+void qm_log10(s32 N, s16 qN, s16 *log10N, s16 *qLog10N)
+{
+ s16 s16norm, s16tableIndex, s16errorApproximation;
+ u16 u16offset;
+ s32 s32log;
+
+ /* normalize the N. */
+ s16norm = qm_norm32(N);
+ N = N << s16norm;
+
+ /* The qformat of N after normalization.
+ * -30 is added to treat the no as between 1.0 to 2.0
+ * i.e. after adding the -30 to the qformat the decimal point will be
+ * just rigtht of the MSB. (i.e. after sign bit and 1st MSB). i.e.
+ * at the right side of 30th bit.
+ */
+ qN = qN + s16norm - 30;
+
+ /* take the table index as the LOG2_OF_LOG_TABLE_SIZE bits right of the
+ * MSB */
+ s16tableIndex = (s16) (N >> (32 - (2 + LOG2_LOG_TABLE_SIZE)));
+
+ /* remove the MSB. the MSB is always 1 after normalization. */
+ s16tableIndex =
+ s16tableIndex & (s16) ((1 << LOG2_LOG_TABLE_SIZE) - 1);
+
+ /* remove the (1+LOG2_OF_LOG_TABLE_SIZE) MSBs in the N. */
+ N = N & ((1 << (32 - (2 + LOG2_LOG_TABLE_SIZE))) - 1);
+
+ /* take the offset as the 16 MSBS after table index.
+ */
+ u16offset = (u16) (N >> (32 - (2 + LOG2_LOG_TABLE_SIZE + 16)));
+
+ /* look the log value in the table. */
+ s32log = log_table[s16tableIndex]; /* q.15 format */
+
+ /* interpolate using the offset. q.15 format. */
+ s16errorApproximation = (s16) qm_mulu16(u16offset,
+ (u16) (log_table[s16tableIndex + 1] -
+ log_table[s16tableIndex]));
+
+ /* q.15 format */
+ s32log = qm_add16((s16) s32log, s16errorApproximation);
+
+ /* adjust for the qformat of the N as
+ * log2(mag * 2^x) = log2(mag) + x
+ */
+ s32log = qm_add32(s32log, ((s32) -qN) << 15); /* q.15 format */
+
+ /* normalize the result. */
+ s16norm = qm_norm32(s32log);
+
+ /* bring all the important bits into lower 16 bits */
+ /* q.15+s16norm-16 format */
+ s32log = qm_shl32(s32log, s16norm - 16);
+
+ /* compute the log10(N) by multiplying log2(N) with log10(2).
+ * as log10(mag * 2^x) = log2(mag * 2^x) * log10(2)
+ * log10N in q.15+s16norm-16+1 (LOG10_2 is in q.16)
+ */
+ *log10N = qm_muls16((s16) s32log, (s16) LOG10_2);
+
+ /* write the q format of the result. */
+ *qLog10N = 15 + s16norm - 16 + 1;
+
+ return;
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.h
new file mode 100644
index 000000000000..20e3783f921b
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_QMATH_H_
+#define _BRCM_QMATH_H_
+
+#include <types.h>
+
+u16 qm_mulu16(u16 op1, u16 op2);
+
+s16 qm_muls16(s16 op1, s16 op2);
+
+s32 qm_add32(s32 op1, s32 op2);
+
+s16 qm_add16(s16 op1, s16 op2);
+
+s16 qm_sub16(s16 op1, s16 op2);
+
+s32 qm_shl32(s32 op, int shift);
+
+s16 qm_shl16(s16 op, int shift);
+
+s16 qm_shr16(s16 op, int shift);
+
+s16 qm_norm32(s32 op);
+
+void qm_log10(s32 N, s16 qN, s16 *log10N, s16 *qLog10N);
+
+#endif /* #ifndef _BRCM_QMATH_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_radio.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_radio.h
new file mode 100644
index 000000000000..c3a675455ff5
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_radio.h
@@ -0,0 +1,1533 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_PHY_RADIO_H_
+#define _BRCM_PHY_RADIO_H_
+
+#define RADIO_IDCODE 0x01
+
+#define RADIO_DEFAULT_CORE 0
+
+#define RXC0_RSSI_RST 0x80
+#define RXC0_MODE_RSSI 0x40
+#define RXC0_MODE_OFF 0x20
+#define RXC0_MODE_CM 0x10
+#define RXC0_LAN_LOAD 0x08
+#define RXC0_OFF_ADJ_MASK 0x07
+
+#define TXC0_MODE_TXLPF 0x04
+#define TXC0_PA_TSSI_EN 0x02
+#define TXC0_TSSI_EN 0x01
+
+#define TXC1_PA_GAIN_MASK 0x60
+#define TXC1_PA_GAIN_3DB 0x40
+#define TXC1_PA_GAIN_2DB 0x20
+#define TXC1_TX_MIX_GAIN 0x10
+#define TXC1_OFF_I_MASK 0x0c
+#define TXC1_OFF_Q_MASK 0x03
+
+#define RADIO_2055_READ_OFF 0x100
+#define RADIO_2057_READ_OFF 0x200
+
+#define RADIO_2055_GEN_SPARE 0x00
+#define RADIO_2055_SP_PIN_PD 0x02
+#define RADIO_2055_SP_RSSI_CORE1 0x03
+#define RADIO_2055_SP_PD_MISC_CORE1 0x04
+#define RADIO_2055_SP_RSSI_CORE2 0x05
+#define RADIO_2055_SP_PD_MISC_CORE2 0x06
+#define RADIO_2055_SP_RX_GC1_CORE1 0x07
+#define RADIO_2055_SP_RX_GC2_CORE1 0x08
+#define RADIO_2055_SP_RX_GC1_CORE2 0x09
+#define RADIO_2055_SP_RX_GC2_CORE2 0x0a
+#define RADIO_2055_SP_LPF_BW_SELECT_CORE1 0x0b
+#define RADIO_2055_SP_LPF_BW_SELECT_CORE2 0x0c
+#define RADIO_2055_SP_TX_GC1_CORE1 0x0d
+#define RADIO_2055_SP_TX_GC2_CORE1 0x0e
+#define RADIO_2055_SP_TX_GC1_CORE2 0x0f
+#define RADIO_2055_SP_TX_GC2_CORE2 0x10
+#define RADIO_2055_MASTER_CNTRL1 0x11
+#define RADIO_2055_MASTER_CNTRL2 0x12
+#define RADIO_2055_PD_LGEN 0x13
+#define RADIO_2055_PD_PLL_TS 0x14
+#define RADIO_2055_PD_CORE1_LGBUF 0x15
+#define RADIO_2055_PD_CORE1_TX 0x16
+#define RADIO_2055_PD_CORE1_RXTX 0x17
+#define RADIO_2055_PD_CORE1_RSSI_MISC 0x18
+#define RADIO_2055_PD_CORE2_LGBUF 0x19
+#define RADIO_2055_PD_CORE2_TX 0x1a
+#define RADIO_2055_PD_CORE2_RXTX 0x1b
+#define RADIO_2055_PD_CORE2_RSSI_MISC 0x1c
+#define RADIO_2055_PWRDET_LGEN 0x1d
+#define RADIO_2055_PWRDET_LGBUF_CORE1 0x1e
+#define RADIO_2055_PWRDET_RXTX_CORE1 0x1f
+#define RADIO_2055_PWRDET_LGBUF_CORE2 0x20
+#define RADIO_2055_PWRDET_RXTX_CORE2 0x21
+#define RADIO_2055_RRCCAL_CNTRL_SPARE 0x22
+#define RADIO_2055_RRCCAL_N_OPT_SEL 0x23
+#define RADIO_2055_CAL_MISC 0x24
+#define RADIO_2055_CAL_COUNTER_OUT 0x25
+#define RADIO_2055_CAL_COUNTER_OUT2 0x26
+#define RADIO_2055_CAL_CVAR_CNTRL 0x27
+#define RADIO_2055_CAL_RVAR_CNTRL 0x28
+#define RADIO_2055_CAL_LPO_CNTRL 0x29
+#define RADIO_2055_CAL_TS 0x2a
+#define RADIO_2055_CAL_RCCAL_READ_TS 0x2b
+#define RADIO_2055_CAL_RCAL_READ_TS 0x2c
+#define RADIO_2055_PAD_DRIVER 0x2d
+#define RADIO_2055_XO_CNTRL1 0x2e
+#define RADIO_2055_XO_CNTRL2 0x2f
+#define RADIO_2055_XO_REGULATOR 0x30
+#define RADIO_2055_XO_MISC 0x31
+#define RADIO_2055_PLL_LF_C1 0x32
+#define RADIO_2055_PLL_CAL_VTH 0x33
+#define RADIO_2055_PLL_LF_C2 0x34
+#define RADIO_2055_PLL_REF 0x35
+#define RADIO_2055_PLL_LF_R1 0x36
+#define RADIO_2055_PLL_PFD_CP 0x37
+#define RADIO_2055_PLL_IDAC_CPOPAMP 0x38
+#define RADIO_2055_PLL_CP_REGULATOR 0x39
+#define RADIO_2055_PLL_RCAL 0x3a
+#define RADIO_2055_RF_PLL_MOD0 0x3b
+#define RADIO_2055_RF_PLL_MOD1 0x3c
+#define RADIO_2055_RF_MMD_IDAC1 0x3d
+#define RADIO_2055_RF_MMD_IDAC0 0x3e
+#define RADIO_2055_RF_MMD_SPARE 0x3f
+#define RADIO_2055_VCO_CAL1 0x40
+#define RADIO_2055_VCO_CAL2 0x41
+#define RADIO_2055_VCO_CAL3 0x42
+#define RADIO_2055_VCO_CAL4 0x43
+#define RADIO_2055_VCO_CAL5 0x44
+#define RADIO_2055_VCO_CAL6 0x45
+#define RADIO_2055_VCO_CAL7 0x46
+#define RADIO_2055_VCO_CAL8 0x47
+#define RADIO_2055_VCO_CAL9 0x48
+#define RADIO_2055_VCO_CAL10 0x49
+#define RADIO_2055_VCO_CAL11 0x4a
+#define RADIO_2055_VCO_CAL12 0x4b
+#define RADIO_2055_VCO_CAL13 0x4c
+#define RADIO_2055_VCO_CAL14 0x4d
+#define RADIO_2055_VCO_CAL15 0x4e
+#define RADIO_2055_VCO_CAL16 0x4f
+#define RADIO_2055_VCO_KVCO 0x50
+#define RADIO_2055_VCO_CAP_TAIL 0x51
+#define RADIO_2055_VCO_IDAC_VCO 0x52
+#define RADIO_2055_VCO_REGULATOR 0x53
+#define RADIO_2055_PLL_RF_VTH 0x54
+#define RADIO_2055_LGBUF_CEN_BUF 0x55
+#define RADIO_2055_LGEN_TUNE1 0x56
+#define RADIO_2055_LGEN_TUNE2 0x57
+#define RADIO_2055_LGEN_IDAC1 0x58
+#define RADIO_2055_LGEN_IDAC2 0x59
+#define RADIO_2055_LGEN_BIAS_CNT 0x5a
+#define RADIO_2055_LGEN_BIAS_IDAC 0x5b
+#define RADIO_2055_LGEN_RCAL 0x5c
+#define RADIO_2055_LGEN_DIV 0x5d
+#define RADIO_2055_LGEN_SPARE2 0x5e
+#define RADIO_2055_CORE1_LGBUF_A_TUNE 0x5f
+#define RADIO_2055_CORE1_LGBUF_G_TUNE 0x60
+#define RADIO_2055_CORE1_LGBUF_DIV 0x61
+#define RADIO_2055_CORE1_LGBUF_A_IDAC 0x62
+#define RADIO_2055_CORE1_LGBUF_G_IDAC 0x63
+#define RADIO_2055_CORE1_LGBUF_IDACFIL_OVR 0x64
+#define RADIO_2055_CORE1_LGBUF_SPARE 0x65
+#define RADIO_2055_CORE1_RXRF_SPC1 0x66
+#define RADIO_2055_CORE1_RXRF_REG1 0x67
+#define RADIO_2055_CORE1_RXRF_REG2 0x68
+#define RADIO_2055_CORE1_RXRF_RCAL 0x69
+#define RADIO_2055_CORE1_RXBB_BUFI_LPFCMP 0x6a
+#define RADIO_2055_CORE1_RXBB_LPF 0x6b
+#define RADIO_2055_CORE1_RXBB_MIDAC_HIPAS 0x6c
+#define RADIO_2055_CORE1_RXBB_VGA1_IDAC 0x6d
+#define RADIO_2055_CORE1_RXBB_VGA2_IDAC 0x6e
+#define RADIO_2055_CORE1_RXBB_VGA3_IDAC 0x6f
+#define RADIO_2055_CORE1_RXBB_BUFO_CTRL 0x70
+#define RADIO_2055_CORE1_RXBB_RCCAL_CTRL 0x71
+#define RADIO_2055_CORE1_RXBB_RSSI_CTRL1 0x72
+#define RADIO_2055_CORE1_RXBB_RSSI_CTRL2 0x73
+#define RADIO_2055_CORE1_RXBB_RSSI_CTRL3 0x74
+#define RADIO_2055_CORE1_RXBB_RSSI_CTRL4 0x75
+#define RADIO_2055_CORE1_RXBB_RSSI_CTRL5 0x76
+#define RADIO_2055_CORE1_RXBB_REGULATOR 0x77
+#define RADIO_2055_CORE1_RXBB_SPARE1 0x78
+#define RADIO_2055_CORE1_RXTXBB_RCAL 0x79
+#define RADIO_2055_CORE1_TXRF_SGM_PGA 0x7a
+#define RADIO_2055_CORE1_TXRF_SGM_PAD 0x7b
+#define RADIO_2055_CORE1_TXRF_CNTR_PGA1 0x7c
+#define RADIO_2055_CORE1_TXRF_CNTR_PAD1 0x7d
+#define RADIO_2055_CORE1_TX_RFPGA_IDAC 0x7e
+#define RADIO_2055_CORE1_TX_PGA_PAD_TN 0x7f
+#define RADIO_2055_CORE1_TX_PAD_IDAC1 0x80
+#define RADIO_2055_CORE1_TX_PAD_IDAC2 0x81
+#define RADIO_2055_CORE1_TX_MX_BGTRIM 0x82
+#define RADIO_2055_CORE1_TXRF_RCAL 0x83
+#define RADIO_2055_CORE1_TXRF_PAD_TSSI1 0x84
+#define RADIO_2055_CORE1_TXRF_PAD_TSSI2 0x85
+#define RADIO_2055_CORE1_TX_RF_SPARE 0x86
+#define RADIO_2055_CORE1_TXRF_IQCAL1 0x87
+#define RADIO_2055_CORE1_TXRF_IQCAL2 0x88
+#define RADIO_2055_CORE1_TXBB_RCCAL_CTRL 0x89
+#define RADIO_2055_CORE1_TXBB_LPF1 0x8a
+#define RADIO_2055_CORE1_TX_VOS_CNCL 0x8b
+#define RADIO_2055_CORE1_TX_LPF_MXGM_IDAC 0x8c
+#define RADIO_2055_CORE1_TX_BB_MXGM 0x8d
+#define RADIO_2055_CORE2_LGBUF_A_TUNE 0x8e
+#define RADIO_2055_CORE2_LGBUF_G_TUNE 0x8f
+#define RADIO_2055_CORE2_LGBUF_DIV 0x90
+#define RADIO_2055_CORE2_LGBUF_A_IDAC 0x91
+#define RADIO_2055_CORE2_LGBUF_G_IDAC 0x92
+#define RADIO_2055_CORE2_LGBUF_IDACFIL_OVR 0x93
+#define RADIO_2055_CORE2_LGBUF_SPARE 0x94
+#define RADIO_2055_CORE2_RXRF_SPC1 0x95
+#define RADIO_2055_CORE2_RXRF_REG1 0x96
+#define RADIO_2055_CORE2_RXRF_REG2 0x97
+#define RADIO_2055_CORE2_RXRF_RCAL 0x98
+#define RADIO_2055_CORE2_RXBB_BUFI_LPFCMP 0x99
+#define RADIO_2055_CORE2_RXBB_LPF 0x9a
+#define RADIO_2055_CORE2_RXBB_MIDAC_HIPAS 0x9b
+#define RADIO_2055_CORE2_RXBB_VGA1_IDAC 0x9c
+#define RADIO_2055_CORE2_RXBB_VGA2_IDAC 0x9d
+#define RADIO_2055_CORE2_RXBB_VGA3_IDAC 0x9e
+#define RADIO_2055_CORE2_RXBB_BUFO_CTRL 0x9f
+#define RADIO_2055_CORE2_RXBB_RCCAL_CTRL 0xa0
+#define RADIO_2055_CORE2_RXBB_RSSI_CTRL1 0xa1
+#define RADIO_2055_CORE2_RXBB_RSSI_CTRL2 0xa2
+#define RADIO_2055_CORE2_RXBB_RSSI_CTRL3 0xa3
+#define RADIO_2055_CORE2_RXBB_RSSI_CTRL4 0xa4
+#define RADIO_2055_CORE2_RXBB_RSSI_CTRL5 0xa5
+#define RADIO_2055_CORE2_RXBB_REGULATOR 0xa6
+#define RADIO_2055_CORE2_RXBB_SPARE1 0xa7
+#define RADIO_2055_CORE2_RXTXBB_RCAL 0xa8
+#define RADIO_2055_CORE2_TXRF_SGM_PGA 0xa9
+#define RADIO_2055_CORE2_TXRF_SGM_PAD 0xaa
+#define RADIO_2055_CORE2_TXRF_CNTR_PGA1 0xab
+#define RADIO_2055_CORE2_TXRF_CNTR_PAD1 0xac
+#define RADIO_2055_CORE2_TX_RFPGA_IDAC 0xad
+#define RADIO_2055_CORE2_TX_PGA_PAD_TN 0xae
+#define RADIO_2055_CORE2_TX_PAD_IDAC1 0xaf
+#define RADIO_2055_CORE2_TX_PAD_IDAC2 0xb0
+#define RADIO_2055_CORE2_TX_MX_BGTRIM 0xb1
+#define RADIO_2055_CORE2_TXRF_RCAL 0xb2
+#define RADIO_2055_CORE2_TXRF_PAD_TSSI1 0xb3
+#define RADIO_2055_CORE2_TXRF_PAD_TSSI2 0xb4
+#define RADIO_2055_CORE2_TX_RF_SPARE 0xb5
+#define RADIO_2055_CORE2_TXRF_IQCAL1 0xb6
+#define RADIO_2055_CORE2_TXRF_IQCAL2 0xb7
+#define RADIO_2055_CORE2_TXBB_RCCAL_CTRL 0xb8
+#define RADIO_2055_CORE2_TXBB_LPF1 0xb9
+#define RADIO_2055_CORE2_TX_VOS_CNCL 0xba
+#define RADIO_2055_CORE2_TX_LPF_MXGM_IDAC 0xbb
+#define RADIO_2055_CORE2_TX_BB_MXGM 0xbc
+#define RADIO_2055_PRG_GC_HPVGA23_21 0xbd
+#define RADIO_2055_PRG_GC_HPVGA23_22 0xbe
+#define RADIO_2055_PRG_GC_HPVGA23_23 0xbf
+#define RADIO_2055_PRG_GC_HPVGA23_24 0xc0
+#define RADIO_2055_PRG_GC_HPVGA23_25 0xc1
+#define RADIO_2055_PRG_GC_HPVGA23_26 0xc2
+#define RADIO_2055_PRG_GC_HPVGA23_27 0xc3
+#define RADIO_2055_PRG_GC_HPVGA23_28 0xc4
+#define RADIO_2055_PRG_GC_HPVGA23_29 0xc5
+#define RADIO_2055_PRG_GC_HPVGA23_30 0xc6
+#define RADIO_2055_CORE1_LNA_GAINBST 0xcd
+#define RADIO_2055_CORE1_B0_NBRSSI_VCM 0xd2
+#define RADIO_2055_CORE1_GEN_SPARE2 0xd6
+#define RADIO_2055_CORE2_LNA_GAINBST 0xd9
+#define RADIO_2055_CORE2_B0_NBRSSI_VCM 0xde
+#define RADIO_2055_CORE2_GEN_SPARE2 0xe2
+
+#define RADIO_2055_GAINBST_GAIN_DB 6
+#define RADIO_2055_GAINBST_CODE 0x6
+
+#define RADIO_2055_JTAGCTRL_MASK 0x04
+#define RADIO_2055_JTAGSYNC_MASK 0x08
+#define RADIO_2055_RRCAL_START 0x40
+#define RADIO_2055_RRCAL_RST_N 0x01
+#define RADIO_2055_CAL_LPO_ENABLE 0x80
+#define RADIO_2055_RCAL_DONE 0x80
+#define RADIO_2055_NBRSSI_VCM_I_MASK 0x03
+#define RADIO_2055_NBRSSI_VCM_I_SHIFT 0x00
+#define RADIO_2055_NBRSSI_VCM_Q_MASK 0x03
+#define RADIO_2055_NBRSSI_VCM_Q_SHIFT 0x00
+#define RADIO_2055_WBRSSI_VCM_IQ_MASK 0x0c
+#define RADIO_2055_WBRSSI_VCM_IQ_SHIFT 0x02
+#define RADIO_2055_NBRSSI_PD 0x01
+#define RADIO_2055_WBRSSI_G1_PD 0x04
+#define RADIO_2055_WBRSSI_G2_PD 0x02
+#define RADIO_2055_NBRSSI_SEL 0x01
+#define RADIO_2055_WBRSSI_G1_SEL 0x04
+#define RADIO_2055_WBRSSI_G2_SEL 0x02
+#define RADIO_2055_COUPLE_RX_MASK 0x01
+#define RADIO_2055_COUPLE_TX_MASK 0x02
+#define RADIO_2055_GAINBST_DISABLE 0x02
+#define RADIO_2055_GAINBST_VAL_MASK 0x07
+#define RADIO_2055_RXMX_GC_MASK 0x0c
+
+#define RADIO_MIMO_CORESEL_OFF 0x0
+#define RADIO_MIMO_CORESEL_CORE1 0x1
+#define RADIO_MIMO_CORESEL_CORE2 0x2
+#define RADIO_MIMO_CORESEL_CORE3 0x3
+#define RADIO_MIMO_CORESEL_CORE4 0x4
+#define RADIO_MIMO_CORESEL_ALLRX 0x5
+#define RADIO_MIMO_CORESEL_ALLTX 0x6
+#define RADIO_MIMO_CORESEL_ALLRXTX 0x7
+
+#define RADIO_2064_READ_OFF 0x200
+
+#define RADIO_2064_REG000 0x0
+#define RADIO_2064_REG001 0x1
+#define RADIO_2064_REG002 0x2
+#define RADIO_2064_REG003 0x3
+#define RADIO_2064_REG004 0x4
+#define RADIO_2064_REG005 0x5
+#define RADIO_2064_REG006 0x6
+#define RADIO_2064_REG007 0x7
+#define RADIO_2064_REG008 0x8
+#define RADIO_2064_REG009 0x9
+#define RADIO_2064_REG00A 0xa
+#define RADIO_2064_REG00B 0xb
+#define RADIO_2064_REG00C 0xc
+#define RADIO_2064_REG00D 0xd
+#define RADIO_2064_REG00E 0xe
+#define RADIO_2064_REG00F 0xf
+#define RADIO_2064_REG010 0x10
+#define RADIO_2064_REG011 0x11
+#define RADIO_2064_REG012 0x12
+#define RADIO_2064_REG013 0x13
+#define RADIO_2064_REG014 0x14
+#define RADIO_2064_REG015 0x15
+#define RADIO_2064_REG016 0x16
+#define RADIO_2064_REG017 0x17
+#define RADIO_2064_REG018 0x18
+#define RADIO_2064_REG019 0x19
+#define RADIO_2064_REG01A 0x1a
+#define RADIO_2064_REG01B 0x1b
+#define RADIO_2064_REG01C 0x1c
+#define RADIO_2064_REG01D 0x1d
+#define RADIO_2064_REG01E 0x1e
+#define RADIO_2064_REG01F 0x1f
+#define RADIO_2064_REG020 0x20
+#define RADIO_2064_REG021 0x21
+#define RADIO_2064_REG022 0x22
+#define RADIO_2064_REG023 0x23
+#define RADIO_2064_REG024 0x24
+#define RADIO_2064_REG025 0x25
+#define RADIO_2064_REG026 0x26
+#define RADIO_2064_REG027 0x27
+#define RADIO_2064_REG028 0x28
+#define RADIO_2064_REG029 0x29
+#define RADIO_2064_REG02A 0x2a
+#define RADIO_2064_REG02B 0x2b
+#define RADIO_2064_REG02C 0x2c
+#define RADIO_2064_REG02D 0x2d
+#define RADIO_2064_REG02E 0x2e
+#define RADIO_2064_REG02F 0x2f
+#define RADIO_2064_REG030 0x30
+#define RADIO_2064_REG031 0x31
+#define RADIO_2064_REG032 0x32
+#define RADIO_2064_REG033 0x33
+#define RADIO_2064_REG034 0x34
+#define RADIO_2064_REG035 0x35
+#define RADIO_2064_REG036 0x36
+#define RADIO_2064_REG037 0x37
+#define RADIO_2064_REG038 0x38
+#define RADIO_2064_REG039 0x39
+#define RADIO_2064_REG03A 0x3a
+#define RADIO_2064_REG03B 0x3b
+#define RADIO_2064_REG03C 0x3c
+#define RADIO_2064_REG03D 0x3d
+#define RADIO_2064_REG03E 0x3e
+#define RADIO_2064_REG03F 0x3f
+#define RADIO_2064_REG040 0x40
+#define RADIO_2064_REG041 0x41
+#define RADIO_2064_REG042 0x42
+#define RADIO_2064_REG043 0x43
+#define RADIO_2064_REG044 0x44
+#define RADIO_2064_REG045 0x45
+#define RADIO_2064_REG046 0x46
+#define RADIO_2064_REG047 0x47
+#define RADIO_2064_REG048 0x48
+#define RADIO_2064_REG049 0x49
+#define RADIO_2064_REG04A 0x4a
+#define RADIO_2064_REG04B 0x4b
+#define RADIO_2064_REG04C 0x4c
+#define RADIO_2064_REG04D 0x4d
+#define RADIO_2064_REG04E 0x4e
+#define RADIO_2064_REG04F 0x4f
+#define RADIO_2064_REG050 0x50
+#define RADIO_2064_REG051 0x51
+#define RADIO_2064_REG052 0x52
+#define RADIO_2064_REG053 0x53
+#define RADIO_2064_REG054 0x54
+#define RADIO_2064_REG055 0x55
+#define RADIO_2064_REG056 0x56
+#define RADIO_2064_REG057 0x57
+#define RADIO_2064_REG058 0x58
+#define RADIO_2064_REG059 0x59
+#define RADIO_2064_REG05A 0x5a
+#define RADIO_2064_REG05B 0x5b
+#define RADIO_2064_REG05C 0x5c
+#define RADIO_2064_REG05D 0x5d
+#define RADIO_2064_REG05E 0x5e
+#define RADIO_2064_REG05F 0x5f
+#define RADIO_2064_REG060 0x60
+#define RADIO_2064_REG061 0x61
+#define RADIO_2064_REG062 0x62
+#define RADIO_2064_REG063 0x63
+#define RADIO_2064_REG064 0x64
+#define RADIO_2064_REG065 0x65
+#define RADIO_2064_REG066 0x66
+#define RADIO_2064_REG067 0x67
+#define RADIO_2064_REG068 0x68
+#define RADIO_2064_REG069 0x69
+#define RADIO_2064_REG06A 0x6a
+#define RADIO_2064_REG06B 0x6b
+#define RADIO_2064_REG06C 0x6c
+#define RADIO_2064_REG06D 0x6d
+#define RADIO_2064_REG06E 0x6e
+#define RADIO_2064_REG06F 0x6f
+#define RADIO_2064_REG070 0x70
+#define RADIO_2064_REG071 0x71
+#define RADIO_2064_REG072 0x72
+#define RADIO_2064_REG073 0x73
+#define RADIO_2064_REG074 0x74
+#define RADIO_2064_REG075 0x75
+#define RADIO_2064_REG076 0x76
+#define RADIO_2064_REG077 0x77
+#define RADIO_2064_REG078 0x78
+#define RADIO_2064_REG079 0x79
+#define RADIO_2064_REG07A 0x7a
+#define RADIO_2064_REG07B 0x7b
+#define RADIO_2064_REG07C 0x7c
+#define RADIO_2064_REG07D 0x7d
+#define RADIO_2064_REG07E 0x7e
+#define RADIO_2064_REG07F 0x7f
+#define RADIO_2064_REG080 0x80
+#define RADIO_2064_REG081 0x81
+#define RADIO_2064_REG082 0x82
+#define RADIO_2064_REG083 0x83
+#define RADIO_2064_REG084 0x84
+#define RADIO_2064_REG085 0x85
+#define RADIO_2064_REG086 0x86
+#define RADIO_2064_REG087 0x87
+#define RADIO_2064_REG088 0x88
+#define RADIO_2064_REG089 0x89
+#define RADIO_2064_REG08A 0x8a
+#define RADIO_2064_REG08B 0x8b
+#define RADIO_2064_REG08C 0x8c
+#define RADIO_2064_REG08D 0x8d
+#define RADIO_2064_REG08E 0x8e
+#define RADIO_2064_REG08F 0x8f
+#define RADIO_2064_REG090 0x90
+#define RADIO_2064_REG091 0x91
+#define RADIO_2064_REG092 0x92
+#define RADIO_2064_REG093 0x93
+#define RADIO_2064_REG094 0x94
+#define RADIO_2064_REG095 0x95
+#define RADIO_2064_REG096 0x96
+#define RADIO_2064_REG097 0x97
+#define RADIO_2064_REG098 0x98
+#define RADIO_2064_REG099 0x99
+#define RADIO_2064_REG09A 0x9a
+#define RADIO_2064_REG09B 0x9b
+#define RADIO_2064_REG09C 0x9c
+#define RADIO_2064_REG09D 0x9d
+#define RADIO_2064_REG09E 0x9e
+#define RADIO_2064_REG09F 0x9f
+#define RADIO_2064_REG0A0 0xa0
+#define RADIO_2064_REG0A1 0xa1
+#define RADIO_2064_REG0A2 0xa2
+#define RADIO_2064_REG0A3 0xa3
+#define RADIO_2064_REG0A4 0xa4
+#define RADIO_2064_REG0A5 0xa5
+#define RADIO_2064_REG0A6 0xa6
+#define RADIO_2064_REG0A7 0xa7
+#define RADIO_2064_REG0A8 0xa8
+#define RADIO_2064_REG0A9 0xa9
+#define RADIO_2064_REG0AA 0xaa
+#define RADIO_2064_REG0AB 0xab
+#define RADIO_2064_REG0AC 0xac
+#define RADIO_2064_REG0AD 0xad
+#define RADIO_2064_REG0AE 0xae
+#define RADIO_2064_REG0AF 0xaf
+#define RADIO_2064_REG0B0 0xb0
+#define RADIO_2064_REG0B1 0xb1
+#define RADIO_2064_REG0B2 0xb2
+#define RADIO_2064_REG0B3 0xb3
+#define RADIO_2064_REG0B4 0xb4
+#define RADIO_2064_REG0B5 0xb5
+#define RADIO_2064_REG0B6 0xb6
+#define RADIO_2064_REG0B7 0xb7
+#define RADIO_2064_REG0B8 0xb8
+#define RADIO_2064_REG0B9 0xb9
+#define RADIO_2064_REG0BA 0xba
+#define RADIO_2064_REG0BB 0xbb
+#define RADIO_2064_REG0BC 0xbc
+#define RADIO_2064_REG0BD 0xbd
+#define RADIO_2064_REG0BE 0xbe
+#define RADIO_2064_REG0BF 0xbf
+#define RADIO_2064_REG0C0 0xc0
+#define RADIO_2064_REG0C1 0xc1
+#define RADIO_2064_REG0C2 0xc2
+#define RADIO_2064_REG0C3 0xc3
+#define RADIO_2064_REG0C4 0xc4
+#define RADIO_2064_REG0C5 0xc5
+#define RADIO_2064_REG0C6 0xc6
+#define RADIO_2064_REG0C7 0xc7
+#define RADIO_2064_REG0C8 0xc8
+#define RADIO_2064_REG0C9 0xc9
+#define RADIO_2064_REG0CA 0xca
+#define RADIO_2064_REG0CB 0xcb
+#define RADIO_2064_REG0CC 0xcc
+#define RADIO_2064_REG0CD 0xcd
+#define RADIO_2064_REG0CE 0xce
+#define RADIO_2064_REG0CF 0xcf
+#define RADIO_2064_REG0D0 0xd0
+#define RADIO_2064_REG0D1 0xd1
+#define RADIO_2064_REG0D2 0xd2
+#define RADIO_2064_REG0D3 0xd3
+#define RADIO_2064_REG0D4 0xd4
+#define RADIO_2064_REG0D5 0xd5
+#define RADIO_2064_REG0D6 0xd6
+#define RADIO_2064_REG0D7 0xd7
+#define RADIO_2064_REG0D8 0xd8
+#define RADIO_2064_REG0D9 0xd9
+#define RADIO_2064_REG0DA 0xda
+#define RADIO_2064_REG0DB 0xdb
+#define RADIO_2064_REG0DC 0xdc
+#define RADIO_2064_REG0DD 0xdd
+#define RADIO_2064_REG0DE 0xde
+#define RADIO_2064_REG0DF 0xdf
+#define RADIO_2064_REG0E0 0xe0
+#define RADIO_2064_REG0E1 0xe1
+#define RADIO_2064_REG0E2 0xe2
+#define RADIO_2064_REG0E3 0xe3
+#define RADIO_2064_REG0E4 0xe4
+#define RADIO_2064_REG0E5 0xe5
+#define RADIO_2064_REG0E6 0xe6
+#define RADIO_2064_REG0E7 0xe7
+#define RADIO_2064_REG0E8 0xe8
+#define RADIO_2064_REG0E9 0xe9
+#define RADIO_2064_REG0EA 0xea
+#define RADIO_2064_REG0EB 0xeb
+#define RADIO_2064_REG0EC 0xec
+#define RADIO_2064_REG0ED 0xed
+#define RADIO_2064_REG0EE 0xee
+#define RADIO_2064_REG0EF 0xef
+#define RADIO_2064_REG0F0 0xf0
+#define RADIO_2064_REG0F1 0xf1
+#define RADIO_2064_REG0F2 0xf2
+#define RADIO_2064_REG0F3 0xf3
+#define RADIO_2064_REG0F4 0xf4
+#define RADIO_2064_REG0F5 0xf5
+#define RADIO_2064_REG0F6 0xf6
+#define RADIO_2064_REG0F7 0xf7
+#define RADIO_2064_REG0F8 0xf8
+#define RADIO_2064_REG0F9 0xf9
+#define RADIO_2064_REG0FA 0xfa
+#define RADIO_2064_REG0FB 0xfb
+#define RADIO_2064_REG0FC 0xfc
+#define RADIO_2064_REG0FD 0xfd
+#define RADIO_2064_REG0FE 0xfe
+#define RADIO_2064_REG0FF 0xff
+#define RADIO_2064_REG100 0x100
+#define RADIO_2064_REG101 0x101
+#define RADIO_2064_REG102 0x102
+#define RADIO_2064_REG103 0x103
+#define RADIO_2064_REG104 0x104
+#define RADIO_2064_REG105 0x105
+#define RADIO_2064_REG106 0x106
+#define RADIO_2064_REG107 0x107
+#define RADIO_2064_REG108 0x108
+#define RADIO_2064_REG109 0x109
+#define RADIO_2064_REG10A 0x10a
+#define RADIO_2064_REG10B 0x10b
+#define RADIO_2064_REG10C 0x10c
+#define RADIO_2064_REG10D 0x10d
+#define RADIO_2064_REG10E 0x10e
+#define RADIO_2064_REG10F 0x10f
+#define RADIO_2064_REG110 0x110
+#define RADIO_2064_REG111 0x111
+#define RADIO_2064_REG112 0x112
+#define RADIO_2064_REG113 0x113
+#define RADIO_2064_REG114 0x114
+#define RADIO_2064_REG115 0x115
+#define RADIO_2064_REG116 0x116
+#define RADIO_2064_REG117 0x117
+#define RADIO_2064_REG118 0x118
+#define RADIO_2064_REG119 0x119
+#define RADIO_2064_REG11A 0x11a
+#define RADIO_2064_REG11B 0x11b
+#define RADIO_2064_REG11C 0x11c
+#define RADIO_2064_REG11D 0x11d
+#define RADIO_2064_REG11E 0x11e
+#define RADIO_2064_REG11F 0x11f
+#define RADIO_2064_REG120 0x120
+#define RADIO_2064_REG121 0x121
+#define RADIO_2064_REG122 0x122
+#define RADIO_2064_REG123 0x123
+#define RADIO_2064_REG124 0x124
+#define RADIO_2064_REG125 0x125
+#define RADIO_2064_REG126 0x126
+#define RADIO_2064_REG127 0x127
+#define RADIO_2064_REG128 0x128
+#define RADIO_2064_REG129 0x129
+#define RADIO_2064_REG12A 0x12a
+#define RADIO_2064_REG12B 0x12b
+#define RADIO_2064_REG12C 0x12c
+#define RADIO_2064_REG12D 0x12d
+#define RADIO_2064_REG12E 0x12e
+#define RADIO_2064_REG12F 0x12f
+#define RADIO_2064_REG130 0x130
+
+#define RADIO_2056_SYN (0x0 << 12)
+#define RADIO_2056_TX0 (0x2 << 12)
+#define RADIO_2056_TX1 (0x3 << 12)
+#define RADIO_2056_RX0 (0x6 << 12)
+#define RADIO_2056_RX1 (0x7 << 12)
+#define RADIO_2056_ALLTX (0xe << 12)
+#define RADIO_2056_ALLRX (0xf << 12)
+
+#define RADIO_2056_SYN_RESERVED_ADDR0 0x0
+#define RADIO_2056_SYN_IDCODE 0x1
+#define RADIO_2056_SYN_RESERVED_ADDR2 0x2
+#define RADIO_2056_SYN_RESERVED_ADDR3 0x3
+#define RADIO_2056_SYN_RESERVED_ADDR4 0x4
+#define RADIO_2056_SYN_RESERVED_ADDR5 0x5
+#define RADIO_2056_SYN_RESERVED_ADDR6 0x6
+#define RADIO_2056_SYN_RESERVED_ADDR7 0x7
+#define RADIO_2056_SYN_COM_CTRL 0x8
+#define RADIO_2056_SYN_COM_PU 0x9
+#define RADIO_2056_SYN_COM_OVR 0xa
+#define RADIO_2056_SYN_COM_RESET 0xb
+#define RADIO_2056_SYN_COM_RCAL 0xc
+#define RADIO_2056_SYN_COM_RC_RXLPF 0xd
+#define RADIO_2056_SYN_COM_RC_TXLPF 0xe
+#define RADIO_2056_SYN_COM_RC_RXHPF 0xf
+#define RADIO_2056_SYN_RESERVED_ADDR16 0x10
+#define RADIO_2056_SYN_RESERVED_ADDR17 0x11
+#define RADIO_2056_SYN_RESERVED_ADDR18 0x12
+#define RADIO_2056_SYN_RESERVED_ADDR19 0x13
+#define RADIO_2056_SYN_RESERVED_ADDR20 0x14
+#define RADIO_2056_SYN_RESERVED_ADDR21 0x15
+#define RADIO_2056_SYN_RESERVED_ADDR22 0x16
+#define RADIO_2056_SYN_RESERVED_ADDR23 0x17
+#define RADIO_2056_SYN_RESERVED_ADDR24 0x18
+#define RADIO_2056_SYN_RESERVED_ADDR25 0x19
+#define RADIO_2056_SYN_RESERVED_ADDR26 0x1a
+#define RADIO_2056_SYN_RESERVED_ADDR27 0x1b
+#define RADIO_2056_SYN_RESERVED_ADDR28 0x1c
+#define RADIO_2056_SYN_RESERVED_ADDR29 0x1d
+#define RADIO_2056_SYN_RESERVED_ADDR30 0x1e
+#define RADIO_2056_SYN_RESERVED_ADDR31 0x1f
+#define RADIO_2056_SYN_GPIO_MASTER1 0x20
+#define RADIO_2056_SYN_GPIO_MASTER2 0x21
+#define RADIO_2056_SYN_TOPBIAS_MASTER 0x22
+#define RADIO_2056_SYN_TOPBIAS_RCAL 0x23
+#define RADIO_2056_SYN_AFEREG 0x24
+#define RADIO_2056_SYN_TEMPPROCSENSE 0x25
+#define RADIO_2056_SYN_TEMPPROCSENSEIDAC 0x26
+#define RADIO_2056_SYN_TEMPPROCSENSERCAL 0x27
+#define RADIO_2056_SYN_LPO 0x28
+#define RADIO_2056_SYN_VDDCAL_MASTER 0x29
+#define RADIO_2056_SYN_VDDCAL_IDAC 0x2a
+#define RADIO_2056_SYN_VDDCAL_STATUS 0x2b
+#define RADIO_2056_SYN_RCAL_MASTER 0x2c
+#define RADIO_2056_SYN_RCAL_CODE_OUT 0x2d
+#define RADIO_2056_SYN_RCCAL_CTRL0 0x2e
+#define RADIO_2056_SYN_RCCAL_CTRL1 0x2f
+#define RADIO_2056_SYN_RCCAL_CTRL2 0x30
+#define RADIO_2056_SYN_RCCAL_CTRL3 0x31
+#define RADIO_2056_SYN_RCCAL_CTRL4 0x32
+#define RADIO_2056_SYN_RCCAL_CTRL5 0x33
+#define RADIO_2056_SYN_RCCAL_CTRL6 0x34
+#define RADIO_2056_SYN_RCCAL_CTRL7 0x35
+#define RADIO_2056_SYN_RCCAL_CTRL8 0x36
+#define RADIO_2056_SYN_RCCAL_CTRL9 0x37
+#define RADIO_2056_SYN_RCCAL_CTRL10 0x38
+#define RADIO_2056_SYN_RCCAL_CTRL11 0x39
+#define RADIO_2056_SYN_ZCAL_SPARE1 0x3a
+#define RADIO_2056_SYN_ZCAL_SPARE2 0x3b
+#define RADIO_2056_SYN_PLL_MAST1 0x3c
+#define RADIO_2056_SYN_PLL_MAST2 0x3d
+#define RADIO_2056_SYN_PLL_MAST3 0x3e
+#define RADIO_2056_SYN_PLL_BIAS_RESET 0x3f
+#define RADIO_2056_SYN_PLL_XTAL0 0x40
+#define RADIO_2056_SYN_PLL_XTAL1 0x41
+#define RADIO_2056_SYN_PLL_XTAL3 0x42
+#define RADIO_2056_SYN_PLL_XTAL4 0x43
+#define RADIO_2056_SYN_PLL_XTAL5 0x44
+#define RADIO_2056_SYN_PLL_XTAL6 0x45
+#define RADIO_2056_SYN_PLL_REFDIV 0x46
+#define RADIO_2056_SYN_PLL_PFD 0x47
+#define RADIO_2056_SYN_PLL_CP1 0x48
+#define RADIO_2056_SYN_PLL_CP2 0x49
+#define RADIO_2056_SYN_PLL_CP3 0x4a
+#define RADIO_2056_SYN_PLL_LOOPFILTER1 0x4b
+#define RADIO_2056_SYN_PLL_LOOPFILTER2 0x4c
+#define RADIO_2056_SYN_PLL_LOOPFILTER3 0x4d
+#define RADIO_2056_SYN_PLL_LOOPFILTER4 0x4e
+#define RADIO_2056_SYN_PLL_LOOPFILTER5 0x4f
+#define RADIO_2056_SYN_PLL_MMD1 0x50
+#define RADIO_2056_SYN_PLL_MMD2 0x51
+#define RADIO_2056_SYN_PLL_VCO1 0x52
+#define RADIO_2056_SYN_PLL_VCO2 0x53
+#define RADIO_2056_SYN_PLL_MONITOR1 0x54
+#define RADIO_2056_SYN_PLL_MONITOR2 0x55
+#define RADIO_2056_SYN_PLL_VCOCAL1 0x56
+#define RADIO_2056_SYN_PLL_VCOCAL2 0x57
+#define RADIO_2056_SYN_PLL_VCOCAL4 0x58
+#define RADIO_2056_SYN_PLL_VCOCAL5 0x59
+#define RADIO_2056_SYN_PLL_VCOCAL6 0x5a
+#define RADIO_2056_SYN_PLL_VCOCAL7 0x5b
+#define RADIO_2056_SYN_PLL_VCOCAL8 0x5c
+#define RADIO_2056_SYN_PLL_VCOCAL9 0x5d
+#define RADIO_2056_SYN_PLL_VCOCAL10 0x5e
+#define RADIO_2056_SYN_PLL_VCOCAL11 0x5f
+#define RADIO_2056_SYN_PLL_VCOCAL12 0x60
+#define RADIO_2056_SYN_PLL_VCOCAL13 0x61
+#define RADIO_2056_SYN_PLL_VREG 0x62
+#define RADIO_2056_SYN_PLL_STATUS1 0x63
+#define RADIO_2056_SYN_PLL_STATUS2 0x64
+#define RADIO_2056_SYN_PLL_STATUS3 0x65
+#define RADIO_2056_SYN_LOGEN_PU0 0x66
+#define RADIO_2056_SYN_LOGEN_PU1 0x67
+#define RADIO_2056_SYN_LOGEN_PU2 0x68
+#define RADIO_2056_SYN_LOGEN_PU3 0x69
+#define RADIO_2056_SYN_LOGEN_PU5 0x6a
+#define RADIO_2056_SYN_LOGEN_PU6 0x6b
+#define RADIO_2056_SYN_LOGEN_PU7 0x6c
+#define RADIO_2056_SYN_LOGEN_PU8 0x6d
+#define RADIO_2056_SYN_LOGEN_BIAS_RESET 0x6e
+#define RADIO_2056_SYN_LOGEN_RCCR1 0x6f
+#define RADIO_2056_SYN_LOGEN_VCOBUF1 0x70
+#define RADIO_2056_SYN_LOGEN_MIXER1 0x71
+#define RADIO_2056_SYN_LOGEN_MIXER2 0x72
+#define RADIO_2056_SYN_LOGEN_BUF1 0x73
+#define RADIO_2056_SYN_LOGENBUF2 0x74
+#define RADIO_2056_SYN_LOGEN_BUF3 0x75
+#define RADIO_2056_SYN_LOGEN_BUF4 0x76
+#define RADIO_2056_SYN_LOGEN_DIV1 0x77
+#define RADIO_2056_SYN_LOGEN_DIV2 0x78
+#define RADIO_2056_SYN_LOGEN_DIV3 0x79
+#define RADIO_2056_SYN_LOGEN_ACL1 0x7a
+#define RADIO_2056_SYN_LOGEN_ACL2 0x7b
+#define RADIO_2056_SYN_LOGEN_ACL3 0x7c
+#define RADIO_2056_SYN_LOGEN_ACL4 0x7d
+#define RADIO_2056_SYN_LOGEN_ACL5 0x7e
+#define RADIO_2056_SYN_LOGEN_ACL6 0x7f
+#define RADIO_2056_SYN_LOGEN_ACLOUT 0x80
+#define RADIO_2056_SYN_LOGEN_ACLCAL1 0x81
+#define RADIO_2056_SYN_LOGEN_ACLCAL2 0x82
+#define RADIO_2056_SYN_LOGEN_ACLCAL3 0x83
+#define RADIO_2056_SYN_CALEN 0x84
+#define RADIO_2056_SYN_LOGEN_PEAKDET1 0x85
+#define RADIO_2056_SYN_LOGEN_CORE_ACL_OVR 0x86
+#define RADIO_2056_SYN_LOGEN_RX_DIFF_ACL_OVR 0x87
+#define RADIO_2056_SYN_LOGEN_TX_DIFF_ACL_OVR 0x88
+#define RADIO_2056_SYN_LOGEN_RX_CMOS_ACL_OVR 0x89
+#define RADIO_2056_SYN_LOGEN_TX_CMOS_ACL_OVR 0x8a
+#define RADIO_2056_SYN_LOGEN_VCOBUF2 0x8b
+#define RADIO_2056_SYN_LOGEN_MIXER3 0x8c
+#define RADIO_2056_SYN_LOGEN_BUF5 0x8d
+#define RADIO_2056_SYN_LOGEN_BUF6 0x8e
+#define RADIO_2056_SYN_LOGEN_CBUFRX1 0x8f
+#define RADIO_2056_SYN_LOGEN_CBUFRX2 0x90
+#define RADIO_2056_SYN_LOGEN_CBUFRX3 0x91
+#define RADIO_2056_SYN_LOGEN_CBUFRX4 0x92
+#define RADIO_2056_SYN_LOGEN_CBUFTX1 0x93
+#define RADIO_2056_SYN_LOGEN_CBUFTX2 0x94
+#define RADIO_2056_SYN_LOGEN_CBUFTX3 0x95
+#define RADIO_2056_SYN_LOGEN_CBUFTX4 0x96
+#define RADIO_2056_SYN_LOGEN_CMOSRX1 0x97
+#define RADIO_2056_SYN_LOGEN_CMOSRX2 0x98
+#define RADIO_2056_SYN_LOGEN_CMOSRX3 0x99
+#define RADIO_2056_SYN_LOGEN_CMOSRX4 0x9a
+#define RADIO_2056_SYN_LOGEN_CMOSTX1 0x9b
+#define RADIO_2056_SYN_LOGEN_CMOSTX2 0x9c
+#define RADIO_2056_SYN_LOGEN_CMOSTX3 0x9d
+#define RADIO_2056_SYN_LOGEN_CMOSTX4 0x9e
+#define RADIO_2056_SYN_LOGEN_VCOBUF2_OVRVAL 0x9f
+#define RADIO_2056_SYN_LOGEN_MIXER3_OVRVAL 0xa0
+#define RADIO_2056_SYN_LOGEN_BUF5_OVRVAL 0xa1
+#define RADIO_2056_SYN_LOGEN_BUF6_OVRVAL 0xa2
+#define RADIO_2056_SYN_LOGEN_CBUFRX1_OVRVAL 0xa3
+#define RADIO_2056_SYN_LOGEN_CBUFRX2_OVRVAL 0xa4
+#define RADIO_2056_SYN_LOGEN_CBUFRX3_OVRVAL 0xa5
+#define RADIO_2056_SYN_LOGEN_CBUFRX4_OVRVAL 0xa6
+#define RADIO_2056_SYN_LOGEN_CBUFTX1_OVRVAL 0xa7
+#define RADIO_2056_SYN_LOGEN_CBUFTX2_OVRVAL 0xa8
+#define RADIO_2056_SYN_LOGEN_CBUFTX3_OVRVAL 0xa9
+#define RADIO_2056_SYN_LOGEN_CBUFTX4_OVRVAL 0xaa
+#define RADIO_2056_SYN_LOGEN_CMOSRX1_OVRVAL 0xab
+#define RADIO_2056_SYN_LOGEN_CMOSRX2_OVRVAL 0xac
+#define RADIO_2056_SYN_LOGEN_CMOSRX3_OVRVAL 0xad
+#define RADIO_2056_SYN_LOGEN_CMOSRX4_OVRVAL 0xae
+#define RADIO_2056_SYN_LOGEN_CMOSTX1_OVRVAL 0xaf
+#define RADIO_2056_SYN_LOGEN_CMOSTX2_OVRVAL 0xb0
+#define RADIO_2056_SYN_LOGEN_CMOSTX3_OVRVAL 0xb1
+#define RADIO_2056_SYN_LOGEN_CMOSTX4_OVRVAL 0xb2
+#define RADIO_2056_SYN_LOGEN_ACL_WAITCNT 0xb3
+#define RADIO_2056_SYN_LOGEN_CORE_CALVALID 0xb4
+#define RADIO_2056_SYN_LOGEN_RX_CMOS_CALVALID 0xb5
+#define RADIO_2056_SYN_LOGEN_TX_CMOS_VALID 0xb6
+
+#define RADIO_2056_TX_RESERVED_ADDR0 0x0
+#define RADIO_2056_TX_IDCODE 0x1
+#define RADIO_2056_TX_RESERVED_ADDR2 0x2
+#define RADIO_2056_TX_RESERVED_ADDR3 0x3
+#define RADIO_2056_TX_RESERVED_ADDR4 0x4
+#define RADIO_2056_TX_RESERVED_ADDR5 0x5
+#define RADIO_2056_TX_RESERVED_ADDR6 0x6
+#define RADIO_2056_TX_RESERVED_ADDR7 0x7
+#define RADIO_2056_TX_COM_CTRL 0x8
+#define RADIO_2056_TX_COM_PU 0x9
+#define RADIO_2056_TX_COM_OVR 0xa
+#define RADIO_2056_TX_COM_RESET 0xb
+#define RADIO_2056_TX_COM_RCAL 0xc
+#define RADIO_2056_TX_COM_RC_RXLPF 0xd
+#define RADIO_2056_TX_COM_RC_TXLPF 0xe
+#define RADIO_2056_TX_COM_RC_RXHPF 0xf
+#define RADIO_2056_TX_RESERVED_ADDR16 0x10
+#define RADIO_2056_TX_RESERVED_ADDR17 0x11
+#define RADIO_2056_TX_RESERVED_ADDR18 0x12
+#define RADIO_2056_TX_RESERVED_ADDR19 0x13
+#define RADIO_2056_TX_RESERVED_ADDR20 0x14
+#define RADIO_2056_TX_RESERVED_ADDR21 0x15
+#define RADIO_2056_TX_RESERVED_ADDR22 0x16
+#define RADIO_2056_TX_RESERVED_ADDR23 0x17
+#define RADIO_2056_TX_RESERVED_ADDR24 0x18
+#define RADIO_2056_TX_RESERVED_ADDR25 0x19
+#define RADIO_2056_TX_RESERVED_ADDR26 0x1a
+#define RADIO_2056_TX_RESERVED_ADDR27 0x1b
+#define RADIO_2056_TX_RESERVED_ADDR28 0x1c
+#define RADIO_2056_TX_RESERVED_ADDR29 0x1d
+#define RADIO_2056_TX_RESERVED_ADDR30 0x1e
+#define RADIO_2056_TX_RESERVED_ADDR31 0x1f
+#define RADIO_2056_TX_IQCAL_GAIN_BW 0x20
+#define RADIO_2056_TX_LOFT_FINE_I 0x21
+#define RADIO_2056_TX_LOFT_FINE_Q 0x22
+#define RADIO_2056_TX_LOFT_COARSE_I 0x23
+#define RADIO_2056_TX_LOFT_COARSE_Q 0x24
+#define RADIO_2056_TX_TX_COM_MASTER1 0x25
+#define RADIO_2056_TX_TX_COM_MASTER2 0x26
+#define RADIO_2056_TX_RXIQCAL_TXMUX 0x27
+#define RADIO_2056_TX_TX_SSI_MASTER 0x28
+#define RADIO_2056_TX_IQCAL_VCM_HG 0x29
+#define RADIO_2056_TX_IQCAL_IDAC 0x2a
+#define RADIO_2056_TX_TSSI_VCM 0x2b
+#define RADIO_2056_TX_TX_AMP_DET 0x2c
+#define RADIO_2056_TX_TX_SSI_MUX 0x2d
+#define RADIO_2056_TX_TSSIA 0x2e
+#define RADIO_2056_TX_TSSIG 0x2f
+#define RADIO_2056_TX_TSSI_MISC1 0x30
+#define RADIO_2056_TX_TSSI_MISC2 0x31
+#define RADIO_2056_TX_TSSI_MISC3 0x32
+#define RADIO_2056_TX_PA_SPARE1 0x33
+#define RADIO_2056_TX_PA_SPARE2 0x34
+#define RADIO_2056_TX_INTPAA_MASTER 0x35
+#define RADIO_2056_TX_INTPAA_GAIN 0x36
+#define RADIO_2056_TX_INTPAA_BOOST_TUNE 0x37
+#define RADIO_2056_TX_INTPAA_IAUX_STAT 0x38
+#define RADIO_2056_TX_INTPAA_IAUX_DYN 0x39
+#define RADIO_2056_TX_INTPAA_IMAIN_STAT 0x3a
+#define RADIO_2056_TX_INTPAA_IMAIN_DYN 0x3b
+#define RADIO_2056_TX_INTPAA_CASCBIAS 0x3c
+#define RADIO_2056_TX_INTPAA_PASLOPE 0x3d
+#define RADIO_2056_TX_INTPAA_PA_MISC 0x3e
+#define RADIO_2056_TX_INTPAG_MASTER 0x3f
+#define RADIO_2056_TX_INTPAG_GAIN 0x40
+#define RADIO_2056_TX_INTPAG_BOOST_TUNE 0x41
+#define RADIO_2056_TX_INTPAG_IAUX_STAT 0x42
+#define RADIO_2056_TX_INTPAG_IAUX_DYN 0x43
+#define RADIO_2056_TX_INTPAG_IMAIN_STAT 0x44
+#define RADIO_2056_TX_INTPAG_IMAIN_DYN 0x45
+#define RADIO_2056_TX_INTPAG_CASCBIAS 0x46
+#define RADIO_2056_TX_INTPAG_PASLOPE 0x47
+#define RADIO_2056_TX_INTPAG_PA_MISC 0x48
+#define RADIO_2056_TX_PADA_MASTER 0x49
+#define RADIO_2056_TX_PADA_IDAC 0x4a
+#define RADIO_2056_TX_PADA_CASCBIAS 0x4b
+#define RADIO_2056_TX_PADA_GAIN 0x4c
+#define RADIO_2056_TX_PADA_BOOST_TUNE 0x4d
+#define RADIO_2056_TX_PADA_SLOPE 0x4e
+#define RADIO_2056_TX_PADG_MASTER 0x4f
+#define RADIO_2056_TX_PADG_IDAC 0x50
+#define RADIO_2056_TX_PADG_CASCBIAS 0x51
+#define RADIO_2056_TX_PADG_GAIN 0x52
+#define RADIO_2056_TX_PADG_BOOST_TUNE 0x53
+#define RADIO_2056_TX_PADG_SLOPE 0x54
+#define RADIO_2056_TX_PGAA_MASTER 0x55
+#define RADIO_2056_TX_PGAA_IDAC 0x56
+#define RADIO_2056_TX_PGAA_GAIN 0x57
+#define RADIO_2056_TX_PGAA_BOOST_TUNE 0x58
+#define RADIO_2056_TX_PGAA_SLOPE 0x59
+#define RADIO_2056_TX_PGAA_MISC 0x5a
+#define RADIO_2056_TX_PGAG_MASTER 0x5b
+#define RADIO_2056_TX_PGAG_IDAC 0x5c
+#define RADIO_2056_TX_PGAG_GAIN 0x5d
+#define RADIO_2056_TX_PGAG_BOOST_TUNE 0x5e
+#define RADIO_2056_TX_PGAG_SLOPE 0x5f
+#define RADIO_2056_TX_PGAG_MISC 0x60
+#define RADIO_2056_TX_MIXA_MASTER 0x61
+#define RADIO_2056_TX_MIXA_BOOST_TUNE 0x62
+#define RADIO_2056_TX_MIXG 0x63
+#define RADIO_2056_TX_MIXG_BOOST_TUNE 0x64
+#define RADIO_2056_TX_BB_GM_MASTER 0x65
+#define RADIO_2056_TX_GMBB_GM 0x66
+#define RADIO_2056_TX_GMBB_IDAC 0x67
+#define RADIO_2056_TX_TXLPF_MASTER 0x68
+#define RADIO_2056_TX_TXLPF_RCCAL 0x69
+#define RADIO_2056_TX_TXLPF_RCCAL_OFF0 0x6a
+#define RADIO_2056_TX_TXLPF_RCCAL_OFF1 0x6b
+#define RADIO_2056_TX_TXLPF_RCCAL_OFF2 0x6c
+#define RADIO_2056_TX_TXLPF_RCCAL_OFF3 0x6d
+#define RADIO_2056_TX_TXLPF_RCCAL_OFF4 0x6e
+#define RADIO_2056_TX_TXLPF_RCCAL_OFF5 0x6f
+#define RADIO_2056_TX_TXLPF_RCCAL_OFF6 0x70
+#define RADIO_2056_TX_TXLPF_BW 0x71
+#define RADIO_2056_TX_TXLPF_GAIN 0x72
+#define RADIO_2056_TX_TXLPF_IDAC 0x73
+#define RADIO_2056_TX_TXLPF_IDAC_0 0x74
+#define RADIO_2056_TX_TXLPF_IDAC_1 0x75
+#define RADIO_2056_TX_TXLPF_IDAC_2 0x76
+#define RADIO_2056_TX_TXLPF_IDAC_3 0x77
+#define RADIO_2056_TX_TXLPF_IDAC_4 0x78
+#define RADIO_2056_TX_TXLPF_IDAC_5 0x79
+#define RADIO_2056_TX_TXLPF_IDAC_6 0x7a
+#define RADIO_2056_TX_TXLPF_OPAMP_IDAC 0x7b
+#define RADIO_2056_TX_TXLPF_MISC 0x7c
+#define RADIO_2056_TX_TXSPARE1 0x7d
+#define RADIO_2056_TX_TXSPARE2 0x7e
+#define RADIO_2056_TX_TXSPARE3 0x7f
+#define RADIO_2056_TX_TXSPARE4 0x80
+#define RADIO_2056_TX_TXSPARE5 0x81
+#define RADIO_2056_TX_TXSPARE6 0x82
+#define RADIO_2056_TX_TXSPARE7 0x83
+#define RADIO_2056_TX_TXSPARE8 0x84
+#define RADIO_2056_TX_TXSPARE9 0x85
+#define RADIO_2056_TX_TXSPARE10 0x86
+#define RADIO_2056_TX_TXSPARE11 0x87
+#define RADIO_2056_TX_TXSPARE12 0x88
+#define RADIO_2056_TX_TXSPARE13 0x89
+#define RADIO_2056_TX_TXSPARE14 0x8a
+#define RADIO_2056_TX_TXSPARE15 0x8b
+#define RADIO_2056_TX_TXSPARE16 0x8c
+#define RADIO_2056_TX_STATUS_INTPA_GAIN 0x8d
+#define RADIO_2056_TX_STATUS_PAD_GAIN 0x8e
+#define RADIO_2056_TX_STATUS_PGA_GAIN 0x8f
+#define RADIO_2056_TX_STATUS_GM_TXLPF_GAIN 0x90
+#define RADIO_2056_TX_STATUS_TXLPF_BW 0x91
+#define RADIO_2056_TX_STATUS_TXLPF_RC 0x92
+#define RADIO_2056_TX_GMBB_IDAC0 0x93
+#define RADIO_2056_TX_GMBB_IDAC1 0x94
+#define RADIO_2056_TX_GMBB_IDAC2 0x95
+#define RADIO_2056_TX_GMBB_IDAC3 0x96
+#define RADIO_2056_TX_GMBB_IDAC4 0x97
+#define RADIO_2056_TX_GMBB_IDAC5 0x98
+#define RADIO_2056_TX_GMBB_IDAC6 0x99
+#define RADIO_2056_TX_GMBB_IDAC7 0x9a
+
+#define RADIO_2056_RX_RESERVED_ADDR0 0x0
+#define RADIO_2056_RX_IDCODE 0x1
+#define RADIO_2056_RX_RESERVED_ADDR2 0x2
+#define RADIO_2056_RX_RESERVED_ADDR3 0x3
+#define RADIO_2056_RX_RESERVED_ADDR4 0x4
+#define RADIO_2056_RX_RESERVED_ADDR5 0x5
+#define RADIO_2056_RX_RESERVED_ADDR6 0x6
+#define RADIO_2056_RX_RESERVED_ADDR7 0x7
+#define RADIO_2056_RX_COM_CTRL 0x8
+#define RADIO_2056_RX_COM_PU 0x9
+#define RADIO_2056_RX_COM_OVR 0xa
+#define RADIO_2056_RX_COM_RESET 0xb
+#define RADIO_2056_RX_COM_RCAL 0xc
+#define RADIO_2056_RX_COM_RC_RXLPF 0xd
+#define RADIO_2056_RX_COM_RC_TXLPF 0xe
+#define RADIO_2056_RX_COM_RC_RXHPF 0xf
+#define RADIO_2056_RX_RESERVED_ADDR16 0x10
+#define RADIO_2056_RX_RESERVED_ADDR17 0x11
+#define RADIO_2056_RX_RESERVED_ADDR18 0x12
+#define RADIO_2056_RX_RESERVED_ADDR19 0x13
+#define RADIO_2056_RX_RESERVED_ADDR20 0x14
+#define RADIO_2056_RX_RESERVED_ADDR21 0x15
+#define RADIO_2056_RX_RESERVED_ADDR22 0x16
+#define RADIO_2056_RX_RESERVED_ADDR23 0x17
+#define RADIO_2056_RX_RESERVED_ADDR24 0x18
+#define RADIO_2056_RX_RESERVED_ADDR25 0x19
+#define RADIO_2056_RX_RESERVED_ADDR26 0x1a
+#define RADIO_2056_RX_RESERVED_ADDR27 0x1b
+#define RADIO_2056_RX_RESERVED_ADDR28 0x1c
+#define RADIO_2056_RX_RESERVED_ADDR29 0x1d
+#define RADIO_2056_RX_RESERVED_ADDR30 0x1e
+#define RADIO_2056_RX_RESERVED_ADDR31 0x1f
+#define RADIO_2056_RX_RXIQCAL_RXMUX 0x20
+#define RADIO_2056_RX_RSSI_PU 0x21
+#define RADIO_2056_RX_RSSI_SEL 0x22
+#define RADIO_2056_RX_RSSI_GAIN 0x23
+#define RADIO_2056_RX_RSSI_NB_IDAC 0x24
+#define RADIO_2056_RX_RSSI_WB2I_IDAC_1 0x25
+#define RADIO_2056_RX_RSSI_WB2I_IDAC_2 0x26
+#define RADIO_2056_RX_RSSI_WB2Q_IDAC_1 0x27
+#define RADIO_2056_RX_RSSI_WB2Q_IDAC_2 0x28
+#define RADIO_2056_RX_RSSI_POLE 0x29
+#define RADIO_2056_RX_RSSI_WB1_IDAC 0x2a
+#define RADIO_2056_RX_RSSI_MISC 0x2b
+#define RADIO_2056_RX_LNAA_MASTER 0x2c
+#define RADIO_2056_RX_LNAA_TUNE 0x2d
+#define RADIO_2056_RX_LNAA_GAIN 0x2e
+#define RADIO_2056_RX_LNA_A_SLOPE 0x2f
+#define RADIO_2056_RX_BIASPOLE_LNAA1_IDAC 0x30
+#define RADIO_2056_RX_LNAA2_IDAC 0x31
+#define RADIO_2056_RX_LNA1A_MISC 0x32
+#define RADIO_2056_RX_LNAG_MASTER 0x33
+#define RADIO_2056_RX_LNAG_TUNE 0x34
+#define RADIO_2056_RX_LNAG_GAIN 0x35
+#define RADIO_2056_RX_LNA_G_SLOPE 0x36
+#define RADIO_2056_RX_BIASPOLE_LNAG1_IDAC 0x37
+#define RADIO_2056_RX_LNAG2_IDAC 0x38
+#define RADIO_2056_RX_LNA1G_MISC 0x39
+#define RADIO_2056_RX_MIXA_MASTER 0x3a
+#define RADIO_2056_RX_MIXA_VCM 0x3b
+#define RADIO_2056_RX_MIXA_CTRLPTAT 0x3c
+#define RADIO_2056_RX_MIXA_LOB_BIAS 0x3d
+#define RADIO_2056_RX_MIXA_CORE_IDAC 0x3e
+#define RADIO_2056_RX_MIXA_CMFB_IDAC 0x3f
+#define RADIO_2056_RX_MIXA_BIAS_AUX 0x40
+#define RADIO_2056_RX_MIXA_BIAS_MAIN 0x41
+#define RADIO_2056_RX_MIXA_BIAS_MISC 0x42
+#define RADIO_2056_RX_MIXA_MAST_BIAS 0x43
+#define RADIO_2056_RX_MIXG_MASTER 0x44
+#define RADIO_2056_RX_MIXG_VCM 0x45
+#define RADIO_2056_RX_MIXG_CTRLPTAT 0x46
+#define RADIO_2056_RX_MIXG_LOB_BIAS 0x47
+#define RADIO_2056_RX_MIXG_CORE_IDAC 0x48
+#define RADIO_2056_RX_MIXG_CMFB_IDAC 0x49
+#define RADIO_2056_RX_MIXG_BIAS_AUX 0x4a
+#define RADIO_2056_RX_MIXG_BIAS_MAIN 0x4b
+#define RADIO_2056_RX_MIXG_BIAS_MISC 0x4c
+#define RADIO_2056_RX_MIXG_MAST_BIAS 0x4d
+#define RADIO_2056_RX_TIA_MASTER 0x4e
+#define RADIO_2056_RX_TIA_IOPAMP 0x4f
+#define RADIO_2056_RX_TIA_QOPAMP 0x50
+#define RADIO_2056_RX_TIA_IMISC 0x51
+#define RADIO_2056_RX_TIA_QMISC 0x52
+#define RADIO_2056_RX_TIA_GAIN 0x53
+#define RADIO_2056_RX_TIA_SPARE1 0x54
+#define RADIO_2056_RX_TIA_SPARE2 0x55
+#define RADIO_2056_RX_BB_LPF_MASTER 0x56
+#define RADIO_2056_RX_AACI_MASTER 0x57
+#define RADIO_2056_RX_RXLPF_IDAC 0x58
+#define RADIO_2056_RX_RXLPF_OPAMPBIAS_LOWQ 0x59
+#define RADIO_2056_RX_RXLPF_OPAMPBIAS_HIGHQ 0x5a
+#define RADIO_2056_RX_RXLPF_BIAS_DCCANCEL 0x5b
+#define RADIO_2056_RX_RXLPF_OUTVCM 0x5c
+#define RADIO_2056_RX_RXLPF_INVCM_BODY 0x5d
+#define RADIO_2056_RX_RXLPF_CC_OP 0x5e
+#define RADIO_2056_RX_RXLPF_GAIN 0x5f
+#define RADIO_2056_RX_RXLPF_Q_BW 0x60
+#define RADIO_2056_RX_RXLPF_HP_CORNER_BW 0x61
+#define RADIO_2056_RX_RXLPF_RCCAL_HPC 0x62
+#define RADIO_2056_RX_RXHPF_OFF0 0x63
+#define RADIO_2056_RX_RXHPF_OFF1 0x64
+#define RADIO_2056_RX_RXHPF_OFF2 0x65
+#define RADIO_2056_RX_RXHPF_OFF3 0x66
+#define RADIO_2056_RX_RXHPF_OFF4 0x67
+#define RADIO_2056_RX_RXHPF_OFF5 0x68
+#define RADIO_2056_RX_RXHPF_OFF6 0x69
+#define RADIO_2056_RX_RXHPF_OFF7 0x6a
+#define RADIO_2056_RX_RXLPF_RCCAL_LPC 0x6b
+#define RADIO_2056_RX_RXLPF_OFF_0 0x6c
+#define RADIO_2056_RX_RXLPF_OFF_1 0x6d
+#define RADIO_2056_RX_RXLPF_OFF_2 0x6e
+#define RADIO_2056_RX_RXLPF_OFF_3 0x6f
+#define RADIO_2056_RX_RXLPF_OFF_4 0x70
+#define RADIO_2056_RX_UNUSED 0x71
+#define RADIO_2056_RX_VGA_MASTER 0x72
+#define RADIO_2056_RX_VGA_BIAS 0x73
+#define RADIO_2056_RX_VGA_BIAS_DCCANCEL 0x74
+#define RADIO_2056_RX_VGA_GAIN 0x75
+#define RADIO_2056_RX_VGA_HP_CORNER_BW 0x76
+#define RADIO_2056_RX_VGABUF_BIAS 0x77
+#define RADIO_2056_RX_VGABUF_GAIN_BW 0x78
+#define RADIO_2056_RX_TXFBMIX_A 0x79
+#define RADIO_2056_RX_TXFBMIX_G 0x7a
+#define RADIO_2056_RX_RXSPARE1 0x7b
+#define RADIO_2056_RX_RXSPARE2 0x7c
+#define RADIO_2056_RX_RXSPARE3 0x7d
+#define RADIO_2056_RX_RXSPARE4 0x7e
+#define RADIO_2056_RX_RXSPARE5 0x7f
+#define RADIO_2056_RX_RXSPARE6 0x80
+#define RADIO_2056_RX_RXSPARE7 0x81
+#define RADIO_2056_RX_RXSPARE8 0x82
+#define RADIO_2056_RX_RXSPARE9 0x83
+#define RADIO_2056_RX_RXSPARE10 0x84
+#define RADIO_2056_RX_RXSPARE11 0x85
+#define RADIO_2056_RX_RXSPARE12 0x86
+#define RADIO_2056_RX_RXSPARE13 0x87
+#define RADIO_2056_RX_RXSPARE14 0x88
+#define RADIO_2056_RX_RXSPARE15 0x89
+#define RADIO_2056_RX_RXSPARE16 0x8a
+#define RADIO_2056_RX_STATUS_LNAA_GAIN 0x8b
+#define RADIO_2056_RX_STATUS_LNAG_GAIN 0x8c
+#define RADIO_2056_RX_STATUS_MIXTIA_GAIN 0x8d
+#define RADIO_2056_RX_STATUS_RXLPF_GAIN 0x8e
+#define RADIO_2056_RX_STATUS_VGA_BUF_GAIN 0x8f
+#define RADIO_2056_RX_STATUS_RXLPF_Q 0x90
+#define RADIO_2056_RX_STATUS_RXLPF_BUF_BW 0x91
+#define RADIO_2056_RX_STATUS_RXLPF_VGA_HPC 0x92
+#define RADIO_2056_RX_STATUS_RXLPF_RC 0x93
+#define RADIO_2056_RX_STATUS_HPC_RC 0x94
+
+#define RADIO_2056_LNA1_A_PU 0x01
+#define RADIO_2056_LNA2_A_PU 0x02
+#define RADIO_2056_LNA1_G_PU 0x01
+#define RADIO_2056_LNA2_G_PU 0x02
+#define RADIO_2056_MIXA_PU_I 0x01
+#define RADIO_2056_MIXA_PU_Q 0x02
+#define RADIO_2056_MIXA_PU_GM 0x10
+#define RADIO_2056_MIXG_PU_I 0x01
+#define RADIO_2056_MIXG_PU_Q 0x02
+#define RADIO_2056_MIXG_PU_GM 0x10
+#define RADIO_2056_TIA_PU 0x01
+#define RADIO_2056_BB_LPF_PU 0x20
+#define RADIO_2056_W1_PU 0x02
+#define RADIO_2056_W2_PU 0x04
+#define RADIO_2056_NB_PU 0x08
+#define RADIO_2056_RSSI_W1_SEL 0x02
+#define RADIO_2056_RSSI_W2_SEL 0x04
+#define RADIO_2056_RSSI_NB_SEL 0x08
+#define RADIO_2056_VCM_MASK 0x1c
+#define RADIO_2056_RSSI_VCM_SHIFT 0x02
+
+#define RADIO_2057_DACBUF_VINCM_CORE0 0x0
+#define RADIO_2057_IDCODE 0x1
+#define RADIO_2057_RCCAL_MASTER 0x2
+#define RADIO_2057_RCCAL_CAP_SIZE 0x3
+#define RADIO_2057_RCAL_CONFIG 0x4
+#define RADIO_2057_GPAIO_CONFIG 0x5
+#define RADIO_2057_GPAIO_SEL1 0x6
+#define RADIO_2057_GPAIO_SEL0 0x7
+#define RADIO_2057_CLPO_CONFIG 0x8
+#define RADIO_2057_BANDGAP_CONFIG 0x9
+#define RADIO_2057_BANDGAP_RCAL_TRIM 0xa
+#define RADIO_2057_AFEREG_CONFIG 0xb
+#define RADIO_2057_TEMPSENSE_CONFIG 0xc
+#define RADIO_2057_XTAL_CONFIG1 0xd
+#define RADIO_2057_XTAL_ICORE_SIZE 0xe
+#define RADIO_2057_XTAL_BUF_SIZE 0xf
+#define RADIO_2057_XTAL_PULLCAP_SIZE 0x10
+#define RADIO_2057_RFPLL_MASTER 0x11
+#define RADIO_2057_VCOMONITOR_VTH_L 0x12
+#define RADIO_2057_VCOMONITOR_VTH_H 0x13
+#define RADIO_2057_VCOCAL_BIASRESET_RFPLLREG_VOUT 0x14
+#define RADIO_2057_VCO_VARCSIZE_IDAC 0x15
+#define RADIO_2057_VCOCAL_COUNTVAL0 0x16
+#define RADIO_2057_VCOCAL_COUNTVAL1 0x17
+#define RADIO_2057_VCOCAL_INTCLK_COUNT 0x18
+#define RADIO_2057_VCOCAL_MASTER 0x19
+#define RADIO_2057_VCOCAL_NUMCAPCHANGE 0x1a
+#define RADIO_2057_VCOCAL_WINSIZE 0x1b
+#define RADIO_2057_VCOCAL_DELAY_AFTER_REFRESH 0x1c
+#define RADIO_2057_VCOCAL_DELAY_AFTER_CLOSELOOP 0x1d
+#define RADIO_2057_VCOCAL_DELAY_AFTER_OPENLOOP 0x1e
+#define RADIO_2057_VCOCAL_DELAY_BEFORE_OPENLOOP 0x1f
+#define RADIO_2057_VCO_FORCECAPEN_FORCECAP1 0x20
+#define RADIO_2057_VCO_FORCECAP0 0x21
+#define RADIO_2057_RFPLL_REFMASTER_SPAREXTALSIZE 0x22
+#define RADIO_2057_RFPLL_PFD_RESET_PW 0x23
+#define RADIO_2057_RFPLL_LOOPFILTER_R2 0x24
+#define RADIO_2057_RFPLL_LOOPFILTER_R1 0x25
+#define RADIO_2057_RFPLL_LOOPFILTER_C3 0x26
+#define RADIO_2057_RFPLL_LOOPFILTER_C2 0x27
+#define RADIO_2057_RFPLL_LOOPFILTER_C1 0x28
+#define RADIO_2057_CP_KPD_IDAC 0x29
+#define RADIO_2057_RFPLL_IDACS 0x2a
+#define RADIO_2057_RFPLL_MISC_EN 0x2b
+#define RADIO_2057_RFPLL_MMD0 0x2c
+#define RADIO_2057_RFPLL_MMD1 0x2d
+#define RADIO_2057_RFPLL_MISC_CAL_RESETN 0x2e
+#define RADIO_2057_JTAGXTAL_SIZE_CPBIAS_FILTRES 0x2f
+#define RADIO_2057_VCO_ALCREF_BBPLLXTAL_SIZE 0x30
+#define RADIO_2057_VCOCAL_READCAP0 0x31
+#define RADIO_2057_VCOCAL_READCAP1 0x32
+#define RADIO_2057_VCOCAL_STATUS 0x33
+#define RADIO_2057_LOGEN_PUS 0x34
+#define RADIO_2057_LOGEN_PTAT_RESETS 0x35
+#define RADIO_2057_VCOBUF_IDACS 0x36
+#define RADIO_2057_VCOBUF_TUNE 0x37
+#define RADIO_2057_CMOSBUF_TX2GQ_IDACS 0x38
+#define RADIO_2057_CMOSBUF_TX2GI_IDACS 0x39
+#define RADIO_2057_CMOSBUF_TX5GQ_IDACS 0x3a
+#define RADIO_2057_CMOSBUF_TX5GI_IDACS 0x3b
+#define RADIO_2057_CMOSBUF_RX2GQ_IDACS 0x3c
+#define RADIO_2057_CMOSBUF_RX2GI_IDACS 0x3d
+#define RADIO_2057_CMOSBUF_RX5GQ_IDACS 0x3e
+#define RADIO_2057_CMOSBUF_RX5GI_IDACS 0x3f
+#define RADIO_2057_LOGEN_MX2G_IDACS 0x40
+#define RADIO_2057_LOGEN_MX2G_TUNE 0x41
+#define RADIO_2057_LOGEN_MX5G_IDACS 0x42
+#define RADIO_2057_LOGEN_MX5G_TUNE 0x43
+#define RADIO_2057_LOGEN_MX5G_RCCR 0x44
+#define RADIO_2057_LOGEN_INDBUF2G_IDAC 0x45
+#define RADIO_2057_LOGEN_INDBUF2G_IBOOST 0x46
+#define RADIO_2057_LOGEN_INDBUF2G_TUNE 0x47
+#define RADIO_2057_LOGEN_INDBUF5G_IDAC 0x48
+#define RADIO_2057_LOGEN_INDBUF5G_IBOOST 0x49
+#define RADIO_2057_LOGEN_INDBUF5G_TUNE 0x4a
+#define RADIO_2057_CMOSBUF_TX_RCCR 0x4b
+#define RADIO_2057_CMOSBUF_RX_RCCR 0x4c
+#define RADIO_2057_LOGEN_SEL_PKDET 0x4d
+#define RADIO_2057_CMOSBUF_SHAREIQ_PTAT 0x4e
+#define RADIO_2057_RXTXBIAS_CONFIG_CORE0 0x4f
+#define RADIO_2057_TXGM_TXRF_PUS_CORE0 0x50
+#define RADIO_2057_TXGM_IDAC_BLEED_CORE0 0x51
+#define RADIO_2057_TXGM_GAIN_CORE0 0x56
+#define RADIO_2057_TXGM2G_PKDET_PUS_CORE0 0x57
+#define RADIO_2057_PAD2G_PTATS_CORE0 0x58
+#define RADIO_2057_PAD2G_IDACS_CORE0 0x59
+#define RADIO_2057_PAD2G_BOOST_PU_CORE0 0x5a
+#define RADIO_2057_PAD2G_CASCV_GAIN_CORE0 0x5b
+#define RADIO_2057_TXMIX2G_TUNE_BOOST_PU_CORE0 0x5c
+#define RADIO_2057_TXMIX2G_LODC_CORE0 0x5d
+#define RADIO_2057_PAD2G_TUNE_PUS_CORE0 0x5e
+#define RADIO_2057_IPA2G_GAIN_CORE0 0x5f
+#define RADIO_2057_TSSI2G_SPARE1_CORE0 0x60
+#define RADIO_2057_TSSI2G_SPARE2_CORE0 0x61
+#define RADIO_2057_IPA2G_TUNEV_CASCV_PTAT_CORE0 0x62
+#define RADIO_2057_IPA2G_IMAIN_CORE0 0x63
+#define RADIO_2057_IPA2G_CASCONV_CORE0 0x64
+#define RADIO_2057_IPA2G_CASCOFFV_CORE0 0x65
+#define RADIO_2057_IPA2G_BIAS_FILTER_CORE0 0x66
+#define RADIO_2057_TX5G_PKDET_CORE0 0x69
+#define RADIO_2057_PGA_PTAT_TXGM5G_PU_CORE0 0x6a
+#define RADIO_2057_PAD5G_PTATS1_CORE0 0x6b
+#define RADIO_2057_PAD5G_CLASS_PTATS2_CORE0 0x6c
+#define RADIO_2057_PGA_BOOSTPTAT_IMAIN_CORE0 0x6d
+#define RADIO_2057_PAD5G_CASCV_IMAIN_CORE0 0x6e
+#define RADIO_2057_TXMIX5G_IBOOST_PAD_IAUX_CORE0 0x6f
+#define RADIO_2057_PGA_BOOST_TUNE_CORE0 0x70
+#define RADIO_2057_PGA_GAIN_CORE0 0x71
+#define RADIO_2057_PAD5G_CASCOFFV_GAIN_PUS_CORE0 0x72
+#define RADIO_2057_TXMIX5G_BOOST_TUNE_CORE0 0x73
+#define RADIO_2057_PAD5G_TUNE_MISC_PUS_CORE0 0x74
+#define RADIO_2057_IPA5G_IAUX_CORE0 0x75
+#define RADIO_2057_IPA5G_GAIN_CORE0 0x76
+#define RADIO_2057_TSSI5G_SPARE1_CORE0 0x77
+#define RADIO_2057_TSSI5G_SPARE2_CORE0 0x78
+#define RADIO_2057_IPA5G_CASCOFFV_PU_CORE0 0x79
+#define RADIO_2057_IPA5G_PTAT_CORE0 0x7a
+#define RADIO_2057_IPA5G_IMAIN_CORE0 0x7b
+#define RADIO_2057_IPA5G_CASCONV_CORE0 0x7c
+#define RADIO_2057_IPA5G_BIAS_FILTER_CORE0 0x7d
+#define RADIO_2057_PAD_BIAS_FILTER_BWS_CORE0 0x80
+#define RADIO_2057_TR2G_CONFIG1_CORE0_NU 0x81
+#define RADIO_2057_TR2G_CONFIG2_CORE0_NU 0x82
+#define RADIO_2057_LNA5G_RFEN_CORE0 0x83
+#define RADIO_2057_TR5G_CONFIG2_CORE0_NU 0x84
+#define RADIO_2057_RXRFBIAS_IBOOST_PU_CORE0 0x85
+#define RADIO_2057_RXRF_IABAND_RXGM_IMAIN_PTAT_CORE0 0x86
+#define RADIO_2057_RXGM_CMFBITAIL_AUXPTAT_CORE0 0x87
+#define RADIO_2057_RXMIX_ICORE_RXGM_IAUX_CORE0 0x88
+#define RADIO_2057_RXMIX_CMFBITAIL_PU_CORE0 0x89
+#define RADIO_2057_LNA2_IMAIN_PTAT_PU_CORE0 0x8a
+#define RADIO_2057_LNA2_IAUX_PTAT_CORE0 0x8b
+#define RADIO_2057_LNA1_IMAIN_PTAT_PU_CORE0 0x8c
+#define RADIO_2057_LNA15G_INPUT_MATCH_TUNE_CORE0 0x8d
+#define RADIO_2057_RXRFBIAS_BANDSEL_CORE0 0x8e
+#define RADIO_2057_TIA_CONFIG_CORE0 0x8f
+#define RADIO_2057_TIA_IQGAIN_CORE0 0x90
+#define RADIO_2057_TIA_IBIAS2_CORE0 0x91
+#define RADIO_2057_TIA_IBIAS1_CORE0 0x92
+#define RADIO_2057_TIA_SPARE_Q_CORE0 0x93
+#define RADIO_2057_TIA_SPARE_I_CORE0 0x94
+#define RADIO_2057_RXMIX2G_PUS_CORE0 0x95
+#define RADIO_2057_RXMIX2G_VCMREFS_CORE0 0x96
+#define RADIO_2057_RXMIX2G_LODC_QI_CORE0 0x97
+#define RADIO_2057_W12G_BW_LNA2G_PUS_CORE0 0x98
+#define RADIO_2057_LNA2G_GAIN_CORE0 0x99
+#define RADIO_2057_LNA2G_TUNE_CORE0 0x9a
+#define RADIO_2057_RXMIX5G_PUS_CORE0 0x9b
+#define RADIO_2057_RXMIX5G_VCMREFS_CORE0 0x9c
+#define RADIO_2057_RXMIX5G_LODC_QI_CORE0 0x9d
+#define RADIO_2057_W15G_BW_LNA5G_PUS_CORE0 0x9e
+#define RADIO_2057_LNA5G_GAIN_CORE0 0x9f
+#define RADIO_2057_LNA5G_TUNE_CORE0 0xa0
+#define RADIO_2057_LPFSEL_TXRX_RXBB_PUS_CORE0 0xa1
+#define RADIO_2057_RXBB_BIAS_MASTER_CORE0 0xa2
+#define RADIO_2057_RXBB_VGABUF_IDACS_CORE0 0xa3
+#define RADIO_2057_LPF_VCMREF_TXBUF_VCMREF_CORE0 0xa4
+#define RADIO_2057_TXBUF_VINCM_CORE0 0xa5
+#define RADIO_2057_TXBUF_IDACS_CORE0 0xa6
+#define RADIO_2057_LPF_RESP_RXBUF_BW_CORE0 0xa7
+#define RADIO_2057_RXBB_CC_CORE0 0xa8
+#define RADIO_2057_RXBB_SPARE3_CORE0 0xa9
+#define RADIO_2057_RXBB_RCCAL_HPC_CORE0 0xaa
+#define RADIO_2057_LPF_IDACS_CORE0 0xab
+#define RADIO_2057_LPFBYP_DCLOOP_BYP_IDAC_CORE0 0xac
+#define RADIO_2057_TXBUF_GAIN_CORE0 0xad
+#define RADIO_2057_AFELOOPBACK_AACI_RESP_CORE0 0xae
+#define RADIO_2057_RXBUF_DEGEN_CORE0 0xaf
+#define RADIO_2057_RXBB_SPARE2_CORE0 0xb0
+#define RADIO_2057_RXBB_SPARE1_CORE0 0xb1
+#define RADIO_2057_RSSI_MASTER_CORE0 0xb2
+#define RADIO_2057_W2_MASTER_CORE0 0xb3
+#define RADIO_2057_NB_MASTER_CORE0 0xb4
+#define RADIO_2057_W2_IDACS0_Q_CORE0 0xb5
+#define RADIO_2057_W2_IDACS1_Q_CORE0 0xb6
+#define RADIO_2057_W2_IDACS0_I_CORE0 0xb7
+#define RADIO_2057_W2_IDACS1_I_CORE0 0xb8
+#define RADIO_2057_RSSI_GPAIOSEL_W1_IDACS_CORE0 0xb9
+#define RADIO_2057_NB_IDACS_Q_CORE0 0xba
+#define RADIO_2057_NB_IDACS_I_CORE0 0xbb
+#define RADIO_2057_BACKUP4_CORE0 0xc1
+#define RADIO_2057_BACKUP3_CORE0 0xc2
+#define RADIO_2057_BACKUP2_CORE0 0xc3
+#define RADIO_2057_BACKUP1_CORE0 0xc4
+#define RADIO_2057_SPARE16_CORE0 0xc5
+#define RADIO_2057_SPARE15_CORE0 0xc6
+#define RADIO_2057_SPARE14_CORE0 0xc7
+#define RADIO_2057_SPARE13_CORE0 0xc8
+#define RADIO_2057_SPARE12_CORE0 0xc9
+#define RADIO_2057_SPARE11_CORE0 0xca
+#define RADIO_2057_TX2G_BIAS_RESETS_CORE0 0xcb
+#define RADIO_2057_TX5G_BIAS_RESETS_CORE0 0xcc
+#define RADIO_2057_IQTEST_SEL_PU 0xcd
+#define RADIO_2057_XTAL_CONFIG2 0xce
+#define RADIO_2057_BUFS_MISC_LPFBW_CORE0 0xcf
+#define RADIO_2057_TXLPF_RCCAL_CORE0 0xd0
+#define RADIO_2057_RXBB_GPAIOSEL_RXLPF_RCCAL_CORE0 0xd1
+#define RADIO_2057_LPF_GAIN_CORE0 0xd2
+#define RADIO_2057_DACBUF_IDACS_BW_CORE0 0xd3
+#define RADIO_2057_RXTXBIAS_CONFIG_CORE1 0xd4
+#define RADIO_2057_TXGM_TXRF_PUS_CORE1 0xd5
+#define RADIO_2057_TXGM_IDAC_BLEED_CORE1 0xd6
+#define RADIO_2057_TXGM_GAIN_CORE1 0xdb
+#define RADIO_2057_TXGM2G_PKDET_PUS_CORE1 0xdc
+#define RADIO_2057_PAD2G_PTATS_CORE1 0xdd
+#define RADIO_2057_PAD2G_IDACS_CORE1 0xde
+#define RADIO_2057_PAD2G_BOOST_PU_CORE1 0xdf
+#define RADIO_2057_PAD2G_CASCV_GAIN_CORE1 0xe0
+#define RADIO_2057_TXMIX2G_TUNE_BOOST_PU_CORE1 0xe1
+#define RADIO_2057_TXMIX2G_LODC_CORE1 0xe2
+#define RADIO_2057_PAD2G_TUNE_PUS_CORE1 0xe3
+#define RADIO_2057_IPA2G_GAIN_CORE1 0xe4
+#define RADIO_2057_TSSI2G_SPARE1_CORE1 0xe5
+#define RADIO_2057_TSSI2G_SPARE2_CORE1 0xe6
+#define RADIO_2057_IPA2G_TUNEV_CASCV_PTAT_CORE1 0xe7
+#define RADIO_2057_IPA2G_IMAIN_CORE1 0xe8
+#define RADIO_2057_IPA2G_CASCONV_CORE1 0xe9
+#define RADIO_2057_IPA2G_CASCOFFV_CORE1 0xea
+#define RADIO_2057_IPA2G_BIAS_FILTER_CORE1 0xeb
+#define RADIO_2057_TX5G_PKDET_CORE1 0xee
+#define RADIO_2057_PGA_PTAT_TXGM5G_PU_CORE1 0xef
+#define RADIO_2057_PAD5G_PTATS1_CORE1 0xf0
+#define RADIO_2057_PAD5G_CLASS_PTATS2_CORE1 0xf1
+#define RADIO_2057_PGA_BOOSTPTAT_IMAIN_CORE1 0xf2
+#define RADIO_2057_PAD5G_CASCV_IMAIN_CORE1 0xf3
+#define RADIO_2057_TXMIX5G_IBOOST_PAD_IAUX_CORE1 0xf4
+#define RADIO_2057_PGA_BOOST_TUNE_CORE1 0xf5
+#define RADIO_2057_PGA_GAIN_CORE1 0xf6
+#define RADIO_2057_PAD5G_CASCOFFV_GAIN_PUS_CORE1 0xf7
+#define RADIO_2057_TXMIX5G_BOOST_TUNE_CORE1 0xf8
+#define RADIO_2057_PAD5G_TUNE_MISC_PUS_CORE1 0xf9
+#define RADIO_2057_IPA5G_IAUX_CORE1 0xfa
+#define RADIO_2057_IPA5G_GAIN_CORE1 0xfb
+#define RADIO_2057_TSSI5G_SPARE1_CORE1 0xfc
+#define RADIO_2057_TSSI5G_SPARE2_CORE1 0xfd
+#define RADIO_2057_IPA5G_CASCOFFV_PU_CORE1 0xfe
+#define RADIO_2057_IPA5G_PTAT_CORE1 0xff
+#define RADIO_2057_IPA5G_IMAIN_CORE1 0x100
+#define RADIO_2057_IPA5G_CASCONV_CORE1 0x101
+#define RADIO_2057_IPA5G_BIAS_FILTER_CORE1 0x102
+#define RADIO_2057_PAD_BIAS_FILTER_BWS_CORE1 0x105
+#define RADIO_2057_TR2G_CONFIG1_CORE1_NU 0x106
+#define RADIO_2057_TR2G_CONFIG2_CORE1_NU 0x107
+#define RADIO_2057_LNA5G_RFEN_CORE1 0x108
+#define RADIO_2057_TR5G_CONFIG2_CORE1_NU 0x109
+#define RADIO_2057_RXRFBIAS_IBOOST_PU_CORE1 0x10a
+#define RADIO_2057_RXRF_IABAND_RXGM_IMAIN_PTAT_CORE1 0x10b
+#define RADIO_2057_RXGM_CMFBITAIL_AUXPTAT_CORE1 0x10c
+#define RADIO_2057_RXMIX_ICORE_RXGM_IAUX_CORE1 0x10d
+#define RADIO_2057_RXMIX_CMFBITAIL_PU_CORE1 0x10e
+#define RADIO_2057_LNA2_IMAIN_PTAT_PU_CORE1 0x10f
+#define RADIO_2057_LNA2_IAUX_PTAT_CORE1 0x110
+#define RADIO_2057_LNA1_IMAIN_PTAT_PU_CORE1 0x111
+#define RADIO_2057_LNA15G_INPUT_MATCH_TUNE_CORE1 0x112
+#define RADIO_2057_RXRFBIAS_BANDSEL_CORE1 0x113
+#define RADIO_2057_TIA_CONFIG_CORE1 0x114
+#define RADIO_2057_TIA_IQGAIN_CORE1 0x115
+#define RADIO_2057_TIA_IBIAS2_CORE1 0x116
+#define RADIO_2057_TIA_IBIAS1_CORE1 0x117
+#define RADIO_2057_TIA_SPARE_Q_CORE1 0x118
+#define RADIO_2057_TIA_SPARE_I_CORE1 0x119
+#define RADIO_2057_RXMIX2G_PUS_CORE1 0x11a
+#define RADIO_2057_RXMIX2G_VCMREFS_CORE1 0x11b
+#define RADIO_2057_RXMIX2G_LODC_QI_CORE1 0x11c
+#define RADIO_2057_W12G_BW_LNA2G_PUS_CORE1 0x11d
+#define RADIO_2057_LNA2G_GAIN_CORE1 0x11e
+#define RADIO_2057_LNA2G_TUNE_CORE1 0x11f
+#define RADIO_2057_RXMIX5G_PUS_CORE1 0x120
+#define RADIO_2057_RXMIX5G_VCMREFS_CORE1 0x121
+#define RADIO_2057_RXMIX5G_LODC_QI_CORE1 0x122
+#define RADIO_2057_W15G_BW_LNA5G_PUS_CORE1 0x123
+#define RADIO_2057_LNA5G_GAIN_CORE1 0x124
+#define RADIO_2057_LNA5G_TUNE_CORE1 0x125
+#define RADIO_2057_LPFSEL_TXRX_RXBB_PUS_CORE1 0x126
+#define RADIO_2057_RXBB_BIAS_MASTER_CORE1 0x127
+#define RADIO_2057_RXBB_VGABUF_IDACS_CORE1 0x128
+#define RADIO_2057_LPF_VCMREF_TXBUF_VCMREF_CORE1 0x129
+#define RADIO_2057_TXBUF_VINCM_CORE1 0x12a
+#define RADIO_2057_TXBUF_IDACS_CORE1 0x12b
+#define RADIO_2057_LPF_RESP_RXBUF_BW_CORE1 0x12c
+#define RADIO_2057_RXBB_CC_CORE1 0x12d
+#define RADIO_2057_RXBB_SPARE3_CORE1 0x12e
+#define RADIO_2057_RXBB_RCCAL_HPC_CORE1 0x12f
+#define RADIO_2057_LPF_IDACS_CORE1 0x130
+#define RADIO_2057_LPFBYP_DCLOOP_BYP_IDAC_CORE1 0x131
+#define RADIO_2057_TXBUF_GAIN_CORE1 0x132
+#define RADIO_2057_AFELOOPBACK_AACI_RESP_CORE1 0x133
+#define RADIO_2057_RXBUF_DEGEN_CORE1 0x134
+#define RADIO_2057_RXBB_SPARE2_CORE1 0x135
+#define RADIO_2057_RXBB_SPARE1_CORE1 0x136
+#define RADIO_2057_RSSI_MASTER_CORE1 0x137
+#define RADIO_2057_W2_MASTER_CORE1 0x138
+#define RADIO_2057_NB_MASTER_CORE1 0x139
+#define RADIO_2057_W2_IDACS0_Q_CORE1 0x13a
+#define RADIO_2057_W2_IDACS1_Q_CORE1 0x13b
+#define RADIO_2057_W2_IDACS0_I_CORE1 0x13c
+#define RADIO_2057_W2_IDACS1_I_CORE1 0x13d
+#define RADIO_2057_RSSI_GPAIOSEL_W1_IDACS_CORE1 0x13e
+#define RADIO_2057_NB_IDACS_Q_CORE1 0x13f
+#define RADIO_2057_NB_IDACS_I_CORE1 0x140
+#define RADIO_2057_BACKUP4_CORE1 0x146
+#define RADIO_2057_BACKUP3_CORE1 0x147
+#define RADIO_2057_BACKUP2_CORE1 0x148
+#define RADIO_2057_BACKUP1_CORE1 0x149
+#define RADIO_2057_SPARE16_CORE1 0x14a
+#define RADIO_2057_SPARE15_CORE1 0x14b
+#define RADIO_2057_SPARE14_CORE1 0x14c
+#define RADIO_2057_SPARE13_CORE1 0x14d
+#define RADIO_2057_SPARE12_CORE1 0x14e
+#define RADIO_2057_SPARE11_CORE1 0x14f
+#define RADIO_2057_TX2G_BIAS_RESETS_CORE1 0x150
+#define RADIO_2057_TX5G_BIAS_RESETS_CORE1 0x151
+#define RADIO_2057_SPARE8_CORE1 0x152
+#define RADIO_2057_SPARE7_CORE1 0x153
+#define RADIO_2057_BUFS_MISC_LPFBW_CORE1 0x154
+#define RADIO_2057_TXLPF_RCCAL_CORE1 0x155
+#define RADIO_2057_RXBB_GPAIOSEL_RXLPF_RCCAL_CORE1 0x156
+#define RADIO_2057_LPF_GAIN_CORE1 0x157
+#define RADIO_2057_DACBUF_IDACS_BW_CORE1 0x158
+#define RADIO_2057_DACBUF_VINCM_CORE1 0x159
+#define RADIO_2057_RCCAL_START_R1_Q1_P1 0x15a
+#define RADIO_2057_RCCAL_X1 0x15b
+#define RADIO_2057_RCCAL_TRC0 0x15c
+#define RADIO_2057_RCCAL_TRC1 0x15d
+#define RADIO_2057_RCCAL_DONE_OSCCAP 0x15e
+#define RADIO_2057_RCCAL_N0_0 0x15f
+#define RADIO_2057_RCCAL_N0_1 0x160
+#define RADIO_2057_RCCAL_N1_0 0x161
+#define RADIO_2057_RCCAL_N1_1 0x162
+#define RADIO_2057_RCAL_STATUS 0x163
+#define RADIO_2057_XTALPUOVR_PINCTRL 0x164
+#define RADIO_2057_OVR_REG0 0x165
+#define RADIO_2057_OVR_REG1 0x166
+#define RADIO_2057_OVR_REG2 0x167
+#define RADIO_2057_OVR_REG3 0x168
+#define RADIO_2057_OVR_REG4 0x169
+#define RADIO_2057_RCCAL_SCAP_VAL 0x16a
+#define RADIO_2057_RCCAL_BCAP_VAL 0x16b
+#define RADIO_2057_RCCAL_HPC_VAL 0x16c
+#define RADIO_2057_RCCAL_OVERRIDES 0x16d
+#define RADIO_2057_TX0_IQCAL_GAIN_BW 0x170
+#define RADIO_2057_TX0_LOFT_FINE_I 0x171
+#define RADIO_2057_TX0_LOFT_FINE_Q 0x172
+#define RADIO_2057_TX0_LOFT_COARSE_I 0x173
+#define RADIO_2057_TX0_LOFT_COARSE_Q 0x174
+#define RADIO_2057_TX0_TX_SSI_MASTER 0x175
+#define RADIO_2057_TX0_IQCAL_VCM_HG 0x176
+#define RADIO_2057_TX0_IQCAL_IDAC 0x177
+#define RADIO_2057_TX0_TSSI_VCM 0x178
+#define RADIO_2057_TX0_TX_SSI_MUX 0x179
+#define RADIO_2057_TX0_TSSIA 0x17a
+#define RADIO_2057_TX0_TSSIG 0x17b
+#define RADIO_2057_TX0_TSSI_MISC1 0x17c
+#define RADIO_2057_TX0_TXRXCOUPLE_2G_ATTEN 0x17d
+#define RADIO_2057_TX0_TXRXCOUPLE_2G_PWRUP 0x17e
+#define RADIO_2057_TX0_TXRXCOUPLE_5G_ATTEN 0x17f
+#define RADIO_2057_TX0_TXRXCOUPLE_5G_PWRUP 0x180
+#define RADIO_2057_TX1_IQCAL_GAIN_BW 0x190
+#define RADIO_2057_TX1_LOFT_FINE_I 0x191
+#define RADIO_2057_TX1_LOFT_FINE_Q 0x192
+#define RADIO_2057_TX1_LOFT_COARSE_I 0x193
+#define RADIO_2057_TX1_LOFT_COARSE_Q 0x194
+#define RADIO_2057_TX1_TX_SSI_MASTER 0x195
+#define RADIO_2057_TX1_IQCAL_VCM_HG 0x196
+#define RADIO_2057_TX1_IQCAL_IDAC 0x197
+#define RADIO_2057_TX1_TSSI_VCM 0x198
+#define RADIO_2057_TX1_TX_SSI_MUX 0x199
+#define RADIO_2057_TX1_TSSIA 0x19a
+#define RADIO_2057_TX1_TSSIG 0x19b
+#define RADIO_2057_TX1_TSSI_MISC1 0x19c
+#define RADIO_2057_TX1_TXRXCOUPLE_2G_ATTEN 0x19d
+#define RADIO_2057_TX1_TXRXCOUPLE_2G_PWRUP 0x19e
+#define RADIO_2057_TX1_TXRXCOUPLE_5G_ATTEN 0x19f
+#define RADIO_2057_TX1_TXRXCOUPLE_5G_PWRUP 0x1a0
+#define RADIO_2057_AFE_VCM_CAL_MASTER_CORE0 0x1a1
+#define RADIO_2057_AFE_SET_VCM_I_CORE0 0x1a2
+#define RADIO_2057_AFE_SET_VCM_Q_CORE0 0x1a3
+#define RADIO_2057_AFE_STATUS_VCM_IQADC_CORE0 0x1a4
+#define RADIO_2057_AFE_STATUS_VCM_I_CORE0 0x1a5
+#define RADIO_2057_AFE_STATUS_VCM_Q_CORE0 0x1a6
+#define RADIO_2057_AFE_VCM_CAL_MASTER_CORE1 0x1a7
+#define RADIO_2057_AFE_SET_VCM_I_CORE1 0x1a8
+#define RADIO_2057_AFE_SET_VCM_Q_CORE1 0x1a9
+#define RADIO_2057_AFE_STATUS_VCM_IQADC_CORE1 0x1aa
+#define RADIO_2057_AFE_STATUS_VCM_I_CORE1 0x1ab
+#define RADIO_2057_AFE_STATUS_VCM_Q_CORE1 0x1ac
+
+#define RADIO_2057v7_DACBUF_VINCM_CORE0 0x1ad
+#define RADIO_2057v7_RCCAL_MASTER 0x1ae
+#define RADIO_2057v7_TR2G_CONFIG3_CORE0_NU 0x1af
+#define RADIO_2057v7_TR2G_CONFIG3_CORE1_NU 0x1b0
+#define RADIO_2057v7_LOGEN_PUS1 0x1b1
+#define RADIO_2057v7_OVR_REG5 0x1b2
+#define RADIO_2057v7_OVR_REG6 0x1b3
+#define RADIO_2057v7_OVR_REG7 0x1b4
+#define RADIO_2057v7_OVR_REG8 0x1b5
+#define RADIO_2057v7_OVR_REG9 0x1b6
+#define RADIO_2057v7_OVR_REG10 0x1b7
+#define RADIO_2057v7_OVR_REG11 0x1b8
+#define RADIO_2057v7_OVR_REG12 0x1b9
+#define RADIO_2057v7_OVR_REG13 0x1ba
+#define RADIO_2057v7_OVR_REG14 0x1bb
+#define RADIO_2057v7_OVR_REG15 0x1bc
+#define RADIO_2057v7_OVR_REG16 0x1bd
+#define RADIO_2057v7_OVR_REG1 0x1be
+#define RADIO_2057v7_OVR_REG18 0x1bf
+#define RADIO_2057v7_OVR_REG19 0x1c0
+#define RADIO_2057v7_OVR_REG20 0x1c1
+#define RADIO_2057v7_OVR_REG21 0x1c2
+#define RADIO_2057v7_OVR_REG2 0x1c3
+#define RADIO_2057v7_OVR_REG23 0x1c4
+#define RADIO_2057v7_OVR_REG24 0x1c5
+#define RADIO_2057v7_OVR_REG25 0x1c6
+#define RADIO_2057v7_OVR_REG26 0x1c7
+#define RADIO_2057v7_OVR_REG27 0x1c8
+#define RADIO_2057v7_OVR_REG28 0x1c9
+#define RADIO_2057v7_IQTEST_SEL_PU2 0x1ca
+
+#define RADIO_2057_VCM_MASK 0x7
+
+#endif /* _BRCM_PHY_RADIO_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phyreg_n.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phyreg_n.h
new file mode 100644
index 000000000000..a97c3a799479
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phyreg_n.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2010 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define NPHY_TBL_ID_GAIN1 0
+#define NPHY_TBL_ID_GAIN2 1
+#define NPHY_TBL_ID_GAINBITS1 2
+#define NPHY_TBL_ID_GAINBITS2 3
+#define NPHY_TBL_ID_GAINLIMIT 4
+#define NPHY_TBL_ID_WRSSIGainLimit 5
+#define NPHY_TBL_ID_RFSEQ 7
+#define NPHY_TBL_ID_AFECTRL 8
+#define NPHY_TBL_ID_ANTSWCTRLLUT 9
+#define NPHY_TBL_ID_IQLOCAL 15
+#define NPHY_TBL_ID_NOISEVAR 16
+#define NPHY_TBL_ID_SAMPLEPLAY 17
+#define NPHY_TBL_ID_CORE1TXPWRCTL 26
+#define NPHY_TBL_ID_CORE2TXPWRCTL 27
+#define NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL 30
+
+#define NPHY_TBL_ID_EPSILONTBL0 31
+#define NPHY_TBL_ID_SCALARTBL0 32
+#define NPHY_TBL_ID_EPSILONTBL1 33
+#define NPHY_TBL_ID_SCALARTBL1 34
+
+#define NPHY_TO_BPHY_OFF 0xc00
+
+#define NPHY_BandControl_currentBand 0x0001
+#define RFCC_CHIP0_PU 0x0400
+#define RFCC_POR_FORCE 0x0040
+#define RFCC_OE_POR_FORCE 0x0080
+#define NPHY_RfctrlIntc_override_OFF 0
+#define NPHY_RfctrlIntc_override_TRSW 1
+#define NPHY_RfctrlIntc_override_PA 2
+#define NPHY_RfctrlIntc_override_EXT_LNA_PU 3
+#define NPHY_RfctrlIntc_override_EXT_LNA_GAIN 4
+#define RIFS_ENABLE 0x80
+#define BPHY_BAND_SEL_UP20 0x10
+#define NPHY_MLenable 0x02
+
+#define NPHY_RfseqMode_CoreActv_override 0x0001
+#define NPHY_RfseqMode_Trigger_override 0x0002
+#define NPHY_RfseqCoreActv_TxRxChain0 (0x11)
+#define NPHY_RfseqCoreActv_TxRxChain1 (0x22)
+
+#define NPHY_RfseqTrigger_rx2tx 0x0001
+#define NPHY_RfseqTrigger_tx2rx 0x0002
+#define NPHY_RfseqTrigger_updategainh 0x0004
+#define NPHY_RfseqTrigger_updategainl 0x0008
+#define NPHY_RfseqTrigger_updategainu 0x0010
+#define NPHY_RfseqTrigger_reset2rx 0x0020
+#define NPHY_RfseqStatus_rx2tx 0x0001
+#define NPHY_RfseqStatus_tx2rx 0x0002
+#define NPHY_RfseqStatus_updategainh 0x0004
+#define NPHY_RfseqStatus_updategainl 0x0008
+#define NPHY_RfseqStatus_updategainu 0x0010
+#define NPHY_RfseqStatus_reset2rx 0x0020
+#define NPHY_ClassifierCtrl_cck_en 0x1
+#define NPHY_ClassifierCtrl_ofdm_en 0x2
+#define NPHY_ClassifierCtrl_waited_en 0x4
+#define NPHY_IQFlip_ADC1 0x0001
+#define NPHY_IQFlip_ADC2 0x0010
+#define NPHY_sampleCmd_STOP 0x0002
+
+#define RX_GF_OR_MM 0x0004
+#define RX_GF_MM_AUTO 0x0100
+
+#define NPHY_iqloCalCmdGctl_IQLO_CAL_EN 0x8000
+
+#define NPHY_IqestCmd_iqstart 0x1
+#define NPHY_IqestCmd_iqMode 0x2
+
+#define NPHY_TxPwrCtrlCmd_pwrIndex_init 0x40
+#define NPHY_TxPwrCtrlCmd_pwrIndex_init_rev7 0x19
+
+#define PRIM_SEL_UP20 0x8000
+
+#define NPHY_RFSEQ_RX2TX 0x0
+#define NPHY_RFSEQ_TX2RX 0x1
+#define NPHY_RFSEQ_RESET2RX 0x2
+#define NPHY_RFSEQ_UPDATEGAINH 0x3
+#define NPHY_RFSEQ_UPDATEGAINL 0x4
+#define NPHY_RFSEQ_UPDATEGAINU 0x5
+
+#define NPHY_RFSEQ_CMD_NOP 0x0
+#define NPHY_RFSEQ_CMD_RXG_FBW 0x1
+#define NPHY_RFSEQ_CMD_TR_SWITCH 0x2
+#define NPHY_RFSEQ_CMD_EXT_PA 0x3
+#define NPHY_RFSEQ_CMD_RXPD_TXPD 0x4
+#define NPHY_RFSEQ_CMD_TX_GAIN 0x5
+#define NPHY_RFSEQ_CMD_RX_GAIN 0x6
+#define NPHY_RFSEQ_CMD_SET_HPF_BW 0x7
+#define NPHY_RFSEQ_CMD_CLR_HIQ_DIS 0x8
+#define NPHY_RFSEQ_CMD_END 0xf
+
+#define NPHY_REV3_RFSEQ_CMD_NOP 0x0
+#define NPHY_REV3_RFSEQ_CMD_RXG_FBW 0x1
+#define NPHY_REV3_RFSEQ_CMD_TR_SWITCH 0x2
+#define NPHY_REV3_RFSEQ_CMD_INT_PA_PU 0x3
+#define NPHY_REV3_RFSEQ_CMD_EXT_PA 0x4
+#define NPHY_REV3_RFSEQ_CMD_RXPD_TXPD 0x5
+#define NPHY_REV3_RFSEQ_CMD_TX_GAIN 0x6
+#define NPHY_REV3_RFSEQ_CMD_RX_GAIN 0x7
+#define NPHY_REV3_RFSEQ_CMD_CLR_HIQ_DIS 0x8
+#define NPHY_REV3_RFSEQ_CMD_SET_HPF_H_HPC 0x9
+#define NPHY_REV3_RFSEQ_CMD_SET_LPF_H_HPC 0xa
+#define NPHY_REV3_RFSEQ_CMD_SET_HPF_M_HPC 0xb
+#define NPHY_REV3_RFSEQ_CMD_SET_LPF_M_HPC 0xc
+#define NPHY_REV3_RFSEQ_CMD_SET_HPF_L_HPC 0xd
+#define NPHY_REV3_RFSEQ_CMD_SET_LPF_L_HPC 0xe
+#define NPHY_REV3_RFSEQ_CMD_CLR_RXRX_BIAS 0xf
+#define NPHY_REV3_RFSEQ_CMD_END 0x1f
+
+#define NPHY_RSSI_SEL_W1 0x0
+#define NPHY_RSSI_SEL_W2 0x1
+#define NPHY_RSSI_SEL_NB 0x2
+#define NPHY_RSSI_SEL_IQ 0x3
+#define NPHY_RSSI_SEL_TSSI_2G 0x4
+#define NPHY_RSSI_SEL_TSSI_5G 0x5
+#define NPHY_RSSI_SEL_TBD 0x6
+
+#define NPHY_RAIL_I 0x0
+#define NPHY_RAIL_Q 0x1
+
+#define NPHY_FORCESIG_DECODEGATEDCLKS 0x8
+
+#define NPHY_REV7_RfctrlOverride_cmd_rxrf_pu 0x0
+#define NPHY_REV7_RfctrlOverride_cmd_rx_pu 0x1
+#define NPHY_REV7_RfctrlOverride_cmd_tx_pu 0x2
+#define NPHY_REV7_RfctrlOverride_cmd_rxgain 0x3
+#define NPHY_REV7_RfctrlOverride_cmd_txgain 0x4
+
+#define NPHY_REV7_RXGAINCODE_RFMXGAIN_MASK 0x000ff
+#define NPHY_REV7_RXGAINCODE_LPFGAIN_MASK 0x0ff00
+#define NPHY_REV7_RXGAINCODE_DVGAGAIN_MASK 0xf0000
+
+#define NPHY_REV7_TXGAINCODE_TGAIN_MASK 0x7fff
+#define NPHY_REV7_TXGAINCODE_LPFGAIN_MASK 0x8000
+#define NPHY_REV7_TXGAINCODE_BIQ0GAIN_SHIFT 14
+
+#define NPHY_REV7_RFCTRLOVERRIDE_ID0 0x0
+#define NPHY_REV7_RFCTRLOVERRIDE_ID1 0x1
+#define NPHY_REV7_RFCTRLOVERRIDE_ID2 0x2
+
+#define NPHY_IqestIqAccLo(core) ((core == 0) ? 0x12c : 0x134)
+
+#define NPHY_IqestIqAccHi(core) ((core == 0) ? 0x12d : 0x135)
+
+#define NPHY_IqestipwrAccLo(core) ((core == 0) ? 0x12e : 0x136)
+
+#define NPHY_IqestipwrAccHi(core) ((core == 0) ? 0x12f : 0x137)
+
+#define NPHY_IqestqpwrAccLo(core) ((core == 0) ? 0x130 : 0x138)
+
+#define NPHY_IqestqpwrAccHi(core) ((core == 0) ? 0x131 : 0x139)
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c
new file mode 100644
index 000000000000..622c01ca72c5
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c
@@ -0,0 +1,3250 @@
+/*
+ * Copyright (c) 2010 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 <types.h>
+#include "phytbl_lcn.h"
+
+static const u32 dot11lcn_gain_tbl_rev0[] = {
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000004,
+ 0x00000000,
+ 0x00000004,
+ 0x00000008,
+ 0x00000001,
+ 0x00000005,
+ 0x00000009,
+ 0x0000000d,
+ 0x0000004d,
+ 0x0000008d,
+ 0x0000000d,
+ 0x0000004d,
+ 0x0000008d,
+ 0x000000cd,
+ 0x0000004f,
+ 0x0000008f,
+ 0x000000cf,
+ 0x000000d3,
+ 0x00000113,
+ 0x00000513,
+ 0x00000913,
+ 0x00000953,
+ 0x00000d53,
+ 0x00001153,
+ 0x00001193,
+ 0x00005193,
+ 0x00009193,
+ 0x0000d193,
+ 0x00011193,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000004,
+ 0x00000000,
+ 0x00000004,
+ 0x00000008,
+ 0x00000001,
+ 0x00000005,
+ 0x00000009,
+ 0x0000000d,
+ 0x0000004d,
+ 0x0000008d,
+ 0x0000000d,
+ 0x0000004d,
+ 0x0000008d,
+ 0x000000cd,
+ 0x0000004f,
+ 0x0000008f,
+ 0x000000cf,
+ 0x000000d3,
+ 0x00000113,
+ 0x00000513,
+ 0x00000913,
+ 0x00000953,
+ 0x00000d53,
+ 0x00001153,
+ 0x00005153,
+ 0x00009153,
+ 0x0000d153,
+ 0x00011153,
+ 0x00015153,
+ 0x00019153,
+ 0x0001d153,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+static const u32 dot11lcn_gain_tbl_rev1[] = {
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000008,
+ 0x00000004,
+ 0x00000008,
+ 0x00000001,
+ 0x00000005,
+ 0x00000009,
+ 0x0000000D,
+ 0x00000011,
+ 0x00000051,
+ 0x00000091,
+ 0x00000011,
+ 0x00000051,
+ 0x00000091,
+ 0x000000d1,
+ 0x00000053,
+ 0x00000093,
+ 0x000000d3,
+ 0x000000d7,
+ 0x00000117,
+ 0x00000517,
+ 0x00000917,
+ 0x00000957,
+ 0x00000d57,
+ 0x00001157,
+ 0x00001197,
+ 0x00005197,
+ 0x00009197,
+ 0x0000d197,
+ 0x00011197,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000008,
+ 0x00000004,
+ 0x00000008,
+ 0x00000001,
+ 0x00000005,
+ 0x00000009,
+ 0x0000000D,
+ 0x00000011,
+ 0x00000051,
+ 0x00000091,
+ 0x00000011,
+ 0x00000051,
+ 0x00000091,
+ 0x000000d1,
+ 0x00000053,
+ 0x00000093,
+ 0x000000d3,
+ 0x000000d7,
+ 0x00000117,
+ 0x00000517,
+ 0x00000917,
+ 0x00000957,
+ 0x00000d57,
+ 0x00001157,
+ 0x00005157,
+ 0x00009157,
+ 0x0000d157,
+ 0x00011157,
+ 0x00015157,
+ 0x00019157,
+ 0x0001d157,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+static const u16 dot11lcn_aux_gain_idx_tbl_rev0[] = {
+ 0x0401,
+ 0x0402,
+ 0x0403,
+ 0x0404,
+ 0x0405,
+ 0x0406,
+ 0x0407,
+ 0x0408,
+ 0x0409,
+ 0x040a,
+ 0x058b,
+ 0x058c,
+ 0x058d,
+ 0x058e,
+ 0x058f,
+ 0x0090,
+ 0x0091,
+ 0x0092,
+ 0x0193,
+ 0x0194,
+ 0x0195,
+ 0x0196,
+ 0x0197,
+ 0x0198,
+ 0x0199,
+ 0x019a,
+ 0x019b,
+ 0x019c,
+ 0x019d,
+ 0x019e,
+ 0x019f,
+ 0x01a0,
+ 0x01a1,
+ 0x01a2,
+ 0x01a3,
+ 0x01a4,
+ 0x01a5,
+ 0x0000,
+};
+
+static const u32 dot11lcn_gain_idx_tbl_rev0[] = {
+ 0x00000000,
+ 0x00000000,
+ 0x10000000,
+ 0x00000000,
+ 0x20000000,
+ 0x00000000,
+ 0x30000000,
+ 0x00000000,
+ 0x40000000,
+ 0x00000000,
+ 0x50000000,
+ 0x00000000,
+ 0x60000000,
+ 0x00000000,
+ 0x70000000,
+ 0x00000000,
+ 0x80000000,
+ 0x00000000,
+ 0x90000000,
+ 0x00000008,
+ 0xa0000000,
+ 0x00000008,
+ 0xb0000000,
+ 0x00000008,
+ 0xc0000000,
+ 0x00000008,
+ 0xd0000000,
+ 0x00000008,
+ 0xe0000000,
+ 0x00000008,
+ 0xf0000000,
+ 0x00000008,
+ 0x00000000,
+ 0x00000009,
+ 0x10000000,
+ 0x00000009,
+ 0x20000000,
+ 0x00000019,
+ 0x30000000,
+ 0x00000019,
+ 0x40000000,
+ 0x00000019,
+ 0x50000000,
+ 0x00000019,
+ 0x60000000,
+ 0x00000019,
+ 0x70000000,
+ 0x00000019,
+ 0x80000000,
+ 0x00000019,
+ 0x90000000,
+ 0x00000019,
+ 0xa0000000,
+ 0x00000019,
+ 0xb0000000,
+ 0x00000019,
+ 0xc0000000,
+ 0x00000019,
+ 0xd0000000,
+ 0x00000019,
+ 0xe0000000,
+ 0x00000019,
+ 0xf0000000,
+ 0x00000019,
+ 0x00000000,
+ 0x0000001a,
+ 0x10000000,
+ 0x0000001a,
+ 0x20000000,
+ 0x0000001a,
+ 0x30000000,
+ 0x0000001a,
+ 0x40000000,
+ 0x0000001a,
+ 0x50000000,
+ 0x00000002,
+ 0x60000000,
+ 0x00000002,
+ 0x70000000,
+ 0x00000002,
+ 0x80000000,
+ 0x00000002,
+ 0x90000000,
+ 0x00000002,
+ 0xa0000000,
+ 0x00000002,
+ 0xb0000000,
+ 0x00000002,
+ 0xc0000000,
+ 0x0000000a,
+ 0xd0000000,
+ 0x0000000a,
+ 0xe0000000,
+ 0x0000000a,
+ 0xf0000000,
+ 0x0000000a,
+ 0x00000000,
+ 0x0000000b,
+ 0x10000000,
+ 0x0000000b,
+ 0x20000000,
+ 0x0000000b,
+ 0x30000000,
+ 0x0000000b,
+ 0x40000000,
+ 0x0000000b,
+ 0x50000000,
+ 0x0000001b,
+ 0x60000000,
+ 0x0000001b,
+ 0x70000000,
+ 0x0000001b,
+ 0x80000000,
+ 0x0000001b,
+ 0x90000000,
+ 0x0000001b,
+ 0xa0000000,
+ 0x0000001b,
+ 0xb0000000,
+ 0x0000001b,
+ 0xc0000000,
+ 0x0000001b,
+ 0xd0000000,
+ 0x0000001b,
+ 0xe0000000,
+ 0x0000001b,
+ 0xf0000000,
+ 0x0000001b,
+ 0x00000000,
+ 0x0000001c,
+ 0x10000000,
+ 0x0000001c,
+ 0x20000000,
+ 0x0000001c,
+ 0x30000000,
+ 0x0000001c,
+ 0x40000000,
+ 0x0000001c,
+ 0x50000000,
+ 0x0000001c,
+ 0x60000000,
+ 0x0000001c,
+ 0x70000000,
+ 0x0000001c,
+ 0x80000000,
+ 0x0000001c,
+ 0x90000000,
+ 0x0000001c,
+};
+
+static const u16 dot11lcn_aux_gain_idx_tbl_2G[] = {
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0001,
+ 0x0080,
+ 0x0081,
+ 0x0100,
+ 0x0101,
+ 0x0180,
+ 0x0181,
+ 0x0182,
+ 0x0183,
+ 0x0184,
+ 0x0185,
+ 0x0186,
+ 0x0187,
+ 0x0188,
+ 0x0285,
+ 0x0289,
+ 0x028a,
+ 0x028b,
+ 0x028c,
+ 0x028d,
+ 0x028e,
+ 0x028f,
+ 0x0290,
+ 0x0291,
+ 0x0292,
+ 0x0293,
+ 0x0294,
+ 0x0295,
+ 0x0296,
+ 0x0297,
+ 0x0298,
+ 0x0299,
+ 0x029a,
+ 0x0000
+};
+
+static const u8 dot11lcn_gain_val_tbl_2G[] = {
+ 0xfc,
+ 0x02,
+ 0x08,
+ 0x0e,
+ 0x13,
+ 0x1b,
+ 0xfc,
+ 0x02,
+ 0x08,
+ 0x0e,
+ 0x13,
+ 0x1b,
+ 0xfc,
+ 0x00,
+ 0x0c,
+ 0x03,
+ 0xeb,
+ 0xfe,
+ 0x07,
+ 0x0b,
+ 0x0f,
+ 0xfb,
+ 0xfe,
+ 0x01,
+ 0x05,
+ 0x08,
+ 0x0b,
+ 0x0e,
+ 0x11,
+ 0x14,
+ 0x17,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x03,
+ 0x06,
+ 0x09,
+ 0x0c,
+ 0x0f,
+ 0x12,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x03,
+ 0x06,
+ 0x09,
+ 0x0c,
+ 0x0f,
+ 0x12,
+ 0x15,
+ 0x18,
+ 0x1b,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+};
+
+static const u32 dot11lcn_gain_idx_tbl_2G[] = {
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x10000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000008,
+ 0x10000000,
+ 0x00000008,
+ 0x00000000,
+ 0x00000010,
+ 0x10000000,
+ 0x00000010,
+ 0x00000000,
+ 0x00000018,
+ 0x10000000,
+ 0x00000018,
+ 0x20000000,
+ 0x00000018,
+ 0x30000000,
+ 0x00000018,
+ 0x40000000,
+ 0x00000018,
+ 0x50000000,
+ 0x00000018,
+ 0x60000000,
+ 0x00000018,
+ 0x70000000,
+ 0x00000018,
+ 0x80000000,
+ 0x00000018,
+ 0x50000000,
+ 0x00000028,
+ 0x90000000,
+ 0x00000028,
+ 0xa0000000,
+ 0x00000028,
+ 0xb0000000,
+ 0x00000028,
+ 0xc0000000,
+ 0x00000028,
+ 0xd0000000,
+ 0x00000028,
+ 0xe0000000,
+ 0x00000028,
+ 0xf0000000,
+ 0x00000028,
+ 0x00000000,
+ 0x00000029,
+ 0x10000000,
+ 0x00000029,
+ 0x20000000,
+ 0x00000029,
+ 0x30000000,
+ 0x00000029,
+ 0x40000000,
+ 0x00000029,
+ 0x50000000,
+ 0x00000029,
+ 0x60000000,
+ 0x00000029,
+ 0x70000000,
+ 0x00000029,
+ 0x80000000,
+ 0x00000029,
+ 0x90000000,
+ 0x00000029,
+ 0xa0000000,
+ 0x00000029,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x10000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000008,
+ 0x10000000,
+ 0x00000008,
+ 0x00000000,
+ 0x00000010,
+ 0x10000000,
+ 0x00000010,
+ 0x00000000,
+ 0x00000018,
+ 0x10000000,
+ 0x00000018,
+ 0x20000000,
+ 0x00000018,
+ 0x30000000,
+ 0x00000018,
+ 0x40000000,
+ 0x00000018,
+ 0x50000000,
+ 0x00000018,
+ 0x60000000,
+ 0x00000018,
+ 0x70000000,
+ 0x00000018,
+ 0x80000000,
+ 0x00000018,
+ 0x50000000,
+ 0x00000028,
+ 0x90000000,
+ 0x00000028,
+ 0xa0000000,
+ 0x00000028,
+ 0xb0000000,
+ 0x00000028,
+ 0xc0000000,
+ 0x00000028,
+ 0xd0000000,
+ 0x00000028,
+ 0xe0000000,
+ 0x00000028,
+ 0xf0000000,
+ 0x00000028,
+ 0x00000000,
+ 0x00000029,
+ 0x10000000,
+ 0x00000029,
+ 0x20000000,
+ 0x00000029,
+ 0x30000000,
+ 0x00000029,
+ 0x40000000,
+ 0x00000029,
+ 0x50000000,
+ 0x00000029,
+ 0x60000000,
+ 0x00000029,
+ 0x70000000,
+ 0x00000029,
+ 0x80000000,
+ 0x00000029,
+ 0x90000000,
+ 0x00000029,
+ 0xa0000000,
+ 0x00000029,
+ 0xb0000000,
+ 0x00000029,
+ 0xc0000000,
+ 0x00000029,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000
+};
+
+static const u32 dot11lcn_gain_tbl_2G[] = {
+ 0x00000000,
+ 0x00000004,
+ 0x00000008,
+ 0x00000001,
+ 0x00000005,
+ 0x00000009,
+ 0x0000000d,
+ 0x0000004d,
+ 0x0000008d,
+ 0x00000049,
+ 0x00000089,
+ 0x000000c9,
+ 0x0000004b,
+ 0x0000008b,
+ 0x000000cb,
+ 0x000000cf,
+ 0x0000010f,
+ 0x0000050f,
+ 0x0000090f,
+ 0x0000094f,
+ 0x00000d4f,
+ 0x0000114f,
+ 0x0000118f,
+ 0x0000518f,
+ 0x0000918f,
+ 0x0000d18f,
+ 0x0001118f,
+ 0x0001518f,
+ 0x0001918f,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000
+};
+
+static const u32 dot11lcn_gain_tbl_extlna_2G[] = {
+ 0x00000000,
+ 0x00000004,
+ 0x00000008,
+ 0x00000001,
+ 0x00000005,
+ 0x00000009,
+ 0x0000000d,
+ 0x00000003,
+ 0x00000007,
+ 0x0000000b,
+ 0x0000000f,
+ 0x0000004f,
+ 0x0000008f,
+ 0x000000cf,
+ 0x0000010f,
+ 0x0000014f,
+ 0x0000018f,
+ 0x0000058f,
+ 0x0000098f,
+ 0x00000d8f,
+ 0x00008000,
+ 0x00008004,
+ 0x00008008,
+ 0x00008001,
+ 0x00008005,
+ 0x00008009,
+ 0x0000800d,
+ 0x00008003,
+ 0x00008007,
+ 0x0000800b,
+ 0x0000800f,
+ 0x0000804f,
+ 0x0000808f,
+ 0x000080cf,
+ 0x0000810f,
+ 0x0000814f,
+ 0x0000818f,
+ 0x0000858f,
+ 0x0000898f,
+ 0x00008d8f,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000
+};
+
+static const u16 dot11lcn_aux_gain_idx_tbl_extlna_2G[] = {
+ 0x0400,
+ 0x0400,
+ 0x0400,
+ 0x0400,
+ 0x0400,
+ 0x0400,
+ 0x0400,
+ 0x0400,
+ 0x0400,
+ 0x0401,
+ 0x0402,
+ 0x0403,
+ 0x0404,
+ 0x0483,
+ 0x0484,
+ 0x0485,
+ 0x0486,
+ 0x0583,
+ 0x0584,
+ 0x0585,
+ 0x0587,
+ 0x0588,
+ 0x0589,
+ 0x058a,
+ 0x0687,
+ 0x0688,
+ 0x0689,
+ 0x068a,
+ 0x068b,
+ 0x068c,
+ 0x068d,
+ 0x068e,
+ 0x068f,
+ 0x0690,
+ 0x0691,
+ 0x0692,
+ 0x0693,
+ 0x0000
+};
+
+static const u8 dot11lcn_gain_val_tbl_extlna_2G[] = {
+ 0xfc,
+ 0x02,
+ 0x08,
+ 0x0e,
+ 0x13,
+ 0x1b,
+ 0xfc,
+ 0x02,
+ 0x08,
+ 0x0e,
+ 0x13,
+ 0x1b,
+ 0xfc,
+ 0x00,
+ 0x0f,
+ 0x03,
+ 0xeb,
+ 0xfe,
+ 0x07,
+ 0x0b,
+ 0x0f,
+ 0xfb,
+ 0xfe,
+ 0x01,
+ 0x05,
+ 0x08,
+ 0x0b,
+ 0x0e,
+ 0x11,
+ 0x14,
+ 0x17,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x03,
+ 0x06,
+ 0x09,
+ 0x0c,
+ 0x0f,
+ 0x12,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x03,
+ 0x06,
+ 0x09,
+ 0x0c,
+ 0x0f,
+ 0x12,
+ 0x15,
+ 0x18,
+ 0x1b,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+};
+
+static const u32 dot11lcn_gain_idx_tbl_extlna_2G[] = {
+ 0x00000000,
+ 0x00000040,
+ 0x00000000,
+ 0x00000040,
+ 0x00000000,
+ 0x00000040,
+ 0x00000000,
+ 0x00000040,
+ 0x00000000,
+ 0x00000040,
+ 0x00000000,
+ 0x00000040,
+ 0x00000000,
+ 0x00000040,
+ 0x00000000,
+ 0x00000040,
+ 0x00000000,
+ 0x00000040,
+ 0x10000000,
+ 0x00000040,
+ 0x20000000,
+ 0x00000040,
+ 0x30000000,
+ 0x00000040,
+ 0x40000000,
+ 0x00000040,
+ 0x30000000,
+ 0x00000048,
+ 0x40000000,
+ 0x00000048,
+ 0x50000000,
+ 0x00000048,
+ 0x60000000,
+ 0x00000048,
+ 0x30000000,
+ 0x00000058,
+ 0x40000000,
+ 0x00000058,
+ 0x50000000,
+ 0x00000058,
+ 0x70000000,
+ 0x00000058,
+ 0x80000000,
+ 0x00000058,
+ 0x90000000,
+ 0x00000058,
+ 0xa0000000,
+ 0x00000058,
+ 0x70000000,
+ 0x00000068,
+ 0x80000000,
+ 0x00000068,
+ 0x90000000,
+ 0x00000068,
+ 0xa0000000,
+ 0x00000068,
+ 0xb0000000,
+ 0x00000068,
+ 0xc0000000,
+ 0x00000068,
+ 0xd0000000,
+ 0x00000068,
+ 0xe0000000,
+ 0x00000068,
+ 0xf0000000,
+ 0x00000068,
+ 0x00000000,
+ 0x00000069,
+ 0x10000000,
+ 0x00000069,
+ 0x20000000,
+ 0x00000069,
+ 0x30000000,
+ 0x00000069,
+ 0x40000000,
+ 0x00000041,
+ 0x40000000,
+ 0x00000041,
+ 0x40000000,
+ 0x00000041,
+ 0x40000000,
+ 0x00000041,
+ 0x40000000,
+ 0x00000041,
+ 0x40000000,
+ 0x00000041,
+ 0x40000000,
+ 0x00000041,
+ 0x40000000,
+ 0x00000041,
+ 0x40000000,
+ 0x00000041,
+ 0x50000000,
+ 0x00000041,
+ 0x60000000,
+ 0x00000041,
+ 0x70000000,
+ 0x00000041,
+ 0x80000000,
+ 0x00000041,
+ 0x70000000,
+ 0x00000049,
+ 0x80000000,
+ 0x00000049,
+ 0x90000000,
+ 0x00000049,
+ 0xa0000000,
+ 0x00000049,
+ 0x70000000,
+ 0x00000059,
+ 0x80000000,
+ 0x00000059,
+ 0x90000000,
+ 0x00000059,
+ 0xb0000000,
+ 0x00000059,
+ 0xc0000000,
+ 0x00000059,
+ 0xd0000000,
+ 0x00000059,
+ 0xe0000000,
+ 0x00000059,
+ 0xb0000000,
+ 0x00000069,
+ 0xc0000000,
+ 0x00000069,
+ 0xd0000000,
+ 0x00000069,
+ 0xe0000000,
+ 0x00000069,
+ 0xf0000000,
+ 0x00000069,
+ 0x00000000,
+ 0x0000006a,
+ 0x10000000,
+ 0x0000006a,
+ 0x20000000,
+ 0x0000006a,
+ 0x30000000,
+ 0x0000006a,
+ 0x40000000,
+ 0x0000006a,
+ 0x50000000,
+ 0x0000006a,
+ 0x60000000,
+ 0x0000006a,
+ 0x70000000,
+ 0x0000006a,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000
+};
+
+static const u32 dot11lcn_aux_gain_idx_tbl_5G[] = {
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0001,
+ 0x0002,
+ 0x0003,
+ 0x0004,
+ 0x0083,
+ 0x0084,
+ 0x0085,
+ 0x0086,
+ 0x0087,
+ 0x0186,
+ 0x0187,
+ 0x0188,
+ 0x0189,
+ 0x018a,
+ 0x018b,
+ 0x018c,
+ 0x018d,
+ 0x018e,
+ 0x018f,
+ 0x0190,
+ 0x0191,
+ 0x0192,
+ 0x0193,
+ 0x0194,
+ 0x0195,
+ 0x0196,
+ 0x0197,
+ 0x0198,
+ 0x0199,
+ 0x019a,
+ 0x019b,
+ 0x019c,
+ 0x019d,
+ 0x0000
+};
+
+static const u32 dot11lcn_gain_val_tbl_5G[] = {
+ 0xf7,
+ 0xfd,
+ 0x00,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0xf7,
+ 0xfd,
+ 0x00,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0xf6,
+ 0x00,
+ 0x0c,
+ 0x03,
+ 0xeb,
+ 0xfe,
+ 0x06,
+ 0x0a,
+ 0x10,
+ 0x00,
+ 0x03,
+ 0x06,
+ 0x09,
+ 0x0c,
+ 0x0f,
+ 0x12,
+ 0x15,
+ 0x18,
+ 0x1b,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x03,
+ 0x06,
+ 0x09,
+ 0x0c,
+ 0x0f,
+ 0x12,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x03,
+ 0x06,
+ 0x09,
+ 0x0c,
+ 0x0f,
+ 0x12,
+ 0x15,
+ 0x18,
+ 0x1b,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+};
+
+static const u32 dot11lcn_gain_idx_tbl_5G[] = {
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x10000000,
+ 0x00000000,
+ 0x20000000,
+ 0x00000000,
+ 0x30000000,
+ 0x00000000,
+ 0x40000000,
+ 0x00000000,
+ 0x30000000,
+ 0x00000008,
+ 0x40000000,
+ 0x00000008,
+ 0x50000000,
+ 0x00000008,
+ 0x60000000,
+ 0x00000008,
+ 0x70000000,
+ 0x00000008,
+ 0x60000000,
+ 0x00000018,
+ 0x70000000,
+ 0x00000018,
+ 0x80000000,
+ 0x00000018,
+ 0x90000000,
+ 0x00000018,
+ 0xa0000000,
+ 0x00000018,
+ 0xb0000000,
+ 0x00000018,
+ 0xc0000000,
+ 0x00000018,
+ 0xd0000000,
+ 0x00000018,
+ 0xe0000000,
+ 0x00000018,
+ 0xf0000000,
+ 0x00000018,
+ 0x00000000,
+ 0x00000019,
+ 0x10000000,
+ 0x00000019,
+ 0x20000000,
+ 0x00000019,
+ 0x30000000,
+ 0x00000019,
+ 0x40000000,
+ 0x00000019,
+ 0x50000000,
+ 0x00000019,
+ 0x60000000,
+ 0x00000019,
+ 0x70000000,
+ 0x00000019,
+ 0x80000000,
+ 0x00000019,
+ 0x90000000,
+ 0x00000019,
+ 0xa0000000,
+ 0x00000019,
+ 0xb0000000,
+ 0x00000019,
+ 0xc0000000,
+ 0x00000019,
+ 0xd0000000,
+ 0x00000019,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000
+};
+
+static const u32 dot11lcn_gain_tbl_5G[] = {
+ 0x00000000,
+ 0x00000040,
+ 0x00000080,
+ 0x00000001,
+ 0x00000005,
+ 0x00000009,
+ 0x0000000d,
+ 0x00000011,
+ 0x00000015,
+ 0x00000055,
+ 0x00000095,
+ 0x00000017,
+ 0x0000001b,
+ 0x0000005b,
+ 0x0000009b,
+ 0x000000db,
+ 0x0000011b,
+ 0x0000015b,
+ 0x0000019b,
+ 0x0000059b,
+ 0x0000099b,
+ 0x00000d9b,
+ 0x0000119b,
+ 0x0000519b,
+ 0x0000919b,
+ 0x0000d19b,
+ 0x0001119b,
+ 0x0001519b,
+ 0x0001919b,
+ 0x0001d19b,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000
+};
+
+const struct phytbl_info dot11lcnphytbl_rx_gain_info_rev0[] = {
+ {&dot11lcn_gain_tbl_rev0,
+ sizeof(dot11lcn_gain_tbl_rev0) / sizeof(dot11lcn_gain_tbl_rev0[0]), 18,
+ 0, 32}
+ ,
+ {&dot11lcn_aux_gain_idx_tbl_rev0,
+ sizeof(dot11lcn_aux_gain_idx_tbl_rev0) /
+ sizeof(dot11lcn_aux_gain_idx_tbl_rev0[0]), 14, 0, 16}
+ ,
+ {&dot11lcn_gain_idx_tbl_rev0,
+ sizeof(dot11lcn_gain_idx_tbl_rev0) /
+ sizeof(dot11lcn_gain_idx_tbl_rev0[0]), 13, 0, 32}
+ ,
+};
+
+static const struct phytbl_info dot11lcnphytbl_rx_gain_info_rev1[] = {
+ {&dot11lcn_gain_tbl_rev1,
+ sizeof(dot11lcn_gain_tbl_rev1) / sizeof(dot11lcn_gain_tbl_rev1[0]), 18,
+ 0, 32}
+ ,
+ {&dot11lcn_aux_gain_idx_tbl_rev0,
+ sizeof(dot11lcn_aux_gain_idx_tbl_rev0) /
+ sizeof(dot11lcn_aux_gain_idx_tbl_rev0[0]), 14, 0, 16}
+ ,
+ {&dot11lcn_gain_idx_tbl_rev0,
+ sizeof(dot11lcn_gain_idx_tbl_rev0) /
+ sizeof(dot11lcn_gain_idx_tbl_rev0[0]), 13, 0, 32}
+ ,
+};
+
+const struct phytbl_info dot11lcnphytbl_rx_gain_info_2G_rev2[] = {
+ {&dot11lcn_gain_tbl_2G,
+ sizeof(dot11lcn_gain_tbl_2G) / sizeof(dot11lcn_gain_tbl_2G[0]), 18, 0,
+ 32}
+ ,
+ {&dot11lcn_aux_gain_idx_tbl_2G,
+ sizeof(dot11lcn_aux_gain_idx_tbl_2G) /
+ sizeof(dot11lcn_aux_gain_idx_tbl_2G[0]), 14, 0, 16}
+ ,
+ {&dot11lcn_gain_idx_tbl_2G,
+ sizeof(dot11lcn_gain_idx_tbl_2G) / sizeof(dot11lcn_gain_idx_tbl_2G[0]),
+ 13, 0, 32}
+ ,
+ {&dot11lcn_gain_val_tbl_2G,
+ sizeof(dot11lcn_gain_val_tbl_2G) / sizeof(dot11lcn_gain_val_tbl_2G[0]),
+ 17, 0, 8}
+};
+
+const struct phytbl_info dot11lcnphytbl_rx_gain_info_5G_rev2[] = {
+ {&dot11lcn_gain_tbl_5G,
+ sizeof(dot11lcn_gain_tbl_5G) / sizeof(dot11lcn_gain_tbl_5G[0]), 18, 0,
+ 32}
+ ,
+ {&dot11lcn_aux_gain_idx_tbl_5G,
+ sizeof(dot11lcn_aux_gain_idx_tbl_5G) /
+ sizeof(dot11lcn_aux_gain_idx_tbl_5G[0]), 14, 0, 16}
+ ,
+ {&dot11lcn_gain_idx_tbl_5G,
+ sizeof(dot11lcn_gain_idx_tbl_5G) / sizeof(dot11lcn_gain_idx_tbl_5G[0]),
+ 13, 0, 32}
+ ,
+ {&dot11lcn_gain_val_tbl_5G,
+ sizeof(dot11lcn_gain_val_tbl_5G) / sizeof(dot11lcn_gain_val_tbl_5G[0]),
+ 17, 0, 8}
+};
+
+const struct phytbl_info dot11lcnphytbl_rx_gain_info_extlna_2G_rev2[] = {
+ {&dot11lcn_gain_tbl_extlna_2G,
+ sizeof(dot11lcn_gain_tbl_extlna_2G) /
+ sizeof(dot11lcn_gain_tbl_extlna_2G[0]), 18, 0, 32}
+ ,
+ {&dot11lcn_aux_gain_idx_tbl_extlna_2G,
+ sizeof(dot11lcn_aux_gain_idx_tbl_extlna_2G) /
+ sizeof(dot11lcn_aux_gain_idx_tbl_extlna_2G[0]), 14, 0, 16}
+ ,
+ {&dot11lcn_gain_idx_tbl_extlna_2G,
+ sizeof(dot11lcn_gain_idx_tbl_extlna_2G) /
+ sizeof(dot11lcn_gain_idx_tbl_extlna_2G[0]), 13, 0, 32}
+ ,
+ {&dot11lcn_gain_val_tbl_extlna_2G,
+ sizeof(dot11lcn_gain_val_tbl_extlna_2G) /
+ sizeof(dot11lcn_gain_val_tbl_extlna_2G[0]), 17, 0, 8}
+};
+
+const struct phytbl_info dot11lcnphytbl_rx_gain_info_extlna_5G_rev2[] = {
+ {&dot11lcn_gain_tbl_5G,
+ sizeof(dot11lcn_gain_tbl_5G) / sizeof(dot11lcn_gain_tbl_5G[0]), 18, 0,
+ 32}
+ ,
+ {&dot11lcn_aux_gain_idx_tbl_5G,
+ sizeof(dot11lcn_aux_gain_idx_tbl_5G) /
+ sizeof(dot11lcn_aux_gain_idx_tbl_5G[0]), 14, 0, 16}
+ ,
+ {&dot11lcn_gain_idx_tbl_5G,
+ sizeof(dot11lcn_gain_idx_tbl_5G) / sizeof(dot11lcn_gain_idx_tbl_5G[0]),
+ 13, 0, 32}
+ ,
+ {&dot11lcn_gain_val_tbl_5G,
+ sizeof(dot11lcn_gain_val_tbl_5G) / sizeof(dot11lcn_gain_val_tbl_5G[0]),
+ 17, 0, 8}
+};
+
+const u32 dot11lcnphytbl_rx_gain_info_sz_rev0 =
+ sizeof(dot11lcnphytbl_rx_gain_info_rev0) /
+ sizeof(dot11lcnphytbl_rx_gain_info_rev0[0]);
+
+const u32 dot11lcnphytbl_rx_gain_info_2G_rev2_sz =
+ sizeof(dot11lcnphytbl_rx_gain_info_2G_rev2) /
+ sizeof(dot11lcnphytbl_rx_gain_info_2G_rev2[0]);
+
+const u32 dot11lcnphytbl_rx_gain_info_5G_rev2_sz =
+ sizeof(dot11lcnphytbl_rx_gain_info_5G_rev2) /
+ sizeof(dot11lcnphytbl_rx_gain_info_5G_rev2[0]);
+
+static const u16 dot11lcn_min_sig_sq_tbl_rev0[] = {
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+ 0x014d,
+};
+
+static const u16 dot11lcn_noise_scale_tbl_rev0[] = {
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+};
+
+static const u32 dot11lcn_fltr_ctrl_tbl_rev0[] = {
+ 0x000141f8,
+ 0x000021f8,
+ 0x000021fb,
+ 0x000041fb,
+ 0x0001fe4b,
+ 0x0000217b,
+ 0x00002133,
+ 0x000040eb,
+ 0x0001fea3,
+ 0x0000024b,
+};
+
+static const u32 dot11lcn_ps_ctrl_tbl_rev0[] = {
+ 0x00100001,
+ 0x00200010,
+ 0x00300001,
+ 0x00400010,
+ 0x00500022,
+ 0x00600122,
+ 0x00700222,
+ 0x00800322,
+ 0x00900422,
+ 0x00a00522,
+ 0x00b00622,
+ 0x00c00722,
+ 0x00d00822,
+ 0x00f00922,
+ 0x00100a22,
+ 0x00200b22,
+ 0x00300c22,
+ 0x00400d22,
+ 0x00500e22,
+ 0x00600f22,
+};
+
+static const u16 dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo[] = {
+ 0x0007,
+ 0x0005,
+ 0x0006,
+ 0x0004,
+ 0x0007,
+ 0x0005,
+ 0x0006,
+ 0x0004,
+ 0x0007,
+ 0x0005,
+ 0x0006,
+ 0x0004,
+ 0x0007,
+ 0x0005,
+ 0x0006,
+ 0x0004,
+ 0x000b,
+ 0x000b,
+ 0x000a,
+ 0x000a,
+ 0x000b,
+ 0x000b,
+ 0x000a,
+ 0x000a,
+ 0x000b,
+ 0x000b,
+ 0x000a,
+ 0x000a,
+ 0x000b,
+ 0x000b,
+ 0x000a,
+ 0x000a,
+ 0x0007,
+ 0x0005,
+ 0x0006,
+ 0x0004,
+ 0x0007,
+ 0x0005,
+ 0x0006,
+ 0x0004,
+ 0x0007,
+ 0x0005,
+ 0x0006,
+ 0x0004,
+ 0x0007,
+ 0x0005,
+ 0x0006,
+ 0x0004,
+ 0x000b,
+ 0x000b,
+ 0x000a,
+ 0x000a,
+ 0x000b,
+ 0x000b,
+ 0x000a,
+ 0x000a,
+ 0x000b,
+ 0x000b,
+ 0x000a,
+ 0x000a,
+ 0x000b,
+ 0x000b,
+ 0x000a,
+ 0x000a,
+
+};
+
+static const u16 dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0[] = {
+ 0x0007,
+ 0x0005,
+ 0x0002,
+ 0x0000,
+ 0x0007,
+ 0x0005,
+ 0x0002,
+ 0x0000,
+ 0x0007,
+ 0x0005,
+ 0x0002,
+ 0x0000,
+ 0x0007,
+ 0x0005,
+ 0x0002,
+ 0x0000,
+ 0x0007,
+ 0x0007,
+ 0x0002,
+ 0x0002,
+ 0x0007,
+ 0x0007,
+ 0x0002,
+ 0x0002,
+ 0x0007,
+ 0x0007,
+ 0x0002,
+ 0x0002,
+ 0x0007,
+ 0x0007,
+ 0x0002,
+ 0x0002,
+ 0x0007,
+ 0x0005,
+ 0x0002,
+ 0x0000,
+ 0x0007,
+ 0x0005,
+ 0x0002,
+ 0x0000,
+ 0x0007,
+ 0x0005,
+ 0x0002,
+ 0x0000,
+ 0x0007,
+ 0x0005,
+ 0x0002,
+ 0x0000,
+ 0x0007,
+ 0x0007,
+ 0x0002,
+ 0x0002,
+ 0x0007,
+ 0x0007,
+ 0x0002,
+ 0x0002,
+ 0x0007,
+ 0x0007,
+ 0x0002,
+ 0x0002,
+ 0x0007,
+ 0x0007,
+ 0x0002,
+ 0x0002,
+};
+
+static const u16 dot11lcn_sw_ctrl_tbl_4313_epa_rev0[] = {
+ 0x0002,
+ 0x0008,
+ 0x0004,
+ 0x0001,
+ 0x0002,
+ 0x0008,
+ 0x0004,
+ 0x0001,
+ 0x0002,
+ 0x0008,
+ 0x0004,
+ 0x0001,
+ 0x0002,
+ 0x0008,
+ 0x0004,
+ 0x0001,
+ 0x0002,
+ 0x0008,
+ 0x0004,
+ 0x0001,
+ 0x0002,
+ 0x0008,
+ 0x0004,
+ 0x0001,
+ 0x0002,
+ 0x0008,
+ 0x0004,
+ 0x0001,
+ 0x0002,
+ 0x0008,
+ 0x0004,
+ 0x0001,
+ 0x0002,
+ 0x0008,
+ 0x0004,
+ 0x0001,
+ 0x0002,
+ 0x0008,
+ 0x0004,
+ 0x0001,
+ 0x0002,
+ 0x0008,
+ 0x0004,
+ 0x0001,
+ 0x0002,
+ 0x0008,
+ 0x0004,
+ 0x0001,
+ 0x0002,
+ 0x0008,
+ 0x0004,
+ 0x0001,
+ 0x0002,
+ 0x0008,
+ 0x0004,
+ 0x0001,
+ 0x0002,
+ 0x0008,
+ 0x0004,
+ 0x0001,
+ 0x0002,
+ 0x0008,
+ 0x0004,
+ 0x0001,
+};
+
+static const u16 dot11lcn_sw_ctrl_tbl_4313_rev0[] = {
+ 0x000a,
+ 0x0009,
+ 0x0006,
+ 0x0005,
+ 0x000a,
+ 0x0009,
+ 0x0006,
+ 0x0005,
+ 0x000a,
+ 0x0009,
+ 0x0006,
+ 0x0005,
+ 0x000a,
+ 0x0009,
+ 0x0006,
+ 0x0005,
+ 0x000a,
+ 0x0009,
+ 0x0006,
+ 0x0005,
+ 0x000a,
+ 0x0009,
+ 0x0006,
+ 0x0005,
+ 0x000a,
+ 0x0009,
+ 0x0006,
+ 0x0005,
+ 0x000a,
+ 0x0009,
+ 0x0006,
+ 0x0005,
+ 0x000a,
+ 0x0009,
+ 0x0006,
+ 0x0005,
+ 0x000a,
+ 0x0009,
+ 0x0006,
+ 0x0005,
+ 0x000a,
+ 0x0009,
+ 0x0006,
+ 0x0005,
+ 0x000a,
+ 0x0009,
+ 0x0006,
+ 0x0005,
+ 0x000a,
+ 0x0009,
+ 0x0006,
+ 0x0005,
+ 0x000a,
+ 0x0009,
+ 0x0006,
+ 0x0005,
+ 0x000a,
+ 0x0009,
+ 0x0006,
+ 0x0005,
+ 0x000a,
+ 0x0009,
+ 0x0006,
+ 0x0005,
+};
+
+static const u16 dot11lcn_sw_ctrl_tbl_rev0[] = {
+ 0x0004,
+ 0x0004,
+ 0x0002,
+ 0x0002,
+ 0x0004,
+ 0x0004,
+ 0x0002,
+ 0x0002,
+ 0x0004,
+ 0x0004,
+ 0x0002,
+ 0x0002,
+ 0x0004,
+ 0x0004,
+ 0x0002,
+ 0x0002,
+ 0x0004,
+ 0x0004,
+ 0x0002,
+ 0x0002,
+ 0x0004,
+ 0x0004,
+ 0x0002,
+ 0x0002,
+ 0x0004,
+ 0x0004,
+ 0x0002,
+ 0x0002,
+ 0x0004,
+ 0x0004,
+ 0x0002,
+ 0x0002,
+ 0x0004,
+ 0x0004,
+ 0x0002,
+ 0x0002,
+ 0x0004,
+ 0x0004,
+ 0x0002,
+ 0x0002,
+ 0x0004,
+ 0x0004,
+ 0x0002,
+ 0x0002,
+ 0x0004,
+ 0x0004,
+ 0x0002,
+ 0x0002,
+ 0x0004,
+ 0x0004,
+ 0x0002,
+ 0x0002,
+ 0x0004,
+ 0x0004,
+ 0x0002,
+ 0x0002,
+ 0x0004,
+ 0x0004,
+ 0x0002,
+ 0x0002,
+ 0x0004,
+ 0x0004,
+ 0x0002,
+ 0x0002,
+};
+
+static const u8 dot11lcn_nf_table_rev0[] = {
+ 0x5f,
+ 0x36,
+ 0x29,
+ 0x1f,
+ 0x5f,
+ 0x36,
+ 0x29,
+ 0x1f,
+ 0x5f,
+ 0x36,
+ 0x29,
+ 0x1f,
+ 0x5f,
+ 0x36,
+ 0x29,
+ 0x1f,
+};
+
+static const u8 dot11lcn_gain_val_tbl_rev0[] = {
+ 0x09,
+ 0x0f,
+ 0x14,
+ 0x18,
+ 0xfe,
+ 0x07,
+ 0x0b,
+ 0x0f,
+ 0xfb,
+ 0xfe,
+ 0x01,
+ 0x05,
+ 0x08,
+ 0x0b,
+ 0x0e,
+ 0x11,
+ 0x14,
+ 0x17,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x03,
+ 0x06,
+ 0x09,
+ 0x0c,
+ 0x0f,
+ 0x12,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x03,
+ 0x06,
+ 0x09,
+ 0x0c,
+ 0x0f,
+ 0x12,
+ 0x15,
+ 0x18,
+ 0x1b,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x03,
+ 0xeb,
+ 0x00,
+ 0x00,
+};
+
+static const u8 dot11lcn_spur_tbl_rev0[] = {
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x02,
+ 0x03,
+ 0x01,
+ 0x03,
+ 0x02,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x02,
+ 0x03,
+ 0x01,
+ 0x03,
+ 0x02,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+};
+
+static const u16 dot11lcn_unsup_mcs_tbl_rev0[] = {
+ 0x001a,
+ 0x0034,
+ 0x004e,
+ 0x0068,
+ 0x009c,
+ 0x00d0,
+ 0x00ea,
+ 0x0104,
+ 0x0034,
+ 0x0068,
+ 0x009c,
+ 0x00d0,
+ 0x0138,
+ 0x01a0,
+ 0x01d4,
+ 0x0208,
+ 0x004e,
+ 0x009c,
+ 0x00ea,
+ 0x0138,
+ 0x01d4,
+ 0x0270,
+ 0x02be,
+ 0x030c,
+ 0x0068,
+ 0x00d0,
+ 0x0138,
+ 0x01a0,
+ 0x0270,
+ 0x0340,
+ 0x03a8,
+ 0x0410,
+ 0x0018,
+ 0x009c,
+ 0x00d0,
+ 0x0104,
+ 0x00ea,
+ 0x0138,
+ 0x0186,
+ 0x00d0,
+ 0x0104,
+ 0x0104,
+ 0x0138,
+ 0x016c,
+ 0x016c,
+ 0x01a0,
+ 0x0138,
+ 0x0186,
+ 0x0186,
+ 0x01d4,
+ 0x0222,
+ 0x0222,
+ 0x0270,
+ 0x0104,
+ 0x0138,
+ 0x016c,
+ 0x0138,
+ 0x016c,
+ 0x01a0,
+ 0x01d4,
+ 0x01a0,
+ 0x01d4,
+ 0x0208,
+ 0x0208,
+ 0x023c,
+ 0x0186,
+ 0x01d4,
+ 0x0222,
+ 0x01d4,
+ 0x0222,
+ 0x0270,
+ 0x02be,
+ 0x0270,
+ 0x02be,
+ 0x030c,
+ 0x030c,
+ 0x035a,
+ 0x0036,
+ 0x006c,
+ 0x00a2,
+ 0x00d8,
+ 0x0144,
+ 0x01b0,
+ 0x01e6,
+ 0x021c,
+ 0x006c,
+ 0x00d8,
+ 0x0144,
+ 0x01b0,
+ 0x0288,
+ 0x0360,
+ 0x03cc,
+ 0x0438,
+ 0x00a2,
+ 0x0144,
+ 0x01e6,
+ 0x0288,
+ 0x03cc,
+ 0x0510,
+ 0x05b2,
+ 0x0654,
+ 0x00d8,
+ 0x01b0,
+ 0x0288,
+ 0x0360,
+ 0x0510,
+ 0x06c0,
+ 0x0798,
+ 0x0870,
+ 0x0018,
+ 0x0144,
+ 0x01b0,
+ 0x021c,
+ 0x01e6,
+ 0x0288,
+ 0x032a,
+ 0x01b0,
+ 0x021c,
+ 0x021c,
+ 0x0288,
+ 0x02f4,
+ 0x02f4,
+ 0x0360,
+ 0x0288,
+ 0x032a,
+ 0x032a,
+ 0x03cc,
+ 0x046e,
+ 0x046e,
+ 0x0510,
+ 0x021c,
+ 0x0288,
+ 0x02f4,
+ 0x0288,
+ 0x02f4,
+ 0x0360,
+ 0x03cc,
+ 0x0360,
+ 0x03cc,
+ 0x0438,
+ 0x0438,
+ 0x04a4,
+ 0x032a,
+ 0x03cc,
+ 0x046e,
+ 0x03cc,
+ 0x046e,
+ 0x0510,
+ 0x05b2,
+ 0x0510,
+ 0x05b2,
+ 0x0654,
+ 0x0654,
+ 0x06f6,
+};
+
+static const u16 dot11lcn_iq_local_tbl_rev0[] = {
+ 0x0200,
+ 0x0300,
+ 0x0400,
+ 0x0600,
+ 0x0800,
+ 0x0b00,
+ 0x1000,
+ 0x1001,
+ 0x1002,
+ 0x1003,
+ 0x1004,
+ 0x1005,
+ 0x1006,
+ 0x1007,
+ 0x1707,
+ 0x2007,
+ 0x2d07,
+ 0x4007,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0200,
+ 0x0300,
+ 0x0400,
+ 0x0600,
+ 0x0800,
+ 0x0b00,
+ 0x1000,
+ 0x1001,
+ 0x1002,
+ 0x1003,
+ 0x1004,
+ 0x1005,
+ 0x1006,
+ 0x1007,
+ 0x1707,
+ 0x2007,
+ 0x2d07,
+ 0x4007,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x4000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+};
+
+static const u32 dot11lcn_papd_compdelta_tbl_rev0[] = {
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+ 0x00080000,
+};
+
+const struct phytbl_info dot11lcnphytbl_info_rev0[] = {
+ {&dot11lcn_min_sig_sq_tbl_rev0,
+ sizeof(dot11lcn_min_sig_sq_tbl_rev0) /
+ sizeof(dot11lcn_min_sig_sq_tbl_rev0[0]), 2, 0, 16}
+ ,
+ {&dot11lcn_noise_scale_tbl_rev0,
+ sizeof(dot11lcn_noise_scale_tbl_rev0) /
+ sizeof(dot11lcn_noise_scale_tbl_rev0[0]), 1, 0, 16}
+ ,
+ {&dot11lcn_fltr_ctrl_tbl_rev0,
+ sizeof(dot11lcn_fltr_ctrl_tbl_rev0) /
+ sizeof(dot11lcn_fltr_ctrl_tbl_rev0[0]), 11, 0, 32}
+ ,
+ {&dot11lcn_ps_ctrl_tbl_rev0,
+ sizeof(dot11lcn_ps_ctrl_tbl_rev0) /
+ sizeof(dot11lcn_ps_ctrl_tbl_rev0[0]), 12, 0, 32}
+ ,
+ {&dot11lcn_gain_idx_tbl_rev0,
+ sizeof(dot11lcn_gain_idx_tbl_rev0) /
+ sizeof(dot11lcn_gain_idx_tbl_rev0[0]), 13, 0, 32}
+ ,
+ {&dot11lcn_aux_gain_idx_tbl_rev0,
+ sizeof(dot11lcn_aux_gain_idx_tbl_rev0) /
+ sizeof(dot11lcn_aux_gain_idx_tbl_rev0[0]), 14, 0, 16}
+ ,
+ {&dot11lcn_sw_ctrl_tbl_rev0,
+ sizeof(dot11lcn_sw_ctrl_tbl_rev0) /
+ sizeof(dot11lcn_sw_ctrl_tbl_rev0[0]), 15, 0, 16}
+ ,
+ {&dot11lcn_nf_table_rev0,
+ sizeof(dot11lcn_nf_table_rev0) / sizeof(dot11lcn_nf_table_rev0[0]), 16,
+ 0, 8}
+ ,
+ {&dot11lcn_gain_val_tbl_rev0,
+ sizeof(dot11lcn_gain_val_tbl_rev0) /
+ sizeof(dot11lcn_gain_val_tbl_rev0[0]), 17, 0, 8}
+ ,
+ {&dot11lcn_gain_tbl_rev0,
+ sizeof(dot11lcn_gain_tbl_rev0) / sizeof(dot11lcn_gain_tbl_rev0[0]), 18,
+ 0, 32}
+ ,
+ {&dot11lcn_spur_tbl_rev0,
+ sizeof(dot11lcn_spur_tbl_rev0) / sizeof(dot11lcn_spur_tbl_rev0[0]), 20,
+ 0, 8}
+ ,
+ {&dot11lcn_unsup_mcs_tbl_rev0,
+ sizeof(dot11lcn_unsup_mcs_tbl_rev0) /
+ sizeof(dot11lcn_unsup_mcs_tbl_rev0[0]), 23, 0, 16}
+ ,
+ {&dot11lcn_iq_local_tbl_rev0,
+ sizeof(dot11lcn_iq_local_tbl_rev0) /
+ sizeof(dot11lcn_iq_local_tbl_rev0[0]), 0, 0, 16}
+ ,
+ {&dot11lcn_papd_compdelta_tbl_rev0,
+ sizeof(dot11lcn_papd_compdelta_tbl_rev0) /
+ sizeof(dot11lcn_papd_compdelta_tbl_rev0[0]), 24, 0, 32}
+ ,
+};
+
+const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313 = {
+ &dot11lcn_sw_ctrl_tbl_4313_rev0,
+ sizeof(dot11lcn_sw_ctrl_tbl_4313_rev0) /
+ sizeof(dot11lcn_sw_ctrl_tbl_4313_rev0[0]), 15, 0, 16
+};
+
+const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_epa = {
+ &dot11lcn_sw_ctrl_tbl_4313_epa_rev0,
+ sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0) /
+ sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0[0]), 15, 0, 16
+};
+
+const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_bt_epa = {
+ &dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo,
+ sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo) /
+ sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo[0]), 15, 0, 16
+};
+
+const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250 = {
+ &dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0,
+ sizeof(dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0) /
+ sizeof(dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0[0]), 15, 0, 16
+};
+
+const u32 dot11lcnphytbl_info_sz_rev0 =
+ sizeof(dot11lcnphytbl_info_rev0) / sizeof(dot11lcnphytbl_info_rev0[0]);
+
+const struct lcnphy_tx_gain_tbl_entry
+dot11lcnphy_2GHz_extPA_gaintable_rev0[128] = {
+ {3, 0, 31, 0, 72},
+ {3, 0, 31, 0, 70},
+ {3, 0, 31, 0, 68},
+ {3, 0, 30, 0, 67},
+ {3, 0, 29, 0, 68},
+ {3, 0, 28, 0, 68},
+ {3, 0, 27, 0, 69},
+ {3, 0, 26, 0, 70},
+ {3, 0, 25, 0, 70},
+ {3, 0, 24, 0, 71},
+ {3, 0, 23, 0, 72},
+ {3, 0, 23, 0, 70},
+ {3, 0, 22, 0, 71},
+ {3, 0, 21, 0, 72},
+ {3, 0, 21, 0, 70},
+ {3, 0, 21, 0, 68},
+ {3, 0, 21, 0, 66},
+ {3, 0, 21, 0, 64},
+ {3, 0, 21, 0, 63},
+ {3, 0, 20, 0, 64},
+ {3, 0, 19, 0, 65},
+ {3, 0, 19, 0, 64},
+ {3, 0, 18, 0, 65},
+ {3, 0, 18, 0, 64},
+ {3, 0, 17, 0, 65},
+ {3, 0, 17, 0, 64},
+ {3, 0, 16, 0, 65},
+ {3, 0, 16, 0, 64},
+ {3, 0, 16, 0, 62},
+ {3, 0, 16, 0, 60},
+ {3, 0, 16, 0, 58},
+ {3, 0, 15, 0, 61},
+ {3, 0, 15, 0, 59},
+ {3, 0, 14, 0, 61},
+ {3, 0, 14, 0, 60},
+ {3, 0, 14, 0, 58},
+ {3, 0, 13, 0, 60},
+ {3, 0, 13, 0, 59},
+ {3, 0, 12, 0, 62},
+ {3, 0, 12, 0, 60},
+ {3, 0, 12, 0, 58},
+ {3, 0, 11, 0, 62},
+ {3, 0, 11, 0, 60},
+ {3, 0, 11, 0, 59},
+ {3, 0, 11, 0, 57},
+ {3, 0, 10, 0, 61},
+ {3, 0, 10, 0, 59},
+ {3, 0, 10, 0, 57},
+ {3, 0, 9, 0, 62},
+ {3, 0, 9, 0, 60},
+ {3, 0, 9, 0, 58},
+ {3, 0, 9, 0, 57},
+ {3, 0, 8, 0, 62},
+ {3, 0, 8, 0, 60},
+ {3, 0, 8, 0, 58},
+ {3, 0, 8, 0, 57},
+ {3, 0, 8, 0, 55},
+ {3, 0, 7, 0, 61},
+ {3, 0, 7, 0, 60},
+ {3, 0, 7, 0, 58},
+ {3, 0, 7, 0, 56},
+ {3, 0, 7, 0, 55},
+ {3, 0, 6, 0, 62},
+ {3, 0, 6, 0, 60},
+ {3, 0, 6, 0, 58},
+ {3, 0, 6, 0, 57},
+ {3, 0, 6, 0, 55},
+ {3, 0, 6, 0, 54},
+ {3, 0, 6, 0, 52},
+ {3, 0, 5, 0, 61},
+ {3, 0, 5, 0, 59},
+ {3, 0, 5, 0, 57},
+ {3, 0, 5, 0, 56},
+ {3, 0, 5, 0, 54},
+ {3, 0, 5, 0, 53},
+ {3, 0, 5, 0, 51},
+ {3, 0, 4, 0, 62},
+ {3, 0, 4, 0, 60},
+ {3, 0, 4, 0, 58},
+ {3, 0, 4, 0, 57},
+ {3, 0, 4, 0, 55},
+ {3, 0, 4, 0, 54},
+ {3, 0, 4, 0, 52},
+ {3, 0, 4, 0, 51},
+ {3, 0, 4, 0, 49},
+ {3, 0, 4, 0, 48},
+ {3, 0, 4, 0, 46},
+ {3, 0, 3, 0, 60},
+ {3, 0, 3, 0, 58},
+ {3, 0, 3, 0, 57},
+ {3, 0, 3, 0, 55},
+ {3, 0, 3, 0, 54},
+ {3, 0, 3, 0, 52},
+ {3, 0, 3, 0, 51},
+ {3, 0, 3, 0, 49},
+ {3, 0, 3, 0, 48},
+ {3, 0, 3, 0, 46},
+ {3, 0, 3, 0, 45},
+ {3, 0, 3, 0, 44},
+ {3, 0, 3, 0, 43},
+ {3, 0, 3, 0, 41},
+ {3, 0, 2, 0, 61},
+ {3, 0, 2, 0, 59},
+ {3, 0, 2, 0, 57},
+ {3, 0, 2, 0, 56},
+ {3, 0, 2, 0, 54},
+ {3, 0, 2, 0, 53},
+ {3, 0, 2, 0, 51},
+ {3, 0, 2, 0, 50},
+ {3, 0, 2, 0, 48},
+ {3, 0, 2, 0, 47},
+ {3, 0, 2, 0, 46},
+ {3, 0, 2, 0, 44},
+ {3, 0, 2, 0, 43},
+ {3, 0, 2, 0, 42},
+ {3, 0, 2, 0, 41},
+ {3, 0, 2, 0, 39},
+ {3, 0, 2, 0, 38},
+ {3, 0, 2, 0, 37},
+ {3, 0, 2, 0, 36},
+ {3, 0, 2, 0, 35},
+ {3, 0, 2, 0, 34},
+ {3, 0, 2, 0, 33},
+ {3, 0, 2, 0, 32},
+ {3, 0, 1, 0, 63},
+ {3, 0, 1, 0, 61},
+ {3, 0, 1, 0, 59},
+ {3, 0, 1, 0, 57},
+};
+
+const struct lcnphy_tx_gain_tbl_entry dot11lcnphy_2GHz_gaintable_rev0[128] = {
+ {7, 0, 31, 0, 72},
+ {7, 0, 31, 0, 70},
+ {7, 0, 31, 0, 68},
+ {7, 0, 30, 0, 67},
+ {7, 0, 29, 0, 68},
+ {7, 0, 28, 0, 68},
+ {7, 0, 27, 0, 69},
+ {7, 0, 26, 0, 70},
+ {7, 0, 25, 0, 70},
+ {7, 0, 24, 0, 71},
+ {7, 0, 23, 0, 72},
+ {7, 0, 23, 0, 70},
+ {7, 0, 22, 0, 71},
+ {7, 0, 21, 0, 72},
+ {7, 0, 21, 0, 70},
+ {7, 0, 21, 0, 68},
+ {7, 0, 21, 0, 66},
+ {7, 0, 21, 0, 64},
+ {7, 0, 21, 0, 63},
+ {7, 0, 20, 0, 64},
+ {7, 0, 19, 0, 65},
+ {7, 0, 19, 0, 64},
+ {7, 0, 18, 0, 65},
+ {7, 0, 18, 0, 64},
+ {7, 0, 17, 0, 65},
+ {7, 0, 17, 0, 64},
+ {7, 0, 16, 0, 65},
+ {7, 0, 16, 0, 64},
+ {7, 0, 16, 0, 62},
+ {7, 0, 16, 0, 60},
+ {7, 0, 16, 0, 58},
+ {7, 0, 15, 0, 61},
+ {7, 0, 15, 0, 59},
+ {7, 0, 14, 0, 61},
+ {7, 0, 14, 0, 60},
+ {7, 0, 14, 0, 58},
+ {7, 0, 13, 0, 60},
+ {7, 0, 13, 0, 59},
+ {7, 0, 12, 0, 62},
+ {7, 0, 12, 0, 60},
+ {7, 0, 12, 0, 58},
+ {7, 0, 11, 0, 62},
+ {7, 0, 11, 0, 60},
+ {7, 0, 11, 0, 59},
+ {7, 0, 11, 0, 57},
+ {7, 0, 10, 0, 61},
+ {7, 0, 10, 0, 59},
+ {7, 0, 10, 0, 57},
+ {7, 0, 9, 0, 62},
+ {7, 0, 9, 0, 60},
+ {7, 0, 9, 0, 58},
+ {7, 0, 9, 0, 57},
+ {7, 0, 8, 0, 62},
+ {7, 0, 8, 0, 60},
+ {7, 0, 8, 0, 58},
+ {7, 0, 8, 0, 57},
+ {7, 0, 8, 0, 55},
+ {7, 0, 7, 0, 61},
+ {7, 0, 7, 0, 60},
+ {7, 0, 7, 0, 58},
+ {7, 0, 7, 0, 56},
+ {7, 0, 7, 0, 55},
+ {7, 0, 6, 0, 62},
+ {7, 0, 6, 0, 60},
+ {7, 0, 6, 0, 58},
+ {7, 0, 6, 0, 57},
+ {7, 0, 6, 0, 55},
+ {7, 0, 6, 0, 54},
+ {7, 0, 6, 0, 52},
+ {7, 0, 5, 0, 61},
+ {7, 0, 5, 0, 59},
+ {7, 0, 5, 0, 57},
+ {7, 0, 5, 0, 56},
+ {7, 0, 5, 0, 54},
+ {7, 0, 5, 0, 53},
+ {7, 0, 5, 0, 51},
+ {7, 0, 4, 0, 62},
+ {7, 0, 4, 0, 60},
+ {7, 0, 4, 0, 58},
+ {7, 0, 4, 0, 57},
+ {7, 0, 4, 0, 55},
+ {7, 0, 4, 0, 54},
+ {7, 0, 4, 0, 52},
+ {7, 0, 4, 0, 51},
+ {7, 0, 4, 0, 49},
+ {7, 0, 4, 0, 48},
+ {7, 0, 4, 0, 46},
+ {7, 0, 3, 0, 60},
+ {7, 0, 3, 0, 58},
+ {7, 0, 3, 0, 57},
+ {7, 0, 3, 0, 55},
+ {7, 0, 3, 0, 54},
+ {7, 0, 3, 0, 52},
+ {7, 0, 3, 0, 51},
+ {7, 0, 3, 0, 49},
+ {7, 0, 3, 0, 48},
+ {7, 0, 3, 0, 46},
+ {7, 0, 3, 0, 45},
+ {7, 0, 3, 0, 44},
+ {7, 0, 3, 0, 43},
+ {7, 0, 3, 0, 41},
+ {7, 0, 2, 0, 61},
+ {7, 0, 2, 0, 59},
+ {7, 0, 2, 0, 57},
+ {7, 0, 2, 0, 56},
+ {7, 0, 2, 0, 54},
+ {7, 0, 2, 0, 53},
+ {7, 0, 2, 0, 51},
+ {7, 0, 2, 0, 50},
+ {7, 0, 2, 0, 48},
+ {7, 0, 2, 0, 47},
+ {7, 0, 2, 0, 46},
+ {7, 0, 2, 0, 44},
+ {7, 0, 2, 0, 43},
+ {7, 0, 2, 0, 42},
+ {7, 0, 2, 0, 41},
+ {7, 0, 2, 0, 39},
+ {7, 0, 2, 0, 38},
+ {7, 0, 2, 0, 37},
+ {7, 0, 2, 0, 36},
+ {7, 0, 2, 0, 35},
+ {7, 0, 2, 0, 34},
+ {7, 0, 2, 0, 33},
+ {7, 0, 2, 0, 32},
+ {7, 0, 1, 0, 63},
+ {7, 0, 1, 0, 61},
+ {7, 0, 1, 0, 59},
+ {7, 0, 1, 0, 57},
+};
+
+const struct lcnphy_tx_gain_tbl_entry dot11lcnphy_5GHz_gaintable_rev0[128] = {
+ {255, 255, 0xf0, 0, 152},
+ {255, 255, 0xf0, 0, 147},
+ {255, 255, 0xf0, 0, 143},
+ {255, 255, 0xf0, 0, 139},
+ {255, 255, 0xf0, 0, 135},
+ {255, 255, 0xf0, 0, 131},
+ {255, 255, 0xf0, 0, 128},
+ {255, 255, 0xf0, 0, 124},
+ {255, 255, 0xf0, 0, 121},
+ {255, 255, 0xf0, 0, 117},
+ {255, 255, 0xf0, 0, 114},
+ {255, 255, 0xf0, 0, 111},
+ {255, 255, 0xf0, 0, 107},
+ {255, 255, 0xf0, 0, 104},
+ {255, 255, 0xf0, 0, 101},
+ {255, 255, 0xf0, 0, 99},
+ {255, 255, 0xf0, 0, 96},
+ {255, 255, 0xf0, 0, 93},
+ {255, 255, 0xf0, 0, 90},
+ {255, 255, 0xf0, 0, 88},
+ {255, 255, 0xf0, 0, 85},
+ {255, 255, 0xf0, 0, 83},
+ {255, 255, 0xf0, 0, 81},
+ {255, 255, 0xf0, 0, 78},
+ {255, 255, 0xf0, 0, 76},
+ {255, 255, 0xf0, 0, 74},
+ {255, 255, 0xf0, 0, 72},
+ {255, 255, 0xf0, 0, 70},
+ {255, 255, 0xf0, 0, 68},
+ {255, 255, 0xf0, 0, 66},
+ {255, 255, 0xf0, 0, 64},
+ {255, 248, 0xf0, 0, 64},
+ {255, 241, 0xf0, 0, 64},
+ {255, 251, 0xe0, 0, 64},
+ {255, 244, 0xe0, 0, 64},
+ {255, 254, 0xd0, 0, 64},
+ {255, 246, 0xd0, 0, 64},
+ {255, 239, 0xd0, 0, 64},
+ {255, 249, 0xc0, 0, 64},
+ {255, 242, 0xc0, 0, 64},
+ {255, 255, 0xb0, 0, 64},
+ {255, 248, 0xb0, 0, 64},
+ {255, 241, 0xb0, 0, 64},
+ {255, 254, 0xa0, 0, 64},
+ {255, 246, 0xa0, 0, 64},
+ {255, 239, 0xa0, 0, 64},
+ {255, 255, 0x90, 0, 64},
+ {255, 248, 0x90, 0, 64},
+ {255, 241, 0x90, 0, 64},
+ {255, 234, 0x90, 0, 64},
+ {255, 255, 0x80, 0, 64},
+ {255, 248, 0x80, 0, 64},
+ {255, 241, 0x80, 0, 64},
+ {255, 234, 0x80, 0, 64},
+ {255, 255, 0x70, 0, 64},
+ {255, 248, 0x70, 0, 64},
+ {255, 241, 0x70, 0, 64},
+ {255, 234, 0x70, 0, 64},
+ {255, 227, 0x70, 0, 64},
+ {255, 221, 0x70, 0, 64},
+ {255, 215, 0x70, 0, 64},
+ {255, 208, 0x70, 0, 64},
+ {255, 203, 0x70, 0, 64},
+ {255, 197, 0x70, 0, 64},
+ {255, 255, 0x60, 0, 64},
+ {255, 248, 0x60, 0, 64},
+ {255, 241, 0x60, 0, 64},
+ {255, 234, 0x60, 0, 64},
+ {255, 227, 0x60, 0, 64},
+ {255, 221, 0x60, 0, 64},
+ {255, 255, 0x50, 0, 64},
+ {255, 248, 0x50, 0, 64},
+ {255, 241, 0x50, 0, 64},
+ {255, 234, 0x50, 0, 64},
+ {255, 227, 0x50, 0, 64},
+ {255, 221, 0x50, 0, 64},
+ {255, 215, 0x50, 0, 64},
+ {255, 208, 0x50, 0, 64},
+ {255, 255, 0x40, 0, 64},
+ {255, 248, 0x40, 0, 64},
+ {255, 241, 0x40, 0, 64},
+ {255, 234, 0x40, 0, 64},
+ {255, 227, 0x40, 0, 64},
+ {255, 221, 0x40, 0, 64},
+ {255, 215, 0x40, 0, 64},
+ {255, 208, 0x40, 0, 64},
+ {255, 203, 0x40, 0, 64},
+ {255, 197, 0x40, 0, 64},
+ {255, 255, 0x30, 0, 64},
+ {255, 248, 0x30, 0, 64},
+ {255, 241, 0x30, 0, 64},
+ {255, 234, 0x30, 0, 64},
+ {255, 227, 0x30, 0, 64},
+ {255, 221, 0x30, 0, 64},
+ {255, 215, 0x30, 0, 64},
+ {255, 208, 0x30, 0, 64},
+ {255, 203, 0x30, 0, 64},
+ {255, 197, 0x30, 0, 64},
+ {255, 191, 0x30, 0, 64},
+ {255, 186, 0x30, 0, 64},
+ {255, 181, 0x30, 0, 64},
+ {255, 175, 0x30, 0, 64},
+ {255, 255, 0x20, 0, 64},
+ {255, 248, 0x20, 0, 64},
+ {255, 241, 0x20, 0, 64},
+ {255, 234, 0x20, 0, 64},
+ {255, 227, 0x20, 0, 64},
+ {255, 221, 0x20, 0, 64},
+ {255, 215, 0x20, 0, 64},
+ {255, 208, 0x20, 0, 64},
+ {255, 203, 0x20, 0, 64},
+ {255, 197, 0x20, 0, 64},
+ {255, 191, 0x20, 0, 64},
+ {255, 186, 0x20, 0, 64},
+ {255, 181, 0x20, 0, 64},
+ {255, 175, 0x20, 0, 64},
+ {255, 170, 0x20, 0, 64},
+ {255, 166, 0x20, 0, 64},
+ {255, 161, 0x20, 0, 64},
+ {255, 156, 0x20, 0, 64},
+ {255, 152, 0x20, 0, 64},
+ {255, 148, 0x20, 0, 64},
+ {255, 143, 0x20, 0, 64},
+ {255, 139, 0x20, 0, 64},
+ {255, 135, 0x20, 0, 64},
+ {255, 132, 0x20, 0, 64},
+ {255, 255, 0x10, 0, 64},
+ {255, 248, 0x10, 0, 64},
+};
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.h
new file mode 100644
index 000000000000..5f75e16bf5a7
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2010 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 <types.h>
+#include "phy_int.h"
+
+extern const struct phytbl_info dot11lcnphytbl_rx_gain_info_rev0[];
+extern const u32 dot11lcnphytbl_rx_gain_info_sz_rev0;
+extern const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313;
+extern const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_epa;
+extern const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_epa_combo;
+extern const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_bt_epa;
+extern const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250;
+
+extern const struct phytbl_info dot11lcnphytbl_info_rev0[];
+extern const u32 dot11lcnphytbl_info_sz_rev0;
+
+extern const struct phytbl_info dot11lcnphytbl_rx_gain_info_2G_rev2[];
+extern const u32 dot11lcnphytbl_rx_gain_info_2G_rev2_sz;
+
+extern const struct phytbl_info dot11lcnphytbl_rx_gain_info_5G_rev2[];
+extern const u32 dot11lcnphytbl_rx_gain_info_5G_rev2_sz;
+
+extern const struct phytbl_info dot11lcnphytbl_rx_gain_info_extlna_2G_rev2[];
+
+extern const struct phytbl_info dot11lcnphytbl_rx_gain_info_extlna_5G_rev2[];
+
+struct lcnphy_tx_gain_tbl_entry {
+ unsigned char gm;
+ unsigned char pga;
+ unsigned char pad;
+ unsigned char dac;
+ unsigned char bb_mult;
+};
+
+extern const struct lcnphy_tx_gain_tbl_entry dot11lcnphy_2GHz_gaintable_rev0[];
+
+extern const struct
+lcnphy_tx_gain_tbl_entry dot11lcnphy_2GHz_extPA_gaintable_rev0[];
+
+extern const struct lcnphy_tx_gain_tbl_entry dot11lcnphy_5GHz_gaintable_rev0[];
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.c
new file mode 100644
index 000000000000..dbf50ef6cd75
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.c
@@ -0,0 +1,10630 @@
+/*
+ * Copyright (c) 2010 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 <types.h>
+#include "phytbl_n.h"
+
+static const u32 frame_struct_rev0[] = {
+ 0x08004a04,
+ 0x00100000,
+ 0x01000a05,
+ 0x00100020,
+ 0x09804506,
+ 0x00100030,
+ 0x09804507,
+ 0x00100030,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x08004a0c,
+ 0x00100004,
+ 0x01000a0d,
+ 0x00100024,
+ 0x0980450e,
+ 0x00100034,
+ 0x0980450f,
+ 0x00100034,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000a04,
+ 0x00100000,
+ 0x11008a05,
+ 0x00100020,
+ 0x1980c506,
+ 0x00100030,
+ 0x21810506,
+ 0x00100030,
+ 0x21810506,
+ 0x00100030,
+ 0x01800504,
+ 0x00100030,
+ 0x11808505,
+ 0x00100030,
+ 0x29814507,
+ 0x01100030,
+ 0x00000a04,
+ 0x00100000,
+ 0x11008a05,
+ 0x00100020,
+ 0x21810506,
+ 0x00100030,
+ 0x21810506,
+ 0x00100030,
+ 0x29814507,
+ 0x01100030,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000a0c,
+ 0x00100008,
+ 0x11008a0d,
+ 0x00100028,
+ 0x1980c50e,
+ 0x00100038,
+ 0x2181050e,
+ 0x00100038,
+ 0x2181050e,
+ 0x00100038,
+ 0x0180050c,
+ 0x00100038,
+ 0x1180850d,
+ 0x00100038,
+ 0x2981450f,
+ 0x01100038,
+ 0x00000a0c,
+ 0x00100008,
+ 0x11008a0d,
+ 0x00100028,
+ 0x2181050e,
+ 0x00100038,
+ 0x2181050e,
+ 0x00100038,
+ 0x2981450f,
+ 0x01100038,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x08004a04,
+ 0x00100000,
+ 0x01000a05,
+ 0x00100020,
+ 0x1980c506,
+ 0x00100030,
+ 0x1980c506,
+ 0x00100030,
+ 0x11808504,
+ 0x00100030,
+ 0x3981ca05,
+ 0x00100030,
+ 0x29814507,
+ 0x01100030,
+ 0x00000000,
+ 0x00000000,
+ 0x10008a04,
+ 0x00100000,
+ 0x3981ca05,
+ 0x00100030,
+ 0x1980c506,
+ 0x00100030,
+ 0x29814507,
+ 0x01100030,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x08004a0c,
+ 0x00100008,
+ 0x01000a0d,
+ 0x00100028,
+ 0x1980c50e,
+ 0x00100038,
+ 0x1980c50e,
+ 0x00100038,
+ 0x1180850c,
+ 0x00100038,
+ 0x3981ca0d,
+ 0x00100038,
+ 0x2981450f,
+ 0x01100038,
+ 0x00000000,
+ 0x00000000,
+ 0x10008a0c,
+ 0x00100008,
+ 0x3981ca0d,
+ 0x00100038,
+ 0x1980c50e,
+ 0x00100038,
+ 0x2981450f,
+ 0x01100038,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x40021404,
+ 0x00100000,
+ 0x02001405,
+ 0x00100040,
+ 0x0b004a06,
+ 0x01900060,
+ 0x13008a06,
+ 0x01900060,
+ 0x13008a06,
+ 0x01900060,
+ 0x43020a04,
+ 0x00100060,
+ 0x1b00ca05,
+ 0x00100060,
+ 0x23010a07,
+ 0x01500060,
+ 0x40021404,
+ 0x00100000,
+ 0x1a00d405,
+ 0x00100040,
+ 0x13008a06,
+ 0x01900060,
+ 0x13008a06,
+ 0x01900060,
+ 0x23010a07,
+ 0x01500060,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x4002140c,
+ 0x00100010,
+ 0x0200140d,
+ 0x00100050,
+ 0x0b004a0e,
+ 0x01900070,
+ 0x13008a0e,
+ 0x01900070,
+ 0x13008a0e,
+ 0x01900070,
+ 0x43020a0c,
+ 0x00100070,
+ 0x1b00ca0d,
+ 0x00100070,
+ 0x23010a0f,
+ 0x01500070,
+ 0x4002140c,
+ 0x00100010,
+ 0x1a00d40d,
+ 0x00100050,
+ 0x13008a0e,
+ 0x01900070,
+ 0x13008a0e,
+ 0x01900070,
+ 0x23010a0f,
+ 0x01500070,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x50029404,
+ 0x00100000,
+ 0x32019405,
+ 0x00100040,
+ 0x0b004a06,
+ 0x01900060,
+ 0x0b004a06,
+ 0x01900060,
+ 0x5b02ca04,
+ 0x00100060,
+ 0x3b01d405,
+ 0x00100060,
+ 0x23010a07,
+ 0x01500060,
+ 0x00000000,
+ 0x00000000,
+ 0x5802d404,
+ 0x00100000,
+ 0x3b01d405,
+ 0x00100060,
+ 0x0b004a06,
+ 0x01900060,
+ 0x23010a07,
+ 0x01500060,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x5002940c,
+ 0x00100010,
+ 0x3201940d,
+ 0x00100050,
+ 0x0b004a0e,
+ 0x01900070,
+ 0x0b004a0e,
+ 0x01900070,
+ 0x5b02ca0c,
+ 0x00100070,
+ 0x3b01d40d,
+ 0x00100070,
+ 0x23010a0f,
+ 0x01500070,
+ 0x00000000,
+ 0x00000000,
+ 0x5802d40c,
+ 0x00100010,
+ 0x3b01d40d,
+ 0x00100070,
+ 0x0b004a0e,
+ 0x01900070,
+ 0x23010a0f,
+ 0x01500070,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x40021404,
+ 0x000f4800,
+ 0x62031405,
+ 0x00100040,
+ 0x53028a06,
+ 0x01900060,
+ 0x53028a07,
+ 0x01900060,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x4002140c,
+ 0x000f4808,
+ 0x6203140d,
+ 0x00100048,
+ 0x53028a0e,
+ 0x01900068,
+ 0x53028a0f,
+ 0x01900068,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000a0c,
+ 0x00100004,
+ 0x11008a0d,
+ 0x00100024,
+ 0x1980c50e,
+ 0x00100034,
+ 0x2181050e,
+ 0x00100034,
+ 0x2181050e,
+ 0x00100034,
+ 0x0180050c,
+ 0x00100038,
+ 0x1180850d,
+ 0x00100038,
+ 0x1181850d,
+ 0x00100038,
+ 0x2981450f,
+ 0x01100038,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000a0c,
+ 0x00100008,
+ 0x11008a0d,
+ 0x00100028,
+ 0x2181050e,
+ 0x00100038,
+ 0x2181050e,
+ 0x00100038,
+ 0x1181850d,
+ 0x00100038,
+ 0x2981450f,
+ 0x01100038,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x08004a04,
+ 0x00100000,
+ 0x01000a05,
+ 0x00100020,
+ 0x0180c506,
+ 0x00100030,
+ 0x0180c506,
+ 0x00100030,
+ 0x2180c50c,
+ 0x00100030,
+ 0x49820a0d,
+ 0x0016a130,
+ 0x41824a0d,
+ 0x0016a130,
+ 0x2981450f,
+ 0x01100030,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x2000ca0c,
+ 0x00100000,
+ 0x49820a0d,
+ 0x0016a130,
+ 0x1980c50e,
+ 0x00100030,
+ 0x41824a0d,
+ 0x0016a130,
+ 0x2981450f,
+ 0x01100030,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x4002140c,
+ 0x00100008,
+ 0x0200140d,
+ 0x00100048,
+ 0x0b004a0e,
+ 0x01900068,
+ 0x13008a0e,
+ 0x01900068,
+ 0x13008a0e,
+ 0x01900068,
+ 0x43020a0c,
+ 0x00100070,
+ 0x1b00ca0d,
+ 0x00100070,
+ 0x1b014a0d,
+ 0x00100070,
+ 0x23010a0f,
+ 0x01500070,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x4002140c,
+ 0x00100010,
+ 0x1a00d40d,
+ 0x00100050,
+ 0x13008a0e,
+ 0x01900070,
+ 0x13008a0e,
+ 0x01900070,
+ 0x1b014a0d,
+ 0x00100070,
+ 0x23010a0f,
+ 0x01500070,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x50029404,
+ 0x00100000,
+ 0x32019405,
+ 0x00100040,
+ 0x03004a06,
+ 0x01900060,
+ 0x03004a06,
+ 0x01900060,
+ 0x6b030a0c,
+ 0x00100060,
+ 0x4b02140d,
+ 0x0016a160,
+ 0x4302540d,
+ 0x0016a160,
+ 0x23010a0f,
+ 0x01500060,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x6b03140c,
+ 0x00100060,
+ 0x4b02140d,
+ 0x0016a160,
+ 0x0b004a0e,
+ 0x01900060,
+ 0x4302540d,
+ 0x0016a160,
+ 0x23010a0f,
+ 0x01500060,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x40021404,
+ 0x00100000,
+ 0x1a00d405,
+ 0x00100040,
+ 0x53028a06,
+ 0x01900060,
+ 0x5b02ca06,
+ 0x01900060,
+ 0x5b02ca06,
+ 0x01900060,
+ 0x43020a04,
+ 0x00100060,
+ 0x1b00ca05,
+ 0x00100060,
+ 0x53028a07,
+ 0x0190c060,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x4002140c,
+ 0x00100010,
+ 0x1a00d40d,
+ 0x00100050,
+ 0x53028a0e,
+ 0x01900070,
+ 0x5b02ca0e,
+ 0x01900070,
+ 0x5b02ca0e,
+ 0x01900070,
+ 0x43020a0c,
+ 0x00100070,
+ 0x1b00ca0d,
+ 0x00100070,
+ 0x53028a0f,
+ 0x0190c070,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x40021404,
+ 0x00100000,
+ 0x1a00d405,
+ 0x00100040,
+ 0x5b02ca06,
+ 0x01900060,
+ 0x5b02ca06,
+ 0x01900060,
+ 0x53028a07,
+ 0x0190c060,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x4002140c,
+ 0x00100010,
+ 0x1a00d40d,
+ 0x00100050,
+ 0x5b02ca0e,
+ 0x01900070,
+ 0x5b02ca0e,
+ 0x01900070,
+ 0x53028a0f,
+ 0x0190c070,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+static const u8 frame_lut_rev0[] = {
+ 0x02,
+ 0x04,
+ 0x14,
+ 0x14,
+ 0x03,
+ 0x05,
+ 0x16,
+ 0x16,
+ 0x0a,
+ 0x0c,
+ 0x1c,
+ 0x1c,
+ 0x0b,
+ 0x0d,
+ 0x1e,
+ 0x1e,
+ 0x06,
+ 0x08,
+ 0x18,
+ 0x18,
+ 0x07,
+ 0x09,
+ 0x1a,
+ 0x1a,
+ 0x0e,
+ 0x10,
+ 0x20,
+ 0x28,
+ 0x0f,
+ 0x11,
+ 0x22,
+ 0x2a,
+};
+
+static const u32 tmap_tbl_rev0[] = {
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00000888,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0xf1111110,
+ 0x11111111,
+ 0x11f11111,
+ 0x00000111,
+ 0x11000000,
+ 0x1111f111,
+ 0x11111111,
+ 0x111111f1,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x000aa888,
+ 0x88880000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0xa1111110,
+ 0x11111111,
+ 0x11c11111,
+ 0x00000111,
+ 0x11000000,
+ 0x1111a111,
+ 0x11111111,
+ 0x111111a1,
+ 0xa2222220,
+ 0x22222222,
+ 0x22c22222,
+ 0x00000222,
+ 0x22000000,
+ 0x2222a222,
+ 0x22222222,
+ 0x222222a2,
+ 0xf1111110,
+ 0x11111111,
+ 0x11f11111,
+ 0x00011111,
+ 0x11110000,
+ 0x1111f111,
+ 0x11111111,
+ 0x111111f1,
+ 0xa8aa88a0,
+ 0xa88888a8,
+ 0xa8a8a88a,
+ 0x00088aaa,
+ 0xaaaa0000,
+ 0xa8a8aa88,
+ 0xa88aaaaa,
+ 0xaaaa8a8a,
+ 0xaaa8aaa0,
+ 0x8aaa8aaa,
+ 0xaa8a8a8a,
+ 0x000aaa88,
+ 0x8aaa0000,
+ 0xaaa8a888,
+ 0x8aa88a8a,
+ 0x8a88a888,
+ 0x08080a00,
+ 0x0a08080a,
+ 0x080a0a08,
+ 0x00080808,
+ 0x080a0000,
+ 0x080a0808,
+ 0x080a0808,
+ 0x0a0a0a08,
+ 0xa0a0a0a0,
+ 0x80a0a080,
+ 0x8080a0a0,
+ 0x00008080,
+ 0x80a00000,
+ 0x80a080a0,
+ 0xa080a0a0,
+ 0x8080a0a0,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x99999000,
+ 0x9b9b99bb,
+ 0x9bb99999,
+ 0x9999b9b9,
+ 0x9b99bb90,
+ 0x9bbbbb9b,
+ 0x9b9b9bb9,
+ 0x00000999,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00aaa888,
+ 0x22000000,
+ 0x2222b222,
+ 0x22222222,
+ 0x222222b2,
+ 0xb2222220,
+ 0x22222222,
+ 0x22d22222,
+ 0x00000222,
+ 0x11000000,
+ 0x1111a111,
+ 0x11111111,
+ 0x111111a1,
+ 0xa1111110,
+ 0x11111111,
+ 0x11c11111,
+ 0x00000111,
+ 0x33000000,
+ 0x3333b333,
+ 0x33333333,
+ 0x333333b3,
+ 0xb3333330,
+ 0x33333333,
+ 0x33d33333,
+ 0x00000333,
+ 0x22000000,
+ 0x2222a222,
+ 0x22222222,
+ 0x222222a2,
+ 0xa2222220,
+ 0x22222222,
+ 0x22c22222,
+ 0x00000222,
+ 0x99b99b00,
+ 0x9b9b99bb,
+ 0x9bb99999,
+ 0x9999b9b9,
+ 0x9b99bb99,
+ 0x9bbbbb9b,
+ 0x9b9b9bb9,
+ 0x00000999,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa88,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x08aaa888,
+ 0x22222200,
+ 0x2222f222,
+ 0x22222222,
+ 0x222222f2,
+ 0x22222222,
+ 0x22222222,
+ 0x22f22222,
+ 0x00000222,
+ 0x11000000,
+ 0x1111f111,
+ 0x11111111,
+ 0x11111111,
+ 0xf1111111,
+ 0x11111111,
+ 0x11f11111,
+ 0x01111111,
+ 0xbb9bb900,
+ 0xb9b9bb99,
+ 0xb99bbbbb,
+ 0xbbbb9b9b,
+ 0xb9bb99bb,
+ 0xb99999b9,
+ 0xb9b9b99b,
+ 0x00000bbb,
+ 0xaa000000,
+ 0xa8a8aa88,
+ 0xa88aaaaa,
+ 0xaaaa8a8a,
+ 0xa8aa88aa,
+ 0xa88888a8,
+ 0xa8a8a88a,
+ 0x0a888aaa,
+ 0xaa000000,
+ 0xa8a8aa88,
+ 0xa88aaaaa,
+ 0xaaaa8a8a,
+ 0xa8aa88a0,
+ 0xa88888a8,
+ 0xa8a8a88a,
+ 0x00000aaa,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00000888,
+ 0xbbbbbb00,
+ 0x999bbbbb,
+ 0x9bb99b9b,
+ 0xb9b9b9bb,
+ 0xb9b99bbb,
+ 0xb9b9b9bb,
+ 0xb9bb9b99,
+ 0x00000999,
+ 0x8a000000,
+ 0xaa88a888,
+ 0xa88888aa,
+ 0xa88a8a88,
+ 0xa88aa88a,
+ 0x88a8aaaa,
+ 0xa8aa8aaa,
+ 0x0888a88a,
+ 0x0b0b0b00,
+ 0x090b0b0b,
+ 0x0b090b0b,
+ 0x0909090b,
+ 0x09090b0b,
+ 0x09090b0b,
+ 0x09090b09,
+ 0x00000909,
+ 0x0a000000,
+ 0x0a080808,
+ 0x080a080a,
+ 0x080a0a08,
+ 0x080a080a,
+ 0x0808080a,
+ 0x0a0a0a08,
+ 0x0808080a,
+ 0xb0b0b000,
+ 0x9090b0b0,
+ 0x90b09090,
+ 0xb0b0b090,
+ 0xb0b090b0,
+ 0x90b0b0b0,
+ 0xb0b09090,
+ 0x00000090,
+ 0x80000000,
+ 0xa080a080,
+ 0xa08080a0,
+ 0xa0808080,
+ 0xa080a080,
+ 0x80a0a0a0,
+ 0xa0a080a0,
+ 0x00a0a0a0,
+ 0x22000000,
+ 0x2222f222,
+ 0x22222222,
+ 0x222222f2,
+ 0xf2222220,
+ 0x22222222,
+ 0x22f22222,
+ 0x00000222,
+ 0x11000000,
+ 0x1111f111,
+ 0x11111111,
+ 0x111111f1,
+ 0xf1111110,
+ 0x11111111,
+ 0x11f11111,
+ 0x00000111,
+ 0x33000000,
+ 0x3333f333,
+ 0x33333333,
+ 0x333333f3,
+ 0xf3333330,
+ 0x33333333,
+ 0x33f33333,
+ 0x00000333,
+ 0x22000000,
+ 0x2222f222,
+ 0x22222222,
+ 0x222222f2,
+ 0xf2222220,
+ 0x22222222,
+ 0x22f22222,
+ 0x00000222,
+ 0x99000000,
+ 0x9b9b99bb,
+ 0x9bb99999,
+ 0x9999b9b9,
+ 0x9b99bb90,
+ 0x9bbbbb9b,
+ 0x9b9b9bb9,
+ 0x00000999,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00000888,
+ 0x88888000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00000888,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00aaa888,
+ 0x88a88a00,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa88,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00000888,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa88,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x08aaa888,
+ 0x11000000,
+ 0x1111a111,
+ 0x11111111,
+ 0x111111a1,
+ 0xa1111110,
+ 0x11111111,
+ 0x11c11111,
+ 0x00000111,
+ 0x11000000,
+ 0x1111a111,
+ 0x11111111,
+ 0x111111a1,
+ 0xa1111110,
+ 0x11111111,
+ 0x11c11111,
+ 0x00000111,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00000888,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00000888,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+static const u32 tdtrn_tbl_rev0[] = {
+ 0x061c061c,
+ 0x0050ee68,
+ 0xf592fe36,
+ 0xfe5212f6,
+ 0x00000c38,
+ 0xfe5212f6,
+ 0xf592fe36,
+ 0x0050ee68,
+ 0x061c061c,
+ 0xee680050,
+ 0xfe36f592,
+ 0x12f6fe52,
+ 0x0c380000,
+ 0x12f6fe52,
+ 0xfe36f592,
+ 0xee680050,
+ 0x061c061c,
+ 0x0050ee68,
+ 0xf592fe36,
+ 0xfe5212f6,
+ 0x00000c38,
+ 0xfe5212f6,
+ 0xf592fe36,
+ 0x0050ee68,
+ 0x061c061c,
+ 0xee680050,
+ 0xfe36f592,
+ 0x12f6fe52,
+ 0x0c380000,
+ 0x12f6fe52,
+ 0xfe36f592,
+ 0xee680050,
+ 0x05e305e3,
+ 0x004def0c,
+ 0xf5f3fe47,
+ 0xfe611246,
+ 0x00000bc7,
+ 0xfe611246,
+ 0xf5f3fe47,
+ 0x004def0c,
+ 0x05e305e3,
+ 0xef0c004d,
+ 0xfe47f5f3,
+ 0x1246fe61,
+ 0x0bc70000,
+ 0x1246fe61,
+ 0xfe47f5f3,
+ 0xef0c004d,
+ 0x05e305e3,
+ 0x004def0c,
+ 0xf5f3fe47,
+ 0xfe611246,
+ 0x00000bc7,
+ 0xfe611246,
+ 0xf5f3fe47,
+ 0x004def0c,
+ 0x05e305e3,
+ 0xef0c004d,
+ 0xfe47f5f3,
+ 0x1246fe61,
+ 0x0bc70000,
+ 0x1246fe61,
+ 0xfe47f5f3,
+ 0xef0c004d,
+ 0xfa58fa58,
+ 0xf895043b,
+ 0xff4c09c0,
+ 0xfbc6ffa8,
+ 0xfb84f384,
+ 0x0798f6f9,
+ 0x05760122,
+ 0x058409f6,
+ 0x0b500000,
+ 0x05b7f542,
+ 0x08860432,
+ 0x06ddfee7,
+ 0xfb84f384,
+ 0xf9d90664,
+ 0xf7e8025c,
+ 0x00fff7bd,
+ 0x05a805a8,
+ 0xf7bd00ff,
+ 0x025cf7e8,
+ 0x0664f9d9,
+ 0xf384fb84,
+ 0xfee706dd,
+ 0x04320886,
+ 0xf54205b7,
+ 0x00000b50,
+ 0x09f60584,
+ 0x01220576,
+ 0xf6f90798,
+ 0xf384fb84,
+ 0xffa8fbc6,
+ 0x09c0ff4c,
+ 0x043bf895,
+ 0x02d402d4,
+ 0x07de0270,
+ 0xfc96079c,
+ 0xf90afe94,
+ 0xfe00ff2c,
+ 0x02d4065d,
+ 0x092a0096,
+ 0x0014fbb8,
+ 0xfd2cfd2c,
+ 0x076afb3c,
+ 0x0096f752,
+ 0xf991fd87,
+ 0xfb2c0200,
+ 0xfeb8f960,
+ 0x08e0fc96,
+ 0x049802a8,
+ 0xfd2cfd2c,
+ 0x02a80498,
+ 0xfc9608e0,
+ 0xf960feb8,
+ 0x0200fb2c,
+ 0xfd87f991,
+ 0xf7520096,
+ 0xfb3c076a,
+ 0xfd2cfd2c,
+ 0xfbb80014,
+ 0x0096092a,
+ 0x065d02d4,
+ 0xff2cfe00,
+ 0xfe94f90a,
+ 0x079cfc96,
+ 0x027007de,
+ 0x02d402d4,
+ 0x027007de,
+ 0x079cfc96,
+ 0xfe94f90a,
+ 0xff2cfe00,
+ 0x065d02d4,
+ 0x0096092a,
+ 0xfbb80014,
+ 0xfd2cfd2c,
+ 0xfb3c076a,
+ 0xf7520096,
+ 0xfd87f991,
+ 0x0200fb2c,
+ 0xf960feb8,
+ 0xfc9608e0,
+ 0x02a80498,
+ 0xfd2cfd2c,
+ 0x049802a8,
+ 0x08e0fc96,
+ 0xfeb8f960,
+ 0xfb2c0200,
+ 0xf991fd87,
+ 0x0096f752,
+ 0x076afb3c,
+ 0xfd2cfd2c,
+ 0x0014fbb8,
+ 0x092a0096,
+ 0x02d4065d,
+ 0xfe00ff2c,
+ 0xf90afe94,
+ 0xfc96079c,
+ 0x07de0270,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x062a0000,
+ 0xfefa0759,
+ 0x08b80908,
+ 0xf396fc2d,
+ 0xf9d6045c,
+ 0xfc4ef608,
+ 0xf748f596,
+ 0x07b207bf,
+ 0x062a062a,
+ 0xf84ef841,
+ 0xf748f596,
+ 0x03b209f8,
+ 0xf9d6045c,
+ 0x0c6a03d3,
+ 0x08b80908,
+ 0x0106f8a7,
+ 0x062a0000,
+ 0xfefaf8a7,
+ 0x08b8f6f8,
+ 0xf39603d3,
+ 0xf9d6fba4,
+ 0xfc4e09f8,
+ 0xf7480a6a,
+ 0x07b2f841,
+ 0x062af9d6,
+ 0xf84e07bf,
+ 0xf7480a6a,
+ 0x03b2f608,
+ 0xf9d6fba4,
+ 0x0c6afc2d,
+ 0x08b8f6f8,
+ 0x01060759,
+ 0x062a0000,
+ 0xfefa0759,
+ 0x08b80908,
+ 0xf396fc2d,
+ 0xf9d6045c,
+ 0xfc4ef608,
+ 0xf748f596,
+ 0x07b207bf,
+ 0x062a062a,
+ 0xf84ef841,
+ 0xf748f596,
+ 0x03b209f8,
+ 0xf9d6045c,
+ 0x0c6a03d3,
+ 0x08b80908,
+ 0x0106f8a7,
+ 0x062a0000,
+ 0xfefaf8a7,
+ 0x08b8f6f8,
+ 0xf39603d3,
+ 0xf9d6fba4,
+ 0xfc4e09f8,
+ 0xf7480a6a,
+ 0x07b2f841,
+ 0x062af9d6,
+ 0xf84e07bf,
+ 0xf7480a6a,
+ 0x03b2f608,
+ 0xf9d6fba4,
+ 0x0c6afc2d,
+ 0x08b8f6f8,
+ 0x01060759,
+ 0x061c061c,
+ 0xff30009d,
+ 0xffb21141,
+ 0xfd87fb54,
+ 0xf65dfe59,
+ 0x02eef99e,
+ 0x0166f03c,
+ 0xfff809b6,
+ 0x000008a4,
+ 0x000af42b,
+ 0x00eff577,
+ 0xfa840bf2,
+ 0xfc02ff51,
+ 0x08260f67,
+ 0xfff0036f,
+ 0x0842f9c3,
+ 0x00000000,
+ 0x063df7be,
+ 0xfc910010,
+ 0xf099f7da,
+ 0x00af03fe,
+ 0xf40e057c,
+ 0x0a89ff11,
+ 0x0bd5fff6,
+ 0xf75c0000,
+ 0xf64a0008,
+ 0x0fc4fe9a,
+ 0x0662fd12,
+ 0x01a709a3,
+ 0x04ac0279,
+ 0xeebf004e,
+ 0xff6300d0,
+ 0xf9e4f9e4,
+ 0x00d0ff63,
+ 0x004eeebf,
+ 0x027904ac,
+ 0x09a301a7,
+ 0xfd120662,
+ 0xfe9a0fc4,
+ 0x0008f64a,
+ 0x0000f75c,
+ 0xfff60bd5,
+ 0xff110a89,
+ 0x057cf40e,
+ 0x03fe00af,
+ 0xf7daf099,
+ 0x0010fc91,
+ 0xf7be063d,
+ 0x00000000,
+ 0xf9c30842,
+ 0x036ffff0,
+ 0x0f670826,
+ 0xff51fc02,
+ 0x0bf2fa84,
+ 0xf57700ef,
+ 0xf42b000a,
+ 0x08a40000,
+ 0x09b6fff8,
+ 0xf03c0166,
+ 0xf99e02ee,
+ 0xfe59f65d,
+ 0xfb54fd87,
+ 0x1141ffb2,
+ 0x009dff30,
+ 0x05e30000,
+ 0xff060705,
+ 0x085408a0,
+ 0xf425fc59,
+ 0xfa1d042a,
+ 0xfc78f67a,
+ 0xf7acf60e,
+ 0x075a0766,
+ 0x05e305e3,
+ 0xf8a6f89a,
+ 0xf7acf60e,
+ 0x03880986,
+ 0xfa1d042a,
+ 0x0bdb03a7,
+ 0x085408a0,
+ 0x00faf8fb,
+ 0x05e30000,
+ 0xff06f8fb,
+ 0x0854f760,
+ 0xf42503a7,
+ 0xfa1dfbd6,
+ 0xfc780986,
+ 0xf7ac09f2,
+ 0x075af89a,
+ 0x05e3fa1d,
+ 0xf8a60766,
+ 0xf7ac09f2,
+ 0x0388f67a,
+ 0xfa1dfbd6,
+ 0x0bdbfc59,
+ 0x0854f760,
+ 0x00fa0705,
+ 0x05e30000,
+ 0xff060705,
+ 0x085408a0,
+ 0xf425fc59,
+ 0xfa1d042a,
+ 0xfc78f67a,
+ 0xf7acf60e,
+ 0x075a0766,
+ 0x05e305e3,
+ 0xf8a6f89a,
+ 0xf7acf60e,
+ 0x03880986,
+ 0xfa1d042a,
+ 0x0bdb03a7,
+ 0x085408a0,
+ 0x00faf8fb,
+ 0x05e30000,
+ 0xff06f8fb,
+ 0x0854f760,
+ 0xf42503a7,
+ 0xfa1dfbd6,
+ 0xfc780986,
+ 0xf7ac09f2,
+ 0x075af89a,
+ 0x05e3fa1d,
+ 0xf8a60766,
+ 0xf7ac09f2,
+ 0x0388f67a,
+ 0xfa1dfbd6,
+ 0x0bdbfc59,
+ 0x0854f760,
+ 0x00fa0705,
+ 0xfa58fa58,
+ 0xf8f0fe00,
+ 0x0448073d,
+ 0xfdc9fe46,
+ 0xf9910258,
+ 0x089d0407,
+ 0xfd5cf71a,
+ 0x02affde0,
+ 0x083e0496,
+ 0xff5a0740,
+ 0xff7afd97,
+ 0x00fe01f1,
+ 0x0009082e,
+ 0xfa94ff75,
+ 0xfecdf8ea,
+ 0xffb0f693,
+ 0xfd2cfa58,
+ 0x0433ff16,
+ 0xfba405dd,
+ 0xfa610341,
+ 0x06a606cb,
+ 0x0039fd2d,
+ 0x0677fa97,
+ 0x01fa05e0,
+ 0xf896003e,
+ 0x075a068b,
+ 0x012cfc3e,
+ 0xfa23f98d,
+ 0xfc7cfd43,
+ 0xff90fc0d,
+ 0x01c10982,
+ 0x00c601d6,
+ 0xfd2cfd2c,
+ 0x01d600c6,
+ 0x098201c1,
+ 0xfc0dff90,
+ 0xfd43fc7c,
+ 0xf98dfa23,
+ 0xfc3e012c,
+ 0x068b075a,
+ 0x003ef896,
+ 0x05e001fa,
+ 0xfa970677,
+ 0xfd2d0039,
+ 0x06cb06a6,
+ 0x0341fa61,
+ 0x05ddfba4,
+ 0xff160433,
+ 0xfa58fd2c,
+ 0xf693ffb0,
+ 0xf8eafecd,
+ 0xff75fa94,
+ 0x082e0009,
+ 0x01f100fe,
+ 0xfd97ff7a,
+ 0x0740ff5a,
+ 0x0496083e,
+ 0xfde002af,
+ 0xf71afd5c,
+ 0x0407089d,
+ 0x0258f991,
+ 0xfe46fdc9,
+ 0x073d0448,
+ 0xfe00f8f0,
+ 0xfd2cfd2c,
+ 0xfce00500,
+ 0xfc09fddc,
+ 0xfe680157,
+ 0x04c70571,
+ 0xfc3aff21,
+ 0xfcd70228,
+ 0x056d0277,
+ 0x0200fe00,
+ 0x0022f927,
+ 0xfe3c032b,
+ 0xfc44ff3c,
+ 0x03e9fbdb,
+ 0x04570313,
+ 0x04c9ff5c,
+ 0x000d03b8,
+ 0xfa580000,
+ 0xfbe900d2,
+ 0xf9d0fe0b,
+ 0x0125fdf9,
+ 0x042501bf,
+ 0x0328fa2b,
+ 0xffa902f0,
+ 0xfa250157,
+ 0x0200fe00,
+ 0x03740438,
+ 0xff0405fd,
+ 0x030cfe52,
+ 0x0037fb39,
+ 0xff6904c5,
+ 0x04f8fd23,
+ 0xfd31fc1b,
+ 0xfd2cfd2c,
+ 0xfc1bfd31,
+ 0xfd2304f8,
+ 0x04c5ff69,
+ 0xfb390037,
+ 0xfe52030c,
+ 0x05fdff04,
+ 0x04380374,
+ 0xfe000200,
+ 0x0157fa25,
+ 0x02f0ffa9,
+ 0xfa2b0328,
+ 0x01bf0425,
+ 0xfdf90125,
+ 0xfe0bf9d0,
+ 0x00d2fbe9,
+ 0x0000fa58,
+ 0x03b8000d,
+ 0xff5c04c9,
+ 0x03130457,
+ 0xfbdb03e9,
+ 0xff3cfc44,
+ 0x032bfe3c,
+ 0xf9270022,
+ 0xfe000200,
+ 0x0277056d,
+ 0x0228fcd7,
+ 0xff21fc3a,
+ 0x057104c7,
+ 0x0157fe68,
+ 0xfddcfc09,
+ 0x0500fce0,
+ 0xfd2cfd2c,
+ 0x0500fce0,
+ 0xfddcfc09,
+ 0x0157fe68,
+ 0x057104c7,
+ 0xff21fc3a,
+ 0x0228fcd7,
+ 0x0277056d,
+ 0xfe000200,
+ 0xf9270022,
+ 0x032bfe3c,
+ 0xff3cfc44,
+ 0xfbdb03e9,
+ 0x03130457,
+ 0xff5c04c9,
+ 0x03b8000d,
+ 0x0000fa58,
+ 0x00d2fbe9,
+ 0xfe0bf9d0,
+ 0xfdf90125,
+ 0x01bf0425,
+ 0xfa2b0328,
+ 0x02f0ffa9,
+ 0x0157fa25,
+ 0xfe000200,
+ 0x04380374,
+ 0x05fdff04,
+ 0xfe52030c,
+ 0xfb390037,
+ 0x04c5ff69,
+ 0xfd2304f8,
+ 0xfc1bfd31,
+ 0xfd2cfd2c,
+ 0xfd31fc1b,
+ 0x04f8fd23,
+ 0xff6904c5,
+ 0x0037fb39,
+ 0x030cfe52,
+ 0xff0405fd,
+ 0x03740438,
+ 0x0200fe00,
+ 0xfa250157,
+ 0xffa902f0,
+ 0x0328fa2b,
+ 0x042501bf,
+ 0x0125fdf9,
+ 0xf9d0fe0b,
+ 0xfbe900d2,
+ 0xfa580000,
+ 0x000d03b8,
+ 0x04c9ff5c,
+ 0x04570313,
+ 0x03e9fbdb,
+ 0xfc44ff3c,
+ 0xfe3c032b,
+ 0x0022f927,
+ 0x0200fe00,
+ 0x056d0277,
+ 0xfcd70228,
+ 0xfc3aff21,
+ 0x04c70571,
+ 0xfe680157,
+ 0xfc09fddc,
+ 0xfce00500,
+ 0x05a80000,
+ 0xff1006be,
+ 0x0800084a,
+ 0xf49cfc7e,
+ 0xfa580400,
+ 0xfc9cf6da,
+ 0xf800f672,
+ 0x0710071c,
+ 0x05a805a8,
+ 0xf8f0f8e4,
+ 0xf800f672,
+ 0x03640926,
+ 0xfa580400,
+ 0x0b640382,
+ 0x0800084a,
+ 0x00f0f942,
+ 0x05a80000,
+ 0xff10f942,
+ 0x0800f7b6,
+ 0xf49c0382,
+ 0xfa58fc00,
+ 0xfc9c0926,
+ 0xf800098e,
+ 0x0710f8e4,
+ 0x05a8fa58,
+ 0xf8f0071c,
+ 0xf800098e,
+ 0x0364f6da,
+ 0xfa58fc00,
+ 0x0b64fc7e,
+ 0x0800f7b6,
+ 0x00f006be,
+ 0x05a80000,
+ 0xff1006be,
+ 0x0800084a,
+ 0xf49cfc7e,
+ 0xfa580400,
+ 0xfc9cf6da,
+ 0xf800f672,
+ 0x0710071c,
+ 0x05a805a8,
+ 0xf8f0f8e4,
+ 0xf800f672,
+ 0x03640926,
+ 0xfa580400,
+ 0x0b640382,
+ 0x0800084a,
+ 0x00f0f942,
+ 0x05a80000,
+ 0xff10f942,
+ 0x0800f7b6,
+ 0xf49c0382,
+ 0xfa58fc00,
+ 0xfc9c0926,
+ 0xf800098e,
+ 0x0710f8e4,
+ 0x05a8fa58,
+ 0xf8f0071c,
+ 0xf800098e,
+ 0x0364f6da,
+ 0xfa58fc00,
+ 0x0b64fc7e,
+ 0x0800f7b6,
+ 0x00f006be,
+};
+
+static const u32 intlv_tbl_rev0[] = {
+ 0x00802070,
+ 0x0671188d,
+ 0x0a60192c,
+ 0x0a300e46,
+ 0x00c1188d,
+ 0x080024d2,
+ 0x00000070,
+};
+
+static const u16 pilot_tbl_rev0[] = {
+ 0xff08,
+ 0xff08,
+ 0xff08,
+ 0xff08,
+ 0xff08,
+ 0xff08,
+ 0xff08,
+ 0xff08,
+ 0x80d5,
+ 0x80d5,
+ 0x80d5,
+ 0x80d5,
+ 0x80d5,
+ 0x80d5,
+ 0x80d5,
+ 0x80d5,
+ 0xff0a,
+ 0xff82,
+ 0xffa0,
+ 0xff28,
+ 0xffff,
+ 0xffff,
+ 0xffff,
+ 0xffff,
+ 0xff82,
+ 0xffa0,
+ 0xff28,
+ 0xff0a,
+ 0xffff,
+ 0xffff,
+ 0xffff,
+ 0xffff,
+ 0xf83f,
+ 0xfa1f,
+ 0xfa97,
+ 0xfab5,
+ 0xf2bd,
+ 0xf0bf,
+ 0xffff,
+ 0xffff,
+ 0xf017,
+ 0xf815,
+ 0xf215,
+ 0xf095,
+ 0xf035,
+ 0xf01d,
+ 0xffff,
+ 0xffff,
+ 0xff08,
+ 0xff02,
+ 0xff80,
+ 0xff20,
+ 0xff08,
+ 0xff02,
+ 0xff80,
+ 0xff20,
+ 0xf01f,
+ 0xf817,
+ 0xfa15,
+ 0xf295,
+ 0xf0b5,
+ 0xf03d,
+ 0xffff,
+ 0xffff,
+ 0xf82a,
+ 0xfa0a,
+ 0xfa82,
+ 0xfaa0,
+ 0xf2a8,
+ 0xf0aa,
+ 0xffff,
+ 0xffff,
+ 0xf002,
+ 0xf800,
+ 0xf200,
+ 0xf080,
+ 0xf020,
+ 0xf008,
+ 0xffff,
+ 0xffff,
+ 0xf00a,
+ 0xf802,
+ 0xfa00,
+ 0xf280,
+ 0xf0a0,
+ 0xf028,
+ 0xffff,
+ 0xffff,
+};
+
+static const u32 pltlut_tbl_rev0[] = {
+ 0x76540123,
+ 0x62407351,
+ 0x76543201,
+ 0x76540213,
+ 0x76540123,
+ 0x76430521,
+};
+
+static const u32 tdi_tbl20_ant0_rev0[] = {
+ 0x00091226,
+ 0x000a1429,
+ 0x000b56ad,
+ 0x000c58b0,
+ 0x000d5ab3,
+ 0x000e9cb6,
+ 0x000f9eba,
+ 0x0000c13d,
+ 0x00020301,
+ 0x00030504,
+ 0x00040708,
+ 0x0005090b,
+ 0x00064b8e,
+ 0x00095291,
+ 0x000a5494,
+ 0x000b9718,
+ 0x000c9927,
+ 0x000d9b2a,
+ 0x000edd2e,
+ 0x000fdf31,
+ 0x000101b4,
+ 0x000243b7,
+ 0x000345bb,
+ 0x000447be,
+ 0x00058982,
+ 0x00068c05,
+ 0x00099309,
+ 0x000a950c,
+ 0x000bd78f,
+ 0x000cd992,
+ 0x000ddb96,
+ 0x000f1d99,
+ 0x00005fa8,
+ 0x0001422c,
+ 0x0002842f,
+ 0x00038632,
+ 0x00048835,
+ 0x0005ca38,
+ 0x0006ccbc,
+ 0x0009d3bf,
+ 0x000b1603,
+ 0x000c1806,
+ 0x000d1a0a,
+ 0x000e1c0d,
+ 0x000f5e10,
+ 0x00008093,
+ 0x00018297,
+ 0x0002c49a,
+ 0x0003c680,
+ 0x0004c880,
+ 0x00060b00,
+ 0x00070d00,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+static const u32 tdi_tbl20_ant1_rev0[] = {
+ 0x00014b26,
+ 0x00028d29,
+ 0x000393ad,
+ 0x00049630,
+ 0x0005d833,
+ 0x0006da36,
+ 0x00099c3a,
+ 0x000a9e3d,
+ 0x000bc081,
+ 0x000cc284,
+ 0x000dc488,
+ 0x000f068b,
+ 0x0000488e,
+ 0x00018b91,
+ 0x0002d214,
+ 0x0003d418,
+ 0x0004d6a7,
+ 0x000618aa,
+ 0x00071aae,
+ 0x0009dcb1,
+ 0x000b1eb4,
+ 0x000c0137,
+ 0x000d033b,
+ 0x000e053e,
+ 0x000f4702,
+ 0x00008905,
+ 0x00020c09,
+ 0x0003128c,
+ 0x0004148f,
+ 0x00051712,
+ 0x00065916,
+ 0x00091b19,
+ 0x000a1d28,
+ 0x000b5f2c,
+ 0x000c41af,
+ 0x000d43b2,
+ 0x000e85b5,
+ 0x000f87b8,
+ 0x0000c9bc,
+ 0x00024cbf,
+ 0x00035303,
+ 0x00045506,
+ 0x0005978a,
+ 0x0006998d,
+ 0x00095b90,
+ 0x000a5d93,
+ 0x000b9f97,
+ 0x000c821a,
+ 0x000d8400,
+ 0x000ec600,
+ 0x000fc800,
+ 0x00010a00,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+static const u32 tdi_tbl40_ant0_rev0[] = {
+ 0x0011a346,
+ 0x00136ccf,
+ 0x0014f5d9,
+ 0x001641e2,
+ 0x0017cb6b,
+ 0x00195475,
+ 0x001b2383,
+ 0x001cad0c,
+ 0x001e7616,
+ 0x0000821f,
+ 0x00020ba8,
+ 0x0003d4b2,
+ 0x00056447,
+ 0x00072dd0,
+ 0x0008b6da,
+ 0x000a02e3,
+ 0x000b8c6c,
+ 0x000d15f6,
+ 0x0011e484,
+ 0x0013ae0d,
+ 0x00153717,
+ 0x00168320,
+ 0x00180ca9,
+ 0x00199633,
+ 0x001b6548,
+ 0x001ceed1,
+ 0x001eb7db,
+ 0x0000c3e4,
+ 0x00024d6d,
+ 0x000416f7,
+ 0x0005a585,
+ 0x00076f0f,
+ 0x0008f818,
+ 0x000a4421,
+ 0x000bcdab,
+ 0x000d9734,
+ 0x00122649,
+ 0x0013efd2,
+ 0x001578dc,
+ 0x0016c4e5,
+ 0x00184e6e,
+ 0x001a17f8,
+ 0x001ba686,
+ 0x001d3010,
+ 0x001ef999,
+ 0x00010522,
+ 0x00028eac,
+ 0x00045835,
+ 0x0005e74a,
+ 0x0007b0d3,
+ 0x00093a5d,
+ 0x000a85e6,
+ 0x000c0f6f,
+ 0x000dd8f9,
+ 0x00126787,
+ 0x00143111,
+ 0x0015ba9a,
+ 0x00170623,
+ 0x00188fad,
+ 0x001a5936,
+ 0x001be84b,
+ 0x001db1d4,
+ 0x001f3b5e,
+ 0x000146e7,
+ 0x00031070,
+ 0x000499fa,
+ 0x00062888,
+ 0x0007f212,
+ 0x00097b9b,
+ 0x000ac7a4,
+ 0x000c50ae,
+ 0x000e1a37,
+ 0x0012a94c,
+ 0x001472d5,
+ 0x0015fc5f,
+ 0x00174868,
+ 0x0018d171,
+ 0x001a9afb,
+ 0x001c2989,
+ 0x001df313,
+ 0x001f7c9c,
+ 0x000188a5,
+ 0x000351af,
+ 0x0004db38,
+ 0x0006aa4d,
+ 0x000833d7,
+ 0x0009bd60,
+ 0x000b0969,
+ 0x000c9273,
+ 0x000e5bfc,
+ 0x00132a8a,
+ 0x0014b414,
+ 0x00163d9d,
+ 0x001789a6,
+ 0x001912b0,
+ 0x001adc39,
+ 0x001c6bce,
+ 0x001e34d8,
+ 0x001fbe61,
+ 0x0001ca6a,
+ 0x00039374,
+ 0x00051cfd,
+ 0x0006ec0b,
+ 0x00087515,
+ 0x0009fe9e,
+ 0x000b4aa7,
+ 0x000cd3b1,
+ 0x000e9d3a,
+ 0x00000000,
+ 0x00000000,
+};
+
+static const u32 tdi_tbl40_ant1_rev0[] = {
+ 0x001edb36,
+ 0x000129ca,
+ 0x0002b353,
+ 0x00047cdd,
+ 0x0005c8e6,
+ 0x000791ef,
+ 0x00091bf9,
+ 0x000aaa07,
+ 0x000c3391,
+ 0x000dfd1a,
+ 0x00120923,
+ 0x0013d22d,
+ 0x00155c37,
+ 0x0016eacb,
+ 0x00187454,
+ 0x001a3dde,
+ 0x001b89e7,
+ 0x001d12f0,
+ 0x001f1cfa,
+ 0x00016b88,
+ 0x00033492,
+ 0x0004be1b,
+ 0x00060a24,
+ 0x0007d32e,
+ 0x00095d38,
+ 0x000aec4c,
+ 0x000c7555,
+ 0x000e3edf,
+ 0x00124ae8,
+ 0x001413f1,
+ 0x0015a37b,
+ 0x00172c89,
+ 0x0018b593,
+ 0x001a419c,
+ 0x001bcb25,
+ 0x001d942f,
+ 0x001f63b9,
+ 0x0001ad4d,
+ 0x00037657,
+ 0x0004c260,
+ 0x00068be9,
+ 0x000814f3,
+ 0x0009a47c,
+ 0x000b2d8a,
+ 0x000cb694,
+ 0x000e429d,
+ 0x00128c26,
+ 0x001455b0,
+ 0x0015e4ba,
+ 0x00176e4e,
+ 0x0018f758,
+ 0x001a8361,
+ 0x001c0cea,
+ 0x001dd674,
+ 0x001fa57d,
+ 0x0001ee8b,
+ 0x0003b795,
+ 0x0005039e,
+ 0x0006cd27,
+ 0x000856b1,
+ 0x0009e5c6,
+ 0x000b6f4f,
+ 0x000cf859,
+ 0x000e8462,
+ 0x00130deb,
+ 0x00149775,
+ 0x00162603,
+ 0x0017af8c,
+ 0x00193896,
+ 0x001ac49f,
+ 0x001c4e28,
+ 0x001e17b2,
+ 0x0000a6c7,
+ 0x00023050,
+ 0x0003f9da,
+ 0x00054563,
+ 0x00070eec,
+ 0x00089876,
+ 0x000a2704,
+ 0x000bb08d,
+ 0x000d3a17,
+ 0x001185a0,
+ 0x00134f29,
+ 0x0014d8b3,
+ 0x001667c8,
+ 0x0017f151,
+ 0x00197adb,
+ 0x001b0664,
+ 0x001c8fed,
+ 0x001e5977,
+ 0x0000e805,
+ 0x0002718f,
+ 0x00043b18,
+ 0x000586a1,
+ 0x0007502b,
+ 0x0008d9b4,
+ 0x000a68c9,
+ 0x000bf252,
+ 0x000dbbdc,
+ 0x0011c7e5,
+ 0x001390ee,
+ 0x00151a78,
+ 0x0016a906,
+ 0x00183290,
+ 0x0019bc19,
+ 0x001b4822,
+ 0x001cd12c,
+ 0x001e9ab5,
+ 0x00000000,
+ 0x00000000,
+};
+
+static const u16 bdi_tbl_rev0[] = {
+ 0x0070,
+ 0x0126,
+ 0x012c,
+ 0x0246,
+ 0x048d,
+ 0x04d2,
+};
+
+static const u32 chanest_tbl_rev0[] = {
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+};
+
+static const u8 mcs_tbl_rev0[] = {
+ 0x00,
+ 0x08,
+ 0x0a,
+ 0x10,
+ 0x12,
+ 0x19,
+ 0x1a,
+ 0x1c,
+ 0x40,
+ 0x48,
+ 0x4a,
+ 0x50,
+ 0x52,
+ 0x59,
+ 0x5a,
+ 0x5c,
+ 0x80,
+ 0x88,
+ 0x8a,
+ 0x90,
+ 0x92,
+ 0x99,
+ 0x9a,
+ 0x9c,
+ 0xc0,
+ 0xc8,
+ 0xca,
+ 0xd0,
+ 0xd2,
+ 0xd9,
+ 0xda,
+ 0xdc,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x01,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x09,
+ 0x0a,
+ 0x0c,
+ 0x10,
+ 0x11,
+ 0x12,
+ 0x14,
+ 0x18,
+ 0x19,
+ 0x1a,
+ 0x1c,
+ 0x20,
+ 0x21,
+ 0x22,
+ 0x24,
+ 0x40,
+ 0x41,
+ 0x42,
+ 0x44,
+ 0x48,
+ 0x49,
+ 0x4a,
+ 0x4c,
+ 0x50,
+ 0x51,
+ 0x52,
+ 0x54,
+ 0x58,
+ 0x59,
+ 0x5a,
+ 0x5c,
+ 0x60,
+ 0x61,
+ 0x62,
+ 0x64,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+};
+
+static const u32 noise_var_tbl0_rev0[] = {
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+};
+
+static const u32 noise_var_tbl1_rev0[] = {
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+};
+
+static const u8 est_pwr_lut_core0_rev0[] = {
+ 0x50,
+ 0x4f,
+ 0x4e,
+ 0x4d,
+ 0x4c,
+ 0x4b,
+ 0x4a,
+ 0x49,
+ 0x48,
+ 0x47,
+ 0x46,
+ 0x45,
+ 0x44,
+ 0x43,
+ 0x42,
+ 0x41,
+ 0x40,
+ 0x3f,
+ 0x3e,
+ 0x3d,
+ 0x3c,
+ 0x3b,
+ 0x3a,
+ 0x39,
+ 0x38,
+ 0x37,
+ 0x36,
+ 0x35,
+ 0x34,
+ 0x33,
+ 0x32,
+ 0x31,
+ 0x30,
+ 0x2f,
+ 0x2e,
+ 0x2d,
+ 0x2c,
+ 0x2b,
+ 0x2a,
+ 0x29,
+ 0x28,
+ 0x27,
+ 0x26,
+ 0x25,
+ 0x24,
+ 0x23,
+ 0x22,
+ 0x21,
+ 0x20,
+ 0x1f,
+ 0x1e,
+ 0x1d,
+ 0x1c,
+ 0x1b,
+ 0x1a,
+ 0x19,
+ 0x18,
+ 0x17,
+ 0x16,
+ 0x15,
+ 0x14,
+ 0x13,
+ 0x12,
+ 0x11,
+};
+
+static const u8 est_pwr_lut_core1_rev0[] = {
+ 0x50,
+ 0x4f,
+ 0x4e,
+ 0x4d,
+ 0x4c,
+ 0x4b,
+ 0x4a,
+ 0x49,
+ 0x48,
+ 0x47,
+ 0x46,
+ 0x45,
+ 0x44,
+ 0x43,
+ 0x42,
+ 0x41,
+ 0x40,
+ 0x3f,
+ 0x3e,
+ 0x3d,
+ 0x3c,
+ 0x3b,
+ 0x3a,
+ 0x39,
+ 0x38,
+ 0x37,
+ 0x36,
+ 0x35,
+ 0x34,
+ 0x33,
+ 0x32,
+ 0x31,
+ 0x30,
+ 0x2f,
+ 0x2e,
+ 0x2d,
+ 0x2c,
+ 0x2b,
+ 0x2a,
+ 0x29,
+ 0x28,
+ 0x27,
+ 0x26,
+ 0x25,
+ 0x24,
+ 0x23,
+ 0x22,
+ 0x21,
+ 0x20,
+ 0x1f,
+ 0x1e,
+ 0x1d,
+ 0x1c,
+ 0x1b,
+ 0x1a,
+ 0x19,
+ 0x18,
+ 0x17,
+ 0x16,
+ 0x15,
+ 0x14,
+ 0x13,
+ 0x12,
+ 0x11,
+};
+
+static const u8 adj_pwr_lut_core0_rev0[] = {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+};
+
+static const u8 adj_pwr_lut_core1_rev0[] = {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+};
+
+static const u32 gainctrl_lut_core0_rev0[] = {
+ 0x03cc2b44,
+ 0x03cc2b42,
+ 0x03cc2b40,
+ 0x03cc2b3e,
+ 0x03cc2b3d,
+ 0x03cc2b3b,
+ 0x03c82b44,
+ 0x03c82b42,
+ 0x03c82b40,
+ 0x03c82b3e,
+ 0x03c82b3d,
+ 0x03c82b3b,
+ 0x03c82b39,
+ 0x03c82b38,
+ 0x03c82b36,
+ 0x03c82b34,
+ 0x03c42b44,
+ 0x03c42b42,
+ 0x03c42b40,
+ 0x03c42b3e,
+ 0x03c42b3d,
+ 0x03c42b3b,
+ 0x03c42b39,
+ 0x03c42b38,
+ 0x03c42b36,
+ 0x03c42b34,
+ 0x03c42b33,
+ 0x03c42b32,
+ 0x03c42b30,
+ 0x03c42b2f,
+ 0x03c42b2d,
+ 0x03c02b44,
+ 0x03c02b42,
+ 0x03c02b40,
+ 0x03c02b3e,
+ 0x03c02b3d,
+ 0x03c02b3b,
+ 0x03c02b39,
+ 0x03c02b38,
+ 0x03c02b36,
+ 0x03c02b34,
+ 0x03b02b44,
+ 0x03b02b42,
+ 0x03b02b40,
+ 0x03b02b3e,
+ 0x03b02b3d,
+ 0x03b02b3b,
+ 0x03b02b39,
+ 0x03b02b38,
+ 0x03b02b36,
+ 0x03b02b34,
+ 0x03b02b33,
+ 0x03b02b32,
+ 0x03b02b30,
+ 0x03b02b2f,
+ 0x03b02b2d,
+ 0x03a02b44,
+ 0x03a02b42,
+ 0x03a02b40,
+ 0x03a02b3e,
+ 0x03a02b3d,
+ 0x03a02b3b,
+ 0x03a02b39,
+ 0x03a02b38,
+ 0x03a02b36,
+ 0x03a02b34,
+ 0x03902b44,
+ 0x03902b42,
+ 0x03902b40,
+ 0x03902b3e,
+ 0x03902b3d,
+ 0x03902b3b,
+ 0x03902b39,
+ 0x03902b38,
+ 0x03902b36,
+ 0x03902b34,
+ 0x03902b33,
+ 0x03902b32,
+ 0x03902b30,
+ 0x03802b44,
+ 0x03802b42,
+ 0x03802b40,
+ 0x03802b3e,
+ 0x03802b3d,
+ 0x03802b3b,
+ 0x03802b39,
+ 0x03802b38,
+ 0x03802b36,
+ 0x03802b34,
+ 0x03802b33,
+ 0x03802b32,
+ 0x03802b30,
+ 0x03802b2f,
+ 0x03802b2d,
+ 0x03802b2c,
+ 0x03802b2b,
+ 0x03802b2a,
+ 0x03802b29,
+ 0x03802b27,
+ 0x03802b26,
+ 0x03802b25,
+ 0x03802b24,
+ 0x03802b23,
+ 0x03802b22,
+ 0x03802b21,
+ 0x03802b20,
+ 0x03802b1f,
+ 0x03802b1e,
+ 0x03802b1e,
+ 0x03802b1d,
+ 0x03802b1c,
+ 0x03802b1b,
+ 0x03802b1a,
+ 0x03802b1a,
+ 0x03802b19,
+ 0x03802b18,
+ 0x03802b18,
+ 0x03802b18,
+ 0x03802b18,
+ 0x03802b18,
+ 0x03802b18,
+ 0x03802b18,
+ 0x03802b18,
+ 0x03802b18,
+ 0x03802b18,
+ 0x03802b18,
+ 0x03802b18,
+ 0x00002b00,
+};
+
+static const u32 gainctrl_lut_core1_rev0[] = {
+ 0x03cc2b44,
+ 0x03cc2b42,
+ 0x03cc2b40,
+ 0x03cc2b3e,
+ 0x03cc2b3d,
+ 0x03cc2b3b,
+ 0x03c82b44,
+ 0x03c82b42,
+ 0x03c82b40,
+ 0x03c82b3e,
+ 0x03c82b3d,
+ 0x03c82b3b,
+ 0x03c82b39,
+ 0x03c82b38,
+ 0x03c82b36,
+ 0x03c82b34,
+ 0x03c42b44,
+ 0x03c42b42,
+ 0x03c42b40,
+ 0x03c42b3e,
+ 0x03c42b3d,
+ 0x03c42b3b,
+ 0x03c42b39,
+ 0x03c42b38,
+ 0x03c42b36,
+ 0x03c42b34,
+ 0x03c42b33,
+ 0x03c42b32,
+ 0x03c42b30,
+ 0x03c42b2f,
+ 0x03c42b2d,
+ 0x03c02b44,
+ 0x03c02b42,
+ 0x03c02b40,
+ 0x03c02b3e,
+ 0x03c02b3d,
+ 0x03c02b3b,
+ 0x03c02b39,
+ 0x03c02b38,
+ 0x03c02b36,
+ 0x03c02b34,
+ 0x03b02b44,
+ 0x03b02b42,
+ 0x03b02b40,
+ 0x03b02b3e,
+ 0x03b02b3d,
+ 0x03b02b3b,
+ 0x03b02b39,
+ 0x03b02b38,
+ 0x03b02b36,
+ 0x03b02b34,
+ 0x03b02b33,
+ 0x03b02b32,
+ 0x03b02b30,
+ 0x03b02b2f,
+ 0x03b02b2d,
+ 0x03a02b44,
+ 0x03a02b42,
+ 0x03a02b40,
+ 0x03a02b3e,
+ 0x03a02b3d,
+ 0x03a02b3b,
+ 0x03a02b39,
+ 0x03a02b38,
+ 0x03a02b36,
+ 0x03a02b34,
+ 0x03902b44,
+ 0x03902b42,
+ 0x03902b40,
+ 0x03902b3e,
+ 0x03902b3d,
+ 0x03902b3b,
+ 0x03902b39,
+ 0x03902b38,
+ 0x03902b36,
+ 0x03902b34,
+ 0x03902b33,
+ 0x03902b32,
+ 0x03902b30,
+ 0x03802b44,
+ 0x03802b42,
+ 0x03802b40,
+ 0x03802b3e,
+ 0x03802b3d,
+ 0x03802b3b,
+ 0x03802b39,
+ 0x03802b38,
+ 0x03802b36,
+ 0x03802b34,
+ 0x03802b33,
+ 0x03802b32,
+ 0x03802b30,
+ 0x03802b2f,
+ 0x03802b2d,
+ 0x03802b2c,
+ 0x03802b2b,
+ 0x03802b2a,
+ 0x03802b29,
+ 0x03802b27,
+ 0x03802b26,
+ 0x03802b25,
+ 0x03802b24,
+ 0x03802b23,
+ 0x03802b22,
+ 0x03802b21,
+ 0x03802b20,
+ 0x03802b1f,
+ 0x03802b1e,
+ 0x03802b1e,
+ 0x03802b1d,
+ 0x03802b1c,
+ 0x03802b1b,
+ 0x03802b1a,
+ 0x03802b1a,
+ 0x03802b19,
+ 0x03802b18,
+ 0x03802b18,
+ 0x03802b18,
+ 0x03802b18,
+ 0x03802b18,
+ 0x03802b18,
+ 0x03802b18,
+ 0x03802b18,
+ 0x03802b18,
+ 0x03802b18,
+ 0x03802b18,
+ 0x03802b18,
+ 0x00002b00,
+};
+
+static const u32 iq_lut_core0_rev0[] = {
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+};
+
+static const u32 iq_lut_core1_rev0[] = {
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+ 0x0000007f,
+};
+
+static const u16 loft_lut_core0_rev0[] = {
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+};
+
+static const u16 loft_lut_core1_rev0[] = {
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+ 0x0000,
+ 0x0101,
+ 0x0002,
+ 0x0103,
+};
+
+const struct phytbl_info mimophytbl_info_rev0_volatile[] = {
+ {&bdi_tbl_rev0, sizeof(bdi_tbl_rev0) / sizeof(bdi_tbl_rev0[0]), 21, 0,
+ 16}
+ ,
+ {&pltlut_tbl_rev0, sizeof(pltlut_tbl_rev0) / sizeof(pltlut_tbl_rev0[0]),
+ 20, 0, 32}
+ ,
+ {&gainctrl_lut_core0_rev0,
+ sizeof(gainctrl_lut_core0_rev0) / sizeof(gainctrl_lut_core0_rev0[0]),
+ 26, 192, 32}
+ ,
+ {&gainctrl_lut_core1_rev0,
+ sizeof(gainctrl_lut_core1_rev0) / sizeof(gainctrl_lut_core1_rev0[0]),
+ 27, 192, 32}
+ ,
+
+ {&est_pwr_lut_core0_rev0,
+ sizeof(est_pwr_lut_core0_rev0) / sizeof(est_pwr_lut_core0_rev0[0]), 26,
+ 0, 8}
+ ,
+ {&est_pwr_lut_core1_rev0,
+ sizeof(est_pwr_lut_core1_rev0) / sizeof(est_pwr_lut_core1_rev0[0]), 27,
+ 0, 8}
+ ,
+ {&adj_pwr_lut_core0_rev0,
+ sizeof(adj_pwr_lut_core0_rev0) / sizeof(adj_pwr_lut_core0_rev0[0]), 26,
+ 64, 8}
+ ,
+ {&adj_pwr_lut_core1_rev0,
+ sizeof(adj_pwr_lut_core1_rev0) / sizeof(adj_pwr_lut_core1_rev0[0]), 27,
+ 64, 8}
+ ,
+ {&iq_lut_core0_rev0,
+ sizeof(iq_lut_core0_rev0) / sizeof(iq_lut_core0_rev0[0]), 26, 320, 32}
+ ,
+ {&iq_lut_core1_rev0,
+ sizeof(iq_lut_core1_rev0) / sizeof(iq_lut_core1_rev0[0]), 27, 320, 32}
+ ,
+ {&loft_lut_core0_rev0,
+ sizeof(loft_lut_core0_rev0) / sizeof(loft_lut_core0_rev0[0]), 26, 448,
+ 16}
+ ,
+ {&loft_lut_core1_rev0,
+ sizeof(loft_lut_core1_rev0) / sizeof(loft_lut_core1_rev0[0]), 27, 448,
+ 16}
+ ,
+};
+
+const struct phytbl_info mimophytbl_info_rev0[] = {
+ {&frame_struct_rev0,
+ sizeof(frame_struct_rev0) / sizeof(frame_struct_rev0[0]), 10, 0, 32}
+ ,
+ {&frame_lut_rev0, sizeof(frame_lut_rev0) / sizeof(frame_lut_rev0[0]),
+ 24, 0, 8}
+ ,
+ {&tmap_tbl_rev0, sizeof(tmap_tbl_rev0) / sizeof(tmap_tbl_rev0[0]), 12,
+ 0, 32}
+ ,
+ {&tdtrn_tbl_rev0, sizeof(tdtrn_tbl_rev0) / sizeof(tdtrn_tbl_rev0[0]),
+ 14, 0, 32}
+ ,
+ {&intlv_tbl_rev0, sizeof(intlv_tbl_rev0) / sizeof(intlv_tbl_rev0[0]),
+ 13, 0, 32}
+ ,
+ {&pilot_tbl_rev0, sizeof(pilot_tbl_rev0) / sizeof(pilot_tbl_rev0[0]),
+ 11, 0, 16}
+ ,
+ {&tdi_tbl20_ant0_rev0,
+ sizeof(tdi_tbl20_ant0_rev0) / sizeof(tdi_tbl20_ant0_rev0[0]), 19, 128,
+ 32}
+ ,
+ {&tdi_tbl20_ant1_rev0,
+ sizeof(tdi_tbl20_ant1_rev0) / sizeof(tdi_tbl20_ant1_rev0[0]), 19, 256,
+ 32}
+ ,
+ {&tdi_tbl40_ant0_rev0,
+ sizeof(tdi_tbl40_ant0_rev0) / sizeof(tdi_tbl40_ant0_rev0[0]), 19, 640,
+ 32}
+ ,
+ {&tdi_tbl40_ant1_rev0,
+ sizeof(tdi_tbl40_ant1_rev0) / sizeof(tdi_tbl40_ant1_rev0[0]), 19, 768,
+ 32}
+ ,
+ {&chanest_tbl_rev0,
+ sizeof(chanest_tbl_rev0) / sizeof(chanest_tbl_rev0[0]), 22, 0, 32}
+ ,
+ {&mcs_tbl_rev0, sizeof(mcs_tbl_rev0) / sizeof(mcs_tbl_rev0[0]), 18, 0,
+ 8}
+ ,
+ {&noise_var_tbl0_rev0,
+ sizeof(noise_var_tbl0_rev0) / sizeof(noise_var_tbl0_rev0[0]), 16, 0,
+ 32}
+ ,
+ {&noise_var_tbl1_rev0,
+ sizeof(noise_var_tbl1_rev0) / sizeof(noise_var_tbl1_rev0[0]), 16, 128,
+ 32}
+ ,
+};
+
+const u32 mimophytbl_info_sz_rev0 =
+ sizeof(mimophytbl_info_rev0) / sizeof(mimophytbl_info_rev0[0]);
+const u32 mimophytbl_info_sz_rev0_volatile =
+ sizeof(mimophytbl_info_rev0_volatile) /
+ sizeof(mimophytbl_info_rev0_volatile[0]);
+
+static const u16 ant_swctrl_tbl_rev3[] = {
+ 0x0082,
+ 0x0082,
+ 0x0211,
+ 0x0222,
+ 0x0328,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0144,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0188,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0082,
+ 0x0082,
+ 0x0211,
+ 0x0222,
+ 0x0328,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0144,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0188,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+};
+
+static const u16 ant_swctrl_tbl_rev3_1[] = {
+ 0x0022,
+ 0x0022,
+ 0x0011,
+ 0x0022,
+ 0x0022,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0011,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0022,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0022,
+ 0x0022,
+ 0x0011,
+ 0x0022,
+ 0x0022,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0011,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0022,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+};
+
+static const u16 ant_swctrl_tbl_rev3_2[] = {
+ 0x0088,
+ 0x0088,
+ 0x0044,
+ 0x0088,
+ 0x0088,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0044,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0088,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0088,
+ 0x0088,
+ 0x0044,
+ 0x0088,
+ 0x0088,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0044,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0088,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+};
+
+static const u16 ant_swctrl_tbl_rev3_3[] = {
+ 0x022,
+ 0x022,
+ 0x011,
+ 0x022,
+ 0x000,
+ 0x000,
+ 0x000,
+ 0x000,
+ 0x011,
+ 0x000,
+ 0x000,
+ 0x000,
+ 0x022,
+ 0x000,
+ 0x000,
+ 0x3cc,
+ 0x022,
+ 0x022,
+ 0x011,
+ 0x022,
+ 0x000,
+ 0x000,
+ 0x000,
+ 0x000,
+ 0x011,
+ 0x000,
+ 0x000,
+ 0x000,
+ 0x022,
+ 0x000,
+ 0x000,
+ 0x3cc
+};
+
+static const u32 frame_struct_rev3[] = {
+ 0x08004a04,
+ 0x00100000,
+ 0x01000a05,
+ 0x00100020,
+ 0x09804506,
+ 0x00100030,
+ 0x09804507,
+ 0x00100030,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x08004a0c,
+ 0x00100004,
+ 0x01000a0d,
+ 0x00100024,
+ 0x0980450e,
+ 0x00100034,
+ 0x0980450f,
+ 0x00100034,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000a04,
+ 0x00100000,
+ 0x11008a05,
+ 0x00100020,
+ 0x1980c506,
+ 0x00100030,
+ 0x21810506,
+ 0x00100030,
+ 0x21810506,
+ 0x00100030,
+ 0x01800504,
+ 0x00100030,
+ 0x11808505,
+ 0x00100030,
+ 0x29814507,
+ 0x01100030,
+ 0x00000a04,
+ 0x00100000,
+ 0x11008a05,
+ 0x00100020,
+ 0x21810506,
+ 0x00100030,
+ 0x21810506,
+ 0x00100030,
+ 0x29814507,
+ 0x01100030,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000a0c,
+ 0x00100008,
+ 0x11008a0d,
+ 0x00100028,
+ 0x1980c50e,
+ 0x00100038,
+ 0x2181050e,
+ 0x00100038,
+ 0x2181050e,
+ 0x00100038,
+ 0x0180050c,
+ 0x00100038,
+ 0x1180850d,
+ 0x00100038,
+ 0x2981450f,
+ 0x01100038,
+ 0x00000a0c,
+ 0x00100008,
+ 0x11008a0d,
+ 0x00100028,
+ 0x2181050e,
+ 0x00100038,
+ 0x2181050e,
+ 0x00100038,
+ 0x2981450f,
+ 0x01100038,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x08004a04,
+ 0x00100000,
+ 0x01000a05,
+ 0x00100020,
+ 0x1980c506,
+ 0x00100030,
+ 0x1980c506,
+ 0x00100030,
+ 0x11808504,
+ 0x00100030,
+ 0x3981ca05,
+ 0x00100030,
+ 0x29814507,
+ 0x01100030,
+ 0x00000000,
+ 0x00000000,
+ 0x10008a04,
+ 0x00100000,
+ 0x3981ca05,
+ 0x00100030,
+ 0x1980c506,
+ 0x00100030,
+ 0x29814507,
+ 0x01100030,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x08004a0c,
+ 0x00100008,
+ 0x01000a0d,
+ 0x00100028,
+ 0x1980c50e,
+ 0x00100038,
+ 0x1980c50e,
+ 0x00100038,
+ 0x1180850c,
+ 0x00100038,
+ 0x3981ca0d,
+ 0x00100038,
+ 0x2981450f,
+ 0x01100038,
+ 0x00000000,
+ 0x00000000,
+ 0x10008a0c,
+ 0x00100008,
+ 0x3981ca0d,
+ 0x00100038,
+ 0x1980c50e,
+ 0x00100038,
+ 0x2981450f,
+ 0x01100038,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x40021404,
+ 0x00100000,
+ 0x02001405,
+ 0x00100040,
+ 0x0b004a06,
+ 0x01900060,
+ 0x13008a06,
+ 0x01900060,
+ 0x13008a06,
+ 0x01900060,
+ 0x43020a04,
+ 0x00100060,
+ 0x1b00ca05,
+ 0x00100060,
+ 0x23010a07,
+ 0x01500060,
+ 0x40021404,
+ 0x00100000,
+ 0x1a00d405,
+ 0x00100040,
+ 0x13008a06,
+ 0x01900060,
+ 0x13008a06,
+ 0x01900060,
+ 0x23010a07,
+ 0x01500060,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x4002140c,
+ 0x00100010,
+ 0x0200140d,
+ 0x00100050,
+ 0x0b004a0e,
+ 0x01900070,
+ 0x13008a0e,
+ 0x01900070,
+ 0x13008a0e,
+ 0x01900070,
+ 0x43020a0c,
+ 0x00100070,
+ 0x1b00ca0d,
+ 0x00100070,
+ 0x23010a0f,
+ 0x01500070,
+ 0x4002140c,
+ 0x00100010,
+ 0x1a00d40d,
+ 0x00100050,
+ 0x13008a0e,
+ 0x01900070,
+ 0x13008a0e,
+ 0x01900070,
+ 0x23010a0f,
+ 0x01500070,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x50029404,
+ 0x00100000,
+ 0x32019405,
+ 0x00100040,
+ 0x0b004a06,
+ 0x01900060,
+ 0x0b004a06,
+ 0x01900060,
+ 0x5b02ca04,
+ 0x00100060,
+ 0x3b01d405,
+ 0x00100060,
+ 0x23010a07,
+ 0x01500060,
+ 0x00000000,
+ 0x00000000,
+ 0x5802d404,
+ 0x00100000,
+ 0x3b01d405,
+ 0x00100060,
+ 0x0b004a06,
+ 0x01900060,
+ 0x23010a07,
+ 0x01500060,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x5002940c,
+ 0x00100010,
+ 0x3201940d,
+ 0x00100050,
+ 0x0b004a0e,
+ 0x01900070,
+ 0x0b004a0e,
+ 0x01900070,
+ 0x5b02ca0c,
+ 0x00100070,
+ 0x3b01d40d,
+ 0x00100070,
+ 0x23010a0f,
+ 0x01500070,
+ 0x00000000,
+ 0x00000000,
+ 0x5802d40c,
+ 0x00100010,
+ 0x3b01d40d,
+ 0x00100070,
+ 0x0b004a0e,
+ 0x01900070,
+ 0x23010a0f,
+ 0x01500070,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x40021404,
+ 0x000f4800,
+ 0x62031405,
+ 0x00100040,
+ 0x53028a06,
+ 0x01900060,
+ 0x53028a07,
+ 0x01900060,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x4002140c,
+ 0x000f4808,
+ 0x6203140d,
+ 0x00100048,
+ 0x53028a0e,
+ 0x01900068,
+ 0x53028a0f,
+ 0x01900068,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000a0c,
+ 0x00100004,
+ 0x11008a0d,
+ 0x00100024,
+ 0x1980c50e,
+ 0x00100034,
+ 0x2181050e,
+ 0x00100034,
+ 0x2181050e,
+ 0x00100034,
+ 0x0180050c,
+ 0x00100038,
+ 0x1180850d,
+ 0x00100038,
+ 0x1181850d,
+ 0x00100038,
+ 0x2981450f,
+ 0x01100038,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000a0c,
+ 0x00100008,
+ 0x11008a0d,
+ 0x00100028,
+ 0x2181050e,
+ 0x00100038,
+ 0x2181050e,
+ 0x00100038,
+ 0x1181850d,
+ 0x00100038,
+ 0x2981450f,
+ 0x01100038,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x08004a04,
+ 0x00100000,
+ 0x01000a05,
+ 0x00100020,
+ 0x0180c506,
+ 0x00100030,
+ 0x0180c506,
+ 0x00100030,
+ 0x2180c50c,
+ 0x00100030,
+ 0x49820a0d,
+ 0x0016a130,
+ 0x41824a0d,
+ 0x0016a130,
+ 0x2981450f,
+ 0x01100030,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x2000ca0c,
+ 0x00100000,
+ 0x49820a0d,
+ 0x0016a130,
+ 0x1980c50e,
+ 0x00100030,
+ 0x41824a0d,
+ 0x0016a130,
+ 0x2981450f,
+ 0x01100030,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x4002140c,
+ 0x00100008,
+ 0x0200140d,
+ 0x00100048,
+ 0x0b004a0e,
+ 0x01900068,
+ 0x13008a0e,
+ 0x01900068,
+ 0x13008a0e,
+ 0x01900068,
+ 0x43020a0c,
+ 0x00100070,
+ 0x1b00ca0d,
+ 0x00100070,
+ 0x1b014a0d,
+ 0x00100070,
+ 0x23010a0f,
+ 0x01500070,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x4002140c,
+ 0x00100010,
+ 0x1a00d40d,
+ 0x00100050,
+ 0x13008a0e,
+ 0x01900070,
+ 0x13008a0e,
+ 0x01900070,
+ 0x1b014a0d,
+ 0x00100070,
+ 0x23010a0f,
+ 0x01500070,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x50029404,
+ 0x00100000,
+ 0x32019405,
+ 0x00100040,
+ 0x03004a06,
+ 0x01900060,
+ 0x03004a06,
+ 0x01900060,
+ 0x6b030a0c,
+ 0x00100060,
+ 0x4b02140d,
+ 0x0016a160,
+ 0x4302540d,
+ 0x0016a160,
+ 0x23010a0f,
+ 0x01500060,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x6b03140c,
+ 0x00100060,
+ 0x4b02140d,
+ 0x0016a160,
+ 0x0b004a0e,
+ 0x01900060,
+ 0x4302540d,
+ 0x0016a160,
+ 0x23010a0f,
+ 0x01500060,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x40021404,
+ 0x00100000,
+ 0x1a00d405,
+ 0x00100040,
+ 0x53028a06,
+ 0x01900060,
+ 0x5b02ca06,
+ 0x01900060,
+ 0x5b02ca06,
+ 0x01900060,
+ 0x43020a04,
+ 0x00100060,
+ 0x1b00ca05,
+ 0x00100060,
+ 0x53028a07,
+ 0x0190c060,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x4002140c,
+ 0x00100010,
+ 0x1a00d40d,
+ 0x00100050,
+ 0x53028a0e,
+ 0x01900070,
+ 0x5b02ca0e,
+ 0x01900070,
+ 0x5b02ca0e,
+ 0x01900070,
+ 0x43020a0c,
+ 0x00100070,
+ 0x1b00ca0d,
+ 0x00100070,
+ 0x53028a0f,
+ 0x0190c070,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x40021404,
+ 0x00100000,
+ 0x1a00d405,
+ 0x00100040,
+ 0x5b02ca06,
+ 0x01900060,
+ 0x5b02ca06,
+ 0x01900060,
+ 0x53028a07,
+ 0x0190c060,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x4002140c,
+ 0x00100010,
+ 0x1a00d40d,
+ 0x00100050,
+ 0x5b02ca0e,
+ 0x01900070,
+ 0x5b02ca0e,
+ 0x01900070,
+ 0x53028a0f,
+ 0x0190c070,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+static const u16 pilot_tbl_rev3[] = {
+ 0xff08,
+ 0xff08,
+ 0xff08,
+ 0xff08,
+ 0xff08,
+ 0xff08,
+ 0xff08,
+ 0xff08,
+ 0x80d5,
+ 0x80d5,
+ 0x80d5,
+ 0x80d5,
+ 0x80d5,
+ 0x80d5,
+ 0x80d5,
+ 0x80d5,
+ 0xff0a,
+ 0xff82,
+ 0xffa0,
+ 0xff28,
+ 0xffff,
+ 0xffff,
+ 0xffff,
+ 0xffff,
+ 0xff82,
+ 0xffa0,
+ 0xff28,
+ 0xff0a,
+ 0xffff,
+ 0xffff,
+ 0xffff,
+ 0xffff,
+ 0xf83f,
+ 0xfa1f,
+ 0xfa97,
+ 0xfab5,
+ 0xf2bd,
+ 0xf0bf,
+ 0xffff,
+ 0xffff,
+ 0xf017,
+ 0xf815,
+ 0xf215,
+ 0xf095,
+ 0xf035,
+ 0xf01d,
+ 0xffff,
+ 0xffff,
+ 0xff08,
+ 0xff02,
+ 0xff80,
+ 0xff20,
+ 0xff08,
+ 0xff02,
+ 0xff80,
+ 0xff20,
+ 0xf01f,
+ 0xf817,
+ 0xfa15,
+ 0xf295,
+ 0xf0b5,
+ 0xf03d,
+ 0xffff,
+ 0xffff,
+ 0xf82a,
+ 0xfa0a,
+ 0xfa82,
+ 0xfaa0,
+ 0xf2a8,
+ 0xf0aa,
+ 0xffff,
+ 0xffff,
+ 0xf002,
+ 0xf800,
+ 0xf200,
+ 0xf080,
+ 0xf020,
+ 0xf008,
+ 0xffff,
+ 0xffff,
+ 0xf00a,
+ 0xf802,
+ 0xfa00,
+ 0xf280,
+ 0xf0a0,
+ 0xf028,
+ 0xffff,
+ 0xffff,
+};
+
+static const u32 tmap_tbl_rev3[] = {
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00000888,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0xf1111110,
+ 0x11111111,
+ 0x11f11111,
+ 0x00000111,
+ 0x11000000,
+ 0x1111f111,
+ 0x11111111,
+ 0x111111f1,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x000aa888,
+ 0x88880000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0xa1111110,
+ 0x11111111,
+ 0x11c11111,
+ 0x00000111,
+ 0x11000000,
+ 0x1111a111,
+ 0x11111111,
+ 0x111111a1,
+ 0xa2222220,
+ 0x22222222,
+ 0x22c22222,
+ 0x00000222,
+ 0x22000000,
+ 0x2222a222,
+ 0x22222222,
+ 0x222222a2,
+ 0xf1111110,
+ 0x11111111,
+ 0x11f11111,
+ 0x00011111,
+ 0x11110000,
+ 0x1111f111,
+ 0x11111111,
+ 0x111111f1,
+ 0xa8aa88a0,
+ 0xa88888a8,
+ 0xa8a8a88a,
+ 0x00088aaa,
+ 0xaaaa0000,
+ 0xa8a8aa88,
+ 0xa88aaaaa,
+ 0xaaaa8a8a,
+ 0xaaa8aaa0,
+ 0x8aaa8aaa,
+ 0xaa8a8a8a,
+ 0x000aaa88,
+ 0x8aaa0000,
+ 0xaaa8a888,
+ 0x8aa88a8a,
+ 0x8a88a888,
+ 0x08080a00,
+ 0x0a08080a,
+ 0x080a0a08,
+ 0x00080808,
+ 0x080a0000,
+ 0x080a0808,
+ 0x080a0808,
+ 0x0a0a0a08,
+ 0xa0a0a0a0,
+ 0x80a0a080,
+ 0x8080a0a0,
+ 0x00008080,
+ 0x80a00000,
+ 0x80a080a0,
+ 0xa080a0a0,
+ 0x8080a0a0,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x99999000,
+ 0x9b9b99bb,
+ 0x9bb99999,
+ 0x9999b9b9,
+ 0x9b99bb90,
+ 0x9bbbbb9b,
+ 0x9b9b9bb9,
+ 0x00000999,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00aaa888,
+ 0x22000000,
+ 0x2222b222,
+ 0x22222222,
+ 0x222222b2,
+ 0xb2222220,
+ 0x22222222,
+ 0x22d22222,
+ 0x00000222,
+ 0x11000000,
+ 0x1111a111,
+ 0x11111111,
+ 0x111111a1,
+ 0xa1111110,
+ 0x11111111,
+ 0x11c11111,
+ 0x00000111,
+ 0x33000000,
+ 0x3333b333,
+ 0x33333333,
+ 0x333333b3,
+ 0xb3333330,
+ 0x33333333,
+ 0x33d33333,
+ 0x00000333,
+ 0x22000000,
+ 0x2222a222,
+ 0x22222222,
+ 0x222222a2,
+ 0xa2222220,
+ 0x22222222,
+ 0x22c22222,
+ 0x00000222,
+ 0x99b99b00,
+ 0x9b9b99bb,
+ 0x9bb99999,
+ 0x9999b9b9,
+ 0x9b99bb99,
+ 0x9bbbbb9b,
+ 0x9b9b9bb9,
+ 0x00000999,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa88,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x08aaa888,
+ 0x22222200,
+ 0x2222f222,
+ 0x22222222,
+ 0x222222f2,
+ 0x22222222,
+ 0x22222222,
+ 0x22f22222,
+ 0x00000222,
+ 0x11000000,
+ 0x1111f111,
+ 0x11111111,
+ 0x11111111,
+ 0xf1111111,
+ 0x11111111,
+ 0x11f11111,
+ 0x01111111,
+ 0xbb9bb900,
+ 0xb9b9bb99,
+ 0xb99bbbbb,
+ 0xbbbb9b9b,
+ 0xb9bb99bb,
+ 0xb99999b9,
+ 0xb9b9b99b,
+ 0x00000bbb,
+ 0xaa000000,
+ 0xa8a8aa88,
+ 0xa88aaaaa,
+ 0xaaaa8a8a,
+ 0xa8aa88aa,
+ 0xa88888a8,
+ 0xa8a8a88a,
+ 0x0a888aaa,
+ 0xaa000000,
+ 0xa8a8aa88,
+ 0xa88aaaaa,
+ 0xaaaa8a8a,
+ 0xa8aa88a0,
+ 0xa88888a8,
+ 0xa8a8a88a,
+ 0x00000aaa,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00000888,
+ 0xbbbbbb00,
+ 0x999bbbbb,
+ 0x9bb99b9b,
+ 0xb9b9b9bb,
+ 0xb9b99bbb,
+ 0xb9b9b9bb,
+ 0xb9bb9b99,
+ 0x00000999,
+ 0x8a000000,
+ 0xaa88a888,
+ 0xa88888aa,
+ 0xa88a8a88,
+ 0xa88aa88a,
+ 0x88a8aaaa,
+ 0xa8aa8aaa,
+ 0x0888a88a,
+ 0x0b0b0b00,
+ 0x090b0b0b,
+ 0x0b090b0b,
+ 0x0909090b,
+ 0x09090b0b,
+ 0x09090b0b,
+ 0x09090b09,
+ 0x00000909,
+ 0x0a000000,
+ 0x0a080808,
+ 0x080a080a,
+ 0x080a0a08,
+ 0x080a080a,
+ 0x0808080a,
+ 0x0a0a0a08,
+ 0x0808080a,
+ 0xb0b0b000,
+ 0x9090b0b0,
+ 0x90b09090,
+ 0xb0b0b090,
+ 0xb0b090b0,
+ 0x90b0b0b0,
+ 0xb0b09090,
+ 0x00000090,
+ 0x80000000,
+ 0xa080a080,
+ 0xa08080a0,
+ 0xa0808080,
+ 0xa080a080,
+ 0x80a0a0a0,
+ 0xa0a080a0,
+ 0x00a0a0a0,
+ 0x22000000,
+ 0x2222f222,
+ 0x22222222,
+ 0x222222f2,
+ 0xf2222220,
+ 0x22222222,
+ 0x22f22222,
+ 0x00000222,
+ 0x11000000,
+ 0x1111f111,
+ 0x11111111,
+ 0x111111f1,
+ 0xf1111110,
+ 0x11111111,
+ 0x11f11111,
+ 0x00000111,
+ 0x33000000,
+ 0x3333f333,
+ 0x33333333,
+ 0x333333f3,
+ 0xf3333330,
+ 0x33333333,
+ 0x33f33333,
+ 0x00000333,
+ 0x22000000,
+ 0x2222f222,
+ 0x22222222,
+ 0x222222f2,
+ 0xf2222220,
+ 0x22222222,
+ 0x22f22222,
+ 0x00000222,
+ 0x99000000,
+ 0x9b9b99bb,
+ 0x9bb99999,
+ 0x9999b9b9,
+ 0x9b99bb90,
+ 0x9bbbbb9b,
+ 0x9b9b9bb9,
+ 0x00000999,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00000888,
+ 0x88888000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00000888,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00aaa888,
+ 0x88a88a00,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa88,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00000888,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa88,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x08aaa888,
+ 0x11000000,
+ 0x1111a111,
+ 0x11111111,
+ 0x111111a1,
+ 0xa1111110,
+ 0x11111111,
+ 0x11c11111,
+ 0x00000111,
+ 0x11000000,
+ 0x1111a111,
+ 0x11111111,
+ 0x111111a1,
+ 0xa1111110,
+ 0x11111111,
+ 0x11c11111,
+ 0x00000111,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00000888,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00000888,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+static const u32 intlv_tbl_rev3[] = {
+ 0x00802070,
+ 0x0671188d,
+ 0x0a60192c,
+ 0x0a300e46,
+ 0x00c1188d,
+ 0x080024d2,
+ 0x00000070,
+};
+
+static const u32 tdtrn_tbl_rev3[] = {
+ 0x061c061c,
+ 0x0050ee68,
+ 0xf592fe36,
+ 0xfe5212f6,
+ 0x00000c38,
+ 0xfe5212f6,
+ 0xf592fe36,
+ 0x0050ee68,
+ 0x061c061c,
+ 0xee680050,
+ 0xfe36f592,
+ 0x12f6fe52,
+ 0x0c380000,
+ 0x12f6fe52,
+ 0xfe36f592,
+ 0xee680050,
+ 0x061c061c,
+ 0x0050ee68,
+ 0xf592fe36,
+ 0xfe5212f6,
+ 0x00000c38,
+ 0xfe5212f6,
+ 0xf592fe36,
+ 0x0050ee68,
+ 0x061c061c,
+ 0xee680050,
+ 0xfe36f592,
+ 0x12f6fe52,
+ 0x0c380000,
+ 0x12f6fe52,
+ 0xfe36f592,
+ 0xee680050,
+ 0x05e305e3,
+ 0x004def0c,
+ 0xf5f3fe47,
+ 0xfe611246,
+ 0x00000bc7,
+ 0xfe611246,
+ 0xf5f3fe47,
+ 0x004def0c,
+ 0x05e305e3,
+ 0xef0c004d,
+ 0xfe47f5f3,
+ 0x1246fe61,
+ 0x0bc70000,
+ 0x1246fe61,
+ 0xfe47f5f3,
+ 0xef0c004d,
+ 0x05e305e3,
+ 0x004def0c,
+ 0xf5f3fe47,
+ 0xfe611246,
+ 0x00000bc7,
+ 0xfe611246,
+ 0xf5f3fe47,
+ 0x004def0c,
+ 0x05e305e3,
+ 0xef0c004d,
+ 0xfe47f5f3,
+ 0x1246fe61,
+ 0x0bc70000,
+ 0x1246fe61,
+ 0xfe47f5f3,
+ 0xef0c004d,
+ 0xfa58fa58,
+ 0xf895043b,
+ 0xff4c09c0,
+ 0xfbc6ffa8,
+ 0xfb84f384,
+ 0x0798f6f9,
+ 0x05760122,
+ 0x058409f6,
+ 0x0b500000,
+ 0x05b7f542,
+ 0x08860432,
+ 0x06ddfee7,
+ 0xfb84f384,
+ 0xf9d90664,
+ 0xf7e8025c,
+ 0x00fff7bd,
+ 0x05a805a8,
+ 0xf7bd00ff,
+ 0x025cf7e8,
+ 0x0664f9d9,
+ 0xf384fb84,
+ 0xfee706dd,
+ 0x04320886,
+ 0xf54205b7,
+ 0x00000b50,
+ 0x09f60584,
+ 0x01220576,
+ 0xf6f90798,
+ 0xf384fb84,
+ 0xffa8fbc6,
+ 0x09c0ff4c,
+ 0x043bf895,
+ 0x02d402d4,
+ 0x07de0270,
+ 0xfc96079c,
+ 0xf90afe94,
+ 0xfe00ff2c,
+ 0x02d4065d,
+ 0x092a0096,
+ 0x0014fbb8,
+ 0xfd2cfd2c,
+ 0x076afb3c,
+ 0x0096f752,
+ 0xf991fd87,
+ 0xfb2c0200,
+ 0xfeb8f960,
+ 0x08e0fc96,
+ 0x049802a8,
+ 0xfd2cfd2c,
+ 0x02a80498,
+ 0xfc9608e0,
+ 0xf960feb8,
+ 0x0200fb2c,
+ 0xfd87f991,
+ 0xf7520096,
+ 0xfb3c076a,
+ 0xfd2cfd2c,
+ 0xfbb80014,
+ 0x0096092a,
+ 0x065d02d4,
+ 0xff2cfe00,
+ 0xfe94f90a,
+ 0x079cfc96,
+ 0x027007de,
+ 0x02d402d4,
+ 0x027007de,
+ 0x079cfc96,
+ 0xfe94f90a,
+ 0xff2cfe00,
+ 0x065d02d4,
+ 0x0096092a,
+ 0xfbb80014,
+ 0xfd2cfd2c,
+ 0xfb3c076a,
+ 0xf7520096,
+ 0xfd87f991,
+ 0x0200fb2c,
+ 0xf960feb8,
+ 0xfc9608e0,
+ 0x02a80498,
+ 0xfd2cfd2c,
+ 0x049802a8,
+ 0x08e0fc96,
+ 0xfeb8f960,
+ 0xfb2c0200,
+ 0xf991fd87,
+ 0x0096f752,
+ 0x076afb3c,
+ 0xfd2cfd2c,
+ 0x0014fbb8,
+ 0x092a0096,
+ 0x02d4065d,
+ 0xfe00ff2c,
+ 0xf90afe94,
+ 0xfc96079c,
+ 0x07de0270,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x062a0000,
+ 0xfefa0759,
+ 0x08b80908,
+ 0xf396fc2d,
+ 0xf9d6045c,
+ 0xfc4ef608,
+ 0xf748f596,
+ 0x07b207bf,
+ 0x062a062a,
+ 0xf84ef841,
+ 0xf748f596,
+ 0x03b209f8,
+ 0xf9d6045c,
+ 0x0c6a03d3,
+ 0x08b80908,
+ 0x0106f8a7,
+ 0x062a0000,
+ 0xfefaf8a7,
+ 0x08b8f6f8,
+ 0xf39603d3,
+ 0xf9d6fba4,
+ 0xfc4e09f8,
+ 0xf7480a6a,
+ 0x07b2f841,
+ 0x062af9d6,
+ 0xf84e07bf,
+ 0xf7480a6a,
+ 0x03b2f608,
+ 0xf9d6fba4,
+ 0x0c6afc2d,
+ 0x08b8f6f8,
+ 0x01060759,
+ 0x062a0000,
+ 0xfefa0759,
+ 0x08b80908,
+ 0xf396fc2d,
+ 0xf9d6045c,
+ 0xfc4ef608,
+ 0xf748f596,
+ 0x07b207bf,
+ 0x062a062a,
+ 0xf84ef841,
+ 0xf748f596,
+ 0x03b209f8,
+ 0xf9d6045c,
+ 0x0c6a03d3,
+ 0x08b80908,
+ 0x0106f8a7,
+ 0x062a0000,
+ 0xfefaf8a7,
+ 0x08b8f6f8,
+ 0xf39603d3,
+ 0xf9d6fba4,
+ 0xfc4e09f8,
+ 0xf7480a6a,
+ 0x07b2f841,
+ 0x062af9d6,
+ 0xf84e07bf,
+ 0xf7480a6a,
+ 0x03b2f608,
+ 0xf9d6fba4,
+ 0x0c6afc2d,
+ 0x08b8f6f8,
+ 0x01060759,
+ 0x061c061c,
+ 0xff30009d,
+ 0xffb21141,
+ 0xfd87fb54,
+ 0xf65dfe59,
+ 0x02eef99e,
+ 0x0166f03c,
+ 0xfff809b6,
+ 0x000008a4,
+ 0x000af42b,
+ 0x00eff577,
+ 0xfa840bf2,
+ 0xfc02ff51,
+ 0x08260f67,
+ 0xfff0036f,
+ 0x0842f9c3,
+ 0x00000000,
+ 0x063df7be,
+ 0xfc910010,
+ 0xf099f7da,
+ 0x00af03fe,
+ 0xf40e057c,
+ 0x0a89ff11,
+ 0x0bd5fff6,
+ 0xf75c0000,
+ 0xf64a0008,
+ 0x0fc4fe9a,
+ 0x0662fd12,
+ 0x01a709a3,
+ 0x04ac0279,
+ 0xeebf004e,
+ 0xff6300d0,
+ 0xf9e4f9e4,
+ 0x00d0ff63,
+ 0x004eeebf,
+ 0x027904ac,
+ 0x09a301a7,
+ 0xfd120662,
+ 0xfe9a0fc4,
+ 0x0008f64a,
+ 0x0000f75c,
+ 0xfff60bd5,
+ 0xff110a89,
+ 0x057cf40e,
+ 0x03fe00af,
+ 0xf7daf099,
+ 0x0010fc91,
+ 0xf7be063d,
+ 0x00000000,
+ 0xf9c30842,
+ 0x036ffff0,
+ 0x0f670826,
+ 0xff51fc02,
+ 0x0bf2fa84,
+ 0xf57700ef,
+ 0xf42b000a,
+ 0x08a40000,
+ 0x09b6fff8,
+ 0xf03c0166,
+ 0xf99e02ee,
+ 0xfe59f65d,
+ 0xfb54fd87,
+ 0x1141ffb2,
+ 0x009dff30,
+ 0x05e30000,
+ 0xff060705,
+ 0x085408a0,
+ 0xf425fc59,
+ 0xfa1d042a,
+ 0xfc78f67a,
+ 0xf7acf60e,
+ 0x075a0766,
+ 0x05e305e3,
+ 0xf8a6f89a,
+ 0xf7acf60e,
+ 0x03880986,
+ 0xfa1d042a,
+ 0x0bdb03a7,
+ 0x085408a0,
+ 0x00faf8fb,
+ 0x05e30000,
+ 0xff06f8fb,
+ 0x0854f760,
+ 0xf42503a7,
+ 0xfa1dfbd6,
+ 0xfc780986,
+ 0xf7ac09f2,
+ 0x075af89a,
+ 0x05e3fa1d,
+ 0xf8a60766,
+ 0xf7ac09f2,
+ 0x0388f67a,
+ 0xfa1dfbd6,
+ 0x0bdbfc59,
+ 0x0854f760,
+ 0x00fa0705,
+ 0x05e30000,
+ 0xff060705,
+ 0x085408a0,
+ 0xf425fc59,
+ 0xfa1d042a,
+ 0xfc78f67a,
+ 0xf7acf60e,
+ 0x075a0766,
+ 0x05e305e3,
+ 0xf8a6f89a,
+ 0xf7acf60e,
+ 0x03880986,
+ 0xfa1d042a,
+ 0x0bdb03a7,
+ 0x085408a0,
+ 0x00faf8fb,
+ 0x05e30000,
+ 0xff06f8fb,
+ 0x0854f760,
+ 0xf42503a7,
+ 0xfa1dfbd6,
+ 0xfc780986,
+ 0xf7ac09f2,
+ 0x075af89a,
+ 0x05e3fa1d,
+ 0xf8a60766,
+ 0xf7ac09f2,
+ 0x0388f67a,
+ 0xfa1dfbd6,
+ 0x0bdbfc59,
+ 0x0854f760,
+ 0x00fa0705,
+ 0xfa58fa58,
+ 0xf8f0fe00,
+ 0x0448073d,
+ 0xfdc9fe46,
+ 0xf9910258,
+ 0x089d0407,
+ 0xfd5cf71a,
+ 0x02affde0,
+ 0x083e0496,
+ 0xff5a0740,
+ 0xff7afd97,
+ 0x00fe01f1,
+ 0x0009082e,
+ 0xfa94ff75,
+ 0xfecdf8ea,
+ 0xffb0f693,
+ 0xfd2cfa58,
+ 0x0433ff16,
+ 0xfba405dd,
+ 0xfa610341,
+ 0x06a606cb,
+ 0x0039fd2d,
+ 0x0677fa97,
+ 0x01fa05e0,
+ 0xf896003e,
+ 0x075a068b,
+ 0x012cfc3e,
+ 0xfa23f98d,
+ 0xfc7cfd43,
+ 0xff90fc0d,
+ 0x01c10982,
+ 0x00c601d6,
+ 0xfd2cfd2c,
+ 0x01d600c6,
+ 0x098201c1,
+ 0xfc0dff90,
+ 0xfd43fc7c,
+ 0xf98dfa23,
+ 0xfc3e012c,
+ 0x068b075a,
+ 0x003ef896,
+ 0x05e001fa,
+ 0xfa970677,
+ 0xfd2d0039,
+ 0x06cb06a6,
+ 0x0341fa61,
+ 0x05ddfba4,
+ 0xff160433,
+ 0xfa58fd2c,
+ 0xf693ffb0,
+ 0xf8eafecd,
+ 0xff75fa94,
+ 0x082e0009,
+ 0x01f100fe,
+ 0xfd97ff7a,
+ 0x0740ff5a,
+ 0x0496083e,
+ 0xfde002af,
+ 0xf71afd5c,
+ 0x0407089d,
+ 0x0258f991,
+ 0xfe46fdc9,
+ 0x073d0448,
+ 0xfe00f8f0,
+ 0xfd2cfd2c,
+ 0xfce00500,
+ 0xfc09fddc,
+ 0xfe680157,
+ 0x04c70571,
+ 0xfc3aff21,
+ 0xfcd70228,
+ 0x056d0277,
+ 0x0200fe00,
+ 0x0022f927,
+ 0xfe3c032b,
+ 0xfc44ff3c,
+ 0x03e9fbdb,
+ 0x04570313,
+ 0x04c9ff5c,
+ 0x000d03b8,
+ 0xfa580000,
+ 0xfbe900d2,
+ 0xf9d0fe0b,
+ 0x0125fdf9,
+ 0x042501bf,
+ 0x0328fa2b,
+ 0xffa902f0,
+ 0xfa250157,
+ 0x0200fe00,
+ 0x03740438,
+ 0xff0405fd,
+ 0x030cfe52,
+ 0x0037fb39,
+ 0xff6904c5,
+ 0x04f8fd23,
+ 0xfd31fc1b,
+ 0xfd2cfd2c,
+ 0xfc1bfd31,
+ 0xfd2304f8,
+ 0x04c5ff69,
+ 0xfb390037,
+ 0xfe52030c,
+ 0x05fdff04,
+ 0x04380374,
+ 0xfe000200,
+ 0x0157fa25,
+ 0x02f0ffa9,
+ 0xfa2b0328,
+ 0x01bf0425,
+ 0xfdf90125,
+ 0xfe0bf9d0,
+ 0x00d2fbe9,
+ 0x0000fa58,
+ 0x03b8000d,
+ 0xff5c04c9,
+ 0x03130457,
+ 0xfbdb03e9,
+ 0xff3cfc44,
+ 0x032bfe3c,
+ 0xf9270022,
+ 0xfe000200,
+ 0x0277056d,
+ 0x0228fcd7,
+ 0xff21fc3a,
+ 0x057104c7,
+ 0x0157fe68,
+ 0xfddcfc09,
+ 0x0500fce0,
+ 0xfd2cfd2c,
+ 0x0500fce0,
+ 0xfddcfc09,
+ 0x0157fe68,
+ 0x057104c7,
+ 0xff21fc3a,
+ 0x0228fcd7,
+ 0x0277056d,
+ 0xfe000200,
+ 0xf9270022,
+ 0x032bfe3c,
+ 0xff3cfc44,
+ 0xfbdb03e9,
+ 0x03130457,
+ 0xff5c04c9,
+ 0x03b8000d,
+ 0x0000fa58,
+ 0x00d2fbe9,
+ 0xfe0bf9d0,
+ 0xfdf90125,
+ 0x01bf0425,
+ 0xfa2b0328,
+ 0x02f0ffa9,
+ 0x0157fa25,
+ 0xfe000200,
+ 0x04380374,
+ 0x05fdff04,
+ 0xfe52030c,
+ 0xfb390037,
+ 0x04c5ff69,
+ 0xfd2304f8,
+ 0xfc1bfd31,
+ 0xfd2cfd2c,
+ 0xfd31fc1b,
+ 0x04f8fd23,
+ 0xff6904c5,
+ 0x0037fb39,
+ 0x030cfe52,
+ 0xff0405fd,
+ 0x03740438,
+ 0x0200fe00,
+ 0xfa250157,
+ 0xffa902f0,
+ 0x0328fa2b,
+ 0x042501bf,
+ 0x0125fdf9,
+ 0xf9d0fe0b,
+ 0xfbe900d2,
+ 0xfa580000,
+ 0x000d03b8,
+ 0x04c9ff5c,
+ 0x04570313,
+ 0x03e9fbdb,
+ 0xfc44ff3c,
+ 0xfe3c032b,
+ 0x0022f927,
+ 0x0200fe00,
+ 0x056d0277,
+ 0xfcd70228,
+ 0xfc3aff21,
+ 0x04c70571,
+ 0xfe680157,
+ 0xfc09fddc,
+ 0xfce00500,
+ 0x05a80000,
+ 0xff1006be,
+ 0x0800084a,
+ 0xf49cfc7e,
+ 0xfa580400,
+ 0xfc9cf6da,
+ 0xf800f672,
+ 0x0710071c,
+ 0x05a805a8,
+ 0xf8f0f8e4,
+ 0xf800f672,
+ 0x03640926,
+ 0xfa580400,
+ 0x0b640382,
+ 0x0800084a,
+ 0x00f0f942,
+ 0x05a80000,
+ 0xff10f942,
+ 0x0800f7b6,
+ 0xf49c0382,
+ 0xfa58fc00,
+ 0xfc9c0926,
+ 0xf800098e,
+ 0x0710f8e4,
+ 0x05a8fa58,
+ 0xf8f0071c,
+ 0xf800098e,
+ 0x0364f6da,
+ 0xfa58fc00,
+ 0x0b64fc7e,
+ 0x0800f7b6,
+ 0x00f006be,
+ 0x05a80000,
+ 0xff1006be,
+ 0x0800084a,
+ 0xf49cfc7e,
+ 0xfa580400,
+ 0xfc9cf6da,
+ 0xf800f672,
+ 0x0710071c,
+ 0x05a805a8,
+ 0xf8f0f8e4,
+ 0xf800f672,
+ 0x03640926,
+ 0xfa580400,
+ 0x0b640382,
+ 0x0800084a,
+ 0x00f0f942,
+ 0x05a80000,
+ 0xff10f942,
+ 0x0800f7b6,
+ 0xf49c0382,
+ 0xfa58fc00,
+ 0xfc9c0926,
+ 0xf800098e,
+ 0x0710f8e4,
+ 0x05a8fa58,
+ 0xf8f0071c,
+ 0xf800098e,
+ 0x0364f6da,
+ 0xfa58fc00,
+ 0x0b64fc7e,
+ 0x0800f7b6,
+ 0x00f006be,
+};
+
+const u32 noise_var_tbl_rev3[] = {
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+ 0x02110211,
+ 0x0000014d,
+};
+
+static const u16 mcs_tbl_rev3[] = {
+ 0x0000,
+ 0x0008,
+ 0x000a,
+ 0x0010,
+ 0x0012,
+ 0x0019,
+ 0x001a,
+ 0x001c,
+ 0x0080,
+ 0x0088,
+ 0x008a,
+ 0x0090,
+ 0x0092,
+ 0x0099,
+ 0x009a,
+ 0x009c,
+ 0x0100,
+ 0x0108,
+ 0x010a,
+ 0x0110,
+ 0x0112,
+ 0x0119,
+ 0x011a,
+ 0x011c,
+ 0x0180,
+ 0x0188,
+ 0x018a,
+ 0x0190,
+ 0x0192,
+ 0x0199,
+ 0x019a,
+ 0x019c,
+ 0x0000,
+ 0x0098,
+ 0x00a0,
+ 0x00a8,
+ 0x009a,
+ 0x00a2,
+ 0x00aa,
+ 0x0120,
+ 0x0128,
+ 0x0128,
+ 0x0130,
+ 0x0138,
+ 0x0138,
+ 0x0140,
+ 0x0122,
+ 0x012a,
+ 0x012a,
+ 0x0132,
+ 0x013a,
+ 0x013a,
+ 0x0142,
+ 0x01a8,
+ 0x01b0,
+ 0x01b8,
+ 0x01b0,
+ 0x01b8,
+ 0x01c0,
+ 0x01c8,
+ 0x01c0,
+ 0x01c8,
+ 0x01d0,
+ 0x01d0,
+ 0x01d8,
+ 0x01aa,
+ 0x01b2,
+ 0x01ba,
+ 0x01b2,
+ 0x01ba,
+ 0x01c2,
+ 0x01ca,
+ 0x01c2,
+ 0x01ca,
+ 0x01d2,
+ 0x01d2,
+ 0x01da,
+ 0x0001,
+ 0x0002,
+ 0x0004,
+ 0x0009,
+ 0x000c,
+ 0x0011,
+ 0x0014,
+ 0x0018,
+ 0x0020,
+ 0x0021,
+ 0x0022,
+ 0x0024,
+ 0x0081,
+ 0x0082,
+ 0x0084,
+ 0x0089,
+ 0x008c,
+ 0x0091,
+ 0x0094,
+ 0x0098,
+ 0x00a0,
+ 0x00a1,
+ 0x00a2,
+ 0x00a4,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+ 0x0007,
+};
+
+static const u32 tdi_tbl20_ant0_rev3[] = {
+ 0x00091226,
+ 0x000a1429,
+ 0x000b56ad,
+ 0x000c58b0,
+ 0x000d5ab3,
+ 0x000e9cb6,
+ 0x000f9eba,
+ 0x0000c13d,
+ 0x00020301,
+ 0x00030504,
+ 0x00040708,
+ 0x0005090b,
+ 0x00064b8e,
+ 0x00095291,
+ 0x000a5494,
+ 0x000b9718,
+ 0x000c9927,
+ 0x000d9b2a,
+ 0x000edd2e,
+ 0x000fdf31,
+ 0x000101b4,
+ 0x000243b7,
+ 0x000345bb,
+ 0x000447be,
+ 0x00058982,
+ 0x00068c05,
+ 0x00099309,
+ 0x000a950c,
+ 0x000bd78f,
+ 0x000cd992,
+ 0x000ddb96,
+ 0x000f1d99,
+ 0x00005fa8,
+ 0x0001422c,
+ 0x0002842f,
+ 0x00038632,
+ 0x00048835,
+ 0x0005ca38,
+ 0x0006ccbc,
+ 0x0009d3bf,
+ 0x000b1603,
+ 0x000c1806,
+ 0x000d1a0a,
+ 0x000e1c0d,
+ 0x000f5e10,
+ 0x00008093,
+ 0x00018297,
+ 0x0002c49a,
+ 0x0003c680,
+ 0x0004c880,
+ 0x00060b00,
+ 0x00070d00,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+static const u32 tdi_tbl20_ant1_rev3[] = {
+ 0x00014b26,
+ 0x00028d29,
+ 0x000393ad,
+ 0x00049630,
+ 0x0005d833,
+ 0x0006da36,
+ 0x00099c3a,
+ 0x000a9e3d,
+ 0x000bc081,
+ 0x000cc284,
+ 0x000dc488,
+ 0x000f068b,
+ 0x0000488e,
+ 0x00018b91,
+ 0x0002d214,
+ 0x0003d418,
+ 0x0004d6a7,
+ 0x000618aa,
+ 0x00071aae,
+ 0x0009dcb1,
+ 0x000b1eb4,
+ 0x000c0137,
+ 0x000d033b,
+ 0x000e053e,
+ 0x000f4702,
+ 0x00008905,
+ 0x00020c09,
+ 0x0003128c,
+ 0x0004148f,
+ 0x00051712,
+ 0x00065916,
+ 0x00091b19,
+ 0x000a1d28,
+ 0x000b5f2c,
+ 0x000c41af,
+ 0x000d43b2,
+ 0x000e85b5,
+ 0x000f87b8,
+ 0x0000c9bc,
+ 0x00024cbf,
+ 0x00035303,
+ 0x00045506,
+ 0x0005978a,
+ 0x0006998d,
+ 0x00095b90,
+ 0x000a5d93,
+ 0x000b9f97,
+ 0x000c821a,
+ 0x000d8400,
+ 0x000ec600,
+ 0x000fc800,
+ 0x00010a00,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+static const u32 tdi_tbl40_ant0_rev3[] = {
+ 0x0011a346,
+ 0x00136ccf,
+ 0x0014f5d9,
+ 0x001641e2,
+ 0x0017cb6b,
+ 0x00195475,
+ 0x001b2383,
+ 0x001cad0c,
+ 0x001e7616,
+ 0x0000821f,
+ 0x00020ba8,
+ 0x0003d4b2,
+ 0x00056447,
+ 0x00072dd0,
+ 0x0008b6da,
+ 0x000a02e3,
+ 0x000b8c6c,
+ 0x000d15f6,
+ 0x0011e484,
+ 0x0013ae0d,
+ 0x00153717,
+ 0x00168320,
+ 0x00180ca9,
+ 0x00199633,
+ 0x001b6548,
+ 0x001ceed1,
+ 0x001eb7db,
+ 0x0000c3e4,
+ 0x00024d6d,
+ 0x000416f7,
+ 0x0005a585,
+ 0x00076f0f,
+ 0x0008f818,
+ 0x000a4421,
+ 0x000bcdab,
+ 0x000d9734,
+ 0x00122649,
+ 0x0013efd2,
+ 0x001578dc,
+ 0x0016c4e5,
+ 0x00184e6e,
+ 0x001a17f8,
+ 0x001ba686,
+ 0x001d3010,
+ 0x001ef999,
+ 0x00010522,
+ 0x00028eac,
+ 0x00045835,
+ 0x0005e74a,
+ 0x0007b0d3,
+ 0x00093a5d,
+ 0x000a85e6,
+ 0x000c0f6f,
+ 0x000dd8f9,
+ 0x00126787,
+ 0x00143111,
+ 0x0015ba9a,
+ 0x00170623,
+ 0x00188fad,
+ 0x001a5936,
+ 0x001be84b,
+ 0x001db1d4,
+ 0x001f3b5e,
+ 0x000146e7,
+ 0x00031070,
+ 0x000499fa,
+ 0x00062888,
+ 0x0007f212,
+ 0x00097b9b,
+ 0x000ac7a4,
+ 0x000c50ae,
+ 0x000e1a37,
+ 0x0012a94c,
+ 0x001472d5,
+ 0x0015fc5f,
+ 0x00174868,
+ 0x0018d171,
+ 0x001a9afb,
+ 0x001c2989,
+ 0x001df313,
+ 0x001f7c9c,
+ 0x000188a5,
+ 0x000351af,
+ 0x0004db38,
+ 0x0006aa4d,
+ 0x000833d7,
+ 0x0009bd60,
+ 0x000b0969,
+ 0x000c9273,
+ 0x000e5bfc,
+ 0x00132a8a,
+ 0x0014b414,
+ 0x00163d9d,
+ 0x001789a6,
+ 0x001912b0,
+ 0x001adc39,
+ 0x001c6bce,
+ 0x001e34d8,
+ 0x001fbe61,
+ 0x0001ca6a,
+ 0x00039374,
+ 0x00051cfd,
+ 0x0006ec0b,
+ 0x00087515,
+ 0x0009fe9e,
+ 0x000b4aa7,
+ 0x000cd3b1,
+ 0x000e9d3a,
+ 0x00000000,
+ 0x00000000,
+};
+
+static const u32 tdi_tbl40_ant1_rev3[] = {
+ 0x001edb36,
+ 0x000129ca,
+ 0x0002b353,
+ 0x00047cdd,
+ 0x0005c8e6,
+ 0x000791ef,
+ 0x00091bf9,
+ 0x000aaa07,
+ 0x000c3391,
+ 0x000dfd1a,
+ 0x00120923,
+ 0x0013d22d,
+ 0x00155c37,
+ 0x0016eacb,
+ 0x00187454,
+ 0x001a3dde,
+ 0x001b89e7,
+ 0x001d12f0,
+ 0x001f1cfa,
+ 0x00016b88,
+ 0x00033492,
+ 0x0004be1b,
+ 0x00060a24,
+ 0x0007d32e,
+ 0x00095d38,
+ 0x000aec4c,
+ 0x000c7555,
+ 0x000e3edf,
+ 0x00124ae8,
+ 0x001413f1,
+ 0x0015a37b,
+ 0x00172c89,
+ 0x0018b593,
+ 0x001a419c,
+ 0x001bcb25,
+ 0x001d942f,
+ 0x001f63b9,
+ 0x0001ad4d,
+ 0x00037657,
+ 0x0004c260,
+ 0x00068be9,
+ 0x000814f3,
+ 0x0009a47c,
+ 0x000b2d8a,
+ 0x000cb694,
+ 0x000e429d,
+ 0x00128c26,
+ 0x001455b0,
+ 0x0015e4ba,
+ 0x00176e4e,
+ 0x0018f758,
+ 0x001a8361,
+ 0x001c0cea,
+ 0x001dd674,
+ 0x001fa57d,
+ 0x0001ee8b,
+ 0x0003b795,
+ 0x0005039e,
+ 0x0006cd27,
+ 0x000856b1,
+ 0x0009e5c6,
+ 0x000b6f4f,
+ 0x000cf859,
+ 0x000e8462,
+ 0x00130deb,
+ 0x00149775,
+ 0x00162603,
+ 0x0017af8c,
+ 0x00193896,
+ 0x001ac49f,
+ 0x001c4e28,
+ 0x001e17b2,
+ 0x0000a6c7,
+ 0x00023050,
+ 0x0003f9da,
+ 0x00054563,
+ 0x00070eec,
+ 0x00089876,
+ 0x000a2704,
+ 0x000bb08d,
+ 0x000d3a17,
+ 0x001185a0,
+ 0x00134f29,
+ 0x0014d8b3,
+ 0x001667c8,
+ 0x0017f151,
+ 0x00197adb,
+ 0x001b0664,
+ 0x001c8fed,
+ 0x001e5977,
+ 0x0000e805,
+ 0x0002718f,
+ 0x00043b18,
+ 0x000586a1,
+ 0x0007502b,
+ 0x0008d9b4,
+ 0x000a68c9,
+ 0x000bf252,
+ 0x000dbbdc,
+ 0x0011c7e5,
+ 0x001390ee,
+ 0x00151a78,
+ 0x0016a906,
+ 0x00183290,
+ 0x0019bc19,
+ 0x001b4822,
+ 0x001cd12c,
+ 0x001e9ab5,
+ 0x00000000,
+ 0x00000000,
+};
+
+static const u32 pltlut_tbl_rev3[] = {
+ 0x76540213,
+ 0x62407351,
+ 0x76543210,
+ 0x76540213,
+ 0x76540213,
+ 0x76430521,
+};
+
+static const u32 chanest_tbl_rev3[] = {
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x44444444,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+ 0x10101010,
+};
+
+static const u8 frame_lut_rev3[] = {
+ 0x02,
+ 0x04,
+ 0x14,
+ 0x14,
+ 0x03,
+ 0x05,
+ 0x16,
+ 0x16,
+ 0x0a,
+ 0x0c,
+ 0x1c,
+ 0x1c,
+ 0x0b,
+ 0x0d,
+ 0x1e,
+ 0x1e,
+ 0x06,
+ 0x08,
+ 0x18,
+ 0x18,
+ 0x07,
+ 0x09,
+ 0x1a,
+ 0x1a,
+ 0x0e,
+ 0x10,
+ 0x20,
+ 0x28,
+ 0x0f,
+ 0x11,
+ 0x22,
+ 0x2a,
+};
+
+static const u8 est_pwr_lut_core0_rev3[] = {
+ 0x55,
+ 0x54,
+ 0x54,
+ 0x53,
+ 0x52,
+ 0x52,
+ 0x51,
+ 0x51,
+ 0x50,
+ 0x4f,
+ 0x4f,
+ 0x4e,
+ 0x4e,
+ 0x4d,
+ 0x4c,
+ 0x4c,
+ 0x4b,
+ 0x4a,
+ 0x49,
+ 0x49,
+ 0x48,
+ 0x47,
+ 0x46,
+ 0x46,
+ 0x45,
+ 0x44,
+ 0x43,
+ 0x42,
+ 0x41,
+ 0x40,
+ 0x40,
+ 0x3f,
+ 0x3e,
+ 0x3d,
+ 0x3c,
+ 0x3a,
+ 0x39,
+ 0x38,
+ 0x37,
+ 0x36,
+ 0x35,
+ 0x33,
+ 0x32,
+ 0x31,
+ 0x2f,
+ 0x2e,
+ 0x2c,
+ 0x2b,
+ 0x29,
+ 0x27,
+ 0x25,
+ 0x23,
+ 0x21,
+ 0x1f,
+ 0x1d,
+ 0x1a,
+ 0x18,
+ 0x15,
+ 0x12,
+ 0x0e,
+ 0x0b,
+ 0x07,
+ 0x02,
+ 0xfd,
+};
+
+static const u8 est_pwr_lut_core1_rev3[] = {
+ 0x55,
+ 0x54,
+ 0x54,
+ 0x53,
+ 0x52,
+ 0x52,
+ 0x51,
+ 0x51,
+ 0x50,
+ 0x4f,
+ 0x4f,
+ 0x4e,
+ 0x4e,
+ 0x4d,
+ 0x4c,
+ 0x4c,
+ 0x4b,
+ 0x4a,
+ 0x49,
+ 0x49,
+ 0x48,
+ 0x47,
+ 0x46,
+ 0x46,
+ 0x45,
+ 0x44,
+ 0x43,
+ 0x42,
+ 0x41,
+ 0x40,
+ 0x40,
+ 0x3f,
+ 0x3e,
+ 0x3d,
+ 0x3c,
+ 0x3a,
+ 0x39,
+ 0x38,
+ 0x37,
+ 0x36,
+ 0x35,
+ 0x33,
+ 0x32,
+ 0x31,
+ 0x2f,
+ 0x2e,
+ 0x2c,
+ 0x2b,
+ 0x29,
+ 0x27,
+ 0x25,
+ 0x23,
+ 0x21,
+ 0x1f,
+ 0x1d,
+ 0x1a,
+ 0x18,
+ 0x15,
+ 0x12,
+ 0x0e,
+ 0x0b,
+ 0x07,
+ 0x02,
+ 0xfd,
+};
+
+static const u8 adj_pwr_lut_core0_rev3[] = {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+};
+
+static const u8 adj_pwr_lut_core1_rev3[] = {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+};
+
+static const u32 gainctrl_lut_core0_rev3[] = {
+ 0x5bf70044,
+ 0x5bf70042,
+ 0x5bf70040,
+ 0x5bf7003e,
+ 0x5bf7003c,
+ 0x5bf7003b,
+ 0x5bf70039,
+ 0x5bf70037,
+ 0x5bf70036,
+ 0x5bf70034,
+ 0x5bf70033,
+ 0x5bf70031,
+ 0x5bf70030,
+ 0x5ba70044,
+ 0x5ba70042,
+ 0x5ba70040,
+ 0x5ba7003e,
+ 0x5ba7003c,
+ 0x5ba7003b,
+ 0x5ba70039,
+ 0x5ba70037,
+ 0x5ba70036,
+ 0x5ba70034,
+ 0x5ba70033,
+ 0x5b770044,
+ 0x5b770042,
+ 0x5b770040,
+ 0x5b77003e,
+ 0x5b77003c,
+ 0x5b77003b,
+ 0x5b770039,
+ 0x5b770037,
+ 0x5b770036,
+ 0x5b770034,
+ 0x5b770033,
+ 0x5b770031,
+ 0x5b770030,
+ 0x5b77002f,
+ 0x5b77002d,
+ 0x5b77002c,
+ 0x5b470044,
+ 0x5b470042,
+ 0x5b470040,
+ 0x5b47003e,
+ 0x5b47003c,
+ 0x5b47003b,
+ 0x5b470039,
+ 0x5b470037,
+ 0x5b470036,
+ 0x5b470034,
+ 0x5b470033,
+ 0x5b470031,
+ 0x5b470030,
+ 0x5b47002f,
+ 0x5b47002d,
+ 0x5b47002c,
+ 0x5b47002b,
+ 0x5b47002a,
+ 0x5b270044,
+ 0x5b270042,
+ 0x5b270040,
+ 0x5b27003e,
+ 0x5b27003c,
+ 0x5b27003b,
+ 0x5b270039,
+ 0x5b270037,
+ 0x5b270036,
+ 0x5b270034,
+ 0x5b270033,
+ 0x5b270031,
+ 0x5b270030,
+ 0x5b27002f,
+ 0x5b170044,
+ 0x5b170042,
+ 0x5b170040,
+ 0x5b17003e,
+ 0x5b17003c,
+ 0x5b17003b,
+ 0x5b170039,
+ 0x5b170037,
+ 0x5b170036,
+ 0x5b170034,
+ 0x5b170033,
+ 0x5b170031,
+ 0x5b170030,
+ 0x5b17002f,
+ 0x5b17002d,
+ 0x5b17002c,
+ 0x5b17002b,
+ 0x5b17002a,
+ 0x5b170028,
+ 0x5b170027,
+ 0x5b170026,
+ 0x5b170025,
+ 0x5b170024,
+ 0x5b170023,
+ 0x5b070044,
+ 0x5b070042,
+ 0x5b070040,
+ 0x5b07003e,
+ 0x5b07003c,
+ 0x5b07003b,
+ 0x5b070039,
+ 0x5b070037,
+ 0x5b070036,
+ 0x5b070034,
+ 0x5b070033,
+ 0x5b070031,
+ 0x5b070030,
+ 0x5b07002f,
+ 0x5b07002d,
+ 0x5b07002c,
+ 0x5b07002b,
+ 0x5b07002a,
+ 0x5b070028,
+ 0x5b070027,
+ 0x5b070026,
+ 0x5b070025,
+ 0x5b070024,
+ 0x5b070023,
+ 0x5b070022,
+ 0x5b070021,
+ 0x5b070020,
+ 0x5b07001f,
+ 0x5b07001e,
+ 0x5b07001d,
+ 0x5b07001d,
+ 0x5b07001c,
+};
+
+static const u32 gainctrl_lut_core1_rev3[] = {
+ 0x5bf70044,
+ 0x5bf70042,
+ 0x5bf70040,
+ 0x5bf7003e,
+ 0x5bf7003c,
+ 0x5bf7003b,
+ 0x5bf70039,
+ 0x5bf70037,
+ 0x5bf70036,
+ 0x5bf70034,
+ 0x5bf70033,
+ 0x5bf70031,
+ 0x5bf70030,
+ 0x5ba70044,
+ 0x5ba70042,
+ 0x5ba70040,
+ 0x5ba7003e,
+ 0x5ba7003c,
+ 0x5ba7003b,
+ 0x5ba70039,
+ 0x5ba70037,
+ 0x5ba70036,
+ 0x5ba70034,
+ 0x5ba70033,
+ 0x5b770044,
+ 0x5b770042,
+ 0x5b770040,
+ 0x5b77003e,
+ 0x5b77003c,
+ 0x5b77003b,
+ 0x5b770039,
+ 0x5b770037,
+ 0x5b770036,
+ 0x5b770034,
+ 0x5b770033,
+ 0x5b770031,
+ 0x5b770030,
+ 0x5b77002f,
+ 0x5b77002d,
+ 0x5b77002c,
+ 0x5b470044,
+ 0x5b470042,
+ 0x5b470040,
+ 0x5b47003e,
+ 0x5b47003c,
+ 0x5b47003b,
+ 0x5b470039,
+ 0x5b470037,
+ 0x5b470036,
+ 0x5b470034,
+ 0x5b470033,
+ 0x5b470031,
+ 0x5b470030,
+ 0x5b47002f,
+ 0x5b47002d,
+ 0x5b47002c,
+ 0x5b47002b,
+ 0x5b47002a,
+ 0x5b270044,
+ 0x5b270042,
+ 0x5b270040,
+ 0x5b27003e,
+ 0x5b27003c,
+ 0x5b27003b,
+ 0x5b270039,
+ 0x5b270037,
+ 0x5b270036,
+ 0x5b270034,
+ 0x5b270033,
+ 0x5b270031,
+ 0x5b270030,
+ 0x5b27002f,
+ 0x5b170044,
+ 0x5b170042,
+ 0x5b170040,
+ 0x5b17003e,
+ 0x5b17003c,
+ 0x5b17003b,
+ 0x5b170039,
+ 0x5b170037,
+ 0x5b170036,
+ 0x5b170034,
+ 0x5b170033,
+ 0x5b170031,
+ 0x5b170030,
+ 0x5b17002f,
+ 0x5b17002d,
+ 0x5b17002c,
+ 0x5b17002b,
+ 0x5b17002a,
+ 0x5b170028,
+ 0x5b170027,
+ 0x5b170026,
+ 0x5b170025,
+ 0x5b170024,
+ 0x5b170023,
+ 0x5b070044,
+ 0x5b070042,
+ 0x5b070040,
+ 0x5b07003e,
+ 0x5b07003c,
+ 0x5b07003b,
+ 0x5b070039,
+ 0x5b070037,
+ 0x5b070036,
+ 0x5b070034,
+ 0x5b070033,
+ 0x5b070031,
+ 0x5b070030,
+ 0x5b07002f,
+ 0x5b07002d,
+ 0x5b07002c,
+ 0x5b07002b,
+ 0x5b07002a,
+ 0x5b070028,
+ 0x5b070027,
+ 0x5b070026,
+ 0x5b070025,
+ 0x5b070024,
+ 0x5b070023,
+ 0x5b070022,
+ 0x5b070021,
+ 0x5b070020,
+ 0x5b07001f,
+ 0x5b07001e,
+ 0x5b07001d,
+ 0x5b07001d,
+ 0x5b07001c,
+};
+
+static const u32 iq_lut_core0_rev3[] = {
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+static const u32 iq_lut_core1_rev3[] = {
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+static const u16 loft_lut_core0_rev3[] = {
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+};
+
+static const u16 loft_lut_core1_rev3[] = {
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+};
+
+static const u16 papd_comp_rfpwr_tbl_core0_rev3[] = {
+ 0x0036,
+ 0x0036,
+ 0x0036,
+ 0x0036,
+ 0x0036,
+ 0x0036,
+ 0x0036,
+ 0x0036,
+ 0x0036,
+ 0x0036,
+ 0x0036,
+ 0x0036,
+ 0x0036,
+ 0x002a,
+ 0x002a,
+ 0x002a,
+ 0x002a,
+ 0x002a,
+ 0x002a,
+ 0x002a,
+ 0x002a,
+ 0x002a,
+ 0x002a,
+ 0x002a,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+};
+
+static const u16 papd_comp_rfpwr_tbl_core1_rev3[] = {
+ 0x0036,
+ 0x0036,
+ 0x0036,
+ 0x0036,
+ 0x0036,
+ 0x0036,
+ 0x0036,
+ 0x0036,
+ 0x0036,
+ 0x0036,
+ 0x0036,
+ 0x0036,
+ 0x0036,
+ 0x002a,
+ 0x002a,
+ 0x002a,
+ 0x002a,
+ 0x002a,
+ 0x002a,
+ 0x002a,
+ 0x002a,
+ 0x002a,
+ 0x002a,
+ 0x002a,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x001e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x000e,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01fc,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01ee,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+ 0x01d6,
+};
+
+static const u32 papd_comp_epsilon_tbl_core0_rev3[] = {
+ 0x00000000,
+ 0x00001fa0,
+ 0x00019f78,
+ 0x0001df7e,
+ 0x03fa9f86,
+ 0x03fd1f90,
+ 0x03fe5f8a,
+ 0x03fb1f94,
+ 0x03fd9fa0,
+ 0x00009f98,
+ 0x03fd1fac,
+ 0x03ff9fa2,
+ 0x03fe9fae,
+ 0x00001fae,
+ 0x03fddfb4,
+ 0x03ff1fb8,
+ 0x03ff9fbc,
+ 0x03ffdfbe,
+ 0x03fe9fc2,
+ 0x03fedfc6,
+ 0x03fedfc6,
+ 0x03ff9fc8,
+ 0x03ff5fc6,
+ 0x03fedfc2,
+ 0x03ff9fc0,
+ 0x03ff5fac,
+ 0x03ff5fac,
+ 0x03ff9fa2,
+ 0x03ff9fa6,
+ 0x03ff9faa,
+ 0x03ff5fb0,
+ 0x03ff5fb4,
+ 0x03ff1fca,
+ 0x03ff5fce,
+ 0x03fcdfdc,
+ 0x03fb4006,
+ 0x00000030,
+ 0x03ff808a,
+ 0x03ff80da,
+ 0x0000016c,
+ 0x03ff8318,
+ 0x03ff063a,
+ 0x03fd8bd6,
+ 0x00014ffe,
+ 0x00034ffe,
+ 0x00034ffe,
+ 0x0003cffe,
+ 0x00040ffe,
+ 0x00040ffe,
+ 0x0003cffe,
+ 0x0003cffe,
+ 0x00020ffe,
+ 0x03fe0ffe,
+ 0x03fdcffe,
+ 0x03f94ffe,
+ 0x03f54ffe,
+ 0x03f44ffe,
+ 0x03ef8ffe,
+ 0x03ee0ffe,
+ 0x03ebcffe,
+ 0x03e8cffe,
+ 0x03e74ffe,
+ 0x03e4cffe,
+ 0x03e38ffe,
+};
+
+static const u32 papd_cal_scalars_tbl_core0_rev3[] = {
+ 0x05af005a,
+ 0x0571005e,
+ 0x05040066,
+ 0x04bd006c,
+ 0x047d0072,
+ 0x04430078,
+ 0x03f70081,
+ 0x03cb0087,
+ 0x03870091,
+ 0x035e0098,
+ 0x032e00a1,
+ 0x030300aa,
+ 0x02d800b4,
+ 0x02ae00bf,
+ 0x028900ca,
+ 0x026400d6,
+ 0x024100e3,
+ 0x022200f0,
+ 0x020200ff,
+ 0x01e5010e,
+ 0x01ca011e,
+ 0x01b0012f,
+ 0x01990140,
+ 0x01830153,
+ 0x016c0168,
+ 0x0158017d,
+ 0x01450193,
+ 0x013301ab,
+ 0x012101c5,
+ 0x011101e0,
+ 0x010201fc,
+ 0x00f4021a,
+ 0x00e6011d,
+ 0x00d9012e,
+ 0x00cd0140,
+ 0x00c20153,
+ 0x00b70167,
+ 0x00ac017c,
+ 0x00a30193,
+ 0x009a01ab,
+ 0x009101c4,
+ 0x008901df,
+ 0x008101fb,
+ 0x007a0219,
+ 0x00730239,
+ 0x006d025b,
+ 0x0067027e,
+ 0x006102a4,
+ 0x005c02cc,
+ 0x005602f6,
+ 0x00520323,
+ 0x004d0353,
+ 0x00490385,
+ 0x004503bb,
+ 0x004103f3,
+ 0x003d042f,
+ 0x003a046f,
+ 0x003704b2,
+ 0x003404f9,
+ 0x00310545,
+ 0x002e0596,
+ 0x002b05f5,
+ 0x00290640,
+ 0x002606a4,
+};
+
+static const u32 papd_comp_epsilon_tbl_core1_rev3[] = {
+ 0x00000000,
+ 0x00001fa0,
+ 0x00019f78,
+ 0x0001df7e,
+ 0x03fa9f86,
+ 0x03fd1f90,
+ 0x03fe5f8a,
+ 0x03fb1f94,
+ 0x03fd9fa0,
+ 0x00009f98,
+ 0x03fd1fac,
+ 0x03ff9fa2,
+ 0x03fe9fae,
+ 0x00001fae,
+ 0x03fddfb4,
+ 0x03ff1fb8,
+ 0x03ff9fbc,
+ 0x03ffdfbe,
+ 0x03fe9fc2,
+ 0x03fedfc6,
+ 0x03fedfc6,
+ 0x03ff9fc8,
+ 0x03ff5fc6,
+ 0x03fedfc2,
+ 0x03ff9fc0,
+ 0x03ff5fac,
+ 0x03ff5fac,
+ 0x03ff9fa2,
+ 0x03ff9fa6,
+ 0x03ff9faa,
+ 0x03ff5fb0,
+ 0x03ff5fb4,
+ 0x03ff1fca,
+ 0x03ff5fce,
+ 0x03fcdfdc,
+ 0x03fb4006,
+ 0x00000030,
+ 0x03ff808a,
+ 0x03ff80da,
+ 0x0000016c,
+ 0x03ff8318,
+ 0x03ff063a,
+ 0x03fd8bd6,
+ 0x00014ffe,
+ 0x00034ffe,
+ 0x00034ffe,
+ 0x0003cffe,
+ 0x00040ffe,
+ 0x00040ffe,
+ 0x0003cffe,
+ 0x0003cffe,
+ 0x00020ffe,
+ 0x03fe0ffe,
+ 0x03fdcffe,
+ 0x03f94ffe,
+ 0x03f54ffe,
+ 0x03f44ffe,
+ 0x03ef8ffe,
+ 0x03ee0ffe,
+ 0x03ebcffe,
+ 0x03e8cffe,
+ 0x03e74ffe,
+ 0x03e4cffe,
+ 0x03e38ffe,
+};
+
+static const u32 papd_cal_scalars_tbl_core1_rev3[] = {
+ 0x05af005a,
+ 0x0571005e,
+ 0x05040066,
+ 0x04bd006c,
+ 0x047d0072,
+ 0x04430078,
+ 0x03f70081,
+ 0x03cb0087,
+ 0x03870091,
+ 0x035e0098,
+ 0x032e00a1,
+ 0x030300aa,
+ 0x02d800b4,
+ 0x02ae00bf,
+ 0x028900ca,
+ 0x026400d6,
+ 0x024100e3,
+ 0x022200f0,
+ 0x020200ff,
+ 0x01e5010e,
+ 0x01ca011e,
+ 0x01b0012f,
+ 0x01990140,
+ 0x01830153,
+ 0x016c0168,
+ 0x0158017d,
+ 0x01450193,
+ 0x013301ab,
+ 0x012101c5,
+ 0x011101e0,
+ 0x010201fc,
+ 0x00f4021a,
+ 0x00e6011d,
+ 0x00d9012e,
+ 0x00cd0140,
+ 0x00c20153,
+ 0x00b70167,
+ 0x00ac017c,
+ 0x00a30193,
+ 0x009a01ab,
+ 0x009101c4,
+ 0x008901df,
+ 0x008101fb,
+ 0x007a0219,
+ 0x00730239,
+ 0x006d025b,
+ 0x0067027e,
+ 0x006102a4,
+ 0x005c02cc,
+ 0x005602f6,
+ 0x00520323,
+ 0x004d0353,
+ 0x00490385,
+ 0x004503bb,
+ 0x004103f3,
+ 0x003d042f,
+ 0x003a046f,
+ 0x003704b2,
+ 0x003404f9,
+ 0x00310545,
+ 0x002e0596,
+ 0x002b05f5,
+ 0x00290640,
+ 0x002606a4,
+};
+
+const struct phytbl_info mimophytbl_info_rev3_volatile[] = {
+ {&ant_swctrl_tbl_rev3,
+ sizeof(ant_swctrl_tbl_rev3) / sizeof(ant_swctrl_tbl_rev3[0]), 9, 0, 16}
+ ,
+};
+
+const struct phytbl_info mimophytbl_info_rev3_volatile1[] = {
+ {&ant_swctrl_tbl_rev3_1,
+ sizeof(ant_swctrl_tbl_rev3_1) / sizeof(ant_swctrl_tbl_rev3_1[0]), 9, 0,
+ 16}
+ ,
+};
+
+const struct phytbl_info mimophytbl_info_rev3_volatile2[] = {
+ {&ant_swctrl_tbl_rev3_2,
+ sizeof(ant_swctrl_tbl_rev3_2) / sizeof(ant_swctrl_tbl_rev3_2[0]), 9, 0,
+ 16}
+ ,
+};
+
+const struct phytbl_info mimophytbl_info_rev3_volatile3[] = {
+ {&ant_swctrl_tbl_rev3_3,
+ sizeof(ant_swctrl_tbl_rev3_3) / sizeof(ant_swctrl_tbl_rev3_3[0]), 9, 0,
+ 16}
+ ,
+};
+
+const struct phytbl_info mimophytbl_info_rev3[] = {
+ {&frame_struct_rev3,
+ sizeof(frame_struct_rev3) / sizeof(frame_struct_rev3[0]), 10, 0, 32}
+ ,
+ {&pilot_tbl_rev3, sizeof(pilot_tbl_rev3) / sizeof(pilot_tbl_rev3[0]),
+ 11, 0, 16}
+ ,
+ {&tmap_tbl_rev3, sizeof(tmap_tbl_rev3) / sizeof(tmap_tbl_rev3[0]), 12,
+ 0, 32}
+ ,
+ {&intlv_tbl_rev3, sizeof(intlv_tbl_rev3) / sizeof(intlv_tbl_rev3[0]),
+ 13, 0, 32}
+ ,
+ {&tdtrn_tbl_rev3, sizeof(tdtrn_tbl_rev3) / sizeof(tdtrn_tbl_rev3[0]),
+ 14, 0, 32}
+ ,
+ {&noise_var_tbl_rev3,
+ sizeof(noise_var_tbl_rev3) / sizeof(noise_var_tbl_rev3[0]), 16, 0, 32}
+ ,
+ {&mcs_tbl_rev3, sizeof(mcs_tbl_rev3) / sizeof(mcs_tbl_rev3[0]), 18, 0,
+ 16}
+ ,
+ {&tdi_tbl20_ant0_rev3,
+ sizeof(tdi_tbl20_ant0_rev3) / sizeof(tdi_tbl20_ant0_rev3[0]), 19, 128,
+ 32}
+ ,
+ {&tdi_tbl20_ant1_rev3,
+ sizeof(tdi_tbl20_ant1_rev3) / sizeof(tdi_tbl20_ant1_rev3[0]), 19, 256,
+ 32}
+ ,
+ {&tdi_tbl40_ant0_rev3,
+ sizeof(tdi_tbl40_ant0_rev3) / sizeof(tdi_tbl40_ant0_rev3[0]), 19, 640,
+ 32}
+ ,
+ {&tdi_tbl40_ant1_rev3,
+ sizeof(tdi_tbl40_ant1_rev3) / sizeof(tdi_tbl40_ant1_rev3[0]), 19, 768,
+ 32}
+ ,
+ {&pltlut_tbl_rev3, sizeof(pltlut_tbl_rev3) / sizeof(pltlut_tbl_rev3[0]),
+ 20, 0, 32}
+ ,
+ {&chanest_tbl_rev3,
+ sizeof(chanest_tbl_rev3) / sizeof(chanest_tbl_rev3[0]), 22, 0, 32}
+ ,
+ {&frame_lut_rev3, sizeof(frame_lut_rev3) / sizeof(frame_lut_rev3[0]),
+ 24, 0, 8}
+ ,
+ {&est_pwr_lut_core0_rev3,
+ sizeof(est_pwr_lut_core0_rev3) / sizeof(est_pwr_lut_core0_rev3[0]), 26,
+ 0, 8}
+ ,
+ {&est_pwr_lut_core1_rev3,
+ sizeof(est_pwr_lut_core1_rev3) / sizeof(est_pwr_lut_core1_rev3[0]), 27,
+ 0, 8}
+ ,
+ {&adj_pwr_lut_core0_rev3,
+ sizeof(adj_pwr_lut_core0_rev3) / sizeof(adj_pwr_lut_core0_rev3[0]), 26,
+ 64, 8}
+ ,
+ {&adj_pwr_lut_core1_rev3,
+ sizeof(adj_pwr_lut_core1_rev3) / sizeof(adj_pwr_lut_core1_rev3[0]), 27,
+ 64, 8}
+ ,
+ {&gainctrl_lut_core0_rev3,
+ sizeof(gainctrl_lut_core0_rev3) / sizeof(gainctrl_lut_core0_rev3[0]),
+ 26, 192, 32}
+ ,
+ {&gainctrl_lut_core1_rev3,
+ sizeof(gainctrl_lut_core1_rev3) / sizeof(gainctrl_lut_core1_rev3[0]),
+ 27, 192, 32}
+ ,
+ {&iq_lut_core0_rev3,
+ sizeof(iq_lut_core0_rev3) / sizeof(iq_lut_core0_rev3[0]), 26, 320, 32}
+ ,
+ {&iq_lut_core1_rev3,
+ sizeof(iq_lut_core1_rev3) / sizeof(iq_lut_core1_rev3[0]), 27, 320, 32}
+ ,
+ {&loft_lut_core0_rev3,
+ sizeof(loft_lut_core0_rev3) / sizeof(loft_lut_core0_rev3[0]), 26, 448,
+ 16}
+ ,
+ {&loft_lut_core1_rev3,
+ sizeof(loft_lut_core1_rev3) / sizeof(loft_lut_core1_rev3[0]), 27, 448,
+ 16}
+};
+
+const u32 mimophytbl_info_sz_rev3 =
+ sizeof(mimophytbl_info_rev3) / sizeof(mimophytbl_info_rev3[0]);
+const u32 mimophytbl_info_sz_rev3_volatile =
+ sizeof(mimophytbl_info_rev3_volatile) /
+ sizeof(mimophytbl_info_rev3_volatile[0]);
+const u32 mimophytbl_info_sz_rev3_volatile1 =
+ sizeof(mimophytbl_info_rev3_volatile1) /
+ sizeof(mimophytbl_info_rev3_volatile1[0]);
+const u32 mimophytbl_info_sz_rev3_volatile2 =
+ sizeof(mimophytbl_info_rev3_volatile2) /
+ sizeof(mimophytbl_info_rev3_volatile2[0]);
+const u32 mimophytbl_info_sz_rev3_volatile3 =
+ sizeof(mimophytbl_info_rev3_volatile3) /
+ sizeof(mimophytbl_info_rev3_volatile3[0]);
+
+static const u32 tmap_tbl_rev7[] = {
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00000888,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0xf1111110,
+ 0x11111111,
+ 0x11f11111,
+ 0x00000111,
+ 0x11000000,
+ 0x1111f111,
+ 0x11111111,
+ 0x111111f1,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x000aa888,
+ 0x88880000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0xa1111110,
+ 0x11111111,
+ 0x11c11111,
+ 0x00000111,
+ 0x11000000,
+ 0x1111a111,
+ 0x11111111,
+ 0x111111a1,
+ 0xa2222220,
+ 0x22222222,
+ 0x22c22222,
+ 0x00000222,
+ 0x22000000,
+ 0x2222a222,
+ 0x22222222,
+ 0x222222a2,
+ 0xf1111110,
+ 0x11111111,
+ 0x11f11111,
+ 0x00011111,
+ 0x11110000,
+ 0x1111f111,
+ 0x11111111,
+ 0x111111f1,
+ 0xa8aa88a0,
+ 0xa88888a8,
+ 0xa8a8a88a,
+ 0x00088aaa,
+ 0xaaaa0000,
+ 0xa8a8aa88,
+ 0xa88aaaaa,
+ 0xaaaa8a8a,
+ 0xaaa8aaa0,
+ 0x8aaa8aaa,
+ 0xaa8a8a8a,
+ 0x000aaa88,
+ 0x8aaa0000,
+ 0xaaa8a888,
+ 0x8aa88a8a,
+ 0x8a88a888,
+ 0x08080a00,
+ 0x0a08080a,
+ 0x080a0a08,
+ 0x00080808,
+ 0x080a0000,
+ 0x080a0808,
+ 0x080a0808,
+ 0x0a0a0a08,
+ 0xa0a0a0a0,
+ 0x80a0a080,
+ 0x8080a0a0,
+ 0x00008080,
+ 0x80a00000,
+ 0x80a080a0,
+ 0xa080a0a0,
+ 0x8080a0a0,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x99999000,
+ 0x9b9b99bb,
+ 0x9bb99999,
+ 0x9999b9b9,
+ 0x9b99bb90,
+ 0x9bbbbb9b,
+ 0x9b9b9bb9,
+ 0x00000999,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00aaa888,
+ 0x22000000,
+ 0x2222b222,
+ 0x22222222,
+ 0x222222b2,
+ 0xb2222220,
+ 0x22222222,
+ 0x22d22222,
+ 0x00000222,
+ 0x11000000,
+ 0x1111a111,
+ 0x11111111,
+ 0x111111a1,
+ 0xa1111110,
+ 0x11111111,
+ 0x11c11111,
+ 0x00000111,
+ 0x33000000,
+ 0x3333b333,
+ 0x33333333,
+ 0x333333b3,
+ 0xb3333330,
+ 0x33333333,
+ 0x33d33333,
+ 0x00000333,
+ 0x22000000,
+ 0x2222a222,
+ 0x22222222,
+ 0x222222a2,
+ 0xa2222220,
+ 0x22222222,
+ 0x22c22222,
+ 0x00000222,
+ 0x99b99b00,
+ 0x9b9b99bb,
+ 0x9bb99999,
+ 0x9999b9b9,
+ 0x9b99bb99,
+ 0x9bbbbb9b,
+ 0x9b9b9bb9,
+ 0x00000999,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa88,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x08aaa888,
+ 0x22222200,
+ 0x2222f222,
+ 0x22222222,
+ 0x222222f2,
+ 0x22222222,
+ 0x22222222,
+ 0x22f22222,
+ 0x00000222,
+ 0x11000000,
+ 0x1111f111,
+ 0x11111111,
+ 0x11111111,
+ 0xf1111111,
+ 0x11111111,
+ 0x11f11111,
+ 0x01111111,
+ 0xbb9bb900,
+ 0xb9b9bb99,
+ 0xb99bbbbb,
+ 0xbbbb9b9b,
+ 0xb9bb99bb,
+ 0xb99999b9,
+ 0xb9b9b99b,
+ 0x00000bbb,
+ 0xaa000000,
+ 0xa8a8aa88,
+ 0xa88aaaaa,
+ 0xaaaa8a8a,
+ 0xa8aa88aa,
+ 0xa88888a8,
+ 0xa8a8a88a,
+ 0x0a888aaa,
+ 0xaa000000,
+ 0xa8a8aa88,
+ 0xa88aaaaa,
+ 0xaaaa8a8a,
+ 0xa8aa88a0,
+ 0xa88888a8,
+ 0xa8a8a88a,
+ 0x00000aaa,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00000888,
+ 0xbbbbbb00,
+ 0x999bbbbb,
+ 0x9bb99b9b,
+ 0xb9b9b9bb,
+ 0xb9b99bbb,
+ 0xb9b9b9bb,
+ 0xb9bb9b99,
+ 0x00000999,
+ 0x8a000000,
+ 0xaa88a888,
+ 0xa88888aa,
+ 0xa88a8a88,
+ 0xa88aa88a,
+ 0x88a8aaaa,
+ 0xa8aa8aaa,
+ 0x0888a88a,
+ 0x0b0b0b00,
+ 0x090b0b0b,
+ 0x0b090b0b,
+ 0x0909090b,
+ 0x09090b0b,
+ 0x09090b0b,
+ 0x09090b09,
+ 0x00000909,
+ 0x0a000000,
+ 0x0a080808,
+ 0x080a080a,
+ 0x080a0a08,
+ 0x080a080a,
+ 0x0808080a,
+ 0x0a0a0a08,
+ 0x0808080a,
+ 0xb0b0b000,
+ 0x9090b0b0,
+ 0x90b09090,
+ 0xb0b0b090,
+ 0xb0b090b0,
+ 0x90b0b0b0,
+ 0xb0b09090,
+ 0x00000090,
+ 0x80000000,
+ 0xa080a080,
+ 0xa08080a0,
+ 0xa0808080,
+ 0xa080a080,
+ 0x80a0a0a0,
+ 0xa0a080a0,
+ 0x00a0a0a0,
+ 0x22000000,
+ 0x2222f222,
+ 0x22222222,
+ 0x222222f2,
+ 0xf2222220,
+ 0x22222222,
+ 0x22f22222,
+ 0x00000222,
+ 0x11000000,
+ 0x1111f111,
+ 0x11111111,
+ 0x111111f1,
+ 0xf1111110,
+ 0x11111111,
+ 0x11f11111,
+ 0x00000111,
+ 0x33000000,
+ 0x3333f333,
+ 0x33333333,
+ 0x333333f3,
+ 0xf3333330,
+ 0x33333333,
+ 0x33f33333,
+ 0x00000333,
+ 0x22000000,
+ 0x2222f222,
+ 0x22222222,
+ 0x222222f2,
+ 0xf2222220,
+ 0x22222222,
+ 0x22f22222,
+ 0x00000222,
+ 0x99000000,
+ 0x9b9b99bb,
+ 0x9bb99999,
+ 0x9999b9b9,
+ 0x9b99bb90,
+ 0x9bbbbb9b,
+ 0x9b9b9bb9,
+ 0x00000999,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00000888,
+ 0x88888000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00000888,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00aaa888,
+ 0x88a88a00,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa88,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x000aa888,
+ 0x88880000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa88,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x08aaa888,
+ 0x11000000,
+ 0x1111a111,
+ 0x11111111,
+ 0x111111a1,
+ 0xa1111110,
+ 0x11111111,
+ 0x11c11111,
+ 0x00000111,
+ 0x11000000,
+ 0x1111a111,
+ 0x11111111,
+ 0x111111a1,
+ 0xa1111110,
+ 0x11111111,
+ 0x11c11111,
+ 0x00000111,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00000888,
+ 0x88000000,
+ 0x8a8a88aa,
+ 0x8aa88888,
+ 0x8888a8a8,
+ 0x8a88aa80,
+ 0x8aaaaa8a,
+ 0x8a8a8aa8,
+ 0x00000888,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+const u32 noise_var_tbl_rev7[] = {
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+ 0x020c020c,
+ 0x0000014d,
+};
+
+static const u32 papd_comp_epsilon_tbl_core0_rev7[] = {
+ 0x00000000,
+ 0x00000000,
+ 0x00016023,
+ 0x00006028,
+ 0x00034036,
+ 0x0003402e,
+ 0x0007203c,
+ 0x0006e037,
+ 0x00070030,
+ 0x0009401f,
+ 0x0009a00f,
+ 0x000b600d,
+ 0x000c8007,
+ 0x000ce007,
+ 0x00101fff,
+ 0x00121ff9,
+ 0x0012e004,
+ 0x0014dffc,
+ 0x0016dff6,
+ 0x0018dfe9,
+ 0x001b3fe5,
+ 0x001c5fd0,
+ 0x001ddfc2,
+ 0x001f1fb6,
+ 0x00207fa4,
+ 0x00219f8f,
+ 0x0022ff7d,
+ 0x00247f6c,
+ 0x0024df5b,
+ 0x00267f4b,
+ 0x0027df3b,
+ 0x0029bf3b,
+ 0x002b5f2f,
+ 0x002d3f2e,
+ 0x002f5f2a,
+ 0x002fff15,
+ 0x00315f0b,
+ 0x0032defa,
+ 0x0033beeb,
+ 0x0034fed9,
+ 0x00353ec5,
+ 0x00361eb0,
+ 0x00363e9b,
+ 0x0036be87,
+ 0x0036be70,
+ 0x0038fe67,
+ 0x0044beb2,
+ 0x00513ef3,
+ 0x00595f11,
+ 0x00669f3d,
+ 0x0078dfdf,
+ 0x00a143aa,
+ 0x01642fff,
+ 0x0162afff,
+ 0x01620fff,
+ 0x0160cfff,
+ 0x015f0fff,
+ 0x015dafff,
+ 0x015bcfff,
+ 0x015bcfff,
+ 0x015b4fff,
+ 0x015acfff,
+ 0x01590fff,
+ 0x0156cfff,
+};
+
+static const u32 papd_cal_scalars_tbl_core0_rev7[] = {
+ 0x0b5e002d,
+ 0x0ae2002f,
+ 0x0a3b0032,
+ 0x09a70035,
+ 0x09220038,
+ 0x08ab003b,
+ 0x081f003f,
+ 0x07a20043,
+ 0x07340047,
+ 0x06d2004b,
+ 0x067a004f,
+ 0x06170054,
+ 0x05bf0059,
+ 0x0571005e,
+ 0x051e0064,
+ 0x04d3006a,
+ 0x04910070,
+ 0x044c0077,
+ 0x040f007e,
+ 0x03d90085,
+ 0x03a1008d,
+ 0x036f0095,
+ 0x033d009e,
+ 0x030b00a8,
+ 0x02e000b2,
+ 0x02b900bc,
+ 0x029200c7,
+ 0x026d00d3,
+ 0x024900e0,
+ 0x022900ed,
+ 0x020a00fb,
+ 0x01ec010a,
+ 0x01d20119,
+ 0x01b7012a,
+ 0x019e013c,
+ 0x0188014e,
+ 0x01720162,
+ 0x015d0177,
+ 0x0149018e,
+ 0x013701a5,
+ 0x012601be,
+ 0x011501d8,
+ 0x010601f4,
+ 0x00f70212,
+ 0x00e90231,
+ 0x00dc0253,
+ 0x00d00276,
+ 0x00c4029b,
+ 0x00b902c3,
+ 0x00af02ed,
+ 0x00a50319,
+ 0x009c0348,
+ 0x0093037a,
+ 0x008b03af,
+ 0x008303e6,
+ 0x007c0422,
+ 0x00750460,
+ 0x006e04a3,
+ 0x006804e9,
+ 0x00620533,
+ 0x005d0582,
+ 0x005805d6,
+ 0x0053062e,
+ 0x004e068c,
+};
+
+static const u32 papd_comp_epsilon_tbl_core1_rev7[] = {
+ 0x00000000,
+ 0x00000000,
+ 0x00016023,
+ 0x00006028,
+ 0x00034036,
+ 0x0003402e,
+ 0x0007203c,
+ 0x0006e037,
+ 0x00070030,
+ 0x0009401f,
+ 0x0009a00f,
+ 0x000b600d,
+ 0x000c8007,
+ 0x000ce007,
+ 0x00101fff,
+ 0x00121ff9,
+ 0x0012e004,
+ 0x0014dffc,
+ 0x0016dff6,
+ 0x0018dfe9,
+ 0x001b3fe5,
+ 0x001c5fd0,
+ 0x001ddfc2,
+ 0x001f1fb6,
+ 0x00207fa4,
+ 0x00219f8f,
+ 0x0022ff7d,
+ 0x00247f6c,
+ 0x0024df5b,
+ 0x00267f4b,
+ 0x0027df3b,
+ 0x0029bf3b,
+ 0x002b5f2f,
+ 0x002d3f2e,
+ 0x002f5f2a,
+ 0x002fff15,
+ 0x00315f0b,
+ 0x0032defa,
+ 0x0033beeb,
+ 0x0034fed9,
+ 0x00353ec5,
+ 0x00361eb0,
+ 0x00363e9b,
+ 0x0036be87,
+ 0x0036be70,
+ 0x0038fe67,
+ 0x0044beb2,
+ 0x00513ef3,
+ 0x00595f11,
+ 0x00669f3d,
+ 0x0078dfdf,
+ 0x00a143aa,
+ 0x01642fff,
+ 0x0162afff,
+ 0x01620fff,
+ 0x0160cfff,
+ 0x015f0fff,
+ 0x015dafff,
+ 0x015bcfff,
+ 0x015bcfff,
+ 0x015b4fff,
+ 0x015acfff,
+ 0x01590fff,
+ 0x0156cfff,
+};
+
+static const u32 papd_cal_scalars_tbl_core1_rev7[] = {
+ 0x0b5e002d,
+ 0x0ae2002f,
+ 0x0a3b0032,
+ 0x09a70035,
+ 0x09220038,
+ 0x08ab003b,
+ 0x081f003f,
+ 0x07a20043,
+ 0x07340047,
+ 0x06d2004b,
+ 0x067a004f,
+ 0x06170054,
+ 0x05bf0059,
+ 0x0571005e,
+ 0x051e0064,
+ 0x04d3006a,
+ 0x04910070,
+ 0x044c0077,
+ 0x040f007e,
+ 0x03d90085,
+ 0x03a1008d,
+ 0x036f0095,
+ 0x033d009e,
+ 0x030b00a8,
+ 0x02e000b2,
+ 0x02b900bc,
+ 0x029200c7,
+ 0x026d00d3,
+ 0x024900e0,
+ 0x022900ed,
+ 0x020a00fb,
+ 0x01ec010a,
+ 0x01d20119,
+ 0x01b7012a,
+ 0x019e013c,
+ 0x0188014e,
+ 0x01720162,
+ 0x015d0177,
+ 0x0149018e,
+ 0x013701a5,
+ 0x012601be,
+ 0x011501d8,
+ 0x010601f4,
+ 0x00f70212,
+ 0x00e90231,
+ 0x00dc0253,
+ 0x00d00276,
+ 0x00c4029b,
+ 0x00b902c3,
+ 0x00af02ed,
+ 0x00a50319,
+ 0x009c0348,
+ 0x0093037a,
+ 0x008b03af,
+ 0x008303e6,
+ 0x007c0422,
+ 0x00750460,
+ 0x006e04a3,
+ 0x006804e9,
+ 0x00620533,
+ 0x005d0582,
+ 0x005805d6,
+ 0x0053062e,
+ 0x004e068c,
+};
+
+const struct phytbl_info mimophytbl_info_rev7[] = {
+ {&frame_struct_rev3,
+ sizeof(frame_struct_rev3) / sizeof(frame_struct_rev3[0]), 10, 0, 32}
+ ,
+ {&pilot_tbl_rev3, sizeof(pilot_tbl_rev3) / sizeof(pilot_tbl_rev3[0]),
+ 11, 0, 16}
+ ,
+ {&tmap_tbl_rev7, sizeof(tmap_tbl_rev7) / sizeof(tmap_tbl_rev7[0]), 12,
+ 0, 32}
+ ,
+ {&intlv_tbl_rev3, sizeof(intlv_tbl_rev3) / sizeof(intlv_tbl_rev3[0]),
+ 13, 0, 32}
+ ,
+ {&tdtrn_tbl_rev3, sizeof(tdtrn_tbl_rev3) / sizeof(tdtrn_tbl_rev3[0]),
+ 14, 0, 32}
+ ,
+ {&noise_var_tbl_rev7,
+ sizeof(noise_var_tbl_rev7) / sizeof(noise_var_tbl_rev7[0]), 16, 0, 32}
+ ,
+ {&mcs_tbl_rev3, sizeof(mcs_tbl_rev3) / sizeof(mcs_tbl_rev3[0]), 18, 0,
+ 16}
+ ,
+ {&tdi_tbl20_ant0_rev3,
+ sizeof(tdi_tbl20_ant0_rev3) / sizeof(tdi_tbl20_ant0_rev3[0]), 19, 128,
+ 32}
+ ,
+ {&tdi_tbl20_ant1_rev3,
+ sizeof(tdi_tbl20_ant1_rev3) / sizeof(tdi_tbl20_ant1_rev3[0]), 19, 256,
+ 32}
+ ,
+ {&tdi_tbl40_ant0_rev3,
+ sizeof(tdi_tbl40_ant0_rev3) / sizeof(tdi_tbl40_ant0_rev3[0]), 19, 640,
+ 32}
+ ,
+ {&tdi_tbl40_ant1_rev3,
+ sizeof(tdi_tbl40_ant1_rev3) / sizeof(tdi_tbl40_ant1_rev3[0]), 19, 768,
+ 32}
+ ,
+ {&pltlut_tbl_rev3, sizeof(pltlut_tbl_rev3) / sizeof(pltlut_tbl_rev3[0]),
+ 20, 0, 32}
+ ,
+ {&chanest_tbl_rev3,
+ sizeof(chanest_tbl_rev3) / sizeof(chanest_tbl_rev3[0]), 22, 0, 32}
+ ,
+ {&frame_lut_rev3, sizeof(frame_lut_rev3) / sizeof(frame_lut_rev3[0]),
+ 24, 0, 8}
+ ,
+ {&est_pwr_lut_core0_rev3,
+ sizeof(est_pwr_lut_core0_rev3) / sizeof(est_pwr_lut_core0_rev3[0]), 26,
+ 0, 8}
+ ,
+ {&est_pwr_lut_core1_rev3,
+ sizeof(est_pwr_lut_core1_rev3) / sizeof(est_pwr_lut_core1_rev3[0]), 27,
+ 0, 8}
+ ,
+ {&adj_pwr_lut_core0_rev3,
+ sizeof(adj_pwr_lut_core0_rev3) / sizeof(adj_pwr_lut_core0_rev3[0]), 26,
+ 64, 8}
+ ,
+ {&adj_pwr_lut_core1_rev3,
+ sizeof(adj_pwr_lut_core1_rev3) / sizeof(adj_pwr_lut_core1_rev3[0]), 27,
+ 64, 8}
+ ,
+ {&gainctrl_lut_core0_rev3,
+ sizeof(gainctrl_lut_core0_rev3) / sizeof(gainctrl_lut_core0_rev3[0]),
+ 26, 192, 32}
+ ,
+ {&gainctrl_lut_core1_rev3,
+ sizeof(gainctrl_lut_core1_rev3) / sizeof(gainctrl_lut_core1_rev3[0]),
+ 27, 192, 32}
+ ,
+ {&iq_lut_core0_rev3,
+ sizeof(iq_lut_core0_rev3) / sizeof(iq_lut_core0_rev3[0]), 26, 320, 32}
+ ,
+ {&iq_lut_core1_rev3,
+ sizeof(iq_lut_core1_rev3) / sizeof(iq_lut_core1_rev3[0]), 27, 320, 32}
+ ,
+ {&loft_lut_core0_rev3,
+ sizeof(loft_lut_core0_rev3) / sizeof(loft_lut_core0_rev3[0]), 26, 448,
+ 16}
+ ,
+ {&loft_lut_core1_rev3,
+ sizeof(loft_lut_core1_rev3) / sizeof(loft_lut_core1_rev3[0]), 27, 448,
+ 16}
+ ,
+ {&papd_comp_rfpwr_tbl_core0_rev3,
+ sizeof(papd_comp_rfpwr_tbl_core0_rev3) /
+ sizeof(papd_comp_rfpwr_tbl_core0_rev3[0]), 26, 576, 16}
+ ,
+ {&papd_comp_rfpwr_tbl_core1_rev3,
+ sizeof(papd_comp_rfpwr_tbl_core1_rev3) /
+ sizeof(papd_comp_rfpwr_tbl_core1_rev3[0]), 27, 576, 16}
+ ,
+ {&papd_comp_epsilon_tbl_core0_rev7,
+ sizeof(papd_comp_epsilon_tbl_core0_rev7) /
+ sizeof(papd_comp_epsilon_tbl_core0_rev7[0]), 31, 0, 32}
+ ,
+ {&papd_cal_scalars_tbl_core0_rev7,
+ sizeof(papd_cal_scalars_tbl_core0_rev7) /
+ sizeof(papd_cal_scalars_tbl_core0_rev7[0]), 32, 0, 32}
+ ,
+ {&papd_comp_epsilon_tbl_core1_rev7,
+ sizeof(papd_comp_epsilon_tbl_core1_rev7) /
+ sizeof(papd_comp_epsilon_tbl_core1_rev7[0]), 33, 0, 32}
+ ,
+ {&papd_cal_scalars_tbl_core1_rev7,
+ sizeof(papd_cal_scalars_tbl_core1_rev7) /
+ sizeof(papd_cal_scalars_tbl_core1_rev7[0]), 34, 0, 32}
+ ,
+};
+
+const u32 mimophytbl_info_sz_rev7 =
+ sizeof(mimophytbl_info_rev7) / sizeof(mimophytbl_info_rev7[0]);
+
+const struct phytbl_info mimophytbl_info_rev16[] = {
+ {&noise_var_tbl_rev7,
+ sizeof(noise_var_tbl_rev7) / sizeof(noise_var_tbl_rev7[0]), 16, 0, 32}
+ ,
+ {&est_pwr_lut_core0_rev3,
+ sizeof(est_pwr_lut_core0_rev3) / sizeof(est_pwr_lut_core0_rev3[0]), 26,
+ 0, 8}
+ ,
+ {&est_pwr_lut_core1_rev3,
+ sizeof(est_pwr_lut_core1_rev3) / sizeof(est_pwr_lut_core1_rev3[0]), 27,
+ 0, 8}
+ ,
+ {&adj_pwr_lut_core0_rev3,
+ sizeof(adj_pwr_lut_core0_rev3) / sizeof(adj_pwr_lut_core0_rev3[0]), 26,
+ 64, 8}
+ ,
+ {&adj_pwr_lut_core1_rev3,
+ sizeof(adj_pwr_lut_core1_rev3) / sizeof(adj_pwr_lut_core1_rev3[0]), 27,
+ 64, 8}
+ ,
+ {&gainctrl_lut_core0_rev3,
+ sizeof(gainctrl_lut_core0_rev3) / sizeof(gainctrl_lut_core0_rev3[0]),
+ 26, 192, 32}
+ ,
+ {&gainctrl_lut_core1_rev3,
+ sizeof(gainctrl_lut_core1_rev3) / sizeof(gainctrl_lut_core1_rev3[0]),
+ 27, 192, 32}
+ ,
+ {&iq_lut_core0_rev3,
+ sizeof(iq_lut_core0_rev3) / sizeof(iq_lut_core0_rev3[0]), 26, 320, 32}
+ ,
+ {&iq_lut_core1_rev3,
+ sizeof(iq_lut_core1_rev3) / sizeof(iq_lut_core1_rev3[0]), 27, 320, 32}
+ ,
+ {&loft_lut_core0_rev3,
+ sizeof(loft_lut_core0_rev3) / sizeof(loft_lut_core0_rev3[0]), 26, 448,
+ 16}
+ ,
+ {&loft_lut_core1_rev3,
+ sizeof(loft_lut_core1_rev3) / sizeof(loft_lut_core1_rev3[0]), 27, 448,
+ 16}
+ ,
+};
+
+const u32 mimophytbl_info_sz_rev16 =
+ sizeof(mimophytbl_info_rev16) / sizeof(mimophytbl_info_rev16[0]);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.h
new file mode 100644
index 000000000000..dc8a84e85117
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2010 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define ANT_SWCTRL_TBL_REV3_IDX (0)
+
+#include <types.h>
+#include "phy_int.h"
+
+extern const struct phytbl_info mimophytbl_info_rev0[],
+ mimophytbl_info_rev0_volatile[];
+
+extern const u32 mimophytbl_info_sz_rev0,
+ mimophytbl_info_sz_rev0_volatile;
+
+extern const struct phytbl_info mimophytbl_info_rev3[],
+ mimophytbl_info_rev3_volatile[],
+ mimophytbl_info_rev3_volatile1[],
+ mimophytbl_info_rev3_volatile2[],
+ mimophytbl_info_rev3_volatile3[];
+
+extern const u32 mimophytbl_info_sz_rev3,
+ mimophytbl_info_sz_rev3_volatile,
+ mimophytbl_info_sz_rev3_volatile1,
+ mimophytbl_info_sz_rev3_volatile2,
+ mimophytbl_info_sz_rev3_volatile3;
+
+extern const u32 noise_var_tbl_rev3[];
+
+extern const struct phytbl_info mimophytbl_info_rev7[];
+
+extern const u32 mimophytbl_info_sz_rev7;
+
+extern const u32 noise_var_tbl_rev7[];
+
+extern const struct phytbl_info mimophytbl_info_rev16[];
+
+extern const u32 mimophytbl_info_sz_rev16;
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.c b/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.c
new file mode 100644
index 000000000000..5926854f62e2
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2010 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.
+ */
+
+/*
+ * This is "two-way" interface, acting as the SHIM layer between driver
+ * and PHY layer. The driver can optionally call this translation layer
+ * to do some preprocessing, then reach PHY. On the PHY->driver direction,
+ * all calls go through this layer since PHY doesn't have access to the
+ * driver's brcms_hardware pointer.
+ */
+#include <linux/slab.h>
+#include <net/mac80211.h>
+
+#include "main.h"
+#include "mac80211_if.h"
+#include "phy_shim.h"
+
+/* PHY SHIM module specific state */
+struct phy_shim_info {
+ struct brcms_hardware *wlc_hw; /* pointer to main wlc_hw structure */
+ struct brcms_c_info *wlc; /* pointer to main wlc structure */
+ struct brcms_info *wl; /* pointer to os-specific private state */
+};
+
+struct phy_shim_info *wlc_phy_shim_attach(struct brcms_hardware *wlc_hw,
+ struct brcms_info *wl,
+ struct brcms_c_info *wlc) {
+ struct phy_shim_info *physhim = NULL;
+
+ physhim = kzalloc(sizeof(struct phy_shim_info), GFP_ATOMIC);
+ if (!physhim)
+ return NULL;
+
+ physhim->wlc_hw = wlc_hw;
+ physhim->wlc = wlc;
+ physhim->wl = wl;
+
+ return physhim;
+}
+
+void wlc_phy_shim_detach(struct phy_shim_info *physhim)
+{
+ kfree(physhim);
+}
+
+struct wlapi_timer *wlapi_init_timer(struct phy_shim_info *physhim,
+ void (*fn)(struct brcms_phy *pi),
+ void *arg, const char *name)
+{
+ return (struct wlapi_timer *)
+ brcms_init_timer(physhim->wl, (void (*)(void *))fn,
+ arg, name);
+}
+
+void wlapi_free_timer(struct wlapi_timer *t)
+{
+ brcms_free_timer((struct brcms_timer *)t);
+}
+
+void
+wlapi_add_timer(struct wlapi_timer *t, uint ms, int periodic)
+{
+ brcms_add_timer((struct brcms_timer *)t, ms, periodic);
+}
+
+bool wlapi_del_timer(struct wlapi_timer *t)
+{
+ return brcms_del_timer((struct brcms_timer *)t);
+}
+
+void wlapi_intrson(struct phy_shim_info *physhim)
+{
+ brcms_intrson(physhim->wl);
+}
+
+u32 wlapi_intrsoff(struct phy_shim_info *physhim)
+{
+ return brcms_intrsoff(physhim->wl);
+}
+
+void wlapi_intrsrestore(struct phy_shim_info *physhim, u32 macintmask)
+{
+ brcms_intrsrestore(physhim->wl, macintmask);
+}
+
+void wlapi_bmac_write_shm(struct phy_shim_info *physhim, uint offset, u16 v)
+{
+ brcms_b_write_shm(physhim->wlc_hw, offset, v);
+}
+
+u16 wlapi_bmac_read_shm(struct phy_shim_info *physhim, uint offset)
+{
+ return brcms_b_read_shm(physhim->wlc_hw, offset);
+}
+
+void
+wlapi_bmac_mhf(struct phy_shim_info *physhim, u8 idx, u16 mask,
+ u16 val, int bands)
+{
+ brcms_b_mhf(physhim->wlc_hw, idx, mask, val, bands);
+}
+
+void wlapi_bmac_corereset(struct phy_shim_info *physhim, u32 flags)
+{
+ brcms_b_corereset(physhim->wlc_hw, flags);
+}
+
+void wlapi_suspend_mac_and_wait(struct phy_shim_info *physhim)
+{
+ brcms_c_suspend_mac_and_wait(physhim->wlc);
+}
+
+void wlapi_switch_macfreq(struct phy_shim_info *physhim, u8 spurmode)
+{
+ brcms_b_switch_macfreq(physhim->wlc_hw, spurmode);
+}
+
+void wlapi_enable_mac(struct phy_shim_info *physhim)
+{
+ brcms_c_enable_mac(physhim->wlc);
+}
+
+void wlapi_bmac_mctrl(struct phy_shim_info *physhim, u32 mask, u32 val)
+{
+ brcms_b_mctrl(physhim->wlc_hw, mask, val);
+}
+
+void wlapi_bmac_phy_reset(struct phy_shim_info *physhim)
+{
+ brcms_b_phy_reset(physhim->wlc_hw);
+}
+
+void wlapi_bmac_bw_set(struct phy_shim_info *physhim, u16 bw)
+{
+ brcms_b_bw_set(physhim->wlc_hw, bw);
+}
+
+u16 wlapi_bmac_get_txant(struct phy_shim_info *physhim)
+{
+ return brcms_b_get_txant(physhim->wlc_hw);
+}
+
+void wlapi_bmac_phyclk_fgc(struct phy_shim_info *physhim, bool clk)
+{
+ brcms_b_phyclk_fgc(physhim->wlc_hw, clk);
+}
+
+void wlapi_bmac_macphyclk_set(struct phy_shim_info *physhim, bool clk)
+{
+ brcms_b_macphyclk_set(physhim->wlc_hw, clk);
+}
+
+void wlapi_bmac_core_phypll_ctl(struct phy_shim_info *physhim, bool on)
+{
+ brcms_b_core_phypll_ctl(physhim->wlc_hw, on);
+}
+
+void wlapi_bmac_core_phypll_reset(struct phy_shim_info *physhim)
+{
+ brcms_b_core_phypll_reset(physhim->wlc_hw);
+}
+
+void wlapi_bmac_ucode_wake_override_phyreg_set(struct phy_shim_info *physhim)
+{
+ brcms_c_ucode_wake_override_set(physhim->wlc_hw,
+ BRCMS_WAKE_OVERRIDE_PHYREG);
+}
+
+void wlapi_bmac_ucode_wake_override_phyreg_clear(struct phy_shim_info *physhim)
+{
+ brcms_c_ucode_wake_override_clear(physhim->wlc_hw,
+ BRCMS_WAKE_OVERRIDE_PHYREG);
+}
+
+void
+wlapi_bmac_write_template_ram(struct phy_shim_info *physhim, int offset,
+ int len, void *buf)
+{
+ brcms_b_write_template_ram(physhim->wlc_hw, offset, len, buf);
+}
+
+u16 wlapi_bmac_rate_shm_offset(struct phy_shim_info *physhim, u8 rate)
+{
+ return brcms_b_rate_shm_offset(physhim->wlc_hw, rate);
+}
+
+void wlapi_ucode_sample_init(struct phy_shim_info *physhim)
+{
+}
+
+void
+wlapi_copyfrom_objmem(struct phy_shim_info *physhim, uint offset, void *buf,
+ int len, u32 sel)
+{
+ brcms_b_copyfrom_objmem(physhim->wlc_hw, offset, buf, len, sel);
+}
+
+void
+wlapi_copyto_objmem(struct phy_shim_info *physhim, uint offset, const void *buf,
+ int l, u32 sel)
+{
+ brcms_b_copyto_objmem(physhim->wlc_hw, offset, buf, l, sel);
+}
+
+char *wlapi_getvar(struct phy_shim_info *physhim, enum brcms_srom_id id)
+{
+ return getvar(physhim->wlc_hw->sih, id);
+}
+int wlapi_getintvar(struct phy_shim_info *physhim, enum brcms_srom_id id)
+{
+ return getintvar(physhim->wlc_hw->sih, id);
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h b/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h
new file mode 100644
index 000000000000..9168c459b185
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2010 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.
+ */
+
+/*
+ * phy_shim.h: stuff defined in phy_shim.c and included only by the phy
+ */
+
+#ifndef _BRCM_PHY_SHIM_H_
+#define _BRCM_PHY_SHIM_H_
+
+#include "types.h"
+
+#define RADAR_TYPE_NONE 0 /* Radar type None */
+#define RADAR_TYPE_ETSI_1 1 /* ETSI 1 Radar type */
+#define RADAR_TYPE_ETSI_2 2 /* ETSI 2 Radar type */
+#define RADAR_TYPE_ETSI_3 3 /* ETSI 3 Radar type */
+#define RADAR_TYPE_ITU_E 4 /* ITU E Radar type */
+#define RADAR_TYPE_ITU_K 5 /* ITU K Radar type */
+#define RADAR_TYPE_UNCLASSIFIED 6 /* Unclassified Radar type */
+#define RADAR_TYPE_BIN5 7 /* long pulse radar type */
+#define RADAR_TYPE_STG2 8 /* staggered-2 radar */
+#define RADAR_TYPE_STG3 9 /* staggered-3 radar */
+#define RADAR_TYPE_FRA 10 /* French radar */
+
+/* French radar pulse widths */
+#define FRA_T1_20MHZ 52770
+#define FRA_T2_20MHZ 61538
+#define FRA_T3_20MHZ 66002
+#define FRA_T1_40MHZ 105541
+#define FRA_T2_40MHZ 123077
+#define FRA_T3_40MHZ 132004
+#define FRA_ERR_20MHZ 60
+#define FRA_ERR_40MHZ 120
+
+#define ANTSEL_NA 0 /* No boardlevel selection available */
+#define ANTSEL_2x4 1 /* 2x4 boardlevel selection available */
+#define ANTSEL_2x3 2 /* 2x3 CB2 boardlevel selection available */
+
+/* Rx Antenna diversity control values */
+#define ANT_RX_DIV_FORCE_0 0 /* Use antenna 0 */
+#define ANT_RX_DIV_FORCE_1 1 /* Use antenna 1 */
+#define ANT_RX_DIV_START_1 2 /* Choose starting with 1 */
+#define ANT_RX_DIV_START_0 3 /* Choose starting with 0 */
+#define ANT_RX_DIV_ENABLE 3 /* APHY bbConfig Enable RX Diversity */
+#define ANT_RX_DIV_DEF ANT_RX_DIV_START_0 /* default antdiv setting */
+
+#define WL_ANT_RX_MAX 2 /* max 2 receive antennas */
+#define WL_ANT_HT_RX_MAX 3 /* max 3 receive antennas/cores */
+#define WL_ANT_IDX_1 0 /* antenna index 1 */
+#define WL_ANT_IDX_2 1 /* antenna index 2 */
+
+/* values for n_preamble_type */
+#define BRCMS_N_PREAMBLE_MIXEDMODE 0
+#define BRCMS_N_PREAMBLE_GF 1
+#define BRCMS_N_PREAMBLE_GF_BRCM 2
+
+#define WL_TX_POWER_RATES_LEGACY 45
+#define WL_TX_POWER_MCS20_FIRST 12
+#define WL_TX_POWER_MCS20_NUM 16
+#define WL_TX_POWER_MCS40_FIRST 28
+#define WL_TX_POWER_MCS40_NUM 17
+
+
+#define WL_TX_POWER_RATES 101
+#define WL_TX_POWER_CCK_FIRST 0
+#define WL_TX_POWER_CCK_NUM 4
+/* Index for first 20MHz OFDM SISO rate */
+#define WL_TX_POWER_OFDM_FIRST 4
+/* Index for first 20MHz OFDM CDD rate */
+#define WL_TX_POWER_OFDM20_CDD_FIRST 12
+/* Index for first 40MHz OFDM SISO rate */
+#define WL_TX_POWER_OFDM40_SISO_FIRST 52
+/* Index for first 40MHz OFDM CDD rate */
+#define WL_TX_POWER_OFDM40_CDD_FIRST 60
+#define WL_TX_POWER_OFDM_NUM 8
+/* Index for first 20MHz MCS SISO rate */
+#define WL_TX_POWER_MCS20_SISO_FIRST 20
+/* Index for first 20MHz MCS CDD rate */
+#define WL_TX_POWER_MCS20_CDD_FIRST 28
+/* Index for first 20MHz MCS STBC rate */
+#define WL_TX_POWER_MCS20_STBC_FIRST 36
+/* Index for first 20MHz MCS SDM rate */
+#define WL_TX_POWER_MCS20_SDM_FIRST 44
+/* Index for first 40MHz MCS SISO rate */
+#define WL_TX_POWER_MCS40_SISO_FIRST 68
+/* Index for first 40MHz MCS CDD rate */
+#define WL_TX_POWER_MCS40_CDD_FIRST 76
+/* Index for first 40MHz MCS STBC rate */
+#define WL_TX_POWER_MCS40_STBC_FIRST 84
+/* Index for first 40MHz MCS SDM rate */
+#define WL_TX_POWER_MCS40_SDM_FIRST 92
+#define WL_TX_POWER_MCS_1_STREAM_NUM 8
+#define WL_TX_POWER_MCS_2_STREAM_NUM 8
+/* Index for 40MHz rate MCS 32 */
+#define WL_TX_POWER_MCS_32 100
+#define WL_TX_POWER_MCS_32_NUM 1
+
+/* sslpnphy specifics */
+/* Index for first 20MHz MCS SISO rate */
+#define WL_TX_POWER_MCS20_SISO_FIRST_SSN 12
+
+/* struct tx_power::flags bits */
+#define WL_TX_POWER_F_ENABLED 1
+#define WL_TX_POWER_F_HW 2
+#define WL_TX_POWER_F_MIMO 4
+#define WL_TX_POWER_F_SISO 8
+
+/* values to force tx/rx chain */
+#define BRCMS_N_TXRX_CHAIN0 0
+#define BRCMS_N_TXRX_CHAIN1 1
+
+struct brcms_phy;
+
+extern struct phy_shim_info *wlc_phy_shim_attach(struct brcms_hardware *wlc_hw,
+ struct brcms_info *wl,
+ struct brcms_c_info *wlc);
+extern void wlc_phy_shim_detach(struct phy_shim_info *physhim);
+
+/* PHY to WL utility functions */
+extern struct wlapi_timer *wlapi_init_timer(struct phy_shim_info *physhim,
+ void (*fn) (struct brcms_phy *pi),
+ void *arg, const char *name);
+extern void wlapi_free_timer(struct wlapi_timer *t);
+extern void wlapi_add_timer(struct wlapi_timer *t, uint ms, int periodic);
+extern bool wlapi_del_timer(struct wlapi_timer *t);
+extern void wlapi_intrson(struct phy_shim_info *physhim);
+extern u32 wlapi_intrsoff(struct phy_shim_info *physhim);
+extern void wlapi_intrsrestore(struct phy_shim_info *physhim,
+ u32 macintmask);
+
+extern void wlapi_bmac_write_shm(struct phy_shim_info *physhim, uint offset,
+ u16 v);
+extern u16 wlapi_bmac_read_shm(struct phy_shim_info *physhim, uint offset);
+extern void wlapi_bmac_mhf(struct phy_shim_info *physhim, u8 idx,
+ u16 mask, u16 val, int bands);
+extern void wlapi_bmac_corereset(struct phy_shim_info *physhim, u32 flags);
+extern void wlapi_suspend_mac_and_wait(struct phy_shim_info *physhim);
+extern void wlapi_switch_macfreq(struct phy_shim_info *physhim, u8 spurmode);
+extern void wlapi_enable_mac(struct phy_shim_info *physhim);
+extern void wlapi_bmac_mctrl(struct phy_shim_info *physhim, u32 mask,
+ u32 val);
+extern void wlapi_bmac_phy_reset(struct phy_shim_info *physhim);
+extern void wlapi_bmac_bw_set(struct phy_shim_info *physhim, u16 bw);
+extern void wlapi_bmac_phyclk_fgc(struct phy_shim_info *physhim, bool clk);
+extern void wlapi_bmac_macphyclk_set(struct phy_shim_info *physhim, bool clk);
+extern void wlapi_bmac_core_phypll_ctl(struct phy_shim_info *physhim, bool on);
+extern void wlapi_bmac_core_phypll_reset(struct phy_shim_info *physhim);
+extern void wlapi_bmac_ucode_wake_override_phyreg_set(struct phy_shim_info *
+ physhim);
+extern void wlapi_bmac_ucode_wake_override_phyreg_clear(struct phy_shim_info *
+ physhim);
+extern void wlapi_bmac_write_template_ram(struct phy_shim_info *physhim, int o,
+ int len, void *buf);
+extern u16 wlapi_bmac_rate_shm_offset(struct phy_shim_info *physhim,
+ u8 rate);
+extern void wlapi_ucode_sample_init(struct phy_shim_info *physhim);
+extern void wlapi_copyfrom_objmem(struct phy_shim_info *physhim, uint,
+ void *buf, int, u32 sel);
+extern void wlapi_copyto_objmem(struct phy_shim_info *physhim, uint,
+ const void *buf, int, u32);
+
+extern void wlapi_high_update_phy_mode(struct phy_shim_info *physhim,
+ u32 phy_mode);
+extern u16 wlapi_bmac_get_txant(struct phy_shim_info *physhim);
+extern char *wlapi_getvar(struct phy_shim_info *physhim, enum brcms_srom_id id);
+extern int wlapi_getintvar(struct phy_shim_info *physhim,
+ enum brcms_srom_id id);
+
+#endif /* _BRCM_PHY_SHIM_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pmu.c b/drivers/net/wireless/brcm80211/brcmsmac/pmu.c
new file mode 100644
index 000000000000..3b36e3acfd74
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/pmu.c
@@ -0,0 +1,458 @@
+/*
+ * 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/delay.h>
+#include <linux/io.h>
+
+#include <brcm_hw_ids.h>
+#include <chipcommon.h>
+#include <brcmu_utils.h>
+#include "pub.h"
+#include "aiutils.h"
+#include "pmu.h"
+
+/*
+ * external LPO crystal frequency
+ */
+#define EXT_ILP_HZ 32768
+
+/*
+ * Duration for ILP clock frequency measurment in milliseconds
+ *
+ * remark: 1000 must be an integer multiple of this duration
+ */
+#define ILP_CALC_DUR 10
+
+/* Fields in pmucontrol */
+#define PCTL_ILP_DIV_MASK 0xffff0000
+#define PCTL_ILP_DIV_SHIFT 16
+#define PCTL_PLL_PLLCTL_UPD 0x00000400 /* rev 2 */
+#define PCTL_NOILP_ON_WAIT 0x00000200 /* rev 1 */
+#define PCTL_HT_REQ_EN 0x00000100
+#define PCTL_ALP_REQ_EN 0x00000080
+#define PCTL_XTALFREQ_MASK 0x0000007c
+#define PCTL_XTALFREQ_SHIFT 2
+#define PCTL_ILP_DIV_EN 0x00000002
+#define PCTL_LPO_SEL 0x00000001
+
+/* ILP clock */
+#define ILP_CLOCK 32000
+
+/* ALP clock on pre-PMU chips */
+#define ALP_CLOCK 20000000
+
+/* pmustatus */
+#define PST_EXTLPOAVAIL 0x0100
+#define PST_WDRESET 0x0080
+#define PST_INTPEND 0x0040
+#define PST_SBCLKST 0x0030
+#define PST_SBCLKST_ILP 0x0010
+#define PST_SBCLKST_ALP 0x0020
+#define PST_SBCLKST_HT 0x0030
+#define PST_ALPAVAIL 0x0008
+#define PST_HTAVAIL 0x0004
+#define PST_RESINIT 0x0003
+
+/* PMU resource bit position */
+#define PMURES_BIT(bit) (1 << (bit))
+
+/* PMU corerev and chip specific PLL controls.
+ * PMU<rev>_PLL<num>_XX where <rev> is PMU corerev and <num> is an arbitrary
+ * number to differentiate different PLLs controlled by the same PMU rev.
+ */
+/* pllcontrol registers:
+ * ndiv_pwrdn, pwrdn_ch<x>, refcomp_pwrdn, dly_ch<x>,
+ * p1div, p2div, _bypass_sdmod
+ */
+#define PMU1_PLL0_PLLCTL0 0
+#define PMU1_PLL0_PLLCTL1 1
+#define PMU1_PLL0_PLLCTL2 2
+#define PMU1_PLL0_PLLCTL3 3
+#define PMU1_PLL0_PLLCTL4 4
+#define PMU1_PLL0_PLLCTL5 5
+
+/* pmu XtalFreqRatio */
+#define PMU_XTALFREQ_REG_ILPCTR_MASK 0x00001FFF
+#define PMU_XTALFREQ_REG_MEASURE_MASK 0x80000000
+#define PMU_XTALFREQ_REG_MEASURE_SHIFT 31
+
+/* 4313 resources */
+#define RES4313_BB_PU_RSRC 0
+#define RES4313_ILP_REQ_RSRC 1
+#define RES4313_XTAL_PU_RSRC 2
+#define RES4313_ALP_AVAIL_RSRC 3
+#define RES4313_RADIO_PU_RSRC 4
+#define RES4313_BG_PU_RSRC 5
+#define RES4313_VREG1P4_PU_RSRC 6
+#define RES4313_AFE_PWRSW_RSRC 7
+#define RES4313_RX_PWRSW_RSRC 8
+#define RES4313_TX_PWRSW_RSRC 9
+#define RES4313_BB_PWRSW_RSRC 10
+#define RES4313_SYNTH_PWRSW_RSRC 11
+#define RES4313_MISC_PWRSW_RSRC 12
+#define RES4313_BB_PLL_PWRSW_RSRC 13
+#define RES4313_HT_AVAIL_RSRC 14
+#define RES4313_MACPHY_CLK_AVAIL_RSRC 15
+
+/* Determine min/max rsrc masks. Value 0 leaves hardware at default. */
+static void si_pmu_res_masks(struct si_pub *sih, u32 * pmin, u32 * pmax)
+{
+ u32 min_mask = 0, max_mask = 0;
+ uint rsrcs;
+
+ /* # resources */
+ rsrcs = (sih->pmucaps & PCAP_RC_MASK) >> PCAP_RC_SHIFT;
+
+ /* determine min/max rsrc masks */
+ switch (sih->chip) {
+ case BCM43224_CHIP_ID:
+ case BCM43225_CHIP_ID:
+ /* ??? */
+ break;
+
+ case BCM4313_CHIP_ID:
+ min_mask = PMURES_BIT(RES4313_BB_PU_RSRC) |
+ PMURES_BIT(RES4313_XTAL_PU_RSRC) |
+ PMURES_BIT(RES4313_ALP_AVAIL_RSRC) |
+ PMURES_BIT(RES4313_BB_PLL_PWRSW_RSRC);
+ max_mask = 0xffff;
+ break;
+ default:
+ break;
+ }
+
+ *pmin = min_mask;
+ *pmax = max_mask;
+}
+
+static void
+si_pmu_spuravoid_pllupdate(struct si_pub *sih, struct chipcregs __iomem *cc,
+ u8 spuravoid)
+{
+ u32 tmp = 0;
+
+ switch (sih->chip) {
+ case BCM43224_CHIP_ID:
+ case BCM43225_CHIP_ID:
+ if (spuravoid == 1) {
+ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL0);
+ W_REG(&cc->pllcontrol_data, 0x11500010);
+ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL1);
+ W_REG(&cc->pllcontrol_data, 0x000C0C06);
+ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL2);
+ W_REG(&cc->pllcontrol_data, 0x0F600a08);
+ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL3);
+ W_REG(&cc->pllcontrol_data, 0x00000000);
+ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL4);
+ W_REG(&cc->pllcontrol_data, 0x2001E920);
+ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL5);
+ W_REG(&cc->pllcontrol_data, 0x88888815);
+ } else {
+ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL0);
+ W_REG(&cc->pllcontrol_data, 0x11100010);
+ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL1);
+ W_REG(&cc->pllcontrol_data, 0x000c0c06);
+ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL2);
+ W_REG(&cc->pllcontrol_data, 0x03000a08);
+ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL3);
+ W_REG(&cc->pllcontrol_data, 0x00000000);
+ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL4);
+ W_REG(&cc->pllcontrol_data, 0x200005c0);
+ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL5);
+ W_REG(&cc->pllcontrol_data, 0x88888815);
+ }
+ tmp = 1 << 10;
+ break;
+
+ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL0);
+ W_REG(&cc->pllcontrol_data, 0x11100008);
+ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL1);
+ W_REG(&cc->pllcontrol_data, 0x0c000c06);
+ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL2);
+ W_REG(&cc->pllcontrol_data, 0x03000a08);
+ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL3);
+ W_REG(&cc->pllcontrol_data, 0x00000000);
+ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL4);
+ W_REG(&cc->pllcontrol_data, 0x200005c0);
+ W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL5);
+ W_REG(&cc->pllcontrol_data, 0x88888855);
+
+ tmp = 1 << 10;
+ break;
+
+ default:
+ /* bail out */
+ return;
+ }
+
+ tmp |= R_REG(&cc->pmucontrol);
+ W_REG(&cc->pmucontrol, tmp);
+}
+
+u16 si_pmu_fast_pwrup_delay(struct si_pub *sih)
+{
+ uint delay = PMU_MAX_TRANSITION_DLY;
+
+ switch (sih->chip) {
+ case BCM43224_CHIP_ID:
+ case BCM43225_CHIP_ID:
+ case BCM4313_CHIP_ID:
+ delay = 3700;
+ break;
+ default:
+ break;
+ }
+
+ return (u16) delay;
+}
+
+void si_pmu_sprom_enable(struct si_pub *sih, bool enable)
+{
+ struct chipcregs __iomem *cc;
+ uint origidx;
+
+ /* Remember original core before switch to chipc */
+ origidx = ai_coreidx(sih);
+ cc = ai_setcoreidx(sih, SI_CC_IDX);
+
+ /* Return to original core */
+ ai_setcoreidx(sih, origidx);
+}
+
+/* Read/write a chipcontrol reg */
+u32 si_pmu_chipcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val)
+{
+ ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, chipcontrol_addr),
+ ~0, reg);
+ return ai_corereg(sih, SI_CC_IDX,
+ offsetof(struct chipcregs, chipcontrol_data), mask,
+ val);
+}
+
+/* Read/write a regcontrol reg */
+u32 si_pmu_regcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val)
+{
+ ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, regcontrol_addr),
+ ~0, reg);
+ return ai_corereg(sih, SI_CC_IDX,
+ offsetof(struct chipcregs, regcontrol_data), mask,
+ val);
+}
+
+/* Read/write a pllcontrol reg */
+u32 si_pmu_pllcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val)
+{
+ ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, pllcontrol_addr),
+ ~0, reg);
+ return ai_corereg(sih, SI_CC_IDX,
+ offsetof(struct chipcregs, pllcontrol_data), mask,
+ val);
+}
+
+/* PMU PLL update */
+void si_pmu_pllupd(struct si_pub *sih)
+{
+ ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, pmucontrol),
+ PCTL_PLL_PLLCTL_UPD, PCTL_PLL_PLLCTL_UPD);
+}
+
+/* query alp/xtal clock frequency */
+u32 si_pmu_alp_clock(struct si_pub *sih)
+{
+ u32 clock = ALP_CLOCK;
+
+ /* bail out with default */
+ if (!(sih->cccaps & CC_CAP_PMU))
+ return clock;
+
+ switch (sih->chip) {
+ case BCM43224_CHIP_ID:
+ case BCM43225_CHIP_ID:
+ case BCM4313_CHIP_ID:
+ /* always 20Mhz */
+ clock = 20000 * 1000;
+ break;
+ default:
+ break;
+ }
+
+ return clock;
+}
+
+void si_pmu_spuravoid(struct si_pub *sih, u8 spuravoid)
+{
+ struct chipcregs __iomem *cc;
+ uint origidx, intr_val;
+
+ /* Remember original core before switch to chipc */
+ cc = (struct chipcregs __iomem *)
+ ai_switch_core(sih, CC_CORE_ID, &origidx, &intr_val);
+
+ /* update the pll changes */
+ si_pmu_spuravoid_pllupdate(sih, cc, spuravoid);
+
+ /* Return to original core */
+ ai_restore_core(sih, origidx, intr_val);
+}
+
+/* initialize PMU */
+void si_pmu_init(struct si_pub *sih)
+{
+ struct chipcregs __iomem *cc;
+ uint origidx;
+
+ /* Remember original core before switch to chipc */
+ origidx = ai_coreidx(sih);
+ cc = ai_setcoreidx(sih, SI_CC_IDX);
+
+ if (sih->pmurev == 1)
+ AND_REG(&cc->pmucontrol, ~PCTL_NOILP_ON_WAIT);
+ else if (sih->pmurev >= 2)
+ OR_REG(&cc->pmucontrol, PCTL_NOILP_ON_WAIT);
+
+ /* Return to original core */
+ ai_setcoreidx(sih, origidx);
+}
+
+/* initialize PMU chip controls and other chip level stuff */
+void si_pmu_chip_init(struct si_pub *sih)
+{
+ uint origidx;
+
+ /* Gate off SPROM clock and chip select signals */
+ si_pmu_sprom_enable(sih, false);
+
+ /* Remember original core */
+ origidx = ai_coreidx(sih);
+
+ /* Return to original core */
+ ai_setcoreidx(sih, origidx);
+}
+
+/* initialize PMU switch/regulators */
+void si_pmu_swreg_init(struct si_pub *sih)
+{
+}
+
+/* initialize PLL */
+void si_pmu_pll_init(struct si_pub *sih, uint xtalfreq)
+{
+ struct chipcregs __iomem *cc;
+ uint origidx;
+
+ /* Remember original core before switch to chipc */
+ origidx = ai_coreidx(sih);
+ cc = ai_setcoreidx(sih, SI_CC_IDX);
+
+ switch (sih->chip) {
+ case BCM4313_CHIP_ID:
+ case BCM43224_CHIP_ID:
+ case BCM43225_CHIP_ID:
+ /* ??? */
+ break;
+ default:
+ break;
+ }
+
+ /* Return to original core */
+ ai_setcoreidx(sih, origidx);
+}
+
+/* initialize PMU resources */
+void si_pmu_res_init(struct si_pub *sih)
+{
+ struct chipcregs __iomem *cc;
+ uint origidx;
+ u32 min_mask = 0, max_mask = 0;
+
+ /* Remember original core before switch to chipc */
+ origidx = ai_coreidx(sih);
+ cc = ai_setcoreidx(sih, SI_CC_IDX);
+
+ /* Determine min/max rsrc masks */
+ si_pmu_res_masks(sih, &min_mask, &max_mask);
+
+ /* It is required to program max_mask first and then min_mask */
+
+ /* Program max resource mask */
+
+ if (max_mask)
+ W_REG(&cc->max_res_mask, max_mask);
+
+ /* Program min resource mask */
+
+ if (min_mask)
+ W_REG(&cc->min_res_mask, min_mask);
+
+ /* Add some delay; allow resources to come up and settle. */
+ mdelay(2);
+
+ /* Return to original core */
+ ai_setcoreidx(sih, origidx);
+}
+
+u32 si_pmu_measure_alpclk(struct si_pub *sih)
+{
+ struct chipcregs __iomem *cc;
+ uint origidx;
+ u32 alp_khz;
+
+ if (sih->pmurev < 10)
+ return 0;
+
+ /* Remember original core before switch to chipc */
+ origidx = ai_coreidx(sih);
+ cc = ai_setcoreidx(sih, SI_CC_IDX);
+
+ if (R_REG(&cc->pmustatus) & PST_EXTLPOAVAIL) {
+ u32 ilp_ctr, alp_hz;
+
+ /*
+ * Enable the reg to measure the freq,
+ * in case it was disabled before
+ */
+ W_REG(&cc->pmu_xtalfreq,
+ 1U << PMU_XTALFREQ_REG_MEASURE_SHIFT);
+
+ /* Delay for well over 4 ILP clocks */
+ udelay(1000);
+
+ /* Read the latched number of ALP ticks per 4 ILP ticks */
+ ilp_ctr =
+ R_REG(&cc->pmu_xtalfreq) & PMU_XTALFREQ_REG_ILPCTR_MASK;
+
+ /*
+ * Turn off the PMU_XTALFREQ_REG_MEASURE_SHIFT
+ * bit to save power
+ */
+ W_REG(&cc->pmu_xtalfreq, 0);
+
+ /* Calculate ALP frequency */
+ alp_hz = (ilp_ctr * EXT_ILP_HZ) / 4;
+
+ /*
+ * Round to nearest 100KHz, and at
+ * the same time convert to KHz
+ */
+ alp_khz = (alp_hz + 50000) / 100000 * 100;
+ } else
+ alp_khz = 0;
+
+ /* Return to original core */
+ ai_setcoreidx(sih, origidx);
+
+ return alp_khz;
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pmu.h b/drivers/net/wireless/brcm80211/brcmsmac/pmu.h
new file mode 100644
index 000000000000..3a08c620640e
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/pmu.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_PMU_H_
+#define _BRCM_PMU_H_
+
+#include "types.h"
+
+extern u16 si_pmu_fast_pwrup_delay(struct si_pub *sih);
+extern void si_pmu_sprom_enable(struct si_pub *sih, bool enable);
+extern u32 si_pmu_chipcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val);
+extern u32 si_pmu_regcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val);
+extern u32 si_pmu_alp_clock(struct si_pub *sih);
+extern void si_pmu_pllupd(struct si_pub *sih);
+extern void si_pmu_spuravoid(struct si_pub *sih, u8 spuravoid);
+extern u32 si_pmu_pllcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val);
+extern void si_pmu_init(struct si_pub *sih);
+extern void si_pmu_chip_init(struct si_pub *sih);
+extern void si_pmu_pll_init(struct si_pub *sih, u32 xtalfreq);
+extern void si_pmu_res_init(struct si_pub *sih);
+extern void si_pmu_swreg_init(struct si_pub *sih);
+extern u32 si_pmu_measure_alpclk(struct si_pub *sih);
+
+#endif /* _BRCM_PMU_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
new file mode 100644
index 000000000000..37bb2dcc113f
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
@@ -0,0 +1,634 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_PUB_H_
+#define _BRCM_PUB_H_
+
+#include <brcmu_wifi.h>
+#include "types.h"
+#include "defs.h"
+
+enum brcms_srom_id {
+ BRCMS_SROM_NULL,
+ BRCMS_SROM_CONT,
+ BRCMS_SROM_AA2G,
+ BRCMS_SROM_AA5G,
+ BRCMS_SROM_AG0,
+ BRCMS_SROM_AG1,
+ BRCMS_SROM_AG2,
+ BRCMS_SROM_AG3,
+ BRCMS_SROM_ANTSWCTL2G,
+ BRCMS_SROM_ANTSWCTL5G,
+ BRCMS_SROM_ANTSWITCH,
+ BRCMS_SROM_BOARDFLAGS2,
+ BRCMS_SROM_BOARDFLAGS,
+ BRCMS_SROM_BOARDNUM,
+ BRCMS_SROM_BOARDREV,
+ BRCMS_SROM_BOARDTYPE,
+ BRCMS_SROM_BW40PO,
+ BRCMS_SROM_BWDUPPO,
+ BRCMS_SROM_BXA2G,
+ BRCMS_SROM_BXA5G,
+ BRCMS_SROM_CC,
+ BRCMS_SROM_CCK2GPO,
+ BRCMS_SROM_CCKBW202GPO,
+ BRCMS_SROM_CCKBW20UL2GPO,
+ BRCMS_SROM_CCODE,
+ BRCMS_SROM_CDDPO,
+ BRCMS_SROM_DEVID,
+ BRCMS_SROM_ET1MACADDR,
+ BRCMS_SROM_EXTPAGAIN2G,
+ BRCMS_SROM_EXTPAGAIN5G,
+ BRCMS_SROM_FREQOFFSET_CORR,
+ BRCMS_SROM_HW_IQCAL_EN,
+ BRCMS_SROM_IL0MACADDR,
+ BRCMS_SROM_IQCAL_SWP_DIS,
+ BRCMS_SROM_LEDBH0,
+ BRCMS_SROM_LEDBH1,
+ BRCMS_SROM_LEDBH2,
+ BRCMS_SROM_LEDBH3,
+ BRCMS_SROM_LEDDC,
+ BRCMS_SROM_LEGOFDM40DUPPO,
+ BRCMS_SROM_LEGOFDMBW202GPO,
+ BRCMS_SROM_LEGOFDMBW205GHPO,
+ BRCMS_SROM_LEGOFDMBW205GLPO,
+ BRCMS_SROM_LEGOFDMBW205GMPO,
+ BRCMS_SROM_LEGOFDMBW20UL2GPO,
+ BRCMS_SROM_LEGOFDMBW20UL5GHPO,
+ BRCMS_SROM_LEGOFDMBW20UL5GLPO,
+ BRCMS_SROM_LEGOFDMBW20UL5GMPO,
+ BRCMS_SROM_MACADDR,
+ BRCMS_SROM_MCS2GPO0,
+ BRCMS_SROM_MCS2GPO1,
+ BRCMS_SROM_MCS2GPO2,
+ BRCMS_SROM_MCS2GPO3,
+ BRCMS_SROM_MCS2GPO4,
+ BRCMS_SROM_MCS2GPO5,
+ BRCMS_SROM_MCS2GPO6,
+ BRCMS_SROM_MCS2GPO7,
+ BRCMS_SROM_MCS32PO,
+ BRCMS_SROM_MCS5GHPO0,
+ BRCMS_SROM_MCS5GHPO1,
+ BRCMS_SROM_MCS5GHPO2,
+ BRCMS_SROM_MCS5GHPO3,
+ BRCMS_SROM_MCS5GHPO4,
+ BRCMS_SROM_MCS5GHPO5,
+ BRCMS_SROM_MCS5GHPO6,
+ BRCMS_SROM_MCS5GHPO7,
+ BRCMS_SROM_MCS5GLPO0,
+ BRCMS_SROM_MCS5GLPO1,
+ BRCMS_SROM_MCS5GLPO2,
+ BRCMS_SROM_MCS5GLPO3,
+ BRCMS_SROM_MCS5GLPO4,
+ BRCMS_SROM_MCS5GLPO5,
+ BRCMS_SROM_MCS5GLPO6,
+ BRCMS_SROM_MCS5GLPO7,
+ BRCMS_SROM_MCS5GPO0,
+ BRCMS_SROM_MCS5GPO1,
+ BRCMS_SROM_MCS5GPO2,
+ BRCMS_SROM_MCS5GPO3,
+ BRCMS_SROM_MCS5GPO4,
+ BRCMS_SROM_MCS5GPO5,
+ BRCMS_SROM_MCS5GPO6,
+ BRCMS_SROM_MCS5GPO7,
+ BRCMS_SROM_MCSBW202GPO,
+ BRCMS_SROM_MCSBW205GHPO,
+ BRCMS_SROM_MCSBW205GLPO,
+ BRCMS_SROM_MCSBW205GMPO,
+ BRCMS_SROM_MCSBW20UL2GPO,
+ BRCMS_SROM_MCSBW20UL5GHPO,
+ BRCMS_SROM_MCSBW20UL5GLPO,
+ BRCMS_SROM_MCSBW20UL5GMPO,
+ BRCMS_SROM_MCSBW402GPO,
+ BRCMS_SROM_MCSBW405GHPO,
+ BRCMS_SROM_MCSBW405GLPO,
+ BRCMS_SROM_MCSBW405GMPO,
+ BRCMS_SROM_MEASPOWER,
+ BRCMS_SROM_OFDM2GPO,
+ BRCMS_SROM_OFDM5GHPO,
+ BRCMS_SROM_OFDM5GLPO,
+ BRCMS_SROM_OFDM5GPO,
+ BRCMS_SROM_OPO,
+ BRCMS_SROM_PA0B0,
+ BRCMS_SROM_PA0B1,
+ BRCMS_SROM_PA0B2,
+ BRCMS_SROM_PA0ITSSIT,
+ BRCMS_SROM_PA0MAXPWR,
+ BRCMS_SROM_PA1B0,
+ BRCMS_SROM_PA1B1,
+ BRCMS_SROM_PA1B2,
+ BRCMS_SROM_PA1HIB0,
+ BRCMS_SROM_PA1HIB1,
+ BRCMS_SROM_PA1HIB2,
+ BRCMS_SROM_PA1HIMAXPWR,
+ BRCMS_SROM_PA1ITSSIT,
+ BRCMS_SROM_PA1LOB0,
+ BRCMS_SROM_PA1LOB1,
+ BRCMS_SROM_PA1LOB2,
+ BRCMS_SROM_PA1LOMAXPWR,
+ BRCMS_SROM_PA1MAXPWR,
+ BRCMS_SROM_PDETRANGE2G,
+ BRCMS_SROM_PDETRANGE5G,
+ BRCMS_SROM_PHYCAL_TEMPDELTA,
+ BRCMS_SROM_RAWTEMPSENSE,
+ BRCMS_SROM_REGREV,
+ BRCMS_SROM_REV,
+ BRCMS_SROM_RSSISAV2G,
+ BRCMS_SROM_RSSISAV5G,
+ BRCMS_SROM_RSSISMC2G,
+ BRCMS_SROM_RSSISMC5G,
+ BRCMS_SROM_RSSISMF2G,
+ BRCMS_SROM_RSSISMF5G,
+ BRCMS_SROM_RXCHAIN,
+ BRCMS_SROM_RXPO2G,
+ BRCMS_SROM_RXPO5G,
+ BRCMS_SROM_STBCPO,
+ BRCMS_SROM_TEMPCORRX,
+ BRCMS_SROM_TEMPOFFSET,
+ BRCMS_SROM_TEMPSENSE_OPTION,
+ BRCMS_SROM_TEMPSENSE_SLOPE,
+ BRCMS_SROM_TEMPTHRESH,
+ BRCMS_SROM_TRI2G,
+ BRCMS_SROM_TRI5GH,
+ BRCMS_SROM_TRI5GL,
+ BRCMS_SROM_TRI5G,
+ BRCMS_SROM_TRISO2G,
+ BRCMS_SROM_TRISO5G,
+ BRCMS_SROM_TSSIPOS2G,
+ BRCMS_SROM_TSSIPOS5G,
+ BRCMS_SROM_TXCHAIN,
+ BRCMS_SROM_TXPID2GA0,
+ BRCMS_SROM_TXPID2GA1,
+ BRCMS_SROM_TXPID2GA2,
+ BRCMS_SROM_TXPID2GA3,
+ BRCMS_SROM_TXPID5GA0,
+ BRCMS_SROM_TXPID5GA1,
+ BRCMS_SROM_TXPID5GA2,
+ BRCMS_SROM_TXPID5GA3,
+ BRCMS_SROM_TXPID5GHA0,
+ BRCMS_SROM_TXPID5GHA1,
+ BRCMS_SROM_TXPID5GHA2,
+ BRCMS_SROM_TXPID5GHA3,
+ BRCMS_SROM_TXPID5GLA0,
+ BRCMS_SROM_TXPID5GLA1,
+ BRCMS_SROM_TXPID5GLA2,
+ BRCMS_SROM_TXPID5GLA3,
+ /*
+ * per-path identifiers (see srom.c)
+ */
+ BRCMS_SROM_ITT2GA0,
+ BRCMS_SROM_ITT2GA1,
+ BRCMS_SROM_ITT2GA2,
+ BRCMS_SROM_ITT2GA3,
+ BRCMS_SROM_ITT5GA0,
+ BRCMS_SROM_ITT5GA1,
+ BRCMS_SROM_ITT5GA2,
+ BRCMS_SROM_ITT5GA3,
+ BRCMS_SROM_MAXP2GA0,
+ BRCMS_SROM_MAXP2GA1,
+ BRCMS_SROM_MAXP2GA2,
+ BRCMS_SROM_MAXP2GA3,
+ BRCMS_SROM_MAXP5GA0,
+ BRCMS_SROM_MAXP5GA1,
+ BRCMS_SROM_MAXP5GA2,
+ BRCMS_SROM_MAXP5GA3,
+ BRCMS_SROM_MAXP5GHA0,
+ BRCMS_SROM_MAXP5GHA1,
+ BRCMS_SROM_MAXP5GHA2,
+ BRCMS_SROM_MAXP5GHA3,
+ BRCMS_SROM_MAXP5GLA0,
+ BRCMS_SROM_MAXP5GLA1,
+ BRCMS_SROM_MAXP5GLA2,
+ BRCMS_SROM_MAXP5GLA3,
+ BRCMS_SROM_PA2GW0A0,
+ BRCMS_SROM_PA2GW0A1,
+ BRCMS_SROM_PA2GW0A2,
+ BRCMS_SROM_PA2GW0A3,
+ BRCMS_SROM_PA2GW1A0,
+ BRCMS_SROM_PA2GW1A1,
+ BRCMS_SROM_PA2GW1A2,
+ BRCMS_SROM_PA2GW1A3,
+ BRCMS_SROM_PA2GW2A0,
+ BRCMS_SROM_PA2GW2A1,
+ BRCMS_SROM_PA2GW2A2,
+ BRCMS_SROM_PA2GW2A3,
+ BRCMS_SROM_PA2GW3A0,
+ BRCMS_SROM_PA2GW3A1,
+ BRCMS_SROM_PA2GW3A2,
+ BRCMS_SROM_PA2GW3A3,
+ BRCMS_SROM_PA5GHW0A0,
+ BRCMS_SROM_PA5GHW0A1,
+ BRCMS_SROM_PA5GHW0A2,
+ BRCMS_SROM_PA5GHW0A3,
+ BRCMS_SROM_PA5GHW1A0,
+ BRCMS_SROM_PA5GHW1A1,
+ BRCMS_SROM_PA5GHW1A2,
+ BRCMS_SROM_PA5GHW1A3,
+ BRCMS_SROM_PA5GHW2A0,
+ BRCMS_SROM_PA5GHW2A1,
+ BRCMS_SROM_PA5GHW2A2,
+ BRCMS_SROM_PA5GHW2A3,
+ BRCMS_SROM_PA5GHW3A0,
+ BRCMS_SROM_PA5GHW3A1,
+ BRCMS_SROM_PA5GHW3A2,
+ BRCMS_SROM_PA5GHW3A3,
+ BRCMS_SROM_PA5GLW0A0,
+ BRCMS_SROM_PA5GLW0A1,
+ BRCMS_SROM_PA5GLW0A2,
+ BRCMS_SROM_PA5GLW0A3,
+ BRCMS_SROM_PA5GLW1A0,
+ BRCMS_SROM_PA5GLW1A1,
+ BRCMS_SROM_PA5GLW1A2,
+ BRCMS_SROM_PA5GLW1A3,
+ BRCMS_SROM_PA5GLW2A0,
+ BRCMS_SROM_PA5GLW2A1,
+ BRCMS_SROM_PA5GLW2A2,
+ BRCMS_SROM_PA5GLW2A3,
+ BRCMS_SROM_PA5GLW3A0,
+ BRCMS_SROM_PA5GLW3A1,
+ BRCMS_SROM_PA5GLW3A2,
+ BRCMS_SROM_PA5GLW3A3,
+ BRCMS_SROM_PA5GW0A0,
+ BRCMS_SROM_PA5GW0A1,
+ BRCMS_SROM_PA5GW0A2,
+ BRCMS_SROM_PA5GW0A3,
+ BRCMS_SROM_PA5GW1A0,
+ BRCMS_SROM_PA5GW1A1,
+ BRCMS_SROM_PA5GW1A2,
+ BRCMS_SROM_PA5GW1A3,
+ BRCMS_SROM_PA5GW2A0,
+ BRCMS_SROM_PA5GW2A1,
+ BRCMS_SROM_PA5GW2A2,
+ BRCMS_SROM_PA5GW2A3,
+ BRCMS_SROM_PA5GW3A0,
+ BRCMS_SROM_PA5GW3A1,
+ BRCMS_SROM_PA5GW3A2,
+ BRCMS_SROM_PA5GW3A3,
+};
+
+#define BRCMS_NUMRATES 16 /* max # of rates in a rateset */
+#define D11_PHY_HDR_LEN 6 /* Phy header length - 6 bytes */
+
+/* phy types */
+#define PHY_TYPE_A 0 /* Phy type A */
+#define PHY_TYPE_G 2 /* Phy type G */
+#define PHY_TYPE_N 4 /* Phy type N */
+#define PHY_TYPE_LP 5 /* Phy type Low Power A/B/G */
+#define PHY_TYPE_SSN 6 /* Phy type Single Stream N */
+#define PHY_TYPE_LCN 8 /* Phy type Single Stream N */
+#define PHY_TYPE_LCNXN 9 /* Phy type 2-stream N */
+#define PHY_TYPE_HT 7 /* Phy type 3-Stream N */
+
+/* bw */
+#define BRCMS_10_MHZ 10 /* 10Mhz nphy channel bandwidth */
+#define BRCMS_20_MHZ 20 /* 20Mhz nphy channel bandwidth */
+#define BRCMS_40_MHZ 40 /* 40Mhz nphy channel bandwidth */
+
+#define BRCMS_RSSI_MINVAL -200 /* Low value, e.g. for forcing roam */
+#define BRCMS_RSSI_NO_SIGNAL -91 /* NDIS RSSI link quality cutoffs */
+#define BRCMS_RSSI_VERY_LOW -80 /* Very low quality cutoffs */
+#define BRCMS_RSSI_LOW -70 /* Low quality cutoffs */
+#define BRCMS_RSSI_GOOD -68 /* Good quality cutoffs */
+#define BRCMS_RSSI_VERY_GOOD -58 /* Very good quality cutoffs */
+#define BRCMS_RSSI_EXCELLENT -57 /* Excellent quality cutoffs */
+
+/* a large TX Power as an init value to factor out of min() calculations,
+ * keep low enough to fit in an s8, units are .25 dBm
+ */
+#define BRCMS_TXPWR_MAX (127) /* ~32 dBm = 1,500 mW */
+
+/* rate related definitions */
+#define BRCMS_RATE_FLAG 0x80 /* Flag to indicate it is a basic rate */
+#define BRCMS_RATE_MASK 0x7f /* Rate value mask w/o basic rate flag */
+
+/* legacy rx Antenna diversity for SISO rates */
+#define ANT_RX_DIV_FORCE_0 0 /* Use antenna 0 */
+#define ANT_RX_DIV_FORCE_1 1 /* Use antenna 1 */
+#define ANT_RX_DIV_START_1 2 /* Choose starting with 1 */
+#define ANT_RX_DIV_START_0 3 /* Choose starting with 0 */
+#define ANT_RX_DIV_ENABLE 3 /* APHY bbConfig Enable RX Diversity */
+/* default antdiv setting */
+#define ANT_RX_DIV_DEF ANT_RX_DIV_START_0
+
+/* legacy rx Antenna diversity for SISO rates */
+/* Tx on antenna 0, "legacy term Main" */
+#define ANT_TX_FORCE_0 0
+/* Tx on antenna 1, "legacy term Aux" */
+#define ANT_TX_FORCE_1 1
+/* Tx on phy's last good Rx antenna */
+#define ANT_TX_LAST_RX 3
+/* driver's default tx antenna setting */
+#define ANT_TX_DEF 3
+
+/* Tx Chain values */
+/* def bitmap of txchain */
+#define TXCHAIN_DEF 0x1
+/* default bitmap of tx chains for nphy */
+#define TXCHAIN_DEF_NPHY 0x3
+/* default bitmap of tx chains for nphy */
+#define TXCHAIN_DEF_HTPHY 0x7
+/* def bitmap of rxchain */
+#define RXCHAIN_DEF 0x1
+/* default bitmap of rx chains for nphy */
+#define RXCHAIN_DEF_NPHY 0x3
+/* default bitmap of rx chains for nphy */
+#define RXCHAIN_DEF_HTPHY 0x7
+/* no antenna switch */
+#define ANTSWITCH_NONE 0
+/* antenna switch on 4321CB2, 2of3 */
+#define ANTSWITCH_TYPE_1 1
+/* antenna switch on 4321MPCI, 2of3 */
+#define ANTSWITCH_TYPE_2 2
+/* antenna switch on 4322, 2of3 */
+#define ANTSWITCH_TYPE_3 3
+
+#define RXBUFSZ PKTBUFSZ
+
+#define MAX_STREAMS_SUPPORTED 4 /* max number of streams supported */
+
+struct brcm_rateset {
+ /* # rates in this set */
+ u32 count;
+ /* rates in 500kbps units w/hi bit set if basic */
+ u8 rates[WL_NUMRATES];
+};
+
+struct brcms_c_rateset {
+ uint count; /* number of rates in rates[] */
+ /* rates in 500kbps units w/hi bit set if basic */
+ u8 rates[BRCMS_NUMRATES];
+ u8 htphy_membership; /* HT PHY Membership */
+ u8 mcs[MCSSET_LEN]; /* supported mcs index bit map */
+};
+
+/* All the HT-specific default advertised capabilities (including AMPDU)
+ * should be grouped here at one place
+ */
+#define AMPDU_DEF_MPDU_DENSITY 6 /* default mpdu density (110 ==> 4us) */
+
+/* wlc internal bss_info */
+struct brcms_bss_info {
+ u8 BSSID[ETH_ALEN]; /* network BSSID */
+ u16 flags; /* flags for internal attributes */
+ u8 SSID_len; /* the length of SSID */
+ u8 SSID[32]; /* SSID string */
+ s16 RSSI; /* receive signal strength (in dBm) */
+ s16 SNR; /* receive signal SNR in dB */
+ u16 beacon_period; /* units are Kusec */
+ u16 chanspec; /* Channel num, bw, ctrl_sb and band */
+ struct brcms_c_rateset rateset; /* supported rates */
+};
+
+#define MAC80211_PROMISC_BCNS (1 << 0)
+#define MAC80211_SCAN (1 << 1)
+
+/*
+ * Public portion of common driver state structure.
+ * The wlc handle points at this.
+ */
+struct brcms_pub {
+ struct brcms_c_info *wlc;
+ struct ieee80211_hw *ieee_hw;
+ struct scb_ampdu *global_ampdu;
+ uint mac80211_state;
+ uint unit; /* device instance number */
+ uint corerev; /* core revision */
+ struct si_pub *sih; /* SI handle (cookie for siutils calls) */
+ bool up; /* interface up and running */
+ bool hw_off; /* HW is off */
+ bool hw_up; /* one time hw up/down */
+ bool _piomode; /* true if pio mode */
+ uint _nbands; /* # bands supported */
+ uint now; /* # elapsed seconds */
+
+ bool promisc; /* promiscuous destination address */
+ bool delayed_down; /* down delayed */
+ bool associated; /* true:part of [I]BSS, false: not */
+ /* (union of stas_associated, aps_associated) */
+ bool _ampdu; /* ampdu enabled or not */
+ u8 _n_enab; /* bitmap of 11N + HT support */
+
+ u8 cur_etheraddr[ETH_ALEN]; /* our local ethernet address */
+
+ int bcmerror; /* last bcm error */
+
+ u32 radio_disabled; /* bit vector for radio disabled reasons */
+
+ u16 boardrev; /* version # of particular board */
+ u8 sromrev; /* version # of the srom */
+ char srom_ccode[BRCM_CNTRY_BUF_SZ]; /* Country Code in SROM */
+ u32 boardflags; /* Board specific flags from srom */
+ u32 boardflags2; /* More board flags if sromrev >= 4 */
+ bool phy_11ncapable; /* the PHY/HW is capable of 802.11N */
+
+ struct wl_cnt *_cnt; /* low-level counters in driver */
+};
+
+enum wlc_par_id {
+ IOV_MPC = 1,
+ IOV_RTSTHRESH,
+ IOV_QTXPOWER,
+ IOV_BCN_LI_BCN /* Beacon listen interval in # of beacons */
+};
+
+/***********************************************
+ * Feature-related macros to optimize out code *
+ * *********************************************
+ */
+
+#define ENAB_1x1 0x01
+#define ENAB_2x2 0x02
+#define ENAB_3x3 0x04
+#define ENAB_4x4 0x08
+#define SUPPORT_11N (ENAB_1x1|ENAB_2x2)
+#define SUPPORT_HT (ENAB_1x1|ENAB_2x2|ENAB_3x3)
+
+/* WL11N Support */
+#define AMPDU_AGG_HOST 1
+
+/* pri is priority encoded in the packet. This maps the Packet priority to
+ * enqueue precedence as defined in wlc_prec_map
+ */
+extern const u8 wlc_prio2prec_map[];
+#define BRCMS_PRIO_TO_PREC(pri) wlc_prio2prec_map[(pri) & 7]
+
+#define BRCMS_PREC_COUNT 16 /* Max precedence level implemented */
+
+/* Mask to describe all precedence levels */
+#define BRCMS_PREC_BMP_ALL MAXBITVAL(BRCMS_PREC_COUNT)
+
+/*
+ * This maps priority to one precedence higher - Used by PS-Poll response
+ * packets to simulate enqueue-at-head operation, but still maintain the
+ * order on the queue
+ */
+#define BRCMS_PRIO_TO_HI_PREC(pri) min(BRCMS_PRIO_TO_PREC(pri) + 1,\
+ BRCMS_PREC_COUNT - 1)
+
+/* Define a bitmap of precedences comprised by each AC */
+#define BRCMS_PREC_BMP_AC_BE (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_BE)) | \
+ NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_BE)) | \
+ NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_EE)) | \
+ NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_EE)))
+#define BRCMS_PREC_BMP_AC_BK (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_BK)) | \
+ NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_BK)) | \
+ NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_NONE)) | \
+ NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_NONE)))
+#define BRCMS_PREC_BMP_AC_VI (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_CL)) | \
+ NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_CL)) | \
+ NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_VI)) | \
+ NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_VI)))
+#define BRCMS_PREC_BMP_AC_VO (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_VO)) | \
+ NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_VO)) | \
+ NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_NC)) | \
+ NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_NC)))
+
+/* network protection config */
+#define BRCMS_PROT_G_SPEC 1 /* SPEC g protection */
+#define BRCMS_PROT_G_OVR 2 /* SPEC g prot override */
+#define BRCMS_PROT_G_USER 3 /* gmode specified by user */
+#define BRCMS_PROT_OVERLAP 4 /* overlap */
+#define BRCMS_PROT_N_USER 10 /* nmode specified by user */
+#define BRCMS_PROT_N_CFG 11 /* n protection */
+#define BRCMS_PROT_N_CFG_OVR 12 /* n protection override */
+#define BRCMS_PROT_N_NONGF 13 /* non-GF protection */
+#define BRCMS_PROT_N_NONGF_OVR 14 /* non-GF protection override */
+#define BRCMS_PROT_N_PAM_OVR 15 /* n preamble override */
+#define BRCMS_PROT_N_OBSS 16 /* non-HT OBSS present */
+
+/*
+ * 54g modes (basic bits may still be overridden)
+ *
+ * GMODE_LEGACY_B
+ * Rateset: 1b, 2b, 5.5, 11
+ * Preamble: Long
+ * Shortslot: Off
+ * GMODE_AUTO
+ * Rateset: 1b, 2b, 5.5b, 11b, 18, 24, 36, 54
+ * Extended Rateset: 6, 9, 12, 48
+ * Preamble: Long
+ * Shortslot: Auto
+ * GMODE_ONLY
+ * Rateset: 1b, 2b, 5.5b, 11b, 18, 24b, 36, 54
+ * Extended Rateset: 6b, 9, 12b, 48
+ * Preamble: Short required
+ * Shortslot: Auto
+ * GMODE_B_DEFERRED
+ * Rateset: 1b, 2b, 5.5b, 11b, 18, 24, 36, 54
+ * Extended Rateset: 6, 9, 12, 48
+ * Preamble: Long
+ * Shortslot: On
+ * GMODE_PERFORMANCE
+ * Rateset: 1b, 2b, 5.5b, 6b, 9, 11b, 12b, 18, 24b, 36, 48, 54
+ * Preamble: Short required
+ * Shortslot: On and required
+ * GMODE_LRS
+ * Rateset: 1b, 2b, 5.5b, 11b
+ * Extended Rateset: 6, 9, 12, 18, 24, 36, 48, 54
+ * Preamble: Long
+ * Shortslot: Auto
+ */
+#define GMODE_LEGACY_B 0
+#define GMODE_AUTO 1
+#define GMODE_ONLY 2
+#define GMODE_B_DEFERRED 3
+#define GMODE_PERFORMANCE 4
+#define GMODE_LRS 5
+#define GMODE_MAX 6
+
+/* MCS values greater than this enable multiple streams */
+#define HIGHEST_SINGLE_STREAM_MCS 7
+
+#define MAXBANDS 2 /* Maximum #of bands */
+
+/* max number of antenna configurations */
+#define ANT_SELCFG_MAX 4
+
+struct brcms_antselcfg {
+ u8 ant_config[ANT_SELCFG_MAX]; /* antenna configuration */
+ u8 num_antcfg; /* number of available antenna configurations */
+};
+
+/* common functions for every port */
+extern struct brcms_c_info *
+brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit,
+ bool piomode, void __iomem *regsva, struct pci_dev *btparam,
+ uint *perr);
+extern uint brcms_c_detach(struct brcms_c_info *wlc);
+extern int brcms_c_up(struct brcms_c_info *wlc);
+extern uint brcms_c_down(struct brcms_c_info *wlc);
+
+extern bool brcms_c_chipmatch(u16 vendor, u16 device);
+extern void brcms_c_init(struct brcms_c_info *wlc);
+extern void brcms_c_reset(struct brcms_c_info *wlc);
+
+extern void brcms_c_intrson(struct brcms_c_info *wlc);
+extern u32 brcms_c_intrsoff(struct brcms_c_info *wlc);
+extern void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask);
+extern bool brcms_c_intrsupd(struct brcms_c_info *wlc);
+extern bool brcms_c_isr(struct brcms_c_info *wlc, bool *wantdpc);
+extern bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded);
+extern void brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc,
+ struct sk_buff *sdu,
+ struct ieee80211_hw *hw);
+extern bool brcms_c_aggregatable(struct brcms_c_info *wlc, u8 tid);
+extern void brcms_c_protection_upd(struct brcms_c_info *wlc, uint idx,
+ int val);
+extern int brcms_c_get_header_len(void);
+extern void brcms_c_set_addrmatch(struct brcms_c_info *wlc,
+ int match_reg_offset,
+ const u8 *addr);
+extern void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
+ const struct ieee80211_tx_queue_params *arg,
+ bool suspend);
+extern struct brcms_pub *brcms_c_pub(struct brcms_c_info *wlc);
+extern void brcms_c_ampdu_flush(struct brcms_c_info *wlc,
+ struct ieee80211_sta *sta, u16 tid);
+extern void brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid,
+ u8 ba_wsize, uint max_rx_ampdu_bytes);
+extern char *getvar(struct si_pub *sih, enum brcms_srom_id id);
+extern int getintvar(struct si_pub *sih, enum brcms_srom_id id);
+extern int brcms_c_module_register(struct brcms_pub *pub,
+ const char *name, struct brcms_info *hdl,
+ int (*down_fn)(void *handle));
+extern int brcms_c_module_unregister(struct brcms_pub *pub, const char *name,
+ struct brcms_info *hdl);
+extern void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc);
+extern void brcms_c_enable_mac(struct brcms_c_info *wlc);
+extern void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state);
+extern void brcms_c_scan_start(struct brcms_c_info *wlc);
+extern void brcms_c_scan_stop(struct brcms_c_info *wlc);
+extern int brcms_c_get_curband(struct brcms_c_info *wlc);
+extern void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc,
+ bool drop);
+extern int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel);
+extern int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl);
+extern void brcms_c_get_current_rateset(struct brcms_c_info *wlc,
+ struct brcm_rateset *currs);
+extern int brcms_c_set_rateset(struct brcms_c_info *wlc,
+ struct brcm_rateset *rs);
+extern int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period);
+extern u16 brcms_c_get_phy_type(struct brcms_c_info *wlc, int phyidx);
+extern void brcms_c_set_shortslot_override(struct brcms_c_info *wlc,
+ s8 sslot_override);
+extern void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc,
+ u8 interval);
+extern int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr);
+extern int brcms_c_get_tx_power(struct brcms_c_info *wlc);
+extern void brcms_c_set_radio_mpc(struct brcms_c_info *wlc, bool mpc);
+extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc);
+
+#endif /* _BRCM_PUB_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/rate.c b/drivers/net/wireless/brcm80211/brcmsmac/rate.c
new file mode 100644
index 000000000000..0a0c0ad4f96f
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/rate.c
@@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 2010 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 <brcmu_wifi.h>
+#include <brcmu_utils.h>
+
+#include "d11.h"
+#include "pub.h"
+#include "rate.h"
+
+/*
+ * Rate info per rate: It tells whether a rate is ofdm or not and its phy_rate
+ * value
+ */
+const u8 rate_info[BRCM_MAXRATE + 1] = {
+ /* 0 1 2 3 4 5 6 7 8 9 */
+/* 0 */ 0x00, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 10 */ 0x00, 0x37, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x00,
+/* 20 */ 0x00, 0x00, 0x6e, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00,
+/* 40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00,
+/* 50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 70 */ 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
+/* 100 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c
+};
+
+/* rates are in units of Kbps */
+const struct brcms_mcs_info mcs_table[MCS_TABLE_SIZE] = {
+ /* MCS 0: SS 1, MOD: BPSK, CR 1/2 */
+ {6500, 13500, CEIL(6500 * 10, 9), CEIL(13500 * 10, 9), 0x00,
+ BRCM_RATE_6M},
+ /* MCS 1: SS 1, MOD: QPSK, CR 1/2 */
+ {13000, 27000, CEIL(13000 * 10, 9), CEIL(27000 * 10, 9), 0x08,
+ BRCM_RATE_12M},
+ /* MCS 2: SS 1, MOD: QPSK, CR 3/4 */
+ {19500, 40500, CEIL(19500 * 10, 9), CEIL(40500 * 10, 9), 0x0A,
+ BRCM_RATE_18M},
+ /* MCS 3: SS 1, MOD: 16QAM, CR 1/2 */
+ {26000, 54000, CEIL(26000 * 10, 9), CEIL(54000 * 10, 9), 0x10,
+ BRCM_RATE_24M},
+ /* MCS 4: SS 1, MOD: 16QAM, CR 3/4 */
+ {39000, 81000, CEIL(39000 * 10, 9), CEIL(81000 * 10, 9), 0x12,
+ BRCM_RATE_36M},
+ /* MCS 5: SS 1, MOD: 64QAM, CR 2/3 */
+ {52000, 108000, CEIL(52000 * 10, 9), CEIL(108000 * 10, 9), 0x19,
+ BRCM_RATE_48M},
+ /* MCS 6: SS 1, MOD: 64QAM, CR 3/4 */
+ {58500, 121500, CEIL(58500 * 10, 9), CEIL(121500 * 10, 9), 0x1A,
+ BRCM_RATE_54M},
+ /* MCS 7: SS 1, MOD: 64QAM, CR 5/6 */
+ {65000, 135000, CEIL(65000 * 10, 9), CEIL(135000 * 10, 9), 0x1C,
+ BRCM_RATE_54M},
+ /* MCS 8: SS 2, MOD: BPSK, CR 1/2 */
+ {13000, 27000, CEIL(13000 * 10, 9), CEIL(27000 * 10, 9), 0x40,
+ BRCM_RATE_6M},
+ /* MCS 9: SS 2, MOD: QPSK, CR 1/2 */
+ {26000, 54000, CEIL(26000 * 10, 9), CEIL(54000 * 10, 9), 0x48,
+ BRCM_RATE_12M},
+ /* MCS 10: SS 2, MOD: QPSK, CR 3/4 */
+ {39000, 81000, CEIL(39000 * 10, 9), CEIL(81000 * 10, 9), 0x4A,
+ BRCM_RATE_18M},
+ /* MCS 11: SS 2, MOD: 16QAM, CR 1/2 */
+ {52000, 108000, CEIL(52000 * 10, 9), CEIL(108000 * 10, 9), 0x50,
+ BRCM_RATE_24M},
+ /* MCS 12: SS 2, MOD: 16QAM, CR 3/4 */
+ {78000, 162000, CEIL(78000 * 10, 9), CEIL(162000 * 10, 9), 0x52,
+ BRCM_RATE_36M},
+ /* MCS 13: SS 2, MOD: 64QAM, CR 2/3 */
+ {104000, 216000, CEIL(104000 * 10, 9), CEIL(216000 * 10, 9), 0x59,
+ BRCM_RATE_48M},
+ /* MCS 14: SS 2, MOD: 64QAM, CR 3/4 */
+ {117000, 243000, CEIL(117000 * 10, 9), CEIL(243000 * 10, 9), 0x5A,
+ BRCM_RATE_54M},
+ /* MCS 15: SS 2, MOD: 64QAM, CR 5/6 */
+ {130000, 270000, CEIL(130000 * 10, 9), CEIL(270000 * 10, 9), 0x5C,
+ BRCM_RATE_54M},
+ /* MCS 16: SS 3, MOD: BPSK, CR 1/2 */
+ {19500, 40500, CEIL(19500 * 10, 9), CEIL(40500 * 10, 9), 0x80,
+ BRCM_RATE_6M},
+ /* MCS 17: SS 3, MOD: QPSK, CR 1/2 */
+ {39000, 81000, CEIL(39000 * 10, 9), CEIL(81000 * 10, 9), 0x88,
+ BRCM_RATE_12M},
+ /* MCS 18: SS 3, MOD: QPSK, CR 3/4 */
+ {58500, 121500, CEIL(58500 * 10, 9), CEIL(121500 * 10, 9), 0x8A,
+ BRCM_RATE_18M},
+ /* MCS 19: SS 3, MOD: 16QAM, CR 1/2 */
+ {78000, 162000, CEIL(78000 * 10, 9), CEIL(162000 * 10, 9), 0x90,
+ BRCM_RATE_24M},
+ /* MCS 20: SS 3, MOD: 16QAM, CR 3/4 */
+ {117000, 243000, CEIL(117000 * 10, 9), CEIL(243000 * 10, 9), 0x92,
+ BRCM_RATE_36M},
+ /* MCS 21: SS 3, MOD: 64QAM, CR 2/3 */
+ {156000, 324000, CEIL(156000 * 10, 9), CEIL(324000 * 10, 9), 0x99,
+ BRCM_RATE_48M},
+ /* MCS 22: SS 3, MOD: 64QAM, CR 3/4 */
+ {175500, 364500, CEIL(175500 * 10, 9), CEIL(364500 * 10, 9), 0x9A,
+ BRCM_RATE_54M},
+ /* MCS 23: SS 3, MOD: 64QAM, CR 5/6 */
+ {195000, 405000, CEIL(195000 * 10, 9), CEIL(405000 * 10, 9), 0x9B,
+ BRCM_RATE_54M},
+ /* MCS 24: SS 4, MOD: BPSK, CR 1/2 */
+ {26000, 54000, CEIL(26000 * 10, 9), CEIL(54000 * 10, 9), 0xC0,
+ BRCM_RATE_6M},
+ /* MCS 25: SS 4, MOD: QPSK, CR 1/2 */
+ {52000, 108000, CEIL(52000 * 10, 9), CEIL(108000 * 10, 9), 0xC8,
+ BRCM_RATE_12M},
+ /* MCS 26: SS 4, MOD: QPSK, CR 3/4 */
+ {78000, 162000, CEIL(78000 * 10, 9), CEIL(162000 * 10, 9), 0xCA,
+ BRCM_RATE_18M},
+ /* MCS 27: SS 4, MOD: 16QAM, CR 1/2 */
+ {104000, 216000, CEIL(104000 * 10, 9), CEIL(216000 * 10, 9), 0xD0,
+ BRCM_RATE_24M},
+ /* MCS 28: SS 4, MOD: 16QAM, CR 3/4 */
+ {156000, 324000, CEIL(156000 * 10, 9), CEIL(324000 * 10, 9), 0xD2,
+ BRCM_RATE_36M},
+ /* MCS 29: SS 4, MOD: 64QAM, CR 2/3 */
+ {208000, 432000, CEIL(208000 * 10, 9), CEIL(432000 * 10, 9), 0xD9,
+ BRCM_RATE_48M},
+ /* MCS 30: SS 4, MOD: 64QAM, CR 3/4 */
+ {234000, 486000, CEIL(234000 * 10, 9), CEIL(486000 * 10, 9), 0xDA,
+ BRCM_RATE_54M},
+ /* MCS 31: SS 4, MOD: 64QAM, CR 5/6 */
+ {260000, 540000, CEIL(260000 * 10, 9), CEIL(540000 * 10, 9), 0xDB,
+ BRCM_RATE_54M},
+ /* MCS 32: SS 1, MOD: BPSK, CR 1/2 */
+ {0, 6000, 0, CEIL(6000 * 10, 9), 0x00, BRCM_RATE_6M},
+};
+
+/*
+ * phycfg for legacy OFDM frames: code rate, modulation scheme, spatial streams
+ * Number of spatial streams: always 1 other fields: refer to table 78 of
+ * section 17.3.2.2 of the original .11a standard
+ */
+struct legacy_phycfg {
+ u32 rate_ofdm; /* ofdm mac rate */
+ /* phy ctl byte 3, code rate, modulation type, # of streams */
+ u8 tx_phy_ctl3;
+};
+
+/* Number of legacy_rate_cfg entries in the table */
+#define LEGACY_PHYCFG_TABLE_SIZE 12
+
+/*
+ * In CCK mode LPPHY overloads OFDM Modulation bits with CCK Data Rate
+ * Eventually MIMOPHY would also be converted to this format
+ * 0 = 1Mbps; 1 = 2Mbps; 2 = 5.5Mbps; 3 = 11Mbps
+ */
+static const struct
+legacy_phycfg legacy_phycfg_table[LEGACY_PHYCFG_TABLE_SIZE] = {
+ {BRCM_RATE_1M, 0x00}, /* CCK 1Mbps, data rate 0 */
+ {BRCM_RATE_2M, 0x08}, /* CCK 2Mbps, data rate 1 */
+ {BRCM_RATE_5M5, 0x10}, /* CCK 5.5Mbps, data rate 2 */
+ {BRCM_RATE_11M, 0x18}, /* CCK 11Mbps, data rate 3 */
+ /* OFDM 6Mbps, code rate 1/2, BPSK, 1 spatial stream */
+ {BRCM_RATE_6M, 0x00},
+ /* OFDM 9Mbps, code rate 3/4, BPSK, 1 spatial stream */
+ {BRCM_RATE_9M, 0x02},
+ /* OFDM 12Mbps, code rate 1/2, QPSK, 1 spatial stream */
+ {BRCM_RATE_12M, 0x08},
+ /* OFDM 18Mbps, code rate 3/4, QPSK, 1 spatial stream */
+ {BRCM_RATE_18M, 0x0A},
+ /* OFDM 24Mbps, code rate 1/2, 16-QAM, 1 spatial stream */
+ {BRCM_RATE_24M, 0x10},
+ /* OFDM 36Mbps, code rate 3/4, 16-QAM, 1 spatial stream */
+ {BRCM_RATE_36M, 0x12},
+ /* OFDM 48Mbps, code rate 2/3, 64-QAM, 1 spatial stream */
+ {BRCM_RATE_48M, 0x19},
+ /* OFDM 54Mbps, code rate 3/4, 64-QAM, 1 spatial stream */
+ {BRCM_RATE_54M, 0x1A},
+};
+
+/* Hardware rates (also encodes default basic rates) */
+
+const struct brcms_c_rateset cck_ofdm_mimo_rates = {
+ 12,
+ /* 1b, 2b, 5.5b, 6, 9, 11b, 12, 18, 24, 36, 48, */
+ { 0x82, 0x84, 0x8b, 0x0c, 0x12, 0x96, 0x18, 0x24, 0x30, 0x48, 0x60,
+ /* 54 Mbps */
+ 0x6c},
+ 0x00,
+ { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+
+const struct brcms_c_rateset ofdm_mimo_rates = {
+ 8,
+ /* 6b, 9, 12b, 18, 24b, 36, 48, 54 Mbps */
+ { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c},
+ 0x00,
+ { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+
+/* Default ratesets that include MCS32 for 40BW channels */
+static const struct brcms_c_rateset cck_ofdm_40bw_mimo_rates = {
+ 12,
+ /* 1b, 2b, 5.5b, 6, 9, 11b, 12, 18, 24, 36, 48 */
+ { 0x82, 0x84, 0x8b, 0x0c, 0x12, 0x96, 0x18, 0x24, 0x30, 0x48, 0x60,
+ /* 54 Mbps */
+ 0x6c},
+ 0x00,
+ { 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+
+static const struct brcms_c_rateset ofdm_40bw_mimo_rates = {
+ 8,
+ /* 6b, 9, 12b, 18, 24b, 36, 48, 54 Mbps */
+ { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c},
+ 0x00,
+ { 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+
+const struct brcms_c_rateset cck_ofdm_rates = {
+ 12,
+ /* 1b, 2b, 5.5b, 6, 9, 11b, 12, 18, 24, 36, 48,*/
+ { 0x82, 0x84, 0x8b, 0x0c, 0x12, 0x96, 0x18, 0x24, 0x30, 0x48, 0x60,
+ /*54 Mbps */
+ 0x6c},
+ 0x00,
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+
+const struct brcms_c_rateset gphy_legacy_rates = {
+ 4,
+ /* 1b, 2b, 5.5b, 11b Mbps */
+ { 0x82, 0x84, 0x8b, 0x96},
+ 0x00,
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+
+const struct brcms_c_rateset ofdm_rates = {
+ 8,
+ /* 6b, 9, 12b, 18, 24b, 36, 48, 54 Mbps */
+ { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c},
+ 0x00,
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+
+const struct brcms_c_rateset cck_rates = {
+ 4,
+ /* 1b, 2b, 5.5, 11 Mbps */
+ { 0x82, 0x84, 0x0b, 0x16},
+ 0x00,
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+
+/* check if rateset is valid.
+ * if check_brate is true, rateset without a basic rate is considered NOT valid.
+ */
+static bool brcms_c_rateset_valid(struct brcms_c_rateset *rs, bool check_brate)
+{
+ uint idx;
+
+ if (!rs->count)
+ return false;
+
+ if (!check_brate)
+ return true;
+
+ /* error if no basic rates */
+ for (idx = 0; idx < rs->count; idx++) {
+ if (rs->rates[idx] & BRCMS_RATE_FLAG)
+ return true;
+ }
+ return false;
+}
+
+void brcms_c_rateset_mcs_upd(struct brcms_c_rateset *rs, u8 txstreams)
+{
+ int i;
+ for (i = txstreams; i < MAX_STREAMS_SUPPORTED; i++)
+ rs->mcs[i] = 0;
+}
+
+/*
+ * filter based on hardware rateset, and sort filtered rateset with basic
+ * bit(s) preserved, and check if resulting rateset is valid.
+*/
+bool
+brcms_c_rate_hwrs_filter_sort_validate(struct brcms_c_rateset *rs,
+ const struct brcms_c_rateset *hw_rs,
+ bool check_brate, u8 txstreams)
+{
+ u8 rateset[BRCM_MAXRATE + 1];
+ u8 r;
+ uint count;
+ uint i;
+
+ memset(rateset, 0, sizeof(rateset));
+ count = rs->count;
+
+ for (i = 0; i < count; i++) {
+ /* mask off "basic rate" bit, BRCMS_RATE_FLAG */
+ r = (int)rs->rates[i] & BRCMS_RATE_MASK;
+ if ((r > BRCM_MAXRATE) || (rate_info[r] == 0))
+ continue;
+ rateset[r] = rs->rates[i]; /* preserve basic bit! */
+ }
+
+ /* fill out the rates in order, looking at only supported rates */
+ count = 0;
+ for (i = 0; i < hw_rs->count; i++) {
+ r = hw_rs->rates[i] & BRCMS_RATE_MASK;
+ if (rateset[r])
+ rs->rates[count++] = rateset[r];
+ }
+
+ rs->count = count;
+
+ /* only set the mcs rate bit if the equivalent hw mcs bit is set */
+ for (i = 0; i < MCSSET_LEN; i++)
+ rs->mcs[i] = (rs->mcs[i] & hw_rs->mcs[i]);
+
+ if (brcms_c_rateset_valid(rs, check_brate))
+ return true;
+ else
+ return false;
+}
+
+/* calculate the rate of a rx'd frame and return it as a ratespec */
+u32 brcms_c_compute_rspec(struct d11rxhdr *rxh, u8 *plcp)
+{
+ int phy_type;
+ u32 rspec = PHY_TXC1_BW_20MHZ << RSPEC_BW_SHIFT;
+
+ phy_type =
+ ((rxh->RxChan & RXS_CHAN_PHYTYPE_MASK) >> RXS_CHAN_PHYTYPE_SHIFT);
+
+ if ((phy_type == PHY_TYPE_N) || (phy_type == PHY_TYPE_SSN) ||
+ (phy_type == PHY_TYPE_LCN) || (phy_type == PHY_TYPE_HT)) {
+ switch (rxh->PhyRxStatus_0 & PRXS0_FT_MASK) {
+ case PRXS0_CCK:
+ rspec =
+ cck_phy2mac_rate(
+ ((struct cck_phy_hdr *) plcp)->signal);
+ break;
+ case PRXS0_OFDM:
+ rspec =
+ ofdm_phy2mac_rate(
+ ((struct ofdm_phy_hdr *) plcp)->rlpt[0]);
+ break;
+ case PRXS0_PREN:
+ rspec = (plcp[0] & MIMO_PLCP_MCS_MASK) | RSPEC_MIMORATE;
+ if (plcp[0] & MIMO_PLCP_40MHZ) {
+ /* indicate rspec is for 40 MHz mode */
+ rspec &= ~RSPEC_BW_MASK;
+ rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT);
+ }
+ break;
+ case PRXS0_STDN:
+ /* fallthru */
+ default:
+ /* not supported, error condition */
+ break;
+ }
+ if (plcp3_issgi(plcp[3]))
+ rspec |= RSPEC_SHORT_GI;
+ } else
+ if ((phy_type == PHY_TYPE_A) || (rxh->PhyRxStatus_0 & PRXS0_OFDM))
+ rspec = ofdm_phy2mac_rate(
+ ((struct ofdm_phy_hdr *) plcp)->rlpt[0]);
+ else
+ rspec = cck_phy2mac_rate(
+ ((struct cck_phy_hdr *) plcp)->signal);
+
+ return rspec;
+}
+
+/* copy rateset src to dst as-is (no masking or sorting) */
+void brcms_c_rateset_copy(const struct brcms_c_rateset *src,
+ struct brcms_c_rateset *dst)
+{
+ memcpy(dst, src, sizeof(struct brcms_c_rateset));
+}
+
+/*
+ * Copy and selectively filter one rateset to another.
+ * 'basic_only' means only copy basic rates.
+ * 'rates' indicates cck (11b) and ofdm rates combinations.
+ * - 0: cck and ofdm
+ * - 1: cck only
+ * - 2: ofdm only
+ * 'xmask' is the copy mask (typically 0x7f or 0xff).
+ */
+void
+brcms_c_rateset_filter(struct brcms_c_rateset *src, struct brcms_c_rateset *dst,
+ bool basic_only, u8 rates, uint xmask, bool mcsallow)
+{
+ uint i;
+ uint r;
+ uint count;
+
+ count = 0;
+ for (i = 0; i < src->count; i++) {
+ r = src->rates[i];
+ if (basic_only && !(r & BRCMS_RATE_FLAG))
+ continue;
+ if (rates == BRCMS_RATES_CCK &&
+ is_ofdm_rate((r & BRCMS_RATE_MASK)))
+ continue;
+ if (rates == BRCMS_RATES_OFDM &&
+ is_cck_rate((r & BRCMS_RATE_MASK)))
+ continue;
+ dst->rates[count++] = r & xmask;
+ }
+ dst->count = count;
+ dst->htphy_membership = src->htphy_membership;
+
+ if (mcsallow && rates != BRCMS_RATES_CCK)
+ memcpy(&dst->mcs[0], &src->mcs[0], MCSSET_LEN);
+ else
+ brcms_c_rateset_mcs_clear(dst);
+}
+
+/* select rateset for a given phy_type and bandtype and filter it, sort it
+ * and fill rs_tgt with result
+ */
+void
+brcms_c_rateset_default(struct brcms_c_rateset *rs_tgt,
+ const struct brcms_c_rateset *rs_hw,
+ uint phy_type, int bandtype, bool cck_only,
+ uint rate_mask, bool mcsallow, u8 bw, u8 txstreams)
+{
+ const struct brcms_c_rateset *rs_dflt;
+ struct brcms_c_rateset rs_sel;
+ if ((PHYTYPE_IS(phy_type, PHY_TYPE_HT)) ||
+ (PHYTYPE_IS(phy_type, PHY_TYPE_N)) ||
+ (PHYTYPE_IS(phy_type, PHY_TYPE_LCN)) ||
+ (PHYTYPE_IS(phy_type, PHY_TYPE_SSN))) {
+ if (bandtype == BRCM_BAND_5G)
+ rs_dflt = (bw == BRCMS_20_MHZ ?
+ &ofdm_mimo_rates : &ofdm_40bw_mimo_rates);
+ else
+ rs_dflt = (bw == BRCMS_20_MHZ ?
+ &cck_ofdm_mimo_rates :
+ &cck_ofdm_40bw_mimo_rates);
+ } else if (PHYTYPE_IS(phy_type, PHY_TYPE_LP)) {
+ rs_dflt = (bandtype == BRCM_BAND_5G) ?
+ &ofdm_rates : &cck_ofdm_rates;
+ } else if (PHYTYPE_IS(phy_type, PHY_TYPE_A)) {
+ rs_dflt = &ofdm_rates;
+ } else if (PHYTYPE_IS(phy_type, PHY_TYPE_G)) {
+ rs_dflt = &cck_ofdm_rates;
+ } else {
+ /* should not happen, error condition */
+ rs_dflt = &cck_rates; /* force cck */
+ }
+
+ /* if hw rateset is not supplied, assign selected rateset to it */
+ if (!rs_hw)
+ rs_hw = rs_dflt;
+
+ brcms_c_rateset_copy(rs_dflt, &rs_sel);
+ brcms_c_rateset_mcs_upd(&rs_sel, txstreams);
+ brcms_c_rateset_filter(&rs_sel, rs_tgt, false,
+ cck_only ? BRCMS_RATES_CCK : BRCMS_RATES_CCK_OFDM,
+ rate_mask, mcsallow);
+ brcms_c_rate_hwrs_filter_sort_validate(rs_tgt, rs_hw, false,
+ mcsallow ? txstreams : 1);
+}
+
+s16 brcms_c_rate_legacy_phyctl(uint rate)
+{
+ uint i;
+ for (i = 0; i < LEGACY_PHYCFG_TABLE_SIZE; i++)
+ if (rate == legacy_phycfg_table[i].rate_ofdm)
+ return legacy_phycfg_table[i].tx_phy_ctl3;
+
+ return -1;
+}
+
+void brcms_c_rateset_mcs_clear(struct brcms_c_rateset *rateset)
+{
+ uint i;
+ for (i = 0; i < MCSSET_LEN; i++)
+ rateset->mcs[i] = 0;
+}
+
+void brcms_c_rateset_mcs_build(struct brcms_c_rateset *rateset, u8 txstreams)
+{
+ memcpy(&rateset->mcs[0], &cck_ofdm_mimo_rates.mcs[0], MCSSET_LEN);
+ brcms_c_rateset_mcs_upd(rateset, txstreams);
+}
+
+/* Based on bandwidth passed, allow/disallow MCS 32 in the rateset */
+void brcms_c_rateset_bw_mcs_filter(struct brcms_c_rateset *rateset, u8 bw)
+{
+ if (bw == BRCMS_40_MHZ)
+ setbit(rateset->mcs, 32);
+ else
+ clrbit(rateset->mcs, 32);
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/rate.h b/drivers/net/wireless/brcm80211/brcmsmac/rate.h
new file mode 100644
index 000000000000..e7b9dc2f2731
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/rate.h
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_RATE_H_
+#define _BRCM_RATE_H_
+
+#include "types.h"
+#include "d11.h"
+
+extern const u8 rate_info[];
+extern const struct brcms_c_rateset cck_ofdm_mimo_rates;
+extern const struct brcms_c_rateset ofdm_mimo_rates;
+extern const struct brcms_c_rateset cck_ofdm_rates;
+extern const struct brcms_c_rateset ofdm_rates;
+extern const struct brcms_c_rateset cck_rates;
+extern const struct brcms_c_rateset gphy_legacy_rates;
+extern const struct brcms_c_rateset rate_limit_1_2;
+
+struct brcms_mcs_info {
+ /* phy rate in kbps [20Mhz] */
+ u32 phy_rate_20;
+ /* phy rate in kbps [40Mhz] */
+ u32 phy_rate_40;
+ /* phy rate in kbps [20Mhz] with SGI */
+ u32 phy_rate_20_sgi;
+ /* phy rate in kbps [40Mhz] with SGI */
+ u32 phy_rate_40_sgi;
+ /* phy ctl byte 3, code rate, modulation type, # of streams */
+ u8 tx_phy_ctl3;
+ /* matching legacy ofdm rate in 500bkps */
+ u8 leg_ofdm;
+};
+
+#define BRCMS_MAXMCS 32 /* max valid mcs index */
+#define MCS_TABLE_SIZE 33 /* Number of mcs entries in the table */
+extern const struct brcms_mcs_info mcs_table[];
+
+#define MCS_TXS_MASK 0xc0 /* num tx streams - 1 bit mask */
+#define MCS_TXS_SHIFT 6 /* num tx streams - 1 bit shift */
+
+/* returns num tx streams - 1 */
+static inline u8 mcs_2_txstreams(u8 mcs)
+{
+ return (mcs_table[mcs].tx_phy_ctl3 & MCS_TXS_MASK) >> MCS_TXS_SHIFT;
+}
+
+static inline uint mcs_2_rate(u8 mcs, bool is40, bool sgi)
+{
+ if (sgi) {
+ if (is40)
+ return mcs_table[mcs].phy_rate_40_sgi;
+ return mcs_table[mcs].phy_rate_20_sgi;
+ }
+ if (is40)
+ return mcs_table[mcs].phy_rate_40;
+
+ return mcs_table[mcs].phy_rate_20;
+}
+
+/* Macro to use the rate_info table */
+#define BRCMS_RATE_MASK_FULL 0xff /* Rate value mask with basic rate flag */
+
+/*
+ * rate spec : holds rate and mode specific information required to generate a
+ * tx frame. Legacy CCK and OFDM information is held in the same manner as was
+ * done in the past (in the lower byte) the upper 3 bytes primarily hold MIMO
+ * specific information
+ */
+
+/* rate spec bit fields */
+
+/* Either 500Kbps units or MIMO MCS idx */
+#define RSPEC_RATE_MASK 0x0000007F
+/* mimo MCS is stored in RSPEC_RATE_MASK */
+#define RSPEC_MIMORATE 0x08000000
+/* mimo bw mask */
+#define RSPEC_BW_MASK 0x00000700
+/* mimo bw shift */
+#define RSPEC_BW_SHIFT 8
+/* mimo Space/Time/Frequency mode mask */
+#define RSPEC_STF_MASK 0x00003800
+/* mimo Space/Time/Frequency mode shift */
+#define RSPEC_STF_SHIFT 11
+/* mimo coding type mask */
+#define RSPEC_CT_MASK 0x0000C000
+/* mimo coding type shift */
+#define RSPEC_CT_SHIFT 14
+/* mimo num STC streams per PLCP defn. */
+#define RSPEC_STC_MASK 0x00300000
+/* mimo num STC streams per PLCP defn. */
+#define RSPEC_STC_SHIFT 20
+/* mimo bit indicates adv coding in use */
+#define RSPEC_LDPC_CODING 0x00400000
+/* mimo bit indicates short GI in use */
+#define RSPEC_SHORT_GI 0x00800000
+/* bit indicates override both rate & mode */
+#define RSPEC_OVERRIDE 0x80000000
+/* bit indicates override rate only */
+#define RSPEC_OVERRIDE_MCS_ONLY 0x40000000
+
+static inline bool rspec_active(u32 rspec)
+{
+ return rspec & (RSPEC_RATE_MASK | RSPEC_MIMORATE);
+}
+
+static inline u8 rspec_phytxbyte2(u32 rspec)
+{
+ return (rspec & 0xff00) >> 8;
+}
+
+static inline u32 rspec_get_bw(u32 rspec)
+{
+ return (rspec & RSPEC_BW_MASK) >> RSPEC_BW_SHIFT;
+}
+
+static inline bool rspec_issgi(u32 rspec)
+{
+ return (rspec & RSPEC_SHORT_GI) == RSPEC_SHORT_GI;
+}
+
+static inline bool rspec_is40mhz(u32 rspec)
+{
+ u32 bw = rspec_get_bw(rspec);
+
+ return bw == PHY_TXC1_BW_40MHZ || bw == PHY_TXC1_BW_40MHZ_DUP;
+}
+
+static inline uint rspec2rate(u32 rspec)
+{
+ if (rspec & RSPEC_MIMORATE)
+ return mcs_2_rate(rspec & RSPEC_RATE_MASK, rspec_is40mhz(rspec),
+ rspec_issgi(rspec));
+ return rspec & RSPEC_RATE_MASK;
+}
+
+static inline u8 rspec_mimoplcp3(u32 rspec)
+{
+ return (rspec & 0xf00000) >> 16;
+}
+
+static inline bool plcp3_issgi(u8 plcp)
+{
+ return (plcp & (RSPEC_SHORT_GI >> 16)) != 0;
+}
+
+static inline uint rspec_stc(u32 rspec)
+{
+ return (rspec & RSPEC_STC_MASK) >> RSPEC_STC_SHIFT;
+}
+
+static inline uint rspec_stf(u32 rspec)
+{
+ return (rspec & RSPEC_STF_MASK) >> RSPEC_STF_SHIFT;
+}
+
+static inline bool is_mcs_rate(u32 ratespec)
+{
+ return (ratespec & RSPEC_MIMORATE) != 0;
+}
+
+static inline bool is_ofdm_rate(u32 ratespec)
+{
+ return !is_mcs_rate(ratespec) &&
+ (rate_info[ratespec & RSPEC_RATE_MASK] & BRCMS_RATE_FLAG);
+}
+
+static inline bool is_cck_rate(u32 ratespec)
+{
+ u32 rate = (ratespec & BRCMS_RATE_MASK);
+
+ return !is_mcs_rate(ratespec) && (
+ rate == BRCM_RATE_1M || rate == BRCM_RATE_2M ||
+ rate == BRCM_RATE_5M5 || rate == BRCM_RATE_11M);
+}
+
+static inline bool is_single_stream(u8 mcs)
+{
+ return mcs <= HIGHEST_SINGLE_STREAM_MCS || mcs == 32;
+}
+
+static inline u8 cck_rspec(u8 cck)
+{
+ return cck & RSPEC_RATE_MASK;
+}
+
+/* Convert encoded rate value in plcp header to numerical rates in 500 KHz
+ * increments */
+extern const u8 ofdm_rate_lookup[];
+
+static inline u8 ofdm_phy2mac_rate(u8 rlpt)
+{
+ return ofdm_rate_lookup[rlpt & 0x7];
+}
+
+static inline u8 cck_phy2mac_rate(u8 signal)
+{
+ return signal/5;
+}
+
+/* Rates specified in brcms_c_rateset_filter() */
+#define BRCMS_RATES_CCK_OFDM 0
+#define BRCMS_RATES_CCK 1
+#define BRCMS_RATES_OFDM 2
+
+/* sanitize, and sort a rateset with the basic bit(s) preserved, validate
+ * rateset */
+extern bool
+brcms_c_rate_hwrs_filter_sort_validate(struct brcms_c_rateset *rs,
+ const struct brcms_c_rateset *hw_rs,
+ bool check_brate, u8 txstreams);
+/* copy rateset src to dst as-is (no masking or sorting) */
+extern void brcms_c_rateset_copy(const struct brcms_c_rateset *src,
+ struct brcms_c_rateset *dst);
+
+/* would be nice to have these documented ... */
+extern u32 brcms_c_compute_rspec(struct d11rxhdr *rxh, u8 *plcp);
+
+extern void brcms_c_rateset_filter(struct brcms_c_rateset *src,
+ struct brcms_c_rateset *dst, bool basic_only, u8 rates, uint xmask,
+ bool mcsallow);
+
+extern void
+brcms_c_rateset_default(struct brcms_c_rateset *rs_tgt,
+ const struct brcms_c_rateset *rs_hw, uint phy_type,
+ int bandtype, bool cck_only, uint rate_mask,
+ bool mcsallow, u8 bw, u8 txstreams);
+
+extern s16 brcms_c_rate_legacy_phyctl(uint rate);
+
+extern void brcms_c_rateset_mcs_upd(struct brcms_c_rateset *rs, u8 txstreams);
+extern void brcms_c_rateset_mcs_clear(struct brcms_c_rateset *rateset);
+extern void brcms_c_rateset_mcs_build(struct brcms_c_rateset *rateset,
+ u8 txstreams);
+extern void brcms_c_rateset_bw_mcs_filter(struct brcms_c_rateset *rateset,
+ u8 bw);
+
+#endif /* _BRCM_RATE_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/scb.h b/drivers/net/wireless/brcm80211/brcmsmac/scb.h
new file mode 100644
index 000000000000..51c79c7239b7
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/scb.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_SCB_H_
+#define _BRCM_SCB_H_
+
+#include <linux/if_ether.h>
+#include <brcmu_utils.h>
+#include <defs.h>
+#include "types.h"
+
+#define AMPDU_TX_BA_MAX_WSIZE 64 /* max Tx ba window size (in pdu) */
+
+#define AMPDU_MAX_SCB_TID NUMPRIO
+
+/* scb flags */
+#define SCB_WMECAP 0x0040
+#define SCB_HTCAP 0x10000 /* HT (MIMO) capable device */
+#define SCB_IS40 0x80000 /* 40MHz capable */
+#define SCB_STBCCAP 0x40000000 /* STBC Capable */
+
+#define SCB_MAGIC 0xbeefcafe
+
+/* structure to store per-tid state for the ampdu initiator */
+struct scb_ampdu_tid_ini {
+ u8 tx_in_transit; /* number of pending mpdus in transit in driver */
+ u8 tid; /* initiator tid for easy lookup */
+ /* tx retry count; indexed by seq modulo */
+ u8 txretry[AMPDU_TX_BA_MAX_WSIZE];
+ struct scb *scb; /* backptr for easy lookup */
+ u8 ba_wsize; /* negotiated ba window size (in pdu) */
+};
+
+struct scb_ampdu {
+ struct scb *scb; /* back pointer for easy reference */
+ u8 mpdu_density; /* mpdu density */
+ u8 max_pdu; /* max pdus allowed in ampdu */
+ u8 release; /* # of mpdus released at a time */
+ u16 min_len; /* min mpdu len to support the density */
+ u32 max_rx_ampdu_bytes; /* max ampdu rcv length; 8k, 16k, 32k, 64k */
+
+ /*
+ * This could easily be a ini[] pointer and we keep this info in wl
+ * itself instead of having mac80211 hold it for us. Also could be made
+ * dynamic per tid instead of static.
+ */
+ /* initiator info - per tid (NUMPRIO): */
+ struct scb_ampdu_tid_ini ini[AMPDU_MAX_SCB_TID];
+};
+
+/* station control block - one per remote MAC address */
+struct scb {
+ u32 magic;
+ u32 flags; /* various bit flags as defined below */
+ u32 flags2; /* various bit flags2 as defined below */
+ u8 state; /* current state bitfield of auth/assoc process */
+ u8 ea[ETH_ALEN]; /* station address */
+ uint fragresid[NUMPRIO];/* #bytes unused in frag buffer per prio */
+
+ u16 seqctl[NUMPRIO]; /* seqctl of last received frame (for dups) */
+ /* seqctl of last received frame (for dups) for non-QoS data and
+ * management */
+ u16 seqctl_nonqos;
+ u16 seqnum[NUMPRIO];/* WME: driver maintained sw seqnum per priority */
+
+ struct scb_ampdu scb_ampdu; /* AMPDU state including per tid info */
+};
+
+#endif /* _BRCM_SCB_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/srom.c b/drivers/net/wireless/brcm80211/brcmsmac/srom.c
new file mode 100644
index 000000000000..99f791048e84
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/srom.c
@@ -0,0 +1,1298 @@
+/*
+ * Copyright (c) 2010 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/kernel.h>
+#include <linux/string.h>
+#include <linux/io.h>
+#include <linux/etherdevice.h>
+#include <linux/crc8.h>
+#include <stdarg.h>
+
+#include <chipcommon.h>
+#include <brcmu_utils.h>
+#include "pub.h"
+#include "nicpci.h"
+#include "aiutils.h"
+#include "otp.h"
+#include "srom.h"
+
+/*
+ * SROM CRC8 polynomial value:
+ *
+ * x^8 + x^7 +x^6 + x^4 + x^2 + 1
+ */
+#define SROM_CRC8_POLY 0xAB
+
+/* Maximum srom: 6 Kilobits == 768 bytes */
+#define SROM_MAX 768
+
+/* PCI fields */
+#define PCI_F0DEVID 48
+
+#define SROM_WORDS 64
+
+#define SROM_SSID 2
+
+#define SROM_WL1LHMAXP 29
+
+#define SROM_WL1LPAB0 30
+#define SROM_WL1LPAB1 31
+#define SROM_WL1LPAB2 32
+
+#define SROM_WL1HPAB0 33
+#define SROM_WL1HPAB1 34
+#define SROM_WL1HPAB2 35
+
+#define SROM_MACHI_IL0 36
+#define SROM_MACMID_IL0 37
+#define SROM_MACLO_IL0 38
+#define SROM_MACHI_ET1 42
+#define SROM_MACMID_ET1 43
+#define SROM_MACLO_ET1 44
+#define SROM3_MACHI 37
+#define SROM3_MACMID 38
+#define SROM3_MACLO 39
+
+#define SROM_BXARSSI2G 40
+#define SROM_BXARSSI5G 41
+
+#define SROM_TRI52G 42
+#define SROM_TRI5GHL 43
+
+#define SROM_RXPO52G 45
+
+#define SROM_AABREV 46
+/* Fields in AABREV */
+#define SROM_BR_MASK 0x00ff
+#define SROM_CC_MASK 0x0f00
+#define SROM_CC_SHIFT 8
+#define SROM_AA0_MASK 0x3000
+#define SROM_AA0_SHIFT 12
+#define SROM_AA1_MASK 0xc000
+#define SROM_AA1_SHIFT 14
+
+#define SROM_WL0PAB0 47
+#define SROM_WL0PAB1 48
+#define SROM_WL0PAB2 49
+
+#define SROM_LEDBH10 50
+#define SROM_LEDBH32 51
+
+#define SROM_WL10MAXP 52
+
+#define SROM_WL1PAB0 53
+#define SROM_WL1PAB1 54
+#define SROM_WL1PAB2 55
+
+#define SROM_ITT 56
+
+#define SROM_BFL 57
+#define SROM_BFL2 28
+#define SROM3_BFL2 61
+
+#define SROM_AG10 58
+
+#define SROM_CCODE 59
+
+#define SROM_OPO 60
+
+#define SROM3_LEDDC 62
+
+#define SROM_CRCREV 63
+
+/* SROM Rev 4: Reallocate the software part of the srom to accommodate
+ * MIMO features. It assumes up to two PCIE functions and 440 bytes
+ * of usable srom i.e. the usable storage in chips with OTP that
+ * implements hardware redundancy.
+ */
+
+#define SROM4_WORDS 220
+
+#define SROM4_SIGN 32
+#define SROM4_SIGNATURE 0x5372
+
+#define SROM4_BREV 33
+
+#define SROM4_BFL0 34
+#define SROM4_BFL1 35
+#define SROM4_BFL2 36
+#define SROM4_BFL3 37
+#define SROM5_BFL0 37
+#define SROM5_BFL1 38
+#define SROM5_BFL2 39
+#define SROM5_BFL3 40
+
+#define SROM4_MACHI 38
+#define SROM4_MACMID 39
+#define SROM4_MACLO 40
+#define SROM5_MACHI 41
+#define SROM5_MACMID 42
+#define SROM5_MACLO 43
+
+#define SROM4_CCODE 41
+#define SROM4_REGREV 42
+#define SROM5_CCODE 34
+#define SROM5_REGREV 35
+
+#define SROM4_LEDBH10 43
+#define SROM4_LEDBH32 44
+#define SROM5_LEDBH10 59
+#define SROM5_LEDBH32 60
+
+#define SROM4_LEDDC 45
+#define SROM5_LEDDC 45
+
+#define SROM4_AA 46
+
+#define SROM4_AG10 47
+#define SROM4_AG32 48
+
+#define SROM4_TXPID2G 49
+#define SROM4_TXPID5G 51
+#define SROM4_TXPID5GL 53
+#define SROM4_TXPID5GH 55
+
+#define SROM4_TXRXC 61
+#define SROM4_TXCHAIN_MASK 0x000f
+#define SROM4_TXCHAIN_SHIFT 0
+#define SROM4_RXCHAIN_MASK 0x00f0
+#define SROM4_RXCHAIN_SHIFT 4
+#define SROM4_SWITCH_MASK 0xff00
+#define SROM4_SWITCH_SHIFT 8
+
+/* Per-path fields */
+#define MAX_PATH_SROM 4
+#define SROM4_PATH0 64
+#define SROM4_PATH1 87
+#define SROM4_PATH2 110
+#define SROM4_PATH3 133
+
+#define SROM4_2G_ITT_MAXP 0
+#define SROM4_2G_PA 1
+#define SROM4_5G_ITT_MAXP 5
+#define SROM4_5GLH_MAXP 6
+#define SROM4_5G_PA 7
+#define SROM4_5GL_PA 11
+#define SROM4_5GH_PA 15
+
+/* All the miriad power offsets */
+#define SROM4_2G_CCKPO 156
+#define SROM4_2G_OFDMPO 157
+#define SROM4_5G_OFDMPO 159
+#define SROM4_5GL_OFDMPO 161
+#define SROM4_5GH_OFDMPO 163
+#define SROM4_2G_MCSPO 165
+#define SROM4_5G_MCSPO 173
+#define SROM4_5GL_MCSPO 181
+#define SROM4_5GH_MCSPO 189
+#define SROM4_CDDPO 197
+#define SROM4_STBCPO 198
+#define SROM4_BW40PO 199
+#define SROM4_BWDUPPO 200
+
+#define SROM4_CRCREV 219
+
+/* SROM Rev 8: Make space for a 48word hardware header for PCIe rev >= 6.
+ * This is acombined srom for both MIMO and SISO boards, usable in
+ * the .130 4Kilobit OTP with hardware redundancy.
+ */
+#define SROM8_BREV 65
+
+#define SROM8_BFL0 66
+#define SROM8_BFL1 67
+#define SROM8_BFL2 68
+#define SROM8_BFL3 69
+
+#define SROM8_MACHI 70
+#define SROM8_MACMID 71
+#define SROM8_MACLO 72
+
+#define SROM8_CCODE 73
+#define SROM8_REGREV 74
+
+#define SROM8_LEDBH10 75
+#define SROM8_LEDBH32 76
+
+#define SROM8_LEDDC 77
+
+#define SROM8_AA 78
+
+#define SROM8_AG10 79
+#define SROM8_AG32 80
+
+#define SROM8_TXRXC 81
+
+#define SROM8_BXARSSI2G 82
+#define SROM8_BXARSSI5G 83
+#define SROM8_TRI52G 84
+#define SROM8_TRI5GHL 85
+#define SROM8_RXPO52G 86
+
+#define SROM8_FEM2G 87
+#define SROM8_FEM5G 88
+#define SROM8_FEM_ANTSWLUT_MASK 0xf800
+#define SROM8_FEM_ANTSWLUT_SHIFT 11
+#define SROM8_FEM_TR_ISO_MASK 0x0700
+#define SROM8_FEM_TR_ISO_SHIFT 8
+#define SROM8_FEM_PDET_RANGE_MASK 0x00f8
+#define SROM8_FEM_PDET_RANGE_SHIFT 3
+#define SROM8_FEM_EXTPA_GAIN_MASK 0x0006
+#define SROM8_FEM_EXTPA_GAIN_SHIFT 1
+#define SROM8_FEM_TSSIPOS_MASK 0x0001
+#define SROM8_FEM_TSSIPOS_SHIFT 0
+
+#define SROM8_THERMAL 89
+
+/* Temp sense related entries */
+#define SROM8_MPWR_RAWTS 90
+#define SROM8_TS_SLP_OPT_CORRX 91
+/* FOC: freiquency offset correction, HWIQ: H/W IOCAL enable,
+ * IQSWP: IQ CAL swap disable */
+#define SROM8_FOC_HWIQ_IQSWP 92
+
+/* Temperature delta for PHY calibration */
+#define SROM8_PHYCAL_TEMPDELTA 93
+
+/* Per-path offsets & fields */
+#define SROM8_PATH0 96
+#define SROM8_PATH1 112
+#define SROM8_PATH2 128
+#define SROM8_PATH3 144
+
+#define SROM8_2G_ITT_MAXP 0
+#define SROM8_2G_PA 1
+#define SROM8_5G_ITT_MAXP 4
+#define SROM8_5GLH_MAXP 5
+#define SROM8_5G_PA 6
+#define SROM8_5GL_PA 9
+#define SROM8_5GH_PA 12
+
+/* All the miriad power offsets */
+#define SROM8_2G_CCKPO 160
+
+#define SROM8_2G_OFDMPO 161
+#define SROM8_5G_OFDMPO 163
+#define SROM8_5GL_OFDMPO 165
+#define SROM8_5GH_OFDMPO 167
+
+#define SROM8_2G_MCSPO 169
+#define SROM8_5G_MCSPO 177
+#define SROM8_5GL_MCSPO 185
+#define SROM8_5GH_MCSPO 193
+
+#define SROM8_CDDPO 201
+#define SROM8_STBCPO 202
+#define SROM8_BW40PO 203
+#define SROM8_BWDUPPO 204
+
+/* SISO PA parameters are in the path0 spaces */
+#define SROM8_SISO 96
+
+/* Legacy names for SISO PA paramters */
+#define SROM8_W0_ITTMAXP (SROM8_SISO + SROM8_2G_ITT_MAXP)
+#define SROM8_W0_PAB0 (SROM8_SISO + SROM8_2G_PA)
+#define SROM8_W0_PAB1 (SROM8_SISO + SROM8_2G_PA + 1)
+#define SROM8_W0_PAB2 (SROM8_SISO + SROM8_2G_PA + 2)
+#define SROM8_W1_ITTMAXP (SROM8_SISO + SROM8_5G_ITT_MAXP)
+#define SROM8_W1_MAXP_LCHC (SROM8_SISO + SROM8_5GLH_MAXP)
+#define SROM8_W1_PAB0 (SROM8_SISO + SROM8_5G_PA)
+#define SROM8_W1_PAB1 (SROM8_SISO + SROM8_5G_PA + 1)
+#define SROM8_W1_PAB2 (SROM8_SISO + SROM8_5G_PA + 2)
+#define SROM8_W1_PAB0_LC (SROM8_SISO + SROM8_5GL_PA)
+#define SROM8_W1_PAB1_LC (SROM8_SISO + SROM8_5GL_PA + 1)
+#define SROM8_W1_PAB2_LC (SROM8_SISO + SROM8_5GL_PA + 2)
+#define SROM8_W1_PAB0_HC (SROM8_SISO + SROM8_5GH_PA)
+#define SROM8_W1_PAB1_HC (SROM8_SISO + SROM8_5GH_PA + 1)
+#define SROM8_W1_PAB2_HC (SROM8_SISO + SROM8_5GH_PA + 2)
+
+/* SROM REV 9 */
+#define SROM9_2GPO_CCKBW20 160
+#define SROM9_2GPO_CCKBW20UL 161
+#define SROM9_2GPO_LOFDMBW20 162
+#define SROM9_2GPO_LOFDMBW20UL 164
+
+#define SROM9_5GLPO_LOFDMBW20 166
+#define SROM9_5GLPO_LOFDMBW20UL 168
+#define SROM9_5GMPO_LOFDMBW20 170
+#define SROM9_5GMPO_LOFDMBW20UL 172
+#define SROM9_5GHPO_LOFDMBW20 174
+#define SROM9_5GHPO_LOFDMBW20UL 176
+
+#define SROM9_2GPO_MCSBW20 178
+#define SROM9_2GPO_MCSBW20UL 180
+#define SROM9_2GPO_MCSBW40 182
+
+#define SROM9_5GLPO_MCSBW20 184
+#define SROM9_5GLPO_MCSBW20UL 186
+#define SROM9_5GLPO_MCSBW40 188
+#define SROM9_5GMPO_MCSBW20 190
+#define SROM9_5GMPO_MCSBW20UL 192
+#define SROM9_5GMPO_MCSBW40 194
+#define SROM9_5GHPO_MCSBW20 196
+#define SROM9_5GHPO_MCSBW20UL 198
+#define SROM9_5GHPO_MCSBW40 200
+
+#define SROM9_PO_MCS32 202
+#define SROM9_PO_LOFDM40DUP 203
+
+/* SROM flags (see sromvar_t) */
+
+/* value continues as described by the next entry */
+#define SRFL_MORE 1
+#define SRFL_NOFFS 2 /* value bits can't be all one's */
+#define SRFL_PRHEX 4 /* value is in hexdecimal format */
+#define SRFL_PRSIGN 8 /* value is in signed decimal format */
+#define SRFL_CCODE 0x10 /* value is in country code format */
+#define SRFL_ETHADDR 0x20 /* value is an Ethernet address */
+#define SRFL_LEDDC 0x40 /* value is an LED duty cycle */
+/* do not generate a nvram param, entry is for mfgc */
+#define SRFL_NOVAR 0x80
+
+/* Max. nvram variable table size */
+#define MAXSZ_NVRAM_VARS 4096
+
+/*
+ * indicates type of value.
+ */
+enum brcms_srom_var_type {
+ BRCMS_SROM_STRING,
+ BRCMS_SROM_SNUMBER,
+ BRCMS_SROM_UNUMBER
+};
+
+/*
+ * storage type for srom variable.
+ *
+ * var_list: for linked list operations.
+ * varid: identifier of the variable.
+ * var_type: type of variable.
+ * buf: variable value when var_type == BRCMS_SROM_STRING.
+ * uval: unsigned variable value when var_type == BRCMS_SROM_UNUMBER.
+ * sval: signed variable value when var_type == BRCMS_SROM_SNUMBER.
+ */
+struct brcms_srom_list_head {
+ struct list_head var_list;
+ enum brcms_srom_id varid;
+ enum brcms_srom_var_type var_type;
+ union {
+ char buf[0];
+ u32 uval;
+ s32 sval;
+ };
+};
+
+struct brcms_sromvar {
+ enum brcms_srom_id varid;
+ u32 revmask;
+ u32 flags;
+ u16 off;
+ u16 mask;
+};
+
+struct brcms_varbuf {
+ char *base; /* pointer to buffer base */
+ char *buf; /* pointer to current position */
+ unsigned int size; /* current (residual) size in bytes */
+};
+
+/*
+ * Assumptions:
+ * - Ethernet address spans across 3 consecutive words
+ *
+ * Table rules:
+ * - Add multiple entries next to each other if a value spans across multiple
+ * words (even multiple fields in the same word) with each entry except the
+ * last having it's SRFL_MORE bit set.
+ * - Ethernet address entry does not follow above rule and must not have
+ * SRFL_MORE bit set. Its SRFL_ETHADDR bit implies it takes multiple words.
+ * - The last entry's name field must be NULL to indicate the end of the table.
+ * Other entries must have non-NULL name.
+ */
+static const struct brcms_sromvar pci_sromvars[] = {
+ {BRCMS_SROM_DEVID, 0xffffff00, SRFL_PRHEX | SRFL_NOVAR, PCI_F0DEVID,
+ 0xffff},
+ {BRCMS_SROM_BOARDREV, 0x0000000e, SRFL_PRHEX, SROM_AABREV,
+ SROM_BR_MASK},
+ {BRCMS_SROM_BOARDREV, 0x000000f0, SRFL_PRHEX, SROM4_BREV, 0xffff},
+ {BRCMS_SROM_BOARDREV, 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff},
+ {BRCMS_SROM_BOARDFLAGS, 0x00000002, SRFL_PRHEX, SROM_BFL, 0xffff},
+ {BRCMS_SROM_BOARDFLAGS, 0x00000004, SRFL_PRHEX | SRFL_MORE, SROM_BFL,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM_BFL2, 0xffff},
+ {BRCMS_SROM_BOARDFLAGS, 0x00000008, SRFL_PRHEX | SRFL_MORE, SROM_BFL,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM3_BFL2, 0xffff},
+ {BRCMS_SROM_BOARDFLAGS, 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL0,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM4_BFL1, 0xffff},
+ {BRCMS_SROM_BOARDFLAGS, 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL0,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM5_BFL1, 0xffff},
+ {BRCMS_SROM_BOARDFLAGS, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL0,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM8_BFL1, 0xffff},
+ {BRCMS_SROM_BOARDFLAGS2, 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL2,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM4_BFL3, 0xffff},
+ {BRCMS_SROM_BOARDFLAGS2, 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL2,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM5_BFL3, 0xffff},
+ {BRCMS_SROM_BOARDFLAGS2, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL2,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM8_BFL3, 0xffff},
+ {BRCMS_SROM_BOARDTYPE, 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff},
+ {BRCMS_SROM_BOARDNUM, 0x00000006, 0, SROM_MACLO_IL0, 0xffff},
+ {BRCMS_SROM_BOARDNUM, 0x00000008, 0, SROM3_MACLO, 0xffff},
+ {BRCMS_SROM_BOARDNUM, 0x00000010, 0, SROM4_MACLO, 0xffff},
+ {BRCMS_SROM_BOARDNUM, 0x000000e0, 0, SROM5_MACLO, 0xffff},
+ {BRCMS_SROM_BOARDNUM, 0xffffff00, 0, SROM8_MACLO, 0xffff},
+ {BRCMS_SROM_CC, 0x00000002, 0, SROM_AABREV, SROM_CC_MASK},
+ {BRCMS_SROM_REGREV, 0x00000008, 0, SROM_OPO, 0xff00},
+ {BRCMS_SROM_REGREV, 0x00000010, 0, SROM4_REGREV, 0x00ff},
+ {BRCMS_SROM_REGREV, 0x000000e0, 0, SROM5_REGREV, 0x00ff},
+ {BRCMS_SROM_REGREV, 0xffffff00, 0, SROM8_REGREV, 0x00ff},
+ {BRCMS_SROM_LEDBH0, 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0x00ff},
+ {BRCMS_SROM_LEDBH1, 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff00},
+ {BRCMS_SROM_LEDBH2, 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0x00ff},
+ {BRCMS_SROM_LEDBH3, 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff00},
+ {BRCMS_SROM_LEDBH0, 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0x00ff},
+ {BRCMS_SROM_LEDBH1, 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff00},
+ {BRCMS_SROM_LEDBH2, 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0x00ff},
+ {BRCMS_SROM_LEDBH3, 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff00},
+ {BRCMS_SROM_LEDBH0, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0x00ff},
+ {BRCMS_SROM_LEDBH1, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff00},
+ {BRCMS_SROM_LEDBH2, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0x00ff},
+ {BRCMS_SROM_LEDBH3, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff00},
+ {BRCMS_SROM_LEDBH0, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0x00ff},
+ {BRCMS_SROM_LEDBH1, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff00},
+ {BRCMS_SROM_LEDBH2, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0x00ff},
+ {BRCMS_SROM_LEDBH3, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff00},
+ {BRCMS_SROM_PA0B0, 0x0000000e, SRFL_PRHEX, SROM_WL0PAB0, 0xffff},
+ {BRCMS_SROM_PA0B1, 0x0000000e, SRFL_PRHEX, SROM_WL0PAB1, 0xffff},
+ {BRCMS_SROM_PA0B2, 0x0000000e, SRFL_PRHEX, SROM_WL0PAB2, 0xffff},
+ {BRCMS_SROM_PA0ITSSIT, 0x0000000e, 0, SROM_ITT, 0x00ff},
+ {BRCMS_SROM_PA0MAXPWR, 0x0000000e, 0, SROM_WL10MAXP, 0x00ff},
+ {BRCMS_SROM_PA0B0, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff},
+ {BRCMS_SROM_PA0B1, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff},
+ {BRCMS_SROM_PA0B2, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff},
+ {BRCMS_SROM_PA0ITSSIT, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff00},
+ {BRCMS_SROM_PA0MAXPWR, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0x00ff},
+ {BRCMS_SROM_OPO, 0x0000000c, 0, SROM_OPO, 0x00ff},
+ {BRCMS_SROM_OPO, 0xffffff00, 0, SROM8_2G_OFDMPO, 0x00ff},
+ {BRCMS_SROM_AA2G, 0x0000000e, 0, SROM_AABREV, SROM_AA0_MASK},
+ {BRCMS_SROM_AA2G, 0x000000f0, 0, SROM4_AA, 0x00ff},
+ {BRCMS_SROM_AA2G, 0xffffff00, 0, SROM8_AA, 0x00ff},
+ {BRCMS_SROM_AA5G, 0x0000000e, 0, SROM_AABREV, SROM_AA1_MASK},
+ {BRCMS_SROM_AA5G, 0x000000f0, 0, SROM4_AA, 0xff00},
+ {BRCMS_SROM_AA5G, 0xffffff00, 0, SROM8_AA, 0xff00},
+ {BRCMS_SROM_AG0, 0x0000000e, 0, SROM_AG10, 0x00ff},
+ {BRCMS_SROM_AG1, 0x0000000e, 0, SROM_AG10, 0xff00},
+ {BRCMS_SROM_AG0, 0x000000f0, 0, SROM4_AG10, 0x00ff},
+ {BRCMS_SROM_AG1, 0x000000f0, 0, SROM4_AG10, 0xff00},
+ {BRCMS_SROM_AG2, 0x000000f0, 0, SROM4_AG32, 0x00ff},
+ {BRCMS_SROM_AG3, 0x000000f0, 0, SROM4_AG32, 0xff00},
+ {BRCMS_SROM_AG0, 0xffffff00, 0, SROM8_AG10, 0x00ff},
+ {BRCMS_SROM_AG1, 0xffffff00, 0, SROM8_AG10, 0xff00},
+ {BRCMS_SROM_AG2, 0xffffff00, 0, SROM8_AG32, 0x00ff},
+ {BRCMS_SROM_AG3, 0xffffff00, 0, SROM8_AG32, 0xff00},
+ {BRCMS_SROM_PA1B0, 0x0000000e, SRFL_PRHEX, SROM_WL1PAB0, 0xffff},
+ {BRCMS_SROM_PA1B1, 0x0000000e, SRFL_PRHEX, SROM_WL1PAB1, 0xffff},
+ {BRCMS_SROM_PA1B2, 0x0000000e, SRFL_PRHEX, SROM_WL1PAB2, 0xffff},
+ {BRCMS_SROM_PA1LOB0, 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB0, 0xffff},
+ {BRCMS_SROM_PA1LOB1, 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB1, 0xffff},
+ {BRCMS_SROM_PA1LOB2, 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB2, 0xffff},
+ {BRCMS_SROM_PA1HIB0, 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB0, 0xffff},
+ {BRCMS_SROM_PA1HIB1, 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB1, 0xffff},
+ {BRCMS_SROM_PA1HIB2, 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB2, 0xffff},
+ {BRCMS_SROM_PA1ITSSIT, 0x0000000e, 0, SROM_ITT, 0xff00},
+ {BRCMS_SROM_PA1MAXPWR, 0x0000000e, 0, SROM_WL10MAXP, 0xff00},
+ {BRCMS_SROM_PA1LOMAXPWR, 0x0000000c, 0, SROM_WL1LHMAXP, 0xff00},
+ {BRCMS_SROM_PA1HIMAXPWR, 0x0000000c, 0, SROM_WL1LHMAXP, 0x00ff},
+ {BRCMS_SROM_PA1B0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff},
+ {BRCMS_SROM_PA1B1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff},
+ {BRCMS_SROM_PA1B2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff},
+ {BRCMS_SROM_PA1LOB0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff},
+ {BRCMS_SROM_PA1LOB1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff},
+ {BRCMS_SROM_PA1LOB2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff},
+ {BRCMS_SROM_PA1HIB0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff},
+ {BRCMS_SROM_PA1HIB1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff},
+ {BRCMS_SROM_PA1HIB2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff},
+ {BRCMS_SROM_PA1ITSSIT, 0xffffff00, 0, SROM8_W1_ITTMAXP, 0xff00},
+ {BRCMS_SROM_PA1MAXPWR, 0xffffff00, 0, SROM8_W1_ITTMAXP, 0x00ff},
+ {BRCMS_SROM_PA1LOMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff00},
+ {BRCMS_SROM_PA1HIMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0x00ff},
+ {BRCMS_SROM_BXA2G, 0x00000008, 0, SROM_BXARSSI2G, 0x1800},
+ {BRCMS_SROM_RSSISAV2G, 0x00000008, 0, SROM_BXARSSI2G, 0x0700},
+ {BRCMS_SROM_RSSISMC2G, 0x00000008, 0, SROM_BXARSSI2G, 0x00f0},
+ {BRCMS_SROM_RSSISMF2G, 0x00000008, 0, SROM_BXARSSI2G, 0x000f},
+ {BRCMS_SROM_BXA2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x1800},
+ {BRCMS_SROM_RSSISAV2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x0700},
+ {BRCMS_SROM_RSSISMC2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x00f0},
+ {BRCMS_SROM_RSSISMF2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x000f},
+ {BRCMS_SROM_BXA5G, 0x00000008, 0, SROM_BXARSSI5G, 0x1800},
+ {BRCMS_SROM_RSSISAV5G, 0x00000008, 0, SROM_BXARSSI5G, 0x0700},
+ {BRCMS_SROM_RSSISMC5G, 0x00000008, 0, SROM_BXARSSI5G, 0x00f0},
+ {BRCMS_SROM_RSSISMF5G, 0x00000008, 0, SROM_BXARSSI5G, 0x000f},
+ {BRCMS_SROM_BXA5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x1800},
+ {BRCMS_SROM_RSSISAV5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x0700},
+ {BRCMS_SROM_RSSISMC5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x00f0},
+ {BRCMS_SROM_RSSISMF5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x000f},
+ {BRCMS_SROM_TRI2G, 0x00000008, 0, SROM_TRI52G, 0x00ff},
+ {BRCMS_SROM_TRI5G, 0x00000008, 0, SROM_TRI52G, 0xff00},
+ {BRCMS_SROM_TRI5GL, 0x00000008, 0, SROM_TRI5GHL, 0x00ff},
+ {BRCMS_SROM_TRI5GH, 0x00000008, 0, SROM_TRI5GHL, 0xff00},
+ {BRCMS_SROM_TRI2G, 0xffffff00, 0, SROM8_TRI52G, 0x00ff},
+ {BRCMS_SROM_TRI5G, 0xffffff00, 0, SROM8_TRI52G, 0xff00},
+ {BRCMS_SROM_TRI5GL, 0xffffff00, 0, SROM8_TRI5GHL, 0x00ff},
+ {BRCMS_SROM_TRI5GH, 0xffffff00, 0, SROM8_TRI5GHL, 0xff00},
+ {BRCMS_SROM_RXPO2G, 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0x00ff},
+ {BRCMS_SROM_RXPO5G, 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff00},
+ {BRCMS_SROM_RXPO2G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff},
+ {BRCMS_SROM_RXPO5G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00},
+ {BRCMS_SROM_TXCHAIN, 0x000000f0, SRFL_NOFFS, SROM4_TXRXC,
+ SROM4_TXCHAIN_MASK},
+ {BRCMS_SROM_RXCHAIN, 0x000000f0, SRFL_NOFFS, SROM4_TXRXC,
+ SROM4_RXCHAIN_MASK},
+ {BRCMS_SROM_ANTSWITCH, 0x000000f0, SRFL_NOFFS, SROM4_TXRXC,
+ SROM4_SWITCH_MASK},
+ {BRCMS_SROM_TXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
+ SROM4_TXCHAIN_MASK},
+ {BRCMS_SROM_RXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
+ SROM4_RXCHAIN_MASK},
+ {BRCMS_SROM_ANTSWITCH, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
+ SROM4_SWITCH_MASK},
+ {BRCMS_SROM_TSSIPOS2G, 0xffffff00, 0, SROM8_FEM2G,
+ SROM8_FEM_TSSIPOS_MASK},
+ {BRCMS_SROM_EXTPAGAIN2G, 0xffffff00, 0, SROM8_FEM2G,
+ SROM8_FEM_EXTPA_GAIN_MASK},
+ {BRCMS_SROM_PDETRANGE2G, 0xffffff00, 0, SROM8_FEM2G,
+ SROM8_FEM_PDET_RANGE_MASK},
+ {BRCMS_SROM_TRISO2G, 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_TR_ISO_MASK},
+ {BRCMS_SROM_ANTSWCTL2G, 0xffffff00, 0, SROM8_FEM2G,
+ SROM8_FEM_ANTSWLUT_MASK},
+ {BRCMS_SROM_TSSIPOS5G, 0xffffff00, 0, SROM8_FEM5G,
+ SROM8_FEM_TSSIPOS_MASK},
+ {BRCMS_SROM_EXTPAGAIN5G, 0xffffff00, 0, SROM8_FEM5G,
+ SROM8_FEM_EXTPA_GAIN_MASK},
+ {BRCMS_SROM_PDETRANGE5G, 0xffffff00, 0, SROM8_FEM5G,
+ SROM8_FEM_PDET_RANGE_MASK},
+ {BRCMS_SROM_TRISO5G, 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_TR_ISO_MASK},
+ {BRCMS_SROM_ANTSWCTL5G, 0xffffff00, 0, SROM8_FEM5G,
+ SROM8_FEM_ANTSWLUT_MASK},
+ {BRCMS_SROM_TEMPTHRESH, 0xffffff00, 0, SROM8_THERMAL, 0xff00},
+ {BRCMS_SROM_TEMPOFFSET, 0xffffff00, 0, SROM8_THERMAL, 0x00ff},
+ {BRCMS_SROM_TXPID2GA0, 0x000000f0, 0, SROM4_TXPID2G, 0x00ff},
+ {BRCMS_SROM_TXPID2GA1, 0x000000f0, 0, SROM4_TXPID2G, 0xff00},
+ {BRCMS_SROM_TXPID2GA2, 0x000000f0, 0, SROM4_TXPID2G + 1, 0x00ff},
+ {BRCMS_SROM_TXPID2GA3, 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff00},
+ {BRCMS_SROM_TXPID5GA0, 0x000000f0, 0, SROM4_TXPID5G, 0x00ff},
+ {BRCMS_SROM_TXPID5GA1, 0x000000f0, 0, SROM4_TXPID5G, 0xff00},
+ {BRCMS_SROM_TXPID5GA2, 0x000000f0, 0, SROM4_TXPID5G + 1, 0x00ff},
+ {BRCMS_SROM_TXPID5GA3, 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff00},
+ {BRCMS_SROM_TXPID5GLA0, 0x000000f0, 0, SROM4_TXPID5GL, 0x00ff},
+ {BRCMS_SROM_TXPID5GLA1, 0x000000f0, 0, SROM4_TXPID5GL, 0xff00},
+ {BRCMS_SROM_TXPID5GLA2, 0x000000f0, 0, SROM4_TXPID5GL + 1, 0x00ff},
+ {BRCMS_SROM_TXPID5GLA3, 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff00},
+ {BRCMS_SROM_TXPID5GHA0, 0x000000f0, 0, SROM4_TXPID5GH, 0x00ff},
+ {BRCMS_SROM_TXPID5GHA1, 0x000000f0, 0, SROM4_TXPID5GH, 0xff00},
+ {BRCMS_SROM_TXPID5GHA2, 0x000000f0, 0, SROM4_TXPID5GH + 1, 0x00ff},
+ {BRCMS_SROM_TXPID5GHA3, 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff00},
+
+ {BRCMS_SROM_CCODE, 0x0000000f, SRFL_CCODE, SROM_CCODE, 0xffff},
+ {BRCMS_SROM_CCODE, 0x00000010, SRFL_CCODE, SROM4_CCODE, 0xffff},
+ {BRCMS_SROM_CCODE, 0x000000e0, SRFL_CCODE, SROM5_CCODE, 0xffff},
+ {BRCMS_SROM_CCODE, 0xffffff00, SRFL_CCODE, SROM8_CCODE, 0xffff},
+ {BRCMS_SROM_MACADDR, 0xffffff00, SRFL_ETHADDR, SROM8_MACHI, 0xffff},
+ {BRCMS_SROM_MACADDR, 0x000000e0, SRFL_ETHADDR, SROM5_MACHI, 0xffff},
+ {BRCMS_SROM_MACADDR, 0x00000010, SRFL_ETHADDR, SROM4_MACHI, 0xffff},
+ {BRCMS_SROM_MACADDR, 0x00000008, SRFL_ETHADDR, SROM3_MACHI, 0xffff},
+ {BRCMS_SROM_IL0MACADDR, 0x00000007, SRFL_ETHADDR, SROM_MACHI_IL0,
+ 0xffff},
+ {BRCMS_SROM_ET1MACADDR, 0x00000007, SRFL_ETHADDR, SROM_MACHI_ET1,
+ 0xffff},
+ {BRCMS_SROM_LEDDC, 0xffffff00, SRFL_NOFFS | SRFL_LEDDC, SROM8_LEDDC,
+ 0xffff},
+ {BRCMS_SROM_LEDDC, 0x000000e0, SRFL_NOFFS | SRFL_LEDDC, SROM5_LEDDC,
+ 0xffff},
+ {BRCMS_SROM_LEDDC, 0x00000010, SRFL_NOFFS | SRFL_LEDDC, SROM4_LEDDC,
+ 0xffff},
+ {BRCMS_SROM_LEDDC, 0x00000008, SRFL_NOFFS | SRFL_LEDDC, SROM3_LEDDC,
+ 0xffff},
+ {BRCMS_SROM_RAWTEMPSENSE, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS,
+ 0x01ff},
+ {BRCMS_SROM_MEASPOWER, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS,
+ 0xfe00},
+ {BRCMS_SROM_TEMPSENSE_SLOPE, 0xffffff00, SRFL_PRHEX,
+ SROM8_TS_SLP_OPT_CORRX, 0x00ff},
+ {BRCMS_SROM_TEMPCORRX, 0xffffff00, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX,
+ 0xfc00},
+ {BRCMS_SROM_TEMPSENSE_OPTION, 0xffffff00, SRFL_PRHEX,
+ SROM8_TS_SLP_OPT_CORRX, 0x0300},
+ {BRCMS_SROM_FREQOFFSET_CORR, 0xffffff00, SRFL_PRHEX,
+ SROM8_FOC_HWIQ_IQSWP, 0x000f},
+ {BRCMS_SROM_IQCAL_SWP_DIS, 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP,
+ 0x0010},
+ {BRCMS_SROM_HW_IQCAL_EN, 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP,
+ 0x0020},
+ {BRCMS_SROM_PHYCAL_TEMPDELTA, 0xffffff00, 0, SROM8_PHYCAL_TEMPDELTA,
+ 0x00ff},
+
+ {BRCMS_SROM_CCK2GPO, 0x000000f0, 0, SROM4_2G_CCKPO, 0xffff},
+ {BRCMS_SROM_CCK2GPO, 0x00000100, 0, SROM8_2G_CCKPO, 0xffff},
+ {BRCMS_SROM_OFDM2GPO, 0x000000f0, SRFL_MORE, SROM4_2G_OFDMPO, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM4_2G_OFDMPO + 1, 0xffff},
+ {BRCMS_SROM_OFDM5GPO, 0x000000f0, SRFL_MORE, SROM4_5G_OFDMPO, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM4_5G_OFDMPO + 1, 0xffff},
+ {BRCMS_SROM_OFDM5GLPO, 0x000000f0, SRFL_MORE, SROM4_5GL_OFDMPO, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM4_5GL_OFDMPO + 1, 0xffff},
+ {BRCMS_SROM_OFDM5GHPO, 0x000000f0, SRFL_MORE, SROM4_5GH_OFDMPO, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM4_5GH_OFDMPO + 1, 0xffff},
+ {BRCMS_SROM_OFDM2GPO, 0x00000100, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM8_2G_OFDMPO + 1, 0xffff},
+ {BRCMS_SROM_OFDM5GPO, 0x00000100, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM8_5G_OFDMPO + 1, 0xffff},
+ {BRCMS_SROM_OFDM5GLPO, 0x00000100, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff},
+ {BRCMS_SROM_OFDM5GHPO, 0x00000100, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff},
+ {BRCMS_SROM_MCS2GPO0, 0x000000f0, 0, SROM4_2G_MCSPO, 0xffff},
+ {BRCMS_SROM_MCS2GPO1, 0x000000f0, 0, SROM4_2G_MCSPO + 1, 0xffff},
+ {BRCMS_SROM_MCS2GPO2, 0x000000f0, 0, SROM4_2G_MCSPO + 2, 0xffff},
+ {BRCMS_SROM_MCS2GPO3, 0x000000f0, 0, SROM4_2G_MCSPO + 3, 0xffff},
+ {BRCMS_SROM_MCS2GPO4, 0x000000f0, 0, SROM4_2G_MCSPO + 4, 0xffff},
+ {BRCMS_SROM_MCS2GPO5, 0x000000f0, 0, SROM4_2G_MCSPO + 5, 0xffff},
+ {BRCMS_SROM_MCS2GPO6, 0x000000f0, 0, SROM4_2G_MCSPO + 6, 0xffff},
+ {BRCMS_SROM_MCS2GPO7, 0x000000f0, 0, SROM4_2G_MCSPO + 7, 0xffff},
+ {BRCMS_SROM_MCS5GPO0, 0x000000f0, 0, SROM4_5G_MCSPO, 0xffff},
+ {BRCMS_SROM_MCS5GPO1, 0x000000f0, 0, SROM4_5G_MCSPO + 1, 0xffff},
+ {BRCMS_SROM_MCS5GPO2, 0x000000f0, 0, SROM4_5G_MCSPO + 2, 0xffff},
+ {BRCMS_SROM_MCS5GPO3, 0x000000f0, 0, SROM4_5G_MCSPO + 3, 0xffff},
+ {BRCMS_SROM_MCS5GPO4, 0x000000f0, 0, SROM4_5G_MCSPO + 4, 0xffff},
+ {BRCMS_SROM_MCS5GPO5, 0x000000f0, 0, SROM4_5G_MCSPO + 5, 0xffff},
+ {BRCMS_SROM_MCS5GPO6, 0x000000f0, 0, SROM4_5G_MCSPO + 6, 0xffff},
+ {BRCMS_SROM_MCS5GPO7, 0x000000f0, 0, SROM4_5G_MCSPO + 7, 0xffff},
+ {BRCMS_SROM_MCS5GLPO0, 0x000000f0, 0, SROM4_5GL_MCSPO, 0xffff},
+ {BRCMS_SROM_MCS5GLPO1, 0x000000f0, 0, SROM4_5GL_MCSPO + 1, 0xffff},
+ {BRCMS_SROM_MCS5GLPO2, 0x000000f0, 0, SROM4_5GL_MCSPO + 2, 0xffff},
+ {BRCMS_SROM_MCS5GLPO3, 0x000000f0, 0, SROM4_5GL_MCSPO + 3, 0xffff},
+ {BRCMS_SROM_MCS5GLPO4, 0x000000f0, 0, SROM4_5GL_MCSPO + 4, 0xffff},
+ {BRCMS_SROM_MCS5GLPO5, 0x000000f0, 0, SROM4_5GL_MCSPO + 5, 0xffff},
+ {BRCMS_SROM_MCS5GLPO6, 0x000000f0, 0, SROM4_5GL_MCSPO + 6, 0xffff},
+ {BRCMS_SROM_MCS5GLPO7, 0x000000f0, 0, SROM4_5GL_MCSPO + 7, 0xffff},
+ {BRCMS_SROM_MCS5GHPO0, 0x000000f0, 0, SROM4_5GH_MCSPO, 0xffff},
+ {BRCMS_SROM_MCS5GHPO1, 0x000000f0, 0, SROM4_5GH_MCSPO + 1, 0xffff},
+ {BRCMS_SROM_MCS5GHPO2, 0x000000f0, 0, SROM4_5GH_MCSPO + 2, 0xffff},
+ {BRCMS_SROM_MCS5GHPO3, 0x000000f0, 0, SROM4_5GH_MCSPO + 3, 0xffff},
+ {BRCMS_SROM_MCS5GHPO4, 0x000000f0, 0, SROM4_5GH_MCSPO + 4, 0xffff},
+ {BRCMS_SROM_MCS5GHPO5, 0x000000f0, 0, SROM4_5GH_MCSPO + 5, 0xffff},
+ {BRCMS_SROM_MCS5GHPO6, 0x000000f0, 0, SROM4_5GH_MCSPO + 6, 0xffff},
+ {BRCMS_SROM_MCS5GHPO7, 0x000000f0, 0, SROM4_5GH_MCSPO + 7, 0xffff},
+ {BRCMS_SROM_MCS2GPO0, 0x00000100, 0, SROM8_2G_MCSPO, 0xffff},
+ {BRCMS_SROM_MCS2GPO1, 0x00000100, 0, SROM8_2G_MCSPO + 1, 0xffff},
+ {BRCMS_SROM_MCS2GPO2, 0x00000100, 0, SROM8_2G_MCSPO + 2, 0xffff},
+ {BRCMS_SROM_MCS2GPO3, 0x00000100, 0, SROM8_2G_MCSPO + 3, 0xffff},
+ {BRCMS_SROM_MCS2GPO4, 0x00000100, 0, SROM8_2G_MCSPO + 4, 0xffff},
+ {BRCMS_SROM_MCS2GPO5, 0x00000100, 0, SROM8_2G_MCSPO + 5, 0xffff},
+ {BRCMS_SROM_MCS2GPO6, 0x00000100, 0, SROM8_2G_MCSPO + 6, 0xffff},
+ {BRCMS_SROM_MCS2GPO7, 0x00000100, 0, SROM8_2G_MCSPO + 7, 0xffff},
+ {BRCMS_SROM_MCS5GPO0, 0x00000100, 0, SROM8_5G_MCSPO, 0xffff},
+ {BRCMS_SROM_MCS5GPO1, 0x00000100, 0, SROM8_5G_MCSPO + 1, 0xffff},
+ {BRCMS_SROM_MCS5GPO2, 0x00000100, 0, SROM8_5G_MCSPO + 2, 0xffff},
+ {BRCMS_SROM_MCS5GPO3, 0x00000100, 0, SROM8_5G_MCSPO + 3, 0xffff},
+ {BRCMS_SROM_MCS5GPO4, 0x00000100, 0, SROM8_5G_MCSPO + 4, 0xffff},
+ {BRCMS_SROM_MCS5GPO5, 0x00000100, 0, SROM8_5G_MCSPO + 5, 0xffff},
+ {BRCMS_SROM_MCS5GPO6, 0x00000100, 0, SROM8_5G_MCSPO + 6, 0xffff},
+ {BRCMS_SROM_MCS5GPO7, 0x00000100, 0, SROM8_5G_MCSPO + 7, 0xffff},
+ {BRCMS_SROM_MCS5GLPO0, 0x00000100, 0, SROM8_5GL_MCSPO, 0xffff},
+ {BRCMS_SROM_MCS5GLPO1, 0x00000100, 0, SROM8_5GL_MCSPO + 1, 0xffff},
+ {BRCMS_SROM_MCS5GLPO2, 0x00000100, 0, SROM8_5GL_MCSPO + 2, 0xffff},
+ {BRCMS_SROM_MCS5GLPO3, 0x00000100, 0, SROM8_5GL_MCSPO + 3, 0xffff},
+ {BRCMS_SROM_MCS5GLPO4, 0x00000100, 0, SROM8_5GL_MCSPO + 4, 0xffff},
+ {BRCMS_SROM_MCS5GLPO5, 0x00000100, 0, SROM8_5GL_MCSPO + 5, 0xffff},
+ {BRCMS_SROM_MCS5GLPO6, 0x00000100, 0, SROM8_5GL_MCSPO + 6, 0xffff},
+ {BRCMS_SROM_MCS5GLPO7, 0x00000100, 0, SROM8_5GL_MCSPO + 7, 0xffff},
+ {BRCMS_SROM_MCS5GHPO0, 0x00000100, 0, SROM8_5GH_MCSPO, 0xffff},
+ {BRCMS_SROM_MCS5GHPO1, 0x00000100, 0, SROM8_5GH_MCSPO + 1, 0xffff},
+ {BRCMS_SROM_MCS5GHPO2, 0x00000100, 0, SROM8_5GH_MCSPO + 2, 0xffff},
+ {BRCMS_SROM_MCS5GHPO3, 0x00000100, 0, SROM8_5GH_MCSPO + 3, 0xffff},
+ {BRCMS_SROM_MCS5GHPO4, 0x00000100, 0, SROM8_5GH_MCSPO + 4, 0xffff},
+ {BRCMS_SROM_MCS5GHPO5, 0x00000100, 0, SROM8_5GH_MCSPO + 5, 0xffff},
+ {BRCMS_SROM_MCS5GHPO6, 0x00000100, 0, SROM8_5GH_MCSPO + 6, 0xffff},
+ {BRCMS_SROM_MCS5GHPO7, 0x00000100, 0, SROM8_5GH_MCSPO + 7, 0xffff},
+ {BRCMS_SROM_CDDPO, 0x000000f0, 0, SROM4_CDDPO, 0xffff},
+ {BRCMS_SROM_STBCPO, 0x000000f0, 0, SROM4_STBCPO, 0xffff},
+ {BRCMS_SROM_BW40PO, 0x000000f0, 0, SROM4_BW40PO, 0xffff},
+ {BRCMS_SROM_BWDUPPO, 0x000000f0, 0, SROM4_BWDUPPO, 0xffff},
+ {BRCMS_SROM_CDDPO, 0x00000100, 0, SROM8_CDDPO, 0xffff},
+ {BRCMS_SROM_STBCPO, 0x00000100, 0, SROM8_STBCPO, 0xffff},
+ {BRCMS_SROM_BW40PO, 0x00000100, 0, SROM8_BW40PO, 0xffff},
+ {BRCMS_SROM_BWDUPPO, 0x00000100, 0, SROM8_BWDUPPO, 0xffff},
+
+ /* power per rate from sromrev 9 */
+ {BRCMS_SROM_CCKBW202GPO, 0xfffffe00, 0, SROM9_2GPO_CCKBW20, 0xffff},
+ {BRCMS_SROM_CCKBW20UL2GPO, 0xfffffe00, 0, SROM9_2GPO_CCKBW20UL, 0xffff},
+ {BRCMS_SROM_LEGOFDMBW202GPO, 0xfffffe00, SRFL_MORE,
+ SROM9_2GPO_LOFDMBW20, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_LOFDMBW20 + 1, 0xffff},
+ {BRCMS_SROM_LEGOFDMBW20UL2GPO, 0xfffffe00, SRFL_MORE,
+ SROM9_2GPO_LOFDMBW20UL, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_LOFDMBW20UL + 1, 0xffff},
+ {BRCMS_SROM_LEGOFDMBW205GLPO, 0xfffffe00, SRFL_MORE,
+ SROM9_5GLPO_LOFDMBW20, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_LOFDMBW20 + 1, 0xffff},
+ {BRCMS_SROM_LEGOFDMBW20UL5GLPO, 0xfffffe00, SRFL_MORE,
+ SROM9_5GLPO_LOFDMBW20UL, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_LOFDMBW20UL + 1, 0xffff},
+ {BRCMS_SROM_LEGOFDMBW205GMPO, 0xfffffe00, SRFL_MORE,
+ SROM9_5GMPO_LOFDMBW20, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_LOFDMBW20 + 1, 0xffff},
+ {BRCMS_SROM_LEGOFDMBW20UL5GMPO, 0xfffffe00, SRFL_MORE,
+ SROM9_5GMPO_LOFDMBW20UL, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_LOFDMBW20UL + 1, 0xffff},
+ {BRCMS_SROM_LEGOFDMBW205GHPO, 0xfffffe00, SRFL_MORE,
+ SROM9_5GHPO_LOFDMBW20, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_LOFDMBW20 + 1, 0xffff},
+ {BRCMS_SROM_LEGOFDMBW20UL5GHPO, 0xfffffe00, SRFL_MORE,
+ SROM9_5GHPO_LOFDMBW20UL, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_LOFDMBW20UL + 1, 0xffff},
+ {BRCMS_SROM_MCSBW202GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW20 + 1, 0xffff},
+ {BRCMS_SROM_MCSBW20UL2GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20UL,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW20UL + 1, 0xffff},
+ {BRCMS_SROM_MCSBW402GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW40,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW40 + 1, 0xffff},
+ {BRCMS_SROM_MCSBW205GLPO, 0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW20,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW20 + 1, 0xffff},
+ {BRCMS_SROM_MCSBW20UL5GLPO, 0xfffffe00, SRFL_MORE,
+ SROM9_5GLPO_MCSBW20UL, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW20UL + 1, 0xffff},
+ {BRCMS_SROM_MCSBW405GLPO, 0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW40,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW40 + 1, 0xffff},
+ {BRCMS_SROM_MCSBW205GMPO, 0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW20,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW20 + 1, 0xffff},
+ {BRCMS_SROM_MCSBW20UL5GMPO, 0xfffffe00, SRFL_MORE,
+ SROM9_5GMPO_MCSBW20UL, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW20UL + 1, 0xffff},
+ {BRCMS_SROM_MCSBW405GMPO, 0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW40,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW40 + 1, 0xffff},
+ {BRCMS_SROM_MCSBW205GHPO, 0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW20,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW20 + 1, 0xffff},
+ {BRCMS_SROM_MCSBW20UL5GHPO, 0xfffffe00, SRFL_MORE,
+ SROM9_5GHPO_MCSBW20UL, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW20UL + 1, 0xffff},
+ {BRCMS_SROM_MCSBW405GHPO, 0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW40,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW40 + 1, 0xffff},
+ {BRCMS_SROM_MCS32PO, 0xfffffe00, 0, SROM9_PO_MCS32, 0xffff},
+ {BRCMS_SROM_LEGOFDM40DUPPO, 0xfffffe00, 0, SROM9_PO_LOFDM40DUP, 0xffff},
+
+ {BRCMS_SROM_NULL, 0, 0, 0, 0}
+};
+
+static const struct brcms_sromvar perpath_pci_sromvars[] = {
+ {BRCMS_SROM_MAXP2GA0, 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0x00ff},
+ {BRCMS_SROM_ITT2GA0, 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff00},
+ {BRCMS_SROM_ITT5GA0, 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff00},
+ {BRCMS_SROM_PA2GW0A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA, 0xffff},
+ {BRCMS_SROM_PA2GW1A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 1, 0xffff},
+ {BRCMS_SROM_PA2GW2A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 2, 0xffff},
+ {BRCMS_SROM_PA2GW3A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 3, 0xffff},
+ {BRCMS_SROM_MAXP5GA0, 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0x00ff},
+ {BRCMS_SROM_MAXP5GHA0, 0x000000f0, 0, SROM4_5GLH_MAXP, 0x00ff},
+ {BRCMS_SROM_MAXP5GLA0, 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff00},
+ {BRCMS_SROM_PA5GW0A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA, 0xffff},
+ {BRCMS_SROM_PA5GW1A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 1, 0xffff},
+ {BRCMS_SROM_PA5GW2A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 2, 0xffff},
+ {BRCMS_SROM_PA5GW3A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 3, 0xffff},
+ {BRCMS_SROM_PA5GLW0A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA, 0xffff},
+ {BRCMS_SROM_PA5GLW1A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 1,
+ 0xffff},
+ {BRCMS_SROM_PA5GLW2A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 2,
+ 0xffff},
+ {BRCMS_SROM_PA5GLW3A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 3,
+ 0xffff},
+ {BRCMS_SROM_PA5GHW0A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA, 0xffff},
+ {BRCMS_SROM_PA5GHW1A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 1,
+ 0xffff},
+ {BRCMS_SROM_PA5GHW2A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 2,
+ 0xffff},
+ {BRCMS_SROM_PA5GHW3A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 3,
+ 0xffff},
+ {BRCMS_SROM_MAXP2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0x00ff},
+ {BRCMS_SROM_ITT2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff00},
+ {BRCMS_SROM_ITT5GA0, 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff00},
+ {BRCMS_SROM_PA2GW0A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA, 0xffff},
+ {BRCMS_SROM_PA2GW1A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 1, 0xffff},
+ {BRCMS_SROM_PA2GW2A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 2, 0xffff},
+ {BRCMS_SROM_MAXP5GA0, 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0x00ff},
+ {BRCMS_SROM_MAXP5GHA0, 0xffffff00, 0, SROM8_5GLH_MAXP, 0x00ff},
+ {BRCMS_SROM_MAXP5GLA0, 0xffffff00, 0, SROM8_5GLH_MAXP, 0xff00},
+ {BRCMS_SROM_PA5GW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA, 0xffff},
+ {BRCMS_SROM_PA5GW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 1, 0xffff},
+ {BRCMS_SROM_PA5GW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 2, 0xffff},
+ {BRCMS_SROM_PA5GLW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA, 0xffff},
+ {BRCMS_SROM_PA5GLW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 1,
+ 0xffff},
+ {BRCMS_SROM_PA5GLW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 2,
+ 0xffff},
+ {BRCMS_SROM_PA5GHW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA, 0xffff},
+ {BRCMS_SROM_PA5GHW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 1,
+ 0xffff},
+ {BRCMS_SROM_PA5GHW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 2,
+ 0xffff},
+ {BRCMS_SROM_NULL, 0, 0, 0, 0}
+};
+
+/* crc table has the same contents for every device instance, so it can be
+ * shared between devices. */
+static u8 brcms_srom_crc8_table[CRC8_TABLE_SIZE];
+
+static u16 __iomem *
+srom_window_address(struct si_pub *sih, u8 __iomem *curmap)
+{
+ if (sih->ccrev < 32)
+ return (u16 __iomem *)(curmap + PCI_BAR0_SPROM_OFFSET);
+ if (sih->cccaps & CC_CAP_SROM)
+ return (u16 __iomem *)
+ (curmap + PCI_16KB0_CCREGS_OFFSET + CC_SROM_OTP);
+
+ return NULL;
+}
+
+/* Parse SROM and create name=value pairs. 'srom' points to
+ * the SROM word array. 'off' specifies the offset of the
+ * first word 'srom' points to, which should be either 0 or
+ * SROM3_SWRG_OFF (full SROM or software region).
+ */
+
+static uint mask_shift(u16 mask)
+{
+ uint i;
+ for (i = 0; i < (sizeof(mask) << 3); i++) {
+ if (mask & (1 << i))
+ return i;
+ }
+ return 0;
+}
+
+static uint mask_width(u16 mask)
+{
+ int i;
+ for (i = (sizeof(mask) << 3) - 1; i >= 0; i--) {
+ if (mask & (1 << i))
+ return (uint) (i - mask_shift(mask) + 1);
+ }
+ return 0;
+}
+
+static inline void ltoh16_buf(u16 *buf, unsigned int size)
+{
+ size /= 2;
+ while (size--)
+ *(buf + size) = le16_to_cpu(*(__le16 *)(buf + size));
+}
+
+static inline void htol16_buf(u16 *buf, unsigned int size)
+{
+ size /= 2;
+ while (size--)
+ *(__le16 *)(buf + size) = cpu_to_le16(*(buf + size));
+}
+
+/*
+ * convert binary srom data into linked list of srom variable items.
+ */
+static void
+_initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
+{
+ struct brcms_srom_list_head *entry;
+ enum brcms_srom_id id;
+ u16 w;
+ u32 val;
+ const struct brcms_sromvar *srv;
+ uint width;
+ uint flags;
+ u32 sr = (1 << sromrev);
+
+ /* first store the srom revision */
+ entry = kzalloc(sizeof(struct brcms_srom_list_head), GFP_KERNEL);
+ entry->varid = BRCMS_SROM_REV;
+ entry->var_type = BRCMS_SROM_UNUMBER;
+ entry->uval = sromrev;
+ list_add(&entry->var_list, var_list);
+
+ for (srv = pci_sromvars; srv->varid != BRCMS_SROM_NULL; srv++) {
+ enum brcms_srom_var_type type;
+ u8 ea[ETH_ALEN];
+ u8 extra_space = 0;
+
+ if ((srv->revmask & sr) == 0)
+ continue;
+
+ flags = srv->flags;
+ id = srv->varid;
+
+ /* This entry is for mfgc only. Don't generate param for it, */
+ if (flags & SRFL_NOVAR)
+ continue;
+
+ if (flags & SRFL_ETHADDR) {
+ /*
+ * stored in string format XX:XX:XX:XX:XX:XX (17 chars)
+ */
+ ea[0] = (srom[srv->off] >> 8) & 0xff;
+ ea[1] = srom[srv->off] & 0xff;
+ ea[2] = (srom[srv->off + 1] >> 8) & 0xff;
+ ea[3] = srom[srv->off + 1] & 0xff;
+ ea[4] = (srom[srv->off + 2] >> 8) & 0xff;
+ ea[5] = srom[srv->off + 2] & 0xff;
+ /* 17 characters + string terminator - union size */
+ extra_space = 18 - sizeof(s32);
+ type = BRCMS_SROM_STRING;
+ } else {
+ w = srom[srv->off];
+ val = (w & srv->mask) >> mask_shift(srv->mask);
+ width = mask_width(srv->mask);
+
+ while (srv->flags & SRFL_MORE) {
+ srv++;
+ if (srv->off == 0)
+ continue;
+
+ w = srom[srv->off];
+ val +=
+ ((w & srv->mask) >> mask_shift(srv->
+ mask)) <<
+ width;
+ width += mask_width(srv->mask);
+ }
+
+ if ((flags & SRFL_NOFFS)
+ && ((int)val == (1 << width) - 1))
+ continue;
+
+ if (flags & SRFL_CCODE) {
+ type = BRCMS_SROM_STRING;
+ } else if (flags & SRFL_LEDDC) {
+ /* LED Powersave duty cycle has to be scaled:
+ *(oncount >> 24) (offcount >> 8)
+ */
+ u32 w32 = /* oncount */
+ (((val >> 8) & 0xff) << 24) |
+ /* offcount */
+ (((val & 0xff)) << 8);
+ type = BRCMS_SROM_UNUMBER;
+ val = w32;
+ } else if ((flags & SRFL_PRSIGN)
+ && (val & (1 << (width - 1)))) {
+ type = BRCMS_SROM_SNUMBER;
+ val |= ~0 << width;
+ } else
+ type = BRCMS_SROM_UNUMBER;
+ }
+
+ entry = kzalloc(sizeof(struct brcms_srom_list_head) +
+ extra_space, GFP_KERNEL);
+ entry->varid = id;
+ entry->var_type = type;
+ if (flags & SRFL_ETHADDR) {
+ snprintf(entry->buf, 18, "%pM", ea);
+ } else if (flags & SRFL_CCODE) {
+ if (val == 0)
+ entry->buf[0] = '\0';
+ else
+ snprintf(entry->buf, 3, "%c%c",
+ (val >> 8), (val & 0xff));
+ } else {
+ entry->uval = val;
+ }
+
+ list_add(&entry->var_list, var_list);
+ }
+
+ if (sromrev >= 4) {
+ /* Do per-path variables */
+ uint p, pb, psz;
+
+ if (sromrev >= 8) {
+ pb = SROM8_PATH0;
+ psz = SROM8_PATH1 - SROM8_PATH0;
+ } else {
+ pb = SROM4_PATH0;
+ psz = SROM4_PATH1 - SROM4_PATH0;
+ }
+
+ for (p = 0; p < MAX_PATH_SROM; p++) {
+ for (srv = perpath_pci_sromvars;
+ srv->varid != BRCMS_SROM_NULL; srv++) {
+ if ((srv->revmask & sr) == 0)
+ continue;
+
+ if (srv->flags & SRFL_NOVAR)
+ continue;
+
+ w = srom[pb + srv->off];
+ val = (w & srv->mask) >> mask_shift(srv->mask);
+ width = mask_width(srv->mask);
+
+ /* Cheating: no per-path var is more than
+ * 1 word */
+ if ((srv->flags & SRFL_NOFFS)
+ && ((int)val == (1 << width) - 1))
+ continue;
+
+ entry =
+ kzalloc(sizeof(struct brcms_srom_list_head),
+ GFP_KERNEL);
+ entry->varid = srv->varid+p;
+ entry->var_type = BRCMS_SROM_UNUMBER;
+ entry->uval = val;
+ list_add(&entry->var_list, var_list);
+ }
+ pb += psz;
+ }
+ }
+}
+
+/*
+ * Read in and validate sprom.
+ * Return 0 on success, nonzero on error.
+ */
+static int
+sprom_read_pci(struct si_pub *sih, u16 __iomem *sprom, uint wordoff,
+ u16 *buf, uint nwords, bool check_crc)
+{
+ int err = 0;
+ uint i;
+
+ /* read the sprom */
+ for (i = 0; i < nwords; i++)
+ buf[i] = R_REG(&sprom[wordoff + i]);
+
+ if (check_crc) {
+
+ if (buf[0] == 0xffff)
+ /*
+ * The hardware thinks that an srom that starts with
+ * 0xffff is blank, regardless of the rest of the
+ * content, so declare it bad.
+ */
+ return -ENODATA;
+
+ /* fixup the endianness so crc8 will pass */
+ htol16_buf(buf, nwords * 2);
+ if (crc8(brcms_srom_crc8_table, (u8 *) buf, nwords * 2,
+ CRC8_INIT_VALUE) !=
+ CRC8_GOOD_VALUE(brcms_srom_crc8_table))
+ /* DBG only pci always read srom4 first, then srom8/9 */
+ err = -EIO;
+
+ /* now correct the endianness of the byte array */
+ ltoh16_buf(buf, nwords * 2);
+ }
+ return err;
+}
+
+static int otp_read_pci(struct si_pub *sih, u16 *buf, uint bufsz)
+{
+ u8 *otp;
+ uint sz = OTP_SZ_MAX / 2; /* size in words */
+ int err = 0;
+
+ otp = kzalloc(OTP_SZ_MAX, GFP_ATOMIC);
+ if (otp == NULL)
+ return -ENOMEM;
+
+ err = otp_read_region(sih, OTP_HW_RGN, (u16 *) otp, &sz);
+
+ memcpy(buf, otp, bufsz);
+
+ kfree(otp);
+
+ /* Check CRC */
+ if (buf[0] == 0xffff)
+ /* The hardware thinks that an srom that starts with 0xffff
+ * is blank, regardless of the rest of the content, so declare
+ * it bad.
+ */
+ return -ENODATA;
+
+ /* fixup the endianness so crc8 will pass */
+ htol16_buf(buf, bufsz);
+ if (crc8(brcms_srom_crc8_table, (u8 *) buf, SROM4_WORDS * 2,
+ CRC8_INIT_VALUE) != CRC8_GOOD_VALUE(brcms_srom_crc8_table))
+ err = -EIO;
+
+ /* now correct the endianness of the byte array */
+ ltoh16_buf(buf, bufsz);
+
+ return err;
+}
+
+/*
+ * Initialize nonvolatile variable table from sprom.
+ * Return 0 on success, nonzero on error.
+ */
+static int initvars_srom_pci(struct si_pub *sih, void __iomem *curmap)
+{
+ u16 *srom;
+ u16 __iomem *sromwindow;
+ u8 sromrev = 0;
+ u32 sr;
+ int err = 0;
+
+ /*
+ * Apply CRC over SROM content regardless SROM is present or not.
+ */
+ srom = kmalloc(SROM_MAX, GFP_ATOMIC);
+ if (!srom)
+ return -ENOMEM;
+
+ sromwindow = srom_window_address(sih, curmap);
+
+ crc8_populate_lsb(brcms_srom_crc8_table, SROM_CRC8_POLY);
+ if (ai_is_sprom_available(sih)) {
+ err = sprom_read_pci(sih, sromwindow, 0, srom, SROM_WORDS,
+ true);
+
+ if ((srom[SROM4_SIGN] == SROM4_SIGNATURE) ||
+ (((sih->buscoretype == PCIE_CORE_ID)
+ && (sih->buscorerev >= 6))
+ || ((sih->buscoretype == PCI_CORE_ID)
+ && (sih->buscorerev >= 0xe)))) {
+ /* sromrev >= 4, read more */
+ err = sprom_read_pci(sih, sromwindow, 0, srom,
+ SROM4_WORDS, true);
+ sromrev = srom[SROM4_CRCREV] & 0xff;
+ } else if (err == 0) {
+ /* srom is good and is rev < 4 */
+ /* top word of sprom contains version and crc8 */
+ sromrev = srom[SROM_CRCREV] & 0xff;
+ /* bcm4401 sroms misprogrammed */
+ if (sromrev == 0x10)
+ sromrev = 1;
+ }
+ } else {
+ /* Use OTP if SPROM not available */
+ err = otp_read_pci(sih, srom, SROM_MAX);
+ if (err == 0)
+ /* OTP only contain SROM rev8/rev9 for now */
+ sromrev = srom[SROM4_CRCREV] & 0xff;
+ }
+
+ if (!err) {
+ struct si_info *sii = (struct si_info *)sih;
+
+ /* Bitmask for the sromrev */
+ sr = 1 << sromrev;
+
+ /*
+ * srom version check: Current valid versions: 1, 2, 3, 4, 5, 8,
+ * 9
+ */
+ if ((sr & 0x33e) == 0) {
+ err = -EINVAL;
+ goto errout;
+ }
+
+ INIT_LIST_HEAD(&sii->var_list);
+
+ /* parse SROM into name=value pairs. */
+ _initvars_srom_pci(sromrev, srom, &sii->var_list);
+ }
+
+errout:
+ kfree(srom);
+ return err;
+}
+
+void srom_free_vars(struct si_pub *sih)
+{
+ struct si_info *sii;
+ struct brcms_srom_list_head *entry, *next;
+
+ sii = (struct si_info *)sih;
+ list_for_each_entry_safe(entry, next, &sii->var_list, var_list) {
+ list_del(&entry->var_list);
+ kfree(entry);
+ }
+}
+/*
+ * Initialize local vars from the right source for this platform.
+ * Return 0 on success, nonzero on error.
+ */
+int srom_var_init(struct si_pub *sih, void __iomem *curmap)
+{
+ uint len;
+
+ len = 0;
+
+ if (curmap != NULL)
+ return initvars_srom_pci(sih, curmap);
+
+ return -EINVAL;
+}
+
+/*
+ * Search the name=value vars for a specific one and return its value.
+ * Returns NULL if not found.
+ */
+char *getvar(struct si_pub *sih, enum brcms_srom_id id)
+{
+ struct si_info *sii;
+ struct brcms_srom_list_head *entry;
+
+ sii = (struct si_info *)sih;
+
+ list_for_each_entry(entry, &sii->var_list, var_list)
+ if (entry->varid == id)
+ return &entry->buf[0];
+
+ /* nothing found */
+ return NULL;
+}
+
+/*
+ * Search the vars for a specific one and return its value as
+ * an integer. Returns 0 if not found.-
+ */
+int getintvar(struct si_pub *sih, enum brcms_srom_id id)
+{
+ struct si_info *sii;
+ struct brcms_srom_list_head *entry;
+ unsigned long res;
+
+ sii = (struct si_info *)sih;
+
+ list_for_each_entry(entry, &sii->var_list, var_list)
+ if (entry->varid == id) {
+ if (entry->var_type == BRCMS_SROM_SNUMBER ||
+ entry->var_type == BRCMS_SROM_UNUMBER)
+ return (int)entry->sval;
+ else if (!kstrtoul(&entry->buf[0], 0, &res))
+ return (int)res;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/srom.h b/drivers/net/wireless/brcm80211/brcmsmac/srom.h
new file mode 100644
index 000000000000..708c43ff51cc
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/srom.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_SROM_H_
+#define _BRCM_SROM_H_
+
+#include "types.h"
+
+/* Prototypes */
+extern int srom_var_init(struct si_pub *sih, void __iomem *curmap);
+extern void srom_free_vars(struct si_pub *sih);
+
+extern int srom_read(struct si_pub *sih, uint bus, void *curmap,
+ uint byteoff, uint nbytes, u16 *buf, bool check_crc);
+
+/* parse standard PCMCIA cis, normally used by SB/PCMCIA/SDIO/SPI/OTP
+ * and extract from it into name=value pairs
+ */
+extern int srom_parsecis(u8 **pcis, uint ciscnt,
+ char **vars, uint *count);
+#endif /* _BRCM_SROM_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/stf.c b/drivers/net/wireless/brcm80211/brcmsmac/stf.c
new file mode 100644
index 000000000000..d8f528eb180c
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/stf.c
@@ -0,0 +1,436 @@
+/*
+ * Copyright (c) 2010 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 <net/mac80211.h>
+
+#include "types.h"
+#include "d11.h"
+#include "rate.h"
+#include "phy/phy_hal.h"
+#include "channel.h"
+#include "main.h"
+#include "stf.h"
+
+#define MIN_SPATIAL_EXPANSION 0
+#define MAX_SPATIAL_EXPANSION 1
+
+#define BRCMS_STF_SS_STBC_RX(wlc) (BRCMS_ISNPHY(wlc->band) && \
+ NREV_GT(wlc->band->phyrev, 3) && NREV_LE(wlc->band->phyrev, 6))
+
+#define NSTS_1 1
+#define NSTS_2 2
+#define NSTS_3 3
+#define NSTS_4 4
+
+static const u8 txcore_default[5] = {
+ (0), /* bitmap of the core enabled */
+ (0x01), /* For Nsts = 1, enable core 1 */
+ (0x03), /* For Nsts = 2, enable core 1 & 2 */
+ (0x07), /* For Nsts = 3, enable core 1, 2 & 3 */
+ (0x0f) /* For Nsts = 4, enable all cores */
+};
+
+static void brcms_c_stf_stbc_rx_ht_update(struct brcms_c_info *wlc, int val)
+{
+ /* MIMOPHYs rev3-6 cannot receive STBC with only one rx core active */
+ if (BRCMS_STF_SS_STBC_RX(wlc)) {
+ if ((wlc->stf->rxstreams == 1) && (val != HT_CAP_RX_STBC_NO))
+ return;
+ }
+
+ if (wlc->pub->up) {
+ brcms_c_update_beacon(wlc);
+ brcms_c_update_probe_resp(wlc, true);
+ }
+}
+
+/*
+ * every WLC_TEMPSENSE_PERIOD seconds temperature check to decide whether to
+ * turn on/off txchain.
+ */
+void brcms_c_tempsense_upd(struct brcms_c_info *wlc)
+{
+ struct brcms_phy_pub *pi = wlc->band->pi;
+ uint active_chains, txchain;
+
+ /* Check if the chip is too hot. Disable one Tx chain, if it is */
+ /* high 4 bits are for Rx chain, low 4 bits are for Tx chain */
+ active_chains = wlc_phy_stf_chain_active_get(pi);
+ txchain = active_chains & 0xf;
+
+ if (wlc->stf->txchain == wlc->stf->hw_txchain) {
+ if (txchain && (txchain < wlc->stf->hw_txchain))
+ /* turn off 1 tx chain */
+ brcms_c_stf_txchain_set(wlc, txchain, true);
+ } else if (wlc->stf->txchain < wlc->stf->hw_txchain) {
+ if (txchain == wlc->stf->hw_txchain)
+ /* turn back on txchain */
+ brcms_c_stf_txchain_set(wlc, txchain, true);
+ }
+}
+
+void
+brcms_c_stf_ss_algo_channel_get(struct brcms_c_info *wlc, u16 *ss_algo_channel,
+ u16 chanspec)
+{
+ struct tx_power power;
+ u8 siso_mcs_id, cdd_mcs_id, stbc_mcs_id;
+
+ /* Clear previous settings */
+ *ss_algo_channel = 0;
+
+ if (!wlc->pub->up) {
+ *ss_algo_channel = (u16) -1;
+ return;
+ }
+
+ wlc_phy_txpower_get_current(wlc->band->pi, &power,
+ CHSPEC_CHANNEL(chanspec));
+
+ siso_mcs_id = (CHSPEC_IS40(chanspec)) ?
+ WL_TX_POWER_MCS40_SISO_FIRST : WL_TX_POWER_MCS20_SISO_FIRST;
+ cdd_mcs_id = (CHSPEC_IS40(chanspec)) ?
+ WL_TX_POWER_MCS40_CDD_FIRST : WL_TX_POWER_MCS20_CDD_FIRST;
+ stbc_mcs_id = (CHSPEC_IS40(chanspec)) ?
+ WL_TX_POWER_MCS40_STBC_FIRST : WL_TX_POWER_MCS20_STBC_FIRST;
+
+ /* criteria to choose stf mode */
+
+ /*
+ * the "+3dbm (12 0.25db units)" is to account for the fact that with
+ * CDD, tx occurs on both chains
+ */
+ if (power.target[siso_mcs_id] > (power.target[cdd_mcs_id] + 12))
+ setbit(ss_algo_channel, PHY_TXC1_MODE_SISO);
+ else
+ setbit(ss_algo_channel, PHY_TXC1_MODE_CDD);
+
+ /*
+ * STBC is ORed into to algo channel as STBC requires per-packet SCB
+ * capability check so cannot be default mode of operation. One of
+ * SISO, CDD have to be set
+ */
+ if (power.target[siso_mcs_id] <= (power.target[stbc_mcs_id] + 12))
+ setbit(ss_algo_channel, PHY_TXC1_MODE_STBC);
+}
+
+static bool brcms_c_stf_stbc_tx_set(struct brcms_c_info *wlc, s32 int_val)
+{
+ if ((int_val != AUTO) && (int_val != OFF) && (int_val != ON))
+ return false;
+
+ if ((int_val == ON) && (wlc->stf->txstreams == 1))
+ return false;
+
+ wlc->bandstate[BAND_2G_INDEX]->band_stf_stbc_tx = (s8) int_val;
+ wlc->bandstate[BAND_5G_INDEX]->band_stf_stbc_tx = (s8) int_val;
+
+ return true;
+}
+
+bool brcms_c_stf_stbc_rx_set(struct brcms_c_info *wlc, s32 int_val)
+{
+ if ((int_val != HT_CAP_RX_STBC_NO)
+ && (int_val != HT_CAP_RX_STBC_ONE_STREAM))
+ return false;
+
+ if (BRCMS_STF_SS_STBC_RX(wlc)) {
+ if ((int_val != HT_CAP_RX_STBC_NO)
+ && (wlc->stf->rxstreams == 1))
+ return false;
+ }
+
+ brcms_c_stf_stbc_rx_ht_update(wlc, int_val);
+ return true;
+}
+
+static int brcms_c_stf_txcore_set(struct brcms_c_info *wlc, u8 Nsts,
+ u8 core_mask)
+{
+ BCMMSG(wlc->wiphy, "wl%d: Nsts %d core_mask %x\n",
+ wlc->pub->unit, Nsts, core_mask);
+
+ if (hweight8(core_mask) > wlc->stf->txstreams)
+ core_mask = 0;
+
+ if ((hweight8(core_mask) == wlc->stf->txstreams) &&
+ ((core_mask & ~wlc->stf->txchain)
+ || !(core_mask & wlc->stf->txchain)))
+ core_mask = wlc->stf->txchain;
+
+ wlc->stf->txcore[Nsts] = core_mask;
+ /* Nsts = 1..4, txcore index = 1..4 */
+ if (Nsts == 1) {
+ /* Needs to update beacon and ucode generated response
+ * frames when 1 stream core map changed
+ */
+ wlc->stf->phytxant = core_mask << PHY_TXC_ANT_SHIFT;
+ brcms_b_txant_set(wlc->hw, wlc->stf->phytxant);
+ if (wlc->clk) {
+ brcms_c_suspend_mac_and_wait(wlc);
+ brcms_c_beacon_phytxctl_txant_upd(wlc, wlc->bcn_rspec);
+ brcms_c_enable_mac(wlc);
+ }
+ }
+
+ return 0;
+}
+
+static int brcms_c_stf_spatial_policy_set(struct brcms_c_info *wlc, int val)
+{
+ int i;
+ u8 core_mask = 0;
+
+ BCMMSG(wlc->wiphy, "wl%d: val %x\n", wlc->pub->unit, val);
+
+ wlc->stf->spatial_policy = (s8) val;
+ for (i = 1; i <= MAX_STREAMS_SUPPORTED; i++) {
+ core_mask = (val == MAX_SPATIAL_EXPANSION) ?
+ wlc->stf->txchain : txcore_default[i];
+ brcms_c_stf_txcore_set(wlc, (u8) i, core_mask);
+ }
+ return 0;
+}
+
+/*
+ * Centralized txant update function. call it whenever wlc->stf->txant and/or
+ * wlc->stf->txchain change.
+ *
+ * Antennas are controlled by ucode indirectly, which drives PHY or GPIO to
+ * achieve various tx/rx antenna selection schemes
+ *
+ * legacy phy, bit 6 and bit 7 means antenna 0 and 1 respectively, bit6+bit7
+ * means auto(last rx).
+ * for NREV<3, bit 6 and bit 7 means antenna 0 and 1 respectively, bit6+bit7
+ * means last rx and do tx-antenna selection for SISO transmissions
+ * for NREV=3, bit 6 and bit _8_ means antenna 0 and 1 respectively, bit6+bit7
+ * means last rx and do tx-antenna selection for SISO transmissions
+ * for NREV>=7, bit 6 and bit 7 mean antenna 0 and 1 respectively, nit6+bit7
+ * means both cores active
+*/
+static void _brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc)
+{
+ s8 txant;
+
+ txant = (s8) wlc->stf->txant;
+ if (BRCMS_PHY_11N_CAP(wlc->band)) {
+ if (txant == ANT_TX_FORCE_0) {
+ wlc->stf->phytxant = PHY_TXC_ANT_0;
+ } else if (txant == ANT_TX_FORCE_1) {
+ wlc->stf->phytxant = PHY_TXC_ANT_1;
+
+ if (BRCMS_ISNPHY(wlc->band) &&
+ NREV_GE(wlc->band->phyrev, 3)
+ && NREV_LT(wlc->band->phyrev, 7))
+ wlc->stf->phytxant = PHY_TXC_ANT_2;
+ } else {
+ if (BRCMS_ISLCNPHY(wlc->band) ||
+ BRCMS_ISSSLPNPHY(wlc->band))
+ wlc->stf->phytxant = PHY_TXC_LCNPHY_ANT_LAST;
+ else {
+ /* catch out of sync wlc->stf->txcore */
+ WARN_ON(wlc->stf->txchain <= 0);
+ wlc->stf->phytxant =
+ wlc->stf->txchain << PHY_TXC_ANT_SHIFT;
+ }
+ }
+ } else {
+ if (txant == ANT_TX_FORCE_0)
+ wlc->stf->phytxant = PHY_TXC_OLD_ANT_0;
+ else if (txant == ANT_TX_FORCE_1)
+ wlc->stf->phytxant = PHY_TXC_OLD_ANT_1;
+ else
+ wlc->stf->phytxant = PHY_TXC_OLD_ANT_LAST;
+ }
+
+ brcms_b_txant_set(wlc->hw, wlc->stf->phytxant);
+}
+
+int brcms_c_stf_txchain_set(struct brcms_c_info *wlc, s32 int_val, bool force)
+{
+ u8 txchain = (u8) int_val;
+ u8 txstreams;
+ uint i;
+
+ if (wlc->stf->txchain == txchain)
+ return 0;
+
+ if ((txchain & ~wlc->stf->hw_txchain)
+ || !(txchain & wlc->stf->hw_txchain))
+ return -EINVAL;
+
+ /*
+ * if nrate override is configured to be non-SISO STF mode, reject
+ * reducing txchain to 1
+ */
+ txstreams = (u8) hweight8(txchain);
+ if (txstreams > MAX_STREAMS_SUPPORTED)
+ return -EINVAL;
+
+ wlc->stf->txchain = txchain;
+ wlc->stf->txstreams = txstreams;
+ brcms_c_stf_stbc_tx_set(wlc, wlc->band->band_stf_stbc_tx);
+ brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]);
+ brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]);
+ wlc->stf->txant =
+ (wlc->stf->txstreams == 1) ? ANT_TX_FORCE_0 : ANT_TX_DEF;
+ _brcms_c_stf_phy_txant_upd(wlc);
+
+ wlc_phy_stf_chain_set(wlc->band->pi, wlc->stf->txchain,
+ wlc->stf->rxchain);
+
+ for (i = 1; i <= MAX_STREAMS_SUPPORTED; i++)
+ brcms_c_stf_txcore_set(wlc, (u8) i, txcore_default[i]);
+
+ return 0;
+}
+
+/*
+ * update wlc->stf->ss_opmode which represents the operational stf_ss mode
+ * we're using
+ */
+int brcms_c_stf_ss_update(struct brcms_c_info *wlc, struct brcms_band *band)
+{
+ int ret_code = 0;
+ u8 prev_stf_ss;
+ u8 upd_stf_ss;
+
+ prev_stf_ss = wlc->stf->ss_opmode;
+
+ /*
+ * NOTE: opmode can only be SISO or CDD as STBC is decided on a
+ * per-packet basis
+ */
+ if (BRCMS_STBC_CAP_PHY(wlc) &&
+ wlc->stf->ss_algosel_auto
+ && (wlc->stf->ss_algo_channel != (u16) -1)) {
+ upd_stf_ss = (wlc->stf->txstreams == 1 ||
+ isset(&wlc->stf->ss_algo_channel,
+ PHY_TXC1_MODE_SISO)) ?
+ PHY_TXC1_MODE_SISO : PHY_TXC1_MODE_CDD;
+ } else {
+ if (wlc->band != band)
+ return ret_code;
+ upd_stf_ss = (wlc->stf->txstreams == 1) ?
+ PHY_TXC1_MODE_SISO : band->band_stf_ss_mode;
+ }
+ if (prev_stf_ss != upd_stf_ss) {
+ wlc->stf->ss_opmode = upd_stf_ss;
+ brcms_b_band_stf_ss_set(wlc->hw, upd_stf_ss);
+ }
+
+ return ret_code;
+}
+
+int brcms_c_stf_attach(struct brcms_c_info *wlc)
+{
+ wlc->bandstate[BAND_2G_INDEX]->band_stf_ss_mode = PHY_TXC1_MODE_SISO;
+ wlc->bandstate[BAND_5G_INDEX]->band_stf_ss_mode = PHY_TXC1_MODE_CDD;
+
+ if (BRCMS_ISNPHY(wlc->band) &&
+ (wlc_phy_txpower_hw_ctrl_get(wlc->band->pi) != PHY_TPC_HW_ON))
+ wlc->bandstate[BAND_2G_INDEX]->band_stf_ss_mode =
+ PHY_TXC1_MODE_CDD;
+ brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]);
+ brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]);
+
+ brcms_c_stf_stbc_rx_ht_update(wlc, HT_CAP_RX_STBC_NO);
+ wlc->bandstate[BAND_2G_INDEX]->band_stf_stbc_tx = OFF;
+ wlc->bandstate[BAND_5G_INDEX]->band_stf_stbc_tx = OFF;
+
+ if (BRCMS_STBC_CAP_PHY(wlc)) {
+ wlc->stf->ss_algosel_auto = true;
+ /* Init the default value */
+ wlc->stf->ss_algo_channel = (u16) -1;
+ }
+ return 0;
+}
+
+void brcms_c_stf_detach(struct brcms_c_info *wlc)
+{
+}
+
+void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc)
+{
+ _brcms_c_stf_phy_txant_upd(wlc);
+}
+
+void brcms_c_stf_phy_chain_calc(struct brcms_c_info *wlc)
+{
+ /* get available rx/tx chains */
+ wlc->stf->hw_txchain = (u8) getintvar(wlc->hw->sih, BRCMS_SROM_TXCHAIN);
+ wlc->stf->hw_rxchain = (u8) getintvar(wlc->hw->sih, BRCMS_SROM_RXCHAIN);
+
+ /* these parameter are intended to be used for all PHY types */
+ if (wlc->stf->hw_txchain == 0 || wlc->stf->hw_txchain == 0xf) {
+ if (BRCMS_ISNPHY(wlc->band))
+ wlc->stf->hw_txchain = TXCHAIN_DEF_NPHY;
+ else
+ wlc->stf->hw_txchain = TXCHAIN_DEF;
+ }
+
+ wlc->stf->txchain = wlc->stf->hw_txchain;
+ wlc->stf->txstreams = (u8) hweight8(wlc->stf->hw_txchain);
+
+ if (wlc->stf->hw_rxchain == 0 || wlc->stf->hw_rxchain == 0xf) {
+ if (BRCMS_ISNPHY(wlc->band))
+ wlc->stf->hw_rxchain = RXCHAIN_DEF_NPHY;
+ else
+ wlc->stf->hw_rxchain = RXCHAIN_DEF;
+ }
+
+ wlc->stf->rxchain = wlc->stf->hw_rxchain;
+ wlc->stf->rxstreams = (u8) hweight8(wlc->stf->hw_rxchain);
+
+ /* initialize the txcore table */
+ memcpy(wlc->stf->txcore, txcore_default, sizeof(wlc->stf->txcore));
+
+ /* default spatial_policy */
+ wlc->stf->spatial_policy = MIN_SPATIAL_EXPANSION;
+ brcms_c_stf_spatial_policy_set(wlc, MIN_SPATIAL_EXPANSION);
+}
+
+static u16 _brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc,
+ u32 rspec)
+{
+ u16 phytxant = wlc->stf->phytxant;
+
+ if (rspec_stf(rspec) != PHY_TXC1_MODE_SISO)
+ phytxant = wlc->stf->txchain << PHY_TXC_ANT_SHIFT;
+ else if (wlc->stf->txant == ANT_TX_DEF)
+ phytxant = wlc->stf->txchain << PHY_TXC_ANT_SHIFT;
+ phytxant &= PHY_TXC_ANT_MASK;
+ return phytxant;
+}
+
+u16 brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc, u32 rspec)
+{
+ return _brcms_c_stf_phytxchain_sel(wlc, rspec);
+}
+
+u16 brcms_c_stf_d11hdrs_phyctl_txant(struct brcms_c_info *wlc, u32 rspec)
+{
+ u16 phytxant = wlc->stf->phytxant;
+ u16 mask = PHY_TXC_ANT_MASK;
+
+ /* for non-siso rates or default setting, use the available chains */
+ if (BRCMS_ISNPHY(wlc->band)) {
+ phytxant = _brcms_c_stf_phytxchain_sel(wlc, rspec);
+ mask = PHY_TXC_HTANT_MASK;
+ }
+ phytxant |= phytxant & mask;
+ return phytxant;
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/stf.h b/drivers/net/wireless/brcm80211/brcmsmac/stf.h
new file mode 100644
index 000000000000..19f6580f69be
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/stf.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_STF_H_
+#define _BRCM_STF_H_
+
+#include "types.h"
+
+extern int brcms_c_stf_attach(struct brcms_c_info *wlc);
+extern void brcms_c_stf_detach(struct brcms_c_info *wlc);
+
+extern void brcms_c_tempsense_upd(struct brcms_c_info *wlc);
+extern void brcms_c_stf_ss_algo_channel_get(struct brcms_c_info *wlc,
+ u16 *ss_algo_channel,
+ u16 chanspec);
+extern int brcms_c_stf_ss_update(struct brcms_c_info *wlc,
+ struct brcms_band *band);
+extern void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc);
+extern int brcms_c_stf_txchain_set(struct brcms_c_info *wlc, s32 int_val,
+ bool force);
+extern bool brcms_c_stf_stbc_rx_set(struct brcms_c_info *wlc, s32 int_val);
+extern void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc);
+extern void brcms_c_stf_phy_chain_calc(struct brcms_c_info *wlc);
+extern u16 brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc,
+ u32 rspec);
+extern u16 brcms_c_stf_d11hdrs_phyctl_txant(struct brcms_c_info *wlc,
+ u32 rspec);
+
+#endif /* _BRCM_STF_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/types.h b/drivers/net/wireless/brcm80211/brcmsmac/types.h
new file mode 100644
index 000000000000..27a814b07462
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/types.h
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_TYPES_H_
+#define _BRCM_TYPES_H_
+
+#include <linux/types.h>
+#include <linux/io.h>
+
+#define WL_CHAN_FREQ_RANGE_2G 0
+#define WL_CHAN_FREQ_RANGE_5GL 1
+#define WL_CHAN_FREQ_RANGE_5GM 2
+#define WL_CHAN_FREQ_RANGE_5GH 3
+
+/* boardflags */
+
+/* Board has gpio 9 controlling the PA */
+#define BFL_PACTRL 0x00000002
+/* Not ok to power down the chip pll and oscillator */
+#define BFL_NOPLLDOWN 0x00000020
+/* Board supports the Front End Module */
+#define BFL_FEM 0x00000800
+/* Board has an external LNA in 2.4GHz band */
+#define BFL_EXTLNA 0x00001000
+/* Board has no PA */
+#define BFL_NOPA 0x00010000
+/* Power topology uses BUCKBOOST */
+#define BFL_BUCKBOOST 0x00200000
+/* Board has FEM and switch to share antenna w/ BT */
+#define BFL_FEM_BT 0x00400000
+/* Power topology doesn't use CBUCK */
+#define BFL_NOCBUCK 0x00800000
+/* Power topology uses PALDO */
+#define BFL_PALDO 0x02000000
+/* Board has an external LNA in 5GHz band */
+#define BFL_EXTLNA_5GHz 0x10000000
+
+/* boardflags2 */
+
+/* Board has an external rxbb regulator */
+#define BFL2_RXBB_INT_REG_DIS 0x00000001
+/* Flag to implement alternative A-band PLL settings */
+#define BFL2_APLL_WAR 0x00000002
+/* Board permits enabling TX Power Control */
+#define BFL2_TXPWRCTRL_EN 0x00000004
+/* Board supports the 2X4 diversity switch */
+#define BFL2_2X4_DIV 0x00000008
+/* Board supports 5G band power gain */
+#define BFL2_5G_PWRGAIN 0x00000010
+/* Board overrides ASPM and Clkreq settings */
+#define BFL2_PCIEWAR_OVR 0x00000020
+#define BFL2_LEGACY 0x00000080
+/* 4321mcm93 board uses Skyworks FEM */
+#define BFL2_SKWRKFEM_BRD 0x00000100
+/* Board has a WAR for clock-harmonic spurs */
+#define BFL2_SPUR_WAR 0x00000200
+/* Flag to narrow G-band PLL loop b/w */
+#define BFL2_GPLL_WAR 0x00000400
+/* Tx CCK pkts on Ant 0 only */
+#define BFL2_SINGLEANT_CCK 0x00001000
+/* WAR to reduce and avoid clock-harmonic spurs in 2G */
+#define BFL2_2G_SPUR_WAR 0x00002000
+/* Flag to widen G-band PLL loop b/w */
+#define BFL2_GPLL_WAR2 0x00010000
+#define BFL2_IPALVLSHIFT_3P3 0x00020000
+/* Use internal envelope detector for TX IQCAL */
+#define BFL2_INTERNDET_TXIQCAL 0x00040000
+/* Keep the buffered Xtal output from radio "ON". Most drivers will turn it
+ * off without this flag to save power. */
+#define BFL2_XTALBUFOUTEN 0x00080000
+
+/*
+ * board specific GPIO assignment, gpio 0-3 are also customer-configurable
+ * led
+ */
+
+/* bit 9 controls the PA on new 4306 boards */
+#define BOARD_GPIO_PACTRL 0x200
+#define BOARD_GPIO_12 0x1000
+#define BOARD_GPIO_13 0x2000
+
+/* **** Core type/rev defaults **** */
+#define D11CONF 0x0fffffb0 /* Supported D11 revs: 4, 5, 7-27
+ * also need to update wlc.h MAXCOREREV
+ */
+
+#define NCONF 0x000001ff /* Supported nphy revs:
+ * 0 4321a0
+ * 1 4321a1
+ * 2 4321b0/b1/c0/c1
+ * 3 4322a0
+ * 4 4322a1
+ * 5 4716a0
+ * 6 43222a0, 43224a0
+ * 7 43226a0
+ * 8 5357a0, 43236a0
+ */
+
+#define LCNCONF 0x00000007 /* Supported lcnphy revs:
+ * 0 4313a0, 4336a0, 4330a0
+ * 1
+ * 2 4330a0
+ */
+
+#define SSLPNCONF 0x0000000f /* Supported sslpnphy revs:
+ * 0 4329a0/k0
+ * 1 4329b0/4329C0
+ * 2 4319a0
+ * 3 5356a0
+ */
+
+/********************************************************************
+ * Phy/Core Configuration. Defines macros to to check core phy/rev *
+ * compile-time configuration. Defines default core support. *
+ * ******************************************************************
+ */
+
+/* Basic macros to check a configuration bitmask */
+
+#define CONF_HAS(config, val) ((config) & (1 << (val)))
+#define CONF_MSK(config, mask) ((config) & (mask))
+#define MSK_RANGE(low, hi) ((1 << ((hi)+1)) - (1 << (low)))
+#define CONF_RANGE(config, low, hi) (CONF_MSK(config, MSK_RANGE(low, high)))
+
+#define CONF_IS(config, val) ((config) == (1 << (val)))
+#define CONF_GE(config, val) ((config) & (0-(1 << (val))))
+#define CONF_GT(config, val) ((config) & (0-2*(1 << (val))))
+#define CONF_LT(config, val) ((config) & ((1 << (val))-1))
+#define CONF_LE(config, val) ((config) & (2*(1 << (val))-1))
+
+/* Wrappers for some of the above, specific to config constants */
+
+#define NCONF_HAS(val) CONF_HAS(NCONF, val)
+#define NCONF_MSK(mask) CONF_MSK(NCONF, mask)
+#define NCONF_IS(val) CONF_IS(NCONF, val)
+#define NCONF_GE(val) CONF_GE(NCONF, val)
+#define NCONF_GT(val) CONF_GT(NCONF, val)
+#define NCONF_LT(val) CONF_LT(NCONF, val)
+#define NCONF_LE(val) CONF_LE(NCONF, val)
+
+#define LCNCONF_HAS(val) CONF_HAS(LCNCONF, val)
+#define LCNCONF_MSK(mask) CONF_MSK(LCNCONF, mask)
+#define LCNCONF_IS(val) CONF_IS(LCNCONF, val)
+#define LCNCONF_GE(val) CONF_GE(LCNCONF, val)
+#define LCNCONF_GT(val) CONF_GT(LCNCONF, val)
+#define LCNCONF_LT(val) CONF_LT(LCNCONF, val)
+#define LCNCONF_LE(val) CONF_LE(LCNCONF, val)
+
+#define D11CONF_HAS(val) CONF_HAS(D11CONF, val)
+#define D11CONF_MSK(mask) CONF_MSK(D11CONF, mask)
+#define D11CONF_IS(val) CONF_IS(D11CONF, val)
+#define D11CONF_GE(val) CONF_GE(D11CONF, val)
+#define D11CONF_GT(val) CONF_GT(D11CONF, val)
+#define D11CONF_LT(val) CONF_LT(D11CONF, val)
+#define D11CONF_LE(val) CONF_LE(D11CONF, val)
+
+#define PHYCONF_HAS(val) CONF_HAS(PHYTYPE, val)
+#define PHYCONF_IS(val) CONF_IS(PHYTYPE, val)
+
+#define NREV_IS(var, val) \
+ (NCONF_HAS(val) && (NCONF_IS(val) || ((var) == (val))))
+
+#define NREV_GE(var, val) \
+ (NCONF_GE(val) && (!NCONF_LT(val) || ((var) >= (val))))
+
+#define NREV_GT(var, val) \
+ (NCONF_GT(val) && (!NCONF_LE(val) || ((var) > (val))))
+
+#define NREV_LT(var, val) \
+ (NCONF_LT(val) && (!NCONF_GE(val) || ((var) < (val))))
+
+#define NREV_LE(var, val) \
+ (NCONF_LE(val) && (!NCONF_GT(val) || ((var) <= (val))))
+
+#define LCNREV_IS(var, val) \
+ (LCNCONF_HAS(val) && (LCNCONF_IS(val) || ((var) == (val))))
+
+#define LCNREV_GE(var, val) \
+ (LCNCONF_GE(val) && (!LCNCONF_LT(val) || ((var) >= (val))))
+
+#define LCNREV_GT(var, val) \
+ (LCNCONF_GT(val) && (!LCNCONF_LE(val) || ((var) > (val))))
+
+#define LCNREV_LT(var, val) \
+ (LCNCONF_LT(val) && (!LCNCONF_GE(val) || ((var) < (val))))
+
+#define LCNREV_LE(var, val) \
+ (LCNCONF_LE(val) && (!LCNCONF_GT(val) || ((var) <= (val))))
+
+#define D11REV_IS(var, val) \
+ (D11CONF_HAS(val) && (D11CONF_IS(val) || ((var) == (val))))
+
+#define D11REV_GE(var, val) \
+ (D11CONF_GE(val) && (!D11CONF_LT(val) || ((var) >= (val))))
+
+#define D11REV_GT(var, val) \
+ (D11CONF_GT(val) && (!D11CONF_LE(val) || ((var) > (val))))
+
+#define D11REV_LT(var, val) \
+ (D11CONF_LT(val) && (!D11CONF_GE(val) || ((var) < (val))))
+
+#define D11REV_LE(var, val) \
+ (D11CONF_LE(val) && (!D11CONF_GT(val) || ((var) <= (val))))
+
+#define PHYTYPE_IS(var, val)\
+ (PHYCONF_HAS(val) && (PHYCONF_IS(val) || ((var) == (val))))
+
+/* Set up PHYTYPE automatically: (depends on PHY_TYPE_X, from d11.h) */
+
+#define _PHYCONF_N (1 << PHY_TYPE_N)
+#define _PHYCONF_LCN (1 << PHY_TYPE_LCN)
+#define _PHYCONF_SSLPN (1 << PHY_TYPE_SSN)
+
+#define PHYTYPE (_PHYCONF_N | _PHYCONF_LCN | _PHYCONF_SSLPN)
+
+/* Utility macro to identify 802.11n (HT) capable PHYs */
+#define PHYTYPE_11N_CAP(phytype) \
+ (PHYTYPE_IS(phytype, PHY_TYPE_N) || \
+ PHYTYPE_IS(phytype, PHY_TYPE_LCN) || \
+ PHYTYPE_IS(phytype, PHY_TYPE_SSN))
+
+/* Last but not least: shorter wlc-specific var checks */
+#define BRCMS_ISNPHY(band) PHYTYPE_IS((band)->phytype, PHY_TYPE_N)
+#define BRCMS_ISLCNPHY(band) PHYTYPE_IS((band)->phytype, PHY_TYPE_LCN)
+#define BRCMS_ISSSLPNPHY(band) PHYTYPE_IS((band)->phytype, PHY_TYPE_SSN)
+
+#define BRCMS_PHY_11N_CAP(band) PHYTYPE_11N_CAP((band)->phytype)
+
+/**********************************************************************
+ * ------------- End of Core phy/rev configuration. ----------------- *
+ * ********************************************************************
+ */
+
+#define BCMMSG(dev, fmt, args...) \
+do { \
+ if (brcm_msg_level & LOG_TRACE_VAL) \
+ wiphy_err(dev, "%s: " fmt, __func__, ##args); \
+} while (0)
+
+/*
+ * Register access macros.
+ *
+ * These macro's take a pointer to the address to read as one of their
+ * arguments. The macro itself deduces the size of the IO transaction (u8, u16
+ * or u32). Advantage of this approach in combination with using a struct to
+ * define the registers in a register block, is that access size and access
+ * location are defined in only one spot. This reduces the risk of the
+ * programmer trying to use an unsupported transaction size on a register.
+ *
+ */
+
+#define R_REG(r) \
+ ({ \
+ __typeof(*(r)) __osl_v; \
+ switch (sizeof(*(r))) { \
+ case sizeof(u8): \
+ __osl_v = readb((u8 __iomem *)(r)); \
+ break; \
+ case sizeof(u16): \
+ __osl_v = readw((u16 __iomem *)(r)); \
+ break; \
+ case sizeof(u32): \
+ __osl_v = readl((u32 __iomem *)(r)); \
+ break; \
+ } \
+ __osl_v; \
+ })
+
+#define W_REG(r, v) do { \
+ switch (sizeof(*(r))) { \
+ case sizeof(u8): \
+ writeb((u8)((v) & 0xFF), (u8 __iomem *)(r)); \
+ break; \
+ case sizeof(u16): \
+ writew((u16)((v) & 0xFFFF), (u16 __iomem *)(r)); \
+ break; \
+ case sizeof(u32): \
+ writel((u32)(v), (u32 __iomem *)(r)); \
+ break; \
+ } \
+ } while (0)
+
+#ifdef CONFIG_BCM47XX
+/*
+ * bcm4716 (which includes 4717 & 4718), plus 4706 on PCIe can reorder
+ * transactions. As a fix, a read after write is performed on certain places
+ * in the code. Older chips and the newer 5357 family don't require this fix.
+ */
+#define W_REG_FLUSH(r, v) ({ W_REG((r), (v)); (void)R_REG(r); })
+#else
+#define W_REG_FLUSH(r, v) W_REG((r), (v))
+#endif /* CONFIG_BCM47XX */
+
+#define AND_REG(r, v) W_REG((r), R_REG(r) & (v))
+#define OR_REG(r, v) W_REG((r), R_REG(r) | (v))
+
+#define SET_REG(r, mask, val) \
+ W_REG((r), ((R_REG(r) & ~(mask)) | (val)))
+
+/* multi-bool data type: set of bools, mbool is true if any is set */
+
+/* set one bool */
+#define mboolset(mb, bit) ((mb) |= (bit))
+/* clear one bool */
+#define mboolclr(mb, bit) ((mb) &= ~(bit))
+/* true if one bool is set */
+#define mboolisset(mb, bit) (((mb) & (bit)) != 0)
+#define mboolmaskset(mb, mask, val) ((mb) = (((mb) & ~(mask)) | (val)))
+
+#define CEIL(x, y) (((x) + ((y)-1)) / (y))
+
+/* forward declarations */
+struct wiphy;
+struct ieee80211_sta;
+struct ieee80211_tx_queue_params;
+struct brcms_info;
+struct brcms_c_info;
+struct brcms_hardware;
+struct brcms_txq_info;
+struct brcms_band;
+struct dma_pub;
+struct si_pub;
+struct tx_status;
+struct d11rxhdr;
+struct txpwr_limits;
+
+/* iovar structure */
+struct brcmu_iovar {
+ const char *name; /* name for lookup and display */
+ u16 varid; /* id for switch */
+ u16 flags; /* driver-specific flag bits */
+ u16 type; /* base type of argument */
+ u16 minlen; /* min length for buffer vars */
+};
+
+/* brcm_msg_level is a bit vector with defs in defs.h */
+extern u32 brcm_msg_level;
+
+#endif /* _BRCM_TYPES_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.c b/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.c
new file mode 100644
index 000000000000..80e3ccf865e3
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2010 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 <defs.h>
+#include "types.h"
+#include <ucode_loader.h>
+
+enum {
+ D11UCODE_NAMETAG_START = 0,
+ D11LCN0BSINITVALS24,
+ D11LCN0INITVALS24,
+ D11LCN1BSINITVALS24,
+ D11LCN1INITVALS24,
+ D11LCN2BSINITVALS24,
+ D11LCN2INITVALS24,
+ D11N0ABSINITVALS16,
+ D11N0BSINITVALS16,
+ D11N0INITVALS16,
+ D11UCODE_OVERSIGHT16_MIMO,
+ D11UCODE_OVERSIGHT16_MIMOSZ,
+ D11UCODE_OVERSIGHT24_LCN,
+ D11UCODE_OVERSIGHT24_LCNSZ,
+ D11UCODE_OVERSIGHT_BOMMAJOR,
+ D11UCODE_OVERSIGHT_BOMMINOR
+};
+
+int brcms_ucode_data_init(struct brcms_info *wl, struct brcms_ucode *ucode)
+{
+ int rc;
+
+ rc = brcms_check_firmwares(wl);
+
+ rc = rc < 0 ? rc :
+ brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn0bsinitvals24,
+ D11LCN0BSINITVALS24);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn0initvals24,
+ D11LCN0INITVALS24);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn1bsinitvals24,
+ D11LCN1BSINITVALS24);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn1initvals24,
+ D11LCN1INITVALS24);
+ rc = rc < 0 ? rc :
+ brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn2bsinitvals24,
+ D11LCN2BSINITVALS24);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn2initvals24,
+ D11LCN2INITVALS24);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11n0absinitvals16,
+ D11N0ABSINITVALS16);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11n0bsinitvals16,
+ D11N0BSINITVALS16);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11n0initvals16,
+ D11N0INITVALS16);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_buf(wl, (void **)&ucode->bcm43xx_16_mimo,
+ D11UCODE_OVERSIGHT16_MIMO);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_uint(wl, &ucode->bcm43xx_16_mimosz,
+ D11UCODE_OVERSIGHT16_MIMOSZ);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_buf(wl, (void **)&ucode->bcm43xx_24_lcn,
+ D11UCODE_OVERSIGHT24_LCN);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_uint(wl, &ucode->bcm43xx_24_lcnsz,
+ D11UCODE_OVERSIGHT24_LCNSZ);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_buf(wl, (void **)&ucode->bcm43xx_bommajor,
+ D11UCODE_OVERSIGHT_BOMMAJOR);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_buf(wl, (void **)&ucode->bcm43xx_bomminor,
+ D11UCODE_OVERSIGHT_BOMMINOR);
+ return rc;
+}
+
+void brcms_ucode_data_free(struct brcms_ucode *ucode)
+{
+ brcms_ucode_free_buf((void *)ucode->d11lcn0bsinitvals24);
+ brcms_ucode_free_buf((void *)ucode->d11lcn0initvals24);
+ brcms_ucode_free_buf((void *)ucode->d11lcn1bsinitvals24);
+ brcms_ucode_free_buf((void *)ucode->d11lcn1initvals24);
+ brcms_ucode_free_buf((void *)ucode->d11lcn2bsinitvals24);
+ brcms_ucode_free_buf((void *)ucode->d11lcn2initvals24);
+ brcms_ucode_free_buf((void *)ucode->d11n0absinitvals16);
+ brcms_ucode_free_buf((void *)ucode->d11n0bsinitvals16);
+ brcms_ucode_free_buf((void *)ucode->d11n0initvals16);
+ brcms_ucode_free_buf((void *)ucode->bcm43xx_16_mimo);
+ brcms_ucode_free_buf((void *)ucode->bcm43xx_24_lcn);
+ brcms_ucode_free_buf((void *)ucode->bcm43xx_bommajor);
+ brcms_ucode_free_buf((void *)ucode->bcm43xx_bomminor);
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.h b/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.h
new file mode 100644
index 000000000000..18750a814b4f
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_UCODE_H_
+#define _BRCM_UCODE_H_
+
+#include "types.h" /* forward structure declarations */
+
+#define MIN_FW_SIZE 40000 /* minimum firmware file size in bytes */
+#define MAX_FW_SIZE 150000
+
+#define UCODE_LOADER_API_VER 0
+
+struct d11init;
+
+struct brcms_ucode {
+ struct d11init *d11lcn0bsinitvals24;
+ struct d11init *d11lcn0initvals24;
+ struct d11init *d11lcn1bsinitvals24;
+ struct d11init *d11lcn1initvals24;
+ struct d11init *d11lcn2bsinitvals24;
+ struct d11init *d11lcn2initvals24;
+ struct d11init *d11n0absinitvals16;
+ struct d11init *d11n0bsinitvals16;
+ struct d11init *d11n0initvals16;
+ __le32 *bcm43xx_16_mimo;
+ size_t bcm43xx_16_mimosz;
+ __le32 *bcm43xx_24_lcn;
+ size_t bcm43xx_24_lcnsz;
+ u32 *bcm43xx_bommajor;
+ u32 *bcm43xx_bomminor;
+};
+
+extern int
+brcms_ucode_data_init(struct brcms_info *wl, struct brcms_ucode *ucode);
+
+extern void brcms_ucode_data_free(struct brcms_ucode *ucode);
+
+extern int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf,
+ unsigned int idx);
+extern int brcms_ucode_init_uint(struct brcms_info *wl, size_t *n_bytes,
+ unsigned int idx);
+extern void brcms_ucode_free_buf(void *);
+extern int brcms_check_firmwares(struct brcms_info *wl);
+
+#endif /* _BRCM_UCODE_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmutil/Makefile b/drivers/net/wireless/brcm80211/brcmutil/Makefile
new file mode 100644
index 000000000000..6281c416289e
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmutil/Makefile
@@ -0,0 +1,28 @@
+#
+# Makefile fragment for Broadcom 802.11n Networking Device Driver Utilities
+#
+# 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.
+
+ccflags-y := \
+ -Idrivers/net/wireless/brcm80211/brcmutil \
+ -Idrivers/net/wireless/brcm80211/include
+
+BRCMUTIL_OFILES := \
+ utils.o
+
+MODULEPFX := brcmutil
+
+obj-$(CONFIG_BRCMUTIL) += $(MODULEPFX).o
+$(MODULEPFX)-objs = $(BRCMUTIL_OFILES)
diff --git a/drivers/net/wireless/brcm80211/brcmutil/utils.c b/drivers/net/wireless/brcm80211/brcmutil/utils.c
new file mode 100644
index 000000000000..f27c48910827
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmutil/utils.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2010 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/netdevice.h>
+#include <linux/module.h>
+#include <brcmu_utils.h>
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver utilities.");
+MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards");
+MODULE_LICENSE("Dual BSD/GPL");
+
+struct sk_buff *brcmu_pkt_buf_get_skb(uint len)
+{
+ struct sk_buff *skb;
+
+ skb = dev_alloc_skb(len);
+ if (skb) {
+ skb_put(skb, len);
+ skb->priority = 0;
+ }
+
+ return skb;
+}
+EXPORT_SYMBOL(brcmu_pkt_buf_get_skb);
+
+/* Free the driver packet. Free the tag if present */
+void brcmu_pkt_buf_free_skb(struct sk_buff *skb)
+{
+ struct sk_buff *nskb;
+ int nest = 0;
+
+ /* perversion: we use skb->next to chain multi-skb packets */
+ while (skb) {
+ nskb = skb->next;
+ skb->next = NULL;
+
+ if (skb->destructor)
+ /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
+ * destructor exists
+ */
+ dev_kfree_skb_any(skb);
+ else
+ /* can free immediately (even in_irq()) if destructor
+ * does not exist
+ */
+ dev_kfree_skb(skb);
+
+ nest++;
+ skb = nskb;
+ }
+}
+EXPORT_SYMBOL(brcmu_pkt_buf_free_skb);
+
+
+/* copy a buffer into a pkt buffer chain */
+uint brcmu_pktfrombuf(struct sk_buff *p, uint offset, int len,
+ unsigned char *buf)
+{
+ uint n, ret = 0;
+
+ /* skip 'offset' bytes */
+ for (; p && offset; p = p->next) {
+ if (offset < (uint) (p->len))
+ break;
+ offset -= p->len;
+ }
+
+ if (!p)
+ return 0;
+
+ /* copy the data */
+ for (; p && len; p = p->next) {
+ n = min((uint) (p->len) - offset, (uint) len);
+ memcpy(p->data + offset, buf, n);
+ buf += n;
+ len -= n;
+ ret += n;
+ offset = 0;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(brcmu_pktfrombuf);
+
+/* return total length of buffer chain */
+uint brcmu_pkttotlen(struct sk_buff *p)
+{
+ uint total;
+
+ total = 0;
+ for (; p; p = p->next)
+ total += p->len;
+ return total;
+}
+EXPORT_SYMBOL(brcmu_pkttotlen);
+
+/*
+ * osl multiple-precedence packet queue
+ * hi_prec is always >= the number of the highest non-empty precedence
+ */
+struct sk_buff *brcmu_pktq_penq(struct pktq *pq, int prec,
+ struct sk_buff *p)
+{
+ struct pktq_prec *q;
+
+ if (pktq_full(pq) || pktq_pfull(pq, prec))
+ return NULL;
+
+ q = &pq->q[prec];
+
+ if (q->head)
+ q->tail->prev = p;
+ else
+ q->head = p;
+
+ q->tail = p;
+ q->len++;
+
+ pq->len++;
+
+ if (pq->hi_prec < prec)
+ pq->hi_prec = (u8) prec;
+
+ return p;
+}
+EXPORT_SYMBOL(brcmu_pktq_penq);
+
+struct sk_buff *brcmu_pktq_penq_head(struct pktq *pq, int prec,
+ struct sk_buff *p)
+{
+ struct pktq_prec *q;
+
+ if (pktq_full(pq) || pktq_pfull(pq, prec))
+ return NULL;
+
+ q = &pq->q[prec];
+
+ if (q->head == NULL)
+ q->tail = p;
+
+ p->prev = q->head;
+ q->head = p;
+ q->len++;
+
+ pq->len++;
+
+ if (pq->hi_prec < prec)
+ pq->hi_prec = (u8) prec;
+
+ return p;
+}
+EXPORT_SYMBOL(brcmu_pktq_penq_head);
+
+struct sk_buff *brcmu_pktq_pdeq(struct pktq *pq, int prec)
+{
+ struct pktq_prec *q;
+ struct sk_buff *p;
+
+ q = &pq->q[prec];
+
+ p = q->head;
+ if (p == NULL)
+ return NULL;
+
+ q->head = p->prev;
+ if (q->head == NULL)
+ q->tail = NULL;
+
+ q->len--;
+
+ pq->len--;
+
+ p->prev = NULL;
+
+ return p;
+}
+EXPORT_SYMBOL(brcmu_pktq_pdeq);
+
+struct sk_buff *brcmu_pktq_pdeq_tail(struct pktq *pq, int prec)
+{
+ struct pktq_prec *q;
+ struct sk_buff *p, *prev;
+
+ q = &pq->q[prec];
+
+ p = q->head;
+ if (p == NULL)
+ return NULL;
+
+ for (prev = NULL; p != q->tail; p = p->prev)
+ prev = p;
+
+ if (prev)
+ prev->prev = NULL;
+ else
+ q->head = NULL;
+
+ q->tail = prev;
+ q->len--;
+
+ pq->len--;
+
+ return p;
+}
+EXPORT_SYMBOL(brcmu_pktq_pdeq_tail);
+
+void
+brcmu_pktq_pflush(struct pktq *pq, int prec, bool dir,
+ bool (*fn)(struct sk_buff *, void *), void *arg)
+{
+ struct pktq_prec *q;
+ struct sk_buff *p, *prev = NULL;
+
+ q = &pq->q[prec];
+ p = q->head;
+ while (p) {
+ if (fn == NULL || (*fn) (p, arg)) {
+ bool head = (p == q->head);
+ if (head)
+ q->head = p->prev;
+ else
+ prev->prev = p->prev;
+ p->prev = NULL;
+ brcmu_pkt_buf_free_skb(p);
+ q->len--;
+ pq->len--;
+ p = (head ? q->head : prev->prev);
+ } else {
+ prev = p;
+ p = p->prev;
+ }
+ }
+
+ if (q->head == NULL)
+ q->tail = NULL;
+}
+EXPORT_SYMBOL(brcmu_pktq_pflush);
+
+void brcmu_pktq_flush(struct pktq *pq, bool dir,
+ bool (*fn)(struct sk_buff *, void *), void *arg)
+{
+ int prec;
+ for (prec = 0; prec < pq->num_prec; prec++)
+ brcmu_pktq_pflush(pq, prec, dir, fn, arg);
+}
+EXPORT_SYMBOL(brcmu_pktq_flush);
+
+void brcmu_pktq_init(struct pktq *pq, int num_prec, int max_len)
+{
+ int prec;
+
+ /* pq is variable size; only zero out what's requested */
+ memset(pq, 0,
+ offsetof(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
+
+ pq->num_prec = (u16) num_prec;
+
+ pq->max = (u16) max_len;
+
+ for (prec = 0; prec < num_prec; prec++)
+ pq->q[prec].max = pq->max;
+}
+EXPORT_SYMBOL(brcmu_pktq_init);
+
+struct sk_buff *brcmu_pktq_peek_tail(struct pktq *pq, int *prec_out)
+{
+ int prec;
+
+ if (pq->len == 0)
+ return NULL;
+
+ for (prec = 0; prec < pq->hi_prec; prec++)
+ if (pq->q[prec].head)
+ break;
+
+ if (prec_out)
+ *prec_out = prec;
+
+ return pq->q[prec].tail;
+}
+EXPORT_SYMBOL(brcmu_pktq_peek_tail);
+
+/* Return sum of lengths of a specific set of precedences */
+int brcmu_pktq_mlen(struct pktq *pq, uint prec_bmp)
+{
+ int prec, len;
+
+ len = 0;
+
+ for (prec = 0; prec <= pq->hi_prec; prec++)
+ if (prec_bmp & (1 << prec))
+ len += pq->q[prec].len;
+
+ return len;
+}
+EXPORT_SYMBOL(brcmu_pktq_mlen);
+
+/* Priority dequeue from a specific set of precedences */
+struct sk_buff *brcmu_pktq_mdeq(struct pktq *pq, uint prec_bmp,
+ int *prec_out)
+{
+ struct pktq_prec *q;
+ struct sk_buff *p;
+ int prec;
+
+ if (pq->len == 0)
+ return NULL;
+
+ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
+ pq->hi_prec--;
+
+ while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
+ if (prec-- == 0)
+ return NULL;
+
+ q = &pq->q[prec];
+
+ p = q->head;
+ if (p == NULL)
+ return NULL;
+
+ q->head = p->prev;
+ if (q->head == NULL)
+ q->tail = NULL;
+
+ q->len--;
+
+ if (prec_out)
+ *prec_out = prec;
+
+ pq->len--;
+
+ p->prev = NULL;
+
+ return p;
+}
+EXPORT_SYMBOL(brcmu_pktq_mdeq);
+
+#if defined(BCMDBG)
+/* pretty hex print a pkt buffer chain */
+void brcmu_prpkt(const char *msg, struct sk_buff *p0)
+{
+ struct sk_buff *p;
+
+ if (msg && (msg[0] != '\0'))
+ printk(KERN_DEBUG "%s:\n", msg);
+
+ for (p = p0; p; p = p->next)
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, p->data, p->len);
+}
+EXPORT_SYMBOL(brcmu_prpkt);
+#endif /* defined(BCMDBG) */
+
+#if defined(BCMDBG)
+/*
+ * print bytes formatted as hex to a string. return the resulting
+ * string length
+ */
+int brcmu_format_hex(char *str, const void *bytes, int len)
+{
+ int i;
+ char *p = str;
+ const u8 *src = (const u8 *)bytes;
+
+ for (i = 0; i < len; i++) {
+ p += snprintf(p, 3, "%02X", *src);
+ src++;
+ }
+ return (int)(p - str);
+}
+EXPORT_SYMBOL(brcmu_format_hex);
+#endif /* defined(BCMDBG) */
diff --git a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
new file mode 100644
index 000000000000..5fb17d53c9b2
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_HW_IDS_H_
+#define _BRCM_HW_IDS_H_
+
+#define BCM4325_D11DUAL_ID 0x431b
+#define BCM4325_D11G_ID 0x431c
+#define BCM4325_D11A_ID 0x431d
+
+#define BCM4329_D11N2G_ID 0x432f /* 4329 802.11n 2.4G device */
+#define BCM4329_D11N5G_ID 0x4330 /* 4329 802.11n 5G device */
+#define BCM4329_D11NDUAL_ID 0x432e
+
+#define BCM4319_D11N_ID 0x4337 /* 4319 802.11n dualband device */
+#define BCM4319_D11N2G_ID 0x4338 /* 4319 802.11n 2.4G device */
+#define BCM4319_D11N5G_ID 0x4339 /* 4319 802.11n 5G device */
+
+#define BCM43224_D11N_ID 0x4353 /* 43224 802.11n dualband device */
+#define BCM43224_D11N_ID_VEN1 0x0576 /* Vendor specific 43224 802.11n db */
+
+#define BCM43225_D11N2G_ID 0x4357 /* 43225 802.11n 2.4GHz device */
+
+#define BCM43236_D11N_ID 0x4346 /* 43236 802.11n dualband device */
+#define BCM43236_D11N2G_ID 0x4347 /* 43236 802.11n 2.4GHz device */
+
+#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */
+
+/* Chip IDs */
+#define BCM4313_CHIP_ID 0x4313 /* 4313 chip id */
+#define BCM4319_CHIP_ID 0x4319 /* 4319 chip id */
+
+#define BCM43224_CHIP_ID 43224 /* 43224 chipcommon chipid */
+#define BCM43225_CHIP_ID 43225 /* 43225 chipcommon chipid */
+#define BCM43421_CHIP_ID 43421 /* 43421 chipcommon chipid */
+#define BCM43235_CHIP_ID 43235 /* 43235 chipcommon chipid */
+#define BCM43236_CHIP_ID 43236 /* 43236 chipcommon chipid */
+#define BCM43238_CHIP_ID 43238 /* 43238 chipcommon chipid */
+#define BCM4329_CHIP_ID 0x4329 /* 4329 chipcommon chipid */
+#define BCM4325_CHIP_ID 0x4325 /* 4325 chipcommon chipid */
+#define BCM4331_CHIP_ID 0x4331 /* 4331 chipcommon chipid */
+#define BCM4336_CHIP_ID 0x4336 /* 4336 chipcommon chipid */
+#define BCM4330_CHIP_ID 0x4330 /* 4330 chipcommon chipid */
+#define BCM6362_CHIP_ID 0x6362 /* 6362 chipcommon chipid */
+
+#endif /* _BRCM_HW_IDS_H_ */
diff --git a/drivers/net/wireless/brcm80211/include/brcmu_utils.h b/drivers/net/wireless/brcm80211/include/brcmu_utils.h
new file mode 100644
index 000000000000..7d0f46e0eb95
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/include/brcmu_utils.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2010 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 _BRCMU_UTILS_H_
+#define _BRCMU_UTILS_H_
+
+#include <linux/skbuff.h>
+
+/*
+ * Spin at most 'us' microseconds while 'exp' is true.
+ * Caller should explicitly test 'exp' when this completes
+ * and take appropriate error action if 'exp' is still true.
+ */
+#define SPINWAIT(exp, us) { \
+ uint countdown = (us) + 9; \
+ while ((exp) && (countdown >= 10)) {\
+ udelay(10); \
+ countdown -= 10; \
+ } \
+}
+
+/* osl multi-precedence packet queue */
+#define PKTQ_LEN_DEFAULT 128 /* Max 128 packets */
+#define PKTQ_MAX_PREC 16 /* Maximum precedence levels */
+
+#define BCME_STRLEN 64 /* Max string length for BCM errors */
+
+/* the largest reasonable packet buffer driver uses for ethernet MTU in bytes */
+#define PKTBUFSZ 2048
+
+#ifndef setbit
+#ifndef NBBY /* the BSD family defines NBBY */
+#define NBBY 8 /* 8 bits per byte */
+#endif /* #ifndef NBBY */
+#define setbit(a, i) (((u8 *)a)[(i)/NBBY] |= 1<<((i)%NBBY))
+#define clrbit(a, i) (((u8 *)a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
+#define isset(a, i) (((const u8 *)a)[(i)/NBBY] & (1<<((i)%NBBY)))
+#define isclr(a, i) ((((const u8 *)a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
+#endif /* setbit */
+
+#define NBITS(type) (sizeof(type) * 8)
+#define NBITVAL(nbits) (1 << (nbits))
+#define MAXBITVAL(nbits) ((1 << (nbits)) - 1)
+#define NBITMASK(nbits) MAXBITVAL(nbits)
+#define MAXNBVAL(nbyte) MAXBITVAL((nbyte) * 8)
+
+/* crc defines */
+#define CRC16_INIT_VALUE 0xffff /* Initial CRC16 checksum value */
+#define CRC16_GOOD_VALUE 0xf0b8 /* Good final CRC16 checksum value */
+
+/* 18-bytes of Ethernet address buffer length */
+#define ETHER_ADDR_STR_LEN 18
+
+struct pktq_prec {
+ struct sk_buff *head; /* first packet to dequeue */
+ struct sk_buff *tail; /* last packet to dequeue */
+ u16 len; /* number of queued packets */
+ u16 max; /* maximum number of queued packets */
+};
+
+/* multi-priority pkt queue */
+struct pktq {
+ u16 num_prec; /* number of precedences in use */
+ u16 hi_prec; /* rapid dequeue hint (>= highest non-empty prec) */
+ u16 max; /* total max packets */
+ u16 len; /* total number of packets */
+ /*
+ * q array must be last since # of elements can be either
+ * PKTQ_MAX_PREC or 1
+ */
+ struct pktq_prec q[PKTQ_MAX_PREC];
+};
+
+/* operations on a specific precedence in packet queue */
+
+static inline int pktq_plen(struct pktq *pq, int prec)
+{
+ return pq->q[prec].len;
+}
+
+static inline int pktq_pavail(struct pktq *pq, int prec)
+{
+ return pq->q[prec].max - pq->q[prec].len;
+}
+
+static inline bool pktq_pfull(struct pktq *pq, int prec)
+{
+ return pq->q[prec].len >= pq->q[prec].max;
+}
+
+static inline bool pktq_pempty(struct pktq *pq, int prec)
+{
+ return pq->q[prec].len == 0;
+}
+
+static inline struct sk_buff *pktq_ppeek(struct pktq *pq, int prec)
+{
+ return pq->q[prec].head;
+}
+
+static inline struct sk_buff *pktq_ppeek_tail(struct pktq *pq, int prec)
+{
+ return pq->q[prec].tail;
+}
+
+extern struct sk_buff *brcmu_pktq_penq(struct pktq *pq, int prec,
+ struct sk_buff *p);
+extern struct sk_buff *brcmu_pktq_penq_head(struct pktq *pq, int prec,
+ struct sk_buff *p);
+extern struct sk_buff *brcmu_pktq_pdeq(struct pktq *pq, int prec);
+extern struct sk_buff *brcmu_pktq_pdeq_tail(struct pktq *pq, int prec);
+
+/* packet primitives */
+extern struct sk_buff *brcmu_pkt_buf_get_skb(uint len);
+extern void brcmu_pkt_buf_free_skb(struct sk_buff *skb);
+
+/* Empty the queue at particular precedence level */
+/* callback function fn(pkt, arg) returns true if pkt belongs to if */
+extern void brcmu_pktq_pflush(struct pktq *pq, int prec,
+ bool dir, bool (*fn)(struct sk_buff *, void *), void *arg);
+
+/* operations on a set of precedences in packet queue */
+
+extern int brcmu_pktq_mlen(struct pktq *pq, uint prec_bmp);
+extern struct sk_buff *brcmu_pktq_mdeq(struct pktq *pq, uint prec_bmp,
+ int *prec_out);
+
+/* operations on packet queue as a whole */
+
+static inline int pktq_len(struct pktq *pq)
+{
+ return (int)pq->len;
+}
+
+static inline int pktq_max(struct pktq *pq)
+{
+ return (int)pq->max;
+}
+
+static inline int pktq_avail(struct pktq *pq)
+{
+ return (int)(pq->max - pq->len);
+}
+
+static inline bool pktq_full(struct pktq *pq)
+{
+ return pq->len >= pq->max;
+}
+
+static inline bool pktq_empty(struct pktq *pq)
+{
+ return pq->len == 0;
+}
+
+extern void brcmu_pktq_init(struct pktq *pq, int num_prec, int max_len);
+/* prec_out may be NULL if caller is not interested in return value */
+extern struct sk_buff *brcmu_pktq_peek_tail(struct pktq *pq, int *prec_out);
+extern void brcmu_pktq_flush(struct pktq *pq, bool dir,
+ bool (*fn)(struct sk_buff *, void *), void *arg);
+
+/* externs */
+/* packet */
+extern uint brcmu_pktfrombuf(struct sk_buff *p,
+ uint offset, int len, unsigned char *buf);
+extern uint brcmu_pkttotlen(struct sk_buff *p);
+
+/* ip address */
+struct ipv4_addr;
+
+#ifdef BCMDBG
+extern void brcmu_prpkt(const char *msg, struct sk_buff *p0);
+#else
+#define brcmu_prpkt(a, b)
+#endif /* BCMDBG */
+
+/* externs */
+/* format/print */
+#if defined(BCMDBG)
+extern int brcmu_format_hex(char *str, const void *bytes, int len);
+#endif
+
+#endif /* _BRCMU_UTILS_H_ */
diff --git a/drivers/net/wireless/brcm80211/include/brcmu_wifi.h b/drivers/net/wireless/brcm80211/include/brcmu_wifi.h
new file mode 100644
index 000000000000..f10d30274c23
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/include/brcmu_wifi.h
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2010 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 _BRCMU_WIFI_H_
+#define _BRCMU_WIFI_H_
+
+#include <linux/if_ether.h> /* for ETH_ALEN */
+#include <linux/ieee80211.h> /* for WLAN_PMKID_LEN */
+
+/*
+ * A chanspec (u16) holds the channel number, band, bandwidth and control
+ * sideband
+ */
+
+/* channel defines */
+#define CH_UPPER_SB 0x01
+#define CH_LOWER_SB 0x02
+#define CH_EWA_VALID 0x04
+#define CH_20MHZ_APART 4
+#define CH_10MHZ_APART 2
+#define CH_5MHZ_APART 1 /* 2G band channels are 5 Mhz apart */
+#define CH_MAX_2G_CHANNEL 14 /* Max channel in 2G band */
+#define BRCM_MAX_2G_CHANNEL CH_MAX_2G_CHANNEL /* legacy define */
+
+/* bandstate array indices */
+#define BAND_2G_INDEX 0 /* wlc->bandstate[x] index */
+#define BAND_5G_INDEX 1 /* wlc->bandstate[x] index */
+
+/*
+ * max # supported channels. The max channel no is 216, this is that + 1
+ * rounded up to a multiple of NBBY (8). DO NOT MAKE it > 255: channels are
+ * u8's all over
+*/
+#define MAXCHANNEL 224
+
+#define WL_CHANSPEC_CHAN_MASK 0x00ff
+#define WL_CHANSPEC_CHAN_SHIFT 0
+
+#define WL_CHANSPEC_CTL_SB_MASK 0x0300
+#define WL_CHANSPEC_CTL_SB_SHIFT 8
+#define WL_CHANSPEC_CTL_SB_LOWER 0x0100
+#define WL_CHANSPEC_CTL_SB_UPPER 0x0200
+#define WL_CHANSPEC_CTL_SB_NONE 0x0300
+
+#define WL_CHANSPEC_BW_MASK 0x0C00
+#define WL_CHANSPEC_BW_SHIFT 10
+#define WL_CHANSPEC_BW_10 0x0400
+#define WL_CHANSPEC_BW_20 0x0800
+#define WL_CHANSPEC_BW_40 0x0C00
+
+#define WL_CHANSPEC_BAND_MASK 0xf000
+#define WL_CHANSPEC_BAND_SHIFT 12
+#define WL_CHANSPEC_BAND_5G 0x1000
+#define WL_CHANSPEC_BAND_2G 0x2000
+#define INVCHANSPEC 255
+
+/* used to calculate the chan_freq = chan_factor * 500Mhz + 5 * chan_number */
+#define WF_CHAN_FACTOR_2_4_G 4814 /* 2.4 GHz band, 2407 MHz */
+#define WF_CHAN_FACTOR_5_G 10000 /* 5 GHz band, 5000 MHz */
+#define WF_CHAN_FACTOR_4_G 8000 /* 4.9 GHz band for Japan */
+
+#define CHSPEC_CHANNEL(chspec) ((u8)((chspec) & WL_CHANSPEC_CHAN_MASK))
+#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK)
+
+#define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK)
+#define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK)
+
+#define CHSPEC_IS10(chspec) \
+ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10)
+
+#define CHSPEC_IS20(chspec) \
+ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20)
+
+#ifndef CHSPEC_IS40
+#define CHSPEC_IS40(chspec) \
+ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)
+#endif
+
+#define CHSPEC_IS5G(chspec) \
+ (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G)
+
+#define CHSPEC_IS2G(chspec) \
+ (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G)
+
+#define CHSPEC_SB_NONE(chspec) \
+ (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_NONE)
+
+#define CHSPEC_SB_UPPER(chspec) \
+ (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER)
+
+#define CHSPEC_SB_LOWER(chspec) \
+ (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER)
+
+#define CHSPEC_CTL_CHAN(chspec) \
+ ((CHSPEC_SB_LOWER(chspec)) ? \
+ (lower_20_sb(((chspec) & WL_CHANSPEC_CHAN_MASK))) : \
+ (upper_20_sb(((chspec) & WL_CHANSPEC_CHAN_MASK))))
+
+#define CHSPEC2BAND(chspec) (CHSPEC_IS5G(chspec) ? BRCM_BAND_5G : BRCM_BAND_2G)
+
+#define CHANSPEC_STR_LEN 8
+
+static inline int lower_20_sb(int channel)
+{
+ return channel > CH_10MHZ_APART ? (channel - CH_10MHZ_APART) : 0;
+}
+
+static inline int upper_20_sb(int channel)
+{
+ return (channel < (MAXCHANNEL - CH_10MHZ_APART)) ?
+ channel + CH_10MHZ_APART : 0;
+}
+
+static inline int chspec_bandunit(u16 chspec)
+{
+ return CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX;
+}
+
+static inline u16 ch20mhz_chspec(int channel)
+{
+ u16 rc = channel <= CH_MAX_2G_CHANNEL ?
+ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G;
+
+ return (u16)((u16)channel | WL_CHANSPEC_BW_20 |
+ WL_CHANSPEC_CTL_SB_NONE | rc);
+}
+
+static inline int next_20mhz_chan(int channel)
+{
+ return channel < (MAXCHANNEL - CH_20MHZ_APART) ?
+ channel + CH_20MHZ_APART : 0;
+}
+
+/* defined rate in 500kbps */
+#define BRCM_MAXRATE 108 /* in 500kbps units */
+#define BRCM_RATE_1M 2 /* in 500kbps units */
+#define BRCM_RATE_2M 4 /* in 500kbps units */
+#define BRCM_RATE_5M5 11 /* in 500kbps units */
+#define BRCM_RATE_11M 22 /* in 500kbps units */
+#define BRCM_RATE_6M 12 /* in 500kbps units */
+#define BRCM_RATE_9M 18 /* in 500kbps units */
+#define BRCM_RATE_12M 24 /* in 500kbps units */
+#define BRCM_RATE_18M 36 /* in 500kbps units */
+#define BRCM_RATE_24M 48 /* in 500kbps units */
+#define BRCM_RATE_36M 72 /* in 500kbps units */
+#define BRCM_RATE_48M 96 /* in 500kbps units */
+#define BRCM_RATE_54M 108 /* in 500kbps units */
+
+#define BRCM_2G_25MHZ_OFFSET 5 /* 2.4GHz band channel offset */
+
+#define MCSSET_LEN 16
+
+static inline bool ac_bitmap_tst(u8 bitmap, int prec)
+{
+ return (bitmap & (1 << (prec))) != 0;
+}
+
+/* Enumerate crypto algorithms */
+#define CRYPTO_ALGO_OFF 0
+#define CRYPTO_ALGO_WEP1 1
+#define CRYPTO_ALGO_TKIP 2
+#define CRYPTO_ALGO_WEP128 3
+#define CRYPTO_ALGO_AES_CCM 4
+#define CRYPTO_ALGO_AES_RESERVED1 5
+#define CRYPTO_ALGO_AES_RESERVED2 6
+#define CRYPTO_ALGO_NALG 7
+
+/* wireless security bitvec */
+
+#define WEP_ENABLED 0x0001
+#define TKIP_ENABLED 0x0002
+#define AES_ENABLED 0x0004
+#define WSEC_SWFLAG 0x0008
+/* to go into transition mode without setting wep */
+#define SES_OW_ENABLED 0x0040
+
+/* WPA authentication mode bitvec */
+#define WPA_AUTH_DISABLED 0x0000 /* Legacy (i.e., non-WPA) */
+#define WPA_AUTH_NONE 0x0001 /* none (IBSS) */
+#define WPA_AUTH_UNSPECIFIED 0x0002 /* over 802.1x */
+#define WPA_AUTH_PSK 0x0004 /* Pre-shared key */
+#define WPA_AUTH_RESERVED1 0x0008
+#define WPA_AUTH_RESERVED2 0x0010
+
+#define WPA2_AUTH_RESERVED1 0x0020
+#define WPA2_AUTH_UNSPECIFIED 0x0040 /* over 802.1x */
+#define WPA2_AUTH_PSK 0x0080 /* Pre-shared key */
+#define WPA2_AUTH_RESERVED3 0x0200
+#define WPA2_AUTH_RESERVED4 0x0400
+#define WPA2_AUTH_RESERVED5 0x0800
+
+/* pmkid */
+#define MAXPMKID 16
+
+#define DOT11_DEFAULT_RTS_LEN 2347
+#define DOT11_DEFAULT_FRAG_LEN 2346
+
+#define DOT11_ICV_AES_LEN 8
+#define DOT11_QOS_LEN 2
+#define DOT11_IV_MAX_LEN 8
+#define DOT11_A4_HDR_LEN 30
+
+#define HT_CAP_RX_STBC_NO 0x0
+#define HT_CAP_RX_STBC_ONE_STREAM 0x1
+
+struct pmkid {
+ u8 BSSID[ETH_ALEN];
+ u8 PMKID[WLAN_PMKID_LEN];
+};
+
+struct pmkid_list {
+ __le32 npmkid;
+ struct pmkid pmkid[1];
+};
+
+struct pmkid_cand {
+ u8 BSSID[ETH_ALEN];
+ u8 preauth;
+};
+
+struct pmkid_cand_list {
+ u32 npmkid_cand;
+ struct pmkid_cand pmkid_cand[1];
+};
+
+#endif /* _BRCMU_WIFI_H_ */
diff --git a/drivers/net/wireless/brcm80211/include/chipcommon.h b/drivers/net/wireless/brcm80211/include/chipcommon.h
new file mode 100644
index 000000000000..fefabc39e646
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/include/chipcommon.h
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2010 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 _SBCHIPC_H
+#define _SBCHIPC_H
+
+#include "defs.h" /* for PAD macro */
+
+struct chipcregs {
+ u32 chipid; /* 0x0 */
+ u32 capabilities;
+ u32 corecontrol; /* corerev >= 1 */
+ u32 bist;
+
+ /* OTP */
+ u32 otpstatus; /* 0x10, corerev >= 10 */
+ u32 otpcontrol;
+ u32 otpprog;
+ u32 otplayout; /* corerev >= 23 */
+
+ /* Interrupt control */
+ u32 intstatus; /* 0x20 */
+ u32 intmask;
+
+ /* Chip specific regs */
+ u32 chipcontrol; /* 0x28, rev >= 11 */
+ u32 chipstatus; /* 0x2c, rev >= 11 */
+
+ /* Jtag Master */
+ u32 jtagcmd; /* 0x30, rev >= 10 */
+ u32 jtagir;
+ u32 jtagdr;
+ u32 jtagctrl;
+
+ /* serial flash interface registers */
+ u32 flashcontrol; /* 0x40 */
+ u32 flashaddress;
+ u32 flashdata;
+ u32 PAD[1];
+
+ /* Silicon backplane configuration broadcast control */
+ u32 broadcastaddress; /* 0x50 */
+ u32 broadcastdata;
+
+ /* gpio - cleared only by power-on-reset */
+ u32 gpiopullup; /* 0x58, corerev >= 20 */
+ u32 gpiopulldown; /* 0x5c, corerev >= 20 */
+ u32 gpioin; /* 0x60 */
+ u32 gpioout; /* 0x64 */
+ u32 gpioouten; /* 0x68 */
+ u32 gpiocontrol; /* 0x6C */
+ u32 gpiointpolarity; /* 0x70 */
+ u32 gpiointmask; /* 0x74 */
+
+ /* GPIO events corerev >= 11 */
+ u32 gpioevent;
+ u32 gpioeventintmask;
+
+ /* Watchdog timer */
+ u32 watchdog; /* 0x80 */
+
+ /* GPIO events corerev >= 11 */
+ u32 gpioeventintpolarity;
+
+ /* GPIO based LED powersave registers corerev >= 16 */
+ u32 gpiotimerval; /* 0x88 */
+ u32 gpiotimeroutmask;
+
+ /* clock control */
+ u32 clockcontrol_n; /* 0x90 */
+ u32 clockcontrol_sb; /* aka m0 */
+ u32 clockcontrol_pci; /* aka m1 */
+ u32 clockcontrol_m2; /* mii/uart/mipsref */
+ u32 clockcontrol_m3; /* cpu */
+ u32 clkdiv; /* corerev >= 3 */
+ u32 gpiodebugsel; /* corerev >= 28 */
+ u32 capabilities_ext; /* 0xac */
+
+ /* pll delay registers (corerev >= 4) */
+ u32 pll_on_delay; /* 0xb0 */
+ u32 fref_sel_delay;
+ u32 slow_clk_ctl; /* 5 < corerev < 10 */
+ u32 PAD;
+
+ /* Instaclock registers (corerev >= 10) */
+ u32 system_clk_ctl; /* 0xc0 */
+ u32 clkstatestretch;
+ u32 PAD[2];
+
+ /* Indirect backplane access (corerev >= 22) */
+ u32 bp_addrlow; /* 0xd0 */
+ u32 bp_addrhigh;
+ u32 bp_data;
+ u32 PAD;
+ u32 bp_indaccess;
+ u32 PAD[3];
+
+ /* More clock dividers (corerev >= 32) */
+ u32 clkdiv2;
+ u32 PAD[2];
+
+ /* In AI chips, pointer to erom */
+ u32 eromptr; /* 0xfc */
+
+ /* ExtBus control registers (corerev >= 3) */
+ u32 pcmcia_config; /* 0x100 */
+ u32 pcmcia_memwait;
+ u32 pcmcia_attrwait;
+ u32 pcmcia_iowait;
+ u32 ide_config;
+ u32 ide_memwait;
+ u32 ide_attrwait;
+ u32 ide_iowait;
+ u32 prog_config;
+ u32 prog_waitcount;
+ u32 flash_config;
+ u32 flash_waitcount;
+ u32 SECI_config; /* 0x130 SECI configuration */
+ u32 PAD[3];
+
+ /* Enhanced Coexistence Interface (ECI) registers (corerev >= 21) */
+ u32 eci_output; /* 0x140 */
+ u32 eci_control;
+ u32 eci_inputlo;
+ u32 eci_inputmi;
+ u32 eci_inputhi;
+ u32 eci_inputintpolaritylo;
+ u32 eci_inputintpolaritymi;
+ u32 eci_inputintpolarityhi;
+ u32 eci_intmasklo;
+ u32 eci_intmaskmi;
+ u32 eci_intmaskhi;
+ u32 eci_eventlo;
+ u32 eci_eventmi;
+ u32 eci_eventhi;
+ u32 eci_eventmasklo;
+ u32 eci_eventmaskmi;
+ u32 eci_eventmaskhi;
+ u32 PAD[3];
+
+ /* SROM interface (corerev >= 32) */
+ u32 sromcontrol; /* 0x190 */
+ u32 sromaddress;
+ u32 sromdata;
+ u32 PAD[17];
+
+ /* Clock control and hardware workarounds (corerev >= 20) */
+ u32 clk_ctl_st; /* 0x1e0 */
+ u32 hw_war;
+ u32 PAD[70];
+
+ /* UARTs */
+ u8 uart0data; /* 0x300 */
+ u8 uart0imr;
+ u8 uart0fcr;
+ u8 uart0lcr;
+ u8 uart0mcr;
+ u8 uart0lsr;
+ u8 uart0msr;
+ u8 uart0scratch;
+ u8 PAD[248]; /* corerev >= 1 */
+
+ u8 uart1data; /* 0x400 */
+ u8 uart1imr;
+ u8 uart1fcr;
+ u8 uart1lcr;
+ u8 uart1mcr;
+ u8 uart1lsr;
+ u8 uart1msr;
+ u8 uart1scratch;
+ u32 PAD[126];
+
+ /* PMU registers (corerev >= 20) */
+ u32 pmucontrol; /* 0x600 */
+ u32 pmucapabilities;
+ u32 pmustatus;
+ u32 res_state;
+ u32 res_pending;
+ u32 pmutimer;
+ u32 min_res_mask;
+ u32 max_res_mask;
+ u32 res_table_sel;
+ u32 res_dep_mask;
+ u32 res_updn_timer;
+ u32 res_timer;
+ u32 clkstretch;
+ u32 pmuwatchdog;
+ u32 gpiosel; /* 0x638, rev >= 1 */
+ u32 gpioenable; /* 0x63c, rev >= 1 */
+ u32 res_req_timer_sel;
+ u32 res_req_timer;
+ u32 res_req_mask;
+ u32 PAD;
+ u32 chipcontrol_addr; /* 0x650 */
+ u32 chipcontrol_data; /* 0x654 */
+ u32 regcontrol_addr;
+ u32 regcontrol_data;
+ u32 pllcontrol_addr;
+ u32 pllcontrol_data;
+ u32 pmustrapopt; /* 0x668, corerev >= 28 */
+ u32 pmu_xtalfreq; /* 0x66C, pmurev >= 10 */
+ u32 PAD[100];
+ u16 sromotp[768];
+};
+
+/* chipid */
+#define CID_ID_MASK 0x0000ffff /* Chip Id mask */
+#define CID_REV_MASK 0x000f0000 /* Chip Revision mask */
+#define CID_REV_SHIFT 16 /* Chip Revision shift */
+#define CID_PKG_MASK 0x00f00000 /* Package Option mask */
+#define CID_PKG_SHIFT 20 /* Package Option shift */
+#define CID_CC_MASK 0x0f000000 /* CoreCount (corerev >= 4) */
+#define CID_CC_SHIFT 24
+#define CID_TYPE_MASK 0xf0000000 /* Chip Type */
+#define CID_TYPE_SHIFT 28
+
+/* capabilities */
+#define CC_CAP_UARTS_MASK 0x00000003 /* Number of UARTs */
+#define CC_CAP_MIPSEB 0x00000004 /* MIPS is in big-endian mode */
+#define CC_CAP_UCLKSEL 0x00000018 /* UARTs clock select */
+/* UARTs are driven by internal divided clock */
+#define CC_CAP_UINTCLK 0x00000008
+#define CC_CAP_UARTGPIO 0x00000020 /* UARTs own GPIOs 15:12 */
+#define CC_CAP_EXTBUS_MASK 0x000000c0 /* External bus mask */
+#define CC_CAP_EXTBUS_NONE 0x00000000 /* No ExtBus present */
+#define CC_CAP_EXTBUS_FULL 0x00000040 /* ExtBus: PCMCIA, IDE & Prog */
+#define CC_CAP_EXTBUS_PROG 0x00000080 /* ExtBus: ProgIf only */
+#define CC_CAP_FLASH_MASK 0x00000700 /* Type of flash */
+#define CC_CAP_PLL_MASK 0x00038000 /* Type of PLL */
+#define CC_CAP_PWR_CTL 0x00040000 /* Power control */
+#define CC_CAP_OTPSIZE 0x00380000 /* OTP Size (0 = none) */
+#define CC_CAP_OTPSIZE_SHIFT 19 /* OTP Size shift */
+#define CC_CAP_OTPSIZE_BASE 5 /* OTP Size base */
+#define CC_CAP_JTAGP 0x00400000 /* JTAG Master Present */
+#define CC_CAP_ROM 0x00800000 /* Internal boot rom active */
+#define CC_CAP_BKPLN64 0x08000000 /* 64-bit backplane */
+#define CC_CAP_PMU 0x10000000 /* PMU Present, rev >= 20 */
+#define CC_CAP_SROM 0x40000000 /* Srom Present, rev >= 32 */
+/* Nand flash present, rev >= 35 */
+#define CC_CAP_NFLASH 0x80000000
+
+#define CC_CAP2_SECI 0x00000001 /* SECI Present, rev >= 36 */
+/* GSIO (spi/i2c) present, rev >= 37 */
+#define CC_CAP2_GSIO 0x00000002
+
+/* pmucapabilities */
+#define PCAP_REV_MASK 0x000000ff
+#define PCAP_RC_MASK 0x00001f00
+#define PCAP_RC_SHIFT 8
+#define PCAP_TC_MASK 0x0001e000
+#define PCAP_TC_SHIFT 13
+#define PCAP_PC_MASK 0x001e0000
+#define PCAP_PC_SHIFT 17
+#define PCAP_VC_MASK 0x01e00000
+#define PCAP_VC_SHIFT 21
+#define PCAP_CC_MASK 0x1e000000
+#define PCAP_CC_SHIFT 25
+#define PCAP5_PC_MASK 0x003e0000 /* PMU corerev >= 5 */
+#define PCAP5_PC_SHIFT 17
+#define PCAP5_VC_MASK 0x07c00000
+#define PCAP5_VC_SHIFT 22
+#define PCAP5_CC_MASK 0xf8000000
+#define PCAP5_CC_SHIFT 27
+
+/*
+* Maximum delay for the PMU state transition in us.
+* This is an upper bound intended for spinwaits etc.
+*/
+#define PMU_MAX_TRANSITION_DLY 15000
+
+#endif /* _SBCHIPC_H */
diff --git a/drivers/net/wireless/brcm80211/include/defs.h b/drivers/net/wireless/brcm80211/include/defs.h
new file mode 100644
index 000000000000..1e5f310af1e7
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/include/defs.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_DEFS_H_
+#define _BRCM_DEFS_H_
+
+#include <linux/types.h>
+
+#define SI_BUS 0
+#define PCI_BUS 1
+#define PCMCIA_BUS 2
+#define SDIO_BUS 3
+#define JTAG_BUS 4
+#define USB_BUS 5
+#define SPI_BUS 6
+
+#define OFF 0
+#define ON 1 /* ON = 1 */
+#define AUTO (-1) /* Auto = -1 */
+
+/*
+ * Priority definitions according 802.1D
+ */
+#define PRIO_8021D_NONE 2
+#define PRIO_8021D_BK 1
+#define PRIO_8021D_BE 0
+#define PRIO_8021D_EE 3
+#define PRIO_8021D_CL 4
+#define PRIO_8021D_VI 5
+#define PRIO_8021D_VO 6
+#define PRIO_8021D_NC 7
+
+#define MAXPRIO 7
+#define NUMPRIO (MAXPRIO + 1)
+
+#define WL_NUMRATES 16 /* max # of rates in a rateset */
+
+#define BRCM_CNTRY_BUF_SZ 4 /* Country string is 3 bytes + NUL */
+
+#define BRCM_SET_CHANNEL 30
+#define BRCM_SET_SRL 32
+#define BRCM_SET_LRL 34
+#define BRCM_SET_BCNPRD 76
+
+#define BRCM_GET_CURR_RATESET 114 /* current rateset */
+#define BRCM_GET_PHYLIST 180
+
+/* Bit masks for radio disabled status - returned by WL_GET_RADIO */
+
+#define WL_RADIO_SW_DISABLE (1<<0)
+#define WL_RADIO_HW_DISABLE (1<<1)
+#define WL_RADIO_MPC_DISABLE (1<<2)
+/* some countries don't support any channel */
+#define WL_RADIO_COUNTRY_DISABLE (1<<3)
+
+/* Override bit for SET_TXPWR. if set, ignore other level limits */
+#define WL_TXPWR_OVERRIDE (1U<<31)
+
+/* band types */
+#define BRCM_BAND_AUTO 0 /* auto-select */
+#define BRCM_BAND_5G 1 /* 5 Ghz */
+#define BRCM_BAND_2G 2 /* 2.4 Ghz */
+#define BRCM_BAND_ALL 3 /* all bands */
+
+/* Values for PM */
+#define PM_OFF 0
+#define PM_MAX 1
+
+/* Message levels */
+#define LOG_ERROR_VAL 0x00000001
+#define LOG_TRACE_VAL 0x00000002
+
+#define PM_OFF 0
+#define PM_MAX 1
+#define PM_FAST 2
+
+/*
+ * Sonics Configuration Space Registers.
+ */
+
+/* core sbconfig regs are top 256bytes of regs */
+#define SBCONFIGOFF 0xf00
+
+/* cpp contortions to concatenate w/arg prescan */
+#ifndef PAD
+#define _PADLINE(line) pad ## line
+#define _XSTR(line) _PADLINE(line)
+#define PAD _XSTR(__LINE__)
+#endif
+
+#endif /* _BRCM_DEFS_H_ */
diff --git a/drivers/net/wireless/brcm80211/include/soc.h b/drivers/net/wireless/brcm80211/include/soc.h
new file mode 100644
index 000000000000..4fcb956ad9e0
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/include/soc.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2010 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 _BRCM_SOC_H
+#define _BRCM_SOC_H
+
+#define SI_ENUM_BASE 0x18000000 /* Enumeration space base */
+
+/* core codes */
+#define NODEV_CORE_ID 0x700 /* Invalid coreid */
+#define CC_CORE_ID 0x800 /* chipcommon core */
+#define ILINE20_CORE_ID 0x801 /* iline20 core */
+#define SRAM_CORE_ID 0x802 /* sram core */
+#define SDRAM_CORE_ID 0x803 /* sdram core */
+#define PCI_CORE_ID 0x804 /* pci core */
+#define MIPS_CORE_ID 0x805 /* mips core */
+#define ENET_CORE_ID 0x806 /* enet mac core */
+#define CODEC_CORE_ID 0x807 /* v90 codec core */
+#define USB_CORE_ID 0x808 /* usb 1.1 host/device core */
+#define ADSL_CORE_ID 0x809 /* ADSL core */
+#define ILINE100_CORE_ID 0x80a /* iline100 core */
+#define IPSEC_CORE_ID 0x80b /* ipsec core */
+#define UTOPIA_CORE_ID 0x80c /* utopia core */
+#define PCMCIA_CORE_ID 0x80d /* pcmcia core */
+#define SOCRAM_CORE_ID 0x80e /* internal memory core */
+#define MEMC_CORE_ID 0x80f /* memc sdram core */
+#define OFDM_CORE_ID 0x810 /* OFDM phy core */
+#define EXTIF_CORE_ID 0x811 /* external interface core */
+#define D11_CORE_ID 0x812 /* 802.11 MAC core */
+#define APHY_CORE_ID 0x813 /* 802.11a phy core */
+#define BPHY_CORE_ID 0x814 /* 802.11b phy core */
+#define GPHY_CORE_ID 0x815 /* 802.11g phy core */
+#define MIPS33_CORE_ID 0x816 /* mips3302 core */
+#define USB11H_CORE_ID 0x817 /* usb 1.1 host core */
+#define USB11D_CORE_ID 0x818 /* usb 1.1 device core */
+#define USB20H_CORE_ID 0x819 /* usb 2.0 host core */
+#define USB20D_CORE_ID 0x81a /* usb 2.0 device core */
+#define SDIOH_CORE_ID 0x81b /* sdio host core */
+#define ROBO_CORE_ID 0x81c /* roboswitch core */
+#define ATA100_CORE_ID 0x81d /* parallel ATA core */
+#define SATAXOR_CORE_ID 0x81e /* serial ATA & XOR DMA core */
+#define GIGETH_CORE_ID 0x81f /* gigabit ethernet core */
+#define PCIE_CORE_ID 0x820 /* pci express core */
+#define NPHY_CORE_ID 0x821 /* 802.11n 2x2 phy core */
+#define SRAMC_CORE_ID 0x822 /* SRAM controller core */
+#define MINIMAC_CORE_ID 0x823 /* MINI MAC/phy core */
+#define ARM11_CORE_ID 0x824 /* ARM 1176 core */
+#define ARM7S_CORE_ID 0x825 /* ARM7tdmi-s core */
+#define LPPHY_CORE_ID 0x826 /* 802.11a/b/g phy core */
+#define PMU_CORE_ID 0x827 /* PMU core */
+#define SSNPHY_CORE_ID 0x828 /* 802.11n single-stream phy core */
+#define SDIOD_CORE_ID 0x829 /* SDIO device core */
+#define ARMCM3_CORE_ID 0x82a /* ARM Cortex M3 core */
+#define HTPHY_CORE_ID 0x82b /* 802.11n 4x4 phy core */
+#define MIPS74K_CORE_ID 0x82c /* mips 74k core */
+#define GMAC_CORE_ID 0x82d /* Gigabit MAC core */
+#define DMEMC_CORE_ID 0x82e /* DDR1/2 memory controller core */
+#define PCIERC_CORE_ID 0x82f /* PCIE Root Complex core */
+#define OCP_CORE_ID 0x830 /* OCP2OCP bridge core */
+#define SC_CORE_ID 0x831 /* shared common core */
+#define AHB_CORE_ID 0x832 /* OCP2AHB bridge core */
+#define SPIH_CORE_ID 0x833 /* SPI host core */
+#define I2S_CORE_ID 0x834 /* I2S core */
+#define DMEMS_CORE_ID 0x835 /* SDR/DDR1 memory controller core */
+#define DEF_SHIM_COMP 0x837 /* SHIM component in ubus/6362 */
+#define OOB_ROUTER_CORE_ID 0x367 /* OOB router core ID */
+/* Default component, in ai chips it maps all unused address ranges */
+#define DEF_AI_COMP 0xfff
+
+/* Common core control flags */
+#define SICF_BIST_EN 0x8000
+#define SICF_PME_EN 0x4000
+#define SICF_CORE_BITS 0x3ffc
+#define SICF_FGC 0x0002
+#define SICF_CLOCK_EN 0x0001
+
+#endif /* _BRCM_SOC_H */
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 89a116fba1de..bfa0d54221e8 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -816,7 +816,7 @@ static const struct net_device_ops hostap_netdev_ops = {
.ndo_stop = prism2_close,
.ndo_do_ioctl = hostap_ioctl,
.ndo_set_mac_address = prism2_set_mac_address,
- .ndo_set_multicast_list = hostap_set_multicast_list,
+ .ndo_set_rx_mode = hostap_set_multicast_list,
.ndo_change_mtu = prism2_change_mtu,
.ndo_tx_timeout = prism2_tx_timeout,
.ndo_validate_addr = eth_validate_addr,
@@ -829,7 +829,7 @@ static const struct net_device_ops hostap_mgmt_netdev_ops = {
.ndo_stop = prism2_close,
.ndo_do_ioctl = hostap_ioctl,
.ndo_set_mac_address = prism2_set_mac_address,
- .ndo_set_multicast_list = hostap_set_multicast_list,
+ .ndo_set_rx_mode = hostap_set_multicast_list,
.ndo_change_mtu = prism2_change_mtu,
.ndo_tx_timeout = prism2_tx_timeout,
.ndo_validate_addr = eth_validate_addr,
@@ -842,7 +842,7 @@ static const struct net_device_ops hostap_master_ops = {
.ndo_stop = prism2_close,
.ndo_do_ioctl = hostap_ioctl,
.ndo_set_mac_address = prism2_set_mac_address,
- .ndo_set_multicast_list = hostap_set_multicast_list,
+ .ndo_set_rx_mode = hostap_set_multicast_list,
.ndo_change_mtu = prism2_change_mtu,
.ndo_tx_timeout = prism2_tx_timeout,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index 3774dd034746..127e9c63beaf 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -161,7 +161,7 @@ that only one external action is invoked at a time.
#include <linux/firmware.h>
#include <linux/acpi.h>
#include <linux/ctype.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
#include <net/lib80211.h>
@@ -174,7 +174,7 @@ that only one external action is invoked at a time.
#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2100 Network Driver"
#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation"
-static struct pm_qos_request_list ipw2100_pm_qos_req;
+static struct pm_qos_request ipw2100_pm_qos_req;
/* Debugging stuff */
#ifdef CONFIG_IPW2100_DEBUG
@@ -1903,15 +1903,17 @@ static void ipw2100_down(struct ipw2100_priv *priv)
static int ipw2100_net_init(struct net_device *dev)
{
struct ipw2100_priv *priv = libipw_priv(dev);
+
+ return ipw2100_up(priv, 1);
+}
+
+static int ipw2100_wdev_init(struct net_device *dev)
+{
+ struct ipw2100_priv *priv = libipw_priv(dev);
const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
struct wireless_dev *wdev = &priv->ieee->wdev;
- int ret;
int i;
- ret = ipw2100_up(priv, 1);
- if (ret)
- return ret;
-
memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN);
/* fill-out priv->ieee->bg_band */
@@ -6350,9 +6352,13 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
"Error calling register_netdev.\n");
goto fail;
}
+ registered = 1;
+
+ err = ipw2100_wdev_init(dev);
+ if (err)
+ goto fail;
mutex_lock(&priv->action_mutex);
- registered = 1;
IPW_DEBUG_INFO("%s: Bound to %s\n", dev->name, pci_name(pci_dev));
@@ -6389,7 +6395,8 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
fail_unlock:
mutex_unlock(&priv->action_mutex);
-
+ wiphy_unregister(priv->ieee->wdev.wiphy);
+ kfree(priv->ieee->bg_band.channels);
fail:
if (dev) {
if (registered)
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 87813c33bdc2..99a710dfe771 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -32,6 +32,7 @@
#include <linux/sched.h>
#include <linux/slab.h>
+#include <net/cfg80211-wext.h>
#include "ipw2200.h"
@@ -11425,16 +11426,23 @@ static void ipw_bg_down(struct work_struct *work)
/* Called by register_netdev() */
static int ipw_net_init(struct net_device *dev)
{
+ int rc = 0;
+ struct ipw_priv *priv = libipw_priv(dev);
+
+ mutex_lock(&priv->mutex);
+ if (ipw_up(priv))
+ rc = -EIO;
+ mutex_unlock(&priv->mutex);
+
+ return rc;
+}
+
+static int ipw_wdev_init(struct net_device *dev)
+{
int i, rc = 0;
struct ipw_priv *priv = libipw_priv(dev);
const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
struct wireless_dev *wdev = &priv->ieee->wdev;
- mutex_lock(&priv->mutex);
-
- if (ipw_up(priv)) {
- rc = -EIO;
- goto out;
- }
memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN);
@@ -11519,13 +11527,9 @@ static int ipw_net_init(struct net_device *dev)
set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);
/* With that information in place, we can now register the wiphy... */
- if (wiphy_register(wdev->wiphy)) {
+ if (wiphy_register(wdev->wiphy))
rc = -EIO;
- goto out;
- }
-
out:
- mutex_unlock(&priv->mutex);
return rc;
}
@@ -11701,7 +11705,7 @@ static const struct net_device_ops ipw_netdev_ops = {
.ndo_init = ipw_net_init,
.ndo_open = ipw_net_open,
.ndo_stop = ipw_net_stop,
- .ndo_set_multicast_list = ipw_net_set_multicast_list,
+ .ndo_set_rx_mode = ipw_net_set_multicast_list,
.ndo_set_mac_address = ipw_net_set_mac_address,
.ndo_start_xmit = libipw_xmit,
.ndo_change_mtu = libipw_change_mtu,
@@ -11832,14 +11836,22 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
goto out_remove_sysfs;
}
+ err = ipw_wdev_init(net_dev);
+ if (err) {
+ IPW_ERROR("failed to register wireless device\n");
+ goto out_unregister_netdev;
+ }
+
#ifdef CONFIG_IPW2200_PROMISCUOUS
if (rtap_iface) {
err = ipw_prom_alloc(priv);
if (err) {
IPW_ERROR("Failed to register promiscuous network "
"device (error %d).\n", err);
- unregister_netdev(priv->net_dev);
- goto out_remove_sysfs;
+ wiphy_unregister(priv->ieee->wdev.wiphy);
+ kfree(priv->ieee->a_band.channels);
+ kfree(priv->ieee->bg_band.channels);
+ goto out_unregister_netdev;
}
}
#endif
@@ -11851,6 +11863,8 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
return 0;
+ out_unregister_netdev:
+ unregister_netdev(priv->net_dev);
out_remove_sysfs:
sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group);
out_release_irq:
diff --git a/drivers/net/wireless/ipw2x00/libipw_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c
index 01c88a71abe1..e8c039879b05 100644
--- a/drivers/net/wireless/ipw2x00/libipw_tx.c
+++ b/drivers/net/wireless/ipw2x00/libipw_tx.c
@@ -395,7 +395,7 @@ netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev)
(CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS))
bytes_per_frag -= LIBIPW_FCS_LEN;
- /* Each fragment may need to have room for encryptiong
+ /* Each fragment may need to have room for encryption
* pre/postfix */
if (host_encrypt)
bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len +
diff --git a/drivers/net/wireless/iwlegacy/iwl-3945-led.c b/drivers/net/wireless/iwlegacy/iwl-3945-led.c
index abd923558d48..7a7f0f38c8ab 100644
--- a/drivers/net/wireless/iwlegacy/iwl-3945-led.c
+++ b/drivers/net/wireless/iwlegacy/iwl-3945-led.c
@@ -32,7 +32,6 @@
#include <linux/delay.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
-#include <linux/wireless.h>
#include <net/mac80211.h>
#include <linux/etherdevice.h>
#include <asm/unaligned.h>
diff --git a/drivers/net/wireless/iwlegacy/iwl-3945-rs.c b/drivers/net/wireless/iwlegacy/iwl-3945-rs.c
index 977bd2477c6a..8faeaf2dddec 100644
--- a/drivers/net/wireless/iwlegacy/iwl-3945-rs.c
+++ b/drivers/net/wireless/iwlegacy/iwl-3945-rs.c
@@ -28,7 +28,6 @@
#include <linux/init.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
-#include <linux/wireless.h>
#include <net/mac80211.h>
#include <linux/netdevice.h>
@@ -822,12 +821,15 @@ static void iwl3945_rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
out:
- rs_sta->last_txrate_idx = index;
- if (sband->band == IEEE80211_BAND_5GHZ)
- info->control.rates[0].idx = rs_sta->last_txrate_idx -
- IWL_FIRST_OFDM_RATE;
- else
+ if (sband->band == IEEE80211_BAND_5GHZ) {
+ if (WARN_ON_ONCE(index < IWL_FIRST_OFDM_RATE))
+ index = IWL_FIRST_OFDM_RATE;
+ rs_sta->last_txrate_idx = index;
+ info->control.rates[0].idx = index - IWL_FIRST_OFDM_RATE;
+ } else {
+ rs_sta->last_txrate_idx = index;
info->control.rates[0].idx = rs_sta->last_txrate_idx;
+ }
IWL_DEBUG_RATE(priv, "leave: %d\n", index);
}
diff --git a/drivers/net/wireless/iwlegacy/iwl-3945.c b/drivers/net/wireless/iwlegacy/iwl-3945.c
index 73fe3cdf796b..f7c0a7438476 100644
--- a/drivers/net/wireless/iwlegacy/iwl-3945.c
+++ b/drivers/net/wireless/iwlegacy/iwl-3945.c
@@ -34,7 +34,6 @@
#include <linux/sched.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
-#include <linux/wireless.h>
#include <linux/firmware.h>
#include <linux/etherdevice.h>
#include <asm/unaligned.h>
diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-led.c b/drivers/net/wireless/iwlegacy/iwl-4965-led.c
index 26d324e30692..6862fdcaee62 100644
--- a/drivers/net/wireless/iwlegacy/iwl-4965-led.c
+++ b/drivers/net/wireless/iwlegacy/iwl-4965-led.c
@@ -32,7 +32,6 @@
#include <linux/delay.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
-#include <linux/wireless.h>
#include <net/mac80211.h>
#include <linux/etherdevice.h>
#include <asm/unaligned.h>
diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-rs.c b/drivers/net/wireless/iwlegacy/iwl-4965-rs.c
index 9b65153bdd01..57ebe214e68c 100644
--- a/drivers/net/wireless/iwlegacy/iwl-4965-rs.c
+++ b/drivers/net/wireless/iwlegacy/iwl-4965-rs.c
@@ -27,7 +27,6 @@
#include <linux/init.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
-#include <linux/wireless.h>
#include <net/mac80211.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-tx.c b/drivers/net/wireless/iwlegacy/iwl-4965-tx.c
index ac4f64de1363..7f12e3638bae 100644
--- a/drivers/net/wireless/iwlegacy/iwl-4965-tx.c
+++ b/drivers/net/wireless/iwlegacy/iwl-4965-tx.c
@@ -335,7 +335,7 @@ int iwl4965_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
sta_priv = (void *)sta->drv_priv;
if (sta_priv && sta_priv->asleep &&
- (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)) {
+ (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) {
/*
* This sends an asynchronous command to the device,
* but we can rely on it being processed before the
diff --git a/drivers/net/wireless/iwlegacy/iwl-4965.c b/drivers/net/wireless/iwlegacy/iwl-4965.c
index ecdc6e557428..86f4fce193e4 100644
--- a/drivers/net/wireless/iwlegacy/iwl-4965.c
+++ b/drivers/net/wireless/iwlegacy/iwl-4965.c
@@ -33,7 +33,6 @@
#include <linux/sched.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
-#include <linux/wireless.h>
#include <net/mac80211.h>
#include <linux/etherdevice.h>
#include <asm/unaligned.h>
diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c
index 35cd2537e7fd..2bd5659310d7 100644
--- a/drivers/net/wireless/iwlegacy/iwl-core.c
+++ b/drivers/net/wireless/iwlegacy/iwl-core.c
@@ -937,7 +937,7 @@ void iwl_legacy_irq_handle_error(struct iwl_priv *priv)
&priv->contexts[IWL_RXON_CTX_BSS]);
#endif
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
/* Keep the restart process from trying to send host
* commands by clearing the INIT status bit */
@@ -1250,7 +1250,8 @@ void iwl_legacy_clear_isr_stats(struct iwl_priv *priv)
memset(&priv->isr_stats, 0, sizeof(priv->isr_stats));
}
-int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
+int iwl_legacy_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;
@@ -1746,7 +1747,7 @@ int iwl_legacy_force_reset(struct iwl_priv *priv, bool external)
/* Set the FW error flag -- cleared on iwl_down */
set_bit(STATUS_FW_ERROR, &priv->status);
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
/*
* Keep the restart process from trying to send host
* commands by clearing the INIT status bit
@@ -2220,7 +2221,8 @@ out:
}
EXPORT_SYMBOL(iwl_legacy_mac_config);
-void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw)
+void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
{
struct iwl_priv *priv = hw->priv;
unsigned long flags;
diff --git a/drivers/net/wireless/iwlegacy/iwl-core.h b/drivers/net/wireless/iwlegacy/iwl-core.h
index 84da79376ef8..d1271fe07d4b 100644
--- a/drivers/net/wireless/iwlegacy/iwl-core.h
+++ b/drivers/net/wireless/iwlegacy/iwl-core.h
@@ -286,7 +286,8 @@ struct iwl_cfg {
***************************/
struct ieee80211_hw *iwl_legacy_alloc_all(struct iwl_cfg *cfg);
-int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
+int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params);
int iwl_legacy_mac_tx_last_beacon(struct ieee80211_hw *hw);
void iwl_legacy_set_rxon_hwcrypto(struct iwl_priv *priv,
@@ -620,7 +621,8 @@ static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
/* mac80211 handlers */
int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed);
-void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw);
+void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif);
void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
diff --git a/drivers/net/wireless/iwlegacy/iwl-hcmd.c b/drivers/net/wireless/iwlegacy/iwl-hcmd.c
index 62b4b09122cb..ce1fc9feb61f 100644
--- a/drivers/net/wireless/iwlegacy/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlegacy/iwl-hcmd.c
@@ -167,7 +167,7 @@ int iwl_legacy_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
goto out;
}
- ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+ ret = wait_event_timeout(priv->wait_command_queue,
!test_bit(STATUS_HCMD_ACTIVE, &priv->status),
HOST_COMPLETE_TIMEOUT);
if (!ret) {
diff --git a/drivers/net/wireless/iwlegacy/iwl-led.c b/drivers/net/wireless/iwlegacy/iwl-led.c
index bda0d61b2c0d..dc568a474c5d 100644
--- a/drivers/net/wireless/iwlegacy/iwl-led.c
+++ b/drivers/net/wireless/iwlegacy/iwl-led.c
@@ -33,7 +33,6 @@
#include <linux/delay.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
-#include <linux/wireless.h>
#include <net/mac80211.h>
#include <linux/etherdevice.h>
#include <asm/unaligned.h>
diff --git a/drivers/net/wireless/iwlegacy/iwl-tx.c b/drivers/net/wireless/iwlegacy/iwl-tx.c
index 4fff995c6f3e..ef9e268bf8a0 100644
--- a/drivers/net/wireless/iwlegacy/iwl-tx.c
+++ b/drivers/net/wireless/iwlegacy/iwl-tx.c
@@ -625,6 +625,8 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
cmd = txq->cmd[cmd_index];
meta = &txq->meta[cmd_index];
+ txq->time_stamp = jiffies;
+
pci_unmap_single(priv->pci_dev,
dma_unmap_addr(meta, mapping),
dma_unmap_len(meta, len),
@@ -645,7 +647,7 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s\n",
iwl_legacy_get_cmd_string(cmd->hdr.cmd));
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
}
/* Mark as unmapped */
diff --git a/drivers/net/wireless/iwlegacy/iwl3945-base.c b/drivers/net/wireless/iwlegacy/iwl3945-base.c
index 795826a014ed..b282d869a546 100644
--- a/drivers/net/wireless/iwlegacy/iwl3945-base.c
+++ b/drivers/net/wireless/iwlegacy/iwl3945-base.c
@@ -40,7 +40,6 @@
#include <linux/sched.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
-#include <linux/wireless.h>
#include <linux/firmware.h>
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
@@ -841,7 +840,7 @@ static void iwl3945_rx_card_state_notif(struct iwl_priv *priv,
wiphy_rfkill_set_hw_state(priv->hw->wiphy,
test_bit(STATUS_RF_KILL_HW, &priv->status));
else
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
}
/**
@@ -2269,7 +2268,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
iwl3945_reg_txpower_periodic(priv);
IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
return;
@@ -2300,7 +2299,7 @@ static void __iwl3945_down(struct iwl_priv *priv)
iwl_legacy_clear_driver_stations(priv);
/* Unblock any waiting calls */
- wake_up_interruptible_all(&priv->wait_command_queue);
+ wake_up_all(&priv->wait_command_queue);
/* Wipe out the EXIT_PENDING status bit if we are not actually
* exiting the module */
@@ -2853,7 +2852,7 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw)
/* Wait for START_ALIVE from ucode. Otherwise callbacks from
* mac80211 will not be run successfully. */
- ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+ ret = wait_event_timeout(priv->wait_command_queue,
test_bit(STATUS_READY, &priv->status),
UCODE_READY_TIMEOUT);
if (!ret) {
diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c
index 14334668034e..d2fba9eae153 100644
--- a/drivers/net/wireless/iwlegacy/iwl4965-base.c
+++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c
@@ -40,7 +40,6 @@
#include <linux/sched.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
-#include <linux/wireless.h>
#include <linux/firmware.h>
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
@@ -576,7 +575,7 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv,
wiphy_rfkill_set_hw_state(priv->hw->wiphy,
test_bit(STATUS_RF_KILL_HW, &priv->status));
else
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
}
/**
@@ -926,7 +925,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
handled |= CSR_INT_BIT_FH_TX;
/* Wake up uCode load routine, now that load is complete */
priv->ucode_write_complete = 1;
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
}
if (inta & ~handled) {
@@ -1795,7 +1794,7 @@ static void iwl4965_alive_start(struct iwl_priv *priv)
iwl4965_rf_kill_ct_config(priv);
IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->wait_command_queue);
iwl_legacy_power_update_mode(priv, true);
IWL_DEBUG_INFO(priv, "Updated power mode\n");
@@ -1828,7 +1827,7 @@ static void __iwl4965_down(struct iwl_priv *priv)
iwl_legacy_clear_driver_stations(priv);
/* Unblock any waiting calls */
- wake_up_interruptible_all(&priv->wait_command_queue);
+ wake_up_all(&priv->wait_command_queue);
/* Wipe out the EXIT_PENDING status bit if we are not actually
* exiting the module */
@@ -2266,7 +2265,7 @@ int iwl4965_mac_start(struct ieee80211_hw *hw)
/* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from
* mac80211 will not be run successfully. */
- ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+ ret = wait_event_timeout(priv->wait_command_queue,
test_bit(STATUS_READY, &priv->status),
UCODE_READY_TIMEOUT);
if (!ret) {
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index ad3bdba6beed..57703d5209d7 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -1,5 +1,5 @@
-config IWLAGN
- tristate "Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlagn) "
+config IWLWIFI
+ tristate "Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlwifi) "
depends on PCI && MAC80211
select FW_LOADER
select NEW_LEDS
@@ -39,14 +39,14 @@ config IWLAGN
If you want to compile the driver as a module ( = code which can be
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 iwlagn.
+ module will be called iwlwifi.
menu "Debugging Options"
- depends on IWLAGN
+ depends on IWLWIFI
config IWLWIFI_DEBUG
- bool "Enable full debugging output in the iwlagn driver"
- depends on IWLAGN
+ bool "Enable full debugging output in the iwlwifi driver"
+ depends on IWLWIFI
---help---
This option will enable debug tracing output for the iwlwifi drivers
@@ -54,13 +54,13 @@ config IWLWIFI_DEBUG
control which debug output is sent to the kernel log by setting the
value in
- /sys/class/net/wlan0/device/debug_level
+ /sys/module/iwlwifi/parameters/debug
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
+ % echo 0x43fff > /sys/module/iwlwifi/parameters/debug
You can find the list of debug mask values in:
drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -70,8 +70,8 @@ config IWLWIFI_DEBUG
any problems you may encounter.
config IWLWIFI_DEBUGFS
- bool "iwlagn debugfs support"
- depends on IWLAGN && MAC80211_DEBUGFS
+ bool "iwlwifi debugfs support"
+ depends on IWLWIFI && MAC80211_DEBUGFS
---help---
Enable creation of debugfs files for the iwlwifi drivers. This
is a low-impact option that allows getting insight into the
@@ -79,13 +79,13 @@ config IWLWIFI_DEBUGFS
config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE
bool "Experimental uCode support"
- depends on IWLAGN && IWLWIFI_DEBUG
+ depends on IWLWIFI && IWLWIFI_DEBUG
---help---
Enable use of experimental ucode for testing and debugging.
config IWLWIFI_DEVICE_TRACING
bool "iwlwifi device access tracing"
- depends on IWLAGN
+ depends on IWLWIFI
depends on EVENT_TRACING
help
Say Y here to trace all commands, including TX frames and IO
@@ -104,27 +104,10 @@ endmenu
config IWLWIFI_DEVICE_SVTOOL
bool "iwlwifi device svtool support"
- depends on IWLAGN
+ depends on IWLWIFI
select NL80211_TESTMODE
help
This option enables the svtool support for iwlwifi device through
NL80211_TESTMODE. svtool is a software validation tool that runs in
the user space and interacts with the device in the kernel space
through the generic netlink message via NL80211_TESTMODE channel.
-
-config IWL_P2P
- bool "iwlwifi experimental P2P support"
- depends on IWLAGN
- help
- This option enables experimental P2P support for some devices
- based on microcode support. Since P2P support is still under
- development, this option may even enable it for some devices
- now that turn out to not support it in the future due to
- microcode restrictions.
-
- To determine if your microcode supports the experimental P2P
- offered by this option, check if the driver advertises AP
- support when it is loaded.
-
- Say Y only if you want to experiment with P2P.
-
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 48ab9142af38..c73e5ed8db5e 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -1,24 +1,24 @@
-# AGN
-obj-$(CONFIG_IWLAGN) += iwlagn.o
-iwlagn-objs := iwl-agn.o iwl-agn-rs.o
-iwlagn-objs += iwl-agn-ucode.o iwl-agn-tx.o
-iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o
-iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o
+# WIFI
+obj-$(CONFIG_IWLWIFI) += iwlwifi.o
+iwlwifi-objs := iwl-agn.o iwl-agn-rs.o
+iwlwifi-objs += iwl-agn-ucode.o iwl-agn-tx.o
+iwlwifi-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o
+iwlwifi-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-rx.o
-iwlagn-objs += iwl-core.o iwl-eeprom.o iwl-power.o
-iwlagn-objs += iwl-rx.o iwl-sta.o
-iwlagn-objs += iwl-scan.o iwl-led.o
-iwlagn-objs += iwl-agn-rxon.o
-iwlagn-objs += iwl-5000.o
-iwlagn-objs += iwl-6000.o
-iwlagn-objs += iwl-1000.o
-iwlagn-objs += iwl-2000.o
-iwlagn-objs += iwl-pci.o
-iwlagn-objs += iwl-trans.o iwl-trans-rx-pcie.o iwl-trans-tx-pcie.o
+iwlwifi-objs += iwl-core.o iwl-eeprom.o iwl-power.o
+iwlwifi-objs += iwl-scan.o iwl-led.o
+iwlwifi-objs += iwl-agn-rxon.o
+iwlwifi-objs += iwl-5000.o
+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-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o
-iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
-iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
-iwlagn-$(CONFIG_IWLWIFI_DEVICE_SVTOOL) += iwl-sv-open.o
+iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
+iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
+iwlwifi-$(CONFIG_IWLWIFI_DEVICE_SVTOOL) += iwl-sv-open.o
CFLAGS_iwl-devtrace.o := -I$(src)
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 01b49eb8c8ec..e12b48c2cff6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -30,7 +30,6 @@
#include <linux/delay.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
-#include <linux/wireless.h>
#include <net/mac80211.h>
#include <linux/etherdevice.h>
#include <asm/unaligned.h>
@@ -40,14 +39,18 @@
#include "iwl-dev.h"
#include "iwl-core.h"
#include "iwl-io.h"
-#include "iwl-sta.h"
#include "iwl-agn.h"
-#include "iwl-helpers.h"
#include "iwl-agn-hw.h"
+#include "iwl-shared.h"
+#include "iwl-cfg.h"
/* Highest firmware API version supported */
-#define IWL1000_UCODE_API_MAX 5
-#define IWL100_UCODE_API_MAX 5
+#define IWL1000_UCODE_API_MAX 6
+#define IWL100_UCODE_API_MAX 6
+
+/* Oldest version we won't warn about */
+#define IWL1000_UCODE_API_OK 5
+#define IWL100_UCODE_API_OK 5
/* Lowest firmware API version supported */
#define IWL1000_UCODE_API_MIN 1
@@ -73,21 +76,21 @@
static void iwl1000_set_ct_threshold(struct iwl_priv *priv)
{
/* want Celsius */
- priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
- priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
+ hw_params(priv).ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
+ hw_params(priv).ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
}
/* NIC configuration for 1000 series */
static void iwl1000_nic_config(struct iwl_priv *priv)
{
/* set CSR_HW_CONFIG_REG for uCode use */
- iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ iwl_set_bit(bus(priv), CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
/* Setting digital SVR for 1000 card to 1.32V */
/* locking is acquired in iwl_set_bits_mask_prph() function */
- iwl_set_bits_mask_prph(priv, APMG_DIGITAL_SVR_REG,
+ iwl_set_bits_mask_prph(bus(priv), APMG_DIGITAL_SVR_REG,
APMG_SVR_DIGITAL_VOLTAGE_1_32,
~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
}
@@ -124,44 +127,36 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
priv->cfg->base_params->num_of_queues =
iwlagn_mod_params.num_of_queues;
- priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
- priv->hw_params.scd_bc_tbls_size =
- priv->cfg->base_params->num_of_queues *
- sizeof(struct iwlagn_scd_bc_tbl);
- priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
- priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
+ hw_params(priv).max_txq_num = priv->cfg->base_params->num_of_queues;
priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
- priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
- priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
+ hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE;
+ hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE;
- priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
- BIT(IEEE80211_BAND_5GHZ);
+ hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ);
- priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
+ hw_params(priv).tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
if (priv->cfg->rx_with_siso_diversity)
- priv->hw_params.rx_chains_num = 1;
+ hw_params(priv).rx_chains_num = 1;
else
- priv->hw_params.rx_chains_num =
+ hw_params(priv).rx_chains_num =
num_of_ant(priv->cfg->valid_rx_ant);
- priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
- priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
+ hw_params(priv).valid_tx_ant = priv->cfg->valid_tx_ant;
+ hw_params(priv).valid_rx_ant = priv->cfg->valid_rx_ant;
iwl1000_set_ct_threshold(priv);
/* Set initial sensitivity parameters */
/* Set initial calibration set */
- priv->hw_params.sens = &iwl1000_sensitivity;
- priv->hw_params.calib_init_cfg =
+ hw_params(priv).sens = &iwl1000_sensitivity;
+ hw_params(priv).calib_init_cfg =
BIT(IWL_CALIB_XTAL) |
BIT(IWL_CALIB_LO) |
BIT(IWL_CALIB_TX_IQ) |
BIT(IWL_CALIB_TX_IQ_PERD) |
BIT(IWL_CALIB_BASE_BAND);
if (priv->cfg->need_dc_calib)
- priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_DC);
-
- priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
+ hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_DC);
return 0;
}
@@ -191,7 +186,6 @@ static struct iwl_base_params iwl1000_base_params = {
.max_ll_items = OTP_MAX_LL_ITEMS_1000,
.shadow_ram_support = false,
.led_compensation = 51,
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
.chain_noise_scale = 1000,
@@ -201,12 +195,13 @@ static struct iwl_base_params iwl1000_base_params = {
static struct iwl_ht_params iwl1000_ht_params = {
.ht_greenfield_support = true,
.use_rts_for_aggregation = true, /* use rts/cts protection */
- .smps_mode = IEEE80211_SMPS_STATIC,
+ .smps_mode = IEEE80211_SMPS_DYNAMIC,
};
#define IWL_DEVICE_1000 \
.fw_name_pre = IWL1000_FW_PRE, \
.ucode_api_max = IWL1000_UCODE_API_MAX, \
+ .ucode_api_ok = IWL1000_UCODE_API_OK, \
.ucode_api_min = IWL1000_UCODE_API_MIN, \
.eeprom_ver = EEPROM_1000_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \
@@ -228,6 +223,7 @@ struct iwl_cfg iwl1000_bg_cfg = {
#define IWL_DEVICE_100 \
.fw_name_pre = IWL100_FW_PRE, \
.ucode_api_max = IWL100_UCODE_API_MAX, \
+ .ucode_api_ok = IWL100_UCODE_API_OK, \
.ucode_api_min = IWL100_UCODE_API_MIN, \
.eeprom_ver = EEPROM_1000_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \
diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c
index 0e13f0bb2e17..79431977a968 100644
--- a/drivers/net/wireless/iwlwifi/iwl-2000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-2000.c
@@ -30,7 +30,6 @@
#include <linux/delay.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
-#include <linux/wireless.h>
#include <net/mac80211.h>
#include <linux/etherdevice.h>
#include <asm/unaligned.h>
@@ -40,17 +39,22 @@
#include "iwl-dev.h"
#include "iwl-core.h"
#include "iwl-io.h"
-#include "iwl-sta.h"
#include "iwl-agn.h"
-#include "iwl-helpers.h"
#include "iwl-agn-hw.h"
-#include "iwl-6000-hw.h"
+#include "iwl-shared.h"
+#include "iwl-cfg.h"
/* Highest firmware API version supported */
-#define IWL2030_UCODE_API_MAX 5
-#define IWL2000_UCODE_API_MAX 5
-#define IWL105_UCODE_API_MAX 5
-#define IWL135_UCODE_API_MAX 5
+#define IWL2030_UCODE_API_MAX 6
+#define IWL2000_UCODE_API_MAX 6
+#define IWL105_UCODE_API_MAX 6
+#define IWL135_UCODE_API_MAX 6
+
+/* Oldest version we won't warn about */
+#define IWL2030_UCODE_API_OK 5
+#define IWL2000_UCODE_API_OK 5
+#define IWL105_UCODE_API_OK 5
+#define IWL135_UCODE_API_OK 5
/* Lowest firmware API version supported */
#define IWL2030_UCODE_API_MIN 5
@@ -68,13 +72,13 @@
#define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE __stringify(api) ".ucode"
#define IWL135_FW_PRE "iwlwifi-135-"
-#define IWL135_MODULE_FIRMWARE(api) IWL135_FW_PRE #api ".ucode"
+#define IWL135_MODULE_FIRMWARE(api) IWL135_FW_PRE __stringify(api) ".ucode"
static void iwl2000_set_ct_threshold(struct iwl_priv *priv)
{
/* want Celsius */
- priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
- priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
+ hw_params(priv).ct_kill_threshold = CT_KILL_THRESHOLD;
+ hw_params(priv).ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
}
/* NIC configuration for 2000 series */
@@ -83,7 +87,7 @@ static void iwl2000_nic_config(struct iwl_priv *priv)
iwl_rf_config(priv);
if (priv->cfg->iq_invert)
- iwl_set_bit(priv, CSR_GP_DRIVER_REG,
+ iwl_set_bit(bus(priv), CSR_GP_DRIVER_REG,
CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER);
}
@@ -119,45 +123,37 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv)
priv->cfg->base_params->num_of_queues =
iwlagn_mod_params.num_of_queues;
- priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
- priv->hw_params.scd_bc_tbls_size =
- priv->cfg->base_params->num_of_queues *
- sizeof(struct iwlagn_scd_bc_tbl);
- priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
- priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
+ hw_params(priv).max_txq_num = priv->cfg->base_params->num_of_queues;
priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
- priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE;
- priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE;
+ hw_params(priv).max_data_size = IWL60_RTC_DATA_SIZE;
+ hw_params(priv).max_inst_size = IWL60_RTC_INST_SIZE;
- priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
- BIT(IEEE80211_BAND_5GHZ);
+ hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ);
- priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
+ hw_params(priv).tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
if (priv->cfg->rx_with_siso_diversity)
- priv->hw_params.rx_chains_num = 1;
+ hw_params(priv).rx_chains_num = 1;
else
- priv->hw_params.rx_chains_num =
+ hw_params(priv).rx_chains_num =
num_of_ant(priv->cfg->valid_rx_ant);
- priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
- priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
+ hw_params(priv).valid_tx_ant = priv->cfg->valid_tx_ant;
+ hw_params(priv).valid_rx_ant = priv->cfg->valid_rx_ant;
iwl2000_set_ct_threshold(priv);
/* Set initial sensitivity parameters */
/* Set initial calibration set */
- priv->hw_params.sens = &iwl2000_sensitivity;
- priv->hw_params.calib_init_cfg =
+ hw_params(priv).sens = &iwl2000_sensitivity;
+ hw_params(priv).calib_init_cfg =
BIT(IWL_CALIB_XTAL) |
BIT(IWL_CALIB_LO) |
BIT(IWL_CALIB_TX_IQ) |
BIT(IWL_CALIB_BASE_BAND);
if (priv->cfg->need_dc_calib)
- priv->hw_params.calib_rt_cfg |= IWL_CALIB_CFG_DC_IDX;
+ hw_params(priv).calib_rt_cfg |= IWL_CALIB_CFG_DC_IDX;
if (priv->cfg->need_temp_offset_calib)
- priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_TEMP_OFFSET);
-
- priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
+ hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_TEMP_OFFSET);
return 0;
}
@@ -175,7 +171,7 @@ static struct iwl_lib_ops iwl2000_lib = {
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
EEPROM_REGULATORY_BAND_NO_HT40,
},
- .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
+ .update_enhanced_txpower = iwl_eeprom_enhanced_txpower,
},
.temperature = iwlagn_temperature,
};
@@ -196,7 +192,7 @@ static struct iwl_lib_ops iwl2030_lib = {
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
EEPROM_REGULATORY_BAND_NO_HT40,
},
- .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
+ .update_enhanced_txpower = iwl_eeprom_enhanced_txpower,
},
.temperature = iwlagn_temperature,
};
@@ -209,7 +205,6 @@ static struct iwl_base_params iwl2000_base_params = {
.max_ll_items = OTP_MAX_LL_ITEMS_2x00,
.shadow_ram_support = true,
.led_compensation = 51,
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
@@ -217,6 +212,7 @@ static struct iwl_base_params iwl2000_base_params = {
.wd_timeout = IWL_DEF_WD_TIMEOUT,
.max_event_log_size = 512,
.shadow_reg_enable = true,
+ .hd_v2 = true,
};
@@ -228,7 +224,6 @@ static struct iwl_base_params iwl2030_base_params = {
.max_ll_items = OTP_MAX_LL_ITEMS_2x00,
.shadow_ram_support = true,
.led_compensation = 57,
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
@@ -236,6 +231,7 @@ static struct iwl_base_params iwl2030_base_params = {
.wd_timeout = IWL_LONG_WD_TIMEOUT,
.max_event_log_size = 512,
.shadow_reg_enable = true,
+ .hd_v2 = true,
};
static struct iwl_ht_params iwl2000_ht_params = {
@@ -256,6 +252,7 @@ static struct iwl_bt_params iwl2030_bt_params = {
#define IWL_DEVICE_2000 \
.fw_name_pre = IWL2000_FW_PRE, \
.ucode_api_max = IWL2000_UCODE_API_MAX, \
+ .ucode_api_ok = IWL2000_UCODE_API_OK, \
.ucode_api_min = IWL2000_UCODE_API_MIN, \
.eeprom_ver = EEPROM_2000_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
@@ -263,6 +260,7 @@ static struct iwl_bt_params iwl2030_bt_params = {
.base_params = &iwl2000_base_params, \
.need_dc_calib = true, \
.need_temp_offset_calib = true, \
+ .temp_offset_v2 = true, \
.led_mode = IWL_LED_RF_STATE, \
.iq_invert = true \
@@ -277,9 +275,16 @@ struct iwl_cfg iwl2000_2bg_cfg = {
IWL_DEVICE_2000,
};
+struct iwl_cfg iwl2000_2bgn_d_cfg = {
+ .name = "2000D Series 2x2 BGN",
+ IWL_DEVICE_2000,
+ .ht_params = &iwl2000_ht_params,
+};
+
#define IWL_DEVICE_2030 \
.fw_name_pre = IWL2030_FW_PRE, \
.ucode_api_max = IWL2030_UCODE_API_MAX, \
+ .ucode_api_ok = IWL2030_UCODE_API_OK, \
.ucode_api_min = IWL2030_UCODE_API_MIN, \
.eeprom_ver = EEPROM_2000_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
@@ -288,6 +293,7 @@ struct iwl_cfg iwl2000_2bg_cfg = {
.bt_params = &iwl2030_bt_params, \
.need_dc_calib = true, \
.need_temp_offset_calib = true, \
+ .temp_offset_v2 = true, \
.led_mode = IWL_LED_RF_STATE, \
.adv_pm = true, \
.iq_invert = true \
@@ -306,6 +312,7 @@ struct iwl_cfg iwl2030_2bg_cfg = {
#define IWL_DEVICE_105 \
.fw_name_pre = IWL105_FW_PRE, \
.ucode_api_max = IWL105_UCODE_API_MAX, \
+ .ucode_api_ok = IWL105_UCODE_API_OK, \
.ucode_api_min = IWL105_UCODE_API_MIN, \
.eeprom_ver = EEPROM_2000_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
@@ -313,6 +320,7 @@ struct iwl_cfg iwl2030_2bg_cfg = {
.base_params = &iwl2000_base_params, \
.need_dc_calib = true, \
.need_temp_offset_calib = true, \
+ .temp_offset_v2 = true, \
.led_mode = IWL_LED_RF_STATE, \
.adv_pm = true, \
.rx_with_siso_diversity = true, \
@@ -329,9 +337,16 @@ struct iwl_cfg iwl105_bgn_cfg = {
.ht_params = &iwl2000_ht_params,
};
+struct iwl_cfg iwl105_bgn_d_cfg = {
+ .name = "105D Series 1x1 BGN",
+ IWL_DEVICE_105,
+ .ht_params = &iwl2000_ht_params,
+};
+
#define IWL_DEVICE_135 \
.fw_name_pre = IWL135_FW_PRE, \
.ucode_api_max = IWL135_UCODE_API_MAX, \
+ .ucode_api_ok = IWL135_UCODE_API_OK, \
.ucode_api_min = IWL135_UCODE_API_MIN, \
.eeprom_ver = EEPROM_2000_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
@@ -340,6 +355,7 @@ struct iwl_cfg iwl105_bgn_cfg = {
.bt_params = &iwl2030_bt_params, \
.need_dc_calib = true, \
.need_temp_offset_calib = true, \
+ .temp_offset_v2 = true, \
.led_mode = IWL_LED_RF_STATE, \
.adv_pm = true, \
.rx_with_siso_diversity = true, \
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
deleted file mode 100644
index f9630a3c79fe..000000000000
--- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
+++ /dev/null
@@ -1,88 +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 - 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.
- *
- *****************************************************************************/
-/*
- * Please use this file (iwl-5000-hw.h) only for hardware-related definitions.
- * Use iwl-commands.h for uCode API definitions.
- */
-
-#ifndef __iwl_5000_hw_h__
-#define __iwl_5000_hw_h__
-
-/* 5150 only */
-#define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF (-5)
-
-static inline s32 iwl_temp_calib_to_offset(struct iwl_priv *priv)
-{
- u16 temperature, voltage;
- __le16 *temp_calib =
- (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_TEMPERATURE);
-
- temperature = le16_to_cpu(temp_calib[0]);
- voltage = le16_to_cpu(temp_calib[1]);
-
- /* offset = temp - volt / coeff */
- return (s32)(temperature - voltage / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF);
-}
-
-#endif /* __iwl_5000_hw_h__ */
-
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index c95cefd529dc..c511c98a89a8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -31,7 +31,6 @@
#include <linux/sched.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
-#include <linux/wireless.h>
#include <net/mac80211.h>
#include <linux/etherdevice.h>
#include <asm/unaligned.h>
@@ -41,12 +40,11 @@
#include "iwl-dev.h"
#include "iwl-core.h"
#include "iwl-io.h"
-#include "iwl-sta.h"
-#include "iwl-helpers.h"
#include "iwl-agn.h"
#include "iwl-agn-hw.h"
-#include "iwl-5000-hw.h"
#include "iwl-trans.h"
+#include "iwl-shared.h"
+#include "iwl-cfg.h"
/* Highest firmware API version supported */
#define IWL5000_UCODE_API_MAX 5
@@ -69,27 +67,27 @@ static void iwl5000_nic_config(struct iwl_priv *priv)
iwl_rf_config(priv);
- spin_lock_irqsave(&priv->lock, flags);
+ 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.
*/
- iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
+ iwl_set_bits_mask_prph(bus(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->lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->lock, flags);
}
static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
- .min_nrg_cck = 95,
+ .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 = 120,
- .auto_corr_min_ofdm_mrc_x1 = 240,
+ .auto_corr_min_ofdm_x1 = 105,
+ .auto_corr_min_ofdm_mrc_x1 = 220,
.auto_corr_max_ofdm = 120,
.auto_corr_max_ofdm_mrc = 210,
@@ -98,10 +96,10 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
.auto_corr_min_cck = 125,
.auto_corr_max_cck = 200,
- .auto_corr_min_cck_mrc = 170,
+ .auto_corr_min_cck_mrc = 200,
.auto_corr_max_cck_mrc = 400,
- .nrg_th_cck = 95,
- .nrg_th_ofdm = 95,
+ .nrg_th_cck = 100,
+ .nrg_th_ofdm = 100,
.barker_corr_th_min = 190,
.barker_corr_th_min_mrc = 390,
@@ -134,19 +132,34 @@ static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
.nrg_th_cca = 62,
};
+#define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF (-5)
+
+static s32 iwl_temp_calib_to_offset(struct iwl_priv *priv)
+{
+ u16 temperature, voltage;
+ __le16 *temp_calib = (__le16 *)iwl_eeprom_query_addr(priv,
+ EEPROM_KELVIN_TEMPERATURE);
+
+ temperature = le16_to_cpu(temp_calib[0]);
+ voltage = le16_to_cpu(temp_calib[1]);
+
+ /* offset = temp - volt / coeff */
+ return (s32)(temperature - voltage / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF);
+}
+
static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
{
const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF;
s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) -
iwl_temp_calib_to_offset(priv);
- priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef;
+ hw_params(priv).ct_kill_threshold = threshold * volt2temp_coef;
}
static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
{
/* want Celsius */
- priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
+ hw_params(priv).ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
}
static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
@@ -156,39 +169,32 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
priv->cfg->base_params->num_of_queues =
iwlagn_mod_params.num_of_queues;
- priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
- priv->hw_params.scd_bc_tbls_size =
- priv->cfg->base_params->num_of_queues *
- sizeof(struct iwlagn_scd_bc_tbl);
- priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
- priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
+ hw_params(priv).max_txq_num = priv->cfg->base_params->num_of_queues;
priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
- priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
- priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
+ hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE;
+ hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE;
- priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
+ hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
BIT(IEEE80211_BAND_5GHZ);
- priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
- priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
- priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
- priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
+ hw_params(priv).tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
+ hw_params(priv).rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
+ hw_params(priv).valid_tx_ant = priv->cfg->valid_tx_ant;
+ hw_params(priv).valid_rx_ant = priv->cfg->valid_rx_ant;
iwl5000_set_ct_threshold(priv);
/* Set initial sensitivity parameters */
/* Set initial calibration set */
- priv->hw_params.sens = &iwl5000_sensitivity;
- priv->hw_params.calib_init_cfg =
+ hw_params(priv).sens = &iwl5000_sensitivity;
+ hw_params(priv).calib_init_cfg =
BIT(IWL_CALIB_XTAL) |
BIT(IWL_CALIB_LO) |
BIT(IWL_CALIB_TX_IQ) |
BIT(IWL_CALIB_TX_IQ_PERD) |
BIT(IWL_CALIB_BASE_BAND);
- priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
-
return 0;
}
@@ -199,38 +205,31 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv)
priv->cfg->base_params->num_of_queues =
iwlagn_mod_params.num_of_queues;
- priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
- priv->hw_params.scd_bc_tbls_size =
- priv->cfg->base_params->num_of_queues *
- sizeof(struct iwlagn_scd_bc_tbl);
- priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
- priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
+ hw_params(priv).max_txq_num = priv->cfg->base_params->num_of_queues;
priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
- priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
- priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
+ hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE;
+ hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE;
- priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
+ hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
BIT(IEEE80211_BAND_5GHZ);
- priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
- priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
- priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
- priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
+ hw_params(priv).tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
+ hw_params(priv).rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
+ hw_params(priv).valid_tx_ant = priv->cfg->valid_tx_ant;
+ hw_params(priv).valid_rx_ant = priv->cfg->valid_rx_ant;
iwl5150_set_ct_threshold(priv);
/* Set initial sensitivity parameters */
/* Set initial calibration set */
- priv->hw_params.sens = &iwl5150_sensitivity;
- priv->hw_params.calib_init_cfg =
+ hw_params(priv).sens = &iwl5150_sensitivity;
+ hw_params(priv).calib_init_cfg =
BIT(IWL_CALIB_LO) |
BIT(IWL_CALIB_TX_IQ) |
BIT(IWL_CALIB_BASE_BAND);
if (priv->cfg->need_dc_calib)
- priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_DC);
-
- priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
+ hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_DC);
return 0;
}
@@ -252,7 +251,7 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
{
/*
* MULTI-FIXME
- * See iwl_mac_channel_switch.
+ * See iwlagn_mac_channel_switch.
*/
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
struct iwl5000_channel_switch_cmd cmd;
@@ -315,7 +314,7 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
return -EFAULT;
}
- return trans_send_cmd(&priv->trans, &hcmd);
+ return iwl_trans_send_cmd(trans(priv), &hcmd);
}
static struct iwl_lib_ops iwl5000_lib = {
@@ -360,7 +359,6 @@ static struct iwl_base_params iwl5000_base_params = {
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
.led_compensation = 51,
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
.chain_noise_scale = 1000,
.wd_timeout = IWL_LONG_WD_TIMEOUT,
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 973d1972e8cc..c840c78278db 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -30,7 +30,6 @@
#include <linux/delay.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
-#include <linux/wireless.h>
#include <net/mac80211.h>
#include <linux/etherdevice.h>
#include <asm/unaligned.h>
@@ -40,17 +39,19 @@
#include "iwl-dev.h"
#include "iwl-core.h"
#include "iwl-io.h"
-#include "iwl-sta.h"
#include "iwl-agn.h"
-#include "iwl-helpers.h"
#include "iwl-agn-hw.h"
-#include "iwl-6000-hw.h"
#include "iwl-trans.h"
+#include "iwl-shared.h"
+#include "iwl-cfg.h"
/* Highest firmware API version supported */
#define IWL6000_UCODE_API_MAX 4
#define IWL6050_UCODE_API_MAX 5
-#define IWL6000G2_UCODE_API_MAX 5
+#define IWL6000G2_UCODE_API_MAX 6
+
+/* Oldest version we won't warn about */
+#define IWL6000G2_UCODE_API_OK 5
/* Lowest firmware API version supported */
#define IWL6000_UCODE_API_MIN 4
@@ -72,15 +73,15 @@
static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
{
/* want Celsius */
- priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
- priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
+ hw_params(priv).ct_kill_threshold = CT_KILL_THRESHOLD;
+ hw_params(priv).ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
}
static void iwl6050_additional_nic_config(struct iwl_priv *priv)
{
/* Indicate calibration version to uCode. */
if (iwlagn_eeprom_calib_version(priv) >= 6)
- iwl_set_bit(priv, CSR_GP_DRIVER_REG,
+ iwl_set_bit(bus(priv), CSR_GP_DRIVER_REG,
CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
}
@@ -88,9 +89,9 @@ static void iwl6150_additional_nic_config(struct iwl_priv *priv)
{
/* Indicate calibration version to uCode. */
if (iwlagn_eeprom_calib_version(priv) >= 6)
- iwl_set_bit(priv, CSR_GP_DRIVER_REG,
+ iwl_set_bit(bus(priv), CSR_GP_DRIVER_REG,
CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
- iwl_set_bit(priv, CSR_GP_DRIVER_REG,
+ iwl_set_bit(bus(priv), CSR_GP_DRIVER_REG,
CSR_GP_DRIVER_REG_BIT_6050_1x2);
}
@@ -102,7 +103,7 @@ static void iwl6000_nic_config(struct iwl_priv *priv)
/* no locking required for register write */
if (priv->cfg->pa_type == IWL_PA_INTERNAL) {
/* 2x2 IPA phy type */
- iwl_write32(priv, CSR_GP_DRIVER_REG,
+ iwl_write32(bus(priv), CSR_GP_DRIVER_REG,
CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA);
}
/* do additional nic configuration if needed */
@@ -111,7 +112,7 @@ static void iwl6000_nic_config(struct iwl_priv *priv)
}
static struct iwl_sensitivity_ranges iwl6000_sensitivity = {
- .min_nrg_cck = 97,
+ .min_nrg_cck = 110,
.max_nrg_cck = 0, /* not used, set to 0 */
.auto_corr_min_ofdm = 80,
.auto_corr_min_ofdm_mrc = 128,
@@ -127,11 +128,11 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = {
.auto_corr_max_cck = 175,
.auto_corr_min_cck_mrc = 160,
.auto_corr_max_cck_mrc = 310,
- .nrg_th_cck = 97,
- .nrg_th_ofdm = 100,
+ .nrg_th_cck = 110,
+ .nrg_th_ofdm = 110,
.barker_corr_th_min = 190,
- .barker_corr_th_min_mrc = 390,
+ .barker_corr_th_min_mrc = 336,
.nrg_th_cca = 62,
};
@@ -142,45 +143,38 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
priv->cfg->base_params->num_of_queues =
iwlagn_mod_params.num_of_queues;
- priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
- priv->hw_params.scd_bc_tbls_size =
- priv->cfg->base_params->num_of_queues *
- sizeof(struct iwlagn_scd_bc_tbl);
- priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
- priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
+ hw_params(priv).max_txq_num = priv->cfg->base_params->num_of_queues;
priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
- priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE;
- priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE;
+ hw_params(priv).max_data_size = IWL60_RTC_DATA_SIZE;
+ hw_params(priv).max_inst_size = IWL60_RTC_INST_SIZE;
- priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
+ hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
BIT(IEEE80211_BAND_5GHZ);
- priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
+ hw_params(priv).tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
if (priv->cfg->rx_with_siso_diversity)
- priv->hw_params.rx_chains_num = 1;
+ hw_params(priv).rx_chains_num = 1;
else
- priv->hw_params.rx_chains_num =
+ hw_params(priv).rx_chains_num =
num_of_ant(priv->cfg->valid_rx_ant);
- priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
- priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
+ hw_params(priv).valid_tx_ant = priv->cfg->valid_tx_ant;
+ hw_params(priv).valid_rx_ant = priv->cfg->valid_rx_ant;
iwl6000_set_ct_threshold(priv);
/* Set initial sensitivity parameters */
/* Set initial calibration set */
- priv->hw_params.sens = &iwl6000_sensitivity;
- priv->hw_params.calib_init_cfg =
+ hw_params(priv).sens = &iwl6000_sensitivity;
+ hw_params(priv).calib_init_cfg =
BIT(IWL_CALIB_XTAL) |
BIT(IWL_CALIB_LO) |
BIT(IWL_CALIB_TX_IQ) |
BIT(IWL_CALIB_BASE_BAND);
if (priv->cfg->need_dc_calib)
- priv->hw_params.calib_rt_cfg |= IWL_CALIB_CFG_DC_IDX;
+ hw_params(priv).calib_rt_cfg |= IWL_CALIB_CFG_DC_IDX;
if (priv->cfg->need_temp_offset_calib)
- priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_TEMP_OFFSET);
-
- priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
+ hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_TEMP_OFFSET);
return 0;
}
@@ -190,7 +184,7 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
{
/*
* MULTI-FIXME
- * See iwl_mac_channel_switch.
+ * See iwlagn_mac_channel_switch.
*/
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
struct iwl6000_channel_switch_cmd cmd;
@@ -253,7 +247,7 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
return -EFAULT;
}
- return trans_send_cmd(&priv->trans, &hcmd);
+ return iwl_trans_send_cmd(trans(priv), &hcmd);
}
static struct iwl_lib_ops iwl6000_lib = {
@@ -270,7 +264,7 @@ static struct iwl_lib_ops iwl6000_lib = {
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
EEPROM_REG_BAND_52_HT40_CHANNELS
},
- .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
+ .update_enhanced_txpower = iwl_eeprom_enhanced_txpower,
},
.temperature = iwlagn_temperature,
};
@@ -292,7 +286,7 @@ static struct iwl_lib_ops iwl6030_lib = {
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
EEPROM_REG_BAND_52_HT40_CHANNELS
},
- .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
+ .update_enhanced_txpower = iwl_eeprom_enhanced_txpower,
},
.temperature = iwlagn_temperature,
};
@@ -305,7 +299,6 @@ static struct iwl_base_params iwl6000_base_params = {
.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true,
.led_compensation = 51,
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
@@ -323,7 +316,6 @@ static struct iwl_base_params iwl6050_base_params = {
.max_ll_items = OTP_MAX_LL_ITEMS_6x50,
.shadow_ram_support = true,
.led_compensation = 51,
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
@@ -340,7 +332,6 @@ static struct iwl_base_params iwl6000_g2_base_params = {
.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true,
.led_compensation = 57,
- .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
@@ -365,8 +356,9 @@ static struct iwl_bt_params iwl6000_bt_params = {
};
#define IWL_DEVICE_6005 \
- .fw_name_pre = IWL6005_FW_PRE, \
+ .fw_name_pre = IWL6005_FW_PRE, \
.ucode_api_max = IWL6000G2_UCODE_API_MAX, \
+ .ucode_api_ok = IWL6000G2_UCODE_API_OK, \
.ucode_api_min = IWL6000G2_UCODE_API_MIN, \
.eeprom_ver = EEPROM_6005_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION, \
@@ -392,9 +384,22 @@ struct iwl_cfg iwl6005_2bg_cfg = {
IWL_DEVICE_6005,
};
+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 = {
+ .name = "Intel(R) Centrino(R) Advanced-N 6205D AGN",
+ IWL_DEVICE_6005,
+ .ht_params = &iwl6000_ht_params,
+};
+
#define IWL_DEVICE_6030 \
- .fw_name_pre = IWL6030_FW_PRE, \
+ .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, \
.eeprom_ver = EEPROM_6030_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION, \
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
index 72d6297602b8..03bac48558b2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
@@ -93,12 +93,12 @@ int iwl_send_calib_results(struct iwl_priv *priv)
};
for (i = 0; i < IWL_CALIB_MAX; i++) {
- if ((BIT(i) & priv->hw_params.calib_init_cfg) &&
+ if ((BIT(i) & hw_params(priv).calib_init_cfg) &&
priv->calib_results[i].buf) {
hcmd.len[0] = priv->calib_results[i].buf_len;
hcmd.data[0] = priv->calib_results[i].buf;
hcmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
- ret = trans_send_cmd(&priv->trans, &hcmd);
+ ret = iwl_trans_send_cmd(trans(priv), &hcmd);
if (ret) {
IWL_ERR(priv, "Error %d iteration %d\n",
ret, i);
@@ -174,7 +174,7 @@ static int iwl_sens_energy_cck(struct iwl_priv *priv,
u32 max_false_alarms = MAX_FA_CCK * rx_enable_time;
u32 min_false_alarms = MIN_FA_CCK * rx_enable_time;
struct iwl_sensitivity_data *data = NULL;
- const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
+ const struct iwl_sensitivity_ranges *ranges = hw_params(priv).sens;
data = &(priv->sensitivity_data);
@@ -357,7 +357,7 @@ static int iwl_sens_auto_corr_ofdm(struct iwl_priv *priv,
u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time;
u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time;
struct iwl_sensitivity_data *data = NULL;
- const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
+ const struct iwl_sensitivity_ranges *ranges = hw_params(priv).sens;
data = &(priv->sensitivity_data);
@@ -484,7 +484,7 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)
memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]),
sizeof(u16)*HD_TABLE_SIZE);
- return trans_send_cmd(&priv->trans, &cmd_out);
+ return iwl_trans_send_cmd(trans(priv), &cmd_out);
}
/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
@@ -505,28 +505,53 @@ static int iwl_enhance_sensitivity_write(struct iwl_priv *priv)
iwl_prepare_legacy_sensitivity_tbl(priv, data, &cmd.enhance_table[0]);
- cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] =
- HD_INA_NON_SQUARE_DET_OFDM_DATA;
- cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] =
- HD_INA_NON_SQUARE_DET_CCK_DATA;
- cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] =
- HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA;
- cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
- HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA;
- cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
- HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA;
- cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] =
- HD_OFDM_NON_SQUARE_DET_SLOPE_DATA;
- cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] =
- HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA;
- cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
- HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA;
- cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
- HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA;
- cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] =
- HD_CCK_NON_SQUARE_DET_SLOPE_DATA;
- cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] =
- HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA;
+ if (priv->cfg->base_params->hd_v2) {
+ cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] =
+ HD_INA_NON_SQUARE_DET_OFDM_DATA_V2;
+ cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] =
+ HD_INA_NON_SQUARE_DET_CCK_DATA_V2;
+ cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] =
+ HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V2;
+ cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
+ HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V2;
+ cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
+ HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2;
+ cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] =
+ HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V2;
+ cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] =
+ HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V2;
+ cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
+ HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V2;
+ cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
+ HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2;
+ cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] =
+ HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V2;
+ cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] =
+ HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V2;
+ } else {
+ cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] =
+ HD_INA_NON_SQUARE_DET_OFDM_DATA_V1;
+ cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] =
+ HD_INA_NON_SQUARE_DET_CCK_DATA_V1;
+ cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] =
+ HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V1;
+ cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
+ HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V1;
+ cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
+ HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1;
+ cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] =
+ HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V1;
+ cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] =
+ HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V1;
+ cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
+ HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V1;
+ cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
+ HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1;
+ cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] =
+ HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V1;
+ cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] =
+ HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V1;
+ }
/* Update uCode's "work" table, and copy it to DSP */
cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
@@ -548,7 +573,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 trans_send_cmd(&priv->trans, &cmd_out);
+ return iwl_trans_send_cmd(trans(priv), &cmd_out);
}
void iwl_init_sensitivity(struct iwl_priv *priv)
@@ -556,7 +581,7 @@ void iwl_init_sensitivity(struct iwl_priv *priv)
int ret = 0;
int i;
struct iwl_sensitivity_data *data = NULL;
- const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
+ const struct iwl_sensitivity_ranges *ranges = hw_params(priv).sens;
if (priv->disable_sens_cal)
return;
@@ -633,13 +658,13 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv)
return;
}
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&priv->shrd->lock, flags);
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->lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->lock, flags);
return;
}
@@ -663,7 +688,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->lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->lock, flags);
IWL_DEBUG_CALIB(priv, "rx_enable_time = %u usecs\n", rx_enable_time);
@@ -741,12 +766,9 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
u8 first_chain;
u16 i = 0;
- average_sig[0] = data->chain_signal_a /
- priv->cfg->base_params->chain_noise_num_beacons;
- average_sig[1] = data->chain_signal_b /
- priv->cfg->base_params->chain_noise_num_beacons;
- average_sig[2] = data->chain_signal_c /
- priv->cfg->base_params->chain_noise_num_beacons;
+ average_sig[0] = data->chain_signal_a / IWL_CAL_NUM_BEACONS;
+ average_sig[1] = data->chain_signal_b / IWL_CAL_NUM_BEACONS;
+ average_sig[2] = data->chain_signal_c / IWL_CAL_NUM_BEACONS;
if (average_sig[0] >= average_sig[1]) {
max_average_sig = average_sig[0];
@@ -796,21 +818,21 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
* To be safe, simply mask out any chains that we know
* are not on the device.
*/
- active_chains &= priv->hw_params.valid_rx_ant;
+ active_chains &= hw_params(priv).valid_rx_ant;
num_tx_chains = 0;
for (i = 0; i < NUM_RX_CHAINS; i++) {
/* loops on all the bits of
* priv->hw_setting.valid_tx_ant */
u8 ant_msk = (1 << i);
- if (!(priv->hw_params.valid_tx_ant & ant_msk))
+ if (!(hw_params(priv).valid_tx_ant & ant_msk))
continue;
num_tx_chains++;
if (data->disconn_array[i] == 0)
/* there is a Tx antenna connected */
break;
- if (num_tx_chains == priv->hw_params.tx_chains_num &&
+ if (num_tx_chains == hw_params(priv).tx_chains_num &&
data->disconn_array[i]) {
/*
* If all chains are disconnected
@@ -827,12 +849,13 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
}
}
- if (active_chains != priv->hw_params.valid_rx_ant &&
+ if (active_chains != hw_params(priv).valid_rx_ant &&
active_chains != priv->chain_noise_data.active_chains)
IWL_DEBUG_CALIB(priv,
"Detected that not all antennas are connected! "
"Connected: %#x, valid: %#x.\n",
- active_chains, priv->hw_params.valid_rx_ant);
+ active_chains,
+ hw_params(priv).valid_rx_ant);
/* Save for use within RXON, TX, SCAN commands, etc. */
data->active_chains = active_chains;
@@ -892,7 +915,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];
- trans_send_cmd_pdu(&priv->trans, REPLY_PHY_CALIBRATION_CMD,
+ iwl_trans_send_cmd_pdu(trans(priv), REPLY_PHY_CALIBRATION_CMD,
CMD_ASYNC, sizeof(cmd), &cmd);
data->radio_write = 1;
@@ -950,13 +973,13 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv)
return;
}
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&priv->shrd->lock, flags);
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->lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->lock, flags);
return;
}
@@ -971,7 +994,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->lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->lock, flags);
return;
}
@@ -990,7 +1013,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->lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->lock, flags);
data->beacon_count++;
@@ -1012,8 +1035,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv)
/* If this is the "chain_noise_num_beacons", determine:
* 1) Disconnected antennas (using signal strengths)
* 2) Differential gain (using silence noise) to balance receivers */
- if (data->beacon_count !=
- priv->cfg->base_params->chain_noise_num_beacons)
+ if (data->beacon_count != IWL_CAL_NUM_BEACONS)
return;
/* Analyze signal for disconnected antenna */
@@ -1021,7 +1043,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv)
priv->cfg->bt_params->advanced_bt_coexist) {
/* Disable disconnected antenna algorithm for advanced
bt coex, assuming valid antennas are connected */
- data->active_chains = priv->hw_params.valid_rx_ant;
+ data->active_chains = hw_params(priv).valid_rx_ant;
for (i = 0; i < NUM_RX_CHAINS; i++)
if (!(data->active_chains & (1<<i)))
data->disconn_array[i] = 1;
@@ -1029,12 +1051,9 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv)
iwl_find_disconn_antenna(priv, average_sig, data);
/* Analyze noise for rx balance */
- average_noise[0] = data->chain_noise_a /
- priv->cfg->base_params->chain_noise_num_beacons;
- average_noise[1] = data->chain_noise_b /
- priv->cfg->base_params->chain_noise_num_beacons;
- average_noise[2] = data->chain_noise_c /
- priv->cfg->base_params->chain_noise_num_beacons;
+ average_noise[0] = data->chain_noise_a / IWL_CAL_NUM_BEACONS;
+ average_noise[1] = data->chain_noise_b / IWL_CAL_NUM_BEACONS;
+ average_noise[2] = data->chain_noise_c / IWL_CAL_NUM_BEACONS;
for (i = 0; i < NUM_RX_CHAINS; i++) {
if (!(data->disconn_array[i]) &&
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
deleted file mode 100644
index b8347db850e7..000000000000
--- a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
+++ /dev/null
@@ -1,299 +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 - 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/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-
-#include <net/mac80211.h>
-
-#include "iwl-commands.h"
-#include "iwl-dev.h"
-#include "iwl-core.h"
-#include "iwl-debug.h"
-#include "iwl-agn.h"
-#include "iwl-io.h"
-
-/******************************************************************************
- *
- * EEPROM related functions
- *
-******************************************************************************/
-
-int iwl_eeprom_check_version(struct iwl_priv *priv)
-{
- u16 eeprom_ver;
- u16 calib_ver;
-
- eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
- calib_ver = iwlagn_eeprom_calib_version(priv);
-
- if (eeprom_ver < priv->cfg->eeprom_ver ||
- calib_ver < priv->cfg->eeprom_calib_ver)
- goto err;
-
- IWL_INFO(priv, "device EEPROM VER=0x%x, CALIB=0x%x\n",
- eeprom_ver, calib_ver);
-
- return 0;
-err:
- IWL_ERR(priv, "Unsupported (too old) EEPROM VER=0x%x < 0x%x "
- "CALIB=0x%x < 0x%x\n",
- eeprom_ver, priv->cfg->eeprom_ver,
- calib_ver, priv->cfg->eeprom_calib_ver);
- return -EINVAL;
-
-}
-
-int iwl_eeprom_check_sku(struct iwl_priv *priv)
-{
- u16 radio_cfg;
-
- if (!priv->cfg->sku) {
- /* not using sku overwrite */
- priv->cfg->sku = iwl_eeprom_query16(priv, EEPROM_SKU_CAP);
- if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE &&
- !priv->cfg->ht_params) {
- IWL_ERR(priv, "Invalid 11n configuration\n");
- return -EINVAL;
- }
- }
- if (!priv->cfg->sku) {
- IWL_ERR(priv, "Invalid device sku\n");
- return -EINVAL;
- }
-
- IWL_INFO(priv, "Device SKU: 0X%x\n", priv->cfg->sku);
-
- if (!priv->cfg->valid_tx_ant && !priv->cfg->valid_rx_ant) {
- /* not using .cfg overwrite */
- radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
- priv->cfg->valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg);
- priv->cfg->valid_rx_ant = EEPROM_RF_CFG_RX_ANT_MSK(radio_cfg);
- if (!priv->cfg->valid_tx_ant || !priv->cfg->valid_rx_ant) {
- IWL_ERR(priv, "Invalid chain (0X%x, 0X%x)\n",
- priv->cfg->valid_tx_ant,
- priv->cfg->valid_rx_ant);
- return -EINVAL;
- }
- IWL_INFO(priv, "Valid Tx ant: 0X%x, Valid Rx ant: 0X%x\n",
- priv->cfg->valid_tx_ant, priv->cfg->valid_rx_ant);
- }
- /*
- * for some special cases,
- * EEPROM did not reflect the correct antenna setting
- * so overwrite the valid tx/rx antenna from .cfg
- */
- return 0;
-}
-
-void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac)
-{
- const u8 *addr = iwl_eeprom_query_addr(priv,
- EEPROM_MAC_ADDRESS);
- memcpy(mac, addr, ETH_ALEN);
-}
-
-/**
- * iwl_get_max_txpower_avg - get the highest tx power from all chains.
- * find the highest tx power from all chains for the channel
- */
-static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
- struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
- int element, s8 *max_txpower_in_half_dbm)
-{
- s8 max_txpower_avg = 0; /* (dBm) */
-
- /* Take the highest tx power from any valid chains */
- if ((priv->cfg->valid_tx_ant & ANT_A) &&
- (enhanced_txpower[element].chain_a_max > max_txpower_avg))
- max_txpower_avg = enhanced_txpower[element].chain_a_max;
- if ((priv->cfg->valid_tx_ant & ANT_B) &&
- (enhanced_txpower[element].chain_b_max > max_txpower_avg))
- max_txpower_avg = enhanced_txpower[element].chain_b_max;
- if ((priv->cfg->valid_tx_ant & ANT_C) &&
- (enhanced_txpower[element].chain_c_max > max_txpower_avg))
- max_txpower_avg = enhanced_txpower[element].chain_c_max;
- if (((priv->cfg->valid_tx_ant == ANT_AB) |
- (priv->cfg->valid_tx_ant == ANT_BC) |
- (priv->cfg->valid_tx_ant == ANT_AC)) &&
- (enhanced_txpower[element].mimo2_max > max_txpower_avg))
- max_txpower_avg = enhanced_txpower[element].mimo2_max;
- if ((priv->cfg->valid_tx_ant == ANT_ABC) &&
- (enhanced_txpower[element].mimo3_max > max_txpower_avg))
- max_txpower_avg = enhanced_txpower[element].mimo3_max;
-
- /*
- * max. tx power in EEPROM is in 1/2 dBm format
- * convert from 1/2 dBm to dBm (round-up convert)
- * but we also do not want to loss 1/2 dBm resolution which
- * will impact performance
- */
- *max_txpower_in_half_dbm = max_txpower_avg;
- return (max_txpower_avg & 0x01) + (max_txpower_avg >> 1);
-}
-
-static void
-iwlcore_eeprom_enh_txp_read_element(struct iwl_priv *priv,
- struct iwl_eeprom_enhanced_txpwr *txp,
- s8 max_txpower_avg)
-{
- int ch_idx;
- bool is_ht40 = txp->flags & IWL_EEPROM_ENH_TXP_FL_40MHZ;
- enum ieee80211_band band;
-
- band = txp->flags & IWL_EEPROM_ENH_TXP_FL_BAND_52G ?
- IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
-
- for (ch_idx = 0; ch_idx < priv->channel_count; ch_idx++) {
- struct iwl_channel_info *ch_info = &priv->channel_info[ch_idx];
-
- /* update matching channel or from common data only */
- if (txp->channel != 0 && ch_info->channel != txp->channel)
- continue;
-
- /* update matching band only */
- if (band != ch_info->band)
- continue;
-
- if (ch_info->max_power_avg < max_txpower_avg && !is_ht40) {
- ch_info->max_power_avg = max_txpower_avg;
- ch_info->curr_txpow = max_txpower_avg;
- ch_info->scan_power = max_txpower_avg;
- }
-
- if (is_ht40 && ch_info->ht40_max_power_avg < max_txpower_avg)
- ch_info->ht40_max_power_avg = max_txpower_avg;
- }
-}
-
-#define EEPROM_TXP_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT)
-#define EEPROM_TXP_ENTRY_LEN sizeof(struct iwl_eeprom_enhanced_txpwr)
-#define EEPROM_TXP_SZ_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT_SIZE)
-
-#define TXP_CHECK_AND_PRINT(x) ((txp->flags & IWL_EEPROM_ENH_TXP_FL_##x) \
- ? # x " " : "")
-
-void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv)
-{
- struct iwl_eeprom_enhanced_txpwr *txp_array, *txp;
- int idx, entries;
- __le16 *txp_len;
- s8 max_txp_avg, max_txp_avg_halfdbm;
-
- BUILD_BUG_ON(sizeof(struct iwl_eeprom_enhanced_txpwr) != 8);
-
- /* the length is in 16-bit words, but we want entries */
- txp_len = (__le16 *) iwl_eeprom_query_addr(priv, EEPROM_TXP_SZ_OFFS);
- entries = le16_to_cpup(txp_len) * 2 / EEPROM_TXP_ENTRY_LEN;
-
- txp_array = (void *) iwl_eeprom_query_addr(priv, EEPROM_TXP_OFFS);
-
- for (idx = 0; idx < entries; idx++) {
- txp = &txp_array[idx];
- /* skip invalid entries */
- if (!(txp->flags & IWL_EEPROM_ENH_TXP_FL_VALID))
- continue;
-
- IWL_DEBUG_EEPROM(priv, "%s %d:\t %s%s%s%s%s%s%s%s (0x%02x)\n",
- (txp->channel && (txp->flags &
- IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE)) ?
- "Common " : (txp->channel) ?
- "Channel" : "Common",
- (txp->channel),
- TXP_CHECK_AND_PRINT(VALID),
- TXP_CHECK_AND_PRINT(BAND_52G),
- TXP_CHECK_AND_PRINT(OFDM),
- TXP_CHECK_AND_PRINT(40MHZ),
- TXP_CHECK_AND_PRINT(HT_AP),
- TXP_CHECK_AND_PRINT(RES1),
- TXP_CHECK_AND_PRINT(RES2),
- TXP_CHECK_AND_PRINT(COMMON_TYPE),
- txp->flags);
- IWL_DEBUG_EEPROM(priv, "\t\t chain_A: 0x%02x "
- "chain_B: 0X%02x chain_C: 0X%02x\n",
- txp->chain_a_max, txp->chain_b_max,
- txp->chain_c_max);
- IWL_DEBUG_EEPROM(priv, "\t\t MIMO2: 0x%02x "
- "MIMO3: 0x%02x High 20_on_40: 0x%02x "
- "Low 20_on_40: 0x%02x\n",
- txp->mimo2_max, txp->mimo3_max,
- ((txp->delta_20_in_40 & 0xf0) >> 4),
- (txp->delta_20_in_40 & 0x0f));
-
- max_txp_avg = iwl_get_max_txpower_avg(priv, txp_array, idx,
- &max_txp_avg_halfdbm);
-
- /*
- * Update the user limit values values to the highest
- * power supported by any channel
- */
- if (max_txp_avg > priv->tx_power_user_lmt)
- priv->tx_power_user_lmt = max_txp_avg;
- if (max_txp_avg_halfdbm > priv->tx_power_lmt_in_half_dbm)
- priv->tx_power_lmt_in_half_dbm = max_txp_avg_halfdbm;
-
- iwlcore_eeprom_enh_txp_read_element(priv, txp, max_txp_avg);
- }
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
index 0e5b842529c4..123ef5e129d5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
@@ -78,10 +78,23 @@
#define IWLAGN_RTC_DATA_SIZE (IWLAGN_RTC_DATA_UPPER_BOUND - \
IWLAGN_RTC_DATA_LOWER_BOUND)
+#define IWL60_RTC_INST_LOWER_BOUND (0x000000)
+#define IWL60_RTC_INST_UPPER_BOUND (0x040000)
+#define IWL60_RTC_DATA_LOWER_BOUND (0x800000)
+#define IWL60_RTC_DATA_UPPER_BOUND (0x814000)
+#define IWL60_RTC_INST_SIZE \
+ (IWL60_RTC_INST_UPPER_BOUND - IWL60_RTC_INST_LOWER_BOUND)
+#define IWL60_RTC_DATA_SIZE \
+ (IWL60_RTC_DATA_UPPER_BOUND - IWL60_RTC_DATA_LOWER_BOUND)
+
/* RSSI to dBm */
#define IWLAGN_RSSI_OFFSET 44
-#define IWLAGN_DEFAULT_TX_RETRY 15
+#define IWLAGN_DEFAULT_TX_RETRY 15
+#define IWLAGN_MGMT_DFAULT_RETRY_LIMIT 3
+#define IWLAGN_RTS_DFAULT_RETRY_LIMIT 60
+#define IWLAGN_BAR_DFAULT_RETRY_LIMIT 60
+#define IWLAGN_LOW_RETRY_LIMIT 7
/* Limit range of txpower output target to be between these values */
#define IWLAGN_TX_POWER_TARGET_POWER_MIN (0) /* 0 dBm: 1 milliwatt */
@@ -92,20 +105,7 @@
#define IWLAGN_CMD_FIFO_NUM 7
#define IWLAGN_NUM_QUEUES 20
-#define IWLAGN_NUM_AMPDU_QUEUES 10
-#define IWLAGN_FIRST_AMPDU_QUEUE 10
-
-/* Fixed (non-configurable) rx data from phy */
-
-/**
- * struct iwlagn_schedq_bc_tbl scheduler byte count table
- * base physical address provided by SCD_DRAM_BASE_ADDR
- * @tfd_offset 0-12 - tx command byte count
- * 12-16 - station index
- */
-struct iwlagn_scd_bc_tbl {
- __le16 tfd_offset[TFD_QUEUE_BC_SIZE];
-} __packed;
-
+#define IWLAGN_NUM_AMPDU_QUEUES 9
+#define IWLAGN_FIRST_AMPDU_QUEUE 11
#endif /* __iwl_agn_hw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 3bee0f119bcd..1a52ed29f2d6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -35,454 +35,10 @@
#include "iwl-dev.h"
#include "iwl-core.h"
#include "iwl-io.h"
-#include "iwl-helpers.h"
#include "iwl-agn-hw.h"
#include "iwl-agn.h"
-#include "iwl-sta.h"
#include "iwl-trans.h"
-
-static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp)
-{
- return le32_to_cpup((__le32 *)&tx_resp->status +
- tx_resp->frame_count) & MAX_SN;
-}
-
-static void iwlagn_count_tx_err_status(struct iwl_priv *priv, u16 status)
-{
- status &= TX_STATUS_MSK;
-
- switch (status) {
- case TX_STATUS_POSTPONE_DELAY:
- priv->reply_tx_stats.pp_delay++;
- break;
- case TX_STATUS_POSTPONE_FEW_BYTES:
- priv->reply_tx_stats.pp_few_bytes++;
- break;
- case TX_STATUS_POSTPONE_BT_PRIO:
- priv->reply_tx_stats.pp_bt_prio++;
- break;
- case TX_STATUS_POSTPONE_QUIET_PERIOD:
- priv->reply_tx_stats.pp_quiet_period++;
- break;
- case TX_STATUS_POSTPONE_CALC_TTAK:
- priv->reply_tx_stats.pp_calc_ttak++;
- break;
- case TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY:
- priv->reply_tx_stats.int_crossed_retry++;
- break;
- case TX_STATUS_FAIL_SHORT_LIMIT:
- priv->reply_tx_stats.short_limit++;
- break;
- case TX_STATUS_FAIL_LONG_LIMIT:
- priv->reply_tx_stats.long_limit++;
- break;
- case TX_STATUS_FAIL_FIFO_UNDERRUN:
- priv->reply_tx_stats.fifo_underrun++;
- break;
- case TX_STATUS_FAIL_DRAIN_FLOW:
- priv->reply_tx_stats.drain_flow++;
- break;
- case TX_STATUS_FAIL_RFKILL_FLUSH:
- priv->reply_tx_stats.rfkill_flush++;
- break;
- case TX_STATUS_FAIL_LIFE_EXPIRE:
- priv->reply_tx_stats.life_expire++;
- break;
- case TX_STATUS_FAIL_DEST_PS:
- priv->reply_tx_stats.dest_ps++;
- break;
- case TX_STATUS_FAIL_HOST_ABORTED:
- priv->reply_tx_stats.host_abort++;
- break;
- case TX_STATUS_FAIL_BT_RETRY:
- priv->reply_tx_stats.bt_retry++;
- break;
- case TX_STATUS_FAIL_STA_INVALID:
- priv->reply_tx_stats.sta_invalid++;
- break;
- case TX_STATUS_FAIL_FRAG_DROPPED:
- priv->reply_tx_stats.frag_drop++;
- break;
- case TX_STATUS_FAIL_TID_DISABLE:
- priv->reply_tx_stats.tid_disable++;
- break;
- case TX_STATUS_FAIL_FIFO_FLUSHED:
- priv->reply_tx_stats.fifo_flush++;
- break;
- case TX_STATUS_FAIL_INSUFFICIENT_CF_POLL:
- priv->reply_tx_stats.insuff_cf_poll++;
- break;
- case TX_STATUS_FAIL_PASSIVE_NO_RX:
- priv->reply_tx_stats.fail_hw_drop++;
- break;
- case TX_STATUS_FAIL_NO_BEACON_ON_RADAR:
- priv->reply_tx_stats.sta_color_mismatch++;
- break;
- default:
- priv->reply_tx_stats.unknown++;
- break;
- }
-}
-
-static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status)
-{
- status &= AGG_TX_STATUS_MSK;
-
- switch (status) {
- case AGG_TX_STATE_UNDERRUN_MSK:
- priv->reply_agg_tx_stats.underrun++;
- break;
- case AGG_TX_STATE_BT_PRIO_MSK:
- priv->reply_agg_tx_stats.bt_prio++;
- break;
- case AGG_TX_STATE_FEW_BYTES_MSK:
- priv->reply_agg_tx_stats.few_bytes++;
- break;
- case AGG_TX_STATE_ABORT_MSK:
- priv->reply_agg_tx_stats.abort++;
- break;
- case AGG_TX_STATE_LAST_SENT_TTL_MSK:
- priv->reply_agg_tx_stats.last_sent_ttl++;
- break;
- case AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK:
- priv->reply_agg_tx_stats.last_sent_try++;
- break;
- case AGG_TX_STATE_LAST_SENT_BT_KILL_MSK:
- priv->reply_agg_tx_stats.last_sent_bt_kill++;
- break;
- case AGG_TX_STATE_SCD_QUERY_MSK:
- priv->reply_agg_tx_stats.scd_query++;
- break;
- case AGG_TX_STATE_TEST_BAD_CRC32_MSK:
- priv->reply_agg_tx_stats.bad_crc32++;
- break;
- case AGG_TX_STATE_RESPONSE_MSK:
- priv->reply_agg_tx_stats.response++;
- break;
- case AGG_TX_STATE_DUMP_TX_MSK:
- priv->reply_agg_tx_stats.dump_tx++;
- break;
- case AGG_TX_STATE_DELAY_TX_MSK:
- priv->reply_agg_tx_stats.delay_tx++;
- break;
- default:
- priv->reply_agg_tx_stats.unknown++;
- break;
- }
-}
-
-static void iwlagn_set_tx_status(struct iwl_priv *priv,
- struct ieee80211_tx_info *info,
- struct iwl_rxon_context *ctx,
- struct iwlagn_tx_resp *tx_resp,
- int txq_id, bool is_agg)
-{
- u16 status = le16_to_cpu(tx_resp->status.status);
-
- info->status.rates[0].count = tx_resp->failure_frame + 1;
- if (is_agg)
- info->flags &= ~IEEE80211_TX_CTL_AMPDU;
- info->flags |= iwl_tx_status_to_mac80211(status);
- iwlagn_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags),
- info);
- if (!iwl_is_tx_success(status))
- iwlagn_count_tx_err_status(priv, status);
-
- 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_stop_queue(priv, &priv->txq[txq_id]);
- }
-
- IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x) rate_n_flags "
- "0x%x retries %d\n",
- txq_id,
- iwl_get_tx_fail_reason(status), status,
- le32_to_cpu(tx_resp->rate_n_flags),
- tx_resp->failure_frame);
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-#define AGG_TX_STATE_FAIL(x) case AGG_TX_STATE_ ## x: return #x
-
-const char *iwl_get_agg_tx_fail_reason(u16 status)
-{
- status &= AGG_TX_STATUS_MSK;
- switch (status) {
- case AGG_TX_STATE_TRANSMITTED:
- return "SUCCESS";
- AGG_TX_STATE_FAIL(UNDERRUN_MSK);
- AGG_TX_STATE_FAIL(BT_PRIO_MSK);
- AGG_TX_STATE_FAIL(FEW_BYTES_MSK);
- AGG_TX_STATE_FAIL(ABORT_MSK);
- AGG_TX_STATE_FAIL(LAST_SENT_TTL_MSK);
- AGG_TX_STATE_FAIL(LAST_SENT_TRY_CNT_MSK);
- AGG_TX_STATE_FAIL(LAST_SENT_BT_KILL_MSK);
- AGG_TX_STATE_FAIL(SCD_QUERY_MSK);
- AGG_TX_STATE_FAIL(TEST_BAD_CRC32_MSK);
- AGG_TX_STATE_FAIL(RESPONSE_MSK);
- AGG_TX_STATE_FAIL(DUMP_TX_MSK);
- AGG_TX_STATE_FAIL(DELAY_TX_MSK);
- }
-
- return "UNKNOWN";
-}
-#endif /* CONFIG_IWLWIFI_DEBUG */
-
-static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,
- struct iwl_ht_agg *agg,
- struct iwlagn_tx_resp *tx_resp,
- int txq_id, u16 start_idx)
-{
- u16 status;
- struct agg_tx_status *frame_status = &tx_resp->status;
- struct ieee80211_hdr *hdr = NULL;
- int i, sh, idx;
- u16 seq;
-
- if (agg->wait_for_ba)
- IWL_DEBUG_TX_REPLY(priv, "got tx response w/o block-ack\n");
-
- agg->frame_count = tx_resp->frame_count;
- agg->start_idx = start_idx;
- agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
- agg->bitmap = 0;
-
- /* # frames attempted by Tx command */
- if (agg->frame_count == 1) {
- struct iwl_tx_info *txb;
-
- /* Only one frame was attempted; no block-ack will arrive */
- idx = start_idx;
-
- IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n",
- agg->frame_count, agg->start_idx, idx);
- txb = &priv->txq[txq_id].txb[idx];
- iwlagn_set_tx_status(priv, IEEE80211_SKB_CB(txb->skb),
- txb->ctx, tx_resp, txq_id, true);
- agg->wait_for_ba = 0;
- } else {
- /* Two or more frames were attempted; expect block-ack */
- u64 bitmap = 0;
-
- /*
- * Start is the lowest frame sent. It may not be the first
- * frame in the batch; we figure this out dynamically during
- * the following loop.
- */
- int start = agg->start_idx;
-
- /* Construct bit-map of pending frames within Tx window */
- 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_INDEX(seq);
- txq_id = SEQ_TO_QUEUE(seq);
-
- if (status & AGG_TX_STATUS_MSK)
- iwlagn_count_agg_tx_err_status(priv, status);
-
- if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
- AGG_TX_STATE_ABORT_MSK))
- continue;
-
- IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, txq_id=%d idx=%d\n",
- agg->frame_count, txq_id, idx);
- IWL_DEBUG_TX_REPLY(priv, "status %s (0x%08x), "
- "try-count (0x%08x)\n",
- iwl_get_agg_tx_fail_reason(status),
- status & AGG_TX_STATUS_MSK,
- status & AGG_TX_TRY_MSK);
-
- hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx);
- if (!hdr) {
- IWL_ERR(priv,
- "BUG_ON idx doesn't point to valid skb"
- " idx=%d, txq_id=%d\n", idx, txq_id);
- return -1;
- }
-
- sc = le16_to_cpu(hdr->seq_ctrl);
- if (idx != (SEQ_TO_SN(sc) & 0xff)) {
- IWL_ERR(priv,
- "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;
- }
-
- IWL_DEBUG_TX_REPLY(priv, "AGG Frame i=%d idx %d seq=%d\n",
- i, idx, SEQ_TO_SN(sc));
-
- /*
- * sh -> how many frames ahead of the starting frame is
- * the current one?
- *
- * Note that all frames sent in the batch must be in a
- * 64-frame window, so this number should be in [0,63].
- * If outside of this window, then we've found a new
- * "first" frame in the batch and need to change start.
- */
- sh = idx - start;
-
- /*
- * If >= 64, out of window. start must be at the front
- * of the circular buffer, idx must be near the end of
- * the buffer, and idx is the new "first" frame. Shift
- * the indices around.
- */
- if (sh >= 64) {
- /* Shift bitmap by start - idx, wrapped */
- sh = 0x100 - idx + start;
- bitmap = bitmap << sh;
- /* Now idx is the new start so sh = 0 */
- sh = 0;
- start = idx;
- /*
- * If <= -64 then wraps the 256-pkt circular buffer
- * (e.g., start = 255 and idx = 0, sh should be 1)
- */
- } else if (sh <= -64) {
- sh = 0x100 - start + idx;
- /*
- * If < 0 but > -64, out of window. idx is before start
- * but not wrapped. Shift the indices around.
- */
- } else if (sh < 0) {
- /* Shift by how far start is ahead of idx */
- sh = start - idx;
- bitmap = bitmap << sh;
- /* Now idx is the new start so sh = 0 */
- start = idx;
- sh = 0;
- }
- /* Sequence number start + sh was sent in this batch */
- bitmap |= 1ULL << sh;
- IWL_DEBUG_TX_REPLY(priv, "start=%d bitmap=0x%llx\n",
- start, (unsigned long long)bitmap);
- }
-
- /*
- * Store the bitmap and possibly the new start, if we wrapped
- * the buffer above
- */
- agg->bitmap = bitmap;
- agg->start_idx = start;
- IWL_DEBUG_TX_REPLY(priv, "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;
-}
-
-void iwl_check_abort_status(struct iwl_priv *priv,
- u8 frame_count, u32 status)
-{
- 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->status))
- queue_work(priv->workqueue, &priv->tx_flush);
- }
-}
-
-void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
-{
- struct iwl_rx_packet *pkt = rxb_addr(rxb);
- u16 sequence = le16_to_cpu(pkt->hdr.sequence);
- int txq_id = SEQ_TO_QUEUE(sequence);
- int index = SEQ_TO_INDEX(sequence);
- struct iwl_tx_queue *txq = &priv->txq[txq_id];
- struct ieee80211_tx_info *info;
- struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
- struct ieee80211_hdr *hdr;
- struct iwl_tx_info *txb;
- u32 status = le16_to_cpu(tx_resp->status.status);
- int tid;
- int sta_id;
- int freed;
- unsigned long flags;
-
- if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
- IWL_ERR(priv, "%s: Read index for DMA queue txq_id (%d) "
- "index %d is out of range [0-%d] %d %d\n", __func__,
- txq_id, index, txq->q.n_bd, txq->q.write_ptr,
- txq->q.read_ptr);
- return;
- }
-
- txq->time_stamp = jiffies;
- txb = &txq->txb[txq->q.read_ptr];
- info = IEEE80211_SKB_CB(txb->skb);
- memset(&info->status, 0, sizeof(info->status));
-
- tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >>
- IWLAGN_TX_RES_TID_POS;
- sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >>
- IWLAGN_TX_RES_RA_POS;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
-
- hdr = (void *)txb->skb->data;
- if (!ieee80211_is_data_qos(hdr->frame_control))
- priv->last_seq_ctl = tx_resp->seq_ctl;
-
- if (txq->sched_retry) {
- const u32 scd_ssn = iwlagn_get_scd_ssn(tx_resp);
- struct iwl_ht_agg *agg;
-
- agg = &priv->stations[sta_id].tid[tid].agg;
- /*
- * If the BT kill count is non-zero, we'll get this
- * notification again.
- */
- if (tx_resp->bt_kill_count && tx_resp->frame_count == 1 &&
- priv->cfg->bt_params &&
- priv->cfg->bt_params->advanced_bt_coexist) {
- IWL_DEBUG_COEX(priv, "receive reply tx with bt_kill\n");
- }
- iwlagn_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index);
-
- /* check if BAR is needed */
- if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status))
- info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
-
- if (txq->q.read_ptr != (scd_ssn & 0xff)) {
- index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
- IWL_DEBUG_TX_REPLY(priv, "Retry scheduler reclaim "
- "scd_ssn=%d idx=%d txq=%d swq=%d\n",
- scd_ssn , index, txq_id, txq->swq_id);
-
- freed = iwlagn_tx_queue_reclaim(priv, txq_id, index);
- iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
-
- if (priv->mac80211_registered &&
- (iwl_queue_space(&txq->q) > txq->q.low_mark) &&
- (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA))
- iwl_wake_queue(priv, txq);
- }
- } else {
- iwlagn_set_tx_status(priv, info, txb->ctx, tx_resp,
- txq_id, false);
- freed = iwlagn_tx_queue_reclaim(priv, txq_id, index);
- iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
-
- if (priv->mac80211_registered &&
- iwl_queue_space(&txq->q) > txq->q.low_mark &&
- status != TX_STATUS_FAIL_PASSIVE_NO_RX)
- iwl_wake_queue(priv, txq);
- }
-
- iwlagn_txq_check_empty(priv, sta_id, tid, txq_id);
-
- iwl_check_abort_status(priv, tx_resp->frame_count, status);
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-}
+#include "iwl-shared.h"
int iwlagn_hw_valid_rtc_data_addr(u32 addr)
{
@@ -495,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->status),
+ if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->shrd->status),
"TX Power requested while scanning!\n"))
return -EAGAIN;
@@ -525,7 +81,7 @@ int iwlagn_send_tx_power(struct iwl_priv *priv)
else
tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD;
- return trans_send_cmd_pdu(&priv->trans, tx_ant_cfg_cmd, CMD_SYNC,
+ return iwl_trans_send_cmd_pdu(trans(priv), tx_ant_cfg_cmd, CMD_SYNC,
sizeof(tx_power_cmd), &tx_power_cmd);
}
@@ -538,11 +94,7 @@ void iwlagn_temperature(struct iwl_priv *priv)
u16 iwlagn_eeprom_calib_version(struct iwl_priv *priv)
{
- struct iwl_eeprom_calib_hdr {
- u8 version;
- u8 pa_type;
- u16 voltage;
- } *hdr;
+ struct iwl_eeprom_calib_hdr *hdr;
hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv,
EEPROM_CALIB_ALL);
@@ -609,6 +161,9 @@ struct iwl_mod_params iwlagn_mod_params = {
.bt_coex_active = true,
.no_sleep_autoadjust = true,
.power_level = IWL_POWER_INDEX_1,
+ .bt_ch_announce = true,
+ .wanted_ucode_alternative = 1,
+ .auto_agg = true,
/* the rest are 0 by default */
};
@@ -633,449 +188,6 @@ int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band)
return -1;
}
-static int iwl_get_single_channel_for_scan(struct iwl_priv *priv,
- struct ieee80211_vif *vif,
- enum ieee80211_band band,
- struct iwl_scan_channel *scan_ch)
-{
- const struct ieee80211_supported_band *sband;
- u16 passive_dwell = 0;
- u16 active_dwell = 0;
- int added = 0;
- u16 channel = 0;
-
- sband = iwl_get_hw_mode(priv, band);
- if (!sband) {
- IWL_ERR(priv, "invalid band\n");
- return added;
- }
-
- active_dwell = iwl_get_active_dwell_time(priv, band, 0);
- passive_dwell = iwl_get_passive_dwell_time(priv, band, vif);
-
- if (passive_dwell <= active_dwell)
- passive_dwell = active_dwell + 1;
-
- channel = iwl_get_single_channel_number(priv, band);
- if (channel) {
- scan_ch->channel = cpu_to_le16(channel);
- scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
- scan_ch->active_dwell = cpu_to_le16(active_dwell);
- scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
- /* Set txpower levels to defaults */
- scan_ch->dsp_atten = 110;
- if (band == IEEE80211_BAND_5GHZ)
- scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
- else
- scan_ch->tx_gain = ((1 << 5) | (5 << 3));
- added++;
- } else
- IWL_ERR(priv, "no valid channel found\n");
- return added;
-}
-
-static int iwl_get_channels_for_scan(struct iwl_priv *priv,
- struct ieee80211_vif *vif,
- enum ieee80211_band band,
- u8 is_active, u8 n_probes,
- struct iwl_scan_channel *scan_ch)
-{
- struct ieee80211_channel *chan;
- const struct ieee80211_supported_band *sband;
- const struct iwl_channel_info *ch_info;
- u16 passive_dwell = 0;
- u16 active_dwell = 0;
- int added, i;
- u16 channel;
-
- sband = iwl_get_hw_mode(priv, band);
- if (!sband)
- return 0;
-
- active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
- passive_dwell = iwl_get_passive_dwell_time(priv, band, vif);
-
- if (passive_dwell <= active_dwell)
- passive_dwell = active_dwell + 1;
-
- for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) {
- chan = priv->scan_request->channels[i];
-
- if (chan->band != band)
- continue;
-
- channel = chan->hw_value;
- scan_ch->channel = cpu_to_le16(channel);
-
- ch_info = iwl_get_channel_info(priv, band, channel);
- if (!is_channel_valid(ch_info)) {
- IWL_DEBUG_SCAN(priv, "Channel %d is INVALID for this band.\n",
- channel);
- continue;
- }
-
- if (!is_active || is_channel_passive(ch_info) ||
- (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
- scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
- else
- scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
-
- if (n_probes)
- scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
-
- scan_ch->active_dwell = cpu_to_le16(active_dwell);
- scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
-
- /* Set txpower levels to defaults */
- scan_ch->dsp_atten = 110;
-
- /* NOTE: if we were doing 6Mb OFDM for scans we'd use
- * power level:
- * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
- */
- if (band == IEEE80211_BAND_5GHZ)
- scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
- else
- scan_ch->tx_gain = ((1 << 5) | (5 << 3));
-
- IWL_DEBUG_SCAN(priv, "Scanning ch=%d prob=0x%X [%s %d]\n",
- channel, le32_to_cpu(scan_ch->type),
- (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
- "ACTIVE" : "PASSIVE",
- (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
- active_dwell : passive_dwell);
-
- scan_ch++;
- added++;
- }
-
- IWL_DEBUG_SCAN(priv, "total channels to scan %d\n", added);
- return added;
-}
-
-static int iwl_fill_offch_tx(struct iwl_priv *priv, void *data, size_t maxlen)
-{
- struct sk_buff *skb = priv->offchan_tx_skb;
-
- if (skb->len < maxlen)
- maxlen = skb->len;
-
- memcpy(data, skb->data, maxlen);
-
- return maxlen;
-}
-
-int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
-{
- struct iwl_host_cmd cmd = {
- .id = REPLY_SCAN_CMD,
- .len = { sizeof(struct iwl_scan_cmd), },
- .flags = CMD_SYNC,
- };
- struct iwl_scan_cmd *scan;
- struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
- u32 rate_flags = 0;
- u16 cmd_len;
- u16 rx_chain = 0;
- enum ieee80211_band band;
- u8 n_probes = 0;
- u8 rx_ant = priv->hw_params.valid_rx_ant;
- u8 rate;
- bool is_active = false;
- int chan_mod;
- u8 active_chains;
- u8 scan_tx_antennas = priv->hw_params.valid_tx_ant;
- int ret;
-
- lockdep_assert_held(&priv->mutex);
-
- if (vif)
- ctx = iwl_rxon_ctx_from_vif(vif);
-
- if (!priv->scan_cmd) {
- priv->scan_cmd = kmalloc(sizeof(struct iwl_scan_cmd) +
- IWL_MAX_SCAN_SIZE, GFP_KERNEL);
- if (!priv->scan_cmd) {
- IWL_DEBUG_SCAN(priv,
- "fail to allocate memory for scan\n");
- return -ENOMEM;
- }
- }
- scan = priv->scan_cmd;
- memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE);
-
- scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
- scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
-
- if (priv->scan_type != IWL_SCAN_OFFCH_TX &&
- iwl_is_any_associated(priv)) {
- u16 interval = 0;
- u32 extra;
- u32 suspend_time = 100;
- u32 scan_suspend_time = 100;
-
- IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
- switch (priv->scan_type) {
- case IWL_SCAN_OFFCH_TX:
- WARN_ON(1);
- break;
- case IWL_SCAN_RADIO_RESET:
- interval = 0;
- break;
- case IWL_SCAN_NORMAL:
- interval = vif->bss_conf.beacon_int;
- break;
- }
-
- scan->suspend_time = 0;
- scan->max_out_time = cpu_to_le32(200 * 1024);
- if (!interval)
- interval = suspend_time;
-
- extra = (suspend_time / interval) << 22;
- scan_suspend_time = (extra |
- ((suspend_time % interval) * 1024));
- scan->suspend_time = cpu_to_le32(scan_suspend_time);
- IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n",
- scan_suspend_time, interval);
- } else if (priv->scan_type == IWL_SCAN_OFFCH_TX) {
- scan->suspend_time = 0;
- scan->max_out_time =
- cpu_to_le32(1024 * priv->offchan_tx_timeout);
- }
-
- switch (priv->scan_type) {
- case IWL_SCAN_RADIO_RESET:
- IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n");
- break;
- case IWL_SCAN_NORMAL:
- if (priv->scan_request->n_ssids) {
- int i, p = 0;
- IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
- for (i = 0; i < priv->scan_request->n_ssids; i++) {
- /* always does wildcard anyway */
- if (!priv->scan_request->ssids[i].ssid_len)
- continue;
- scan->direct_scan[p].id = WLAN_EID_SSID;
- scan->direct_scan[p].len =
- priv->scan_request->ssids[i].ssid_len;
- memcpy(scan->direct_scan[p].ssid,
- priv->scan_request->ssids[i].ssid,
- priv->scan_request->ssids[i].ssid_len);
- n_probes++;
- p++;
- }
- is_active = true;
- } else
- IWL_DEBUG_SCAN(priv, "Start passive scan.\n");
- break;
- case IWL_SCAN_OFFCH_TX:
- IWL_DEBUG_SCAN(priv, "Start offchannel TX scan.\n");
- break;
- }
-
- scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
- scan->tx_cmd.sta_id = ctx->bcast_sta_id;
- scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
-
- switch (priv->scan_band) {
- case IEEE80211_BAND_2GHZ:
- scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
- chan_mod = le32_to_cpu(
- priv->contexts[IWL_RXON_CTX_BSS].active.flags &
- RXON_FLG_CHANNEL_MODE_MSK)
- >> RXON_FLG_CHANNEL_MODE_POS;
- if (chan_mod == CHANNEL_MODE_PURE_40) {
- rate = IWL_RATE_6M_PLCP;
- } else {
- rate = IWL_RATE_1M_PLCP;
- rate_flags = RATE_MCS_CCK_MSK;
- }
- /*
- * Internal scans are passive, so we can indiscriminately set
- * the BT ignore flag on 2.4 GHz since it applies to TX only.
- */
- if (priv->cfg->bt_params &&
- priv->cfg->bt_params->advanced_bt_coexist)
- scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT;
- break;
- case IEEE80211_BAND_5GHZ:
- rate = IWL_RATE_6M_PLCP;
- break;
- default:
- IWL_WARN(priv, "Invalid scan band\n");
- return -EIO;
- }
-
- /*
- * If active scanning is requested but a certain channel is
- * marked passive, we can do active scanning if we detect
- * transmissions.
- *
- * There is an issue with some firmware versions that triggers
- * a sysassert on a "good CRC threshold" of zero (== disabled),
- * on a radar channel even though this means that we should NOT
- * send probes.
- *
- * The "good CRC threshold" is the number of frames that we
- * need to receive during our dwell time on a channel before
- * sending out probes -- setting this to a huge value will
- * mean we never reach it, but at the same time work around
- * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER
- * here instead of IWL_GOOD_CRC_TH_DISABLED.
- *
- * This was fixed in later versions along with some other
- * scan changes, and the threshold behaves as a flag in those
- * versions.
- */
- if (priv->new_scan_threshold_behaviour)
- scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
- IWL_GOOD_CRC_TH_DISABLED;
- else
- scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
- IWL_GOOD_CRC_TH_NEVER;
-
- band = priv->scan_band;
-
- if (priv->cfg->scan_rx_antennas[band])
- rx_ant = priv->cfg->scan_rx_antennas[band];
-
- if (band == IEEE80211_BAND_2GHZ &&
- priv->cfg->bt_params &&
- priv->cfg->bt_params->advanced_bt_coexist) {
- /* transmit 2.4 GHz probes only on first antenna */
- scan_tx_antennas = first_antenna(scan_tx_antennas);
- }
-
- priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band],
- scan_tx_antennas);
- rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]);
- scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags);
-
- /* In power save mode use one chain, otherwise use all chains */
- if (test_bit(STATUS_POWER_PMI, &priv->status)) {
- /* rx_ant has been set to all valid chains previously */
- active_chains = rx_ant &
- ((u8)(priv->chain_noise_data.active_chains));
- if (!active_chains)
- active_chains = rx_ant;
-
- IWL_DEBUG_SCAN(priv, "chain_noise_data.active_chains: %u\n",
- priv->chain_noise_data.active_chains);
-
- rx_ant = first_antenna(active_chains);
- }
- if (priv->cfg->bt_params &&
- priv->cfg->bt_params->advanced_bt_coexist &&
- priv->bt_full_concurrent) {
- /* operated as 1x1 in full concurrency mode */
- rx_ant = first_antenna(rx_ant);
- }
-
- /* MIMO is not used here, but value is required */
- rx_chain |= priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
- rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
- rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS;
- rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
- scan->rx_chain = cpu_to_le16(rx_chain);
- switch (priv->scan_type) {
- case IWL_SCAN_NORMAL:
- cmd_len = iwl_fill_probe_req(priv,
- (struct ieee80211_mgmt *)scan->data,
- vif->addr,
- priv->scan_request->ie,
- priv->scan_request->ie_len,
- IWL_MAX_SCAN_SIZE - sizeof(*scan));
- break;
- case IWL_SCAN_RADIO_RESET:
- /* use bcast addr, will not be transmitted but must be valid */
- cmd_len = iwl_fill_probe_req(priv,
- (struct ieee80211_mgmt *)scan->data,
- iwl_bcast_addr, NULL, 0,
- IWL_MAX_SCAN_SIZE - sizeof(*scan));
- break;
- case IWL_SCAN_OFFCH_TX:
- cmd_len = iwl_fill_offch_tx(priv, scan->data,
- IWL_MAX_SCAN_SIZE
- - sizeof(*scan)
- - sizeof(struct iwl_scan_channel));
- scan->scan_flags |= IWL_SCAN_FLAGS_ACTION_FRAME_TX;
- break;
- default:
- BUG();
- }
- scan->tx_cmd.len = cpu_to_le16(cmd_len);
-
- scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
- RXON_FILTER_BCON_AWARE_MSK);
-
- switch (priv->scan_type) {
- case IWL_SCAN_RADIO_RESET:
- scan->channel_count =
- iwl_get_single_channel_for_scan(priv, vif, band,
- (void *)&scan->data[cmd_len]);
- break;
- case IWL_SCAN_NORMAL:
- scan->channel_count =
- iwl_get_channels_for_scan(priv, vif, band,
- is_active, n_probes,
- (void *)&scan->data[cmd_len]);
- break;
- case IWL_SCAN_OFFCH_TX: {
- struct iwl_scan_channel *scan_ch;
-
- scan->channel_count = 1;
-
- scan_ch = (void *)&scan->data[cmd_len];
- scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
- scan_ch->channel =
- cpu_to_le16(priv->offchan_tx_chan->hw_value);
- scan_ch->active_dwell =
- cpu_to_le16(priv->offchan_tx_timeout);
- scan_ch->passive_dwell = 0;
-
- /* Set txpower levels to defaults */
- scan_ch->dsp_atten = 110;
-
- /* NOTE: if we were doing 6Mb OFDM for scans we'd use
- * power level:
- * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
- */
- if (priv->offchan_tx_chan->band == IEEE80211_BAND_5GHZ)
- scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
- else
- scan_ch->tx_gain = ((1 << 5) | (5 << 3));
- }
- break;
- }
-
- if (scan->channel_count == 0) {
- IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
- return -EIO;
- }
-
- cmd.len[0] += le16_to_cpu(scan->tx_cmd.len) +
- scan->channel_count * sizeof(struct iwl_scan_channel);
- cmd.data[0] = scan;
- cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
- scan->len = cpu_to_le16(cmd.len[0]);
-
- /* set scan bit here for PAN params */
- set_bit(STATUS_SCAN_HW, &priv->status);
-
- ret = iwlagn_set_pan_params(priv);
- if (ret)
- return ret;
-
- ret = trans_send_cmd(&priv->trans, &cmd);
- if (ret) {
- clear_bit(STATUS_SCAN_HW, &priv->status);
- iwlagn_set_pan_params(priv);
- }
-
- return ret;
-}
-
int iwlagn_manage_ibss_station(struct iwl_priv *priv,
struct ieee80211_vif *vif, bool add)
{
@@ -1089,52 +201,6 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv,
vif->bss_conf.bssid);
}
-void iwl_free_tfds_in_queue(struct iwl_priv *priv,
- int sta_id, int tid, int freed)
-{
- lockdep_assert_held(&priv->sta_lock);
-
- if (priv->stations[sta_id].tid[tid].tfds_in_queue >= freed)
- priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
- else {
- IWL_DEBUG_TX(priv, "free more than tfds_in_queue (%u:%d)\n",
- priv->stations[sta_id].tid[tid].tfds_in_queue,
- freed);
- priv->stations[sta_id].tid[tid].tfds_in_queue = 0;
- }
-}
-
-#define IWL_FLUSH_WAIT_MS 2000
-
-int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv)
-{
- struct iwl_tx_queue *txq;
- struct iwl_queue *q;
- int cnt;
- unsigned long now = jiffies;
- int ret = 0;
-
- /* waiting for all the tx frames complete might take a while */
- for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
- if (cnt == priv->cmd_queue)
- continue;
- txq = &priv->txq[cnt];
- q = &txq->q;
- while (q->read_ptr != q->write_ptr && !time_after(jiffies,
- now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS)))
- msleep(1);
-
- if (q->read_ptr != q->write_ptr) {
- IWL_ERR(priv, "fail to flush all tx fifo queues\n");
- ret = -ETIMEDOUT;
- break;
- }
- }
- return ret;
-}
-
-#define IWL_TX_QUEUE_MSK 0xfffff
-
/**
* iwlagn_txfifo_flush: send REPLY_TXFIFO_FLUSH command to uCode
*
@@ -1160,7 +226,7 @@ int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
IWL_SCD_BE_MSK | IWL_SCD_BK_MSK |
IWL_SCD_MGMT_MSK;
if ((flush_control & BIT(IWL_RXON_CTX_PAN)) &&
- (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)))
+ (priv->shrd->valid_contexts != BIT(IWL_RXON_CTX_BSS)))
flush_cmd.fifo_control |= IWL_PAN_SCD_VO_MSK |
IWL_PAN_SCD_VI_MSK | IWL_PAN_SCD_BE_MSK |
IWL_PAN_SCD_BK_MSK | IWL_PAN_SCD_MGMT_MSK |
@@ -1173,22 +239,22 @@ int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
flush_cmd.fifo_control);
flush_cmd.flush_control = cpu_to_le16(flush_control);
- return trans_send_cmd(&priv->trans, &cmd);
+ return iwl_trans_send_cmd(trans(priv), &cmd);
}
void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
{
- mutex_lock(&priv->mutex);
+ mutex_lock(&priv->shrd->mutex);
ieee80211_stop_queues(priv->hw);
if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) {
IWL_ERR(priv, "flush request fail\n");
goto done;
}
IWL_DEBUG_INFO(priv, "wait transmit/flush all frames\n");
- iwlagn_wait_tx_queue_empty(priv);
+ iwl_trans_wait_tx_queue_empty(trans(priv));
done:
ieee80211_wake_queues(priv->hw);
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
}
/*
@@ -1367,12 +433,12 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
if (priv->cfg->bt_params->bt_session_2) {
memcpy(&bt_cmd_2000.basic, &basic,
sizeof(basic));
- ret = trans_send_cmd_pdu(&priv->trans, REPLY_BT_CONFIG,
+ ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_BT_CONFIG,
CMD_SYNC, sizeof(bt_cmd_2000), &bt_cmd_2000);
} else {
memcpy(&bt_cmd_6000.basic, &basic,
sizeof(basic));
- ret = trans_send_cmd_pdu(&priv->trans, REPLY_BT_CONFIG,
+ ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_BT_CONFIG,
CMD_SYNC, sizeof(bt_cmd_6000), &bt_cmd_6000);
}
if (ret)
@@ -1385,7 +451,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->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
/* Check whether AP or GO mode is active. */
if (rssi_ena) {
@@ -1498,7 +564,7 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work)
break;
}
- mutex_lock(&priv->mutex);
+ mutex_lock(&priv->shrd->mutex);
/*
* We can not send command to firmware while scanning. When the scan
@@ -1507,7 +573,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->status))
+ if (test_bit(STATUS_SCAN_HW, &priv->shrd->status))
goto out;
iwl_update_chain_flags(priv);
@@ -1526,7 +592,7 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work)
*/
iwlagn_bt_coex_rssi_monitor(priv);
out:
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
}
/*
@@ -1633,12 +699,13 @@ 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->workqueue, &priv->bt_runtime_config);
+ queue_work(priv->shrd->workqueue, &priv->bt_runtime_config);
}
}
-void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
+int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb,
+ struct iwl_device_cmd *cmd)
{
unsigned long flags;
struct iwl_rx_packet *pkt = rxb_addr(rxb);
@@ -1647,7 +714,7 @@ void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
if (priv->bt_enable_flag == IWLAGN_BT_FLAG_COEX_MODE_DISABLED) {
/* bt coex disabled */
- return;
+ return 0;
}
IWL_DEBUG_COEX(priv, "BT Coex notification:\n");
@@ -1677,7 +744,7 @@ void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
IWL_BT_COEX_TRAFFIC_LOAD_NONE;
}
priv->bt_status = coex->bt_status;
- queue_work(priv->workqueue,
+ queue_work(priv->shrd->workqueue,
&priv->bt_traffic_change_work);
}
}
@@ -1686,9 +753,10 @@ void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
/* FIXME: based on notification, adjust the prio_boost */
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&priv->shrd->lock, flags);
priv->bt_ci_compliance = coex->bt_ci_compliance;
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->lock, flags);
+ return 0;
}
void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv)
@@ -1788,7 +856,7 @@ static u8 iwl_count_chain_bitmap(u32 chain_bitmap)
void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
{
bool is_single = is_single_rx_stream(priv);
- bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
+ bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->shrd->status);
u8 idle_rx_cnt, active_rx_cnt, valid_rx_cnt;
u32 active_chains;
u16 rx_chain;
@@ -1800,7 +868,7 @@ void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
if (priv->chain_noise_data.active_chains)
active_chains = priv->chain_noise_data.active_chains;
else
- active_chains = priv->hw_params.valid_rx_ant;
+ active_chains = hw_params(priv).valid_rx_ant;
if (priv->cfg->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist &&
@@ -1865,136 +933,6 @@ u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant, u8 valid)
return ant;
}
-static const char *get_csr_string(int cmd)
-{
- switch (cmd) {
- IWL_CMD(CSR_HW_IF_CONFIG_REG);
- IWL_CMD(CSR_INT_COALESCING);
- IWL_CMD(CSR_INT);
- IWL_CMD(CSR_INT_MASK);
- IWL_CMD(CSR_FH_INT_STATUS);
- IWL_CMD(CSR_GPIO_IN);
- IWL_CMD(CSR_RESET);
- IWL_CMD(CSR_GP_CNTRL);
- IWL_CMD(CSR_HW_REV);
- IWL_CMD(CSR_EEPROM_REG);
- IWL_CMD(CSR_EEPROM_GP);
- IWL_CMD(CSR_OTP_GP_REG);
- IWL_CMD(CSR_GIO_REG);
- IWL_CMD(CSR_GP_UCODE_REG);
- IWL_CMD(CSR_GP_DRIVER_REG);
- IWL_CMD(CSR_UCODE_DRV_GP1);
- IWL_CMD(CSR_UCODE_DRV_GP2);
- IWL_CMD(CSR_LED_REG);
- IWL_CMD(CSR_DRAM_INT_TBL_REG);
- IWL_CMD(CSR_GIO_CHICKEN_BITS);
- IWL_CMD(CSR_ANA_PLL_CFG);
- IWL_CMD(CSR_HW_REV_WA_REG);
- IWL_CMD(CSR_DBG_HPET_MEM_REG);
- default:
- return "UNKNOWN";
- }
-}
-
-void iwl_dump_csr(struct iwl_priv *priv)
-{
- int i;
- static const u32 csr_tbl[] = {
- CSR_HW_IF_CONFIG_REG,
- CSR_INT_COALESCING,
- CSR_INT,
- CSR_INT_MASK,
- CSR_FH_INT_STATUS,
- CSR_GPIO_IN,
- CSR_RESET,
- CSR_GP_CNTRL,
- CSR_HW_REV,
- CSR_EEPROM_REG,
- CSR_EEPROM_GP,
- CSR_OTP_GP_REG,
- CSR_GIO_REG,
- CSR_GP_UCODE_REG,
- CSR_GP_DRIVER_REG,
- CSR_UCODE_DRV_GP1,
- CSR_UCODE_DRV_GP2,
- CSR_LED_REG,
- CSR_DRAM_INT_TBL_REG,
- CSR_GIO_CHICKEN_BITS,
- CSR_ANA_PLL_CFG,
- CSR_HW_REV_WA_REG,
- CSR_DBG_HPET_MEM_REG
- };
- IWL_ERR(priv, "CSR values:\n");
- IWL_ERR(priv, "(2nd byte of CSR_INT_COALESCING is "
- "CSR_INT_PERIODIC_REG)\n");
- for (i = 0; i < ARRAY_SIZE(csr_tbl); i++) {
- IWL_ERR(priv, " %25s: 0X%08x\n",
- get_csr_string(csr_tbl[i]),
- iwl_read32(priv, csr_tbl[i]));
- }
-}
-
-static const char *get_fh_string(int cmd)
-{
- switch (cmd) {
- IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG);
- IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG);
- IWL_CMD(FH_RSCSR_CHNL0_WPTR);
- IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG);
- IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG);
- IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG);
- IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV);
- IWL_CMD(FH_TSSR_TX_STATUS_REG);
- IWL_CMD(FH_TSSR_TX_ERROR_REG);
- default:
- return "UNKNOWN";
- }
-}
-
-int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display)
-{
- int i;
-#ifdef CONFIG_IWLWIFI_DEBUG
- int pos = 0;
- size_t bufsz = 0;
-#endif
- static const u32 fh_tbl[] = {
- FH_RSCSR_CHNL0_STTS_WPTR_REG,
- FH_RSCSR_CHNL0_RBDCB_BASE_REG,
- FH_RSCSR_CHNL0_WPTR,
- FH_MEM_RCSR_CHNL0_CONFIG_REG,
- FH_MEM_RSSR_SHARED_CTRL_REG,
- FH_MEM_RSSR_RX_STATUS_REG,
- FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV,
- FH_TSSR_TX_STATUS_REG,
- FH_TSSR_TX_ERROR_REG
- };
-#ifdef CONFIG_IWLWIFI_DEBUG
- if (display) {
- bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40;
- *buf = kmalloc(bufsz, GFP_KERNEL);
- if (!*buf)
- return -ENOMEM;
- pos += scnprintf(*buf + pos, bufsz - pos,
- "FH register values:\n");
- for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) {
- pos += scnprintf(*buf + pos, bufsz - pos,
- " %34s: 0X%08x\n",
- get_fh_string(fh_tbl[i]),
- iwl_read_direct32(priv, fh_tbl[i]));
- }
- return pos;
- }
-#endif
- IWL_ERR(priv, "FH register values:\n");
- for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) {
- IWL_ERR(priv, " %34s: 0X%08x\n",
- get_fh_string(fh_tbl[i]),
- iwl_read_direct32(priv, fh_tbl[i]));
- }
- return 0;
-}
-
/* notification wait support */
void iwlagn_init_notification_wait(struct iwl_priv *priv,
struct iwl_notification_wait *wait_entry,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index 3789ff4bf53b..66118cea2af3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -27,7 +27,6 @@
#include <linux/init.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
-#include <linux/wireless.h>
#include <net/mac80211.h>
#include <linux/netdevice.h>
@@ -37,7 +36,6 @@
#include <linux/workqueue.h>
#include "iwl-dev.h"
-#include "iwl-sta.h"
#include "iwl-core.h"
#include "iwl-agn.h"
@@ -298,10 +296,10 @@ static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data,
u8 *qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & 0xf;
} else
- return MAX_TID_COUNT;
+ return IWL_MAX_TID_COUNT;
if (unlikely(tid >= TID_MAX_LOAD_COUNT))
- return MAX_TID_COUNT;
+ return IWL_MAX_TID_COUNT;
tl = &lq_data->load[tid];
@@ -314,7 +312,7 @@ static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data,
tl->queue_count = 1;
tl->head = 0;
tl->packet_count[0] = 1;
- return MAX_TID_COUNT;
+ return IWL_MAX_TID_COUNT;
}
time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time);
@@ -347,7 +345,7 @@ static void rs_program_fix_rate(struct iwl_priv *priv,
{
struct iwl_station_priv *sta_priv =
container_of(lq_sta, struct iwl_station_priv, lq_sta);
- struct iwl_rxon_context *ctx = sta_priv->common.ctx;
+ struct iwl_rxon_context *ctx = sta_priv->ctx;
lq_sta->active_legacy_rate = 0x0FFF; /* 1 - 54 MBits, includes CCK */
lq_sta->active_siso_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */
@@ -421,7 +419,7 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
load = rs_tl_get_load(lq_data, tid);
- if (load > IWL_AGG_LOAD_THRESHOLD) {
+ if ((iwlagn_mod_params.auto_agg) || (load > IWL_AGG_LOAD_THRESHOLD)) {
IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n",
sta->addr, tid);
ret = ieee80211_start_tx_ba_session(sta, tid, 5000);
@@ -711,7 +709,7 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
static bool rs_use_green(struct ieee80211_sta *sta)
{
struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
- struct iwl_rxon_context *ctx = sta_priv->common.ctx;
+ struct iwl_rxon_context *ctx = sta_priv->ctx;
return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) &&
!(ctx->ht.non_gf_sta_present);
@@ -820,7 +818,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
if (num_of_ant(tbl->ant_type) > 1)
tbl->ant_type =
- first_antenna(priv->hw_params.valid_tx_ant);
+ first_antenna(hw_params(priv).valid_tx_ant);
tbl->is_ht40 = 0;
tbl->is_SGI = 0;
@@ -878,12 +876,12 @@ static void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
* Is there a need to switch between
* full concurrency and 3-wire?
*/
- spin_lock_irqsave(&priv->lock, flags);
+ 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->lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->lock, flags);
}
if ((priv->bt_traffic_load != priv->last_bt_traffic_load) ||
(priv->bt_full_concurrent != full_concurrent)) {
@@ -894,7 +892,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->workqueue, &priv->bt_full_concurrency);
+ queue_work(priv->shrd->workqueue, &priv->bt_full_concurrency);
}
}
@@ -918,7 +916,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
struct iwl_scale_tbl_info tbl_type;
struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;
struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
- struct iwl_rxon_context *ctx = sta_priv->common.ctx;
+ struct iwl_rxon_context *ctx = sta_priv->ctx;
IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n");
@@ -1284,7 +1282,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
s32 rate;
s8 is_green = lq_sta->is_green;
struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
- struct iwl_rxon_context *ctx = sta_priv->common.ctx;
+ struct iwl_rxon_context *ctx = sta_priv->ctx;
if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
return -1;
@@ -1294,7 +1292,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
return -1;
/* Need both Tx chains/antennas to support MIMO */
- if (priv->hw_params.tx_chains_num < 2)
+ if (hw_params(priv).tx_chains_num < 2)
return -1;
IWL_DEBUG_RATE(priv, "LQ: try to switch to MIMO2\n");
@@ -1340,7 +1338,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv,
s32 rate;
s8 is_green = lq_sta->is_green;
struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
- struct iwl_rxon_context *ctx = sta_priv->common.ctx;
+ struct iwl_rxon_context *ctx = sta_priv->ctx;
if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
return -1;
@@ -1350,7 +1348,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv,
return -1;
/* Need both Tx chains/antennas to support MIMO */
- if (priv->hw_params.tx_chains_num < 3)
+ if (hw_params(priv).tx_chains_num < 3)
return -1;
IWL_DEBUG_RATE(priv, "LQ: try to switch to MIMO3\n");
@@ -1397,7 +1395,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
u8 is_green = lq_sta->is_green;
s32 rate;
struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
- struct iwl_rxon_context *ctx = sta_priv->common.ctx;
+ struct iwl_rxon_context *ctx = sta_priv->ctx;
if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
return -1;
@@ -1449,8 +1447,8 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
u8 start_action;
- u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
- u8 tx_chains_num = priv->hw_params.tx_chains_num;
+ u8 valid_tx_ant = hw_params(priv).valid_tx_ant;
+ u8 tx_chains_num = hw_params(priv).tx_chains_num;
int ret = 0;
u8 update_search_tbl_counter = 0;
@@ -1460,14 +1458,16 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
break;
case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
/* avoid antenna B unless MIMO */
- valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant);
+ valid_tx_ant =
+ first_antenna(hw_params(priv).valid_tx_ant);
if (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2)
tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
break;
case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
/* avoid antenna B and MIMO */
- valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant);
+ valid_tx_ant =
+ first_antenna(hw_params(priv).valid_tx_ant);
if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2 &&
tbl->action != IWL_LEGACY_SWITCH_SISO)
tbl->action = IWL_LEGACY_SWITCH_SISO;
@@ -1490,7 +1490,8 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
else if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2)
tbl->action = IWL_LEGACY_SWITCH_SISO;
- valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant);
+ valid_tx_ant =
+ first_antenna(hw_params(priv).valid_tx_ant);
}
start_action = tbl->action;
@@ -1624,8 +1625,8 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
u8 start_action;
- u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
- u8 tx_chains_num = priv->hw_params.tx_chains_num;
+ u8 valid_tx_ant = hw_params(priv).valid_tx_ant;
+ u8 tx_chains_num = hw_params(priv).tx_chains_num;
u8 update_search_tbl_counter = 0;
int ret;
@@ -1635,14 +1636,16 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
break;
case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
/* avoid antenna B unless MIMO */
- valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant);
+ valid_tx_ant =
+ first_antenna(hw_params(priv).valid_tx_ant);
if (tbl->action == IWL_SISO_SWITCH_ANTENNA2)
tbl->action = IWL_SISO_SWITCH_ANTENNA1;
break;
case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
/* avoid antenna B and MIMO */
- valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant);
+ valid_tx_ant =
+ first_antenna(hw_params(priv).valid_tx_ant);
if (tbl->action != IWL_SISO_SWITCH_ANTENNA1)
tbl->action = IWL_SISO_SWITCH_ANTENNA1;
break;
@@ -1659,7 +1662,8 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
/* configure as 1x1 if bt full concurrency */
if (priv->bt_full_concurrent) {
- valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant);
+ valid_tx_ant =
+ first_antenna(hw_params(priv).valid_tx_ant);
if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2)
tbl->action = IWL_SISO_SWITCH_ANTENNA1;
}
@@ -1795,8 +1799,8 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
u8 start_action;
- u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
- u8 tx_chains_num = priv->hw_params.tx_chains_num;
+ u8 valid_tx_ant = hw_params(priv).valid_tx_ant;
+ u8 tx_chains_num = hw_params(priv).tx_chains_num;
u8 update_search_tbl_counter = 0;
int ret;
@@ -1965,8 +1969,8 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
u8 start_action;
- u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
- u8 tx_chains_num = priv->hw_params.tx_chains_num;
+ u8 valid_tx_ant = hw_params(priv).valid_tx_ant;
+ u8 tx_chains_num = hw_params(priv).tx_chains_num;
int ret;
u8 update_search_tbl_counter = 0;
@@ -2209,7 +2213,6 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
/*
* setup rate table in uCode
- * return rate_n_flags as used in the table
*/
static void rs_update_rate_tbl(struct iwl_priv *priv,
struct iwl_rxon_context *ctx,
@@ -2256,10 +2259,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
u8 done_search = 0;
u16 high_low;
s32 sr;
- u8 tid = MAX_TID_COUNT;
+ u8 tid = IWL_MAX_TID_COUNT;
struct iwl_tid_data *tid_data;
struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
- struct iwl_rxon_context *ctx = sta_priv->common.ctx;
+ struct iwl_rxon_context *ctx = sta_priv->ctx;
IWL_DEBUG_RATE(priv, "rate scale calculate new rate for skb\n");
@@ -2269,14 +2272,12 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
info->flags & IEEE80211_TX_CTL_NO_ACK)
return;
- if (!sta || !lq_sta)
- return;
-
lq_sta->supp_rates = sta->supp_rates[lq_sta->band];
tid = rs_tl_add_packet(lq_sta, hdr);
- if ((tid != MAX_TID_COUNT) && (lq_sta->tx_agg_tid_en & (1 << tid))) {
- tid_data = &priv->stations[lq_sta->lq.sta_id].tid[tid];
+ if ((tid != IWL_MAX_TID_COUNT) &&
+ (lq_sta->tx_agg_tid_en & (1 << tid))) {
+ tid_data = &priv->shrd->tid_data[lq_sta->lq.sta_id][tid];
if (tid_data->agg.state == IWL_AGG_OFF)
lq_sta->is_agg = 0;
else
@@ -2646,9 +2647,10 @@ lq_update:
iwl_ht_enabled(priv)) {
if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) &&
(lq_sta->tx_agg_tid_en & (1 << tid)) &&
- (tid != MAX_TID_COUNT)) {
+ (tid != IWL_MAX_TID_COUNT)) {
+ u8 sta_id = lq_sta->lq.sta_id;
tid_data =
- &priv->stations[lq_sta->lq.sta_id].tid[tid];
+ &priv->shrd->tid_data[sta_id][tid];
if (tid_data->agg.state == IWL_AGG_OFF) {
IWL_DEBUG_RATE(priv,
"try to aggregate tid %d\n",
@@ -2663,8 +2665,7 @@ lq_update:
out:
tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
- i = index;
- lq_sta->last_txrate_idx = i;
+ lq_sta->last_txrate_idx = index;
}
/**
@@ -2700,11 +2701,11 @@ static void rs_initialize_lq(struct iwl_priv *priv,
return;
sta_priv = (void *)sta->drv_priv;
- ctx = sta_priv->common.ctx;
+ ctx = sta_priv->ctx;
i = lq_sta->last_txrate_idx;
- valid_tx_ant = priv->hw_params.valid_tx_ant;
+ valid_tx_ant = hw_params(priv).valid_tx_ant;
if (!lq_sta->search_better_tbl)
active_tbl = lq_sta->active_tbl;
@@ -2887,15 +2888,15 @@ void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_i
/* These values will be overridden later */
lq_sta->lq.general_params.single_stream_ant_msk =
- first_antenna(priv->hw_params.valid_tx_ant);
+ first_antenna(hw_params(priv).valid_tx_ant);
lq_sta->lq.general_params.dual_stream_ant_msk =
- priv->hw_params.valid_tx_ant &
- ~first_antenna(priv->hw_params.valid_tx_ant);
+ hw_params(priv).valid_tx_ant &
+ ~first_antenna(hw_params(priv).valid_tx_ant);
if (!lq_sta->lq.general_params.dual_stream_ant_msk) {
lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB;
- } else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) {
+ } else if (num_of_ant(hw_params(priv).valid_tx_ant) == 2) {
lq_sta->lq.general_params.dual_stream_ant_msk =
- priv->hw_params.valid_tx_ant;
+ hw_params(priv).valid_tx_ant;
}
/* as default allow aggregation for all tids */
@@ -2941,7 +2942,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
if (priv && priv->bt_full_concurrent) {
/* 1x1 only */
tbl_type.ant_type =
- first_antenna(priv->hw_params.valid_tx_ant);
+ first_antenna(hw_params(priv).valid_tx_ant);
}
/* How many times should we repeat the initial rate? */
@@ -2973,7 +2974,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
if (priv->bt_full_concurrent)
valid_tx_ant = ANT_A;
else
- valid_tx_ant = priv->hw_params.valid_tx_ant;
+ valid_tx_ant = hw_params(priv).valid_tx_ant;
}
/* Fill rest of rate table */
@@ -3007,7 +3008,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
if (priv && priv->bt_full_concurrent) {
/* 1x1 only */
tbl_type.ant_type =
- first_antenna(priv->hw_params.valid_tx_ant);
+ first_antenna(hw_params(priv).valid_tx_ant);
}
/* Indicate to uCode which entries might be MIMO.
@@ -3098,7 +3099,7 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
u8 ant_sel_tx;
priv = lq_sta->drv;
- valid_tx_ant = priv->hw_params.valid_tx_ant;
+ valid_tx_ant = hw_params(priv).valid_tx_ant;
if (lq_sta->dbg_fixed_rate) {
ant_sel_tx =
((lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK)
@@ -3169,9 +3170,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
desc += sprintf(buff+desc, "fixed rate 0x%X\n",
lq_sta->dbg_fixed_rate);
desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n",
- (priv->hw_params.valid_tx_ant & ANT_A) ? "ANT_A," : "",
- (priv->hw_params.valid_tx_ant & ANT_B) ? "ANT_B," : "",
- (priv->hw_params.valid_tx_ant & ANT_C) ? "ANT_C" : "");
+ (hw_params(priv).valid_tx_ant & ANT_A) ? "ANT_A," : "",
+ (hw_params(priv).valid_tx_ant & ANT_B) ? "ANT_B," : "",
+ (hw_params(priv).valid_tx_ant & ANT_C) ? "ANT_C" : "");
desc += sprintf(buff+desc, "lq type %s\n",
(is_legacy(tbl->lq_type)) ? "legacy" : "HT");
if (is_Ht(tbl->lq_type)) {
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
index bdae82e7fa90..f4f6deb829ae 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
@@ -27,6 +27,10 @@
#ifndef __iwl_agn_rs_h__
#define __iwl_agn_rs_h__
+#include <net/mac80211.h>
+
+#include "iwl-commands.h"
+
struct iwl_rate_info {
u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */
u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
index 8e314003b63a..5af9e6258a16 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
@@ -3,7 +3,7 @@
* Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
+ * as portionhelp of the ieee80211 subsystem header files.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -35,12 +35,93 @@
#include "iwl-eeprom.h"
#include "iwl-dev.h"
#include "iwl-core.h"
-#include "iwl-sta.h"
#include "iwl-io.h"
-#include "iwl-helpers.h"
#include "iwl-agn-calib.h"
#include "iwl-agn.h"
+#include "iwl-shared.h"
+const char *get_cmd_string(u8 cmd)
+{
+ switch (cmd) {
+ IWL_CMD(REPLY_ALIVE);
+ IWL_CMD(REPLY_ERROR);
+ IWL_CMD(REPLY_ECHO);
+ IWL_CMD(REPLY_RXON);
+ IWL_CMD(REPLY_RXON_ASSOC);
+ IWL_CMD(REPLY_QOS_PARAM);
+ IWL_CMD(REPLY_RXON_TIMING);
+ IWL_CMD(REPLY_ADD_STA);
+ IWL_CMD(REPLY_REMOVE_STA);
+ IWL_CMD(REPLY_REMOVE_ALL_STA);
+ IWL_CMD(REPLY_TXFIFO_FLUSH);
+ IWL_CMD(REPLY_WEPKEY);
+ IWL_CMD(REPLY_TX);
+ IWL_CMD(REPLY_LEDS_CMD);
+ IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
+ IWL_CMD(COEX_PRIORITY_TABLE_CMD);
+ IWL_CMD(COEX_MEDIUM_NOTIFICATION);
+ IWL_CMD(COEX_EVENT_CMD);
+ IWL_CMD(REPLY_QUIET_CMD);
+ IWL_CMD(REPLY_CHANNEL_SWITCH);
+ IWL_CMD(CHANNEL_SWITCH_NOTIFICATION);
+ IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD);
+ IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION);
+ IWL_CMD(POWER_TABLE_CMD);
+ IWL_CMD(PM_SLEEP_NOTIFICATION);
+ IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC);
+ IWL_CMD(REPLY_SCAN_CMD);
+ IWL_CMD(REPLY_SCAN_ABORT_CMD);
+ IWL_CMD(SCAN_START_NOTIFICATION);
+ IWL_CMD(SCAN_RESULTS_NOTIFICATION);
+ IWL_CMD(SCAN_COMPLETE_NOTIFICATION);
+ IWL_CMD(BEACON_NOTIFICATION);
+ IWL_CMD(REPLY_TX_BEACON);
+ IWL_CMD(WHO_IS_AWAKE_NOTIFICATION);
+ IWL_CMD(QUIET_NOTIFICATION);
+ IWL_CMD(REPLY_TX_PWR_TABLE_CMD);
+ IWL_CMD(MEASURE_ABORT_NOTIFICATION);
+ IWL_CMD(REPLY_BT_CONFIG);
+ IWL_CMD(REPLY_STATISTICS_CMD);
+ IWL_CMD(STATISTICS_NOTIFICATION);
+ IWL_CMD(REPLY_CARD_STATE_CMD);
+ IWL_CMD(CARD_STATE_NOTIFICATION);
+ IWL_CMD(MISSED_BEACONS_NOTIFICATION);
+ IWL_CMD(REPLY_CT_KILL_CONFIG_CMD);
+ IWL_CMD(SENSITIVITY_CMD);
+ IWL_CMD(REPLY_PHY_CALIBRATION_CMD);
+ IWL_CMD(REPLY_RX_PHY_CMD);
+ IWL_CMD(REPLY_RX_MPDU_CMD);
+ IWL_CMD(REPLY_RX);
+ IWL_CMD(REPLY_COMPRESSED_BA);
+ IWL_CMD(CALIBRATION_CFG_CMD);
+ IWL_CMD(CALIBRATION_RES_NOTIFICATION);
+ IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION);
+ IWL_CMD(REPLY_TX_POWER_DBM_CMD);
+ IWL_CMD(TEMPERATURE_NOTIFICATION);
+ IWL_CMD(TX_ANT_CONFIGURATION_CMD);
+ IWL_CMD(REPLY_BT_COEX_PROFILE_NOTIF);
+ IWL_CMD(REPLY_BT_COEX_PRIO_TABLE);
+ IWL_CMD(REPLY_BT_COEX_PROT_ENV);
+ IWL_CMD(REPLY_WIPAN_PARAMS);
+ IWL_CMD(REPLY_WIPAN_RXON);
+ IWL_CMD(REPLY_WIPAN_RXON_TIMING);
+ IWL_CMD(REPLY_WIPAN_RXON_ASSOC);
+ IWL_CMD(REPLY_WIPAN_QOS_PARAM);
+ IWL_CMD(REPLY_WIPAN_WEPKEY);
+ IWL_CMD(REPLY_WIPAN_P2P_CHANNEL_SWITCH);
+ IWL_CMD(REPLY_WIPAN_NOA_NOTIFICATION);
+ IWL_CMD(REPLY_WIPAN_DEACTIVATION_COMPLETE);
+ IWL_CMD(REPLY_WOWLAN_PATTERNS);
+ IWL_CMD(REPLY_WOWLAN_WAKEUP_FILTER);
+ IWL_CMD(REPLY_WOWLAN_TSC_RSC_PARAMS);
+ IWL_CMD(REPLY_WOWLAN_TKIP_PARAMS);
+ IWL_CMD(REPLY_WOWLAN_KEK_KCK_MATERIAL);
+ IWL_CMD(REPLY_WOWLAN_GET_STATUS);
+ default:
+ return "UNKNOWN";
+
+ }
+}
/******************************************************************************
*
@@ -48,8 +129,9 @@
*
******************************************************************************/
-static void iwl_rx_reply_error(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
+static int iwlagn_rx_reply_error(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb,
+ struct iwl_device_cmd *cmd)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
@@ -60,21 +142,23 @@ static void iwl_rx_reply_error(struct iwl_priv *priv,
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));
+ return 0;
}
-static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+static int iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+ struct iwl_device_cmd *cmd)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
/*
* MULTI-FIXME
- * See iwl_mac_channel_switch.
+ * See iwlagn_mac_channel_switch.
*/
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->status))
- return;
+ if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status))
+ return 0;
if (!le32_to_cpu(csa->status) && csa->channel == priv->switch_channel) {
rxon->channel = csa->channel;
@@ -87,11 +171,13 @@ static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
le16_to_cpu(csa->channel));
iwl_chswitch_done(priv, false);
}
+ return 0;
}
-static void iwl_rx_spectrum_measure_notif(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_device_cmd *cmd)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
@@ -99,15 +185,17 @@ static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
if (!report->state) {
IWL_DEBUG_11H(priv,
"Spectrum Measure Notification: Start\n");
- return;
+ return 0;
}
memcpy(&priv->measure_report, report, sizeof(*report));
priv->measurement_status |= MEASUREMENT_READY;
+ return 0;
}
-static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
+static int iwlagn_rx_pm_sleep_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb,
+ struct iwl_device_cmd *cmd)
{
#ifdef CONFIG_IWLWIFI_DEBUG
struct iwl_rx_packet *pkt = rxb_addr(rxb);
@@ -115,21 +203,26 @@ static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n",
sleep->pm_sleep_mode, sleep->pm_wakeup_src);
#endif
+ return 0;
}
-static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
+static int iwlagn_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb,
+ struct iwl_device_cmd *cmd)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
- u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+ u32 __maybe_unused len =
+ le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
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);
+ return 0;
}
-static void iwl_rx_beacon_notif(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
+static int iwlagn_rx_beacon_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb,
+ struct iwl_device_cmd *cmd)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwlagn_beacon_notif *beacon = (void *)pkt->u.raw;
@@ -148,8 +241,7 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status);
- if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
- queue_work(priv->workqueue, &priv->beacon_update);
+ return 0;
}
/* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */
@@ -164,7 +256,7 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
* the BA_TIMEOUT_MAX, reload firmware and bring system back to normal
* operation state.
*/
-static bool iwl_good_ack_health(struct iwl_priv *priv,
+static bool iwlagn_good_ack_health(struct iwl_priv *priv,
struct statistics_tx *cur)
{
int actual_delta, expected_delta, ba_timeout_delta;
@@ -189,8 +281,9 @@ static bool iwl_good_ack_health(struct iwl_priv *priv,
if ((actual_delta * 100 / expected_delta) < ACK_CNT_RATIO &&
ba_timeout_delta > BA_TIMEOUT_CNT) {
- IWL_DEBUG_RADIO(priv, "deltas: actual %d expected %d ba_timeout %d\n",
- actual_delta, expected_delta, ba_timeout_delta);
+ IWL_DEBUG_RADIO(priv,
+ "deltas: actual %d expected %d ba_timeout %d\n",
+ actual_delta, expected_delta, ba_timeout_delta);
#ifdef CONFIG_IWLWIFI_DEBUGFS
/*
@@ -218,7 +311,7 @@ static bool iwl_good_ack_health(struct iwl_priv *priv,
* When the plcp error is exceeding the thresholds, reset the radio
* to improve the throughput.
*/
-static bool iwl_good_plcp_health(struct iwl_priv *priv,
+static bool iwlagn_good_plcp_health(struct iwl_priv *priv,
struct statistics_rx_phy *cur_ofdm,
struct statistics_rx_ht_phy *cur_ofdm_ht,
unsigned int msecs)
@@ -250,15 +343,15 @@ static bool iwl_good_plcp_health(struct iwl_priv *priv,
return true;
}
-static void iwl_recover_from_statistics(struct iwl_priv *priv,
- struct statistics_rx_phy *cur_ofdm,
- struct statistics_rx_ht_phy *cur_ofdm_ht,
- struct statistics_tx *tx,
- unsigned long stamp)
+static void iwlagn_recover_from_statistics(struct iwl_priv *priv,
+ struct statistics_rx_phy *cur_ofdm,
+ struct statistics_rx_ht_phy *cur_ofdm_ht,
+ struct statistics_tx *tx,
+ unsigned long stamp)
{
unsigned int msecs;
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
return;
msecs = jiffies_to_msecs(stamp - priv->rx_statistics_jiffies);
@@ -271,21 +364,21 @@ static void iwl_recover_from_statistics(struct iwl_priv *priv,
if (msecs < 99)
return;
- if (iwlagn_mod_params.ack_check && !iwl_good_ack_health(priv, tx)) {
+ if (iwlagn_mod_params.ack_check && !iwlagn_good_ack_health(priv, tx)) {
IWL_ERR(priv, "low ack count detected, restart firmware\n");
if (!iwl_force_reset(priv, IWL_FW_RESET, false))
return;
}
if (iwlagn_mod_params.plcp_check &&
- !iwl_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs))
+ !iwlagn_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs))
iwl_force_reset(priv, IWL_RF_RESET, false);
}
/* Calculate noise level, based on measurements during network silence just
* before arriving beacon. This measurement can be done only if we know
* exactly when to expect beacons, therefore only when we're associated. */
-static void iwl_rx_calc_noise(struct iwl_priv *priv)
+static void iwlagn_rx_calc_noise(struct iwl_priv *priv)
{
struct statistics_rx_non_phy *rx_info;
int num_active_rx = 0;
@@ -351,7 +444,7 @@ static void accum_stats(__le32 *prev, __le32 *cur, __le32 *delta,
}
static void
-iwl_accumulative_statistics(struct iwl_priv *priv,
+iwlagn_accumulative_statistics(struct iwl_priv *priv,
struct statistics_general_common *common,
struct statistics_rx_non_phy *rx_non_phy,
struct statistics_rx_phy *rx_ofdm,
@@ -380,7 +473,7 @@ iwl_accumulative_statistics(struct iwl_priv *priv,
}
#else
static inline void
-iwl_accumulative_statistics(struct iwl_priv *priv,
+iwlagn_accumulative_statistics(struct iwl_priv *priv,
struct statistics_general_common *common,
struct statistics_rx_non_phy *rx_non_phy,
struct statistics_rx_phy *rx_ofdm,
@@ -392,8 +485,9 @@ iwl_accumulative_statistics(struct iwl_priv *priv,
}
#endif
-static void iwl_rx_statistics(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
+static int iwlagn_rx_statistics(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb,
+ struct iwl_device_cmd *cmd)
{
unsigned long stamp = jiffies;
const int reg_recalib_period = 60;
@@ -447,17 +541,17 @@ static void iwl_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));
- return;
+ return 0;
}
change = common->temperature != priv->statistics.common.temperature ||
(*flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
(priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK);
- iwl_accumulative_statistics(priv, common, rx_non_phy, rx_ofdm,
+ iwlagn_accumulative_statistics(priv, common, rx_non_phy, rx_ofdm,
rx_ofdm_ht, rx_cck, tx, bt_activity);
- iwl_recover_from_statistics(priv, rx_ofdm, rx_ofdm_ht, tx, stamp);
+ iwlagn_recover_from_statistics(priv, rx_ofdm, rx_ofdm_ht, tx, stamp);
priv->statistics.flag = *flag;
memcpy(&priv->statistics.common, common, sizeof(*common));
@@ -474,7 +568,7 @@ static void iwl_rx_statistics(struct iwl_priv *priv,
priv->rx_statistics_jiffies = stamp;
- set_bit(STATUS_STATISTICS, &priv->status);
+ set_bit(STATUS_STATISTICS, &priv->shrd->status);
/* Reschedule the statistics timer to occur in
* reg_recalib_period seconds to ensure we get a
@@ -483,17 +577,19 @@ static void iwl_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->status)) &&
+ if (unlikely(!test_bit(STATUS_SCANNING, &priv->shrd->status)) &&
(pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
- iwl_rx_calc_noise(priv);
- queue_work(priv->workqueue, &priv->run_time_calib_work);
+ iwlagn_rx_calc_noise(priv);
+ queue_work(priv->shrd->workqueue, &priv->run_time_calib_work);
}
if (priv->cfg->lib->temperature && change)
priv->cfg->lib->temperature(priv);
+ return 0;
}
-static void iwl_rx_reply_statistics(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
+static int iwlagn_rx_reply_statistics(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb,
+ struct iwl_device_cmd *cmd)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
@@ -508,17 +604,19 @@ static void iwl_rx_reply_statistics(struct iwl_priv *priv,
#endif
IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
}
- iwl_rx_statistics(priv, rxb);
+ iwlagn_rx_statistics(priv, rxb, cmd);
+ return 0;
}
/* Handle notification from uCode that card's power state is changing
* due to software, hardware, or critical temperature RFKILL */
-static void iwl_rx_card_state_notif(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
+static int iwlagn_rx_card_state_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_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->status;
+ unsigned long status = priv->shrd->status;
IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s CT:%s\n",
(flags & HW_CARD_DISABLED) ? "Kill" : "On",
@@ -529,16 +627,16 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED |
CT_CARD_DISABLED)) {
- iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+ iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_SET,
CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
- iwl_write_direct32(priv, HBUS_TARG_MBX_C,
+ iwl_write_direct32(bus(priv), HBUS_TARG_MBX_C,
HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
if (!(flags & RXON_CARD_DISABLED)) {
- iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+ iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR,
CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
- iwl_write_direct32(priv, HBUS_TARG_MBX_C,
+ iwl_write_direct32(bus(priv), HBUS_TARG_MBX_C,
HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
}
if (flags & CT_CARD_DISABLED)
@@ -548,24 +646,26 @@ static void iwl_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->status);
+ set_bit(STATUS_RF_KILL_HW, &priv->shrd->status);
else
- clear_bit(STATUS_RF_KILL_HW, &priv->status);
+ clear_bit(STATUS_RF_KILL_HW, &priv->shrd->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->status)))
+ test_bit(STATUS_RF_KILL_HW, &priv->shrd->status)))
wiphy_rfkill_set_hw_state(priv->hw->wiphy,
- test_bit(STATUS_RF_KILL_HW, &priv->status));
+ test_bit(STATUS_RF_KILL_HW, &priv->shrd->status));
else
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->shrd->wait_command_queue);
+ return 0;
}
-static void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
+static int iwlagn_rx_missed_beacon_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb,
+ struct iwl_device_cmd *cmd)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
@@ -580,27 +680,30 @@ static void iwl_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->status))
+ if (!test_bit(STATUS_SCANNING, &priv->shrd->status))
iwl_init_sensitivity(priv);
}
+ return 0;
}
/* 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 void iwl_rx_reply_rx_phy(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
+static int iwlagn_rx_reply_rx_phy(struct iwl_priv *priv,
+ struct iwl_rx_mem_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,
sizeof(struct iwl_rx_phy_res));
+ return 0;
}
/*
* returns non-zero if packet should be dropped
*/
-static int iwl_set_decrypted_flag(struct iwl_priv *priv,
+static int iwlagn_set_decrypted_flag(struct iwl_priv *priv,
struct ieee80211_hdr *hdr,
u32 decrypt_res,
struct ieee80211_rx_status *stats)
@@ -649,7 +752,7 @@ static int iwl_set_decrypted_flag(struct iwl_priv *priv,
return 0;
}
-static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
+static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
struct ieee80211_hdr *hdr,
u16 len,
u32 ampdu_status,
@@ -669,7 +772,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
/* In case of HW accelerated crypto and bad decryption, drop */
if (!iwlagn_mod_params.sw_crypto &&
- iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats))
+ iwlagn_set_decrypted_flag(priv, hdr, ampdu_status, stats))
return;
skb = dev_alloc_skb(128);
@@ -697,7 +800,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
ctx->active.bssid_addr))
continue;
ctx->last_tx_rejected = false;
- iwl_wake_any_queue(priv, ctx);
+ iwl_trans_wake_any_queue(trans(priv), ctx->ctxid);
}
}
@@ -707,7 +810,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
rxb->page = NULL;
}
-static u32 iwl_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
+static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
{
u32 decrypt_out = 0;
@@ -809,8 +912,9 @@ 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 void iwl_rx_reply_rx(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
+static int iwlagn_rx_reply_rx(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb,
+ struct iwl_device_cmd *cmd)
{
struct ieee80211_hdr *header;
struct ieee80211_rx_status rx_status;
@@ -843,28 +947,28 @@ static void iwl_rx_reply_rx(struct iwl_priv *priv,
} else {
if (!priv->last_phy_res_valid) {
IWL_ERR(priv, "MPDU frame without cached PHY data\n");
- return;
+ 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));
len = le16_to_cpu(amsdu->byte_count);
rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len);
- ampdu_status = iwl_translate_rx_status(priv,
+ ampdu_status = iwlagn_translate_rx_status(priv,
le32_to_cpu(rx_pkt_status));
}
if ((unlikely(phy_res->cfg_phy_cnt > 20))) {
IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n",
phy_res->cfg_phy_cnt);
- return;
+ return 0;
}
if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) ||
!(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n",
le32_to_cpu(rx_pkt_status));
- return;
+ return 0;
}
/* This will be used in several places later */
@@ -923,8 +1027,9 @@ static void iwl_rx_reply_rx(struct iwl_priv *priv,
if (rate_n_flags & RATE_MCS_SGI_MSK)
rx_status.flag |= RX_FLAG_SHORT_GI;
- iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status,
+ iwlagn_pass_packet_to_mac80211(priv, header, len, ampdu_status,
rxb, &rx_status);
+ return 0;
}
/**
@@ -935,36 +1040,42 @@ static void iwl_rx_reply_rx(struct iwl_priv *priv,
*/
void iwl_setup_rx_handlers(struct iwl_priv *priv)
{
- void (**handlers)(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
+ int (**handlers)(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+ struct iwl_device_cmd *cmd);
handlers = priv->rx_handlers;
- handlers[REPLY_ERROR] = iwl_rx_reply_error;
- handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa;
- handlers[SPECTRUM_MEASURE_NOTIFICATION] = iwl_rx_spectrum_measure_notif;
- handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif;
- handlers[PM_DEBUG_STATISTIC_NOTIFIC] = iwl_rx_pm_debug_statistics_notif;
- handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif;
+ handlers[REPLY_ERROR] = iwlagn_rx_reply_error;
+ handlers[CHANNEL_SWITCH_NOTIFICATION] = iwlagn_rx_csa;
+ handlers[SPECTRUM_MEASURE_NOTIFICATION] =
+ iwlagn_rx_spectrum_measure_notif;
+ handlers[PM_SLEEP_NOTIFICATION] = iwlagn_rx_pm_sleep_notif;
+ handlers[PM_DEBUG_STATISTIC_NOTIFIC] =
+ iwlagn_rx_pm_debug_statistics_notif;
+ handlers[BEACON_NOTIFICATION] = iwlagn_rx_beacon_notif;
+ handlers[REPLY_ADD_STA] = iwl_add_sta_callback;
/*
* The same handler is used for both the REPLY to a discrete
* statistics request from the host as well as for the periodic
* statistics notifications (after received beacons) from the uCode.
*/
- handlers[REPLY_STATISTICS_CMD] = iwl_rx_reply_statistics;
- handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics;
+ handlers[REPLY_STATISTICS_CMD] = iwlagn_rx_reply_statistics;
+ handlers[STATISTICS_NOTIFICATION] = iwlagn_rx_statistics;
iwl_setup_rx_scan_handlers(priv);
- handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif;
- handlers[MISSED_BEACONS_NOTIFICATION] = iwl_rx_missed_beacon_notif;
+ handlers[CARD_STATE_NOTIFICATION] = iwlagn_rx_card_state_notif;
+ handlers[MISSED_BEACONS_NOTIFICATION] =
+ iwlagn_rx_missed_beacon_notif;
/* Rx handlers */
- handlers[REPLY_RX_PHY_CMD] = iwl_rx_reply_rx_phy;
- handlers[REPLY_RX_MPDU_CMD] = iwl_rx_reply_rx;
+ handlers[REPLY_RX_PHY_CMD] = iwlagn_rx_reply_rx_phy;
+ handlers[REPLY_RX_MPDU_CMD] = iwlagn_rx_reply_rx;
/* block ack */
- handlers[REPLY_COMPRESSED_BA] = iwlagn_rx_reply_compressed_ba;
+ handlers[REPLY_COMPRESSED_BA] =
+ iwlagn_rx_reply_compressed_ba;
/* init calibration handlers */
priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] =
@@ -982,9 +1093,11 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv)
}
-void iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+int iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+ struct iwl_device_cmd *cmd)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ int err = 0;
/*
* Do the notification wait before RX handlers so
@@ -1018,12 +1131,13 @@ void iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
* handle those that need handling via function in
* rx_handlers table. See iwl_setup_rx_handlers() */
if (priv->rx_handlers[pkt->hdr.cmd]) {
- priv->isr_stats.rx_handlers[pkt->hdr.cmd]++;
- priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
+ priv->rx_handlers_stats[pkt->hdr.cmd]++;
+ err = priv->rx_handlers[pkt->hdr.cmd] (priv, rxb, cmd);
} else {
/* No handling needed */
IWL_DEBUG_RX(priv,
"No handler needed for %s, 0x%02x\n",
get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
}
+ return err;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
index d42ef1763a71..58a381c01c89 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
@@ -26,11 +26,10 @@
#include "iwl-dev.h"
#include "iwl-agn.h"
-#include "iwl-sta.h"
#include "iwl-core.h"
#include "iwl-agn-calib.h"
-#include "iwl-helpers.h"
#include "iwl-trans.h"
+#include "iwl-shared.h"
static int iwlagn_disable_bss(struct iwl_priv *priv,
struct iwl_rxon_context *ctx,
@@ -40,7 +39,7 @@ static int iwlagn_disable_bss(struct iwl_priv *priv,
int ret;
send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- ret = trans_send_cmd_pdu(&priv->trans, ctx->rxon_cmd,
+ ret = iwl_trans_send_cmd_pdu(trans(priv), ctx->rxon_cmd,
CMD_SYNC, sizeof(*send), send);
send->filter_flags = old_filter;
@@ -66,7 +65,7 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,
send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
send->dev_type = RXON_DEV_TYPE_P2P;
- ret = trans_send_cmd_pdu(&priv->trans, ctx->rxon_cmd,
+ ret = iwl_trans_send_cmd_pdu(trans(priv), ctx->rxon_cmd,
CMD_SYNC, sizeof(*send), send);
send->filter_flags = old_filter;
@@ -92,7 +91,7 @@ static int iwlagn_disconn_pan(struct iwl_priv *priv,
int ret;
send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- ret = trans_send_cmd_pdu(&priv->trans, ctx->rxon_cmd, CMD_SYNC,
+ ret = iwl_trans_send_cmd_pdu(trans(priv), ctx->rxon_cmd, CMD_SYNC,
sizeof(*send), send);
send->filter_flags = old_filter;
@@ -121,7 +120,7 @@ static void iwlagn_update_qos(struct iwl_priv *priv,
ctx->qos_data.qos_active,
ctx->qos_data.def_qos_parm.qos_flags);
- ret = trans_send_cmd_pdu(&priv->trans, ctx->qos_cmd, CMD_SYNC,
+ ret = iwl_trans_send_cmd_pdu(trans(priv), ctx->qos_cmd, CMD_SYNC,
sizeof(struct iwl_qosparam_cmd),
&ctx->qos_data.def_qos_parm);
if (ret)
@@ -131,7 +130,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->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
dev_kfree_skb(priv->beacon_skb);
priv->beacon_skb = ieee80211_beacon_get(priv->hw, vif);
@@ -180,7 +179,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 = trans_send_cmd_pdu(&priv->trans, ctx->rxon_assoc_cmd,
+ ret = iwl_trans_send_cmd_pdu(trans(priv), ctx->rxon_assoc_cmd,
CMD_ASYNC, sizeof(rxon_assoc), &rxon_assoc);
return ret;
}
@@ -266,7 +265,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 = trans_send_cmd_pdu(&priv->trans, ctx->rxon_cmd, CMD_SYNC,
+ ret = iwl_trans_send_cmd_pdu(trans(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);
@@ -295,8 +294,8 @@ static int iwlagn_rxon_connect(struct iwl_priv *priv,
return ret;
}
- if ((ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION) &&
- priv->cfg->ht_params->smps_mode)
+ if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION &&
+ priv->cfg->ht_params && priv->cfg->ht_params->smps_mode)
ieee80211_request_smps(ctx->vif,
priv->cfg->ht_params->smps_mode);
@@ -310,12 +309,12 @@ int iwlagn_set_pan_params(struct iwl_priv *priv)
int slot0 = 300, slot1 = 0;
int ret;
- if (priv->valid_contexts == BIT(IWL_RXON_CTX_BSS))
+ if (priv->shrd->valid_contexts == BIT(IWL_RXON_CTX_BSS))
return 0;
BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
- lockdep_assert_held(&priv->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
ctx_bss = &priv->contexts[IWL_RXON_CTX_BSS];
ctx_pan = &priv->contexts[IWL_RXON_CTX_PAN];
@@ -337,10 +336,10 @@ int iwlagn_set_pan_params(struct iwl_priv *priv)
cmd.slots[0].type = 0; /* BSS */
cmd.slots[1].type = 1; /* PAN */
- if (priv->hw_roc_channel) {
+ if (priv->hw_roc_setup) {
/* both contexts must be used for this to happen */
- slot1 = priv->hw_roc_duration;
- slot0 = IWL_MIN_SLOT_TIME;
+ slot1 = IWL_MIN_SLOT_TIME;
+ slot0 = 3000;
} else if (ctx_bss->vif && ctx_pan->vif) {
int bcnint = ctx_pan->beacon_int;
int dtim = ctx_pan->vif->bss_conf.dtim_period ?: 1;
@@ -362,14 +361,14 @@ int iwlagn_set_pan_params(struct iwl_priv *priv)
slot0 = bcnint / 2;
slot1 = bcnint - slot0;
- if (test_bit(STATUS_SCAN_HW, &priv->status) ||
+ if (test_bit(STATUS_SCAN_HW, &priv->shrd->status) ||
(!ctx_bss->vif->bss_conf.idle &&
!ctx_bss->vif->bss_conf.assoc)) {
slot0 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME;
slot1 = IWL_MIN_SLOT_TIME;
} else if (!ctx_pan->vif->bss_conf.idle &&
!ctx_pan->vif->bss_conf.assoc) {
- slot1 = bcnint * 3 - IWL_MIN_SLOT_TIME;
+ slot1 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME;
slot0 = IWL_MIN_SLOT_TIME;
}
} else if (ctx_pan->vif) {
@@ -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->status)) {
+ if (test_bit(STATUS_SCAN_HW, &priv->shrd->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 = trans_send_cmd_pdu(&priv->trans, REPLY_WIPAN_PARAMS, CMD_SYNC,
+ ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_WIPAN_PARAMS, CMD_SYNC,
sizeof(cmd), &cmd);
if (ret)
IWL_ERR(priv, "Error setting PAN parameters (%d)\n", ret);
@@ -420,12 +419,12 @@ 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->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
return -EINVAL;
- if (!iwl_is_alive(priv))
+ if (!iwl_is_alive(priv->shrd))
return -EBUSY;
/* This function hardcodes a bunch of dual-mode assumptions */
@@ -434,26 +433,13 @@ 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;
- if (ctx->ctxid == IWL_RXON_CTX_PAN && priv->hw_roc_channel) {
- struct ieee80211_channel *chan = priv->hw_roc_channel;
-
- iwl_set_rxon_channel(priv, chan, ctx);
- iwl_set_flags_for_band(priv, ctx, chan->band, NULL);
- ctx->staging.filter_flags |=
- RXON_FILTER_ASSOC_MSK |
- RXON_FILTER_PROMISC_MSK |
- RXON_FILTER_CTL2HOST_MSK;
- ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
- new_assoc = true;
-
- if (memcmp(&ctx->staging, &ctx->active,
- sizeof(ctx->staging)) == 0)
- return 0;
- }
-
/*
* force CTS-to-self frames protection if RTS-CTS is not preferred
* one aggregation protection method
@@ -468,7 +454,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
else
ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
- iwl_print_rx_config_cmd(priv, ctx);
+ iwl_print_rx_config_cmd(priv, ctx->ctxid);
ret = iwl_check_rxon_cmd(priv, ctx);
if (ret) {
IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n");
@@ -479,7 +465,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->status) &&
+ if (test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status) &&
(priv->switch_channel != ctx->staging.channel)) {
IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
le16_to_cpu(priv->switch_channel));
@@ -551,16 +537,16 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
const struct iwl_channel_info *ch_info;
int ret = 0;
- IWL_DEBUG_MAC80211(priv, "changed %#x", changed);
+ IWL_DEBUG_MAC80211(priv, "enter: changed %#x", changed);
- mutex_lock(&priv->mutex);
+ mutex_lock(&priv->shrd->mutex);
- if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
+ if (unlikely(test_bit(STATUS_SCANNING, &priv->shrd->status))) {
IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
goto out;
}
- if (!iwl_is_ready(priv)) {
+ if (!iwl_is_ready(priv->shrd)) {
IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
goto out;
}
@@ -592,7 +578,7 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
goto out;
}
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&priv->shrd->lock, flags);
for_each_context(priv, ctx) {
/* Configure HT40 channels */
@@ -636,7 +622,7 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
ctx->vif);
}
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->lock, flags);
iwl_update_bcast_stations(priv);
@@ -668,7 +654,9 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
iwlagn_commit_rxon(priv, ctx);
}
out:
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+
return ret;
}
@@ -683,7 +671,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->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
switch (vif->type) {
case NL80211_IFTYPE_STATION:
@@ -787,7 +775,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 = trans_send_cmd_pdu(&priv->trans,
+ ret = iwl_trans_send_cmd_pdu(trans(priv),
REPLY_PHY_CALIBRATION_CMD,
CMD_SYNC, sizeof(cmd), &cmd);
if (ret)
@@ -808,17 +796,17 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
int ret;
bool force = false;
- mutex_lock(&priv->mutex);
+ mutex_lock(&priv->shrd->mutex);
- if (unlikely(!iwl_is_ready(priv))) {
+ if (unlikely(!iwl_is_ready(priv->shrd))) {
IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
return;
}
if (unlikely(!ctx->vif)) {
IWL_DEBUG_MAC80211(priv, "leave - vif is NULL\n");
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
return;
}
@@ -851,7 +839,8 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
*/
if (ctx->last_tx_rejected) {
ctx->last_tx_rejected = false;
- iwl_wake_any_queue(priv, ctx);
+ iwl_trans_wake_any_queue(trans(priv),
+ ctx->ctxid);
}
ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
@@ -912,6 +901,7 @@ 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) {
@@ -929,7 +919,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
IWL_ERR(priv, "Error sending IBSS beacon\n");
}
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
}
void iwlagn_post_scan(struct iwl_priv *priv)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
index 37e624095e40..ed6283623932 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
@@ -31,25 +31,833 @@
#include "iwl-dev.h"
#include "iwl-core.h"
-#include "iwl-sta.h"
#include "iwl-agn.h"
#include "iwl-trans.h"
-static struct iwl_link_quality_cmd *
-iwl_sta_alloc_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, u8 sta_id)
+/* priv->shrd->sta_lock must be held */
+static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
+{
+
+ if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE))
+ IWL_ERR(priv, "ACTIVATE a non DRIVER active station id %u "
+ "addr %pM\n",
+ sta_id, priv->stations[sta_id].sta.sta.addr);
+
+ if (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) {
+ IWL_DEBUG_ASSOC(priv,
+ "STA id %u addr %pM already present in uCode "
+ "(according to driver)\n",
+ sta_id, priv->stations[sta_id].sta.sta.addr);
+ } else {
+ priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE;
+ IWL_DEBUG_ASSOC(priv, "Added STA id %u addr %pM to uCode\n",
+ sta_id, priv->stations[sta_id].sta.sta.addr);
+ }
+}
+
+static int iwl_process_add_sta_resp(struct iwl_priv *priv,
+ struct iwl_addsta_cmd *addsta,
+ struct iwl_rx_packet *pkt)
+{
+ u8 sta_id = addsta->sta.sta_id;
+ unsigned long flags;
+ int ret = -EIO;
+
+ if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
+ pkt->hdr.flags);
+ return ret;
+ }
+
+ IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n",
+ sta_id);
+
+ spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+
+ switch (pkt->u.add_sta.status) {
+ case ADD_STA_SUCCESS_MSK:
+ IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n");
+ iwl_sta_ucode_activate(priv, sta_id);
+ ret = 0;
+ break;
+ case ADD_STA_NO_ROOM_IN_TABLE:
+ IWL_ERR(priv, "Adding station %d failed, no room in table.\n",
+ sta_id);
+ break;
+ case ADD_STA_NO_BLOCK_ACK_RESOURCE:
+ IWL_ERR(priv, "Adding station %d failed, no block ack "
+ "resource.\n", sta_id);
+ break;
+ case ADD_STA_MODIFY_NON_EXIST_STA:
+ IWL_ERR(priv, "Attempting to modify non-existing station %d\n",
+ sta_id);
+ break;
+ default:
+ IWL_DEBUG_ASSOC(priv, "Received REPLY_ADD_STA:(0x%08X)\n",
+ pkt->u.add_sta.status);
+ break;
+ }
+
+ IWL_DEBUG_INFO(priv, "%s station id %u addr %pM\n",
+ priv->stations[sta_id].sta.mode ==
+ STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
+ sta_id, priv->stations[sta_id].sta.sta.addr);
+
+ /*
+ * XXX: The MAC address in the command buffer is often changed from
+ * the original sent to the device. That is, the MAC address
+ * written to the command buffer often is not the same MAC address
+ * read from the command buffer when the command returns. This
+ * issue has not yet been resolved and this debugging is left to
+ * observe the problem.
+ */
+ IWL_DEBUG_INFO(priv, "%s station according to cmd buffer %pM\n",
+ priv->stations[sta_id].sta.mode ==
+ STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
+ addsta->sta.addr);
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+
+ return ret;
+}
+
+int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+ struct iwl_device_cmd *cmd)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_addsta_cmd *addsta =
+ (struct iwl_addsta_cmd *) cmd->payload;
+
+ return iwl_process_add_sta_resp(priv, addsta, pkt);
+}
+
+static u16 iwlagn_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
+{
+ u16 size = (u16)sizeof(struct iwl_addsta_cmd);
+ struct iwl_addsta_cmd *addsta = (struct iwl_addsta_cmd *)data;
+ memcpy(addsta, cmd, size);
+ /* resrved in 5000 */
+ addsta->rate_n_flags = cpu_to_le16(0);
+ return size;
+}
+
+int iwl_send_add_sta(struct iwl_priv *priv,
+ struct iwl_addsta_cmd *sta, u8 flags)
+{
+ int ret = 0;
+ u8 data[sizeof(*sta)];
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_ADD_STA,
+ .flags = flags,
+ .data = { data, },
+ };
+ u8 sta_id __maybe_unused = sta->sta.sta_id;
+
+ IWL_DEBUG_INFO(priv, "Adding sta %u (%pM) %ssynchronously\n",
+ sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : "");
+
+ if (!(flags & CMD_ASYNC)) {
+ cmd.flags |= CMD_WANT_SKB;
+ might_sleep();
+ }
+
+ cmd.len[0] = iwlagn_build_addsta_hcmd(sta, data);
+ ret = iwl_trans_send_cmd(trans(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);
+
+ if (cmd.handler_status)
+ IWL_ERR(priv, "%s - error in the CMD response %d", __func__,
+ cmd.handler_status);
+
+ 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)
+{
+ struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap;
+ __le32 sta_flags;
+ u8 mimo_ps_mode;
+
+ if (!sta || !sta_ht_inf->ht_supported)
+ goto done;
+
+ mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2;
+ IWL_DEBUG_ASSOC(priv, "spatial multiplexing power save 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;
+ break;
+ case WLAN_HT_CAP_SM_PS_DYNAMIC:
+ sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
+ break;
+ case WLAN_HT_CAP_SM_PS_DISABLED:
+ break;
+ default:
+ IWL_WARN(priv, "Invalid MIMO PS mode %d\n", mimo_ps_mode);
+ break;
+ }
+
+ sta_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);
+
+ 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;
+
+ priv->stations[index].sta.station_flags = sta_flags;
+ done:
+ return;
+}
+
+/**
+ * iwl_prep_station - Prepare station information for addition
+ *
+ * should be called with sta_lock held
+ */
+u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+ const u8 *addr, bool is_ap, struct ieee80211_sta *sta)
+{
+ struct iwl_station_entry *station;
+ int i;
+ u8 sta_id = IWL_INVALID_STATION;
+
+ if (is_ap)
+ sta_id = ctx->ap_sta_id;
+ else if (is_broadcast_ether_addr(addr))
+ sta_id = ctx->bcast_sta_id;
+ else
+ for (i = IWL_STA_ID; i < IWLAGN_STATION_COUNT; i++) {
+ if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
+ addr)) {
+ sta_id = i;
+ break;
+ }
+
+ if (!priv->stations[i].used &&
+ sta_id == IWL_INVALID_STATION)
+ sta_id = i;
+ }
+
+ /*
+ * These two conditions have the same outcome, but keep them
+ * separate
+ */
+ if (unlikely(sta_id == IWL_INVALID_STATION))
+ return sta_id;
+
+ /*
+ * uCode is not able to deal with multiple requests to add a
+ * station. Keep track if one is in progress so that we do not send
+ * another.
+ */
+ 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);
+ return sta_id;
+ }
+
+ if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) &&
+ (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) &&
+ !compare_ether_addr(priv->stations[sta_id].sta.sta.addr, addr)) {
+ IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not "
+ "adding again.\n", sta_id, addr);
+ return sta_id;
+ }
+
+ station = &priv->stations[sta_id];
+ station->used = IWL_STA_DRIVER_ACTIVE;
+ IWL_DEBUG_ASSOC(priv, "Add STA to driver ID %d: %pM\n",
+ sta_id, addr);
+ priv->num_stations++;
+
+ /* Set up the REPLY_ADD_STA command to send to device */
+ memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd));
+ memcpy(station->sta.sta.addr, addr, ETH_ALEN);
+ station->sta.mode = 0;
+ station->sta.sta.sta_id = sta_id;
+ station->sta.station_flags = ctx->station_flags;
+ station->ctxid = ctx->ctxid;
+
+ if (sta) {
+ struct iwl_station_priv *sta_priv;
+
+ sta_priv = (void *)sta->drv_priv;
+ sta_priv->ctx = ctx;
+ }
+
+ /*
+ * OK to call unconditionally, since local stations (IBSS BSSID
+ * STA and broadcast STA) pass in a NULL sta, and mac80211
+ * doesn't allow HT IBSS.
+ */
+ iwl_set_ht_add_station(priv, sta_id, sta, ctx);
+
+ return sta_id;
+
+}
+
+#define STA_WAIT_TIMEOUT (HZ/2)
+
+/**
+ * iwl_add_station_common -
+ */
+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);
+ 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);
+ return -EINVAL;
+ }
+
+ /*
+ * uCode is not able to deal with multiple requests to add a
+ * station. Keep track if one is in progress so that we do not send
+ * another.
+ */
+ 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);
+ return -EEXIST;
+ }
+
+ if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) &&
+ (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);
+ 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);
+
+ /* 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);
+ 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);
+ }
+ *sta_id_r = sta_id;
+ return ret;
+}
+
+/**
+ * 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)
+{
+ /* Ucode must be active and driver must be non active */
+ if ((priv->stations[sta_id].used &
+ (IWL_STA_UCODE_ACTIVE | IWL_STA_DRIVER_ACTIVE)) !=
+ IWL_STA_UCODE_ACTIVE)
+ IWL_ERR(priv, "removed non active STA %u\n", sta_id);
+
+ priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE;
+
+ memset(&priv->stations[sta_id], 0, sizeof(struct iwl_station_entry));
+ IWL_DEBUG_ASSOC(priv, "Removed STA %u\n", sta_id);
+}
+
+static int iwl_send_remove_station(struct iwl_priv *priv,
+ const u8 *addr, int sta_id,
+ bool temporary)
+{
+ struct iwl_rx_packet *pkt;
+ int ret;
+
+ unsigned long flags_spin;
+ struct iwl_rem_sta_cmd rm_sta_cmd;
+
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_REMOVE_STA,
+ .len = { sizeof(struct iwl_rem_sta_cmd), },
+ .flags = CMD_SYNC,
+ .data = { &rm_sta_cmd, },
+ };
+
+ memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
+ rm_sta_cmd.num_sta = 1;
+ memcpy(&rm_sta_cmd.addr, addr, ETH_ALEN);
+
+ cmd.flags |= CMD_WANT_SKB;
+
+ ret = iwl_trans_send_cmd(trans(priv), &cmd);
+
+ if (ret)
+ return ret;
+
+ pkt = (struct iwl_rx_packet *)cmd.reply_page;
+ if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
+ pkt->hdr.flags);
+ ret = -EIO;
+ }
+
+ if (!ret) {
+ switch (pkt->u.rem_sta.status) {
+ case REM_STA_SUCCESS_MSK:
+ if (!temporary) {
+ spin_lock_irqsave(&priv->shrd->sta_lock,
+ flags_spin);
+ iwl_sta_ucode_deactivate(priv, sta_id);
+ spin_unlock_irqrestore(&priv->shrd->sta_lock,
+ flags_spin);
+ }
+ IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
+ break;
+ default:
+ ret = -EIO;
+ IWL_ERR(priv, "REPLY_REMOVE_STA failed\n");
+ break;
+ }
+ }
+ iwl_free_pages(priv->shrd, cmd.reply_page);
+
+ return ret;
+}
+
+/**
+ * iwl_remove_station - Remove driver's knowledge of station.
+ */
+int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
+ const u8 *addr)
+{
+ unsigned long flags;
+
+ if (!iwl_is_ready(priv->shrd)) {
+ IWL_DEBUG_INFO(priv,
+ "Unable to remove station %pM, device not ready.\n",
+ addr);
+ /*
+ * It is typical for stations to be removed when we are
+ * going down. Return success since device will be down
+ * soon anyway
+ */
+ return 0;
+ }
+
+ IWL_DEBUG_ASSOC(priv, "Removing STA from driver:%d %pM\n",
+ sta_id, addr);
+
+ if (WARN_ON(sta_id == IWL_INVALID_STATION))
+ return -EINVAL;
+
+ spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+
+ if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
+ IWL_DEBUG_INFO(priv, "Removing %pM but non DRIVER active\n",
+ addr);
+ goto out_err;
+ }
+
+ if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) {
+ IWL_DEBUG_INFO(priv, "Removing %pM but non UCODE active\n",
+ addr);
+ goto out_err;
+ }
+
+ if (priv->stations[sta_id].used & IWL_STA_LOCAL) {
+ kfree(priv->stations[sta_id].lq);
+ priv->stations[sta_id].lq = NULL;
+ }
+
+ priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
+
+ priv->num_stations--;
+
+ if (WARN_ON(priv->num_stations < 0))
+ priv->num_stations = 0;
+
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+
+ return iwl_send_remove_station(priv, addr, sta_id, false);
+out_err:
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+ return -EINVAL;
+}
+
+/**
+ * iwl_clear_ucode_stations - clear ucode station table bits
+ *
+ * This function clears all the bits in the driver indicating
+ * which stations are active in the ucode. Call when something
+ * other than explicit station management would cause this in
+ * the ucode, e.g. unassociated RXON.
+ */
+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);
+ for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
+ if (ctx && ctx->ctxid != priv->stations[i].ctxid)
+ continue;
+
+ if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) {
+ IWL_DEBUG_INFO(priv,
+ "Clearing ucode active for station %d\n", i);
+ priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
+ cleared = true;
+ }
+ }
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin);
+
+ if (!cleared)
+ IWL_DEBUG_INFO(priv,
+ "No active stations found to be cleared\n");
+}
+
+/**
+ * iwl_restore_stations() - Restore driver known stations to device
+ *
+ * All stations considered active by driver, but not present in ucode, is
+ * restored.
+ *
+ * Function sleeps.
+ */
+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)) {
+ 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);
+ for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
+ if (ctx->ctxid != priv->stations[i].ctxid)
+ continue;
+ if ((priv->stations[i].used & IWL_STA_DRIVER_ACTIVE) &&
+ !(priv->stations[i].used & IWL_STA_UCODE_ACTIVE)) {
+ IWL_DEBUG_ASSOC(priv, "Restoring sta %pM\n",
+ priv->stations[i].sta.sta.addr);
+ priv->stations[i].sta.mode = 0;
+ priv->stations[i].used |= IWL_STA_UCODE_INPROGRESS;
+ found = true;
+ }
+ }
+
+ for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
+ if ((priv->stations[i].used & IWL_STA_UCODE_INPROGRESS)) {
+ memcpy(&sta_cmd, &priv->stations[i].sta,
+ sizeof(struct iwl_addsta_cmd));
+ send_lq = false;
+ if (priv->stations[i].lq) {
+ if (priv->shrd->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);
+ ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
+ if (ret) {
+ spin_lock_irqsave(&priv->shrd->sta_lock,
+ flags_spin);
+ 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);
+ }
+ /*
+ * Rate scaling has already been initialized, send
+ * current LQ command
+ */
+ if (send_lq)
+ iwl_send_lq_cmd(priv, ctx, &lq,
+ CMD_SYNC, true);
+ spin_lock_irqsave(&priv->shrd->sta_lock, flags_spin);
+ priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS;
+ }
+ }
+
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin);
+ if (!found)
+ IWL_DEBUG_INFO(priv, "Restoring all known stations .... "
+ "no stations to be restored.\n");
+ else
+ IWL_DEBUG_INFO(priv, "Restoring all known stations .... "
+ "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;
+
+ 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;
+ memcpy(&lq, priv->stations[sta_id].lq, sizeof(lq));
+
+ 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);
+ iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true);
+}
+
+int iwl_get_free_ucode_key_offset(struct iwl_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < priv->sta_key_max_num; i++)
+ if (!test_and_set_bit(i, &priv->ucode_key_table))
+ return i;
+
+ return WEP_INVALID_OFFSET;
+}
+
+void iwl_dealloc_bcast_stations(struct iwl_priv *priv)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+ for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
+ if (!(priv->stations[i].used & IWL_STA_BCAST))
+ continue;
+
+ priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
+ priv->num_stations--;
+ if (WARN_ON(priv->num_stations < 0))
+ priv->num_stations = 0;
+ kfree(priv->stations[i].lq);
+ priv->stations[i].lq = NULL;
+ }
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+static void iwl_dump_lq_cmd(struct iwl_priv *priv,
+ struct iwl_link_quality_cmd *lq)
+{
+ int i;
+ IWL_DEBUG_RATE(priv, "lq station id 0x%x\n", lq->sta_id);
+ IWL_DEBUG_RATE(priv, "lq ant 0x%X 0x%X\n",
+ lq->general_params.single_stream_ant_msk,
+ lq->general_params.dual_stream_ant_msk);
+
+ for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
+ IWL_DEBUG_RATE(priv, "lq index %d 0x%X\n",
+ i, lq->rs_table[i].rate_n_flags);
+}
+#else
+static inline void iwl_dump_lq_cmd(struct iwl_priv *priv,
+ struct iwl_link_quality_cmd *lq)
+{
+}
+#endif
+
+/**
+ * is_lq_table_valid() - Test one aspect of LQ cmd for validity
+ *
+ * It sometimes happens when a HT rate has been in use and we
+ * loose connectivity with AP then mac80211 will first tell us that the
+ * current channel is not HT anymore before removing the station. In such a
+ * scenario the RXON flags will be updated to indicate we are not
+ * communicating HT anymore, but the LQ command may still contain HT rates.
+ * Test for this to prevent driver from sending LQ command between the time
+ * RXON flags are updated and when LQ command is updated.
+ */
+static bool is_lq_table_valid(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
+ struct iwl_link_quality_cmd *lq)
+{
+ int i;
+
+ if (ctx->ht.enabled)
+ return true;
+
+ IWL_DEBUG_INFO(priv, "Channel %u is not an HT channel\n",
+ ctx->active.channel);
+ for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
+ if (le32_to_cpu(lq->rs_table[i].rate_n_flags) &
+ RATE_MCS_HT_MSK) {
+ IWL_DEBUG_INFO(priv,
+ "index %d of LQ expects HT channel\n",
+ i);
+ return false;
+ }
+ }
+ return true;
+}
+
+/**
+ * iwl_send_lq_cmd() - Send link quality command
+ * @init: This command is sent as part of station initialization right
+ * after station has been added.
+ *
+ * The link quality command is sent as the last step of station creation.
+ * This is the special case in which init is set and we call a callback in
+ * this case to clear the state indicating that station creation is in
+ * progress.
+ */
+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), },
+ .flags = flags,
+ .data = { lq, },
+ };
+
+ if (WARN_ON(lq->sta_id == IWL_INVALID_STATION))
+ return -EINVAL;
+
+
+ spin_lock_irqsave(&priv->shrd->sta_lock, flags_spin);
+ if (!(priv->stations[lq->sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin);
+ return -EINVAL;
+ }
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin);
+
+ 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);
+ else
+ ret = -EINVAL;
+
+ if (cmd.flags & CMD_ASYNC)
+ return ret;
+
+ if (init) {
+ 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);
+ priv->stations[lq->sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin);
+ }
+ return ret;
+}
+
+int iwlagn_mac_sta_remove(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct iwl_priv *priv = hw->priv;
+ struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+ int ret;
+
+ IWL_DEBUG_MAC80211(priv, "enter: received request to remove "
+ "station %pM\n", sta->addr);
+ mutex_lock(&priv->shrd->mutex);
+ IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n",
+ sta->addr);
+ ret = iwl_remove_station(priv, sta_priv->sta_id, sta->addr);
+ if (ret)
+ IWL_ERR(priv, "Error removing station %pM\n",
+ sta->addr);
+ mutex_unlock(&priv->shrd->mutex);
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+
+ return ret;
+}
+
+void iwl_sta_fill_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+ u8 sta_id, struct iwl_link_quality_cmd *link_cmd)
{
int i, r;
- struct iwl_link_quality_cmd *link_cmd;
u32 rate_flags = 0;
__le32 rate_n_flags;
- link_cmd = kzalloc(sizeof(struct iwl_link_quality_cmd), GFP_KERNEL);
- if (!link_cmd) {
- IWL_ERR(priv, "Unable to allocate memory for LQ cmd.\n");
- return NULL;
- }
+ lockdep_assert_held(&priv->shrd->mutex);
- lockdep_assert_held(&priv->mutex);
+ memset(link_cmd, 0, sizeof(*link_cmd));
/* Set up the rate scaling to start at selected rate, fall back
* all the way down to 1M in IEEE order, and then spin on 1M */
@@ -63,30 +871,46 @@ iwl_sta_alloc_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, u8 sta_id)
if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
rate_flags |= RATE_MCS_CCK_MSK;
- rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) <<
+ rate_flags |= first_antenna(hw_params(priv).valid_tx_ant) <<
RATE_MCS_ANT_POS;
rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
link_cmd->rs_table[i].rate_n_flags = rate_n_flags;
link_cmd->general_params.single_stream_ant_msk =
- first_antenna(priv->hw_params.valid_tx_ant);
+ first_antenna(hw_params(priv).valid_tx_ant);
link_cmd->general_params.dual_stream_ant_msk =
- priv->hw_params.valid_tx_ant &
- ~first_antenna(priv->hw_params.valid_tx_ant);
+ hw_params(priv).valid_tx_ant &
+ ~first_antenna(hw_params(priv).valid_tx_ant);
if (!link_cmd->general_params.dual_stream_ant_msk) {
link_cmd->general_params.dual_stream_ant_msk = ANT_AB;
- } else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) {
+ } else if (num_of_ant(hw_params(priv).valid_tx_ant) == 2) {
link_cmd->general_params.dual_stream_ant_msk =
- priv->hw_params.valid_tx_ant;
+ hw_params(priv).valid_tx_ant;
}
- link_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
+ link_cmd->agg_params.agg_dis_start_th =
+ LINK_QUAL_AGG_DISABLE_START_DEF;
link_cmd->agg_params.agg_time_limit =
cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
link_cmd->sta_id = sta_id;
+}
+
+static struct iwl_link_quality_cmd *
+iwl_sta_alloc_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+ u8 sta_id)
+{
+ struct iwl_link_quality_cmd *link_cmd;
+
+ link_cmd = kzalloc(sizeof(struct iwl_link_quality_cmd), GFP_KERNEL);
+ if (!link_cmd) {
+ IWL_ERR(priv, "Unable to allocate memory for LQ cmd.\n");
+ return NULL;
+ }
+
+ iwl_sta_fill_lq(priv, ctx, sta_id, link_cmd);
return link_cmd;
}
@@ -96,7 +920,8 @@ iwl_sta_alloc_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, u8 sta_id)
*
* Function sleeps.
*/
-int iwlagn_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+int iwlagn_add_bssid_station(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
const u8 *addr, u8 *sta_id_r)
{
int ret;
@@ -116,14 +941,15 @@ int iwlagn_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx
if (sta_id_r)
*sta_id_r = sta_id;
- spin_lock_irqsave(&priv->sta_lock, flags);
+ spin_lock_irqsave(&priv->shrd->sta_lock, flags);
priv->stations[sta_id].used |= IWL_STA_LOCAL;
- spin_unlock_irqrestore(&priv->sta_lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
/* Set up default rate scaling table in device's station table */
link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id);
if (!link_cmd) {
- IWL_ERR(priv, "Unable to initialize rate scaling for station %pM.\n",
+ IWL_ERR(priv,
+ "Unable to initialize rate scaling for station %pM.\n",
addr);
return -ENOMEM;
}
@@ -132,9 +958,9 @@ int iwlagn_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx
if (ret)
IWL_ERR(priv, "Link quality command failed (%d)\n", ret);
- spin_lock_irqsave(&priv->sta_lock, flags);
+ spin_lock_irqsave(&priv->shrd->sta_lock, flags);
priv->stations[sta_id].lq = link_cmd;
- spin_unlock_irqrestore(&priv->sta_lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
return 0;
}
@@ -189,7 +1015,7 @@ static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv,
cmd.len[0] = cmd_size;
if (not_empty || send_if_empty)
- return trans_send_cmd(&priv->trans, &cmd);
+ return iwl_trans_send_cmd(trans(priv), &cmd);
else
return 0;
}
@@ -197,7 +1023,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->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
return iwl_send_static_wepkey_cmd(priv, ctx, false);
}
@@ -208,14 +1034,15 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
{
int ret;
- lockdep_assert_held(&priv->mutex);
+ lockdep_assert_held(&priv->shrd->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)) {
- IWL_DEBUG_WEP(priv, "Not sending REPLY_WEPKEY command due to RFKILL.\n");
+ if (iwl_is_rfkill(priv->shrd)) {
+ IWL_DEBUG_WEP(priv,
+ "Not sending REPLY_WEPKEY command due to RFKILL.\n");
/* but keys in device are clear anyway so return success */
return 0;
}
@@ -232,11 +1059,12 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
{
int ret;
- lockdep_assert_held(&priv->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
if (keyconf->keylen != WEP_KEY_LEN_128 &&
keyconf->keylen != WEP_KEY_LEN_64) {
- IWL_DEBUG_WEP(priv, "Bad WEP key length %d\n", keyconf->keylen);
+ IWL_DEBUG_WEP(priv,
+ "Bad WEP key length %d\n", keyconf->keylen);
return -EINVAL;
}
@@ -311,9 +1139,9 @@ static int iwlagn_send_sta_key(struct iwl_priv *priv,
struct iwl_addsta_cmd sta_cmd;
int i;
- spin_lock_irqsave(&priv->sta_lock, flags);
+ spin_lock_irqsave(&priv->shrd->sta_lock, flags);
memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd));
- spin_unlock_irqrestore(&priv->sta_lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
key_flags = cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
key_flags |= STA_KEY_FLG_MAP_KEY_MSK;
@@ -388,16 +1216,16 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
if (sta_id == IWL_INVALID_STATION)
return -ENOENT;
- spin_lock_irqsave(&priv->sta_lock, flags);
+ spin_lock_irqsave(&priv->shrd->sta_lock, flags);
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->sta_lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
if (sta_id == IWL_INVALID_STATION)
return 0;
- lockdep_assert_held(&priv->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
ctx->key_mapping_keys--;
@@ -430,7 +1258,7 @@ int iwl_set_dynamic_key(struct iwl_priv *priv,
if (sta_id == IWL_INVALID_STATION)
return -EINVAL;
- lockdep_assert_held(&priv->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
keyconf->hw_key_idx = iwl_get_free_ucode_key_offset(priv);
if (keyconf->hw_key_idx == WEP_INVALID_OFFSET)
@@ -493,18 +1321,18 @@ int iwlagn_alloc_bcast_station(struct iwl_priv *priv,
unsigned long flags;
u8 sta_id;
- spin_lock_irqsave(&priv->sta_lock, flags);
+ spin_lock_irqsave(&priv->shrd->sta_lock, flags);
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->sta_lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
return -EINVAL;
}
priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE;
priv->stations[sta_id].used |= IWL_STA_BCAST;
- spin_unlock_irqrestore(&priv->sta_lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id);
if (!link_cmd) {
@@ -513,9 +1341,9 @@ int iwlagn_alloc_bcast_station(struct iwl_priv *priv,
return -ENOMEM;
}
- spin_lock_irqsave(&priv->sta_lock, flags);
+ spin_lock_irqsave(&priv->shrd->sta_lock, flags);
priv->stations[sta_id].lq = link_cmd;
- spin_unlock_irqrestore(&priv->sta_lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
return 0;
}
@@ -539,13 +1367,13 @@ int iwl_update_bcast_station(struct iwl_priv *priv,
return -ENOMEM;
}
- spin_lock_irqsave(&priv->sta_lock, flags);
+ spin_lock_irqsave(&priv->shrd->sta_lock, flags);
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->sta_lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
return 0;
}
@@ -572,15 +1400,15 @@ 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->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
/* Remove "disable" flag, to enable Tx for this TID */
- spin_lock_irqsave(&priv->sta_lock, flags);
+ spin_lock_irqsave(&priv->shrd->sta_lock, flags);
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->sta_lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
}
@@ -592,20 +1420,20 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
int sta_id;
struct iwl_addsta_cmd sta_cmd;
- lockdep_assert_held(&priv->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
sta_id = iwl_sta_id(sta);
if (sta_id == IWL_INVALID_STATION)
return -ENXIO;
- spin_lock_irqsave(&priv->sta_lock, flags);
+ spin_lock_irqsave(&priv->shrd->sta_lock, flags);
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->sta_lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
}
@@ -617,7 +1445,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
int sta_id;
struct iwl_addsta_cmd sta_cmd;
- lockdep_assert_held(&priv->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
sta_id = iwl_sta_id(sta);
if (sta_id == IWL_INVALID_STATION) {
@@ -625,13 +1453,13 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
return -ENXIO;
}
- spin_lock_irqsave(&priv->sta_lock, flags);
+ spin_lock_irqsave(&priv->shrd->sta_lock, flags);
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->sta_lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
}
@@ -640,14 +1468,14 @@ static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
{
unsigned long flags;
- spin_lock_irqsave(&priv->sta_lock, 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->sta_lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
}
@@ -655,7 +1483,7 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
{
unsigned long flags;
- spin_lock_irqsave(&priv->sta_lock, 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 =
@@ -663,7 +1491,7 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
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->sta_lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
}
@@ -676,6 +1504,8 @@ void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
int sta_id;
+ IWL_DEBUG_MAC80211(priv, "enter\n");
+
switch (cmd) {
case STA_NOTIFY_SLEEP:
WARN_ON(!sta_priv->client);
@@ -695,4 +1525,5 @@ void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
default:
break;
}
+ IWL_DEBUG_MAC80211(priv, "leave\n");
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c
index f501d742984c..c27180a73351 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c
@@ -114,9 +114,6 @@ static bool iwl_within_ct_kill_margin(struct iwl_priv *priv)
s32 temp = priv->temperature; /* degrees CELSIUS except specified */
bool within_margin = false;
- if (priv->cfg->base_params->temperature_kelvin)
- temp = KELVIN_TO_CELSIUS(priv->temperature);
-
if (!priv->thermal_throttle.advanced_tt)
within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
CT_KILL_THRESHOLD_LEGACY) ? true : false;
@@ -176,24 +173,24 @@ 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->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
return;
if (tt->state == IWL_TI_CT_KILL) {
if (priv->thermal_throttle.ct_kill_toggle) {
- iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+ iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR,
CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
priv->thermal_throttle.ct_kill_toggle = false;
} else {
- iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+ iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_SET,
CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
priv->thermal_throttle.ct_kill_toggle = true;
}
- iwl_read32(priv, CSR_UCODE_DRV_GP1);
- spin_lock_irqsave(&priv->reg_lock, flags);
- if (!iwl_grab_nic_access(priv))
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->reg_lock, flags);
+ iwl_read32(bus(priv), CSR_UCODE_DRV_GP1);
+ spin_lock_irqsave(&bus(priv)->reg_lock, flags);
+ if (!iwl_grab_nic_access(bus(priv)))
+ iwl_release_nic_access(bus(priv));
+ spin_unlock_irqrestore(&bus(priv)->reg_lock, flags);
/* Reschedule the ct_kill timer to occur in
* CT_KILL_EXIT_DURATION seconds to ensure we get a
@@ -227,7 +224,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->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
return;
/* temperature timer expired, ready to go into CT_KILL state */
@@ -235,7 +232,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->status);
+ set_bit(STATUS_CT_KILL, &priv->shrd->status);
iwl_perform_ct_kill_task(priv, true);
}
}
@@ -313,23 +310,24 @@ 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->mutex);
+ mutex_lock(&priv->shrd->mutex);
if (old_state == IWL_TI_CT_KILL)
- clear_bit(STATUS_CT_KILL, &priv->status);
+ clear_bit(STATUS_CT_KILL, &priv->shrd->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->status);
+ set_bit(STATUS_CT_KILL, &priv->shrd->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->status);
+ set_bit(STATUS_CT_KILL,
+ &priv->shrd->status);
iwl_perform_ct_kill_task(priv, true);
} else {
iwl_prepare_ct_kill_task(priv);
@@ -343,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->mutex);
+ mutex_unlock(&priv->shrd->mutex);
}
}
@@ -453,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->mutex);
+ mutex_lock(&priv->shrd->mutex);
if (old_state == IWL_TI_CT_KILL)
- clear_bit(STATUS_CT_KILL, &priv->status);
+ clear_bit(STATUS_CT_KILL, &priv->shrd->status);
if (tt->state != IWL_TI_CT_KILL &&
iwl_power_update_mode(priv, true)) {
/* TT state not updated
@@ -464,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->status);
+ set_bit(STATUS_CT_KILL, &priv->shrd->status);
tt->state = old_state;
} else {
IWL_DEBUG_TEMP(priv,
@@ -475,7 +473,8 @@ 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->status);
+ set_bit(STATUS_CT_KILL,
+ &priv->shrd->status);
iwl_perform_ct_kill_task(priv, true);
} else {
iwl_prepare_ct_kill_task(priv);
@@ -487,7 +486,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->mutex);
+ mutex_unlock(&priv->shrd->mutex);
}
}
@@ -506,10 +505,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->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
return;
- if (!iwl_is_ready(priv))
+ if (!iwl_is_ready(priv->shrd))
return;
if (tt->state != IWL_TI_CT_KILL) {
@@ -535,10 +534,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->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
return;
- if (!iwl_is_ready(priv))
+ if (!iwl_is_ready(priv->shrd))
return;
/* stop ct_kill_exit_tm timer */
@@ -565,20 +564,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->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
return;
IWL_DEBUG_TEMP(priv, "Queueing critical temperature enter.\n");
- queue_work(priv->workqueue, &priv->ct_enter);
+ queue_work(priv->shrd->workqueue, &priv->ct_enter);
}
void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
{
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
return;
IWL_DEBUG_TEMP(priv, "Queueing critical temperature exit.\n");
- queue_work(priv->workqueue, &priv->ct_exit);
+ queue_work(priv->shrd->workqueue, &priv->ct_exit);
}
static void iwl_bg_tt_work(struct work_struct *work)
@@ -586,12 +585,9 @@ 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->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
return;
- if (priv->cfg->base_params->temperature_kelvin)
- temp = KELVIN_TO_CELSIUS(priv->temperature);
-
if (!priv->thermal_throttle.advanced_tt)
iwl_legacy_tt_handler(priv, temp, false);
else
@@ -600,11 +596,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->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
return;
IWL_DEBUG_TEMP(priv, "Queueing thermal throttling work.\n");
- queue_work(priv->workqueue, &priv->tt_work);
+ queue_work(priv->shrd->workqueue, &priv->tt_work);
}
/* Thermal throttling initialization
@@ -639,11 +635,13 @@ void iwl_tt_initialize(struct iwl_priv *priv)
if (priv->cfg->base_params->adv_thermal_throttle) {
IWL_DEBUG_TEMP(priv, "Advanced Thermal Throttling\n");
- tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) *
- IWL_TI_STATE_MAX, GFP_KERNEL);
- tt->transaction = kzalloc(sizeof(struct iwl_tt_trans) *
- IWL_TI_STATE_MAX * (IWL_TI_STATE_MAX - 1),
- GFP_KERNEL);
+ tt->restriction = kcalloc(IWL_TI_STATE_MAX,
+ sizeof(struct iwl_tt_restriction),
+ GFP_KERNEL);
+ tt->transaction = kcalloc(IWL_TI_STATE_MAX *
+ (IWL_TI_STATE_MAX - 1),
+ sizeof(struct iwl_tt_trans),
+ GFP_KERNEL);
if (!tt->restriction || !tt->transaction) {
IWL_ERR(priv, "Fallback to Legacy Throttling\n");
priv->thermal_throttle.advanced_tt = false;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h
index d118ed29bf3f..7282a23e8f1c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h
@@ -117,7 +117,6 @@ struct iwl_tt_mgmt {
u8 iwl_tt_current_power_mode(struct iwl_priv *priv);
bool iwl_tt_is_low_power_state(struct iwl_priv *priv);
bool iwl_ht_enabled(struct iwl_priv *priv);
-bool iwl_check_for_ct_kill(struct iwl_priv *priv);
enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv);
enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv);
void iwl_tt_enter_ct_kill(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index 53bb59ee719d..35a6b71f358c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -31,89 +31,15 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
+#include <linux/ieee80211.h>
#include "iwl-dev.h"
#include "iwl-core.h"
-#include "iwl-sta.h"
#include "iwl-io.h"
-#include "iwl-helpers.h"
#include "iwl-agn-hw.h"
#include "iwl-agn.h"
#include "iwl-trans.h"
-/*
- * 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)
-{
- 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_rxon_context *ctx, u16 tid)
-{
- if (likely(tid < ARRAY_SIZE(tid_to_ac)))
- return ctx->ac_to_fifo[tid_to_ac[tid]];
-
- /* no support for TIDs 8-15 yet */
- return -EINVAL;
-}
-
-static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, int sta_id,
- int tid)
-{
- if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
- (IWLAGN_FIRST_AMPDU_QUEUE +
- priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) {
- IWL_WARN(priv,
- "queue number out of range: %d, must be %d to %d\n",
- txq_id, IWLAGN_FIRST_AMPDU_QUEUE,
- IWLAGN_FIRST_AMPDU_QUEUE +
- priv->cfg->base_params->num_of_ampdu_queues - 1);
- return -EINVAL;
- }
-
- /* Modify device's station table to Tx this TID */
- return iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
-}
-
static void iwlagn_tx_cmd_protection(struct iwl_priv *priv,
struct ieee80211_tx_info *info,
__le16 fc, __le32 *tx_flags)
@@ -128,11 +54,10 @@ static void iwlagn_tx_cmd_protection(struct iwl_priv *priv,
* handle build REPLY_TX command notification.
*/
static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
- struct sk_buff *skb,
- struct iwl_tx_cmd *tx_cmd,
- struct ieee80211_tx_info *info,
- struct ieee80211_hdr *hdr,
- u8 std_id)
+ struct sk_buff *skb,
+ struct iwl_tx_cmd *tx_cmd,
+ struct ieee80211_tx_info *info,
+ struct ieee80211_hdr *hdr, u8 sta_id)
{
__le16 fc = hdr->frame_control;
__le32 tx_flags = tx_cmd->tx_flags;
@@ -157,7 +82,7 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
tx_flags |= TX_CMD_FLG_IGNORE_BT;
- tx_cmd->sta_id = std_id;
+ tx_cmd->sta_id = sta_id;
if (ieee80211_has_morefrags(fc))
tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
@@ -186,12 +111,10 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
tx_cmd->next_frame_len = 0;
}
-#define RTS_DFAULT_RETRY_LIMIT 60
-
static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
- struct iwl_tx_cmd *tx_cmd,
- struct ieee80211_tx_info *info,
- __le16 fc)
+ struct iwl_tx_cmd *tx_cmd,
+ struct ieee80211_tx_info *info,
+ __le16 fc)
{
u32 rate_flags;
int rate_idx;
@@ -199,17 +122,25 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
u8 data_retry_limit;
u8 rate_plcp;
- /* Set retry limit on DATA packets and Probe Responses*/
- if (ieee80211_is_probe_resp(fc))
- data_retry_limit = 3;
- else
- data_retry_limit = IWLAGN_DEFAULT_TX_RETRY;
- tx_cmd->data_retry_limit = data_retry_limit;
+ if (priv->shrd->wowlan) {
+ rts_retry_limit = IWLAGN_LOW_RETRY_LIMIT;
+ data_retry_limit = IWLAGN_LOW_RETRY_LIMIT;
+ } else {
+ /* Set retry limit on RTS packets */
+ rts_retry_limit = IWLAGN_RTS_DFAULT_RETRY_LIMIT;
+
+ /* Set retry limit on DATA packets and Probe Responses*/
+ if (ieee80211_is_probe_resp(fc)) {
+ data_retry_limit = IWLAGN_MGMT_DFAULT_RETRY_LIMIT;
+ rts_retry_limit =
+ min(data_retry_limit, rts_retry_limit);
+ } else if (ieee80211_is_back_req(fc))
+ data_retry_limit = IWLAGN_BAR_DFAULT_RETRY_LIMIT;
+ else
+ data_retry_limit = IWLAGN_DEFAULT_TX_RETRY;
+ }
- /* Set retry limit on RTS packets */
- rts_retry_limit = RTS_DFAULT_RETRY_LIMIT;
- if (data_retry_limit < rts_retry_limit)
- rts_retry_limit = data_retry_limit;
+ tx_cmd->data_retry_limit = data_retry_limit;
tx_cmd->rts_retry_limit = rts_retry_limit;
/* DATA packets will use the uCode station table for rate/antenna
@@ -261,10 +192,10 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
priv->bt_full_concurrent) {
/* operated as 1x1 in full concurrency mode */
priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
- first_antenna(priv->hw_params.valid_tx_ant));
+ first_antenna(hw_params(priv).valid_tx_ant));
} else
priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
- priv->hw_params.valid_tx_ant);
+ hw_params(priv).valid_tx_ant);
rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
/* Set the rate in the TX cmd */
@@ -322,30 +253,21 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl_station_priv *sta_priv = NULL;
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+ struct iwl_device_cmd *dev_cmd = NULL;
struct iwl_tx_cmd *tx_cmd;
- int txq_id;
- u16 seq_number = 0;
__le16 fc;
u8 hdr_len;
u16 len;
u8 sta_id;
- u8 tid = 0;
unsigned long flags;
bool is_agg = false;
- /*
- * If the frame needs to go out off-channel, then
- * we'll have put the PAN context to that channel,
- * so make the frame go out there.
- */
- if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
- ctx = &priv->contexts[IWL_RXON_CTX_PAN];
- else if (info->control.vif)
+ if (info->control.vif)
ctx = iwl_rxon_ctx_from_vif(info->control.vif);
- spin_lock_irqsave(&priv->lock, flags);
- if (iwl_is_rfkill(priv)) {
+ spin_lock_irqsave(&priv->shrd->lock, flags);
+ if (iwl_is_rfkill(priv->shrd)) {
IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n");
goto drop_unlock_priv;
}
@@ -382,7 +304,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_PSPOLL_RESPONSE)) {
+ (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) {
/*
* This sends an asynchronous command to the device,
* but we can rely on it being processed before the
@@ -395,52 +317,19 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
iwl_sta_modify_sleep_tx_count(priv, sta_id, 1);
}
- /*
- * Send this frame after DTIM -- there's a special queue
- * reserved for this for contexts that support AP mode.
- */
- if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
- txq_id = ctx->mcast_queue;
- /*
- * The microcode will clear the more data
- * bit in the last frame it transmits.
- */
- hdr->frame_control |=
- cpu_to_le16(IEEE80211_FCTL_MOREDATA);
- } else
- txq_id = ctx->ac_to_queue[skb_get_queue_mapping(skb)];
+ if (info->flags & IEEE80211_TX_CTL_AMPDU)
+ is_agg = true;
- /* irqs already disabled/saved above when locking priv->lock */
- spin_lock(&priv->sta_lock);
+ /* irqs already disabled/saved above when locking priv->shrd->lock */
+ spin_lock(&priv->shrd->sta_lock);
- if (ieee80211_is_data_qos(fc)) {
- u8 *qc = NULL;
- qc = ieee80211_get_qos_ctl(hdr);
- tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
-
- if (WARN_ON_ONCE(tid >= MAX_TID_COUNT))
- goto drop_unlock_sta;
-
- seq_number = priv->stations[sta_id].tid[tid].seq_number;
- seq_number &= IEEE80211_SCTL_SEQ;
- hdr->seq_ctrl = hdr->seq_ctrl &
- cpu_to_le16(IEEE80211_SCTL_FRAG);
- hdr->seq_ctrl |= cpu_to_le16(seq_number);
- seq_number += 0x10;
- /* aggregation is on for this <sta,tid> */
- if (info->flags & IEEE80211_TX_CTL_AMPDU &&
- priv->stations[sta_id].tid[tid].agg.state == IWL_AGG_ON) {
- txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
- is_agg = true;
- }
- }
+ dev_cmd = kmem_cache_alloc(priv->tx_cmd_pool, GFP_ATOMIC);
- tx_cmd = trans_get_tx_cmd(&priv->trans, txq_id);
- if (unlikely(!tx_cmd))
+ if (unlikely(!dev_cmd))
goto drop_unlock_sta;
- /* Copy MAC header from skb into command buffer */
- memcpy(tx_cmd->hdr, hdr, hdr_len);
+ memset(dev_cmd, 0, sizeof(*dev_cmd));
+ tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload;
/* Total # bytes to be transmitted */
len = (u16)skb->len;
@@ -457,17 +346,16 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
iwl_update_stats(priv, true, fc, len);
- if (trans_tx(&priv->trans, skb, tx_cmd, txq_id, fc, is_agg, ctx))
- goto drop_unlock_sta;
+ memset(&info->status, 0, sizeof(info->status));
- if (ieee80211_is_data_qos(fc)) {
- priv->stations[sta_id].tid[tid].tfds_in_queue++;
- if (!ieee80211_has_morefrags(fc))
- priv->stations[sta_id].tid[tid].seq_number = seq_number;
- }
+ info->driver_data[0] = ctx;
+ info->driver_data[1] = dev_cmd;
+
+ if (iwl_trans_tx(trans(priv), skb, dev_cmd, ctx->ctxid, sta_id))
+ goto drop_unlock_sta;
- spin_unlock(&priv->sta_lock);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock(&priv->shrd->sta_lock);
+ spin_unlock_irqrestore(&priv->shrd->lock, flags);
/*
* Avoid atomic ops if it isn't an associated client.
@@ -482,41 +370,20 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
return 0;
drop_unlock_sta:
- spin_unlock(&priv->sta_lock);
+ if (dev_cmd)
+ kmem_cache_free(priv->tx_cmd_pool, dev_cmd);
+ spin_unlock(&priv->shrd->sta_lock);
drop_unlock_priv:
- spin_unlock_irqrestore(&priv->lock, flags);
- return -1;
-}
-
-/*
- * Find first available (lowest unused) Tx Queue, mark it "active".
- * Called only when finding queue for aggregation.
- * Should never return anything < 7, because they should already
- * be in use as EDCA AC (0-3), Command (4), reserved (5, 6)
- */
-static int iwlagn_txq_ctx_activate_free(struct iwl_priv *priv)
-{
- int txq_id;
-
- for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
- if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk))
- return txq_id;
+ spin_unlock_irqrestore(&priv->shrd->lock, flags);
return -1;
}
int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
{
+ struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
int sta_id;
- int tx_fifo;
- int txq_id;
int ret;
- unsigned long flags;
- struct iwl_tid_data *tid_data;
-
- tx_fifo = get_fifo_from_tid(iwl_rxon_ctx_from_vif(vif), tid);
- if (unlikely(tx_fifo < 0))
- return tx_fifo;
IWL_DEBUG_HT(priv, "TX AGG request on ra = %pM tid = %d\n",
sta->addr, tid);
@@ -526,58 +393,29 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
IWL_ERR(priv, "Start AGG on invalid station\n");
return -ENXIO;
}
- if (unlikely(tid >= MAX_TID_COUNT))
+ if (unlikely(tid >= IWL_MAX_TID_COUNT))
return -EINVAL;
- if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) {
+ if (priv->shrd->tid_data[sta_id][tid].agg.state != IWL_AGG_OFF) {
IWL_ERR(priv, "Start AGG when state is not IWL_AGG_OFF !\n");
return -ENXIO;
}
- txq_id = iwlagn_txq_ctx_activate_free(priv);
- if (txq_id == -1) {
- IWL_ERR(priv, "No free aggregation queue available\n");
- return -ENXIO;
- }
-
- spin_lock_irqsave(&priv->sta_lock, flags);
- tid_data = &priv->stations[sta_id].tid[tid];
- *ssn = SEQ_TO_SN(tid_data->seq_number);
- tid_data->agg.txq_id = txq_id;
- tid_data->agg.tx_fifo = tx_fifo;
- iwl_set_swq_id(&priv->txq[txq_id], get_ac_from_tid(tid), txq_id);
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-
- ret = iwlagn_txq_agg_enable(priv, txq_id, sta_id, tid);
+ ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
if (ret)
return ret;
- spin_lock_irqsave(&priv->sta_lock, flags);
- tid_data = &priv->stations[sta_id].tid[tid];
- if (tid_data->tfds_in_queue == 0) {
- IWL_DEBUG_HT(priv, "HW queue is empty\n");
- tid_data->agg.state = IWL_AGG_ON;
- ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
- } else {
- IWL_DEBUG_HT(priv, "HW queue is NOT empty: %d packets in HW queue\n",
- tid_data->tfds_in_queue);
- tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
- }
- spin_unlock_irqrestore(&priv->sta_lock, flags);
+ ret = iwl_trans_tx_agg_alloc(trans(priv), vif_priv->ctx->ctxid, sta_id,
+ tid, ssn);
+
return ret;
}
int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid)
{
- int tx_fifo_id, txq_id, sta_id, ssn;
- struct iwl_tid_data *tid_data;
- int write_ptr, read_ptr;
- unsigned long flags;
-
- tx_fifo_id = get_fifo_from_tid(iwl_rxon_ctx_from_vif(vif), tid);
- if (unlikely(tx_fifo_id < 0))
- return tx_fifo_id;
+ int sta_id;
+ struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
sta_id = iwl_sta_id(sta);
@@ -586,101 +424,8 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
return -ENXIO;
}
- spin_lock_irqsave(&priv->sta_lock, flags);
-
- tid_data = &priv->stations[sta_id].tid[tid];
- ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
- txq_id = tid_data->agg.txq_id;
-
- switch (priv->stations[sta_id].tid[tid].agg.state) {
- case IWL_EMPTYING_HW_QUEUE_ADDBA:
- /*
- * This can happen if the peer stops aggregation
- * again before we've had a chance to drain the
- * queue we selected previously, i.e. before the
- * session was really started completely.
- */
- IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
- goto turn_off;
- case IWL_AGG_ON:
- break;
- default:
- IWL_WARN(priv, "Stopping AGG while state not ON or starting\n");
- }
-
- write_ptr = priv->txq[txq_id].q.write_ptr;
- read_ptr = priv->txq[txq_id].q.read_ptr;
-
- /* The queue is not empty */
- if (write_ptr != read_ptr) {
- IWL_DEBUG_HT(priv, "Stopping a non empty AGG HW QUEUE\n");
- priv->stations[sta_id].tid[tid].agg.state =
- IWL_EMPTYING_HW_QUEUE_DELBA;
- spin_unlock_irqrestore(&priv->sta_lock, flags);
- return 0;
- }
-
- IWL_DEBUG_HT(priv, "HW queue is empty\n");
- turn_off:
- priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
-
- /* do not restore/save irqs */
- spin_unlock(&priv->sta_lock);
- spin_lock(&priv->lock);
-
- /*
- * the only reason this call can fail is queue number out of range,
- * which can happen if uCode is reloaded and all the station
- * information are lost. if it is outside the range, there is no need
- * to deactivate the uCode queue, just return "success" to allow
- * mac80211 to clean up it own data.
- */
- trans_txq_agg_disable(&priv->trans, txq_id, ssn, tx_fifo_id);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
-
- return 0;
-}
-
-int iwlagn_txq_check_empty(struct iwl_priv *priv,
- int sta_id, u8 tid, int txq_id)
-{
- struct iwl_queue *q = &priv->txq[txq_id].q;
- u8 *addr = priv->stations[sta_id].sta.sta.addr;
- struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
- struct iwl_rxon_context *ctx;
-
- ctx = &priv->contexts[priv->stations[sta_id].ctxid];
-
- lockdep_assert_held(&priv->sta_lock);
-
- switch (priv->stations[sta_id].tid[tid].agg.state) {
- case IWL_EMPTYING_HW_QUEUE_DELBA:
- /* We are reclaiming the last packet of the */
- /* aggregated HW queue */
- if ((txq_id == tid_data->agg.txq_id) &&
- (q->read_ptr == q->write_ptr)) {
- u16 ssn = SEQ_TO_SN(tid_data->seq_number);
- int tx_fifo = get_fifo_from_tid(ctx, tid);
- IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n");
- trans_txq_agg_disable(&priv->trans, txq_id,
- ssn, tx_fifo);
- tid_data->agg.state = IWL_AGG_OFF;
- ieee80211_stop_tx_ba_cb_irqsafe(ctx->vif, addr, tid);
- }
- break;
- case IWL_EMPTYING_HW_QUEUE_ADDBA:
- /* We are reclaiming the last packet of the queue */
- if (tid_data->tfds_in_queue == 0) {
- IWL_DEBUG_HT(priv, "HW queue empty: continue ADDBA flow\n");
- tid_data->agg.state = IWL_AGG_ON;
- ieee80211_start_tx_ba_cb_irqsafe(ctx->vif, addr, tid);
- }
- break;
- }
-
- return 0;
+ return iwl_trans_tx_agg_disable(trans(priv), vif_priv->ctx->ctxid,
+ sta_id, tid);
}
static void iwlagn_non_agg_tx_status(struct iwl_priv *priv,
@@ -702,147 +447,394 @@ static void iwlagn_non_agg_tx_status(struct iwl_priv *priv,
rcu_read_unlock();
}
-static void iwlagn_tx_status(struct iwl_priv *priv, struct iwl_tx_info *tx_info,
- bool is_agg)
+/**
+ * translate ucode response to mac80211 tx status control values
+ */
+static void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
+ struct ieee80211_tx_info *info)
+{
+ struct ieee80211_tx_rate *r = &info->control.rates[0];
+
+ info->antenna_sel_tx =
+ ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
+ if (rate_n_flags & RATE_MCS_HT_MSK)
+ r->flags |= IEEE80211_TX_RC_MCS;
+ if (rate_n_flags & RATE_MCS_GF_MSK)
+ r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
+ if (rate_n_flags & RATE_MCS_HT40_MSK)
+ r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+ if (rate_n_flags & RATE_MCS_DUP_MSK)
+ r->flags |= IEEE80211_TX_RC_DUP_DATA;
+ if (rate_n_flags & RATE_MCS_SGI_MSK)
+ r->flags |= IEEE80211_TX_RC_SHORT_GI;
+ r->idx = iwlagn_hwrate_to_mac80211_idx(rate_n_flags, info->band);
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+const char *iwl_get_tx_fail_reason(u32 status)
{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx_info->skb->data;
+#define TX_STATUS_FAIL(x) case TX_STATUS_FAIL_ ## x: return #x
+#define TX_STATUS_POSTPONE(x) case TX_STATUS_POSTPONE_ ## x: return #x
+
+ switch (status & TX_STATUS_MSK) {
+ case TX_STATUS_SUCCESS:
+ return "SUCCESS";
+ TX_STATUS_POSTPONE(DELAY);
+ TX_STATUS_POSTPONE(FEW_BYTES);
+ TX_STATUS_POSTPONE(BT_PRIO);
+ TX_STATUS_POSTPONE(QUIET_PERIOD);
+ TX_STATUS_POSTPONE(CALC_TTAK);
+ TX_STATUS_FAIL(INTERNAL_CROSSED_RETRY);
+ TX_STATUS_FAIL(SHORT_LIMIT);
+ TX_STATUS_FAIL(LONG_LIMIT);
+ TX_STATUS_FAIL(FIFO_UNDERRUN);
+ TX_STATUS_FAIL(DRAIN_FLOW);
+ TX_STATUS_FAIL(RFKILL_FLUSH);
+ TX_STATUS_FAIL(LIFE_EXPIRE);
+ TX_STATUS_FAIL(DEST_PS);
+ TX_STATUS_FAIL(HOST_ABORTED);
+ TX_STATUS_FAIL(BT_RETRY);
+ TX_STATUS_FAIL(STA_INVALID);
+ TX_STATUS_FAIL(FRAG_DROPPED);
+ TX_STATUS_FAIL(TID_DISABLE);
+ TX_STATUS_FAIL(FIFO_FLUSHED);
+ TX_STATUS_FAIL(INSUFFICIENT_CF_POLL);
+ TX_STATUS_FAIL(PASSIVE_NO_RX);
+ TX_STATUS_FAIL(NO_BEACON_ON_RADAR);
+ }
- if (!is_agg)
- iwlagn_non_agg_tx_status(priv, tx_info->ctx, hdr->addr1);
+ return "UNKNOWN";
- ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb);
+#undef TX_STATUS_FAIL
+#undef TX_STATUS_POSTPONE
}
+#endif /* CONFIG_IWLWIFI_DEBUG */
-int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
+static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status)
{
- struct iwl_tx_queue *txq = &priv->txq[txq_id];
- struct iwl_queue *q = &txq->q;
- struct iwl_tx_info *tx_info;
- int nfreed = 0;
- struct ieee80211_hdr *hdr;
+ status &= AGG_TX_STATUS_MSK;
- if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) {
- IWL_ERR(priv, "%s: Read index for DMA queue txq id (%d), "
- "index %d is out of range [0-%d] %d %d.\n", __func__,
- txq_id, index, q->n_bd, q->write_ptr, q->read_ptr);
- return 0;
+ switch (status) {
+ case AGG_TX_STATE_UNDERRUN_MSK:
+ priv->reply_agg_tx_stats.underrun++;
+ break;
+ case AGG_TX_STATE_BT_PRIO_MSK:
+ priv->reply_agg_tx_stats.bt_prio++;
+ break;
+ case AGG_TX_STATE_FEW_BYTES_MSK:
+ priv->reply_agg_tx_stats.few_bytes++;
+ break;
+ case AGG_TX_STATE_ABORT_MSK:
+ priv->reply_agg_tx_stats.abort++;
+ break;
+ case AGG_TX_STATE_LAST_SENT_TTL_MSK:
+ priv->reply_agg_tx_stats.last_sent_ttl++;
+ break;
+ case AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK:
+ priv->reply_agg_tx_stats.last_sent_try++;
+ break;
+ case AGG_TX_STATE_LAST_SENT_BT_KILL_MSK:
+ priv->reply_agg_tx_stats.last_sent_bt_kill++;
+ break;
+ case AGG_TX_STATE_SCD_QUERY_MSK:
+ priv->reply_agg_tx_stats.scd_query++;
+ break;
+ case AGG_TX_STATE_TEST_BAD_CRC32_MSK:
+ priv->reply_agg_tx_stats.bad_crc32++;
+ break;
+ case AGG_TX_STATE_RESPONSE_MSK:
+ priv->reply_agg_tx_stats.response++;
+ break;
+ case AGG_TX_STATE_DUMP_TX_MSK:
+ priv->reply_agg_tx_stats.dump_tx++;
+ break;
+ case AGG_TX_STATE_DELAY_TX_MSK:
+ priv->reply_agg_tx_stats.delay_tx++;
+ break;
+ default:
+ priv->reply_agg_tx_stats.unknown++;
+ break;
}
+}
+
+static void iwl_rx_reply_tx_agg(struct iwl_priv *priv,
+ struct iwlagn_tx_resp *tx_resp)
+{
+ struct agg_tx_status *frame_status = &tx_resp->status;
+ int tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >>
+ IWLAGN_TX_RES_TID_POS;
+ int sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >>
+ IWLAGN_TX_RES_RA_POS;
+ struct iwl_ht_agg *agg = &priv->shrd->tid_data[sta_id][tid].agg;
+ u32 status = le16_to_cpu(tx_resp->status.status);
+ int i;
+
+ if (agg->wait_for_ba)
+ IWL_DEBUG_TX_REPLY(priv,
+ "got tx response w/o block-ack\n");
- for (index = iwl_queue_inc_wrap(index, q->n_bd);
- q->read_ptr != index;
- q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+ agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+ agg->wait_for_ba = (tx_resp->frame_count > 1);
- tx_info = &txq->txb[txq->q.read_ptr];
+ /*
+ * If the BT kill count is non-zero, we'll get this
+ * notification again.
+ */
+ if (tx_resp->bt_kill_count && tx_resp->frame_count == 1 &&
+ priv->cfg->bt_params &&
+ priv->cfg->bt_params->advanced_bt_coexist) {
+ IWL_DEBUG_COEX(priv, "receive reply tx w/ bt_kill\n");
+ }
- if (WARN_ON_ONCE(tx_info->skb == NULL))
- continue;
+ if (tx_resp->frame_count == 1)
+ return;
- hdr = (struct ieee80211_hdr *)tx_info->skb->data;
- if (ieee80211_is_data_qos(hdr->frame_control))
- nfreed++;
+ /* Construct bit-map of pending frames within Tx window */
+ for (i = 0; i < tx_resp->frame_count; i++) {
+ u16 fstatus = le16_to_cpu(frame_status[i].status);
- iwlagn_tx_status(priv, tx_info,
- txq_id >= IWLAGN_FIRST_AMPDU_QUEUE);
- tx_info->skb = NULL;
+ if (status & AGG_TX_STATUS_MSK)
+ iwlagn_count_agg_tx_err_status(priv, fstatus);
- iwlagn_txq_inval_byte_cnt_tbl(priv, txq);
+ if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
+ AGG_TX_STATE_ABORT_MSK))
+ continue;
- iwlagn_txq_free_tfd(priv, txq, txq->q.read_ptr);
+ IWL_DEBUG_TX_REPLY(priv, "status %s (0x%08x), "
+ "try-count (0x%08x)\n",
+ iwl_get_agg_tx_fail_reason(fstatus),
+ fstatus & AGG_TX_STATUS_MSK,
+ fstatus & AGG_TX_TRY_MSK);
}
- return nfreed;
}
-/**
- * iwlagn_tx_status_reply_compressed_ba - Update tx status from block-ack
- *
- * Go through block-ack's bitmap of ACK'd frames, update driver's record of
- * ACK vs. not. This gets sent to mac80211, then to rate scaling algo.
- */
-static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv,
- struct iwl_ht_agg *agg,
- struct iwl_compressed_ba_resp *ba_resp)
+#ifdef CONFIG_IWLWIFI_DEBUG
+#define AGG_TX_STATE_FAIL(x) case AGG_TX_STATE_ ## x: return #x
+const char *iwl_get_agg_tx_fail_reason(u16 status)
{
- int sh;
- u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl);
- u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
- struct ieee80211_tx_info *info;
- u64 bitmap, sent_bitmap;
-
- if (unlikely(!agg->wait_for_ba)) {
- if (unlikely(ba_resp->bitmap))
- IWL_ERR(priv, "Received BA when not expected\n");
- return -EINVAL;
+ status &= AGG_TX_STATUS_MSK;
+ switch (status) {
+ case AGG_TX_STATE_TRANSMITTED:
+ return "SUCCESS";
+ AGG_TX_STATE_FAIL(UNDERRUN_MSK);
+ AGG_TX_STATE_FAIL(BT_PRIO_MSK);
+ AGG_TX_STATE_FAIL(FEW_BYTES_MSK);
+ AGG_TX_STATE_FAIL(ABORT_MSK);
+ AGG_TX_STATE_FAIL(LAST_SENT_TTL_MSK);
+ AGG_TX_STATE_FAIL(LAST_SENT_TRY_CNT_MSK);
+ AGG_TX_STATE_FAIL(LAST_SENT_BT_KILL_MSK);
+ AGG_TX_STATE_FAIL(SCD_QUERY_MSK);
+ AGG_TX_STATE_FAIL(TEST_BAD_CRC32_MSK);
+ AGG_TX_STATE_FAIL(RESPONSE_MSK);
+ AGG_TX_STATE_FAIL(DUMP_TX_MSK);
+ AGG_TX_STATE_FAIL(DELAY_TX_MSK);
}
- /* Mark that the expected block-ack response arrived */
- agg->wait_for_ba = 0;
- IWL_DEBUG_TX_REPLY(priv, "BA %d %d\n", agg->start_idx, ba_resp->seq_ctl);
-
- /* Calculate shift to align block-ack bits with our Tx window bits */
- sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4);
- if (sh < 0)
- sh += 0x100;
+ return "UNKNOWN";
+}
+#endif /* CONFIG_IWLWIFI_DEBUG */
- /*
- * Check for success or failure according to the
- * transmitted bitmap and block-ack bitmap
- */
- bitmap = le64_to_cpu(ba_resp->bitmap) >> sh;
- sent_bitmap = bitmap & agg->bitmap;
+static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp)
+{
+ return le32_to_cpup((__le32 *)&tx_resp->status +
+ tx_resp->frame_count) & MAX_SN;
+}
- /* Sanity check values reported by uCode */
- if (ba_resp->txed_2_done > ba_resp->txed) {
- IWL_DEBUG_TX_REPLY(priv,
- "bogus sent(%d) and ack(%d) count\n",
- ba_resp->txed, ba_resp->txed_2_done);
- /*
- * set txed_2_done = txed,
- * so it won't impact rate scale
- */
- ba_resp->txed = ba_resp->txed_2_done;
- }
- IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n",
- ba_resp->txed, ba_resp->txed_2_done);
+static void iwlagn_count_tx_err_status(struct iwl_priv *priv, u16 status)
+{
+ status &= TX_STATUS_MSK;
- /* Find the first ACKed frame to store the TX status */
- while (sent_bitmap && !(sent_bitmap & 1)) {
- agg->start_idx = (agg->start_idx + 1) & 0xff;
- sent_bitmap >>= 1;
+ switch (status) {
+ case TX_STATUS_POSTPONE_DELAY:
+ priv->reply_tx_stats.pp_delay++;
+ break;
+ case TX_STATUS_POSTPONE_FEW_BYTES:
+ priv->reply_tx_stats.pp_few_bytes++;
+ break;
+ case TX_STATUS_POSTPONE_BT_PRIO:
+ priv->reply_tx_stats.pp_bt_prio++;
+ break;
+ case TX_STATUS_POSTPONE_QUIET_PERIOD:
+ priv->reply_tx_stats.pp_quiet_period++;
+ break;
+ case TX_STATUS_POSTPONE_CALC_TTAK:
+ priv->reply_tx_stats.pp_calc_ttak++;
+ break;
+ case TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY:
+ priv->reply_tx_stats.int_crossed_retry++;
+ break;
+ case TX_STATUS_FAIL_SHORT_LIMIT:
+ priv->reply_tx_stats.short_limit++;
+ break;
+ case TX_STATUS_FAIL_LONG_LIMIT:
+ priv->reply_tx_stats.long_limit++;
+ break;
+ case TX_STATUS_FAIL_FIFO_UNDERRUN:
+ priv->reply_tx_stats.fifo_underrun++;
+ break;
+ case TX_STATUS_FAIL_DRAIN_FLOW:
+ priv->reply_tx_stats.drain_flow++;
+ break;
+ case TX_STATUS_FAIL_RFKILL_FLUSH:
+ priv->reply_tx_stats.rfkill_flush++;
+ break;
+ case TX_STATUS_FAIL_LIFE_EXPIRE:
+ priv->reply_tx_stats.life_expire++;
+ break;
+ case TX_STATUS_FAIL_DEST_PS:
+ priv->reply_tx_stats.dest_ps++;
+ break;
+ case TX_STATUS_FAIL_HOST_ABORTED:
+ priv->reply_tx_stats.host_abort++;
+ break;
+ case TX_STATUS_FAIL_BT_RETRY:
+ priv->reply_tx_stats.bt_retry++;
+ break;
+ case TX_STATUS_FAIL_STA_INVALID:
+ priv->reply_tx_stats.sta_invalid++;
+ break;
+ case TX_STATUS_FAIL_FRAG_DROPPED:
+ priv->reply_tx_stats.frag_drop++;
+ break;
+ case TX_STATUS_FAIL_TID_DISABLE:
+ priv->reply_tx_stats.tid_disable++;
+ break;
+ case TX_STATUS_FAIL_FIFO_FLUSHED:
+ priv->reply_tx_stats.fifo_flush++;
+ break;
+ case TX_STATUS_FAIL_INSUFFICIENT_CF_POLL:
+ priv->reply_tx_stats.insuff_cf_poll++;
+ break;
+ case TX_STATUS_FAIL_PASSIVE_NO_RX:
+ priv->reply_tx_stats.fail_hw_drop++;
+ break;
+ case TX_STATUS_FAIL_NO_BEACON_ON_RADAR:
+ priv->reply_tx_stats.sta_color_mismatch++;
+ break;
+ default:
+ priv->reply_tx_stats.unknown++;
+ break;
}
+}
- info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb);
- memset(&info->status, 0, sizeof(info->status));
- info->flags |= IEEE80211_TX_STAT_ACK;
- info->flags |= IEEE80211_TX_STAT_AMPDU;
- info->status.ampdu_ack_len = ba_resp->txed_2_done;
- info->status.ampdu_len = ba_resp->txed;
- iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info);
+static void iwlagn_set_tx_status(struct iwl_priv *priv,
+ struct ieee80211_tx_info *info,
+ struct iwlagn_tx_resp *tx_resp,
+ bool is_agg)
+{
+ u16 status = le16_to_cpu(tx_resp->status.status);
+
+ info->status.rates[0].count = tx_resp->failure_frame + 1;
+ if (is_agg)
+ info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+ info->flags |= iwl_tx_status_to_mac80211(status);
+ iwlagn_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags),
+ info);
+ if (!iwl_is_tx_success(status))
+ iwlagn_count_tx_err_status(priv, status);
+}
- return 0;
+static void iwl_check_abort_status(struct iwl_priv *priv,
+ u8 frame_count, u32 status)
+{
+ 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);
+ }
}
-/**
- * translate ucode response to mac80211 tx status control values
- */
-void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
- struct ieee80211_tx_info *info)
+int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+ struct iwl_device_cmd *cmd)
{
- struct ieee80211_tx_rate *r = &info->control.rates[0];
+ 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 ieee80211_hdr *hdr;
+ u32 status = le16_to_cpu(tx_resp->status.status);
+ u32 ssn = iwlagn_get_scd_ssn(tx_resp);
+ int tid;
+ 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;
+ bool is_agg = (txq_id >= IWLAGN_FIRST_AMPDU_QUEUE);
+
+ tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >>
+ IWLAGN_TX_RES_TID_POS;
+ sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >>
+ IWLAGN_TX_RES_RA_POS;
+
+ spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+
+ if (is_agg)
+ iwl_rx_reply_tx_agg(priv, tx_resp);
+
+ if (tx_resp->frame_count == 1) {
+ __skb_queue_head_init(&skbs);
+ /*we can free until ssn % q.n_bd not inclusive */
+ iwl_trans_reclaim(trans(priv), sta_id, tid, txq_id,
+ ssn, status, &skbs);
+ freed = 0;
+ while (!skb_queue_empty(&skbs)) {
+ skb = __skb_dequeue(&skbs);
+ hdr = (struct ieee80211_hdr *)skb->data;
+
+ if (!ieee80211_is_data_qos(hdr->frame_control))
+ priv->last_seq_ctl = tx_resp->seq_ctl;
+
+ info = IEEE80211_SKB_CB(skb);
+ ctx = info->driver_data[0];
+ kmem_cache_free(priv->tx_cmd_pool,
+ (info->driver_data[1]));
+
+ memset(&info->status, 0, sizeof(info->status));
+
+ 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);
+
+ IWL_DEBUG_TX_REPLY(priv,
+ "TXQ %d status %s (0x%08x) "
+ "rate_n_flags 0x%x retries %d\n",
+ txq_id,
+ iwl_get_tx_fail_reason(status),
+ status,
+ le32_to_cpu(tx_resp->rate_n_flags),
+ tx_resp->failure_frame);
+
+ IWL_DEBUG_TX_REPLY(priv,
+ "FrameCnt = %d, idx=%d\n",
+ tx_resp->frame_count, cmd_index);
+ }
+
+ /* check if BAR is needed */
+ if (is_agg && !iwl_is_tx_success(status))
+ info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
+ iwlagn_set_tx_status(priv, IEEE80211_SKB_CB(skb),
+ tx_resp, is_agg);
+ if (!is_agg)
+ iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1);
+
+ ieee80211_tx_status_irqsafe(priv->hw, skb);
+
+ freed++;
+ }
- info->antenna_sel_tx =
- ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
- if (rate_n_flags & RATE_MCS_HT_MSK)
- r->flags |= IEEE80211_TX_RC_MCS;
- if (rate_n_flags & RATE_MCS_GF_MSK)
- r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
- if (rate_n_flags & RATE_MCS_HT40_MSK)
- r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
- if (rate_n_flags & RATE_MCS_DUP_MSK)
- r->flags |= IEEE80211_TX_RC_DUP_DATA;
- if (rate_n_flags & RATE_MCS_SGI_MSK)
- r->flags |= IEEE80211_TX_RC_SHORT_GI;
- r->idx = iwlagn_hwrate_to_mac80211_idx(rate_n_flags, info->band);
+ WARN_ON(!is_agg && freed != 1);
+ }
+
+ iwl_check_abort_status(priv, tx_resp->frame_count, status);
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+ return 0;
}
/**
@@ -851,17 +843,21 @@ void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
* Handles block-acknowledge notification from device, which reports success
* of frames sent via aggregation.
*/
-void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
+int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
+ struct iwl_rx_mem_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_tx_queue *txq = NULL;
struct iwl_ht_agg *agg;
- int index;
+ 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;
- unsigned long flags;
+ int freed;
/* "flow" corresponds to Tx queue */
u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
@@ -870,16 +866,18 @@ void 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 >= priv->hw_params.max_txq_num) {
+ if (scd_flow >= hw_params(priv).max_txq_num) {
IWL_ERR(priv,
"BUG_ON scd_flow is bigger than number of queues\n");
- return;
+ return 0;
}
- txq = &priv->txq[scd_flow];
sta_id = ba_resp->sta_id;
tid = ba_resp->tid;
- agg = &priv->stations[sta_id].tid[tid].agg;
+ agg = &priv->shrd->tid_data[sta_id][tid].agg;
+
+ spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+
if (unlikely(agg->txq_id != scd_flow)) {
/*
* FIXME: this is a uCode bug which need to be addressed,
@@ -890,88 +888,84 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
IWL_DEBUG_TX_REPLY(priv,
"BA scd_flow %d does not match txq_id %d\n",
scd_flow, agg->txq_id);
- return;
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+ return 0;
}
- /* Find index just before block-ack window */
- index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
-
- spin_lock_irqsave(&priv->sta_lock, flags);
+ 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);
+ return 0;
+ }
IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, "
"sta_id = %d\n",
agg->wait_for_ba,
(u8 *) &ba_resp->sta_addr_lo32,
ba_resp->sta_id);
- IWL_DEBUG_TX_REPLY(priv, "TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = "
- "%d, scd_ssn = %d\n",
+ IWL_DEBUG_TX_REPLY(priv, "TID = %d, SeqCtl = %d, bitmap = 0x%llx, "
+ "scd_flow = %d, scd_ssn = %d\n",
ba_resp->tid,
ba_resp->seq_ctl,
(unsigned long long)le64_to_cpu(ba_resp->bitmap),
ba_resp->scd_flow,
ba_resp->scd_ssn);
- IWL_DEBUG_TX_REPLY(priv, "DAT start_idx = %d, bitmap = 0x%llx\n",
- agg->start_idx,
- (unsigned long long)agg->bitmap);
- /* Update driver's record of ACK vs. not for each frame in window */
- iwlagn_tx_status_reply_compressed_ba(priv, agg, ba_resp);
+ /* Mark that the expected block-ack response arrived */
+ agg->wait_for_ba = false;
+
+ /* Sanity check values reported by uCode */
+ if (ba_resp->txed_2_done > ba_resp->txed) {
+ IWL_DEBUG_TX_REPLY(priv,
+ "bogus sent(%d) and ack(%d) count\n",
+ ba_resp->txed, ba_resp->txed_2_done);
+ /*
+ * set txed_2_done = txed,
+ * so it won't impact rate scale
+ */
+ ba_resp->txed = ba_resp->txed_2_done;
+ }
+ IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n",
+ ba_resp->txed, ba_resp->txed_2_done);
+
+ __skb_queue_head_init(&reclaimed_skbs);
/* Release all TFDs before the SSN, i.e. all TFDs in front of
* block-ack window (we assume that they've been successfully
* transmitted ... if not, it's too late anyway). */
- if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) {
- /* calculate mac80211 ampdu sw queue to wake */
- int freed = iwlagn_tx_queue_reclaim(priv, scd_flow, index);
- iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
-
- if ((iwl_queue_space(&txq->q) > txq->q.low_mark) &&
- priv->mac80211_registered &&
- (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA))
- iwl_wake_queue(priv, txq);
-
- iwlagn_txq_check_empty(priv, sta_id, tid, scd_flow);
- }
+ iwl_trans_reclaim(trans(priv), sta_id, tid, scd_flow, ba_resp_scd_ssn,
+ 0, &reclaimed_skbs);
+ freed = 0;
+ while (!skb_queue_empty(&reclaimed_skbs)) {
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-}
+ skb = __skb_dequeue(&reclaimed_skbs);
+ hdr = (struct ieee80211_hdr *)skb->data;
-#ifdef CONFIG_IWLWIFI_DEBUG
-const char *iwl_get_tx_fail_reason(u32 status)
-{
-#define TX_STATUS_FAIL(x) case TX_STATUS_FAIL_ ## x: return #x
-#define TX_STATUS_POSTPONE(x) case TX_STATUS_POSTPONE_ ## x: return #x
+ if (ieee80211_is_data_qos(hdr->frame_control))
+ freed++;
+ else
+ WARN_ON_ONCE(1);
+
+ info = IEEE80211_SKB_CB(skb);
+ kmem_cache_free(priv->tx_cmd_pool, (info->driver_data[1]));
+
+ if (freed == 1) {
+ /* this is the first skb we deliver in this batch */
+ /* put the rate scaling data there */
+ info = IEEE80211_SKB_CB(skb);
+ memset(&info->status, 0, sizeof(info->status));
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ info->flags |= IEEE80211_TX_STAT_AMPDU;
+ info->status.ampdu_ack_len = ba_resp->txed_2_done;
+ info->status.ampdu_len = ba_resp->txed;
+ iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags,
+ info);
+ }
- switch (status & TX_STATUS_MSK) {
- case TX_STATUS_SUCCESS:
- return "SUCCESS";
- TX_STATUS_POSTPONE(DELAY);
- TX_STATUS_POSTPONE(FEW_BYTES);
- TX_STATUS_POSTPONE(BT_PRIO);
- TX_STATUS_POSTPONE(QUIET_PERIOD);
- TX_STATUS_POSTPONE(CALC_TTAK);
- TX_STATUS_FAIL(INTERNAL_CROSSED_RETRY);
- TX_STATUS_FAIL(SHORT_LIMIT);
- TX_STATUS_FAIL(LONG_LIMIT);
- TX_STATUS_FAIL(FIFO_UNDERRUN);
- TX_STATUS_FAIL(DRAIN_FLOW);
- TX_STATUS_FAIL(RFKILL_FLUSH);
- TX_STATUS_FAIL(LIFE_EXPIRE);
- TX_STATUS_FAIL(DEST_PS);
- TX_STATUS_FAIL(HOST_ABORTED);
- TX_STATUS_FAIL(BT_RETRY);
- TX_STATUS_FAIL(STA_INVALID);
- TX_STATUS_FAIL(FRAG_DROPPED);
- TX_STATUS_FAIL(TID_DISABLE);
- TX_STATUS_FAIL(FIFO_FLUSHED);
- TX_STATUS_FAIL(INSUFFICIENT_CF_POLL);
- TX_STATUS_FAIL(PASSIVE_NO_RX);
- TX_STATUS_FAIL(NO_BEACON_ON_RADAR);
+ ieee80211_tx_status_irqsafe(priv->hw, skb);
}
- return "UNKNOWN";
-
-#undef TX_STATUS_FAIL
-#undef TX_STATUS_POSTPONE
+ spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+ return 0;
}
-#endif /* CONFIG_IWLWIFI_DEBUG */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
index a895a099d086..8ba0dd54e37d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
@@ -35,11 +35,11 @@
#include "iwl-dev.h"
#include "iwl-core.h"
#include "iwl-io.h"
-#include "iwl-helpers.h"
#include "iwl-agn-hw.h"
#include "iwl-agn.h"
#include "iwl-agn-calib.h"
#include "iwl-trans.h"
+#include "iwl-fh.h"
static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
{COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP,
@@ -84,42 +84,37 @@ static int iwlagn_load_section(struct iwl_priv *priv, const char *name,
priv->ucode_write_complete = 0;
- iwl_write_direct32(priv,
+ iwl_write_direct32(bus(priv),
FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
- iwl_write_direct32(priv,
+ iwl_write_direct32(bus(priv),
FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr);
- iwl_write_direct32(priv,
+ iwl_write_direct32(bus(priv),
FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
- iwl_write_direct32(priv,
+ iwl_write_direct32(bus(priv),
FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
(iwl_get_dma_hi_addr(phy_addr)
<< FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
- iwl_write_direct32(priv,
+ iwl_write_direct32(bus(priv),
FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX |
FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
- iwl_write_direct32(priv,
+ iwl_write_direct32(bus(priv),
FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE |
FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
IWL_DEBUG_FW(priv, "%s uCode section being loaded...\n", name);
- ret = wait_event_interruptible_timeout(priv->wait_command_queue,
- priv->ucode_write_complete, 5 * HZ);
- if (ret == -ERESTARTSYS) {
- IWL_ERR(priv, "Could not load the %s uCode section due "
- "to interrupt\n", name);
- return ret;
- }
+ ret = wait_event_timeout(priv->shrd->wait_command_queue,
+ priv->ucode_write_complete, 5 * HZ);
if (!ret) {
IWL_ERR(priv, "Could not load the %s uCode section\n",
name);
@@ -163,11 +158,11 @@ static int iwlagn_set_temperature_offset_calib(struct iwl_priv *priv)
{
struct iwl_calib_temperature_offset_cmd cmd;
__le16 *offset_calib =
- (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_TEMPERATURE);
+ (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_RAW_TEMPERATURE);
memset(&cmd, 0, sizeof(cmd));
iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD);
- memcpy(&cmd.radio_sensor_offset, offset_calib, sizeof(offset_calib));
+ memcpy(&cmd.radio_sensor_offset, offset_calib, sizeof(*offset_calib));
if (!(cmd.radio_sensor_offset))
cmd.radio_sensor_offset = DEFAULT_RADIO_SENSOR_OFFSET;
@@ -177,6 +172,42 @@ static int iwlagn_set_temperature_offset_calib(struct iwl_priv *priv)
(u8 *)&cmd, sizeof(cmd));
}
+static int iwlagn_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(priv,
+ EEPROM_KELVIN_TEMPERATURE);
+ __le16 *offset_calib_low =
+ (__le16 *)iwl_eeprom_query_addr(priv, 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(priv,
+ 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(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(priv, "Radio sensor offset high: %d\n",
+ le16_to_cpu(cmd.radio_sensor_offset_high));
+ IWL_DEBUG_CALIB(priv, "Radio sensor offset low: %d\n",
+ le16_to_cpu(cmd.radio_sensor_offset_low));
+ IWL_DEBUG_CALIB(priv, "Voltage Ref: %d\n",
+ le16_to_cpu(cmd.burntVoltageRef));
+
+ return iwl_calib_set(&priv->calib_results[IWL_CALIB_TEMP_OFFSET],
+ (u8 *)&cmd, sizeof(cmd));
+}
+
static int iwlagn_send_calib_cfg(struct iwl_priv *priv)
{
struct iwl_calib_cfg_cmd calib_cfg_cmd;
@@ -193,11 +224,12 @@ static int iwlagn_send_calib_cfg(struct iwl_priv *priv)
calib_cfg_cmd.ucd_calib_cfg.flags =
IWL_CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_MSK;
- return trans_send_cmd(&priv->trans, &cmd);
+ return iwl_trans_send_cmd(trans(priv), &cmd);
}
-void iwlagn_rx_calib_result(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
+int iwlagn_rx_calib_result(struct iwl_priv *priv,
+ struct iwl_rx_mem_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;
@@ -230,9 +262,10 @@ void iwlagn_rx_calib_result(struct iwl_priv *priv,
default:
IWL_ERR(priv, "Unknown calibration notification %d\n",
hdr->op_code);
- return;
+ return -1;
}
iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len);
+ return 0;
}
int iwlagn_init_alive_start(struct iwl_priv *priv)
@@ -262,8 +295,12 @@ int iwlagn_init_alive_start(struct iwl_priv *priv)
* temperature offset calibration is only needed for runtime ucode,
* so prepare the value now.
*/
- if (priv->cfg->need_temp_offset_calib)
- return iwlagn_set_temperature_offset_calib(priv);
+ if (priv->cfg->need_temp_offset_calib) {
+ if (priv->cfg->temp_offset_v2)
+ return iwlagn_set_temperature_offset_calib_v2(priv);
+ else
+ return iwlagn_set_temperature_offset_calib(priv);
+ }
return 0;
}
@@ -291,7 +328,7 @@ static int iwlagn_send_wimax_coex(struct iwl_priv *priv)
/* coexistence is disabled */
memset(&coex_cmd, 0, sizeof(coex_cmd));
}
- return trans_send_cmd_pdu(&priv->trans,
+ return iwl_trans_send_cmd_pdu(trans(priv),
COEX_PRIORITY_TABLE_CMD, CMD_SYNC,
sizeof(coex_cmd), &coex_cmd);
}
@@ -324,7 +361,7 @@ void iwlagn_send_prio_tbl(struct iwl_priv *priv)
memcpy(prio_tbl_cmd.prio_tbl, iwlagn_bt_prio_tbl,
sizeof(iwlagn_bt_prio_tbl));
- if (trans_send_cmd_pdu(&priv->trans,
+ if (iwl_trans_send_cmd_pdu(trans(priv),
REPLY_BT_COEX_PRIO_TABLE, CMD_SYNC,
sizeof(prio_tbl_cmd), &prio_tbl_cmd))
IWL_ERR(priv, "failed to send BT prio tbl command\n");
@@ -337,7 +374,7 @@ int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
env_cmd.action = action;
env_cmd.type = type;
- ret = trans_send_cmd_pdu(&priv->trans,
+ ret = iwl_trans_send_cmd_pdu(trans(priv),
REPLY_BT_COEX_PROT_ENV, CMD_SYNC,
sizeof(env_cmd), &env_cmd);
if (ret)
@@ -348,9 +385,21 @@ int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
static int iwlagn_alive_notify(struct iwl_priv *priv)
{
+ struct iwl_rxon_context *ctx;
int ret;
- trans_tx_start(&priv->trans);
+ if (!priv->tx_cmd_pool)
+ priv->tx_cmd_pool =
+ kmem_cache_create("iwlagn_dev_cmd",
+ sizeof(struct iwl_device_cmd),
+ sizeof(void *), 0, NULL);
+
+ if (!priv->tx_cmd_pool)
+ return -ENOMEM;
+
+ iwl_trans_tx_start(trans(priv));
+ for_each_context(priv, ctx)
+ ctx->last_tx_rejected = false;
ret = iwlagn_send_wimax_coex(priv);
if (ret)
@@ -369,7 +418,7 @@ static int iwlagn_alive_notify(struct iwl_priv *priv)
* using sample data 100 bytes apart. If these sample points are good,
* it's a pretty good bet that everything between them is good, too.
*/
-static int iwlcore_verify_inst_sparse(struct iwl_priv *priv,
+static int iwl_verify_inst_sparse(struct iwl_priv *priv,
struct fw_desc *fw_desc)
{
__le32 *image = (__le32 *)fw_desc->v_addr;
@@ -383,9 +432,9 @@ static int iwlcore_verify_inst_sparse(struct iwl_priv *priv,
/* 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(priv, HBUS_TARG_MEM_RADDR,
+ iwl_write_direct32(bus(priv), HBUS_TARG_MEM_RADDR,
i + IWLAGN_RTC_INST_LOWER_BOUND);
- val = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
+ val = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
if (val != le32_to_cpu(*image))
return -EIO;
}
@@ -404,14 +453,14 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv,
IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
- iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
+ iwl_write_direct32(bus(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(priv, HBUS_TARG_MEM_RDAT);
+ val = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
if (val != le32_to_cpu(*image)) {
IWL_ERR(priv, "uCode INST section at "
"offset 0x%x, is 0x%x, s/b 0x%x\n",
@@ -427,7 +476,7 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv,
*/
static int iwl_verify_ucode(struct iwl_priv *priv, struct fw_img *img)
{
- if (!iwlcore_verify_inst_sparse(priv, &img->code)) {
+ if (!iwl_verify_inst_sparse(priv, &img->code)) {
IWL_DEBUG_FW(priv, "uCode is good in inst SRAM\n");
return 0;
}
@@ -478,7 +527,7 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
int ret;
enum iwlagn_ucode_type old_type;
- ret = trans_start_device(&priv->trans);
+ ret = iwl_trans_start_device(trans(priv));
if (ret)
return ret;
@@ -495,7 +544,7 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
return ret;
}
- trans_kick_nic(&priv->trans);
+ iwl_trans_kick_nic(trans(priv));
/*
* Some things may run in the background now, but we
@@ -545,7 +594,7 @@ int iwlagn_run_init_ucode(struct iwl_priv *priv)
struct iwl_notification_wait calib_wait;
int ret;
- lockdep_assert_held(&priv->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
/* No init ucode required? Curious, but maybe ok */
if (!priv->ucode_init.code.len)
@@ -580,6 +629,6 @@ int iwlagn_run_init_ucode(struct iwl_priv *priv)
iwlagn_remove_notification(priv, &calib_wait);
out:
/* Whatever happened, stop the device */
- trans_stop_device(&priv->trans);
+ iwl_trans_stop_device(trans(priv));
return ret;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index b0ae4de7f083..ccba69b7f8a7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -35,7 +35,6 @@
#include <linux/sched.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
-#include <linux/wireless.h>
#include <linux/firmware.h>
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
@@ -48,10 +47,9 @@
#include "iwl-dev.h"
#include "iwl-core.h"
#include "iwl-io.h"
-#include "iwl-helpers.h"
-#include "iwl-sta.h"
#include "iwl-agn-calib.h"
#include "iwl-agn.h"
+#include "iwl-shared.h"
#include "iwl-bus.h"
#include "iwl-trans.h"
@@ -79,9 +77,7 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_VERSION(DRV_VERSION);
MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
MODULE_LICENSE("GPL");
-
-static int iwlagn_ant_coupling;
-static bool iwlagn_bt_ch_announce = 1;
+MODULE_ALIAS("iwlagn");
void iwl_update_chain_flags(struct iwl_priv *priv)
{
@@ -138,7 +134,7 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
* beacon contents.
*/
- lockdep_assert_held(&priv->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
if (!priv->beacon_ctx) {
IWL_ERR(priv, "trying to build beacon w/o beacon context!\n");
@@ -183,7 +179,7 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
rate = info->control.rates[0].idx;
priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
- priv->hw_params.valid_tx_ant);
+ hw_params(priv).valid_tx_ant);
rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
/* In mac80211, rates for 5 GHz start at 0 */
@@ -203,7 +199,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 trans_send_cmd(&priv->trans, &cmd);
+ return iwl_trans_send_cmd(trans(priv), &cmd);
}
static void iwl_bg_beacon_update(struct work_struct *work)
@@ -212,7 +208,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->mutex);
+ mutex_lock(&priv->shrd->mutex);
if (!priv->beacon_ctx) {
IWL_ERR(priv, "updating beacon w/o beacon context!\n");
goto out;
@@ -242,7 +238,7 @@ static void iwl_bg_beacon_update(struct work_struct *work)
iwlagn_send_beacon_cmd(priv);
out:
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
}
static void iwl_bg_bt_runtime_config(struct work_struct *work)
@@ -250,11 +246,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->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
return;
/* dont send host command if rf-kill is on */
- if (!iwl_is_ready_rf(priv))
+ if (!iwl_is_ready_rf(priv->shrd))
return;
iwlagn_send_advance_bt_config(priv);
}
@@ -265,13 +261,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->mutex);
+ mutex_lock(&priv->shrd->mutex);
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
goto out;
/* dont send host command if rf-kill is on */
- if (!iwl_is_ready_rf(priv))
+ if (!iwl_is_ready_rf(priv->shrd))
goto out;
IWL_DEBUG_INFO(priv, "BT coex in %s mode\n",
@@ -289,7 +285,7 @@ static void iwl_bg_bt_full_concurrency(struct work_struct *work)
iwlagn_send_advance_bt_config(priv);
out:
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
}
/**
@@ -306,11 +302,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->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
return;
/* dont send host command if rf-kill is on */
- if (!iwl_is_ready_rf(priv))
+ if (!iwl_is_ready_rf(priv->shrd))
return;
iwl_send_statistics_request(priv, CMD_ASYNC, false);
@@ -332,14 +328,14 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32));
/* Make sure device is powered up for SRAM reads */
- spin_lock_irqsave(&priv->reg_lock, reg_flags);
- if (iwl_grab_nic_access(priv)) {
- spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
+ spin_lock_irqsave(&bus(priv)->reg_lock, reg_flags);
+ if (iwl_grab_nic_access(bus(priv))) {
+ spin_unlock_irqrestore(&bus(priv)->reg_lock, reg_flags);
return;
}
/* Set starting address; reads will auto-increment */
- iwl_write32(priv, HBUS_TARG_MEM_RADDR, ptr);
+ iwl_write32(bus(priv), HBUS_TARG_MEM_RADDR, ptr);
rmb();
/*
@@ -347,20 +343,20 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
* place event id # at far right for easier visual parsing.
*/
for (i = 0; i < num_events; i++) {
- ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
- time = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
+ ev = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
+ time = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
if (mode == 0) {
trace_iwlwifi_dev_ucode_cont_event(priv,
0, time, ev);
} else {
- data = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
+ data = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
trace_iwlwifi_dev_ucode_cont_event(priv,
time, data, ev);
}
}
/* Allow device to power down */
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
+ iwl_release_nic_access(bus(priv));
+ spin_unlock_irqrestore(&bus(priv)->reg_lock, reg_flags);
}
static void iwl_continuous_event_trace(struct iwl_priv *priv)
@@ -373,10 +369,12 @@ static void iwl_continuous_event_trace(struct iwl_priv *priv)
base = priv->device_pointers.error_event_table;
if (iwlagn_hw_valid_rtc_data_addr(base)) {
- capacity = iwl_read_targ_mem(priv, base);
- num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
- mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
- next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
+ capacity = iwl_read_targ_mem(bus(priv), base);
+ num_wraps = iwl_read_targ_mem(bus(priv),
+ base + (2 * sizeof(u32)));
+ mode = iwl_read_targ_mem(bus(priv), base + (1 * sizeof(u32)));
+ next_entry = iwl_read_targ_mem(bus(priv),
+ base + (3 * sizeof(u32)));
} else
return;
@@ -427,7 +425,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->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
return;
if (priv->event_log.ucode_trace) {
@@ -443,131 +441,17 @@ 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->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
return;
/* do nothing if rf-kill is on */
- if (!iwl_is_ready_rf(priv))
+ if (!iwl_is_ready_rf(priv->shrd))
return;
IWL_DEBUG_INFO(priv, "device request: flush all tx frames\n");
iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
}
-/*****************************************************************************
- *
- * sysfs attributes
- *
- *****************************************************************************/
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-
-/*
- * The following adds a new attribute to the sysfs representation
- * of this device driver (i.e. a new file in /sys/class/net/wlan0/device/)
- * used for controlling the debug level.
- *
- * See the level definitions in iwl for details.
- *
- * The debug_level being managed using sysfs below is a per device debug
- * level that is used instead of the global debug level if it (the per
- * device debug level) is set.
- */
-static ssize_t show_debug_level(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv));
-}
-static ssize_t store_debug_level(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- unsigned long val;
- int ret;
-
- ret = strict_strtoul(buf, 0, &val);
- if (ret)
- IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf);
- else {
- priv->debug_level = val;
- if (iwl_alloc_traffic_mem(priv))
- IWL_ERR(priv,
- "Not enough memory to generate traffic log\n");
- }
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO,
- show_debug_level, store_debug_level);
-
-
-#endif /* CONFIG_IWLWIFI_DEBUG */
-
-
-static ssize_t show_temperature(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
-
- if (!iwl_is_alive(priv))
- return -EAGAIN;
-
- return sprintf(buf, "%d\n", priv->temperature);
-}
-
-static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
-
-static ssize_t show_tx_power(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
-
- if (!iwl_is_ready_rf(priv))
- return sprintf(buf, "off\n");
- else
- return sprintf(buf, "%d\n", priv->tx_power_user_lmt);
-}
-
-static ssize_t store_tx_power(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- unsigned long val;
- int ret;
-
- ret = strict_strtoul(buf, 10, &val);
- if (ret)
- IWL_INFO(priv, "%s is not in decimal form.\n", buf);
- else {
- ret = iwl_set_tx_power(priv, val, false);
- if (ret)
- IWL_ERR(priv, "failed setting tx power (0x%d).\n",
- ret);
- else
- ret = count;
- }
- return ret;
-}
-
-static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
-
-static struct attribute *iwl_sysfs_entries[] = {
- &dev_attr_temperature.attr,
- &dev_attr_tx_power.attr,
-#ifdef CONFIG_IWLWIFI_DEBUG
- &dev_attr_debug_level.attr,
-#endif
- NULL
-};
-
-static struct attribute_group iwl_attribute_group = {
- .name = NULL, /* put in device directory */
- .attrs = iwl_sysfs_entries,
-};
-
/******************************************************************************
*
* uCode download functions
@@ -577,7 +461,7 @@ static struct attribute_group iwl_attribute_group = {
static void iwl_free_fw_desc(struct iwl_priv *priv, struct fw_desc *desc)
{
if (desc->v_addr)
- dma_free_coherent(priv->bus->dev, desc->len,
+ dma_free_coherent(bus(priv)->dev, desc->len,
desc->v_addr, desc->p_addr);
desc->v_addr = NULL;
desc->len = 0;
@@ -604,7 +488,7 @@ static int iwl_alloc_fw_desc(struct iwl_priv *priv, struct fw_desc *desc,
return -EINVAL;
}
- desc->v_addr = dma_alloc_coherent(priv->bus->dev, len,
+ desc->v_addr = dma_alloc_coherent(bus(priv)->dev, len,
&desc->p_addr, GFP_KERNEL);
if (!desc->v_addr)
return -ENOMEM;
@@ -614,6 +498,64 @@ static int iwl_alloc_fw_desc(struct iwl_priv *priv, struct fw_desc *desc,
return 0;
}
+static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
+{
+ int i;
+
+ /*
+ * The default context is always valid,
+ * the PAN context depends on uCode.
+ */
+ priv->shrd->valid_contexts = BIT(IWL_RXON_CTX_BSS);
+ if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN)
+ priv->shrd->valid_contexts |= BIT(IWL_RXON_CTX_PAN);
+
+ for (i = 0; i < NUM_IWL_RXON_CTX; i++)
+ priv->contexts[i].ctxid = i;
+
+ priv->contexts[IWL_RXON_CTX_BSS].always_active = true;
+ priv->contexts[IWL_RXON_CTX_BSS].is_active = true;
+ priv->contexts[IWL_RXON_CTX_BSS].rxon_cmd = REPLY_RXON;
+ priv->contexts[IWL_RXON_CTX_BSS].rxon_timing_cmd = REPLY_RXON_TIMING;
+ priv->contexts[IWL_RXON_CTX_BSS].rxon_assoc_cmd = REPLY_RXON_ASSOC;
+ priv->contexts[IWL_RXON_CTX_BSS].qos_cmd = REPLY_QOS_PARAM;
+ priv->contexts[IWL_RXON_CTX_BSS].ap_sta_id = IWL_AP_ID;
+ priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY;
+ priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes =
+ BIT(NL80211_IFTYPE_ADHOC);
+ priv->contexts[IWL_RXON_CTX_BSS].interface_modes =
+ BIT(NL80211_IFTYPE_STATION);
+ priv->contexts[IWL_RXON_CTX_BSS].ap_devtype = RXON_DEV_TYPE_AP;
+ priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS;
+ priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS;
+ priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS;
+
+ priv->contexts[IWL_RXON_CTX_PAN].rxon_cmd = REPLY_WIPAN_RXON;
+ priv->contexts[IWL_RXON_CTX_PAN].rxon_timing_cmd =
+ REPLY_WIPAN_RXON_TIMING;
+ priv->contexts[IWL_RXON_CTX_PAN].rxon_assoc_cmd =
+ REPLY_WIPAN_RXON_ASSOC;
+ priv->contexts[IWL_RXON_CTX_PAN].qos_cmd = REPLY_WIPAN_QOS_PARAM;
+ priv->contexts[IWL_RXON_CTX_PAN].ap_sta_id = IWL_AP_ID_PAN;
+ priv->contexts[IWL_RXON_CTX_PAN].wep_key_cmd = REPLY_WIPAN_WEPKEY;
+ priv->contexts[IWL_RXON_CTX_PAN].bcast_sta_id = IWLAGN_PAN_BCAST_ID;
+ priv->contexts[IWL_RXON_CTX_PAN].station_flags = STA_FLG_PAN_STATION;
+ priv->contexts[IWL_RXON_CTX_PAN].interface_modes =
+ BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP);
+
+ if (ucode_flags & IWL_UCODE_TLV_FLAGS_P2P)
+ priv->contexts[IWL_RXON_CTX_PAN].interface_modes |=
+ BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO);
+
+ priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP;
+ priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA;
+ priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P;
+
+ BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+}
+
+
struct iwlagn_ucode_capabilities {
u32 max_probe_length;
u32 standard_phy_calibration_size;
@@ -621,7 +563,7 @@ struct iwlagn_ucode_capabilities {
};
static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context);
-static int iwl_mac_setup_register(struct iwl_priv *priv,
+static int iwlagn_mac_setup_register(struct iwl_priv *priv,
struct iwlagn_ucode_capabilities *capa);
#define UCODE_EXPERIMENTAL_INDEX 100
@@ -658,7 +600,7 @@ static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first)
priv->firmware_name);
return request_firmware_nowait(THIS_MODULE, 1, priv->firmware_name,
- priv->bus->dev,
+ bus(priv)->dev,
GFP_KERNEL, priv, iwl_ucode_callback);
}
@@ -738,8 +680,6 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv,
return 0;
}
-static int iwlagn_wanted_ucode_alternative = 1;
-
static int iwlagn_load_firmware(struct iwl_priv *priv,
const struct firmware *ucode_raw,
struct iwlagn_firmware_pieces *pieces,
@@ -749,7 +689,8 @@ static int iwlagn_load_firmware(struct iwl_priv *priv,
struct iwl_ucode_tlv *tlv;
size_t len = ucode_raw->size;
const u8 *data;
- int wanted_alternative = iwlagn_wanted_ucode_alternative, tmp;
+ int wanted_alternative = iwlagn_mod_params.wanted_ucode_alternative;
+ int tmp;
u64 alternatives;
u32 tlv_len;
enum iwl_ucode_tlv_type tlv_type;
@@ -952,6 +893,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
int err;
struct iwlagn_firmware_pieces pieces;
const unsigned int api_max = priv->cfg->ucode_api_max;
+ unsigned int api_ok = priv->cfg->ucode_api_ok;
const unsigned int api_min = priv->cfg->ucode_api_min;
u32 api_ver;
char buildstr[25];
@@ -962,10 +904,13 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
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 <= priv->cfg->ucode_api_max)
+ if (priv->fw_index <= api_ok)
IWL_ERR(priv,
"request for firmware file '%s' failed.\n",
priv->firmware_name);
@@ -1011,12 +956,18 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
goto try_again;
}
- if (api_ver != api_max)
- IWL_ERR(priv,
- "Firmware has old API version. Expected v%u, "
- "got v%u. New firmware can be obtained "
- "from http://www.intellinuxwireless.org.\n",
- api_max, api_ver);
+ 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)
@@ -1060,25 +1011,25 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
pieces.init_data_size);
/* Verify that uCode images will fit in card's SRAM */
- if (pieces.inst_size > priv->hw_params.max_inst_size) {
+ 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 > priv->hw_params.max_data_size) {
+ 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 > priv->hw_params.max_inst_size) {
+ 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 > priv->hw_params.max_data_size) {
+ 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;
@@ -1143,17 +1094,23 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
priv->new_scan_threshold_behaviour =
!!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN);
- if ((priv->cfg->sku & EEPROM_SKU_CAP_IPAN_ENABLE) &&
- (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN)) {
- priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN);
+ if (!(priv->cfg->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;
- } else
+ priv->shrd->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM;
+ } else {
priv->sta_key_max_num = STA_KEY_MAX_NUM;
-
- if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))
- priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM;
- else
- priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
+ priv->shrd->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
+ }
/*
* figure out the offset of chain noise reset and gain commands
@@ -1169,12 +1126,15 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
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 = iwl_mac_setup_register(priv, &ucode_capa);
+ err = iwlagn_mac_setup_register(priv, &ucode_capa);
if (err)
goto out_unbind;
@@ -1182,13 +1142,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
if (err)
IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err);
- err = sysfs_create_group(&(priv->bus->dev->kobj),
- &iwl_attribute_group);
- if (err) {
- IWL_ERR(priv, "failed to create sysfs device attributes\n");
- goto out_unbind;
- }
-
/* We have our copies now, allow OS release its copies */
release_firmware(ucode_raw);
complete(&priv->firmware_loading_complete);
@@ -1206,368 +1159,10 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
iwl_dealloc_ucode(priv);
out_unbind:
complete(&priv->firmware_loading_complete);
- device_release_driver(priv->bus->dev);
+ device_release_driver(bus(priv)->dev);
release_firmware(ucode_raw);
}
-static const char * const desc_lookup_text[] = {
- "OK",
- "FAIL",
- "BAD_PARAM",
- "BAD_CHECKSUM",
- "NMI_INTERRUPT_WDG",
- "SYSASSERT",
- "FATAL_ERROR",
- "BAD_COMMAND",
- "HW_ERROR_TUNE_LOCK",
- "HW_ERROR_TEMPERATURE",
- "ILLEGAL_CHAN_FREQ",
- "VCC_NOT_STABLE",
- "FH_ERROR",
- "NMI_INTERRUPT_HOST",
- "NMI_INTERRUPT_ACTION_PT",
- "NMI_INTERRUPT_UNKNOWN",
- "UCODE_VERSION_MISMATCH",
- "HW_ERROR_ABS_LOCK",
- "HW_ERROR_CAL_LOCK_FAIL",
- "NMI_INTERRUPT_INST_ACTION_PT",
- "NMI_INTERRUPT_DATA_ACTION_PT",
- "NMI_TRM_HW_ER",
- "NMI_INTERRUPT_TRM",
- "NMI_INTERRUPT_BREAK_POINT",
- "DEBUG_0",
- "DEBUG_1",
- "DEBUG_2",
- "DEBUG_3",
-};
-
-static struct { char *name; u8 num; } advanced_lookup[] = {
- { "NMI_INTERRUPT_WDG", 0x34 },
- { "SYSASSERT", 0x35 },
- { "UCODE_VERSION_MISMATCH", 0x37 },
- { "BAD_COMMAND", 0x38 },
- { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C },
- { "FATAL_ERROR", 0x3D },
- { "NMI_TRM_HW_ERR", 0x46 },
- { "NMI_INTERRUPT_TRM", 0x4C },
- { "NMI_INTERRUPT_BREAK_POINT", 0x54 },
- { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C },
- { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 },
- { "NMI_INTERRUPT_HOST", 0x66 },
- { "NMI_INTERRUPT_ACTION_PT", 0x7C },
- { "NMI_INTERRUPT_UNKNOWN", 0x84 },
- { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 },
- { "ADVANCED_SYSASSERT", 0 },
-};
-
-static const char *desc_lookup(u32 num)
-{
- int i;
- int max = ARRAY_SIZE(desc_lookup_text);
-
- if (num < max)
- return desc_lookup_text[num];
-
- max = ARRAY_SIZE(advanced_lookup) - 1;
- for (i = 0; i < max; i++) {
- if (advanced_lookup[i].num == num)
- break;
- }
- return advanced_lookup[i].name;
-}
-
-#define ERROR_START_OFFSET (1 * sizeof(u32))
-#define ERROR_ELEM_SIZE (7 * sizeof(u32))
-
-void iwl_dump_nic_error_log(struct iwl_priv *priv)
-{
- u32 base;
- struct iwl_error_event_table table;
-
- base = priv->device_pointers.error_event_table;
- if (priv->ucode_type == IWL_UCODE_INIT) {
- if (!base)
- base = priv->init_errlog_ptr;
- } else {
- if (!base)
- base = priv->inst_errlog_ptr;
- }
-
- if (!iwlagn_hw_valid_rtc_data_addr(base)) {
- IWL_ERR(priv,
- "Not valid error log pointer 0x%08X for %s uCode\n",
- base,
- (priv->ucode_type == IWL_UCODE_INIT)
- ? "Init" : "RT");
- return;
- }
-
- iwl_read_targ_mem_words(priv, base, &table, sizeof(table));
-
- if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
- IWL_ERR(priv, "Start IWL Error Log Dump:\n");
- IWL_ERR(priv, "Status: 0x%08lX, count: %d\n",
- priv->status, table.valid);
- }
-
- priv->isr_stats.err_code = table.error_id;
-
- trace_iwlwifi_dev_ucode_error(priv, 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,
- table.gp2, table.gp3, table.ucode_ver,
- table.hw_ver, table.brd_ver);
- IWL_ERR(priv, "0x%08X | %-28s\n", table.error_id,
- desc_lookup(table.error_id));
- IWL_ERR(priv, "0x%08X | uPc\n", table.pc);
- IWL_ERR(priv, "0x%08X | branchlink1\n", table.blink1);
- IWL_ERR(priv, "0x%08X | branchlink2\n", table.blink2);
- IWL_ERR(priv, "0x%08X | interruptlink1\n", table.ilink1);
- IWL_ERR(priv, "0x%08X | interruptlink2\n", table.ilink2);
- IWL_ERR(priv, "0x%08X | data1\n", table.data1);
- IWL_ERR(priv, "0x%08X | data2\n", table.data2);
- IWL_ERR(priv, "0x%08X | line\n", table.line);
- IWL_ERR(priv, "0x%08X | beacon time\n", table.bcon_time);
- IWL_ERR(priv, "0x%08X | tsf low\n", table.tsf_low);
- IWL_ERR(priv, "0x%08X | tsf hi\n", table.tsf_hi);
- IWL_ERR(priv, "0x%08X | time gp1\n", table.gp1);
- IWL_ERR(priv, "0x%08X | time gp2\n", table.gp2);
- IWL_ERR(priv, "0x%08X | time gp3\n", table.gp3);
- IWL_ERR(priv, "0x%08X | uCode version\n", table.ucode_ver);
- IWL_ERR(priv, "0x%08X | hw version\n", table.hw_ver);
- IWL_ERR(priv, "0x%08X | board version\n", table.brd_ver);
- IWL_ERR(priv, "0x%08X | hcmd\n", table.hcmd);
-}
-
-#define EVENT_START_OFFSET (4 * sizeof(u32))
-
-/**
- * iwl_print_event_log - Dump error event log to syslog
- *
- */
-static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
- u32 num_events, u32 mode,
- int pos, char **buf, size_t bufsz)
-{
- u32 i;
- u32 base; /* SRAM byte address of event log header */
- u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
- u32 ptr; /* SRAM byte address of log data */
- u32 ev, time, data; /* event log data */
- unsigned long reg_flags;
-
- if (num_events == 0)
- return pos;
-
- base = priv->device_pointers.log_event_table;
- if (priv->ucode_type == IWL_UCODE_INIT) {
- if (!base)
- base = priv->init_evtlog_ptr;
- } else {
- if (!base)
- base = priv->inst_evtlog_ptr;
- }
-
- if (mode == 0)
- event_size = 2 * sizeof(u32);
- else
- event_size = 3 * sizeof(u32);
-
- ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
-
- /* Make sure device is powered up for SRAM reads */
- spin_lock_irqsave(&priv->reg_lock, reg_flags);
- iwl_grab_nic_access(priv);
-
- /* Set starting address; reads will auto-increment */
- iwl_write32(priv, 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. */
- for (i = 0; i < num_events; i++) {
- ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
- time = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
- if (mode == 0) {
- /* data, ev */
- if (bufsz) {
- pos += scnprintf(*buf + pos, bufsz - pos,
- "EVT_LOG:0x%08x:%04u\n",
- time, ev);
- } else {
- trace_iwlwifi_dev_ucode_event(priv, 0,
- time, ev);
- IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n",
- time, ev);
- }
- } else {
- data = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
- if (bufsz) {
- pos += scnprintf(*buf + pos, bufsz - pos,
- "EVT_LOGT:%010u:0x%08x:%04u\n",
- time, data, ev);
- } else {
- IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
- time, data, ev);
- trace_iwlwifi_dev_ucode_event(priv, time,
- data, ev);
- }
- }
- }
-
- /* Allow device to power down */
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
- return pos;
-}
-
-/**
- * iwl_print_last_event_logs - Dump the newest # of event log to syslog
- */
-static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
- u32 num_wraps, u32 next_entry,
- u32 size, u32 mode,
- int pos, char **buf, size_t bufsz)
-{
- /*
- * display the newest DEFAULT_LOG_ENTRIES entries
- * i.e the entries just before the next ont that uCode would fill.
- */
- if (num_wraps) {
- if (next_entry < size) {
- pos = iwl_print_event_log(priv,
- capacity - (size - next_entry),
- size - next_entry, mode,
- pos, buf, bufsz);
- pos = iwl_print_event_log(priv, 0,
- next_entry, mode,
- pos, buf, bufsz);
- } else
- pos = iwl_print_event_log(priv, next_entry - size,
- size, mode, pos, buf, bufsz);
- } else {
- if (next_entry < size) {
- pos = iwl_print_event_log(priv, 0, next_entry,
- mode, pos, buf, bufsz);
- } else {
- pos = iwl_print_event_log(priv, next_entry - size,
- size, mode, pos, buf, bufsz);
- }
- }
- return pos;
-}
-
-#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20)
-
-int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
- char **buf, bool display)
-{
- u32 base; /* SRAM byte address of event log header */
- u32 capacity; /* event log capacity in # entries */
- u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
- u32 num_wraps; /* # times uCode wrapped to top of log */
- u32 next_entry; /* index of next entry to be written by uCode */
- u32 size; /* # entries that we'll print */
- u32 logsize;
- int pos = 0;
- size_t bufsz = 0;
-
- base = priv->device_pointers.log_event_table;
- if (priv->ucode_type == IWL_UCODE_INIT) {
- logsize = priv->init_evtlog_size;
- if (!base)
- base = priv->init_evtlog_ptr;
- } else {
- logsize = priv->inst_evtlog_size;
- if (!base)
- base = priv->inst_evtlog_ptr;
- }
-
- if (!iwlagn_hw_valid_rtc_data_addr(base)) {
- IWL_ERR(priv,
- "Invalid event log pointer 0x%08X for %s uCode\n",
- base,
- (priv->ucode_type == IWL_UCODE_INIT)
- ? "Init" : "RT");
- return -EINVAL;
- }
-
- /* event log header */
- capacity = iwl_read_targ_mem(priv, base);
- mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
- num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
- next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
-
- if (capacity > logsize) {
- IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n",
- capacity, logsize);
- capacity = logsize;
- }
-
- if (next_entry > logsize) {
- IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n",
- next_entry, logsize);
- next_entry = logsize;
- }
-
- size = num_wraps ? capacity : next_entry;
-
- /* bail out if nothing in log */
- if (size == 0) {
- IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
- return pos;
- }
-
- /* enable/disable bt channel inhibition */
- priv->bt_ch_announce = iwlagn_bt_ch_announce;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
- if (!(iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) && !full_log)
- size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
- ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
-#else
- size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
- ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
-#endif
- IWL_ERR(priv, "Start IWL Event Log Dump: display last %u entries\n",
- size);
-
-#ifdef CONFIG_IWLWIFI_DEBUG
- if (display) {
- if (full_log)
- bufsz = capacity * 48;
- else
- bufsz = size * 48;
- *buf = kmalloc(bufsz, GFP_KERNEL);
- if (!*buf)
- return -ENOMEM;
- }
- if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) {
- /*
- * if uCode has wrapped back to top of log,
- * start at the oldest entry,
- * i.e the next one that uCode would fill.
- */
- if (num_wraps)
- pos = iwl_print_event_log(priv, next_entry,
- capacity - next_entry, mode,
- pos, buf, bufsz);
- /* (then/else) start at top of log */
- pos = iwl_print_event_log(priv, 0,
- next_entry, mode, pos, buf, bufsz);
- } else
- pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
- next_entry, size, mode,
- pos, buf, bufsz);
-#else
- pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
- next_entry, size, mode,
- pos, buf, bufsz);
-#endif
- return pos;
-}
-
static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
{
struct iwl_ct_kill_config cmd;
@@ -1575,44 +1170,43 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
unsigned long flags;
int ret = 0;
- spin_lock_irqsave(&priv->lock, flags);
- iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+ spin_lock_irqsave(&priv->shrd->lock, flags);
+ iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR,
CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->lock, flags);
priv->thermal_throttle.ct_kill_toggle = false;
if (priv->cfg->base_params->support_ct_kill_exit) {
adv_cmd.critical_temperature_enter =
- cpu_to_le32(priv->hw_params.ct_kill_threshold);
+ cpu_to_le32(hw_params(priv).ct_kill_threshold);
adv_cmd.critical_temperature_exit =
- cpu_to_le32(priv->hw_params.ct_kill_exit_threshold);
+ cpu_to_le32(hw_params(priv).ct_kill_exit_threshold);
- ret = trans_send_cmd_pdu(&priv->trans,
+ ret = iwl_trans_send_cmd_pdu(trans(priv),
REPLY_CT_KILL_CONFIG_CMD,
CMD_SYNC, sizeof(adv_cmd), &adv_cmd);
if (ret)
IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
else
IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
- "succeeded, "
- "critical temperature enter is %d,"
- "exit is %d\n",
- priv->hw_params.ct_kill_threshold,
- priv->hw_params.ct_kill_exit_threshold);
+ "succeeded, critical temperature enter is %d,"
+ "exit is %d\n",
+ hw_params(priv).ct_kill_threshold,
+ hw_params(priv).ct_kill_exit_threshold);
} else {
cmd.critical_temperature_R =
- cpu_to_le32(priv->hw_params.ct_kill_threshold);
+ cpu_to_le32(hw_params(priv).ct_kill_threshold);
- ret = trans_send_cmd_pdu(&priv->trans,
+ ret = iwl_trans_send_cmd_pdu(trans(priv),
REPLY_CT_KILL_CONFIG_CMD,
CMD_SYNC, sizeof(cmd), &cmd);
if (ret)
IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
else
IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
- "succeeded, "
- "critical temperature is %d\n",
- priv->hw_params.ct_kill_threshold);
+ "succeeded, "
+ "critical temperature is %d\n",
+ hw_params(priv).ct_kill_threshold);
}
}
@@ -1626,10 +1220,10 @@ static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg)
};
memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
- calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL;
+ 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 trans_send_cmd(&priv->trans, &cmd);
+ return iwl_trans_send_cmd(trans(priv), &cmd);
}
@@ -1641,7 +1235,7 @@ static int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
if (IWL_UCODE_API(priv->ucode_ver) > 1) {
IWL_DEBUG_HC(priv, "select valid tx ant: %u\n", valid_tx_ant);
- return trans_send_cmd_pdu(&priv->trans,
+ return iwl_trans_send_cmd_pdu(trans(priv),
TX_ANT_CONFIGURATION_CMD,
CMD_SYNC,
sizeof(struct iwl_tx_ant_config_cmd),
@@ -1663,17 +1257,17 @@ int iwl_alive_start(struct iwl_priv *priv)
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
/*TODO: this should go to the transport layer */
- iwl_reset_ict(priv);
+ iwl_reset_ict(trans(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->status);
+ set_bit(STATUS_ALIVE, &priv->shrd->status);
/* Enable watchdog to monitor the driver tx queues */
iwl_setup_watchdog(priv);
- if (iwl_is_rfkill(priv))
+ if (iwl_is_rfkill(priv->shrd))
return -ERFKILL;
/* download priority table before any calibration request */
@@ -1710,8 +1304,9 @@ int iwl_alive_start(struct iwl_priv *priv)
iwl_send_bt_config(priv);
}
- if (priv->hw_params.calib_rt_cfg)
- iwlagn_send_calib_cfg_rt(priv, priv->hw_params.calib_rt_cfg);
+ if (hw_params(priv).calib_rt_cfg)
+ iwlagn_send_calib_cfg_rt(priv,
+ hw_params(priv).calib_rt_cfg);
ieee80211_wake_queues(priv->hw);
@@ -1720,7 +1315,7 @@ int iwl_alive_start(struct iwl_priv *priv)
/* Configure Tx antenna selection based on H/W config */
iwlagn_send_tx_ant_config(priv, priv->cfg->valid_tx_ant);
- if (iwl_is_associated_ctx(ctx) && !priv->wowlan) {
+ if (iwl_is_associated_ctx(ctx) && !priv->shrd->wowlan) {
struct iwl_rxon_cmd *active_rxon =
(struct iwl_rxon_cmd *)&ctx->active;
/* apply any changes in staging */
@@ -1735,12 +1330,12 @@ int iwl_alive_start(struct iwl_priv *priv)
iwlagn_set_rxon_chain(priv, ctx);
}
- if (!priv->wowlan) {
+ if (!priv->shrd->wowlan) {
/* WoWLAN ucode will not reply in the same way, skip it */
iwl_reset_run_time_calib(priv);
}
- set_bit(STATUS_READY, &priv->status);
+ set_bit(STATUS_READY, &priv->shrd->status);
/* Configure the adapter for unassociated operation */
ret = iwlagn_commit_rxon(priv, ctx);
@@ -1765,7 +1360,15 @@ static void __iwl_down(struct iwl_priv *priv)
iwl_scan_cancel_timeout(priv, 200);
- exit_pending = test_and_set_bit(STATUS_EXIT_PENDING, &priv->status);
+ /*
+ * If active, scanning won't cancel it, so say it expired.
+ * No race since we hold the mutex here and a new one
+ * can't come in at this time.
+ */
+ ieee80211_remain_on_channel_expired(priv->hw);
+
+ exit_pending =
+ test_and_set_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
/* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set
* to prevent rearm timer */
@@ -1790,32 +1393,33 @@ static 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->status);
+ clear_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
if (priv->mac80211_registered)
ieee80211_stop_queues(priv->hw);
+ iwl_trans_stop_device(trans(priv));
+
/* Clear out all status bits but a few that are stable across reset */
- priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
+ priv->shrd->status &=
+ test_bit(STATUS_RF_KILL_HW, &priv->shrd->status) <<
STATUS_RF_KILL_HW |
- test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
+ test_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status) <<
STATUS_GEO_CONFIGURED |
- test_bit(STATUS_FW_ERROR, &priv->status) <<
+ test_bit(STATUS_FW_ERROR, &priv->shrd->status) <<
STATUS_FW_ERROR |
- test_bit(STATUS_EXIT_PENDING, &priv->status) <<
+ test_bit(STATUS_EXIT_PENDING, &priv->shrd->status) <<
STATUS_EXIT_PENDING;
- trans_stop_device(&priv->trans);
-
dev_kfree_skb(priv->beacon_skb);
priv->beacon_skb = NULL;
}
static void iwl_down(struct iwl_priv *priv)
{
- mutex_lock(&priv->mutex);
+ mutex_lock(&priv->shrd->mutex);
__iwl_down(priv);
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
iwl_cancel_deferred_work(priv);
}
@@ -1827,9 +1431,9 @@ static int __iwl_up(struct iwl_priv *priv)
struct iwl_rxon_context *ctx;
int ret;
- lockdep_assert_held(&priv->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
- if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) {
IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
return -EIO;
}
@@ -1862,9 +1466,9 @@ static int __iwl_up(struct iwl_priv *priv)
return 0;
error:
- set_bit(STATUS_EXIT_PENDING, &priv->status);
+ set_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
__iwl_down(priv);
- clear_bit(STATUS_EXIT_PENDING, &priv->status);
+ clear_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
IWL_ERR(priv, "Unable to initialize device.\n");
return ret;
@@ -1882,11 +1486,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->mutex);
+ mutex_lock(&priv->shrd->mutex);
- if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
- test_bit(STATUS_SCANNING, &priv->status)) {
- mutex_unlock(&priv->mutex);
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status) ||
+ test_bit(STATUS_SCANNING, &priv->shrd->status)) {
+ mutex_unlock(&priv->shrd->mutex);
return;
}
@@ -1895,7 +1499,7 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work)
iwl_sensitivity_calibration(priv);
}
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
}
static void iwlagn_prepare_restart(struct iwl_priv *priv)
@@ -1907,7 +1511,7 @@ static void iwlagn_prepare_restart(struct iwl_priv *priv)
u8 bt_status;
bool bt_is_sco;
- lockdep_assert_held(&priv->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
for_each_context(priv, ctx)
ctx->vif = NULL;
@@ -1941,13 +1545,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->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
return;
- if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) {
- mutex_lock(&priv->mutex);
+ if (test_and_clear_bit(STATUS_FW_ERROR, &priv->shrd->status)) {
+ mutex_lock(&priv->shrd->mutex);
iwlagn_prepare_restart(priv);
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
iwl_cancel_deferred_work(priv);
ieee80211_restart_hw(priv->hw);
} else {
@@ -1955,94 +1559,6 @@ static void iwl_bg_restart(struct work_struct *data)
}
}
-static int iwl_mac_offchannel_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
- unsigned int wait)
-{
- struct iwl_priv *priv = hw->priv;
- int ret;
-
- /* Not supported if we don't have PAN */
- if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) {
- ret = -EOPNOTSUPP;
- goto free;
- }
-
- /* Not supported on pre-P2P firmware */
- if (!(priv->contexts[IWL_RXON_CTX_PAN].interface_modes &
- BIT(NL80211_IFTYPE_P2P_CLIENT))) {
- ret = -EOPNOTSUPP;
- goto free;
- }
-
- mutex_lock(&priv->mutex);
-
- if (!priv->contexts[IWL_RXON_CTX_PAN].is_active) {
- /*
- * If the PAN context is free, use the normal
- * way of doing remain-on-channel offload + TX.
- */
- ret = 1;
- goto out;
- }
-
- /* TODO: queue up if scanning? */
- if (test_bit(STATUS_SCANNING, &priv->status) ||
- priv->offchan_tx_skb) {
- ret = -EBUSY;
- goto out;
- }
-
- /*
- * max_scan_ie_len doesn't include the blank SSID or the header,
- * so need to add that again here.
- */
- if (skb->len > hw->wiphy->max_scan_ie_len + 24 + 2) {
- ret = -ENOBUFS;
- goto out;
- }
-
- priv->offchan_tx_skb = skb;
- priv->offchan_tx_timeout = wait;
- priv->offchan_tx_chan = chan;
-
- ret = iwl_scan_initiate(priv, priv->contexts[IWL_RXON_CTX_PAN].vif,
- IWL_SCAN_OFFCH_TX, chan->band);
- if (ret)
- priv->offchan_tx_skb = NULL;
- out:
- mutex_unlock(&priv->mutex);
- free:
- if (ret < 0)
- kfree_skb(skb);
-
- return ret;
-}
-
-static int iwl_mac_offchannel_tx_cancel_wait(struct ieee80211_hw *hw)
-{
- struct iwl_priv *priv = hw->priv;
- int ret;
-
- mutex_lock(&priv->mutex);
-
- if (!priv->offchan_tx_skb) {
- ret = -EINVAL;
- goto unlock;
- }
-
- priv->offchan_tx_skb = NULL;
-
- ret = iwl_scan_cancel_timeout(priv, 200);
- if (ret)
- ret = -EIO;
-unlock:
- mutex_unlock(&priv->mutex);
-
- return ret;
-}
-
/*****************************************************************************
*
* mac80211 entry point functions
@@ -2124,7 +1640,7 @@ iwlagn_iface_combinations_p2p[] = {
* Not a mac80211 entry point function, but it fits in with all the
* other mac80211 functions grouped here.
*/
-static int iwl_mac_setup_register(struct iwl_priv *priv,
+static int iwlagn_mac_setup_register(struct iwl_priv *priv,
struct iwlagn_ucode_capabilities *capa)
{
int ret;
@@ -2140,7 +1656,12 @@ static int iwl_mac_setup_register(struct iwl_priv *priv,
IEEE80211_HW_SPECTRUM_MGMT |
IEEE80211_HW_REPORTS_TX_ACK_STATUS;
+ /*
+ * Including the following line will crash some AP's. This
+ * workaround removes the stimulus which causes the crash until
+ * the AP software can be fixed.
hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
+ */
hw->flags |= IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
@@ -2178,7 +1699,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv,
WIPHY_FLAG_DISABLE_BEACON_HINTS |
WIPHY_FLAG_IBSS_RSN;
- if (priv->ucode_wowlan.code.len && device_can_wakeup(priv->bus->dev)) {
+ if (priv->ucode_wowlan.code.len && device_can_wakeup(bus(priv)->dev)) {
hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
WIPHY_WOWLAN_DISCONNECT |
WIPHY_WOWLAN_EAP_IDENTITY_REQ |
@@ -2237,16 +1758,16 @@ static int iwlagn_mac_start(struct ieee80211_hw *hw)
IWL_DEBUG_MAC80211(priv, "enter\n");
/* we should be verifying the device is ready to be opened */
- mutex_lock(&priv->mutex);
+ mutex_lock(&priv->shrd->mutex);
ret = __iwl_up(priv);
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
if (ret)
return ret;
IWL_DEBUG_INFO(priv, "Start UP work done.\n");
/* Now we should be done, and the READY bit should be set. */
- if (WARN_ON(!test_bit(STATUS_READY, &priv->status)))
+ if (WARN_ON(!test_bit(STATUS_READY, &priv->shrd->status)))
ret = -EIO;
iwlagn_led_enable(priv);
@@ -2269,17 +1790,17 @@ static void iwlagn_mac_stop(struct ieee80211_hw *hw)
iwl_down(priv);
- flush_workqueue(priv->workqueue);
+ flush_workqueue(priv->shrd->workqueue);
/* User space software may expect getting rfkill changes
* even if interface is down */
- iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+ iwl_write32(bus(priv), CSR_INT, 0xFFFFFFFF);
iwl_enable_rfkill_int(priv);
IWL_DEBUG_MAC80211(priv, "leave\n");
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int iwlagn_send_patterns(struct iwl_priv *priv,
struct cfg80211_wowlan *wowlan)
{
@@ -2317,7 +1838,7 @@ static int iwlagn_send_patterns(struct iwl_priv *priv,
}
cmd.data[0] = pattern_cmd;
- err = trans_send_cmd(&priv->trans, &cmd);
+ err = iwl_trans_send_cmd(trans(priv), &cmd);
kfree(pattern_cmd);
return err;
}
@@ -2332,7 +1853,8 @@ static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw,
if (iwlagn_mod_params.sw_crypto)
return;
- mutex_lock(&priv->mutex);
+ IWL_DEBUG_MAC80211(priv, "enter\n");
+ mutex_lock(&priv->shrd->mutex);
if (priv->contexts[IWL_RXON_CTX_BSS].vif != vif)
goto out;
@@ -2343,7 +1865,8 @@ static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw,
priv->have_rekey_data = true;
out:
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
+ IWL_DEBUG_MAC80211(priv, "leave\n");
}
struct wowlan_key_data {
@@ -2354,7 +1877,7 @@ struct wowlan_key_data {
bool error, use_rsc_tsc, use_tkip;
};
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static void iwlagn_convert_p1k(u16 *p1k, __le16 *out)
{
int i;
@@ -2381,7 +1904,7 @@ static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
u16 p1k[IWLAGN_P1K_SIZE];
int ret, i;
- mutex_lock(&priv->mutex);
+ mutex_lock(&priv->shrd->mutex);
if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
key->cipher == WLAN_CIPHER_SUITE_WEP104) &&
@@ -2486,7 +2009,7 @@ static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
break;
}
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
}
static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
@@ -2511,7 +2034,8 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
if (WARN_ON(!wowlan))
return -EINVAL;
- mutex_lock(&priv->mutex);
+ IWL_DEBUG_MAC80211(priv, "enter\n");
+ mutex_lock(&priv->shrd->mutex);
/* Don't attempt WoWLAN when not associated, tear down instead. */
if (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION ||
@@ -2540,7 +2064,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
* since the uCode will add 0x10 before using the value.
*/
for (i = 0; i < 8; i++) {
- seq = priv->stations[IWL_AP_ID].tid[i].seq_number;
+ seq = priv->shrd->tid_data[IWL_AP_ID][i].seq_number;
seq -= 0x10;
wakeup_filter_cmd.qos_seq[i] = cpu_to_le16(seq);
}
@@ -2572,9 +2096,9 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
memcpy(&rxon, &ctx->active, sizeof(rxon));
- trans_stop_device(&priv->trans);
+ iwl_trans_stop_device(trans(priv));
- priv->wowlan = true;
+ priv->shrd->wowlan = true;
ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_wowlan,
IWL_UCODE_WOWLAN);
@@ -2605,11 +2129,11 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
* constraints. Since we're in the suspend path
* that isn't really a problem though.
*/
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
ieee80211_iter_keys(priv->hw, ctx->vif,
iwlagn_wowlan_program_keys,
&key_data);
- mutex_lock(&priv->mutex);
+ mutex_lock(&priv->shrd->mutex);
if (key_data.error) {
ret = -EIO;
goto error;
@@ -2624,13 +2148,13 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
.len[0] = sizeof(*key_data.rsc_tsc),
};
- ret = trans_send_cmd(&priv->trans, &rsc_tsc_cmd);
+ ret = iwl_trans_send_cmd(trans(priv), &rsc_tsc_cmd);
if (ret)
goto error;
}
if (key_data.use_tkip) {
- ret = trans_send_cmd_pdu(&priv->trans,
+ ret = iwl_trans_send_cmd_pdu(trans(priv),
REPLY_WOWLAN_TKIP_PARAMS,
CMD_SYNC, sizeof(tkip_cmd),
&tkip_cmd);
@@ -2646,7 +2170,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN);
kek_kck_cmd.replay_ctr = priv->replay_ctr;
- ret = trans_send_cmd_pdu(&priv->trans,
+ ret = iwl_trans_send_cmd_pdu(trans(priv),
REPLY_WOWLAN_KEK_KCK_MATERIAL,
CMD_SYNC, sizeof(kek_kck_cmd),
&kek_kck_cmd);
@@ -2655,7 +2179,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
}
}
- ret = trans_send_cmd_pdu(&priv->trans, REPLY_WOWLAN_WAKEUP_FILTER,
+ ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_WOWLAN_WAKEUP_FILTER,
CMD_SYNC, sizeof(wakeup_filter_cmd),
&wakeup_filter_cmd);
if (ret)
@@ -2665,21 +2189,23 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
if (ret)
goto error;
- device_set_wakeup_enable(priv->bus->dev, true);
+ device_set_wakeup_enable(bus(priv)->dev, true);
/* Now let the ucode operate on its own */
- iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+ iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_SET,
CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
goto out;
error:
- priv->wowlan = false;
+ priv->shrd->wowlan = false;
iwlagn_prepare_restart(priv);
ieee80211_restart_hw(priv->hw);
out:
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
kfree(key_data.rsc_tsc);
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+
return ret;
}
@@ -2692,21 +2218,22 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
u32 base, status = 0xffffffff;
int ret = -EIO;
- mutex_lock(&priv->mutex);
+ IWL_DEBUG_MAC80211(priv, "enter\n");
+ mutex_lock(&priv->shrd->mutex);
- iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+ iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR,
CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
base = priv->device_pointers.error_event_table;
if (iwlagn_hw_valid_rtc_data_addr(base)) {
- spin_lock_irqsave(&priv->reg_lock, flags);
- ret = iwl_grab_nic_access_silent(priv);
+ spin_lock_irqsave(&bus(priv)->reg_lock, flags);
+ ret = iwl_grab_nic_access_silent(bus(priv));
if (ret == 0) {
- iwl_write32(priv, HBUS_TARG_MEM_RADDR, base);
- status = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
- iwl_release_nic_access(priv);
+ iwl_write32(bus(priv), HBUS_TARG_MEM_RADDR, base);
+ status = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
+ iwl_release_nic_access(bus(priv));
}
- spin_unlock_irqrestore(&priv->reg_lock, flags);
+ spin_unlock_irqrestore(&bus(priv)->reg_lock, flags);
#ifdef CONFIG_IWLWIFI_DEBUGFS
if (ret == 0) {
@@ -2717,7 +2244,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
if (priv->wowlan_sram)
_iwl_read_targ_mem_words(
- priv, 0x800000, priv->wowlan_sram,
+ bus(priv), 0x800000, priv->wowlan_sram,
priv->ucode_wowlan.data.len / 4);
}
#endif
@@ -2726,9 +2253,9 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
/* we'll clear ctx->vif during iwlagn_prepare_restart() */
vif = ctx->vif;
- priv->wowlan = false;
+ priv->shrd->wowlan = false;
- device_set_wakeup_enable(priv->bus->dev, false);
+ device_set_wakeup_enable(bus(priv)->dev, false);
iwlagn_prepare_restart(priv);
@@ -2736,7 +2263,8 @@ 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->mutex);
+ mutex_unlock(&priv->shrd->mutex);
+ IWL_DEBUG_MAC80211(priv, "leave\n");
ieee80211_resume_disconnect(vif);
@@ -2805,7 +2333,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->mutex);
+ mutex_lock(&priv->shrd->mutex);
iwl_scan_cancel_timeout(priv, 100);
BUILD_BUG_ON(WEP_INVALID_OFFSET == IWLAGN_HW_KEY_DEFAULT);
@@ -2856,7 +2384,7 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
ret = -EINVAL;
}
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
IWL_DEBUG_MAC80211(priv, "leave\n");
return ret;
@@ -2871,6 +2399,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
struct iwl_priv *priv = hw->priv;
int ret = -EINVAL;
struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
+ struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",
sta->addr, tid);
@@ -2878,7 +2407,8 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
if (!(priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE))
return -EACCES;
- mutex_lock(&priv->mutex);
+ IWL_DEBUG_MAC80211(priv, "enter\n");
+ mutex_lock(&priv->shrd->mutex);
switch (action) {
case IEEE80211_AMPDU_RX_START:
@@ -2888,17 +2418,12 @@ 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->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
ret = 0;
break;
case IEEE80211_AMPDU_TX_START:
IWL_DEBUG_HT(priv, "start Tx\n");
ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
- if (ret == 0) {
- priv->agg_tids_count++;
- IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
- priv->agg_tids_count);
- }
break;
case IEEE80211_AMPDU_TX_STOP:
IWL_DEBUG_HT(priv, "stop Tx\n");
@@ -2908,9 +2433,9 @@ 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->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
ret = 0;
- if (priv->cfg->ht_params &&
+ if (!priv->agg_tids_count && priv->cfg->ht_params &&
priv->cfg->ht_params->use_rts_for_aggregation) {
/*
* switch off RTS/CTS if it was previously enabled
@@ -2924,8 +2449,8 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
case IEEE80211_AMPDU_TX_OPERATIONAL:
buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
- trans_txq_agg_setup(&priv->trans, iwl_sta_id(sta), tid,
- buf_size);
+ iwl_trans_tx_agg_setup(trans(priv), ctx->ctxid, iwl_sta_id(sta),
+ tid, buf_size);
/*
* If the limit is 0, then it wasn't initialised yet,
@@ -2957,6 +2482,9 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
sta_priv->lq_sta.lq.general_params.flags |=
LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
}
+ priv->agg_tids_count++;
+ IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
+ priv->agg_tids_count);
sta_priv->lq_sta.lq.agg_params.agg_frame_cnt_limit =
sta_priv->max_agg_bufsize;
@@ -2969,8 +2497,8 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
ret = 0;
break;
}
- mutex_unlock(&priv->mutex);
-
+ mutex_unlock(&priv->shrd->mutex);
+ IWL_DEBUG_MAC80211(priv, "leave\n");
return ret;
}
@@ -2982,15 +2510,15 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *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;
+ int ret = 0;
u8 sta_id;
- IWL_DEBUG_INFO(priv, "received request to add station %pM\n",
+ IWL_DEBUG_MAC80211(priv, "received request to add station %pM\n",
sta->addr);
- mutex_lock(&priv->mutex);
+ mutex_lock(&priv->shrd->mutex);
IWL_DEBUG_INFO(priv, "proceeding to add station %pM\n",
sta->addr);
- sta_priv->common.sta_id = IWL_INVALID_STATION;
+ sta_priv->sta_id = IWL_INVALID_STATION;
atomic_set(&sta_priv->pending_frames, 0);
if (vif->type == NL80211_IFTYPE_AP)
@@ -3002,19 +2530,20 @@ 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 ? */
- mutex_unlock(&priv->mutex);
- return ret;
+ goto out;
}
- sta_priv->common.sta_id = sta_id;
+ 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);
- mutex_unlock(&priv->mutex);
+ out:
+ mutex_unlock(&priv->shrd->mutex);
+ IWL_DEBUG_MAC80211(priv, "leave\n");
- return 0;
+ return ret;
}
static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
@@ -3038,14 +2567,14 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
IWL_DEBUG_MAC80211(priv, "enter\n");
- mutex_lock(&priv->mutex);
+ mutex_lock(&priv->shrd->mutex);
- if (iwl_is_rfkill(priv))
+ if (iwl_is_rfkill(priv->shrd))
goto out;
- if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
- test_bit(STATUS_SCANNING, &priv->status) ||
- test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status) ||
+ test_bit(STATUS_SCANNING, &priv->shrd->status) ||
+ test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status))
goto out;
if (!iwl_is_associated_ctx(ctx))
@@ -3064,7 +2593,7 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
goto out;
}
- spin_lock_irq(&priv->lock);
+ spin_lock_irq(&priv->shrd->lock);
priv->current_ht_config.smps = conf->smps_mode;
@@ -3094,23 +2623,23 @@ 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->lock);
+ 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->status);
+ set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status);
priv->switch_channel = cpu_to_le16(ch);
if (priv->cfg->lib->set_channel_switch(priv, ch_switch)) {
- clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status);
+ clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status);
priv->switch_channel = 0;
ieee80211_chswitch_done(ctx->vif, false);
}
out:
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
IWL_DEBUG_MAC80211(priv, "leave\n");
}
@@ -3140,7 +2669,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
#undef CHK
- mutex_lock(&priv->mutex);
+ mutex_lock(&priv->shrd->mutex);
for_each_context(priv, ctx) {
ctx->staging.filter_flags &= ~filter_nand;
@@ -3152,7 +2681,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
*/
}
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
/*
* Receiving all multicast frames is always enabled by the
@@ -3168,14 +2697,14 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
{
struct iwl_priv *priv = hw->priv;
- mutex_lock(&priv->mutex);
+ mutex_lock(&priv->shrd->mutex);
IWL_DEBUG_MAC80211(priv, "enter\n");
- if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) {
IWL_DEBUG_TX(priv, "Aborting flush due to device shutdown\n");
goto done;
}
- if (iwl_is_rfkill(priv)) {
+ if (iwl_is_rfkill(priv->shrd)) {
IWL_DEBUG_TX(priv, "Aborting flush due to RF Kill\n");
goto done;
}
@@ -3192,101 +2721,198 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
}
}
IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n");
- iwlagn_wait_tx_queue_empty(priv);
+ iwl_trans_wait_tx_queue_empty(trans(priv));
done:
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
IWL_DEBUG_MAC80211(priv, "leave\n");
}
-static void iwlagn_disable_roc(struct iwl_priv *priv)
+void iwlagn_disable_roc(struct iwl_priv *priv)
{
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
- struct ieee80211_channel *chan = ACCESS_ONCE(priv->hw->conf.channel);
- lockdep_assert_held(&priv->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
- if (!ctx->is_active)
+ if (!priv->hw_roc_setup)
return;
- ctx->staging.dev_type = RXON_DEV_TYPE_2STA;
+ ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwl_set_rxon_channel(priv, chan, ctx);
- iwl_set_flags_for_band(priv, ctx, chan->band, NULL);
priv->hw_roc_channel = NULL;
+ memset(ctx->staging.node_addr, 0, ETH_ALEN);
+
iwlagn_commit_rxon(priv, ctx);
ctx->is_active = false;
+ priv->hw_roc_setup = false;
}
-static void iwlagn_bg_roc_done(struct work_struct *work)
+static void iwlagn_disable_roc_work(struct work_struct *work)
{
struct iwl_priv *priv = container_of(work, struct iwl_priv,
- hw_roc_work.work);
+ hw_roc_disable_work.work);
- mutex_lock(&priv->mutex);
- ieee80211_remain_on_channel_expired(priv->hw);
+ mutex_lock(&priv->shrd->mutex);
iwlagn_disable_roc(priv);
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
}
-static int iwl_mac_remain_on_channel(struct ieee80211_hw *hw,
+static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
struct ieee80211_channel *channel,
enum nl80211_channel_type channel_type,
int duration)
{
struct iwl_priv *priv = hw->priv;
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
int err = 0;
- if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
+ if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
return -EOPNOTSUPP;
- if (!(priv->contexts[IWL_RXON_CTX_PAN].interface_modes &
- BIT(NL80211_IFTYPE_P2P_CLIENT)))
+ if (!(ctx->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)))
return -EOPNOTSUPP;
- mutex_lock(&priv->mutex);
+ IWL_DEBUG_MAC80211(priv, "enter\n");
+ mutex_lock(&priv->shrd->mutex);
- if (priv->contexts[IWL_RXON_CTX_PAN].is_active ||
- test_bit(STATUS_SCAN_HW, &priv->status)) {
+ if (test_bit(STATUS_SCAN_HW, &priv->shrd->status)) {
err = -EBUSY;
goto out;
}
- priv->contexts[IWL_RXON_CTX_PAN].is_active = true;
priv->hw_roc_channel = channel;
priv->hw_roc_chantype = channel_type;
- priv->hw_roc_duration = DIV_ROUND_UP(duration * 1000, 1024);
- iwlagn_commit_rxon(priv, &priv->contexts[IWL_RXON_CTX_PAN]);
- queue_delayed_work(priv->workqueue, &priv->hw_roc_work,
- msecs_to_jiffies(duration + 20));
+ priv->hw_roc_duration = duration;
+ priv->hw_roc_start_notified = false;
+ cancel_delayed_work(&priv->hw_roc_disable_work);
+
+ if (!ctx->is_active) {
+ ctx->is_active = true;
+ ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
+ memcpy(ctx->staging.node_addr,
+ priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
+ ETH_ALEN);
+ memcpy(ctx->staging.bssid_addr,
+ priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
+ ETH_ALEN);
+ err = iwlagn_commit_rxon(priv, ctx);
+ if (err)
+ goto out;
+ ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK |
+ RXON_FILTER_PROMISC_MSK |
+ RXON_FILTER_CTL2HOST_MSK;
+
+ err = iwlagn_commit_rxon(priv, ctx);
+ if (err) {
+ iwlagn_disable_roc(priv);
+ goto out;
+ }
+ priv->hw_roc_setup = true;
+ }
- msleep(IWL_MIN_SLOT_TIME); /* TU is almost ms */
- ieee80211_ready_on_channel(priv->hw);
+ err = iwl_scan_initiate(priv, ctx->vif, IWL_SCAN_ROC, channel->band);
+ if (err)
+ iwlagn_disable_roc(priv);
out:
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
+ IWL_DEBUG_MAC80211(priv, "leave\n");
return err;
}
-static int iwl_mac_cancel_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;
- if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
+ if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
return -EOPNOTSUPP;
- cancel_delayed_work_sync(&priv->hw_roc_work);
-
- mutex_lock(&priv->mutex);
+ IWL_DEBUG_MAC80211(priv, "enter\n");
+ mutex_lock(&priv->shrd->mutex);
+ iwl_scan_cancel_timeout(priv, priv->hw_roc_duration);
iwlagn_disable_roc(priv);
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
+ IWL_DEBUG_MAC80211(priv, "leave\n");
return 0;
}
+static int iwlagn_mac_tx_sync(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ const u8 *bssid,
+ enum ieee80211_tx_sync_type type)
+{
+ struct iwl_priv *priv = hw->priv;
+ struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+ struct iwl_rxon_context *ctx = vif_priv->ctx;
+ int ret;
+ u8 sta_id;
+
+ IWL_DEBUG_MAC80211(priv, "enter\n");
+ mutex_lock(&priv->shrd->mutex);
+
+ if (iwl_is_associated_ctx(ctx)) {
+ ret = 0;
+ goto out;
+ }
+
+ if (ctx->preauth_bssid || test_bit(STATUS_SCAN_HW, &priv->shrd->status)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ ret = iwl_add_station_common(priv, ctx, bssid, true, NULL, &sta_id);
+ if (ret)
+ goto out;
+
+ if (WARN_ON(sta_id != ctx->ap_sta_id)) {
+ ret = -EIO;
+ goto out_remove_sta;
+ }
+
+ memcpy(ctx->bssid, bssid, ETH_ALEN);
+ ctx->preauth_bssid = true;
+
+ ret = iwlagn_commit_rxon(priv, ctx);
+
+ if (ret == 0)
+ goto out;
+
+ out_remove_sta:
+ iwl_remove_station(priv, sta_id, bssid);
+ out:
+ mutex_unlock(&priv->shrd->mutex);
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+
+ return ret;
+}
+
+static void iwlagn_mac_finish_tx_sync(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ const u8 *bssid,
+ enum ieee80211_tx_sync_type type)
+{
+ struct iwl_priv *priv = hw->priv;
+ struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+ struct iwl_rxon_context *ctx = vif_priv->ctx;
+
+ IWL_DEBUG_MAC80211(priv, "enter\n");
+ mutex_lock(&priv->shrd->mutex);
+
+ if (iwl_is_associated_ctx(ctx))
+ goto out;
+
+ iwl_remove_station(priv, ctx->ap_sta_id, bssid);
+ ctx->preauth_bssid = false;
+ /* no need to commit */
+ out:
+ mutex_unlock(&priv->shrd->mutex);
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
/*****************************************************************************
*
* driver setup and teardown
@@ -3295,9 +2921,9 @@ static int iwl_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
static void iwl_setup_deferred_work(struct iwl_priv *priv)
{
- priv->workqueue = create_singlethread_workqueue(DRV_NAME);
+ priv->shrd->workqueue = create_singlethread_workqueue(DRV_NAME);
- init_waitqueue_head(&priv->wait_command_queue);
+ init_waitqueue_head(&priv->shrd->wait_command_queue);
INIT_WORK(&priv->restart, iwl_bg_restart);
INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
@@ -3305,7 +2931,8 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency);
INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config);
- INIT_DELAYED_WORK(&priv->hw_roc_work, iwlagn_bg_roc_done);
+ INIT_DELAYED_WORK(&priv->hw_roc_disable_work,
+ iwlagn_disable_roc_work);
iwl_setup_scan_deferred_work(priv);
@@ -3337,6 +2964,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
cancel_work_sync(&priv->bt_full_concurrency);
cancel_work_sync(&priv->bt_runtime_config);
+ cancel_delayed_work_sync(&priv->hw_roc_disable_work);
del_timer_sync(&priv->statistics_periodic);
del_timer_sync(&priv->ucode_trace);
@@ -3367,10 +2995,9 @@ static int iwl_init_drv(struct iwl_priv *priv)
{
int ret;
- spin_lock_init(&priv->sta_lock);
- spin_lock_init(&priv->hcmd_lock);
+ spin_lock_init(&priv->shrd->sta_lock);
- mutex_init(&priv->mutex);
+ mutex_init(&priv->shrd->mutex);
priv->ieee_channels = NULL;
priv->ieee_rates = NULL;
@@ -3411,7 +3038,7 @@ static int iwl_init_drv(struct iwl_priv *priv)
goto err;
}
- ret = iwlcore_init_geos(priv);
+ ret = iwl_init_geos(priv);
if (ret) {
IWL_ERR(priv, "initializing geos failed: %d\n", ret);
goto err_free_channel_map;
@@ -3429,8 +3056,10 @@ err:
static void iwl_uninit_drv(struct iwl_priv *priv)
{
iwl_calib_free_results(priv);
- iwlcore_free_geos(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);
#ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -3438,12 +3067,13 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
#endif
}
-static void iwl_mac_rssi_callback(struct ieee80211_hw *hw,
+static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
enum ieee80211_rssi_event rssi_event)
{
struct iwl_priv *priv = hw->priv;
- mutex_lock(&priv->mutex);
+ IWL_DEBUG_MAC80211(priv, "enter\n");
+ mutex_lock(&priv->shrd->mutex);
if (priv->cfg->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist) {
@@ -3458,89 +3088,88 @@ static void iwl_mac_rssi_callback(struct ieee80211_hw *hw,
"ignoring RSSI callback\n");
}
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static int iwlagn_mac_set_tim(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, bool set)
+{
+ struct iwl_priv *priv = hw->priv;
+
+ queue_work(priv->shrd->workqueue, &priv->beacon_update);
+
+ return 0;
}
struct ieee80211_ops iwlagn_hw_ops = {
.tx = iwlagn_mac_tx,
.start = iwlagn_mac_start,
.stop = iwlagn_mac_stop,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = iwlagn_mac_suspend,
.resume = iwlagn_mac_resume,
#endif
- .add_interface = iwl_mac_add_interface,
- .remove_interface = iwl_mac_remove_interface,
- .change_interface = iwl_mac_change_interface,
+ .add_interface = iwlagn_mac_add_interface,
+ .remove_interface = iwlagn_mac_remove_interface,
+ .change_interface = iwlagn_mac_change_interface,
.config = iwlagn_mac_config,
.configure_filter = iwlagn_configure_filter,
.set_key = iwlagn_mac_set_key,
.update_tkip_key = iwlagn_mac_update_tkip_key,
.set_rekey_data = iwlagn_mac_set_rekey_data,
- .conf_tx = iwl_mac_conf_tx,
+ .conf_tx = iwlagn_mac_conf_tx,
.bss_info_changed = iwlagn_bss_info_changed,
.ampdu_action = iwlagn_mac_ampdu_action,
- .hw_scan = iwl_mac_hw_scan,
+ .hw_scan = iwlagn_mac_hw_scan,
.sta_notify = iwlagn_mac_sta_notify,
.sta_add = iwlagn_mac_sta_add,
- .sta_remove = iwl_mac_sta_remove,
+ .sta_remove = iwlagn_mac_sta_remove,
.channel_switch = iwlagn_mac_channel_switch,
.flush = iwlagn_mac_flush,
- .tx_last_beacon = iwl_mac_tx_last_beacon,
- .remain_on_channel = iwl_mac_remain_on_channel,
- .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel,
- .offchannel_tx = iwl_mac_offchannel_tx,
- .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait,
- .rssi_callback = iwl_mac_rssi_callback,
- CFG80211_TESTMODE_CMD(iwl_testmode_cmd)
- CFG80211_TESTMODE_DUMP(iwl_testmode_dump)
+ .tx_last_beacon = iwlagn_mac_tx_last_beacon,
+ .remain_on_channel = iwlagn_mac_remain_on_channel,
+ .cancel_remain_on_channel = iwlagn_mac_cancel_remain_on_channel,
+ .rssi_callback = iwlagn_mac_rssi_callback,
+ CFG80211_TESTMODE_CMD(iwlagn_mac_testmode_cmd)
+ CFG80211_TESTMODE_DUMP(iwlagn_mac_testmode_dump)
+ .tx_sync = iwlagn_mac_tx_sync,
+ .finish_tx_sync = iwlagn_mac_finish_tx_sync,
+ .set_tim = iwlagn_mac_set_tim,
};
static u32 iwl_hw_detect(struct iwl_priv *priv)
{
- return iwl_read32(priv, CSR_HW_REV);
+ return iwl_read32(bus(priv), CSR_HW_REV);
}
+/* Size of one Rx buffer in host DRAM */
+#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)
{
- priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
- priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
if (iwlagn_mod_params.amsdu_size_8K)
- priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_8K);
+ hw_params(priv).rx_page_order =
+ get_order(IWL_RX_BUF_SIZE_8K);
else
- priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_4K);
-
- priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL;
+ hw_params(priv).rx_page_order =
+ get_order(IWL_RX_BUF_SIZE_4K);
if (iwlagn_mod_params.disable_11n)
priv->cfg->sku &= ~EEPROM_SKU_CAP_11N_ENABLE;
+ hw_params(priv).num_ampdu_queues =
+ priv->cfg->base_params->num_of_ampdu_queues;
+ hw_params(priv).shadow_reg_enable =
+ priv->cfg->base_params->shadow_reg_enable;
+ hw_params(priv).sku = priv->cfg->sku;
+ hw_params(priv).wd_timeout = priv->cfg->base_params->wd_timeout;
+
/* Device-specific setup */
return priv->cfg->lib->set_hw_params(priv);
}
-static const u8 iwlagn_bss_ac_to_fifo[] = {
- IWL_TX_FIFO_VO,
- IWL_TX_FIFO_VI,
- IWL_TX_FIFO_BE,
- IWL_TX_FIFO_BK,
-};
-
-static const u8 iwlagn_bss_ac_to_queue[] = {
- 0, 1, 2, 3,
-};
-
-static const u8 iwlagn_pan_ac_to_fifo[] = {
- IWL_TX_FIFO_VO_IPAN,
- IWL_TX_FIFO_VI_IPAN,
- IWL_TX_FIFO_BE_IPAN,
- IWL_TX_FIFO_BK_IPAN,
-};
-
-static const u8 iwlagn_pan_ac_to_queue[] = {
- 7, 6, 5, 4,
-};
-
/* This function both allocates and initializes hw and priv. */
static struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg)
{
@@ -3563,66 +3192,8 @@ out:
return hw;
}
-static void iwl_init_context(struct iwl_priv *priv)
-{
- int i;
-
- /*
- * The default context is always valid,
- * more may be discovered when firmware
- * is loaded.
- */
- priv->valid_contexts = BIT(IWL_RXON_CTX_BSS);
-
- for (i = 0; i < NUM_IWL_RXON_CTX; i++)
- priv->contexts[i].ctxid = i;
-
- priv->contexts[IWL_RXON_CTX_BSS].always_active = true;
- priv->contexts[IWL_RXON_CTX_BSS].is_active = true;
- priv->contexts[IWL_RXON_CTX_BSS].rxon_cmd = REPLY_RXON;
- priv->contexts[IWL_RXON_CTX_BSS].rxon_timing_cmd = REPLY_RXON_TIMING;
- priv->contexts[IWL_RXON_CTX_BSS].rxon_assoc_cmd = REPLY_RXON_ASSOC;
- priv->contexts[IWL_RXON_CTX_BSS].qos_cmd = REPLY_QOS_PARAM;
- priv->contexts[IWL_RXON_CTX_BSS].ap_sta_id = IWL_AP_ID;
- priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY;
- priv->contexts[IWL_RXON_CTX_BSS].ac_to_fifo = iwlagn_bss_ac_to_fifo;
- priv->contexts[IWL_RXON_CTX_BSS].ac_to_queue = iwlagn_bss_ac_to_queue;
- priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes =
- BIT(NL80211_IFTYPE_ADHOC);
- priv->contexts[IWL_RXON_CTX_BSS].interface_modes =
- BIT(NL80211_IFTYPE_STATION);
- priv->contexts[IWL_RXON_CTX_BSS].ap_devtype = RXON_DEV_TYPE_AP;
- priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS;
- priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS;
- priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS;
-
- priv->contexts[IWL_RXON_CTX_PAN].rxon_cmd = REPLY_WIPAN_RXON;
- priv->contexts[IWL_RXON_CTX_PAN].rxon_timing_cmd =
- REPLY_WIPAN_RXON_TIMING;
- priv->contexts[IWL_RXON_CTX_PAN].rxon_assoc_cmd =
- REPLY_WIPAN_RXON_ASSOC;
- priv->contexts[IWL_RXON_CTX_PAN].qos_cmd = REPLY_WIPAN_QOS_PARAM;
- priv->contexts[IWL_RXON_CTX_PAN].ap_sta_id = IWL_AP_ID_PAN;
- priv->contexts[IWL_RXON_CTX_PAN].wep_key_cmd = REPLY_WIPAN_WEPKEY;
- priv->contexts[IWL_RXON_CTX_PAN].bcast_sta_id = IWLAGN_PAN_BCAST_ID;
- priv->contexts[IWL_RXON_CTX_PAN].station_flags = STA_FLG_PAN_STATION;
- priv->contexts[IWL_RXON_CTX_PAN].ac_to_fifo = iwlagn_pan_ac_to_fifo;
- priv->contexts[IWL_RXON_CTX_PAN].ac_to_queue = iwlagn_pan_ac_to_queue;
- priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE;
- priv->contexts[IWL_RXON_CTX_PAN].interface_modes =
- BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP);
-#ifdef CONFIG_IWL_P2P
- priv->contexts[IWL_RXON_CTX_PAN].interface_modes |=
- BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
-#endif
- priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP;
- priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA;
- priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P;
-
- BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
-}
-
-int iwl_probe(struct iwl_bus *bus, struct iwl_cfg *cfg)
+int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
+ struct iwl_cfg *cfg)
{
int err = 0;
struct iwl_priv *priv;
@@ -3640,24 +3211,32 @@ int iwl_probe(struct iwl_bus *bus, struct iwl_cfg *cfg)
}
priv = hw->priv;
- priv->bus = bus;
- bus_set_drv_data(priv->bus, priv);
+ priv->shrd = &priv->_shrd;
+ bus->shrd = priv->shrd;
+ priv->shrd->bus = bus;
+ priv->shrd->priv = priv;
+
+ priv->shrd->trans = trans_ops->alloc(priv->shrd);
+ if (priv->shrd->trans == NULL) {
+ err = -ENOMEM;
+ goto out_free_traffic_mem;
+ }
/* At this point both hw and priv are allocated. */
- SET_IEEE80211_DEV(hw, priv->bus->dev);
+ SET_IEEE80211_DEV(hw, bus(priv)->dev);
IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n");
priv->cfg = cfg;
- priv->inta_mask = CSR_INI_SET_MASK;
/* is antenna coupling more than 35dB ? */
priv->bt_ant_couple_ok =
- (iwlagn_ant_coupling > IWL_BT_ANTENNA_COUPLING_THRESHOLD) ?
- true : false;
+ (iwlagn_mod_params.ant_coupling >
+ IWL_BT_ANTENNA_COUPLING_THRESHOLD) ?
+ true : false;
/* enable/disable bt channel inhibition */
- priv->bt_ch_announce = iwlagn_bt_ch_announce;
+ priv->bt_ch_announce = iwlagn_mod_params.bt_ch_announce;
IWL_DEBUG_INFO(priv, "BT channel inhibition is %s\n",
(priv->bt_ch_announce) ? "On" : "Off");
@@ -3667,15 +3246,15 @@ int iwl_probe(struct iwl_bus *bus, struct iwl_cfg *cfg)
/* these spin locks will be used in apm_ops.init and EEPROM access
* we should init now
*/
- spin_lock_init(&priv->reg_lock);
- spin_lock_init(&priv->lock);
+ spin_lock_init(&bus(priv)->reg_lock);
+ spin_lock_init(&priv->shrd->lock);
/*
* stop and reset the on-board processor just in case it is in a
* strange state ... like being left stranded by a primary kernel
* and this is now the kdump kernel trying to start up
*/
- iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
+ iwl_write32(bus(priv), CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
/***********************
* 3. Read REV register
@@ -3684,11 +3263,11 @@ int iwl_probe(struct iwl_bus *bus, struct iwl_cfg *cfg)
IWL_INFO(priv, "Detected %s, REV=0x%X\n",
priv->cfg->name, hw_rev);
- err = iwl_trans_register(&priv->trans, priv);
+ err = iwl_trans_request_irq(trans(priv));
if (err)
- goto out_free_traffic_mem;
+ goto out_free_trans;
- if (trans_prepare_card_hw(&priv->trans)) {
+ if (iwl_trans_prepare_card_hw(trans(priv))) {
err = -EIO;
IWL_WARN(priv, "Failed, HW not ready\n");
goto out_free_trans;
@@ -3724,9 +3303,6 @@ int iwl_probe(struct iwl_bus *bus, struct iwl_cfg *cfg)
priv->hw->wiphy->n_addresses++;
}
- /* initialize all valid contexts */
- iwl_init_context(priv);
-
/************************
* 5. Setup HW constants
************************/
@@ -3759,13 +3335,14 @@ int iwl_probe(struct iwl_bus *bus, struct iwl_cfg *cfg)
iwl_enable_rfkill_int(priv);
/* If platform's RF_KILL switch is NOT set to KILL */
- if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
- clear_bit(STATUS_RF_KILL_HW, &priv->status);
+ if (iwl_read32(bus(priv),
+ CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
+ clear_bit(STATUS_RF_KILL_HW, &priv->shrd->status);
else
- set_bit(STATUS_RF_KILL_HW, &priv->status);
+ set_bit(STATUS_RF_KILL_HW, &priv->shrd->status);
wiphy_rfkill_set_hw_state(priv->hw->wiphy,
- test_bit(STATUS_RF_KILL_HW, &priv->status));
+ test_bit(STATUS_RF_KILL_HW, &priv->shrd->status));
iwl_power_initialize(priv);
iwl_tt_initialize(priv);
@@ -3779,13 +3356,13 @@ int iwl_probe(struct iwl_bus *bus, struct iwl_cfg *cfg)
return 0;
out_destroy_workqueue:
- destroy_workqueue(priv->workqueue);
- priv->workqueue = NULL;
+ destroy_workqueue(priv->shrd->workqueue);
+ priv->shrd->workqueue = NULL;
iwl_uninit_drv(priv);
out_free_eeprom:
iwl_eeprom_free(priv);
out_free_trans:
- trans_free(&priv->trans);
+ iwl_trans_free(trans(priv));
out_free_traffic_mem:
iwl_free_traffic_mem(priv);
ieee80211_free_hw(priv->hw);
@@ -3795,21 +3372,17 @@ out:
void __devexit iwl_remove(struct iwl_priv * priv)
{
- unsigned long flags;
-
wait_for_completion(&priv->firmware_loading_complete);
IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n");
iwl_dbgfs_unregister(priv);
- sysfs_remove_group(&priv->bus->dev->kobj,
- &iwl_attribute_group);
- /* ieee80211_unregister_hw call wil cause iwl_mac_stop to
+ /* 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->status);
+ set_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
iwl_testmode_cleanup(priv);
iwl_leds_exit(priv);
@@ -3819,40 +3392,26 @@ void __devexit iwl_remove(struct iwl_priv * priv)
priv->mac80211_registered = 0;
}
- /* Reset to low power before unloading driver. */
- iwl_apm_stop(priv);
-
iwl_tt_exit(priv);
- /* make sure we flush any pending irq or
- * tasklet for the driver
- */
- spin_lock_irqsave(&priv->lock, flags);
- iwl_disable_interrupts(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- trans_sync_irq(&priv->trans);
+ /*This will stop the queues, move the device to low power state */
+ iwl_trans_stop_device(trans(priv));
iwl_dealloc_ucode(priv);
- trans_rx_free(&priv->trans);
- trans_tx_free(&priv->trans);
-
iwl_eeprom_free(priv);
/*netif_stop_queue(dev); */
- flush_workqueue(priv->workqueue);
+ flush_workqueue(priv->shrd->workqueue);
- /* ieee80211_unregister_hw calls iwl_mac_stop, which flushes
- * priv->workqueue... so we can't take down the workqueue
+ /* ieee80211_unregister_hw calls iwlagn_mac_stop, which flushes
+ * priv->shrd->workqueue... so we can't take down the workqueue
* until now... */
- destroy_workqueue(priv->workqueue);
- priv->workqueue = NULL;
+ destroy_workqueue(priv->shrd->workqueue);
+ priv->shrd->workqueue = NULL;
iwl_free_traffic_mem(priv);
- trans_free(&priv->trans);
-
- bus_set_drv_data(priv->bus, NULL);
+ iwl_trans_free(trans(priv));
iwl_uninit_drv(priv);
@@ -3901,7 +3460,8 @@ module_exit(iwl_exit);
module_init(iwl_init);
#ifdef CONFIG_IWLWIFI_DEBUG
-module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR);
+module_param_named(debug, iwlagn_mod_params.debug_level, uint,
+ S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "debug output mask");
#endif
@@ -3917,18 +3477,21 @@ MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
module_param_named(fw_restart, iwlagn_mod_params.restart_fw, int, S_IRUGO);
MODULE_PARM_DESC(fw_restart, "restart firmware in case of error");
-module_param_named(ucode_alternative, iwlagn_wanted_ucode_alternative, int,
- S_IRUGO);
+module_param_named(ucode_alternative,
+ iwlagn_mod_params.wanted_ucode_alternative,
+ int, S_IRUGO);
MODULE_PARM_DESC(ucode_alternative,
"specify ucode alternative to use from ucode file");
-module_param_named(antenna_coupling, iwlagn_ant_coupling, int, S_IRUGO);
+module_param_named(antenna_coupling, iwlagn_mod_params.ant_coupling,
+ int, S_IRUGO);
MODULE_PARM_DESC(antenna_coupling,
"specify antenna coupling in dB (defualt: 0 dB)");
-module_param_named(bt_ch_inhibition, iwlagn_bt_ch_announce, bool, S_IRUGO);
+module_param_named(bt_ch_inhibition, iwlagn_mod_params.bt_ch_announce,
+ bool, S_IRUGO);
MODULE_PARM_DESC(bt_ch_inhibition,
- "Disable BT channel inhibition (default: enable)");
+ "Enable BT channel inhibition (default: enable)");
module_param_named(plcp_check, iwlagn_mod_params.plcp_check, bool, S_IRUGO);
MODULE_PARM_DESC(plcp_check, "Check plcp health (default: 1 [enabled])");
@@ -3974,6 +3537,11 @@ module_param_named(power_level, iwlagn_mod_params.power_level,
MODULE_PARM_DESC(power_level,
"default power save level (range from 1 - 5, default: 1)");
+module_param_named(auto_agg, iwlagn_mod_params.auto_agg,
+ bool, S_IRUGO);
+MODULE_PARM_DESC(auto_agg,
+ "enable agg w/o check traffic load (default: enable)");
+
/*
* For now, keep using power level 1 instead of automatically
* adjusting ...
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index d941c4c98e4b..5b936ec1a541 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -65,54 +65,9 @@
#include "iwl-dev.h"
-/* configuration for the _agn 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 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_2bg_cfg;
-extern struct iwl_cfg iwl2030_2bgn_cfg;
-extern struct iwl_cfg iwl2030_2bg_cfg;
-extern struct iwl_cfg iwl6035_2agn_cfg;
-extern struct iwl_cfg iwl6035_2abg_cfg;
-extern struct iwl_cfg iwl6035_2bg_cfg;
-extern struct iwl_cfg iwl105_bg_cfg;
-extern struct iwl_cfg iwl105_bgn_cfg;
-extern struct iwl_cfg iwl135_bg_cfg;
-extern struct iwl_cfg iwl135_bgn_cfg;
-
-extern struct iwl_mod_params iwlagn_mod_params;
-
extern struct ieee80211_ops iwlagn_hw_ops;
-int iwl_reset_ict(struct iwl_priv *priv);
+int iwl_reset_ict(struct iwl_trans *trans);
static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd)
{
@@ -122,10 +77,6 @@ static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd)
hdr->data_valid = 1;
}
-/* tx queue */
-void iwl_free_tfds_in_queue(struct iwl_priv *priv,
- int sta_id, int tid, int freed);
-
/* RXON */
int iwlagn_set_pan_params(struct iwl_priv *priv);
int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
@@ -137,8 +88,9 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
u32 changes);
/* uCode */
-void iwlagn_rx_calib_result(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb);
+int iwlagn_rx_calib_result(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb,
+ struct iwl_device_cmd *cmd);
int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
void iwlagn_send_prio_tbl(struct iwl_priv *priv);
int iwlagn_run_init_ucode(struct iwl_priv *priv);
@@ -147,13 +99,9 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
enum iwlagn_ucode_type ucode_type);
/* lib */
-void iwl_check_abort_status(struct iwl_priv *priv,
- u8 frame_count, u32 status);
-int iwlagn_hw_valid_rtc_data_addr(u32 addr);
int iwlagn_send_tx_power(struct iwl_priv *priv);
void iwlagn_temperature(struct iwl_priv *priv);
u16 iwlagn_eeprom_calib_version(struct iwl_priv *priv);
-int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv);
int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
int iwlagn_send_beacon_cmd(struct iwl_priv *priv);
@@ -161,25 +109,19 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv);
/* rx */
int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
void iwl_setup_rx_handlers(struct iwl_priv *priv);
-void iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
/* tx */
-void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq,
- int index);
-void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
- struct ieee80211_tx_info *info);
int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid, u16 *ssn);
int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid);
-int iwlagn_txq_check_empty(struct iwl_priv *priv,
- int sta_id, u8 tid, int txq_id);
-void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb);
-void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
-int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
+int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+ struct iwl_device_cmd *cmd);
static inline u32 iwl_tx_status_to_mac80211(u32 status)
{
@@ -207,17 +149,14 @@ static inline bool iwl_is_tx_success(u32 status)
u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid);
/* scan */
-int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif);
void iwlagn_post_scan(struct iwl_priv *priv);
-
-/* station mgmt */
-int iwlagn_manage_ibss_station(struct iwl_priv *priv,
- struct ieee80211_vif *vif, bool add);
+void iwlagn_disable_roc(struct iwl_priv *priv);
/* bt coex */
void iwlagn_send_advance_bt_config(struct iwl_priv *priv);
-void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb);
+int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_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);
void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv);
@@ -232,7 +171,120 @@ static inline const char *iwl_get_tx_fail_reason(u32 status) { return ""; }
static inline const char *iwl_get_agg_tx_fail_reason(u16 status) { return ""; }
#endif
+
/* station management */
+int iwlagn_manage_ibss_station(struct iwl_priv *priv,
+ struct ieee80211_vif *vif, bool add);
+#define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */
+#define IWL_STA_UCODE_ACTIVE BIT(1) /* ucode entry is active */
+#define IWL_STA_UCODE_INPROGRESS BIT(2) /* ucode entry is in process of
+ being activated */
+#define IWL_STA_LOCAL BIT(3) /* station state not directed by mac80211;
+ (this is for the IBSS BSSID stations) */
+#define IWL_STA_BCAST BIT(4) /* this station is the special bcast station */
+
+
+void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+void iwl_clear_ucode_stations(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx);
+void iwl_dealloc_bcast_stations(struct iwl_priv *priv);
+int iwl_get_free_ucode_key_offset(struct iwl_priv *priv);
+int iwl_send_add_sta(struct iwl_priv *priv,
+ struct iwl_addsta_cmd *sta, u8 flags);
+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);
+int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
+ const u8 *addr);
+int iwlagn_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
+
+u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+ const u8 *addr, bool is_ap, struct ieee80211_sta *sta);
+
+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,
+ struct iwl_device_cmd *cmd);
+
+
+/**
+ * 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))
+ return IWL_INVALID_STATION;
+
+ 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,
@@ -286,7 +338,7 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
}
/* eeprom */
-void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv);
+void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv);
void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac);
/* notification wait support */
@@ -309,20 +361,22 @@ extern int iwlagn_init_alive_start(struct iwl_priv *priv);
extern int iwl_alive_start(struct iwl_priv *priv);
/* svtool */
#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL
-extern int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len);
-extern int iwl_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct netlink_callback *cb,
- void *data, int len);
+extern int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data,
+ int len);
+extern int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw,
+ struct sk_buff *skb,
+ struct netlink_callback *cb,
+ void *data, int len);
extern void iwl_testmode_init(struct iwl_priv *priv);
extern void iwl_testmode_cleanup(struct iwl_priv *priv);
#else
static inline
-int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
+int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
{
return -ENOSYS;
}
static inline
-int iwl_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
+int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
struct netlink_callback *cb,
void *data, int len)
{
diff --git a/drivers/net/wireless/iwlwifi/iwl-bus.h b/drivers/net/wireless/iwlwifi/iwl-bus.h
index f3ee1c0c004c..08b97594e305 100644
--- a/drivers/net/wireless/iwlwifi/iwl-bus.h
+++ b/drivers/net/wireless/iwlwifi/iwl-bus.h
@@ -60,16 +60,68 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
-#ifndef __iwl_pci_h__
-#define __iwl_pci_h__
+#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_ops - bus specific operations
* @get_pm_support: must returns true if the bus can go to sleep
- * @apm_config: will be called during the config of the APM configuration
- * @set_drv_data: set the drv_data pointer to the bus layer
+ * @apm_config: will be called during the config of the APM
* @get_hw_id: prints the hw_id in the provided buffer
* @write8: write a byte to register at offset ofs
* @write32: write a dword to register at offset ofs
@@ -78,20 +130,32 @@ struct iwl_bus;
struct iwl_bus_ops {
bool (*get_pm_support)(struct iwl_bus *bus);
void (*apm_config)(struct iwl_bus *bus);
- void (*set_drv_data)(struct iwl_bus *bus, void *drv_data);
void (*get_hw_id)(struct iwl_bus *bus, char buf[], int buf_len);
void (*write8)(struct iwl_bus *bus, u32 ofs, u8 val);
void (*write32)(struct iwl_bus *bus, u32 ofs, u32 val);
u32 (*read32)(struct iwl_bus *bus, u32 ofs);
};
+/**
+ * struct iwl_bus - bus common data
+ *
+ * This data is common to all bus layer implementations.
+ *
+ * @dev - pointer to struct device * that represents the device
+ * @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
+ * @irq - the irq number for the device
+ * @reg_lock - protect hw register access
+ */
struct iwl_bus {
- /* Common data to all buses */
- void *drv_data; /* driver's context */
struct device *dev;
- struct iwl_bus_ops *ops;
+ const struct iwl_bus_ops *ops;
+ struct iwl_shared *shrd;
unsigned int irq;
+ spinlock_t reg_lock;
/* pointer to bus specific struct */
/*Ensure that this pointer will always be aligned to sizeof pointer */
@@ -108,11 +172,6 @@ static inline void bus_apm_config(struct iwl_bus *bus)
bus->ops->apm_config(bus);
}
-static inline void bus_set_drv_data(struct iwl_bus *bus, void *drv_data)
-{
- bus->ops->set_drv_data(bus, drv_data);
-}
-
static inline void bus_get_hw_id(struct iwl_bus *bus, char buf[], int buf_len)
{
bus->ops->get_hw_id(bus, buf, buf_len);
@@ -133,7 +192,10 @@ static inline u32 bus_read32(struct iwl_bus *bus, u32 ofs)
return bus->ops->read32(bus, ofs);
}
+/*****************************************************
+* Bus layer registration functions
+******************************************************/
int __must_check iwl_pci_register_driver(void);
void iwl_pci_unregister_driver(void);
-#endif
+#endif /* __iwl_bus_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h b/drivers/net/wireless/iwlwifi/iwl-cfg.h
index b27986e57c92..2a2dc4597ba1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-cfg.h
@@ -60,22 +60,58 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
-/*
- * Please use this file (iwl-6000-hw.h) only for hardware-related definitions.
- * Use iwl-commands.h for uCode API definitions.
- */
+#ifndef __iwl_pci_h__
+#define __iwl_pci_h__
-#ifndef __iwl_6000_hw_h__
-#define __iwl_6000_hw_h__
-#define IWL60_RTC_INST_LOWER_BOUND (0x000000)
-#define IWL60_RTC_INST_UPPER_BOUND (0x040000)
-#define IWL60_RTC_DATA_LOWER_BOUND (0x800000)
-#define IWL60_RTC_DATA_UPPER_BOUND (0x814000)
-#define IWL60_RTC_INST_SIZE \
- (IWL60_RTC_INST_UPPER_BOUND - IWL60_RTC_INST_LOWER_BOUND)
-#define IWL60_RTC_DATA_SIZE \
- (IWL60_RTC_DATA_UPPER_BOUND - IWL60_RTC_DATA_LOWER_BOUND)
+/*
+ * This file declares the config structures for all devices.
+ */
-#endif /* __iwl_6000_hw_h__ */
+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_2bg_cfg;
+extern struct iwl_cfg iwl2000_2bgn_d_cfg;
+extern struct iwl_cfg iwl2030_2bgn_cfg;
+extern struct iwl_cfg iwl2030_2bg_cfg;
+extern struct iwl_cfg iwl6035_2agn_cfg;
+extern struct iwl_cfg iwl6035_2abg_cfg;
+extern struct iwl_cfg iwl6035_2bg_cfg;
+extern struct iwl_cfg iwl105_bg_cfg;
+extern struct iwl_cfg iwl105_bgn_cfg;
+extern struct iwl_cfg iwl105_bgn_d_cfg;
+extern struct iwl_cfg iwl135_bg_cfg;
+extern struct iwl_cfg iwl135_bgn_cfg;
+#endif /* __iwl_pci_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index e9e9d1d1778d..69d5f85d11e2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -69,6 +69,9 @@
#ifndef __iwl_commands_h__
#define __iwl_commands_h__
+#include <linux/etherdevice.h>
+#include <linux/ieee80211.h>
+
struct iwl_priv;
/* uCode version contains 4 values: Major/Minor/API/Serial */
@@ -86,6 +89,7 @@ struct iwl_priv;
enum {
REPLY_ALIVE = 0x1,
REPLY_ERROR = 0x2,
+ REPLY_ECHO = 0x3, /* test command */
/* RXON and QOS commands */
REPLY_RXON = 0x10,
@@ -670,7 +674,6 @@ struct iwl_rxon_assoc_cmd {
#define IWL_CONN_MAX_LISTEN_INTERVAL 10
#define IWL_MAX_UCODE_BEACON_INTERVAL 4 /* 4096 */
-#define IWL39_MAX_UCODE_BEACON_INTERVAL 1 /* 1024 */
/*
* REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
@@ -806,6 +809,7 @@ struct iwl_qosparam_cmd {
#define IWLAGN_STATION_COUNT 16
#define IWL_INVALID_STATION 255
+#define IWL_MAX_TID_COUNT 9
#define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2)
#define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8)
@@ -3067,17 +3071,29 @@ struct iwl_missed_beacon_notif {
/* number of additional entries for enhanced tbl */
#define ENHANCE_HD_TABLE_ENTRIES (ENHANCE_HD_TABLE_SIZE - HD_TABLE_SIZE)
-#define HD_INA_NON_SQUARE_DET_OFDM_DATA cpu_to_le16(0)
-#define HD_INA_NON_SQUARE_DET_CCK_DATA cpu_to_le16(0)
-#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA cpu_to_le16(0)
-#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA cpu_to_le16(668)
-#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA cpu_to_le16(4)
-#define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA cpu_to_le16(486)
-#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA cpu_to_le16(37)
-#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA cpu_to_le16(853)
-#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA cpu_to_le16(4)
-#define HD_CCK_NON_SQUARE_DET_SLOPE_DATA cpu_to_le16(476)
-#define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA cpu_to_le16(99)
+#define HD_INA_NON_SQUARE_DET_OFDM_DATA_V1 cpu_to_le16(0)
+#define HD_INA_NON_SQUARE_DET_CCK_DATA_V1 cpu_to_le16(0)
+#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V1 cpu_to_le16(0)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V1 cpu_to_le16(668)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1 cpu_to_le16(4)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V1 cpu_to_le16(486)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V1 cpu_to_le16(37)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V1 cpu_to_le16(853)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1 cpu_to_le16(4)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V1 cpu_to_le16(476)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V1 cpu_to_le16(99)
+
+#define HD_INA_NON_SQUARE_DET_OFDM_DATA_V2 cpu_to_le16(1)
+#define HD_INA_NON_SQUARE_DET_CCK_DATA_V2 cpu_to_le16(1)
+#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V2 cpu_to_le16(1)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V2 cpu_to_le16(600)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2 cpu_to_le16(40)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V2 cpu_to_le16(486)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V2 cpu_to_le16(45)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V2 cpu_to_le16(853)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2 cpu_to_le16(60)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V2 cpu_to_le16(476)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V2 cpu_to_le16(99)
/* Control field in struct iwl_sensitivity_cmd */
@@ -3198,12 +3214,17 @@ enum iwl_ucode_calib_cfg {
IWL_CALIB_CFG_LO_IDX | \
IWL_CALIB_CFG_TX_IQ_IDX | \
IWL_CALIB_CFG_RX_IQ_IDX | \
- IWL_CALIB_CFG_NOISE_IDX | \
- IWL_CALIB_CFG_CRYSTAL_IDX | \
+ IWL_CALIB_CFG_CRYSTAL_IDX)
+
+#define IWL_CALIB_RT_CFG_ALL cpu_to_le32(IWL_CALIB_CFG_RX_BB_IDX | \
+ IWL_CALIB_CFG_DC_IDX | \
+ IWL_CALIB_CFG_LO_IDX | \
+ IWL_CALIB_CFG_TX_IQ_IDX | \
+ IWL_CALIB_CFG_RX_IQ_IDX | \
IWL_CALIB_CFG_TEMPERATURE_IDX | \
IWL_CALIB_CFG_PAPD_IDX | \
- IWL_CALIB_CFG_SENSITIVITY_IDX | \
- IWL_CALIB_CFG_TX_PWR_IDX)
+ IWL_CALIB_CFG_TX_PWR_IDX | \
+ IWL_CALIB_CFG_CRYSTAL_IDX)
#define IWL_CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_MSK cpu_to_le32(BIT(0))
@@ -3253,6 +3274,14 @@ struct iwl_calib_temperature_offset_cmd {
__le16 reserved;
} __packed;
+struct iwl_calib_temperature_offset_v2_cmd {
+ struct iwl_calib_hdr hdr;
+ __le16 radio_sensor_offset_high;
+ __le16 radio_sensor_offset_low;
+ __le16 burntVoltageRef;
+ __le16 reserved;
+} __packed;
+
/* IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */
struct iwl_calib_chain_noise_reset_cmd {
struct iwl_calib_hdr hdr;
@@ -3897,6 +3926,7 @@ struct iwlagn_wowlan_kek_kck_material_cmd {
* Union of all expected notifications/responses:
*
*****************************************************************************/
+#define FH_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */
struct iwl_rx_packet {
/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index cf376f62b2f6..b247a56d5135 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -34,29 +34,26 @@
#include <net/mac80211.h>
#include "iwl-eeprom.h"
-#include "iwl-dev.h" /* FIXME: remove */
#include "iwl-debug.h"
#include "iwl-core.h"
#include "iwl-io.h"
#include "iwl-power.h"
-#include "iwl-sta.h"
-#include "iwl-helpers.h"
+#include "iwl-agn.h"
+#include "iwl-shared.h"
#include "iwl-agn.h"
#include "iwl-trans.h"
-u32 iwl_debug_level;
-
const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */
-static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
+static void iwl_init_ht_hw_capab(const struct iwl_priv *priv,
struct ieee80211_sta_ht_cap *ht_info,
enum ieee80211_band band)
{
u16 max_bit_rate = 0;
- u8 rx_chains_num = priv->hw_params.rx_chains_num;
- u8 tx_chains_num = priv->hw_params.tx_chains_num;
+ u8 rx_chains_num = hw_params(priv).rx_chains_num;
+ u8 tx_chains_num = hw_params(priv).tx_chains_num;
ht_info->cap = 0;
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
@@ -68,7 +65,7 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
max_bit_rate = MAX_BIT_RATE_20_MHZ;
- if (priv->hw_params.ht40_channel & BIT(band)) {
+ if (hw_params(priv).ht40_channel & BIT(band)) {
ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
ht_info->mcs.rx_mask[4] = 0x01;
@@ -106,9 +103,9 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
}
/**
- * iwlcore_init_geos - Initialize mac80211's geo/channel info based from eeprom
+ * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom
*/
-int iwlcore_init_geos(struct iwl_priv *priv)
+int iwl_init_geos(struct iwl_priv *priv)
{
struct iwl_channel_info *ch;
struct ieee80211_supported_band *sband;
@@ -121,16 +118,16 @@ int iwlcore_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->status);
+ set_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status);
return 0;
}
- channels = kzalloc(sizeof(struct ieee80211_channel) *
- priv->channel_count, GFP_KERNEL);
+ channels = kcalloc(priv->channel_count,
+ sizeof(struct ieee80211_channel), GFP_KERNEL);
if (!channels)
return -ENOMEM;
- rates = kzalloc((sizeof(struct ieee80211_rate) * IWL_RATE_COUNT_LEGACY),
+ rates = kcalloc(IWL_RATE_COUNT_LEGACY, sizeof(struct ieee80211_rate),
GFP_KERNEL);
if (!rates) {
kfree(channels);
@@ -145,7 +142,7 @@ int iwlcore_init_geos(struct iwl_priv *priv)
sband->n_bitrates = IWL_RATE_COUNT_LEGACY - IWL_FIRST_OFDM_RATE;
if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE)
- iwlcore_init_ht_hw_capab(priv, &sband->ht_cap,
+ iwl_init_ht_hw_capab(priv, &sband->ht_cap,
IEEE80211_BAND_5GHZ);
sband = &priv->bands[IEEE80211_BAND_2GHZ];
@@ -155,7 +152,7 @@ int iwlcore_init_geos(struct iwl_priv *priv)
sband->n_bitrates = IWL_RATE_COUNT_LEGACY;
if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE)
- iwlcore_init_ht_hw_capab(priv, &sband->ht_cap,
+ iwl_init_ht_hw_capab(priv, &sband->ht_cap,
IEEE80211_BAND_2GHZ);
priv->ieee_channels = channels;
@@ -211,7 +208,7 @@ int iwlcore_init_geos(struct iwl_priv *priv)
if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) &&
priv->cfg->sku & EEPROM_SKU_CAP_BAND_52GHZ) {
char buf[32];
- bus_get_hw_id(priv->bus, buf, sizeof(buf));
+ bus_get_hw_id(bus(priv), buf, sizeof(buf));
IWL_INFO(priv, "Incorrectly detected BG card as ABG. "
"Please send your %s to maintainer.\n", buf);
priv->cfg->sku &= ~EEPROM_SKU_CAP_BAND_52GHZ;
@@ -221,19 +218,19 @@ int iwlcore_init_geos(struct iwl_priv *priv)
priv->bands[IEEE80211_BAND_2GHZ].n_channels,
priv->bands[IEEE80211_BAND_5GHZ].n_channels);
- set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+ set_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status);
return 0;
}
/*
- * iwlcore_free_geos - undo allocations in iwlcore_init_geos
+ * iwl_free_geos - undo allocations in iwl_init_geos
*/
-void iwlcore_free_geos(struct iwl_priv *priv)
+void iwl_free_geos(struct iwl_priv *priv)
{
kfree(priv->ieee_channels);
kfree(priv->ieee_rates);
- clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
+ clear_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status);
}
static bool iwl_is_channel_extension(struct iwl_priv *priv,
@@ -323,9 +320,9 @@ int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
u16 beacon_int;
struct ieee80211_vif *vif = ctx->vif;
- conf = ieee80211_get_hw_conf(priv->hw);
+ conf = &priv->hw->conf;
- lockdep_assert_held(&priv->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
memset(&ctx->timing, 0, sizeof(struct iwl_rxon_time_cmd));
@@ -359,7 +356,7 @@ int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
beacon_int = le16_to_cpu(ctx->timing.beacon_interval);
} else {
beacon_int = iwl_adjust_beacon_interval(beacon_int,
- priv->hw_params.max_beacon_itrvl * TIME_UNIT);
+ IWL_MAX_UCODE_BEACON_INTERVAL * TIME_UNIT);
ctx->timing.beacon_interval = cpu_to_le16(beacon_int);
}
@@ -378,7 +375,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 trans_send_cmd_pdu(&priv->trans, ctx->rxon_timing_cmd,
+ return iwl_trans_send_cmd_pdu(trans(priv), ctx->rxon_timing_cmd,
CMD_SYNC, sizeof(ctx->timing), &ctx->timing);
}
@@ -804,21 +801,23 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
{
/*
* MULTI-FIXME
- * See iwl_mac_channel_switch.
+ * See iwlagn_mac_channel_switch.
*/
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
return;
- if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
+ if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING,
+ &priv->shrd->status))
ieee80211_chswitch_done(ctx->vif, is_success);
}
#ifdef CONFIG_IWLWIFI_DEBUG
void iwl_print_rx_config_cmd(struct iwl_priv *priv,
- struct iwl_rxon_context *ctx)
+ enum iwl_rxon_context_id ctxid)
{
+ struct iwl_rxon_context *ctx = &priv->contexts[ctxid];
struct iwl_rxon_cmd *rxon = &ctx->staging;
IWL_DEBUG_RADIO(priv, "RX CONFIG:\n");
@@ -856,18 +855,18 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
unsigned long reload_jiffies;
/* Set the FW error flag -- cleared on iwl_down */
- set_bit(STATUS_FW_ERROR, &priv->status);
+ set_bit(STATUS_FW_ERROR, &priv->shrd->status);
/* Cancel currently queued command. */
- clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+ clear_bit(STATUS_HCMD_ACTIVE, &priv->shrd->status);
iwlagn_abort_notification_waits(priv);
/* Keep the restart process from trying to send host
* commands by clearing the ready bit */
- clear_bit(STATUS_READY, &priv->status);
+ clear_bit(STATUS_READY, &priv->shrd->status);
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&priv->shrd->wait_command_queue);
if (!ondemand) {
/*
@@ -890,63 +889,26 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
priv->reload_count = 0;
}
- if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+ if (!test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) {
if (iwlagn_mod_params.restart_fw) {
- IWL_DEBUG(priv, IWL_DL_FW_ERRORS,
+ IWL_DEBUG_FW_ERRORS(priv,
"Restarting adapter due to uCode error.\n");
- queue_work(priv->workqueue, &priv->restart);
+ queue_work(priv->shrd->workqueue, &priv->restart);
} else
- IWL_DEBUG(priv, IWL_DL_FW_ERRORS,
+ IWL_DEBUG_FW_ERRORS(priv,
"Detected FW error, but not restarting\n");
}
}
-/**
- * iwl_irq_handle_error - called for HW or SW error interrupt from card
- */
-void iwl_irq_handle_error(struct iwl_priv *priv)
-{
- /* W/A for WiFi/WiMAX coex and WiMAX own the RF */
- if (priv->cfg->internal_wimax_coex &&
- (!(iwl_read_prph(priv, APMG_CLK_CTRL_REG) &
- APMS_CLK_VAL_MRB_FUNC_MODE) ||
- (iwl_read_prph(priv, APMG_PS_CTRL_REG) &
- APMG_PS_CTRL_VAL_RESET_REQ))) {
- /*
- * Keep the restart process from trying to send host
- * commands by clearing the ready bit.
- */
- clear_bit(STATUS_READY, &priv->status);
- clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
- wake_up_interruptible(&priv->wait_command_queue);
- IWL_ERR(priv, "RF is used by WiMAX\n");
- return;
- }
-
- IWL_ERR(priv, "Loaded firmware version: %s\n",
- priv->hw->wiphy->fw_version);
-
- iwl_dump_nic_error_log(priv);
- iwl_dump_csr(priv);
- iwl_dump_fh(priv, NULL, false);
- iwl_dump_nic_event_log(priv, false, NULL, false);
-#ifdef CONFIG_IWLWIFI_DEBUG
- if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS)
- iwl_print_rx_config_cmd(priv,
- &priv->contexts[IWL_RXON_CTX_BSS]);
-#endif
-
- iwlagn_fw_error(priv, false);
-}
-
static int iwl_apm_stop_master(struct iwl_priv *priv)
{
int ret = 0;
/* stop device's busmaster DMA activity */
- iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
+ iwl_set_bit(bus(priv), CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
- ret = iwl_poll_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED,
+ ret = iwl_poll_bit(bus(priv), CSR_RESET,
+ CSR_RESET_REG_FLAG_MASTER_DISABLED,
CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
if (ret)
IWL_WARN(priv, "Master Disable Timed Out, 100 usec\n");
@@ -960,13 +922,13 @@ void iwl_apm_stop(struct iwl_priv *priv)
{
IWL_DEBUG_INFO(priv, "Stop card, put in low power state\n");
- clear_bit(STATUS_DEVICE_ENABLED, &priv->status);
+ clear_bit(STATUS_DEVICE_ENABLED, &priv->shrd->status);
/* Stop device's DMA activity */
iwl_apm_stop_master(priv);
/* Reset the entire device */
- iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+ iwl_set_bit(bus(priv), CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
udelay(10);
@@ -974,7 +936,7 @@ void iwl_apm_stop(struct iwl_priv *priv)
* Clear "initialization complete" bit to move adapter from
* D0A* (powered-up Active) --> D0U* (Uninitialized) state.
*/
- iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+ iwl_clear_bit(bus(priv), CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
}
@@ -994,45 +956,45 @@ int iwl_apm_init(struct iwl_priv *priv)
*/
/* Disable L0S exit timer (platform NMI Work/Around) */
- iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+ iwl_set_bit(bus(priv), CSR_GIO_CHICKEN_BITS,
CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
/*
* Disable L0s without affecting L1;
* don't wait for ICH L0s (ICH bug W/A)
*/
- iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+ iwl_set_bit(bus(priv), CSR_GIO_CHICKEN_BITS,
CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
/* Set FH wait threshold to maximum (HW error during stress W/A) */
- iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL);
+ iwl_set_bit(bus(priv), CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL);
/*
* Enable HAP INTA (interrupt from management bus) to
* wake device's PCI Express link L1a -> L0s
*/
- iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ iwl_set_bit(bus(priv), CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
- bus_apm_config(priv->bus);
+ bus_apm_config(bus(priv));
/* Configure analog phase-lock-loop before activating to D0A */
if (priv->cfg->base_params->pll_cfg_val)
- iwl_set_bit(priv, CSR_ANA_PLL_CFG,
+ iwl_set_bit(bus(priv), CSR_ANA_PLL_CFG,
priv->cfg->base_params->pll_cfg_val);
/*
* Set "initialization complete" bit to move adapter from
* D0U* --> D0A* (powered-up active) state.
*/
- iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+ iwl_set_bit(bus(priv), CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
/*
* Wait for clock stabilization; once stabilized, access to
* device-internal resources is supported, e.g. iwl_write_prph()
* and accesses to uCode SRAM.
*/
- ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
+ ret = iwl_poll_bit(bus(priv), CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
if (ret < 0) {
@@ -1047,14 +1009,14 @@ int iwl_apm_init(struct iwl_priv *priv)
* do not disable clocks. This preserves any hardware bits already
* set by default in "CLK_CTRL_REG" after reset.
*/
- iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
+ iwl_write_prph(bus(priv), APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
udelay(20);
/* Disable L1-Active */
- iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
+ iwl_set_bits_prph(bus(priv), APMG_PCIDEV_STT_REG,
APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
- set_bit(STATUS_DEVICE_ENABLED, &priv->status);
+ set_bit(STATUS_DEVICE_ENABLED, &priv->shrd->status);
out:
return ret;
@@ -1068,7 +1030,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->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
if (priv->tx_power_user_lmt == tx_power && !force)
return 0;
@@ -1088,7 +1050,7 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
return -EINVAL;
}
- if (!iwl_is_ready_rf(priv))
+ if (!iwl_is_ready_rf(priv->shrd))
return -EIO;
/* scan complete and commit_rxon use tx_power_next value,
@@ -1096,7 +1058,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->status) ||
+ defer = test_bit(STATUS_SCANNING, &priv->shrd->status) ||
memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging));
if (defer && !force) {
IWL_DEBUG_INFO(priv, "Deferring tx power set\n");
@@ -1134,7 +1096,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 (trans_send_cmd_pdu(&priv->trans, REPLY_BT_CONFIG,
+ if (iwl_trans_send_cmd_pdu(trans(priv), REPLY_BT_CONFIG,
CMD_SYNC, sizeof(struct iwl_bt_cmd), &bt_cmd))
IWL_ERR(priv, "failed to send BT Coex Config\n");
}
@@ -1147,24 +1109,20 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
};
if (flags & CMD_ASYNC)
- return trans_send_cmd_pdu(&priv->trans, REPLY_STATISTICS_CMD,
+ return iwl_trans_send_cmd_pdu(trans(priv), REPLY_STATISTICS_CMD,
CMD_ASYNC,
sizeof(struct iwl_statistics_cmd),
&statistics_cmd);
else
- return trans_send_cmd_pdu(&priv->trans, REPLY_STATISTICS_CMD,
+ return iwl_trans_send_cmd_pdu(trans(priv), REPLY_STATISTICS_CMD,
CMD_SYNC,
sizeof(struct iwl_statistics_cmd),
&statistics_cmd);
}
-void iwl_clear_isr_stats(struct iwl_priv *priv)
-{
- memset(&priv->isr_stats, 0, sizeof(priv->isr_stats));
-}
-
-int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
- const struct ieee80211_tx_queue_params *params)
+int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
{
struct iwl_priv *priv = hw->priv;
struct iwl_rxon_context *ctx;
@@ -1173,7 +1131,7 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
IWL_DEBUG_MAC80211(priv, "enter\n");
- if (!iwl_is_ready_rf(priv)) {
+ if (!iwl_is_ready_rf(priv->shrd)) {
IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
return -EIO;
}
@@ -1185,7 +1143,7 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
q = AC_NUM - 1 - queue;
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&priv->shrd->lock, flags);
/*
* MULTI-FIXME
@@ -1203,13 +1161,13 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0;
}
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irqrestore(&priv->shrd->lock, flags);
IWL_DEBUG_MAC80211(priv, "leave\n");
return 0;
}
-int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw)
+int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw)
{
struct iwl_priv *priv = hw->priv;
@@ -1231,7 +1189,7 @@ static int iwl_setup_interface(struct iwl_priv *priv,
struct ieee80211_vif *vif = ctx->vif;
int err;
- lockdep_assert_held(&priv->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
/*
* This variable will be correct only when there's just
@@ -1262,7 +1220,8 @@ static int iwl_setup_interface(struct iwl_priv *priv,
return 0;
}
-int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
{
struct iwl_priv *priv = hw->priv;
struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
@@ -1273,9 +1232,13 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
viftype, vif->addr);
- mutex_lock(&priv->mutex);
+ cancel_delayed_work_sync(&priv->hw_roc_disable_work);
+
+ mutex_lock(&priv->shrd->mutex);
+
+ iwlagn_disable_roc(priv);
- if (!iwl_is_ready_rf(priv)) {
+ if (!iwl_is_ready_rf(priv->shrd)) {
IWL_WARN(priv, "Try to add interface when device not ready\n");
err = -EINVAL;
goto out;
@@ -1318,7 +1281,7 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
ctx->vif = NULL;
priv->iw_mode = NL80211_IFTYPE_STATION;
out:
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
IWL_DEBUG_MAC80211(priv, "leave\n");
return err;
@@ -1330,7 +1293,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->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
if (priv->scan_vif == vif) {
iwl_scan_cancel_timeout(priv, 200);
@@ -1354,7 +1317,7 @@ static void iwl_teardown_interface(struct iwl_priv *priv,
priv->bt_traffic_load = priv->last_bt_traffic_load;
}
-void iwl_mac_remove_interface(struct ieee80211_hw *hw,
+void iwlagn_mac_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct iwl_priv *priv = hw->priv;
@@ -1362,14 +1325,20 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
IWL_DEBUG_MAC80211(priv, "enter\n");
- mutex_lock(&priv->mutex);
+ mutex_lock(&priv->shrd->mutex);
- WARN_ON(ctx->vif != vif);
+ if (WARN_ON(ctx->vif != vif)) {
+ struct iwl_rxon_context *tmp;
+ IWL_ERR(priv, "ctx->vif = %p, vif = %p\n", ctx->vif, vif);
+ for_each_context(priv, tmp)
+ IWL_ERR(priv, "\tID = %d:\tctx = %p\tctx->vif = %p\n",
+ tmp->ctxid, tmp, tmp->vif);
+ }
ctx->vif = NULL;
iwl_teardown_interface(priv, vif, false);
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -1393,7 +1362,7 @@ int iwl_alloc_traffic_mem(struct iwl_priv *priv)
{
u32 traffic_size = IWL_TRAFFIC_DUMP_SIZE;
- if (iwl_debug_level & IWL_DL_TX) {
+ if (iwl_get_debug_level(priv->shrd) & IWL_DL_TX) {
if (!priv->tx_traffic) {
priv->tx_traffic =
kzalloc(traffic_size, GFP_KERNEL);
@@ -1401,7 +1370,7 @@ int iwl_alloc_traffic_mem(struct iwl_priv *priv)
return -ENOMEM;
}
}
- if (iwl_debug_level & IWL_DL_RX) {
+ if (iwl_get_debug_level(priv->shrd) & IWL_DL_RX) {
if (!priv->rx_traffic) {
priv->rx_traffic =
kzalloc(traffic_size, GFP_KERNEL);
@@ -1428,7 +1397,7 @@ void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv,
__le16 fc;
u16 len;
- if (likely(!(iwl_debug_level & IWL_DL_TX)))
+ if (likely(!(iwl_get_debug_level(priv->shrd) & IWL_DL_TX)))
return;
if (!priv->tx_traffic)
@@ -1452,7 +1421,7 @@ void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv,
__le16 fc;
u16 len;
- if (likely(!(iwl_debug_level & IWL_DL_RX)))
+ if (likely(!(iwl_get_debug_level(priv->shrd) & IWL_DL_RX)))
return;
if (!priv->rx_traffic)
@@ -1609,7 +1578,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->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
return;
if (!iwl_is_any_associated(priv)) {
@@ -1634,7 +1603,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->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
return -EINVAL;
if (mode >= IWL_MAX_FORCE_RESET) {
@@ -1680,8 +1649,9 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external)
return 0;
}
-int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- enum nl80211_iftype newtype, bool newp2p)
+int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum nl80211_iftype newtype, bool newp2p)
{
struct iwl_priv *priv = hw->priv;
struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
@@ -1691,11 +1661,13 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 interface_modes;
int err;
+ IWL_DEBUG_MAC80211(priv, "enter\n");
+
newtype = ieee80211_iftype_p2p(newtype, newp2p);
- mutex_lock(&priv->mutex);
+ mutex_lock(&priv->shrd->mutex);
- if (!ctx->vif || !iwl_is_ready_rf(priv)) {
+ if (!ctx->vif || !iwl_is_ready_rf(priv->shrd)) {
/*
* Huh? But wait ... this can maybe happen when
* we're in the middle of a firmware restart!
@@ -1757,36 +1729,45 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
err = 0;
out:
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+
return err;
}
-/*
- * On every watchdog tick we check (latest) time stamp. If it does not
- * change during timeout period and queue is not empty we reset firmware.
- */
-static int iwl_check_stuck_queue(struct iwl_priv *priv, int cnt)
+int iwl_cmd_echo_test(struct iwl_priv *priv)
{
- struct iwl_tx_queue *txq = &priv->txq[cnt];
- struct iwl_queue *q = &txq->q;
- unsigned long timeout;
int ret;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_ECHO,
+ .flags = CMD_SYNC,
+ };
- if (q->read_ptr == q->write_ptr) {
- txq->time_stamp = jiffies;
- return 0;
- }
-
- timeout = txq->time_stamp +
- msecs_to_jiffies(priv->cfg->base_params->wd_timeout);
+ ret = iwl_trans_send_cmd(trans(priv), &cmd);
+ if (ret)
+ IWL_ERR(priv, "echo testing fail: 0X%x\n", ret);
+ else
+ IWL_DEBUG_INFO(priv, "echo testing pass\n");
+ return ret;
+}
- if (time_after(jiffies, timeout)) {
- IWL_ERR(priv, "Queue %d stuck for %u ms.\n",
- q->id, priv->cfg->base_params->wd_timeout);
+static inline int iwl_check_stuck_queue(struct iwl_priv *priv, int txq)
+{
+ if (iwl_trans_check_stuck_queue(trans(priv), txq)) {
+ int ret;
+ if (txq == priv->shrd->cmd_queue) {
+ /*
+ * validate command queue still working
+ * by sending "ECHO" command
+ */
+ if (!iwl_cmd_echo_test(priv))
+ return 0;
+ else
+ IWL_DEBUG_HC(priv, "echo testing fail\n");
+ }
ret = iwl_force_reset(priv, IWL_FW_RESET, false);
return (ret == -EAGAIN) ? 0 : 1;
}
-
return 0;
}
@@ -1806,7 +1787,10 @@ void iwl_bg_watchdog(unsigned long data)
int cnt;
unsigned long timeout;
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+ return;
+
+ if (iwl_is_rfkill(priv->shrd))
return;
timeout = priv->cfg->base_params->wd_timeout;
@@ -1814,14 +1798,14 @@ void iwl_bg_watchdog(unsigned long data)
return;
/* monitor and check for stuck cmd queue */
- if (iwl_check_stuck_queue(priv, priv->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 < priv->hw_params.max_txq_num; cnt++) {
+ for (cnt = 0; cnt < hw_params(priv).max_txq_num; cnt++) {
/* skip as we already checked the command queue */
- if (cnt == priv->cmd_queue)
+ if (cnt == priv->shrd->cmd_queue)
continue;
if (iwl_check_stuck_queue(priv, cnt))
return;
@@ -1843,6 +1827,28 @@ void iwl_setup_watchdog(struct iwl_priv *priv)
del_timer(&priv->watchdog);
}
+/**
+ * iwl_beacon_time_mask_low - mask of lower 32 bit of beacon time
+ * @priv -- pointer to iwl_priv data structure
+ * @tsf_bits -- number of bits need to shift for masking)
+ */
+static inline u32 iwl_beacon_time_mask_low(struct iwl_priv *priv,
+ u16 tsf_bits)
+{
+ return (1 << tsf_bits) - 1;
+}
+
+/**
+ * iwl_beacon_time_mask_high - mask of higher 32 bit of beacon time
+ * @priv -- pointer to iwl_priv data structure
+ * @tsf_bits -- number of bits need to shift for masking)
+ */
+static inline u32 iwl_beacon_time_mask_high(struct iwl_priv *priv,
+ u16 tsf_bits)
+{
+ return ((1 << (32 - tsf_bits)) - 1) << tsf_bits;
+}
+
/*
* extended beacon time format
* time in usec will be changed into a 32-bit value in extended:internal format
@@ -1859,13 +1865,12 @@ u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval)
return 0;
quot = (usec / interval) &
- (iwl_beacon_time_mask_high(priv,
- priv->hw_params.beacon_time_tsf_bits) >>
- priv->hw_params.beacon_time_tsf_bits);
+ (iwl_beacon_time_mask_high(priv, IWLAGN_EXT_BEACON_TIME_POS) >>
+ IWLAGN_EXT_BEACON_TIME_POS);
rem = (usec % interval) & iwl_beacon_time_mask_low(priv,
- priv->hw_params.beacon_time_tsf_bits);
+ IWLAGN_EXT_BEACON_TIME_POS);
- return (quot << priv->hw_params.beacon_time_tsf_bits) + rem;
+ return (quot << IWLAGN_EXT_BEACON_TIME_POS) + rem;
}
/* base is usually what we get from ucode with each received frame,
@@ -1875,64 +1880,80 @@ __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
u32 addon, u32 beacon_interval)
{
u32 base_low = base & iwl_beacon_time_mask_low(priv,
- priv->hw_params.beacon_time_tsf_bits);
+ IWLAGN_EXT_BEACON_TIME_POS);
u32 addon_low = addon & iwl_beacon_time_mask_low(priv,
- priv->hw_params.beacon_time_tsf_bits);
+ IWLAGN_EXT_BEACON_TIME_POS);
u32 interval = beacon_interval * TIME_UNIT;
u32 res = (base & iwl_beacon_time_mask_high(priv,
- priv->hw_params.beacon_time_tsf_bits)) +
+ IWLAGN_EXT_BEACON_TIME_POS)) +
(addon & iwl_beacon_time_mask_high(priv,
- priv->hw_params.beacon_time_tsf_bits));
+ IWLAGN_EXT_BEACON_TIME_POS));
if (base_low > addon_low)
res += base_low - addon_low;
else if (base_low < addon_low) {
res += interval + base_low - addon_low;
- res += (1 << priv->hw_params.beacon_time_tsf_bits);
+ res += (1 << IWLAGN_EXT_BEACON_TIME_POS);
} else
- res += (1 << priv->hw_params.beacon_time_tsf_bits);
+ res += (1 << IWLAGN_EXT_BEACON_TIME_POS);
return cpu_to_le32(res);
}
-#ifdef CONFIG_PM
+void iwl_start_tx_ba_trans_ready(struct iwl_priv *priv,
+ enum iwl_rxon_context_id ctx,
+ u8 sta_id, u8 tid)
+{
+ struct ieee80211_vif *vif;
+ u8 *addr = priv->stations[sta_id].sta.sta.addr;
-int iwl_suspend(struct iwl_priv *priv)
+ if (ctx == NUM_IWL_RXON_CTX)
+ ctx = priv->stations[sta_id].ctxid;
+ vif = priv->contexts[ctx].vif;
+
+ ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid);
+}
+
+void iwl_stop_tx_ba_trans_ready(struct iwl_priv *priv,
+ enum iwl_rxon_context_id ctx,
+ u8 sta_id, u8 tid)
{
- /*
- * This function is called when system goes into suspend state
- * mac80211 will call iwl_mac_stop() from the mac80211 suspend function
- * first but since iwl_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 (!priv->wowlan)
- iwl_apm_stop(priv);
+ struct ieee80211_vif *vif;
+ u8 *addr = priv->stations[sta_id].sta.sta.addr;
- return 0;
+ if (ctx == NUM_IWL_RXON_CTX)
+ ctx = priv->stations[sta_id].ctxid;
+ vif = priv->contexts[ctx].vif;
+
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid);
}
-int iwl_resume(struct iwl_priv *priv)
+void iwl_set_hw_rfkill_state(struct iwl_priv *priv, bool state)
{
- bool hw_rfkill = false;
+ wiphy_rfkill_set_hw_state(priv->hw->wiphy, state);
+}
- iwl_enable_interrupts(priv);
+void iwl_nic_config(struct iwl_priv *priv)
+{
+ priv->cfg->lib->nic_config(priv);
- if (!(iwl_read32(priv, CSR_GP_CNTRL) &
- CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
- hw_rfkill = true;
+}
- if (hw_rfkill)
- set_bit(STATUS_RF_KILL_HW, &priv->status);
- else
- clear_bit(STATUS_RF_KILL_HW, &priv->status);
+void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *info;
- wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rfkill);
+ info = IEEE80211_SKB_CB(skb);
+ kmem_cache_free(priv->tx_cmd_pool, (info->driver_data[1]));
+ dev_kfree_skb_any(skb);
+}
- return 0;
+void iwl_stop_sw_queue(struct iwl_priv *priv, u8 ac)
+{
+ ieee80211_stop_queue(priv->hw, ac);
}
-#endif /* CONFIG_PM */
+void iwl_wake_sw_queue(struct iwl_priv *priv, u8 ac)
+{
+ ieee80211_wake_queue(priv->hw, ac);
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 02817a438550..137da3380704 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -64,6 +64,7 @@
#define __iwl_core_h__
#include "iwl-dev.h"
+#include "iwl-io.h"
/************************
* forward declarations *
@@ -71,15 +72,8 @@
struct iwl_host_cmd;
struct iwl_cmd;
-
-#define IWLWIFI_VERSION "in-tree:"
-#define DRV_COPYRIGHT "Copyright(c) 2003-2011 Intel Corporation"
-#define DRV_AUTHOR "<ilw@linux.intel.com>"
-
#define TIME_UNIT 1024
-#define IWL_CMD(x) case x: return #x
-
struct iwl_lib_ops {
/* set hw dependent parameters */
int (*set_hw_params)(struct iwl_priv *priv);
@@ -101,23 +95,6 @@ struct iwl_lib_ops {
void (*temperature)(struct iwl_priv *priv);
};
-struct iwl_mod_params {
- int sw_crypto; /* def: 0 = using hardware encryption */
- int num_of_queues; /* def: HW dependent */
- int disable_11n; /* def: 0 = 11n capabilities enabled */
- int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */
- int antenna; /* def: 0 = both antennas (use diversity) */
- int restart_fw; /* def: 1 = restart firmware */
- bool plcp_check; /* def: true = enable plcp health check */
- bool ack_check; /* def: false = disable ack health check */
- bool wd_disable; /* def: false = enable stuck queue check */
- bool bt_coex_active; /* def: true = enable bt coex */
- int led_mode; /* def: 0 = system default */
- bool no_sleep_autoadjust; /* def: true = disable autoadjust */
- bool power_save; /* def: false = disable power save */
- int power_level; /* def: 1 = power level */
-};
-
/*
* @max_ll_items: max number of OTP blocks
* @shadow_ram_support: shadow support for OTP memory
@@ -132,10 +109,10 @@ struct iwl_mod_params {
* 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
- * @temperature_kelvin: temperature report by uCode in kelvin
* @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
*/
struct iwl_base_params {
int eeprom_size;
@@ -147,17 +124,16 @@ struct iwl_base_params {
const u16 max_ll_items;
const bool shadow_ram_support;
u16 led_compensation;
- int chain_noise_num_beacons;
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;
- bool temperature_kelvin;
u32 max_event_log_size;
const bool shadow_reg_enable;
const bool no_idle_support;
+ const bool hd_v2;
};
/*
* @advanced_bt_coexist: support advanced bt coexist
@@ -194,6 +170,8 @@ struct iwl_ht_params {
* (.ucode) will be added to filename before loading from disk. The
* filename is constructed as fw_name_pre<api>.ucode.
* @ucode_api_max: Highest version of uCode API supported by driver.
+ * @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.
* @valid_tx_ant: valid transmit antenna
* @valid_rx_ant: valid receive antenna
@@ -214,20 +192,12 @@ struct iwl_ht_params {
* @rx_with_siso_diversity: 1x1 device with rx antenna diversity
* @internal_wimax_coex: internal wifi/wimax combo device
* @iq_invert: I/Q inversion
+ * @temp_offset_v2: support v2 of temperature offset calibration
*
* We enable the driver to be backward compatible wrt API version. The
* driver specifies which APIs it supports (with @ucode_api_max being the
* highest and @ucode_api_min the lowest). Firmware will only be loaded if
- * it has a supported API version. The firmware's API version will be
- * stored in @iwl_priv, enabling the driver to make runtime changes based
- * on firmware version used.
- *
- * For example,
- * if (IWL_UCODE_API(priv->ucode_ver) >= 2) {
- * Driver interacts with Firmware API version >= 2.
- * } else {
- * Driver interacts with Firmware API version 1.
- * }
+ * it has a supported API version.
*
* The ideal usage of this infrastructure is to treat a new ucode API
* release as a new hardware revision.
@@ -237,6 +207,7 @@ struct iwl_cfg {
const char *name;
const char *fw_name_pre;
const unsigned int ucode_api_max;
+ const unsigned int ucode_api_ok;
const unsigned int ucode_api_min;
u8 valid_tx_ant;
u8 valid_rx_ant;
@@ -259,15 +230,17 @@ struct iwl_cfg {
const bool rx_with_siso_diversity;
const bool internal_wimax_coex;
const bool iq_invert;
+ const bool temp_offset_v2;
};
/***************************
* L i b *
***************************/
-int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
+int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params);
-int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw);
+int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw);
void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
int hw_decrypt);
int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
@@ -287,18 +260,17 @@ bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
void iwl_connection_init_rx_config(struct iwl_priv *priv,
struct iwl_rxon_context *ctx);
void iwl_set_rate(struct iwl_priv *priv);
-void iwl_irq_handle_error(struct iwl_priv *priv);
-int iwl_mac_add_interface(struct ieee80211_hw *hw,
+int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
-void iwl_mac_remove_interface(struct ieee80211_hw *hw,
+void iwlagn_mac_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
-int iwl_mac_change_interface(struct ieee80211_hw *hw,
+int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum nl80211_iftype newtype, bool newp2p);
+int iwl_cmd_echo_test(struct iwl_priv *priv);
#ifdef CONFIG_IWLWIFI_DEBUGFS
int iwl_alloc_traffic_mem(struct iwl_priv *priv);
void iwl_free_traffic_mem(struct iwl_priv *priv);
-void iwl_reset_traffic_log(struct iwl_priv *priv);
void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv,
u16 length, struct ieee80211_hdr *header);
void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv,
@@ -349,9 +321,9 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force);
******************************************************************************/
void iwl_init_scan_params(struct iwl_priv *priv);
int iwl_scan_cancel(struct iwl_priv *priv);
-int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
+void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
void iwl_force_scan_end(struct iwl_priv *priv);
-int iwl_mac_hw_scan(struct ieee80211_hw *hw,
+int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_scan_request *req);
void iwl_internal_short_hw_scan(struct iwl_priv *priv);
@@ -359,12 +331,6 @@ 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);
-u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
- enum ieee80211_band band,
- u8 n_probes);
-u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
- enum ieee80211_band band,
- struct ieee80211_vif *vif);
void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
void iwl_cancel_scan_deferred_work(struct iwl_priv *priv);
int __must_check iwl_scan_initiate(struct iwl_priv *priv,
@@ -387,117 +353,21 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv,
* S e n d i n g H o s t C o m m a n d s *
*****************************************************/
-const char *get_cmd_string(u8 cmd);
void iwl_bg_watchdog(unsigned long data);
u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval);
__le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
u32 addon, u32 beacon_interval);
-#ifdef CONFIG_PM
-int iwl_suspend(struct iwl_priv *priv);
-int iwl_resume(struct iwl_priv *priv);
-#endif /* !CONFIG_PM */
-
-int iwl_probe(struct iwl_bus *bus, struct iwl_cfg *cfg);
-void __devexit iwl_remove(struct iwl_priv * priv);
-
-/*****************************************************
-* Error Handling Debugging
-******************************************************/
-void iwl_dump_nic_error_log(struct iwl_priv *priv);
-int iwl_dump_nic_event_log(struct iwl_priv *priv,
- bool full_log, char **buf, bool display);
-void iwl_dump_csr(struct iwl_priv *priv);
-int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display);
-#ifdef CONFIG_IWLWIFI_DEBUG
-void iwl_print_rx_config_cmd(struct iwl_priv *priv,
- struct iwl_rxon_context *ctx);
-#else
-static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv,
- struct iwl_rxon_context *ctx)
-{
-}
-#endif
-
-void iwl_clear_isr_stats(struct iwl_priv *priv);
/*****************************************************
* GEOS
******************************************************/
-int iwlcore_init_geos(struct iwl_priv *priv);
-void iwlcore_free_geos(struct iwl_priv *priv);
-
-/*************** DRIVER STATUS FUNCTIONS *****/
-
-#define STATUS_HCMD_ACTIVE 0 /* host command in progress */
-/* 1 is unused (used to be STATUS_HCMD_SYNC_ACTIVE) */
-#define STATUS_INT_ENABLED 2
-#define STATUS_RF_KILL_HW 3
-#define STATUS_CT_KILL 4
-#define STATUS_INIT 5
-#define STATUS_ALIVE 6
-#define STATUS_READY 7
-#define STATUS_TEMPERATURE 8
-#define STATUS_GEO_CONFIGURED 9
-#define STATUS_EXIT_PENDING 10
-#define STATUS_STATISTICS 12
-#define STATUS_SCANNING 13
-#define STATUS_SCAN_ABORTING 14
-#define STATUS_SCAN_HW 15
-#define STATUS_POWER_PMI 16
-#define STATUS_FW_ERROR 17
-#define STATUS_DEVICE_ENABLED 18
-#define STATUS_CHANNEL_SWITCH_PENDING 19
-
-
-static inline int iwl_is_ready(struct iwl_priv *priv)
-{
- /* 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_init(struct iwl_priv *priv)
-{
- return test_bit(STATUS_INIT, &priv->status);
-}
-
-static inline int iwl_is_rfkill_hw(struct iwl_priv *priv)
-{
- return test_bit(STATUS_RF_KILL_HW, &priv->status);
-}
-
-static inline int iwl_is_rfkill(struct iwl_priv *priv)
-{
- return iwl_is_rfkill_hw(priv);
-}
-
-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);
-}
+int iwl_init_geos(struct iwl_priv *priv);
+void iwl_free_geos(struct iwl_priv *priv);
extern void iwl_send_bt_config(struct iwl_priv *priv);
extern int iwl_send_statistics_request(struct iwl_priv *priv,
u8 flags, bool clear);
-void iwl_apm_stop(struct iwl_priv *priv);
-int iwl_apm_init(struct iwl_priv *priv);
int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
@@ -513,9 +383,12 @@ static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv)
priv->cfg->bt_params->advanced_bt_coexist;
}
-extern bool bt_siso_mode;
-
+static inline void iwl_enable_rfkill_int(struct iwl_priv *priv)
+{
+ IWL_DEBUG_ISR(priv, "Enabling rfkill interrupt\n");
+ iwl_write32(bus(priv), CSR_INT_MASK, CSR_INT_BIT_RF_KILL);
+}
-void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand);
+extern bool bt_siso_mode;
#endif /* __iwl_core_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index d6dbb0423045..b9f3267e720c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -439,4 +439,22 @@
*/
#define HBUS_TARG_WRPTR (HBUS_BASE+0x060)
+/**********************************************************
+ * CSR values
+ **********************************************************/
+ /*
+ * host interrupt timeout value
+ * used with setting interrupt coalescing timer
+ * the CSR_INT_COALESCING is an 8 bit register in 32-usec unit
+ *
+ * default interrupt coalescing timer is 64 x 32 = 2048 usecs
+ * default interrupt coalescing calibration timer is 16 x 32 = 512 usecs
+ */
+#define IWL_HOST_INT_TIMEOUT_MAX (0xFF)
+#define IWL_HOST_INT_TIMEOUT_DEF (0x40)
+#define IWL_HOST_INT_TIMEOUT_MIN (0x0)
+#define IWL_HOST_INT_CALIB_TIMEOUT_MAX (0xFF)
+#define IWL_HOST_INT_CALIB_TIMEOUT_DEF (0x10)
+#define IWL_HOST_INT_CALIB_TIMEOUT_MIN (0x0)
+
#endif /* !__iwl_csr_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index f9a407e40aff..69a77e24d229 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -29,50 +29,51 @@
#ifndef __iwl_debug_h__
#define __iwl_debug_h__
+#include "iwl-bus.h"
+#include "iwl-shared.h"
+
struct iwl_priv;
-extern u32 iwl_debug_level;
-#define IWL_ERR(p, f, a...) dev_err(p->bus->dev, f, ## a)
-#define IWL_WARN(p, f, a...) dev_warn(p->bus->dev, f, ## a)
-#define IWL_INFO(p, f, a...) dev_info(p->bus->dev, f, ## a)
-#define IWL_CRIT(p, f, a...) dev_crit(p->bus->dev, f, ## a)
+/*No matter what is m (priv, bus, trans), this will work */
+#define IWL_ERR(m, f, a...) dev_err(bus(m)->dev, f, ## a)
+#define IWL_WARN(m, f, a...) dev_warn(bus(m)->dev, f, ## a)
+#define IWL_INFO(m, f, a...) dev_info(bus(m)->dev, f, ## a)
+#define IWL_CRIT(m, f, a...) dev_crit(bus(m)->dev, f, ## a)
-#define iwl_print_hex_error(priv, p, len) \
+#define iwl_print_hex_error(m, p, len) \
do { \
print_hex_dump(KERN_ERR, "iwl data: ", \
DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \
} while (0)
#ifdef CONFIG_IWLWIFI_DEBUG
-#define IWL_DEBUG(__priv, level, fmt, args...) \
+#define IWL_DEBUG(m, level, fmt, args...) \
do { \
- if (iwl_get_debug_level(__priv) & (level)) \
- dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \
+ if (iwl_get_debug_level((m)->shrd) & (level)) \
+ dev_printk(KERN_ERR, bus(m)->dev, \
"%c %s " fmt, in_interrupt() ? 'I' : 'U', \
__func__ , ## args); \
} while (0)
-#define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) \
+#define IWL_DEBUG_LIMIT(m, level, fmt, args...) \
do { \
- if ((iwl_get_debug_level(__priv) & (level)) && net_ratelimit()) \
- dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \
+ if (iwl_get_debug_level((m)->shrd) & (level) && net_ratelimit())\
+ dev_printk(KERN_ERR, bus(m)->dev, \
"%c %s " fmt, in_interrupt() ? 'I' : 'U', \
__func__ , ## args); \
} while (0)
-#define iwl_print_hex_dump(priv, level, p, len) \
+#define iwl_print_hex_dump(m, level, p, len) \
do { \
- if (iwl_get_debug_level(priv) & level) \
+ if (iwl_get_debug_level((m)->shrd) & level) \
print_hex_dump(KERN_DEBUG, "iwl data: ", \
DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \
} while (0)
#else
-#define IWL_DEBUG(__priv, level, fmt, args...)
-#define IWL_DEBUG_LIMIT(__priv, level, fmt, args...)
-static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level,
- const void *p, u32 len)
-{}
+#define IWL_DEBUG(m, level, fmt, args...)
+#define IWL_DEBUG_LIMIT(m, level, fmt, args...)
+#define iwl_print_hex_dump(m, level, p, len)
#endif /* CONFIG_IWLWIFI_DEBUG */
#ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -104,10 +105,12 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
*
* The active debug levels can be accessed via files
*
- * /sys/module/iwlagn/parameters/debug{50}
- * /sys/class/net/wlan0/device/debug_level
- *
+ * /sys/module/iwlwifi/parameters/debug
* when CONFIG_IWLWIFI_DEBUG=y.
+ *
+ * /sys/kernel/debug/phy0/iwlwifi/debug/debug_level
+ * when CONFIG_IWLWIFI_DEBUGFS=y.
+ *
*/
/* 0x0000000F - 0x00000001 */
@@ -166,6 +169,7 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
#define IWL_DEBUG_CALIB(p, f, a...) IWL_DEBUG(p, IWL_DL_CALIB, f, ## a)
#define IWL_DEBUG_FW(p, f, a...) IWL_DEBUG(p, IWL_DL_FW, f, ## a)
#define IWL_DEBUG_RF_KILL(p, f, a...) IWL_DEBUG(p, IWL_DL_RF_KILL, f, ## a)
+#define IWL_DEBUG_FW_ERRORS(p, f, a...) IWL_DEBUG(p, IWL_DL_FW_ERRORS, f, ## a)
#define IWL_DEBUG_DROP(p, f, a...) IWL_DEBUG(p, IWL_DL_DROP, f, ## a)
#define IWL_DEBUG_DROP_LIMIT(p, f, a...) \
IWL_DEBUG_LIMIT(p, IWL_DL_DROP, f, ## a)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index ec1485b2d3fe..a1670e3f8bfa 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -64,6 +64,14 @@
goto err; \
} while (0)
+#define DEBUGFS_ADD_U32(name, parent, ptr, mode) do { \
+ struct dentry *__tmp; \
+ __tmp = debugfs_create_u32(#name, mode, \
+ parent, ptr); \
+ if (IS_ERR(__tmp) || !__tmp) \
+ goto err; \
+} while (0)
+
/* file operation */
#define DEBUGFS_READ_FUNC(name) \
static ssize_t iwl_dbgfs_##name##_read(struct file *file, \
@@ -254,7 +262,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
sram = priv->dbgfs_sram_offset & ~0x3;
/* read the first u32 from sram */
- val = iwl_read_targ_mem(priv, sram);
+ val = iwl_read_targ_mem(bus(priv), sram);
for (; len; len--) {
/* put the address at the start of every line */
@@ -273,7 +281,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
if (++offset == 4) {
sram += 4;
offset = 0;
- val = iwl_read_targ_mem(priv, sram);
+ val = iwl_read_targ_mem(bus(priv), sram);
}
/* put in extra spaces and split lines for human readability */
@@ -340,7 +348,7 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
{
struct iwl_priv *priv = file->private_data;
struct iwl_station_entry *station;
- int max_sta = priv->hw_params.max_stations;
+ struct iwl_tid_data *tid_data;
char *buf;
int i, j, pos = 0;
ssize_t ret;
@@ -354,7 +362,7 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
pos += scnprintf(buf + pos, bufsz - pos, "num of stations: %d\n\n",
priv->num_stations);
- for (i = 0; i < max_sta; i++) {
+ for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
station = &priv->stations[i];
if (!station->used)
continue;
@@ -363,22 +371,18 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
i, station->sta.sta.addr,
station->sta.station_flags_msk);
pos += scnprintf(buf + pos, bufsz - pos,
- "TID\tseq_num\ttxq_id\tframes\ttfds\t");
- pos += scnprintf(buf + pos, bufsz - pos,
- "start_idx\tbitmap\t\t\trate_n_flags\n");
+ "TID\tseq_num\ttxq_id\ttfds\trate_n_flags\n");
- for (j = 0; j < MAX_TID_COUNT; j++) {
+ for (j = 0; j < IWL_MAX_TID_COUNT; j++) {
+ tid_data = &priv->shrd->tid_data[i][j];
pos += scnprintf(buf + pos, bufsz - pos,
- "%d:\t%#x\t%#x\t%u\t%u\t%u\t\t%#.16llx\t%#x",
- j, station->tid[j].seq_number,
- station->tid[j].agg.txq_id,
- station->tid[j].agg.frame_count,
- station->tid[j].tfds_in_queue,
- station->tid[j].agg.start_idx,
- station->tid[j].agg.bitmap,
- station->tid[j].agg.rate_n_flags);
-
- if (station->tid[j].agg.wait_for_ba)
+ "%d:\t%#x\t%#x\t%u\t%#x",
+ j, tid_data->seq_number,
+ tid_data->agg.txq_id,
+ tid_data->tfds_in_queue,
+ tid_data->agg.rate_n_flags);
+
+ if (tid_data->agg.wait_for_ba)
pos += scnprintf(buf + pos, bufsz - pos,
" - waitforba");
pos += scnprintf(buf + pos, bufsz - pos, "\n");
@@ -442,46 +446,6 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
return ret;
}
-static ssize_t iwl_dbgfs_log_event_read(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct iwl_priv *priv = file->private_data;
- char *buf;
- int pos = 0;
- ssize_t ret = -ENOMEM;
-
- ret = pos = iwl_dump_nic_event_log(priv, true, &buf, true);
- if (buf) {
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
- kfree(buf);
- }
- return ret;
-}
-
-static ssize_t iwl_dbgfs_log_event_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct iwl_priv *priv = file->private_data;
- u32 event_log_flag;
- char buf[8];
- int buf_size;
-
- 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", &event_log_flag) != 1)
- return -EFAULT;
- if (event_log_flag == 1)
- iwl_dump_nic_event_log(priv, true, NULL, false);
-
- return count;
-}
-
-
-
static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@@ -492,7 +456,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->status))
+ if (!test_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status))
return -EAGAIN;
buf = kzalloc(bufsz, GFP_KERNEL);
@@ -562,45 +526,46 @@ static ssize_t iwl_dbgfs_status_read(struct file *file,
const size_t bufsz = sizeof(buf);
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_ACTIVE:\t %d\n",
- test_bit(STATUS_HCMD_ACTIVE, &priv->status));
+ 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->status));
+ 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->status));
+ test_bit(STATUS_RF_KILL_HW, &priv->shrd->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_CT_KILL:\t\t %d\n",
- test_bit(STATUS_CT_KILL, &priv->status));
+ 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->status));
+ test_bit(STATUS_INIT, &priv->shrd->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n",
- test_bit(STATUS_ALIVE, &priv->status));
+ test_bit(STATUS_ALIVE, &priv->shrd->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_READY:\t\t %d\n",
- test_bit(STATUS_READY, &priv->status));
+ test_bit(STATUS_READY, &priv->shrd->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_TEMPERATURE:\t %d\n",
- test_bit(STATUS_TEMPERATURE, &priv->status));
+ test_bit(STATUS_TEMPERATURE, &priv->shrd->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_GEO_CONFIGURED:\t %d\n",
- test_bit(STATUS_GEO_CONFIGURED, &priv->status));
+ test_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_EXIT_PENDING:\t %d\n",
- test_bit(STATUS_EXIT_PENDING, &priv->status));
+ test_bit(STATUS_EXIT_PENDING, &priv->shrd->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_STATISTICS:\t %d\n",
- test_bit(STATUS_STATISTICS, &priv->status));
+ test_bit(STATUS_STATISTICS, &priv->shrd->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCANNING:\t %d\n",
- test_bit(STATUS_SCANNING, &priv->status));
+ test_bit(STATUS_SCANNING, &priv->shrd->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_ABORTING:\t %d\n",
- test_bit(STATUS_SCAN_ABORTING, &priv->status));
+ test_bit(STATUS_SCAN_ABORTING, &priv->shrd->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_HW:\t\t %d\n",
- test_bit(STATUS_SCAN_HW, &priv->status));
+ test_bit(STATUS_SCAN_HW, &priv->shrd->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_POWER_PMI:\t %d\n",
- test_bit(STATUS_POWER_PMI, &priv->status));
+ test_bit(STATUS_POWER_PMI, &priv->shrd->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_FW_ERROR:\t %d\n",
- test_bit(STATUS_FW_ERROR, &priv->status));
+ test_bit(STATUS_FW_ERROR, &priv->shrd->status));
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
-static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
+static ssize_t iwl_dbgfs_rx_handlers_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos) {
struct iwl_priv *priv = file->private_data;
+
int pos = 0;
int cnt = 0;
char *buf;
@@ -613,61 +578,25 @@ static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
return -ENOMEM;
}
- pos += scnprintf(buf + pos, bufsz - pos,
- "Interrupt Statistics Report:\n");
-
- pos += scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n",
- priv->isr_stats.hw);
- pos += scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n",
- priv->isr_stats.sw);
- if (priv->isr_stats.sw || priv->isr_stats.hw) {
- pos += scnprintf(buf + pos, bufsz - pos,
- "\tLast Restarting Code: 0x%X\n",
- priv->isr_stats.err_code);
- }
-#ifdef CONFIG_IWLWIFI_DEBUG
- pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n",
- priv->isr_stats.sch);
- pos += scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n",
- priv->isr_stats.alive);
-#endif
- pos += scnprintf(buf + pos, bufsz - pos,
- "HW RF KILL switch toggled:\t %u\n",
- priv->isr_stats.rfkill);
-
- pos += scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n",
- priv->isr_stats.ctkill);
-
- pos += scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n",
- priv->isr_stats.wakeup);
-
- pos += scnprintf(buf + pos, bufsz - pos,
- "Rx command responses:\t\t %u\n",
- priv->isr_stats.rx);
for (cnt = 0; cnt < REPLY_MAX; cnt++) {
- if (priv->isr_stats.rx_handlers[cnt] > 0)
+ if (priv->rx_handlers_stats[cnt] > 0)
pos += scnprintf(buf + pos, bufsz - pos,
"\tRx handler[%36s]:\t\t %u\n",
get_cmd_string(cnt),
- priv->isr_stats.rx_handlers[cnt]);
+ priv->rx_handlers_stats[cnt]);
}
- pos += scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n",
- priv->isr_stats.tx);
-
- pos += scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n",
- priv->isr_stats.unhandled);
-
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
kfree(buf);
return ret;
}
-static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
+static ssize_t iwl_dbgfs_rx_handlers_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct iwl_priv *priv = file->private_data;
+
char buf[8];
int buf_size;
u32 reset_flag;
@@ -679,7 +608,8 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
if (sscanf(buf, "%x", &reset_flag) != 1)
return -EFAULT;
if (reset_flag == 0)
- iwl_clear_isr_stats(priv);
+ memset(&priv->rx_handlers_stats[0], 0,
+ sizeof(priv->rx_handlers_stats));
return count;
}
@@ -784,6 +714,20 @@ static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file,
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
+static ssize_t iwl_dbgfs_temperature_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = file->private_data;
+ char buf[8];
+ int pos = 0;
+ const size_t bufsz = sizeof(buf);
+
+ pos += scnprintf(buf + pos, bufsz - pos, "%d\n", priv->temperature);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+
static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
@@ -814,14 +758,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))
+ if (!iwl_is_ready_rf(priv->shrd))
return -EAGAIN;
priv->power_data.debug_sleep_level_override = value;
- mutex_lock(&priv->mutex);
+ mutex_lock(&priv->shrd->mutex);
iwl_power_update_mode(priv, true);
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
return count;
}
@@ -870,15 +814,15 @@ static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file,
DEBUGFS_READ_WRITE_FILE_OPS(sram);
DEBUGFS_READ_FILE_OPS(wowlan_sram);
-DEBUGFS_READ_WRITE_FILE_OPS(log_event);
DEBUGFS_READ_FILE_OPS(nvm);
DEBUGFS_READ_FILE_OPS(stations);
DEBUGFS_READ_FILE_OPS(channels);
DEBUGFS_READ_FILE_OPS(status);
-DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
+DEBUGFS_READ_WRITE_FILE_OPS(rx_handlers);
DEBUGFS_READ_FILE_OPS(qos);
DEBUGFS_READ_FILE_OPS(thermal_throttling);
DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
+DEBUGFS_READ_FILE_OPS(temperature);
DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override);
DEBUGFS_READ_FILE_OPS(current_sleep_command);
@@ -889,36 +833,23 @@ static ssize_t iwl_dbgfs_traffic_log_read(struct file *file,
struct iwl_priv *priv = file->private_data;
int pos = 0, ofs = 0;
int cnt = 0, entry;
- struct iwl_tx_queue *txq;
- struct iwl_queue *q;
- struct iwl_rx_queue *rxq = &priv->rxq;
+
char *buf;
int bufsz = ((IWL_TRAFFIC_ENTRIES * IWL_TRAFFIC_ENTRY_SIZE * 64) * 2) +
- (priv->cfg->base_params->num_of_queues * 32 * 8) + 400;
+ (hw_params(priv).max_txq_num * 32 * 8) + 400;
const u8 *ptr;
ssize_t ret;
- if (!priv->txq) {
- IWL_ERR(priv, "txq not ready\n");
- return -EAGAIN;
- }
buf = kzalloc(bufsz, GFP_KERNEL);
if (!buf) {
IWL_ERR(priv, "Can not allocate buffer\n");
return -ENOMEM;
}
- pos += scnprintf(buf + pos, bufsz - pos, "Tx Queue\n");
- for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
- txq = &priv->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 (priv->tx_traffic && (iwl_debug_level & IWL_DL_TX)) {
+ if (priv->tx_traffic &&
+ (iwl_get_debug_level(priv->shrd) & IWL_DL_TX)) {
ptr = priv->tx_traffic;
pos += scnprintf(buf + pos, bufsz - pos,
- "Tx Traffic idx: %u\n", priv->tx_traffic_idx);
+ "Tx Traffic idx: %u\n", priv->tx_traffic_idx);
for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) {
for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16;
entry++, ofs += 16) {
@@ -933,15 +864,11 @@ static ssize_t iwl_dbgfs_traffic_log_read(struct file *file,
}
}
- 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 (priv->rx_traffic && (iwl_debug_level & IWL_DL_RX)) {
+ if (priv->rx_traffic &&
+ (iwl_get_debug_level(priv->shrd) & IWL_DL_RX)) {
ptr = priv->rx_traffic;
pos += scnprintf(buf + pos, bufsz - pos,
- "Rx Traffic idx: %u\n", priv->rx_traffic_idx);
+ "Rx Traffic idx: %u\n", priv->rx_traffic_idx);
for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) {
for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16;
entry++, ofs += 16) {
@@ -982,76 +909,6 @@ static ssize_t iwl_dbgfs_traffic_log_write(struct file *file,
return count;
}
-static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos) {
-
- struct iwl_priv *priv = file->private_data;
- struct iwl_tx_queue *txq;
- struct iwl_queue *q;
- char *buf;
- int pos = 0;
- int cnt;
- int ret;
- const size_t bufsz = sizeof(char) * 64 *
- priv->cfg->base_params->num_of_queues;
-
- if (!priv->txq) {
- IWL_ERR(priv, "txq not ready\n");
- return -EAGAIN;
- }
- buf = kzalloc(bufsz, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
- txq = &priv->txq[cnt];
- q = &txq->q;
- pos += scnprintf(buf + pos, bufsz - pos,
- "hwq %.2d: read=%u write=%u stop=%d"
- " swq_id=%#.2x (ac %d/hwq %d)\n",
- cnt, q->read_ptr, q->write_ptr,
- !!test_bit(cnt, priv->queue_stopped),
- txq->swq_id, txq->swq_id & 3,
- (txq->swq_id >> 2) & 0x1f);
- if (cnt >= 4)
- continue;
- /* for the ACs, display the stop count too */
- pos += scnprintf(buf + pos, bufsz - pos,
- " stop-count: %d\n",
- atomic_read(&priv->queue_stop_count[cnt]));
- }
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
- kfree(buf);
- return ret;
-}
-
-static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos) {
-
- struct iwl_priv *priv = file->private_data;
- struct iwl_rx_queue *rxq = &priv->rxq;
- char buf[256];
- int pos = 0;
- const size_t bufsz = sizeof(buf);
-
- pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n",
- rxq->read);
- pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n",
- rxq->write);
- pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
- rxq->free_count);
- if (rxq->rb_stts) {
- pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n",
- le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF);
- } else {
- pos += scnprintf(buf + pos, bufsz - pos,
- "closed_rb_num: Not Allocated\n");
- }
- return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
static const char *fmt_value = " %-30s %10u\n";
static const char *fmt_hex = " %-30s 0x%02X\n";
static const char *fmt_table = " %-30s %10u %10u %10u %10u\n";
@@ -1096,7 +953,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))
+ if (!iwl_is_alive(priv->shrd))
return -EAGAIN;
buf = kzalloc(bufsz, GFP_KERNEL);
@@ -1522,7 +1379,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))
+ if (!iwl_is_alive(priv->shrd))
return -EAGAIN;
buf = kzalloc(bufsz, GFP_KERNEL);
@@ -1716,7 +1573,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))
+ if (!iwl_is_alive(priv->shrd))
return -EAGAIN;
buf = kzalloc(bufsz, GFP_KERNEL);
@@ -1829,16 +1686,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))
+ if (!iwl_is_alive(priv->shrd))
return -EAGAIN;
if (!priv->bt_enable_flag)
return -EINVAL;
/* make request to uCode to retrieve statistics information */
- mutex_lock(&priv->mutex);
+ mutex_lock(&priv->shrd->mutex);
ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
if (ret) {
IWL_ERR(priv,
@@ -1917,7 +1774,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))
+ if (!iwl_is_alive(priv->shrd))
return -EAGAIN;
buf = kzalloc(bufsz, GFP_KERNEL);
@@ -2199,7 +2056,7 @@ static ssize_t iwl_dbgfs_power_save_status_read(struct file *file,
const size_t bufsz = sizeof(buf);
u32 pwrsave_status;
- pwrsave_status = iwl_read32(priv, CSR_GP_CNTRL) &
+ pwrsave_status = iwl_read32(bus(priv), CSR_GP_CNTRL) &
CSR_GP_REG_POWER_SAVE_STATUS_MSK;
pos += scnprintf(buf + pos, bufsz - pos, "Power Save Status: ");
@@ -2229,30 +2086,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->mutex);
+ mutex_lock(&priv->shrd->mutex);
iwl_send_statistics_request(priv, CMD_SYNC, true);
- mutex_unlock(&priv->mutex);
-
- return count;
-}
-
-static ssize_t iwl_dbgfs_csr_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct iwl_priv *priv = file->private_data;
- char buf[8];
- int buf_size;
- int csr;
-
- 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", &csr) != 1)
- return -EFAULT;
-
- iwl_dump_csr(priv);
+ mutex_unlock(&priv->shrd->mutex);
return count;
}
@@ -2333,25 +2169,6 @@ static ssize_t iwl_dbgfs_rxon_filter_flags_read(struct file *file,
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
-static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct iwl_priv *priv = file->private_data;
- char *buf;
- int pos = 0;
- ssize_t ret = -EFAULT;
-
- ret = pos = iwl_dump_fh(priv, &buf, true);
- if (buf) {
- ret = simple_read_from_buffer(user_buf,
- count, ppos, buf, pos);
- kfree(buf);
- }
-
- return ret;
-}
-
static ssize_t iwl_dbgfs_missed_beacon_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos) {
@@ -2434,8 +2251,8 @@ static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file,
static ssize_t iwl_dbgfs_force_reset_read(struct file *file,
char __user *user_buf,
- size_t count, loff_t *ppos) {
-
+ size_t count, loff_t *ppos)
+{
struct iwl_priv *priv = file->private_data;
int i, pos = 0;
char buf[300];
@@ -2504,7 +2321,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))
+ if (iwl_is_rfkill(priv->shrd))
return -EFAULT;
iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
@@ -2514,8 +2331,8 @@ static ssize_t iwl_dbgfs_txfifo_flush_write(struct file *file,
static ssize_t iwl_dbgfs_wd_timeout_write(struct file *file,
const char __user *user_buf,
- size_t count, loff_t *ppos) {
-
+ size_t count, loff_t *ppos)
+{
struct iwl_priv *priv = file->private_data;
char buf[8];
int buf_size;
@@ -2626,11 +2443,26 @@ static ssize_t iwl_dbgfs_protection_mode_write(struct file *file,
return count;
}
+static ssize_t iwl_dbgfs_echo_test_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = file->private_data;
+ char buf[8];
+ int buf_size;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+
+ iwl_cmd_echo_test(priv);
+ return count;
+}
+
DEBUGFS_READ_FILE_OPS(rx_statistics);
DEBUGFS_READ_FILE_OPS(tx_statistics);
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);
DEBUGFS_READ_FILE_OPS(ucode_tx_stats);
DEBUGFS_READ_FILE_OPS(ucode_general_stats);
@@ -2639,9 +2471,7 @@ DEBUGFS_READ_FILE_OPS(chain_noise);
DEBUGFS_READ_FILE_OPS(power_save_status);
DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics);
DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics);
-DEBUGFS_WRITE_FILE_OPS(csr);
DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing);
-DEBUGFS_READ_FILE_OPS(fh_reg);
DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta);
DEBUGFS_READ_WRITE_FILE_OPS(force_reset);
@@ -2653,6 +2483,53 @@ DEBUGFS_WRITE_FILE_OPS(wd_timeout);
DEBUGFS_READ_FILE_OPS(bt_traffic);
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
@@ -2682,26 +2559,23 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR);
DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR);
DEBUGFS_ADD_FILE(wowlan_sram, dir_data, S_IRUSR);
- DEBUGFS_ADD_FILE(log_event, dir_data, S_IWUSR | S_IRUSR);
DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR);
DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR);
DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR);
- DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR);
+ DEBUGFS_ADD_FILE(rx_handlers, dir_data, S_IWUSR | S_IRUSR);
DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR);
DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR);
DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
+ DEBUGFS_ADD_FILE(temperature, dir_data, S_IRUSR);
+
DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR);
DEBUGFS_ADD_FILE(tx_statistics, 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);
DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(clear_traffic_statistics, dir_debug, S_IWUSR);
- DEBUGFS_ADD_FILE(csr, dir_debug, S_IWUSR);
- DEBUGFS_ADD_FILE(fh_reg, dir_debug, S_IRUSR);
DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(plcp_delta, dir_debug, S_IWUSR | S_IRUSR);
DEBUGFS_ADD_FILE(force_reset, dir_debug, S_IWUSR | S_IRUSR);
@@ -2710,7 +2584,6 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(protection_mode, dir_debug, S_IWUSR | S_IRUSR);
-
DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
@@ -2719,12 +2592,20 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR);
+ 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);
DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
&priv->disable_chain_noise_cal);
+
+ if (iwl_trans_dbgfs_register(trans(priv), dir_debug))
+ goto err;
return 0;
err:
@@ -2745,6 +2626,3 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
debugfs_remove_recursive(priv->debugfs_dir);
priv->debugfs_dir = NULL;
}
-
-
-
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 6c9790cac8d0..6c00a447963d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -32,16 +32,15 @@
#define __iwl_dev_h__
#include <linux/interrupt.h>
-#include <linux/pci.h> /* for struct pci_device_id */
#include <linux/kernel.h>
#include <linux/wait.h>
#include <linux/leds.h>
+#include <linux/slab.h>
#include <net/ieee80211_radiotap.h>
#include "iwl-eeprom.h"
#include "iwl-csr.h"
#include "iwl-prph.h"
-#include "iwl-fh.h"
#include "iwl-debug.h"
#include "iwl-agn-hw.h"
#include "iwl-led.h"
@@ -50,8 +49,7 @@
#include "iwl-agn-tt.h"
#include "iwl-bus.h"
#include "iwl-trans.h"
-
-#define DRV_NAME "iwlagn"
+#include "iwl-shared.h"
struct iwl_tx_queue;
@@ -90,109 +88,6 @@ struct iwl_tx_queue;
#define DEFAULT_SHORT_RETRY_LIMIT 7U
#define DEFAULT_LONG_RETRY_LIMIT 4U
-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)
-
-/* defined below */
-struct iwl_device_cmd;
-
-struct iwl_cmd_meta {
- /* only for SYNC commands, iff the reply skb is wanted */
- struct iwl_host_cmd *source;
- /*
- * only for ASYNC commands
- * (which is somewhat stupid -- look at iwl-sta.c for instance
- * which duplicates a bunch of code because the callback isn't
- * invoked for SYNC commands, if it were and its result passed
- * through it would be simpler...)
- */
- void (*callback)(struct iwl_priv *priv,
- struct iwl_device_cmd *cmd,
- struct iwl_rx_packet *pkt);
-
- u32 flags;
-
- DEFINE_DMA_UNMAP_ADDR(mapping);
- DEFINE_DMA_UNMAP_LEN(len);
-};
-
-/*
- * Generic queue structure
- *
- * Contains common data for Rx and Tx queues.
- *
- * Note the difference between n_bd and n_window: the hardware
- * always assumes 256 descriptors, so n_bd is always 256 (unless
- * there might be HW changes in the future). For the normal TX
- * queues, n_window, which is the size of the software queue data
- * is also 256; however, for the command queue, n_window is only
- * 32 since we don't need so many commands pending. Since the HW
- * still uses 256 BDs for DMA though, n_bd stays 256. As a result,
- * the software buffers (in the variables @meta, @txb in struct
- * iwl_tx_queue) only have 32 entries, while the HW buffers (@tfds
- * in the same struct) have 256.
- * This means that we end up with the following:
- * HW entries: | 0 | ... | N * 32 | ... | N * 32 + 31 | ... | 255 |
- * SW entries: | 0 | ... | 31 |
- * where N is a number between 0 and 7. This means that the SW
- * data is a window overlayed over the HW queue.
- */
-struct iwl_queue {
- int n_bd; /* number of BDs in this queue */
- int write_ptr; /* 1-st empty entry (index) host_w*/
- int read_ptr; /* last used entry (index) host_r*/
- /* use for monitoring and recovering the stuck queue */
- dma_addr_t dma_addr; /* physical addr for BD's */
- int n_window; /* safe queue window */
- u32 id;
- int low_mark; /* low watermark, resume queue if free
- * space more than this */
- int high_mark; /* high watermark, stop queue if free
- * space less than this */
-};
-
-/* One for each TFD */
-struct iwl_tx_info {
- struct sk_buff *skb;
- struct iwl_rxon_context *ctx;
-};
-
-/**
- * struct iwl_tx_queue - Tx Queue for DMA
- * @q: generic Rx/Tx queue descriptor
- * @bd: base of circular buffer of TFDs
- * @cmd: array of command/TX buffer pointers
- * @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
- * @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
- *
- * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame
- * descriptors) and required locking structures.
- */
-#define TFD_TX_CMD_SLOTS 256
-#define TFD_CMD_SLOTS 32
-
-struct iwl_tx_queue {
- struct iwl_queue q;
- struct iwl_tfd *tfds;
- struct iwl_device_cmd **cmd;
- struct iwl_cmd_meta *meta;
- struct iwl_tx_info *txb;
- unsigned long time_stamp;
- u8 need_update;
- u8 sched_retry;
- u8 active;
- u8 swq_id;
-};
-
#define IWL_NUM_SCAN_RATES (2)
/*
@@ -222,20 +117,16 @@ struct iwl_channel_info {
u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */
};
-#define IWL_TX_FIFO_BK 0 /* shared */
-#define IWL_TX_FIFO_BE 1
-#define IWL_TX_FIFO_VI 2 /* shared */
-#define IWL_TX_FIFO_VO 3
-#define IWL_TX_FIFO_BK_IPAN IWL_TX_FIFO_BK
-#define IWL_TX_FIFO_BE_IPAN 4
-#define IWL_TX_FIFO_VI_IPAN IWL_TX_FIFO_VI
-#define IWL_TX_FIFO_VO_IPAN 5
-#define IWL_TX_FIFO_UNUSED -1
-
-/* Minimum number of queues. MAX_NUM is defined in hw specific files.
- * Set the minimum to accommodate the 4 standard TX queues, 1 command
- * queue, 2 (unused) HCCA queues, and 4 HT queues (one for each AC) */
-#define IWL_MIN_NUM_QUEUES 10
+/*
+ * Minimum number of queues. MAX_NUM is defined in hw specific files.
+ * Set the minimum to accommodate
+ * - 4 standard TX queues
+ * - the command queue
+ * - 4 PAN TX queues
+ * - the PAN multicast queue, and
+ * - the AUX (TX during scan dwell) queue.
+ */
+#define IWL_MIN_NUM_QUEUES 11
/*
* Command queue depends on iPAN support.
@@ -243,161 +134,20 @@ struct iwl_channel_info {
#define IWL_DEFAULT_CMD_QUEUE_NUM 4
#define IWL_IPAN_CMD_QUEUE_NUM 9
-/*
- * This queue number is required for proper operation
- * because the ucode will stop/start the scheduler as
- * required.
- */
-#define IWL_IPAN_MCAST_QUEUE 8
-
#define IEEE80211_DATA_LEN 2304
#define IEEE80211_4ADDR_LEN 30
#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN)
#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN)
-
-#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)
-
-enum {
- CMD_SYNC = 0,
- CMD_ASYNC = BIT(0),
- CMD_WANT_SKB = BIT(1),
- CMD_ON_DEMAND = BIT(2),
-};
-
-#define DEF_CMD_PAYLOAD_SIZE 320
-
-/**
- * struct iwl_device_cmd
- *
- * For allocation of the command and tx queues, this establishes the overall
- * size of the largest command we send to uCode, except for commands that
- * aren't fully copied and use other TFD space.
- */
-struct iwl_device_cmd {
- struct iwl_cmd_header hdr; /* uCode API */
- union {
- u32 flags;
- u8 val8;
- u16 val16;
- u32 val32;
- struct iwl_tx_cmd tx;
- struct iwl6000_channel_switch_cmd chswitch;
- u8 payload[DEF_CMD_PAYLOAD_SIZE];
- } __packed cmd;
-} __packed;
-
-#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd))
-
-#define IWL_MAX_CMD_TFDS 2
-
-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
- * @callback:
- * @flags: can be CMD_* note CMD_WANT_SKB is incompatible withe CMD_ASYNC
- * @len: array of the lenths of the chunks in data
- * @dataflags:
- * @id: id of the host command
- */
-struct iwl_host_cmd {
- const void *data[IWL_MAX_CMD_TFDS];
- unsigned long reply_page;
- void (*callback)(struct iwl_priv *priv,
- struct iwl_device_cmd *cmd,
- struct iwl_rx_packet *pkt);
- u32 flags;
- u16 len[IWL_MAX_CMD_TFDS];
- u8 dataflags[IWL_MAX_CMD_TFDS];
- u8 id;
-};
-
#define SUP_RATE_11A_MAX_NUM_CHANNELS 8
#define SUP_RATE_11B_MAX_NUM_CHANNELS 4
#define SUP_RATE_11G_MAX_NUM_CHANNELS 12
-/**
- * struct iwl_rx_queue - Rx queue
- * @bd: driver's pointer to buffer of receive buffer descriptors (rbd)
- * @bd_dma: bus address of buffer of receive buffer descriptors (rbd)
- * @read: Shared index to newest available Rx buffer
- * @write: Shared index to oldest written Rx packet
- * @free_count: Number of pre-allocated buffers in rx_free
- * @rx_free: list of free SKBs for use
- * @rx_used: List of Rx buffers with no SKB
- * @need_update: flag to indicate we need to update read/write index
- * @rb_stts: driver's pointer to receive buffer status
- * @rb_stts_dma: bus address of receive buffer status
- *
- * NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers
- */
-struct iwl_rx_queue {
- __le32 *bd;
- dma_addr_t bd_dma;
- struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
- struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
- u32 read;
- u32 write;
- u32 free_count;
- u32 write_actual;
- struct list_head rx_free;
- struct list_head rx_used;
- int need_update;
- struct iwl_rb_status *rb_stts;
- dma_addr_t rb_stts_dma;
- spinlock_t lock;
-};
-
#define IWL_SUPPORTED_RATES_IE_LEN 8
-#define MAX_TID_COUNT 9
-
#define IWL_INVALID_RATE 0xFF
#define IWL_INVALID_VALUE -1
-/**
- * struct iwl_ht_agg -- aggregation status while waiting for block-ack
- * @txq_id: Tx queue used for Tx attempt
- * @frame_count: # frames attempted by Tx command
- * @wait_for_ba: Expect block-ack before next Tx reply
- * @start_idx: Index of 1st Transmit Frame Descriptor (TFD) in Tx window
- * @bitmap0: Low order bitmap, one bit for each frame pending ACK in Tx window
- * @bitmap1: High order, one bit for each frame pending ACK in Tx window
- * @rate_n_flags: Rate at which Tx was attempted
- *
- * If REPLY_TX indicates that aggregation was attempted, driver must wait
- * for block ack (REPLY_COMPRESSED_BA). This struct stores tx reply info
- * until block ack arrives.
- */
-struct iwl_ht_agg {
- u16 txq_id;
- u16 frame_count;
- u16 wait_for_ba;
- u16 start_idx;
- u64 bitmap;
- u32 rate_n_flags;
-#define IWL_AGG_OFF 0
-#define IWL_AGG_ON 1
-#define IWL_EMPTYING_HW_QUEUE_ADDBA 2
-#define IWL_EMPTYING_HW_QUEUE_DELBA 3
- u8 state;
- u8 tx_fifo;
-};
-
-
-struct iwl_tid_data {
- u16 seq_number; /* agn only */
- u16 tfds_in_queue;
- struct iwl_ht_agg agg;
-};
-
union iwl_ht_rate_supp {
u16 rates;
struct {
@@ -448,16 +198,10 @@ struct iwl_qos_info {
*/
struct iwl_station_entry {
struct iwl_addsta_cmd sta;
- struct iwl_tid_data tid[MAX_TID_COUNT];
u8 used, ctxid;
struct iwl_link_quality_cmd *lq;
};
-struct iwl_station_priv_common {
- struct iwl_rxon_context *ctx;
- u8 sta_id;
-};
-
/*
* iwl_station_priv: Driver's private station information
*
@@ -466,12 +210,13 @@ struct iwl_station_priv_common {
* space.
*/
struct iwl_station_priv {
- struct iwl_station_priv_common common;
+ struct iwl_rxon_context *ctx;
struct iwl_lq_sta lq_sta;
atomic_t pending_frames;
bool client;
bool asleep;
u8 max_agg_bufsize;
+ u8 sta_id;
};
/**
@@ -564,11 +309,13 @@ enum iwl_ucode_tlv_type {
* @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 {
@@ -634,54 +381,6 @@ struct iwl_sensitivity_ranges {
#define CELSIUS_TO_KELVIN(x) ((x)+273)
-/**
- * struct iwl_hw_params
- * @max_txq_num: Max # Tx queues supported
- * @scd_bc_tbls_size: size of scheduler byte count tables
- * @tfd_size: TFD size
- * @tx/rx_chains_num: Number of TX/RX chains
- * @valid_tx/rx_ant: usable antennas
- * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2)
- * @max_rxq_log: Log-base-2 of max_rxq_size
- * @rx_page_order: Rx buffer page order
- * @rx_wrt_ptr_reg: FH{39}_RSCSR_CHNL0_WPTR
- * @max_stations:
- * @ht40_channel: is 40MHz width possible in band 2.4
- * BIT(IEEE80211_BAND_5GHZ) BIT(IEEE80211_BAND_5GHZ)
- * @sw_crypto: 0 for hw, 1 for sw
- * @max_xxx_size: for ucode uses
- * @ct_kill_threshold: temperature threshold
- * @beacon_time_tsf_bits: number of valid tsf bits for beacon time
- * @calib_init_cfg: setup initial calibrations for the hw
- * @calib_rt_cfg: setup runtime calibrations for the hw
- * @struct iwl_sensitivity_ranges: range of sensitivity values
- */
-struct iwl_hw_params {
- u8 max_txq_num;
- u16 scd_bc_tbls_size;
- u32 tfd_size;
- u8 tx_chains_num;
- u8 rx_chains_num;
- u8 valid_tx_ant;
- u8 valid_rx_ant;
- u16 max_rxq_size;
- u16 max_rxq_log;
- u32 rx_page_order;
- u8 max_stations;
- u8 ht40_channel;
- u8 max_beacon_itrvl; /* in 1024 ms */
- u32 max_inst_size;
- u32 max_data_size;
- u32 ct_kill_threshold; /* value in hw-dependent units */
- u32 ct_kill_exit_threshold; /* value in hw-dependent units */
- /* for 1000, 6000 series and up */
- u16 beacon_time_tsf_bits;
- u32 calib_init_cfg;
- u32 calib_rt_cfg;
- const struct iwl_sensitivity_ranges *sens;
-};
-
-
/******************************************************************************
*
* Functions implemented in core module which are forward declared here
@@ -697,35 +396,12 @@ struct iwl_hw_params {
****************************************************************************/
extern void iwl_update_chain_flags(struct iwl_priv *priv);
extern const u8 iwl_bcast_addr[ETH_ALEN];
-extern int iwl_queue_space(const struct iwl_queue *q);
-static inline int iwl_queue_used(const struct iwl_queue *q, int i)
-{
- return q->write_ptr >= q->read_ptr ?
- (i >= q->read_ptr && i < q->write_ptr) :
- !(i < q->read_ptr && i >= q->write_ptr);
-}
-
-
-static inline u8 get_cmd_index(struct iwl_queue *q, u32 index)
-{
- return index & (q->n_window - 1);
-}
-
-
-struct iwl_dma_ptr {
- dma_addr_t dma;
- void *addr;
- size_t size;
-};
#define IWL_OPERATION_MODE_AUTO 0
#define IWL_OPERATION_MODE_HT_ONLY 1
#define IWL_OPERATION_MODE_MIXED 2
#define IWL_OPERATION_MODE_20MHZ 3
-#define IWL_TX_CRC_SIZE 4
-#define IWL_TX_DELIMITER_SIZE 4
-
#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
/* Sensitivity and chain noise calibration */
@@ -849,9 +525,6 @@ struct iwl_chain_noise_data {
#define EEPROM_SEM_TIMEOUT 10 /* milliseconds */
#define EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */
-#define IWL_TRAFFIC_ENTRIES (256)
-#define IWL_TRAFFIC_ENTRY_SIZE (64)
-
enum {
MEASUREMENT_READY = (1 << 0),
MEASUREMENT_ACTIVE = (1 << 1),
@@ -884,22 +557,6 @@ enum iwl_pa_type {
IWL_PA_INTERNAL = 1,
};
-/* interrupt statistics */
-struct isr_statistics {
- u32 hw;
- u32 sw;
- u32 err_code;
- u32 sch;
- u32 alive;
- u32 rfkill;
- u32 ctkill;
- u32 wakeup;
- u32 rx;
- u32 rx_handlers[REPLY_MAX];
- u32 tx;
- u32 unhandled;
-};
-
/* reply_tx_statistics (for _agn devices) */
struct reply_tx_error_statistics {
u32 pp_delay;
@@ -1009,21 +666,6 @@ struct iwl_event_log {
};
/*
- * host interrupt timeout value
- * used with setting interrupt coalescing timer
- * the CSR_INT_COALESCING is an 8 bit register in 32-usec unit
- *
- * default interrupt coalescing timer is 64 x 32 = 2048 usecs
- * default interrupt coalescing calibration timer is 16 x 32 = 512 usecs
- */
-#define IWL_HOST_INT_TIMEOUT_MAX (0xFF)
-#define IWL_HOST_INT_TIMEOUT_DEF (0x40)
-#define IWL_HOST_INT_TIMEOUT_MIN (0x0)
-#define IWL_HOST_INT_CALIB_TIMEOUT_MAX (0xFF)
-#define IWL_HOST_INT_CALIB_TIMEOUT_DEF (0x10)
-#define IWL_HOST_INT_CALIB_TIMEOUT_MIN (0x0)
-
-/*
* This is the threshold value of plcp error rate per 100mSecs. It is
* used to set and check for the validity of plcp_delta.
*/
@@ -1101,20 +743,9 @@ struct iwl_notification_wait {
bool triggered, aborted;
};
-enum iwl_rxon_context_id {
- IWL_RXON_CTX_BSS,
- IWL_RXON_CTX_PAN,
-
- NUM_IWL_RXON_CTX
-};
-
struct iwl_rxon_context {
struct ieee80211_vif *vif;
- const u8 *ac_to_fifo;
- const u8 *ac_to_queue;
- u8 mcast_queue;
-
/*
* We could use the vif to indicate active, but we
* also need it to be active during disabling when
@@ -1162,13 +793,16 @@ struct iwl_rxon_context {
u8 extension_chan_offset;
} ht;
+ u8 bssid[ETH_ALEN];
+ bool preauth_bssid;
+
bool last_tx_rejected;
};
enum iwl_scan_type {
IWL_SCAN_NORMAL,
IWL_SCAN_RADIO_RESET,
- IWL_SCAN_OFFCH_TX,
+ IWL_SCAN_ROC,
};
enum iwlagn_ucode_type {
@@ -1190,24 +824,26 @@ struct iwl_testmode_trace {
};
#endif
-/* uCode ownership */
-#define IWL_OWNERSHIP_DRIVER 0
-#define IWL_OWNERSHIP_TM 1
-
struct iwl_priv {
+ /*data shared among all the driver's layers */
+ struct iwl_shared _shrd;
+ struct iwl_shared *shrd;
+
/* 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 iwl_cfg *cfg;
enum ieee80211_band band;
void (*pre_rx_handler)(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
- void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb);
+ int (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb,
+ struct iwl_device_cmd *cmd);
struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
@@ -1225,6 +861,9 @@ struct iwl_priv {
/* jiffies when last recovery from statistics was performed */
unsigned long rx_statistics_jiffies;
+ /*counters */
+ u32 rx_handlers_stats[REPLY_MAX];
+
/* force reset */
struct iwl_force_reset force_reset[IWL_MAX_FORCE_RESET];
@@ -1238,7 +877,7 @@ struct iwl_priv {
u8 channel_count; /* # of channels */
/* thermal calibration */
- s32 temperature; /* degrees Kelvin */
+ s32 temperature; /* Celsius */
s32 last_temperature;
/* init calibration results */
@@ -1255,21 +894,6 @@ struct iwl_priv {
u8 scan_tx_ant[IEEE80211_NUM_BANDS];
u8 mgmt_tx_ant;
- /* spinlock */
- spinlock_t lock; /* protect general shared data */
- spinlock_t hcmd_lock; /* protect hcmd */
- spinlock_t reg_lock; /* protect hw register access */
- struct mutex mutex;
-
- struct iwl_bus *bus; /* bus specific data */
- struct iwl_trans trans;
-
- /* microcode/device supports multiple contexts */
- u8 valid_contexts;
-
- /* command queue number */
- u8 cmd_queue;
-
/* max number of station keys */
u8 sta_key_max_num;
@@ -1283,9 +907,6 @@ struct iwl_priv {
u32 ucode_ver; /* version of ucode, copy of
iwl_ucode.ver */
- /* uCode owner: default: IWL_OWNERSHIP_DRIVER */
- u8 ucode_owner;
-
struct fw_img ucode_rt;
struct fw_img ucode_init;
struct fw_img ucode_wowlan;
@@ -1317,52 +938,25 @@ struct iwl_priv {
/* Rate scaling data */
u8 retry_rate;
- wait_queue_head_t wait_command_queue;
-
int activity_timer_active;
- /* Rx and Tx DMA processing queues */
- struct iwl_rx_queue rxq;
- struct iwl_tx_queue *txq;
- unsigned long txq_ctx_active_msk;
- struct iwl_dma_ptr kw; /* keep warm address */
- struct iwl_dma_ptr scd_bc_tbls;
-
- u32 scd_base_addr; /* scheduler sram base address */
-
- unsigned long status;
-
/* counts mgmt, ctl, and data packets */
struct traffic_stats tx_stats;
struct traffic_stats rx_stats;
- /* counts interrupts */
- struct isr_statistics isr_stats;
-
struct iwl_power_mgr power_data;
struct iwl_tt_mgmt thermal_throttle;
/* station table variables */
-
- /* Note: if lock and sta_lock are needed, lock must be acquired first */
- spinlock_t sta_lock;
int num_stations;
struct iwl_station_entry stations[IWLAGN_STATION_COUNT];
unsigned long ucode_key_table;
- /* queue refcounts */
-#define IWL_MAX_HW_QUEUES 32
- unsigned long queue_stopped[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)];
- /* for each AC */
- atomic_t queue_stop_count[4];
+ u8 mac80211_registered;
/* Indication if ieee80211_ops->open has been called */
u8 is_open;
- u8 mac80211_registered;
-
- bool wowlan;
-
/* eeprom -- this is in the card's little endian byte order */
u8 *eeprom;
int nvm_device_type;
@@ -1398,14 +992,6 @@ struct iwl_priv {
} accum_stats, delta_stats, max_delta_stats;
#endif
- /* INT ICT Table */
- __le32 *ict_tbl;
- void *ict_tbl_vir;
- dma_addr_t ict_tbl_dma;
- dma_addr_t aligned_ict_tbl_dma;
- int ict_index;
- u32 inta;
- bool use_ict;
/*
* reporting the number of tids has AGG on. 0 means
* no AGGREGATION
@@ -1438,14 +1024,10 @@ struct iwl_priv {
/* remain-on-channel offload support */
struct ieee80211_channel *hw_roc_channel;
- struct delayed_work hw_roc_work;
+ struct delayed_work hw_roc_disable_work;
enum nl80211_channel_type hw_roc_chantype;
int hw_roc_duration;
- bool hw_roc_setup;
-
- struct sk_buff *offchan_tx_skb;
- int offchan_tx_timeout;
- struct ieee80211_channel *offchan_tx_chan;
+ bool hw_roc_setup, hw_roc_start_notified;
/* bt coex */
u8 bt_enable_flag;
@@ -1466,15 +1048,8 @@ struct iwl_priv {
struct iwl_rxon_context *cur_rssi_ctx;
bool bt_is_sco;
- struct iwl_hw_params hw_params;
-
- u32 inta_mask;
-
- struct workqueue_struct *workqueue;
-
struct work_struct restart;
struct work_struct scan_completed;
- struct work_struct rx_replenish;
struct work_struct abort_scan;
struct work_struct beacon_update;
@@ -1490,8 +1065,6 @@ struct iwl_priv {
struct work_struct bt_full_concurrency;
struct work_struct bt_runtime_config;
- struct tasklet_struct irq_tasklet;
-
struct delayed_work scan_check;
/* TX Power */
@@ -1500,12 +1073,6 @@ struct iwl_priv {
s8 tx_power_lmt_in_half_dbm; /* max tx power in half-dBm format */
s8 tx_power_next;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
- /* debugging info */
- u32 debug_level; /* per device debugging will override global
- iwl_debug_level if set */
-#endif /* CONFIG_IWLWIFI_DEBUG */
#ifdef CONFIG_IWLWIFI_DEBUGFS
/* debugfs */
u16 tx_traffic_idx;
@@ -1543,47 +1110,7 @@ struct iwl_priv {
bool have_rekey_data;
}; /*iwl_priv */
-static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id)
-{
- set_bit(txq_id, &priv->txq_ctx_active_msk);
-}
-
-static inline void iwl_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id)
-{
- clear_bit(txq_id, &priv->txq_ctx_active_msk);
-}
-
-#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_priv *priv)
-{
- if (priv->debug_level)
- return priv->debug_level;
- else
- return iwl_debug_level;
-}
-#else
-static inline u32 iwl_get_debug_level(struct iwl_priv *priv)
-{
- return iwl_debug_level;
-}
-#endif
-
-
-static inline struct ieee80211_hdr *iwl_tx_queue_get_hdr(struct iwl_priv *priv,
- int txq_id, int idx)
-{
- if (priv->txq[txq_id].txb[idx].skb)
- return (struct ieee80211_hdr *)priv->txq[txq_id].
- txb[idx].skb->data;
- return NULL;
-}
+extern struct iwl_mod_params iwlagn_mod_params;
static inline struct iwl_rxon_context *
iwl_rxon_ctx_from_vif(struct ieee80211_vif *vif)
@@ -1596,7 +1123,7 @@ iwl_rxon_ctx_from_vif(struct ieee80211_vif *vif)
#define for_each_context(priv, ctx) \
for (ctx = &priv->contexts[IWL_RXON_CTX_BSS]; \
ctx < &priv->contexts[NUM_IWL_RXON_CTX]; ctx++) \
- if (priv->valid_contexts & BIT(ctx->ctxid))
+ if (priv->shrd->valid_contexts & BIT(ctx->ctxid))
static inline int iwl_is_associated_ctx(struct iwl_rxon_context *ctx)
{
@@ -1650,13 +1177,4 @@ static inline int is_channel_ibss(const struct iwl_channel_info *ch)
return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0;
}
-static inline void __iwl_free_pages(struct iwl_priv *priv, struct page *page)
-{
- __free_pages(page, priv->hw_params.rx_page_order);
-}
-
-static inline void iwl_free_pages(struct iwl_priv *priv, unsigned long page)
-{
- free_pages(page, priv->hw_params.rx_page_order);
-}
#endif /* __iwl_dev_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
index 2c84ba95afca..8a51c5ccda1e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
@@ -29,6 +29,8 @@
#include <linux/tracepoint.h>
+struct iwl_priv;
+
#if !defined(CONFIG_IWLWIFI_DEVICE_TRACING) || defined(__CHECKER__)
#undef TRACE_EVENT
#define TRACE_EVENT(name, proto, ...) \
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index 19d31a5e32e5..a4e43bd4a547 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -72,6 +72,7 @@
#include "iwl-dev.h"
#include "iwl-core.h"
#include "iwl-debug.h"
+#include "iwl-agn.h"
#include "iwl-eeprom.h"
#include "iwl-io.h"
@@ -138,7 +139,7 @@ static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */
/******************************************************************************
*
- * EEPROM related functions
+ * generic NVM functions
*
******************************************************************************/
@@ -155,11 +156,11 @@ static int iwl_eeprom_acquire_semaphore(struct iwl_priv *priv)
for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
/* Request semaphore */
- iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ iwl_set_bit(bus(priv), CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
/* See if we got it */
- ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
+ ret = iwl_poll_bit(bus(priv), 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);
@@ -176,14 +177,14 @@ static int iwl_eeprom_acquire_semaphore(struct iwl_priv *priv)
static void iwl_eeprom_release_semaphore(struct iwl_priv *priv)
{
- iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
+ iwl_clear_bit(bus(priv), CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
}
static int iwl_eeprom_verify_signature(struct iwl_priv *priv)
{
- u32 gp = iwl_read32(priv, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK;
+ u32 gp = iwl_read32(bus(priv), CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK;
int ret = 0;
IWL_DEBUG_EEPROM(priv, "EEPROM signature=0x%08x\n", gp);
@@ -214,19 +215,106 @@ static int iwl_eeprom_verify_signature(struct iwl_priv *priv)
return ret;
}
+u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset)
+{
+ if (!priv->eeprom)
+ return 0;
+ return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8);
+}
+
+int iwl_eeprom_check_version(struct iwl_priv *priv)
+{
+ u16 eeprom_ver;
+ u16 calib_ver;
+
+ eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
+ calib_ver = iwlagn_eeprom_calib_version(priv);
+
+ if (eeprom_ver < priv->cfg->eeprom_ver ||
+ calib_ver < priv->cfg->eeprom_calib_ver)
+ goto err;
+
+ IWL_INFO(priv, "device EEPROM VER=0x%x, CALIB=0x%x\n",
+ eeprom_ver, calib_ver);
+
+ return 0;
+err:
+ IWL_ERR(priv, "Unsupported (too old) EEPROM VER=0x%x < 0x%x "
+ "CALIB=0x%x < 0x%x\n",
+ eeprom_ver, priv->cfg->eeprom_ver,
+ calib_ver, priv->cfg->eeprom_calib_ver);
+ return -EINVAL;
+
+}
+
+int iwl_eeprom_check_sku(struct iwl_priv *priv)
+{
+ u16 radio_cfg;
+
+ if (!priv->cfg->sku) {
+ /* not using sku overwrite */
+ priv->cfg->sku = iwl_eeprom_query16(priv, EEPROM_SKU_CAP);
+ if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE &&
+ !priv->cfg->ht_params) {
+ IWL_ERR(priv, "Invalid 11n configuration\n");
+ return -EINVAL;
+ }
+ }
+ if (!priv->cfg->sku) {
+ IWL_ERR(priv, "Invalid device sku\n");
+ return -EINVAL;
+ }
+
+ IWL_INFO(priv, "Device SKU: 0X%x\n", priv->cfg->sku);
+
+ if (!priv->cfg->valid_tx_ant && !priv->cfg->valid_rx_ant) {
+ /* not using .cfg overwrite */
+ radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
+ priv->cfg->valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg);
+ priv->cfg->valid_rx_ant = EEPROM_RF_CFG_RX_ANT_MSK(radio_cfg);
+ if (!priv->cfg->valid_tx_ant || !priv->cfg->valid_rx_ant) {
+ IWL_ERR(priv, "Invalid chain (0X%x, 0X%x)\n",
+ priv->cfg->valid_tx_ant,
+ priv->cfg->valid_rx_ant);
+ return -EINVAL;
+ }
+ IWL_INFO(priv, "Valid Tx ant: 0X%x, Valid Rx ant: 0X%x\n",
+ priv->cfg->valid_tx_ant, priv->cfg->valid_rx_ant);
+ }
+ /*
+ * for some special cases,
+ * EEPROM did not reflect the correct antenna setting
+ * so overwrite the valid tx/rx antenna from .cfg
+ */
+ return 0;
+}
+
+void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac)
+{
+ const u8 *addr = iwl_eeprom_query_addr(priv,
+ EEPROM_MAC_ADDRESS);
+ memcpy(mac, addr, ETH_ALEN);
+}
+
+/******************************************************************************
+ *
+ * OTP related functions
+ *
+******************************************************************************/
+
static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode)
{
- iwl_read32(priv, CSR_OTP_GP_REG);
+ iwl_read32(bus(priv), CSR_OTP_GP_REG);
if (mode == IWL_OTP_ACCESS_ABSOLUTE)
- iwl_clear_bit(priv, CSR_OTP_GP_REG,
+ iwl_clear_bit(bus(priv), CSR_OTP_GP_REG,
CSR_OTP_GP_REG_OTP_ACCESS_MODE);
else
- iwl_set_bit(priv, CSR_OTP_GP_REG,
+ iwl_set_bit(bus(priv), CSR_OTP_GP_REG,
CSR_OTP_GP_REG_OTP_ACCESS_MODE);
}
-static int iwlcore_get_nvm_type(struct iwl_priv *priv, u32 hw_rev)
+static int iwl_get_nvm_type(struct iwl_priv *priv, u32 hw_rev)
{
u32 otpgp;
int nvm_type;
@@ -243,7 +331,7 @@ static int iwlcore_get_nvm_type(struct iwl_priv *priv, u32 hw_rev)
nvm_type = NVM_DEVICE_TYPE_EEPROM;
break;
default:
- otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
+ otpgp = iwl_read32(bus(priv), CSR_OTP_GP_REG);
if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT)
nvm_type = NVM_DEVICE_TYPE_OTP;
else
@@ -258,22 +346,22 @@ static int iwl_init_otp_access(struct iwl_priv *priv)
int ret;
/* Enable 40MHz radio clock */
- iwl_write32(priv, CSR_GP_CNTRL,
- iwl_read32(priv, CSR_GP_CNTRL) |
+ iwl_write32(bus(priv), CSR_GP_CNTRL,
+ iwl_read32(bus(priv), CSR_GP_CNTRL) |
CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
/* wait for clock to be ready */
- ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
+ ret = iwl_poll_bit(bus(priv), CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
25000);
if (ret < 0)
IWL_ERR(priv, "Time out access OTP\n");
else {
- iwl_set_bits_prph(priv, APMG_PS_CTRL_REG,
+ iwl_set_bits_prph(bus(priv), APMG_PS_CTRL_REG,
APMG_PS_CTRL_VAL_RESET_REQ);
udelay(5);
- iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG,
+ iwl_clear_bits_prph(bus(priv), APMG_PS_CTRL_REG,
APMG_PS_CTRL_VAL_RESET_REQ);
/*
@@ -281,7 +369,7 @@ static int iwl_init_otp_access(struct iwl_priv *priv)
* this is only applicable for HW with OTP shadow RAM
*/
if (priv->cfg->base_params->shadow_ram_support)
- iwl_set_bit(priv, CSR_DBG_LINK_PWR_MGMT_REG,
+ iwl_set_bit(bus(priv), CSR_DBG_LINK_PWR_MGMT_REG,
CSR_RESET_LINK_PWR_MGMT_DISABLED);
}
return ret;
@@ -293,9 +381,9 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_dat
u32 r;
u32 otpgp;
- iwl_write32(priv, CSR_EEPROM_REG,
+ iwl_write32(bus(priv), CSR_EEPROM_REG,
CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
- ret = iwl_poll_bit(priv, CSR_EEPROM_REG,
+ ret = iwl_poll_bit(bus(priv), CSR_EEPROM_REG,
CSR_EEPROM_REG_READ_VALID_MSK,
CSR_EEPROM_REG_READ_VALID_MSK,
IWL_EEPROM_ACCESS_TIMEOUT);
@@ -303,13 +391,13 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_dat
IWL_ERR(priv, "Time out reading OTP[%d]\n", addr);
return ret;
}
- r = iwl_read32(priv, CSR_EEPROM_REG);
+ r = iwl_read32(bus(priv), CSR_EEPROM_REG);
/* check for ECC errors: */
- otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
+ otpgp = iwl_read32(bus(priv), 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(priv, CSR_OTP_GP_REG,
+ iwl_set_bit(bus(priv), CSR_OTP_GP_REG,
CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
IWL_ERR(priv, "Uncorrectable OTP ECC error, abort OTP read\n");
return -EINVAL;
@@ -317,7 +405,7 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_dat
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(priv, CSR_OTP_GP_REG,
+ iwl_set_bit(bus(priv), CSR_OTP_GP_REG,
CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
IWL_ERR(priv, "Correctable OTP ECC error, continue read\n");
}
@@ -407,11 +495,152 @@ static int iwl_find_otp_image(struct iwl_priv *priv,
return -EINVAL;
}
-u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset)
+/******************************************************************************
+ *
+ * Tx Power related functions
+ *
+******************************************************************************/
+/**
+ * iwl_get_max_txpower_avg - get the highest tx power from all chains.
+ * find the highest tx power from all chains for the channel
+ */
+static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
+ struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
+ int element, s8 *max_txpower_in_half_dbm)
{
- if (!priv->eeprom)
- return 0;
- return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8);
+ s8 max_txpower_avg = 0; /* (dBm) */
+
+ /* Take the highest tx power from any valid chains */
+ if ((priv->cfg->valid_tx_ant & ANT_A) &&
+ (enhanced_txpower[element].chain_a_max > max_txpower_avg))
+ max_txpower_avg = enhanced_txpower[element].chain_a_max;
+ if ((priv->cfg->valid_tx_ant & ANT_B) &&
+ (enhanced_txpower[element].chain_b_max > max_txpower_avg))
+ max_txpower_avg = enhanced_txpower[element].chain_b_max;
+ if ((priv->cfg->valid_tx_ant & ANT_C) &&
+ (enhanced_txpower[element].chain_c_max > max_txpower_avg))
+ max_txpower_avg = enhanced_txpower[element].chain_c_max;
+ if (((priv->cfg->valid_tx_ant == ANT_AB) |
+ (priv->cfg->valid_tx_ant == ANT_BC) |
+ (priv->cfg->valid_tx_ant == ANT_AC)) &&
+ (enhanced_txpower[element].mimo2_max > max_txpower_avg))
+ max_txpower_avg = enhanced_txpower[element].mimo2_max;
+ if ((priv->cfg->valid_tx_ant == ANT_ABC) &&
+ (enhanced_txpower[element].mimo3_max > max_txpower_avg))
+ max_txpower_avg = enhanced_txpower[element].mimo3_max;
+
+ /*
+ * max. tx power in EEPROM is in 1/2 dBm format
+ * convert from 1/2 dBm to dBm (round-up convert)
+ * but we also do not want to loss 1/2 dBm resolution which
+ * will impact performance
+ */
+ *max_txpower_in_half_dbm = max_txpower_avg;
+ return (max_txpower_avg & 0x01) + (max_txpower_avg >> 1);
+}
+
+static void
+iwl_eeprom_enh_txp_read_element(struct iwl_priv *priv,
+ struct iwl_eeprom_enhanced_txpwr *txp,
+ s8 max_txpower_avg)
+{
+ int ch_idx;
+ bool is_ht40 = txp->flags & IWL_EEPROM_ENH_TXP_FL_40MHZ;
+ enum ieee80211_band band;
+
+ band = txp->flags & IWL_EEPROM_ENH_TXP_FL_BAND_52G ?
+ IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
+
+ for (ch_idx = 0; ch_idx < priv->channel_count; ch_idx++) {
+ struct iwl_channel_info *ch_info = &priv->channel_info[ch_idx];
+
+ /* update matching channel or from common data only */
+ if (txp->channel != 0 && ch_info->channel != txp->channel)
+ continue;
+
+ /* update matching band only */
+ if (band != ch_info->band)
+ continue;
+
+ if (ch_info->max_power_avg < max_txpower_avg && !is_ht40) {
+ ch_info->max_power_avg = max_txpower_avg;
+ ch_info->curr_txpow = max_txpower_avg;
+ ch_info->scan_power = max_txpower_avg;
+ }
+
+ if (is_ht40 && ch_info->ht40_max_power_avg < max_txpower_avg)
+ ch_info->ht40_max_power_avg = max_txpower_avg;
+ }
+}
+
+#define EEPROM_TXP_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT)
+#define EEPROM_TXP_ENTRY_LEN sizeof(struct iwl_eeprom_enhanced_txpwr)
+#define EEPROM_TXP_SZ_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT_SIZE)
+
+#define TXP_CHECK_AND_PRINT(x) ((txp->flags & IWL_EEPROM_ENH_TXP_FL_##x) \
+ ? # x " " : "")
+
+void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv)
+{
+ struct iwl_eeprom_enhanced_txpwr *txp_array, *txp;
+ int idx, entries;
+ __le16 *txp_len;
+ s8 max_txp_avg, max_txp_avg_halfdbm;
+
+ BUILD_BUG_ON(sizeof(struct iwl_eeprom_enhanced_txpwr) != 8);
+
+ /* the length is in 16-bit words, but we want entries */
+ txp_len = (__le16 *) iwl_eeprom_query_addr(priv, EEPROM_TXP_SZ_OFFS);
+ entries = le16_to_cpup(txp_len) * 2 / EEPROM_TXP_ENTRY_LEN;
+
+ txp_array = (void *) iwl_eeprom_query_addr(priv, EEPROM_TXP_OFFS);
+
+ for (idx = 0; idx < entries; idx++) {
+ txp = &txp_array[idx];
+ /* skip invalid entries */
+ if (!(txp->flags & IWL_EEPROM_ENH_TXP_FL_VALID))
+ continue;
+
+ IWL_DEBUG_EEPROM(priv, "%s %d:\t %s%s%s%s%s%s%s%s (0x%02x)\n",
+ (txp->channel && (txp->flags &
+ IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE)) ?
+ "Common " : (txp->channel) ?
+ "Channel" : "Common",
+ (txp->channel),
+ TXP_CHECK_AND_PRINT(VALID),
+ TXP_CHECK_AND_PRINT(BAND_52G),
+ TXP_CHECK_AND_PRINT(OFDM),
+ TXP_CHECK_AND_PRINT(40MHZ),
+ TXP_CHECK_AND_PRINT(HT_AP),
+ TXP_CHECK_AND_PRINT(RES1),
+ TXP_CHECK_AND_PRINT(RES2),
+ TXP_CHECK_AND_PRINT(COMMON_TYPE),
+ txp->flags);
+ IWL_DEBUG_EEPROM(priv, "\t\t chain_A: 0x%02x "
+ "chain_B: 0X%02x chain_C: 0X%02x\n",
+ txp->chain_a_max, txp->chain_b_max,
+ txp->chain_c_max);
+ IWL_DEBUG_EEPROM(priv, "\t\t MIMO2: 0x%02x "
+ "MIMO3: 0x%02x High 20_on_40: 0x%02x "
+ "Low 20_on_40: 0x%02x\n",
+ txp->mimo2_max, txp->mimo3_max,
+ ((txp->delta_20_in_40 & 0xf0) >> 4),
+ (txp->delta_20_in_40 & 0x0f));
+
+ max_txp_avg = iwl_get_max_txpower_avg(priv, txp_array, idx,
+ &max_txp_avg_halfdbm);
+
+ /*
+ * Update the user limit values values to the highest
+ * power supported by any channel
+ */
+ if (max_txp_avg > priv->tx_power_user_lmt)
+ priv->tx_power_user_lmt = max_txp_avg;
+ if (max_txp_avg_halfdbm > priv->tx_power_lmt_in_half_dbm)
+ priv->tx_power_lmt_in_half_dbm = max_txp_avg_halfdbm;
+
+ iwl_eeprom_enh_txp_read_element(priv, txp, max_txp_avg);
+ }
}
/**
@@ -424,14 +653,14 @@ u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset)
int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
{
__le16 *e;
- u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
+ u32 gp = iwl_read32(bus(priv), CSR_EEPROM_GP);
int sz;
int ret;
u16 addr;
u16 validblockaddr = 0;
u16 cache_addr = 0;
- priv->nvm_device_type = iwlcore_get_nvm_type(priv, hw_rev);
+ priv->nvm_device_type = iwl_get_nvm_type(priv, hw_rev);
if (priv->nvm_device_type == -ENOENT)
return -ENOENT;
/* allocate eeprom */
@@ -469,11 +698,11 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
ret = -ENOENT;
goto done;
}
- iwl_write32(priv, CSR_EEPROM_GP,
- iwl_read32(priv, CSR_EEPROM_GP) &
+ iwl_write32(bus(priv), CSR_EEPROM_GP,
+ iwl_read32(bus(priv), CSR_EEPROM_GP) &
~CSR_EEPROM_GP_IF_OWNER_MSK);
- iwl_set_bit(priv, CSR_OTP_GP_REG,
+ iwl_set_bit(bus(priv), 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 */
@@ -498,10 +727,10 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
for (addr = 0; addr < sz; addr += sizeof(u16)) {
u32 r;
- iwl_write32(priv, CSR_EEPROM_REG,
+ iwl_write32(bus(priv), CSR_EEPROM_REG,
CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
- ret = iwl_poll_bit(priv, CSR_EEPROM_REG,
+ ret = iwl_poll_bit(bus(priv), CSR_EEPROM_REG,
CSR_EEPROM_REG_READ_VALID_MSK,
CSR_EEPROM_REG_READ_VALID_MSK,
IWL_EEPROM_ACCESS_TIMEOUT);
@@ -509,7 +738,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr);
goto done;
}
- r = iwl_read32(priv, CSR_EEPROM_REG);
+ r = iwl_read32(bus(priv), CSR_EEPROM_REG);
e[addr / 2] = cpu_to_le16(r >> 16);
}
}
@@ -670,8 +899,9 @@ int iwl_init_channel_map(struct iwl_priv *priv)
IWL_DEBUG_EEPROM(priv, "Parsing data for %d channels.\n",
priv->channel_count);
- priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) *
- priv->channel_count, GFP_KERNEL);
+ priv->channel_info = kcalloc(priv->channel_count,
+ sizeof(struct iwl_channel_info),
+ GFP_KERNEL);
if (!priv->channel_info) {
IWL_ERR(priv, "Could not allocate channel_info\n");
priv->channel_count = 0;
@@ -838,7 +1068,7 @@ void iwl_rf_config(struct iwl_priv *priv)
/* write radio config values to register */
if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) <= EEPROM_RF_CONFIG_TYPE_MAX) {
- iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ iwl_set_bit(bus(priv), CSR_HW_IF_CONFIG_REG,
EEPROM_RF_CFG_TYPE_MSK(radio_cfg) |
EEPROM_RF_CFG_STEP_MSK(radio_cfg) |
EEPROM_RF_CFG_DASH_MSK(radio_cfg));
@@ -850,7 +1080,7 @@ void iwl_rf_config(struct iwl_priv *priv)
WARN_ON(1);
/* set CSR_HW_CONFIG_REG for uCode use */
- iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ iwl_set_bit(bus(priv), CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index e4bf8ac5e64e..c94747e7299e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -163,11 +163,19 @@ struct iwl_eeprom_enhanced_txpwr {
} __packed;
/* calibration */
+struct iwl_eeprom_calib_hdr {
+ u8 version;
+ u8 pa_type;
+ __le16 voltage;
+} __packed;
+
#define EEPROM_CALIB_ALL (INDIRECT_ADDRESS | INDIRECT_CALIBRATION)
#define EEPROM_XTAL ((2*0x128) | EEPROM_CALIB_ALL)
/* temperature */
-#define EEPROM_TEMPERATURE ((2*0x12A) | EEPROM_CALIB_ALL)
+#define EEPROM_KELVIN_TEMPERATURE ((2*0x12A) | EEPROM_CALIB_ALL)
+#define EEPROM_RAW_TEMPERATURE ((2*0x12B) | EEPROM_CALIB_ALL)
+
/* agn links */
#define EEPROM_LINK_HOST (2*0x64)
@@ -301,7 +309,6 @@ void iwl_eeprom_free(struct iwl_priv *priv);
int iwl_eeprom_check_version(struct iwl_priv *priv);
int iwl_eeprom_check_sku(struct iwl_priv *priv);
const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset);
-int iwlcore_eeprom_verify_signature(struct iwl_priv *priv);
u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset);
int iwl_init_channel_map(struct iwl_priv *priv);
void iwl_free_channel_map(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h
index 0ad60b3c04db..5bede9d7f955 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fh.h
@@ -63,6 +63,8 @@
#ifndef __iwl_fh_h__
#define __iwl_fh_h__
+#include <linux/types.h>
+
/****************************/
/* Flow Handler Definitions */
/****************************/
@@ -266,8 +268,6 @@
#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000)
#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000)
-#define FH_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */
-
/**
* Rx Shared Status Registers (RSSR)
*
@@ -422,10 +422,6 @@
#define RX_FREE_BUFFERS 64
#define RX_LOW_WATERMARK 8
-/* Size of one Rx buffer in host DRAM */
-#define IWL_RX_BUF_SIZE_4K (4 * 1024)
-#define IWL_RX_BUF_SIZE_8K (8 * 1024)
-
/**
* struct iwl_rb_status - reseve buffer status
* host memory mapped FH registers
@@ -508,4 +504,16 @@ struct iwl_tfd {
/* Keep Warm Size */
#define IWL_KW_SIZE 0x1000 /* 4k */
+/* Fixed (non-configurable) rx data from phy */
+
+/**
+ * struct iwlagn_schedq_bc_tbl scheduler byte count table
+ * base physical address provided by SCD_DRAM_BASE_ADDR
+ * @tfd_offset 0-12 - tx command byte count
+ * 12-16 - station index
+ */
+struct iwlagn_scd_bc_tbl {
+ __le16 tfd_offset[TFD_QUEUE_BC_SIZE];
+} __packed;
+
#endif /* !__iwl_fh_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
deleted file mode 100644
index 9d91552d13c1..000000000000
--- a/drivers/net/wireless/iwlwifi/iwl-helpers.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- * Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#ifndef __iwl_helpers_h__
-#define __iwl_helpers_h__
-
-#include <linux/ctype.h>
-#include <net/mac80211.h>
-
-#include "iwl-io.h"
-
-#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
-
-
-static inline struct ieee80211_conf *ieee80211_get_hw_conf(
- struct ieee80211_hw *hw)
-{
- return &hw->conf;
-}
-
-/**
- * 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);
-}
-
-/*
- * we have 8 bits used like this:
- *
- * 7 6 5 4 3 2 1 0
- * | | | | | | | |
- * | | | | | | +-+-------- AC queue (0-3)
- * | | | | | |
- * | +-+-+-+-+------------ HW queue ID
- * |
- * +---------------------- unused
- */
-static inline void iwl_set_swq_id(struct iwl_tx_queue *txq, u8 ac, u8 hwq)
-{
- BUG_ON(ac > 3); /* only have 2 bits */
- BUG_ON(hwq > 31); /* only use 5 bits */
-
- txq->swq_id = (hwq << 2) | ac;
-}
-
-static inline void iwl_wake_queue(struct iwl_priv *priv,
- struct iwl_tx_queue *txq)
-{
- u8 queue = txq->swq_id;
- u8 ac = queue & 3;
- u8 hwq = (queue >> 2) & 0x1f;
-
- if (test_and_clear_bit(hwq, priv->queue_stopped))
- if (atomic_dec_return(&priv->queue_stop_count[ac]) <= 0)
- ieee80211_wake_queue(priv->hw, ac);
-}
-
-static inline void iwl_stop_queue(struct iwl_priv *priv,
- struct iwl_tx_queue *txq)
-{
- u8 queue = txq->swq_id;
- u8 ac = queue & 3;
- u8 hwq = (queue >> 2) & 0x1f;
-
- if (!test_and_set_bit(hwq, priv->queue_stopped))
- if (atomic_inc_return(&priv->queue_stop_count[ac]) > 0)
- ieee80211_stop_queue(priv->hw, ac);
-}
-
-static inline void iwl_wake_any_queue(struct iwl_priv *priv,
- struct iwl_rxon_context *ctx)
-{
- u8 ac;
-
- for (ac = 0; ac < AC_NUM; ac++) {
- IWL_DEBUG_INFO(priv, "Queue Status: Q[%d] %s\n",
- ac, (atomic_read(&priv->queue_stop_count[ac]) > 0)
- ? "stopped" : "awake");
- iwl_wake_queue(priv, &priv->txq[ctx->ac_to_queue[ac]]);
- }
-}
-
-#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_disable_interrupts(struct iwl_priv *priv)
-{
- clear_bit(STATUS_INT_ENABLED, &priv->status);
-
- /* disable interrupts from uCode/NIC to host */
- iwl_write32(priv, CSR_INT_MASK, 0x00000000);
-
- /* acknowledge/clear/reset any interrupts still pending
- * from uCode or flow handler (Rx/Tx DMA) */
- iwl_write32(priv, CSR_INT, 0xffffffff);
- iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
- IWL_DEBUG_ISR(priv, "Disabled interrupts\n");
-}
-
-static inline void iwl_enable_rfkill_int(struct iwl_priv *priv)
-{
- IWL_DEBUG_ISR(priv, "Enabling rfkill interrupt\n");
- iwl_write32(priv, CSR_INT_MASK, CSR_INT_BIT_RF_KILL);
-}
-
-static inline void iwl_enable_interrupts(struct iwl_priv *priv)
-{
- IWL_DEBUG_ISR(priv, "Enabling interrupts\n");
- set_bit(STATUS_INT_ENABLED, &priv->status);
- iwl_write32(priv, CSR_INT_MASK, priv->inta_mask);
-}
-
-/**
- * iwl_beacon_time_mask_low - mask of lower 32 bit of beacon time
- * @priv -- pointer to iwl_priv data structure
- * @tsf_bits -- number of bits need to shift for masking)
- */
-static inline u32 iwl_beacon_time_mask_low(struct iwl_priv *priv,
- u16 tsf_bits)
-{
- return (1 << tsf_bits) - 1;
-}
-
-/**
- * iwl_beacon_time_mask_high - mask of higher 32 bit of beacon time
- * @priv -- pointer to iwl_priv data structure
- * @tsf_bits -- number of bits need to shift for masking)
- */
-static inline u32 iwl_beacon_time_mask_high(struct iwl_priv *priv,
- u16 tsf_bits)
-{
- return ((1 << (32 - tsf_bits)) - 1) << tsf_bits;
-}
-
-#endif /* __iwl_helpers_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c
index aa4a90674452..3ffa8e62b856 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.c
+++ b/drivers/net/wireless/iwlwifi/iwl-io.c
@@ -25,46 +25,50 @@
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
+#include <linux/delay.h>
+#include <linux/device.h>
#include "iwl-io.h"
+#include"iwl-csr.h"
+#include "iwl-debug.h"
#define IWL_POLL_INTERVAL 10 /* microseconds */
-static inline void __iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask)
+static inline void __iwl_set_bit(struct iwl_bus *bus, u32 reg, u32 mask)
{
- iwl_write32(priv, reg, iwl_read32(priv, reg) | mask);
+ iwl_write32(bus, reg, iwl_read32(bus, reg) | mask);
}
-static inline void __iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask)
+static inline void __iwl_clear_bit(struct iwl_bus *bus, u32 reg, u32 mask)
{
- iwl_write32(priv, reg, iwl_read32(priv, reg) & ~mask);
+ iwl_write32(bus, reg, iwl_read32(bus, reg) & ~mask);
}
-void iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask)
+void iwl_set_bit(struct iwl_bus *bus, u32 reg, u32 mask)
{
unsigned long flags;
- spin_lock_irqsave(&priv->reg_lock, flags);
- __iwl_set_bit(priv, reg, mask);
- spin_unlock_irqrestore(&priv->reg_lock, flags);
+ spin_lock_irqsave(&bus->reg_lock, flags);
+ __iwl_set_bit(bus, reg, mask);
+ spin_unlock_irqrestore(&bus->reg_lock, flags);
}
-void iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask)
+void iwl_clear_bit(struct iwl_bus *bus, u32 reg, u32 mask)
{
unsigned long flags;
- spin_lock_irqsave(&priv->reg_lock, flags);
- __iwl_clear_bit(priv, reg, mask);
- spin_unlock_irqrestore(&priv->reg_lock, flags);
+ spin_lock_irqsave(&bus->reg_lock, flags);
+ __iwl_clear_bit(bus, reg, mask);
+ spin_unlock_irqrestore(&bus->reg_lock, flags);
}
-int iwl_poll_bit(struct iwl_priv *priv, u32 addr,
+int iwl_poll_bit(struct iwl_bus *bus, u32 addr,
u32 bits, u32 mask, int timeout)
{
int t = 0;
do {
- if ((iwl_read32(priv, addr) & mask) == (bits & mask))
+ if ((iwl_read32(bus, addr) & mask) == (bits & mask))
return t;
udelay(IWL_POLL_INTERVAL);
t += IWL_POLL_INTERVAL;
@@ -73,14 +77,14 @@ int iwl_poll_bit(struct iwl_priv *priv, u32 addr,
return -ETIMEDOUT;
}
-int iwl_grab_nic_access_silent(struct iwl_priv *priv)
+int iwl_grab_nic_access_silent(struct iwl_bus *bus)
{
int ret;
- lockdep_assert_held(&priv->reg_lock);
+ lockdep_assert_held(&bus->reg_lock);
/* this bit wakes up the NIC */
- __iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ __iwl_set_bit(bus, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
/*
* These bits say the device is running, and should keep running for
@@ -101,70 +105,70 @@ int iwl_grab_nic_access_silent(struct iwl_priv *priv)
* 5000 series and later (including 1000 series) have non-volatile SRAM,
* and do not save/restore SRAM when power cycling.
*/
- ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
+ ret = iwl_poll_bit(bus, 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) {
- iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
+ iwl_write32(bus, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
return -EIO;
}
return 0;
}
-int iwl_grab_nic_access(struct iwl_priv *priv)
+int iwl_grab_nic_access(struct iwl_bus *bus)
{
- int ret = iwl_grab_nic_access_silent(priv);
+ int ret = iwl_grab_nic_access_silent(bus);
if (ret) {
- u32 val = iwl_read32(priv, CSR_GP_CNTRL);
- IWL_ERR(priv,
+ u32 val = iwl_read32(bus, CSR_GP_CNTRL);
+ IWL_ERR(bus,
"MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val);
}
return ret;
}
-void iwl_release_nic_access(struct iwl_priv *priv)
+void iwl_release_nic_access(struct iwl_bus *bus)
{
- lockdep_assert_held(&priv->reg_lock);
- __iwl_clear_bit(priv, CSR_GP_CNTRL,
+ lockdep_assert_held(&bus->reg_lock);
+ __iwl_clear_bit(bus, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
}
-u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg)
+u32 iwl_read_direct32(struct iwl_bus *bus, u32 reg)
{
u32 value;
unsigned long flags;
- spin_lock_irqsave(&priv->reg_lock, flags);
- iwl_grab_nic_access(priv);
- value = iwl_read32(priv, reg);
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->reg_lock, flags);
+ spin_lock_irqsave(&bus->reg_lock, flags);
+ iwl_grab_nic_access(bus);
+ value = iwl_read32(bus(bus), reg);
+ iwl_release_nic_access(bus);
+ spin_unlock_irqrestore(&bus->reg_lock, flags);
return value;
}
-void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value)
+void iwl_write_direct32(struct iwl_bus *bus, u32 reg, u32 value)
{
unsigned long flags;
- spin_lock_irqsave(&priv->reg_lock, flags);
- if (!iwl_grab_nic_access(priv)) {
- iwl_write32(priv, reg, value);
- iwl_release_nic_access(priv);
+ spin_lock_irqsave(&bus->reg_lock, flags);
+ if (!iwl_grab_nic_access(bus)) {
+ iwl_write32(bus, reg, value);
+ iwl_release_nic_access(bus);
}
- spin_unlock_irqrestore(&priv->reg_lock, flags);
+ spin_unlock_irqrestore(&bus->reg_lock, flags);
}
-int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask,
+int iwl_poll_direct_bit(struct iwl_bus *bus, u32 addr, u32 mask,
int timeout)
{
int t = 0;
do {
- if ((iwl_read_direct32(priv, addr) & mask) == mask)
+ if ((iwl_read_direct32(bus, addr) & mask) == mask)
return t;
udelay(IWL_POLL_INTERVAL);
t += IWL_POLL_INTERVAL;
@@ -173,122 +177,122 @@ int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask,
return -ETIMEDOUT;
}
-static inline u32 __iwl_read_prph(struct iwl_priv *priv, u32 reg)
+static inline u32 __iwl_read_prph(struct iwl_bus *bus, u32 reg)
{
- iwl_write32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
+ iwl_write32(bus, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
rmb();
- return iwl_read32(priv, HBUS_TARG_PRPH_RDAT);
+ return iwl_read32(bus, HBUS_TARG_PRPH_RDAT);
}
-static inline void __iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val)
+static inline void __iwl_write_prph(struct iwl_bus *bus, u32 addr, u32 val)
{
- iwl_write32(priv, HBUS_TARG_PRPH_WADDR,
+ iwl_write32(bus, HBUS_TARG_PRPH_WADDR,
((addr & 0x0000FFFF) | (3 << 24)));
wmb();
- iwl_write32(priv, HBUS_TARG_PRPH_WDAT, val);
+ iwl_write32(bus, HBUS_TARG_PRPH_WDAT, val);
}
-u32 iwl_read_prph(struct iwl_priv *priv, u32 reg)
+u32 iwl_read_prph(struct iwl_bus *bus, u32 reg)
{
unsigned long flags;
u32 val;
- spin_lock_irqsave(&priv->reg_lock, flags);
- iwl_grab_nic_access(priv);
- val = __iwl_read_prph(priv, reg);
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->reg_lock, flags);
+ spin_lock_irqsave(&bus->reg_lock, flags);
+ iwl_grab_nic_access(bus);
+ val = __iwl_read_prph(bus, reg);
+ iwl_release_nic_access(bus);
+ spin_unlock_irqrestore(&bus->reg_lock, flags);
return val;
}
-void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val)
+void iwl_write_prph(struct iwl_bus *bus, u32 addr, u32 val)
{
unsigned long flags;
- spin_lock_irqsave(&priv->reg_lock, flags);
- if (!iwl_grab_nic_access(priv)) {
- __iwl_write_prph(priv, addr, val);
- iwl_release_nic_access(priv);
+ spin_lock_irqsave(&bus->reg_lock, flags);
+ if (!iwl_grab_nic_access(bus)) {
+ __iwl_write_prph(bus, addr, val);
+ iwl_release_nic_access(bus);
}
- spin_unlock_irqrestore(&priv->reg_lock, flags);
+ spin_unlock_irqrestore(&bus->reg_lock, flags);
}
-void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask)
+void iwl_set_bits_prph(struct iwl_bus *bus, u32 reg, u32 mask)
{
unsigned long flags;
- spin_lock_irqsave(&priv->reg_lock, flags);
- iwl_grab_nic_access(priv);
- __iwl_write_prph(priv, reg, __iwl_read_prph(priv, reg) | mask);
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->reg_lock, flags);
+ spin_lock_irqsave(&bus->reg_lock, flags);
+ iwl_grab_nic_access(bus);
+ __iwl_write_prph(bus, reg, __iwl_read_prph(bus, reg) | mask);
+ iwl_release_nic_access(bus);
+ spin_unlock_irqrestore(&bus->reg_lock, flags);
}
-void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg,
+void iwl_set_bits_mask_prph(struct iwl_bus *bus, u32 reg,
u32 bits, u32 mask)
{
unsigned long flags;
- spin_lock_irqsave(&priv->reg_lock, flags);
- iwl_grab_nic_access(priv);
- __iwl_write_prph(priv, reg,
- (__iwl_read_prph(priv, reg) & mask) | bits);
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->reg_lock, flags);
+ spin_lock_irqsave(&bus->reg_lock, flags);
+ iwl_grab_nic_access(bus);
+ __iwl_write_prph(bus, reg,
+ (__iwl_read_prph(bus, reg) & mask) | bits);
+ iwl_release_nic_access(bus);
+ spin_unlock_irqrestore(&bus->reg_lock, flags);
}
-void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask)
+void iwl_clear_bits_prph(struct iwl_bus *bus, u32 reg, u32 mask)
{
unsigned long flags;
u32 val;
- spin_lock_irqsave(&priv->reg_lock, flags);
- iwl_grab_nic_access(priv);
- val = __iwl_read_prph(priv, reg);
- __iwl_write_prph(priv, reg, (val & ~mask));
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->reg_lock, flags);
+ spin_lock_irqsave(&bus->reg_lock, flags);
+ iwl_grab_nic_access(bus);
+ val = __iwl_read_prph(bus, reg);
+ __iwl_write_prph(bus, reg, (val & ~mask));
+ iwl_release_nic_access(bus);
+ spin_unlock_irqrestore(&bus->reg_lock, flags);
}
-void _iwl_read_targ_mem_words(struct iwl_priv *priv, u32 addr,
+void _iwl_read_targ_mem_words(struct iwl_bus *bus, u32 addr,
void *buf, int words)
{
unsigned long flags;
int offs;
u32 *vals = buf;
- spin_lock_irqsave(&priv->reg_lock, flags);
- iwl_grab_nic_access(priv);
+ spin_lock_irqsave(&bus->reg_lock, flags);
+ iwl_grab_nic_access(bus);
- iwl_write32(priv, HBUS_TARG_MEM_RADDR, addr);
+ iwl_write32(bus, HBUS_TARG_MEM_RADDR, addr);
rmb();
for (offs = 0; offs < words; offs++)
- vals[offs] = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
+ vals[offs] = iwl_read32(bus, HBUS_TARG_MEM_RDAT);
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->reg_lock, flags);
+ iwl_release_nic_access(bus);
+ spin_unlock_irqrestore(&bus->reg_lock, flags);
}
-u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr)
+u32 iwl_read_targ_mem(struct iwl_bus *bus, u32 addr)
{
u32 value;
- _iwl_read_targ_mem_words(priv, addr, &value, 1);
+ _iwl_read_targ_mem_words(bus, addr, &value, 1);
return value;
}
-void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val)
+void iwl_write_targ_mem(struct iwl_bus *bus, u32 addr, u32 val)
{
unsigned long flags;
- spin_lock_irqsave(&priv->reg_lock, flags);
- if (!iwl_grab_nic_access(priv)) {
- iwl_write32(priv, HBUS_TARG_MEM_WADDR, addr);
+ spin_lock_irqsave(&bus->reg_lock, flags);
+ if (!iwl_grab_nic_access(bus)) {
+ iwl_write32(bus, HBUS_TARG_MEM_WADDR, addr);
wmb();
- iwl_write32(priv, HBUS_TARG_MEM_WDAT, val);
- iwl_release_nic_access(priv);
+ iwl_write32(bus, HBUS_TARG_MEM_WDAT, val);
+ iwl_release_nic_access(bus);
}
- spin_unlock_irqrestore(&priv->reg_lock, flags);
+ spin_unlock_irqrestore(&bus->reg_lock, flags);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
index 19a093101122..ced2cbeb6eae 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -29,65 +29,62 @@
#ifndef __iwl_io_h__
#define __iwl_io_h__
-#include <linux/io.h>
-
-#include "iwl-dev.h"
-#include "iwl-debug.h"
#include "iwl-devtrace.h"
+#include "iwl-shared.h"
#include "iwl-bus.h"
-static inline void iwl_write8(struct iwl_priv *priv, u32 ofs, u8 val)
+static inline void iwl_write8(struct iwl_bus *bus, u32 ofs, u8 val)
{
- trace_iwlwifi_dev_iowrite8(priv, ofs, val);
- bus_write8(priv->bus, ofs, val);
+ trace_iwlwifi_dev_iowrite8(priv(bus), ofs, val);
+ bus_write8(bus, ofs, val);
}
-static inline void iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val)
+static inline void iwl_write32(struct iwl_bus *bus, u32 ofs, u32 val)
{
- trace_iwlwifi_dev_iowrite32(priv, ofs, val);
- bus_write32(priv->bus, ofs, val);
+ trace_iwlwifi_dev_iowrite32(priv(bus), ofs, val);
+ bus_write32(bus, ofs, val);
}
-static inline u32 iwl_read32(struct iwl_priv *priv, u32 ofs)
+static inline u32 iwl_read32(struct iwl_bus *bus, u32 ofs)
{
- u32 val = bus_read32(priv->bus, ofs);
- trace_iwlwifi_dev_ioread32(priv, ofs, val);
+ u32 val = bus_read32(bus, ofs);
+ trace_iwlwifi_dev_ioread32(priv(bus), ofs, val);
return val;
}
-void iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask);
-void iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask);
+void iwl_set_bit(struct iwl_bus *bus, u32 reg, u32 mask);
+void iwl_clear_bit(struct iwl_bus *bus, u32 reg, u32 mask);
-int iwl_poll_bit(struct iwl_priv *priv, u32 addr,
+int iwl_poll_bit(struct iwl_bus *bus, u32 addr,
u32 bits, u32 mask, int timeout);
-int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask,
+int iwl_poll_direct_bit(struct iwl_bus *bus, u32 addr, u32 mask,
int timeout);
-int iwl_grab_nic_access_silent(struct iwl_priv *priv);
-int iwl_grab_nic_access(struct iwl_priv *priv);
-void iwl_release_nic_access(struct iwl_priv *priv);
+int iwl_grab_nic_access_silent(struct iwl_bus *bus);
+int iwl_grab_nic_access(struct iwl_bus *bus);
+void iwl_release_nic_access(struct iwl_bus *bus);
-u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg);
-void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value);
+u32 iwl_read_direct32(struct iwl_bus *bus, u32 reg);
+void iwl_write_direct32(struct iwl_bus *bus, u32 reg, u32 value);
-u32 iwl_read_prph(struct iwl_priv *priv, u32 reg);
-void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val);
-void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask);
-void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg,
+u32 iwl_read_prph(struct iwl_bus *bus, u32 reg);
+void iwl_write_prph(struct iwl_bus *bus, u32 addr, u32 val);
+void iwl_set_bits_prph(struct iwl_bus *bus, u32 reg, u32 mask);
+void iwl_set_bits_mask_prph(struct iwl_bus *bus, u32 reg,
u32 bits, u32 mask);
-void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask);
+void iwl_clear_bits_prph(struct iwl_bus *bus, u32 reg, u32 mask);
-void _iwl_read_targ_mem_words(struct iwl_priv *priv, u32 addr,
+void _iwl_read_targ_mem_words(struct iwl_bus *bus, u32 addr,
void *buf, int words);
-#define iwl_read_targ_mem_words(priv, addr, buf, bufsize) \
+#define iwl_read_targ_mem_words(bus, addr, buf, bufsize) \
do { \
BUILD_BUG_ON((bufsize) % sizeof(u32)); \
- _iwl_read_targ_mem_words(priv, addr, buf, \
+ _iwl_read_targ_mem_words(bus, addr, buf, \
(bufsize) / sizeof(u32));\
} while (0)
-u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr);
-void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val);
+u32 iwl_read_targ_mem(struct iwl_bus *bus, u32 addr);
+void iwl_write_targ_mem(struct iwl_bus *bus, u32 addr, u32 val);
#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index a67ae56d5464..eb541735296c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -31,7 +31,6 @@
#include <linux/delay.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
-#include <linux/wireless.h>
#include <net/mac80211.h>
#include <linux/etherdevice.h>
#include <asm/unaligned.h>
@@ -41,6 +40,7 @@
#include "iwl-agn.h"
#include "iwl-io.h"
#include "iwl-trans.h"
+#include "iwl-shared.h"
/* Throughput OFF time(ms) ON time (ms)
* >300 25 25
@@ -71,7 +71,7 @@ static const struct ieee80211_tpt_blink iwl_blink[] = {
/* Set led register off */
void iwlagn_led_enable(struct iwl_priv *priv)
{
- iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
+ iwl_write32(bus(priv), CSR_LED_REG, CSR_LED_REG_TRUN_ON);
}
/*
@@ -104,15 +104,14 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
.len = { sizeof(struct iwl_led_cmd), },
.data = { led_cmd, },
.flags = CMD_ASYNC,
- .callback = NULL,
};
u32 reg;
- reg = iwl_read32(priv, CSR_LED_REG);
+ reg = iwl_read32(bus(priv), CSR_LED_REG);
if (reg != (reg & CSR_LED_BSM_CTRL_MSK))
- iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK);
+ iwl_write32(bus(priv), CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK);
- return trans_send_cmd(&priv->trans, &cmd);
+ return iwl_trans_send_cmd(trans(priv), &cmd);
}
/* Set led pattern command */
@@ -126,7 +125,7 @@ static int iwl_led_cmd(struct iwl_priv *priv,
};
int ret;
- if (!test_bit(STATUS_READY, &priv->status))
+ if (!test_bit(STATUS_READY, &priv->shrd->status))
return -EBUSY;
if (priv->blink_on == on && priv->blink_off == off)
@@ -203,8 +202,7 @@ void iwl_leds_init(struct iwl_priv *priv)
break;
}
- ret = led_classdev_register(priv->bus->dev,
- &priv->led);
+ ret = led_classdev_register(bus(priv)->dev, &priv->led);
if (ret) {
kfree(priv->led.name);
return;
diff --git a/drivers/net/wireless/iwlwifi/iwl-pci.c b/drivers/net/wireless/iwlwifi/iwl-pci.c
index 69d4ec467dca..3b6cc66365e5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-pci.c
+++ b/drivers/net/wireless/iwlwifi/iwl-pci.c
@@ -64,9 +64,11 @@
#include <linux/pci-aspm.h>
#include "iwl-bus.h"
-#include "iwl-agn.h"
-#include "iwl-core.h"
#include "iwl-io.h"
+#include "iwl-shared.h"
+#include "iwl-trans.h"
+#include "iwl-csr.h"
+#include "iwl-cfg.h"
/* PCI registers */
#define PCI_CFG_RETRY_TIMEOUT 0x041
@@ -91,6 +93,7 @@ static u16 iwl_pciexp_link_ctrl(struct iwl_bus *bus)
{
int pos;
u16 pci_lnk_ctl;
+
struct pci_dev *pci_dev = IWL_BUS_GET_PCI_DEV(bus);
pos = pci_pcie_cap(pci_dev);
@@ -120,23 +123,17 @@ static void iwl_pci_apm_config(struct iwl_bus *bus)
if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) ==
PCI_CFG_LINK_CTRL_VAL_L1_EN) {
/* L1-ASPM enabled; disable(!) L0S */
- iwl_set_bit(bus->drv_data, CSR_GIO_REG,
+ iwl_set_bit(bus, CSR_GIO_REG,
CSR_GIO_REG_VAL_L0S_ENABLED);
dev_printk(KERN_INFO, bus->dev, "L1 Enabled; Disabling L0S\n");
} else {
/* L1-ASPM disabled; enable(!) L0S */
- iwl_clear_bit(bus->drv_data, CSR_GIO_REG,
+ iwl_clear_bit(bus, CSR_GIO_REG,
CSR_GIO_REG_VAL_L0S_ENABLED);
dev_printk(KERN_INFO, bus->dev, "L1 Disabled; Enabling L0S\n");
}
}
-static void iwl_pci_set_drv_data(struct iwl_bus *bus, void *drv_data)
-{
- bus->drv_data = drv_data;
- pci_set_drvdata(IWL_BUS_GET_PCI_DEV(bus), drv_data);
-}
-
static void iwl_pci_get_hw_id(struct iwl_bus *bus, char buf[],
int buf_len)
{
@@ -162,10 +159,9 @@ static u32 iwl_pci_read32(struct iwl_bus *bus, u32 ofs)
return val;
}
-static struct iwl_bus_ops pci_ops = {
+static const struct iwl_bus_ops bus_ops_pci = {
.get_pm_support = iwl_pci_is_pm_supported,
.apm_config = iwl_pci_apm_config,
- .set_drv_data = iwl_pci_set_drv_data,
.get_hw_id = iwl_pci_get_hw_id,
.write8 = iwl_pci_write8,
.write32 = iwl_pci_write32,
@@ -256,6 +252,9 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{IWL_PCI_DEVICE(0x0082, 0x1326, iwl6005_2abg_cfg)},
{IWL_PCI_DEVICE(0x0085, 0x1311, iwl6005_2agn_cfg)},
{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)},
/* 6x30 Series */
{IWL_PCI_DEVICE(0x008A, 0x5305, iwl1030_bgn_cfg)},
@@ -328,6 +327,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{IWL_PCI_DEVICE(0x0890, 0x4026, iwl2000_2bg_cfg)},
{IWL_PCI_DEVICE(0x0891, 0x4226, iwl2000_2bg_cfg)},
{IWL_PCI_DEVICE(0x0890, 0x4426, iwl2000_2bg_cfg)},
+ {IWL_PCI_DEVICE(0x0890, 0x4822, iwl2000_2bgn_d_cfg)},
/* 2x30 Series */
{IWL_PCI_DEVICE(0x0887, 0x4062, iwl2030_2bgn_cfg)},
@@ -355,6 +355,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{IWL_PCI_DEVICE(0x0894, 0x0026, iwl105_bg_cfg)},
{IWL_PCI_DEVICE(0x0895, 0x0226, iwl105_bg_cfg)},
{IWL_PCI_DEVICE(0x0894, 0x0426, iwl105_bg_cfg)},
+ {IWL_PCI_DEVICE(0x0894, 0x0822, iwl105_bgn_d_cfg)},
/* 135 Series */
{IWL_PCI_DEVICE(0x0892, 0x0062, iwl135_bgn_cfg)},
@@ -387,6 +388,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_bus = IWL_BUS_GET_PCI_BUS(bus);
pci_bus->pci_dev = pdev;
+ pci_set_drvdata(pdev, bus);
+
/* 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 */
pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
@@ -457,9 +460,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
bus->dev = &pdev->dev;
bus->irq = pdev->irq;
- bus->ops = &pci_ops;
+ bus->ops = &bus_ops_pci;
- err = iwl_probe(bus, cfg);
+ err = iwl_probe(bus, &trans_ops_pcie, cfg);
if (err)
goto out_disable_msi;
return 0;
@@ -478,48 +481,45 @@ out_no_pci:
return err;
}
-static void iwl_pci_down(struct iwl_bus *bus)
-{
- struct iwl_pci_bus *pci_bus = (struct iwl_pci_bus *) bus->bus_specific;
-
- pci_disable_msi(pci_bus->pci_dev);
- pci_iounmap(pci_bus->pci_dev, pci_bus->hw_base);
- pci_release_regions(pci_bus->pci_dev);
- pci_disable_device(pci_bus->pci_dev);
- pci_set_drvdata(pci_bus->pci_dev, NULL);
-
- kfree(bus);
-}
-
static void __devexit iwl_pci_remove(struct pci_dev *pdev)
{
- struct iwl_priv *priv = pci_get_drvdata(pdev);
- void *bus_specific = priv->bus->bus_specific;
+ struct iwl_bus *bus = pci_get_drvdata(pdev);
+ struct iwl_pci_bus *pci_bus = IWL_BUS_GET_PCI_BUS(bus);
+ struct pci_dev *pci_dev = IWL_BUS_GET_PCI_DEV(bus);
+ struct iwl_shared *shrd = bus->shrd;
+
+ iwl_remove(shrd->priv);
- iwl_remove(priv);
+ pci_disable_msi(pci_dev);
+ pci_iounmap(pci_dev, pci_bus->hw_base);
+ pci_release_regions(pci_dev);
+ pci_disable_device(pci_dev);
+ pci_set_drvdata(pci_dev, NULL);
- iwl_pci_down(bus_specific);
+ kfree(bus);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int iwl_pci_suspend(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
- struct iwl_priv *priv = pci_get_drvdata(pdev);
+ struct iwl_bus *bus = pci_get_drvdata(pdev);
+ struct iwl_shared *shrd = bus->shrd;
/* 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_suspend(priv);
+ return iwl_trans_suspend(shrd->trans);
}
static int iwl_pci_resume(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
- struct iwl_priv *priv = pci_get_drvdata(pdev);
+ struct iwl_bus *bus = pci_get_drvdata(pdev);
+ struct iwl_shared *shrd = bus->shrd;
/* 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
@@ -532,7 +532,7 @@ static int iwl_pci_resume(struct device *device)
*/
pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
- return iwl_resume(priv);
+ return iwl_trans_resume(shrd->trans);
}
static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume);
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index cd64df05f9ed..4eaab204322d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -43,6 +43,7 @@
#include "iwl-debug.h"
#include "iwl-power.h"
#include "iwl-trans.h"
+#include "iwl-shared.h"
/*
* Setting power level allows the card to go to sleep when not busy.
@@ -214,7 +215,7 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
else
cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
- if (priv->cfg->base_params->shadow_reg_enable)
+ if (hw_params(priv).shadow_reg_enable)
cmd->flags |= IWL_POWER_SHADOW_REG_ENA;
else
cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA;
@@ -300,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 (priv->cfg->base_params->shadow_reg_enable)
+ if (hw_params(priv).shadow_reg_enable)
cmd->flags |= IWL_POWER_SHADOW_REG_ENA;
else
cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA;
@@ -335,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 trans_send_cmd_pdu(&priv->trans, POWER_TABLE_CMD, CMD_SYNC,
+ return iwl_trans_send_cmd_pdu(trans(priv), POWER_TABLE_CMD, CMD_SYNC,
sizeof(struct iwl_powertable_cmd), cmd);
}
@@ -347,7 +348,7 @@ static void iwl_power_build_cmd(struct iwl_priv *priv,
dtimper = priv->hw->conf.ps_dtim_period ?: 1;
- if (priv->wowlan)
+ if (priv->shrd->wowlan)
iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, dtimper);
else if (!priv->cfg->base_params->no_idle_support &&
priv->hw->conf.flags & IEEE80211_CONF_IDLE)
@@ -382,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->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
/* Don't update the RX chain when chain noise calibration is running */
update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE ||
@@ -391,23 +392,23 @@ 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))
+ if (!iwl_is_ready_rf(priv->shrd))
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->status) && !force) {
+ if (test_bit(STATUS_SCANNING, &priv->shrd->status) && !force) {
IWL_DEBUG_INFO(priv, "Defer power set mode while scanning\n");
return 0;
}
if (cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)
- set_bit(STATUS_POWER_PMI, &priv->status);
+ set_bit(STATUS_POWER_PMI, &priv->shrd->status);
ret = iwl_set_power(priv, cmd);
if (!ret) {
if (!(cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK))
- clear_bit(STATUS_POWER_PMI, &priv->status);
+ clear_bit(STATUS_POWER_PMI, &priv->shrd->status);
if (update_chains)
iwl_update_chain_flags(priv);
@@ -435,7 +436,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
/* initialize to default */
void iwl_power_initialize(struct iwl_priv *priv)
{
- priv->power_data.bus_pm = bus_get_pm_support(priv->bus);
+ priv->power_data.bus_pm = bus_get_pm_support(bus(priv));
priv->power_data.debug_sleep_level_override = -1;
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 2f267b8aabbb..bebdd828f324 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -217,8 +217,8 @@
((SCD_TRANS_TBL_MEM_LOWER_BOUND + ((x) * 2)) & 0xfffc)
#define SCD_QUEUECHAIN_SEL_ALL(priv) \
- (((1<<(priv)->hw_params.max_txq_num) - 1) &\
- (~(1<<(priv)->cmd_queue)))
+ (((1<<hw_params(priv).max_txq_num) - 1) &\
+ (~(1<<(priv)->shrd->cmd_queue)))
#define SCD_BASE (PRPH_BASE + 0xa02c00)
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index dd6937e97055..e5d727f537d0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -33,9 +33,7 @@
#include "iwl-eeprom.h"
#include "iwl-dev.h"
#include "iwl-core.h"
-#include "iwl-sta.h"
#include "iwl-io.h"
-#include "iwl-helpers.h"
#include "iwl-agn.h"
#include "iwl-trans.h"
@@ -68,14 +66,14 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
/* 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->status) ||
- !test_bit(STATUS_GEO_CONFIGURED, &priv->status) ||
- !test_bit(STATUS_SCAN_HW, &priv->status) ||
- test_bit(STATUS_FW_ERROR, &priv->status) ||
- test_bit(STATUS_EXIT_PENDING, &priv->status))
+ 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))
return -EIO;
- ret = trans_send_cmd(&priv->trans, &cmd);
+ ret = iwl_trans_send_cmd(trans(priv), &cmd);
if (ret)
return ret;
@@ -91,7 +89,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
ret = -EIO;
}
- iwl_free_pages(priv, cmd.reply_page);
+ iwl_free_pages(priv->shrd, cmd.reply_page);
return ret;
}
@@ -103,24 +101,90 @@ static void iwl_complete_scan(struct iwl_priv *priv, bool aborted)
ieee80211_scan_completed(priv->hw, aborted);
}
+ if (priv->scan_type == IWL_SCAN_ROC) {
+ ieee80211_remain_on_channel_expired(priv->hw);
+ priv->hw_roc_channel = NULL;
+ schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ);
+ }
+
priv->scan_type = IWL_SCAN_NORMAL;
priv->scan_vif = NULL;
priv->scan_request = NULL;
}
+static void iwl_process_scan_complete(struct iwl_priv *priv)
+{
+ bool aborted;
+
+ lockdep_assert_held(&priv->shrd->mutex);
+
+ if (!test_and_clear_bit(STATUS_SCAN_COMPLETE, &priv->shrd->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);
+ if (aborted)
+ IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n");
+
+ if (!test_and_clear_bit(STATUS_SCANNING, &priv->shrd->status)) {
+ IWL_DEBUG_SCAN(priv, "Scan already completed.\n");
+ goto out_settings;
+ }
+
+ if (priv->scan_type == IWL_SCAN_ROC) {
+ ieee80211_remain_on_channel_expired(priv->hw);
+ priv->hw_roc_channel = NULL;
+ schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ);
+ }
+
+ if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) {
+ int err;
+
+ /* Check if mac80211 requested scan during our internal scan */
+ if (priv->scan_request == NULL)
+ goto out_complete;
+
+ /* If so request a new scan */
+ err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL,
+ priv->scan_request->channels[0]->band);
+ if (err) {
+ IWL_DEBUG_SCAN(priv,
+ "failed to initiate pending scan: %d\n", err);
+ aborted = true;
+ goto out_complete;
+ }
+
+ return;
+ }
+
+out_complete:
+ iwl_complete_scan(priv, aborted);
+
+out_settings:
+ /* Can we still talk to firmware ? */
+ if (!iwl_is_ready_rf(priv->shrd))
+ return;
+
+ iwlagn_post_scan(priv);
+}
+
void iwl_force_scan_end(struct iwl_priv *priv)
{
- lockdep_assert_held(&priv->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
- if (!test_bit(STATUS_SCANNING, &priv->status)) {
+ if (!test_bit(STATUS_SCANNING, &priv->shrd->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->status);
- clear_bit(STATUS_SCAN_HW, &priv->status);
- clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+ 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);
iwl_complete_scan(priv, true);
}
@@ -128,14 +192,14 @@ static void iwl_do_scan_abort(struct iwl_priv *priv)
{
int ret;
- lockdep_assert_held(&priv->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
- if (!test_bit(STATUS_SCANNING, &priv->status)) {
+ if (!test_bit(STATUS_SCANNING, &priv->shrd->status)) {
IWL_DEBUG_SCAN(priv, "Not performing scan to abort\n");
return;
}
- if (test_and_set_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ if (test_and_set_bit(STATUS_SCAN_ABORTING, &priv->shrd->status)) {
IWL_DEBUG_SCAN(priv, "Scan abort in progress\n");
return;
}
@@ -154,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->workqueue, &priv->abort_scan);
+ queue_work(priv->shrd->workqueue, &priv->abort_scan);
return 0;
}
@@ -163,28 +227,42 @@ int iwl_scan_cancel(struct iwl_priv *priv)
* @ms: amount of time to wait (in milliseconds) for scan to abort
*
*/
-int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
+void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
{
unsigned long timeout = jiffies + msecs_to_jiffies(ms);
- lockdep_assert_held(&priv->mutex);
+ lockdep_assert_held(&priv->shrd->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->status))
- break;
+ if (!test_bit(STATUS_SCAN_HW, &priv->shrd->status))
+ goto finished;
msleep(20);
}
- return test_bit(STATUS_SCAN_HW, &priv->status);
+ return;
+
+ finished:
+ /*
+ * Now STATUS_SCAN_HW is clear. This means that the
+ * device finished, but the background work is going
+ * to execute at best as soon as we release the mutex.
+ * Since we need to be able to issue a new scan right
+ * after this function returns, run the complete here.
+ * The STATUS_SCAN_COMPLETE bit will then be cleared
+ * and prevent the background work from "completing"
+ * a possible new scan.
+ */
+ iwl_process_scan_complete(priv);
}
/* Service response to REPLY_SCAN_CMD (0x80) */
-static void iwl_rx_reply_scan(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_reply_scan(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb,
+ struct iwl_device_cmd *cmd)
{
#ifdef CONFIG_IWLWIFI_DEBUG
struct iwl_rx_packet *pkt = rxb_addr(rxb);
@@ -193,11 +271,13 @@ static void iwl_rx_reply_scan(struct iwl_priv *priv,
IWL_DEBUG_SCAN(priv, "Scan request status = 0x%x\n", notif->status);
#endif
+ return 0;
}
/* Service SCAN_START_NOTIFICATION (0x82) */
-static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_scan_start_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb,
+ struct iwl_device_cmd *cmd)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_scanstart_notification *notif =
@@ -211,11 +291,20 @@ static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
le32_to_cpu(notif->tsf_high),
le32_to_cpu(notif->tsf_low),
notif->status, notif->beacon_timer);
+
+ if (priv->scan_type == IWL_SCAN_ROC &&
+ !priv->hw_roc_start_notified) {
+ ieee80211_ready_on_channel(priv->hw);
+ priv->hw_roc_start_notified = true;
+ }
+
+ return 0;
}
/* Service SCAN_RESULTS_NOTIFICATION (0x83) */
-static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_scan_results_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb,
+ struct iwl_device_cmd *cmd)
{
#ifdef CONFIG_IWLWIFI_DEBUG
struct iwl_rx_packet *pkt = rxb_addr(rxb);
@@ -224,20 +313,24 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
IWL_DEBUG_SCAN(priv, "Scan ch.res: "
"%d [802.11%s] "
+ "probe status: %u:%u "
"(TSF: 0x%08X:%08X) - %d "
"elapsed=%lu usec\n",
notif->channel,
notif->band ? "bg" : "a",
+ notif->probe_status, notif->num_probe_not_sent,
le32_to_cpu(notif->tsf_high),
le32_to_cpu(notif->tsf_low),
le32_to_cpu(notif->statistics[0]),
le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf);
#endif
+ return 0;
}
/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
-static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_scan_complete_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_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;
@@ -247,14 +340,21 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
scan_notif->tsf_low,
scan_notif->tsf_high, scan_notif->status);
- /* The HW is no longer scanning */
- clear_bit(STATUS_SCAN_HW, &priv->status);
-
IWL_DEBUG_SCAN(priv, "Scan on %sGHz took %dms\n",
(priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2",
jiffies_to_msecs(jiffies - priv->scan_start));
- queue_work(priv->workqueue, &priv->scan_completed);
+ /*
+ * When aborting, we run the scan completed background work inline
+ * and the background work must then do nothing. The SCAN_COMPLETE
+ * bit helps implement that logic and thus needs to be set before
+ * queueing the work. Also, since the scan abort waits for SCAN_HW
+ * 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);
if (priv->iw_mode != NL80211_IFTYPE_ADHOC &&
iwl_advanced_bt_coexist(priv) &&
@@ -274,8 +374,10 @@ static void 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->workqueue, &priv->bt_traffic_change_work);
+ queue_work(priv->shrd->workqueue,
+ &priv->bt_traffic_change_work);
}
+ return 0;
}
void iwl_setup_rx_scan_handlers(struct iwl_priv *priv)
@@ -289,9 +391,8 @@ void iwl_setup_rx_scan_handlers(struct iwl_priv *priv)
iwl_rx_scan_complete_notif;
}
-inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
- enum ieee80211_band band,
- u8 n_probes)
+static u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
+ enum ieee80211_band band, u8 n_probes)
{
if (band == IEEE80211_BAND_5GHZ)
return IWL_ACTIVE_DWELL_TIME_52 +
@@ -301,40 +402,486 @@ inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1);
}
-u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
- enum ieee80211_band band,
- struct ieee80211_vif *vif)
+static u16 iwl_limit_dwell(struct iwl_priv *priv, u16 dwell_time)
{
struct iwl_rxon_context *ctx;
+
+ /*
+ * If we're associated, we clamp the dwell time 98%
+ * of the smallest beacon interval (minus 2 * channel
+ * tune time)
+ */
+ for_each_context(priv, ctx) {
+ u16 value;
+
+ if (!iwl_is_associated_ctx(ctx))
+ continue;
+ value = ctx->beacon_int;
+ if (!value)
+ value = IWL_PASSIVE_DWELL_BASE;
+ value = (value * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
+ dwell_time = min(value, dwell_time);
+ }
+
+ return dwell_time;
+}
+
+static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
+ enum ieee80211_band band)
+{
u16 passive = (band == IEEE80211_BAND_2GHZ) ?
IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
- if (iwl_is_any_associated(priv)) {
+ return iwl_limit_dwell(priv, passive);
+}
+
+static int iwl_get_single_channel_for_scan(struct iwl_priv *priv,
+ struct ieee80211_vif *vif,
+ enum ieee80211_band band,
+ struct iwl_scan_channel *scan_ch)
+{
+ const struct ieee80211_supported_band *sband;
+ u16 passive_dwell = 0;
+ u16 active_dwell = 0;
+ int added = 0;
+ u16 channel = 0;
+
+ sband = iwl_get_hw_mode(priv, band);
+ if (!sband) {
+ IWL_ERR(priv, "invalid band\n");
+ return added;
+ }
+
+ active_dwell = iwl_get_active_dwell_time(priv, band, 0);
+ passive_dwell = iwl_get_passive_dwell_time(priv, band);
+
+ if (passive_dwell <= active_dwell)
+ passive_dwell = active_dwell + 1;
+
+ channel = iwl_get_single_channel_number(priv, band);
+ if (channel) {
+ scan_ch->channel = cpu_to_le16(channel);
+ scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
+ scan_ch->active_dwell = cpu_to_le16(active_dwell);
+ scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
+ /* Set txpower levels to defaults */
+ scan_ch->dsp_atten = 110;
+ if (band == IEEE80211_BAND_5GHZ)
+ scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
+ else
+ scan_ch->tx_gain = ((1 << 5) | (5 << 3));
+ added++;
+ } else
+ IWL_ERR(priv, "no valid channel found\n");
+ return added;
+}
+
+static int iwl_get_channels_for_scan(struct iwl_priv *priv,
+ struct ieee80211_vif *vif,
+ enum ieee80211_band band,
+ u8 is_active, u8 n_probes,
+ struct iwl_scan_channel *scan_ch)
+{
+ struct ieee80211_channel *chan;
+ const struct ieee80211_supported_band *sband;
+ const struct iwl_channel_info *ch_info;
+ u16 passive_dwell = 0;
+ u16 active_dwell = 0;
+ int added, i;
+ u16 channel;
+
+ sband = iwl_get_hw_mode(priv, band);
+ if (!sband)
+ return 0;
+
+ active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
+ passive_dwell = iwl_get_passive_dwell_time(priv, band);
+
+ if (passive_dwell <= active_dwell)
+ passive_dwell = active_dwell + 1;
+
+ for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) {
+ chan = priv->scan_request->channels[i];
+
+ if (chan->band != band)
+ continue;
+
+ channel = chan->hw_value;
+ scan_ch->channel = cpu_to_le16(channel);
+
+ ch_info = iwl_get_channel_info(priv, band, channel);
+ if (!is_channel_valid(ch_info)) {
+ IWL_DEBUG_SCAN(priv,
+ "Channel %d is INVALID for this band.\n",
+ channel);
+ continue;
+ }
+
+ if (!is_active || is_channel_passive(ch_info) ||
+ (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
+ scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
+ else
+ scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
+
+ if (n_probes)
+ scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
+
+ scan_ch->active_dwell = cpu_to_le16(active_dwell);
+ scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
+
+ /* Set txpower levels to defaults */
+ scan_ch->dsp_atten = 110;
+
+ /* NOTE: if we were doing 6Mb OFDM for scans we'd use
+ * power level:
+ * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
+ */
+ if (band == IEEE80211_BAND_5GHZ)
+ scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
+ else
+ scan_ch->tx_gain = ((1 << 5) | (5 << 3));
+
+ IWL_DEBUG_SCAN(priv, "Scanning ch=%d prob=0x%X [%s %d]\n",
+ channel, le32_to_cpu(scan_ch->type),
+ (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
+ "ACTIVE" : "PASSIVE",
+ (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
+ active_dwell : passive_dwell);
+
+ scan_ch++;
+ added++;
+ }
+
+ IWL_DEBUG_SCAN(priv, "total channels to scan %d\n", added);
+ return added;
+}
+
+static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
+{
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_SCAN_CMD,
+ .len = { sizeof(struct iwl_scan_cmd), },
+ .flags = CMD_SYNC,
+ };
+ struct iwl_scan_cmd *scan;
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+ u32 rate_flags = 0;
+ u16 cmd_len;
+ u16 rx_chain = 0;
+ enum ieee80211_band band;
+ u8 n_probes = 0;
+ u8 rx_ant = hw_params(priv).valid_rx_ant;
+ u8 rate;
+ bool is_active = false;
+ int chan_mod;
+ u8 active_chains;
+ u8 scan_tx_antennas = hw_params(priv).valid_tx_ant;
+ int ret;
+
+ lockdep_assert_held(&priv->shrd->mutex);
+
+ if (vif)
+ ctx = iwl_rxon_ctx_from_vif(vif);
+
+ if (!priv->scan_cmd) {
+ priv->scan_cmd = kmalloc(sizeof(struct iwl_scan_cmd) +
+ IWL_MAX_SCAN_SIZE, GFP_KERNEL);
+ if (!priv->scan_cmd) {
+ IWL_DEBUG_SCAN(priv,
+ "fail to allocate memory for scan\n");
+ return -ENOMEM;
+ }
+ }
+ scan = priv->scan_cmd;
+ memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE);
+
+ scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
+ scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
+
+ if (priv->scan_type != IWL_SCAN_ROC &&
+ iwl_is_any_associated(priv)) {
+ u16 interval = 0;
+ u32 extra;
+ u32 suspend_time = 100;
+ u32 scan_suspend_time = 100;
+
+ IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
+ switch (priv->scan_type) {
+ case IWL_SCAN_ROC:
+ WARN_ON(1);
+ break;
+ case IWL_SCAN_RADIO_RESET:
+ interval = 0;
+ break;
+ case IWL_SCAN_NORMAL:
+ interval = vif->bss_conf.beacon_int;
+ break;
+ }
+
+ scan->suspend_time = 0;
+ scan->max_out_time = cpu_to_le32(200 * 1024);
+ if (!interval)
+ interval = suspend_time;
+
+ extra = (suspend_time / interval) << 22;
+ scan_suspend_time = (extra |
+ ((suspend_time % interval) * 1024));
+ scan->suspend_time = cpu_to_le32(scan_suspend_time);
+ IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n",
+ scan_suspend_time, interval);
+ } else if (priv->scan_type == IWL_SCAN_ROC) {
+ scan->suspend_time = 0;
+ scan->max_out_time = 0;
+ scan->quiet_time = 0;
+ scan->quiet_plcp_th = 0;
+ }
+
+ switch (priv->scan_type) {
+ case IWL_SCAN_RADIO_RESET:
+ IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n");
+ break;
+ case IWL_SCAN_NORMAL:
+ if (priv->scan_request->n_ssids) {
+ int i, p = 0;
+ IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
+ for (i = 0; i < priv->scan_request->n_ssids; i++) {
+ /* always does wildcard anyway */
+ if (!priv->scan_request->ssids[i].ssid_len)
+ continue;
+ scan->direct_scan[p].id = WLAN_EID_SSID;
+ scan->direct_scan[p].len =
+ priv->scan_request->ssids[i].ssid_len;
+ memcpy(scan->direct_scan[p].ssid,
+ priv->scan_request->ssids[i].ssid,
+ priv->scan_request->ssids[i].ssid_len);
+ n_probes++;
+ p++;
+ }
+ is_active = true;
+ } else
+ IWL_DEBUG_SCAN(priv, "Start passive scan.\n");
+ break;
+ case IWL_SCAN_ROC:
+ IWL_DEBUG_SCAN(priv, "Start ROC scan.\n");
+ break;
+ }
+
+ scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
+ scan->tx_cmd.sta_id = ctx->bcast_sta_id;
+ scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+
+ switch (priv->scan_band) {
+ case IEEE80211_BAND_2GHZ:
+ scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
+ chan_mod = le32_to_cpu(
+ priv->contexts[IWL_RXON_CTX_BSS].active.flags &
+ RXON_FLG_CHANNEL_MODE_MSK)
+ >> RXON_FLG_CHANNEL_MODE_POS;
+ if (chan_mod == CHANNEL_MODE_PURE_40) {
+ rate = IWL_RATE_6M_PLCP;
+ } else {
+ rate = IWL_RATE_1M_PLCP;
+ rate_flags = RATE_MCS_CCK_MSK;
+ }
/*
- * If we're associated, we clamp the maximum passive
- * dwell time to be 98% of the smallest beacon interval
- * (minus 2 * channel tune time)
+ * Internal scans are passive, so we can indiscriminately set
+ * the BT ignore flag on 2.4 GHz since it applies to TX only.
*/
- for_each_context(priv, ctx) {
- u16 value;
-
- if (!iwl_is_associated_ctx(ctx))
- continue;
- value = ctx->vif ? ctx->vif->bss_conf.beacon_int : 0;
- if ((value > IWL_PASSIVE_DWELL_BASE) || !value)
- value = IWL_PASSIVE_DWELL_BASE;
- value = (value * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
- passive = min(value, passive);
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->advanced_bt_coexist)
+ scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT;
+ break;
+ case IEEE80211_BAND_5GHZ:
+ rate = IWL_RATE_6M_PLCP;
+ break;
+ default:
+ IWL_WARN(priv, "Invalid scan band\n");
+ return -EIO;
+ }
+
+ /*
+ * If active scanning is requested but a certain channel is
+ * marked passive, we can do active scanning if we detect
+ * transmissions.
+ *
+ * There is an issue with some firmware versions that triggers
+ * a sysassert on a "good CRC threshold" of zero (== disabled),
+ * on a radar channel even though this means that we should NOT
+ * send probes.
+ *
+ * The "good CRC threshold" is the number of frames that we
+ * need to receive during our dwell time on a channel before
+ * sending out probes -- setting this to a huge value will
+ * mean we never reach it, but at the same time work around
+ * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER
+ * here instead of IWL_GOOD_CRC_TH_DISABLED.
+ *
+ * This was fixed in later versions along with some other
+ * scan changes, and the threshold behaves as a flag in those
+ * versions.
+ */
+ if (priv->new_scan_threshold_behaviour)
+ scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
+ IWL_GOOD_CRC_TH_DISABLED;
+ else
+ scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
+ IWL_GOOD_CRC_TH_NEVER;
+
+ band = priv->scan_band;
+
+ if (priv->cfg->scan_rx_antennas[band])
+ rx_ant = priv->cfg->scan_rx_antennas[band];
+
+ if (band == IEEE80211_BAND_2GHZ &&
+ priv->cfg->bt_params &&
+ priv->cfg->bt_params->advanced_bt_coexist) {
+ /* transmit 2.4 GHz probes only on first antenna */
+ scan_tx_antennas = first_antenna(scan_tx_antennas);
+ }
+
+ priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv,
+ priv->scan_tx_ant[band],
+ scan_tx_antennas);
+ rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]);
+ scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags);
+
+ /* In power save mode use one chain, otherwise use all chains */
+ if (test_bit(STATUS_POWER_PMI, &priv->shrd->status)) {
+ /* rx_ant has been set to all valid chains previously */
+ active_chains = rx_ant &
+ ((u8)(priv->chain_noise_data.active_chains));
+ if (!active_chains)
+ active_chains = rx_ant;
+
+ IWL_DEBUG_SCAN(priv, "chain_noise_data.active_chains: %u\n",
+ priv->chain_noise_data.active_chains);
+
+ rx_ant = first_antenna(active_chains);
+ }
+ if (priv->cfg->bt_params &&
+ priv->cfg->bt_params->advanced_bt_coexist &&
+ priv->bt_full_concurrent) {
+ /* operated as 1x1 in full concurrency mode */
+ rx_ant = first_antenna(rx_ant);
+ }
+
+ /* MIMO is not used here, but value is required */
+ rx_chain |=
+ hw_params(priv).valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
+ rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
+ rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS;
+ rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
+ scan->rx_chain = cpu_to_le16(rx_chain);
+ switch (priv->scan_type) {
+ case IWL_SCAN_NORMAL:
+ cmd_len = iwl_fill_probe_req(priv,
+ (struct ieee80211_mgmt *)scan->data,
+ vif->addr,
+ priv->scan_request->ie,
+ priv->scan_request->ie_len,
+ IWL_MAX_SCAN_SIZE - sizeof(*scan));
+ break;
+ 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,
+ (struct ieee80211_mgmt *)scan->data,
+ iwl_bcast_addr, NULL, 0,
+ IWL_MAX_SCAN_SIZE - sizeof(*scan));
+ break;
+ default:
+ BUG();
+ }
+ scan->tx_cmd.len = cpu_to_le16(cmd_len);
+
+ scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
+ RXON_FILTER_BCON_AWARE_MSK);
+
+ switch (priv->scan_type) {
+ case IWL_SCAN_RADIO_RESET:
+ scan->channel_count =
+ iwl_get_single_channel_for_scan(priv, vif, band,
+ (void *)&scan->data[cmd_len]);
+ break;
+ case IWL_SCAN_NORMAL:
+ scan->channel_count =
+ iwl_get_channels_for_scan(priv, vif, band,
+ is_active, n_probes,
+ (void *)&scan->data[cmd_len]);
+ break;
+ case IWL_SCAN_ROC: {
+ struct iwl_scan_channel *scan_ch;
+ int n_chan, i;
+ u16 dwell;
+
+ dwell = iwl_limit_dwell(priv, priv->hw_roc_duration);
+ n_chan = DIV_ROUND_UP(priv->hw_roc_duration, dwell);
+
+ scan->channel_count = n_chan;
+
+ scan_ch = (void *)&scan->data[cmd_len];
+
+ for (i = 0; i < n_chan; i++) {
+ scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
+ scan_ch->channel =
+ cpu_to_le16(priv->hw_roc_channel->hw_value);
+
+ if (i == n_chan - 1)
+ dwell = priv->hw_roc_duration - i * dwell;
+
+ scan_ch->active_dwell =
+ scan_ch->passive_dwell = cpu_to_le16(dwell);
+
+ /* Set txpower levels to defaults */
+ scan_ch->dsp_atten = 110;
+
+ /* NOTE: if we were doing 6Mb OFDM for scans we'd use
+ * power level:
+ * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
+ */
+ if (priv->hw_roc_channel->band == IEEE80211_BAND_5GHZ)
+ scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
+ else
+ scan_ch->tx_gain = ((1 << 5) | (5 << 3));
+
+ scan_ch++;
+ }
}
+
+ break;
+ }
+
+ if (scan->channel_count == 0) {
+ IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
+ return -EIO;
}
- return passive;
+ cmd.len[0] += le16_to_cpu(scan->tx_cmd.len) +
+ scan->channel_count * sizeof(struct iwl_scan_channel);
+ cmd.data[0] = scan;
+ cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
+ scan->len = cpu_to_le16(cmd.len[0]);
+
+ /* set scan bit here for PAN params */
+ set_bit(STATUS_SCAN_HW, &priv->shrd->status);
+
+ ret = iwlagn_set_pan_params(priv);
+ if (ret)
+ return ret;
+
+ ret = iwl_trans_send_cmd(trans(priv), &cmd);
+ if (ret) {
+ clear_bit(STATUS_SCAN_HW, &priv->shrd->status);
+ iwlagn_set_pan_params(priv);
+ }
+
+ return ret;
}
void iwl_init_scan_params(struct iwl_priv *priv)
{
- u8 ant_idx = fls(priv->hw_params.valid_tx_ant) - 1;
+ u8 ant_idx = fls(hw_params(priv).valid_tx_ant) - 1;
if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ])
priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = ant_idx;
if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ])
@@ -348,50 +895,50 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv,
{
int ret;
- lockdep_assert_held(&priv->mutex);
+ lockdep_assert_held(&priv->shrd->mutex);
cancel_delayed_work(&priv->scan_check);
- if (!iwl_is_ready_rf(priv)) {
+ if (!iwl_is_ready_rf(priv->shrd)) {
IWL_WARN(priv, "Request scan called when driver not ready.\n");
return -EIO;
}
- if (test_bit(STATUS_SCAN_HW, &priv->status)) {
+ if (test_bit(STATUS_SCAN_HW, &priv->shrd->status)) {
IWL_DEBUG_SCAN(priv,
"Multiple concurrent scan requests in parallel.\n");
return -EBUSY;
}
- if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ if (test_bit(STATUS_SCAN_ABORTING, &priv->shrd->status)) {
IWL_DEBUG_SCAN(priv, "Scan request while abort pending.\n");
return -EBUSY;
}
IWL_DEBUG_SCAN(priv, "Starting %sscan...\n",
scan_type == IWL_SCAN_NORMAL ? "" :
- scan_type == IWL_SCAN_OFFCH_TX ? "offchan TX " :
+ scan_type == IWL_SCAN_ROC ? "remain-on-channel " :
"internal short ");
- set_bit(STATUS_SCANNING, &priv->status);
+ set_bit(STATUS_SCANNING, &priv->shrd->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->status);
+ clear_bit(STATUS_SCANNING, &priv->shrd->status);
priv->scan_type = IWL_SCAN_NORMAL;
return ret;
}
- queue_delayed_work(priv->workqueue, &priv->scan_check,
+ queue_delayed_work(priv->shrd->workqueue, &priv->scan_check,
IWL_SCAN_CHECK_WATCHDOG);
return 0;
}
-int iwl_mac_hw_scan(struct ieee80211_hw *hw,
+int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_scan_request *req)
{
@@ -403,34 +950,36 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
if (req->n_channels == 0)
return -EINVAL;
- mutex_lock(&priv->mutex);
-
- if (test_bit(STATUS_SCANNING, &priv->status) &&
- priv->scan_type != IWL_SCAN_NORMAL) {
- IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
- ret = -EAGAIN;
- goto out_unlock;
- }
-
- /* mac80211 will only ask for one band at a time */
- priv->scan_request = req;
- priv->scan_vif = vif;
+ mutex_lock(&priv->shrd->mutex);
/*
* If an internal scan is in progress, just set
* up the scan_request as per above.
*/
if (priv->scan_type != IWL_SCAN_NORMAL) {
- IWL_DEBUG_SCAN(priv, "SCAN request during internal scan\n");
+ IWL_DEBUG_SCAN(priv,
+ "SCAN request during internal scan - defer\n");
+ priv->scan_request = req;
+ priv->scan_vif = vif;
ret = 0;
- } else
+ } else {
+ priv->scan_request = req;
+ priv->scan_vif = vif;
+ /*
+ * mac80211 will only ask for one band at a time
+ * so using channels[0] here is ok
+ */
ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL,
req->channels[0]->band);
+ if (ret) {
+ priv->scan_request = NULL;
+ priv->scan_vif = NULL;
+ }
+ }
IWL_DEBUG_MAC80211(priv, "leave\n");
-out_unlock:
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
return ret;
}
@@ -441,7 +990,7 @@ out_unlock:
*/
void iwl_internal_short_hw_scan(struct iwl_priv *priv)
{
- queue_work(priv->workqueue, &priv->start_internal_scan);
+ queue_work(priv->shrd->workqueue, &priv->start_internal_scan);
}
static void iwl_bg_start_internal_scan(struct work_struct *work)
@@ -451,14 +1000,14 @@ static void iwl_bg_start_internal_scan(struct work_struct *work)
IWL_DEBUG_SCAN(priv, "Start internal scan\n");
- mutex_lock(&priv->mutex);
+ mutex_lock(&priv->shrd->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->status)) {
+ if (test_bit(STATUS_SCANNING, &priv->shrd->status)) {
IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
goto unlock;
}
@@ -466,7 +1015,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->mutex);
+ mutex_unlock(&priv->shrd->mutex);
}
static void iwl_bg_scan_check(struct work_struct *data)
@@ -479,9 +1028,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->mutex);
+ mutex_lock(&priv->shrd->mutex);
iwl_force_scan_end(priv);
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
}
/**
@@ -539,70 +1088,19 @@ 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->mutex);
+ mutex_lock(&priv->shrd->mutex);
iwl_scan_cancel_timeout(priv, 200);
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
}
static void iwl_bg_scan_completed(struct work_struct *work)
{
struct iwl_priv *priv =
- container_of(work, struct iwl_priv, scan_completed);
- bool aborted;
-
- IWL_DEBUG_SCAN(priv, "Completed scan.\n");
-
- cancel_delayed_work(&priv->scan_check);
-
- mutex_lock(&priv->mutex);
-
- 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->status)) {
- IWL_DEBUG_SCAN(priv, "Scan already completed.\n");
- goto out_settings;
- }
-
- if (priv->scan_type == IWL_SCAN_OFFCH_TX && priv->offchan_tx_skb) {
- ieee80211_tx_status_irqsafe(priv->hw,
- priv->offchan_tx_skb);
- priv->offchan_tx_skb = NULL;
- }
-
- if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) {
- int err;
-
- /* Check if mac80211 requested scan during our internal scan */
- if (priv->scan_request == NULL)
- goto out_complete;
-
- /* If so request a new scan */
- err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL,
- priv->scan_request->channels[0]->band);
- if (err) {
- IWL_DEBUG_SCAN(priv,
- "failed to initiate pending scan: %d\n", err);
- aborted = true;
- goto out_complete;
- }
-
- goto out;
- }
-
-out_complete:
- iwl_complete_scan(priv, aborted);
-
-out_settings:
- /* Can we still talk to firmware ? */
- if (!iwl_is_ready_rf(priv))
- goto out;
-
- iwlagn_post_scan(priv);
+ container_of(work, struct iwl_priv, scan_completed);
-out:
- mutex_unlock(&priv->mutex);
+ mutex_lock(&priv->shrd->mutex);
+ iwl_process_scan_complete(priv);
+ mutex_unlock(&priv->shrd->mutex);
}
void iwl_setup_scan_deferred_work(struct iwl_priv *priv)
@@ -620,8 +1118,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->mutex);
+ mutex_lock(&priv->shrd->mutex);
iwl_force_scan_end(priv);
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
}
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h
new file mode 100644
index 000000000000..1f7a93c67c45
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-shared.h
@@ -0,0 +1,534 @@
+/******************************************************************************
+ *
+ * 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.
+ *
+ *****************************************************************************/
+#ifndef __iwl_shared_h__
+#define __iwl_shared_h__
+
+#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"
+
+/**
+ * DOC: shared area - role and goal
+ *
+ * The shared area contains all the data exported by the upper layer to the
+ * other layers. Since the bus and transport layer shouldn't dereference
+ * iwl_priv, all the data needed by the upper layer and the transport / bus
+ * layer must be here.
+ * The shared area also holds pointer to all the other layers. This allows a
+ * layer to call a function from another layer.
+ *
+ * NOTE: All the layers hold a pointer to the shared area which must be shrd.
+ * A few macros assume that (_m)->shrd points to the shared area no matter
+ * what _m is.
+ *
+ * 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
+ */
+
+struct iwl_cfg;
+struct iwl_bus;
+struct iwl_priv;
+struct iwl_sensitivity_ranges;
+struct iwl_trans_ops;
+
+#define DRV_NAME "iwlwifi"
+#define IWLWIFI_VERSION "in-tree:"
+#define DRV_COPYRIGHT "Copyright(c) 2003-2011 Intel Corporation"
+#define DRV_AUTHOR "<ilw@linux.intel.com>"
+
+extern struct iwl_mod_params iwlagn_mod_params;
+
+/**
+ * struct iwl_mod_params
+ *
+ * Holds the module parameters
+ *
+ * @sw_crypto: using hardware encryption, default = 0
+ * @num_of_queues: number of tx queue, HW dependent
+ * @disable_11n: 11n capabilities enabled, default = 0
+ * @amsdu_size_8K: enable 8K amsdu size, default = 1
+ * @antenna: both antennas (use diversity), default = 0
+ * @restart_fw: restart firmware, default = 1
+ * @plcp_check: enable plcp health check, default = true
+ * @ack_check: disable ack health check, default = false
+ * @wd_disable: enable stuck queue check, default = false
+ * @bt_coex_active: enable bt coex, default = true
+ * @led_mode: system default, default = 0
+ * @no_sleep_autoadjust: disable autoadjust, default = true
+ * @power_save: disable power save, default = false
+ * @power_level: power level, default = 1
+ * @debug_level: levels are IWL_DL_*
+ * @ant_coupling: antenna coupling in dB, default = 0
+ * @bt_ch_announce: BT channel inhibition, default = enable
+ * @wanted_ucode_alternative: ucode alternative to use, default = 1
+ * @auto_agg: enable agg. without check, default = true
+ */
+struct iwl_mod_params {
+ int sw_crypto;
+ int num_of_queues;
+ int disable_11n;
+ int amsdu_size_8K;
+ int antenna;
+ int restart_fw;
+ bool plcp_check;
+ bool ack_check;
+ bool wd_disable;
+ bool bt_coex_active;
+ int led_mode;
+ bool no_sleep_autoadjust;
+ bool power_save;
+ int power_level;
+ u32 debug_level;
+ int ant_coupling;
+ bool bt_ch_announce;
+ int wanted_ucode_alternative;
+ bool auto_agg;
+};
+
+/**
+ * struct iwl_hw_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
+ * @valid_tx_ant: usable antennas for TX
+ * @valid_rx_ant: usable antennas for RX
+ * @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
+ * @calib_init_cfg: setup initial calibrations for the hw
+ * @calib_rt_cfg: setup runtime calibrations for the hw
+ * @struct iwl_sensitivity_ranges: range of sensitivity values
+ */
+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;
+ 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;
+
+ u32 calib_init_cfg;
+ u32 calib_rt_cfg;
+ const struct iwl_sensitivity_ranges *sens;
+};
+
+/**
+ * enum iwl_agg_state
+ *
+ * The state machine of the BA agreement establishment / tear down.
+ * These states relate to a specific RA / TID.
+ *
+ * @IWL_AGG_OFF: aggregation is not used
+ * @IWL_AGG_ON: aggregation session is up
+ * @IWL_EMPTYING_HW_QUEUE_ADDBA: establishing a BA session - waiting for the
+ * HW queue to be empty from packets for this RA /TID.
+ * @IWL_EMPTYING_HW_QUEUE_DELBA: tearing down a BA session - waiting for the
+ * HW queue to be empty from packets for this RA /TID.
+ */
+enum iwl_agg_state {
+ IWL_AGG_OFF = 0,
+ IWL_AGG_ON,
+ IWL_EMPTYING_HW_QUEUE_ADDBA,
+ IWL_EMPTYING_HW_QUEUE_DELBA,
+};
+
+/**
+ * struct iwl_ht_agg - aggregation state machine
+
+ * This structs holds the states for the BA agreement establishment and tear
+ * down. It also holds the state during the BA session itself. This struct is
+ * duplicated for each RA / TID.
+
+ * @rate_n_flags: Rate at which Tx was attempted. Holds the data between the
+ * Tx response (REPLY_TX), and the block ack notification
+ * (REPLY_COMPRESSED_BA).
+ * @state: state of the BA agreement establishment / tear down.
+ * @txq_id: Tx queue used by the BA session - used by the transport layer.
+ * Needed by the upper layer for debugfs only.
+ * @wait_for_ba: Expect block-ack before next Tx reply
+ */
+struct iwl_ht_agg {
+ u32 rate_n_flags;
+ enum iwl_agg_state state;
+ u16 txq_id;
+ bool wait_for_ba;
+};
+
+/**
+ * struct iwl_tid_data - one for each RA / TID
+
+ * This structs holds the states for each RA / TID.
+
+ * @seq_number: the next WiFi sequence number to use
+ * @tfds_in_queue: number of packets sent to the HW queues.
+ * Exported for debugfs only
+ * @agg: aggregation state machine
+ */
+struct iwl_tid_data {
+ u16 seq_number;
+ u16 tfds_in_queue;
+ struct iwl_ht_agg agg;
+};
+
+/**
+ * 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_*
+ * @valid_contexts: microcode/device supports multiple contexts
+ * @bus: pointer to the bus layer data
+ * @priv: pointer to the upper layer 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:
+ */
+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_priv *priv;
+ struct iwl_trans *trans;
+ struct iwl_hw_params hw_params;
+
+ struct workqueue_struct *workqueue;
+ spinlock_t lock;
+ spinlock_t sta_lock;
+ struct mutex mutex;
+
+ struct iwl_tid_data tid_data[IWLAGN_STATION_COUNT][IWL_MAX_TID_COUNT];
+
+ wait_queue_head_t wait_command_queue;
+};
+
+/*Whatever _m is (iwl_trans, iwl_priv, iwl_bus, these macros will work */
+#define priv(_m) ((_m)->shrd->priv)
+#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)
+{
+ if (likely(tid < ARRAY_SIZE(tid_to_ac)))
+ return tid_to_ac[tid];
+
+ /* no support for TIDs 8-15 yet */
+ return -EINVAL;
+}
+
+enum iwl_rxon_context_id {
+ IWL_RXON_CTX_BSS,
+ IWL_RXON_CTX_PAN,
+
+ 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_start_tx_ba_trans_ready(struct iwl_priv *priv,
+ enum iwl_rxon_context_id ctx,
+ u8 sta_id, u8 tid);
+void iwl_stop_tx_ba_trans_ready(struct iwl_priv *priv,
+ enum iwl_rxon_context_id ctx,
+ u8 sta_id, u8 tid);
+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 iwl_apm_stop(struct iwl_priv *priv);
+int iwl_apm_init(struct iwl_priv *priv);
+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);
+
+#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
+******************************************************/
+#define STATUS_HCMD_ACTIVE 0 /* host command in progress */
+/* 1 is unused (used to be STATUS_HCMD_SYNC_ACTIVE) */
+#define STATUS_INT_ENABLED 2
+#define STATUS_RF_KILL_HW 3
+#define STATUS_CT_KILL 4
+#define STATUS_INIT 5
+#define STATUS_ALIVE 6
+#define STATUS_READY 7
+#define STATUS_TEMPERATURE 8
+#define STATUS_GEO_CONFIGURED 9
+#define STATUS_EXIT_PENDING 10
+#define STATUS_STATISTICS 12
+#define STATUS_SCANNING 13
+#define STATUS_SCAN_ABORTING 14
+#define STATUS_SCAN_HW 15
+#define STATUS_POWER_PMI 16
+#define STATUS_FW_ERROR 17
+#define STATUS_DEVICE_ENABLED 18
+#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__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
deleted file mode 100644
index 1ef3b7106ad5..000000000000
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ /dev/null
@@ -1,832 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- * Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#include <net/mac80211.h>
-#include <linux/etherdevice.h>
-#include <linux/sched.h>
-#include <linux/lockdep.h>
-
-#include "iwl-dev.h"
-#include "iwl-core.h"
-#include "iwl-sta.h"
-#include "iwl-trans.h"
-#include "iwl-agn.h"
-
-/* priv->sta_lock must be held */
-static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
-{
-
- if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE))
- IWL_ERR(priv, "ACTIVATE a non DRIVER active station id %u addr %pM\n",
- sta_id, priv->stations[sta_id].sta.sta.addr);
-
- if (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) {
- IWL_DEBUG_ASSOC(priv,
- "STA id %u addr %pM already present in uCode (according to driver)\n",
- sta_id, priv->stations[sta_id].sta.sta.addr);
- } else {
- priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE;
- IWL_DEBUG_ASSOC(priv, "Added STA id %u addr %pM to uCode\n",
- sta_id, priv->stations[sta_id].sta.sta.addr);
- }
-}
-
-static int iwl_process_add_sta_resp(struct iwl_priv *priv,
- struct iwl_addsta_cmd *addsta,
- struct iwl_rx_packet *pkt,
- bool sync)
-{
- u8 sta_id = addsta->sta.sta_id;
- unsigned long flags;
- int ret = -EIO;
-
- if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
- IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
- pkt->hdr.flags);
- return ret;
- }
-
- IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n",
- sta_id);
-
- spin_lock_irqsave(&priv->sta_lock, flags);
-
- switch (pkt->u.add_sta.status) {
- case ADD_STA_SUCCESS_MSK:
- IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n");
- iwl_sta_ucode_activate(priv, sta_id);
- ret = 0;
- break;
- case ADD_STA_NO_ROOM_IN_TABLE:
- IWL_ERR(priv, "Adding station %d failed, no room in table.\n",
- sta_id);
- break;
- case ADD_STA_NO_BLOCK_ACK_RESOURCE:
- IWL_ERR(priv, "Adding station %d failed, no block ack resource.\n",
- sta_id);
- break;
- case ADD_STA_MODIFY_NON_EXIST_STA:
- IWL_ERR(priv, "Attempting to modify non-existing station %d\n",
- sta_id);
- break;
- default:
- IWL_DEBUG_ASSOC(priv, "Received REPLY_ADD_STA:(0x%08X)\n",
- pkt->u.add_sta.status);
- break;
- }
-
- IWL_DEBUG_INFO(priv, "%s station id %u addr %pM\n",
- priv->stations[sta_id].sta.mode ==
- STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
- sta_id, priv->stations[sta_id].sta.sta.addr);
-
- /*
- * XXX: The MAC address in the command buffer is often changed from
- * the original sent to the device. That is, the MAC address
- * written to the command buffer often is not the same MAC address
- * read from the command buffer when the command returns. This
- * issue has not yet been resolved and this debugging is left to
- * observe the problem.
- */
- IWL_DEBUG_INFO(priv, "%s station according to cmd buffer %pM\n",
- priv->stations[sta_id].sta.mode ==
- STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
- addsta->sta.addr);
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-
- return ret;
-}
-
-static void iwl_add_sta_callback(struct iwl_priv *priv,
- struct iwl_device_cmd *cmd,
- struct iwl_rx_packet *pkt)
-{
- struct iwl_addsta_cmd *addsta =
- (struct iwl_addsta_cmd *)cmd->cmd.payload;
-
- iwl_process_add_sta_resp(priv, addsta, pkt, false);
-
-}
-
-static u16 iwlagn_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
-{
- u16 size = (u16)sizeof(struct iwl_addsta_cmd);
- struct iwl_addsta_cmd *addsta = (struct iwl_addsta_cmd *)data;
- memcpy(addsta, cmd, size);
- /* resrved in 5000 */
- addsta->rate_n_flags = cpu_to_le16(0);
- return size;
-}
-
-int iwl_send_add_sta(struct iwl_priv *priv,
- struct iwl_addsta_cmd *sta, u8 flags)
-{
- struct iwl_rx_packet *pkt = NULL;
- int ret = 0;
- u8 data[sizeof(*sta)];
- struct iwl_host_cmd cmd = {
- .id = REPLY_ADD_STA,
- .flags = flags,
- .data = { data, },
- };
- u8 sta_id __maybe_unused = sta->sta.sta_id;
-
- IWL_DEBUG_INFO(priv, "Adding sta %u (%pM) %ssynchronously\n",
- sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : "");
-
- if (flags & CMD_ASYNC)
- cmd.callback = iwl_add_sta_callback;
- else {
- cmd.flags |= CMD_WANT_SKB;
- might_sleep();
- }
-
- cmd.len[0] = iwlagn_build_addsta_hcmd(sta, data);
- ret = trans_send_cmd(&priv->trans, &cmd);
-
- if (ret || (flags & CMD_ASYNC))
- return ret;
-
- if (ret == 0) {
- pkt = (struct iwl_rx_packet *)cmd.reply_page;
- ret = iwl_process_add_sta_resp(priv, sta, pkt, true);
- }
- iwl_free_pages(priv, cmd.reply_page);
-
- return ret;
-}
-
-static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
- struct ieee80211_sta *sta,
- struct iwl_rxon_context *ctx)
-{
- struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap;
- __le32 sta_flags;
- u8 mimo_ps_mode;
-
- if (!sta || !sta_ht_inf->ht_supported)
- goto done;
-
- mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2;
- IWL_DEBUG_ASSOC(priv, "spatial multiplexing power save 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;
- break;
- case WLAN_HT_CAP_SM_PS_DYNAMIC:
- sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
- break;
- case WLAN_HT_CAP_SM_PS_DISABLED:
- break;
- default:
- IWL_WARN(priv, "Invalid MIMO PS mode %d\n", mimo_ps_mode);
- break;
- }
-
- sta_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);
-
- 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;
-
- priv->stations[index].sta.station_flags = sta_flags;
- done:
- return;
-}
-
-/**
- * iwl_prep_station - Prepare station information for addition
- *
- * should be called with sta_lock held
- */
-u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
- const u8 *addr, bool is_ap, struct ieee80211_sta *sta)
-{
- struct iwl_station_entry *station;
- int i;
- u8 sta_id = IWL_INVALID_STATION;
-
- if (is_ap)
- sta_id = ctx->ap_sta_id;
- else if (is_broadcast_ether_addr(addr))
- sta_id = ctx->bcast_sta_id;
- else
- for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) {
- if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
- addr)) {
- sta_id = i;
- break;
- }
-
- if (!priv->stations[i].used &&
- sta_id == IWL_INVALID_STATION)
- sta_id = i;
- }
-
- /*
- * These two conditions have the same outcome, but keep them
- * separate
- */
- if (unlikely(sta_id == IWL_INVALID_STATION))
- return sta_id;
-
- /*
- * uCode is not able to deal with multiple requests to add a
- * station. Keep track if one is in progress so that we do not send
- * another.
- */
- 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);
- return sta_id;
- }
-
- if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) &&
- (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) &&
- !compare_ether_addr(priv->stations[sta_id].sta.sta.addr, addr)) {
- IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not adding again.\n",
- sta_id, addr);
- return sta_id;
- }
-
- station = &priv->stations[sta_id];
- station->used = IWL_STA_DRIVER_ACTIVE;
- IWL_DEBUG_ASSOC(priv, "Add STA to driver ID %d: %pM\n",
- sta_id, addr);
- priv->num_stations++;
-
- /* Set up the REPLY_ADD_STA command to send to device */
- memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd));
- memcpy(station->sta.sta.addr, addr, ETH_ALEN);
- station->sta.mode = 0;
- station->sta.sta.sta_id = sta_id;
- station->sta.station_flags = ctx->station_flags;
- station->ctxid = ctx->ctxid;
-
- if (sta) {
- struct iwl_station_priv_common *sta_priv;
-
- sta_priv = (void *)sta->drv_priv;
- sta_priv->ctx = ctx;
- }
-
- /*
- * OK to call unconditionally, since local stations (IBSS BSSID
- * STA and broadcast STA) pass in a NULL sta, and mac80211
- * doesn't allow HT IBSS.
- */
- iwl_set_ht_add_station(priv, sta_id, sta, ctx);
-
- return sta_id;
-
-}
-
-#define STA_WAIT_TIMEOUT (HZ/2)
-
-/**
- * iwl_add_station_common -
- */
-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->sta_lock, flags_spin);
- 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->sta_lock, flags_spin);
- return -EINVAL;
- }
-
- /*
- * uCode is not able to deal with multiple requests to add a
- * station. Keep track if one is in progress so that we do not send
- * another.
- */
- 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->sta_lock, flags_spin);
- return -EEXIST;
- }
-
- if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) &&
- (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->sta_lock, flags_spin);
- 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->sta_lock, flags_spin);
-
- /* Add station to device's station table */
- ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
- if (ret) {
- spin_lock_irqsave(&priv->sta_lock, flags_spin);
- 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->sta_lock, flags_spin);
- }
- *sta_id_r = sta_id;
- return ret;
-}
-
-/**
- * iwl_sta_ucode_deactivate - deactivate ucode status for a station
- *
- * priv->sta_lock must be held
- */
-static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id)
-{
- /* Ucode must be active and driver must be non active */
- if ((priv->stations[sta_id].used &
- (IWL_STA_UCODE_ACTIVE | IWL_STA_DRIVER_ACTIVE)) != IWL_STA_UCODE_ACTIVE)
- IWL_ERR(priv, "removed non active STA %u\n", sta_id);
-
- priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE;
-
- memset(&priv->stations[sta_id], 0, sizeof(struct iwl_station_entry));
- IWL_DEBUG_ASSOC(priv, "Removed STA %u\n", sta_id);
-}
-
-static int iwl_send_remove_station(struct iwl_priv *priv,
- const u8 *addr, int sta_id,
- bool temporary)
-{
- struct iwl_rx_packet *pkt;
- int ret;
-
- unsigned long flags_spin;
- struct iwl_rem_sta_cmd rm_sta_cmd;
-
- struct iwl_host_cmd cmd = {
- .id = REPLY_REMOVE_STA,
- .len = { sizeof(struct iwl_rem_sta_cmd), },
- .flags = CMD_SYNC,
- .data = { &rm_sta_cmd, },
- };
-
- memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
- rm_sta_cmd.num_sta = 1;
- memcpy(&rm_sta_cmd.addr, addr, ETH_ALEN);
-
- cmd.flags |= CMD_WANT_SKB;
-
- ret = trans_send_cmd(&priv->trans, &cmd);
-
- if (ret)
- return ret;
-
- pkt = (struct iwl_rx_packet *)cmd.reply_page;
- if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
- IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
- pkt->hdr.flags);
- ret = -EIO;
- }
-
- if (!ret) {
- switch (pkt->u.rem_sta.status) {
- case REM_STA_SUCCESS_MSK:
- if (!temporary) {
- spin_lock_irqsave(&priv->sta_lock, flags_spin);
- iwl_sta_ucode_deactivate(priv, sta_id);
- spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
- }
- IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
- break;
- default:
- ret = -EIO;
- IWL_ERR(priv, "REPLY_REMOVE_STA failed\n");
- break;
- }
- }
- iwl_free_pages(priv, cmd.reply_page);
-
- return ret;
-}
-
-/**
- * iwl_remove_station - Remove driver's knowledge of station.
- */
-int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
- const u8 *addr)
-{
- unsigned long flags;
-
- if (!iwl_is_ready(priv)) {
- IWL_DEBUG_INFO(priv,
- "Unable to remove station %pM, device not ready.\n",
- addr);
- /*
- * It is typical for stations to be removed when we are
- * going down. Return success since device will be down
- * soon anyway
- */
- return 0;
- }
-
- IWL_DEBUG_ASSOC(priv, "Removing STA from driver:%d %pM\n",
- sta_id, addr);
-
- if (WARN_ON(sta_id == IWL_INVALID_STATION))
- return -EINVAL;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
-
- if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
- IWL_DEBUG_INFO(priv, "Removing %pM but non DRIVER active\n",
- addr);
- goto out_err;
- }
-
- if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) {
- IWL_DEBUG_INFO(priv, "Removing %pM but non UCODE active\n",
- addr);
- goto out_err;
- }
-
- if (priv->stations[sta_id].used & IWL_STA_LOCAL) {
- kfree(priv->stations[sta_id].lq);
- priv->stations[sta_id].lq = NULL;
- }
-
- priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
-
- priv->num_stations--;
-
- if (WARN_ON(priv->num_stations < 0))
- priv->num_stations = 0;
-
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-
- return iwl_send_remove_station(priv, addr, sta_id, false);
-out_err:
- spin_unlock_irqrestore(&priv->sta_lock, flags);
- return -EINVAL;
-}
-
-/**
- * iwl_clear_ucode_stations - clear ucode station table bits
- *
- * This function clears all the bits in the driver indicating
- * which stations are active in the ucode. Call when something
- * other than explicit station management would cause this in
- * the ucode, e.g. unassociated RXON.
- */
-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->sta_lock, flags_spin);
- for (i = 0; i < priv->hw_params.max_stations; i++) {
- if (ctx && ctx->ctxid != priv->stations[i].ctxid)
- continue;
-
- if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) {
- IWL_DEBUG_INFO(priv, "Clearing ucode active for station %d\n", i);
- priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
- cleared = true;
- }
- }
- spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
-
- if (!cleared)
- IWL_DEBUG_INFO(priv, "No active stations found to be cleared\n");
-}
-
-/**
- * iwl_restore_stations() - Restore driver known stations to device
- *
- * All stations considered active by driver, but not present in ucode, is
- * restored.
- *
- * Function sleeps.
- */
-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)) {
- 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->sta_lock, flags_spin);
- for (i = 0; i < priv->hw_params.max_stations; i++) {
- if (ctx->ctxid != priv->stations[i].ctxid)
- continue;
- if ((priv->stations[i].used & IWL_STA_DRIVER_ACTIVE) &&
- !(priv->stations[i].used & IWL_STA_UCODE_ACTIVE)) {
- IWL_DEBUG_ASSOC(priv, "Restoring sta %pM\n",
- priv->stations[i].sta.sta.addr);
- priv->stations[i].sta.mode = 0;
- priv->stations[i].used |= IWL_STA_UCODE_INPROGRESS;
- found = true;
- }
- }
-
- for (i = 0; i < priv->hw_params.max_stations; i++) {
- if ((priv->stations[i].used & IWL_STA_UCODE_INPROGRESS)) {
- memcpy(&sta_cmd, &priv->stations[i].sta,
- sizeof(struct iwl_addsta_cmd));
- send_lq = false;
- if (priv->stations[i].lq) {
- memcpy(&lq, priv->stations[i].lq,
- sizeof(struct iwl_link_quality_cmd));
- send_lq = true;
- }
- spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
- ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
- if (ret) {
- spin_lock_irqsave(&priv->sta_lock, flags_spin);
- 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->sta_lock, flags_spin);
- }
- /*
- * Rate scaling has already been initialized, send
- * current LQ command
- */
- if (send_lq)
- iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true);
- spin_lock_irqsave(&priv->sta_lock, flags_spin);
- priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS;
- }
- }
-
- spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
- if (!found)
- IWL_DEBUG_INFO(priv, "Restoring all known stations .... no stations to be restored.\n");
- else
- IWL_DEBUG_INFO(priv, "Restoring all known stations .... 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;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
- if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
- spin_unlock_irqrestore(&priv->sta_lock, flags);
- return;
- }
-
- memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd));
- sta_cmd.mode = 0;
- memcpy(&lq, priv->stations[sta_id].lq, sizeof(lq));
-
- active = priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE;
- priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
- spin_unlock_irqrestore(&priv->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->sta_lock, flags);
- priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE;
- spin_unlock_irqrestore(&priv->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);
- iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true);
-}
-
-int iwl_get_free_ucode_key_offset(struct iwl_priv *priv)
-{
- int i;
-
- for (i = 0; i < priv->sta_key_max_num; i++)
- if (!test_and_set_bit(i, &priv->ucode_key_table))
- return i;
-
- return WEP_INVALID_OFFSET;
-}
-
-void iwl_dealloc_bcast_stations(struct iwl_priv *priv)
-{
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
- for (i = 0; i < priv->hw_params.max_stations; i++) {
- if (!(priv->stations[i].used & IWL_STA_BCAST))
- continue;
-
- priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
- priv->num_stations--;
- if (WARN_ON(priv->num_stations < 0))
- priv->num_stations = 0;
- kfree(priv->stations[i].lq);
- priv->stations[i].lq = NULL;
- }
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-static void iwl_dump_lq_cmd(struct iwl_priv *priv,
- struct iwl_link_quality_cmd *lq)
-{
- int i;
- IWL_DEBUG_RATE(priv, "lq station id 0x%x\n", lq->sta_id);
- IWL_DEBUG_RATE(priv, "lq ant 0x%X 0x%X\n",
- lq->general_params.single_stream_ant_msk,
- lq->general_params.dual_stream_ant_msk);
-
- for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
- IWL_DEBUG_RATE(priv, "lq index %d 0x%X\n",
- i, lq->rs_table[i].rate_n_flags);
-}
-#else
-static inline void iwl_dump_lq_cmd(struct iwl_priv *priv,
- struct iwl_link_quality_cmd *lq)
-{
-}
-#endif
-
-/**
- * is_lq_table_valid() - Test one aspect of LQ cmd for validity
- *
- * It sometimes happens when a HT rate has been in use and we
- * loose connectivity with AP then mac80211 will first tell us that the
- * current channel is not HT anymore before removing the station. In such a
- * scenario the RXON flags will be updated to indicate we are not
- * communicating HT anymore, but the LQ command may still contain HT rates.
- * Test for this to prevent driver from sending LQ command between the time
- * RXON flags are updated and when LQ command is updated.
- */
-static bool is_lq_table_valid(struct iwl_priv *priv,
- struct iwl_rxon_context *ctx,
- struct iwl_link_quality_cmd *lq)
-{
- int i;
-
- if (ctx->ht.enabled)
- return true;
-
- IWL_DEBUG_INFO(priv, "Channel %u is not an HT channel\n",
- ctx->active.channel);
- for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
- if (le32_to_cpu(lq->rs_table[i].rate_n_flags) & RATE_MCS_HT_MSK) {
- IWL_DEBUG_INFO(priv,
- "index %d of LQ expects HT channel\n",
- i);
- return false;
- }
- }
- return true;
-}
-
-/**
- * iwl_send_lq_cmd() - Send link quality command
- * @init: This command is sent as part of station initialization right
- * after station has been added.
- *
- * The link quality command is sent as the last step of station creation.
- * This is the special case in which init is set and we call a callback in
- * this case to clear the state indicating that station creation is in
- * progress.
- */
-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), },
- .flags = flags,
- .data = { lq, },
- };
-
- if (WARN_ON(lq->sta_id == IWL_INVALID_STATION))
- return -EINVAL;
-
-
- spin_lock_irqsave(&priv->sta_lock, flags_spin);
- if (!(priv->stations[lq->sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
- spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
- return -EINVAL;
- }
- spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
-
- 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 = trans_send_cmd(&priv->trans, &cmd);
- else
- ret = -EINVAL;
-
- if (cmd.flags & CMD_ASYNC)
- return ret;
-
- if (init) {
- IWL_DEBUG_INFO(priv, "init LQ command complete, clearing sta addition status for sta %d\n",
- lq->sta_id);
- spin_lock_irqsave(&priv->sta_lock, flags_spin);
- priv->stations[lq->sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
- spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
- }
- return ret;
-}
-
-int iwl_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_common *sta_common = (void *)sta->drv_priv;
- int ret;
-
- IWL_DEBUG_INFO(priv, "received request to remove station %pM\n",
- sta->addr);
- mutex_lock(&priv->mutex);
- IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n",
- sta->addr);
- ret = iwl_remove_station(priv, sta_common->sta_id, sta->addr);
- if (ret)
- IWL_ERR(priv, "Error removing station %pM\n",
- sta->addr);
- mutex_unlock(&priv->mutex);
- return ret;
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h
deleted file mode 100644
index 9a6768d66851..000000000000
--- a/drivers/net/wireless/iwlwifi/iwl-sta.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- * Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-#ifndef __iwl_sta_h__
-#define __iwl_sta_h__
-
-#include "iwl-dev.h"
-
-#define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */
-#define IWL_STA_UCODE_ACTIVE BIT(1) /* ucode entry is active */
-#define IWL_STA_UCODE_INPROGRESS BIT(2) /* ucode entry is in process of
- being activated */
-#define IWL_STA_LOCAL BIT(3) /* station state not directed by mac80211;
- (this is for the IBSS BSSID stations) */
-#define IWL_STA_BCAST BIT(4) /* this station is the special bcast station */
-
-
-void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
-void iwl_clear_ucode_stations(struct iwl_priv *priv,
- struct iwl_rxon_context *ctx);
-void iwl_dealloc_bcast_stations(struct iwl_priv *priv);
-int iwl_get_free_ucode_key_offset(struct iwl_priv *priv);
-int iwl_send_add_sta(struct iwl_priv *priv,
- struct iwl_addsta_cmd *sta, u8 flags);
-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);
-int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
- const u8 *addr);
-int iwl_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
-
-u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
- const u8 *addr, bool is_ap, struct ieee80211_sta *sta);
-
-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);
-
-/**
- * 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->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->sta_lock, flags);
-}
-
-static inline int iwl_sta_id(struct ieee80211_sta *sta)
-{
- if (WARN_ON(!sta))
- return IWL_INVALID_STATION;
-
- return ((struct iwl_station_priv_common *)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;
-}
-#endif /* __iwl_sta_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-sv-open.c b/drivers/net/wireless/iwlwifi/iwl-sv-open.c
index b11f60de4f1e..5e50d88f302b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sv-open.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sv-open.c
@@ -63,6 +63,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/dma-mapping.h>
#include <net/net_namespace.h>
#include <linux/netdevice.h>
#include <net/cfg80211.h>
@@ -72,7 +73,6 @@
#include "iwl-dev.h"
#include "iwl-core.h"
#include "iwl-debug.h"
-#include "iwl-fh.h"
#include "iwl-io.h"
#include "iwl-agn.h"
#include "iwl-testmode.h"
@@ -184,7 +184,7 @@ static void iwl_trace_cleanup(struct iwl_priv *priv)
if (priv->testmode_trace.trace_enabled) {
if (priv->testmode_trace.cpu_addr &&
priv->testmode_trace.dma_addr)
- dma_free_coherent(priv->bus->dev,
+ dma_free_coherent(bus(priv)->dev,
priv->testmode_trace.total_size,
priv->testmode_trace.cpu_addr,
priv->testmode_trace.dma_addr);
@@ -239,7 +239,7 @@ static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb)
IWL_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 trans_send_cmd(&priv->trans, &cmd);
+ return iwl_trans_send_cmd(trans(priv), &cmd);
}
@@ -277,7 +277,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
case IWL_TM_CMD_APP2DEV_REG_READ32:
- val32 = iwl_read32(priv, ofs);
+ val32 = iwl_read32(bus(priv), ofs);
IWL_INFO(priv, "32bit value to read 0x%x\n", val32);
skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
@@ -299,7 +299,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
} else {
val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]);
IWL_INFO(priv, "32bit value to write 0x%x\n", val32);
- iwl_write32(priv, ofs, val32);
+ iwl_write32(bus(priv), ofs, val32);
}
break;
case IWL_TM_CMD_APP2DEV_REG_WRITE8:
@@ -309,7 +309,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
} else {
val8 = nla_get_u8(tb[IWL_TM_ATTR_REG_VALUE8]);
IWL_INFO(priv, "8bit value to write 0x%x\n", val8);
- iwl_write8(priv, ofs, val8);
+ iwl_write8(bus(priv), ofs, val8);
}
break;
default:
@@ -405,7 +405,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
iwl_testmode_cfg_init_calib(priv);
- trans_stop_device(&priv->trans);
+ iwl_trans_stop_device(trans(priv));
break;
case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
@@ -484,7 +484,7 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb)
struct iwl_priv *priv = hw->priv;
struct sk_buff *skb;
int status = 0;
- struct device *dev = priv->bus->dev;
+ struct device *dev = bus(priv)->dev;
switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
case IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
@@ -613,7 +613,7 @@ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb)
owner = nla_get_u8(tb[IWL_TM_ATTR_UCODE_OWNER]);
if ((owner == IWL_OWNERSHIP_DRIVER) || (owner == IWL_OWNERSHIP_TM))
- priv->ucode_owner = owner;
+ priv->shrd->ucode_owner = owner;
else {
IWL_DEBUG_INFO(priv, "Invalid owner\n");
return -EINVAL;
@@ -641,7 +641,7 @@ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb)
* @data: pointer to user space message
* @len: length in byte of @data
*/
-int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
+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;
@@ -661,7 +661,7 @@ int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
return -ENOMSG;
}
/* in case multiple accesses to the device happens */
- mutex_lock(&priv->mutex);
+ mutex_lock(&priv->shrd->mutex);
switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
case IWL_TM_CMD_APP2DEV_UCODE:
@@ -702,11 +702,11 @@ int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
break;
}
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
return result;
}
-int iwl_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
+int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
struct netlink_callback *cb,
void *data, int len)
{
@@ -738,7 +738,7 @@ int iwl_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
}
/* in case multiple accesses to the device happens */
- mutex_lock(&priv->mutex);
+ mutex_lock(&priv->shrd->mutex);
switch (cmd) {
case IWL_TM_CMD_APP2DEV_READ_TRACE:
IWL_DEBUG_INFO(priv, "uCode trace cmd to driver\n");
@@ -749,6 +749,6 @@ int iwl_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
break;
}
- mutex_unlock(&priv->mutex);
+ mutex_unlock(&priv->shrd->mutex);
return result;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-int-pcie.h b/drivers/net/wireless/iwlwifi/iwl-trans-int-pcie.h
deleted file mode 100644
index b79330d84185..000000000000
--- a/drivers/net/wireless/iwlwifi/iwl-trans-int-pcie.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- * Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-#ifndef __iwl_trans_int_pcie_h__
-#define __iwl_trans_int_pcie_h__
-
-/*This file includes the declaration that are internal to the
- * trans_pcie layer */
-
-/*****************************************************
-* RX
-******************************************************/
-void iwl_bg_rx_replenish(struct work_struct *data);
-void iwl_irq_tasklet(struct iwl_priv *priv);
-void iwlagn_rx_replenish(struct iwl_priv *priv);
-void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
- struct iwl_rx_queue *q);
-
-/*****************************************************
-* ICT
-******************************************************/
-int iwl_reset_ict(struct iwl_priv *priv);
-void iwl_disable_ict(struct iwl_priv *priv);
-int iwl_alloc_isr_ict(struct iwl_priv *priv);
-void iwl_free_isr_ict(struct iwl_priv *priv);
-irqreturn_t iwl_isr_ict(int irq, void *data);
-
-
-/*****************************************************
-* TX / HCMD
-******************************************************/
-void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
-void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq,
- int index);
-int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv,
- struct iwl_tx_queue *txq,
- dma_addr_t addr, u16 len, u8 reset);
-int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
- int count, int slots_num, u32 id);
-int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
-int __must_check iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u32 flags,
- u16 len, const void *data);
-void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
-void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
- struct iwl_tx_queue *txq,
- u16 byte_cnt);
-int iwl_trans_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
- u16 ssn_idx, u8 tx_fifo);
-void iwl_trans_set_wr_ptrs(struct iwl_priv *priv,
- int txq_id, u32 index);
-void iwl_trans_tx_queue_set_status(struct iwl_priv *priv,
- struct iwl_tx_queue *txq,
- int tx_fifo_id, int scd_retry);
-void iwl_trans_txq_agg_setup(struct iwl_priv *priv, int sta_id, int tid,
- int frame_limit);
-
-#endif /* __iwl_trans_int_pcie_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
new file mode 100644
index 000000000000..2b6756e8b8f9
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
@@ -0,0 +1,436 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#ifndef __iwl_trans_int_pcie_h__
+#define __iwl_trans_int_pcie_h__
+
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/skbuff.h>
+#include <linux/pci.h>
+
+#include "iwl-fh.h"
+#include "iwl-csr.h"
+#include "iwl-shared.h"
+#include "iwl-trans.h"
+#include "iwl-debug.h"
+#include "iwl-io.h"
+
+struct iwl_tx_queue;
+struct iwl_queue;
+struct iwl_host_cmd;
+
+/*This file includes the declaration that are internal to the
+ * trans_pcie layer */
+
+/**
+ * struct isr_statistics - interrupt statistics
+ *
+ */
+struct isr_statistics {
+ u32 hw;
+ u32 sw;
+ u32 err_code;
+ u32 sch;
+ u32 alive;
+ u32 rfkill;
+ u32 ctkill;
+ u32 wakeup;
+ u32 rx;
+ u32 tx;
+ u32 unhandled;
+};
+
+/**
+ * struct iwl_rx_queue - Rx queue
+ * @bd: driver's pointer to buffer of receive buffer descriptors (rbd)
+ * @bd_dma: bus address of buffer of receive buffer descriptors (rbd)
+ * @pool:
+ * @queue:
+ * @read: Shared index to newest available Rx buffer
+ * @write: Shared index to oldest written Rx packet
+ * @free_count: Number of pre-allocated buffers in rx_free
+ * @write_actual:
+ * @rx_free: list of free SKBs for use
+ * @rx_used: List of Rx buffers with no SKB
+ * @need_update: flag to indicate we need to update read/write index
+ * @rb_stts: driver's pointer to receive buffer status
+ * @rb_stts_dma: bus address of receive buffer status
+ * @lock:
+ *
+ * NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers
+ */
+struct iwl_rx_queue {
+ __le32 *bd;
+ dma_addr_t bd_dma;
+ struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
+ struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
+ u32 read;
+ u32 write;
+ u32 free_count;
+ u32 write_actual;
+ struct list_head rx_free;
+ struct list_head rx_used;
+ int need_update;
+ struct iwl_rb_status *rb_stts;
+ dma_addr_t rb_stts_dma;
+ spinlock_t lock;
+};
+
+struct iwl_dma_ptr {
+ dma_addr_t dma;
+ void *addr;
+ size_t size;
+};
+
+/*
+ * This queue number is required for proper operation
+ * because the ucode will stop/start the scheduler as
+ * required.
+ */
+#define IWL_IPAN_MCAST_QUEUE 8
+
+struct iwl_cmd_meta {
+ /* only for SYNC commands, iff the reply skb is wanted */
+ struct iwl_host_cmd *source;
+
+ u32 flags;
+
+ DEFINE_DMA_UNMAP_ADDR(mapping);
+ DEFINE_DMA_UNMAP_LEN(len);
+};
+
+/*
+ * Generic queue structure
+ *
+ * Contains common data for Rx and Tx queues.
+ *
+ * Note the difference between n_bd and n_window: the hardware
+ * always assumes 256 descriptors, so n_bd is always 256 (unless
+ * there might be HW changes in the future). For the normal TX
+ * queues, n_window, which is the size of the software queue data
+ * is also 256; however, for the command queue, n_window is only
+ * 32 since we don't need so many commands pending. Since the HW
+ * still uses 256 BDs for DMA though, n_bd stays 256. As a result,
+ * the software buffers (in the variables @meta, @txb in struct
+ * iwl_tx_queue) only have 32 entries, while the HW buffers (@tfds
+ * in the same struct) have 256.
+ * This means that we end up with the following:
+ * HW entries: | 0 | ... | N * 32 | ... | N * 32 + 31 | ... | 255 |
+ * SW entries: | 0 | ... | 31 |
+ * where N is a number between 0 and 7. This means that the SW
+ * data is a window overlayed over the HW queue.
+ */
+struct iwl_queue {
+ int n_bd; /* number of BDs in this queue */
+ int write_ptr; /* 1-st empty entry (index) host_w*/
+ int read_ptr; /* last used entry (index) host_r*/
+ /* use for monitoring and recovering the stuck queue */
+ dma_addr_t dma_addr; /* physical addr for BD's */
+ int n_window; /* safe queue window */
+ u32 id;
+ int low_mark; /* low watermark, resume queue if free
+ * space more than this */
+ int high_mark; /* high watermark, stop queue if free
+ * space less than this */
+};
+
+/**
+ * struct iwl_tx_queue - Tx Queue for DMA
+ * @q: generic Rx/Tx queue descriptor
+ * @bd: base of circular buffer of TFDs
+ * @cmd: array of command/TX buffer pointers
+ * @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
+ * @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
+ * @sta_id: valid if sched_retry is set
+ * @tid: valid if sched_retry is set
+ *
+ * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame
+ * descriptors) and required locking structures.
+ */
+#define TFD_TX_CMD_SLOTS 256
+#define TFD_CMD_SLOTS 32
+
+struct iwl_tx_queue {
+ struct iwl_queue q;
+ struct iwl_tfd *tfds;
+ struct iwl_device_cmd **cmd;
+ struct iwl_cmd_meta *meta;
+ struct sk_buff **skbs;
+ unsigned long time_stamp;
+ u8 need_update;
+ u8 sched_retry;
+ u8 active;
+ u8 swq_id;
+
+ u16 sta_id;
+ u16 tid;
+};
+
+/**
+ * struct iwl_trans_pcie - PCIe transport specific data
+ * @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
+ * @scd_base_addr: scheduler sram base address in SRAM
+ * @scd_bc_tbls: pointer to the byte count table of the scheduler
+ * @kw: keep warm address
+ * @ac_to_fifo: to what fifo is a specifc AC mapped ?
+ * @ac_to_queue: to what tx queue is a specifc AC mapped ?
+ * @mcast_queue:
+ * @txq: Tx DMA processing queues
+ * @txq_ctx_active_msk: what queue is active
+ * queue_stopped: tracks what queue is stopped
+ * queue_stop_count: tracks what SW queue is stopped
+ */
+struct iwl_trans_pcie {
+ struct iwl_rx_queue rxq;
+ struct work_struct rx_replenish;
+ struct iwl_trans *trans;
+
+ /* INT ICT Table */
+ __le32 *ict_tbl;
+ void *ict_tbl_vir;
+ dma_addr_t ict_tbl_dma;
+ dma_addr_t aligned_ict_tbl_dma;
+ int ict_index;
+ u32 inta;
+ bool use_ict;
+ struct tasklet_struct irq_tasklet;
+ struct isr_statistics isr_stats;
+
+ u32 inta_mask;
+ u32 scd_base_addr;
+ struct iwl_dma_ptr scd_bc_tbls;
+ struct iwl_dma_ptr kw;
+
+ const u8 *ac_to_fifo[NUM_IWL_RXON_CTX];
+ const u8 *ac_to_queue[NUM_IWL_RXON_CTX];
+ u8 mcast_queue[NUM_IWL_RXON_CTX];
+
+ struct iwl_tx_queue *txq;
+ unsigned long txq_ctx_active_msk;
+#define IWL_MAX_HW_QUEUES 32
+ unsigned long queue_stopped[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)];
+ atomic_t queue_stop_count[4];
+};
+
+#define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \
+ ((struct iwl_trans_pcie *) ((_iwl_trans)->trans_specific))
+
+/*****************************************************
+* RX
+******************************************************/
+void iwl_bg_rx_replenish(struct work_struct *data);
+void iwl_irq_tasklet(struct iwl_trans *trans);
+void iwlagn_rx_replenish(struct iwl_trans *trans);
+void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans,
+ struct iwl_rx_queue *q);
+
+/*****************************************************
+* ICT
+******************************************************/
+int iwl_reset_ict(struct iwl_trans *trans);
+void iwl_disable_ict(struct iwl_trans *trans);
+int iwl_alloc_isr_ict(struct iwl_trans *trans);
+void iwl_free_isr_ict(struct iwl_trans *trans);
+irqreturn_t iwl_isr_ict(int irq, void *data);
+
+/*****************************************************
+* TX / HCMD
+******************************************************/
+void iwl_txq_update_write_ptr(struct iwl_trans *trans,
+ struct iwl_tx_queue *txq);
+int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans,
+ struct iwl_tx_queue *txq,
+ dma_addr_t addr, u16 len, u8 reset);
+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);
+void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
+ struct iwl_tx_queue *txq,
+ u16 byte_cnt);
+void iwl_trans_pcie_txq_agg_disable(struct iwl_trans *trans, int txq_id);
+int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans,
+ enum iwl_rxon_context_id ctx, int sta_id,
+ int tid);
+void iwl_trans_set_wr_ptrs(struct iwl_trans *trans, int txq_id, u32 index);
+void iwl_trans_tx_queue_set_status(struct iwl_trans *trans,
+ struct iwl_tx_queue *txq,
+ int tx_fifo_id, int scd_retry);
+int iwl_trans_pcie_tx_agg_alloc(struct iwl_trans *trans,
+ enum iwl_rxon_context_id ctx, int sta_id,
+ int tid, u16 *ssn);
+void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans,
+ enum iwl_rxon_context_id ctx,
+ int sta_id, int tid, int frame_limit);
+void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
+ int index, enum dma_data_direction dma_dir);
+int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
+ struct sk_buff_head *skbs);
+int iwl_queue_space(const struct iwl_queue *q);
+
+/*****************************************************
+* Error handling
+******************************************************/
+int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log,
+ char **buf, bool display);
+int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display);
+void iwl_dump_csr(struct iwl_trans *trans);
+
+/*****************************************************
+* Helpers
+******************************************************/
+static inline void iwl_disable_interrupts(struct iwl_trans *trans)
+{
+ clear_bit(STATUS_INT_ENABLED, &trans->shrd->status);
+
+ /* disable interrupts from uCode/NIC to host */
+ iwl_write32(bus(trans), CSR_INT_MASK, 0x00000000);
+
+ /* acknowledge/clear/reset any interrupts still pending
+ * from uCode or flow handler (Rx/Tx DMA) */
+ iwl_write32(bus(trans), CSR_INT, 0xffffffff);
+ iwl_write32(bus(trans), CSR_FH_INT_STATUS, 0xffffffff);
+ IWL_DEBUG_ISR(trans, "Disabled interrupts\n");
+}
+
+static inline void iwl_enable_interrupts(struct iwl_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);
+ iwl_write32(bus(trans), CSR_INT_MASK, trans_pcie->inta_mask);
+}
+
+/*
+ * we have 8 bits used like this:
+ *
+ * 7 6 5 4 3 2 1 0
+ * | | | | | | | |
+ * | | | | | | +-+-------- AC queue (0-3)
+ * | | | | | |
+ * | +-+-+-+-+------------ HW queue ID
+ * |
+ * +---------------------- unused
+ */
+static inline void iwl_set_swq_id(struct iwl_tx_queue *txq, u8 ac, u8 hwq)
+{
+ BUG_ON(ac > 3); /* only have 2 bits */
+ BUG_ON(hwq > 31); /* only use 5 bits */
+
+ txq->swq_id = (hwq << 2) | ac;
+}
+
+static inline void iwl_wake_queue(struct iwl_trans *trans,
+ struct iwl_tx_queue *txq)
+{
+ u8 queue = txq->swq_id;
+ u8 ac = queue & 3;
+ u8 hwq = (queue >> 2) & 0x1f;
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
+
+ if (test_and_clear_bit(hwq, trans_pcie->queue_stopped))
+ if (atomic_dec_return(&trans_pcie->queue_stop_count[ac]) <= 0)
+ iwl_wake_sw_queue(priv(trans), ac);
+}
+
+static inline void iwl_stop_queue(struct iwl_trans *trans,
+ struct iwl_tx_queue *txq)
+{
+ u8 queue = txq->swq_id;
+ u8 ac = queue & 3;
+ u8 hwq = (queue >> 2) & 0x1f;
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
+
+ if (!test_and_set_bit(hwq, trans_pcie->queue_stopped))
+ if (atomic_inc_return(&trans_pcie->queue_stop_count[ac]) > 0)
+ iwl_stop_sw_queue(priv(trans), ac);
+}
+
+#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)
+{
+ set_bit(txq_id, &trans_pcie->txq_ctx_active_msk);
+}
+
+static inline void iwl_txq_ctx_deactivate(struct iwl_trans_pcie *trans_pcie,
+ int txq_id)
+{
+ clear_bit(txq_id, &trans_pcie->txq_ctx_active_msk);
+}
+
+static inline int iwl_queue_used(const struct iwl_queue *q, int i)
+{
+ return q->write_ptr >= q->read_ptr ?
+ (i >= q->read_ptr && i < q->write_ptr) :
+ !(i < q->read_ptr && i >= q->write_ptr);
+}
+
+static inline u8 get_cmd_index(struct iwl_queue *q, u32 index)
+{
+ return index & (q->n_window - 1);
+}
+
+#define IWL_TX_FIFO_BK 0 /* shared */
+#define IWL_TX_FIFO_BE 1
+#define IWL_TX_FIFO_VI 2 /* shared */
+#define IWL_TX_FIFO_VO 3
+#define IWL_TX_FIFO_BK_IPAN IWL_TX_FIFO_BK
+#define IWL_TX_FIFO_BE_IPAN 4
+#define IWL_TX_FIFO_VI_IPAN IWL_TX_FIFO_VI
+#define IWL_TX_FIFO_VO_IPAN 5
+/* re-uses the VO FIFO, uCode will properly flush/schedule */
+#define IWL_TX_FIFO_AUX 5
+#define IWL_TX_FIFO_UNUSED -1
+
+/* AUX (TX during scan dwell) queue */
+#define IWL_AUX_QUEUE 10
+
+#endif /* __iwl_trans_int_pcie_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
new file mode 100644
index 000000000000..374c68cc1d70
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
@@ -0,0 +1,1435 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/gfp.h>
+
+/*TODO: Remove include to iwl-core.h*/
+#include "iwl-core.h"
+#include "iwl-io.h"
+#include "iwl-trans-pcie-int.h"
+
+/******************************************************************************
+ *
+ * RX path functions
+ *
+ ******************************************************************************/
+
+/*
+ * Rx theory of operation
+ *
+ * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs),
+ * each of which point to Receive Buffers to be filled by the NIC. These get
+ * used not only for Rx frames, but for any command response or notification
+ * from the NIC. The driver and NIC manage the Rx buffers by means
+ * of indexes into the circular buffer.
+ *
+ * Rx Queue Indexes
+ * The host/firmware share two index registers for managing the Rx buffers.
+ *
+ * The READ index maps to the first position that the firmware may be writing
+ * to -- the driver can read up to (but not including) this position and get
+ * good data.
+ * The READ index is managed by the firmware once the card is enabled.
+ *
+ * The WRITE index maps to the last position the driver has read from -- the
+ * position preceding WRITE is the last slot the firmware can place a packet.
+ *
+ * The queue is empty (no good data) if WRITE = READ - 1, and is full if
+ * WRITE = READ.
+ *
+ * During initialization, the host sets up the READ queue position to the first
+ * INDEX position, and WRITE to the last (READ - 1 wrapped)
+ *
+ * When the firmware places a packet in a buffer, it will advance the READ index
+ * and fire the RX interrupt. The driver can then query the READ index and
+ * process as many packets as possible, moving the WRITE index forward as it
+ * resets the Rx queue buffers with new memory.
+ *
+ * The management in the driver is as follows:
+ * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When
+ * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
+ * to replenish the iwl->rxq->rx_free.
+ * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the
+ * iwl->rxq is replenished and the READ INDEX is updated (updating the
+ * 'processed' and 'read' driver indexes as well)
+ * + A received packet is processed and handed to the kernel network stack,
+ * detached from the iwl->rxq. The driver 'processed' index is updated.
+ * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
+ * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
+ * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there
+ * were enough free buffers and RX_STALLED is set it is cleared.
+ *
+ *
+ * Driver sequence:
+ *
+ * iwl_rx_queue_alloc() Allocates rx_free
+ * iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls
+ * iwl_rx_queue_restock
+ * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx
+ * queue, updates firmware pointers, and updates
+ * the WRITE index. If insufficient rx_free buffers
+ * are available, schedules iwl_rx_replenish
+ *
+ * -- enable interrupts --
+ * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the
+ * READ INDEX, detaching the SKB from the pool.
+ * Moves the packet buffer from queue to rx_used.
+ * Calls iwl_rx_queue_restock to refill any empty
+ * slots.
+ * ...
+ *
+ */
+
+/**
+ * iwl_rx_queue_space - Return number of free slots available in queue.
+ */
+static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
+{
+ int s = q->read - q->write;
+ if (s <= 0)
+ s += RX_QUEUE_SIZE;
+ /* keep some buffer to not confuse full and empty queue */
+ s -= 2;
+ if (s < 0)
+ s = 0;
+ return s;
+}
+
+/**
+ * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
+ */
+void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans,
+ struct iwl_rx_queue *q)
+{
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&q->lock, flags);
+
+ if (q->need_update == 0)
+ goto exit_unlock;
+
+ if (hw_params(trans).shadow_reg_enable) {
+ /* shadow register enabled */
+ /* Device expects a multiple of 8 */
+ q->write_actual = (q->write & ~0x7);
+ iwl_write32(bus(trans), FH_RSCSR_CHNL0_WPTR, q->write_actual);
+ } else {
+ /* If power-saving is in use, make sure device is awake */
+ if (test_bit(STATUS_POWER_PMI, &trans->shrd->status)) {
+ reg = iwl_read32(bus(trans), CSR_UCODE_DRV_GP1);
+
+ if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+ IWL_DEBUG_INFO(trans,
+ "Rx queue requesting wakeup,"
+ " GP1 = 0x%x\n", reg);
+ iwl_set_bit(bus(trans), CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ goto exit_unlock;
+ }
+
+ q->write_actual = (q->write & ~0x7);
+ iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_WPTR,
+ q->write_actual);
+
+ /* Else device is assumed to be awake */
+ } else {
+ /* Device expects a multiple of 8 */
+ q->write_actual = (q->write & ~0x7);
+ iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_WPTR,
+ q->write_actual);
+ }
+ }
+ q->need_update = 0;
+
+ exit_unlock:
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+
+/**
+ * iwlagn_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
+ */
+static inline __le32 iwlagn_dma_addr2rbd_ptr(dma_addr_t dma_addr)
+{
+ return cpu_to_le32((u32)(dma_addr >> 8));
+}
+
+/**
+ * iwlagn_rx_queue_restock - refill RX queue from pre-allocated pool
+ *
+ * If there are slots in the RX queue that need to be restocked,
+ * and we have free pre-allocated buffers, fill the ranks as much
+ * as we can, pulling from rx_free.
+ *
+ * This moves the 'write' index forward to catch up with 'processed', and
+ * also updates the memory address in the firmware to reference the new
+ * target buffer.
+ */
+static void iwlagn_rx_queue_restock(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
+
+ struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+ struct list_head *element;
+ struct iwl_rx_mem_buffer *rxb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rxq->lock, flags);
+ while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
+ /* The overwritten rxb must be a used one */
+ rxb = rxq->queue[rxq->write];
+ BUG_ON(rxb && rxb->page);
+
+ /* Get next free Rx buffer, remove from free list */
+ element = rxq->rx_free.next;
+ rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+ list_del(element);
+
+ /* Point to Rx buffer via next RBD in circular buffer */
+ rxq->bd[rxq->write] = iwlagn_dma_addr2rbd_ptr(rxb->page_dma);
+ rxq->queue[rxq->write] = rxb;
+ rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
+ rxq->free_count--;
+ }
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ /* 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);
+
+
+ /* If we've added more space for the firmware to place data, tell it.
+ * Increment device's write pointer in multiples of 8. */
+ if (rxq->write_actual != (rxq->write & ~0x7)) {
+ spin_lock_irqsave(&rxq->lock, flags);
+ rxq->need_update = 1;
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ iwl_rx_queue_update_write_ptr(trans, rxq);
+ }
+}
+
+/**
+ * iwlagn_rx_replenish - Move all used packet from rx_used to rx_free
+ *
+ * When moving to rx_free an SKB is allocated for the slot.
+ *
+ * Also restock the Rx queue via iwl_rx_queue_restock.
+ * This is called as a scheduled work item (except for during initialization)
+ */
+static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority)
+{
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
+
+ struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+ struct list_head *element;
+ struct iwl_rx_mem_buffer *rxb;
+ struct page *page;
+ unsigned long flags;
+ gfp_t gfp_mask = priority;
+
+ while (1) {
+ spin_lock_irqsave(&rxq->lock, flags);
+ if (list_empty(&rxq->rx_used)) {
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&rxq->lock, flags);
+
+ if (rxq->free_count > RX_LOW_WATERMARK)
+ gfp_mask |= __GFP_NOWARN;
+
+ if (hw_params(trans).rx_page_order > 0)
+ gfp_mask |= __GFP_COMP;
+
+ /* Alloc a new receive buffer */
+ page = alloc_pages(gfp_mask,
+ hw_params(trans).rx_page_order);
+ if (!page) {
+ if (net_ratelimit())
+ IWL_DEBUG_INFO(trans, "alloc_pages failed, "
+ "order: %d\n",
+ hw_params(trans).rx_page_order);
+
+ if ((rxq->free_count <= RX_LOW_WATERMARK) &&
+ net_ratelimit())
+ IWL_CRIT(trans, "Failed to alloc_pages with %s."
+ "Only %u free buffers remaining.\n",
+ priority == GFP_ATOMIC ?
+ "GFP_ATOMIC" : "GFP_KERNEL",
+ rxq->free_count);
+ /* We don't reschedule replenish work here -- we will
+ * call the restock method and if it still needs
+ * more buffers it will schedule replenish */
+ return;
+ }
+
+ spin_lock_irqsave(&rxq->lock, flags);
+
+ if (list_empty(&rxq->rx_used)) {
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ __free_pages(page, hw_params(trans).rx_page_order);
+ return;
+ }
+ element = rxq->rx_used.next;
+ rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+ list_del(element);
+
+ spin_unlock_irqrestore(&rxq->lock, flags);
+
+ BUG_ON(rxb->page);
+ rxb->page = page;
+ /* Get physical address of the RB */
+ rxb->page_dma = dma_map_page(bus(trans)->dev, page, 0,
+ PAGE_SIZE << hw_params(trans).rx_page_order,
+ DMA_FROM_DEVICE);
+ /* dma address must be no more than 36 bits */
+ BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
+ /* and also 256 byte aligned! */
+ BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
+
+ spin_lock_irqsave(&rxq->lock, flags);
+
+ list_add_tail(&rxb->list, &rxq->rx_free);
+ rxq->free_count++;
+
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ }
+}
+
+void iwlagn_rx_replenish(struct iwl_trans *trans)
+{
+ unsigned long flags;
+
+ iwlagn_rx_allocate(trans, GFP_KERNEL);
+
+ spin_lock_irqsave(&trans->shrd->lock, flags);
+ iwlagn_rx_queue_restock(trans);
+ spin_unlock_irqrestore(&trans->shrd->lock, flags);
+}
+
+static void iwlagn_rx_replenish_now(struct iwl_trans *trans)
+{
+ iwlagn_rx_allocate(trans, GFP_ATOMIC);
+
+ iwlagn_rx_queue_restock(trans);
+}
+
+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))
+ return;
+
+ mutex_lock(&trans->shrd->mutex);
+ iwlagn_rx_replenish(trans);
+ mutex_unlock(&trans->shrd->mutex);
+}
+
+/**
+ * iwl_rx_handle - Main entry function for receiving responses from uCode
+ *
+ * Uses the priv->rx_handlers callback function array to invoke
+ * the appropriate handlers, including command responses,
+ * frame-received notifications, and other notifications.
+ */
+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_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). */
+ r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF;
+ i = rxq->read;
+
+ /* Rx interrupt, but nothing sent from uCode */
+ if (i == r)
+ IWL_DEBUG_RX(trans, "r = %d, i = %d\n", r, i);
+
+ /* calculate total frames need to be restock after handling RX */
+ total_empty = r - rxq->write_actual;
+ if (total_empty < 0)
+ total_empty += RX_QUEUE_SIZE;
+
+ if (total_empty > (RX_QUEUE_SIZE / 2))
+ fill_rx = 1;
+
+ while (i != r) {
+ int len, err;
+ u16 sequence;
+
+ 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(bus(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);
+
+ /*
+ * 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(bus(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);
+
+ i = (i + 1) & RX_QUEUE_MASK;
+ /* If there are a lot of unused frames,
+ * restock the Rx queue so ucode wont assert. */
+ if (fill_rx) {
+ count++;
+ if (count >= 8) {
+ rxq->read = i;
+ iwlagn_rx_replenish_now(trans);
+ count = 0;
+ }
+ }
+ }
+
+ /* Backtrack one entry */
+ rxq->read = i;
+ if (fill_rx)
+ iwlagn_rx_replenish_now(trans);
+ else
+ iwlagn_rx_queue_restock(trans);
+}
+
+static const char * const desc_lookup_text[] = {
+ "OK",
+ "FAIL",
+ "BAD_PARAM",
+ "BAD_CHECKSUM",
+ "NMI_INTERRUPT_WDG",
+ "SYSASSERT",
+ "FATAL_ERROR",
+ "BAD_COMMAND",
+ "HW_ERROR_TUNE_LOCK",
+ "HW_ERROR_TEMPERATURE",
+ "ILLEGAL_CHAN_FREQ",
+ "VCC_NOT_STABLE",
+ "FH_ERROR",
+ "NMI_INTERRUPT_HOST",
+ "NMI_INTERRUPT_ACTION_PT",
+ "NMI_INTERRUPT_UNKNOWN",
+ "UCODE_VERSION_MISMATCH",
+ "HW_ERROR_ABS_LOCK",
+ "HW_ERROR_CAL_LOCK_FAIL",
+ "NMI_INTERRUPT_INST_ACTION_PT",
+ "NMI_INTERRUPT_DATA_ACTION_PT",
+ "NMI_TRM_HW_ER",
+ "NMI_INTERRUPT_TRM",
+ "NMI_INTERRUPT_BREAK_POINT",
+ "DEBUG_0",
+ "DEBUG_1",
+ "DEBUG_2",
+ "DEBUG_3",
+};
+
+static struct { char *name; u8 num; } advanced_lookup[] = {
+ { "NMI_INTERRUPT_WDG", 0x34 },
+ { "SYSASSERT", 0x35 },
+ { "UCODE_VERSION_MISMATCH", 0x37 },
+ { "BAD_COMMAND", 0x38 },
+ { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C },
+ { "FATAL_ERROR", 0x3D },
+ { "NMI_TRM_HW_ERR", 0x46 },
+ { "NMI_INTERRUPT_TRM", 0x4C },
+ { "NMI_INTERRUPT_BREAK_POINT", 0x54 },
+ { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C },
+ { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 },
+ { "NMI_INTERRUPT_HOST", 0x66 },
+ { "NMI_INTERRUPT_ACTION_PT", 0x7C },
+ { "NMI_INTERRUPT_UNKNOWN", 0x84 },
+ { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 },
+ { "ADVANCED_SYSASSERT", 0 },
+};
+
+static const char *desc_lookup(u32 num)
+{
+ int i;
+ int max = ARRAY_SIZE(desc_lookup_text);
+
+ if (num < max)
+ return desc_lookup_text[num];
+
+ max = ARRAY_SIZE(advanced_lookup) - 1;
+ for (i = 0; i < max; i++) {
+ if (advanced_lookup[i].num == num)
+ break;
+ }
+ return advanced_lookup[i].name;
+}
+
+#define ERROR_START_OFFSET (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE (7 * sizeof(u32))
+
+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 = priv->device_pointers.error_event_table;
+ if (priv->ucode_type == IWL_UCODE_INIT) {
+ if (!base)
+ base = priv->init_errlog_ptr;
+ } else {
+ if (!base)
+ base = priv->inst_errlog_ptr;
+ }
+
+ if (!iwlagn_hw_valid_rtc_data_addr(base)) {
+ IWL_ERR(trans,
+ "Not valid error log pointer 0x%08X for %s uCode\n",
+ base,
+ (priv->ucode_type == IWL_UCODE_INIT)
+ ? "Init" : "RT");
+ return;
+ }
+
+ iwl_read_targ_mem_words(bus(priv), base, &table, sizeof(table));
+
+ if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
+ IWL_ERR(trans, "Start IWL Error Log Dump:\n");
+ IWL_ERR(trans, "Status: 0x%08lX, count: %d\n",
+ trans->shrd->status, table.valid);
+ }
+
+ trans_pcie->isr_stats.err_code = table.error_id;
+
+ trace_iwlwifi_dev_ucode_error(priv, 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,
+ table.gp2, table.gp3, table.ucode_ver,
+ table.hw_ver, table.brd_ver);
+ IWL_ERR(trans, "0x%08X | %-28s\n", table.error_id,
+ desc_lookup(table.error_id));
+ IWL_ERR(trans, "0x%08X | uPc\n", table.pc);
+ IWL_ERR(trans, "0x%08X | branchlink1\n", table.blink1);
+ IWL_ERR(trans, "0x%08X | branchlink2\n", table.blink2);
+ IWL_ERR(trans, "0x%08X | interruptlink1\n", table.ilink1);
+ IWL_ERR(trans, "0x%08X | interruptlink2\n", table.ilink2);
+ IWL_ERR(trans, "0x%08X | data1\n", table.data1);
+ IWL_ERR(trans, "0x%08X | data2\n", table.data2);
+ IWL_ERR(trans, "0x%08X | line\n", table.line);
+ IWL_ERR(trans, "0x%08X | beacon time\n", table.bcon_time);
+ IWL_ERR(trans, "0x%08X | tsf low\n", table.tsf_low);
+ IWL_ERR(trans, "0x%08X | tsf hi\n", table.tsf_hi);
+ IWL_ERR(trans, "0x%08X | time gp1\n", table.gp1);
+ IWL_ERR(trans, "0x%08X | time gp2\n", table.gp2);
+ IWL_ERR(trans, "0x%08X | time gp3\n", table.gp3);
+ IWL_ERR(trans, "0x%08X | uCode version\n", table.ucode_ver);
+ IWL_ERR(trans, "0x%08X | hw version\n", table.hw_ver);
+ IWL_ERR(trans, "0x%08X | board version\n", table.brd_ver);
+ IWL_ERR(trans, "0x%08X | hcmd\n", table.hcmd);
+}
+
+/**
+ * iwl_irq_handle_error - called for HW or SW error interrupt from card
+ */
+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 (priv->cfg->internal_wimax_coex &&
+ (!(iwl_read_prph(bus(trans), APMG_CLK_CTRL_REG) &
+ APMS_CLK_VAL_MRB_FUNC_MODE) ||
+ (iwl_read_prph(bus(trans), APMG_PS_CTRL_REG) &
+ APMG_PS_CTRL_VAL_RESET_REQ))) {
+ /*
+ * Keep the restart process from trying to send host
+ * commands by clearing the ready bit.
+ */
+ clear_bit(STATUS_READY, &trans->shrd->status);
+ clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status);
+ wake_up(&priv->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);
+
+ 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);
+}
+
+#define EVENT_START_OFFSET (4 * sizeof(u32))
+
+/**
+ * iwl_print_event_log - Dump error event log to syslog
+ *
+ */
+static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx,
+ u32 num_events, u32 mode,
+ int pos, char **buf, size_t bufsz)
+{
+ u32 i;
+ u32 base; /* SRAM byte address of event log header */
+ u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
+ 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;
+
+ base = priv->device_pointers.log_event_table;
+ if (priv->ucode_type == IWL_UCODE_INIT) {
+ if (!base)
+ base = priv->init_evtlog_ptr;
+ } else {
+ if (!base)
+ base = priv->inst_evtlog_ptr;
+ }
+
+ if (mode == 0)
+ event_size = 2 * sizeof(u32);
+ else
+ event_size = 3 * sizeof(u32);
+
+ ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
+
+ /* Make sure device is powered up for SRAM reads */
+ spin_lock_irqsave(&bus(trans)->reg_lock, reg_flags);
+ iwl_grab_nic_access(bus(trans));
+
+ /* Set starting address; reads will auto-increment */
+ iwl_write32(bus(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. */
+ for (i = 0; i < num_events; i++) {
+ ev = iwl_read32(bus(trans), HBUS_TARG_MEM_RDAT);
+ time = iwl_read32(bus(trans), HBUS_TARG_MEM_RDAT);
+ if (mode == 0) {
+ /* data, ev */
+ if (bufsz) {
+ pos += scnprintf(*buf + pos, bufsz - pos,
+ "EVT_LOG:0x%08x:%04u\n",
+ time, ev);
+ } else {
+ trace_iwlwifi_dev_ucode_event(priv, 0,
+ time, ev);
+ IWL_ERR(trans, "EVT_LOG:0x%08x:%04u\n",
+ time, ev);
+ }
+ } else {
+ data = iwl_read32(bus(trans), HBUS_TARG_MEM_RDAT);
+ if (bufsz) {
+ pos += scnprintf(*buf + pos, bufsz - pos,
+ "EVT_LOGT:%010u:0x%08x:%04u\n",
+ time, data, ev);
+ } else {
+ IWL_ERR(trans, "EVT_LOGT:%010u:0x%08x:%04u\n",
+ time, data, ev);
+ trace_iwlwifi_dev_ucode_event(priv, time,
+ data, ev);
+ }
+ }
+ }
+
+ /* Allow device to power down */
+ iwl_release_nic_access(bus(trans));
+ spin_unlock_irqrestore(&bus(trans)->reg_lock, reg_flags);
+ return pos;
+}
+
+/**
+ * iwl_print_last_event_logs - Dump the newest # of event log to syslog
+ */
+static int iwl_print_last_event_logs(struct iwl_trans *trans, u32 capacity,
+ u32 num_wraps, u32 next_entry,
+ u32 size, u32 mode,
+ int pos, char **buf, size_t bufsz)
+{
+ /*
+ * display the newest DEFAULT_LOG_ENTRIES entries
+ * i.e the entries just before the next ont that uCode would fill.
+ */
+ if (num_wraps) {
+ if (next_entry < size) {
+ pos = iwl_print_event_log(trans,
+ capacity - (size - next_entry),
+ size - next_entry, mode,
+ pos, buf, bufsz);
+ pos = iwl_print_event_log(trans, 0,
+ next_entry, mode,
+ pos, buf, bufsz);
+ } else
+ pos = iwl_print_event_log(trans, next_entry - size,
+ size, mode, pos, buf, bufsz);
+ } else {
+ if (next_entry < size) {
+ pos = iwl_print_event_log(trans, 0, next_entry,
+ mode, pos, buf, bufsz);
+ } else {
+ pos = iwl_print_event_log(trans, next_entry - size,
+ size, mode, pos, buf, bufsz);
+ }
+ }
+ return pos;
+}
+
+#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20)
+
+int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log,
+ char **buf, bool display)
+{
+ u32 base; /* SRAM byte address of event log header */
+ u32 capacity; /* event log capacity in # entries */
+ u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
+ u32 num_wraps; /* # times uCode wrapped to top of log */
+ u32 next_entry; /* index of next entry to be written by uCode */
+ u32 size; /* # entries that we'll print */
+ u32 logsize;
+ int pos = 0;
+ size_t bufsz = 0;
+ struct iwl_priv *priv = priv(trans);
+
+ base = priv->device_pointers.log_event_table;
+ if (priv->ucode_type == IWL_UCODE_INIT) {
+ logsize = priv->init_evtlog_size;
+ if (!base)
+ base = priv->init_evtlog_ptr;
+ } else {
+ logsize = priv->inst_evtlog_size;
+ if (!base)
+ base = priv->inst_evtlog_ptr;
+ }
+
+ if (!iwlagn_hw_valid_rtc_data_addr(base)) {
+ IWL_ERR(trans,
+ "Invalid event log pointer 0x%08X for %s uCode\n",
+ base,
+ (priv->ucode_type == IWL_UCODE_INIT)
+ ? "Init" : "RT");
+ return -EINVAL;
+ }
+
+ /* event log header */
+ capacity = iwl_read_targ_mem(bus(trans), base);
+ mode = iwl_read_targ_mem(bus(trans), base + (1 * sizeof(u32)));
+ num_wraps = iwl_read_targ_mem(bus(trans), base + (2 * sizeof(u32)));
+ next_entry = iwl_read_targ_mem(bus(trans), base + (3 * sizeof(u32)));
+
+ if (capacity > logsize) {
+ IWL_ERR(trans, "Log capacity %d is bogus, limit to %d "
+ "entries\n", capacity, logsize);
+ capacity = logsize;
+ }
+
+ if (next_entry > logsize) {
+ IWL_ERR(trans, "Log write index %d is bogus, limit to %d\n",
+ next_entry, logsize);
+ next_entry = logsize;
+ }
+
+ size = num_wraps ? capacity : next_entry;
+
+ /* bail out if nothing in log */
+ if (size == 0) {
+ IWL_ERR(trans, "Start IWL Event Log Dump: nothing in log\n");
+ return pos;
+ }
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (!(iwl_get_debug_level(trans->shrd) & IWL_DL_FW_ERRORS) && !full_log)
+ size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
+ ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
+#else
+ size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
+ ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
+#endif
+ IWL_ERR(trans, "Start IWL Event Log Dump: display last %u entries\n",
+ size);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (display) {
+ if (full_log)
+ bufsz = capacity * 48;
+ else
+ bufsz = size * 48;
+ *buf = kmalloc(bufsz, GFP_KERNEL);
+ if (!*buf)
+ return -ENOMEM;
+ }
+ if ((iwl_get_debug_level(trans->shrd) & IWL_DL_FW_ERRORS) || full_log) {
+ /*
+ * if uCode has wrapped back to top of log,
+ * start at the oldest entry,
+ * i.e the next one that uCode would fill.
+ */
+ if (num_wraps)
+ pos = iwl_print_event_log(trans, next_entry,
+ capacity - next_entry, mode,
+ pos, buf, bufsz);
+ /* (then/else) start at top of log */
+ pos = iwl_print_event_log(trans, 0,
+ next_entry, mode, pos, buf, bufsz);
+ } else
+ pos = iwl_print_last_event_logs(trans, capacity, num_wraps,
+ next_entry, size, mode,
+ pos, buf, bufsz);
+#else
+ pos = iwl_print_last_event_logs(trans, capacity, num_wraps,
+ next_entry, size, mode,
+ pos, buf, bufsz);
+#endif
+ return pos;
+}
+
+/* tasklet for iwlagn interrupt */
+void iwl_irq_tasklet(struct iwl_trans *trans)
+{
+ u32 inta = 0;
+ u32 handled = 0;
+ unsigned long flags;
+ u32 i;
+#ifdef CONFIG_IWLWIFI_DEBUG
+ u32 inta_mask;
+#endif
+
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
+
+
+ spin_lock_irqsave(&trans->shrd->lock, flags);
+
+ /* Ack/clear/reset pending uCode interrupts.
+ * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
+ */
+ /* There is a hardware bug in the interrupt mask function that some
+ * interrupts (i.e. CSR_INT_BIT_SCD) can still be generated even if
+ * they are disabled in the CSR_INT_MASK register. Furthermore the
+ * ICT interrupt handling mechanism has another bug that might cause
+ * these unmasked interrupts fail to be detected. We workaround the
+ * hardware bugs here by ACKing all the possible interrupts so that
+ * interrupt coalescing can still be achieved.
+ */
+ iwl_write32(bus(trans), CSR_INT,
+ trans_pcie->inta | ~trans_pcie->inta_mask);
+
+ inta = trans_pcie->inta;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (iwl_get_debug_level(trans->shrd) & IWL_DL_ISR) {
+ /* just for debug */
+ inta_mask = iwl_read32(bus(trans), CSR_INT_MASK);
+ IWL_DEBUG_ISR(trans, "inta 0x%08x, enabled 0x%08x\n ",
+ inta, inta_mask);
+ }
+#endif
+
+ spin_unlock_irqrestore(&trans->shrd->lock, flags);
+
+ /* saved interrupt in inta variable now we can reset trans_pcie->inta */
+ trans_pcie->inta = 0;
+
+ /* Now service all interrupt bits discovered above. */
+ if (inta & CSR_INT_BIT_HW_ERR) {
+ IWL_ERR(trans, "Hardware error detected. Restarting.\n");
+
+ /* Tell the device to stop sending interrupts */
+ iwl_disable_interrupts(trans);
+
+ isr_stats->hw++;
+ iwl_irq_handle_error(trans);
+
+ handled |= CSR_INT_BIT_HW_ERR;
+
+ return;
+ }
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (iwl_get_debug_level(trans->shrd) & (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 "
+ "the frame/frames.\n");
+ isr_stats->sch++;
+ }
+
+ /* Alive notification via Rx interrupt will do the real work */
+ if (inta & CSR_INT_BIT_ALIVE) {
+ IWL_DEBUG_ISR(trans, "Alive interrupt\n");
+ isr_stats->alive++;
+ }
+ }
+#endif
+ /* Safely ignore these bits for debug checks below */
+ inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE);
+
+ /* HW RF KILL switch toggled */
+ if (inta & CSR_INT_BIT_RF_KILL) {
+ int hw_rf_kill = 0;
+ if (!(iwl_read32(bus(trans), CSR_GP_CNTRL) &
+ CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
+ hw_rf_kill = 1;
+
+ IWL_WARN(trans, "RF_KILL bit toggled to %s.\n",
+ hw_rf_kill ? "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);
+ }
+
+ handled |= CSR_INT_BIT_RF_KILL;
+ }
+
+ /* Chip got too hot and stopped itself */
+ if (inta & CSR_INT_BIT_CT_KILL) {
+ IWL_ERR(trans, "Microcode CT kill error detected.\n");
+ isr_stats->ctkill++;
+ handled |= CSR_INT_BIT_CT_KILL;
+ }
+
+ /* Error detected by uCode */
+ if (inta & CSR_INT_BIT_SW_ERR) {
+ IWL_ERR(trans, "Microcode SW error detected. "
+ " Restarting 0x%X.\n", inta);
+ isr_stats->sw++;
+ iwl_irq_handle_error(trans);
+ handled |= CSR_INT_BIT_SW_ERR;
+ }
+
+ /* uCode wakes up after power-down sleep */
+ 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++)
+ iwl_txq_update_write_ptr(trans,
+ &trans_pcie->txq[i]);
+
+ isr_stats->wakeup++;
+
+ handled |= CSR_INT_BIT_WAKEUP;
+ }
+
+ /* All uCode command responses, including Tx command responses,
+ * Rx "responses" (frame-received notification), and other
+ * notifications from uCode come through here*/
+ if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX |
+ CSR_INT_BIT_RX_PERIODIC)) {
+ IWL_DEBUG_ISR(trans, "Rx interrupt\n");
+ if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
+ handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
+ iwl_write32(bus(trans), CSR_FH_INT_STATUS,
+ CSR_FH_INT_RX_MASK);
+ }
+ if (inta & CSR_INT_BIT_RX_PERIODIC) {
+ handled |= CSR_INT_BIT_RX_PERIODIC;
+ iwl_write32(bus(trans),
+ CSR_INT, CSR_INT_BIT_RX_PERIODIC);
+ }
+ /* Sending RX interrupt require many steps to be done in the
+ * the device:
+ * 1- write interrupt to current index in ICT table.
+ * 2- dma RX frame.
+ * 3- update RX shared data to indicate last write index.
+ * 4- send interrupt.
+ * This could lead to RX race, driver could receive RX interrupt
+ * but the shared data changes does not reflect this;
+ * periodic interrupt will detect any dangling Rx activity.
+ */
+
+ /* Disable periodic interrupt; we use it as just a one-shot. */
+ iwl_write8(bus(trans), CSR_INT_PERIODIC_REG,
+ CSR_INT_PERIODIC_DIS);
+ iwl_rx_handle(trans);
+
+ /*
+ * Enable periodic interrupt in 8 msec only if we received
+ * real RX interrupt (instead of just periodic int), to catch
+ * any dangling Rx interrupt. If it was just the periodic
+ * interrupt, there was no dangling Rx activity, and no need
+ * to extend the periodic interrupt; one-shot is enough.
+ */
+ if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX))
+ iwl_write8(bus(trans), CSR_INT_PERIODIC_REG,
+ CSR_INT_PERIODIC_ENA);
+
+ isr_stats->rx++;
+ }
+
+ /* This "Tx" DMA channel is used only for loading uCode */
+ if (inta & CSR_INT_BIT_FH_TX) {
+ iwl_write32(bus(trans), CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK);
+ IWL_DEBUG_ISR(trans, "uCode load interrupt\n");
+ isr_stats->tx++;
+ handled |= CSR_INT_BIT_FH_TX;
+ /* Wake up uCode load routine, now that load is complete */
+ priv(trans)->ucode_write_complete = 1;
+ wake_up(&trans->shrd->wait_command_queue);
+ }
+
+ if (inta & ~handled) {
+ IWL_ERR(trans, "Unhandled INTA bits 0x%08x\n", inta & ~handled);
+ isr_stats->unhandled++;
+ }
+
+ if (inta & ~(trans_pcie->inta_mask)) {
+ IWL_WARN(trans, "Disabled INTA bits 0x%08x were pending\n",
+ inta & ~trans_pcie->inta_mask);
+ }
+
+ /* Re-enable all interrupts */
+ /* only Re-enable if disabled by irq */
+ if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status))
+ iwl_enable_interrupts(trans);
+ /* Re-enable RF_KILL if it occurred */
+ else if (handled & CSR_INT_BIT_RF_KILL)
+ iwl_enable_rfkill_int(priv(trans));
+}
+
+/******************************************************************************
+ *
+ * ICT functions
+ *
+ ******************************************************************************/
+#define ICT_COUNT (PAGE_SIZE/sizeof(u32))
+
+/* Free dram table */
+void iwl_free_isr_ict(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
+
+ if (trans_pcie->ict_tbl_vir) {
+ dma_free_coherent(bus(trans)->dev,
+ (sizeof(u32) * ICT_COUNT) + PAGE_SIZE,
+ trans_pcie->ict_tbl_vir,
+ trans_pcie->ict_tbl_dma);
+ trans_pcie->ict_tbl_vir = NULL;
+ memset(&trans_pcie->ict_tbl_dma, 0,
+ sizeof(trans_pcie->ict_tbl_dma));
+ memset(&trans_pcie->aligned_ict_tbl_dma, 0,
+ sizeof(trans_pcie->aligned_ict_tbl_dma));
+ }
+}
+
+
+/* allocate dram shared table it is a PAGE_SIZE aligned
+ * also reset all data related to ICT table interrupt.
+ */
+int iwl_alloc_isr_ict(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
+
+ /* allocate shrared data table */
+ trans_pcie->ict_tbl_vir =
+ dma_alloc_coherent(bus(trans)->dev,
+ (sizeof(u32) * ICT_COUNT) + PAGE_SIZE,
+ &trans_pcie->ict_tbl_dma, GFP_KERNEL);
+ if (!trans_pcie->ict_tbl_vir)
+ return -ENOMEM;
+
+ /* align table to PAGE_SIZE boundary */
+ trans_pcie->aligned_ict_tbl_dma =
+ ALIGN(trans_pcie->ict_tbl_dma, PAGE_SIZE);
+
+ IWL_DEBUG_ISR(trans, "ict dma addr %Lx dma aligned %Lx diff %d\n",
+ (unsigned long long)trans_pcie->ict_tbl_dma,
+ (unsigned long long)trans_pcie->aligned_ict_tbl_dma,
+ (int)(trans_pcie->aligned_ict_tbl_dma -
+ trans_pcie->ict_tbl_dma));
+
+ trans_pcie->ict_tbl = trans_pcie->ict_tbl_vir +
+ (trans_pcie->aligned_ict_tbl_dma -
+ trans_pcie->ict_tbl_dma);
+
+ IWL_DEBUG_ISR(trans, "ict vir addr %p vir aligned %p diff %d\n",
+ trans_pcie->ict_tbl, trans_pcie->ict_tbl_vir,
+ (int)(trans_pcie->aligned_ict_tbl_dma -
+ trans_pcie->ict_tbl_dma));
+
+ /* reset table and index to all 0 */
+ memset(trans_pcie->ict_tbl_vir, 0,
+ (sizeof(u32) * ICT_COUNT) + PAGE_SIZE);
+ trans_pcie->ict_index = 0;
+
+ /* add periodic RX interrupt */
+ trans_pcie->inta_mask |= CSR_INT_BIT_RX_PERIODIC;
+ return 0;
+}
+
+/* Device is going up inform it about using ICT interrupt table,
+ * also we need to tell the driver to start using ICT interrupt.
+ */
+int iwl_reset_ict(struct iwl_trans *trans)
+{
+ u32 val;
+ unsigned long flags;
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
+
+ if (!trans_pcie->ict_tbl_vir)
+ return 0;
+
+ spin_lock_irqsave(&trans->shrd->lock, flags);
+ iwl_disable_interrupts(trans);
+
+ memset(&trans_pcie->ict_tbl[0], 0, sizeof(u32) * ICT_COUNT);
+
+ val = trans_pcie->aligned_ict_tbl_dma >> PAGE_SHIFT;
+
+ val |= CSR_DRAM_INT_TBL_ENABLE;
+ val |= CSR_DRAM_INIT_TBL_WRAP_CHECK;
+
+ IWL_DEBUG_ISR(trans, "CSR_DRAM_INT_TBL_REG =0x%X "
+ "aligned dma address %Lx\n",
+ val,
+ (unsigned long long)trans_pcie->aligned_ict_tbl_dma);
+
+ iwl_write32(bus(trans), CSR_DRAM_INT_TBL_REG, val);
+ trans_pcie->use_ict = true;
+ trans_pcie->ict_index = 0;
+ iwl_write32(bus(trans), CSR_INT, trans_pcie->inta_mask);
+ iwl_enable_interrupts(trans);
+ spin_unlock_irqrestore(&trans->shrd->lock, flags);
+
+ return 0;
+}
+
+/* Device is going down disable ict interrupt usage */
+void iwl_disable_ict(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
+
+ unsigned long flags;
+
+ spin_lock_irqsave(&trans->shrd->lock, flags);
+ trans_pcie->use_ict = false;
+ spin_unlock_irqrestore(&trans->shrd->lock, flags);
+}
+
+static irqreturn_t iwl_isr(int irq, void *data)
+{
+ struct iwl_trans *trans = data;
+ struct iwl_trans_pcie *trans_pcie;
+ u32 inta, inta_mask;
+ unsigned long flags;
+#ifdef CONFIG_IWLWIFI_DEBUG
+ u32 inta_fh;
+#endif
+ if (!trans)
+ return IRQ_NONE;
+
+ trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+ spin_lock_irqsave(&trans->shrd->lock, flags);
+
+ /* Disable (but don't clear!) interrupts here to avoid
+ * back-to-back ISRs and sporadic interrupts from our NIC.
+ * If we have something to service, the tasklet will re-enable ints.
+ * If we *don't* have something, we'll re-enable before leaving here. */
+ inta_mask = iwl_read32(bus(trans), CSR_INT_MASK); /* just for debug */
+ iwl_write32(bus(trans), CSR_INT_MASK, 0x00000000);
+
+ /* Discover which interrupts are active/pending */
+ inta = iwl_read32(bus(trans), CSR_INT);
+
+ /* Ignore interrupt if there's nothing in NIC to service.
+ * This may be due to IRQ shared with another device,
+ * or due to sporadic interrupts thrown from our NIC. */
+ if (!inta) {
+ IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n");
+ goto none;
+ }
+
+ if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
+ /* Hardware disappeared. It might have already raised
+ * an interrupt */
+ IWL_WARN(trans, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
+ goto unplugged;
+ }
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (iwl_get_debug_level(trans->shrd) & (IWL_DL_ISR)) {
+ inta_fh = iwl_read32(bus(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);
+ }
+#endif
+
+ trans_pcie->inta |= inta;
+ /* 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) &&
+ !trans_pcie->inta)
+ iwl_enable_interrupts(trans);
+
+ unplugged:
+ spin_unlock_irqrestore(&trans->shrd->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) &&
+ !trans_pcie->inta)
+ iwl_enable_interrupts(trans);
+
+ spin_unlock_irqrestore(&trans->shrd->lock, flags);
+ return IRQ_NONE;
+}
+
+/* interrupt handler using ict table, with this interrupt driver will
+ * stop using INTA register to get device's interrupt, reading this register
+ * is expensive, device will write interrupts in ICT dram table, increment
+ * index then will fire interrupt to driver, driver will OR all ICT table
+ * entries from current index up to table entry with 0 value. the result is
+ * the interrupt we need to service, driver will set the entries back to 0 and
+ * set index.
+ */
+irqreturn_t iwl_isr_ict(int irq, void *data)
+{
+ struct iwl_trans *trans = data;
+ struct iwl_trans_pcie *trans_pcie;
+ u32 inta, inta_mask;
+ u32 val = 0;
+ unsigned long flags;
+
+ if (!trans)
+ return IRQ_NONE;
+
+ trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+ /* dram interrupt table not set yet,
+ * use legacy interrupt.
+ */
+ if (!trans_pcie->use_ict)
+ return iwl_isr(irq, data);
+
+ spin_lock_irqsave(&trans->shrd->lock, flags);
+
+ /* Disable (but don't clear!) interrupts here to avoid
+ * back-to-back ISRs and sporadic interrupts from our NIC.
+ * If we have something to service, the tasklet will re-enable ints.
+ * If we *don't* have something, we'll re-enable before leaving here.
+ */
+ inta_mask = iwl_read32(bus(trans), CSR_INT_MASK); /* just for debug */
+ iwl_write32(bus(trans), CSR_INT_MASK, 0x00000000);
+
+
+ /* Ignore interrupt if there's nothing in NIC to service.
+ * This may be due to IRQ shared with another device,
+ * or due to sporadic interrupts thrown from our NIC. */
+ if (!trans_pcie->ict_tbl[trans_pcie->ict_index]) {
+ IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n");
+ goto none;
+ }
+
+ /* read all entries that not 0 start with ict_index */
+ while (trans_pcie->ict_tbl[trans_pcie->ict_index]) {
+
+ val |= le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]);
+ IWL_DEBUG_ISR(trans, "ICT index %d value 0x%08X\n",
+ trans_pcie->ict_index,
+ le32_to_cpu(
+ trans_pcie->ict_tbl[trans_pcie->ict_index]));
+ trans_pcie->ict_tbl[trans_pcie->ict_index] = 0;
+ trans_pcie->ict_index =
+ iwl_queue_inc_wrap(trans_pcie->ict_index, ICT_COUNT);
+
+ }
+
+ /* We should not get this value, just ignore it. */
+ if (val == 0xffffffff)
+ val = 0;
+
+ /*
+ * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit
+ * (bit 15 before shifting it to 31) to clear when using interrupt
+ * coalescing. fortunately, bits 18 and 19 stay set when this happens
+ * so we use them to decide on the real state of the Rx bit.
+ * In order words, bit 15 is set if bit 18 or bit 19 are set.
+ */
+ if (val & 0xC0000)
+ val |= 0x8000;
+
+ inta = (0xff & val) | ((0xff00 & val) << 16);
+ IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n",
+ inta, inta_mask, val);
+
+ inta &= trans_pcie->inta_mask;
+ trans_pcie->inta |= inta;
+
+ /* 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) &&
+ !trans_pcie->inta) {
+ /* Allow interrupt if was disabled by this handler and
+ * no tasklet was schedules, We should not enable interrupt,
+ * tasklet will enable it.
+ */
+ iwl_enable_interrupts(trans);
+ }
+
+ spin_unlock_irqrestore(&trans->shrd->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) &&
+ !trans_pcie->inta)
+ iwl_enable_interrupts(trans);
+
+ spin_unlock_irqrestore(&trans->shrd->lock, flags);
+ return IRQ_NONE;
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
index a6b2b1db0b1d..4a0c95302a7e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
@@ -29,34 +29,42 @@
#include <linux/etherdevice.h>
#include <linux/slab.h>
#include <linux/sched.h>
-#include <net/mac80211.h>
-#include "iwl-agn.h"
-#include "iwl-dev.h"
-#include "iwl-core.h"
+#include "iwl-debug.h"
+#include "iwl-csr.h"
+#include "iwl-prph.h"
#include "iwl-io.h"
-#include "iwl-helpers.h"
-#include "iwl-trans-int-pcie.h"
+#include "iwl-agn-hw.h"
+#include "iwl-trans-pcie-int.h"
+
+#define IWL_TX_CRC_SIZE 4
+#define IWL_TX_DELIMITER_SIZE 4
/**
* iwl_trans_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
*/
-void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
+void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
struct iwl_tx_queue *txq,
u16 byte_cnt)
{
- struct iwlagn_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
+ struct iwlagn_scd_bc_tbl *scd_bc_tbl;
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
int write_ptr = txq->q.write_ptr;
int txq_id = txq->q.id;
u8 sec_ctl = 0;
u8 sta_id = 0;
u16 len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
__le16 bc_ent;
+ struct iwl_tx_cmd *tx_cmd =
+ (struct iwl_tx_cmd *) txq->cmd[txq->q.write_ptr]->payload;
+
+ scd_bc_tbl = trans_pcie->scd_bc_tbls.addr;
WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX);
- sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id;
- sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl;
+ sta_id = tx_cmd->sta_id;
+ sec_ctl = tx_cmd->sec_ctl;
switch (sec_ctl & TX_CMD_SEC_MSK) {
case TX_CMD_SEC_CCM:
@@ -82,7 +90,7 @@ void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
/**
* iwl_txq_update_write_ptr - Send new write index to hardware
*/
-void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+void iwl_txq_update_write_ptr(struct iwl_trans *trans, struct iwl_tx_queue *txq)
{
u32 reg = 0;
int txq_id = txq->q.id;
@@ -90,28 +98,28 @@ void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
if (txq->need_update == 0)
return;
- if (priv->cfg->base_params->shadow_reg_enable) {
+ if (hw_params(trans).shadow_reg_enable) {
/* shadow register enabled */
- iwl_write32(priv, HBUS_TARG_WRPTR,
+ iwl_write32(bus(trans), HBUS_TARG_WRPTR,
txq->q.write_ptr | (txq_id << 8));
} else {
/* if we're trying to save power */
- if (test_bit(STATUS_POWER_PMI, &priv->status)) {
+ if (test_bit(STATUS_POWER_PMI, &trans->shrd->status)) {
/* wake up nic if it's powered down ...
* uCode will wake up, and interrupt us again, so next
* time we'll skip this part. */
- reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
+ reg = iwl_read32(bus(trans), CSR_UCODE_DRV_GP1);
if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
- IWL_DEBUG_INFO(priv,
+ IWL_DEBUG_INFO(trans,
"Tx queue %d requesting wakeup,"
" GP1 = 0x%x\n", txq_id, reg);
- iwl_set_bit(priv, CSR_GP_CNTRL,
+ iwl_set_bit(bus(trans), CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
return;
}
- iwl_write_direct32(priv, HBUS_TARG_WRPTR,
+ iwl_write_direct32(bus(trans), HBUS_TARG_WRPTR,
txq->q.write_ptr | (txq_id << 8));
/*
@@ -120,7 +128,7 @@ void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
* trying to tx (during RFKILL, we're not trying to tx).
*/
} else
- iwl_write32(priv, HBUS_TARG_WRPTR,
+ iwl_write32(bus(trans), HBUS_TARG_WRPTR,
txq->q.write_ptr | (txq_id << 8));
}
txq->need_update = 0;
@@ -165,7 +173,7 @@ static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd)
return tfd->num_tbs & 0x1f;
}
-static void iwlagn_unmap_tfd(struct iwl_priv *priv, struct iwl_cmd_meta *meta,
+static void iwlagn_unmap_tfd(struct iwl_trans *trans, struct iwl_cmd_meta *meta,
struct iwl_tfd *tfd, enum dma_data_direction dma_dir)
{
int i;
@@ -175,56 +183,59 @@ static void iwlagn_unmap_tfd(struct iwl_priv *priv, struct iwl_cmd_meta *meta,
num_tbs = iwl_tfd_get_num_tbs(tfd);
if (num_tbs >= IWL_NUM_OF_TBS) {
- IWL_ERR(priv, "Too many chunks: %i\n", num_tbs);
+ IWL_ERR(trans, "Too many chunks: %i\n", num_tbs);
/* @todo issue fatal error, it is quite serious situation */
return;
}
/* Unmap tx_cmd */
if (num_tbs)
- dma_unmap_single(priv->bus->dev,
+ dma_unmap_single(bus(trans)->dev,
dma_unmap_addr(meta, mapping),
dma_unmap_len(meta, len),
DMA_BIDIRECTIONAL);
/* Unmap chunks, if any. */
for (i = 1; i < num_tbs; i++)
- dma_unmap_single(priv->bus->dev, iwl_tfd_tb_get_addr(tfd, i),
+ dma_unmap_single(bus(trans)->dev, iwl_tfd_tb_get_addr(tfd, i),
iwl_tfd_tb_get_len(tfd, i), dma_dir);
}
/**
* iwlagn_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
- * @priv - driver private data
+ * @trans - transport private data
* @txq - tx queue
* @index - the index of the TFD to be freed
+ *@dma_dir - the direction of the DMA mapping
*
* Does NOT advance any TFD circular buffer read/write indexes
* Does NOT free the TFD itself (which is within circular buffer)
*/
-void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq,
- int index)
+void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
+ int index, enum dma_data_direction dma_dir)
{
struct iwl_tfd *tfd_tmp = txq->tfds;
- iwlagn_unmap_tfd(priv, &txq->meta[index], &tfd_tmp[index],
- DMA_TO_DEVICE);
+ iwlagn_unmap_tfd(trans, &txq->meta[index], &tfd_tmp[index], dma_dir);
/* free SKB */
- if (txq->txb) {
+ if (txq->skbs) {
struct sk_buff *skb;
- skb = txq->txb[index].skb;
+ skb = txq->skbs[index];
- /* can be called from irqs-disabled context */
+ /* Can be called from irqs-disabled context
+ * If skb is not NULL, it means that the whole queue is being
+ * freed and that the queue is not empty - free the skb
+ */
if (skb) {
- dev_kfree_skb_any(skb);
- txq->txb[index].skb = NULL;
+ iwl_free_skb(priv(trans), skb);
+ txq->skbs[index] = NULL;
}
}
}
-int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv,
+int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans,
struct iwl_tx_queue *txq,
dma_addr_t addr, u16 len,
u8 reset)
@@ -244,7 +255,7 @@ int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv,
/* Each TFD can point to a maximum 20 Tx buffers */
if (num_tbs >= IWL_NUM_OF_TBS) {
- IWL_ERR(priv, "Error can not send more than %d chunks\n",
+ IWL_ERR(trans, "Error can not send more than %d chunks\n",
IWL_NUM_OF_TBS);
return -EINVAL;
}
@@ -253,7 +264,7 @@ int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv,
return -EINVAL;
if (unlikely(addr & ~IWL_TX_DMA_MASK))
- IWL_ERR(priv, "Unaligned address = %llx\n",
+ IWL_ERR(trans, "Unaligned address = %llx\n",
(unsigned long long)addr);
iwl_tfd_set_tb(tfd, num_tbs, addr, len);
@@ -302,8 +313,7 @@ int iwl_queue_space(const struct iwl_queue *q)
/**
* iwl_queue_init - Initialize queue's high/low-water and read/write indexes
*/
-int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
- int count, int slots_num, u32 id)
+int iwl_queue_init(struct iwl_queue *q, int count, int slots_num, u32 id)
{
q->n_bd = count;
q->n_window = slots_num;
@@ -332,25 +342,23 @@ int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
return 0;
}
-/*TODO: this functions should NOT be exported from trans module - export it
- * until the reclaim flow will be brought to the transport module too.
- * Add a declaration to make sparse happy */
-void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
- struct iwl_tx_queue *txq);
-
-void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
+static void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_trans *trans,
struct iwl_tx_queue *txq)
{
- struct iwlagn_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwlagn_scd_bc_tbl *scd_bc_tbl = trans_pcie->scd_bc_tbls.addr;
int txq_id = txq->q.id;
int read_ptr = txq->q.read_ptr;
u8 sta_id = 0;
__le16 bc_ent;
+ struct iwl_tx_cmd *tx_cmd =
+ (struct iwl_tx_cmd *) txq->cmd[txq->q.read_ptr]->payload;
WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX);
- if (txq_id != priv->cmd_queue)
- sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id;
+ if (txq_id != trans->shrd->cmd_queue)
+ sta_id = tx_cmd->sta_id;
bc_ent = cpu_to_le16(1 | (sta_id << 12));
scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent;
@@ -360,56 +368,61 @@ void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent;
}
-static int iwlagn_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
+static int iwlagn_tx_queue_set_q2ratid(struct iwl_trans *trans, u16 ra_tid,
u16 txq_id)
{
u32 tbl_dw_addr;
u32 tbl_dw;
u16 scd_q2ratid;
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
+
scd_q2ratid = ra_tid & SCD_QUEUE_RA_TID_MAP_RATID_MSK;
- tbl_dw_addr = priv->scd_base_addr +
+ tbl_dw_addr = trans_pcie->scd_base_addr +
SCD_TRANS_TBL_OFFSET_QUEUE(txq_id);
- tbl_dw = iwl_read_targ_mem(priv, tbl_dw_addr);
+ tbl_dw = iwl_read_targ_mem(bus(trans), tbl_dw_addr);
if (txq_id & 0x1)
tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF);
else
tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000);
- iwl_write_targ_mem(priv, tbl_dw_addr, tbl_dw);
+ iwl_write_targ_mem(bus(trans), tbl_dw_addr, tbl_dw);
return 0;
}
-static void iwlagn_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id)
+static void iwlagn_tx_queue_stop_scheduler(struct iwl_trans *trans, u16 txq_id)
{
/* Simply stop the queue, but don't change any configuration;
* the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */
- iwl_write_prph(priv,
+ iwl_write_prph(bus(trans),
SCD_QUEUE_STATUS_BITS(txq_id),
(0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
(1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
}
-void iwl_trans_set_wr_ptrs(struct iwl_priv *priv,
+void iwl_trans_set_wr_ptrs(struct iwl_trans *trans,
int txq_id, u32 index)
{
- iwl_write_direct32(priv, HBUS_TARG_WRPTR,
+ iwl_write_direct32(bus(trans), HBUS_TARG_WRPTR,
(index & 0xff) | (txq_id << 8));
- iwl_write_prph(priv, SCD_QUEUE_RDPTR(txq_id), index);
+ iwl_write_prph(bus(trans), SCD_QUEUE_RDPTR(txq_id), index);
}
-void iwl_trans_tx_queue_set_status(struct iwl_priv *priv,
+void iwl_trans_tx_queue_set_status(struct iwl_trans *trans,
struct iwl_tx_queue *txq,
int tx_fifo_id, int scd_retry)
{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int txq_id = txq->q.id;
- int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0;
+ int active =
+ test_bit(txq_id, &trans_pcie->txq_ctx_active_msk) ? 1 : 0;
- iwl_write_prph(priv, SCD_QUEUE_STATUS_BITS(txq_id),
+ iwl_write_prph(bus(trans), SCD_QUEUE_STATUS_BITS(txq_id),
(active << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
(tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF) |
(1 << SCD_QUEUE_STTS_REG_POS_WSL) |
@@ -417,55 +430,75 @@ void iwl_trans_tx_queue_set_status(struct iwl_priv *priv,
txq->sched_retry = scd_retry;
- IWL_DEBUG_INFO(priv, "%s %s Queue %d on FIFO %d\n",
+ IWL_DEBUG_INFO(trans, "%s %s Queue %d on FIFO %d\n",
active ? "Activate" : "Deactivate",
scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id);
}
-void iwl_trans_txq_agg_setup(struct iwl_priv *priv, int sta_id, int tid,
- int frame_limit)
+static inline int get_fifo_from_tid(struct iwl_trans_pcie *trans_pcie,
+ u8 ctx, u16 tid)
+{
+ const u8 *ac_to_fifo = trans_pcie->ac_to_fifo[ctx];
+ if (likely(tid < ARRAY_SIZE(tid_to_ac)))
+ return ac_to_fifo[tid_to_ac[tid]];
+
+ /* no support for TIDs 8-15 yet */
+ return -EINVAL;
+}
+
+void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans,
+ enum iwl_rxon_context_id ctx, int sta_id,
+ int tid, int frame_limit)
{
int tx_fifo, txq_id, ssn_idx;
u16 ra_tid;
unsigned long flags;
struct iwl_tid_data *tid_data;
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
+
if (WARN_ON(sta_id == IWL_INVALID_STATION))
return;
- if (WARN_ON(tid >= MAX_TID_COUNT))
+ if (WARN_ON(tid >= IWL_MAX_TID_COUNT))
return;
- spin_lock_irqsave(&priv->sta_lock, flags);
- tid_data = &priv->stations[sta_id].tid[tid];
+ tx_fifo = get_fifo_from_tid(trans_pcie, ctx, tid);
+ if (WARN_ON(tx_fifo < 0)) {
+ IWL_ERR(trans, "txq_agg_setup, bad fifo: %d\n", tx_fifo);
+ return;
+ }
+
+ spin_lock_irqsave(&trans->shrd->sta_lock, flags);
+ tid_data = &trans->shrd->tid_data[sta_id][tid];
ssn_idx = SEQ_TO_SN(tid_data->seq_number);
txq_id = tid_data->agg.txq_id;
- tx_fifo = tid_data->agg.tx_fifo;
- spin_unlock_irqrestore(&priv->sta_lock, flags);
+ spin_unlock_irqrestore(&trans->shrd->sta_lock, flags);
ra_tid = BUILD_RAxTID(sta_id, tid);
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&trans->shrd->lock, flags);
/* Stop this Tx queue before configuring it */
- iwlagn_tx_queue_stop_scheduler(priv, txq_id);
+ iwlagn_tx_queue_stop_scheduler(trans, txq_id);
/* Map receiver-address / traffic-ID to this queue */
- iwlagn_tx_queue_set_q2ratid(priv, ra_tid, txq_id);
+ iwlagn_tx_queue_set_q2ratid(trans, ra_tid, txq_id);
/* Set this queue as a chain-building queue */
- iwl_set_bits_prph(priv, SCD_QUEUECHAIN_SEL, (1<<txq_id));
+ iwl_set_bits_prph(bus(trans), SCD_QUEUECHAIN_SEL, (1<<txq_id));
/* enable aggregations for the queue */
- iwl_set_bits_prph(priv, SCD_AGGR_SEL, (1<<txq_id));
+ iwl_set_bits_prph(bus(trans), SCD_AGGR_SEL, (1<<txq_id));
/* Place first TFD at index corresponding to start sequence number.
* Assumes that ssn_idx is valid (!= 0xFFF) */
- priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff);
- priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff);
- iwl_trans_set_wr_ptrs(priv, txq_id, ssn_idx);
+ trans_pcie->txq[txq_id].q.read_ptr = (ssn_idx & 0xff);
+ trans_pcie->txq[txq_id].q.write_ptr = (ssn_idx & 0xff);
+ iwl_trans_set_wr_ptrs(trans, txq_id, ssn_idx);
/* Set up Tx window size and frame limit for this queue */
- iwl_write_targ_mem(priv, priv->scd_base_addr +
+ iwl_write_targ_mem(bus(trans), trans_pcie->scd_base_addr +
SCD_CONTEXT_QUEUE_OFFSET(txq_id) +
sizeof(u32),
((frame_limit <<
@@ -475,40 +508,161 @@ void iwl_trans_txq_agg_setup(struct iwl_priv *priv, int sta_id, int tid,
SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
- iwl_set_bits_prph(priv, SCD_INTERRUPT_MASK, (1 << txq_id));
+ iwl_set_bits_prph(bus(trans), SCD_INTERRUPT_MASK, (1 << txq_id));
/* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
- iwl_trans_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
+ iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[txq_id],
+ tx_fifo, 1);
+
+ 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(&priv->lock, flags);
+/*
+ * Find first available (lowest unused) Tx Queue, mark it "active".
+ * Called only when finding queue for aggregation.
+ * Should never return anything < 7, because they should already
+ * be in use as EDCA AC (0-3), Command (4), reserved (5, 6)
+ */
+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++)
+ if (!test_and_set_bit(txq_id,
+ &trans_pcie->txq_ctx_active_msk))
+ return txq_id;
+ return -1;
}
-int iwl_trans_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
- u16 ssn_idx, u8 tx_fifo)
+int iwl_trans_pcie_tx_agg_alloc(struct iwl_trans *trans,
+ enum iwl_rxon_context_id ctx, int sta_id,
+ int tid, u16 *ssn)
{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_tid_data *tid_data;
+ unsigned long flags;
+ int txq_id;
+
+ txq_id = iwlagn_txq_ctx_activate_free(trans);
+ if (txq_id == -1) {
+ IWL_ERR(trans, "No free aggregation queue available\n");
+ return -ENXIO;
+ }
+
+ spin_lock_irqsave(&trans->shrd->sta_lock, flags);
+ tid_data = &trans->shrd->tid_data[sta_id][tid];
+ *ssn = SEQ_TO_SN(tid_data->seq_number);
+ tid_data->agg.txq_id = txq_id;
+ iwl_set_swq_id(&trans_pcie->txq[txq_id], get_ac_from_tid(tid), txq_id);
+
+ tid_data = &trans->shrd->tid_data[sta_id][tid];
+ if (tid_data->tfds_in_queue == 0) {
+ IWL_DEBUG_HT(trans, "HW queue is empty\n");
+ tid_data->agg.state = IWL_AGG_ON;
+ iwl_start_tx_ba_trans_ready(priv(trans), ctx, sta_id, tid);
+ } else {
+ IWL_DEBUG_HT(trans, "HW queue is NOT empty: %d packets in HW"
+ "queue\n", tid_data->tfds_in_queue);
+ tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
+ }
+ spin_unlock_irqrestore(&trans->shrd->sta_lock, flags);
+
+ return 0;
+}
+
+void iwl_trans_pcie_txq_agg_disable(struct iwl_trans *trans, int txq_id)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ iwlagn_tx_queue_stop_scheduler(trans, txq_id);
+
+ iwl_clear_bits_prph(bus(trans), SCD_AGGR_SEL, (1 << txq_id));
+
+ trans_pcie->txq[txq_id].q.read_ptr = 0;
+ trans_pcie->txq[txq_id].q.write_ptr = 0;
+ /* supposes that ssn_idx is valid (!= 0xFFF) */
+ iwl_trans_set_wr_ptrs(trans, txq_id, 0);
+
+ iwl_clear_bits_prph(bus(trans), SCD_INTERRUPT_MASK, (1 << txq_id));
+ iwl_txq_ctx_deactivate(trans_pcie, txq_id);
+ iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[txq_id], 0, 0);
+}
+
+int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans,
+ enum iwl_rxon_context_id ctx, int sta_id,
+ int tid)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ unsigned long flags;
+ int read_ptr, write_ptr;
+ struct iwl_tid_data *tid_data;
+ int txq_id;
+
+ spin_lock_irqsave(&trans->shrd->sta_lock, flags);
+
+ tid_data = &trans->shrd->tid_data[sta_id][tid];
+ txq_id = tid_data->agg.txq_id;
+
if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
(IWLAGN_FIRST_AMPDU_QUEUE +
- priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) {
- IWL_ERR(priv,
+ hw_params(trans).num_ampdu_queues <= txq_id)) {
+ IWL_ERR(trans,
"queue number out of range: %d, must be %d to %d\n",
txq_id, IWLAGN_FIRST_AMPDU_QUEUE,
IWLAGN_FIRST_AMPDU_QUEUE +
- priv->cfg->base_params->num_of_ampdu_queues - 1);
+ hw_params(trans).num_ampdu_queues - 1);
+ spin_unlock_irqrestore(&trans->shrd->sta_lock, flags);
return -EINVAL;
}
- iwlagn_tx_queue_stop_scheduler(priv, txq_id);
+ switch (trans->shrd->tid_data[sta_id][tid].agg.state) {
+ case IWL_EMPTYING_HW_QUEUE_ADDBA:
+ /*
+ * This can happen if the peer stops aggregation
+ * again before we've had a chance to drain the
+ * queue we selected previously, i.e. before the
+ * session was really started completely.
+ */
+ IWL_DEBUG_HT(trans, "AGG stop before setup done\n");
+ goto turn_off;
+ case IWL_AGG_ON:
+ break;
+ default:
+ IWL_WARN(trans, "Stopping AGG while state not ON "
+ "or starting for %d on %d (%d)\n", sta_id, tid,
+ trans->shrd->tid_data[sta_id][tid].agg.state);
+ spin_unlock_irqrestore(&trans->shrd->sta_lock, flags);
+ return 0;
+ }
+
+ write_ptr = trans_pcie->txq[txq_id].q.write_ptr;
+ read_ptr = trans_pcie->txq[txq_id].q.read_ptr;
- iwl_clear_bits_prph(priv, SCD_AGGR_SEL, (1 << txq_id));
+ /* The queue is not empty */
+ if (write_ptr != read_ptr) {
+ IWL_DEBUG_HT(trans, "Stopping a non empty AGG HW QUEUE\n");
+ trans->shrd->tid_data[sta_id][tid].agg.state =
+ IWL_EMPTYING_HW_QUEUE_DELBA;
+ spin_unlock_irqrestore(&trans->shrd->sta_lock, flags);
+ return 0;
+ }
- priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff);
- priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff);
- /* supposes that ssn_idx is valid (!= 0xFFF) */
- iwl_trans_set_wr_ptrs(priv, txq_id, ssn_idx);
+ IWL_DEBUG_HT(trans, "HW queue is empty\n");
+turn_off:
+ trans->shrd->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF;
+
+ /* do not restore/save irqs */
+ spin_unlock(&trans->shrd->sta_lock);
+ spin_lock(&trans->shrd->lock);
- iwl_clear_bits_prph(priv, SCD_INTERRUPT_MASK, (1 << txq_id));
- iwl_txq_ctx_deactivate(priv, txq_id);
- iwl_trans_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0);
+ iwl_trans_pcie_txq_agg_disable(trans, txq_id);
+
+ spin_unlock_irqrestore(&trans->shrd->lock, flags);
+
+ iwl_stop_tx_ba_trans_ready(priv(trans), ctx, sta_id, tid);
return 0;
}
@@ -524,9 +678,10 @@ int iwl_trans_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
* failed. On success, it turns the index (> 0) of command in the
* command queue.
*/
-static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
{
- struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
+ 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_queue *q = &txq->q;
struct iwl_device_cmd *out_cmd;
struct iwl_cmd_meta *out_meta;
@@ -544,14 +699,14 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
int trace_idx;
#endif
- if (test_bit(STATUS_FW_ERROR, &priv->status)) {
- IWL_WARN(priv, "fw recovery, no hcmd send\n");
+ if (test_bit(STATUS_FW_ERROR, &trans->shrd->status)) {
+ IWL_WARN(trans, "fw recovery, no hcmd send\n");
return -EIO;
}
- if ((priv->ucode_owner == IWL_OWNERSHIP_TM) &&
+ if ((trans->shrd->ucode_owner == IWL_OWNERSHIP_TM) &&
!(cmd->flags & CMD_ON_DEMAND)) {
- IWL_DEBUG_HC(priv, "tm own the uCode, no regular hcmd send\n");
+ IWL_DEBUG_HC(trans, "tm own the uCode, no regular hcmd send\n");
return -EIO;
}
@@ -584,22 +739,22 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
if (WARN_ON(copy_size > TFD_MAX_PAYLOAD_SIZE))
return -EINVAL;
- if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) {
- IWL_WARN(priv, "Not sending command - %s KILL\n",
- iwl_is_rfkill(priv) ? "RF" : "CT");
+ 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(&priv->hcmd_lock, flags);
+ spin_lock_irqsave(&trans->hcmd_lock, flags);
if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
- spin_unlock_irqrestore(&priv->hcmd_lock, flags);
+ spin_unlock_irqrestore(&trans->hcmd_lock, flags);
- IWL_ERR(priv, "No space in command queue\n");
- is_ct_kill = iwl_check_for_ct_kill(priv);
+ 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(priv, "Restarting adapter due to queue full\n");
- iwlagn_fw_error(priv, false);
+ IWL_ERR(trans, "Restarting adapter queue is full\n");
+ iwlagn_fw_error(priv(trans), false);
}
return -ENOSPC;
}
@@ -611,19 +766,18 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */
if (cmd->flags & CMD_WANT_SKB)
out_meta->source = cmd;
- if (cmd->flags & CMD_ASYNC)
- out_meta->callback = cmd->callback;
/* set up the header */
out_cmd->hdr.cmd = cmd->id;
out_cmd->hdr.flags = 0;
- out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(priv->cmd_queue) |
- INDEX_TO_SEQ(q->write_ptr));
+ out_cmd->hdr.sequence =
+ cpu_to_le16(QUEUE_TO_SEQ(trans->shrd->cmd_queue) |
+ INDEX_TO_SEQ(q->write_ptr));
/* and copy the data that needs to be copied */
- cmd_dest = &out_cmd->cmd.payload[0];
+ cmd_dest = out_cmd->payload;
for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
if (!cmd->len[i])
continue;
@@ -633,16 +787,16 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
cmd_dest += cmd->len[i];
}
- IWL_DEBUG_HC(priv, "Sending command %s (#%x), seq: 0x%04X, "
+ IWL_DEBUG_HC(trans, "Sending command %s (#%x), seq: 0x%04X, "
"%d bytes at %d[%d]:%d\n",
get_cmd_string(out_cmd->hdr.cmd),
out_cmd->hdr.cmd,
le16_to_cpu(out_cmd->hdr.sequence), cmd_size,
- q->write_ptr, idx, priv->cmd_queue);
+ q->write_ptr, idx, trans->shrd->cmd_queue);
- phys_addr = dma_map_single(priv->bus->dev, &out_cmd->hdr, copy_size,
+ phys_addr = dma_map_single(bus(trans)->dev, &out_cmd->hdr, copy_size,
DMA_BIDIRECTIONAL);
- if (unlikely(dma_mapping_error(priv->bus->dev, phys_addr))) {
+ if (unlikely(dma_mapping_error(bus(trans)->dev, phys_addr))) {
idx = -ENOMEM;
goto out;
}
@@ -650,7 +804,8 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
dma_unmap_addr_set(out_meta, mapping, phys_addr);
dma_unmap_len_set(out_meta, len, copy_size);
- iwlagn_txq_attach_buf_to_tfd(priv, txq, phys_addr, copy_size, 1);
+ iwlagn_txq_attach_buf_to_tfd(trans, txq,
+ phys_addr, copy_size, 1);
#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
trace_bufs[0] = &out_cmd->hdr;
trace_lens[0] = copy_size;
@@ -662,17 +817,18 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
continue;
if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY))
continue;
- phys_addr = dma_map_single(priv->bus->dev, (void *)cmd->data[i],
+ phys_addr = dma_map_single(bus(trans)->dev,
+ (void *)cmd->data[i],
cmd->len[i], DMA_BIDIRECTIONAL);
- if (dma_mapping_error(priv->bus->dev, phys_addr)) {
- iwlagn_unmap_tfd(priv, out_meta,
+ if (dma_mapping_error(bus(trans)->dev, phys_addr)) {
+ iwlagn_unmap_tfd(trans, out_meta,
&txq->tfds[q->write_ptr],
DMA_BIDIRECTIONAL);
idx = -ENOMEM;
goto out;
}
- iwlagn_txq_attach_buf_to_tfd(priv, txq, phys_addr,
+ iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr,
cmd->len[i], 0);
#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
trace_bufs[trace_idx] = cmd->data[i];
@@ -688,7 +844,7 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, 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, cmd->flags,
+ trace_iwlwifi_dev_hcmd(priv(trans), cmd->flags,
trace_bufs[0], trace_lens[0],
trace_bufs[1], trace_lens[1],
trace_bufs[2], trace_lens[2]);
@@ -696,10 +852,10 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
/* Increment and update queue's write index */
q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
- iwl_txq_update_write_ptr(priv, txq);
+ iwl_txq_update_write_ptr(trans, txq);
out:
- spin_unlock_irqrestore(&priv->hcmd_lock, flags);
+ spin_unlock_irqrestore(&trans->hcmd_lock, flags);
return idx;
}
@@ -710,14 +866,16 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
* need to be reclaimed. As result, some free space forms. If there is
* enough free space (> low mark), wake the stack that feeds us.
*/
-static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int idx)
+static void iwl_hcmd_queue_reclaim(struct iwl_trans *trans, int txq_id,
+ int idx)
{
- struct iwl_tx_queue *txq = &priv->txq[txq_id];
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
struct iwl_queue *q = &txq->q;
int nfreed = 0;
if ((idx >= q->n_bd) || (iwl_queue_used(q, idx) == 0)) {
- IWL_ERR(priv, "%s: Read index for DMA queue txq id (%d), "
+ IWL_ERR(trans, "%s: Read index for DMA queue txq id (%d), "
"index %d is out of range [0-%d] %d %d.\n", __func__,
txq_id, idx, q->n_bd, q->write_ptr, q->read_ptr);
return;
@@ -727,9 +885,9 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int idx)
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
if (nfreed++ > 0) {
- IWL_ERR(priv, "HCMD skipped: index (%d) %d %d\n", idx,
+ IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n", idx,
q->write_ptr, q->read_ptr);
- iwlagn_fw_error(priv, false);
+ iwlagn_fw_error(priv(trans), false);
}
}
@@ -738,12 +896,15 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int idx)
/**
* iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
* @rxb: Rx buffer to reclaim
+ * @handler_status: return value of the handler of the command
+ * (put in setup_rx_handlers)
*
* If an Rx buffer has an async callback associated with it the callback
* will be executed. The attached skb (if present) will only be freed
* if the callback returns 1
*/
-void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_mem_buffer *rxb,
+ int handler_status)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
u16 sequence = le16_to_cpu(pkt->hdr.sequence);
@@ -752,18 +913,19 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
int cmd_index;
struct iwl_device_cmd *cmd;
struct iwl_cmd_meta *meta;
- struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
+ 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;
/* 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 != priv->cmd_queue,
+ if (WARN(txq_id != trans->shrd->cmd_queue,
"wrong command queue %d (should be %d), sequence 0x%X readp=%d writep=%d\n",
- txq_id, priv->cmd_queue, sequence,
- priv->txq[priv->cmd_queue].q.read_ptr,
- priv->txq[priv->cmd_queue].q.write_ptr)) {
- iwl_print_hex_error(priv, pkt, 32);
+ 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)) {
+ iwl_print_hex_error(trans, pkt, 32);
return;
}
@@ -771,140 +933,42 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
cmd = txq->cmd[cmd_index];
meta = &txq->meta[cmd_index];
- iwlagn_unmap_tfd(priv, meta, &txq->tfds[index], DMA_BIDIRECTIONAL);
+ txq->time_stamp = jiffies;
+
+ iwlagn_unmap_tfd(trans, meta, &txq->tfds[index],
+ DMA_BIDIRECTIONAL);
/* 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);
+ meta->source->handler_status = handler_status;
rxb->page = NULL;
- } else if (meta->callback)
- meta->callback(priv, cmd, pkt);
+ }
- spin_lock_irqsave(&priv->hcmd_lock, flags);
+ spin_lock_irqsave(&trans->hcmd_lock, flags);
- iwl_hcmd_queue_reclaim(priv, txq_id, index);
+ iwl_hcmd_queue_reclaim(trans, txq_id, index);
if (!(meta->flags & CMD_ASYNC)) {
- clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
- IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s\n",
+ if (!test_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status)) {
+ IWL_WARN(trans,
+ "HCMD_ACTIVE already clear for command %s\n",
+ get_cmd_string(cmd->hdr.cmd));
+ }
+ clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status);
+ IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n",
get_cmd_string(cmd->hdr.cmd));
- wake_up_interruptible(&priv->wait_command_queue);
+ wake_up(&trans->shrd->wait_command_queue);
}
meta->flags = 0;
- spin_unlock_irqrestore(&priv->hcmd_lock, flags);
-}
-
-const char *get_cmd_string(u8 cmd)
-{
- switch (cmd) {
- IWL_CMD(REPLY_ALIVE);
- IWL_CMD(REPLY_ERROR);
- IWL_CMD(REPLY_RXON);
- IWL_CMD(REPLY_RXON_ASSOC);
- IWL_CMD(REPLY_QOS_PARAM);
- IWL_CMD(REPLY_RXON_TIMING);
- IWL_CMD(REPLY_ADD_STA);
- IWL_CMD(REPLY_REMOVE_STA);
- IWL_CMD(REPLY_REMOVE_ALL_STA);
- IWL_CMD(REPLY_TXFIFO_FLUSH);
- IWL_CMD(REPLY_WEPKEY);
- IWL_CMD(REPLY_TX);
- IWL_CMD(REPLY_LEDS_CMD);
- IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
- IWL_CMD(COEX_PRIORITY_TABLE_CMD);
- IWL_CMD(COEX_MEDIUM_NOTIFICATION);
- IWL_CMD(COEX_EVENT_CMD);
- IWL_CMD(REPLY_QUIET_CMD);
- IWL_CMD(REPLY_CHANNEL_SWITCH);
- IWL_CMD(CHANNEL_SWITCH_NOTIFICATION);
- IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD);
- IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION);
- IWL_CMD(POWER_TABLE_CMD);
- IWL_CMD(PM_SLEEP_NOTIFICATION);
- IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC);
- IWL_CMD(REPLY_SCAN_CMD);
- IWL_CMD(REPLY_SCAN_ABORT_CMD);
- IWL_CMD(SCAN_START_NOTIFICATION);
- IWL_CMD(SCAN_RESULTS_NOTIFICATION);
- IWL_CMD(SCAN_COMPLETE_NOTIFICATION);
- IWL_CMD(BEACON_NOTIFICATION);
- IWL_CMD(REPLY_TX_BEACON);
- IWL_CMD(WHO_IS_AWAKE_NOTIFICATION);
- IWL_CMD(QUIET_NOTIFICATION);
- IWL_CMD(REPLY_TX_PWR_TABLE_CMD);
- IWL_CMD(MEASURE_ABORT_NOTIFICATION);
- IWL_CMD(REPLY_BT_CONFIG);
- IWL_CMD(REPLY_STATISTICS_CMD);
- IWL_CMD(STATISTICS_NOTIFICATION);
- IWL_CMD(REPLY_CARD_STATE_CMD);
- IWL_CMD(CARD_STATE_NOTIFICATION);
- IWL_CMD(MISSED_BEACONS_NOTIFICATION);
- IWL_CMD(REPLY_CT_KILL_CONFIG_CMD);
- IWL_CMD(SENSITIVITY_CMD);
- IWL_CMD(REPLY_PHY_CALIBRATION_CMD);
- IWL_CMD(REPLY_RX_PHY_CMD);
- IWL_CMD(REPLY_RX_MPDU_CMD);
- IWL_CMD(REPLY_RX);
- IWL_CMD(REPLY_COMPRESSED_BA);
- IWL_CMD(CALIBRATION_CFG_CMD);
- IWL_CMD(CALIBRATION_RES_NOTIFICATION);
- IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION);
- IWL_CMD(REPLY_TX_POWER_DBM_CMD);
- IWL_CMD(TEMPERATURE_NOTIFICATION);
- IWL_CMD(TX_ANT_CONFIGURATION_CMD);
- IWL_CMD(REPLY_BT_COEX_PROFILE_NOTIF);
- IWL_CMD(REPLY_BT_COEX_PRIO_TABLE);
- IWL_CMD(REPLY_BT_COEX_PROT_ENV);
- IWL_CMD(REPLY_WIPAN_PARAMS);
- IWL_CMD(REPLY_WIPAN_RXON);
- IWL_CMD(REPLY_WIPAN_RXON_TIMING);
- IWL_CMD(REPLY_WIPAN_RXON_ASSOC);
- IWL_CMD(REPLY_WIPAN_QOS_PARAM);
- IWL_CMD(REPLY_WIPAN_WEPKEY);
- IWL_CMD(REPLY_WIPAN_P2P_CHANNEL_SWITCH);
- IWL_CMD(REPLY_WIPAN_NOA_NOTIFICATION);
- IWL_CMD(REPLY_WIPAN_DEACTIVATION_COMPLETE);
- IWL_CMD(REPLY_WOWLAN_PATTERNS);
- IWL_CMD(REPLY_WOWLAN_WAKEUP_FILTER);
- IWL_CMD(REPLY_WOWLAN_TSC_RSC_PARAMS);
- IWL_CMD(REPLY_WOWLAN_TKIP_PARAMS);
- IWL_CMD(REPLY_WOWLAN_KEK_KCK_MATERIAL);
- IWL_CMD(REPLY_WOWLAN_GET_STATUS);
- default:
- return "UNKNOWN";
-
- }
+ spin_unlock_irqrestore(&trans->hcmd_lock, flags);
}
#define HOST_COMPLETE_TIMEOUT (2 * HZ)
-static void iwl_generic_cmd_callback(struct iwl_priv *priv,
- struct iwl_device_cmd *cmd,
- struct iwl_rx_packet *pkt)
-{
- if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
- IWL_ERR(priv, "Bad return from %s (0x%08X)\n",
- get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
- return;
- }
-
-#ifdef CONFIG_IWLWIFI_DEBUG
- switch (cmd->hdr.cmd) {
- case REPLY_TX_LINK_QUALITY_CMD:
- case SENSITIVITY_CMD:
- IWL_DEBUG_HC_DUMP(priv, "back from %s (0x%08X)\n",
- get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
- break;
- default:
- IWL_DEBUG_HC(priv, "back from %s (0x%08X)\n",
- get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
- }
-#endif
-}
-
-static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+static int iwl_send_cmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
{
int ret;
@@ -912,81 +976,83 @@ static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
if (WARN_ON(cmd->flags & CMD_WANT_SKB))
return -EINVAL;
- /* Assign a generic callback if one is not provided */
- if (!cmd->callback)
- cmd->callback = iwl_generic_cmd_callback;
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ if (test_bit(STATUS_EXIT_PENDING, &trans->shrd->status))
return -EBUSY;
- ret = iwl_enqueue_hcmd(priv, cmd);
+ ret = iwl_enqueue_hcmd(trans, cmd);
if (ret < 0) {
- IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n",
+ IWL_ERR(trans, "Error sending %s: enqueue_hcmd failed: %d\n",
get_cmd_string(cmd->id), ret);
return ret;
}
return 0;
}
-static int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int cmd_idx;
int ret;
- lockdep_assert_held(&priv->mutex);
+ lockdep_assert_held(&trans->shrd->mutex);
- /* A synchronous command can not have a callback set. */
- if (WARN_ON(cmd->callback))
- return -EINVAL;
-
- IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n",
+ IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n",
get_cmd_string(cmd->id));
- set_bit(STATUS_HCMD_ACTIVE, &priv->status);
- IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n",
+ set_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status);
+ IWL_DEBUG_INFO(trans, "Setting HCMD_ACTIVE for command %s\n",
get_cmd_string(cmd->id));
- cmd_idx = iwl_enqueue_hcmd(priv, cmd);
+ cmd_idx = iwl_enqueue_hcmd(trans, cmd);
if (cmd_idx < 0) {
ret = cmd_idx;
- clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
- IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n",
+ clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status);
+ IWL_ERR(trans, "Error sending %s: enqueue_hcmd failed: %d\n",
get_cmd_string(cmd->id), ret);
return ret;
}
- ret = wait_event_interruptible_timeout(priv->wait_command_queue,
- !test_bit(STATUS_HCMD_ACTIVE, &priv->status),
+ ret = wait_event_timeout(trans->shrd->wait_command_queue,
+ !test_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status),
HOST_COMPLETE_TIMEOUT);
if (!ret) {
- if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) {
- IWL_ERR(priv,
+ if (test_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status)) {
+ struct iwl_tx_queue *txq =
+ &trans_pcie->txq[trans->shrd->cmd_queue];
+ struct iwl_queue *q = &txq->q;
+
+ IWL_ERR(trans,
"Error sending %s: time out after %dms.\n",
get_cmd_string(cmd->id),
jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
- clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
- IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command"
+ IWL_ERR(trans,
+ "Current CMD queue read_ptr %d write_ptr %d\n",
+ q->read_ptr, q->write_ptr);
+
+ clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status);
+ IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command"
"%s\n", get_cmd_string(cmd->id));
ret = -ETIMEDOUT;
goto cancel;
}
}
- if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
- IWL_ERR(priv, "Command %s aborted: RF KILL Switch\n",
+ if (test_bit(STATUS_RF_KILL_HW, &trans->shrd->status)) {
+ IWL_ERR(trans, "Command %s aborted: RF KILL Switch\n",
get_cmd_string(cmd->id));
ret = -ECANCELED;
goto fail;
}
- if (test_bit(STATUS_FW_ERROR, &priv->status)) {
- IWL_ERR(priv, "Command %s failed: FW Error\n",
+ if (test_bit(STATUS_FW_ERROR, &trans->shrd->status)) {
+ IWL_ERR(trans, "Command %s failed: FW Error\n",
get_cmd_string(cmd->id));
ret = -EIO;
goto fail;
}
if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_page) {
- IWL_ERR(priv, "Error: Response NULL in '%s'\n",
+ IWL_ERR(trans, "Error: Response NULL in '%s'\n",
get_cmd_string(cmd->id));
ret = -EIO;
goto cancel;
@@ -1002,35 +1068,74 @@ cancel:
* in later, it will possibly set an invalid
* address (cmd->meta.source).
*/
- priv->txq[priv->cmd_queue].meta[cmd_idx].flags &=
+ trans_pcie->txq[trans->shrd->cmd_queue].meta[cmd_idx].flags &=
~CMD_WANT_SKB;
}
fail:
if (cmd->reply_page) {
- iwl_free_pages(priv, cmd->reply_page);
+ iwl_free_pages(trans->shrd, cmd->reply_page);
cmd->reply_page = 0;
}
return ret;
}
-int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
{
if (cmd->flags & CMD_ASYNC)
- return iwl_send_cmd_async(priv, cmd);
+ return iwl_send_cmd_async(trans, cmd);
- return iwl_send_cmd_sync(priv, cmd);
+ return iwl_send_cmd_sync(trans, cmd);
}
-int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u32 flags, u16 len,
- const void *data)
+/* Frees buffers until index _not_ inclusive */
+int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
+ struct sk_buff_head *skbs)
{
- struct iwl_host_cmd cmd = {
- .id = id,
- .len = { len, },
- .data = { data, },
- .flags = flags,
- };
-
- return iwl_send_cmd(priv, &cmd);
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
+ struct iwl_queue *q = &txq->q;
+ int last_to_free;
+ int freed = 0;
+
+ /* This function is not meant to release cmd queue*/
+ if (WARN_ON(txq_id == trans->shrd->cmd_queue))
+ return 0;
+
+ /*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);
+
+ if ((index >= q->n_bd) ||
+ (iwl_queue_used(q, last_to_free) == 0)) {
+ IWL_ERR(trans, "%s: Read index for DMA queue txq id (%d), "
+ "last_to_free %d is out of range [0-%d] %d %d.\n",
+ __func__, txq_id, last_to_free, q->n_bd,
+ q->write_ptr, q->read_ptr);
+ return 0;
+ }
+
+ IWL_DEBUG_TX_REPLY(trans, "reclaim: [%d, %d, %d]\n", txq_id,
+ q->read_ptr, index);
+
+ if (WARN_ON(!skb_queue_empty(skbs)))
+ return 0;
+
+ for (;
+ q->read_ptr != index;
+ q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+
+ if (WARN_ON_ONCE(txq->skbs[txq->q.read_ptr] == NULL))
+ continue;
+
+ __skb_queue_tail(skbs, txq->skbs[txq->q.read_ptr]);
+
+ txq->skbs[txq->q.read_ptr] = NULL;
+
+ iwlagn_txq_inval_byte_cnt_tbl(trans, txq);
+
+ iwlagn_txq_free_tfd(trans, txq, txq->q.read_ptr, DMA_TO_DEVICE);
+ freed++;
+ }
+ return freed;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
new file mode 100644
index 000000000000..8e8c75c997ee
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
@@ -0,0 +1,1998 @@
+/******************************************************************************
+ *
+ * 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 <linux/debugfs.h>
+#include <linux/bitops.h>
+#include <linux/gfp.h>
+
+#include "iwl-trans.h"
+#include "iwl-trans-pcie-int.h"
+#include "iwl-csr.h"
+#include "iwl-prph.h"
+#include "iwl-shared.h"
+#include "iwl-eeprom.h"
+#include "iwl-agn-hw.h"
+
+static int iwl_trans_rx_alloc(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+ struct device *dev = bus(trans)->dev;
+
+ memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq));
+
+ spin_lock_init(&rxq->lock);
+
+ if (WARN_ON(rxq->bd || rxq->rb_stts))
+ return -EINVAL;
+
+ /* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */
+ rxq->bd = dma_alloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
+ &rxq->bd_dma, GFP_KERNEL);
+ if (!rxq->bd)
+ goto err_bd;
+ memset(rxq->bd, 0, sizeof(__le32) * RX_QUEUE_SIZE);
+
+ /*Allocate the driver's pointer to receive buffer status */
+ rxq->rb_stts = dma_alloc_coherent(dev, sizeof(*rxq->rb_stts),
+ &rxq->rb_stts_dma, GFP_KERNEL);
+ if (!rxq->rb_stts)
+ goto err_rb_stts;
+ memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
+
+ return 0;
+
+err_rb_stts:
+ dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
+ rxq->bd, rxq->bd_dma);
+ memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
+ rxq->bd = NULL;
+err_bd:
+ return -ENOMEM;
+}
+
+static void iwl_trans_rxq_free_rx_bufs(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+ int i;
+
+ /* Fill the rx_used queue with _all_ of the Rx buffers */
+ for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
+ /* In the reset function, these buffers may have been allocated
+ * to an SKB, so we need to unmap and free potential storage */
+ if (rxq->pool[i].page != NULL) {
+ dma_unmap_page(bus(trans)->dev, rxq->pool[i].page_dma,
+ PAGE_SIZE << hw_params(trans).rx_page_order,
+ DMA_FROM_DEVICE);
+ __free_pages(rxq->pool[i].page,
+ hw_params(trans).rx_page_order);
+ rxq->pool[i].page = NULL;
+ }
+ list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+ }
+}
+
+static void iwl_trans_rx_hw_init(struct iwl_trans *trans,
+ struct iwl_rx_queue *rxq)
+{
+ u32 rb_size;
+ const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
+ u32 rb_timeout = RX_RB_TIMEOUT; /* FIXME: RX_RB_TIMEOUT for all devices? */
+
+ if (iwlagn_mod_params.amsdu_size_8K)
+ rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
+ else
+ rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
+
+ /* Stop Rx DMA */
+ iwl_write_direct32(bus(trans), FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+
+ /* Reset driver's Rx queue write index */
+ iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
+
+ /* Tell device where to find RBD circular buffer in DRAM */
+ iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_RBDCB_BASE_REG,
+ (u32)(rxq->bd_dma >> 8));
+
+ /* Tell device where in DRAM to update its Rx status */
+ iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_STTS_WPTR_REG,
+ rxq->rb_stts_dma >> 4);
+
+ /* Enable Rx DMA
+ * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in
+ * the credit mechanism in 5000 HW RX FIFO
+ * Direct rx interrupts to hosts
+ * Rx buffer size 4 or 8k
+ * RB timeout 0x10
+ * 256 RBDs
+ */
+ iwl_write_direct32(bus(trans), FH_MEM_RCSR_CHNL0_CONFIG_REG,
+ FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
+ FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY |
+ FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
+ FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK |
+ rb_size|
+ (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
+ (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
+
+ /* Set interrupt coalescing timer to default (2048 usecs) */
+ iwl_write8(bus(trans), CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
+}
+
+static int iwl_rx_init(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+
+ int i, err;
+ unsigned long flags;
+
+ if (!rxq->bd) {
+ err = iwl_trans_rx_alloc(trans);
+ if (err)
+ return err;
+ }
+
+ spin_lock_irqsave(&rxq->lock, flags);
+ INIT_LIST_HEAD(&rxq->rx_free);
+ INIT_LIST_HEAD(&rxq->rx_used);
+
+ iwl_trans_rxq_free_rx_bufs(trans);
+
+ for (i = 0; i < RX_QUEUE_SIZE; i++)
+ rxq->queue[i] = NULL;
+
+ /* Set us so that we have processed and used all buffers, but have
+ * not restocked the Rx queue with fresh buffers */
+ rxq->read = rxq->write = 0;
+ rxq->write_actual = 0;
+ rxq->free_count = 0;
+ spin_unlock_irqrestore(&rxq->lock, flags);
+
+ iwlagn_rx_replenish(trans);
+
+ iwl_trans_rx_hw_init(trans, rxq);
+
+ spin_lock_irqsave(&trans->shrd->lock, flags);
+ rxq->need_update = 1;
+ iwl_rx_queue_update_write_ptr(trans, rxq);
+ spin_unlock_irqrestore(&trans->shrd->lock, flags);
+
+ return 0;
+}
+
+static void iwl_trans_pcie_rx_free(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+
+ unsigned long flags;
+
+ /*if rxq->bd is NULL, it means that nothing has been allocated,
+ * exit now */
+ if (!rxq->bd) {
+ IWL_DEBUG_INFO(trans, "Free NULL rx context\n");
+ return;
+ }
+
+ spin_lock_irqsave(&rxq->lock, flags);
+ iwl_trans_rxq_free_rx_bufs(trans);
+ spin_unlock_irqrestore(&rxq->lock, flags);
+
+ dma_free_coherent(bus(trans)->dev, sizeof(__le32) * RX_QUEUE_SIZE,
+ rxq->bd, rxq->bd_dma);
+ memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
+ rxq->bd = NULL;
+
+ if (rxq->rb_stts)
+ dma_free_coherent(bus(trans)->dev,
+ sizeof(struct iwl_rb_status),
+ rxq->rb_stts, rxq->rb_stts_dma);
+ else
+ IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n");
+ memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma));
+ rxq->rb_stts = NULL;
+}
+
+static int iwl_trans_rx_stop(struct iwl_trans *trans)
+{
+
+ /* stop Rx DMA */
+ iwl_write_direct32(bus(trans), FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+ return iwl_poll_direct_bit(bus(trans), FH_MEM_RSSR_RX_STATUS_REG,
+ FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
+}
+
+static inline int iwlagn_alloc_dma_ptr(struct iwl_trans *trans,
+ struct iwl_dma_ptr *ptr, size_t size)
+{
+ if (WARN_ON(ptr->addr))
+ return -EINVAL;
+
+ ptr->addr = dma_alloc_coherent(bus(trans)->dev, size,
+ &ptr->dma, GFP_KERNEL);
+ if (!ptr->addr)
+ return -ENOMEM;
+ ptr->size = size;
+ return 0;
+}
+
+static inline void iwlagn_free_dma_ptr(struct iwl_trans *trans,
+ struct iwl_dma_ptr *ptr)
+{
+ if (unlikely(!ptr->addr))
+ return;
+
+ dma_free_coherent(bus(trans)->dev, ptr->size, ptr->addr, ptr->dma);
+ memset(ptr, 0, sizeof(*ptr));
+}
+
+static int iwl_trans_txq_alloc(struct iwl_trans *trans,
+ struct iwl_tx_queue *txq, int slots_num,
+ u32 txq_id)
+{
+ size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX;
+ int i;
+
+ if (WARN_ON(txq->meta || txq->cmd || txq->skbs || txq->tfds))
+ return -EINVAL;
+
+ txq->q.n_window = slots_num;
+
+ txq->meta = kcalloc(slots_num, sizeof(txq->meta[0]), GFP_KERNEL);
+ txq->cmd = kcalloc(slots_num, sizeof(txq->cmd[0]), GFP_KERNEL);
+
+ if (!txq->meta || !txq->cmd)
+ goto error;
+
+ if (txq_id == trans->shrd->cmd_queue)
+ for (i = 0; i < slots_num; i++) {
+ txq->cmd[i] = kmalloc(sizeof(struct iwl_device_cmd),
+ GFP_KERNEL);
+ if (!txq->cmd[i])
+ goto error;
+ }
+
+ /* 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) {
+ txq->skbs = kcalloc(TFD_QUEUE_SIZE_MAX, sizeof(txq->skbs[0]),
+ GFP_KERNEL);
+ if (!txq->skbs) {
+ IWL_ERR(trans, "kmalloc for auxiliary BD "
+ "structures failed\n");
+ goto error;
+ }
+ } else {
+ txq->skbs = NULL;
+ }
+
+ /* Circular buffer of transmit frame descriptors (TFDs),
+ * shared with device */
+ txq->tfds = dma_alloc_coherent(bus(trans)->dev, tfd_sz,
+ &txq->q.dma_addr, GFP_KERNEL);
+ if (!txq->tfds) {
+ IWL_ERR(trans, "dma_alloc_coherent(%zd) failed\n", tfd_sz);
+ goto error;
+ }
+ txq->q.id = txq_id;
+
+ return 0;
+error:
+ kfree(txq->skbs);
+ 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)
+ for (i = 0; i < slots_num; i++)
+ kfree(txq->cmd[i]);
+ kfree(txq->meta);
+ kfree(txq->cmd);
+ txq->meta = NULL;
+ txq->cmd = NULL;
+
+ return -ENOMEM;
+
+}
+
+static int iwl_trans_txq_init(struct iwl_trans *trans, struct iwl_tx_queue *txq,
+ int slots_num, u32 txq_id)
+{
+ int ret;
+
+ txq->need_update = 0;
+ memset(txq->meta, 0, sizeof(txq->meta[0]) * slots_num);
+
+ /*
+ * For the default queues 0-3, set up the swq_id
+ * already -- all others need to get one later
+ * (if they need one at all).
+ */
+ if (txq_id < 4)
+ iwl_set_swq_id(txq, txq_id, txq_id);
+
+ /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
+ * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
+ BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
+
+ /* Initialize queue's high/low-water marks, and head/tail indexes */
+ ret = iwl_queue_init(&txq->q, TFD_QUEUE_SIZE_MAX, slots_num,
+ txq_id);
+ if (ret)
+ return ret;
+
+ /*
+ * Tell nic where to find circular buffer of Tx Frame Descriptors for
+ * given Tx queue, and enable the DMA channel used for that queue.
+ * Circular buffer (TFD queue in DRAM) physical base address */
+ iwl_write_direct32(bus(trans), FH_MEM_CBBC_QUEUE(txq_id),
+ txq->q.dma_addr >> 8);
+
+ return 0;
+}
+
+/**
+ * iwl_tx_queue_unmap - Unmap any remaining DMA mappings and free skb's
+ */
+static void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ 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;
+
+ if (!q->n_bd)
+ return;
+
+ /* In the command queue, all the TBs are mapped as BIDI
+ * so unmap them as such.
+ */
+ if (txq_id == trans->shrd->cmd_queue)
+ dma_dir = DMA_BIDIRECTIONAL;
+ else
+ dma_dir = DMA_TO_DEVICE;
+
+ spin_lock_irqsave(&trans->shrd->sta_lock, flags);
+ 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(&trans->shrd->sta_lock, flags);
+}
+
+/**
+ * iwl_tx_queue_free - Deallocate DMA queue.
+ * @txq: Transmit queue to deallocate.
+ *
+ * Empty queue by removing and destroying all BD's.
+ * Free all buffers.
+ * 0-fill, but do not free "txq" descriptor structure.
+ */
+static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
+ struct device *dev = bus(trans)->dev;
+ int i;
+ if (WARN_ON(!txq))
+ return;
+
+ iwl_tx_queue_unmap(trans, txq_id);
+
+ /* De-alloc array of command/tx buffers */
+
+ if (txq_id == trans->shrd->cmd_queue)
+ for (i = 0; i < txq->q.n_window; i++)
+ kfree(txq->cmd[i]);
+
+ /* De-alloc circular buffer of TFDs */
+ if (txq->q.n_bd) {
+ dma_free_coherent(dev, sizeof(struct iwl_tfd) *
+ txq->q.n_bd, txq->tfds, txq->q.dma_addr);
+ memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr));
+ }
+
+ /* De-alloc array of per-TFD driver data */
+ kfree(txq->skbs);
+ txq->skbs = NULL;
+
+ /* deallocate arrays */
+ kfree(txq->cmd);
+ kfree(txq->meta);
+ txq->cmd = NULL;
+ txq->meta = NULL;
+
+ /* 0-fill queue descriptor structure */
+ memset(txq, 0, sizeof(*txq));
+}
+
+/**
+ * iwl_trans_tx_free - Free TXQ Context
+ *
+ * Destroy all TX DMA queues and structures
+ */
+static void iwl_trans_pcie_tx_free(struct iwl_trans *trans)
+{
+ int txq_id;
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+ /* Tx queues */
+ if (trans_pcie->txq) {
+ for (txq_id = 0;
+ txq_id < hw_params(trans).max_txq_num; txq_id++)
+ iwl_tx_queue_free(trans, txq_id);
+ }
+
+ kfree(trans_pcie->txq);
+ trans_pcie->txq = NULL;
+
+ iwlagn_free_dma_ptr(trans, &trans_pcie->kw);
+
+ iwlagn_free_dma_ptr(trans, &trans_pcie->scd_bc_tbls);
+}
+
+/**
+ * iwl_trans_tx_alloc - allocate TX context
+ * Allocate all Tx DMA structures and initialize them
+ *
+ * @param priv
+ * @return error code
+ */
+static int iwl_trans_tx_alloc(struct iwl_trans *trans)
+{
+ int ret;
+ 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 *
+ sizeof(struct iwlagn_scd_bc_tbl);
+
+ /*It is not allowed to alloc twice, so warn when this happens.
+ * We cannot rely on the previous allocation, so free and fail */
+ if (WARN_ON(trans_pcie->txq)) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = iwlagn_alloc_dma_ptr(trans, &trans_pcie->scd_bc_tbls,
+ scd_bc_tbls_size);
+ if (ret) {
+ IWL_ERR(trans, "Scheduler BC Table allocation failed\n");
+ goto error;
+ }
+
+ /* Alloc keep-warm buffer */
+ ret = iwlagn_alloc_dma_ptr(trans, &trans_pcie->kw, IWL_KW_SIZE);
+ if (ret) {
+ IWL_ERR(trans, "Keep Warm allocation failed\n");
+ goto error;
+ }
+
+ trans_pcie->txq = kcalloc(hw_params(trans).max_txq_num,
+ sizeof(struct iwl_tx_queue), GFP_KERNEL);
+ if (!trans_pcie->txq) {
+ IWL_ERR(trans, "Not enough memory for txq\n");
+ ret = ENOMEM;
+ goto error;
+ }
+
+ /* 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) ?
+ TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+ ret = iwl_trans_txq_alloc(trans, &trans_pcie->txq[txq_id],
+ slots_num, txq_id);
+ if (ret) {
+ IWL_ERR(trans, "Tx %d queue alloc failed\n", txq_id);
+ goto error;
+ }
+ }
+
+ return 0;
+
+error:
+ iwl_trans_pcie_tx_free(trans);
+
+ return ret;
+}
+static int iwl_tx_init(struct iwl_trans *trans)
+{
+ int ret;
+ int txq_id, slots_num;
+ unsigned long flags;
+ bool alloc = false;
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+ if (!trans_pcie->txq) {
+ ret = iwl_trans_tx_alloc(trans);
+ if (ret)
+ goto error;
+ alloc = true;
+ }
+
+ spin_lock_irqsave(&trans->shrd->lock, flags);
+
+ /* Turn off all Tx DMA fifos */
+ iwl_write_prph(bus(trans), SCD_TXFACT, 0);
+
+ /* Tell NIC where to find the "keep warm" buffer */
+ iwl_write_direct32(bus(trans), FH_KW_MEM_ADDR_REG,
+ trans_pcie->kw.dma >> 4);
+
+ spin_unlock_irqrestore(&trans->shrd->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) ?
+ TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+ ret = iwl_trans_txq_init(trans, &trans_pcie->txq[txq_id],
+ slots_num, txq_id);
+ if (ret) {
+ IWL_ERR(trans, "Tx %d queue init failed\n", txq_id);
+ goto error;
+ }
+ }
+
+ return 0;
+error:
+ /*Upon error, free only if we allocated something */
+ if (alloc)
+ iwl_trans_pcie_tx_free(trans);
+ return ret;
+}
+
+static void iwl_set_pwr_vmain(struct iwl_trans *trans)
+{
+/*
+ * (for documentation purposes)
+ * to set power to V_AUX, do:
+
+ if (pci_pme_capable(priv->pci_dev, PCI_D3cold))
+ iwl_set_bits_mask_prph(bus(trans), APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
+ ~APMG_PS_CTRL_MSK_PWR_SRC);
+ */
+
+ iwl_set_bits_mask_prph(bus(trans), APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
+ ~APMG_PS_CTRL_MSK_PWR_SRC);
+}
+
+static int iwl_nic_init(struct iwl_trans *trans)
+{
+ unsigned long flags;
+
+ /* nic_init */
+ spin_lock_irqsave(&trans->shrd->lock, flags);
+ iwl_apm_init(priv(trans));
+
+ /* Set interrupt coalescing calibration timer to default (512 usecs) */
+ iwl_write8(bus(trans), CSR_INT_COALESCING,
+ IWL_HOST_INT_CALIB_TIMEOUT_DEF);
+
+ spin_unlock_irqrestore(&trans->shrd->lock, flags);
+
+ iwl_set_pwr_vmain(trans);
+
+ iwl_nic_config(priv(trans));
+
+ /* Allocate the RX queue, or reset if it is already allocated */
+ iwl_rx_init(trans);
+
+ /* Allocate or reset and init all Tx and Command queues */
+ if (iwl_tx_init(trans))
+ return -ENOMEM;
+
+ if (hw_params(trans).shadow_reg_enable) {
+ /* enable shadow regs in HW */
+ iwl_set_bit(bus(trans), CSR_MAC_SHADOW_REG_CTRL,
+ 0x800FFFFF);
+ }
+
+ set_bit(STATUS_INIT, &trans->shrd->status);
+
+ return 0;
+}
+
+#define HW_READY_TIMEOUT (50)
+
+/* Note: returns poll_bit return value, which is >= 0 if success */
+static int iwl_set_hw_ready(struct iwl_trans *trans)
+{
+ int ret;
+
+ iwl_set_bit(bus(trans), CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
+
+ /* See if we got it */
+ ret = iwl_poll_bit(bus(trans), CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
+ CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
+ HW_READY_TIMEOUT);
+
+ IWL_DEBUG_INFO(trans, "hardware%s ready\n", ret < 0 ? " not" : "");
+ return ret;
+}
+
+/* Note: returns standard 0/-ERROR code */
+static int iwl_trans_pcie_prepare_card_hw(struct iwl_trans *trans)
+{
+ int ret;
+
+ IWL_DEBUG_INFO(trans, "iwl_trans_prepare_card_hw enter\n");
+
+ ret = iwl_set_hw_ready(trans);
+ if (ret >= 0)
+ return 0;
+
+ /* If HW is not ready, prepare the conditions to check again */
+ iwl_set_bit(bus(trans), CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_PREPARE);
+
+ ret = iwl_poll_bit(bus(trans), CSR_HW_IF_CONFIG_REG,
+ ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
+ CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
+
+ if (ret < 0)
+ return ret;
+
+ /* HW should be ready by now, check again. */
+ ret = iwl_set_hw_ready(trans);
+ if (ret >= 0)
+ return 0;
+ return ret;
+}
+
+#define IWL_AC_UNSET -1
+
+struct queue_to_fifo_ac {
+ s8 fifo, ac;
+};
+
+static const struct queue_to_fifo_ac iwlagn_default_queue_to_tx_fifo[] = {
+ { IWL_TX_FIFO_VO, IEEE80211_AC_VO, },
+ { IWL_TX_FIFO_VI, IEEE80211_AC_VI, },
+ { IWL_TX_FIFO_BE, IEEE80211_AC_BE, },
+ { IWL_TX_FIFO_BK, IEEE80211_AC_BK, },
+ { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
+ { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
+ { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
+ { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
+ { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
+ { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
+ { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
+};
+
+static const struct queue_to_fifo_ac iwlagn_ipan_queue_to_tx_fifo[] = {
+ { IWL_TX_FIFO_VO, IEEE80211_AC_VO, },
+ { IWL_TX_FIFO_VI, IEEE80211_AC_VI, },
+ { IWL_TX_FIFO_BE, IEEE80211_AC_BE, },
+ { IWL_TX_FIFO_BK, IEEE80211_AC_BK, },
+ { IWL_TX_FIFO_BK_IPAN, IEEE80211_AC_BK, },
+ { IWL_TX_FIFO_BE_IPAN, IEEE80211_AC_BE, },
+ { IWL_TX_FIFO_VI_IPAN, IEEE80211_AC_VI, },
+ { IWL_TX_FIFO_VO_IPAN, IEEE80211_AC_VO, },
+ { IWL_TX_FIFO_BE_IPAN, 2, },
+ { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
+ { IWL_TX_FIFO_AUX, IWL_AC_UNSET, },
+};
+
+static const u8 iwlagn_bss_ac_to_fifo[] = {
+ IWL_TX_FIFO_VO,
+ IWL_TX_FIFO_VI,
+ IWL_TX_FIFO_BE,
+ IWL_TX_FIFO_BK,
+};
+static const u8 iwlagn_bss_ac_to_queue[] = {
+ 0, 1, 2, 3,
+};
+static const u8 iwlagn_pan_ac_to_fifo[] = {
+ IWL_TX_FIFO_VO_IPAN,
+ IWL_TX_FIFO_VI_IPAN,
+ IWL_TX_FIFO_BE_IPAN,
+ IWL_TX_FIFO_BK_IPAN,
+};
+static const u8 iwlagn_pan_ac_to_queue[] = {
+ 7, 6, 5, 4,
+};
+
+static int iwl_trans_pcie_start_device(struct iwl_trans *trans)
+{
+ int ret;
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
+
+ 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;
+
+ trans_pcie->ac_to_fifo[IWL_RXON_CTX_BSS] = iwlagn_bss_ac_to_fifo;
+ trans_pcie->ac_to_fifo[IWL_RXON_CTX_PAN] = iwlagn_pan_ac_to_fifo;
+
+ 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_trans_pcie_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(bus(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);
+
+ if (iwl_is_rfkill(trans->shrd)) {
+ iwl_set_hw_rfkill_state(priv(trans), true);
+ iwl_enable_interrupts(trans);
+ return -ERFKILL;
+ }
+
+ iwl_write32(bus(trans), CSR_INT, 0xFFFFFFFF);
+
+ ret = iwl_nic_init(trans);
+ if (ret) {
+ IWL_ERR(trans, "Unable to init nic\n");
+ return ret;
+ }
+
+ /* make sure rfkill handshake bits are cleared */
+ iwl_write32(bus(trans), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+ iwl_write32(bus(trans), CSR_UCODE_DRV_GP1_CLR,
+ CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+ /* clear (again), then enable host interrupts */
+ iwl_write32(bus(trans), CSR_INT, 0xFFFFFFFF);
+ iwl_enable_interrupts(trans);
+
+ /* really make sure rfkill handshake bits are cleared */
+ iwl_write32(bus(trans), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+ iwl_write32(bus(trans), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+ return 0;
+}
+
+/*
+ * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
+ * must be called under priv->shrd->lock and mac access
+ */
+static void iwl_trans_txq_set_sched(struct iwl_trans *trans, u32 mask)
+{
+ iwl_write_prph(bus(trans), SCD_TXFACT, mask);
+}
+
+static void iwl_trans_pcie_tx_start(struct iwl_trans *trans)
+{
+ const struct queue_to_fifo_ac *queue_to_fifo;
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
+ u32 a;
+ unsigned long flags;
+ int i, chan;
+ u32 reg_val;
+
+ spin_lock_irqsave(&trans->shrd->lock, flags);
+
+ trans_pcie->scd_base_addr =
+ iwl_read_prph(bus(trans), SCD_SRAM_BASE_ADDR);
+ a = trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND;
+ /* reset conext data memory */
+ for (; a < trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND;
+ a += 4)
+ iwl_write_targ_mem(bus(trans), a, 0);
+ /* reset tx status memory */
+ for (; a < trans_pcie->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND;
+ a += 4)
+ iwl_write_targ_mem(bus(trans), a, 0);
+ for (; a < trans_pcie->scd_base_addr +
+ SCD_TRANS_TBL_OFFSET_QUEUE(hw_params(trans).max_txq_num);
+ a += 4)
+ iwl_write_targ_mem(bus(trans), a, 0);
+
+ iwl_write_prph(bus(trans), SCD_DRAM_BASE_ADDR,
+ trans_pcie->scd_bc_tbls.dma >> 10);
+
+ /* Enable DMA channel */
+ for (chan = 0; chan < FH_TCSR_CHNL_NUM ; chan++)
+ iwl_write_direct32(bus(trans), FH_TCSR_CHNL_TX_CONFIG_REG(chan),
+ FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+ FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
+
+ /* Update FH chicken bits */
+ reg_val = iwl_read_direct32(bus(trans), FH_TX_CHICKEN_BITS_REG);
+ iwl_write_direct32(bus(trans), FH_TX_CHICKEN_BITS_REG,
+ reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
+
+ iwl_write_prph(bus(trans), SCD_QUEUECHAIN_SEL,
+ SCD_QUEUECHAIN_SEL_ALL(trans));
+ iwl_write_prph(bus(trans), SCD_AGGR_SEL, 0);
+
+ /* initiate the queues */
+ for (i = 0; i < hw_params(trans).max_txq_num; i++) {
+ iwl_write_prph(bus(trans), SCD_QUEUE_RDPTR(i), 0);
+ iwl_write_direct32(bus(trans), HBUS_TARG_WRPTR, 0 | (i << 8));
+ iwl_write_targ_mem(bus(trans), trans_pcie->scd_base_addr +
+ SCD_CONTEXT_QUEUE_OFFSET(i), 0);
+ iwl_write_targ_mem(bus(trans), trans_pcie->scd_base_addr +
+ SCD_CONTEXT_QUEUE_OFFSET(i) +
+ sizeof(u32),
+ ((SCD_WIN_SIZE <<
+ SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
+ SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
+ ((SCD_FRAME_LIMIT <<
+ SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
+ SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
+ }
+
+ iwl_write_prph(bus(trans), SCD_INTERRUPT_MASK,
+ IWL_MASK(0, hw_params(trans).max_txq_num));
+
+ /* Activate all Tx DMA/FIFO channels */
+ iwl_trans_txq_set_sched(trans, IWL_MASK(0, 7));
+
+ /* map queues to FIFOs */
+ if (trans->shrd->valid_contexts != BIT(IWL_RXON_CTX_BSS))
+ queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo;
+ else
+ queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
+
+ iwl_trans_set_wr_ptrs(trans, trans->shrd->cmd_queue, 0);
+
+ /* make sure all queue are not stopped */
+ memset(&trans_pcie->queue_stopped[0], 0,
+ sizeof(trans_pcie->queue_stopped));
+ for (i = 0; i < 4; i++)
+ atomic_set(&trans_pcie->queue_stop_count[i], 0);
+
+ /* reset to 0 to enable all the queue first */
+ trans_pcie->txq_ctx_active_msk = 0;
+
+ BUILD_BUG_ON(ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo) <
+ IWLAGN_FIRST_AMPDU_QUEUE);
+ BUILD_BUG_ON(ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo) <
+ IWLAGN_FIRST_AMPDU_QUEUE);
+
+ for (i = 0; i < IWLAGN_FIRST_AMPDU_QUEUE; i++) {
+ int fifo = queue_to_fifo[i].fifo;
+ int ac = queue_to_fifo[i].ac;
+
+ iwl_txq_ctx_activate(trans_pcie, i);
+
+ if (fifo == IWL_TX_FIFO_UNUSED)
+ continue;
+
+ if (ac != IWL_AC_UNSET)
+ iwl_set_swq_id(&trans_pcie->txq[i], ac, i);
+ iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[i],
+ fifo, 0);
+ }
+
+ spin_unlock_irqrestore(&trans->shrd->lock, flags);
+
+ /* Enable L1-Active */
+ iwl_clear_bits_prph(bus(trans), APMG_PCIDEV_STT_REG,
+ APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+}
+
+/**
+ * iwlagn_txq_ctx_stop - Stop all Tx DMA channels
+ */
+static int iwl_trans_tx_stop(struct iwl_trans *trans)
+{
+ int ch, txq_id;
+ 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);
+
+ iwl_trans_txq_set_sched(trans, 0);
+
+ /* Stop each Tx DMA channel, and wait for it to be idle */
+ for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) {
+ iwl_write_direct32(bus(trans),
+ FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
+ if (iwl_poll_direct_bit(bus(trans), FH_TSSR_TX_STATUS_REG,
+ FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
+ 1000))
+ IWL_ERR(trans, "Failing on timeout while stopping"
+ " DMA channel %d [0x%08x]", ch,
+ iwl_read_direct32(bus(trans),
+ FH_TSSR_TX_STATUS_REG));
+ }
+ spin_unlock_irqrestore(&trans->shrd->lock, flags);
+
+ if (!trans_pcie->txq) {
+ IWL_WARN(trans, "Stopping tx queues that aren't allocated...");
+ return 0;
+ }
+
+ /* Unmap DMA from host system and free skb's */
+ for (txq_id = 0; txq_id < hw_params(trans).max_txq_num; txq_id++)
+ iwl_tx_queue_unmap(trans, txq_id);
+
+ return 0;
+}
+
+static void iwl_trans_pcie_disable_sync_irq(struct iwl_trans *trans)
+{
+ unsigned long flags;
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
+
+ spin_lock_irqsave(&trans->shrd->lock, flags);
+ iwl_disable_interrupts(trans);
+ spin_unlock_irqrestore(&trans->shrd->lock, flags);
+
+ /* wait to make sure we flush pending tasklet*/
+ synchronize_irq(bus(trans)->irq);
+ tasklet_kill(&trans_pcie->irq_tasklet);
+}
+
+static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
+{
+ /* stop and reset the on-board processor */
+ iwl_write32(bus(trans), CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
+
+ /* tell the device to stop sending interrupts */
+ iwl_trans_pcie_disable_sync_irq(trans);
+
+ /* device going down, Stop using ICT table */
+ iwl_disable_ict(trans);
+
+ /*
+ * If a HW restart happens during firmware loading,
+ * then the firmware loading might call this function
+ * and later it might be called again due to the
+ * restart. So don't process again if the device is
+ * already dead.
+ */
+ if (test_bit(STATUS_DEVICE_ENABLED, &trans->shrd->status)) {
+ iwl_trans_tx_stop(trans);
+ iwl_trans_rx_stop(trans);
+
+ /* Power-down device's busmaster DMA clocks */
+ iwl_write_prph(bus(trans), APMG_CLK_DIS_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT);
+ udelay(5);
+ }
+
+ /* Make sure (redundant) we've released our request to stay awake */
+ iwl_clear_bit(bus(trans), CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+
+ /* Stop the device, and put it in low power state */
+ iwl_apm_stop(priv(trans));
+}
+
+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)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct iwl_tx_cmd *tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload;
+ struct iwl_cmd_meta *out_meta;
+ struct iwl_tx_queue *txq;
+ struct iwl_queue *q;
+
+ dma_addr_t phys_addr = 0;
+ dma_addr_t txcmd_phys;
+ dma_addr_t scratch_phys;
+ u16 len, firstlen, secondlen;
+ u16 seq_number = 0;
+ u8 wait_write_ptr = 0;
+ u8 txq_id;
+ u8 tid = 0;
+ bool is_agg = false;
+ __le16 fc = hdr->frame_control;
+ u8 hdr_len = ieee80211_hdrlen(fc);
+
+ /*
+ * Send this frame after DTIM -- there's a special queue
+ * reserved for this for contexts that support AP mode.
+ */
+ if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
+ txq_id = trans_pcie->mcast_queue[ctx];
+
+ /*
+ * The microcode will clear the more data
+ * bit in the last frame it transmits.
+ */
+ hdr->frame_control |=
+ cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+ } else if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
+ txq_id = IWL_AUX_QUEUE;
+ else
+ txq_id =
+ trans_pcie->ac_to_queue[ctx][skb_get_queue_mapping(skb)];
+
+ if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) {
+ u8 *qc = NULL;
+ struct iwl_tid_data *tid_data;
+ qc = ieee80211_get_qos_ctl(hdr);
+ tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+ tid_data = &trans->shrd->tid_data[sta_id][tid];
+
+ if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
+ return -1;
+
+ seq_number = tid_data->seq_number;
+ seq_number &= IEEE80211_SCTL_SEQ;
+ hdr->seq_ctrl = hdr->seq_ctrl &
+ cpu_to_le16(IEEE80211_SCTL_FRAG);
+ hdr->seq_ctrl |= cpu_to_le16(seq_number);
+ seq_number += 0x10;
+ /* aggregation is on for this <sta,tid> */
+ if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+ WARN_ON_ONCE(tid_data->agg.state != IWL_AGG_ON);
+ txq_id = tid_data->agg.txq_id;
+ is_agg = true;
+ }
+ }
+
+ /* Copy MAC header from skb into command buffer */
+ memcpy(tx_cmd->hdr, hdr, hdr_len);
+
+ txq = &trans_pcie->txq[txq_id];
+ q = &txq->q;
+
+ /* Set up driver data for this TFD */
+ txq->skbs[q->write_ptr] = skb;
+ txq->cmd[q->write_ptr] = dev_cmd;
+
+ dev_cmd->hdr.cmd = REPLY_TX;
+ dev_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
+ INDEX_TO_SEQ(q->write_ptr)));
+
+ /* Set up first empty entry in queue's array of Tx/cmd buffers */
+ out_meta = &txq->meta[q->write_ptr];
+
+ /*
+ * Use the first empty entry in this queue's command buffer array
+ * to contain the Tx command and MAC header concatenated together
+ * (payload data will be in another buffer).
+ * Size of this varies, due to varying MAC header length.
+ * If end is not dword aligned, we'll have 2 extra bytes at the end
+ * of the MAC header (device reads on dword boundaries).
+ * We'll tell device about this padding later.
+ */
+ len = sizeof(struct iwl_tx_cmd) +
+ sizeof(struct iwl_cmd_header) + hdr_len;
+ firstlen = (len + 3) & ~3;
+
+ /* Tell NIC about any 2-byte padding after MAC header */
+ if (firstlen != len)
+ tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
+
+ /* Physical address of this Tx command's header (not MAC header!),
+ * within command buffer array. */
+ txcmd_phys = dma_map_single(bus(trans)->dev,
+ &dev_cmd->hdr, firstlen,
+ DMA_BIDIRECTIONAL);
+ if (unlikely(dma_mapping_error(bus(trans)->dev, txcmd_phys)))
+ return -1;
+ dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
+ dma_unmap_len_set(out_meta, len, firstlen);
+
+ if (!ieee80211_has_morefrags(fc)) {
+ txq->need_update = 1;
+ } else {
+ wait_write_ptr = 1;
+ txq->need_update = 0;
+ }
+
+ /* Set up TFD's 2nd entry to point directly to remainder of skb,
+ * if any (802.11 null frames have no payload). */
+ secondlen = skb->len - hdr_len;
+ if (secondlen > 0) {
+ phys_addr = dma_map_single(bus(trans)->dev, skb->data + hdr_len,
+ secondlen, DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(bus(trans)->dev, phys_addr))) {
+ dma_unmap_single(bus(trans)->dev,
+ dma_unmap_addr(out_meta, mapping),
+ dma_unmap_len(out_meta, len),
+ DMA_BIDIRECTIONAL);
+ return -1;
+ }
+ }
+
+ /* Attach buffers to TFD */
+ iwlagn_txq_attach_buf_to_tfd(trans, txq, txcmd_phys, firstlen, 1);
+ if (secondlen > 0)
+ iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr,
+ secondlen, 0);
+
+ scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
+ offsetof(struct iwl_tx_cmd, scratch);
+
+ /* take back ownership of DMA buffer to enable update */
+ dma_sync_single_for_cpu(bus(trans)->dev, txcmd_phys, firstlen,
+ DMA_BIDIRECTIONAL);
+ tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
+ tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
+
+ IWL_DEBUG_TX(trans, "sequence nr = 0X%x\n",
+ le16_to_cpu(dev_cmd->hdr.sequence));
+ IWL_DEBUG_TX(trans, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
+ iwl_print_hex_dump(trans, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
+ iwl_print_hex_dump(trans, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
+
+ /* Set up entry for this TFD in Tx byte-count array */
+ if (is_agg)
+ iwl_trans_txq_update_byte_cnt_tbl(trans, txq,
+ le16_to_cpu(tx_cmd->len));
+
+ dma_sync_single_for_device(bus(trans)->dev, txcmd_phys, firstlen,
+ DMA_BIDIRECTIONAL);
+
+ trace_iwlwifi_dev_tx(priv(trans),
+ &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr],
+ sizeof(struct iwl_tfd),
+ &dev_cmd->hdr, firstlen,
+ skb->data + hdr_len, secondlen);
+
+ /* Tell device the write index *just past* this latest filled TFD */
+ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
+ iwl_txq_update_write_ptr(trans, txq);
+
+ if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) {
+ trans->shrd->tid_data[sta_id][tid].tfds_in_queue++;
+ if (!ieee80211_has_morefrags(fc))
+ trans->shrd->tid_data[sta_id][tid].seq_number =
+ seq_number;
+ }
+
+ /*
+ * At this point the frame is "transmitted" successfully
+ * and we will get a TX status notification eventually,
+ * regardless of the value of ret. "ret" only indicates
+ * whether or not we should update the write pointer.
+ */
+ if (iwl_queue_space(q) < q->high_mark) {
+ if (wait_write_ptr) {
+ txq->need_update = 1;
+ iwl_txq_update_write_ptr(trans, txq);
+ } else {
+ iwl_stop_queue(trans, txq);
+ }
+ }
+ return 0;
+}
+
+static void iwl_trans_pcie_kick_nic(struct iwl_trans *trans)
+{
+ /* Remove all resets to allow NIC to operate */
+ iwl_write32(bus(trans), CSR_RESET, 0);
+}
+
+static int iwl_trans_pcie_request_irq(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
+ int err;
+
+ trans_pcie->inta_mask = CSR_INI_SET_MASK;
+
+ tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long))
+ iwl_irq_tasklet, (unsigned long)trans);
+
+ iwl_alloc_isr_ict(trans);
+
+ err = request_irq(bus(trans)->irq, iwl_isr_ict, IRQF_SHARED,
+ DRV_NAME, trans);
+ if (err) {
+ IWL_ERR(trans, "Error allocating IRQ %d\n", bus(trans)->irq);
+ iwl_free_isr_ict(trans);
+ return err;
+ }
+
+ INIT_WORK(&trans_pcie->rx_replenish, iwl_bg_rx_replenish);
+ return 0;
+}
+
+static int iwlagn_txq_check_empty(struct iwl_trans *trans,
+ int sta_id, u8 tid, int txq_id)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_queue *q = &trans_pcie->txq[txq_id].q;
+ struct iwl_tid_data *tid_data = &trans->shrd->tid_data[sta_id][tid];
+
+ lockdep_assert_held(&trans->shrd->sta_lock);
+
+ switch (trans->shrd->tid_data[sta_id][tid].agg.state) {
+ case IWL_EMPTYING_HW_QUEUE_DELBA:
+ /* We are reclaiming the last packet of the */
+ /* aggregated HW queue */
+ if ((txq_id == tid_data->agg.txq_id) &&
+ (q->read_ptr == q->write_ptr)) {
+ IWL_DEBUG_HT(trans,
+ "HW queue empty: continue DELBA flow\n");
+ iwl_trans_pcie_txq_agg_disable(trans, txq_id);
+ tid_data->agg.state = IWL_AGG_OFF;
+ iwl_stop_tx_ba_trans_ready(priv(trans),
+ NUM_IWL_RXON_CTX,
+ sta_id, tid);
+ iwl_wake_queue(trans, &trans_pcie->txq[txq_id]);
+ }
+ break;
+ case IWL_EMPTYING_HW_QUEUE_ADDBA:
+ /* We are reclaiming the last packet of the queue */
+ if (tid_data->tfds_in_queue == 0) {
+ IWL_DEBUG_HT(trans,
+ "HW queue empty: continue ADDBA flow\n");
+ tid_data->agg.state = IWL_AGG_ON;
+ iwl_start_tx_ba_trans_ready(priv(trans),
+ NUM_IWL_RXON_CTX,
+ sta_id, tid);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void iwl_free_tfds_in_queue(struct iwl_trans *trans,
+ int sta_id, int tid, int freed)
+{
+ lockdep_assert_held(&trans->shrd->sta_lock);
+
+ if (trans->shrd->tid_data[sta_id][tid].tfds_in_queue >= freed)
+ trans->shrd->tid_data[sta_id][tid].tfds_in_queue -= freed;
+ else {
+ IWL_DEBUG_TX(trans, "free more than tfds_in_queue (%u:%d)\n",
+ trans->shrd->tid_data[sta_id][tid].tfds_in_queue,
+ freed);
+ trans->shrd->tid_data[sta_id][tid].tfds_in_queue = 0;
+ }
+}
+
+static void 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)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
+ enum iwl_agg_state agg_state;
+ /* n_bd is usually 256 => n_bd - 1 = 0xff */
+ int tfd_num = ssn & (txq->q.n_bd - 1);
+ int freed = 0;
+ bool cond;
+
+ txq->time_stamp = jiffies;
+
+ if (txq->sched_retry) {
+ agg_state =
+ trans->shrd->tid_data[txq->sta_id][txq->tid].agg.state;
+ cond = (agg_state != IWL_EMPTYING_HW_QUEUE_DELBA);
+ } else {
+ cond = (status != TX_STATUS_FAIL_PASSIVE_NO_RX);
+ }
+
+ if (txq->q.read_ptr != tfd_num) {
+ IWL_DEBUG_TX_REPLY(trans, "Retry scheduler reclaim "
+ "scd_ssn=%d idx=%d txq=%d swq=%d\n",
+ ssn , tfd_num, txq_id, txq->swq_id);
+ freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs);
+ if (iwl_queue_space(&txq->q) > txq->q.low_mark && cond)
+ iwl_wake_queue(trans, txq);
+ }
+
+ iwl_free_tfds_in_queue(trans, sta_id, tid, freed);
+ iwlagn_txq_check_empty(trans, sta_id, tid, txq_id);
+}
+
+static void iwl_trans_pcie_free(struct iwl_trans *trans)
+{
+ iwl_trans_pcie_tx_free(trans);
+ iwl_trans_pcie_rx_free(trans);
+ free_irq(bus(trans)->irq, trans);
+ iwl_free_isr_ict(trans);
+ trans->shrd->trans = NULL;
+ kfree(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(priv(trans));
+ } else {
+ iwl_disable_interrupts(trans);
+ iwl_clear_bit(bus(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);
+
+ if (!(iwl_read32(bus(trans), CSR_GP_CNTRL) &
+ CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
+ hw_rfkill = true;
+
+ if (hw_rfkill)
+ 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_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)
+{
+ 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_INFO(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]);
+ }
+}
+
+const struct iwl_trans_ops trans_ops_pcie;
+
+static struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd)
+{
+ struct iwl_trans *iwl_trans = kzalloc(sizeof(struct iwl_trans) +
+ sizeof(struct iwl_trans_pcie),
+ GFP_KERNEL);
+ if (iwl_trans) {
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(iwl_trans);
+ iwl_trans->ops = &trans_ops_pcie;
+ iwl_trans->shrd = shrd;
+ trans_pcie->trans = iwl_trans;
+ spin_lock_init(&iwl_trans->hcmd_lock);
+ }
+
+ return iwl_trans;
+}
+
+static void iwl_trans_pcie_stop_queue(struct iwl_trans *trans, int txq_id)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+ iwl_stop_queue(trans, &trans_pcie->txq[txq_id]);
+}
+
+#define IWL_FLUSH_WAIT_MS 2000
+
+static int iwl_trans_pcie_wait_tx_queue_empty(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_tx_queue *txq;
+ struct iwl_queue *q;
+ int cnt;
+ unsigned long now = jiffies;
+ 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)
+ continue;
+ txq = &trans_pcie->txq[cnt];
+ q = &txq->q;
+ while (q->read_ptr != q->write_ptr && !time_after(jiffies,
+ now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS)))
+ msleep(1);
+
+ if (q->read_ptr != q->write_ptr) {
+ IWL_ERR(trans, "fail to flush all tx fifo queues\n");
+ ret = -ETIMEDOUT;
+ break;
+ }
+ }
+ return ret;
+}
+
+/*
+ * On every watchdog tick we check (latest) time stamp. If it does not
+ * change during timeout period and queue is not empty we reset firmware.
+ */
+static int iwl_trans_pcie_check_stuck_queue(struct iwl_trans *trans, int cnt)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_tx_queue *txq = &trans_pcie->txq[cnt];
+ struct iwl_queue *q = &txq->q;
+ unsigned long timeout;
+
+ if (q->read_ptr == q->write_ptr) {
+ txq->time_stamp = jiffies;
+ return 0;
+ }
+
+ timeout = txq->time_stamp +
+ msecs_to_jiffies(hw_params(trans).wd_timeout);
+
+ if (time_after(jiffies, timeout)) {
+ IWL_ERR(trans, "Queue %d stuck for %u ms.\n", q->id,
+ hw_params(trans).wd_timeout);
+ IWL_ERR(trans, "Current read_ptr %d write_ptr %d\n",
+ q->read_ptr, q->write_ptr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static const char *get_fh_string(int cmd)
+{
+ switch (cmd) {
+ IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG);
+ IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG);
+ IWL_CMD(FH_RSCSR_CHNL0_WPTR);
+ IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG);
+ IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG);
+ IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG);
+ IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV);
+ IWL_CMD(FH_TSSR_TX_STATUS_REG);
+ IWL_CMD(FH_TSSR_TX_ERROR_REG);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display)
+{
+ int i;
+#ifdef CONFIG_IWLWIFI_DEBUG
+ int pos = 0;
+ size_t bufsz = 0;
+#endif
+ static const u32 fh_tbl[] = {
+ FH_RSCSR_CHNL0_STTS_WPTR_REG,
+ FH_RSCSR_CHNL0_RBDCB_BASE_REG,
+ FH_RSCSR_CHNL0_WPTR,
+ FH_MEM_RCSR_CHNL0_CONFIG_REG,
+ FH_MEM_RSSR_SHARED_CTRL_REG,
+ FH_MEM_RSSR_RX_STATUS_REG,
+ FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV,
+ FH_TSSR_TX_STATUS_REG,
+ FH_TSSR_TX_ERROR_REG
+ };
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (display) {
+ bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40;
+ *buf = kmalloc(bufsz, GFP_KERNEL);
+ if (!*buf)
+ return -ENOMEM;
+ pos += scnprintf(*buf + pos, bufsz - pos,
+ "FH register values:\n");
+ for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) {
+ pos += scnprintf(*buf + pos, bufsz - pos,
+ " %34s: 0X%08x\n",
+ get_fh_string(fh_tbl[i]),
+ iwl_read_direct32(bus(trans), fh_tbl[i]));
+ }
+ return pos;
+ }
+#endif
+ IWL_ERR(trans, "FH register values:\n");
+ for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) {
+ IWL_ERR(trans, " %34s: 0X%08x\n",
+ get_fh_string(fh_tbl[i]),
+ iwl_read_direct32(bus(trans), fh_tbl[i]));
+ }
+ return 0;
+}
+
+static const char *get_csr_string(int cmd)
+{
+ switch (cmd) {
+ IWL_CMD(CSR_HW_IF_CONFIG_REG);
+ IWL_CMD(CSR_INT_COALESCING);
+ IWL_CMD(CSR_INT);
+ IWL_CMD(CSR_INT_MASK);
+ IWL_CMD(CSR_FH_INT_STATUS);
+ IWL_CMD(CSR_GPIO_IN);
+ IWL_CMD(CSR_RESET);
+ IWL_CMD(CSR_GP_CNTRL);
+ IWL_CMD(CSR_HW_REV);
+ IWL_CMD(CSR_EEPROM_REG);
+ IWL_CMD(CSR_EEPROM_GP);
+ IWL_CMD(CSR_OTP_GP_REG);
+ IWL_CMD(CSR_GIO_REG);
+ IWL_CMD(CSR_GP_UCODE_REG);
+ IWL_CMD(CSR_GP_DRIVER_REG);
+ IWL_CMD(CSR_UCODE_DRV_GP1);
+ IWL_CMD(CSR_UCODE_DRV_GP2);
+ IWL_CMD(CSR_LED_REG);
+ IWL_CMD(CSR_DRAM_INT_TBL_REG);
+ IWL_CMD(CSR_GIO_CHICKEN_BITS);
+ IWL_CMD(CSR_ANA_PLL_CFG);
+ IWL_CMD(CSR_HW_REV_WA_REG);
+ IWL_CMD(CSR_DBG_HPET_MEM_REG);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+void iwl_dump_csr(struct iwl_trans *trans)
+{
+ int i;
+ static const u32 csr_tbl[] = {
+ CSR_HW_IF_CONFIG_REG,
+ CSR_INT_COALESCING,
+ CSR_INT,
+ CSR_INT_MASK,
+ CSR_FH_INT_STATUS,
+ CSR_GPIO_IN,
+ CSR_RESET,
+ CSR_GP_CNTRL,
+ CSR_HW_REV,
+ CSR_EEPROM_REG,
+ CSR_EEPROM_GP,
+ CSR_OTP_GP_REG,
+ CSR_GIO_REG,
+ CSR_GP_UCODE_REG,
+ CSR_GP_DRIVER_REG,
+ CSR_UCODE_DRV_GP1,
+ CSR_UCODE_DRV_GP2,
+ CSR_LED_REG,
+ CSR_DRAM_INT_TBL_REG,
+ CSR_GIO_CHICKEN_BITS,
+ CSR_ANA_PLL_CFG,
+ CSR_HW_REV_WA_REG,
+ CSR_DBG_HPET_MEM_REG
+ };
+ IWL_ERR(trans, "CSR values:\n");
+ IWL_ERR(trans, "(2nd byte of CSR_INT_COALESCING is "
+ "CSR_INT_PERIODIC_REG)\n");
+ for (i = 0; i < ARRAY_SIZE(csr_tbl); i++) {
+ IWL_ERR(trans, " %25s: 0X%08x\n",
+ get_csr_string(csr_tbl[i]),
+ iwl_read32(bus(trans), csr_tbl[i]));
+ }
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+/* create and remove of files */
+#define DEBUGFS_ADD_FILE(name, parent, mode) do { \
+ if (!debugfs_create_file(#name, mode, parent, trans, \
+ &iwl_dbgfs_##name##_ops)) \
+ return -ENOMEM; \
+} while (0)
+
+/* file operation */
+#define DEBUGFS_READ_FUNC(name) \
+static ssize_t iwl_dbgfs_##name##_read(struct file *file, \
+ char __user *user_buf, \
+ size_t count, loff_t *ppos);
+
+#define DEBUGFS_WRITE_FUNC(name) \
+static ssize_t iwl_dbgfs_##name##_write(struct file *file, \
+ const char __user *user_buf, \
+ size_t count, loff_t *ppos);
+
+
+static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+#define DEBUGFS_READ_FILE_OPS(name) \
+ DEBUGFS_READ_FUNC(name); \
+static const struct file_operations iwl_dbgfs_##name##_ops = { \
+ .read = iwl_dbgfs_##name##_read, \
+ .open = iwl_dbgfs_open_file_generic, \
+ .llseek = generic_file_llseek, \
+};
+
+#define DEBUGFS_WRITE_FILE_OPS(name) \
+ DEBUGFS_WRITE_FUNC(name); \
+static const struct file_operations iwl_dbgfs_##name##_ops = { \
+ .write = iwl_dbgfs_##name##_write, \
+ .open = iwl_dbgfs_open_file_generic, \
+ .llseek = generic_file_llseek, \
+};
+
+#define DEBUGFS_READ_WRITE_FILE_OPS(name) \
+ DEBUGFS_READ_FUNC(name); \
+ DEBUGFS_WRITE_FUNC(name); \
+static const struct file_operations iwl_dbgfs_##name##_ops = { \
+ .write = iwl_dbgfs_##name##_write, \
+ .read = iwl_dbgfs_##name##_read, \
+ .open = iwl_dbgfs_open_file_generic, \
+ .llseek = generic_file_llseek, \
+};
+
+static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_trans *trans = file->private_data;
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_tx_queue *txq;
+ struct iwl_queue *q;
+ char *buf;
+ int pos = 0;
+ int cnt;
+ int ret;
+ const size_t bufsz = sizeof(char) * 64 * hw_params(trans).max_txq_num;
+
+ if (!trans_pcie->txq) {
+ IWL_ERR(trans, "txq not ready\n");
+ return -EAGAIN;
+ }
+ buf = kzalloc(bufsz, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ for (cnt = 0; cnt < hw_params(trans).max_txq_num; cnt++) {
+ txq = &trans_pcie->txq[cnt];
+ q = &txq->q;
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "hwq %.2d: read=%u write=%u stop=%d"
+ " swq_id=%#.2x (ac %d/hwq %d)\n",
+ cnt, q->read_ptr, q->write_ptr,
+ !!test_bit(cnt, trans_pcie->queue_stopped),
+ txq->swq_id, txq->swq_id & 3,
+ (txq->swq_id >> 2) & 0x1f);
+ if (cnt >= 4)
+ continue;
+ /* for the ACs, display the stop count too */
+ pos += scnprintf(buf + pos, bufsz - pos,
+ " stop-count: %d\n",
+ atomic_read(&trans_pcie->queue_stop_count[cnt]));
+ }
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos) {
+ struct iwl_trans *trans = file->private_data;
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+ char buf[256];
+ int pos = 0;
+ const size_t bufsz = sizeof(buf);
+
+ pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n",
+ rxq->read);
+ pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n",
+ rxq->write);
+ pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
+ rxq->free_count);
+ if (rxq->rb_stts) {
+ pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n",
+ le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF);
+ } else {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "closed_rb_num: Not Allocated\n");
+ }
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_log_event_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_trans *trans = file->private_data;
+ char *buf;
+ int pos = 0;
+ ssize_t ret = -ENOMEM;
+
+ ret = pos = iwl_dump_nic_event_log(trans, true, &buf, true);
+ if (buf) {
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ }
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_log_event_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_trans *trans = file->private_data;
+ u32 event_log_flag;
+ char buf[8];
+ int buf_size;
+
+ 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", &event_log_flag) != 1)
+ return -EFAULT;
+ if (event_log_flag == 1)
+ iwl_dump_nic_event_log(trans, true, NULL, false);
+
+ return count;
+}
+
+static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos) {
+
+ struct iwl_trans *trans = file->private_data;
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
+
+ int pos = 0;
+ char *buf;
+ int bufsz = 24 * 64; /* 24 items * 64 char per item */
+ ssize_t ret;
+
+ buf = kzalloc(bufsz, GFP_KERNEL);
+ if (!buf) {
+ IWL_ERR(trans, "Can not allocate Buffer\n");
+ return -ENOMEM;
+ }
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Interrupt Statistics Report:\n");
+
+ pos += scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n",
+ isr_stats->hw);
+ pos += scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n",
+ isr_stats->sw);
+ if (isr_stats->sw || isr_stats->hw) {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\tLast Restarting Code: 0x%X\n",
+ isr_stats->err_code);
+ }
+#ifdef CONFIG_IWLWIFI_DEBUG
+ pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n",
+ isr_stats->sch);
+ pos += scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n",
+ isr_stats->alive);
+#endif
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "HW RF KILL switch toggled:\t %u\n", isr_stats->rfkill);
+
+ pos += scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n",
+ isr_stats->ctkill);
+
+ pos += scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n",
+ isr_stats->wakeup);
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Rx command responses:\t\t %u\n", isr_stats->rx);
+
+ pos += scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n",
+ isr_stats->tx);
+
+ pos += scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n",
+ isr_stats->unhandled);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_trans *trans = file->private_data;
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
+
+ char buf[8];
+ int buf_size;
+ u32 reset_flag;
+
+ 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, "%x", &reset_flag) != 1)
+ return -EFAULT;
+ if (reset_flag == 0)
+ memset(isr_stats, 0, sizeof(*isr_stats));
+
+ return count;
+}
+
+static ssize_t iwl_dbgfs_csr_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_trans *trans = file->private_data;
+ char buf[8];
+ int buf_size;
+ int csr;
+
+ 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", &csr) != 1)
+ return -EFAULT;
+
+ iwl_dump_csr(trans);
+
+ return count;
+}
+
+static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_trans *trans = file->private_data;
+ char *buf;
+ int pos = 0;
+ ssize_t ret = -EFAULT;
+
+ ret = pos = iwl_dump_fh(trans, &buf, true);
+ if (buf) {
+ ret = simple_read_from_buffer(user_buf,
+ count, ppos, buf, pos);
+ kfree(buf);
+ }
+
+ return ret;
+}
+
+DEBUGFS_READ_WRITE_FILE_OPS(log_event);
+DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
+DEBUGFS_READ_FILE_OPS(fh_reg);
+DEBUGFS_READ_FILE_OPS(rx_queue);
+DEBUGFS_READ_FILE_OPS(tx_queue);
+DEBUGFS_WRITE_FILE_OPS(csr);
+
+/*
+ * Create the debugfs files and directories
+ *
+ */
+static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
+ struct dentry *dir)
+{
+ DEBUGFS_ADD_FILE(rx_queue, dir, S_IRUSR);
+ DEBUGFS_ADD_FILE(tx_queue, dir, S_IRUSR);
+ DEBUGFS_ADD_FILE(log_event, dir, S_IWUSR | S_IRUSR);
+ DEBUGFS_ADD_FILE(interrupt, dir, S_IWUSR | S_IRUSR);
+ DEBUGFS_ADD_FILE(csr, dir, S_IWUSR);
+ DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR);
+ return 0;
+}
+#else
+static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
+ struct dentry *dir)
+{ return 0; }
+
+#endif /*CONFIG_IWLWIFI_DEBUGFS */
+
+const struct iwl_trans_ops trans_ops_pcie = {
+ .alloc = iwl_trans_pcie_alloc,
+ .request_irq = iwl_trans_pcie_request_irq,
+ .start_device = iwl_trans_pcie_start_device,
+ .prepare_card_hw = iwl_trans_pcie_prepare_card_hw,
+ .stop_device = iwl_trans_pcie_stop_device,
+
+ .tx_start = iwl_trans_pcie_tx_start,
+ .wake_any_queue = iwl_trans_pcie_wake_any_queue,
+
+ .send_cmd = iwl_trans_pcie_send_cmd,
+
+ .tx = iwl_trans_pcie_tx,
+ .reclaim = iwl_trans_pcie_reclaim,
+
+ .tx_agg_disable = iwl_trans_pcie_tx_agg_disable,
+ .tx_agg_alloc = iwl_trans_pcie_tx_agg_alloc,
+ .tx_agg_setup = iwl_trans_pcie_tx_agg_setup,
+
+ .kick_nic = iwl_trans_pcie_kick_nic,
+
+ .free = iwl_trans_pcie_free,
+ .stop_queue = iwl_trans_pcie_stop_queue,
+
+ .dbgfs_register = iwl_trans_pcie_dbgfs_register,
+
+ .wait_tx_queue_empty = iwl_trans_pcie_wait_tx_queue_empty,
+ .check_stuck_queue = iwl_trans_pcie_check_stuck_queue,
+
+#ifdef CONFIG_PM_SLEEP
+ .suspend = iwl_trans_pcie_suspend,
+ .resume = iwl_trans_pcie_resume,
+#endif
+};
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-rx-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-rx-pcie.c
deleted file mode 100644
index 474860290404..000000000000
--- a/drivers/net/wireless/iwlwifi/iwl-trans-rx-pcie.c
+++ /dev/null
@@ -1,979 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- * Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/gfp.h>
-
-#include "iwl-dev.h"
-#include "iwl-agn.h"
-#include "iwl-core.h"
-#include "iwl-io.h"
-#include "iwl-helpers.h"
-#include "iwl-trans-int-pcie.h"
-
-/******************************************************************************
- *
- * RX path functions
- *
- ******************************************************************************/
-
-/*
- * Rx theory of operation
- *
- * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs),
- * each of which point to Receive Buffers to be filled by the NIC. These get
- * used not only for Rx frames, but for any command response or notification
- * from the NIC. The driver and NIC manage the Rx buffers by means
- * of indexes into the circular buffer.
- *
- * Rx Queue Indexes
- * The host/firmware share two index registers for managing the Rx buffers.
- *
- * The READ index maps to the first position that the firmware may be writing
- * to -- the driver can read up to (but not including) this position and get
- * good data.
- * The READ index is managed by the firmware once the card is enabled.
- *
- * The WRITE index maps to the last position the driver has read from -- the
- * position preceding WRITE is the last slot the firmware can place a packet.
- *
- * The queue is empty (no good data) if WRITE = READ - 1, and is full if
- * WRITE = READ.
- *
- * During initialization, the host sets up the READ queue position to the first
- * INDEX position, and WRITE to the last (READ - 1 wrapped)
- *
- * When the firmware places a packet in a buffer, it will advance the READ index
- * and fire the RX interrupt. The driver can then query the READ index and
- * process as many packets as possible, moving the WRITE index forward as it
- * resets the Rx queue buffers with new memory.
- *
- * The management in the driver is as follows:
- * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When
- * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
- * to replenish the iwl->rxq->rx_free.
- * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the
- * iwl->rxq is replenished and the READ INDEX is updated (updating the
- * 'processed' and 'read' driver indexes as well)
- * + A received packet is processed and handed to the kernel network stack,
- * detached from the iwl->rxq. The driver 'processed' index is updated.
- * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
- * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
- * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there
- * were enough free buffers and RX_STALLED is set it is cleared.
- *
- *
- * Driver sequence:
- *
- * iwl_rx_queue_alloc() Allocates rx_free
- * iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls
- * iwl_rx_queue_restock
- * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx
- * queue, updates firmware pointers, and updates
- * the WRITE index. If insufficient rx_free buffers
- * are available, schedules iwl_rx_replenish
- *
- * -- enable interrupts --
- * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the
- * READ INDEX, detaching the SKB from the pool.
- * Moves the packet buffer from queue to rx_used.
- * Calls iwl_rx_queue_restock to refill any empty
- * slots.
- * ...
- *
- */
-
-/**
- * iwl_rx_queue_space - Return number of free slots available in queue.
- */
-static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
-{
- int s = q->read - q->write;
- if (s <= 0)
- s += RX_QUEUE_SIZE;
- /* keep some buffer to not confuse full and empty queue */
- s -= 2;
- if (s < 0)
- s = 0;
- return s;
-}
-
-/**
- * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
- */
-void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
- struct iwl_rx_queue *q)
-{
- unsigned long flags;
- u32 reg;
-
- spin_lock_irqsave(&q->lock, flags);
-
- if (q->need_update == 0)
- goto exit_unlock;
-
- if (priv->cfg->base_params->shadow_reg_enable) {
- /* shadow register enabled */
- /* Device expects a multiple of 8 */
- q->write_actual = (q->write & ~0x7);
- iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write_actual);
- } else {
- /* If power-saving is in use, make sure device is awake */
- if (test_bit(STATUS_POWER_PMI, &priv->status)) {
- reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
-
- if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
- IWL_DEBUG_INFO(priv,
- "Rx queue requesting wakeup,"
- " GP1 = 0x%x\n", reg);
- iwl_set_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
- goto exit_unlock;
- }
-
- q->write_actual = (q->write & ~0x7);
- iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR,
- q->write_actual);
-
- /* Else device is assumed to be awake */
- } else {
- /* Device expects a multiple of 8 */
- q->write_actual = (q->write & ~0x7);
- iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR,
- q->write_actual);
- }
- }
- q->need_update = 0;
-
- exit_unlock:
- spin_unlock_irqrestore(&q->lock, flags);
-}
-
-/**
- * iwlagn_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
- */
-static inline __le32 iwlagn_dma_addr2rbd_ptr(struct iwl_priv *priv,
- dma_addr_t dma_addr)
-{
- return cpu_to_le32((u32)(dma_addr >> 8));
-}
-
-/**
- * iwlagn_rx_queue_restock - refill RX queue from pre-allocated pool
- *
- * If there are slots in the RX queue that need to be restocked,
- * and we have free pre-allocated buffers, fill the ranks as much
- * as we can, pulling from rx_free.
- *
- * This moves the 'write' index forward to catch up with 'processed', and
- * also updates the memory address in the firmware to reference the new
- * target buffer.
- */
-static void iwlagn_rx_queue_restock(struct iwl_priv *priv)
-{
- struct iwl_rx_queue *rxq = &priv->rxq;
- struct list_head *element;
- struct iwl_rx_mem_buffer *rxb;
- unsigned long flags;
-
- spin_lock_irqsave(&rxq->lock, flags);
- while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
- /* The overwritten rxb must be a used one */
- rxb = rxq->queue[rxq->write];
- BUG_ON(rxb && rxb->page);
-
- /* Get next free Rx buffer, remove from free list */
- element = rxq->rx_free.next;
- rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
- list_del(element);
-
- /* Point to Rx buffer via next RBD in circular buffer */
- rxq->bd[rxq->write] = iwlagn_dma_addr2rbd_ptr(priv,
- rxb->page_dma);
- rxq->queue[rxq->write] = rxb;
- rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
- rxq->free_count--;
- }
- spin_unlock_irqrestore(&rxq->lock, flags);
- /* If the pre-allocated buffer pool is dropping low, schedule to
- * refill it */
- if (rxq->free_count <= RX_LOW_WATERMARK)
- queue_work(priv->workqueue, &priv->rx_replenish);
-
-
- /* If we've added more space for the firmware to place data, tell it.
- * Increment device's write pointer in multiples of 8. */
- if (rxq->write_actual != (rxq->write & ~0x7)) {
- spin_lock_irqsave(&rxq->lock, flags);
- rxq->need_update = 1;
- spin_unlock_irqrestore(&rxq->lock, flags);
- iwl_rx_queue_update_write_ptr(priv, rxq);
- }
-}
-
-/**
- * iwlagn_rx_replenish - Move all used packet from rx_used to rx_free
- *
- * When moving to rx_free an SKB is allocated for the slot.
- *
- * Also restock the Rx queue via iwl_rx_queue_restock.
- * This is called as a scheduled work item (except for during initialization)
- */
-static void iwlagn_rx_allocate(struct iwl_priv *priv, gfp_t priority)
-{
- struct iwl_rx_queue *rxq = &priv->rxq;
- struct list_head *element;
- struct iwl_rx_mem_buffer *rxb;
- struct page *page;
- unsigned long flags;
- gfp_t gfp_mask = priority;
-
- while (1) {
- spin_lock_irqsave(&rxq->lock, flags);
- if (list_empty(&rxq->rx_used)) {
- spin_unlock_irqrestore(&rxq->lock, flags);
- return;
- }
- spin_unlock_irqrestore(&rxq->lock, flags);
-
- if (rxq->free_count > RX_LOW_WATERMARK)
- gfp_mask |= __GFP_NOWARN;
-
- if (priv->hw_params.rx_page_order > 0)
- gfp_mask |= __GFP_COMP;
-
- /* Alloc a new receive buffer */
- page = alloc_pages(gfp_mask, priv->hw_params.rx_page_order);
- if (!page) {
- if (net_ratelimit())
- IWL_DEBUG_INFO(priv, "alloc_pages failed, "
- "order: %d\n",
- priv->hw_params.rx_page_order);
-
- if ((rxq->free_count <= RX_LOW_WATERMARK) &&
- net_ratelimit())
- IWL_CRIT(priv, "Failed to alloc_pages with %s."
- "Only %u free buffers remaining.\n",
- priority == GFP_ATOMIC ?
- "GFP_ATOMIC" : "GFP_KERNEL",
- rxq->free_count);
- /* We don't reschedule replenish work here -- we will
- * call the restock method and if it still needs
- * more buffers it will schedule replenish */
- return;
- }
-
- spin_lock_irqsave(&rxq->lock, flags);
-
- if (list_empty(&rxq->rx_used)) {
- spin_unlock_irqrestore(&rxq->lock, flags);
- __free_pages(page, priv->hw_params.rx_page_order);
- return;
- }
- element = rxq->rx_used.next;
- rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
- list_del(element);
-
- spin_unlock_irqrestore(&rxq->lock, flags);
-
- BUG_ON(rxb->page);
- rxb->page = page;
- /* Get physical address of the RB */
- rxb->page_dma = dma_map_page(priv->bus->dev, page, 0,
- PAGE_SIZE << priv->hw_params.rx_page_order,
- DMA_FROM_DEVICE);
- /* dma address must be no more than 36 bits */
- BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
- /* and also 256 byte aligned! */
- BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
-
- spin_lock_irqsave(&rxq->lock, flags);
-
- list_add_tail(&rxb->list, &rxq->rx_free);
- rxq->free_count++;
-
- spin_unlock_irqrestore(&rxq->lock, flags);
- }
-}
-
-void iwlagn_rx_replenish(struct iwl_priv *priv)
-{
- unsigned long flags;
-
- iwlagn_rx_allocate(priv, GFP_KERNEL);
-
- spin_lock_irqsave(&priv->lock, flags);
- iwlagn_rx_queue_restock(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void iwlagn_rx_replenish_now(struct iwl_priv *priv)
-{
- iwlagn_rx_allocate(priv, GFP_ATOMIC);
-
- iwlagn_rx_queue_restock(priv);
-}
-
-void iwl_bg_rx_replenish(struct work_struct *data)
-{
- struct iwl_priv *priv =
- container_of(data, struct iwl_priv, rx_replenish);
-
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
-
- mutex_lock(&priv->mutex);
- iwlagn_rx_replenish(priv);
- mutex_unlock(&priv->mutex);
-}
-
-/**
- * iwl_rx_handle - Main entry function for receiving responses from uCode
- *
- * Uses the priv->rx_handlers callback function array to invoke
- * the appropriate handlers, including command responses,
- * frame-received notifications, and other notifications.
- */
-static void iwl_rx_handle(struct iwl_priv *priv)
-{
- struct iwl_rx_mem_buffer *rxb;
- struct iwl_rx_packet *pkt;
- struct iwl_rx_queue *rxq = &priv->rxq;
- u32 r, i;
- int reclaim;
- unsigned long flags;
- u8 fill_rx = 0;
- u32 count = 8;
- int total_empty;
-
- /* uCode's read index (stored in shared DRAM) indicates the last Rx
- * buffer that the driver may process (last buffer filled by ucode). */
- r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF;
- i = rxq->read;
-
- /* Rx interrupt, but nothing sent from uCode */
- if (i == r)
- IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i);
-
- /* calculate total frames need to be restock after handling RX */
- total_empty = r - rxq->write_actual;
- if (total_empty < 0)
- total_empty += RX_QUEUE_SIZE;
-
- if (total_empty > (RX_QUEUE_SIZE / 2))
- fill_rx = 1;
-
- while (i != r) {
- int len;
-
- 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(priv->bus->dev, rxb->page_dma,
- PAGE_SIZE << priv->hw_params.rx_page_order,
- DMA_FROM_DEVICE);
- pkt = rxb_addr(rxb);
-
- IWL_DEBUG_RX(priv, "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, 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);
-
- iwl_rx_dispatch(priv, 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
- * trans_send_cmd()
- * as we reclaim the driver command queue */
- if (rxb->page)
- iwl_tx_cmd_complete(priv, rxb);
- else
- IWL_WARN(priv, "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(priv->bus->dev, rxb->page,
- 0, PAGE_SIZE << priv->hw_params.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);
-
- i = (i + 1) & RX_QUEUE_MASK;
- /* If there are a lot of unused frames,
- * restock the Rx queue so ucode wont assert. */
- if (fill_rx) {
- count++;
- if (count >= 8) {
- rxq->read = i;
- iwlagn_rx_replenish_now(priv);
- count = 0;
- }
- }
- }
-
- /* Backtrack one entry */
- rxq->read = i;
- if (fill_rx)
- iwlagn_rx_replenish_now(priv);
- else
- iwlagn_rx_queue_restock(priv);
-}
-
-/* tasklet for iwlagn interrupt */
-void iwl_irq_tasklet(struct iwl_priv *priv)
-{
- u32 inta = 0;
- u32 handled = 0;
- unsigned long flags;
- u32 i;
-#ifdef CONFIG_IWLWIFI_DEBUG
- u32 inta_mask;
-#endif
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* Ack/clear/reset pending uCode interrupts.
- * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
- */
- /* There is a hardware bug in the interrupt mask function that some
- * interrupts (i.e. CSR_INT_BIT_SCD) can still be generated even if
- * they are disabled in the CSR_INT_MASK register. Furthermore the
- * ICT interrupt handling mechanism has another bug that might cause
- * these unmasked interrupts fail to be detected. We workaround the
- * hardware bugs here by ACKing all the possible interrupts so that
- * interrupt coalescing can still be achieved.
- */
- iwl_write32(priv, CSR_INT, priv->inta | ~priv->inta_mask);
-
- inta = priv->inta;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
- if (iwl_get_debug_level(priv) & IWL_DL_ISR) {
- /* just for debug */
- inta_mask = iwl_read32(priv, CSR_INT_MASK);
- IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ",
- inta, inta_mask);
- }
-#endif
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- /* saved interrupt in inta variable now we can reset priv->inta */
- priv->inta = 0;
-
- /* Now service all interrupt bits discovered above. */
- if (inta & CSR_INT_BIT_HW_ERR) {
- IWL_ERR(priv, "Hardware error detected. Restarting.\n");
-
- /* Tell the device to stop sending interrupts */
- iwl_disable_interrupts(priv);
-
- priv->isr_stats.hw++;
- iwl_irq_handle_error(priv);
-
- handled |= CSR_INT_BIT_HW_ERR;
-
- return;
- }
-
-#ifdef CONFIG_IWLWIFI_DEBUG
- if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
- /* NIC fires this, but we don't use it, redundant with WAKEUP */
- if (inta & CSR_INT_BIT_SCD) {
- IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
- "the frame/frames.\n");
- priv->isr_stats.sch++;
- }
-
- /* Alive notification via Rx interrupt will do the real work */
- if (inta & CSR_INT_BIT_ALIVE) {
- IWL_DEBUG_ISR(priv, "Alive interrupt\n");
- priv->isr_stats.alive++;
- }
- }
-#endif
- /* Safely ignore these bits for debug checks below */
- inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE);
-
- /* HW RF KILL switch toggled */
- if (inta & CSR_INT_BIT_RF_KILL) {
- int hw_rf_kill = 0;
- if (!(iwl_read32(priv, CSR_GP_CNTRL) &
- CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
- hw_rf_kill = 1;
-
- IWL_WARN(priv, "RF_KILL bit toggled to %s.\n",
- hw_rf_kill ? "disable radio" : "enable radio");
-
- priv->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, &priv->status)) {
- if (hw_rf_kill)
- 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, hw_rf_kill);
- }
-
- handled |= CSR_INT_BIT_RF_KILL;
- }
-
- /* Chip got too hot and stopped itself */
- if (inta & CSR_INT_BIT_CT_KILL) {
- IWL_ERR(priv, "Microcode CT kill error detected.\n");
- priv->isr_stats.ctkill++;
- handled |= CSR_INT_BIT_CT_KILL;
- }
-
- /* Error detected by uCode */
- if (inta & CSR_INT_BIT_SW_ERR) {
- IWL_ERR(priv, "Microcode SW error detected. "
- " Restarting 0x%X.\n", inta);
- priv->isr_stats.sw++;
- iwl_irq_handle_error(priv);
- handled |= CSR_INT_BIT_SW_ERR;
- }
-
- /* uCode wakes up after power-down sleep */
- if (inta & CSR_INT_BIT_WAKEUP) {
- IWL_DEBUG_ISR(priv, "Wakeup interrupt\n");
- iwl_rx_queue_update_write_ptr(priv, &priv->rxq);
- for (i = 0; i < priv->hw_params.max_txq_num; i++)
- iwl_txq_update_write_ptr(priv, &priv->txq[i]);
-
- priv->isr_stats.wakeup++;
-
- handled |= CSR_INT_BIT_WAKEUP;
- }
-
- /* All uCode command responses, including Tx command responses,
- * Rx "responses" (frame-received notification), and other
- * notifications from uCode come through here*/
- if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX |
- CSR_INT_BIT_RX_PERIODIC)) {
- IWL_DEBUG_ISR(priv, "Rx interrupt\n");
- if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
- handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
- iwl_write32(priv, CSR_FH_INT_STATUS,
- CSR_FH_INT_RX_MASK);
- }
- if (inta & CSR_INT_BIT_RX_PERIODIC) {
- handled |= CSR_INT_BIT_RX_PERIODIC;
- iwl_write32(priv, CSR_INT, CSR_INT_BIT_RX_PERIODIC);
- }
- /* Sending RX interrupt require many steps to be done in the
- * the device:
- * 1- write interrupt to current index in ICT table.
- * 2- dma RX frame.
- * 3- update RX shared data to indicate last write index.
- * 4- send interrupt.
- * This could lead to RX race, driver could receive RX interrupt
- * but the shared data changes does not reflect this;
- * periodic interrupt will detect any dangling Rx activity.
- */
-
- /* Disable periodic interrupt; we use it as just a one-shot. */
- iwl_write8(priv, CSR_INT_PERIODIC_REG,
- CSR_INT_PERIODIC_DIS);
- iwl_rx_handle(priv);
-
- /*
- * Enable periodic interrupt in 8 msec only if we received
- * real RX interrupt (instead of just periodic int), to catch
- * any dangling Rx interrupt. If it was just the periodic
- * interrupt, there was no dangling Rx activity, and no need
- * to extend the periodic interrupt; one-shot is enough.
- */
- if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX))
- iwl_write8(priv, CSR_INT_PERIODIC_REG,
- CSR_INT_PERIODIC_ENA);
-
- priv->isr_stats.rx++;
- }
-
- /* This "Tx" DMA channel is used only for loading uCode */
- if (inta & CSR_INT_BIT_FH_TX) {
- iwl_write32(priv, CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK);
- IWL_DEBUG_ISR(priv, "uCode load interrupt\n");
- priv->isr_stats.tx++;
- handled |= CSR_INT_BIT_FH_TX;
- /* Wake up uCode load routine, now that load is complete */
- priv->ucode_write_complete = 1;
- wake_up_interruptible(&priv->wait_command_queue);
- }
-
- if (inta & ~handled) {
- IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled);
- priv->isr_stats.unhandled++;
- }
-
- if (inta & ~(priv->inta_mask)) {
- IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n",
- inta & ~priv->inta_mask);
- }
-
- /* Re-enable all interrupts */
- /* only Re-enable if disabled by irq */
- if (test_bit(STATUS_INT_ENABLED, &priv->status))
- iwl_enable_interrupts(priv);
- /* Re-enable RF_KILL if it occurred */
- else if (handled & CSR_INT_BIT_RF_KILL)
- iwl_enable_rfkill_int(priv);
-}
-
-/******************************************************************************
- *
- * ICT functions
- *
- ******************************************************************************/
-#define ICT_COUNT (PAGE_SIZE/sizeof(u32))
-
-/* Free dram table */
-void iwl_free_isr_ict(struct iwl_priv *priv)
-{
- if (priv->ict_tbl_vir) {
- dma_free_coherent(priv->bus->dev,
- (sizeof(u32) * ICT_COUNT) + PAGE_SIZE,
- priv->ict_tbl_vir,
- priv->ict_tbl_dma);
- priv->ict_tbl_vir = NULL;
- memset(&priv->ict_tbl_dma, 0,
- sizeof(priv->ict_tbl_dma));
- memset(&priv->aligned_ict_tbl_dma, 0,
- sizeof(priv->aligned_ict_tbl_dma));
- }
-}
-
-
-/* allocate dram shared table it is a PAGE_SIZE aligned
- * also reset all data related to ICT table interrupt.
- */
-int iwl_alloc_isr_ict(struct iwl_priv *priv)
-{
-
- /* allocate shrared data table */
- priv->ict_tbl_vir =
- dma_alloc_coherent(priv->bus->dev,
- (sizeof(u32) * ICT_COUNT) + PAGE_SIZE,
- &priv->ict_tbl_dma, GFP_KERNEL);
- if (!priv->ict_tbl_vir)
- return -ENOMEM;
-
- /* align table to PAGE_SIZE boundary */
- priv->aligned_ict_tbl_dma =
- ALIGN(priv->ict_tbl_dma, PAGE_SIZE);
-
- IWL_DEBUG_ISR(priv, "ict dma addr %Lx dma aligned %Lx diff %d\n",
- (unsigned long long)priv->ict_tbl_dma,
- (unsigned long long)priv->aligned_ict_tbl_dma,
- (int)(priv->aligned_ict_tbl_dma -
- priv->ict_tbl_dma));
-
- priv->ict_tbl = priv->ict_tbl_vir +
- (priv->aligned_ict_tbl_dma -
- priv->ict_tbl_dma);
-
- IWL_DEBUG_ISR(priv, "ict vir addr %p vir aligned %p diff %d\n",
- priv->ict_tbl, priv->ict_tbl_vir,
- (int)(priv->aligned_ict_tbl_dma -
- priv->ict_tbl_dma));
-
- /* reset table and index to all 0 */
- memset(priv->ict_tbl_vir, 0,
- (sizeof(u32) * ICT_COUNT) + PAGE_SIZE);
- priv->ict_index = 0;
-
- /* add periodic RX interrupt */
- priv->inta_mask |= CSR_INT_BIT_RX_PERIODIC;
- return 0;
-}
-
-/* Device is going up inform it about using ICT interrupt table,
- * also we need to tell the driver to start using ICT interrupt.
- */
-int iwl_reset_ict(struct iwl_priv *priv)
-{
- u32 val;
- unsigned long flags;
-
- if (!priv->ict_tbl_vir)
- return 0;
-
- spin_lock_irqsave(&priv->lock, flags);
- iwl_disable_interrupts(priv);
-
- memset(&priv->ict_tbl[0], 0, sizeof(u32) * ICT_COUNT);
-
- val = priv->aligned_ict_tbl_dma >> PAGE_SHIFT;
-
- val |= CSR_DRAM_INT_TBL_ENABLE;
- val |= CSR_DRAM_INIT_TBL_WRAP_CHECK;
-
- IWL_DEBUG_ISR(priv, "CSR_DRAM_INT_TBL_REG =0x%X "
- "aligned dma address %Lx\n",
- val,
- (unsigned long long)priv->aligned_ict_tbl_dma);
-
- iwl_write32(priv, CSR_DRAM_INT_TBL_REG, val);
- priv->use_ict = true;
- priv->ict_index = 0;
- iwl_write32(priv, CSR_INT, priv->inta_mask);
- iwl_enable_interrupts(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
-}
-
-/* Device is going down disable ict interrupt usage */
-void iwl_disable_ict(struct iwl_priv *priv)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- priv->use_ict = false;
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static irqreturn_t iwl_isr(int irq, void *data)
-{
- struct iwl_priv *priv = data;
- u32 inta, inta_mask;
- unsigned long flags;
-#ifdef CONFIG_IWLWIFI_DEBUG
- u32 inta_fh;
-#endif
- if (!priv)
- return IRQ_NONE;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* Disable (but don't clear!) interrupts here to avoid
- * back-to-back ISRs and sporadic interrupts from our NIC.
- * If we have something to service, the tasklet will re-enable ints.
- * If we *don't* have something, we'll re-enable before leaving here. */
- inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */
- iwl_write32(priv, CSR_INT_MASK, 0x00000000);
-
- /* Discover which interrupts are active/pending */
- inta = iwl_read32(priv, CSR_INT);
-
- /* Ignore interrupt if there's nothing in NIC to service.
- * This may be due to IRQ shared with another device,
- * or due to sporadic interrupts thrown from our NIC. */
- if (!inta) {
- IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n");
- goto none;
- }
-
- if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
- /* Hardware disappeared. It might have already raised
- * an interrupt */
- IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
- goto unplugged;
- }
-
-#ifdef CONFIG_IWLWIFI_DEBUG
- if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
- inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
- IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, "
- "fh 0x%08x\n", inta, inta_mask, inta_fh);
- }
-#endif
-
- priv->inta |= inta;
- /* iwl_irq_tasklet() will service interrupts and re-enable them */
- if (likely(inta))
- tasklet_schedule(&priv->irq_tasklet);
- else if (test_bit(STATUS_INT_ENABLED, &priv->status) &&
- !priv->inta)
- iwl_enable_interrupts(priv);
-
- unplugged:
- spin_unlock_irqrestore(&priv->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, &priv->status) && !priv->inta)
- iwl_enable_interrupts(priv);
-
- spin_unlock_irqrestore(&priv->lock, flags);
- return IRQ_NONE;
-}
-
-/* interrupt handler using ict table, with this interrupt driver will
- * stop using INTA register to get device's interrupt, reading this register
- * is expensive, device will write interrupts in ICT dram table, increment
- * index then will fire interrupt to driver, driver will OR all ICT table
- * entries from current index up to table entry with 0 value. the result is
- * the interrupt we need to service, driver will set the entries back to 0 and
- * set index.
- */
-irqreturn_t iwl_isr_ict(int irq, void *data)
-{
- struct iwl_priv *priv = data;
- u32 inta, inta_mask;
- u32 val = 0;
- unsigned long flags;
-
- if (!priv)
- return IRQ_NONE;
-
- /* dram interrupt table not set yet,
- * use legacy interrupt.
- */
- if (!priv->use_ict)
- return iwl_isr(irq, data);
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* Disable (but don't clear!) interrupts here to avoid
- * back-to-back ISRs and sporadic interrupts from our NIC.
- * If we have something to service, the tasklet will re-enable ints.
- * If we *don't* have something, we'll re-enable before leaving here.
- */
- inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */
- iwl_write32(priv, CSR_INT_MASK, 0x00000000);
-
-
- /* Ignore interrupt if there's nothing in NIC to service.
- * This may be due to IRQ shared with another device,
- * or due to sporadic interrupts thrown from our NIC. */
- if (!priv->ict_tbl[priv->ict_index]) {
- IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n");
- goto none;
- }
-
- /* read all entries that not 0 start with ict_index */
- while (priv->ict_tbl[priv->ict_index]) {
-
- val |= le32_to_cpu(priv->ict_tbl[priv->ict_index]);
- IWL_DEBUG_ISR(priv, "ICT index %d value 0x%08X\n",
- priv->ict_index,
- le32_to_cpu(
- priv->ict_tbl[priv->ict_index]));
- priv->ict_tbl[priv->ict_index] = 0;
- priv->ict_index = iwl_queue_inc_wrap(priv->ict_index,
- ICT_COUNT);
-
- }
-
- /* We should not get this value, just ignore it. */
- if (val == 0xffffffff)
- val = 0;
-
- /*
- * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit
- * (bit 15 before shifting it to 31) to clear when using interrupt
- * coalescing. fortunately, bits 18 and 19 stay set when this happens
- * so we use them to decide on the real state of the Rx bit.
- * In order words, bit 15 is set if bit 18 or bit 19 are set.
- */
- if (val & 0xC0000)
- val |= 0x8000;
-
- inta = (0xff & val) | ((0xff00 & val) << 16);
- IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n",
- inta, inta_mask, val);
-
- inta &= priv->inta_mask;
- priv->inta |= inta;
-
- /* iwl_irq_tasklet() will service interrupts and re-enable them */
- if (likely(inta))
- tasklet_schedule(&priv->irq_tasklet);
- else if (test_bit(STATUS_INT_ENABLED, &priv->status) &&
- !priv->inta) {
- /* Allow interrupt if was disabled by this handler and
- * no tasklet was schedules, We should not enable interrupt,
- * tasklet will enable it.
- */
- iwl_enable_interrupts(priv);
- }
-
- spin_unlock_irqrestore(&priv->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, &priv->status) && !priv->inta)
- iwl_enable_interrupts(priv);
-
- spin_unlock_irqrestore(&priv->lock, flags);
- return IRQ_NONE;
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.c b/drivers/net/wireless/iwlwifi/iwl-trans.c
index 41f0de914008..1b20c4fb791b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.c
@@ -60,1113 +60,18 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
-#include "iwl-dev.h"
-#include "iwl-trans.h"
-#include "iwl-core.h"
-#include "iwl-helpers.h"
-#include "iwl-trans-int-pcie.h"
-/*TODO remove uneeded includes when the transport layer tx_free will be here */
-#include "iwl-agn.h"
-#include "iwl-core.h"
-
-static int iwl_trans_rx_alloc(struct iwl_priv *priv)
-{
- struct iwl_rx_queue *rxq = &priv->rxq;
- struct device *dev = priv->bus->dev;
-
- memset(&priv->rxq, 0, sizeof(priv->rxq));
-
- spin_lock_init(&rxq->lock);
- INIT_LIST_HEAD(&rxq->rx_free);
- INIT_LIST_HEAD(&rxq->rx_used);
-
- if (WARN_ON(rxq->bd || rxq->rb_stts))
- return -EINVAL;
-
- /* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */
- rxq->bd = dma_alloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
- &rxq->bd_dma, GFP_KERNEL);
- if (!rxq->bd)
- goto err_bd;
- memset(rxq->bd, 0, sizeof(__le32) * RX_QUEUE_SIZE);
-
- /*Allocate the driver's pointer to receive buffer status */
- rxq->rb_stts = dma_alloc_coherent(dev, sizeof(*rxq->rb_stts),
- &rxq->rb_stts_dma, GFP_KERNEL);
- if (!rxq->rb_stts)
- goto err_rb_stts;
- memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
-
- return 0;
-
-err_rb_stts:
- dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
- rxq->bd, rxq->bd_dma);
- memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
- rxq->bd = NULL;
-err_bd:
- return -ENOMEM;
-}
-
-static void iwl_trans_rxq_free_rx_bufs(struct iwl_priv *priv)
-{
- struct iwl_rx_queue *rxq = &priv->rxq;
- int i;
-
- /* Fill the rx_used queue with _all_ of the Rx buffers */
- for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
- /* In the reset function, these buffers may have been allocated
- * to an SKB, so we need to unmap and free potential storage */
- if (rxq->pool[i].page != NULL) {
- dma_unmap_page(priv->bus->dev, rxq->pool[i].page_dma,
- PAGE_SIZE << priv->hw_params.rx_page_order,
- DMA_FROM_DEVICE);
- __iwl_free_pages(priv, rxq->pool[i].page);
- rxq->pool[i].page = NULL;
- }
- list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
- }
-}
-
-static void iwl_trans_rx_hw_init(struct iwl_priv *priv,
- struct iwl_rx_queue *rxq)
-{
- u32 rb_size;
- const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
- u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */
-
- rb_timeout = RX_RB_TIMEOUT;
-
- if (iwlagn_mod_params.amsdu_size_8K)
- rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
- else
- rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
-
- /* Stop Rx DMA */
- iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
-
- /* Reset driver's Rx queue write index */
- iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
-
- /* Tell device where to find RBD circular buffer in DRAM */
- iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
- (u32)(rxq->bd_dma >> 8));
-
- /* Tell device where in DRAM to update its Rx status */
- iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
- rxq->rb_stts_dma >> 4);
-
- /* Enable Rx DMA
- * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in
- * the credit mechanism in 5000 HW RX FIFO
- * Direct rx interrupts to hosts
- * Rx buffer size 4 or 8k
- * RB timeout 0x10
- * 256 RBDs
- */
- iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
- FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
- FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY |
- FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
- FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK |
- rb_size|
- (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
- (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
-
- /* Set interrupt coalescing timer to default (2048 usecs) */
- iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
-}
-
-static int iwl_rx_init(struct iwl_priv *priv)
-{
- struct iwl_rx_queue *rxq = &priv->rxq;
- int i, err;
- unsigned long flags;
-
- if (!rxq->bd) {
- err = iwl_trans_rx_alloc(priv);
- if (err)
- return err;
- }
-
- spin_lock_irqsave(&rxq->lock, flags);
- INIT_LIST_HEAD(&rxq->rx_free);
- INIT_LIST_HEAD(&rxq->rx_used);
-
- iwl_trans_rxq_free_rx_bufs(priv);
-
- for (i = 0; i < RX_QUEUE_SIZE; i++)
- rxq->queue[i] = NULL;
-
- /* Set us so that we have processed and used all buffers, but have
- * not restocked the Rx queue with fresh buffers */
- rxq->read = rxq->write = 0;
- rxq->write_actual = 0;
- rxq->free_count = 0;
- spin_unlock_irqrestore(&rxq->lock, flags);
-
- iwlagn_rx_replenish(priv);
-
- iwl_trans_rx_hw_init(priv, rxq);
-
- spin_lock_irqsave(&priv->lock, flags);
- rxq->need_update = 1;
- iwl_rx_queue_update_write_ptr(priv, rxq);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
-}
-
-static void iwl_trans_rx_free(struct iwl_priv *priv)
-{
- struct iwl_rx_queue *rxq = &priv->rxq;
- unsigned long flags;
-
- /*if rxq->bd is NULL, it means that nothing has been allocated,
- * exit now */
- if (!rxq->bd) {
- IWL_DEBUG_INFO(priv, "Free NULL rx context\n");
- return;
- }
-
- spin_lock_irqsave(&rxq->lock, flags);
- iwl_trans_rxq_free_rx_bufs(priv);
- spin_unlock_irqrestore(&rxq->lock, flags);
-
- dma_free_coherent(priv->bus->dev, sizeof(__le32) * RX_QUEUE_SIZE,
- rxq->bd, rxq->bd_dma);
- memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
- rxq->bd = NULL;
-
- if (rxq->rb_stts)
- dma_free_coherent(priv->bus->dev,
- sizeof(struct iwl_rb_status),
- rxq->rb_stts, rxq->rb_stts_dma);
- else
- IWL_DEBUG_INFO(priv, "Free rxq->rb_stts which is NULL\n");
- memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma));
- rxq->rb_stts = NULL;
-}
-
-static int iwl_trans_rx_stop(struct iwl_priv *priv)
-{
-
- /* stop Rx DMA */
- iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
- return iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
- FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
-}
-
-static inline int iwlagn_alloc_dma_ptr(struct iwl_priv *priv,
- struct iwl_dma_ptr *ptr, size_t size)
-{
- if (WARN_ON(ptr->addr))
- return -EINVAL;
-
- ptr->addr = dma_alloc_coherent(priv->bus->dev, size,
- &ptr->dma, GFP_KERNEL);
- if (!ptr->addr)
- return -ENOMEM;
- ptr->size = size;
- return 0;
-}
-
-static inline void iwlagn_free_dma_ptr(struct iwl_priv *priv,
- struct iwl_dma_ptr *ptr)
-{
- if (unlikely(!ptr->addr))
- return;
-
- dma_free_coherent(priv->bus->dev, ptr->size, ptr->addr, ptr->dma);
- memset(ptr, 0, sizeof(*ptr));
-}
-
-static int iwl_trans_txq_alloc(struct iwl_priv *priv, struct iwl_tx_queue *txq,
- int slots_num, u32 txq_id)
-{
- size_t tfd_sz = priv->hw_params.tfd_size * TFD_QUEUE_SIZE_MAX;
- int i;
-
- if (WARN_ON(txq->meta || txq->cmd || txq->txb || txq->tfds))
- return -EINVAL;
-
- txq->q.n_window = slots_num;
-
- txq->meta = kzalloc(sizeof(txq->meta[0]) * slots_num,
- GFP_KERNEL);
- txq->cmd = kzalloc(sizeof(txq->cmd[0]) * slots_num,
- GFP_KERNEL);
-
- if (!txq->meta || !txq->cmd)
- goto error;
-
- for (i = 0; i < slots_num; i++) {
- txq->cmd[i] = kmalloc(sizeof(struct iwl_device_cmd),
- GFP_KERNEL);
- if (!txq->cmd[i])
- goto error;
- }
-
- /* Alloc driver data array and TFD circular buffer */
- /* Driver private data, only for Tx (not command) queues,
- * not shared with device. */
- if (txq_id != priv->cmd_queue) {
- txq->txb = kzalloc(sizeof(txq->txb[0]) *
- TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
- if (!txq->txb) {
- IWL_ERR(priv, "kmalloc for auxiliary BD "
- "structures failed\n");
- goto error;
- }
- } else {
- txq->txb = NULL;
- }
-
- /* Circular buffer of transmit frame descriptors (TFDs),
- * shared with device */
- txq->tfds = dma_alloc_coherent(priv->bus->dev, tfd_sz, &txq->q.dma_addr,
- GFP_KERNEL);
- if (!txq->tfds) {
- IWL_ERR(priv, "dma_alloc_coherent(%zd) failed\n", tfd_sz);
- goto error;
- }
- txq->q.id = txq_id;
-
- return 0;
-error:
- kfree(txq->txb);
- txq->txb = NULL;
- /* since txq->cmd has been zeroed,
- * all non allocated cmd[i] will be NULL */
- if (txq->cmd)
- for (i = 0; i < slots_num; i++)
- kfree(txq->cmd[i]);
- kfree(txq->meta);
- kfree(txq->cmd);
- txq->meta = NULL;
- txq->cmd = NULL;
-
- return -ENOMEM;
-
-}
-
-static int iwl_trans_txq_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
- int slots_num, u32 txq_id)
-{
- int ret;
-
- txq->need_update = 0;
- memset(txq->meta, 0, sizeof(txq->meta[0]) * slots_num);
-
- /*
- * For the default queues 0-3, set up the swq_id
- * already -- all others need to get one later
- * (if they need one at all).
- */
- if (txq_id < 4)
- iwl_set_swq_id(txq, txq_id, txq_id);
-
- /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
- * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
- BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
-
- /* Initialize queue's high/low-water marks, and head/tail indexes */
- ret = iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num,
- txq_id);
- if (ret)
- return ret;
-
- /*
- * Tell nic where to find circular buffer of Tx Frame Descriptors for
- * given Tx queue, and enable the DMA channel used for that queue.
- * Circular buffer (TFD queue in DRAM) physical base address */
- iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
- txq->q.dma_addr >> 8);
-
- return 0;
-}
-
-/**
- * iwl_tx_queue_unmap - Unmap any remaining DMA mappings and free skb's
- */
-static void iwl_tx_queue_unmap(struct iwl_priv *priv, int txq_id)
-{
- struct iwl_tx_queue *txq = &priv->txq[txq_id];
- struct iwl_queue *q = &txq->q;
-
- if (!q->n_bd)
- return;
-
- while (q->write_ptr != q->read_ptr) {
- /* The read_ptr needs to bound by q->n_window */
- iwlagn_txq_free_tfd(priv, txq, get_cmd_index(q, q->read_ptr));
- q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
- }
-}
-
-/**
- * iwl_tx_queue_free - Deallocate DMA queue.
- * @txq: Transmit queue to deallocate.
- *
- * Empty queue by removing and destroying all BD's.
- * Free all buffers.
- * 0-fill, but do not free "txq" descriptor structure.
- */
-static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
-{
- struct iwl_tx_queue *txq = &priv->txq[txq_id];
- struct device *dev = priv->bus->dev;
- int i;
- if (WARN_ON(!txq))
- return;
-
- iwl_tx_queue_unmap(priv, txq_id);
-
- /* De-alloc array of command/tx buffers */
- for (i = 0; i < txq->q.n_window; i++)
- kfree(txq->cmd[i]);
-
- /* De-alloc circular buffer of TFDs */
- if (txq->q.n_bd) {
- dma_free_coherent(dev, priv->hw_params.tfd_size *
- txq->q.n_bd, txq->tfds, txq->q.dma_addr);
- memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr));
- }
-
- /* De-alloc array of per-TFD driver data */
- kfree(txq->txb);
- txq->txb = NULL;
-
- /* deallocate arrays */
- kfree(txq->cmd);
- kfree(txq->meta);
- txq->cmd = NULL;
- txq->meta = NULL;
-
- /* 0-fill queue descriptor structure */
- memset(txq, 0, sizeof(*txq));
-}
-
-/**
- * iwl_trans_tx_free - Free TXQ Context
- *
- * Destroy all TX DMA queues and structures
- */
-static void iwl_trans_tx_free(struct iwl_priv *priv)
-{
- int txq_id;
-
- /* Tx queues */
- if (priv->txq) {
- for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
- iwl_tx_queue_free(priv, txq_id);
- }
-
- kfree(priv->txq);
- priv->txq = NULL;
-
- iwlagn_free_dma_ptr(priv, &priv->kw);
-
- iwlagn_free_dma_ptr(priv, &priv->scd_bc_tbls);
-}
-
-/**
- * iwl_trans_tx_alloc - allocate TX context
- * Allocate all Tx DMA structures and initialize them
- *
- * @param priv
- * @return error code
- */
-static int iwl_trans_tx_alloc(struct iwl_priv *priv)
-{
- int ret;
- int txq_id, slots_num;
-
- /*It is not allowed to alloc twice, so warn when this happens.
- * We cannot rely on the previous allocation, so free and fail */
- if (WARN_ON(priv->txq)) {
- ret = -EINVAL;
- goto error;
- }
-
- ret = iwlagn_alloc_dma_ptr(priv, &priv->scd_bc_tbls,
- priv->hw_params.scd_bc_tbls_size);
- if (ret) {
- IWL_ERR(priv, "Scheduler BC Table allocation failed\n");
- goto error;
- }
-
- /* Alloc keep-warm buffer */
- ret = iwlagn_alloc_dma_ptr(priv, &priv->kw, IWL_KW_SIZE);
- if (ret) {
- IWL_ERR(priv, "Keep Warm allocation failed\n");
- goto error;
- }
-
- priv->txq = kzalloc(sizeof(struct iwl_tx_queue) *
- priv->cfg->base_params->num_of_queues, GFP_KERNEL);
- if (!priv->txq) {
- IWL_ERR(priv, "Not enough memory for txq\n");
- ret = ENOMEM;
- goto error;
- }
-
- /* Alloc and init all Tx queues, including the command queue (#4/#9) */
- for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
- slots_num = (txq_id == priv->cmd_queue) ?
- TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
- ret = iwl_trans_txq_alloc(priv, &priv->txq[txq_id], slots_num,
- txq_id);
- if (ret) {
- IWL_ERR(priv, "Tx %d queue alloc failed\n", txq_id);
- goto error;
- }
- }
-
- return 0;
-
-error:
- trans_tx_free(&priv->trans);
-
- return ret;
-}
-static int iwl_tx_init(struct iwl_priv *priv)
-{
- int ret;
- int txq_id, slots_num;
- unsigned long flags;
- bool alloc = false;
-
- if (!priv->txq) {
- ret = iwl_trans_tx_alloc(priv);
- if (ret)
- goto error;
- alloc = true;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* Turn off all Tx DMA fifos */
- iwl_write_prph(priv, SCD_TXFACT, 0);
-
- /* Tell NIC where to find the "keep warm" buffer */
- iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- /* Alloc and init all Tx queues, including the command queue (#4/#9) */
- for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
- slots_num = (txq_id == priv->cmd_queue) ?
- TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
- ret = iwl_trans_txq_init(priv, &priv->txq[txq_id], slots_num,
- txq_id);
- if (ret) {
- IWL_ERR(priv, "Tx %d queue init failed\n", txq_id);
- goto error;
- }
- }
-
- return 0;
-error:
- /*Upon error, free only if we allocated something */
- if (alloc)
- trans_tx_free(&priv->trans);
- return ret;
-}
-
-static void iwl_set_pwr_vmain(struct iwl_priv *priv)
-{
-/*
- * (for documentation purposes)
- * to set power to V_AUX, do:
-
- if (pci_pme_capable(priv->pci_dev, PCI_D3cold))
- iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
- APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
- ~APMG_PS_CTRL_MSK_PWR_SRC);
- */
-
- iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
- APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
- ~APMG_PS_CTRL_MSK_PWR_SRC);
-}
-
-static int iwl_nic_init(struct iwl_priv *priv)
-{
- unsigned long flags;
-
- /* nic_init */
- spin_lock_irqsave(&priv->lock, flags);
- iwl_apm_init(priv);
-
- /* Set interrupt coalescing calibration timer to default (512 usecs) */
- iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_CALIB_TIMEOUT_DEF);
-
- spin_unlock_irqrestore(&priv->lock, flags);
- iwl_set_pwr_vmain(priv);
-
- priv->cfg->lib->nic_config(priv);
-
- /* Allocate the RX queue, or reset if it is already allocated */
- iwl_rx_init(priv);
-
- /* Allocate or reset and init all Tx and Command queues */
- if (iwl_tx_init(priv))
- return -ENOMEM;
-
- if (priv->cfg->base_params->shadow_reg_enable) {
- /* enable shadow regs in HW */
- iwl_set_bit(priv, CSR_MAC_SHADOW_REG_CTRL,
- 0x800FFFFF);
- }
-
- set_bit(STATUS_INIT, &priv->status);
-
- return 0;
-}
-
-#define HW_READY_TIMEOUT (50)
-
-/* Note: returns poll_bit return value, which is >= 0 if success */
-static int iwl_set_hw_ready(struct iwl_priv *priv)
-{
- int ret;
-
- iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
-
- /* See if we got it */
- ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
- CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
- HW_READY_TIMEOUT);
-
- IWL_DEBUG_INFO(priv, "hardware%s ready\n", ret < 0 ? " not" : "");
- return ret;
-}
-
-/* Note: returns standard 0/-ERROR code */
-static int iwl_trans_prepare_card_hw(struct iwl_priv *priv)
-{
- int ret;
-
- IWL_DEBUG_INFO(priv, "iwl_trans_prepare_card_hw enter\n");
-
- ret = iwl_set_hw_ready(priv);
- if (ret >= 0)
- return 0;
-
- /* If HW is not ready, prepare the conditions to check again */
- iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_PREPARE);
-
- ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
- ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
- CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
-
- if (ret < 0)
- return ret;
-
- /* HW should be ready by now, check again. */
- ret = iwl_set_hw_ready(priv);
- if (ret >= 0)
- return 0;
- return ret;
-}
-
-static int iwl_trans_start_device(struct iwl_priv *priv)
-{
- int ret;
-
- priv->ucode_owner = IWL_OWNERSHIP_DRIVER;
-
- if ((priv->cfg->sku & EEPROM_SKU_CAP_AMT_ENABLE) &&
- iwl_trans_prepare_card_hw(priv)) {
- IWL_WARN(priv, "Exit HW not ready\n");
- return -EIO;
- }
-
- /* If platform's RF_KILL switch is NOT set to KILL */
- if (iwl_read32(priv, CSR_GP_CNTRL) &
- CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
- clear_bit(STATUS_RF_KILL_HW, &priv->status);
- else
- set_bit(STATUS_RF_KILL_HW, &priv->status);
-
- if (iwl_is_rfkill(priv)) {
- wiphy_rfkill_set_hw_state(priv->hw->wiphy, true);
- iwl_enable_interrupts(priv);
- return -ERFKILL;
- }
-
- iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
-
- ret = iwl_nic_init(priv);
- if (ret) {
- IWL_ERR(priv, "Unable to init nic\n");
- return ret;
- }
-
- /* make sure rfkill handshake bits are cleared */
- iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
- iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
- CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-
- /* clear (again), then enable host interrupts */
- iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
- iwl_enable_interrupts(priv);
-
- /* really make sure rfkill handshake bits are cleared */
- iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
- iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-
- return 0;
-}
-
-/*
- * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
- * must be called under priv->lock and mac access
- */
-static void iwl_trans_txq_set_sched(struct iwl_priv *priv, u32 mask)
-{
- iwl_write_prph(priv, SCD_TXFACT, mask);
-}
-
-#define IWL_AC_UNSET -1
-
-struct queue_to_fifo_ac {
- s8 fifo, ac;
-};
-
-static const struct queue_to_fifo_ac iwlagn_default_queue_to_tx_fifo[] = {
- { IWL_TX_FIFO_VO, IEEE80211_AC_VO, },
- { IWL_TX_FIFO_VI, IEEE80211_AC_VI, },
- { IWL_TX_FIFO_BE, IEEE80211_AC_BE, },
- { IWL_TX_FIFO_BK, IEEE80211_AC_BK, },
- { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
- { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
- { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
- { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
- { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
- { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
-};
-
-static const struct queue_to_fifo_ac iwlagn_ipan_queue_to_tx_fifo[] = {
- { IWL_TX_FIFO_VO, IEEE80211_AC_VO, },
- { IWL_TX_FIFO_VI, IEEE80211_AC_VI, },
- { IWL_TX_FIFO_BE, IEEE80211_AC_BE, },
- { IWL_TX_FIFO_BK, IEEE80211_AC_BK, },
- { IWL_TX_FIFO_BK_IPAN, IEEE80211_AC_BK, },
- { IWL_TX_FIFO_BE_IPAN, IEEE80211_AC_BE, },
- { IWL_TX_FIFO_VI_IPAN, IEEE80211_AC_VI, },
- { IWL_TX_FIFO_VO_IPAN, IEEE80211_AC_VO, },
- { IWL_TX_FIFO_BE_IPAN, 2, },
- { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
-};
-static void iwl_trans_tx_start(struct iwl_priv *priv)
-{
- const struct queue_to_fifo_ac *queue_to_fifo;
- struct iwl_rxon_context *ctx;
- u32 a;
- unsigned long flags;
- int i, chan;
- u32 reg_val;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- priv->scd_base_addr = iwl_read_prph(priv, SCD_SRAM_BASE_ADDR);
- a = priv->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND;
- /* reset conext data memory */
- for (; a < priv->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND;
- a += 4)
- iwl_write_targ_mem(priv, a, 0);
- /* reset tx status memory */
- for (; a < priv->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND;
- a += 4)
- iwl_write_targ_mem(priv, a, 0);
- for (; a < priv->scd_base_addr +
- SCD_TRANS_TBL_OFFSET_QUEUE(priv->hw_params.max_txq_num); a += 4)
- iwl_write_targ_mem(priv, a, 0);
-
- iwl_write_prph(priv, SCD_DRAM_BASE_ADDR,
- priv->scd_bc_tbls.dma >> 10);
-
- /* Enable DMA channel */
- for (chan = 0; chan < FH_TCSR_CHNL_NUM ; chan++)
- iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(chan),
- FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
- FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
-
- /* Update FH chicken bits */
- reg_val = iwl_read_direct32(priv, FH_TX_CHICKEN_BITS_REG);
- iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG,
- reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
-
- iwl_write_prph(priv, SCD_QUEUECHAIN_SEL,
- SCD_QUEUECHAIN_SEL_ALL(priv));
- iwl_write_prph(priv, SCD_AGGR_SEL, 0);
-
- /* initiate the queues */
- for (i = 0; i < priv->hw_params.max_txq_num; i++) {
- iwl_write_prph(priv, SCD_QUEUE_RDPTR(i), 0);
- iwl_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8));
- iwl_write_targ_mem(priv, priv->scd_base_addr +
- SCD_CONTEXT_QUEUE_OFFSET(i), 0);
- iwl_write_targ_mem(priv, priv->scd_base_addr +
- SCD_CONTEXT_QUEUE_OFFSET(i) +
- sizeof(u32),
- ((SCD_WIN_SIZE <<
- SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
- SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
- ((SCD_FRAME_LIMIT <<
- SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
- SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
- }
-
- iwl_write_prph(priv, SCD_INTERRUPT_MASK,
- IWL_MASK(0, priv->hw_params.max_txq_num));
-
- /* Activate all Tx DMA/FIFO channels */
- iwl_trans_txq_set_sched(priv, IWL_MASK(0, 7));
-
- /* map queues to FIFOs */
- if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))
- queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo;
- else
- queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
-
- iwl_trans_set_wr_ptrs(priv, priv->cmd_queue, 0);
-
- /* make sure all queue are not stopped */
- memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped));
- for (i = 0; i < 4; i++)
- atomic_set(&priv->queue_stop_count[i], 0);
- for_each_context(priv, ctx)
- ctx->last_tx_rejected = false;
-
- /* reset to 0 to enable all the queue first */
- priv->txq_ctx_active_msk = 0;
-
- BUILD_BUG_ON(ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo) != 10);
- BUILD_BUG_ON(ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo) != 10);
-
- for (i = 0; i < 10; i++) {
- int fifo = queue_to_fifo[i].fifo;
- int ac = queue_to_fifo[i].ac;
-
- iwl_txq_ctx_activate(priv, i);
-
- if (fifo == IWL_TX_FIFO_UNUSED)
- continue;
-
- if (ac != IWL_AC_UNSET)
- iwl_set_swq_id(&priv->txq[i], ac, i);
- iwl_trans_tx_queue_set_status(priv, &priv->txq[i], fifo, 0);
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- /* Enable L1-Active */
- iwl_clear_bits_prph(priv, APMG_PCIDEV_STT_REG,
- APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
-}
-
-/**
- * iwlagn_txq_ctx_stop - Stop all Tx DMA channels
- */
-static int iwl_trans_tx_stop(struct iwl_priv *priv)
-{
- int ch, txq_id;
- unsigned long flags;
-
- /* Turn off all Tx DMA fifos */
- spin_lock_irqsave(&priv->lock, flags);
-
- iwl_trans_txq_set_sched(priv, 0);
-
- /* Stop each Tx DMA channel, and wait for it to be idle */
- for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) {
- iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
- if (iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG,
- FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
- 1000))
- IWL_ERR(priv, "Failing on timeout while stopping"
- " DMA channel %d [0x%08x]", ch,
- iwl_read_direct32(priv, FH_TSSR_TX_STATUS_REG));
- }
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if (!priv->txq) {
- IWL_WARN(priv, "Stopping tx queues that aren't allocated...");
- return 0;
- }
-
- /* Unmap DMA from host system and free skb's */
- for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
- iwl_tx_queue_unmap(priv, txq_id);
-
- return 0;
-}
-
-static void iwl_trans_stop_device(struct iwl_priv *priv)
-{
- unsigned long flags;
-
- /* stop and reset the on-board processor */
- iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
-
- /* tell the device to stop sending interrupts */
- spin_lock_irqsave(&priv->lock, flags);
- iwl_disable_interrupts(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
- trans_sync_irq(&priv->trans);
-
- /* device going down, Stop using ICT table */
- iwl_disable_ict(priv);
-
- /*
- * If a HW restart happens during firmware loading,
- * then the firmware loading might call this function
- * and later it might be called again due to the
- * restart. So don't process again if the device is
- * already dead.
- */
- if (test_bit(STATUS_DEVICE_ENABLED, &priv->status)) {
- iwl_trans_tx_stop(priv);
- iwl_trans_rx_stop(priv);
-
- /* Power-down device's busmaster DMA clocks */
- iwl_write_prph(priv, APMG_CLK_DIS_REG,
- APMG_CLK_VAL_DMA_CLK_RQT);
- udelay(5);
- }
-
- /* Make sure (redundant) we've released our request to stay awake */
- iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-
- /* Stop the device, and put it in low power state */
- iwl_apm_stop(priv);
-}
-
-static struct iwl_tx_cmd *iwl_trans_get_tx_cmd(struct iwl_priv *priv,
- int txq_id)
-{
- struct iwl_tx_queue *txq = &priv->txq[txq_id];
- struct iwl_queue *q = &txq->q;
- struct iwl_device_cmd *dev_cmd;
-
- if (unlikely(iwl_queue_space(q) < q->high_mark))
- return NULL;
-
- /*
- * Set up the Tx-command (not MAC!) header.
- * Store the chosen Tx queue and TFD index within the sequence field;
- * after Tx, uCode's Tx response will return this value so driver can
- * locate the frame within the tx queue and do post-tx processing.
- */
- dev_cmd = txq->cmd[q->write_ptr];
- memset(dev_cmd, 0, sizeof(*dev_cmd));
- dev_cmd->hdr.cmd = REPLY_TX;
- dev_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
- INDEX_TO_SEQ(q->write_ptr)));
- return &dev_cmd->cmd.tx;
-}
-
-static int iwl_trans_tx(struct iwl_priv *priv, struct sk_buff *skb,
- struct iwl_tx_cmd *tx_cmd, int txq_id, __le16 fc, bool ampdu,
- struct iwl_rxon_context *ctx)
-{
- struct iwl_tx_queue *txq = &priv->txq[txq_id];
- struct iwl_queue *q = &txq->q;
- struct iwl_device_cmd *dev_cmd = txq->cmd[q->write_ptr];
- struct iwl_cmd_meta *out_meta;
-
- dma_addr_t phys_addr = 0;
- dma_addr_t txcmd_phys;
- dma_addr_t scratch_phys;
- u16 len, firstlen, secondlen;
- u8 wait_write_ptr = 0;
- u8 hdr_len = ieee80211_hdrlen(fc);
-
- /* Set up driver data for this TFD */
- memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
- txq->txb[q->write_ptr].skb = skb;
- txq->txb[q->write_ptr].ctx = ctx;
-
- /* Set up first empty entry in queue's array of Tx/cmd buffers */
- out_meta = &txq->meta[q->write_ptr];
-
- /*
- * Use the first empty entry in this queue's command buffer array
- * to contain the Tx command and MAC header concatenated together
- * (payload data will be in another buffer).
- * Size of this varies, due to varying MAC header length.
- * If end is not dword aligned, we'll have 2 extra bytes at the end
- * of the MAC header (device reads on dword boundaries).
- * We'll tell device about this padding later.
- */
- len = sizeof(struct iwl_tx_cmd) +
- sizeof(struct iwl_cmd_header) + hdr_len;
- firstlen = (len + 3) & ~3;
-
- /* Tell NIC about any 2-byte padding after MAC header */
- if (firstlen != len)
- tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
-
- /* Physical address of this Tx command's header (not MAC header!),
- * within command buffer array. */
- txcmd_phys = dma_map_single(priv->bus->dev,
- &dev_cmd->hdr, firstlen,
- DMA_BIDIRECTIONAL);
- if (unlikely(dma_mapping_error(priv->bus->dev, txcmd_phys)))
- return -1;
- dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
- dma_unmap_len_set(out_meta, len, firstlen);
-
- if (!ieee80211_has_morefrags(fc)) {
- txq->need_update = 1;
- } else {
- wait_write_ptr = 1;
- txq->need_update = 0;
- }
-
- /* Set up TFD's 2nd entry to point directly to remainder of skb,
- * if any (802.11 null frames have no payload). */
- secondlen = skb->len - hdr_len;
- if (secondlen > 0) {
- phys_addr = dma_map_single(priv->bus->dev, skb->data + hdr_len,
- secondlen, DMA_TO_DEVICE);
- if (unlikely(dma_mapping_error(priv->bus->dev, phys_addr))) {
- dma_unmap_single(priv->bus->dev,
- dma_unmap_addr(out_meta, mapping),
- dma_unmap_len(out_meta, len),
- DMA_BIDIRECTIONAL);
- return -1;
- }
- }
-
- /* Attach buffers to TFD */
- iwlagn_txq_attach_buf_to_tfd(priv, txq, txcmd_phys, firstlen, 1);
- if (secondlen > 0)
- iwlagn_txq_attach_buf_to_tfd(priv, txq, phys_addr,
- secondlen, 0);
-
- scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
- offsetof(struct iwl_tx_cmd, scratch);
-
- /* take back ownership of DMA buffer to enable update */
- dma_sync_single_for_cpu(priv->bus->dev, txcmd_phys, firstlen,
- DMA_BIDIRECTIONAL);
- tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
- tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
-
- IWL_DEBUG_TX(priv, "sequence nr = 0X%x\n",
- le16_to_cpu(dev_cmd->hdr.sequence));
- IWL_DEBUG_TX(priv, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
- iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
- iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
-
- /* Set up entry for this TFD in Tx byte-count array */
- if (ampdu)
- iwl_trans_txq_update_byte_cnt_tbl(priv, txq,
- le16_to_cpu(tx_cmd->len));
-
- dma_sync_single_for_device(priv->bus->dev, txcmd_phys, firstlen,
- DMA_BIDIRECTIONAL);
-
- trace_iwlwifi_dev_tx(priv,
- &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr],
- sizeof(struct iwl_tfd),
- &dev_cmd->hdr, firstlen,
- skb->data + hdr_len, secondlen);
-
- /* Tell device the write index *just past* this latest filled TFD */
- q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
- iwl_txq_update_write_ptr(priv, txq);
-
- /*
- * At this point the frame is "transmitted" successfully
- * and we will get a TX status notification eventually,
- * regardless of the value of ret. "ret" only indicates
- * whether or not we should update the write pointer.
- */
- if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) {
- if (wait_write_ptr) {
- txq->need_update = 1;
- iwl_txq_update_write_ptr(priv, txq);
- } else {
- iwl_stop_queue(priv, txq);
- }
- }
- return 0;
-}
-
-static void iwl_trans_kick_nic(struct iwl_priv *priv)
-{
- /* Remove all resets to allow NIC to operate */
- iwl_write32(priv, CSR_RESET, 0);
-}
-
-static void iwl_trans_sync_irq(struct iwl_priv *priv)
-{
- /* wait to make sure we flush pending tasklet*/
- synchronize_irq(priv->bus->irq);
- tasklet_kill(&priv->irq_tasklet);
-}
-
-static void iwl_trans_free(struct iwl_priv *priv)
-{
- free_irq(priv->bus->irq, priv);
- iwl_free_isr_ict(priv);
-}
-
-static const struct iwl_trans_ops trans_ops = {
- .start_device = iwl_trans_start_device,
- .prepare_card_hw = iwl_trans_prepare_card_hw,
- .stop_device = iwl_trans_stop_device,
-
- .tx_start = iwl_trans_tx_start,
-
- .rx_free = iwl_trans_rx_free,
- .tx_free = iwl_trans_tx_free,
-
- .send_cmd = iwl_send_cmd,
- .send_cmd_pdu = iwl_send_cmd_pdu,
-
- .get_tx_cmd = iwl_trans_get_tx_cmd,
- .tx = iwl_trans_tx,
-
- .txq_agg_disable = iwl_trans_txq_agg_disable,
- .txq_agg_setup = iwl_trans_txq_agg_setup,
-
- .kick_nic = iwl_trans_kick_nic,
-
- .sync_irq = iwl_trans_sync_irq,
- .free = iwl_trans_free,
-};
+#include "iwl-trans.h"
-int iwl_trans_register(struct iwl_trans *trans, struct iwl_priv *priv)
+int iwl_trans_send_cmd_pdu(struct iwl_trans *trans, u8 id,
+ u32 flags, u16 len, const void *data)
{
- int err;
-
- priv->trans.ops = &trans_ops;
- priv->trans.priv = priv;
-
- tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
- iwl_irq_tasklet, (unsigned long)priv);
-
- iwl_alloc_isr_ict(priv);
-
- err = request_irq(priv->bus->irq, iwl_isr_ict, IRQF_SHARED,
- DRV_NAME, priv);
- if (err) {
- IWL_ERR(priv, "Error allocating IRQ %d\n", priv->bus->irq);
- iwl_free_isr_ict(priv);
- return err;
- }
-
- INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish);
+ struct iwl_host_cmd cmd = {
+ .id = id,
+ .len = { len, },
+ .data = { data, },
+ .flags = flags,
+ };
- return 0;
+ return iwl_trans_send_cmd(trans, &cmd);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 7993aa7ae668..c5923125c3f9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -63,163 +63,289 @@
#ifndef __iwl_trans_h__
#define __iwl_trans_h__
+#include <linux/debugfs.h>
+#include <linux/skbuff.h>
+
+#include "iwl-shared.h"
+#include "iwl-commands.h"
+
/*This file includes the declaration that are exported from the transport
* layer */
struct iwl_priv;
-struct iwl_rxon_context;
-struct iwl_host_cmd;
+struct iwl_shared;
+
+#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)
+
+enum {
+ CMD_SYNC = 0,
+ CMD_ASYNC = BIT(0),
+ CMD_WANT_SKB = BIT(1),
+ CMD_ON_DEMAND = BIT(2),
+};
+
+#define DEF_CMD_PAYLOAD_SIZE 320
+
+/**
+ * struct iwl_device_cmd
+ *
+ * For allocation of the command and tx queues, this establishes the overall
+ * size of the largest command we send to uCode, except for commands that
+ * aren't fully copied and use other TFD space.
+ */
+struct iwl_device_cmd {
+ struct iwl_cmd_header hdr; /* uCode API */
+ u8 payload[DEF_CMD_PAYLOAD_SIZE];
+} __packed;
+
+#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd))
+
+#define IWL_MAX_CMD_TFDS 2
+
+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
+ * @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
+ * @len: array of the lenths of the chunks in data
+ * @dataflags:
+ * @id: id of the host command
+ */
+struct iwl_host_cmd {
+ const void *data[IWL_MAX_CMD_TFDS];
+ unsigned long reply_page;
+ int handler_status;
+
+ u32 flags;
+ u16 len[IWL_MAX_CMD_TFDS];
+ u8 dataflags[IWL_MAX_CMD_TFDS];
+ u8 id;
+};
/**
* struct iwl_trans_ops - transport specific operations
+ * @alloc: allocates the meta data (not the queues themselves)
+ * @request_irq: requests IRQ - will be called before the FW load in probe flow
* @start_device: allocates and inits all the resources for the transport
* layer.
* @prepare_card_hw: claim the ownership on the HW. Will be called during
* probe.
* @tx_start: starts and configures all the Tx fifo - usually done once the fw
* is alive.
+ * @wake_any_queue: wake all the queues of a specfic context IWL_RXON_CTX_*
* @stop_device:stops the whole device (embedded CPU put to reset)
- * @rx_free: frees the rx memory
- * @tx_free: frees the tx memory
* @send_cmd:send a host command
- * @send_cmd_pdu:send a host command: flags can be CMD_*
- * @get_tx_cmd: returns a pointer to a new Tx cmd for the upper layer use
* @tx: send an skb
- * @txq_agg_setup: setup a tx queue for AMPDU - will be called once the HW is
+ * @reclaim: free packet until ssn. Returns a list of freed packets.
+ * @tx_agg_alloc: allocate resources for a TX BA session
+ * @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.
- * @txq_agg_disable: de-configure a Tx queue to send AMPDUs
+ * @tx_agg_disable: de-configure a Tx queue to send AMPDUs
* @kick_nic: remove the RESET from the embedded CPU and let it run
- * @sync_irq: the upper layer will typically disable interrupt and call this
- * handler. After this handler returns, it is guaranteed that all
- * the ISR / tasklet etc... have finished running and the transport
- * layer shall not pass any Rx.
* @free: release all the ressource for the transport layer itself such as
* irq, tasklet etc...
+ * @stop_queue: stop a specific queue
+ * @check_stuck_queue: check if a specific queue is stuck
+ * @wait_tx_queue_empty: wait until all tx queues are empty
+ * @dbgfs_register: add the dbgfs files under this directory. Files will be
+ * automatically deleted.
+ * @suspend: stop the device unless WoWLAN is configured
+ * @resume: resume activity of the device
*/
struct iwl_trans_ops {
- int (*start_device)(struct iwl_priv *priv);
- int (*prepare_card_hw)(struct iwl_priv *priv);
- void (*stop_device)(struct iwl_priv *priv);
- void (*tx_start)(struct iwl_priv *priv);
- void (*tx_free)(struct iwl_priv *priv);
- void (*rx_free)(struct iwl_priv *priv);
+ struct iwl_trans *(*alloc)(struct iwl_shared *shrd);
+ int (*request_irq)(struct iwl_trans *iwl_trans);
+ int (*start_device)(struct iwl_trans *trans);
+ int (*prepare_card_hw)(struct iwl_trans *trans);
+ void (*stop_device)(struct iwl_trans *trans);
+ void (*tx_start)(struct iwl_trans *trans);
+
+ void (*wake_any_queue)(struct iwl_trans *trans,
+ enum iwl_rxon_context_id ctx);
- int (*send_cmd)(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
+ int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
- int (*send_cmd_pdu)(struct iwl_priv *priv, u8 id, u32 flags, u16 len,
- const void *data);
- struct iwl_tx_cmd * (*get_tx_cmd)(struct iwl_priv *priv, int txq_id);
- int (*tx)(struct iwl_priv *priv, struct sk_buff *skb,
- struct iwl_tx_cmd *tx_cmd, int txq_id, __le16 fc, bool ampdu,
- struct iwl_rxon_context *ctx);
+ int (*tx)(struct iwl_trans *trans, struct sk_buff *skb,
+ struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx,
+ u8 sta_id);
+ void (*reclaim)(struct iwl_trans *trans, int sta_id, int tid,
+ int txq_id, int ssn, u32 status,
+ struct sk_buff_head *skbs);
- int (*txq_agg_disable)(struct iwl_priv *priv, u16 txq_id,
- u16 ssn_idx, u8 tx_fifo);
- void (*txq_agg_setup)(struct iwl_priv *priv, int sta_id, int tid,
- int frame_limit);
+ int (*tx_agg_disable)(struct iwl_trans *trans,
+ enum iwl_rxon_context_id ctx, int sta_id,
+ int tid);
+ int (*tx_agg_alloc)(struct iwl_trans *trans,
+ enum iwl_rxon_context_id ctx, int sta_id, int tid,
+ u16 *ssn);
+ void (*tx_agg_setup)(struct iwl_trans *trans,
+ enum iwl_rxon_context_id ctx, int sta_id, int tid,
+ int frame_limit);
- void (*kick_nic)(struct iwl_priv *priv);
+ void (*kick_nic)(struct iwl_trans *trans);
- void (*sync_irq)(struct iwl_priv *priv);
- void (*free)(struct iwl_priv *priv);
+ void (*free)(struct iwl_trans *trans);
+
+ void (*stop_queue)(struct iwl_trans *trans, int q);
+
+ 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);
+#ifdef CONFIG_PM_SLEEP
+ int (*suspend)(struct iwl_trans *trans);
+ int (*resume)(struct iwl_trans *trans);
+#endif
};
+/**
+ * struct iwl_trans - transport common data
+ * @ops - pointer to iwl_trans_ops
+ * @shrd - pointer to iwl_shared which holds shared data from the upper layer
+ * @hcmd_lock: protects HCMD
+ */
struct iwl_trans {
const struct iwl_trans_ops *ops;
- struct iwl_priv *priv;
+ struct iwl_shared *shrd;
+ spinlock_t hcmd_lock;
+
+ /* pointer to trans specific struct */
+ /*Ensure that this pointer will always be aligned to sizeof pointer */
+ char trans_specific[0] __attribute__((__aligned__(sizeof(void *))));
};
-static inline int trans_start_device(struct iwl_trans *trans)
+static inline int iwl_trans_request_irq(struct iwl_trans *trans)
{
- return trans->ops->start_device(trans->priv);
+ return trans->ops->request_irq(trans);
}
-static inline int trans_prepare_card_hw(struct iwl_trans *trans)
+static inline int iwl_trans_start_device(struct iwl_trans *trans)
{
- return trans->ops->prepare_card_hw(trans->priv);
+ return trans->ops->start_device(trans);
}
-static inline void trans_stop_device(struct iwl_trans *trans)
+static inline int iwl_trans_prepare_card_hw(struct iwl_trans *trans)
{
- trans->ops->stop_device(trans->priv);
+ return trans->ops->prepare_card_hw(trans);
}
-static inline void trans_tx_start(struct iwl_trans *trans)
+static inline void iwl_trans_stop_device(struct iwl_trans *trans)
{
- trans->ops->tx_start(trans->priv);
+ trans->ops->stop_device(trans);
}
-static inline void trans_rx_free(struct iwl_trans *trans)
+static inline void iwl_trans_tx_start(struct iwl_trans *trans)
{
- trans->ops->rx_free(trans->priv);
+ trans->ops->tx_start(trans);
}
-static inline void trans_tx_free(struct iwl_trans *trans)
+static inline void iwl_trans_wake_any_queue(struct iwl_trans *trans,
+ enum iwl_rxon_context_id ctx)
{
- trans->ops->tx_free(trans->priv);
+ trans->ops->wake_any_queue(trans, ctx);
}
-static inline int trans_send_cmd(struct iwl_trans *trans,
+
+static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
struct iwl_host_cmd *cmd)
{
- return trans->ops->send_cmd(trans->priv, cmd);
+ 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)
+{
+ return trans->ops->tx(trans, skb, dev_cmd, ctx, sta_id);
}
-static inline int trans_send_cmd_pdu(struct iwl_trans *trans, u8 id, u32 flags,
- u16 len, const void *data)
+static inline void iwl_trans_reclaim(struct iwl_trans *trans, int sta_id,
+ int tid, int txq_id, int ssn, u32 status,
+ struct sk_buff_head *skbs)
{
- return trans->ops->send_cmd_pdu(trans->priv, id, flags, len, data);
+ trans->ops->reclaim(trans, sta_id, tid, txq_id, ssn, status, skbs);
}
-static inline struct iwl_tx_cmd *trans_get_tx_cmd(struct iwl_trans *trans,
- int txq_id)
+static inline int iwl_trans_tx_agg_disable(struct iwl_trans *trans,
+ enum iwl_rxon_context_id ctx,
+ int sta_id, int tid)
{
- return trans->ops->get_tx_cmd(trans->priv, txq_id);
+ return trans->ops->tx_agg_disable(trans, ctx, sta_id, tid);
}
-static inline int trans_tx(struct iwl_trans *trans, struct sk_buff *skb,
- struct iwl_tx_cmd *tx_cmd, int txq_id, __le16 fc, bool ampdu,
- struct iwl_rxon_context *ctx)
+static inline int iwl_trans_tx_agg_alloc(struct iwl_trans *trans,
+ enum iwl_rxon_context_id ctx,
+ int sta_id, int tid, u16 *ssn)
{
- return trans->ops->tx(trans->priv, skb, tx_cmd, txq_id, fc, ampdu, ctx);
+ return trans->ops->tx_agg_alloc(trans, ctx, sta_id, tid, ssn);
}
-static inline int trans_txq_agg_disable(struct iwl_trans *trans, u16 txq_id,
- u16 ssn_idx, u8 tx_fifo)
+
+static inline void iwl_trans_tx_agg_setup(struct iwl_trans *trans,
+ enum iwl_rxon_context_id ctx,
+ int sta_id, int tid,
+ int frame_limit)
{
- return trans->ops->txq_agg_disable(trans->priv, txq_id,
- ssn_idx, tx_fifo);
+ trans->ops->tx_agg_setup(trans, ctx, sta_id, tid, frame_limit);
}
-static inline void trans_txq_agg_setup(struct iwl_trans *trans, int sta_id,
- int tid, int frame_limit)
+static inline void iwl_trans_kick_nic(struct iwl_trans *trans)
{
- trans->ops->txq_agg_setup(trans->priv, sta_id, tid, frame_limit);
+ trans->ops->kick_nic(trans);
}
-static inline void trans_kick_nic(struct iwl_trans *trans)
+static inline void iwl_trans_free(struct iwl_trans *trans)
{
- trans->ops->kick_nic(trans->priv);
+ trans->ops->free(trans);
}
-static inline void trans_sync_irq(struct iwl_trans *trans)
+static inline void iwl_trans_stop_queue(struct iwl_trans *trans, int q)
{
- trans->ops->sync_irq(trans->priv);
+ trans->ops->stop_queue(trans, q);
}
-static inline void trans_free(struct iwl_trans *trans)
+static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans)
+{
+ return trans->ops->wait_tx_queue_empty(trans);
+}
+
+static inline int iwl_trans_check_stuck_queue(struct iwl_trans *trans, int q)
+{
+ return trans->ops->check_stuck_queue(trans, q);
+}
+static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans,
+ struct dentry *dir)
{
- trans->ops->free(trans->priv);
+ return trans->ops->dbgfs_register(trans, dir);
}
-int iwl_trans_register(struct iwl_trans *trans, struct iwl_priv *priv);
+#ifdef CONFIG_PM_SLEEP
+static inline int iwl_trans_suspend(struct iwl_trans *trans)
+{
+ return trans->ops->suspend(trans);
+}
-/*TODO: this functions should NOT be exported from trans module - export it
- * until the reclaim flow will be brought to the transport module too */
+static inline int iwl_trans_resume(struct iwl_trans *trans)
+{
+ return trans->ops->resume(trans);
+}
+#endif
-struct iwl_tx_queue;
-void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
- struct iwl_tx_queue *txq);
+/*****************************************************
+* Transport layers implementations
+******************************************************/
+extern const struct iwl_trans_ops trans_ops_pcie;
#endif /* __iwl_trans_h__ */
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index ed57e4402800..c42be81e979e 100644
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -187,13 +187,17 @@ static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
struct key_params*))
{
struct iwm_priv *iwm = ndev_to_iwm(ndev);
- struct iwm_key *key = &iwm->keys[key_index];
+ struct iwm_key *key;
struct key_params params;
IWM_DBG_WEXT(iwm, DBG, "Getting key %d\n", key_index);
+ if (key_index >= IWM_NUM_KEYS)
+ return -ENOENT;
+
memset(&params, 0, sizeof(params));
+ key = &iwm->keys[key_index];
params.cipher = key->cipher;
params.key_len = key->key_len;
params.seq_len = key->seq_len;
diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
index 1453eec82a99..91f2ca90c70f 100644
--- a/drivers/net/wireless/libertas/README
+++ b/drivers/net/wireless/libertas/README
@@ -238,28 +238,3 @@ hostsleep
echo "1" > hostsleep : enable host sleep.
echo "0" > hostsleep : disable host sleep
-========================
-IWCONFIG COMMANDS
-========================
-power period
-
- This command is used to configure the station in deep sleep mode /
- auto deep sleep mode.
-
- The timer is implemented to monitor the activities (command, event,
- etc.). When an activity is detected station will exit from deep
- sleep mode automatically and restart the timer. At timer expiry
- (no activity for defined time period) the deep sleep mode is entered
- automatically.
-
- Note: this command is for SDIO interface only.
-
- Usage:
- To enable deep sleep mode do:
- iwconfig wlan0 power period 0
- To enable auto deep sleep mode with idle time period 5 seconds do:
- iwconfig wlan0 power period 5
- To disable deep sleep/auto deep sleep mode do:
- iwconfig wlan0 power period -1
-
-==============================================================================
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index b456a53b64b1..ff6378276ff0 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -19,6 +19,7 @@
#include "decl.h"
#include "cfg.h"
#include "cmd.h"
+#include "mesh.h"
#define CHAN2G(_channel, _freq, _flags) { \
@@ -442,13 +443,16 @@ static int lbs_cfg_set_channel(struct wiphy *wiphy,
struct lbs_private *priv = wiphy_priv(wiphy);
int ret = -ENOTSUPP;
- lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d",
- channel->center_freq, channel_type);
+ lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d, type %d",
+ netdev_name(netdev), channel->center_freq, channel_type);
if (channel_type != NL80211_CHAN_NO_HT)
goto out;
- ret = lbs_set_channel(priv, channel->hw_value);
+ if (netdev == priv->mesh_dev)
+ ret = lbs_mesh_set_channel(priv, channel->hw_value);
+ else
+ ret = lbs_set_channel(priv, channel->hw_value);
out:
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
@@ -691,7 +695,7 @@ static void lbs_scan_worker(struct work_struct *work)
tlv = scan_cmd->tlvbuffer;
/* add SSID TLV */
- if (priv->scan_req->n_ssids)
+ if (priv->scan_req->n_ssids && priv->scan_req->ssids[0].ssid_len > 0)
tlv += lbs_add_ssid_tlv(tlv,
priv->scan_req->ssids[0].ssid,
priv->scan_req->ssids[0].ssid_len);
@@ -708,7 +712,7 @@ static void lbs_scan_worker(struct work_struct *work)
if (priv->scan_channel < priv->scan_req->n_channels) {
cancel_delayed_work(&priv->scan_work);
- if (!priv->stopping)
+ if (netif_running(priv->dev))
queue_delayed_work(priv->work_thread, &priv->scan_work,
msecs_to_jiffies(300));
}
@@ -732,7 +736,6 @@ static void lbs_scan_worker(struct work_struct *work)
cfg80211_scan_done(priv->scan_req, false);
priv->scan_req = NULL;
- priv->last_scan = jiffies;
}
/* Restart network */
@@ -1292,27 +1295,32 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
int ret = 0;
u8 preamble = RADIO_PREAMBLE_SHORT;
+ if (dev == priv->mesh_dev)
+ return -EOPNOTSUPP;
+
lbs_deb_enter(LBS_DEB_CFG80211);
if (!sme->bssid) {
- /* Run a scan if one isn't in-progress already and if the last
- * scan was done more than 2 seconds ago.
- */
- if (priv->scan_req == NULL &&
- time_after(jiffies, priv->last_scan + (2 * HZ))) {
- struct cfg80211_scan_request *creq;
+ struct cfg80211_scan_request *creq;
- creq = _new_connect_scan_req(wiphy, sme);
- if (!creq) {
- ret = -EINVAL;
- goto done;
- }
+ /*
+ * Scan for the requested network after waiting for existing
+ * scans to finish.
+ */
+ lbs_deb_assoc("assoc: waiting for existing scans\n");
+ wait_event_interruptible_timeout(priv->scan_q,
+ (priv->scan_req == NULL),
+ (15 * HZ));
- lbs_deb_assoc("assoc: scanning for compatible AP\n");
- _internal_start_scan(priv, true, creq);
+ creq = _new_connect_scan_req(wiphy, sme);
+ if (!creq) {
+ ret = -EINVAL;
+ goto done;
}
- /* Wait for any in-progress scan to complete */
+ lbs_deb_assoc("assoc: scanning for compatible AP\n");
+ _internal_start_scan(priv, true, creq);
+
lbs_deb_assoc("assoc: waiting for scan to complete\n");
wait_event_interruptible_timeout(priv->scan_q,
(priv->scan_req == NULL),
@@ -1402,28 +1410,23 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
return ret;
}
-static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev,
- u16 reason_code)
+int lbs_disconnect(struct lbs_private *priv, u16 reason)
{
- struct lbs_private *priv = wiphy_priv(wiphy);
struct cmd_ds_802_11_deauthenticate cmd;
-
- lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code);
-
- /* store for lbs_cfg_ret_disconnect() */
- priv->disassoc_reason = reason_code;
+ int ret;
memset(&cmd, 0, sizeof(cmd));
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
/* Mildly ugly to use a locally store my own BSSID ... */
memcpy(cmd.macaddr, &priv->assoc_bss, ETH_ALEN);
- cmd.reasoncode = cpu_to_le16(reason_code);
+ cmd.reasoncode = cpu_to_le16(reason);
- if (lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd))
- return -EFAULT;
+ ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd);
+ if (ret)
+ return ret;
cfg80211_disconnected(priv->dev,
- priv->disassoc_reason,
+ reason,
NULL, 0,
GFP_KERNEL);
priv->connect_status = LBS_DISCONNECTED;
@@ -1431,6 +1434,21 @@ static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev,
return 0;
}
+static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ u16 reason_code)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+
+ if (dev == priv->mesh_dev)
+ return -EOPNOTSUPP;
+
+ lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code);
+
+ /* store for lbs_cfg_ret_disconnect() */
+ priv->disassoc_reason = reason_code;
+
+ return lbs_disconnect(priv, reason_code);
+}
static int lbs_cfg_set_default_key(struct wiphy *wiphy,
struct net_device *netdev,
@@ -1439,6 +1457,9 @@ static int lbs_cfg_set_default_key(struct wiphy *wiphy,
{
struct lbs_private *priv = wiphy_priv(wiphy);
+ if (netdev == priv->mesh_dev)
+ return -EOPNOTSUPP;
+
lbs_deb_enter(LBS_DEB_CFG80211);
if (key_index != priv->wep_tx_key) {
@@ -1460,6 +1481,9 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
u16 key_type;
int ret = 0;
+ if (netdev == priv->mesh_dev)
+ return -EOPNOTSUPP;
+
lbs_deb_enter(LBS_DEB_CFG80211);
lbs_deb_assoc("add_key: cipher 0x%x, mac_addr %pM\n",
@@ -1603,6 +1627,9 @@ static int lbs_get_survey(struct wiphy *wiphy, struct net_device *dev,
s8 signal, noise;
int ret;
+ if (dev == priv->mesh_dev)
+ return -EOPNOTSUPP;
+
if (idx != 0)
ret = -ENOENT;
@@ -1636,28 +1663,23 @@ static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev,
struct lbs_private *priv = wiphy_priv(wiphy);
int ret = 0;
- lbs_deb_enter(LBS_DEB_CFG80211);
+ if (dev == priv->mesh_dev)
+ return -EOPNOTSUPP;
switch (type) {
case NL80211_IFTYPE_MONITOR:
- ret = lbs_set_monitor_mode(priv, 1);
- break;
case NL80211_IFTYPE_STATION:
- if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
- ret = lbs_set_monitor_mode(priv, 0);
- if (!ret)
- ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 1);
- break;
case NL80211_IFTYPE_ADHOC:
- if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
- ret = lbs_set_monitor_mode(priv, 0);
- if (!ret)
- ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 2);
break;
default:
- ret = -ENOTSUPP;
+ return -EOPNOTSUPP;
}
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ if (priv->iface_running)
+ ret = lbs_set_iface_type(priv, type);
+
if (!ret)
priv->wdev->iftype = type;
@@ -1959,6 +1981,9 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_bss *bss;
DECLARE_SSID_BUF(ssid_buf);
+ if (dev == priv->mesh_dev)
+ return -EOPNOTSUPP;
+
lbs_deb_enter(LBS_DEB_CFG80211);
if (!params->channel) {
@@ -1995,6 +2020,9 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
struct cmd_ds_802_11_ad_hoc_stop cmd;
int ret = 0;
+ if (dev == priv->mesh_dev)
+ return -EOPNOTSUPP;
+
lbs_deb_enter(LBS_DEB_CFG80211);
memset(&cmd, 0, sizeof(cmd));
@@ -2117,6 +2145,8 @@ int lbs_cfg_register(struct lbs_private *priv)
BIT(NL80211_IFTYPE_ADHOC);
if (lbs_rtap_supported(priv))
wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
+ if (lbs_mesh_activated(priv))
+ wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MESH_POINT);
wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz;
diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h
index 4f46bb744bee..a02ee151710e 100644
--- a/drivers/net/wireless/libertas/cfg.h
+++ b/drivers/net/wireless/libertas/cfg.h
@@ -17,5 +17,6 @@ void lbs_send_disconnect_notification(struct lbs_private *priv);
void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
void lbs_scan_deinit(struct lbs_private *priv);
+int lbs_disconnect(struct lbs_private *priv, u16 reason);
#endif
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index dbd24a4607ec..e08ab1de3d9d 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -1088,7 +1088,7 @@ void __lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
if (!cmd->callback || cmd->callback == lbs_cmd_async_callback)
__lbs_cleanup_and_insert_cmd(priv, cmd);
priv->cur_cmd = NULL;
- wake_up_interruptible(&priv->waitq);
+ wake_up(&priv->waitq);
}
void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
@@ -1627,7 +1627,7 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
/* Wake up main thread to execute next command */
- wake_up_interruptible(&priv->waitq);
+ wake_up(&priv->waitq);
cmdnode = ERR_PTR(-ENOBUFS);
goto done;
}
@@ -1647,7 +1647,7 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
cmdnode->cmdwaitqwoken = 0;
lbs_queue_cmd(priv, cmdnode);
- wake_up_interruptible(&priv->waitq);
+ wake_up(&priv->waitq);
done:
lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode);
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index da0b05bb89fe..bc951ab4b681 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -9,6 +9,7 @@
#include <linux/netdevice.h>
#include <linux/firmware.h>
+#include <linux/nl80211.h>
/* Should be terminated by a NULL entry */
struct lbs_fw_table {
@@ -43,10 +44,15 @@ int lbs_start_card(struct lbs_private *priv);
void lbs_stop_card(struct lbs_private *priv);
void lbs_host_to_card_done(struct lbs_private *priv);
+int lbs_start_iface(struct lbs_private *priv);
+int lbs_stop_iface(struct lbs_private *priv);
+int lbs_set_iface_type(struct lbs_private *priv, enum nl80211_iftype type);
+
int lbs_rtap_supported(struct lbs_private *priv);
int lbs_set_mac_address(struct net_device *dev, void *addr);
void lbs_set_multicast_list(struct net_device *dev);
+void lbs_update_mcast(struct lbs_private *priv);
int lbs_suspend(struct lbs_private *priv);
int lbs_resume(struct lbs_private *priv);
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index adb3490e3cf5..f3fd447131c2 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -6,7 +6,6 @@
#ifndef _LBS_DEV_H_
#define _LBS_DEV_H_
-#include "mesh.h"
#include "defs.h"
#include "host.h"
@@ -22,6 +21,17 @@ struct sleep_params {
uint16_t sp_reserved;
};
+/* Mesh statistics */
+struct lbs_mesh_stats {
+ u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */
+ u32 fwd_unicast_cnt; /* Fwd: Unicast counter */
+ u32 fwd_drop_ttl; /* Fwd: TTL zero */
+ u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */
+ u32 fwd_drop_noroute; /* Fwd: No route to Destination */
+ u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */
+ u32 drop_blind; /* Rx: Dropped by blinding table */
+ u32 tx_failed_cnt; /* Tx: Failed transmissions */
+};
/* Private structure for the MV device */
struct lbs_private {
@@ -36,7 +46,6 @@ struct lbs_private {
/* CFG80211 */
struct wireless_dev *wdev;
bool wiphy_registered;
- bool stopping;
struct cfg80211_scan_request *scan_req;
u8 assoc_bss[ETH_ALEN];
u8 disassoc_reason;
@@ -86,11 +95,14 @@ struct lbs_private {
/* Hardware access */
void *card;
+ bool iface_running;
u8 fw_ready;
u8 surpriseremoved;
u8 setup_fw_on_resume;
int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
void (*reset_card) (struct lbs_private *priv);
+ int (*power_save) (struct lbs_private *priv);
+ int (*power_restore) (struct lbs_private *priv);
int (*enter_deep_sleep) (struct lbs_private *priv);
int (*exit_deep_sleep) (struct lbs_private *priv);
int (*reset_deep_sleep_wakeup) (struct lbs_private *priv);
@@ -146,6 +158,7 @@ struct lbs_private {
/* protected by hard_start_xmit serialization */
u8 txretrycount;
struct sk_buff *currenttxskb;
+ struct timer_list tx_lockup_timer;
/* Locks */
struct mutex lock;
@@ -167,9 +180,20 @@ struct lbs_private {
wait_queue_head_t scan_q;
/* Whether the scan was initiated internally and not by cfg80211 */
bool internal_scan;
- unsigned long last_scan;
};
extern struct cmd_confirm_sleep confirm_sleep;
+/* Check if there is an interface active. */
+static inline int lbs_iface_active(struct lbs_private *priv)
+{
+ int r;
+
+ r = netif_running(priv->dev);
+ if (priv->mesh_dev)
+ r |= netif_running(priv->mesh_dev);
+
+ return r;
+}
+
#endif
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
index 4dfb3bfd2cf3..885ddc1c4fed 100644
--- a/drivers/net/wireless/libertas/ethtool.c
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -5,6 +5,7 @@
#include "decl.h"
#include "cmd.h"
+#include "mesh.h"
static void lbs_ethtool_get_drvinfo(struct net_device *dev,
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 387786e1b394..c962e21762dc 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -39,6 +39,7 @@
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/host.h>
+#include <linux/pm_runtime.h>
#include "host.h"
#include "decl.h"
@@ -47,6 +48,8 @@
#include "cmd.h"
#include "if_sdio.h"
+static void if_sdio_interrupt(struct sdio_func *func);
+
/* The if_sdio_remove() callback function is called when
* user removes this module from kernel space or ejects
* the card from the slot. The driver handles these 2 cases
@@ -757,6 +760,136 @@ out:
return ret;
}
+/********************************************************************/
+/* Power management */
+/********************************************************************/
+
+static int if_sdio_power_on(struct if_sdio_card *card)
+{
+ struct sdio_func *func = card->func;
+ struct lbs_private *priv = card->priv;
+ struct mmc_host *host = func->card->host;
+ int ret;
+
+ sdio_claim_host(func);
+
+ ret = sdio_enable_func(func);
+ if (ret)
+ goto release;
+
+ /* For 1-bit transfers to the 8686 model, we need to enable the
+ * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
+ * bit to allow access to non-vendor registers. */
+ if ((card->model == MODEL_8686) &&
+ (host->caps & MMC_CAP_SDIO_IRQ) &&
+ (host->ios.bus_width == MMC_BUS_WIDTH_1)) {
+ u8 reg;
+
+ func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
+ reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret);
+ if (ret)
+ goto disable;
+
+ reg |= SDIO_BUS_ECSI;
+ sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret);
+ if (ret)
+ goto disable;
+ }
+
+ card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
+ if (ret)
+ goto disable;
+
+ card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8;
+ if (ret)
+ goto disable;
+
+ card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16;
+ if (ret)
+ goto disable;
+
+ sdio_release_host(func);
+ ret = if_sdio_prog_firmware(card);
+ sdio_claim_host(func);
+ if (ret)
+ goto disable;
+
+ /*
+ * Get rx_unit if the chip is SD8688 or newer.
+ * SD8385 & SD8686 do not have rx_unit.
+ */
+ if ((card->model != MODEL_8385)
+ && (card->model != MODEL_8686))
+ card->rx_unit = if_sdio_read_rx_unit(card);
+ else
+ card->rx_unit = 0;
+
+ /*
+ * Set up the interrupt handler late.
+ *
+ * If we set it up earlier, the (buggy) hardware generates a spurious
+ * interrupt, even before the interrupt has been enabled, with
+ * CCCR_INTx = 0.
+ *
+ * We register the interrupt handler late so that we can handle any
+ * spurious interrupts, and also to avoid generation of that known
+ * spurious interrupt in the first place.
+ */
+ ret = sdio_claim_irq(func, if_sdio_interrupt);
+ if (ret)
+ goto disable;
+
+ /*
+ * Enable interrupts now that everything is set up
+ */
+ sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret);
+ if (ret)
+ goto release_irq;
+
+ sdio_release_host(func);
+
+ /*
+ * FUNC_INIT is required for SD8688 WLAN/BT multiple functions
+ */
+ if (card->model == MODEL_8688) {
+ struct cmd_header cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ lbs_deb_sdio("send function INIT command\n");
+ if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
+ lbs_cmd_copyback, (unsigned long) &cmd))
+ netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n");
+ }
+
+ priv->fw_ready = 1;
+
+ return 0;
+
+release_irq:
+ sdio_release_irq(func);
+disable:
+ sdio_disable_func(func);
+release:
+ sdio_release_host(func);
+ return ret;
+}
+
+static int if_sdio_power_off(struct if_sdio_card *card)
+{
+ struct sdio_func *func = card->func;
+ struct lbs_private *priv = card->priv;
+
+ priv->fw_ready = 0;
+
+ sdio_claim_host(func);
+ sdio_release_irq(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+ return 0;
+}
+
+
/*******************************************************************/
/* Libertas callbacks */
/*******************************************************************/
@@ -923,6 +1056,32 @@ static void if_sdio_reset_card(struct lbs_private *priv)
schedule_work(&card_reset_work);
}
+static int if_sdio_power_save(struct lbs_private *priv)
+{
+ struct if_sdio_card *card = priv->card;
+ int ret;
+
+ flush_workqueue(card->workqueue);
+
+ ret = if_sdio_power_off(card);
+
+ /* Let runtime PM know the card is powered off */
+ pm_runtime_put_sync(&card->func->dev);
+
+ return ret;
+}
+
+static int if_sdio_power_restore(struct lbs_private *priv)
+{
+ struct if_sdio_card *card = priv->card;
+
+ /* Make sure the card will not be powered off by runtime PM */
+ pm_runtime_get_sync(&card->func->dev);
+
+ return if_sdio_power_on(card);
+}
+
+
/*******************************************************************/
/* SDIO callbacks */
/*******************************************************************/
@@ -976,7 +1135,6 @@ static int if_sdio_probe(struct sdio_func *func,
int ret, i;
unsigned int model;
struct if_sdio_packet *packet;
- struct mmc_host *host = func->card->host;
lbs_deb_enter(LBS_DEB_SDIO);
@@ -1033,45 +1191,6 @@ static int if_sdio_probe(struct sdio_func *func,
goto free;
}
- sdio_claim_host(func);
-
- ret = sdio_enable_func(func);
- if (ret)
- goto release;
-
- /* For 1-bit transfers to the 8686 model, we need to enable the
- * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
- * bit to allow access to non-vendor registers. */
- if ((card->model == MODEL_8686) &&
- (host->caps & MMC_CAP_SDIO_IRQ) &&
- (host->ios.bus_width == MMC_BUS_WIDTH_1)) {
- u8 reg;
-
- func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
- reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret);
- if (ret)
- goto release_int;
-
- reg |= SDIO_BUS_ECSI;
- sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret);
- if (ret)
- goto release_int;
- }
-
- card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
- if (ret)
- goto release_int;
-
- card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8;
- if (ret)
- goto release_int;
-
- card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16;
- if (ret)
- goto release_int;
-
- sdio_release_host(func);
-
sdio_set_drvdata(func, card);
lbs_deb_sdio("class = 0x%X, vendor = 0x%X, "
@@ -1079,14 +1198,11 @@ static int if_sdio_probe(struct sdio_func *func,
func->class, func->vendor, func->device,
model, (unsigned)card->ioport);
- ret = if_sdio_prog_firmware(card);
- if (ret)
- goto reclaim;
priv = lbs_add_card(card, &func->dev);
if (!priv) {
ret = -ENOMEM;
- goto reclaim;
+ goto free;
}
card->priv = priv;
@@ -1097,62 +1213,21 @@ static int if_sdio_probe(struct sdio_func *func,
priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
priv->reset_card = if_sdio_reset_card;
+ priv->power_save = if_sdio_power_save;
+ priv->power_restore = if_sdio_power_restore;
- sdio_claim_host(func);
-
- /*
- * Get rx_unit if the chip is SD8688 or newer.
- * SD8385 & SD8686 do not have rx_unit.
- */
- if ((card->model != MODEL_8385)
- && (card->model != MODEL_8686))
- card->rx_unit = if_sdio_read_rx_unit(card);
- else
- card->rx_unit = 0;
-
- /*
- * Set up the interrupt handler late.
- *
- * If we set it up earlier, the (buggy) hardware generates a spurious
- * interrupt, even before the interrupt has been enabled, with
- * CCCR_INTx = 0.
- *
- * We register the interrupt handler late so that we can handle any
- * spurious interrupts, and also to avoid generation of that known
- * spurious interrupt in the first place.
- */
- ret = sdio_claim_irq(func, if_sdio_interrupt);
- if (ret)
- goto disable;
-
- /*
- * Enable interrupts now that everything is set up
- */
- sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret);
- sdio_release_host(func);
+ ret = if_sdio_power_on(card);
if (ret)
- goto reclaim;
-
- priv->fw_ready = 1;
-
- /*
- * FUNC_INIT is required for SD8688 WLAN/BT multiple functions
- */
- if (card->model == MODEL_8688) {
- struct cmd_header cmd;
-
- memset(&cmd, 0, sizeof(cmd));
-
- lbs_deb_sdio("send function INIT command\n");
- if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
- lbs_cmd_copyback, (unsigned long) &cmd))
- netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n");
- }
+ goto err_activate_card;
ret = lbs_start_card(priv);
+ if_sdio_power_off(card);
if (ret)
goto err_activate_card;
+ /* Tell PM core that we don't need the card to be powered now */
+ pm_runtime_put_noidle(&func->dev);
+
out:
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
@@ -1161,14 +1236,6 @@ out:
err_activate_card:
flush_workqueue(card->workqueue);
lbs_remove_card(priv);
-reclaim:
- sdio_claim_host(func);
-release_int:
- sdio_release_irq(func);
-disable:
- sdio_disable_func(func);
-release:
- sdio_release_host(func);
free:
destroy_workqueue(card->workqueue);
while (card->packets) {
@@ -1195,6 +1262,9 @@ static void if_sdio_remove(struct sdio_func *func)
card = sdio_get_drvdata(func);
+ /* Undo decrement done above in if_sdio_probe */
+ pm_runtime_get_noresume(&func->dev);
+
if (user_rmmod && (card->model == MODEL_8688)) {
/*
* FUNC_SHUTDOWN is required for SD8688 WLAN/BT
@@ -1219,11 +1289,6 @@ static void if_sdio_remove(struct sdio_func *func)
flush_workqueue(card->workqueue);
destroy_workqueue(card->workqueue);
- sdio_claim_host(func);
- sdio_release_irq(func);
- sdio_disable_func(func);
- sdio_release_host(func);
-
while (card->packets) {
packet = card->packets;
card->packets = card->packets->next;
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index e0286cfbc91d..622ae6de0d8b 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -531,10 +531,6 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card,
goto out;
err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
IF_SPI_CIC_CMD_DOWNLOAD_OVER);
- goto out;
-
- lbs_deb_spi("waiting for helper to boot...\n");
-
out:
if (err)
pr_err("failed to load helper firmware (err=%d)\n", err);
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index b5acc393a65a..8147f1e2a0b0 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -324,7 +324,7 @@ static int if_usb_probe(struct usb_interface *intf,
}
kparam_unblock_sysfs_write(fw_name);
- if (!(priv = lbs_add_card(cardp, &udev->dev)))
+ if (!(priv = lbs_add_card(cardp, &intf->dev)))
goto err_prog_firmware;
cardp->priv = priv;
@@ -956,7 +956,7 @@ static int if_usb_prog_firmware(struct if_usb_card *cardp,
priv->dnld_sent = DNLD_RES_RECEIVED;
spin_unlock_irqrestore(&priv->driver_lock, flags);
- wake_up_interruptible(&priv->waitq);
+ wake_up(&priv->waitq);
return ret;
}
@@ -973,6 +973,23 @@ static const struct {
{ MODEL_8682, "libertas/usb8682.bin" }
};
+#ifdef CONFIG_OLPC
+
+static int try_olpc_fw(struct if_usb_card *cardp)
+{
+ int retval = -ENOENT;
+
+ /* try the OLPC firmware first; fall back to fw_table list */
+ if (machine_is_olpc() && cardp->model == MODEL_8388)
+ retval = request_firmware(&cardp->fw,
+ "libertas/usb8388_olpc.bin", &cardp->udev->dev);
+ return retval;
+}
+
+#else
+static int try_olpc_fw(struct if_usb_card *cardp) { return -ENOENT; }
+#endif /* !CONFIG_OLPC */
+
static int get_fw(struct if_usb_card *cardp, const char *fwname)
{
int i;
@@ -981,6 +998,10 @@ static int get_fw(struct if_usb_card *cardp, const char *fwname)
if (fwname)
return request_firmware(&cardp->fw, fwname, &cardp->udev->dev);
+ /* Handle OLPC firmware */
+ if (try_olpc_fw(cardp) == 0)
+ return 0;
+
/* Otherwise search for firmware to use */
for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
if (fw_table[i].model != cardp->model)
@@ -1112,6 +1133,15 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
if (priv->psstate != PS_STATE_FULL_POWER)
return -1;
+#ifdef CONFIG_OLPC
+ if (machine_is_olpc()) {
+ if (priv->wol_criteria == EHS_REMOVE_WAKEUP)
+ olpc_ec_wakeup_clear(EC_SCI_SRC_WLAN);
+ else
+ olpc_ec_wakeup_set(EC_SCI_SRC_WLAN);
+ }
+#endif
+
ret = lbs_suspend(priv);
if (ret)
goto out;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 94652c5a25de..b03779bcd547 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -23,6 +23,7 @@
#include "cfg.h"
#include "debugfs.h"
#include "cmd.h"
+#include "mesh.h"
#define DRIVER_RELEASE_VERSION "323.p0"
const char lbs_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
@@ -98,6 +99,69 @@ u8 lbs_data_rate_to_fw_index(u32 rate)
return 0;
}
+int lbs_set_iface_type(struct lbs_private *priv, enum nl80211_iftype type)
+{
+ int ret = 0;
+
+ switch (type) {
+ case NL80211_IFTYPE_MONITOR:
+ ret = lbs_set_monitor_mode(priv, 1);
+ break;
+ case NL80211_IFTYPE_STATION:
+ if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
+ ret = lbs_set_monitor_mode(priv, 0);
+ if (!ret)
+ ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 1);
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
+ ret = lbs_set_monitor_mode(priv, 0);
+ if (!ret)
+ ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 2);
+ break;
+ default:
+ ret = -ENOTSUPP;
+ }
+ return ret;
+}
+
+int lbs_start_iface(struct lbs_private *priv)
+{
+ struct cmd_ds_802_11_mac_address cmd;
+ int ret;
+
+ if (priv->power_restore) {
+ ret = priv->power_restore(priv);
+ if (ret)
+ return ret;
+ }
+
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_SET);
+ memcpy(cmd.macadd, priv->current_addr, ETH_ALEN);
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11_MAC_ADDRESS, &cmd);
+ if (ret) {
+ lbs_deb_net("set MAC address failed\n");
+ goto err;
+ }
+
+ ret = lbs_set_iface_type(priv, priv->wdev->iftype);
+ if (ret) {
+ lbs_deb_net("set iface type failed\n");
+ goto err;
+ }
+
+ lbs_update_channel(priv);
+
+ priv->iface_running = true;
+ return 0;
+
+err:
+ if (priv->power_save)
+ priv->power_save(priv);
+ return ret;
+}
/**
* lbs_dev_open - open the ethX interface
@@ -111,23 +175,65 @@ static int lbs_dev_open(struct net_device *dev)
int ret = 0;
lbs_deb_enter(LBS_DEB_NET);
+ if (!priv->iface_running) {
+ ret = lbs_start_iface(priv);
+ if (ret)
+ goto out;
+ }
spin_lock_irq(&priv->driver_lock);
- priv->stopping = false;
- if (priv->connect_status == LBS_CONNECTED)
- netif_carrier_on(dev);
- else
- netif_carrier_off(dev);
+ netif_carrier_off(dev);
if (!priv->tx_pending_len)
netif_wake_queue(dev);
spin_unlock_irq(&priv->driver_lock);
+
+out:
lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
return ret;
}
+static bool lbs_command_queue_empty(struct lbs_private *priv)
+{
+ unsigned long flags;
+ bool ret;
+ spin_lock_irqsave(&priv->driver_lock, flags);
+ ret = priv->cur_cmd == NULL && list_empty(&priv->cmdpendingq);
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
+ return ret;
+}
+
+int lbs_stop_iface(struct lbs_private *priv)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_MAIN);
+
+ spin_lock_irqsave(&priv->driver_lock, flags);
+ priv->iface_running = false;
+ kfree_skb(priv->currenttxskb);
+ priv->currenttxskb = NULL;
+ priv->tx_pending_len = 0;
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+ cancel_work_sync(&priv->mcast_work);
+ del_timer_sync(&priv->tx_lockup_timer);
+
+ /* Disable command processing, and wait for all commands to complete */
+ lbs_deb_main("waiting for commands to complete\n");
+ wait_event(priv->waitq, lbs_command_queue_empty(priv));
+ lbs_deb_main("all commands completed\n");
+
+ if (priv->power_save)
+ ret = priv->power_save(priv);
+
+ lbs_deb_leave(LBS_DEB_MAIN);
+ return ret;
+}
+
/**
* lbs_eth_stop - close the ethX interface
*
@@ -140,18 +246,25 @@ static int lbs_eth_stop(struct net_device *dev)
lbs_deb_enter(LBS_DEB_NET);
+ if (priv->connect_status == LBS_CONNECTED)
+ lbs_disconnect(priv, WLAN_REASON_DEAUTH_LEAVING);
+
spin_lock_irq(&priv->driver_lock);
- priv->stopping = true;
netif_stop_queue(dev);
spin_unlock_irq(&priv->driver_lock);
- schedule_work(&priv->mcast_work);
+ lbs_update_mcast(priv);
cancel_delayed_work_sync(&priv->scan_work);
if (priv->scan_req) {
cfg80211_scan_done(priv->scan_req, false);
priv->scan_req = NULL;
}
+ netif_carrier_off(priv->dev);
+
+ if (!lbs_iface_active(priv))
+ lbs_stop_iface(priv);
+
lbs_deb_leave(LBS_DEB_NET);
return 0;
}
@@ -163,13 +276,14 @@ void lbs_host_to_card_done(struct lbs_private *priv)
lbs_deb_enter(LBS_DEB_THREAD);
spin_lock_irqsave(&priv->driver_lock, flags);
+ del_timer(&priv->tx_lockup_timer);
priv->dnld_sent = DNLD_RES_RECEIVED;
/* Wake main thread if commands are pending */
if (!priv->cur_cmd || priv->tx_pending_len > 0) {
if (!priv->wakeup_dev_required)
- wake_up_interruptible(&priv->waitq);
+ wake_up(&priv->waitq);
}
spin_unlock_irqrestore(&priv->driver_lock, flags);
@@ -182,29 +296,24 @@ int lbs_set_mac_address(struct net_device *dev, void *addr)
int ret = 0;
struct lbs_private *priv = dev->ml_priv;
struct sockaddr *phwaddr = addr;
- struct cmd_ds_802_11_mac_address cmd;
lbs_deb_enter(LBS_DEB_NET);
+ /*
+ * Can only set MAC address when all interfaces are down, to be written
+ * to the hardware when one of them is brought up.
+ */
+ if (lbs_iface_active(priv))
+ return -EBUSY;
+
/* In case it was called from the mesh device */
dev = priv->dev;
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
- cmd.action = cpu_to_le16(CMD_ACT_SET);
- memcpy(cmd.macadd, phwaddr->sa_data, ETH_ALEN);
-
- ret = lbs_cmd_with_response(priv, CMD_802_11_MAC_ADDRESS, &cmd);
- if (ret) {
- lbs_deb_net("set MAC address failed\n");
- goto done;
- }
-
memcpy(priv->current_addr, phwaddr->sa_data, ETH_ALEN);
memcpy(dev->dev_addr, phwaddr->sa_data, ETH_ALEN);
if (priv->mesh_dev)
memcpy(priv->mesh_dev->dev_addr, phwaddr->sa_data, ETH_ALEN);
-done:
lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
return ret;
}
@@ -258,18 +367,18 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd,
return i;
}
-static void lbs_set_mcast_worker(struct work_struct *work)
+void lbs_update_mcast(struct lbs_private *priv)
{
- struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work);
struct cmd_ds_mac_multicast_adr mcast_cmd;
- int dev_flags;
+ int dev_flags = 0;
int nr_addrs;
int old_mac_control = priv->mac_control;
lbs_deb_enter(LBS_DEB_NET);
- dev_flags = priv->dev->flags;
- if (priv->mesh_dev)
+ if (netif_running(priv->dev))
+ dev_flags |= priv->dev->flags;
+ if (priv->mesh_dev && netif_running(priv->mesh_dev))
dev_flags |= priv->mesh_dev->flags;
if (dev_flags & IFF_PROMISC) {
@@ -315,6 +424,12 @@ static void lbs_set_mcast_worker(struct work_struct *work)
lbs_deb_leave(LBS_DEB_NET);
}
+static void lbs_set_mcast_worker(struct work_struct *work)
+{
+ struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work);
+ lbs_update_mcast(priv);
+}
+
void lbs_set_multicast_list(struct net_device *dev)
{
struct lbs_private *priv = dev->ml_priv;
@@ -504,6 +619,9 @@ static int lbs_thread(void *data)
if (ret) {
lbs_deb_tx("host_to_card failed %d\n", ret);
priv->dnld_sent = DNLD_RES_RECEIVED;
+ } else {
+ mod_timer(&priv->tx_lockup_timer,
+ jiffies + (HZ * 5));
}
priv->tx_pending_len = 0;
if (!priv->currenttxskb) {
@@ -520,6 +638,7 @@ static int lbs_thread(void *data)
}
del_timer(&priv->command_timer);
+ del_timer(&priv->tx_lockup_timer);
del_timer(&priv->auto_deepsleep_timer);
lbs_deb_leave(LBS_DEB_THREAD);
@@ -647,13 +766,39 @@ static void lbs_cmd_timeout_handler(unsigned long data)
if (priv->dnld_sent == DNLD_CMD_SENT)
priv->dnld_sent = DNLD_RES_RECEIVED;
- wake_up_interruptible(&priv->waitq);
+ wake_up(&priv->waitq);
out:
spin_unlock_irqrestore(&priv->driver_lock, flags);
lbs_deb_leave(LBS_DEB_CMD);
}
/**
+ * lbs_tx_lockup_handler - handles the timeout of the passing of TX frames
+ * to the hardware. This is known to frequently happen with SD8686 when
+ * waking up after a Wake-on-WLAN-triggered resume.
+ *
+ * @data: &struct lbs_private pointer
+ */
+static void lbs_tx_lockup_handler(unsigned long data)
+{
+ struct lbs_private *priv = (struct lbs_private *)data;
+ unsigned long flags;
+
+ lbs_deb_enter(LBS_DEB_TX);
+ spin_lock_irqsave(&priv->driver_lock, flags);
+
+ netdev_info(priv->dev, "TX lockup detected\n");
+ if (priv->reset_card)
+ priv->reset_card(priv);
+
+ priv->dnld_sent = DNLD_RES_RECEIVED;
+ wake_up_interruptible(&priv->waitq);
+
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
+ lbs_deb_leave(LBS_DEB_TX);
+}
+
+/**
* auto_deepsleep_timer_fn - put the device back to deep sleep mode when
* timer expires and no activity (command, event, data etc.) is detected.
* @data: &struct lbs_private pointer
@@ -739,6 +884,8 @@ static int lbs_init_adapter(struct lbs_private *priv)
setup_timer(&priv->command_timer, lbs_cmd_timeout_handler,
(unsigned long)priv);
+ setup_timer(&priv->tx_lockup_timer, lbs_tx_lockup_handler,
+ (unsigned long)priv);
setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn,
(unsigned long)priv);
@@ -776,6 +923,7 @@ static void lbs_free_adapter(struct lbs_private *priv)
lbs_free_cmd_buffer(priv);
kfifo_free(&priv->event_fifo);
del_timer(&priv->command_timer);
+ del_timer(&priv->tx_lockup_timer);
del_timer(&priv->auto_deepsleep_timer);
lbs_deb_leave(LBS_DEB_MAIN);
@@ -786,7 +934,7 @@ static const struct net_device_ops lbs_netdev_ops = {
.ndo_stop = lbs_eth_stop,
.ndo_start_xmit = lbs_hard_start_xmit,
.ndo_set_mac_address = lbs_set_mac_address,
- .ndo_set_multicast_list = lbs_set_multicast_list,
+ .ndo_set_rx_mode = lbs_set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
};
@@ -889,10 +1037,6 @@ void lbs_remove_card(struct lbs_private *priv)
lbs_remove_mesh(priv);
lbs_scan_deinit(priv);
- dev = priv->dev;
-
- cancel_work_sync(&priv->mcast_work);
-
/* worker thread destruction blocks on the in-flight command which
* should have been cleared already in lbs_stop_card().
*/
@@ -950,17 +1094,18 @@ int lbs_start_card(struct lbs_private *priv)
if (ret)
goto done;
+ if (!lbs_disablemesh)
+ lbs_init_mesh(priv);
+ else
+ pr_info("%s: mesh disabled\n", dev->name);
+
if (lbs_cfg_register(priv)) {
pr_err("cannot register device\n");
goto done;
}
- lbs_update_channel(priv);
-
- if (!lbs_disablemesh)
- lbs_init_mesh(priv);
- else
- pr_info("%s: mesh disabled\n", dev->name);
+ if (lbs_mesh_activated(priv))
+ lbs_start_mesh(priv);
lbs_debugfs_init_one(priv, dev);
@@ -978,8 +1123,6 @@ EXPORT_SYMBOL_GPL(lbs_start_card);
void lbs_stop_card(struct lbs_private *priv)
{
struct net_device *dev;
- struct cmd_ctrl_node *cmdnode;
- unsigned long flags;
lbs_deb_enter(LBS_DEB_MAIN);
@@ -992,30 +1135,6 @@ void lbs_stop_card(struct lbs_private *priv)
lbs_debugfs_remove_one(priv);
lbs_deinit_mesh(priv);
-
- /* Delete the timeout of the currently processing command */
- del_timer_sync(&priv->command_timer);
- del_timer_sync(&priv->auto_deepsleep_timer);
-
- /* Flush pending command nodes */
- spin_lock_irqsave(&priv->driver_lock, flags);
- lbs_deb_main("clearing pending commands\n");
- list_for_each_entry(cmdnode, &priv->cmdpendingq, list) {
- cmdnode->result = -ENOENT;
- cmdnode->cmdwaitqwoken = 1;
- wake_up(&cmdnode->cmdwait_q);
- }
-
- /* Flush the command the card is currently processing */
- if (priv->cur_cmd) {
- lbs_deb_main("clearing current command\n");
- priv->cur_cmd->result = -ENOENT;
- priv->cur_cmd->cmdwaitqwoken = 1;
- wake_up(&priv->cur_cmd->cmdwait_q);
- }
- lbs_deb_main("done clearing commands\n");
- spin_unlock_irqrestore(&priv->driver_lock, flags);
-
unregister_netdev(dev);
out:
@@ -1036,7 +1155,7 @@ void lbs_queue_event(struct lbs_private *priv, u32 event)
kfifo_in(&priv->event_fifo, (unsigned char *) &event, sizeof(u32));
- wake_up_interruptible(&priv->waitq);
+ wake_up(&priv->waitq);
spin_unlock_irqrestore(&priv->driver_lock, flags);
lbs_deb_leave(LBS_DEB_THREAD);
@@ -1054,7 +1173,7 @@ void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx)
BUG_ON(resp_idx > 1);
priv->resp_idx = resp_idx;
- wake_up_interruptible(&priv->waitq);
+ wake_up(&priv->waitq);
lbs_deb_leave(LBS_DEB_THREAD);
}
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
index be72c08ea2a7..e87c031b298f 100644
--- a/drivers/net/wireless/libertas/mesh.c
+++ b/drivers/net/wireless/libertas/mesh.c
@@ -129,6 +129,19 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
}
+int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel)
+{
+ return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel);
+}
+
+static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
+{
+ struct wireless_dev *mesh_wdev = priv->mesh_dev->ieee80211_ptr;
+ if (mesh_wdev->channel)
+ return mesh_wdev->channel->hw_value;
+ else
+ return 1;
+}
/***************************************************************************
* Mesh sysfs support
@@ -812,7 +825,6 @@ static void lbs_persist_config_remove(struct net_device *dev)
*/
int lbs_init_mesh(struct lbs_private *priv)
{
- struct net_device *dev = priv->dev;
int ret = 0;
lbs_deb_enter(LBS_DEB_MESH);
@@ -837,11 +849,9 @@ int lbs_init_mesh(struct lbs_private *priv)
useful */
priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
- if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->channel)) {
+ if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) {
priv->mesh_tlv = TLV_TYPE_MESH_ID;
- if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->channel))
+ if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
priv->mesh_tlv = 0;
}
} else
@@ -851,23 +861,16 @@ int lbs_init_mesh(struct lbs_private *priv)
* 0x100+37; Do not invoke command with old TLV.
*/
priv->mesh_tlv = TLV_TYPE_MESH_ID;
- if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->channel))
+ if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
priv->mesh_tlv = 0;
}
/* Stop meshing until interface is brought up */
- lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel);
+ lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, 1);
if (priv->mesh_tlv) {
sprintf(priv->mesh_ssid, "mesh");
priv->mesh_ssid_len = 4;
-
- lbs_add_mesh(priv);
-
- if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
- netdev_err(dev, "cannot register lbs_mesh attribute\n");
-
ret = 1;
}
@@ -875,6 +878,13 @@ int lbs_init_mesh(struct lbs_private *priv)
return ret;
}
+void lbs_start_mesh(struct lbs_private *priv)
+{
+ lbs_add_mesh(priv);
+
+ if (device_create_file(&priv->dev->dev, &dev_attr_lbs_mesh))
+ netdev_err(priv->dev, "cannot register lbs_mesh attribute\n");
+}
int lbs_deinit_mesh(struct lbs_private *priv)
{
@@ -904,7 +914,8 @@ static int lbs_mesh_stop(struct net_device *dev)
struct lbs_private *priv = dev->ml_priv;
lbs_deb_enter(LBS_DEB_MESH);
- lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel);
+ lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
+ lbs_mesh_get_channel(priv));
spin_lock_irq(&priv->driver_lock);
@@ -913,7 +924,9 @@ static int lbs_mesh_stop(struct net_device *dev)
spin_unlock_irq(&priv->driver_lock);
- schedule_work(&priv->mcast_work);
+ lbs_update_mcast(priv);
+ if (!lbs_iface_active(priv))
+ lbs_stop_iface(priv);
lbs_deb_leave(LBS_DEB_MESH);
return 0;
@@ -931,6 +944,11 @@ static int lbs_mesh_dev_open(struct net_device *dev)
int ret = 0;
lbs_deb_enter(LBS_DEB_NET);
+ if (!priv->iface_running) {
+ ret = lbs_start_iface(priv);
+ if (ret)
+ goto out;
+ }
spin_lock_irq(&priv->driver_lock);
@@ -947,7 +965,8 @@ static int lbs_mesh_dev_open(struct net_device *dev)
spin_unlock_irq(&priv->driver_lock);
- ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, priv->channel);
+ ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
+ lbs_mesh_get_channel(priv));
out:
lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
@@ -959,7 +978,7 @@ static const struct net_device_ops mesh_netdev_ops = {
.ndo_stop = lbs_mesh_stop,
.ndo_start_xmit = lbs_hard_start_xmit,
.ndo_set_mac_address = lbs_set_mac_address,
- .ndo_set_multicast_list = lbs_set_multicast_list,
+ .ndo_set_rx_mode = lbs_set_multicast_list,
};
/**
@@ -971,18 +990,32 @@ static const struct net_device_ops mesh_netdev_ops = {
static int lbs_add_mesh(struct lbs_private *priv)
{
struct net_device *mesh_dev = NULL;
+ struct wireless_dev *mesh_wdev;
int ret = 0;
lbs_deb_enter(LBS_DEB_MESH);
/* Allocate a virtual mesh device */
+ mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+ if (!mesh_wdev) {
+ lbs_deb_mesh("init mshX wireless device failed\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
mesh_dev = alloc_netdev(0, "msh%d", ether_setup);
if (!mesh_dev) {
lbs_deb_mesh("init mshX device failed\n");
ret = -ENOMEM;
- goto done;
+ goto err_free_wdev;
}
+
+ mesh_wdev->iftype = NL80211_IFTYPE_MESH_POINT;
+ mesh_wdev->wiphy = priv->wdev->wiphy;
+ mesh_wdev->netdev = mesh_dev;
+
mesh_dev->ml_priv = priv;
+ mesh_dev->ieee80211_ptr = mesh_wdev;
priv->mesh_dev = mesh_dev;
mesh_dev->netdev_ops = &mesh_netdev_ops;
@@ -996,7 +1029,7 @@ static int lbs_add_mesh(struct lbs_private *priv)
ret = register_netdev(mesh_dev);
if (ret) {
pr_err("cannot register mshX virtual interface\n");
- goto err_free;
+ goto err_free_netdev;
}
ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
@@ -1012,9 +1045,12 @@ static int lbs_add_mesh(struct lbs_private *priv)
err_unregister:
unregister_netdev(mesh_dev);
-err_free:
+err_free_netdev:
free_netdev(mesh_dev);
+err_free_wdev:
+ kfree(mesh_wdev);
+
done:
lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
return ret;
@@ -1035,6 +1071,7 @@ void lbs_remove_mesh(struct lbs_private *priv)
lbs_persist_config_remove(mesh_dev);
unregister_netdev(mesh_dev);
priv->mesh_dev = NULL;
+ kfree(mesh_dev->ieee80211_ptr);
free_netdev(mesh_dev);
lbs_deb_leave(LBS_DEB_MESH);
}
diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h
index 50144913f2ab..6603f341c874 100644
--- a/drivers/net/wireless/libertas/mesh.h
+++ b/drivers/net/wireless/libertas/mesh.h
@@ -9,30 +9,25 @@
#include <net/lib80211.h>
#include "host.h"
+#include "dev.h"
#ifdef CONFIG_LIBERTAS_MESH
-/* Mesh statistics */
-struct lbs_mesh_stats {
- u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */
- u32 fwd_unicast_cnt; /* Fwd: Unicast counter */
- u32 fwd_drop_ttl; /* Fwd: TTL zero */
- u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */
- u32 fwd_drop_noroute; /* Fwd: No route to Destination */
- u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */
- u32 drop_blind; /* Rx: Dropped by blinding table */
- u32 tx_failed_cnt; /* Tx: Failed transmissions */
-};
-
-
struct net_device;
-struct lbs_private;
int lbs_init_mesh(struct lbs_private *priv);
+void lbs_start_mesh(struct lbs_private *priv);
int lbs_deinit_mesh(struct lbs_private *priv);
void lbs_remove_mesh(struct lbs_private *priv);
+static inline bool lbs_mesh_activated(struct lbs_private *priv)
+{
+ /* Mesh SSID is only programmed after successful init */
+ return priv->mesh_ssid_len != 0;
+}
+
+int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel);
/* Sending / Receiving */
@@ -67,11 +62,13 @@ void lbs_mesh_ethtool_get_strings(struct net_device *dev,
#define lbs_init_mesh(priv)
#define lbs_deinit_mesh(priv)
+#define lbs_start_mesh(priv)
#define lbs_add_mesh(priv)
#define lbs_remove_mesh(priv)
#define lbs_mesh_set_dev(priv, dev, rxpd) (dev)
#define lbs_mesh_set_txpd(priv, dev, txpd)
-#define lbs_mesh_config(priv, enable, chan)
+#define lbs_mesh_set_channel(priv, channel) (0)
+#define lbs_mesh_activated(priv) (false)
#endif
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index bfb8898ae518..62e10eeadd7e 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -15,6 +15,7 @@
#include "radiotap.h"
#include "decl.h"
#include "dev.h"
+#include "mesh.h"
struct eth803hdr {
u8 dest_addr[6];
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index a6e85134cfe1..8f127520d786 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -12,6 +12,7 @@
#include "decl.h"
#include "defs.h"
#include "dev.h"
+#include "mesh.h"
/**
* convert_radiotap_rate_to_mv - converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
diff --git a/drivers/net/wireless/libertas_tf/deb_defs.h b/drivers/net/wireless/libertas_tf/deb_defs.h
index ae753962d8b5..4bd3dc5adf7c 100644
--- a/drivers/net/wireless/libertas_tf/deb_defs.h
+++ b/drivers/net/wireless/libertas_tf/deb_defs.h
@@ -3,7 +3,7 @@
* global variable declaration.
*/
#ifndef _LBS_DEB_DEFS_H_
-#define _LBS_DEB_EFS_H_
+#define _LBS_DEB_DEFS_H_
#ifndef DRV_NAME
#define DRV_NAME "libertas_tf"
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 031cd89b1768..68455a2307cb 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -612,6 +612,12 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
rx_status.freq = data->channel->center_freq;
rx_status.band = data->channel->band;
rx_status.rate_idx = info->control.rates[0].idx;
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS)
+ rx_status.flag |= RX_FLAG_HT;
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ rx_status.flag |= RX_FLAG_40MHZ;
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)
+ rx_status.flag |= RX_FLAG_SHORT_GI;
/* TODO: simulate real signal strength (and optional packet loss) */
rx_status.signal = data->power_level - 50;
@@ -964,7 +970,8 @@ static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw,
}
static int mac80211_hwsim_conf_tx(
- struct ieee80211_hw *hw, u16 queue,
+ struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
wiphy_debug(hw->wiphy,
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c
index 1a453a605b3f..079e5532e686 100644
--- a/drivers/net/wireless/mwifiex/11n_aggr.c
+++ b/drivers/net/wireless/mwifiex/11n_aggr.c
@@ -193,7 +193,6 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
skb_src = skb_dequeue(&pra_list->skb_head);
pra_list->total_pkts_size -= skb_src->len;
- pra_list->total_pkts--;
atomic_dec(&priv->wmm.tx_pkts_queued);
@@ -247,8 +246,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
tx_param.next_pkt_len = 0;
ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
- skb_aggr->data,
- skb_aggr->len, &tx_param);
+ skb_aggr, &tx_param);
switch (ret) {
case -EBUSY:
spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
@@ -269,7 +267,6 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
skb_queue_tail(&pra_list->skb_head, skb_aggr);
pra_list->total_pkts_size += skb_aggr->len;
- pra_list->total_pkts++;
atomic_inc(&priv->wmm.tx_pkts_queued);
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.h b/drivers/net/wireless/mwifiex/11n_aggr.h
index 9c6dca7ab02c..900e1c62a0cc 100644
--- a/drivers/net/wireless/mwifiex/11n_aggr.h
+++ b/drivers/net/wireless/mwifiex/11n_aggr.h
@@ -21,6 +21,7 @@
#define _MWIFIEX_11N_AGGR_H_
#define PKT_TYPE_AMSDU 0xE6
+#define MIN_NUM_AMSDU 2
int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv,
struct sk_buff *skb);
diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig
index 86962920cef3..8f2797aa0c60 100644
--- a/drivers/net/wireless/mwifiex/Kconfig
+++ b/drivers/net/wireless/mwifiex/Kconfig
@@ -19,3 +19,14 @@ config MWIFIEX_SDIO
If you choose to build it as a module, it will be called
mwifiex_sdio.
+
+config MWIFIEX_PCIE
+ tristate "Marvell WiFi-Ex Driver for PCIE 8766"
+ depends on MWIFIEX && PCI
+ select FW_LOADER
+ ---help---
+ This adds support for wireless adapters based on Marvell
+ 8766 chipset with PCIe interface.
+
+ If you choose to build it as a module, it will be called
+ mwifiex_pcie.
diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile
index 42cb733ea33a..b0257ad1bbed 100644
--- a/drivers/net/wireless/mwifiex/Makefile
+++ b/drivers/net/wireless/mwifiex/Makefile
@@ -39,3 +39,6 @@ obj-$(CONFIG_MWIFIEX) += mwifiex.o
mwifiex_sdio-y += sdio.o
obj-$(CONFIG_MWIFIEX_SDIO) += mwifiex_sdio.o
+
+mwifiex_pcie-y += pcie.o
+obj-$(CONFIG_MWIFIEX_PCIE) += mwifiex_pcie.o
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 352d2c5da1fc..462c71067bfb 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -543,12 +543,28 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,
ret = -EFAULT;
}
+ /*
+ * Bit 0 in tx_htinfo indicates that current Tx rate is 11n rate. Valid
+ * MCS index values for us are 0 to 7.
+ */
+ if ((priv->tx_htinfo & BIT(0)) && (priv->tx_rate < 8)) {
+ sinfo->txrate.mcs = priv->tx_rate;
+ sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
+ /* 40MHz rate */
+ if (priv->tx_htinfo & BIT(1))
+ sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+ /* SGI enabled */
+ if (priv->tx_htinfo & BIT(2))
+ sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+ }
+
sinfo->rx_bytes = priv->stats.rx_bytes;
sinfo->tx_bytes = priv->stats.tx_bytes;
sinfo->rx_packets = priv->stats.rx_packets;
sinfo->tx_packets = priv->stats.tx_packets;
- sinfo->signal = priv->w_stats.qual.level;
- sinfo->txrate.legacy = rate.rate;
+ sinfo->signal = priv->qual_level;
+ /* bit rate is in 500 kb/s units. Convert it to 100kb/s units */
+ sinfo->txrate.legacy = rate.rate * 5;
return ret;
}
@@ -565,8 +581,6 @@ mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
- mwifiex_dump_station_info(priv, sinfo);
-
if (!priv->media_connected)
return -ENOENT;
if (memcmp(mac, priv->cfg_bssid, ETH_ALEN))
@@ -768,6 +782,7 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
struct mwifiex_bss_info bss_info;
int ie_len;
u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)];
+ enum ieee80211_band band;
if (mwifiex_get_bss_info(priv, &bss_info))
return -1;
@@ -780,9 +795,10 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
bss_info.ssid.ssid_len);
ie_len = ie_buf[1] + sizeof(struct ieee_types_header);
+ band = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
chan = __ieee80211_get_channel(priv->wdev->wiphy,
ieee80211_channel_to_frequency(bss_info.bss_chan,
- priv->curr_bss_params.band));
+ band));
cfg80211_inform_bss(priv->wdev->wiphy, chan,
bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
@@ -793,139 +809,6 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
}
/*
- * This function informs the CFG802.11 subsystem of a new BSS connection.
- *
- * The following information are sent to the CFG802.11 subsystem
- * to register the new BSS connection. If we do not register the new BSS,
- * a kernel panic will result.
- * - MAC address
- * - Capabilities
- * - Beacon period
- * - RSSI value
- * - Channel
- * - Supported rates IE
- * - Extended capabilities IE
- * - DS parameter set IE
- * - HT Capability IE
- * - Vendor Specific IE (221)
- * - WPA IE
- * - RSN IE
- */
-static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv,
- struct mwifiex_802_11_ssid *ssid)
-{
- struct mwifiex_bssdescriptor *scan_table;
- int i, j;
- struct ieee80211_channel *chan;
- u8 *ie, *ie_buf;
- u32 ie_len;
- u8 *beacon;
- int beacon_size;
- u8 element_id, element_len;
-
-#define MAX_IE_BUF 2048
- ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL);
- if (!ie_buf) {
- dev_err(priv->adapter->dev, "%s: failed to alloc ie_buf\n",
- __func__);
- return -ENOMEM;
- }
-
- scan_table = priv->adapter->scan_table;
- for (i = 0; i < priv->adapter->num_in_scan_table; i++) {
- if (ssid) {
- /* Inform specific BSS only */
- if (memcmp(ssid->ssid, scan_table[i].ssid.ssid,
- ssid->ssid_len))
- continue;
- }
- memset(ie_buf, 0, MAX_IE_BUF);
- ie_buf[0] = WLAN_EID_SSID;
- ie_buf[1] = scan_table[i].ssid.ssid_len;
- memcpy(&ie_buf[sizeof(struct ieee_types_header)],
- scan_table[i].ssid.ssid, ie_buf[1]);
-
- ie = ie_buf + ie_buf[1] + sizeof(struct ieee_types_header);
- ie_len = ie_buf[1] + sizeof(struct ieee_types_header);
-
- ie[0] = WLAN_EID_SUPP_RATES;
-
- for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) {
- if (!scan_table[i].supported_rates[j])
- break;
- else
- ie[j + sizeof(struct ieee_types_header)] =
- scan_table[i].supported_rates[j];
- }
-
- ie[1] = j;
- ie_len += ie[1] + sizeof(struct ieee_types_header);
-
- beacon = scan_table[i].beacon_buf;
- beacon_size = scan_table[i].beacon_buf_size;
-
- /* Skip time stamp, beacon interval and capability */
-
- if (beacon) {
- beacon += sizeof(scan_table[i].beacon_period)
- + sizeof(scan_table[i].time_stamp) +
- +sizeof(scan_table[i].cap_info_bitmap);
-
- beacon_size -= sizeof(scan_table[i].beacon_period)
- + sizeof(scan_table[i].time_stamp)
- + sizeof(scan_table[i].cap_info_bitmap);
- }
-
- while (beacon_size >= sizeof(struct ieee_types_header)) {
- ie = ie_buf + ie_len;
- element_id = *beacon;
- element_len = *(beacon + 1);
- if (beacon_size < (int) element_len +
- sizeof(struct ieee_types_header)) {
- dev_err(priv->adapter->dev, "%s: in processing"
- " IE, bytes left < IE length\n",
- __func__);
- break;
- }
- switch (element_id) {
- case WLAN_EID_EXT_CAPABILITY:
- case WLAN_EID_DS_PARAMS:
- case WLAN_EID_HT_CAPABILITY:
- case WLAN_EID_VENDOR_SPECIFIC:
- case WLAN_EID_RSN:
- case WLAN_EID_BSS_AC_ACCESS_DELAY:
- ie[0] = element_id;
- ie[1] = element_len;
- memcpy(&ie[sizeof(struct ieee_types_header)],
- (u8 *) beacon
- + sizeof(struct ieee_types_header),
- element_len);
- ie_len += ie[1] +
- sizeof(struct ieee_types_header);
- break;
- default:
- break;
- }
- beacon += element_len +
- sizeof(struct ieee_types_header);
- beacon_size -= element_len +
- sizeof(struct ieee_types_header);
- }
- chan = ieee80211_get_channel(priv->wdev->wiphy,
- scan_table[i].freq);
- cfg80211_inform_bss(priv->wdev->wiphy, chan,
- scan_table[i].mac_address,
- 0, scan_table[i].cap_info_bitmap,
- scan_table[i].beacon_period,
- ie_buf, ie_len,
- scan_table[i].rssi, GFP_KERNEL);
- }
-
- kfree(ie_buf);
- return 0;
-}
-
-/*
* This function connects with a BSS.
*
* This function handles both Infra and Ad-Hoc modes. It also performs
@@ -937,8 +820,7 @@ static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv,
* For Infra mode, the function returns failure if the specified SSID
* is not found in scan table. However, for Ad-Hoc mode, it can create
* the IBSS if it does not exist. On successful completion in either case,
- * the function notifies the CFG802.11 subsystem of the new BSS connection,
- * otherwise the kernel will panic.
+ * the function notifies the CFG802.11 subsystem of the new BSS connection.
*/
static int
mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
@@ -946,11 +828,11 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
struct cfg80211_connect_params *sme, bool privacy)
{
struct mwifiex_802_11_ssid req_ssid;
- struct mwifiex_ssid_bssid ssid_bssid;
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(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid));
req_ssid.ssid_len = ssid_len;
if (ssid_len > IEEE80211_MAX_SSID_LEN) {
@@ -1028,30 +910,48 @@ done:
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
+ * then request scan and cfg80211_get_bss() again for final output.
+ */
+ while (1) {
+ if (is_scanning_required) {
+ /* Do specific SSID scanning */
+ if (mwifiex_request_scan(priv, &req_ssid)) {
+ dev_err(priv->adapter->dev, "scan error\n");
+ return -EFAULT;
+ }
+ }
- memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(struct mwifiex_802_11_ssid));
-
- if (mode != NL80211_IFTYPE_ADHOC) {
- if (mwifiex_find_best_bss(priv, &ssid_bssid))
- return -EFAULT;
- /* Inform the BSS information to kernel, otherwise
- * kernel will give a panic after successful assoc */
- if (mwifiex_inform_bss_from_scan_result(priv, &req_ssid))
- return -EFAULT;
+ /* Find the BSS we want using available scan results */
+ if (mode == NL80211_IFTYPE_ADHOC)
+ bss = cfg80211_get_bss(priv->wdev->wiphy, channel,
+ bssid, ssid, ssid_len,
+ WLAN_CAPABILITY_IBSS,
+ WLAN_CAPABILITY_IBSS);
+ else
+ bss = cfg80211_get_bss(priv->wdev->wiphy, channel,
+ bssid, ssid, ssid_len,
+ WLAN_CAPABILITY_ESS,
+ WLAN_CAPABILITY_ESS);
+
+ if (!bss) {
+ if (is_scanning_required) {
+ dev_warn(priv->adapter->dev, "assoc: requested "
+ "bss not found in scan results\n");
+ break;
+ }
+ is_scanning_required = 1;
+ } else {
+ dev_dbg(priv->adapter->dev, "info: trying to associate to %s and bssid %pM\n",
+ (char *) req_ssid.ssid, bss->bssid);
+ memcpy(&priv->cfg_bssid, bss->bssid, ETH_ALEN);
+ break;
+ }
}
- dev_dbg(priv->adapter->dev, "info: trying to associate to %s and bssid %pM\n",
- (char *) req_ssid.ssid, ssid_bssid.bssid);
-
- memcpy(&priv->cfg_bssid, ssid_bssid.bssid, 6);
-
- /* Connect to BSS by ESSID */
- memset(&ssid_bssid.bssid, 0, ETH_ALEN);
-
- if (!netif_queue_stopped(priv->netdev))
- netif_stop_queue(priv->netdev);
-
- if (mwifiex_bss_start(priv, &ssid_bssid))
+ if (mwifiex_bss_start(priv, bss, &req_ssid))
return -EFAULT;
if (mode == NL80211_IFTYPE_ADHOC) {
@@ -1262,8 +1162,150 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info,
ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
}
+/*
+ * create a new virtual interface with the given name
+ */
+struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
+ char *name,
+ enum nl80211_iftype type,
+ u32 *flags,
+ struct vif_params *params)
+{
+ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+ struct mwifiex_adapter *adapter;
+ struct net_device *dev;
+ void *mdev_priv;
+
+ if (!priv)
+ return NULL;
+
+ adapter = priv->adapter;
+ if (!adapter)
+ return NULL;
+
+ switch (type) {
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ if (priv->bss_mode) {
+ wiphy_err(wiphy, "cannot create multiple"
+ " station/adhoc interfaces\n");
+ return NULL;
+ }
+
+ if (type == NL80211_IFTYPE_UNSPECIFIED)
+ priv->bss_mode = NL80211_IFTYPE_STATION;
+ else
+ priv->bss_mode = type;
+
+ priv->bss_type = MWIFIEX_BSS_TYPE_STA;
+ priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II;
+ priv->bss_priority = 0;
+ priv->bss_role = MWIFIEX_BSS_ROLE_STA;
+ priv->bss_index = 0;
+ priv->bss_num = 0;
+
+ break;
+ default:
+ wiphy_err(wiphy, "type not supported\n");
+ return NULL;
+ }
+
+ dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), name,
+ ether_setup, 1);
+ if (!dev) {
+ wiphy_err(wiphy, "no memory available for netdevice\n");
+ goto error;
+ }
+
+ dev_net_set(dev, wiphy_net(wiphy));
+ dev->ieee80211_ptr = priv->wdev;
+ dev->ieee80211_ptr->iftype = priv->bss_mode;
+ memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN);
+ memcpy(dev->perm_addr, wiphy->perm_addr, ETH_ALEN);
+ SET_NETDEV_DEV(dev, wiphy_dev(wiphy));
+
+ dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+ dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT;
+ dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN;
+
+ mdev_priv = netdev_priv(dev);
+ *((unsigned long *) mdev_priv) = (unsigned long) priv;
+
+ priv->netdev = dev;
+ mwifiex_init_priv_params(priv, dev);
+
+ SET_NETDEV_DEV(dev, adapter->dev);
+
+ /* Register network device */
+ if (register_netdevice(dev)) {
+ wiphy_err(wiphy, "cannot register virtual network device\n");
+ goto error;
+ }
+
+ sema_init(&priv->async_sem, 1);
+ priv->scan_pending_on_block = false;
+
+ dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name);
+
+#ifdef CONFIG_DEBUG_FS
+ mwifiex_dev_debugfs_init(priv);
+#endif
+ return dev;
+error:
+ if (dev && (dev->reg_state == NETREG_UNREGISTERED))
+ free_netdev(dev);
+ priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf);
+
+/*
+ * del_virtual_intf: remove the virtual interface determined by dev
+ */
+int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev)
+{
+ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+
+ if (!priv || !dev)
+ return 0;
+
+#ifdef CONFIG_DEBUG_FS
+ mwifiex_dev_debugfs_remove(priv);
+#endif
+
+ if (!netif_queue_stopped(priv->netdev))
+ netif_stop_queue(priv->netdev);
+
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+
+ if (dev->reg_state == NETREG_REGISTERED)
+ unregister_netdevice(dev);
+
+ if (dev->reg_state == NETREG_UNREGISTERED)
+ free_netdev(dev);
+
+ /* Clear the priv in adapter */
+ priv->netdev = NULL;
+
+ priv->media_connected = false;
+
+ cancel_work_sync(&priv->cfg_workqueue);
+ flush_workqueue(priv->workqueue);
+ destroy_workqueue(priv->workqueue);
+
+ priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mwifiex_del_virtual_intf);
+
/* station cfg80211 operations */
static struct cfg80211_ops mwifiex_cfg80211_ops = {
+ .add_virtual_intf = mwifiex_add_virtual_intf,
+ .del_virtual_intf = mwifiex_del_virtual_intf,
.change_virtual_intf = mwifiex_cfg80211_change_virtual_intf,
.scan = mwifiex_cfg80211_scan,
.connect = mwifiex_cfg80211_connect,
@@ -1288,8 +1330,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
* default parameters and handler function pointers, and finally
* registers the device.
*/
-int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac,
- struct mwifiex_private *priv)
+int mwifiex_register_cfg80211(struct mwifiex_private *priv)
{
int ret;
void *wdev_priv;
@@ -1329,12 +1370,15 @@ int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac,
wdev->wiphy->cipher_suites = mwifiex_cipher_suites;
wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites);
- memcpy(wdev->wiphy->perm_addr, mac, 6);
+ memcpy(wdev->wiphy->perm_addr, priv->curr_addr, ETH_ALEN);
wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
/* We are using custom domains */
wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+ /* Reserve space for bss band information */
+ wdev->wiphy->bss_priv_size = sizeof(u8);
+
wdev->wiphy->reg_notifier = mwifiex_reg_notifier;
/* Set struct mwifiex_private pointer in wiphy_priv */
@@ -1356,17 +1400,8 @@ int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac,
"info: successfully registered wiphy device\n");
}
- dev_net_set(dev, wiphy_net(wdev->wiphy));
- dev->ieee80211_ptr = wdev;
- memcpy(dev->dev_addr, wdev->wiphy->perm_addr, 6);
- memcpy(dev->perm_addr, wdev->wiphy->perm_addr, 6);
- SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy));
priv->wdev = wdev;
- dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
- dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT;
- dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN;
-
return ret;
}
@@ -1416,13 +1451,8 @@ mwifiex_cfg80211_results(struct work_struct *work)
MWIFIEX_SCAN_TYPE_ACTIVE;
scan_req->chan_list[i].scan_time = 0;
}
- if (mwifiex_set_user_scan_ioctl(priv, scan_req)) {
+ if (mwifiex_set_user_scan_ioctl(priv, scan_req))
ret = -EFAULT;
- goto done;
- }
- if (mwifiex_inform_bss_from_scan_result(priv, NULL))
- ret = -EFAULT;
-done:
priv->scan_result_status = ret;
dev_dbg(priv->adapter->dev, "info: %s: sending scan results\n",
__func__);
diff --git a/drivers/net/wireless/mwifiex/cfg80211.h b/drivers/net/wireless/mwifiex/cfg80211.h
index c4db8f36aa16..8d010f2500c5 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.h
+++ b/drivers/net/wireless/mwifiex/cfg80211.h
@@ -24,8 +24,7 @@
#include "main.h"
-int mwifiex_register_cfg80211(struct net_device *, u8 *,
- struct mwifiex_private *);
+int mwifiex_register_cfg80211(struct mwifiex_private *);
void mwifiex_cfg80211_results(struct work_struct *work);
#endif
diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c
index d0cada5a29a0..f2e6de03805c 100644
--- a/drivers/net/wireless/mwifiex/cfp.c
+++ b/drivers/net/wireless/mwifiex/cfp.c
@@ -48,7 +48,7 @@ static u8 adhoc_rates_bg[BG_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96,
static u8 adhoc_rates_a[A_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24,
0xb0, 0x48, 0x60, 0x6c, 0 };
-u8 supported_rates_a[A_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24,
+static u8 supported_rates_a[A_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24,
0xb0, 0x48, 0x60, 0x6c, 0 };
static u16 mwifiex_data_rates[MWIFIEX_SUPPORTED_RATES_EXT] = { 0x02, 0x04,
0x0B, 0x16, 0x00, 0x0C, 0x12, 0x18,
@@ -57,19 +57,19 @@ static u16 mwifiex_data_rates[MWIFIEX_SUPPORTED_RATES_EXT] = { 0x02, 0x04,
0x75, 0x82, 0x0C, 0x1B, 0x36, 0x51,
0x6C, 0xA2, 0xD8, 0xF3, 0x10E, 0x00 };
-u8 supported_rates_b[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 };
+static u8 supported_rates_b[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 };
-u8 supported_rates_g[G_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24,
+static u8 supported_rates_g[G_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24,
0x30, 0x48, 0x60, 0x6c, 0 };
-u8 supported_rates_bg[BG_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x0c,
+static u8 supported_rates_bg[BG_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x0c,
0x12, 0x16, 0x18, 0x24, 0x30, 0x48,
0x60, 0x6c, 0 };
u16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x10, 0x20, 0x30,
0x32, 0x40, 0x41, 0xff };
-u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 };
+static u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 };
/*
* This function maps an index in supported rates table into
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index b5352afb8714..ac278156d390 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -40,8 +40,12 @@ mwifiex_init_cmd_node(struct mwifiex_private *priv,
{
cmd_node->priv = priv;
cmd_node->cmd_oid = cmd_oid;
- cmd_node->wait_q_enabled = priv->adapter->cmd_wait_q_required;
- priv->adapter->cmd_wait_q_required = false;
+ if (priv->adapter->cmd_wait_q_required) {
+ cmd_node->wait_q_enabled = priv->adapter->cmd_wait_q_required;
+ priv->adapter->cmd_wait_q_required = false;
+ cmd_node->cmd_wait_q_woken = false;
+ cmd_node->condition = &cmd_node->cmd_wait_q_woken;
+ }
cmd_node->data_buf = data_buf;
cmd_node->cmd_skb = cmd_node->skb;
}
@@ -90,8 +94,11 @@ mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter,
cmd_node->data_buf = NULL;
cmd_node->wait_q_enabled = false;
+ if (cmd_node->cmd_skb)
+ skb_trim(cmd_node->cmd_skb, 0);
+
if (cmd_node->resp_skb) {
- dev_kfree_skb_any(cmd_node->resp_skb);
+ adapter->if_ops.cmdrsp_complete(adapter, cmd_node->resp_skb);
cmd_node->resp_skb = NULL;
}
}
@@ -173,8 +180,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
skb_push(cmd_node->cmd_skb, INTF_HEADER_LEN);
ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD,
- cmd_node->cmd_skb->data,
- cmd_node->cmd_skb->len, NULL);
+ cmd_node->cmd_skb, NULL);
skb_pull(cmd_node->cmd_skb, INTF_HEADER_LEN);
@@ -235,8 +241,7 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
skb_push(adapter->sleep_cfm, INTF_HEADER_LEN);
ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD,
- adapter->sleep_cfm->data,
- adapter->sleep_cfm->len, NULL);
+ adapter->sleep_cfm, NULL);
skb_pull(adapter->sleep_cfm, INTF_HEADER_LEN);
if (ret == -1) {
@@ -399,8 +404,7 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter)
adapter->event_cause = 0;
adapter->event_skb = NULL;
-
- dev_kfree_skb_any(skb);
+ adapter->if_ops.event_complete(adapter, skb);
return ret;
}
@@ -418,7 +422,6 @@ int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no,
struct mwifiex_adapter *adapter = priv->adapter;
adapter->cmd_wait_q_required = true;
- adapter->cmd_wait_q.condition = false;
ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid,
data_buf);
@@ -511,10 +514,12 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
}
/* Send command */
- if (cmd_no == HostCmd_CMD_802_11_SCAN)
+ if (cmd_no == HostCmd_CMD_802_11_SCAN) {
mwifiex_queue_scan_cmd(priv, cmd_node);
- else
+ } else {
+ adapter->cmd_queued = cmd_node;
mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
+ }
return ret;
}
@@ -535,7 +540,7 @@ mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
return;
if (cmd_node->wait_q_enabled)
- mwifiex_complete_cmd(adapter);
+ mwifiex_complete_cmd(adapter, cmd_node);
/* Clean the node */
mwifiex_clean_cmd_node(adapter, cmd_node);
@@ -882,7 +887,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
adapter->curr_cmd->wait_q_enabled = false;
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
adapter->cmd_wait_q.status = -1;
- mwifiex_complete_cmd(adapter);
+ mwifiex_complete_cmd(adapter, adapter->curr_cmd);
}
/* Cancel all pending command */
spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
@@ -893,7 +898,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
if (cmd_node->wait_q_enabled) {
adapter->cmd_wait_q.status = -1;
- mwifiex_complete_cmd(adapter);
+ mwifiex_complete_cmd(adapter, cmd_node);
cmd_node->wait_q_enabled = false;
}
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
@@ -976,7 +981,7 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
}
adapter->cmd_wait_q.status = -1;
- mwifiex_complete_cmd(adapter);
+ mwifiex_complete_cmd(adapter, adapter->curr_cmd);
}
/*
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
index 94ddc9038cb3..ae17ce02a3d0 100644
--- a/drivers/net/wireless/mwifiex/decl.h
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -98,7 +98,6 @@ struct mwifiex_802_11_ssid {
struct mwifiex_wait_queue {
wait_queue_head_t wait;
- u16 condition;
int status;
};
@@ -114,14 +113,6 @@ struct mwifiex_txinfo {
u8 bss_index;
};
-struct mwifiex_bss_attr {
- u8 bss_type;
- u8 frame_type;
- u8 active;
- u8 bss_priority;
- u8 bss_num;
-};
-
enum mwifiex_wmm_ac_e {
WMM_AC_BK,
WMM_AC_BE,
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 4fee0993b186..0cc5d73cb0c1 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -57,12 +57,6 @@ struct tx_packet_hdr {
#define GET_FW_DEFAULT_BANDS(adapter) \
((adapter->fw_cap_info >> 8) & ALL_802_11_BANDS)
-extern u8 supported_rates_b[B_SUPPORTED_RATES];
-extern u8 supported_rates_g[G_SUPPORTED_RATES];
-extern u8 supported_rates_bg[BG_SUPPORTED_RATES];
-extern u8 supported_rates_a[A_SUPPORTED_RATES];
-extern u8 supported_rates_n[N_SUPPORTED_RATES];
-
#define HostCmd_WEP_KEY_INDEX_MASK 0x3fff
#define KEY_INFO_ENABLED 0x01
@@ -84,7 +78,8 @@ enum KEY_TYPE_ID {
#define MAX_FIRMWARE_POLL_TRIES 100
-#define FIRMWARE_READY 0xfedc
+#define FIRMWARE_READY_SDIO 0xfedc
+#define FIRMWARE_READY_PCIE 0xfedcba00
enum MWIFIEX_802_11_PRIVACY_FILTER {
MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL,
@@ -221,7 +216,7 @@ enum MWIFIEX_802_11_WEP_STATUS {
#define HostCmd_CMD_802_11_HS_CFG_ENH 0x00e5
#define HostCmd_CMD_CAU_REG_ACCESS 0x00ed
#define HostCmd_CMD_SET_BSS_MODE 0x00f7
-
+#define HostCmd_CMD_PCIE_DESC_DETAILS 0x00fa
enum ENH_PS_MODES {
EN_PS = 1,
@@ -821,6 +816,14 @@ struct host_cmd_ds_txpwr_cfg {
__le32 mode;
} __packed;
+struct mwifiex_bcn_param {
+ u8 bssid[ETH_ALEN];
+ u8 rssi;
+ __le32 timestamp[2];
+ __le16 beacon_period;
+ __le16 cap_info_bitmap;
+} __packed;
+
#define MWIFIEX_USER_SCAN_CHAN_MAX 50
#define MWIFIEX_MAX_SSID_LIST_LENGTH 10
@@ -862,13 +865,6 @@ struct mwifiex_user_scan_ssid {
struct mwifiex_user_scan_cfg {
/*
- * Flag set to keep the previous scan table intact
- *
- * If set, the scan results will accumulate, replacing any previous
- * matched entries for a BSS with the new scan data
- */
- u8 keep_previous_scan;
- /*
* BSS mode to be sent in the firmware command
*/
u8 bss_mode;
@@ -1136,6 +1132,30 @@ struct host_cmd_ds_set_bss_mode {
u8 con_type;
} __packed;
+struct host_cmd_ds_pcie_details {
+ /* TX buffer descriptor ring address */
+ u32 txbd_addr_lo;
+ u32 txbd_addr_hi;
+ /* TX buffer descriptor ring count */
+ u32 txbd_count;
+
+ /* RX buffer descriptor ring address */
+ u32 rxbd_addr_lo;
+ u32 rxbd_addr_hi;
+ /* RX buffer descriptor ring count */
+ u32 rxbd_count;
+
+ /* Event buffer descriptor ring address */
+ u32 evtbd_addr_lo;
+ u32 evtbd_addr_hi;
+ /* Event buffer descriptor ring count */
+ u32 evtbd_count;
+
+ /* Sleep cookie buffer physical address */
+ u32 sleep_cookie_addr_lo;
+ u32 sleep_cookie_addr_hi;
+} __packed;
+
struct host_cmd_ds_command {
__le16 command;
__le16 size;
@@ -1183,6 +1203,7 @@ struct host_cmd_ds_command {
struct host_cmd_ds_rf_reg_access rf_reg;
struct host_cmd_ds_pmic_reg_access pmic_reg;
struct host_cmd_ds_set_bss_mode bss_mode;
+ struct host_cmd_ds_pcie_details pcie_host_spec;
struct host_cmd_ds_802_11_eeprom_access eeprom;
} params;
} __packed;
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index 3f1559e61320..d792b3fb7c16 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -76,7 +76,7 @@ static int mwifiex_init_priv(struct mwifiex_private *priv)
memset(priv->curr_addr, 0xff, ETH_ALEN);
priv->pkt_tx_ctrl = 0;
- priv->bss_mode = NL80211_IFTYPE_STATION;
+ priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
priv->data_rate = 0; /* Initially indicate the rate as auto */
priv->is_data_rate_auto = true;
priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
@@ -152,19 +152,6 @@ static int mwifiex_init_priv(struct mwifiex_private *priv)
static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter)
{
int ret;
- u32 buf_size;
- struct mwifiex_bssdescriptor *temp_scan_table;
-
- /* Allocate buffer to store the BSSID list */
- buf_size = sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP;
- temp_scan_table = kzalloc(buf_size, GFP_KERNEL);
- if (!temp_scan_table) {
- dev_err(adapter->dev, "%s: failed to alloc temp_scan_table\n",
- __func__);
- return -ENOMEM;
- }
-
- adapter->scan_table = temp_scan_table;
/* Allocate command buffer */
ret = mwifiex_alloc_cmd_buffer(adapter);
@@ -204,7 +191,12 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
(adapter->sleep_cfm->data);
adapter->cmd_sent = false;
- adapter->data_sent = true;
+
+ if (adapter->iface_type == MWIFIEX_PCIE)
+ adapter->data_sent = false;
+ else
+ adapter->data_sent = true;
+
adapter->cmd_resp_received = false;
adapter->event_received = false;
adapter->data_received = false;
@@ -222,14 +214,8 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
adapter->active_scan_time = MWIFIEX_ACTIVE_SCAN_CHAN_TIME;
adapter->passive_scan_time = MWIFIEX_PASSIVE_SCAN_CHAN_TIME;
- adapter->num_in_scan_table = 0;
- memset(adapter->scan_table, 0,
- (sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP));
adapter->scan_probes = 1;
- memset(adapter->bcn_buf, 0, sizeof(adapter->bcn_buf));
- adapter->bcn_buf_end = adapter->bcn_buf;
-
adapter->multiple_dtim = 1;
adapter->local_listen_interval = 0; /* default value in firmware
@@ -297,6 +283,34 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
}
/*
+ * This function releases the lock variables and frees the locks and
+ * associated locks.
+ */
+static void mwifiex_free_lock_list(struct mwifiex_adapter *adapter)
+{
+ struct mwifiex_private *priv;
+ s32 i, j;
+
+ /* Free lists */
+ list_del(&adapter->cmd_free_q);
+ list_del(&adapter->cmd_pending_q);
+ list_del(&adapter->scan_pending_q);
+
+ for (i = 0; i < adapter->priv_num; i++)
+ list_del(&adapter->bss_prio_tbl[i].bss_prio_head);
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (adapter->priv[i]) {
+ priv = adapter->priv[i];
+ for (j = 0; j < MAX_NUM_TID; ++j)
+ list_del(&priv->wmm.tid_tbl_ptr[j].ra_list);
+ list_del(&priv->tx_ba_stream_tbl_ptr);
+ list_del(&priv->rx_reorder_tbl_ptr);
+ }
+ }
+}
+
+/*
* This function frees the adapter structure.
*
* The freeing operation is done recursively, by canceling all
@@ -326,8 +340,6 @@ mwifiex_free_adapter(struct mwifiex_adapter *adapter)
del_timer(&adapter->cmd_timer);
dev_dbg(adapter->dev, "info: free scan table\n");
- kfree(adapter->scan_table);
- adapter->scan_table = NULL;
adapter->if_ops.cleanup_if(adapter);
@@ -392,34 +404,6 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
}
/*
- * This function releases the lock variables and frees the locks and
- * associated locks.
- */
-void mwifiex_free_lock_list(struct mwifiex_adapter *adapter)
-{
- struct mwifiex_private *priv;
- s32 i, j;
-
- /* Free lists */
- list_del(&adapter->cmd_free_q);
- list_del(&adapter->cmd_pending_q);
- list_del(&adapter->scan_pending_q);
-
- for (i = 0; i < adapter->priv_num; i++)
- list_del(&adapter->bss_prio_tbl[i].bss_prio_head);
-
- for (i = 0; i < adapter->priv_num; i++) {
- if (adapter->priv[i]) {
- priv = adapter->priv[i];
- for (j = 0; j < MAX_NUM_TID; ++j)
- list_del(&priv->wmm.tid_tbl_ptr[j].ra_list);
- list_del(&priv->tx_ba_stream_tbl_ptr);
- list_del(&priv->rx_reorder_tbl_ptr);
- }
- }
-}
-
-/*
* This function initializes the firmware.
*
* The following operations are performed sequentially -
@@ -602,11 +586,13 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
struct mwifiex_fw_image *pmfw)
{
- int ret, winner;
+ int ret;
u32 poll_num = 1;
+ adapter->winner = 0;
+
/* Check if firmware is already running */
- ret = adapter->if_ops.check_fw_status(adapter, poll_num, &winner);
+ ret = adapter->if_ops.check_fw_status(adapter, poll_num);
if (!ret) {
dev_notice(adapter->dev,
"WLAN FW already running! Skip FW download\n");
@@ -615,7 +601,7 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
poll_num = MAX_FIRMWARE_POLL_TRIES;
/* Check if we are the winner for downloading FW */
- if (!winner) {
+ if (!adapter->winner) {
dev_notice(adapter->dev,
"Other interface already running!"
" Skip FW download\n");
@@ -633,7 +619,7 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
poll_fw:
/* Check if the firmware is downloaded successfully or not */
- ret = adapter->if_ops.check_fw_status(adapter, poll_num, NULL);
+ ret = adapter->if_ops.check_fw_status(adapter, poll_num);
if (ret) {
dev_err(adapter->dev, "FW failed to be active in time\n");
return -1;
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h
index f6bcc868562f..e0b68e7c8ca2 100644
--- a/drivers/net/wireless/mwifiex/ioctl.h
+++ b/drivers/net/wireless/mwifiex/ioctl.h
@@ -134,7 +134,6 @@ struct mwifiex_ver_ext {
struct mwifiex_bss_info {
u32 bss_mode;
struct mwifiex_802_11_ssid ssid;
- u32 scan_table_idx;
u32 bss_chan;
u32 region_code;
u32 media_connected;
@@ -307,10 +306,12 @@ struct mwifiex_ds_read_eeprom {
u8 value[MAX_EEPROM_DATA];
};
+#define IEEE_MAX_IE_SIZE 256
+
struct mwifiex_ds_misc_gen_ie {
u32 type;
u32 len;
- u8 ie_data[IW_CUSTOM_MAX];
+ u8 ie_data[IEEE_MAX_IE_SIZE];
};
struct mwifiex_ds_misc_cmd {
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
index 644e2e405cb5..62b4c2938608 100644
--- a/drivers/net/wireless/mwifiex/join.c
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -147,13 +147,12 @@ static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1,
u8 *ptr = rate1, *tmp;
u32 i, j;
- tmp = kmalloc(rate1_size, GFP_KERNEL);
+ tmp = kmemdup(rate1, rate1_size, GFP_KERNEL);
if (!tmp) {
dev_err(priv->adapter->dev, "failed to alloc tmp buf\n");
return -ENOMEM;
}
- memcpy(tmp, rate1, rate1_size);
memset(rate1, 0, rate1_size);
for (i = 0; rate2[i] && i < rate2_size; i++) {
@@ -224,32 +223,6 @@ mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv,
}
/*
- * This function updates the scan entry TSF timestamps to reflect
- * a new association.
- */
-static void
-mwifiex_update_tsf_timestamps(struct mwifiex_private *priv,
- struct mwifiex_bssdescriptor *new_bss_desc)
-{
- struct mwifiex_adapter *adapter = priv->adapter;
- u32 table_idx;
- long long new_tsf_base;
- signed long long tsf_delta;
-
- memcpy(&new_tsf_base, new_bss_desc->time_stamp, sizeof(new_tsf_base));
-
- tsf_delta = new_tsf_base - new_bss_desc->network_tsf;
-
- dev_dbg(adapter->dev, "info: TSF: update TSF timestamps, "
- "0x%016llx -> 0x%016llx\n",
- new_bss_desc->network_tsf, new_tsf_base);
-
- for (table_idx = 0; table_idx < adapter->num_in_scan_table;
- table_idx++)
- adapter->scan_table[table_idx].network_tsf += tsf_delta;
-}
-
-/*
* This function appends a WAPI IE.
*
* This function is called from the network join command preparation routine.
@@ -639,12 +612,6 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
priv->curr_bss_params.band = (u8) bss_desc->bss_band;
- /*
- * Adjust the timestamps in the scan table to be relative to the newly
- * associated AP's TSF
- */
- mwifiex_update_tsf_timestamps(priv, bss_desc);
-
if (bss_desc->wmm_ie.vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC)
priv->curr_bss_params.wmm_enabled = true;
else
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index e5fc53dc6887..67e6db7d672d 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -26,21 +26,6 @@
const char driver_version[] = "mwifiex " VERSION " (%s) ";
-static struct mwifiex_bss_attr mwifiex_bss_sta[] = {
- {MWIFIEX_BSS_TYPE_STA, MWIFIEX_DATA_FRAME_TYPE_ETH_II, true, 0, 0},
-};
-
-static int drv_mode = DRV_MODE_STA;
-
-/* Supported drv_mode table */
-static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = {
- {
- .drv_mode = DRV_MODE_STA,
- .intf_num = ARRAY_SIZE(mwifiex_bss_sta),
- .bss_attr = mwifiex_bss_sta,
- },
-};
-
/*
* This function registers the device and performs all the necessary
* initializations.
@@ -57,7 +42,6 @@ static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = {
* proper cleanup before exiting.
*/
static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
- struct mwifiex_drv_mode *drv_mode_ptr,
void **padapter)
{
struct mwifiex_adapter *adapter;
@@ -78,44 +62,20 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
goto error;
adapter->priv_num = 0;
- for (i = 0; i < drv_mode_ptr->intf_num; i++) {
- adapter->priv[i] = NULL;
-
- if (!drv_mode_ptr->bss_attr[i].active)
- continue;
- /* Allocate memory for private structure */
- adapter->priv[i] = kzalloc(sizeof(struct mwifiex_private),
- GFP_KERNEL);
- if (!adapter->priv[i]) {
- dev_err(adapter->dev, "%s: failed to alloc priv[%d]\n",
- __func__, i);
- goto error;
- }
-
- adapter->priv_num++;
- adapter->priv[i]->adapter = adapter;
- /* Save bss_type, frame_type & bss_priority */
- adapter->priv[i]->bss_type = drv_mode_ptr->bss_attr[i].bss_type;
- adapter->priv[i]->frame_type =
- drv_mode_ptr->bss_attr[i].frame_type;
- adapter->priv[i]->bss_priority =
- drv_mode_ptr->bss_attr[i].bss_priority;
-
- if (drv_mode_ptr->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_STA)
- adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_STA;
- else if (drv_mode_ptr->bss_attr[i].bss_type ==
- MWIFIEX_BSS_TYPE_UAP)
- adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_UAP;
-
- /* Save bss_index & bss_num */
- adapter->priv[i]->bss_index = i;
- adapter->priv[i]->bss_num = drv_mode_ptr->bss_attr[i].bss_num;
+ /* Allocate memory for private structure */
+ adapter->priv[0] = kzalloc(sizeof(struct mwifiex_private),
+ GFP_KERNEL);
+ if (!adapter->priv[0]) {
+ dev_err(adapter->dev, "%s: failed to alloc priv[0]\n",
+ __func__);
+ goto error;
}
- adapter->drv_mode = drv_mode_ptr;
- if (mwifiex_init_lock_list(adapter))
- goto error;
+ adapter->priv_num++;
+
+ adapter->priv[0]->adapter = adapter;
+ mwifiex_init_lock_list(adapter);
init_timer(&adapter->cmd_timer);
adapter->cmd_timer.function = mwifiex_cmd_timeout_func;
@@ -126,9 +86,9 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
error:
dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n");
- mwifiex_free_lock_list(adapter);
- for (i = 0; i < drv_mode_ptr->intf_num; i++)
+ for (i = 0; i < adapter->priv_num; i++)
kfree(adapter->priv[i]);
+
kfree(adapter);
return -1;
@@ -316,38 +276,6 @@ exit_main_proc:
}
/*
- * This function initializes the software.
- *
- * The main work includes allocating and initializing the adapter structure
- * and initializing the private structures.
- */
-static int
-mwifiex_init_sw(void *card, struct mwifiex_if_ops *if_ops, void **padapter)
-{
- int i;
- struct mwifiex_drv_mode *drv_mode_ptr;
-
- /* find mwifiex_drv_mode entry from mwifiex_drv_mode_tbl */
- drv_mode_ptr = NULL;
- for (i = 0; i < ARRAY_SIZE(mwifiex_drv_mode_tbl); i++) {
- if (mwifiex_drv_mode_tbl[i].drv_mode == drv_mode) {
- drv_mode_ptr = &mwifiex_drv_mode_tbl[i];
- break;
- }
- }
-
- if (!drv_mode_ptr) {
- pr_err("invalid drv_mode=%d\n", drv_mode);
- return -1;
- }
-
- if (mwifiex_register(card, if_ops, drv_mode_ptr, padapter))
- return -1;
-
- return 0;
-}
-
-/*
* This function frees the adapter structure.
*
* Additionally, this closes the netlink socket, frees the timers
@@ -627,7 +555,7 @@ static const struct net_device_ops mwifiex_netdev_ops = {
.ndo_set_mac_address = mwifiex_set_mac_address,
.ndo_tx_timeout = mwifiex_tx_timeout,
.ndo_get_stats = mwifiex_get_stats,
- .ndo_set_multicast_list = mwifiex_set_multicast_list,
+ .ndo_set_rx_mode = mwifiex_set_multicast_list,
};
/*
@@ -649,8 +577,8 @@ static const struct net_device_ops mwifiex_netdev_ops = {
*
* In addition, the CFG80211 work queue is also created.
*/
-static void
-mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev)
+void mwifiex_init_priv_params(struct mwifiex_private *priv,
+ struct net_device *dev)
{
dev->netdev_ops = &mwifiex_netdev_ops;
/* Initialize private structure */
@@ -664,118 +592,6 @@ mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev)
}
/*
- * This function adds a new logical interface.
- *
- * It allocates, initializes and registers the interface by performing
- * the following opearations -
- * - Allocate a new net device structure
- * - Assign device name
- * - Register the new device with CFG80211 subsystem
- * - Initialize semaphore and private structure
- * - Register the new device with kernel
- * - Create the complete debug FS structure if configured
- */
-static struct mwifiex_private *mwifiex_add_interface(
- struct mwifiex_adapter *adapter,
- u8 bss_index, u8 bss_type)
-{
- struct net_device *dev;
- struct mwifiex_private *priv;
- void *mdev_priv;
-
- dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), "mlan%d",
- ether_setup, 1);
- if (!dev) {
- dev_err(adapter->dev, "no memory available for netdevice\n");
- goto error;
- }
-
- if (mwifiex_register_cfg80211(dev, adapter->priv[bss_index]->curr_addr,
- adapter->priv[bss_index]) != 0) {
- dev_err(adapter->dev, "cannot register netdevice with cfg80211\n");
- goto error;
- }
- /* Save the priv pointer in netdev */
- priv = adapter->priv[bss_index];
- mdev_priv = netdev_priv(dev);
- *((unsigned long *) mdev_priv) = (unsigned long) priv;
-
- priv->netdev = dev;
-
- sema_init(&priv->async_sem, 1);
- priv->scan_pending_on_block = false;
-
- mwifiex_init_priv_params(priv, dev);
-
- SET_NETDEV_DEV(dev, adapter->dev);
-
- /* Register network device */
- if (register_netdev(dev)) {
- dev_err(adapter->dev, "cannot register virtual network device\n");
- goto error;
- }
-
- dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name);
-#ifdef CONFIG_DEBUG_FS
- mwifiex_dev_debugfs_init(priv);
-#endif
- return priv;
-error:
- if (dev)
- free_netdev(dev);
- return NULL;
-}
-
-/*
- * This function removes a logical interface.
- *
- * It deregisters, resets and frees the interface by performing
- * the following operations -
- * - Disconnect the device if connected, send wireless event to
- * notify applications.
- * - Remove the debug FS structure if configured
- * - Unregister the device from kernel
- * - Free the net device structure
- * - Cancel all works and destroy work queue
- * - Unregister and free the wireless device from CFG80211 subsystem
- */
-static void
-mwifiex_remove_interface(struct mwifiex_adapter *adapter, u8 bss_index)
-{
- struct net_device *dev;
- struct mwifiex_private *priv = adapter->priv[bss_index];
-
- if (!priv)
- return;
- dev = priv->netdev;
-
- if (priv->media_connected)
- priv->media_connected = false;
-
-#ifdef CONFIG_DEBUG_FS
- mwifiex_dev_debugfs_remove(priv);
-#endif
- /* Last reference is our one */
- dev_dbg(adapter->dev, "info: %s: refcnt = %d\n",
- dev->name, netdev_refcnt_read(dev));
-
- if (dev->reg_state == NETREG_REGISTERED)
- unregister_netdev(dev);
-
- /* Clear the priv in adapter */
- priv->netdev = NULL;
- if (dev)
- free_netdev(dev);
-
- cancel_work_sync(&priv->cfg_workqueue);
- flush_workqueue(priv->workqueue);
- destroy_workqueue(priv->workqueue);
- wiphy_unregister(priv->wdev->wiphy);
- wiphy_free(priv->wdev->wiphy);
- kfree(priv->wdev);
-}
-
-/*
* This function check if command is pending.
*/
int is_command_pending(struct mwifiex_adapter *adapter)
@@ -845,19 +661,22 @@ mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter)
*/
int
mwifiex_add_card(void *card, struct semaphore *sem,
- struct mwifiex_if_ops *if_ops)
+ struct mwifiex_if_ops *if_ops, u8 iface_type)
{
- int i;
struct mwifiex_adapter *adapter;
+ char fmt[64];
+ struct mwifiex_private *priv;
if (down_interruptible(sem))
goto exit_sem_err;
- if (mwifiex_init_sw(card, if_ops, (void **)&adapter)) {
+ if (mwifiex_register(card, if_ops, (void **)&adapter)) {
pr_err("%s: software init failed\n", __func__);
goto err_init_sw;
}
+ adapter->iface_type = iface_type;
+
adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
adapter->surprise_removed = false;
init_waitqueue_head(&adapter->init_wait_q);
@@ -866,8 +685,8 @@ mwifiex_add_card(void *card, struct semaphore *sem,
init_waitqueue_head(&adapter->hs_activate_wait_q);
adapter->cmd_wait_q_required = false;
init_waitqueue_head(&adapter->cmd_wait_q.wait);
- adapter->cmd_wait_q.condition = false;
adapter->cmd_wait_q.status = 0;
+ adapter->scan_wait_q_woken = false;
adapter->workqueue = create_workqueue("MWIFIEX_WORK_QUEUE");
if (!adapter->workqueue)
@@ -887,21 +706,37 @@ mwifiex_add_card(void *card, struct semaphore *sem,
goto err_init_fw;
}
- /* Add interfaces */
- for (i = 0; i < adapter->drv_mode->intf_num; i++) {
- if (!mwifiex_add_interface(adapter, i,
- adapter->drv_mode->bss_attr[i].bss_type)) {
- goto err_add_intf;
- }
+ priv = adapter->priv[0];
+
+ if (mwifiex_register_cfg80211(priv) != 0) {
+ dev_err(adapter->dev, "cannot register netdevice"
+ " with cfg80211\n");
+ goto err_init_fw;
}
+ rtnl_lock();
+ /* Create station interface by default */
+ if (!mwifiex_add_virtual_intf(priv->wdev->wiphy, "mlan%d",
+ NL80211_IFTYPE_STATION, NULL, NULL)) {
+ rtnl_unlock();
+ dev_err(adapter->dev, "cannot create default station"
+ " interface\n");
+ goto err_add_intf;
+ }
+
+ rtnl_unlock();
+
up(sem);
+ mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1);
+ dev_notice(adapter->dev, "driver_version = %s\n", fmt);
+
return 0;
err_add_intf:
- for (i = 0; i < adapter->priv_num; i++)
- mwifiex_remove_interface(adapter, i);
+ rtnl_lock();
+ mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev);
+ rtnl_unlock();
err_init_fw:
pr_debug("info: %s: unregister device\n", __func__);
adapter->if_ops.unregister_dev(adapter);
@@ -956,7 +791,7 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
/* Stop data */
for (i = 0; i < adapter->priv_num; i++) {
priv = adapter->priv[i];
- if (priv) {
+ if (priv && priv->netdev) {
if (!netif_queue_stopped(priv->netdev))
netif_stop_queue(priv->netdev);
if (netif_carrier_ok(priv->netdev))
@@ -981,9 +816,24 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
atomic_read(&adapter->cmd_pending));
}
- /* Remove interface */
- for (i = 0; i < adapter->priv_num; i++)
- mwifiex_remove_interface(adapter, i);
+ for (i = 0; i < adapter->priv_num; i++) {
+ priv = adapter->priv[i];
+
+ if (!priv)
+ continue;
+
+ rtnl_lock();
+ mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev);
+ rtnl_unlock();
+ }
+
+ priv = adapter->priv[0];
+ if (!priv)
+ goto exit_remove;
+
+ wiphy_unregister(priv->wdev->wiphy);
+ wiphy_free(priv->wdev->wiphy);
+ kfree(priv->wdev);
mwifiex_terminate_workqueue(adapter);
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 2215c3c97354..30f138b6fa4c 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -37,6 +37,7 @@
#include "ioctl.h"
#include "util.h"
#include "fw.h"
+#include "pcie.h"
extern const char driver_version[];
@@ -45,14 +46,7 @@ enum {
MWIFIEX_SYNC_CMD
};
-#define DRV_MODE_STA 0x1
-
-struct mwifiex_drv_mode {
- u16 drv_mode;
- u16 intf_num;
- struct mwifiex_bss_attr *bss_attr;
-};
-
+#define MWIFIEX_MAX_AP 64
#define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ)
@@ -114,6 +108,8 @@ struct mwifiex_drv_mode {
#define MAX_FREQUENCY_BAND_BG 2484
+#define MWIFIEX_EVENT_HEADER_LEN 4
+
struct mwifiex_dbg {
u32 num_cmd_host_to_card_failure;
u32 num_cmd_sleep_cfm_host_to_card_failure;
@@ -163,6 +159,11 @@ enum MWIFIEX_PS_STATE {
PS_STATE_SLEEP
};
+enum mwifiex_iface_type {
+ MWIFIEX_SDIO,
+ MWIFIEX_PCIE,
+};
+
struct mwifiex_add_ba_param {
u32 tx_win_size;
u32 rx_win_size;
@@ -180,7 +181,6 @@ struct mwifiex_ra_list_tbl {
struct sk_buff_head skb_head;
u8 ra[ETH_ALEN];
u32 total_pkts_size;
- u32 total_pkts;
u32 is_11n_enabled;
};
@@ -227,27 +227,10 @@ struct ieee_types_header {
u8 len;
} __packed;
-struct ieee_obss_scan_param {
- u16 obss_scan_passive_dwell;
- u16 obss_scan_active_dwell;
- u16 bss_chan_width_trigger_scan_int;
- u16 obss_scan_passive_total;
- u16 obss_scan_active_total;
- u16 bss_width_chan_trans_delay;
- u16 obss_scan_active_threshold;
-} __packed;
-
-struct ieee_types_obss_scan_param {
- struct ieee_types_header ieee_hdr;
- struct ieee_obss_scan_param obss_scan;
-} __packed;
-
#define MWIFIEX_SUPPORTED_RATES 14
#define MWIFIEX_SUPPORTED_RATES_EXT 32
-#define IEEE_MAX_IE_SIZE 256
-
struct ieee_types_vendor_specific {
struct ieee_types_vendor_header vend_hdr;
u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_vendor_header)];
@@ -291,8 +274,6 @@ struct mwifiex_bssdescriptor {
u16 bss_co_2040_offset;
u8 *bcn_ext_cap;
u16 ext_cap_offset;
- struct ieee_types_obss_scan_param *bcn_obss_scan;
- u16 overlap_bss_offset;
struct ieee_types_vendor_specific *bcn_wpa_ie;
u16 wpa_offset;
struct ieee_types_generic *bcn_rsn_ie;
@@ -301,8 +282,6 @@ struct mwifiex_bssdescriptor {
u16 wapi_offset;
u8 *beacon_buf;
u32 beacon_buf_size;
- u32 beacon_buf_size_max;
-
};
struct mwifiex_current_bss_params {
@@ -468,7 +447,7 @@ struct mwifiex_private {
struct dentry *dfs_dev_dir;
#endif
u8 nick_name[16];
- struct iw_statistics w_stats;
+ u8 qual_level, qual_noise;
u16 current_key_index;
struct semaphore async_sem;
u8 scan_pending_on_block;
@@ -541,33 +520,38 @@ struct cmd_ctrl_node {
void *data_buf;
u32 wait_q_enabled;
struct sk_buff *skb;
+ u8 *condition;
+ u8 cmd_wait_q_woken;
};
struct mwifiex_if_ops {
int (*init_if) (struct mwifiex_adapter *);
void (*cleanup_if) (struct mwifiex_adapter *);
- int (*check_fw_status) (struct mwifiex_adapter *, u32, int *);
+ int (*check_fw_status) (struct mwifiex_adapter *, u32);
int (*prog_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *);
int (*register_dev) (struct mwifiex_adapter *);
void (*unregister_dev) (struct mwifiex_adapter *);
int (*enable_int) (struct mwifiex_adapter *);
int (*process_int_status) (struct mwifiex_adapter *);
- int (*host_to_card) (struct mwifiex_adapter *, u8,
- u8 *payload, u32 pkt_len,
+ int (*host_to_card) (struct mwifiex_adapter *, u8, struct sk_buff *,
struct mwifiex_tx_param *);
int (*wakeup) (struct mwifiex_adapter *);
int (*wakeup_complete) (struct mwifiex_adapter *);
+ /* Interface specific functions */
void (*update_mp_end_port) (struct mwifiex_adapter *, u16);
void (*cleanup_mpa_buf) (struct mwifiex_adapter *);
+ int (*cmdrsp_complete) (struct mwifiex_adapter *, struct sk_buff *);
+ int (*event_complete) (struct mwifiex_adapter *, struct sk_buff *);
};
struct mwifiex_adapter {
+ u8 iface_type;
struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM];
u8 priv_num;
- struct mwifiex_drv_mode *drv_mode;
const struct firmware *firmware;
char fw_name[32];
+ int winner;
struct device *dev;
bool surprise_removed;
u32 fw_release_number;
@@ -624,15 +608,11 @@ struct mwifiex_adapter {
u32 scan_processing;
u16 region_code;
struct mwifiex_802_11d_domain_reg domain_reg;
- struct mwifiex_bssdescriptor *scan_table;
- u32 num_in_scan_table;
u16 scan_probes;
u32 scan_mode;
u16 specific_scan_time;
u16 active_scan_time;
u16 passive_scan_time;
- u8 bcn_buf[MAX_SCAN_BEACON_BUFFER];
- u8 *bcn_buf_end;
u8 fw_bands;
u8 adhoc_start_band;
u8 config_bands;
@@ -673,10 +653,11 @@ struct mwifiex_adapter {
u32 arp_filter_size;
u16 cmd_wait_q_required;
struct mwifiex_wait_queue cmd_wait_q;
+ u8 scan_wait_q_woken;
+ struct cmd_ctrl_node *cmd_queued;
};
int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
-void mwifiex_free_lock_list(struct mwifiex_adapter *adapter);
int mwifiex_init_fw(struct mwifiex_adapter *adapter);
@@ -692,7 +673,8 @@ int mwifiex_recv_packet(struct mwifiex_adapter *, struct sk_buff *skb);
int mwifiex_process_event(struct mwifiex_adapter *adapter);
-int mwifiex_complete_cmd(struct mwifiex_adapter *adapter);
+int mwifiex_complete_cmd(struct mwifiex_adapter *adapter,
+ struct cmd_ctrl_node *cmd_node);
int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
u16 cmd_action, u32 cmd_oid, void *data_buf);
@@ -726,8 +708,6 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags);
int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
struct sk_buff *skb, int status);
-int mwifiex_recv_packet_complete(struct mwifiex_adapter *,
- struct sk_buff *skb, int status);
void mwifiex_clean_txrx(struct mwifiex_private *priv);
u8 mwifiex_check_last_packet_indication(struct mwifiex_private *priv);
void mwifiex_check_ps_cond(struct mwifiex_adapter *adapter);
@@ -757,21 +737,12 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *,
int mwifiex_process_sta_event(struct mwifiex_private *);
void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb);
int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta);
-int mwifiex_scan_networks(struct mwifiex_private *priv,
- const struct mwifiex_user_scan_cfg *user_scan_in);
int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd,
struct mwifiex_scan_cmd_config *scan_cfg);
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_find_ssid_in_list(struct mwifiex_private *priv,
- struct mwifiex_802_11_ssid *ssid, u8 *bssid,
- u32 mode);
-s32 mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid,
- u32 mode);
-int mwifiex_find_best_network(struct mwifiex_private *priv,
- struct mwifiex_ssid_bssid *req_ssid_bssid);
s32 mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1,
struct mwifiex_802_11_ssid *ssid2);
int mwifiex_associate(struct mwifiex_private *priv,
@@ -782,7 +753,6 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
struct host_cmd_ds_command *resp);
void mwifiex_reset_connect_state(struct mwifiex_private *priv);
-void mwifiex_2040_coex_event(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,
@@ -823,6 +793,8 @@ int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv,
int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
struct host_cmd_ds_command *resp);
int is_command_pending(struct mwifiex_adapter *adapter);
+void mwifiex_init_priv_params(struct mwifiex_private *priv,
+ struct net_device *dev);
/*
* This function checks if the queuing is RA based or not.
@@ -912,7 +884,7 @@ struct mwifiex_private *mwifiex_bss_index_to_priv(struct mwifiex_adapter
*adapter, u8 bss_index);
int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
u32 func_init_shutdown);
-int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *);
+int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8);
int mwifiex_remove_card(struct mwifiex_adapter *, struct semaphore *);
void mwifiex_get_version(struct mwifiex_adapter *adapter, char *version,
@@ -922,11 +894,8 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
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 mwifiex_ssid_bssid *ssid_bssid);
-int mwifiex_set_hs_params(struct mwifiex_private *priv,
- u16 action, int cmd_type,
- struct mwifiex_ds_hs_cfg *hscfg);
+int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
+ struct mwifiex_802_11_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);
@@ -934,8 +903,6 @@ int mwifiex_get_signal_info(struct mwifiex_private *priv,
struct mwifiex_ds_get_signal *signal);
int mwifiex_drv_get_data_rate(struct mwifiex_private *priv,
struct mwifiex_rate_cfg *rate);
-int mwifiex_find_best_bss(struct mwifiex_private *priv,
- struct mwifiex_ssid_bssid *ssid_bssid);
int mwifiex_request_scan(struct mwifiex_private *priv,
struct mwifiex_802_11_ssid *req_ssid);
int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv,
@@ -984,12 +951,26 @@ int mwifiex_main_process(struct mwifiex_adapter *);
int mwifiex_bss_set_channel(struct mwifiex_private *,
struct mwifiex_chan_freq_power *cfp);
-int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *,
- struct mwifiex_ssid_bssid *);
int mwifiex_set_radio_band_cfg(struct mwifiex_private *,
struct mwifiex_ds_band_cfg *);
int mwifiex_get_bss_info(struct mwifiex_private *,
struct mwifiex_bss_info *);
+int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
+ u8 *bssid, s32 rssi, u8 *ie_buf,
+ size_t ie_len, u16 beacon_period,
+ u16 cap_info_bitmap, u8 band,
+ struct mwifiex_bssdescriptor *bss_desc);
+int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
+ struct mwifiex_bssdescriptor *bss_entry,
+ u8 *ie_buf, u32 ie_len);
+int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
+ struct mwifiex_bssdescriptor *bss_desc);
+
+struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
+ char *name, enum nl80211_iftype type,
+ u32 *flags, struct vif_params *params);
+int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev);
+
#ifdef CONFIG_DEBUG_FS
void mwifiex_debugfs_init(void);
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c
new file mode 100644
index 000000000000..d34acf082d3a
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/pcie.c
@@ -0,0 +1,1948 @@
+/*
+ * Marvell Wireless LAN device driver: PCIE specific handling
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include <linux/firmware.h>
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+#include "pcie.h"
+
+#define PCIE_VERSION "1.0"
+#define DRV_NAME "Marvell mwifiex PCIe"
+
+static u8 user_rmmod;
+
+static struct mwifiex_if_ops pcie_ops;
+
+static struct semaphore add_remove_card_sem;
+static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter);
+static int mwifiex_pcie_resume(struct pci_dev *pdev);
+
+/*
+ * This function is called after skb allocation to update
+ * "skb->cb" with physical address of data pointer.
+ */
+static phys_addr_t *mwifiex_update_sk_buff_pa(struct sk_buff *skb)
+{
+ phys_addr_t *buf_pa = MWIFIEX_SKB_PACB(skb);
+
+ *buf_pa = (phys_addr_t)virt_to_phys(skb->data);
+
+ return buf_pa;
+}
+
+/*
+ * This function reads sleep cookie and checks if FW is ready
+ */
+static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter)
+{
+ u32 *cookie_addr;
+ struct pcie_service_card *card = adapter->card;
+
+ if (card->sleep_cookie) {
+ cookie_addr = (u32 *)card->sleep_cookie->data;
+ dev_dbg(adapter->dev, "info: ACCESS_HW: sleep cookie=0x%x\n",
+ *cookie_addr);
+ if (*cookie_addr == FW_AWAKE_COOKIE)
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * This function probes an mwifiex device and registers it. It allocates
+ * the card structure, enables PCIE function number and initiates the
+ * device registration and initialization procedure by adding a logical
+ * interface.
+ */
+static int mwifiex_pcie_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct pcie_service_card *card;
+
+ pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n",
+ pdev->vendor, pdev->device, pdev->revision);
+
+ card = kzalloc(sizeof(struct pcie_service_card), GFP_KERNEL);
+ if (!card) {
+ pr_err("%s: failed to alloc memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ card->dev = pdev;
+
+ if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops,
+ MWIFIEX_PCIE)) {
+ pr_err("%s failed\n", __func__);
+ kfree(card);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * This function removes the interface and frees up the card structure.
+ */
+static void mwifiex_pcie_remove(struct pci_dev *pdev)
+{
+ struct pcie_service_card *card;
+ struct mwifiex_adapter *adapter;
+ int i;
+
+ card = pci_get_drvdata(pdev);
+ if (!card)
+ return;
+
+ adapter = card->adapter;
+ if (!adapter || !adapter->priv_num)
+ return;
+
+ if (user_rmmod) {
+#ifdef CONFIG_PM
+ if (adapter->is_suspended)
+ mwifiex_pcie_resume(pdev);
+#endif
+
+ for (i = 0; i < adapter->priv_num; i++)
+ if ((GET_BSS_ROLE(adapter->priv[i]) ==
+ MWIFIEX_BSS_ROLE_STA) &&
+ adapter->priv[i]->media_connected)
+ mwifiex_deauthenticate(adapter->priv[i], NULL);
+
+ mwifiex_disable_auto_ds(mwifiex_get_priv(adapter,
+ MWIFIEX_BSS_ROLE_ANY));
+
+ mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter,
+ MWIFIEX_BSS_ROLE_ANY),
+ MWIFIEX_FUNC_SHUTDOWN);
+ }
+
+ mwifiex_remove_card(card->adapter, &add_remove_card_sem);
+ kfree(card);
+}
+
+/*
+ * Kernel needs to suspend all functions separately. Therefore all
+ * registered functions must have drivers with suspend and resume
+ * methods. Failing that the kernel simply removes the whole card.
+ *
+ * If already not suspended, this function allocates and sends a host
+ * sleep activate request to the firmware and turns off the traffic.
+ */
+static int mwifiex_pcie_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct mwifiex_adapter *adapter;
+ struct pcie_service_card *card;
+ int hs_actived, i;
+
+ if (pdev) {
+ card = (struct pcie_service_card *) pci_get_drvdata(pdev);
+ if (!card || card->adapter) {
+ pr_err("Card or adapter structure is not valid\n");
+ return 0;
+ }
+ } else {
+ pr_err("PCIE device is not specified\n");
+ return 0;
+ }
+
+ adapter = card->adapter;
+
+ hs_actived = mwifiex_enable_hs(adapter);
+
+ /* Indicate device suspended */
+ adapter->is_suspended = true;
+
+ for (i = 0; i < adapter->priv_num; i++)
+ netif_carrier_off(adapter->priv[i]->netdev);
+
+ return 0;
+}
+
+/*
+ * Kernel needs to suspend all functions separately. Therefore all
+ * registered functions must have drivers with suspend and resume
+ * methods. Failing that the kernel simply removes the whole card.
+ *
+ * If already not resumed, this function turns on the traffic and
+ * sends a host sleep cancel request to the firmware.
+ */
+static int mwifiex_pcie_resume(struct pci_dev *pdev)
+{
+ struct mwifiex_adapter *adapter;
+ struct pcie_service_card *card;
+ int i;
+
+ if (pdev) {
+ card = (struct pcie_service_card *) pci_get_drvdata(pdev);
+ if (!card || !card->adapter) {
+ pr_err("Card or adapter structure is not valid\n");
+ return 0;
+ }
+ } else {
+ pr_err("PCIE device is not specified\n");
+ return 0;
+ }
+
+ adapter = card->adapter;
+
+ if (!adapter->is_suspended) {
+ dev_warn(adapter->dev, "Device already resumed\n");
+ return 0;
+ }
+
+ adapter->is_suspended = false;
+
+ for (i = 0; i < adapter->priv_num; i++)
+ if (adapter->priv[i]->media_connected)
+ netif_carrier_on(adapter->priv[i]->netdev);
+
+ mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
+ MWIFIEX_ASYNC_CMD);
+
+ return 0;
+}
+
+#define PCIE_VENDOR_ID_MARVELL (0x11ab)
+#define PCIE_DEVICE_ID_MARVELL_88W8766P (0x2b30)
+
+static DEFINE_PCI_DEVICE_TABLE(mwifiex_ids) = {
+ {
+ PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8766P,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(pci, mwifiex_ids);
+
+/* PCI Device Driver */
+static struct pci_driver __refdata mwifiex_pcie = {
+ .name = "mwifiex_pcie",
+ .id_table = mwifiex_ids,
+ .probe = mwifiex_pcie_probe,
+ .remove = mwifiex_pcie_remove,
+#ifdef CONFIG_PM
+ /* Power Management Hooks */
+ .suspend = mwifiex_pcie_suspend,
+ .resume = mwifiex_pcie_resume,
+#endif
+};
+
+/*
+ * This function writes data into PCIE card register.
+ */
+static int mwifiex_write_reg(struct mwifiex_adapter *adapter, int reg, u32 data)
+{
+ struct pcie_service_card *card = adapter->card;
+
+ iowrite32(data, card->pci_mmap1 + reg);
+
+ return 0;
+}
+
+/*
+ * This function reads data from PCIE card register.
+ */
+static int mwifiex_read_reg(struct mwifiex_adapter *adapter, int reg, u32 *data)
+{
+ struct pcie_service_card *card = adapter->card;
+
+ *data = ioread32(card->pci_mmap1 + reg);
+
+ return 0;
+}
+
+/*
+ * This function wakes up the card.
+ *
+ * A host power up command is written to the card configuration
+ * register to wake up the card.
+ */
+static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
+{
+ int i = 0;
+
+ while (mwifiex_pcie_ok_to_access_hw(adapter)) {
+ i++;
+ udelay(10);
+ /* 50ms max wait */
+ if (i == 50000)
+ break;
+ }
+
+ dev_dbg(adapter->dev, "event: Wakeup device...\n");
+
+ /* Enable interrupts or any chip access will wakeup device */
+ if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK, HOST_INTR_MASK)) {
+ dev_warn(adapter->dev, "Enable host interrupt failed\n");
+ return -1;
+ }
+
+ dev_dbg(adapter->dev, "PCIE wakeup: Setting PS_STATE_AWAKE\n");
+ adapter->ps_state = PS_STATE_AWAKE;
+
+ return 0;
+}
+
+/*
+ * This function is called after the card has woken up.
+ *
+ * The card configuration register is reset.
+ */
+static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter)
+{
+ dev_dbg(adapter->dev, "cmd: Wakeup device completed\n");
+
+ return 0;
+}
+
+/*
+ * This function disables the host interrupt.
+ *
+ * The host interrupt mask is read, the disable bit is reset and
+ * written back to the card host interrupt mask register.
+ */
+static int mwifiex_pcie_disable_host_int(struct mwifiex_adapter *adapter)
+{
+ if (mwifiex_pcie_ok_to_access_hw(adapter)) {
+ if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK,
+ 0x00000000)) {
+ dev_warn(adapter->dev, "Disable host interrupt failed\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * This function enables the host interrupt.
+ *
+ * The host interrupt enable mask is written to the card
+ * host interrupt mask register.
+ */
+static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter)
+{
+ if (mwifiex_pcie_ok_to_access_hw(adapter)) {
+ /* Simply write the mask to the register */
+ if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK,
+ HOST_INTR_MASK)) {
+ dev_warn(adapter->dev, "Enable host interrupt failed\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * This function creates buffer descriptor ring for TX
+ */
+static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ struct sk_buff *skb;
+ int i;
+ phys_addr_t *buf_pa;
+
+ /*
+ * driver maintaines the write pointer and firmware maintaines the read
+ * pointer. The write pointer starts at 0 (zero) while the read pointer
+ * starts at zero with rollover bit set
+ */
+ card->txbd_wrptr = 0;
+ card->txbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND;
+
+ /* allocate shared memory for the BD ring and divide the same in to
+ several descriptors */
+ card->txbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
+ MWIFIEX_MAX_TXRX_BD;
+ dev_dbg(adapter->dev, "info: txbd_ring: Allocating %d bytes\n",
+ card->txbd_ring_size);
+ card->txbd_ring_vbase = kzalloc(card->txbd_ring_size, GFP_KERNEL);
+ if (!card->txbd_ring_vbase) {
+ dev_err(adapter->dev, "Unable to allocate buffer for txbd ring.\n");
+ kfree(card->txbd_ring_vbase);
+ return -1;
+ }
+ card->txbd_ring_pbase = virt_to_phys(card->txbd_ring_vbase);
+
+ dev_dbg(adapter->dev, "info: txbd_ring - base: %p, pbase: %#x:%x,"
+ "len: %x\n", card->txbd_ring_vbase,
+ (u32)card->txbd_ring_pbase,
+ (u32)((u64)card->txbd_ring_pbase >> 32),
+ card->txbd_ring_size);
+
+ for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+ card->txbd_ring[i] = (struct mwifiex_pcie_buf_desc *)
+ (card->txbd_ring_vbase +
+ (sizeof(struct mwifiex_pcie_buf_desc) * i));
+
+ /* Allocate buffer here so that firmware can DMA data from it */
+ skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
+ if (!skb) {
+ dev_err(adapter->dev, "Unable to allocate skb for TX ring.\n");
+ kfree(card->txbd_ring_vbase);
+ return -ENOMEM;
+ }
+ buf_pa = mwifiex_update_sk_buff_pa(skb);
+
+ skb_put(skb, MWIFIEX_RX_DATA_BUF_SIZE);
+ dev_dbg(adapter->dev, "info: TX ring: add new skb base: %p, "
+ "buf_base: %p, buf_pbase: %#x:%x, "
+ "buf_len: %#x\n", skb, skb->data,
+ (u32)*buf_pa, (u32)(((u64)*buf_pa >> 32)),
+ skb->len);
+
+ card->tx_buf_list[i] = skb;
+ card->txbd_ring[i]->paddr = *buf_pa;
+ card->txbd_ring[i]->len = (u16)skb->len;
+ card->txbd_ring[i]->flags = 0;
+ }
+
+ return 0;
+}
+
+static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ int i;
+
+ for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+ if (card->tx_buf_list[i])
+ dev_kfree_skb_any(card->tx_buf_list[i]);
+ card->tx_buf_list[i] = NULL;
+ card->txbd_ring[i]->paddr = 0;
+ card->txbd_ring[i]->len = 0;
+ card->txbd_ring[i]->flags = 0;
+ card->txbd_ring[i] = NULL;
+ }
+
+ kfree(card->txbd_ring_vbase);
+ card->txbd_ring_size = 0;
+ card->txbd_wrptr = 0;
+ card->txbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
+ card->txbd_ring_vbase = NULL;
+
+ return 0;
+}
+
+/*
+ * This function creates buffer descriptor ring for RX
+ */
+static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ struct sk_buff *skb;
+ int i;
+ phys_addr_t *buf_pa;
+
+ /*
+ * driver maintaines the read pointer and firmware maintaines the write
+ * pointer. The write pointer starts at 0 (zero) while the read pointer
+ * starts at zero with rollover bit set
+ */
+ card->rxbd_wrptr = 0;
+ card->rxbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND;
+
+ card->rxbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
+ MWIFIEX_MAX_TXRX_BD;
+ dev_dbg(adapter->dev, "info: rxbd_ring: Allocating %d bytes\n",
+ card->rxbd_ring_size);
+ card->rxbd_ring_vbase = kzalloc(card->rxbd_ring_size, GFP_KERNEL);
+ if (!card->rxbd_ring_vbase) {
+ dev_err(adapter->dev, "Unable to allocate buffer for "
+ "rxbd_ring.\n");
+ return -1;
+ }
+ card->rxbd_ring_pbase = virt_to_phys(card->rxbd_ring_vbase);
+
+ dev_dbg(adapter->dev, "info: rxbd_ring - base: %p, pbase: %#x:%x,"
+ "len: %#x\n", card->rxbd_ring_vbase,
+ (u32)card->rxbd_ring_pbase,
+ (u32)((u64)card->rxbd_ring_pbase >> 32),
+ card->rxbd_ring_size);
+
+ for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+ card->rxbd_ring[i] = (struct mwifiex_pcie_buf_desc *)
+ (card->rxbd_ring_vbase +
+ (sizeof(struct mwifiex_pcie_buf_desc) * i));
+
+ /* Allocate skb here so that firmware can DMA data from it */
+ skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
+ if (!skb) {
+ dev_err(adapter->dev, "Unable to allocate skb for RX ring.\n");
+ kfree(card->rxbd_ring_vbase);
+ return -ENOMEM;
+ }
+ buf_pa = mwifiex_update_sk_buff_pa(skb);
+ skb_put(skb, MWIFIEX_RX_DATA_BUF_SIZE);
+
+ dev_dbg(adapter->dev, "info: RX ring: add new skb base: %p, "
+ "buf_base: %p, buf_pbase: %#x:%x, "
+ "buf_len: %#x\n", skb, skb->data,
+ (u32)*buf_pa, (u32)((u64)*buf_pa >> 32),
+ skb->len);
+
+ card->rx_buf_list[i] = skb;
+ card->rxbd_ring[i]->paddr = *buf_pa;
+ card->rxbd_ring[i]->len = (u16)skb->len;
+ card->rxbd_ring[i]->flags = 0;
+ }
+
+ return 0;
+}
+
+/*
+ * This function deletes Buffer descriptor ring for RX
+ */
+static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ int i;
+
+ for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+ if (card->rx_buf_list[i])
+ dev_kfree_skb_any(card->rx_buf_list[i]);
+ card->rx_buf_list[i] = NULL;
+ card->rxbd_ring[i]->paddr = 0;
+ card->rxbd_ring[i]->len = 0;
+ card->rxbd_ring[i]->flags = 0;
+ card->rxbd_ring[i] = NULL;
+ }
+
+ kfree(card->rxbd_ring_vbase);
+ card->rxbd_ring_size = 0;
+ card->rxbd_wrptr = 0;
+ card->rxbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
+ card->rxbd_ring_vbase = NULL;
+
+ return 0;
+}
+
+/*
+ * This function creates buffer descriptor ring for Events
+ */
+static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ struct sk_buff *skb;
+ int i;
+ phys_addr_t *buf_pa;
+
+ /*
+ * driver maintaines the read pointer and firmware maintaines the write
+ * pointer. The write pointer starts at 0 (zero) while the read pointer
+ * starts at zero with rollover bit set
+ */
+ card->evtbd_wrptr = 0;
+ card->evtbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND;
+
+ card->evtbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
+ MWIFIEX_MAX_EVT_BD;
+ dev_dbg(adapter->dev, "info: evtbd_ring: Allocating %d bytes\n",
+ card->evtbd_ring_size);
+ card->evtbd_ring_vbase = kzalloc(card->evtbd_ring_size, GFP_KERNEL);
+ if (!card->evtbd_ring_vbase) {
+ dev_err(adapter->dev, "Unable to allocate buffer. "
+ "Terminating download\n");
+ return -1;
+ }
+ card->evtbd_ring_pbase = virt_to_phys(card->evtbd_ring_vbase);
+
+ dev_dbg(adapter->dev, "info: CMDRSP/EVT bd_ring - base: %p, "
+ "pbase: %#x:%x, len: %#x\n", card->evtbd_ring_vbase,
+ (u32)card->evtbd_ring_pbase,
+ (u32)((u64)card->evtbd_ring_pbase >> 32),
+ card->evtbd_ring_size);
+
+ for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
+ card->evtbd_ring[i] = (struct mwifiex_pcie_buf_desc *)
+ (card->evtbd_ring_vbase +
+ (sizeof(struct mwifiex_pcie_buf_desc) * i));
+
+ /* Allocate skb here so that firmware can DMA data from it */
+ skb = dev_alloc_skb(MAX_EVENT_SIZE);
+ if (!skb) {
+ dev_err(adapter->dev, "Unable to allocate skb for EVENT buf.\n");
+ kfree(card->evtbd_ring_vbase);
+ return -ENOMEM;
+ }
+ buf_pa = mwifiex_update_sk_buff_pa(skb);
+ skb_put(skb, MAX_EVENT_SIZE);
+
+ dev_dbg(adapter->dev, "info: Evt ring: add new skb. base: %p, "
+ "buf_base: %p, buf_pbase: %#x:%x, "
+ "buf_len: %#x\n", skb, skb->data,
+ (u32)*buf_pa, (u32)((u64)*buf_pa >> 32),
+ skb->len);
+
+ card->evt_buf_list[i] = skb;
+ card->evtbd_ring[i]->paddr = *buf_pa;
+ card->evtbd_ring[i]->len = (u16)skb->len;
+ card->evtbd_ring[i]->flags = 0;
+ }
+
+ return 0;
+}
+
+/*
+ * This function deletes Buffer descriptor ring for Events
+ */
+static int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ int i;
+
+ for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
+ if (card->evt_buf_list[i])
+ dev_kfree_skb_any(card->evt_buf_list[i]);
+ card->evt_buf_list[i] = NULL;
+ card->evtbd_ring[i]->paddr = 0;
+ card->evtbd_ring[i]->len = 0;
+ card->evtbd_ring[i]->flags = 0;
+ card->evtbd_ring[i] = NULL;
+ }
+
+ kfree(card->evtbd_ring_vbase);
+ card->evtbd_wrptr = 0;
+ card->evtbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
+ card->evtbd_ring_size = 0;
+ card->evtbd_ring_vbase = NULL;
+
+ return 0;
+}
+
+/*
+ * This function allocates a buffer for CMDRSP
+ */
+static int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ struct sk_buff *skb;
+
+ /* Allocate memory for receiving command response data */
+ skb = dev_alloc_skb(MWIFIEX_UPLD_SIZE);
+ if (!skb) {
+ dev_err(adapter->dev, "Unable to allocate skb for command "
+ "response data.\n");
+ return -ENOMEM;
+ }
+ mwifiex_update_sk_buff_pa(skb);
+ skb_put(skb, MWIFIEX_UPLD_SIZE);
+ card->cmdrsp_buf = skb;
+
+ skb = NULL;
+ /* Allocate memory for sending command to firmware */
+ skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER);
+ if (!skb) {
+ dev_err(adapter->dev, "Unable to allocate skb for command "
+ "data.\n");
+ return -ENOMEM;
+ }
+ mwifiex_update_sk_buff_pa(skb);
+ skb_put(skb, MWIFIEX_SIZE_OF_CMD_BUFFER);
+ card->cmd_buf = skb;
+
+ return 0;
+}
+
+/*
+ * This function deletes a buffer for CMDRSP
+ */
+static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card;
+
+ if (!adapter)
+ return 0;
+
+ card = adapter->card;
+
+ if (card && card->cmdrsp_buf)
+ dev_kfree_skb_any(card->cmdrsp_buf);
+
+ if (card && card->cmd_buf)
+ dev_kfree_skb_any(card->cmd_buf);
+
+ return 0;
+}
+
+/*
+ * This function allocates a buffer for sleep cookie
+ */
+static int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter)
+{
+ struct sk_buff *skb;
+ struct pcie_service_card *card = adapter->card;
+
+ /* Allocate memory for sleep cookie */
+ skb = dev_alloc_skb(sizeof(u32));
+ if (!skb) {
+ dev_err(adapter->dev, "Unable to allocate skb for sleep "
+ "cookie!\n");
+ return -ENOMEM;
+ }
+ mwifiex_update_sk_buff_pa(skb);
+ skb_put(skb, sizeof(u32));
+
+ /* Init val of Sleep Cookie */
+ *(u32 *)skb->data = FW_AWAKE_COOKIE;
+
+ dev_dbg(adapter->dev, "alloc_scook: sleep cookie=0x%x\n",
+ *((u32 *)skb->data));
+
+ /* Save the sleep cookie */
+ card->sleep_cookie = skb;
+
+ return 0;
+}
+
+/*
+ * This function deletes buffer for sleep cookie
+ */
+static int mwifiex_pcie_delete_sleep_cookie_buf(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card;
+
+ if (!adapter)
+ return 0;
+
+ card = adapter->card;
+
+ if (card && card->sleep_cookie) {
+ dev_kfree_skb_any(card->sleep_cookie);
+ card->sleep_cookie = NULL;
+ }
+
+ return 0;
+}
+
+/*
+ * This function sends data buffer to device
+ */
+static int
+mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb)
+{
+ struct pcie_service_card *card = adapter->card;
+ u32 wrindx, rdptr;
+ phys_addr_t *buf_pa;
+ __le16 *tmp;
+
+ if (!mwifiex_pcie_ok_to_access_hw(adapter))
+ mwifiex_pm_wakeup_card(adapter);
+
+ /* Read the TX ring read pointer set by firmware */
+ if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) {
+ dev_err(adapter->dev, "SEND DATA: failed to read "
+ "REG_TXBD_RDPTR\n");
+ return -1;
+ }
+
+ wrindx = card->txbd_wrptr & MWIFIEX_TXBD_MASK;
+
+ dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n", rdptr,
+ card->txbd_wrptr);
+ if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) !=
+ (rdptr & MWIFIEX_TXBD_MASK)) ||
+ ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) !=
+ (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
+ struct sk_buff *skb_data;
+ u8 *payload;
+
+ adapter->data_sent = true;
+ skb_data = card->tx_buf_list[wrindx];
+ memcpy(skb_data->data, skb->data, skb->len);
+ payload = skb_data->data;
+ tmp = (__le16 *)&payload[0];
+ *tmp = cpu_to_le16((u16)skb->len);
+ tmp = (__le16 *)&payload[2];
+ *tmp = cpu_to_le16(MWIFIEX_TYPE_DATA);
+ skb_put(skb_data, MWIFIEX_RX_DATA_BUF_SIZE - skb_data->len);
+ skb_trim(skb_data, skb->len);
+ buf_pa = MWIFIEX_SKB_PACB(skb_data);
+ card->txbd_ring[wrindx]->paddr = *buf_pa;
+ card->txbd_ring[wrindx]->len = (u16)skb_data->len;
+ card->txbd_ring[wrindx]->flags = MWIFIEX_BD_FLAG_FIRST_DESC |
+ MWIFIEX_BD_FLAG_LAST_DESC;
+
+ if ((++card->txbd_wrptr & MWIFIEX_TXBD_MASK) ==
+ MWIFIEX_MAX_TXRX_BD)
+ card->txbd_wrptr = ((card->txbd_wrptr &
+ MWIFIEX_BD_FLAG_ROLLOVER_IND) ^
+ MWIFIEX_BD_FLAG_ROLLOVER_IND);
+
+ /* Write the TX ring write pointer in to REG_TXBD_WRPTR */
+ if (mwifiex_write_reg(adapter, REG_TXBD_WRPTR,
+ card->txbd_wrptr)) {
+ dev_err(adapter->dev, "SEND DATA: failed to write "
+ "REG_TXBD_WRPTR\n");
+ return 0;
+ }
+
+ /* Send the TX ready interrupt */
+ if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
+ CPU_INTR_DNLD_RDY)) {
+ dev_err(adapter->dev, "SEND DATA: failed to assert "
+ "door-bell interrupt.\n");
+ return -1;
+ }
+ dev_dbg(adapter->dev, "info: SEND DATA: Updated <Rd: %#x, Wr: "
+ "%#x> and sent packet to firmware "
+ "successfully\n", rdptr,
+ card->txbd_wrptr);
+ } else {
+ dev_dbg(adapter->dev, "info: TX Ring full, can't send anymore "
+ "packets to firmware\n");
+ adapter->data_sent = true;
+ /* Send the TX ready interrupt */
+ if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
+ CPU_INTR_DNLD_RDY))
+ dev_err(adapter->dev, "SEND DATA: failed to assert "
+ "door-bell interrupt\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+/*
+ * This function handles received buffer ring and
+ * dispatches packets to upper
+ */
+static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ u32 wrptr, rd_index;
+ int ret = 0;
+ struct sk_buff *skb_tmp = NULL;
+
+ /* Read the RX ring Write pointer set by firmware */
+ if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) {
+ dev_err(adapter->dev, "RECV DATA: failed to read "
+ "REG_TXBD_RDPTR\n");
+ ret = -1;
+ goto done;
+ }
+
+ while (((wrptr & MWIFIEX_RXBD_MASK) !=
+ (card->rxbd_rdptr & MWIFIEX_RXBD_MASK)) ||
+ ((wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) ==
+ (card->rxbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
+ struct sk_buff *skb_data;
+ u16 rx_len;
+
+ rd_index = card->rxbd_rdptr & MWIFIEX_RXBD_MASK;
+ skb_data = card->rx_buf_list[rd_index];
+
+ /* Get data length from interface header -
+ first byte is len, second byte is type */
+ rx_len = *((u16 *)skb_data->data);
+ dev_dbg(adapter->dev, "info: RECV DATA: Rd=%#x, Wr=%#x, "
+ "Len=%d\n", card->rxbd_rdptr, wrptr, rx_len);
+ skb_tmp = dev_alloc_skb(rx_len);
+ if (!skb_tmp) {
+ dev_dbg(adapter->dev, "info: Failed to alloc skb "
+ "for RX\n");
+ ret = -EBUSY;
+ goto done;
+ }
+
+ skb_put(skb_tmp, rx_len);
+
+ memcpy(skb_tmp->data, skb_data->data + INTF_HEADER_LEN, rx_len);
+ if ((++card->rxbd_rdptr & MWIFIEX_RXBD_MASK) ==
+ MWIFIEX_MAX_TXRX_BD) {
+ card->rxbd_rdptr = ((card->rxbd_rdptr &
+ MWIFIEX_BD_FLAG_ROLLOVER_IND) ^
+ MWIFIEX_BD_FLAG_ROLLOVER_IND);
+ }
+ dev_dbg(adapter->dev, "info: RECV DATA: <Rd: %#x, Wr: %#x>\n",
+ card->rxbd_rdptr, wrptr);
+
+ /* Write the RX ring read pointer in to REG_RXBD_RDPTR */
+ if (mwifiex_write_reg(adapter, REG_RXBD_RDPTR,
+ card->rxbd_rdptr)) {
+ dev_err(adapter->dev, "RECV DATA: failed to "
+ "write REG_RXBD_RDPTR\n");
+ ret = -1;
+ goto done;
+ }
+
+ /* Read the RX ring Write pointer set by firmware */
+ if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) {
+ dev_err(adapter->dev, "RECV DATA: failed to read "
+ "REG_TXBD_RDPTR\n");
+ ret = -1;
+ goto done;
+ }
+ dev_dbg(adapter->dev, "info: RECV DATA: Received packet from "
+ "firmware successfully\n");
+ mwifiex_handle_rx_packet(adapter, skb_tmp);
+ }
+
+done:
+ if (ret && skb_tmp)
+ dev_kfree_skb_any(skb_tmp);
+ return ret;
+}
+
+/*
+ * This function downloads the boot command to device
+ */
+static int
+mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
+{
+ phys_addr_t *buf_pa = MWIFIEX_SKB_PACB(skb);
+
+ if (!(skb->data && skb->len && *buf_pa)) {
+ dev_err(adapter->dev, "Invalid parameter in %s <%p, %#x:%x, "
+ "%x>\n", __func__, skb->data, skb->len,
+ (u32)*buf_pa, (u32)((u64)*buf_pa >> 32));
+ return -1;
+ }
+
+ /* Write the lower 32bits of the physical address to scratch
+ * register 0 */
+ if (mwifiex_write_reg(adapter, PCIE_SCRATCH_0_REG, (u32)*buf_pa)) {
+ dev_err(adapter->dev, "%s: failed to write download command "
+ "to boot code.\n", __func__);
+ return -1;
+ }
+
+ /* Write the upper 32bits of the physical address to scratch
+ * register 1 */
+ if (mwifiex_write_reg(adapter, PCIE_SCRATCH_1_REG,
+ (u32)((u64)*buf_pa >> 32))) {
+ dev_err(adapter->dev, "%s: failed to write download command "
+ "to boot code.\n", __func__);
+ return -1;
+ }
+
+ /* Write the command length to scratch register 2 */
+ if (mwifiex_write_reg(adapter, PCIE_SCRATCH_2_REG, skb->len)) {
+ dev_err(adapter->dev, "%s: failed to write command length to "
+ "scratch register 2\n", __func__);
+ return -1;
+ }
+
+ /* Ring the door bell */
+ if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
+ CPU_INTR_DOOR_BELL)) {
+ dev_err(adapter->dev, "%s: failed to assert door-bell "
+ "interrupt.\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * This function downloads commands to the device
+ */
+static int
+mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
+{
+ struct pcie_service_card *card = adapter->card;
+ int ret = 0;
+ phys_addr_t *cmd_buf_pa;
+ phys_addr_t *cmdrsp_buf_pa;
+
+ if (!(skb->data && skb->len)) {
+ dev_err(adapter->dev, "Invalid parameter in %s <%p, %#x>\n",
+ __func__, skb->data, skb->len);
+ return -1;
+ }
+
+ /* Make sure a command response buffer is available */
+ if (!card->cmdrsp_buf) {
+ dev_err(adapter->dev, "No response buffer available, send "
+ "command failed\n");
+ return -EBUSY;
+ }
+
+ /* Make sure a command buffer is available */
+ if (!card->cmd_buf) {
+ dev_err(adapter->dev, "Command buffer not available\n");
+ return -EBUSY;
+ }
+
+ adapter->cmd_sent = true;
+ /* Copy the given skb in to DMA accessable shared buffer */
+ skb_put(card->cmd_buf, MWIFIEX_SIZE_OF_CMD_BUFFER - card->cmd_buf->len);
+ skb_trim(card->cmd_buf, skb->len);
+ memcpy(card->cmd_buf->data, skb->data, skb->len);
+
+ /* To send a command, the driver will:
+ 1. Write the 64bit physical address of the data buffer to
+ SCRATCH1 + SCRATCH0
+ 2. Ring the door bell (i.e. set the door bell interrupt)
+
+ In response to door bell interrupt, the firmware will perform
+ the DMA of the command packet (first header to obtain the total
+ length and then rest of the command).
+ */
+
+ if (card->cmdrsp_buf) {
+ cmdrsp_buf_pa = MWIFIEX_SKB_PACB(card->cmdrsp_buf);
+ /* Write the lower 32bits of the cmdrsp buffer physical
+ address */
+ if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO,
+ (u32)*cmdrsp_buf_pa)) {
+ dev_err(adapter->dev, "Failed to write download command to boot code.\n");
+ ret = -1;
+ goto done;
+ }
+ /* Write the upper 32bits of the cmdrsp buffer physical
+ address */
+ if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI,
+ (u32)((u64)*cmdrsp_buf_pa >> 32))) {
+ dev_err(adapter->dev, "Failed to write download command"
+ " to boot code.\n");
+ ret = -1;
+ goto done;
+ }
+ }
+
+ cmd_buf_pa = MWIFIEX_SKB_PACB(card->cmd_buf);
+ /* Write the lower 32bits of the physical address to REG_CMD_ADDR_LO */
+ if (mwifiex_write_reg(adapter, REG_CMD_ADDR_LO,
+ (u32)*cmd_buf_pa)) {
+ dev_err(adapter->dev, "Failed to write download command "
+ "to boot code.\n");
+ ret = -1;
+ goto done;
+ }
+ /* Write the upper 32bits of the physical address to REG_CMD_ADDR_HI */
+ if (mwifiex_write_reg(adapter, REG_CMD_ADDR_HI,
+ (u32)((u64)*cmd_buf_pa >> 32))) {
+ dev_err(adapter->dev, "Failed to write download command "
+ "to boot code.\n");
+ ret = -1;
+ goto done;
+ }
+
+ /* Write the command length to REG_CMD_SIZE */
+ if (mwifiex_write_reg(adapter, REG_CMD_SIZE,
+ card->cmd_buf->len)) {
+ dev_err(adapter->dev, "Failed to write command length to "
+ "REG_CMD_SIZE\n");
+ ret = -1;
+ goto done;
+ }
+
+ /* Ring the door bell */
+ if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
+ CPU_INTR_DOOR_BELL)) {
+ dev_err(adapter->dev, "Failed to assert door-bell "
+ "interrupt.\n");
+ ret = -1;
+ goto done;
+ }
+
+done:
+ if (ret)
+ adapter->cmd_sent = false;
+
+ return 0;
+}
+
+/*
+ * This function handles command complete interrupt
+ */
+static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ int count = 0;
+
+ dev_dbg(adapter->dev, "info: Rx CMD Response\n");
+
+ if (!adapter->curr_cmd) {
+ skb_pull(card->cmdrsp_buf, INTF_HEADER_LEN);
+ if (adapter->ps_state == PS_STATE_SLEEP_CFM) {
+ mwifiex_process_sleep_confirm_resp(adapter,
+ card->cmdrsp_buf->data,
+ card->cmdrsp_buf->len);
+ while (mwifiex_pcie_ok_to_access_hw(adapter) &&
+ (count++ < 10))
+ udelay(50);
+ } else {
+ dev_err(adapter->dev, "There is no command but "
+ "got cmdrsp\n");
+ }
+ memcpy(adapter->upld_buf, card->cmdrsp_buf->data,
+ min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER,
+ card->cmdrsp_buf->len));
+ skb_push(card->cmdrsp_buf, INTF_HEADER_LEN);
+ } else if (mwifiex_pcie_ok_to_access_hw(adapter)) {
+ skb_pull(card->cmdrsp_buf, INTF_HEADER_LEN);
+ adapter->curr_cmd->resp_skb = card->cmdrsp_buf;
+ adapter->cmd_resp_received = true;
+ /* Take the pointer and set it to CMD node and will
+ return in the response complete callback */
+ card->cmdrsp_buf = NULL;
+
+ /* Clear the cmd-rsp buffer address in scratch registers. This
+ will prevent firmware from writing to the same response
+ buffer again. */
+ if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO, 0)) {
+ dev_err(adapter->dev, "cmd_done: failed to clear "
+ "cmd_rsp address.\n");
+ return -1;
+ }
+ /* Write the upper 32bits of the cmdrsp buffer physical
+ address */
+ if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI, 0)) {
+ dev_err(adapter->dev, "cmd_done: failed to clear "
+ "cmd_rsp address.\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Command Response processing complete handler
+ */
+static int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb)
+{
+ struct pcie_service_card *card = adapter->card;
+
+ if (skb) {
+ card->cmdrsp_buf = skb;
+ skb_push(card->cmdrsp_buf, INTF_HEADER_LEN);
+ }
+
+ return 0;
+}
+
+/*
+ * This function handles firmware event ready interrupt
+ */
+static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
+ u32 wrptr, event;
+
+ if (adapter->event_received) {
+ dev_dbg(adapter->dev, "info: Event being processed, "\
+ "do not process this interrupt just yet\n");
+ return 0;
+ }
+
+ if (rdptr >= MWIFIEX_MAX_EVT_BD) {
+ dev_dbg(adapter->dev, "info: Invalid read pointer...\n");
+ return -1;
+ }
+
+ /* Read the event ring write pointer set by firmware */
+ if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) {
+ dev_err(adapter->dev, "EventReady: failed to read REG_EVTBD_WRPTR\n");
+ return -1;
+ }
+
+ dev_dbg(adapter->dev, "info: EventReady: Initial <Rd: 0x%x, Wr: 0x%x>",
+ card->evtbd_rdptr, wrptr);
+ if (((wrptr & MWIFIEX_EVTBD_MASK) !=
+ (card->evtbd_rdptr & MWIFIEX_EVTBD_MASK)) ||
+ ((wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) ==
+ (card->evtbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
+ struct sk_buff *skb_cmd;
+ __le16 data_len = 0;
+ u16 evt_len;
+
+ dev_dbg(adapter->dev, "info: Read Index: %d\n", rdptr);
+ skb_cmd = card->evt_buf_list[rdptr];
+ /* Take the pointer and set it to event pointer in adapter
+ and will return back after event handling callback */
+ card->evt_buf_list[rdptr] = NULL;
+ card->evtbd_ring[rdptr]->paddr = 0;
+ card->evtbd_ring[rdptr]->len = 0;
+ card->evtbd_ring[rdptr]->flags = 0;
+
+ event = *(u32 *) &skb_cmd->data[INTF_HEADER_LEN];
+ adapter->event_cause = event;
+ /* The first 4bytes will be the event transfer header
+ len is 2 bytes followed by type which is 2 bytes */
+ memcpy(&data_len, skb_cmd->data, sizeof(__le16));
+ evt_len = le16_to_cpu(data_len);
+
+ skb_pull(skb_cmd, INTF_HEADER_LEN);
+ dev_dbg(adapter->dev, "info: Event length: %d\n", evt_len);
+
+ if ((evt_len > 0) && (evt_len < MAX_EVENT_SIZE))
+ memcpy(adapter->event_body, skb_cmd->data +
+ MWIFIEX_EVENT_HEADER_LEN, evt_len -
+ MWIFIEX_EVENT_HEADER_LEN);
+
+ adapter->event_received = true;
+ adapter->event_skb = skb_cmd;
+
+ /* Do not update the event read pointer here, wait till the
+ buffer is released. This is just to make things simpler,
+ we need to find a better method of managing these buffers.
+ */
+ }
+
+ return 0;
+}
+
+/*
+ * Event processing complete handler
+ */
+static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb)
+{
+ struct pcie_service_card *card = adapter->card;
+ int ret = 0;
+ u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
+ u32 wrptr;
+ phys_addr_t *buf_pa;
+
+ if (!skb)
+ return 0;
+
+ if (rdptr >= MWIFIEX_MAX_EVT_BD)
+ dev_err(adapter->dev, "event_complete: Invalid rdptr 0x%x\n",
+ rdptr);
+
+ /* Read the event ring write pointer set by firmware */
+ if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) {
+ dev_err(adapter->dev, "event_complete: failed to read REG_EVTBD_WRPTR\n");
+ ret = -1;
+ goto done;
+ }
+
+ if (!card->evt_buf_list[rdptr]) {
+ skb_push(skb, INTF_HEADER_LEN);
+ card->evt_buf_list[rdptr] = skb;
+ buf_pa = MWIFIEX_SKB_PACB(skb);
+ card->evtbd_ring[rdptr]->paddr = *buf_pa;
+ card->evtbd_ring[rdptr]->len = (u16)skb->len;
+ card->evtbd_ring[rdptr]->flags = 0;
+ skb = NULL;
+ } else {
+ dev_dbg(adapter->dev, "info: ERROR: Buffer is still valid at "
+ "index %d, <%p, %p>\n", rdptr,
+ card->evt_buf_list[rdptr], skb);
+ }
+
+ if ((++card->evtbd_rdptr & MWIFIEX_EVTBD_MASK) == MWIFIEX_MAX_EVT_BD) {
+ card->evtbd_rdptr = ((card->evtbd_rdptr &
+ MWIFIEX_BD_FLAG_ROLLOVER_IND) ^
+ MWIFIEX_BD_FLAG_ROLLOVER_IND);
+ }
+
+ dev_dbg(adapter->dev, "info: Updated <Rd: 0x%x, Wr: 0x%x>",
+ card->evtbd_rdptr, wrptr);
+
+ /* Write the event ring read pointer in to REG_EVTBD_RDPTR */
+ if (mwifiex_write_reg(adapter, REG_EVTBD_RDPTR, card->evtbd_rdptr)) {
+ dev_err(adapter->dev, "event_complete: failed to read REG_EVTBD_RDPTR\n");
+ ret = -1;
+ goto done;
+ }
+
+done:
+ /* Free the buffer for failure case */
+ if (ret && skb)
+ dev_kfree_skb_any(skb);
+
+ dev_dbg(adapter->dev, "info: Check Events Again\n");
+ ret = mwifiex_pcie_process_event_ready(adapter);
+
+ return ret;
+}
+
+/*
+ * This function downloads the firmware to the card.
+ *
+ * Firmware is downloaded to the card in blocks. Every block download
+ * is tested for CRC errors, and retried a number of times before
+ * returning failure.
+ */
+static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
+ struct mwifiex_fw_image *fw)
+{
+ int ret;
+ u8 *firmware = fw->fw_buf;
+ u32 firmware_len = fw->fw_len;
+ u32 offset = 0;
+ struct sk_buff *skb;
+ u32 txlen, tx_blocks = 0, tries, len;
+ u32 block_retry_cnt = 0;
+
+ if (!adapter) {
+ pr_err("adapter structure is not valid\n");
+ return -1;
+ }
+
+ if (!firmware || !firmware_len) {
+ dev_err(adapter->dev, "No firmware image found! "
+ "Terminating download\n");
+ return -1;
+ }
+
+ dev_dbg(adapter->dev, "info: Downloading FW image (%d bytes)\n",
+ firmware_len);
+
+ if (mwifiex_pcie_disable_host_int(adapter)) {
+ dev_err(adapter->dev, "%s: Disabling interrupts"
+ " failed.\n", __func__);
+ return -1;
+ }
+
+ skb = dev_alloc_skb(MWIFIEX_UPLD_SIZE);
+ if (!skb) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ mwifiex_update_sk_buff_pa(skb);
+
+ /* Perform firmware data transfer */
+ do {
+ u32 ireg_intr = 0;
+
+ /* More data? */
+ if (offset >= firmware_len)
+ break;
+
+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+ ret = mwifiex_read_reg(adapter, PCIE_SCRATCH_2_REG,
+ &len);
+ if (ret) {
+ dev_warn(adapter->dev, "Failed reading length from boot code\n");
+ goto done;
+ }
+ if (len)
+ break;
+ udelay(10);
+ }
+
+ if (!len) {
+ break;
+ } else if (len > MWIFIEX_UPLD_SIZE) {
+ pr_err("FW download failure @ %d, invalid length %d\n",
+ offset, len);
+ ret = -1;
+ goto done;
+ }
+
+ txlen = len;
+
+ if (len & BIT(0)) {
+ block_retry_cnt++;
+ if (block_retry_cnt > MAX_WRITE_IOMEM_RETRY) {
+ pr_err("FW download failure @ %d, over max "
+ "retry count\n", offset);
+ ret = -1;
+ goto done;
+ }
+ dev_err(adapter->dev, "FW CRC error indicated by the "
+ "helper: len = 0x%04X, txlen = "
+ "%d\n", len, txlen);
+ len &= ~BIT(0);
+ /* Setting this to 0 to resend from same offset */
+ txlen = 0;
+ } else {
+ block_retry_cnt = 0;
+ /* Set blocksize to transfer - checking for
+ last block */
+ if (firmware_len - offset < txlen)
+ txlen = firmware_len - offset;
+
+ dev_dbg(adapter->dev, ".");
+
+ tx_blocks =
+ (txlen + MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD - 1) /
+ MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD;
+
+ /* Copy payload to buffer */
+ memmove(skb->data, &firmware[offset], txlen);
+ }
+
+ skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len);
+ skb_trim(skb, tx_blocks * MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD);
+
+ /* Send the boot command to device */
+ if (mwifiex_pcie_send_boot_cmd(adapter, skb)) {
+ dev_err(adapter->dev, "Failed to send firmware download command\n");
+ ret = -1;
+ goto done;
+ }
+ /* Wait for the command done interrupt */
+ do {
+ if (mwifiex_read_reg(adapter, PCIE_CPU_INT_STATUS,
+ &ireg_intr)) {
+ dev_err(adapter->dev, "%s: Failed to read "
+ "interrupt status during "
+ "fw dnld.\n", __func__);
+ ret = -1;
+ goto done;
+ }
+ } while ((ireg_intr & CPU_INTR_DOOR_BELL) ==
+ CPU_INTR_DOOR_BELL);
+ offset += txlen;
+ } while (true);
+
+ dev_dbg(adapter->dev, "info:\nFW download over, size %d bytes\n",
+ offset);
+
+ ret = 0;
+
+done:
+ dev_kfree_skb_any(skb);
+ return ret;
+}
+
+/*
+ * This function checks the firmware status in card.
+ *
+ * The winner interface is also determined by this function.
+ */
+static int
+mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
+{
+ int ret = 0;
+ u32 firmware_stat, winner_status;
+ u32 tries;
+
+ /* Mask spurios interrupts */
+ if (mwifiex_write_reg(adapter, PCIE_HOST_INT_STATUS_MASK,
+ HOST_INTR_MASK)) {
+ dev_warn(adapter->dev, "Write register failed\n");
+ return -1;
+ }
+
+ dev_dbg(adapter->dev, "Setting driver ready signature\n");
+ if (mwifiex_write_reg(adapter, REG_DRV_READY, FIRMWARE_READY_PCIE)) {
+ dev_err(adapter->dev, "Failed to write driver ready signature\n");
+ return -1;
+ }
+
+ /* Wait for firmware initialization event */
+ for (tries = 0; tries < poll_num; tries++) {
+ if (mwifiex_read_reg(adapter, PCIE_SCRATCH_3_REG,
+ &firmware_stat))
+ ret = -1;
+ else
+ ret = 0;
+ if (ret)
+ continue;
+ if (firmware_stat == FIRMWARE_READY_PCIE) {
+ ret = 0;
+ break;
+ } else {
+ mdelay(100);
+ ret = -1;
+ }
+ }
+
+ if (ret) {
+ if (mwifiex_read_reg(adapter, PCIE_SCRATCH_3_REG,
+ &winner_status))
+ ret = -1;
+ else if (!winner_status) {
+ dev_err(adapter->dev, "PCI-E is the winner\n");
+ adapter->winner = 1;
+ ret = -1;
+ } else {
+ dev_err(adapter->dev, "PCI-E is not the winner <%#x, %d>, exit download\n",
+ ret, adapter->winner);
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * This function reads the interrupt status from card.
+ */
+static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
+{
+ u32 pcie_ireg;
+ unsigned long flags;
+
+ if (!mwifiex_pcie_ok_to_access_hw(adapter))
+ return;
+
+ if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS, &pcie_ireg)) {
+ dev_warn(adapter->dev, "Read register failed\n");
+ return;
+ }
+
+ if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
+
+ mwifiex_pcie_disable_host_int(adapter);
+
+ /* Clear the pending interrupts */
+ if (mwifiex_write_reg(adapter, PCIE_HOST_INT_STATUS,
+ ~pcie_ireg)) {
+ dev_warn(adapter->dev, "Write register failed\n");
+ return;
+ }
+ spin_lock_irqsave(&adapter->int_lock, flags);
+ adapter->int_status |= pcie_ireg;
+ spin_unlock_irqrestore(&adapter->int_lock, flags);
+
+ if (pcie_ireg & HOST_INTR_CMD_DONE) {
+ if ((adapter->ps_state == PS_STATE_SLEEP_CFM) ||
+ (adapter->ps_state == PS_STATE_SLEEP)) {
+ mwifiex_pcie_enable_host_int(adapter);
+ if (mwifiex_write_reg(adapter,
+ PCIE_CPU_INT_EVENT,
+ CPU_INTR_SLEEP_CFM_DONE)) {
+ dev_warn(adapter->dev, "Write register"
+ " failed\n");
+ return;
+
+ }
+ }
+ } else if (!adapter->pps_uapsd_mode &&
+ adapter->ps_state == PS_STATE_SLEEP) {
+ /* Potentially for PCIe we could get other
+ * interrupts like shared. Don't change power
+ * state until cookie is set */
+ if (mwifiex_pcie_ok_to_access_hw(adapter))
+ adapter->ps_state = PS_STATE_AWAKE;
+ }
+ }
+}
+
+/*
+ * Interrupt handler for PCIe root port
+ *
+ * This function reads the interrupt status from firmware and assigns
+ * the main process in workqueue which will handle the interrupt.
+ */
+static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context)
+{
+ struct pci_dev *pdev = (struct pci_dev *)context;
+ struct pcie_service_card *card;
+ struct mwifiex_adapter *adapter;
+
+ if (!pdev) {
+ pr_debug("info: %s: pdev is NULL\n", (u8 *)pdev);
+ goto exit;
+ }
+
+ card = (struct pcie_service_card *) pci_get_drvdata(pdev);
+ if (!card || !card->adapter) {
+ pr_debug("info: %s: card=%p adapter=%p\n", __func__, card,
+ card ? card->adapter : NULL);
+ goto exit;
+ }
+ adapter = card->adapter;
+
+ if (adapter->surprise_removed)
+ goto exit;
+
+ mwifiex_interrupt_status(adapter);
+ queue_work(adapter->workqueue, &adapter->main_work);
+
+exit:
+ return IRQ_HANDLED;
+}
+
+/*
+ * This function checks the current interrupt status.
+ *
+ * The following interrupts are checked and handled by this function -
+ * - Data sent
+ * - Command sent
+ * - Command received
+ * - Packets received
+ * - Events received
+ *
+ * In case of Rx packets received, the packets are uploaded from card to
+ * host and processed accordingly.
+ */
+static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
+{
+ int ret;
+ u32 pcie_ireg = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->int_lock, flags);
+ /* Clear out unused interrupts */
+ adapter->int_status &= HOST_INTR_MASK;
+ spin_unlock_irqrestore(&adapter->int_lock, flags);
+
+ while (adapter->int_status & HOST_INTR_MASK) {
+ if (adapter->int_status & HOST_INTR_DNLD_DONE) {
+ adapter->int_status &= ~HOST_INTR_DNLD_DONE;
+ if (adapter->data_sent) {
+ dev_dbg(adapter->dev, "info: DATA sent Interrupt\n");
+ adapter->data_sent = false;
+ }
+ }
+ if (adapter->int_status & HOST_INTR_UPLD_RDY) {
+ adapter->int_status &= ~HOST_INTR_UPLD_RDY;
+ dev_dbg(adapter->dev, "info: Rx DATA\n");
+ ret = mwifiex_pcie_process_recv_data(adapter);
+ if (ret)
+ return ret;
+ }
+ if (adapter->int_status & HOST_INTR_EVENT_RDY) {
+ adapter->int_status &= ~HOST_INTR_EVENT_RDY;
+ dev_dbg(adapter->dev, "info: Rx EVENT\n");
+ ret = mwifiex_pcie_process_event_ready(adapter);
+ if (ret)
+ return ret;
+ }
+
+ if (adapter->int_status & HOST_INTR_CMD_DONE) {
+ adapter->int_status &= ~HOST_INTR_CMD_DONE;
+ if (adapter->cmd_sent) {
+ dev_dbg(adapter->dev, "info: CMD sent Interrupt\n");
+ adapter->cmd_sent = false;
+ }
+ /* Handle command response */
+ ret = mwifiex_pcie_process_cmd_complete(adapter);
+ if (ret)
+ return ret;
+ }
+
+ if (mwifiex_pcie_ok_to_access_hw(adapter)) {
+ if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS,
+ &pcie_ireg)) {
+ dev_warn(adapter->dev, "Read register failed\n");
+ return -1;
+ }
+
+ if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
+ if (mwifiex_write_reg(adapter,
+ PCIE_HOST_INT_STATUS, ~pcie_ireg)) {
+ dev_warn(adapter->dev, "Write register"
+ " failed\n");
+ return -1;
+ }
+ adapter->int_status |= pcie_ireg;
+ adapter->int_status &= HOST_INTR_MASK;
+ }
+
+ }
+ }
+ dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n",
+ adapter->cmd_sent, adapter->data_sent);
+ mwifiex_pcie_enable_host_int(adapter);
+
+ return 0;
+}
+
+/*
+ * This function downloads data from driver to card.
+ *
+ * Both commands and data packets are transferred to the card by this
+ * function.
+ *
+ * This function adds the PCIE specific header to the front of the buffer
+ * before transferring. The header contains the length of the packet and
+ * the type. The firmware handles the packets based upon this set type.
+ */
+static int mwifiex_pcie_host_to_card(struct mwifiex_adapter *adapter, u8 type,
+ struct sk_buff *skb,
+ struct mwifiex_tx_param *tx_param)
+{
+ if (!adapter || !skb) {
+ dev_err(adapter->dev, "Invalid parameter in %s <%p, %p>\n",
+ __func__, adapter, skb);
+ return -1;
+ }
+
+ if (type == MWIFIEX_TYPE_DATA)
+ return mwifiex_pcie_send_data(adapter, skb);
+ else if (type == MWIFIEX_TYPE_CMD)
+ return mwifiex_pcie_send_cmd(adapter, skb);
+
+ return 0;
+}
+
+/*
+ * This function initializes the PCI-E host memory space, WCB rings, etc.
+ *
+ * The following initializations steps are followed -
+ * - Allocate TXBD ring buffers
+ * - Allocate RXBD ring buffers
+ * - Allocate event BD ring buffers
+ * - Allocate command response ring buffer
+ * - Allocate sleep cookie buffer
+ */
+static int mwifiex_pcie_init(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ int ret;
+ struct pci_dev *pdev = card->dev;
+
+ pci_set_drvdata(pdev, card);
+
+ ret = pci_enable_device(pdev);
+ if (ret)
+ goto err_enable_dev;
+
+ pci_set_master(pdev);
+
+ dev_dbg(adapter->dev, "try set_consistent_dma_mask(32)\n");
+ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(adapter->dev, "set_dma_mask(32) failed\n");
+ goto err_set_dma_mask;
+ }
+
+ ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(adapter->dev, "set_consistent_dma_mask(64) failed\n");
+ goto err_set_dma_mask;
+ }
+
+ ret = pci_request_region(pdev, 0, DRV_NAME);
+ if (ret) {
+ dev_err(adapter->dev, "req_reg(0) error\n");
+ goto err_req_region0;
+ }
+ card->pci_mmap = pci_iomap(pdev, 0, 0);
+ if (!card->pci_mmap) {
+ dev_err(adapter->dev, "iomap(0) error\n");
+ goto err_iomap0;
+ }
+ ret = pci_request_region(pdev, 2, DRV_NAME);
+ if (ret) {
+ dev_err(adapter->dev, "req_reg(2) error\n");
+ goto err_req_region2;
+ }
+ card->pci_mmap1 = pci_iomap(pdev, 2, 0);
+ if (!card->pci_mmap1) {
+ dev_err(adapter->dev, "iomap(2) error\n");
+ goto err_iomap2;
+ }
+
+ dev_dbg(adapter->dev, "PCI memory map Virt0: %p PCI memory map Virt2: "
+ "%p\n", card->pci_mmap, card->pci_mmap1);
+
+ card->cmdrsp_buf = NULL;
+ ret = mwifiex_pcie_create_txbd_ring(adapter);
+ if (ret)
+ goto err_cre_txbd;
+ ret = mwifiex_pcie_create_rxbd_ring(adapter);
+ if (ret)
+ goto err_cre_rxbd;
+ ret = mwifiex_pcie_create_evtbd_ring(adapter);
+ if (ret)
+ goto err_cre_evtbd;
+ ret = mwifiex_pcie_alloc_cmdrsp_buf(adapter);
+ if (ret)
+ goto err_alloc_cmdbuf;
+ ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter);
+ if (ret)
+ goto err_alloc_cookie;
+
+ return ret;
+
+err_alloc_cookie:
+ mwifiex_pcie_delete_cmdrsp_buf(adapter);
+err_alloc_cmdbuf:
+ mwifiex_pcie_delete_evtbd_ring(adapter);
+err_cre_evtbd:
+ mwifiex_pcie_delete_rxbd_ring(adapter);
+err_cre_rxbd:
+ mwifiex_pcie_delete_txbd_ring(adapter);
+err_cre_txbd:
+ pci_iounmap(pdev, card->pci_mmap1);
+err_iomap2:
+ pci_release_region(pdev, 2);
+err_req_region2:
+ pci_iounmap(pdev, card->pci_mmap);
+err_iomap0:
+ pci_release_region(pdev, 0);
+err_req_region0:
+err_set_dma_mask:
+ pci_disable_device(pdev);
+err_enable_dev:
+ pci_set_drvdata(pdev, NULL);
+ return ret;
+}
+
+/*
+ * This function cleans up the allocated card buffers.
+ *
+ * The following are freed by this function -
+ * - TXBD ring buffers
+ * - RXBD ring buffers
+ * - Event BD ring buffers
+ * - Command response ring buffer
+ * - Sleep cookie buffer
+ */
+static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ struct pci_dev *pdev = card->dev;
+
+ mwifiex_pcie_delete_sleep_cookie_buf(adapter);
+ mwifiex_pcie_delete_cmdrsp_buf(adapter);
+ mwifiex_pcie_delete_evtbd_ring(adapter);
+ mwifiex_pcie_delete_rxbd_ring(adapter);
+ mwifiex_pcie_delete_txbd_ring(adapter);
+ card->cmdrsp_buf = NULL;
+
+ dev_dbg(adapter->dev, "Clearing driver ready signature\n");
+ if (user_rmmod) {
+ if (mwifiex_write_reg(adapter, REG_DRV_READY, 0x00000000))
+ dev_err(adapter->dev, "Failed to write driver not-ready signature\n");
+ }
+
+ if (pdev) {
+ pci_iounmap(pdev, card->pci_mmap);
+ pci_iounmap(pdev, card->pci_mmap1);
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ }
+}
+
+/*
+ * This function registers the PCIE device.
+ *
+ * PCIE IRQ is claimed, block size is set and driver data is initialized.
+ */
+static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
+{
+ int ret;
+ struct pcie_service_card *card = adapter->card;
+ struct pci_dev *pdev = card->dev;
+
+ /* save adapter pointer in card */
+ card->adapter = adapter;
+
+ ret = request_irq(pdev->irq, mwifiex_pcie_interrupt, IRQF_SHARED,
+ "MRVL_PCIE", pdev);
+ if (ret) {
+ pr_err("request_irq failed: ret=%d\n", ret);
+ adapter->card = NULL;
+ return -1;
+ }
+
+ adapter->dev = &pdev->dev;
+ strcpy(adapter->fw_name, PCIE8766_DEFAULT_FW_NAME);
+
+ return 0;
+}
+
+/*
+ * This function unregisters the PCIE device.
+ *
+ * The PCIE IRQ is released, the function is disabled and driver
+ * data is set to null.
+ */
+static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+
+ if (card) {
+ dev_dbg(adapter->dev, "%s(): calling free_irq()\n", __func__);
+ free_irq(card->dev->irq, card->dev);
+ }
+}
+
+static struct mwifiex_if_ops pcie_ops = {
+ .init_if = mwifiex_pcie_init,
+ .cleanup_if = mwifiex_pcie_cleanup,
+ .check_fw_status = mwifiex_check_fw_status,
+ .prog_fw = mwifiex_prog_fw_w_helper,
+ .register_dev = mwifiex_register_dev,
+ .unregister_dev = mwifiex_unregister_dev,
+ .enable_int = mwifiex_pcie_enable_host_int,
+ .process_int_status = mwifiex_process_int_status,
+ .host_to_card = mwifiex_pcie_host_to_card,
+ .wakeup = mwifiex_pm_wakeup_card,
+ .wakeup_complete = mwifiex_pm_wakeup_card_complete,
+
+ /* PCIE specific */
+ .cmdrsp_complete = mwifiex_pcie_cmdrsp_complete,
+ .event_complete = mwifiex_pcie_event_complete,
+ .update_mp_end_port = NULL,
+ .cleanup_mpa_buf = NULL,
+};
+
+/*
+ * This function initializes the PCIE driver module.
+ *
+ * This initiates the semaphore and registers the device with
+ * PCIE bus.
+ */
+static int mwifiex_pcie_init_module(void)
+{
+ int ret;
+
+ pr_debug("Marvell 8766 PCIe Driver\n");
+
+ sema_init(&add_remove_card_sem, 1);
+
+ /* Clear the flag in case user removes the card. */
+ user_rmmod = 0;
+
+ ret = pci_register_driver(&mwifiex_pcie);
+ if (ret)
+ pr_err("Driver register failed!\n");
+ else
+ pr_debug("info: Driver registered successfully!\n");
+
+ return ret;
+}
+
+/*
+ * This function cleans up the PCIE driver.
+ *
+ * The following major steps are followed for cleanup -
+ * - Resume the device if its suspended
+ * - Disconnect the device if connected
+ * - Shutdown the firmware
+ * - Unregister the device from PCIE bus.
+ */
+static void mwifiex_pcie_cleanup_module(void)
+{
+ if (!down_interruptible(&add_remove_card_sem))
+ up(&add_remove_card_sem);
+
+ /* Set the flag as user is removing this module. */
+ user_rmmod = 1;
+
+ pci_unregister_driver(&mwifiex_pcie);
+}
+
+module_init(mwifiex_pcie_init_module);
+module_exit(mwifiex_pcie_cleanup_module);
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_DESCRIPTION("Marvell WiFi-Ex PCI-Express Driver version " PCIE_VERSION);
+MODULE_VERSION(PCIE_VERSION);
+MODULE_LICENSE("GPL v2");
+MODULE_FIRMWARE("mrvl/pcie8766_uapsta.bin");
diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h
new file mode 100644
index 000000000000..445ff21772e2
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/pcie.h
@@ -0,0 +1,148 @@
+/* @file mwifiex_pcie.h
+ *
+ * @brief This file contains definitions for PCI-E interface.
+ * driver.
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef _MWIFIEX_PCIE_H
+#define _MWIFIEX_PCIE_H
+
+#include <linux/pci.h>
+#include <linux/pcieport_if.h>
+#include <linux/interrupt.h>
+
+#include "main.h"
+
+#define PCIE8766_DEFAULT_FW_NAME "mrvl/pcie8766_uapsta.bin"
+
+/* Constants for Buffer Descriptor (BD) rings */
+#define MWIFIEX_MAX_TXRX_BD 0x20
+#define MWIFIEX_TXBD_MASK 0x3F
+#define MWIFIEX_RXBD_MASK 0x3F
+
+#define MWIFIEX_MAX_EVT_BD 0x04
+#define MWIFIEX_EVTBD_MASK 0x07
+
+/* PCIE INTERNAL REGISTERS */
+#define PCIE_SCRATCH_0_REG 0xC10
+#define PCIE_SCRATCH_1_REG 0xC14
+#define PCIE_CPU_INT_EVENT 0xC18
+#define PCIE_CPU_INT_STATUS 0xC1C
+#define PCIE_HOST_INT_STATUS 0xC30
+#define PCIE_HOST_INT_MASK 0xC34
+#define PCIE_HOST_INT_STATUS_MASK 0xC3C
+#define PCIE_SCRATCH_2_REG 0xC40
+#define PCIE_SCRATCH_3_REG 0xC44
+#define PCIE_SCRATCH_4_REG 0xCC0
+#define PCIE_SCRATCH_5_REG 0xCC4
+#define PCIE_SCRATCH_6_REG 0xCC8
+#define PCIE_SCRATCH_7_REG 0xCCC
+#define PCIE_SCRATCH_8_REG 0xCD0
+#define PCIE_SCRATCH_9_REG 0xCD4
+#define PCIE_SCRATCH_10_REG 0xCD8
+#define PCIE_SCRATCH_11_REG 0xCDC
+#define PCIE_SCRATCH_12_REG 0xCE0
+
+#define CPU_INTR_DNLD_RDY BIT(0)
+#define CPU_INTR_DOOR_BELL BIT(1)
+#define CPU_INTR_SLEEP_CFM_DONE BIT(2)
+#define CPU_INTR_RESET BIT(3)
+
+#define HOST_INTR_DNLD_DONE BIT(0)
+#define HOST_INTR_UPLD_RDY BIT(1)
+#define HOST_INTR_CMD_DONE BIT(2)
+#define HOST_INTR_EVENT_RDY BIT(3)
+#define HOST_INTR_MASK (HOST_INTR_DNLD_DONE | \
+ HOST_INTR_UPLD_RDY | \
+ HOST_INTR_CMD_DONE | \
+ HOST_INTR_EVENT_RDY)
+
+#define MWIFIEX_BD_FLAG_ROLLOVER_IND BIT(7)
+#define MWIFIEX_BD_FLAG_FIRST_DESC BIT(0)
+#define MWIFIEX_BD_FLAG_LAST_DESC BIT(1)
+#define REG_CMD_ADDR_LO PCIE_SCRATCH_0_REG
+#define REG_CMD_ADDR_HI PCIE_SCRATCH_1_REG
+#define REG_CMD_SIZE PCIE_SCRATCH_2_REG
+
+#define REG_CMDRSP_ADDR_LO PCIE_SCRATCH_4_REG
+#define REG_CMDRSP_ADDR_HI PCIE_SCRATCH_5_REG
+
+/* TX buffer description read pointer */
+#define REG_TXBD_RDPTR PCIE_SCRATCH_6_REG
+/* TX buffer description write pointer */
+#define REG_TXBD_WRPTR PCIE_SCRATCH_7_REG
+/* RX buffer description read pointer */
+#define REG_RXBD_RDPTR PCIE_SCRATCH_8_REG
+/* RX buffer description write pointer */
+#define REG_RXBD_WRPTR PCIE_SCRATCH_9_REG
+/* Event buffer description read pointer */
+#define REG_EVTBD_RDPTR PCIE_SCRATCH_10_REG
+/* Event buffer description write pointer */
+#define REG_EVTBD_WRPTR PCIE_SCRATCH_11_REG
+/* Driver ready signature write pointer */
+#define REG_DRV_READY PCIE_SCRATCH_12_REG
+
+/* Max retry number of command write */
+#define MAX_WRITE_IOMEM_RETRY 2
+/* Define PCIE block size for firmware download */
+#define MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD 256
+/* FW awake cookie after FW ready */
+#define FW_AWAKE_COOKIE (0xAA55AA55)
+
+struct mwifiex_pcie_buf_desc {
+ u64 paddr;
+ u16 len;
+ u16 flags;
+} __packed;
+
+struct pcie_service_card {
+ struct pci_dev *dev;
+ struct mwifiex_adapter *adapter;
+
+ u32 txbd_wrptr;
+ u32 txbd_rdptr;
+ u32 txbd_ring_size;
+ u8 *txbd_ring_vbase;
+ phys_addr_t txbd_ring_pbase;
+ struct mwifiex_pcie_buf_desc *txbd_ring[MWIFIEX_MAX_TXRX_BD];
+ struct sk_buff *tx_buf_list[MWIFIEX_MAX_TXRX_BD];
+
+ u32 rxbd_wrptr;
+ u32 rxbd_rdptr;
+ u32 rxbd_ring_size;
+ u8 *rxbd_ring_vbase;
+ phys_addr_t rxbd_ring_pbase;
+ struct mwifiex_pcie_buf_desc *rxbd_ring[MWIFIEX_MAX_TXRX_BD];
+ struct sk_buff *rx_buf_list[MWIFIEX_MAX_TXRX_BD];
+
+ u32 evtbd_wrptr;
+ u32 evtbd_rdptr;
+ u32 evtbd_ring_size;
+ u8 *evtbd_ring_vbase;
+ phys_addr_t evtbd_ring_pbase;
+ struct mwifiex_pcie_buf_desc *evtbd_ring[MWIFIEX_MAX_EVT_BD];
+ struct sk_buff *evt_buf_list[MWIFIEX_MAX_EVT_BD];
+
+ struct sk_buff *cmd_buf;
+ struct sk_buff *cmdrsp_buf;
+ struct sk_buff *sleep_cookie;
+ void __iomem *pci_mmap;
+ void __iomem *pci_mmap1;
+};
+
+#endif /* _MWIFIEX_PCIE_H */
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index 6f88c8ab5de5..dae8dbb24a03 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -172,59 +172,6 @@ mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1,
}
/*
- * Sends IOCTL request to get the best BSS.
- *
- * This function allocates the IOCTL request buffer, fills it
- * with requisite parameters and calls the IOCTL handler.
- */
-int mwifiex_find_best_bss(struct mwifiex_private *priv,
- struct mwifiex_ssid_bssid *ssid_bssid)
-{
- struct mwifiex_ssid_bssid tmp_ssid_bssid;
- u8 *mac;
-
- if (!ssid_bssid)
- return -1;
-
- memcpy(&tmp_ssid_bssid, ssid_bssid,
- sizeof(struct mwifiex_ssid_bssid));
-
- if (!mwifiex_bss_ioctl_find_bss(priv, &tmp_ssid_bssid)) {
- memcpy(ssid_bssid, &tmp_ssid_bssid,
- sizeof(struct mwifiex_ssid_bssid));
- mac = (u8 *) &ssid_bssid->bssid;
- dev_dbg(priv->adapter->dev, "cmd: found network: ssid=%s,"
- " %pM\n", ssid_bssid->ssid.ssid, mac);
- return 0;
- }
-
- return -1;
-}
-
-/*
- * Sends IOCTL request to start a scan with user configurations.
- *
- * This function allocates the IOCTL request buffer, fills it
- * with requisite parameters and calls the IOCTL handler.
- *
- * Upon completion, it also generates a wireless event to notify
- * applications.
- */
-int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv,
- struct mwifiex_user_scan_cfg *scan_req)
-{
- int status;
-
- priv->adapter->cmd_wait_q.condition = false;
-
- status = mwifiex_scan_networks(priv, scan_req);
- if (!status)
- status = mwifiex_wait_queue_complete(priv->adapter);
-
- return status;
-}
-
-/*
* This function checks if wapi is enabled in driver and scanned network is
* compatible with it.
*/
@@ -286,8 +233,7 @@ mwifiex_is_network_compatible_for_static_wep(struct mwifiex_private *priv,
*/
static bool
mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv,
- struct mwifiex_bssdescriptor *bss_desc,
- int index)
+ 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
@@ -298,9 +244,9 @@ mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv,
* LinkSys WRT54G && bss_desc->privacy
*/
) {
- dev_dbg(priv->adapter->dev, "info: %s: WPA: index=%d"
+ dev_dbg(priv->adapter->dev, "info: %s: WPA:"
" wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
- "EncMode=%#x privacy=%#x\n", __func__, index,
+ "EncMode=%#x privacy=%#x\n", __func__,
(bss_desc->bcn_wpa_ie) ?
(*(bss_desc->bcn_wpa_ie)).
vend_hdr.element_id : 0,
@@ -324,8 +270,7 @@ mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv,
*/
static bool
mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv,
- struct mwifiex_bssdescriptor *bss_desc,
- int index)
+ 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
@@ -336,9 +281,9 @@ mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv,
* LinkSys WRT54G && bss_desc->privacy
*/
) {
- dev_dbg(priv->adapter->dev, "info: %s: WPA2: index=%d"
+ dev_dbg(priv->adapter->dev, "info: %s: WPA2: "
" wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
- "EncMode=%#x privacy=%#x\n", __func__, index,
+ "EncMode=%#x privacy=%#x\n", __func__,
(bss_desc->bcn_wpa_ie) ?
(*(bss_desc->bcn_wpa_ie)).
vend_hdr.element_id : 0,
@@ -383,8 +328,7 @@ mwifiex_is_network_compatible_for_adhoc_aes(struct mwifiex_private *priv,
*/
static bool
mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv,
- struct mwifiex_bssdescriptor *bss_desc,
- int index)
+ 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
@@ -395,9 +339,9 @@ mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv,
&& priv->sec_info.encryption_mode
&& bss_desc->privacy) {
dev_dbg(priv->adapter->dev, "info: %s: dynamic "
- "WEP: index=%d wpa_ie=%#x wpa2_ie=%#x "
+ "WEP: wpa_ie=%#x wpa2_ie=%#x "
"EncMode=%#x privacy=%#x\n",
- __func__, index,
+ __func__,
(bss_desc->bcn_wpa_ie) ?
(*(bss_desc->bcn_wpa_ie)).
vend_hdr.element_id : 0,
@@ -430,42 +374,41 @@ mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv,
* Compatibility is not matched while roaming, except for mode.
*/
static s32
-mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode)
+mwifiex_is_network_compatible(struct mwifiex_private *priv,
+ struct mwifiex_bssdescriptor *bss_desc, u32 mode)
{
struct mwifiex_adapter *adapter = priv->adapter;
- struct mwifiex_bssdescriptor *bss_desc;
- bss_desc = &adapter->scan_table[index];
bss_desc->disable_11n = false;
/* Don't check for compatibility if roaming */
if (priv->media_connected && (priv->bss_mode == NL80211_IFTYPE_STATION)
&& (bss_desc->bss_mode == NL80211_IFTYPE_STATION))
- return index;
+ return 0;
if (priv->wps.session_enable) {
dev_dbg(adapter->dev,
"info: return success directly in WPS period\n");
- return index;
+ return 0;
}
if (mwifiex_is_network_compatible_for_wapi(priv, bss_desc)) {
dev_dbg(adapter->dev, "info: return success for WAPI AP\n");
- return index;
+ return 0;
}
if (bss_desc->bss_mode == mode) {
if (mwifiex_is_network_compatible_for_no_sec(priv, bss_desc)) {
/* No security */
- return index;
+ return 0;
} else if (mwifiex_is_network_compatible_for_static_wep(priv,
bss_desc)) {
/* Static WEP enabled */
dev_dbg(adapter->dev, "info: Disable 11n in WEP mode.\n");
bss_desc->disable_11n = true;
- return index;
- } else if (mwifiex_is_network_compatible_for_wpa(priv, bss_desc,
- index)) {
+ return 0;
+ } else if (mwifiex_is_network_compatible_for_wpa(priv,
+ bss_desc)) {
/* WPA enabled */
if (((priv->adapter->config_bands & BAND_GN
|| priv->adapter->config_bands & BAND_AN)
@@ -483,9 +426,9 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode)
return -1;
}
}
- return index;
+ return 0;
} else if (mwifiex_is_network_compatible_for_wpa2(priv,
- bss_desc, index)) {
+ bss_desc)) {
/* WPA2 enabled */
if (((priv->adapter->config_bands & BAND_GN
|| priv->adapter->config_bands & BAND_AN)
@@ -503,22 +446,22 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode)
return -1;
}
}
- return index;
+ return 0;
} else if (mwifiex_is_network_compatible_for_adhoc_aes(priv,
bss_desc)) {
/* Ad-hoc AES enabled */
- return index;
+ return 0;
} else if (mwifiex_is_network_compatible_for_dynamic_wep(priv,
- bss_desc, index)) {
+ bss_desc)) {
/* Dynamic WEP enabled */
- return index;
+ return 0;
}
/* Security doesn't match */
- dev_dbg(adapter->dev, "info: %s: failed: index=%d "
+ dev_dbg(adapter->dev, "info: %s: failed: "
"wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode"
"=%#x privacy=%#x\n",
- __func__, index,
+ __func__,
(bss_desc->bcn_wpa_ie) ?
(*(bss_desc->bcn_wpa_ie)).vend_hdr.
element_id : 0,
@@ -538,52 +481,6 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode)
}
/*
- * This function finds the best SSID in the scan list.
- *
- * It searches the scan table for the best SSID that also matches the current
- * adapter network preference (mode, security etc.).
- */
-static s32
-mwifiex_find_best_network_in_list(struct mwifiex_private *priv)
-{
- struct mwifiex_adapter *adapter = priv->adapter;
- u32 mode = priv->bss_mode;
- s32 best_net = -1;
- s32 best_rssi = 0;
- u32 i;
-
- dev_dbg(adapter->dev, "info: num of BSSIDs = %d\n",
- adapter->num_in_scan_table);
-
- for (i = 0; i < adapter->num_in_scan_table; i++) {
- switch (mode) {
- case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_ADHOC:
- if (mwifiex_is_network_compatible(priv, i, mode) >= 0) {
- if (SCAN_RSSI(adapter->scan_table[i].rssi) >
- best_rssi) {
- best_rssi = SCAN_RSSI(adapter->
- scan_table[i].rssi);
- best_net = i;
- }
- }
- break;
- case NL80211_IFTYPE_UNSPECIFIED:
- default:
- if (SCAN_RSSI(adapter->scan_table[i].rssi) >
- best_rssi) {
- best_rssi = SCAN_RSSI(adapter->scan_table[i].
- rssi);
- best_net = i;
- }
- break;
- }
- }
-
- return best_net;
-}
-
-/*
* This function creates a channel list for the driver to scan, based
* on region/band information.
*
@@ -612,7 +509,7 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
sband = priv->wdev->wiphy->bands[band];
- for (i = 0; (i < sband->n_channels) ; i++, chan_idx++) {
+ for (i = 0; (i < sband->n_channels) ; i++) {
ch = &sband->channels[i];
if (ch->flags & IEEE80211_CHAN_DISABLED)
continue;
@@ -643,6 +540,7 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
scan_chan_list[chan_idx].chan_scan_mode_bitmap
|= MWIFIEX_DISABLE_CHAN_FILT;
}
+ chan_idx++;
}
}
@@ -1161,34 +1059,13 @@ mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter,
}
/*
- * This function interprets a BSS scan response returned from the firmware.
- *
- * The various fixed fields and IEs are parsed and passed back for a BSS
- * probe response or beacon from scan command. Information is recorded as
- * needed in the scan table for that entry.
- *
- * The following IE types are recognized and parsed -
- * - SSID
- * - Supported rates
- * - FH parameters set
- * - DS parameters set
- * - CF parameters set
- * - IBSS parameters set
- * - ERP information
- * - Extended supported rates
- * - Vendor specific (221)
- * - RSN IE
- * - WAPI IE
- * - HT capability
- * - HT operation
- * - BSS Coexistence 20/40
- * - Extended capability
- * - Overlapping BSS scan parameters
+ * This function parses provided beacon buffer and updates
+ * respective fields in bss descriptor structure.
*/
-static int
-mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter,
- struct mwifiex_bssdescriptor *bss_entry,
- u8 **beacon_info, u32 *bytes_left)
+int
+mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
+ struct mwifiex_bssdescriptor *bss_entry,
+ u8 *ie_buf, u32 ie_len)
{
int ret = 0;
u8 element_id;
@@ -1196,135 +1073,43 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter,
struct ieee_types_ds_param_set *ds_param_set;
struct ieee_types_cf_param_set *cf_param_set;
struct ieee_types_ibss_param_set *ibss_param_set;
- __le16 beacon_interval;
- __le16 capabilities;
u8 *current_ptr;
u8 *rate;
u8 element_len;
u16 total_ie_len;
u8 bytes_to_copy;
u8 rate_size;
- u16 beacon_size;
u8 found_data_rate_ie;
- u32 bytes_left_for_current_beacon;
+ u32 bytes_left;
struct ieee_types_vendor_specific *vendor_ie;
const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 };
found_data_rate_ie = false;
rate_size = 0;
- beacon_size = 0;
-
- if (*bytes_left >= sizeof(beacon_size)) {
- /* Extract & convert beacon size from the command buffer */
- memcpy(&beacon_size, *beacon_info, sizeof(beacon_size));
- *bytes_left -= sizeof(beacon_size);
- *beacon_info += sizeof(beacon_size);
- }
-
- if (!beacon_size || beacon_size > *bytes_left) {
- *beacon_info += *bytes_left;
- *bytes_left = 0;
- return -1;
- }
-
- /* Initialize the current working beacon pointer for this BSS
- iteration */
- current_ptr = *beacon_info;
-
- /* Advance the return beacon pointer past the current beacon */
- *beacon_info += beacon_size;
- *bytes_left -= beacon_size;
-
- bytes_left_for_current_beacon = beacon_size;
-
- memcpy(bss_entry->mac_address, current_ptr, ETH_ALEN);
- dev_dbg(adapter->dev, "info: InterpretIE: AP MAC Addr: %pM\n",
- bss_entry->mac_address);
-
- current_ptr += ETH_ALEN;
- bytes_left_for_current_beacon -= ETH_ALEN;
-
- if (bytes_left_for_current_beacon < 12) {
- dev_err(adapter->dev, "InterpretIE: not enough bytes left\n");
- return -1;
- }
-
- /*
- * Next 4 fields are RSSI, time stamp, beacon interval,
- * and capability information
- */
-
- /* RSSI is 1 byte long */
- bss_entry->rssi = (s32) (*current_ptr);
- dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n", *current_ptr);
- current_ptr += 1;
- bytes_left_for_current_beacon -= 1;
-
- /*
- * The RSSI is not part of the beacon/probe response. After we have
- * advanced current_ptr past the RSSI field, save the remaining
- * data for use at the application layer
- */
- bss_entry->beacon_buf = current_ptr;
- bss_entry->beacon_buf_size = bytes_left_for_current_beacon;
-
- /* Time stamp is 8 bytes long */
- memcpy(bss_entry->time_stamp, current_ptr, 8);
- current_ptr += 8;
- bytes_left_for_current_beacon -= 8;
-
- /* Beacon interval is 2 bytes long */
- memcpy(&beacon_interval, current_ptr, 2);
- bss_entry->beacon_period = le16_to_cpu(beacon_interval);
- current_ptr += 2;
- bytes_left_for_current_beacon -= 2;
-
- /* Capability information is 2 bytes long */
- memcpy(&capabilities, current_ptr, 2);
- dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n",
- capabilities);
- bss_entry->cap_info_bitmap = le16_to_cpu(capabilities);
- current_ptr += 2;
- bytes_left_for_current_beacon -= 2;
-
- /* Rest of the current buffer are IE's */
- dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP = %d\n",
- bytes_left_for_current_beacon);
-
- if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {
- dev_dbg(adapter->dev, "info: InterpretIE: AP WEP enabled\n");
- bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
- } else {
- bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
- }
-
- if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_IBSS)
- bss_entry->bss_mode = NL80211_IFTYPE_ADHOC;
- else
- bss_entry->bss_mode = NL80211_IFTYPE_STATION;
-
+ current_ptr = ie_buf;
+ bytes_left = ie_len;
+ bss_entry->beacon_buf = ie_buf;
+ bss_entry->beacon_buf_size = ie_len;
/* Process variable IE */
- while (bytes_left_for_current_beacon >= 2) {
+ while (bytes_left >= 2) {
element_id = *current_ptr;
element_len = *(current_ptr + 1);
total_ie_len = element_len + sizeof(struct ieee_types_header);
- if (bytes_left_for_current_beacon < total_ie_len) {
+ if (bytes_left < total_ie_len) {
dev_err(adapter->dev, "err: InterpretIE: in processing"
" IE, bytes left < IE length\n");
- bytes_left_for_current_beacon = 0;
- ret = -1;
- continue;
+ return -1;
}
switch (element_id) {
case WLAN_EID_SSID:
bss_entry->ssid.ssid_len = element_len;
memcpy(bss_entry->ssid.ssid, (current_ptr + 2),
element_len);
- dev_dbg(adapter->dev, "info: InterpretIE: ssid: %-32s\n",
- bss_entry->ssid.ssid);
+ dev_dbg(adapter->dev, "info: InterpretIE: ssid: "
+ "%-32s\n", bss_entry->ssid.ssid);
break;
case WLAN_EID_SUPP_RATES:
@@ -1471,13 +1256,6 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter,
sizeof(struct ieee_types_header) -
bss_entry->beacon_buf);
break;
- case WLAN_EID_OVERLAP_BSS_SCAN_PARAM:
- bss_entry->bcn_obss_scan =
- (struct ieee_types_obss_scan_param *)
- current_ptr;
- bss_entry->overlap_bss_offset = (u16) (current_ptr -
- bss_entry->beacon_buf);
- break;
default:
break;
}
@@ -1485,577 +1263,13 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter,
current_ptr += element_len + 2;
/* Need to account for IE ID and IE Len */
- bytes_left_for_current_beacon -= (element_len + 2);
+ bytes_left -= (element_len + 2);
- } /* while (bytes_left_for_current_beacon > 2) */
+ } /* while (bytes_left > 2) */
return ret;
}
/*
- * This function adjusts the pointers used in beacon buffers to reflect
- * shifts.
- *
- * The memory allocated for beacon buffers is of fixed sizes where all the
- * saved beacons must be stored. New beacons are added in the free portion
- * of this memory, space permitting; while duplicate beacon buffers are
- * placed at the same start location. However, since duplicate beacon
- * buffers may not match the size of the old one, all the following buffers
- * in the memory must be shifted to either make space, or to fill up freed
- * up space.
- *
- * This function is used to update the beacon buffer pointers that are past
- * an existing beacon buffer that is updated with a new one of different
- * size. The pointers are shifted by a fixed amount, either forward or
- * backward.
- *
- * the following pointers in every affected beacon buffers are changed, if
- * present -
- * - WPA IE pointer
- * - RSN IE pointer
- * - WAPI IE pointer
- * - HT capability IE pointer
- * - HT information IE pointer
- * - BSS coexistence 20/40 IE pointer
- * - Extended capability IE pointer
- * - Overlapping BSS scan parameter IE pointer
- */
-static void
-mwifiex_adjust_beacon_buffer_ptrs(struct mwifiex_private *priv, u8 advance,
- u8 *bcn_store, u32 rem_bcn_size,
- u32 num_of_ent)
-{
- struct mwifiex_adapter *adapter = priv->adapter;
- u32 adj_idx;
- for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) {
- if (adapter->scan_table[adj_idx].beacon_buf > bcn_store) {
-
- if (advance)
- adapter->scan_table[adj_idx].beacon_buf +=
- rem_bcn_size;
- else
- adapter->scan_table[adj_idx].beacon_buf -=
- rem_bcn_size;
-
- if (adapter->scan_table[adj_idx].bcn_wpa_ie)
- adapter->scan_table[adj_idx].bcn_wpa_ie =
- (struct ieee_types_vendor_specific *)
- (adapter->scan_table[adj_idx].beacon_buf +
- adapter->scan_table[adj_idx].wpa_offset);
- if (adapter->scan_table[adj_idx].bcn_rsn_ie)
- adapter->scan_table[adj_idx].bcn_rsn_ie =
- (struct ieee_types_generic *)
- (adapter->scan_table[adj_idx].beacon_buf +
- adapter->scan_table[adj_idx].rsn_offset);
- if (adapter->scan_table[adj_idx].bcn_wapi_ie)
- adapter->scan_table[adj_idx].bcn_wapi_ie =
- (struct ieee_types_generic *)
- (adapter->scan_table[adj_idx].beacon_buf +
- adapter->scan_table[adj_idx].wapi_offset);
- if (adapter->scan_table[adj_idx].bcn_ht_cap)
- adapter->scan_table[adj_idx].bcn_ht_cap =
- (struct ieee80211_ht_cap *)
- (adapter->scan_table[adj_idx].beacon_buf +
- adapter->scan_table[adj_idx].ht_cap_offset);
-
- if (adapter->scan_table[adj_idx].bcn_ht_info)
- adapter->scan_table[adj_idx].bcn_ht_info =
- (struct ieee80211_ht_info *)
- (adapter->scan_table[adj_idx].beacon_buf +
- adapter->scan_table[adj_idx].ht_info_offset);
- if (adapter->scan_table[adj_idx].bcn_bss_co_2040)
- adapter->scan_table[adj_idx].bcn_bss_co_2040 =
- (u8 *)
- (adapter->scan_table[adj_idx].beacon_buf +
- adapter->scan_table[adj_idx].bss_co_2040_offset);
- if (adapter->scan_table[adj_idx].bcn_ext_cap)
- adapter->scan_table[adj_idx].bcn_ext_cap =
- (u8 *)
- (adapter->scan_table[adj_idx].beacon_buf +
- adapter->scan_table[adj_idx].ext_cap_offset);
- if (adapter->scan_table[adj_idx].bcn_obss_scan)
- adapter->scan_table[adj_idx].bcn_obss_scan =
- (struct ieee_types_obss_scan_param *)
- (adapter->scan_table[adj_idx].beacon_buf +
- adapter->scan_table[adj_idx].overlap_bss_offset);
- }
- }
-}
-
-/*
- * This function updates the pointers used in beacon buffer for given bss
- * descriptor to reflect shifts
- *
- * Following pointers are updated
- * - WPA IE pointer
- * - RSN IE pointer
- * - WAPI IE pointer
- * - HT capability IE pointer
- * - HT information IE pointer
- * - BSS coexistence 20/40 IE pointer
- * - Extended capability IE pointer
- * - Overlapping BSS scan parameter IE pointer
- */
-static void
-mwifiex_update_beacon_buffer_ptrs(struct mwifiex_bssdescriptor *beacon)
-{
- if (beacon->bcn_wpa_ie)
- beacon->bcn_wpa_ie = (struct ieee_types_vendor_specific *)
- (beacon->beacon_buf + beacon->wpa_offset);
- if (beacon->bcn_rsn_ie)
- beacon->bcn_rsn_ie = (struct ieee_types_generic *)
- (beacon->beacon_buf + beacon->rsn_offset);
- if (beacon->bcn_wapi_ie)
- beacon->bcn_wapi_ie = (struct ieee_types_generic *)
- (beacon->beacon_buf + beacon->wapi_offset);
- if (beacon->bcn_ht_cap)
- beacon->bcn_ht_cap = (struct ieee80211_ht_cap *)
- (beacon->beacon_buf + beacon->ht_cap_offset);
- if (beacon->bcn_ht_info)
- beacon->bcn_ht_info = (struct ieee80211_ht_info *)
- (beacon->beacon_buf + beacon->ht_info_offset);
- if (beacon->bcn_bss_co_2040)
- beacon->bcn_bss_co_2040 = (u8 *) (beacon->beacon_buf +
- beacon->bss_co_2040_offset);
- if (beacon->bcn_ext_cap)
- beacon->bcn_ext_cap = (u8 *) (beacon->beacon_buf +
- beacon->ext_cap_offset);
- if (beacon->bcn_obss_scan)
- beacon->bcn_obss_scan = (struct ieee_types_obss_scan_param *)
- (beacon->beacon_buf + beacon->overlap_bss_offset);
-}
-
-/*
- * This function stores a beacon or probe response for a BSS returned
- * in the scan.
- *
- * This stores a new scan response or an update for a previous scan response.
- * New entries need to verify that they do not exceed the total amount of
- * memory allocated for the table.
- *
- * Replacement entries need to take into consideration the amount of space
- * currently allocated for the beacon/probe response and adjust the entry
- * as needed.
- *
- * A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved
- * for an entry in case it is a beacon since a probe response for the
- * network will by larger per the standard. This helps to reduce the
- * amount of memory copying to fit a new probe response into an entry
- * already occupied by a network's previously stored beacon.
- */
-static void
-mwifiex_ret_802_11_scan_store_beacon(struct mwifiex_private *priv,
- u32 beacon_idx, u32 num_of_ent,
- struct mwifiex_bssdescriptor *new_beacon)
-{
- struct mwifiex_adapter *adapter = priv->adapter;
- u8 *bcn_store;
- u32 new_bcn_size;
- u32 old_bcn_size;
- u32 bcn_space;
-
- if (adapter->scan_table[beacon_idx].beacon_buf) {
-
- new_bcn_size = new_beacon->beacon_buf_size;
- old_bcn_size = adapter->scan_table[beacon_idx].beacon_buf_size;
- bcn_space = adapter->scan_table[beacon_idx].beacon_buf_size_max;
- bcn_store = adapter->scan_table[beacon_idx].beacon_buf;
-
- /* Set the max to be the same as current entry unless changed
- below */
- new_beacon->beacon_buf_size_max = bcn_space;
- if (new_bcn_size == old_bcn_size) {
- /*
- * Beacon is the same size as the previous entry.
- * Replace the previous contents with the scan result
- */
- memcpy(bcn_store, new_beacon->beacon_buf,
- new_beacon->beacon_buf_size);
-
- } else if (new_bcn_size <= bcn_space) {
- /*
- * New beacon size will fit in the amount of space
- * we have previously allocated for it
- */
-
- /* Copy the new beacon buffer entry over the old one */
- memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size);
-
- /*
- * If the old beacon size was less than the maximum
- * we had alloted for the entry, and the new entry
- * is even smaller, reset the max size to the old
- * beacon entry and compress the storage space
- * (leaving a new pad space of (old_bcn_size -
- * new_bcn_size).
- */
- if (old_bcn_size < bcn_space
- && new_bcn_size <= old_bcn_size) {
- /*
- * Old Beacon size is smaller than the alloted
- * storage size. Shrink the alloted storage
- * space.
- */
- dev_dbg(adapter->dev, "info: AppControl:"
- " smaller duplicate beacon "
- "(%d), old = %d, new = %d, space = %d,"
- "left = %d\n",
- beacon_idx, old_bcn_size, new_bcn_size,
- bcn_space,
- (int)(sizeof(adapter->bcn_buf) -
- (adapter->bcn_buf_end -
- adapter->bcn_buf)));
-
- /*
- * memmove (since the memory overlaps) the
- * data after the beacon we just stored to the
- * end of the current beacon. This cleans up
- * any unused space the old larger beacon was
- * using in the buffer
- */
- memmove(bcn_store + old_bcn_size,
- bcn_store + bcn_space,
- adapter->bcn_buf_end - (bcn_store +
- bcn_space));
-
- /*
- * Decrement the end pointer by the difference
- * between the old larger size and the new
- * smaller size since we are using less space
- * due to the new beacon being smaller
- */
- adapter->bcn_buf_end -=
- (bcn_space - old_bcn_size);
-
- /* Set the maximum storage size to the old
- beacon size */
- new_beacon->beacon_buf_size_max = old_bcn_size;
-
- /* Adjust beacon buffer pointers that are past
- the current */
- mwifiex_adjust_beacon_buffer_ptrs(priv, 0,
- bcn_store, (bcn_space - old_bcn_size),
- num_of_ent);
- }
- } else if (adapter->bcn_buf_end + (new_bcn_size - bcn_space)
- < (adapter->bcn_buf + sizeof(adapter->bcn_buf))) {
- /*
- * Beacon is larger than space previously allocated
- * (bcn_space) and there is enough space left in the
- * beaconBuffer to store the additional data
- */
- dev_dbg(adapter->dev, "info: AppControl:"
- " larger duplicate beacon (%d), "
- "old = %d, new = %d, space = %d, left = %d\n",
- beacon_idx, old_bcn_size, new_bcn_size,
- bcn_space,
- (int)(sizeof(adapter->bcn_buf) -
- (adapter->bcn_buf_end -
- adapter->bcn_buf)));
-
- /*
- * memmove (since the memory overlaps) the data
- * after the beacon we just stored to the end of
- * the current beacon. This moves the data for
- * the beacons after this further in memory to
- * make space for the new larger beacon we are
- * about to copy in.
- */
- memmove(bcn_store + new_bcn_size,
- bcn_store + bcn_space,
- adapter->bcn_buf_end - (bcn_store + bcn_space));
-
- /* Copy the new beacon buffer entry over the old one */
- memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size);
-
- /* Move the beacon end pointer by the amount of new
- beacon data we are adding */
- adapter->bcn_buf_end += (new_bcn_size - bcn_space);
-
- /*
- * This entry is bigger than the alloted max space
- * previously reserved. Increase the max space to
- * be equal to the new beacon size
- */
- new_beacon->beacon_buf_size_max = new_bcn_size;
-
- /* Adjust beacon buffer pointers that are past the
- current */
- mwifiex_adjust_beacon_buffer_ptrs(priv, 1, bcn_store,
- (new_bcn_size - bcn_space),
- num_of_ent);
- } else {
- /*
- * Beacon is larger than the previously allocated space,
- * but there is not enough free space to store the
- * additional data.
- */
- dev_err(adapter->dev, "AppControl: larger duplicate "
- " beacon (%d), old = %d new = %d, space = %d,"
- " left = %d\n", beacon_idx, old_bcn_size,
- new_bcn_size, bcn_space,
- (int)(sizeof(adapter->bcn_buf) -
- (adapter->bcn_buf_end - adapter->bcn_buf)));
-
- /* Storage failure, keep old beacon intact */
- new_beacon->beacon_buf_size = old_bcn_size;
- if (new_beacon->bcn_wpa_ie)
- new_beacon->wpa_offset =
- adapter->scan_table[beacon_idx].
- wpa_offset;
- if (new_beacon->bcn_rsn_ie)
- new_beacon->rsn_offset =
- adapter->scan_table[beacon_idx].
- rsn_offset;
- if (new_beacon->bcn_wapi_ie)
- new_beacon->wapi_offset =
- adapter->scan_table[beacon_idx].
- wapi_offset;
- if (new_beacon->bcn_ht_cap)
- new_beacon->ht_cap_offset =
- adapter->scan_table[beacon_idx].
- ht_cap_offset;
- if (new_beacon->bcn_ht_info)
- new_beacon->ht_info_offset =
- adapter->scan_table[beacon_idx].
- ht_info_offset;
- if (new_beacon->bcn_bss_co_2040)
- new_beacon->bss_co_2040_offset =
- adapter->scan_table[beacon_idx].
- bss_co_2040_offset;
- if (new_beacon->bcn_ext_cap)
- new_beacon->ext_cap_offset =
- adapter->scan_table[beacon_idx].
- ext_cap_offset;
- if (new_beacon->bcn_obss_scan)
- new_beacon->overlap_bss_offset =
- adapter->scan_table[beacon_idx].
- overlap_bss_offset;
- }
- /* Point the new entry to its permanent storage space */
- new_beacon->beacon_buf = bcn_store;
- mwifiex_update_beacon_buffer_ptrs(new_beacon);
- } else {
- /*
- * No existing beacon data exists for this entry, check to see
- * if we can fit it in the remaining space
- */
- if (adapter->bcn_buf_end + new_beacon->beacon_buf_size +
- SCAN_BEACON_ENTRY_PAD < (adapter->bcn_buf +
- sizeof(adapter->bcn_buf))) {
-
- /*
- * Copy the beacon buffer data from the local entry to
- * the adapter dev struct buffer space used to store
- * the raw beacon data for each entry in the scan table
- */
- memcpy(adapter->bcn_buf_end, new_beacon->beacon_buf,
- new_beacon->beacon_buf_size);
-
- /* Update the beacon ptr to point to the table save
- area */
- new_beacon->beacon_buf = adapter->bcn_buf_end;
- new_beacon->beacon_buf_size_max =
- (new_beacon->beacon_buf_size +
- SCAN_BEACON_ENTRY_PAD);
-
- mwifiex_update_beacon_buffer_ptrs(new_beacon);
-
- /* Increment the end pointer by the size reserved */
- adapter->bcn_buf_end += new_beacon->beacon_buf_size_max;
-
- dev_dbg(adapter->dev, "info: AppControl: beacon[%02d]"
- " sz=%03d, used = %04d, left = %04d\n",
- beacon_idx,
- new_beacon->beacon_buf_size,
- (int)(adapter->bcn_buf_end - adapter->bcn_buf),
- (int)(sizeof(adapter->bcn_buf) -
- (adapter->bcn_buf_end -
- adapter->bcn_buf)));
- } else {
- /* No space for new beacon */
- dev_dbg(adapter->dev, "info: AppControl: no space for"
- " beacon (%d): %pM sz=%03d, left=%03d\n",
- beacon_idx, new_beacon->mac_address,
- new_beacon->beacon_buf_size,
- (int)(sizeof(adapter->bcn_buf) -
- (adapter->bcn_buf_end -
- adapter->bcn_buf)));
-
- /* Storage failure; clear storage records for this
- bcn */
- new_beacon->beacon_buf = NULL;
- new_beacon->beacon_buf_size = 0;
- new_beacon->beacon_buf_size_max = 0;
- new_beacon->bcn_wpa_ie = NULL;
- new_beacon->wpa_offset = 0;
- new_beacon->bcn_rsn_ie = NULL;
- new_beacon->rsn_offset = 0;
- new_beacon->bcn_wapi_ie = NULL;
- new_beacon->wapi_offset = 0;
- new_beacon->bcn_ht_cap = NULL;
- new_beacon->ht_cap_offset = 0;
- new_beacon->bcn_ht_info = NULL;
- new_beacon->ht_info_offset = 0;
- new_beacon->bcn_bss_co_2040 = NULL;
- new_beacon->bss_co_2040_offset = 0;
- new_beacon->bcn_ext_cap = NULL;
- new_beacon->ext_cap_offset = 0;
- new_beacon->bcn_obss_scan = NULL;
- new_beacon->overlap_bss_offset = 0;
- }
- }
-}
-
-/*
- * This function restores a beacon buffer of the current BSS descriptor.
- */
-static void mwifiex_restore_curr_bcn(struct mwifiex_private *priv)
-{
- struct mwifiex_adapter *adapter = priv->adapter;
- struct mwifiex_bssdescriptor *curr_bss =
- &priv->curr_bss_params.bss_descriptor;
- unsigned long flags;
-
- if (priv->curr_bcn_buf &&
- ((adapter->bcn_buf_end + priv->curr_bcn_size) <
- (adapter->bcn_buf + sizeof(adapter->bcn_buf)))) {
- spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags);
-
- /* restore the current beacon buffer */
- memcpy(adapter->bcn_buf_end, priv->curr_bcn_buf,
- priv->curr_bcn_size);
- curr_bss->beacon_buf = adapter->bcn_buf_end;
- curr_bss->beacon_buf_size = priv->curr_bcn_size;
- adapter->bcn_buf_end += priv->curr_bcn_size;
-
- /* adjust the pointers in the current BSS descriptor */
- if (curr_bss->bcn_wpa_ie)
- curr_bss->bcn_wpa_ie =
- (struct ieee_types_vendor_specific *)
- (curr_bss->beacon_buf +
- curr_bss->wpa_offset);
-
- if (curr_bss->bcn_rsn_ie)
- curr_bss->bcn_rsn_ie = (struct ieee_types_generic *)
- (curr_bss->beacon_buf +
- curr_bss->rsn_offset);
-
- if (curr_bss->bcn_ht_cap)
- curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *)
- (curr_bss->beacon_buf +
- curr_bss->ht_cap_offset);
-
- if (curr_bss->bcn_ht_info)
- curr_bss->bcn_ht_info = (struct ieee80211_ht_info *)
- (curr_bss->beacon_buf +
- curr_bss->ht_info_offset);
-
- if (curr_bss->bcn_bss_co_2040)
- curr_bss->bcn_bss_co_2040 =
- (u8 *) (curr_bss->beacon_buf +
- curr_bss->bss_co_2040_offset);
-
- if (curr_bss->bcn_ext_cap)
- curr_bss->bcn_ext_cap = (u8 *) (curr_bss->beacon_buf +
- curr_bss->ext_cap_offset);
-
- if (curr_bss->bcn_obss_scan)
- curr_bss->bcn_obss_scan =
- (struct ieee_types_obss_scan_param *)
- (curr_bss->beacon_buf +
- curr_bss->overlap_bss_offset);
-
- spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags);
-
- dev_dbg(adapter->dev, "info: current beacon restored %d\n",
- priv->curr_bcn_size);
- } else {
- dev_warn(adapter->dev,
- "curr_bcn_buf not saved or bcn_buf has no space\n");
- }
-}
-
-/*
- * This function post processes the scan table after a new scan command has
- * completed.
- *
- * It inspects each entry of the scan table and tries to find an entry that
- * matches with our current associated/joined network from the scan. If
- * one is found, the stored copy of the BSS descriptor of our current network
- * is updated.
- *
- * It also debug dumps the current scan table contents after processing is over.
- */
-static void
-mwifiex_process_scan_results(struct mwifiex_private *priv)
-{
- struct mwifiex_adapter *adapter = priv->adapter;
- s32 j;
- u32 i;
- unsigned long flags;
-
- if (priv->media_connected) {
-
- j = mwifiex_find_ssid_in_list(priv, &priv->curr_bss_params.
- bss_descriptor.ssid,
- priv->curr_bss_params.
- bss_descriptor.mac_address,
- priv->bss_mode);
-
- if (j >= 0) {
- spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags);
- priv->curr_bss_params.bss_descriptor.bcn_wpa_ie = NULL;
- priv->curr_bss_params.bss_descriptor.wpa_offset = 0;
- priv->curr_bss_params.bss_descriptor.bcn_rsn_ie = NULL;
- priv->curr_bss_params.bss_descriptor.rsn_offset = 0;
- priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL;
- priv->curr_bss_params.bss_descriptor.wapi_offset = 0;
- priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL;
- priv->curr_bss_params.bss_descriptor.ht_cap_offset =
- 0;
- priv->curr_bss_params.bss_descriptor.bcn_ht_info = NULL;
- priv->curr_bss_params.bss_descriptor.ht_info_offset =
- 0;
- priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 =
- NULL;
- priv->curr_bss_params.bss_descriptor.
- bss_co_2040_offset = 0;
- priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL;
- priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0;
- priv->curr_bss_params.bss_descriptor.
- bcn_obss_scan = NULL;
- priv->curr_bss_params.bss_descriptor.
- overlap_bss_offset = 0;
- priv->curr_bss_params.bss_descriptor.beacon_buf = NULL;
- priv->curr_bss_params.bss_descriptor.beacon_buf_size =
- 0;
- priv->curr_bss_params.bss_descriptor.
- beacon_buf_size_max = 0;
-
- dev_dbg(adapter->dev, "info: Found current ssid/bssid"
- " in list @ index #%d\n", j);
- /* Make a copy of current BSSID descriptor */
- memcpy(&priv->curr_bss_params.bss_descriptor,
- &adapter->scan_table[j],
- sizeof(priv->curr_bss_params.bss_descriptor));
-
- mwifiex_save_curr_bcn(priv);
- spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags);
-
- } else {
- mwifiex_restore_curr_bcn(priv);
- }
- }
-
- for (i = 0; i < adapter->num_in_scan_table; i++)
- dev_dbg(adapter->dev, "info: scan:(%02d) %pM "
- "RSSI[%03d], SSID[%s]\n",
- i, adapter->scan_table[i].mac_address,
- (s32) adapter->scan_table[i].rssi,
- adapter->scan_table[i].ssid.ssid);
-}
-
-/*
* This function converts radio type scan parameter to a band configuration
* to be used in join command.
*/
@@ -2072,175 +1286,6 @@ mwifiex_radio_type_to_band(u8 radio_type)
}
/*
- * This function deletes a specific indexed entry from the scan table.
- *
- * This also compacts the remaining entries and adjusts any buffering
- * of beacon/probe response data if needed.
- */
-static void
-mwifiex_scan_delete_table_entry(struct mwifiex_private *priv, s32 table_idx)
-{
- struct mwifiex_adapter *adapter = priv->adapter;
- u32 del_idx;
- u32 beacon_buf_adj;
- u8 *beacon_buf;
-
- /*
- * Shift the saved beacon buffer data for the scan table back over the
- * entry being removed. Update the end of buffer pointer. Save the
- * deleted buffer allocation size for pointer adjustments for entries
- * compacted after the deleted index.
- */
- beacon_buf_adj = adapter->scan_table[table_idx].beacon_buf_size_max;
-
- dev_dbg(adapter->dev, "info: Scan: Delete Entry %d, beacon buffer "
- "removal = %d bytes\n", table_idx, beacon_buf_adj);
-
- /* Check if the table entry had storage allocated for its beacon */
- if (beacon_buf_adj) {
- beacon_buf = adapter->scan_table[table_idx].beacon_buf;
-
- /*
- * Remove the entry's buffer space, decrement the table end
- * pointer by the amount we are removing
- */
- adapter->bcn_buf_end -= beacon_buf_adj;
-
- dev_dbg(adapter->dev, "info: scan: delete entry %d,"
- " compact data: %p <- %p (sz = %d)\n",
- table_idx, beacon_buf,
- beacon_buf + beacon_buf_adj,
- (int)(adapter->bcn_buf_end - beacon_buf));
-
- /*
- * Compact data storage. Copy all data after the deleted
- * entry's end address (beacon_buf + beacon_buf_adj) back
- * to the original start address (beacon_buf).
- *
- * Scan table entries affected by the move will have their
- * entry pointer adjusted below.
- *
- * Use memmove since the dest/src memory regions overlap.
- */
- memmove(beacon_buf, beacon_buf + beacon_buf_adj,
- adapter->bcn_buf_end - beacon_buf);
- }
-
- dev_dbg(adapter->dev,
- "info: Scan: Delete Entry %d, num_in_scan_table = %d\n",
- table_idx, adapter->num_in_scan_table);
-
- /* Shift all of the entries after the table_idx back by one, compacting
- the table and removing the requested entry */
- for (del_idx = table_idx; (del_idx + 1) < adapter->num_in_scan_table;
- del_idx++) {
- /* Copy the next entry over this one */
- memcpy(adapter->scan_table + del_idx,
- adapter->scan_table + del_idx + 1,
- sizeof(struct mwifiex_bssdescriptor));
-
- /*
- * Adjust this entry's pointer to its beacon buffer based on
- * the removed/compacted entry from the deleted index. Don't
- * decrement if the buffer pointer is NULL (no data stored for
- * this entry).
- */
- if (adapter->scan_table[del_idx].beacon_buf) {
- adapter->scan_table[del_idx].beacon_buf -=
- beacon_buf_adj;
- if (adapter->scan_table[del_idx].bcn_wpa_ie)
- adapter->scan_table[del_idx].bcn_wpa_ie =
- (struct ieee_types_vendor_specific *)
- (adapter->scan_table[del_idx].
- beacon_buf +
- adapter->scan_table[del_idx].
- wpa_offset);
- if (adapter->scan_table[del_idx].bcn_rsn_ie)
- adapter->scan_table[del_idx].bcn_rsn_ie =
- (struct ieee_types_generic *)
- (adapter->scan_table[del_idx].
- beacon_buf +
- adapter->scan_table[del_idx].
- rsn_offset);
- if (adapter->scan_table[del_idx].bcn_wapi_ie)
- adapter->scan_table[del_idx].bcn_wapi_ie =
- (struct ieee_types_generic *)
- (adapter->scan_table[del_idx].beacon_buf
- + adapter->scan_table[del_idx].
- wapi_offset);
- if (adapter->scan_table[del_idx].bcn_ht_cap)
- adapter->scan_table[del_idx].bcn_ht_cap =
- (struct ieee80211_ht_cap *)
- (adapter->scan_table[del_idx].beacon_buf
- + adapter->scan_table[del_idx].
- ht_cap_offset);
-
- if (adapter->scan_table[del_idx].bcn_ht_info)
- adapter->scan_table[del_idx].bcn_ht_info =
- (struct ieee80211_ht_info *)
- (adapter->scan_table[del_idx].beacon_buf
- + adapter->scan_table[del_idx].
- ht_info_offset);
- if (adapter->scan_table[del_idx].bcn_bss_co_2040)
- adapter->scan_table[del_idx].bcn_bss_co_2040 =
- (u8 *)
- (adapter->scan_table[del_idx].beacon_buf
- + adapter->scan_table[del_idx].
- bss_co_2040_offset);
- if (adapter->scan_table[del_idx].bcn_ext_cap)
- adapter->scan_table[del_idx].bcn_ext_cap =
- (u8 *)
- (adapter->scan_table[del_idx].beacon_buf
- + adapter->scan_table[del_idx].
- ext_cap_offset);
- if (adapter->scan_table[del_idx].bcn_obss_scan)
- adapter->scan_table[del_idx].
- bcn_obss_scan =
- (struct ieee_types_obss_scan_param *)
- (adapter->scan_table[del_idx].beacon_buf
- + adapter->scan_table[del_idx].
- overlap_bss_offset);
- }
- }
-
- /* The last entry is invalid now that it has been deleted or moved
- back */
- memset(adapter->scan_table + adapter->num_in_scan_table - 1,
- 0x00, sizeof(struct mwifiex_bssdescriptor));
-
- adapter->num_in_scan_table--;
-}
-
-/*
- * This function deletes all occurrences of a given SSID from the scan table.
- *
- * This iterates through the scan table and deletes all entries that match
- * the given SSID. It also compacts the remaining scan table entries.
- */
-static int
-mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv,
- struct mwifiex_802_11_ssid *del_ssid)
-{
- s32 table_idx = -1;
-
- dev_dbg(priv->adapter->dev, "info: scan: delete ssid entry: %-32s\n",
- del_ssid->ssid);
-
- /* If the requested SSID is found in the table, delete it. Then keep
- searching the table for multiple entires for the SSID until no
- more are found */
- while ((table_idx = mwifiex_find_ssid_in_list(priv, del_ssid, NULL,
- NL80211_IFTYPE_UNSPECIFIED)) >= 0) {
- dev_dbg(priv->adapter->dev,
- "info: Scan: Delete SSID Entry: Found Idx = %d\n",
- table_idx);
- mwifiex_scan_delete_table_entry(priv, table_idx);
- }
-
- return table_idx == -1 ? -1 : 0;
-}
-
-/*
* This is an internal function used to start a scan based on an input
* configuration.
*
@@ -2248,8 +1293,8 @@ mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv,
* order to send the appropriate scan commands to firmware to populate or
* update the internal driver scan table.
*/
-int mwifiex_scan_networks(struct mwifiex_private *priv,
- const struct mwifiex_user_scan_cfg *user_scan_in)
+static int mwifiex_scan_networks(struct mwifiex_private *priv,
+ const struct mwifiex_user_scan_cfg *user_scan_in)
{
int ret = 0;
struct mwifiex_adapter *adapter = priv->adapter;
@@ -2258,7 +1303,6 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
struct mwifiex_ie_types_chan_list_param_set *chan_list_out;
u32 buf_size;
struct mwifiex_chan_scan_param_set *scan_chan_list;
- u8 keep_previous_scan;
u8 filtered_scan;
u8 scan_current_chan_only;
u8 max_chan_per_scan;
@@ -2295,24 +1339,11 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
return -ENOMEM;
}
- keep_previous_scan = false;
-
mwifiex_scan_setup_scan_config(priv, user_scan_in,
&scan_cfg_out->config, &chan_list_out,
scan_chan_list, &max_chan_per_scan,
&filtered_scan, &scan_current_chan_only);
- if (user_scan_in)
- keep_previous_scan = user_scan_in->keep_previous_scan;
-
-
- if (!keep_previous_scan) {
- memset(adapter->scan_table, 0x00,
- sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP);
- adapter->num_in_scan_table = 0;
- adapter->bcn_buf_end = adapter->bcn_buf;
- }
-
ret = mwifiex_scan_channel_list(priv, max_chan_per_scan, filtered_scan,
&scan_cfg_out->config, chan_list_out,
scan_chan_list);
@@ -2326,6 +1357,7 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
list_del(&cmd_node->list);
spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
flags);
+ adapter->cmd_queued = cmd_node;
mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
true);
} else {
@@ -2344,6 +1376,29 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
}
/*
+ * Sends IOCTL request to start a scan with user configurations.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ *
+ * Upon completion, it also generates a wireless event to notify
+ * applications.
+ */
+int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv,
+ struct mwifiex_user_scan_cfg *scan_req)
+{
+ int status;
+
+ priv->adapter->scan_wait_q_woken = false;
+
+ status = mwifiex_scan_networks(priv, scan_req);
+ if (!status)
+ status = mwifiex_wait_queue_complete(priv->adapter);
+
+ return status;
+}
+
+/*
* This function prepares a scan command to be sent to the firmware.
*
* This uses the scan command configuration sent to the command processing
@@ -2379,6 +1434,112 @@ int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd,
}
/*
+ * This function checks compatibility of requested network with current
+ * driver settings.
+ */
+int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
+ struct mwifiex_bssdescriptor *bss_desc)
+{
+ int ret = -1;
+
+ if (!bss_desc)
+ return -1;
+
+ if ((mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv,
+ (u8) bss_desc->bss_band, (u16) bss_desc->channel))) {
+ switch (priv->bss_mode) {
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ ret = mwifiex_is_network_compatible(priv, bss_desc,
+ priv->bss_mode);
+ if (ret)
+ dev_err(priv->adapter->dev, "cannot find ssid "
+ "%s\n", bss_desc->ssid.ssid);
+ break;
+ default:
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
+static int
+mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid,
+ s32 rssi, const u8 *ie_buf, size_t ie_len,
+ u16 beacon_period, u16 cap_info_bitmap, u8 band)
+{
+ struct mwifiex_bssdescriptor *bss_desc = NULL;
+ int ret;
+ unsigned long flags;
+ u8 *beacon_ie;
+
+ /* Allocate and fill new bss descriptor */
+ bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor),
+ GFP_KERNEL);
+ if (!bss_desc) {
+ dev_err(priv->adapter->dev, " failed to alloc bss_desc\n");
+ return -ENOMEM;
+ }
+
+ beacon_ie = kmemdup(ie_buf, ie_len, GFP_KERNEL);
+ if (!beacon_ie) {
+ dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n");
+ return -ENOMEM;
+ }
+
+ ret = mwifiex_fill_new_bss_desc(priv, bssid, rssi, beacon_ie,
+ ie_len, beacon_period,
+ cap_info_bitmap, band, bss_desc);
+ if (ret)
+ goto done;
+
+ ret = mwifiex_check_network_compatibility(priv, bss_desc);
+ if (ret)
+ goto done;
+
+ /* Update current bss descriptor parameters */
+ spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags);
+ priv->curr_bss_params.bss_descriptor.bcn_wpa_ie = NULL;
+ priv->curr_bss_params.bss_descriptor.wpa_offset = 0;
+ priv->curr_bss_params.bss_descriptor.bcn_rsn_ie = NULL;
+ priv->curr_bss_params.bss_descriptor.rsn_offset = 0;
+ priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL;
+ priv->curr_bss_params.bss_descriptor.wapi_offset = 0;
+ priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL;
+ priv->curr_bss_params.bss_descriptor.ht_cap_offset =
+ 0;
+ priv->curr_bss_params.bss_descriptor.bcn_ht_info = NULL;
+ priv->curr_bss_params.bss_descriptor.ht_info_offset =
+ 0;
+ priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 =
+ NULL;
+ priv->curr_bss_params.bss_descriptor.
+ bss_co_2040_offset = 0;
+ priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL;
+ priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0;
+ priv->curr_bss_params.bss_descriptor.beacon_buf = NULL;
+ priv->curr_bss_params.bss_descriptor.beacon_buf_size =
+ 0;
+
+ /* Make a copy of current BSSID descriptor */
+ memcpy(&priv->curr_bss_params.bss_descriptor, bss_desc,
+ sizeof(priv->curr_bss_params.bss_descriptor));
+ mwifiex_save_curr_bcn(priv);
+ spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags);
+
+done:
+ kfree(bss_desc);
+ kfree(beacon_ie);
+ return 0;
+}
+
+static void mwifiex_free_bss_priv(struct cfg80211_bss *bss)
+{
+ kfree(bss->priv);
+}
+
+/*
* This function handles the command response of scan.
*
* The response buffer for the scan command has the following
@@ -2404,23 +1565,19 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
struct mwifiex_adapter *adapter = priv->adapter;
struct cmd_ctrl_node *cmd_node;
struct host_cmd_ds_802_11_scan_rsp *scan_rsp;
- struct mwifiex_bssdescriptor *bss_new_entry = NULL;
struct mwifiex_ie_types_data *tlv_data;
struct mwifiex_ie_types_tsf_timestamp *tsf_tlv;
u8 *bss_info;
u32 scan_resp_size;
u32 bytes_left;
- u32 num_in_table;
- u32 bss_idx;
u32 idx;
u32 tlv_buf_size;
- long long tsf_val;
struct mwifiex_chan_freq_power *cfp;
struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv;
struct chan_band_param_set *chan_band;
- u8 band;
u8 is_bgscan_resp;
unsigned long flags;
+ struct cfg80211_bss *bss;
is_bgscan_resp = (le16_to_cpu(resp->command)
== HostCmd_CMD_802_11_BG_SCAN_QUERY);
@@ -2430,7 +1587,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
scan_rsp = &resp->params.scan_resp;
- if (scan_rsp->number_of_sets > IW_MAX_AP) {
+ if (scan_rsp->number_of_sets > MWIFIEX_MAX_AP) {
dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n",
scan_rsp->number_of_sets);
ret = -1;
@@ -2447,7 +1604,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
"info: SCAN_RESP: returned %d APs before parsing\n",
scan_rsp->number_of_sets);
- num_in_table = adapter->num_in_scan_table;
bss_info = scan_rsp->bss_desc_and_tlv_buffer;
/*
@@ -2479,125 +1635,149 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
(struct mwifiex_ie_types_data **)
&chan_band_tlv);
- /*
- * Process each scan response returned (scan_rsp->number_of_sets).
- * Save the information in the bss_new_entry and then insert into the
- * driver scan table either as an update to an existing entry
- * or as an addition at the end of the table
- */
- bss_new_entry = kzalloc(sizeof(struct mwifiex_bssdescriptor),
- GFP_KERNEL);
- if (!bss_new_entry) {
- dev_err(adapter->dev, " failed to alloc bss_new_entry\n");
- return -ENOMEM;
- }
-
for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) {
- /* Zero out the bss_new_entry we are about to store info in */
- memset(bss_new_entry, 0x00,
- sizeof(struct mwifiex_bssdescriptor));
-
- if (mwifiex_interpret_bss_desc_with_ie(adapter, bss_new_entry,
- &bss_info,
- &bytes_left)) {
- /* Error parsing/interpreting scan response, skipped */
- dev_err(adapter->dev, "SCAN_RESP: "
- "mwifiex_interpret_bss_desc_with_ie "
- "returned ERROR\n");
- continue;
+ u8 bssid[ETH_ALEN];
+ s32 rssi;
+ const u8 *ie_buf;
+ size_t ie_len;
+ int channel = -1;
+ u64 network_tsf = 0;
+ u16 beacon_size = 0;
+ u32 curr_bcn_bytes;
+ u32 freq;
+ u16 beacon_period;
+ u16 cap_info_bitmap;
+ u8 *current_ptr;
+ struct mwifiex_bcn_param *bcn_param;
+
+ if (bytes_left >= sizeof(beacon_size)) {
+ /* Extract & convert beacon size from command buffer */
+ memcpy(&beacon_size, bss_info, sizeof(beacon_size));
+ bytes_left -= sizeof(beacon_size);
+ bss_info += sizeof(beacon_size);
}
- /* Process the data fields and IEs returned for this BSS */
- dev_dbg(adapter->dev, "info: SCAN_RESP: BSSID = %pM\n",
- bss_new_entry->mac_address);
+ if (!beacon_size || beacon_size > bytes_left) {
+ bss_info += bytes_left;
+ bytes_left = 0;
+ return -1;
+ }
- /* Search the scan table for the same bssid */
- for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) {
- if (memcmp(bss_new_entry->mac_address,
- adapter->scan_table[bss_idx].mac_address,
- sizeof(bss_new_entry->mac_address))) {
- continue;
+ /* Initialize the current working beacon pointer for this BSS
+ * iteration */
+ current_ptr = bss_info;
+
+ /* Advance the return beacon pointer past the current beacon */
+ bss_info += beacon_size;
+ bytes_left -= beacon_size;
+
+ curr_bcn_bytes = beacon_size;
+
+ /*
+ * First 5 fields are bssid, RSSI, time stamp, beacon interval,
+ * and capability information
+ */
+ if (curr_bcn_bytes < sizeof(struct mwifiex_bcn_param)) {
+ dev_err(adapter->dev, "InterpretIE: not enough bytes left\n");
+ continue;
+ }
+ bcn_param = (struct mwifiex_bcn_param *)current_ptr;
+ current_ptr += sizeof(*bcn_param);
+ curr_bcn_bytes -= sizeof(*bcn_param);
+
+ memcpy(bssid, bcn_param->bssid, ETH_ALEN);
+
+ rssi = (s32) (bcn_param->rssi);
+ dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n",
+ rssi);
+
+ beacon_period = le16_to_cpu(bcn_param->beacon_period);
+
+ cap_info_bitmap = le16_to_cpu(bcn_param->cap_info_bitmap);
+ dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n",
+ cap_info_bitmap);
+
+ /* Rest of the current buffer are IE's */
+ ie_buf = current_ptr;
+ ie_len = curr_bcn_bytes;
+ dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP"
+ " = %d\n", curr_bcn_bytes);
+
+ while (curr_bcn_bytes >= sizeof(struct ieee_types_header)) {
+ u8 element_id, element_len;
+
+ element_id = *current_ptr;
+ element_len = *(current_ptr + 1);
+ if (curr_bcn_bytes < element_len +
+ sizeof(struct ieee_types_header)) {
+ dev_err(priv->adapter->dev, "%s: in processing"
+ " IE, bytes left < IE length\n",
+ __func__);
+ goto done;
}
- /*
- * If the SSID matches as well, it is a
- * duplicate of this entry. Keep the bss_idx
- * set to this entry so we replace the old
- * contents in the table
- */
- if ((bss_new_entry->ssid.ssid_len
- == adapter->scan_table[bss_idx]. ssid.ssid_len)
- && (!memcmp(bss_new_entry->ssid.ssid,
- adapter->scan_table[bss_idx].ssid.ssid,
- bss_new_entry->ssid.ssid_len))) {
- dev_dbg(adapter->dev, "info: SCAN_RESP:"
- " duplicate of index: %d\n", bss_idx);
+ if (element_id == WLAN_EID_DS_PARAMS) {
+ channel = *(u8 *) (current_ptr +
+ sizeof(struct ieee_types_header));
break;
}
- }
- /*
- * If the bss_idx is equal to the number of entries in
- * the table, the new entry was not a duplicate; append
- * it to the scan table
- */
- if (bss_idx == num_in_table) {
- /* Range check the bss_idx, keep it limited to
- the last entry */
- if (bss_idx == IW_MAX_AP)
- bss_idx--;
- else
- num_in_table++;
+
+ current_ptr += element_len +
+ sizeof(struct ieee_types_header);
+ curr_bcn_bytes -= element_len +
+ sizeof(struct ieee_types_header);
}
/*
- * Save the beacon/probe response returned for later application
- * retrieval. Duplicate beacon/probe responses are updated if
- * possible
- */
- mwifiex_ret_802_11_scan_store_beacon(priv, bss_idx,
- num_in_table, bss_new_entry);
- /*
* If the TSF TLV was appended to the scan results, save this
* entry's TSF value in the networkTSF field.The networkTSF is
* the firmware's TSF value at the time the beacon or probe
* response was received.
*/
- if (tsf_tlv) {
- memcpy(&tsf_val, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE]
- , sizeof(tsf_val));
- memcpy(&bss_new_entry->network_tsf, &tsf_val,
- sizeof(bss_new_entry->network_tsf));
- }
- band = BAND_G;
- if (chan_band_tlv) {
- chan_band = &chan_band_tlv->chan_band_param[idx];
- band = mwifiex_radio_type_to_band(chan_band->radio_type
- & (BIT(0) | BIT(1)));
- }
+ if (tsf_tlv)
+ memcpy(&network_tsf,
+ &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE],
+ sizeof(network_tsf));
+
+ if (channel != -1) {
+ struct ieee80211_channel *chan;
+ u8 band;
+
+ band = BAND_G;
+ if (chan_band_tlv) {
+ chan_band =
+ &chan_band_tlv->chan_band_param[idx];
+ band = mwifiex_radio_type_to_band(
+ chan_band->radio_type
+ & (BIT(0) | BIT(1)));
+ }
- /* Save the band designation for this entry for use in join */
- bss_new_entry->bss_band = band;
- cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv,
- (u8) bss_new_entry->bss_band,
- (u16)bss_new_entry->channel);
+ cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(
+ priv, (u8)band, (u16)channel);
- if (cfp)
- bss_new_entry->freq = cfp->freq;
- else
- bss_new_entry->freq = 0;
+ freq = cfp ? cfp->freq : 0;
- /* Copy the locally created bss_new_entry to the scan table */
- memcpy(&adapter->scan_table[bss_idx], bss_new_entry,
- sizeof(adapter->scan_table[bss_idx]));
+ chan = ieee80211_get_channel(priv->wdev->wiphy, freq);
- }
+ if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
+ bss = cfg80211_inform_bss(priv->wdev->wiphy,
+ chan, bssid, network_tsf,
+ cap_info_bitmap, beacon_period,
+ ie_buf, ie_len, rssi, GFP_KERNEL);
+ *(u8 *)bss->priv = band;
+ bss->free_priv = mwifiex_free_bss_priv;
- dev_dbg(adapter->dev,
- "info: SCAN_RESP: Scanned %2d APs, %d valid, %d total\n",
- scan_rsp->number_of_sets,
- num_in_table - adapter->num_in_scan_table, num_in_table);
-
- /* Update the total number of BSSIDs in the scan table */
- adapter->num_in_scan_table = num_in_table;
+ if (priv->media_connected && !memcmp(bssid,
+ priv->curr_bss_params.bss_descriptor
+ .mac_address, ETH_ALEN))
+ mwifiex_update_curr_bss_params(priv,
+ bssid, rssi, ie_buf,
+ ie_len, beacon_period,
+ cap_info_bitmap, band);
+ }
+ } else {
+ dev_dbg(adapter->dev, "missing BSS channel IE\n");
+ }
+ }
spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
if (list_empty(&adapter->scan_pending_q)) {
@@ -2605,17 +1785,11 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->scan_processing = false;
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
- /*
- * Process the resulting scan table:
- * - Remove any bad ssids
- * - Update our current BSS information from scan data
- */
- mwifiex_process_scan_results(priv);
/* Need to indicate IOCTL complete */
if (adapter->curr_cmd->wait_q_enabled) {
adapter->cmd_wait_q.status = 0;
- mwifiex_complete_cmd(adapter);
+ mwifiex_complete_cmd(adapter, adapter->curr_cmd);
}
if (priv->report_scan_result)
priv->report_scan_result = false;
@@ -2636,7 +1810,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
}
done:
- kfree((u8 *) bss_new_entry);
return ret;
}
@@ -2663,141 +1836,6 @@ int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd)
}
/*
- * This function finds a SSID in the scan table.
- *
- * A BSSID may optionally be provided to qualify the SSID.
- * For non-Auto mode, further check is made to make sure the
- * BSS found in the scan table is compatible with the current
- * settings of the driver.
- */
-s32
-mwifiex_find_ssid_in_list(struct mwifiex_private *priv,
- struct mwifiex_802_11_ssid *ssid, u8 *bssid,
- u32 mode)
-{
- struct mwifiex_adapter *adapter = priv->adapter;
- s32 net = -1, j;
- u8 best_rssi = 0;
- u32 i;
-
- dev_dbg(adapter->dev, "info: num of entries in table = %d\n",
- adapter->num_in_scan_table);
-
- /*
- * Loop through the table until the maximum is reached or until a match
- * is found based on the bssid field comparison
- */
- for (i = 0;
- i < adapter->num_in_scan_table && (!bssid || (bssid && net < 0));
- i++) {
- if (!mwifiex_ssid_cmp(&adapter->scan_table[i].ssid, ssid) &&
- (!bssid
- || !memcmp(adapter->scan_table[i].mac_address, bssid,
- ETH_ALEN))
- &&
- (mwifiex_get_cfp_by_band_and_channel_from_cfg80211
- (priv, (u8) adapter->scan_table[i].bss_band,
- (u16) adapter->scan_table[i].channel))) {
- switch (mode) {
- case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_ADHOC:
- j = mwifiex_is_network_compatible(priv, i,
- mode);
-
- if (j >= 0) {
- if (SCAN_RSSI
- (adapter->scan_table[i].rssi) >
- best_rssi) {
- best_rssi = SCAN_RSSI(adapter->
- scan_table
- [i].rssi);
- net = i;
- }
- } else {
- if (net == -1)
- net = j;
- }
- break;
- case NL80211_IFTYPE_UNSPECIFIED:
- default:
- /*
- * Do not check compatibility if the mode
- * requested is Auto/Unknown. Allows generic
- * find to work without verifying against the
- * Adapter security settings
- */
- if (SCAN_RSSI(adapter->scan_table[i].rssi) >
- best_rssi) {
- best_rssi = SCAN_RSSI(adapter->
- scan_table[i].rssi);
- net = i;
- }
- break;
- }
- }
- }
-
- return net;
-}
-
-/*
- * This function finds a specific compatible BSSID in the scan list.
- *
- * This function loops through the scan table looking for a compatible
- * match. If a BSSID matches, but the BSS is found to be not compatible
- * the function ignores it and continues to search through the rest of
- * the entries in case there is an AP with multiple SSIDs assigned to
- * the same BSSID.
- */
-s32
-mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid,
- u32 mode)
-{
- struct mwifiex_adapter *adapter = priv->adapter;
- s32 net = -1;
- u32 i;
-
- if (!bssid)
- return -1;
-
- dev_dbg(adapter->dev, "info: FindBSSID: Num of BSSIDs = %d\n",
- adapter->num_in_scan_table);
-
- /*
- * Look through the scan table for a compatible match. The ret return
- * variable will be equal to the index in the scan table (greater
- * than zero) if the network is compatible. The loop will continue
- * past a matched bssid that is not compatible in case there is an
- * AP with multiple SSIDs assigned to the same BSSID
- */
- for (i = 0; net < 0 && i < adapter->num_in_scan_table; i++) {
- if (!memcmp
- (adapter->scan_table[i].mac_address, bssid, ETH_ALEN)
- && mwifiex_get_cfp_by_band_and_channel_from_cfg80211
- (priv,
- (u8) adapter->
- scan_table[i].
- bss_band,
- (u16) adapter->
- scan_table[i].
- channel)) {
- switch (mode) {
- case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_ADHOC:
- net = mwifiex_is_network_compatible(priv, i,
- mode);
- break;
- default:
- net = i;
- break;
- }
- }
- }
-
- return net;
-}
-
-/*
* This function inserts scan command node to the scan pending queue.
*/
void
@@ -2808,48 +1846,13 @@ mwifiex_queue_scan_cmd(struct mwifiex_private *priv,
unsigned long flags;
cmd_node->wait_q_enabled = true;
+ cmd_node->condition = &adapter->scan_wait_q_woken;
spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
list_add_tail(&cmd_node->list, &adapter->scan_pending_q);
spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
}
/*
- * This function finds an AP with specific ssid in the scan list.
- */
-int mwifiex_find_best_network(struct mwifiex_private *priv,
- struct mwifiex_ssid_bssid *req_ssid_bssid)
-{
- struct mwifiex_adapter *adapter = priv->adapter;
- struct mwifiex_bssdescriptor *req_bss;
- s32 i;
-
- memset(req_ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid));
-
- i = mwifiex_find_best_network_in_list(priv);
-
- if (i >= 0) {
- req_bss = &adapter->scan_table[i];
- memcpy(&req_ssid_bssid->ssid, &req_bss->ssid,
- sizeof(struct mwifiex_802_11_ssid));
- memcpy((u8 *) &req_ssid_bssid->bssid,
- (u8 *) &req_bss->mac_address, ETH_ALEN);
-
- /* Make sure we are in the right mode */
- if (priv->bss_mode == NL80211_IFTYPE_UNSPECIFIED)
- priv->bss_mode = req_bss->bss_mode;
- }
-
- if (!req_ssid_bssid->ssid.ssid_len)
- return -1;
-
- dev_dbg(adapter->dev, "info: Best network found = [%s], "
- "[%pM]\n", req_ssid_bssid->ssid.ssid,
- req_ssid_bssid->bssid);
-
- return 0;
-}
-
-/*
* This function sends a scan command for all available channels to the
* firmware, filtered on a specific SSID.
*/
@@ -2874,8 +1877,6 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv,
return ret;
}
- mwifiex_scan_delete_ssid_table_entry(priv, req_ssid);
-
scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL);
if (!scan_cfg) {
dev_err(adapter->dev, "failed to alloc scan_cfg\n");
@@ -2884,7 +1885,6 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv,
memcpy(scan_cfg->ssid_list[0].ssid, req_ssid->ssid,
req_ssid->ssid_len);
- scan_cfg->keep_previous_scan = true;
ret = mwifiex_scan_networks(priv, scan_cfg);
@@ -2913,7 +1913,7 @@ int mwifiex_request_scan(struct mwifiex_private *priv,
}
priv->scan_pending_on_block = true;
- priv->adapter->cmd_wait_q.condition = false;
+ priv->adapter->scan_wait_q_woken = false;
if (req_ssid && req_ssid->ssid_len != 0)
/* Specific SSID scan */
@@ -2997,7 +1997,7 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv)
priv->curr_bcn_size = curr_bss->beacon_buf_size;
kfree(priv->curr_bcn_buf);
- priv->curr_bcn_buf = kzalloc(curr_bss->beacon_buf_size,
+ priv->curr_bcn_buf = kmalloc(curr_bss->beacon_buf_size,
GFP_KERNEL);
if (!priv->curr_bcn_buf) {
dev_err(priv->adapter->dev,
@@ -3010,6 +2010,39 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv)
curr_bss->beacon_buf_size);
dev_dbg(priv->adapter->dev, "info: current beacon saved %d\n",
priv->curr_bcn_size);
+
+ curr_bss->beacon_buf = priv->curr_bcn_buf;
+
+ /* adjust the pointers in the current BSS descriptor */
+ if (curr_bss->bcn_wpa_ie)
+ curr_bss->bcn_wpa_ie =
+ (struct ieee_types_vendor_specific *)
+ (curr_bss->beacon_buf +
+ curr_bss->wpa_offset);
+
+ if (curr_bss->bcn_rsn_ie)
+ curr_bss->bcn_rsn_ie = (struct ieee_types_generic *)
+ (curr_bss->beacon_buf +
+ curr_bss->rsn_offset);
+
+ if (curr_bss->bcn_ht_cap)
+ curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *)
+ (curr_bss->beacon_buf +
+ curr_bss->ht_cap_offset);
+
+ if (curr_bss->bcn_ht_info)
+ curr_bss->bcn_ht_info = (struct ieee80211_ht_info *)
+ (curr_bss->beacon_buf +
+ curr_bss->ht_info_offset);
+
+ if (curr_bss->bcn_bss_co_2040)
+ curr_bss->bcn_bss_co_2040 =
+ (u8 *) (curr_bss->beacon_buf +
+ curr_bss->bss_co_2040_offset);
+
+ if (curr_bss->bcn_ext_cap)
+ curr_bss->bcn_ext_cap = (u8 *) (curr_bss->beacon_buf +
+ curr_bss->ext_cap_offset);
}
/*
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
index 82098ac483b8..283171bbcedf 100644
--- a/drivers/net/wireless/mwifiex/sdio.c
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -89,7 +89,8 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
return -EIO;
}
- if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops)) {
+ if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops,
+ MWIFIEX_SDIO)) {
pr_err("%s: add card failed\n", __func__);
kfree(card);
sdio_claim_host(func);
@@ -830,7 +831,7 @@ done:
* The winner interface is also determined by this function.
*/
static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
- u32 poll_num, int *winner)
+ u32 poll_num)
{
int ret = 0;
u16 firmware_stat;
@@ -842,7 +843,7 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat);
if (ret)
continue;
- if (firmware_stat == FIRMWARE_READY) {
+ if (firmware_stat == FIRMWARE_READY_SDIO) {
ret = 0;
break;
} else {
@@ -851,15 +852,15 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
}
}
- if (winner && ret) {
+ if (ret) {
if (mwifiex_read_reg
(adapter, CARD_FW_STATUS0_REG, &winner_status))
winner_status = 0;
if (winner_status)
- *winner = 0;
+ adapter->winner = 0;
else
- *winner = 1;
+ adapter->winner = 1;
}
return ret;
}
@@ -1413,7 +1414,7 @@ tx_curr_single:
* the type. The firmware handles the packets based upon this set type.
*/
static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter,
- u8 type, u8 *payload, u32 pkt_len,
+ u8 type, struct sk_buff *skb,
struct mwifiex_tx_param *tx_param)
{
struct sdio_mmc_card *card = adapter->card;
@@ -1421,6 +1422,8 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter,
u32 buf_block_len;
u32 blk_size;
u8 port = CTRL_PORT;
+ u8 *payload = (u8 *)skb->data;
+ u32 pkt_len = skb->len;
/* Allocate buffer and copy payload */
blk_size = MWIFIEX_SDIO_BLOCK_SIZE;
@@ -1722,6 +1725,8 @@ static struct mwifiex_if_ops sdio_ops = {
/* SDIO specific */
.update_mp_end_port = mwifiex_update_mp_end_port,
.cleanup_mpa_buf = mwifiex_cleanup_mpa_buf,
+ .cmdrsp_complete = mwifiex_sdio_cmdrsp_complete,
+ .event_complete = mwifiex_sdio_event_complete,
};
/*
diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h
index 524f78f4ee69..3f711801e58a 100644
--- a/drivers/net/wireless/mwifiex/sdio.h
+++ b/drivers/net/wireless/mwifiex/sdio.h
@@ -169,9 +169,6 @@
/* Rx unit register */
#define CARD_RX_UNIT_REG 0x63
-/* Event header len w/o 4 bytes of interface header */
-#define MWIFIEX_EVENT_HEADER_LEN 4
-
/* Max retry number of CMD53 write */
#define MAX_WRITE_IOMEM_RETRY 2
@@ -304,4 +301,25 @@ struct sdio_mmc_card {
struct mwifiex_sdio_mpa_tx mpa_tx;
struct mwifiex_sdio_mpa_rx mpa_rx;
};
+
+/*
+ * .cmdrsp_complete handler
+ */
+static inline int mwifiex_sdio_cmdrsp_complete(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb)
+{
+ dev_kfree_skb_any(skb);
+ return 0;
+}
+
+/*
+ * .event_complete handler
+ */
+static inline int mwifiex_sdio_event_complete(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb)
+{
+ dev_kfree_skb_any(skb);
+ return 0;
+}
+
#endif /* _MWIFIEX_SDIO_H */
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index c54ee287b878..ea6518d1c9e3 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -902,6 +902,59 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
}
/*
+ * This function prepares command to set PCI-Express
+ * host buffer configuration
+ *
+ * Preparation includes -
+ * - Setting command ID, action and proper size
+ * - Setting host buffer configuration
+ * - Ensuring correct endian-ness
+ */
+static int
+mwifiex_cmd_pcie_host_spec(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd, u16 action)
+{
+ struct host_cmd_ds_pcie_details *host_spec =
+ &cmd->params.pcie_host_spec;
+ struct pcie_service_card *card = priv->adapter->card;
+ phys_addr_t *buf_pa;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_PCIE_DESC_DETAILS);
+ cmd->size = cpu_to_le16(sizeof(struct
+ host_cmd_ds_pcie_details) + S_DS_GEN);
+ cmd->result = 0;
+
+ memset(host_spec, 0, sizeof(struct host_cmd_ds_pcie_details));
+
+ if (action == HostCmd_ACT_GEN_SET) {
+ /* Send the ring base addresses and count to firmware */
+ host_spec->txbd_addr_lo = (u32)(card->txbd_ring_pbase);
+ host_spec->txbd_addr_hi =
+ (u32)(((u64)card->txbd_ring_pbase)>>32);
+ host_spec->txbd_count = MWIFIEX_MAX_TXRX_BD;
+ host_spec->rxbd_addr_lo = (u32)(card->rxbd_ring_pbase);
+ host_spec->rxbd_addr_hi =
+ (u32)(((u64)card->rxbd_ring_pbase)>>32);
+ host_spec->rxbd_count = MWIFIEX_MAX_TXRX_BD;
+ host_spec->evtbd_addr_lo =
+ (u32)(card->evtbd_ring_pbase);
+ host_spec->evtbd_addr_hi =
+ (u32)(((u64)card->evtbd_ring_pbase)>>32);
+ host_spec->evtbd_count = MWIFIEX_MAX_EVT_BD;
+ if (card->sleep_cookie) {
+ buf_pa = MWIFIEX_SKB_PACB(card->sleep_cookie);
+ host_spec->sleep_cookie_addr_lo = (u32) *buf_pa;
+ host_spec->sleep_cookie_addr_hi =
+ (u32) (((u64)*buf_pa) >> 32);
+ dev_dbg(priv->adapter->dev, "sleep_cook_lo phy addr: "
+ "0x%x\n", host_spec->sleep_cookie_addr_lo);
+ }
+ }
+
+ return 0;
+}
+
+/*
* This function prepares the commands before sending them to the firmware.
*
* This is a generic function which calls specific command preparation
@@ -1079,6 +1132,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
host_cmd_ds_set_bss_mode) + S_DS_GEN);
ret = 0;
break;
+ case HostCmd_CMD_PCIE_DESC_DETAILS:
+ ret = mwifiex_cmd_pcie_host_spec(priv, cmd_ptr, cmd_action);
+ break;
default:
dev_err(priv->adapter->dev,
"PREP_CMD: unknown cmd- %#x\n", cmd_no);
@@ -1095,6 +1151,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
* working state.
*
* The following commands are issued sequentially -
+ * - Set PCI-Express host buffer configuration (PCIE only)
* - Function init (for first interface only)
* - Read MAC address (for first interface only)
* - Reconfigure Tx buffer size (for first interface only)
@@ -1116,6 +1173,13 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
struct mwifiex_ds_11n_tx_cfg tx_cfg;
if (first_sta) {
+ if (priv->adapter->iface_type == MWIFIEX_PCIE) {
+ ret = mwifiex_send_cmd_async(priv,
+ HostCmd_CMD_PCIE_DESC_DETAILS,
+ HostCmd_ACT_GEN_SET, 0, NULL);
+ if (ret)
+ return -1;
+ }
ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_FUNC_INIT,
HostCmd_ACT_GEN_SET, 0, NULL);
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index 6804239d87bd..7a16b0c417af 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -952,6 +952,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
case HostCmd_CMD_11N_CFG:
ret = mwifiex_ret_11n_cfg(resp, data_buf);
break;
+ case HostCmd_CMD_PCIE_DESC_DETAILS:
+ break;
default:
dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
resp->command);
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c
index fc265cab0907..f204810e8338 100644
--- a/drivers/net/wireless/mwifiex/sta_event.c
+++ b/drivers/net/wireless/mwifiex/sta_event.c
@@ -130,8 +130,8 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv)
if (netif_carrier_ok(priv->netdev))
netif_carrier_off(priv->netdev);
/* Reset wireless stats signal info */
- priv->w_stats.qual.level = 0;
- priv->w_stats.qual.noise = 0;
+ priv->qual_level = 0;
+ priv->qual_noise = 0;
}
/*
@@ -299,11 +299,6 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
case EVENT_BG_SCAN_REPORT:
dev_dbg(adapter->dev, "event: BGS_REPORT\n");
- /* Clear the previous scan result */
- memset(adapter->scan_table, 0x00,
- sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP);
- adapter->num_in_scan_table = 0;
- adapter->bcn_buf_end = adapter->bcn_buf;
ret = mwifiex_send_cmd_async(priv,
HostCmd_CMD_802_11_BG_SCAN_QUERY,
HostCmd_ACT_GEN_GET, 0, NULL);
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index c34ff8c4f4f8..ea4a29b7e331 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -55,7 +55,9 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter)
{
bool cancel_flag = false;
int status = adapter->cmd_wait_q.status;
+ struct cmd_ctrl_node *cmd_queued = adapter->cmd_queued;
+ adapter->cmd_queued = NULL;
dev_dbg(adapter->dev, "cmd pending\n");
atomic_inc(&adapter->cmd_pending);
@@ -64,8 +66,8 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter)
/* Wait for completion */
wait_event_interruptible(adapter->cmd_wait_q.wait,
- adapter->cmd_wait_q.condition);
- if (!adapter->cmd_wait_q.condition)
+ *(cmd_queued->condition));
+ if (!*(cmd_queued->condition))
cancel_flag = true;
if (cancel_flag) {
@@ -142,90 +144,146 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
}
/*
+ * This function fills bss descriptor structure using provided
+ * information.
+ */
+int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
+ u8 *bssid, s32 rssi, u8 *ie_buf,
+ size_t ie_len, u16 beacon_period,
+ u16 cap_info_bitmap, u8 band,
+ struct mwifiex_bssdescriptor *bss_desc)
+{
+ int ret;
+
+ memcpy(bss_desc->mac_address, bssid, ETH_ALEN);
+ bss_desc->rssi = rssi;
+ bss_desc->beacon_buf = ie_buf;
+ bss_desc->beacon_buf_size = ie_len;
+ bss_desc->beacon_period = beacon_period;
+ bss_desc->cap_info_bitmap = cap_info_bitmap;
+ bss_desc->bss_band = band;
+ if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {
+ dev_dbg(priv->adapter->dev, "info: InterpretIE: AP WEP enabled\n");
+ bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
+ } else {
+ bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
+ }
+ if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_IBSS)
+ bss_desc->bss_mode = NL80211_IFTYPE_ADHOC;
+ else
+ bss_desc->bss_mode = NL80211_IFTYPE_STATION;
+
+ ret = mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc,
+ ie_buf, ie_len);
+
+ return ret;
+}
+
+/*
* In Ad-Hoc mode, the IBSS is created if not found in scan list.
* In both Ad-Hoc and infra mode, an deauthentication is performed
* first.
*/
-int mwifiex_bss_start(struct mwifiex_private *priv,
- struct mwifiex_ssid_bssid *ssid_bssid)
+int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
+ struct mwifiex_802_11_ssid *req_ssid)
{
int ret;
struct mwifiex_adapter *adapter = priv->adapter;
- s32 i = -1;
+ struct mwifiex_bssdescriptor *bss_desc = NULL;
+ u8 *beacon_ie = NULL;
priv->scan_block = false;
- if (!ssid_bssid)
- return -1;
+
+ if (bss) {
+ /* Allocate and fill new bss descriptor */
+ bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor),
+ GFP_KERNEL);
+ if (!bss_desc) {
+ dev_err(priv->adapter->dev, " failed to alloc bss_desc\n");
+ return -ENOMEM;
+ }
+
+ beacon_ie = kmemdup(bss->information_elements,
+ bss->len_beacon_ies, GFP_KERNEL);
+ if (!beacon_ie) {
+ kfree(bss_desc);
+ dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n");
+ return -ENOMEM;
+ }
+
+ ret = mwifiex_fill_new_bss_desc(priv, bss->bssid, bss->signal,
+ beacon_ie, bss->len_beacon_ies,
+ bss->beacon_interval,
+ bss->capability,
+ *(u8 *)bss->priv, bss_desc);
+ if (ret)
+ goto done;
+ }
if (priv->bss_mode == NL80211_IFTYPE_STATION) {
/* Infra mode */
ret = mwifiex_deauthenticate(priv, NULL);
if (ret)
- return ret;
+ goto done;
- /* Search for the requested SSID in the scan table */
- if (ssid_bssid->ssid.ssid_len)
- i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid,
- NULL, NL80211_IFTYPE_STATION);
- else
- i = mwifiex_find_bssid_in_list(priv,
- (u8 *) &ssid_bssid->bssid,
- NL80211_IFTYPE_STATION);
- if (i < 0)
- return -1;
+ ret = mwifiex_check_network_compatibility(priv, bss_desc);
+ if (ret)
+ goto done;
- dev_dbg(adapter->dev,
- "info: SSID found in scan list ... associating...\n");
+ dev_dbg(adapter->dev, "info: SSID found in scan list ... "
+ "associating...\n");
+
+ if (!netif_queue_stopped(priv->netdev))
+ netif_stop_queue(priv->netdev);
/* Clear any past association response stored for
* application retrieval */
priv->assoc_rsp_size = 0;
- ret = mwifiex_associate(priv, &adapter->scan_table[i]);
- if (ret)
- return ret;
+ ret = mwifiex_associate(priv, bss_desc);
+ if (bss)
+ cfg80211_put_bss(bss);
} else {
/* Adhoc mode */
/* If the requested SSID matches current SSID, return */
- if (ssid_bssid->ssid.ssid_len &&
+ if (bss_desc && bss_desc->ssid.ssid_len &&
(!mwifiex_ssid_cmp
(&priv->curr_bss_params.bss_descriptor.ssid,
- &ssid_bssid->ssid)))
+ &bss_desc->ssid))) {
+ kfree(bss_desc);
+ kfree(beacon_ie);
return 0;
+ }
/* Exit Adhoc mode first */
dev_dbg(adapter->dev, "info: Sending Adhoc Stop\n");
ret = mwifiex_deauthenticate(priv, NULL);
if (ret)
- return ret;
+ goto done;
priv->adhoc_is_link_sensed = false;
- /* Search for the requested network in the scan table */
- if (ssid_bssid->ssid.ssid_len)
- i = mwifiex_find_ssid_in_list(priv,
- &ssid_bssid->ssid, NULL,
- NL80211_IFTYPE_ADHOC);
- else
- i = mwifiex_find_bssid_in_list(priv,
- (u8 *)&ssid_bssid->bssid,
- NL80211_IFTYPE_ADHOC);
+ ret = mwifiex_check_network_compatibility(priv, bss_desc);
+
+ if (!netif_queue_stopped(priv->netdev))
+ netif_stop_queue(priv->netdev);
- if (i >= 0) {
+ if (!ret) {
dev_dbg(adapter->dev, "info: network found in scan"
" list. Joining...\n");
- ret = mwifiex_adhoc_join(priv, &adapter->scan_table[i]);
- if (ret)
- return ret;
+ ret = mwifiex_adhoc_join(priv, bss_desc);
+ if (bss)
+ cfg80211_put_bss(bss);
} else {
dev_dbg(adapter->dev, "info: Network not found in "
"the list, creating adhoc with ssid = %s\n",
- ssid_bssid->ssid.ssid);
- ret = mwifiex_adhoc_start(priv, &ssid_bssid->ssid);
- if (ret)
- return ret;
+ req_ssid->ssid);
+ ret = mwifiex_adhoc_start(priv, req_ssid);
}
}
+done:
+ kfree(bss_desc);
+ kfree(beacon_ie);
return ret;
}
@@ -235,8 +293,8 @@ int mwifiex_bss_start(struct mwifiex_private *priv,
* This function prepares the correct firmware command and
* issues it.
*/
-int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
- int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg)
+static int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
+ int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg)
{
struct mwifiex_adapter *adapter = priv->adapter;
@@ -376,7 +434,6 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv,
{
struct mwifiex_adapter *adapter = priv->adapter;
struct mwifiex_bssdescriptor *bss_desc;
- s32 tbl_idx;
if (!info)
return -1;
@@ -394,17 +451,6 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv,
info->region_code = adapter->region_code;
- /* Scan table index if connected */
- info->scan_table_idx = 0;
- if (priv->media_connected) {
- tbl_idx =
- mwifiex_find_ssid_in_list(priv, &bss_desc->ssid,
- bss_desc->mac_address,
- priv->bss_mode);
- if (tbl_idx >= 0)
- info->scan_table_idx = tbl_idx;
- }
-
info->media_connected = priv->media_connected;
info->max_power_level = priv->max_tx_power_level;
@@ -586,50 +632,6 @@ static int mwifiex_bss_ioctl_ibss_channel(struct mwifiex_private *priv,
}
/*
- * IOCTL request handler to find a particular BSS.
- *
- * The BSS can be searched with either a BSSID or a SSID. If none of
- * these are provided, just the best BSS (best RSSI) is returned.
- */
-int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *priv,
- struct mwifiex_ssid_bssid *ssid_bssid)
-{
- struct mwifiex_adapter *adapter = priv->adapter;
- struct mwifiex_bssdescriptor *bss_desc;
- u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
- u8 mac[ETH_ALEN];
- int i = 0;
-
- if (memcmp(ssid_bssid->bssid, zero_mac, sizeof(zero_mac))) {
- i = mwifiex_find_bssid_in_list(priv,
- (u8 *) ssid_bssid->bssid,
- priv->bss_mode);
- if (i < 0) {
- memcpy(mac, ssid_bssid->bssid, sizeof(mac));
- dev_err(adapter->dev, "cannot find bssid %pM\n", mac);
- return -1;
- }
- bss_desc = &adapter->scan_table[i];
- memcpy(&ssid_bssid->ssid, &bss_desc->ssid,
- sizeof(struct mwifiex_802_11_ssid));
- } else if (ssid_bssid->ssid.ssid_len) {
- i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, NULL,
- priv->bss_mode);
- if (i < 0) {
- dev_err(adapter->dev, "cannot find ssid %s\n",
- ssid_bssid->ssid.ssid);
- return -1;
- }
- bss_desc = &adapter->scan_table[i];
- memcpy(ssid_bssid->bssid, bss_desc->mac_address, ETH_ALEN);
- } else {
- return mwifiex_find_best_network(priv, ssid_bssid);
- }
-
- return 0;
-}
-
-/*
* IOCTL request handler to change Ad-Hoc channel.
*
* This function allocates the IOCTL request buffer, fills it
@@ -653,6 +655,9 @@ mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel)
struct mwifiex_bss_info bss_info;
struct mwifiex_ssid_bssid ssid_bssid;
u16 curr_chan = 0;
+ struct cfg80211_bss *bss = NULL;
+ struct ieee80211_channel *chan;
+ enum ieee80211_band band;
memset(&bss_info, 0, sizeof(bss_info));
@@ -688,12 +693,20 @@ mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel)
ret = -1;
goto done;
}
- /* Start/Join Adhoc network */
- memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid));
- memcpy(&ssid_bssid.ssid, &bss_info.ssid,
- sizeof(struct mwifiex_802_11_ssid));
- ret = mwifiex_bss_start(priv, &ssid_bssid);
+ band = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
+ chan = __ieee80211_get_channel(priv->wdev->wiphy,
+ ieee80211_channel_to_frequency(channel, band));
+
+ /* Find the BSS we want using available scan results */
+ bss = cfg80211_get_bss(priv->wdev->wiphy, chan, bss_info.bssid,
+ bss_info.ssid.ssid, bss_info.ssid.ssid_len,
+ WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+ if (!bss)
+ wiphy_warn(priv->wdev->wiphy, "assoc: bss %pM not in scan results\n",
+ bss_info.bssid);
+
+ ret = mwifiex_bss_start(priv, bss, &bss_info.ssid);
done:
return ret;
}
@@ -709,51 +722,9 @@ done:
static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv,
struct mwifiex_rate_cfg *rate_cfg)
{
- struct mwifiex_adapter *adapter = priv->adapter;
-
rate_cfg->is_rate_auto = priv->is_data_rate_auto;
- if (!priv->media_connected) {
- switch (adapter->config_bands) {
- case BAND_B:
- /* Return the lowest supported rate for B band */
- rate_cfg->rate = supported_rates_b[0] & 0x7f;
- break;
- case BAND_G:
- case BAND_G | BAND_GN:
- /* Return the lowest supported rate for G band */
- rate_cfg->rate = supported_rates_g[0] & 0x7f;
- break;
- case BAND_B | BAND_G:
- case BAND_A | BAND_B | BAND_G:
- case BAND_A | BAND_B:
- case BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN:
- case BAND_B | BAND_G | BAND_GN:
- /* Return the lowest supported rate for BG band */
- rate_cfg->rate = supported_rates_bg[0] & 0x7f;
- break;
- case BAND_A:
- case BAND_A | BAND_G:
- case BAND_A | BAND_G | BAND_AN | BAND_GN:
- case BAND_A | BAND_AN:
- /* Return the lowest supported rate for A band */
- rate_cfg->rate = supported_rates_a[0] & 0x7f;
- break;
- case BAND_GN:
- /* Return the lowest supported rate for N band */
- rate_cfg->rate = supported_rates_n[0] & 0x7f;
- break;
- default:
- dev_warn(adapter->dev, "invalid band %#x\n",
- adapter->config_bands);
- break;
- }
- } else {
- return mwifiex_send_cmd_sync(priv,
- HostCmd_CMD_802_11_TX_RATE_QUERY,
- HostCmd_ACT_GEN_GET, 0, NULL);
- }
-
- return 0;
+ return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_TX_RATE_QUERY,
+ HostCmd_ACT_GEN_GET, 0, NULL);
}
/*
@@ -794,7 +765,7 @@ static int mwifiex_rate_ioctl_set_rate_value(struct mwifiex_private *priv,
if ((rate[i] & 0x7f) == (rate_cfg->rate & 0x7f))
break;
}
- if (!rate[i] || (i == MWIFIEX_SUPPORTED_RATES)) {
+ if ((i == MWIFIEX_SUPPORTED_RATES) || !rate[i]) {
dev_err(adapter->dev, "fixed data rate %#x is out "
"of range\n", rate_cfg->rate);
return -1;
@@ -860,10 +831,10 @@ int mwifiex_drv_get_data_rate(struct mwifiex_private *priv,
ret = mwifiex_rate_ioctl_cfg(priv, rate);
if (!ret) {
- if (rate && rate->is_rate_auto)
+ if (rate->is_rate_auto)
rate->rate = mwifiex_index_to_data_rate(priv->tx_rate,
priv->tx_htinfo);
- else if (rate)
+ else
rate->rate = priv->data_rate;
} else {
ret = -1;
@@ -1280,9 +1251,9 @@ int mwifiex_get_signal_info(struct mwifiex_private *priv,
if (!status) {
if (signal->selector & BCN_RSSI_AVG_MASK)
- priv->w_stats.qual.level = signal->bcn_rssi_avg;
+ priv->qual_level = signal->bcn_rssi_avg;
if (signal->selector & BCN_NF_AVG_MASK)
- priv->w_stats.qual.noise = signal->bcn_nf_avg;
+ priv->qual_noise = signal->bcn_nf_avg;
}
return status;
@@ -1341,18 +1312,8 @@ int
mwifiex_get_stats_info(struct mwifiex_private *priv,
struct mwifiex_ds_get_stats *log)
{
- int ret;
-
- ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG,
+ return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG,
HostCmd_ACT_GEN_GET, 0, log);
-
- if (!ret) {
- priv->w_stats.discard.fragment = log->fcs_error;
- priv->w_stats.discard.retries = log->retry;
- priv->w_stats.discard.misc = log->ack_failure;
- }
-
- return ret;
}
/*
@@ -1594,7 +1555,7 @@ mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len)
{
struct mwifiex_ds_misc_gen_ie gen_ie;
- if (ie_len > IW_CUSTOM_MAX)
+ if (ie_len > IEEE_MAX_IE_SIZE)
return -EFAULT;
gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE;
diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c
index 1822bfad8896..d97facd70e88 100644
--- a/drivers/net/wireless/mwifiex/sta_tx.c
+++ b/drivers/net/wireless/mwifiex/sta_tx.c
@@ -151,7 +151,7 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags)
skb_push(skb, INTF_HEADER_LEN);
ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
- skb->data, skb->len, NULL);
+ skb, NULL);
switch (ret) {
case -EBUSY:
adapter->data_sent = true;
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c
index 6190b2fa57a3..a206f412875f 100644
--- a/drivers/net/wireless/mwifiex/txrx.c
+++ b/drivers/net/wireless/mwifiex/txrx.c
@@ -78,7 +78,7 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
(struct txpd *) (head_ptr + INTF_HEADER_LEN);
ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
- skb->data, skb->len, tx_param);
+ skb, tx_param);
}
switch (ret) {
@@ -87,7 +87,8 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
(adapter->pps_uapsd_mode) &&
(adapter->tx_lock_flag)) {
priv->adapter->tx_lock_flag = false;
- local_tx_pd->flags = 0;
+ if (local_tx_pd)
+ local_tx_pd->flags = 0;
}
dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
break;
@@ -160,43 +161,3 @@ done:
return 0;
}
-/*
- * Packet receive completion callback handler.
- *
- * This function calls another completion callback handler which
- * updates the statistics, and optionally updates the parent buffer
- * use count before freeing the received packet.
- */
-int mwifiex_recv_packet_complete(struct mwifiex_adapter *adapter,
- struct sk_buff *skb, int status)
-{
- struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
- struct mwifiex_rxinfo *rx_info_parent;
- struct mwifiex_private *priv;
- struct sk_buff *skb_parent;
- unsigned long flags;
-
- priv = adapter->priv[rx_info->bss_index];
-
- if (priv && (status == -1))
- priv->stats.rx_dropped++;
-
- if (rx_info->parent) {
- skb_parent = rx_info->parent;
- rx_info_parent = MWIFIEX_SKB_RXCB(skb_parent);
-
- spin_lock_irqsave(&priv->rx_pkt_lock, flags);
- --rx_info_parent->use_count;
-
- if (!rx_info_parent->use_count) {
- spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
- dev_kfree_skb_any(skb_parent);
- } else {
- spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
- }
- } else {
- dev_kfree_skb_any(skb);
- }
-
- return 0;
-}
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c
index d41291529bc0..06976f517f66 100644
--- a/drivers/net/wireless/mwifiex/util.c
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -185,13 +185,14 @@ int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb)
* corresponding waiting function. Otherwise, it processes the
* IOCTL response and frees the response buffer.
*/
-int mwifiex_complete_cmd(struct mwifiex_adapter *adapter)
+int mwifiex_complete_cmd(struct mwifiex_adapter *adapter,
+ struct cmd_ctrl_node *cmd_node)
{
atomic_dec(&adapter->cmd_pending);
dev_dbg(adapter->dev, "cmd completed: status=%d\n",
adapter->cmd_wait_q.status);
- adapter->cmd_wait_q.condition = true;
+ *(cmd_node->condition) = true;
if (adapter->cmd_wait_q.status == -ETIMEDOUT)
dev_err(adapter->dev, "cmd timeout\n");
diff --git a/drivers/net/wireless/mwifiex/util.h b/drivers/net/wireless/mwifiex/util.h
index 9506afc6c0e4..f6d36b9654a0 100644
--- a/drivers/net/wireless/mwifiex/util.h
+++ b/drivers/net/wireless/mwifiex/util.h
@@ -22,11 +22,16 @@
static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb)
{
- return (struct mwifiex_rxinfo *)skb->cb;
+ return (struct mwifiex_rxinfo *)(skb->cb + sizeof(phys_addr_t));
}
static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb)
{
- return (struct mwifiex_txinfo *)skb->cb;
+ return (struct mwifiex_txinfo *)(skb->cb + sizeof(phys_addr_t));
+}
+
+static inline phys_addr_t *MWIFIEX_SKB_PACB(struct sk_buff *skb)
+{
+ return (phys_addr_t *)skb->cb;
}
#endif /* !_MWIFIEX_UTIL_H_ */
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
index 69e260b41711..6c239c3c8249 100644
--- a/drivers/net/wireless/mwifiex/wmm.c
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -121,7 +121,6 @@ mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, u8 *ra)
memcpy(ra_list->ra, ra, ETH_ALEN);
ra_list->total_pkts_size = 0;
- ra_list->total_pkts = 0;
dev_dbg(adapter->dev, "info: allocated ra_list %p\n", ra_list);
@@ -648,7 +647,6 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter,
skb_queue_tail(&ra_list->skb_head, skb);
ra_list->total_pkts_size += skb->len;
- ra_list->total_pkts++;
atomic_inc(&priv->wmm.tx_pkts_queued);
@@ -975,6 +973,28 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
}
/*
+ * This function checks if 11n aggregation is possible.
+ */
+static int
+mwifiex_is_11n_aggragation_possible(struct mwifiex_private *priv,
+ struct mwifiex_ra_list_tbl *ptr,
+ int max_buf_size)
+{
+ int count = 0, total_size = 0;
+ struct sk_buff *skb, *tmp;
+
+ skb_queue_walk_safe(&ptr->skb_head, skb, tmp) {
+ total_size += skb->len;
+ if (total_size >= max_buf_size)
+ break;
+ if (++count >= MIN_NUM_AMSDU)
+ return true;
+ }
+
+ return false;
+}
+
+/*
* This function sends a single packet to firmware for transmission.
*/
static void
@@ -1001,7 +1021,6 @@ mwifiex_send_single_packet(struct mwifiex_private *priv,
dev_dbg(adapter->dev, "data: dequeuing the packet %p %p\n", ptr, skb);
ptr->total_pkts_size -= skb->len;
- ptr->total_pkts--;
if (!skb_queue_empty(&ptr->skb_head))
skb_next = skb_peek(&ptr->skb_head);
@@ -1027,7 +1046,6 @@ mwifiex_send_single_packet(struct mwifiex_private *priv,
skb_queue_tail(&ptr->skb_head, skb);
ptr->total_pkts_size += skb->len;
- ptr->total_pkts++;
tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags);
@@ -1107,8 +1125,8 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
tx_param.next_pkt_len =
((skb_next) ? skb_next->len +
sizeof(struct txpd) : 0);
- ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
- skb->data, skb->len, &tx_param);
+ ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, skb,
+ &tx_param);
switch (ret) {
case -EBUSY:
dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
@@ -1213,11 +1231,9 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
mwifiex_send_delba(priv, tid_del, ra, 1);
}
}
-/* Minimum number of AMSDU */
-#define MIN_NUM_AMSDU 2
-
if (mwifiex_is_amsdu_allowed(priv, tid) &&
- (ptr->total_pkts >= MIN_NUM_AMSDU))
+ mwifiex_is_11n_aggragation_possible(priv, ptr,
+ adapter->tx_buf_size))
mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN,
ptr_index, flags);
/* ra_list_spinlock has been freed in
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index da36dbf8d871..995695c28d5c 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -4097,9 +4097,6 @@ static int mwl8k_set_key(struct ieee80211_hw *hw,
if (rc)
goto out;
-
- mwl8k_vif->is_hw_crypto_enabled = false;
-
}
out:
return rc;
@@ -4918,7 +4915,8 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw,
return ret;
}
-static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue,
+static int mwl8k_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct mwl8k_priv *priv = hw->priv;
@@ -5465,7 +5463,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image)
goto fail;
for (i = 0; i < MWL8K_TX_WMM_QUEUES; i++) {
- rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]);
+ rc = mwl8k_conf_tx(hw, NULL, i, &priv->wmm_params[i]);
if (rc)
goto fail;
}
@@ -5504,6 +5502,14 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)
/* Set rssi values to dBm */
hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_HAS_RATE_CONTROL;
+
+ /*
+ * Ask mac80211 to not to trigger PS mode
+ * based on PM bit of incoming frames.
+ */
+ if (priv->ap_fw)
+ hw->flags |= IEEE80211_HW_AP_LINK_PS;
+
hw->vif_data_size = sizeof(struct mwl8k_vif);
hw->sta_data_size = sizeof(struct mwl8k_sta);
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index ef7efe839bb8..b52acc4b4086 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -2135,7 +2135,7 @@ static const struct net_device_ops orinoco_netdev_ops = {
.ndo_open = orinoco_open,
.ndo_stop = orinoco_stop,
.ndo_start_xmit = orinoco_xmit,
- .ndo_set_multicast_list = orinoco_set_multicast_list,
+ .ndo_set_rx_mode = orinoco_set_multicast_list,
.ndo_change_mtu = orinoco_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
index 811e87f8a349..0793e4265b43 100644
--- a/drivers/net/wireless/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/orinoco/orinoco_usb.c
@@ -1562,7 +1562,7 @@ static const struct net_device_ops ezusb_netdev_ops = {
.ndo_open = orinoco_open,
.ndo_stop = orinoco_stop,
.ndo_start_xmit = ezusb_xmit,
- .ndo_set_multicast_list = orinoco_set_multicast_list,
+ .ndo_set_rx_mode = orinoco_set_multicast_list,
.ndo_change_mtu = orinoco_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c
index bbb9beb206b1..33747e131a96 100644
--- a/drivers/net/wireless/orinoco/wext.c
+++ b/drivers/net/wireless/orinoco/wext.c
@@ -9,6 +9,7 @@
#include <linux/ieee80211.h>
#include <net/iw_handler.h>
#include <net/cfg80211.h>
+#include <net/cfg80211-wext.h>
#include "hermes.h"
#include "hermes_rid.h"
diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c
index 54cc0bba66b9..8b6f363b3f7d 100644
--- a/drivers/net/wireless/p54/eeprom.c
+++ b/drivers/net/wireless/p54/eeprom.c
@@ -145,6 +145,7 @@ static int p54_fill_band_bitrates(struct ieee80211_hw *dev,
static int p54_generate_band(struct ieee80211_hw *dev,
struct p54_channel_list *list,
+ unsigned int *chan_num,
enum ieee80211_band band)
{
struct p54_common *priv = dev->priv;
@@ -190,7 +191,14 @@ static int p54_generate_band(struct ieee80211_hw *dev,
tmp->channels[j].band = chan->band;
tmp->channels[j].center_freq = chan->freq;
+ priv->survey[*chan_num].channel = &tmp->channels[j];
+ priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM |
+ SURVEY_INFO_CHANNEL_TIME |
+ SURVEY_INFO_CHANNEL_TIME_BUSY |
+ SURVEY_INFO_CHANNEL_TIME_TX;
+ tmp->channels[j].hw_value = (*chan_num);
j++;
+ (*chan_num)++;
}
if (j == 0) {
@@ -263,7 +271,7 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)
{
struct p54_common *priv = dev->priv;
struct p54_channel_list *list;
- unsigned int i, j, max_channel_num;
+ unsigned int i, j, k, max_channel_num;
int ret = 0;
u16 freq;
@@ -283,6 +291,13 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)
ret = -ENOMEM;
goto free;
}
+ priv->chan_num = max_channel_num;
+ priv->survey = kzalloc(sizeof(struct survey_info) * max_channel_num,
+ GFP_KERNEL);
+ if (!priv->survey) {
+ ret = -ENOMEM;
+ goto free;
+ }
list->max_entries = max_channel_num;
list->channels = kzalloc(sizeof(struct p54_channel_entry) *
@@ -321,8 +336,9 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)
sort(list->channels, list->entries, sizeof(struct p54_channel_entry),
p54_compare_channels, NULL);
+ k = 0;
for (i = 0, j = 0; i < IEEE80211_NUM_BANDS; i++) {
- if (p54_generate_band(dev, list, i) == 0)
+ if (p54_generate_band(dev, list, &k, i) == 0)
j++;
}
if (j == 0) {
@@ -335,6 +351,10 @@ free:
kfree(list->channels);
kfree(list);
}
+ if (ret) {
+ kfree(priv->survey);
+ priv->survey = NULL;
+ }
return ret;
}
@@ -853,10 +873,12 @@ err:
kfree(priv->output_limit);
kfree(priv->curve_data);
kfree(priv->rssi_db);
+ kfree(priv->survey);
priv->iq_autocal = NULL;
priv->output_limit = NULL;
priv->curve_data = NULL;
priv->rssi_db = NULL;
+ priv->survey = NULL;
wiphy_err(dev->wiphy, "eeprom parse failed!\n");
return err;
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
index b6a061cbbdec..53a3408931be 100644
--- a/drivers/net/wireless/p54/fwio.c
+++ b/drivers/net/wireless/p54/fwio.c
@@ -385,6 +385,7 @@ int p54_setup_mac(struct p54_common *priv)
setup->v2.osc_start_delay = cpu_to_le16(65535);
}
p54_tx(priv, skb);
+ priv->phy_idle = mode == P54_FILTER_TYPE_HIBERNATE;
return 0;
}
@@ -626,6 +627,7 @@ int p54_set_ps(struct p54_common *priv)
psm->exclude[0] = WLAN_EID_TIM;
p54_tx(priv, skb);
+ priv->phy_ps = mode != P54_PSM_CAM;
return 0;
}
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
index a5a6d9e647bb..ad9ae04d07aa 100644
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -204,13 +204,11 @@ static void p54_stop(struct ieee80211_hw *dev)
struct p54_common *priv = dev->priv;
int i;
- mutex_lock(&priv->conf_mutex);
priv->mode = NL80211_IFTYPE_UNSPECIFIED;
priv->softled_state = 0;
- p54_set_leds(priv);
-
cancel_delayed_work_sync(&priv->work);
-
+ mutex_lock(&priv->conf_mutex);
+ p54_set_leds(priv);
priv->stop(dev);
skb_queue_purge(&priv->tx_pending);
skb_queue_purge(&priv->tx_queue);
@@ -278,6 +276,42 @@ static void p54_remove_interface(struct ieee80211_hw *dev,
mutex_unlock(&priv->conf_mutex);
}
+static int p54_wait_for_stats(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ int ret;
+
+ priv->update_stats = true;
+ ret = p54_fetch_statistics(priv);
+ if (ret)
+ return ret;
+
+ ret = wait_for_completion_interruptible_timeout(&priv->stat_comp, HZ);
+ if (ret == 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static void p54_reset_stats(struct p54_common *priv)
+{
+ struct ieee80211_channel *chan = priv->curchan;
+
+ if (chan) {
+ struct survey_info *info = &priv->survey[chan->hw_value];
+
+ /* only reset channel statistics, don't touch .filled, etc. */
+ info->channel_time = 0;
+ info->channel_time_busy = 0;
+ info->channel_time_tx = 0;
+ }
+
+ priv->update_stats = true;
+ priv->survey_raw.active = 0;
+ priv->survey_raw.cca = 0;
+ priv->survey_raw.tx = 0;
+}
+
static int p54_config(struct ieee80211_hw *dev, u32 changed)
{
int ret = 0;
@@ -288,19 +322,36 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed)
if (changed & IEEE80211_CONF_CHANGE_POWER)
priv->output_power = conf->power_level << 2;
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ struct ieee80211_channel *oldchan;
+ WARN_ON(p54_wait_for_stats(dev));
+ oldchan = priv->curchan;
+ priv->curchan = NULL;
ret = p54_scan(priv, P54_SCAN_EXIT, 0);
- if (ret)
+ if (ret) {
+ priv->curchan = oldchan;
goto out;
+ }
+ /*
+ * TODO: Use the LM_SCAN_TRAP to determine the current
+ * operating channel.
+ */
+ priv->curchan = priv->hw->conf.channel;
+ p54_reset_stats(priv);
+ WARN_ON(p54_fetch_statistics(priv));
}
if (changed & IEEE80211_CONF_CHANGE_PS) {
+ WARN_ON(p54_wait_for_stats(dev));
ret = p54_set_ps(priv);
if (ret)
goto out;
+ WARN_ON(p54_wait_for_stats(dev));
}
if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+ WARN_ON(p54_wait_for_stats(dev));
ret = p54_setup_mac(priv);
if (ret)
goto out;
+ WARN_ON(p54_wait_for_stats(dev));
}
out:
@@ -353,7 +404,8 @@ static void p54_configure_filter(struct ieee80211_hw *dev,
p54_set_groupfilter(priv);
}
-static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
+static int p54_conf_tx(struct ieee80211_hw *dev,
+ struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct p54_common *priv = dev->priv;
@@ -384,7 +436,9 @@ static void p54_work(struct work_struct *work)
* 2. cancel stuck frames / reset the device if necessary.
*/
- p54_fetch_statistics(priv);
+ mutex_lock(&priv->conf_mutex);
+ WARN_ON_ONCE(p54_fetch_statistics(priv));
+ mutex_unlock(&priv->conf_mutex);
}
static int p54_get_stats(struct ieee80211_hw *dev,
@@ -541,16 +595,47 @@ static int p54_get_survey(struct ieee80211_hw *dev, int idx,
struct survey_info *survey)
{
struct p54_common *priv = dev->priv;
- struct ieee80211_conf *conf = &dev->conf;
+ struct ieee80211_channel *chan;
+ int err, tries;
+ bool in_use = false;
- if (idx != 0)
+ if (idx >= priv->chan_num)
return -ENOENT;
- survey->channel = conf->channel;
- survey->filled = SURVEY_INFO_NOISE_DBM;
- survey->noise = clamp_t(s8, priv->noise, -128, 127);
+#define MAX_TRIES 1
+ for (tries = 0; tries < MAX_TRIES; tries++) {
+ chan = priv->curchan;
+ if (chan && chan->hw_value == idx) {
+ mutex_lock(&priv->conf_mutex);
+ err = p54_wait_for_stats(dev);
+ mutex_unlock(&priv->conf_mutex);
+ if (err)
+ return err;
+
+ in_use = true;
+ }
- return 0;
+ memcpy(survey, &priv->survey[idx], sizeof(*survey));
+
+ if (in_use) {
+ /* test if the reported statistics are valid. */
+ if (survey->channel_time != 0) {
+ survey->filled |= SURVEY_INFO_IN_USE;
+ } else {
+ /*
+ * hw/fw has not accumulated enough sample sets.
+ * Wait for 100ms, this ought to be enough to
+ * to get at least one non-null set of channel
+ * usage statistics.
+ */
+ msleep(100);
+ continue;
+ }
+ }
+ return 0;
+ }
+ return -ETIMEDOUT;
+#undef MAX_TRIES
}
static unsigned int p54_flush_count(struct p54_common *priv)
@@ -686,11 +771,14 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
mutex_init(&priv->conf_mutex);
mutex_init(&priv->eeprom_mutex);
+ init_completion(&priv->stat_comp);
init_completion(&priv->eeprom_comp);
init_completion(&priv->beacon_comp);
INIT_DELAYED_WORK(&priv->work, p54_work);
memset(&priv->mc_maclist[0], ~0, ETH_ALEN);
+ priv->curchan = NULL;
+ p54_reset_stats(priv);
return dev;
}
EXPORT_SYMBOL_GPL(p54_init_common);
@@ -730,11 +818,13 @@ void p54_free_common(struct ieee80211_hw *dev)
kfree(priv->curve_data);
kfree(priv->rssi_db);
kfree(priv->used_rxkeys);
+ kfree(priv->survey);
priv->iq_autocal = NULL;
priv->output_limit = NULL;
priv->curve_data = NULL;
priv->rssi_db = NULL;
priv->used_rxkeys = NULL;
+ priv->survey = NULL;
ieee80211_free_hw(dev);
}
EXPORT_SYMBOL_GPL(p54_free_common);
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index 799d05e12595..452fa3a64aa1 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -199,6 +199,22 @@ struct p54_common {
u8 tx_diversity_mask;
unsigned int output_power;
struct p54_rssi_db_entry *cur_rssi;
+ struct ieee80211_channel *curchan;
+ struct survey_info *survey;
+ unsigned int chan_num;
+ struct completion stat_comp;
+ bool update_stats;
+ struct {
+ unsigned int timestamp;
+ unsigned int cached_cca;
+ unsigned int cached_tx;
+ unsigned int cached_rssi;
+ u64 active;
+ u64 cca;
+ u64 tx;
+ u64 rssi;
+ } survey_raw;
+
int noise;
/* calibration, output power limit and rssi<->dBm conversation data */
struct pda_iq_autocal_entry *iq_autocal;
@@ -220,6 +236,8 @@ struct p54_common {
u32 basic_rate_mask;
u16 aid;
u8 coverage_class;
+ bool phy_idle;
+ bool phy_ps;
bool powersave_override;
__le32 beacon_req_id;
struct completion beacon_comp;
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c
index 6d9204fef90b..f18df82eeb92 100644
--- a/drivers/net/wireless/p54/p54spi.c
+++ b/drivers/net/wireless/p54/p54spi.c
@@ -41,7 +41,6 @@
#endif /* CONFIG_P54_SPI_DEFAULT_EEPROM */
MODULE_FIRMWARE("3826.arm");
-MODULE_ALIAS("stlc45xx");
/*
* gpios should be handled in board files and provided via platform data,
@@ -738,3 +737,4 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>");
MODULE_ALIAS("spi:cx3110x");
MODULE_ALIAS("spi:p54spi");
+MODULE_ALIAS("spi:stlc45xx");
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
index 042842e704de..f485784a60ae 100644
--- a/drivers/net/wireless/p54/txrx.c
+++ b/drivers/net/wireless/p54/txrx.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/firmware.h>
#include <linux/etherdevice.h>
+#include <asm/div64.h>
#include <net/mac80211.h>
@@ -507,6 +508,8 @@ static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb)
struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
struct p54_statistics *stats = (struct p54_statistics *) hdr->data;
struct sk_buff *tmp;
+ struct ieee80211_channel *chan;
+ unsigned int i, rssi, tx, cca, dtime, dtotal, dcca, dtx, drssi, unit;
u32 tsf32;
if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
@@ -523,8 +526,75 @@ static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb)
priv->noise = p54_rssi_to_dbm(priv, le32_to_cpu(stats->noise));
+ /*
+ * STSW450X LMAC API page 26 - 3.8 Statistics
+ * "The exact measurement period can be derived from the
+ * timestamp member".
+ */
+ dtime = tsf32 - priv->survey_raw.timestamp;
+
+ /*
+ * STSW450X LMAC API page 26 - 3.8.1 Noise histogram
+ * The LMAC samples RSSI, CCA and transmit state at regular
+ * periods (typically 8 times per 1k [as in 1024] usec).
+ */
+ cca = le32_to_cpu(stats->sample_cca);
+ tx = le32_to_cpu(stats->sample_tx);
+ rssi = 0;
+ for (i = 0; i < ARRAY_SIZE(stats->sample_noise); i++)
+ rssi += le32_to_cpu(stats->sample_noise[i]);
+
+ dcca = cca - priv->survey_raw.cached_cca;
+ drssi = rssi - priv->survey_raw.cached_rssi;
+ dtx = tx - priv->survey_raw.cached_tx;
+ dtotal = dcca + drssi + dtx;
+
+ /*
+ * update statistics when more than a second is over since the
+ * last call, or when a update is badly needed.
+ */
+ if (dtotal && (priv->update_stats || dtime >= USEC_PER_SEC) &&
+ dtime >= dtotal) {
+ priv->survey_raw.timestamp = tsf32;
+ priv->update_stats = false;
+ unit = dtime / dtotal;
+
+ if (dcca) {
+ priv->survey_raw.cca += dcca * unit;
+ priv->survey_raw.cached_cca = cca;
+ }
+ if (dtx) {
+ priv->survey_raw.tx += dtx * unit;
+ priv->survey_raw.cached_tx = tx;
+ }
+ if (drssi) {
+ priv->survey_raw.rssi += drssi * unit;
+ priv->survey_raw.cached_rssi = rssi;
+ }
+
+ /* 1024 usec / 8 times = 128 usec / time */
+ if (!(priv->phy_ps || priv->phy_idle))
+ priv->survey_raw.active += dtotal * unit;
+ else
+ priv->survey_raw.active += (dcca + dtx) * unit;
+ }
+
+ chan = priv->curchan;
+ if (chan) {
+ struct survey_info *survey = &priv->survey[chan->hw_value];
+ survey->noise = clamp_t(s8, priv->noise, -128, 127);
+ survey->channel_time = priv->survey_raw.active;
+ survey->channel_time_tx = priv->survey_raw.tx;
+ survey->channel_time_busy = priv->survey_raw.tx +
+ priv->survey_raw.cca;
+ do_div(survey->channel_time, 1024);
+ do_div(survey->channel_time_tx, 1024);
+ do_div(survey->channel_time_busy, 1024);
+ }
+
tmp = p54_find_and_unlink_skb(priv, hdr->req_id);
dev_kfree_skb_any(tmp);
+ complete(&priv->stat_comp);
}
static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb)
@@ -619,7 +689,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_PSPOLL_RESPONSE)
+ if (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)
*flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 2a06ebcd67c5..0021e4948512 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -273,7 +273,7 @@ static const struct net_device_ops ray_netdev_ops = {
.ndo_start_xmit = ray_dev_start_xmit,
.ndo_set_config = ray_dev_config,
.ndo_get_stats = ray_get_stats,
- .ndo_set_multicast_list = set_multicast_list,
+ .ndo_set_rx_mode = set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 29f938930667..0c13840a7de5 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -36,13 +36,11 @@
#include <linux/mii.h>
#include <linux/usb.h>
#include <linux/usb/cdc.h>
-#include <linux/wireless.h>
#include <linux/ieee80211.h>
#include <linux/if_arp.h>
#include <linux/ctype.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
-#include <net/iw_handler.h>
#include <net/cfg80211.h>
#include <linux/usb/usbnet.h>
#include <linux/usb/rndis_host.h>
@@ -3392,7 +3390,7 @@ static const struct net_device_ops rndis_wlan_netdev_ops = {
.ndo_tx_timeout = usbnet_tx_timeout,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = rndis_wlan_set_multicast_list,
+ .ndo_set_rx_mode = rndis_wlan_set_multicast_list,
};
static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf)
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 76bcc3547976..3a6b40239bc1 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -645,11 +645,6 @@ static void rt2400pci_start_queue(struct data_queue *queue)
rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
break;
case QID_BEACON:
- /*
- * Allow the tbtt tasklet to be scheduled.
- */
- tasklet_enable(&rt2x00dev->tbtt_tasklet);
-
rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
rt2x00_set_field32(&reg, CSR14_TBCN, 1);
@@ -715,7 +710,7 @@ static void rt2400pci_stop_queue(struct data_queue *queue)
/*
* Wait for possibly running tbtt tasklets.
*/
- tasklet_disable(&rt2x00dev->tbtt_tasklet);
+ tasklet_kill(&rt2x00dev->tbtt_tasklet);
break;
default:
break;
@@ -982,12 +977,6 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
if (state == STATE_RADIO_IRQ_ON) {
rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
rt2x00pci_register_write(rt2x00dev, CSR7, reg);
-
- /*
- * Enable tasklets.
- */
- tasklet_enable(&rt2x00dev->txstatus_tasklet);
- tasklet_enable(&rt2x00dev->rxdone_tasklet);
}
/*
@@ -1011,8 +1000,9 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
* Ensure that all tasklets are finished before
* disabling the interrupts.
*/
- tasklet_disable(&rt2x00dev->txstatus_tasklet);
- tasklet_disable(&rt2x00dev->rxdone_tasklet);
+ tasklet_kill(&rt2x00dev->txstatus_tasklet);
+ tasklet_kill(&rt2x00dev->rxdone_tasklet);
+ tasklet_kill(&rt2x00dev->tbtt_tasklet);
}
}
@@ -1249,7 +1239,7 @@ static void rt2400pci_fill_rxdone(struct queue_entry *entry,
* call, we must decrease the higher 32bits with 1 to get
* to correct value.
*/
- tsf = rt2x00dev->ops->hw->get_tsf(rt2x00dev->hw);
+ tsf = rt2x00dev->ops->hw->get_tsf(rt2x00dev->hw, NULL);
rx_low = rt2x00_get_field32(word4, RXD_W4_RX_END_TIME);
rx_high = upper_32_bits(tsf);
@@ -1347,22 +1337,25 @@ static void rt2400pci_txstatus_tasklet(unsigned long data)
/*
* Enable all TXDONE interrupts again.
*/
- spin_lock_irq(&rt2x00dev->irqmask_lock);
+ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) {
+ spin_lock_irq(&rt2x00dev->irqmask_lock);
- rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
- rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 0);
- rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 0);
- rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 0);
- rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+ rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 0);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 0);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR8, reg);
- spin_unlock_irq(&rt2x00dev->irqmask_lock);
+ spin_unlock_irq(&rt2x00dev->irqmask_lock);
+ }
}
static void rt2400pci_tbtt_tasklet(unsigned long data)
{
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
rt2x00lib_beacondone(rt2x00dev);
- rt2400pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE);
+ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ rt2400pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE);
}
static void rt2400pci_rxdone_tasklet(unsigned long data)
@@ -1370,7 +1363,7 @@ static void rt2400pci_rxdone_tasklet(unsigned long data)
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
if (rt2x00pci_rxdone(rt2x00dev))
tasklet_schedule(&rt2x00dev->rxdone_tasklet);
- else
+ else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE);
}
@@ -1655,7 +1648,8 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* IEEE80211 stack callback functions.
*/
-static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue,
+static int rt2400pci_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -1668,7 +1662,7 @@ static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue,
if (queue != 0)
return -EINVAL;
- if (rt2x00mac_conf_tx(hw, queue, params))
+ if (rt2x00mac_conf_tx(hw, vif, queue, params))
return -EINVAL;
/*
@@ -1680,7 +1674,8 @@ static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue,
return 0;
}
-static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw)
+static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
u64 tsf;
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index c288d951c034..dcc0e1fcca77 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -735,11 +735,6 @@ static void rt2500pci_start_queue(struct data_queue *queue)
rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
break;
case QID_BEACON:
- /*
- * Allow the tbtt tasklet to be scheduled.
- */
- tasklet_enable(&rt2x00dev->tbtt_tasklet);
-
rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
rt2x00_set_field32(&reg, CSR14_TBCN, 1);
@@ -805,7 +800,7 @@ static void rt2500pci_stop_queue(struct data_queue *queue)
/*
* Wait for possibly running tbtt tasklets.
*/
- tasklet_disable(&rt2x00dev->tbtt_tasklet);
+ tasklet_kill(&rt2x00dev->tbtt_tasklet);
break;
default:
break;
@@ -1137,12 +1132,6 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
if (state == STATE_RADIO_IRQ_ON) {
rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
rt2x00pci_register_write(rt2x00dev, CSR7, reg);
-
- /*
- * Enable tasklets.
- */
- tasklet_enable(&rt2x00dev->txstatus_tasklet);
- tasklet_enable(&rt2x00dev->rxdone_tasklet);
}
/*
@@ -1165,8 +1154,9 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
/*
* Ensure that all tasklets are finished.
*/
- tasklet_disable(&rt2x00dev->txstatus_tasklet);
- tasklet_disable(&rt2x00dev->rxdone_tasklet);
+ tasklet_kill(&rt2x00dev->txstatus_tasklet);
+ tasklet_kill(&rt2x00dev->rxdone_tasklet);
+ tasklet_kill(&rt2x00dev->tbtt_tasklet);
}
}
@@ -1479,22 +1469,25 @@ static void rt2500pci_txstatus_tasklet(unsigned long data)
/*
* Enable all TXDONE interrupts again.
*/
- spin_lock_irq(&rt2x00dev->irqmask_lock);
+ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) {
+ spin_lock_irq(&rt2x00dev->irqmask_lock);
- rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
- rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 0);
- rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 0);
- rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 0);
- rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+ rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 0);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 0);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR8, reg);
- spin_unlock_irq(&rt2x00dev->irqmask_lock);
+ spin_unlock_irq(&rt2x00dev->irqmask_lock);
+ }
}
static void rt2500pci_tbtt_tasklet(unsigned long data)
{
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
rt2x00lib_beacondone(rt2x00dev);
- rt2500pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE);
+ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ rt2500pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE);
}
static void rt2500pci_rxdone_tasklet(unsigned long data)
@@ -1502,7 +1495,7 @@ static void rt2500pci_rxdone_tasklet(unsigned long data)
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
if (rt2x00pci_rxdone(rt2x00dev))
tasklet_schedule(&rt2x00dev->rxdone_tasklet);
- else
+ else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE);
}
@@ -1973,7 +1966,8 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* IEEE80211 stack callback functions.
*/
-static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw)
+static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
u64 tsf;
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index c69a7d71f4ca..4778620347c4 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -664,6 +664,9 @@
/*
* LED_CFG: LED control
+ * ON_PERIOD: LED active time (ms) during TX (only used for LED mode 1)
+ * OFF_PERIOD: LED inactive time (ms) during TX (only used for LED mode 1)
+ * SLOW_BLINK_PERIOD: LED blink interval in seconds (only used for LED mode 2)
* color LED's:
* 0: off
* 1: blinking upon TX2
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index ef67f6786a84..3f183a15186e 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -493,7 +493,7 @@ void rt2800_write_tx_data(struct queue_entry *entry,
rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->u.ht.ba_size);
rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID,
test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
- txdesc->key_idx : 0xff);
+ txdesc->key_idx : txdesc->u.ht.wcid);
rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
txdesc->length);
rt2x00_set_field32(&word, TXWI_W1_PACKETID_QUEUE, entry->queue->qid);
@@ -601,7 +601,7 @@ void rt2800_process_rxwi(struct queue_entry *entry,
}
EXPORT_SYMBOL_GPL(rt2800_process_rxwi);
-void rt2800_txdone_entry(struct queue_entry *entry, u32 status)
+void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
@@ -609,13 +609,11 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status)
u32 word;
u16 mcs, real_mcs;
int aggr, ampdu;
- __le32 *txwi;
/*
* Obtain the status about this packet.
*/
txdesc.flags = 0;
- txwi = rt2800_drv_get_txwi(entry);
rt2x00_desc_read(txwi, 0, &word);
mcs = rt2x00_get_field32(word, TXWI_W0_MCS);
@@ -899,28 +897,12 @@ static void rt2800_brightness_set(struct led_classdev *led_cdev,
}
}
-static int rt2800_blink_set(struct led_classdev *led_cdev,
- unsigned long *delay_on, unsigned long *delay_off)
-{
- struct rt2x00_led *led =
- container_of(led_cdev, struct rt2x00_led, led_dev);
- u32 reg;
-
- rt2800_register_read(led->rt2x00dev, LED_CFG, &reg);
- rt2x00_set_field32(&reg, LED_CFG_ON_PERIOD, *delay_on);
- rt2x00_set_field32(&reg, LED_CFG_OFF_PERIOD, *delay_off);
- rt2800_register_write(led->rt2x00dev, LED_CFG, reg);
-
- return 0;
-}
-
static void rt2800_init_led(struct rt2x00_dev *rt2x00dev,
struct rt2x00_led *led, enum led_type type)
{
led->rt2x00dev = rt2x00dev;
led->type = type;
led->led_dev.brightness_set = rt2800_brightness_set;
- led->led_dev.blink_set = rt2800_blink_set;
led->flags = LED_INITIALIZED;
}
#endif /* CONFIG_RT2X00_LIB_LEDS */
@@ -928,11 +910,51 @@ static void rt2800_init_led(struct rt2x00_dev *rt2x00dev,
/*
* Configuration handlers.
*/
-static void rt2800_config_wcid_attr(struct rt2x00_dev *rt2x00dev,
- struct rt2x00lib_crypto *crypto,
- struct ieee80211_key_conf *key)
+static void rt2800_config_wcid(struct rt2x00_dev *rt2x00dev,
+ const u8 *address,
+ int wcid)
{
struct mac_wcid_entry wcid_entry;
+ u32 offset;
+
+ offset = MAC_WCID_ENTRY(wcid);
+
+ memset(&wcid_entry, 0xff, sizeof(wcid_entry));
+ if (address)
+ memcpy(wcid_entry.mac, address, ETH_ALEN);
+
+ rt2800_register_multiwrite(rt2x00dev, offset,
+ &wcid_entry, sizeof(wcid_entry));
+}
+
+static void rt2800_delete_wcid_attr(struct rt2x00_dev *rt2x00dev, int wcid)
+{
+ u32 offset;
+ offset = MAC_WCID_ATTR_ENTRY(wcid);
+ rt2800_register_write(rt2x00dev, offset, 0);
+}
+
+static void rt2800_config_wcid_attr_bssidx(struct rt2x00_dev *rt2x00dev,
+ int wcid, u32 bssidx)
+{
+ u32 offset = MAC_WCID_ATTR_ENTRY(wcid);
+ u32 reg;
+
+ /*
+ * The BSS Idx numbers is split in a main value of 3 bits,
+ * and a extended field for adding one additional bit to the value.
+ */
+ rt2800_register_read(rt2x00dev, offset, &reg);
+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX, (bssidx & 0x7));
+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX_EXT,
+ (bssidx & 0x8) >> 3);
+ rt2800_register_write(rt2x00dev, offset, reg);
+}
+
+static void rt2800_config_wcid_attr_cipher(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_crypto *crypto,
+ struct ieee80211_key_conf *key)
+{
struct mac_iveiv_entry iveiv_entry;
u32 offset;
u32 reg;
@@ -952,14 +974,16 @@ static void rt2800_config_wcid_attr(struct rt2x00_dev *rt2x00dev,
(crypto->cipher & 0x7));
rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_CIPHER_EXT,
(crypto->cipher & 0x8) >> 3);
- rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX,
- (crypto->bssidx & 0x7));
- rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX_EXT,
- (crypto->bssidx & 0x8) >> 3);
rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher);
rt2800_register_write(rt2x00dev, offset, reg);
} else {
- rt2800_register_write(rt2x00dev, offset, 0);
+ /* Delete the cipher without touching the bssidx */
+ rt2800_register_read(rt2x00dev, offset, &reg);
+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_KEYTAB, 0);
+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_CIPHER, 0);
+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_CIPHER_EXT, 0);
+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_RX_WIUDF, 0);
+ rt2800_register_write(rt2x00dev, offset, reg);
}
offset = MAC_IVEIV_ENTRY(key->hw_key_idx);
@@ -972,14 +996,6 @@ static void rt2800_config_wcid_attr(struct rt2x00_dev *rt2x00dev,
iveiv_entry.iv[3] |= key->keyidx << 6;
rt2800_register_multiwrite(rt2x00dev, offset,
&iveiv_entry, sizeof(iveiv_entry));
-
- offset = MAC_WCID_ENTRY(key->hw_key_idx);
-
- memset(&wcid_entry, 0, sizeof(wcid_entry));
- if (crypto->cmd == SET_KEY)
- memcpy(wcid_entry.mac, crypto->address, ETH_ALEN);
- rt2800_register_multiwrite(rt2x00dev, offset,
- &wcid_entry, sizeof(wcid_entry));
}
int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev,
@@ -1026,20 +1042,24 @@ int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev,
/*
* Update WCID information
*/
- rt2800_config_wcid_attr(rt2x00dev, crypto, key);
+ rt2800_config_wcid(rt2x00dev, crypto->address, key->hw_key_idx);
+ rt2800_config_wcid_attr_bssidx(rt2x00dev, key->hw_key_idx,
+ crypto->bssidx);
+ rt2800_config_wcid_attr_cipher(rt2x00dev, crypto, key);
return 0;
}
EXPORT_SYMBOL_GPL(rt2800_config_shared_key);
-static inline int rt2800_find_pairwise_keyslot(struct rt2x00_dev *rt2x00dev)
+static inline int rt2800_find_wcid(struct rt2x00_dev *rt2x00dev)
{
+ struct mac_wcid_entry wcid_entry;
int idx;
- u32 offset, reg;
+ u32 offset;
/*
- * Search for the first free pairwise key entry and return the
- * corresponding index.
+ * Search for the first free WCID entry and return the corresponding
+ * index.
*
* Make sure the WCID starts _after_ the last possible shared key
* entry (>32).
@@ -1049,11 +1069,17 @@ static inline int rt2800_find_pairwise_keyslot(struct rt2x00_dev *rt2x00dev)
* first 222 entries.
*/
for (idx = 33; idx <= 222; idx++) {
- offset = MAC_WCID_ATTR_ENTRY(idx);
- rt2800_register_read(rt2x00dev, offset, &reg);
- if (!reg)
+ offset = MAC_WCID_ENTRY(idx);
+ rt2800_register_multiread(rt2x00dev, offset, &wcid_entry,
+ sizeof(wcid_entry));
+ if (is_broadcast_ether_addr(wcid_entry.mac))
return idx;
}
+
+ /*
+ * Use -1 to indicate that we don't have any more space in the WCID
+ * table.
+ */
return -1;
}
@@ -1063,13 +1089,15 @@ int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
{
struct hw_key_entry key_entry;
u32 offset;
- int idx;
if (crypto->cmd == SET_KEY) {
- idx = rt2800_find_pairwise_keyslot(rt2x00dev);
- if (idx < 0)
+ /*
+ * Allow key configuration only for STAs that are
+ * known by the hw.
+ */
+ if (crypto->wcid < 0)
return -ENOSPC;
- key->hw_key_idx = idx;
+ key->hw_key_idx = crypto->wcid;
memcpy(key_entry.key, crypto->key,
sizeof(key_entry.key));
@@ -1086,12 +1114,59 @@ int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
/*
* Update WCID information
*/
- rt2800_config_wcid_attr(rt2x00dev, crypto, key);
+ rt2800_config_wcid_attr_cipher(rt2x00dev, crypto, key);
return 0;
}
EXPORT_SYMBOL_GPL(rt2800_config_pairwise_key);
+int rt2800_sta_add(struct rt2x00_dev *rt2x00dev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ int wcid;
+ struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta);
+
+ /*
+ * Find next free WCID.
+ */
+ wcid = rt2800_find_wcid(rt2x00dev);
+
+ /*
+ * Store selected wcid even if it is invalid so that we can
+ * later decide if the STA is uploaded into the hw.
+ */
+ sta_priv->wcid = wcid;
+
+ /*
+ * No space left in the device, however, we can still communicate
+ * with the STA -> No error.
+ */
+ if (wcid < 0)
+ return 0;
+
+ /*
+ * Clean up WCID attributes and write STA address to the device.
+ */
+ rt2800_delete_wcid_attr(rt2x00dev, wcid);
+ rt2800_config_wcid(rt2x00dev, sta->addr, wcid);
+ rt2800_config_wcid_attr_bssidx(rt2x00dev, wcid,
+ rt2x00lib_get_bssidx(rt2x00dev, vif));
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2800_sta_add);
+
+int rt2800_sta_remove(struct rt2x00_dev *rt2x00dev, int wcid)
+{
+ /*
+ * Remove WCID entry, no need to clean the attributes as they will
+ * get renewed when the WCID is reused.
+ */
+ rt2800_config_wcid(rt2x00dev, NULL, wcid);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2800_sta_remove);
+
void rt2800_config_filter(struct rt2x00_dev *rt2x00dev,
const unsigned int filter_flags)
{
@@ -2771,11 +2846,8 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
SHARED_KEY_MODE_ENTRY(i), 0);
for (i = 0; i < 256; i++) {
- static const u32 wcid[2] = { 0xffffffff, 0x00ffffff };
- rt2800_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i),
- wcid, sizeof(wcid));
-
- rt2800_register_write(rt2x00dev, MAC_WCID_ATTR_ENTRY(i), 0);
+ rt2800_config_wcid(rt2x00dev, NULL, i);
+ rt2800_delete_wcid_attr(rt2x00dev, i);
rt2800_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0);
}
@@ -3697,14 +3769,15 @@ static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i)
rt2800_regbusy_read(rt2x00dev, EFUSE_CTRL, EFUSE_CTRL_KICK, &reg);
/* Apparently the data is read from end to start */
- rt2800_register_read_lock(rt2x00dev, EFUSE_DATA3,
- (u32 *)&rt2x00dev->eeprom[i]);
- rt2800_register_read_lock(rt2x00dev, EFUSE_DATA2,
- (u32 *)&rt2x00dev->eeprom[i + 2]);
- rt2800_register_read_lock(rt2x00dev, EFUSE_DATA1,
- (u32 *)&rt2x00dev->eeprom[i + 4]);
- rt2800_register_read_lock(rt2x00dev, EFUSE_DATA0,
- (u32 *)&rt2x00dev->eeprom[i + 6]);
+ rt2800_register_read_lock(rt2x00dev, EFUSE_DATA3, &reg);
+ /* The returned value is in CPU order, but eeprom is le */
+ rt2x00dev->eeprom[i] = cpu_to_le32(reg);
+ rt2800_register_read_lock(rt2x00dev, EFUSE_DATA2, &reg);
+ *(u32 *)&rt2x00dev->eeprom[i + 2] = cpu_to_le32(reg);
+ rt2800_register_read_lock(rt2x00dev, EFUSE_DATA1, &reg);
+ *(u32 *)&rt2x00dev->eeprom[i + 4] = cpu_to_le32(reg);
+ rt2800_register_read_lock(rt2x00dev, EFUSE_DATA0, &reg);
+ *(u32 *)&rt2x00dev->eeprom[i + 6] = cpu_to_le32(reg);
mutex_unlock(&rt2x00dev->csr_mutex);
}
@@ -3870,19 +3943,23 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
return -ENODEV;
}
- if (!rt2x00_rf(rt2x00dev, RF2820) &&
- !rt2x00_rf(rt2x00dev, RF2850) &&
- !rt2x00_rf(rt2x00dev, RF2720) &&
- !rt2x00_rf(rt2x00dev, RF2750) &&
- !rt2x00_rf(rt2x00dev, RF3020) &&
- !rt2x00_rf(rt2x00dev, RF2020) &&
- !rt2x00_rf(rt2x00dev, RF3021) &&
- !rt2x00_rf(rt2x00dev, RF3022) &&
- !rt2x00_rf(rt2x00dev, RF3052) &&
- !rt2x00_rf(rt2x00dev, RF3320) &&
- !rt2x00_rf(rt2x00dev, RF5370) &&
- !rt2x00_rf(rt2x00dev, RF5390)) {
- ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+ switch (rt2x00dev->chip.rf) {
+ case RF2820:
+ case RF2850:
+ case RF2720:
+ case RF2750:
+ case RF3020:
+ case RF2020:
+ case RF3021:
+ case RF3022:
+ case RF3052:
+ case RF3320:
+ case RF5370:
+ case RF5390:
+ break;
+ default:
+ ERROR(rt2x00dev, "Invalid RF chipset 0x%x detected.\n",
+ rt2x00dev->chip.rf);
return -ENODEV;
}
@@ -4321,7 +4398,8 @@ int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
}
EXPORT_SYMBOL_GPL(rt2800_set_rts_threshold);
-int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
+int rt2800_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 queue_idx,
const struct ieee80211_tx_queue_params *params)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -4337,7 +4415,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
* we are free to update the registers based on the value
* in the queue parameter.
*/
- retval = rt2x00mac_conf_tx(hw, queue_idx, params);
+ retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params);
if (retval)
return retval;
@@ -4389,7 +4467,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
}
EXPORT_SYMBOL_GPL(rt2800_conf_tx);
-u64 rt2800_get_tsf(struct ieee80211_hw *hw)
+u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
u64 tsf;
@@ -4409,8 +4487,19 @@ int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
u8 buf_size)
{
+ struct rt2x00_sta *sta_priv = (struct rt2x00_sta *)sta->drv_priv;
int ret = 0;
+ /*
+ * Don't allow aggregation for stations the hardware isn't aware
+ * of because tx status reports for frames to an unknown station
+ * always contain wcid=255 and thus we can't distinguish between
+ * multiple stations which leads to unwanted situations when the
+ * hw reorders frames due to aggregation.
+ */
+ if (sta_priv->wcid < 0)
+ return 1;
+
switch (action) {
case IEEE80211_AMPDU_RX_START:
case IEEE80211_AMPDU_RX_STOP:
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index 69deb3148ae7..8c3c281904fe 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -152,7 +152,7 @@ void rt2800_write_tx_data(struct queue_entry *entry,
struct txentry_desc *txdesc);
void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *txdesc);
-void rt2800_txdone_entry(struct queue_entry *entry, u32 status);
+void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32* txwi);
void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
void rt2800_clear_beacon(struct queue_entry *entry);
@@ -166,6 +166,9 @@ int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev,
int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_crypto *crypto,
struct ieee80211_key_conf *key);
+int rt2800_sta_add(struct rt2x00_dev *rt2x00dev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
+int rt2800_sta_remove(struct rt2x00_dev *rt2x00dev, int wcid);
void rt2800_config_filter(struct rt2x00_dev *rt2x00dev,
const unsigned int filter_flags);
void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
@@ -194,9 +197,10 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev);
void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32,
u16 *iv16);
int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
-int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
+int rt2800_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 queue_idx,
const struct ieee80211_tx_queue_params *params);
-u64 rt2800_get_tsf(struct ieee80211_hw *hw);
+u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index ebc17ad61dec..da48c8ac27bd 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -200,13 +200,6 @@ static void rt2800pci_start_queue(struct data_queue *queue)
rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
break;
case QID_BEACON:
- /*
- * Allow beacon tasklets to be scheduled for periodic
- * beacon updates.
- */
- tasklet_enable(&rt2x00dev->tbtt_tasklet);
- tasklet_enable(&rt2x00dev->pretbtt_tasklet);
-
rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
@@ -269,10 +262,13 @@ static void rt2800pci_stop_queue(struct data_queue *queue)
rt2x00pci_register_write(rt2x00dev, INT_TIMER_EN, reg);
/*
- * Wait for tbtt tasklets to finish.
+ * Wait for current invocation to finish. The tasklet
+ * won't be scheduled anymore afterwards since we disabled
+ * the TBTT and PRE TBTT timer.
*/
- tasklet_disable(&rt2x00dev->tbtt_tasklet);
- tasklet_disable(&rt2x00dev->pretbtt_tasklet);
+ tasklet_kill(&rt2x00dev->tbtt_tasklet);
+ tasklet_kill(&rt2x00dev->pretbtt_tasklet);
+
break;
default:
break;
@@ -437,14 +433,6 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
if (state == STATE_RADIO_IRQ_ON) {
rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
-
- /*
- * Enable tasklets. The beacon related tasklets are
- * enabled when the beacon queue is started.
- */
- tasklet_enable(&rt2x00dev->txstatus_tasklet);
- tasklet_enable(&rt2x00dev->rxdone_tasklet);
- tasklet_enable(&rt2x00dev->autowake_tasklet);
}
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
@@ -472,12 +460,13 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
if (state == STATE_RADIO_IRQ_OFF) {
/*
- * Ensure that all tasklets are finished before
- * disabling the interrupts.
+ * Wait for possibly running tasklets to finish.
*/
- tasklet_disable(&rt2x00dev->txstatus_tasklet);
- tasklet_disable(&rt2x00dev->rxdone_tasklet);
- tasklet_disable(&rt2x00dev->autowake_tasklet);
+ tasklet_kill(&rt2x00dev->txstatus_tasklet);
+ tasklet_kill(&rt2x00dev->rxdone_tasklet);
+ tasklet_kill(&rt2x00dev->autowake_tasklet);
+ tasklet_kill(&rt2x00dev->tbtt_tasklet);
+ tasklet_kill(&rt2x00dev->pretbtt_tasklet);
}
}
@@ -630,11 +619,11 @@ static void rt2800pci_write_tx_desc(struct queue_entry *entry,
/*
* Initialize TX descriptor
*/
- rt2x00_desc_read(txd, 0, &word);
+ word = 0;
rt2x00_set_field32(&word, TXD_W0_SD_PTR0, skbdesc->skb_dma);
rt2x00_desc_write(txd, 0, word);
- rt2x00_desc_read(txd, 1, &word);
+ word = 0;
rt2x00_set_field32(&word, TXD_W1_SD_LEN1, entry->skb->len);
rt2x00_set_field32(&word, TXD_W1_LAST_SEC1,
!test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
@@ -645,12 +634,12 @@ static void rt2800pci_write_tx_desc(struct queue_entry *entry,
rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 0);
rt2x00_desc_write(txd, 1, word);
- rt2x00_desc_read(txd, 2, &word);
+ word = 0;
rt2x00_set_field32(&word, TXD_W2_SD_PTR1,
skbdesc->skb_dma + TXWI_DESC_SIZE);
rt2x00_desc_write(txd, 2, word);
- rt2x00_desc_read(txd, 3, &word);
+ word = 0;
rt2x00_set_field32(&word, TXD_W3_WIV,
!test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W3_QSEL, 2);
@@ -771,7 +760,7 @@ static bool rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
}
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
- rt2800_txdone_entry(entry, status);
+ rt2800_txdone_entry(entry, status, rt2800pci_get_txwi(entry));
if (--max_tx_done == 0)
break;
@@ -813,14 +802,16 @@ static void rt2800pci_pretbtt_tasklet(unsigned long data)
{
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
rt2x00lib_pretbtt(rt2x00dev);
- rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_PRE_TBTT);
+ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_PRE_TBTT);
}
static void rt2800pci_tbtt_tasklet(unsigned long data)
{
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
rt2x00lib_beacondone(rt2x00dev);
- rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TBTT);
+ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TBTT);
}
static void rt2800pci_rxdone_tasklet(unsigned long data)
@@ -828,7 +819,7 @@ static void rt2800pci_rxdone_tasklet(unsigned long data)
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
if (rt2x00pci_rxdone(rt2x00dev))
tasklet_schedule(&rt2x00dev->rxdone_tasklet);
- else
+ else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE);
}
@@ -836,7 +827,8 @@ static void rt2800pci_autowake_tasklet(unsigned long data)
{
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
rt2800pci_wakeup(rt2x00dev);
- rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_AUTO_WAKEUP);
+ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_AUTO_WAKEUP);
}
static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev)
@@ -1023,6 +1015,8 @@ static const struct ieee80211_ops rt2800pci_mac80211_ops = {
.get_stats = rt2x00mac_get_stats,
.get_tkip_seq = rt2800_get_tkip_seq,
.set_rts_threshold = rt2800_set_rts_threshold,
+ .sta_add = rt2x00mac_sta_add,
+ .sta_remove = rt2x00mac_sta_remove,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2800_conf_tx,
.get_tsf = rt2800_get_tsf,
@@ -1084,6 +1078,8 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.config_erp = rt2800_config_erp,
.config_ant = rt2800_config_ant,
.config = rt2800_config,
+ .sta_add = rt2800_sta_add,
+ .sta_remove = rt2800_sta_remove,
};
static const struct data_queue_desc rt2800pci_queue_rx = {
@@ -1161,6 +1157,7 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
#endif
#ifdef CONFIG_RT2800PCI_RT53XX
{ PCI_DEVICE(0x1814, 0x5390) },
+ { PCI_DEVICE(0x1814, 0x539a) },
{ PCI_DEVICE(0x1814, 0x539f) },
#endif
{ 0, }
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 939563162fb3..f1565792f270 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -464,6 +464,15 @@ static bool rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg)
int wcid, ack, pid;
int tx_wcid, tx_ack, tx_pid;
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
+ !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) {
+ WARNING(entry->queue->rt2x00dev,
+ "Data pending for entry %u in queue %u\n",
+ entry->entry_idx, entry->queue->qid);
+ cond_resched();
+ return false;
+ }
+
wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
@@ -529,12 +538,12 @@ static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev)
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
if (rt2800usb_txdone_entry_check(entry, reg))
break;
+ entry = NULL;
}
- if (!entry || rt2x00queue_empty(queue))
- break;
-
- rt2800_txdone_entry(entry, reg);
+ if (entry)
+ rt2800_txdone_entry(entry, reg,
+ rt2800usb_get_txwi(entry));
}
}
@@ -558,8 +567,10 @@ static void rt2800usb_work_txdone(struct work_struct *work)
while (!rt2x00queue_empty(queue)) {
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
- if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
+ !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
break;
+
if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
else if (rt2x00queue_status_timeout(entry))
@@ -749,6 +760,8 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
.get_stats = rt2x00mac_get_stats,
.get_tkip_seq = rt2800_get_tkip_seq,
.set_rts_threshold = rt2800_set_rts_threshold,
+ .sta_add = rt2x00mac_sta_add,
+ .sta_remove = rt2x00mac_sta_remove,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2800_conf_tx,
.get_tsf = rt2800_get_tsf,
@@ -806,6 +819,8 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
.config_erp = rt2800_config_erp,
.config_ant = rt2800_config_ant,
.config = rt2800_config,
+ .sta_add = rt2800_sta_add,
+ .sta_remove = rt2800_sta_remove,
};
static const struct data_queue_desc rt2800usb_queue_rx = {
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index f82bfeb79ebb..2ec5c00235e6 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -478,6 +478,8 @@ struct rt2x00lib_crypto {
u8 key[16];
u8 tx_mic[8];
u8 rx_mic[8];
+
+ int wcid;
};
/*
@@ -512,6 +514,19 @@ struct rt2x00intf_conf {
};
/*
+ * Private structure for storing STA details
+ * wcid: Wireless Client ID
+ */
+struct rt2x00_sta {
+ int wcid;
+};
+
+static inline struct rt2x00_sta* sta_to_rt2x00_sta(struct ieee80211_sta *sta)
+{
+ return (struct rt2x00_sta *)sta->drv_priv;
+}
+
+/*
* rt2x00lib callback functions.
*/
struct rt2x00lib_ops {
@@ -620,6 +635,11 @@ struct rt2x00lib_ops {
void (*config) (struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_conf *libconf,
const unsigned int changed_flags);
+ int (*sta_add) (struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
+ int (*sta_remove) (struct rt2x00_dev *rt2x00dev,
+ int wcid);
};
/*
@@ -1226,6 +1246,12 @@ static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
/*
+ * Utility functions.
+ */
+u32 rt2x00lib_get_bssidx(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_vif *vif);
+
+/*
* Interrupt context handlers.
*/
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
@@ -1261,6 +1287,10 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
#else
#define rt2x00mac_set_key NULL
#endif /* CONFIG_RT2X00_LIB_CRYPTO */
+int rt2x00mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
+int rt2x00mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw);
void rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw);
int rt2x00mac_get_stats(struct ieee80211_hw *hw,
@@ -1269,7 +1299,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
u32 changes);
-int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
+int rt2x00mac_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params);
void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw);
void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop);
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 0955c941317f..e1fb2a8569be 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -33,6 +33,22 @@
#include "rt2x00lib.h"
/*
+ * Utility functions.
+ */
+u32 rt2x00lib_get_bssidx(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_vif *vif)
+{
+ /*
+ * When in STA mode, bssidx is always 0 otherwise local_address[5]
+ * contains the bss number, see BSS_ID_MASK comments for details.
+ */
+ if (rt2x00dev->intf_sta_count)
+ return 0;
+ return vif->addr[5] & (rt2x00dev->ops->max_ap_intf - 1);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_get_bssidx);
+
+/*
* Radio control handlers.
*/
int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
@@ -915,6 +931,11 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
rt2x00dev->hw->extra_tx_headroom += RT2X00_ALIGN_SIZE;
/*
+ * Tell mac80211 about the size of our private STA structure.
+ */
+ rt2x00dev->hw->sta_data_size = sizeof(struct rt2x00_sta);
+
+ /*
* Allocate tx status FIFO for driver use.
*/
if (test_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags)) {
@@ -946,7 +967,6 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
tasklet_init(&rt2x00dev->taskletname, \
rt2x00dev->ops->lib->taskletname, \
(unsigned long)rt2x00dev); \
- tasklet_disable(&rt2x00dev->taskletname); \
}
RT2X00_TASKLET_INIT(txstatus_tasklet);
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 4ccf23805973..bf0acff07807 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -494,6 +494,7 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct rt2x00lib_crypto crypto;
static const u8 bcast_addr[ETH_ALEN] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, };
+ struct rt2x00_sta *sta_priv = NULL;
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return 0;
@@ -504,24 +505,18 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
memset(&crypto, 0, sizeof(crypto));
- /*
- * When in STA mode, bssidx is always 0 otherwise local_address[5]
- * contains the bss number, see BSS_ID_MASK comments for details.
- */
- if (rt2x00dev->intf_sta_count)
- crypto.bssidx = 0;
- else
- crypto.bssidx = vif->addr[5] & (rt2x00dev->ops->max_ap_intf - 1);
-
+ crypto.bssidx = rt2x00lib_get_bssidx(rt2x00dev, vif);
crypto.cipher = rt2x00crypto_key_to_cipher(key);
if (crypto.cipher == CIPHER_NONE)
return -EOPNOTSUPP;
crypto.cmd = cmd;
- if (sta)
+ if (sta) {
crypto.address = sta->addr;
- else
+ sta_priv = sta_to_rt2x00_sta(sta);
+ crypto.wcid = sta_priv->wcid;
+ } else
crypto.address = bcast_addr;
if (crypto.cipher == CIPHER_TKIP)
@@ -560,6 +555,39 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
EXPORT_SYMBOL_GPL(rt2x00mac_set_key);
#endif /* CONFIG_RT2X00_LIB_CRYPTO */
+int rt2x00mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta);
+
+ /*
+ * If there's no space left in the device table store
+ * -1 as wcid but tell mac80211 everything went ok.
+ */
+ if (rt2x00dev->ops->lib->sta_add(rt2x00dev, vif, sta))
+ sta_priv->wcid = -1;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_sta_add);
+
+int rt2x00mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta);
+
+ /*
+ * If we never sent the STA to the device no need to clean it up.
+ */
+ if (sta_priv->wcid < 0)
+ return 0;
+
+ return rt2x00dev->ops->lib->sta_remove(rt2x00dev, sta_priv->wcid);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_sta_remove);
+
void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -685,7 +713,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed);
-int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
+int rt2x00mac_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 queue_idx,
const struct ieee80211_tx_queue_params *params)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 29edb9fbe6f1..5adfb3eab9cd 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -310,11 +310,16 @@ static void rt2x00queue_create_tx_descriptor_ht(struct rt2x00_dev *rt2x00dev,
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0];
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct rt2x00_sta *sta_priv = NULL;
- if (tx_info->control.sta)
+ if (tx_info->control.sta) {
txdesc->u.ht.mpdu_density =
tx_info->control.sta->ht_cap.ampdu_density;
+ sta_priv = sta_to_rt2x00_sta(tx_info->control.sta);
+ txdesc->u.ht.wcid = sta_priv->wcid;
+ }
+
txdesc->u.ht.ba_size = 7; /* FIXME: What value is needed? */
/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index f2100f4ddcff..349008d1fb28 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -288,8 +288,8 @@ enum txentry_desc_flags {
* @signal: PLCP signal.
* @service: PLCP service.
* @msc: MCS.
- * @stbc: STBC.
- * @ba_size: BA size.
+ * @stbc: Use Space Time Block Coding (only available for MCS rates < 8).
+ * @ba_size: Size of the recepients RX reorder buffer - 1.
* @rate_mode: Rate mode (See @enum rate_modulation).
* @mpdu_density: MDPU density.
* @retry_limit: Max number of retries.
@@ -321,6 +321,7 @@ struct txentry_desc {
u8 ba_size;
u8 mpdu_density;
enum txop txop;
+ int wcid;
} ht;
} u;
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index b6b4542c2460..1e31050dafc9 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -262,23 +262,20 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
struct queue_entry *entry = (struct queue_entry *)urb->context;
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- if (!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;
-
- if (rt2x00dev->ops->lib->tx_dma_done)
- rt2x00dev->ops->lib->tx_dma_done(entry);
-
- /*
- * Report the frame as DMA done
- */
- rt2x00lib_dmadone(entry);
-
/*
* Check if the frame was correctly uploaded
*/
if (urb->status)
set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
+ /*
+ * Report the frame as DMA done
+ */
+ rt2x00lib_dmadone(entry);
+ if (rt2x00dev->ops->lib->tx_dma_done)
+ rt2x00dev->ops->lib->tx_dma_done(entry);
/*
* Schedule the delayed work for reading the TX status
* from the device.
@@ -874,18 +871,8 @@ int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state)
{
struct ieee80211_hw *hw = usb_get_intfdata(usb_intf);
struct rt2x00_dev *rt2x00dev = hw->priv;
- int retval;
-
- retval = rt2x00lib_suspend(rt2x00dev, state);
- if (retval)
- return retval;
- /*
- * Decrease usbdev refcount.
- */
- usb_put_dev(interface_to_usbdev(usb_intf));
-
- return 0;
+ return rt2x00lib_suspend(rt2x00dev, state);
}
EXPORT_SYMBOL_GPL(rt2x00usb_suspend);
@@ -894,8 +881,6 @@ int rt2x00usb_resume(struct usb_interface *usb_intf)
struct ieee80211_hw *hw = usb_get_intfdata(usb_intf);
struct rt2x00_dev *rt2x00dev = hw->priv;
- usb_get_dev(interface_to_usbdev(usb_intf));
-
return rt2x00lib_resume(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00usb_resume);
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 53110b83bf6e..bf55b4a311e3 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1142,11 +1142,6 @@ static void rt61pci_start_queue(struct data_queue *queue)
rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
break;
case QID_BEACON:
- /*
- * Allow the tbtt tasklet to be scheduled.
- */
- tasklet_enable(&rt2x00dev->tbtt_tasklet);
-
rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
@@ -1230,7 +1225,7 @@ static void rt61pci_stop_queue(struct data_queue *queue)
/*
* Wait for possibly running tbtt tasklets.
*/
- tasklet_disable(&rt2x00dev->tbtt_tasklet);
+ tasklet_kill(&rt2x00dev->tbtt_tasklet);
break;
default:
break;
@@ -1731,13 +1726,6 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg);
rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg);
-
- /*
- * Enable tasklets.
- */
- tasklet_enable(&rt2x00dev->txstatus_tasklet);
- tasklet_enable(&rt2x00dev->rxdone_tasklet);
- tasklet_enable(&rt2x00dev->autowake_tasklet);
}
/*
@@ -1772,9 +1760,10 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
/*
* Ensure that all tasklets are finished.
*/
- tasklet_disable(&rt2x00dev->txstatus_tasklet);
- tasklet_disable(&rt2x00dev->rxdone_tasklet);
- tasklet_disable(&rt2x00dev->autowake_tasklet);
+ tasklet_kill(&rt2x00dev->txstatus_tasklet);
+ tasklet_kill(&rt2x00dev->rxdone_tasklet);
+ tasklet_kill(&rt2x00dev->autowake_tasklet);
+ tasklet_kill(&rt2x00dev->tbtt_tasklet);
}
}
@@ -2300,22 +2289,24 @@ static void rt61pci_txstatus_tasklet(unsigned long data)
{
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
rt61pci_txdone(rt2x00dev);
- rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TXDONE);
+ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TXDONE);
}
static void rt61pci_tbtt_tasklet(unsigned long data)
{
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
rt2x00lib_beacondone(rt2x00dev);
- rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_BEACON_DONE);
+ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_BEACON_DONE);
}
static void rt61pci_rxdone_tasklet(unsigned long data)
{
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
if (rt2x00pci_rxdone(rt2x00dev))
- rt2x00pci_rxdone(rt2x00dev);
- else
+ tasklet_schedule(&rt2x00dev->rxdone_tasklet);
+ else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE);
}
@@ -2325,7 +2316,8 @@ static void rt61pci_autowake_tasklet(unsigned long data)
rt61pci_wakeup(rt2x00dev);
rt2x00pci_register_write(rt2x00dev,
M2H_CMD_DONE_CSR, 0xffffffff);
- rt61pci_enable_mcu_interrupt(rt2x00dev, MCU_INT_MASK_CSR_TWAKEUP);
+ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ rt61pci_enable_mcu_interrupt(rt2x00dev, MCU_INT_MASK_CSR_TWAKEUP);
}
static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
@@ -2891,7 +2883,8 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* IEEE80211 stack callback functions.
*/
-static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
+static int rt61pci_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 queue_idx,
const struct ieee80211_tx_queue_params *params)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -2907,7 +2900,7 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
* we are free to update the registers based on the value
* in the queue parameter.
*/
- retval = rt2x00mac_conf_tx(hw, queue_idx, params);
+ retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params);
if (retval)
return retval;
@@ -2948,7 +2941,7 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
return 0;
}
-static u64 rt61pci_get_tsf(struct ieee80211_hw *hw)
+static u64 rt61pci_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
u64 tsf;
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 0baeb894f093..cfb19dbb0a67 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -2222,7 +2222,8 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* IEEE80211 stack callback functions.
*/
-static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
+static int rt73usb_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 queue_idx,
const struct ieee80211_tx_queue_params *params)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -2238,7 +2239,7 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
* we are free to update the registers based on the value
* in the queue parameter.
*/
- retval = rt2x00mac_conf_tx(hw, queue_idx, params);
+ retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params);
if (retval)
return retval;
@@ -2279,7 +2280,7 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
return 0;
}
-static u64 rt73usb_get_tsf(struct ieee80211_hw *hw)
+static u64 rt73usb_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
u64 tsf;
diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c
index 66b29dc07cc3..0082015ff664 100644
--- a/drivers/net/wireless/rtl818x/rtl8180/dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c
@@ -669,7 +669,8 @@ static void rtl8180_stop(struct ieee80211_hw *dev)
rtl8180_free_tx_ring(dev, i);
}
-static u64 rtl8180_get_tsf(struct ieee80211_hw *dev)
+static u64 rtl8180_get_tsf(struct ieee80211_hw *dev,
+ struct ieee80211_vif *vif)
{
struct rtl8180_priv *priv = dev->priv;
@@ -701,7 +702,7 @@ static void rtl8180_beacon_work(struct work_struct *work)
* TODO: make hardware update beacon timestamp
*/
mgmt = (struct ieee80211_mgmt *)skb->data;
- mgmt->u.beacon.timestamp = cpu_to_le64(rtl8180_get_tsf(dev));
+ mgmt->u.beacon.timestamp = cpu_to_le64(rtl8180_get_tsf(dev, vif));
/* TODO: use actual beacon queue */
skb_set_queue_mapping(skb, 0);
diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c
index 1e0be14d10d4..24873b55b55c 100644
--- a/drivers/net/wireless/rtl818x/rtl8187/dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c
@@ -1241,7 +1241,8 @@ static void rtl8187_configure_filter(struct ieee80211_hw *dev,
rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf);
}
-static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue,
+static int rtl8187_conf_tx(struct ieee80211_hw *dev,
+ struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct rtl8187_priv *priv = dev->priv;
@@ -1277,7 +1278,7 @@ static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue,
return 0;
}
-static u64 rtl8187_get_tsf(struct ieee80211_hw *dev)
+static u64 rtl8187_get_tsf(struct ieee80211_hw *dev, struct ieee80211_vif *vif)
{
struct rtl8187_priv *priv = dev->priv;
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
index 0b598db38da9..d4fdd2a5a739 100644
--- a/drivers/net/wireless/rtlwifi/base.c
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -311,6 +311,8 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw)
IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_BEACON_FILTER |
IEEE80211_HW_AMPDU_AGGREGATION |
+ IEEE80211_HW_CONNECTION_MONITOR |
+ /* IEEE80211_HW_SUPPORTS_CQM_RSSI | */
IEEE80211_HW_REPORTS_TX_ACK_STATUS | 0;
/* swlps or hwlps has been set in diff chip in init_sw_vars */
@@ -664,6 +666,167 @@ static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw)
return hw_rate;
}
+/* mac80211's rate_idx is like this:
+ *
+ * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ
+ *
+ * B/G rate:
+ * (rx_status->flag & RX_FLAG_HT) = 0,
+ * DESC92_RATE1M-->DESC92_RATE54M ==> idx is 0-->11,
+ *
+ * N rate:
+ * (rx_status->flag & RX_FLAG_HT) = 1,
+ * DESC92_RATEMCS0-->DESC92_RATEMCS15 ==> idx is 0-->15
+ *
+ * 5G band:rx_status->band == IEEE80211_BAND_5GHZ
+ * A rate:
+ * (rx_status->flag & RX_FLAG_HT) = 0,
+ * DESC92_RATE6M-->DESC92_RATE54M ==> idx is 0-->7,
+ *
+ * N rate:
+ * (rx_status->flag & RX_FLAG_HT) = 1,
+ * DESC92_RATEMCS0-->DESC92_RATEMCS15 ==> idx is 0-->15
+ */
+int rtlwifi_rate_mapping(struct ieee80211_hw *hw,
+ bool isht, u8 desc_rate, bool first_ampdu)
+{
+ int rate_idx;
+
+ if (false == isht) {
+ if (IEEE80211_BAND_2GHZ == hw->conf.channel->band) {
+ switch (desc_rate) {
+ case DESC92_RATE1M:
+ rate_idx = 0;
+ break;
+ case DESC92_RATE2M:
+ rate_idx = 1;
+ break;
+ case DESC92_RATE5_5M:
+ rate_idx = 2;
+ break;
+ case DESC92_RATE11M:
+ rate_idx = 3;
+ break;
+ case DESC92_RATE6M:
+ rate_idx = 4;
+ break;
+ case DESC92_RATE9M:
+ rate_idx = 5;
+ break;
+ case DESC92_RATE12M:
+ rate_idx = 6;
+ break;
+ case DESC92_RATE18M:
+ rate_idx = 7;
+ break;
+ case DESC92_RATE24M:
+ rate_idx = 8;
+ break;
+ case DESC92_RATE36M:
+ rate_idx = 9;
+ break;
+ case DESC92_RATE48M:
+ rate_idx = 10;
+ break;
+ case DESC92_RATE54M:
+ rate_idx = 11;
+ break;
+ default:
+ rate_idx = 0;
+ break;
+ }
+ } else {
+ switch (desc_rate) {
+ case DESC92_RATE6M:
+ rate_idx = 0;
+ break;
+ case DESC92_RATE9M:
+ rate_idx = 1;
+ break;
+ case DESC92_RATE12M:
+ rate_idx = 2;
+ break;
+ case DESC92_RATE18M:
+ rate_idx = 3;
+ break;
+ case DESC92_RATE24M:
+ rate_idx = 4;
+ break;
+ case DESC92_RATE36M:
+ rate_idx = 5;
+ break;
+ case DESC92_RATE48M:
+ rate_idx = 6;
+ break;
+ case DESC92_RATE54M:
+ rate_idx = 7;
+ break;
+ default:
+ rate_idx = 0;
+ break;
+ }
+ }
+
+ } else {
+
+ switch (desc_rate) {
+ case DESC92_RATEMCS0:
+ rate_idx = 0;
+ break;
+ case DESC92_RATEMCS1:
+ rate_idx = 1;
+ break;
+ case DESC92_RATEMCS2:
+ rate_idx = 2;
+ break;
+ case DESC92_RATEMCS3:
+ rate_idx = 3;
+ break;
+ case DESC92_RATEMCS4:
+ rate_idx = 4;
+ break;
+ case DESC92_RATEMCS5:
+ rate_idx = 5;
+ break;
+ case DESC92_RATEMCS6:
+ rate_idx = 6;
+ break;
+ case DESC92_RATEMCS7:
+ rate_idx = 7;
+ break;
+ case DESC92_RATEMCS8:
+ rate_idx = 8;
+ break;
+ case DESC92_RATEMCS9:
+ rate_idx = 9;
+ break;
+ case DESC92_RATEMCS10:
+ rate_idx = 10;
+ break;
+ case DESC92_RATEMCS11:
+ rate_idx = 11;
+ break;
+ case DESC92_RATEMCS12:
+ rate_idx = 12;
+ break;
+ case DESC92_RATEMCS13:
+ rate_idx = 13;
+ break;
+ case DESC92_RATEMCS14:
+ rate_idx = 14;
+ break;
+ case DESC92_RATEMCS15:
+ rate_idx = 15;
+ break;
+ default:
+ rate_idx = 0;
+ break;
+ }
+ }
+ return rate_idx;
+}
+EXPORT_SYMBOL(rtlwifi_rate_mapping);
+
void rtl_get_tcb_desc(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info,
struct ieee80211_sta *sta,
@@ -689,7 +852,7 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
*So tcb_desc->hw_rate is just used for
*special data and mgt frames
*/
- if (info->control.rates[0].idx == 0 &&
+ if (info->control.rates[0].idx == 0 ||
ieee80211_is_nullfunc(fc)) {
tcb_desc->use_driver_rate = true;
tcb_desc->ratr_index = RATR_INX_WIRELESS_MC;
@@ -977,7 +1140,7 @@ void rtl_watchdog_wq_callback(void *data)
}
/*
- *<3> to check if traffic busy, if
+ *<2> to check if traffic busy, if
* busytraffic we don't change channel
*/
if (mac->link_state >= MAC80211_LINKED) {
diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h
index a91f3eee59c8..4ae905983d0d 100644
--- a/drivers/net/wireless/rtlwifi/base.h
+++ b/drivers/net/wireless/rtlwifi/base.h
@@ -140,4 +140,6 @@ u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie);
void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len);
u8 rtl_tid_to_ac(struct ieee80211_hw *hw, u8 tid);
extern struct attribute_group rtl_attribute_group;
+int rtlwifi_rate_mapping(struct ieee80211_hw *hw,
+ bool isht, u8 desc_rate, bool first_ampdu);
#endif
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index 1bdc1aa305c0..3f0f056fae9c 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -504,7 +504,8 @@ static int _rtl_get_hal_qnum(u16 queue)
*for mac80211 VO=0, VI=1, BE=2, BK=3
*for rtl819x BE=0, BK=1, VI=2, VO=3
*/
-static int rtl_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
+static int rtl_op_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *param)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -610,6 +611,11 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
mac->link_state = MAC80211_NOLINK;
memset(mac->bssid, 0, 6);
+
+ /* reset sec info */
+ rtl_cam_reset_sec_info(hw);
+
+ rtl_cam_reset_all_entry(hw);
mac->vendor = PEER_UNKNOWN;
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
@@ -770,7 +776,7 @@ out:
mutex_unlock(&rtlpriv->locks.conf_mutex);
}
-static u64 rtl_op_get_tsf(struct ieee80211_hw *hw)
+static u64 rtl_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u64 tsf;
@@ -779,7 +785,8 @@ static u64 rtl_op_get_tsf(struct ieee80211_hw *hw)
return tsf;
}
-static void rtl_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+static void rtl_op_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ u64 tsf)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
@@ -789,7 +796,8 @@ static void rtl_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CORRECT_TSF, (u8 *) (&bibss));
}
-static void rtl_op_reset_tsf(struct ieee80211_hw *hw)
+static void rtl_op_reset_tsf(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u8 tmp = 0;
@@ -1063,6 +1071,9 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
*or clear all entry here.
*/
rtl_cam_delete_one_entry(hw, mac_addr, key_idx);
+
+ rtl_cam_reset_sec_info(hw);
+
break;
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
diff --git a/drivers/net/wireless/rtlwifi/debug.c b/drivers/net/wireless/rtlwifi/debug.c
index 5fa73852cb66..1b5cb7153a52 100644
--- a/drivers/net/wireless/rtlwifi/debug.c
+++ b/drivers/net/wireless/rtlwifi/debug.c
@@ -33,8 +33,6 @@ void rtl_dbgp_flag_init(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
u8 i;
- rtlpriv->dbg.global_debuglevel = DBG_EMERG;
-
rtlpriv->dbg.global_debugcomponents =
COMP_ERR | COMP_FW | COMP_INIT | COMP_RECV | COMP_SEND |
COMP_MLME | COMP_SCAN | COMP_INTR | COMP_LED | COMP_SEC |
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index 56f12358389d..177a8e669241 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -218,7 +218,6 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw)
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
- u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
u8 num4bytes = pcipriv->ndis_adapter.num4bytes;
/*Retrieve original configuration settings. */
u8 linkctrl_reg = pcipriv->ndis_adapter.linkctrl_reg;
@@ -254,9 +253,8 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw)
udelay(50);
/*4 Disable Pci Bridge ASPM */
- rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
- pcicfg_addrport + (num4bytes << 2));
- rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, pcibridge_linkctrlreg);
+ pci_write_config_byte(rtlpci->pdev, (num4bytes << 2),
+ pcibridge_linkctrlreg);
udelay(50);
}
@@ -277,7 +275,6 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
u8 pcibridge_devnum = pcipriv->ndis_adapter.pcibridge_devnum;
u8 pcibridge_funcnum = pcipriv->ndis_adapter.pcibridge_funcnum;
u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
- u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
u8 num4bytes = pcipriv->ndis_adapter.num4bytes;
u16 aspmlevel;
u8 u_pcibridge_aspmsetting;
@@ -293,8 +290,6 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
}
/*4 Enable Pci Bridge ASPM */
- rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
- pcicfg_addrport + (num4bytes << 2));
u_pcibridge_aspmsetting =
pcipriv->ndis_adapter.pcibridge_linkctrlreg |
@@ -303,7 +298,8 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL)
u_pcibridge_aspmsetting &= ~BIT(0);
- rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, u_pcibridge_aspmsetting);
+ pci_write_config_byte(rtlpci->pdev, (num4bytes << 2),
+ u_pcibridge_aspmsetting);
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
("PlatformEnableASPM():PciBridge busnumber[%x], "
@@ -335,25 +331,18 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw)
{
- struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
- u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
bool status = false;
u8 offset_e0;
unsigned offset_e4;
- rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
- pcicfg_addrport + 0xE0);
- rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, 0xA0);
+ pci_write_config_byte(rtlpci->pdev, 0xe0, 0xa0);
- rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
- pcicfg_addrport + 0xE0);
- rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &offset_e0);
+ pci_read_config_byte(rtlpci->pdev, 0xe0, &offset_e0);
if (offset_e0 == 0xA0) {
- rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
- pcicfg_addrport + 0xE4);
- rtl_pci_raw_read_port_ulong(PCI_CONF_DATA, &offset_e4);
+ pci_read_config_dword(rtlpci->pdev, 0xe4, &offset_e4);
if (offset_e4 & BIT(23))
status = true;
}
@@ -364,17 +353,15 @@ static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw)
static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw)
{
struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
u8 capabilityoffset = pcipriv->ndis_adapter.pcibridge_pciehdr_offset;
- u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
u8 linkctrl_reg;
u8 num4bbytes;
num4bbytes = (capabilityoffset + 0x10) / 4;
/*Read Link Control Register */
- rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
- pcicfg_addrport + (num4bbytes << 2));
- rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &linkctrl_reg);
+ pci_read_config_byte(rtlpci->pdev, (num4bbytes << 2), &linkctrl_reg);
pcipriv->ndis_adapter.pcibridge_linkctrlreg = linkctrl_reg;
}
@@ -488,7 +475,7 @@ static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw)
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct sk_buff *skb = NULL;
struct ieee80211_tx_info *info = NULL;
- int tid; /* should be int */
+ int tid;
if (!rtlpriv->rtlhal.earlymode_enable)
return;
@@ -1538,7 +1525,7 @@ static int rtl_pci_start(struct ieee80211_hw *hw)
rtl_init_rx_config(hw);
- /*should after adapter start and interrupt enable. */
+ /*should be after adapter start and interrupt enable. */
set_hal_start(rtlhal);
RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
@@ -1559,7 +1546,7 @@ static void rtl_pci_stop(struct ieee80211_hw *hw)
u8 RFInProgressTimeOut = 0;
/*
- *should before disable interrrupt&adapter
+ *should be before disable interrupt&adapter
*and will do it immediately.
*/
set_hal_stop(rtlhal);
@@ -1718,10 +1705,6 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
PCI_SLOT(bridge_pdev->devfn);
pcipriv->ndis_adapter.pcibridge_funcnum =
PCI_FUNC(bridge_pdev->devfn);
- pcipriv->ndis_adapter.pcicfg_addrport =
- (pcipriv->ndis_adapter.pcibridge_busnum << 16) |
- (pcipriv->ndis_adapter.pcibridge_devnum << 11) |
- (pcipriv->ndis_adapter.pcibridge_funcnum << 8) | (1 << 31);
pcipriv->ndis_adapter.pcibridge_pciehdr_offset =
pci_pcie_cap(bridge_pdev);
pcipriv->ndis_adapter.num4bytes =
@@ -2010,36 +1993,25 @@ call rtl_mac_stop() from the mac80211
suspend function first, So there is
no need to call hw_disable here.
****************************************/
-int rtl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+int rtl_pci_suspend(struct device *dev)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
struct rtl_priv *rtlpriv = rtl_priv(hw);
rtlpriv->cfg->ops->hw_suspend(hw);
rtl_deinit_rfkill(hw);
- pci_save_state(pdev);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
return 0;
}
EXPORT_SYMBOL(rtl_pci_suspend);
-int rtl_pci_resume(struct pci_dev *pdev)
+int rtl_pci_resume(struct device *dev)
{
- int ret;
+ struct pci_dev *pdev = to_pci_dev(dev);
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
struct rtl_priv *rtlpriv = rtl_priv(hw);
- pci_set_power_state(pdev, PCI_D0);
- ret = pci_enable_device(pdev);
- if (ret) {
- RT_ASSERT(false, ("ERR: <======\n"));
- return ret;
- }
-
- pci_restore_state(pdev);
-
rtlpriv->cfg->ops->hw_resume(hw);
rtl_init_rfkill(hw);
return 0;
diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h
index c53c62046747..ebe0b42c0518 100644
--- a/drivers/net/wireless/rtlwifi/pci.h
+++ b/drivers/net/wireless/rtlwifi/pci.h
@@ -212,7 +212,6 @@ struct mp_adapter {
u16 pcibridge_vendorid;
u16 pcibridge_deviceid;
- u32 pcicfg_addrport;
u8 num4bytes;
u8 pcibridge_pciehdr_offset;
@@ -238,8 +237,8 @@ extern struct rtl_intf_ops rtl_pci_ops;
int __devinit rtl_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id);
void rtl_pci_disconnect(struct pci_dev *pdev);
-int rtl_pci_suspend(struct pci_dev *pdev, pm_message_t state);
-int rtl_pci_resume(struct pci_dev *pdev);
+int rtl_pci_suspend(struct device *dev);
+int rtl_pci_resume(struct device *dev);
static inline u8 pci_read8_sync(struct rtl_priv *rtlpriv, u32 addr)
{
@@ -273,29 +272,4 @@ static inline void pci_write32_async(struct rtl_priv *rtlpriv,
writel(val, (u8 __iomem *) rtlpriv->io.pci_mem_start + addr);
}
-static inline void rtl_pci_raw_write_port_ulong(u32 port, u32 val)
-{
- outl(val, port);
-}
-
-static inline void rtl_pci_raw_write_port_uchar(u32 port, u8 val)
-{
- outb(val, port);
-}
-
-static inline void rtl_pci_raw_read_port_uchar(u32 port, u8 *pval)
-{
- *pval = inb(port);
-}
-
-static inline void rtl_pci_raw_read_port_ushort(u32 port, u16 *pval)
-{
- *pval = inw(port);
-}
-
-static inline void rtl_pci_raw_read_port_ulong(u32 port, u32 *pval)
-{
- *pval = inl(port);
-}
-
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
index 35ff7df41a1d..9fc804d89d65 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
@@ -142,8 +142,22 @@ enum version_8192c {
VERSION_UNKNOWN = 0x88,
};
+#define CUT_VERSION_MASK (BIT(6)|BIT(7))
+#define CHIP_VENDOR_UMC BIT(5)
+#define CHIP_VENDOR_UMC_B_CUT BIT(6) /* Chip version for ECO */
+#define IS_VENDOR_UMC_A_CUT(version) ((IS_CHIP_VENDOR_UMC(version)) ? \
+ ((GET_CVID_CUT_VERSION(version)) ? false : true) : false)
#define IS_CHIP_VER_B(version) ((version & CHIP_VER_B) ? true : false)
+#define IS_VENDOR_UMC_A_CUT(version) ((IS_CHIP_VENDOR_UMC(version)) ? \
+ ((GET_CVID_CUT_VERSION(version)) ? false : true) : false)
#define IS_92C_SERIAL(version) ((version & CHIP_92C_BITMASK) ? true : false)
+#define IS_CHIP_VENDOR_UMC(version) \
+ ((version & CHIP_VENDOR_UMC) ? true : false)
+#define GET_CVID_CUT_VERSION(version) ((version) & CUT_VERSION_MASK)
+#define IS_81xxC_VENDOR_UMC_B_CUT(version) \
+ ((IS_CHIP_VENDOR_UMC(version)) ? \
+ ((GET_CVID_CUT_VERSION(version) == CHIP_VENDOR_UMC_B_CUT) ? \
+ true : false) : false)
enum rtl819x_loopback_e {
RTL819X_NO_LOOPBACK = 0,
@@ -220,41 +234,6 @@ enum rtl_desc_qsel {
QSLT_CMD = 0x13,
};
-enum rtl_desc92c_rate {
- DESC92C_RATE1M = 0x00,
- DESC92C_RATE2M = 0x01,
- DESC92C_RATE5_5M = 0x02,
- DESC92C_RATE11M = 0x03,
-
- DESC92C_RATE6M = 0x04,
- DESC92C_RATE9M = 0x05,
- DESC92C_RATE12M = 0x06,
- DESC92C_RATE18M = 0x07,
- DESC92C_RATE24M = 0x08,
- DESC92C_RATE36M = 0x09,
- DESC92C_RATE48M = 0x0a,
- DESC92C_RATE54M = 0x0b,
-
- DESC92C_RATEMCS0 = 0x0c,
- DESC92C_RATEMCS1 = 0x0d,
- DESC92C_RATEMCS2 = 0x0e,
- DESC92C_RATEMCS3 = 0x0f,
- DESC92C_RATEMCS4 = 0x10,
- DESC92C_RATEMCS5 = 0x11,
- DESC92C_RATEMCS6 = 0x12,
- DESC92C_RATEMCS7 = 0x13,
- DESC92C_RATEMCS8 = 0x14,
- DESC92C_RATEMCS9 = 0x15,
- DESC92C_RATEMCS10 = 0x16,
- DESC92C_RATEMCS11 = 0x17,
- DESC92C_RATEMCS12 = 0x18,
- DESC92C_RATEMCS13 = 0x19,
- DESC92C_RATEMCS14 = 0x1a,
- DESC92C_RATEMCS15 = 0x1b,
- DESC92C_RATEMCS15_SG = 0x1c,
- DESC92C_RATEMCS32 = 0x20,
-};
-
struct phy_sts_cck_8192s_t {
u8 adc_pwdb_X[4];
u8 sq_rpt;
@@ -267,108 +246,4 @@ struct h2c_cmd_8192c {
u8 *p_cmdbuffer;
};
-/* NOTE: reference to rtl8192c_rates struct */
-static inline int _rtl92c_rate_mapping(struct ieee80211_hw *hw, bool isHT,
- u8 desc_rate, bool first_ampdu)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- int rate_idx = 0;
-
- if (first_ampdu) {
- if (false == isHT) {
- switch (desc_rate) {
- case DESC92C_RATE1M:
- rate_idx = 0;
- break;
- case DESC92C_RATE2M:
- rate_idx = 1;
- break;
- case DESC92C_RATE5_5M:
- rate_idx = 2;
- break;
- case DESC92C_RATE11M:
- rate_idx = 3;
- break;
- case DESC92C_RATE6M:
- rate_idx = 4;
- break;
- case DESC92C_RATE9M:
- rate_idx = 5;
- break;
- case DESC92C_RATE12M:
- rate_idx = 6;
- break;
- case DESC92C_RATE18M:
- rate_idx = 7;
- break;
- case DESC92C_RATE24M:
- rate_idx = 8;
- break;
- case DESC92C_RATE36M:
- rate_idx = 9;
- break;
- case DESC92C_RATE48M:
- rate_idx = 10;
- break;
- case DESC92C_RATE54M:
- rate_idx = 11;
- break;
- default:
- RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG,
- ("Rate %d is not support, set to "
- "1M rate.\n", desc_rate));
- rate_idx = 0;
- break;
- }
- } else {
- rate_idx = 11;
- }
- return rate_idx;
- }
- switch (desc_rate) {
- case DESC92C_RATE1M:
- rate_idx = 0;
- break;
- case DESC92C_RATE2M:
- rate_idx = 1;
- break;
- case DESC92C_RATE5_5M:
- rate_idx = 2;
- break;
- case DESC92C_RATE11M:
- rate_idx = 3;
- break;
- case DESC92C_RATE6M:
- rate_idx = 4;
- break;
- case DESC92C_RATE9M:
- rate_idx = 5;
- break;
- case DESC92C_RATE12M:
- rate_idx = 6;
- break;
- case DESC92C_RATE18M:
- rate_idx = 7;
- break;
- case DESC92C_RATE24M:
- rate_idx = 8;
- break;
- case DESC92C_RATE36M:
- rate_idx = 9;
- break;
- case DESC92C_RATE48M:
- rate_idx = 10;
- break;
- case DESC92C_RATE54M:
- rate_idx = 11;
- break;
- /* TODO: How to mapping MCS rate? */
- /* NOTE: referenc to __ieee80211_rx */
- default:
- rate_idx = 11;
- break;
- }
- return rate_idx;
-}
-
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
index 373dc78af1dc..a48404cc2b96 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
@@ -92,6 +92,8 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
const struct firmware *firmware;
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ char *fw_name = NULL;
rtl8192ce_bt_reg_init(hw);
@@ -129,10 +131,16 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw)
rtlpci->irq_mask[1] = (u32) (IMR_CPWM | IMR_C2HCMD | 0);
+ /* for debug level */
+ rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug;
/* for LPS & IPS */
rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+ if (!rtlpriv->psc.inactiveps)
+ pr_info("rtl8192ce: Power Save off (module option)\n");
+ if (!rtlpriv->psc.fwctrl_lps)
+ pr_info("rtl8192ce: FW Power Save off (module option)\n");
rtlpriv->psc.reg_fwctrl_lps = 3;
rtlpriv->psc.reg_max_lps_awakeintvl = 5;
/* for ASPM, you can close aspm through
@@ -155,8 +163,14 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw)
}
/* request fw */
- err = request_firmware(&firmware, rtlpriv->cfg->fw_name,
- rtlpriv->io.dev);
+ if (IS_VENDOR_UMC_A_CUT(rtlhal->version) &&
+ !IS_92C_SERIAL(rtlhal->version))
+ fw_name = "rtlwifi/rtl8192cfwU.bin";
+ else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version))
+ fw_name = "rtlwifi/rtl8192cfwU_B.bin";
+ else
+ fw_name = rtlpriv->cfg->fw_name;
+ err = request_firmware(&firmware, fw_name, rtlpriv->io.dev);
if (err) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
("Failed to request firmware!\n"));
@@ -241,6 +255,7 @@ static struct rtl_mod_params rtl92ce_mod_params = {
.inactiveps = true,
.swctrl_lps = false,
.fwctrl_lps = true,
+ .debug = DBG_EMERG,
};
static struct rtl_hal_cfg rtl92ce_hal_cfg = {
@@ -318,21 +333,21 @@ static struct rtl_hal_cfg rtl92ce_hal_cfg = {
.maps[RTL_IMR_ROK] = IMR_ROK,
.maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER),
- .maps[RTL_RC_CCK_RATE1M] = DESC92C_RATE1M,
- .maps[RTL_RC_CCK_RATE2M] = DESC92C_RATE2M,
- .maps[RTL_RC_CCK_RATE5_5M] = DESC92C_RATE5_5M,
- .maps[RTL_RC_CCK_RATE11M] = DESC92C_RATE11M,
- .maps[RTL_RC_OFDM_RATE6M] = DESC92C_RATE6M,
- .maps[RTL_RC_OFDM_RATE9M] = DESC92C_RATE9M,
- .maps[RTL_RC_OFDM_RATE12M] = DESC92C_RATE12M,
- .maps[RTL_RC_OFDM_RATE18M] = DESC92C_RATE18M,
- .maps[RTL_RC_OFDM_RATE24M] = DESC92C_RATE24M,
- .maps[RTL_RC_OFDM_RATE36M] = DESC92C_RATE36M,
- .maps[RTL_RC_OFDM_RATE48M] = DESC92C_RATE48M,
- .maps[RTL_RC_OFDM_RATE54M] = DESC92C_RATE54M,
-
- .maps[RTL_RC_HT_RATEMCS7] = DESC92C_RATEMCS7,
- .maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15,
+ .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M,
+ .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M,
+ .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M,
+ .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M,
+ .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M,
+ .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M,
+ .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M,
+ .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M,
+ .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M,
+ .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M,
+ .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M,
+ .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M,
+
+ .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7,
+ .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15,
};
DEFINE_PCI_DEVICE_TABLE(rtl92ce_pci_ids) = {
@@ -351,27 +366,35 @@ MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Realtek 8192C/8188C 802.11n PCI wireless");
MODULE_FIRMWARE("rtlwifi/rtl8192cfw.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8192cfwU.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8192cfwU_B.bin");
module_param_named(swenc, rtl92ce_mod_params.sw_crypto, bool, 0444);
+module_param_named(debug, rtl92ce_mod_params.debug, int, 0444);
module_param_named(ips, rtl92ce_mod_params.inactiveps, bool, 0444);
module_param_named(swlps, rtl92ce_mod_params.swctrl_lps, bool, 0444);
module_param_named(fwlps, rtl92ce_mod_params.fwctrl_lps, bool, 0444);
-MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n");
-MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n");
-MODULE_PARM_DESC(fwlps, "using linked fw control power save "
- "(default 1 is open)\n");
+MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n");
+MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n");
+MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n");
+MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n");
+MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)");
+
+static const struct dev_pm_ops rtlwifi_pm_ops = {
+ .suspend = rtl_pci_suspend,
+ .resume = rtl_pci_resume,
+ .freeze = rtl_pci_suspend,
+ .thaw = rtl_pci_resume,
+ .poweroff = rtl_pci_suspend,
+ .restore = rtl_pci_resume,
+};
static struct pci_driver rtl92ce_driver = {
.name = KBUILD_MODNAME,
.id_table = rtl92ce_pci_ids,
.probe = rtl_pci_probe,
.remove = rtl_pci_disconnect,
-
-#ifdef CONFIG_PM
- .suspend = rtl_pci_suspend,
- .resume = rtl_pci_resume,
-#endif
-
+ .driver.pm = &rtlwifi_pm_ops,
};
static int __init rtl92ce_module_init(void)
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
index 230bbe900d8d..4fb5ae24dee0 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
@@ -48,104 +48,6 @@ static u8 _rtl92ce_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
return skb->priority;
}
-static int _rtl92ce_rate_mapping(bool isht, u8 desc_rate, bool first_ampdu)
-{
- int rate_idx;
-
- if (first_ampdu) {
- if (false == isht) {
- switch (desc_rate) {
- case DESC92C_RATE1M:
- rate_idx = 0;
- break;
- case DESC92C_RATE2M:
- rate_idx = 1;
- break;
- case DESC92C_RATE5_5M:
- rate_idx = 2;
- break;
- case DESC92C_RATE11M:
- rate_idx = 3;
- break;
- case DESC92C_RATE6M:
- rate_idx = 4;
- break;
- case DESC92C_RATE9M:
- rate_idx = 5;
- break;
- case DESC92C_RATE12M:
- rate_idx = 6;
- break;
- case DESC92C_RATE18M:
- rate_idx = 7;
- break;
- case DESC92C_RATE24M:
- rate_idx = 8;
- break;
- case DESC92C_RATE36M:
- rate_idx = 9;
- break;
- case DESC92C_RATE48M:
- rate_idx = 10;
- break;
- case DESC92C_RATE54M:
- rate_idx = 11;
- break;
- default:
- rate_idx = 0;
- break;
- }
- } else {
- rate_idx = 11;
- }
-
- return rate_idx;
- }
-
- switch (desc_rate) {
- case DESC92C_RATE1M:
- rate_idx = 0;
- break;
- case DESC92C_RATE2M:
- rate_idx = 1;
- break;
- case DESC92C_RATE5_5M:
- rate_idx = 2;
- break;
- case DESC92C_RATE11M:
- rate_idx = 3;
- break;
- case DESC92C_RATE6M:
- rate_idx = 4;
- break;
- case DESC92C_RATE9M:
- rate_idx = 5;
- break;
- case DESC92C_RATE12M:
- rate_idx = 6;
- break;
- case DESC92C_RATE18M:
- rate_idx = 7;
- break;
- case DESC92C_RATE24M:
- rate_idx = 8;
- break;
- case DESC92C_RATE36M:
- rate_idx = 9;
- break;
- case DESC92C_RATE48M:
- rate_idx = 10;
- break;
- case DESC92C_RATE54M:
- rate_idx = 11;
- break;
- default:
- rate_idx = 11;
- break;
- }
- return rate_idx;
-}
-
static u8 _rtl92c_query_rxpwrpercentage(char antpower)
{
if ((antpower <= -100) || (antpower >= 20))
@@ -336,8 +238,8 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
pstats->rxpower = rx_pwr_all;
pstats->recvsignalpower = rx_pwr_all;
- if (pdesc->rxht && pdesc->rxmcs >= DESC92C_RATEMCS8 &&
- pdesc->rxmcs <= DESC92C_RATEMCS15)
+ if (pdesc->rxht && pdesc->rxmcs >= DESC92_RATEMCS8 &&
+ pdesc->rxmcs <= DESC92_RATEMCS15)
max_spatial_stream = 2;
else
max_spatial_stream = 1;
@@ -670,12 +572,10 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
if (stats->decrypted)
rx_status->flag |= RX_FLAG_DECRYPTED;
- rx_status->rate_idx = _rtl92ce_rate_mapping((bool)
- GET_RX_DESC_RXHT(pdesc),
- (u8)
- GET_RX_DESC_RXMCS(pdesc),
- (bool)
- GET_RX_DESC_PAGGR(pdesc));
+ rx_status->rate_idx = rtlwifi_rate_mapping(hw,
+ (bool)GET_RX_DESC_RXHT(pdesc),
+ (u8)GET_RX_DESC_RXMCS(pdesc),
+ (bool)GET_RX_DESC_PAGGR(pdesc));
rx_status->mactime = GET_RX_DESC_TSFL(pdesc);
if (phystatus) {
@@ -768,7 +668,7 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
SET_TX_DESC_RTS_BW(pdesc, 0);
SET_TX_DESC_RTS_SC(pdesc, tcb_desc->rts_sc);
SET_TX_DESC_RTS_SHORT(pdesc,
- ((tcb_desc->rts_rate <= DESC92C_RATE54M) ?
+ ((tcb_desc->rts_rate <= DESC92_RATE54M) ?
(tcb_desc->rts_use_shortpreamble ? 1 : 0)
: (tcb_desc->rts_use_shortgi ? 1 : 0)));
@@ -886,7 +786,7 @@ void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw,
if (firstseg)
SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
- SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M);
+ SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE1M);
SET_TX_DESC_SEQ(pdesc, 0);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
index 0f1177137501..c8977a50ca36 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
@@ -537,12 +537,6 @@ do { \
memset(__pdesc, 0, _size); \
} while (0);
-#define RX_HAL_IS_CCK_RATE(_pdesc)\
- (_pdesc->rxmcs == DESC92C_RATE1M || \
- _pdesc->rxmcs == DESC92C_RATE2M || \
- _pdesc->rxmcs == DESC92C_RATE5_5M || \
- _pdesc->rxmcs == DESC92C_RATE11M)
-
struct rx_fwinfo_92c {
u8 gain_trsw[4];
u8 pwdb_all;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/def.h b/drivers/net/wireless/rtlwifi/rtl8192cu/def.h
index c54940ea72fe..d097efb1e717 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/def.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/def.h
@@ -50,10 +50,6 @@
#define IS_VENDOR_UMC(version) \
(((version) & CHIP_VENDOR_UMC) ? true : false)
-#define IS_VENDOR_UMC_A_CUT(version) \
- (((version) & CHIP_VENDOR_UMC) ? (((version) & (BIT(6) | BIT(7))) ? \
- false : true) : false)
-
#define IS_VENDOR_8723_A_CUT(version) \
(((version) & CHIP_VENDOR_UMC) ? (((version) & (BIT(6))) ? \
false : true) : false)
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
index 194fc693c1fa..060a06f4a885 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
@@ -892,8 +892,8 @@ static void _rtl92c_query_rxphystatus(struct ieee80211_hw *hw,
pstats->rxpower = rx_pwr_all;
pstats->recvsignalpower = rx_pwr_all;
if (GET_RX_DESC_RX_MCS(pdesc) &&
- GET_RX_DESC_RX_MCS(pdesc) >= DESC92C_RATEMCS8 &&
- GET_RX_DESC_RX_MCS(pdesc) <= DESC92C_RATEMCS15)
+ GET_RX_DESC_RX_MCS(pdesc) >= DESC92_RATEMCS8 &&
+ GET_RX_DESC_RX_MCS(pdesc) <= DESC92_RATEMCS15)
max_spatial_stream = 2;
else
max_spatial_stream = 1;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h
index 298fdb724aa5..626d88e88e26 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h
@@ -87,12 +87,6 @@ void rtl92c_set_data_filter(struct ieee80211_hw *hw, u16 filter);
u32 rtl92c_get_txdma_status(struct ieee80211_hw *hw);
-#define RX_HAL_IS_CCK_RATE(_pdesc)\
- (GET_RX_DESC_RX_MCS(_pdesc) == DESC92C_RATE1M ||\
- GET_RX_DESC_RX_MCS(_pdesc) == DESC92C_RATE2M ||\
- GET_RX_DESC_RX_MCS(_pdesc) == DESC92C_RATE5_5M ||\
- GET_RX_DESC_RX_MCS(_pdesc) == DESC92C_RATE11M)
-
struct rx_fwinfo_92c {
u8 gain_trsw[4];
u8 pwdb_all;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
index 17a8e9628512..1e851aae58db 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
@@ -104,7 +104,7 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
tx_agc[RF90_PATH_A] = 0x10101010;
tx_agc[RF90_PATH_B] = 0x10101010;
} else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
- TXHIGHPWRLEVEL_LEVEL2) {
+ TXHIGHPWRLEVEL_LEVEL1) {
tx_agc[RF90_PATH_A] = 0x00000000;
tx_agc[RF90_PATH_B] = 0x00000000;
} else{
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
index ef63c0df006a..feed1ed8d9b6 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
@@ -60,6 +60,7 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw)
rtlpriv->dm.dm_flag = 0;
rtlpriv->dm.disable_framebursting = 0;
rtlpriv->dm.thermalvalue = 0;
+ rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug;
rtlpriv->rtlhal.pfirmware = vmalloc(0x4000);
if (!rtlpriv->rtlhal.pfirmware) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
@@ -149,8 +150,14 @@ static struct rtl_hal_ops rtl8192cu_hal_ops = {
static struct rtl_mod_params rtl92cu_mod_params = {
.sw_crypto = 0,
+ .debug = DBG_EMERG,
};
+module_param_named(swenc, rtl92cu_mod_params.sw_crypto, bool, 0444);
+module_param_named(debug, rtl92cu_mod_params.debug, int, 0444);
+MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n");
+MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)");
+
static struct rtl_hal_usbint_cfg rtl92cu_interface_cfg = {
/* rx */
.in_ep_num = RTL92C_USB_BULK_IN_NUM,
@@ -241,20 +248,20 @@ static struct rtl_hal_cfg rtl92cu_hal_cfg = {
.maps[RTL_IMR_ROK] = IMR_ROK,
.maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER),
- .maps[RTL_RC_CCK_RATE1M] = DESC92C_RATE1M,
- .maps[RTL_RC_CCK_RATE2M] = DESC92C_RATE2M,
- .maps[RTL_RC_CCK_RATE5_5M] = DESC92C_RATE5_5M,
- .maps[RTL_RC_CCK_RATE11M] = DESC92C_RATE11M,
- .maps[RTL_RC_OFDM_RATE6M] = DESC92C_RATE6M,
- .maps[RTL_RC_OFDM_RATE9M] = DESC92C_RATE9M,
- .maps[RTL_RC_OFDM_RATE12M] = DESC92C_RATE12M,
- .maps[RTL_RC_OFDM_RATE18M] = DESC92C_RATE18M,
- .maps[RTL_RC_OFDM_RATE24M] = DESC92C_RATE24M,
- .maps[RTL_RC_OFDM_RATE36M] = DESC92C_RATE36M,
- .maps[RTL_RC_OFDM_RATE48M] = DESC92C_RATE48M,
- .maps[RTL_RC_OFDM_RATE54M] = DESC92C_RATE54M,
- .maps[RTL_RC_HT_RATEMCS7] = DESC92C_RATEMCS7,
- .maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15,
+ .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M,
+ .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M,
+ .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M,
+ .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M,
+ .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M,
+ .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M,
+ .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M,
+ .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M,
+ .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M,
+ .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M,
+ .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M,
+ .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M,
+ .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7,
+ .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15,
};
#define USB_VENDER_ID_REALTEK 0x0bda
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
index 906e7aa55bc3..bc33b147f44f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
@@ -337,10 +337,10 @@ bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw,
rx_status->flag |= RX_FLAG_MACTIME_MPDU;
if (stats->decrypted)
rx_status->flag |= RX_FLAG_DECRYPTED;
- rx_status->rate_idx = _rtl92c_rate_mapping(hw,
- (bool)GET_RX_DESC_RX_HT(pdesc),
- (u8)GET_RX_DESC_RX_MCS(pdesc),
- (bool)GET_RX_DESC_PAGGR(pdesc));
+ rx_status->rate_idx = rtlwifi_rate_mapping(hw,
+ (bool)GET_RX_DESC_RX_HT(pdesc),
+ (u8)GET_RX_DESC_RX_MCS(pdesc),
+ (bool)GET_RX_DESC_PAGGR(pdesc));
rx_status->mactime = GET_RX_DESC_TSFL(pdesc);
if (phystatus) {
p_drvinfo = (struct rx_fwinfo_92c *)(pdesc + RTL_RX_DESC_SIZE);
@@ -406,11 +406,10 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb)
if (GET_RX_DESC_RX_HT(rxdesc))
rx_status->flag |= RX_FLAG_HT;
/* Data rate */
- rx_status->rate_idx = _rtl92c_rate_mapping(hw,
- (bool)GET_RX_DESC_RX_HT(rxdesc),
- (u8)GET_RX_DESC_RX_MCS(rxdesc),
- (bool)GET_RX_DESC_PAGGR(rxdesc)
- );
+ rx_status->rate_idx = rtlwifi_rate_mapping(hw,
+ (bool)GET_RX_DESC_RX_HT(rxdesc),
+ (u8)GET_RX_DESC_RX_MCS(rxdesc),
+ (bool)GET_RX_DESC_PAGGR(rxdesc));
/* There is a phy status after this rx descriptor. */
if (GET_RX_DESC_PHY_STATUS(rxdesc)) {
p_drvinfo = (struct rx_fwinfo_92c *)(rxdesc + RTL_RX_DESC_SIZE);
@@ -545,19 +544,20 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw,
SET_TX_DESC_RTS_BW(txdesc, 0);
SET_TX_DESC_RTS_SC(txdesc, tcb_desc->rts_sc);
SET_TX_DESC_RTS_SHORT(txdesc,
- ((tcb_desc->rts_rate <= DESC92C_RATE54M) ?
+ ((tcb_desc->rts_rate <= DESC92_RATE54M) ?
(tcb_desc->rts_use_shortpreamble ? 1 : 0)
: (tcb_desc->rts_use_shortgi ? 1 : 0)));
if (mac->bw_40) {
- if (tcb_desc->packet_bw) {
+ if (rate_flag & IEEE80211_TX_RC_DUP_DATA) {
SET_TX_DESC_DATA_BW(txdesc, 1);
SET_TX_DESC_DATA_SC(txdesc, 3);
+ } else if(rate_flag & IEEE80211_TX_RC_40_MHZ_WIDTH){
+ SET_TX_DESC_DATA_BW(txdesc, 1);
+ SET_TX_DESC_DATA_SC(txdesc, mac->cur_40_prime_sc);
} else {
SET_TX_DESC_DATA_BW(txdesc, 0);
- if (rate_flag & IEEE80211_TX_RC_DUP_DATA)
- SET_TX_DESC_DATA_SC(txdesc,
- mac->cur_40_prime_sc);
- }
+ SET_TX_DESC_DATA_SC(txdesc, 0);
+ }
} else {
SET_TX_DESC_DATA_BW(txdesc, 0);
SET_TX_DESC_DATA_SC(txdesc, 0);
@@ -643,7 +643,7 @@ void rtl92cu_fill_fake_txdesc(struct ieee80211_hw *hw, u8 * pDesc,
}
SET_TX_DESC_USE_RATE(pDesc, 1); /* use data rate which is set by Sw */
SET_TX_DESC_OWN(pDesc, 1);
- SET_TX_DESC_TX_RATE(pDesc, DESC92C_RATE1M);
+ SET_TX_DESC_TX_RATE(pDesc, DESC92_RATE1M);
_rtl_tx_desc_checksum(pDesc);
}
@@ -659,7 +659,7 @@ void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw,
memset((void *)pdesc, 0, RTL_TX_HEADER_SIZE);
if (firstseg)
SET_TX_DESC_OFFSET(pdesc, RTL_TX_HEADER_SIZE);
- SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M);
+ SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE1M);
SET_TX_DESC_SEQ(pdesc, 0);
SET_TX_DESC_LINIP(pdesc, 0);
SET_TX_DESC_QUEUE_SEL(pdesc, fw_queue);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/def.h b/drivers/net/wireless/rtlwifi/rtl8192de/def.h
index f0f5f9bfbb7b..946304771748 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/def.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/def.h
@@ -122,60 +122,99 @@
#define GET_C2H_CMD_FEEDBACK_CCX_SEQ(__pcmdfbhdr) \
LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 20, 12)
-/*
- * 92D chip ver:
- * BIT8: IS 92D
- * BIT9: single phy
- * BIT10: C-cut
- * BIT11: D-cut
- */
-
-/* Chip specific */
-#define CHIP_92C BIT(0)
-#define CHIP_92C_1T2R BIT(1)
-#define CHIP_8723 BIT(2) /* RTL8723 With BT feature */
-#define CHIP_8723_DRV_REV BIT(3) /* RTL8723 Driver Revised */
-#define NORMAL_CHIP BIT(4)
-#define CHIP_VENDOR_UMC BIT(5)
-#define CHIP_VENDOR_UMC_B_CUT BIT(6) /* Chip version for ECO */
+enum version_8192d {
+ VERSION_TEST_CHIP_88C = 0x0000,
+ VERSION_TEST_CHIP_92C = 0x0020,
+ VERSION_TEST_UMC_CHIP_8723 = 0x0081,
+ VERSION_NORMAL_TSMC_CHIP_88C = 0x0008,
+ VERSION_NORMAL_TSMC_CHIP_92C = 0x0028,
+ VERSION_NORMAL_TSMC_CHIP_92C_1T2R = 0x0018,
+ VERSION_NORMAL_UMC_CHIP_88C_A_CUT = 0x0088,
+ VERSION_NORMAL_UMC_CHIP_92C_A_CUT = 0x00a8,
+ VERSION_NORMAL_UMC_CHIP_92C_1T2R_A_CUT = 0x0098,
+ VERSION_NORMAL_UMC_CHIP_8723_1T1R_A_CUT = 0x0089,
+ VERSION_NORMAL_UMC_CHIP_8723_1T1R_B_CUT = 0x1089,
+ VERSION_NORMAL_UMC_CHIP_88C_B_CUT = 0x1088,
+ VERSION_NORMAL_UMC_CHIP_92C_B_CUT = 0x10a8,
+ VERSION_NORMAL_UMC_CHIP_92C_1T2R_B_CUT = 0x1090,
+ VERSION_TEST_CHIP_92D_SINGLEPHY = 0x0022,
+ VERSION_TEST_CHIP_92D_DUALPHY = 0x0002,
+ VERSION_NORMAL_CHIP_92D_SINGLEPHY = 0x002a,
+ VERSION_NORMAL_CHIP_92D_DUALPHY = 0x000a,
+ VERSION_NORMAL_CHIP_92D_C_CUT_SINGLEPHY = 0x202a,
+ VERSION_NORMAL_CHIP_92D_C_CUT_DUALPHY = 0x200a,
+ VERSION_NORMAL_CHIP_92D_D_CUT_SINGLEPHY = 0x302a,
+ VERSION_NORMAL_CHIP_92D_D_CUT_DUALPHY = 0x300a,
+ VERSION_NORMAL_CHIP_92D_E_CUT_SINGLEPHY = 0x402a,
+ VERSION_NORMAL_CHIP_92D_E_CUT_DUALPHY = 0x400a,
+};
/* for 92D */
-#define CHIP_92D BIT(8)
#define CHIP_92D_SINGLEPHY BIT(9)
+#define C_CUT_VERSION BIT(13)
+#define D_CUT_VERSION ((BIT(12)|BIT(13)))
+#define E_CUT_VERSION BIT(14)
+
+/* Chip specific */
+#define CHIP_BONDING_IDENTIFIER(_value) (((_value)>>22)&0x3)
+#define CHIP_BONDING_92C_1T2R 0x1
+#define CHIP_BONDING_88C_USB_MCARD 0x2
+#define CHIP_BONDING_88C_USB_HP 0x1
+
+/* [15:12] IC version(CUT): A-cut=0, B-cut=1, C-cut=2, D-cut=3 */
+/* [7] Manufacturer: TSMC=0, UMC=1 */
+/* [6:4] RF type: 1T1R=0, 1T2R=1, 2T2R=2 */
+/* [3] Chip type: TEST=0, NORMAL=1 */
+/* [2:0] IC type: 81xxC=0, 8723=1, 92D=2 */
+#define CHIP_8723 BIT(0)
+#define CHIP_92D BIT(1)
+#define NORMAL_CHIP BIT(3)
+#define RF_TYPE_1T1R (~(BIT(4)|BIT(5)|BIT(6)))
+#define RF_TYPE_1T2R BIT(4)
+#define RF_TYPE_2T2R BIT(5)
+#define CHIP_VENDOR_UMC BIT(7)
+#define B_CUT_VERSION BIT(12)
+
+/* MASK */
+#define IC_TYPE_MASK (BIT(0)|BIT(1)|BIT(2))
+#define CHIP_TYPE_MASK BIT(3)
+#define RF_TYPE_MASK (BIT(4)|BIT(5)|BIT(6))
+#define MANUFACTUER_MASK BIT(7)
+#define ROM_VERSION_MASK (BIT(11)|BIT(10)|BIT(9)|BIT(8))
+#define CUT_VERSION_MASK (BIT(15)|BIT(14)|BIT(13)|BIT(12))
+
+
+/* Get element */
+#define GET_CVID_IC_TYPE(version) ((version) & IC_TYPE_MASK)
+#define GET_CVID_CHIP_TYPE(version) ((version) & CHIP_TYPE_MASK)
+#define GET_CVID_RF_TYPE(version) ((version) & RF_TYPE_MASK)
+#define GET_CVID_MANUFACTUER(version) ((version) & MANUFACTUER_MASK)
+#define GET_CVID_ROM_VERSION(version) ((version) & ROM_VERSION_MASK)
+#define GET_CVID_CUT_VERSION(version) ((version) & CUT_VERSION_MASK)
+
+#define IS_1T1R(version) ((GET_CVID_RF_TYPE(version)) ? \
+ false : true)
+#define IS_1T2R(version) ((GET_CVID_RF_TYPE(version) == \
+ RF_TYPE_1T2R) ? true : false)
+#define IS_2T2R(version) ((GET_CVID_RF_TYPE(version) == \
+ RF_TYPE_2T2R) ? true : false)
+
+#define IS_92D_SINGLEPHY(version) ((IS_92D(version)) ? \
+ (IS_2T2R(version) ? true : false) : false)
+#define IS_92D(version) ((GET_CVID_IC_TYPE(version) == \
+ CHIP_92D) ? true : false)
+#define IS_92D_C_CUT(version) ((IS_92D(version)) ? \
+ ((GET_CVID_CUT_VERSION(version) == \
+ 0x2000) ? true : false) : false)
+#define IS_92D_D_CUT(version) ((IS_92D(version)) ? \
+ ((GET_CVID_CUT_VERSION(version) == \
+ 0x3000) ? true : false) : false)
+#define IS_92D_E_CUT(version) ((IS_92D(version)) ? \
+ ((GET_CVID_CUT_VERSION(version) == \
+ 0x4000) ? true : false) : false)
#define CHIP_92D_C_CUT BIT(10)
#define CHIP_92D_D_CUT BIT(11)
-enum version_8192d {
- VERSION_TEST_CHIP_88C = 0x00,
- VERSION_TEST_CHIP_92C = 0x01,
- VERSION_NORMAL_TSMC_CHIP_88C = 0x10,
- VERSION_NORMAL_TSMC_CHIP_92C = 0x11,
- VERSION_NORMAL_TSMC_CHIP_92C_1T2R = 0x13,
- VERSION_NORMAL_UMC_CHIP_88C_A_CUT = 0x30,
- VERSION_NORMAL_UMC_CHIP_92C_A_CUT = 0x31,
- VERSION_NORMAL_UMC_CHIP_92C_1T2R_A_CUT = 0x33,
- VERSION_NORMA_UMC_CHIP_8723_1T1R_A_CUT = 0x34,
- VERSION_NORMA_UMC_CHIP_8723_1T1R_B_CUT = 0x3c,
- VERSION_NORMAL_UMC_CHIP_88C_B_CUT = 0x70,
- VERSION_NORMAL_UMC_CHIP_92C_B_CUT = 0x71,
- VERSION_NORMAL_UMC_CHIP_92C_1T2R_B_CUT = 0x73,
- VERSION_TEST_CHIP_92D_SINGLEPHY = 0x300,
- VERSION_TEST_CHIP_92D_DUALPHY = 0x100,
- VERSION_NORMAL_CHIP_92D_SINGLEPHY = 0x310,
- VERSION_NORMAL_CHIP_92D_DUALPHY = 0x110,
- VERSION_NORMAL_CHIP_92D_C_CUT_SINGLEPHY = 0x710,
- VERSION_NORMAL_CHIP_92D_C_CUT_DUALPHY = 0x510,
- VERSION_NORMAL_CHIP_92D_D_CUT_SINGLEPHY = 0xB10,
- VERSION_NORMAL_CHIP_92D_D_CUT_DUALPHY = 0x910,
-};
-
-#define IS_92D_SINGLEPHY(version) \
- ((version & CHIP_92D_SINGLEPHY) ? true : false)
-#define IS_92D_C_CUT(version) \
- ((version & CHIP_92D_C_CUT) ? true : false)
-#define IS_92D_D_CUT(version) \
- ((version & CHIP_92D_D_CUT) ? true : false)
-
enum rf_optype {
RF_OP_BY_SW_3WIRE = 0,
RF_OP_BY_FW,
@@ -193,41 +232,6 @@ enum rtl_desc_qsel {
QSLT_CMD = 0x13,
};
-enum rtl_desc92d_rate {
- DESC92D_RATE1M = 0x00,
- DESC92D_RATE2M = 0x01,
- DESC92D_RATE5_5M = 0x02,
- DESC92D_RATE11M = 0x03,
-
- DESC92D_RATE6M = 0x04,
- DESC92D_RATE9M = 0x05,
- DESC92D_RATE12M = 0x06,
- DESC92D_RATE18M = 0x07,
- DESC92D_RATE24M = 0x08,
- DESC92D_RATE36M = 0x09,
- DESC92D_RATE48M = 0x0a,
- DESC92D_RATE54M = 0x0b,
-
- DESC92D_RATEMCS0 = 0x0c,
- DESC92D_RATEMCS1 = 0x0d,
- DESC92D_RATEMCS2 = 0x0e,
- DESC92D_RATEMCS3 = 0x0f,
- DESC92D_RATEMCS4 = 0x10,
- DESC92D_RATEMCS5 = 0x11,
- DESC92D_RATEMCS6 = 0x12,
- DESC92D_RATEMCS7 = 0x13,
- DESC92D_RATEMCS8 = 0x14,
- DESC92D_RATEMCS9 = 0x15,
- DESC92D_RATEMCS10 = 0x16,
- DESC92D_RATEMCS11 = 0x17,
- DESC92D_RATEMCS12 = 0x18,
- DESC92D_RATEMCS13 = 0x19,
- DESC92D_RATEMCS14 = 0x1a,
- DESC92D_RATEMCS15 = 0x1b,
- DESC92D_RATEMCS15_SG = 0x1c,
- DESC92D_RATEMCS32 = 0x20,
-};
-
enum channel_plan {
CHPL_FCC = 0,
CHPL_IC = 1,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
index 0073cf106af2..f5bd3a3cd34a 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
@@ -1608,17 +1608,16 @@ static void _rtl92de_read_txpower_info(struct ieee80211_hw *hw,
tempval[0] = hwinfo[EEPROM_IQK_DELTA] & 0x03;
tempval[1] = (hwinfo[EEPROM_LCK_DELTA] & 0x0C) >> 2;
rtlefuse->txpwr_fromeprom = true;
- if (IS_92D_D_CUT(rtlpriv->rtlhal.version)) {
+ if (IS_92D_D_CUT(rtlpriv->rtlhal.version) ||
+ IS_92D_E_CUT(rtlpriv->rtlhal.version)) {
rtlefuse->internal_pa_5g[0] =
- !((hwinfo[EEPROM_TSSI_A_5G] &
- BIT(6)) >> 6);
+ !((hwinfo[EEPROM_TSSI_A_5G] & BIT(6)) >> 6);
rtlefuse->internal_pa_5g[1] =
- !((hwinfo[EEPROM_TSSI_B_5G] &
- BIT(6)) >> 6);
- RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ !((hwinfo[EEPROM_TSSI_B_5G] & BIT(6)) >> 6);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
("Is D cut,Internal PA0 %d Internal PA1 %d\n",
- rtlefuse->internal_pa_5g[0],
- rtlefuse->internal_pa_5g[1]))
+ rtlefuse->internal_pa_5g[0],
+ rtlefuse->internal_pa_5g[1]))
}
rtlefuse->eeprom_c9 = hwinfo[EEPROM_RF_OPT6];
rtlefuse->eeprom_cc = hwinfo[EEPROM_RF_OPT7];
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c
index 351765df517d..691f80092185 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c
@@ -146,10 +146,16 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw)
rtlpci->irq_mask[1] = (u32) (IMR_CPWM | IMR_C2HCMD);
+ /* for debug level */
+ rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug;
/* for LPS & IPS */
rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+ if (!rtlpriv->psc.inactiveps)
+ pr_info("rtl8192ce: Power Save off (module option)\n");
+ if (!rtlpriv->psc.fwctrl_lps)
+ pr_info("rtl8192ce: FW Power Save off (module option)\n");
rtlpriv->psc.reg_fwctrl_lps = 3;
rtlpriv->psc.reg_max_lps_awakeintvl = 5;
/* for ASPM, you can close aspm through
@@ -263,6 +269,7 @@ static struct rtl_mod_params rtl92de_mod_params = {
.inactiveps = true,
.swctrl_lps = true,
.fwctrl_lps = false,
+ .debug = DBG_EMERG,
};
static struct rtl_hal_cfg rtl92de_hal_cfg = {
@@ -340,21 +347,21 @@ static struct rtl_hal_cfg rtl92de_hal_cfg = {
.maps[RTL_IMR_ROK] = IMR_ROK,
.maps[RTL_IBSS_INT_MASKS] = (IMR_BcnInt | IMR_TBDOK | IMR_TBDER),
- .maps[RTL_RC_CCK_RATE1M] = DESC92D_RATE1M,
- .maps[RTL_RC_CCK_RATE2M] = DESC92D_RATE2M,
- .maps[RTL_RC_CCK_RATE5_5M] = DESC92D_RATE5_5M,
- .maps[RTL_RC_CCK_RATE11M] = DESC92D_RATE11M,
- .maps[RTL_RC_OFDM_RATE6M] = DESC92D_RATE6M,
- .maps[RTL_RC_OFDM_RATE9M] = DESC92D_RATE9M,
- .maps[RTL_RC_OFDM_RATE12M] = DESC92D_RATE12M,
- .maps[RTL_RC_OFDM_RATE18M] = DESC92D_RATE18M,
- .maps[RTL_RC_OFDM_RATE24M] = DESC92D_RATE24M,
- .maps[RTL_RC_OFDM_RATE36M] = DESC92D_RATE36M,
- .maps[RTL_RC_OFDM_RATE48M] = DESC92D_RATE48M,
- .maps[RTL_RC_OFDM_RATE54M] = DESC92D_RATE54M,
-
- .maps[RTL_RC_HT_RATEMCS7] = DESC92D_RATEMCS7,
- .maps[RTL_RC_HT_RATEMCS15] = DESC92D_RATEMCS15,
+ .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M,
+ .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M,
+ .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M,
+ .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M,
+ .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M,
+ .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M,
+ .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M,
+ .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M,
+ .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M,
+ .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M,
+ .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M,
+ .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M,
+
+ .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7,
+ .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15,
};
static struct pci_device_id rtl92de_pci_ids[] __devinitdata = {
@@ -373,25 +380,31 @@ MODULE_DESCRIPTION("Realtek 8192DE 802.11n Dual Mac PCI wireless");
MODULE_FIRMWARE("rtlwifi/rtl8192defw.bin");
module_param_named(swenc, rtl92de_mod_params.sw_crypto, bool, 0444);
+module_param_named(debug, rtl92de_mod_params.debug, int, 0444);
module_param_named(ips, rtl92de_mod_params.inactiveps, bool, 0444);
module_param_named(swlps, rtl92de_mod_params.swctrl_lps, bool, 0444);
module_param_named(fwlps, rtl92de_mod_params.fwctrl_lps, bool, 0444);
-MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n");
-MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n");
-MODULE_PARM_DESC(swlps, "using linked sw control power save (default 1"
- " is open)\n");
+MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n");
+MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n");
+MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n");
+MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n");
+MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)");
+
+static const struct dev_pm_ops rtlwifi_pm_ops = {
+ .suspend = rtl_pci_suspend,
+ .resume = rtl_pci_resume,
+ .freeze = rtl_pci_suspend,
+ .thaw = rtl_pci_resume,
+ .poweroff = rtl_pci_suspend,
+ .restore = rtl_pci_resume,
+};
static struct pci_driver rtl92de_driver = {
.name = KBUILD_MODNAME,
.id_table = rtl92de_pci_ids,
.probe = rtl_pci_probe,
.remove = rtl_pci_disconnect,
-
-#ifdef CONFIG_PM
- .suspend = rtl_pci_suspend,
- .resume = rtl_pci_resume,
-#endif
-
+ .driver.pm = &rtlwifi_pm_ops,
};
/* add global spin lock to solve the problem that
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
index dc86fcb0b3a3..3637c0c33525 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
@@ -48,99 +48,6 @@ static u8 _rtl92de_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
return skb->priority;
}
-static int _rtl92de_rate_mapping(bool isht, u8 desc_rate)
-{
- int rate_idx;
-
- if (false == isht) {
- switch (desc_rate) {
- case DESC92D_RATE1M:
- rate_idx = 0;
- break;
- case DESC92D_RATE2M:
- rate_idx = 1;
- break;
- case DESC92D_RATE5_5M:
- rate_idx = 2;
- break;
- case DESC92D_RATE11M:
- rate_idx = 3;
- break;
- case DESC92D_RATE6M:
- rate_idx = 4;
- break;
- case DESC92D_RATE9M:
- rate_idx = 5;
- break;
- case DESC92D_RATE12M:
- rate_idx = 6;
- break;
- case DESC92D_RATE18M:
- rate_idx = 7;
- break;
- case DESC92D_RATE24M:
- rate_idx = 8;
- break;
- case DESC92D_RATE36M:
- rate_idx = 9;
- break;
- case DESC92D_RATE48M:
- rate_idx = 10;
- break;
- case DESC92D_RATE54M:
- rate_idx = 11;
- break;
- default:
- rate_idx = 0;
- break;
- }
- return rate_idx;
- } else {
- switch (desc_rate) {
- case DESC92D_RATE1M:
- rate_idx = 0;
- break;
- case DESC92D_RATE2M:
- rate_idx = 1;
- break;
- case DESC92D_RATE5_5M:
- rate_idx = 2;
- break;
- case DESC92D_RATE11M:
- rate_idx = 3;
- break;
- case DESC92D_RATE6M:
- rate_idx = 4;
- break;
- case DESC92D_RATE9M:
- rate_idx = 5;
- break;
- case DESC92D_RATE12M:
- rate_idx = 6;
- break;
- case DESC92D_RATE18M:
- rate_idx = 7;
- break;
- case DESC92D_RATE24M:
- rate_idx = 8;
- break;
- case DESC92D_RATE36M:
- rate_idx = 9;
- break;
- case DESC92D_RATE48M:
- rate_idx = 10;
- break;
- case DESC92D_RATE54M:
- rate_idx = 11;
- break;
- default:
- rate_idx = 11;
- break;
- }
- return rate_idx;
- }
-}
-
static u8 _rtl92d_query_rxpwrpercentage(char antpower)
{
if ((antpower <= -100) || (antpower >= 20))
@@ -328,8 +235,8 @@ static void _rtl92de_query_rxphystatus(struct ieee80211_hw *hw,
pstats->rx_pwdb_all = pwdb_all;
pstats->rxpower = rx_pwr_all;
pstats->recvsignalpower = rx_pwr_all;
- if (pdesc->rxht && pdesc->rxmcs >= DESC92D_RATEMCS8 &&
- pdesc->rxmcs <= DESC92D_RATEMCS15)
+ if (pdesc->rxht && pdesc->rxmcs >= DESC92_RATEMCS8 &&
+ pdesc->rxmcs <= DESC92_RATEMCS15)
max_spatial_stream = 2;
else
max_spatial_stream = 1;
@@ -609,10 +516,10 @@ bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
rx_status->flag |= RX_FLAG_MACTIME_MPDU;
if (stats->decrypted)
rx_status->flag |= RX_FLAG_DECRYPTED;
- rx_status->rate_idx = _rtl92de_rate_mapping((bool)
- GET_RX_DESC_RXHT(pdesc),
- (u8)
- GET_RX_DESC_RXMCS(pdesc));
+ rx_status->rate_idx = rtlwifi_rate_mapping(hw,
+ (bool)GET_RX_DESC_RXHT(pdesc),
+ (u8)GET_RX_DESC_RXMCS(pdesc),
+ (bool)GET_RX_DESC_PAGGR(pdesc));
rx_status->mactime = GET_RX_DESC_TSFL(pdesc);
if (phystatus) {
p_drvinfo = (struct rx_fwinfo_92d *)(skb->data +
@@ -705,14 +612,14 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw,
}
/* 5G have no CCK rate */
if (rtlhal->current_bandtype == BAND_ON_5G)
- if (ptcb_desc->hw_rate < DESC92D_RATE6M)
- ptcb_desc->hw_rate = DESC92D_RATE6M;
+ if (ptcb_desc->hw_rate < DESC92_RATE6M)
+ ptcb_desc->hw_rate = DESC92_RATE6M;
SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate);
if (ptcb_desc->use_shortgi || ptcb_desc->use_shortpreamble)
SET_TX_DESC_DATA_SHORTGI(pdesc, 1);
if (rtlhal->macphymode == DUALMAC_DUALPHY &&
- ptcb_desc->hw_rate == DESC92D_RATEMCS7)
+ ptcb_desc->hw_rate == DESC92_RATEMCS7)
SET_TX_DESC_DATA_SHORTGI(pdesc, 1);
if (info->flags & IEEE80211_TX_CTL_AMPDU) {
@@ -728,13 +635,13 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw,
SET_TX_DESC_RTS_STBC(pdesc, ((ptcb_desc->rts_stbc) ? 1 : 0));
/* 5G have no CCK rate */
if (rtlhal->current_bandtype == BAND_ON_5G)
- if (ptcb_desc->rts_rate < DESC92D_RATE6M)
- ptcb_desc->rts_rate = DESC92D_RATE6M;
+ if (ptcb_desc->rts_rate < DESC92_RATE6M)
+ ptcb_desc->rts_rate = DESC92_RATE6M;
SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate);
SET_TX_DESC_RTS_BW(pdesc, 0);
SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc);
SET_TX_DESC_RTS_SHORT(pdesc, ((ptcb_desc->rts_rate <=
- DESC92D_RATE54M) ?
+ DESC92_RATE54M) ?
(ptcb_desc->rts_use_shortpreamble ? 1 : 0) :
(ptcb_desc->rts_use_shortgi ? 1 : 0)));
if (bw_40) {
@@ -844,9 +751,9 @@ void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw,
* The braces are needed no matter what checkpatch says
*/
if (rtlhal->current_bandtype == BAND_ON_5G) {
- SET_TX_DESC_TX_RATE(pdesc, DESC92D_RATE6M);
+ SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE6M);
} else {
- SET_TX_DESC_TX_RATE(pdesc, DESC92D_RATE1M);
+ SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE1M);
}
SET_TX_DESC_SEQ(pdesc, 0);
SET_TX_DESC_LINIP(pdesc, 0);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.h b/drivers/net/wireless/rtlwifi/rtl8192de/trx.h
index 992d6766e667..4d55d0b6816d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.h
@@ -537,12 +537,6 @@ do { \
memset((void *)__pdesc, 0, _size); \
} while (0);
-#define RX_HAL_IS_CCK_RATE(_pdesc)\
- (_pdesc->rxmcs == DESC92D_RATE1M || \
- _pdesc->rxmcs == DESC92D_RATE2M || \
- _pdesc->rxmcs == DESC92D_RATE5_5M || \
- _pdesc->rxmcs == DESC92D_RATE11M)
-
/* For 92D early mode */
#define SET_EARLYMODE_PKTNUM(__paddr, __value) \
SET_BITS_OFFSET_LE(__paddr, 0, 3, __value)
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/def.h b/drivers/net/wireless/rtlwifi/rtl8192se/def.h
index 69828f2b3fab..c6c044816d39 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/def.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/def.h
@@ -33,37 +33,6 @@
#define RX_CMD_QUEUE 1
#define RX_MAX_QUEUE 2
-#define DESC92S_RATE1M 0x00
-#define DESC92S_RATE2M 0x01
-#define DESC92S_RATE5_5M 0x02
-#define DESC92S_RATE11M 0x03
-#define DESC92S_RATE6M 0x04
-#define DESC92S_RATE9M 0x05
-#define DESC92S_RATE12M 0x06
-#define DESC92S_RATE18M 0x07
-#define DESC92S_RATE24M 0x08
-#define DESC92S_RATE36M 0x09
-#define DESC92S_RATE48M 0x0a
-#define DESC92S_RATE54M 0x0b
-#define DESC92S_RATEMCS0 0x0c
-#define DESC92S_RATEMCS1 0x0d
-#define DESC92S_RATEMCS2 0x0e
-#define DESC92S_RATEMCS3 0x0f
-#define DESC92S_RATEMCS4 0x10
-#define DESC92S_RATEMCS5 0x11
-#define DESC92S_RATEMCS6 0x12
-#define DESC92S_RATEMCS7 0x13
-#define DESC92S_RATEMCS8 0x14
-#define DESC92S_RATEMCS9 0x15
-#define DESC92S_RATEMCS10 0x16
-#define DESC92S_RATEMCS11 0x17
-#define DESC92S_RATEMCS12 0x18
-#define DESC92S_RATEMCS13 0x19
-#define DESC92S_RATEMCS14 0x1a
-#define DESC92S_RATEMCS15 0x1b
-#define DESC92S_RATEMCS15_SG 0x1c
-#define DESC92S_RATEMCS32 0x20
-
#define SHORT_SLOT_TIME 9
#define NON_SHORT_SLOT_TIME 20
@@ -490,11 +459,11 @@ do { \
#define SET_RX_STATUS__DESC_BUFF_ADDR(__pdesc, __val) \
SET_BITS_OFFSET_LE(__pdesc + 24, 0, 32, __val)
-#define RX_HAL_IS_CCK_RATE(_pdesc)\
- (GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE1M || \
- GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE2M || \
- GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE5_5M ||\
- GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE11M)
+#define SE_RX_HAL_IS_CCK_RATE(_pdesc)\
+ (GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE1M || \
+ GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE2M || \
+ GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE5_5M ||\
+ GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE11M)
enum rf_optype {
RF_OP_BY_SW_3WIRE = 0,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
index d59f66cb7768..c474486e3911 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
@@ -1382,7 +1382,7 @@ static void _rtl92se_power_domain_init(struct ieee80211_hw *hw)
rtl_write_byte(rtlpriv, LDOA15_CTRL, 0x34);
/* Reset MAC-IO and CPU and Core Digital BIT10/11/15 */
- tmpu1b = rtl_read_byte(rtlpriv, SYS_FUNC_EN + 1);
+ tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
/* If IPS we need to turn LED on. So we not
* not disable BIT 3/7 of reg3. */
@@ -1391,7 +1391,7 @@ static void _rtl92se_power_domain_init(struct ieee80211_hw *hw)
else
tmpu1b &= 0x73;
- rtl_write_byte(rtlpriv, SYS_FUNC_EN + 1, tmpu1b);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b);
/* wait for BIT 10/11/15 to pull high automatically!! */
mdelay(1);
@@ -1428,15 +1428,15 @@ static void _rtl92se_power_domain_init(struct ieee80211_hw *hw)
rtl_write_byte(rtlpriv, LDOA15_CTRL, (tmpu1b | BIT(0)));
/* Set Digital Vdd to Retention isolation Path. */
- tmpu2b = rtl_read_word(rtlpriv, SYS_ISO_CTRL);
- rtl_write_word(rtlpriv, SYS_ISO_CTRL, (tmpu2b | BIT(11)));
+ tmpu2b = rtl_read_word(rtlpriv, REG_SYS_ISO_CTRL);
+ rtl_write_word(rtlpriv, REG_SYS_ISO_CTRL, (tmpu2b | BIT(11)));
/* For warm reboot NIC disappera bug. */
- tmpu2b = rtl_read_word(rtlpriv, SYS_FUNC_EN);
- rtl_write_word(rtlpriv, SYS_FUNC_EN, (tmpu2b | BIT(13)));
+ tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
+ rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(13)));
- rtl_write_byte(rtlpriv, SYS_ISO_CTRL + 1, 0x68);
+ rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, 0x68);
/* Enable AFE PLL Macro Block */
tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL);
@@ -1447,17 +1447,17 @@ static void _rtl92se_power_domain_init(struct ieee80211_hw *hw)
mdelay(1);
/* Release isolation AFE PLL & MD */
- rtl_write_byte(rtlpriv, SYS_ISO_CTRL, 0xA6);
+ rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL, 0xA6);
/* Enable MAC clock */
tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR);
rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b | BIT(12) | BIT(11)));
/* Enable Core digital and enable IOREG R/W */
- tmpu2b = rtl_read_word(rtlpriv, SYS_FUNC_EN);
- rtl_write_word(rtlpriv, SYS_FUNC_EN, (tmpu2b | BIT(11)));
+ tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
+ rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(11)));
/* enable REG_EN */
- rtl_write_word(rtlpriv, SYS_FUNC_EN, (tmpu2b | BIT(11) | BIT(15)));
+ rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(11) | BIT(15)));
/* Switch the control path. */
tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/reg.h b/drivers/net/wireless/rtlwifi/rtl8192se/reg.h
index ea32ef2d4098..11f125c030ce 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/reg.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/reg.h
@@ -735,6 +735,7 @@
#define HWSET_MAX_SIZE_92S 128
#define EFUSE_MAX_SECTION 16
#define EFUSE_REAL_CONTENT_LEN 512
+#define EFUSE_OOB_PROTECT_BYTES 15
#define RTL8190_EEPROM_ID 0x8129
#define EEPROM_HPON 0x02
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
index 3876078a63de..3ec9a0d41baf 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
@@ -160,10 +160,16 @@ static int rtl92s_init_sw_vars(struct ieee80211_hw *hw)
rtlpci->first_init = true;
+ /* for debug level */
+ rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug;
/* for LPS & IPS */
rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+ if (!rtlpriv->psc.inactiveps)
+ pr_info("rtl8192ce: Power Save off (module option)\n");
+ if (!rtlpriv->psc.fwctrl_lps)
+ pr_info("rtl8192ce: FW Power Save off (module option)\n");
rtlpriv->psc.reg_fwctrl_lps = 3;
rtlpriv->psc.reg_max_lps_awakeintvl = 5;
/* for ASPM, you can close aspm through
@@ -268,6 +274,7 @@ static struct rtl_mod_params rtl92se_mod_params = {
.inactiveps = true,
.swctrl_lps = true,
.fwctrl_lps = false,
+ .debug = DBG_EMERG,
};
/* Because memory R/W bursting will cause system hang/crash
@@ -300,6 +307,7 @@ static struct rtl_hal_cfg rtl92se_hal_cfg = {
.maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE_92S,
.maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION,
.maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN,
+ .maps[EFUSE_OOB_PROTECT_BYTES_LEN] = EFUSE_OOB_PROTECT_BYTES,
.maps[RWCAM] = REG_RWCAM,
.maps[WCAMI] = REG_WCAMI,
@@ -348,21 +356,21 @@ static struct rtl_hal_cfg rtl92se_hal_cfg = {
.maps[RTL_IMR_ROK] = IMR_ROK,
.maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER),
- .maps[RTL_RC_CCK_RATE1M] = DESC92S_RATE1M,
- .maps[RTL_RC_CCK_RATE2M] = DESC92S_RATE2M,
- .maps[RTL_RC_CCK_RATE5_5M] = DESC92S_RATE5_5M,
- .maps[RTL_RC_CCK_RATE11M] = DESC92S_RATE11M,
- .maps[RTL_RC_OFDM_RATE6M] = DESC92S_RATE6M,
- .maps[RTL_RC_OFDM_RATE9M] = DESC92S_RATE9M,
- .maps[RTL_RC_OFDM_RATE12M] = DESC92S_RATE12M,
- .maps[RTL_RC_OFDM_RATE18M] = DESC92S_RATE18M,
- .maps[RTL_RC_OFDM_RATE24M] = DESC92S_RATE24M,
- .maps[RTL_RC_OFDM_RATE36M] = DESC92S_RATE36M,
- .maps[RTL_RC_OFDM_RATE48M] = DESC92S_RATE48M,
- .maps[RTL_RC_OFDM_RATE54M] = DESC92S_RATE54M,
-
- .maps[RTL_RC_HT_RATEMCS7] = DESC92S_RATEMCS7,
- .maps[RTL_RC_HT_RATEMCS15] = DESC92S_RATEMCS15,
+ .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M,
+ .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M,
+ .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M,
+ .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M,
+ .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M,
+ .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M,
+ .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M,
+ .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M,
+ .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M,
+ .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M,
+ .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M,
+ .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M,
+
+ .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7,
+ .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15,
};
static struct pci_device_id rtl92se_pci_ids[] __devinitdata = {
@@ -378,31 +386,37 @@ MODULE_DEVICE_TABLE(pci, rtl92se_pci_ids);
MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>");
MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Realtek 8192S/8191S 802.11n PCI wireless");
MODULE_FIRMWARE("rtlwifi/rtl8192sefw.bin");
module_param_named(swenc, rtl92se_mod_params.sw_crypto, bool, 0444);
+module_param_named(debug, rtl92se_mod_params.debug, int, 0444);
module_param_named(ips, rtl92se_mod_params.inactiveps, bool, 0444);
module_param_named(swlps, rtl92se_mod_params.swctrl_lps, bool, 0444);
module_param_named(fwlps, rtl92se_mod_params.fwctrl_lps, bool, 0444);
-MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n");
-MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n");
-MODULE_PARM_DESC(swlps, "using linked sw control power save (default 1 is "
- "open)\n");
+MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n");
+MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n");
+MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n");
+MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n");
+MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)");
+static const struct dev_pm_ops rtlwifi_pm_ops = {
+ .suspend = rtl_pci_suspend,
+ .resume = rtl_pci_resume,
+ .freeze = rtl_pci_suspend,
+ .thaw = rtl_pci_resume,
+ .poweroff = rtl_pci_suspend,
+ .restore = rtl_pci_resume,
+};
static struct pci_driver rtl92se_driver = {
.name = KBUILD_MODNAME,
.id_table = rtl92se_pci_ids,
.probe = rtl_pci_probe,
.remove = rtl_pci_disconnect,
-
-#ifdef CONFIG_PM
- .suspend = rtl_pci_suspend,
- .resume = rtl_pci_resume,
-#endif
-
+ .driver.pm = &rtlwifi_pm_ops,
};
static int __init rtl92se_module_init(void)
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
index cffe30851f79..fbebe3ea0a22 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
@@ -51,104 +51,6 @@ static u8 _rtl92se_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 skb_queue)
return skb->priority;
}
-static int _rtl92se_rate_mapping(bool isht, u8 desc_rate, bool first_ampdu)
-{
- int rate_idx = 0;
-
- if (first_ampdu) {
- if (false == isht) {
- switch (desc_rate) {
- case DESC92S_RATE1M:
- rate_idx = 0;
- break;
- case DESC92S_RATE2M:
- rate_idx = 1;
- break;
- case DESC92S_RATE5_5M:
- rate_idx = 2;
- break;
- case DESC92S_RATE11M:
- rate_idx = 3;
- break;
- case DESC92S_RATE6M:
- rate_idx = 4;
- break;
- case DESC92S_RATE9M:
- rate_idx = 5;
- break;
- case DESC92S_RATE12M:
- rate_idx = 6;
- break;
- case DESC92S_RATE18M:
- rate_idx = 7;
- break;
- case DESC92S_RATE24M:
- rate_idx = 8;
- break;
- case DESC92S_RATE36M:
- rate_idx = 9;
- break;
- case DESC92S_RATE48M:
- rate_idx = 10;
- break;
- case DESC92S_RATE54M:
- rate_idx = 11;
- break;
- default:
- rate_idx = 0;
- break;
- }
- } else {
- rate_idx = 11;
- }
-
- return rate_idx;
- }
-
- switch (desc_rate) {
- case DESC92S_RATE1M:
- rate_idx = 0;
- break;
- case DESC92S_RATE2M:
- rate_idx = 1;
- break;
- case DESC92S_RATE5_5M:
- rate_idx = 2;
- break;
- case DESC92S_RATE11M:
- rate_idx = 3;
- break;
- case DESC92S_RATE6M:
- rate_idx = 4;
- break;
- case DESC92S_RATE9M:
- rate_idx = 5;
- break;
- case DESC92S_RATE12M:
- rate_idx = 6;
- break;
- case DESC92S_RATE18M:
- rate_idx = 7;
- break;
- case DESC92S_RATE24M:
- rate_idx = 8;
- break;
- case DESC92S_RATE36M:
- rate_idx = 9;
- break;
- case DESC92S_RATE48M:
- rate_idx = 10;
- break;
- case DESC92S_RATE54M:
- rate_idx = 11;
- break;
- default:
- rate_idx = 11;
- break;
- }
- return rate_idx;
-}
-
static u8 _rtl92s_query_rxpwrpercentage(char antpower)
{
if ((antpower <= -100) || (antpower >= 20))
@@ -222,18 +124,15 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
u8 i, max_spatial_stream;
u32 rssi, total_rssi = 0;
bool in_powersavemode = false;
- bool is_cck_rate;
+ bool is_cck = pstats->is_cck;
- is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc);
pstats->packet_matchbssid = packet_match_bssid;
pstats->packet_toself = packet_toself;
- pstats->is_cck = is_cck_rate;
pstats->packet_beacon = packet_beacon;
- pstats->is_cck = is_cck_rate;
pstats->rx_mimo_signalquality[0] = -1;
pstats->rx_mimo_signalquality[1] = -1;
- if (is_cck_rate) {
+ if (is_cck) {
u8 report, cck_highpwr;
cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo;
@@ -344,9 +243,8 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
pstats->rxpower = rx_pwr_all;
pstats->recvsignalpower = rx_pwr_all;
- if (GET_RX_STATUS_DESC_RX_HT(pdesc) &&
- GET_RX_STATUS_DESC_RX_MCS(pdesc) >= DESC92S_RATEMCS8 &&
- GET_RX_STATUS_DESC_RX_MCS(pdesc) <= DESC92S_RATEMCS15)
+ if (pstats->is_ht && pstats->rate >= DESC92_RATEMCS8 &&
+ pstats->rate <= DESC92_RATEMCS15)
max_spatial_stream = 2;
else
max_spatial_stream = 1;
@@ -364,7 +262,7 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
}
}
- if (is_cck_rate)
+ if (is_cck)
pstats->signalstrength = (u8)(_rtl92se_signal_scale_mapping(hw,
pwdb_all));
else if (rf_rx_num != 0)
@@ -616,6 +514,8 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
{
struct rx_fwinfo *p_drvinfo;
u32 phystatus = (u32)GET_RX_STATUS_DESC_PHY_STATUS(pdesc);
+ struct ieee80211_hdr *hdr;
+ bool first_ampdu = false;
stats->length = (u16)GET_RX_STATUS_DESC_PKT_LEN(pdesc);
stats->rx_drvinfo_size = (u8)GET_RX_STATUS_DESC_DRVINFO_SIZE(pdesc) * 8;
@@ -628,8 +528,12 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
stats->rate = (u8)GET_RX_STATUS_DESC_RX_MCS(pdesc);
stats->shortpreamble = (u16)GET_RX_STATUS_DESC_SPLCP(pdesc);
stats->isampdu = (bool)(GET_RX_STATUS_DESC_PAGGR(pdesc) == 1);
+ stats->isfirst_ampdu = (bool) ((GET_RX_STATUS_DESC_PAGGR(pdesc) == 1)
+ && (GET_RX_STATUS_DESC_FAGGR(pdesc) == 1));
stats->timestamp_low = GET_RX_STATUS_DESC_TSFL(pdesc);
stats->rx_is40Mhzpacket = (bool)GET_RX_STATUS_DESC_BW(pdesc);
+ stats->is_ht = (bool)GET_RX_STATUS_DESC_RX_HT(pdesc);
+ stats->is_cck = SE_RX_HAL_IS_CCK_RATE(pdesc);
if (stats->hwerror)
return false;
@@ -637,30 +541,39 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
rx_status->freq = hw->conf.channel->center_freq;
rx_status->band = hw->conf.channel->band;
- if (GET_RX_STATUS_DESC_CRC32(pdesc))
- rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+ hdr = (struct ieee80211_hdr *)(skb->data + stats->rx_drvinfo_size
+ + stats->rx_bufshift);
- if (!GET_RX_STATUS_DESC_SWDEC(pdesc))
- rx_status->flag |= RX_FLAG_DECRYPTED;
+ if (stats->crc)
+ rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
- if (GET_RX_STATUS_DESC_BW(pdesc))
+ if (stats->rx_is40Mhzpacket)
rx_status->flag |= RX_FLAG_40MHZ;
- if (GET_RX_STATUS_DESC_RX_HT(pdesc))
+ if (stats->is_ht)
rx_status->flag |= RX_FLAG_HT;
rx_status->flag |= RX_FLAG_MACTIME_MPDU;
- if (stats->decrypted)
- rx_status->flag |= RX_FLAG_DECRYPTED;
-
- rx_status->rate_idx = _rtl92se_rate_mapping((bool)
- GET_RX_STATUS_DESC_RX_HT(pdesc),
- (u8)GET_RX_STATUS_DESC_RX_MCS(pdesc),
- (bool)GET_RX_STATUS_DESC_PAGGR(pdesc));
+ /* hw will set stats->decrypted true, if it finds the
+ * frame is open data frame or mgmt frame,
+ * hw will not decrypt robust managment frame
+ * for IEEE80211w but still set stats->decrypted
+ * true, so here we should set it back to undecrypted
+ * for IEEE80211w frame, and mac80211 sw will help
+ * to decrypt it */
+ if (stats->decrypted) {
+ if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
+ (ieee80211_has_protected(hdr->frame_control)))
+ rx_status->flag &= ~RX_FLAG_DECRYPTED;
+ else
+ rx_status->flag |= RX_FLAG_DECRYPTED;
+ }
+ rx_status->rate_idx = rtlwifi_rate_mapping(hw,
+ stats->is_ht, stats->rate, first_ampdu);
- rx_status->mactime = GET_RX_STATUS_DESC_TSFL(pdesc);
+ rx_status->mactime = stats->timestamp_low;
if (phystatus) {
p_drvinfo = (struct rx_fwinfo *)(skb->data +
stats->rx_bufshift);
@@ -723,14 +636,14 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw,
SET_TX_DESC_RSVD_MACID(pdesc, reserved_macid);
SET_TX_DESC_TXHT(pdesc, ((ptcb_desc->hw_rate >=
- DESC92S_RATEMCS0) ? 1 : 0));
+ DESC92_RATEMCS0) ? 1 : 0));
if (rtlhal->version == VERSION_8192S_ACUT) {
- if (ptcb_desc->hw_rate == DESC92S_RATE1M ||
- ptcb_desc->hw_rate == DESC92S_RATE2M ||
- ptcb_desc->hw_rate == DESC92S_RATE5_5M ||
- ptcb_desc->hw_rate == DESC92S_RATE11M) {
- ptcb_desc->hw_rate = DESC92S_RATE12M;
+ if (ptcb_desc->hw_rate == DESC92_RATE1M ||
+ ptcb_desc->hw_rate == DESC92_RATE2M ||
+ ptcb_desc->hw_rate == DESC92_RATE5_5M ||
+ ptcb_desc->hw_rate == DESC92_RATE11M) {
+ ptcb_desc->hw_rate = DESC92_RATE12M;
}
}
@@ -759,7 +672,7 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw,
SET_TX_DESC_RTS_BANDWIDTH(pdesc, 0);
SET_TX_DESC_RTS_SUB_CARRIER(pdesc, ptcb_desc->rts_sc);
SET_TX_DESC_RTS_SHORT(pdesc, ((ptcb_desc->rts_rate <=
- DESC92S_RATE54M) ?
+ DESC92_RATE54M) ?
(ptcb_desc->rts_use_shortpreamble ? 1 : 0)
: (ptcb_desc->rts_use_shortgi ? 1 : 0)));
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c
index 8b1cef0ffde6..b42c2e2b2055 100644
--- a/drivers/net/wireless/rtlwifi/usb.c
+++ b/drivers/net/wireless/rtlwifi/usb.c
@@ -191,44 +191,6 @@ static void _usb_write32_async(struct rtl_priv *rtlpriv, u32 addr, u32 val)
_usb_write_async(to_usb_device(dev), addr, val, 4);
}
-static int _usb_nbytes_read_write(struct usb_device *udev, bool read, u32 addr,
- u16 len, u8 *pdata)
-{
- int status;
- u8 request;
- u16 wvalue;
- u16 index;
-
- request = REALTEK_USB_VENQT_CMD_REQ;
- index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */
- wvalue = (u16)addr;
- if (read)
- status = _usbctrl_vendorreq_sync_read(udev, request, wvalue,
- index, pdata, len);
- else
- status = _usbctrl_vendorreq_async_write(udev, request, wvalue,
- index, pdata, len);
- return status;
-}
-
-static int _usb_readN_sync(struct rtl_priv *rtlpriv, u32 addr, u16 len,
- u8 *pdata)
-{
- struct device *dev = rtlpriv->io.dev;
-
- return _usb_nbytes_read_write(to_usb_device(dev), true, addr, len,
- pdata);
-}
-
-static int _usb_writeN_async(struct rtl_priv *rtlpriv, u32 addr, u16 len,
- u8 *pdata)
-{
- struct device *dev = rtlpriv->io.dev;
-
- return _usb_nbytes_read_write(to_usb_device(dev), false, addr, len,
- pdata);
-}
-
static void _rtl_usb_io_handler_init(struct device *dev,
struct ieee80211_hw *hw)
{
@@ -239,11 +201,9 @@ static void _rtl_usb_io_handler_init(struct device *dev,
rtlpriv->io.write8_async = _usb_write8_async;
rtlpriv->io.write16_async = _usb_write16_async;
rtlpriv->io.write32_async = _usb_write32_async;
- rtlpriv->io.writeN_async = _usb_writeN_async;
rtlpriv->io.read8_sync = _usb_read8_sync;
rtlpriv->io.read16_sync = _usb_read16_sync;
rtlpriv->io.read32_sync = _usb_read32_sync;
- rtlpriv->io.readN_sync = _usb_readN_sync;
}
static void _rtl_usb_io_handler_release(struct ieee80211_hw *hw)
@@ -863,6 +823,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb,
u8 tid = 0;
u16 seq_number = 0;
+ memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
if (ieee80211_is_auth(fc)) {
RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n"));
rtl_ips_nic_on(hw);
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
index d3c3ffd38984..713c7ddba8eb 100644
--- a/drivers/net/wireless/rtlwifi/wifi.h
+++ b/drivers/net/wireless/rtlwifi/wifi.h
@@ -165,6 +165,12 @@ enum hardware_type {
#define IS_HARDWARE_TYPE_8723U(rtlhal) \
(rtlhal->hw_type == HARDWARE_TYPE_RTL8723U)
+#define RX_HAL_IS_CCK_RATE(_pdesc)\
+ (_pdesc->rxmcs == DESC92_RATE1M || \
+ _pdesc->rxmcs == DESC92_RATE2M || \
+ _pdesc->rxmcs == DESC92_RATE5_5M || \
+ _pdesc->rxmcs == DESC92_RATE11M)
+
enum scan_operation_backup_opt {
SCAN_OPT_BACKUP = 0,
SCAN_OPT_RESTORE,
@@ -386,6 +392,41 @@ enum rtl_hal_state {
_HAL_STATE_START = 1,
};
+enum rtl_desc92_rate {
+ DESC92_RATE1M = 0x00,
+ DESC92_RATE2M = 0x01,
+ DESC92_RATE5_5M = 0x02,
+ DESC92_RATE11M = 0x03,
+
+ DESC92_RATE6M = 0x04,
+ DESC92_RATE9M = 0x05,
+ DESC92_RATE12M = 0x06,
+ DESC92_RATE18M = 0x07,
+ DESC92_RATE24M = 0x08,
+ DESC92_RATE36M = 0x09,
+ DESC92_RATE48M = 0x0a,
+ DESC92_RATE54M = 0x0b,
+
+ DESC92_RATEMCS0 = 0x0c,
+ DESC92_RATEMCS1 = 0x0d,
+ DESC92_RATEMCS2 = 0x0e,
+ DESC92_RATEMCS3 = 0x0f,
+ DESC92_RATEMCS4 = 0x10,
+ DESC92_RATEMCS5 = 0x11,
+ DESC92_RATEMCS6 = 0x12,
+ DESC92_RATEMCS7 = 0x13,
+ DESC92_RATEMCS8 = 0x14,
+ DESC92_RATEMCS9 = 0x15,
+ DESC92_RATEMCS10 = 0x16,
+ DESC92_RATEMCS11 = 0x17,
+ DESC92_RATEMCS12 = 0x18,
+ DESC92_RATEMCS13 = 0x19,
+ DESC92_RATEMCS14 = 0x1a,
+ DESC92_RATEMCS15 = 0x1b,
+ DESC92_RATEMCS15_SG = 0x1c,
+ DESC92_RATEMCS32 = 0x20,
+};
+
enum rtl_var_map {
/*reg map */
SYS_ISO_CTRL = 0,
@@ -409,6 +450,7 @@ enum rtl_var_map {
EFUSE_HWSET_MAX_SIZE,
EFUSE_MAX_SECTION_MAP,
EFUSE_REAL_CONTENT_SIZE,
+ EFUSE_OOB_PROTECT_BYTES_LEN,
/*CAM map */
RWCAM,
@@ -901,16 +943,12 @@ struct rtl_io {
unsigned long pci_base_addr; /*device I/O address */
void (*write8_async) (struct rtl_priv *rtlpriv, u32 addr, u8 val);
- void (*write16_async) (struct rtl_priv *rtlpriv, u32 addr, u16 val);
- void (*write32_async) (struct rtl_priv *rtlpriv, u32 addr, u32 val);
- int (*writeN_async) (struct rtl_priv *rtlpriv, u32 addr, u16 len,
- u8 *pdata);
+ void (*write16_async) (struct rtl_priv *rtlpriv, u32 addr, __le16 val);
+ void (*write32_async) (struct rtl_priv *rtlpriv, u32 addr, __le32 val);
u8(*read8_sync) (struct rtl_priv *rtlpriv, u32 addr);
u16(*read16_sync) (struct rtl_priv *rtlpriv, u32 addr);
u32(*read32_sync) (struct rtl_priv *rtlpriv, u32 addr);
- int (*readN_sync) (struct rtl_priv *rtlpriv, u32 addr, u16 len,
- u8 *pdata);
};
@@ -1287,6 +1325,7 @@ struct rtl_stats {
s8 rx_mimo_signalquality[2];
bool packet_matchbssid;
bool is_cck;
+ bool is_ht;
bool packet_toself;
bool packet_beacon; /*for rssi */
char cck_adc_pwdb[4]; /*for rx path selection */
@@ -1448,6 +1487,9 @@ struct rtl_mod_params {
/* default: 0 = using hardware encryption */
int sw_crypto;
+ /* default: 0 = DBG_EMERG (0)*/
+ int debug;
+
/* default: 1 = using no linked power save */
bool inactiveps;
diff --git a/drivers/net/wireless/wl1251/cmd.h b/drivers/net/wireless/wl1251/cmd.h
index 79ca5273c9e9..ee4f2b391822 100644
--- a/drivers/net/wireless/wl1251/cmd.h
+++ b/drivers/net/wireless/wl1251/cmd.h
@@ -269,7 +269,7 @@ struct cmd_join {
u8 bss_type;
u8 channel;
u8 ssid_len;
- u8 ssid[IW_ESSID_MAX_SIZE];
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 ctrl; /* JOIN_CMD_CTRL_* */
u8 tx_mgt_frame_rate; /* OBSOLETE */
u8 tx_mgt_frame_mod; /* OBSOLETE */
diff --git a/drivers/net/wireless/wl1251/main.c b/drivers/net/wireless/wl1251/main.c
index a14a48c99cdc..ba3268ea81fe 100644
--- a/drivers/net/wireless/wl1251/main.c
+++ b/drivers/net/wireless/wl1251/main.c
@@ -1158,7 +1158,8 @@ static struct ieee80211_channel wl1251_channels[] = {
{ .hw_value = 13, .center_freq = 2472},
};
-static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
+static int wl1251_op_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
enum wl1251_acx_ps_scheme ps_scheme;
diff --git a/drivers/net/wireless/wl1251/wl12xx_80211.h b/drivers/net/wireless/wl1251/wl12xx_80211.h
index 1417b1445c3d..04ed51495772 100644
--- a/drivers/net/wireless/wl1251/wl12xx_80211.h
+++ b/drivers/net/wireless/wl1251/wl12xx_80211.h
@@ -76,7 +76,7 @@ struct wl12xx_ie_header {
struct wl12xx_ie_ssid {
struct wl12xx_ie_header header;
- char ssid[IW_ESSID_MAX_SIZE];
+ char ssid[IEEE80211_MAX_SSID_LEN];
} __packed;
struct wl12xx_ie_rates {
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig
index 07bcb1548d8b..3fe388b87c2e 100644
--- a/drivers/net/wireless/wl12xx/Kconfig
+++ b/drivers/net/wireless/wl12xx/Kconfig
@@ -19,16 +19,6 @@ config WL12XX
If you choose to build a module, it will be called wl12xx. Say N if
unsure.
-config WL12XX_HT
- bool "TI wl12xx 802.11 HT support (EXPERIMENTAL)"
- depends on WL12XX && EXPERIMENTAL
- default n
- ---help---
- This will enable 802.11 HT support in the wl12xx module.
-
- That configuration is temporary due to the code incomplete and
- still in testing process.
-
config WL12XX_SPI
tristate "TI wl12xx SPI support"
depends on WL12XX && SPI_MASTER
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile
index 521c0414e52e..621b3483ca2c 100644
--- a/drivers/net/wireless/wl12xx/Makefile
+++ b/drivers/net/wireless/wl12xx/Makefile
@@ -1,16 +1,16 @@
wl12xx-objs = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \
boot.o init.o debugfs.o scan.o
-wl12xx_spi-objs = spi.o
+wl12xx_spi-objs = spi.o
wl12xx_sdio-objs = sdio.o
-wl12xx_sdio_test-objs = sdio_test.o
+wl12xx_sdio_test-objs = sdio_test.o
wl12xx-$(CONFIG_NL80211_TESTMODE) += testmode.o
obj-$(CONFIG_WL12XX) += wl12xx.o
obj-$(CONFIG_WL12XX_SPI) += wl12xx_spi.o
obj-$(CONFIG_WL12XX_SDIO) += wl12xx_sdio.o
-obj-$(CONFIG_WL12XX_SDIO_TEST) += wl12xx_sdio_test.o
+obj-$(CONFIG_WL12XX_SDIO_TEST) += wl12xx_sdio_test.o
# small builtin driver bit
obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index 7e33f1f4f3d4..ca044a743191 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -46,6 +46,7 @@ int wl1271_acx_wake_up_conditions(struct wl1271 *wl)
goto out;
}
+ wake_up->role_id = wl->role_id;
wake_up->wake_up_event = wl->conf.conn.wake_up_event;
wake_up->listen_interval = wl->conf.conn.listen_interval;
@@ -77,8 +78,6 @@ int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth)
auth->sleep_auth = sleep_auth;
ret = wl1271_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth));
- if (ret < 0)
- return ret;
out:
kfree(auth);
@@ -101,6 +100,7 @@ int wl1271_acx_tx_power(struct wl1271 *wl, int power)
goto out;
}
+ acx->role_id = wl->role_id;
acx->current_tx_power = power * 10;
ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx));
@@ -128,6 +128,7 @@ int wl1271_acx_feature_cfg(struct wl1271 *wl)
}
/* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */
+ feature->role_id = wl->role_id;
feature->data_flow_options = 0;
feature->options = 0;
@@ -183,34 +184,6 @@ out:
return ret;
}
-int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter)
-{
- struct acx_rx_config *rx_config;
- int ret;
-
- wl1271_debug(DEBUG_ACX, "acx rx config");
-
- rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL);
- if (!rx_config) {
- ret = -ENOMEM;
- goto out;
- }
-
- rx_config->config_options = cpu_to_le32(config);
- rx_config->filter_options = cpu_to_le32(filter);
-
- ret = wl1271_cmd_configure(wl, ACX_RX_CFG,
- rx_config, sizeof(*rx_config));
- if (ret < 0) {
- wl1271_warning("failed to set rx config: %d", ret);
- goto out;
- }
-
-out:
- kfree(rx_config);
- return ret;
-}
-
int wl1271_acx_pd_threshold(struct wl1271 *wl)
{
struct acx_packet_detection *pd;
@@ -250,6 +223,7 @@ int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time)
goto out;
}
+ slot->role_id = wl->role_id;
slot->wone_index = STATION_WONE_INDEX;
slot->slot_time = slot_time;
@@ -279,6 +253,7 @@ int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable,
}
/* MAC filtering */
+ acx->role_id = wl->role_id;
acx->enabled = enable;
acx->num_groups = mc_list_len;
memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN);
@@ -308,6 +283,7 @@ int wl1271_acx_service_period_timeout(struct wl1271 *wl)
wl1271_debug(DEBUG_ACX, "acx service period timeout");
+ rx_timeout->role_id = wl->role_id;
rx_timeout->ps_poll_timeout = cpu_to_le16(wl->conf.rx.ps_poll_timeout);
rx_timeout->upsd_timeout = cpu_to_le16(wl->conf.rx.upsd_timeout);
@@ -344,6 +320,7 @@ int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold)
goto out;
}
+ rts->role_id = wl->role_id;
rts->threshold = cpu_to_le16((u16)rts_threshold);
ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts));
@@ -403,6 +380,7 @@ int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter)
goto out;
}
+ beacon_filter->role_id = wl->role_id;
beacon_filter->enable = enable_filter;
/*
@@ -439,6 +417,7 @@ int wl1271_acx_beacon_filter_table(struct wl1271 *wl)
}
/* configure default beacon pass-through rules */
+ ie_table->role_id = wl->role_id;
ie_table->num_ie = 0;
for (i = 0; i < wl->conf.conn.bcn_filt_ie_count; i++) {
struct conf_bcn_filt_rule *r = &(wl->conf.conn.bcn_filt_ie[i]);
@@ -500,6 +479,7 @@ int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable)
timeout = wl->conf.conn.bss_lose_timeout;
}
+ acx->role_id = wl->role_id;
acx->synch_fail_thold = cpu_to_le32(threshold);
acx->bss_lose_timeout = cpu_to_le32(timeout);
@@ -546,43 +526,13 @@ out:
return ret;
}
-int wl1271_acx_sta_sg_cfg(struct wl1271 *wl)
-{
- struct acx_sta_bt_wlan_coex_param *param;
- struct conf_sg_settings *c = &wl->conf.sg;
- int i, ret;
-
- wl1271_debug(DEBUG_ACX, "acx sg sta cfg");
-
- param = kzalloc(sizeof(*param), GFP_KERNEL);
- if (!param) {
- ret = -ENOMEM;
- goto out;
- }
-
- /* BT-WLAN coext parameters */
- for (i = 0; i < CONF_SG_STA_PARAMS_MAX; i++)
- param->params[i] = cpu_to_le32(c->sta_params[i]);
- param->param_idx = CONF_SG_PARAMS_ALL;
-
- ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
- if (ret < 0) {
- wl1271_warning("failed to set sg config: %d", ret);
- goto out;
- }
-
-out:
- kfree(param);
- return ret;
-}
-
-int wl1271_acx_ap_sg_cfg(struct wl1271 *wl)
+int wl12xx_acx_sg_cfg(struct wl1271 *wl)
{
- struct acx_ap_bt_wlan_coex_param *param;
+ struct acx_bt_wlan_coex_param *param;
struct conf_sg_settings *c = &wl->conf.sg;
int i, ret;
- wl1271_debug(DEBUG_ACX, "acx sg ap cfg");
+ wl1271_debug(DEBUG_ACX, "acx sg cfg");
param = kzalloc(sizeof(*param), GFP_KERNEL);
if (!param) {
@@ -591,8 +541,8 @@ int wl1271_acx_ap_sg_cfg(struct wl1271 *wl)
}
/* BT-WLAN coext parameters */
- for (i = 0; i < CONF_SG_AP_PARAMS_MAX; i++)
- param->params[i] = cpu_to_le32(c->ap_params[i]);
+ for (i = 0; i < CONF_SG_PARAMS_MAX; i++)
+ param->params[i] = cpu_to_le32(c->params[i]);
param->param_idx = CONF_SG_PARAMS_ALL;
ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
@@ -624,10 +574,8 @@ int wl1271_acx_cca_threshold(struct wl1271 *wl)
ret = wl1271_cmd_configure(wl, ACX_CCA_THRESHOLD,
detection, sizeof(*detection));
- if (ret < 0) {
+ if (ret < 0)
wl1271_warning("failed to set cca threshold: %d", ret);
- return ret;
- }
out:
kfree(detection);
@@ -647,6 +595,7 @@ int wl1271_acx_bcn_dtim_options(struct wl1271 *wl)
goto out;
}
+ bb->role_id = wl->role_id;
bb->beacon_rx_timeout = cpu_to_le16(wl->conf.conn.beacon_rx_timeout);
bb->broadcast_timeout = cpu_to_le16(wl->conf.conn.broadcast_timeout);
bb->rx_broadcast_in_ps = wl->conf.conn.rx_broadcast_in_ps;
@@ -676,6 +625,7 @@ int wl1271_acx_aid(struct wl1271 *wl, u16 aid)
goto out;
}
+ acx_aid->role_id = wl->role_id;
acx_aid->aid = cpu_to_le16(aid);
ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid));
@@ -731,6 +681,7 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble)
goto out;
}
+ acx->role_id = wl->role_id;
acx->preamble = preamble;
ret = wl1271_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx));
@@ -758,6 +709,7 @@ int wl1271_acx_cts_protect(struct wl1271 *wl,
goto out;
}
+ acx->role_id = wl->role_id;
acx->ctsprotect = ctsprotect;
ret = wl1271_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx));
@@ -789,9 +741,8 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats)
int wl1271_acx_sta_rate_policies(struct wl1271 *wl)
{
- struct acx_sta_rate_policy *acx;
+ struct acx_rate_policy *acx;
struct conf_tx_rate_class *c = &wl->conf.tx.sta_rc_conf;
- int idx = 0;
int ret = 0;
wl1271_debug(DEBUG_ACX, "acx rate policies");
@@ -803,25 +754,46 @@ int wl1271_acx_sta_rate_policies(struct wl1271 *wl)
goto out;
}
+ wl1271_debug(DEBUG_ACX, "basic_rate: 0x%x, full_rate: 0x%x",
+ wl->basic_rate, wl->rate_set);
+
/* configure one basic rate class */
- idx = ACX_TX_BASIC_RATE;
- acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->basic_rate);
- acx->rate_class[idx].short_retry_limit = c->short_retry_limit;
- acx->rate_class[idx].long_retry_limit = c->long_retry_limit;
- acx->rate_class[idx].aflags = c->aflags;
+ acx->rate_policy_idx = cpu_to_le32(ACX_TX_BASIC_RATE);
+ acx->rate_policy.enabled_rates = cpu_to_le32(wl->basic_rate);
+ acx->rate_policy.short_retry_limit = c->short_retry_limit;
+ acx->rate_policy.long_retry_limit = c->long_retry_limit;
+ acx->rate_policy.aflags = c->aflags;
+
+ ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("Setting of rate policies failed: %d", ret);
+ goto out;
+ }
/* configure one AP supported rate class */
- idx = ACX_TX_AP_FULL_RATE;
- acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->rate_set);
- acx->rate_class[idx].short_retry_limit = c->short_retry_limit;
- acx->rate_class[idx].long_retry_limit = c->long_retry_limit;
- acx->rate_class[idx].aflags = c->aflags;
+ acx->rate_policy_idx = cpu_to_le32(ACX_TX_AP_FULL_RATE);
+ acx->rate_policy.enabled_rates = cpu_to_le32(wl->rate_set);
+ acx->rate_policy.short_retry_limit = c->short_retry_limit;
+ acx->rate_policy.long_retry_limit = c->long_retry_limit;
+ acx->rate_policy.aflags = c->aflags;
- acx->rate_class_cnt = cpu_to_le32(ACX_TX_RATE_POLICY_CNT);
+ ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("Setting of rate policies failed: %d", ret);
+ goto out;
+ }
- wl1271_debug(DEBUG_ACX, "basic_rate: 0x%x, full_rate: 0x%x",
- acx->rate_class[ACX_TX_BASIC_RATE].enabled_rates,
- acx->rate_class[ACX_TX_AP_FULL_RATE].enabled_rates);
+ /*
+ * configure one rate class for basic p2p operations.
+ * (p2p packets should always go out with OFDM rates, even
+ * if we are currently connected to 11b AP)
+ */
+ acx->rate_policy_idx = cpu_to_le32(ACX_TX_BASIC_RATE_P2P);
+ acx->rate_policy.enabled_rates =
+ cpu_to_le32(CONF_TX_RATE_MASK_BASIC_P2P);
+ acx->rate_policy.short_retry_limit = c->short_retry_limit;
+ acx->rate_policy.long_retry_limit = c->long_retry_limit;
+ acx->rate_policy.aflags = c->aflags;
ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
if (ret < 0) {
@@ -837,7 +809,7 @@ out:
int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c,
u8 idx)
{
- struct acx_ap_rate_policy *acx;
+ struct acx_rate_policy *acx;
int ret = 0;
wl1271_debug(DEBUG_ACX, "acx ap rate policy %d rates 0x%x",
@@ -883,6 +855,7 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,
goto out;
}
+ acx->role_id = wl->role_id;
acx->ac = ac;
acx->cw_min = cw_min;
acx->cw_max = cpu_to_le16(cw_max);
@@ -916,6 +889,7 @@ int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
goto out;
}
+ acx->role_id = wl->role_id;
acx->queue_id = queue_id;
acx->channel_type = channel_type;
acx->tsid = tsid;
@@ -995,52 +969,9 @@ out:
return ret;
}
-int wl1271_acx_ap_mem_cfg(struct wl1271 *wl)
+int wl12xx_acx_mem_cfg(struct wl1271 *wl)
{
- struct wl1271_acx_ap_config_memory *mem_conf;
- struct conf_memory_settings *mem;
- int ret;
-
- wl1271_debug(DEBUG_ACX, "wl1271 mem cfg");
-
- mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL);
- if (!mem_conf) {
- ret = -ENOMEM;
- goto out;
- }
-
- if (wl->chip.id == CHIP_ID_1283_PG20)
- /*
- * FIXME: The 128x AP FW does not yet support dynamic memory.
- * Use the base memory configuration for 128x for now. This
- * should be fine tuned in the future.
- */
- mem = &wl->conf.mem_wl128x;
- else
- mem = &wl->conf.mem_wl127x;
-
- /* memory config */
- mem_conf->num_stations = mem->num_stations;
- mem_conf->rx_mem_block_num = mem->rx_block_num;
- mem_conf->tx_min_mem_block_num = mem->tx_min_block_num;
- mem_conf->num_ssid_profiles = mem->ssid_profiles;
- mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS);
-
- ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
- sizeof(*mem_conf));
- if (ret < 0) {
- wl1271_warning("wl1271 mem config failed: %d", ret);
- goto out;
- }
-
-out:
- kfree(mem_conf);
- return ret;
-}
-
-int wl1271_acx_sta_mem_cfg(struct wl1271 *wl)
-{
- struct wl1271_acx_sta_config_memory *mem_conf;
+ struct wl12xx_acx_config_memory *mem_conf;
struct conf_memory_settings *mem;
int ret;
@@ -1183,6 +1114,7 @@ int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable)
goto out;
}
+ acx->role_id = wl->role_id;
acx->enable = enable ? CONF_BET_MODE_ENABLE : CONF_BET_MODE_DISABLE;
acx->max_consecutive = wl->conf.conn.bet_max_consecutive;
@@ -1210,6 +1142,7 @@ int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address)
goto out;
}
+ acx->role_id = wl->role_id;
acx->version = ACX_IPV4_VERSION;
acx->enable = enable;
@@ -1269,6 +1202,7 @@ int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable)
goto out;
}
+ acx->role_id = wl->role_id;
acx->enabled = enable;
ret = wl1271_cmd_configure(wl, ACX_KEEP_ALIVE_MODE, acx, sizeof(*acx));
@@ -1295,6 +1229,7 @@ int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid)
goto out;
}
+ acx->role_id = wl->role_id;
acx->period = cpu_to_le32(wl->conf.conn.keep_alive_interval);
acx->index = index;
acx->tpl_validation = tpl_valid;
@@ -1328,6 +1263,7 @@ int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
wl->last_rssi_event = -1;
+ acx->role_id = wl->role_id;
acx->pacing = cpu_to_le16(wl->conf.roam_trigger.trigger_pacing);
acx->metric = WL1271_ACX_TRIG_METRIC_RSSI_BEACON;
acx->type = WL1271_ACX_TRIG_TYPE_EDGE;
@@ -1366,6 +1302,7 @@ int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl)
goto out;
}
+ acx->role_id = wl->role_id;
acx->rssi_beacon = c->avg_weight_rssi_beacon;
acx->rssi_data = c->avg_weight_rssi_data;
acx->snr_beacon = c->avg_weight_snr_beacon;
@@ -1384,14 +1321,15 @@ out:
int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
struct ieee80211_sta_ht_cap *ht_cap,
- bool allow_ht_operation)
+ bool allow_ht_operation, u8 hlid)
{
struct wl1271_acx_ht_capabilities *acx;
- u8 mac_address[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
int ret = 0;
u32 ht_capabilites = 0;
- wl1271_debug(DEBUG_ACX, "acx ht capabilities setting");
+ wl1271_debug(DEBUG_ACX, "acx ht capabilities setting "
+ "sta supp: %d sta cap: %d", ht_cap->ht_supported,
+ ht_cap->cap);
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
@@ -1399,26 +1337,22 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
goto out;
}
- /* Allow HT Operation ? */
- if (allow_ht_operation) {
- ht_capabilites =
- WL1271_ACX_FW_CAP_HT_OPERATION;
- if (ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD)
- ht_capabilites |=
- WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT;
- if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)
- ht_capabilites |=
- WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS;
- if (ht_cap->cap & IEEE80211_HT_CAP_LSIG_TXOP_PROT)
- ht_capabilites |=
- WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION;
+ if (allow_ht_operation && ht_cap->ht_supported) {
+ /* no need to translate capabilities - use the spec values */
+ ht_capabilites = ht_cap->cap;
+
+ /*
+ * this bit is not employed by the spec but only by FW to
+ * indicate peer HT support
+ */
+ ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION;
/* get data from A-MPDU parameters field */
acx->ampdu_max_length = ht_cap->ampdu_factor;
acx->ampdu_min_spacing = ht_cap->ampdu_density;
}
- memcpy(acx->mac_address, mac_address, ETH_ALEN);
+ acx->hlid = hlid;
acx->ht_capabilites = cpu_to_le32(ht_capabilites);
ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx));
@@ -1446,6 +1380,7 @@ int wl1271_acx_set_ht_information(struct wl1271 *wl,
goto out;
}
+ acx->role_id = wl->role_id;
acx->ht_protection =
(u8)(ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION);
acx->rifs_mode = 0;
@@ -1467,14 +1402,12 @@ out:
}
/* Configure BA session initiator/receiver parameters setting in the FW. */
-int wl1271_acx_set_ba_session(struct wl1271 *wl,
- enum ieee80211_back_parties direction,
- u8 tid_index, u8 policy)
+int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl)
{
- struct wl1271_acx_ba_session_policy *acx;
+ struct wl1271_acx_ba_initiator_policy *acx;
int ret;
- wl1271_debug(DEBUG_ACX, "acx ba session setting");
+ wl1271_debug(DEBUG_ACX, "acx ba initiator policy");
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
@@ -1482,33 +1415,18 @@ int wl1271_acx_set_ba_session(struct wl1271 *wl,
goto out;
}
- /* ANY role */
- acx->role_id = 0xff;
- acx->tid = tid_index;
- acx->enable = policy;
- acx->ba_direction = direction;
-
- switch (direction) {
- case WLAN_BACK_INITIATOR:
- acx->win_size = wl->conf.ht.tx_ba_win_size;
- acx->inactivity_timeout = wl->conf.ht.inactivity_timeout;
- break;
- case WLAN_BACK_RECIPIENT:
- acx->win_size = RX_BA_WIN_SIZE;
- acx->inactivity_timeout = 0;
- break;
- default:
- wl1271_error("Incorrect acx command id=%x\n", direction);
- ret = -EINVAL;
- goto out;
- }
+ /* set for the current role */
+ acx->role_id = wl->role_id;
+ acx->tid_bitmap = wl->conf.ht.tx_ba_tid_bitmap;
+ acx->win_size = wl->conf.ht.tx_ba_win_size;
+ acx->inactivity_timeout = wl->conf.ht.inactivity_timeout;
ret = wl1271_cmd_configure(wl,
- ACX_BA_SESSION_POLICY_CFG,
+ ACX_BA_SESSION_INIT_POLICY,
acx,
sizeof(*acx));
if (ret < 0) {
- wl1271_warning("acx ba session setting failed: %d", ret);
+ wl1271_warning("acx ba initiator policy failed: %d", ret);
goto out;
}
@@ -1518,8 +1436,8 @@ out:
}
/* setup BA session receiver setting in the FW. */
-int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
- bool enable)
+int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index,
+ u16 ssn, bool enable, u8 peer_hlid)
{
struct wl1271_acx_ba_receiver_setup *acx;
int ret;
@@ -1532,11 +1450,10 @@ int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
goto out;
}
- /* Single link for now */
- acx->link_id = 1;
+ acx->hlid = peer_hlid;
acx->tid = tid_index;
acx->enable = enable;
- acx->win_size = 0;
+ acx->win_size = wl->conf.ht.rx_ba_win_size;
acx->ssn = ssn;
ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_RX_SETUP, acx,
@@ -1606,6 +1523,7 @@ int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable)
if (!(conf_queues & BIT(i)))
continue;
+ rx_streaming->role_id = wl->role_id;
rx_streaming->tid = i;
rx_streaming->enable = enable_queues & BIT(i);
rx_streaming->period = wl->conf.rx_streaming.interval;
@@ -1635,6 +1553,7 @@ int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl)
if (!acx)
return -ENOMEM;
+ acx->role_id = wl->role_id;
acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries);
ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx));
@@ -1703,31 +1622,6 @@ out:
return ret;
}
-int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable)
-{
- struct acx_ap_beacon_filter *acx = NULL;
- int ret;
-
- wl1271_debug(DEBUG_ACX, "acx set ap beacon filter: %d", enable);
-
- acx = kzalloc(sizeof(*acx), GFP_KERNEL);
- if (!acx)
- return -ENOMEM;
-
- acx->enable = enable ? 1 : 0;
-
- ret = wl1271_cmd_configure(wl, ACX_AP_BEACON_FILTER_OPT,
- acx, sizeof(*acx));
- if (ret < 0) {
- wl1271_warning("acx set ap beacon filter failed: %d", ret);
- goto out;
- }
-
-out:
- kfree(acx);
- return ret;
-}
-
int wl1271_acx_fm_coex(struct wl1271 *wl)
{
struct wl1271_acx_fm_coex *acx;
@@ -1767,3 +1661,85 @@ out:
kfree(acx);
return ret;
}
+
+int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl)
+{
+ struct wl12xx_acx_set_rate_mgmt_params *acx = NULL;
+ struct conf_rate_policy_settings *conf = &wl->conf.rate;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx set rate mgmt params");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx)
+ return -ENOMEM;
+
+ acx->index = ACX_RATE_MGMT_ALL_PARAMS;
+ acx->rate_retry_score = cpu_to_le16(conf->rate_retry_score);
+ acx->per_add = cpu_to_le16(conf->per_add);
+ acx->per_th1 = cpu_to_le16(conf->per_th1);
+ acx->per_th2 = cpu_to_le16(conf->per_th2);
+ acx->max_per = cpu_to_le16(conf->max_per);
+ acx->inverse_curiosity_factor = conf->inverse_curiosity_factor;
+ acx->tx_fail_low_th = conf->tx_fail_low_th;
+ acx->tx_fail_high_th = conf->tx_fail_high_th;
+ acx->per_alpha_shift = conf->per_alpha_shift;
+ acx->per_add_shift = conf->per_add_shift;
+ acx->per_beta1_shift = conf->per_beta1_shift;
+ acx->per_beta2_shift = conf->per_beta2_shift;
+ acx->rate_check_up = conf->rate_check_up;
+ acx->rate_check_down = conf->rate_check_down;
+ memcpy(acx->rate_retry_policy, conf->rate_retry_policy,
+ sizeof(acx->rate_retry_policy));
+
+ ret = wl1271_cmd_configure(wl, ACX_SET_RATE_MGMT_PARAMS,
+ acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx set rate mgmt params failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl12xx_acx_config_hangover(struct wl1271 *wl)
+{
+ struct wl12xx_acx_config_hangover *acx;
+ struct conf_hangover_settings *conf = &wl->conf.hangover;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx config hangover");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->recover_time = cpu_to_le32(conf->recover_time);
+ acx->hangover_period = conf->hangover_period;
+ acx->dynamic_mode = conf->dynamic_mode;
+ acx->early_termination_mode = conf->early_termination_mode;
+ acx->max_period = conf->max_period;
+ acx->min_period = conf->min_period;
+ acx->increase_delta = conf->increase_delta;
+ acx->decrease_delta = conf->decrease_delta;
+ acx->quiet_time = conf->quiet_time;
+ acx->increase_time = conf->increase_time;
+ acx->window_size = acx->window_size;
+
+ ret = wl1271_cmd_configure(wl, ACX_CONFIG_HANGOVER, acx,
+ sizeof(*acx));
+
+ if (ret < 0) {
+ wl1271_warning("acx config hangover failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+
+}
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index d2eb86eccc04..e3f93b4b3429 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -101,6 +101,17 @@ struct acx_error_counter {
__le32 seq_num_miss;
} __packed;
+enum wl12xx_role {
+ WL1271_ROLE_STA = 0,
+ WL1271_ROLE_IBSS,
+ WL1271_ROLE_AP,
+ WL1271_ROLE_DEVICE,
+ WL1271_ROLE_P2P_CL,
+ WL1271_ROLE_P2P_GO,
+
+ WL12XX_INVALID_ROLE_TYPE = 0xff
+};
+
enum wl1271_psm_mode {
/* Active mode */
WL1271_PSM_CAM = 0,
@@ -160,94 +171,6 @@ struct acx_rx_msdu_lifetime {
__le32 lifetime;
} __packed;
-/*
- * RX Config Options Table
- * Bit Definition
- * === ==========
- * 31:14 Reserved
- * 13 Copy RX Status - when set, write three receive status words
- * to top of rx'd MPDUs.
- * When cleared, do not write three status words (added rev 1.5)
- * 12 Reserved
- * 11 RX Complete upon FCS error - when set, give rx complete
- * interrupt for FCS errors, after the rx filtering, e.g. unicast
- * frames not to us with FCS error will not generate an interrupt.
- * 10 SSID Filter Enable - When set, the WiLink discards all beacon,
- * probe request, and probe response frames with an SSID that does
- * not match the SSID specified by the host in the START/JOIN
- * command.
- * When clear, the WiLink receives frames with any SSID.
- * 9 Broadcast Filter Enable - When set, the WiLink discards all
- * broadcast frames. When clear, the WiLink receives all received
- * broadcast frames.
- * 8:6 Reserved
- * 5 BSSID Filter Enable - When set, the WiLink discards any frames
- * with a BSSID that does not match the BSSID specified by the
- * host.
- * When clear, the WiLink receives frames from any BSSID.
- * 4 MAC Addr Filter - When set, the WiLink discards any frames
- * with a destination address that does not match the MAC address
- * of the adaptor.
- * When clear, the WiLink receives frames destined to any MAC
- * address.
- * 3 Promiscuous - When set, the WiLink receives all valid frames
- * (i.e., all frames that pass the FCS check).
- * When clear, only frames that pass the other filters specified
- * are received.
- * 2 FCS - When set, the WiLink includes the FCS with the received
- * frame.
- * When cleared, the FCS is discarded.
- * 1 PLCP header - When set, write all data from baseband to frame
- * buffer including PHY header.
- * 0 Reserved - Always equal to 0.
- *
- * RX Filter Options Table
- * Bit Definition
- * === ==========
- * 31:12 Reserved - Always equal to 0.
- * 11 Association - When set, the WiLink receives all association
- * related frames (association request/response, reassocation
- * request/response, and disassociation). When clear, these frames
- * are discarded.
- * 10 Auth/De auth - When set, the WiLink receives all authentication
- * and de-authentication frames. When clear, these frames are
- * discarded.
- * 9 Beacon - When set, the WiLink receives all beacon frames.
- * When clear, these frames are discarded.
- * 8 Contention Free - When set, the WiLink receives all contention
- * free frames.
- * When clear, these frames are discarded.
- * 7 Control - When set, the WiLink receives all control frames.
- * When clear, these frames are discarded.
- * 6 Data - When set, the WiLink receives all data frames.
- * When clear, these frames are discarded.
- * 5 FCS Error - When set, the WiLink receives frames that have FCS
- * errors.
- * When clear, these frames are discarded.
- * 4 Management - When set, the WiLink receives all management
- * frames.
- * When clear, these frames are discarded.
- * 3 Probe Request - When set, the WiLink receives all probe request
- * frames.
- * When clear, these frames are discarded.
- * 2 Probe Response - When set, the WiLink receives all probe
- * response frames.
- * When clear, these frames are discarded.
- * 1 RTS/CTS/ACK - When set, the WiLink receives all RTS, CTS and ACK
- * frames.
- * When clear, these frames are discarded.
- * 0 Rsvd Type/Sub Type - When set, the WiLink receives all frames
- * that have reserved frame types and sub types as defined by the
- * 802.11 specification.
- * When clear, these frames are discarded.
- */
-struct acx_rx_config {
- struct acx_header header;
-
- __le32 config_options;
- __le32 filter_options;
-} __packed;
-
struct acx_packet_detection {
struct acx_header header;
@@ -267,9 +190,10 @@ enum acx_slot_type {
struct acx_slot {
struct acx_header header;
+ u8 role_id;
u8 wone_index; /* Reserved */
u8 slot_time;
- u8 reserved[6];
+ u8 reserved[5];
} __packed;
@@ -279,29 +203,35 @@ struct acx_slot {
struct acx_dot11_grp_addr_tbl {
struct acx_header header;
+ u8 role_id;
u8 enabled;
u8 num_groups;
- u8 pad[2];
+ u8 pad[1];
u8 mac_table[ADDRESS_GROUP_MAX_LEN];
} __packed;
struct acx_rx_timeout {
struct acx_header header;
+ u8 role_id;
+ u8 reserved;
__le16 ps_poll_timeout;
__le16 upsd_timeout;
+ u8 padding[2];
} __packed;
struct acx_rts_threshold {
struct acx_header header;
+ u8 role_id;
+ u8 reserved;
__le16 threshold;
- u8 pad[2];
} __packed;
struct acx_beacon_filter_option {
struct acx_header header;
+ u8 role_id;
u8 enable;
/*
* The number of beacons without the unicast TIM
@@ -311,7 +241,7 @@ struct acx_beacon_filter_option {
* without the unicast TIM bit set are dropped.
*/
u8 max_num_beacons;
- u8 pad[2];
+ u8 pad[1];
} __packed;
/*
@@ -350,14 +280,17 @@ struct acx_beacon_filter_option {
struct acx_beacon_filter_ie_table {
struct acx_header header;
+ u8 role_id;
u8 num_ie;
- u8 pad[3];
+ u8 pad[2];
u8 table[BEACON_FILTER_TABLE_MAX_SIZE];
} __packed;
struct acx_conn_monit_params {
struct acx_header header;
+ u8 role_id;
+ u8 padding[3];
__le32 synch_fail_thold; /* number of beacons missed */
__le32 bss_lose_timeout; /* number of TU's from synch fail */
} __packed;
@@ -369,23 +302,14 @@ struct acx_bt_wlan_coex {
u8 pad[3];
} __packed;
-struct acx_sta_bt_wlan_coex_param {
- struct acx_header header;
-
- __le32 params[CONF_SG_STA_PARAMS_MAX];
- u8 param_idx;
- u8 padding[3];
-} __packed;
-
-struct acx_ap_bt_wlan_coex_param {
+struct acx_bt_wlan_coex_param {
struct acx_header header;
- __le32 params[CONF_SG_AP_PARAMS_MAX];
+ __le32 params[CONF_SG_PARAMS_MAX];
u8 param_idx;
u8 padding[3];
} __packed;
-
struct acx_dco_itrim_params {
struct acx_header header;
@@ -406,15 +330,16 @@ struct acx_energy_detection {
struct acx_beacon_broadcast {
struct acx_header header;
- __le16 beacon_rx_timeout;
- __le16 broadcast_timeout;
-
+ u8 role_id;
/* Enables receiving of broadcast packets in PS mode */
u8 rx_broadcast_in_ps;
+ __le16 beacon_rx_timeout;
+ __le16 broadcast_timeout;
+
/* Consecutive PS Poll failures before updating the host */
u8 ps_poll_threshold;
- u8 pad[2];
+ u8 pad[1];
} __packed;
struct acx_event_mask {
@@ -424,35 +349,6 @@ struct acx_event_mask {
__le32 high_event_mask; /* Unused */
} __packed;
-#define CFG_RX_FCS BIT(2)
-#define CFG_RX_ALL_GOOD BIT(3)
-#define CFG_UNI_FILTER_EN BIT(4)
-#define CFG_BSSID_FILTER_EN BIT(5)
-#define CFG_MC_FILTER_EN BIT(6)
-#define CFG_MC_ADDR0_EN BIT(7)
-#define CFG_MC_ADDR1_EN BIT(8)
-#define CFG_BC_REJECT_EN BIT(9)
-#define CFG_SSID_FILTER_EN BIT(10)
-#define CFG_RX_INT_FCS_ERROR BIT(11)
-#define CFG_RX_INT_ENCRYPTED BIT(12)
-#define CFG_RX_WR_RX_STATUS BIT(13)
-#define CFG_RX_FILTER_NULTI BIT(14)
-#define CFG_RX_RESERVE BIT(15)
-#define CFG_RX_TIMESTAMP_TSF BIT(16)
-
-#define CFG_RX_RSV_EN BIT(0)
-#define CFG_RX_RCTS_ACK BIT(1)
-#define CFG_RX_PRSP_EN BIT(2)
-#define CFG_RX_PREQ_EN BIT(3)
-#define CFG_RX_MGMT_EN BIT(4)
-#define CFG_RX_FCS_ERROR BIT(5)
-#define CFG_RX_DATA_EN BIT(6)
-#define CFG_RX_CTL_EN BIT(7)
-#define CFG_RX_CF_EN BIT(8)
-#define CFG_RX_BCN_EN BIT(9)
-#define CFG_RX_AUTH_EN BIT(10)
-#define CFG_RX_ASSOC_EN BIT(11)
-
#define SCAN_PASSIVE BIT(0)
#define SCAN_5GHZ_BAND BIT(1)
#define SCAN_TRIGGERED BIT(2)
@@ -465,6 +361,8 @@ struct acx_event_mask {
struct acx_feature_config {
struct acx_header header;
+ u8 role_id;
+ u8 padding[3];
__le32 options;
__le32 data_flow_options;
} __packed;
@@ -472,16 +370,18 @@ struct acx_feature_config {
struct acx_current_tx_power {
struct acx_header header;
+ u8 role_id;
u8 current_tx_power;
- u8 padding[3];
+ u8 padding[2];
} __packed;
struct acx_wake_up_condition {
struct acx_header header;
+ u8 role_id;
u8 wake_up_event; /* Only one bit can be set */
u8 listen_interval;
- u8 pad[2];
+ u8 pad[1];
} __packed;
struct acx_aid {
@@ -490,8 +390,9 @@ struct acx_aid {
/*
* To be set when associated with an AP.
*/
+ u8 role_id;
+ u8 reserved;
__le16 aid;
- u8 pad[2];
} __packed;
enum acx_preamble_type {
@@ -506,8 +407,9 @@ struct acx_preamble {
* When set, the WiLink transmits the frames with a short preamble and
* when cleared, the WiLink transmits the frames with a long preamble.
*/
+ u8 role_id;
u8 preamble;
- u8 padding[3];
+ u8 padding[2];
} __packed;
enum acx_ctsprotect_type {
@@ -517,8 +419,9 @@ enum acx_ctsprotect_type {
struct acx_ctsprotect {
struct acx_header header;
+ u8 role_id;
u8 ctsprotect;
- u8 padding[3];
+ u8 padding[2];
} __packed;
struct acx_tx_statistics {
@@ -753,18 +656,10 @@ struct acx_rate_class {
#define ACX_TX_BASIC_RATE 0
#define ACX_TX_AP_FULL_RATE 1
-#define ACX_TX_RATE_POLICY_CNT 2
-struct acx_sta_rate_policy {
- struct acx_header header;
-
- __le32 rate_class_cnt;
- struct acx_rate_class rate_class[CONF_TX_MAX_RATE_CLASSES];
-} __packed;
-
-
+#define ACX_TX_BASIC_RATE_P2P 2
#define ACX_TX_AP_MODE_MGMT_RATE 4
#define ACX_TX_AP_MODE_BCST_RATE 5
-struct acx_ap_rate_policy {
+struct acx_rate_policy {
struct acx_header header;
__le32 rate_policy_idx;
@@ -773,22 +668,23 @@ struct acx_ap_rate_policy {
struct acx_ac_cfg {
struct acx_header header;
+ u8 role_id;
u8 ac;
+ u8 aifsn;
u8 cw_min;
__le16 cw_max;
- u8 aifsn;
- u8 reserved;
__le16 tx_op_limit;
} __packed;
struct acx_tid_config {
struct acx_header header;
+ u8 role_id;
u8 queue_id;
u8 channel_type;
u8 tsid;
u8 ps_scheme;
u8 ack_policy;
- u8 padding[3];
+ u8 padding[2];
__le32 apsd_conf[2];
} __packed;
@@ -804,19 +700,7 @@ struct acx_tx_config_options {
__le16 tx_compl_threshold; /* number of packets */
} __packed;
-#define ACX_TX_DESCRIPTORS 32
-
-struct wl1271_acx_ap_config_memory {
- struct acx_header header;
-
- u8 rx_mem_block_num;
- u8 tx_min_mem_block_num;
- u8 num_stations;
- u8 num_ssid_profiles;
- __le32 total_tx_descriptors;
-} __packed;
-
-struct wl1271_acx_sta_config_memory {
+struct wl12xx_acx_config_memory {
struct acx_header header;
u8 rx_mem_block_num;
@@ -890,9 +774,10 @@ struct wl1271_acx_rx_config_opt {
struct wl1271_acx_bet_enable {
struct acx_header header;
+ u8 role_id;
u8 enable;
u8 max_consecutive;
- u8 padding[2];
+ u8 padding[1];
} __packed;
#define ACX_IPV4_VERSION 4
@@ -905,9 +790,10 @@ struct wl1271_acx_bet_enable {
struct wl1271_acx_arp_filter {
struct acx_header header;
+ u8 role_id;
u8 version; /* ACX_IPV4_VERSION, ACX_IPV6_VERSION */
u8 enable; /* bitmap of enabled ARP filtering features */
- u8 padding[2];
+ u8 padding[1];
u8 address[16]; /* The configured device IP address - all ARP
requests directed to this IP address will pass
through. For IPv4, the first four bytes are
@@ -925,8 +811,9 @@ struct wl1271_acx_pm_config {
struct wl1271_acx_keep_alive_mode {
struct acx_header header;
+ u8 role_id;
u8 enabled;
- u8 padding[3];
+ u8 padding[2];
} __packed;
enum {
@@ -942,11 +829,11 @@ enum {
struct wl1271_acx_keep_alive_config {
struct acx_header header;
- __le32 period;
+ u8 role_id;
u8 index;
u8 tpl_validation;
u8 trigger;
- u8 padding;
+ __le32 period;
} __packed;
#define HOST_IF_CFG_RX_FIFO_ENABLE BIT(0)
@@ -990,26 +877,33 @@ enum {
struct wl1271_acx_rssi_snr_trigger {
struct acx_header header;
- __le16 threshold;
- __le16 pacing; /* 0 - 60000 ms */
+ u8 role_id;
u8 metric;
u8 type;
u8 dir;
+ __le16 threshold;
+ __le16 pacing; /* 0 - 60000 ms */
u8 hysteresis;
u8 index;
u8 enable;
- u8 padding[2];
+ u8 padding[1];
};
struct wl1271_acx_rssi_snr_avg_weights {
struct acx_header header;
+ u8 role_id;
+ u8 padding[3];
u8 rssi_beacon;
u8 rssi_data;
u8 snr_beacon;
u8 snr_data;
};
+
+/* special capability bit (not employed by the 802.11n spec) */
+#define WL12XX_HT_CAP_HT_OPERATION BIT(16)
+
/*
* ACX_PEER_HT_CAP
* Configure HT capabilities - declare the capabilities of the peer
@@ -1018,28 +912,11 @@ struct wl1271_acx_rssi_snr_avg_weights {
struct wl1271_acx_ht_capabilities {
struct acx_header header;
- /*
- * bit 0 - Allow HT Operation
- * bit 1 - Allow Greenfield format in TX
- * bit 2 - Allow Short GI in TX
- * bit 3 - Allow L-SIG TXOP Protection in TX
- * bit 4 - Allow HT Control fields in TX.
- * Note, driver will still leave space for HT control in packets
- * regardless of the value of this field. FW will be responsible
- * to drop the HT field from any frame when this Bit set to 0.
- * bit 5 - Allow RD initiation in TXOP. FW is allowed to initate RD.
- * Exact policy setting for this feature is TBD.
- * Note, this bit can only be set to 1 if bit 3 is set to 1.
- */
+ /* bitmask of capability bits supported by the peer */
__le32 ht_capabilites;
- /*
- * Indicates to which peer these capabilities apply.
- * For infrastructure use ff:ff:ff:ff:ff:ff that indicates relevance
- * for all peers.
- * Only valid for IBSS/DLS operation.
- */
- u8 mac_address[ETH_ALEN];
+ /* Indicates to which link these capabilities apply. */
+ u8 hlid;
/*
* This the maximum A-MPDU length supported by the AP. The FW may not
@@ -1049,16 +926,9 @@ struct wl1271_acx_ht_capabilities {
/* This is the minimal spacing required when sending A-MPDUs to the AP*/
u8 ampdu_min_spacing;
-} __packed;
-
-/* HT Capabilites Fw Bit Mask Mapping */
-#define WL1271_ACX_FW_CAP_HT_OPERATION BIT(0)
-#define WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT BIT(1)
-#define WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS BIT(2)
-#define WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION BIT(3)
-#define WL1271_ACX_FW_CAP_HT_CONTROL_FIELDS BIT(4)
-#define WL1271_ACX_FW_CAP_RD_INITIATION BIT(5)
+ u8 padding;
+} __packed;
/*
* ACX_HT_BSS_OPERATION
@@ -1067,6 +937,8 @@ struct wl1271_acx_ht_capabilities {
struct wl1271_acx_ht_information {
struct acx_header header;
+ u8 role_id;
+
/* Values: 0 - RIFS not allowed, 1 - RIFS allowed */
u8 rifs_mode;
@@ -1088,60 +960,51 @@ struct wl1271_acx_ht_information {
*/
u8 dual_cts_protection;
- u8 padding[3];
+ u8 padding[2];
} __packed;
-#define RX_BA_WIN_SIZE 8
+#define RX_BA_MAX_SESSIONS 2
-struct wl1271_acx_ba_session_policy {
+struct wl1271_acx_ba_initiator_policy {
struct acx_header header;
- /*
- * Specifies role Id, Range 0-7, 0xFF means ANY role.
- * Future use. For now this field is irrelevant
- */
+
+ /* Specifies role Id, Range 0-7, 0xFF means ANY role. */
u8 role_id;
+
/*
- * Specifies Link Id, Range 0-31, 0xFF means ANY Link Id.
- * Not applicable if Role Id is set to ANY.
+ * Per TID setting for allowing TX BA. Set a bit to 1 to allow
+ * TX BA sessions for the corresponding TID.
*/
- u8 link_id;
-
- u8 tid;
-
- u8 enable;
+ u8 tid_bitmap;
/* Windows size in number of packets */
- u16 win_size;
+ u8 win_size;
- /*
- * As initiator inactivity timeout in time units(TU) of 1024us.
- * As receiver reserved
- */
- u16 inactivity_timeout;
+ u8 padding1[1];
- /* Initiator = 1/Receiver = 0 */
- u8 ba_direction;
+ /* As initiator inactivity timeout in time units(TU) of 1024us */
+ u16 inactivity_timeout;
- u8 padding[3];
+ u8 padding[2];
} __packed;
struct wl1271_acx_ba_receiver_setup {
struct acx_header header;
- /* Specifies Link Id, Range 0-31, 0xFF means ANY Link Id */
- u8 link_id;
+ /* Specifies link id, range 0-31 */
+ u8 hlid;
u8 tid;
u8 enable;
- u8 padding[1];
-
/* Windows size in number of packets */
- u16 win_size;
+ u8 win_size;
/* BA session starting sequence number. RANGE 0-FFF */
u16 ssn;
+
+ u8 padding[2];
} __packed;
struct wl1271_acx_fw_tsf_information {
@@ -1158,6 +1021,7 @@ struct wl1271_acx_fw_tsf_information {
struct wl1271_acx_ps_rx_streaming {
struct acx_header header;
+ u8 role_id;
u8 tid;
u8 enable;
@@ -1166,17 +1030,20 @@ struct wl1271_acx_ps_rx_streaming {
/* timeout before first trigger (0-200 msec) */
u8 timeout;
+ u8 padding[3];
} __packed;
struct wl1271_acx_ap_max_tx_retry {
struct acx_header header;
+ u8 role_id;
+ u8 padding_1;
+
/*
* the number of frames transmission failures before
* issuing the aging event.
*/
__le16 max_tx_retry;
- u8 padding_1[2];
} __packed;
struct wl1271_acx_config_ps {
@@ -1195,13 +1062,6 @@ struct wl1271_acx_inconnection_sta {
u8 padding1[2];
} __packed;
-struct acx_ap_beacon_filter {
- struct acx_header header;
-
- u8 enable;
- u8 pad[3];
-} __packed;
-
/*
* ACX_FM_COEX_CFG
* set the FM co-existence parameters.
@@ -1261,6 +1121,47 @@ struct wl1271_acx_fm_coex {
u8 swallow_clk_diff;
} __packed;
+#define ACX_RATE_MGMT_ALL_PARAMS 0xff
+struct wl12xx_acx_set_rate_mgmt_params {
+ struct acx_header header;
+
+ u8 index; /* 0xff to configure all params */
+ u8 padding1;
+ __le16 rate_retry_score;
+ __le16 per_add;
+ __le16 per_th1;
+ __le16 per_th2;
+ __le16 max_per;
+ u8 inverse_curiosity_factor;
+ u8 tx_fail_low_th;
+ u8 tx_fail_high_th;
+ u8 per_alpha_shift;
+ u8 per_add_shift;
+ u8 per_beta1_shift;
+ u8 per_beta2_shift;
+ u8 rate_check_up;
+ u8 rate_check_down;
+ u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES];
+ u8 padding2[2];
+} __packed;
+
+struct wl12xx_acx_config_hangover {
+ struct acx_header header;
+
+ __le32 recover_time;
+ u8 hangover_period;
+ u8 dynamic_mode;
+ u8 early_termination_mode;
+ u8 max_period;
+ u8 min_period;
+ u8 increase_delta;
+ u8 decrease_delta;
+ u8 quiet_time;
+ u8 increase_time;
+ u8 window_size;
+ u8 padding[2];
+} __packed;
+
enum {
ACX_WAKE_UP_CONDITIONS = 0x0002,
ACX_MEM_CFG = 0x0003,
@@ -1268,10 +1169,7 @@ enum {
ACX_AC_CFG = 0x0007,
ACX_MEM_MAP = 0x0008,
ACX_AID = 0x000A,
- /* ACX_FW_REV is missing in the ref driver, but seems to work */
- ACX_FW_REV = 0x000D,
ACX_MEDIUM_USAGE = 0x000F,
- ACX_RX_CFG = 0x0010,
ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */
ACX_STATISTICS = 0x0013, /* Debug API */
ACX_PWR_CONSUMPTION_STATISTICS = 0x0014,
@@ -1279,7 +1177,6 @@ enum {
ACX_TID_CFG = 0x001A,
ACX_PS_RX_STREAMING = 0x001B,
ACX_BEACON_FILTER_OPT = 0x001F,
- ACX_AP_BEACON_FILTER_OPT = 0x0020,
ACX_NOISE_HIST = 0x0021,
ACX_HDK_VERSION = 0x0022, /* ??? */
ACX_PD_THRESHOLD = 0x0023,
@@ -1287,7 +1184,6 @@ enum {
ACX_CCA_THRESHOLD = 0x0025,
ACX_EVENT_MBOX_MASK = 0x0026,
ACX_CONN_MONIT_PARAMS = 0x002D,
- ACX_CONS_TX_FAILURE = 0x002F,
ACX_BCN_DTIM_OPTIONS = 0x0031,
ACX_SG_ENABLE = 0x0032,
ACX_SG_CFG = 0x0033,
@@ -1314,11 +1210,14 @@ enum {
ACX_RSSI_SNR_WEIGHTS = 0x0052,
ACX_KEEP_ALIVE_MODE = 0x0053,
ACX_SET_KEEP_ALIVE_CONFIG = 0x0054,
- ACX_BA_SESSION_POLICY_CFG = 0x0055,
+ 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,
@@ -1342,7 +1241,6 @@ int wl1271_acx_feature_cfg(struct wl1271 *wl);
int wl1271_acx_mem_map(struct wl1271 *wl,
struct acx_header *mem_map, size_t len);
int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl);
-int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter);
int wl1271_acx_pd_threshold(struct wl1271 *wl);
int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time);
int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable,
@@ -1354,8 +1252,7 @@ int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter);
int wl1271_acx_beacon_filter_table(struct wl1271 *wl);
int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable);
int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable);
-int wl1271_acx_sta_sg_cfg(struct wl1271 *wl);
-int wl1271_acx_ap_sg_cfg(struct wl1271 *wl);
+int wl12xx_acx_sg_cfg(struct wl1271 *wl);
int wl1271_acx_cca_threshold(struct wl1271 *wl);
int wl1271_acx_bcn_dtim_options(struct wl1271 *wl);
int wl1271_acx_aid(struct wl1271 *wl, u16 aid);
@@ -1374,8 +1271,7 @@ int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
u32 apsd_conf0, u32 apsd_conf1);
int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold);
int wl1271_acx_tx_config_options(struct wl1271 *wl);
-int wl1271_acx_ap_mem_cfg(struct wl1271 *wl);
-int wl1271_acx_sta_mem_cfg(struct wl1271 *wl);
+int wl12xx_acx_mem_cfg(struct wl1271 *wl);
int wl1271_acx_init_mem_config(struct wl1271 *wl);
int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap);
int wl1271_acx_init_rx_interrupt(struct wl1271 *wl);
@@ -1390,20 +1286,19 @@ int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl);
int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
struct ieee80211_sta_ht_cap *ht_cap,
- bool allow_ht_operation);
+ bool allow_ht_operation, u8 hlid);
int wl1271_acx_set_ht_information(struct wl1271 *wl,
u16 ht_operation_mode);
-int wl1271_acx_set_ba_session(struct wl1271 *wl,
- enum ieee80211_back_parties direction,
- u8 tid_index, u8 policy);
-int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
- bool enable);
+int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl);
+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 wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable);
int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl);
int wl1271_acx_config_ps(struct wl1271 *wl);
int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
-int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable);
int wl1271_acx_fm_coex(struct wl1271 *wl);
+int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl);
+int wl12xx_acx_config_hangover(struct wl1271 *wl);
#endif /* __WL1271_ACX_H__ */
diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c
index 5ebc64d89407..d4e628db76b0 100644
--- a/drivers/net/wireless/wl12xx/boot.c
+++ b/drivers/net/wireless/wl12xx/boot.c
@@ -107,16 +107,6 @@ static unsigned int wl12xx_get_fw_ver_quirks(struct wl1271 *wl)
unsigned int quirks = 0;
unsigned int *fw_ver = wl->chip.fw_ver;
- /* Only for wl127x */
- if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
- /* Check STA version */
- (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
- (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
- /* Check AP version */
- ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
- (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
- quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
-
/* Only new station firmwares support routing fw logs to the host */
if ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
(fw_ver[FW_VER_MINOR] < FW_VER_MINOR_FWLOG_STA_MIN))
@@ -304,9 +294,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
*/
if (wl->nvs_len == sizeof(struct wl1271_nvs_file) ||
wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) {
- /* for now 11a is unsupported in AP mode */
- if (wl->bss_type != BSS_TYPE_AP_BSS &&
- nvs->general_params.dual_mode_select)
+ if (nvs->general_params.dual_mode_select)
wl->enable_11a = true;
}
@@ -504,21 +492,19 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
wl->event_mask = BSS_LOSE_EVENT_ID |
SCAN_COMPLETE_EVENT_ID |
PS_REPORT_EVENT_ID |
- JOIN_EVENT_COMPLETE_ID |
DISCONNECT_EVENT_COMPLETE_ID |
RSSI_SNR_TRIGGER_0_EVENT_ID |
PSPOLL_DELIVERY_FAILURE_EVENT_ID |
SOFT_GEMINI_SENSE_EVENT_ID |
PERIODIC_SCAN_REPORT_EVENT_ID |
- PERIODIC_SCAN_COMPLETE_EVENT_ID;
-
- if (wl->bss_type == BSS_TYPE_AP_BSS)
- wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID |
- INACTIVE_STA_EVENT_ID |
- MAX_TX_RETRY_EVENT_ID;
- else
- wl->event_mask |= DUMMY_PACKET_EVENT_ID |
- BA_SESSION_RX_CONSTRAINT_EVENT_ID;
+ PERIODIC_SCAN_COMPLETE_EVENT_ID |
+ DUMMY_PACKET_EVENT_ID |
+ PEER_REMOVE_COMPLETE_EVENT_ID |
+ BA_SESSION_RX_CONSTRAINT_EVENT_ID |
+ REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID |
+ INACTIVE_STA_EVENT_ID |
+ MAX_TX_RETRY_EVENT_ID |
+ CHANNEL_SWITCH_COMPLETE_EVENT_ID;
ret = wl1271_event_unmask(wl);
if (ret < 0) {
@@ -549,13 +535,13 @@ static void wl1271_boot_hw_version(struct wl1271 *wl)
{
u32 fuse;
- fuse = wl1271_top_reg_read(wl, REG_FUSE_DATA_2_1);
+ 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;
-
- if (((wl->hw_pg_ver & PG_MAJOR_VER_MASK) >> PG_MAJOR_VER_OFFSET) < 3)
- wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
}
static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl)
@@ -696,7 +682,8 @@ static int wl127x_boot_clk(struct wl1271 *wl)
u32 pause;
u32 clk;
- wl1271_boot_hw_version(wl);
+ if (((wl->hw_pg_ver & PG_MAJOR_VER_MASK) >> PG_MAJOR_VER_OFFSET) < 3)
+ wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
if (wl->ref_clock == CONF_REF_CLK_19_2_E ||
wl->ref_clock == CONF_REF_CLK_38_4_E ||
@@ -750,6 +737,8 @@ 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)
@@ -781,9 +770,6 @@ int wl1271_load_firmware(struct wl1271 *wl)
clk |= (wl->ref_clock << 1) << 4;
}
- if (wl->quirks & WL12XX_QUIRK_LPD_MODE)
- clk |= SCRATCH_ENABLE_LPD;
-
wl1271_write32(wl, DRPW_SCRATCH_START, clk);
wl1271_set_partition(wl, &part_table[PART_WORK]);
@@ -852,9 +838,6 @@ int wl1271_boot(struct wl1271 *wl)
/* Enable firmware interrupts now */
wl1271_boot_enable_interrupts(wl);
- /* set the wl1271 default filters */
- wl1271_set_default_filters(wl);
-
wl1271_event_mbox_config(wl);
out:
diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/boot.h
index e8f8255bbabe..06dad9380fa7 100644
--- a/drivers/net/wireless/wl12xx/boot.h
+++ b/drivers/net/wireless/wl12xx/boot.h
@@ -55,7 +55,8 @@ struct wl1271_static_data {
#define OCP_REG_CLK_POLARITY 0x0cb2
#define OCP_REG_CLK_PULL 0x0cb4
-#define REG_FUSE_DATA_2_1 0x050a
+#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
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 97dd237a9580..a52299e548fa 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -134,11 +134,6 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
/* Override the REF CLK from the NVS with the one from platform data */
gen_parms->general_params.ref_clock = wl->ref_clock;
- /* LPD mode enable (bits 6-7) in WL1271 AP mode only */
- if (wl->quirks & WL12XX_QUIRK_LPD_MODE)
- gen_parms->general_params.general_settings |=
- GENERAL_SETTINGS_DRPW_LPD;
-
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
if (ret < 0) {
wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
@@ -363,63 +358,476 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
return 0;
}
-int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
+int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 role_type, u8 *role_id)
{
- struct wl1271_cmd_join *join;
- int ret, i;
- u8 *bssid;
+ struct wl12xx_cmd_role_enable *cmd;
+ int ret;
+
+ wl1271_debug(DEBUG_CMD, "cmd role enable");
+
+ if (WARN_ON(*role_id != WL12XX_INVALID_ROLE_ID))
+ return -EBUSY;
- join = kzalloc(sizeof(*join), GFP_KERNEL);
- if (!join) {
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
ret = -ENOMEM;
goto out;
}
- wl1271_debug(DEBUG_CMD, "cmd join");
+ /* get role id */
+ cmd->role_id = find_first_zero_bit(wl->roles_map, WL12XX_MAX_ROLES);
+ if (cmd->role_id >= WL12XX_MAX_ROLES) {
+ ret = -EBUSY;
+ goto out_free;
+ }
+
+ memcpy(cmd->mac_address, wl->mac_addr, ETH_ALEN);
+ cmd->role_type = role_type;
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_ENABLE, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role enable");
+ goto out_free;
+ }
+
+ __set_bit(cmd->role_id, wl->roles_map);
+ *role_id = cmd->role_id;
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
+
+int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id)
+{
+ struct wl12xx_cmd_role_disable *cmd;
+ int ret;
+
+ wl1271_debug(DEBUG_CMD, "cmd role disable");
+
+ if (WARN_ON(*role_id == WL12XX_INVALID_ROLE_ID))
+ return -ENOENT;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ cmd->role_id = *role_id;
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_DISABLE, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role disable");
+ goto out_free;
+ }
+
+ __clear_bit(*role_id, wl->roles_map);
+ *role_id = WL12XX_INVALID_ROLE_ID;
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
+
+static int wl12xx_allocate_link(struct wl1271 *wl, u8 *hlid)
+{
+ u8 link = find_first_zero_bit(wl->links_map, WL12XX_MAX_LINKS);
+ if (link >= WL12XX_MAX_LINKS)
+ return -EBUSY;
+
+ __set_bit(link, wl->links_map);
+ *hlid = link;
+ return 0;
+}
+
+static void wl12xx_free_link(struct wl1271 *wl, u8 *hlid)
+{
+ if (*hlid == WL12XX_INVALID_LINK_ID)
+ return;
+
+ __clear_bit(*hlid, wl->links_map);
+ *hlid = WL12XX_INVALID_LINK_ID;
+}
+
+static int wl12xx_get_new_session_id(struct wl1271 *wl)
+{
+ if (wl->session_counter >= SESSION_COUNTER_MAX)
+ wl->session_counter = 0;
+
+ wl->session_counter++;
+
+ return wl->session_counter;
+}
- /* Reverse order BSSID */
- bssid = (u8 *) &join->bssid_lsb;
- for (i = 0; i < ETH_ALEN; i++)
- bssid[i] = wl->bssid[ETH_ALEN - i - 1];
+int wl12xx_cmd_role_start_dev(struct wl1271 *wl)
+{
+ struct wl12xx_cmd_role_start *cmd;
+ int ret;
- join->rx_config_options = cpu_to_le32(wl->rx_config);
- join->rx_filter_options = cpu_to_le32(wl->rx_filter);
- join->bss_type = bss_type;
- join->basic_rate_set = cpu_to_le32(wl->basic_rate_set);
- join->supported_rate_set = cpu_to_le32(wl->rate_set);
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ wl1271_debug(DEBUG_CMD, "cmd role start dev %d", wl->dev_role_id);
+
+ cmd->role_id = wl->dev_role_id;
if (wl->band == IEEE80211_BAND_5GHZ)
- join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ;
+ cmd->band = WL12XX_BAND_5GHZ;
+ cmd->channel = wl->channel;
+
+ if (wl->dev_hlid == WL12XX_INVALID_LINK_ID) {
+ ret = wl12xx_allocate_link(wl, &wl->dev_hlid);
+ if (ret)
+ goto out_free;
+ }
+ cmd->device.hlid = wl->dev_hlid;
+ cmd->device.session = wl->session_counter;
- join->beacon_interval = cpu_to_le16(wl->beacon_int);
- join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD;
+ wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d",
+ cmd->role_id, cmd->device.hlid, cmd->device.session);
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role enable");
+ goto err_hlid;
+ }
- join->channel = wl->channel;
- join->ssid_len = wl->ssid_len;
- memcpy(join->ssid, wl->ssid, wl->ssid_len);
+ goto out_free;
- join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET;
+err_hlid:
+ /* clear links on error */
+ __clear_bit(wl->dev_hlid, wl->links_map);
+ wl->dev_hlid = WL12XX_INVALID_LINK_ID;
- wl1271_debug(DEBUG_CMD, "cmd join: basic_rate_set=0x%x, rate_set=0x%x",
- join->basic_rate_set, join->supported_rate_set);
- ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join), 0);
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
+
+int wl12xx_cmd_role_stop_dev(struct wl1271 *wl)
+{
+ struct wl12xx_cmd_role_stop *cmd;
+ int ret;
+
+ if (WARN_ON(wl->dev_hlid == WL12XX_INVALID_LINK_ID))
+ return -EINVAL;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1271_debug(DEBUG_CMD, "cmd role stop dev");
+
+ cmd->role_id = wl->dev_role_id;
+ cmd->disc_type = DISCONNECT_IMMEDIATE;
+ cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED);
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role stop");
+ goto out_free;
+ }
+
+ ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID);
if (ret < 0) {
- wl1271_error("failed to initiate cmd join");
+ wl1271_error("cmd role stop dev event completion error");
goto out_free;
}
- ret = wl1271_cmd_wait_for_event(wl, JOIN_EVENT_COMPLETE_ID);
+ wl12xx_free_link(wl, &wl->dev_hlid);
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
+
+int wl12xx_cmd_role_start_sta(struct wl1271 *wl)
+{
+ struct wl12xx_cmd_role_start *cmd;
+ int ret;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1271_debug(DEBUG_CMD, "cmd role start sta %d", wl->role_id);
+
+ cmd->role_id = wl->role_id;
+ if (wl->band == IEEE80211_BAND_5GHZ)
+ cmd->band = WL12XX_BAND_5GHZ;
+ cmd->channel = wl->channel;
+ cmd->sta.basic_rate_set = cpu_to_le32(wl->basic_rate_set);
+ cmd->sta.beacon_interval = cpu_to_le16(wl->beacon_int);
+ cmd->sta.ssid_type = WL12XX_SSID_TYPE_ANY;
+ cmd->sta.ssid_len = wl->ssid_len;
+ memcpy(cmd->sta.ssid, wl->ssid, wl->ssid_len);
+ memcpy(cmd->sta.bssid, wl->bssid, ETH_ALEN);
+ cmd->sta.local_rates = cpu_to_le32(wl->rate_set);
+
+ if (wl->sta_hlid == WL12XX_INVALID_LINK_ID) {
+ ret = wl12xx_allocate_link(wl, &wl->sta_hlid);
+ if (ret)
+ goto out_free;
+ }
+ cmd->sta.hlid = wl->sta_hlid;
+ cmd->sta.session = wl12xx_get_new_session_id(wl);
+ cmd->sta.remote_rates = cpu_to_le32(wl->rate_set);
+
+ wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d "
+ "basic_rate_set: 0x%x, remote_rates: 0x%x",
+ wl->role_id, cmd->sta.hlid, cmd->sta.session,
+ wl->basic_rate_set, wl->rate_set);
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role start sta");
+ goto err_hlid;
+ }
+
+ goto out_free;
+
+err_hlid:
+ /* clear links on error. */
+ wl12xx_free_link(wl, &wl->sta_hlid);
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
+
+/* use this function to stop ibss as well */
+int wl12xx_cmd_role_stop_sta(struct wl1271 *wl)
+{
+ struct wl12xx_cmd_role_stop *cmd;
+ int ret;
+
+ if (WARN_ON(wl->sta_hlid == WL12XX_INVALID_LINK_ID))
+ return -EINVAL;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1271_debug(DEBUG_CMD, "cmd role stop sta %d", wl->role_id);
+
+ cmd->role_id = wl->role_id;
+ cmd->disc_type = DISCONNECT_IMMEDIATE;
+ cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED);
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role stop sta");
+ goto out_free;
+ }
+
+ wl12xx_free_link(wl, &wl->sta_hlid);
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
+
+int wl12xx_cmd_role_start_ap(struct wl1271 *wl)
+{
+ struct wl12xx_cmd_role_start *cmd;
+ struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
+ int ret;
+
+ wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wl->role_id);
+
+ /* trying to use hidden SSID with an old hostapd version */
+ if (wl->ssid_len == 0 && !bss_conf->hidden_ssid) {
+ wl1271_error("got a null SSID from beacon/bss");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = wl12xx_allocate_link(wl, &wl->ap_global_hlid);
if (ret < 0)
- wl1271_error("cmd join event completion error");
+ goto out_free;
+
+ ret = wl12xx_allocate_link(wl, &wl->ap_bcast_hlid);
+ if (ret < 0)
+ goto out_free_global;
+
+ cmd->role_id = wl->role_id;
+ cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period);
+ cmd->ap.bss_index = WL1271_AP_BSS_INDEX;
+ cmd->ap.global_hlid = wl->ap_global_hlid;
+ cmd->ap.broadcast_hlid = wl->ap_bcast_hlid;
+ cmd->ap.basic_rate_set = cpu_to_le32(wl->basic_rate_set);
+ cmd->ap.beacon_interval = cpu_to_le16(wl->beacon_int);
+ cmd->ap.dtim_interval = bss_conf->dtim_period;
+ cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
+ cmd->channel = wl->channel;
+
+ if (!bss_conf->hidden_ssid) {
+ /* take the SSID from the beacon for backward compatibility */
+ cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC;
+ cmd->ap.ssid_len = wl->ssid_len;
+ memcpy(cmd->ap.ssid, wl->ssid, wl->ssid_len);
+ } else {
+ cmd->ap.ssid_type = WL12XX_SSID_TYPE_HIDDEN;
+ cmd->ap.ssid_len = bss_conf->ssid_len;
+ memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len);
+ }
+
+ cmd->ap.local_rates = cpu_to_le32(0xffffffff);
+
+ switch (wl->band) {
+ case IEEE80211_BAND_2GHZ:
+ cmd->band = RADIO_BAND_2_4GHZ;
+ break;
+ case IEEE80211_BAND_5GHZ:
+ cmd->band = RADIO_BAND_5GHZ;
+ break;
+ default:
+ wl1271_warning("ap start - unknown band: %d", (int)wl->band);
+ cmd->band = RADIO_BAND_2_4GHZ;
+ break;
+ }
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role start ap");
+ goto out_free_bcast;
+ }
+
+ goto out_free;
+
+out_free_bcast:
+ wl12xx_free_link(wl, &wl->ap_bcast_hlid);
+
+out_free_global:
+ wl12xx_free_link(wl, &wl->ap_global_hlid);
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
+
+int wl12xx_cmd_role_stop_ap(struct wl1271 *wl)
+{
+ struct wl12xx_cmd_role_stop *cmd;
+ int ret;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1271_debug(DEBUG_CMD, "cmd role stop ap %d", wl->role_id);
+
+ cmd->role_id = wl->role_id;
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role stop ap");
+ goto out_free;
+ }
+
+ wl12xx_free_link(wl, &wl->ap_bcast_hlid);
+ wl12xx_free_link(wl, &wl->ap_global_hlid);
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
+
+int wl12xx_cmd_role_start_ibss(struct wl1271 *wl)
+{
+ struct wl12xx_cmd_role_start *cmd;
+ struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
+ int ret;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1271_debug(DEBUG_CMD, "cmd role start ibss %d", wl->role_id);
+
+ cmd->role_id = wl->role_id;
+ if (wl->band == IEEE80211_BAND_5GHZ)
+ cmd->band = WL12XX_BAND_5GHZ;
+ cmd->channel = wl->channel;
+ cmd->ibss.basic_rate_set = cpu_to_le32(wl->basic_rate_set);
+ cmd->ibss.beacon_interval = cpu_to_le16(wl->beacon_int);
+ cmd->ibss.dtim_interval = bss_conf->dtim_period;
+ cmd->ibss.ssid_type = WL12XX_SSID_TYPE_ANY;
+ cmd->ibss.ssid_len = wl->ssid_len;
+ memcpy(cmd->ibss.ssid, wl->ssid, wl->ssid_len);
+ memcpy(cmd->ibss.bssid, wl->bssid, ETH_ALEN);
+ cmd->sta.local_rates = cpu_to_le32(wl->rate_set);
+
+ if (wl->sta_hlid == WL12XX_INVALID_LINK_ID) {
+ ret = wl12xx_allocate_link(wl, &wl->sta_hlid);
+ if (ret)
+ goto out_free;
+ }
+ cmd->ibss.hlid = wl->sta_hlid;
+ cmd->ibss.remote_rates = cpu_to_le32(wl->rate_set);
+
+ wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d "
+ "basic_rate_set: 0x%x, remote_rates: 0x%x",
+ wl->role_id, cmd->sta.hlid, cmd->sta.session,
+ wl->basic_rate_set, wl->rate_set);
+
+ wl1271_debug(DEBUG_CMD, "wl->bssid = %pM", wl->bssid);
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role enable");
+ goto err_hlid;
+ }
+
+ goto out_free;
+
+err_hlid:
+ /* clear links on error. */
+ wl12xx_free_link(wl, &wl->sta_hlid);
out_free:
- kfree(join);
+ kfree(cmd);
out:
return ret;
}
+
/**
* send test command to firmware
*
@@ -488,7 +896,7 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
struct acx_header *acx = buf;
int ret;
- wl1271_debug(DEBUG_CMD, "cmd configure");
+ wl1271_debug(DEBUG_CMD, "cmd configure (%d)", id);
acx->id = cpu_to_le16(id);
@@ -567,6 +975,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
goto out;
}
+ ps_params->role_id = wl->role_id;
ps_params->ps_mode = ps_mode;
ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
@@ -698,6 +1107,7 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl,
{
struct sk_buff *skb;
int ret;
+ u32 rate;
skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len,
ie, ie_len);
@@ -708,14 +1118,13 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl,
wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len);
+ rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
if (band == IEEE80211_BAND_2GHZ)
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
- skb->data, skb->len, 0,
- wl->conf.tx.basic_rate);
+ skb->data, skb->len, 0, rate);
else
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
- skb->data, skb->len, 0,
- wl->conf.tx.basic_rate_5);
+ skb->data, skb->len, 0, rate);
out:
dev_kfree_skb(skb);
@@ -726,6 +1135,7 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
struct sk_buff *skb)
{
int ret;
+ u32 rate;
if (!skb)
skb = ieee80211_ap_probereq_get(wl->hw, wl->vif);
@@ -734,14 +1144,13 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len);
+ rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[wl->band]);
if (wl->band == IEEE80211_BAND_2GHZ)
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
- skb->data, skb->len, 0,
- wl->conf.tx.basic_rate);
+ skb->data, skb->len, 0, rate);
else
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
- skb->data, skb->len, 0,
- wl->conf.tx.basic_rate_5);
+ skb->data, skb->len, 0, rate);
if (ret < 0)
wl1271_error("Unable to set ap probe request template.");
@@ -813,9 +1222,9 @@ int wl1271_build_qos_null_data(struct wl1271 *wl)
wl->basic_rate);
}
-int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id)
+int wl12xx_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid)
{
- struct wl1271_cmd_set_sta_keys *cmd;
+ struct wl1271_cmd_set_keys *cmd;
int ret = 0;
wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id);
@@ -826,36 +1235,7 @@ int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id)
goto out;
}
- cmd->id = id;
- cmd->key_action = cpu_to_le16(KEY_SET_ID);
- cmd->key_type = KEY_WEP;
-
- ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
- if (ret < 0) {
- wl1271_warning("cmd set_default_wep_key failed: %d", ret);
- goto out;
- }
-
-out:
- kfree(cmd);
-
- return ret;
-}
-
-int wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id)
-{
- struct wl1271_cmd_set_ap_keys *cmd;
- int ret = 0;
-
- wl1271_debug(DEBUG_CMD, "cmd set_ap_default_wep_key %d", id);
-
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
- if (!cmd) {
- ret = -ENOMEM;
- goto out;
- }
-
- cmd->hlid = WL1271_AP_BROADCAST_HLID;
+ cmd->hlid = hlid;
cmd->key_id = id;
cmd->lid_key_type = WEP_DEFAULT_LID_TYPE;
cmd->key_action = cpu_to_le16(KEY_SET_ID);
@@ -863,7 +1243,7 @@ int wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id)
ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
if (ret < 0) {
- wl1271_warning("cmd set_ap_default_wep_key failed: %d", ret);
+ wl1271_warning("cmd set_default_wep_key failed: %d", ret);
goto out;
}
@@ -877,17 +1257,27 @@ int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, const u8 *addr,
u32 tx_seq_32, u16 tx_seq_16)
{
- struct wl1271_cmd_set_sta_keys *cmd;
+ struct wl1271_cmd_set_keys *cmd;
int ret = 0;
+ /* hlid might have already been deleted */
+ if (wl->sta_hlid == WL12XX_INVALID_LINK_ID)
+ return 0;
+
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}
- if (key_type != KEY_WEP)
- memcpy(cmd->addr, addr, ETH_ALEN);
+ cmd->hlid = wl->sta_hlid;
+
+ if (key_type == KEY_WEP)
+ cmd->lid_key_type = WEP_DEFAULT_LID_TYPE;
+ else if (is_broadcast_ether_addr(addr))
+ cmd->lid_key_type = BROADCAST_LID_TYPE;
+ else
+ cmd->lid_key_type = UNICAST_LID_TYPE;
cmd->key_action = cpu_to_le16(action);
cmd->key_size = key_size;
@@ -896,10 +1286,7 @@ int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16);
cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32);
- /* we have only one SSID profile */
- cmd->ssid_profile = 0;
-
- cmd->id = id;
+ cmd->key_id = id;
if (key_type == KEY_TKIP) {
/*
@@ -930,11 +1317,15 @@ out:
return ret;
}
+/*
+ * TODO: merge with sta/ibss into 1 set_key function.
+ * note there are slight diffs
+ */
int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
u16 tx_seq_16)
{
- struct wl1271_cmd_set_ap_keys *cmd;
+ struct wl1271_cmd_set_keys *cmd;
int ret = 0;
u8 lid_type;
@@ -942,7 +1333,7 @@ int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
if (!cmd)
return -ENOMEM;
- if (hlid == WL1271_AP_BROADCAST_HLID) {
+ if (hlid == wl->ap_bcast_hlid) {
if (key_type == KEY_WEP)
lid_type = WEP_DEFAULT_LID_TYPE;
else
@@ -991,12 +1382,12 @@ out:
return ret;
}
-int wl1271_cmd_disconnect(struct wl1271 *wl)
+int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid)
{
- struct wl1271_cmd_disconnect *cmd;
+ struct wl12xx_cmd_set_peer_state *cmd;
int ret = 0;
- wl1271_debug(DEBUG_CMD, "cmd disconnect");
+ wl1271_debug(DEBUG_CMD, "cmd set peer state (hlid=%d)", hlid);
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
@@ -1004,21 +1395,15 @@ int wl1271_cmd_disconnect(struct wl1271 *wl)
goto out;
}
- cmd->rx_config_options = cpu_to_le32(wl->rx_config);
- cmd->rx_filter_options = cpu_to_le32(wl->rx_filter);
- /* disconnect reason is not used in immediate disconnections */
- cmd->type = DISCONNECT_IMMEDIATE;
+ cmd->hlid = hlid;
+ cmd->state = WL1271_CMD_STA_STATE_CONNECTED;
- ret = wl1271_cmd_send(wl, CMD_DISCONNECT, cmd, sizeof(*cmd), 0);
+ ret = wl1271_cmd_send(wl, CMD_SET_PEER_STATE, cmd, sizeof(*cmd), 0);
if (ret < 0) {
- wl1271_error("failed to send disconnect command");
+ wl1271_error("failed to send set peer state command");
goto out_free;
}
- ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID);
- if (ret < 0)
- wl1271_error("cmd disconnect event completion error");
-
out_free:
kfree(cmd);
@@ -1026,12 +1411,13 @@ out:
return ret;
}
-int wl1271_cmd_set_sta_state(struct wl1271 *wl)
+int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
{
- struct wl1271_cmd_set_sta_state *cmd;
- int ret = 0;
+ struct wl12xx_cmd_add_peer *cmd;
+ int i, ret;
+ u32 sta_rates;
- wl1271_debug(DEBUG_CMD, "cmd set sta state");
+ wl1271_debug(DEBUG_CMD, "cmd add peer %d", (int)hlid);
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
@@ -1039,11 +1425,33 @@ int wl1271_cmd_set_sta_state(struct wl1271 *wl)
goto out;
}
- cmd->state = WL1271_CMD_STA_STATE_CONNECTED;
+ memcpy(cmd->addr, sta->addr, ETH_ALEN);
+ cmd->bss_index = WL1271_AP_BSS_INDEX;
+ cmd->aid = sta->aid;
+ cmd->hlid = hlid;
+ cmd->sp_len = sta->max_sp;
+ cmd->wmm = sta->wme ? 1 : 0;
+
+ for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++)
+ if (sta->wme && (sta->uapsd_queues & BIT(i)))
+ cmd->psd_type[i] = WL1271_PSD_UPSD_TRIGGER;
+ else
+ cmd->psd_type[i] = WL1271_PSD_LEGACY;
+
+ sta_rates = sta->supp_rates[wl->band];
+ if (sta->ht_cap.ht_supported)
+ sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET;
- ret = wl1271_cmd_send(wl, CMD_SET_STA_STATE, cmd, sizeof(*cmd), 0);
+ cmd->supported_rates =
+ cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates,
+ wl->band));
+
+ wl1271_debug(DEBUG_CMD, "new peer rates=0x%x queues=0x%x",
+ cmd->supported_rates, sta->uapsd_queues);
+
+ ret = wl1271_cmd_send(wl, CMD_ADD_PEER, cmd, sizeof(*cmd), 0);
if (ret < 0) {
- wl1271_error("failed to send set STA state command");
+ wl1271_error("failed to initiate cmd add peer");
goto out_free;
}
@@ -1054,23 +1462,12 @@ out:
return ret;
}
-int wl1271_cmd_start_bss(struct wl1271 *wl)
+int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid)
{
- struct wl1271_cmd_bss_start *cmd;
- struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
+ struct wl12xx_cmd_remove_peer *cmd;
int ret;
- wl1271_debug(DEBUG_CMD, "cmd start bss");
-
- /*
- * FIXME: We currently do not support hidden SSID. The real SSID
- * should be fetched from mac80211 first.
- */
- if (wl->ssid_len == 0) {
- wl1271_warning("Hidden SSID currently not supported for AP");
- ret = -EINVAL;
- goto out;
- }
+ wl1271_debug(DEBUG_CMD, "cmd remove peer %d", (int)hlid);
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
@@ -1078,40 +1475,24 @@ int wl1271_cmd_start_bss(struct wl1271 *wl)
goto out;
}
- memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN);
-
- cmd->aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period);
- cmd->bss_index = WL1271_AP_BSS_INDEX;
- cmd->global_hlid = WL1271_AP_GLOBAL_HLID;
- cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID;
- cmd->basic_rate_set = cpu_to_le32(wl->basic_rate_set);
- cmd->beacon_interval = cpu_to_le16(wl->beacon_int);
- cmd->dtim_interval = bss_conf->dtim_period;
- cmd->beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
- cmd->channel = wl->channel;
- cmd->ssid_len = wl->ssid_len;
- cmd->ssid_type = SSID_TYPE_PUBLIC;
- memcpy(cmd->ssid, wl->ssid, wl->ssid_len);
-
- switch (wl->band) {
- case IEEE80211_BAND_2GHZ:
- cmd->band = RADIO_BAND_2_4GHZ;
- break;
- case IEEE80211_BAND_5GHZ:
- cmd->band = RADIO_BAND_5GHZ;
- break;
- default:
- wl1271_warning("bss start - unknown band: %d", (int)wl->band);
- cmd->band = RADIO_BAND_2_4GHZ;
- break;
- }
+ cmd->hlid = hlid;
+ /* We never send a deauth, mac80211 is in charge of this */
+ cmd->reason_opcode = 0;
+ cmd->send_deauth_flag = 0;
- ret = wl1271_cmd_send(wl, CMD_BSS_START, cmd, sizeof(*cmd), 0);
+ ret = wl1271_cmd_send(wl, CMD_REMOVE_PEER, cmd, sizeof(*cmd), 0);
if (ret < 0) {
- wl1271_error("failed to initiate cmd start bss");
+ wl1271_error("failed to initiate cmd remove peer");
goto out_free;
}
+ /*
+ * We are ok with a timeout here. The event is sometimes not sent
+ * due to a firmware bug.
+ */
+ wl1271_cmd_wait_for_event_or_timeout(wl,
+ PEER_REMOVE_COMPLETE_EVENT_ID);
+
out_free:
kfree(cmd);
@@ -1119,12 +1500,12 @@ out:
return ret;
}
-int wl1271_cmd_stop_bss(struct wl1271 *wl)
+int wl12xx_cmd_config_fwlog(struct wl1271 *wl)
{
- struct wl1271_cmd_bss_start *cmd;
- int ret;
+ struct wl12xx_cmd_config_fwlog *cmd;
+ int ret = 0;
- wl1271_debug(DEBUG_CMD, "cmd stop bss");
+ wl1271_debug(DEBUG_CMD, "cmd config firmware logger");
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
@@ -1132,11 +1513,15 @@ int wl1271_cmd_stop_bss(struct wl1271 *wl)
goto out;
}
- cmd->bss_index = WL1271_AP_BSS_INDEX;
+ cmd->logger_mode = wl->conf.fwlog.mode;
+ cmd->log_severity = wl->conf.fwlog.severity;
+ cmd->timestamp = wl->conf.fwlog.timestamp;
+ cmd->output = wl->conf.fwlog.output;
+ cmd->threshold = wl->conf.fwlog.threshold;
- ret = wl1271_cmd_send(wl, CMD_BSS_STOP, cmd, sizeof(*cmd), 0);
+ ret = wl1271_cmd_send(wl, CMD_CONFIG_FWLOGGER, cmd, sizeof(*cmd), 0);
if (ret < 0) {
- wl1271_error("failed to initiate cmd stop bss");
+ wl1271_error("failed to send config firmware logger command");
goto out_free;
}
@@ -1147,12 +1532,12 @@ out:
return ret;
}
-int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
+int wl12xx_cmd_start_fwlog(struct wl1271 *wl)
{
- struct wl1271_cmd_add_sta *cmd;
- int ret;
+ struct wl12xx_cmd_start_fwlog *cmd;
+ int ret = 0;
- wl1271_debug(DEBUG_CMD, "cmd add sta %d", (int)hlid);
+ wl1271_debug(DEBUG_CMD, "cmd start firmware logger");
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
@@ -1160,23 +1545,35 @@ int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
goto out;
}
- /* currently we don't support UAPSD */
- cmd->sp_len = 0;
+ ret = wl1271_cmd_send(wl, CMD_START_FWLOGGER, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to send start firmware logger command");
+ goto out_free;
+ }
- memcpy(cmd->addr, sta->addr, ETH_ALEN);
- cmd->bss_index = WL1271_AP_BSS_INDEX;
- cmd->aid = sta->aid;
- cmd->hlid = hlid;
- cmd->wmm = sta->wme ? 1 : 0;
+out_free:
+ kfree(cmd);
- cmd->supported_rates = cpu_to_le32(wl1271_tx_enabled_rates_get(wl,
- sta->supp_rates[wl->band]));
+out:
+ return ret;
+}
- wl1271_debug(DEBUG_CMD, "new sta rates: 0x%x", cmd->supported_rates);
+int wl12xx_cmd_stop_fwlog(struct wl1271 *wl)
+{
+ struct wl12xx_cmd_stop_fwlog *cmd;
+ int ret = 0;
- ret = wl1271_cmd_send(wl, CMD_ADD_STA, cmd, sizeof(*cmd), 0);
+ wl1271_debug(DEBUG_CMD, "cmd stop firmware logger");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = wl1271_cmd_send(wl, CMD_STOP_FWLOGGER, cmd, sizeof(*cmd), 0);
if (ret < 0) {
- wl1271_error("failed to initiate cmd add sta");
+ wl1271_error("failed to send stop firmware logger command");
goto out_free;
}
@@ -1187,12 +1584,15 @@ out:
return ret;
}
-int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid)
+static int wl12xx_cmd_roc(struct wl1271 *wl, u8 role_id)
{
- struct wl1271_cmd_remove_sta *cmd;
- int ret;
+ struct wl12xx_cmd_roc *cmd;
+ int ret = 0;
- wl1271_debug(DEBUG_CMD, "cmd remove sta %d", (int)hlid);
+ wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wl->channel, role_id);
+
+ if (WARN_ON(role_id == WL12XX_INVALID_ROLE_ID))
+ return -EINVAL;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
@@ -1200,23 +1600,28 @@ int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid)
goto out;
}
- cmd->hlid = hlid;
- /* We never send a deauth, mac80211 is in charge of this */
- cmd->reason_opcode = 0;
- cmd->send_deauth_flag = 0;
+ cmd->role_id = role_id;
+ cmd->channel = wl->channel;
+ switch (wl->band) {
+ case IEEE80211_BAND_2GHZ:
+ cmd->band = RADIO_BAND_2_4GHZ;
+ break;
+ case IEEE80211_BAND_5GHZ:
+ cmd->band = RADIO_BAND_5GHZ;
+ break;
+ default:
+ wl1271_error("roc - unknown band: %d", (int)wl->band);
+ ret = -EINVAL;
+ goto out_free;
+ }
- ret = wl1271_cmd_send(wl, CMD_REMOVE_STA, cmd, sizeof(*cmd), 0);
+
+ ret = wl1271_cmd_send(wl, CMD_REMAIN_ON_CHANNEL, cmd, sizeof(*cmd), 0);
if (ret < 0) {
- wl1271_error("failed to initiate cmd remove sta");
+ wl1271_error("failed to send ROC command");
goto out_free;
}
- /*
- * We are ok with a timeout here. The event is sometimes not sent
- * due to a firmware bug.
- */
- wl1271_cmd_wait_for_event_or_timeout(wl, STA_REMOVE_COMPLETE_EVENT_ID);
-
out_free:
kfree(cmd);
@@ -1224,28 +1629,24 @@ out:
return ret;
}
-int wl12xx_cmd_config_fwlog(struct wl1271 *wl)
+static int wl12xx_cmd_croc(struct wl1271 *wl, u8 role_id)
{
- struct wl12xx_cmd_config_fwlog *cmd;
+ struct wl12xx_cmd_croc *cmd;
int ret = 0;
- wl1271_debug(DEBUG_CMD, "cmd config firmware logger");
+ wl1271_debug(DEBUG_CMD, "cmd croc (%d)", role_id);
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}
+ cmd->role_id = role_id;
- cmd->logger_mode = wl->conf.fwlog.mode;
- cmd->log_severity = wl->conf.fwlog.severity;
- cmd->timestamp = wl->conf.fwlog.timestamp;
- cmd->output = wl->conf.fwlog.output;
- cmd->threshold = wl->conf.fwlog.threshold;
-
- ret = wl1271_cmd_send(wl, CMD_CONFIG_FWLOGGER, cmd, sizeof(*cmd), 0);
+ ret = wl1271_cmd_send(wl, CMD_CANCEL_REMAIN_ON_CHANNEL, cmd,
+ sizeof(*cmd), 0);
if (ret < 0) {
- wl1271_error("failed to send config firmware logger command");
+ wl1271_error("failed to send ROC command");
goto out_free;
}
@@ -1256,12 +1657,52 @@ out:
return ret;
}
-int wl12xx_cmd_start_fwlog(struct wl1271 *wl)
+int wl12xx_roc(struct wl1271 *wl, u8 role_id)
{
- struct wl12xx_cmd_start_fwlog *cmd;
int ret = 0;
- wl1271_debug(DEBUG_CMD, "cmd start firmware logger");
+ if (WARN_ON(test_bit(role_id, wl->roc_map)))
+ return 0;
+
+ ret = wl12xx_cmd_roc(wl, role_id);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1271_cmd_wait_for_event(wl,
+ REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID);
+ if (ret < 0) {
+ wl1271_error("cmd roc event completion error");
+ goto out;
+ }
+
+ __set_bit(role_id, wl->roc_map);
+out:
+ return ret;
+}
+
+int wl12xx_croc(struct wl1271 *wl, u8 role_id)
+{
+ int ret = 0;
+
+ if (WARN_ON(!test_bit(role_id, wl->roc_map)))
+ return 0;
+
+ ret = wl12xx_cmd_croc(wl, role_id);
+ if (ret < 0)
+ goto out;
+
+ __clear_bit(role_id, wl->roc_map);
+out:
+ return ret;
+}
+
+int wl12xx_cmd_channel_switch(struct wl1271 *wl,
+ struct ieee80211_channel_switch *ch_switch)
+{
+ struct wl12xx_cmd_channel_switch *cmd;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "cmd channel switch");
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
@@ -1269,9 +1710,14 @@ int wl12xx_cmd_start_fwlog(struct wl1271 *wl)
goto out;
}
- ret = wl1271_cmd_send(wl, CMD_START_FWLOGGER, cmd, sizeof(*cmd), 0);
+ 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 */
+
+ ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0);
if (ret < 0) {
- wl1271_error("failed to send start firmware logger command");
+ wl1271_error("failed to send channel switch command");
goto out_free;
}
@@ -1282,12 +1728,12 @@ out:
return ret;
}
-int wl12xx_cmd_stop_fwlog(struct wl1271 *wl)
+int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl)
{
- struct wl12xx_cmd_stop_fwlog *cmd;
- int ret = 0;
+ struct wl12xx_cmd_stop_channel_switch *cmd;
+ int ret;
- wl1271_debug(DEBUG_CMD, "cmd stop firmware logger");
+ wl1271_debug(DEBUG_ACX, "cmd stop channel switch");
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
@@ -1295,9 +1741,9 @@ int wl12xx_cmd_stop_fwlog(struct wl1271 *wl)
goto out;
}
- ret = wl1271_cmd_send(wl, CMD_STOP_FWLOGGER, cmd, sizeof(*cmd), 0);
+ ret = wl1271_cmd_send(wl, CMD_STOP_CHANNEL_SWICTH, cmd, sizeof(*cmd), 0);
if (ret < 0) {
- wl1271_error("failed to send stop firmware logger command");
+ wl1271_error("failed to stop channel switch command");
goto out_free;
}
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h
index 1f7037292c15..b7bd42769aa7 100644
--- a/drivers/net/wireless/wl12xx/cmd.h
+++ b/drivers/net/wireless/wl12xx/cmd.h
@@ -36,7 +36,15 @@ int wl128x_cmd_general_parms(struct wl1271 *wl);
int wl1271_cmd_radio_parms(struct wl1271 *wl);
int wl128x_cmd_radio_parms(struct wl1271 *wl);
int wl1271_cmd_ext_radio_parms(struct wl1271 *wl);
-int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type);
+int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 role_type, u8 *role_id);
+int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id);
+int wl12xx_cmd_role_start_dev(struct wl1271 *wl);
+int wl12xx_cmd_role_stop_dev(struct wl1271 *wl);
+int wl12xx_cmd_role_start_sta(struct wl1271 *wl);
+int wl12xx_cmd_role_stop_sta(struct wl1271 *wl);
+int wl12xx_cmd_role_start_ap(struct wl1271 *wl);
+int wl12xx_cmd_role_stop_ap(struct wl1271 *wl);
+int wl12xx_cmd_role_start_ibss(struct wl1271 *wl);
int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
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);
@@ -56,23 +64,24 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr);
int wl1271_build_qos_null_data(struct wl1271 *wl);
int wl1271_cmd_build_klv_null_data(struct wl1271 *wl);
-int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id);
-int wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id);
+int wl12xx_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid);
int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, const u8 *addr,
u32 tx_seq_32, u16 tx_seq_16);
int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
u16 tx_seq_16);
-int wl1271_cmd_disconnect(struct wl1271 *wl);
-int wl1271_cmd_set_sta_state(struct wl1271 *wl);
-int wl1271_cmd_start_bss(struct wl1271 *wl);
-int wl1271_cmd_stop_bss(struct wl1271 *wl);
-int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid);
-int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid);
+int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid);
+int wl12xx_roc(struct wl1271 *wl, u8 role_id);
+int wl12xx_croc(struct wl1271 *wl, u8 role_id);
+int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid);
+int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid);
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 ieee80211_channel_switch *ch_switch);
+int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl);
enum wl1271_commands {
CMD_INTERROGATE = 1, /*use this to read information elements*/
@@ -83,25 +92,21 @@ enum wl1271_commands {
CMD_DISABLE_TX = 6,
CMD_SCAN = 8,
CMD_STOP_SCAN = 9,
- CMD_START_JOIN = 11,
CMD_SET_KEYS = 12,
CMD_READ_MEMORY = 13,
CMD_WRITE_MEMORY = 14,
CMD_SET_TEMPLATE = 19,
CMD_TEST = 23,
CMD_NOISE_HIST = 28,
- CMD_LNA_CONTROL = 32,
+ CMD_QUIET_ELEMENT_SET_STATE = 29,
CMD_SET_BCN_MODE = 33,
CMD_MEASUREMENT = 34,
CMD_STOP_MEASUREMENT = 35,
- CMD_DISCONNECT = 36,
CMD_SET_PS_MODE = 37,
CMD_CHANNEL_SWITCH = 38,
CMD_STOP_CHANNEL_SWICTH = 39,
CMD_AP_DISCOVERY = 40,
CMD_STOP_AP_DISCOVERY = 41,
- CMD_SPS_SCAN = 42,
- CMD_STOP_SPS_SCAN = 43,
CMD_HEALTH_CHECK = 45,
CMD_DEBUG = 46,
CMD_TRIGGER_SCAN_TO = 47,
@@ -109,16 +114,30 @@ enum wl1271_commands {
CMD_CONNECTION_SCAN_SSID_CFG = 49,
CMD_START_PERIODIC_SCAN = 50,
CMD_STOP_PERIODIC_SCAN = 51,
- CMD_SET_STA_STATE = 52,
- CMD_CONFIG_FWLOGGER = 53,
- CMD_START_FWLOGGER = 54,
- CMD_STOP_FWLOGGER = 55,
+ CMD_SET_PEER_STATE = 52,
+ CMD_REMAIN_ON_CHANNEL = 53,
+ CMD_CANCEL_REMAIN_ON_CHANNEL = 54,
- /* AP mode commands */
- CMD_BSS_START = 60,
- CMD_BSS_STOP = 61,
- CMD_ADD_STA = 62,
- CMD_REMOVE_STA = 63,
+ CMD_CONFIG_FWLOGGER = 55,
+ CMD_START_FWLOGGER = 56,
+ CMD_STOP_FWLOGGER = 57,
+
+ /* AP commands */
+ CMD_ADD_PEER = 62,
+ CMD_REMOVE_PEER = 63,
+
+ /* Role API */
+ CMD_ROLE_ENABLE = 70,
+ CMD_ROLE_DISABLE = 71,
+ CMD_ROLE_START = 72,
+ CMD_ROLE_STOP = 73,
+
+ /* WIFI Direct */
+ CMD_WFD_START_DISCOVERY = 80,
+ CMD_WFD_STOP_DISCOVERY = 81,
+ CMD_WFD_ATTRIBUTE_CONFIG = 82,
+
+ CMD_NOP = 100,
NUM_COMMANDS,
MAX_COMMAND_ID = 0xFFFF,
@@ -147,21 +166,20 @@ enum cmd_templ {
CMD_TEMPL_CTS, /*
* For CTS-to-self (FastCTS) mechanism
* for BT/WLAN coexistence (SoftGemini). */
- CMD_TEMPL_ARP_RSP,
- CMD_TEMPL_LINK_MEASUREMENT_REPORT,
-
- /* AP-mode specific */
- CMD_TEMPL_AP_BEACON = 13,
+ CMD_TEMPL_AP_BEACON,
CMD_TEMPL_AP_PROBE_RESPONSE,
- CMD_TEMPL_AP_ARP_RSP,
+ CMD_TEMPL_ARP_RSP,
CMD_TEMPL_DEAUTH_AP,
+ CMD_TEMPL_TEMPORARY,
+ CMD_TEMPL_LINK_MEASUREMENT_REPORT,
CMD_TEMPL_MAX = 0xff
};
/* unit ms */
#define WL1271_COMMAND_TIMEOUT 2000
-#define WL1271_CMD_TEMPL_MAX_SIZE 252
+#define WL1271_CMD_TEMPL_DFLT_SIZE 252
+#define WL1271_CMD_TEMPL_MAX_SIZE 548
#define WL1271_EVENT_TIMEOUT 750
struct wl1271_cmd_header {
@@ -193,6 +211,8 @@ enum {
CMD_STATUS_WRONG_NESTING = 19,
CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/
CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/
+ CMD_STATUS_TEMPLATE_OOM = 23,
+ CMD_STATUS_NO_RX_BA_SESSION = 24,
MAX_COMMAND_STATUS = 0xff
};
@@ -210,38 +230,114 @@ enum {
#define WL1271_JOIN_CMD_TX_SESSION_OFFSET 1
#define WL1271_JOIN_CMD_BSS_TYPE_5GHZ 0x10
-struct wl1271_cmd_join {
+struct wl12xx_cmd_role_enable {
struct wl1271_cmd_header header;
- __le32 bssid_lsb;
- __le16 bssid_msb;
- __le16 beacon_interval; /* in TBTTs */
- __le32 rx_config_options;
- __le32 rx_filter_options;
+ u8 role_id;
+ u8 role_type;
+ u8 mac_address[ETH_ALEN];
+} __packed;
- /*
- * The target uses this field to determine the rate at
- * which to transmit control frame responses (such as
- * ACK or CTS frames).
- */
- __le32 basic_rate_set;
- __le32 supported_rate_set;
- u8 dtim_interval;
- /*
- * bits 0-2: This bitwise field specifies the type
- * of BSS to start or join (BSS_TYPE_*).
- * bit 4: Band - The radio band in which to join
- * or start.
- * 0 - 2.4GHz band
- * 1 - 5GHz band
- * bits 3, 5-7: Reserved
- */
- u8 bss_type;
+struct wl12xx_cmd_role_disable {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+ u8 padding[3];
+} __packed;
+
+enum wl12xx_band {
+ WL12XX_BAND_2_4GHZ = 0,
+ WL12XX_BAND_5GHZ = 1,
+ WL12XX_BAND_JAPAN_4_9_GHZ = 2,
+ WL12XX_BAND_DEFAULT = WL12XX_BAND_2_4GHZ,
+ WL12XX_BAND_INVALID = 0x7E,
+ WL12XX_BAND_MAX_RADIO = 0x7F,
+};
+
+struct wl12xx_cmd_role_start {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+ u8 band;
u8 channel;
- u8 ssid_len;
- u8 ssid[IW_ESSID_MAX_SIZE];
- u8 ctrl; /* JOIN_CMD_CTRL_* */
- u8 reserved[3];
+ u8 padding;
+
+ union {
+ struct {
+ u8 hlid;
+ u8 session;
+ u8 padding_1[54];
+ } __packed device;
+ /* sta & p2p_cli use the same struct */
+ struct {
+ u8 bssid[ETH_ALEN];
+ u8 hlid; /* data hlid */
+ u8 session;
+ __le32 remote_rates; /* remote supported rates */
+
+ /*
+ * The target uses this field to determine the rate at
+ * which to transmit control frame responses (such as
+ * ACK or CTS frames).
+ */
+ __le32 basic_rate_set;
+ __le32 local_rates; /* local supported rates */
+
+ u8 ssid_type;
+ u8 ssid_len;
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+
+ __le16 beacon_interval; /* in TBTTs */
+ } __packed sta;
+ struct {
+ u8 bssid[ETH_ALEN];
+ u8 hlid; /* data hlid */
+ u8 dtim_interval;
+ __le32 remote_rates; /* remote supported rates */
+
+ __le32 basic_rate_set;
+ __le32 local_rates; /* local supported rates */
+
+ u8 ssid_type;
+ u8 ssid_len;
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+
+ __le16 beacon_interval; /* in TBTTs */
+
+ u8 padding_1[4];
+ } __packed ibss;
+ /* ap & p2p_go use the same struct */
+ struct {
+ __le16 aging_period; /* in secs */
+ u8 beacon_expiry; /* in ms */
+ u8 bss_index;
+ /* The host link id for the AP's global queue */
+ u8 global_hlid;
+ /* The host link id for the AP's broadcast queue */
+ u8 broadcast_hlid;
+
+ __le16 beacon_interval; /* in TBTTs */
+
+ __le32 basic_rate_set;
+ __le32 local_rates; /* local supported rates */
+
+ u8 dtim_interval;
+
+ u8 ssid_type;
+ u8 ssid_len;
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+
+ u8 padding_1[5];
+ } __packed ap;
+ };
+} __packed;
+
+struct wl12xx_cmd_role_stop {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+ u8 disc_type; /* only STA and P2P_CLI */
+ __le16 reason; /* only STA and P2P_CLI */
} __packed;
struct cmd_enabledisable_path {
@@ -287,8 +383,9 @@ enum wl1271_cmd_ps_mode {
struct wl1271_cmd_ps_params {
struct wl1271_cmd_header header;
+ u8 role_id;
u8 ps_mode; /* STATION_* */
- u8 padding[3];
+ u8 padding[2];
} __packed;
/* HW encryption keys */
@@ -301,6 +398,12 @@ enum wl1271_cmd_key_action {
MAX_KEY_ACTION = 0xffff,
};
+enum wl1271_cmd_lid_key_type {
+ UNICAST_LID_TYPE = 0,
+ BROADCAST_LID_TYPE = 1,
+ WEP_DEFAULT_LID_TYPE = 2
+};
+
enum wl1271_cmd_key_type {
KEY_NONE = 0,
KEY_WEP = 1,
@@ -309,44 +412,7 @@ enum wl1271_cmd_key_type {
KEY_GEM = 4,
};
-/* FIXME: Add description for key-types */
-
-struct wl1271_cmd_set_sta_keys {
- struct wl1271_cmd_header header;
-
- /* Ignored for default WEP key */
- u8 addr[ETH_ALEN];
-
- /* key_action_e */
- __le16 key_action;
-
- __le16 reserved_1;
-
- /* key size in bytes */
- u8 key_size;
-
- /* key_type_e */
- u8 key_type;
- u8 ssid_profile;
-
- /*
- * TKIP, AES: frame's key id field.
- * For WEP default key: key id;
- */
- u8 id;
- u8 reserved_2[6];
- u8 key[MAX_KEY_SIZE];
- __le16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
- __le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
-} __packed;
-
-enum wl1271_cmd_lid_key_type {
- UNICAST_LID_TYPE = 0,
- BROADCAST_LID_TYPE = 1,
- WEP_DEFAULT_LID_TYPE = 2
-};
-
-struct wl1271_cmd_set_ap_keys {
+struct wl1271_cmd_set_keys {
struct wl1271_cmd_header header;
/*
@@ -496,69 +562,46 @@ enum wl1271_disconnect_type {
DISCONNECT_DISASSOC
};
-struct wl1271_cmd_disconnect {
- struct wl1271_cmd_header header;
-
- __le32 rx_config_options;
- __le32 rx_filter_options;
-
- __le16 reason;
- u8 type;
-
- u8 padding;
-} __packed;
-
#define WL1271_CMD_STA_STATE_CONNECTED 1
-struct wl1271_cmd_set_sta_state {
+struct wl12xx_cmd_set_peer_state {
struct wl1271_cmd_header header;
+ u8 hlid;
u8 state;
- u8 padding[3];
+ u8 padding[2];
} __packed;
-enum wl1271_ssid_type {
- SSID_TYPE_PUBLIC = 0,
- SSID_TYPE_HIDDEN = 1
+struct wl12xx_cmd_roc {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+ u8 channel;
+ u8 band;
+ u8 padding;
};
-struct wl1271_cmd_bss_start {
+struct wl12xx_cmd_croc {
struct wl1271_cmd_header header;
- /* wl1271_ssid_type */
- u8 ssid_type;
- u8 ssid_len;
- u8 ssid[IW_ESSID_MAX_SIZE];
- u8 padding_1[2];
+ u8 role_id;
+ u8 padding[3];
+};
- /* Basic rate set */
- __le32 basic_rate_set;
- /* Aging period in seconds*/
- __le16 aging_period;
+enum wl12xx_ssid_type {
+ WL12XX_SSID_TYPE_PUBLIC = 0,
+ WL12XX_SSID_TYPE_HIDDEN = 1,
+ WL12XX_SSID_TYPE_ANY = 2,
+};
- /*
- * This field specifies the time between target beacon
- * transmission times (TBTTs), in time units (TUs).
- * Valid values are 1 to 1024.
- */
- __le16 beacon_interval;
- u8 bssid[ETH_ALEN];
- u8 bss_index;
- /* Radio band */
- u8 band;
- u8 channel;
- /* The host link id for the AP's global queue */
- u8 global_hlid;
- /* The host link id for the AP's broadcast queue */
- u8 broadcast_hlid;
- /* DTIM count */
- u8 dtim_interval;
- /* Beacon expiry time in ms */
- u8 beacon_expiry;
- u8 padding_2[3];
-} __packed;
+enum wl1271_psd_type {
+ WL1271_PSD_LEGACY = 0,
+ WL1271_PSD_UPSD_TRIGGER = 1,
+ WL1271_PSD_LEGACY_PSPOLL = 2,
+ WL1271_PSD_SAPSD = 3
+};
-struct wl1271_cmd_add_sta {
+struct wl12xx_cmd_add_peer {
struct wl1271_cmd_header header;
u8 addr[ETH_ALEN];
@@ -572,7 +615,7 @@ struct wl1271_cmd_add_sta {
u8 padding1;
} __packed;
-struct wl1271_cmd_remove_sta {
+struct wl12xx_cmd_remove_peer {
struct wl1271_cmd_header header;
u8 hlid;
@@ -637,4 +680,21 @@ struct wl12xx_cmd_stop_fwlog {
struct wl1271_cmd_header header;
} __packed;
+struct wl12xx_cmd_channel_switch {
+ struct wl1271_cmd_header header;
+
+ /* 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;
+} __packed;
+
+struct wl12xx_cmd_stop_channel_switch {
+ struct wl1271_cmd_header header;
+} __packed;
+
#endif /* __WL1271_CMD_H__ */
diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h
index 6080e01d92c6..04bb8fbf93f9 100644
--- a/drivers/net/wireless/wl12xx/conf.h
+++ b/drivers/net/wireless/wl12xx/conf.h
@@ -99,40 +99,75 @@ enum {
enum {
/*
- * PER threshold in PPM of the BT voice
+ * Configure the min and max time BT gains the antenna
+ * in WLAN / BT master basic rate
*
- * Range: 0 - 10000000
+ * Range: 0 - 255 (ms)
*/
- CONF_SG_BT_PER_THRESHOLD = 0,
+ CONF_SG_ACL_BT_MASTER_MIN_BR = 0,
+ CONF_SG_ACL_BT_MASTER_MAX_BR,
/*
- * Number of consequent RX_ACTIVE activities to override BT voice
- * frames to ensure WLAN connection
+ * Configure the min and max time BT gains the antenna
+ * in WLAN / BT slave basic rate
*
- * Range: 0 - 100
+ * Range: 0 - 255 (ms)
*/
- CONF_SG_HV3_MAX_OVERRIDE,
+ CONF_SG_ACL_BT_SLAVE_MIN_BR,
+ CONF_SG_ACL_BT_SLAVE_MAX_BR,
/*
- * Defines the PER threshold of the BT voice
+ * Configure the min and max time BT gains the antenna
+ * in WLAN / BT master EDR
*
- * Range: 0 - 65000
+ * Range: 0 - 255 (ms)
*/
- CONF_SG_BT_NFS_SAMPLE_INTERVAL,
+ CONF_SG_ACL_BT_MASTER_MIN_EDR,
+ CONF_SG_ACL_BT_MASTER_MAX_EDR,
/*
- * Defines the load ratio of BT
+ * Configure the min and max time BT gains the antenna
+ * in WLAN / BT slave EDR
*
- * Range: 0 - 100 (%)
+ * Range: 0 - 255 (ms)
*/
- CONF_SG_BT_LOAD_RATIO,
+ CONF_SG_ACL_BT_SLAVE_MIN_EDR,
+ CONF_SG_ACL_BT_SLAVE_MAX_EDR,
/*
- * Defines whether the SG will force WLAN host to enter/exit PSM
+ * The maximum time WLAN can gain the antenna
+ * in WLAN PSM / BT master/slave BR
*
- * Range: 1 - SG can force, 0 - host handles PSM
+ * Range: 0 - 255 (ms)
*/
- CONF_SG_AUTO_PS_MODE,
+ CONF_SG_ACL_WLAN_PS_MASTER_BR,
+ CONF_SG_ACL_WLAN_PS_SLAVE_BR,
+
+ /*
+ * The maximum time WLAN can gain the antenna
+ * in WLAN PSM / BT master/slave EDR
+ *
+ * Range: 0 - 255 (ms)
+ */
+ CONF_SG_ACL_WLAN_PS_MASTER_EDR,
+ CONF_SG_ACL_WLAN_PS_SLAVE_EDR,
+
+ /* TODO: explain these values */
+ CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR,
+ CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR,
+ CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR,
+ CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR,
+ CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR,
+ CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR,
+ CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR,
+ CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR,
+
+ CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR,
+ CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR,
+ CONF_SG_ACL_PASSIVE_SCAN_BT_BR,
+ CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR,
+ CONF_SG_ACL_PASSIVE_SCAN_BT_EDR,
+ CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR,
/*
* Compensation percentage of probe requests when scan initiated
@@ -151,102 +186,70 @@ enum {
CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3,
/*
- * Defines antenna configuration (single/dual antenna)
- *
- * Range: 0 - single antenna, 1 - dual antenna
- */
- CONF_SG_ANTENNA_CONFIGURATION,
-
- /*
- * The threshold (percent) of max consequtive beacon misses before
- * increasing priority of beacon reception.
- *
- * Range: 0 - 100 (%)
- */
- CONF_SG_BEACON_MISS_PERCENT,
-
- /*
- * The rate threshold below which receiving a data frame from the AP
- * will increase the priority of the data frame above BT traffic.
- *
- * Range: 0,2, 5(=5.5), 6, 9, 11, 12, 18, 24, 36, 48, 54
- */
- CONF_SG_RATE_ADAPT_THRESH,
-
- /*
- * Not used currently.
+ * Compensation percentage of WLAN active scan window if initiated
+ * during BT A2DP
*
- * Range: 0
+ * Range: 0 - 1000 (%)
*/
- CONF_SG_RATE_ADAPT_SNR,
+ CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP,
/*
- * Configure the min and max time BT gains the antenna
- * in WLAN PSM / BT master basic rate
+ * Compensation percentage of WLAN passive scan window if initiated
+ * during BT A2DP BR
*
- * Range: 0 - 255 (ms)
+ * Range: 0 - 1000 (%)
*/
- CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR,
- CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR,
+ CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR,
/*
- * The time after it expires no new WLAN trigger frame is trasmitted
- * in WLAN PSM / BT master basic rate
+ * Compensation percentage of WLAN passive scan window if initiated
+ * during BT A2DP EDR
*
- * Range: 0 - 255 (ms)
+ * Range: 0 - 1000 (%)
*/
- CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR,
+ CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR,
/*
- * Configure the min and max time BT gains the antenna
- * in WLAN PSM / BT slave basic rate
+ * Compensation percentage of WLAN passive scan window if initiated
+ * during BT voice
*
- * Range: 0 - 255 (ms)
+ * Range: 0 - 1000 (%)
*/
- CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR,
- CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR,
+ CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3,
- /*
- * The time after it expires no new WLAN trigger frame is trasmitted
- * in WLAN PSM / BT slave basic rate
- *
- * Range: 0 - 255 (ms)
- */
- CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR,
+ /* TODO: explain these values */
+ CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN,
+ CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN,
+ CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN,
/*
- * Configure the min and max time BT gains the antenna
- * in WLAN PSM / BT master EDR
+ * Defines whether the SG will force WLAN host to enter/exit PSM
*
- * Range: 0 - 255 (ms)
+ * Range: 1 - SG can force, 0 - host handles PSM
*/
- CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR,
- CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR,
+ CONF_SG_STA_FORCE_PS_IN_BT_SCO,
/*
- * The time after it expires no new WLAN trigger frame is trasmitted
- * in WLAN PSM / BT master EDR
+ * Defines antenna configuration (single/dual antenna)
*
- * Range: 0 - 255 (ms)
+ * Range: 0 - single antenna, 1 - dual antenna
*/
- CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR,
+ CONF_SG_ANTENNA_CONFIGURATION,
/*
- * Configure the min and max time BT gains the antenna
- * in WLAN PSM / BT slave EDR
+ * The threshold (percent) of max consecutive beacon misses before
+ * increasing priority of beacon reception.
*
- * Range: 0 - 255 (ms)
+ * Range: 0 - 100 (%)
*/
- CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR,
- CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR,
+ CONF_SG_BEACON_MISS_PERCENT,
/*
- * The time after it expires no new WLAN trigger frame is trasmitted
- * in WLAN PSM / BT slave EDR
+ * Protection time of the DHCP procedure.
*
- * Range: 0 - 255 (ms)
+ * Range: 0 - 100000 (ms)
*/
- CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR,
+ CONF_SG_DHCP_TIME,
/*
* RX guard time before the beginning of a new BT voice frame during
@@ -273,166 +276,59 @@ enum {
*/
CONF_SG_ADAPTIVE_RXT_TXT,
- /*
- * The used WLAN legacy service period during active BT ACL link
- *
- * Range: 0 - 255 (ms)
- */
- CONF_SG_PS_POLL_TIMEOUT,
+ /* TODO: explain this value */
+ CONF_SG_GENERAL_USAGE_BIT_MAP,
/*
- * The used WLAN UPSD service period during active BT ACL link
+ * Number of consecutive BT voice frames not interrupted by WLAN
*
- * Range: 0 - 255 (ms)
- */
- CONF_SG_UPSD_TIMEOUT,
-
- /*
- * Configure the min and max time BT gains the antenna
- * in WLAN Active / BT master EDR
- *
- * Range: 0 - 255 (ms)
- */
- CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR,
- CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR,
-
- /*
- * The maximum time WLAN can gain the antenna for
- * in WLAN Active / BT master EDR
- *
- * Range: 0 - 255 (ms)
- */
- CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR,
-
- /*
- * Configure the min and max time BT gains the antenna
- * in WLAN Active / BT slave EDR
- *
- * Range: 0 - 255 (ms)
- */
- CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR,
- CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR,
-
- /*
- * The maximum time WLAN can gain the antenna for
- * in WLAN Active / BT slave EDR
- *
- * Range: 0 - 255 (ms)
+ * Range: 0 - 100
*/
- CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR,
+ CONF_SG_HV3_MAX_SERVED,
/*
- * Configure the min and max time BT gains the antenna
- * in WLAN Active / BT basic rate
+ * The used WLAN legacy service period during active BT ACL link
*
* Range: 0 - 255 (ms)
*/
- CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR,
- CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR,
+ CONF_SG_PS_POLL_TIMEOUT,
/*
- * The maximum time WLAN can gain the antenna for
- * in WLAN Active / BT basic rate
+ * The used WLAN UPSD service period during active BT ACL link
*
* Range: 0 - 255 (ms)
*/
- CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR,
-
- /*
- * Compensation percentage of WLAN passive scan window if initiated
- * during BT voice
- *
- * Range: 0 - 1000 (%)
- */
- CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3,
-
- /*
- * Compensation percentage of WLAN passive scan window if initiated
- * during BT A2DP
- *
- * Range: 0 - 1000 (%)
- */
- CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP,
+ CONF_SG_UPSD_TIMEOUT,
- /*
- * Fixed time ensured for BT traffic to gain the antenna during WLAN
- * passive scan.
- *
- * Range: 0 - 1000 ms
- */
- CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME,
+ CONF_SG_CONSECUTIVE_CTS_THRESHOLD,
+ CONF_SG_STA_RX_WINDOW_AFTER_DTIM,
+ CONF_SG_STA_CONNECTION_PROTECTION_TIME,
- /*
- * Fixed time ensured for WLAN traffic to gain the antenna during WLAN
- * passive scan.
- *
- * Range: 0 - 1000 ms
- */
- CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME,
+ /* AP params */
+ CONF_AP_BEACON_MISS_TX,
+ CONF_AP_RX_WINDOW_AFTER_BEACON,
+ CONF_AP_BEACON_WINDOW_INTERVAL,
+ CONF_AP_CONNECTION_PROTECTION_TIME,
+ CONF_AP_BT_ACL_VAL_BT_SERVE_TIME,
+ CONF_AP_BT_ACL_VAL_WL_SERVE_TIME,
- /*
- * Number of consequent BT voice frames not interrupted by WLAN
- *
- * Range: 0 - 100
- */
- CONF_SG_HV3_MAX_SERVED,
-
- /*
- * Protection time of the DHCP procedure.
- *
- * Range: 0 - 100000 (ms)
- */
- CONF_SG_DHCP_TIME,
-
- /*
- * Compensation percentage of WLAN active scan window if initiated
- * during BT A2DP
- *
- * Range: 0 - 1000 (%)
- */
- CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP,
CONF_SG_TEMP_PARAM_1,
CONF_SG_TEMP_PARAM_2,
CONF_SG_TEMP_PARAM_3,
CONF_SG_TEMP_PARAM_4,
CONF_SG_TEMP_PARAM_5,
-
- /*
- * AP beacon miss
- *
- * Range: 0 - 255
- */
- CONF_SG_AP_BEACON_MISS_TX,
-
- /*
- * AP RX window length
- *
- * Range: 0 - 50
- */
- CONF_SG_RX_WINDOW_LENGTH,
-
- /*
- * AP connection protection time
- *
- * Range: 0 - 5000
- */
- CONF_SG_AP_CONNECTION_PROTECTION_TIME,
-
CONF_SG_TEMP_PARAM_6,
CONF_SG_TEMP_PARAM_7,
CONF_SG_TEMP_PARAM_8,
CONF_SG_TEMP_PARAM_9,
CONF_SG_TEMP_PARAM_10,
- CONF_SG_STA_PARAMS_MAX = CONF_SG_TEMP_PARAM_5 + 1,
- CONF_SG_AP_PARAMS_MAX = CONF_SG_TEMP_PARAM_10 + 1,
-
+ CONF_SG_PARAMS_MAX,
CONF_SG_PARAMS_ALL = 0xff
};
struct conf_sg_settings {
- u32 sta_params[CONF_SG_STA_PARAMS_MAX];
- u32 ap_params[CONF_SG_AP_PARAMS_MAX];
+ u32 params[CONF_SG_PARAMS_MAX];
u8 state;
};
@@ -520,13 +416,17 @@ struct conf_rx_settings {
u8 queue_type;
};
-#define CONF_TX_MAX_RATE_CLASSES 8
+#define CONF_TX_MAX_RATE_CLASSES 10
#define CONF_TX_RATE_MASK_UNSPECIFIED 0
#define CONF_TX_RATE_MASK_BASIC (CONF_HW_BIT_RATE_1MBPS | \
CONF_HW_BIT_RATE_2MBPS)
#define CONF_TX_RATE_RETRY_LIMIT 10
+/* basic rates for p2p operations (probe req/resp, etc.) */
+#define CONF_TX_RATE_MASK_BASIC_P2P (CONF_HW_BIT_RATE_6MBPS | \
+ CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS)
+
/*
* Rates supported for data packets when operating as AP. Note the absence
* of the 22Mbps rate. There is a FW limitation on 12 rates so we must drop
@@ -545,6 +445,11 @@ struct conf_rx_settings {
CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \
CONF_HW_BIT_RATE_54MBPS)
+#define CONF_TX_MCS_RATES (CONF_HW_BIT_RATE_MCS_0 | \
+ CONF_HW_BIT_RATE_MCS_1 | CONF_HW_BIT_RATE_MCS_2 | \
+ CONF_HW_BIT_RATE_MCS_3 | CONF_HW_BIT_RATE_MCS_4 | \
+ CONF_HW_BIT_RATE_MCS_5 | CONF_HW_BIT_RATE_MCS_6 | \
+ CONF_HW_BIT_RATE_MCS_7)
/*
* Default rates for management traffic when operating in AP mode. This
@@ -553,12 +458,10 @@ struct conf_rx_settings {
#define CONF_TX_AP_DEFAULT_MGMT_RATES (CONF_HW_BIT_RATE_1MBPS | \
CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS)
-/*
- * Default rates for working as IBSS. use 11b rates
- */
+/* default rates for working as IBSS (11b and OFDM) */
#define CONF_TX_IBSS_DEFAULT_RATES (CONF_HW_BIT_RATE_1MBPS | \
CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \
- CONF_HW_BIT_RATE_11MBPS);
+ CONF_HW_BIT_RATE_11MBPS | CONF_TX_OFDM_RATES);
struct conf_tx_rate_class {
@@ -661,6 +564,9 @@ struct conf_tx_ac_category {
#define CONF_TX_MAX_TID_COUNT 8
+/* Allow TX BA on all TIDs but 6,7. These are currently reserved in the FW */
+#define CONF_TX_BA_ENABLED_TID_BITMAP 0x3F
+
enum {
CONF_CHANNEL_TYPE_DCF = 0, /* DC/LEGACY*/
CONF_CHANNEL_TYPE_EDCF = 1, /* EDCA*/
@@ -913,7 +819,7 @@ struct conf_conn_settings {
struct conf_bcn_filt_rule bcn_filt_ie[CONF_MAX_BCN_FILT_IE_COUNT];
/*
- * The number of consequtive beacons to lose, before the firmware
+ * The number of consecutive beacons to lose, before the firmware
* becomes out of synch.
*
* Range: u32
@@ -951,7 +857,7 @@ struct conf_conn_settings {
u8 rx_broadcast_in_ps;
/*
- * Consequtive PS Poll failures before sending event to driver
+ * Consecutive PS Poll failures before sending event to driver
*
* Range: u8
*/
@@ -1012,14 +918,6 @@ struct conf_conn_settings {
u8 psm_entry_nullfunc_retries;
/*
- * Specifies the time to linger in active mode after successfully
- * transmitting the PSM entry null-func frame.
- *
- * Range 0 - 255 TU's
- */
- u8 psm_entry_hangover_period;
-
- /*
*
* Specifies the interval of the connection keep-alive null-func
* frame in ms.
@@ -1199,8 +1097,12 @@ struct conf_rf_settings {
};
struct conf_ht_setting {
- u16 tx_ba_win_size;
+ u8 rx_ba_win_size;
+ u8 tx_ba_win_size;
u16 inactivity_timeout;
+
+ /* bitmap of enabled TIDs for TX BA sessions */
+ u8 tx_ba_tid_bitmap;
};
struct conf_memory_settings {
@@ -1309,6 +1211,39 @@ struct conf_fwlog {
u8 threshold;
};
+#define ACX_RATE_MGMT_NUM_OF_RATES 13
+struct conf_rate_policy_settings {
+ u16 rate_retry_score;
+ u16 per_add;
+ u16 per_th1;
+ u16 per_th2;
+ u16 max_per;
+ u8 inverse_curiosity_factor;
+ u8 tx_fail_low_th;
+ u8 tx_fail_high_th;
+ u8 per_alpha_shift;
+ u8 per_add_shift;
+ u8 per_beta1_shift;
+ u8 per_beta2_shift;
+ u8 rate_check_up;
+ u8 rate_check_down;
+ u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES];
+};
+
+struct conf_hangover_settings {
+ u32 recover_time;
+ u8 hangover_period;
+ u8 dynamic_mode;
+ u8 early_termination_mode;
+ u8 max_period;
+ u8 min_period;
+ u8 increase_delta;
+ u8 decrease_delta;
+ u8 quiet_time;
+ u8 increase_time;
+ u8 window_size;
+};
+
struct conf_drv_settings {
struct conf_sg_settings sg;
struct conf_rx_settings rx;
@@ -1326,6 +1261,8 @@ struct conf_drv_settings {
struct conf_fm_coex fm_coex;
struct conf_rx_streaming_settings rx_streaming;
struct conf_fwlog fwlog;
+ struct conf_rate_policy_settings rate;
+ struct conf_hangover_settings hangover;
u8 hci_io_ds;
};
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index 37934b5601cd..3999fd528302 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -265,18 +265,10 @@ static ssize_t gpio_power_write(struct file *file,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
- char buf[10];
- size_t len;
unsigned long value;
int ret;
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len)) {
- return -EFAULT;
- }
- buf[len] = '\0';
-
- ret = kstrtoul(buf, 0, &value);
+ ret = kstrtoul_from_user(user_buf, count, 10, &value);
if (ret < 0) {
wl1271_warning("illegal value in gpio_power");
return -EINVAL;
@@ -339,10 +331,11 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
#define DRIVER_STATE_PRINT_HEX(x) DRIVER_STATE_PRINT(x, "0x%x")
DRIVER_STATE_PRINT_INT(tx_blocks_available);
- DRIVER_STATE_PRINT_INT(tx_allocated_blocks[0]);
- DRIVER_STATE_PRINT_INT(tx_allocated_blocks[1]);
- DRIVER_STATE_PRINT_INT(tx_allocated_blocks[2]);
- DRIVER_STATE_PRINT_INT(tx_allocated_blocks[3]);
+ DRIVER_STATE_PRINT_INT(tx_allocated_blocks);
+ DRIVER_STATE_PRINT_INT(tx_allocated_pkts[0]);
+ DRIVER_STATE_PRINT_INT(tx_allocated_pkts[1]);
+ DRIVER_STATE_PRINT_INT(tx_allocated_pkts[2]);
+ DRIVER_STATE_PRINT_INT(tx_allocated_pkts[3]);
DRIVER_STATE_PRINT_INT(tx_frames_cnt);
DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]);
DRIVER_STATE_PRINT_INT(tx_queue_count[0]);
@@ -352,10 +345,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
DRIVER_STATE_PRINT_INT(tx_packets_count);
DRIVER_STATE_PRINT_INT(tx_results_count);
DRIVER_STATE_PRINT_LHEX(flags);
- DRIVER_STATE_PRINT_INT(tx_blocks_freed[0]);
- DRIVER_STATE_PRINT_INT(tx_blocks_freed[1]);
- DRIVER_STATE_PRINT_INT(tx_blocks_freed[2]);
- DRIVER_STATE_PRINT_INT(tx_blocks_freed[3]);
+ DRIVER_STATE_PRINT_INT(tx_blocks_freed);
DRIVER_STATE_PRINT_INT(tx_security_last_seq_lsb);
DRIVER_STATE_PRINT_INT(rx_counter);
DRIVER_STATE_PRINT_INT(session_counter);
@@ -369,9 +359,6 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
DRIVER_STATE_PRINT_INT(beacon_int);
DRIVER_STATE_PRINT_INT(psm_entry_retry);
DRIVER_STATE_PRINT_INT(ps_poll_failures);
- DRIVER_STATE_PRINT_HEX(filters);
- DRIVER_STATE_PRINT_HEX(rx_config);
- DRIVER_STATE_PRINT_HEX(rx_filter);
DRIVER_STATE_PRINT_INT(power_level);
DRIVER_STATE_PRINT_INT(rssi_thold);
DRIVER_STATE_PRINT_INT(last_rssi_event);
@@ -432,17 +419,10 @@ static ssize_t dtim_interval_write(struct file *file,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
- char buf[10];
- size_t len;
unsigned long value;
int ret;
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
- buf[len] = '\0';
-
- ret = kstrtoul(buf, 0, &value);
+ ret = kstrtoul_from_user(user_buf, count, 10, &value);
if (ret < 0) {
wl1271_warning("illegal value for dtim_interval");
return -EINVAL;
@@ -497,17 +477,10 @@ static ssize_t beacon_interval_write(struct file *file,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
- char buf[10];
- size_t len;
unsigned long value;
int ret;
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
- buf[len] = '\0';
-
- ret = kstrtoul(buf, 0, &value);
+ ret = kstrtoul_from_user(user_buf, count, 10, &value);
if (ret < 0) {
wl1271_warning("illegal value for beacon_interval");
return -EINVAL;
@@ -547,17 +520,10 @@ static ssize_t rx_streaming_interval_write(struct file *file,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
- char buf[10];
- size_t len;
unsigned long value;
int ret;
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
- buf[len] = '\0';
-
- ret = kstrtoul(buf, 0, &value);
+ ret = kstrtoul_from_user(user_buf, count, 10, &value);
if (ret < 0) {
wl1271_warning("illegal value in rx_streaming_interval!");
return -EINVAL;
@@ -606,17 +572,10 @@ static ssize_t rx_streaming_always_write(struct file *file,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
- char buf[10];
- size_t len;
unsigned long value;
int ret;
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
- buf[len] = '\0';
-
- ret = kstrtoul(buf, 0, &value);
+ ret = kstrtoul_from_user(user_buf, count, 10, &value);
if (ret < 0) {
wl1271_warning("illegal value in rx_streaming_write!");
return -EINVAL;
@@ -660,6 +619,47 @@ static const struct file_operations rx_streaming_always_ops = {
.llseek = default_llseek,
};
+static ssize_t beacon_filtering_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ char buf[10];
+ size_t len;
+ unsigned long value;
+ int ret;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+ buf[len] = '\0';
+
+ ret = kstrtoul(buf, 0, &value);
+ if (ret < 0) {
+ wl1271_warning("illegal value for beacon_filtering!");
+ return -EINVAL;
+ }
+
+ mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1271_acx_beacon_filter_opt(wl, !!value);
+
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+ return count;
+}
+
+static const struct file_operations beacon_filtering_ops = {
+ .write = beacon_filtering_write,
+ .open = wl1271_open_file_generic,
+ .llseek = default_llseek,
+};
+
static int wl1271_debugfs_add_files(struct wl1271 *wl,
struct dentry *rootdir)
{
@@ -772,6 +772,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
DEBUGFS_ADD(driver_state, rootdir);
DEBUGFS_ADD(dtim_interval, rootdir);
DEBUGFS_ADD(beacon_interval, rootdir);
+ DEBUGFS_ADD(beacon_filtering, rootdir);
streaming = debugfs_create_dir("rx_streaming", rootdir);
if (!streaming || IS_ERR(streaming))
diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c
index 304aaa2ee011..674ad2a9e409 100644
--- a/drivers/net/wireless/wl12xx/event.c
+++ b/drivers/net/wireless/wl12xx/event.c
@@ -171,19 +171,26 @@ static void wl1271_event_rssi_trigger(struct wl1271 *wl,
wl->last_rssi_event = event;
}
-static void wl1271_stop_ba_event(struct wl1271 *wl, u8 ba_allowed)
+static void wl1271_stop_ba_event(struct wl1271 *wl)
{
- /* Convert the value to bool */
- wl->ba_allowed = !!ba_allowed;
-
- /*
- * Return in case:
- * there are not BA open or the event indication is to allowed BA
- */
- if ((!wl->ba_rx_bitmap) || (wl->ba_allowed))
- return;
+ if (wl->bss_type != BSS_TYPE_AP_BSS) {
+ if (!wl->ba_rx_bitmap)
+ return;
+ ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap,
+ wl->bssid);
+ } else {
+ int i;
+ struct wl1271_link *lnk;
+ for (i = WL1271_AP_STA_HLID_START; i < AP_MAX_LINKS; i++) {
+ lnk = &wl->links[i];
+ if (!wl1271_is_active_sta(wl, i) || !lnk->ba_bitmap)
+ continue;
- ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap, wl->bssid);
+ ieee80211_stop_rx_ba_session(wl->vif,
+ lnk->ba_bitmap,
+ lnk->addr);
+ }
+ }
}
static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl,
@@ -283,15 +290,32 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
wl1271_event_rssi_trigger(wl, mbox);
}
- if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) && !is_ap) {
+ if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID)) {
wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. "
- "ba_allowed = 0x%x", mbox->ba_allowed);
+ "ba_allowed = 0x%x", mbox->rx_ba_allowed);
- if (wl->vif)
- wl1271_stop_ba_event(wl, mbox->ba_allowed);
+ wl->ba_allowed = !!mbox->rx_ba_allowed;
+
+ if (wl->vif && !wl->ba_allowed)
+ wl1271_stop_ba_event(wl);
+ }
+
+ if ((vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) && !is_ap) {
+ wl1271_debug(DEBUG_EVENT, "CHANNEL_SWITCH_COMPLETE_EVENT_ID. "
+ "status = 0x%x",
+ mbox->channel_switch_status);
+ /*
+ * That event uses for two cases:
+ * 1) channel switch complete with status=0
+ * 2) channel switch failed status=1
+ */
+ if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags) &&
+ (wl->vif))
+ ieee80211_chswitch_done(wl->vif,
+ mbox->channel_switch_status ? false : true);
}
- if ((vector & DUMMY_PACKET_EVENT_ID) && !is_ap) {
+ if ((vector & DUMMY_PACKET_EVENT_ID)) {
wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
if (wl->vif)
wl1271_tx_dummy_packet(wl);
diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h
index e524ad6fe4e3..49c1a0ede5b1 100644
--- a/drivers/net/wireless/wl12xx/event.h
+++ b/drivers/net/wireless/wl12xx/event.h
@@ -49,32 +49,27 @@ enum {
MEASUREMENT_START_EVENT_ID = BIT(8),
MEASUREMENT_COMPLETE_EVENT_ID = BIT(9),
SCAN_COMPLETE_EVENT_ID = BIT(10),
- SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(11),
+ WFD_DISCOVERY_COMPLETE_EVENT_ID = BIT(11),
AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12),
PS_REPORT_EVENT_ID = BIT(13),
PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14),
DISCONNECT_EVENT_COMPLETE_ID = BIT(15),
- JOIN_EVENT_COMPLETE_ID = BIT(16),
+ /* BIT(16) is reserved */
CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17),
BSS_LOSE_EVENT_ID = BIT(18),
REGAINED_BSS_EVENT_ID = BIT(19),
MAX_TX_RETRY_EVENT_ID = BIT(20),
- /* STA: dummy paket for dynamic mem blocks */
- DUMMY_PACKET_EVENT_ID = BIT(21),
- /* AP: STA remove complete */
- STA_REMOVE_COMPLETE_EVENT_ID = BIT(21),
+ DUMMY_PACKET_EVENT_ID = BIT(21),
SOFT_GEMINI_SENSE_EVENT_ID = BIT(22),
- /* STA: SG prediction */
- SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23),
- /* AP: Inactive STA */
- INACTIVE_STA_EVENT_ID = BIT(23),
+ CHANGE_AUTO_MODE_TIMEOUT_EVENT_ID = BIT(23),
SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24),
PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25),
- DBG_EVENT_ID = BIT(26),
- HEALTH_CHECK_REPLY_EVENT_ID = BIT(27),
+ INACTIVE_STA_EVENT_ID = BIT(26),
+ PEER_REMOVE_COMPLETE_EVENT_ID = BIT(27),
PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(28),
PERIODIC_SCAN_REPORT_EVENT_ID = BIT(29),
BA_SESSION_RX_CONSTRAINT_EVENT_ID = BIT(30),
+ REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(31),
EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff,
};
@@ -83,15 +78,6 @@ enum {
EVENT_ENTER_POWER_SAVE_SUCCESS,
};
-struct event_debug_report {
- u8 debug_event_id;
- u8 num_params;
- __le16 pad;
- __le32 report_1;
- __le32 report_2;
- __le32 report_3;
-} __packed;
-
#define NUM_OF_RSSI_SNR_TRIGGERS 8
struct event_mailbox {
@@ -100,49 +86,45 @@ struct event_mailbox {
__le32 reserved_1;
__le32 reserved_2;
- u8 dbg_event_id;
- u8 num_relevant_params;
- __le16 reserved_3;
- __le32 event_report_p1;
- __le32 event_report_p2;
- __le32 event_report_p3;
-
u8 number_of_scan_results;
u8 scan_tag;
- u8 reserved_4[2];
- __le32 compl_scheduled_scan_status;
+ u8 completed_scan_status;
+ u8 reserved_3;
- __le16 scheduled_scan_attended_channels;
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 scheduled_scan_status;
u8 ps_status;
+ /* tuned channel (roc) */
+ u8 roc_channel;
- /* AP FW only */
- u8 hlid_removed;
+ __le16 hlid_removed_bitmap;
- /* a bitmap of hlids for stations that have been inactive too long */
+ /* bitmap of aged stations (by HLID) */
__le16 sta_aging_status;
- /* a bitmap of hlids for stations which didn't respond to TX */
+ /* bitmap of stations (by HLID) which exceeded max tx retries */
__le16 sta_tx_retry_exceeded;
- /*
- * Bitmap, Each bit set represents the Role ID for which this constraint
- * is set. Range: 0 - FF, FF means ANY role
- */
- u8 ba_role_id;
- /*
- * Bitmap, Each bit set represents the Link ID for which this constraint
- * is set. Not applicable if ba_role_id is set to ANY role (FF).
- * Range: 0 - FFFF, FFFF means ANY link in that role
- */
- u8 ba_link_id;
- u8 ba_allowed;
-
- u8 reserved_5[21];
+ /* discovery completed results */
+ u8 discovery_tag;
+ u8 number_of_preq_results;
+ u8 number_of_prsp_results;
+ u8 reserved_5;
+
+ /* rx ba constraint */
+ u8 role_id; /* 0xFF means any role. */
+ u8 rx_ba_allowed;
+ u8 reserved_6[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];
} __packed;
int wl1271_event_unmask(struct wl1271 *wl);
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index c3e9a2e4410e..04db64c94e9a 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -39,13 +39,13 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl)
/* send empty templates for fw memory reservation */
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
- WL1271_CMD_TEMPL_MAX_SIZE,
+ WL1271_CMD_TEMPL_DFLT_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_MAX_SIZE, 0,
+ NULL, WL1271_CMD_TEMPL_DFLT_SIZE, 0,
WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
@@ -70,15 +70,13 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl)
return ret;
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL,
- sizeof
- (struct wl12xx_probe_resp_template),
+ WL1271_CMD_TEMPL_DFLT_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL,
- sizeof
- (struct wl12xx_beacon_template),
+ WL1271_CMD_TEMPL_DFLT_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
@@ -92,7 +90,7 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl)
for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL,
- WL1271_CMD_TEMPL_MAX_SIZE, i,
+ WL1271_CMD_TEMPL_DFLT_SIZE, i,
WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
@@ -105,6 +103,7 @@ static int wl1271_ap_init_deauth_template(struct wl1271 *wl)
{
struct wl12xx_disconn_template *tmpl;
int ret;
+ u32 rate;
tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
if (!tmpl) {
@@ -115,9 +114,9 @@ static int wl1271_ap_init_deauth_template(struct wl1271 *wl)
tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_DEAUTH);
+ rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP,
- tmpl, sizeof(*tmpl), 0,
- wl1271_tx_min_rate_get(wl));
+ tmpl, sizeof(*tmpl), 0, rate);
out:
kfree(tmpl);
@@ -128,6 +127,7 @@ static int wl1271_ap_init_null_template(struct wl1271 *wl)
{
struct ieee80211_hdr_3addr *nullfunc;
int ret;
+ u32 rate;
nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL);
if (!nullfunc) {
@@ -144,9 +144,9 @@ static int wl1271_ap_init_null_template(struct wl1271 *wl)
memcpy(nullfunc->addr2, wl->mac_addr, ETH_ALEN);
memcpy(nullfunc->addr3, wl->mac_addr, ETH_ALEN);
+ rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, nullfunc,
- sizeof(*nullfunc), 0,
- wl1271_tx_min_rate_get(wl));
+ sizeof(*nullfunc), 0, rate);
out:
kfree(nullfunc);
@@ -157,6 +157,7 @@ static int wl1271_ap_init_qos_null_template(struct wl1271 *wl)
{
struct ieee80211_qos_hdr *qosnull;
int ret;
+ u32 rate;
qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL);
if (!qosnull) {
@@ -173,9 +174,9 @@ static int wl1271_ap_init_qos_null_template(struct wl1271 *wl)
memcpy(qosnull->addr2, wl->mac_addr, ETH_ALEN);
memcpy(qosnull->addr3, wl->mac_addr, ETH_ALEN);
+ rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, qosnull,
- sizeof(*qosnull), 0,
- wl1271_tx_min_rate_get(wl));
+ sizeof(*qosnull), 0, rate);
out:
kfree(qosnull);
@@ -191,15 +192,13 @@ static int wl1271_ap_init_templates_config(struct wl1271 *wl)
* reserve memory for later.
*/
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_PROBE_RESPONSE, NULL,
- sizeof
- (struct wl12xx_probe_resp_template),
+ 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,
- sizeof
- (struct wl12xx_beacon_template),
+ WL1271_CMD_TEMPL_MAX_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
@@ -227,7 +226,7 @@ static int wl1271_ap_init_templates_config(struct wl1271 *wl)
return 0;
}
-static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter)
+static int wl12xx_init_rx_config(struct wl1271 *wl)
{
int ret;
@@ -235,10 +234,6 @@ static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter)
if (ret < 0)
return ret;
- ret = wl1271_acx_rx_config(wl, config, filter);
- if (ret < 0)
- return ret;
-
return 0;
}
@@ -285,10 +280,7 @@ int wl1271_init_pta(struct wl1271 *wl)
{
int ret;
- if (wl->bss_type == BSS_TYPE_AP_BSS)
- ret = wl1271_acx_ap_sg_cfg(wl);
- else
- ret = wl1271_acx_sta_sg_cfg(wl);
+ ret = wl12xx_acx_sg_cfg(wl);
if (ret < 0)
return ret;
@@ -392,7 +384,7 @@ static int wl1271_sta_hw_init(struct wl1271 *wl)
if (ret < 0)
return ret;
- ret = wl1271_acx_sta_mem_cfg(wl);
+ ret = wl12xx_acx_mem_cfg(wl);
if (ret < 0)
return ret;
@@ -408,12 +400,6 @@ static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl)
{
int ret, i;
- ret = wl1271_cmd_set_sta_default_wep_key(wl, wl->default_key);
- if (ret < 0) {
- wl1271_warning("couldn't set default key");
- return ret;
- }
-
/* disable all keep-alive templates */
for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
ret = wl1271_acx_keep_alive_config(wl, i,
@@ -451,7 +437,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl)
if (ret < 0)
return ret;
- ret = wl1271_acx_ap_mem_cfg(wl);
+ ret = wl12xx_acx_mem_cfg(wl);
if (ret < 0)
return ret;
@@ -483,7 +469,7 @@ int wl1271_ap_init_templates(struct wl1271 *wl)
* when operating as AP we want to receive external beacons for
* configuring ERP protection.
*/
- ret = wl1271_acx_set_ap_beacon_filter(wl, false);
+ ret = wl1271_acx_beacon_filter_opt(wl, false);
if (ret < 0)
return ret;
@@ -515,7 +501,7 @@ int wl1271_init_ap_rates(struct wl1271 *wl)
return ret;
/* use the min basic rate for AP broadcast/multicast */
- rc.enabled_rates = wl1271_tx_min_rate_get(wl);
+ rc.enabled_rates = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
rc.short_retry_limit = 10;
rc.long_retry_limit = 10;
rc.aflags = 0;
@@ -532,6 +518,9 @@ int wl1271_init_ap_rates(struct wl1271 *wl)
else
supported_rates = CONF_TX_AP_ENABLED_RATES;
+ /* unconditionally enable HT rates */
+ supported_rates |= CONF_TX_MCS_RATES;
+
/* configure unicast TX rate classes */
for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
rc.enabled_rates = supported_rates;
@@ -546,41 +535,24 @@ int wl1271_init_ap_rates(struct wl1271 *wl)
return 0;
}
-static void wl1271_check_ba_support(struct wl1271 *wl)
-{
- /* validate FW cose ver x.x.x.50-60.x */
- if ((wl->chip.fw_ver[3] >= WL12XX_BA_SUPPORT_FW_COST_VER2_START) &&
- (wl->chip.fw_ver[3] < WL12XX_BA_SUPPORT_FW_COST_VER2_END)) {
- wl->ba_support = true;
- return;
- }
-
- wl->ba_support = false;
-}
-
static int wl1271_set_ba_policies(struct wl1271 *wl)
{
- u8 tid_index;
- int ret = 0;
-
/* Reset the BA RX indicators */
wl->ba_rx_bitmap = 0;
wl->ba_allowed = true;
+ wl->ba_rx_session_count = 0;
- /* validate that FW support BA */
- wl1271_check_ba_support(wl);
+ /* BA is supported in STA/AP modes */
+ if (wl->bss_type != BSS_TYPE_AP_BSS &&
+ wl->bss_type != BSS_TYPE_STA_BSS) {
+ wl->ba_support = false;
+ return 0;
+ }
- if (wl->ba_support)
- /* 802.11n initiator BA session setting */
- for (tid_index = 0; tid_index < CONF_TX_MAX_TID_COUNT;
- ++tid_index) {
- ret = wl1271_acx_set_ba_session(wl, WLAN_BACK_INITIATOR,
- tid_index, true);
- if (ret < 0)
- break;
- }
+ wl->ba_support = true;
- return ret;
+ /* 802.11n initiator BA session setting */
+ return wl12xx_acx_set_ba_initiator_policy(wl);
}
int wl1271_chip_specific_init(struct wl1271 *wl)
@@ -650,11 +622,7 @@ int wl1271_hw_init(struct wl1271 *wl)
return ret;
/* RX config */
- ret = wl1271_init_rx_config(wl,
- RX_CFG_PROMISCUOUS | RX_CFG_TSF,
- RX_FILTER_OPTION_DEF);
- /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS,
- RX_FILTER_OPTION_FILTER_ALL); */
+ ret = wl12xx_init_rx_config(wl);
if (ret < 0)
goto out_free_memmap;
@@ -733,11 +701,20 @@ int wl1271_hw_init(struct wl1271 *wl)
if (ret < 0)
goto out_free_memmap;
+ ret = wl12xx_acx_set_rate_mgmt_params(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
/* Configure initiator BA sessions policies */
ret = wl1271_set_ba_policies(wl);
if (ret < 0)
goto out_free_memmap;
+ /* configure hangover */
+ ret = wl12xx_acx_config_hangover(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
return 0;
out_free_memmap:
diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h
index a2fe4f506ada..e839341dfafe 100644
--- a/drivers/net/wireless/wl12xx/io.h
+++ b/drivers/net/wireless/wl12xx/io.h
@@ -186,6 +186,5 @@ int wl1271_free_hw(struct wl1271 *wl);
irqreturn_t wl1271_irq(int irq, void *data);
bool wl1271_set_block_size(struct wl1271 *wl);
int wl1271_tx_dummy_packet(struct wl1271 *wl);
-void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters);
#endif
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index e58c22d21e39..884f82b63219 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -52,110 +52,67 @@
static struct conf_drv_settings default_conf = {
.sg = {
- .sta_params = {
- [CONF_SG_BT_PER_THRESHOLD] = 7500,
- [CONF_SG_HV3_MAX_OVERRIDE] = 0,
- [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
- [CONF_SG_BT_LOAD_RATIO] = 200,
- [CONF_SG_AUTO_PS_MODE] = 1,
- [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
- [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
- [CONF_SG_ANTENNA_CONFIGURATION] = 0,
- [CONF_SG_BEACON_MISS_PERCENT] = 60,
- [CONF_SG_RATE_ADAPT_THRESH] = 12,
- [CONF_SG_RATE_ADAPT_SNR] = 0,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
- [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
- /* Note: with UPSD, this should be 4 */
- [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
- [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
- /* Note: with UPDS, this should be 15 */
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
- /* Note: with UPDS, this should be 50 */
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
- /* Note: with UPDS, this should be 10 */
- [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
- [CONF_SG_RXT] = 1200,
- [CONF_SG_TXT] = 1000,
- [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
- [CONF_SG_PS_POLL_TIMEOUT] = 10,
- [CONF_SG_UPSD_TIMEOUT] = 10,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
- [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
- [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
- [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
- [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
- [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
- [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
- [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
- [CONF_SG_HV3_MAX_SERVED] = 6,
- [CONF_SG_DHCP_TIME] = 5000,
- [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
- },
- .ap_params = {
- [CONF_SG_BT_PER_THRESHOLD] = 7500,
- [CONF_SG_HV3_MAX_OVERRIDE] = 0,
- [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
- [CONF_SG_BT_LOAD_RATIO] = 50,
- [CONF_SG_AUTO_PS_MODE] = 1,
- [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
- [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
- [CONF_SG_ANTENNA_CONFIGURATION] = 0,
- [CONF_SG_BEACON_MISS_PERCENT] = 60,
- [CONF_SG_RATE_ADAPT_THRESH] = 64,
- [CONF_SG_RATE_ADAPT_SNR] = 1,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 25,
- [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 25,
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 25,
- [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 25,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
- [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 25,
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 25,
- [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 25,
- [CONF_SG_RXT] = 1200,
- [CONF_SG_TXT] = 1000,
- [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
- [CONF_SG_PS_POLL_TIMEOUT] = 10,
- [CONF_SG_UPSD_TIMEOUT] = 10,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
- [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
- [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
- [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
- [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
- [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
- [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
- [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
- [CONF_SG_HV3_MAX_SERVED] = 6,
- [CONF_SG_DHCP_TIME] = 5000,
- [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
- [CONF_SG_TEMP_PARAM_1] = 0,
- [CONF_SG_TEMP_PARAM_2] = 0,
- [CONF_SG_TEMP_PARAM_3] = 0,
- [CONF_SG_TEMP_PARAM_4] = 0,
- [CONF_SG_TEMP_PARAM_5] = 0,
- [CONF_SG_AP_BEACON_MISS_TX] = 3,
- [CONF_SG_RX_WINDOW_LENGTH] = 6,
- [CONF_SG_AP_CONNECTION_PROTECTION_TIME] = 50,
- [CONF_SG_TEMP_PARAM_6] = 1,
+ .params = {
+ [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
+ [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
+ [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
+ [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
+ [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
+ [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
+ [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
+ [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
+ [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
+ [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
+ [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
+ [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
+ [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
+ [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
+ [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
+ [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
+ [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
+ [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
+ [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
+ [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
+ [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
+ [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
+ [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
+ [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
+ [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
+ [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
+ /* active scan params */
+ [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
+ [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
+ [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
+ /* passive scan params */
+ [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
+ [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
+ [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
+ /* passive scan in dual antenna params */
+ [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
+ [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
+ [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
+ /* general params */
+ [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
+ [CONF_SG_ANTENNA_CONFIGURATION] = 0,
+ [CONF_SG_BEACON_MISS_PERCENT] = 60,
+ [CONF_SG_DHCP_TIME] = 5000,
+ [CONF_SG_RXT] = 1200,
+ [CONF_SG_TXT] = 1000,
+ [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
+ [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
+ [CONF_SG_HV3_MAX_SERVED] = 6,
+ [CONF_SG_PS_POLL_TIMEOUT] = 10,
+ [CONF_SG_UPSD_TIMEOUT] = 10,
+ [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
+ [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
+ [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
+ /* AP params */
+ [CONF_AP_BEACON_MISS_TX] = 3,
+ [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
+ [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
+ [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
+ [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
+ [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
},
.state = CONF_SG_PROTECTIVE,
},
@@ -279,10 +236,9 @@ static struct conf_drv_settings default_conf = {
.ps_poll_recovery_period = 700,
.bet_enable = CONF_BET_MODE_ENABLE,
.bet_max_consecutive = 50,
- .psm_entry_retries = 5,
+ .psm_entry_retries = 8,
.psm_exit_retries = 16,
.psm_entry_nullfunc_retries = 3,
- .psm_entry_hangover_period = 1,
.keep_alive_interval = 55000,
.max_listen_interval = 20,
},
@@ -310,8 +266,8 @@ static struct conf_drv_settings default_conf = {
},
.sched_scan = {
/* sched_scan requires dwell times in TU instead of TU/1000 */
- .min_dwell_time_active = 8,
- .max_dwell_time_active = 30,
+ .min_dwell_time_active = 30,
+ .max_dwell_time_active = 60,
.dwell_time_passive = 100,
.dwell_time_dfs = 150,
.num_probe_reqs = 2,
@@ -329,8 +285,10 @@ static struct conf_drv_settings default_conf = {
},
},
.ht = {
+ .rx_ba_win_size = 8,
.tx_ba_win_size = 64,
.inactivity_timeout = 10000,
+ .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
},
.mem_wl127x = {
.num_stations = 1,
@@ -379,9 +337,44 @@ static struct conf_drv_settings default_conf = {
.threshold = 0,
},
.hci_io_ds = HCI_IO_DS_6MA,
+ .rate = {
+ .rate_retry_score = 32000,
+ .per_add = 8192,
+ .per_th1 = 2048,
+ .per_th2 = 4096,
+ .max_per = 8100,
+ .inverse_curiosity_factor = 5,
+ .tx_fail_low_th = 4,
+ .tx_fail_high_th = 10,
+ .per_alpha_shift = 4,
+ .per_add_shift = 13,
+ .per_beta1_shift = 10,
+ .per_beta2_shift = 8,
+ .rate_check_up = 2,
+ .rate_check_down = 12,
+ .rate_retry_policy = {
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00,
+ },
+ },
+ .hangover = {
+ .recover_time = 0,
+ .hangover_period = 20,
+ .dynamic_mode = 1,
+ .early_termination_mode = 1,
+ .max_period = 20,
+ .min_period = 1,
+ .increase_delta = 1,
+ .decrease_delta = 2,
+ .quiet_time = 4,
+ .increase_time = 1,
+ .window_size = 16,
+ },
};
static char *fwlog_param;
+static bool bug_on_recovery;
static void __wl1271_op_remove_interface(struct wl1271 *wl,
bool reset_tx_queues);
@@ -415,10 +408,12 @@ static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate)
if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags))
return 0;
- ret = wl1271_cmd_set_sta_state(wl);
+ ret = wl12xx_cmd_set_peer_state(wl, wl->sta_hlid);
if (ret < 0)
return ret;
+ wl12xx_croc(wl, wl->role_id);
+
wl1271_info("Association completed.");
return 0;
}
@@ -718,7 +713,7 @@ static int wl1271_plt_init(struct wl1271 *wl)
if (ret < 0)
goto out_free_memmap;
- ret = wl1271_acx_sta_mem_cfg(wl);
+ ret = wl12xx_acx_mem_cfg(wl);
if (ret < 0)
goto out_free_memmap;
@@ -773,33 +768,52 @@ static int wl1271_plt_init(struct wl1271 *wl)
return ret;
}
-static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
+static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts)
{
- bool fw_ps;
+ bool fw_ps, single_sta;
/* only regulate station links */
if (hlid < WL1271_AP_STA_HLID_START)
return;
fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
+ single_sta = (wl->active_sta_count == 1);
/*
* Wake up from high level PS if the STA is asleep with too little
- * blocks in FW or if the STA is awake.
+ * packets in FW or if the STA is awake.
*/
- if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
+ if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
wl1271_ps_link_end(wl, hlid);
- /* Start high-level PS if the STA is asleep with enough blocks in FW */
- else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
+ /*
+ * Start high-level PS if the STA is asleep with enough blocks in FW.
+ * Make an exception if this is the only connected station. In this
+ * case FW-memory congestion is not a problem.
+ */
+ else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
wl1271_ps_link_start(wl, hlid, true);
}
-static void wl1271_irq_update_links_status(struct wl1271 *wl,
- struct wl1271_fw_ap_status *status)
+bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
+{
+ int id;
+
+ /* global/broadcast "stations" are always active */
+ if (hlid < WL1271_AP_STA_HLID_START)
+ return true;
+
+ id = hlid - WL1271_AP_STA_HLID_START;
+ return test_bit(id, wl->ap_hlid_map);
+}
+
+static void wl12xx_irq_update_links_status(struct wl1271 *wl,
+ struct wl12xx_fw_status *status)
{
u32 cur_fw_ps_map;
- u8 hlid;
+ u8 hlid, cnt;
+
+ /* TODO: also use link_fast_bitmap here */
cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
if (wl->ap_fw_ps_map != cur_fw_ps_map) {
@@ -812,45 +826,30 @@ static void wl1271_irq_update_links_status(struct wl1271 *wl,
}
for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
- u8 cnt = status->tx_lnk_free_blks[hlid] -
- wl->links[hlid].prev_freed_blks;
-
- wl->links[hlid].prev_freed_blks =
- status->tx_lnk_free_blks[hlid];
- wl->links[hlid].allocated_blks -= cnt;
-
- wl1271_irq_ps_regulate_link(wl, hlid,
- wl->links[hlid].allocated_blks);
- }
-}
+ if (!wl1271_is_active_sta(wl, hlid))
+ continue;
-static u32 wl1271_tx_allocated_blocks(struct wl1271 *wl)
-{
- int i;
- u32 total_alloc_blocks = 0;
+ cnt = status->tx_lnk_free_pkts[hlid] -
+ wl->links[hlid].prev_freed_pkts;
- for (i = 0; i < NUM_TX_QUEUES; i++)
- total_alloc_blocks += wl->tx_allocated_blocks[i];
+ wl->links[hlid].prev_freed_pkts =
+ status->tx_lnk_free_pkts[hlid];
+ wl->links[hlid].allocated_pkts -= cnt;
- return total_alloc_blocks;
+ wl12xx_irq_ps_regulate_link(wl, hlid,
+ wl->links[hlid].allocated_pkts);
+ }
}
-static void wl1271_fw_status(struct wl1271 *wl,
- struct wl1271_fw_full_status *full_status)
+static void wl12xx_fw_status(struct wl1271 *wl,
+ struct wl12xx_fw_status *status)
{
- struct wl1271_fw_common_status *status = &full_status->common;
struct timespec ts;
u32 old_tx_blk_count = wl->tx_blocks_available;
- u32 freed_blocks = 0, ac_freed_blocks;
+ int avail, freed_blocks;
int i;
- if (wl->bss_type == BSS_TYPE_AP_BSS) {
- wl1271_raw_read(wl, FW_STATUS_ADDR, status,
- sizeof(struct wl1271_fw_ap_status), false);
- } else {
- wl1271_raw_read(wl, FW_STATUS_ADDR, status,
- sizeof(struct wl1271_fw_sta_status), false);
- }
+ wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
"drv_rx_counter = %d, tx_results_counter = %d)",
@@ -859,42 +858,49 @@ static void wl1271_fw_status(struct wl1271 *wl,
status->drv_rx_counter,
status->tx_results_counter);
- /* update number of available TX blocks */
for (i = 0; i < NUM_TX_QUEUES; i++) {
- ac_freed_blocks = le32_to_cpu(status->tx_released_blks[i]) -
- wl->tx_blocks_freed[i];
- freed_blocks += ac_freed_blocks;
-
- wl->tx_allocated_blocks[i] -= ac_freed_blocks;
+ /* prevent wrap-around in freed-packets counter */
+ wl->tx_allocated_pkts[i] -=
+ (status->tx_released_pkts[i] -
+ wl->tx_pkts_freed[i]) & 0xff;
- wl->tx_blocks_freed[i] =
- le32_to_cpu(status->tx_released_blks[i]);
+ wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
}
- if (wl->bss_type == BSS_TYPE_AP_BSS) {
- /* Update num of allocated TX blocks per link and ps status */
- wl1271_irq_update_links_status(wl, &full_status->ap);
- wl->tx_blocks_available += freed_blocks;
- } else {
- int avail = full_status->sta.tx_total -
- wl1271_tx_allocated_blocks(wl);
+ /* prevent wrap-around in total blocks counter */
+ if (likely(wl->tx_blocks_freed <=
+ le32_to_cpu(status->total_released_blks)))
+ freed_blocks = le32_to_cpu(status->total_released_blks) -
+ wl->tx_blocks_freed;
+ else
+ freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
+ le32_to_cpu(status->total_released_blks);
- /*
- * The FW might change the total number of TX memblocks before
- * we get a notification about blocks being released. Thus, the
- * available blocks calculation might yield a temporary result
- * which is lower than the actual available blocks. Keeping in
- * mind that only blocks that were allocated can be moved from
- * TX to RX, tx_blocks_available should never decrease here.
- */
- wl->tx_blocks_available = max((int)wl->tx_blocks_available,
- avail);
- }
+ wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
+
+ wl->tx_allocated_blocks -= freed_blocks;
+
+ avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
+
+ /*
+ * The FW might change the total number of TX memblocks before
+ * we get a notification about blocks being released. Thus, the
+ * available blocks calculation might yield a temporary result
+ * which is lower than the actual available blocks. Keeping in
+ * mind that only blocks that were allocated can be moved from
+ * TX to RX, tx_blocks_available should never decrease here.
+ */
+ wl->tx_blocks_available = max((int)wl->tx_blocks_available,
+ avail);
/* if more blocks are available now, tx work can be scheduled */
if (wl->tx_blocks_available > old_tx_blk_count)
clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
+ /* for AP update num of allocated TX blocks per link and ps status */
+ if (wl->bss_type == BSS_TYPE_AP_BSS)
+ wl12xx_irq_update_links_status(wl, status);
+
/* update the host-chipset time offset */
getnstimeofday(&ts);
wl->time_offset = (timespec_to_ns(&ts) >> 10) -
@@ -967,8 +973,8 @@ irqreturn_t wl1271_irq(int irq, void *cookie)
clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
smp_mb__after_clear_bit();
- wl1271_fw_status(wl, wl->fw_status);
- intr = le32_to_cpu(wl->fw_status->common.intr);
+ wl12xx_fw_status(wl, wl->fw_status);
+ intr = le32_to_cpu(wl->fw_status->intr);
intr &= WL1271_INTR_MASK;
if (!intr) {
done = true;
@@ -987,7 +993,7 @@ irqreturn_t wl1271_irq(int irq, void *cookie)
if (likely(intr & WL1271_ACX_INTR_DATA)) {
wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
- wl1271_rx(wl, &wl->fw_status->common);
+ wl12xx_rx(wl, wl->fw_status);
/* Check if any tx blocks were freed */
spin_lock_irqsave(&wl->wl_lock, flags);
@@ -1004,7 +1010,7 @@ irqreturn_t wl1271_irq(int irq, void *cookie)
}
/* check for tx results */
- if (wl->fw_status->common.tx_results_counter !=
+ if (wl->fw_status->tx_results_counter !=
(wl->tx_results_count & 0xff))
wl1271_tx_complete(wl);
@@ -1056,25 +1062,10 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
const char *fw_name;
int ret;
- switch (wl->bss_type) {
- case BSS_TYPE_AP_BSS:
- if (wl->chip.id == CHIP_ID_1283_PG20)
- fw_name = WL128X_AP_FW_NAME;
- else
- fw_name = WL127X_AP_FW_NAME;
- break;
- case BSS_TYPE_IBSS:
- case BSS_TYPE_STA_BSS:
- if (wl->chip.id == CHIP_ID_1283_PG20)
- fw_name = WL128X_FW_NAME;
- else
- fw_name = WL1271_FW_NAME;
- break;
- default:
- wl1271_error("no compatible firmware for bss_type %d",
- wl->bss_type);
- return -EINVAL;
- }
+ if (wl->chip.id == CHIP_ID_1283_PG20)
+ fw_name = WL128X_FW_NAME;
+ else
+ fw_name = WL127X_FW_NAME;
wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
@@ -1103,7 +1094,6 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
}
memcpy(wl->fw, fw->data, wl->fw_len);
- wl->fw_bss_type = wl->bss_type;
ret = 0;
out:
@@ -1194,8 +1184,8 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
wl12xx_cmd_stop_fwlog(wl);
/* Read the first memory block address */
- wl1271_fw_status(wl, wl->fw_status);
- first_addr = __le32_to_cpu(wl->fw_status->sta.log_start_addr);
+ wl12xx_fw_status(wl, wl->fw_status);
+ first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
if (!first_addr)
goto out;
@@ -1211,7 +1201,7 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
* of each memory block hold the hardware address of the next
* one. The last memory block points to the first one.
*/
- addr = __le32_to_cpup((__le32 *)block);
+ addr = le32_to_cpup((__le32 *)block);
if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
break;
@@ -1241,6 +1231,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);
+
/*
* Advance security sequence number to overcome potential progress
* in the firmware during recovery. This doens't hurt if the network is
@@ -1250,9 +1242,6 @@ static void wl1271_recovery_work(struct work_struct *work)
test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING;
- if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
- ieee80211_connection_loss(wl->vif);
-
/* Prevent spurious TX during FW restart */
ieee80211_stop_queues(wl->hw);
@@ -1344,14 +1333,6 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
wl->chip.id);
- /*
- * 'end-of-transaction flag' and 'LPD mode flag'
- * should be set in wl127x AP mode only
- */
- if (wl->bss_type == BSS_TYPE_AP_BSS)
- wl->quirks |= (WL12XX_QUIRK_END_OF_TRANSACTION |
- WL12XX_QUIRK_LPD_MODE);
-
ret = wl1271_setup(wl);
if (ret < 0)
goto out;
@@ -1374,8 +1355,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
goto out;
}
- /* Make sure the firmware type matches the BSS type */
- if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
+ if (wl->fw == NULL) {
ret = wl1271_fetch_firmware(wl);
if (ret < 0)
goto out;
@@ -1395,6 +1375,7 @@ out:
int wl1271_plt_start(struct wl1271 *wl)
{
int retries = WL1271_BOOT_RETRIES;
+ struct wiphy *wiphy = wl->hw->wiphy;
int ret;
mutex_lock(&wl->mutex);
@@ -1428,6 +1409,11 @@ int wl1271_plt_start(struct wl1271 *wl)
wl1271_notice("firmware booted in PLT mode (%s)",
wl->chip.fw_ver_str);
+ /* update hw/fw version info in wiphy struct */
+ wiphy->hw_version = wl->chip.id;
+ strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
+ sizeof(wiphy->fw_version));
+
goto out;
irq_disable:
@@ -1504,10 +1490,25 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
q = wl1271_tx_get_queue(mapping);
if (wl->bss_type == BSS_TYPE_AP_BSS)
- hlid = wl1271_tx_get_hlid(skb);
+ hlid = wl12xx_tx_get_hlid_ap(wl, skb);
spin_lock_irqsave(&wl->wl_lock, flags);
+ /* queue the packet */
+ if (wl->bss_type == BSS_TYPE_AP_BSS) {
+ if (!wl1271_is_active_sta(wl, hlid)) {
+ wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d",
+ hlid, q);
+ dev_kfree_skb(skb);
+ goto out;
+ }
+
+ wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
+ skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
+ } else {
+ skb_queue_tail(&wl->tx_queue[q], skb);
+ }
+
wl->tx_queue_count[q]++;
/*
@@ -1520,14 +1521,6 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
set_bit(q, &wl->stopped_queues_map);
}
- /* queue the packet */
- if (wl->bss_type == BSS_TYPE_AP_BSS) {
- wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
- skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
- } else {
- skb_queue_tail(&wl->tx_queue[q], skb);
- }
-
/*
* The chip specific setup must run before the first TX packet -
* before that, the tx_work will not be initialized!
@@ -1537,13 +1530,20 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
!test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
ieee80211_queue_work(wl->hw, &wl->tx_work);
+out:
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
int wl1271_tx_dummy_packet(struct wl1271 *wl)
{
unsigned long flags;
- int q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
+ int q;
+
+ /* no need to queue a new dummy packet if one is already pending */
+ if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
+ return 0;
+
+ q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
spin_lock_irqsave(&wl->wl_lock, flags);
set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
@@ -1673,7 +1673,7 @@ static int wl1271_configure_suspend_ap(struct wl1271 *wl)
if (ret < 0)
goto out_unlock;
- ret = wl1271_acx_set_ap_beacon_filter(wl, true);
+ ret = wl1271_acx_beacon_filter_opt(wl, true);
wl1271_ps_elp_sleep(wl);
out_unlock:
@@ -1711,7 +1711,7 @@ static void wl1271_configure_resume(struct wl1271 *wl)
wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
wl->basic_rate, true);
} else if (is_ap) {
- wl1271_acx_set_ap_beacon_filter(wl, false);
+ wl1271_acx_beacon_filter_opt(wl, false);
}
wl1271_ps_elp_sleep(wl);
@@ -1803,9 +1803,6 @@ static int wl1271_op_start(struct ieee80211_hw *hw)
*
* The MAC address is first known when the corresponding interface
* is added. That is where we will initialize the hardware.
- *
- * In addition, we currently have different firmwares for AP and managed
- * operation. We will know which to boot according to interface type.
*/
return 0;
@@ -1816,6 +1813,30 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
}
+static u8 wl12xx_get_role_type(struct wl1271 *wl)
+{
+ switch (wl->bss_type) {
+ case BSS_TYPE_AP_BSS:
+ if (wl->p2p)
+ return WL1271_ROLE_P2P_GO;
+ else
+ return WL1271_ROLE_AP;
+
+ case BSS_TYPE_STA_BSS:
+ if (wl->p2p)
+ return WL1271_ROLE_P2P_CL;
+ else
+ return WL1271_ROLE_STA;
+
+ case BSS_TYPE_IBSS:
+ return WL1271_ROLE_IBSS;
+
+ default:
+ wl1271_error("invalid bss_type: %d", wl->bss_type);
+ }
+ return WL12XX_INVALID_ROLE_TYPE;
+}
+
static int wl1271_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -1823,10 +1844,11 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
struct wiphy *wiphy = hw->wiphy;
int retries = WL1271_BOOT_RETRIES;
int ret = 0;
+ u8 role_type;
bool booted = false;
wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
- vif->type, vif->addr);
+ ieee80211_vif_type_p2p(vif), vif->addr);
mutex_lock(&wl->mutex);
if (wl->vif) {
@@ -1846,7 +1868,10 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
goto out;
}
- switch (vif->type) {
+ switch (ieee80211_vif_type_p2p(vif)) {
+ case NL80211_IFTYPE_P2P_CLIENT:
+ wl->p2p = 1;
+ /* fall-through */
case NL80211_IFTYPE_STATION:
wl->bss_type = BSS_TYPE_STA_BSS;
wl->set_bss_type = BSS_TYPE_STA_BSS;
@@ -1855,6 +1880,9 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
wl->bss_type = BSS_TYPE_IBSS;
wl->set_bss_type = BSS_TYPE_STA_BSS;
break;
+ case NL80211_IFTYPE_P2P_GO:
+ wl->p2p = 1;
+ /* fall-through */
case NL80211_IFTYPE_AP:
wl->bss_type = BSS_TYPE_AP_BSS;
break;
@@ -1863,6 +1891,11 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
goto out;
}
+ role_type = wl12xx_get_role_type(wl);
+ if (role_type == WL12XX_INVALID_ROLE_TYPE) {
+ ret = -EINVAL;
+ goto out;
+ }
memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
if (wl->state != WL1271_STATE_OFF) {
@@ -1882,6 +1915,25 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
if (ret < 0)
goto power_off;
+ if (wl->bss_type == BSS_TYPE_STA_BSS ||
+ wl->bss_type == BSS_TYPE_IBSS) {
+ /*
+ * The device role is a special role used for
+ * rx and tx frames prior to association (as
+ * the STA role can get packets only from
+ * its associated bssid)
+ */
+ ret = wl12xx_cmd_role_enable(wl,
+ WL1271_ROLE_DEVICE,
+ &wl->dev_role_id);
+ if (ret < 0)
+ goto irq_disable;
+ }
+
+ ret = wl12xx_cmd_role_enable(wl, role_type, &wl->role_id);
+ if (ret < 0)
+ goto irq_disable;
+
ret = wl1271_hw_init(wl);
if (ret < 0)
goto irq_disable;
@@ -1946,7 +1998,7 @@ out:
static void __wl1271_op_remove_interface(struct wl1271 *wl,
bool reset_tx_queues)
{
- int i;
+ int ret, i;
wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
@@ -1971,6 +2023,31 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
ieee80211_scan_completed(wl->hw, true);
}
+ if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
+ /* disable active roles */
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto deinit;
+
+ if (wl->bss_type == BSS_TYPE_STA_BSS) {
+ ret = wl12xx_cmd_role_disable(wl, &wl->dev_role_id);
+ if (ret < 0)
+ goto deinit;
+ }
+
+ ret = wl12xx_cmd_role_disable(wl, &wl->role_id);
+ if (ret < 0)
+ goto deinit;
+
+ wl1271_ps_elp_sleep(wl);
+ }
+deinit:
+ /* clear all hlids (except system_hlid) */
+ wl->sta_hlid = WL12XX_INVALID_LINK_ID;
+ wl->dev_hlid = WL12XX_INVALID_LINK_ID;
+ wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
+ wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
+
/*
* this must be before the cancel_work calls below, so that the work
* functions don't perform further work.
@@ -1997,28 +2074,41 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
wl1271_power_off(wl);
memset(wl->bssid, 0, ETH_ALEN);
- memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
+ memset(wl->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
wl->ssid_len = 0;
wl->bss_type = MAX_BSS_TYPE;
wl->set_bss_type = MAX_BSS_TYPE;
+ wl->p2p = 0;
wl->band = IEEE80211_BAND_2GHZ;
wl->rx_counter = 0;
wl->psm_entry_retry = 0;
wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
wl->tx_blocks_available = 0;
+ wl->tx_allocated_blocks = 0;
wl->tx_results_count = 0;
wl->tx_packets_count = 0;
wl->time_offset = 0;
wl->session_counter = 0;
wl->rate_set = CONF_TX_RATE_MASK_BASIC;
+ wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
+ wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
wl->vif = NULL;
- wl->filters = 0;
+ wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
wl1271_free_ap_keys(wl);
memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
wl->ap_fw_ps_map = 0;
wl->ap_ps_map = 0;
wl->sched_scanning = false;
+ wl->role_id = WL12XX_INVALID_ROLE_ID;
+ wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
+ memset(wl->roles_map, 0, sizeof(wl->roles_map));
+ memset(wl->links_map, 0, sizeof(wl->links_map));
+ memset(wl->roc_map, 0, sizeof(wl->roc_map));
+ wl->active_sta_count = 0;
+
+ /* The system link is always allocated */
+ __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
/*
* this is performed after the cancel_work calls and the associated
@@ -2027,9 +2117,11 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
*/
wl->flags = 0;
+ wl->tx_blocks_freed = 0;
+
for (i = 0; i < NUM_TX_QUEUES; i++) {
- wl->tx_blocks_freed[i] = 0;
- wl->tx_allocated_blocks[i] = 0;
+ wl->tx_pkts_freed[i] = 0;
+ wl->tx_allocated_pkts[i] = 0;
}
wl1271_debugfs_reset(wl);
@@ -2061,64 +2153,10 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
cancel_work_sync(&wl->recovery_work);
}
-void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
-{
- wl1271_set_default_filters(wl);
-
- /* combine requested filters with current filter config */
- filters = wl->filters | filters;
-
- wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
-
- if (filters & FIF_PROMISC_IN_BSS) {
- wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
- wl->rx_config &= ~CFG_UNI_FILTER_EN;
- wl->rx_config |= CFG_BSSID_FILTER_EN;
- }
- if (filters & FIF_BCN_PRBRESP_PROMISC) {
- wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
- wl->rx_config &= ~CFG_BSSID_FILTER_EN;
- wl->rx_config &= ~CFG_SSID_FILTER_EN;
- }
- if (filters & FIF_OTHER_BSS) {
- wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
- wl->rx_config &= ~CFG_BSSID_FILTER_EN;
- }
- if (filters & FIF_CONTROL) {
- wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
- wl->rx_filter |= CFG_RX_CTL_EN;
- }
- if (filters & FIF_FCSFAIL) {
- wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
- wl->rx_filter |= CFG_RX_FCS_ERROR;
- }
-}
-
-static int wl1271_dummy_join(struct wl1271 *wl)
-{
- int ret = 0;
- /* we need to use a dummy BSSID for now */
- static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
- 0xad, 0xbe, 0xef };
-
- memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
-
- /* pass through frames from all BSS */
- wl1271_configure_filters(wl, FIF_OTHER_BSS);
-
- ret = wl1271_cmd_join(wl, wl->set_bss_type);
- if (ret < 0)
- goto out;
-
- set_bit(WL1271_FLAG_JOINED, &wl->flags);
-
-out:
- return ret;
-}
-
static int wl1271_join(struct wl1271 *wl, bool set_assoc)
{
int ret;
+ bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
/*
* One of the side effects of the JOIN command is that is clears
@@ -2135,12 +2173,13 @@ static int wl1271_join(struct wl1271 *wl, bool set_assoc)
if (set_assoc)
set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
- ret = wl1271_cmd_join(wl, wl->set_bss_type);
+ if (is_ibss)
+ ret = wl12xx_cmd_role_start_ibss(wl);
+ else
+ ret = wl12xx_cmd_role_start_sta(wl);
if (ret < 0)
goto out;
- set_bit(WL1271_FLAG_JOINED, &wl->flags);
-
if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
goto out;
@@ -2175,31 +2214,41 @@ static int wl1271_unjoin(struct wl1271 *wl)
{
int ret;
+ if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags)) {
+ wl12xx_cmd_stop_channel_switch(wl);
+ ieee80211_chswitch_done(wl->vif, false);
+ }
+
/* to stop listening to a channel, we disconnect */
- ret = wl1271_cmd_disconnect(wl);
+ ret = wl12xx_cmd_role_stop_sta(wl);
if (ret < 0)
goto out;
- clear_bit(WL1271_FLAG_JOINED, &wl->flags);
memset(wl->bssid, 0, ETH_ALEN);
/* reset TX security counters on a clean disconnect */
wl->tx_security_last_seq_lsb = 0;
wl->tx_security_seq = 0;
- /* stop filtering packets based on bssid */
- wl1271_configure_filters(wl, FIF_OTHER_BSS);
-
out:
return ret;
}
static void wl1271_set_band_rate(struct wl1271 *wl)
{
- if (wl->band == IEEE80211_BAND_2GHZ)
- wl->basic_rate_set = wl->conf.tx.basic_rate;
- else
- wl->basic_rate_set = wl->conf.tx.basic_rate_5;
+ wl->basic_rate_set = wl->bitrate_masks[wl->band];
+ wl->rate_set = wl->basic_rate_set;
+}
+
+static bool wl12xx_is_roc(struct wl1271 *wl)
+{
+ u8 role_id;
+
+ role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
+ if (role_id >= WL12XX_MAX_ROLES)
+ return false;
+
+ return true;
}
static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
@@ -2207,12 +2256,17 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
int ret;
if (idle) {
- if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
- ret = wl1271_unjoin(wl);
+ /* no need to croc if we weren't busy (e.g. during boot) */
+ if (wl12xx_is_roc(wl)) {
+ ret = wl12xx_croc(wl, wl->dev_role_id);
+ if (ret < 0)
+ goto out;
+
+ ret = wl12xx_cmd_role_stop_dev(wl);
if (ret < 0)
goto out;
}
- wl->rate_set = wl1271_tx_min_rate_get(wl);
+ wl->rate_set = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
ret = wl1271_acx_sta_rate_policies(wl);
if (ret < 0)
goto out;
@@ -2223,18 +2277,17 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
goto out;
set_bit(WL1271_FLAG_IDLE, &wl->flags);
} else {
- /* increment the session counter */
- wl->session_counter++;
- if (wl->session_counter >= SESSION_COUNTER_MAX)
- wl->session_counter = 0;
-
/* The current firmware only supports sched_scan in idle */
if (wl->sched_scanning) {
wl1271_scan_sched_scan_stop(wl);
ieee80211_sched_scan_stopped(wl->hw);
}
- ret = wl1271_dummy_join(wl);
+ ret = wl12xx_cmd_role_start_dev(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wl12xx_roc(wl, wl->dev_role_id);
if (ret < 0)
goto out;
clear_bit(WL1271_FLAG_IDLE, &wl->flags);
@@ -2295,6 +2348,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
((wl->band != conf->channel->band) ||
(wl->channel != channel))) {
+ /* send all pending packets */
+ wl1271_tx_work_locked(wl);
wl->band = conf->channel->band;
wl->channel = channel;
@@ -2308,17 +2363,41 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
wl1271_set_band_rate(wl);
- wl->basic_rate = wl1271_tx_min_rate_get(wl);
+ wl->basic_rate =
+ wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
ret = wl1271_acx_sta_rate_policies(wl);
if (ret < 0)
wl1271_warning("rate policy for channel "
"failed %d", ret);
- if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
+ if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
+ if (wl12xx_is_roc(wl)) {
+ /* roaming */
+ ret = wl12xx_croc(wl, wl->dev_role_id);
+ if (ret < 0)
+ goto out_sleep;
+ }
ret = wl1271_join(wl, false);
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_is_roc(wl) &&
+ !(conf->flags & IEEE80211_CONF_IDLE)) {
+ ret = wl12xx_croc(wl, wl->dev_role_id);
+ if (ret < 0)
+ goto out_sleep;
+
+ ret = wl12xx_roc(wl, wl->dev_role_id);
+ if (ret < 0)
+ wl1271_warning("roc failed %d",
+ ret);
+ }
}
}
}
@@ -2458,18 +2537,11 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
goto out_sleep;
}
- /* determine, whether supported filter values have changed */
- if (changed == 0)
- goto out_sleep;
-
- /* configure filters */
- wl->filters = *total;
- wl1271_configure_filters(wl, 0);
-
- /* apply configured filters */
- ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
- if (ret < 0)
- goto out_sleep;
+ /*
+ * the fw doesn't provide an api to configure the filters. instead,
+ * the filters configuration is based on the active roles / ROC
+ * state.
+ */
out_sleep:
wl1271_ps_elp_sleep(wl);
@@ -2541,14 +2613,19 @@ static int wl1271_ap_init_hwenc(struct wl1271 *wl)
bool wep_key_added = false;
for (i = 0; i < MAX_NUM_KEYS; i++) {
+ u8 hlid;
if (wl->recorded_ap_keys[i] == NULL)
break;
key = wl->recorded_ap_keys[i];
+ hlid = key->hlid;
+ if (hlid == WL12XX_INVALID_LINK_ID)
+ hlid = wl->ap_bcast_hlid;
+
ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
key->id, key->key_type,
key->key_size, key->key,
- key->hlid, key->tx_seq_32,
+ hlid, key->tx_seq_32,
key->tx_seq_16);
if (ret < 0)
goto out;
@@ -2558,7 +2635,8 @@ static int wl1271_ap_init_hwenc(struct wl1271 *wl)
}
if (wep_key_added) {
- ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
+ ret = wl12xx_cmd_set_default_wep_key(wl, wl->default_key,
+ wl->ap_bcast_hlid);
if (ret < 0)
goto out;
}
@@ -2583,7 +2661,7 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
wl_sta = (struct wl1271_station *)sta->drv_priv;
hlid = wl_sta->hlid;
} else {
- hlid = WL1271_AP_BROADCAST_HLID;
+ hlid = wl->ap_bcast_hlid;
}
if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
@@ -2613,6 +2691,17 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
+ /*
+ * A STA set to GEM cipher requires 2 tx spare blocks.
+ * Return to default value when GEM cipher key is removed
+ */
+ if (key_type == KEY_GEM) {
+ if (action == KEY_ADD_OR_REPLACE)
+ wl->tx_spare_blocks = 2;
+ else if (action == KEY_REMOVE)
+ wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
+ }
+
addr = sta ? sta->addr : bcast_addr;
if (is_zero_ether_addr(addr)) {
@@ -2627,6 +2716,11 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
return 0;
+ /* don't remove key if hlid was already deleted */
+ if (action == KEY_REMOVE &&
+ wl->sta_hlid == WL12XX_INVALID_LINK_ID)
+ return 0;
+
ret = wl1271_cmd_set_sta_key(wl, action,
id, key_type, key_size,
key, addr, tx_seq_32,
@@ -2636,8 +2730,9 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
/* the default WEP key needs to be configured at least once */
if (key_type == KEY_WEP) {
- ret = wl1271_cmd_set_sta_default_wep_key(wl,
- wl->default_key);
+ ret = wl12xx_cmd_set_default_wep_key(wl,
+ wl->default_key,
+ wl->sta_hlid);
if (ret < 0)
return ret;
}
@@ -2779,10 +2874,20 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
- ret = wl1271_scan(hw->priv, ssid, len, req);
+ /* cancel ROC before scanning */
+ if (wl12xx_is_roc(wl)) {
+ if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
+ /* don't allow scanning right now */
+ ret = -EBUSY;
+ goto out_sleep;
+ }
+ wl12xx_croc(wl, wl->dev_role_id);
+ wl12xx_cmd_role_stop_dev(wl);
+ }
+ ret = wl1271_scan(hw->priv, ssid, len, req);
+out_sleep:
wl1271_ps_elp_sleep(wl);
-
out:
mutex_unlock(&wl->mutex);
@@ -2960,6 +3065,93 @@ static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
return 0;
}
+static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
+{
+ int len;
+ const u8 *next, *end = skb->data + skb->len;
+ u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
+ skb->len - ieoffset);
+ if (!ie)
+ return;
+ len = ie[1] + 2;
+ next = ie + len;
+ memmove(ie, next, end - next);
+ skb_trim(skb, skb->len - len);
+}
+
+static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
+ unsigned int oui, u8 oui_type,
+ int ieoffset)
+{
+ int len;
+ const u8 *next, *end = skb->data + skb->len;
+ u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
+ skb->data + ieoffset,
+ skb->len - ieoffset);
+ if (!ie)
+ return;
+ len = ie[1] + 2;
+ next = ie + len;
+ memmove(ie, next, end - next);
+ skb_trim(skb, skb->len - len);
+}
+
+static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl,
+ u8 *probe_rsp_data,
+ size_t probe_rsp_len,
+ u32 rates)
+{
+ struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
+ u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
+ int ssid_ie_offset, ie_offset, templ_len;
+ const u8 *ptr;
+
+ /* no need to change probe response if the SSID is set correctly */
+ if (wl->ssid_len > 0)
+ return wl1271_cmd_template_set(wl,
+ CMD_TEMPL_AP_PROBE_RESPONSE,
+ probe_rsp_data,
+ probe_rsp_len, 0,
+ rates);
+
+ if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
+ wl1271_error("probe_rsp template too big");
+ return -EINVAL;
+ }
+
+ /* start searching from IE offset */
+ ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+
+ ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
+ probe_rsp_len - ie_offset);
+ if (!ptr) {
+ wl1271_error("No SSID in beacon!");
+ return -EINVAL;
+ }
+
+ ssid_ie_offset = ptr - probe_rsp_data;
+ ptr += (ptr[1] + 2);
+
+ memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
+
+ /* insert SSID from bss_conf */
+ probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
+ probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
+ memcpy(probe_rsp_templ + ssid_ie_offset + 2,
+ bss_conf->ssid, bss_conf->ssid_len);
+ templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
+
+ memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
+ ptr, probe_rsp_len - (ptr - probe_rsp_data));
+ templ_len += probe_rsp_len - (ptr - probe_rsp_data);
+
+ return wl1271_cmd_template_set(wl,
+ CMD_TEMPL_AP_PROBE_RESPONSE,
+ probe_rsp_templ,
+ templ_len, 0,
+ rates);
+}
+
static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
struct ieee80211_bss_conf *bss_conf,
u32 changed)
@@ -3016,6 +3208,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
if ((changed & BSS_CHANGED_BEACON)) {
struct ieee80211_hdr *hdr;
+ u32 min_rate;
int ieoffset = offsetof(struct ieee80211_mgmt,
u.beacon.variable);
struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
@@ -3031,28 +3224,46 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
dev_kfree_skb(beacon);
goto out;
}
+ min_rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
CMD_TEMPL_BEACON;
ret = wl1271_cmd_template_set(wl, tmpl_id,
beacon->data,
beacon->len, 0,
- wl1271_tx_min_rate_get(wl));
+ min_rate);
if (ret < 0) {
dev_kfree_skb(beacon);
goto out;
}
+ /* remove TIM ie from probe response */
+ wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
+
+ /*
+ * remove p2p ie from probe response.
+ * the fw reponds to probe requests that don't include
+ * the p2p ie. probe requests with p2p ie will be passed,
+ * and will be responded by the supplicant (the spec
+ * forbids including the p2p ie when responding to probe
+ * requests that didn't include it).
+ */
+ wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
+ WLAN_OUI_TYPE_WFA_P2P, ieoffset);
+
hdr = (struct ieee80211_hdr *) beacon->data;
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_PROBE_RESP);
-
- tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
- CMD_TEMPL_PROBE_RESPONSE;
- ret = wl1271_cmd_template_set(wl,
- tmpl_id,
- beacon->data,
- beacon->len, 0,
- wl1271_tx_min_rate_get(wl));
+ if (is_ap)
+ ret = wl1271_ap_set_probe_resp_tmpl(wl,
+ beacon->data,
+ beacon->len,
+ min_rate);
+ else
+ ret = wl1271_cmd_template_set(wl,
+ CMD_TEMPL_PROBE_RESPONSE,
+ beacon->data,
+ beacon->len, 0,
+ min_rate);
dev_kfree_skb(beacon);
if (ret < 0)
goto out;
@@ -3073,8 +3284,10 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
if ((changed & BSS_CHANGED_BASIC_RATES)) {
u32 rates = bss_conf->basic_rates;
- wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
- wl->basic_rate = wl1271_tx_min_rate_get(wl);
+ wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
+ wl->band);
+ wl->basic_rate = wl1271_tx_min_rate_get(wl,
+ wl->basic_rate_set);
ret = wl1271_init_ap_rates(wl);
if (ret < 0) {
@@ -3094,20 +3307,20 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
if (bss_conf->enable_beacon) {
if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
- ret = wl1271_cmd_start_bss(wl);
+ ret = wl12xx_cmd_role_start_ap(wl);
if (ret < 0)
goto out;
- set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
- wl1271_debug(DEBUG_AP, "started AP");
-
ret = wl1271_ap_init_hwenc(wl);
if (ret < 0)
goto out;
+
+ set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
+ wl1271_debug(DEBUG_AP, "started AP");
}
} else {
if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
- ret = wl1271_cmd_stop_bss(wl);
+ ret = wl12xx_cmd_role_stop_ap(wl);
if (ret < 0)
goto out;
@@ -3120,6 +3333,18 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
if (ret < 0)
goto out;
+
+ /* Handle HT information change */
+ if ((changed & BSS_CHANGED_HT) &&
+ (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
+ ret = wl1271_acx_set_ht_information(wl,
+ bss_conf->ht_operation_mode);
+ if (ret < 0) {
+ wl1271_warning("Set ht information failed %d", ret);
+ goto out;
+ }
+ }
+
out:
return;
}
@@ -3132,6 +3357,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
{
bool do_join = false, set_assoc = false;
bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
+ bool ibss_joined = false;
u32 sta_rate_set = 0;
int ret;
struct ieee80211_sta *sta;
@@ -3145,14 +3371,28 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
goto out;
}
- if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
+ if (changed & BSS_CHANGED_IBSS) {
+ if (bss_conf->ibss_joined) {
+ set_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags);
+ ibss_joined = true;
+ } else {
+ if (test_and_clear_bit(WL1271_FLAG_IBSS_JOINED,
+ &wl->flags)) {
+ wl1271_unjoin(wl);
+ wl12xx_cmd_role_start_dev(wl);
+ wl12xx_roc(wl, wl->dev_role_id);
+ }
+ }
+ }
+
+ if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
do_join = true;
/* Need to update the SSID (for filtering etc) */
- if ((changed & BSS_CHANGED_BEACON) && is_ibss)
+ if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
do_join = true;
- if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
+ if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
bss_conf->enable_beacon ? "enabled" : "disabled");
@@ -3192,17 +3432,17 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
if (ret < 0)
goto out;
- /* filter out all packets not from this BSSID */
- wl1271_configure_filters(wl, 0);
-
/* Need to update the BSSID (for filtering etc) */
do_join = true;
}
}
- rcu_read_lock();
- sta = ieee80211_find_sta(vif, bss_conf->bssid);
- if (sta) {
+ if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
+ rcu_read_lock();
+ sta = ieee80211_find_sta(vif, bss_conf->bssid);
+ if (!sta)
+ goto sta_not_found;
+
/* save the supp_rates of the ap */
sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
if (sta->ht_cap.ht_supported)
@@ -3210,38 +3450,9 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
(sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
sta_ht_cap = sta->ht_cap;
sta_exists = true;
- }
- rcu_read_unlock();
- if (sta_exists) {
- /* handle new association with HT and HT information change */
- if ((changed & BSS_CHANGED_HT) &&
- (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
- ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
- true);
- if (ret < 0) {
- wl1271_warning("Set ht cap true failed %d",
- ret);
- goto out;
- }
- ret = wl1271_acx_set_ht_information(wl,
- bss_conf->ht_operation_mode);
- if (ret < 0) {
- wl1271_warning("Set ht information failed %d",
- ret);
- goto out;
- }
- }
- /* handle new association without HT and disassociation */
- else if (changed & BSS_CHANGED_ASSOC) {
- ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
- false);
- if (ret < 0) {
- wl1271_warning("Set ht cap false failed %d",
- ret);
- goto out;
- }
- }
+sta_not_found:
+ rcu_read_unlock();
}
if ((changed & BSS_CHANGED_ASSOC)) {
@@ -3258,12 +3469,15 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
* to use with control frames.
*/
rates = bss_conf->basic_rates;
- wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
- rates);
- wl->basic_rate = wl1271_tx_min_rate_get(wl);
+ wl->basic_rate_set =
+ wl1271_tx_enabled_rates_get(wl, rates,
+ wl->band);
+ wl->basic_rate =
+ wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
if (sta_rate_set)
wl->rate_set = wl1271_tx_enabled_rates_get(wl,
- sta_rate_set);
+ sta_rate_set,
+ wl->band);
ret = wl1271_acx_sta_rate_policies(wl);
if (ret < 0)
goto out;
@@ -3291,25 +3505,14 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
ret = wl1271_acx_conn_monit_params(wl, true);
if (ret < 0)
goto out;
-
- /* If we want to go in PSM but we're not there yet */
- if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
- !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
- enum wl1271_cmd_ps_mode mode;
-
- mode = STATION_POWER_SAVE_MODE;
- ret = wl1271_ps_set_mode(wl, mode,
- wl->basic_rate,
- true);
- if (ret < 0)
- goto out;
- }
} else {
/* use defaults when not associated */
bool was_assoc =
!!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
&wl->flags);
- clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
+ bool was_ifup =
+ !!test_and_clear_bit(WL1271_FLAG_STA_STATE_SENT,
+ &wl->flags);
wl->aid = 0;
/* free probe-request template */
@@ -3321,7 +3524,8 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
/* revert back to minimum rates for the current band */
wl1271_set_band_rate(wl);
- wl->basic_rate = wl1271_tx_min_rate_get(wl);
+ wl->basic_rate =
+ wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
ret = wl1271_acx_sta_rate_policies(wl);
if (ret < 0)
goto out;
@@ -3336,8 +3540,32 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
/* 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.
+ */
+ if (!was_ifup) {
+ ret = wl12xx_croc(wl, wl->role_id);
+ if (ret < 0)
+ goto out;
+ }
+ /*
+ * (we also need to disable roc in case of
+ * roaming on the same channel. until we will
+ * have a better flow...)
+ */
+ if (test_bit(wl->dev_role_id, wl->roc_map)) {
+ ret = wl12xx_croc(wl, wl->dev_role_id);
+ if (ret < 0)
+ goto out;
+ }
+
wl1271_unjoin(wl);
- wl1271_dummy_join(wl);
+ if (!(conf_flags & IEEE80211_CONF_IDLE)) {
+ wl12xx_cmd_role_start_dev(wl);
+ wl12xx_roc(wl, wl->dev_role_id);
+ }
}
}
}
@@ -3348,11 +3576,13 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
if (bss_conf->ibss_joined) {
u32 rates = bss_conf->basic_rates;
- wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
- rates);
- wl->basic_rate = wl1271_tx_min_rate_get(wl);
+ wl->basic_rate_set =
+ wl1271_tx_enabled_rates_get(wl, rates,
+ wl->band);
+ wl->basic_rate =
+ wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
- /* by default, use 11b rates */
+ /* by default, use 11b + OFDM rates */
wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
ret = wl1271_acx_sta_rate_policies(wl);
if (ret < 0)
@@ -3398,7 +3628,81 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
wl1271_warning("cmd join failed %d", ret);
goto out;
}
- wl1271_check_operstate(wl, ieee80211_get_operstate(vif));
+
+ /* ROC until connected (after EAPOL exchange) */
+ if (!is_ibss) {
+ ret = wl12xx_roc(wl, wl->role_id);
+ if (ret < 0)
+ goto out;
+
+ wl1271_check_operstate(wl,
+ ieee80211_get_operstate(vif));
+ }
+ /*
+ * stop device role if started (we might already be in
+ * STA role). TODO: make it better.
+ */
+ if (wl->dev_role_id != WL12XX_INVALID_ROLE_ID) {
+ ret = wl12xx_croc(wl, wl->dev_role_id);
+ if (ret < 0)
+ goto out;
+
+ ret = wl12xx_cmd_role_stop_dev(wl);
+ if (ret < 0)
+ goto out;
+ }
+
+ /* If we want to go in PSM but we're not there yet */
+ if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
+ !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
+ enum wl1271_cmd_ps_mode mode;
+
+ mode = STATION_POWER_SAVE_MODE;
+ ret = wl1271_ps_set_mode(wl, mode,
+ wl->basic_rate,
+ true);
+ if (ret < 0)
+ goto out;
+ }
+ }
+
+ /* Handle new association with HT. Do this after join. */
+ if (sta_exists) {
+ if ((changed & BSS_CHANGED_HT) &&
+ (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
+ ret = wl1271_acx_set_ht_capabilities(wl,
+ &sta_ht_cap,
+ true,
+ wl->sta_hlid);
+ if (ret < 0) {
+ wl1271_warning("Set ht cap true failed %d",
+ ret);
+ goto out;
+ }
+ }
+ /* handle new association without HT and disassociation */
+ else if (changed & BSS_CHANGED_ASSOC) {
+ ret = wl1271_acx_set_ht_capabilities(wl,
+ &sta_ht_cap,
+ false,
+ wl->sta_hlid);
+ if (ret < 0) {
+ wl1271_warning("Set ht cap false failed %d",
+ ret);
+ goto out;
+ }
+ }
+ }
+
+ /* Handle HT information change. Done after join. */
+ if ((changed & BSS_CHANGED_HT) &&
+ (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
+ ret = wl1271_acx_set_ht_information(wl,
+ bss_conf->ht_operation_mode);
+ if (ret < 0) {
+ wl1271_warning("Set ht information failed %d", ret);
+ goto out;
+ }
}
out:
@@ -3437,7 +3741,8 @@ out:
mutex_unlock(&wl->mutex);
}
-static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
+static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct wl1271 *wl = hw->priv;
@@ -3508,7 +3813,8 @@ out:
return ret;
}
-static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
+static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
{
struct wl1271 *wl = hw->priv;
@@ -3568,31 +3874,31 @@ static int wl1271_allocate_sta(struct wl1271 *wl,
}
wl_sta = (struct wl1271_station *)sta->drv_priv;
- __set_bit(id, wl->ap_hlid_map);
+ set_bit(id, wl->ap_hlid_map);
wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
*hlid = wl_sta->hlid;
memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
+ wl->active_sta_count++;
return 0;
}
-static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
+void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
{
int id = hlid - WL1271_AP_STA_HLID_START;
- if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
+ if (hlid < WL1271_AP_STA_HLID_START)
+ return;
+
+ if (!test_bit(id, wl->ap_hlid_map))
return;
- __clear_bit(id, wl->ap_hlid_map);
+ clear_bit(id, wl->ap_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);
-}
-
-bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
-{
- int id = hlid - WL1271_AP_STA_HLID_START;
- return test_bit(id, wl->ap_hlid_map);
+ wl->active_sta_count--;
}
static int wl1271_op_sta_add(struct ieee80211_hw *hw,
@@ -3621,7 +3927,15 @@ static int wl1271_op_sta_add(struct ieee80211_hw *hw,
if (ret < 0)
goto out_free_sta;
- ret = wl1271_cmd_add_sta(wl, sta, hlid);
+ ret = wl12xx_cmd_add_peer(wl, sta, hlid);
+ if (ret < 0)
+ goto out_sleep;
+
+ ret = wl12xx_cmd_set_peer_state(wl, hlid);
+ if (ret < 0)
+ goto out_sleep;
+
+ ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
if (ret < 0)
goto out_sleep;
@@ -3664,7 +3978,7 @@ static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
- ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
+ ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
if (ret < 0)
goto out_sleep;
@@ -3686,6 +4000,14 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
{
struct wl1271 *wl = hw->priv;
int ret;
+ u8 hlid, *ba_bitmap;
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
+ tid);
+
+ /* sanity check - the fields in FW are only 8bits wide */
+ if (WARN_ON(tid > 0xFF))
+ return -ENOTSUPP;
mutex_lock(&wl->mutex);
@@ -3694,6 +4016,20 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
goto out;
}
+ if (wl->bss_type == BSS_TYPE_STA_BSS) {
+ hlid = wl->sta_hlid;
+ ba_bitmap = &wl->ba_rx_bitmap;
+ } else if (wl->bss_type == BSS_TYPE_AP_BSS) {
+ struct wl1271_station *wl_sta;
+
+ wl_sta = (struct wl1271_station *)sta->drv_priv;
+ hlid = wl_sta->hlid;
+ ba_bitmap = &wl->links[hlid].ba_bitmap;
+ } else {
+ ret = -EINVAL;
+ goto out;
+ }
+
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
@@ -3703,20 +4039,46 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
switch (action) {
case IEEE80211_AMPDU_RX_START:
- if ((wl->ba_support) && (wl->ba_allowed)) {
- ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
- true);
- if (!ret)
- wl->ba_rx_bitmap |= BIT(tid);
- } else {
+ if (!wl->ba_support || !wl->ba_allowed) {
ret = -ENOTSUPP;
+ break;
+ }
+
+ if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
+ ret = -EBUSY;
+ wl1271_error("exceeded max RX BA sessions");
+ break;
+ }
+
+ if (*ba_bitmap & BIT(tid)) {
+ ret = -EINVAL;
+ wl1271_error("cannot enable RX BA session on active "
+ "tid: %d", tid);
+ break;
+ }
+
+ ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
+ hlid);
+ if (!ret) {
+ *ba_bitmap |= BIT(tid);
+ wl->ba_rx_session_count++;
}
break;
case IEEE80211_AMPDU_RX_STOP:
- ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
- if (!ret)
- wl->ba_rx_bitmap &= ~BIT(tid);
+ if (!(*ba_bitmap & BIT(tid))) {
+ ret = -EINVAL;
+ wl1271_error("no active RX BA session on tid: %d",
+ tid);
+ break;
+ }
+
+ ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
+ hlid);
+ if (!ret) {
+ *ba_bitmap &= ~BIT(tid);
+ wl->ba_rx_session_count--;
+ }
break;
/*
@@ -3742,6 +4104,60 @@ out:
return ret;
}
+static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ const struct cfg80211_bitrate_mask *mask)
+{
+ struct wl1271 *wl = hw->priv;
+ int i;
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
+ mask->control[NL80211_BAND_2GHZ].legacy,
+ mask->control[NL80211_BAND_5GHZ].legacy);
+
+ mutex_lock(&wl->mutex);
+
+ for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+ wl->bitrate_masks[i] =
+ wl1271_tx_enabled_rates_get(wl,
+ mask->control[i].legacy,
+ i);
+ mutex_unlock(&wl->mutex);
+
+ return 0;
+}
+
+static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
+ struct ieee80211_channel_switch *ch_switch)
+{
+ struct wl1271 *wl = hw->priv;
+ int ret;
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state == WL1271_STATE_OFF)) {
+ mutex_unlock(&wl->mutex);
+ ieee80211_chswitch_done(wl->vif, false);
+ return;
+ }
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wl12xx_cmd_channel_switch(wl, ch_switch);
+
+ if (!ret)
+ set_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags);
+
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+}
+
static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
{
struct wl1271 *wl = hw->priv;
@@ -3858,7 +4274,6 @@ static const u8 wl1271_rate_to_idx_2ghz[] = {
/* 11n STA capabilities */
#define HW_RX_HIGHEST_RATE 72
-#ifdef CONFIG_WL12XX_HT
#define WL12XX_HT_CAP { \
.cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
(1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
@@ -3871,11 +4286,6 @@ static const u8 wl1271_rate_to_idx_2ghz[] = {
.tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
}, \
}
-#else
-#define WL12XX_HT_CAP { \
- .ht_supported = false, \
-}
-#endif
/* can't be const, mac80211 writes to this */
static struct ieee80211_supported_band wl1271_band_2ghz = {
@@ -4023,6 +4433,8 @@ static const struct ieee80211_ops wl1271_ops = {
.sta_remove = wl1271_op_sta_remove,
.ampdu_action = wl1271_op_ampdu_action,
.tx_frames_pending = wl1271_tx_frames_pending,
+ .set_bitrate_mask = wl12xx_set_bitrate_mask,
+ .channel_switch = wl12xx_op_channel_switch,
CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
};
@@ -4126,7 +4538,7 @@ static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
return len;
}
-static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
+static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
wl1271_sysfs_show_hw_pg_ver, NULL);
static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
@@ -4275,22 +4687,32 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
IEEE80211_HW_SUPPORTS_CQM_RSSI |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
IEEE80211_HW_SPECTRUM_MGMT |
- IEEE80211_HW_AP_LINK_PS;
+ IEEE80211_HW_AP_LINK_PS |
+ IEEE80211_HW_AMPDU_AGGREGATION |
+ IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
wl->hw->wiphy->cipher_suites = cipher_suites;
wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
+ BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
wl->hw->wiphy->max_scan_ssids = 1;
+ wl->hw->wiphy->max_sched_scan_ssids = 16;
+ wl->hw->wiphy->max_match_sets = 16;
/*
* Maximum length of elements in scanning probe request templates
* 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_MAX_SIZE -
+ wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
sizeof(struct ieee80211_header);
+ wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
+ sizeof(struct ieee80211_header);
+
+ wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
+
/* make sure all our channels fit in the scanned_ch bitmask */
BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
ARRAY_SIZE(wl1271_channels_5ghz) >
@@ -4334,6 +4756,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
int i, j, ret;
unsigned int order;
+ BUILD_BUG_ON(AP_MAX_LINKS > WL12XX_MAX_LINKS);
+
hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
if (!hw) {
wl1271_error("could not alloc ieee80211_hw");
@@ -4387,8 +4811,6 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
wl->default_key = 0;
wl->rx_counter = 0;
- wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
- wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
wl->psm_entry_retry = 0;
wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
@@ -4401,7 +4823,6 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl->hw_pg_ver = -1;
wl->bss_type = MAX_BSS_TYPE;
wl->set_bss_type = MAX_BSS_TYPE;
- wl->fw_bss_type = MAX_BSS_TYPE;
wl->last_tx_hlid = 0;
wl->ap_ps_map = 0;
wl->ap_fw_ps_map = 0;
@@ -4410,12 +4831,24 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl->sched_scanning = false;
wl->tx_security_seq = 0;
wl->tx_security_last_seq_lsb = 0;
-
+ wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
+ wl->role_id = WL12XX_INVALID_ROLE_ID;
+ wl->system_hlid = WL12XX_SYSTEM_HLID;
+ wl->sta_hlid = WL12XX_INVALID_LINK_ID;
+ wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
+ wl->dev_hlid = WL12XX_INVALID_LINK_ID;
+ wl->session_counter = 0;
+ wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
+ wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
+ wl->active_sta_count = 0;
setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
(unsigned long) wl);
wl->fwlog_size = 0;
init_waitqueue_head(&wl->fwlog_waitq);
+ /* The system link is always allocated */
+ __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
+
memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
wl->tx_frames[i] = NULL;
@@ -4427,6 +4860,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
/* Apply default driver configuration. */
wl1271_conf_init(wl);
+ wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
+ wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
order = get_order(WL1271_AGGR_BUFFER_SIZE);
wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
@@ -4522,6 +4957,10 @@ int wl1271_free_hw(struct wl1271 *wl)
mutex_unlock(&wl->mutex);
device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
+
+ device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
+
+ device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
platform_device_unregister(wl->plat_dev);
free_page((unsigned long)wl->fwlog);
dev_kfree_skb(wl->dummy_packet);
@@ -4555,6 +4994,9 @@ module_param_named(fwlog, fwlog_param, charp, 0);
MODULE_PARM_DESC(keymap,
"FW logger options: continuous, ondemand, dbgpins or disable");
+module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
+
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c
index 3548377ab9c2..c15ebf2efd40 100644
--- a/drivers/net/wireless/wl12xx/ps.c
+++ b/drivers/net/wireless/wl12xx/ps.c
@@ -199,15 +199,19 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid)
unsigned long flags;
int filtered[NUM_TX_QUEUES];
- /* filter all frames currently the low level queus for this hlid */
+ /* filter all frames currently in the low level queues for this hlid */
for (i = 0; i < NUM_TX_QUEUES; i++) {
filtered[i] = 0;
while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) {
+ filtered[i]++;
+
+ if (WARN_ON(wl12xx_is_dummy_packet(wl, skb)))
+ continue;
+
info = IEEE80211_SKB_CB(skb);
info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
info->status.rates[0].idx = -1;
ieee80211_tx_status_ni(wl->hw, skb);
- filtered[i]++;
}
}
@@ -226,8 +230,8 @@ void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues)
if (test_bit(hlid, &wl->ap_ps_map))
return;
- wl1271_debug(DEBUG_PSM, "start mac80211 PSM on hlid %d blks %d "
- "clean_queues %d", hlid, wl->links[hlid].allocated_blks,
+ wl1271_debug(DEBUG_PSM, "start mac80211 PSM on hlid %d pkts %d "
+ "clean_queues %d", hlid, wl->links[hlid].allocated_pkts,
clean_queues);
rcu_read_lock();
diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h
index 440a4ee9cb42..3f570f397586 100644
--- a/drivers/net/wireless/wl12xx/reg.h
+++ b/drivers/net/wireless/wl12xx/reg.h
@@ -296,81 +296,6 @@
===============================================*/
#define REG_EVENT_MAILBOX_PTR (SCR_PAD1)
-
-/* Misc */
-
-#define REG_ENABLE_TX_RX (ENABLE)
-/*
- * Rx configuration (filter) information element
- * ---------------------------------------------
- */
-#define REG_RX_CONFIG (RX_CFG)
-#define REG_RX_FILTER (RX_FILTER_CFG)
-
-
-#define RX_CFG_ENABLE_PHY_HEADER_PLCP 0x0002
-
-/* promiscuous - receives all valid frames */
-#define RX_CFG_PROMISCUOUS 0x0008
-
-/* receives frames from any BSSID */
-#define RX_CFG_BSSID 0x0020
-
-/* receives frames destined to any MAC address */
-#define RX_CFG_MAC 0x0010
-
-#define RX_CFG_ENABLE_ONLY_MY_DEST_MAC 0x0010
-#define RX_CFG_ENABLE_ANY_DEST_MAC 0x0000
-#define RX_CFG_ENABLE_ONLY_MY_BSSID 0x0020
-#define RX_CFG_ENABLE_ANY_BSSID 0x0000
-
-/* discards all broadcast frames */
-#define RX_CFG_DISABLE_BCAST 0x0200
-
-#define RX_CFG_ENABLE_ONLY_MY_SSID 0x0400
-#define RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR 0x0800
-#define RX_CFG_COPY_RX_STATUS 0x2000
-#define RX_CFG_TSF 0x10000
-
-#define RX_CONFIG_OPTION_ANY_DST_MY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \
- RX_CFG_ENABLE_ONLY_MY_BSSID)
-
-#define RX_CONFIG_OPTION_MY_DST_ANY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\
- | RX_CFG_ENABLE_ANY_BSSID)
-
-#define RX_CONFIG_OPTION_ANY_DST_ANY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \
- RX_CFG_ENABLE_ANY_BSSID)
-
-#define RX_CONFIG_OPTION_MY_DST_MY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\
- | RX_CFG_ENABLE_ONLY_MY_BSSID)
-
-#define RX_CONFIG_OPTION_FOR_SCAN (RX_CFG_ENABLE_PHY_HEADER_PLCP \
- | RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR \
- | RX_CFG_COPY_RX_STATUS | RX_CFG_TSF)
-
-#define RX_CONFIG_OPTION_FOR_MEASUREMENT (RX_CFG_ENABLE_ANY_DEST_MAC)
-
-#define RX_CONFIG_OPTION_FOR_JOIN (RX_CFG_ENABLE_ONLY_MY_BSSID | \
- RX_CFG_ENABLE_ONLY_MY_DEST_MAC)
-
-#define RX_CONFIG_OPTION_FOR_IBSS_JOIN (RX_CFG_ENABLE_ONLY_MY_SSID | \
- RX_CFG_ENABLE_ONLY_MY_DEST_MAC)
-
-#define RX_FILTER_OPTION_DEF (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\
- | CFG_RX_CTL_EN | CFG_RX_BCN_EN\
- | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN)
-
-#define RX_FILTER_OPTION_FILTER_ALL 0
-
-#define RX_FILTER_OPTION_DEF_PRSP_BCN (CFG_RX_PRSP_EN | CFG_RX_MGMT_EN\
- | CFG_RX_RCTS_ACK | CFG_RX_BCN_EN)
-
-#define RX_FILTER_OPTION_JOIN (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\
- | CFG_RX_BCN_EN | CFG_RX_AUTH_EN\
- | CFG_RX_ASSOC_EN | CFG_RX_RCTS_ACK\
- | CFG_RX_PRSP_EN)
-
-
/*===============================================
EEPROM Read/Write Request 32bit RW
------------------------------------------
diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c
index 0450fb49dbb1..dee4cfe9ccc1 100644
--- a/drivers/net/wireless/wl12xx/rx.c
+++ b/drivers/net/wireless/wl12xx/rx.c
@@ -30,20 +30,28 @@
#include "rx.h"
#include "io.h"
-static u8 wl1271_rx_get_mem_block(struct wl1271_fw_common_status *status,
+static u8 wl12xx_rx_get_mem_block(struct wl12xx_fw_status *status,
u32 drv_rx_counter)
{
return le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
RX_MEM_BLOCK_MASK;
}
-static u32 wl1271_rx_get_buf_size(struct wl1271_fw_common_status *status,
+static u32 wl12xx_rx_get_buf_size(struct wl12xx_fw_status *status,
u32 drv_rx_counter)
{
return (le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
RX_BUF_SIZE_MASK) >> RX_BUF_SIZE_SHIFT_DIV;
}
+static bool wl12xx_rx_get_unaligned(struct wl12xx_fw_status *status,
+ u32 drv_rx_counter)
+{
+ /* Convert the value to bool */
+ return !!(le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
+ RX_BUF_UNALIGNED_PAYLOAD);
+}
+
static void wl1271_rx_status(struct wl1271 *wl,
struct wl1271_rx_descriptor *desc,
struct ieee80211_rx_status *status,
@@ -58,11 +66,9 @@ static void wl1271_rx_status(struct wl1271 *wl,
status->rate_idx = wl1271_rate_to_idx(desc->rate, status->band);
-#ifdef CONFIG_WL12XX_HT
/* 11n support */
if (desc->rate <= CONF_HW_RXTX_RATE_MCS0)
status->flag |= RX_FLAG_HT;
-#endif
status->signal = desc->rssi;
@@ -89,7 +95,8 @@ static void wl1271_rx_status(struct wl1271 *wl,
}
}
-static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
+static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
+ bool unaligned)
{
struct wl1271_rx_descriptor *desc;
struct sk_buff *skb;
@@ -97,6 +104,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
u8 *buf;
u8 beacon = 0;
u8 is_data = 0;
+ u8 reserved = unaligned ? NET_IP_ALIGN : 0;
+ u16 seq_num;
/*
* In PLT mode we seem to get frames and mac80211 warns about them,
@@ -131,17 +140,25 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
return -EINVAL;
}
- skb = __dev_alloc_skb(length, GFP_KERNEL);
+ /* skb length not included rx descriptor */
+ skb = __dev_alloc_skb(length + reserved - sizeof(*desc), GFP_KERNEL);
if (!skb) {
wl1271_error("Couldn't allocate RX frame");
return -ENOMEM;
}
- buf = skb_put(skb, length);
- memcpy(buf, data, length);
+ /* reserve the unaligned payload(if any) */
+ skb_reserve(skb, reserved);
- /* now we pull the descriptor out of the buffer */
- skb_pull(skb, sizeof(*desc));
+ buf = skb_put(skb, length - sizeof(*desc));
+
+ /*
+ * Copy packets from aggregation buffer to the skbs without rx
+ * descriptor and with packet payload aligned care. In case of unaligned
+ * packets copy the packets in offset of 2 bytes guarantee IP header
+ * payload aligned to 4 bytes.
+ */
+ memcpy(buf, data + sizeof(*desc), length - sizeof(*desc));
hdr = (struct ieee80211_hdr *)skb->data;
if (ieee80211_is_beacon(hdr->frame_control))
@@ -151,9 +168,11 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon);
- wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb,
+ seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
+ wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d", skb,
skb->len - desc->pad_len,
- beacon ? "beacon" : "");
+ beacon ? "beacon" : "",
+ seq_num);
skb_trim(skb, skb->len - desc->pad_len);
@@ -163,7 +182,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
return is_data;
}
-void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
+void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
{
struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map;
u32 buf_size;
@@ -175,12 +194,13 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
u32 pkt_offset;
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
bool had_data = false;
+ bool unaligned = false;
while (drv_rx_counter != fw_rx_counter) {
buf_size = 0;
rx_counter = drv_rx_counter;
while (rx_counter != fw_rx_counter) {
- pkt_length = wl1271_rx_get_buf_size(status, rx_counter);
+ pkt_length = wl12xx_rx_get_buf_size(status, rx_counter);
if (buf_size + pkt_length > WL1271_AGGR_BUFFER_SIZE)
break;
buf_size += pkt_length;
@@ -199,7 +219,7 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
* For aggregated packets, only the first memory block
* should be retrieved. The FW takes care of the rest.
*/
- mem_block = wl1271_rx_get_mem_block(status,
+ mem_block = wl12xx_rx_get_mem_block(status,
drv_rx_counter);
wl->rx_mem_pool_addr.addr = (mem_block << 8) +
@@ -220,8 +240,12 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
/* Split data into separate packets */
pkt_offset = 0;
while (pkt_offset < buf_size) {
- pkt_length = wl1271_rx_get_buf_size(status,
+ pkt_length = wl12xx_rx_get_buf_size(status,
drv_rx_counter);
+
+ unaligned = wl12xx_rx_get_unaligned(status,
+ drv_rx_counter);
+
/*
* the handle data call can only fail in memory-outage
* conditions, in that case the received frame will just
@@ -229,7 +253,7 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
*/
if (wl1271_rx_handle_data(wl,
wl->aggr_buf + pkt_offset,
- pkt_length) == 1)
+ pkt_length, unaligned) == 1)
had_data = true;
wl->rx_counter++;
@@ -260,14 +284,3 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
jiffies + msecs_to_jiffies(timeout));
}
}
-
-void wl1271_set_default_filters(struct wl1271 *wl)
-{
- if (wl->bss_type == BSS_TYPE_AP_BSS) {
- wl->rx_config = WL1271_DEFAULT_AP_RX_CONFIG;
- wl->rx_filter = WL1271_DEFAULT_AP_RX_FILTER;
- } else {
- wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
- wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
- }
-}
diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/rx.h
index c88e3fa1d603..86ba6b1d0cdc 100644
--- a/drivers/net/wireless/wl12xx/rx.h
+++ b/drivers/net/wireless/wl12xx/rx.h
@@ -86,16 +86,18 @@
* Bits 3-5 - process_id tag (AP mode FW)
* Bits 6-7 - reserved
*/
-#define WL1271_RX_DESC_STATUS_MASK 0x07
+#define WL1271_RX_DESC_STATUS_MASK 0x03
#define WL1271_RX_DESC_SUCCESS 0x00
#define WL1271_RX_DESC_DECRYPT_FAIL 0x01
#define WL1271_RX_DESC_MIC_FAIL 0x02
#define WL1271_RX_DESC_DRIVER_RX_Q_FAIL 0x03
-#define RX_MEM_BLOCK_MASK 0xFF
-#define RX_BUF_SIZE_MASK 0xFFF00
-#define RX_BUF_SIZE_SHIFT_DIV 6
+#define RX_MEM_BLOCK_MASK 0xFF
+#define RX_BUF_SIZE_MASK 0xFFF00
+#define RX_BUF_SIZE_SHIFT_DIV 6
+/* If set, the start of IP payload is not 4 bytes aligned */
+#define RX_BUF_UNALIGNED_PAYLOAD BIT(20)
enum {
WL12XX_RX_CLASS_UNKNOWN,
@@ -119,16 +121,12 @@ struct wl1271_rx_descriptor {
u8 snr;
__le32 timestamp;
u8 packet_class;
- union {
- u8 process_id; /* STA FW */
- u8 hlid; /* AP FW */
- } __packed;
+ u8 hlid;
u8 pad_len;
u8 reserved;
} __packed;
-void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status);
+void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status);
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
-void wl1271_set_default_filters(struct wl1271 *wl);
#endif
diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c
index edfe01c321ca..128ccb79318c 100644
--- a/drivers/net/wireless/wl12xx/scan.c
+++ b/drivers/net/wireless/wl12xx/scan.c
@@ -28,11 +28,14 @@
#include "scan.h"
#include "acx.h"
#include "ps.h"
+#include "tx.h"
void wl1271_scan_complete_work(struct work_struct *work)
{
struct delayed_work *dwork;
struct wl1271 *wl;
+ int ret;
+ bool is_sta, is_ibss;
dwork = container_of(work, struct delayed_work, work);
wl = container_of(dwork, struct wl1271, scan_complete_work);
@@ -50,21 +53,35 @@ void wl1271_scan_complete_work(struct work_struct *work)
wl->scan.state = WL1271_SCAN_STATE_IDLE;
memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
wl->scan.req = NULL;
- ieee80211_scan_completed(wl->hw, false);
- /* restore hardware connection monitoring template */
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
- if (wl1271_ps_elp_wakeup(wl) == 0) {
- wl1271_cmd_build_ap_probe_req(wl, wl->probereq);
- wl1271_ps_elp_sleep(wl);
- }
+ /* restore hardware connection monitoring template */
+ wl1271_cmd_build_ap_probe_req(wl, wl->probereq);
+ }
+
+ /* return to ROC if needed */
+ is_sta = (wl->bss_type == BSS_TYPE_STA_BSS);
+ is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
+ if (((is_sta && !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) ||
+ (is_ibss && !test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags))) &&
+ !test_bit(wl->dev_role_id, wl->roc_map)) {
+ /* restore remain on channel */
+ wl12xx_cmd_role_start_dev(wl);
+ wl12xx_roc(wl, wl->dev_role_id);
}
+ wl1271_ps_elp_sleep(wl);
if (wl->scan.failed) {
wl1271_info("Scan completed due to error.");
wl12xx_queue_recovery_work(wl);
}
+ ieee80211_scan_completed(wl->hw, false);
+
out:
mutex_unlock(&wl->mutex);
@@ -83,14 +100,18 @@ static int wl1271_get_scan_channels(struct wl1271 *wl,
for (i = 0, j = 0;
i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS;
i++) {
-
flags = req->channels[i]->flags;
if (!test_bit(i, wl->scan.scanned_ch) &&
!(flags & IEEE80211_CHAN_DISABLED) &&
- ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) &&
- (req->channels[i]->band == band)) {
-
+ (req->channels[i]->band == band) &&
+ /*
+ * In passive scans, we scan all remaining
+ * channels, even if not marked as such.
+ * In active scans, we only scan channels not
+ * marked as passive.
+ */
+ (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) {
wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
req->channels[i]->band,
req->channels[i]->center_freq);
@@ -142,6 +163,10 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
int ret;
u16 scan_options = 0;
+ /* skip active scans if we don't have SSIDs */
+ if (!passive && wl->scan.req->n_ssids == 0)
+ return WL1271_NOTHING_TO_SCAN;
+
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
if (!cmd || !trigger) {
@@ -149,13 +174,14 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
goto out;
}
- /* We always use high priority scans */
- scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH;
-
- /* No SSIDs means that we have a forced passive scan */
- if (passive || wl->scan.req->n_ssids == 0)
+ if (passive)
scan_options |= WL1271_SCAN_OPT_PASSIVE;
+ if (WARN_ON(wl->role_id == WL12XX_INVALID_ROLE_ID)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ cmd->params.role_id = wl->role_id;
cmd->params.scan_options = cpu_to_le16(scan_options);
cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
@@ -167,10 +193,6 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
}
cmd->params.tx_rate = cpu_to_le32(basic_rate);
- cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
- cmd->params.rx_filter_options =
- cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);
-
cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs;
cmd->params.tx_rate = cpu_to_le32(basic_rate);
cmd->params.tid_trigger = 0;
@@ -186,6 +208,8 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len);
}
+ memcpy(cmd->addr, wl->mac_addr, ETH_ALEN);
+
ret = wl1271_cmd_build_probe_req(wl, wl->scan.ssid, wl->scan.ssid_len,
wl->scan.req->ie, wl->scan.req->ie_len,
band);
@@ -220,14 +244,17 @@ out:
void wl1271_scan_stm(struct wl1271 *wl)
{
int ret = 0;
+ enum ieee80211_band band;
+ u32 rate;
switch (wl->scan.state) {
case WL1271_SCAN_STATE_IDLE:
break;
case WL1271_SCAN_STATE_2GHZ_ACTIVE:
- ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, false,
- wl->conf.tx.basic_rate);
+ band = IEEE80211_BAND_2GHZ;
+ rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
+ ret = wl1271_scan_send(wl, band, false, rate);
if (ret == WL1271_NOTHING_TO_SCAN) {
wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE;
wl1271_scan_stm(wl);
@@ -236,8 +263,9 @@ void wl1271_scan_stm(struct wl1271 *wl)
break;
case WL1271_SCAN_STATE_2GHZ_PASSIVE:
- ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true,
- wl->conf.tx.basic_rate);
+ band = IEEE80211_BAND_2GHZ;
+ rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
+ ret = wl1271_scan_send(wl, band, true, rate);
if (ret == WL1271_NOTHING_TO_SCAN) {
if (wl->enable_11a)
wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE;
@@ -249,8 +277,9 @@ void wl1271_scan_stm(struct wl1271 *wl)
break;
case WL1271_SCAN_STATE_5GHZ_ACTIVE:
- ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, false,
- wl->conf.tx.basic_rate_5);
+ band = IEEE80211_BAND_5GHZ;
+ rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
+ ret = wl1271_scan_send(wl, band, false, rate);
if (ret == WL1271_NOTHING_TO_SCAN) {
wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE;
wl1271_scan_stm(wl);
@@ -259,8 +288,9 @@ void wl1271_scan_stm(struct wl1271 *wl)
break;
case WL1271_SCAN_STATE_5GHZ_PASSIVE:
- ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, true,
- wl->conf.tx.basic_rate_5);
+ band = IEEE80211_BAND_5GHZ;
+ rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
+ ret = wl1271_scan_send(wl, band, true, rate);
if (ret == WL1271_NOTHING_TO_SCAN) {
wl->scan.state = WL1271_SCAN_STATE_DONE;
wl1271_scan_stm(wl);
@@ -455,6 +485,105 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl,
cfg->passive[2] || cfg->active[2];
}
+/* Returns the scan type to be used or a negative value on error */
+static int
+wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
+ struct cfg80211_sched_scan_request *req)
+{
+ struct wl1271_cmd_sched_scan_ssid_list *cmd = NULL;
+ struct cfg80211_match_set *sets = req->match_sets;
+ struct cfg80211_ssid *ssids = req->ssids;
+ int ret = 0, type, i, j, n_match_ssids = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd sched scan ssid list");
+
+ /* count the match sets that contain SSIDs */
+ for (i = 0; i < req->n_match_sets; i++)
+ if (sets[i].ssid.ssid_len > 0)
+ n_match_ssids++;
+
+ /* No filter, no ssids or only bcast ssid */
+ if (!n_match_ssids &&
+ (!req->n_ssids ||
+ (req->n_ssids == 1 && req->ssids[0].ssid_len == 0))) {
+ type = SCAN_SSID_FILTER_ANY;
+ goto out;
+ }
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (!n_match_ssids) {
+ /* No filter, with ssids */
+ type = SCAN_SSID_FILTER_DISABLED;
+
+ for (i = 0; i < req->n_ssids; i++) {
+ cmd->ssids[cmd->n_ssids].type = (ssids[i].ssid_len) ?
+ SCAN_SSID_TYPE_HIDDEN : SCAN_SSID_TYPE_PUBLIC;
+ cmd->ssids[cmd->n_ssids].len = ssids[i].ssid_len;
+ memcpy(cmd->ssids[cmd->n_ssids].ssid, ssids[i].ssid,
+ ssids[i].ssid_len);
+ cmd->n_ssids++;
+ }
+ } else {
+ type = SCAN_SSID_FILTER_LIST;
+
+ /* Add all SSIDs from the filters */
+ for (i = 0; i < req->n_match_sets; i++) {
+ /* ignore sets without SSIDs */
+ if (!sets[i].ssid.ssid_len)
+ continue;
+
+ cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_PUBLIC;
+ cmd->ssids[cmd->n_ssids].len = sets[i].ssid.ssid_len;
+ memcpy(cmd->ssids[cmd->n_ssids].ssid,
+ sets[i].ssid.ssid, sets[i].ssid.ssid_len);
+ cmd->n_ssids++;
+ }
+ if ((req->n_ssids > 1) ||
+ (req->n_ssids == 1 && req->ssids[0].ssid_len > 0)) {
+ /*
+ * Mark all the SSIDs passed in the SSID list as HIDDEN,
+ * so they're used in probe requests.
+ */
+ for (i = 0; i < req->n_ssids; i++) {
+ for (j = 0; j < cmd->n_ssids; j++)
+ if (!memcmp(req->ssids[i].ssid,
+ cmd->ssids[j].ssid,
+ req->ssids[i].ssid_len)) {
+ cmd->ssids[j].type =
+ SCAN_SSID_TYPE_HIDDEN;
+ break;
+ }
+ /* Fail if SSID isn't present in the filters */
+ if (j == req->n_ssids) {
+ ret = -EINVAL;
+ goto out_free;
+ }
+ }
+ }
+ }
+
+ wl1271_dump(DEBUG_SCAN, "SSID_LIST: ", cmd, sizeof(*cmd));
+
+ ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_SSID_CFG, cmd,
+ sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("cmd sched scan ssid list failed");
+ goto out_free;
+ }
+
+out_free:
+ kfree(cmd);
+out:
+ if (ret < 0)
+ return ret;
+ return type;
+}
+
int wl1271_scan_sched_scan_config(struct wl1271 *wl,
struct cfg80211_sched_scan_request *req,
struct ieee80211_sched_scan_ies *ies)
@@ -486,15 +615,14 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++)
cfg->intervals[i] = cpu_to_le32(req->interval);
- if (!force_passive && req->ssids[0].ssid_len && req->ssids[0].ssid) {
- cfg->filter_type = SCAN_SSID_FILTER_SPECIFIC;
- cfg->ssid_len = req->ssids[0].ssid_len;
- memcpy(cfg->ssid, req->ssids[0].ssid,
- req->ssids[0].ssid_len);
- } else {
- cfg->filter_type = SCAN_SSID_FILTER_ANY;
- cfg->ssid_len = 0;
- }
+ cfg->ssid_len = 0;
+ ret = wl12xx_scan_sched_scan_ssid_list(wl, req);
+ if (ret < 0)
+ goto out;
+
+ cfg->filter_type = ret;
+
+ wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type);
if (!wl1271_scan_sched_scan_channels(wl, req, cfg)) {
wl1271_error("scan channel list is empty");
diff --git a/drivers/net/wireless/wl12xx/scan.h b/drivers/net/wireless/wl12xx/scan.h
index d882e4da71b7..92115156522f 100644
--- a/drivers/net/wireless/wl12xx/scan.h
+++ b/drivers/net/wireless/wl12xx/scan.h
@@ -46,7 +46,10 @@ 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_PRIORITY_HIGH 4
+/* scan even if we fail to enter psm */
+#define WL1271_SCAN_OPT_FORCE 8
#define WL1271_SCAN_BAND_2_4_GHZ 0
#define WL1271_SCAN_BAND_5_GHZ 1
@@ -62,27 +65,27 @@ enum {
};
struct basic_scan_params {
- __le32 rx_config_options;
- __le32 rx_filter_options;
/* Scan option flags (WL1271_SCAN_OPT_*) */
__le16 scan_options;
+ u8 role_id;
/* Number of scan channels in the list (maximum 30) */
u8 n_ch;
/* This field indicates the number of probe requests to send
per channel for an active scan */
u8 n_probe_reqs;
- /* Rate bit field for sending the probes */
- __le32 tx_rate;
u8 tid_trigger;
u8 ssid_len;
- /* in order to align */
- u8 padding1[2];
- u8 ssid[IW_ESSID_MAX_SIZE];
+ u8 use_ssid_list;
+
+ /* Rate bit field for sending the probes */
+ __le32 tx_rate;
+
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
/* Band to scan */
u8 band;
- u8 use_ssid_list;
+
u8 scan_tag;
- u8 padding2;
+ u8 padding2[2];
} __packed;
struct basic_scan_channel_params {
@@ -105,6 +108,10 @@ struct wl1271_cmd_scan {
struct basic_scan_params params;
struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS];
+
+ /* src mac address */
+ u8 addr[ETH_ALEN];
+ u8 padding[2];
} __packed;
struct wl1271_cmd_trigger_scan_to {
@@ -167,7 +174,7 @@ struct wl1271_cmd_sched_scan_config {
u8 filter_type;
u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */
- u8 ssid[IW_ESSID_MAX_SIZE];
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 n_probe_reqs; /* Number of probes requests per channel */
@@ -184,7 +191,7 @@ struct wl1271_cmd_sched_scan_config {
} __packed;
-#define SCHED_SCAN_MAX_SSIDS 8
+#define SCHED_SCAN_MAX_SSIDS 16
enum {
SCAN_SSID_TYPE_PUBLIC = 0,
@@ -194,7 +201,7 @@ enum {
struct wl1271_ssid {
u8 type;
u8 len;
- u8 ssid[IW_ESSID_MAX_SIZE];
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
/* u8 padding[2]; */
} __packed;
diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c
index 5cf18c2c23f0..516a8980723c 100644
--- a/drivers/net/wireless/wl12xx/sdio.c
+++ b/drivers/net/wireless/wl12xx/sdio.c
@@ -164,7 +164,7 @@ static int wl1271_sdio_power_on(struct wl1271 *wl)
/* If enabled, tell runtime PM not to power off the card */
if (pm_runtime_enabled(&func->dev)) {
ret = pm_runtime_get_sync(&func->dev);
- if (ret)
+ if (ret < 0)
goto out;
} else {
/* Runtime PM is disabled: power up the card manually */
@@ -412,7 +412,5 @@ module_exit(wl1271_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
-MODULE_FIRMWARE(WL1271_FW_NAME);
+MODULE_FIRMWARE(WL127X_FW_NAME);
MODULE_FIRMWARE(WL128X_FW_NAME);
-MODULE_FIRMWARE(WL127X_AP_FW_NAME);
-MODULE_FIRMWARE(WL128X_AP_FW_NAME);
diff --git a/drivers/net/wireless/wl12xx/sdio_test.c b/drivers/net/wireless/wl12xx/sdio_test.c
index f28915392877..f25d5d9212e7 100644
--- a/drivers/net/wireless/wl12xx/sdio_test.c
+++ b/drivers/net/wireless/wl12xx/sdio_test.c
@@ -30,6 +30,7 @@
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
#include <linux/gpio.h>
#include <linux/wl12xx.h>
#include <linux/kthread.h>
@@ -142,14 +143,23 @@ static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable)
ret = pm_runtime_get_sync(&func->dev);
if (ret < 0)
goto out;
+
+ /* Runtime PM might be disabled, power up the card manually */
+ ret = mmc_power_restore_host(func->card->host);
+ if (ret < 0)
+ goto out;
+
sdio_claim_host(func);
sdio_enable_func(func);
- sdio_release_host(func);
} else {
- sdio_claim_host(func);
sdio_disable_func(func);
sdio_release_host(func);
+ /* Runtime PM might be disabled, power off the card manually */
+ ret = mmc_power_save_host(func->card->host);
+ if (ret < 0)
+ goto out;
+
/* Power down the card */
ret = pm_runtime_put_sync(&func->dev);
}
@@ -193,7 +203,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
ret = request_firmware(&fw, WL128X_FW_NAME,
wl1271_wl_to_dev(wl));
else
- ret = request_firmware(&fw, WL1271_FW_NAME,
+ ret = request_firmware(&fw, WL127X_FW_NAME,
wl1271_wl_to_dev(wl));
if (ret < 0) {
@@ -433,7 +443,6 @@ static int __devinit wl1271_probe(struct sdio_func *func,
sdio_set_drvdata(func, wl_test);
-
/* power up the device */
ret = wl1271_chip_wakeup(wl);
if (ret) {
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c
index e0b3736d7e19..0f9718677860 100644
--- a/drivers/net/wireless/wl12xx/spi.c
+++ b/drivers/net/wireless/wl12xx/spi.c
@@ -486,8 +486,6 @@ module_exit(wl1271_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
-MODULE_FIRMWARE(WL1271_FW_NAME);
+MODULE_FIRMWARE(WL127X_FW_NAME);
MODULE_FIRMWARE(WL128X_FW_NAME);
-MODULE_FIRMWARE(WL127X_AP_FW_NAME);
-MODULE_FIRMWARE(WL128X_AP_FW_NAME);
MODULE_ALIAS("spi:wl1271");
diff --git a/drivers/net/wireless/wl12xx/testmode.c b/drivers/net/wireless/wl12xx/testmode.c
index 5d5e1ef87206..4ae8effaee22 100644
--- a/drivers/net/wireless/wl12xx/testmode.c
+++ b/drivers/net/wireless/wl12xx/testmode.c
@@ -36,7 +36,6 @@ enum wl1271_tm_commands {
WL1271_TM_CMD_TEST,
WL1271_TM_CMD_INTERROGATE,
WL1271_TM_CMD_CONFIGURE,
- WL1271_TM_CMD_NVS_PUSH,
WL1271_TM_CMD_SET_PLT_MODE,
WL1271_TM_CMD_RECOVER,
@@ -139,12 +138,15 @@ static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[])
if (ret < 0) {
wl1271_warning("testmode cmd interrogate failed: %d", ret);
+ kfree(cmd);
return ret;
}
skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, sizeof(*cmd));
- if (!skb)
+ if (!skb) {
+ kfree(cmd);
return -ENOMEM;
+ }
NLA_PUT(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd);
@@ -187,48 +189,6 @@ static int wl1271_tm_cmd_configure(struct wl1271 *wl, struct nlattr *tb[])
return 0;
}
-static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[])
-{
- int ret = 0;
- size_t len;
- void *buf;
-
- wl1271_debug(DEBUG_TESTMODE, "testmode cmd nvs push");
-
- if (!tb[WL1271_TM_ATTR_DATA])
- return -EINVAL;
-
- buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
- len = nla_len(tb[WL1271_TM_ATTR_DATA]);
-
- mutex_lock(&wl->mutex);
-
- kfree(wl->nvs);
-
- if ((wl->chip.id == CHIP_ID_1283_PG20) &&
- (len != sizeof(struct wl128x_nvs_file)))
- return -EINVAL;
- else if (len != sizeof(struct wl1271_nvs_file))
- return -EINVAL;
-
- wl->nvs = kzalloc(len, GFP_KERNEL);
- if (!wl->nvs) {
- wl1271_error("could not allocate memory for the nvs file");
- ret = -ENOMEM;
- goto out;
- }
-
- memcpy(wl->nvs, buf, len);
- wl->nvs_len = len;
-
- wl1271_debug(DEBUG_TESTMODE, "testmode pushed nvs");
-
-out:
- mutex_unlock(&wl->mutex);
-
- return ret;
-}
-
static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[])
{
u32 val;
@@ -285,8 +245,6 @@ int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len)
return wl1271_tm_cmd_interrogate(wl, tb);
case WL1271_TM_CMD_CONFIGURE:
return wl1271_tm_cmd_configure(wl, tb);
- case WL1271_TM_CMD_NVS_PUSH:
- return wl1271_tm_cmd_nvs_push(wl, tb);
case WL1271_TM_CMD_SET_PLT_MODE:
return wl1271_tm_cmd_set_plt_mode(wl, tb);
case WL1271_TM_CMD_RECOVER:
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 48fde96ce0d4..bad9e29d49b0 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -30,6 +30,7 @@
#include "reg.h"
#include "ps.h"
#include "tx.h"
+#include "event.h"
static int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id)
{
@@ -37,9 +38,10 @@ static int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id)
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
if (is_ap)
- ret = wl1271_cmd_set_ap_default_wep_key(wl, id);
+ ret = wl12xx_cmd_set_default_wep_key(wl, id,
+ wl->ap_bcast_hlid);
else
- ret = wl1271_cmd_set_sta_default_wep_key(wl, id);
+ ret = wl12xx_cmd_set_default_wep_key(wl, id, wl->sta_hlid);
if (ret < 0)
return ret;
@@ -77,9 +79,9 @@ static int wl1271_tx_update_filters(struct wl1271 *wl,
struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
+ int ret;
- hdr = (struct ieee80211_hdr *)(skb->data +
- sizeof(struct wl1271_tx_hw_descr));
+ hdr = (struct ieee80211_hdr *)skb->data;
/*
* stop bssid-based filtering before transmitting authentication
@@ -90,9 +92,19 @@ static int wl1271_tx_update_filters(struct wl1271 *wl,
if (!ieee80211_is_auth(hdr->frame_control))
return 0;
- wl1271_configure_filters(wl, FIF_OTHER_BSS);
+ if (wl->dev_hlid != WL12XX_INVALID_LINK_ID)
+ goto out;
- return wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
+ wl1271_debug(DEBUG_CMD, "starting device role for roaming");
+ ret = wl12xx_cmd_role_start_dev(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wl12xx_roc(wl, wl->dev_role_id);
+ if (ret < 0)
+ goto out;
+out:
+ return 0;
}
static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
@@ -113,25 +125,36 @@ static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid)
{
- bool fw_ps;
- u8 tx_blks;
+ bool fw_ps, single_sta;
+ u8 tx_pkts;
/* only regulate station links */
if (hlid < WL1271_AP_STA_HLID_START)
return;
+ if (WARN_ON(!wl1271_is_active_sta(wl, hlid)))
+ return;
+
fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
- tx_blks = wl->links[hlid].allocated_blks;
+ tx_pkts = wl->links[hlid].allocated_pkts;
+ single_sta = (wl->active_sta_count == 1);
/*
* if in FW PS and there is enough data in FW we can put the link
* into high-level PS and clean out its TX queues.
+ * Make an exception if this is the only connected station. In this
+ * case FW-memory congestion is not a problem.
*/
- if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
+ if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
wl1271_ps_link_start(wl, hlid, true);
}
-u8 wl1271_tx_get_hlid(struct sk_buff *skb)
+bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb)
+{
+ return wl->dummy_packet == skb;
+}
+
+u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb)
{
struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb);
@@ -144,14 +167,38 @@ u8 wl1271_tx_get_hlid(struct sk_buff *skb)
} else {
struct ieee80211_hdr *hdr;
+ if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
+ return wl->system_hlid;
+
hdr = (struct ieee80211_hdr *)skb->data;
if (ieee80211_is_mgmt(hdr->frame_control))
- return WL1271_AP_GLOBAL_HLID;
+ return wl->ap_global_hlid;
else
- return WL1271_AP_BROADCAST_HLID;
+ return wl->ap_bcast_hlid;
}
}
+static u8 wl1271_tx_get_hlid(struct wl1271 *wl, struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
+ if (wl12xx_is_dummy_packet(wl, skb))
+ return wl->system_hlid;
+
+ if (wl->bss_type == BSS_TYPE_AP_BSS)
+ return wl12xx_tx_get_hlid_ap(wl, skb);
+
+ wl1271_tx_update_filters(wl, skb);
+
+ if ((test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
+ test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags)) &&
+ !ieee80211_is_auth(hdr->frame_control) &&
+ !ieee80211_is_assoc_req(hdr->frame_control))
+ return wl->sta_hlid;
+ else
+ return wl->dev_hlid;
+}
+
static unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl,
unsigned int packet_length)
{
@@ -169,12 +216,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
u32 len;
u32 total_blocks;
int id, ret = -EBUSY, ac;
- u32 spare_blocks;
-
- if (unlikely(wl->quirks & WL12XX_QUIRK_USE_2_SPARE_BLOCKS))
- spare_blocks = 2;
- else
- spare_blocks = 1;
+ u32 spare_blocks = wl->tx_spare_blocks;
if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE)
return -EAGAIN;
@@ -188,6 +230,10 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
in the firmware */
len = wl12xx_calc_packet_alignment(wl, total_len);
+ /* in case of a dummy packet, use default amount of spare mem blocks */
+ if (unlikely(wl12xx_is_dummy_packet(wl, skb)))
+ spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
+
total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE +
spare_blocks;
@@ -206,12 +252,14 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
desc->id = id;
wl->tx_blocks_available -= total_blocks;
+ wl->tx_allocated_blocks += total_blocks;
ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
- wl->tx_allocated_blocks[ac] += total_blocks;
+ wl->tx_allocated_pkts[ac]++;
- if (wl->bss_type == BSS_TYPE_AP_BSS)
- wl->links[hlid].allocated_blks += total_blocks;
+ if (wl->bss_type == BSS_TYPE_AP_BSS &&
+ hlid >= WL1271_AP_STA_HLID_START)
+ wl->links[hlid].allocated_pkts++;
ret = 0;
@@ -225,11 +273,6 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
return ret;
}
-static bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb)
-{
- return wl->dummy_packet == skb;
-}
-
static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
u32 extra, struct ieee80211_tx_info *control,
u8 hlid)
@@ -280,9 +323,9 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
}
- if (wl->bss_type != BSS_TYPE_AP_BSS) {
- desc->aid = hlid;
+ desc->hlid = hlid;
+ if (wl->bss_type != BSS_TYPE_AP_BSS) {
/* if the packets are destined for AP (have a STA entry)
send them with AP rate policies, otherwise use default
basic rates */
@@ -291,18 +334,12 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
else
rate_idx = ACX_TX_BASIC_RATE;
} else {
- desc->hlid = hlid;
- switch (hlid) {
- case WL1271_AP_GLOBAL_HLID:
+ if (hlid == wl->ap_global_hlid)
rate_idx = ACX_TX_AP_MODE_MGMT_RATE;
- break;
- case WL1271_AP_BROADCAST_HLID:
+ else if (hlid == wl->ap_bcast_hlid)
rate_idx = ACX_TX_AP_MODE_BCST_RATE;
- break;
- default:
+ else
rate_idx = ac;
- break;
- }
}
tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY;
@@ -376,10 +413,11 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
}
}
- if (wl->bss_type == BSS_TYPE_AP_BSS)
- hlid = wl1271_tx_get_hlid(skb);
- else
- hlid = TX_HW_DEFAULT_AID;
+ hlid = wl1271_tx_get_hlid(wl, skb);
+ if (hlid == WL12XX_INVALID_LINK_ID) {
+ wl1271_error("invalid hlid. dropping skb 0x%p", skb);
+ return -EINVAL;
+ }
ret = wl1271_tx_allocate(wl, skb, extra, buf_offset, hlid);
if (ret < 0)
@@ -390,8 +428,6 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
if (wl->bss_type == BSS_TYPE_AP_BSS) {
wl1271_tx_ap_update_inconnection_sta(wl, skb);
wl1271_tx_regulate_link(wl, hlid);
- } else {
- wl1271_tx_update_filters(wl, skb);
}
/*
@@ -414,20 +450,20 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
return total_len;
}
-u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
+u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
+ enum ieee80211_band rate_band)
{
struct ieee80211_supported_band *band;
u32 enabled_rates = 0;
int bit;
- band = wl->hw->wiphy->bands[wl->band];
+ band = wl->hw->wiphy->bands[rate_band];
for (bit = 0; bit < band->n_bitrates; bit++) {
if (rate_set & 0x1)
enabled_rates |= band->bitrates[bit].hw_value;
rate_set >>= 1;
}
-#ifdef CONFIG_WL12XX_HT
/* MCS rates indication are on bits 16 - 23 */
rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates;
@@ -436,7 +472,6 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit);
rate_set >>= 1;
}
-#endif
return enabled_rates;
}
@@ -462,20 +497,24 @@ void wl1271_handle_tx_low_watermark(struct wl1271 *wl)
static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl,
struct sk_buff_head *queues)
{
- int i, q = -1;
- u32 min_blks = 0xffffffff;
+ int i, q = -1, ac;
+ u32 min_pkts = 0xffffffff;
/*
* Find a non-empty ac where:
* 1. There are packets to transmit
* 2. The FW has the least allocated blocks
+ *
+ * We prioritize the ACs according to VO>VI>BE>BK
*/
- for (i = 0; i < NUM_TX_QUEUES; i++)
- if (!skb_queue_empty(&queues[i]) &&
- (wl->tx_allocated_blocks[i] < min_blks)) {
- q = i;
- min_blks = wl->tx_allocated_blocks[q];
+ for (i = 0; i < NUM_TX_QUEUES; i++) {
+ ac = wl1271_tx_get_queue(i);
+ if (!skb_queue_empty(&queues[ac]) &&
+ (wl->tx_allocated_pkts[ac] < min_pkts)) {
+ q = ac;
+ min_pkts = wl->tx_allocated_pkts[q];
}
+ }
if (q == -1)
return NULL;
@@ -579,7 +618,7 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
if (wl12xx_is_dummy_packet(wl, skb)) {
set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
} else if (wl->bss_type == BSS_TYPE_AP_BSS) {
- u8 hlid = wl1271_tx_get_hlid(skb);
+ u8 hlid = wl1271_tx_get_hlid(wl, skb);
skb_queue_head(&wl->links[hlid].tx_queue[q], skb);
/* make sure we dequeue the same packet next time */
@@ -826,10 +865,14 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
total[i] = 0;
while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) {
wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb);
- info = IEEE80211_SKB_CB(skb);
- info->status.rates[0].idx = -1;
- info->status.rates[0].count = 0;
- ieee80211_tx_status_ni(wl->hw, skb);
+
+ if (!wl12xx_is_dummy_packet(wl, skb)) {
+ info = IEEE80211_SKB_CB(skb);
+ info->status.rates[0].idx = -1;
+ info->status.rates[0].count = 0;
+ ieee80211_tx_status_ni(wl->hw, skb);
+ }
+
total[i]++;
}
}
@@ -852,9 +895,10 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
/* TX failure */
if (wl->bss_type == BSS_TYPE_AP_BSS) {
for (i = 0; i < AP_MAX_LINKS; i++) {
+ wl1271_free_sta(wl, i);
wl1271_tx_reset_link_queues(wl, i);
- wl->links[i].allocated_blks = 0;
- wl->links[i].prev_freed_blks = 0;
+ wl->links[i].allocated_pkts = 0;
+ wl->links[i].prev_freed_pkts = 0;
}
wl->last_tx_hlid = 0;
@@ -871,10 +915,14 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
ieee80211_tx_status_ni(wl->hw, skb);
}
}
- wl->tx_queue_count[i] = 0;
}
+
+ wl->ba_rx_bitmap = 0;
}
+ for (i = 0; i < NUM_TX_QUEUES; i++)
+ wl->tx_queue_count[i] = 0;
+
wl->stopped_queues_map = 0;
/*
@@ -942,20 +990,10 @@ void wl1271_tx_flush(struct wl1271 *wl)
wl1271_warning("Unable to flush all TX buffers, timed out.");
}
-u32 wl1271_tx_min_rate_get(struct wl1271 *wl)
+u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set)
{
- int i;
- u32 rate = 0;
-
- if (!wl->basic_rate_set) {
- WARN_ON(1);
- wl->basic_rate_set = wl->conf.tx.basic_rate;
- }
-
- for (i = 0; !rate; i++) {
- if ((wl->basic_rate_set >> i) & 0x1)
- rate = 1 << i;
- }
+ if (WARN_ON(!rate_set))
+ return 0;
- return rate;
+ return BIT(__ffs(rate_set));
}
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h
index 5d719b5a3d1d..dc4f09adf088 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/tx.h
@@ -25,13 +25,11 @@
#ifndef __TX_H__
#define __TX_H__
+#define TX_HW_BLOCK_SPARE_DEFAULT 1
#define TX_HW_BLOCK_SIZE 252
#define TX_HW_MGMT_PKT_LIFETIME_TU 2000
#define TX_HW_AP_MODE_PKT_LIFETIME_TU 8000
-/* The chipset reference driver states, that the "aid" value 1
- * is for infra-BSS, but is still always used */
-#define TX_HW_DEFAULT_AID 1
#define TX_HW_ATTR_SAVE_RETRIES BIT(0)
#define TX_HW_ATTR_HEADER_PAD BIT(1)
@@ -116,12 +114,8 @@ struct wl1271_tx_hw_descr {
u8 id;
/* The packet TID value (as User-Priority) */
u8 tid;
- union {
- /* STA - Identifier of the remote STA in IBSS, 1 in infra-BSS */
- u8 aid;
- /* AP - host link ID (HLID) */
- u8 hlid;
- } __packed;
+ /* host link ID (HLID) */
+ u8 hlid;
u8 reserved;
} __packed;
@@ -133,7 +127,8 @@ enum wl1271_tx_hw_res_status {
TX_TIMEOUT = 4,
TX_KEY_NOT_FOUND = 5,
TX_PEER_NOT_FOUND = 6,
- TX_SESSION_MISMATCH = 7
+ TX_SESSION_MISMATCH = 7,
+ TX_LINK_NOT_VALID = 8,
};
struct wl1271_tx_hw_res_descr {
@@ -214,10 +209,15 @@ void wl1271_tx_complete(struct wl1271 *wl);
void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues);
void wl1271_tx_flush(struct wl1271 *wl);
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
-u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set);
-u32 wl1271_tx_min_rate_get(struct wl1271 *wl);
-u8 wl1271_tx_get_hlid(struct sk_buff *skb);
+u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
+ enum ieee80211_band rate_band);
+u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set);
+u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb);
void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid);
void wl1271_handle_tx_low_watermark(struct wl1271 *wl);
+bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb);
+
+/* from main.c */
+void wl1271_free_sta(struct wl1271 *wl, u8 hlid);
#endif
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 1a8751eb8140..1ec90fc7505e 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -112,28 +112,8 @@ extern u32 wl12xx_debug_level;
true); \
} while (0)
-#define WL1271_DEFAULT_STA_RX_CONFIG (CFG_UNI_FILTER_EN | \
- CFG_BSSID_FILTER_EN | \
- CFG_MC_FILTER_EN)
-
-#define WL1271_DEFAULT_STA_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PRSP_EN | \
- CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \
- CFG_RX_CTL_EN | CFG_RX_BCN_EN | \
- CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN)
-
-#define WL1271_DEFAULT_AP_RX_CONFIG 0
-
-#define WL1271_DEFAULT_AP_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PREQ_EN | \
- CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \
- CFG_RX_CTL_EN | CFG_RX_AUTH_EN | \
- CFG_RX_ASSOC_EN)
-
-
-
-#define WL1271_FW_NAME "ti-connectivity/wl1271-fw-2.bin"
-#define WL128X_FW_NAME "ti-connectivity/wl128x-fw.bin"
-#define WL127X_AP_FW_NAME "ti-connectivity/wl1271-fw-ap.bin"
-#define WL128X_AP_FW_NAME "ti-connectivity/wl128x-fw-ap.bin"
+#define WL127X_FW_NAME "ti-connectivity/wl127x-fw-3.bin"
+#define WL128X_FW_NAME "ti-connectivity/wl128x-fw-3.bin"
/*
* wl127x and wl128x are using the same NVS file name. However, the
@@ -157,25 +137,34 @@ extern u32 wl12xx_debug_level;
#define WL1271_DEFAULT_BEACON_INT 100
#define WL1271_DEFAULT_DTIM_PERIOD 1
-#define WL1271_AP_GLOBAL_HLID 0
-#define WL1271_AP_BROADCAST_HLID 1
-#define WL1271_AP_STA_HLID_START 2
+#define WL12XX_MAX_ROLES 4
+#define WL12XX_MAX_LINKS 12
+#define WL12XX_INVALID_ROLE_ID 0xff
+#define WL12XX_INVALID_LINK_ID 0xff
+
+/* Defined by FW as 0. Will not be freed or allocated. */
+#define WL12XX_SYSTEM_HLID 0
+
+/*
+ * TODO: we currently don't support multirole. remove
+ * this constant from the code when we do.
+ */
+#define WL1271_AP_STA_HLID_START 3
/*
- * When in AP-mode, we allow (at least) this number of mem-blocks
+ * When in AP-mode, we allow (at least) this number of packets
* to be transmitted to FW for a STA in PS-mode. Only when packets are
* present in the FW buffers it will wake the sleeping STA. We want to put
* enough packets for the driver to transmit all of its buffered data before
- * the STA goes to sleep again. But we don't want to take too much mem-blocks
+ * the STA goes to sleep again. But we don't want to take too much memory
* as it might hurt the throughput of active STAs.
- * The number of blocks (18) is enough for 2 large packets.
*/
-#define WL1271_PS_STA_MAX_BLOCKS (2 * 9)
+#define WL1271_PS_STA_MAX_PACKETS 2
#define WL1271_AP_BSS_INDEX 0
#define WL1271_AP_DEF_BEACON_EXP 20
-#define ACX_TX_DESCRIPTORS 32
+#define ACX_TX_DESCRIPTORS 16
#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
@@ -245,28 +234,24 @@ struct wl1271_stats {
#define NUM_TX_QUEUES 4
#define NUM_RX_PKT_DESC 8
-#define AP_MAX_STATIONS 5
+#define AP_MAX_STATIONS 8
-/* Broadcast and Global links + links to stations */
-#define AP_MAX_LINKS (AP_MAX_STATIONS + 2)
+/* Broadcast and Global links + system link + links to stations */
+/*
+ * TODO: when WL1271_AP_STA_HLID_START is no longer constant, change all
+ * the places that use this.
+ */
+#define AP_MAX_LINKS (AP_MAX_STATIONS + WL1271_AP_STA_HLID_START)
-/* FW status registers common for AP/STA */
-struct wl1271_fw_common_status {
+/* FW status registers */
+struct wl12xx_fw_status {
__le32 intr;
u8 fw_rx_counter;
u8 drv_rx_counter;
u8 reserved;
u8 tx_results_counter;
__le32 rx_pkt_descs[NUM_RX_PKT_DESC];
- __le32 tx_released_blks[NUM_TX_QUEUES];
__le32 fw_localtime;
-} __packed;
-
-/* FW status registers for AP */
-struct wl1271_fw_ap_status {
- struct wl1271_fw_common_status common;
-
- /* Next fields valid only in AP FW */
/*
* A bitmap (where each bit represents a single HLID)
@@ -274,29 +259,29 @@ struct wl1271_fw_ap_status {
*/
__le32 link_ps_bitmap;
- /* Number of freed MBs per HLID */
- u8 tx_lnk_free_blks[AP_MAX_LINKS];
- u8 padding_1[1];
-} __packed;
+ /*
+ * A bitmap (where each bit represents a single HLID) to indicate
+ * if the station is in Fast mode
+ */
+ __le32 link_fast_bitmap;
-/* FW status registers for STA */
-struct wl1271_fw_sta_status {
- struct wl1271_fw_common_status common;
+ /* Cumulative counter of total released mem blocks since FW-reset */
+ __le32 total_released_blks;
- u8 tx_total;
- u8 reserved1;
- __le16 reserved2;
- __le32 log_start_addr;
-} __packed;
+ /* Size (in Memory Blocks) of TX pool */
+ __le32 tx_total;
-struct wl1271_fw_full_status {
- union {
- struct wl1271_fw_common_status common;
- struct wl1271_fw_sta_status sta;
- struct wl1271_fw_ap_status ap;
- };
-} __packed;
+ /* Cumulative counter of released packets per AC */
+ u8 tx_released_pkts[NUM_TX_QUEUES];
+ /* Cumulative counter of freed packets per HLID */
+ u8 tx_lnk_free_pkts[WL12XX_MAX_LINKS];
+
+ /* Cumulative counter of released Voice memory blocks */
+ u8 tx_voice_released_blks;
+ u8 padding_1[3];
+ __le32 log_start_addr;
+} __packed;
struct wl1271_rx_mem_pool_addr {
u32 addr;
@@ -309,7 +294,7 @@ struct wl1271_scan {
unsigned long scanned_ch[BITS_TO_LONGS(WL1271_MAX_CHANNELS)];
bool failed;
u8 state;
- u8 ssid[IW_ESSID_MAX_SIZE+1];
+ u8 ssid[IEEE80211_MAX_SSID_LEN+1];
size_t ssid_len;
};
@@ -342,7 +327,7 @@ struct wl1271_ap_key {
enum wl12xx_flags {
WL1271_FLAG_STA_ASSOCIATED,
- WL1271_FLAG_JOINED,
+ WL1271_FLAG_IBSS_JOINED,
WL1271_FLAG_GPIO_POWER,
WL1271_FLAG_TX_QUEUE_STOPPED,
WL1271_FLAG_TX_PENDING,
@@ -363,17 +348,21 @@ enum wl12xx_flags {
WL1271_FLAG_SOFT_GEMINI,
WL1271_FLAG_RX_STREAMING_STARTED,
WL1271_FLAG_RECOVERY_IN_PROGRESS,
+ WL1271_FLAG_CS_PROGRESS,
};
struct wl1271_link {
/* AP-mode - TX queue per AC in link */
struct sk_buff_head tx_queue[NUM_TX_QUEUES];
- /* accounting for allocated / available TX blocks in FW */
- u8 allocated_blks;
- u8 prev_freed_blks;
+ /* accounting for allocated / freed packets in FW */
+ u8 allocated_pkts;
+ u8 prev_freed_pkts;
u8 addr[ETH_ALEN];
+
+ /* bitmap of TIDs where RX BA sessions are active for this link */
+ u8 ba_bitmap;
};
struct wl1271 {
@@ -405,7 +394,6 @@ struct wl1271 {
u8 *fw;
size_t fw_len;
- u8 fw_bss_type;
void *nvs;
size_t nvs_len;
@@ -415,18 +403,37 @@ struct wl1271 {
u8 mac_addr[ETH_ALEN];
u8 bss_type;
u8 set_bss_type;
- u8 ssid[IW_ESSID_MAX_SIZE + 1];
+ u8 p2p; /* we are using p2p role */
+ u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
u8 ssid_len;
int channel;
+ u8 role_id;
+ u8 dev_role_id;
+ u8 system_hlid;
+ u8 sta_hlid;
+ u8 dev_hlid;
+ u8 ap_global_hlid;
+ u8 ap_bcast_hlid;
+
+ unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)];
+ unsigned long roles_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)];
+ unsigned long roc_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)];
struct wl1271_acx_mem_map *target_mem_map;
/* Accounting for allocated / available TX blocks on HW */
- u32 tx_blocks_freed[NUM_TX_QUEUES];
+ u32 tx_blocks_freed;
u32 tx_blocks_available;
- u32 tx_allocated_blocks[NUM_TX_QUEUES];
+ u32 tx_allocated_blocks;
u32 tx_results_count;
+ /* amount of spare TX blocks to use */
+ u32 tx_spare_blocks;
+
+ /* Accounting for allocated / available Tx packets in HW */
+ u32 tx_pkts_freed[NUM_TX_QUEUES];
+ u32 tx_allocated_pkts[NUM_TX_QUEUES];
+
/* Transmitted TX packets counter for chipset interface */
u32 tx_packets_count;
@@ -520,6 +527,7 @@ struct wl1271 {
u32 basic_rate_set;
u32 basic_rate;
u32 rate_set;
+ u32 bitrate_masks[IEEE80211_NUM_BANDS];
/* The current band */
enum ieee80211_band band;
@@ -535,10 +543,6 @@ struct wl1271 {
struct work_struct rx_streaming_disable_work;
struct timer_list rx_streaming_timer;
- unsigned int filters;
- unsigned int rx_config;
- unsigned int rx_filter;
-
struct completion *elp_compl;
struct completion *ps_compl;
struct delayed_work elp_work;
@@ -562,7 +566,7 @@ struct wl1271 {
u32 buffer_cmd;
u32 buffer_busyword[WL1271_BUSY_WORD_CNT];
- struct wl1271_fw_full_status *fw_status;
+ struct wl12xx_fw_status *fw_status;
struct wl1271_tx_hw_res_if *tx_res_if;
struct ieee80211_vif *vif;
@@ -622,6 +626,12 @@ struct wl1271 {
/* Platform limitations */
unsigned int platform_quirks;
+
+ /* number of currently active RX BA sessions */
+ int ba_rx_session_count;
+
+ /* AP-mode - number of currently connected stations */
+ int active_sta_count;
};
struct wl1271_station {
@@ -659,21 +669,9 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen);
/* Each RX/TX transaction requires an end-of-transaction transfer */
#define WL12XX_QUIRK_END_OF_TRANSACTION BIT(0)
-/*
- * Older firmwares use 2 spare TX blocks
- * (for STA < 6.1.3.50.58 or for AP < 6.2.0.0.47)
- */
-#define WL12XX_QUIRK_USE_2_SPARE_BLOCKS BIT(1)
-
/* WL128X requires aggregated packets to be aligned to the SDIO block size */
#define WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT BIT(2)
-/*
- * WL127X AP mode requires Low Power DRPw (LPD) enable to reduce power
- * consumption
- */
-#define WL12XX_QUIRK_LPD_MODE BIT(3)
-
/* Older firmwares did not implement the FW logger over bus feature */
#define WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED BIT(4)
diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h
index 18fe542360f2..f7971d3b0898 100644
--- a/drivers/net/wireless/wl12xx/wl12xx_80211.h
+++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h
@@ -77,7 +77,7 @@ struct wl12xx_ie_header {
struct wl12xx_ie_ssid {
struct wl12xx_ie_header header;
- char ssid[IW_ESSID_MAX_SIZE];
+ char ssid[IEEE80211_MAX_SSID_LEN];
} __packed;
struct wl12xx_ie_rates {
@@ -105,18 +105,6 @@ struct wl12xx_ie_country {
/* Templates */
-struct wl12xx_beacon_template {
- struct ieee80211_header header;
- __le32 time_stamp[2];
- __le16 beacon_interval;
- __le16 capability;
- struct wl12xx_ie_ssid ssid;
- struct wl12xx_ie_rates rates;
- struct wl12xx_ie_rates ext_rates;
- struct wl12xx_ie_ds_params ds_params;
- struct wl12xx_ie_country country;
-} __packed;
-
struct wl12xx_null_data_template {
struct ieee80211_header header;
} __packed;
@@ -146,19 +134,6 @@ struct wl12xx_arp_rsp_template {
__be32 target_ip;
} __packed;
-
-struct wl12xx_probe_resp_template {
- struct ieee80211_header header;
- __le32 time_stamp[2];
- __le16 beacon_interval;
- __le16 capability;
- struct wl12xx_ie_ssid ssid;
- struct wl12xx_ie_rates rates;
- struct wl12xx_ie_rates ext_rates;
- struct wl12xx_ie_ds_params ds_params;
- struct wl12xx_ie_country country;
-} __packed;
-
struct wl12xx_disconn_template {
struct ieee80211_header header;
__le16 disconn_reason;
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index 6bc7c92fbff7..98fbf54f6004 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -1781,7 +1781,7 @@ static int wl3501_get_encode(struct net_device *dev,
keys, len_keys);
if (rc)
goto out;
- tocopy = min_t(u8, len_keys, wrqu->encoding.length);
+ tocopy = min_t(u16, len_keys, wrqu->encoding.length);
tocopy = min_t(u8, tocopy, 100);
wrqu->encoding.length = tocopy;
memcpy(extra, keys, tocopy);
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index 415eec401e2e..8efa2f2d9579 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -1722,7 +1722,7 @@ static const struct net_device_ops zd1201_netdev_ops = {
.ndo_stop = zd1201_net_stop,
.ndo_start_xmit = zd1201_hard_start_xmit,
.ndo_tx_timeout = zd1201_tx_timeout,
- .ndo_set_multicast_list = zd1201_set_multicast,
+ .ndo_set_rx_mode = zd1201_set_multicast,
.ndo_set_mac_address = zd1201_set_mac_address,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index cabfae1e70b1..0a70149df3fc 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -1332,7 +1332,7 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw,
}
}
-static u64 zd_op_get_tsf(struct ieee80211_hw *hw)
+static u64 zd_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct zd_mac *mac = zd_hw_mac(hw);
return zd_chip_get_tsf(&mac->chip);
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index 0ca86f9ec4ed..182562952c79 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -327,12 +327,12 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
xenvif_get(vif);
rtnl_lock();
- if (netif_running(vif->dev))
- xenvif_up(vif);
if (!vif->can_sg && vif->dev->mtu > ETH_DATA_LEN)
dev_set_mtu(vif->dev, ETH_DATA_LEN);
netdev_update_features(vif->dev);
netif_carrier_on(vif->dev);
+ if (netif_running(vif->dev))
+ xenvif_up(vif);
rtnl_unlock();
return 0;
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index fd00f25d9850..d5508957200e 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -60,6 +60,9 @@ struct netbk_rx_meta {
#define MAX_PENDING_REQS 256
+/* Discriminate from any valid pending_idx value. */
+#define INVALID_PENDING_IDX 0xFFFF
+
#define MAX_BUFFER_OFFSET PAGE_SIZE
/* extra field used in struct page */
@@ -155,13 +158,13 @@ static struct xen_netif_rx_response *make_rx_response(struct xenvif *vif,
u16 flags);
static inline unsigned long idx_to_pfn(struct xen_netbk *netbk,
- unsigned int idx)
+ u16 idx)
{
return page_to_pfn(netbk->mmap_pages[idx]);
}
static inline unsigned long idx_to_kaddr(struct xen_netbk *netbk,
- unsigned int idx)
+ u16 idx)
{
return (unsigned long)pfn_to_kaddr(idx_to_pfn(netbk, idx));
}
@@ -215,6 +218,16 @@ static int get_page_ext(struct page *pg,
sizeof(struct iphdr) + MAX_IPOPTLEN + \
sizeof(struct tcphdr) + MAX_TCP_OPTION_SPACE)
+static u16 frag_get_pending_idx(skb_frag_t *frag)
+{
+ return (u16)frag->page_offset;
+}
+
+static void frag_set_pending_idx(skb_frag_t *frag, u16 pending_idx)
+{
+ frag->page_offset = pending_idx;
+}
+
static inline pending_ring_idx_t pending_index(unsigned i)
{
return i & (MAX_PENDING_REQS-1);
@@ -321,7 +334,7 @@ unsigned int xen_netbk_count_skb_slots(struct xenvif *vif, struct sk_buff *skb)
count++;
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- unsigned long size = skb_shinfo(skb)->frags[i].size;
+ unsigned long size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
unsigned long bytes;
while (size > 0) {
BUG_ON(copy_off > MAX_BUFFER_OFFSET);
@@ -512,8 +525,8 @@ static int netbk_gop_skb(struct sk_buff *skb,
for (i = 0; i < nr_frags; i++) {
netbk_gop_frag_copy(vif, skb, npo,
- skb_shinfo(skb)->frags[i].page,
- skb_shinfo(skb)->frags[i].size,
+ skb_frag_page(&skb_shinfo(skb)->frags[i]),
+ skb_frag_size(&skb_shinfo(skb)->frags[i]),
skb_shinfo(skb)->frags[i].page_offset,
&head);
}
@@ -890,7 +903,7 @@ static int netbk_count_requests(struct xenvif *vif,
static struct page *xen_netbk_alloc_page(struct xen_netbk *netbk,
struct sk_buff *skb,
- unsigned long pending_idx)
+ u16 pending_idx)
{
struct page *page;
page = alloc_page(GFP_KERNEL|__GFP_COLD);
@@ -909,11 +922,11 @@ static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk *netbk,
{
struct skb_shared_info *shinfo = skb_shinfo(skb);
skb_frag_t *frags = shinfo->frags;
- unsigned long pending_idx = *((u16 *)skb->data);
+ u16 pending_idx = *((u16 *)skb->data);
int i, start;
/* Skip first skb fragment if it is on same page as header fragment. */
- start = ((unsigned long)shinfo->frags[0].page == pending_idx);
+ start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx);
for (i = start; i < shinfo->nr_frags; i++, txp++) {
struct page *page;
@@ -945,7 +958,7 @@ static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk *netbk,
memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp));
xenvif_get(vif);
pending_tx_info[pending_idx].vif = vif;
- frags[i].page = (void *)pending_idx;
+ frag_set_pending_idx(&frags[i], pending_idx);
}
return gop;
@@ -956,7 +969,7 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
struct gnttab_copy **gopp)
{
struct gnttab_copy *gop = *gopp;
- int pending_idx = *((u16 *)skb->data);
+ u16 pending_idx = *((u16 *)skb->data);
struct pending_tx_info *pending_tx_info = netbk->pending_tx_info;
struct xenvif *vif = pending_tx_info[pending_idx].vif;
struct xen_netif_tx_request *txp;
@@ -976,13 +989,13 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
}
/* Skip first skb fragment if it is on same page as header fragment. */
- start = ((unsigned long)shinfo->frags[0].page == pending_idx);
+ start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx);
for (i = start; i < nr_frags; i++) {
int j, newerr;
pending_ring_idx_t index;
- pending_idx = (unsigned long)shinfo->frags[i].page;
+ pending_idx = frag_get_pending_idx(&shinfo->frags[i]);
/* Check error status: if okay then remember grant handle. */
newerr = (++gop)->status;
@@ -1008,7 +1021,7 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
pending_idx = *((u16 *)skb->data);
xen_netbk_idx_release(netbk, pending_idx);
for (j = start; j < i; j++) {
- pending_idx = (unsigned long)shinfo->frags[i].page;
+ pending_idx = frag_get_pending_idx(&shinfo->frags[i]);
xen_netbk_idx_release(netbk, pending_idx);
}
@@ -1029,15 +1042,14 @@ static void xen_netbk_fill_frags(struct xen_netbk *netbk, struct sk_buff *skb)
for (i = 0; i < nr_frags; i++) {
skb_frag_t *frag = shinfo->frags + i;
struct xen_netif_tx_request *txp;
- unsigned long pending_idx;
+ struct page *page;
+ u16 pending_idx;
- pending_idx = (unsigned long)frag->page;
+ pending_idx = frag_get_pending_idx(frag);
txp = &netbk->pending_tx_info[pending_idx].req;
- frag->page = virt_to_page(idx_to_kaddr(netbk, pending_idx));
- frag->size = txp->size;
- frag->page_offset = txp->offset;
-
+ page = virt_to_page(idx_to_kaddr(netbk, pending_idx));
+ __skb_fill_page_desc(skb, i, page, txp->offset, txp->size);
skb->len += txp->size;
skb->data_len += txp->size;
skb->truesize += txp->size;
@@ -1349,11 +1361,11 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
skb_shinfo(skb)->nr_frags = ret;
if (data_len < txreq.size) {
skb_shinfo(skb)->nr_frags++;
- skb_shinfo(skb)->frags[0].page =
- (void *)(unsigned long)pending_idx;
+ frag_set_pending_idx(&skb_shinfo(skb)->frags[0],
+ pending_idx);
} else {
- /* Discriminate from any valid pending_idx value. */
- skb_shinfo(skb)->frags[0].page = (void *)~0UL;
+ frag_set_pending_idx(&skb_shinfo(skb)->frags[0],
+ INVALID_PENDING_IDX);
}
__skb_queue_tail(&netbk->tx_queue, skb);
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index d7c8a98daff6..226faab23603 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -275,7 +275,7 @@ no_skb:
break;
}
- skb_shinfo(skb)->frags[0].page = page;
+ __skb_fill_page_desc(skb, 0, page, 0, 0);
skb_shinfo(skb)->nr_frags = 1;
__skb_queue_tail(&np->rx_batch, skb);
}
@@ -309,8 +309,8 @@ no_skb:
BUG_ON((signed short)ref < 0);
np->grant_rx_ref[id] = ref;
- pfn = page_to_pfn(skb_shinfo(skb)->frags[0].page);
- vaddr = page_address(skb_shinfo(skb)->frags[0].page);
+ pfn = page_to_pfn(skb_frag_page(&skb_shinfo(skb)->frags[0]));
+ vaddr = page_address(skb_frag_page(&skb_shinfo(skb)->frags[0]));
req = RING_GET_REQUEST(&np->rx, req_prod + i);
gnttab_grant_foreign_access_ref(ref,
@@ -461,13 +461,13 @@ static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev,
ref = gnttab_claim_grant_reference(&np->gref_tx_head);
BUG_ON((signed short)ref < 0);
- mfn = pfn_to_mfn(page_to_pfn(frag->page));
+ mfn = pfn_to_mfn(page_to_pfn(skb_frag_page(frag)));
gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id,
mfn, GNTMAP_readonly);
tx->gref = np->grant_tx_ref[id] = ref;
tx->offset = frag->page_offset;
- tx->size = frag->size;
+ tx->size = skb_frag_size(frag);
tx->flags = 0;
}
@@ -762,23 +762,22 @@ static RING_IDX xennet_fill_frags(struct netfront_info *np,
struct skb_shared_info *shinfo = skb_shinfo(skb);
int nr_frags = shinfo->nr_frags;
RING_IDX cons = np->rx.rsp_cons;
- skb_frag_t *frag = shinfo->frags + nr_frags;
struct sk_buff *nskb;
while ((nskb = __skb_dequeue(list))) {
struct xen_netif_rx_response *rx =
RING_GET_RESPONSE(&np->rx, ++cons);
+ skb_frag_t *nfrag = &skb_shinfo(nskb)->frags[0];
- frag->page = skb_shinfo(nskb)->frags[0].page;
- frag->page_offset = rx->offset;
- frag->size = rx->status;
+ __skb_fill_page_desc(skb, nr_frags,
+ skb_frag_page(nfrag),
+ rx->offset, rx->status);
skb->data_len += rx->status;
skb_shinfo(nskb)->nr_frags = 0;
kfree_skb(nskb);
- frag++;
nr_frags++;
}
@@ -873,7 +872,7 @@ static int handle_incoming_queue(struct net_device *dev,
memcpy(skb->data, vaddr + offset,
skb_headlen(skb));
- if (page != skb_shinfo(skb)->frags[0].page)
+ if (page != skb_frag_page(&skb_shinfo(skb)->frags[0]))
__free_page(page);
/* Ethernet work: Delayed to here as it peeks the header. */
@@ -954,7 +953,8 @@ err:
}
}
- NETFRONT_SKB_CB(skb)->page = skb_shinfo(skb)->frags[0].page;
+ NETFRONT_SKB_CB(skb)->page =
+ skb_frag_page(&skb_shinfo(skb)->frags[0]);
NETFRONT_SKB_CB(skb)->offset = rx->offset;
len = rx->status;
@@ -965,10 +965,10 @@ err:
if (rx->status > len) {
skb_shinfo(skb)->frags[0].page_offset =
rx->offset + len;
- skb_shinfo(skb)->frags[0].size = rx->status - len;
+ skb_frag_size_set(&skb_shinfo(skb)->frags[0], rx->status - len);
skb->data_len = rx->status - len;
} else {
- skb_shinfo(skb)->frags[0].page = NULL;
+ __skb_fill_page_desc(skb, 0, NULL, 0, 0);
skb_shinfo(skb)->nr_frags = 0;
}
@@ -1143,7 +1143,8 @@ static void xennet_release_rx_bufs(struct netfront_info *np)
if (!xen_feature(XENFEAT_auto_translated_physmap)) {
/* Remap the page. */
- struct page *page = skb_shinfo(skb)->frags[0].page;
+ const struct page *page =
+ skb_frag_page(&skb_shinfo(skb)->frags[0]);
unsigned long pfn = page_to_pfn(page);
void *vaddr = page_address(page);
@@ -1650,6 +1651,8 @@ static int xennet_connect(struct net_device *dev)
/* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */
for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) {
+ skb_frag_t *frag;
+ const struct page *page;
if (!np->rx_skbs[i])
continue;
@@ -1657,10 +1660,11 @@ static int xennet_connect(struct net_device *dev)
ref = np->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(np, i);
req = RING_GET_REQUEST(&np->rx, requeue_idx);
+ frag = &skb_shinfo(skb)->frags[0];
+ page = skb_frag_page(frag);
gnttab_grant_foreign_access_ref(
ref, np->xbdev->otherend_id,
- pfn_to_mfn(page_to_pfn(skb_shinfo(skb)->
- frags->page)),
+ pfn_to_mfn(page_to_pfn(page)),
0);
req->gref = ref;
req->id = requeue_idx;
diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index 2acff4307ca4..5af959274d4e 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -27,4 +27,15 @@ config NFC_PN533
Say Y here to compile support for PN533 devices into the
kernel or say M to compile it as module (pn533).
+config NFC_WILINK
+ tristate "Texas Instruments NFC WiLink driver"
+ depends on TI_ST && NFC_NCI
+ help
+ This enables the NFC driver for Texas Instrument's BT/FM/GPS/NFC
+ combo devices. This makes use of shared transport line discipline
+ core driver to communicate with the NFC core of the combo chip.
+
+ Say Y here to compile support for Texas Instrument's NFC WiLink driver
+ into the kernel or say M to compile it as module.
+
endmenu
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index 8ef446d2c1bd..ab99e8572f02 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -4,5 +4,6 @@
obj-$(CONFIG_PN544_NFC) += pn544.o
obj-$(CONFIG_NFC_PN533) += pn533.o
+obj-$(CONFIG_NFC_WILINK) += nfcwilink.o
ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/nfcwilink.c b/drivers/nfc/nfcwilink.c
new file mode 100644
index 000000000000..5b0f1ff80361
--- /dev/null
+++ b/drivers/nfc/nfcwilink.c
@@ -0,0 +1,342 @@
+/*
+ * Texas Instrument's NFC Driver For Shared Transport.
+ *
+ * NFC Driver acts as interface between NCI core and
+ * TI Shared Transport Layer.
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ * Written by Ilan Elias <ilane@ti.com>
+ *
+ * Acknowledgements:
+ * This file is based on btwilink.c, which was written
+ * by Raja Mani and Pavan Savoy.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <linux/platform_device.h>
+#include <linux/nfc.h>
+#include <net/nfc/nci.h>
+#include <net/nfc/nci_core.h>
+#include <linux/ti_wilink_st.h>
+
+#define NFCWILINK_CHNL 12
+#define NFCWILINK_OPCODE 7
+#define NFCWILINK_MAX_FRAME_SIZE 300
+#define NFCWILINK_HDR_LEN 4
+#define NFCWILINK_OFFSET_LEN_IN_HDR 1
+#define NFCWILINK_LEN_SIZE 2
+#define NFCWILINK_REGISTER_TIMEOUT 8000 /* 8 sec */
+
+struct nfcwilink_hdr {
+ u8 chnl;
+ u8 opcode;
+ u16 len;
+} __packed;
+
+struct nfcwilink {
+ struct platform_device *pdev;
+ struct nci_dev *ndev;
+ unsigned long flags;
+
+ char st_register_cb_status;
+ long (*st_write) (struct sk_buff *);
+ struct completion st_register_completed;
+};
+
+/* NFCWILINK driver flags */
+enum {
+ NFCWILINK_RUNNING,
+};
+
+/* Called by ST when registration is complete */
+static void nfcwilink_register_complete(void *priv_data, char data)
+{
+ struct nfcwilink *drv = priv_data;
+
+ nfc_dev_dbg(&drv->pdev->dev, "register_complete entry");
+
+ /* store ST registration status */
+ drv->st_register_cb_status = data;
+
+ /* complete the wait in nfc_st_open() */
+ complete(&drv->st_register_completed);
+}
+
+/* Called by ST when receive data is available */
+static long nfcwilink_receive(void *priv_data, struct sk_buff *skb)
+{
+ struct nfcwilink *drv = priv_data;
+ int rc;
+
+ nfc_dev_dbg(&drv->pdev->dev, "receive entry, len %d", skb->len);
+
+ if (!skb)
+ return -EFAULT;
+
+ if (!drv) {
+ kfree_skb(skb);
+ return -EFAULT;
+ }
+
+ /* strip the ST header
+ (apart for the chnl byte, which is not received in the hdr) */
+ skb_pull(skb, (NFCWILINK_HDR_LEN-1));
+
+ skb->dev = (void *) drv->ndev;
+
+ /* Forward skb to NCI core layer */
+ rc = nci_recv_frame(skb);
+ if (rc < 0) {
+ nfc_dev_err(&drv->pdev->dev, "nci_recv_frame failed %d", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+/* protocol structure registered with ST */
+static struct st_proto_s nfcwilink_proto = {
+ .chnl_id = NFCWILINK_CHNL,
+ .max_frame_size = NFCWILINK_MAX_FRAME_SIZE,
+ .hdr_len = (NFCWILINK_HDR_LEN-1), /* not including chnl byte */
+ .offset_len_in_hdr = NFCWILINK_OFFSET_LEN_IN_HDR,
+ .len_size = NFCWILINK_LEN_SIZE,
+ .reserve = 0,
+ .recv = nfcwilink_receive,
+ .reg_complete_cb = nfcwilink_register_complete,
+ .write = NULL,
+};
+
+static int nfcwilink_open(struct nci_dev *ndev)
+{
+ struct nfcwilink *drv = nci_get_drvdata(ndev);
+ unsigned long comp_ret;
+ int rc;
+
+ nfc_dev_dbg(&drv->pdev->dev, "open entry");
+
+ if (test_and_set_bit(NFCWILINK_RUNNING, &drv->flags)) {
+ rc = -EBUSY;
+ goto exit;
+ }
+
+ nfcwilink_proto.priv_data = drv;
+
+ init_completion(&drv->st_register_completed);
+ drv->st_register_cb_status = -EINPROGRESS;
+
+ rc = st_register(&nfcwilink_proto);
+ if (rc < 0) {
+ if (rc == -EINPROGRESS) {
+ comp_ret = wait_for_completion_timeout(
+ &drv->st_register_completed,
+ msecs_to_jiffies(NFCWILINK_REGISTER_TIMEOUT));
+
+ nfc_dev_dbg(&drv->pdev->dev,
+ "wait_for_completion_timeout returned %ld",
+ comp_ret);
+
+ if (comp_ret == 0) {
+ /* timeout */
+ rc = -ETIMEDOUT;
+ goto clear_exit;
+ } else if (drv->st_register_cb_status != 0) {
+ rc = drv->st_register_cb_status;
+ nfc_dev_err(&drv->pdev->dev,
+ "st_register_cb failed %d", rc);
+ goto clear_exit;
+ }
+ } else {
+ nfc_dev_err(&drv->pdev->dev,
+ "st_register failed %d", rc);
+ goto clear_exit;
+ }
+ }
+
+ /* st_register MUST fill the write callback */
+ BUG_ON(nfcwilink_proto.write == NULL);
+ drv->st_write = nfcwilink_proto.write;
+
+ goto exit;
+
+clear_exit:
+ clear_bit(NFCWILINK_RUNNING, &drv->flags);
+
+exit:
+ return rc;
+}
+
+static int nfcwilink_close(struct nci_dev *ndev)
+{
+ struct nfcwilink *drv = nci_get_drvdata(ndev);
+ int rc;
+
+ nfc_dev_dbg(&drv->pdev->dev, "close entry");
+
+ if (!test_and_clear_bit(NFCWILINK_RUNNING, &drv->flags))
+ return 0;
+
+ rc = st_unregister(&nfcwilink_proto);
+ if (rc)
+ nfc_dev_err(&drv->pdev->dev, "st_unregister failed %d", rc);
+
+ drv->st_write = NULL;
+
+ return rc;
+}
+
+static int nfcwilink_send(struct sk_buff *skb)
+{
+ struct nci_dev *ndev = (struct nci_dev *)skb->dev;
+ struct nfcwilink *drv = nci_get_drvdata(ndev);
+ struct nfcwilink_hdr hdr = {NFCWILINK_CHNL, NFCWILINK_OPCODE, 0x0000};
+ long len;
+
+ nfc_dev_dbg(&drv->pdev->dev, "send entry, len %d", skb->len);
+
+ if (!test_bit(NFCWILINK_RUNNING, &drv->flags))
+ return -EBUSY;
+
+ /* add the ST hdr to the start of the buffer */
+ hdr.len = skb->len;
+ memcpy(skb_push(skb, NFCWILINK_HDR_LEN), &hdr, NFCWILINK_HDR_LEN);
+
+ /* Insert skb to shared transport layer's transmit queue.
+ * Freeing skb memory is taken care in shared transport layer,
+ * so don't free skb memory here.
+ */
+ len = drv->st_write(skb);
+ if (len < 0) {
+ kfree_skb(skb);
+ nfc_dev_err(&drv->pdev->dev, "st_write failed %ld", len);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static struct nci_ops nfcwilink_ops = {
+ .open = nfcwilink_open,
+ .close = nfcwilink_close,
+ .send = nfcwilink_send,
+};
+
+static int nfcwilink_probe(struct platform_device *pdev)
+{
+ static struct nfcwilink *drv;
+ int rc;
+ u32 protocols;
+
+ nfc_dev_dbg(&pdev->dev, "probe entry");
+
+ drv = kzalloc(sizeof(struct nfcwilink), GFP_KERNEL);
+ if (!drv) {
+ rc = -ENOMEM;
+ goto exit;
+ }
+
+ drv->pdev = pdev;
+
+ protocols = NFC_PROTO_JEWEL_MASK
+ | NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK
+ | NFC_PROTO_ISO14443_MASK
+ | NFC_PROTO_NFC_DEP_MASK;
+
+ drv->ndev = nci_allocate_device(&nfcwilink_ops,
+ protocols,
+ NFCWILINK_HDR_LEN,
+ 0);
+ if (!drv->ndev) {
+ nfc_dev_err(&pdev->dev, "nci_allocate_device failed");
+ rc = -ENOMEM;
+ goto free_exit;
+ }
+
+ nci_set_parent_dev(drv->ndev, &pdev->dev);
+ nci_set_drvdata(drv->ndev, drv);
+
+ rc = nci_register_device(drv->ndev);
+ if (rc < 0) {
+ nfc_dev_err(&pdev->dev, "nci_register_device failed %d", rc);
+ goto free_dev_exit;
+ }
+
+ dev_set_drvdata(&pdev->dev, drv);
+
+ goto exit;
+
+free_dev_exit:
+ nci_free_device(drv->ndev);
+
+free_exit:
+ kfree(drv);
+
+exit:
+ return rc;
+}
+
+static int nfcwilink_remove(struct platform_device *pdev)
+{
+ struct nfcwilink *drv = dev_get_drvdata(&pdev->dev);
+ struct nci_dev *ndev;
+
+ nfc_dev_dbg(&pdev->dev, "remove entry");
+
+ if (!drv)
+ return -EFAULT;
+
+ ndev = drv->ndev;
+
+ nci_unregister_device(ndev);
+ nci_free_device(ndev);
+
+ kfree(drv);
+
+ dev_set_drvdata(&pdev->dev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver nfcwilink_driver = {
+ .probe = nfcwilink_probe,
+ .remove = nfcwilink_remove,
+ .driver = {
+ .name = "nfcwilink",
+ .owner = THIS_MODULE,
+ },
+};
+
+/* ------- Module Init/Exit interfaces ------ */
+static int __init nfcwilink_init(void)
+{
+ printk(KERN_INFO "NFC Driver for TI WiLink");
+
+ return platform_driver_register(&nfcwilink_driver);
+}
+
+static void __exit nfcwilink_exit(void)
+{
+ platform_driver_unregister(&nfcwilink_driver);
+}
+
+module_init(nfcwilink_init);
+module_exit(nfcwilink_exit);
+
+/* ------ Module Info ------ */
+
+MODULE_AUTHOR("Ilan Elias <ilane@ti.com>");
+MODULE_DESCRIPTION("NFC Driver for TI Shared Transport");
+MODULE_LICENSE("GPL");
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index c77e0543e502..7bcb1febef0d 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -28,7 +28,7 @@
#include <linux/usb.h>
#include <linux/nfc.h>
#include <linux/netdevice.h>
-#include <net/nfc.h>
+#include <net/nfc/nfc.h>
#define VERSION "0.1"
@@ -1246,7 +1246,6 @@ static int pn533_data_exchange_tx_frame(struct pn533 *dev, struct sk_buff *skb)
{
int payload_len = skb->len;
struct pn533_frame *out_frame;
- struct sk_buff *discarded;
u8 tg;
nfc_dev_dbg(&dev->interface->dev, "%s - Sending %d bytes", __func__,
@@ -1260,18 +1259,6 @@ static int pn533_data_exchange_tx_frame(struct pn533 *dev, struct sk_buff *skb)
return -ENOSYS;
}
- /* Reserving header space */
- if (skb_cow_head(skb, PN533_CMD_DATAEXCH_HEAD_LEN)) {
- nfc_dev_err(&dev->interface->dev, "Error to add header data");
- return -ENOMEM;
- }
-
- /* Reserving tail space, see pn533_tx_frame_finish */
- if (skb_cow_data(skb, PN533_FRAME_TAIL_SIZE, &discarded) < 0) {
- nfc_dev_err(&dev->interface->dev, "Error to add tail data");
- return -ENOMEM;
- }
-
skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN);
out_frame = (struct pn533_frame *) skb->data;
@@ -1445,6 +1432,8 @@ static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata,
}
struct nfc_ops pn533_nfc_ops = {
+ .dev_up = NULL,
+ .dev_down = NULL,
.start_poll = pn533_start_poll,
.stop_poll = pn533_stop_poll,
.activate_target = pn533_activate_target,
@@ -1536,7 +1525,9 @@ static int pn533_probe(struct usb_interface *interface,
| NFC_PROTO_ISO14443_MASK
| NFC_PROTO_NFC_DEP_MASK;
- dev->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols);
+ dev->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols,
+ PN533_CMD_DATAEXCH_HEAD_LEN,
+ PN533_FRAME_TAIL_SIZE);
if (!dev->nfc_dev)
goto kill_tasklet;
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
index 57a6d19eba4c..a6f762188bc3 100644
--- a/drivers/parisc/sba_iommu.c
+++ b/drivers/parisc/sba_iommu.c
@@ -668,7 +668,7 @@ sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
* @dev: instance of PCI owned by the driver that's asking
* @mask: number of address bits this PCI device can handle
*
- * See Documentation/PCI/PCI-DMA-mapping.txt
+ * See Documentation/DMA-API-HOWTO.txt
*/
static int sba_dma_supported( struct device *dev, u64 mask)
{
@@ -680,7 +680,7 @@ static int sba_dma_supported( struct device *dev, u64 mask)
return(0);
}
- /* Documentation/PCI/PCI-DMA-mapping.txt tells drivers to try 64-bit
+ /* Documentation/DMA-API-HOWTO.txt tells drivers to try 64-bit
* first, then fall back to 32-bit if that fails.
* We are just "encouraging" 32-bit DMA masks here since we can
* never allow IOMMU bypass unless we add special support for ZX1.
@@ -706,7 +706,7 @@ static int sba_dma_supported( struct device *dev, u64 mask)
* @size: number of bytes to map in driver buffer.
* @direction: R/W or both.
*
- * See Documentation/PCI/PCI-DMA-mapping.txt
+ * See Documentation/DMA-API-HOWTO.txt
*/
static dma_addr_t
sba_map_single(struct device *dev, void *addr, size_t size,
@@ -785,7 +785,7 @@ sba_map_single(struct device *dev, void *addr, size_t size,
* @size: number of bytes mapped in driver buffer.
* @direction: R/W or both.
*
- * See Documentation/PCI/PCI-DMA-mapping.txt
+ * See Documentation/DMA-API-HOWTO.txt
*/
static void
sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size,
@@ -861,7 +861,7 @@ sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size,
* @size: number of bytes mapped in driver buffer.
* @dma_handle: IOVA of new buffer.
*
- * See Documentation/PCI/PCI-DMA-mapping.txt
+ * See Documentation/DMA-API-HOWTO.txt
*/
static void *sba_alloc_consistent(struct device *hwdev, size_t size,
dma_addr_t *dma_handle, gfp_t gfp)
@@ -892,7 +892,7 @@ static void *sba_alloc_consistent(struct device *hwdev, size_t size,
* @vaddr: virtual address IOVA of "consistent" buffer.
* @dma_handler: IO virtual address of "consistent" buffer.
*
- * See Documentation/PCI/PCI-DMA-mapping.txt
+ * See Documentation/DMA-API-HOWTO.txt
*/
static void
sba_free_consistent(struct device *hwdev, size_t size, void *vaddr,
@@ -927,7 +927,7 @@ int dump_run_sg = 0;
* @nents: number of entries in list
* @direction: R/W or both.
*
- * See Documentation/PCI/PCI-DMA-mapping.txt
+ * See Documentation/DMA-API-HOWTO.txt
*/
static int
sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
@@ -1011,7 +1011,7 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
* @nents: number of entries in list
* @direction: R/W or both.
*
- * See Documentation/PCI/PCI-DMA-mapping.txt
+ * See Documentation/DMA-API-HOWTO.txt
*/
static void
sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
diff --git a/drivers/pci/hotplug/pcihp_slot.c b/drivers/pci/hotplug/pcihp_slot.c
index 753b21aaea61..3ffd9c1acc0a 100644
--- a/drivers/pci/hotplug/pcihp_slot.c
+++ b/drivers/pci/hotplug/pcihp_slot.c
@@ -169,7 +169,9 @@ void pci_configure_slot(struct pci_dev *dev)
(dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
return;
- pcie_bus_configure_settings(dev->bus, dev->bus->self->pcie_mpss);
+ if (dev->bus && dev->bus->self)
+ pcie_bus_configure_settings(dev->bus,
+ dev->bus->self->pcie_mpss);
memset(&hpp, 0, sizeof(hpp));
ret = pci_get_hp_params(dev, &hpp);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 0ce67423a0a3..e9651f0a8817 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -77,7 +77,7 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;
unsigned long pci_hotplug_io_size = DEFAULT_HOTPLUG_IO_SIZE;
unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE;
-enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_PERFORMANCE;
+enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_TUNE_OFF;
/*
* The default CLS is used if arch didn't set CLS explicitly and not
@@ -3568,10 +3568,14 @@ static int __init pci_setup(char *str)
pci_hotplug_io_size = memparse(str + 9, &str);
} else if (!strncmp(str, "hpmemsize=", 10)) {
pci_hotplug_mem_size = memparse(str + 10, &str);
+ } else if (!strncmp(str, "pcie_bus_tune_off", 17)) {
+ pcie_bus_config = PCIE_BUS_TUNE_OFF;
} else if (!strncmp(str, "pcie_bus_safe", 13)) {
pcie_bus_config = PCIE_BUS_SAFE;
} else if (!strncmp(str, "pcie_bus_perf", 13)) {
pcie_bus_config = PCIE_BUS_PERFORMANCE;
+ } else if (!strncmp(str, "pcie_bus_peer2peer", 18)) {
+ pcie_bus_config = PCIE_BUS_PEER2PEER;
} else {
printk(KERN_ERR "PCI: Unknown option `%s'\n",
str);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 8473727b29fa..6ab6bd3df4b2 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1351,7 +1351,8 @@ static int pcie_find_smpss(struct pci_dev *dev, void *data)
* will occur as normal.
*/
if (dev->is_hotplug_bridge && (!list_is_singular(&dev->bus->devices) ||
- dev->bus->self->pcie_type != PCI_EXP_TYPE_ROOT_PORT))
+ (dev->bus->self &&
+ dev->bus->self->pcie_type != PCI_EXP_TYPE_ROOT_PORT)))
*smpss = 0;
if (*smpss > dev->pcie_mpss)
@@ -1396,34 +1397,37 @@ static void pcie_write_mps(struct pci_dev *dev, int mps)
static void pcie_write_mrrs(struct pci_dev *dev, int mps)
{
- int rc, mrrs;
+ int rc, mrrs, dev_mpss;
- if (pcie_bus_config == PCIE_BUS_PERFORMANCE) {
- int dev_mpss = 128 << dev->pcie_mpss;
+ /* In the "safe" case, do not configure the MRRS. There appear to be
+ * issues with setting MRRS to 0 on a number of devices.
+ */
- /* For Max performance, the MRRS must be set to the largest
- * supported value. However, it cannot be configured larger
- * than the MPS the device or the bus can support. This assumes
- * that the largest MRRS available on the device cannot be
- * smaller than the device MPSS.
- */
- mrrs = mps < dev_mpss ? mps : dev_mpss;
- } else
- /* In the "safe" case, configure the MRRS for fairness on the
- * bus by making all devices have the same size
- */
- mrrs = mps;
+ if (pcie_bus_config != PCIE_BUS_PERFORMANCE)
+ return;
+ dev_mpss = 128 << dev->pcie_mpss;
+
+ /* For Max performance, the MRRS must be set to the largest supported
+ * value. However, it cannot be configured larger than the MPS the
+ * device or the bus can support. This assumes that the largest MRRS
+ * available on the device cannot be smaller than the device MPSS.
+ */
+ mrrs = min(mps, dev_mpss);
/* MRRS is a R/W register. Invalid values can be written, but a
- * subsiquent read will verify if the value is acceptable or not.
+ * subsequent read will verify if the value is acceptable or not.
* If the MRRS value provided is not acceptable (e.g., too large),
* shrink the value until it is acceptable to the HW.
*/
while (mrrs != pcie_get_readrq(dev) && mrrs >= 128) {
+ dev_warn(&dev->dev, "Attempting to modify the PCI-E MRRS value"
+ " to %d. If any issues are encountered, please try "
+ "running with pci=pcie_bus_safe\n", mrrs);
rc = pcie_set_readrq(dev, mrrs);
if (rc)
- dev_err(&dev->dev, "Failed attempting to set the MRRS\n");
+ dev_err(&dev->dev,
+ "Failed attempting to set the MRRS\n");
mrrs /= 2;
}
@@ -1436,13 +1440,13 @@ static int pcie_bus_configure_set(struct pci_dev *dev, void *data)
if (!pci_is_pcie(dev))
return 0;
- dev_info(&dev->dev, "Dev MPS %d MPSS %d MRRS %d\n",
+ dev_dbg(&dev->dev, "Dev MPS %d MPSS %d MRRS %d\n",
pcie_get_mps(dev), 128<<dev->pcie_mpss, pcie_get_readrq(dev));
pcie_write_mps(dev, mps);
pcie_write_mrrs(dev, mps);
- dev_info(&dev->dev, "Dev MPS %d MPSS %d MRRS %d\n",
+ dev_dbg(&dev->dev, "Dev MPS %d MPSS %d MRRS %d\n",
pcie_get_mps(dev), 128<<dev->pcie_mpss, pcie_get_readrq(dev));
return 0;
@@ -1454,15 +1458,24 @@ static int pcie_bus_configure_set(struct pci_dev *dev, void *data)
*/
void pcie_bus_configure_settings(struct pci_bus *bus, u8 mpss)
{
- u8 smpss = mpss;
+ u8 smpss;
- if (!bus->self)
+ if (!pci_is_pcie(bus->self))
return;
- if (!pci_is_pcie(bus->self))
+ if (pcie_bus_config == PCIE_BUS_TUNE_OFF)
return;
+ /* FIXME - Peer to peer DMA is possible, though the endpoint would need
+ * to be aware to the MPS of the destination. To work around this,
+ * simply force the MPS of the entire system to the smallest possible.
+ */
+ if (pcie_bus_config == PCIE_BUS_PEER2PEER)
+ smpss = 0;
+
if (pcie_bus_config == PCIE_BUS_SAFE) {
+ smpss = mpss;
+
pcie_find_smpss(bus->self, &smpss);
pci_walk_bus(bus, pcie_find_smpss, &smpss);
}
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
index 6fa215a38615..90832a955991 100644
--- a/drivers/pci/xen-pcifront.c
+++ b/drivers/pci/xen-pcifront.c
@@ -400,9 +400,8 @@ static int pcifront_claim_resource(struct pci_dev *dev, void *data)
dev_info(&pdev->xdev->dev, "claiming resource %s/%d\n",
pci_name(dev), i);
if (pci_claim_resource(dev, i)) {
- dev_err(&pdev->xdev->dev, "Could not claim "
- "resource %s/%d! Device offline. Try "
- "giving less than 4GB to domain.\n",
+ dev_err(&pdev->xdev->dev, "Could not claim resource %s/%d! "
+ "Device offline. Try using e820_host=1 in the guest config.\n",
pci_name(dev), i);
}
}
diff --git a/drivers/pcmcia/sa1100_simpad.c b/drivers/pcmcia/sa1100_simpad.c
index c998f7aaadbc..0fac9658b020 100644
--- a/drivers/pcmcia/sa1100_simpad.c
+++ b/drivers/pcmcia/sa1100_simpad.c
@@ -15,10 +15,6 @@
#include <mach/simpad.h>
#include "sa1100_generic.h"
-extern long get_cs3_shadow(void);
-extern void set_cs3_bit(int value);
-extern void clear_cs3_bit(int value);
-
static struct pcmcia_irqs irqs[] = {
{ 1, IRQ_GPIO_CF_CD, "CF_CD" },
};
@@ -26,7 +22,7 @@ static struct pcmcia_irqs irqs[] = {
static int simpad_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
{
- clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
+ simpad_clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
skt->socket.pci_irq = IRQ_GPIO_CF_IRQ;
@@ -38,8 +34,8 @@ static void simpad_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
/* Disable CF bus: */
- //set_cs3_bit(PCMCIA_BUFF_DIS);
- clear_cs3_bit(PCMCIA_RESET);
+ /*simpad_set_cs3_bit(PCMCIA_BUFF_DIS);*/
+ simpad_clear_cs3_bit(PCMCIA_RESET);
}
static void
@@ -47,15 +43,16 @@ simpad_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
struct pcmcia_state *state)
{
unsigned long levels = GPLR;
- long cs3reg = get_cs3_shadow();
+ long cs3reg = simpad_get_cs3_ro();
state->detect=((levels & GPIO_CF_CD)==0)?1:0;
state->ready=(levels & GPIO_CF_IRQ)?1:0;
- state->bvd1=1; /* Not available on Simpad. */
- state->bvd2=1; /* Not available on Simpad. */
+ state->bvd1 = 1; /* Might be cs3reg & PCMCIA_BVD1 */
+ state->bvd2 = 1; /* Might be cs3reg & PCMCIA_BVD2 */
state->wrprot=0; /* Not available on Simpad. */
-
- if((cs3reg & 0x0c) == 0x0c) {
+
+ if ((cs3reg & (PCMCIA_VS1|PCMCIA_VS2)) ==
+ (PCMCIA_VS1|PCMCIA_VS2)) {
state->vs_3v=0;
state->vs_Xv=0;
} else {
@@ -75,23 +72,23 @@ simpad_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
/* Murphy: see table of MIC2562a-1 */
switch (state->Vcc) {
case 0:
- clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
+ simpad_clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
break;
case 33:
- clear_cs3_bit(VCC_3V_EN|EN1);
- set_cs3_bit(VCC_5V_EN|EN0);
+ simpad_clear_cs3_bit(VCC_3V_EN|EN1);
+ simpad_set_cs3_bit(VCC_5V_EN|EN0);
break;
case 50:
- clear_cs3_bit(VCC_5V_EN|EN1);
- set_cs3_bit(VCC_3V_EN|EN0);
+ simpad_clear_cs3_bit(VCC_5V_EN|EN1);
+ simpad_set_cs3_bit(VCC_3V_EN|EN0);
break;
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
__func__, state->Vcc);
- clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
+ simpad_clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
local_irq_restore(flags);
return -1;
}
@@ -110,7 +107,7 @@ static void simpad_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
static void simpad_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
{
soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
- set_cs3_bit(PCMCIA_RESET);
+ simpad_set_cs3_bit(PCMCIA_RESET);
}
static struct pcmcia_low_level simpad_pcmcia_ops = {
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
new file mode 100644
index 000000000000..ef566443f945
--- /dev/null
+++ b/drivers/pinctrl/Kconfig
@@ -0,0 +1,43 @@
+#
+# PINCTRL infrastructure and drivers
+#
+
+menuconfig PINCTRL
+ bool "PINCTRL Support"
+ depends on EXPERIMENTAL
+ help
+ This enables the PINCTRL subsystem for controlling pins
+ on chip packages, for example multiplexing pins on primarily
+ PGA and BGA packages for systems on chip.
+
+ If unsure, say N.
+
+if PINCTRL
+
+config PINMUX
+ bool "Support pinmux controllers"
+ help
+ Say Y here if you want the pincontrol subsystem to handle pin
+ multiplexing drivers.
+
+config DEBUG_PINCTRL
+ bool "Debug PINCTRL calls"
+ depends on DEBUG_KERNEL
+ help
+ Say Y here to add some extra checks and diagnostics to PINCTRL calls.
+
+config PINMUX_SIRF
+ bool "CSR SiRFprimaII pinmux driver"
+ depends on ARCH_PRIMA2
+ select PINMUX
+ help
+ Say Y here to enable the SiRFprimaII pinmux driver
+
+config PINMUX_U300
+ bool "U300 pinmux driver"
+ depends on ARCH_U300
+ select PINMUX
+ help
+ Say Y here to enable the U300 pinmux driver
+
+endif
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
new file mode 100644
index 000000000000..bdc548a6b7e9
--- /dev/null
+++ b/drivers/pinctrl/Makefile
@@ -0,0 +1,8 @@
+# generic pinmux support
+
+ccflags-$(CONFIG_DEBUG_PINMUX) += -DDEBUG
+
+obj-$(CONFIG_PINCTRL) += core.o
+obj-$(CONFIG_PINMUX) += pinmux.o
+obj-$(CONFIG_PINMUX_SIRF) += pinmux-sirf.o
+obj-$(CONFIG_PINMUX_U300) += pinmux-u300.o
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
new file mode 100644
index 000000000000..423522d87313
--- /dev/null
+++ b/drivers/pinctrl/core.c
@@ -0,0 +1,598 @@
+/*
+ * Core driver for the pin control subsystem
+ *
+ * Copyright (C) 2011 ST-Ericsson SA
+ * Written on behalf of Linaro for ST-Ericsson
+ * Based on bits of regulator core, gpio core and clk core
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#define pr_fmt(fmt) "pinctrl core: " fmt
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/radix-tree.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/sysfs.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/machine.h>
+#include "core.h"
+#include "pinmux.h"
+
+/* Global list of pin control devices */
+static DEFINE_MUTEX(pinctrldev_list_mutex);
+static LIST_HEAD(pinctrldev_list);
+
+static void pinctrl_dev_release(struct device *dev)
+{
+ struct pinctrl_dev *pctldev = dev_get_drvdata(dev);
+ kfree(pctldev);
+}
+
+const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev)
+{
+ /* We're not allowed to register devices without name */
+ return pctldev->desc->name;
+}
+EXPORT_SYMBOL_GPL(pinctrl_dev_get_name);
+
+void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev)
+{
+ return pctldev->driver_data;
+}
+EXPORT_SYMBOL_GPL(pinctrl_dev_get_drvdata);
+
+/**
+ * get_pinctrl_dev_from_dev() - look up pin controller device
+ * @dev: a device pointer, this may be NULL but then devname needs to be
+ * defined instead
+ * @devname: the name of a device instance, as returned by dev_name(), this
+ * may be NULL but then dev needs to be defined instead
+ *
+ * Looks up a pin control device matching a certain device name or pure device
+ * pointer, the pure device pointer will take precedence.
+ */
+struct pinctrl_dev *get_pinctrl_dev_from_dev(struct device *dev,
+ const char *devname)
+{
+ struct pinctrl_dev *pctldev = NULL;
+ bool found = false;
+
+ mutex_lock(&pinctrldev_list_mutex);
+ list_for_each_entry(pctldev, &pinctrldev_list, node) {
+ if (dev && &pctldev->dev == dev) {
+ /* Matched on device pointer */
+ found = true;
+ break;
+ }
+
+ if (devname &&
+ !strcmp(dev_name(&pctldev->dev), devname)) {
+ /* Matched on device name */
+ found = true;
+ break;
+ }
+ }
+ mutex_unlock(&pinctrldev_list_mutex);
+
+ return found ? pctldev : NULL;
+}
+
+struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev, int pin)
+{
+ struct pin_desc *pindesc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pctldev->pin_desc_tree_lock, flags);
+ pindesc = radix_tree_lookup(&pctldev->pin_desc_tree, pin);
+ spin_unlock_irqrestore(&pctldev->pin_desc_tree_lock, flags);
+
+ return pindesc;
+}
+
+/**
+ * pin_is_valid() - check if pin exists on controller
+ * @pctldev: the pin control device to check the pin on
+ * @pin: pin to check, use the local pin controller index number
+ *
+ * This tells us whether a certain pin exist on a certain pin controller or
+ * not. Pin lists may be sparse, so some pins may not exist.
+ */
+bool pin_is_valid(struct pinctrl_dev *pctldev, int pin)
+{
+ struct pin_desc *pindesc;
+
+ if (pin < 0)
+ return false;
+
+ pindesc = pin_desc_get(pctldev, pin);
+ if (pindesc == NULL)
+ return false;
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(pin_is_valid);
+
+/* Deletes a range of pin descriptors */
+static void pinctrl_free_pindescs(struct pinctrl_dev *pctldev,
+ const struct pinctrl_pin_desc *pins,
+ unsigned num_pins)
+{
+ int i;
+
+ spin_lock(&pctldev->pin_desc_tree_lock);
+ for (i = 0; i < num_pins; i++) {
+ struct pin_desc *pindesc;
+
+ pindesc = radix_tree_lookup(&pctldev->pin_desc_tree,
+ pins[i].number);
+ if (pindesc != NULL) {
+ radix_tree_delete(&pctldev->pin_desc_tree,
+ pins[i].number);
+ }
+ kfree(pindesc);
+ }
+ spin_unlock(&pctldev->pin_desc_tree_lock);
+}
+
+static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev,
+ unsigned number, const char *name)
+{
+ struct pin_desc *pindesc;
+
+ pindesc = pin_desc_get(pctldev, number);
+ if (pindesc != NULL) {
+ pr_err("pin %d already registered on %s\n", number,
+ pctldev->desc->name);
+ return -EINVAL;
+ }
+
+ pindesc = kzalloc(sizeof(*pindesc), GFP_KERNEL);
+ if (pindesc == NULL)
+ return -ENOMEM;
+ spin_lock_init(&pindesc->lock);
+
+ /* Set owner */
+ pindesc->pctldev = pctldev;
+
+ /* Copy basic pin info */
+ pindesc->name = name;
+
+ spin_lock(&pctldev->pin_desc_tree_lock);
+ radix_tree_insert(&pctldev->pin_desc_tree, number, pindesc);
+ spin_unlock(&pctldev->pin_desc_tree_lock);
+ pr_debug("registered pin %d (%s) on %s\n",
+ number, name ? name : "(unnamed)", pctldev->desc->name);
+ return 0;
+}
+
+static int pinctrl_register_pins(struct pinctrl_dev *pctldev,
+ struct pinctrl_pin_desc const *pins,
+ unsigned num_descs)
+{
+ unsigned i;
+ int ret = 0;
+
+ for (i = 0; i < num_descs; i++) {
+ ret = pinctrl_register_one_pin(pctldev,
+ pins[i].number, pins[i].name);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * pinctrl_match_gpio_range() - check if a certain GPIO pin is in range
+ * @pctldev: pin controller device to check
+ * @gpio: gpio pin to check taken from the global GPIO pin space
+ *
+ * Tries to match a GPIO pin number to the ranges handled by a certain pin
+ * controller, return the range or NULL
+ */
+static struct pinctrl_gpio_range *
+pinctrl_match_gpio_range(struct pinctrl_dev *pctldev, unsigned gpio)
+{
+ struct pinctrl_gpio_range *range = NULL;
+
+ /* Loop over the ranges */
+ mutex_lock(&pctldev->gpio_ranges_lock);
+ list_for_each_entry(range, &pctldev->gpio_ranges, node) {
+ /* Check if we're in the valid range */
+ if (gpio >= range->base &&
+ gpio < range->base + range->npins) {
+ mutex_unlock(&pctldev->gpio_ranges_lock);
+ return range;
+ }
+ }
+ mutex_unlock(&pctldev->gpio_ranges_lock);
+
+ return NULL;
+}
+
+/**
+ * pinctrl_get_device_gpio_range() - find device for GPIO range
+ * @gpio: the pin to locate the pin controller for
+ * @outdev: the pin control device if found
+ * @outrange: the GPIO range if found
+ *
+ * Find the pin controller handling a certain GPIO pin from the pinspace of
+ * the GPIO subsystem, return the device and the matching GPIO range. Returns
+ * negative if the GPIO range could not be found in any device.
+ */
+int pinctrl_get_device_gpio_range(unsigned gpio,
+ struct pinctrl_dev **outdev,
+ struct pinctrl_gpio_range **outrange)
+{
+ struct pinctrl_dev *pctldev = NULL;
+
+ /* Loop over the pin controllers */
+ mutex_lock(&pinctrldev_list_mutex);
+ list_for_each_entry(pctldev, &pinctrldev_list, node) {
+ struct pinctrl_gpio_range *range;
+
+ range = pinctrl_match_gpio_range(pctldev, gpio);
+ if (range != NULL) {
+ *outdev = pctldev;
+ *outrange = range;
+ mutex_unlock(&pinctrldev_list_mutex);
+ return 0;
+ }
+ }
+ mutex_unlock(&pinctrldev_list_mutex);
+
+ return -EINVAL;
+}
+
+/**
+ * pinctrl_add_gpio_range() - register a GPIO range for a controller
+ * @pctldev: pin controller device to add the range to
+ * @range: the GPIO range to add
+ *
+ * This adds a range of GPIOs to be handled by a certain pin controller. Call
+ * this to register handled ranges after registering your pin controller.
+ */
+void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range)
+{
+ mutex_lock(&pctldev->gpio_ranges_lock);
+ list_add(&range->node, &pctldev->gpio_ranges);
+ mutex_unlock(&pctldev->gpio_ranges_lock);
+}
+
+/**
+ * pinctrl_remove_gpio_range() - remove a range of GPIOs fro a pin controller
+ * @pctldev: pin controller device to remove the range from
+ * @range: the GPIO range to remove
+ */
+void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range)
+{
+ mutex_lock(&pctldev->gpio_ranges_lock);
+ list_del(&range->node);
+ mutex_unlock(&pctldev->gpio_ranges_lock);
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+static int pinctrl_pins_show(struct seq_file *s, void *what)
+{
+ struct pinctrl_dev *pctldev = s->private;
+ const struct pinctrl_ops *ops = pctldev->desc->pctlops;
+ unsigned pin;
+
+ seq_printf(s, "registered pins: %d\n", pctldev->desc->npins);
+ seq_printf(s, "max pin number: %d\n", pctldev->desc->maxpin);
+
+ /* The highest pin number need to be included in the loop, thus <= */
+ for (pin = 0; pin <= pctldev->desc->maxpin; pin++) {
+ struct pin_desc *desc;
+
+ desc = pin_desc_get(pctldev, pin);
+ /* Pin space may be sparse */
+ if (desc == NULL)
+ continue;
+
+ seq_printf(s, "pin %d (%s) ", pin,
+ desc->name ? desc->name : "unnamed");
+
+ /* Driver-specific info per pin */
+ if (ops->pin_dbg_show)
+ ops->pin_dbg_show(pctldev, s, pin);
+
+ seq_puts(s, "\n");
+ }
+
+ return 0;
+}
+
+static int pinctrl_groups_show(struct seq_file *s, void *what)
+{
+ struct pinctrl_dev *pctldev = s->private;
+ const struct pinctrl_ops *ops = pctldev->desc->pctlops;
+ unsigned selector = 0;
+
+ /* No grouping */
+ if (!ops)
+ return 0;
+
+ seq_puts(s, "registered pin groups:\n");
+ while (ops->list_groups(pctldev, selector) >= 0) {
+ const unsigned *pins;
+ unsigned num_pins;
+ const char *gname = ops->get_group_name(pctldev, selector);
+ int ret;
+ int i;
+
+ ret = ops->get_group_pins(pctldev, selector,
+ &pins, &num_pins);
+ if (ret)
+ seq_printf(s, "%s [ERROR GETTING PINS]\n",
+ gname);
+ else {
+ seq_printf(s, "group: %s, pins = [ ", gname);
+ for (i = 0; i < num_pins; i++)
+ seq_printf(s, "%d ", pins[i]);
+ seq_puts(s, "]\n");
+ }
+ selector++;
+ }
+
+
+ return 0;
+}
+
+static int pinctrl_gpioranges_show(struct seq_file *s, void *what)
+{
+ struct pinctrl_dev *pctldev = s->private;
+ struct pinctrl_gpio_range *range = NULL;
+
+ seq_puts(s, "GPIO ranges handled:\n");
+
+ /* Loop over the ranges */
+ mutex_lock(&pctldev->gpio_ranges_lock);
+ list_for_each_entry(range, &pctldev->gpio_ranges, node) {
+ seq_printf(s, "%u: %s [%u - %u]\n", range->id, range->name,
+ range->base, (range->base + range->npins - 1));
+ }
+ mutex_unlock(&pctldev->gpio_ranges_lock);
+
+ return 0;
+}
+
+static int pinctrl_devices_show(struct seq_file *s, void *what)
+{
+ struct pinctrl_dev *pctldev;
+
+ seq_puts(s, "name [pinmux]\n");
+ mutex_lock(&pinctrldev_list_mutex);
+ list_for_each_entry(pctldev, &pinctrldev_list, node) {
+ seq_printf(s, "%s ", pctldev->desc->name);
+ if (pctldev->desc->pmxops)
+ seq_puts(s, "yes");
+ else
+ seq_puts(s, "no");
+ seq_puts(s, "\n");
+ }
+ mutex_unlock(&pinctrldev_list_mutex);
+
+ return 0;
+}
+
+static int pinctrl_pins_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, pinctrl_pins_show, inode->i_private);
+}
+
+static int pinctrl_groups_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, pinctrl_groups_show, inode->i_private);
+}
+
+static int pinctrl_gpioranges_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, pinctrl_gpioranges_show, inode->i_private);
+}
+
+static int pinctrl_devices_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, pinctrl_devices_show, NULL);
+}
+
+static const struct file_operations pinctrl_pins_ops = {
+ .open = pinctrl_pins_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations pinctrl_groups_ops = {
+ .open = pinctrl_groups_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations pinctrl_gpioranges_ops = {
+ .open = pinctrl_gpioranges_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations pinctrl_devices_ops = {
+ .open = pinctrl_devices_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct dentry *debugfs_root;
+
+static void pinctrl_init_device_debugfs(struct pinctrl_dev *pctldev)
+{
+ static struct dentry *device_root;
+
+ device_root = debugfs_create_dir(dev_name(&pctldev->dev),
+ debugfs_root);
+ if (IS_ERR(device_root) || !device_root) {
+ pr_warn("failed to create debugfs directory for %s\n",
+ dev_name(&pctldev->dev));
+ return;
+ }
+ debugfs_create_file("pins", S_IFREG | S_IRUGO,
+ device_root, pctldev, &pinctrl_pins_ops);
+ debugfs_create_file("pingroups", S_IFREG | S_IRUGO,
+ device_root, pctldev, &pinctrl_groups_ops);
+ debugfs_create_file("gpio-ranges", S_IFREG | S_IRUGO,
+ device_root, pctldev, &pinctrl_gpioranges_ops);
+ pinmux_init_device_debugfs(device_root, pctldev);
+}
+
+static void pinctrl_init_debugfs(void)
+{
+ debugfs_root = debugfs_create_dir("pinctrl", NULL);
+ if (IS_ERR(debugfs_root) || !debugfs_root) {
+ pr_warn("failed to create debugfs directory\n");
+ debugfs_root = NULL;
+ return;
+ }
+
+ debugfs_create_file("pinctrl-devices", S_IFREG | S_IRUGO,
+ debugfs_root, NULL, &pinctrl_devices_ops);
+ pinmux_init_debugfs(debugfs_root);
+}
+
+#else /* CONFIG_DEBUG_FS */
+
+static void pinctrl_init_device_debugfs(struct pinctrl_dev *pctldev)
+{
+}
+
+static void pinctrl_init_debugfs(void)
+{
+}
+
+#endif
+
+/**
+ * pinctrl_register() - register a pin controller device
+ * @pctldesc: descriptor for this pin controller
+ * @dev: parent device for this pin controller
+ * @driver_data: private pin controller data for this pin controller
+ */
+struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
+ struct device *dev, void *driver_data)
+{
+ static atomic_t pinmux_no = ATOMIC_INIT(0);
+ struct pinctrl_dev *pctldev;
+ int ret;
+
+ if (pctldesc == NULL)
+ return NULL;
+ if (pctldesc->name == NULL)
+ return NULL;
+
+ /* If we're implementing pinmuxing, check the ops for sanity */
+ if (pctldesc->pmxops) {
+ ret = pinmux_check_ops(pctldesc->pmxops);
+ if (ret) {
+ pr_err("%s pinmux ops lacks necessary functions\n",
+ pctldesc->name);
+ return NULL;
+ }
+ }
+
+ pctldev = kzalloc(sizeof(struct pinctrl_dev), GFP_KERNEL);
+ if (pctldev == NULL)
+ return NULL;
+
+ /* Initialize pin control device struct */
+ pctldev->owner = pctldesc->owner;
+ pctldev->desc = pctldesc;
+ pctldev->driver_data = driver_data;
+ INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
+ spin_lock_init(&pctldev->pin_desc_tree_lock);
+ INIT_LIST_HEAD(&pctldev->gpio_ranges);
+ mutex_init(&pctldev->gpio_ranges_lock);
+
+ /* Register device */
+ pctldev->dev.parent = dev;
+ dev_set_name(&pctldev->dev, "pinctrl.%d",
+ atomic_inc_return(&pinmux_no) - 1);
+ pctldev->dev.release = pinctrl_dev_release;
+ ret = device_register(&pctldev->dev);
+ if (ret != 0) {
+ pr_err("error in device registration\n");
+ goto out_reg_dev_err;
+ }
+ dev_set_drvdata(&pctldev->dev, pctldev);
+
+ /* Register all the pins */
+ pr_debug("try to register %d pins on %s...\n",
+ pctldesc->npins, pctldesc->name);
+ ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins);
+ if (ret) {
+ pr_err("error during pin registration\n");
+ pinctrl_free_pindescs(pctldev, pctldesc->pins,
+ pctldesc->npins);
+ goto out_reg_pins_err;
+ }
+
+ pinctrl_init_device_debugfs(pctldev);
+ mutex_lock(&pinctrldev_list_mutex);
+ list_add(&pctldev->node, &pinctrldev_list);
+ mutex_unlock(&pinctrldev_list_mutex);
+ pinmux_hog_maps(pctldev);
+ return pctldev;
+
+out_reg_pins_err:
+ device_del(&pctldev->dev);
+out_reg_dev_err:
+ put_device(&pctldev->dev);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(pinctrl_register);
+
+/**
+ * pinctrl_unregister() - unregister pinmux
+ * @pctldev: pin controller to unregister
+ *
+ * Called by pinmux drivers to unregister a pinmux.
+ */
+void pinctrl_unregister(struct pinctrl_dev *pctldev)
+{
+ if (pctldev == NULL)
+ return;
+
+ pinmux_unhog_maps(pctldev);
+ /* TODO: check that no pinmuxes are still active? */
+ mutex_lock(&pinctrldev_list_mutex);
+ list_del(&pctldev->node);
+ mutex_unlock(&pinctrldev_list_mutex);
+ /* Destroy descriptor tree */
+ pinctrl_free_pindescs(pctldev, pctldev->desc->pins,
+ pctldev->desc->npins);
+ device_unregister(&pctldev->dev);
+}
+EXPORT_SYMBOL_GPL(pinctrl_unregister);
+
+static int __init pinctrl_init(void)
+{
+ pr_info("initialized pinctrl subsystem\n");
+ pinctrl_init_debugfs();
+ return 0;
+}
+
+/* init early since many drivers really need to initialized pinmux early */
+core_initcall(pinctrl_init);
diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
new file mode 100644
index 000000000000..472fa1341cc0
--- /dev/null
+++ b/drivers/pinctrl/core.h
@@ -0,0 +1,71 @@
+/*
+ * Core private header for the pin control subsystem
+ *
+ * Copyright (C) 2011 ST-Ericsson SA
+ * Written on behalf of Linaro for ST-Ericsson
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+/**
+ * struct pinctrl_dev - pin control class device
+ * @node: node to include this pin controller in the global pin controller list
+ * @desc: the pin controller descriptor supplied when initializing this pin
+ * controller
+ * @pin_desc_tree: each pin descriptor for this pin controller is stored in
+ * this radix tree
+ * @pin_desc_tree_lock: lock for the descriptor tree
+ * @gpio_ranges: a list of GPIO ranges that is handled by this pin controller,
+ * ranges are added to this list at runtime
+ * @gpio_ranges_lock: lock for the GPIO ranges list
+ * @dev: the device entry for this pin controller
+ * @owner: module providing the pin controller, used for refcounting
+ * @driver_data: driver data for drivers registering to the pin controller
+ * subsystem
+ * @pinmux_hogs_lock: lock for the pinmux hog list
+ * @pinmux_hogs: list of pinmux maps hogged by this device
+ */
+struct pinctrl_dev {
+ struct list_head node;
+ struct pinctrl_desc *desc;
+ struct radix_tree_root pin_desc_tree;
+ spinlock_t pin_desc_tree_lock;
+ struct list_head gpio_ranges;
+ struct mutex gpio_ranges_lock;
+ struct device dev;
+ struct module *owner;
+ void *driver_data;
+#ifdef CONFIG_PINMUX
+ struct mutex pinmux_hogs_lock;
+ struct list_head pinmux_hogs;
+#endif
+};
+
+/**
+ * struct pin_desc - pin descriptor for each physical pin in the arch
+ * @pctldev: corresponding pin control device
+ * @name: a name for the pin, e.g. the name of the pin/pad/finger on a
+ * datasheet or such
+ * @lock: a lock to protect the descriptor structure
+ * @mux_requested: whether the pin is already requested by pinmux or not
+ * @mux_function: a named muxing function for the pin that will be passed to
+ * subdrivers and shown in debugfs etc
+ */
+struct pin_desc {
+ struct pinctrl_dev *pctldev;
+ const char *name;
+ spinlock_t lock;
+ /* These fields only added when supporting pinmux drivers */
+#ifdef CONFIG_PINMUX
+ const char *mux_function;
+#endif
+};
+
+struct pinctrl_dev *get_pinctrl_dev_from_dev(struct device *dev,
+ const char *dev_name);
+struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev, int pin);
+int pinctrl_get_device_gpio_range(unsigned gpio,
+ struct pinctrl_dev **outdev,
+ struct pinctrl_gpio_range **outrange);
diff --git a/drivers/pinctrl/pinmux-sirf.c b/drivers/pinctrl/pinmux-sirf.c
new file mode 100644
index 000000000000..d76cae620956
--- /dev/null
+++ b/drivers/pinctrl/pinmux-sirf.c
@@ -0,0 +1,1215 @@
+/*
+ * pinmux driver for CSR SiRFprimaII
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/bitops.h>
+
+#define DRIVER_NAME "pinmux-sirf"
+
+#define SIRFSOC_NUM_PADS 622
+#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84)
+#define SIRFSOC_RSC_PIN_MUX 0x4
+
+/*
+ * pad list for the pinmux subsystem
+ * refer to CS-131858-DC-6A.xls
+ */
+static const struct pinctrl_pin_desc sirfsoc_pads[] = {
+ PINCTRL_PIN(4, "pwm0"),
+ PINCTRL_PIN(5, "pwm1"),
+ PINCTRL_PIN(6, "pwm2"),
+ PINCTRL_PIN(7, "pwm3"),
+ PINCTRL_PIN(8, "warm_rst_b"),
+ PINCTRL_PIN(9, "odo_0"),
+ PINCTRL_PIN(10, "odo_1"),
+ PINCTRL_PIN(11, "dr_dir"),
+ PINCTRL_PIN(13, "scl_1"),
+ PINCTRL_PIN(15, "sda_1"),
+ PINCTRL_PIN(16, "x_ldd[16]"),
+ PINCTRL_PIN(17, "x_ldd[17]"),
+ PINCTRL_PIN(18, "x_ldd[18]"),
+ PINCTRL_PIN(19, "x_ldd[19]"),
+ PINCTRL_PIN(20, "x_ldd[20]"),
+ PINCTRL_PIN(21, "x_ldd[21]"),
+ PINCTRL_PIN(22, "x_ldd[22]"),
+ PINCTRL_PIN(23, "x_ldd[23], lcdrom_frdy"),
+ PINCTRL_PIN(24, "gps_sgn"),
+ PINCTRL_PIN(25, "gps_mag"),
+ PINCTRL_PIN(26, "gps_clk"),
+ PINCTRL_PIN(27, "sd_cd_b_1"),
+ PINCTRL_PIN(28, "sd_vcc_on_1"),
+ PINCTRL_PIN(29, "sd_wp_b_1"),
+ PINCTRL_PIN(30, "sd_clk_3"),
+ PINCTRL_PIN(31, "sd_cmd_3"),
+
+ PINCTRL_PIN(32, "x_sd_dat_3[0]"),
+ PINCTRL_PIN(33, "x_sd_dat_3[1]"),
+ PINCTRL_PIN(34, "x_sd_dat_3[2]"),
+ PINCTRL_PIN(35, "x_sd_dat_3[3]"),
+ PINCTRL_PIN(36, "x_sd_clk_4"),
+ PINCTRL_PIN(37, "x_sd_cmd_4"),
+ PINCTRL_PIN(38, "x_sd_dat_4[0]"),
+ PINCTRL_PIN(39, "x_sd_dat_4[1]"),
+ PINCTRL_PIN(40, "x_sd_dat_4[2]"),
+ PINCTRL_PIN(41, "x_sd_dat_4[3]"),
+ PINCTRL_PIN(42, "x_cko_1"),
+ PINCTRL_PIN(43, "x_ac97_bit_clk"),
+ PINCTRL_PIN(44, "x_ac97_dout"),
+ PINCTRL_PIN(45, "x_ac97_din"),
+ PINCTRL_PIN(46, "x_ac97_sync"),
+ PINCTRL_PIN(47, "x_txd_1"),
+ PINCTRL_PIN(48, "x_txd_2"),
+ PINCTRL_PIN(49, "x_rxd_1"),
+ PINCTRL_PIN(50, "x_rxd_2"),
+ PINCTRL_PIN(51, "x_usclk_0"),
+ PINCTRL_PIN(52, "x_utxd_0"),
+ PINCTRL_PIN(53, "x_urxd_0"),
+ PINCTRL_PIN(54, "x_utfs_0"),
+ PINCTRL_PIN(55, "x_urfs_0"),
+ PINCTRL_PIN(56, "x_usclk_1"),
+ PINCTRL_PIN(57, "x_utxd_1"),
+ PINCTRL_PIN(58, "x_urxd_1"),
+ PINCTRL_PIN(59, "x_utfs_1"),
+ PINCTRL_PIN(60, "x_urfs_1"),
+ PINCTRL_PIN(61, "x_usclk_2"),
+ PINCTRL_PIN(62, "x_utxd_2"),
+ PINCTRL_PIN(63, "x_urxd_2"),
+
+ PINCTRL_PIN(64, "x_utfs_2"),
+ PINCTRL_PIN(65, "x_urfs_2"),
+ PINCTRL_PIN(66, "x_df_we_b"),
+ PINCTRL_PIN(67, "x_df_re_b"),
+ PINCTRL_PIN(68, "x_txd_0"),
+ PINCTRL_PIN(69, "x_rxd_0"),
+ PINCTRL_PIN(78, "x_cko_0"),
+ PINCTRL_PIN(79, "x_vip_pxd[7]"),
+ PINCTRL_PIN(80, "x_vip_pxd[6]"),
+ PINCTRL_PIN(81, "x_vip_pxd[5]"),
+ PINCTRL_PIN(82, "x_vip_pxd[4]"),
+ PINCTRL_PIN(83, "x_vip_pxd[3]"),
+ PINCTRL_PIN(84, "x_vip_pxd[2]"),
+ PINCTRL_PIN(85, "x_vip_pxd[1]"),
+ PINCTRL_PIN(86, "x_vip_pxd[0]"),
+ PINCTRL_PIN(87, "x_vip_vsync"),
+ PINCTRL_PIN(88, "x_vip_hsync"),
+ PINCTRL_PIN(89, "x_vip_pxclk"),
+ PINCTRL_PIN(90, "x_sda_0"),
+ PINCTRL_PIN(91, "x_scl_0"),
+ PINCTRL_PIN(92, "x_df_ry_by"),
+ PINCTRL_PIN(93, "x_df_cs_b[1]"),
+ PINCTRL_PIN(94, "x_df_cs_b[0]"),
+ PINCTRL_PIN(95, "x_l_pclk"),
+
+ PINCTRL_PIN(96, "x_l_lck"),
+ PINCTRL_PIN(97, "x_l_fck"),
+ PINCTRL_PIN(98, "x_l_de"),
+ PINCTRL_PIN(99, "x_ldd[0]"),
+ PINCTRL_PIN(100, "x_ldd[1]"),
+ PINCTRL_PIN(101, "x_ldd[2]"),
+ PINCTRL_PIN(102, "x_ldd[3]"),
+ PINCTRL_PIN(103, "x_ldd[4]"),
+ PINCTRL_PIN(104, "x_ldd[5]"),
+ PINCTRL_PIN(105, "x_ldd[6]"),
+ PINCTRL_PIN(106, "x_ldd[7]"),
+ PINCTRL_PIN(107, "x_ldd[8]"),
+ PINCTRL_PIN(108, "x_ldd[9]"),
+ PINCTRL_PIN(109, "x_ldd[10]"),
+ PINCTRL_PIN(110, "x_ldd[11]"),
+ PINCTRL_PIN(111, "x_ldd[12]"),
+ PINCTRL_PIN(112, "x_ldd[13]"),
+ PINCTRL_PIN(113, "x_ldd[14]"),
+ PINCTRL_PIN(114, "x_ldd[15]"),
+};
+
+/**
+ * @dev: a pointer back to containing device
+ * @virtbase: the offset to the controller in virtual memory
+ */
+struct sirfsoc_pmx {
+ struct device *dev;
+ struct pinctrl_dev *pmx;
+ void __iomem *gpio_virtbase;
+ void __iomem *rsc_virtbase;
+};
+
+/* SIRFSOC_GPIO_PAD_EN set */
+struct sirfsoc_muxmask {
+ unsigned long group;
+ unsigned long mask;
+};
+
+struct sirfsoc_padmux {
+ unsigned long muxmask_counts;
+ const struct sirfsoc_muxmask *muxmask;
+ /* RSC_PIN_MUX set */
+ unsigned long funcmask;
+ unsigned long funcval;
+};
+
+ /**
+ * struct sirfsoc_pin_group - describes a SiRFprimaII pin group
+ * @name: the name of this specific pin group
+ * @pins: an array of discrete physical pins used in this group, taken
+ * from the driver-local pin enumeration space
+ * @num_pins: the number of pins in this group array, i.e. the number of
+ * elements in .pins so we can iterate over that array
+ */
+struct sirfsoc_pin_group {
+ const char *name;
+ const unsigned int *pins;
+ const unsigned num_pins;
+};
+
+static const struct sirfsoc_muxmask lcd_16bits_sirfsoc_muxmask[] = {
+ {
+ .group = 3,
+ .mask = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(8) |
+ BIT(9) | BIT(10) | BIT(11) | BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) |
+ BIT(17) | BIT(18),
+ }, {
+ .group = 2,
+ .mask = BIT(31),
+ },
+};
+
+static const struct sirfsoc_padmux lcd_16bits_padmux = {
+ .muxmask_counts = ARRAY_SIZE(lcd_16bits_sirfsoc_muxmask),
+ .muxmask = lcd_16bits_sirfsoc_muxmask,
+ .funcmask = BIT(4),
+ .funcval = 0,
+};
+
+static const unsigned lcd_16bits_pins[] = { 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114 };
+
+static const struct sirfsoc_muxmask lcd_18bits_muxmask[] = {
+ {
+ .group = 3,
+ .mask = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(8) |
+ BIT(9) | BIT(10) | BIT(11) | BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) |
+ BIT(17) | BIT(18),
+ }, {
+ .group = 2,
+ .mask = BIT(31),
+ }, {
+ .group = 0,
+ .mask = BIT(16) | BIT(17),
+ },
+};
+
+static const struct sirfsoc_padmux lcd_18bits_padmux = {
+ .muxmask_counts = ARRAY_SIZE(lcd_18bits_muxmask),
+ .muxmask = lcd_18bits_muxmask,
+ .funcmask = BIT(4),
+ .funcval = 0,
+};
+
+static const unsigned lcd_18bits_pins[] = { 16, 17, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114};
+
+static const struct sirfsoc_muxmask lcd_24bits_muxmask[] = {
+ {
+ .group = 3,
+ .mask = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(8) |
+ BIT(9) | BIT(10) | BIT(11) | BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) |
+ BIT(17) | BIT(18),
+ }, {
+ .group = 2,
+ .mask = BIT(31),
+ }, {
+ .group = 0,
+ .mask = BIT(16) | BIT(17) | BIT(18) | BIT(19) | BIT(20) | BIT(21) | BIT(22) | BIT(23),
+ },
+};
+
+static const struct sirfsoc_padmux lcd_24bits_padmux = {
+ .muxmask_counts = ARRAY_SIZE(lcd_24bits_muxmask),
+ .muxmask = lcd_24bits_muxmask,
+ .funcmask = BIT(4),
+ .funcval = 0,
+};
+
+static const unsigned lcd_24bits_pins[] = { 16, 17, 18, 19, 20, 21, 22, 23, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114 };
+
+static const struct sirfsoc_muxmask lcdrom_muxmask[] = {
+ {
+ .group = 3,
+ .mask = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(8) |
+ BIT(9) | BIT(10) | BIT(11) | BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) |
+ BIT(17) | BIT(18),
+ }, {
+ .group = 2,
+ .mask = BIT(31),
+ }, {
+ .group = 0,
+ .mask = BIT(23),
+ },
+};
+
+static const struct sirfsoc_padmux lcdrom_padmux = {
+ .muxmask_counts = ARRAY_SIZE(lcdrom_muxmask),
+ .muxmask = lcdrom_muxmask,
+ .funcmask = BIT(4),
+ .funcval = BIT(4),
+};
+
+static const unsigned lcdrom_pins[] = { 23, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114 };
+
+static const struct sirfsoc_muxmask uart0_muxmask[] = {
+ {
+ .group = 2,
+ .mask = BIT(4) | BIT(5),
+ }, {
+ .group = 1,
+ .mask = BIT(23) | BIT(28),
+ },
+};
+
+static const struct sirfsoc_padmux uart0_padmux = {
+ .muxmask_counts = ARRAY_SIZE(uart0_muxmask),
+ .muxmask = uart0_muxmask,
+ .funcmask = BIT(9),
+ .funcval = BIT(9),
+};
+
+static const unsigned uart0_pins[] = { 55, 60, 68, 69 };
+
+static const struct sirfsoc_muxmask uart0_nostreamctrl_muxmask[] = {
+ {
+ .group = 2,
+ .mask = BIT(4) | BIT(5),
+ },
+};
+
+static const struct sirfsoc_padmux uart0_nostreamctrl_padmux = {
+ .muxmask_counts = ARRAY_SIZE(uart0_nostreamctrl_muxmask),
+ .muxmask = uart0_nostreamctrl_muxmask,
+};
+
+static const unsigned uart0_nostreamctrl_pins[] = { 68, 39 };
+
+static const struct sirfsoc_muxmask uart1_muxmask[] = {
+ {
+ .group = 1,
+ .mask = BIT(15) | BIT(17),
+ },
+};
+
+static const struct sirfsoc_padmux uart1_padmux = {
+ .muxmask_counts = ARRAY_SIZE(uart1_muxmask),
+ .muxmask = uart1_muxmask,
+};
+
+static const unsigned uart1_pins[] = { 47, 49 };
+
+static const struct sirfsoc_muxmask uart2_muxmask[] = {
+ {
+ .group = 1,
+ .mask = BIT(16) | BIT(18) | BIT(24) | BIT(27),
+ },
+};
+
+static const struct sirfsoc_padmux uart2_padmux = {
+ .muxmask_counts = ARRAY_SIZE(uart2_muxmask),
+ .muxmask = uart2_muxmask,
+ .funcmask = BIT(10),
+ .funcval = BIT(10),
+};
+
+static const unsigned uart2_pins[] = { 48, 50, 56, 59 };
+
+static const struct sirfsoc_muxmask uart2_nostreamctrl_muxmask[] = {
+ {
+ .group = 1,
+ .mask = BIT(16) | BIT(18),
+ },
+};
+
+static const struct sirfsoc_padmux uart2_nostreamctrl_padmux = {
+ .muxmask_counts = ARRAY_SIZE(uart2_nostreamctrl_muxmask),
+ .muxmask = uart2_nostreamctrl_muxmask,
+};
+
+static const unsigned uart2_nostreamctrl_pins[] = { 48, 50 };
+
+static const struct sirfsoc_muxmask sdmmc3_muxmask[] = {
+ {
+ .group = 0,
+ .mask = BIT(30) | BIT(31),
+ }, {
+ .group = 1,
+ .mask = BIT(0) | BIT(1) | BIT(2) | BIT(3),
+ },
+};
+
+static const struct sirfsoc_padmux sdmmc3_padmux = {
+ .muxmask_counts = ARRAY_SIZE(sdmmc3_muxmask),
+ .muxmask = sdmmc3_muxmask,
+ .funcmask = BIT(7),
+ .funcval = 0,
+};
+
+static const unsigned sdmmc3_pins[] = { 30, 31, 32, 33, 34, 35 };
+
+static const struct sirfsoc_muxmask spi0_muxmask[] = {
+ {
+ .group = 1,
+ .mask = BIT(0) | BIT(1) | BIT(2) | BIT(3),
+ },
+};
+
+static const struct sirfsoc_padmux spi0_padmux = {
+ .muxmask_counts = ARRAY_SIZE(spi0_muxmask),
+ .muxmask = spi0_muxmask,
+ .funcmask = BIT(7),
+ .funcval = BIT(7),
+};
+
+static const unsigned spi0_pins[] = { 32, 33, 34, 35 };
+
+static const struct sirfsoc_muxmask sdmmc4_muxmask[] = {
+ {
+ .group = 1,
+ .mask = BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(8) | BIT(9),
+ },
+};
+
+static const struct sirfsoc_padmux sdmmc4_padmux = {
+ .muxmask_counts = ARRAY_SIZE(sdmmc4_muxmask),
+ .muxmask = sdmmc4_muxmask,
+};
+
+static const unsigned sdmmc4_pins[] = { 36, 37, 38, 39, 40, 41 };
+
+static const struct sirfsoc_muxmask cko1_muxmask[] = {
+ {
+ .group = 1,
+ .mask = BIT(10),
+ },
+};
+
+static const struct sirfsoc_padmux cko1_padmux = {
+ .muxmask_counts = ARRAY_SIZE(cko1_muxmask),
+ .muxmask = cko1_muxmask,
+ .funcmask = BIT(3),
+ .funcval = 0,
+};
+
+static const unsigned cko1_pins[] = { 42 };
+
+static const struct sirfsoc_muxmask i2s_muxmask[] = {
+ {
+ .group = 1,
+ .mask =
+ BIT(10) | BIT(11) | BIT(12) | BIT(13) | BIT(14) | BIT(19)
+ | BIT(23) | BIT(28),
+ },
+};
+
+static const struct sirfsoc_padmux i2s_padmux = {
+ .muxmask_counts = ARRAY_SIZE(i2s_muxmask),
+ .muxmask = i2s_muxmask,
+ .funcmask = BIT(3) | BIT(9),
+ .funcval = BIT(3),
+};
+
+static const unsigned i2s_pins[] = { 42, 43, 44, 45, 46, 51, 55, 60 };
+
+static const struct sirfsoc_muxmask ac97_muxmask[] = {
+ {
+ .group = 1,
+ .mask = BIT(11) | BIT(12) | BIT(13) | BIT(14),
+ },
+};
+
+static const struct sirfsoc_padmux ac97_padmux = {
+ .muxmask_counts = ARRAY_SIZE(ac97_muxmask),
+ .muxmask = ac97_muxmask,
+ .funcmask = BIT(8),
+ .funcval = 0,
+};
+
+static const unsigned ac97_pins[] = { 33, 34, 35, 36 };
+
+static const struct sirfsoc_muxmask spi1_muxmask[] = {
+ {
+ .group = 1,
+ .mask = BIT(11) | BIT(12) | BIT(13) | BIT(14),
+ },
+};
+
+static const struct sirfsoc_padmux spi1_padmux = {
+ .muxmask_counts = ARRAY_SIZE(spi1_muxmask),
+ .muxmask = spi1_muxmask,
+ .funcmask = BIT(8),
+ .funcval = BIT(8),
+};
+
+static const unsigned spi1_pins[] = { 33, 34, 35, 36 };
+
+static const struct sirfsoc_muxmask sdmmc1_muxmask[] = {
+ {
+ .group = 0,
+ .mask = BIT(27) | BIT(28) | BIT(29),
+ },
+};
+
+static const struct sirfsoc_padmux sdmmc1_padmux = {
+ .muxmask_counts = ARRAY_SIZE(sdmmc1_muxmask),
+ .muxmask = sdmmc1_muxmask,
+};
+
+static const unsigned sdmmc1_pins[] = { 27, 28, 29 };
+
+static const struct sirfsoc_muxmask gps_muxmask[] = {
+ {
+ .group = 0,
+ .mask = BIT(24) | BIT(25) | BIT(26),
+ },
+};
+
+static const struct sirfsoc_padmux gps_padmux = {
+ .muxmask_counts = ARRAY_SIZE(gps_muxmask),
+ .muxmask = gps_muxmask,
+ .funcmask = BIT(12) | BIT(13) | BIT(14),
+ .funcval = BIT(12),
+};
+
+static const unsigned gps_pins[] = { 24, 25, 26 };
+
+static const struct sirfsoc_muxmask sdmmc5_muxmask[] = {
+ {
+ .group = 0,
+ .mask = BIT(24) | BIT(25) | BIT(26),
+ }, {
+ .group = 1,
+ .mask = BIT(29),
+ }, {
+ .group = 2,
+ .mask = BIT(0) | BIT(1),
+ },
+};
+
+static const struct sirfsoc_padmux sdmmc5_padmux = {
+ .muxmask_counts = ARRAY_SIZE(sdmmc5_muxmask),
+ .muxmask = sdmmc5_muxmask,
+ .funcmask = BIT(13) | BIT(14),
+ .funcval = BIT(13) | BIT(14),
+};
+
+static const unsigned sdmmc5_pins[] = { 24, 25, 26, 61, 64, 65 };
+
+static const struct sirfsoc_muxmask usp0_muxmask[] = {
+ {
+ .group = 1,
+ .mask = BIT(19) | BIT(20) | BIT(21) | BIT(22) | BIT(23),
+ },
+};
+
+static const struct sirfsoc_padmux usp0_padmux = {
+ .muxmask_counts = ARRAY_SIZE(usp0_muxmask),
+ .muxmask = usp0_muxmask,
+ .funcmask = BIT(1) | BIT(2) | BIT(6) | BIT(9),
+ .funcval = 0,
+};
+
+static const unsigned usp0_pins[] = { 51, 52, 53, 54, 55 };
+
+static const struct sirfsoc_muxmask usp1_muxmask[] = {
+ {
+ .group = 1,
+ .mask = BIT(24) | BIT(25) | BIT(26) | BIT(27) | BIT(28),
+ },
+};
+
+static const struct sirfsoc_padmux usp1_padmux = {
+ .muxmask_counts = ARRAY_SIZE(usp1_muxmask),
+ .muxmask = usp1_muxmask,
+ .funcmask = BIT(1) | BIT(9) | BIT(10) | BIT(11),
+ .funcval = 0,
+};
+
+static const unsigned usp1_pins[] = { 56, 57, 58, 59, 60 };
+
+static const struct sirfsoc_muxmask usp2_muxmask[] = {
+ {
+ .group = 1,
+ .mask = BIT(29) | BIT(30) | BIT(31),
+ }, {
+ .group = 2,
+ .mask = BIT(0) | BIT(1),
+ },
+};
+
+static const struct sirfsoc_padmux usp2_padmux = {
+ .muxmask_counts = ARRAY_SIZE(usp2_muxmask),
+ .muxmask = usp2_muxmask,
+ .funcmask = BIT(13) | BIT(14),
+ .funcval = 0,
+};
+
+static const unsigned usp2_pins[] = { 61, 62, 63, 64, 65 };
+
+static const struct sirfsoc_muxmask nand_muxmask[] = {
+ {
+ .group = 2,
+ .mask = BIT(2) | BIT(3) | BIT(28) | BIT(29) | BIT(30),
+ },
+};
+
+static const struct sirfsoc_padmux nand_padmux = {
+ .muxmask_counts = ARRAY_SIZE(nand_muxmask),
+ .muxmask = nand_muxmask,
+ .funcmask = BIT(5),
+ .funcval = 0,
+};
+
+static const unsigned nand_pins[] = { 64, 65, 92, 93, 94 };
+
+static const struct sirfsoc_padmux sdmmc0_padmux = {
+ .muxmask_counts = 0,
+ .funcmask = BIT(5),
+ .funcval = 0,
+};
+
+static const unsigned sdmmc0_pins[] = { };
+
+static const struct sirfsoc_muxmask sdmmc2_muxmask[] = {
+ {
+ .group = 2,
+ .mask = BIT(2) | BIT(3),
+ },
+};
+
+static const struct sirfsoc_padmux sdmmc2_padmux = {
+ .muxmask_counts = ARRAY_SIZE(sdmmc2_muxmask),
+ .muxmask = sdmmc2_muxmask,
+ .funcmask = BIT(5),
+ .funcval = BIT(5),
+};
+
+static const unsigned sdmmc2_pins[] = { 66, 67 };
+
+static const struct sirfsoc_muxmask cko0_muxmask[] = {
+ {
+ .group = 2,
+ .mask = BIT(14),
+ },
+};
+
+static const struct sirfsoc_padmux cko0_padmux = {
+ .muxmask_counts = ARRAY_SIZE(cko0_muxmask),
+ .muxmask = cko0_muxmask,
+};
+
+static const unsigned cko0_pins[] = { 78 };
+
+static const struct sirfsoc_muxmask vip_muxmask[] = {
+ {
+ .group = 2,
+ .mask = BIT(15) | BIT(16) | BIT(17) | BIT(18) | BIT(19)
+ | BIT(20) | BIT(21) | BIT(22) | BIT(23) | BIT(24) |
+ BIT(25),
+ },
+};
+
+static const struct sirfsoc_padmux vip_padmux = {
+ .muxmask_counts = ARRAY_SIZE(vip_muxmask),
+ .muxmask = vip_muxmask,
+ .funcmask = BIT(0),
+ .funcval = 0,
+};
+
+static const unsigned vip_pins[] = { 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89 };
+
+static const struct sirfsoc_muxmask i2c0_muxmask[] = {
+ {
+ .group = 2,
+ .mask = BIT(26) | BIT(27),
+ },
+};
+
+static const struct sirfsoc_padmux i2c0_padmux = {
+ .muxmask_counts = ARRAY_SIZE(i2c0_muxmask),
+ .muxmask = i2c0_muxmask,
+};
+
+static const unsigned i2c0_pins[] = { 90, 91 };
+
+static const struct sirfsoc_muxmask i2c1_muxmask[] = {
+ {
+ .group = 0,
+ .mask = BIT(13) | BIT(15),
+ },
+};
+
+static const struct sirfsoc_padmux i2c1_padmux = {
+ .muxmask_counts = ARRAY_SIZE(i2c1_muxmask),
+ .muxmask = i2c1_muxmask,
+};
+
+static const unsigned i2c1_pins[] = { 13, 15 };
+
+static const struct sirfsoc_muxmask viprom_muxmask[] = {
+ {
+ .group = 2,
+ .mask = BIT(15) | BIT(16) | BIT(17) | BIT(18) | BIT(19)
+ | BIT(20) | BIT(21) | BIT(22) | BIT(23) | BIT(24) |
+ BIT(25),
+ }, {
+ .group = 0,
+ .mask = BIT(12),
+ },
+};
+
+static const struct sirfsoc_padmux viprom_padmux = {
+ .muxmask_counts = ARRAY_SIZE(viprom_muxmask),
+ .muxmask = viprom_muxmask,
+ .funcmask = BIT(0),
+ .funcval = BIT(0),
+};
+
+static const unsigned viprom_pins[] = { 12, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89 };
+
+static const struct sirfsoc_muxmask pwm0_muxmask[] = {
+ {
+ .group = 0,
+ .mask = BIT(4),
+ },
+};
+
+static const struct sirfsoc_padmux pwm0_padmux = {
+ .muxmask_counts = ARRAY_SIZE(pwm0_muxmask),
+ .muxmask = pwm0_muxmask,
+ .funcmask = BIT(12),
+ .funcval = 0,
+};
+
+static const unsigned pwm0_pins[] = { 4 };
+
+static const struct sirfsoc_muxmask pwm1_muxmask[] = {
+ {
+ .group = 0,
+ .mask = BIT(5),
+ },
+};
+
+static const struct sirfsoc_padmux pwm1_padmux = {
+ .muxmask_counts = ARRAY_SIZE(pwm1_muxmask),
+ .muxmask = pwm1_muxmask,
+};
+
+static const unsigned pwm1_pins[] = { 5 };
+
+static const struct sirfsoc_muxmask pwm2_muxmask[] = {
+ {
+ .group = 0,
+ .mask = BIT(6),
+ },
+};
+
+static const struct sirfsoc_padmux pwm2_padmux = {
+ .muxmask_counts = ARRAY_SIZE(pwm2_muxmask),
+ .muxmask = pwm2_muxmask,
+};
+
+static const unsigned pwm2_pins[] = { 6 };
+
+static const struct sirfsoc_muxmask pwm3_muxmask[] = {
+ {
+ .group = 0,
+ .mask = BIT(7),
+ },
+};
+
+static const struct sirfsoc_padmux pwm3_padmux = {
+ .muxmask_counts = ARRAY_SIZE(pwm3_muxmask),
+ .muxmask = pwm3_muxmask,
+};
+
+static const unsigned pwm3_pins[] = { 7 };
+
+static const struct sirfsoc_muxmask warm_rst_muxmask[] = {
+ {
+ .group = 0,
+ .mask = BIT(8),
+ },
+};
+
+static const struct sirfsoc_padmux warm_rst_padmux = {
+ .muxmask_counts = ARRAY_SIZE(warm_rst_muxmask),
+ .muxmask = warm_rst_muxmask,
+};
+
+static const unsigned warm_rst_pins[] = { 8 };
+
+static const struct sirfsoc_muxmask usb0_utmi_drvbus_muxmask[] = {
+ {
+ .group = 1,
+ .mask = BIT(22),
+ },
+};
+static const struct sirfsoc_padmux usb0_utmi_drvbus_padmux = {
+ .muxmask_counts = ARRAY_SIZE(usb0_utmi_drvbus_muxmask),
+ .muxmask = usb0_utmi_drvbus_muxmask,
+ .funcmask = BIT(6),
+ .funcval = BIT(6), /* refer to PAD_UTMI_DRVVBUS0_ENABLE */
+};
+
+static const unsigned usb0_utmi_drvbus_pins[] = { 54 };
+
+static const struct sirfsoc_muxmask usb1_utmi_drvbus_muxmask[] = {
+ {
+ .group = 1,
+ .mask = BIT(27),
+ },
+};
+
+static const struct sirfsoc_padmux usb1_utmi_drvbus_padmux = {
+ .muxmask_counts = ARRAY_SIZE(usb1_utmi_drvbus_muxmask),
+ .muxmask = usb1_utmi_drvbus_muxmask,
+ .funcmask = BIT(11),
+ .funcval = BIT(11), /* refer to PAD_UTMI_DRVVBUS1_ENABLE */
+};
+
+static const unsigned usb1_utmi_drvbus_pins[] = { 59 };
+
+static const struct sirfsoc_muxmask pulse_count_muxmask[] = {
+ {
+ .group = 0,
+ .mask = BIT(9) | BIT(10) | BIT(11),
+ },
+};
+
+static const struct sirfsoc_padmux pulse_count_padmux = {
+ .muxmask_counts = ARRAY_SIZE(pulse_count_muxmask),
+ .muxmask = pulse_count_muxmask,
+};
+
+static const unsigned pulse_count_pins[] = { 9, 10, 11 };
+
+#define SIRFSOC_PIN_GROUP(n, p) \
+ { \
+ .name = n, \
+ .pins = p, \
+ .num_pins = ARRAY_SIZE(p), \
+ }
+
+static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = {
+ SIRFSOC_PIN_GROUP("lcd_16bitsgrp", lcd_16bits_pins),
+ SIRFSOC_PIN_GROUP("lcd_18bitsgrp", lcd_18bits_pins),
+ SIRFSOC_PIN_GROUP("lcd_24bitsgrp", lcd_24bits_pins),
+ SIRFSOC_PIN_GROUP("lcdrom_grp", lcdrom_pins),
+ SIRFSOC_PIN_GROUP("uart0grp", uart0_pins),
+ SIRFSOC_PIN_GROUP("uart1grp", uart1_pins),
+ SIRFSOC_PIN_GROUP("uart2grp", uart2_pins),
+ SIRFSOC_PIN_GROUP("uart2_nostreamctrlgrp", uart2_nostreamctrl_pins),
+ SIRFSOC_PIN_GROUP("usp0grp", usp0_pins),
+ SIRFSOC_PIN_GROUP("usp1grp", usp1_pins),
+ SIRFSOC_PIN_GROUP("usp2grp", usp2_pins),
+ SIRFSOC_PIN_GROUP("i2c0grp", i2c0_pins),
+ SIRFSOC_PIN_GROUP("i2c1grp", i2c1_pins),
+ SIRFSOC_PIN_GROUP("pwm0grp", pwm0_pins),
+ SIRFSOC_PIN_GROUP("pwm1grp", pwm1_pins),
+ SIRFSOC_PIN_GROUP("pwm2grp", pwm2_pins),
+ SIRFSOC_PIN_GROUP("pwm3grp", pwm3_pins),
+ SIRFSOC_PIN_GROUP("vipgrp", vip_pins),
+ SIRFSOC_PIN_GROUP("vipromgrp", viprom_pins),
+ SIRFSOC_PIN_GROUP("warm_rstgrp", warm_rst_pins),
+ SIRFSOC_PIN_GROUP("cko0_rstgrp", cko0_pins),
+ SIRFSOC_PIN_GROUP("cko1_rstgrp", cko1_pins),
+ SIRFSOC_PIN_GROUP("sdmmc0grp", sdmmc0_pins),
+ SIRFSOC_PIN_GROUP("sdmmc1grp", sdmmc1_pins),
+ SIRFSOC_PIN_GROUP("sdmmc2grp", sdmmc2_pins),
+ SIRFSOC_PIN_GROUP("sdmmc3grp", sdmmc3_pins),
+ SIRFSOC_PIN_GROUP("sdmmc4grp", sdmmc4_pins),
+ SIRFSOC_PIN_GROUP("sdmmc5grp", sdmmc5_pins),
+ SIRFSOC_PIN_GROUP("usb0_utmi_drvbusgrp", usb0_utmi_drvbus_pins),
+ SIRFSOC_PIN_GROUP("usb1_utmi_drvbusgrp", usb1_utmi_drvbus_pins),
+ SIRFSOC_PIN_GROUP("pulse_countgrp", pulse_count_pins),
+ SIRFSOC_PIN_GROUP("i2sgrp", i2s_pins),
+ SIRFSOC_PIN_GROUP("ac97grp", ac97_pins),
+ SIRFSOC_PIN_GROUP("nandgrp", nand_pins),
+ SIRFSOC_PIN_GROUP("spi0grp", spi0_pins),
+ SIRFSOC_PIN_GROUP("spi1grp", spi1_pins),
+ SIRFSOC_PIN_GROUP("gpsgrp", gps_pins),
+};
+
+static int sirfsoc_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
+{
+ if (selector >= ARRAY_SIZE(sirfsoc_pin_groups))
+ return -EINVAL;
+ return 0;
+}
+
+static const char *sirfsoc_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ if (selector >= ARRAY_SIZE(sirfsoc_pin_groups))
+ return NULL;
+ return sirfsoc_pin_groups[selector].name;
+}
+
+static int sirfsoc_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+ const unsigned **pins,
+ unsigned *num_pins)
+{
+ if (selector >= ARRAY_SIZE(sirfsoc_pin_groups))
+ return -EINVAL;
+ *pins = sirfsoc_pin_groups[selector].pins;
+ *num_pins = sirfsoc_pin_groups[selector].num_pins;
+ return 0;
+}
+
+static void sirfsoc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+ unsigned offset)
+{
+ seq_printf(s, " " DRIVER_NAME);
+}
+
+static struct pinctrl_ops sirfsoc_pctrl_ops = {
+ .list_groups = sirfsoc_list_groups,
+ .get_group_name = sirfsoc_get_group_name,
+ .get_group_pins = sirfsoc_get_group_pins,
+ .pin_dbg_show = sirfsoc_pin_dbg_show,
+};
+
+struct sirfsoc_pmx_func {
+ const char *name;
+ const char * const *groups;
+ const unsigned num_groups;
+ const struct sirfsoc_padmux *padmux;
+};
+
+static const char * const lcd_16bitsgrp[] = { "lcd_16bitsgrp" };
+static const char * const lcd_18bitsgrp[] = { "lcd_18bitsgrp" };
+static const char * const lcd_24bitsgrp[] = { "lcd_24bitsgrp" };
+static const char * const lcdromgrp[] = { "lcdromgrp" };
+static const char * const uart0grp[] = { "uart0grp" };
+static const char * const uart1grp[] = { "uart1grp" };
+static const char * const uart2grp[] = { "uart2grp" };
+static const char * const uart2_nostreamctrlgrp[] = { "uart2_nostreamctrlgrp" };
+static const char * const usp0grp[] = { "usp0grp" };
+static const char * const usp1grp[] = { "usp1grp" };
+static const char * const usp2grp[] = { "usp2grp" };
+static const char * const i2c0grp[] = { "i2c0grp" };
+static const char * const i2c1grp[] = { "i2c1grp" };
+static const char * const pwm0grp[] = { "pwm0grp" };
+static const char * const pwm1grp[] = { "pwm1grp" };
+static const char * const pwm2grp[] = { "pwm2grp" };
+static const char * const pwm3grp[] = { "pwm3grp" };
+static const char * const vipgrp[] = { "vipgrp" };
+static const char * const vipromgrp[] = { "vipromgrp" };
+static const char * const warm_rstgrp[] = { "warm_rstgrp" };
+static const char * const cko0grp[] = { "cko0grp" };
+static const char * const cko1grp[] = { "cko1grp" };
+static const char * const sdmmc0grp[] = { "sdmmc0grp" };
+static const char * const sdmmc1grp[] = { "sdmmc1grp" };
+static const char * const sdmmc2grp[] = { "sdmmc2grp" };
+static const char * const sdmmc3grp[] = { "sdmmc3grp" };
+static const char * const sdmmc4grp[] = { "sdmmc4grp" };
+static const char * const sdmmc5grp[] = { "sdmmc5grp" };
+static const char * const usb0_utmi_drvbusgrp[] = { "usb0_utmi_drvbusgrp" };
+static const char * const usb1_utmi_drvbusgrp[] = { "usb1_utmi_drvbusgrp" };
+static const char * const pulse_countgrp[] = { "pulse_countgrp" };
+static const char * const i2sgrp[] = { "i2sgrp" };
+static const char * const ac97grp[] = { "ac97grp" };
+static const char * const nandgrp[] = { "nandgrp" };
+static const char * const spi0grp[] = { "spi0grp" };
+static const char * const spi1grp[] = { "spi1grp" };
+static const char * const gpsgrp[] = { "gpsgrp" };
+
+#define SIRFSOC_PMX_FUNCTION(n, g, m) \
+ { \
+ .name = n, \
+ .groups = g, \
+ .num_groups = ARRAY_SIZE(g), \
+ .padmux = &m, \
+ }
+
+static const struct sirfsoc_pmx_func sirfsoc_pmx_functions[] = {
+ SIRFSOC_PMX_FUNCTION("lcd_16bits", lcd_16bitsgrp, lcd_16bits_padmux),
+ SIRFSOC_PMX_FUNCTION("lcd_18bits", lcd_18bitsgrp, lcd_18bits_padmux),
+ SIRFSOC_PMX_FUNCTION("lcd_24bits", lcd_24bitsgrp, lcd_24bits_padmux),
+ SIRFSOC_PMX_FUNCTION("lcdrom", lcdromgrp, lcdrom_padmux),
+ SIRFSOC_PMX_FUNCTION("uart0", uart0grp, uart0_padmux),
+ SIRFSOC_PMX_FUNCTION("uart1", uart1grp, uart1_padmux),
+ SIRFSOC_PMX_FUNCTION("uart2", uart2grp, uart2_padmux),
+ SIRFSOC_PMX_FUNCTION("uart2_nostreamctrl", uart2_nostreamctrlgrp, uart2_nostreamctrl_padmux),
+ SIRFSOC_PMX_FUNCTION("usp0", usp0grp, usp0_padmux),
+ SIRFSOC_PMX_FUNCTION("usp1", usp1grp, usp1_padmux),
+ SIRFSOC_PMX_FUNCTION("usp2", usp2grp, usp2_padmux),
+ SIRFSOC_PMX_FUNCTION("i2c0", i2c0grp, i2c0_padmux),
+ SIRFSOC_PMX_FUNCTION("i2c1", i2c1grp, i2c1_padmux),
+ SIRFSOC_PMX_FUNCTION("pwm0", pwm0grp, pwm0_padmux),
+ SIRFSOC_PMX_FUNCTION("pwm1", pwm1grp, pwm1_padmux),
+ SIRFSOC_PMX_FUNCTION("pwm2", pwm2grp, pwm2_padmux),
+ SIRFSOC_PMX_FUNCTION("pwm3", pwm3grp, pwm3_padmux),
+ SIRFSOC_PMX_FUNCTION("vip", vipgrp, vip_padmux),
+ SIRFSOC_PMX_FUNCTION("viprom", vipromgrp, viprom_padmux),
+ SIRFSOC_PMX_FUNCTION("warm_rst", warm_rstgrp, warm_rst_padmux),
+ SIRFSOC_PMX_FUNCTION("cko0", cko0grp, cko0_padmux),
+ SIRFSOC_PMX_FUNCTION("cko1", cko1grp, cko1_padmux),
+ SIRFSOC_PMX_FUNCTION("sdmmc0", sdmmc0grp, sdmmc0_padmux),
+ SIRFSOC_PMX_FUNCTION("sdmmc1", sdmmc1grp, sdmmc1_padmux),
+ SIRFSOC_PMX_FUNCTION("sdmmc2", sdmmc2grp, sdmmc2_padmux),
+ SIRFSOC_PMX_FUNCTION("sdmmc3", sdmmc3grp, sdmmc3_padmux),
+ SIRFSOC_PMX_FUNCTION("sdmmc4", sdmmc4grp, sdmmc4_padmux),
+ SIRFSOC_PMX_FUNCTION("sdmmc5", sdmmc5grp, sdmmc5_padmux),
+ SIRFSOC_PMX_FUNCTION("usb0_utmi_drvbus", usb0_utmi_drvbusgrp, usb0_utmi_drvbus_padmux),
+ SIRFSOC_PMX_FUNCTION("usb1_utmi_drvbus", usb1_utmi_drvbusgrp, usb1_utmi_drvbus_padmux),
+ SIRFSOC_PMX_FUNCTION("pulse_count", pulse_countgrp, pulse_count_padmux),
+ SIRFSOC_PMX_FUNCTION("i2s", i2sgrp, i2s_padmux),
+ SIRFSOC_PMX_FUNCTION("ac97", ac97grp, ac97_padmux),
+ SIRFSOC_PMX_FUNCTION("nand", nandgrp, nand_padmux),
+ SIRFSOC_PMX_FUNCTION("spi0", spi0grp, spi0_padmux),
+ SIRFSOC_PMX_FUNCTION("spi1", spi1grp, spi1_padmux),
+ SIRFSOC_PMX_FUNCTION("gps", gpsgrp, gps_padmux),
+};
+
+static void sirfsoc_pinmux_endisable(struct sirfsoc_pmx *spmx, unsigned selector,
+ bool enable)
+{
+ int i;
+ const struct sirfsoc_padmux *mux = sirfsoc_pmx_functions[selector].padmux;
+ const struct sirfsoc_muxmask *mask = mux->muxmask;
+
+ for (i = 0; i < mux->muxmask_counts; i++) {
+ u32 muxval;
+ muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
+ if (enable)
+ muxval = muxval & ~mask[i].mask;
+ else
+ muxval = muxval | mask[i].mask;
+ writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
+ }
+
+ if (mux->funcmask && enable) {
+ u32 func_en_val;
+ func_en_val =
+ readl(spmx->rsc_virtbase + SIRFSOC_RSC_PIN_MUX);
+ func_en_val =
+ (func_en_val & ~mux->funcmask) | (mux->
+ funcval);
+ writel(func_en_val, spmx->rsc_virtbase + SIRFSOC_RSC_PIN_MUX);
+ }
+}
+
+static int sirfsoc_pinmux_enable(struct pinctrl_dev *pmxdev, unsigned selector,
+ unsigned group)
+{
+ struct sirfsoc_pmx *spmx;
+
+ spmx = pinctrl_dev_get_drvdata(pmxdev);
+ sirfsoc_pinmux_endisable(spmx, selector, true);
+
+ return 0;
+}
+
+static void sirfsoc_pinmux_disable(struct pinctrl_dev *pmxdev, unsigned selector,
+ unsigned group)
+{
+ struct sirfsoc_pmx *spmx;
+
+ spmx = pinctrl_dev_get_drvdata(pmxdev);
+ sirfsoc_pinmux_endisable(spmx, selector, false);
+}
+
+static int sirfsoc_pinmux_list_funcs(struct pinctrl_dev *pmxdev, unsigned selector)
+{
+ if (selector >= ARRAY_SIZE(sirfsoc_pmx_functions))
+ return -EINVAL;
+ return 0;
+}
+
+static const char *sirfsoc_pinmux_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ return sirfsoc_pmx_functions[selector].name;
+}
+
+static int sirfsoc_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ *groups = sirfsoc_pmx_functions[selector].groups;
+ *num_groups = sirfsoc_pmx_functions[selector].num_groups;
+ return 0;
+}
+
+static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev,
+ struct pinctrl_gpio_range *range, unsigned offset)
+{
+ struct sirfsoc_pmx *spmx;
+
+ int group = range->id;
+
+ u32 muxval;
+
+ spmx = pinctrl_dev_get_drvdata(pmxdev);
+
+ muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
+ muxval = muxval | (1 << offset);
+ writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
+
+ return 0;
+}
+
+static struct pinmux_ops sirfsoc_pinmux_ops = {
+ .list_functions = sirfsoc_pinmux_list_funcs,
+ .enable = sirfsoc_pinmux_enable,
+ .disable = sirfsoc_pinmux_disable,
+ .get_function_name = sirfsoc_pinmux_get_func_name,
+ .get_function_groups = sirfsoc_pinmux_get_groups,
+ .gpio_request_enable = sirfsoc_pinmux_request_gpio,
+};
+
+static struct pinctrl_desc sirfsoc_pinmux_desc = {
+ .name = DRIVER_NAME,
+ .pins = sirfsoc_pads,
+ .npins = ARRAY_SIZE(sirfsoc_pads),
+ .maxpin = SIRFSOC_NUM_PADS - 1,
+ .pctlops = &sirfsoc_pctrl_ops,
+ .pmxops = &sirfsoc_pinmux_ops,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * Todo: bind irq_chip to every pinctrl_gpio_range
+ */
+static struct pinctrl_gpio_range sirfsoc_gpio_ranges[] = {
+ {
+ .name = "sirfsoc-gpio*",
+ .id = 0,
+ .base = 0,
+ .npins = 32,
+ }, {
+ .name = "sirfsoc-gpio*",
+ .id = 1,
+ .base = 32,
+ .npins = 32,
+ }, {
+ .name = "sirfsoc-gpio*",
+ .id = 2,
+ .base = 64,
+ .npins = 32,
+ }, {
+ .name = "sirfsoc-gpio*",
+ .id = 3,
+ .base = 96,
+ .npins = 19,
+ },
+};
+
+static void __iomem *sirfsoc_rsc_of_iomap(void)
+{
+ const struct of_device_id rsc_ids[] = {
+ { .compatible = "sirf,prima2-rsc" },
+ {}
+ };
+ struct device_node *np;
+
+ np = of_find_matching_node(NULL, rsc_ids);
+ if (!np)
+ panic("unable to find compatible rsc node in dtb\n");
+
+ return of_iomap(np, 0);
+}
+
+static int __devinit sirfsoc_pinmux_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct sirfsoc_pmx *spmx;
+ struct device_node *np = pdev->dev.of_node;
+ int i;
+
+ /* Create state holders etc for this driver */
+ spmx = devm_kzalloc(&pdev->dev, sizeof(*spmx), GFP_KERNEL);
+ if (!spmx)
+ return -ENOMEM;
+
+ spmx->dev = &pdev->dev;
+
+ platform_set_drvdata(pdev, spmx);
+
+ spmx->gpio_virtbase = of_iomap(np, 0);
+ if (!spmx->gpio_virtbase) {
+ ret = -ENOMEM;
+ dev_err(&pdev->dev, "can't map gpio registers\n");
+ goto out_no_gpio_remap;
+ }
+
+ spmx->rsc_virtbase = sirfsoc_rsc_of_iomap();
+ if (!spmx->rsc_virtbase) {
+ ret = -ENOMEM;
+ dev_err(&pdev->dev, "can't map rsc registers\n");
+ goto out_no_rsc_remap;
+ }
+
+ /* Now register the pin controller and all pins it handles */
+ spmx->pmx = pinctrl_register(&sirfsoc_pinmux_desc, &pdev->dev, spmx);
+ if (!spmx->pmx) {
+ dev_err(&pdev->dev, "could not register SIRFSOC pinmux driver\n");
+ ret = -EINVAL;
+ goto out_no_pmx;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sirfsoc_gpio_ranges); i++)
+ pinctrl_add_gpio_range(spmx->pmx, &sirfsoc_gpio_ranges[i]);
+
+ dev_info(&pdev->dev, "initialized SIRFSOC pinmux driver\n");
+
+ return 0;
+
+out_no_pmx:
+ iounmap(spmx->rsc_virtbase);
+out_no_rsc_remap:
+ iounmap(spmx->gpio_virtbase);
+out_no_gpio_remap:
+ platform_set_drvdata(pdev, NULL);
+ devm_kfree(&pdev->dev, spmx);
+ return ret;
+}
+
+static const struct of_device_id pinmux_ids[] = {
+ { .compatible = "sirf,prima2-gpio-pinmux" },
+ {}
+};
+
+static struct platform_driver sirfsoc_pinmux_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = pinmux_ids,
+ },
+ .probe = sirfsoc_pinmux_probe,
+};
+
+static int __init sirfsoc_pinmux_init(void)
+{
+ return platform_driver_register(&sirfsoc_pinmux_driver);
+}
+arch_initcall(sirfsoc_pinmux_init);
+
+MODULE_AUTHOR("Rongjun Ying <rongjun.ying@csr.com>, "
+ "Barry Song <baohua.song@csr.com>");
+MODULE_DESCRIPTION("SIRFSOC pin control driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/pinmux-u300.c b/drivers/pinctrl/pinmux-u300.c
new file mode 100644
index 000000000000..4858a64131f8
--- /dev/null
+++ b/drivers/pinctrl/pinmux-u300.c
@@ -0,0 +1,1135 @@
+/*
+ * Driver for the U300 pin controller
+ *
+ * Based on the original U300 padmux functions
+ * Copyright (C) 2009-2011 ST-Ericsson AB
+ * Author: Martin Persson <martin.persson@stericsson.com>
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * The DB3350 design and control registers are oriented around pads rather than
+ * pins, so we enumerate the pads we can mux rather than actual pins. The pads
+ * are connected to different pins in different packaging types, so it would
+ * be confusing.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+/*
+ * Register definitions for the U300 Padmux control registers in the
+ * system controller
+ */
+
+/* PAD MUX Control register 1 (LOW) 16bit (R/W) */
+#define U300_SYSCON_PMC1LR 0x007C
+#define U300_SYSCON_PMC1LR_MASK 0xFFFF
+#define U300_SYSCON_PMC1LR_CDI_MASK 0xC000
+#define U300_SYSCON_PMC1LR_CDI_CDI 0x0000
+#define U300_SYSCON_PMC1LR_CDI_EMIF 0x4000
+/* For BS335 */
+#define U300_SYSCON_PMC1LR_CDI_CDI2 0x8000
+#define U300_SYSCON_PMC1LR_CDI_WCDMA_APP_GPIO 0xC000
+/* For BS365 */
+#define U300_SYSCON_PMC1LR_CDI_GPIO 0x8000
+#define U300_SYSCON_PMC1LR_CDI_WCDMA 0xC000
+/* Common defs */
+#define U300_SYSCON_PMC1LR_PDI_MASK 0x3000
+#define U300_SYSCON_PMC1LR_PDI_PDI 0x0000
+#define U300_SYSCON_PMC1LR_PDI_EGG 0x1000
+#define U300_SYSCON_PMC1LR_PDI_WCDMA 0x3000
+#define U300_SYSCON_PMC1LR_MMCSD_MASK 0x0C00
+#define U300_SYSCON_PMC1LR_MMCSD_MMCSD 0x0000
+#define U300_SYSCON_PMC1LR_MMCSD_MSPRO 0x0400
+#define U300_SYSCON_PMC1LR_MMCSD_DSP 0x0800
+#define U300_SYSCON_PMC1LR_MMCSD_WCDMA 0x0C00
+#define U300_SYSCON_PMC1LR_ETM_MASK 0x0300
+#define U300_SYSCON_PMC1LR_ETM_ACC 0x0000
+#define U300_SYSCON_PMC1LR_ETM_APP 0x0100
+#define U300_SYSCON_PMC1LR_EMIF_1_CS2_MASK 0x00C0
+#define U300_SYSCON_PMC1LR_EMIF_1_CS2_STATIC 0x0000
+#define U300_SYSCON_PMC1LR_EMIF_1_CS2_NFIF 0x0040
+#define U300_SYSCON_PMC1LR_EMIF_1_CS2_SDRAM 0x0080
+#define U300_SYSCON_PMC1LR_EMIF_1_CS2_STATIC_2GB 0x00C0
+#define U300_SYSCON_PMC1LR_EMIF_1_CS1_MASK 0x0030
+#define U300_SYSCON_PMC1LR_EMIF_1_CS1_STATIC 0x0000
+#define U300_SYSCON_PMC1LR_EMIF_1_CS1_NFIF 0x0010
+#define U300_SYSCON_PMC1LR_EMIF_1_CS1_SDRAM 0x0020
+#define U300_SYSCON_PMC1LR_EMIF_1_CS1_SEMI 0x0030
+#define U300_SYSCON_PMC1LR_EMIF_1_CS0_MASK 0x000C
+#define U300_SYSCON_PMC1LR_EMIF_1_CS0_STATIC 0x0000
+#define U300_SYSCON_PMC1LR_EMIF_1_CS0_NFIF 0x0004
+#define U300_SYSCON_PMC1LR_EMIF_1_CS0_SDRAM 0x0008
+#define U300_SYSCON_PMC1LR_EMIF_1_CS0_SEMI 0x000C
+#define U300_SYSCON_PMC1LR_EMIF_1_MASK 0x0003
+#define U300_SYSCON_PMC1LR_EMIF_1_STATIC 0x0000
+#define U300_SYSCON_PMC1LR_EMIF_1_SDRAM0 0x0001
+#define U300_SYSCON_PMC1LR_EMIF_1_SDRAM1 0x0002
+#define U300_SYSCON_PMC1LR_EMIF_1 0x0003
+/* PAD MUX Control register 2 (HIGH) 16bit (R/W) */
+#define U300_SYSCON_PMC1HR 0x007E
+#define U300_SYSCON_PMC1HR_MASK 0xFFFF
+#define U300_SYSCON_PMC1HR_MISC_2_MASK 0xC000
+#define U300_SYSCON_PMC1HR_MISC_2_APP_GPIO 0x0000
+#define U300_SYSCON_PMC1HR_MISC_2_MSPRO 0x4000
+#define U300_SYSCON_PMC1HR_MISC_2_DSP 0x8000
+#define U300_SYSCON_PMC1HR_MISC_2_AAIF 0xC000
+#define U300_SYSCON_PMC1HR_APP_GPIO_2_MASK 0x3000
+#define U300_SYSCON_PMC1HR_APP_GPIO_2_APP_GPIO 0x0000
+#define U300_SYSCON_PMC1HR_APP_GPIO_2_NFIF 0x1000
+#define U300_SYSCON_PMC1HR_APP_GPIO_2_DSP 0x2000
+#define U300_SYSCON_PMC1HR_APP_GPIO_2_AAIF 0x3000
+#define U300_SYSCON_PMC1HR_APP_GPIO_1_MASK 0x0C00
+#define U300_SYSCON_PMC1HR_APP_GPIO_1_APP_GPIO 0x0000
+#define U300_SYSCON_PMC1HR_APP_GPIO_1_MMC 0x0400
+#define U300_SYSCON_PMC1HR_APP_GPIO_1_DSP 0x0800
+#define U300_SYSCON_PMC1HR_APP_GPIO_1_AAIF 0x0C00
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_MASK 0x0300
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_APP_GPIO 0x0000
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_SPI 0x0100
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_2_AAIF 0x0300
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_MASK 0x00C0
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_APP_GPIO 0x0000
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_SPI 0x0040
+#define U300_SYSCON_PMC1HR_APP_SPI_CS_1_AAIF 0x00C0
+#define U300_SYSCON_PMC1HR_APP_SPI_2_MASK 0x0030
+#define U300_SYSCON_PMC1HR_APP_SPI_2_APP_GPIO 0x0000
+#define U300_SYSCON_PMC1HR_APP_SPI_2_SPI 0x0010
+#define U300_SYSCON_PMC1HR_APP_SPI_2_DSP 0x0020
+#define U300_SYSCON_PMC1HR_APP_SPI_2_AAIF 0x0030
+#define U300_SYSCON_PMC1HR_APP_UART0_2_MASK 0x000C
+#define U300_SYSCON_PMC1HR_APP_UART0_2_APP_GPIO 0x0000
+#define U300_SYSCON_PMC1HR_APP_UART0_2_UART0 0x0004
+#define U300_SYSCON_PMC1HR_APP_UART0_2_NFIF_CS 0x0008
+#define U300_SYSCON_PMC1HR_APP_UART0_2_AAIF 0x000C
+#define U300_SYSCON_PMC1HR_APP_UART0_1_MASK 0x0003
+#define U300_SYSCON_PMC1HR_APP_UART0_1_APP_GPIO 0x0000
+#define U300_SYSCON_PMC1HR_APP_UART0_1_UART0 0x0001
+#define U300_SYSCON_PMC1HR_APP_UART0_1_AAIF 0x0003
+/* Padmux 2 control */
+#define U300_SYSCON_PMC2R 0x100
+#define U300_SYSCON_PMC2R_APP_MISC_0_MASK 0x00C0
+#define U300_SYSCON_PMC2R_APP_MISC_0_APP_GPIO 0x0000
+#define U300_SYSCON_PMC2R_APP_MISC_0_EMIF_SDRAM 0x0040
+#define U300_SYSCON_PMC2R_APP_MISC_0_MMC 0x0080
+#define U300_SYSCON_PMC2R_APP_MISC_0_CDI2 0x00C0
+#define U300_SYSCON_PMC2R_APP_MISC_1_MASK 0x0300
+#define U300_SYSCON_PMC2R_APP_MISC_1_APP_GPIO 0x0000
+#define U300_SYSCON_PMC2R_APP_MISC_1_EMIF_SDRAM 0x0100
+#define U300_SYSCON_PMC2R_APP_MISC_1_MMC 0x0200
+#define U300_SYSCON_PMC2R_APP_MISC_1_CDI2 0x0300
+#define U300_SYSCON_PMC2R_APP_MISC_2_MASK 0x0C00
+#define U300_SYSCON_PMC2R_APP_MISC_2_APP_GPIO 0x0000
+#define U300_SYSCON_PMC2R_APP_MISC_2_EMIF_SDRAM 0x0400
+#define U300_SYSCON_PMC2R_APP_MISC_2_MMC 0x0800
+#define U300_SYSCON_PMC2R_APP_MISC_2_CDI2 0x0C00
+#define U300_SYSCON_PMC2R_APP_MISC_3_MASK 0x3000
+#define U300_SYSCON_PMC2R_APP_MISC_3_APP_GPIO 0x0000
+#define U300_SYSCON_PMC2R_APP_MISC_3_EMIF_SDRAM 0x1000
+#define U300_SYSCON_PMC2R_APP_MISC_3_MMC 0x2000
+#define U300_SYSCON_PMC2R_APP_MISC_3_CDI2 0x3000
+#define U300_SYSCON_PMC2R_APP_MISC_4_MASK 0xC000
+#define U300_SYSCON_PMC2R_APP_MISC_4_APP_GPIO 0x0000
+#define U300_SYSCON_PMC2R_APP_MISC_4_EMIF_SDRAM 0x4000
+#define U300_SYSCON_PMC2R_APP_MISC_4_MMC 0x8000
+#define U300_SYSCON_PMC2R_APP_MISC_4_ACC_GPIO 0xC000
+/* TODO: More SYSCON registers missing */
+#define U300_SYSCON_PMC3R 0x10C
+#define U300_SYSCON_PMC3R_APP_MISC_11_MASK 0xC000
+#define U300_SYSCON_PMC3R_APP_MISC_11_SPI 0x4000
+#define U300_SYSCON_PMC3R_APP_MISC_10_MASK 0x3000
+#define U300_SYSCON_PMC3R_APP_MISC_10_SPI 0x1000
+/* TODO: Missing other configs */
+#define U300_SYSCON_PMC4R 0x168
+#define U300_SYSCON_PMC4R_APP_MISC_12_MASK 0x0003
+#define U300_SYSCON_PMC4R_APP_MISC_12_APP_GPIO 0x0000
+#define U300_SYSCON_PMC4R_APP_MISC_13_MASK 0x000C
+#define U300_SYSCON_PMC4R_APP_MISC_13_CDI 0x0000
+#define U300_SYSCON_PMC4R_APP_MISC_13_SMIA 0x0004
+#define U300_SYSCON_PMC4R_APP_MISC_13_SMIA2 0x0008
+#define U300_SYSCON_PMC4R_APP_MISC_13_APP_GPIO 0x000C
+#define U300_SYSCON_PMC4R_APP_MISC_14_MASK 0x0030
+#define U300_SYSCON_PMC4R_APP_MISC_14_CDI 0x0000
+#define U300_SYSCON_PMC4R_APP_MISC_14_SMIA 0x0010
+#define U300_SYSCON_PMC4R_APP_MISC_14_CDI2 0x0020
+#define U300_SYSCON_PMC4R_APP_MISC_14_APP_GPIO 0x0030
+#define U300_SYSCON_PMC4R_APP_MISC_16_MASK 0x0300
+#define U300_SYSCON_PMC4R_APP_MISC_16_APP_GPIO_13 0x0000
+#define U300_SYSCON_PMC4R_APP_MISC_16_APP_UART1_CTS 0x0100
+#define U300_SYSCON_PMC4R_APP_MISC_16_EMIF_1_STATIC_CS5_N 0x0200
+
+#define DRIVER_NAME "pinmux-u300"
+
+/*
+ * The DB3350 has 467 pads, I have enumerated the pads clockwise around the
+ * edges of the silicon, finger by finger. LTCORNER upper left is pad 0.
+ * Data taken from the PadRing chart, arranged like this:
+ *
+ * 0 ..... 104
+ * 466 105
+ * . .
+ * . .
+ * 358 224
+ * 357 .... 225
+ */
+#define U300_NUM_PADS 467
+
+/* Pad names for the pinmux subsystem */
+static const struct pinctrl_pin_desc u300_pads[] = {
+ /* Pads along the top edge of the chip */
+ PINCTRL_PIN(0, "P PAD VDD 28"),
+ PINCTRL_PIN(1, "P PAD GND 28"),
+ PINCTRL_PIN(2, "PO SIM RST N"),
+ PINCTRL_PIN(3, "VSSIO 25"),
+ PINCTRL_PIN(4, "VSSA ADDA ESDSUB"),
+ PINCTRL_PIN(5, "PWR VSSCOMMON"),
+ PINCTRL_PIN(6, "PI ADC I1 POS"),
+ PINCTRL_PIN(7, "PI ADC I1 NEG"),
+ PINCTRL_PIN(8, "PWR VSSAD0"),
+ PINCTRL_PIN(9, "PWR VCCAD0"),
+ PINCTRL_PIN(10, "PI ADC Q1 NEG"),
+ PINCTRL_PIN(11, "PI ADC Q1 POS"),
+ PINCTRL_PIN(12, "PWR VDDAD"),
+ PINCTRL_PIN(13, "PWR GNDAD"),
+ PINCTRL_PIN(14, "PI ADC I2 POS"),
+ PINCTRL_PIN(15, "PI ADC I2 NEG"),
+ PINCTRL_PIN(16, "PWR VSSAD1"),
+ PINCTRL_PIN(17, "PWR VCCAD1"),
+ PINCTRL_PIN(18, "PI ADC Q2 NEG"),
+ PINCTRL_PIN(19, "PI ADC Q2 POS"),
+ PINCTRL_PIN(20, "VSSA ADDA ESDSUB"),
+ PINCTRL_PIN(21, "PWR VCCGPAD"),
+ PINCTRL_PIN(22, "PI TX POW"),
+ PINCTRL_PIN(23, "PWR VSSGPAD"),
+ PINCTRL_PIN(24, "PO DAC I POS"),
+ PINCTRL_PIN(25, "PO DAC I NEG"),
+ PINCTRL_PIN(26, "PO DAC Q POS"),
+ PINCTRL_PIN(27, "PO DAC Q NEG"),
+ PINCTRL_PIN(28, "PWR VSSDA"),
+ PINCTRL_PIN(29, "PWR VCCDA"),
+ PINCTRL_PIN(30, "VSSA ADDA ESDSUB"),
+ PINCTRL_PIN(31, "P PAD VDDIO 11"),
+ PINCTRL_PIN(32, "PI PLL 26 FILTVDD"),
+ PINCTRL_PIN(33, "PI PLL 26 VCONT"),
+ PINCTRL_PIN(34, "PWR AGNDPLL2V5 32 13"),
+ PINCTRL_PIN(35, "PWR AVDDPLL2V5 32 13"),
+ PINCTRL_PIN(36, "VDDA PLL ESD"),
+ PINCTRL_PIN(37, "VSSA PLL ESD"),
+ PINCTRL_PIN(38, "VSS PLL"),
+ PINCTRL_PIN(39, "VDDC PLL"),
+ PINCTRL_PIN(40, "PWR AGNDPLL2V5 26 60"),
+ PINCTRL_PIN(41, "PWR AVDDPLL2V5 26 60"),
+ PINCTRL_PIN(42, "PWR AVDDPLL2V5 26 208"),
+ PINCTRL_PIN(43, "PWR AGNDPLL2V5 26 208"),
+ PINCTRL_PIN(44, "PWR AVDDPLL2V5 13 208"),
+ PINCTRL_PIN(45, "PWR AGNDPLL2V5 13 208"),
+ PINCTRL_PIN(46, "P PAD VSSIO 11"),
+ PINCTRL_PIN(47, "P PAD VSSIO 12"),
+ PINCTRL_PIN(48, "PI POW RST N"),
+ PINCTRL_PIN(49, "VDDC IO"),
+ PINCTRL_PIN(50, "P PAD VDDIO 16"),
+ PINCTRL_PIN(51, "PO RF WCDMA EN 4"),
+ PINCTRL_PIN(52, "PO RF WCDMA EN 3"),
+ PINCTRL_PIN(53, "PO RF WCDMA EN 2"),
+ PINCTRL_PIN(54, "PO RF WCDMA EN 1"),
+ PINCTRL_PIN(55, "PO RF WCDMA EN 0"),
+ PINCTRL_PIN(56, "PO GSM PA ENABLE"),
+ PINCTRL_PIN(57, "PO RF DATA STRB"),
+ PINCTRL_PIN(58, "PO RF DATA2"),
+ PINCTRL_PIN(59, "PIO RF DATA1"),
+ PINCTRL_PIN(60, "PIO RF DATA0"),
+ PINCTRL_PIN(61, "P PAD VDD 11"),
+ PINCTRL_PIN(62, "P PAD GND 11"),
+ PINCTRL_PIN(63, "P PAD VSSIO 16"),
+ PINCTRL_PIN(64, "P PAD VDDIO 18"),
+ PINCTRL_PIN(65, "PO RF CTRL STRB2"),
+ PINCTRL_PIN(66, "PO RF CTRL STRB1"),
+ PINCTRL_PIN(67, "PO RF CTRL STRB0"),
+ PINCTRL_PIN(68, "PIO RF CTRL DATA"),
+ PINCTRL_PIN(69, "PO RF CTRL CLK"),
+ PINCTRL_PIN(70, "PO TX ADC STRB"),
+ PINCTRL_PIN(71, "PO ANT SW 2"),
+ PINCTRL_PIN(72, "PO ANT SW 3"),
+ PINCTRL_PIN(73, "PO ANT SW 0"),
+ PINCTRL_PIN(74, "PO ANT SW 1"),
+ PINCTRL_PIN(75, "PO M CLKRQ"),
+ PINCTRL_PIN(76, "PI M CLK"),
+ PINCTRL_PIN(77, "PI RTC CLK"),
+ PINCTRL_PIN(78, "P PAD VDD 8"),
+ PINCTRL_PIN(79, "P PAD GND 8"),
+ PINCTRL_PIN(80, "P PAD VSSIO 13"),
+ PINCTRL_PIN(81, "P PAD VDDIO 13"),
+ PINCTRL_PIN(82, "PO SYS 1 CLK"),
+ PINCTRL_PIN(83, "PO SYS 2 CLK"),
+ PINCTRL_PIN(84, "PO SYS 0 CLK"),
+ PINCTRL_PIN(85, "PI SYS 0 CLKRQ"),
+ PINCTRL_PIN(86, "PO PWR MNGT CTRL 1"),
+ PINCTRL_PIN(87, "PO PWR MNGT CTRL 0"),
+ PINCTRL_PIN(88, "PO RESOUT2 RST N"),
+ PINCTRL_PIN(89, "PO RESOUT1 RST N"),
+ PINCTRL_PIN(90, "PO RESOUT0 RST N"),
+ PINCTRL_PIN(91, "PI SERVICE N"),
+ PINCTRL_PIN(92, "P PAD VDD 29"),
+ PINCTRL_PIN(93, "P PAD GND 29"),
+ PINCTRL_PIN(94, "P PAD VSSIO 8"),
+ PINCTRL_PIN(95, "P PAD VDDIO 8"),
+ PINCTRL_PIN(96, "PI EXT IRQ1 N"),
+ PINCTRL_PIN(97, "PI EXT IRQ0 N"),
+ PINCTRL_PIN(98, "PIO DC ON"),
+ PINCTRL_PIN(99, "PIO ACC APP I2C DATA"),
+ PINCTRL_PIN(100, "PIO ACC APP I2C CLK"),
+ PINCTRL_PIN(101, "P PAD VDD 12"),
+ PINCTRL_PIN(102, "P PAD GND 12"),
+ PINCTRL_PIN(103, "P PAD VSSIO 14"),
+ PINCTRL_PIN(104, "P PAD VDDIO 14"),
+ /* Pads along the right edge of the chip */
+ PINCTRL_PIN(105, "PIO APP I2C1 DATA"),
+ PINCTRL_PIN(106, "PIO APP I2C1 CLK"),
+ PINCTRL_PIN(107, "PO KEY OUT0"),
+ PINCTRL_PIN(108, "PO KEY OUT1"),
+ PINCTRL_PIN(109, "PO KEY OUT2"),
+ PINCTRL_PIN(110, "PO KEY OUT3"),
+ PINCTRL_PIN(111, "PO KEY OUT4"),
+ PINCTRL_PIN(112, "PI KEY IN0"),
+ PINCTRL_PIN(113, "PI KEY IN1"),
+ PINCTRL_PIN(114, "PI KEY IN2"),
+ PINCTRL_PIN(115, "P PAD VDDIO 15"),
+ PINCTRL_PIN(116, "P PAD VSSIO 15"),
+ PINCTRL_PIN(117, "P PAD GND 13"),
+ PINCTRL_PIN(118, "P PAD VDD 13"),
+ PINCTRL_PIN(119, "PI KEY IN3"),
+ PINCTRL_PIN(120, "PI KEY IN4"),
+ PINCTRL_PIN(121, "PI KEY IN5"),
+ PINCTRL_PIN(122, "PIO APP PCM I2S1 DATA B"),
+ PINCTRL_PIN(123, "PIO APP PCM I2S1 DATA A"),
+ PINCTRL_PIN(124, "PIO APP PCM I2S1 WS"),
+ PINCTRL_PIN(125, "PIO APP PCM I2S1 CLK"),
+ PINCTRL_PIN(126, "PIO APP PCM I2S0 DATA B"),
+ PINCTRL_PIN(127, "PIO APP PCM I2S0 DATA A"),
+ PINCTRL_PIN(128, "PIO APP PCM I2S0 WS"),
+ PINCTRL_PIN(129, "PIO APP PCM I2S0 CLK"),
+ PINCTRL_PIN(130, "P PAD VDD 17"),
+ PINCTRL_PIN(131, "P PAD GND 17"),
+ PINCTRL_PIN(132, "P PAD VSSIO 19"),
+ PINCTRL_PIN(133, "P PAD VDDIO 19"),
+ PINCTRL_PIN(134, "UART0 RTS"),
+ PINCTRL_PIN(135, "UART0 CTS"),
+ PINCTRL_PIN(136, "UART0 TX"),
+ PINCTRL_PIN(137, "UART0 RX"),
+ PINCTRL_PIN(138, "PIO ACC SPI DO"),
+ PINCTRL_PIN(139, "PIO ACC SPI DI"),
+ PINCTRL_PIN(140, "PIO ACC SPI CS0 N"),
+ PINCTRL_PIN(141, "PIO ACC SPI CS1 N"),
+ PINCTRL_PIN(142, "PIO ACC SPI CS2 N"),
+ PINCTRL_PIN(143, "PIO ACC SPI CLK"),
+ PINCTRL_PIN(144, "PO PDI EXT RST N"),
+ PINCTRL_PIN(145, "P PAD VDDIO 22"),
+ PINCTRL_PIN(146, "P PAD VSSIO 22"),
+ PINCTRL_PIN(147, "P PAD GND 18"),
+ PINCTRL_PIN(148, "P PAD VDD 18"),
+ PINCTRL_PIN(149, "PIO PDI C0"),
+ PINCTRL_PIN(150, "PIO PDI C1"),
+ PINCTRL_PIN(151, "PIO PDI C2"),
+ PINCTRL_PIN(152, "PIO PDI C3"),
+ PINCTRL_PIN(153, "PIO PDI C4"),
+ PINCTRL_PIN(154, "PIO PDI C5"),
+ PINCTRL_PIN(155, "PIO PDI D0"),
+ PINCTRL_PIN(156, "PIO PDI D1"),
+ PINCTRL_PIN(157, "PIO PDI D2"),
+ PINCTRL_PIN(158, "PIO PDI D3"),
+ PINCTRL_PIN(159, "P PAD VDDIO 21"),
+ PINCTRL_PIN(160, "P PAD VSSIO 21"),
+ PINCTRL_PIN(161, "PIO PDI D4"),
+ PINCTRL_PIN(162, "PIO PDI D5"),
+ PINCTRL_PIN(163, "PIO PDI D6"),
+ PINCTRL_PIN(164, "PIO PDI D7"),
+ PINCTRL_PIN(165, "PIO MS INS"),
+ PINCTRL_PIN(166, "MMC DATA DIR LS"),
+ PINCTRL_PIN(167, "MMC DATA 3"),
+ PINCTRL_PIN(168, "MMC DATA 2"),
+ PINCTRL_PIN(169, "MMC DATA 1"),
+ PINCTRL_PIN(170, "MMC DATA 0"),
+ PINCTRL_PIN(171, "MMC CMD DIR LS"),
+ PINCTRL_PIN(172, "P PAD VDD 27"),
+ PINCTRL_PIN(173, "P PAD GND 27"),
+ PINCTRL_PIN(174, "P PAD VSSIO 20"),
+ PINCTRL_PIN(175, "P PAD VDDIO 20"),
+ PINCTRL_PIN(176, "MMC CMD"),
+ PINCTRL_PIN(177, "MMC CLK"),
+ PINCTRL_PIN(178, "PIO APP GPIO 14"),
+ PINCTRL_PIN(179, "PIO APP GPIO 13"),
+ PINCTRL_PIN(180, "PIO APP GPIO 11"),
+ PINCTRL_PIN(181, "PIO APP GPIO 25"),
+ PINCTRL_PIN(182, "PIO APP GPIO 24"),
+ PINCTRL_PIN(183, "PIO APP GPIO 23"),
+ PINCTRL_PIN(184, "PIO APP GPIO 22"),
+ PINCTRL_PIN(185, "PIO APP GPIO 21"),
+ PINCTRL_PIN(186, "PIO APP GPIO 20"),
+ PINCTRL_PIN(187, "P PAD VDD 19"),
+ PINCTRL_PIN(188, "P PAD GND 19"),
+ PINCTRL_PIN(189, "P PAD VSSIO 23"),
+ PINCTRL_PIN(190, "P PAD VDDIO 23"),
+ PINCTRL_PIN(191, "PIO APP GPIO 19"),
+ PINCTRL_PIN(192, "PIO APP GPIO 18"),
+ PINCTRL_PIN(193, "PIO APP GPIO 17"),
+ PINCTRL_PIN(194, "PIO APP GPIO 16"),
+ PINCTRL_PIN(195, "PI CI D1"),
+ PINCTRL_PIN(196, "PI CI D0"),
+ PINCTRL_PIN(197, "PI CI HSYNC"),
+ PINCTRL_PIN(198, "PI CI VSYNC"),
+ PINCTRL_PIN(199, "PI CI EXT CLK"),
+ PINCTRL_PIN(200, "PO CI EXT RST N"),
+ PINCTRL_PIN(201, "P PAD VSSIO 43"),
+ PINCTRL_PIN(202, "P PAD VDDIO 43"),
+ PINCTRL_PIN(203, "PI CI D6"),
+ PINCTRL_PIN(204, "PI CI D7"),
+ PINCTRL_PIN(205, "PI CI D2"),
+ PINCTRL_PIN(206, "PI CI D3"),
+ PINCTRL_PIN(207, "PI CI D4"),
+ PINCTRL_PIN(208, "PI CI D5"),
+ PINCTRL_PIN(209, "PI CI D8"),
+ PINCTRL_PIN(210, "PI CI D9"),
+ PINCTRL_PIN(211, "P PAD VDD 20"),
+ PINCTRL_PIN(212, "P PAD GND 20"),
+ PINCTRL_PIN(213, "P PAD VSSIO 24"),
+ PINCTRL_PIN(214, "P PAD VDDIO 24"),
+ PINCTRL_PIN(215, "P PAD VDDIO 26"),
+ PINCTRL_PIN(216, "PO EMIF 1 A26"),
+ PINCTRL_PIN(217, "PO EMIF 1 A25"),
+ PINCTRL_PIN(218, "P PAD VSSIO 26"),
+ PINCTRL_PIN(219, "PO EMIF 1 A24"),
+ PINCTRL_PIN(220, "PO EMIF 1 A23"),
+ /* Pads along the bottom edge of the chip */
+ PINCTRL_PIN(221, "PO EMIF 1 A22"),
+ PINCTRL_PIN(222, "PO EMIF 1 A21"),
+ PINCTRL_PIN(223, "P PAD VDD 21"),
+ PINCTRL_PIN(224, "P PAD GND 21"),
+ PINCTRL_PIN(225, "P PAD VSSIO 27"),
+ PINCTRL_PIN(226, "P PAD VDDIO 27"),
+ PINCTRL_PIN(227, "PO EMIF 1 A20"),
+ PINCTRL_PIN(228, "PO EMIF 1 A19"),
+ PINCTRL_PIN(229, "PO EMIF 1 A18"),
+ PINCTRL_PIN(230, "PO EMIF 1 A17"),
+ PINCTRL_PIN(231, "P PAD VDDIO 28"),
+ PINCTRL_PIN(232, "P PAD VSSIO 28"),
+ PINCTRL_PIN(233, "PO EMIF 1 A16"),
+ PINCTRL_PIN(234, "PIO EMIF 1 D15"),
+ PINCTRL_PIN(235, "PO EMIF 1 A15"),
+ PINCTRL_PIN(236, "PIO EMIF 1 D14"),
+ PINCTRL_PIN(237, "P PAD VDD 22"),
+ PINCTRL_PIN(238, "P PAD GND 22"),
+ PINCTRL_PIN(239, "P PAD VSSIO 29"),
+ PINCTRL_PIN(240, "P PAD VDDIO 29"),
+ PINCTRL_PIN(241, "PO EMIF 1 A14"),
+ PINCTRL_PIN(242, "PIO EMIF 1 D13"),
+ PINCTRL_PIN(243, "PO EMIF 1 A13"),
+ PINCTRL_PIN(244, "PIO EMIF 1 D12"),
+ PINCTRL_PIN(245, "P PAD VSSIO 30"),
+ PINCTRL_PIN(246, "P PAD VDDIO 30"),
+ PINCTRL_PIN(247, "PO EMIF 1 A12"),
+ PINCTRL_PIN(248, "PIO EMIF 1 D11"),
+ PINCTRL_PIN(249, "PO EMIF 1 A11"),
+ PINCTRL_PIN(250, "PIO EMIF 1 D10"),
+ PINCTRL_PIN(251, "P PAD VSSIO 31"),
+ PINCTRL_PIN(252, "P PAD VDDIO 31"),
+ PINCTRL_PIN(253, "PO EMIF 1 A10"),
+ PINCTRL_PIN(254, "PIO EMIF 1 D09"),
+ PINCTRL_PIN(255, "PO EMIF 1 A09"),
+ PINCTRL_PIN(256, "P PAD VDDIO 32"),
+ PINCTRL_PIN(257, "P PAD VSSIO 32"),
+ PINCTRL_PIN(258, "P PAD GND 24"),
+ PINCTRL_PIN(259, "P PAD VDD 24"),
+ PINCTRL_PIN(260, "PIO EMIF 1 D08"),
+ PINCTRL_PIN(261, "PO EMIF 1 A08"),
+ PINCTRL_PIN(262, "PIO EMIF 1 D07"),
+ PINCTRL_PIN(263, "PO EMIF 1 A07"),
+ PINCTRL_PIN(264, "P PAD VDDIO 33"),
+ PINCTRL_PIN(265, "P PAD VSSIO 33"),
+ PINCTRL_PIN(266, "PIO EMIF 1 D06"),
+ PINCTRL_PIN(267, "PO EMIF 1 A06"),
+ PINCTRL_PIN(268, "PIO EMIF 1 D05"),
+ PINCTRL_PIN(269, "PO EMIF 1 A05"),
+ PINCTRL_PIN(270, "P PAD VDDIO 34"),
+ PINCTRL_PIN(271, "P PAD VSSIO 34"),
+ PINCTRL_PIN(272, "PIO EMIF 1 D04"),
+ PINCTRL_PIN(273, "PO EMIF 1 A04"),
+ PINCTRL_PIN(274, "PIO EMIF 1 D03"),
+ PINCTRL_PIN(275, "PO EMIF 1 A03"),
+ PINCTRL_PIN(276, "P PAD VDDIO 35"),
+ PINCTRL_PIN(277, "P PAD VSSIO 35"),
+ PINCTRL_PIN(278, "P PAD GND 23"),
+ PINCTRL_PIN(279, "P PAD VDD 23"),
+ PINCTRL_PIN(280, "PIO EMIF 1 D02"),
+ PINCTRL_PIN(281, "PO EMIF 1 A02"),
+ PINCTRL_PIN(282, "PIO EMIF 1 D01"),
+ PINCTRL_PIN(283, "PO EMIF 1 A01"),
+ PINCTRL_PIN(284, "P PAD VDDIO 36"),
+ PINCTRL_PIN(285, "P PAD VSSIO 36"),
+ PINCTRL_PIN(286, "PIO EMIF 1 D00"),
+ PINCTRL_PIN(287, "PO EMIF 1 BE1 N"),
+ PINCTRL_PIN(288, "PO EMIF 1 BE0 N"),
+ PINCTRL_PIN(289, "PO EMIF 1 ADV N"),
+ PINCTRL_PIN(290, "P PAD VDDIO 37"),
+ PINCTRL_PIN(291, "P PAD VSSIO 37"),
+ PINCTRL_PIN(292, "PO EMIF 1 SD CKE0"),
+ PINCTRL_PIN(293, "PO EMIF 1 OE N"),
+ PINCTRL_PIN(294, "PO EMIF 1 WE N"),
+ PINCTRL_PIN(295, "P PAD VDDIO 38"),
+ PINCTRL_PIN(296, "P PAD VSSIO 38"),
+ PINCTRL_PIN(297, "PO EMIF 1 CLK"),
+ PINCTRL_PIN(298, "PIO EMIF 1 SD CLK"),
+ PINCTRL_PIN(299, "P PAD VSSIO 45 (not bonded)"),
+ PINCTRL_PIN(300, "P PAD VDDIO 42"),
+ PINCTRL_PIN(301, "P PAD VSSIO 42"),
+ PINCTRL_PIN(302, "P PAD GND 31"),
+ PINCTRL_PIN(303, "P PAD VDD 31"),
+ PINCTRL_PIN(304, "PI EMIF 1 RET CLK"),
+ PINCTRL_PIN(305, "PI EMIF 1 WAIT N"),
+ PINCTRL_PIN(306, "PI EMIF 1 NFIF READY"),
+ PINCTRL_PIN(307, "PO EMIF 1 SD CKE1"),
+ PINCTRL_PIN(308, "PO EMIF 1 CS3 N"),
+ PINCTRL_PIN(309, "P PAD VDD 25"),
+ PINCTRL_PIN(310, "P PAD GND 25"),
+ PINCTRL_PIN(311, "P PAD VSSIO 39"),
+ PINCTRL_PIN(312, "P PAD VDDIO 39"),
+ PINCTRL_PIN(313, "PO EMIF 1 CS2 N"),
+ PINCTRL_PIN(314, "PO EMIF 1 CS1 N"),
+ PINCTRL_PIN(315, "PO EMIF 1 CS0 N"),
+ PINCTRL_PIN(316, "PO ETM TRACE PKT0"),
+ PINCTRL_PIN(317, "PO ETM TRACE PKT1"),
+ PINCTRL_PIN(318, "PO ETM TRACE PKT2"),
+ PINCTRL_PIN(319, "P PAD VDD 30"),
+ PINCTRL_PIN(320, "P PAD GND 30"),
+ PINCTRL_PIN(321, "P PAD VSSIO 44"),
+ PINCTRL_PIN(322, "P PAD VDDIO 44"),
+ PINCTRL_PIN(323, "PO ETM TRACE PKT3"),
+ PINCTRL_PIN(324, "PO ETM TRACE PKT4"),
+ PINCTRL_PIN(325, "PO ETM TRACE PKT5"),
+ PINCTRL_PIN(326, "PO ETM TRACE PKT6"),
+ PINCTRL_PIN(327, "PO ETM TRACE PKT7"),
+ PINCTRL_PIN(328, "PO ETM PIPE STAT0"),
+ PINCTRL_PIN(329, "P PAD VDD 26"),
+ PINCTRL_PIN(330, "P PAD GND 26"),
+ PINCTRL_PIN(331, "P PAD VSSIO 40"),
+ PINCTRL_PIN(332, "P PAD VDDIO 40"),
+ PINCTRL_PIN(333, "PO ETM PIPE STAT1"),
+ PINCTRL_PIN(334, "PO ETM PIPE STAT2"),
+ PINCTRL_PIN(335, "PO ETM TRACE CLK"),
+ PINCTRL_PIN(336, "PO ETM TRACE SYNC"),
+ PINCTRL_PIN(337, "PIO ACC GPIO 33"),
+ PINCTRL_PIN(338, "PIO ACC GPIO 32"),
+ PINCTRL_PIN(339, "PIO ACC GPIO 30"),
+ PINCTRL_PIN(340, "PIO ACC GPIO 29"),
+ PINCTRL_PIN(341, "P PAD VDDIO 17"),
+ PINCTRL_PIN(342, "P PAD VSSIO 17"),
+ PINCTRL_PIN(343, "P PAD GND 15"),
+ PINCTRL_PIN(344, "P PAD VDD 15"),
+ PINCTRL_PIN(345, "PIO ACC GPIO 28"),
+ PINCTRL_PIN(346, "PIO ACC GPIO 27"),
+ PINCTRL_PIN(347, "PIO ACC GPIO 16"),
+ PINCTRL_PIN(348, "PI TAP TMS"),
+ PINCTRL_PIN(349, "PI TAP TDI"),
+ PINCTRL_PIN(350, "PO TAP TDO"),
+ PINCTRL_PIN(351, "PI TAP RST N"),
+ /* Pads along the left edge of the chip */
+ PINCTRL_PIN(352, "PI EMU MODE 0"),
+ PINCTRL_PIN(353, "PO TAP RET CLK"),
+ PINCTRL_PIN(354, "PI TAP CLK"),
+ PINCTRL_PIN(355, "PO EMIF 0 SD CS N"),
+ PINCTRL_PIN(356, "PO EMIF 0 SD CAS N"),
+ PINCTRL_PIN(357, "PO EMIF 0 SD WE N"),
+ PINCTRL_PIN(358, "P PAD VDDIO 1"),
+ PINCTRL_PIN(359, "P PAD VSSIO 1"),
+ PINCTRL_PIN(360, "P PAD GND 1"),
+ PINCTRL_PIN(361, "P PAD VDD 1"),
+ PINCTRL_PIN(362, "PO EMIF 0 SD CKE"),
+ PINCTRL_PIN(363, "PO EMIF 0 SD DQML"),
+ PINCTRL_PIN(364, "PO EMIF 0 SD DQMU"),
+ PINCTRL_PIN(365, "PO EMIF 0 SD RAS N"),
+ PINCTRL_PIN(366, "PIO EMIF 0 D15"),
+ PINCTRL_PIN(367, "PO EMIF 0 A15"),
+ PINCTRL_PIN(368, "PIO EMIF 0 D14"),
+ PINCTRL_PIN(369, "PO EMIF 0 A14"),
+ PINCTRL_PIN(370, "PIO EMIF 0 D13"),
+ PINCTRL_PIN(371, "PO EMIF 0 A13"),
+ PINCTRL_PIN(372, "P PAD VDDIO 2"),
+ PINCTRL_PIN(373, "P PAD VSSIO 2"),
+ PINCTRL_PIN(374, "P PAD GND 2"),
+ PINCTRL_PIN(375, "P PAD VDD 2"),
+ PINCTRL_PIN(376, "PIO EMIF 0 D12"),
+ PINCTRL_PIN(377, "PO EMIF 0 A12"),
+ PINCTRL_PIN(378, "PIO EMIF 0 D11"),
+ PINCTRL_PIN(379, "PO EMIF 0 A11"),
+ PINCTRL_PIN(380, "PIO EMIF 0 D10"),
+ PINCTRL_PIN(381, "PO EMIF 0 A10"),
+ PINCTRL_PIN(382, "PIO EMIF 0 D09"),
+ PINCTRL_PIN(383, "PO EMIF 0 A09"),
+ PINCTRL_PIN(384, "PIO EMIF 0 D08"),
+ PINCTRL_PIN(385, "PO EMIF 0 A08"),
+ PINCTRL_PIN(386, "PIO EMIF 0 D07"),
+ PINCTRL_PIN(387, "PO EMIF 0 A07"),
+ PINCTRL_PIN(388, "P PAD VDDIO 3"),
+ PINCTRL_PIN(389, "P PAD VSSIO 3"),
+ PINCTRL_PIN(390, "P PAD GND 3"),
+ PINCTRL_PIN(391, "P PAD VDD 3"),
+ PINCTRL_PIN(392, "PO EFUSE RDOUT1"),
+ PINCTRL_PIN(393, "PIO EMIF 0 D06"),
+ PINCTRL_PIN(394, "PO EMIF 0 A06"),
+ PINCTRL_PIN(395, "PIO EMIF 0 D05"),
+ PINCTRL_PIN(396, "PO EMIF 0 A05"),
+ PINCTRL_PIN(397, "PIO EMIF 0 D04"),
+ PINCTRL_PIN(398, "PO EMIF 0 A04"),
+ PINCTRL_PIN(399, "A PADS/A VDDCO1v82v5 GND 80U SF LIN VDDCO AF"),
+ PINCTRL_PIN(400, "PWR VDDCO AF"),
+ PINCTRL_PIN(401, "PWR EFUSE HV1"),
+ PINCTRL_PIN(402, "P PAD VSSIO 4"),
+ PINCTRL_PIN(403, "P PAD VDDIO 4"),
+ PINCTRL_PIN(404, "P PAD GND 4"),
+ PINCTRL_PIN(405, "P PAD VDD 4"),
+ PINCTRL_PIN(406, "PIO EMIF 0 D03"),
+ PINCTRL_PIN(407, "PO EMIF 0 A03"),
+ PINCTRL_PIN(408, "PWR EFUSE HV2"),
+ PINCTRL_PIN(409, "PWR EFUSE HV3"),
+ PINCTRL_PIN(410, "PIO EMIF 0 D02"),
+ PINCTRL_PIN(411, "PO EMIF 0 A02"),
+ PINCTRL_PIN(412, "PIO EMIF 0 D01"),
+ PINCTRL_PIN(413, "P PAD VDDIO 5"),
+ PINCTRL_PIN(414, "P PAD VSSIO 5"),
+ PINCTRL_PIN(415, "P PAD GND 5"),
+ PINCTRL_PIN(416, "P PAD VDD 5"),
+ PINCTRL_PIN(417, "PO EMIF 0 A01"),
+ PINCTRL_PIN(418, "PIO EMIF 0 D00"),
+ PINCTRL_PIN(419, "IF 0 SD CLK"),
+ PINCTRL_PIN(420, "APP SPI CLK"),
+ PINCTRL_PIN(421, "APP SPI DO"),
+ PINCTRL_PIN(422, "APP SPI DI"),
+ PINCTRL_PIN(423, "APP SPI CS0"),
+ PINCTRL_PIN(424, "APP SPI CS1"),
+ PINCTRL_PIN(425, "APP SPI CS2"),
+ PINCTRL_PIN(426, "PIO APP GPIO 10"),
+ PINCTRL_PIN(427, "P PAD VDDIO 41"),
+ PINCTRL_PIN(428, "P PAD VSSIO 41"),
+ PINCTRL_PIN(429, "P PAD GND 6"),
+ PINCTRL_PIN(430, "P PAD VDD 6"),
+ PINCTRL_PIN(431, "PIO ACC SDIO0 CMD"),
+ PINCTRL_PIN(432, "PIO ACC SDIO0 CK"),
+ PINCTRL_PIN(433, "PIO ACC SDIO0 D3"),
+ PINCTRL_PIN(434, "PIO ACC SDIO0 D2"),
+ PINCTRL_PIN(435, "PIO ACC SDIO0 D1"),
+ PINCTRL_PIN(436, "PIO ACC SDIO0 D0"),
+ PINCTRL_PIN(437, "PIO USB PU"),
+ PINCTRL_PIN(438, "PIO USB SP"),
+ PINCTRL_PIN(439, "PIO USB DAT VP"),
+ PINCTRL_PIN(440, "PIO USB SE0 VM"),
+ PINCTRL_PIN(441, "PIO USB OE"),
+ PINCTRL_PIN(442, "PIO USB SUSP"),
+ PINCTRL_PIN(443, "P PAD VSSIO 6"),
+ PINCTRL_PIN(444, "P PAD VDDIO 6"),
+ PINCTRL_PIN(445, "PIO USB PUEN"),
+ PINCTRL_PIN(446, "PIO ACC UART0 RX"),
+ PINCTRL_PIN(447, "PIO ACC UART0 TX"),
+ PINCTRL_PIN(448, "PIO ACC UART0 CTS"),
+ PINCTRL_PIN(449, "PIO ACC UART0 RTS"),
+ PINCTRL_PIN(450, "PIO ACC UART3 RX"),
+ PINCTRL_PIN(451, "PIO ACC UART3 TX"),
+ PINCTRL_PIN(452, "PIO ACC UART3 CTS"),
+ PINCTRL_PIN(453, "PIO ACC UART3 RTS"),
+ PINCTRL_PIN(454, "PIO ACC IRDA TX"),
+ PINCTRL_PIN(455, "P PAD VDDIO 7"),
+ PINCTRL_PIN(456, "P PAD VSSIO 7"),
+ PINCTRL_PIN(457, "P PAD GND 7"),
+ PINCTRL_PIN(458, "P PAD VDD 7"),
+ PINCTRL_PIN(459, "PIO ACC IRDA RX"),
+ PINCTRL_PIN(460, "PIO ACC PCM I2S CLK"),
+ PINCTRL_PIN(461, "PIO ACC PCM I2S WS"),
+ PINCTRL_PIN(462, "PIO ACC PCM I2S DATA A"),
+ PINCTRL_PIN(463, "PIO ACC PCM I2S DATA B"),
+ PINCTRL_PIN(464, "PO SIM CLK"),
+ PINCTRL_PIN(465, "PIO ACC IRDA SD"),
+ PINCTRL_PIN(466, "PIO SIM DATA"),
+};
+
+/**
+ * @dev: a pointer back to containing device
+ * @virtbase: the offset to the controller in virtual memory
+ */
+struct u300_pmx {
+ struct device *dev;
+ struct pinctrl_dev *pctl;
+ u32 phybase;
+ u32 physize;
+ void __iomem *virtbase;
+};
+
+/**
+ * u300_pmx_registers - the array of registers read/written for each pinmux
+ * shunt setting
+ */
+const u32 u300_pmx_registers[] = {
+ U300_SYSCON_PMC1LR,
+ U300_SYSCON_PMC1HR,
+ U300_SYSCON_PMC2R,
+ U300_SYSCON_PMC3R,
+ U300_SYSCON_PMC4R,
+};
+
+/**
+ * struct u300_pin_group - describes a U300 pin group
+ * @name: the name of this specific pin group
+ * @pins: an array of discrete physical pins used in this group, taken
+ * from the driver-local pin enumeration space
+ * @num_pins: the number of pins in this group array, i.e. the number of
+ * elements in .pins so we can iterate over that array
+ */
+struct u300_pin_group {
+ const char *name;
+ const unsigned int *pins;
+ const unsigned num_pins;
+};
+
+/**
+ * struct pmx_onmask - mask bits to enable/disable padmux
+ * @mask: mask bits to disable
+ * @val: mask bits to enable
+ *
+ * onmask lazy dog:
+ * onmask = {
+ * {"PMC1LR" mask, "PMC1LR" value},
+ * {"PMC1HR" mask, "PMC1HR" value},
+ * {"PMC2R" mask, "PMC2R" value},
+ * {"PMC3R" mask, "PMC3R" value},
+ * {"PMC4R" mask, "PMC4R" value}
+ * }
+ */
+struct u300_pmx_mask {
+ u16 mask;
+ u16 bits;
+};
+
+/* The chip power pins are VDD, GND, VDDIO and VSSIO */
+static const unsigned power_pins[] = { 0, 1, 3, 31, 46, 47, 49, 50, 61, 62, 63,
+ 64, 78, 79, 80, 81, 92, 93, 94, 95, 101, 102, 103, 104, 115, 116, 117,
+ 118, 130, 131, 132, 133, 145, 146, 147, 148, 159, 160, 172, 173, 174,
+ 175, 187, 188, 189, 190, 201, 202, 211, 212, 213, 214, 215, 218, 223,
+ 224, 225, 226, 231, 232, 237, 238, 239, 240, 245, 246, 251, 252, 256,
+ 257, 258, 259, 264, 265, 270, 271, 276, 277, 278, 279, 284, 285, 290,
+ 291, 295, 296, 299, 300, 301, 302, 303, 309, 310, 311, 312, 319, 320,
+ 321, 322, 329, 330, 331, 332, 341, 342, 343, 344, 358, 359, 360, 361,
+ 372, 373, 374, 375, 388, 389, 390, 391, 402, 403, 404, 405, 413, 414,
+ 415, 416, 427, 428, 429, 430, 443, 444, 455, 456, 457, 458 };
+static const unsigned emif0_pins[] = { 355, 356, 357, 362, 363, 364, 365, 366,
+ 367, 368, 369, 370, 371, 376, 377, 378, 379, 380, 381, 382, 383, 384,
+ 385, 386, 387, 393, 394, 395, 396, 397, 398, 406, 407, 410, 411, 412,
+ 417, 418 };
+static const unsigned emif1_pins[] = { 216, 217, 219, 220, 221, 222, 227, 228,
+ 229, 230, 233, 234, 235, 236, 241, 242, 243, 244, 247, 248, 249, 250,
+ 253, 254, 255, 260, 261, 262, 263, 266, 267, 268, 269, 272, 273, 274,
+ 275, 280, 281, 282, 283, 286, 287, 288, 289, 292, 293, 294, 297, 298,
+ 304, 305, 306, 307, 308, 313, 314, 315 };
+static const unsigned uart0_pins[] = { 134, 135, 136, 137 };
+static const unsigned mmc0_pins[] = { 166, 167, 168, 169, 170, 171, 176, 177 };
+static const unsigned spi0_pins[] = { 420, 421, 422, 423, 424, 425 };
+
+static const struct u300_pmx_mask emif0_mask[] = {
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+};
+
+static const struct u300_pmx_mask emif1_mask[] = {
+ /*
+ * This connects the SDRAM to CS2 and a NAND flash to
+ * CS0 on the EMIF.
+ */
+ {
+ U300_SYSCON_PMC1LR_EMIF_1_CS2_MASK |
+ U300_SYSCON_PMC1LR_EMIF_1_CS1_MASK |
+ U300_SYSCON_PMC1LR_EMIF_1_CS0_MASK |
+ U300_SYSCON_PMC1LR_EMIF_1_MASK,
+ U300_SYSCON_PMC1LR_EMIF_1_CS2_SDRAM |
+ U300_SYSCON_PMC1LR_EMIF_1_CS1_STATIC |
+ U300_SYSCON_PMC1LR_EMIF_1_CS0_NFIF |
+ U300_SYSCON_PMC1LR_EMIF_1_SDRAM0
+ },
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+};
+
+static const struct u300_pmx_mask uart0_mask[] = {
+ {0, 0},
+ {
+ U300_SYSCON_PMC1HR_APP_UART0_1_MASK |
+ U300_SYSCON_PMC1HR_APP_UART0_2_MASK,
+ U300_SYSCON_PMC1HR_APP_UART0_1_UART0 |
+ U300_SYSCON_PMC1HR_APP_UART0_2_UART0
+ },
+ {0, 0},
+ {0, 0},
+ {0, 0},
+};
+
+static const struct u300_pmx_mask mmc0_mask[] = {
+ { U300_SYSCON_PMC1LR_MMCSD_MASK, U300_SYSCON_PMC1LR_MMCSD_MMCSD},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ { U300_SYSCON_PMC4R_APP_MISC_12_MASK,
+ U300_SYSCON_PMC4R_APP_MISC_12_APP_GPIO }
+};
+
+static const struct u300_pmx_mask spi0_mask[] = {
+ {0, 0},
+ {
+ U300_SYSCON_PMC1HR_APP_SPI_2_MASK |
+ U300_SYSCON_PMC1HR_APP_SPI_CS_1_MASK |
+ U300_SYSCON_PMC1HR_APP_SPI_CS_2_MASK,
+ U300_SYSCON_PMC1HR_APP_SPI_2_SPI |
+ U300_SYSCON_PMC1HR_APP_SPI_CS_1_SPI |
+ U300_SYSCON_PMC1HR_APP_SPI_CS_2_SPI
+ },
+ {0, 0},
+ {0, 0},
+ {0, 0}
+};
+
+static const struct u300_pin_group u300_pin_groups[] = {
+ {
+ .name = "powergrp",
+ .pins = power_pins,
+ .num_pins = ARRAY_SIZE(power_pins),
+ },
+ {
+ .name = "emif0grp",
+ .pins = emif0_pins,
+ .num_pins = ARRAY_SIZE(emif0_pins),
+ },
+ {
+ .name = "emif1grp",
+ .pins = emif1_pins,
+ .num_pins = ARRAY_SIZE(emif1_pins),
+ },
+ {
+ .name = "uart0grp",
+ .pins = uart0_pins,
+ .num_pins = ARRAY_SIZE(uart0_pins),
+ },
+ {
+ .name = "mmc0grp",
+ .pins = mmc0_pins,
+ .num_pins = ARRAY_SIZE(mmc0_pins),
+ },
+ {
+ .name = "spi0grp",
+ .pins = spi0_pins,
+ .num_pins = ARRAY_SIZE(spi0_pins),
+ },
+};
+
+static int u300_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
+{
+ if (selector >= ARRAY_SIZE(u300_pin_groups))
+ return -EINVAL;
+ return 0;
+}
+
+static const char *u300_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ if (selector >= ARRAY_SIZE(u300_pin_groups))
+ return NULL;
+ return u300_pin_groups[selector].name;
+}
+
+static int u300_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+ const unsigned **pins,
+ unsigned *num_pins)
+{
+ if (selector >= ARRAY_SIZE(u300_pin_groups))
+ return -EINVAL;
+ *pins = u300_pin_groups[selector].pins;
+ *num_pins = u300_pin_groups[selector].num_pins;
+ return 0;
+}
+
+static void u300_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+ unsigned offset)
+{
+ seq_printf(s, " " DRIVER_NAME);
+}
+
+static struct pinctrl_ops u300_pctrl_ops = {
+ .list_groups = u300_list_groups,
+ .get_group_name = u300_get_group_name,
+ .get_group_pins = u300_get_group_pins,
+ .pin_dbg_show = u300_pin_dbg_show,
+};
+
+/*
+ * Here we define the available functions and their corresponding pin groups
+ */
+
+/**
+ * struct u300_pmx_func - describes U300 pinmux functions
+ * @name: the name of this specific function
+ * @groups: corresponding pin groups
+ * @onmask: bits to set to enable this when doing pin muxing
+ */
+struct u300_pmx_func {
+ const char *name;
+ const char * const *groups;
+ const unsigned num_groups;
+ const struct u300_pmx_mask *mask;
+};
+
+static const char * const powergrps[] = { "powergrp" };
+static const char * const emif0grps[] = { "emif0grp" };
+static const char * const emif1grps[] = { "emif1grp" };
+static const char * const uart0grps[] = { "uart0grp" };
+static const char * const mmc0grps[] = { "mmc0grp" };
+static const char * const spi0grps[] = { "spi0grp" };
+
+static const struct u300_pmx_func u300_pmx_functions[] = {
+ {
+ .name = "power",
+ .groups = powergrps,
+ .num_groups = ARRAY_SIZE(powergrps),
+ /* Mask is N/A */
+ },
+ {
+ .name = "emif0",
+ .groups = emif0grps,
+ .num_groups = ARRAY_SIZE(emif0grps),
+ .mask = emif0_mask,
+ },
+ {
+ .name = "emif1",
+ .groups = emif1grps,
+ .num_groups = ARRAY_SIZE(emif1grps),
+ .mask = emif1_mask,
+ },
+ {
+ .name = "uart0",
+ .groups = uart0grps,
+ .num_groups = ARRAY_SIZE(uart0grps),
+ .mask = uart0_mask,
+ },
+ {
+ .name = "mmc0",
+ .groups = mmc0grps,
+ .num_groups = ARRAY_SIZE(mmc0grps),
+ .mask = mmc0_mask,
+ },
+ {
+ .name = "spi0",
+ .groups = spi0grps,
+ .num_groups = ARRAY_SIZE(spi0grps),
+ .mask = spi0_mask,
+ },
+};
+
+static void u300_pmx_endisable(struct u300_pmx *upmx, unsigned selector,
+ bool enable)
+{
+ u16 regval, val, mask;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(u300_pmx_registers); i++) {
+ if (enable)
+ val = u300_pmx_functions[selector].mask->bits;
+ else
+ val = 0;
+
+ mask = u300_pmx_functions[selector].mask->mask;
+ if (mask != 0) {
+ regval = readw(upmx->virtbase + u300_pmx_registers[i]);
+ regval &= ~mask;
+ regval |= val;
+ writew(regval, upmx->virtbase + u300_pmx_registers[i]);
+ }
+ }
+}
+
+static int u300_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector,
+ unsigned group)
+{
+ struct u300_pmx *upmx;
+
+ /* There is nothing to do with the power pins */
+ if (selector == 0)
+ return 0;
+
+ upmx = pinctrl_dev_get_drvdata(pctldev);
+ u300_pmx_endisable(upmx, selector, true);
+
+ return 0;
+}
+
+static void u300_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector,
+ unsigned group)
+{
+ struct u300_pmx *upmx;
+
+ /* There is nothing to do with the power pins */
+ if (selector == 0)
+ return;
+
+ upmx = pinctrl_dev_get_drvdata(pctldev);
+ u300_pmx_endisable(upmx, selector, false);
+}
+
+static int u300_pmx_list_funcs(struct pinctrl_dev *pctldev, unsigned selector)
+{
+ if (selector >= ARRAY_SIZE(u300_pmx_functions))
+ return -EINVAL;
+ return 0;
+}
+
+static const char *u300_pmx_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ return u300_pmx_functions[selector].name;
+}
+
+static int u300_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ *groups = u300_pmx_functions[selector].groups;
+ *num_groups = u300_pmx_functions[selector].num_groups;
+ return 0;
+}
+
+static struct pinmux_ops u300_pmx_ops = {
+ .list_functions = u300_pmx_list_funcs,
+ .get_function_name = u300_pmx_get_func_name,
+ .get_function_groups = u300_pmx_get_groups,
+ .enable = u300_pmx_enable,
+ .disable = u300_pmx_disable,
+};
+
+/*
+ * FIXME: this will be set to sane values as this driver engulfs
+ * drivers/gpio/gpio-u300.c and we really know this stuff.
+ */
+static struct pinctrl_gpio_range u300_gpio_range = {
+ .name = "COH901*",
+ .id = 0,
+ .base = 0,
+ .npins = 64,
+};
+
+static struct pinctrl_desc u300_pmx_desc = {
+ .name = DRIVER_NAME,
+ .pins = u300_pads,
+ .npins = ARRAY_SIZE(u300_pads),
+ .maxpin = U300_NUM_PADS-1,
+ .pctlops = &u300_pctrl_ops,
+ .pmxops = &u300_pmx_ops,
+ .owner = THIS_MODULE,
+};
+
+static int __init u300_pmx_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct u300_pmx *upmx;
+ struct resource *res;
+
+ /* Create state holders etc for this driver */
+ upmx = devm_kzalloc(&pdev->dev, sizeof(*upmx), GFP_KERNEL);
+ if (!upmx)
+ return -ENOMEM;
+
+ upmx->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENOENT;
+ goto out_no_resource;
+ }
+ upmx->phybase = res->start;
+ upmx->physize = resource_size(res);
+
+ if (request_mem_region(upmx->phybase, upmx->physize,
+ DRIVER_NAME) == NULL) {
+ ret = -ENOMEM;
+ goto out_no_memregion;
+ }
+
+ upmx->virtbase = ioremap(upmx->phybase, upmx->physize);
+ if (!upmx->virtbase) {
+ ret = -ENOMEM;
+ goto out_no_remap;
+ }
+
+ upmx->pctl = pinctrl_register(&u300_pmx_desc, &pdev->dev, upmx);
+ if (!upmx->pctl) {
+ dev_err(&pdev->dev, "could not register U300 pinmux driver\n");
+ ret = -EINVAL;
+ goto out_no_pmx;
+ }
+
+ /* We will handle a range of GPIO pins */
+ pinctrl_add_gpio_range(upmx->pctl, &u300_gpio_range);
+
+ platform_set_drvdata(pdev, upmx);
+
+ dev_info(&pdev->dev, "initialized U300 pinmux driver\n");
+
+ return 0;
+
+out_no_pmx:
+ iounmap(upmx->virtbase);
+out_no_remap:
+ platform_set_drvdata(pdev, NULL);
+out_no_memregion:
+ release_mem_region(upmx->phybase, upmx->physize);
+out_no_resource:
+ devm_kfree(&pdev->dev, upmx);
+ return ret;
+}
+
+static int __exit u300_pmx_remove(struct platform_device *pdev)
+{
+ struct u300_pmx *upmx = platform_get_drvdata(pdev);
+
+ pinctrl_remove_gpio_range(upmx->pctl, &u300_gpio_range);
+ pinctrl_unregister(upmx->pctl);
+ iounmap(upmx->virtbase);
+ release_mem_region(upmx->phybase, upmx->physize);
+ platform_set_drvdata(pdev, NULL);
+ devm_kfree(&pdev->dev, upmx);
+
+ return 0;
+}
+
+static struct platform_driver u300_pmx_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(u300_pmx_remove),
+};
+
+static int __init u300_pmx_init(void)
+{
+ return platform_driver_probe(&u300_pmx_driver, u300_pmx_probe);
+}
+arch_initcall(u300_pmx_init);
+
+static void __exit u300_pmx_exit(void)
+{
+ platform_driver_unregister(&u300_pmx_driver);
+}
+module_exit(u300_pmx_exit);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
+MODULE_DESCRIPTION("U300 pin control driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
new file mode 100644
index 000000000000..a5467f8709e9
--- /dev/null
+++ b/drivers/pinctrl/pinmux.c
@@ -0,0 +1,1190 @@
+/*
+ * Core driver for the pin muxing portions of the pin control subsystem
+ *
+ * Copyright (C) 2011 ST-Ericsson SA
+ * Written on behalf of Linaro for ST-Ericsson
+ * Based on bits of regulator core, gpio core and clk core
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#define pr_fmt(fmt) "pinmux core: " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/radix-tree.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/sysfs.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinmux.h>
+#include "core.h"
+
+/* List of pinmuxes */
+static DEFINE_MUTEX(pinmux_list_mutex);
+static LIST_HEAD(pinmux_list);
+
+/* List of pinmux hogs */
+static DEFINE_MUTEX(pinmux_hoglist_mutex);
+static LIST_HEAD(pinmux_hoglist);
+
+/* Global pinmux maps, we allow one set only */
+static struct pinmux_map const *pinmux_maps;
+static unsigned pinmux_maps_num;
+
+/**
+ * struct pinmux_group - group list item for pinmux groups
+ * @node: pinmux group list node
+ * @group_selector: the group selector for this group
+ */
+struct pinmux_group {
+ struct list_head node;
+ unsigned group_selector;
+};
+
+/**
+ * struct pinmux - per-device pinmux state holder
+ * @node: global list node
+ * @dev: the device using this pinmux
+ * @usecount: the number of active users of this mux setting, used to keep
+ * track of nested use cases
+ * @pins: an array of discrete physical pins used in this mapping, taken
+ * from the global pin enumeration space (copied from pinmux map)
+ * @num_pins: the number of pins in this mapping array, i.e. the number of
+ * elements in .pins so we can iterate over that array (copied from
+ * pinmux map)
+ * @pctldev: pin control device handling this pinmux
+ * @func_selector: the function selector for the pinmux device handling
+ * this pinmux
+ * @groups: the group selectors for the pinmux device and
+ * selector combination handling this pinmux, this is a list that
+ * will be traversed on all pinmux operations such as
+ * get/put/enable/disable
+ * @mutex: a lock for the pinmux state holder
+ */
+struct pinmux {
+ struct list_head node;
+ struct device *dev;
+ unsigned usecount;
+ struct pinctrl_dev *pctldev;
+ unsigned func_selector;
+ struct list_head groups;
+ struct mutex mutex;
+};
+
+/**
+ * struct pinmux_hog - a list item to stash mux hogs
+ * @node: pinmux hog list node
+ * @map: map entry responsible for this hogging
+ * @pmx: the pinmux hogged by this item
+ */
+struct pinmux_hog {
+ struct list_head node;
+ struct pinmux_map const *map;
+ struct pinmux *pmx;
+};
+
+/**
+ * pin_request() - request a single pin to be muxed in, typically for GPIO
+ * @pin: the pin number in the global pin space
+ * @function: a functional name to give to this pin, passed to the driver
+ * so it knows what function to mux in, e.g. the string "gpioNN"
+ * means that you want to mux in the pin for use as GPIO number NN
+ * @gpio: if this request concerns a single GPIO pin
+ * @gpio_range: the range matching the GPIO pin if this is a request for a
+ * single GPIO pin
+ */
+static int pin_request(struct pinctrl_dev *pctldev,
+ int pin, const char *function, bool gpio,
+ struct pinctrl_gpio_range *gpio_range)
+{
+ struct pin_desc *desc;
+ const struct pinmux_ops *ops = pctldev->desc->pmxops;
+ int status = -EINVAL;
+
+ dev_dbg(&pctldev->dev, "request pin %d for %s\n", pin, function);
+
+ if (!pin_is_valid(pctldev, pin)) {
+ dev_err(&pctldev->dev, "pin is invalid\n");
+ return -EINVAL;
+ }
+
+ if (!function) {
+ dev_err(&pctldev->dev, "no function name given\n");
+ return -EINVAL;
+ }
+
+ desc = pin_desc_get(pctldev, pin);
+ if (desc == NULL) {
+ dev_err(&pctldev->dev,
+ "pin is not registered so it cannot be requested\n");
+ goto out;
+ }
+
+ spin_lock(&desc->lock);
+ if (desc->mux_function) {
+ spin_unlock(&desc->lock);
+ dev_err(&pctldev->dev,
+ "pin already requested\n");
+ goto out;
+ }
+ desc->mux_function = function;
+ spin_unlock(&desc->lock);
+
+ /* Let each pin increase references to this module */
+ if (!try_module_get(pctldev->owner)) {
+ dev_err(&pctldev->dev,
+ "could not increase module refcount for pin %d\n",
+ pin);
+ status = -EINVAL;
+ goto out_free_pin;
+ }
+
+ /*
+ * If there is no kind of request function for the pin we just assume
+ * we got it by default and proceed.
+ */
+ if (gpio && ops->gpio_request_enable)
+ /* This requests and enables a single GPIO pin */
+ status = ops->gpio_request_enable(pctldev, gpio_range, pin);
+ else if (ops->request)
+ status = ops->request(pctldev, pin);
+ else
+ status = 0;
+
+ if (status)
+ dev_err(&pctldev->dev, "->request on device %s failed "
+ "for pin %d\n",
+ pctldev->desc->name, pin);
+out_free_pin:
+ if (status) {
+ spin_lock(&desc->lock);
+ desc->mux_function = NULL;
+ spin_unlock(&desc->lock);
+ }
+out:
+ if (status)
+ dev_err(&pctldev->dev, "pin-%d (%s) status %d\n",
+ pin, function ? : "?", status);
+
+ return status;
+}
+
+/**
+ * pin_free() - release a single muxed in pin so something else can be muxed
+ * @pctldev: pin controller device handling this pin
+ * @pin: the pin to free
+ * @free_func: whether to free the pin's assigned function name string
+ */
+static void pin_free(struct pinctrl_dev *pctldev, int pin, int free_func)
+{
+ const struct pinmux_ops *ops = pctldev->desc->pmxops;
+ struct pin_desc *desc;
+
+ desc = pin_desc_get(pctldev, pin);
+ if (desc == NULL) {
+ dev_err(&pctldev->dev,
+ "pin is not registered so it cannot be freed\n");
+ return;
+ }
+
+ if (ops->free)
+ ops->free(pctldev, pin);
+
+ spin_lock(&desc->lock);
+ if (free_func)
+ kfree(desc->mux_function);
+ desc->mux_function = NULL;
+ spin_unlock(&desc->lock);
+ module_put(pctldev->owner);
+}
+
+/**
+ * pinmux_request_gpio() - request a single pin to be muxed in as GPIO
+ * @gpio: the GPIO pin number from the GPIO subsystem number space
+ */
+int pinmux_request_gpio(unsigned gpio)
+{
+ char gpiostr[16];
+ const char *function;
+ struct pinctrl_dev *pctldev;
+ struct pinctrl_gpio_range *range;
+ int ret;
+ int pin;
+
+ ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
+ if (ret)
+ return -EINVAL;
+
+ /* Convert to the pin controllers number space */
+ pin = gpio - range->base;
+
+ /* Conjure some name stating what chip and pin this is taken by */
+ snprintf(gpiostr, 15, "%s:%d", range->name, gpio);
+
+ function = kstrdup(gpiostr, GFP_KERNEL);
+ if (!function)
+ return -EINVAL;
+
+ ret = pin_request(pctldev, pin, function, true, range);
+ if (ret < 0)
+ kfree(function);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pinmux_request_gpio);
+
+/**
+ * pinmux_free_gpio() - free a single pin, currently used as GPIO
+ * @gpio: the GPIO pin number from the GPIO subsystem number space
+ */
+void pinmux_free_gpio(unsigned gpio)
+{
+ struct pinctrl_dev *pctldev;
+ struct pinctrl_gpio_range *range;
+ int ret;
+ int pin;
+
+ ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
+ if (ret)
+ return;
+
+ /* Convert to the pin controllers number space */
+ pin = gpio - range->base;
+
+ pin_free(pctldev, pin, true);
+}
+EXPORT_SYMBOL_GPL(pinmux_free_gpio);
+
+/**
+ * pinmux_register_mappings() - register a set of pinmux mappings
+ * @maps: the pinmux mappings table to register
+ * @num_maps: the number of maps in the mapping table
+ *
+ * Only call this once during initialization of your machine, the function is
+ * tagged as __init and won't be callable after init has completed. The map
+ * passed into this function will be owned by the pinmux core and cannot be
+ * free:d.
+ */
+int __init pinmux_register_mappings(struct pinmux_map const *maps,
+ unsigned num_maps)
+{
+ int i;
+
+ if (pinmux_maps != NULL) {
+ pr_err("pinmux mappings already registered, you can only "
+ "register one set of maps\n");
+ return -EINVAL;
+ }
+
+ pr_debug("add %d pinmux maps\n", num_maps);
+ for (i = 0; i < num_maps; i++) {
+ /* Sanity check the mapping */
+ if (!maps[i].name) {
+ pr_err("failed to register map %d: "
+ "no map name given\n", i);
+ return -EINVAL;
+ }
+ if (!maps[i].ctrl_dev && !maps[i].ctrl_dev_name) {
+ pr_err("failed to register map %s (%d): "
+ "no pin control device given\n",
+ maps[i].name, i);
+ return -EINVAL;
+ }
+ if (!maps[i].function) {
+ pr_err("failed to register map %s (%d): "
+ "no function ID given\n", maps[i].name, i);
+ return -EINVAL;
+ }
+
+ if (!maps[i].dev && !maps[i].dev_name)
+ pr_debug("add system map %s function %s with no device\n",
+ maps[i].name,
+ maps[i].function);
+ else
+ pr_debug("register map %s, function %s\n",
+ maps[i].name,
+ maps[i].function);
+ }
+
+ pinmux_maps = maps;
+ pinmux_maps_num = num_maps;
+
+ return 0;
+}
+
+/**
+ * acquire_pins() - acquire all the pins for a certain funcion on a pinmux
+ * @pctldev: the device to take the pins on
+ * @func_selector: the function selector to acquire the pins for
+ * @group_selector: the group selector containing the pins to acquire
+ */
+static int acquire_pins(struct pinctrl_dev *pctldev,
+ unsigned func_selector,
+ unsigned group_selector)
+{
+ const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
+ const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
+ const char *func = pmxops->get_function_name(pctldev,
+ func_selector);
+ const unsigned *pins;
+ unsigned num_pins;
+ int ret;
+ int i;
+
+ ret = pctlops->get_group_pins(pctldev, group_selector,
+ &pins, &num_pins);
+ if (ret)
+ return ret;
+
+ dev_dbg(&pctldev->dev, "requesting the %u pins from group %u\n",
+ num_pins, group_selector);
+
+ /* Try to allocate all pins in this group, one by one */
+ for (i = 0; i < num_pins; i++) {
+ ret = pin_request(pctldev, pins[i], func, false, NULL);
+ if (ret) {
+ dev_err(&pctldev->dev,
+ "could not get pin %d for function %s "
+ "on device %s - conflicting mux mappings?\n",
+ pins[i], func ? : "(undefined)",
+ pinctrl_dev_get_name(pctldev));
+ /* On error release all taken pins */
+ i--; /* this pin just failed */
+ for (; i >= 0; i--)
+ pin_free(pctldev, pins[i], false);
+ return -ENODEV;
+ }
+ }
+ return 0;
+}
+
+/**
+ * release_pins() - release pins taken by earlier acquirement
+ * @pctldev: the device to free the pinx on
+ * @group_selector: the group selector containing the pins to free
+ */
+static void release_pins(struct pinctrl_dev *pctldev,
+ unsigned group_selector)
+{
+ const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
+ const unsigned *pins;
+ unsigned num_pins;
+ int ret;
+ int i;
+
+ ret = pctlops->get_group_pins(pctldev, group_selector,
+ &pins, &num_pins);
+ if (ret) {
+ dev_err(&pctldev->dev, "could not get pins to release for "
+ "group selector %d\n",
+ group_selector);
+ return;
+ }
+ for (i = 0; i < num_pins; i++)
+ pin_free(pctldev, pins[i], false);
+}
+
+/**
+ * pinmux_get_group_selector() - returns the group selector for a group
+ * @pctldev: the pin controller handling the group
+ * @pin_group: the pin group to look up
+ */
+static int pinmux_get_group_selector(struct pinctrl_dev *pctldev,
+ const char *pin_group)
+{
+ const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
+ unsigned group_selector = 0;
+
+ while (pctlops->list_groups(pctldev, group_selector) >= 0) {
+ const char *gname = pctlops->get_group_name(pctldev,
+ group_selector);
+ if (!strcmp(gname, pin_group)) {
+ dev_dbg(&pctldev->dev,
+ "found group selector %u for %s\n",
+ group_selector,
+ pin_group);
+ return group_selector;
+ }
+
+ group_selector++;
+ }
+
+ dev_err(&pctldev->dev, "does not have pin group %s\n",
+ pin_group);
+
+ return -EINVAL;
+}
+
+/**
+ * pinmux_check_pin_group() - check function and pin group combo
+ * @pctldev: device to check the pin group vs function for
+ * @func_selector: the function selector to check the pin group for, we have
+ * already looked this up in the calling function
+ * @pin_group: the pin group to match to the function
+ *
+ * This function will check that the pinmux driver can supply the
+ * selected pin group for a certain function, returns the group selector if
+ * the group and function selector will work fine together, else returns
+ * negative
+ */
+static int pinmux_check_pin_group(struct pinctrl_dev *pctldev,
+ unsigned func_selector,
+ const char *pin_group)
+{
+ const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
+ const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
+ int ret;
+
+ /*
+ * If the driver does not support different pin groups for the
+ * functions, we only support group 0, and assume this exists.
+ */
+ if (!pctlops || !pctlops->list_groups)
+ return 0;
+
+ /*
+ * Passing NULL (no specific group) will select the first and
+ * hopefully only group of pins available for this function.
+ */
+ if (!pin_group) {
+ char const * const *groups;
+ unsigned num_groups;
+
+ ret = pmxops->get_function_groups(pctldev, func_selector,
+ &groups, &num_groups);
+ if (ret)
+ return ret;
+ if (num_groups < 1)
+ return -EINVAL;
+ ret = pinmux_get_group_selector(pctldev, groups[0]);
+ if (ret < 0) {
+ dev_err(&pctldev->dev,
+ "function %s wants group %s but the pin "
+ "controller does not seem to have that group\n",
+ pmxops->get_function_name(pctldev, func_selector),
+ groups[0]);
+ return ret;
+ }
+
+ if (num_groups > 1)
+ dev_dbg(&pctldev->dev,
+ "function %s support more than one group, "
+ "default-selecting first group %s (%d)\n",
+ pmxops->get_function_name(pctldev, func_selector),
+ groups[0],
+ ret);
+
+ return ret;
+ }
+
+ dev_dbg(&pctldev->dev,
+ "check if we have pin group %s on controller %s\n",
+ pin_group, pinctrl_dev_get_name(pctldev));
+
+ ret = pinmux_get_group_selector(pctldev, pin_group);
+ if (ret < 0) {
+ dev_dbg(&pctldev->dev,
+ "%s does not support pin group %s with function %s\n",
+ pinctrl_dev_get_name(pctldev),
+ pin_group,
+ pmxops->get_function_name(pctldev, func_selector));
+ }
+ return ret;
+}
+
+/**
+ * pinmux_search_function() - check pin control driver for a certain function
+ * @pctldev: device to check for function and position
+ * @map: function map containing the function and position to look for
+ * @func_selector: returns the applicable function selector if found
+ * @group_selector: returns the applicable group selector if found
+ *
+ * This will search the pinmux driver for an applicable
+ * function with a specific pin group, returns 0 if these can be mapped
+ * negative otherwise
+ */
+static int pinmux_search_function(struct pinctrl_dev *pctldev,
+ struct pinmux_map const *map,
+ unsigned *func_selector,
+ unsigned *group_selector)
+{
+ const struct pinmux_ops *ops = pctldev->desc->pmxops;
+ unsigned selector = 0;
+
+ /* See if this pctldev has this function */
+ while (ops->list_functions(pctldev, selector) >= 0) {
+ const char *fname = ops->get_function_name(pctldev,
+ selector);
+ int ret;
+
+ if (!strcmp(map->function, fname)) {
+ /* Found the function, check pin group */
+ ret = pinmux_check_pin_group(pctldev, selector,
+ map->group);
+ if (ret < 0)
+ return ret;
+
+ /* This function and group selector can be used */
+ *func_selector = selector;
+ *group_selector = ret;
+ return 0;
+
+ }
+ selector++;
+ }
+
+ pr_err("%s does not support function %s\n",
+ pinctrl_dev_get_name(pctldev), map->function);
+ return -EINVAL;
+}
+
+/**
+ * pinmux_enable_muxmap() - enable a map entry for a certain pinmux
+ */
+static int pinmux_enable_muxmap(struct pinctrl_dev *pctldev,
+ struct pinmux *pmx,
+ struct device *dev,
+ const char *devname,
+ struct pinmux_map const *map)
+{
+ unsigned func_selector;
+ unsigned group_selector;
+ struct pinmux_group *grp;
+ int ret;
+
+ /*
+ * Note that we're not locking the pinmux mutex here, because
+ * this is only called at pinmux initialization time when it
+ * has not been added to any list and thus is not reachable
+ * by anyone else.
+ */
+
+ if (pmx->pctldev && pmx->pctldev != pctldev) {
+ dev_err(&pctldev->dev,
+ "different pin control devices given for device %s, "
+ "function %s\n",
+ devname,
+ map->function);
+ return -EINVAL;
+ }
+ pmx->dev = dev;
+ pmx->pctldev = pctldev;
+
+ /* Now go into the driver and try to match a function and group */
+ ret = pinmux_search_function(pctldev, map, &func_selector,
+ &group_selector);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * If the function selector is already set, it needs to be identical,
+ * we support several groups with one function but not several
+ * functions with one or several groups in the same pinmux.
+ */
+ if (pmx->func_selector != UINT_MAX &&
+ pmx->func_selector != func_selector) {
+ dev_err(&pctldev->dev,
+ "dual function defines in the map for device %s\n",
+ devname);
+ return -EINVAL;
+ }
+ pmx->func_selector = func_selector;
+
+ /* Now add this group selector, we may have many of them */
+ grp = kmalloc(sizeof(struct pinmux_group), GFP_KERNEL);
+ if (!grp)
+ return -ENOMEM;
+ grp->group_selector = group_selector;
+ ret = acquire_pins(pctldev, func_selector, group_selector);
+ if (ret) {
+ kfree(grp);
+ return ret;
+ }
+ list_add(&grp->node, &pmx->groups);
+
+ return 0;
+}
+
+static void pinmux_free_groups(struct pinmux *pmx)
+{
+ struct list_head *node, *tmp;
+
+ list_for_each_safe(node, tmp, &pmx->groups) {
+ struct pinmux_group *grp =
+ list_entry(node, struct pinmux_group, node);
+ /* Release all pins taken by this group */
+ release_pins(pmx->pctldev, grp->group_selector);
+ list_del(node);
+ kfree(grp);
+ }
+}
+
+/**
+ * pinmux_get() - retrieves the pinmux for a certain device
+ * @dev: the device to get the pinmux for
+ * @name: an optional specific mux mapping name or NULL, the name is only
+ * needed if you want to have more than one mapping per device, or if you
+ * need an anonymous pinmux (not tied to any specific device)
+ */
+struct pinmux *pinmux_get(struct device *dev, const char *name)
+{
+
+ struct pinmux_map const *map = NULL;
+ struct pinctrl_dev *pctldev = NULL;
+ const char *devname = NULL;
+ struct pinmux *pmx;
+ bool found_map;
+ unsigned num_maps = 0;
+ int ret = -ENODEV;
+ int i;
+
+ /* We must have dev or ID or both */
+ if (!dev && !name)
+ return ERR_PTR(-EINVAL);
+
+ if (dev)
+ devname = dev_name(dev);
+
+ pr_debug("get mux %s for device %s\n", name,
+ devname ? devname : "(none)");
+
+ /*
+ * create the state cookie holder struct pinmux for each
+ * mapping, this is what consumers will get when requesting
+ * a pinmux handle with pinmux_get()
+ */
+ pmx = kzalloc(sizeof(struct pinmux), GFP_KERNEL);
+ if (pmx == NULL)
+ return ERR_PTR(-ENOMEM);
+ mutex_init(&pmx->mutex);
+ pmx->func_selector = UINT_MAX;
+ INIT_LIST_HEAD(&pmx->groups);
+
+ /* Iterate over the pinmux maps to locate the right ones */
+ for (i = 0; i < pinmux_maps_num; i++) {
+ map = &pinmux_maps[i];
+ found_map = false;
+
+ /*
+ * First, try to find the pctldev given in the map
+ */
+ pctldev = get_pinctrl_dev_from_dev(map->ctrl_dev,
+ map->ctrl_dev_name);
+ if (!pctldev) {
+ const char *devname = NULL;
+
+ if (map->ctrl_dev)
+ devname = dev_name(map->ctrl_dev);
+ else if (map->ctrl_dev_name)
+ devname = map->ctrl_dev_name;
+
+ pr_warning("could not find a pinctrl device for pinmux "
+ "function %s, fishy, they shall all have one\n",
+ map->function);
+ pr_warning("given pinctrl device name: %s",
+ devname ? devname : "UNDEFINED");
+
+ /* Continue to check the other mappings anyway... */
+ continue;
+ }
+
+ pr_debug("in map, found pctldev %s to handle function %s",
+ dev_name(&pctldev->dev), map->function);
+
+
+ /*
+ * If we're looking for a specific named map, this must match,
+ * else we loop and look for the next.
+ */
+ if (name != NULL) {
+ if (map->name == NULL)
+ continue;
+ if (strcmp(map->name, name))
+ continue;
+ }
+
+ /*
+ * This is for the case where no device name is given, we
+ * already know that the function name matches from above
+ * code.
+ */
+ if (!map->dev_name && (name != NULL))
+ found_map = true;
+
+ /* If the mapping has a device set up it must match */
+ if (map->dev_name &&
+ (!devname || !strcmp(map->dev_name, devname)))
+ /* MATCH! */
+ found_map = true;
+
+ /* If this map is applicable, then apply it */
+ if (found_map) {
+ ret = pinmux_enable_muxmap(pctldev, pmx, dev,
+ devname, map);
+ if (ret) {
+ pinmux_free_groups(pmx);
+ kfree(pmx);
+ return ERR_PTR(ret);
+ }
+ num_maps++;
+ }
+ }
+
+
+ /* We should have atleast one map, right */
+ if (!num_maps) {
+ pr_err("could not find any mux maps for device %s, ID %s\n",
+ devname ? devname : "(anonymous)",
+ name ? name : "(undefined)");
+ kfree(pmx);
+ return ERR_PTR(-EINVAL);
+ }
+
+ pr_debug("found %u mux maps for device %s, UD %s\n",
+ num_maps,
+ devname ? devname : "(anonymous)",
+ name ? name : "(undefined)");
+
+ /* Add the pinmux to the global list */
+ mutex_lock(&pinmux_list_mutex);
+ list_add(&pmx->node, &pinmux_list);
+ mutex_unlock(&pinmux_list_mutex);
+
+ return pmx;
+}
+EXPORT_SYMBOL_GPL(pinmux_get);
+
+/**
+ * pinmux_put() - release a previously claimed pinmux
+ * @pmx: a pinmux previously claimed by pinmux_get()
+ */
+void pinmux_put(struct pinmux *pmx)
+{
+ if (pmx == NULL)
+ return;
+
+ mutex_lock(&pmx->mutex);
+ if (pmx->usecount)
+ pr_warn("releasing pinmux with active users!\n");
+ /* Free the groups and all acquired pins */
+ pinmux_free_groups(pmx);
+ mutex_unlock(&pmx->mutex);
+
+ /* Remove from list */
+ mutex_lock(&pinmux_list_mutex);
+ list_del(&pmx->node);
+ mutex_unlock(&pinmux_list_mutex);
+
+ kfree(pmx);
+}
+EXPORT_SYMBOL_GPL(pinmux_put);
+
+/**
+ * pinmux_enable() - enable a certain pinmux setting
+ * @pmx: the pinmux to enable, previously claimed by pinmux_get()
+ */
+int pinmux_enable(struct pinmux *pmx)
+{
+ int ret = 0;
+
+ if (pmx == NULL)
+ return -EINVAL;
+ mutex_lock(&pmx->mutex);
+ if (pmx->usecount++ == 0) {
+ struct pinctrl_dev *pctldev = pmx->pctldev;
+ const struct pinmux_ops *ops = pctldev->desc->pmxops;
+ struct pinmux_group *grp;
+
+ list_for_each_entry(grp, &pmx->groups, node) {
+ ret = ops->enable(pctldev, pmx->func_selector,
+ grp->group_selector);
+ if (ret) {
+ /*
+ * TODO: call disable() on all groups we called
+ * enable() on to this point?
+ */
+ pmx->usecount--;
+ break;
+ }
+ }
+ }
+ mutex_unlock(&pmx->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pinmux_enable);
+
+/**
+ * pinmux_disable() - disable a certain pinmux setting
+ * @pmx: the pinmux to disable, previously claimed by pinmux_get()
+ */
+void pinmux_disable(struct pinmux *pmx)
+{
+ if (pmx == NULL)
+ return;
+
+ mutex_lock(&pmx->mutex);
+ if (--pmx->usecount == 0) {
+ struct pinctrl_dev *pctldev = pmx->pctldev;
+ const struct pinmux_ops *ops = pctldev->desc->pmxops;
+ struct pinmux_group *grp;
+
+ list_for_each_entry(grp, &pmx->groups, node) {
+ ops->disable(pctldev, pmx->func_selector,
+ grp->group_selector);
+ }
+ }
+ mutex_unlock(&pmx->mutex);
+}
+EXPORT_SYMBOL_GPL(pinmux_disable);
+
+int pinmux_check_ops(const struct pinmux_ops *ops)
+{
+ /* Check that we implement required operations */
+ if (!ops->list_functions ||
+ !ops->get_function_name ||
+ !ops->get_function_groups ||
+ !ops->enable ||
+ !ops->disable)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* Hog a single map entry and add to the hoglist */
+static int pinmux_hog_map(struct pinctrl_dev *pctldev,
+ struct pinmux_map const *map)
+{
+ struct pinmux_hog *hog;
+ struct pinmux *pmx;
+ int ret;
+
+ if (map->dev || map->dev_name) {
+ /*
+ * TODO: the day we have device tree support, we can
+ * traverse the device tree and hog to specific device nodes
+ * without any problems, so then we can hog pinmuxes for
+ * all devices that just want a static pin mux at this point.
+ */
+ dev_err(&pctldev->dev, "map %s wants to hog a non-system "
+ "pinmux, this is not going to work\n", map->name);
+ return -EINVAL;
+ }
+
+ hog = kzalloc(sizeof(struct pinmux_hog), GFP_KERNEL);
+ if (!hog)
+ return -ENOMEM;
+
+ pmx = pinmux_get(NULL, map->name);
+ if (IS_ERR(pmx)) {
+ kfree(hog);
+ dev_err(&pctldev->dev,
+ "could not get the %s pinmux mapping for hogging\n",
+ map->name);
+ return PTR_ERR(pmx);
+ }
+
+ ret = pinmux_enable(pmx);
+ if (ret) {
+ pinmux_put(pmx);
+ kfree(hog);
+ dev_err(&pctldev->dev,
+ "could not enable the %s pinmux mapping for hogging\n",
+ map->name);
+ return ret;
+ }
+
+ hog->map = map;
+ hog->pmx = pmx;
+
+ dev_info(&pctldev->dev, "hogged map %s, function %s\n", map->name,
+ map->function);
+ mutex_lock(&pctldev->pinmux_hogs_lock);
+ list_add(&hog->node, &pctldev->pinmux_hogs);
+ mutex_unlock(&pctldev->pinmux_hogs_lock);
+
+ return 0;
+}
+
+/**
+ * pinmux_hog_maps() - hog specific map entries on controller device
+ * @pctldev: the pin control device to hog entries on
+ *
+ * When the pin controllers are registered, there may be some specific pinmux
+ * map entries that need to be hogged, i.e. get+enabled until the system shuts
+ * down.
+ */
+int pinmux_hog_maps(struct pinctrl_dev *pctldev)
+{
+ struct device *dev = &pctldev->dev;
+ const char *devname = dev_name(dev);
+ int ret;
+ int i;
+
+ INIT_LIST_HEAD(&pctldev->pinmux_hogs);
+ mutex_init(&pctldev->pinmux_hogs_lock);
+
+ for (i = 0; i < pinmux_maps_num; i++) {
+ struct pinmux_map const *map = &pinmux_maps[i];
+
+ if (((map->ctrl_dev == dev) ||
+ !strcmp(map->ctrl_dev_name, devname)) &&
+ map->hog_on_boot) {
+ /* OK time to hog! */
+ ret = pinmux_hog_map(pctldev, map);
+ if (ret)
+ return ret;
+ }
+ }
+ return 0;
+}
+
+/**
+ * pinmux_hog_maps() - unhog specific map entries on controller device
+ * @pctldev: the pin control device to unhog entries on
+ */
+void pinmux_unhog_maps(struct pinctrl_dev *pctldev)
+{
+ struct list_head *node, *tmp;
+
+ mutex_lock(&pctldev->pinmux_hogs_lock);
+ list_for_each_safe(node, tmp, &pctldev->pinmux_hogs) {
+ struct pinmux_hog *hog =
+ list_entry(node, struct pinmux_hog, node);
+ pinmux_disable(hog->pmx);
+ pinmux_put(hog->pmx);
+ list_del(node);
+ kfree(hog);
+ }
+ mutex_unlock(&pctldev->pinmux_hogs_lock);
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+/* Called from pincontrol core */
+static int pinmux_functions_show(struct seq_file *s, void *what)
+{
+ struct pinctrl_dev *pctldev = s->private;
+ const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
+ unsigned func_selector = 0;
+
+ while (pmxops->list_functions(pctldev, func_selector) >= 0) {
+ const char *func = pmxops->get_function_name(pctldev,
+ func_selector);
+ const char * const *groups;
+ unsigned num_groups;
+ int ret;
+ int i;
+
+ ret = pmxops->get_function_groups(pctldev, func_selector,
+ &groups, &num_groups);
+ if (ret)
+ seq_printf(s, "function %s: COULD NOT GET GROUPS\n",
+ func);
+
+ seq_printf(s, "function: %s, groups = [ ", func);
+ for (i = 0; i < num_groups; i++)
+ seq_printf(s, "%s ", groups[i]);
+ seq_puts(s, "]\n");
+
+ func_selector++;
+
+ }
+
+ return 0;
+}
+
+static int pinmux_pins_show(struct seq_file *s, void *what)
+{
+ struct pinctrl_dev *pctldev = s->private;
+ unsigned pin;
+
+ seq_puts(s, "Pinmux settings per pin\n");
+ seq_puts(s, "Format: pin (name): pinmuxfunction\n");
+
+ /* The highest pin number need to be included in the loop, thus <= */
+ for (pin = 0; pin <= pctldev->desc->maxpin; pin++) {
+
+ struct pin_desc *desc;
+
+ desc = pin_desc_get(pctldev, pin);
+ /* Pin space may be sparse */
+ if (desc == NULL)
+ continue;
+
+ seq_printf(s, "pin %d (%s): %s\n", pin,
+ desc->name ? desc->name : "unnamed",
+ desc->mux_function ? desc->mux_function
+ : "UNCLAIMED");
+ }
+
+ return 0;
+}
+
+static int pinmux_hogs_show(struct seq_file *s, void *what)
+{
+ struct pinctrl_dev *pctldev = s->private;
+ struct pinmux_hog *hog;
+
+ seq_puts(s, "Pinmux map hogs held by device\n");
+
+ list_for_each_entry(hog, &pctldev->pinmux_hogs, node)
+ seq_printf(s, "%s\n", hog->map->name);
+
+ return 0;
+}
+
+static int pinmux_show(struct seq_file *s, void *what)
+{
+ struct pinmux *pmx;
+
+ seq_puts(s, "Requested pinmuxes and their maps:\n");
+ list_for_each_entry(pmx, &pinmux_list, node) {
+ struct pinctrl_dev *pctldev = pmx->pctldev;
+ const struct pinmux_ops *pmxops;
+ const struct pinctrl_ops *pctlops;
+ struct pinmux_group *grp;
+
+ if (!pctldev) {
+ seq_puts(s, "NO PIN CONTROLLER DEVICE\n");
+ continue;
+ }
+
+ pmxops = pctldev->desc->pmxops;
+ pctlops = pctldev->desc->pctlops;
+
+ seq_printf(s, "device: %s function: %s (%u),",
+ pinctrl_dev_get_name(pmx->pctldev),
+ pmxops->get_function_name(pctldev, pmx->func_selector),
+ pmx->func_selector);
+
+ seq_printf(s, " groups: [");
+ list_for_each_entry(grp, &pmx->groups, node) {
+ seq_printf(s, " %s (%u)",
+ pctlops->get_group_name(pctldev, grp->group_selector),
+ grp->group_selector);
+ }
+ seq_printf(s, " ]");
+
+ seq_printf(s, " users: %u map-> %s\n",
+ pmx->usecount,
+ pmx->dev ? dev_name(pmx->dev) : "(system)");
+ }
+
+ return 0;
+}
+
+static int pinmux_maps_show(struct seq_file *s, void *what)
+{
+ int i;
+
+ seq_puts(s, "Pinmux maps:\n");
+
+ for (i = 0; i < pinmux_maps_num; i++) {
+ struct pinmux_map const *map = &pinmux_maps[i];
+
+ seq_printf(s, "%s:\n", map->name);
+ if (map->dev || map->dev_name)
+ seq_printf(s, " device: %s\n",
+ map->dev ? dev_name(map->dev) :
+ map->dev_name);
+ else
+ seq_printf(s, " SYSTEM MUX\n");
+ seq_printf(s, " controlling device %s\n",
+ map->ctrl_dev ? dev_name(map->ctrl_dev) :
+ map->ctrl_dev_name);
+ seq_printf(s, " function: %s\n", map->function);
+ seq_printf(s, " group: %s\n", map->group ? map->group :
+ "(default)");
+ }
+ return 0;
+}
+
+static int pinmux_functions_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, pinmux_functions_show, inode->i_private);
+}
+
+static int pinmux_pins_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, pinmux_pins_show, inode->i_private);
+}
+
+static int pinmux_hogs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, pinmux_hogs_show, inode->i_private);
+}
+
+static int pinmux_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, pinmux_show, NULL);
+}
+
+static int pinmux_maps_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, pinmux_maps_show, NULL);
+}
+
+static const struct file_operations pinmux_functions_ops = {
+ .open = pinmux_functions_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations pinmux_pins_ops = {
+ .open = pinmux_pins_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations pinmux_hogs_ops = {
+ .open = pinmux_hogs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations pinmux_ops = {
+ .open = pinmux_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations pinmux_maps_ops = {
+ .open = pinmux_maps_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+void pinmux_init_device_debugfs(struct dentry *devroot,
+ struct pinctrl_dev *pctldev)
+{
+ debugfs_create_file("pinmux-functions", S_IFREG | S_IRUGO,
+ devroot, pctldev, &pinmux_functions_ops);
+ debugfs_create_file("pinmux-pins", S_IFREG | S_IRUGO,
+ devroot, pctldev, &pinmux_pins_ops);
+ debugfs_create_file("pinmux-hogs", S_IFREG | S_IRUGO,
+ devroot, pctldev, &pinmux_hogs_ops);
+}
+
+void pinmux_init_debugfs(struct dentry *subsys_root)
+{
+ debugfs_create_file("pinmuxes", S_IFREG | S_IRUGO,
+ subsys_root, NULL, &pinmux_ops);
+ debugfs_create_file("pinmux-maps", S_IFREG | S_IRUGO,
+ subsys_root, NULL, &pinmux_maps_ops);
+}
+
+#endif /* CONFIG_DEBUG_FS */
diff --git a/drivers/pinctrl/pinmux.h b/drivers/pinctrl/pinmux.h
new file mode 100644
index 000000000000..844500b3331b
--- /dev/null
+++ b/drivers/pinctrl/pinmux.h
@@ -0,0 +1,47 @@
+/*
+ * Internal interface between the core pin control system and the
+ * pinmux portions
+ *
+ * Copyright (C) 2011 ST-Ericsson SA
+ * Written on behalf of Linaro for ST-Ericsson
+ * Based on bits of regulator core, gpio core and clk core
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#ifdef CONFIG_PINMUX
+
+int pinmux_check_ops(const struct pinmux_ops *ops);
+void pinmux_init_device_debugfs(struct dentry *devroot,
+ struct pinctrl_dev *pctldev);
+void pinmux_init_debugfs(struct dentry *subsys_root);
+int pinmux_hog_maps(struct pinctrl_dev *pctldev);
+void pinmux_unhog_maps(struct pinctrl_dev *pctldev);
+
+#else
+
+static inline int pinmux_check_ops(const struct pinmux_ops *ops)
+{
+ return 0;
+}
+
+static inline void pinmux_init_device_debugfs(struct dentry *devroot,
+ struct pinctrl_dev *pctldev)
+{
+}
+
+static inline void pinmux_init_debugfs(struct dentry *subsys_root)
+{
+}
+
+static inline int pinmux_hog_maps(struct pinctrl_dev *pctldev)
+{
+ return 0;
+}
+
+static inline void pinmux_unhog_maps(struct pinctrl_dev *pctldev)
+{
+}
+
+#endif
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 1e88d4785321..10cf2500522b 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -31,9 +31,6 @@ config ACER_WMI
wireless radio and bluetooth control, and on some laptops,
exposes the mail LED and LCD backlight.
- For more information about this driver see
- <file:Documentation/laptops/acer-wmi.txt>
-
If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M
here.
@@ -164,7 +161,7 @@ config HP_ACCEL
Support for a led indicating disk protection will be provided as
hp::hddprotect. For more information on the feature, refer to
- Documentation/hwmon/lis3lv02d.
+ Documentation/misc-devices/lis3lv02d.
To compile this driver as a module, choose M here: the module will
be called hp_accel.
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 7bd829f247eb..7b828680b21d 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -4007,7 +4007,7 @@ static void bluetooth_shutdown(void)
pr_notice("failed to save bluetooth state to NVRAM\n");
else
vdbg_printk(TPACPI_DBG_RFKILL,
- "bluestooth state saved to NVRAM\n");
+ "bluetooth state saved to NVRAM\n");
}
static void bluetooth_exit(void)
diff --git a/drivers/power/max8997_charger.c b/drivers/power/max8997_charger.c
index 7106b49b26e4..ffc5033ea9c9 100644
--- a/drivers/power/max8997_charger.c
+++ b/drivers/power/max8997_charger.c
@@ -20,6 +20,7 @@
*/
#include <linux/err.h>
+#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
diff --git a/drivers/power/max8998_charger.c b/drivers/power/max8998_charger.c
index cc21fa2120be..ef8efadb58cb 100644
--- a/drivers/power/max8998_charger.c
+++ b/drivers/power/max8998_charger.c
@@ -20,6 +20,7 @@
*/
#include <linux/err.h>
+#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
diff --git a/drivers/power/s3c_adc_battery.c b/drivers/power/s3c_adc_battery.c
index a675e31b4f13..d32d0d70f9ba 100644
--- a/drivers/power/s3c_adc_battery.c
+++ b/drivers/power/s3c_adc_battery.c
@@ -20,6 +20,7 @@
#include <linux/s3c_adc_battery.h>
#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/module.h>
#include <plat/adc.h>
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index ee893581d4b7..ebe77dd87daf 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -505,8 +505,7 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
rdev->dev.dma_mask = &rdev->dma_mask;
rdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
- if ((rdev->pef & RIO_PEF_INB_DOORBELL) &&
- (rdev->dst_ops & RIO_DST_OPS_DOORBELL))
+ if (rdev->dst_ops & RIO_DST_OPS_DOORBELL)
rio_init_dbell_res(&rdev->riores[RIO_DOORBELL_RESOURCE],
0, 0xffff);
diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c
index 335551d333b2..14a42a1edc66 100644
--- a/drivers/rtc/rtc-ep93xx.c
+++ b/drivers/rtc/rtc-ep93xx.c
@@ -36,6 +36,7 @@
*/
struct ep93xx_rtc {
void __iomem *mmio_base;
+ struct rtc_device *rtc;
};
static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload,
@@ -130,7 +131,6 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev)
{
struct ep93xx_rtc *ep93xx_rtc;
struct resource *res;
- struct rtc_device *rtc;
int err;
ep93xx_rtc = devm_kzalloc(&pdev->dev, sizeof(*ep93xx_rtc), GFP_KERNEL);
@@ -151,12 +151,12 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev)
return -ENXIO;
pdev->dev.platform_data = ep93xx_rtc;
- platform_set_drvdata(pdev, rtc);
+ platform_set_drvdata(pdev, ep93xx_rtc);
- rtc = rtc_device_register(pdev->name,
+ ep93xx_rtc->rtc = rtc_device_register(pdev->name,
&pdev->dev, &ep93xx_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc)) {
- err = PTR_ERR(rtc);
+ if (IS_ERR(ep93xx_rtc->rtc)) {
+ err = PTR_ERR(ep93xx_rtc->rtc);
goto exit;
}
@@ -167,7 +167,7 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev)
return 0;
fail:
- rtc_device_unregister(rtc);
+ rtc_device_unregister(ep93xx_rtc->rtc);
exit:
platform_set_drvdata(pdev, NULL);
pdev->dev.platform_data = NULL;
@@ -176,11 +176,11 @@ exit:
static int __exit ep93xx_rtc_remove(struct platform_device *pdev)
{
- struct rtc_device *rtc = platform_get_drvdata(pdev);
+ struct ep93xx_rtc *ep93xx_rtc = platform_get_drvdata(pdev);
sysfs_remove_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files);
platform_set_drvdata(pdev, NULL);
- rtc_device_unregister(rtc);
+ rtc_device_unregister(ep93xx_rtc->rtc);
pdev->dev.platform_data = NULL;
return 0;
diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c
index 2dd3c0163272..d93a9608b1f0 100644
--- a/drivers/rtc/rtc-imxdi.c
+++ b/drivers/rtc/rtc-imxdi.c
@@ -35,6 +35,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
+#include <linux/sched.h>
#include <linux/workqueue.h>
/* DryIce Register Definitions */
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
index 075f1708deae..c4cf05731118 100644
--- a/drivers/rtc/rtc-lib.c
+++ b/drivers/rtc/rtc-lib.c
@@ -85,6 +85,8 @@ void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
time -= tm->tm_hour * 3600;
tm->tm_min = time / 60;
tm->tm_sec = time - tm->tm_min * 60;
+
+ tm->tm_isdst = 0;
}
EXPORT_SYMBOL(rtc_time_to_tm);
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 9329dbb9ebab..7639ab906f02 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -51,6 +51,27 @@ static enum s3c_cpu_type s3c_rtc_cpu_type;
static DEFINE_SPINLOCK(s3c_rtc_pie_lock);
+static void s3c_rtc_alarm_clk_enable(bool enable)
+{
+ static DEFINE_SPINLOCK(s3c_rtc_alarm_clk_lock);
+ static bool alarm_clk_enabled;
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&s3c_rtc_alarm_clk_lock, irq_flags);
+ if (enable) {
+ if (!alarm_clk_enabled) {
+ clk_enable(rtc_clk);
+ alarm_clk_enabled = true;
+ }
+ } else {
+ if (alarm_clk_enabled) {
+ clk_disable(rtc_clk);
+ alarm_clk_enabled = false;
+ }
+ }
+ spin_unlock_irqrestore(&s3c_rtc_alarm_clk_lock, irq_flags);
+}
+
/* IRQ Handlers */
static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
@@ -64,6 +85,9 @@ static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
writeb(S3C2410_INTP_ALM, s3c_rtc_base + S3C2410_INTP);
clk_disable(rtc_clk);
+
+ s3c_rtc_alarm_clk_enable(false);
+
return IRQ_HANDLED;
}
@@ -97,6 +121,8 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
writeb(tmp, s3c_rtc_base + S3C2410_RTCALM);
clk_disable(rtc_clk);
+ s3c_rtc_alarm_clk_enable(enabled);
+
return 0;
}
@@ -152,10 +178,6 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
goto retry_get_time;
}
- pr_debug("read time %04d.%02d.%02d %02d:%02d:%02d\n",
- 1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
- rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
-
rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
@@ -164,6 +186,11 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
rtc_tm->tm_year += 100;
+
+ pr_debug("read time %04d.%02d.%02d %02d:%02d:%02d\n",
+ 1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
+ rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
+
rtc_tm->tm_mon -= 1;
clk_disable(rtc_clk);
@@ -269,10 +296,9 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
clk_enable(rtc_clk);
pr_debug("s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",
alrm->enabled,
- 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+ 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
-
alrm_en = readb(base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
writeb(0x00, base + S3C2410_RTCALM);
@@ -319,49 +345,7 @@ static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
return 0;
}
-static int s3c_rtc_open(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
- int ret;
-
- ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq,
- IRQF_DISABLED, "s3c2410-rtc alarm", rtc_dev);
-
- if (ret) {
- dev_err(dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret);
- return ret;
- }
-
- ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq,
- IRQF_DISABLED, "s3c2410-rtc tick", rtc_dev);
-
- if (ret) {
- dev_err(dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret);
- goto tick_err;
- }
-
- return ret;
-
- tick_err:
- free_irq(s3c_rtc_alarmno, rtc_dev);
- return ret;
-}
-
-static void s3c_rtc_release(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
-
- /* do not clear AIE here, it may be needed for wake */
-
- free_irq(s3c_rtc_alarmno, rtc_dev);
- free_irq(s3c_rtc_tickno, rtc_dev);
-}
-
static const struct rtc_class_ops s3c_rtcops = {
- .open = s3c_rtc_open,
- .release = s3c_rtc_release,
.read_time = s3c_rtc_gettime,
.set_time = s3c_rtc_settime,
.read_alarm = s3c_rtc_getalarm,
@@ -425,6 +409,9 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev)
{
struct rtc_device *rtc = platform_get_drvdata(dev);
+ free_irq(s3c_rtc_alarmno, rtc);
+ free_irq(s3c_rtc_tickno, rtc);
+
platform_set_drvdata(dev, NULL);
rtc_device_unregister(rtc);
@@ -548,10 +535,32 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
s3c_rtc_setfreq(&pdev->dev, 1);
+ ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq,
+ IRQF_DISABLED, "s3c2410-rtc alarm", rtc);
+ if (ret) {
+ dev_err(&pdev->dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret);
+ goto err_alarm_irq;
+ }
+
+ ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq,
+ IRQF_DISABLED, "s3c2410-rtc tick", rtc);
+ if (ret) {
+ dev_err(&pdev->dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret);
+ free_irq(s3c_rtc_alarmno, rtc);
+ goto err_tick_irq;
+ }
+
clk_disable(rtc_clk);
return 0;
+ err_tick_irq:
+ free_irq(s3c_rtc_alarmno, rtc);
+
+ err_alarm_irq:
+ platform_set_drvdata(pdev, NULL);
+ rtc_device_unregister(rtc);
+
err_nortc:
s3c_rtc_enable(pdev, 0);
clk_disable(rtc_clk);
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c
index 9a81f778d6b2..20687d55e7a7 100644
--- a/drivers/rtc/rtc-twl.c
+++ b/drivers/rtc/rtc-twl.c
@@ -362,14 +362,6 @@ static irqreturn_t twl_rtc_interrupt(int irq, void *rtc)
int res;
u8 rd_reg;
-#ifdef CONFIG_LOCKDEP
- /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
- * we don't want and can't tolerate. Although it might be
- * friendlier not to borrow this thread context...
- */
- local_irq_enable();
-#endif
-
res = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
if (res)
goto out;
@@ -428,24 +420,12 @@ static struct rtc_class_ops twl_rtc_ops = {
static int __devinit twl_rtc_probe(struct platform_device *pdev)
{
struct rtc_device *rtc;
- int ret = 0;
+ int ret = -EINVAL;
int irq = platform_get_irq(pdev, 0);
u8 rd_reg;
if (irq <= 0)
- return -EINVAL;
-
- rtc = rtc_device_register(pdev->name,
- &pdev->dev, &twl_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc)) {
- ret = PTR_ERR(rtc);
- dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
- PTR_ERR(rtc));
- goto out0;
-
- }
-
- platform_set_drvdata(pdev, rtc);
+ goto out1;
ret = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
if (ret < 0)
@@ -462,14 +442,6 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev)
if (ret < 0)
goto out1;
- ret = request_irq(irq, twl_rtc_interrupt,
- IRQF_TRIGGER_RISING,
- dev_name(&rtc->dev), rtc);
- if (ret < 0) {
- dev_err(&pdev->dev, "IRQ is not free.\n");
- goto out1;
- }
-
if (twl_class_is_6030()) {
twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK,
REG_INT_MSK_LINE_A);
@@ -480,28 +452,44 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev)
/* Check RTC module status, Enable if it is off */
ret = twl_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG);
if (ret < 0)
- goto out2;
+ goto out1;
if (!(rd_reg & BIT_RTC_CTRL_REG_STOP_RTC_M)) {
dev_info(&pdev->dev, "Enabling TWL-RTC.\n");
rd_reg = BIT_RTC_CTRL_REG_STOP_RTC_M;
ret = twl_rtc_write_u8(rd_reg, REG_RTC_CTRL_REG);
if (ret < 0)
- goto out2;
+ goto out1;
}
/* init cached IRQ enable bits */
ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG);
if (ret < 0)
+ goto out1;
+
+ rtc = rtc_device_register(pdev->name,
+ &pdev->dev, &twl_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ ret = PTR_ERR(rtc);
+ dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
+ PTR_ERR(rtc));
+ goto out1;
+ }
+
+ ret = request_threaded_irq(irq, NULL, twl_rtc_interrupt,
+ IRQF_TRIGGER_RISING,
+ dev_name(&rtc->dev), rtc);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "IRQ is not free.\n");
goto out2;
+ }
- return ret;
+ platform_set_drvdata(pdev, rtc);
+ return 0;
out2:
- free_irq(irq, rtc);
-out1:
rtc_device_unregister(rtc);
-out0:
+out1:
return ret;
}
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index eb4e034378cd..f1a2016829fc 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -249,6 +249,7 @@ static int dasd_ioctl_reset_profile(struct dasd_block *block)
static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)
{
struct dasd_profile_info_t *data;
+ int rc = 0;
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data)
@@ -279,11 +280,14 @@ static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)
spin_unlock_bh(&block->profile.lock);
} else {
spin_unlock_bh(&block->profile.lock);
- return -EIO;
+ rc = -EIO;
+ goto out;
}
if (copy_to_user(argp, data, sizeof(*data)))
- return -EFAULT;
- return 0;
+ rc = -EFAULT;
+out:
+ kfree(data);
+ return rc;
}
#else
static int dasd_ioctl_reset_profile(struct dasd_block *block)
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
index be55fb2b1b1c..837e010299a8 100644
--- a/drivers/s390/char/sclp_cmd.c
+++ b/drivers/s390/char/sclp_cmd.c
@@ -383,8 +383,10 @@ static int sclp_attach_storage(u8 id)
switch (sccb->header.response_code) {
case 0x0020:
set_bit(id, sclp_storage_ids);
- for (i = 0; i < sccb->assigned; i++)
- sclp_unassign_storage(sccb->entries[i] >> 16);
+ for (i = 0; i < sccb->assigned; i++) {
+ if (sccb->entries[i])
+ sclp_unassign_storage(sccb->entries[i] >> 16);
+ }
break;
default:
rc = -EIO;
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index 76058a5166ed..08c66035dd19 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -335,10 +335,9 @@ cio_ignore_write(struct file *file, const char __user *user_buf,
return -EINVAL;
if (user_len > 65536)
user_len = 65536;
- buf = vmalloc (user_len + 1); /* maybe better use the stack? */
+ buf = vzalloc(user_len + 1); /* maybe better use the stack? */
if (buf == NULL)
return -ENOMEM;
- memset(buf, 0, user_len + 1);
if (strncpy_from_user (buf, user_buf, user_len) < 0) {
rc = -EFAULT;
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index cbde448f9947..eb3140ee821e 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -654,8 +654,8 @@ static struct io_subchannel_private console_priv;
static int console_subchannel_in_use;
/*
- * Use tpi to get a pending interrupt, call the interrupt handler and
- * return a pointer to the subchannel structure.
+ * Use cio_tpi to get a pending interrupt and call the interrupt handler.
+ * Return non-zero if an interrupt was processed, zero otherwise.
*/
static int cio_tpi(void)
{
@@ -667,6 +667,10 @@ static int cio_tpi(void)
tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id;
if (tpi(NULL) != 1)
return 0;
+ if (tpi_info->adapter_IO) {
+ do_adapter_IO(tpi_info->isc);
+ return 1;
+ }
irb = (struct irb *)&S390_lowcore.irb;
/* Store interrupt response block to lowcore. */
if (tsch(tpi_info->schid, irb) != 0)
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index e5c966462c5a..3dd86441da3d 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -44,6 +44,7 @@ enum qdio_irq_states {
#define SLSB_STATE_NOT_INIT 0x0
#define SLSB_STATE_EMPTY 0x1
#define SLSB_STATE_PRIMED 0x2
+#define SLSB_STATE_PENDING 0x3
#define SLSB_STATE_HALTED 0xe
#define SLSB_STATE_ERROR 0xf
#define SLSB_TYPE_INPUT 0x0
@@ -67,6 +68,8 @@ enum qdio_irq_states {
(SLSB_OWNER_PROG | SLSB_TYPE_OUTPUT | SLSB_STATE_NOT_INIT) /* 0xa0 */
#define SLSB_P_OUTPUT_EMPTY \
(SLSB_OWNER_PROG | SLSB_TYPE_OUTPUT | SLSB_STATE_EMPTY) /* 0xa1 */
+#define SLSB_P_OUTPUT_PENDING \
+ (SLSB_OWNER_PROG | SLSB_TYPE_OUTPUT | SLSB_STATE_PENDING) /* 0xa3 */
#define SLSB_CU_OUTPUT_PRIMED \
(SLSB_OWNER_CU | SLSB_TYPE_OUTPUT | SLSB_STATE_PRIMED) /* 0x62 */
#define SLSB_P_OUTPUT_HALTED \
@@ -84,19 +87,11 @@ enum qdio_irq_states {
#define CHSC_FLAG_QDIO_CAPABILITY 0x80
#define CHSC_FLAG_VALIDITY 0x40
-/* qdio adapter-characteristics-1 flag */
-#define AC1_SIGA_INPUT_NEEDED 0x40 /* process input queues */
-#define AC1_SIGA_OUTPUT_NEEDED 0x20 /* process output queues */
-#define AC1_SIGA_SYNC_NEEDED 0x10 /* ask hypervisor to sync */
-#define AC1_AUTOMATIC_SYNC_ON_THININT 0x08 /* set by hypervisor */
-#define AC1_AUTOMATIC_SYNC_ON_OUT_PCI 0x04 /* set by hypervisor */
-#define AC1_SC_QEBSM_AVAILABLE 0x02 /* available for subchannel */
-#define AC1_SC_QEBSM_ENABLED 0x01 /* enabled for subchannel */
-
/* SIGA flags */
#define QDIO_SIGA_WRITE 0x00
#define QDIO_SIGA_READ 0x01
#define QDIO_SIGA_SYNC 0x02
+#define QDIO_SIGA_WRITEQ 0x04
#define QDIO_SIGA_QEBSM_FLAG 0x80
#ifdef CONFIG_64BIT
@@ -253,6 +248,12 @@ struct qdio_input_q {
struct qdio_output_q {
/* PCIs are enabled for the queue */
int pci_out_enabled;
+ /* cq: use asynchronous output buffers */
+ int use_cq;
+ /* cq: aobs used for particual SBAL */
+ struct qaob **aobs;
+ /* cq: sbal state related to asynchronous operation */
+ struct qdio_outbuf_state *sbal_state;
/* timer to check for more outbound work */
struct timer_list timer;
/* used SBALs before tasklet schedule */
@@ -432,9 +433,20 @@ struct indicator_t {
extern struct indicator_t *q_indicators;
-static inline int shared_ind(u32 *dsci)
+static inline int has_multiple_inq_on_dsci(struct qdio_irq *irq)
+{
+ return irq->nr_input_qs > 1;
+}
+
+static inline int references_shared_dsci(struct qdio_irq *irq)
{
- return dsci == &q_indicators[TIQDIO_SHARED_IND].ind;
+ return irq->dsci == &q_indicators[TIQDIO_SHARED_IND].ind;
+}
+
+static inline int shared_ind(struct qdio_q *q)
+{
+ struct qdio_irq *i = q->irq_ptr;
+ return references_shared_dsci(i) || has_multiple_inq_on_dsci(i);
}
/* prototypes for thin interrupt */
@@ -449,6 +461,7 @@ void tiqdio_free_memory(void);
int tiqdio_register_thinints(void);
void tiqdio_unregister_thinints(void);
+
/* prototypes for setup */
void qdio_inbound_processing(unsigned long data);
void qdio_outbound_processing(unsigned long data);
@@ -469,6 +482,9 @@ int qdio_setup_create_sysfs(struct ccw_device *cdev);
void qdio_setup_destroy_sysfs(struct ccw_device *cdev);
int qdio_setup_init(void);
void qdio_setup_exit(void);
+int qdio_enable_async_operation(struct qdio_output_q *q);
+void qdio_disable_async_operation(struct qdio_output_q *q);
+struct qaob *qdio_allocate_aob(void);
int debug_get_buf_state(struct qdio_q *q, unsigned int bufnr,
unsigned char *state);
diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c
index 0e615cb912d0..aaf7f935bfd3 100644
--- a/drivers/s390/cio/qdio_debug.c
+++ b/drivers/s390/cio/qdio_debug.c
@@ -76,6 +76,9 @@ static int qstat_show(struct seq_file *m, void *v)
case SLSB_P_OUTPUT_NOT_INIT:
seq_printf(m, "N");
break;
+ case SLSB_P_OUTPUT_PENDING:
+ seq_printf(m, "P");
+ break;
case SLSB_P_INPUT_PRIMED:
case SLSB_CU_OUTPUT_PRIMED:
seq_printf(m, "+");
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 288c9140290e..9a122280246c 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -14,6 +14,7 @@
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/gfp.h>
+#include <linux/io.h>
#include <linux/kernel_stat.h>
#include <linux/atomic.h>
#include <asm/debug.h>
@@ -77,11 +78,13 @@ static inline int do_siga_input(unsigned long schid, unsigned int mask,
* Note: For IQDC unicast queues only the highest priority queue is processed.
*/
static inline int do_siga_output(unsigned long schid, unsigned long mask,
- unsigned int *bb, unsigned int fc)
+ unsigned int *bb, unsigned int fc,
+ unsigned long aob)
{
register unsigned long __fc asm("0") = fc;
register unsigned long __schid asm("1") = schid;
register unsigned long __mask asm("2") = mask;
+ register unsigned long __aob asm("3") = aob;
int cc = QDIO_ERROR_SIGA_ACCESS_EXCEPTION;
asm volatile(
@@ -90,7 +93,8 @@ static inline int do_siga_output(unsigned long schid, unsigned long mask,
" srl %0,28\n"
"1:\n"
EX_TABLE(0b, 1b)
- : "+d" (cc), "+d" (__fc), "+d" (__schid), "+d" (__mask)
+ : "+d" (cc), "+d" (__fc), "+d" (__schid), "+d" (__mask),
+ "+d" (__aob)
: : "cc", "memory");
*bb = ((unsigned int) __fc) >> 31;
return cc;
@@ -212,7 +216,7 @@ again:
/* returns number of examined buffers and their common state in *state */
static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr,
unsigned char *state, unsigned int count,
- int auto_ack)
+ int auto_ack, int merge_pending)
{
unsigned char __state = 0;
int i;
@@ -224,9 +228,14 @@ static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr,
return qdio_do_eqbs(q, state, bufnr, count, auto_ack);
for (i = 0; i < count; i++) {
- if (!__state)
+ if (!__state) {
__state = q->slsb.val[bufnr];
- else if (q->slsb.val[bufnr] != __state)
+ if (merge_pending && __state == SLSB_P_OUTPUT_PENDING)
+ __state = SLSB_P_OUTPUT_EMPTY;
+ } else if (merge_pending) {
+ if ((q->slsb.val[bufnr] & __state) != __state)
+ break;
+ } else if (q->slsb.val[bufnr] != __state)
break;
bufnr = next_buf(bufnr);
}
@@ -237,7 +246,7 @@ static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr,
static inline int get_buf_state(struct qdio_q *q, unsigned int bufnr,
unsigned char *state, int auto_ack)
{
- return get_buf_states(q, bufnr, state, 1, auto_ack);
+ return get_buf_states(q, bufnr, state, 1, auto_ack, 0);
}
/* wrap-around safe setting of slsb states, returns number of changed buffers */
@@ -308,19 +317,28 @@ static inline int qdio_siga_sync_q(struct qdio_q *q)
return qdio_siga_sync(q, q->mask, 0);
}
-static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit)
+static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit,
+ unsigned long aob)
{
unsigned long schid = *((u32 *) &q->irq_ptr->schid);
unsigned int fc = QDIO_SIGA_WRITE;
u64 start_time = 0;
int retries = 0, cc;
+ unsigned long laob = 0;
+
+ if (q->u.out.use_cq && aob != 0) {
+ fc = QDIO_SIGA_WRITEQ;
+ laob = aob;
+ }
if (is_qebsm(q)) {
schid = q->irq_ptr->sch_token;
fc |= QDIO_SIGA_QEBSM_FLAG;
}
again:
- cc = do_siga_output(schid, q->mask, busy_bit, fc);
+ WARN_ON_ONCE((aob && queue_type(q) != QDIO_IQDIO_QFMT) ||
+ (aob && fc != QDIO_SIGA_WRITEQ));
+ cc = do_siga_output(schid, q->mask, busy_bit, fc, laob);
/* hipersocket busy condition */
if (unlikely(*busy_bit)) {
@@ -379,7 +397,7 @@ int debug_get_buf_state(struct qdio_q *q, unsigned int bufnr,
{
if (need_siga_sync(q))
qdio_siga_sync_q(q);
- return get_buf_states(q, bufnr, state, 1, 0);
+ return get_buf_states(q, bufnr, state, 1, 0, 0);
}
static inline void qdio_stop_polling(struct qdio_q *q)
@@ -507,7 +525,7 @@ static int get_inbound_buffer_frontier(struct qdio_q *q)
* No siga sync here, as a PCI or we after a thin interrupt
* already sync'ed the queues.
*/
- count = get_buf_states(q, q->first_to_check, &state, count, 1);
+ count = get_buf_states(q, q->first_to_check, &state, count, 1, 0);
if (!count)
goto out;
@@ -590,6 +608,107 @@ static inline int qdio_inbound_q_done(struct qdio_q *q)
return 0;
}
+static inline int contains_aobs(struct qdio_q *q)
+{
+ return !q->is_input_q && q->u.out.use_cq;
+}
+
+static inline void qdio_trace_aob(struct qdio_irq *irq, struct qdio_q *q,
+ int i, struct qaob *aob)
+{
+ int tmp;
+
+ DBF_DEV_EVENT(DBF_INFO, irq, "AOB%d:%lx", i,
+ (unsigned long) virt_to_phys(aob));
+ DBF_DEV_EVENT(DBF_INFO, irq, "RES00:%lx",
+ (unsigned long) aob->res0[0]);
+ DBF_DEV_EVENT(DBF_INFO, irq, "RES01:%lx",
+ (unsigned long) aob->res0[1]);
+ DBF_DEV_EVENT(DBF_INFO, irq, "RES02:%lx",
+ (unsigned long) aob->res0[2]);
+ DBF_DEV_EVENT(DBF_INFO, irq, "RES03:%lx",
+ (unsigned long) aob->res0[3]);
+ DBF_DEV_EVENT(DBF_INFO, irq, "RES04:%lx",
+ (unsigned long) aob->res0[4]);
+ DBF_DEV_EVENT(DBF_INFO, irq, "RES05:%lx",
+ (unsigned long) aob->res0[5]);
+ DBF_DEV_EVENT(DBF_INFO, irq, "RES1:%x", aob->res1);
+ DBF_DEV_EVENT(DBF_INFO, irq, "RES2:%x", aob->res2);
+ DBF_DEV_EVENT(DBF_INFO, irq, "RES3:%x", aob->res3);
+ DBF_DEV_EVENT(DBF_INFO, irq, "AORC:%u", aob->aorc);
+ DBF_DEV_EVENT(DBF_INFO, irq, "FLAGS:%u", aob->flags);
+ DBF_DEV_EVENT(DBF_INFO, irq, "CBTBS:%u", aob->cbtbs);
+ DBF_DEV_EVENT(DBF_INFO, irq, "SBC:%u", aob->sb_count);
+ for (tmp = 0; tmp < QDIO_MAX_ELEMENTS_PER_BUFFER; ++tmp) {
+ DBF_DEV_EVENT(DBF_INFO, irq, "SBA%d:%lx", tmp,
+ (unsigned long) aob->sba[tmp]);
+ DBF_DEV_EVENT(DBF_INFO, irq, "rSBA%d:%lx", tmp,
+ (unsigned long) q->sbal[i]->element[tmp].addr);
+ DBF_DEV_EVENT(DBF_INFO, irq, "DC%d:%u", tmp, aob->dcount[tmp]);
+ DBF_DEV_EVENT(DBF_INFO, irq, "rDC%d:%u", tmp,
+ q->sbal[i]->element[tmp].length);
+ }
+ DBF_DEV_EVENT(DBF_INFO, irq, "USER0:%lx", (unsigned long) aob->user0);
+ for (tmp = 0; tmp < 2; ++tmp) {
+ DBF_DEV_EVENT(DBF_INFO, irq, "RES4%d:%lx", tmp,
+ (unsigned long) aob->res4[tmp]);
+ }
+ DBF_DEV_EVENT(DBF_INFO, irq, "USER1:%lx", (unsigned long) aob->user1);
+ DBF_DEV_EVENT(DBF_INFO, irq, "USER2:%lx", (unsigned long) aob->user2);
+}
+
+static inline void qdio_handle_aobs(struct qdio_q *q, int start, int count)
+{
+ unsigned char state = 0;
+ int j, b = start;
+
+ if (!contains_aobs(q))
+ return;
+
+ for (j = 0; j < count; ++j) {
+ get_buf_state(q, b, &state, 0);
+ if (state == SLSB_P_OUTPUT_PENDING) {
+ struct qaob *aob = q->u.out.aobs[b];
+ if (aob == NULL)
+ continue;
+
+ BUG_ON(q->u.out.sbal_state == NULL);
+ q->u.out.sbal_state[b].flags |=
+ QDIO_OUTBUF_STATE_FLAG_PENDING;
+ q->u.out.aobs[b] = NULL;
+ } else if (state == SLSB_P_OUTPUT_EMPTY) {
+ BUG_ON(q->u.out.sbal_state == NULL);
+ q->u.out.sbal_state[b].aob = NULL;
+ }
+ b = next_buf(b);
+ }
+}
+
+static inline unsigned long qdio_aob_for_buffer(struct qdio_output_q *q,
+ int bufnr)
+{
+ unsigned long phys_aob = 0;
+
+ if (!q->use_cq)
+ goto out;
+
+ if (!q->aobs[bufnr]) {
+ struct qaob *aob = qdio_allocate_aob();
+ q->aobs[bufnr] = aob;
+ }
+ if (q->aobs[bufnr]) {
+ BUG_ON(q->sbal_state == NULL);
+ q->sbal_state[bufnr].flags = QDIO_OUTBUF_STATE_FLAG_NONE;
+ q->sbal_state[bufnr].aob = q->aobs[bufnr];
+ q->aobs[bufnr]->user1 = (u64) q->sbal_state[bufnr].user;
+ phys_aob = virt_to_phys(q->aobs[bufnr]);
+ BUG_ON(phys_aob & 0xFF);
+ }
+
+out:
+ return phys_aob;
+}
+
static void qdio_kick_handler(struct qdio_q *q)
{
int start = q->first_to_kick;
@@ -610,6 +729,8 @@ static void qdio_kick_handler(struct qdio_q *q)
start, count);
}
+ qdio_handle_aobs(q, start, count);
+
q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count,
q->irq_ptr->int_parm);
@@ -672,23 +793,26 @@ static int get_outbound_buffer_frontier(struct qdio_q *q)
*/
count = min(atomic_read(&q->nr_buf_used), QDIO_MAX_BUFFERS_MASK);
stop = add_buf(q->first_to_check, count);
-
if (q->first_to_check == stop)
- return q->first_to_check;
+ goto out;
- count = get_buf_states(q, q->first_to_check, &state, count, 0);
+ count = get_buf_states(q, q->first_to_check, &state, count, 0, 1);
if (!count)
- return q->first_to_check;
+ goto out;
switch (state) {
+ case SLSB_P_OUTPUT_PENDING:
+ BUG();
case SLSB_P_OUTPUT_EMPTY:
/* the adapter got it */
- DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out empty:%1d %02x", q->nr, count);
+ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr,
+ "out empty:%1d %02x", q->nr, count);
atomic_sub(count, &q->nr_buf_used);
q->first_to_check = add_buf(q->first_to_check, count);
if (q->irq_ptr->perf_stat_enabled)
account_sbals(q, count);
+
break;
case SLSB_P_OUTPUT_ERROR:
process_buffer_error(q, count);
@@ -701,7 +825,8 @@ static int get_outbound_buffer_frontier(struct qdio_q *q)
/* the adapter has not fetched the output yet */
if (q->irq_ptr->perf_stat_enabled)
q->q_stats.nr_sbal_nop++;
- DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out primed:%1d", q->nr);
+ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out primed:%1d",
+ q->nr);
break;
case SLSB_P_OUTPUT_NOT_INIT:
case SLSB_P_OUTPUT_HALTED:
@@ -709,6 +834,8 @@ static int get_outbound_buffer_frontier(struct qdio_q *q)
default:
BUG();
}
+
+out:
return q->first_to_check;
}
@@ -732,7 +859,7 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q)
return 0;
}
-static int qdio_kick_outbound_q(struct qdio_q *q)
+static int qdio_kick_outbound_q(struct qdio_q *q, unsigned long aob)
{
int retries = 0, cc;
unsigned int busy_bit;
@@ -744,7 +871,7 @@ static int qdio_kick_outbound_q(struct qdio_q *q)
retry:
qperf_inc(q, siga_write);
- cc = qdio_siga_output(q, &busy_bit);
+ cc = qdio_siga_output(q, &busy_bit, aob);
switch (cc) {
case 0:
break;
@@ -921,8 +1048,9 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr)
}
q->u.in.queue_start_poll(q->irq_ptr->cdev, q->nr,
q->irq_ptr->int_parm);
- } else
+ } else {
tasklet_schedule(&q->tasklet);
+ }
}
if (!pci_out_supported(q))
@@ -1236,6 +1364,26 @@ out_err:
}
EXPORT_SYMBOL_GPL(qdio_allocate);
+static void qdio_detect_hsicq(struct qdio_irq *irq_ptr)
+{
+ struct qdio_q *q = irq_ptr->input_qs[0];
+ int i, use_cq = 0;
+
+ if (irq_ptr->nr_input_qs > 1 && queue_type(q) == QDIO_IQDIO_QFMT)
+ use_cq = 1;
+
+ for_each_output_queue(irq_ptr, q, i) {
+ if (use_cq) {
+ if (qdio_enable_async_operation(&q->u.out) < 0) {
+ use_cq = 0;
+ continue;
+ }
+ } else
+ qdio_disable_async_operation(&q->u.out);
+ }
+ DBF_EVENT("use_cq:%d", use_cq);
+}
+
/**
* qdio_establish - establish queues on a qdio subchannel
* @init_data: initialization data
@@ -1301,6 +1449,8 @@ int qdio_establish(struct qdio_initialize *init_data)
qdio_setup_ssqd_info(irq_ptr);
DBF_EVENT("qib ac:%4x", irq_ptr->qib.ac);
+ qdio_detect_hsicq(irq_ptr);
+
/* qebsm is now setup if available, initialize buffer states */
qdio_init_buf_states(irq_ptr);
@@ -1442,12 +1592,9 @@ set:
used = atomic_add_return(count, &q->nr_buf_used) - count;
BUG_ON(used + count > QDIO_MAX_BUFFERS_PER_Q);
- /* no need to signal as long as the adapter had free buffers */
- if (used)
- return 0;
-
if (need_siga_in(q))
return qdio_siga_input(q);
+
return 0;
}
@@ -1480,17 +1627,21 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags,
q->u.out.pci_out_enabled = 0;
if (queue_type(q) == QDIO_IQDIO_QFMT) {
- /* One SIGA-W per buffer required for unicast HiperSockets. */
+ unsigned long phys_aob = 0;
+
+ /* One SIGA-W per buffer required for unicast HSI */
WARN_ON_ONCE(count > 1 && !multicast_outbound(q));
- rc = qdio_kick_outbound_q(q);
+ phys_aob = qdio_aob_for_buffer(&q->u.out, bufnr);
+
+ rc = qdio_kick_outbound_q(q, phys_aob);
} else if (need_siga_sync(q)) {
rc = qdio_siga_sync_q(q);
} else {
/* try to fast requeue buffers */
get_buf_state(q, prev_buf(bufnr), &state, 0);
if (state != SLSB_CU_OUTPUT_PRIMED)
- rc = qdio_kick_outbound_q(q);
+ rc = qdio_kick_outbound_q(q, 0);
else
qperf_inc(q, fast_requeue);
}
@@ -1518,6 +1669,7 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags,
{
struct qdio_irq *irq_ptr;
+
if (bufnr >= QDIO_MAX_BUFFERS_PER_Q || count > QDIO_MAX_BUFFERS_PER_Q)
return -EINVAL;
@@ -1562,7 +1714,7 @@ int qdio_start_irq(struct ccw_device *cdev, int nr)
WARN_ON(queue_irqs_enabled(q));
- if (!shared_ind(q->irq_ptr->dsci))
+ if (!shared_ind(q))
xchg(q->irq_ptr->dsci, 0);
qdio_stop_polling(q);
@@ -1572,7 +1724,7 @@ int qdio_start_irq(struct ccw_device *cdev, int nr)
* We need to check again to not lose initiative after
* resetting the ACK state.
*/
- if (!shared_ind(q->irq_ptr->dsci) && *q->irq_ptr->dsci)
+ if (!shared_ind(q) && *q->irq_ptr->dsci)
goto rescan;
if (!qdio_inbound_q_done(q))
goto rescan;
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c
index 89107d0938c4..dd8bd670a6b8 100644
--- a/drivers/s390/cio/qdio_setup.c
+++ b/drivers/s390/cio/qdio_setup.c
@@ -19,6 +19,22 @@
#include "qdio_debug.h"
static struct kmem_cache *qdio_q_cache;
+static struct kmem_cache *qdio_aob_cache;
+
+struct qaob *qdio_allocate_aob()
+{
+ struct qaob *aob;
+
+ aob = kmem_cache_zalloc(qdio_aob_cache, GFP_ATOMIC);
+ return aob;
+}
+EXPORT_SYMBOL_GPL(qdio_allocate_aob);
+
+void qdio_release_aob(struct qaob *aob)
+{
+ kmem_cache_free(qdio_aob_cache, aob);
+}
+EXPORT_SYMBOL_GPL(qdio_release_aob);
/*
* qebsm is only available under 64bit but the adapter sets the feature
@@ -154,29 +170,36 @@ static void setup_queues(struct qdio_irq *irq_ptr,
struct qdio_q *q;
void **input_sbal_array = qdio_init->input_sbal_addr_array;
void **output_sbal_array = qdio_init->output_sbal_addr_array;
+ struct qdio_outbuf_state *output_sbal_state_array =
+ qdio_init->output_sbal_state_array;
int i;
for_each_input_queue(irq_ptr, q, i) {
- DBF_EVENT("in-q:%1d", i);
+ DBF_EVENT("inq:%1d", i);
setup_queues_misc(q, irq_ptr, qdio_init->input_handler, i);
q->is_input_q = 1;
- q->u.in.queue_start_poll = qdio_init->queue_start_poll;
+ q->u.in.queue_start_poll = qdio_init->queue_start_poll[i];
+
setup_storage_lists(q, irq_ptr, input_sbal_array, i);
input_sbal_array += QDIO_MAX_BUFFERS_PER_Q;
- if (is_thinint_irq(irq_ptr))
+ if (is_thinint_irq(irq_ptr)) {
tasklet_init(&q->tasklet, tiqdio_inbound_processing,
(unsigned long) q);
- else
+ } else {
tasklet_init(&q->tasklet, qdio_inbound_processing,
(unsigned long) q);
+ }
}
for_each_output_queue(irq_ptr, q, i) {
DBF_EVENT("outq:%1d", i);
setup_queues_misc(q, irq_ptr, qdio_init->output_handler, i);
+ q->u.out.sbal_state = output_sbal_state_array;
+ output_sbal_state_array += QDIO_MAX_BUFFERS_PER_Q;
+
q->is_input_q = 0;
q->u.out.scan_threshold = qdio_init->scan_threshold;
setup_storage_lists(q, irq_ptr, output_sbal_array, i);
@@ -311,6 +334,19 @@ void qdio_release_memory(struct qdio_irq *irq_ptr)
for (i = 0; i < QDIO_MAX_QUEUES_PER_IRQ; i++) {
q = irq_ptr->output_qs[i];
if (q) {
+ if (q->u.out.use_cq) {
+ int n;
+
+ for (n = 0; n < QDIO_MAX_BUFFERS_PER_Q; ++n) {
+ struct qaob *aob = q->u.out.aobs[n];
+ if (aob) {
+ qdio_release_aob(aob);
+ q->u.out.aobs[n] = NULL;
+ }
+ }
+
+ qdio_disable_async_operation(&q->u.out);
+ }
free_page((unsigned long) q->slib);
kmem_cache_free(qdio_q_cache, q);
}
@@ -465,23 +501,60 @@ void qdio_print_subchannel_info(struct qdio_irq *irq_ptr,
printk(KERN_INFO "%s", s);
}
+int qdio_enable_async_operation(struct qdio_output_q *outq)
+{
+ outq->aobs = kzalloc(sizeof(struct qaob *) * QDIO_MAX_BUFFERS_PER_Q,
+ GFP_ATOMIC);
+ if (!outq->aobs) {
+ outq->use_cq = 0;
+ return -ENOMEM;
+ }
+ outq->use_cq = 1;
+ return 0;
+}
+
+void qdio_disable_async_operation(struct qdio_output_q *q)
+{
+ kfree(q->aobs);
+ q->aobs = NULL;
+ q->use_cq = 0;
+}
+
int __init qdio_setup_init(void)
{
+ int rc;
+
qdio_q_cache = kmem_cache_create("qdio_q", sizeof(struct qdio_q),
256, 0, NULL);
if (!qdio_q_cache)
return -ENOMEM;
+ qdio_aob_cache = kmem_cache_create("qdio_aob",
+ sizeof(struct qaob),
+ sizeof(struct qaob),
+ 0,
+ NULL);
+ if (!qdio_aob_cache) {
+ rc = -ENOMEM;
+ goto free_qdio_q_cache;
+ }
+
/* Check for OSA/FCP thin interrupts (bit 67). */
DBF_EVENT("thinint:%1d",
(css_general_characteristics.aif_osa) ? 1 : 0);
/* Check for QEBSM support in general (bit 58). */
DBF_EVENT("cssQEBSM:%1d", (qebsm_possible()) ? 1 : 0);
- return 0;
+ rc = 0;
+out:
+ return rc;
+free_qdio_q_cache:
+ kmem_cache_destroy(qdio_q_cache);
+ goto out;
}
void qdio_setup_exit(void)
{
+ kmem_cache_destroy(qdio_aob_cache);
kmem_cache_destroy(qdio_q_cache);
}
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c
index 2a1d4dfaf859..a3e3949d7b69 100644
--- a/drivers/s390/cio/qdio_thinint.c
+++ b/drivers/s390/cio/qdio_thinint.c
@@ -67,12 +67,9 @@ static void put_indicator(u32 *addr)
void tiqdio_add_input_queues(struct qdio_irq *irq_ptr)
{
- struct qdio_q *q;
- int i;
-
mutex_lock(&tiq_list_lock);
- for_each_input_queue(irq_ptr, q, i)
- list_add_rcu(&q->entry, &tiq_list);
+ BUG_ON(irq_ptr->nr_input_qs < 1);
+ list_add_rcu(&irq_ptr->input_qs[0]->entry, &tiq_list);
mutex_unlock(&tiq_list_lock);
xchg(irq_ptr->dsci, 1 << 7);
}
@@ -80,19 +77,17 @@ void tiqdio_add_input_queues(struct qdio_irq *irq_ptr)
void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr)
{
struct qdio_q *q;
- int i;
- for (i = 0; i < irq_ptr->nr_input_qs; i++) {
- q = irq_ptr->input_qs[i];
- /* if establish triggered an error */
- if (!q || !q->entry.prev || !q->entry.next)
- continue;
+ BUG_ON(irq_ptr->nr_input_qs < 1);
+ q = irq_ptr->input_qs[0];
+ /* if establish triggered an error */
+ if (!q || !q->entry.prev || !q->entry.next)
+ return;
- mutex_lock(&tiq_list_lock);
- list_del_rcu(&q->entry);
- mutex_unlock(&tiq_list_lock);
- synchronize_rcu();
- }
+ mutex_lock(&tiq_list_lock);
+ list_del_rcu(&q->entry);
+ mutex_unlock(&tiq_list_lock);
+ synchronize_rcu();
}
static inline u32 clear_shared_ind(void)
@@ -102,6 +97,40 @@ static inline u32 clear_shared_ind(void)
return xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0);
}
+static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq)
+{
+ struct qdio_q *q;
+ int i;
+
+ for_each_input_queue(irq, q, i) {
+ if (!references_shared_dsci(irq) &&
+ has_multiple_inq_on_dsci(irq))
+ xchg(q->irq_ptr->dsci, 0);
+
+ if (q->u.in.queue_start_poll) {
+ /* skip if polling is enabled or already in work */
+ if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED,
+ &q->u.in.queue_irq_state)) {
+ qperf_inc(q, int_discarded);
+ continue;
+ }
+
+ /* avoid dsci clear here, done after processing */
+ q->u.in.queue_start_poll(q->irq_ptr->cdev, q->nr,
+ q->irq_ptr->int_parm);
+ } else {
+ if (!shared_ind(q))
+ xchg(q->irq_ptr->dsci, 0);
+
+ /*
+ * Call inbound processing but not directly
+ * since that could starve other thinint queues.
+ */
+ tasklet_schedule(&q->tasklet);
+ }
+ }
+}
+
/**
* tiqdio_thinint_handler - thin interrupt handler for qdio
* @alsi: pointer to adapter local summary indicator
@@ -120,35 +149,18 @@ static void tiqdio_thinint_handler(void *alsi, void *data)
/* check for work on all inbound thinint queues */
list_for_each_entry_rcu(q, &tiq_list, entry) {
+ struct qdio_irq *irq;
/* only process queues from changed sets */
- if (unlikely(shared_ind(q->irq_ptr->dsci))) {
+ irq = q->irq_ptr;
+ if (unlikely(references_shared_dsci(irq))) {
if (!si_used)
continue;
- } else if (!*q->irq_ptr->dsci)
+ } else if (!*irq->dsci)
continue;
- if (q->u.in.queue_start_poll) {
- /* skip if polling is enabled or already in work */
- if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED,
- &q->u.in.queue_irq_state)) {
- qperf_inc(q, int_discarded);
- continue;
- }
+ tiqdio_call_inq_handlers(irq);
- /* avoid dsci clear here, done after processing */
- q->u.in.queue_start_poll(q->irq_ptr->cdev, q->nr,
- q->irq_ptr->int_parm);
- } else {
- /* only clear it if the indicator is non-shared */
- if (!shared_ind(q->irq_ptr->dsci))
- xchg(q->irq_ptr->dsci, 0);
- /*
- * Call inbound processing but not directly
- * since that could starve other thinint queues.
- */
- tasklet_schedule(&q->tasklet);
- }
qperf_inc(q, adapter_int);
}
rcu_read_unlock();
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index c3b8064a102d..fb246b944b16 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -2122,7 +2122,7 @@ static const struct net_device_ops lcs_mc_netdev_ops = {
.ndo_stop = lcs_stop_device,
.ndo_get_stats = lcs_getstats,
.ndo_start_xmit = lcs_start_xmit,
- .ndo_set_multicast_list = lcs_set_multicast_list,
+ .ndo_set_rx_mode = lcs_set_multicast_list,
};
static int
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 26a4110eeb2d..b77c65ed1381 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -110,6 +110,10 @@ struct qeth_perf_stats {
unsigned int sc_dp_p;
unsigned int sc_p_dp;
+ /* qdio_cq_handler: number of times called, time spent in */
+ __u64 cq_start_time;
+ unsigned int cq_cnt;
+ unsigned int cq_time;
/* qdio_input_handler: number of times called, time spent in */
__u64 inbound_start_time;
unsigned int inbound_cnt;
@@ -213,6 +217,7 @@ static inline int qeth_is_ipa_enabled(struct qeth_ipa_info *ipa,
*/
#define QETH_TX_TIMEOUT 100 * HZ
#define QETH_RCD_TIMEOUT 60 * HZ
+#define QETH_RECLAIM_WORK_TIME HZ
#define QETH_HEADER_SIZE 32
#define QETH_MAX_PORTNO 15
@@ -231,7 +236,8 @@ static inline int qeth_is_ipa_enabled(struct qeth_ipa_info *ipa,
#define QETH_IN_BUF_COUNT_MAX 128
#define QETH_MAX_BUFFER_ELEMENTS(card) ((card)->qdio.in_buf_size >> 12)
#define QETH_IN_BUF_REQUEUE_THRESHOLD(card) \
- ((card)->qdio.in_buf_pool.buf_count / 2)
+ ((card)->ssqd.qdioac1 & AC1_SIGA_INPUT_NEEDED ? 1 : \
+ ((card)->qdio.in_buf_pool.buf_count / 2))
/* buffers we have to be behind before we get a PCI */
#define QETH_PCI_THRESHOLD_A(card) ((card)->qdio.in_buf_pool.buf_count+1)
@@ -260,6 +266,7 @@ static inline int qeth_is_ipa_enabled(struct qeth_ipa_info *ipa,
/* large receive scatter gather copy break */
#define QETH_RX_SG_CB (PAGE_SIZE >> 1)
+#define QETH_RX_PULL_LEN 256
struct qeth_hdr_layer3 {
__u8 id;
@@ -375,6 +382,21 @@ enum qeth_qdio_buffer_states {
* outbound: filled by driver; owned by hardware in order to be sent
*/
QETH_QDIO_BUF_PRIMED,
+ /*
+ * inbound: not applicable
+ * outbound: identified to be pending in TPQ
+ */
+ QETH_QDIO_BUF_PENDING,
+ /*
+ * inbound: not applicable
+ * outbound: found in completion queue
+ */
+ QETH_QDIO_BUF_IN_CQ,
+ /*
+ * inbound: not applicable
+ * outbound: handled via transfer pending / completion queue
+ */
+ QETH_QDIO_BUF_HANDLED_DELAYED,
};
enum qeth_qdio_info_states {
@@ -399,6 +421,7 @@ struct qeth_qdio_buffer {
struct qdio_buffer *buffer;
/* the buffer pool entry currently associated to this buffer */
struct qeth_buffer_pool_entry *pool_entry;
+ struct sk_buff *rx_skb;
};
struct qeth_qdio_q {
@@ -412,8 +435,11 @@ struct qeth_qdio_out_buffer {
atomic_t state;
int next_element_to_fill;
struct sk_buff_head skb_list;
- struct list_head ctx_list;
int is_header[16];
+
+ struct qaob *aob;
+ struct qeth_qdio_out_q *q;
+ struct qeth_qdio_out_buffer *next_pending;
};
struct qeth_card;
@@ -426,7 +452,8 @@ enum qeth_out_q_states {
struct qeth_qdio_out_q {
struct qdio_buffer qdio_bufs[QDIO_MAX_BUFFERS_PER_Q];
- struct qeth_qdio_out_buffer bufs[QDIO_MAX_BUFFERS_PER_Q];
+ struct qeth_qdio_out_buffer *bufs[QDIO_MAX_BUFFERS_PER_Q];
+ struct qdio_outbuf_state *bufstates; /* convenience pointer */
int queue_no;
struct qeth_card *card;
atomic_t state;
@@ -447,7 +474,9 @@ struct qeth_qdio_out_q {
struct qeth_qdio_info {
atomic_t state;
/* input */
+ int no_in_queues;
struct qeth_qdio_q *in_q;
+ struct qeth_qdio_q *c_q;
struct qeth_qdio_buffer_pool in_buf_pool;
struct qeth_qdio_buffer_pool init_pool;
int in_buf_size;
@@ -455,6 +484,7 @@ struct qeth_qdio_info {
/* output */
int no_out_queues;
struct qeth_qdio_out_q **out_qs;
+ struct qdio_outbuf_state *out_bufstates;
/* priority queueing */
int do_prio_queueing;
@@ -526,6 +556,12 @@ enum qeth_cmd_buffer_state {
BUF_STATE_PROCESSED,
};
+enum qeth_cq {
+ QETH_CQ_DISABLED = 0,
+ QETH_CQ_ENABLED = 1,
+ QETH_CQ_NOTAVAILABLE = 2,
+};
+
struct qeth_ipato {
int enabled;
int invert4;
@@ -650,6 +686,8 @@ struct qeth_card_options {
int rx_sg_cb;
enum qeth_ipa_isolation_modes isolation;
int sniffer;
+ enum qeth_cq cq;
+ char hsuid[9];
};
/*
@@ -747,6 +785,8 @@ struct qeth_card {
struct mutex discipline_mutex;
struct napi_struct napi;
struct qeth_rx rx;
+ struct delayed_work buffer_reclaim_work;
+ int reclaim_index;
};
struct qeth_card_list_struct {
@@ -812,6 +852,7 @@ int qeth_core_create_device_attributes(struct device *);
void qeth_core_remove_device_attributes(struct device *);
int qeth_core_create_osn_attributes(struct device *);
void qeth_core_remove_osn_attributes(struct device *);
+void qeth_buffer_reclaim_work(struct work_struct *);
/* exports for qeth discipline device drivers */
extern struct qeth_card_list_struct qeth_core_card_list;
@@ -840,7 +881,7 @@ int qeth_check_qdio_errors(struct qeth_card *, struct qdio_buffer *,
unsigned int, const char *);
void qeth_queue_input_buffer(struct qeth_card *, int);
struct sk_buff *qeth_core_get_next_skb(struct qeth_card *,
- struct qdio_buffer *, struct qdio_buffer_element **, int *,
+ struct qeth_qdio_buffer *, struct qdio_buffer_element **, int *,
struct qeth_hdr **);
void qeth_schedule_recovery(struct qeth_card *);
void qeth_qdio_start_poll(struct ccw_device *, int, unsigned long);
@@ -887,6 +928,7 @@ void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...);
int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *);
int qeth_set_access_ctrl_online(struct qeth_card *card);
int qeth_hdr_chk_and_bounce(struct sk_buff *, int);
+int qeth_configure_cq(struct qeth_card *, enum qeth_cq);
int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action);
int qeth_query_ipassists(struct qeth_card *, enum qeth_prot_versions prot);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 4550573c25e5..81534437373a 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -21,6 +21,7 @@
#include <linux/mii.h>
#include <linux/kthread.h>
#include <linux/slab.h>
+#include <net/iucv/af_iucv.h>
#include <asm/ebcdic.h>
#include <asm/io.h>
@@ -44,6 +45,7 @@ struct qeth_card_list_struct qeth_core_card_list;
EXPORT_SYMBOL_GPL(qeth_core_card_list);
struct kmem_cache *qeth_core_header_cache;
EXPORT_SYMBOL_GPL(qeth_core_header_cache);
+static struct kmem_cache *qeth_qdio_outbuf_cache;
static struct device *qeth_core_root_dev;
static unsigned int known_devices[][6] = QETH_MODELLIST_ARRAY;
@@ -56,6 +58,14 @@ static struct qeth_cmd_buffer *qeth_get_buffer(struct qeth_channel *);
static void qeth_setup_ccw(struct qeth_channel *, unsigned char *, __u32);
static void qeth_free_buffer_pool(struct qeth_card *);
static int qeth_qdio_establish(struct qeth_card *);
+static void qeth_free_qdio_buffers(struct qeth_card *);
+static void qeth_notify_skbs(struct qeth_qdio_out_q *queue,
+ struct qeth_qdio_out_buffer *buf,
+ enum iucv_tx_notify notification);
+static void qeth_release_skbs(struct qeth_qdio_out_buffer *buf);
+static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
+ struct qeth_qdio_out_buffer *buf,
+ enum qeth_qdio_buffer_states newbufstate);
static inline const char *qeth_get_cardname(struct qeth_card *card)
@@ -199,7 +209,7 @@ static int qeth_alloc_buffer_pool(struct qeth_card *card)
QETH_CARD_TEXT(card, 5, "alocpool");
for (i = 0; i < card->qdio.init_pool.buf_count; ++i) {
- pool_entry = kmalloc(sizeof(*pool_entry), GFP_KERNEL);
+ pool_entry = kzalloc(sizeof(*pool_entry), GFP_KERNEL);
if (!pool_entry) {
qeth_free_buffer_pool(card);
return -ENOMEM;
@@ -239,6 +249,196 @@ int qeth_realloc_buffer_pool(struct qeth_card *card, int bufcnt)
}
EXPORT_SYMBOL_GPL(qeth_realloc_buffer_pool);
+static inline int qeth_cq_init(struct qeth_card *card)
+{
+ int rc;
+
+ if (card->options.cq == QETH_CQ_ENABLED) {
+ QETH_DBF_TEXT(SETUP, 2, "cqinit");
+ memset(card->qdio.c_q->qdio_bufs, 0,
+ QDIO_MAX_BUFFERS_PER_Q * sizeof(struct qdio_buffer));
+ card->qdio.c_q->next_buf_to_init = 127;
+ rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT,
+ card->qdio.no_in_queues - 1, 0,
+ 127);
+ if (rc) {
+ QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
+ goto out;
+ }
+ }
+ rc = 0;
+out:
+ return rc;
+}
+
+static inline int qeth_alloc_cq(struct qeth_card *card)
+{
+ int rc;
+
+ if (card->options.cq == QETH_CQ_ENABLED) {
+ int i;
+ struct qdio_outbuf_state *outbuf_states;
+
+ QETH_DBF_TEXT(SETUP, 2, "cqon");
+ card->qdio.c_q = kzalloc(sizeof(struct qeth_qdio_q),
+ GFP_KERNEL);
+ if (!card->qdio.c_q) {
+ rc = -1;
+ goto kmsg_out;
+ }
+ QETH_DBF_HEX(SETUP, 2, &card->qdio.c_q, sizeof(void *));
+
+ for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; ++i) {
+ card->qdio.c_q->bufs[i].buffer =
+ &card->qdio.c_q->qdio_bufs[i];
+ }
+
+ card->qdio.no_in_queues = 2;
+
+ card->qdio.out_bufstates = (struct qdio_outbuf_state *)
+ kzalloc(card->qdio.no_out_queues *
+ QDIO_MAX_BUFFERS_PER_Q *
+ sizeof(struct qdio_outbuf_state), GFP_KERNEL);
+ outbuf_states = card->qdio.out_bufstates;
+ if (outbuf_states == NULL) {
+ rc = -1;
+ goto free_cq_out;
+ }
+ for (i = 0; i < card->qdio.no_out_queues; ++i) {
+ card->qdio.out_qs[i]->bufstates = outbuf_states;
+ outbuf_states += QDIO_MAX_BUFFERS_PER_Q;
+ }
+ } else {
+ QETH_DBF_TEXT(SETUP, 2, "nocq");
+ card->qdio.c_q = NULL;
+ card->qdio.no_in_queues = 1;
+ }
+ QETH_DBF_TEXT_(SETUP, 2, "iqc%d", card->qdio.no_in_queues);
+ rc = 0;
+out:
+ return rc;
+free_cq_out:
+ kfree(card->qdio.c_q);
+ card->qdio.c_q = NULL;
+kmsg_out:
+ dev_err(&card->gdev->dev, "Failed to create completion queue\n");
+ goto out;
+}
+
+static inline void qeth_free_cq(struct qeth_card *card)
+{
+ if (card->qdio.c_q) {
+ --card->qdio.no_in_queues;
+ kfree(card->qdio.c_q);
+ card->qdio.c_q = NULL;
+ }
+ kfree(card->qdio.out_bufstates);
+ card->qdio.out_bufstates = NULL;
+}
+
+static inline enum iucv_tx_notify qeth_compute_cq_notification(int sbalf15,
+ int delayed) {
+ enum iucv_tx_notify n;
+
+ switch (sbalf15) {
+ case 0:
+ n = delayed ? TX_NOTIFY_DELAYED_OK : TX_NOTIFY_OK;
+ break;
+ case 4:
+ case 16:
+ case 17:
+ case 18:
+ n = delayed ? TX_NOTIFY_DELAYED_UNREACHABLE :
+ TX_NOTIFY_UNREACHABLE;
+ break;
+ default:
+ n = delayed ? TX_NOTIFY_DELAYED_GENERALERROR :
+ TX_NOTIFY_GENERALERROR;
+ break;
+ }
+
+ return n;
+}
+
+static inline void qeth_cleanup_handled_pending(struct qeth_qdio_out_q *q,
+ int bidx, int forced_cleanup)
+{
+ if (q->bufs[bidx]->next_pending != NULL) {
+ struct qeth_qdio_out_buffer *head = q->bufs[bidx];
+ struct qeth_qdio_out_buffer *c = q->bufs[bidx]->next_pending;
+
+ while (c) {
+ if (forced_cleanup ||
+ atomic_read(&c->state) ==
+ QETH_QDIO_BUF_HANDLED_DELAYED) {
+ struct qeth_qdio_out_buffer *f = c;
+ QETH_CARD_TEXT(f->q->card, 5, "fp");
+ QETH_CARD_TEXT_(f->q->card, 5, "%lx", (long) f);
+ /* release here to avoid interleaving between
+ outbound tasklet and inbound tasklet
+ regarding notifications and lifecycle */
+ qeth_release_skbs(c);
+
+ c = f->next_pending;
+ BUG_ON(head->next_pending != f);
+ head->next_pending = c;
+ kmem_cache_free(qeth_qdio_outbuf_cache, f);
+ } else {
+ head = c;
+ c = c->next_pending;
+ }
+
+ }
+ }
+}
+
+
+static inline void qeth_qdio_handle_aob(struct qeth_card *card,
+ unsigned long phys_aob_addr) {
+ struct qaob *aob;
+ struct qeth_qdio_out_buffer *buffer;
+ enum iucv_tx_notify notification;
+
+ aob = (struct qaob *) phys_to_virt(phys_aob_addr);
+ QETH_CARD_TEXT(card, 5, "haob");
+ QETH_CARD_TEXT_(card, 5, "%lx", phys_aob_addr);
+ buffer = (struct qeth_qdio_out_buffer *) aob->user1;
+ QETH_CARD_TEXT_(card, 5, "%lx", aob->user1);
+
+ BUG_ON(buffer == NULL);
+
+ if (atomic_cmpxchg(&buffer->state, QETH_QDIO_BUF_PRIMED,
+ QETH_QDIO_BUF_IN_CQ) == QETH_QDIO_BUF_PRIMED) {
+ notification = TX_NOTIFY_OK;
+ } else {
+ BUG_ON(atomic_read(&buffer->state) != QETH_QDIO_BUF_PENDING);
+
+ atomic_set(&buffer->state, QETH_QDIO_BUF_IN_CQ);
+ notification = TX_NOTIFY_DELAYED_OK;
+ }
+
+ if (aob->aorc != 0) {
+ QETH_CARD_TEXT_(card, 2, "aorc%02X", aob->aorc);
+ notification = qeth_compute_cq_notification(aob->aorc, 1);
+ }
+ qeth_notify_skbs(buffer->q, buffer, notification);
+
+ buffer->aob = NULL;
+ qeth_clear_output_buffer(buffer->q, buffer,
+ QETH_QDIO_BUF_HANDLED_DELAYED);
+ /* from here on: do not touch buffer anymore */
+ qdio_release_aob(aob);
+}
+
+static inline int qeth_is_cq(struct qeth_card *card, unsigned int queue)
+{
+ return card->options.cq == QETH_CQ_ENABLED &&
+ card->qdio.c_q != NULL &&
+ queue != 0 &&
+ queue == card->qdio.no_in_queues - 1;
+}
+
+
static int qeth_issue_next_read(struct qeth_card *card)
{
int rc;
@@ -589,7 +789,7 @@ static int qeth_setup_channel(struct qeth_channel *channel)
QETH_DBF_TEXT(SETUP, 2, "setupch");
for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++) {
channel->iob[cnt].data =
- kmalloc(QETH_BUFSIZE, GFP_DMA|GFP_KERNEL);
+ kzalloc(QETH_BUFSIZE, GFP_DMA|GFP_KERNEL);
if (channel->iob[cnt].data == NULL)
break;
channel->iob[cnt].state = BUF_STATE_FREE;
@@ -681,6 +881,7 @@ EXPORT_SYMBOL_GPL(qeth_do_run_thread);
void qeth_schedule_recovery(struct qeth_card *card)
{
QETH_CARD_TEXT(card, 2, "startrec");
+ WARN_ON(1);
if (qeth_set_thread_start_bit(card, QETH_RECOVER_THREAD) == 0)
schedule_work(&card->kernel_thread_starter);
}
@@ -883,22 +1084,60 @@ out:
return;
}
-static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
- struct qeth_qdio_out_buffer *buf)
+static void qeth_notify_skbs(struct qeth_qdio_out_q *q,
+ struct qeth_qdio_out_buffer *buf,
+ enum iucv_tx_notify notification)
{
- int i;
struct sk_buff *skb;
- /* is PCI flag set on buffer? */
- if (buf->buffer->element[0].sflags & SBAL_SFLAGS0_PCI_REQ)
- atomic_dec(&queue->set_pci_flags_count);
+ if (skb_queue_empty(&buf->skb_list))
+ goto out;
+ skb = skb_peek(&buf->skb_list);
+ while (skb) {
+ QETH_CARD_TEXT_(q->card, 5, "skbn%d", notification);
+ QETH_CARD_TEXT_(q->card, 5, "%lx", (long) skb);
+ if (skb->protocol == ETH_P_AF_IUCV) {
+ if (skb->sk) {
+ struct iucv_sock *iucv = iucv_sk(skb->sk);
+ iucv->sk_txnotify(skb, notification);
+ }
+ }
+ if (skb_queue_is_last(&buf->skb_list, skb))
+ skb = NULL;
+ else
+ skb = skb_queue_next(&buf->skb_list, skb);
+ }
+out:
+ return;
+}
+
+static void qeth_release_skbs(struct qeth_qdio_out_buffer *buf)
+{
+ struct sk_buff *skb;
skb = skb_dequeue(&buf->skb_list);
while (skb) {
+ QETH_CARD_TEXT(buf->q->card, 5, "skbr");
+ QETH_CARD_TEXT_(buf->q->card, 5, "%lx", (long) skb);
atomic_dec(&skb->users);
dev_kfree_skb_any(skb);
skb = skb_dequeue(&buf->skb_list);
}
+}
+
+static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
+ struct qeth_qdio_out_buffer *buf,
+ enum qeth_qdio_buffer_states newbufstate)
+{
+ int i;
+
+ /* is PCI flag set on buffer? */
+ if (buf->buffer->element[0].sflags & SBAL_SFLAGS0_PCI_REQ)
+ atomic_dec(&queue->set_pci_flags_count);
+
+ if (newbufstate == QETH_QDIO_BUF_EMPTY) {
+ qeth_release_skbs(buf);
+ }
for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(queue->card); ++i) {
if (buf->buffer->element[i].addr && buf->is_header[i])
kmem_cache_free(qeth_core_header_cache,
@@ -912,21 +1151,36 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
buf->buffer->element[15].eflags = 0;
buf->buffer->element[15].sflags = 0;
buf->next_element_to_fill = 0;
- atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY);
+ atomic_set(&buf->state, newbufstate);
+}
+
+static void qeth_clear_outq_buffers(struct qeth_qdio_out_q *q, int free)
+{
+ int j;
+
+ for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) {
+ if (!q->bufs[j])
+ continue;
+ qeth_cleanup_handled_pending(q, j, free);
+ qeth_clear_output_buffer(q, q->bufs[j], QETH_QDIO_BUF_EMPTY);
+ if (free) {
+ kmem_cache_free(qeth_qdio_outbuf_cache, q->bufs[j]);
+ q->bufs[j] = NULL;
+ }
+ }
}
void qeth_clear_qdio_buffers(struct qeth_card *card)
{
- int i, j;
+ int i;
QETH_CARD_TEXT(card, 2, "clearqdbf");
/* clear outbound buffers to free skbs */
- for (i = 0; i < card->qdio.no_out_queues; ++i)
+ for (i = 0; i < card->qdio.no_out_queues; ++i) {
if (card->qdio.out_qs[i]) {
- for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j)
- qeth_clear_output_buffer(card->qdio.out_qs[i],
- &card->qdio.out_qs[i]->bufs[j]);
+ qeth_clear_outq_buffers(card->qdio.out_qs[i], 0);
}
+ }
}
EXPORT_SYMBOL_GPL(qeth_clear_qdio_buffers);
@@ -950,6 +1204,11 @@ static void qeth_free_qdio_buffers(struct qeth_card *card)
if (atomic_xchg(&card->qdio.state, QETH_QDIO_UNINITIALIZED) ==
QETH_QDIO_UNINITIALIZED)
return;
+
+ qeth_free_cq(card);
+ cancel_delayed_work_sync(&card->buffer_reclaim_work);
+ for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j)
+ kfree_skb(card->qdio.in_q->bufs[j].rx_skb);
kfree(card->qdio.in_q);
card->qdio.in_q = NULL;
/* inbound buffer pool */
@@ -957,9 +1216,7 @@ static void qeth_free_qdio_buffers(struct qeth_card *card)
/* free outbound qdio_qs */
if (card->qdio.out_qs) {
for (i = 0; i < card->qdio.no_out_queues; ++i) {
- for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j)
- qeth_clear_output_buffer(card->qdio.out_qs[i],
- &card->qdio.out_qs[i]->bufs[j]);
+ qeth_clear_outq_buffers(card->qdio.out_qs[i], 1);
kfree(card->qdio.out_qs[i]);
}
kfree(card->qdio.out_qs);
@@ -995,27 +1252,29 @@ static void qeth_get_channel_path_desc(struct qeth_card *card)
ccwdev = card->data.ccwdev;
chp_dsc = (struct channelPath_dsc *)ccw_device_get_chp_desc(ccwdev, 0);
if (chp_dsc != NULL) {
- /* CHPP field bit 6 == 1 -> single queue */
- if ((chp_dsc->chpp & 0x02) == 0x02) {
- if ((atomic_read(&card->qdio.state) !=
- QETH_QDIO_UNINITIALIZED) &&
- (card->qdio.no_out_queues == 4))
- /* change from 4 to 1 outbound queues */
- qeth_free_qdio_buffers(card);
- card->qdio.no_out_queues = 1;
- if (card->qdio.default_out_queue != 0)
- dev_info(&card->gdev->dev,
+ if (card->info.type != QETH_CARD_TYPE_IQD) {
+ /* CHPP field bit 6 == 1 -> single queue */
+ if ((chp_dsc->chpp & 0x02) == 0x02) {
+ if ((atomic_read(&card->qdio.state) !=
+ QETH_QDIO_UNINITIALIZED) &&
+ (card->qdio.no_out_queues == 4))
+ /* change from 4 to 1 outbound queues */
+ qeth_free_qdio_buffers(card);
+ card->qdio.no_out_queues = 1;
+ if (card->qdio.default_out_queue != 0)
+ dev_info(&card->gdev->dev,
"Priority Queueing not supported\n");
- card->qdio.default_out_queue = 0;
- } else {
- if ((atomic_read(&card->qdio.state) !=
- QETH_QDIO_UNINITIALIZED) &&
- (card->qdio.no_out_queues == 1)) {
- /* change from 1 to 4 outbound queues */
- qeth_free_qdio_buffers(card);
- card->qdio.default_out_queue = 2;
+ card->qdio.default_out_queue = 0;
+ } else {
+ if ((atomic_read(&card->qdio.state) !=
+ QETH_QDIO_UNINITIALIZED) &&
+ (card->qdio.no_out_queues == 1)) {
+ /* change from 1 to 4 outbound queues */
+ qeth_free_qdio_buffers(card);
+ card->qdio.default_out_queue = 2;
+ }
+ card->qdio.no_out_queues = 4;
}
- card->qdio.no_out_queues = 4;
}
card->info.func_level = 0x4100 + chp_dsc->desc;
kfree(chp_dsc);
@@ -1051,6 +1310,7 @@ static void qeth_set_intial_options(struct qeth_card *card)
card->options.performance_stats = 0;
card->options.rx_sg_cb = QETH_RX_SG_CB;
card->options.isolation = ISOLATION_MODE_NONE;
+ card->options.cq = QETH_CQ_DISABLED;
}
static int qeth_do_start_thread(struct qeth_card *card, unsigned long thread)
@@ -1119,6 +1379,7 @@ static int qeth_setup_card(struct qeth_card *card)
card->ipato.invert6 = 0;
/* init QDIO stuff */
qeth_init_qdio_info(card);
+ INIT_DELAYED_WORK(&card->buffer_reclaim_work, qeth_buffer_reclaim_work);
return 0;
}
@@ -1140,7 +1401,7 @@ static struct qeth_card *qeth_alloc_card(void)
if (!card)
goto out;
QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
- card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL);
+ card->ip_tbd_list = kzalloc(sizeof(struct list_head), GFP_KERNEL);
if (!card->ip_tbd_list) {
QETH_DBF_TEXT(SETUP, 0, "iptbdnom");
goto out_card;
@@ -1180,6 +1441,7 @@ static int qeth_determine_card_type(struct qeth_card *card)
card->info.type = known_devices[i][QETH_DEV_MODEL_IND];
card->qdio.no_out_queues =
known_devices[i][QETH_QUEUE_NO_IND];
+ card->qdio.no_in_queues = 1;
card->info.is_multicast_different =
known_devices[i][QETH_MULTICAST_IND];
qeth_get_channel_path_desc(card);
@@ -2027,6 +2289,37 @@ static int qeth_ulp_setup(struct qeth_card *card)
return rc;
}
+static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *q, int bidx)
+{
+ int rc;
+ struct qeth_qdio_out_buffer *newbuf;
+
+ rc = 0;
+ newbuf = kmem_cache_zalloc(qeth_qdio_outbuf_cache, GFP_ATOMIC);
+ if (!newbuf) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ newbuf->buffer = &q->qdio_bufs[bidx];
+ skb_queue_head_init(&newbuf->skb_list);
+ lockdep_set_class(&newbuf->skb_list.lock, &qdio_out_skb_queue_key);
+ newbuf->q = q;
+ newbuf->aob = NULL;
+ newbuf->next_pending = q->bufs[bidx];
+ atomic_set(&newbuf->state, QETH_QDIO_BUF_EMPTY);
+ q->bufs[bidx] = newbuf;
+ if (q->bufstates) {
+ q->bufstates[bidx].user = newbuf;
+ QETH_CARD_TEXT_(q->card, 2, "nbs%d", bidx);
+ QETH_CARD_TEXT_(q->card, 2, "%lx", (long) newbuf);
+ QETH_CARD_TEXT_(q->card, 2, "%lx",
+ (long) newbuf->next_pending);
+ }
+out:
+ return rc;
+}
+
+
static int qeth_alloc_qdio_buffers(struct qeth_card *card)
{
int i, j;
@@ -2037,52 +2330,63 @@ static int qeth_alloc_qdio_buffers(struct qeth_card *card)
QETH_QDIO_ALLOCATED) != QETH_QDIO_UNINITIALIZED)
return 0;
- card->qdio.in_q = kmalloc(sizeof(struct qeth_qdio_q),
- GFP_KERNEL);
+ card->qdio.in_q = kzalloc(sizeof(struct qeth_qdio_q),
+ GFP_KERNEL);
if (!card->qdio.in_q)
goto out_nomem;
QETH_DBF_TEXT(SETUP, 2, "inq");
QETH_DBF_HEX(SETUP, 2, &card->qdio.in_q, sizeof(void *));
memset(card->qdio.in_q, 0, sizeof(struct qeth_qdio_q));
/* give inbound qeth_qdio_buffers their qdio_buffers */
- for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; ++i)
+ for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; ++i) {
card->qdio.in_q->bufs[i].buffer =
&card->qdio.in_q->qdio_bufs[i];
+ card->qdio.in_q->bufs[i].rx_skb = NULL;
+ }
/* inbound buffer pool */
if (qeth_alloc_buffer_pool(card))
goto out_freeinq;
+
/* outbound */
card->qdio.out_qs =
- kmalloc(card->qdio.no_out_queues *
+ kzalloc(card->qdio.no_out_queues *
sizeof(struct qeth_qdio_out_q *), GFP_KERNEL);
if (!card->qdio.out_qs)
goto out_freepool;
for (i = 0; i < card->qdio.no_out_queues; ++i) {
- card->qdio.out_qs[i] = kmalloc(sizeof(struct qeth_qdio_out_q),
+ card->qdio.out_qs[i] = kzalloc(sizeof(struct qeth_qdio_out_q),
GFP_KERNEL);
if (!card->qdio.out_qs[i])
goto out_freeoutq;
QETH_DBF_TEXT_(SETUP, 2, "outq %i", i);
QETH_DBF_HEX(SETUP, 2, &card->qdio.out_qs[i], sizeof(void *));
- memset(card->qdio.out_qs[i], 0, sizeof(struct qeth_qdio_out_q));
card->qdio.out_qs[i]->queue_no = i;
/* give outbound qeth_qdio_buffers their qdio_buffers */
for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) {
- card->qdio.out_qs[i]->bufs[j].buffer =
- &card->qdio.out_qs[i]->qdio_bufs[j];
- skb_queue_head_init(&card->qdio.out_qs[i]->bufs[j].
- skb_list);
- lockdep_set_class(
- &card->qdio.out_qs[i]->bufs[j].skb_list.lock,
- &qdio_out_skb_queue_key);
- INIT_LIST_HEAD(&card->qdio.out_qs[i]->bufs[j].ctx_list);
+ BUG_ON(card->qdio.out_qs[i]->bufs[j] != NULL);
+ if (qeth_init_qdio_out_buf(card->qdio.out_qs[i], j))
+ goto out_freeoutqbufs;
}
}
+
+ /* completion */
+ if (qeth_alloc_cq(card))
+ goto out_freeoutq;
+
return 0;
+out_freeoutqbufs:
+ while (j > 0) {
+ --j;
+ kmem_cache_free(qeth_qdio_outbuf_cache,
+ card->qdio.out_qs[i]->bufs[j]);
+ card->qdio.out_qs[i]->bufs[j] = NULL;
+ }
out_freeoutq:
- while (i > 0)
+ while (i > 0) {
kfree(card->qdio.out_qs[--i]);
+ qeth_clear_outq_buffers(card->qdio.out_qs[i], 1);
+ }
kfree(card->qdio.out_qs);
card->qdio.out_qs = NULL;
out_freepool:
@@ -2353,6 +2657,12 @@ static int qeth_init_input_buffer(struct qeth_card *card,
struct qeth_buffer_pool_entry *pool_entry;
int i;
+ if ((card->options.cq == QETH_CQ_ENABLED) && (!buf->rx_skb)) {
+ buf->rx_skb = dev_alloc_skb(QETH_RX_PULL_LEN + ETH_HLEN);
+ if (!buf->rx_skb)
+ return 1;
+ }
+
pool_entry = qeth_find_free_buffer_pool_entry(card);
if (!pool_entry)
return 1;
@@ -2399,13 +2709,21 @@ int qeth_init_qdio_queues(struct qeth_card *card)
QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
return rc;
}
+
+ /* completion */
+ rc = qeth_cq_init(card);
+ if (rc) {
+ return rc;
+ }
+
/* outbound queue */
for (i = 0; i < card->qdio.no_out_queues; ++i) {
memset(card->qdio.out_qs[i]->qdio_bufs, 0,
QDIO_MAX_BUFFERS_PER_Q * sizeof(struct qdio_buffer));
for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) {
qeth_clear_output_buffer(card->qdio.out_qs[i],
- &card->qdio.out_qs[i]->bufs[j]);
+ card->qdio.out_qs[i]->bufs[j],
+ QETH_QDIO_BUF_EMPTY);
}
card->qdio.out_qs[i]->card = card;
card->qdio.out_qs[i]->next_buf_to_fill = 0;
@@ -2734,9 +3052,19 @@ int qeth_check_qdio_errors(struct qeth_card *card, struct qdio_buffer *buf,
}
EXPORT_SYMBOL_GPL(qeth_check_qdio_errors);
+void qeth_buffer_reclaim_work(struct work_struct *work)
+{
+ struct qeth_card *card = container_of(work, struct qeth_card,
+ buffer_reclaim_work.work);
+
+ QETH_CARD_TEXT_(card, 2, "brw:%x", card->reclaim_index);
+ qeth_queue_input_buffer(card, card->reclaim_index);
+}
+
void qeth_queue_input_buffer(struct qeth_card *card, int index)
{
struct qeth_qdio_q *queue = card->qdio.in_q;
+ struct list_head *lh;
int count;
int i;
int rc;
@@ -2768,6 +3096,20 @@ void qeth_queue_input_buffer(struct qeth_card *card, int index)
atomic_add_unless(&card->force_alloc_skb, -1, 0);
}
+ if (!count) {
+ i = 0;
+ list_for_each(lh, &card->qdio.in_buf_pool.entry_list)
+ i++;
+ if (i == card->qdio.in_buf_pool.buf_count) {
+ QETH_CARD_TEXT(card, 2, "qsarbw");
+ card->reclaim_index = index;
+ schedule_delayed_work(
+ &card->buffer_reclaim_work,
+ QETH_RECLAIM_WORK_TIME);
+ }
+ return;
+ }
+
/*
* according to old code it should be avoided to requeue all
* 128 buffers in order to benefit from PCI avoidance.
@@ -2787,8 +3129,6 @@ void qeth_queue_input_buffer(struct qeth_card *card, int index)
qeth_get_micros() -
card->perf_stats.inbound_do_qdio_start_time;
if (rc) {
- dev_warn(&card->gdev->dev,
- "QDIO reported an error, rc=%i\n", rc);
QETH_CARD_TEXT(card, 2, "qinberr");
}
queue->next_buf_to_init = (queue->next_buf_to_init + count) %
@@ -2862,12 +3202,12 @@ static int qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue)
queue->card->perf_stats.sc_p_dp++;
queue->do_pack = 0;
/* flush packing buffers */
- buffer = &queue->bufs[queue->next_buf_to_fill];
+ buffer = queue->bufs[queue->next_buf_to_fill];
if ((atomic_read(&buffer->state) ==
QETH_QDIO_BUF_EMPTY) &&
(buffer->next_element_to_fill > 0)) {
atomic_set(&buffer->state,
- QETH_QDIO_BUF_PRIMED);
+ QETH_QDIO_BUF_PRIMED);
flush_count++;
queue->next_buf_to_fill =
(queue->next_buf_to_fill + 1) %
@@ -2878,6 +3218,7 @@ static int qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue)
return flush_count;
}
+
/*
* Called to flush a packing buffer if no more pci flags are on the queue.
* Checks if there is a packing buffer and prepares it to be flushed.
@@ -2887,7 +3228,7 @@ static int qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue)
{
struct qeth_qdio_out_buffer *buffer;
- buffer = &queue->bufs[queue->next_buf_to_fill];
+ buffer = queue->bufs[queue->next_buf_to_fill];
if ((atomic_read(&buffer->state) == QETH_QDIO_BUF_EMPTY) &&
(buffer->next_element_to_fill > 0)) {
/* it's a packing buffer */
@@ -2908,10 +3249,14 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
unsigned int qdio_flags;
for (i = index; i < index + count; ++i) {
- buf = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q];
+ int bidx = i % QDIO_MAX_BUFFERS_PER_Q;
+ buf = queue->bufs[bidx];
buf->buffer->element[buf->next_element_to_fill - 1].eflags |=
SBAL_EFLAGS_LAST_ENTRY;
+ if (queue->bufstates)
+ queue->bufstates[bidx].user = buf;
+
if (queue->card->info.type == QETH_CARD_TYPE_IQD)
continue;
@@ -2963,6 +3308,9 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
if (rc == QDIO_ERROR_SIGA_TARGET)
return;
QETH_CARD_TEXT(queue->card, 2, "flushbuf");
+ QETH_CARD_TEXT_(queue->card, 2, " q%d", queue->queue_no);
+ QETH_CARD_TEXT_(queue->card, 2, " idx%d", index);
+ QETH_CARD_TEXT_(queue->card, 2, " c%d", count);
QETH_CARD_TEXT_(queue->card, 2, " err%d", rc);
/* this must not happen under normal circumstances. if it
@@ -3024,14 +3372,120 @@ void qeth_qdio_start_poll(struct ccw_device *ccwdev, int queue,
}
EXPORT_SYMBOL_GPL(qeth_qdio_start_poll);
+int qeth_configure_cq(struct qeth_card *card, enum qeth_cq cq)
+{
+ int rc;
+
+ if (card->options.cq == QETH_CQ_NOTAVAILABLE) {
+ rc = -1;
+ goto out;
+ } else {
+ if (card->options.cq == cq) {
+ rc = 0;
+ goto out;
+ }
+
+ if (card->state != CARD_STATE_DOWN &&
+ card->state != CARD_STATE_RECOVER) {
+ rc = -1;
+ goto out;
+ }
+
+ qeth_free_qdio_buffers(card);
+ card->options.cq = cq;
+ rc = 0;
+ }
+out:
+ return rc;
+
+}
+EXPORT_SYMBOL_GPL(qeth_configure_cq);
+
+
+static void qeth_qdio_cq_handler(struct qeth_card *card,
+ unsigned int qdio_err,
+ unsigned int queue, int first_element, int count) {
+ struct qeth_qdio_q *cq = card->qdio.c_q;
+ int i;
+ int rc;
+
+ if (!qeth_is_cq(card, queue))
+ goto out;
+
+ QETH_CARD_TEXT_(card, 5, "qcqhe%d", first_element);
+ QETH_CARD_TEXT_(card, 5, "qcqhc%d", count);
+ QETH_CARD_TEXT_(card, 5, "qcqherr%d", qdio_err);
+
+ if (qdio_err) {
+ netif_stop_queue(card->dev);
+ qeth_schedule_recovery(card);
+ goto out;
+ }
+
+ if (card->options.performance_stats) {
+ card->perf_stats.cq_cnt++;
+ card->perf_stats.cq_start_time = qeth_get_micros();
+ }
+
+ for (i = first_element; i < first_element + count; ++i) {
+ int bidx = i % QDIO_MAX_BUFFERS_PER_Q;
+ struct qdio_buffer *buffer = &cq->qdio_bufs[bidx];
+ int e;
+
+ e = 0;
+ while (buffer->element[e].addr) {
+ unsigned long phys_aob_addr;
+
+ phys_aob_addr = (unsigned long) buffer->element[e].addr;
+ qeth_qdio_handle_aob(card, phys_aob_addr);
+ buffer->element[e].addr = NULL;
+ buffer->element[e].eflags = 0;
+ buffer->element[e].sflags = 0;
+ buffer->element[e].length = 0;
+
+ ++e;
+ }
+
+ buffer->element[15].eflags = 0;
+ buffer->element[15].sflags = 0;
+ }
+ rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, queue,
+ card->qdio.c_q->next_buf_to_init,
+ count);
+ if (rc) {
+ dev_warn(&card->gdev->dev,
+ "QDIO reported an error, rc=%i\n", rc);
+ QETH_CARD_TEXT(card, 2, "qcqherr");
+ }
+ card->qdio.c_q->next_buf_to_init = (card->qdio.c_q->next_buf_to_init
+ + count) % QDIO_MAX_BUFFERS_PER_Q;
+
+ netif_wake_queue(card->dev);
+
+ if (card->options.performance_stats) {
+ int delta_t = qeth_get_micros();
+ delta_t -= card->perf_stats.cq_start_time;
+ card->perf_stats.cq_time += delta_t;
+ }
+out:
+ return;
+}
+
void qeth_qdio_input_handler(struct ccw_device *ccwdev, unsigned int qdio_err,
- unsigned int queue, int first_element, int count,
+ unsigned int queue, int first_elem, int count,
unsigned long card_ptr)
{
struct qeth_card *card = (struct qeth_card *)card_ptr;
- if (qdio_err)
+ QETH_CARD_TEXT_(card, 2, "qihq%d", queue);
+ QETH_CARD_TEXT_(card, 2, "qiec%d", qdio_err);
+
+ if (qeth_is_cq(card, queue))
+ qeth_qdio_cq_handler(card, qdio_err, queue, first_elem, count);
+ else if (qdio_err)
qeth_schedule_recovery(card);
+
+
}
EXPORT_SYMBOL_GPL(qeth_qdio_input_handler);
@@ -3057,9 +3511,45 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev,
qeth_get_micros();
}
for (i = first_element; i < (first_element + count); ++i) {
- buffer = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q];
+ int bidx = i % QDIO_MAX_BUFFERS_PER_Q;
+ buffer = queue->bufs[bidx];
qeth_handle_send_error(card, buffer, qdio_error);
- qeth_clear_output_buffer(queue, buffer);
+
+ if (queue->bufstates &&
+ (queue->bufstates[bidx].flags &
+ QDIO_OUTBUF_STATE_FLAG_PENDING) != 0) {
+ BUG_ON(card->options.cq != QETH_CQ_ENABLED);
+
+ if (atomic_cmpxchg(&buffer->state,
+ QETH_QDIO_BUF_PRIMED,
+ QETH_QDIO_BUF_PENDING) ==
+ QETH_QDIO_BUF_PRIMED) {
+ qeth_notify_skbs(queue, buffer,
+ TX_NOTIFY_PENDING);
+ }
+ buffer->aob = queue->bufstates[bidx].aob;
+ QETH_CARD_TEXT_(queue->card, 5, "pel%d", bidx);
+ QETH_CARD_TEXT(queue->card, 5, "aob");
+ QETH_CARD_TEXT_(queue->card, 5, "%lx",
+ virt_to_phys(buffer->aob));
+ BUG_ON(bidx < 0 || bidx >= QDIO_MAX_BUFFERS_PER_Q);
+ if (qeth_init_qdio_out_buf(queue, bidx)) {
+ QETH_CARD_TEXT(card, 2, "outofbuf");
+ qeth_schedule_recovery(card);
+ }
+ } else {
+ if (card->options.cq == QETH_CQ_ENABLED) {
+ enum iucv_tx_notify n;
+
+ n = qeth_compute_cq_notification(
+ buffer->buffer->element[15].sflags, 0);
+ qeth_notify_skbs(queue, buffer, n);
+ }
+
+ qeth_clear_output_buffer(queue, buffer,
+ QETH_QDIO_BUF_EMPTY);
+ }
+ qeth_cleanup_handled_pending(queue, bidx, 0);
}
atomic_sub(count, &queue->used_buffers);
/* check if we need to do something on this outbound queue */
@@ -3204,7 +3694,8 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb,
for (cnt = 0; cnt < skb_shinfo(skb)->nr_frags; cnt++) {
frag = &skb_shinfo(skb)->frags[cnt];
- buffer->element[element].addr = (char *)page_to_phys(frag->page)
+ buffer->element[element].addr = (char *)
+ page_to_phys(skb_frag_page(frag))
+ frag->page_offset;
buffer->element[element].length = frag->size;
buffer->element[element].eflags = SBAL_EFLAGS_MIDDLE_FRAG;
@@ -3291,7 +3782,7 @@ int qeth_do_send_packet_fast(struct qeth_card *card,
QETH_OUT_Q_LOCKED) != QETH_OUT_Q_UNLOCKED);
/* ... now we've got the queue */
index = queue->next_buf_to_fill;
- buffer = &queue->bufs[queue->next_buf_to_fill];
+ buffer = queue->bufs[queue->next_buf_to_fill];
/*
* check if buffer is empty to make sure that we do not 'overtake'
* ourselves and try to fill a buffer that is already primed
@@ -3325,7 +3816,7 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
while (atomic_cmpxchg(&queue->state, QETH_OUT_Q_UNLOCKED,
QETH_OUT_Q_LOCKED) != QETH_OUT_Q_UNLOCKED);
start_index = queue->next_buf_to_fill;
- buffer = &queue->bufs[queue->next_buf_to_fill];
+ buffer = queue->bufs[queue->next_buf_to_fill];
/*
* check if buffer is empty to make sure that we do not 'overtake'
* ourselves and try to fill a buffer that is already primed
@@ -3347,7 +3838,7 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
queue->next_buf_to_fill =
(queue->next_buf_to_fill + 1) %
QDIO_MAX_BUFFERS_PER_Q;
- buffer = &queue->bufs[queue->next_buf_to_fill];
+ buffer = queue->bufs[queue->next_buf_to_fill];
/* we did a step forward, so check buffer state
* again */
if (atomic_read(&buffer->state) !=
@@ -3925,6 +4416,20 @@ static void qeth_determine_capabilities(struct qeth_card *card)
if (rc)
QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc);
+ QETH_DBF_TEXT_(SETUP, 2, "qfmt%d", card->ssqd.qfmt);
+ QETH_DBF_TEXT_(SETUP, 2, "%d", card->ssqd.qdioac1);
+ QETH_DBF_TEXT_(SETUP, 2, "%d", card->ssqd.qdioac3);
+ QETH_DBF_TEXT_(SETUP, 2, "icnt%d", card->ssqd.icnt);
+ if (!((card->ssqd.qfmt != QDIO_IQDIO_QFMT) ||
+ ((card->ssqd.qdioac1 & CHSC_AC1_INITIATE_INPUTQ) == 0) ||
+ ((card->ssqd.qdioac3 & CHSC_AC3_FORMAT2_CQ_AVAILABLE) == 0))) {
+ dev_info(&card->gdev->dev,
+ "Completion Queueing supported\n");
+ } else {
+ card->options.cq = QETH_CQ_NOTAVAILABLE;
+ }
+
+
out_offline:
if (ddev_offline == 1)
ccw_device_set_offline(ddev);
@@ -3932,11 +4437,30 @@ out:
return;
}
+static inline void qeth_qdio_establish_cq(struct qeth_card *card,
+ struct qdio_buffer **in_sbal_ptrs,
+ void (**queue_start_poll) (struct ccw_device *, int, unsigned long)) {
+ int i;
+
+ if (card->options.cq == QETH_CQ_ENABLED) {
+ int offset = QDIO_MAX_BUFFERS_PER_Q *
+ (card->qdio.no_in_queues - 1);
+ i = QDIO_MAX_BUFFERS_PER_Q * (card->qdio.no_in_queues - 1);
+ for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; ++i) {
+ in_sbal_ptrs[offset + i] = (struct qdio_buffer *)
+ virt_to_phys(card->qdio.c_q->bufs[i].buffer);
+ }
+
+ queue_start_poll[card->qdio.no_in_queues - 1] = NULL;
+ }
+}
+
static int qeth_qdio_establish(struct qeth_card *card)
{
struct qdio_initialize init_data;
char *qib_param_field;
struct qdio_buffer **in_sbal_ptrs;
+ void (**queue_start_poll) (struct ccw_device *, int, unsigned long);
struct qdio_buffer **out_sbal_ptrs;
int i, j, k;
int rc = 0;
@@ -3945,34 +4469,48 @@ static int qeth_qdio_establish(struct qeth_card *card)
qib_param_field = kzalloc(QDIO_MAX_BUFFERS_PER_Q * sizeof(char),
GFP_KERNEL);
- if (!qib_param_field)
- return -ENOMEM;
+ if (!qib_param_field) {
+ rc = -ENOMEM;
+ goto out_free_nothing;
+ }
qeth_create_qib_param_field(card, qib_param_field);
qeth_create_qib_param_field_blkt(card, qib_param_field);
- in_sbal_ptrs = kmalloc(QDIO_MAX_BUFFERS_PER_Q * sizeof(void *),
+ in_sbal_ptrs = kzalloc(card->qdio.no_in_queues *
+ QDIO_MAX_BUFFERS_PER_Q * sizeof(void *),
GFP_KERNEL);
if (!in_sbal_ptrs) {
- kfree(qib_param_field);
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto out_free_qib_param;
}
- for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; ++i)
+ for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; ++i) {
in_sbal_ptrs[i] = (struct qdio_buffer *)
virt_to_phys(card->qdio.in_q->bufs[i].buffer);
+ }
+
+ queue_start_poll = kzalloc(sizeof(void *) * card->qdio.no_in_queues,
+ GFP_KERNEL);
+ if (!queue_start_poll) {
+ rc = -ENOMEM;
+ goto out_free_in_sbals;
+ }
+ for (i = 0; i < card->qdio.no_in_queues; ++i)
+ queue_start_poll[i] = card->discipline.start_poll;
+
+ qeth_qdio_establish_cq(card, in_sbal_ptrs, queue_start_poll);
out_sbal_ptrs =
- kmalloc(card->qdio.no_out_queues * QDIO_MAX_BUFFERS_PER_Q *
+ kzalloc(card->qdio.no_out_queues * QDIO_MAX_BUFFERS_PER_Q *
sizeof(void *), GFP_KERNEL);
if (!out_sbal_ptrs) {
- kfree(in_sbal_ptrs);
- kfree(qib_param_field);
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto out_free_queue_start_poll;
}
for (i = 0, k = 0; i < card->qdio.no_out_queues; ++i)
for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j, ++k) {
out_sbal_ptrs[k] = (struct qdio_buffer *)virt_to_phys(
- card->qdio.out_qs[i]->bufs[j].buffer);
+ card->qdio.out_qs[i]->bufs[j]->buffer);
}
memset(&init_data, 0, sizeof(struct qdio_initialize));
@@ -3980,14 +4518,15 @@ static int qeth_qdio_establish(struct qeth_card *card)
init_data.q_format = qeth_get_qdio_q_format(card);
init_data.qib_param_field_format = 0;
init_data.qib_param_field = qib_param_field;
- init_data.no_input_qs = 1;
+ init_data.no_input_qs = card->qdio.no_in_queues;
init_data.no_output_qs = card->qdio.no_out_queues;
init_data.input_handler = card->discipline.input_handler;
init_data.output_handler = card->discipline.output_handler;
- init_data.queue_start_poll = card->discipline.start_poll;
+ init_data.queue_start_poll = queue_start_poll;
init_data.int_parm = (unsigned long) card;
init_data.input_sbal_addr_array = (void **) in_sbal_ptrs;
init_data.output_sbal_addr_array = (void **) out_sbal_ptrs;
+ init_data.output_sbal_state_array = card->qdio.out_bufstates;
init_data.scan_threshold =
(card->info.type == QETH_CARD_TYPE_IQD) ? 8 : 32;
@@ -4004,10 +4543,26 @@ static int qeth_qdio_establish(struct qeth_card *card)
qdio_free(CARD_DDEV(card));
}
}
+
+ switch (card->options.cq) {
+ case QETH_CQ_ENABLED:
+ dev_info(&card->gdev->dev, "Completion Queue support enabled");
+ break;
+ case QETH_CQ_DISABLED:
+ dev_info(&card->gdev->dev, "Completion Queue support disabled");
+ break;
+ default:
+ break;
+ }
out:
kfree(out_sbal_ptrs);
+out_free_queue_start_poll:
+ kfree(queue_start_poll);
+out_free_in_sbals:
kfree(in_sbal_ptrs);
+out_free_qib_param:
kfree(qib_param_field);
+out_free_nothing:
return rc;
}
@@ -4144,29 +4699,36 @@ out:
}
EXPORT_SYMBOL_GPL(qeth_core_hardsetup_card);
-static inline int qeth_create_skb_frag(struct qdio_buffer_element *element,
+static inline int qeth_create_skb_frag(struct qeth_qdio_buffer *qethbuffer,
+ struct qdio_buffer_element *element,
struct sk_buff **pskb, int offset, int *pfrag, int data_len)
{
struct page *page = virt_to_page(element->addr);
if (*pskb == NULL) {
- /* the upper protocol layers assume that there is data in the
- * skb itself. Copy a small amount (64 bytes) to make them
- * happy. */
- *pskb = dev_alloc_skb(64 + ETH_HLEN);
- if (!(*pskb))
- return -ENOMEM;
+ if (qethbuffer->rx_skb) {
+ /* only if qeth_card.options.cq == QETH_CQ_ENABLED */
+ *pskb = qethbuffer->rx_skb;
+ qethbuffer->rx_skb = NULL;
+ } else {
+ *pskb = dev_alloc_skb(QETH_RX_PULL_LEN + ETH_HLEN);
+ if (!(*pskb))
+ return -ENOMEM;
+ }
+
skb_reserve(*pskb, ETH_HLEN);
- if (data_len <= 64) {
+ if (data_len <= QETH_RX_PULL_LEN) {
memcpy(skb_put(*pskb, data_len), element->addr + offset,
data_len);
} else {
get_page(page);
- memcpy(skb_put(*pskb, 64), element->addr + offset, 64);
- skb_fill_page_desc(*pskb, *pfrag, page, offset + 64,
- data_len - 64);
- (*pskb)->data_len += data_len - 64;
- (*pskb)->len += data_len - 64;
- (*pskb)->truesize += data_len - 64;
+ memcpy(skb_put(*pskb, QETH_RX_PULL_LEN),
+ element->addr + offset, QETH_RX_PULL_LEN);
+ skb_fill_page_desc(*pskb, *pfrag, page,
+ offset + QETH_RX_PULL_LEN,
+ data_len - QETH_RX_PULL_LEN);
+ (*pskb)->data_len += data_len - QETH_RX_PULL_LEN;
+ (*pskb)->len += data_len - QETH_RX_PULL_LEN;
+ (*pskb)->truesize += data_len - QETH_RX_PULL_LEN;
(*pfrag)++;
}
} else {
@@ -4177,15 +4739,18 @@ static inline int qeth_create_skb_frag(struct qdio_buffer_element *element,
(*pskb)->truesize += data_len;
(*pfrag)++;
}
+
+
return 0;
}
struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
- struct qdio_buffer *buffer,
+ struct qeth_qdio_buffer *qethbuffer,
struct qdio_buffer_element **__element, int *__offset,
struct qeth_hdr **hdr)
{
struct qdio_buffer_element *element = *__element;
+ struct qdio_buffer *buffer = qethbuffer->buffer;
int offset = *__offset;
struct sk_buff *skb = NULL;
int skb_len = 0;
@@ -4230,9 +4795,10 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
if (!skb_len)
return NULL;
- if ((skb_len >= card->options.rx_sg_cb) &&
- (!(card->info.type == QETH_CARD_TYPE_OSN)) &&
- (!atomic_read(&card->force_alloc_skb))) {
+ if (((skb_len >= card->options.rx_sg_cb) &&
+ (!(card->info.type == QETH_CARD_TYPE_OSN)) &&
+ (!atomic_read(&card->force_alloc_skb))) ||
+ (card->options.cq == QETH_CQ_ENABLED)) {
use_rx_sg = 1;
} else {
skb = dev_alloc_skb(skb_len + headroom);
@@ -4247,8 +4813,8 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
data_len = min(skb_len, (int)(element->length - offset));
if (data_len) {
if (use_rx_sg) {
- if (qeth_create_skb_frag(element, &skb, offset,
- &frag, data_len))
+ if (qeth_create_skb_frag(qethbuffer, element,
+ &skb, offset, &frag, data_len))
goto no_mem;
} else {
memcpy(skb_put(skb, data_len), data_ptr,
@@ -4650,6 +5216,8 @@ static struct {
{"tx do_QDIO count"},
{"tx csum"},
{"tx lin"},
+ {"cq handler count"},
+ {"cq handler time"}
};
int qeth_core_get_sset_count(struct net_device *dev, int stringset)
@@ -4708,6 +5276,8 @@ void qeth_core_get_ethtool_stats(struct net_device *dev,
data[32] = card->perf_stats.outbound_do_qdio_cnt;
data[33] = card->perf_stats.tx_csum;
data[34] = card->perf_stats.tx_lin;
+ data[35] = card->perf_stats.cq_cnt;
+ data[36] = card->perf_stats.cq_time;
}
EXPORT_SYMBOL_GPL(qeth_core_get_ethtool_stats);
@@ -4866,7 +5436,16 @@ static int __init qeth_core_init(void)
goto slab_err;
}
+ qeth_qdio_outbuf_cache = kmem_cache_create("qeth_buf",
+ sizeof(struct qeth_qdio_out_buffer), 0, 0, NULL);
+ if (!qeth_qdio_outbuf_cache) {
+ rc = -ENOMEM;
+ goto cqslab_err;
+ }
+
return 0;
+cqslab_err:
+ kmem_cache_destroy(qeth_core_header_cache);
slab_err:
root_device_unregister(qeth_core_root_dev);
register_err:
@@ -4891,6 +5470,7 @@ static void __exit qeth_core_exit(void)
&driver_attr_group);
ccwgroup_driver_unregister(&qeth_core_ccwgroup_driver);
ccw_driver_unregister(&qeth_ccw_driver);
+ kmem_cache_destroy(qeth_qdio_outbuf_cache);
kmem_cache_destroy(qeth_core_header_cache);
qeth_unregister_dbf_views();
pr_info("core functions removed\n");
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index b70b47fbd6cd..a21ae3d549db 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -409,7 +409,7 @@ static int qeth_l2_process_inbound_buffer(struct qeth_card *card,
BUG_ON(!budget);
while (budget) {
skb = qeth_core_get_next_skb(card,
- card->qdio.in_q->bufs[card->rx.b_index].buffer,
+ &card->qdio.in_q->bufs[card->rx.b_index],
&card->rx.b_element, &card->rx.e_offset, &hdr);
if (!skb) {
*done = 1;
@@ -925,7 +925,7 @@ static const struct net_device_ops qeth_l2_netdev_ops = {
.ndo_get_stats = qeth_get_stats,
.ndo_start_xmit = qeth_l2_hard_start_xmit,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = qeth_l2_set_multicast_list,
+ .ndo_set_rx_mode = qeth_l2_set_multicast_list,
.ndo_do_ioctl = qeth_l2_do_ioctl,
.ndo_set_mac_address = qeth_l2_set_mac_address,
.ndo_change_mtu = qeth_change_mtu,
diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h
index 14a43aeb0c2a..e367315a63f0 100644
--- a/drivers/s390/net/qeth_l3.h
+++ b/drivers/s390/net/qeth_l3.h
@@ -63,5 +63,9 @@ int qeth_l3_add_rxip(struct qeth_card *, enum qeth_prot_versions, const u8 *);
void qeth_l3_del_rxip(struct qeth_card *card, enum qeth_prot_versions,
const u8 *);
int qeth_l3_is_addr_covered_by_ipato(struct qeth_card *, struct qeth_ipaddr *);
+struct qeth_ipaddr *qeth_l3_get_addr_buffer(enum qeth_prot_versions);
+int qeth_l3_add_ip(struct qeth_card *, struct qeth_ipaddr *);
+int qeth_l3_delete_ip(struct qeth_card *, struct qeth_ipaddr *);
+void qeth_l3_set_ip_addr_list(struct qeth_card *);
#endif /* __QETH_L3_H__ */
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index fafb8c299540..ce735204d317 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -29,6 +29,7 @@
#include <net/ip.h>
#include <net/arp.h>
#include <net/ip6_checksum.h>
+#include <net/iucv/af_iucv.h>
#include "qeth_l3.h"
@@ -267,7 +268,7 @@ static int __qeth_l3_insert_ip_todo(struct qeth_card *card,
}
}
-static int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *addr)
+int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *addr)
{
unsigned long flags;
int rc = 0;
@@ -286,7 +287,7 @@ static int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *addr)
return rc;
}
-static int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr)
+int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr)
{
unsigned long flags;
int rc = 0;
@@ -305,7 +306,7 @@ static int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr)
}
-static struct qeth_ipaddr *qeth_l3_get_addr_buffer(
+struct qeth_ipaddr *qeth_l3_get_addr_buffer(
enum qeth_prot_versions prot)
{
struct qeth_ipaddr *addr;
@@ -421,7 +422,7 @@ again:
list_splice(&fail_list, &card->ip_list);
}
-static void qeth_l3_set_ip_addr_list(struct qeth_card *card)
+void qeth_l3_set_ip_addr_list(struct qeth_card *card)
{
struct list_head *tbd_list;
struct qeth_ipaddr *todo, *addr;
@@ -438,7 +439,7 @@ static void qeth_l3_set_ip_addr_list(struct qeth_card *card)
spin_lock_irqsave(&card->ip_lock, flags);
tbd_list = card->ip_tbd_list;
- card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC);
+ card->ip_tbd_list = kzalloc(sizeof(struct list_head), GFP_ATOMIC);
if (!card->ip_tbd_list) {
QETH_CARD_TEXT(card, 0, "silnomem");
card->ip_tbd_list = tbd_list;
@@ -1993,12 +1994,13 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card,
__u16 vlan_tag = 0;
int is_vlan;
unsigned int len;
+ __u16 magic;
*done = 0;
BUG_ON(!budget);
while (budget) {
skb = qeth_core_get_next_skb(card,
- card->qdio.in_q->bufs[card->rx.b_index].buffer,
+ &card->qdio.in_q->bufs[card->rx.b_index],
&card->rx.b_element, &card->rx.e_offset, &hdr);
if (!skb) {
*done = 1;
@@ -2007,12 +2009,26 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card,
skb->dev = card->dev;
switch (hdr->hdr.l3.id) {
case QETH_HEADER_TYPE_LAYER3:
- is_vlan = qeth_l3_rebuild_skb(card, skb, hdr,
+ magic = *(__u16 *)skb->data;
+ if ((card->info.type == QETH_CARD_TYPE_IQD) &&
+ (magic == ETH_P_AF_IUCV)) {
+ skb->protocol = ETH_P_AF_IUCV;
+ skb->pkt_type = PACKET_HOST;
+ skb->mac_header = NET_SKB_PAD;
+ skb->dev = card->dev;
+ len = skb->len;
+ card->dev->header_ops->create(skb, card->dev, 0,
+ card->dev->dev_addr, "FAKELL",
+ card->dev->addr_len);
+ netif_receive_skb(skb);
+ } else {
+ is_vlan = qeth_l3_rebuild_skb(card, skb, hdr,
&vlan_tag);
- len = skb->len;
- if (is_vlan && !card->options.sniffer)
- __vlan_hwaccel_put_tag(skb, vlan_tag);
- napi_gro_receive(&card->napi, skb);
+ len = skb->len;
+ if (is_vlan && !card->options.sniffer)
+ __vlan_hwaccel_put_tag(skb, vlan_tag);
+ napi_gro_receive(&card->napi, skb);
+ }
break;
case QETH_HEADER_TYPE_LAYER2: /* for HiperSockets sniffer */
skb->pkt_type = PACKET_HOST;
@@ -2784,6 +2800,30 @@ int inline qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
return cast_type;
}
+static void qeth_l3_fill_af_iucv_hdr(struct qeth_card *card,
+ struct qeth_hdr *hdr, struct sk_buff *skb)
+{
+ char daddr[16];
+ struct af_iucv_trans_hdr *iucv_hdr;
+
+ skb_pull(skb, 14);
+ card->dev->header_ops->create(skb, card->dev, 0,
+ card->dev->dev_addr, card->dev->dev_addr,
+ card->dev->addr_len);
+ skb_pull(skb, 14);
+ iucv_hdr = (struct af_iucv_trans_hdr *)skb->data;
+ memset(hdr, 0, sizeof(struct qeth_hdr));
+ hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3;
+ hdr->hdr.l3.ext_flags = 0;
+ hdr->hdr.l3.length = skb->len;
+ hdr->hdr.l3.flags = QETH_HDR_IPV6 | QETH_CAST_UNICAST;
+ memset(daddr, 0, sizeof(daddr));
+ daddr[0] = 0xfe;
+ daddr[1] = 0x80;
+ memcpy(&daddr[8], iucv_hdr->destUserID, 8);
+ memcpy(hdr->hdr.l3.dest_addr, daddr, 16);
+}
+
static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
struct sk_buff *skb, int ipv, int cast_type)
{
@@ -2936,8 +2976,11 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
int data_offset = -1;
int nr_frags;
- if (((card->info.type == QETH_CARD_TYPE_IQD) && (!ipv)) ||
- card->options.sniffer)
+ if (((card->info.type == QETH_CARD_TYPE_IQD) &&
+ (((card->options.cq != QETH_CQ_ENABLED) && !ipv) ||
+ ((card->options.cq == QETH_CQ_ENABLED) &&
+ (skb->protocol != ETH_P_AF_IUCV)))) ||
+ card->options.sniffer)
goto tx_drop;
if ((card->state != CARD_STATE_UP) || !card->lan_online) {
@@ -2959,7 +3002,10 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) &&
(skb_shinfo(skb)->nr_frags == 0)) {
new_skb = skb;
- data_offset = ETH_HLEN;
+ if (new_skb->protocol == ETH_P_AF_IUCV)
+ data_offset = 0;
+ else
+ data_offset = ETH_HLEN;
hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC);
if (!hdr)
goto tx_drop;
@@ -2993,7 +3039,6 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
tag = (u16 *)(new_skb->data + 12);
*tag = __constant_htons(ETH_P_8021Q);
*(tag + 1) = htons(vlan_tx_tag_get(new_skb));
- new_skb->vlan_tci = 0;
}
}
@@ -3025,9 +3070,13 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
qeth_l3_fill_header(card, hdr, new_skb, ipv,
cast_type);
} else {
- qeth_l3_fill_header(card, hdr, new_skb, ipv,
- cast_type);
- hdr->hdr.l3.length = new_skb->len - data_offset;
+ if (new_skb->protocol == ETH_P_AF_IUCV)
+ qeth_l3_fill_af_iucv_hdr(card, hdr, new_skb);
+ else {
+ qeth_l3_fill_header(card, hdr, new_skb, ipv,
+ cast_type);
+ hdr->hdr.l3.length = new_skb->len - data_offset;
+ }
}
if (skb->ip_summed == CHECKSUM_PARTIAL)
@@ -3226,7 +3275,7 @@ static const struct net_device_ops qeth_l3_netdev_ops = {
.ndo_get_stats = qeth_get_stats,
.ndo_start_xmit = qeth_l3_hard_start_xmit,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = qeth_l3_set_multicast_list,
+ .ndo_set_rx_mode = qeth_l3_set_multicast_list,
.ndo_do_ioctl = qeth_l3_do_ioctl,
.ndo_change_mtu = qeth_change_mtu,
.ndo_fix_features = qeth_l3_fix_features,
@@ -3242,7 +3291,7 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = {
.ndo_get_stats = qeth_get_stats,
.ndo_start_xmit = qeth_l3_hard_start_xmit,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = qeth_l3_set_multicast_list,
+ .ndo_set_rx_mode = qeth_l3_set_multicast_list,
.ndo_do_ioctl = qeth_l3_do_ioctl,
.ndo_change_mtu = qeth_change_mtu,
.ndo_fix_features = qeth_l3_fix_features,
@@ -3290,6 +3339,8 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
card->dev->flags |= IFF_NOARP;
card->dev->netdev_ops = &qeth_l3_netdev_ops;
qeth_l3_iqd_read_initial_mac(card);
+ if (card->options.hsuid[0])
+ memcpy(card->dev->perm_addr, card->options.hsuid, 9);
} else
return -ENODEV;
@@ -3660,7 +3711,6 @@ static int qeth_l3_ip6_event(struct notifier_block *this,
struct qeth_ipaddr *addr;
struct qeth_card *card;
-
card = qeth_l3_get_card_from_dev(dev);
if (!card)
return NOTIFY_DONE;
diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c
index cd99210296e2..0ea2fbfe0e99 100644
--- a/drivers/s390/net/qeth_l3_sys.c
+++ b/drivers/s390/net/qeth_l3_sys.c
@@ -9,7 +9,7 @@
*/
#include <linux/slab.h>
-
+#include <asm/ebcdic.h>
#include "qeth_l3.h"
#define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \
@@ -308,6 +308,8 @@ static ssize_t qeth_l3_dev_sniffer_store(struct device *dev,
if (card->info.type != QETH_CARD_TYPE_IQD)
return -EPERM;
+ if (card->options.cq == QETH_CQ_ENABLED)
+ return -EPERM;
mutex_lock(&card->conf_mutex);
if ((card->state != CARD_STATE_DOWN) &&
@@ -347,6 +349,111 @@ out:
static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show,
qeth_l3_dev_sniffer_store);
+
+static ssize_t qeth_l3_dev_hsuid_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct qeth_card *card = dev_get_drvdata(dev);
+ char tmp_hsuid[9];
+
+ if (!card)
+ return -EINVAL;
+
+ if (card->info.type != QETH_CARD_TYPE_IQD)
+ return -EPERM;
+
+ if (card->state == CARD_STATE_DOWN)
+ return -EPERM;
+
+ memcpy(tmp_hsuid, card->options.hsuid, sizeof(tmp_hsuid));
+ EBCASC(tmp_hsuid, 8);
+ return sprintf(buf, "%s\n", tmp_hsuid);
+}
+
+static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct qeth_card *card = dev_get_drvdata(dev);
+ struct qeth_ipaddr *addr;
+ char *tmp;
+ int i;
+
+ if (!card)
+ return -EINVAL;
+
+ if (card->info.type != QETH_CARD_TYPE_IQD)
+ return -EPERM;
+ if (card->state != CARD_STATE_DOWN &&
+ card->state != CARD_STATE_RECOVER)
+ return -EPERM;
+ if (card->options.sniffer)
+ return -EPERM;
+ if (card->options.cq == QETH_CQ_NOTAVAILABLE)
+ return -EPERM;
+
+ tmp = strsep((char **)&buf, "\n");
+ if (strlen(tmp) > 8)
+ return -EINVAL;
+
+ if (card->options.hsuid[0]) {
+ /* delete old ip address */
+ addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
+ if (addr != NULL) {
+ addr->u.a6.addr.s6_addr32[0] = 0xfe800000;
+ addr->u.a6.addr.s6_addr32[1] = 0x00000000;
+ for (i = 8; i < 16; i++)
+ addr->u.a6.addr.s6_addr[i] =
+ card->options.hsuid[i - 8];
+ addr->u.a6.pfxlen = 0;
+ addr->type = QETH_IP_TYPE_NORMAL;
+ } else
+ return -ENOMEM;
+ if (!qeth_l3_delete_ip(card, addr))
+ kfree(addr);
+ qeth_l3_set_ip_addr_list(card);
+ }
+
+ if (strlen(tmp) == 0) {
+ /* delete ip address only */
+ card->options.hsuid[0] = '\0';
+ if (card->dev)
+ memcpy(card->dev->perm_addr, card->options.hsuid, 9);
+ qeth_configure_cq(card, QETH_CQ_DISABLED);
+ return count;
+ }
+
+ if (qeth_configure_cq(card, QETH_CQ_ENABLED))
+ return -EPERM;
+
+ for (i = 0; i < 8; i++)
+ card->options.hsuid[i] = ' ';
+ card->options.hsuid[8] = '\0';
+ strncpy(card->options.hsuid, tmp, strlen(tmp));
+ ASCEBC(card->options.hsuid, 8);
+ if (card->dev)
+ memcpy(card->dev->perm_addr, card->options.hsuid, 9);
+
+ addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
+ if (addr != NULL) {
+ addr->u.a6.addr.s6_addr32[0] = 0xfe800000;
+ addr->u.a6.addr.s6_addr32[1] = 0x00000000;
+ for (i = 8; i < 16; i++)
+ addr->u.a6.addr.s6_addr[i] = card->options.hsuid[i - 8];
+ addr->u.a6.pfxlen = 0;
+ addr->type = QETH_IP_TYPE_NORMAL;
+ } else
+ return -ENOMEM;
+ if (!qeth_l3_add_ip(card, addr))
+ kfree(addr);
+ qeth_l3_set_ip_addr_list(card);
+
+ return count;
+}
+
+static DEVICE_ATTR(hsuid, 0644, qeth_l3_dev_hsuid_show,
+ qeth_l3_dev_hsuid_store);
+
+
static struct attribute *qeth_l3_device_attrs[] = {
&dev_attr_route4.attr,
&dev_attr_route6.attr,
@@ -354,6 +461,7 @@ static struct attribute *qeth_l3_device_attrs[] = {
&dev_attr_broadcast_mode.attr,
&dev_attr_canonical_macaddr.attr,
&dev_attr_sniffer.attr,
+ &dev_attr_hsuid.attr,
NULL,
};
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index b7bd5b0cc7aa..3868ab2397c6 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -1800,10 +1800,12 @@ static int twa_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_
switch (retval) {
case SCSI_MLQUEUE_HOST_BUSY:
twa_free_request_id(tw_dev, request_id);
+ twa_unmap_scsi_data(tw_dev, request_id);
break;
case 1:
tw_dev->state[request_id] = TW_S_COMPLETED;
twa_free_request_id(tw_dev, request_id);
+ twa_unmap_scsi_data(tw_dev, request_id);
SCpnt->result = (DID_ERROR << 16);
done(SCpnt);
retval = 0;
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 8d9dae89f065..3878b7395081 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -837,6 +837,7 @@ config SCSI_ISCI
# (temporary): known alpha quality driver
depends on EXPERIMENTAL
select SCSI_SAS_LIBSAS
+ select SCSI_SAS_HOST_SMP
---help---
This driver supports the 6Gb/s SAS capabilities of the storage
control unit found in the Intel(R) C600 series chipset.
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 3c08f5352b2d..6153a66a8a31 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -88,7 +88,7 @@ obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas408.o qlogicfas.o
obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o
obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o
obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx/
-obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx/
+obj-$(CONFIG_SCSI_QLA_ISCSI) += libiscsi.o qla4xxx/
obj-$(CONFIG_SCSI_LPFC) += lpfc/
obj-$(CONFIG_SCSI_BFA_FC) += bfa/
obj-$(CONFIG_SCSI_PAS16) += pas16.o
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index e7d0d47b9185..e5f2d7d9002e 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -1283,6 +1283,8 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
kfree(aac->queues);
aac->queues = NULL;
free_irq(aac->pdev->irq, aac);
+ if (aac->msi)
+ pci_disable_msi(aac->pdev);
kfree(aac->fsa_dev);
aac->fsa_dev = NULL;
quirks = aac_get_driver_ident(index)->quirks;
diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c
index c20494660603..957595a7a45c 100644
--- a/drivers/scsi/aacraid/src.c
+++ b/drivers/scsi/aacraid/src.c
@@ -37,7 +37,6 @@
#include <linux/slab.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
-#include <linux/version.h>
#include <linux/completion.h>
#include <linux/time.h>
#include <linux/interrupt.h>
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx
index 5e6620f8dabc..6739069477de 100644
--- a/drivers/scsi/aic7xxx/Kconfig.aic79xx
+++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx
@@ -31,8 +31,7 @@ config AIC79XX_CMDS_PER_DEVICE
on some devices. The upper bound is 253. 0 disables tagged queueing.
Per device tag depth can be controlled via the kernel command line
- "tag_info" option. See drivers/scsi/aic7xxx/README.aic79xx
- for details.
+ "tag_info" option. See Documentation/scsi/aic79xx.txt for details.
config AIC79XX_RESET_DELAY_MS
int "Initial bus reset delay in milli-seconds"
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
index 88da670a7915..55ac55ee6068 100644
--- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx
+++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
@@ -36,8 +36,7 @@ config AIC7XXX_CMDS_PER_DEVICE
on some devices. The upper bound is 253. 0 disables tagged queueing.
Per device tag depth can be controlled via the kernel command line
- "tag_info" option. See drivers/scsi/aic7xxx/README.aic7xxx
- for details.
+ "tag_info" option. See Documentation/scsi/aic7xxx.txt for details.
config AIC7XXX_RESET_DELAY_MS
int "Initial bus reset delay in milli-seconds"
diff --git a/drivers/scsi/aic94xx/aic94xx_dump.c b/drivers/scsi/aic94xx/aic94xx_dump.c
index 67eeba3bdb06..a16a77c8b9cf 100644
--- a/drivers/scsi/aic94xx/aic94xx_dump.c
+++ b/drivers/scsi/aic94xx/aic94xx_dump.c
@@ -29,7 +29,7 @@
*
*/
-#include "linux/pci.h"
+#include <linux/pci.h>
#include "aic94xx.h"
#include "aic94xx_reg.h"
#include "aic94xx_reg_def.h"
diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h
index bda999ad9f52..5e19a5f820ec 100644
--- a/drivers/scsi/bfa/bfad_drv.h
+++ b/drivers/scsi/bfa/bfad_drv.h
@@ -27,7 +27,6 @@
#define __BFAD_DRV_H__
#include <linux/types.h>
-#include <linux/version.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/idr.h>
diff --git a/drivers/scsi/bnx2fc/Kconfig b/drivers/scsi/bnx2fc/Kconfig
index 6a38080e35ed..cfcad8bde7cf 100644
--- a/drivers/scsi/bnx2fc/Kconfig
+++ b/drivers/scsi/bnx2fc/Kconfig
@@ -2,7 +2,8 @@ config SCSI_BNX2X_FCOE
tristate "Broadcom NetXtreme II FCoE support"
depends on PCI
select NETDEVICES
- select NETDEV_1000
+ select ETHERNET
+ select NET_VENDOR_BROADCOM
select LIBFC
select LIBFCOE
select CNIC
diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h
index 42228ca5a9d2..dd335a2a797b 100644
--- a/drivers/scsi/bnx2fc/bnx2fc.h
+++ b/drivers/scsi/bnx2fc/bnx2fc.h
@@ -58,7 +58,7 @@
#include "57xx_hsi_bnx2fc.h"
#include "bnx2fc_debug.h"
-#include "../../net/cnic_if.h"
+#include "../../net/ethernet/broadcom/cnic_if.h"
#include "bnx2fc_constants.h"
#define BNX2FC_NAME "bnx2fc"
@@ -81,7 +81,7 @@
#define BNX2FC_RQ_WQES_MAX 16
#define BNX2FC_CQ_WQES_MAX (BNX2FC_SQ_WQES_MAX + BNX2FC_RQ_WQES_MAX)
-#define BNX2FC_NUM_MAX_SESS 128
+#define BNX2FC_NUM_MAX_SESS 1024
#define BNX2FC_NUM_MAX_SESS_LOG (ilog2(BNX2FC_NUM_MAX_SESS))
#define BNX2FC_MAX_OUTSTANDING_CMNDS 2048
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index 7cb2cd48b17b..820a1840c3f7 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -302,7 +302,7 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp)
return -ENOMEM;
}
frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1];
- cp = kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ)
+ cp = kmap_atomic(skb_frag_page(frag), KM_SKB_DATA_SOFTIRQ)
+ frag->page_offset;
} else {
cp = (struct fcoe_crc_eof *)skb_put(skb, tlen);
@@ -673,7 +673,7 @@ static void bnx2fc_link_speed_update(struct fc_lport *lport)
struct net_device *netdev = interface->netdev;
struct ethtool_cmd ecmd;
- if (!dev_ethtool_get_settings(netdev, &ecmd)) {
+ if (!__ethtool_get_settings(netdev, &ecmd)) {
lport->link_supported_speeds &=
~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT);
if (ecmd.supported & (SUPPORTED_1000baseT_Half |
@@ -1001,9 +1001,11 @@ static int bnx2fc_vport_create(struct fc_vport *vport, bool disabled)
"this interface\n");
return -EIO;
}
+ rtnl_lock();
mutex_lock(&bnx2fc_dev_lock);
vn_port = bnx2fc_if_create(interface, &vport->dev, 1);
mutex_unlock(&bnx2fc_dev_lock);
+ rtnl_unlock();
if (IS_ERR(vn_port)) {
printk(KERN_ERR PFX "bnx2fc_vport_create (%s) failed\n",
diff --git a/drivers/scsi/bnx2i/Kconfig b/drivers/scsi/bnx2i/Kconfig
index 45a6154ce972..01cff1894b6d 100644
--- a/drivers/scsi/bnx2i/Kconfig
+++ b/drivers/scsi/bnx2i/Kconfig
@@ -4,7 +4,8 @@ config SCSI_BNX2_ISCSI
depends on PCI
select SCSI_ISCSI_ATTRS
select NETDEVICES
- select NETDEV_1000
+ select ETHERNET
+ select NET_VENDOR_BROADCOM
select CNIC
---help---
This driver supports iSCSI offload for the Broadcom NetXtreme II
diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h
index dc5700765db4..0bd70e80efe4 100644
--- a/drivers/scsi/bnx2i/bnx2i.h
+++ b/drivers/scsi/bnx2i/bnx2i.h
@@ -40,7 +40,7 @@
#include <scsi/libiscsi.h>
#include <scsi/scsi_transport_iscsi.h>
-#include "../../net/cnic_if.h"
+#include "../../net/ethernet/broadcom/cnic_if.h"
#include "57xx_iscsi_hsi.h"
#include "57xx_iscsi_constants.h"
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index 9ae80cd5953b..dba72a4e6a1c 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -563,7 +563,7 @@ int bnx2i_send_iscsi_nopout(struct bnx2i_conn *bnx2i_conn,
nopout_wqe->itt = ((u16)task->itt |
(ISCSI_TASK_TYPE_MPATH <<
ISCSI_TMF_REQUEST_TYPE_SHIFT));
- nopout_wqe->ttt = nopout_hdr->ttt;
+ nopout_wqe->ttt = be32_to_cpu(nopout_hdr->ttt);
nopout_wqe->flags = 0;
if (!unsol)
nopout_wqe->flags = ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION;
diff --git a/drivers/scsi/cxgbi/cxgb3i/Kbuild b/drivers/scsi/cxgbi/cxgb3i/Kbuild
index 09dbf9efc8ea..6f095e28a974 100644
--- a/drivers/scsi/cxgbi/cxgb3i/Kbuild
+++ b/drivers/scsi/cxgbi/cxgb3i/Kbuild
@@ -1,3 +1,3 @@
-EXTRA_CFLAGS += -I$(srctree)/drivers/net/cxgb3
+EXTRA_CFLAGS += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb3
obj-$(CONFIG_SCSI_CXGB3_ISCSI) += cxgb3i.o
diff --git a/drivers/scsi/cxgbi/cxgb3i/Kconfig b/drivers/scsi/cxgbi/cxgb3i/Kconfig
index 11dff23f7838..6bbc36fbd6ec 100644
--- a/drivers/scsi/cxgbi/cxgb3i/Kconfig
+++ b/drivers/scsi/cxgbi/cxgb3i/Kconfig
@@ -2,7 +2,8 @@ config SCSI_CXGB3_ISCSI
tristate "Chelsio T3 iSCSI support"
depends on PCI && INET
select NETDEVICES
- select NETDEV_10000
+ select ETHERNET
+ select NET_VENDOR_CHELSIO
select CHELSIO_T3
select SCSI_ISCSI_ATTRS
---help---
diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
index bd22041e2789..1242c7c04a01 100644
--- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
+++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
@@ -14,7 +14,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <scsi/scsi_host.h>
@@ -913,7 +912,7 @@ static void l2t_put(struct cxgbi_sock *csk)
struct t3cdev *t3dev = (struct t3cdev *)csk->cdev->lldev;
if (csk->l2t) {
- l2t_release(L2DATA(t3dev), csk->l2t);
+ l2t_release(t3dev, csk->l2t);
csk->l2t = NULL;
cxgbi_sock_put(csk);
}
diff --git a/drivers/scsi/cxgbi/cxgb4i/Kbuild b/drivers/scsi/cxgbi/cxgb4i/Kbuild
index b9f4af7454b7..8290cdaa4652 100644
--- a/drivers/scsi/cxgbi/cxgb4i/Kbuild
+++ b/drivers/scsi/cxgbi/cxgb4i/Kbuild
@@ -1,3 +1,3 @@
-EXTRA_CFLAGS += -I$(srctree)/drivers/net/cxgb4
+EXTRA_CFLAGS += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb4
obj-$(CONFIG_SCSI_CXGB4_ISCSI) += cxgb4i.o
diff --git a/drivers/scsi/cxgbi/cxgb4i/Kconfig b/drivers/scsi/cxgbi/cxgb4i/Kconfig
index d5302c27f377..16b2c7d26617 100644
--- a/drivers/scsi/cxgbi/cxgb4i/Kconfig
+++ b/drivers/scsi/cxgbi/cxgb4i/Kconfig
@@ -2,7 +2,8 @@ config SCSI_CXGB4_ISCSI
tristate "Chelsio T4 iSCSI support"
depends on PCI && INET
select NETDEVICES
- select NETDEV_10000
+ select ETHERNET
+ select NET_VENDOR_CHELSIO
select CHELSIO_T4
select SCSI_ISCSI_ATTRS
---help---
diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
index ae13c4993aa3..31c79bde6976 100644
--- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
+++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
@@ -13,7 +13,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index 77ac217ad5ce..1c1329bc77c7 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -1787,7 +1787,7 @@ static int sgl_seek_offset(struct scatterlist *sgl, unsigned int sgcnt,
}
static int sgl_read_to_frags(struct scatterlist *sg, unsigned int sgoffset,
- unsigned int dlen, skb_frag_t *frags,
+ unsigned int dlen, struct page_frag *frags,
int frag_max)
{
unsigned int datalen = dlen;
@@ -1814,7 +1814,7 @@ static int sgl_read_to_frags(struct scatterlist *sg, unsigned int sgoffset,
copy = min(datalen, sglen);
if (i && page == frags[i - 1].page &&
sgoffset + sg->offset ==
- frags[i - 1].page_offset + frags[i - 1].size) {
+ frags[i - 1].offset + frags[i - 1].size) {
frags[i - 1].size += copy;
} else {
if (i >= frag_max) {
@@ -1824,7 +1824,7 @@ static int sgl_read_to_frags(struct scatterlist *sg, unsigned int sgoffset,
}
frags[i].page = page;
- frags[i].page_offset = sg->offset + sgoffset;
+ frags[i].offset = sg->offset + sgoffset;
frags[i].size = copy;
i++;
}
@@ -1944,14 +1944,14 @@ int cxgbi_conn_init_pdu(struct iscsi_task *task, unsigned int offset,
if (tdata->nr_frags > MAX_SKB_FRAGS ||
(padlen && tdata->nr_frags == MAX_SKB_FRAGS)) {
char *dst = skb->data + task->hdr_len;
- skb_frag_t *frag = tdata->frags;
+ struct page_frag *frag = tdata->frags;
/* data fits in the skb's headroom */
for (i = 0; i < tdata->nr_frags; i++, frag++) {
char *src = kmap_atomic(frag->page,
KM_SOFTIRQ0);
- memcpy(dst, src+frag->page_offset, frag->size);
+ memcpy(dst, src+frag->offset, frag->size);
dst += frag->size;
kunmap_atomic(src, KM_SOFTIRQ0);
}
@@ -1962,11 +1962,13 @@ int cxgbi_conn_init_pdu(struct iscsi_task *task, unsigned int offset,
skb_put(skb, count + padlen);
} else {
/* data fit into frag_list */
- for (i = 0; i < tdata->nr_frags; i++)
- get_page(tdata->frags[i].page);
-
- memcpy(skb_shinfo(skb)->frags, tdata->frags,
- sizeof(skb_frag_t) * tdata->nr_frags);
+ for (i = 0; i < tdata->nr_frags; i++) {
+ __skb_fill_page_desc(skb, i,
+ tdata->frags[i].page,
+ tdata->frags[i].offset,
+ tdata->frags[i].size);
+ skb_frag_ref(skb, i);
+ }
skb_shinfo(skb)->nr_frags = tdata->nr_frags;
skb->len += count;
skb->data_len += count;
diff --git a/drivers/scsi/cxgbi/libcxgbi.h b/drivers/scsi/cxgbi/libcxgbi.h
index 9267844519c9..3a25b1187c10 100644
--- a/drivers/scsi/cxgbi/libcxgbi.h
+++ b/drivers/scsi/cxgbi/libcxgbi.h
@@ -574,7 +574,7 @@ struct cxgbi_endpoint {
#define MAX_PDU_FRAGS ((ULP2_MAX_PDU_PAYLOAD + 512 - 1) / 512)
struct cxgbi_task_data {
unsigned short nr_frags;
- skb_frag_t frags[MAX_PDU_FRAGS];
+ struct page_frag frags[MAX_PDU_FRAGS];
struct sk_buff *skb;
unsigned int offset;
unsigned int count;
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index ba710e350ac5..a1c0ddd53aa9 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -18,7 +18,6 @@
*/
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/spinlock.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -432,6 +431,8 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
u8 flogi_maddr[ETH_ALEN];
const struct net_device_ops *ops;
+ rtnl_lock();
+
/*
* Don't listen for Ethernet packets anymore.
* synchronize_net() ensures that the packet handlers are not running
@@ -461,6 +462,8 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
" specific feature for LLD.\n");
}
+ rtnl_unlock();
+
/* Release the self-reference taken during fcoe_interface_create() */
fcoe_interface_put(fcoe);
}
@@ -1514,7 +1517,7 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
return -ENOMEM;
}
frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1];
- cp = kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ)
+ cp = kmap_atomic(skb_frag_page(frag), KM_SKB_DATA_SOFTIRQ)
+ frag->page_offset;
} else {
cp = (struct fcoe_crc_eof *)skb_put(skb, tlen);
@@ -1951,11 +1954,8 @@ static void fcoe_destroy_work(struct work_struct *work)
fcoe_if_destroy(port->lport);
/* Do not tear down the fcoe interface for NPIV port */
- if (!npiv) {
- rtnl_lock();
+ if (!npiv)
fcoe_interface_cleanup(fcoe);
- rtnl_unlock();
- }
mutex_unlock(&fcoe_config_mutex);
}
@@ -2009,8 +2009,9 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode)
printk(KERN_ERR "fcoe: Failed to create interface (%s)\n",
netdev->name);
rc = -EIO;
+ rtnl_unlock();
fcoe_interface_cleanup(fcoe);
- goto out_nodev;
+ goto out_nortnl;
}
/* Make this the "master" N_Port */
@@ -2027,6 +2028,7 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode)
out_nodev:
rtnl_unlock();
+out_nortnl:
mutex_unlock(&fcoe_config_mutex);
return rc;
}
@@ -2043,7 +2045,7 @@ int fcoe_link_speed_update(struct fc_lport *lport)
struct net_device *netdev = fcoe_netdev(lport);
struct ethtool_cmd ecmd;
- if (!dev_ethtool_get_settings(netdev, &ecmd)) {
+ if (!__ethtool_get_settings(netdev, &ecmd)) {
lport->link_supported_speeds &=
~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT);
if (ecmd.supported & (SUPPORTED_1000baseT_Half |
@@ -2452,7 +2454,9 @@ static int fcoe_vport_create(struct fc_vport *vport, bool disabled)
}
mutex_lock(&fcoe_config_mutex);
+ rtnl_lock();
vn_port = fcoe_if_create(fcoe, &vport->dev, 1);
+ rtnl_unlock();
mutex_unlock(&fcoe_config_mutex);
if (IS_ERR(vn_port)) {
diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c
index 41068e8748e7..dac8e39a5188 100644
--- a/drivers/scsi/fcoe/fcoe_transport.c
+++ b/drivers/scsi/fcoe/fcoe_transport.c
@@ -105,11 +105,12 @@ u32 fcoe_fc_crc(struct fc_frame *fp)
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
frag = &skb_shinfo(skb)->frags[i];
off = frag->page_offset;
- len = frag->size;
+ len = skb_frag_size(frag);
while (len > 0) {
clen = min(len, PAGE_SIZE - (off & ~PAGE_MASK));
- data = kmap_atomic(frag->page + (off >> PAGE_SHIFT),
- KM_SKB_DATA_SOFTIRQ);
+ data = kmap_atomic(
+ skb_frag_page(frag) + (off >> PAGE_SHIFT),
+ KM_SKB_DATA_SOFTIRQ);
crc = crc32(crc, data + (off & ~PAGE_MASK), clen);
kunmap_atomic(data, KM_SKB_DATA_SOFTIRQ);
off += clen;
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index ec61bdb833ac..b200b736b000 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -676,6 +676,16 @@ static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno,
BUG_ON(entry < 0 || entry >= HPSA_MAX_SCSI_DEVS_PER_HBA);
removed[*nremoved] = h->dev[entry];
(*nremoved)++;
+
+ /*
+ * New physical devices won't have target/lun assigned yet
+ * so we need to preserve the values in the slot we are replacing.
+ */
+ if (new_entry->target == -1) {
+ new_entry->target = h->dev[entry]->target;
+ new_entry->lun = h->dev[entry]->lun;
+ }
+
h->dev[entry] = new_entry;
added[*nadded] = new_entry;
(*nadded)++;
@@ -1548,10 +1558,17 @@ static inline void hpsa_set_bus_target_lun(struct hpsa_scsi_dev_t *device,
}
static int hpsa_update_device_info(struct ctlr_info *h,
- unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device)
+ unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device,
+ unsigned char *is_OBDR_device)
{
-#define OBDR_TAPE_INQ_SIZE 49
+
+#define OBDR_SIG_OFFSET 43
+#define OBDR_TAPE_SIG "$DR-10"
+#define OBDR_SIG_LEN (sizeof(OBDR_TAPE_SIG) - 1)
+#define OBDR_TAPE_INQ_SIZE (OBDR_SIG_OFFSET + OBDR_SIG_LEN)
+
unsigned char *inq_buff;
+ unsigned char *obdr_sig;
inq_buff = kzalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
if (!inq_buff)
@@ -1583,6 +1600,16 @@ static int hpsa_update_device_info(struct ctlr_info *h,
else
this_device->raid_level = RAID_UNKNOWN;
+ if (is_OBDR_device) {
+ /* See if this is a One-Button-Disaster-Recovery device
+ * by looking for "$DR-10" at offset 43 in inquiry data.
+ */
+ obdr_sig = &inq_buff[OBDR_SIG_OFFSET];
+ *is_OBDR_device = (this_device->devtype == TYPE_ROM &&
+ strncmp(obdr_sig, OBDR_TAPE_SIG,
+ OBDR_SIG_LEN) == 0);
+ }
+
kfree(inq_buff);
return 0;
@@ -1716,7 +1743,7 @@ static int add_msa2xxx_enclosure_device(struct ctlr_info *h,
return 0;
}
- if (hpsa_update_device_info(h, scsi3addr, this_device))
+ if (hpsa_update_device_info(h, scsi3addr, this_device, NULL))
return 0;
(*nmsa2xxx_enclosures)++;
hpsa_set_bus_target_lun(this_device, bus, target, 0);
@@ -1808,7 +1835,6 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
*/
struct ReportLUNdata *physdev_list = NULL;
struct ReportLUNdata *logdev_list = NULL;
- unsigned char *inq_buff = NULL;
u32 nphysicals = 0;
u32 nlogicals = 0;
u32 ndev_allocated = 0;
@@ -1824,11 +1850,9 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
GFP_KERNEL);
physdev_list = kzalloc(reportlunsize, GFP_KERNEL);
logdev_list = kzalloc(reportlunsize, GFP_KERNEL);
- inq_buff = kmalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
tmpdevice = kzalloc(sizeof(*tmpdevice), GFP_KERNEL);
- if (!currentsd || !physdev_list || !logdev_list ||
- !inq_buff || !tmpdevice) {
+ if (!currentsd || !physdev_list || !logdev_list || !tmpdevice) {
dev_err(&h->pdev->dev, "out of memory\n");
goto out;
}
@@ -1863,7 +1887,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
/* adjust our table of devices */
nmsa2xxx_enclosures = 0;
for (i = 0; i < nphysicals + nlogicals + 1; i++) {
- u8 *lunaddrbytes;
+ u8 *lunaddrbytes, is_OBDR = 0;
/* Figure out where the LUN ID info is coming from */
lunaddrbytes = figure_lunaddrbytes(h, raid_ctlr_position,
@@ -1874,7 +1898,8 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
continue;
/* Get device type, vendor, model, device id */
- if (hpsa_update_device_info(h, lunaddrbytes, tmpdevice))
+ if (hpsa_update_device_info(h, lunaddrbytes, tmpdevice,
+ &is_OBDR))
continue; /* skip it if we can't talk to it. */
figure_bus_target_lun(h, lunaddrbytes, &bus, &target, &lun,
tmpdevice);
@@ -1898,7 +1923,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
hpsa_set_bus_target_lun(this_device, bus, target, lun);
switch (this_device->devtype) {
- case TYPE_ROM: {
+ case TYPE_ROM:
/* We don't *really* support actual CD-ROM devices,
* just "One Button Disaster Recovery" tape drive
* which temporarily pretends to be a CD-ROM drive.
@@ -1906,15 +1931,8 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
* device by checking for "$DR-10" in bytes 43-48 of
* the inquiry data.
*/
- char obdr_sig[7];
-#define OBDR_TAPE_SIG "$DR-10"
- strncpy(obdr_sig, &inq_buff[43], 6);
- obdr_sig[6] = '\0';
- if (strncmp(obdr_sig, OBDR_TAPE_SIG, 6) != 0)
- /* Not OBDR device, ignore it. */
- break;
- }
- ncurrent++;
+ if (is_OBDR)
+ ncurrent++;
break;
case TYPE_DISK:
if (i < nphysicals)
@@ -1947,7 +1965,6 @@ out:
for (i = 0; i < ndev_allocated; i++)
kfree(currentsd[i]);
kfree(currentsd);
- kfree(inq_buff);
kfree(physdev_list);
kfree(logdev_list);
}
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 26072f1e9852..6981b773a88d 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -531,6 +531,9 @@ static void sci_controller_process_completions(struct isci_host *ihost)
break;
case SCU_COMPLETION_TYPE_EVENT:
+ sci_controller_event_completion(ihost, ent);
+ break;
+
case SCU_COMPLETION_TYPE_NOTIFY: {
event_cycle ^= ((event_get+1) & SCU_MAX_EVENTS) <<
(SMU_COMPLETION_QUEUE_GET_EVENT_CYCLE_BIT_SHIFT - SCU_MAX_EVENTS_SHIFT);
@@ -1091,6 +1094,7 @@ static void isci_host_completion_routine(unsigned long data)
struct isci_request *request;
struct isci_request *next_request;
struct sas_task *task;
+ u16 active;
INIT_LIST_HEAD(&completed_request_list);
INIT_LIST_HEAD(&errored_request_list);
@@ -1181,6 +1185,13 @@ static void isci_host_completion_routine(unsigned long data)
}
}
+ /* the coalesence timeout doubles at each encoding step, so
+ * update it based on the ilog2 value of the outstanding requests
+ */
+ active = isci_tci_active(ihost);
+ writel(SMU_ICC_GEN_VAL(NUMBER, active) |
+ SMU_ICC_GEN_VAL(TIMER, ISCI_COALESCE_BASE + ilog2(active)),
+ &ihost->smu_registers->interrupt_coalesce_control);
}
/**
@@ -1471,7 +1482,7 @@ static void sci_controller_ready_state_enter(struct sci_base_state_machine *sm)
struct isci_host *ihost = container_of(sm, typeof(*ihost), sm);
/* set the default interrupt coalescence number and timeout value. */
- sci_controller_set_interrupt_coalescence(ihost, 0x10, 250);
+ sci_controller_set_interrupt_coalescence(ihost, 0, 0);
}
static void sci_controller_ready_state_exit(struct sci_base_state_machine *sm)
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index 062101a39f79..9f33831a2f04 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -369,6 +369,9 @@ static inline struct isci_host *dev_to_ihost(struct domain_device *dev)
#define ISCI_TAG_SEQ(tag) (((tag) >> 12) & (SCI_MAX_SEQ-1))
#define ISCI_TAG_TCI(tag) ((tag) & (SCI_MAX_IO_REQUESTS-1))
+/* interrupt coalescing baseline: 9 == 3 to 5us interrupt delay per command */
+#define ISCI_COALESCE_BASE 9
+
/* expander attached sata devices require 3 rnc slots */
static inline int sci_remote_device_node_count(struct isci_remote_device *idev)
{
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index 61e0d09e2b57..29aa34efb0f5 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -59,10 +59,19 @@
#include <linux/firmware.h>
#include <linux/efi.h>
#include <asm/string.h>
+#include <scsi/scsi_host.h>
#include "isci.h"
#include "task.h"
#include "probe_roms.h"
+#define MAJ 1
+#define MIN 0
+#define BUILD 0
+#define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \
+ __stringify(BUILD)
+
+MODULE_VERSION(DRV_VERSION);
+
static struct scsi_transport_template *isci_transport_template;
static DEFINE_PCI_DEVICE_TABLE(isci_id_table) = {
@@ -113,6 +122,22 @@ unsigned char max_concurr_spinup = 1;
module_param(max_concurr_spinup, byte, 0);
MODULE_PARM_DESC(max_concurr_spinup, "Max concurrent device spinup");
+static ssize_t isci_show_id(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = container_of(dev, typeof(*shost), shost_dev);
+ struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
+ struct isci_host *ihost = container_of(sas_ha, typeof(*ihost), sas_ha);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", ihost->id);
+}
+
+static DEVICE_ATTR(isci_id, S_IRUGO, isci_show_id, NULL);
+
+struct device_attribute *isci_host_attrs[] = {
+ &dev_attr_isci_id,
+ NULL
+};
+
static struct scsi_host_template isci_sht = {
.module = THIS_MODULE,
@@ -138,6 +163,7 @@ static struct scsi_host_template isci_sht = {
.slave_alloc = sas_slave_alloc,
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
+ .shost_attrs = isci_host_attrs,
};
static struct sas_domain_function_template isci_transport_ops = {
@@ -232,17 +258,6 @@ static int isci_register_sas_ha(struct isci_host *isci_host)
return 0;
}
-static ssize_t isci_show_id(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct Scsi_Host *shost = container_of(dev, typeof(*shost), shost_dev);
- struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
- struct isci_host *ihost = container_of(sas_ha, typeof(*ihost), sas_ha);
-
- return snprintf(buf, PAGE_SIZE, "%d\n", ihost->id);
-}
-
-static DEVICE_ATTR(isci_id, S_IRUGO, isci_show_id, NULL);
-
static void isci_unregister(struct isci_host *isci_host)
{
struct Scsi_Host *shost;
@@ -251,7 +266,6 @@ static void isci_unregister(struct isci_host *isci_host)
return;
shost = isci_host->shost;
- device_remove_file(&shost->shost_dev, &dev_attr_isci_id);
sas_unregister_ha(&isci_host->sas_ha);
@@ -415,14 +429,8 @@ static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
if (err)
goto err_shost_remove;
- err = device_create_file(&shost->shost_dev, &dev_attr_isci_id);
- if (err)
- goto err_unregister_ha;
-
return isci_host;
- err_unregister_ha:
- sas_unregister_ha(&(isci_host->sas_ha));
err_shost_remove:
scsi_remove_host(shost);
err_shost:
@@ -540,7 +548,8 @@ static __init int isci_init(void)
{
int err;
- pr_info("%s: Intel(R) C600 SAS Controller Driver\n", DRV_NAME);
+ pr_info("%s: Intel(R) C600 SAS Controller Driver - version %s\n",
+ DRV_NAME, DRV_VERSION);
isci_transport_template = sas_domain_attach_transport(&isci_transport_ops);
if (!isci_transport_template)
diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c
index 79313a7a2356..09e61134037f 100644
--- a/drivers/scsi/isci/phy.c
+++ b/drivers/scsi/isci/phy.c
@@ -104,6 +104,7 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy,
u32 parity_count = 0;
u32 llctl, link_rate;
u32 clksm_value = 0;
+ u32 sp_timeouts = 0;
iphy->link_layer_registers = reg;
@@ -211,6 +212,18 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy,
llctl |= SCU_SAS_LLCTL_GEN_VAL(MAX_LINK_RATE, link_rate);
writel(llctl, &iphy->link_layer_registers->link_layer_control);
+ sp_timeouts = readl(&iphy->link_layer_registers->sas_phy_timeouts);
+
+ /* Clear the default 0x36 (54us) RATE_CHANGE timeout value. */
+ sp_timeouts &= ~SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0xFF);
+
+ /* Set RATE_CHANGE timeout value to 0x3B (59us). This ensures SCU can
+ * lock with 3Gb drive when SCU max rate is set to 1.5Gb.
+ */
+ sp_timeouts |= SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0x3B);
+
+ writel(sp_timeouts, &iphy->link_layer_registers->sas_phy_timeouts);
+
if (is_a2(ihost->pdev)) {
/* Program the max ARB time for the PHY to 700us so we inter-operate with
* the PMC expander which shuts down PHYs if the expander PHY generates too
@@ -695,7 +708,7 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
__func__,
event_code);
- return SCI_FAILURE;;
+ return SCI_FAILURE;
}
return SCI_SUCCESS;
case SCI_PHY_SUB_AWAIT_SATA_SPEED_EN:
diff --git a/drivers/scsi/isci/registers.h b/drivers/scsi/isci/registers.h
index 9b266c7428e8..00afc738bbed 100644
--- a/drivers/scsi/isci/registers.h
+++ b/drivers/scsi/isci/registers.h
@@ -1299,6 +1299,18 @@ struct scu_transport_layer_registers {
#define SCU_AFE_XCVRCR_OFFSET 0x00DC
#define SCU_AFE_LUTCR_OFFSET 0x00E0
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_ALIGN_DETECTION_SHIFT (0UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_ALIGN_DETECTION_MASK (0x000000FFUL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_HOT_PLUG_SHIFT (8UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_HOT_PLUG_MASK (0x0000FF00UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_COMSAS_DETECTION_SHIFT (16UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_COMSAS_DETECTION_MASK (0x00FF0000UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_RATE_CHANGE_SHIFT (24UL)
+#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_RATE_CHANGE_MASK (0xFF000000UL)
+
+#define SCU_SAS_PHYTOV_GEN_VAL(name, value) \
+ SCU_GEN_VALUE(SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_##name, value)
+
#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_SHIFT (0)
#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_MASK (0x00000003)
#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN1 (0)
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index a46e07ac789f..b5d3a8c4d329 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -732,12 +732,20 @@ sci_io_request_terminate(struct isci_request *ireq)
sci_change_state(&ireq->sm, SCI_REQ_ABORTING);
return SCI_SUCCESS;
case SCI_REQ_TASK_WAIT_TC_RESP:
+ /* The task frame was already confirmed to have been
+ * sent by the SCU HW. Since the state machine is
+ * now only waiting for the task response itself,
+ * abort the request and complete it immediately
+ * and don't wait for the task response.
+ */
sci_change_state(&ireq->sm, SCI_REQ_ABORTING);
sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
return SCI_SUCCESS;
case SCI_REQ_ABORTING:
- sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
- return SCI_SUCCESS;
+ /* If a request has a termination requested twice, return
+ * a failure indication, since HW confirmation of the first
+ * abort is still outstanding.
+ */
case SCI_REQ_COMPLETED:
default:
dev_warn(&ireq->owning_controller->pdev->dev,
@@ -2399,22 +2407,19 @@ static void isci_task_save_for_upper_layer_completion(
}
}
-static void isci_request_process_stp_response(struct sas_task *task,
- void *response_buffer)
+static void isci_process_stp_response(struct sas_task *task, struct dev_to_host_fis *fis)
{
- struct dev_to_host_fis *d2h_reg_fis = response_buffer;
struct task_status_struct *ts = &task->task_status;
struct ata_task_resp *resp = (void *)&ts->buf[0];
- resp->frame_len = le16_to_cpu(*(__le16 *)(response_buffer + 6));
- memcpy(&resp->ending_fis[0], response_buffer + 16, 24);
+ resp->frame_len = sizeof(*fis);
+ memcpy(resp->ending_fis, fis, sizeof(*fis));
ts->buf_valid_size = sizeof(*resp);
- /**
- * If the device fault bit is set in the status register, then
+ /* If the device fault bit is set in the status register, then
* set the sense data and return.
*/
- if (d2h_reg_fis->status & ATA_DF)
+ if (fis->status & ATA_DF)
ts->stat = SAS_PROTO_RESPONSE;
else
ts->stat = SAM_STAT_GOOD;
@@ -2428,7 +2433,6 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
{
struct sas_task *task = isci_request_access_task(request);
struct ssp_response_iu *resp_iu;
- void *resp_buf;
unsigned long task_flags;
struct isci_remote_device *idev = isci_lookup_device(task->dev);
enum service_response response = SAS_TASK_UNDELIVERED;
@@ -2565,9 +2569,7 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
task);
if (sas_protocol_ata(task->task_proto)) {
- resp_buf = &request->stp.rsp;
- isci_request_process_stp_response(task,
- resp_buf);
+ isci_process_stp_response(task, &request->stp.rsp);
} else if (SAS_PROTOCOL_SSP == task->task_proto) {
/* crack the iu response buffer. */
diff --git a/drivers/scsi/isci/unsolicited_frame_control.c b/drivers/scsi/isci/unsolicited_frame_control.c
index e9e1e2abacb9..16f88ab939c8 100644
--- a/drivers/scsi/isci/unsolicited_frame_control.c
+++ b/drivers/scsi/isci/unsolicited_frame_control.c
@@ -72,7 +72,7 @@ int sci_unsolicited_frame_control_construct(struct isci_host *ihost)
*/
buf_len = SCU_MAX_UNSOLICITED_FRAMES * SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
header_len = SCU_MAX_UNSOLICITED_FRAMES * sizeof(struct scu_unsolicited_frame_header);
- size = buf_len + header_len + SCU_MAX_UNSOLICITED_FRAMES * sizeof(dma_addr_t);
+ size = buf_len + header_len + SCU_MAX_UNSOLICITED_FRAMES * sizeof(uf_control->address_table.array[0]);
/*
* The Unsolicited Frame buffers are set at the start of the UF
diff --git a/drivers/scsi/isci/unsolicited_frame_control.h b/drivers/scsi/isci/unsolicited_frame_control.h
index 31cb9506f52d..75d896686f5a 100644
--- a/drivers/scsi/isci/unsolicited_frame_control.h
+++ b/drivers/scsi/isci/unsolicited_frame_control.h
@@ -214,7 +214,7 @@ struct sci_uf_address_table_array {
* starting address of the UF address table.
* 64-bit pointers are required by the hardware.
*/
- dma_addr_t *array;
+ u64 *array;
/**
* This field specifies the physical address location for the UF
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index 01ff082dc34c..d261e982a2fa 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -494,6 +494,9 @@ static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp,
*/
error = lport->tt.frame_send(lport, fp);
+ if (fh->fh_type == FC_TYPE_BLS)
+ return error;
+
/*
* Update the exchange and sequence flags,
* assuming all frames for the sequence have been sent.
@@ -575,42 +578,35 @@ static void fc_seq_set_resp(struct fc_seq *sp,
}
/**
- * fc_seq_exch_abort() - Abort an exchange and sequence
- * @req_sp: The sequence to be aborted
+ * fc_exch_abort_locked() - Abort an exchange
+ * @ep: The exchange to be aborted
* @timer_msec: The period of time to wait before aborting
*
- * Generally called because of a timeout or an abort from the upper layer.
+ * Locking notes: Called with exch lock held
+ *
+ * Return value: 0 on success else error code
*/
-static int fc_seq_exch_abort(const struct fc_seq *req_sp,
- unsigned int timer_msec)
+static int fc_exch_abort_locked(struct fc_exch *ep,
+ unsigned int timer_msec)
{
struct fc_seq *sp;
- struct fc_exch *ep;
struct fc_frame *fp;
int error;
- ep = fc_seq_exch(req_sp);
-
- spin_lock_bh(&ep->ex_lock);
if (ep->esb_stat & (ESB_ST_COMPLETE | ESB_ST_ABNORMAL) ||
- ep->state & (FC_EX_DONE | FC_EX_RST_CLEANUP)) {
- spin_unlock_bh(&ep->ex_lock);
+ ep->state & (FC_EX_DONE | FC_EX_RST_CLEANUP))
return -ENXIO;
- }
/*
* Send the abort on a new sequence if possible.
*/
sp = fc_seq_start_next_locked(&ep->seq);
- if (!sp) {
- spin_unlock_bh(&ep->ex_lock);
+ if (!sp)
return -ENOMEM;
- }
ep->esb_stat |= ESB_ST_SEQ_INIT | ESB_ST_ABNORMAL;
if (timer_msec)
fc_exch_timer_set_locked(ep, timer_msec);
- spin_unlock_bh(&ep->ex_lock);
/*
* If not logged into the fabric, don't send ABTS but leave
@@ -633,6 +629,28 @@ static int fc_seq_exch_abort(const struct fc_seq *req_sp,
}
/**
+ * fc_seq_exch_abort() - Abort an exchange and sequence
+ * @req_sp: The sequence to be aborted
+ * @timer_msec: The period of time to wait before aborting
+ *
+ * Generally called because of a timeout or an abort from the upper layer.
+ *
+ * Return value: 0 on success else error code
+ */
+static int fc_seq_exch_abort(const struct fc_seq *req_sp,
+ unsigned int timer_msec)
+{
+ struct fc_exch *ep;
+ int error;
+
+ ep = fc_seq_exch(req_sp);
+ spin_lock_bh(&ep->ex_lock);
+ error = fc_exch_abort_locked(ep, timer_msec);
+ spin_unlock_bh(&ep->ex_lock);
+ return error;
+}
+
+/**
* fc_exch_timeout() - Handle exchange timer expiration
* @work: The work_struct identifying the exchange that timed out
*/
@@ -1715,6 +1733,7 @@ static void fc_exch_reset(struct fc_exch *ep)
int rc = 1;
spin_lock_bh(&ep->ex_lock);
+ fc_exch_abort_locked(ep, 0);
ep->state |= FC_EX_RST_CLEANUP;
if (cancel_delayed_work(&ep->timeout_work))
atomic_dec(&ep->ex_refcnt); /* drop hold for timer */
@@ -1962,6 +1981,7 @@ static struct fc_seq *fc_exch_seq_send(struct fc_lport *lport,
struct fc_exch *ep;
struct fc_seq *sp = NULL;
struct fc_frame_header *fh;
+ struct fc_fcp_pkt *fsp = NULL;
int rc = 1;
ep = fc_exch_alloc(lport, fp);
@@ -1984,8 +2004,10 @@ static struct fc_seq *fc_exch_seq_send(struct fc_lport *lport,
fc_exch_setup_hdr(ep, fp, ep->f_ctl);
sp->cnt++;
- if (ep->xid <= lport->lro_xid && fh->fh_r_ctl == FC_RCTL_DD_UNSOL_CMD)
+ if (ep->xid <= lport->lro_xid && fh->fh_r_ctl == FC_RCTL_DD_UNSOL_CMD) {
+ fsp = fr_fsp(fp);
fc_fcp_ddp_setup(fr_fsp(fp), ep->xid);
+ }
if (unlikely(lport->tt.frame_send(lport, fp)))
goto err;
@@ -1999,7 +2021,8 @@ static struct fc_seq *fc_exch_seq_send(struct fc_lport *lport,
spin_unlock_bh(&ep->ex_lock);
return sp;
err:
- fc_fcp_ddp_done(fr_fsp(fp));
+ if (fsp)
+ fc_fcp_ddp_done(fsp);
rc = fc_exch_done_locked(ep);
spin_unlock_bh(&ep->ex_lock);
if (!rc)
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c
index afb63c843144..4c41ee816f0b 100644
--- a/drivers/scsi/libfc/fc_fcp.c
+++ b/drivers/scsi/libfc/fc_fcp.c
@@ -2019,6 +2019,11 @@ int fc_eh_abort(struct scsi_cmnd *sc_cmd)
struct fc_fcp_internal *si;
int rc = FAILED;
unsigned long flags;
+ int rval;
+
+ rval = fc_block_scsi_eh(sc_cmd);
+ if (rval)
+ return rval;
lport = shost_priv(sc_cmd->device->host);
if (lport->state != LPORT_ST_READY)
@@ -2068,9 +2073,9 @@ int fc_eh_device_reset(struct scsi_cmnd *sc_cmd)
int rc = FAILED;
int rval;
- rval = fc_remote_port_chkready(rport);
+ rval = fc_block_scsi_eh(sc_cmd);
if (rval)
- goto out;
+ return rval;
lport = shost_priv(sc_cmd->device->host);
@@ -2116,6 +2121,8 @@ int fc_eh_host_reset(struct scsi_cmnd *sc_cmd)
FC_SCSI_DBG(lport, "Resetting host\n");
+ fc_block_scsi_eh(sc_cmd);
+
lport->tt.lport_reset(lport);
wait_tmo = jiffies + FC_HOST_RESET_TIMEOUT;
while (!fc_fcp_lport_queue_ready(lport) && time_before(jiffies,
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index e55ed9cf23fb..628f347404f9 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -88,6 +88,7 @@
*/
#include <linux/timer.h>
+#include <linux/delay.h>
#include <linux/slab.h>
#include <asm/unaligned.h>
@@ -1029,8 +1030,16 @@ static void fc_lport_enter_reset(struct fc_lport *lport)
FCH_EVT_LIPRESET, 0);
fc_vports_linkchange(lport);
fc_lport_reset_locked(lport);
- if (lport->link_up)
+ if (lport->link_up) {
+ /*
+ * Wait upto resource allocation time out before
+ * doing re-login since incomplete FIP exchanged
+ * from last session may collide with exchanges
+ * in new session.
+ */
+ msleep(lport->r_a_tov);
fc_lport_enter_flogi(lport);
+ }
}
/**
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index f84084bba2f0..16ad97df5ba6 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -1721,7 +1721,7 @@ static int sas_find_bcast_dev(struct domain_device *dev,
list_for_each_entry(ch, &ex->children, siblings) {
if (ch->dev_type == EDGE_DEV || ch->dev_type == FANOUT_DEV) {
res = sas_find_bcast_dev(ch, src_dev);
- if (src_dev)
+ if (*src_dev)
return res;
}
}
@@ -1769,10 +1769,12 @@ static void sas_unregister_devs_sas_addr(struct domain_device *parent,
sas_disable_routing(parent, phy->attached_sas_addr);
}
memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
- sas_port_delete_phy(phy->port, phy->phy);
- if (phy->port->num_phys == 0)
- sas_port_delete(phy->port);
- phy->port = NULL;
+ if (phy->port) {
+ sas_port_delete_phy(phy->port, phy->phy);
+ if (phy->port->num_phys == 0)
+ sas_port_delete(phy->port);
+ phy->port = NULL;
+ }
}
static int sas_discover_bfs_by_root_level(struct domain_device *root,
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index 2e6619eff3ea..8883ca36f932 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -67,7 +67,7 @@
*
* NEC MegaRAID PCI Express ROMB 1000 0408 1033 8287
*
- * For history of changes, see Documentation/ChangeLog.megaraid
+ * For history of changes, see Documentation/scsi/ChangeLog.megaraid
*/
#include <linux/slab.h>
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 83035bd1c489..6825772cfd6a 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -42,7 +42,6 @@
* USA.
*/
-#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c
index 6861244249a3..2b1101076cfe 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_config.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_config.c
@@ -41,7 +41,6 @@
* USA.
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
index 38ed0260959d..246d5fbc6e5a 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
@@ -42,7 +42,6 @@
* USA.
*/
-#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index 6abd2fcc43e2..5202de3f3d3f 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -41,7 +41,6 @@
* USA.
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h
index 44d7885a4a1d..44b474513223 100644
--- a/drivers/scsi/mvsas/mv_sas.h
+++ b/drivers/scsi/mvsas/mv_sas.h
@@ -43,7 +43,6 @@
#include <scsi/scsi.h>
#include <scsi/scsi_tcq.h>
#include <scsi/sas_ata.h>
-#include <linux/version.h>
#include "mv_defs.h"
#define DRV_NAME "mvsas"
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index d079f9a3c6b3..b86db84d6f32 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -39,7 +39,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/hdreg.h>
-#include <linux/version.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <asm/irq.h>
diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h
index f920baf3ff24..ca496c7474e3 100644
--- a/drivers/scsi/pmcraid.h
+++ b/drivers/scsi/pmcraid.h
@@ -24,7 +24,6 @@
#ifndef _PMCRAID_H
#define _PMCRAID_H
-#include <linux/version.h>
#include <linux/types.h>
#include <linux/completion.h>
#include <linux/list.h>
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 7836eb01c7fc..a31e05f3bfd4 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -1786,13 +1786,16 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
}
- if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) {
+ if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) {
if (ha->fw_attributes & BIT_4) {
+ int prot = 0;
vha->flags.difdix_supported = 1;
ql_dbg(ql_dbg_user, vha, 0x7082,
"Registered for DIF/DIX type 1 and 3 protection.\n");
+ if (ql2xenabledif == 1)
+ prot = SHOST_DIX_TYPE0_PROTECTION;
scsi_host_set_prot(vha->host,
- SHOST_DIF_TYPE1_PROTECTION
+ prot | SHOST_DIF_TYPE1_PROTECTION
| SHOST_DIF_TYPE2_PROTECTION
| SHOST_DIF_TYPE3_PROTECTION
| SHOST_DIX_TYPE1_PROTECTION
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 2155071f3100..d79cd8a5f831 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -8,24 +8,24 @@
/*
* Table for showing the current message id in use for particular level
* Change this table for addition of log/debug messages.
- * -----------------------------------------------------
- * | Level | Last Value Used |
- * -----------------------------------------------------
- * | Module Init and Probe | 0x0116 |
- * | Mailbox commands | 0x111e |
- * | Device Discovery | 0x2083 |
- * | Queue Command and IO tracing | 0x302e |
- * | DPC Thread | 0x401c |
- * | Async Events | 0x5059 |
- * | Timer Routines | 0x600d |
- * | User Space Interactions | 0x709c |
- * | Task Management | 0x8043 |
- * | AER/EEH | 0x900f |
- * | Virtual Port | 0xa007 |
- * | ISP82XX Specific | 0xb027 |
- * | MultiQ | 0xc00b |
- * | Misc | 0xd00b |
- * -----------------------------------------------------
+ * ----------------------------------------------------------------------
+ * | Level | Last Value Used | Holes |
+ * ----------------------------------------------------------------------
+ * | Module Init and Probe | 0x0116 | |
+ * | Mailbox commands | 0x1126 | |
+ * | Device Discovery | 0x2083 | |
+ * | Queue Command and IO tracing | 0x302e | 0x3008 |
+ * | DPC Thread | 0x401c | |
+ * | Async Events | 0x5059 | |
+ * | Timer Routines | 0x600d | |
+ * | User Space Interactions | 0x709d | |
+ * | Task Management | 0x8041 | |
+ * | AER/EEH | 0x900f | |
+ * | Virtual Port | 0xa007 | |
+ * | ISP82XX Specific | 0xb04f | |
+ * | MultiQ | 0xc00b | |
+ * | Misc | 0xd00b | |
+ * ----------------------------------------------------------------------
*/
#include "qla_def.h"
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index cc5a79259d33..a03eaf40f377 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2529,6 +2529,7 @@ struct qla_hw_data {
#define DT_ISP8021 BIT_14
#define DT_ISP_LAST (DT_ISP8021 << 1)
+#define DT_T10_PI BIT_25
#define DT_IIDMA BIT_26
#define DT_FWI2 BIT_27
#define DT_ZIO_SUPPORTED BIT_28
@@ -2572,6 +2573,7 @@ struct qla_hw_data {
#define IS_NOCACHE_VPD_TYPE(ha) (IS_QLA81XX(ha))
#define IS_ALOGIO_CAPABLE(ha) (IS_QLA23XX(ha) || IS_FWI2_CAPABLE(ha))
+#define IS_T10_PI_CAPABLE(ha) ((ha)->device_type & DT_T10_PI)
#define IS_IIDMA_CAPABLE(ha) ((ha)->device_type & DT_IIDMA)
#define IS_FWI2_CAPABLE(ha) ((ha)->device_type & DT_FWI2)
#define IS_ZIO_SUPPORTED(ha) ((ha)->device_type & DT_ZIO_SUPPORTED)
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 691783abfb69..aa69486dc064 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -537,6 +537,11 @@ struct sts_entry_24xx {
/*
* If DIF Error is set in comp_status, these additional fields are
* defined:
+ *
+ * !!! NOTE: Firmware sends expected/actual DIF data in big endian
+ * format; but all of the "data" field gets swab32-d in the beginning
+ * of qla2x00_status_entry().
+ *
* &data[10] : uint8_t report_runt_bg[2]; - computed guard
* &data[12] : uint8_t actual_dif[8]; - DIF Data received
* &data[20] : uint8_t expected_dif[8]; - DIF Data computed
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index def694271bf7..37da04d3db26 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -3838,15 +3838,12 @@ qla2x00_loop_resync(scsi_qla_host_t *vha)
req = vha->req;
rsp = req->rsp;
- atomic_set(&vha->loop_state, LOOP_UPDATE);
clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
if (vha->flags.online) {
if (!(rval = qla2x00_fw_ready(vha))) {
/* Wait at most MAX_TARGET RSCNs for a stable link. */
wait_time = 256;
do {
- atomic_set(&vha->loop_state, LOOP_UPDATE);
-
/* Issue a marker after FW becomes ready. */
qla2x00_marker(vha, req, rsp, 0, 0,
MK_SYNC_ALL);
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index d2e904bc21c0..9902834e0b74 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -102,3 +102,32 @@ qla2x00_set_fcport_state(fc_port_t *fcport, int state)
fcport->d_id.b.al_pa);
}
}
+
+static inline int
+qla2x00_hba_err_chk_enabled(srb_t *sp)
+{
+ /*
+ * Uncomment when corresponding SCSI changes are done.
+ *
+ if (!sp->cmd->prot_chk)
+ return 0;
+ *
+ */
+
+ switch (scsi_get_prot_op(sp->cmd)) {
+ case SCSI_PROT_READ_STRIP:
+ case SCSI_PROT_WRITE_INSERT:
+ if (ql2xenablehba_err_chk >= 1)
+ return 1;
+ break;
+ case SCSI_PROT_READ_PASS:
+ case SCSI_PROT_WRITE_PASS:
+ if (ql2xenablehba_err_chk >= 2)
+ return 1;
+ break;
+ case SCSI_PROT_READ_INSERT:
+ case SCSI_PROT_WRITE_STRIP:
+ return 1;
+ }
+ return 0;
+}
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 49d6906af886..dbec89622a0f 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -709,20 +709,28 @@ struct fw_dif_context {
*
*/
static inline void
-qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt,
+qla24xx_set_t10dif_tags(srb_t *sp, struct fw_dif_context *pkt,
unsigned int protcnt)
{
- struct sd_dif_tuple *spt;
+ struct scsi_cmnd *cmd = sp->cmd;
scsi_qla_host_t *vha = shost_priv(cmd->device->host);
- unsigned char op = scsi_get_prot_op(cmd);
switch (scsi_get_prot_type(cmd)) {
- /* For TYPE 0 protection: no checking */
case SCSI_PROT_DIF_TYPE0:
- pkt->ref_tag_mask[0] = 0x00;
- pkt->ref_tag_mask[1] = 0x00;
- pkt->ref_tag_mask[2] = 0x00;
- pkt->ref_tag_mask[3] = 0x00;
+ /*
+ * No check for ql2xenablehba_err_chk, as it would be an
+ * I/O error if hba tag generation is not done.
+ */
+ pkt->ref_tag = cpu_to_le32((uint32_t)
+ (0xffffffff & scsi_get_lba(cmd)));
+
+ if (!qla2x00_hba_err_chk_enabled(sp))
+ break;
+
+ pkt->ref_tag_mask[0] = 0xff;
+ pkt->ref_tag_mask[1] = 0xff;
+ pkt->ref_tag_mask[2] = 0xff;
+ pkt->ref_tag_mask[3] = 0xff;
break;
/*
@@ -730,20 +738,16 @@ qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt,
* match LBA in CDB + N
*/
case SCSI_PROT_DIF_TYPE2:
- if (!ql2xenablehba_err_chk)
- break;
-
- if (scsi_prot_sg_count(cmd)) {
- spt = page_address(sg_page(scsi_prot_sglist(cmd))) +
- scsi_prot_sglist(cmd)[0].offset;
- pkt->app_tag = swab32(spt->app_tag);
- pkt->app_tag_mask[0] = 0xff;
- pkt->app_tag_mask[1] = 0xff;
- }
+ pkt->app_tag = __constant_cpu_to_le16(0);
+ pkt->app_tag_mask[0] = 0x0;
+ pkt->app_tag_mask[1] = 0x0;
pkt->ref_tag = cpu_to_le32((uint32_t)
(0xffffffff & scsi_get_lba(cmd)));
+ if (!qla2x00_hba_err_chk_enabled(sp))
+ break;
+
/* enable ALL bytes of the ref tag */
pkt->ref_tag_mask[0] = 0xff;
pkt->ref_tag_mask[1] = 0xff;
@@ -763,26 +767,15 @@ qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt,
* 16 bit app tag.
*/
case SCSI_PROT_DIF_TYPE1:
- if (!ql2xenablehba_err_chk)
+ pkt->ref_tag = cpu_to_le32((uint32_t)
+ (0xffffffff & scsi_get_lba(cmd)));
+ pkt->app_tag = __constant_cpu_to_le16(0);
+ pkt->app_tag_mask[0] = 0x0;
+ pkt->app_tag_mask[1] = 0x0;
+
+ if (!qla2x00_hba_err_chk_enabled(sp))
break;
- if (protcnt && (op == SCSI_PROT_WRITE_STRIP ||
- op == SCSI_PROT_WRITE_PASS)) {
- spt = page_address(sg_page(scsi_prot_sglist(cmd))) +
- scsi_prot_sglist(cmd)[0].offset;
- ql_dbg(ql_dbg_io, vha, 0x3008,
- "LBA from user %p, lba = 0x%x for cmd=%p.\n",
- spt, (int)spt->ref_tag, cmd);
- pkt->ref_tag = swab32(spt->ref_tag);
- pkt->app_tag_mask[0] = 0x0;
- pkt->app_tag_mask[1] = 0x0;
- } else {
- pkt->ref_tag = cpu_to_le32((uint32_t)
- (0xffffffff & scsi_get_lba(cmd)));
- pkt->app_tag = __constant_cpu_to_le16(0);
- pkt->app_tag_mask[0] = 0x0;
- pkt->app_tag_mask[1] = 0x0;
- }
/* enable ALL bytes of the ref tag */
pkt->ref_tag_mask[0] = 0xff;
pkt->ref_tag_mask[1] = 0xff;
@@ -798,8 +791,162 @@ qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt,
scsi_get_prot_type(cmd), cmd);
}
+struct qla2_sgx {
+ dma_addr_t dma_addr; /* OUT */
+ uint32_t dma_len; /* OUT */
+
+ uint32_t tot_bytes; /* IN */
+ struct scatterlist *cur_sg; /* IN */
+
+ /* for book keeping, bzero on initial invocation */
+ uint32_t bytes_consumed;
+ uint32_t num_bytes;
+ uint32_t tot_partial;
+
+ /* for debugging */
+ uint32_t num_sg;
+ srb_t *sp;
+};
static int
+qla24xx_get_one_block_sg(uint32_t blk_sz, struct qla2_sgx *sgx,
+ uint32_t *partial)
+{
+ struct scatterlist *sg;
+ uint32_t cumulative_partial, sg_len;
+ dma_addr_t sg_dma_addr;
+
+ if (sgx->num_bytes == sgx->tot_bytes)
+ return 0;
+
+ sg = sgx->cur_sg;
+ cumulative_partial = sgx->tot_partial;
+
+ sg_dma_addr = sg_dma_address(sg);
+ sg_len = sg_dma_len(sg);
+
+ sgx->dma_addr = sg_dma_addr + sgx->bytes_consumed;
+
+ if ((cumulative_partial + (sg_len - sgx->bytes_consumed)) >= blk_sz) {
+ sgx->dma_len = (blk_sz - cumulative_partial);
+ sgx->tot_partial = 0;
+ sgx->num_bytes += blk_sz;
+ *partial = 0;
+ } else {
+ sgx->dma_len = sg_len - sgx->bytes_consumed;
+ sgx->tot_partial += sgx->dma_len;
+ *partial = 1;
+ }
+
+ sgx->bytes_consumed += sgx->dma_len;
+
+ if (sg_len == sgx->bytes_consumed) {
+ sg = sg_next(sg);
+ sgx->num_sg++;
+ sgx->cur_sg = sg;
+ sgx->bytes_consumed = 0;
+ }
+
+ return 1;
+}
+
+static int
+qla24xx_walk_and_build_sglist_no_difb(struct qla_hw_data *ha, srb_t *sp,
+ uint32_t *dsd, uint16_t tot_dsds)
+{
+ void *next_dsd;
+ uint8_t avail_dsds = 0;
+ uint32_t dsd_list_len;
+ struct dsd_dma *dsd_ptr;
+ struct scatterlist *sg_prot;
+ uint32_t *cur_dsd = dsd;
+ uint16_t used_dsds = tot_dsds;
+
+ uint32_t prot_int;
+ uint32_t partial;
+ struct qla2_sgx sgx;
+ dma_addr_t sle_dma;
+ uint32_t sle_dma_len, tot_prot_dma_len = 0;
+ struct scsi_cmnd *cmd = sp->cmd;
+
+ prot_int = cmd->device->sector_size;
+
+ memset(&sgx, 0, sizeof(struct qla2_sgx));
+ sgx.tot_bytes = scsi_bufflen(sp->cmd);
+ sgx.cur_sg = scsi_sglist(sp->cmd);
+ sgx.sp = sp;
+
+ sg_prot = scsi_prot_sglist(sp->cmd);
+
+ while (qla24xx_get_one_block_sg(prot_int, &sgx, &partial)) {
+
+ sle_dma = sgx.dma_addr;
+ sle_dma_len = sgx.dma_len;
+alloc_and_fill:
+ /* Allocate additional continuation packets? */
+ if (avail_dsds == 0) {
+ avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ?
+ QLA_DSDS_PER_IOCB : used_dsds;
+ dsd_list_len = (avail_dsds + 1) * 12;
+ used_dsds -= avail_dsds;
+
+ /* allocate tracking DS */
+ dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC);
+ if (!dsd_ptr)
+ return 1;
+
+ /* allocate new list */
+ dsd_ptr->dsd_addr = next_dsd =
+ dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC,
+ &dsd_ptr->dsd_list_dma);
+
+ if (!next_dsd) {
+ /*
+ * Need to cleanup only this dsd_ptr, rest
+ * will be done by sp_free_dma()
+ */
+ kfree(dsd_ptr);
+ return 1;
+ }
+
+ list_add_tail(&dsd_ptr->list,
+ &((struct crc_context *)sp->ctx)->dsd_list);
+
+ sp->flags |= SRB_CRC_CTX_DSD_VALID;
+
+ /* add new list to cmd iocb or last list */
+ *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma));
+ *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma));
+ *cur_dsd++ = dsd_list_len;
+ cur_dsd = (uint32_t *)next_dsd;
+ }
+ *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(sle_dma_len);
+ avail_dsds--;
+
+ if (partial == 0) {
+ /* Got a full protection interval */
+ sle_dma = sg_dma_address(sg_prot) + tot_prot_dma_len;
+ sle_dma_len = 8;
+
+ tot_prot_dma_len += sle_dma_len;
+ if (tot_prot_dma_len == sg_dma_len(sg_prot)) {
+ tot_prot_dma_len = 0;
+ sg_prot = sg_next(sg_prot);
+ }
+
+ partial = 1; /* So as to not re-enter this block */
+ goto alloc_and_fill;
+ }
+ }
+ /* Null termination */
+ *cur_dsd++ = 0;
+ *cur_dsd++ = 0;
+ *cur_dsd++ = 0;
+ return 0;
+}
+static int
qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd,
uint16_t tot_dsds)
{
@@ -981,7 +1128,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
struct scsi_cmnd *cmd;
struct scatterlist *cur_seg;
int sgc;
- uint32_t total_bytes;
+ uint32_t total_bytes = 0;
uint32_t data_bytes;
uint32_t dif_bytes;
uint8_t bundling = 1;
@@ -1023,8 +1170,10 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
__constant_cpu_to_le16(CF_READ_DATA);
}
- tot_prot_dsds = scsi_prot_sg_count(cmd);
- if (!tot_prot_dsds)
+ if ((scsi_get_prot_op(sp->cmd) == SCSI_PROT_READ_INSERT) ||
+ (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_STRIP) ||
+ (scsi_get_prot_op(sp->cmd) == SCSI_PROT_READ_STRIP) ||
+ (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_INSERT))
bundling = 0;
/* Allocate CRC context from global pool */
@@ -1047,7 +1196,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
INIT_LIST_HEAD(&crc_ctx_pkt->dsd_list);
- qla24xx_set_t10dif_tags(cmd, (struct fw_dif_context *)
+ qla24xx_set_t10dif_tags(sp, (struct fw_dif_context *)
&crc_ctx_pkt->ref_tag, tot_prot_dsds);
cmd_pkt->crc_context_address[0] = cpu_to_le32(LSD(crc_ctx_dma));
@@ -1076,7 +1225,6 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
fcp_cmnd->additional_cdb_len |= 2;
int_to_scsilun(sp->cmd->device->lun, &fcp_cmnd->lun);
- host_to_fcp_swap((uint8_t *)&fcp_cmnd->lun, sizeof(fcp_cmnd->lun));
memcpy(fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len);
cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(fcp_cmnd_len);
cmd_pkt->fcp_cmnd_dseg_address[0] = cpu_to_le32(
@@ -1107,15 +1255,28 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
cmd_pkt->fcp_rsp_dseg_len = 0; /* Let response come in status iocb */
/* Compute dif len and adjust data len to incude protection */
- total_bytes = data_bytes;
dif_bytes = 0;
blk_size = cmd->device->sector_size;
- if (scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) {
- dif_bytes = (data_bytes / blk_size) * 8;
- total_bytes += dif_bytes;
+ dif_bytes = (data_bytes / blk_size) * 8;
+
+ switch (scsi_get_prot_op(sp->cmd)) {
+ case SCSI_PROT_READ_INSERT:
+ case SCSI_PROT_WRITE_STRIP:
+ total_bytes = data_bytes;
+ data_bytes += dif_bytes;
+ break;
+
+ case SCSI_PROT_READ_STRIP:
+ case SCSI_PROT_WRITE_INSERT:
+ case SCSI_PROT_READ_PASS:
+ case SCSI_PROT_WRITE_PASS:
+ total_bytes = data_bytes + dif_bytes;
+ break;
+ default:
+ BUG();
}
- if (!ql2xenablehba_err_chk)
+ if (!qla2x00_hba_err_chk_enabled(sp))
fw_prot_opts |= 0x10; /* Disable Guard tag checking */
if (!bundling) {
@@ -1151,7 +1312,12 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
cmd_pkt->control_flags |=
__constant_cpu_to_le16(CF_DATA_SEG_DESCR_ENABLE);
- if (qla24xx_walk_and_build_sglist(ha, sp, cur_dsd,
+
+ if (!bundling && tot_prot_dsds) {
+ if (qla24xx_walk_and_build_sglist_no_difb(ha, sp,
+ cur_dsd, tot_dsds))
+ goto crc_queuing_error;
+ } else if (qla24xx_walk_and_build_sglist(ha, sp, cur_dsd,
(tot_dsds - tot_prot_dsds)))
goto crc_queuing_error;
@@ -1414,6 +1580,22 @@ qla24xx_dif_start_scsi(srb_t *sp)
goto queuing_error;
else
sp->flags |= SRB_DMA_VALID;
+
+ if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) ||
+ (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP)) {
+ struct qla2_sgx sgx;
+ uint32_t partial;
+
+ memset(&sgx, 0, sizeof(struct qla2_sgx));
+ sgx.tot_bytes = scsi_bufflen(cmd);
+ sgx.cur_sg = scsi_sglist(cmd);
+ sgx.sp = sp;
+
+ nseg = 0;
+ while (qla24xx_get_one_block_sg(
+ cmd->device->sector_size, &sgx, &partial))
+ nseg++;
+ }
} else
nseg = 0;
@@ -1428,6 +1610,11 @@ qla24xx_dif_start_scsi(srb_t *sp)
goto queuing_error;
else
sp->flags |= SRB_CRC_PROT_DMA_VALID;
+
+ if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) ||
+ (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP)) {
+ nseg = scsi_bufflen(cmd) / cmd->device->sector_size;
+ }
} else {
nseg = 0;
}
@@ -1454,6 +1641,7 @@ qla24xx_dif_start_scsi(srb_t *sp)
/* Build header part of command packet (excluding the OPCODE). */
req->current_outstanding_cmd = handle;
req->outstanding_cmds[handle] = sp;
+ sp->handle = handle;
sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle;
req->cnt -= req_cnt;
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index b16b7725dee0..8a7591f035e6 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -719,7 +719,6 @@ skip_rio:
vha->flags.rscn_queue_overflow = 1;
}
- atomic_set(&vha->loop_state, LOOP_UPDATE);
atomic_set(&vha->loop_down_timer, 0);
vha->flags.management_server_logged_in = 0;
@@ -1435,25 +1434,27 @@ struct scsi_dif_tuple {
* ASC/ASCQ fields in the sense buffer with ILLEGAL_REQUEST
* to indicate to the kernel that the HBA detected error.
*/
-static inline void
+static inline int
qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24)
{
struct scsi_qla_host *vha = sp->fcport->vha;
struct scsi_cmnd *cmd = sp->cmd;
- struct scsi_dif_tuple *ep =
- (struct scsi_dif_tuple *)&sts24->data[20];
- struct scsi_dif_tuple *ap =
- (struct scsi_dif_tuple *)&sts24->data[12];
+ uint8_t *ap = &sts24->data[12];
+ uint8_t *ep = &sts24->data[20];
uint32_t e_ref_tag, a_ref_tag;
uint16_t e_app_tag, a_app_tag;
uint16_t e_guard, a_guard;
- e_ref_tag = be32_to_cpu(ep->ref_tag);
- a_ref_tag = be32_to_cpu(ap->ref_tag);
- e_app_tag = be16_to_cpu(ep->app_tag);
- a_app_tag = be16_to_cpu(ap->app_tag);
- e_guard = be16_to_cpu(ep->guard);
- a_guard = be16_to_cpu(ap->guard);
+ /*
+ * swab32 of the "data" field in the beginning of qla2x00_status_entry()
+ * would make guard field appear at offset 2
+ */
+ a_guard = le16_to_cpu(*(uint16_t *)(ap + 2));
+ a_app_tag = le16_to_cpu(*(uint16_t *)(ap + 0));
+ a_ref_tag = le32_to_cpu(*(uint32_t *)(ap + 4));
+ e_guard = le16_to_cpu(*(uint16_t *)(ep + 2));
+ e_app_tag = le16_to_cpu(*(uint16_t *)(ep + 0));
+ e_ref_tag = le32_to_cpu(*(uint32_t *)(ep + 4));
ql_dbg(ql_dbg_io, vha, 0x3023,
"iocb(s) %p Returned STATUS.\n", sts24);
@@ -1465,6 +1466,63 @@ qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24)
cmd->cmnd[0], (u64)scsi_get_lba(cmd), a_ref_tag, e_ref_tag,
a_app_tag, e_app_tag, a_guard, e_guard);
+ /*
+ * Ignore sector if:
+ * For type 3: ref & app tag is all 'f's
+ * For type 0,1,2: app tag is all 'f's
+ */
+ if ((a_app_tag == 0xffff) &&
+ ((scsi_get_prot_type(cmd) != SCSI_PROT_DIF_TYPE3) ||
+ (a_ref_tag == 0xffffffff))) {
+ uint32_t blocks_done, resid;
+ sector_t lba_s = scsi_get_lba(cmd);
+
+ /* 2TB boundary case covered automatically with this */
+ blocks_done = e_ref_tag - (uint32_t)lba_s + 1;
+
+ resid = scsi_bufflen(cmd) - (blocks_done *
+ cmd->device->sector_size);
+
+ scsi_set_resid(cmd, resid);
+ cmd->result = DID_OK << 16;
+
+ /* Update protection tag */
+ if (scsi_prot_sg_count(cmd)) {
+ uint32_t i, j = 0, k = 0, num_ent;
+ struct scatterlist *sg;
+ struct sd_dif_tuple *spt;
+
+ /* Patch the corresponding protection tags */
+ scsi_for_each_prot_sg(cmd, sg,
+ scsi_prot_sg_count(cmd), i) {
+ num_ent = sg_dma_len(sg) / 8;
+ if (k + num_ent < blocks_done) {
+ k += num_ent;
+ continue;
+ }
+ j = blocks_done - k - 1;
+ k = blocks_done;
+ break;
+ }
+
+ if (k != blocks_done) {
+ qla_printk(KERN_WARNING, sp->fcport->vha->hw,
+ "unexpected tag values tag:lba=%x:%llx)\n",
+ e_ref_tag, (unsigned long long)lba_s);
+ return 1;
+ }
+
+ spt = page_address(sg_page(sg)) + sg->offset;
+ spt += j;
+
+ spt->app_tag = 0xffff;
+ if (scsi_get_prot_type(cmd) == SCSI_PROT_DIF_TYPE3)
+ spt->ref_tag = 0xffffffff;
+ }
+
+ return 0;
+ }
+
/* check guard */
if (e_guard != a_guard) {
scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
@@ -1472,28 +1530,30 @@ qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24)
set_driver_byte(cmd, DRIVER_SENSE);
set_host_byte(cmd, DID_ABORT);
cmd->result |= SAM_STAT_CHECK_CONDITION << 1;
- return;
+ return 1;
}
- /* check appl tag */
- if (e_app_tag != a_app_tag) {
+ /* check ref tag */
+ if (e_ref_tag != a_ref_tag) {
scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
- 0x10, 0x2);
+ 0x10, 0x3);
set_driver_byte(cmd, DRIVER_SENSE);
set_host_byte(cmd, DID_ABORT);
cmd->result |= SAM_STAT_CHECK_CONDITION << 1;
- return;
+ return 1;
}
- /* check ref tag */
- if (e_ref_tag != a_ref_tag) {
+ /* check appl tag */
+ if (e_app_tag != a_app_tag) {
scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
- 0x10, 0x3);
+ 0x10, 0x2);
set_driver_byte(cmd, DRIVER_SENSE);
set_host_byte(cmd, DID_ABORT);
cmd->result |= SAM_STAT_CHECK_CONDITION << 1;
- return;
+ return 1;
}
+
+ return 1;
}
/**
@@ -1767,7 +1827,7 @@ check_scsi_status:
break;
case CS_DIF_ERROR:
- qla2x00_handle_dif_error(sp, sts24);
+ logit = qla2x00_handle_dif_error(sp, sts24);
break;
default:
cp->result = DID_ERROR << 16;
@@ -2468,11 +2528,10 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
goto skip_msi;
}
- if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX ||
- !QLA_MSIX_FW_MODE_1(ha->fw_attributes))) {
+ if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX)) {
ql_log(ql_log_warn, vha, 0x0035,
"MSI-X; Unsupported ISP2432 (0x%X, 0x%X).\n",
- ha->pdev->revision, ha->fw_attributes);
+ ha->pdev->revision, QLA_MSIX_CHIP_REV_24XX);
goto skip_msix;
}
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index c706ed370000..f488cc69fc79 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -472,7 +472,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
host->can_queue = base_vha->req->length + 128;
host->this_id = 255;
host->cmd_per_lun = 3;
- if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif)
+ if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif)
host->max_cmd_len = 32;
else
host->max_cmd_len = MAX_CMDSZ;
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index 5cbf33a50b14..049807cda419 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -2208,6 +2208,7 @@ qla82xx_msix_rsp_q(int irq, void *dev_id)
struct qla_hw_data *ha;
struct rsp_que *rsp;
struct device_reg_82xx __iomem *reg;
+ unsigned long flags;
rsp = (struct rsp_que *) dev_id;
if (!rsp) {
@@ -2218,11 +2219,11 @@ qla82xx_msix_rsp_q(int irq, void *dev_id)
ha = rsp->hw;
reg = &ha->iobase->isp82;
- spin_lock_irq(&ha->hardware_lock);
+ spin_lock_irqsave(&ha->hardware_lock, flags);
vha = pci_get_drvdata(ha->pdev);
qla24xx_process_response_queue(vha, rsp);
WRT_REG_DWORD(&reg->host_int, 0);
- spin_unlock_irq(&ha->hardware_lock);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
return IRQ_HANDLED;
}
@@ -2838,6 +2839,16 @@ sufficient_dsds:
int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
+ /* build FCP_CMND IU */
+ memset(ctx->fcp_cmnd, 0, sizeof(struct fcp_cmnd));
+ int_to_scsilun(sp->cmd->device->lun, &ctx->fcp_cmnd->lun);
+ ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len;
+
+ if (cmd->sc_data_direction == DMA_TO_DEVICE)
+ ctx->fcp_cmnd->additional_cdb_len |= 1;
+ else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
+ ctx->fcp_cmnd->additional_cdb_len |= 2;
+
/*
* Update tagged queuing modifier -- default is TSK_SIMPLE (0).
*/
@@ -2854,16 +2865,6 @@ sufficient_dsds:
}
}
- /* build FCP_CMND IU */
- memset(ctx->fcp_cmnd, 0, sizeof(struct fcp_cmnd));
- int_to_scsilun(sp->cmd->device->lun, &ctx->fcp_cmnd->lun);
- ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len;
-
- if (cmd->sc_data_direction == DMA_TO_DEVICE)
- ctx->fcp_cmnd->additional_cdb_len |= 1;
- else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
- ctx->fcp_cmnd->additional_cdb_len |= 2;
-
memcpy(ctx->fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len);
fcp_dl = (uint32_t *)(ctx->fcp_cmnd->cdb + 16 +
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index e02df276804e..1e69527f1e4e 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -106,17 +106,21 @@ MODULE_PARM_DESC(ql2xmaxqdepth,
"Maximum queue depth to report for target devices.");
/* Do not change the value of this after module load */
-int ql2xenabledif = 1;
+int ql2xenabledif = 0;
module_param(ql2xenabledif, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ql2xenabledif,
" Enable T10-CRC-DIF "
- " Default is 0 - No DIF Support. 1 - Enable it");
+ " Default is 0 - No DIF Support. 1 - Enable it"
+ ", 2 - Enable DIF for all types, except Type 0.");
-int ql2xenablehba_err_chk;
+int ql2xenablehba_err_chk = 2;
module_param(ql2xenablehba_err_chk, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ql2xenablehba_err_chk,
- " Enable T10-CRC-DIF Error isolation by HBA"
- " Default is 0 - Error isolation disabled, 1 - Enable it");
+ " Enable T10-CRC-DIF Error isolation by HBA:\n"
+ " Default is 1.\n"
+ " 0 -- Error isolation disabled\n"
+ " 1 -- Error isolation enabled only for DIX Type 0\n"
+ " 2 -- Error isolation enabled for all Types\n");
int ql2xiidmaenable=1;
module_param(ql2xiidmaenable, int, S_IRUGO);
@@ -909,7 +913,14 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
"Abort command mbx success.\n");
wait = 1;
}
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
qla2x00_sp_compl(ha, sp);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ /* Did the command return during mailbox execution? */
+ if (ret == FAILED && !CMD_SP(cmd))
+ ret = SUCCESS;
/* Wait for the command to be returned. */
if (wait) {
@@ -1317,10 +1328,9 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res)
qla2x00_sp_compl(ha, sp);
} else {
ctx = sp->ctx;
- if (ctx->type == SRB_LOGIN_CMD ||
- ctx->type == SRB_LOGOUT_CMD) {
- ctx->u.iocb_cmd->free(sp);
- } else {
+ if (ctx->type == SRB_ELS_CMD_RPT ||
+ ctx->type == SRB_ELS_CMD_HST ||
+ ctx->type == SRB_CT_CMD) {
struct fc_bsg_job *bsg_job =
ctx->u.bsg_job;
if (bsg_job->request->msgcode
@@ -1332,6 +1342,8 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res)
kfree(sp->ctx);
mempool_free(sp,
ha->srb_mempool);
+ } else {
+ ctx->u.iocb_cmd->free(sp);
}
}
}
@@ -2251,7 +2263,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
host->this_id = 255;
host->cmd_per_lun = 3;
host->unique_id = host->host_no;
- if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif)
+ if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif)
host->max_cmd_len = 32;
else
host->max_cmd_len = MAX_CMDSZ;
@@ -2378,13 +2390,16 @@ skip_dpc:
"Detected hba at address=%p.\n",
ha);
- if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) {
+ if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) {
if (ha->fw_attributes & BIT_4) {
+ int prot = 0;
base_vha->flags.difdix_supported = 1;
ql_dbg(ql_dbg_init, base_vha, 0x00f1,
"Registering for DIF/DIX type 1 and 3 protection.\n");
+ if (ql2xenabledif == 1)
+ prot = SHOST_DIX_TYPE0_PROTECTION;
scsi_host_set_prot(host,
- SHOST_DIF_TYPE1_PROTECTION
+ prot | SHOST_DIF_TYPE1_PROTECTION
| SHOST_DIF_TYPE2_PROTECTION
| SHOST_DIF_TYPE3_PROTECTION
| SHOST_DIX_TYPE1_PROTECTION
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 062c97bf62f5..13b6357c1fa2 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.03.07.03-k"
+#define QLA2XXX_VERSION "8.03.07.07-k"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 3
diff --git a/drivers/scsi/qla4xxx/Kconfig b/drivers/scsi/qla4xxx/Kconfig
index 2c33ce6eac1e..0f5599e0abf6 100644
--- a/drivers/scsi/qla4xxx/Kconfig
+++ b/drivers/scsi/qla4xxx/Kconfig
@@ -1,6 +1,6 @@
config SCSI_QLA_ISCSI
tristate "QLogic ISP4XXX and ISP82XX host adapter family support"
- depends on PCI && SCSI
+ depends on PCI && SCSI && NET
select SCSI_ISCSI_ATTRS
---help---
This driver supports the QLogic 40xx (ISP4XXX) and 8022 (ISP82XX)
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 909ed9ed24c0..441a1c5b8974 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -50,6 +50,7 @@ static int sg_version_num = 30534; /* 2 digits for each component */
#include <linux/delay.h>
#include <linux/blktrace_api.h>
#include <linux/mutex.h>
+#include <linux/ratelimit.h>
#include "scsi.h"
#include <scsi/scsi_dbg.h>
@@ -626,14 +627,15 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
*/
if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV) {
static char cmd[TASK_COMM_LEN];
- if (strcmp(current->comm, cmd) && printk_ratelimit()) {
- printk(KERN_WARNING
- "sg_write: data in/out %d/%d bytes for SCSI command 0x%x--"
- "guessing data in;\n "
- "program %s not setting count and/or reply_len properly\n",
- old_hdr.reply_len - (int)SZ_SG_HEADER,
- input_size, (unsigned int) cmnd[0],
- current->comm);
+ if (strcmp(current->comm, cmd)) {
+ printk_ratelimited(KERN_WARNING
+ "sg_write: data in/out %d/%d bytes "
+ "for SCSI command 0x%x-- guessing "
+ "data in;\n program %s not setting "
+ "count and/or reply_len properly\n",
+ old_hdr.reply_len - (int)SZ_SG_HEADER,
+ input_size, (unsigned int) cmnd[0],
+ current->comm);
strcpy(cmd, current->comm);
}
}
diff --git a/drivers/sh/intc/chip.c b/drivers/sh/intc/chip.c
index f33e2dd97934..33b2ed451e09 100644
--- a/drivers/sh/intc/chip.c
+++ b/drivers/sh/intc/chip.c
@@ -186,6 +186,9 @@ static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
!defined(CONFIG_CPU_SUBTYPE_SH7709)
[IRQ_TYPE_LEVEL_HIGH] = VALID(3),
#endif
+#if defined(CONFIG_ARCH_SH7372)
+ [IRQ_TYPE_EDGE_BOTH] = VALID(4),
+#endif
};
static int intc_set_type(struct irq_data *data, unsigned int type)
diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c
index d2407558773f..24cacff57786 100644
--- a/drivers/spi/spi-fsl-spi.c
+++ b/drivers/spi/spi-fsl-spi.c
@@ -825,6 +825,9 @@ static void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi)
{
struct device *dev = mspi->dev;
+ if (!(mspi->flags & SPI_CPM_MODE))
+ return;
+
dma_unmap_single(dev, mspi->dma_dummy_rx, SPI_MRBLR, DMA_FROM_DEVICE);
dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
cpm_muram_free(cpm_muram_offset(mspi->tx_bd));
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 8ac6542aedcd..fa594d604aca 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -786,9 +786,11 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
if (cs_gpio < 0)
cs_gpio = mxc_platform_info->chipselect[i];
+
+ spi_imx->chipselect[i] = cs_gpio;
if (cs_gpio < 0)
continue;
- spi_imx->chipselect[i] = cs_gpio;
+
ret = gpio_request(spi_imx->chipselect[i], DRIVER_NAME);
if (ret) {
while (i > 0) {
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
index 1d23f3831866..6a80749391db 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.c
@@ -50,6 +50,8 @@
#define PCH_RX_THOLD 7
#define PCH_RX_THOLD_MAX 15
+#define PCH_TX_THOLD 2
+
#define PCH_MAX_BAUDRATE 5000000
#define PCH_MAX_FIFO_DEPTH 16
@@ -58,6 +60,7 @@
#define PCH_SLEEP_TIME 10
#define SSN_LOW 0x02U
+#define SSN_HIGH 0x03U
#define SSN_NO_CONTROL 0x00U
#define PCH_MAX_CS 0xFF
#define PCI_DEVICE_ID_GE_SPI 0x8816
@@ -316,16 +319,19 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val,
/* if transfer complete interrupt */
if (reg_spsr_val & SPSR_FI_BIT) {
- if (tx_index < bpw_len)
+ if ((tx_index == bpw_len) && (rx_index == tx_index)) {
+ /* disable interrupts */
+ pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL);
+
+ /* transfer is completed;
+ inform pch_spi_process_messages */
+ data->transfer_complete = true;
+ data->transfer_active = false;
+ wake_up(&data->wait);
+ } else {
dev_err(&data->master->dev,
"%s : Transfer is not completed", __func__);
- /* disable interrupts */
- pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL);
-
- /* transfer is completed;inform pch_spi_process_messages */
- data->transfer_complete = true;
- data->transfer_active = false;
- wake_up(&data->wait);
+ }
}
}
@@ -348,16 +354,26 @@ static irqreturn_t pch_spi_handler(int irq, void *dev_id)
"%s returning due to suspend\n", __func__);
return IRQ_NONE;
}
- if (data->use_dma)
- return IRQ_NONE;
io_remap_addr = data->io_remap_addr;
spsr = io_remap_addr + PCH_SPSR;
reg_spsr_val = ioread32(spsr);
- if (reg_spsr_val & SPSR_ORF_BIT)
- dev_err(&board_dat->pdev->dev, "%s Over run error", __func__);
+ if (reg_spsr_val & SPSR_ORF_BIT) {
+ dev_err(&board_dat->pdev->dev, "%s Over run error\n", __func__);
+ if (data->current_msg->complete != 0) {
+ data->transfer_complete = true;
+ data->current_msg->status = -EIO;
+ data->current_msg->complete(data->current_msg->context);
+ data->bcurrent_msg_processing = false;
+ data->current_msg = NULL;
+ data->cur_trans = NULL;
+ }
+ }
+
+ if (data->use_dma)
+ return IRQ_NONE;
/* Check if the interrupt is for SPI device */
if (reg_spsr_val & (SPSR_FI_BIT | SPSR_RFI_BIT)) {
@@ -756,10 +772,6 @@ static void pch_spi_set_ir(struct pch_spi_data *data)
wait_event_interruptible(data->wait, data->transfer_complete);
- pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL);
- dev_dbg(&data->master->dev,
- "%s:no more control over SSN-writing 0 to SSNXCR.", __func__);
-
/* clear all interrupts */
pch_spi_writereg(data->master, PCH_SPSR,
pch_spi_readreg(data->master, PCH_SPSR));
@@ -815,10 +827,11 @@ static void pch_spi_copy_rx_data_for_dma(struct pch_spi_data *data, int bpw)
}
}
-static void pch_spi_start_transfer(struct pch_spi_data *data)
+static int pch_spi_start_transfer(struct pch_spi_data *data)
{
struct pch_spi_dma_ctrl *dma;
unsigned long flags;
+ int rtn;
dma = &data->dma;
@@ -833,19 +846,23 @@ static void pch_spi_start_transfer(struct pch_spi_data *data)
initiating the transfer. */
dev_dbg(&data->master->dev,
"%s:waiting for transfer to get over\n", __func__);
- wait_event_interruptible(data->wait, data->transfer_complete);
+ rtn = wait_event_interruptible_timeout(data->wait,
+ data->transfer_complete,
+ msecs_to_jiffies(2 * HZ));
dma_sync_sg_for_cpu(&data->master->dev, dma->sg_rx_p, dma->nent,
DMA_FROM_DEVICE);
+
+ dma_sync_sg_for_cpu(&data->master->dev, dma->sg_tx_p, dma->nent,
+ DMA_FROM_DEVICE);
+ memset(data->dma.tx_buf_virt, 0, PAGE_SIZE);
+
async_tx_ack(dma->desc_rx);
async_tx_ack(dma->desc_tx);
kfree(dma->sg_tx_p);
kfree(dma->sg_rx_p);
spin_lock_irqsave(&data->lock, flags);
- pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL);
- dev_dbg(&data->master->dev,
- "%s:no more control over SSN-writing 0 to SSNXCR.", __func__);
/* clear fifo threshold, disable interrupts, disable SPI transfer */
pch_spi_setclr_reg(data->master, PCH_SPCR, 0,
@@ -858,6 +875,8 @@ static void pch_spi_start_transfer(struct pch_spi_data *data)
pch_spi_clear_fifo(data->master);
spin_unlock_irqrestore(&data->lock, flags);
+
+ return rtn;
}
static void pch_dma_rx_complete(void *arg)
@@ -1023,8 +1042,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
/* set receive fifo threshold and transmit fifo threshold */
pch_spi_setclr_reg(data->master, PCH_SPCR,
((size - 1) << SPCR_RFIC_FIELD) |
- ((PCH_MAX_FIFO_DEPTH - PCH_DMA_TRANS_SIZE) <<
- SPCR_TFIC_FIELD),
+ (PCH_TX_THOLD << SPCR_TFIC_FIELD),
MASK_RFIC_SPCR_BITS | MASK_TFIC_SPCR_BITS);
spin_unlock_irqrestore(&data->lock, flags);
@@ -1035,13 +1053,20 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
/* offset, length setting */
sg = dma->sg_rx_p;
for (i = 0; i < num; i++, sg++) {
- if (i == 0) {
- sg->offset = 0;
+ if (i == (num - 2)) {
+ sg->offset = size * i;
+ sg->offset = sg->offset * (*bpw / 8);
sg_set_page(sg, virt_to_page(dma->rx_buf_virt), rem,
sg->offset);
sg_dma_len(sg) = rem;
+ } else if (i == (num - 1)) {
+ sg->offset = size * (i - 1) + rem;
+ sg->offset = sg->offset * (*bpw / 8);
+ sg_set_page(sg, virt_to_page(dma->rx_buf_virt), size,
+ sg->offset);
+ sg_dma_len(sg) = size;
} else {
- sg->offset = rem + size * (i - 1);
+ sg->offset = size * i;
sg->offset = sg->offset * (*bpw / 8);
sg_set_page(sg, virt_to_page(dma->rx_buf_virt), size,
sg->offset);
@@ -1065,6 +1090,16 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
dma->desc_rx = desc_rx;
/* TX */
+ if (data->bpw_len > PCH_DMA_TRANS_SIZE) {
+ num = data->bpw_len / PCH_DMA_TRANS_SIZE;
+ size = PCH_DMA_TRANS_SIZE;
+ rem = 16;
+ } else {
+ num = 1;
+ size = data->bpw_len;
+ rem = data->bpw_len;
+ }
+
dma->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC);
sg_init_table(dma->sg_tx_p, num); /* Initialize SG table */
/* offset, length setting */
@@ -1162,6 +1197,7 @@ static void pch_spi_process_messages(struct work_struct *pwork)
if (data->use_dma)
pch_spi_request_dma(data,
data->current_msg->spi->bits_per_word);
+ pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL);
do {
/* If we are already processing a message get the next
transfer structure from the message otherwise retrieve
@@ -1184,7 +1220,8 @@ static void pch_spi_process_messages(struct work_struct *pwork)
if (data->use_dma) {
pch_spi_handle_dma(data, &bpw);
- pch_spi_start_transfer(data);
+ if (!pch_spi_start_transfer(data))
+ goto out;
pch_spi_copy_rx_data_for_dma(data, bpw);
} else {
pch_spi_set_tx(data, &bpw);
@@ -1222,6 +1259,8 @@ static void pch_spi_process_messages(struct work_struct *pwork)
} while (data->cur_trans != NULL);
+out:
+ pch_spi_writereg(data->master, PCH_SSNXCR, SSN_HIGH);
if (data->use_dma)
pch_spi_release_dma(data);
}
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 29c7d4f9d1ae..d0cbdb0cf9d5 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -1260,16 +1260,34 @@ void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags)
}
EXPORT_SYMBOL(ssb_device_disable);
+/* Some chipsets need routing known for PCIe and 64-bit DMA */
+static bool ssb_dma_translation_special_bit(struct ssb_device *dev)
+{
+ u16 chip_id = dev->bus->chip_id;
+
+ if (dev->id.coreid == SSB_DEV_80211) {
+ return (chip_id == 0x4322 || chip_id == 43221 ||
+ chip_id == 43231 || chip_id == 43222);
+ }
+
+ return 0;
+}
+
u32 ssb_dma_translation(struct ssb_device *dev)
{
switch (dev->bus->bustype) {
case SSB_BUSTYPE_SSB:
return 0;
case SSB_BUSTYPE_PCI:
- if (ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64)
+ if (pci_is_pcie(dev->bus->host_pci) &&
+ ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64) {
return SSB_PCIE_DMA_H32;
- else
- return SSB_PCI_DMA;
+ } else {
+ if (ssb_dma_translation_special_bit(dev))
+ return SSB_PCIE_DMA_H32;
+ else
+ return SSB_PCI_DMA;
+ }
default:
__ssb_dma_not_implemented(dev);
}
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index bd3d1cc1d16e..036d9de041b8 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -46,7 +46,7 @@ source "drivers/staging/wlan-ng/Kconfig"
source "drivers/staging/echo/Kconfig"
-source "drivers/staging/brcm80211/Kconfig"
+
source "drivers/staging/comedi/Kconfig"
@@ -128,8 +128,6 @@ source "drivers/staging/quickstart/Kconfig"
source "drivers/staging/sbe-2t3e3/Kconfig"
-source "drivers/staging/ath6kl/Kconfig"
-
source "drivers/staging/keucr/Kconfig"
source "drivers/staging/bcm/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index d480a94cc7fd..0599509ff4f7 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -15,8 +15,8 @@ obj-$(CONFIG_USBIP_CORE) += usbip/
obj-$(CONFIG_W35UND) += winbond/
obj-$(CONFIG_PRISM2_USB) += wlan-ng/
obj-$(CONFIG_ECHO) += echo/
-obj-$(CONFIG_BRCMSMAC) += brcm80211/
-obj-$(CONFIG_BRCMFMAC) += brcm80211/
+
+
obj-$(CONFIG_COMEDI) += comedi/
obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon/
obj-$(CONFIG_ASUS_OLED) += asus_oled/
@@ -55,7 +55,6 @@ obj-$(CONFIG_SOLO6X10) += solo6x10/
obj-$(CONFIG_TIDSPBRIDGE) += tidspbridge/
obj-$(CONFIG_ACPI_QUICKSTART) += quickstart/
obj-$(CONFIG_SBE_2T3E3) += sbe-2t3e3/
-obj-$(CONFIG_ATH6K_LEGACY) += ath6kl/
obj-$(CONFIG_USB_ENESTORAGE) += keucr/
obj-$(CONFIG_BCM_WIMAX) += bcm/
obj-$(CONFIG_FT1000) += ft1000/
diff --git a/drivers/staging/ath6kl/Kconfig b/drivers/staging/ath6kl/Kconfig
deleted file mode 100644
index afd6cc16a2b8..000000000000
--- a/drivers/staging/ath6kl/Kconfig
+++ /dev/null
@@ -1,158 +0,0 @@
-config ATH6K_LEGACY
- tristate "Atheros AR6003 support (non mac80211)"
- depends on MMC && WLAN
- depends on CFG80211
- select WIRELESS_EXT
- select WEXT_PRIV
- help
- This module adds support for wireless adapters based on Atheros AR6003 chipset running over SDIO. If you choose to build it as a module, it will be called ath6kl. Pls note that AR6002 and AR6001 are not supported by this driver.
-
-choice
- prompt "AR6003 Board Data Configuration"
- depends on ATH6K_LEGACY
- default AR600x_SD31_XXX
- help
- Select the appropriate board data template from the list below that matches your AR6003 based reference design.
-
-config AR600x_SD31_XXX
- bool "SD31-xxx"
- help
- Board Data file for a standard SD31 reference design (File: bdata.SD31.bin)
-
-config AR600x_WB31_XXX
- bool "WB31-xxx"
- help
- Board Data file for a standard WB31 (BT/WiFi) reference design (File: bdata.WB31.bin)
-
-config AR600x_SD32_XXX
- bool "SD32-xxx"
- help
- Board Data file for a standard SD32 (5GHz) reference design (File: bdata.SD32.bin)
-
-config AR600x_CUSTOM_XXX
- bool "CUSTOM-xxx"
- help
- Board Data file for a custom reference design (File: should be named as bdata.CUSTOM.bin)
-endchoice
-
-config ATH6KL_ENABLE_COEXISTENCE
- bool "BT Coexistence support"
- depends on ATH6K_LEGACY
- help
- Enables WLAN/BT coexistence support. Select the apprpriate configuration from below.
-
-choice
- prompt "Front-End Antenna Configuration"
- depends on ATH6KL_ENABLE_COEXISTENCE
- default AR600x_DUAL_ANTENNA
- help
- Indicates the number of antennas being used by BT and WLAN. Select the appropriate configuration from the list below that matches your AR6003 based reference design.
-
-config AR600x_DUAL_ANTENNA
- bool "Dual Antenna"
- help
- Dual Antenna Design
-
-config AR600x_SINGLE_ANTENNA
- bool "Single Antenna"
- help
- Single Antenna Design
-endchoice
-
-choice
- prompt "Collocated Bluetooth Type"
- depends on ATH6KL_ENABLE_COEXISTENCE
- default AR600x_BT_AR3001
- help
- Select the appropriate configuration from the list below that matches your AR6003 based reference design.
-
-config AR600x_BT_QCOM
- bool "Qualcomm BTS4020X"
- help
- Qualcomm BT (3 Wire PTA)
-
-config AR600x_BT_CSR
- bool "CSR BC06"
- help
- CSR BT (3 Wire PTA)
-
-config AR600x_BT_AR3001
- bool "Atheros AR3001"
- help
- Atheros BT (3 Wire PTA)
-endchoice
-
-config ATH6KL_HCI_BRIDGE
- bool "HCI over SDIO support"
- depends on ATH6K_LEGACY
- help
- Enables BT over SDIO. Applicable only for combo designs (eg: WB31)
-
-config ATH6KL_CONFIG_GPIO_BT_RESET
- bool "Configure BT Reset GPIO"
- depends on ATH6KL_HCI_BRIDGE
- help
- Configure a WLAN GPIO for use with BT.
-
-config AR600x_BT_RESET_PIN
- int "GPIO"
- depends on ATH6KL_CONFIG_GPIO_BT_RESET
- default 22
- help
- WLAN GPIO to be used for resetting BT
-
-config ATH6KL_HTC_RAW_INTERFACE
- bool "RAW HTC support"
- depends on ATH6K_LEGACY
- help
- Enables raw HTC interface. Allows application to directly talk to the HTC interface via the ioctl interface
-
-config ATH6KL_VIRTUAL_SCATTER_GATHER
- bool "Virtual Scatter-Gather support"
- depends on ATH6K_LEGACY
- help
- Enables virtual scatter gather support for the hardware that does not support it natively.
-
-config ATH6KL_SKIP_ABI_VERSION_CHECK
- bool "Skip ABI version check support"
- depends on ATH6K_LEGACY
- help
- Forces the driver to disable ABI version check. Caution: Incompatilbity between the host driver and target firmware may lead to unknown side effects.
-
-config ATH6KL_BT_UART_FC_POLARITY
- int "UART Flow Control Polarity"
- depends on ATH6KL_LEGACY
- default 0
- help
- Configures the polarity of UART Flow Control. A value of 0 implies active low and is the default setting. Set it to 1 for active high.
-
-config ATH6KL_DEBUG
- bool "Debug support"
- depends on ATH6K_LEGACY
- help
- Enables debug support
-
-config ATH6KL_ENABLE_HOST_DEBUG
- bool "Host Debug support"
- depends on ATH6KL_DEBUG
- help
- Enables debug support in the driver
-
-config ATH6KL_ENABLE_TARGET_DEBUG_PRINTS
- bool "Target Debug support - Enable UART prints"
- depends on ATH6KL_DEBUG
- help
- Enables uart prints
-
-config AR600x_DEBUG_UART_TX_PIN
- int "GPIO"
- depends on ATH6KL_ENABLE_TARGET_DEBUG_PRINTS
- default 8
- help
- WLAN GPIO to be used for Debug UART (Tx)
-
-config ATH6KL_DISABLE_TARGET_DBGLOGS
- bool "Target Debug support - Disable Debug logs"
- depends on ATH6KL_DEBUG
- help
- Enables debug logs
diff --git a/drivers/staging/ath6kl/Makefile b/drivers/staging/ath6kl/Makefile
deleted file mode 100644
index 1d3f2390a172..000000000000
--- a/drivers/staging/ath6kl/Makefile
+++ /dev/null
@@ -1,122 +0,0 @@
-#------------------------------------------------------------------------------
-# Copyright (c) 2004-2010 Atheros Communications Inc.
-# All rights reserved.
-#
-#
-#
-# 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.
-#
-#
-#
-# Author(s): ="Atheros"
-#------------------------------------------------------------------------------
-
-ccflags-y += -I$(obj)/include
-ccflags-y += -I$(obj)/include/common
-ccflags-y += -I$(obj)/wlan/include
-ccflags-y += -I$(obj)/os/linux/include
-ccflags-y += -I$(obj)/os
-ccflags-y += -I$(obj)/bmi/include
-ccflags-y += -I$(obj)/include/common/AR6002/hw4.0
-
-ifeq ($(CONFIG_AR600x_DUAL_ANTENNA),y)
-ccflags-y += -DAR600x_DUAL_ANTENNA
-endif
-
-ifeq ($(CONFIG_AR600x_SINGLE_ANTENNA),y)
-ccflags-y += -DAR600x_SINGLE_ANTENNA
-endif
-
-ifeq ($(CONFIG_AR600x_BT_QCOM),y)
-ccflags-y += -DAR600x_BT_QCOM
-endif
-
-ifeq ($(CONFIG_AR600x_BT_CSR),y)
-ccflags-y += -DAR600x_BT_CSR
-endif
-
-ifeq ($(CONFIG_AR600x_BT_AR3001),y)
-ccflags-y += -DAR600x_BT_AR3001
-endif
-
-ifeq ($(CONFIG_ATH6KL_HCI_BRIDGE),y)
-ccflags-y += -DATH_AR6K_ENABLE_GMBOX
-ccflags-y += -DHCI_TRANSPORT_SDIO
-ccflags-y += -DSETUPHCI_ENABLED
-ccflags-y += -DSETUPBTDEV_ENABLED
-ath6kl-y += htc2/AR6000/ar6k_gmbox.o
-ath6kl-y += htc2/AR6000/ar6k_gmbox_hciuart.o
-ath6kl-y += miscdrv/ar3kconfig.o
-ath6kl-y += miscdrv/ar3kps/ar3kpsconfig.o
-ath6kl-y += miscdrv/ar3kps/ar3kpsparser.o
-endif
-
-ifeq ($(CONFIG_ATH6KL_CONFIG_GPIO_BT_RESET),y)
-ccflags-y += -DATH6KL_CONFIG_GPIO_BT_RESET
-endif
-
-ifeq ($(CONFIG_ATH6KL_HTC_RAW_INTERFACE),y)
-ccflags-y += -DHTC_RAW_INTERFACE
-endif
-
-ifeq ($(CONFIG_ATH6KL_ENABLE_HOST_DEBUG),y)
-ccflags-y += -DDEBUG
-ccflags-y += -DATH_DEBUG_MODULE
-endif
-
-ifeq ($(CONFIG_ATH6KL_ENABLE_TARGET_DEBUG_PRINTS),y)
-ccflags-y += -DENABLEUARTPRINT_SET
-endif
-
-ifeq ($(CONFIG_ATH6KL_DISABLE_TARGET_DBGLOGS),y)
-ccflags-y += -DATH6KL_DISABLE_TARGET_DBGLOGS
-endif
-
-ifeq ($(CONFIG_ATH6KL_VIRTUAL_SCATTER_GATHER),y)
-ccflags-y += -DATH6KL_CONFIG_HIF_VIRTUAL_SCATTER
-endif
-
-ifeq ($(CONFIG_ATH6KL_SKIP_ABI_VERSION_CHECK),y)
-ccflags-y += -DATH6KL_SKIP_ABI_VERSION_CHECK
-endif
-
-ccflags-y += -DWAPI_ENABLE
-ccflags-y += -DCHECKSUM_OFFLOAD
-
-obj-$(CONFIG_ATH6K_LEGACY) := ath6kl.o
-ath6kl-y += htc2/AR6000/ar6k.o
-ath6kl-y += htc2/AR6000/ar6k_events.o
-ath6kl-y += htc2/htc_send.o
-ath6kl-y += htc2/htc_recv.o
-ath6kl-y += htc2/htc_services.o
-ath6kl-y += htc2/htc.o
-ath6kl-y += bmi/src/bmi.o
-ath6kl-y += os/linux/cfg80211.o
-ath6kl-y += os/linux/ar6000_drv.o
-ath6kl-y += os/linux/ar6000_raw_if.o
-ath6kl-y += os/linux/ar6000_pm.o
-ath6kl-y += os/linux/netbuf.o
-ath6kl-y += os/linux/hci_bridge.o
-ath6kl-y += miscdrv/common_drv.o
-ath6kl-y += miscdrv/credit_dist.o
-ath6kl-y += wmi/wmi.o
-ath6kl-y += reorder/rcv_aggr.o
-ath6kl-y += wlan/src/wlan_node.o
-ath6kl-y += wlan/src/wlan_recv_beacon.o
-ath6kl-y += wlan/src/wlan_utils.o
-
-# ATH_HIF_TYPE := sdio
-ccflags-y += -I$(obj)/hif/sdio/linux_sdio/include
-ccflags-y += -DSDIO
-ath6kl-y += hif/sdio/linux_sdio/src/hif.o
-ath6kl-y += hif/sdio/linux_sdio/src/hif_scatter.o
diff --git a/drivers/staging/ath6kl/TODO b/drivers/staging/ath6kl/TODO
deleted file mode 100644
index 7be4b46ebb59..000000000000
--- a/drivers/staging/ath6kl/TODO
+++ /dev/null
@@ -1,25 +0,0 @@
-TODO:
-
-We are working hard on cleaning up the driver. There's sooooooooo much todo
-so instead of editing this file please use the wiki:
-
-http://wireless.kernel.org/en/users/Drivers/ath6kl
-
-There's a respective TODO page there. Please also subscribe to the wiki page
-to get e-mail updates on changes.
-
-IRC:
-
-We *really* need to coordinate development for ath6kl as the cleanup
-patches will break pretty much any other patches. Please use IRC to
-help coordinate better:
-
-irc.freenode.net
-#ath6kl
-
-Send patches to:
-
- - Greg Kroah-Hartman <greg@kroah.com>
- - Luis R. Rodriguez <mcgrof@gmail.com>
- - Joe Perches <joe@perches.com>
- - Naveen Singh <nsingh@atheros.com>
diff --git a/drivers/staging/ath6kl/bmi/include/bmi_internal.h b/drivers/staging/ath6kl/bmi/include/bmi_internal.h
deleted file mode 100644
index 8e2577074d65..000000000000
--- a/drivers/staging/ath6kl/bmi/include/bmi_internal.h
+++ /dev/null
@@ -1,54 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Communications Inc.
-// All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef BMI_INTERNAL_H
-#define BMI_INTERNAL_H
-
-#include "a_config.h"
-#include "athdefs.h"
-#include "a_osapi.h"
-#define ATH_MODULE_NAME bmi
-#include "a_debug.h"
-#include "hw/mbox_host_reg.h"
-#include "bmi_msg.h"
-
-#define ATH_DEBUG_BMI ATH_DEBUG_MAKE_MODULE_MASK(0)
-
-
-#define BMI_COMMUNICATION_TIMEOUT 100000
-
-/* ------ Global Variable Declarations ------- */
-static bool bmiDone;
-
-int
-bmiBufferSend(struct hif_device *device,
- u8 *buffer,
- u32 length);
-
-int
-bmiBufferReceive(struct hif_device *device,
- u8 *buffer,
- u32 length,
- bool want_timeout);
-
-#endif
diff --git a/drivers/staging/ath6kl/bmi/src/bmi.c b/drivers/staging/ath6kl/bmi/src/bmi.c
deleted file mode 100644
index f1f085eba9c8..000000000000
--- a/drivers/staging/ath6kl/bmi/src/bmi.c
+++ /dev/null
@@ -1,1010 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="bmi.c" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-//
-// Author(s): ="Atheros"
-//==============================================================================
-
-
-#ifdef THREAD_X
-#include <string.h>
-#endif
-
-#include "hif.h"
-#include "bmi.h"
-#include "htc_api.h"
-#include "bmi_internal.h"
-
-#ifdef ATH_DEBUG_MODULE
-static struct ath_debug_mask_description bmi_debug_desc[] = {
- { ATH_DEBUG_BMI , "BMI Tracing"},
-};
-
-ATH_DEBUG_INSTANTIATE_MODULE_VAR(bmi,
- "bmi",
- "Boot Manager Interface",
- ATH_DEBUG_MASK_DEFAULTS,
- ATH_DEBUG_DESCRIPTION_COUNT(bmi_debug_desc),
- bmi_debug_desc);
-
-#endif
-
-/*
-Although we had envisioned BMI to run on top of HTC, this is not how the
-final implementation ended up. On the Target side, BMI is a part of the BSP
-and does not use the HTC protocol nor even DMA -- it is intentionally kept
-very simple.
-*/
-
-static bool pendingEventsFuncCheck = false;
-static u32 *pBMICmdCredits;
-static u8 *pBMICmdBuf;
-#define MAX_BMI_CMDBUF_SZ (BMI_DATASZ_MAX + \
- sizeof(u32) /* cmd */ + \
- sizeof(u32) /* addr */ + \
- sizeof(u32))/* length */
-#define BMI_COMMAND_FITS(sz) ((sz) <= MAX_BMI_CMDBUF_SZ)
-
-/* APIs visible to the driver */
-void
-BMIInit(void)
-{
- bmiDone = false;
- pendingEventsFuncCheck = false;
-
- /*
- * On some platforms, it's not possible to DMA to a static variable
- * in a device driver (e.g. Linux loadable driver module).
- * So we need to A_MALLOC space for "command credits" and for commands.
- *
- * Note: implicitly relies on A_MALLOC to provide a buffer that is
- * suitable for DMA (or PIO). This buffer will be passed down the
- * bus stack.
- */
- if (!pBMICmdCredits) {
- pBMICmdCredits = (u32 *)A_MALLOC_NOWAIT(4);
- A_ASSERT(pBMICmdCredits);
- }
-
- if (!pBMICmdBuf) {
- pBMICmdBuf = (u8 *)A_MALLOC_NOWAIT(MAX_BMI_CMDBUF_SZ);
- A_ASSERT(pBMICmdBuf);
- }
-
- A_REGISTER_MODULE_DEBUG_INFO(bmi);
-}
-
-void
-BMICleanup(void)
-{
- if (pBMICmdCredits) {
- kfree(pBMICmdCredits);
- pBMICmdCredits = NULL;
- }
-
- if (pBMICmdBuf) {
- kfree(pBMICmdBuf);
- pBMICmdBuf = NULL;
- }
-}
-
-int
-BMIDone(struct hif_device *device)
-{
- int status;
- u32 cid;
-
- if (bmiDone) {
- AR_DEBUG_PRINTF (ATH_DEBUG_BMI, ("BMIDone skipped\n"));
- return 0;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Done: Enter (device: 0x%p)\n", device));
- bmiDone = true;
- cid = BMI_DONE;
-
- status = bmiBufferSend(device, (u8 *)&cid, sizeof(cid));
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
- return A_ERROR;
- }
-
- if (pBMICmdCredits) {
- kfree(pBMICmdCredits);
- pBMICmdCredits = NULL;
- }
-
- if (pBMICmdBuf) {
- kfree(pBMICmdBuf);
- pBMICmdBuf = NULL;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Done: Exit\n"));
-
- return 0;
-}
-
-int
-BMIGetTargetInfo(struct hif_device *device, struct bmi_target_info *targ_info)
-{
- int status;
- u32 cid;
-
- if (bmiDone) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
- return A_ERROR;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Get Target Info: Enter (device: 0x%p)\n", device));
- cid = BMI_GET_TARGET_INFO;
-
- status = bmiBufferSend(device, (u8 *)&cid, sizeof(cid));
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
- return A_ERROR;
- }
-
- status = bmiBufferReceive(device, (u8 *)&targ_info->target_ver,
- sizeof(targ_info->target_ver), true);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read Target Version from the device\n"));
- return A_ERROR;
- }
-
- if (targ_info->target_ver == TARGET_VERSION_SENTINAL) {
- /* Determine how many bytes are in the Target's targ_info */
- status = bmiBufferReceive(device, (u8 *)&targ_info->target_info_byte_count,
- sizeof(targ_info->target_info_byte_count), true);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read Target Info Byte Count from the device\n"));
- return A_ERROR;
- }
-
- /*
- * The Target's targ_info doesn't match the Host's targ_info.
- * We need to do some backwards compatibility work to make this OK.
- */
- A_ASSERT(targ_info->target_info_byte_count == sizeof(*targ_info));
-
- /* Read the remainder of the targ_info */
- status = bmiBufferReceive(device,
- ((u8 *)targ_info)+sizeof(targ_info->target_info_byte_count),
- sizeof(*targ_info)-sizeof(targ_info->target_info_byte_count), true);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read Target Info (%d bytes) from the device\n",
- targ_info->target_info_byte_count));
- return A_ERROR;
- }
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Get Target Info: Exit (ver: 0x%x type: 0x%x)\n",
- targ_info->target_ver, targ_info->target_type));
-
- return 0;
-}
-
-int
-BMIReadMemory(struct hif_device *device,
- u32 address,
- u8 *buffer,
- u32 length)
-{
- u32 cid;
- int status;
- u32 offset;
- u32 remaining, rxlen;
-
- A_ASSERT(BMI_COMMAND_FITS(BMI_DATASZ_MAX + sizeof(cid) + sizeof(address) + sizeof(length)));
- memset (pBMICmdBuf, 0, BMI_DATASZ_MAX + sizeof(cid) + sizeof(address) + sizeof(length));
-
- if (bmiDone) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
- return A_ERROR;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
- ("BMI Read Memory: Enter (device: 0x%p, address: 0x%x, length: %d)\n",
- device, address, length));
-
- cid = BMI_READ_MEMORY;
-
- remaining = length;
-
- while (remaining)
- {
- rxlen = (remaining < BMI_DATASZ_MAX) ? remaining : BMI_DATASZ_MAX;
- offset = 0;
- memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid));
- offset += sizeof(cid);
- memcpy(&(pBMICmdBuf[offset]), &address, sizeof(address));
- offset += sizeof(address);
- memcpy(&(pBMICmdBuf[offset]), &rxlen, sizeof(rxlen));
- offset += sizeof(length);
-
- status = bmiBufferSend(device, pBMICmdBuf, offset);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
- return A_ERROR;
- }
- status = bmiBufferReceive(device, pBMICmdBuf, rxlen, true);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n"));
- return A_ERROR;
- }
- memcpy(&buffer[length - remaining], pBMICmdBuf, rxlen);
- remaining -= rxlen; address += rxlen;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Read Memory: Exit\n"));
- return 0;
-}
-
-int
-BMIWriteMemory(struct hif_device *device,
- u32 address,
- u8 *buffer,
- u32 length)
-{
- u32 cid;
- int status;
- u32 offset;
- u32 remaining, txlen;
- const u32 header = sizeof(cid) + sizeof(address) + sizeof(length);
- u8 alignedBuffer[BMI_DATASZ_MAX];
- u8 *src;
-
- A_ASSERT(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header));
- memset (pBMICmdBuf, 0, BMI_DATASZ_MAX + header);
-
- if (bmiDone) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
- return A_ERROR;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
- ("BMI Write Memory: Enter (device: 0x%p, address: 0x%x, length: %d)\n",
- device, address, length));
-
- cid = BMI_WRITE_MEMORY;
-
- remaining = length;
- while (remaining)
- {
- src = &buffer[length - remaining];
- if (remaining < (BMI_DATASZ_MAX - header)) {
- if (remaining & 3) {
- /* align it with 4 bytes */
- remaining = remaining + (4 - (remaining & 3));
- memcpy(alignedBuffer, src, remaining);
- src = alignedBuffer;
- }
- txlen = remaining;
- } else {
- txlen = (BMI_DATASZ_MAX - header);
- }
- offset = 0;
- memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid));
- offset += sizeof(cid);
- memcpy(&(pBMICmdBuf[offset]), &address, sizeof(address));
- offset += sizeof(address);
- memcpy(&(pBMICmdBuf[offset]), &txlen, sizeof(txlen));
- offset += sizeof(txlen);
- memcpy(&(pBMICmdBuf[offset]), src, txlen);
- offset += txlen;
- status = bmiBufferSend(device, pBMICmdBuf, offset);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
- return A_ERROR;
- }
- remaining -= txlen; address += txlen;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Write Memory: Exit\n"));
-
- return 0;
-}
-
-int
-BMIExecute(struct hif_device *device,
- u32 address,
- u32 *param)
-{
- u32 cid;
- int status;
- u32 offset;
-
- A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address) + sizeof(param)));
- memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(address) + sizeof(param));
-
- if (bmiDone) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
- return A_ERROR;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
- ("BMI Execute: Enter (device: 0x%p, address: 0x%x, param: %d)\n",
- device, address, *param));
-
- cid = BMI_EXECUTE;
-
- offset = 0;
- memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid));
- offset += sizeof(cid);
- memcpy(&(pBMICmdBuf[offset]), &address, sizeof(address));
- offset += sizeof(address);
- memcpy(&(pBMICmdBuf[offset]), param, sizeof(*param));
- offset += sizeof(*param);
- status = bmiBufferSend(device, pBMICmdBuf, offset);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
- return A_ERROR;
- }
-
- status = bmiBufferReceive(device, pBMICmdBuf, sizeof(*param), false);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n"));
- return A_ERROR;
- }
-
- memcpy(param, pBMICmdBuf, sizeof(*param));
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Execute: Exit (param: %d)\n", *param));
- return 0;
-}
-
-int
-BMISetAppStart(struct hif_device *device,
- u32 address)
-{
- u32 cid;
- int status;
- u32 offset;
-
- A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address)));
- memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(address));
-
- if (bmiDone) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
- return A_ERROR;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
- ("BMI Set App Start: Enter (device: 0x%p, address: 0x%x)\n",
- device, address));
-
- cid = BMI_SET_APP_START;
-
- offset = 0;
- memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid));
- offset += sizeof(cid);
- memcpy(&(pBMICmdBuf[offset]), &address, sizeof(address));
- offset += sizeof(address);
- status = bmiBufferSend(device, pBMICmdBuf, offset);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
- return A_ERROR;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Set App Start: Exit\n"));
- return 0;
-}
-
-int
-BMIReadSOCRegister(struct hif_device *device,
- u32 address,
- u32 *param)
-{
- u32 cid;
- int status;
- u32 offset;
-
- A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address)));
- memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(address));
-
- if (bmiDone) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
- return A_ERROR;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
- ("BMI Read SOC Register: Enter (device: 0x%p, address: 0x%x)\n",
- device, address));
-
- cid = BMI_READ_SOC_REGISTER;
-
- offset = 0;
- memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid));
- offset += sizeof(cid);
- memcpy(&(pBMICmdBuf[offset]), &address, sizeof(address));
- offset += sizeof(address);
-
- status = bmiBufferSend(device, pBMICmdBuf, offset);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
- return A_ERROR;
- }
-
- status = bmiBufferReceive(device, pBMICmdBuf, sizeof(*param), true);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n"));
- return A_ERROR;
- }
- memcpy(param, pBMICmdBuf, sizeof(*param));
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Read SOC Register: Exit (value: %d)\n", *param));
- return 0;
-}
-
-int
-BMIWriteSOCRegister(struct hif_device *device,
- u32 address,
- u32 param)
-{
- u32 cid;
- int status;
- u32 offset;
-
- A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address) + sizeof(param)));
- memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(address) + sizeof(param));
-
- if (bmiDone) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
- return A_ERROR;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
- ("BMI Write SOC Register: Enter (device: 0x%p, address: 0x%x, param: %d)\n",
- device, address, param));
-
- cid = BMI_WRITE_SOC_REGISTER;
-
- offset = 0;
- memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid));
- offset += sizeof(cid);
- memcpy(&(pBMICmdBuf[offset]), &address, sizeof(address));
- offset += sizeof(address);
- memcpy(&(pBMICmdBuf[offset]), &param, sizeof(param));
- offset += sizeof(param);
- status = bmiBufferSend(device, pBMICmdBuf, offset);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
- return A_ERROR;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Read SOC Register: Exit\n"));
- return 0;
-}
-
-int
-BMIrompatchInstall(struct hif_device *device,
- u32 ROM_addr,
- u32 RAM_addr,
- u32 nbytes,
- u32 do_activate,
- u32 *rompatch_id)
-{
- u32 cid;
- int status;
- u32 offset;
-
- A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(ROM_addr) + sizeof(RAM_addr) +
- sizeof(nbytes) + sizeof(do_activate)));
- memset(pBMICmdBuf, 0, sizeof(cid) + sizeof(ROM_addr) + sizeof(RAM_addr) +
- sizeof(nbytes) + sizeof(do_activate));
-
- if (bmiDone) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
- return A_ERROR;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
- ("BMI rompatch Install: Enter (device: 0x%p, ROMaddr: 0x%x, RAMaddr: 0x%x length: %d activate: %d)\n",
- device, ROM_addr, RAM_addr, nbytes, do_activate));
-
- cid = BMI_ROMPATCH_INSTALL;
-
- offset = 0;
- memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid));
- offset += sizeof(cid);
- memcpy(&(pBMICmdBuf[offset]), &ROM_addr, sizeof(ROM_addr));
- offset += sizeof(ROM_addr);
- memcpy(&(pBMICmdBuf[offset]), &RAM_addr, sizeof(RAM_addr));
- offset += sizeof(RAM_addr);
- memcpy(&(pBMICmdBuf[offset]), &nbytes, sizeof(nbytes));
- offset += sizeof(nbytes);
- memcpy(&(pBMICmdBuf[offset]), &do_activate, sizeof(do_activate));
- offset += sizeof(do_activate);
- status = bmiBufferSend(device, pBMICmdBuf, offset);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
- return A_ERROR;
- }
-
- status = bmiBufferReceive(device, pBMICmdBuf, sizeof(*rompatch_id), true);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n"));
- return A_ERROR;
- }
- memcpy(rompatch_id, pBMICmdBuf, sizeof(*rompatch_id));
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI rompatch Install: (rompatch_id=%d)\n", *rompatch_id));
- return 0;
-}
-
-int
-BMIrompatchUninstall(struct hif_device *device,
- u32 rompatch_id)
-{
- u32 cid;
- int status;
- u32 offset;
-
- A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(rompatch_id)));
- memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(rompatch_id));
-
- if (bmiDone) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
- return A_ERROR;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
- ("BMI rompatch Uninstall: Enter (device: 0x%p, rompatch_id: %d)\n",
- device, rompatch_id));
-
- cid = BMI_ROMPATCH_UNINSTALL;
-
- offset = 0;
- memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid));
- offset += sizeof(cid);
- memcpy(&(pBMICmdBuf[offset]), &rompatch_id, sizeof(rompatch_id));
- offset += sizeof(rompatch_id);
- status = bmiBufferSend(device, pBMICmdBuf, offset);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
- return A_ERROR;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI rompatch UNinstall: (rompatch_id=0x%x)\n", rompatch_id));
- return 0;
-}
-
-static int
-_BMIrompatchChangeActivation(struct hif_device *device,
- u32 rompatch_count,
- u32 *rompatch_list,
- u32 do_activate)
-{
- u32 cid;
- int status;
- u32 offset;
- u32 length;
-
- A_ASSERT(BMI_COMMAND_FITS(BMI_DATASZ_MAX + sizeof(cid) + sizeof(rompatch_count)));
- memset(pBMICmdBuf, 0, BMI_DATASZ_MAX + sizeof(cid) + sizeof(rompatch_count));
-
- if (bmiDone) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
- return A_ERROR;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
- ("BMI Change rompatch Activation: Enter (device: 0x%p, count: %d)\n",
- device, rompatch_count));
-
- cid = do_activate ? BMI_ROMPATCH_ACTIVATE : BMI_ROMPATCH_DEACTIVATE;
-
- offset = 0;
- memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid));
- offset += sizeof(cid);
- memcpy(&(pBMICmdBuf[offset]), &rompatch_count, sizeof(rompatch_count));
- offset += sizeof(rompatch_count);
- length = rompatch_count * sizeof(*rompatch_list);
- memcpy(&(pBMICmdBuf[offset]), rompatch_list, length);
- offset += length;
- status = bmiBufferSend(device, pBMICmdBuf, offset);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
- return A_ERROR;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Change rompatch Activation: Exit\n"));
-
- return 0;
-}
-
-int
-BMIrompatchActivate(struct hif_device *device,
- u32 rompatch_count,
- u32 *rompatch_list)
-{
- return _BMIrompatchChangeActivation(device, rompatch_count, rompatch_list, 1);
-}
-
-int
-BMIrompatchDeactivate(struct hif_device *device,
- u32 rompatch_count,
- u32 *rompatch_list)
-{
- return _BMIrompatchChangeActivation(device, rompatch_count, rompatch_list, 0);
-}
-
-int
-BMILZData(struct hif_device *device,
- u8 *buffer,
- u32 length)
-{
- u32 cid;
- int status;
- u32 offset;
- u32 remaining, txlen;
- const u32 header = sizeof(cid) + sizeof(length);
-
- A_ASSERT(BMI_COMMAND_FITS(BMI_DATASZ_MAX+header));
- memset (pBMICmdBuf, 0, BMI_DATASZ_MAX+header);
-
- if (bmiDone) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
- return A_ERROR;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
- ("BMI Send LZ Data: Enter (device: 0x%p, length: %d)\n",
- device, length));
-
- cid = BMI_LZ_DATA;
-
- remaining = length;
- while (remaining)
- {
- txlen = (remaining < (BMI_DATASZ_MAX - header)) ?
- remaining : (BMI_DATASZ_MAX - header);
- offset = 0;
- memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid));
- offset += sizeof(cid);
- memcpy(&(pBMICmdBuf[offset]), &txlen, sizeof(txlen));
- offset += sizeof(txlen);
- memcpy(&(pBMICmdBuf[offset]), &buffer[length - remaining], txlen);
- offset += txlen;
- status = bmiBufferSend(device, pBMICmdBuf, offset);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
- return A_ERROR;
- }
- remaining -= txlen;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI LZ Data: Exit\n"));
-
- return 0;
-}
-
-int
-BMILZStreamStart(struct hif_device *device,
- u32 address)
-{
- u32 cid;
- int status;
- u32 offset;
-
- A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address)));
- memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(address));
-
- if (bmiDone) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
- return A_ERROR;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
- ("BMI LZ Stream Start: Enter (device: 0x%p, address: 0x%x)\n",
- device, address));
-
- cid = BMI_LZ_STREAM_START;
- offset = 0;
- memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid));
- offset += sizeof(cid);
- memcpy(&(pBMICmdBuf[offset]), &address, sizeof(address));
- offset += sizeof(address);
- status = bmiBufferSend(device, pBMICmdBuf, offset);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to Start LZ Stream to the device\n"));
- return A_ERROR;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI LZ Stream Start: Exit\n"));
-
- return 0;
-}
-
-/* BMI Access routines */
-int
-bmiBufferSend(struct hif_device *device,
- u8 *buffer,
- u32 length)
-{
- int status;
- u32 timeout;
- u32 address;
- u32 mboxAddress[HTC_MAILBOX_NUM_MAX];
-
- HIFConfigureDevice(device, HIF_DEVICE_GET_MBOX_ADDR,
- &mboxAddress[0], sizeof(mboxAddress));
-
- *pBMICmdCredits = 0;
- timeout = BMI_COMMUNICATION_TIMEOUT;
-
- while(timeout-- && !(*pBMICmdCredits)) {
- /* Read the counter register to get the command credits */
- address = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4;
- /* hit the credit counter with a 4-byte access, the first byte read will hit the counter and cause
- * a decrement, while the remaining 3 bytes has no effect. The rationale behind this is to
- * make all HIF accesses 4-byte aligned */
- status = HIFReadWrite(device, address, (u8 *)pBMICmdCredits, 4,
- HIF_RD_SYNC_BYTE_INC, NULL);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to decrement the command credit count register\n"));
- return A_ERROR;
- }
- /* the counter is only 8=bits, ignore anything in the upper 3 bytes */
- (*pBMICmdCredits) &= 0xFF;
- }
-
- if (*pBMICmdCredits) {
- address = mboxAddress[ENDPOINT1];
- status = HIFReadWrite(device, address, buffer, length,
- HIF_WR_SYNC_BYTE_INC, NULL);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to send the BMI data to the device\n"));
- return A_ERROR;
- }
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI Communication timeout - bmiBufferSend\n"));
- return A_ERROR;
- }
-
- return status;
-}
-
-int
-bmiBufferReceive(struct hif_device *device,
- u8 *buffer,
- u32 length,
- bool want_timeout)
-{
- int status;
- u32 address;
- u32 mboxAddress[HTC_MAILBOX_NUM_MAX];
- struct hif_pending_events_info hifPendingEvents;
- static HIF_PENDING_EVENTS_FUNC getPendingEventsFunc = NULL;
-
- if (!pendingEventsFuncCheck) {
- /* see if the HIF layer implements an alternative function to get pending events
- * do this only once! */
- HIFConfigureDevice(device,
- HIF_DEVICE_GET_PENDING_EVENTS_FUNC,
- &getPendingEventsFunc,
- sizeof(getPendingEventsFunc));
- pendingEventsFuncCheck = true;
- }
-
- HIFConfigureDevice(device, HIF_DEVICE_GET_MBOX_ADDR,
- &mboxAddress[0], sizeof(mboxAddress));
-
- /*
- * During normal bootup, small reads may be required.
- * Rather than issue an HIF Read and then wait as the Target
- * adds successive bytes to the FIFO, we wait here until
- * we know that response data is available.
- *
- * This allows us to cleanly timeout on an unexpected
- * Target failure rather than risk problems at the HIF level. In
- * particular, this avoids SDIO timeouts and possibly garbage
- * data on some host controllers. And on an interconnect
- * such as Compact Flash (as well as some SDIO masters) which
- * does not provide any indication on data timeout, it avoids
- * a potential hang or garbage response.
- *
- * Synchronization is more difficult for reads larger than the
- * size of the MBOX FIFO (128B), because the Target is unable
- * to push the 129th byte of data until AFTER the Host posts an
- * HIF Read and removes some FIFO data. So for large reads the
- * Host proceeds to post an HIF Read BEFORE all the data is
- * actually available to read. Fortunately, large BMI reads do
- * not occur in practice -- they're supported for debug/development.
- *
- * So Host/Target BMI synchronization is divided into these cases:
- * CASE 1: length < 4
- * Should not happen
- *
- * CASE 2: 4 <= length <= 128
- * Wait for first 4 bytes to be in FIFO
- * If CONSERVATIVE_BMI_READ is enabled, also wait for
- * a BMI command credit, which indicates that the ENTIRE
- * response is available in the the FIFO
- *
- * CASE 3: length > 128
- * Wait for the first 4 bytes to be in FIFO
- *
- * For most uses, a small timeout should be sufficient and we will
- * usually see a response quickly; but there may be some unusual
- * (debug) cases of BMI_EXECUTE where we want an larger timeout.
- * For now, we use an unbounded busy loop while waiting for
- * BMI_EXECUTE.
- *
- * If BMI_EXECUTE ever needs to support longer-latency execution,
- * especially in production, this code needs to be enhanced to sleep
- * and yield. Also note that BMI_COMMUNICATION_TIMEOUT is currently
- * a function of Host processor speed.
- */
- if (length >= 4) { /* NB: Currently, always true */
- /*
- * NB: word_available is declared static for esoteric reasons
- * having to do with protection on some OSes.
- */
- static u32 word_available;
- u32 timeout;
-
- word_available = 0;
- timeout = BMI_COMMUNICATION_TIMEOUT;
- while((!want_timeout || timeout--) && !word_available) {
-
- if (getPendingEventsFunc != NULL) {
- status = getPendingEventsFunc(device,
- &hifPendingEvents,
- NULL);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BMI: Failed to get pending events \n"));
- break;
- }
-
- if (hifPendingEvents.AvailableRecvBytes >= sizeof(u32)) {
- word_available = 1;
- }
- continue;
- }
-
- status = HIFReadWrite(device, RX_LOOKAHEAD_VALID_ADDRESS, (u8 *)&word_available,
- sizeof(word_available), HIF_RD_SYNC_BYTE_INC, NULL);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read RX_LOOKAHEAD_VALID register\n"));
- return A_ERROR;
- }
- /* We did a 4-byte read to the same register; all we really want is one bit */
- word_available &= (1 << ENDPOINT1);
- }
-
- if (!word_available) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI Communication timeout - bmiBufferReceive FIFO empty\n"));
- return A_ERROR;
- }
- }
-
-#define CONSERVATIVE_BMI_READ 0
-#if CONSERVATIVE_BMI_READ
- /*
- * This is an extra-conservative CREDIT check. It guarantees
- * that ALL data is available in the FIFO before we start to
- * read from the interconnect.
- *
- * This credit check is useless when firmware chooses to
- * allow multiple outstanding BMI Command Credits, since the next
- * credit will already be present. To restrict the Target to one
- * BMI Command Credit, see HI_OPTION_BMI_CRED_LIMIT.
- *
- * And for large reads (when HI_OPTION_BMI_CRED_LIMIT is set)
- * we cannot wait for the next credit because the Target's FIFO
- * will not hold the entire response. So we need the Host to
- * start to empty the FIFO sooner. (And again, large reads are
- * not used in practice; they are for debug/development only.)
- *
- * For a more conservative Host implementation (which would be
- * safer for a Compact Flash interconnect):
- * Set CONSERVATIVE_BMI_READ (above) to 1
- * Set HI_OPTION_BMI_CRED_LIMIT and
- * reduce BMI_DATASZ_MAX to 32 or 64
- */
- if ((length > 4) && (length < 128)) { /* check against MBOX FIFO size */
- u32 timeout;
-
- *pBMICmdCredits = 0;
- timeout = BMI_COMMUNICATION_TIMEOUT;
- while((!want_timeout || timeout--) && !(*pBMICmdCredits) {
- /* Read the counter register to get the command credits */
- address = COUNT_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 1;
- /* read the counter using a 4-byte read. Since the counter is NOT auto-decrementing,
- * we can read this counter multiple times using a non-incrementing address mode.
- * The rationale here is to make all HIF accesses a multiple of 4 bytes */
- status = HIFReadWrite(device, address, (u8 *)pBMICmdCredits, sizeof(*pBMICmdCredits),
- HIF_RD_SYNC_BYTE_FIX, NULL);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read the command credit count register\n"));
- return A_ERROR;
- }
- /* we did a 4-byte read to the same count register so mask off upper bytes */
- (*pBMICmdCredits) &= 0xFF;
- }
-
- if (!(*pBMICmdCredits)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI Communication timeout- bmiBufferReceive no credit\n"));
- return A_ERROR;
- }
- }
-#endif
-
- address = mboxAddress[ENDPOINT1];
- status = HIFReadWrite(device, address, buffer, length, HIF_RD_SYNC_BYTE_INC, NULL);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read the BMI data from the device\n"));
- return A_ERROR;
- }
-
- return 0;
-}
-
-int
-BMIFastDownload(struct hif_device *device, u32 address, u8 *buffer, u32 length)
-{
- int status = A_ERROR;
- u32 lastWord = 0;
- u32 lastWordOffset = length & ~0x3;
- u32 unalignedBytes = length & 0x3;
-
- status = BMILZStreamStart (device, address);
- if (status) {
- return A_ERROR;
- }
-
- if (unalignedBytes) {
- /* copy the last word into a zero padded buffer */
- memcpy(&lastWord, &buffer[lastWordOffset], unalignedBytes);
- }
-
- status = BMILZData(device, buffer, lastWordOffset);
-
- if (status) {
- return A_ERROR;
- }
-
- if (unalignedBytes) {
- status = BMILZData(device, (u8 *)&lastWord, 4);
- }
-
- if (!status) {
- //
- // Close compressed stream and open a new (fake) one. This serves mainly to flush Target caches.
- //
- status = BMILZStreamStart (device, 0x00);
- if (status) {
- return A_ERROR;
- }
- }
- return status;
-}
-
-int
-BMIRawWrite(struct hif_device *device, u8 *buffer, u32 length)
-{
- return bmiBufferSend(device, buffer, length);
-}
-
-int
-BMIRawRead(struct hif_device *device, u8 *buffer, u32 length, bool want_timeout)
-{
- return bmiBufferReceive(device, buffer, length, want_timeout);
-}
diff --git a/drivers/staging/ath6kl/hif/common/hif_sdio_common.h b/drivers/staging/ath6kl/hif/common/hif_sdio_common.h
deleted file mode 100644
index 93a2adceca33..000000000000
--- a/drivers/staging/ath6kl/hif/common/hif_sdio_common.h
+++ /dev/null
@@ -1,87 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2009-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// common header file for HIF modules designed for SDIO
-//
-// Author(s): ="Atheros"
-//==============================================================================
-
-#ifndef HIF_SDIO_COMMON_H_
-#define HIF_SDIO_COMMON_H_
-
- /* SDIO manufacturer ID and Codes */
-#define MANUFACTURER_ID_AR6002_BASE 0x200
-#define MANUFACTURER_ID_AR6003_BASE 0x300
-#define MANUFACTURER_ID_AR6K_BASE_MASK 0xFF00
-#define FUNCTION_CLASS 0x0
-#define MANUFACTURER_CODE 0x271 /* Atheros */
-
- /* Mailbox address in SDIO address space */
-#define HIF_MBOX_BASE_ADDR 0x800
-#define HIF_MBOX_WIDTH 0x800
-#define HIF_MBOX_START_ADDR(mbox) \
- ( HIF_MBOX_BASE_ADDR + mbox * HIF_MBOX_WIDTH)
-
-#define HIF_MBOX_END_ADDR(mbox) \
- (HIF_MBOX_START_ADDR(mbox) + HIF_MBOX_WIDTH - 1)
-
- /* extended MBOX address for larger MBOX writes to MBOX 0*/
-#define HIF_MBOX0_EXTENDED_BASE_ADDR 0x2800
-#define HIF_MBOX0_EXTENDED_WIDTH_AR6002 (6*1024)
-#define HIF_MBOX0_EXTENDED_WIDTH_AR6003 (18*1024)
-
- /* version 1 of the chip has only a 12K extended mbox range */
-#define HIF_MBOX0_EXTENDED_BASE_ADDR_AR6003_V1 0x4000
-#define HIF_MBOX0_EXTENDED_WIDTH_AR6003_V1 (12*1024)
-
- /* GMBOX addresses */
-#define HIF_GMBOX_BASE_ADDR 0x7000
-#define HIF_GMBOX_WIDTH 0x4000
-
- /* for SDIO we recommend a 128-byte block size */
-#define HIF_DEFAULT_IO_BLOCK_SIZE 128
-
- /* set extended MBOX window information for SDIO interconnects */
-static INLINE void SetExtendedMboxWindowInfo(u16 Manfid, struct hif_device_mbox_info *pInfo)
-{
- switch (Manfid & MANUFACTURER_ID_AR6K_BASE_MASK) {
- case MANUFACTURER_ID_AR6002_BASE :
- /* MBOX 0 has an extended range */
- pInfo->MboxProp[0].ExtendedAddress = HIF_MBOX0_EXTENDED_BASE_ADDR;
- pInfo->MboxProp[0].ExtendedSize = HIF_MBOX0_EXTENDED_WIDTH_AR6002;
- break;
- case MANUFACTURER_ID_AR6003_BASE :
- /* MBOX 0 has an extended range */
- pInfo->MboxProp[0].ExtendedAddress = HIF_MBOX0_EXTENDED_BASE_ADDR_AR6003_V1;
- pInfo->MboxProp[0].ExtendedSize = HIF_MBOX0_EXTENDED_WIDTH_AR6003_V1;
- pInfo->GMboxAddress = HIF_GMBOX_BASE_ADDR;
- pInfo->GMboxSize = HIF_GMBOX_WIDTH;
- break;
- default:
- A_ASSERT(false);
- break;
- }
-}
-
-/* special CCCR (func 0) registers */
-
-#define CCCR_SDIO_IRQ_MODE_REG 0xF0 /* interrupt mode register */
-#define SDIO_IRQ_MODE_ASYNC_4BIT_IRQ (1 << 0) /* mode to enable special 4-bit interrupt assertion without clock*/
-
-#endif /*HIF_SDIO_COMMON_H_*/
diff --git a/drivers/staging/ath6kl/hif/sdio/linux_sdio/include/hif_internal.h b/drivers/staging/ath6kl/hif/sdio/linux_sdio/include/hif_internal.h
deleted file mode 100644
index ed7ad4786f5a..000000000000
--- a/drivers/staging/ath6kl/hif/sdio/linux_sdio/include/hif_internal.h
+++ /dev/null
@@ -1,131 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="hif_internal.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// internal header file for hif layer
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _HIF_INTERNAL_H_
-#define _HIF_INTERNAL_H_
-
-#include "a_config.h"
-#include "athdefs.h"
-#include "a_osapi.h"
-#include "hif.h"
-#include "../../../common/hif_sdio_common.h"
-#include <linux/scatterlist.h>
-#define HIF_LINUX_MMC_SCATTER_SUPPORT
-
-#define BUS_REQUEST_MAX_NUM 64
-
-#define SDIO_CLOCK_FREQUENCY_DEFAULT 25000000
-#define SDWLAN_ENABLE_DISABLE_TIMEOUT 20
-#define FLAGS_CARD_ENAB 0x02
-#define FLAGS_CARD_IRQ_UNMSK 0x04
-
-#define HIF_MBOX_BLOCK_SIZE HIF_DEFAULT_IO_BLOCK_SIZE
-#define HIF_MBOX0_BLOCK_SIZE 1
-#define HIF_MBOX1_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE
-#define HIF_MBOX2_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE
-#define HIF_MBOX3_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE
-
-typedef struct bus_request {
- struct bus_request *next; /* link list of available requests */
- struct bus_request *inusenext; /* link list of in use requests */
- struct semaphore sem_req;
- u32 address; /* request data */
- u8 *buffer;
- u32 length;
- u32 request;
- void *context;
- int status;
- struct hif_scatter_req_priv *pScatterReq; /* this request is a scatter request */
-} BUS_REQUEST;
-
-struct hif_device {
- struct sdio_func *func;
- spinlock_t asynclock;
- struct task_struct* async_task; /* task to handle async commands */
- struct semaphore sem_async; /* wake up for async task */
- int async_shutdown; /* stop the async task */
- struct completion async_completion; /* thread completion */
- BUS_REQUEST *asyncreq; /* request for async tasklet */
- BUS_REQUEST *taskreq; /* async tasklet data */
- spinlock_t lock;
- BUS_REQUEST *s_busRequestFreeQueue; /* free list */
- BUS_REQUEST busRequest[BUS_REQUEST_MAX_NUM]; /* available bus requests */
- void *claimedContext;
- HTC_CALLBACKS htcCallbacks;
- u8 *dma_buffer;
- struct dl_list ScatterReqHead; /* scatter request list head */
- bool scatter_enabled; /* scatter enabled flag */
- bool is_suspend;
- bool is_disabled;
- atomic_t irqHandling;
- HIF_DEVICE_POWER_CHANGE_TYPE powerConfig;
- const struct sdio_device_id *id;
-};
-
-#define HIF_DMA_BUFFER_SIZE (32 * 1024)
-#define CMD53_FIXED_ADDRESS 1
-#define CMD53_INCR_ADDRESS 2
-
-BUS_REQUEST *hifAllocateBusRequest(struct hif_device *device);
-void hifFreeBusRequest(struct hif_device *device, BUS_REQUEST *busrequest);
-void AddToAsyncList(struct hif_device *device, BUS_REQUEST *busrequest);
-
-#ifdef HIF_LINUX_MMC_SCATTER_SUPPORT
-
-#define MAX_SCATTER_REQUESTS 4
-#define MAX_SCATTER_ENTRIES_PER_REQ 16
-#define MAX_SCATTER_REQ_TRANSFER_SIZE 32*1024
-
-struct hif_scatter_req_priv {
- struct hif_scatter_req *pHifScatterReq; /* HIF scatter request with allocated entries */
- struct hif_device *device; /* this device */
- BUS_REQUEST *busrequest; /* request associated with request */
- /* scatter list for linux */
- struct scatterlist sgentries[MAX_SCATTER_ENTRIES_PER_REQ];
-};
-
-#define ATH_DEBUG_SCATTER ATH_DEBUG_MAKE_MODULE_MASK(0)
-
-int SetupHIFScatterSupport(struct hif_device *device, struct hif_device_scatter_support_info *pInfo);
-void CleanupHIFScatterResources(struct hif_device *device);
-int DoHifReadWriteScatter(struct hif_device *device, BUS_REQUEST *busrequest);
-
-#else // HIF_LINUX_MMC_SCATTER_SUPPORT
-
-static inline int SetupHIFScatterSupport(struct hif_device *device, struct hif_device_scatter_support_info *pInfo)
-{
- return A_ENOTSUP;
-}
-
-static inline int DoHifReadWriteScatter(struct hif_device *device, BUS_REQUEST *busrequest)
-{
- return A_ENOTSUP;
-}
-
-#define CleanupHIFScatterResources(d) { }
-
-#endif // HIF_LINUX_MMC_SCATTER_SUPPORT
-
-#endif // _HIF_INTERNAL_H_
-
diff --git a/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c b/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c
deleted file mode 100644
index 5f5d67720fa4..000000000000
--- a/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c
+++ /dev/null
@@ -1,1273 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="hif.c" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// HIF layer reference implementation for Linux Native MMC stack
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#include <linux/mmc/card.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/sdio_ids.h>
-#include <linux/mmc/sdio.h>
-#include <linux/mmc/sd.h>
-#include <linux/kthread.h>
-
-/* by default setup a bounce buffer for the data packets, if the underlying host controller driver
- does not use DMA you may be able to skip this step and save the memory allocation and transfer time */
-#define HIF_USE_DMA_BOUNCE_BUFFER 1
-#include "hif_internal.h"
-#define ATH_MODULE_NAME hif
-#include "a_debug.h"
-#include "hw/mbox_host_reg.h"
-
-#if HIF_USE_DMA_BOUNCE_BUFFER
-/* macro to check if DMA buffer is WORD-aligned and DMA-able. Most host controllers assume the
- * buffer is DMA'able and will bug-check otherwise (i.e. buffers on the stack).
- * virt_addr_valid check fails on stack memory.
- */
-#define BUFFER_NEEDS_BOUNCE(buffer) (((unsigned long)(buffer) & 0x3) || !virt_addr_valid((buffer)))
-#else
-#define BUFFER_NEEDS_BOUNCE(buffer) (false)
-#endif
-
-/* ATHENV */
-#if defined(CONFIG_PM)
-#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev)
-#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv)
-#endif /* CONFIG_PM */
-static void delHifDevice(struct hif_device * device);
-static int Func0_CMD52WriteByte(struct mmc_card *card, unsigned int address, unsigned char byte);
-static int Func0_CMD52ReadByte(struct mmc_card *card, unsigned int address, unsigned char *byte);
-
-static int hifEnableFunc(struct hif_device *device, struct sdio_func *func);
-static int hifDisableFunc(struct hif_device *device, struct sdio_func *func);
-OSDRV_CALLBACKS osdrvCallbacks;
-
-int reset_sdio_on_unload = 0;
-module_param(reset_sdio_on_unload, int, 0644);
-
-extern u32 nohifscattersupport;
-
-static struct hif_device *ath6kl_alloc_hifdev(struct sdio_func *func)
-{
- struct hif_device *hifdevice;
-
- hifdevice = kzalloc(sizeof(struct hif_device), GFP_KERNEL);
-
-#if HIF_USE_DMA_BOUNCE_BUFFER
- hifdevice->dma_buffer = kmalloc(HIF_DMA_BUFFER_SIZE, GFP_KERNEL);
-#endif
- hifdevice->func = func;
- hifdevice->powerConfig = HIF_DEVICE_POWER_UP;
- sdio_set_drvdata(func, hifdevice);
-
- return hifdevice;
-}
-
-static struct hif_device *ath6kl_get_hifdev(struct sdio_func *func)
-{
- return (struct hif_device *) sdio_get_drvdata(func);
-}
-
-static const struct sdio_device_id ath6kl_hifdev_ids[] = {
- { SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6002_BASE | 0x0)) },
- { SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6002_BASE | 0x1)) },
- { SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x0)) },
- { SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x1)) },
- { /* null */ },
-};
-
-MODULE_DEVICE_TABLE(sdio, ath6kl_hifdev_ids);
-
-static int ath6kl_hifdev_probe(struct sdio_func *func,
- const struct sdio_device_id *id)
-{
- int ret;
- struct hif_device *device;
- int count;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
- ("ath6kl: Function: 0x%X, Vendor ID: 0x%X, "
- "Device ID: 0x%X, block size: 0x%X/0x%X\n",
- func->num, func->vendor, func->device,
- func->max_blksize, func->cur_blksize));
-
- ath6kl_alloc_hifdev(func);
- device = ath6kl_get_hifdev(func);
-
- device->id = id;
- device->is_disabled = true;
-
- spin_lock_init(&device->lock);
- spin_lock_init(&device->asynclock);
-
- DL_LIST_INIT(&device->ScatterReqHead);
-
- /* Try to allow scatter unless globally overridden */
- if (!nohifscattersupport)
- device->scatter_enabled = true;
-
- A_MEMZERO(device->busRequest, sizeof(device->busRequest));
-
- for (count = 0; count < BUS_REQUEST_MAX_NUM; count++) {
- sema_init(&device->busRequest[count].sem_req, 0);
- hifFreeBusRequest(device, &device->busRequest[count]);
- }
-
- sema_init(&device->sem_async, 0);
-
- ret = hifEnableFunc(device, func);
-
- return ret;
-}
-
-static void ath6kl_hifdev_remove(struct sdio_func *func)
-{
- int status = 0;
- struct hif_device *device;
-
- device = ath6kl_get_hifdev(func);
- if (device->claimedContext != NULL)
- status = osdrvCallbacks.
- deviceRemovedHandler(device->claimedContext, device);
-
- if (device->is_disabled)
- device->is_disabled = false;
- else
- status = hifDisableFunc(device, func);
-
- CleanupHIFScatterResources(device);
-
- delHifDevice(device);
-}
-
-#if defined(CONFIG_PM)
-static int ath6kl_hifdev_suspend(struct device *dev)
-{
- struct sdio_func *func = dev_to_sdio_func(dev);
- int status = 0;
- struct hif_device *device;
-
- device = ath6kl_get_hifdev(func);
-
- if (device && device->claimedContext &&
- osdrvCallbacks.deviceSuspendHandler) {
- /* set true first for PowerStateChangeNotify(..) */
- device->is_suspend = true;
- status = osdrvCallbacks.
- deviceSuspendHandler(device->claimedContext);
- if (status)
- device->is_suspend = false;
- }
-
- CleanupHIFScatterResources(device);
-
- switch (status) {
- case 0:
- return 0;
- case A_EBUSY:
- /* Hack for kernel in order to support deep sleep and wow */
- return -EBUSY;
- default:
- return -1;
- }
-}
-
-static int ath6kl_hifdev_resume(struct device *dev)
-{
- struct sdio_func *func = dev_to_sdio_func(dev);
- int status = 0;
- struct hif_device *device;
-
- device = ath6kl_get_hifdev(func);
- if (device && device->claimedContext &&
- osdrvCallbacks.deviceSuspendHandler) {
- status = osdrvCallbacks.
- deviceResumeHandler(device->claimedContext);
- if (status == 0)
- device->is_suspend = false;
- }
-
- return status;
-}
-
-static const struct dev_pm_ops ath6kl_hifdev_pmops = {
- .suspend = ath6kl_hifdev_suspend,
- .resume = ath6kl_hifdev_resume,
-};
-#endif /* CONFIG_PM */
-
-static struct sdio_driver ath6kl_hifdev_driver = {
- .name = "ath6kl_hifdev",
- .id_table = ath6kl_hifdev_ids,
- .probe = ath6kl_hifdev_probe,
- .remove = ath6kl_hifdev_remove,
-#if defined(CONFIG_PM)
- .drv = {
- .pm = &ath6kl_hifdev_pmops,
- },
-#endif
-};
-
-/* make sure we only unregister when registered. */
-static int registered = 0;
-
-extern u32 onebitmode;
-extern u32 busspeedlow;
-extern u32 debughif;
-
-static void ResetAllCards(void);
-
-#ifdef DEBUG
-
-ATH_DEBUG_INSTANTIATE_MODULE_VAR(hif,
- "hif",
- "(Linux MMC) Host Interconnect Framework",
- ATH_DEBUG_MASK_DEFAULTS,
- 0,
- NULL);
-
-#endif
-
-
-/* ------ Functions ------ */
-int HIFInit(OSDRV_CALLBACKS *callbacks)
-{
- int r;
- AR_DEBUG_ASSERT(callbacks != NULL);
-
- A_REGISTER_MODULE_DEBUG_INFO(hif);
-
- /* store the callback handlers */
- osdrvCallbacks = *callbacks;
-
- /* Register with bus driver core */
- registered = 1;
-
- r = sdio_register_driver(&ath6kl_hifdev_driver);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static int
-__HIFReadWrite(struct hif_device *device,
- u32 address,
- u8 *buffer,
- u32 length,
- u32 request,
- void *context)
-{
- u8 opcode;
- int status = 0;
- int ret;
- u8 *tbuffer;
- bool bounced = false;
-
- AR_DEBUG_ASSERT(device != NULL);
- AR_DEBUG_ASSERT(device->func != NULL);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Device: 0x%p, buffer:0x%p (addr:0x%X)\n",
- device, buffer, address));
-
- do {
- if (request & HIF_EXTENDED_IO) {
- //AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Command type: CMD53\n"));
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
- ("AR6000: Invalid command type: 0x%08x\n", request));
- status = A_EINVAL;
- break;
- }
-
- if (request & HIF_BLOCK_BASIS) {
- /* round to whole block length size */
- length = (length / HIF_MBOX_BLOCK_SIZE) * HIF_MBOX_BLOCK_SIZE;
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
- ("AR6000: Block mode (BlockLen: %d)\n",
- length));
- } else if (request & HIF_BYTE_BASIS) {
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
- ("AR6000: Byte mode (BlockLen: %d)\n",
- length));
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
- ("AR6000: Invalid data mode: 0x%08x\n", request));
- status = A_EINVAL;
- break;
- }
-
-#if 0
- /* useful for checking register accesses */
- if (length & 0x3) {
- A_PRINTF(KERN_ALERT"AR6000: HIF (%s) is not a multiple of 4 bytes, addr:0x%X, len:%d\n",
- request & HIF_WRITE ? "write":"read", address, length);
- }
-#endif
-
- if (request & HIF_WRITE) {
- if ((address >= HIF_MBOX_START_ADDR(0)) &&
- (address <= HIF_MBOX_END_ADDR(3)))
- {
-
- AR_DEBUG_ASSERT(length <= HIF_MBOX_WIDTH);
-
- /*
- * Mailbox write. Adjust the address so that the last byte
- * falls on the EOM address.
- */
- address += (HIF_MBOX_WIDTH - length);
- }
- }
-
- if (request & HIF_FIXED_ADDRESS) {
- opcode = CMD53_FIXED_ADDRESS;
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Address mode: Fixed 0x%X\n", address));
- } else if (request & HIF_INCREMENTAL_ADDRESS) {
- opcode = CMD53_INCR_ADDRESS;
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Address mode: Incremental 0x%X\n", address));
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
- ("AR6000: Invalid address mode: 0x%08x\n", request));
- status = A_EINVAL;
- break;
- }
-
- if (request & HIF_WRITE) {
-#if HIF_USE_DMA_BOUNCE_BUFFER
- if (BUFFER_NEEDS_BOUNCE(buffer)) {
- AR_DEBUG_ASSERT(device->dma_buffer != NULL);
- tbuffer = device->dma_buffer;
- /* copy the write data to the dma buffer */
- AR_DEBUG_ASSERT(length <= HIF_DMA_BUFFER_SIZE);
- memcpy(tbuffer, buffer, length);
- bounced = true;
- } else {
- tbuffer = buffer;
- }
-#else
- tbuffer = buffer;
-#endif
- if (opcode == CMD53_FIXED_ADDRESS) {
- ret = sdio_writesb(device->func, address, tbuffer, length);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: writesb ret=%d address: 0x%X, len: %d, 0x%X\n",
- ret, address, length, *(int *)tbuffer));
- } else {
- ret = sdio_memcpy_toio(device->func, address, tbuffer, length);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: writeio ret=%d address: 0x%X, len: %d, 0x%X\n",
- ret, address, length, *(int *)tbuffer));
- }
- } else if (request & HIF_READ) {
-#if HIF_USE_DMA_BOUNCE_BUFFER
- if (BUFFER_NEEDS_BOUNCE(buffer)) {
- AR_DEBUG_ASSERT(device->dma_buffer != NULL);
- AR_DEBUG_ASSERT(length <= HIF_DMA_BUFFER_SIZE);
- tbuffer = device->dma_buffer;
- bounced = true;
- } else {
- tbuffer = buffer;
- }
-#else
- tbuffer = buffer;
-#endif
- if (opcode == CMD53_FIXED_ADDRESS) {
- ret = sdio_readsb(device->func, tbuffer, address, length);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: readsb ret=%d address: 0x%X, len: %d, 0x%X\n",
- ret, address, length, *(int *)tbuffer));
- } else {
- ret = sdio_memcpy_fromio(device->func, tbuffer, address, length);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: readio ret=%d address: 0x%X, len: %d, 0x%X\n",
- ret, address, length, *(int *)tbuffer));
- }
-#if HIF_USE_DMA_BOUNCE_BUFFER
- if (bounced) {
- /* copy the read data from the dma buffer */
- memcpy(buffer, tbuffer, length);
- }
-#endif
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
- ("AR6000: Invalid direction: 0x%08x\n", request));
- status = A_EINVAL;
- break;
- }
-
- if (ret) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
- ("AR6000: SDIO bus operation failed! MMC stack returned : %d \n", ret));
- status = A_ERROR;
- }
- } while (false);
-
- return status;
-}
-
-void AddToAsyncList(struct hif_device *device, BUS_REQUEST *busrequest)
-{
- unsigned long flags;
- BUS_REQUEST *async;
- BUS_REQUEST *active;
-
- spin_lock_irqsave(&device->asynclock, flags);
- active = device->asyncreq;
- if (active == NULL) {
- device->asyncreq = busrequest;
- device->asyncreq->inusenext = NULL;
- } else {
- for (async = device->asyncreq;
- async != NULL;
- async = async->inusenext) {
- active = async;
- }
- active->inusenext = busrequest;
- busrequest->inusenext = NULL;
- }
- spin_unlock_irqrestore(&device->asynclock, flags);
-}
-
-
-/* queue a read/write request */
-int
-HIFReadWrite(struct hif_device *device,
- u32 address,
- u8 *buffer,
- u32 length,
- u32 request,
- void *context)
-{
- int status = 0;
- BUS_REQUEST *busrequest;
-
-
- AR_DEBUG_ASSERT(device != NULL);
- AR_DEBUG_ASSERT(device->func != NULL);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Device: %p addr:0x%X\n", device,address));
-
- do {
- if ((request & HIF_ASYNCHRONOUS) || (request & HIF_SYNCHRONOUS)){
- /* serialize all requests through the async thread */
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Execution mode: %s\n",
- (request & HIF_ASYNCHRONOUS)?"Async":"Synch"));
- busrequest = hifAllocateBusRequest(device);
- if (busrequest == NULL) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
- ("AR6000: no async bus requests available (%s, addr:0x%X, len:%d) \n",
- request & HIF_READ ? "READ":"WRITE", address, length));
- return A_ERROR;
- }
- busrequest->address = address;
- busrequest->buffer = buffer;
- busrequest->length = length;
- busrequest->request = request;
- busrequest->context = context;
-
- AddToAsyncList(device, busrequest);
-
- if (request & HIF_SYNCHRONOUS) {
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: queued sync req: 0x%lX\n", (unsigned long)busrequest));
-
- /* wait for completion */
- up(&device->sem_async);
- if (down_interruptible(&busrequest->sem_req) != 0) {
- /* interrupted, exit */
- return A_ERROR;
- } else {
- int status = busrequest->status;
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: sync return freeing 0x%lX: 0x%X\n",
- (unsigned long)busrequest, busrequest->status));
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: freeing req: 0x%X\n", (unsigned int)request));
- hifFreeBusRequest(device, busrequest);
- return status;
- }
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: queued async req: 0x%lX\n", (unsigned long)busrequest));
- up(&device->sem_async);
- return A_PENDING;
- }
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
- ("AR6000: Invalid execution mode: 0x%08x\n", (unsigned int)request));
- status = A_EINVAL;
- break;
- }
- } while(0);
-
- return status;
-}
-/* thread to serialize all requests, both sync and async */
-static int async_task(void *param)
- {
- struct hif_device *device;
- BUS_REQUEST *request;
- int status;
- unsigned long flags;
-
- device = (struct hif_device *)param;
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async task\n"));
- set_current_state(TASK_INTERRUPTIBLE);
- while(!device->async_shutdown) {
- /* wait for work */
- if (down_interruptible(&device->sem_async) != 0) {
- /* interrupted, exit */
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async task interrupted\n"));
- break;
- }
- if (device->async_shutdown) {
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async task stopping\n"));
- break;
- }
- /* we want to hold the host over multiple cmds if possible, but holding the host blocks card interrupts */
- sdio_claim_host(device->func);
- spin_lock_irqsave(&device->asynclock, flags);
- /* pull the request to work on */
- while (device->asyncreq != NULL) {
- request = device->asyncreq;
- if (request->inusenext != NULL) {
- device->asyncreq = request->inusenext;
- } else {
- device->asyncreq = NULL;
- }
- spin_unlock_irqrestore(&device->asynclock, flags);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async_task processing req: 0x%lX\n", (unsigned long)request));
-
- if (request->pScatterReq != NULL) {
- A_ASSERT(device->scatter_enabled);
- /* this is a queued scatter request, pass the request to scatter routine which
- * executes it synchronously, note, no need to free the request since scatter requests
- * are maintained on a separate list */
- status = DoHifReadWriteScatter(device,request);
- } else {
- /* call HIFReadWrite in sync mode to do the work */
- status = __HIFReadWrite(device, request->address, request->buffer,
- request->length, request->request & ~HIF_SYNCHRONOUS, NULL);
- if (request->request & HIF_ASYNCHRONOUS) {
- void *context = request->context;
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async_task freeing req: 0x%lX\n", (unsigned long)request));
- hifFreeBusRequest(device, request);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async_task completion routine req: 0x%lX\n", (unsigned long)request));
- device->htcCallbacks.rwCompletionHandler(context, status);
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async_task upping req: 0x%lX\n", (unsigned long)request));
- request->status = status;
- up(&request->sem_req);
- }
- }
- spin_lock_irqsave(&device->asynclock, flags);
- }
- spin_unlock_irqrestore(&device->asynclock, flags);
- sdio_release_host(device->func);
- }
-
- complete_and_exit(&device->async_completion, 0);
- return 0;
-}
-
-static s32 IssueSDCommand(struct hif_device *device, u32 opcode, u32 arg, u32 flags, u32 *resp)
-{
- struct mmc_command cmd;
- s32 err;
- struct mmc_host *host;
- struct sdio_func *func;
-
- func = device->func;
- host = func->card->host;
-
- memset(&cmd, 0, sizeof(struct mmc_command));
- cmd.opcode = opcode;
- cmd.arg = arg;
- cmd.flags = flags;
- err = mmc_wait_for_cmd(host, &cmd, 3);
-
- if ((!err) && (resp)) {
- *resp = cmd.resp[0];
- }
-
- return err;
-}
-
-int ReinitSDIO(struct hif_device *device)
-{
- s32 err;
- struct mmc_host *host;
- struct mmc_card *card;
- struct sdio_func *func;
- u8 cmd52_resp;
- u32 clock;
-
- func = device->func;
- card = func->card;
- host = card->host;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +ReinitSDIO \n"));
- sdio_claim_host(func);
-
- do {
- if (!device->is_suspend) {
- u32 resp;
- u16 rca;
- u32 i;
- int bit = fls(host->ocr_avail) - 1;
- /* emulate the mmc_power_up(...) */
- host->ios.vdd = bit;
- host->ios.chip_select = MMC_CS_DONTCARE;
- host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
- host->ios.power_mode = MMC_POWER_UP;
- host->ios.bus_width = MMC_BUS_WIDTH_1;
- host->ios.timing = MMC_TIMING_LEGACY;
- host->ops->set_ios(host, &host->ios);
- /*
- * This delay should be sufficient to allow the power supply
- * to reach the minimum voltage.
- */
- msleep(2);
-
- host->ios.clock = host->f_min;
- host->ios.power_mode = MMC_POWER_ON;
- host->ops->set_ios(host, &host->ios);
-
- /*
- * This delay must be at least 74 clock sizes, or 1 ms, or the
- * time required to reach a stable voltage.
- */
- msleep(2);
-
- /* Issue CMD0. Goto idle state */
- host->ios.chip_select = MMC_CS_HIGH;
- host->ops->set_ios(host, &host->ios);
- msleep(1);
- err = IssueSDCommand(device, MMC_GO_IDLE_STATE, 0, (MMC_RSP_NONE | MMC_CMD_BC), NULL);
- host->ios.chip_select = MMC_CS_DONTCARE;
- host->ops->set_ios(host, &host->ios);
- msleep(1);
- host->use_spi_crc = 0;
-
- if (err) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD0 failed : %d \n",err));
- break;
- }
-
- if (!host->ocr) {
- /* Issue CMD5, arg = 0 */
- err = IssueSDCommand(device, SD_IO_SEND_OP_COND, 0, (MMC_RSP_R4 | MMC_CMD_BCR), &resp);
- if (err) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD5 failed : %d \n",err));
- break;
- }
- host->ocr = resp;
- }
-
- /* Issue CMD5, arg = ocr. Wait till card is ready */
- for (i=0;i<100;i++) {
- err = IssueSDCommand(device, SD_IO_SEND_OP_COND, host->ocr, (MMC_RSP_R4 | MMC_CMD_BCR), &resp);
- if (err) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD5 failed : %d \n",err));
- break;
- }
- if (resp & MMC_CARD_BUSY) {
- break;
- }
- msleep(10);
- }
-
- if ((i == 100) || (err)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: card in not ready : %d %d \n",i,err));
- break;
- }
-
- /* Issue CMD3, get RCA */
- err = IssueSDCommand(device, SD_SEND_RELATIVE_ADDR, 0, MMC_RSP_R6 | MMC_CMD_BCR, &resp);
- if (err) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD3 failed : %d \n",err));
- break;
- }
- rca = resp >> 16;
- host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
- host->ops->set_ios(host, &host->ios);
-
- /* Issue CMD7, select card */
- err = IssueSDCommand(device, MMC_SELECT_CARD, (rca << 16), MMC_RSP_R1 | MMC_CMD_AC, NULL);
- if (err) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD7 failed : %d \n",err));
- break;
- }
- }
-
- /* Enable high speed */
- if (card->host->caps & MMC_CAP_SD_HIGHSPEED) {
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("ReinitSDIO: Set high speed mode\n"));
- err = Func0_CMD52ReadByte(card, SDIO_CCCR_SPEED, &cmd52_resp);
- if (err) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD52 read to CCCR speed register failed : %d \n",err));
- card->state &= ~MMC_STATE_HIGHSPEED;
- /* no need to break */
- } else {
- err = Func0_CMD52WriteByte(card, SDIO_CCCR_SPEED, (cmd52_resp | SDIO_SPEED_EHS));
- if (err) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD52 write to CCCR speed register failed : %d \n",err));
- break;
- }
- mmc_card_set_highspeed(card);
- host->ios.timing = MMC_TIMING_SD_HS;
- host->ops->set_ios(host, &host->ios);
- }
- }
-
- /* Set clock */
- if (mmc_card_highspeed(card)) {
- clock = 50000000;
- } else {
- clock = card->cis.max_dtr;
- }
-
- if (clock > host->f_max) {
- clock = host->f_max;
- }
- host->ios.clock = clock;
- host->ops->set_ios(host, &host->ios);
-
-
- if (card->host->caps & MMC_CAP_4_BIT_DATA) {
- /* CMD52: Set bus width & disable card detect resistor */
- err = Func0_CMD52WriteByte(card, SDIO_CCCR_IF, SDIO_BUS_CD_DISABLE | SDIO_BUS_WIDTH_4BIT);
- if (err) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD52 to set bus mode failed : %d \n",err));
- break;
- }
- host->ios.bus_width = MMC_BUS_WIDTH_4;
- host->ops->set_ios(host, &host->ios);
- }
- } while (0);
-
- sdio_release_host(func);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -ReinitSDIO \n"));
-
- return (err) ? A_ERROR : 0;
-}
-
-int
-PowerStateChangeNotify(struct hif_device *device, HIF_DEVICE_POWER_CHANGE_TYPE config)
-{
- int status = 0;
-#if defined(CONFIG_PM)
- struct sdio_func *func = device->func;
- int old_reset_val;
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +PowerStateChangeNotify %d\n", config));
- switch (config) {
- case HIF_DEVICE_POWER_DOWN:
- case HIF_DEVICE_POWER_CUT:
- old_reset_val = reset_sdio_on_unload;
- reset_sdio_on_unload = 1;
- status = hifDisableFunc(device, func);
- reset_sdio_on_unload = old_reset_val;
- if (!device->is_suspend) {
- struct mmc_host *host = func->card->host;
- host->ios.clock = 0;
- host->ios.vdd = 0;
- host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
- host->ios.chip_select = MMC_CS_DONTCARE;
- host->ios.power_mode = MMC_POWER_OFF;
- host->ios.bus_width = MMC_BUS_WIDTH_1;
- host->ios.timing = MMC_TIMING_LEGACY;
- host->ops->set_ios(host, &host->ios);
- }
- break;
- case HIF_DEVICE_POWER_UP:
- if (device->powerConfig == HIF_DEVICE_POWER_CUT) {
- status = ReinitSDIO(device);
- }
- if (status == 0) {
- status = hifEnableFunc(device, func);
- }
- break;
- }
- device->powerConfig = config;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -PowerStateChangeNotify\n"));
-#endif
- return status;
-}
-
-int
-HIFConfigureDevice(struct hif_device *device, HIF_DEVICE_CONFIG_OPCODE opcode,
- void *config, u32 configLen)
-{
- u32 count;
- int status = 0;
-
- switch(opcode) {
- case HIF_DEVICE_GET_MBOX_BLOCK_SIZE:
- ((u32 *)config)[0] = HIF_MBOX0_BLOCK_SIZE;
- ((u32 *)config)[1] = HIF_MBOX1_BLOCK_SIZE;
- ((u32 *)config)[2] = HIF_MBOX2_BLOCK_SIZE;
- ((u32 *)config)[3] = HIF_MBOX3_BLOCK_SIZE;
- break;
-
- case HIF_DEVICE_GET_MBOX_ADDR:
- for (count = 0; count < 4; count ++) {
- ((u32 *)config)[count] = HIF_MBOX_START_ADDR(count);
- }
-
- if (configLen >= sizeof(struct hif_device_mbox_info)) {
- SetExtendedMboxWindowInfo((u16)device->func->device,
- (struct hif_device_mbox_info *)config);
- }
-
- break;
- case HIF_DEVICE_GET_IRQ_PROC_MODE:
- *((HIF_DEVICE_IRQ_PROCESSING_MODE *)config) = HIF_DEVICE_IRQ_SYNC_ONLY;
- break;
- case HIF_CONFIGURE_QUERY_SCATTER_REQUEST_SUPPORT:
- if (!device->scatter_enabled) {
- return A_ENOTSUP;
- }
- status = SetupHIFScatterSupport(device, (struct hif_device_scatter_support_info *)config);
- if (status) {
- device->scatter_enabled = false;
- }
- break;
- case HIF_DEVICE_GET_OS_DEVICE:
- /* pass back a pointer to the SDIO function's "dev" struct */
- ((struct hif_device_os_device_info *)config)->pOSDevice = &device->func->dev;
- break;
- case HIF_DEVICE_POWER_STATE_CHANGE:
- status = PowerStateChangeNotify(device, *(HIF_DEVICE_POWER_CHANGE_TYPE *)config);
- break;
- default:
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
- ("AR6000: Unsupported configuration opcode: %d\n", opcode));
- status = A_ERROR;
- }
-
- return status;
-}
-
-void
-HIFShutDownDevice(struct hif_device *device)
-{
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +HIFShutDownDevice\n"));
- if (device != NULL) {
- AR_DEBUG_ASSERT(device->func != NULL);
- } else {
- /* since we are unloading the driver anyways, reset all cards in case the SDIO card
- * is externally powered and we are unloading the SDIO stack. This avoids the problem when
- * the SDIO stack is reloaded and attempts are made to re-enumerate a card that is already
- * enumerated */
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: HIFShutDownDevice, resetting\n"));
- ResetAllCards();
-
- /* Unregister with bus driver core */
- if (registered) {
- registered = 0;
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
- ("AR6000: Unregistering with the bus driver\n"));
- sdio_unregister_driver(&ath6kl_hifdev_driver);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
- ("AR6000: Unregistered\n"));
- }
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -HIFShutDownDevice\n"));
-}
-
-static void
-hifIRQHandler(struct sdio_func *func)
-{
- int status;
- struct hif_device *device;
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +hifIRQHandler\n"));
-
- device = ath6kl_get_hifdev(func);
- atomic_set(&device->irqHandling, 1);
- /* release the host during ints so we can pick it back up when we process cmds */
- sdio_release_host(device->func);
- status = device->htcCallbacks.dsrHandler(device->htcCallbacks.context);
- sdio_claim_host(device->func);
- atomic_set(&device->irqHandling, 0);
- AR_DEBUG_ASSERT(status == 0 || status == A_ECANCELED);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -hifIRQHandler\n"));
-}
-
-/* handle HTC startup via thread*/
-static int startup_task(void *param)
-{
- struct hif_device *device;
-
- device = (struct hif_device *)param;
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: call HTC from startup_task\n"));
- /* start up inform DRV layer */
- if ((osdrvCallbacks.deviceInsertedHandler(osdrvCallbacks.context,device)) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Device rejected\n"));
- }
- return 0;
-}
-
-#if defined(CONFIG_PM)
-static int enable_task(void *param)
-{
- struct hif_device *device;
- device = (struct hif_device *)param;
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: call from resume_task\n"));
-
- /* start up inform DRV layer */
- if (device &&
- device->claimedContext &&
- osdrvCallbacks.devicePowerChangeHandler &&
- osdrvCallbacks.devicePowerChangeHandler(device->claimedContext, HIF_DEVICE_POWER_UP) != 0)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Device rejected\n"));
- }
-
- return 0;
-}
-#endif
-
-void
-HIFAckInterrupt(struct hif_device *device)
-{
- AR_DEBUG_ASSERT(device != NULL);
-
- /* Acknowledge our function IRQ */
-}
-
-void
-HIFUnMaskInterrupt(struct hif_device *device)
-{
- int ret;
-
- AR_DEBUG_ASSERT(device != NULL);
- AR_DEBUG_ASSERT(device->func != NULL);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: HIFUnMaskInterrupt\n"));
-
- /* Register the IRQ Handler */
- sdio_claim_host(device->func);
- ret = sdio_claim_irq(device->func, hifIRQHandler);
- sdio_release_host(device->func);
- AR_DEBUG_ASSERT(ret == 0);
-}
-
-void HIFMaskInterrupt(struct hif_device *device)
-{
- int ret;
- AR_DEBUG_ASSERT(device != NULL);
- AR_DEBUG_ASSERT(device->func != NULL);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: HIFMaskInterrupt\n"));
-
- /* Mask our function IRQ */
- sdio_claim_host(device->func);
- while (atomic_read(&device->irqHandling)) {
- sdio_release_host(device->func);
- schedule_timeout(HZ/10);
- sdio_claim_host(device->func);
- }
- ret = sdio_release_irq(device->func);
- sdio_release_host(device->func);
- AR_DEBUG_ASSERT(ret == 0);
-}
-
-BUS_REQUEST *hifAllocateBusRequest(struct hif_device *device)
-{
- BUS_REQUEST *busrequest;
- unsigned long flag;
-
- /* Acquire lock */
- spin_lock_irqsave(&device->lock, flag);
-
- /* Remove first in list */
- if((busrequest = device->s_busRequestFreeQueue) != NULL)
- {
- device->s_busRequestFreeQueue = busrequest->next;
- }
- /* Release lock */
- spin_unlock_irqrestore(&device->lock, flag);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: hifAllocateBusRequest: 0x%p\n", busrequest));
- return busrequest;
-}
-
-void
-hifFreeBusRequest(struct hif_device *device, BUS_REQUEST *busrequest)
-{
- unsigned long flag;
-
- AR_DEBUG_ASSERT(busrequest != NULL);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: hifFreeBusRequest: 0x%p\n", busrequest));
- /* Acquire lock */
- spin_lock_irqsave(&device->lock, flag);
-
-
- /* Insert first in list */
- busrequest->next = device->s_busRequestFreeQueue;
- busrequest->inusenext = NULL;
- device->s_busRequestFreeQueue = busrequest;
-
- /* Release lock */
- spin_unlock_irqrestore(&device->lock, flag);
-}
-
-static int hifDisableFunc(struct hif_device *device, struct sdio_func *func)
-{
- int ret;
- int status = 0;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +hifDisableFunc\n"));
- device = ath6kl_get_hifdev(func);
- if (!IS_ERR(device->async_task)) {
- init_completion(&device->async_completion);
- device->async_shutdown = 1;
- up(&device->sem_async);
- wait_for_completion(&device->async_completion);
- device->async_task = NULL;
- }
- /* Disable the card */
- sdio_claim_host(device->func);
- ret = sdio_disable_func(device->func);
- if (ret) {
- status = A_ERROR;
- }
-
- if (reset_sdio_on_unload) {
- /* reset the SDIO interface. This is useful in automated testing where the card
- * does not need to be removed at the end of the test. It is expected that the user will
- * also unload/reload the host controller driver to force the bus driver to re-enumerate the slot */
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("AR6000: reseting SDIO card back to uninitialized state \n"));
-
- /* NOTE : sdio_f0_writeb() cannot be used here, that API only allows access
- * to undefined registers in the range of: 0xF0-0xFF */
-
- ret = Func0_CMD52WriteByte(device->func->card, SDIO_CCCR_ABORT, (1 << 3));
- if (ret) {
- status = A_ERROR;
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("AR6000: reset failed : %d \n",ret));
- }
- }
-
- sdio_release_host(device->func);
-
- if (status == 0) {
- device->is_disabled = true;
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -hifDisableFunc\n"));
-
- return status;
-}
-
-static int hifEnableFunc(struct hif_device *device, struct sdio_func *func)
-{
- struct task_struct* pTask;
- const char *taskName = NULL;
- int (*taskFunc)(void *) = NULL;
- int ret = 0;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +hifEnableFunc\n"));
- device = ath6kl_get_hifdev(func);
-
- if (device->is_disabled) {
- /* enable the SDIO function */
- sdio_claim_host(func);
-
- if ((device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK) >= MANUFACTURER_ID_AR6003_BASE) {
- /* enable 4-bit ASYNC interrupt on AR6003 or later devices */
- ret = Func0_CMD52WriteByte(func->card, CCCR_SDIO_IRQ_MODE_REG, SDIO_IRQ_MODE_ASYNC_4BIT_IRQ);
- if (ret) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("AR6000: failed to enable 4-bit ASYNC IRQ mode %d \n",ret));
- sdio_release_host(func);
- return ret;
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: 4-bit ASYNC IRQ mode enabled\n"));
- }
- /* give us some time to enable, in ms */
- func->enable_timeout = 100;
- ret = sdio_enable_func(func);
- if (ret) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), Unable to enable AR6K: 0x%X\n",
- __FUNCTION__, ret));
- sdio_release_host(func);
- return ret;
- }
- ret = sdio_set_block_size(func, HIF_MBOX_BLOCK_SIZE);
- sdio_release_host(func);
- if (ret) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), Unable to set block size 0x%x AR6K: 0x%X\n",
- __FUNCTION__, HIF_MBOX_BLOCK_SIZE, ret));
- return ret;
- }
- device->is_disabled = false;
- /* create async I/O thread */
- if (!device->async_task) {
- device->async_shutdown = 0;
- device->async_task = kthread_create(async_task,
- (void *)device,
- "AR6K Async");
- if (IS_ERR(device->async_task)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), to create async task\n", __FUNCTION__));
- return -ENOMEM;
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: start async task\n"));
- wake_up_process(device->async_task );
- }
- }
-
- if (!device->claimedContext) {
- taskFunc = startup_task;
- taskName = "AR6K startup";
- ret = 0;
-#if defined(CONFIG_PM)
- } else {
- taskFunc = enable_task;
- taskName = "AR6K enable";
- ret = -ENOMEM;
-#endif /* CONFIG_PM */
- }
- /* create resume thread */
- pTask = kthread_create(taskFunc, (void *)device, taskName);
- if (IS_ERR(pTask)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), to create enabel task\n", __FUNCTION__));
- return -ENOMEM;
- }
- wake_up_process(pTask);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -hifEnableFunc\n"));
-
- /* task will call the enable func, indicate pending */
- return ret;
-}
-
-/*
- * This should be moved to AR6K HTC layer.
- */
-int hifWaitForPendingRecv(struct hif_device *device)
-{
- s32 cnt = 10;
- u8 host_int_status;
- int status = 0;
-
- do {
- while (atomic_read(&device->irqHandling)) {
- /* wait until irq handler finished all the jobs */
- schedule_timeout(HZ/10);
- }
- /* check if there is any pending irq due to force done */
- host_int_status = 0;
- status = HIFReadWrite(device, HOST_INT_STATUS_ADDRESS,
- (u8 *)&host_int_status, sizeof(host_int_status),
- HIF_RD_SYNC_BYTE_INC, NULL);
- host_int_status = !status ? (host_int_status & (1 << 0)) : 0;
- if (host_int_status) {
- schedule(); /* schedule for next dsrHandler */
- }
- } while (host_int_status && --cnt > 0);
-
- if (host_int_status && cnt == 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
- ("AR6000: %s(), Unable clear up pending IRQ before the system suspended\n", __FUNCTION__));
- }
-
- return 0;
-}
-
-static void
-delHifDevice(struct hif_device * device)
-{
- AR_DEBUG_ASSERT(device!= NULL);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: delHifDevice; 0x%p\n", device));
- kfree(device->dma_buffer);
- kfree(device);
-}
-
-static void ResetAllCards(void)
-{
-}
-
-void HIFClaimDevice(struct hif_device *device, void *context)
-{
- device->claimedContext = context;
-}
-
-void HIFReleaseDevice(struct hif_device *device)
-{
- device->claimedContext = NULL;
-}
-
-int HIFAttachHTC(struct hif_device *device, HTC_CALLBACKS *callbacks)
-{
- if (device->htcCallbacks.context != NULL) {
- /* already in use! */
- return A_ERROR;
- }
- device->htcCallbacks = *callbacks;
- return 0;
-}
-
-void HIFDetachHTC(struct hif_device *device)
-{
- A_MEMZERO(&device->htcCallbacks,sizeof(device->htcCallbacks));
-}
-
-#define SDIO_SET_CMD52_ARG(arg,rw,func,raw,address,writedata) \
- (arg) = (((rw) & 1) << 31) | \
- (((func) & 0x7) << 28) | \
- (((raw) & 1) << 27) | \
- (1 << 26) | \
- (((address) & 0x1FFFF) << 9) | \
- (1 << 8) | \
- ((writedata) & 0xFF)
-
-#define SDIO_SET_CMD52_READ_ARG(arg,func,address) \
- SDIO_SET_CMD52_ARG(arg,0,(func),0,address,0x00)
-#define SDIO_SET_CMD52_WRITE_ARG(arg,func,address,value) \
- SDIO_SET_CMD52_ARG(arg,1,(func),0,address,value)
-
-static int Func0_CMD52WriteByte(struct mmc_card *card, unsigned int address, unsigned char byte)
-{
- struct mmc_command ioCmd;
- unsigned long arg;
-
- memset(&ioCmd,0,sizeof(ioCmd));
- SDIO_SET_CMD52_WRITE_ARG(arg,0,address,byte);
- ioCmd.opcode = SD_IO_RW_DIRECT;
- ioCmd.arg = arg;
- ioCmd.flags = MMC_RSP_R5 | MMC_CMD_AC;
-
- return mmc_wait_for_cmd(card->host, &ioCmd, 0);
-}
-
-static int Func0_CMD52ReadByte(struct mmc_card *card, unsigned int address, unsigned char *byte)
-{
- struct mmc_command ioCmd;
- unsigned long arg;
- s32 err;
-
- memset(&ioCmd,0,sizeof(ioCmd));
- SDIO_SET_CMD52_READ_ARG(arg,0,address);
- ioCmd.opcode = SD_IO_RW_DIRECT;
- ioCmd.arg = arg;
- ioCmd.flags = MMC_RSP_R5 | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(card->host, &ioCmd, 0);
-
- if ((!err) && (byte)) {
- *byte = ioCmd.resp[0] & 0xFF;
- }
-
- return err;
-}
diff --git a/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif_scatter.c b/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif_scatter.c
deleted file mode 100644
index 7516d913dab3..000000000000
--- a/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif_scatter.c
+++ /dev/null
@@ -1,393 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2009-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// HIF scatter implementation
-//
-// Author(s): ="Atheros"
-//==============================================================================
-
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/sdio_ids.h>
-#include <linux/mmc/sdio.h>
-#include <linux/kthread.h>
-#include "hif_internal.h"
-#define ATH_MODULE_NAME hif
-#include "a_debug.h"
-
-#ifdef HIF_LINUX_MMC_SCATTER_SUPPORT
-
-#define _CMD53_ARG_READ 0
-#define _CMD53_ARG_WRITE 1
-#define _CMD53_ARG_BLOCK_BASIS 1
-#define _CMD53_ARG_FIXED_ADDRESS 0
-#define _CMD53_ARG_INCR_ADDRESS 1
-
-#define SDIO_SET_CMD53_ARG(arg,rw,func,mode,opcode,address,bytes_blocks) \
- (arg) = (((rw) & 1) << 31) | \
- (((func) & 0x7) << 28) | \
- (((mode) & 1) << 27) | \
- (((opcode) & 1) << 26) | \
- (((address) & 0x1FFFF) << 9) | \
- ((bytes_blocks) & 0x1FF)
-
-static void FreeScatterReq(struct hif_device *device, struct hif_scatter_req *pReq)
-{
- unsigned long flag;
-
- spin_lock_irqsave(&device->lock, flag);
-
- DL_ListInsertTail(&device->ScatterReqHead, &pReq->ListLink);
-
- spin_unlock_irqrestore(&device->lock, flag);
-
-}
-
-static struct hif_scatter_req *AllocScatterReq(struct hif_device *device)
-{
- struct dl_list *pItem;
- unsigned long flag;
-
- spin_lock_irqsave(&device->lock, flag);
-
- pItem = DL_ListRemoveItemFromHead(&device->ScatterReqHead);
-
- spin_unlock_irqrestore(&device->lock, flag);
-
- if (pItem != NULL) {
- return A_CONTAINING_STRUCT(pItem, struct hif_scatter_req, ListLink);
- }
-
- return NULL;
-}
-
- /* called by async task to perform the operation synchronously using direct MMC APIs */
-int DoHifReadWriteScatter(struct hif_device *device, BUS_REQUEST *busrequest)
-{
- int i;
- u8 rw;
- u8 opcode;
- struct mmc_request mmcreq;
- struct mmc_command cmd;
- struct mmc_data data;
- struct hif_scatter_req_priv *pReqPriv;
- struct hif_scatter_req *pReq;
- int status = 0;
- struct scatterlist *pSg;
-
- pReqPriv = busrequest->pScatterReq;
-
- A_ASSERT(pReqPriv != NULL);
-
- pReq = pReqPriv->pHifScatterReq;
-
- memset(&mmcreq, 0, sizeof(struct mmc_request));
- memset(&cmd, 0, sizeof(struct mmc_command));
- memset(&data, 0, sizeof(struct mmc_data));
-
- data.blksz = HIF_MBOX_BLOCK_SIZE;
- data.blocks = pReq->TotalLength / HIF_MBOX_BLOCK_SIZE;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, ("HIF-SCATTER: (%s) Address: 0x%X, (BlockLen: %d, BlockCount: %d) , (tot:%d,sg:%d)\n",
- (pReq->Request & HIF_WRITE) ? "WRITE":"READ", pReq->Address, data.blksz, data.blocks,
- pReq->TotalLength,pReq->ValidScatterEntries));
-
- if (pReq->Request & HIF_WRITE) {
- rw = _CMD53_ARG_WRITE;
- data.flags = MMC_DATA_WRITE;
- } else {
- rw = _CMD53_ARG_READ;
- data.flags = MMC_DATA_READ;
- }
-
- if (pReq->Request & HIF_FIXED_ADDRESS) {
- opcode = _CMD53_ARG_FIXED_ADDRESS;
- } else {
- opcode = _CMD53_ARG_INCR_ADDRESS;
- }
-
- /* fill SG entries */
- pSg = pReqPriv->sgentries;
- sg_init_table(pSg, pReq->ValidScatterEntries);
-
- /* assemble SG list */
- for (i = 0 ; i < pReq->ValidScatterEntries ; i++, pSg++) {
- /* setup each sg entry */
- if ((unsigned long)pReq->ScatterList[i].pBuffer & 0x3) {
- /* note some scatter engines can handle unaligned buffers, print this
- * as informational only */
- AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER,
- ("HIF: (%s) Scatter Buffer is unaligned 0x%lx\n",
- pReq->Request & HIF_WRITE ? "WRITE":"READ",
- (unsigned long)pReq->ScatterList[i].pBuffer));
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, (" %d: Addr:0x%lX, Len:%d \n",
- i,(unsigned long)pReq->ScatterList[i].pBuffer,pReq->ScatterList[i].Length));
-
- sg_set_buf(pSg, pReq->ScatterList[i].pBuffer, pReq->ScatterList[i].Length);
- }
- /* set scatter-gather table for request */
- data.sg = pReqPriv->sgentries;
- data.sg_len = pReq->ValidScatterEntries;
- /* set command argument */
- SDIO_SET_CMD53_ARG(cmd.arg,
- rw,
- device->func->num,
- _CMD53_ARG_BLOCK_BASIS,
- opcode,
- pReq->Address,
- data.blocks);
-
- cmd.opcode = SD_IO_RW_EXTENDED;
- cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
-
- mmcreq.cmd = &cmd;
- mmcreq.data = &data;
-
- mmc_set_data_timeout(&data, device->func->card);
- /* synchronous call to process request */
- mmc_wait_for_req(device->func->card->host, &mmcreq);
-
- if (cmd.error) {
- status = A_ERROR;
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("HIF-SCATTER: cmd error: %d \n",cmd.error));
- }
-
- if (data.error) {
- status = A_ERROR;
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("HIF-SCATTER: data error: %d \n",data.error));
- }
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("HIF-SCATTER: FAILED!!! (%s) Address: 0x%X, Block mode (BlockLen: %d, BlockCount: %d)\n",
- (pReq->Request & HIF_WRITE) ? "WRITE":"READ",pReq->Address, data.blksz, data.blocks));
- }
-
- /* set completion status, fail or success */
- pReq->CompletionStatus = status;
-
- if (pReq->Request & HIF_ASYNCHRONOUS) {
- AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, ("HIF-SCATTER: async_task completion routine req: 0x%lX (%d)\n",(unsigned long)busrequest, status));
- /* complete the request */
- A_ASSERT(pReq->CompletionRoutine != NULL);
- pReq->CompletionRoutine(pReq);
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, ("HIF-SCATTER async_task upping busrequest : 0x%lX (%d)\n", (unsigned long)busrequest,status));
- /* signal wait */
- up(&busrequest->sem_req);
- }
-
- return status;
-}
-
- /* callback to issue a read-write scatter request */
-static int HifReadWriteScatter(struct hif_device *device, struct hif_scatter_req *pReq)
-{
- int status = A_EINVAL;
- u32 request = pReq->Request;
- struct hif_scatter_req_priv *pReqPriv = (struct hif_scatter_req_priv *)pReq->HIFPrivate[0];
-
- do {
-
- A_ASSERT(pReqPriv != NULL);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, ("HIF-SCATTER: total len: %d Scatter Entries: %d\n",
- pReq->TotalLength, pReq->ValidScatterEntries));
-
- if (!(request & HIF_EXTENDED_IO)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
- ("HIF-SCATTER: Invalid command type: 0x%08x\n", request));
- break;
- }
-
- if (!(request & (HIF_SYNCHRONOUS | HIF_ASYNCHRONOUS))) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
- ("HIF-SCATTER: Invalid execution mode: 0x%08x\n", request));
- break;
- }
-
- if (!(request & HIF_BLOCK_BASIS)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
- ("HIF-SCATTER: Invalid data mode: 0x%08x\n", request));
- break;
- }
-
- if (pReq->TotalLength > MAX_SCATTER_REQ_TRANSFER_SIZE) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
- ("HIF-SCATTER: Invalid length: %d \n", pReq->TotalLength));
- break;
- }
-
- if (pReq->TotalLength == 0) {
- A_ASSERT(false);
- break;
- }
-
- /* add bus request to the async list for the async I/O thread to process */
- AddToAsyncList(device, pReqPriv->busrequest);
-
- if (request & HIF_SYNCHRONOUS) {
- AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, ("HIF-SCATTER: queued sync req: 0x%lX\n", (unsigned long)pReqPriv->busrequest));
- /* signal thread and wait */
- up(&device->sem_async);
- if (down_interruptible(&pReqPriv->busrequest->sem_req) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,("HIF-SCATTER: interrupted! \n"));
- /* interrupted, exit */
- status = A_ERROR;
- break;
- } else {
- status = pReq->CompletionStatus;
- }
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, ("HIF-SCATTER: queued async req: 0x%lX\n", (unsigned long)pReqPriv->busrequest));
- /* wake thread, it will process and then take care of the async callback */
- up(&device->sem_async);
- status = 0;
- }
-
- } while (false);
-
- if (status && (request & HIF_ASYNCHRONOUS)) {
- pReq->CompletionStatus = status;
- pReq->CompletionRoutine(pReq);
- status = 0;
- }
-
- return status;
-}
-
- /* setup of HIF scatter resources */
-int SetupHIFScatterSupport(struct hif_device *device, struct hif_device_scatter_support_info *pInfo)
-{
- int status = A_ERROR;
- int i;
- struct hif_scatter_req_priv *pReqPriv;
- BUS_REQUEST *busrequest;
-
- do {
-
- /* check if host supports scatter requests and it meets our requirements */
- if (device->func->card->host->max_segs < MAX_SCATTER_ENTRIES_PER_REQ) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HIF-SCATTER : host only supports scatter of : %d entries, need: %d \n",
- device->func->card->host->max_segs, MAX_SCATTER_ENTRIES_PER_REQ));
- status = A_ENOTSUP;
- break;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("HIF-SCATTER Enabled: max scatter req : %d entries: %d \n",
- MAX_SCATTER_REQUESTS, MAX_SCATTER_ENTRIES_PER_REQ));
-
- for (i = 0; i < MAX_SCATTER_REQUESTS; i++) {
- /* allocate the private request blob */
- pReqPriv = (struct hif_scatter_req_priv *)A_MALLOC(sizeof(struct hif_scatter_req_priv));
- if (NULL == pReqPriv) {
- break;
- }
- A_MEMZERO(pReqPriv, sizeof(struct hif_scatter_req_priv));
- /* save the device instance*/
- pReqPriv->device = device;
- /* allocate the scatter request */
- pReqPriv->pHifScatterReq = (struct hif_scatter_req *)A_MALLOC(sizeof(struct hif_scatter_req) +
- (MAX_SCATTER_ENTRIES_PER_REQ - 1) * (sizeof(struct hif_scatter_item)));
-
- if (NULL == pReqPriv->pHifScatterReq) {
- kfree(pReqPriv);
- break;
- }
- /* just zero the main part of the scatter request */
- A_MEMZERO(pReqPriv->pHifScatterReq, sizeof(struct hif_scatter_req));
- /* back pointer to the private struct */
- pReqPriv->pHifScatterReq->HIFPrivate[0] = pReqPriv;
- /* allocate a bus request for this scatter request */
- busrequest = hifAllocateBusRequest(device);
- if (NULL == busrequest) {
- kfree(pReqPriv->pHifScatterReq);
- kfree(pReqPriv);
- break;
- }
- /* assign the scatter request to this bus request */
- busrequest->pScatterReq = pReqPriv;
- /* point back to the request */
- pReqPriv->busrequest = busrequest;
- /* add it to the scatter pool */
- FreeScatterReq(device,pReqPriv->pHifScatterReq);
- }
-
- if (i != MAX_SCATTER_REQUESTS) {
- status = A_NO_MEMORY;
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HIF-SCATTER : failed to alloc scatter resources !\n"));
- break;
- }
-
- /* set scatter function pointers */
- pInfo->pAllocateReqFunc = AllocScatterReq;
- pInfo->pFreeReqFunc = FreeScatterReq;
- pInfo->pReadWriteScatterFunc = HifReadWriteScatter;
- pInfo->MaxScatterEntries = MAX_SCATTER_ENTRIES_PER_REQ;
- pInfo->MaxTransferSizePerScatterReq = MAX_SCATTER_REQ_TRANSFER_SIZE;
-
- status = 0;
-
- } while (false);
-
- if (status) {
- CleanupHIFScatterResources(device);
- }
-
- return status;
-}
-
- /* clean up scatter support */
-void CleanupHIFScatterResources(struct hif_device *device)
-{
- struct hif_scatter_req_priv *pReqPriv;
- struct hif_scatter_req *pReq;
-
- /* empty the free list */
-
- while (1) {
-
- pReq = AllocScatterReq(device);
-
- if (NULL == pReq) {
- break;
- }
-
- pReqPriv = (struct hif_scatter_req_priv *)pReq->HIFPrivate[0];
- A_ASSERT(pReqPriv != NULL);
-
- if (pReqPriv->busrequest != NULL) {
- pReqPriv->busrequest->pScatterReq = NULL;
- /* free bus request */
- hifFreeBusRequest(device, pReqPriv->busrequest);
- pReqPriv->busrequest = NULL;
- }
-
- if (pReqPriv->pHifScatterReq != NULL) {
- kfree(pReqPriv->pHifScatterReq);
- pReqPriv->pHifScatterReq = NULL;
- }
-
- kfree(pReqPriv);
- }
-}
-
-#endif // HIF_LINUX_MMC_SCATTER_SUPPORT
diff --git a/drivers/staging/ath6kl/htc2/AR6000/ar6k.c b/drivers/staging/ath6kl/htc2/AR6000/ar6k.c
deleted file mode 100644
index f8607bc08929..000000000000
--- a/drivers/staging/ath6kl/htc2/AR6000/ar6k.c
+++ /dev/null
@@ -1,1479 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="ar6k.c" company="Atheros">
-// Copyright (c) 2007-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// AR6K device layer that handles register level I/O
-//
-// Author(s): ="Atheros"
-//==============================================================================
-
-#include "a_config.h"
-#include "athdefs.h"
-#include "hw/mbox_host_reg.h"
-#include "a_osapi.h"
-#include "../htc_debug.h"
-#include "hif.h"
-#include "htc_packet.h"
-#include "ar6k.h"
-
-#define MAILBOX_FOR_BLOCK_SIZE 1
-
-int DevEnableInterrupts(struct ar6k_device *pDev);
-int DevDisableInterrupts(struct ar6k_device *pDev);
-
-static void DevCleanupVirtualScatterSupport(struct ar6k_device *pDev);
-
-void AR6KFreeIOPacket(struct ar6k_device *pDev, struct htc_packet *pPacket)
-{
- LOCK_AR6K(pDev);
- HTC_PACKET_ENQUEUE(&pDev->RegisterIOList,pPacket);
- UNLOCK_AR6K(pDev);
-}
-
-struct htc_packet *AR6KAllocIOPacket(struct ar6k_device *pDev)
-{
- struct htc_packet *pPacket;
-
- LOCK_AR6K(pDev);
- pPacket = HTC_PACKET_DEQUEUE(&pDev->RegisterIOList);
- UNLOCK_AR6K(pDev);
-
- return pPacket;
-}
-
-void DevCleanup(struct ar6k_device *pDev)
-{
- DevCleanupGMbox(pDev);
-
- if (pDev->HifAttached) {
- HIFDetachHTC(pDev->HIFDevice);
- pDev->HifAttached = false;
- }
-
- DevCleanupVirtualScatterSupport(pDev);
-
- if (A_IS_MUTEX_VALID(&pDev->Lock)) {
- A_MUTEX_DELETE(&pDev->Lock);
- }
-}
-
-int DevSetup(struct ar6k_device *pDev)
-{
- u32 blocksizes[AR6K_MAILBOXES];
- int status = 0;
- int i;
- HTC_CALLBACKS htcCallbacks;
-
- do {
-
- DL_LIST_INIT(&pDev->ScatterReqHead);
- /* initialize our free list of IO packets */
- INIT_HTC_PACKET_QUEUE(&pDev->RegisterIOList);
- A_MUTEX_INIT(&pDev->Lock);
-
- A_MEMZERO(&htcCallbacks, sizeof(HTC_CALLBACKS));
- /* the device layer handles these */
- htcCallbacks.rwCompletionHandler = DevRWCompletionHandler;
- htcCallbacks.dsrHandler = DevDsrHandler;
- htcCallbacks.context = pDev;
-
- status = HIFAttachHTC(pDev->HIFDevice, &htcCallbacks);
-
- if (status) {
- break;
- }
-
- pDev->HifAttached = true;
-
- /* get the addresses for all 4 mailboxes */
- status = HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_MBOX_ADDR,
- &pDev->MailBoxInfo, sizeof(pDev->MailBoxInfo));
-
- if (status) {
- A_ASSERT(false);
- break;
- }
-
- /* carve up register I/O packets (these are for ASYNC register I/O ) */
- for (i = 0; i < AR6K_MAX_REG_IO_BUFFERS; i++) {
- struct htc_packet *pIOPacket;
- pIOPacket = &pDev->RegIOBuffers[i].HtcPacket;
- SET_HTC_PACKET_INFO_RX_REFILL(pIOPacket,
- pDev,
- pDev->RegIOBuffers[i].Buffer,
- AR6K_REG_IO_BUFFER_SIZE,
- 0); /* don't care */
- AR6KFreeIOPacket(pDev,pIOPacket);
- }
-
- /* get the block sizes */
- status = HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_MBOX_BLOCK_SIZE,
- blocksizes, sizeof(blocksizes));
-
- if (status) {
- A_ASSERT(false);
- break;
- }
-
- /* note: we actually get the block size of a mailbox other than 0, for SDIO the block
- * size on mailbox 0 is artificially set to 1. So we use the block size that is set
- * for the other 3 mailboxes */
- pDev->BlockSize = blocksizes[MAILBOX_FOR_BLOCK_SIZE];
- /* must be a power of 2 */
- A_ASSERT((pDev->BlockSize & (pDev->BlockSize - 1)) == 0);
-
- /* assemble mask, used for padding to a block */
- pDev->BlockMask = pDev->BlockSize - 1;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("BlockSize: %d, MailboxAddress:0x%X \n",
- pDev->BlockSize, pDev->MailBoxInfo.MboxAddresses[HTC_MAILBOX]));
-
- pDev->GetPendingEventsFunc = NULL;
- /* see if the HIF layer implements the get pending events function */
- HIFConfigureDevice(pDev->HIFDevice,
- HIF_DEVICE_GET_PENDING_EVENTS_FUNC,
- &pDev->GetPendingEventsFunc,
- sizeof(pDev->GetPendingEventsFunc));
-
- /* assume we can process HIF interrupt events asynchronously */
- pDev->HifIRQProcessingMode = HIF_DEVICE_IRQ_ASYNC_SYNC;
-
- /* see if the HIF layer overrides this assumption */
- HIFConfigureDevice(pDev->HIFDevice,
- HIF_DEVICE_GET_IRQ_PROC_MODE,
- &pDev->HifIRQProcessingMode,
- sizeof(pDev->HifIRQProcessingMode));
-
- switch (pDev->HifIRQProcessingMode) {
- case HIF_DEVICE_IRQ_SYNC_ONLY:
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN,("HIF Interrupt processing is SYNC ONLY\n"));
- /* see if HIF layer wants HTC to yield */
- HIFConfigureDevice(pDev->HIFDevice,
- HIF_DEVICE_GET_IRQ_YIELD_PARAMS,
- &pDev->HifIRQYieldParams,
- sizeof(pDev->HifIRQYieldParams));
-
- if (pDev->HifIRQYieldParams.RecvPacketYieldCount > 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
- ("HIF requests that DSR yield per %d RECV packets \n",
- pDev->HifIRQYieldParams.RecvPacketYieldCount));
- pDev->DSRCanYield = true;
- }
- break;
- case HIF_DEVICE_IRQ_ASYNC_SYNC:
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("HIF Interrupt processing is ASYNC and SYNC\n"));
- break;
- default:
- A_ASSERT(false);
- }
-
- pDev->HifMaskUmaskRecvEvent = NULL;
-
- /* see if the HIF layer implements the mask/unmask recv events function */
- HIFConfigureDevice(pDev->HIFDevice,
- HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC,
- &pDev->HifMaskUmaskRecvEvent,
- sizeof(pDev->HifMaskUmaskRecvEvent));
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("HIF special overrides : 0x%lX , 0x%lX\n",
- (unsigned long)pDev->GetPendingEventsFunc, (unsigned long)pDev->HifMaskUmaskRecvEvent));
-
- status = DevDisableInterrupts(pDev);
-
- if (status) {
- break;
- }
-
- status = DevSetupGMbox(pDev);
-
- } while (false);
-
- if (status) {
- if (pDev->HifAttached) {
- HIFDetachHTC(pDev->HIFDevice);
- pDev->HifAttached = false;
- }
- }
-
- return status;
-
-}
-
-int DevEnableInterrupts(struct ar6k_device *pDev)
-{
- int status;
- struct ar6k_irq_enable_registers regs;
-
- LOCK_AR6K(pDev);
-
- /* Enable all the interrupts except for the internal AR6000 CPU interrupt */
- pDev->IrqEnableRegisters.int_status_enable = INT_STATUS_ENABLE_ERROR_SET(0x01) |
- INT_STATUS_ENABLE_CPU_SET(0x01) |
- INT_STATUS_ENABLE_COUNTER_SET(0x01);
-
- if (NULL == pDev->GetPendingEventsFunc) {
- pDev->IrqEnableRegisters.int_status_enable |= INT_STATUS_ENABLE_MBOX_DATA_SET(0x01);
- } else {
- /* The HIF layer provided us with a pending events function which means that
- * the detection of pending mbox messages is handled in the HIF layer.
- * This is the case for the SPI2 interface.
- * In the normal case we enable MBOX interrupts, for the case
- * with HIFs that offer this mechanism, we keep these interrupts
- * masked */
- pDev->IrqEnableRegisters.int_status_enable &= ~INT_STATUS_ENABLE_MBOX_DATA_SET(0x01);
- }
-
-
- /* Set up the CPU Interrupt Status Register */
- pDev->IrqEnableRegisters.cpu_int_status_enable = CPU_INT_STATUS_ENABLE_BIT_SET(0x00);
-
- /* Set up the Error Interrupt Status Register */
- pDev->IrqEnableRegisters.error_status_enable =
- ERROR_STATUS_ENABLE_RX_UNDERFLOW_SET(0x01) |
- ERROR_STATUS_ENABLE_TX_OVERFLOW_SET(0x01);
-
- /* Set up the Counter Interrupt Status Register (only for debug interrupt to catch fatal errors) */
- pDev->IrqEnableRegisters.counter_int_status_enable =
- COUNTER_INT_STATUS_ENABLE_BIT_SET(AR6K_TARGET_DEBUG_INTR_MASK);
-
- /* copy into our temp area */
- memcpy(&regs,&pDev->IrqEnableRegisters,AR6K_IRQ_ENABLE_REGS_SIZE);
-
- UNLOCK_AR6K(pDev);
-
- /* always synchronous */
- status = HIFReadWrite(pDev->HIFDevice,
- INT_STATUS_ENABLE_ADDRESS,
- &regs.int_status_enable,
- AR6K_IRQ_ENABLE_REGS_SIZE,
- HIF_WR_SYNC_BYTE_INC,
- NULL);
-
- if (status) {
- /* Can't write it for some reason */
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("Failed to update interrupt control registers err: %d\n", status));
-
- }
-
- return status;
-}
-
-int DevDisableInterrupts(struct ar6k_device *pDev)
-{
- struct ar6k_irq_enable_registers regs;
-
- LOCK_AR6K(pDev);
- /* Disable all interrupts */
- pDev->IrqEnableRegisters.int_status_enable = 0;
- pDev->IrqEnableRegisters.cpu_int_status_enable = 0;
- pDev->IrqEnableRegisters.error_status_enable = 0;
- pDev->IrqEnableRegisters.counter_int_status_enable = 0;
- /* copy into our temp area */
- memcpy(&regs,&pDev->IrqEnableRegisters,AR6K_IRQ_ENABLE_REGS_SIZE);
-
- UNLOCK_AR6K(pDev);
-
- /* always synchronous */
- return HIFReadWrite(pDev->HIFDevice,
- INT_STATUS_ENABLE_ADDRESS,
- &regs.int_status_enable,
- AR6K_IRQ_ENABLE_REGS_SIZE,
- HIF_WR_SYNC_BYTE_INC,
- NULL);
-}
-
-/* enable device interrupts */
-int DevUnmaskInterrupts(struct ar6k_device *pDev)
-{
- /* for good measure, make sure interrupt are disabled before unmasking at the HIF
- * layer.
- * The rationale here is that between device insertion (where we clear the interrupts the first time)
- * and when HTC is finally ready to handle interrupts, other software can perform target "soft" resets.
- * The AR6K interrupt enables reset back to an "enabled" state when this happens.
- * */
- int IntStatus = 0;
- DevDisableInterrupts(pDev);
-
-#ifdef THREAD_X
- // Tobe verified...
- IntStatus = DevEnableInterrupts(pDev);
- /* Unmask the host controller interrupts */
- HIFUnMaskInterrupt(pDev->HIFDevice);
-#else
- /* Unmask the host controller interrupts */
- HIFUnMaskInterrupt(pDev->HIFDevice);
- IntStatus = DevEnableInterrupts(pDev);
-#endif
-
- return IntStatus;
-}
-
-/* disable all device interrupts */
-int DevMaskInterrupts(struct ar6k_device *pDev)
-{
- /* mask the interrupt at the HIF layer, we don't want a stray interrupt taken while
- * we zero out our shadow registers in DevDisableInterrupts()*/
- HIFMaskInterrupt(pDev->HIFDevice);
-
- return DevDisableInterrupts(pDev);
-}
-
-/* callback when our fetch to enable/disable completes */
-static void DevDoEnableDisableRecvAsyncHandler(void *Context, struct htc_packet *pPacket)
-{
- struct ar6k_device *pDev = (struct ar6k_device *)Context;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevDoEnableDisableRecvAsyncHandler: (dev: 0x%lX)\n", (unsigned long)pDev));
-
- if (pPacket->Status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- (" Failed to disable receiver, status:%d \n", pPacket->Status));
- }
- /* free this IO packet */
- AR6KFreeIOPacket(pDev,pPacket);
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevDoEnableDisableRecvAsyncHandler \n"));
-}
-
-/* disable packet reception (used in case the host runs out of buffers)
- * this is the "override" method when the HIF reports another methods to
- * disable recv events */
-static int DevDoEnableDisableRecvOverride(struct ar6k_device *pDev, bool EnableRecv, bool AsyncMode)
-{
- int status = 0;
- struct htc_packet *pIOPacket = NULL;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("DevDoEnableDisableRecvOverride: Enable:%d Mode:%d\n",
- EnableRecv,AsyncMode));
-
- do {
-
- if (AsyncMode) {
-
- pIOPacket = AR6KAllocIOPacket(pDev);
-
- if (NULL == pIOPacket) {
- status = A_NO_MEMORY;
- A_ASSERT(false);
- break;
- }
-
- /* stick in our completion routine when the I/O operation completes */
- pIOPacket->Completion = DevDoEnableDisableRecvAsyncHandler;
- pIOPacket->pContext = pDev;
-
- /* call the HIF layer override and do this asynchronously */
- status = pDev->HifMaskUmaskRecvEvent(pDev->HIFDevice,
- EnableRecv ? HIF_UNMASK_RECV : HIF_MASK_RECV,
- pIOPacket);
- break;
- }
-
- /* if we get here we are doing it synchronously */
- status = pDev->HifMaskUmaskRecvEvent(pDev->HIFDevice,
- EnableRecv ? HIF_UNMASK_RECV : HIF_MASK_RECV,
- NULL);
-
- } while (false);
-
- if (status && (pIOPacket != NULL)) {
- AR6KFreeIOPacket(pDev,pIOPacket);
- }
-
- return status;
-}
-
-/* disable packet reception (used in case the host runs out of buffers)
- * this is the "normal" method using the interrupt enable registers through
- * the host I/F */
-static int DevDoEnableDisableRecvNormal(struct ar6k_device *pDev, bool EnableRecv, bool AsyncMode)
-{
- int status = 0;
- struct htc_packet *pIOPacket = NULL;
- struct ar6k_irq_enable_registers regs;
-
- /* take the lock to protect interrupt enable shadows */
- LOCK_AR6K(pDev);
-
- if (EnableRecv) {
- pDev->IrqEnableRegisters.int_status_enable |= INT_STATUS_ENABLE_MBOX_DATA_SET(0x01);
- } else {
- pDev->IrqEnableRegisters.int_status_enable &= ~INT_STATUS_ENABLE_MBOX_DATA_SET(0x01);
- }
-
- /* copy into our temp area */
- memcpy(&regs,&pDev->IrqEnableRegisters,AR6K_IRQ_ENABLE_REGS_SIZE);
- UNLOCK_AR6K(pDev);
-
- do {
-
- if (AsyncMode) {
-
- pIOPacket = AR6KAllocIOPacket(pDev);
-
- if (NULL == pIOPacket) {
- status = A_NO_MEMORY;
- A_ASSERT(false);
- break;
- }
-
- /* copy values to write to our async I/O buffer */
- memcpy(pIOPacket->pBuffer,&regs,AR6K_IRQ_ENABLE_REGS_SIZE);
-
- /* stick in our completion routine when the I/O operation completes */
- pIOPacket->Completion = DevDoEnableDisableRecvAsyncHandler;
- pIOPacket->pContext = pDev;
-
- /* write it out asynchronously */
- HIFReadWrite(pDev->HIFDevice,
- INT_STATUS_ENABLE_ADDRESS,
- pIOPacket->pBuffer,
- AR6K_IRQ_ENABLE_REGS_SIZE,
- HIF_WR_ASYNC_BYTE_INC,
- pIOPacket);
- break;
- }
-
- /* if we get here we are doing it synchronously */
-
- status = HIFReadWrite(pDev->HIFDevice,
- INT_STATUS_ENABLE_ADDRESS,
- &regs.int_status_enable,
- AR6K_IRQ_ENABLE_REGS_SIZE,
- HIF_WR_SYNC_BYTE_INC,
- NULL);
-
- } while (false);
-
- if (status && (pIOPacket != NULL)) {
- AR6KFreeIOPacket(pDev,pIOPacket);
- }
-
- return status;
-}
-
-
-int DevStopRecv(struct ar6k_device *pDev, bool AsyncMode)
-{
- if (NULL == pDev->HifMaskUmaskRecvEvent) {
- return DevDoEnableDisableRecvNormal(pDev,false,AsyncMode);
- } else {
- return DevDoEnableDisableRecvOverride(pDev,false,AsyncMode);
- }
-}
-
-int DevEnableRecv(struct ar6k_device *pDev, bool AsyncMode)
-{
- if (NULL == pDev->HifMaskUmaskRecvEvent) {
- return DevDoEnableDisableRecvNormal(pDev,true,AsyncMode);
- } else {
- return DevDoEnableDisableRecvOverride(pDev,true,AsyncMode);
- }
-}
-
-int DevWaitForPendingRecv(struct ar6k_device *pDev,u32 TimeoutInMs,bool *pbIsRecvPending)
-{
- int status = 0;
- u8 host_int_status = 0x0;
- u32 counter = 0x0;
-
- if(TimeoutInMs < 100)
- {
- TimeoutInMs = 100;
- }
-
- counter = TimeoutInMs / 100;
-
- do
- {
- //Read the Host Interrupt Status Register
- status = HIFReadWrite(pDev->HIFDevice,
- HOST_INT_STATUS_ADDRESS,
- &host_int_status,
- sizeof(u8),
- HIF_RD_SYNC_BYTE_INC,
- NULL);
- if (status)
- {
- AR_DEBUG_PRINTF(ATH_LOG_ERR,("DevWaitForPendingRecv:Read HOST_INT_STATUS_ADDRESS Failed 0x%X\n",status));
- break;
- }
-
- host_int_status = !status ? (host_int_status & (1 << 0)):0;
- if(!host_int_status)
- {
- status = 0;
- *pbIsRecvPending = false;
- break;
- }
- else
- {
- *pbIsRecvPending = true;
- }
-
- A_MDELAY(100);
-
- counter--;
-
- }while(counter);
- return status;
-}
-
-void DevDumpRegisters(struct ar6k_device *pDev,
- struct ar6k_irq_proc_registers *pIrqProcRegs,
- struct ar6k_irq_enable_registers *pIrqEnableRegs)
-{
-
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("\n<------- Register Table -------->\n"));
-
- if (pIrqProcRegs != NULL) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
- ("Host Int Status: 0x%x\n",pIrqProcRegs->host_int_status));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
- ("CPU Int Status: 0x%x\n",pIrqProcRegs->cpu_int_status));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
- ("Error Int Status: 0x%x\n",pIrqProcRegs->error_int_status));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
- ("Counter Int Status: 0x%x\n",pIrqProcRegs->counter_int_status));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
- ("Mbox Frame: 0x%x\n",pIrqProcRegs->mbox_frame));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
- ("Rx Lookahead Valid: 0x%x\n",pIrqProcRegs->rx_lookahead_valid));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
- ("Rx Lookahead 0: 0x%x\n",pIrqProcRegs->rx_lookahead[0]));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
- ("Rx Lookahead 1: 0x%x\n",pIrqProcRegs->rx_lookahead[1]));
-
- if (pDev->MailBoxInfo.GMboxAddress != 0) {
- /* if the target supports GMBOX hardware, dump some additional state */
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
- ("GMBOX Host Int Status 2: 0x%x\n",pIrqProcRegs->host_int_status2));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
- ("GMBOX RX Avail: 0x%x\n",pIrqProcRegs->gmbox_rx_avail));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
- ("GMBOX lookahead alias 0: 0x%x\n",pIrqProcRegs->rx_gmbox_lookahead_alias[0]));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
- ("GMBOX lookahead alias 1: 0x%x\n",pIrqProcRegs->rx_gmbox_lookahead_alias[1]));
- }
-
- }
-
- if (pIrqEnableRegs != NULL) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
- ("Int Status Enable: 0x%x\n",pIrqEnableRegs->int_status_enable));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
- ("Counter Int Status Enable: 0x%x\n",pIrqEnableRegs->counter_int_status_enable));
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("<------------------------------->\n"));
-}
-
-
-#define DEV_GET_VIRT_DMA_INFO(p) ((struct dev_scatter_dma_virtual_info *)((p)->HIFPrivate[0]))
-
-static struct hif_scatter_req *DevAllocScatterReq(struct hif_device *Context)
-{
- struct dl_list *pItem;
- struct ar6k_device *pDev = (struct ar6k_device *)Context;
- LOCK_AR6K(pDev);
- pItem = DL_ListRemoveItemFromHead(&pDev->ScatterReqHead);
- UNLOCK_AR6K(pDev);
- if (pItem != NULL) {
- return A_CONTAINING_STRUCT(pItem, struct hif_scatter_req, ListLink);
- }
- return NULL;
-}
-
-static void DevFreeScatterReq(struct hif_device *Context, struct hif_scatter_req *pReq)
-{
- struct ar6k_device *pDev = (struct ar6k_device *)Context;
- LOCK_AR6K(pDev);
- DL_ListInsertTail(&pDev->ScatterReqHead, &pReq->ListLink);
- UNLOCK_AR6K(pDev);
-}
-
-int DevCopyScatterListToFromDMABuffer(struct hif_scatter_req *pReq, bool FromDMA)
-{
- u8 *pDMABuffer = NULL;
- int i, remaining;
- u32 length;
-
- pDMABuffer = pReq->pScatterBounceBuffer;
-
- if (pDMABuffer == NULL) {
- A_ASSERT(false);
- return A_EINVAL;
- }
-
- remaining = (int)pReq->TotalLength;
-
- for (i = 0; i < pReq->ValidScatterEntries; i++) {
-
- length = min((int)pReq->ScatterList[i].Length, remaining);
-
- if (length != (int)pReq->ScatterList[i].Length) {
- A_ASSERT(false);
- /* there is a problem with the scatter list */
- return A_EINVAL;
- }
-
- if (FromDMA) {
- /* from DMA buffer */
- memcpy(pReq->ScatterList[i].pBuffer, pDMABuffer , length);
- } else {
- /* to DMA buffer */
- memcpy(pDMABuffer, pReq->ScatterList[i].pBuffer, length);
- }
-
- pDMABuffer += length;
- remaining -= length;
- }
-
- return 0;
-}
-
-static void DevReadWriteScatterAsyncHandler(void *Context, struct htc_packet *pPacket)
-{
- struct ar6k_device *pDev = (struct ar6k_device *)Context;
- struct hif_scatter_req *pReq = (struct hif_scatter_req *)pPacket->pPktContext;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+DevReadWriteScatterAsyncHandler: (dev: 0x%lX)\n", (unsigned long)pDev));
-
- pReq->CompletionStatus = pPacket->Status;
-
- AR6KFreeIOPacket(pDev,pPacket);
-
- pReq->CompletionRoutine(pReq);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-DevReadWriteScatterAsyncHandler \n"));
-}
-
-static int DevReadWriteScatter(struct hif_device *Context, struct hif_scatter_req *pReq)
-{
- struct ar6k_device *pDev = (struct ar6k_device *)Context;
- int status = 0;
- struct htc_packet *pIOPacket = NULL;
- u32 request = pReq->Request;
-
- do {
-
- if (pReq->TotalLength > AR6K_MAX_TRANSFER_SIZE_PER_SCATTER) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("Invalid length: %d \n", pReq->TotalLength));
- break;
- }
-
- if (pReq->TotalLength == 0) {
- A_ASSERT(false);
- break;
- }
-
- if (request & HIF_ASYNCHRONOUS) {
- /* use an I/O packet to carry this request */
- pIOPacket = AR6KAllocIOPacket(pDev);
- if (NULL == pIOPacket) {
- status = A_NO_MEMORY;
- break;
- }
-
- /* save the request */
- pIOPacket->pPktContext = pReq;
- /* stick in our completion routine when the I/O operation completes */
- pIOPacket->Completion = DevReadWriteScatterAsyncHandler;
- pIOPacket->pContext = pDev;
- }
-
- if (request & HIF_WRITE) {
- /* in virtual DMA, we are issuing the requests through the legacy HIFReadWrite API
- * this API will adjust the address automatically for the last byte to fall on the mailbox
- * EOM. */
-
- /* if the address is an extended address, we can adjust the address here since the extended
- * address will bypass the normal checks in legacy HIF layers */
- if (pReq->Address == pDev->MailBoxInfo.MboxProp[HTC_MAILBOX].ExtendedAddress) {
- pReq->Address += pDev->MailBoxInfo.MboxProp[HTC_MAILBOX].ExtendedSize - pReq->TotalLength;
- }
- }
-
- /* use legacy readwrite */
- status = HIFReadWrite(pDev->HIFDevice,
- pReq->Address,
- DEV_GET_VIRT_DMA_INFO(pReq)->pVirtDmaBuffer,
- pReq->TotalLength,
- request,
- (request & HIF_ASYNCHRONOUS) ? pIOPacket : NULL);
-
- } while (false);
-
- if ((status != A_PENDING) && status && (request & HIF_ASYNCHRONOUS)) {
- if (pIOPacket != NULL) {
- AR6KFreeIOPacket(pDev,pIOPacket);
- }
- pReq->CompletionStatus = status;
- pReq->CompletionRoutine(pReq);
- status = 0;
- }
-
- return status;
-}
-
-
-static void DevCleanupVirtualScatterSupport(struct ar6k_device *pDev)
-{
- struct hif_scatter_req *pReq;
-
- while (1) {
- pReq = DevAllocScatterReq((struct hif_device *)pDev);
- if (NULL == pReq) {
- break;
- }
- kfree(pReq);
- }
-
-}
-
- /* function to set up virtual scatter support if HIF layer has not implemented the interface */
-static int DevSetupVirtualScatterSupport(struct ar6k_device *pDev)
-{
- int status = 0;
- int bufferSize, sgreqSize;
- int i;
- struct dev_scatter_dma_virtual_info *pVirtualInfo;
- struct hif_scatter_req *pReq;
-
- bufferSize = sizeof(struct dev_scatter_dma_virtual_info) +
- 2 * (A_GET_CACHE_LINE_BYTES()) + AR6K_MAX_TRANSFER_SIZE_PER_SCATTER;
-
- sgreqSize = sizeof(struct hif_scatter_req) +
- (AR6K_SCATTER_ENTRIES_PER_REQ - 1) * (sizeof(struct hif_scatter_item));
-
- for (i = 0; i < AR6K_SCATTER_REQS; i++) {
- /* allocate the scatter request, buffer info and the actual virtual buffer itself */
- pReq = (struct hif_scatter_req *)A_MALLOC(sgreqSize + bufferSize);
-
- if (NULL == pReq) {
- status = A_NO_MEMORY;
- break;
- }
-
- A_MEMZERO(pReq, sgreqSize);
-
- /* the virtual DMA starts after the scatter request struct */
- pVirtualInfo = (struct dev_scatter_dma_virtual_info *)((u8 *)pReq + sgreqSize);
- A_MEMZERO(pVirtualInfo, sizeof(struct dev_scatter_dma_virtual_info));
-
- pVirtualInfo->pVirtDmaBuffer = &pVirtualInfo->DataArea[0];
- /* align buffer to cache line in case host controller can actually DMA this */
- pVirtualInfo->pVirtDmaBuffer = A_ALIGN_TO_CACHE_LINE(pVirtualInfo->pVirtDmaBuffer);
- /* store the structure in the private area */
- pReq->HIFPrivate[0] = pVirtualInfo;
- /* we emulate a DMA bounce interface */
- pReq->ScatterMethod = HIF_SCATTER_DMA_BOUNCE;
- pReq->pScatterBounceBuffer = pVirtualInfo->pVirtDmaBuffer;
- /* free request to the list */
- DevFreeScatterReq((struct hif_device *)pDev,pReq);
- }
-
- if (status) {
- DevCleanupVirtualScatterSupport(pDev);
- } else {
- pDev->HifScatterInfo.pAllocateReqFunc = DevAllocScatterReq;
- pDev->HifScatterInfo.pFreeReqFunc = DevFreeScatterReq;
- pDev->HifScatterInfo.pReadWriteScatterFunc = DevReadWriteScatter;
- if (pDev->MailBoxInfo.MboxBusIFType == MBOX_BUS_IF_SPI) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("AR6K: SPI bus requires RX scatter limits\n"));
- pDev->HifScatterInfo.MaxScatterEntries = AR6K_MIN_SCATTER_ENTRIES_PER_REQ;
- pDev->HifScatterInfo.MaxTransferSizePerScatterReq = AR6K_MIN_TRANSFER_SIZE_PER_SCATTER;
- } else {
- pDev->HifScatterInfo.MaxScatterEntries = AR6K_SCATTER_ENTRIES_PER_REQ;
- pDev->HifScatterInfo.MaxTransferSizePerScatterReq = AR6K_MAX_TRANSFER_SIZE_PER_SCATTER;
- }
- pDev->ScatterIsVirtual = true;
- }
-
- return status;
-}
-
-int DevCleanupMsgBundling(struct ar6k_device *pDev)
-{
- if(NULL != pDev)
- {
- DevCleanupVirtualScatterSupport(pDev);
- }
-
- return 0;
-}
-
-int DevSetupMsgBundling(struct ar6k_device *pDev, int MaxMsgsPerTransfer)
-{
- int status;
-
- if (pDev->MailBoxInfo.Flags & HIF_MBOX_FLAG_NO_BUNDLING) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("HIF requires bundling disabled\n"));
- return A_ENOTSUP;
- }
-
- status = HIFConfigureDevice(pDev->HIFDevice,
- HIF_CONFIGURE_QUERY_SCATTER_REQUEST_SUPPORT,
- &pDev->HifScatterInfo,
- sizeof(pDev->HifScatterInfo));
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
- ("AR6K: ** HIF layer does not support scatter requests (%d) \n",status));
-
- /* we can try to use a virtual DMA scatter mechanism using legacy HIFReadWrite() */
- status = DevSetupVirtualScatterSupport(pDev);
-
- if (!status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
- ("AR6K: virtual scatter transfers enabled (max scatter items:%d: maxlen:%d) \n",
- DEV_GET_MAX_MSG_PER_BUNDLE(pDev), DEV_GET_MAX_BUNDLE_LENGTH(pDev)));
- }
-
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
- ("AR6K: HIF layer supports scatter requests (max scatter items:%d: maxlen:%d) \n",
- DEV_GET_MAX_MSG_PER_BUNDLE(pDev), DEV_GET_MAX_BUNDLE_LENGTH(pDev)));
- }
-
- if (!status) {
- /* for the recv path, the maximum number of bytes per recv bundle is just limited
- * by the maximum transfer size at the HIF layer */
- pDev->MaxRecvBundleSize = pDev->HifScatterInfo.MaxTransferSizePerScatterReq;
-
- if (pDev->MailBoxInfo.MboxBusIFType == MBOX_BUS_IF_SPI) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("AR6K : SPI bus requires TX bundling disabled\n"));
- pDev->MaxSendBundleSize = 0;
- } else {
- /* for the send path, the max transfer size is limited by the existence and size of
- * the extended mailbox address range */
- if (pDev->MailBoxInfo.MboxProp[0].ExtendedAddress != 0) {
- pDev->MaxSendBundleSize = pDev->MailBoxInfo.MboxProp[0].ExtendedSize;
- } else {
- /* legacy */
- pDev->MaxSendBundleSize = AR6K_LEGACY_MAX_WRITE_LENGTH;
- }
-
- if (pDev->MaxSendBundleSize > pDev->HifScatterInfo.MaxTransferSizePerScatterReq) {
- /* limit send bundle size to what the HIF can support for scatter requests */
- pDev->MaxSendBundleSize = pDev->HifScatterInfo.MaxTransferSizePerScatterReq;
- }
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
- ("AR6K: max recv: %d max send: %d \n",
- DEV_GET_MAX_BUNDLE_RECV_LENGTH(pDev), DEV_GET_MAX_BUNDLE_SEND_LENGTH(pDev)));
-
- }
- return status;
-}
-
-int DevSubmitScatterRequest(struct ar6k_device *pDev, struct hif_scatter_req *pScatterReq, bool Read, bool Async)
-{
- int status;
-
- if (Read) {
- /* read operation */
- pScatterReq->Request = (Async) ? HIF_RD_ASYNC_BLOCK_FIX : HIF_RD_SYNC_BLOCK_FIX;
- pScatterReq->Address = pDev->MailBoxInfo.MboxAddresses[HTC_MAILBOX];
- A_ASSERT(pScatterReq->TotalLength <= (u32)DEV_GET_MAX_BUNDLE_RECV_LENGTH(pDev));
- } else {
- u32 mailboxWidth;
-
- /* write operation */
- pScatterReq->Request = (Async) ? HIF_WR_ASYNC_BLOCK_INC : HIF_WR_SYNC_BLOCK_INC;
- A_ASSERT(pScatterReq->TotalLength <= (u32)DEV_GET_MAX_BUNDLE_SEND_LENGTH(pDev));
- if (pScatterReq->TotalLength > AR6K_LEGACY_MAX_WRITE_LENGTH) {
- /* for large writes use the extended address */
- pScatterReq->Address = pDev->MailBoxInfo.MboxProp[HTC_MAILBOX].ExtendedAddress;
- mailboxWidth = pDev->MailBoxInfo.MboxProp[HTC_MAILBOX].ExtendedSize;
- } else {
- pScatterReq->Address = pDev->MailBoxInfo.MboxAddresses[HTC_MAILBOX];
- mailboxWidth = AR6K_LEGACY_MAX_WRITE_LENGTH;
- }
-
- if (!pDev->ScatterIsVirtual) {
- /* we are passing this scatter list down to the HIF layer' scatter request handler, fixup the address
- * so that the last byte falls on the EOM, we do this for those HIFs that support the
- * scatter API */
- pScatterReq->Address += (mailboxWidth - pScatterReq->TotalLength);
- }
-
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV | ATH_DEBUG_SEND,
- ("DevSubmitScatterRequest, Entries: %d, Total Length: %d Mbox:0x%X (mode: %s : %s)\n",
- pScatterReq->ValidScatterEntries,
- pScatterReq->TotalLength,
- pScatterReq->Address,
- Async ? "ASYNC" : "SYNC",
- (Read) ? "RD" : "WR"));
-
- status = DEV_PREPARE_SCATTER_OPERATION(pScatterReq);
-
- if (status) {
- if (Async) {
- pScatterReq->CompletionStatus = status;
- pScatterReq->CompletionRoutine(pScatterReq);
- return 0;
- }
- return status;
- }
-
- status = pDev->HifScatterInfo.pReadWriteScatterFunc(pDev->ScatterIsVirtual ? pDev : pDev->HIFDevice,
- pScatterReq);
- if (!Async) {
- /* in sync mode, we can touch the scatter request */
- pScatterReq->CompletionStatus = status;
- DEV_FINISH_SCATTER_OPERATION(pScatterReq);
- } else {
- if (status == A_PENDING) {
- status = 0;
- }
- }
-
- return status;
-}
-
-
-#ifdef MBOXHW_UNIT_TEST
-
-
-/* This is a mailbox hardware unit test that must be called in a schedulable context
- * This test is very simple, it will send a list of buffers with a counting pattern
- * and the target will invert the data and send the message back
- *
- * the unit test has the following constraints:
- *
- * The target has at least 8 buffers of 256 bytes each. The host will send
- * the following pattern of buffers in rapid succession :
- *
- * 1 buffer - 128 bytes
- * 1 buffer - 256 bytes
- * 1 buffer - 512 bytes
- * 1 buffer - 1024 bytes
- *
- * The host will send the buffers to one mailbox and wait for buffers to be reflected
- * back from the same mailbox. The target sends the buffers FIFO order.
- * Once the final buffer has been received for a mailbox, the next mailbox is tested.
- *
- *
- * Note: To simplifythe test , we assume that the chosen buffer sizes
- * will fall on a nice block pad
- *
- * It is expected that higher-order tests will be written to stress the mailboxes using
- * a message-based protocol (with some performance timming) that can create more
- * randomness in the packets sent over mailboxes.
- *
- * */
-
-#define A_ROUND_UP_PWR2(x, align) (((int) (x) + ((align)-1)) & ~((align)-1))
-
-#define BUFFER_BLOCK_PAD 128
-
-#if 0
-#define BUFFER1 128
-#define BUFFER2 256
-#define BUFFER3 512
-#define BUFFER4 1024
-#endif
-
-#if 1
-#define BUFFER1 80
-#define BUFFER2 200
-#define BUFFER3 444
-#define BUFFER4 800
-#endif
-
-#define TOTAL_BYTES (A_ROUND_UP_PWR2(BUFFER1,BUFFER_BLOCK_PAD) + \
- A_ROUND_UP_PWR2(BUFFER2,BUFFER_BLOCK_PAD) + \
- A_ROUND_UP_PWR2(BUFFER3,BUFFER_BLOCK_PAD) + \
- A_ROUND_UP_PWR2(BUFFER4,BUFFER_BLOCK_PAD) )
-
-#define TEST_BYTES (BUFFER1 + BUFFER2 + BUFFER3 + BUFFER4)
-
-#define TEST_CREDITS_RECV_TIMEOUT 100
-
-static u8 g_Buffer[TOTAL_BYTES];
-static u32 g_MailboxAddrs[AR6K_MAILBOXES];
-static u32 g_BlockSizes[AR6K_MAILBOXES];
-
-#define BUFFER_PROC_LIST_DEPTH 4
-
-struct buffer_proc_list {
- u8 *pBuffer;
- u32 length;
-};
-
-
-#define PUSH_BUFF_PROC_ENTRY(pList,len,pCurrpos) \
-{ \
- (pList)->pBuffer = (pCurrpos); \
- (pList)->length = (len); \
- (pCurrpos) += (len); \
- (pList)++; \
-}
-
-/* a simple and crude way to send different "message" sizes */
-static void AssembleBufferList(struct buffer_proc_list *pList)
-{
- u8 *pBuffer = g_Buffer;
-
-#if BUFFER_PROC_LIST_DEPTH < 4
-#error "Buffer processing list depth is not deep enough!!"
-#endif
-
- PUSH_BUFF_PROC_ENTRY(pList,BUFFER1,pBuffer);
- PUSH_BUFF_PROC_ENTRY(pList,BUFFER2,pBuffer);
- PUSH_BUFF_PROC_ENTRY(pList,BUFFER3,pBuffer);
- PUSH_BUFF_PROC_ENTRY(pList,BUFFER4,pBuffer);
-
-}
-
-#define FILL_ZERO true
-#define FILL_COUNTING false
-static void InitBuffers(bool Zero)
-{
- u16 *pBuffer16 = (u16 *)g_Buffer;
- int i;
-
- /* fill buffer with 16 bit counting pattern or zeros */
- for (i = 0; i < (TOTAL_BYTES / 2) ; i++) {
- if (!Zero) {
- pBuffer16[i] = (u16)i;
- } else {
- pBuffer16[i] = 0;
- }
- }
-}
-
-
-static bool CheckOneBuffer(u16 *pBuffer16, int Length)
-{
- int i;
- u16 startCount;
- bool success = true;
-
- /* get the starting count */
- startCount = pBuffer16[0];
- /* invert it, this is the expected value */
- startCount = ~startCount;
- /* scan the buffer and verify */
- for (i = 0; i < (Length / 2) ; i++,startCount++) {
- /* target will invert all the data */
- if ((u16)pBuffer16[i] != (u16)~startCount) {
- success = false;
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Invalid Data Got:0x%X, Expecting:0x%X (offset:%d, total:%d) \n",
- pBuffer16[i], ((u16)~startCount), i, Length));
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("0x%X 0x%X 0x%X 0x%X \n",
- pBuffer16[i], pBuffer16[i + 1], pBuffer16[i + 2],pBuffer16[i+3]));
- break;
- }
- }
-
- return success;
-}
-
-static bool CheckBuffers(void)
-{
- int i;
- bool success = true;
- struct buffer_proc_list checkList[BUFFER_PROC_LIST_DEPTH];
-
- /* assemble the list */
- AssembleBufferList(checkList);
-
- /* scan the buffers and verify */
- for (i = 0; i < BUFFER_PROC_LIST_DEPTH ; i++) {
- success = CheckOneBuffer((u16 *)checkList[i].pBuffer, checkList[i].length);
- if (!success) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Buffer : 0x%X, Length:%d failed verify \n",
- (u32)checkList[i].pBuffer, checkList[i].length));
- break;
- }
- }
-
- return success;
-}
-
- /* find the end marker for the last buffer we will be sending */
-static u16 GetEndMarker(void)
-{
- u8 *pBuffer;
- struct buffer_proc_list checkList[BUFFER_PROC_LIST_DEPTH];
-
- /* fill up buffers with the normal counting pattern */
- InitBuffers(FILL_COUNTING);
-
- /* assemble the list we will be sending down */
- AssembleBufferList(checkList);
- /* point to the last 2 bytes of the last buffer */
- pBuffer = &(checkList[BUFFER_PROC_LIST_DEPTH - 1].pBuffer[(checkList[BUFFER_PROC_LIST_DEPTH - 1].length) - 2]);
-
- /* the last count in the last buffer is the marker */
- return (u16)pBuffer[0] | ((u16)pBuffer[1] << 8);
-}
-
-#define ATH_PRINT_OUT_ZONE ATH_DEBUG_ERR
-
-/* send the ordered buffers to the target */
-static int SendBuffers(struct ar6k_device *pDev, int mbox)
-{
- int status = 0;
- u32 request = HIF_WR_SYNC_BLOCK_INC;
- struct buffer_proc_list sendList[BUFFER_PROC_LIST_DEPTH];
- int i;
- int totalBytes = 0;
- int paddedLength;
- int totalwPadding = 0;
-
- AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Sending buffers on mailbox : %d \n",mbox));
-
- /* fill buffer with counting pattern */
- InitBuffers(FILL_COUNTING);
-
- /* assemble the order in which we send */
- AssembleBufferList(sendList);
-
- for (i = 0; i < BUFFER_PROC_LIST_DEPTH; i++) {
-
- /* we are doing block transfers, so we need to pad everything to a block size */
- paddedLength = (sendList[i].length + (g_BlockSizes[mbox] - 1)) &
- (~(g_BlockSizes[mbox] - 1));
-
- /* send each buffer synchronously */
- status = HIFReadWrite(pDev->HIFDevice,
- g_MailboxAddrs[mbox],
- sendList[i].pBuffer,
- paddedLength,
- request,
- NULL);
- if (status) {
- break;
- }
- totalBytes += sendList[i].length;
- totalwPadding += paddedLength;
- }
-
- AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Sent %d bytes (%d padded bytes) to mailbox : %d \n",totalBytes,totalwPadding,mbox));
-
- return status;
-}
-
-/* poll the mailbox credit counter until we get a credit or timeout */
-static int GetCredits(struct ar6k_device *pDev, int mbox, int *pCredits)
-{
- int status = 0;
- int timeout = TEST_CREDITS_RECV_TIMEOUT;
- u8 credits = 0;
- u32 address;
-
- while (true) {
-
- /* Read the counter register to get credits, this auto-decrements */
- address = COUNT_DEC_ADDRESS + (AR6K_MAILBOXES + mbox) * 4;
- status = HIFReadWrite(pDev->HIFDevice, address, &credits, sizeof(credits),
- HIF_RD_SYNC_BYTE_FIX, NULL);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("Unable to decrement the command credit count register (mbox=%d)\n",mbox));
- status = A_ERROR;
- break;
- }
-
- if (credits) {
- break;
- }
-
- timeout--;
-
- if (timeout <= 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- (" Timeout reading credit registers (mbox=%d, address:0x%X) \n",mbox,address));
- status = A_ERROR;
- break;
- }
-
- /* delay a little, target may not be ready */
- A_MDELAY(1000);
-
- }
-
- if (status == 0) {
- *pCredits = credits;
- }
-
- return status;
-}
-
-
-/* wait for the buffers to come back */
-static int RecvBuffers(struct ar6k_device *pDev, int mbox)
-{
- int status = 0;
- u32 request = HIF_RD_SYNC_BLOCK_INC;
- struct buffer_proc_list recvList[BUFFER_PROC_LIST_DEPTH];
- int curBuffer;
- int credits;
- int i;
- int totalBytes = 0;
- int paddedLength;
- int totalwPadding = 0;
-
- AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Waiting for buffers on mailbox : %d \n",mbox));
-
- /* zero the buffers */
- InitBuffers(FILL_ZERO);
-
- /* assemble the order in which we should receive */
- AssembleBufferList(recvList);
-
- curBuffer = 0;
-
- while (curBuffer < BUFFER_PROC_LIST_DEPTH) {
-
- /* get number of buffers that have been completed, this blocks
- * until we get at least 1 credit or it times out */
- status = GetCredits(pDev, mbox, &credits);
-
- if (status) {
- break;
- }
-
- AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Got %d messages on mailbox : %d \n",credits, mbox));
-
- /* get all the buffers that are sitting on the queue */
- for (i = 0; i < credits; i++) {
- A_ASSERT(curBuffer < BUFFER_PROC_LIST_DEPTH);
- /* recv the current buffer synchronously, the buffers should come back in
- * order... with padding applied by the target */
- paddedLength = (recvList[curBuffer].length + (g_BlockSizes[mbox] - 1)) &
- (~(g_BlockSizes[mbox] - 1));
-
- status = HIFReadWrite(pDev->HIFDevice,
- g_MailboxAddrs[mbox],
- recvList[curBuffer].pBuffer,
- paddedLength,
- request,
- NULL);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to read %d bytes on mailbox:%d : address:0x%X \n",
- recvList[curBuffer].length, mbox, g_MailboxAddrs[mbox]));
- break;
- }
-
- totalwPadding += paddedLength;
- totalBytes += recvList[curBuffer].length;
- curBuffer++;
- }
-
- if (status) {
- break;
- }
- /* go back and get some more */
- credits = 0;
- }
-
- if (totalBytes != TEST_BYTES) {
- A_ASSERT(false);
- } else {
- AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Got all buffers on mbox:%d total recv :%d (w/Padding : %d) \n",
- mbox, totalBytes, totalwPadding));
- }
-
- return status;
-
-
-}
-
-static int DoOneMboxHWTest(struct ar6k_device *pDev, int mbox)
-{
- int status;
-
- do {
- /* send out buffers */
- status = SendBuffers(pDev,mbox);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Sending buffers Failed : %d mbox:%d\n",status,mbox));
- break;
- }
-
- /* go get them, this will block */
- status = RecvBuffers(pDev, mbox);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Recv buffers Failed : %d mbox:%d\n",status,mbox));
- break;
- }
-
- /* check the returned data patterns */
- if (!CheckBuffers()) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Buffer Verify Failed : mbox:%d\n",mbox));
- status = A_ERROR;
- break;
- }
-
- AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, (" Send/Recv success! mailbox : %d \n",mbox));
-
- } while (false);
-
- return status;
-}
-
-/* here is where the test starts */
-int DoMboxHWTest(struct ar6k_device *pDev)
-{
- int i;
- int status;
- int credits = 0;
- u8 params[4];
- int numBufs;
- int bufferSize;
- u16 temp;
-
-
- AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, (" DoMboxHWTest START - \n"));
-
- do {
- /* get the addresses for all 4 mailboxes */
- status = HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_MBOX_ADDR,
- g_MailboxAddrs, sizeof(g_MailboxAddrs));
-
- if (status) {
- A_ASSERT(false);
- break;
- }
-
- /* get the block sizes */
- status = HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_MBOX_BLOCK_SIZE,
- g_BlockSizes, sizeof(g_BlockSizes));
-
- if (status) {
- A_ASSERT(false);
- break;
- }
-
- /* note, the HIF layer usually reports mbox 0 to have a block size of
- * 1, but our test wants to run in block-mode for all mailboxes, so we treat all mailboxes
- * the same. */
- g_BlockSizes[0] = g_BlockSizes[1];
- AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Block Size to use: %d \n",g_BlockSizes[0]));
-
- if (g_BlockSizes[1] > BUFFER_BLOCK_PAD) {
- AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("%d Block size is too large for buffer pad %d\n",
- g_BlockSizes[1], BUFFER_BLOCK_PAD));
- break;
- }
-
- AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Waiting for target.... \n"));
-
- /* the target lets us know it is ready by giving us 1 credit on
- * mailbox 0 */
- status = GetCredits(pDev, 0, &credits);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to wait for target ready \n"));
- break;
- }
-
- AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Target is ready ...\n"));
-
- /* read the first 4 scratch registers */
- status = HIFReadWrite(pDev->HIFDevice,
- SCRATCH_ADDRESS,
- params,
- 4,
- HIF_RD_SYNC_BYTE_INC,
- NULL);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to wait get parameters \n"));
- break;
- }
-
- numBufs = params[0];
- bufferSize = (int)(((u16)params[2] << 8) | (u16)params[1]);
-
- AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE,
- ("Target parameters: bufs per mailbox:%d, buffer size:%d bytes (total space: %d, minimum required space (w/padding): %d) \n",
- numBufs, bufferSize, (numBufs * bufferSize), TOTAL_BYTES));
-
- if ((numBufs * bufferSize) < TOTAL_BYTES) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Not Enough buffer space to run test! need:%d, got:%d \n",
- TOTAL_BYTES, (numBufs*bufferSize)));
- status = A_ERROR;
- break;
- }
-
- temp = GetEndMarker();
-
- status = HIFReadWrite(pDev->HIFDevice,
- SCRATCH_ADDRESS + 4,
- (u8 *)&temp,
- 2,
- HIF_WR_SYNC_BYTE_INC,
- NULL);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to write end marker \n"));
- break;
- }
-
- AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("End Marker: 0x%X \n",temp));
-
- temp = (u16)g_BlockSizes[1];
- /* convert to a mask */
- temp = temp - 1;
- status = HIFReadWrite(pDev->HIFDevice,
- SCRATCH_ADDRESS + 6,
- (u8 *)&temp,
- 2,
- HIF_WR_SYNC_BYTE_INC,
- NULL);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to write block mask \n"));
- break;
- }
-
- AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Set Block Mask: 0x%X \n",temp));
-
- /* execute the test on each mailbox */
- for (i = 0; i < AR6K_MAILBOXES; i++) {
- status = DoOneMboxHWTest(pDev, i);
- if (status) {
- break;
- }
- }
-
- } while (false);
-
- if (status == 0) {
- AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, (" DoMboxHWTest DONE - SUCCESS! - \n"));
- } else {
- AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, (" DoMboxHWTest DONE - FAILED! - \n"));
- }
- /* don't let HTC_Start continue, the target is actually not running any HTC code */
- return A_ERROR;
-}
-#endif
-
-
-
diff --git a/drivers/staging/ath6kl/htc2/AR6000/ar6k.h b/drivers/staging/ath6kl/htc2/AR6000/ar6k.h
deleted file mode 100644
index e551dbe674dc..000000000000
--- a/drivers/staging/ath6kl/htc2/AR6000/ar6k.h
+++ /dev/null
@@ -1,401 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="ar6k.h" company="Atheros">
-// Copyright (c) 2007-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// AR6K device layer that handles register level I/O
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef AR6K_H_
-#define AR6K_H_
-
-#include "hci_transport_api.h"
-#include "../htc_debug.h"
-
-#define AR6K_MAILBOXES 4
-
-/* HTC runs over mailbox 0 */
-#define HTC_MAILBOX 0
-
-#define AR6K_TARGET_DEBUG_INTR_MASK 0x01
-
-#define OTHER_INTS_ENABLED (INT_STATUS_ENABLE_ERROR_MASK | \
- INT_STATUS_ENABLE_CPU_MASK | \
- INT_STATUS_ENABLE_COUNTER_MASK)
-
-
-//#define MBOXHW_UNIT_TEST 1
-
-PREPACK struct ar6k_irq_proc_registers {
- u8 host_int_status;
- u8 cpu_int_status;
- u8 error_int_status;
- u8 counter_int_status;
- u8 mbox_frame;
- u8 rx_lookahead_valid;
- u8 host_int_status2;
- u8 gmbox_rx_avail;
- u32 rx_lookahead[2];
- u32 rx_gmbox_lookahead_alias[2];
-} POSTPACK;
-
-#define AR6K_IRQ_PROC_REGS_SIZE sizeof(struct ar6k_irq_proc_registers)
-
-PREPACK struct ar6k_irq_enable_registers {
- u8 int_status_enable;
- u8 cpu_int_status_enable;
- u8 error_status_enable;
- u8 counter_int_status_enable;
-} POSTPACK;
-
-PREPACK struct ar6k_gmbox_ctrl_registers {
- u8 int_status_enable;
-} POSTPACK;
-
-#define AR6K_IRQ_ENABLE_REGS_SIZE sizeof(struct ar6k_irq_enable_registers)
-
-#define AR6K_REG_IO_BUFFER_SIZE 32
-#define AR6K_MAX_REG_IO_BUFFERS 8
-#define FROM_DMA_BUFFER true
-#define TO_DMA_BUFFER false
-#define AR6K_SCATTER_ENTRIES_PER_REQ 16
-#define AR6K_MAX_TRANSFER_SIZE_PER_SCATTER 16*1024
-#define AR6K_SCATTER_REQS 4
-#define AR6K_LEGACY_MAX_WRITE_LENGTH 2048
-
-#ifndef A_CACHE_LINE_PAD
-#define A_CACHE_LINE_PAD 128
-#endif
-#define AR6K_MIN_SCATTER_ENTRIES_PER_REQ 2
-#define AR6K_MIN_TRANSFER_SIZE_PER_SCATTER 4*1024
-
-/* buffers for ASYNC I/O */
-struct ar6k_async_reg_io_buffer {
- struct htc_packet HtcPacket; /* we use an HTC packet as a wrapper for our async register-based I/O */
- u8 _Pad1[A_CACHE_LINE_PAD];
- u8 Buffer[AR6K_REG_IO_BUFFER_SIZE]; /* cache-line safe with pads around */
- u8 _Pad2[A_CACHE_LINE_PAD];
-};
-
-struct ar6k_gmbox_info {
- void *pProtocolContext;
- int (*pMessagePendingCallBack)(void *pContext, u8 LookAheadBytes[], int ValidBytes);
- int (*pCreditsPendingCallback)(void *pContext, int NumCredits, bool CreditIRQEnabled);
- void (*pTargetFailureCallback)(void *pContext, int Status);
- void (*pStateDumpCallback)(void *pContext);
- bool CreditCountIRQEnabled;
-};
-
-struct ar6k_device {
- A_MUTEX_T Lock;
- u8 _Pad1[A_CACHE_LINE_PAD];
- struct ar6k_irq_proc_registers IrqProcRegisters; /* cache-line safe with pads around */
- u8 _Pad2[A_CACHE_LINE_PAD];
- struct ar6k_irq_enable_registers IrqEnableRegisters; /* cache-line safe with pads around */
- u8 _Pad3[A_CACHE_LINE_PAD];
- void *HIFDevice;
- u32 BlockSize;
- u32 BlockMask;
- struct hif_device_mbox_info MailBoxInfo;
- HIF_PENDING_EVENTS_FUNC GetPendingEventsFunc;
- void *HTCContext;
- struct htc_packet_queue RegisterIOList;
- struct ar6k_async_reg_io_buffer RegIOBuffers[AR6K_MAX_REG_IO_BUFFERS];
- void (*TargetFailureCallback)(void *Context);
- int (*MessagePendingCallback)(void *Context,
- u32 LookAheads[],
- int NumLookAheads,
- bool *pAsyncProc,
- int *pNumPktsFetched);
- HIF_DEVICE_IRQ_PROCESSING_MODE HifIRQProcessingMode;
- HIF_MASK_UNMASK_RECV_EVENT HifMaskUmaskRecvEvent;
- bool HifAttached;
- struct hif_device_irq_yield_params HifIRQYieldParams;
- bool DSRCanYield;
- int CurrentDSRRecvCount;
- struct hif_device_scatter_support_info HifScatterInfo;
- struct dl_list ScatterReqHead;
- bool ScatterIsVirtual;
- int MaxRecvBundleSize;
- int MaxSendBundleSize;
- struct ar6k_gmbox_info GMboxInfo;
- bool GMboxEnabled;
- struct ar6k_gmbox_ctrl_registers GMboxControlRegisters;
- int RecheckIRQStatusCnt;
-};
-
-#define LOCK_AR6K(p) A_MUTEX_LOCK(&(p)->Lock);
-#define UNLOCK_AR6K(p) A_MUTEX_UNLOCK(&(p)->Lock);
-#define REF_IRQ_STATUS_RECHECK(p) (p)->RecheckIRQStatusCnt = 1 /* note: no need to lock this, it only gets set */
-
-int DevSetup(struct ar6k_device *pDev);
-void DevCleanup(struct ar6k_device *pDev);
-int DevUnmaskInterrupts(struct ar6k_device *pDev);
-int DevMaskInterrupts(struct ar6k_device *pDev);
-int DevPollMboxMsgRecv(struct ar6k_device *pDev,
- u32 *pLookAhead,
- int TimeoutMS);
-int DevRWCompletionHandler(void *context, int status);
-int DevDsrHandler(void *context);
-int DevCheckPendingRecvMsgsAsync(void *context);
-void DevAsyncIrqProcessComplete(struct ar6k_device *pDev);
-void DevDumpRegisters(struct ar6k_device *pDev,
- struct ar6k_irq_proc_registers *pIrqProcRegs,
- struct ar6k_irq_enable_registers *pIrqEnableRegs);
-
-#define DEV_STOP_RECV_ASYNC true
-#define DEV_STOP_RECV_SYNC false
-#define DEV_ENABLE_RECV_ASYNC true
-#define DEV_ENABLE_RECV_SYNC false
-int DevStopRecv(struct ar6k_device *pDev, bool ASyncMode);
-int DevEnableRecv(struct ar6k_device *pDev, bool ASyncMode);
-int DevEnableInterrupts(struct ar6k_device *pDev);
-int DevDisableInterrupts(struct ar6k_device *pDev);
-int DevWaitForPendingRecv(struct ar6k_device *pDev,u32 TimeoutInMs,bool *pbIsRecvPending);
-
-#define DEV_CALC_RECV_PADDED_LEN(pDev, length) (((length) + (pDev)->BlockMask) & (~((pDev)->BlockMask)))
-#define DEV_CALC_SEND_PADDED_LEN(pDev, length) DEV_CALC_RECV_PADDED_LEN(pDev,length)
-#define DEV_IS_LEN_BLOCK_ALIGNED(pDev, length) (((length) % (pDev)->BlockSize) == 0)
-
-static INLINE int DevSendPacket(struct ar6k_device *pDev, struct htc_packet *pPacket, u32 SendLength) {
- u32 paddedLength;
- bool sync = (pPacket->Completion == NULL) ? true : false;
- int status;
-
- /* adjust the length to be a multiple of block size if appropriate */
- paddedLength = DEV_CALC_SEND_PADDED_LEN(pDev, SendLength);
-
-#if 0
- if (paddedLength > pPacket->BufferLength) {
- A_ASSERT(false);
- if (pPacket->Completion != NULL) {
- COMPLETE_HTC_PACKET(pPacket,A_EINVAL);
- return 0;
- }
- return A_EINVAL;
- }
-#endif
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
- ("DevSendPacket, Padded Length: %d Mbox:0x%X (mode:%s)\n",
- paddedLength,
- pDev->MailBoxInfo.MboxAddresses[HTC_MAILBOX],
- sync ? "SYNC" : "ASYNC"));
-
- status = HIFReadWrite(pDev->HIFDevice,
- pDev->MailBoxInfo.MboxAddresses[HTC_MAILBOX],
- pPacket->pBuffer,
- paddedLength, /* the padded length */
- sync ? HIF_WR_SYNC_BLOCK_INC : HIF_WR_ASYNC_BLOCK_INC,
- sync ? NULL : pPacket); /* pass the packet as the context to the HIF request */
-
- if (sync) {
- pPacket->Status = status;
- } else {
- if (status == A_PENDING) {
- status = 0;
- }
- }
-
- return status;
-}
-
-static INLINE int DevRecvPacket(struct ar6k_device *pDev, struct htc_packet *pPacket, u32 RecvLength) {
- u32 paddedLength;
- int status;
- bool sync = (pPacket->Completion == NULL) ? true : false;
-
- /* adjust the length to be a multiple of block size if appropriate */
- paddedLength = DEV_CALC_RECV_PADDED_LEN(pDev, RecvLength);
-
- if (paddedLength > pPacket->BufferLength) {
- A_ASSERT(false);
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("DevRecvPacket, Not enough space for padlen:%d recvlen:%d bufferlen:%d \n",
- paddedLength,RecvLength,pPacket->BufferLength));
- if (pPacket->Completion != NULL) {
- COMPLETE_HTC_PACKET(pPacket,A_EINVAL);
- return 0;
- }
- return A_EINVAL;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
- ("DevRecvPacket (0x%lX : hdr:0x%X) Padded Length: %d Mbox:0x%X (mode:%s)\n",
- (unsigned long)pPacket, pPacket->PktInfo.AsRx.ExpectedHdr,
- paddedLength,
- pDev->MailBoxInfo.MboxAddresses[HTC_MAILBOX],
- sync ? "SYNC" : "ASYNC"));
-
- status = HIFReadWrite(pDev->HIFDevice,
- pDev->MailBoxInfo.MboxAddresses[HTC_MAILBOX],
- pPacket->pBuffer,
- paddedLength,
- sync ? HIF_RD_SYNC_BLOCK_FIX : HIF_RD_ASYNC_BLOCK_FIX,
- sync ? NULL : pPacket); /* pass the packet as the context to the HIF request */
-
- if (sync) {
- pPacket->Status = status;
- }
-
- return status;
-}
-
-#define DEV_CHECK_RECV_YIELD(pDev) \
- ((pDev)->CurrentDSRRecvCount >= (pDev)->HifIRQYieldParams.RecvPacketYieldCount)
-
-#define IS_DEV_IRQ_PROC_SYNC_MODE(pDev) (HIF_DEVICE_IRQ_SYNC_ONLY == (pDev)->HifIRQProcessingMode)
-#define IS_DEV_IRQ_PROCESSING_ASYNC_ALLOWED(pDev) ((pDev)->HifIRQProcessingMode != HIF_DEVICE_IRQ_SYNC_ONLY)
-
-/**************************************************/
-/****** Scatter Function and Definitions
- *
- *
- */
-
-int DevCopyScatterListToFromDMABuffer(struct hif_scatter_req *pReq, bool FromDMA);
-
- /* copy any READ data back into scatter list */
-#define DEV_FINISH_SCATTER_OPERATION(pR) \
-do { \
- if (!((pR)->CompletionStatus) && \
- !((pR)->Request & HIF_WRITE) && \
- ((pR)->ScatterMethod == HIF_SCATTER_DMA_BOUNCE)) { \
- (pR)->CompletionStatus = \
- DevCopyScatterListToFromDMABuffer((pR), \
- FROM_DMA_BUFFER); \
- } \
-} while (0)
-
- /* copy any WRITE data to bounce buffer */
-static INLINE int DEV_PREPARE_SCATTER_OPERATION(struct hif_scatter_req *pReq) {
- if ((pReq->Request & HIF_WRITE) && (pReq->ScatterMethod == HIF_SCATTER_DMA_BOUNCE)) {
- return DevCopyScatterListToFromDMABuffer(pReq,TO_DMA_BUFFER);
- } else {
- return 0;
- }
-}
-
-
-int DevSetupMsgBundling(struct ar6k_device *pDev, int MaxMsgsPerTransfer);
-
-int DevCleanupMsgBundling(struct ar6k_device *pDev);
-
-#define DEV_GET_MAX_MSG_PER_BUNDLE(pDev) (pDev)->HifScatterInfo.MaxScatterEntries
-#define DEV_GET_MAX_BUNDLE_LENGTH(pDev) (pDev)->HifScatterInfo.MaxTransferSizePerScatterReq
-#define DEV_ALLOC_SCATTER_REQ(pDev) \
- (pDev)->HifScatterInfo.pAllocateReqFunc((pDev)->ScatterIsVirtual ? (pDev) : (pDev)->HIFDevice)
-
-#define DEV_FREE_SCATTER_REQ(pDev,pR) \
- (pDev)->HifScatterInfo.pFreeReqFunc((pDev)->ScatterIsVirtual ? (pDev) : (pDev)->HIFDevice,(pR))
-
-#define DEV_GET_MAX_BUNDLE_RECV_LENGTH(pDev) (pDev)->MaxRecvBundleSize
-#define DEV_GET_MAX_BUNDLE_SEND_LENGTH(pDev) (pDev)->MaxSendBundleSize
-
-#define DEV_SCATTER_READ true
-#define DEV_SCATTER_WRITE false
-#define DEV_SCATTER_ASYNC true
-#define DEV_SCATTER_SYNC false
-int DevSubmitScatterRequest(struct ar6k_device *pDev, struct hif_scatter_req *pScatterReq, bool Read, bool Async);
-
-#ifdef MBOXHW_UNIT_TEST
-int DoMboxHWTest(struct ar6k_device *pDev);
-#endif
-
- /* completely virtual */
-struct dev_scatter_dma_virtual_info {
- u8 *pVirtDmaBuffer; /* dma-able buffer - CPU accessible address */
- u8 DataArea[1]; /* start of data area */
-};
-
-
-
-void DumpAR6KDevState(struct ar6k_device *pDev);
-
-/**************************************************/
-/****** GMBOX functions and definitions
- *
- *
- */
-
-#ifdef ATH_AR6K_ENABLE_GMBOX
-
-void DevCleanupGMbox(struct ar6k_device *pDev);
-int DevSetupGMbox(struct ar6k_device *pDev);
-int DevCheckGMboxInterrupts(struct ar6k_device *pDev);
-void DevNotifyGMboxTargetFailure(struct ar6k_device *pDev);
-
-#else
-
- /* compiled out */
-#define DevCleanupGMbox(p)
-#define DevCheckGMboxInterrupts(p) 0
-#define DevNotifyGMboxTargetFailure(p)
-
-static INLINE int DevSetupGMbox(struct ar6k_device *pDev) {
- pDev->GMboxEnabled = false;
- return 0;
-}
-
-#endif
-
-#ifdef ATH_AR6K_ENABLE_GMBOX
-
- /* GMBOX protocol modules must expose each of these internal APIs */
-HCI_TRANSPORT_HANDLE GMboxAttachProtocol(struct ar6k_device *pDev, struct hci_transport_config_info *pInfo);
-int GMboxProtocolInstall(struct ar6k_device *pDev);
-void GMboxProtocolUninstall(struct ar6k_device *pDev);
-
- /* API used by GMBOX protocol modules */
-struct ar6k_device *HTCGetAR6KDevice(void *HTCHandle);
-#define DEV_GMBOX_SET_PROTOCOL(pDev,recv_callback,credits_pending,failure,statedump,context) \
-{ \
- (pDev)->GMboxInfo.pProtocolContext = (context); \
- (pDev)->GMboxInfo.pMessagePendingCallBack = (recv_callback); \
- (pDev)->GMboxInfo.pCreditsPendingCallback = (credits_pending); \
- (pDev)->GMboxInfo.pTargetFailureCallback = (failure); \
- (pDev)->GMboxInfo.pStateDumpCallback = (statedump); \
-}
-
-#define DEV_GMBOX_GET_PROTOCOL(pDev) (pDev)->GMboxInfo.pProtocolContext
-
-int DevGMboxWrite(struct ar6k_device *pDev, struct htc_packet *pPacket, u32 WriteLength);
-int DevGMboxRead(struct ar6k_device *pDev, struct htc_packet *pPacket, u32 ReadLength);
-
-#define PROC_IO_ASYNC true
-#define PROC_IO_SYNC false
-typedef enum GMBOX_IRQ_ACTION_TYPE {
- GMBOX_ACTION_NONE = 0,
- GMBOX_DISABLE_ALL,
- GMBOX_ERRORS_IRQ_ENABLE,
- GMBOX_RECV_IRQ_ENABLE,
- GMBOX_RECV_IRQ_DISABLE,
- GMBOX_CREDIT_IRQ_ENABLE,
- GMBOX_CREDIT_IRQ_DISABLE,
-} GMBOX_IRQ_ACTION_TYPE;
-
-int DevGMboxIRQAction(struct ar6k_device *pDev, GMBOX_IRQ_ACTION_TYPE, bool AsyncMode);
-int DevGMboxReadCreditCounter(struct ar6k_device *pDev, bool AsyncMode, int *pCredits);
-int DevGMboxReadCreditSize(struct ar6k_device *pDev, int *pCreditSize);
-int DevGMboxRecvLookAheadPeek(struct ar6k_device *pDev, u8 *pLookAheadBuffer, int *pLookAheadBytes);
-int DevGMboxSetTargetInterrupt(struct ar6k_device *pDev, int SignalNumber, int AckTimeoutMS);
-
-#endif
-
-#endif /*AR6K_H_*/
diff --git a/drivers/staging/ath6kl/htc2/AR6000/ar6k_events.c b/drivers/staging/ath6kl/htc2/AR6000/ar6k_events.c
deleted file mode 100644
index d7af68f70560..000000000000
--- a/drivers/staging/ath6kl/htc2/AR6000/ar6k_events.c
+++ /dev/null
@@ -1,783 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="ar6k_events.c" company="Atheros">
-// Copyright (c) 2007-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// AR6K Driver layer event handling (i.e. interrupts, message polling)
-//
-// Author(s): ="Atheros"
-//==============================================================================
-
-#include "a_config.h"
-#include "athdefs.h"
-#include "hw/mbox_host_reg.h"
-#include "a_osapi.h"
-#include "../htc_debug.h"
-#include "hif.h"
-#include "htc_packet.h"
-#include "ar6k.h"
-
-extern void AR6KFreeIOPacket(struct ar6k_device *pDev, struct htc_packet *pPacket);
-extern struct htc_packet *AR6KAllocIOPacket(struct ar6k_device *pDev);
-
-static int DevServiceDebugInterrupt(struct ar6k_device *pDev);
-
-#define DELAY_PER_INTERVAL_MS 10 /* 10 MS delay per polling interval */
-
-/* completion routine for ALL HIF layer async I/O */
-int DevRWCompletionHandler(void *context, int status)
-{
- struct htc_packet *pPacket = (struct htc_packet *)context;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
- ("+DevRWCompletionHandler (Pkt:0x%lX) , Status: %d \n",
- (unsigned long)pPacket,
- status));
-
- COMPLETE_HTC_PACKET(pPacket,status);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
- ("-DevRWCompletionHandler\n"));
-
- return 0;
-}
-
-/* mailbox recv message polling */
-int DevPollMboxMsgRecv(struct ar6k_device *pDev,
- u32 *pLookAhead,
- int TimeoutMS)
-{
- int status = 0;
- int timeout = TimeoutMS/DELAY_PER_INTERVAL_MS;
-
- A_ASSERT(timeout > 0);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+DevPollMboxMsgRecv \n"));
-
- while (true) {
-
- if (pDev->GetPendingEventsFunc != NULL) {
-
- struct hif_pending_events_info events;
-
-#ifdef THREAD_X
- events.Polling =1;
-#endif
-
- /* the HIF layer uses a special mechanism to get events, do this
- * synchronously */
- status = pDev->GetPendingEventsFunc(pDev->HIFDevice,
- &events,
- NULL);
- if (status)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to get pending events \n"));
- break;
- }
-
- if (events.Events & HIF_RECV_MSG_AVAIL)
- {
- /* there is a message available, the lookahead should be valid now */
- *pLookAhead = events.LookAhead;
-
- break;
- }
- } else {
-
- /* this is the standard HIF way.... */
- /* load the register table */
- status = HIFReadWrite(pDev->HIFDevice,
- HOST_INT_STATUS_ADDRESS,
- (u8 *)&pDev->IrqProcRegisters,
- AR6K_IRQ_PROC_REGS_SIZE,
- HIF_RD_SYNC_BYTE_INC,
- NULL);
-
- if (status){
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to read register table \n"));
- break;
- }
-
- /* check for MBOX data and valid lookahead */
- if (pDev->IrqProcRegisters.host_int_status & (1 << HTC_MAILBOX)) {
- if (pDev->IrqProcRegisters.rx_lookahead_valid & (1 << HTC_MAILBOX))
- {
- /* mailbox has a message and the look ahead is valid */
- *pLookAhead = pDev->IrqProcRegisters.rx_lookahead[HTC_MAILBOX];
- break;
- }
- }
-
- }
-
- timeout--;
-
- if (timeout <= 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" Timeout waiting for recv message \n"));
- status = A_ERROR;
-
- /* check if the target asserted */
- if ( pDev->IrqProcRegisters.counter_int_status & AR6K_TARGET_DEBUG_INTR_MASK) {
- /* target signaled an assert, process this pending interrupt
- * this will call the target failure handler */
- DevServiceDebugInterrupt(pDev);
- }
-
- break;
- }
-
- /* delay a little */
- A_MDELAY(DELAY_PER_INTERVAL_MS);
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,(" Retry Mbox Poll : %d \n",timeout));
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-DevPollMboxMsgRecv \n"));
-
- return status;
-}
-
-static int DevServiceCPUInterrupt(struct ar6k_device *pDev)
-{
- int status;
- u8 cpu_int_status;
- u8 regBuffer[4];
-
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("CPU Interrupt\n"));
- cpu_int_status = pDev->IrqProcRegisters.cpu_int_status &
- pDev->IrqEnableRegisters.cpu_int_status_enable;
- A_ASSERT(cpu_int_status);
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
- ("Valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n",
- cpu_int_status));
-
- /* Clear the interrupt */
- pDev->IrqProcRegisters.cpu_int_status &= ~cpu_int_status; /* W1C */
-
- /* set up the register transfer buffer to hit the register 4 times , this is done
- * to make the access 4-byte aligned to mitigate issues with host bus interconnects that
- * restrict bus transfer lengths to be a multiple of 4-bytes */
-
- /* set W1C value to clear the interrupt, this hits the register first */
- regBuffer[0] = cpu_int_status;
- /* the remaining 4 values are set to zero which have no-effect */
- regBuffer[1] = 0;
- regBuffer[2] = 0;
- regBuffer[3] = 0;
-
- status = HIFReadWrite(pDev->HIFDevice,
- CPU_INT_STATUS_ADDRESS,
- regBuffer,
- 4,
- HIF_WR_SYNC_BYTE_FIX,
- NULL);
-
- A_ASSERT(status == 0);
- return status;
-}
-
-
-static int DevServiceErrorInterrupt(struct ar6k_device *pDev)
-{
- int status;
- u8 error_int_status;
- u8 regBuffer[4];
-
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("Error Interrupt\n"));
- error_int_status = pDev->IrqProcRegisters.error_int_status & 0x0F;
- A_ASSERT(error_int_status);
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
- ("Valid interrupt source(s) in ERROR_INT_STATUS: 0x%x\n",
- error_int_status));
-
- if (ERROR_INT_STATUS_WAKEUP_GET(error_int_status)) {
- /* Wakeup */
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("Error : Wakeup\n"));
- }
-
- if (ERROR_INT_STATUS_RX_UNDERFLOW_GET(error_int_status)) {
- /* Rx Underflow */
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Error : Rx Underflow\n"));
- }
-
- if (ERROR_INT_STATUS_TX_OVERFLOW_GET(error_int_status)) {
- /* Tx Overflow */
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Error : Tx Overflow\n"));
- }
-
- /* Clear the interrupt */
- pDev->IrqProcRegisters.error_int_status &= ~error_int_status; /* W1C */
-
- /* set up the register transfer buffer to hit the register 4 times , this is done
- * to make the access 4-byte aligned to mitigate issues with host bus interconnects that
- * restrict bus transfer lengths to be a multiple of 4-bytes */
-
- /* set W1C value to clear the interrupt, this hits the register first */
- regBuffer[0] = error_int_status;
- /* the remaining 4 values are set to zero which have no-effect */
- regBuffer[1] = 0;
- regBuffer[2] = 0;
- regBuffer[3] = 0;
-
- status = HIFReadWrite(pDev->HIFDevice,
- ERROR_INT_STATUS_ADDRESS,
- regBuffer,
- 4,
- HIF_WR_SYNC_BYTE_FIX,
- NULL);
-
- A_ASSERT(status == 0);
- return status;
-}
-
-static int DevServiceDebugInterrupt(struct ar6k_device *pDev)
-{
- u32 dummy;
- int status;
-
- /* Send a target failure event to the application */
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Target debug interrupt\n"));
-
- if (pDev->TargetFailureCallback != NULL) {
- pDev->TargetFailureCallback(pDev->HTCContext);
- }
-
- if (pDev->GMboxEnabled) {
- DevNotifyGMboxTargetFailure(pDev);
- }
-
- /* clear the interrupt , the debug error interrupt is
- * counter 0 */
- /* read counter to clear interrupt */
- status = HIFReadWrite(pDev->HIFDevice,
- COUNT_DEC_ADDRESS,
- (u8 *)&dummy,
- 4,
- HIF_RD_SYNC_BYTE_INC,
- NULL);
-
- A_ASSERT(status == 0);
- return status;
-}
-
-static int DevServiceCounterInterrupt(struct ar6k_device *pDev)
-{
- u8 counter_int_status;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("Counter Interrupt\n"));
-
- counter_int_status = pDev->IrqProcRegisters.counter_int_status &
- pDev->IrqEnableRegisters.counter_int_status_enable;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
- ("Valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n",
- counter_int_status));
-
- /* Check if the debug interrupt is pending
- * NOTE: other modules like GMBOX may use the counter interrupt for
- * credit flow control on other counters, we only need to check for the debug assertion
- * counter interrupt */
- if (counter_int_status & AR6K_TARGET_DEBUG_INTR_MASK) {
- return DevServiceDebugInterrupt(pDev);
- }
-
- return 0;
-}
-
-/* callback when our fetch to get interrupt status registers completes */
-static void DevGetEventAsyncHandler(void *Context, struct htc_packet *pPacket)
-{
- struct ar6k_device *pDev = (struct ar6k_device *)Context;
- u32 lookAhead = 0;
- bool otherInts = false;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevGetEventAsyncHandler: (dev: 0x%lX)\n", (unsigned long)pDev));
-
- do {
-
- if (pPacket->Status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- (" GetEvents I/O request failed, status:%d \n", pPacket->Status));
- /* bail out, don't unmask HIF interrupt */
- break;
- }
-
- if (pDev->GetPendingEventsFunc != NULL) {
- /* the HIF layer collected the information for us */
- struct hif_pending_events_info *pEvents = (struct hif_pending_events_info *)pPacket->pBuffer;
- if (pEvents->Events & HIF_RECV_MSG_AVAIL) {
- lookAhead = pEvents->LookAhead;
- if (0 == lookAhead) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" DevGetEventAsyncHandler1, lookAhead is zero! \n"));
- }
- }
- if (pEvents->Events & HIF_OTHER_EVENTS) {
- otherInts = true;
- }
- } else {
- /* standard interrupt table handling.... */
- struct ar6k_irq_proc_registers *pReg = (struct ar6k_irq_proc_registers *)pPacket->pBuffer;
- u8 host_int_status;
-
- host_int_status = pReg->host_int_status & pDev->IrqEnableRegisters.int_status_enable;
-
- if (host_int_status & (1 << HTC_MAILBOX)) {
- host_int_status &= ~(1 << HTC_MAILBOX);
- if (pReg->rx_lookahead_valid & (1 << HTC_MAILBOX)) {
- /* mailbox has a message and the look ahead is valid */
- lookAhead = pReg->rx_lookahead[HTC_MAILBOX];
- if (0 == lookAhead) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" DevGetEventAsyncHandler2, lookAhead is zero! \n"));
- }
- }
- }
-
- if (host_int_status) {
- /* there are other interrupts to handle */
- otherInts = true;
- }
- }
-
- if (otherInts || (lookAhead == 0)) {
- /* if there are other interrupts to process, we cannot do this in the async handler so
- * ack the interrupt which will cause our sync handler to run again
- * if however there are no more messages, we can now ack the interrupt */
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
- (" Acking interrupt from DevGetEventAsyncHandler (otherints:%d, lookahead:0x%X)\n",
- otherInts, lookAhead));
- HIFAckInterrupt(pDev->HIFDevice);
- } else {
- int fetched = 0;
- int status;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
- (" DevGetEventAsyncHandler : detected another message, lookahead :0x%X \n",
- lookAhead));
- /* lookahead is non-zero and there are no other interrupts to service,
- * go get the next message */
- status = pDev->MessagePendingCallback(pDev->HTCContext, &lookAhead, 1, NULL, &fetched);
-
- if (!status && !fetched) {
- /* HTC layer could not pull out messages due to lack of resources, stop IRQ processing */
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("MessagePendingCallback did not pull any messages, force-ack \n"));
- DevAsyncIrqProcessComplete(pDev);
- }
- }
-
- } while (false);
-
- /* free this IO packet */
- AR6KFreeIOPacket(pDev,pPacket);
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevGetEventAsyncHandler \n"));
-}
-
-/* called by the HTC layer when it wants us to check if the device has any more pending
- * recv messages, this starts off a series of async requests to read interrupt registers */
-int DevCheckPendingRecvMsgsAsync(void *context)
-{
- struct ar6k_device *pDev = (struct ar6k_device *)context;
- int status = 0;
- struct htc_packet *pIOPacket;
-
- /* this is called in an ASYNC only context, we may NOT block, sleep or call any apis that can
- * cause us to switch contexts */
-
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevCheckPendingRecvMsgsAsync: (dev: 0x%lX)\n", (unsigned long)pDev));
-
- do {
-
- if (HIF_DEVICE_IRQ_SYNC_ONLY == pDev->HifIRQProcessingMode) {
- /* break the async processing chain right here, no need to continue.
- * The DevDsrHandler() will handle things in a loop when things are driven
- * synchronously */
- break;
- }
-
- /* an optimization to bypass reading the IRQ status registers unecessarily which can re-wake
- * the target, if upper layers determine that we are in a low-throughput mode, we can
- * rely on taking another interrupt rather than re-checking the status registers which can
- * re-wake the target */
- if (pDev->RecheckIRQStatusCnt == 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("Bypassing IRQ Status re-check, re-acking HIF interrupts\n"));
- /* ack interrupt */
- HIFAckInterrupt(pDev->HIFDevice);
- break;
- }
-
- /* first allocate one of our HTC packets we created for async I/O
- * we reuse HTC packet definitions so that we can use the completion mechanism
- * in DevRWCompletionHandler() */
- pIOPacket = AR6KAllocIOPacket(pDev);
-
- if (NULL == pIOPacket) {
- /* there should be only 1 asynchronous request out at a time to read these registers
- * so this should actually never happen */
- status = A_NO_MEMORY;
- A_ASSERT(false);
- break;
- }
-
- /* stick in our completion routine when the I/O operation completes */
- pIOPacket->Completion = DevGetEventAsyncHandler;
- pIOPacket->pContext = pDev;
-
- if (pDev->GetPendingEventsFunc) {
- /* HIF layer has it's own mechanism, pass the IO to it.. */
- status = pDev->GetPendingEventsFunc(pDev->HIFDevice,
- (struct hif_pending_events_info *)pIOPacket->pBuffer,
- pIOPacket);
-
- } else {
- /* standard way, read the interrupt register table asynchronously again */
- status = HIFReadWrite(pDev->HIFDevice,
- HOST_INT_STATUS_ADDRESS,
- pIOPacket->pBuffer,
- AR6K_IRQ_PROC_REGS_SIZE,
- HIF_RD_ASYNC_BYTE_INC,
- pIOPacket);
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,(" Async IO issued to get interrupt status...\n"));
- } while (false);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevCheckPendingRecvMsgsAsync \n"));
-
- return status;
-}
-
-void DevAsyncIrqProcessComplete(struct ar6k_device *pDev)
-{
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("DevAsyncIrqProcessComplete - forcing HIF IRQ ACK \n"));
- HIFAckInterrupt(pDev->HIFDevice);
-}
-
-/* process pending interrupts synchronously */
-static int ProcessPendingIRQs(struct ar6k_device *pDev, bool *pDone, bool *pASyncProcessing)
-{
- int status = 0;
- u8 host_int_status = 0;
- u32 lookAhead = 0;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+ProcessPendingIRQs: (dev: 0x%lX)\n", (unsigned long)pDev));
-
- /*** NOTE: the HIF implementation guarantees that the context of this call allows
- * us to perform SYNCHRONOUS I/O, that is we can block, sleep or call any API that
- * can block or switch thread/task ontexts.
- * This is a fully schedulable context.
- * */
- do {
-
- if (pDev->IrqEnableRegisters.int_status_enable == 0) {
- /* interrupt enables have been cleared, do not try to process any pending interrupts that
- * may result in more bus transactions. The target may be unresponsive at this
- * point. */
- break;
- }
-
- if (pDev->GetPendingEventsFunc != NULL) {
- struct hif_pending_events_info events;
-
-#ifdef THREAD_X
- events.Polling= 0;
-#endif
- /* the HIF layer uses a special mechanism to get events
- * get this synchronously */
- status = pDev->GetPendingEventsFunc(pDev->HIFDevice,
- &events,
- NULL);
-
- if (status) {
- break;
- }
-
- if (events.Events & HIF_RECV_MSG_AVAIL) {
- lookAhead = events.LookAhead;
- if (0 == lookAhead) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" ProcessPendingIRQs1 lookAhead is zero! \n"));
- }
- }
-
- if (!(events.Events & HIF_OTHER_EVENTS) ||
- !(pDev->IrqEnableRegisters.int_status_enable & OTHER_INTS_ENABLED)) {
- /* no need to read the register table, no other interesting interrupts.
- * Some interfaces (like SPI) can shadow interrupt sources without
- * requiring the host to do a full table read */
- break;
- }
-
- /* otherwise fall through and read the register table */
- }
-
- /*
- * Read the first 28 bytes of the HTC register table. This will yield us
- * the value of different int status registers and the lookahead
- * registers.
- * length = sizeof(int_status) + sizeof(cpu_int_status) +
- * sizeof(error_int_status) + sizeof(counter_int_status) +
- * sizeof(mbox_frame) + sizeof(rx_lookahead_valid) +
- * sizeof(hole) + sizeof(rx_lookahead) +
- * sizeof(int_status_enable) + sizeof(cpu_int_status_enable) +
- * sizeof(error_status_enable) +
- * sizeof(counter_int_status_enable);
- *
- */
-#ifdef CONFIG_MMC_SDHCI_S3C
- pDev->IrqProcRegisters.host_int_status = 0;
- pDev->IrqProcRegisters.rx_lookahead_valid = 0;
- pDev->IrqProcRegisters.host_int_status2 = 0;
- pDev->IrqProcRegisters.rx_lookahead[0] = 0;
- pDev->IrqProcRegisters.rx_lookahead[1] = 0xaaa5555;
-#endif /* CONFIG_MMC_SDHCI_S3C */
- status = HIFReadWrite(pDev->HIFDevice,
- HOST_INT_STATUS_ADDRESS,
- (u8 *)&pDev->IrqProcRegisters,
- AR6K_IRQ_PROC_REGS_SIZE,
- HIF_RD_SYNC_BYTE_INC,
- NULL);
-
- if (status) {
- break;
- }
-
-#ifdef ATH_DEBUG_MODULE
- if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_IRQ)) {
- DevDumpRegisters(pDev,
- &pDev->IrqProcRegisters,
- &pDev->IrqEnableRegisters);
- }
-#endif
-
- /* Update only those registers that are enabled */
- host_int_status = pDev->IrqProcRegisters.host_int_status &
- pDev->IrqEnableRegisters.int_status_enable;
-
- if (NULL == pDev->GetPendingEventsFunc) {
- /* only look at mailbox status if the HIF layer did not provide this function,
- * on some HIF interfaces reading the RX lookahead is not valid to do */
- if (host_int_status & (1 << HTC_MAILBOX)) {
- /* mask out pending mailbox value, we use "lookAhead" as the real flag for
- * mailbox processing below */
- host_int_status &= ~(1 << HTC_MAILBOX);
- if (pDev->IrqProcRegisters.rx_lookahead_valid & (1 << HTC_MAILBOX)) {
- /* mailbox has a message and the look ahead is valid */
- lookAhead = pDev->IrqProcRegisters.rx_lookahead[HTC_MAILBOX];
- if (0 == lookAhead) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" ProcessPendingIRQs2, lookAhead is zero! \n"));
- }
- }
- }
- } else {
- /* not valid to check if the HIF has another mechanism for reading mailbox pending status*/
- host_int_status &= ~(1 << HTC_MAILBOX);
- }
-
- if (pDev->GMboxEnabled) {
- /*call GMBOX layer to process any interrupts of interest */
- status = DevCheckGMboxInterrupts(pDev);
- }
-
- } while (false);
-
-
- do {
-
- /* did the interrupt status fetches succeed? */
- if (status) {
- break;
- }
-
- if ((0 == host_int_status) && (0 == lookAhead)) {
- /* nothing to process, the caller can use this to break out of a loop */
- *pDone = true;
- break;
- }
-
- if (lookAhead != 0) {
- int fetched = 0;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("Pending mailbox message, LookAhead: 0x%X\n",lookAhead));
- /* Mailbox Interrupt, the HTC layer may issue async requests to empty the
- * mailbox...
- * When emptying the recv mailbox we use the async handler above called from the
- * completion routine of the callers read request. This can improve performance
- * by reducing context switching when we rapidly pull packets */
- status = pDev->MessagePendingCallback(pDev->HTCContext, &lookAhead, 1, pASyncProcessing, &fetched);
- if (status) {
- break;
- }
-
- if (!fetched) {
- /* HTC could not pull any messages out due to lack of resources */
- /* force DSR handler to ack the interrupt */
- *pASyncProcessing = false;
- pDev->RecheckIRQStatusCnt = 0;
- }
- }
-
- /* now handle the rest of them */
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
- (" Valid interrupt source(s) for OTHER interrupts: 0x%x\n",
- host_int_status));
-
- if (HOST_INT_STATUS_CPU_GET(host_int_status)) {
- /* CPU Interrupt */
- status = DevServiceCPUInterrupt(pDev);
- if (status){
- break;
- }
- }
-
- if (HOST_INT_STATUS_ERROR_GET(host_int_status)) {
- /* Error Interrupt */
- status = DevServiceErrorInterrupt(pDev);
- if (status){
- break;
- }
- }
-
- if (HOST_INT_STATUS_COUNTER_GET(host_int_status)) {
- /* Counter Interrupt */
- status = DevServiceCounterInterrupt(pDev);
- if (status){
- break;
- }
- }
-
- } while (false);
-
- /* an optimization to bypass reading the IRQ status registers unecessarily which can re-wake
- * the target, if upper layers determine that we are in a low-throughput mode, we can
- * rely on taking another interrupt rather than re-checking the status registers which can
- * re-wake the target.
- *
- * NOTE : for host interfaces that use the special GetPendingEventsFunc, this optimization cannot
- * be used due to possible side-effects. For example, SPI requires the host to drain all
- * messages from the mailbox before exiting the ISR routine. */
- if (!(*pASyncProcessing) && (pDev->RecheckIRQStatusCnt == 0) && (pDev->GetPendingEventsFunc == NULL)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("Bypassing IRQ Status re-check, forcing done \n"));
- *pDone = true;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-ProcessPendingIRQs: (done:%d, async:%d) status=%d \n",
- *pDone, *pASyncProcessing, status));
-
- return status;
-}
-
-
-/* Synchronousinterrupt handler, this handler kicks off all interrupt processing.*/
-int DevDsrHandler(void *context)
-{
- struct ar6k_device *pDev = (struct ar6k_device *)context;
- int status = 0;
- bool done = false;
- bool asyncProc = false;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevDsrHandler: (dev: 0x%lX)\n", (unsigned long)pDev));
-
- /* reset the recv counter that tracks when we need to yield from the DSR */
- pDev->CurrentDSRRecvCount = 0;
- /* reset counter used to flag a re-scan of IRQ status registers on the target */
- pDev->RecheckIRQStatusCnt = 0;
-
- while (!done) {
- status = ProcessPendingIRQs(pDev, &done, &asyncProc);
- if (status) {
- break;
- }
-
- if (HIF_DEVICE_IRQ_SYNC_ONLY == pDev->HifIRQProcessingMode) {
- /* the HIF layer does not allow async IRQ processing, override the asyncProc flag */
- asyncProc = false;
- /* this will cause us to re-enter ProcessPendingIRQ() and re-read interrupt status registers.
- * this has a nice side effect of blocking us until all async read requests are completed.
- * This behavior is required on some HIF implementations that do not allow ASYNC
- * processing in interrupt handlers (like Windows CE) */
-
- if (pDev->DSRCanYield && DEV_CHECK_RECV_YIELD(pDev)) {
- /* ProcessPendingIRQs() pulled enough recv messages to satisfy the yield count, stop
- * checking for more messages and return */
- break;
- }
- }
-
- if (asyncProc) {
- /* the function performed some async I/O for performance, we
- need to exit the ISR immediately, the check below will prevent the interrupt from being
- Ack'd while we handle it asynchronously */
- break;
- }
-
- }
-
- if (!status && !asyncProc) {
- /* Ack the interrupt only if :
- * 1. we did not get any errors in processing interrupts
- * 2. there are no outstanding async processing requests */
- if (pDev->DSRCanYield) {
- /* if the DSR can yield do not ACK the interrupt, there could be more pending messages.
- * The HIF layer must ACK the interrupt on behalf of HTC */
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,(" Yield in effect (cur RX count: %d) \n", pDev->CurrentDSRRecvCount));
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,(" Acking interrupt from DevDsrHandler \n"));
- HIFAckInterrupt(pDev->HIFDevice);
- }
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevDsrHandler \n"));
- return status;
-}
-
-#ifdef ATH_DEBUG_MODULE
-void DumpAR6KDevState(struct ar6k_device *pDev)
-{
- int status;
- struct ar6k_irq_enable_registers regs;
- struct ar6k_irq_proc_registers procRegs;
-
- LOCK_AR6K(pDev);
- /* copy into our temp area */
- memcpy(&regs,&pDev->IrqEnableRegisters,AR6K_IRQ_ENABLE_REGS_SIZE);
- UNLOCK_AR6K(pDev);
-
- /* load the register table from the device */
- status = HIFReadWrite(pDev->HIFDevice,
- HOST_INT_STATUS_ADDRESS,
- (u8 *)&procRegs,
- AR6K_IRQ_PROC_REGS_SIZE,
- HIF_RD_SYNC_BYTE_INC,
- NULL);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("DumpAR6KDevState : Failed to read register table (%d) \n",status));
- return;
- }
-
- DevDumpRegisters(pDev,&procRegs,&regs);
-
- if (pDev->GMboxInfo.pStateDumpCallback != NULL) {
- pDev->GMboxInfo.pStateDumpCallback(pDev->GMboxInfo.pProtocolContext);
- }
-
- /* dump any bus state at the HIF layer */
- HIFConfigureDevice(pDev->HIFDevice,HIF_DEVICE_DEBUG_BUS_STATE,NULL,0);
-
-}
-#endif
-
-
diff --git a/drivers/staging/ath6kl/htc2/AR6000/ar6k_gmbox.c b/drivers/staging/ath6kl/htc2/AR6000/ar6k_gmbox.c
deleted file mode 100644
index 725540f9adde..000000000000
--- a/drivers/staging/ath6kl/htc2/AR6000/ar6k_gmbox.c
+++ /dev/null
@@ -1,755 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="ar6k_gmbox.c" company="Atheros">
-// Copyright (c) 2007-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Generic MBOX API implementation
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#include "a_config.h"
-#include "athdefs.h"
-#include "a_osapi.h"
-#include "../htc_debug.h"
-#include "hif.h"
-#include "htc_packet.h"
-#include "ar6k.h"
-#include "hw/mbox_host_reg.h"
-#include "gmboxif.h"
-
-/*
- * This file provides management functions and a toolbox for GMBOX protocol modules.
- * Only one protocol module can be installed at a time. The determination of which protocol
- * module is installed is determined at compile time.
- *
- */
-#ifdef ATH_AR6K_ENABLE_GMBOX
- /* GMBOX definitions */
-#define GMBOX_INT_STATUS_ENABLE_REG 0x488
-#define GMBOX_INT_STATUS_RX_DATA (1 << 0)
-#define GMBOX_INT_STATUS_TX_OVERFLOW (1 << 1)
-#define GMBOX_INT_STATUS_RX_OVERFLOW (1 << 2)
-
-#define GMBOX_LOOKAHEAD_MUX_REG 0x498
-#define GMBOX_LA_MUX_OVERRIDE_2_3 (1 << 0)
-
-#define AR6K_GMBOX_CREDIT_DEC_ADDRESS (COUNT_DEC_ADDRESS + 4 * AR6K_GMBOX_CREDIT_COUNTER)
-#define AR6K_GMBOX_CREDIT_SIZE_ADDRESS (COUNT_ADDRESS + AR6K_GMBOX_CREDIT_SIZE_COUNTER)
-
-
- /* external APIs for allocating and freeing internal I/O packets to handle ASYNC I/O */
-extern void AR6KFreeIOPacket(struct ar6k_device *pDev, struct htc_packet *pPacket);
-extern struct htc_packet *AR6KAllocIOPacket(struct ar6k_device *pDev);
-
-
-/* callback when our fetch to enable/disable completes */
-static void DevGMboxIRQActionAsyncHandler(void *Context, struct htc_packet *pPacket)
-{
- struct ar6k_device *pDev = (struct ar6k_device *)Context;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevGMboxIRQActionAsyncHandler: (dev: 0x%lX)\n", (unsigned long)pDev));
-
- if (pPacket->Status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("IRQAction Operation (%d) failed! status:%d \n", pPacket->PktInfo.AsRx.HTCRxFlags,pPacket->Status));
- }
- /* free this IO packet */
- AR6KFreeIOPacket(pDev,pPacket);
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevGMboxIRQActionAsyncHandler \n"));
-}
-
-static int DevGMboxCounterEnableDisable(struct ar6k_device *pDev, GMBOX_IRQ_ACTION_TYPE IrqAction, bool AsyncMode)
-{
- int status = 0;
- struct ar6k_irq_enable_registers regs;
- struct htc_packet *pIOPacket = NULL;
-
- LOCK_AR6K(pDev);
-
- if (GMBOX_CREDIT_IRQ_ENABLE == IrqAction) {
- pDev->GMboxInfo.CreditCountIRQEnabled = true;
- pDev->IrqEnableRegisters.counter_int_status_enable |=
- COUNTER_INT_STATUS_ENABLE_BIT_SET(1 << AR6K_GMBOX_CREDIT_COUNTER);
- pDev->IrqEnableRegisters.int_status_enable |= INT_STATUS_ENABLE_COUNTER_SET(0x01);
- } else {
- pDev->GMboxInfo.CreditCountIRQEnabled = false;
- pDev->IrqEnableRegisters.counter_int_status_enable &=
- ~(COUNTER_INT_STATUS_ENABLE_BIT_SET(1 << AR6K_GMBOX_CREDIT_COUNTER));
- }
- /* copy into our temp area */
- memcpy(&regs,&pDev->IrqEnableRegisters,AR6K_IRQ_ENABLE_REGS_SIZE);
-
- UNLOCK_AR6K(pDev);
-
- do {
-
- if (AsyncMode) {
-
- pIOPacket = AR6KAllocIOPacket(pDev);
-
- if (NULL == pIOPacket) {
- status = A_NO_MEMORY;
- A_ASSERT(false);
- break;
- }
-
- /* copy values to write to our async I/O buffer */
- memcpy(pIOPacket->pBuffer,&pDev->IrqEnableRegisters,AR6K_IRQ_ENABLE_REGS_SIZE);
-
- /* stick in our completion routine when the I/O operation completes */
- pIOPacket->Completion = DevGMboxIRQActionAsyncHandler;
- pIOPacket->pContext = pDev;
- pIOPacket->PktInfo.AsRx.HTCRxFlags = IrqAction;
- /* write it out asynchronously */
- HIFReadWrite(pDev->HIFDevice,
- INT_STATUS_ENABLE_ADDRESS,
- pIOPacket->pBuffer,
- AR6K_IRQ_ENABLE_REGS_SIZE,
- HIF_WR_ASYNC_BYTE_INC,
- pIOPacket);
-
- pIOPacket = NULL;
- break;
- }
-
- /* if we get here we are doing it synchronously */
- status = HIFReadWrite(pDev->HIFDevice,
- INT_STATUS_ENABLE_ADDRESS,
- &regs.int_status_enable,
- AR6K_IRQ_ENABLE_REGS_SIZE,
- HIF_WR_SYNC_BYTE_INC,
- NULL);
- } while (false);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- (" IRQAction Operation (%d) failed! status:%d \n", IrqAction, status));
- } else {
- if (!AsyncMode) {
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
- (" IRQAction Operation (%d) success \n", IrqAction));
- }
- }
-
- if (pIOPacket != NULL) {
- AR6KFreeIOPacket(pDev,pIOPacket);
- }
-
- return status;
-}
-
-
-int DevGMboxIRQAction(struct ar6k_device *pDev, GMBOX_IRQ_ACTION_TYPE IrqAction, bool AsyncMode)
-{
- int status = 0;
- struct htc_packet *pIOPacket = NULL;
- u8 GMboxIntControl[4];
-
- if (GMBOX_CREDIT_IRQ_ENABLE == IrqAction) {
- return DevGMboxCounterEnableDisable(pDev, GMBOX_CREDIT_IRQ_ENABLE, AsyncMode);
- } else if(GMBOX_CREDIT_IRQ_DISABLE == IrqAction) {
- return DevGMboxCounterEnableDisable(pDev, GMBOX_CREDIT_IRQ_DISABLE, AsyncMode);
- }
-
- if (GMBOX_DISABLE_ALL == IrqAction) {
- /* disable credit IRQ, those are on a different set of registers */
- DevGMboxCounterEnableDisable(pDev, GMBOX_CREDIT_IRQ_DISABLE, AsyncMode);
- }
-
- /* take the lock to protect interrupt enable shadows */
- LOCK_AR6K(pDev);
-
- switch (IrqAction) {
-
- case GMBOX_DISABLE_ALL:
- pDev->GMboxControlRegisters.int_status_enable = 0;
- break;
- case GMBOX_ERRORS_IRQ_ENABLE:
- pDev->GMboxControlRegisters.int_status_enable |= GMBOX_INT_STATUS_TX_OVERFLOW |
- GMBOX_INT_STATUS_RX_OVERFLOW;
- break;
- case GMBOX_RECV_IRQ_ENABLE:
- pDev->GMboxControlRegisters.int_status_enable |= GMBOX_INT_STATUS_RX_DATA;
- break;
- case GMBOX_RECV_IRQ_DISABLE:
- pDev->GMboxControlRegisters.int_status_enable &= ~GMBOX_INT_STATUS_RX_DATA;
- break;
- case GMBOX_ACTION_NONE:
- default:
- A_ASSERT(false);
- break;
- }
-
- GMboxIntControl[0] = pDev->GMboxControlRegisters.int_status_enable;
- GMboxIntControl[1] = GMboxIntControl[0];
- GMboxIntControl[2] = GMboxIntControl[0];
- GMboxIntControl[3] = GMboxIntControl[0];
-
- UNLOCK_AR6K(pDev);
-
- do {
-
- if (AsyncMode) {
-
- pIOPacket = AR6KAllocIOPacket(pDev);
-
- if (NULL == pIOPacket) {
- status = A_NO_MEMORY;
- A_ASSERT(false);
- break;
- }
-
- /* copy values to write to our async I/O buffer */
- memcpy(pIOPacket->pBuffer,GMboxIntControl,sizeof(GMboxIntControl));
-
- /* stick in our completion routine when the I/O operation completes */
- pIOPacket->Completion = DevGMboxIRQActionAsyncHandler;
- pIOPacket->pContext = pDev;
- pIOPacket->PktInfo.AsRx.HTCRxFlags = IrqAction;
- /* write it out asynchronously */
- HIFReadWrite(pDev->HIFDevice,
- GMBOX_INT_STATUS_ENABLE_REG,
- pIOPacket->pBuffer,
- sizeof(GMboxIntControl),
- HIF_WR_ASYNC_BYTE_FIX,
- pIOPacket);
- pIOPacket = NULL;
- break;
- }
-
- /* if we get here we are doing it synchronously */
-
- status = HIFReadWrite(pDev->HIFDevice,
- GMBOX_INT_STATUS_ENABLE_REG,
- GMboxIntControl,
- sizeof(GMboxIntControl),
- HIF_WR_SYNC_BYTE_FIX,
- NULL);
-
- } while (false);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- (" IRQAction Operation (%d) failed! status:%d \n", IrqAction, status));
- } else {
- if (!AsyncMode) {
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
- (" IRQAction Operation (%d) success \n", IrqAction));
- }
- }
-
- if (pIOPacket != NULL) {
- AR6KFreeIOPacket(pDev,pIOPacket);
- }
-
- return status;
-}
-
-void DevCleanupGMbox(struct ar6k_device *pDev)
-{
- if (pDev->GMboxEnabled) {
- pDev->GMboxEnabled = false;
- GMboxProtocolUninstall(pDev);
- }
-}
-
-int DevSetupGMbox(struct ar6k_device *pDev)
-{
- int status = 0;
- u8 muxControl[4];
-
- do {
-
- if (0 == pDev->MailBoxInfo.GMboxAddress) {
- break;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,(" GMBOX Advertised: Address:0x%X , size:%d \n",
- pDev->MailBoxInfo.GMboxAddress, pDev->MailBoxInfo.GMboxSize));
-
- status = DevGMboxIRQAction(pDev, GMBOX_DISABLE_ALL, PROC_IO_SYNC);
-
- if (status) {
- break;
- }
-
- /* write to mailbox look ahead mux control register, we want the
- * GMBOX lookaheads to appear on lookaheads 2 and 3
- * the register is 1-byte wide so we need to hit it 4 times to align the operation
- * to 4-bytes */
- muxControl[0] = GMBOX_LA_MUX_OVERRIDE_2_3;
- muxControl[1] = GMBOX_LA_MUX_OVERRIDE_2_3;
- muxControl[2] = GMBOX_LA_MUX_OVERRIDE_2_3;
- muxControl[3] = GMBOX_LA_MUX_OVERRIDE_2_3;
-
- status = HIFReadWrite(pDev->HIFDevice,
- GMBOX_LOOKAHEAD_MUX_REG,
- muxControl,
- sizeof(muxControl),
- HIF_WR_SYNC_BYTE_FIX, /* hit this register 4 times */
- NULL);
-
- if (status) {
- break;
- }
-
- status = GMboxProtocolInstall(pDev);
-
- if (status) {
- break;
- }
-
- pDev->GMboxEnabled = true;
-
- } while (false);
-
- return status;
-}
-
-int DevCheckGMboxInterrupts(struct ar6k_device *pDev)
-{
- int status = 0;
- u8 counter_int_status;
- int credits;
- u8 host_int_status2;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("+DevCheckGMboxInterrupts \n"));
-
- /* the caller guarantees that this is a context that allows for blocking I/O */
-
- do {
-
- host_int_status2 = pDev->IrqProcRegisters.host_int_status2 &
- pDev->GMboxControlRegisters.int_status_enable;
-
- if (host_int_status2 & GMBOX_INT_STATUS_TX_OVERFLOW) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("GMBOX : TX Overflow \n"));
- status = A_ECOMM;
- }
-
- if (host_int_status2 & GMBOX_INT_STATUS_RX_OVERFLOW) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("GMBOX : RX Overflow \n"));
- status = A_ECOMM;
- }
-
- if (status) {
- if (pDev->GMboxInfo.pTargetFailureCallback != NULL) {
- pDev->GMboxInfo.pTargetFailureCallback(pDev->GMboxInfo.pProtocolContext, status);
- }
- break;
- }
-
- if (host_int_status2 & GMBOX_INT_STATUS_RX_DATA) {
- if (pDev->IrqProcRegisters.gmbox_rx_avail > 0) {
- A_ASSERT(pDev->GMboxInfo.pMessagePendingCallBack != NULL);
- status = pDev->GMboxInfo.pMessagePendingCallBack(
- pDev->GMboxInfo.pProtocolContext,
- (u8 *)&pDev->IrqProcRegisters.rx_gmbox_lookahead_alias[0],
- pDev->IrqProcRegisters.gmbox_rx_avail);
- }
- }
-
- if (status) {
- break;
- }
-
- counter_int_status = pDev->IrqProcRegisters.counter_int_status &
- pDev->IrqEnableRegisters.counter_int_status_enable;
-
- /* check if credit interrupt is pending */
- if (counter_int_status & (COUNTER_INT_STATUS_ENABLE_BIT_SET(1 << AR6K_GMBOX_CREDIT_COUNTER))) {
-
- /* do synchronous read */
- status = DevGMboxReadCreditCounter(pDev, PROC_IO_SYNC, &credits);
-
- if (status) {
- break;
- }
-
- A_ASSERT(pDev->GMboxInfo.pCreditsPendingCallback != NULL);
- status = pDev->GMboxInfo.pCreditsPendingCallback(pDev->GMboxInfo.pProtocolContext,
- credits,
- pDev->GMboxInfo.CreditCountIRQEnabled);
- }
-
- } while (false);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("-DevCheckGMboxInterrupts (%d) \n",status));
-
- return status;
-}
-
-
-int DevGMboxWrite(struct ar6k_device *pDev, struct htc_packet *pPacket, u32 WriteLength)
-{
- u32 paddedLength;
- bool sync = (pPacket->Completion == NULL) ? true : false;
- int status;
- u32 address;
-
- /* adjust the length to be a multiple of block size if appropriate */
- paddedLength = DEV_CALC_SEND_PADDED_LEN(pDev, WriteLength);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
- ("DevGMboxWrite, Padded Length: %d Mbox:0x%X (mode:%s)\n",
- WriteLength,
- pDev->MailBoxInfo.GMboxAddress,
- sync ? "SYNC" : "ASYNC"));
-
- /* last byte of packet has to hit the EOM marker */
- address = pDev->MailBoxInfo.GMboxAddress + pDev->MailBoxInfo.GMboxSize - paddedLength;
-
- status = HIFReadWrite(pDev->HIFDevice,
- address,
- pPacket->pBuffer,
- paddedLength, /* the padded length */
- sync ? HIF_WR_SYNC_BLOCK_INC : HIF_WR_ASYNC_BLOCK_INC,
- sync ? NULL : pPacket); /* pass the packet as the context to the HIF request */
-
- if (sync) {
- pPacket->Status = status;
- } else {
- if (status == A_PENDING) {
- status = 0;
- }
- }
-
- return status;
-}
-
-int DevGMboxRead(struct ar6k_device *pDev, struct htc_packet *pPacket, u32 ReadLength)
-{
-
- u32 paddedLength;
- int status;
- bool sync = (pPacket->Completion == NULL) ? true : false;
-
- /* adjust the length to be a multiple of block size if appropriate */
- paddedLength = DEV_CALC_RECV_PADDED_LEN(pDev, ReadLength);
-
- if (paddedLength > pPacket->BufferLength) {
- A_ASSERT(false);
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("DevGMboxRead, Not enough space for padlen:%d recvlen:%d bufferlen:%d \n",
- paddedLength,ReadLength,pPacket->BufferLength));
- if (pPacket->Completion != NULL) {
- COMPLETE_HTC_PACKET(pPacket,A_EINVAL);
- return 0;
- }
- return A_EINVAL;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
- ("DevGMboxRead (0x%lX : hdr:0x%X) Padded Length: %d Mbox:0x%X (mode:%s)\n",
- (unsigned long)pPacket, pPacket->PktInfo.AsRx.ExpectedHdr,
- paddedLength,
- pDev->MailBoxInfo.GMboxAddress,
- sync ? "SYNC" : "ASYNC"));
-
- status = HIFReadWrite(pDev->HIFDevice,
- pDev->MailBoxInfo.GMboxAddress,
- pPacket->pBuffer,
- paddedLength,
- sync ? HIF_RD_SYNC_BLOCK_FIX : HIF_RD_ASYNC_BLOCK_FIX,
- sync ? NULL : pPacket); /* pass the packet as the context to the HIF request */
-
- if (sync) {
- pPacket->Status = status;
- }
-
- return status;
-}
-
-
-static int ProcessCreditCounterReadBuffer(u8 *pBuffer, int Length)
-{
- int credits = 0;
-
- /* theory of how this works:
- * We read the credit decrement register multiple times on a byte-wide basis.
- * The number of times (32) aligns the I/O operation to be a multiple of 4 bytes and provides a
- * reasonable chance to acquire "all" pending credits in a single I/O operation.
- *
- * Once we obtain the filled buffer, we can walk through it looking for credit decrement transitions.
- * Each non-zero byte represents a single credit decrement (which is a credit given back to the host)
- * For example if the target provides 3 credits and added 4 more during the 32-byte read operation the following
- * pattern "could" appear:
- *
- * 0x3 0x2 0x1 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x1 0x0 0x1 0x0 0x1 0x0 ......rest zeros
- * <---------> <----------------------------->
- * \_ credits aleady there \_ target adding 4 more credits
- *
- * The total available credits would be 7, since there are 7 non-zero bytes in the buffer.
- *
- * */
-
- if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
- DebugDumpBytes(pBuffer, Length, "GMBOX Credit read buffer");
- }
-
- while (Length) {
- if (*pBuffer != 0) {
- credits++;
- }
- Length--;
- pBuffer++;
- }
-
- return credits;
-}
-
-
-/* callback when our fetch to enable/disable completes */
-static void DevGMboxReadCreditsAsyncHandler(void *Context, struct htc_packet *pPacket)
-{
- struct ar6k_device *pDev = (struct ar6k_device *)Context;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevGMboxReadCreditsAsyncHandler: (dev: 0x%lX)\n", (unsigned long)pDev));
-
- if (pPacket->Status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("Read Credit Operation failed! status:%d \n", pPacket->Status));
- } else {
- int credits = 0;
- credits = ProcessCreditCounterReadBuffer(pPacket->pBuffer, AR6K_REG_IO_BUFFER_SIZE);
- pDev->GMboxInfo.pCreditsPendingCallback(pDev->GMboxInfo.pProtocolContext,
- credits,
- pDev->GMboxInfo.CreditCountIRQEnabled);
-
-
- }
- /* free this IO packet */
- AR6KFreeIOPacket(pDev,pPacket);
- AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevGMboxReadCreditsAsyncHandler \n"));
-}
-
-int DevGMboxReadCreditCounter(struct ar6k_device *pDev, bool AsyncMode, int *pCredits)
-{
- int status = 0;
- struct htc_packet *pIOPacket = NULL;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+DevGMboxReadCreditCounter (%s) \n", AsyncMode ? "ASYNC" : "SYNC"));
-
- do {
-
- pIOPacket = AR6KAllocIOPacket(pDev);
-
- if (NULL == pIOPacket) {
- status = A_NO_MEMORY;
- A_ASSERT(false);
- break;
- }
-
- A_MEMZERO(pIOPacket->pBuffer,AR6K_REG_IO_BUFFER_SIZE);
-
- if (AsyncMode) {
- /* stick in our completion routine when the I/O operation completes */
- pIOPacket->Completion = DevGMboxReadCreditsAsyncHandler;
- pIOPacket->pContext = pDev;
- /* read registers asynchronously */
- HIFReadWrite(pDev->HIFDevice,
- AR6K_GMBOX_CREDIT_DEC_ADDRESS,
- pIOPacket->pBuffer,
- AR6K_REG_IO_BUFFER_SIZE, /* hit the register multiple times */
- HIF_RD_ASYNC_BYTE_FIX,
- pIOPacket);
- pIOPacket = NULL;
- break;
- }
-
- pIOPacket->Completion = NULL;
- /* if we get here we are doing it synchronously */
- status = HIFReadWrite(pDev->HIFDevice,
- AR6K_GMBOX_CREDIT_DEC_ADDRESS,
- pIOPacket->pBuffer,
- AR6K_REG_IO_BUFFER_SIZE,
- HIF_RD_SYNC_BYTE_FIX,
- NULL);
- } while (false);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- (" DevGMboxReadCreditCounter failed! status:%d \n", status));
- }
-
- if (pIOPacket != NULL) {
- if (!status) {
- /* sync mode processing */
- *pCredits = ProcessCreditCounterReadBuffer(pIOPacket->pBuffer, AR6K_REG_IO_BUFFER_SIZE);
- }
- AR6KFreeIOPacket(pDev,pIOPacket);
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-DevGMboxReadCreditCounter (%s) (%d) \n",
- AsyncMode ? "ASYNC" : "SYNC", status));
-
- return status;
-}
-
-int DevGMboxReadCreditSize(struct ar6k_device *pDev, int *pCreditSize)
-{
- int status;
- u8 buffer[4];
-
- status = HIFReadWrite(pDev->HIFDevice,
- AR6K_GMBOX_CREDIT_SIZE_ADDRESS,
- buffer,
- sizeof(buffer),
- HIF_RD_SYNC_BYTE_FIX, /* hit the register 4 times to align the I/O */
- NULL);
-
- if (!status) {
- if (buffer[0] == 0) {
- *pCreditSize = 256;
- } else {
- *pCreditSize = buffer[0];
- }
-
- }
-
- return status;
-}
-
-void DevNotifyGMboxTargetFailure(struct ar6k_device *pDev)
-{
- /* Target ASSERTED!!! */
- if (pDev->GMboxInfo.pTargetFailureCallback != NULL) {
- pDev->GMboxInfo.pTargetFailureCallback(pDev->GMboxInfo.pProtocolContext, A_HARDWARE);
- }
-}
-
-int DevGMboxRecvLookAheadPeek(struct ar6k_device *pDev, u8 *pLookAheadBuffer, int *pLookAheadBytes)
-{
-
- int status = 0;
- struct ar6k_irq_proc_registers procRegs;
- int maxCopy;
-
- do {
- /* on entry the caller provides the length of the lookahead buffer */
- if (*pLookAheadBytes > sizeof(procRegs.rx_gmbox_lookahead_alias)) {
- A_ASSERT(false);
- status = A_EINVAL;
- break;
- }
-
- maxCopy = *pLookAheadBytes;
- *pLookAheadBytes = 0;
- /* load the register table from the device */
- status = HIFReadWrite(pDev->HIFDevice,
- HOST_INT_STATUS_ADDRESS,
- (u8 *)&procRegs,
- AR6K_IRQ_PROC_REGS_SIZE,
- HIF_RD_SYNC_BYTE_INC,
- NULL);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("DevGMboxRecvLookAheadPeek : Failed to read register table (%d) \n",status));
- break;
- }
-
- if (procRegs.gmbox_rx_avail > 0) {
- int bytes = procRegs.gmbox_rx_avail > maxCopy ? maxCopy : procRegs.gmbox_rx_avail;
- memcpy(pLookAheadBuffer,&procRegs.rx_gmbox_lookahead_alias[0],bytes);
- *pLookAheadBytes = bytes;
- }
-
- } while (false);
-
- return status;
-}
-
-int DevGMboxSetTargetInterrupt(struct ar6k_device *pDev, int Signal, int AckTimeoutMS)
-{
- int status = 0;
- int i;
- u8 buffer[4];
-
- A_MEMZERO(buffer, sizeof(buffer));
-
- do {
-
- if (Signal >= MBOX_SIG_HCI_BRIDGE_MAX) {
- status = A_EINVAL;
- break;
- }
-
- /* set the last buffer to do the actual signal trigger */
- buffer[3] = (1 << Signal);
-
- status = HIFReadWrite(pDev->HIFDevice,
- INT_WLAN_ADDRESS,
- buffer,
- sizeof(buffer),
- HIF_WR_SYNC_BYTE_FIX, /* hit the register 4 times to align the I/O */
- NULL);
-
- if (status) {
- break;
- }
-
- } while (false);
-
-
- if (!status) {
- /* now read back the register to see if the bit cleared */
- while (AckTimeoutMS) {
- status = HIFReadWrite(pDev->HIFDevice,
- INT_WLAN_ADDRESS,
- buffer,
- sizeof(buffer),
- HIF_RD_SYNC_BYTE_FIX,
- NULL);
-
- if (status) {
- break;
- }
-
- for (i = 0; i < sizeof(buffer); i++) {
- if (buffer[i] & (1 << Signal)) {
- /* bit is still set */
- break;
- }
- }
-
- if (i >= sizeof(buffer)) {
- /* done */
- break;
- }
-
- AckTimeoutMS--;
- A_MDELAY(1);
- }
-
- if (0 == AckTimeoutMS) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("DevGMboxSetTargetInterrupt : Ack Timed-out (sig:%d) \n",Signal));
- status = A_ERROR;
- }
- }
-
- return status;
-
-}
-
-#endif //ATH_AR6K_ENABLE_GMBOX
-
-
-
-
diff --git a/drivers/staging/ath6kl/htc2/AR6000/ar6k_gmbox_hciuart.c b/drivers/staging/ath6kl/htc2/AR6000/ar6k_gmbox_hciuart.c
deleted file mode 100644
index 56a0d7143804..000000000000
--- a/drivers/staging/ath6kl/htc2/AR6000/ar6k_gmbox_hciuart.c
+++ /dev/null
@@ -1,1284 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="ar6k_prot_hciUart.c" company="Atheros">
-// Copyright (c) 2007-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Protocol module for use in bridging HCI-UART packets over the GMBOX interface
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#include "a_config.h"
-#include "athdefs.h"
-#include "a_osapi.h"
-#include "../htc_debug.h"
-#include "hif.h"
-#include "htc_packet.h"
-#include "ar6k.h"
-#include "hci_transport_api.h"
-#include "gmboxif.h"
-#include "ar6000_diag.h"
-#include "hw/apb_map.h"
-#include "hw/mbox_reg.h"
-
-#ifdef ATH_AR6K_ENABLE_GMBOX
-#define HCI_UART_COMMAND_PKT 0x01
-#define HCI_UART_ACL_PKT 0x02
-#define HCI_UART_SCO_PKT 0x03
-#define HCI_UART_EVENT_PKT 0x04
-
-#define HCI_RECV_WAIT_BUFFERS (1 << 0)
-
-#define HCI_SEND_WAIT_CREDITS (1 << 0)
-
-#define HCI_UART_BRIDGE_CREDIT_SIZE 128
-
-#define CREDIT_POLL_COUNT 256
-
-#define HCI_DELAY_PER_INTERVAL_MS 10
-#define BTON_TIMEOUT_MS 500
-#define BTOFF_TIMEOUT_MS 500
-#define BAUD_TIMEOUT_MS 1
-#define BTPWRSAV_TIMEOUT_MS 1
-
-struct gmbox_proto_hci_uart {
- struct hci_transport_config_info HCIConfig;
- bool HCIAttached;
- bool HCIStopped;
- u32 RecvStateFlags;
- u32 SendStateFlags;
- HCI_TRANSPORT_PACKET_TYPE WaitBufferType;
- struct htc_packet_queue SendQueue; /* write queue holding HCI Command and ACL packets */
- struct htc_packet_queue HCIACLRecvBuffers; /* recv queue holding buffers for incomming ACL packets */
- struct htc_packet_queue HCIEventBuffers; /* recv queue holding buffers for incomming event packets */
- struct ar6k_device *pDev;
- A_MUTEX_T HCIRxLock;
- A_MUTEX_T HCITxLock;
- int CreditsMax;
- int CreditsConsumed;
- int CreditsAvailable;
- int CreditSize;
- int CreditsCurrentSeek;
- int SendProcessCount;
-};
-
-#define LOCK_HCI_RX(t) A_MUTEX_LOCK(&(t)->HCIRxLock);
-#define UNLOCK_HCI_RX(t) A_MUTEX_UNLOCK(&(t)->HCIRxLock);
-#define LOCK_HCI_TX(t) A_MUTEX_LOCK(&(t)->HCITxLock);
-#define UNLOCK_HCI_TX(t) A_MUTEX_UNLOCK(&(t)->HCITxLock);
-
-#define DO_HCI_RECV_INDICATION(p, pt) \
-do { \
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV, \
- ("HCI: Indicate Recv on packet:0x%lX status:%d len:%d type:%d \n", \
- (unsigned long)(pt), \
- (pt)->Status, \
- !(pt)->Status ? (pt)->ActualLength : 0, \
- HCI_GET_PACKET_TYPE(pt))); \
- (p)->HCIConfig.pHCIPktRecv((p)->HCIConfig.pContext, (pt)); \
-} while (0)
-
-#define DO_HCI_SEND_INDICATION(p,pt) \
-{ AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: Indicate Send on packet:0x%lX status:%d type:%d \n", \
- (unsigned long)(pt),(pt)->Status,HCI_GET_PACKET_TYPE(pt))); \
- (p)->HCIConfig.pHCISendComplete((p)->HCIConfig.pContext, (pt)); \
-}
-
-static int HCITrySend(struct gmbox_proto_hci_uart *pProt, struct htc_packet *pPacket, bool Synchronous);
-
-static void HCIUartCleanup(struct gmbox_proto_hci_uart *pProtocol)
-{
- A_ASSERT(pProtocol != NULL);
-
- A_MUTEX_DELETE(&pProtocol->HCIRxLock);
- A_MUTEX_DELETE(&pProtocol->HCITxLock);
-
- kfree(pProtocol);
-}
-
-static int InitTxCreditState(struct gmbox_proto_hci_uart *pProt)
-{
- int status;
- int credits;
- int creditPollCount = CREDIT_POLL_COUNT;
- bool gotCredits = false;
-
- pProt->CreditsConsumed = 0;
-
- do {
-
- if (pProt->CreditsMax != 0) {
- /* we can only call this only once per target reset */
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HCI: InitTxCreditState - already called! \n"));
- A_ASSERT(false);
- status = A_EINVAL;
- break;
- }
-
- /* read the credit counter. At startup the target will set the credit counter
- * to the max available, we read this in a loop because it may take
- * multiple credit counter reads to get all credits */
-
- while (creditPollCount) {
-
- credits = 0;
-
- status = DevGMboxReadCreditCounter(pProt->pDev, PROC_IO_SYNC, &credits);
-
- if (status) {
- break;
- }
-
- if (!gotCredits && (0 == credits)) {
- creditPollCount--;
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: credit is 0, retrying (%d) \n",creditPollCount));
- A_MDELAY(HCI_DELAY_PER_INTERVAL_MS);
- continue;
- } else {
- gotCredits = true;
- }
-
- if (0 == credits) {
- break;
- }
-
- pProt->CreditsMax += credits;
- }
-
- if (status) {
- break;
- }
-
- if (0 == creditPollCount) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("** HCI : Failed to get credits! GMBOX Target was not available \n"));
- status = A_ERROR;
- break;
- }
-
- /* now get the size */
- status = DevGMboxReadCreditSize(pProt->pDev, &pProt->CreditSize);
-
- if (status) {
- break;
- }
-
- } while (false);
-
- if (!status) {
- pProt->CreditsAvailable = pProt->CreditsMax;
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("HCI : InitTxCreditState - credits avail: %d, size: %d \n",
- pProt->CreditsAvailable, pProt->CreditSize));
- }
-
- return status;
-}
-
-static int CreditsAvailableCallback(void *pContext, int Credits, bool CreditIRQEnabled)
-{
- struct gmbox_proto_hci_uart *pProt = (struct gmbox_proto_hci_uart *)pContext;
- bool enableCreditIrq = false;
- bool disableCreditIrq = false;
- bool doPendingSends = false;
- int status = 0;
-
- /** this callback is called under 2 conditions:
- * 1. The credit IRQ interrupt was enabled and signaled.
- * 2. A credit counter read completed.
- *
- * The function must not assume that the calling context can block !
- */
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+CreditsAvailableCallback (Credits:%d, IRQ:%s) \n",
- Credits, CreditIRQEnabled ? "ON" : "OFF"));
-
- LOCK_HCI_TX(pProt);
-
- do {
-
- if (0 == Credits) {
- if (!CreditIRQEnabled) {
- /* enable credit IRQ */
- enableCreditIrq = true;
- }
- break;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: current credit state, consumed:%d available:%d max:%d seek:%d\n",
- pProt->CreditsConsumed,
- pProt->CreditsAvailable,
- pProt->CreditsMax,
- pProt->CreditsCurrentSeek));
-
- pProt->CreditsAvailable += Credits;
- A_ASSERT(pProt->CreditsAvailable <= pProt->CreditsMax);
- pProt->CreditsConsumed -= Credits;
- A_ASSERT(pProt->CreditsConsumed >= 0);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: new credit state, consumed:%d available:%d max:%d seek:%d\n",
- pProt->CreditsConsumed,
- pProt->CreditsAvailable,
- pProt->CreditsMax,
- pProt->CreditsCurrentSeek));
-
- if (pProt->CreditsAvailable >= pProt->CreditsCurrentSeek) {
- /* we have enough credits to fulfill at least 1 packet waiting in the queue */
- pProt->CreditsCurrentSeek = 0;
- pProt->SendStateFlags &= ~HCI_SEND_WAIT_CREDITS;
- doPendingSends = true;
- if (CreditIRQEnabled) {
- /* credit IRQ was enabled, we shouldn't need it anymore */
- disableCreditIrq = true;
- }
- } else {
- /* not enough credits yet, enable credit IRQ if we haven't already */
- if (!CreditIRQEnabled) {
- enableCreditIrq = true;
- }
- }
-
- } while (false);
-
- UNLOCK_HCI_TX(pProt);
-
- if (enableCreditIrq) {
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,(" Enabling credit count IRQ...\n"));
- /* must use async only */
- status = DevGMboxIRQAction(pProt->pDev, GMBOX_CREDIT_IRQ_ENABLE, PROC_IO_ASYNC);
- } else if (disableCreditIrq) {
- /* must use async only */
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,(" Disabling credit count IRQ...\n"));
- status = DevGMboxIRQAction(pProt->pDev, GMBOX_CREDIT_IRQ_DISABLE, PROC_IO_ASYNC);
- }
-
- if (doPendingSends) {
- HCITrySend(pProt, NULL, false);
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+CreditsAvailableCallback \n"));
- return status;
-}
-
-static INLINE void NotifyTransportFailure(struct gmbox_proto_hci_uart *pProt, int status)
-{
- if (pProt->HCIConfig.TransportFailure != NULL) {
- pProt->HCIConfig.TransportFailure(pProt->HCIConfig.pContext, status);
- }
-}
-
-static void FailureCallback(void *pContext, int Status)
-{
- struct gmbox_proto_hci_uart *pProt = (struct gmbox_proto_hci_uart *)pContext;
-
- /* target assertion occurred */
- NotifyTransportFailure(pProt, Status);
-}
-
-static void StateDumpCallback(void *pContext)
-{
- struct gmbox_proto_hci_uart *pProt = (struct gmbox_proto_hci_uart *)pContext;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("============ HCIUart State ======================\n"));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("RecvStateFlags : 0x%X \n",pProt->RecvStateFlags));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("SendStateFlags : 0x%X \n",pProt->SendStateFlags));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("WaitBufferType : %d \n",pProt->WaitBufferType));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("SendQueue Depth : %d \n",HTC_PACKET_QUEUE_DEPTH(&pProt->SendQueue)));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("CreditsMax : %d \n",pProt->CreditsMax));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("CreditsConsumed : %d \n",pProt->CreditsConsumed));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("CreditsAvailable : %d \n",pProt->CreditsAvailable));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("==================================================\n"));
-}
-
-static int HCIUartMessagePending(void *pContext, u8 LookAheadBytes[], int ValidBytes)
-{
- struct gmbox_proto_hci_uart *pProt = (struct gmbox_proto_hci_uart *)pContext;
- int status = 0;
- int totalRecvLength = 0;
- HCI_TRANSPORT_PACKET_TYPE pktType = HCI_PACKET_INVALID;
- bool recvRefillCalled = false;
- bool blockRecv = false;
- struct htc_packet *pPacket = NULL;
-
- /** caller guarantees that this is a fully block-able context (synch I/O is allowed) */
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HCIUartMessagePending Lookahead Bytes:%d \n",ValidBytes));
-
- LOCK_HCI_RX(pProt);
-
- do {
-
- if (ValidBytes < 3) {
- /* not enough for ACL or event header */
- break;
- }
-
- if ((LookAheadBytes[0] == HCI_UART_ACL_PKT) && (ValidBytes < 5)) {
- /* not enough for ACL data header */
- break;
- }
-
- switch (LookAheadBytes[0]) {
- case HCI_UART_EVENT_PKT:
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("HCI Event: %d param length: %d \n",
- LookAheadBytes[1], LookAheadBytes[2]));
- totalRecvLength = LookAheadBytes[2];
- totalRecvLength += 3; /* add type + event code + length field */
- pktType = HCI_EVENT_TYPE;
- break;
- case HCI_UART_ACL_PKT:
- totalRecvLength = (LookAheadBytes[4] << 8) | LookAheadBytes[3];
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("HCI ACL: conn:0x%X length: %d \n",
- ((LookAheadBytes[2] & 0xF0) << 8) | LookAheadBytes[1], totalRecvLength));
- totalRecvLength += 5; /* add type + connection handle + length field */
- pktType = HCI_ACL_TYPE;
- break;
- default:
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("**Invalid HCI packet type: %d \n",LookAheadBytes[0]));
- status = A_EPROTO;
- break;
- }
-
- if (status) {
- break;
- }
-
- if (pProt->HCIConfig.pHCIPktRecvAlloc != NULL) {
- UNLOCK_HCI_RX(pProt);
- /* user is using a per-packet allocation callback */
- pPacket = pProt->HCIConfig.pHCIPktRecvAlloc(pProt->HCIConfig.pContext,
- pktType,
- totalRecvLength);
- LOCK_HCI_RX(pProt);
-
- } else {
- struct htc_packet_queue *pQueue;
- /* user is using a refill handler that can refill multiple HTC buffers */
-
- /* select buffer queue */
- if (pktType == HCI_ACL_TYPE) {
- pQueue = &pProt->HCIACLRecvBuffers;
- } else {
- pQueue = &pProt->HCIEventBuffers;
- }
-
- if (HTC_QUEUE_EMPTY(pQueue)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
- ("** HCI pkt type: %d has no buffers available calling allocation handler \n",
- pktType));
- /* check for refill handler */
- if (pProt->HCIConfig.pHCIPktRecvRefill != NULL) {
- recvRefillCalled = true;
- UNLOCK_HCI_RX(pProt);
- /* call the re-fill handler */
- pProt->HCIConfig.pHCIPktRecvRefill(pProt->HCIConfig.pContext,
- pktType,
- 0);
- LOCK_HCI_RX(pProt);
- /* check if we have more buffers */
- pPacket = HTC_PACKET_DEQUEUE(pQueue);
- /* fall through */
- }
- } else {
- pPacket = HTC_PACKET_DEQUEUE(pQueue);
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
- ("HCI pkt type: %d now has %d recv buffers left \n",
- pktType, HTC_PACKET_QUEUE_DEPTH(pQueue)));
- }
- }
-
- if (NULL == pPacket) {
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
- ("** HCI pkt type: %d has no buffers available stopping recv...\n", pktType));
- /* this is not an error, we simply need to mark that we are waiting for buffers.*/
- pProt->RecvStateFlags |= HCI_RECV_WAIT_BUFFERS;
- pProt->WaitBufferType = pktType;
- blockRecv = true;
- break;
- }
-
- if (totalRecvLength > (int)pPacket->BufferLength) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("** HCI-UART pkt: %d requires %d bytes (%d buffer bytes avail) ! \n",
- LookAheadBytes[0], totalRecvLength, pPacket->BufferLength));
- status = A_EINVAL;
- break;
- }
-
- } while (false);
-
- UNLOCK_HCI_RX(pProt);
-
- /* locks are released, we can go fetch the packet */
-
- do {
-
- if (status || (NULL == pPacket)) {
- break;
- }
-
- /* do this synchronously, we don't need to be fast here */
- pPacket->Completion = NULL;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("HCI : getting recv packet len:%d hci-uart-type: %s \n",
- totalRecvLength, (LookAheadBytes[0] == HCI_UART_EVENT_PKT) ? "EVENT" : "ACL"));
-
- status = DevGMboxRead(pProt->pDev, pPacket, totalRecvLength);
-
- if (status) {
- break;
- }
-
- if (pPacket->pBuffer[0] != LookAheadBytes[0]) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("** HCI buffer does not contain expected packet type: %d ! \n",
- pPacket->pBuffer[0]));
- status = A_EPROTO;
- break;
- }
-
- if (pPacket->pBuffer[0] == HCI_UART_EVENT_PKT) {
- /* validate event header fields */
- if ((pPacket->pBuffer[1] != LookAheadBytes[1]) ||
- (pPacket->pBuffer[2] != LookAheadBytes[2])) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("** HCI buffer does not match lookahead! \n"));
- DebugDumpBytes(LookAheadBytes, 3, "Expected HCI-UART Header");
- DebugDumpBytes(pPacket->pBuffer, 3, "** Bad HCI-UART Header");
- status = A_EPROTO;
- break;
- }
- } else if (pPacket->pBuffer[0] == HCI_UART_ACL_PKT) {
- /* validate acl header fields */
- if ((pPacket->pBuffer[1] != LookAheadBytes[1]) ||
- (pPacket->pBuffer[2] != LookAheadBytes[2]) ||
- (pPacket->pBuffer[3] != LookAheadBytes[3]) ||
- (pPacket->pBuffer[4] != LookAheadBytes[4])) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("** HCI buffer does not match lookahead! \n"));
- DebugDumpBytes(LookAheadBytes, 5, "Expected HCI-UART Header");
- DebugDumpBytes(pPacket->pBuffer, 5, "** Bad HCI-UART Header");
- status = A_EPROTO;
- break;
- }
- }
-
- /* adjust buffer to move past packet ID */
- pPacket->pBuffer++;
- pPacket->ActualLength = totalRecvLength - 1;
- pPacket->Status = 0;
- /* indicate packet */
- DO_HCI_RECV_INDICATION(pProt,pPacket);
- pPacket = NULL;
-
- /* check if we need to refill recv buffers */
- if ((pProt->HCIConfig.pHCIPktRecvRefill != NULL) && !recvRefillCalled) {
- struct htc_packet_queue *pQueue;
- int watermark;
-
- if (pktType == HCI_ACL_TYPE) {
- watermark = pProt->HCIConfig.ACLRecvBufferWaterMark;
- pQueue = &pProt->HCIACLRecvBuffers;
- } else {
- watermark = pProt->HCIConfig.EventRecvBufferWaterMark;
- pQueue = &pProt->HCIEventBuffers;
- }
-
- if (HTC_PACKET_QUEUE_DEPTH(pQueue) < watermark) {
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
- ("** HCI pkt type: %d watermark hit (%d) current:%d \n",
- pktType, watermark, HTC_PACKET_QUEUE_DEPTH(pQueue)));
- /* call the re-fill handler */
- pProt->HCIConfig.pHCIPktRecvRefill(pProt->HCIConfig.pContext,
- pktType,
- HTC_PACKET_QUEUE_DEPTH(pQueue));
- }
- }
-
- } while (false);
-
- /* check if we need to disable the receiver */
- if (status || blockRecv) {
- DevGMboxIRQAction(pProt->pDev, GMBOX_RECV_IRQ_DISABLE, PROC_IO_SYNC);
- }
-
- /* see if we need to recycle the recv buffer */
- if (status && (pPacket != NULL)) {
- struct htc_packet_queue queue;
-
- if (A_EPROTO == status) {
- DebugDumpBytes(pPacket->pBuffer, totalRecvLength, "Bad HCI-UART Recv packet");
- }
- /* recycle packet */
- HTC_PACKET_RESET_RX(pPacket);
- INIT_HTC_PACKET_QUEUE_AND_ADD(&queue,pPacket);
- HCI_TransportAddReceivePkts(pProt,&queue);
- NotifyTransportFailure(pProt,status);
- }
-
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HCIUartMessagePending \n"));
-
- return status;
-}
-
-static void HCISendPacketCompletion(void *Context, struct htc_packet *pPacket)
-{
- struct gmbox_proto_hci_uart *pProt = (struct gmbox_proto_hci_uart *)Context;
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HCISendPacketCompletion (pPacket:0x%lX) \n",(unsigned long)pPacket));
-
- if (pPacket->Status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" Send Packet (0x%lX) failed: %d , len:%d \n",
- (unsigned long)pPacket, pPacket->Status, pPacket->ActualLength));
- }
-
- DO_HCI_SEND_INDICATION(pProt,pPacket);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HCISendPacketCompletion \n"));
-}
-
-static int SeekCreditsSynch(struct gmbox_proto_hci_uart *pProt)
-{
- int status = 0;
- int credits;
- int retry = 100;
-
- while (true) {
- credits = 0;
- status = DevGMboxReadCreditCounter(pProt->pDev, PROC_IO_SYNC, &credits);
- if (status) {
- break;
- }
- LOCK_HCI_TX(pProt);
- pProt->CreditsAvailable += credits;
- pProt->CreditsConsumed -= credits;
- if (pProt->CreditsAvailable >= pProt->CreditsCurrentSeek) {
- pProt->CreditsCurrentSeek = 0;
- UNLOCK_HCI_TX(pProt);
- break;
- }
- UNLOCK_HCI_TX(pProt);
- retry--;
- if (0 == retry) {
- status = A_EBUSY;
- break;
- }
- A_MDELAY(20);
- }
-
- return status;
-}
-
-static int HCITrySend(struct gmbox_proto_hci_uart *pProt, struct htc_packet *pPacket, bool Synchronous)
-{
- int status = 0;
- int transferLength;
- int creditsRequired, remainder;
- u8 hciUartType;
- bool synchSendComplete = false;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HCITrySend (pPacket:0x%lX) %s \n",(unsigned long)pPacket,
- Synchronous ? "SYNC" :"ASYNC"));
-
- LOCK_HCI_TX(pProt);
-
- /* increment write processing count on entry */
- pProt->SendProcessCount++;
-
- do {
-
- if (pProt->HCIStopped) {
- status = A_ECANCELED;
- break;
- }
-
- if (pPacket != NULL) {
- /* packet was supplied */
- if (Synchronous) {
- /* in synchronous mode, the send queue can only hold 1 packet */
- if (!HTC_QUEUE_EMPTY(&pProt->SendQueue)) {
- status = A_EBUSY;
- A_ASSERT(false);
- break;
- }
-
- if (pProt->SendProcessCount > 1) {
- /* another thread or task is draining the TX queues */
- status = A_EBUSY;
- A_ASSERT(false);
- break;
- }
-
- HTC_PACKET_ENQUEUE(&pProt->SendQueue,pPacket);
-
- } else {
- /* see if adding this packet hits the max depth (asynchronous mode only) */
- if ((pProt->HCIConfig.MaxSendQueueDepth > 0) &&
- ((HTC_PACKET_QUEUE_DEPTH(&pProt->SendQueue) + 1) >= pProt->HCIConfig.MaxSendQueueDepth)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("HCI Send queue is full, Depth:%d, Max:%d \n",
- HTC_PACKET_QUEUE_DEPTH(&pProt->SendQueue),
- pProt->HCIConfig.MaxSendQueueDepth));
- /* queue will be full, invoke any callbacks to determine what action to take */
- if (pProt->HCIConfig.pHCISendFull != NULL) {
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
- ("HCI : Calling driver's send full callback.... \n"));
- if (pProt->HCIConfig.pHCISendFull(pProt->HCIConfig.pContext,
- pPacket) == HCI_SEND_FULL_DROP) {
- /* drop it */
- status = A_NO_RESOURCE;
- break;
- }
- }
- }
-
- HTC_PACKET_ENQUEUE(&pProt->SendQueue,pPacket);
- }
-
- }
-
- if (pProt->SendStateFlags & HCI_SEND_WAIT_CREDITS) {
- break;
- }
-
- if (pProt->SendProcessCount > 1) {
- /* another thread or task is draining the TX queues */
- break;
- }
-
- /***** beyond this point only 1 thread may enter ******/
-
- /* now drain the send queue for transmission as long as we have enough
- * credits */
- while (!HTC_QUEUE_EMPTY(&pProt->SendQueue)) {
-
- pPacket = HTC_PACKET_DEQUEUE(&pProt->SendQueue);
-
- switch (HCI_GET_PACKET_TYPE(pPacket)) {
- case HCI_COMMAND_TYPE:
- hciUartType = HCI_UART_COMMAND_PKT;
- break;
- case HCI_ACL_TYPE:
- hciUartType = HCI_UART_ACL_PKT;
- break;
- default:
- status = A_EINVAL;
- A_ASSERT(false);
- break;
- }
-
- if (status) {
- break;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: Got head packet:0x%lX , Type:%d Length: %d Remaining Queue Depth: %d\n",
- (unsigned long)pPacket, HCI_GET_PACKET_TYPE(pPacket), pPacket->ActualLength,
- HTC_PACKET_QUEUE_DEPTH(&pProt->SendQueue)));
-
- transferLength = 1; /* UART type header is 1 byte */
- transferLength += pPacket->ActualLength;
- transferLength = DEV_CALC_SEND_PADDED_LEN(pProt->pDev, transferLength);
-
- /* figure out how many credits this message requires */
- creditsRequired = transferLength / pProt->CreditSize;
- remainder = transferLength % pProt->CreditSize;
-
- if (remainder) {
- creditsRequired++;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: Creds Required:%d Got:%d\n",
- creditsRequired, pProt->CreditsAvailable));
-
- if (creditsRequired > pProt->CreditsAvailable) {
- if (Synchronous) {
- /* in synchronous mode we need to seek credits in synchronously */
- pProt->CreditsCurrentSeek = creditsRequired;
- UNLOCK_HCI_TX(pProt);
- status = SeekCreditsSynch(pProt);
- LOCK_HCI_TX(pProt);
- if (status) {
- break;
- }
- /* fall through and continue processing this send op */
- } else {
- /* not enough credits, queue back to the head */
- HTC_PACKET_ENQUEUE_TO_HEAD(&pProt->SendQueue,pPacket);
- /* waiting for credits */
- pProt->SendStateFlags |= HCI_SEND_WAIT_CREDITS;
- /* provide a hint to reduce attempts to re-send if credits are dribbling back
- * this hint is the short fall of credits */
- pProt->CreditsCurrentSeek = creditsRequired;
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: packet:0x%lX placed back in queue. head packet needs: %d credits \n",
- (unsigned long)pPacket, pProt->CreditsCurrentSeek));
- pPacket = NULL;
- UNLOCK_HCI_TX(pProt);
-
- /* schedule a credit counter read, our CreditsAvailableCallback callback will be called
- * with the result */
- DevGMboxReadCreditCounter(pProt->pDev, PROC_IO_ASYNC, NULL);
-
- LOCK_HCI_TX(pProt);
- break;
- }
- }
-
- /* caller guarantees some head room */
- pPacket->pBuffer--;
- pPacket->pBuffer[0] = hciUartType;
-
- pProt->CreditsAvailable -= creditsRequired;
- pProt->CreditsConsumed += creditsRequired;
- A_ASSERT(pProt->CreditsConsumed <= pProt->CreditsMax);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: new credit state: consumed:%d available:%d max:%d\n",
- pProt->CreditsConsumed, pProt->CreditsAvailable, pProt->CreditsMax));
-
- UNLOCK_HCI_TX(pProt);
-
- /* write it out */
- if (Synchronous) {
- pPacket->Completion = NULL;
- pPacket->pContext = NULL;
- } else {
- pPacket->Completion = HCISendPacketCompletion;
- pPacket->pContext = pProt;
- }
-
- status = DevGMboxWrite(pProt->pDev,pPacket,transferLength);
- if (Synchronous) {
- synchSendComplete = true;
- } else {
- pPacket = NULL;
- }
-
- LOCK_HCI_TX(pProt);
-
- }
-
- } while (false);
-
- pProt->SendProcessCount--;
- A_ASSERT(pProt->SendProcessCount >= 0);
- UNLOCK_HCI_TX(pProt);
-
- if (Synchronous) {
- A_ASSERT(pPacket != NULL);
- if (!status && (!synchSendComplete)) {
- status = A_EBUSY;
- A_ASSERT(false);
- LOCK_HCI_TX(pProt);
- if (pPacket->ListLink.pNext != NULL) {
- /* remove from the queue */
- HTC_PACKET_REMOVE(&pProt->SendQueue,pPacket);
- }
- UNLOCK_HCI_TX(pProt);
- }
- } else {
- if (status && (pPacket != NULL)) {
- pPacket->Status = status;
- DO_HCI_SEND_INDICATION(pProt,pPacket);
- }
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HCITrySend: \n"));
- return status;
-}
-
-static void FlushSendQueue(struct gmbox_proto_hci_uart *pProt)
-{
- struct htc_packet *pPacket;
- struct htc_packet_queue discardQueue;
-
- INIT_HTC_PACKET_QUEUE(&discardQueue);
-
- LOCK_HCI_TX(pProt);
-
- if (!HTC_QUEUE_EMPTY(&pProt->SendQueue)) {
- HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&discardQueue,&pProt->SendQueue);
- }
-
- UNLOCK_HCI_TX(pProt);
-
- /* discard packets */
- while (!HTC_QUEUE_EMPTY(&discardQueue)) {
- pPacket = HTC_PACKET_DEQUEUE(&discardQueue);
- pPacket->Status = A_ECANCELED;
- DO_HCI_SEND_INDICATION(pProt,pPacket);
- }
-
-}
-
-static void FlushRecvBuffers(struct gmbox_proto_hci_uart *pProt)
-{
- struct htc_packet_queue discardQueue;
- struct htc_packet *pPacket;
-
- INIT_HTC_PACKET_QUEUE(&discardQueue);
-
- LOCK_HCI_RX(pProt);
- /*transfer list items from ACL and event buffer queues to the discard queue */
- if (!HTC_QUEUE_EMPTY(&pProt->HCIACLRecvBuffers)) {
- HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&discardQueue,&pProt->HCIACLRecvBuffers);
- }
- if (!HTC_QUEUE_EMPTY(&pProt->HCIEventBuffers)) {
- HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&discardQueue,&pProt->HCIEventBuffers);
- }
- UNLOCK_HCI_RX(pProt);
-
- /* now empty the discard queue */
- while (!HTC_QUEUE_EMPTY(&discardQueue)) {
- pPacket = HTC_PACKET_DEQUEUE(&discardQueue);
- pPacket->Status = A_ECANCELED;
- DO_HCI_RECV_INDICATION(pProt,pPacket);
- }
-
-}
-
-/*** protocol module install entry point ***/
-
-int GMboxProtocolInstall(struct ar6k_device *pDev)
-{
- int status = 0;
- struct gmbox_proto_hci_uart *pProtocol = NULL;
-
- do {
-
- pProtocol = A_MALLOC(sizeof(struct gmbox_proto_hci_uart));
-
- if (NULL == pProtocol) {
- status = A_NO_MEMORY;
- break;
- }
-
- A_MEMZERO(pProtocol, sizeof(*pProtocol));
- pProtocol->pDev = pDev;
- INIT_HTC_PACKET_QUEUE(&pProtocol->SendQueue);
- INIT_HTC_PACKET_QUEUE(&pProtocol->HCIACLRecvBuffers);
- INIT_HTC_PACKET_QUEUE(&pProtocol->HCIEventBuffers);
- A_MUTEX_INIT(&pProtocol->HCIRxLock);
- A_MUTEX_INIT(&pProtocol->HCITxLock);
-
- } while (false);
-
- if (!status) {
- LOCK_AR6K(pDev);
- DEV_GMBOX_SET_PROTOCOL(pDev,
- HCIUartMessagePending,
- CreditsAvailableCallback,
- FailureCallback,
- StateDumpCallback,
- pProtocol);
- UNLOCK_AR6K(pDev);
- } else {
- if (pProtocol != NULL) {
- HCIUartCleanup(pProtocol);
- }
- }
-
- return status;
-}
-
-/*** protocol module uninstall entry point ***/
-void GMboxProtocolUninstall(struct ar6k_device *pDev)
-{
- struct gmbox_proto_hci_uart *pProtocol = (struct gmbox_proto_hci_uart *)DEV_GMBOX_GET_PROTOCOL(pDev);
-
- if (pProtocol != NULL) {
-
- /* notify anyone attached */
- if (pProtocol->HCIAttached) {
- A_ASSERT(pProtocol->HCIConfig.TransportRemoved != NULL);
- pProtocol->HCIConfig.TransportRemoved(pProtocol->HCIConfig.pContext);
- pProtocol->HCIAttached = false;
- }
-
- HCIUartCleanup(pProtocol);
- DEV_GMBOX_SET_PROTOCOL(pDev,NULL,NULL,NULL,NULL,NULL);
- }
-
-}
-
-static int NotifyTransportReady(struct gmbox_proto_hci_uart *pProt)
-{
- struct hci_transport_properties props;
- int status = 0;
-
- do {
-
- A_MEMZERO(&props,sizeof(props));
-
- /* HCI UART only needs one extra byte at the head to indicate the packet TYPE */
- props.HeadRoom = 1;
- props.TailRoom = 0;
- props.IOBlockPad = pProt->pDev->BlockSize;
- if (pProt->HCIAttached) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("HCI: notifying attached client to transport... \n"));
- A_ASSERT(pProt->HCIConfig.TransportReady != NULL);
- status = pProt->HCIConfig.TransportReady(pProt,
- &props,
- pProt->HCIConfig.pContext);
- }
-
- } while (false);
-
- return status;
-}
-
-/*********** HCI UART protocol implementation ************************************************/
-
-HCI_TRANSPORT_HANDLE HCI_TransportAttach(void *HTCHandle, struct hci_transport_config_info *pInfo)
-{
- struct gmbox_proto_hci_uart *pProtocol = NULL;
- struct ar6k_device *pDev;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("+HCI_TransportAttach \n"));
-
- pDev = HTCGetAR6KDevice(HTCHandle);
-
- LOCK_AR6K(pDev);
-
- do {
-
- pProtocol = (struct gmbox_proto_hci_uart *)DEV_GMBOX_GET_PROTOCOL(pDev);
-
- if (NULL == pProtocol) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("GMBOX protocol not installed! \n"));
- break;
- }
-
- if (pProtocol->HCIAttached) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("GMBOX protocol already attached! \n"));
- break;
- }
-
- memcpy(&pProtocol->HCIConfig, pInfo, sizeof(struct hci_transport_config_info));
-
- A_ASSERT(pProtocol->HCIConfig.pHCIPktRecv != NULL);
- A_ASSERT(pProtocol->HCIConfig.pHCISendComplete != NULL);
-
- pProtocol->HCIAttached = true;
-
- } while (false);
-
- UNLOCK_AR6K(pDev);
-
- if (pProtocol != NULL) {
- /* TODO ... should we use a worker? */
- NotifyTransportReady(pProtocol);
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("-HCI_TransportAttach (0x%lX) \n",(unsigned long)pProtocol));
- return (HCI_TRANSPORT_HANDLE)pProtocol;
-}
-
-void HCI_TransportDetach(HCI_TRANSPORT_HANDLE HciTrans)
-{
- struct gmbox_proto_hci_uart *pProtocol = (struct gmbox_proto_hci_uart *)HciTrans;
- struct ar6k_device *pDev = pProtocol->pDev;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("+HCI_TransportDetach \n"));
-
- LOCK_AR6K(pDev);
- if (!pProtocol->HCIAttached) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("GMBOX protocol not attached! \n"));
- UNLOCK_AR6K(pDev);
- return;
- }
- pProtocol->HCIAttached = false;
- UNLOCK_AR6K(pDev);
-
- HCI_TransportStop(HciTrans);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("-HCI_TransportAttach \n"));
-}
-
-int HCI_TransportAddReceivePkts(HCI_TRANSPORT_HANDLE HciTrans, struct htc_packet_queue *pQueue)
-{
- struct gmbox_proto_hci_uart *pProt = (struct gmbox_proto_hci_uart *)HciTrans;
- int status = 0;
- bool unblockRecv = false;
- struct htc_packet *pPacket;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HCI_TransportAddReceivePkt \n"));
-
- LOCK_HCI_RX(pProt);
-
- do {
-
- if (pProt->HCIStopped) {
- status = A_ECANCELED;
- break;
- }
-
- pPacket = HTC_GET_PKT_AT_HEAD(pQueue);
-
- if (NULL == pPacket) {
- status = A_EINVAL;
- break;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,(" HCI recv packet added, type :%d, len:%d num:%d \n",
- HCI_GET_PACKET_TYPE(pPacket), pPacket->BufferLength, HTC_PACKET_QUEUE_DEPTH(pQueue)));
-
- if (HCI_GET_PACKET_TYPE(pPacket) == HCI_EVENT_TYPE) {
- HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pProt->HCIEventBuffers, pQueue);
- } else if (HCI_GET_PACKET_TYPE(pPacket) == HCI_ACL_TYPE) {
- HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pProt->HCIACLRecvBuffers, pQueue);
- } else {
- status = A_EINVAL;
- break;
- }
-
- if (pProt->RecvStateFlags & HCI_RECV_WAIT_BUFFERS) {
- if (pProt->WaitBufferType == HCI_GET_PACKET_TYPE(pPacket)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,(" HCI recv was blocked on packet type :%d, unblocking.. \n",
- pProt->WaitBufferType));
- pProt->RecvStateFlags &= ~HCI_RECV_WAIT_BUFFERS;
- pProt->WaitBufferType = HCI_PACKET_INVALID;
- unblockRecv = true;
- }
- }
-
- } while (false);
-
- UNLOCK_HCI_RX(pProt);
-
- if (status) {
- while (!HTC_QUEUE_EMPTY(pQueue)) {
- pPacket = HTC_PACKET_DEQUEUE(pQueue);
- pPacket->Status = A_ECANCELED;
- DO_HCI_RECV_INDICATION(pProt,pPacket);
- }
- }
-
- if (unblockRecv) {
- DevGMboxIRQAction(pProt->pDev, GMBOX_RECV_IRQ_ENABLE, PROC_IO_ASYNC);
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HCI_TransportAddReceivePkt \n"));
-
- return 0;
-}
-
-int HCI_TransportSendPkt(HCI_TRANSPORT_HANDLE HciTrans, struct htc_packet *pPacket, bool Synchronous)
-{
- struct gmbox_proto_hci_uart *pProt = (struct gmbox_proto_hci_uart *)HciTrans;
-
- return HCITrySend(pProt,pPacket,Synchronous);
-}
-
-void HCI_TransportStop(HCI_TRANSPORT_HANDLE HciTrans)
-{
- struct gmbox_proto_hci_uart *pProt = (struct gmbox_proto_hci_uart *)HciTrans;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("+HCI_TransportStop \n"));
-
- LOCK_AR6K(pProt->pDev);
- if (pProt->HCIStopped) {
- UNLOCK_AR6K(pProt->pDev);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("-HCI_TransportStop \n"));
- return;
- }
- pProt->HCIStopped = true;
- UNLOCK_AR6K(pProt->pDev);
-
- /* disable interrupts */
- DevGMboxIRQAction(pProt->pDev, GMBOX_DISABLE_ALL, PROC_IO_SYNC);
- FlushSendQueue(pProt);
- FlushRecvBuffers(pProt);
-
- /* signal bridge side to power down BT */
- DevGMboxSetTargetInterrupt(pProt->pDev, MBOX_SIG_HCI_BRIDGE_BT_OFF, BTOFF_TIMEOUT_MS);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("-HCI_TransportStop \n"));
-}
-
-int HCI_TransportStart(HCI_TRANSPORT_HANDLE HciTrans)
-{
- int status;
- struct gmbox_proto_hci_uart *pProt = (struct gmbox_proto_hci_uart *)HciTrans;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("+HCI_TransportStart \n"));
-
- /* set stopped in case we have a problem in starting */
- pProt->HCIStopped = true;
-
- do {
-
- status = InitTxCreditState(pProt);
-
- if (status) {
- break;
- }
-
- status = DevGMboxIRQAction(pProt->pDev, GMBOX_ERRORS_IRQ_ENABLE, PROC_IO_SYNC);
-
- if (status) {
- break;
- }
- /* enable recv */
- status = DevGMboxIRQAction(pProt->pDev, GMBOX_RECV_IRQ_ENABLE, PROC_IO_SYNC);
-
- if (status) {
- break;
- }
- /* signal bridge side to power up BT */
- status = DevGMboxSetTargetInterrupt(pProt->pDev, MBOX_SIG_HCI_BRIDGE_BT_ON, BTON_TIMEOUT_MS);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HCI_TransportStart : Failed to trigger BT ON \n"));
- break;
- }
-
- /* we made it */
- pProt->HCIStopped = false;
-
- } while (false);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("-HCI_TransportStart \n"));
-
- return status;
-}
-
-int HCI_TransportEnableDisableAsyncRecv(HCI_TRANSPORT_HANDLE HciTrans, bool Enable)
-{
- struct gmbox_proto_hci_uart *pProt = (struct gmbox_proto_hci_uart *)HciTrans;
- return DevGMboxIRQAction(pProt->pDev,
- Enable ? GMBOX_RECV_IRQ_ENABLE : GMBOX_RECV_IRQ_DISABLE,
- PROC_IO_SYNC);
-
-}
-
-int HCI_TransportRecvHCIEventSync(HCI_TRANSPORT_HANDLE HciTrans,
- struct htc_packet *pPacket,
- int MaxPollMS)
-{
- struct gmbox_proto_hci_uart *pProt = (struct gmbox_proto_hci_uart *)HciTrans;
- int status = 0;
- u8 lookAhead[8];
- int bytes;
- int totalRecvLength;
-
- MaxPollMS = MaxPollMS / 16;
-
- if (MaxPollMS < 2) {
- MaxPollMS = 2;
- }
-
- while (MaxPollMS) {
-
- bytes = sizeof(lookAhead);
- status = DevGMboxRecvLookAheadPeek(pProt->pDev,lookAhead,&bytes);
- if (status) {
- break;
- }
-
- if (bytes < 3) {
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("HCI recv poll got bytes: %d, retry : %d \n",
- bytes, MaxPollMS));
- A_MDELAY(16);
- MaxPollMS--;
- continue;
- }
-
- totalRecvLength = 0;
- switch (lookAhead[0]) {
- case HCI_UART_EVENT_PKT:
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("HCI Event: %d param length: %d \n",
- lookAhead[1], lookAhead[2]));
- totalRecvLength = lookAhead[2];
- totalRecvLength += 3; /* add type + event code + length field */
- break;
- default:
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("**Invalid HCI packet type: %d \n",lookAhead[0]));
- status = A_EPROTO;
- break;
- }
-
- if (status) {
- break;
- }
-
- pPacket->Completion = NULL;
- status = DevGMboxRead(pProt->pDev,pPacket,totalRecvLength);
- if (status) {
- break;
- }
-
- pPacket->pBuffer++;
- pPacket->ActualLength = totalRecvLength - 1;
- pPacket->Status = 0;
- break;
- }
-
- if (MaxPollMS == 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HCI recv poll timeout! \n"));
- status = A_ERROR;
- }
-
- return status;
-}
-
-#define LSB_SCRATCH_IDX 4
-#define MSB_SCRATCH_IDX 5
-int HCI_TransportSetBaudRate(HCI_TRANSPORT_HANDLE HciTrans, u32 Baud)
-{
- struct gmbox_proto_hci_uart *pProt = (struct gmbox_proto_hci_uart *)HciTrans;
- struct hif_device *pHIFDevice = (struct hif_device *)(pProt->pDev->HIFDevice);
- u32 scaledBaud, scratchAddr;
- int status = 0;
-
- /* Divide the desired baud rate by 100
- * Store the LSB in the local scratch register 4 and the MSB in the local
- * scratch register 5 for the target to read
- */
- scratchAddr = MBOX_BASE_ADDRESS | (LOCAL_SCRATCH_ADDRESS + 4 * LSB_SCRATCH_IDX);
- scaledBaud = (Baud / 100) & LOCAL_SCRATCH_VALUE_MASK;
- status = ar6000_WriteRegDiag(pHIFDevice, &scratchAddr, &scaledBaud);
- scratchAddr = MBOX_BASE_ADDRESS | (LOCAL_SCRATCH_ADDRESS + 4 * MSB_SCRATCH_IDX);
- scaledBaud = ((Baud / 100) >> (LOCAL_SCRATCH_VALUE_MSB+1)) & LOCAL_SCRATCH_VALUE_MASK;
- status |= ar6000_WriteRegDiag(pHIFDevice, &scratchAddr, &scaledBaud);
- if (0 != status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to set up baud rate in scratch register!"));
- return status;
- }
-
- /* Now interrupt the target to tell it about the baud rate */
- status = DevGMboxSetTargetInterrupt(pProt->pDev, MBOX_SIG_HCI_BRIDGE_BAUD_SET, BAUD_TIMEOUT_MS);
- if (0 != status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to tell target to change baud rate!"));
- }
-
- return status;
-}
-
-int HCI_TransportEnablePowerMgmt(HCI_TRANSPORT_HANDLE HciTrans, bool Enable)
-{
- int status;
- struct gmbox_proto_hci_uart *pProt = (struct gmbox_proto_hci_uart *)HciTrans;
-
- if (Enable) {
- status = DevGMboxSetTargetInterrupt(pProt->pDev, MBOX_SIG_HCI_BRIDGE_PWR_SAV_ON, BTPWRSAV_TIMEOUT_MS);
- } else {
- status = DevGMboxSetTargetInterrupt(pProt->pDev, MBOX_SIG_HCI_BRIDGE_PWR_SAV_OFF, BTPWRSAV_TIMEOUT_MS);
- }
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to enable/disable HCI power management!\n"));
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HCI power management enabled/disabled!\n"));
- }
-
- return status;
-}
-
-#endif //ATH_AR6K_ENABLE_GMBOX
-
diff --git a/drivers/staging/ath6kl/htc2/htc.c b/drivers/staging/ath6kl/htc2/htc.c
deleted file mode 100644
index ae54e64b6243..000000000000
--- a/drivers/staging/ath6kl/htc2/htc.c
+++ /dev/null
@@ -1,575 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="htc.c" company="Atheros">
-// Copyright (c) 2007-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-#include "htc_internal.h"
-
-#ifdef ATH_DEBUG_MODULE
-static struct ath_debug_mask_description g_HTCDebugDescription[] = {
- { ATH_DEBUG_SEND , "Send"},
- { ATH_DEBUG_RECV , "Recv"},
- { ATH_DEBUG_SYNC , "Sync"},
- { ATH_DEBUG_DUMP , "Dump Data (RX or TX)"},
- { ATH_DEBUG_IRQ , "Interrupt Processing"}
-};
-
-ATH_DEBUG_INSTANTIATE_MODULE_VAR(htc,
- "htc",
- "Host Target Communications",
- ATH_DEBUG_MASK_DEFAULTS,
- ATH_DEBUG_DESCRIPTION_COUNT(g_HTCDebugDescription),
- g_HTCDebugDescription);
-
-#endif
-
-static void HTCReportFailure(void *Context);
-static void ResetEndpointStates(struct htc_target *target);
-
-void HTCFreeControlBuffer(struct htc_target *target, struct htc_packet *pPacket, struct htc_packet_queue *pList)
-{
- LOCK_HTC(target);
- HTC_PACKET_ENQUEUE(pList,pPacket);
- UNLOCK_HTC(target);
-}
-
-struct htc_packet *HTCAllocControlBuffer(struct htc_target *target, struct htc_packet_queue *pList)
-{
- struct htc_packet *pPacket;
-
- LOCK_HTC(target);
- pPacket = HTC_PACKET_DEQUEUE(pList);
- UNLOCK_HTC(target);
-
- return pPacket;
-}
-
-/* cleanup the HTC instance */
-static void HTCCleanup(struct htc_target *target)
-{
- s32 i;
-
- DevCleanup(&target->Device);
-
- for (i = 0;i < NUM_CONTROL_BUFFERS;i++) {
- if (target->HTCControlBuffers[i].Buffer) {
- kfree(target->HTCControlBuffers[i].Buffer);
- }
- }
-
- if (A_IS_MUTEX_VALID(&target->HTCLock)) {
- A_MUTEX_DELETE(&target->HTCLock);
- }
-
- if (A_IS_MUTEX_VALID(&target->HTCRxLock)) {
- A_MUTEX_DELETE(&target->HTCRxLock);
- }
-
- if (A_IS_MUTEX_VALID(&target->HTCTxLock)) {
- A_MUTEX_DELETE(&target->HTCTxLock);
- }
- /* free our instance */
- kfree(target);
-}
-
-/* registered target arrival callback from the HIF layer */
-HTC_HANDLE HTCCreate(void *hif_handle, struct htc_init_info *pInfo)
-{
- struct htc_target *target = NULL;
- int status = 0;
- int i;
- u32 ctrl_bufsz;
- u32 blocksizes[HTC_MAILBOX_NUM_MAX];
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCCreate - Enter\n"));
-
- A_REGISTER_MODULE_DEBUG_INFO(htc);
-
- do {
-
- /* allocate target memory */
- if ((target = (struct htc_target *)A_MALLOC(sizeof(struct htc_target))) == NULL) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to allocate memory\n"));
- status = A_ERROR;
- break;
- }
-
- A_MEMZERO(target, sizeof(struct htc_target));
- A_MUTEX_INIT(&target->HTCLock);
- A_MUTEX_INIT(&target->HTCRxLock);
- A_MUTEX_INIT(&target->HTCTxLock);
- INIT_HTC_PACKET_QUEUE(&target->ControlBufferTXFreeList);
- INIT_HTC_PACKET_QUEUE(&target->ControlBufferRXFreeList);
-
- /* give device layer the hif device handle */
- target->Device.HIFDevice = hif_handle;
- /* give the device layer our context (for event processing)
- * the device layer will register it's own context with HIF
- * so we need to set this so we can fetch it in the target remove handler */
- target->Device.HTCContext = target;
- /* set device layer target failure callback */
- target->Device.TargetFailureCallback = HTCReportFailure;
- /* set device layer recv message pending callback */
- target->Device.MessagePendingCallback = HTCRecvMessagePendingHandler;
- target->EpWaitingForBuffers = ENDPOINT_MAX;
-
- memcpy(&target->HTCInitInfo,pInfo,sizeof(struct htc_init_info));
-
- ResetEndpointStates(target);
-
- /* setup device layer */
- status = DevSetup(&target->Device);
-
- if (status) {
- break;
- }
-
-
- /* get the block sizes */
- status = HIFConfigureDevice(hif_handle, HIF_DEVICE_GET_MBOX_BLOCK_SIZE,
- blocksizes, sizeof(blocksizes));
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to get block size info from HIF layer...\n"));
- break;
- }
-
- /* Set the control buffer size based on the block size */
- if (blocksizes[1] > HTC_MAX_CONTROL_MESSAGE_LENGTH) {
- ctrl_bufsz = blocksizes[1] + HTC_HDR_LENGTH;
- } else {
- ctrl_bufsz = HTC_MAX_CONTROL_MESSAGE_LENGTH + HTC_HDR_LENGTH;
- }
- for (i = 0;i < NUM_CONTROL_BUFFERS;i++) {
- target->HTCControlBuffers[i].Buffer = A_MALLOC(ctrl_bufsz);
- if (target->HTCControlBuffers[i].Buffer == NULL) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to allocate memory\n"));
- status = A_ERROR;
- break;
- }
- }
-
- if (status) {
- break;
- }
-
- /* carve up buffers/packets for control messages */
- for (i = 0; i < NUM_CONTROL_RX_BUFFERS; i++) {
- struct htc_packet *pControlPacket;
- pControlPacket = &target->HTCControlBuffers[i].HtcPacket;
- SET_HTC_PACKET_INFO_RX_REFILL(pControlPacket,
- target,
- target->HTCControlBuffers[i].Buffer,
- ctrl_bufsz,
- ENDPOINT_0);
- HTC_FREE_CONTROL_RX(target,pControlPacket);
- }
-
- for (;i < NUM_CONTROL_BUFFERS;i++) {
- struct htc_packet *pControlPacket;
- pControlPacket = &target->HTCControlBuffers[i].HtcPacket;
- INIT_HTC_PACKET_INFO(pControlPacket,
- target->HTCControlBuffers[i].Buffer,
- ctrl_bufsz);
- HTC_FREE_CONTROL_TX(target,pControlPacket);
- }
-
- } while (false);
-
- if (status) {
- if (target != NULL) {
- HTCCleanup(target);
- target = NULL;
- }
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCCreate - Exit\n"));
-
- return target;
-}
-
-void HTCDestroy(HTC_HANDLE HTCHandle)
-{
- struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCDestroy .. Destroying :0x%lX \n",(unsigned long)target));
- HTCCleanup(target);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCDestroy \n"));
-}
-
-/* get the low level HIF device for the caller , the caller may wish to do low level
- * HIF requests */
-void *HTCGetHifDevice(HTC_HANDLE HTCHandle)
-{
- struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
- return target->Device.HIFDevice;
-}
-
-/* wait for the target to arrive (sends HTC Ready message)
- * this operation is fully synchronous and the message is polled for */
-int HTCWaitTarget(HTC_HANDLE HTCHandle)
-{
- struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
- int status;
- struct htc_packet *pPacket = NULL;
- HTC_READY_EX_MSG *pRdyMsg;
-
- struct htc_service_connect_req connect;
- struct htc_service_connect_resp resp;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCWaitTarget - Enter (target:0x%lX) \n", (unsigned long)target));
-
- do {
-
-#ifdef MBOXHW_UNIT_TEST
-
- status = DoMboxHWTest(&target->Device);
-
- if (status) {
- break;
- }
-
-#endif
-
- /* we should be getting 1 control message that the target is ready */
- status = HTCWaitforControlMessage(target, &pPacket);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" Target Not Available!!\n"));
- break;
- }
-
- /* we controlled the buffer creation so it has to be properly aligned */
- pRdyMsg = (HTC_READY_EX_MSG *)pPacket->pBuffer;
-
- if ((pRdyMsg->Version2_0_Info.MessageID != HTC_MSG_READY_ID) ||
- (pPacket->ActualLength < sizeof(HTC_READY_MSG))) {
- /* this message is not valid */
- AR_DEBUG_ASSERT(false);
- status = A_EPROTO;
- break;
- }
-
-
- if (pRdyMsg->Version2_0_Info.CreditCount == 0 || pRdyMsg->Version2_0_Info.CreditSize == 0) {
- /* this message is not valid */
- AR_DEBUG_ASSERT(false);
- status = A_EPROTO;
- break;
- }
-
- target->TargetCredits = pRdyMsg->Version2_0_Info.CreditCount;
- target->TargetCreditSize = pRdyMsg->Version2_0_Info.CreditSize;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN, (" Target Ready: credits: %d credit size: %d\n",
- target->TargetCredits, target->TargetCreditSize));
-
- /* check if this is an extended ready message */
- if (pPacket->ActualLength >= sizeof(HTC_READY_EX_MSG)) {
- /* this is an extended message */
- target->HTCTargetVersion = pRdyMsg->HTCVersion;
- target->MaxMsgPerBundle = pRdyMsg->MaxMsgsPerHTCBundle;
- } else {
- /* legacy */
- target->HTCTargetVersion = HTC_VERSION_2P0;
- target->MaxMsgPerBundle = 0;
- }
-
-#ifdef HTC_FORCE_LEGACY_2P0
- /* for testing and comparison...*/
- target->HTCTargetVersion = HTC_VERSION_2P0;
- target->MaxMsgPerBundle = 0;
-#endif
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
- ("Using HTC Protocol Version : %s (%d)\n ",
- (target->HTCTargetVersion == HTC_VERSION_2P0) ? "2.0" : ">= 2.1",
- target->HTCTargetVersion));
-
- if (target->MaxMsgPerBundle > 0) {
- /* limit what HTC can handle */
- target->MaxMsgPerBundle = min(HTC_HOST_MAX_MSG_PER_BUNDLE, target->MaxMsgPerBundle);
- /* target supports message bundling, setup device layer */
- if (DevSetupMsgBundling(&target->Device,target->MaxMsgPerBundle)) {
- /* device layer can't handle bundling */
- target->MaxMsgPerBundle = 0;
- } else {
- /* limit bundle what the device layer can handle */
- target->MaxMsgPerBundle = min(DEV_GET_MAX_MSG_PER_BUNDLE(&target->Device),
- target->MaxMsgPerBundle);
- }
- }
-
- if (target->MaxMsgPerBundle > 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
- (" HTC bundling allowed. Max Msg Per HTC Bundle: %d\n", target->MaxMsgPerBundle));
-
- if (DEV_GET_MAX_BUNDLE_SEND_LENGTH(&target->Device) != 0) {
- target->SendBundlingEnabled = true;
- }
- if (DEV_GET_MAX_BUNDLE_RECV_LENGTH(&target->Device) != 0) {
- target->RecvBundlingEnabled = true;
- }
-
- if (!DEV_IS_LEN_BLOCK_ALIGNED(&target->Device,target->TargetCreditSize)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("*** Credit size: %d is not block aligned! Disabling send bundling \n",
- target->TargetCreditSize));
- /* disallow send bundling since the credit size is not aligned to a block size
- * the I/O block padding will spill into the next credit buffer which is fatal */
- target->SendBundlingEnabled = false;
- }
- }
-
- /* setup our pseudo HTC control endpoint connection */
- A_MEMZERO(&connect,sizeof(connect));
- A_MEMZERO(&resp,sizeof(resp));
- connect.EpCallbacks.pContext = target;
- connect.EpCallbacks.EpTxComplete = HTCControlTxComplete;
- connect.EpCallbacks.EpRecv = HTCControlRecv;
- connect.EpCallbacks.EpRecvRefill = NULL; /* not needed */
- connect.EpCallbacks.EpSendFull = NULL; /* not nedded */
- connect.MaxSendQueueDepth = NUM_CONTROL_BUFFERS;
- connect.ServiceID = HTC_CTRL_RSVD_SVC;
-
- /* connect fake service */
- status = HTCConnectService((HTC_HANDLE)target,
- &connect,
- &resp);
-
- if (!status) {
- break;
- }
-
- } while (false);
-
- if (pPacket != NULL) {
- HTC_FREE_CONTROL_RX(target,pPacket);
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCWaitTarget - Exit\n"));
-
- return status;
-}
-
-
-
-/* Start HTC, enable interrupts and let the target know host has finished setup */
-int HTCStart(HTC_HANDLE HTCHandle)
-{
- struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
- struct htc_packet *pPacket;
- int status;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCStart Enter\n"));
-
- /* make sure interrupts are disabled at the chip level,
- * this function can be called again from a reboot of the target without shutting down HTC */
- DevDisableInterrupts(&target->Device);
- /* make sure state is cleared again */
- target->OpStateFlags = 0;
- target->RecvStateFlags = 0;
-
- /* now that we are starting, push control receive buffers into the
- * HTC control endpoint */
-
- while (1) {
- pPacket = HTC_ALLOC_CONTROL_RX(target);
- if (NULL == pPacket) {
- break;
- }
- HTCAddReceivePkt((HTC_HANDLE)target,pPacket);
- }
-
- do {
-
- AR_DEBUG_ASSERT(target->InitCredits != NULL);
- AR_DEBUG_ASSERT(target->EpCreditDistributionListHead != NULL);
- AR_DEBUG_ASSERT(target->EpCreditDistributionListHead->pNext != NULL);
-
- /* call init credits callback to do the distribution ,
- * NOTE: the first entry in the distribution list is ENDPOINT_0, so
- * we pass the start of the list after this one. */
- target->InitCredits(target->pCredDistContext,
- target->EpCreditDistributionListHead->pNext,
- target->TargetCredits);
-
-#ifdef ATH_DEBUG_MODULE
-
- if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_TRC)) {
- DumpCreditDistStates(target);
- }
-#endif
-
- /* the caller is done connecting to services, so we can indicate to the
- * target that the setup phase is complete */
- status = HTCSendSetupComplete(target);
-
- if (status) {
- break;
- }
-
- /* unmask interrupts */
- status = DevUnmaskInterrupts(&target->Device);
-
- if (status) {
- HTCStop(target);
- }
-
- } while (false);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCStart Exit\n"));
- return status;
-}
-
-static void ResetEndpointStates(struct htc_target *target)
-{
- struct htc_endpoint *pEndpoint;
- int i;
-
- for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
- pEndpoint = &target->EndPoint[i];
-
- A_MEMZERO(&pEndpoint->CreditDist, sizeof(pEndpoint->CreditDist));
- pEndpoint->ServiceID = 0;
- pEndpoint->MaxMsgLength = 0;
- pEndpoint->MaxTxQueueDepth = 0;
- A_MEMZERO(&pEndpoint->EndPointStats,sizeof(pEndpoint->EndPointStats));
- INIT_HTC_PACKET_QUEUE(&pEndpoint->RxBuffers);
- INIT_HTC_PACKET_QUEUE(&pEndpoint->TxQueue);
- INIT_HTC_PACKET_QUEUE(&pEndpoint->RecvIndicationQueue);
- pEndpoint->target = target;
- }
- /* reset distribution list */
- target->EpCreditDistributionListHead = NULL;
-}
-
-/* stop HTC communications, i.e. stop interrupt reception, and flush all queued buffers */
-void HTCStop(HTC_HANDLE HTCHandle)
-{
- struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCStop \n"));
-
- LOCK_HTC(target);
- /* mark that we are shutting down .. */
- target->OpStateFlags |= HTC_OP_STATE_STOPPING;
- UNLOCK_HTC(target);
-
- /* Masking interrupts is a synchronous operation, when this function returns
- * all pending HIF I/O has completed, we can safely flush the queues */
- DevMaskInterrupts(&target->Device);
-
-#ifdef THREAD_X
- //
- // Is this delay required
- //
- A_MDELAY(200); // wait for IRQ process done
-#endif
- /* flush all send packets */
- HTCFlushSendPkts(target);
- /* flush all recv buffers */
- HTCFlushRecvBuffers(target);
-
- DevCleanupMsgBundling(&target->Device);
-
- ResetEndpointStates(target);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCStop \n"));
-}
-
-#ifdef ATH_DEBUG_MODULE
-void HTCDumpCreditStates(HTC_HANDLE HTCHandle)
-{
- struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
-
- LOCK_HTC_TX(target);
-
- DumpCreditDistStates(target);
-
- UNLOCK_HTC_TX(target);
-
- DumpAR6KDevState(&target->Device);
-}
-#endif
-/* report a target failure from the device, this is a callback from the device layer
- * which uses a mechanism to report errors from the target (i.e. special interrupts) */
-static void HTCReportFailure(void *Context)
-{
- struct htc_target *target = (struct htc_target *)Context;
-
- target->TargetFailure = true;
-
- if (target->HTCInitInfo.TargetFailure != NULL) {
- /* let upper layer know, it needs to call HTCStop() */
- target->HTCInitInfo.TargetFailure(target->HTCInitInfo.pContext, A_ERROR);
- }
-}
-
-bool HTCGetEndpointStatistics(HTC_HANDLE HTCHandle,
- HTC_ENDPOINT_ID Endpoint,
- HTC_ENDPOINT_STAT_ACTION Action,
- struct htc_endpoint_stats *pStats)
-{
-
- struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
- bool clearStats = false;
- bool sample = false;
-
- switch (Action) {
- case HTC_EP_STAT_SAMPLE :
- sample = true;
- break;
- case HTC_EP_STAT_SAMPLE_AND_CLEAR :
- sample = true;
- clearStats = true;
- break;
- case HTC_EP_STAT_CLEAR :
- clearStats = true;
- break;
- default:
- break;
- }
-
- A_ASSERT(Endpoint < ENDPOINT_MAX);
-
- /* lock out TX and RX while we sample and/or clear */
- LOCK_HTC_TX(target);
- LOCK_HTC_RX(target);
-
- if (sample) {
- A_ASSERT(pStats != NULL);
- /* return the stats to the caller */
- memcpy(pStats, &target->EndPoint[Endpoint].EndPointStats, sizeof(struct htc_endpoint_stats));
- }
-
- if (clearStats) {
- /* reset stats */
- A_MEMZERO(&target->EndPoint[Endpoint].EndPointStats, sizeof(struct htc_endpoint_stats));
- }
-
- UNLOCK_HTC_RX(target);
- UNLOCK_HTC_TX(target);
-
- return true;
-}
-
-struct ar6k_device *HTCGetAR6KDevice(void *HTCHandle)
-{
- struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
- return &target->Device;
-}
-
diff --git a/drivers/staging/ath6kl/htc2/htc_debug.h b/drivers/staging/ath6kl/htc2/htc_debug.h
deleted file mode 100644
index 8455703e221c..000000000000
--- a/drivers/staging/ath6kl/htc2/htc_debug.h
+++ /dev/null
@@ -1,38 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="htc_debug.h" company="Atheros">
-// Copyright (c) 2007-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef HTC_DEBUG_H_
-#define HTC_DEBUG_H_
-
-#define ATH_MODULE_NAME htc
-#include "a_debug.h"
-
-/* ------- Debug related stuff ------- */
-
-#define ATH_DEBUG_SEND ATH_DEBUG_MAKE_MODULE_MASK(0)
-#define ATH_DEBUG_RECV ATH_DEBUG_MAKE_MODULE_MASK(1)
-#define ATH_DEBUG_SYNC ATH_DEBUG_MAKE_MODULE_MASK(2)
-#define ATH_DEBUG_DUMP ATH_DEBUG_MAKE_MODULE_MASK(3)
-#define ATH_DEBUG_IRQ ATH_DEBUG_MAKE_MODULE_MASK(4)
-
-
-#endif /*HTC_DEBUG_H_*/
diff --git a/drivers/staging/ath6kl/htc2/htc_internal.h b/drivers/staging/ath6kl/htc2/htc_internal.h
deleted file mode 100644
index cac97351769a..000000000000
--- a/drivers/staging/ath6kl/htc2/htc_internal.h
+++ /dev/null
@@ -1,211 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="htc_internal.h" company="Atheros">
-// Copyright (c) 2007-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _HTC_INTERNAL_H_
-#define _HTC_INTERNAL_H_
-
-/* for debugging, uncomment this to capture the last frame header, on frame header
- * processing errors, the last frame header is dump for comparison */
-//#define HTC_CAPTURE_LAST_FRAME
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-/* Header files */
-
-#include "a_config.h"
-#include "athdefs.h"
-#include "a_osapi.h"
-#include "htc_debug.h"
-#include "htc.h"
-#include "htc_api.h"
-#include "bmi_msg.h"
-#include "hif.h"
-#include "AR6000/ar6k.h"
-
-/* HTC operational parameters */
-#define HTC_TARGET_RESPONSE_TIMEOUT 2000 /* in ms */
-#define HTC_TARGET_DEBUG_INTR_MASK 0x01
-#define HTC_TARGET_CREDIT_INTR_MASK 0xF0
-
-#define HTC_HOST_MAX_MSG_PER_BUNDLE 8
-#define HTC_MIN_HTC_MSGS_TO_BUNDLE 2
-
-/* packet flags */
-
-#define HTC_RX_PKT_IGNORE_LOOKAHEAD (1 << 0)
-#define HTC_RX_PKT_REFRESH_HDR (1 << 1)
-#define HTC_RX_PKT_PART_OF_BUNDLE (1 << 2)
-#define HTC_RX_PKT_NO_RECYCLE (1 << 3)
-
-/* scatter request flags */
-
-#define HTC_SCATTER_REQ_FLAGS_PARTIAL_BUNDLE (1 << 0)
-
-struct htc_endpoint {
- HTC_ENDPOINT_ID Id;
- HTC_SERVICE_ID ServiceID; /* service ID this endpoint is bound to
- non-zero value means this endpoint is in use */
- struct htc_packet_queue TxQueue; /* HTC frame buffer TX queue */
- struct htc_packet_queue RxBuffers; /* HTC frame buffer RX list */
- struct htc_endpoint_credit_dist CreditDist; /* credit distribution structure (exposed to driver layer) */
- struct htc_ep_callbacks EpCallBacks; /* callbacks associated with this endpoint */
- int MaxTxQueueDepth; /* max depth of the TX queue before we need to
- call driver's full handler */
- int MaxMsgLength; /* max length of endpoint message */
- int TxProcessCount; /* reference count to continue tx processing */
- struct htc_packet_queue RecvIndicationQueue; /* recv packets ready to be indicated */
- int RxProcessCount; /* reference count to allow single processing context */
- struct htc_target *target; /* back pointer to target */
- u8 SeqNo; /* TX seq no (helpful) for debugging */
- u32 LocalConnectionFlags; /* local connection flags */
- struct htc_endpoint_stats EndPointStats; /* endpoint statistics */
-};
-
-#define INC_HTC_EP_STAT(p,stat,count) (p)->EndPointStats.stat += (count);
-#define HTC_SERVICE_TX_PACKET_TAG HTC_TX_PACKET_TAG_INTERNAL
-
-#define NUM_CONTROL_BUFFERS 8
-#define NUM_CONTROL_TX_BUFFERS 2
-#define NUM_CONTROL_RX_BUFFERS (NUM_CONTROL_BUFFERS - NUM_CONTROL_TX_BUFFERS)
-
-struct htc_control_buffer {
- struct htc_packet HtcPacket;
- u8 *Buffer;
-};
-
-#define HTC_RECV_WAIT_BUFFERS (1 << 0)
-#define HTC_OP_STATE_STOPPING (1 << 0)
-
-/* our HTC target state */
-struct htc_target {
- struct htc_endpoint EndPoint[ENDPOINT_MAX];
- struct htc_control_buffer HTCControlBuffers[NUM_CONTROL_BUFFERS];
- struct htc_endpoint_credit_dist *EpCreditDistributionListHead;
- struct htc_packet_queue ControlBufferTXFreeList;
- struct htc_packet_queue ControlBufferRXFreeList;
- HTC_CREDIT_DIST_CALLBACK DistributeCredits;
- HTC_CREDIT_INIT_CALLBACK InitCredits;
- void *pCredDistContext;
- int TargetCredits;
- unsigned int TargetCreditSize;
- A_MUTEX_T HTCLock;
- A_MUTEX_T HTCRxLock;
- A_MUTEX_T HTCTxLock;
- struct ar6k_device Device; /* AR6K - specific state */
- u32 OpStateFlags;
- u32 RecvStateFlags;
- HTC_ENDPOINT_ID EpWaitingForBuffers;
- bool TargetFailure;
-#ifdef HTC_CAPTURE_LAST_FRAME
- struct htc_frame_hdr LastFrameHdr; /* useful for debugging */
- u8 LastTrailer[256];
- u8 LastTrailerLength;
-#endif
- struct htc_init_info HTCInitInfo;
- u8 HTCTargetVersion;
- int MaxMsgPerBundle; /* max messages per bundle for HTC */
- bool SendBundlingEnabled; /* run time enable for send bundling (dynamic) */
- int RecvBundlingEnabled; /* run time enable for recv bundling (dynamic) */
-};
-
-#define HTC_STOPPING(t) ((t)->OpStateFlags & HTC_OP_STATE_STOPPING)
-#define LOCK_HTC(t) A_MUTEX_LOCK(&(t)->HTCLock);
-#define UNLOCK_HTC(t) A_MUTEX_UNLOCK(&(t)->HTCLock);
-#define LOCK_HTC_RX(t) A_MUTEX_LOCK(&(t)->HTCRxLock);
-#define UNLOCK_HTC_RX(t) A_MUTEX_UNLOCK(&(t)->HTCRxLock);
-#define LOCK_HTC_TX(t) A_MUTEX_LOCK(&(t)->HTCTxLock);
-#define UNLOCK_HTC_TX(t) A_MUTEX_UNLOCK(&(t)->HTCTxLock);
-
-#define GET_HTC_TARGET_FROM_HANDLE(hnd) ((struct htc_target *)(hnd))
-#define HTC_RECYCLE_RX_PKT(target,p,e) \
-{ \
- if ((p)->PktInfo.AsRx.HTCRxFlags & HTC_RX_PKT_NO_RECYCLE) { \
- HTC_PACKET_RESET_RX(pPacket); \
- pPacket->Status = A_ECANCELED; \
- (e)->EpCallBacks.EpRecv((e)->EpCallBacks.pContext, \
- (p)); \
- } else { \
- HTC_PACKET_RESET_RX(pPacket); \
- HTCAddReceivePkt((HTC_HANDLE)(target),(p)); \
- } \
-}
-
-/* internal HTC functions */
-void HTCControlTxComplete(void *Context, struct htc_packet *pPacket);
-void HTCControlRecv(void *Context, struct htc_packet *pPacket);
-int HTCWaitforControlMessage(struct htc_target *target, struct htc_packet **ppControlPacket);
-struct htc_packet *HTCAllocControlBuffer(struct htc_target *target, struct htc_packet_queue *pList);
-void HTCFreeControlBuffer(struct htc_target *target, struct htc_packet *pPacket, struct htc_packet_queue *pList);
-int HTCIssueSend(struct htc_target *target, struct htc_packet *pPacket);
-void HTCRecvCompleteHandler(void *Context, struct htc_packet *pPacket);
-int HTCRecvMessagePendingHandler(void *Context, u32 MsgLookAheads[], int NumLookAheads, bool *pAsyncProc, int *pNumPktsFetched);
-void HTCProcessCreditRpt(struct htc_target *target, HTC_CREDIT_REPORT *pRpt, int NumEntries, HTC_ENDPOINT_ID FromEndpoint);
-int HTCSendSetupComplete(struct htc_target *target);
-void HTCFlushRecvBuffers(struct htc_target *target);
-void HTCFlushSendPkts(struct htc_target *target);
-
-#ifdef ATH_DEBUG_MODULE
-void DumpCreditDist(struct htc_endpoint_credit_dist *pEPDist);
-void DumpCreditDistStates(struct htc_target *target);
-void DebugDumpBytes(u8 *buffer, u16 length, char *pDescription);
-#endif
-
-static INLINE struct htc_packet *HTC_ALLOC_CONTROL_TX(struct htc_target *target) {
- struct htc_packet *pPacket = HTCAllocControlBuffer(target,&target->ControlBufferTXFreeList);
- if (pPacket != NULL) {
- /* set payload pointer area with some headroom */
- pPacket->pBuffer = pPacket->pBufferStart + HTC_HDR_LENGTH;
- }
- return pPacket;
-}
-
-#define HTC_FREE_CONTROL_TX(t,p) HTCFreeControlBuffer((t),(p),&(t)->ControlBufferTXFreeList)
-#define HTC_ALLOC_CONTROL_RX(t) HTCAllocControlBuffer((t),&(t)->ControlBufferRXFreeList)
-#define HTC_FREE_CONTROL_RX(t,p) \
-{ \
- HTC_PACKET_RESET_RX(p); \
- HTCFreeControlBuffer((t),(p),&(t)->ControlBufferRXFreeList); \
-}
-
-#define HTC_PREPARE_SEND_PKT(pP,sendflags,ctrl0,ctrl1) \
-{ \
- u8 *pHdrBuf; \
- (pP)->pBuffer -= HTC_HDR_LENGTH; \
- pHdrBuf = (pP)->pBuffer; \
- A_SET_UINT16_FIELD(pHdrBuf,struct htc_frame_hdr,PayloadLen,(u16)(pP)->ActualLength); \
- A_SET_UINT8_FIELD(pHdrBuf,struct htc_frame_hdr,Flags,(sendflags)); \
- A_SET_UINT8_FIELD(pHdrBuf,struct htc_frame_hdr,EndpointID, (u8)(pP)->Endpoint); \
- A_SET_UINT8_FIELD(pHdrBuf,struct htc_frame_hdr,ControlBytes[0], (u8)(ctrl0)); \
- A_SET_UINT8_FIELD(pHdrBuf,struct htc_frame_hdr,ControlBytes[1], (u8)(ctrl1)); \
-}
-
-#define HTC_UNPREPARE_SEND_PKT(pP) \
- (pP)->pBuffer += HTC_HDR_LENGTH; \
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _HTC_INTERNAL_H_ */
diff --git a/drivers/staging/ath6kl/htc2/htc_recv.c b/drivers/staging/ath6kl/htc2/htc_recv.c
deleted file mode 100644
index 974cc8cd6936..000000000000
--- a/drivers/staging/ath6kl/htc2/htc_recv.c
+++ /dev/null
@@ -1,1572 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="htc_recv.c" company="Atheros">
-// Copyright (c) 2007-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-#include "htc_internal.h"
-
-#define HTCIssueRecv(t, p) \
- DevRecvPacket(&(t)->Device, \
- (p), \
- (p)->ActualLength)
-
-#define DO_RCV_COMPLETION(e,q) DoRecvCompletion(e,q)
-
-#define DUMP_RECV_PKT_INFO(pP) \
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" HTC RECV packet 0x%lX (%d bytes) (hdr:0x%X) on ep : %d \n", \
- (unsigned long)(pP), \
- (pP)->ActualLength, \
- (pP)->PktInfo.AsRx.ExpectedHdr, \
- (pP)->Endpoint))
-
-#define HTC_RX_STAT_PROFILE(t,ep,numLookAheads) \
-{ \
- INC_HTC_EP_STAT((ep), RxReceived, 1); \
- if ((numLookAheads) == 1) { \
- INC_HTC_EP_STAT((ep), RxLookAheads, 1); \
- } else if ((numLookAheads) > 1) { \
- INC_HTC_EP_STAT((ep), RxBundleLookAheads, 1); \
- } \
-}
-
-static void DoRecvCompletion(struct htc_endpoint *pEndpoint,
- struct htc_packet_queue *pQueueToIndicate)
-{
-
- do {
-
- if (HTC_QUEUE_EMPTY(pQueueToIndicate)) {
- /* nothing to indicate */
- break;
- }
-
- if (pEndpoint->EpCallBacks.EpRecvPktMultiple != NULL) {
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" HTC calling ep %d, recv multiple callback (%d pkts) \n",
- pEndpoint->Id, HTC_PACKET_QUEUE_DEPTH(pQueueToIndicate)));
- /* a recv multiple handler is being used, pass the queue to the handler */
- pEndpoint->EpCallBacks.EpRecvPktMultiple(pEndpoint->EpCallBacks.pContext,
- pQueueToIndicate);
- INIT_HTC_PACKET_QUEUE(pQueueToIndicate);
- } else {
- struct htc_packet *pPacket;
- /* using legacy EpRecv */
- do {
- pPacket = HTC_PACKET_DEQUEUE(pQueueToIndicate);
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" HTC calling ep %d recv callback on packet 0x%lX \n", \
- pEndpoint->Id, (unsigned long)(pPacket)));
- pEndpoint->EpCallBacks.EpRecv(pEndpoint->EpCallBacks.pContext, pPacket);
- } while (!HTC_QUEUE_EMPTY(pQueueToIndicate));
- }
-
- } while (false);
-
-}
-
-static INLINE int HTCProcessTrailer(struct htc_target *target,
- u8 *pBuffer,
- int Length,
- u32 *pNextLookAheads,
- int *pNumLookAheads,
- HTC_ENDPOINT_ID FromEndpoint)
-{
- HTC_RECORD_HDR *pRecord;
- u8 *pRecordBuf;
- HTC_LOOKAHEAD_REPORT *pLookAhead;
- u8 *pOrigBuffer;
- int origLength;
- int status;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCProcessTrailer (length:%d) \n", Length));
-
- if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
- AR_DEBUG_PRINTBUF(pBuffer,Length,"Recv Trailer");
- }
-
- pOrigBuffer = pBuffer;
- origLength = Length;
- status = 0;
-
- while (Length > 0) {
-
- if (Length < sizeof(HTC_RECORD_HDR)) {
- status = A_EPROTO;
- break;
- }
- /* these are byte aligned structs */
- pRecord = (HTC_RECORD_HDR *)pBuffer;
- Length -= sizeof(HTC_RECORD_HDR);
- pBuffer += sizeof(HTC_RECORD_HDR);
-
- if (pRecord->Length > Length) {
- /* no room left in buffer for record */
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- (" invalid record length: %d (id:%d) buffer has: %d bytes left \n",
- pRecord->Length, pRecord->RecordID, Length));
- status = A_EPROTO;
- break;
- }
- /* start of record follows the header */
- pRecordBuf = pBuffer;
-
- switch (pRecord->RecordID) {
- case HTC_RECORD_CREDITS:
- AR_DEBUG_ASSERT(pRecord->Length >= sizeof(HTC_CREDIT_REPORT));
- HTCProcessCreditRpt(target,
- (HTC_CREDIT_REPORT *)pRecordBuf,
- pRecord->Length / (sizeof(HTC_CREDIT_REPORT)),
- FromEndpoint);
- break;
- case HTC_RECORD_LOOKAHEAD:
- AR_DEBUG_ASSERT(pRecord->Length >= sizeof(HTC_LOOKAHEAD_REPORT));
- pLookAhead = (HTC_LOOKAHEAD_REPORT *)pRecordBuf;
- if ((pLookAhead->PreValid == ((~pLookAhead->PostValid) & 0xFF)) &&
- (pNextLookAheads != NULL)) {
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
- (" LookAhead Report Found (pre valid:0x%X, post valid:0x%X) \n",
- pLookAhead->PreValid,
- pLookAhead->PostValid));
-
- /* look ahead bytes are valid, copy them over */
- ((u8 *)(&pNextLookAheads[0]))[0] = pLookAhead->LookAhead[0];
- ((u8 *)(&pNextLookAheads[0]))[1] = pLookAhead->LookAhead[1];
- ((u8 *)(&pNextLookAheads[0]))[2] = pLookAhead->LookAhead[2];
- ((u8 *)(&pNextLookAheads[0]))[3] = pLookAhead->LookAhead[3];
-
-#ifdef ATH_DEBUG_MODULE
- if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
- DebugDumpBytes((u8 *)pNextLookAheads,4,"Next Look Ahead");
- }
-#endif
- /* just one normal lookahead */
- *pNumLookAheads = 1;
- }
- break;
- case HTC_RECORD_LOOKAHEAD_BUNDLE:
- AR_DEBUG_ASSERT(pRecord->Length >= sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT));
- if (pRecord->Length >= sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT) &&
- (pNextLookAheads != NULL)) {
- HTC_BUNDLED_LOOKAHEAD_REPORT *pBundledLookAheadRpt;
- int i;
-
- pBundledLookAheadRpt = (HTC_BUNDLED_LOOKAHEAD_REPORT *)pRecordBuf;
-
-#ifdef ATH_DEBUG_MODULE
- if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
- DebugDumpBytes(pRecordBuf,pRecord->Length,"Bundle LookAhead");
- }
-#endif
-
- if ((pRecord->Length / (sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT))) >
- HTC_HOST_MAX_MSG_PER_BUNDLE) {
- /* this should never happen, the target restricts the number
- * of messages per bundle configured by the host */
- A_ASSERT(false);
- status = A_EPROTO;
- break;
- }
-
- for (i = 0; i < (int)(pRecord->Length / (sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT))); i++) {
- ((u8 *)(&pNextLookAheads[i]))[0] = pBundledLookAheadRpt->LookAhead[0];
- ((u8 *)(&pNextLookAheads[i]))[1] = pBundledLookAheadRpt->LookAhead[1];
- ((u8 *)(&pNextLookAheads[i]))[2] = pBundledLookAheadRpt->LookAhead[2];
- ((u8 *)(&pNextLookAheads[i]))[3] = pBundledLookAheadRpt->LookAhead[3];
- pBundledLookAheadRpt++;
- }
-
- *pNumLookAheads = i;
- }
- break;
- default:
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" unhandled record: id:%d length:%d \n",
- pRecord->RecordID, pRecord->Length));
- break;
- }
-
- if (status) {
- break;
- }
-
- /* advance buffer past this record for next time around */
- pBuffer += pRecord->Length;
- Length -= pRecord->Length;
- }
-
-#ifdef ATH_DEBUG_MODULE
- if (status) {
- DebugDumpBytes(pOrigBuffer,origLength,"BAD Recv Trailer");
- }
-#endif
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCProcessTrailer \n"));
- return status;
-
-}
-
-/* process a received message (i.e. strip off header, process any trailer data)
- * note : locks must be released when this function is called */
-static int HTCProcessRecvHeader(struct htc_target *target,
- struct htc_packet *pPacket,
- u32 *pNextLookAheads,
- int *pNumLookAheads)
-{
- u8 temp;
- u8 *pBuf;
- int status = 0;
- u16 payloadLen;
- u32 lookAhead;
-
- pBuf = pPacket->pBuffer;
-
- if (pNumLookAheads != NULL) {
- *pNumLookAheads = 0;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCProcessRecvHeader \n"));
-
- if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
- AR_DEBUG_PRINTBUF(pBuf,pPacket->ActualLength,"HTC Recv PKT");
- }
-
- do {
- /* note, we cannot assume the alignment of pBuffer, so we use the safe macros to
- * retrieve 16 bit fields */
- payloadLen = A_GET_UINT16_FIELD(pBuf, struct htc_frame_hdr, PayloadLen);
-
- ((u8 *)&lookAhead)[0] = pBuf[0];
- ((u8 *)&lookAhead)[1] = pBuf[1];
- ((u8 *)&lookAhead)[2] = pBuf[2];
- ((u8 *)&lookAhead)[3] = pBuf[3];
-
- if (pPacket->PktInfo.AsRx.HTCRxFlags & HTC_RX_PKT_REFRESH_HDR) {
- /* refresh expected hdr, since this was unknown at the time we grabbed the packets
- * as part of a bundle */
- pPacket->PktInfo.AsRx.ExpectedHdr = lookAhead;
- /* refresh actual length since we now have the real header */
- pPacket->ActualLength = payloadLen + HTC_HDR_LENGTH;
-
- /* validate the actual header that was refreshed */
- if (pPacket->ActualLength > pPacket->BufferLength) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("Refreshed HDR payload length (%d) in bundled RECV is invalid (hdr: 0x%X) \n",
- payloadLen, lookAhead));
- /* limit this to max buffer just to print out some of the buffer */
- pPacket->ActualLength = min(pPacket->ActualLength, pPacket->BufferLength);
- status = A_EPROTO;
- break;
- }
-
- if (pPacket->Endpoint != A_GET_UINT8_FIELD(pBuf, struct htc_frame_hdr, EndpointID)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("Refreshed HDR endpoint (%d) does not match expected endpoint (%d) \n",
- A_GET_UINT8_FIELD(pBuf, struct htc_frame_hdr, EndpointID), pPacket->Endpoint));
- status = A_EPROTO;
- break;
- }
- }
-
- if (lookAhead != pPacket->PktInfo.AsRx.ExpectedHdr) {
- /* somehow the lookahead that gave us the full read length did not
- * reflect the actual header in the pending message */
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("HTCProcessRecvHeader, lookahead mismatch! (pPkt:0x%lX flags:0x%X) \n",
- (unsigned long)pPacket, pPacket->PktInfo.AsRx.HTCRxFlags));
-#ifdef ATH_DEBUG_MODULE
- DebugDumpBytes((u8 *)&pPacket->PktInfo.AsRx.ExpectedHdr,4,"Expected Message LookAhead");
- DebugDumpBytes(pBuf,sizeof(struct htc_frame_hdr),"Current Frame Header");
-#ifdef HTC_CAPTURE_LAST_FRAME
- DebugDumpBytes((u8 *)&target->LastFrameHdr,sizeof(struct htc_frame_hdr),"Last Frame Header");
- if (target->LastTrailerLength != 0) {
- DebugDumpBytes(target->LastTrailer,
- target->LastTrailerLength,
- "Last trailer");
- }
-#endif
-#endif
- status = A_EPROTO;
- break;
- }
-
- /* get flags */
- temp = A_GET_UINT8_FIELD(pBuf, struct htc_frame_hdr, Flags);
-
- if (temp & HTC_FLAGS_RECV_TRAILER) {
- /* this packet has a trailer */
-
- /* extract the trailer length in control byte 0 */
- temp = A_GET_UINT8_FIELD(pBuf, struct htc_frame_hdr, ControlBytes[0]);
-
- if ((temp < sizeof(HTC_RECORD_HDR)) || (temp > payloadLen)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("HTCProcessRecvHeader, invalid header (payloadlength should be :%d, CB[0] is:%d) \n",
- payloadLen, temp));
- status = A_EPROTO;
- break;
- }
-
- if (pPacket->PktInfo.AsRx.HTCRxFlags & HTC_RX_PKT_IGNORE_LOOKAHEAD) {
- /* this packet was fetched as part of an HTC bundle, the embedded lookahead is
- * not valid since the next packet may have already been fetched as part of the
- * bundle */
- pNextLookAheads = NULL;
- pNumLookAheads = NULL;
- }
-
- /* process trailer data that follows HDR + application payload */
- status = HTCProcessTrailer(target,
- (pBuf + HTC_HDR_LENGTH + payloadLen - temp),
- temp,
- pNextLookAheads,
- pNumLookAheads,
- pPacket->Endpoint);
-
- if (status) {
- break;
- }
-
-#ifdef HTC_CAPTURE_LAST_FRAME
- memcpy(target->LastTrailer, (pBuf + HTC_HDR_LENGTH + payloadLen - temp), temp);
- target->LastTrailerLength = temp;
-#endif
- /* trim length by trailer bytes */
- pPacket->ActualLength -= temp;
- }
-#ifdef HTC_CAPTURE_LAST_FRAME
- else {
- target->LastTrailerLength = 0;
- }
-#endif
-
- /* if we get to this point, the packet is good */
- /* remove header and adjust length */
- pPacket->pBuffer += HTC_HDR_LENGTH;
- pPacket->ActualLength -= HTC_HDR_LENGTH;
-
- } while (false);
-
- if (status) {
- /* dump the whole packet */
-#ifdef ATH_DEBUG_MODULE
- DebugDumpBytes(pBuf,pPacket->ActualLength < 256 ? pPacket->ActualLength : 256 ,"BAD HTC Recv PKT");
-#endif
- } else {
-#ifdef HTC_CAPTURE_LAST_FRAME
- memcpy(&target->LastFrameHdr,pBuf,sizeof(struct htc_frame_hdr));
-#endif
- if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
- if (pPacket->ActualLength > 0) {
- AR_DEBUG_PRINTBUF(pPacket->pBuffer,pPacket->ActualLength,"HTC - Application Msg");
- }
- }
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCProcessRecvHeader \n"));
- return status;
-}
-
-static INLINE void HTCAsyncRecvCheckMorePackets(struct htc_target *target,
- u32 NextLookAheads[],
- int NumLookAheads,
- bool CheckMoreMsgs)
-{
- /* was there a lookahead for the next packet? */
- if (NumLookAheads > 0) {
- int nextStatus;
- int fetched = 0;
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
- ("HTCAsyncRecvCheckMorePackets - num lookaheads were non-zero : %d \n",
- NumLookAheads));
- /* force status re-check */
- REF_IRQ_STATUS_RECHECK(&target->Device);
- /* we have more packets, get the next packet fetch started */
- nextStatus = HTCRecvMessagePendingHandler(target, NextLookAheads, NumLookAheads, NULL, &fetched);
- if (A_EPROTO == nextStatus) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("Next look ahead from recv header was INVALID\n"));
-#ifdef ATH_DEBUG_MODULE
- DebugDumpBytes((u8 *)NextLookAheads,
- NumLookAheads * (sizeof(u32)),
- "BAD lookaheads from lookahead report");
-#endif
- }
- if (!nextStatus && !fetched) {
- /* we could not fetch any more packets due to resources */
- DevAsyncIrqProcessComplete(&target->Device);
- }
- } else {
- if (CheckMoreMsgs) {
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
- ("HTCAsyncRecvCheckMorePackets - rechecking for more messages...\n"));
- /* if we did not get anything on the look-ahead,
- * call device layer to asynchronously re-check for messages. If we can keep the async
- * processing going we get better performance. If there is a pending message we will keep processing
- * messages asynchronously which should pipeline things nicely */
- DevCheckPendingRecvMsgsAsync(&target->Device);
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("HTCAsyncRecvCheckMorePackets - no check \n"));
- }
- }
-
-
-}
-
- /* unload the recv completion queue */
-static INLINE void DrainRecvIndicationQueue(struct htc_target *target, struct htc_endpoint *pEndpoint)
-{
- struct htc_packet_queue recvCompletions;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+DrainRecvIndicationQueue \n"));
-
- INIT_HTC_PACKET_QUEUE(&recvCompletions);
-
- LOCK_HTC_RX(target);
-
- /* increment rx processing count on entry */
- pEndpoint->RxProcessCount++;
- if (pEndpoint->RxProcessCount > 1) {
- pEndpoint->RxProcessCount--;
- /* another thread or task is draining the RX completion queue on this endpoint
- * that thread will reset the rx processing count when the queue is drained */
- UNLOCK_HTC_RX(target);
- return;
- }
-
- /******* at this point only 1 thread may enter ******/
-
- while (true) {
-
- /* transfer items from main recv queue to the local one so we can release the lock */
- HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&recvCompletions, &pEndpoint->RecvIndicationQueue);
-
- if (HTC_QUEUE_EMPTY(&recvCompletions)) {
- /* all drained */
- break;
- }
-
- /* release lock while we do the recv completions
- * other threads can now queue more recv completions */
- UNLOCK_HTC_RX(target);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
- ("DrainRecvIndicationQueue : completing %d RECV packets \n",
- HTC_PACKET_QUEUE_DEPTH(&recvCompletions)));
- /* do completion */
- DO_RCV_COMPLETION(pEndpoint,&recvCompletions);
-
- /* re-acquire lock to grab some more completions */
- LOCK_HTC_RX(target);
- }
-
- /* reset count */
- pEndpoint->RxProcessCount = 0;
- UNLOCK_HTC_RX(target);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-DrainRecvIndicationQueue \n"));
-
-}
-
- /* optimization for recv packets, we can indicate a "hint" that there are more
- * single-packets to fetch on this endpoint */
-#define SET_MORE_RX_PACKET_INDICATION_FLAG(L,N,E,P) \
- if ((N) > 0) { SetRxPacketIndicationFlags((L)[0],(E),(P)); }
-
- /* for bundled frames, we can force the flag to indicate there are more packets */
-#define FORCE_MORE_RX_PACKET_INDICATION_FLAG(P) \
- (P)->PktInfo.AsRx.IndicationFlags |= HTC_RX_FLAGS_INDICATE_MORE_PKTS;
-
- /* note: this function can be called with the RX lock held */
-static INLINE void SetRxPacketIndicationFlags(u32 LookAhead,
- struct htc_endpoint *pEndpoint,
- struct htc_packet *pPacket)
-{
- struct htc_frame_hdr *pHdr = (struct htc_frame_hdr *)&LookAhead;
- /* check to see if the "next" packet is from the same endpoint of the
- completing packet */
- if (pHdr->EndpointID == pPacket->Endpoint) {
- /* check that there is a buffer available to actually fetch it */
- if (!HTC_QUEUE_EMPTY(&pEndpoint->RxBuffers)) {
- /* provide a hint that there are more RX packets to fetch */
- FORCE_MORE_RX_PACKET_INDICATION_FLAG(pPacket);
- }
- }
-}
-
-
-/* asynchronous completion handler for recv packet fetching, when the device layer
- * completes a read request, it will call this completion handler */
-void HTCRecvCompleteHandler(void *Context, struct htc_packet *pPacket)
-{
- struct htc_target *target = (struct htc_target *)Context;
- struct htc_endpoint *pEndpoint;
- u32 nextLookAheads[HTC_HOST_MAX_MSG_PER_BUNDLE];
- int numLookAheads = 0;
- int status;
- bool checkMorePkts = true;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCRecvCompleteHandler (pkt:0x%lX, status:%d, ep:%d) \n",
- (unsigned long)pPacket, pPacket->Status, pPacket->Endpoint));
-
- A_ASSERT(!IS_DEV_IRQ_PROC_SYNC_MODE(&target->Device));
- AR_DEBUG_ASSERT(pPacket->Endpoint < ENDPOINT_MAX);
- pEndpoint = &target->EndPoint[pPacket->Endpoint];
- pPacket->Completion = NULL;
-
- /* get completion status */
- status = pPacket->Status;
-
- do {
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HTCRecvCompleteHandler: request failed (status:%d, ep:%d) \n",
- pPacket->Status, pPacket->Endpoint));
- break;
- }
- /* process the header for any trailer data */
- status = HTCProcessRecvHeader(target,pPacket,nextLookAheads,&numLookAheads);
-
- if (status) {
- break;
- }
-
- if (pPacket->PktInfo.AsRx.HTCRxFlags & HTC_RX_PKT_IGNORE_LOOKAHEAD) {
- /* this packet was part of a bundle that had to be broken up.
- * It was fetched one message at a time. There may be other asynchronous reads queued behind this one.
- * Do no issue another check for more packets since the last one in the series of requests
- * will handle it */
- checkMorePkts = false;
- }
-
- DUMP_RECV_PKT_INFO(pPacket);
- LOCK_HTC_RX(target);
- SET_MORE_RX_PACKET_INDICATION_FLAG(nextLookAheads,numLookAheads,pEndpoint,pPacket);
- /* we have a good packet, queue it to the completion queue */
- HTC_PACKET_ENQUEUE(&pEndpoint->RecvIndicationQueue,pPacket);
- HTC_RX_STAT_PROFILE(target,pEndpoint,numLookAheads);
- UNLOCK_HTC_RX(target);
-
- /* check for more recv packets before indicating */
- HTCAsyncRecvCheckMorePackets(target,nextLookAheads,numLookAheads,checkMorePkts);
-
- } while (false);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("HTCRecvCompleteHandler , message fetch failed (status = %d) \n",
- status));
- /* recycle this packet */
- HTC_RECYCLE_RX_PKT(target, pPacket, pEndpoint);
- } else {
- /* a good packet was queued, drain the queue */
- DrainRecvIndicationQueue(target,pEndpoint);
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCRecvCompleteHandler\n"));
-}
-
-/* synchronously wait for a control message from the target,
- * This function is used at initialization time ONLY. At init messages
- * on ENDPOINT 0 are expected. */
-int HTCWaitforControlMessage(struct htc_target *target, struct htc_packet **ppControlPacket)
-{
- int status;
- u32 lookAhead;
- struct htc_packet *pPacket = NULL;
- struct htc_frame_hdr *pHdr;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCWaitforControlMessage \n"));
-
- do {
-
- *ppControlPacket = NULL;
-
- /* call the polling function to see if we have a message */
- status = DevPollMboxMsgRecv(&target->Device,
- &lookAhead,
- HTC_TARGET_RESPONSE_TIMEOUT);
-
- if (status) {
- break;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
- ("HTCWaitforControlMessage : lookAhead : 0x%X \n", lookAhead));
-
- /* check the lookahead */
- pHdr = (struct htc_frame_hdr *)&lookAhead;
-
- if (pHdr->EndpointID != ENDPOINT_0) {
- /* unexpected endpoint number, should be zero */
- AR_DEBUG_ASSERT(false);
- status = A_EPROTO;
- break;
- }
-
- if (status) {
- /* bad message */
- AR_DEBUG_ASSERT(false);
- status = A_EPROTO;
- break;
- }
-
- pPacket = HTC_ALLOC_CONTROL_RX(target);
-
- if (pPacket == NULL) {
- AR_DEBUG_ASSERT(false);
- status = A_NO_MEMORY;
- break;
- }
-
- pPacket->PktInfo.AsRx.HTCRxFlags = 0;
- pPacket->PktInfo.AsRx.ExpectedHdr = lookAhead;
- pPacket->ActualLength = pHdr->PayloadLen + HTC_HDR_LENGTH;
-
- if (pPacket->ActualLength > pPacket->BufferLength) {
- AR_DEBUG_ASSERT(false);
- status = A_EPROTO;
- break;
- }
-
- /* we want synchronous operation */
- pPacket->Completion = NULL;
-
- /* get the message from the device, this will block */
- status = HTCIssueRecv(target, pPacket);
-
- if (status) {
- break;
- }
-
- /* process receive header */
- status = HTCProcessRecvHeader(target,pPacket,NULL,NULL);
-
- pPacket->Status = status;
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("HTCWaitforControlMessage, HTCProcessRecvHeader failed (status = %d) \n",
- status));
- break;
- }
-
- /* give the caller this control message packet, they are responsible to free */
- *ppControlPacket = pPacket;
-
- } while (false);
-
- if (status) {
- if (pPacket != NULL) {
- /* cleanup buffer on error */
- HTC_FREE_CONTROL_RX(target,pPacket);
- }
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCWaitforControlMessage \n"));
-
- return status;
-}
-
-static int AllocAndPrepareRxPackets(struct htc_target *target,
- u32 LookAheads[],
- int Messages,
- struct htc_endpoint *pEndpoint,
- struct htc_packet_queue *pQueue)
-{
- int status = 0;
- struct htc_packet *pPacket;
- struct htc_frame_hdr *pHdr;
- int i,j;
- int numMessages;
- int fullLength;
- bool noRecycle;
-
- /* lock RX while we assemble the packet buffers */
- LOCK_HTC_RX(target);
-
- for (i = 0; i < Messages; i++) {
-
- pHdr = (struct htc_frame_hdr *)&LookAheads[i];
-
- if (pHdr->EndpointID >= ENDPOINT_MAX) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Invalid Endpoint in look-ahead: %d \n",pHdr->EndpointID));
- /* invalid endpoint */
- status = A_EPROTO;
- break;
- }
-
- if (pHdr->EndpointID != pEndpoint->Id) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Invalid Endpoint in look-ahead: %d should be : %d (index:%d)\n",
- pHdr->EndpointID, pEndpoint->Id, i));
- /* invalid endpoint */
- status = A_EPROTO;
- break;
- }
-
- if (pHdr->PayloadLen > HTC_MAX_PAYLOAD_LENGTH) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Payload length %d exceeds max HTC : %d !\n",
- pHdr->PayloadLen, (u32)HTC_MAX_PAYLOAD_LENGTH));
- status = A_EPROTO;
- break;
- }
-
- if (0 == pEndpoint->ServiceID) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Endpoint %d is not connected !\n",pHdr->EndpointID));
- /* endpoint isn't even connected */
- status = A_EPROTO;
- break;
- }
-
- if ((pHdr->Flags & HTC_FLAGS_RECV_BUNDLE_CNT_MASK) == 0) {
- /* HTC header only indicates 1 message to fetch */
- numMessages = 1;
- } else {
- /* HTC header indicates that every packet to follow has the same padded length so that it can
- * be optimally fetched as a full bundle */
- numMessages = (pHdr->Flags & HTC_FLAGS_RECV_BUNDLE_CNT_MASK) >> HTC_FLAGS_RECV_BUNDLE_CNT_SHIFT;
- /* the count doesn't include the starter frame, just a count of frames to follow */
- numMessages++;
- A_ASSERT(numMessages <= target->MaxMsgPerBundle);
- INC_HTC_EP_STAT(pEndpoint, RxBundleIndFromHdr, 1);
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
- ("HTC header indicates :%d messages can be fetched as a bundle \n",numMessages));
- }
-
- fullLength = DEV_CALC_RECV_PADDED_LEN(&target->Device,pHdr->PayloadLen + sizeof(struct htc_frame_hdr));
-
- /* get packet buffers for each message, if there was a bundle detected in the header,
- * use pHdr as a template to fetch all packets in the bundle */
- for (j = 0; j < numMessages; j++) {
-
- /* reset flag, any packets allocated using the RecvAlloc() API cannot be recycled on cleanup,
- * they must be explicitly returned */
- noRecycle = false;
-
- if (pEndpoint->EpCallBacks.EpRecvAlloc != NULL) {
- UNLOCK_HTC_RX(target);
- noRecycle = true;
- /* user is using a per-packet allocation callback */
- pPacket = pEndpoint->EpCallBacks.EpRecvAlloc(pEndpoint->EpCallBacks.pContext,
- pEndpoint->Id,
- fullLength);
- LOCK_HTC_RX(target);
-
- } else if ((pEndpoint->EpCallBacks.EpRecvAllocThresh != NULL) &&
- (fullLength > pEndpoint->EpCallBacks.RecvAllocThreshold)) {
- INC_HTC_EP_STAT(pEndpoint,RxAllocThreshHit,1);
- INC_HTC_EP_STAT(pEndpoint,RxAllocThreshBytes,pHdr->PayloadLen);
- /* threshold was hit, call the special recv allocation callback */
- UNLOCK_HTC_RX(target);
- noRecycle = true;
- /* user wants to allocate packets above a certain threshold */
- pPacket = pEndpoint->EpCallBacks.EpRecvAllocThresh(pEndpoint->EpCallBacks.pContext,
- pEndpoint->Id,
- fullLength);
- LOCK_HTC_RX(target);
-
- } else {
- /* user is using a refill handler that can refill multiple HTC buffers */
-
- /* get a packet from the endpoint recv queue */
- pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers);
-
- if (NULL == pPacket) {
- /* check for refill handler */
- if (pEndpoint->EpCallBacks.EpRecvRefill != NULL) {
- UNLOCK_HTC_RX(target);
- /* call the re-fill handler */
- pEndpoint->EpCallBacks.EpRecvRefill(pEndpoint->EpCallBacks.pContext,
- pEndpoint->Id);
- LOCK_HTC_RX(target);
- /* check if we have more buffers */
- pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers);
- /* fall through */
- }
- }
- }
-
- if (NULL == pPacket) {
- /* this is not an error, we simply need to mark that we are waiting for buffers.*/
- target->RecvStateFlags |= HTC_RECV_WAIT_BUFFERS;
- target->EpWaitingForBuffers = pEndpoint->Id;
- status = A_NO_RESOURCE;
- break;
- }
-
- AR_DEBUG_ASSERT(pPacket->Endpoint == pEndpoint->Id);
- /* clear flags */
- pPacket->PktInfo.AsRx.HTCRxFlags = 0;
- pPacket->PktInfo.AsRx.IndicationFlags = 0;
- pPacket->Status = 0;
-
- if (noRecycle) {
- /* flag that these packets cannot be recycled, they have to be returned to the
- * user */
- pPacket->PktInfo.AsRx.HTCRxFlags |= HTC_RX_PKT_NO_RECYCLE;
- }
- /* add packet to queue (also incase we need to cleanup down below) */
- HTC_PACKET_ENQUEUE(pQueue,pPacket);
-
- if (HTC_STOPPING(target)) {
- status = A_ECANCELED;
- break;
- }
-
- /* make sure this message can fit in the endpoint buffer */
- if ((u32)fullLength > pPacket->BufferLength) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("Payload Length Error : header reports payload of: %d (%d) endpoint buffer size: %d \n",
- pHdr->PayloadLen, fullLength, pPacket->BufferLength));
- status = A_EPROTO;
- break;
- }
-
- if (j > 0) {
- /* for messages fetched in a bundle the expected lookahead is unknown since we
- * are only using the lookahead of the first packet as a template of what to
- * expect for lengths */
- /* flag that once we get the real HTC header we need to refesh the information */
- pPacket->PktInfo.AsRx.HTCRxFlags |= HTC_RX_PKT_REFRESH_HDR;
- /* set it to something invalid */
- pPacket->PktInfo.AsRx.ExpectedHdr = 0xFFFFFFFF;
- } else {
-
- pPacket->PktInfo.AsRx.ExpectedHdr = LookAheads[i]; /* set expected look ahead */
- }
- /* set the amount of data to fetch */
- pPacket->ActualLength = pHdr->PayloadLen + HTC_HDR_LENGTH;
- }
-
- if (status) {
- if (A_NO_RESOURCE == status) {
- /* this is actually okay */
- status = 0;
- }
- break;
- }
-
- }
-
- UNLOCK_HTC_RX(target);
-
- if (status) {
- while (!HTC_QUEUE_EMPTY(pQueue)) {
- pPacket = HTC_PACKET_DEQUEUE(pQueue);
- /* recycle all allocated packets */
- HTC_RECYCLE_RX_PKT(target,pPacket,&target->EndPoint[pPacket->Endpoint]);
- }
- }
-
- return status;
-}
-
-static void HTCAsyncRecvScatterCompletion(struct hif_scatter_req *pScatterReq)
-{
- int i;
- struct htc_packet *pPacket;
- struct htc_endpoint *pEndpoint;
- u32 lookAheads[HTC_HOST_MAX_MSG_PER_BUNDLE];
- int numLookAheads = 0;
- struct htc_target *target = (struct htc_target *)pScatterReq->Context;
- int status;
- bool partialBundle = false;
- struct htc_packet_queue localRecvQueue;
- bool procError = false;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCAsyncRecvScatterCompletion TotLen: %d Entries: %d\n",
- pScatterReq->TotalLength, pScatterReq->ValidScatterEntries));
-
- A_ASSERT(!IS_DEV_IRQ_PROC_SYNC_MODE(&target->Device));
-
- if (pScatterReq->CompletionStatus) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("** Recv Scatter Request Failed: %d \n",pScatterReq->CompletionStatus));
- }
-
- if (pScatterReq->CallerFlags & HTC_SCATTER_REQ_FLAGS_PARTIAL_BUNDLE) {
- partialBundle = true;
- }
-
- DEV_FINISH_SCATTER_OPERATION(pScatterReq);
-
- INIT_HTC_PACKET_QUEUE(&localRecvQueue);
-
- pPacket = (struct htc_packet *)pScatterReq->ScatterList[0].pCallerContexts[0];
- /* note: all packets in a scatter req are for the same endpoint ! */
- pEndpoint = &target->EndPoint[pPacket->Endpoint];
-
- /* walk through the scatter list and process */
- /* **** NOTE: DO NOT HOLD ANY LOCKS here, HTCProcessRecvHeader can take the TX lock
- * as it processes credit reports */
- for (i = 0; i < pScatterReq->ValidScatterEntries; i++) {
- pPacket = (struct htc_packet *)pScatterReq->ScatterList[i].pCallerContexts[0];
- A_ASSERT(pPacket != NULL);
- /* reset count, we are only interested in the look ahead in the last packet when we
- * break out of this loop */
- numLookAheads = 0;
-
- if (!pScatterReq->CompletionStatus) {
- /* process header for each of the recv packets */
- status = HTCProcessRecvHeader(target,pPacket,lookAheads,&numLookAheads);
- } else {
- status = A_ERROR;
- }
-
- if (!status) {
- LOCK_HTC_RX(target);
- HTC_RX_STAT_PROFILE(target,pEndpoint,numLookAheads);
- INC_HTC_EP_STAT(pEndpoint, RxPacketsBundled, 1);
- UNLOCK_HTC_RX(target);
- if (i == (pScatterReq->ValidScatterEntries - 1)) {
- /* last packet's more packets flag is set based on the lookahead */
- SET_MORE_RX_PACKET_INDICATION_FLAG(lookAheads,numLookAheads,pEndpoint,pPacket);
- } else {
- /* packets in a bundle automatically have this flag set */
- FORCE_MORE_RX_PACKET_INDICATION_FLAG(pPacket);
- }
-
- DUMP_RECV_PKT_INFO(pPacket);
- /* since we can't hold a lock in this loop, we insert into our local recv queue for
- * storage until we can transfer them to the recv completion queue */
- HTC_PACKET_ENQUEUE(&localRecvQueue,pPacket);
-
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" Recv packet scatter entry %d failed (out of %d) \n",
- i, pScatterReq->ValidScatterEntries));
- /* recycle failed recv */
- HTC_RECYCLE_RX_PKT(target, pPacket, pEndpoint);
- /* set flag and continue processing the remaining scatter entries */
- procError = true;
- }
-
- }
-
- /* free scatter request */
- DEV_FREE_SCATTER_REQ(&target->Device,pScatterReq);
-
- LOCK_HTC_RX(target);
- /* transfer the packets in the local recv queue to the recv completion queue */
- HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->RecvIndicationQueue, &localRecvQueue);
-
- UNLOCK_HTC_RX(target);
-
- if (!procError) {
- /* pipeline the next check (asynchronously) for more packets */
- HTCAsyncRecvCheckMorePackets(target,
- lookAheads,
- numLookAheads,
- partialBundle ? false : true);
- }
-
- /* now drain the indication queue */
- DrainRecvIndicationQueue(target,pEndpoint);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCAsyncRecvScatterCompletion \n"));
-}
-
-static int HTCIssueRecvPacketBundle(struct htc_target *target,
- struct htc_packet_queue *pRecvPktQueue,
- struct htc_packet_queue *pSyncCompletionQueue,
- int *pNumPacketsFetched,
- bool PartialBundle)
-{
- int status = 0;
- struct hif_scatter_req *pScatterReq;
- int i, totalLength;
- int pktsToScatter;
- struct htc_packet *pPacket;
- bool asyncMode = (pSyncCompletionQueue == NULL) ? true : false;
- int scatterSpaceRemaining = DEV_GET_MAX_BUNDLE_RECV_LENGTH(&target->Device);
-
- pktsToScatter = HTC_PACKET_QUEUE_DEPTH(pRecvPktQueue);
- pktsToScatter = min(pktsToScatter, target->MaxMsgPerBundle);
-
- if ((HTC_PACKET_QUEUE_DEPTH(pRecvPktQueue) - pktsToScatter) > 0) {
- /* we were forced to split this bundle receive operation
- * all packets in this partial bundle must have their lookaheads ignored */
- PartialBundle = true;
- /* this would only happen if the target ignored our max bundle limit */
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
- ("HTCIssueRecvPacketBundle : partial bundle detected num:%d , %d \n",
- HTC_PACKET_QUEUE_DEPTH(pRecvPktQueue), pktsToScatter));
- }
-
- totalLength = 0;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCIssueRecvPacketBundle (Numpackets: %d , actual : %d) \n",
- HTC_PACKET_QUEUE_DEPTH(pRecvPktQueue), pktsToScatter));
-
- do {
-
- pScatterReq = DEV_ALLOC_SCATTER_REQ(&target->Device);
-
- if (pScatterReq == NULL) {
- /* no scatter resources left, just let caller handle it the legacy way */
- break;
- }
-
- pScatterReq->CallerFlags = 0;
-
- if (PartialBundle) {
- /* mark that this is a partial bundle, this has special ramifications to the
- * scatter completion routine */
- pScatterReq->CallerFlags |= HTC_SCATTER_REQ_FLAGS_PARTIAL_BUNDLE;
- }
-
- /* convert HTC packets to scatter list */
- for (i = 0; i < pktsToScatter; i++) {
- int paddedLength;
-
- pPacket = HTC_PACKET_DEQUEUE(pRecvPktQueue);
- A_ASSERT(pPacket != NULL);
-
- paddedLength = DEV_CALC_RECV_PADDED_LEN(&target->Device, pPacket->ActualLength);
-
- if ((scatterSpaceRemaining - paddedLength) < 0) {
- /* exceeds what we can transfer, put the packet back */
- HTC_PACKET_ENQUEUE_TO_HEAD(pRecvPktQueue,pPacket);
- break;
- }
-
- scatterSpaceRemaining -= paddedLength;
-
- if (PartialBundle || (i < (pktsToScatter - 1))) {
- /* packet 0..n-1 cannot be checked for look-aheads since we are fetching a bundle
- * the last packet however can have it's lookahead used */
- pPacket->PktInfo.AsRx.HTCRxFlags |= HTC_RX_PKT_IGNORE_LOOKAHEAD;
- }
-
- /* note: 1 HTC packet per scatter entry */
- /* setup packet into */
- pScatterReq->ScatterList[i].pBuffer = pPacket->pBuffer;
- pScatterReq->ScatterList[i].Length = paddedLength;
-
- pPacket->PktInfo.AsRx.HTCRxFlags |= HTC_RX_PKT_PART_OF_BUNDLE;
-
- if (asyncMode) {
- /* save HTC packet for async completion routine */
- pScatterReq->ScatterList[i].pCallerContexts[0] = pPacket;
- } else {
- /* queue to caller's sync completion queue, caller will unload this when we return */
- HTC_PACKET_ENQUEUE(pSyncCompletionQueue,pPacket);
- }
-
- A_ASSERT(pScatterReq->ScatterList[i].Length);
- totalLength += pScatterReq->ScatterList[i].Length;
- }
-
- pScatterReq->TotalLength = totalLength;
- pScatterReq->ValidScatterEntries = i;
-
- if (asyncMode) {
- pScatterReq->CompletionRoutine = HTCAsyncRecvScatterCompletion;
- pScatterReq->Context = target;
- }
-
- status = DevSubmitScatterRequest(&target->Device, pScatterReq, DEV_SCATTER_READ, asyncMode);
-
- if (!status) {
- *pNumPacketsFetched = i;
- }
-
- if (!asyncMode) {
- /* free scatter request */
- DEV_FREE_SCATTER_REQ(&target->Device, pScatterReq);
- }
-
- } while (false);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCIssueRecvPacketBundle (status:%d) (fetched:%d) \n",
- status,*pNumPacketsFetched));
-
- return status;
-}
-
-static INLINE void CheckRecvWaterMark(struct htc_endpoint *pEndpoint)
-{
- /* see if endpoint is using a refill watermark
- * ** no need to use a lock here, since we are only inspecting...
- * caller may must not hold locks when calling this function */
- if (pEndpoint->EpCallBacks.RecvRefillWaterMark > 0) {
- if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->RxBuffers) < pEndpoint->EpCallBacks.RecvRefillWaterMark) {
- /* call the re-fill handler before we continue */
- pEndpoint->EpCallBacks.EpRecvRefill(pEndpoint->EpCallBacks.pContext,
- pEndpoint->Id);
- }
- }
-}
-
-/* callback when device layer or lookahead report parsing detects a pending message */
-int HTCRecvMessagePendingHandler(void *Context, u32 MsgLookAheads[], int NumLookAheads, bool *pAsyncProc, int *pNumPktsFetched)
-{
- struct htc_target *target = (struct htc_target *)Context;
- int status = 0;
- struct htc_packet *pPacket;
- struct htc_endpoint *pEndpoint;
- bool asyncProc = false;
- u32 lookAheads[HTC_HOST_MAX_MSG_PER_BUNDLE];
- int pktsFetched;
- struct htc_packet_queue recvPktQueue, syncCompletedPktsQueue;
- bool partialBundle;
- HTC_ENDPOINT_ID id;
- int totalFetched = 0;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCRecvMessagePendingHandler NumLookAheads: %d \n",NumLookAheads));
-
- if (pNumPktsFetched != NULL) {
- *pNumPktsFetched = 0;
- }
-
- if (IS_DEV_IRQ_PROCESSING_ASYNC_ALLOWED(&target->Device)) {
- /* We use async mode to get the packets if the device layer supports it.
- * The device layer interfaces with HIF in which HIF may have restrictions on
- * how interrupts are processed */
- asyncProc = true;
- }
-
- if (pAsyncProc != NULL) {
- /* indicate to caller how we decided to process this */
- *pAsyncProc = asyncProc;
- }
-
- if (NumLookAheads > HTC_HOST_MAX_MSG_PER_BUNDLE) {
- A_ASSERT(false);
- return A_EPROTO;
- }
-
- /* on first entry copy the lookaheads into our temp array for processing */
- memcpy(lookAheads, MsgLookAheads, (sizeof(u32)) * NumLookAheads);
-
- while (true) {
-
- /* reset packets queues */
- INIT_HTC_PACKET_QUEUE(&recvPktQueue);
- INIT_HTC_PACKET_QUEUE(&syncCompletedPktsQueue);
-
- if (NumLookAheads > HTC_HOST_MAX_MSG_PER_BUNDLE) {
- status = A_EPROTO;
- A_ASSERT(false);
- break;
- }
-
- /* first lookahead sets the expected endpoint IDs for all packets in a bundle */
- id = ((struct htc_frame_hdr *)&lookAheads[0])->EndpointID;
- pEndpoint = &target->EndPoint[id];
-
- if (id >= ENDPOINT_MAX) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("MsgPend, Invalid Endpoint in look-ahead: %d \n",id));
- status = A_EPROTO;
- break;
- }
-
- /* try to allocate as many HTC RX packets indicated by the lookaheads
- * these packets are stored in the recvPkt queue */
- status = AllocAndPrepareRxPackets(target,
- lookAheads,
- NumLookAheads,
- pEndpoint,
- &recvPktQueue);
- if (status) {
- break;
- }
-
- if (HTC_PACKET_QUEUE_DEPTH(&recvPktQueue) >= 2) {
- /* a recv bundle was detected, force IRQ status re-check again */
- REF_IRQ_STATUS_RECHECK(&target->Device);
- }
-
- totalFetched += HTC_PACKET_QUEUE_DEPTH(&recvPktQueue);
-
- /* we've got packet buffers for all we can currently fetch,
- * this count is not valid anymore */
- NumLookAheads = 0;
- partialBundle = false;
-
- /* now go fetch the list of HTC packets */
- while (!HTC_QUEUE_EMPTY(&recvPktQueue)) {
-
- pktsFetched = 0;
-
- if (target->RecvBundlingEnabled && (HTC_PACKET_QUEUE_DEPTH(&recvPktQueue) > 1)) {
- /* there are enough packets to attempt a bundle transfer and recv bundling is allowed */
- status = HTCIssueRecvPacketBundle(target,
- &recvPktQueue,
- asyncProc ? NULL : &syncCompletedPktsQueue,
- &pktsFetched,
- partialBundle);
- if (status) {
- break;
- }
-
- if (HTC_PACKET_QUEUE_DEPTH(&recvPktQueue) != 0) {
- /* we couldn't fetch all packets at one time, this creates a broken
- * bundle */
- partialBundle = true;
- }
- }
-
- /* see if the previous operation fetched any packets using bundling */
- if (0 == pktsFetched) {
- /* dequeue one packet */
- pPacket = HTC_PACKET_DEQUEUE(&recvPktQueue);
- A_ASSERT(pPacket != NULL);
-
- if (asyncProc) {
- /* we use async mode to get the packet if the device layer supports it
- * set our callback and context */
- pPacket->Completion = HTCRecvCompleteHandler;
- pPacket->pContext = target;
- } else {
- /* fully synchronous */
- pPacket->Completion = NULL;
- }
-
- if (HTC_PACKET_QUEUE_DEPTH(&recvPktQueue) > 0) {
- /* lookaheads in all packets except the last one in the bundle must be ignored */
- pPacket->PktInfo.AsRx.HTCRxFlags |= HTC_RX_PKT_IGNORE_LOOKAHEAD;
- }
-
- /* go fetch the packet */
- status = HTCIssueRecv(target, pPacket);
- if (status) {
- break;
- }
-
- if (!asyncProc) {
- /* sent synchronously, queue this packet for synchronous completion */
- HTC_PACKET_ENQUEUE(&syncCompletedPktsQueue,pPacket);
- }
-
- }
-
- }
-
- if (!status) {
- CheckRecvWaterMark(pEndpoint);
- }
-
- if (asyncProc) {
- /* we did this asynchronously so we can get out of the loop, the asynch processing
- * creates a chain of requests to continue processing pending messages in the
- * context of callbacks */
- break;
- }
-
- /* synchronous handling */
- if (target->Device.DSRCanYield) {
- /* for the SYNC case, increment count that tracks when the DSR should yield */
- target->Device.CurrentDSRRecvCount++;
- }
-
- /* in the sync case, all packet buffers are now filled,
- * we can process each packet, check lookaheads and then repeat */
-
- /* unload sync completion queue */
- while (!HTC_QUEUE_EMPTY(&syncCompletedPktsQueue)) {
- struct htc_packet_queue container;
-
- pPacket = HTC_PACKET_DEQUEUE(&syncCompletedPktsQueue);
- A_ASSERT(pPacket != NULL);
-
- pEndpoint = &target->EndPoint[pPacket->Endpoint];
- /* reset count on each iteration, we are only interested in the last packet's lookahead
- * information when we break out of this loop */
- NumLookAheads = 0;
- /* process header for each of the recv packets
- * note: the lookahead of the last packet is useful for us to continue in this loop */
- status = HTCProcessRecvHeader(target,pPacket,lookAheads,&NumLookAheads);
- if (status) {
- break;
- }
-
- if (HTC_QUEUE_EMPTY(&syncCompletedPktsQueue)) {
- /* last packet's more packets flag is set based on the lookahead */
- SET_MORE_RX_PACKET_INDICATION_FLAG(lookAheads,NumLookAheads,pEndpoint,pPacket);
- } else {
- /* packets in a bundle automatically have this flag set */
- FORCE_MORE_RX_PACKET_INDICATION_FLAG(pPacket);
- }
- /* good packet, indicate it */
- HTC_RX_STAT_PROFILE(target,pEndpoint,NumLookAheads);
-
- if (pPacket->PktInfo.AsRx.HTCRxFlags & HTC_RX_PKT_PART_OF_BUNDLE) {
- INC_HTC_EP_STAT(pEndpoint, RxPacketsBundled, 1);
- }
-
- INIT_HTC_PACKET_QUEUE_AND_ADD(&container,pPacket);
- DO_RCV_COMPLETION(pEndpoint,&container);
- }
-
- if (status) {
- break;
- }
-
- if (NumLookAheads == 0) {
- /* no more look aheads */
- break;
- }
-
- /* when we process recv synchronously we need to check if we should yield and stop
- * fetching more packets indicated by the embedded lookaheads */
- if (target->Device.DSRCanYield) {
- if (DEV_CHECK_RECV_YIELD(&target->Device)) {
- /* break out, don't fetch any more packets */
- break;
- }
- }
-
-
- /* check whether other OS contexts have queued any WMI command/data for WLAN.
- * This check is needed only if WLAN Tx and Rx happens in same thread context */
- A_CHECK_DRV_TX();
-
- /* for SYNCH processing, if we get here, we are running through the loop again due to a detected lookahead.
- * Set flag that we should re-check IRQ status registers again before leaving IRQ processing,
- * this can net better performance in high throughput situations */
- REF_IRQ_STATUS_RECHECK(&target->Device);
- }
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("Failed to get pending recv messages (%d) \n",status));
- /* cleanup any packets we allocated but didn't use to actually fetch any packets */
- while (!HTC_QUEUE_EMPTY(&recvPktQueue)) {
- pPacket = HTC_PACKET_DEQUEUE(&recvPktQueue);
- /* clean up packets */
- HTC_RECYCLE_RX_PKT(target, pPacket, &target->EndPoint[pPacket->Endpoint]);
- }
- /* cleanup any packets in sync completion queue */
- while (!HTC_QUEUE_EMPTY(&syncCompletedPktsQueue)) {
- pPacket = HTC_PACKET_DEQUEUE(&syncCompletedPktsQueue);
- /* clean up packets */
- HTC_RECYCLE_RX_PKT(target, pPacket, &target->EndPoint[pPacket->Endpoint]);
- }
- if (HTC_STOPPING(target)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
- (" Host is going to stop. blocking receiver for HTCStop.. \n"));
- DevStopRecv(&target->Device, asyncProc ? DEV_STOP_RECV_ASYNC : DEV_STOP_RECV_SYNC);
- }
- }
- /* before leaving, check to see if host ran out of buffers and needs to stop the
- * receiver */
- if (target->RecvStateFlags & HTC_RECV_WAIT_BUFFERS) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
- (" Host has no RX buffers, blocking receiver to prevent overrun.. \n"));
- /* try to stop receive at the device layer */
- DevStopRecv(&target->Device, asyncProc ? DEV_STOP_RECV_ASYNC : DEV_STOP_RECV_SYNC);
- }
-
- if (pNumPktsFetched != NULL) {
- *pNumPktsFetched = totalFetched;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCRecvMessagePendingHandler \n"));
-
- return status;
-}
-
-int HTCAddReceivePktMultiple(HTC_HANDLE HTCHandle, struct htc_packet_queue *pPktQueue)
-{
- struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
- struct htc_endpoint *pEndpoint;
- bool unblockRecv = false;
- int status = 0;
- struct htc_packet *pFirstPacket;
-
- pFirstPacket = HTC_GET_PKT_AT_HEAD(pPktQueue);
-
- if (NULL == pFirstPacket) {
- A_ASSERT(false);
- return A_EINVAL;
- }
-
- AR_DEBUG_ASSERT(pFirstPacket->Endpoint < ENDPOINT_MAX);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
- ("+- HTCAddReceivePktMultiple : endPointId: %d, cnt:%d, length: %d\n",
- pFirstPacket->Endpoint,
- HTC_PACKET_QUEUE_DEPTH(pPktQueue),
- pFirstPacket->BufferLength));
-
- do {
-
- pEndpoint = &target->EndPoint[pFirstPacket->Endpoint];
-
- LOCK_HTC_RX(target);
-
- if (HTC_STOPPING(target)) {
- struct htc_packet *pPacket;
-
- UNLOCK_HTC_RX(target);
-
- /* walk through queue and mark each one canceled */
- HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue,pPacket) {
- pPacket->Status = A_ECANCELED;
- } HTC_PACKET_QUEUE_ITERATE_END;
-
- DO_RCV_COMPLETION(pEndpoint,pPktQueue);
- break;
- }
-
- /* store receive packets */
- HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->RxBuffers, pPktQueue);
-
- /* check if we are blocked waiting for a new buffer */
- if (target->RecvStateFlags & HTC_RECV_WAIT_BUFFERS) {
- if (target->EpWaitingForBuffers == pFirstPacket->Endpoint) {
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,(" receiver was blocked on ep:%d, unblocking.. \n",
- target->EpWaitingForBuffers));
- target->RecvStateFlags &= ~HTC_RECV_WAIT_BUFFERS;
- target->EpWaitingForBuffers = ENDPOINT_MAX;
- unblockRecv = true;
- }
- }
-
- UNLOCK_HTC_RX(target);
-
- if (unblockRecv && !HTC_STOPPING(target)) {
- /* TODO : implement a buffer threshold count? */
- DevEnableRecv(&target->Device,DEV_ENABLE_RECV_SYNC);
- }
-
- } while (false);
-
- return status;
-}
-
-/* Makes a buffer available to the HTC module */
-int HTCAddReceivePkt(HTC_HANDLE HTCHandle, struct htc_packet *pPacket)
-{
- struct htc_packet_queue queue;
- INIT_HTC_PACKET_QUEUE_AND_ADD(&queue,pPacket);
- return HTCAddReceivePktMultiple(HTCHandle, &queue);
-}
-
-void HTCUnblockRecv(HTC_HANDLE HTCHandle)
-{
- struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
- bool unblockRecv = false;
-
- LOCK_HTC_RX(target);
-
- /* check if we are blocked waiting for a new buffer */
- if (target->RecvStateFlags & HTC_RECV_WAIT_BUFFERS) {
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("HTCUnblockRx : receiver was blocked on ep:%d, unblocking.. \n",
- target->EpWaitingForBuffers));
- target->RecvStateFlags &= ~HTC_RECV_WAIT_BUFFERS;
- target->EpWaitingForBuffers = ENDPOINT_MAX;
- unblockRecv = true;
- }
-
- UNLOCK_HTC_RX(target);
-
- if (unblockRecv && !HTC_STOPPING(target)) {
- /* re-enable */
- DevEnableRecv(&target->Device,DEV_ENABLE_RECV_ASYNC);
- }
-}
-
-static void HTCFlushRxQueue(struct htc_target *target, struct htc_endpoint *pEndpoint, struct htc_packet_queue *pQueue)
-{
- struct htc_packet *pPacket;
- struct htc_packet_queue container;
-
- LOCK_HTC_RX(target);
-
- while (1) {
- pPacket = HTC_PACKET_DEQUEUE(pQueue);
- if (NULL == pPacket) {
- break;
- }
- UNLOCK_HTC_RX(target);
- pPacket->Status = A_ECANCELED;
- pPacket->ActualLength = 0;
- AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" Flushing RX packet:0x%lX, length:%d, ep:%d \n",
- (unsigned long)pPacket, pPacket->BufferLength, pPacket->Endpoint));
- INIT_HTC_PACKET_QUEUE_AND_ADD(&container,pPacket);
- /* give the packet back */
- DO_RCV_COMPLETION(pEndpoint,&container);
- LOCK_HTC_RX(target);
- }
-
- UNLOCK_HTC_RX(target);
-}
-
-static void HTCFlushEndpointRX(struct htc_target *target, struct htc_endpoint *pEndpoint)
-{
- /* flush any recv indications not already made */
- HTCFlushRxQueue(target,pEndpoint,&pEndpoint->RecvIndicationQueue);
- /* flush any rx buffers */
- HTCFlushRxQueue(target,pEndpoint,&pEndpoint->RxBuffers);
-}
-
-void HTCFlushRecvBuffers(struct htc_target *target)
-{
- struct htc_endpoint *pEndpoint;
- int i;
-
- for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
- pEndpoint = &target->EndPoint[i];
- if (pEndpoint->ServiceID == 0) {
- /* not in use.. */
- continue;
- }
- HTCFlushEndpointRX(target,pEndpoint);
- }
-}
-
-
-void HTCEnableRecv(HTC_HANDLE HTCHandle)
-{
- struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
-
- if (!HTC_STOPPING(target)) {
- /* re-enable */
- DevEnableRecv(&target->Device,DEV_ENABLE_RECV_SYNC);
- }
-}
-
-void HTCDisableRecv(HTC_HANDLE HTCHandle)
-{
- struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
-
- if (!HTC_STOPPING(target)) {
- /* disable */
- DevStopRecv(&target->Device,DEV_ENABLE_RECV_SYNC);
- }
-}
-
-int HTCGetNumRecvBuffers(HTC_HANDLE HTCHandle,
- HTC_ENDPOINT_ID Endpoint)
-{
- struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
- return HTC_PACKET_QUEUE_DEPTH(&(target->EndPoint[Endpoint].RxBuffers));
-}
-
-int HTCWaitForPendingRecv(HTC_HANDLE HTCHandle,
- u32 TimeoutInMs,
- bool *pbIsRecvPending)
-{
- int status = 0;
- struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
-
- status = DevWaitForPendingRecv(&target->Device,
- TimeoutInMs,
- pbIsRecvPending);
-
- return status;
-}
diff --git a/drivers/staging/ath6kl/htc2/htc_send.c b/drivers/staging/ath6kl/htc2/htc_send.c
deleted file mode 100644
index 9310d4d5c992..000000000000
--- a/drivers/staging/ath6kl/htc2/htc_send.c
+++ /dev/null
@@ -1,1018 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="htc_send.c" company="Atheros">
-// Copyright (c) 2007-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-#include "htc_internal.h"
-
-typedef enum _HTC_SEND_QUEUE_RESULT {
- HTC_SEND_QUEUE_OK = 0, /* packet was queued */
- HTC_SEND_QUEUE_DROP = 1, /* this packet should be dropped */
-} HTC_SEND_QUEUE_RESULT;
-
-#define DO_EP_TX_COMPLETION(ep,q) DoSendCompletion(ep,q)
-
-/* call the distribute credits callback with the distribution */
-#define DO_DISTRIBUTION(t,reason,description,pList) \
-{ \
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND, \
- (" calling distribute function (%s) (dfn:0x%lX, ctxt:0x%lX, dist:0x%lX) \n", \
- (description), \
- (unsigned long)(t)->DistributeCredits, \
- (unsigned long)(t)->pCredDistContext, \
- (unsigned long)pList)); \
- (t)->DistributeCredits((t)->pCredDistContext, \
- (pList), \
- (reason)); \
-}
-
-static void DoSendCompletion(struct htc_endpoint *pEndpoint,
- struct htc_packet_queue *pQueueToIndicate)
-{
- do {
-
- if (HTC_QUEUE_EMPTY(pQueueToIndicate)) {
- /* nothing to indicate */
- break;
- }
-
- if (pEndpoint->EpCallBacks.EpTxCompleteMultiple != NULL) {
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" HTC calling ep %d, send complete multiple callback (%d pkts) \n",
- pEndpoint->Id, HTC_PACKET_QUEUE_DEPTH(pQueueToIndicate)));
- /* a multiple send complete handler is being used, pass the queue to the handler */
- pEndpoint->EpCallBacks.EpTxCompleteMultiple(pEndpoint->EpCallBacks.pContext,
- pQueueToIndicate);
- /* all packets are now owned by the callback, reset queue to be safe */
- INIT_HTC_PACKET_QUEUE(pQueueToIndicate);
- } else {
- struct htc_packet *pPacket;
- /* using legacy EpTxComplete */
- do {
- pPacket = HTC_PACKET_DEQUEUE(pQueueToIndicate);
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" HTC calling ep %d send complete callback on packet 0x%lX \n", \
- pEndpoint->Id, (unsigned long)(pPacket)));
- pEndpoint->EpCallBacks.EpTxComplete(pEndpoint->EpCallBacks.pContext, pPacket);
- } while (!HTC_QUEUE_EMPTY(pQueueToIndicate));
- }
-
- } while (false);
-
-}
-
-/* do final completion on sent packet */
-static INLINE void CompleteSentPacket(struct htc_target *target, struct htc_endpoint *pEndpoint, struct htc_packet *pPacket)
-{
- pPacket->Completion = NULL;
-
- if (pPacket->Status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("CompleteSentPacket: request failed (status:%d, ep:%d, length:%d creds:%d) \n",
- pPacket->Status, pPacket->Endpoint, pPacket->ActualLength, pPacket->PktInfo.AsTx.CreditsUsed));
- /* on failure to submit, reclaim credits for this packet */
- LOCK_HTC_TX(target);
- pEndpoint->CreditDist.TxCreditsToDist += pPacket->PktInfo.AsTx.CreditsUsed;
- pEndpoint->CreditDist.TxQueueDepth = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue);
- DO_DISTRIBUTION(target,
- HTC_CREDIT_DIST_SEND_COMPLETE,
- "Send Complete",
- target->EpCreditDistributionListHead->pNext);
- UNLOCK_HTC_TX(target);
- }
- /* first, fixup the head room we allocated */
- pPacket->pBuffer += HTC_HDR_LENGTH;
-}
-
-/* our internal send packet completion handler when packets are submited to the AR6K device
- * layer */
-static void HTCSendPktCompletionHandler(void *Context, struct htc_packet *pPacket)
-{
- struct htc_target *target = (struct htc_target *)Context;
- struct htc_endpoint *pEndpoint = &target->EndPoint[pPacket->Endpoint];
- struct htc_packet_queue container;
-
- CompleteSentPacket(target,pEndpoint,pPacket);
- INIT_HTC_PACKET_QUEUE_AND_ADD(&container,pPacket);
- /* do completion */
- DO_EP_TX_COMPLETION(pEndpoint,&container);
-}
-
-int HTCIssueSend(struct htc_target *target, struct htc_packet *pPacket)
-{
- int status;
- bool sync = false;
-
- if (pPacket->Completion == NULL) {
- /* mark that this request was synchronously issued */
- sync = true;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
- ("+-HTCIssueSend: transmit length : %d (%s) \n",
- pPacket->ActualLength + (u32)HTC_HDR_LENGTH,
- sync ? "SYNC" : "ASYNC" ));
-
- /* send message to device */
- status = DevSendPacket(&target->Device,
- pPacket,
- pPacket->ActualLength + HTC_HDR_LENGTH);
-
- if (sync) {
- /* use local sync variable. If this was issued asynchronously, pPacket is no longer
- * safe to access. */
- pPacket->pBuffer += HTC_HDR_LENGTH;
- }
-
- /* if this request was asynchronous, the packet completion routine will be invoked by
- * the device layer when the HIF layer completes the request */
-
- return status;
-}
-
- /* get HTC send packets from the TX queue on an endpoint */
-static INLINE void GetHTCSendPackets(struct htc_target *target,
- struct htc_endpoint *pEndpoint,
- struct htc_packet_queue *pQueue)
-{
- int creditsRequired;
- int remainder;
- u8 sendFlags;
- struct htc_packet *pPacket;
- unsigned int transferLength;
-
- /****** NOTE : the TX lock is held when this function is called *****************/
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+GetHTCSendPackets \n"));
-
- /* loop until we can grab as many packets out of the queue as we can */
- while (true) {
-
- sendFlags = 0;
- /* get packet at head, but don't remove it */
- pPacket = HTC_GET_PKT_AT_HEAD(&pEndpoint->TxQueue);
- if (pPacket == NULL) {
- break;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Got head packet:0x%lX , Queue Depth: %d\n",
- (unsigned long)pPacket, HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)));
-
- transferLength = DEV_CALC_SEND_PADDED_LEN(&target->Device, pPacket->ActualLength + HTC_HDR_LENGTH);
-
- if (transferLength <= target->TargetCreditSize) {
- creditsRequired = 1;
- } else {
- /* figure out how many credits this message requires */
- creditsRequired = transferLength / target->TargetCreditSize;
- remainder = transferLength % target->TargetCreditSize;
-
- if (remainder) {
- creditsRequired++;
- }
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Creds Required:%d Got:%d\n",
- creditsRequired, pEndpoint->CreditDist.TxCredits));
-
- if (pEndpoint->CreditDist.TxCredits < creditsRequired) {
-
- /* not enough credits */
- if (pPacket->Endpoint == ENDPOINT_0) {
- /* leave it in the queue */
- break;
- }
- /* invoke the registered distribution function only if this is not
- * endpoint 0, we let the driver layer provide more credits if it can.
- * We pass the credit distribution list starting at the endpoint in question
- * */
-
- /* set how many credits we need */
- pEndpoint->CreditDist.TxCreditsSeek =
- creditsRequired - pEndpoint->CreditDist.TxCredits;
- DO_DISTRIBUTION(target,
- HTC_CREDIT_DIST_SEEK_CREDITS,
- "Seek Credits",
- &pEndpoint->CreditDist);
- pEndpoint->CreditDist.TxCreditsSeek = 0;
-
- if (pEndpoint->CreditDist.TxCredits < creditsRequired) {
- /* still not enough credits to send, leave packet in the queue */
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
- (" Not enough credits for ep %d leaving packet in queue..\n",
- pPacket->Endpoint));
- break;
- }
-
- }
-
- pEndpoint->CreditDist.TxCredits -= creditsRequired;
- INC_HTC_EP_STAT(pEndpoint, TxCreditsConsummed, creditsRequired);
-
- /* check if we need credits back from the target */
- if (pEndpoint->CreditDist.TxCredits < pEndpoint->CreditDist.TxCreditsPerMaxMsg) {
- /* we are getting low on credits, see if we can ask for more from the distribution function */
- pEndpoint->CreditDist.TxCreditsSeek =
- pEndpoint->CreditDist.TxCreditsPerMaxMsg - pEndpoint->CreditDist.TxCredits;
-
- DO_DISTRIBUTION(target,
- HTC_CREDIT_DIST_SEEK_CREDITS,
- "Seek Credits",
- &pEndpoint->CreditDist);
-
- pEndpoint->CreditDist.TxCreditsSeek = 0;
- /* see if we were successful in getting more */
- if (pEndpoint->CreditDist.TxCredits < pEndpoint->CreditDist.TxCreditsPerMaxMsg) {
- /* tell the target we need credits ASAP! */
- sendFlags |= HTC_FLAGS_NEED_CREDIT_UPDATE;
- INC_HTC_EP_STAT(pEndpoint, TxCreditLowIndications, 1);
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Host Needs Credits \n"));
- }
- }
-
- /* now we can fully dequeue */
- pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->TxQueue);
- /* save the number of credits this packet consumed */
- pPacket->PktInfo.AsTx.CreditsUsed = creditsRequired;
- /* all TX packets are handled asynchronously */
- pPacket->Completion = HTCSendPktCompletionHandler;
- pPacket->pContext = target;
- INC_HTC_EP_STAT(pEndpoint, TxIssued, 1);
- /* save send flags */
- pPacket->PktInfo.AsTx.SendFlags = sendFlags;
- pPacket->PktInfo.AsTx.SeqNo = pEndpoint->SeqNo;
- pEndpoint->SeqNo++;
- /* queue this packet into the caller's queue */
- HTC_PACKET_ENQUEUE(pQueue,pPacket);
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-GetHTCSendPackets \n"));
-
-}
-
-static void HTCAsyncSendScatterCompletion(struct hif_scatter_req *pScatterReq)
-{
- int i;
- struct htc_packet *pPacket;
- struct htc_endpoint *pEndpoint = (struct htc_endpoint *)pScatterReq->Context;
- struct htc_target *target = (struct htc_target *)pEndpoint->target;
- int status = 0;
- struct htc_packet_queue sendCompletes;
-
- INIT_HTC_PACKET_QUEUE(&sendCompletes);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HTCAsyncSendScatterCompletion TotLen: %d Entries: %d\n",
- pScatterReq->TotalLength, pScatterReq->ValidScatterEntries));
-
- DEV_FINISH_SCATTER_OPERATION(pScatterReq);
-
- if (pScatterReq->CompletionStatus) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("** Send Scatter Request Failed: %d \n",pScatterReq->CompletionStatus));
- status = A_ERROR;
- }
-
- /* walk through the scatter list and process */
- for (i = 0; i < pScatterReq->ValidScatterEntries; i++) {
- pPacket = (struct htc_packet *)(pScatterReq->ScatterList[i].pCallerContexts[0]);
- A_ASSERT(pPacket != NULL);
- pPacket->Status = status;
- CompleteSentPacket(target,pEndpoint,pPacket);
- /* add it to the completion queue */
- HTC_PACKET_ENQUEUE(&sendCompletes, pPacket);
- }
-
- /* free scatter request */
- DEV_FREE_SCATTER_REQ(&target->Device,pScatterReq);
- /* complete all packets */
- DO_EP_TX_COMPLETION(pEndpoint,&sendCompletes);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCAsyncSendScatterCompletion \n"));
-}
-
- /* drain a queue and send as bundles
- * this function may return without fully draining the queue under the following conditions :
- * - scatter resources are exhausted
- * - a message that will consume a partial credit will stop the bundling process early
- * - we drop below the minimum number of messages for a bundle
- * */
-static void HTCIssueSendBundle(struct htc_endpoint *pEndpoint,
- struct htc_packet_queue *pQueue,
- int *pBundlesSent,
- int *pTotalBundlesPkts)
-{
- int pktsToScatter;
- unsigned int scatterSpaceRemaining;
- struct hif_scatter_req *pScatterReq = NULL;
- int i, packetsInScatterReq;
- unsigned int transferLength;
- struct htc_packet *pPacket;
- bool done = false;
- int bundlesSent = 0;
- int totalPktsInBundle = 0;
- struct htc_target *target = pEndpoint->target;
- int creditRemainder = 0;
- int creditPad;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HTCIssueSendBundle \n"));
-
- while (!done) {
-
- pktsToScatter = HTC_PACKET_QUEUE_DEPTH(pQueue);
- pktsToScatter = min(pktsToScatter, target->MaxMsgPerBundle);
-
- if (pktsToScatter < HTC_MIN_HTC_MSGS_TO_BUNDLE) {
- /* not enough to bundle */
- break;
- }
-
- pScatterReq = DEV_ALLOC_SCATTER_REQ(&target->Device);
-
- if (pScatterReq == NULL) {
- /* no scatter resources */
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" No more scatter resources \n"));
- break;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" pkts to scatter: %d \n", pktsToScatter));
-
- pScatterReq->TotalLength = 0;
- pScatterReq->ValidScatterEntries = 0;
-
- packetsInScatterReq = 0;
- scatterSpaceRemaining = DEV_GET_MAX_BUNDLE_SEND_LENGTH(&target->Device);
-
- for (i = 0; i < pktsToScatter; i++) {
-
- pScatterReq->ScatterList[i].pCallerContexts[0] = NULL;
-
- pPacket = HTC_GET_PKT_AT_HEAD(pQueue);
- if (pPacket == NULL) {
- A_ASSERT(false);
- break;
- }
-
- creditPad = 0;
- transferLength = DEV_CALC_SEND_PADDED_LEN(&target->Device,
- pPacket->ActualLength + HTC_HDR_LENGTH);
- /* see if the padded transfer length falls on a credit boundary */
- creditRemainder = transferLength % target->TargetCreditSize;
-
- if (creditRemainder != 0) {
- /* the transfer consumes a "partial" credit, this packet cannot be bundled unless
- * we add additional "dummy" padding (max 255 bytes) to consume the entire credit
- *** NOTE: only allow the send padding if the endpoint is allowed to */
- if (pEndpoint->LocalConnectionFlags & HTC_LOCAL_CONN_FLAGS_ENABLE_SEND_BUNDLE_PADDING) {
- if (transferLength < target->TargetCreditSize) {
- /* special case where the transfer is less than a credit */
- creditPad = target->TargetCreditSize - transferLength;
- } else {
- creditPad = creditRemainder;
- }
-
- /* now check to see if we can indicate padding in the HTC header */
- if ((creditPad > 0) && (creditPad <= 255)) {
- /* adjust the transferlength of this packet with the new credit padding */
- transferLength += creditPad;
- } else {
- /* the amount to pad is too large, bail on this packet, we have to
- * send it using the non-bundled method */
- pPacket = NULL;
- }
- } else {
- /* bail on this packet, user does not want padding applied */
- pPacket = NULL;
- }
- }
-
- if (NULL == pPacket) {
- /* can't bundle */
- done = true;
- break;
- }
-
- if (scatterSpaceRemaining < transferLength) {
- /* exceeds what we can transfer */
- break;
- }
-
- scatterSpaceRemaining -= transferLength;
- /* now remove it from the queue */
- pPacket = HTC_PACKET_DEQUEUE(pQueue);
- /* save it in the scatter list */
- pScatterReq->ScatterList[i].pCallerContexts[0] = pPacket;
- /* prepare packet and flag message as part of a send bundle */
- HTC_PREPARE_SEND_PKT(pPacket,
- pPacket->PktInfo.AsTx.SendFlags | HTC_FLAGS_SEND_BUNDLE,
- creditPad,
- pPacket->PktInfo.AsTx.SeqNo);
- pScatterReq->ScatterList[i].pBuffer = pPacket->pBuffer;
- pScatterReq->ScatterList[i].Length = transferLength;
- A_ASSERT(transferLength);
- pScatterReq->TotalLength += transferLength;
- pScatterReq->ValidScatterEntries++;
- packetsInScatterReq++;
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" %d, Adding packet : 0x%lX, len:%d (remaining space:%d) \n",
- i, (unsigned long)pPacket,transferLength,scatterSpaceRemaining));
- }
-
- if (packetsInScatterReq >= HTC_MIN_HTC_MSGS_TO_BUNDLE) {
- /* send path is always asynchronous */
- pScatterReq->CompletionRoutine = HTCAsyncSendScatterCompletion;
- pScatterReq->Context = pEndpoint;
- bundlesSent++;
- totalPktsInBundle += packetsInScatterReq;
- packetsInScatterReq = 0;
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Send Scatter total bytes: %d , entries: %d\n",
- pScatterReq->TotalLength,pScatterReq->ValidScatterEntries));
- DevSubmitScatterRequest(&target->Device, pScatterReq, DEV_SCATTER_WRITE, DEV_SCATTER_ASYNC);
- /* we don't own this anymore */
- pScatterReq = NULL;
- /* try to send some more */
- continue;
- }
-
- /* not enough packets to use the scatter request, cleanup */
- if (pScatterReq != NULL) {
- if (packetsInScatterReq > 0) {
- /* work backwards to requeue requests */
- for (i = (packetsInScatterReq - 1); i >= 0; i--) {
- pPacket = (struct htc_packet *)(pScatterReq->ScatterList[i].pCallerContexts[0]);
- if (pPacket != NULL) {
- /* undo any prep */
- HTC_UNPREPARE_SEND_PKT(pPacket);
- /* queue back to the head */
- HTC_PACKET_ENQUEUE_TO_HEAD(pQueue,pPacket);
- }
- }
- }
- DEV_FREE_SCATTER_REQ(&target->Device,pScatterReq);
- }
-
- /* if we get here, we sent all that we could, get out */
- break;
-
- }
-
- *pBundlesSent = bundlesSent;
- *pTotalBundlesPkts = totalPktsInBundle;
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCIssueSendBundle (sent:%d) \n",bundlesSent));
-
- return;
-}
-
-/*
- * if there are no credits, the packet(s) remains in the queue.
- * this function returns the result of the attempt to send a queue of HTC packets */
-static HTC_SEND_QUEUE_RESULT HTCTrySend(struct htc_target *target,
- struct htc_endpoint *pEndpoint,
- struct htc_packet_queue *pCallersSendQueue)
-{
- struct htc_packet_queue sendQueue; /* temp queue to hold packets at various stages */
- struct htc_packet *pPacket;
- int bundlesSent;
- int pktsInBundles;
- int overflow;
- HTC_SEND_QUEUE_RESULT result = HTC_SEND_QUEUE_OK;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HTCTrySend (Queue:0x%lX Depth:%d)\n",
- (unsigned long)pCallersSendQueue,
- (pCallersSendQueue == NULL) ? 0 : HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue)));
-
- /* init the local send queue */
- INIT_HTC_PACKET_QUEUE(&sendQueue);
-
- do {
-
- if (NULL == pCallersSendQueue) {
- /* caller didn't provide a queue, just wants us to check queues and send */
- break;
- }
-
- if (HTC_QUEUE_EMPTY(pCallersSendQueue)) {
- /* empty queue */
- result = HTC_SEND_QUEUE_DROP;
- break;
- }
-
- if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) >= pEndpoint->MaxTxQueueDepth) {
- /* we've already overflowed */
- overflow = HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue);
- } else {
- /* figure out how much we will overflow by */
- overflow = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue);
- overflow += HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue);
- /* figure out how much we will overflow the TX queue by */
- overflow -= pEndpoint->MaxTxQueueDepth;
- }
-
- /* if overflow is negative or zero, we are okay */
- if (overflow > 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
- (" Endpoint %d, TX queue will overflow :%d , Tx Depth:%d, Max:%d \n",
- pEndpoint->Id, overflow, HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue), pEndpoint->MaxTxQueueDepth));
- }
- if ((overflow <= 0) || (pEndpoint->EpCallBacks.EpSendFull == NULL)) {
- /* all packets will fit or caller did not provide send full indication handler
- * -- just move all of them to the local sendQueue object */
- HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&sendQueue, pCallersSendQueue);
- } else {
- int i;
- int goodPkts = HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue) - overflow;
-
- A_ASSERT(goodPkts >= 0);
- /* we have overflowed, and a callback is provided */
- /* dequeue all non-overflow packets into the sendqueue */
- for (i = 0; i < goodPkts; i++) {
- /* pop off caller's queue*/
- pPacket = HTC_PACKET_DEQUEUE(pCallersSendQueue);
- A_ASSERT(pPacket != NULL);
- /* insert into local queue */
- HTC_PACKET_ENQUEUE(&sendQueue,pPacket);
- }
-
- /* the caller's queue has all the packets that won't fit*/
- /* walk through the caller's queue and indicate each one to the send full handler */
- ITERATE_OVER_LIST_ALLOW_REMOVE(&pCallersSendQueue->QueueHead, pPacket, struct htc_packet, ListLink) {
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Indicating overflowed TX packet: 0x%lX \n",
- (unsigned long)pPacket));
- if (pEndpoint->EpCallBacks.EpSendFull(pEndpoint->EpCallBacks.pContext,
- pPacket) == HTC_SEND_FULL_DROP) {
- /* callback wants the packet dropped */
- INC_HTC_EP_STAT(pEndpoint, TxDropped, 1);
- /* leave this one in the caller's queue for cleanup */
- } else {
- /* callback wants to keep this packet, remove from caller's queue */
- HTC_PACKET_REMOVE(pCallersSendQueue, pPacket);
- /* put it in the send queue */
- HTC_PACKET_ENQUEUE(&sendQueue,pPacket);
- }
-
- } ITERATE_END;
-
- if (HTC_QUEUE_EMPTY(&sendQueue)) {
- /* no packets made it in, caller will cleanup */
- result = HTC_SEND_QUEUE_DROP;
- break;
- }
- }
-
- } while (false);
-
- if (result != HTC_SEND_QUEUE_OK) {
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCTrySend: \n"));
- return result;
- }
-
- LOCK_HTC_TX(target);
-
- if (!HTC_QUEUE_EMPTY(&sendQueue)) {
- /* transfer packets */
- HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->TxQueue,&sendQueue);
- A_ASSERT(HTC_QUEUE_EMPTY(&sendQueue));
- INIT_HTC_PACKET_QUEUE(&sendQueue);
- }
-
- /* increment tx processing count on entry */
- pEndpoint->TxProcessCount++;
- if (pEndpoint->TxProcessCount > 1) {
- /* another thread or task is draining the TX queues on this endpoint
- * that thread will reset the tx processing count when the queue is drained */
- pEndpoint->TxProcessCount--;
- UNLOCK_HTC_TX(target);
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCTrySend (busy) \n"));
- return HTC_SEND_QUEUE_OK;
- }
-
- /***** beyond this point only 1 thread may enter ******/
-
- /* now drain the endpoint TX queue for transmission as long as we have enough
- * credits */
- while (true) {
-
- if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) == 0) {
- break;
- }
-
- /* get all the packets for this endpoint that we can for this pass */
- GetHTCSendPackets(target, pEndpoint, &sendQueue);
-
- if (HTC_PACKET_QUEUE_DEPTH(&sendQueue) == 0) {
- /* didn't get any packets due to a lack of credits */
- break;
- }
-
- UNLOCK_HTC_TX(target);
-
- /* any packets to send are now in our local send queue */
-
- bundlesSent = 0;
- pktsInBundles = 0;
-
- while (true) {
-
- /* try to send a bundle on each pass */
- if ((target->SendBundlingEnabled) &&
- (HTC_PACKET_QUEUE_DEPTH(&sendQueue) >= HTC_MIN_HTC_MSGS_TO_BUNDLE)) {
- int temp1,temp2;
- /* bundling is enabled and there is at least a minimum number of packets in the send queue
- * send what we can in this pass */
- HTCIssueSendBundle(pEndpoint, &sendQueue, &temp1, &temp2);
- bundlesSent += temp1;
- pktsInBundles += temp2;
- }
-
- /* if not bundling or there was a packet that could not be placed in a bundle, pull it out
- * and send it the normal way */
- pPacket = HTC_PACKET_DEQUEUE(&sendQueue);
- if (NULL == pPacket) {
- /* local queue is fully drained */
- break;
- }
- HTC_PREPARE_SEND_PKT(pPacket,
- pPacket->PktInfo.AsTx.SendFlags,
- 0,
- pPacket->PktInfo.AsTx.SeqNo);
- HTCIssueSend(target, pPacket);
-
- /* go back and see if we can bundle some more */
- }
-
- LOCK_HTC_TX(target);
-
- INC_HTC_EP_STAT(pEndpoint, TxBundles, bundlesSent);
- INC_HTC_EP_STAT(pEndpoint, TxPacketsBundled, pktsInBundles);
-
- }
-
- /* done with this endpoint, we can clear the count */
- pEndpoint->TxProcessCount = 0;
- UNLOCK_HTC_TX(target);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCTrySend: \n"));
-
- return HTC_SEND_QUEUE_OK;
-}
-
-int HTCSendPktsMultiple(HTC_HANDLE HTCHandle, struct htc_packet_queue *pPktQueue)
-{
- struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
- struct htc_endpoint *pEndpoint;
- struct htc_packet *pPacket;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+HTCSendPktsMultiple: Queue: 0x%lX, Pkts %d \n",
- (unsigned long)pPktQueue, HTC_PACKET_QUEUE_DEPTH(pPktQueue)));
-
- /* get packet at head to figure out which endpoint these packets will go into */
- pPacket = HTC_GET_PKT_AT_HEAD(pPktQueue);
- if (NULL == pPacket) {
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCSendPktsMultiple \n"));
- return A_EINVAL;
- }
-
- AR_DEBUG_ASSERT(pPacket->Endpoint < ENDPOINT_MAX);
- pEndpoint = &target->EndPoint[pPacket->Endpoint];
-
- HTCTrySend(target, pEndpoint, pPktQueue);
-
- /* do completion on any packets that couldn't get in */
- if (!HTC_QUEUE_EMPTY(pPktQueue)) {
-
- HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue,pPacket) {
- if (HTC_STOPPING(target)) {
- pPacket->Status = A_ECANCELED;
- } else {
- pPacket->Status = A_NO_RESOURCE;
- }
- } HTC_PACKET_QUEUE_ITERATE_END;
-
- DO_EP_TX_COMPLETION(pEndpoint,pPktQueue);
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCSendPktsMultiple \n"));
-
- return 0;
-}
-
-/* HTC API - HTCSendPkt */
-int HTCSendPkt(HTC_HANDLE HTCHandle, struct htc_packet *pPacket)
-{
- struct htc_packet_queue queue;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
- ("+-HTCSendPkt: Enter endPointId: %d, buffer: 0x%lX, length: %d \n",
- pPacket->Endpoint, (unsigned long)pPacket->pBuffer, pPacket->ActualLength));
- INIT_HTC_PACKET_QUEUE_AND_ADD(&queue,pPacket);
- return HTCSendPktsMultiple(HTCHandle, &queue);
-}
-
-/* check TX queues to drain because of credit distribution update */
-static INLINE void HTCCheckEndpointTxQueues(struct htc_target *target)
-{
- struct htc_endpoint *pEndpoint;
- struct htc_endpoint_credit_dist *pDistItem;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+HTCCheckEndpointTxQueues \n"));
- pDistItem = target->EpCreditDistributionListHead;
-
- /* run through the credit distribution list to see
- * if there are packets queued
- * NOTE: no locks need to be taken since the distribution list
- * is not dynamic (cannot be re-ordered) and we are not modifying any state */
- while (pDistItem != NULL) {
- pEndpoint = (struct htc_endpoint *)pDistItem->pHTCReserved;
-
- if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) > 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Ep %d has %d credits and %d Packets in TX Queue \n",
- pDistItem->Endpoint, pEndpoint->CreditDist.TxCredits, HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)));
- /* try to start the stalled queue, this list is ordered by priority.
- * Highest priority queue get's processed first, if there are credits available the
- * highest priority queue will get a chance to reclaim credits from lower priority
- * ones */
- HTCTrySend(target, pEndpoint, NULL);
- }
-
- pDistItem = pDistItem->pNext;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCCheckEndpointTxQueues \n"));
-}
-
-/* process credit reports and call distribution function */
-void HTCProcessCreditRpt(struct htc_target *target, HTC_CREDIT_REPORT *pRpt, int NumEntries, HTC_ENDPOINT_ID FromEndpoint)
-{
- int i;
- struct htc_endpoint *pEndpoint;
- int totalCredits = 0;
- bool doDist = false;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+HTCProcessCreditRpt, Credit Report Entries:%d \n", NumEntries));
-
- /* lock out TX while we update credits */
- LOCK_HTC_TX(target);
-
- for (i = 0; i < NumEntries; i++, pRpt++) {
- if (pRpt->EndpointID >= ENDPOINT_MAX) {
- AR_DEBUG_ASSERT(false);
- break;
- }
-
- pEndpoint = &target->EndPoint[pRpt->EndpointID];
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Endpoint %d got %d credits \n",
- pRpt->EndpointID, pRpt->Credits));
-
- INC_HTC_EP_STAT(pEndpoint, TxCreditRpts, 1);
- INC_HTC_EP_STAT(pEndpoint, TxCreditsReturned, pRpt->Credits);
-
- if (FromEndpoint == pRpt->EndpointID) {
- /* this credit report arrived on the same endpoint indicating it arrived in an RX
- * packet */
- INC_HTC_EP_STAT(pEndpoint, TxCreditsFromRx, pRpt->Credits);
- INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromRx, 1);
- } else if (FromEndpoint == ENDPOINT_0) {
- /* this credit arrived on endpoint 0 as a NULL message */
- INC_HTC_EP_STAT(pEndpoint, TxCreditsFromEp0, pRpt->Credits);
- INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromEp0, 1);
- } else {
- /* arrived on another endpoint */
- INC_HTC_EP_STAT(pEndpoint, TxCreditsFromOther, pRpt->Credits);
- INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromOther, 1);
- }
-
- if (ENDPOINT_0 == pRpt->EndpointID) {
- /* always give endpoint 0 credits back */
- pEndpoint->CreditDist.TxCredits += pRpt->Credits;
- } else {
- /* for all other endpoints, update credits to distribute, the distribution function
- * will handle giving out credits back to the endpoints */
- pEndpoint->CreditDist.TxCreditsToDist += pRpt->Credits;
- /* flag that we have to do the distribution */
- doDist = true;
- }
-
- /* refresh tx depth for distribution function that will recover these credits
- * NOTE: this is only valid when there are credits to recover! */
- pEndpoint->CreditDist.TxQueueDepth = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue);
-
- totalCredits += pRpt->Credits;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Report indicated %d credits to distribute \n", totalCredits));
-
- if (doDist) {
- /* this was a credit return based on a completed send operations
- * note, this is done with the lock held */
- DO_DISTRIBUTION(target,
- HTC_CREDIT_DIST_SEND_COMPLETE,
- "Send Complete",
- target->EpCreditDistributionListHead->pNext);
- }
-
- UNLOCK_HTC_TX(target);
-
- if (totalCredits) {
- HTCCheckEndpointTxQueues(target);
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCProcessCreditRpt \n"));
-}
-
-/* flush endpoint TX queue */
-static void HTCFlushEndpointTX(struct htc_target *target, struct htc_endpoint *pEndpoint, HTC_TX_TAG Tag)
-{
- struct htc_packet *pPacket;
- struct htc_packet_queue discardQueue;
- struct htc_packet_queue container;
-
- /* initialize the discard queue */
- INIT_HTC_PACKET_QUEUE(&discardQueue);
-
- LOCK_HTC_TX(target);
-
- /* interate from the front of the TX queue and flush out packets */
- ITERATE_OVER_LIST_ALLOW_REMOVE(&pEndpoint->TxQueue.QueueHead, pPacket, struct htc_packet, ListLink) {
-
- /* check for removal */
- if ((HTC_TX_PACKET_TAG_ALL == Tag) || (Tag == pPacket->PktInfo.AsTx.Tag)) {
- /* remove from queue */
- HTC_PACKET_REMOVE(&pEndpoint->TxQueue, pPacket);
- /* add it to the discard pile */
- HTC_PACKET_ENQUEUE(&discardQueue, pPacket);
- }
-
- } ITERATE_END;
-
- UNLOCK_HTC_TX(target);
-
- /* empty the discard queue */
- while (1) {
- pPacket = HTC_PACKET_DEQUEUE(&discardQueue);
- if (NULL == pPacket) {
- break;
- }
- pPacket->Status = A_ECANCELED;
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" Flushing TX packet:0x%lX, length:%d, ep:%d tag:0x%X \n",
- (unsigned long)pPacket, pPacket->ActualLength, pPacket->Endpoint, pPacket->PktInfo.AsTx.Tag));
- INIT_HTC_PACKET_QUEUE_AND_ADD(&container,pPacket);
- DO_EP_TX_COMPLETION(pEndpoint,&container);
- }
-
-}
-
-void DumpCreditDist(struct htc_endpoint_credit_dist *pEPDist)
-{
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("--- EP : %d ServiceID: 0x%X --------------\n",
- pEPDist->Endpoint, pEPDist->ServiceID));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" this:0x%lX next:0x%lX prev:0x%lX\n",
- (unsigned long)pEPDist, (unsigned long)pEPDist->pNext, (unsigned long)pEPDist->pPrev));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" DistFlags : 0x%X \n", pEPDist->DistFlags));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsNorm : %d \n", pEPDist->TxCreditsNorm));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsMin : %d \n", pEPDist->TxCreditsMin));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCredits : %d \n", pEPDist->TxCredits));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsAssigned : %d \n", pEPDist->TxCreditsAssigned));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsSeek : %d \n", pEPDist->TxCreditsSeek));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditSize : %d \n", pEPDist->TxCreditSize));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsPerMaxMsg : %d \n", pEPDist->TxCreditsPerMaxMsg));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsToDist : %d \n", pEPDist->TxCreditsToDist));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxQueueDepth : %d \n",
- HTC_PACKET_QUEUE_DEPTH(&((struct htc_endpoint *)pEPDist->pHTCReserved)->TxQueue)));
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("----------------------------------------------------\n"));
-}
-
-void DumpCreditDistStates(struct htc_target *target)
-{
- struct htc_endpoint_credit_dist *pEPList = target->EpCreditDistributionListHead;
-
- while (pEPList != NULL) {
- DumpCreditDist(pEPList);
- pEPList = pEPList->pNext;
- }
-
- if (target->DistributeCredits != NULL) {
- DO_DISTRIBUTION(target,
- HTC_DUMP_CREDIT_STATE,
- "Dump State",
- NULL);
- }
-}
-
-/* flush all send packets from all endpoint queues */
-void HTCFlushSendPkts(struct htc_target *target)
-{
- struct htc_endpoint *pEndpoint;
- int i;
-
- if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_TRC)) {
- DumpCreditDistStates(target);
- }
-
- for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
- pEndpoint = &target->EndPoint[i];
- if (pEndpoint->ServiceID == 0) {
- /* not in use.. */
- continue;
- }
- HTCFlushEndpointTX(target,pEndpoint,HTC_TX_PACKET_TAG_ALL);
- }
-
-
-}
-
-/* HTC API to flush an endpoint's TX queue*/
-void HTCFlushEndpoint(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint, HTC_TX_TAG Tag)
-{
- struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
- struct htc_endpoint *pEndpoint = &target->EndPoint[Endpoint];
-
- if (pEndpoint->ServiceID == 0) {
- AR_DEBUG_ASSERT(false);
- /* not in use.. */
- return;
- }
-
- HTCFlushEndpointTX(target, pEndpoint, Tag);
-}
-
-/* HTC API to indicate activity to the credit distribution function */
-void HTCIndicateActivityChange(HTC_HANDLE HTCHandle,
- HTC_ENDPOINT_ID Endpoint,
- bool Active)
-{
- struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
- struct htc_endpoint *pEndpoint = &target->EndPoint[Endpoint];
- bool doDist = false;
-
- if (pEndpoint->ServiceID == 0) {
- AR_DEBUG_ASSERT(false);
- /* not in use.. */
- return;
- }
-
- LOCK_HTC_TX(target);
-
- if (Active) {
- if (!(pEndpoint->CreditDist.DistFlags & HTC_EP_ACTIVE)) {
- /* mark active now */
- pEndpoint->CreditDist.DistFlags |= HTC_EP_ACTIVE;
- doDist = true;
- }
- } else {
- if (pEndpoint->CreditDist.DistFlags & HTC_EP_ACTIVE) {
- /* mark inactive now */
- pEndpoint->CreditDist.DistFlags &= ~HTC_EP_ACTIVE;
- doDist = true;
- }
- }
-
- if (doDist) {
- /* indicate current Tx Queue depth to the credit distribution function */
- pEndpoint->CreditDist.TxQueueDepth = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue);
- /* do distribution again based on activity change
- * note, this is done with the lock held */
- DO_DISTRIBUTION(target,
- HTC_CREDIT_DIST_ACTIVITY_CHANGE,
- "Activity Change",
- target->EpCreditDistributionListHead->pNext);
- }
-
- UNLOCK_HTC_TX(target);
-
- if (doDist && !Active) {
- /* if a stream went inactive and this resulted in a credit distribution change,
- * some credits may now be available for HTC packets that are stuck in
- * HTC queues */
- HTCCheckEndpointTxQueues(target);
- }
-}
-
-bool HTCIsEndpointActive(HTC_HANDLE HTCHandle,
- HTC_ENDPOINT_ID Endpoint)
-{
- struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
- struct htc_endpoint *pEndpoint = &target->EndPoint[Endpoint];
-
- if (pEndpoint->ServiceID == 0) {
- return false;
- }
-
- if (pEndpoint->CreditDist.DistFlags & HTC_EP_ACTIVE) {
- return true;
- }
-
- return false;
-}
diff --git a/drivers/staging/ath6kl/htc2/htc_services.c b/drivers/staging/ath6kl/htc2/htc_services.c
deleted file mode 100644
index c48070cbd54f..000000000000
--- a/drivers/staging/ath6kl/htc2/htc_services.c
+++ /dev/null
@@ -1,450 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="htc_services.c" company="Atheros">
-// Copyright (c) 2007-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-#include "htc_internal.h"
-
-void HTCControlTxComplete(void *Context, struct htc_packet *pPacket)
-{
- /* not implemented
- * we do not send control TX frames during normal runtime, only during setup */
- AR_DEBUG_ASSERT(false);
-}
-
- /* callback when a control message arrives on this endpoint */
-void HTCControlRecv(void *Context, struct htc_packet *pPacket)
-{
- AR_DEBUG_ASSERT(pPacket->Endpoint == ENDPOINT_0);
-
- if (pPacket->Status == A_ECANCELED) {
- /* this is a flush operation, return the control packet back to the pool */
- HTC_FREE_CONTROL_RX((struct htc_target*)Context,pPacket);
- return;
- }
-
- /* the only control messages we are expecting are NULL messages (credit resports) */
- if (pPacket->ActualLength > 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("HTCControlRecv, got message with length:%d \n",
- pPacket->ActualLength + (u32)HTC_HDR_LENGTH));
-
-#ifdef ATH_DEBUG_MODULE
- /* dump header and message */
- DebugDumpBytes(pPacket->pBuffer - HTC_HDR_LENGTH,
- pPacket->ActualLength + HTC_HDR_LENGTH,
- "Unexpected ENDPOINT 0 Message");
-#endif
- }
-
- HTC_RECYCLE_RX_PKT((struct htc_target*)Context,pPacket,&((struct htc_target*)Context)->EndPoint[0]);
-}
-
-int HTCSendSetupComplete(struct htc_target *target)
-{
- struct htc_packet *pSendPacket = NULL;
- int status;
-
- do {
- /* allocate a packet to send to the target */
- pSendPacket = HTC_ALLOC_CONTROL_TX(target);
-
- if (NULL == pSendPacket) {
- status = A_NO_MEMORY;
- break;
- }
-
- if (target->HTCTargetVersion >= HTC_VERSION_2P1) {
- HTC_SETUP_COMPLETE_EX_MSG *pSetupCompleteEx;
- u32 setupFlags = 0;
-
- pSetupCompleteEx = (HTC_SETUP_COMPLETE_EX_MSG *)pSendPacket->pBuffer;
- A_MEMZERO(pSetupCompleteEx, sizeof(HTC_SETUP_COMPLETE_EX_MSG));
- pSetupCompleteEx->MessageID = HTC_MSG_SETUP_COMPLETE_EX_ID;
- if (target->MaxMsgPerBundle > 0) {
- /* host can do HTC bundling, indicate this to the target */
- setupFlags |= HTC_SETUP_COMPLETE_FLAGS_ENABLE_BUNDLE_RECV;
- pSetupCompleteEx->MaxMsgsPerBundledRecv = target->MaxMsgPerBundle;
- }
- memcpy(&pSetupCompleteEx->SetupFlags, &setupFlags, sizeof(pSetupCompleteEx->SetupFlags));
- SET_HTC_PACKET_INFO_TX(pSendPacket,
- NULL,
- (u8 *)pSetupCompleteEx,
- sizeof(HTC_SETUP_COMPLETE_EX_MSG),
- ENDPOINT_0,
- HTC_SERVICE_TX_PACKET_TAG);
-
- } else {
- HTC_SETUP_COMPLETE_MSG *pSetupComplete;
- /* assemble setup complete message */
- pSetupComplete = (HTC_SETUP_COMPLETE_MSG *)pSendPacket->pBuffer;
- A_MEMZERO(pSetupComplete, sizeof(HTC_SETUP_COMPLETE_MSG));
- pSetupComplete->MessageID = HTC_MSG_SETUP_COMPLETE_ID;
- SET_HTC_PACKET_INFO_TX(pSendPacket,
- NULL,
- (u8 *)pSetupComplete,
- sizeof(HTC_SETUP_COMPLETE_MSG),
- ENDPOINT_0,
- HTC_SERVICE_TX_PACKET_TAG);
- }
-
- /* we want synchronous operation */
- pSendPacket->Completion = NULL;
- HTC_PREPARE_SEND_PKT(pSendPacket,0,0,0);
- /* send the message */
- status = HTCIssueSend(target,pSendPacket);
-
- } while (false);
-
- if (pSendPacket != NULL) {
- HTC_FREE_CONTROL_TX(target,pSendPacket);
- }
-
- return status;
-}
-
-
-int HTCConnectService(HTC_HANDLE HTCHandle,
- struct htc_service_connect_req *pConnectReq,
- struct htc_service_connect_resp *pConnectResp)
-{
- struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
- int status = 0;
- struct htc_packet *pRecvPacket = NULL;
- struct htc_packet *pSendPacket = NULL;
- HTC_CONNECT_SERVICE_RESPONSE_MSG *pResponseMsg;
- HTC_CONNECT_SERVICE_MSG *pConnectMsg;
- HTC_ENDPOINT_ID assignedEndpoint = ENDPOINT_MAX;
- struct htc_endpoint *pEndpoint;
- unsigned int maxMsgSize = 0;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCConnectService, target:0x%lX SvcID:0x%X \n",
- (unsigned long)target, pConnectReq->ServiceID));
-
- do {
-
- AR_DEBUG_ASSERT(pConnectReq->ServiceID != 0);
-
- if (HTC_CTRL_RSVD_SVC == pConnectReq->ServiceID) {
- /* special case for pseudo control service */
- assignedEndpoint = ENDPOINT_0;
- maxMsgSize = HTC_MAX_CONTROL_MESSAGE_LENGTH;
- } else {
- /* allocate a packet to send to the target */
- pSendPacket = HTC_ALLOC_CONTROL_TX(target);
-
- if (NULL == pSendPacket) {
- AR_DEBUG_ASSERT(false);
- status = A_NO_MEMORY;
- break;
- }
- /* assemble connect service message */
- pConnectMsg = (HTC_CONNECT_SERVICE_MSG *)pSendPacket->pBuffer;
- AR_DEBUG_ASSERT(pConnectMsg != NULL);
- A_MEMZERO(pConnectMsg,sizeof(HTC_CONNECT_SERVICE_MSG));
- pConnectMsg->MessageID = HTC_MSG_CONNECT_SERVICE_ID;
- pConnectMsg->ServiceID = pConnectReq->ServiceID;
- pConnectMsg->ConnectionFlags = pConnectReq->ConnectionFlags;
- /* check caller if it wants to transfer meta data */
- if ((pConnectReq->pMetaData != NULL) &&
- (pConnectReq->MetaDataLength <= HTC_SERVICE_META_DATA_MAX_LENGTH)) {
- /* copy meta data into message buffer (after header ) */
- memcpy((u8 *)pConnectMsg + sizeof(HTC_CONNECT_SERVICE_MSG),
- pConnectReq->pMetaData,
- pConnectReq->MetaDataLength);
- pConnectMsg->ServiceMetaLength = pConnectReq->MetaDataLength;
- }
-
- SET_HTC_PACKET_INFO_TX(pSendPacket,
- NULL,
- (u8 *)pConnectMsg,
- sizeof(HTC_CONNECT_SERVICE_MSG) + pConnectMsg->ServiceMetaLength,
- ENDPOINT_0,
- HTC_SERVICE_TX_PACKET_TAG);
-
- /* we want synchronous operation */
- pSendPacket->Completion = NULL;
- HTC_PREPARE_SEND_PKT(pSendPacket,0,0,0);
- status = HTCIssueSend(target,pSendPacket);
-
- if (status) {
- break;
- }
-
- /* wait for response */
- status = HTCWaitforControlMessage(target, &pRecvPacket);
-
- if (status) {
- break;
- }
- /* we controlled the buffer creation so it has to be properly aligned */
- pResponseMsg = (HTC_CONNECT_SERVICE_RESPONSE_MSG *)pRecvPacket->pBuffer;
-
- if ((pResponseMsg->MessageID != HTC_MSG_CONNECT_SERVICE_RESPONSE_ID) ||
- (pRecvPacket->ActualLength < sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG))) {
- /* this message is not valid */
- AR_DEBUG_ASSERT(false);
- status = A_EPROTO;
- break;
- }
-
- pConnectResp->ConnectRespCode = pResponseMsg->Status;
- /* check response status */
- if (pResponseMsg->Status != HTC_SERVICE_SUCCESS) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- (" Target failed service 0x%X connect request (status:%d)\n",
- pResponseMsg->ServiceID, pResponseMsg->Status));
- status = A_EPROTO;
- break;
- }
-
- assignedEndpoint = (HTC_ENDPOINT_ID) pResponseMsg->EndpointID;
- maxMsgSize = pResponseMsg->MaxMsgSize;
-
- if ((pConnectResp->pMetaData != NULL) &&
- (pResponseMsg->ServiceMetaLength > 0) &&
- (pResponseMsg->ServiceMetaLength <= HTC_SERVICE_META_DATA_MAX_LENGTH)) {
- /* caller supplied a buffer and the target responded with data */
- int copyLength = min((int)pConnectResp->BufferLength, (int)pResponseMsg->ServiceMetaLength);
- /* copy the meta data */
- memcpy(pConnectResp->pMetaData,
- ((u8 *)pResponseMsg) + sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG),
- copyLength);
- pConnectResp->ActualLength = copyLength;
- }
-
- }
-
- /* the rest of these are parameter checks so set the error status */
- status = A_EPROTO;
-
- if (assignedEndpoint >= ENDPOINT_MAX) {
- AR_DEBUG_ASSERT(false);
- break;
- }
-
- if (0 == maxMsgSize) {
- AR_DEBUG_ASSERT(false);
- break;
- }
-
- pEndpoint = &target->EndPoint[assignedEndpoint];
- pEndpoint->Id = assignedEndpoint;
- if (pEndpoint->ServiceID != 0) {
- /* endpoint already in use! */
- AR_DEBUG_ASSERT(false);
- break;
- }
-
- /* return assigned endpoint to caller */
- pConnectResp->Endpoint = assignedEndpoint;
- pConnectResp->MaxMsgLength = maxMsgSize;
-
- /* setup the endpoint */
- pEndpoint->ServiceID = pConnectReq->ServiceID; /* this marks the endpoint in use */
- pEndpoint->MaxTxQueueDepth = pConnectReq->MaxSendQueueDepth;
- pEndpoint->MaxMsgLength = maxMsgSize;
- /* copy all the callbacks */
- pEndpoint->EpCallBacks = pConnectReq->EpCallbacks;
- /* set the credit distribution info for this endpoint, this information is
- * passed back to the credit distribution callback function */
- pEndpoint->CreditDist.ServiceID = pConnectReq->ServiceID;
- pEndpoint->CreditDist.pHTCReserved = pEndpoint;
- pEndpoint->CreditDist.Endpoint = assignedEndpoint;
- pEndpoint->CreditDist.TxCreditSize = target->TargetCreditSize;
-
- if (pConnectReq->MaxSendMsgSize != 0) {
- /* override TxCreditsPerMaxMsg calculation, this optimizes the credit-low indications
- * since the host will actually issue smaller messages in the Send path */
- if (pConnectReq->MaxSendMsgSize > maxMsgSize) {
- /* can't be larger than the maximum the target can support */
- AR_DEBUG_ASSERT(false);
- break;
- }
- pEndpoint->CreditDist.TxCreditsPerMaxMsg = pConnectReq->MaxSendMsgSize / target->TargetCreditSize;
- } else {
- pEndpoint->CreditDist.TxCreditsPerMaxMsg = maxMsgSize / target->TargetCreditSize;
- }
-
- if (0 == pEndpoint->CreditDist.TxCreditsPerMaxMsg) {
- pEndpoint->CreditDist.TxCreditsPerMaxMsg = 1;
- }
-
- /* save local connection flags */
- pEndpoint->LocalConnectionFlags = pConnectReq->LocalConnectionFlags;
-
- status = 0;
-
- } while (false);
-
- if (pSendPacket != NULL) {
- HTC_FREE_CONTROL_TX(target,pSendPacket);
- }
-
- if (pRecvPacket != NULL) {
- HTC_FREE_CONTROL_RX(target,pRecvPacket);
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCConnectService \n"));
-
- return status;
-}
-
-static void AddToEndpointDistList(struct htc_target *target, struct htc_endpoint_credit_dist *pEpDist)
-{
- struct htc_endpoint_credit_dist *pCurEntry,*pLastEntry;
-
- if (NULL == target->EpCreditDistributionListHead) {
- target->EpCreditDistributionListHead = pEpDist;
- pEpDist->pNext = NULL;
- pEpDist->pPrev = NULL;
- return;
- }
-
- /* queue to the end of the list, this does not have to be very
- * fast since this list is built at startup time */
- pCurEntry = target->EpCreditDistributionListHead;
-
- while (pCurEntry) {
- pLastEntry = pCurEntry;
- pCurEntry = pCurEntry->pNext;
- }
-
- pLastEntry->pNext = pEpDist;
- pEpDist->pPrev = pLastEntry;
- pEpDist->pNext = NULL;
-}
-
-
-
-/* default credit init callback */
-static void HTCDefaultCreditInit(void *Context,
- struct htc_endpoint_credit_dist *pEPList,
- int TotalCredits)
-{
- struct htc_endpoint_credit_dist *pCurEpDist;
- int totalEps = 0;
- int creditsPerEndpoint;
-
- pCurEpDist = pEPList;
- /* first run through the list and figure out how many endpoints we are dealing with */
- while (pCurEpDist != NULL) {
- pCurEpDist = pCurEpDist->pNext;
- totalEps++;
- }
-
- /* even distribution */
- creditsPerEndpoint = TotalCredits/totalEps;
-
- pCurEpDist = pEPList;
- /* run through the list and set minimum and normal credits and
- * provide the endpoint with some credits to start */
- while (pCurEpDist != NULL) {
-
- if (creditsPerEndpoint < pCurEpDist->TxCreditsPerMaxMsg) {
- /* too many endpoints and not enough credits */
- AR_DEBUG_ASSERT(false);
- break;
- }
- /* our minimum is set for at least 1 max message */
- pCurEpDist->TxCreditsMin = pCurEpDist->TxCreditsPerMaxMsg;
- /* this value is ignored by our credit alg, since we do
- * not dynamically adjust credits, this is the policy of
- * the "default" credit distribution, something simple and easy */
- pCurEpDist->TxCreditsNorm = 0xFFFF;
- /* give the endpoint minimum credits */
- pCurEpDist->TxCredits = creditsPerEndpoint;
- pCurEpDist->TxCreditsAssigned = creditsPerEndpoint;
- pCurEpDist = pCurEpDist->pNext;
- }
-
-}
-
-/* default credit distribution callback, NOTE, this callback holds the TX lock */
-void HTCDefaultCreditDist(void *Context,
- struct htc_endpoint_credit_dist *pEPDistList,
- HTC_CREDIT_DIST_REASON Reason)
-{
- struct htc_endpoint_credit_dist *pCurEpDist;
-
- if (Reason == HTC_CREDIT_DIST_SEND_COMPLETE) {
- pCurEpDist = pEPDistList;
- /* simple distribution */
- while (pCurEpDist != NULL) {
- if (pCurEpDist->TxCreditsToDist > 0) {
- /* just give the endpoint back the credits */
- pCurEpDist->TxCredits += pCurEpDist->TxCreditsToDist;
- pCurEpDist->TxCreditsToDist = 0;
- }
- pCurEpDist = pCurEpDist->pNext;
- }
- }
-
- /* note we do not need to handle the other reason codes as this is a very
- * simple distribution scheme, no need to seek for more credits or handle inactivity */
-}
-
-void HTCSetCreditDistribution(HTC_HANDLE HTCHandle,
- void *pCreditDistContext,
- HTC_CREDIT_DIST_CALLBACK CreditDistFunc,
- HTC_CREDIT_INIT_CALLBACK CreditInitFunc,
- HTC_SERVICE_ID ServicePriorityOrder[],
- int ListLength)
-{
- struct htc_target *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
- int i;
- int ep;
-
- if (CreditInitFunc != NULL) {
- /* caller has supplied their own distribution functions */
- target->InitCredits = CreditInitFunc;
- AR_DEBUG_ASSERT(CreditDistFunc != NULL);
- target->DistributeCredits = CreditDistFunc;
- target->pCredDistContext = pCreditDistContext;
- } else {
- /* caller wants HTC to do distribution */
- /* if caller wants service to handle distributions then
- * it must set both of these to NULL! */
- AR_DEBUG_ASSERT(CreditDistFunc == NULL);
- target->InitCredits = HTCDefaultCreditInit;
- target->DistributeCredits = HTCDefaultCreditDist;
- target->pCredDistContext = target;
- }
-
- /* always add HTC control endpoint first, we only expose the list after the
- * first one, this is added for TX queue checking */
- AddToEndpointDistList(target, &target->EndPoint[ENDPOINT_0].CreditDist);
-
- /* build the list of credit distribution structures in priority order
- * supplied by the caller, these will follow endpoint 0 */
- for (i = 0; i < ListLength; i++) {
- /* match services with endpoints and add the endpoints to the distribution list
- * in FIFO order */
- for (ep = ENDPOINT_1; ep < ENDPOINT_MAX; ep++) {
- if (target->EndPoint[ep].ServiceID == ServicePriorityOrder[i]) {
- /* queue this one to the list */
- AddToEndpointDistList(target, &target->EndPoint[ep].CreditDist);
- break;
- }
- }
- AR_DEBUG_ASSERT(ep < ENDPOINT_MAX);
- }
-
-}
diff --git a/drivers/staging/ath6kl/include/a_config.h b/drivers/staging/ath6kl/include/a_config.h
deleted file mode 100644
index f7c09319433f..000000000000
--- a/drivers/staging/ath6kl/include/a_config.h
+++ /dev/null
@@ -1,31 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="a_config.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// This file contains software configuration options that enables
-// specific software "features"
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _A_CONFIG_H_
-#define _A_CONFIG_H_
-
-#include "../os/linux/include/config_linux.h"
-
-#endif
diff --git a/drivers/staging/ath6kl/include/a_debug.h b/drivers/staging/ath6kl/include/a_debug.h
deleted file mode 100644
index 5154fcb1ca64..000000000000
--- a/drivers/staging/ath6kl/include/a_debug.h
+++ /dev/null
@@ -1,195 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="a_debug.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _A_DEBUG_H_
-#define _A_DEBUG_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#include <a_osapi.h>
-
- /* standard debug print masks bits 0..7 */
-#define ATH_DEBUG_ERR (1 << 0) /* errors */
-#define ATH_DEBUG_WARN (1 << 1) /* warnings */
-#define ATH_DEBUG_INFO (1 << 2) /* informational (module startup info) */
-#define ATH_DEBUG_TRC (1 << 3) /* generic function call tracing */
-#define ATH_DEBUG_RSVD1 (1 << 4)
-#define ATH_DEBUG_RSVD2 (1 << 5)
-#define ATH_DEBUG_RSVD3 (1 << 6)
-#define ATH_DEBUG_RSVD4 (1 << 7)
-
-#define ATH_DEBUG_MASK_DEFAULTS (ATH_DEBUG_ERR | ATH_DEBUG_WARN)
-#define ATH_DEBUG_ANY 0xFFFF
-
- /* other aliases used throughout */
-#define ATH_DEBUG_ERROR ATH_DEBUG_ERR
-#define ATH_LOG_ERR ATH_DEBUG_ERR
-#define ATH_LOG_INF ATH_DEBUG_INFO
-#define ATH_LOG_TRC ATH_DEBUG_TRC
-#define ATH_DEBUG_TRACE ATH_DEBUG_TRC
-#define ATH_DEBUG_INIT ATH_DEBUG_INFO
-
- /* bits 8..31 are module-specific masks */
-#define ATH_DEBUG_MODULE_MASK_SHIFT 8
-
- /* macro to make a module-specific masks */
-#define ATH_DEBUG_MAKE_MODULE_MASK(index) (1 << (ATH_DEBUG_MODULE_MASK_SHIFT + (index)))
-
-void DebugDumpBytes(u8 *buffer, u16 length, char *pDescription);
-
-/* Debug support on a per-module basis
- *
- * Usage:
- *
- * Each module can utilize it's own debug mask variable. A set of commonly used
- * masks are provided (ERRORS, WARNINGS, TRACE etc..). It is up to each module
- * to define module-specific masks using the macros above.
- *
- * Each module defines a single debug mask variable debug_XXX where the "name" of the module is
- * common to all C-files within that module. This requires every C-file that includes a_debug.h
- * to define the module name in that file.
- *
- * Example:
- *
- * #define ATH_MODULE_NAME htc
- * #include "a_debug.h"
- *
- * This will define a debug mask structure called debug_htc and all debug macros will reference this
- * variable.
- *
- * A module can define module-specific bit masks using the ATH_DEBUG_MAKE_MODULE_MASK() macro:
- *
- * #define ATH_DEBUG_MY_MASK1 ATH_DEBUG_MAKE_MODULE_MASK(0)
- * #define ATH_DEBUG_MY_MASK2 ATH_DEBUG_MAKE_MODULE_MASK(1)
- *
- * The instantiation of the debug structure should be made by the module. When a module is
- * instantiated, the module can set a description string, a default mask and an array of description
- * entries containing information on each module-defined debug mask.
- * NOTE: The instantiation is statically allocated, only one instance can exist per module.
- *
- * Example:
- *
- *
- * #define ATH_DEBUG_BMI ATH_DEBUG_MAKE_MODULE_MASK(0)
- *
- * #ifdef DEBUG
- * static struct ath_debug_mask_description bmi_debug_desc[] = {
- * { ATH_DEBUG_BMI , "BMI Tracing"}, <== description of the module specific mask
- * };
- *
- * ATH_DEBUG_INSTANTIATE_MODULE_VAR(bmi,
- * "bmi" <== module name
- * "Boot Manager Interface", <== description of module
- * ATH_DEBUG_MASK_DEFAULTS, <== defaults
- * ATH_DEBUG_DESCRIPTION_COUNT(bmi_debug_desc),
- * bmi_debug_desc);
- *
- * #endif
- *
- * A module can optionally register it's debug module information in order for other tools to change the
- * bit mask at runtime. A module can call A_REGISTER_MODULE_DEBUG_INFO() in it's module
- * init code. This macro can be called multiple times without consequence. The debug info maintains
- * state to indicate whether the information was previously registered.
- *
- * */
-
-#define ATH_DEBUG_MAX_MASK_DESC_LENGTH 32
-#define ATH_DEBUG_MAX_MOD_DESC_LENGTH 64
-
-struct ath_debug_mask_description {
- u32 Mask;
- char Description[ATH_DEBUG_MAX_MASK_DESC_LENGTH];
-};
-
-#define ATH_DEBUG_INFO_FLAGS_REGISTERED (1 << 0)
-
-typedef struct _ATH_DEBUG_MODULE_DBG_INFO{
- struct _ATH_DEBUG_MODULE_DBG_INFO *pNext;
- char ModuleName[16];
- char ModuleDescription[ATH_DEBUG_MAX_MOD_DESC_LENGTH];
- u32 Flags;
- u32 CurrentMask;
- int MaxDescriptions;
- struct ath_debug_mask_description *pMaskDescriptions; /* pointer to array of descriptions */
-} ATH_DEBUG_MODULE_DBG_INFO;
-
-#define ATH_DEBUG_DESCRIPTION_COUNT(d) (int)((sizeof((d))) / (sizeof(struct ath_debug_mask_description)))
-
-#define GET_ATH_MODULE_DEBUG_VAR_NAME(s) _XGET_ATH_MODULE_NAME_DEBUG_(s)
-#define GET_ATH_MODULE_DEBUG_VAR_MASK(s) _XGET_ATH_MODULE_NAME_DEBUG_(s).CurrentMask
-#define _XGET_ATH_MODULE_NAME_DEBUG_(s) debug_ ## s
-
-#ifdef ATH_DEBUG_MODULE
-
- /* for source files that will instantiate the debug variables */
-#define ATH_DEBUG_INSTANTIATE_MODULE_VAR(s,name,moddesc,initmask,count,descriptions) \
-ATH_DEBUG_MODULE_DBG_INFO GET_ATH_MODULE_DEBUG_VAR_NAME(s) = \
- {NULL,(name),(moddesc),0,(initmask),count,(descriptions)}
-
-#ifdef ATH_MODULE_NAME
-extern ATH_DEBUG_MODULE_DBG_INFO GET_ATH_MODULE_DEBUG_VAR_NAME(ATH_MODULE_NAME);
-#define AR_DEBUG_LVL_CHECK(lvl) (GET_ATH_MODULE_DEBUG_VAR_MASK(ATH_MODULE_NAME) & (lvl))
-#endif /* ATH_MODULE_NAME */
-
-#define ATH_DEBUG_SET_DEBUG_MASK(s,lvl) GET_ATH_MODULE_DEBUG_VAR_MASK(s) = (lvl)
-
-#define ATH_DEBUG_DECLARE_EXTERN(s) \
- extern ATH_DEBUG_MODULE_DBG_INFO GET_ATH_MODULE_DEBUG_VAR_NAME(s)
-
-#define AR_DEBUG_PRINTBUF(buffer, length, desc) DebugDumpBytes(buffer,length,desc)
-
-
-#define AR_DEBUG_ASSERT A_ASSERT
-
-void a_dump_module_debug_info(ATH_DEBUG_MODULE_DBG_INFO *pInfo);
-void a_register_module_debug_info(ATH_DEBUG_MODULE_DBG_INFO *pInfo);
-#define A_DUMP_MODULE_DEBUG_INFO(s) a_dump_module_debug_info(&(GET_ATH_MODULE_DEBUG_VAR_NAME(s)))
-#define A_REGISTER_MODULE_DEBUG_INFO(s) a_register_module_debug_info(&(GET_ATH_MODULE_DEBUG_VAR_NAME(s)))
-
-#else /* !ATH_DEBUG_MODULE */
- /* NON ATH_DEBUG_MODULE */
-#define ATH_DEBUG_INSTANTIATE_MODULE_VAR(s,name,moddesc,initmask,count,descriptions)
-#define AR_DEBUG_LVL_CHECK(lvl) 0
-#define AR_DEBUG_PRINTBUF(buffer, length, desc)
-#define AR_DEBUG_ASSERT(test)
-#define ATH_DEBUG_DECLARE_EXTERN(s)
-#define ATH_DEBUG_SET_DEBUG_MASK(s,lvl)
-#define A_DUMP_MODULE_DEBUG_INFO(s)
-#define A_REGISTER_MODULE_DEBUG_INFO(s)
-
-#endif
-
-int a_get_module_mask(char *module_name, u32 *pMask);
-int a_set_module_mask(char *module_name, u32 Mask);
-void a_dump_module_debug_info_by_name(char *module_name);
-void a_module_debug_support_init(void);
-void a_module_debug_support_cleanup(void);
-
-#include "../os/linux/include/debug_linux.h"
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif
diff --git a/drivers/staging/ath6kl/include/a_drv.h b/drivers/staging/ath6kl/include/a_drv.h
deleted file mode 100644
index 1548604e8465..000000000000
--- a/drivers/staging/ath6kl/include/a_drv.h
+++ /dev/null
@@ -1,32 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="a_drv.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// This file contains the definitions of the basic atheros data types.
-// It is used to map the data types in atheros files to a platform specific
-// type.
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _A_DRV_H_
-#define _A_DRV_H_
-
-#include "../os/linux/include/athdrv_linux.h"
-
-#endif /* _ADRV_H_ */
diff --git a/drivers/staging/ath6kl/include/a_drv_api.h b/drivers/staging/ath6kl/include/a_drv_api.h
deleted file mode 100644
index a40d97a84ffc..000000000000
--- a/drivers/staging/ath6kl/include/a_drv_api.h
+++ /dev/null
@@ -1,204 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="a_drv_api.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _A_DRV_API_H_
-#define _A_DRV_API_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/****************************************************************************/
-/****************************************************************************/
-/** **/
-/** WMI related hooks **/
-/** **/
-/****************************************************************************/
-/****************************************************************************/
-
-#include <ar6000_api.h>
-
-#define A_WMI_CHANNELLIST_RX(devt, numChan, chanList) \
- ar6000_channelList_rx((devt), (numChan), (chanList))
-
-#define A_WMI_SET_NUMDATAENDPTS(devt, num) \
- ar6000_set_numdataendpts((devt), (num))
-
-#define A_WMI_CONTROL_TX(devt, osbuf, streamID) \
- ar6000_control_tx((devt), (osbuf), (streamID))
-
-#define A_WMI_TARGETSTATS_EVENT(devt, pStats, len) \
- ar6000_targetStats_event((devt), (pStats), (len))
-
-#define A_WMI_SCANCOMPLETE_EVENT(devt, status) \
- ar6000_scanComplete_event((devt), (status))
-
-#ifdef CONFIG_HOST_DSET_SUPPORT
-
-#define A_WMI_DSET_DATA_REQ(devt, access_cookie, offset, length, targ_buf, targ_reply_fn, targ_reply_arg) \
- ar6000_dset_data_req((devt), (access_cookie), (offset), (length), (targ_buf), (targ_reply_fn), (targ_reply_arg))
-
-#define A_WMI_DSET_CLOSE(devt, access_cookie) \
- ar6000_dset_close((devt), (access_cookie))
-
-#endif
-
-#define A_WMI_DSET_OPEN_REQ(devt, id, targ_handle, targ_reply_fn, targ_reply_arg) \
- ar6000_dset_open_req((devt), (id), (targ_handle), (targ_reply_fn), (targ_reply_arg))
-
-#define A_WMI_CONNECT_EVENT(devt, channel, bssid, listenInterval, beaconInterval, networkType, beaconIeLen, assocReqLen, assocRespLen, assocInfo) \
- ar6000_connect_event((devt), (channel), (bssid), (listenInterval), (beaconInterval), (networkType), (beaconIeLen), (assocReqLen), (assocRespLen), (assocInfo))
-
-#define A_WMI_PSPOLL_EVENT(devt, aid)\
- ar6000_pspoll_event((devt),(aid))
-
-#define A_WMI_DTIMEXPIRY_EVENT(devt)\
- ar6000_dtimexpiry_event((devt))
-
-#ifdef WAPI_ENABLE
-#define A_WMI_WAPI_REKEY_EVENT(devt, type, mac)\
- ap_wapi_rekey_event((devt),(type),(mac))
-#endif
-
-#define A_WMI_REGDOMAIN_EVENT(devt, regCode) \
- ar6000_regDomain_event((devt), (regCode))
-
-#define A_WMI_NEIGHBORREPORT_EVENT(devt, numAps, info) \
- ar6000_neighborReport_event((devt), (numAps), (info))
-
-#define A_WMI_DISCONNECT_EVENT(devt, reason, bssid, assocRespLen, assocInfo, protocolReasonStatus) \
- ar6000_disconnect_event((devt), (reason), (bssid), (assocRespLen), (assocInfo), (protocolReasonStatus))
-
-#define A_WMI_TKIP_MICERR_EVENT(devt, keyid, ismcast) \
- ar6000_tkip_micerr_event((devt), (keyid), (ismcast))
-
-#define A_WMI_BITRATE_RX(devt, rateKbps) \
- ar6000_bitrate_rx((devt), (rateKbps))
-
-#define A_WMI_TXPWR_RX(devt, txPwr) \
- ar6000_txPwr_rx((devt), (txPwr))
-
-#define A_WMI_READY_EVENT(devt, datap, phyCap, sw_ver, abi_ver) \
- ar6000_ready_event((devt), (datap), (phyCap), (sw_ver), (abi_ver))
-
-#define A_WMI_DBGLOG_INIT_DONE(ar) \
- ar6000_dbglog_init_done(ar);
-
-#define A_WMI_RSSI_THRESHOLD_EVENT(devt, newThreshold, rssi) \
- ar6000_rssiThreshold_event((devt), (newThreshold), (rssi))
-
-#define A_WMI_REPORT_ERROR_EVENT(devt, errorVal) \
- ar6000_reportError_event((devt), (errorVal))
-
-#define A_WMI_ROAM_TABLE_EVENT(devt, pTbl) \
- ar6000_roam_tbl_event((devt), (pTbl))
-
-#define A_WMI_ROAM_DATA_EVENT(devt, p) \
- ar6000_roam_data_event((devt), (p))
-
-#define A_WMI_WOW_LIST_EVENT(devt, num_filters, wow_filters) \
- ar6000_wow_list_event((devt), (num_filters), (wow_filters))
-
-#define A_WMI_CAC_EVENT(devt, ac, cac_indication, statusCode, tspecSuggestion) \
- ar6000_cac_event((devt), (ac), (cac_indication), (statusCode), (tspecSuggestion))
-
-#define A_WMI_CHANNEL_CHANGE_EVENT(devt, oldChannel, newChannel) \
- ar6000_channel_change_event((devt), (oldChannel), (newChannel))
-
-#define A_WMI_PMKID_LIST_EVENT(devt, num_pmkid, pmkid_list, bssid_list) \
- ar6000_pmkid_list_event((devt), (num_pmkid), (pmkid_list), (bssid_list))
-
-#define A_WMI_PEER_EVENT(devt, eventCode, bssid) \
- ar6000_peer_event ((devt), (eventCode), (bssid))
-
-#ifdef CONFIG_HOST_TCMD_SUPPORT
-#define A_WMI_TCMD_RX_REPORT_EVENT(devt, results, len) \
- ar6000_tcmd_rx_report_event((devt), (results), (len))
-#endif
-
-#define A_WMI_HBCHALLENGERESP_EVENT(devt, cookie, source) \
- ar6000_hbChallengeResp_event((devt), (cookie), (source))
-
-#define A_WMI_TX_RETRY_ERR_EVENT(devt) \
- ar6000_tx_retry_err_event((devt))
-
-#define A_WMI_SNR_THRESHOLD_EVENT_RX(devt, newThreshold, snr) \
- ar6000_snrThresholdEvent_rx((devt), (newThreshold), (snr))
-
-#define A_WMI_LQ_THRESHOLD_EVENT_RX(devt, range, lqVal) \
- ar6000_lqThresholdEvent_rx((devt), (range), (lqVal))
-
-#define A_WMI_RATEMASK_RX(devt, ratemask) \
- ar6000_ratemask_rx((devt), (ratemask))
-
-#define A_WMI_KEEPALIVE_RX(devt, configured) \
- ar6000_keepalive_rx((devt), (configured))
-
-#define A_WMI_BSSINFO_EVENT_RX(ar, datp, len) \
- ar6000_bssInfo_event_rx((ar), (datap), (len))
-
-#define A_WMI_DBGLOG_EVENT(ar, dropped, buffer, length) \
- ar6000_dbglog_event((ar), (dropped), (buffer), (length));
-
-#define A_WMI_STREAM_TX_ACTIVE(devt,trafficClass) \
- ar6000_indicate_tx_activity((devt),(trafficClass), true)
-
-#define A_WMI_STREAM_TX_INACTIVE(devt,trafficClass) \
- ar6000_indicate_tx_activity((devt),(trafficClass), false)
-#define A_WMI_Ac2EndpointID(devht, ac)\
- ar6000_ac2_endpoint_id((devht), (ac))
-
-#define A_WMI_AGGR_RECV_ADDBA_REQ_EVT(devt, cmd)\
- ar6000_aggr_rcv_addba_req_evt((devt), (cmd))
-#define A_WMI_AGGR_RECV_ADDBA_RESP_EVT(devt, cmd)\
- ar6000_aggr_rcv_addba_resp_evt((devt), (cmd))
-#define A_WMI_AGGR_RECV_DELBA_REQ_EVT(devt, cmd)\
- ar6000_aggr_rcv_delba_req_evt((devt), (cmd))
-#define A_WMI_HCI_EVENT_EVT(devt, cmd)\
- ar6000_hci_event_rcv_evt((devt), (cmd))
-
-#define A_WMI_Endpoint2Ac(devt, ep) \
- ar6000_endpoint_id2_ac((devt), (ep))
-
-#define A_WMI_BTCOEX_CONFIG_EVENT(devt, evt, len)\
- ar6000_btcoex_config_event((devt), (evt), (len))
-
-#define A_WMI_BTCOEX_STATS_EVENT(devt, datap, len)\
- ar6000_btcoex_stats_event((devt), (datap), (len))
-
-/****************************************************************************/
-/****************************************************************************/
-/** **/
-/** HTC related hooks **/
-/** **/
-/****************************************************************************/
-/****************************************************************************/
-
-#if defined(CONFIG_TARGET_PROFILE_SUPPORT)
-#define A_WMI_PROF_COUNT_RX(addr, count) prof_count_rx((addr), (count))
-#endif /* CONFIG_TARGET_PROFILE_SUPPORT */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/drivers/staging/ath6kl/include/a_osapi.h b/drivers/staging/ath6kl/include/a_osapi.h
deleted file mode 100644
index fd7ae0d612c6..000000000000
--- a/drivers/staging/ath6kl/include/a_osapi.h
+++ /dev/null
@@ -1,32 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="a_osapi.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// This file contains the definitions of the basic atheros data types.
-// It is used to map the data types in atheros files to a platform specific
-// type.
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _A_OSAPI_H_
-#define _A_OSAPI_H_
-
-#include "../os/linux/include/osapi_linux.h"
-
-#endif /* _OSAPI_H_ */
diff --git a/drivers/staging/ath6kl/include/aggr_recv_api.h b/drivers/staging/ath6kl/include/aggr_recv_api.h
deleted file mode 100644
index 5ead58d5febd..000000000000
--- a/drivers/staging/ath6kl/include/aggr_recv_api.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- *
- * Copyright (c) 2004-2010 Atheros Communications Inc.
- * All rights reserved.
- *
- *
-//
-// 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 __AGGR_RECV_API_H__
-#define __AGGR_RECV_API_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef void (* RX_CALLBACK)(void * dev, void *osbuf);
-
-typedef void (* ALLOC_NETBUFS)(A_NETBUF_QUEUE_T *q, u16 num);
-
-/*
- * aggr_init:
- * Initialises the data structures, allocates data queues and
- * os buffers. Netbuf allocator is the input param, used by the
- * aggr module for allocation of NETBUFs from driver context.
- * These NETBUFs are used for AMSDU processing.
- * Returns the context for the aggr module.
- */
-void *
-aggr_init(ALLOC_NETBUFS netbuf_allocator);
-
-
-/*
- * aggr_register_rx_dispatcher:
- * Registers OS call back function to deliver the
- * frames to OS. This is generally the topmost layer of
- * the driver context, after which the frames go to
- * IP stack via the call back function.
- * This dispatcher is active only when aggregation is ON.
- */
-void
-aggr_register_rx_dispatcher(void *cntxt, void * dev, RX_CALLBACK fn);
-
-
-/*
- * aggr_process_bar:
- * When target receives BAR, it communicates to host driver
- * for modifying window parameters. Target indicates this via the
- * event: WMI_ADDBA_REQ_EVENTID. Host will dequeue all frames
- * up to the indicated sequence number.
- */
-void
-aggr_process_bar(void *cntxt, u8 tid, u16 seq_no);
-
-
-/*
- * aggr_recv_addba_req_evt:
- * This event is to initiate/modify the receive side window.
- * Target will send WMI_ADDBA_REQ_EVENTID event to host - to setup
- * recv re-ordering queues. Target will negotiate ADDBA with peer,
- * and indicate via this event after successfully completing the
- * negotiation. This happens in two situations:
- * 1. Initial setup of aggregation
- * 2. Renegotiation of current recv window.
- * Window size for re-ordering is limited by target buffer
- * space, which is reflected in win_sz.
- * (Re)Start the periodic timer to deliver long standing frames,
- * in hold_q to OS.
- */
-void
-aggr_recv_addba_req_evt(void * cntxt, u8 tid, u16 seq_no, u8 win_sz);
-
-
-/*
- * aggr_recv_delba_req_evt:
- * Target indicates deletion of a BA window for a tid via the
- * WMI_DELBA_EVENTID. Host would deliver all the frames in the
- * hold_q, reset tid config and disable the periodic timer, if
- * aggr is not enabled on any tid.
- */
-void
-aggr_recv_delba_req_evt(void * cntxt, u8 tid);
-
-
-
-/*
- * aggr_process_recv_frm:
- * Called only for data frames. When aggr is ON for a tid, the buffer
- * is always consumed, and osbuf would be NULL. For a non-aggr case,
- * osbuf is not modified.
- * AMSDU frames are consumed and are later freed. They are sliced and
- * diced to individual frames and dispatched to stack.
- * After consuming a osbuf(when aggr is ON), a previously registered
- * callback may be called to deliver frames in order.
- */
-void
-aggr_process_recv_frm(void *cntxt, u8 tid, u16 seq_no, bool is_amsdu, void **osbuf);
-
-
-/*
- * aggr_module_destroy:
- * Frees up all the queues and frames in them. Releases the cntxt to OS.
- */
-void
-aggr_module_destroy(void *cntxt);
-
-/*
- * Dumps the aggregation stats
- */
-void
-aggr_dump_stats(void *cntxt, PACKET_LOG **log_buf);
-
-/*
- * aggr_reset_state -- Called when it is deemed necessary to clear the aggregate
- * hold Q state. Examples include when a Connect event or disconnect event is
- * received.
- */
-void
-aggr_reset_state(void *cntxt);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /*__AGGR_RECV_API_H__ */
diff --git a/drivers/staging/ath6kl/include/ar3kconfig.h b/drivers/staging/ath6kl/include/ar3kconfig.h
deleted file mode 100644
index 91bc4ee3512d..000000000000
--- a/drivers/staging/ath6kl/include/ar3kconfig.h
+++ /dev/null
@@ -1,65 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2009-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-
-/* AR3K module configuration APIs for HCI-bridge operation */
-
-#ifndef AR3KCONFIG_H_
-#define AR3KCONFIG_H_
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define AR3K_CONFIG_FLAG_FORCE_MINBOOT_EXIT (1 << 0)
-#define AR3K_CONFIG_FLAG_SET_AR3K_BAUD (1 << 1)
-#define AR3K_CONFIG_FLAG_AR3K_BAUD_CHANGE_DELAY (1 << 2)
-#define AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP (1 << 3)
-
-
-struct ar3k_config_info {
- u32 Flags; /* config flags */
- void *pHCIDev; /* HCI bridge device */
- struct hci_transport_properties *pHCIProps; /* HCI bridge props */
- struct hif_device *pHIFDevice; /* HIF layer device */
-
- u32 AR3KBaudRate; /* AR3K operational baud rate */
- u16 AR6KScale; /* AR6K UART scale value */
- u16 AR6KStep; /* AR6K UART step value */
- struct hci_dev *pBtStackHCIDev; /* BT Stack HCI dev */
- u32 PwrMgmtEnabled; /* TLPM enabled? */
- u16 IdleTimeout; /* TLPM idle timeout */
- u16 WakeupTimeout; /* TLPM wakeup timeout */
- u8 bdaddr[6]; /* Bluetooth device address */
-};
-
-int AR3KConfigure(struct ar3k_config_info *pConfigInfo);
-
-int AR3KConfigureExit(void *config);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /*AR3KCONFIG_H_*/
diff --git a/drivers/staging/ath6kl/include/ar6000_api.h b/drivers/staging/ath6kl/include/ar6000_api.h
deleted file mode 100644
index e9460800272c..000000000000
--- a/drivers/staging/ath6kl/include/ar6000_api.h
+++ /dev/null
@@ -1,32 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="ar6000_api.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// This file contains the API to access the OS dependent atheros host driver
-// by the WMI or WLAN generic modules.
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _AR6000_API_H_
-#define _AR6000_API_H_
-
-#include "../os/linux/include/ar6xapi_linux.h"
-
-#endif /* _AR6000_API_H */
-
diff --git a/drivers/staging/ath6kl/include/ar6000_diag.h b/drivers/staging/ath6kl/include/ar6000_diag.h
deleted file mode 100644
index 739c01c53f08..000000000000
--- a/drivers/staging/ath6kl/include/ar6000_diag.h
+++ /dev/null
@@ -1,48 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="ar6000_diag.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-
-#ifndef AR6000_DIAG_H_
-#define AR6000_DIAG_H_
-
-
-int
-ar6000_ReadRegDiag(struct hif_device *hifDevice, u32 *address, u32 *data);
-
-int
-ar6000_WriteRegDiag(struct hif_device *hifDevice, u32 *address, u32 *data);
-
-int
-ar6000_ReadDataDiag(struct hif_device *hifDevice, u32 address,
- u8 *data, u32 length);
-
-int
-ar6000_WriteDataDiag(struct hif_device *hifDevice, u32 address,
- u8 *data, u32 length);
-
-int
-ar6k_ReadTargetRegister(struct hif_device *hifDevice, int regsel, u32 *regval);
-
-void
-ar6k_FetchTargetRegs(struct hif_device *hifDevice, u32 *targregs);
-
-#endif /*AR6000_DIAG_H_*/
diff --git a/drivers/staging/ath6kl/include/ar6kap_common.h b/drivers/staging/ath6kl/include/ar6kap_common.h
deleted file mode 100644
index 532d8eba9326..000000000000
--- a/drivers/staging/ath6kl/include/ar6kap_common.h
+++ /dev/null
@@ -1,44 +0,0 @@
-//------------------------------------------------------------------------------
-
-// <copyright file="ar6kap_common.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-
-//==============================================================================
-
-// This file contains the definitions of common AP mode data structures.
-//
-// Author(s): ="Atheros"
-//==============================================================================
-
-#ifndef _AR6KAP_COMMON_H_
-#define _AR6KAP_COMMON_H_
-/*
- * Used with AR6000_XIOCTL_AP_GET_STA_LIST
- */
-typedef struct {
- u8 mac[ATH_MAC_LEN];
- u8 aid;
- u8 keymgmt;
- u8 ucipher;
- u8 auth;
-} station_t;
-typedef struct {
- station_t sta[AP_MAX_NUM_STA];
-} ap_get_sta_t;
-#endif /* _AR6KAP_COMMON_H_ */
diff --git a/drivers/staging/ath6kl/include/athbtfilter.h b/drivers/staging/ath6kl/include/athbtfilter.h
deleted file mode 100644
index 81456eea3b0b..000000000000
--- a/drivers/staging/ath6kl/include/athbtfilter.h
+++ /dev/null
@@ -1,135 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="athbtfilter.h" company="Atheros">
-// Copyright (c) 2007-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Public Bluetooth filter APIs
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef ATHBTFILTER_H_
-#define ATHBTFILTER_H_
-
-#define ATH_DEBUG_INFO (1 << 2)
-#define ATH_DEBUG_INF ATH_DEBUG_INFO
-
-typedef enum _ATHBT_HCI_CTRL_TYPE {
- ATHBT_HCI_COMMAND = 0,
- ATHBT_HCI_EVENT = 1,
-} ATHBT_HCI_CTRL_TYPE;
-
-typedef enum _ATHBT_STATE_INDICATION {
- ATH_BT_NOOP = 0,
- ATH_BT_INQUIRY = 1,
- ATH_BT_CONNECT = 2,
- ATH_BT_SCO = 3,
- ATH_BT_ACL = 4,
- ATH_BT_A2DP = 5,
- ATH_BT_ESCO = 6,
- /* new states go here.. */
-
- ATH_BT_MAX_STATE_INDICATION
-} ATHBT_STATE_INDICATION;
-
- /* filter function for OUTGOING commands and INCOMMING events */
-typedef void (*ATHBT_FILTER_CMD_EVENTS_FN)(void *pContext, ATHBT_HCI_CTRL_TYPE Type, unsigned char *pBuffer, int Length);
-
- /* filter function for OUTGOING data HCI packets */
-typedef void (*ATHBT_FILTER_DATA_FN)(void *pContext, unsigned char *pBuffer, int Length);
-
-typedef enum _ATHBT_STATE {
- STATE_OFF = 0,
- STATE_ON = 1,
- STATE_MAX
-} ATHBT_STATE;
-
- /* BT state indication (when filter functions are not used) */
-
-typedef void (*ATHBT_INDICATE_STATE_FN)(void *pContext, ATHBT_STATE_INDICATION Indication, ATHBT_STATE State, unsigned char LMPVersion);
-
-struct athbt_filter_instance {
-#ifdef UNDER_CE
- WCHAR *pWlanAdapterName; /* filled in by user */
-#else
- char *pWlanAdapterName; /* filled in by user */
-#endif /* UNDER_CE */
- int FilterEnabled; /* filtering is enabled */
- int Attached; /* filter library is attached */
- void *pContext; /* private context for filter library */
- ATHBT_FILTER_CMD_EVENTS_FN pFilterCmdEvents; /* function ptr to filter a command or event */
- ATHBT_FILTER_DATA_FN pFilterAclDataOut; /* function ptr to filter ACL data out (to radio) */
- ATHBT_FILTER_DATA_FN pFilterAclDataIn; /* function ptr to filter ACL data in (from radio) */
- ATHBT_INDICATE_STATE_FN pIndicateState; /* function ptr to indicate a state */
-}; /* XXX: unused ? */
-
-
-/* API MACROS */
-
-#define AthBtFilterHciCommand(instance,packet,length) \
- if ((instance)->FilterEnabled) { \
- (instance)->pFilterCmdEvents((instance)->pContext, \
- ATHBT_HCI_COMMAND, \
- (unsigned char *)(packet), \
- (length)); \
- }
-
-#define AthBtFilterHciEvent(instance,packet,length) \
- if ((instance)->FilterEnabled) { \
- (instance)->pFilterCmdEvents((instance)->pContext, \
- ATHBT_HCI_EVENT, \
- (unsigned char *)(packet), \
- (length)); \
- }
-
-#define AthBtFilterHciAclDataOut(instance,packet,length) \
- if ((instance)->FilterEnabled) { \
- (instance)->pFilterAclDataOut((instance)->pContext, \
- (unsigned char *)(packet), \
- (length)); \
- }
-
-#define AthBtFilterHciAclDataIn(instance,packet,length) \
- if ((instance)->FilterEnabled) { \
- (instance)->pFilterAclDataIn((instance)->pContext, \
- (unsigned char *)(packet), \
- (length)); \
- }
-
-/* if filtering is not desired, the application can indicate the state directly using this
- * macro:
- */
-#define AthBtIndicateState(instance,indication,state) \
- if ((instance)->FilterEnabled) { \
- (instance)->pIndicateState((instance)->pContext, \
- (indication), \
- (state), \
- 0); \
- }
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* API prototypes */
-int AthBtFilter_Attach(ATH_BT_FILTER_INSTANCE *pInstance, unsigned int flags);
-void AthBtFilter_Detach(ATH_BT_FILTER_INSTANCE *pInstance);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /*ATHBTFILTER_H_*/
diff --git a/drivers/staging/ath6kl/include/bmi.h b/drivers/staging/ath6kl/include/bmi.h
deleted file mode 100644
index d3227f77fa5d..000000000000
--- a/drivers/staging/ath6kl/include/bmi.h
+++ /dev/null
@@ -1,134 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="bmi.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// BMI declarations and prototypes
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _BMI_H_
-#define _BMI_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-/* Header files */
-#include "a_config.h"
-#include "athdefs.h"
-#include "hif.h"
-#include "a_osapi.h"
-#include "bmi_msg.h"
-
-void
-BMIInit(void);
-
-void
-BMICleanup(void);
-
-int
-BMIDone(struct hif_device *device);
-
-int
-BMIGetTargetInfo(struct hif_device *device, struct bmi_target_info *targ_info);
-
-int
-BMIReadMemory(struct hif_device *device,
- u32 address,
- u8 *buffer,
- u32 length);
-
-int
-BMIWriteMemory(struct hif_device *device,
- u32 address,
- u8 *buffer,
- u32 length);
-
-int
-BMIExecute(struct hif_device *device,
- u32 address,
- u32 *param);
-
-int
-BMISetAppStart(struct hif_device *device,
- u32 address);
-
-int
-BMIReadSOCRegister(struct hif_device *device,
- u32 address,
- u32 *param);
-
-int
-BMIWriteSOCRegister(struct hif_device *device,
- u32 address,
- u32 param);
-
-int
-BMIrompatchInstall(struct hif_device *device,
- u32 ROM_addr,
- u32 RAM_addr,
- u32 nbytes,
- u32 do_activate,
- u32 *patch_id);
-
-int
-BMIrompatchUninstall(struct hif_device *device,
- u32 rompatch_id);
-
-int
-BMIrompatchActivate(struct hif_device *device,
- u32 rompatch_count,
- u32 *rompatch_list);
-
-int
-BMIrompatchDeactivate(struct hif_device *device,
- u32 rompatch_count,
- u32 *rompatch_list);
-
-int
-BMILZStreamStart(struct hif_device *device,
- u32 address);
-
-int
-BMILZData(struct hif_device *device,
- u8 *buffer,
- u32 length);
-
-int
-BMIFastDownload(struct hif_device *device,
- u32 address,
- u8 *buffer,
- u32 length);
-
-int
-BMIRawWrite(struct hif_device *device,
- u8 *buffer,
- u32 length);
-
-int
-BMIRawRead(struct hif_device *device,
- u8 *buffer,
- u32 length,
- bool want_timeout);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _BMI_H_ */
diff --git a/drivers/staging/ath6kl/include/common/AR6002/AR6K_version.h b/drivers/staging/ath6kl/include/common/AR6002/AR6K_version.h
deleted file mode 100644
index 5407e05d9b05..000000000000
--- a/drivers/staging/ath6kl/include/common/AR6002/AR6K_version.h
+++ /dev/null
@@ -1,52 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="AR6K_version.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-
-#define __VER_MAJOR_ 3
-#define __VER_MINOR_ 0
-#define __VER_PATCH_ 0
-
-/* The makear6ksdk script (used for release builds) modifies the following line. */
-#define __BUILD_NUMBER_ 233
-
-
-/* Format of the version number. */
-#define VER_MAJOR_BIT_OFFSET 28
-#define VER_MINOR_BIT_OFFSET 24
-#define VER_PATCH_BIT_OFFSET 16
-#define VER_BUILD_NUM_BIT_OFFSET 0
-
-
-/*
- * The version has the following format:
- * Bits 28-31: Major version
- * Bits 24-27: Minor version
- * Bits 16-23: Patch version
- * Bits 0-15: Build number (automatically generated during build process )
- * E.g. Build 1.1.3.7 would be represented as 0x11030007.
- *
- * DO NOT split the following macro into multiple lines as this may confuse the build scripts.
- */
-#define AR6K_SW_VERSION ( ( __VER_MAJOR_ << VER_MAJOR_BIT_OFFSET ) + ( __VER_MINOR_ << VER_MINOR_BIT_OFFSET ) + ( __VER_PATCH_ << VER_PATCH_BIT_OFFSET ) + ( __BUILD_NUMBER_ << VER_BUILD_NUM_BIT_OFFSET ) )
-
-/* ABI Version. Reflects the version of binary interface exposed by AR6K target firmware. Needs to be incremented by 1 for any change in the firmware that requires upgrade of the driver on the host side for the change to work correctly */
-#define AR6K_ABI_VERSION 1
diff --git a/drivers/staging/ath6kl/include/common/AR6002/addrs.h b/drivers/staging/ath6kl/include/common/AR6002/addrs.h
deleted file mode 100644
index bbf8d42828c1..000000000000
--- a/drivers/staging/ath6kl/include/common/AR6002/addrs.h
+++ /dev/null
@@ -1,90 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//
-// Author(s): ="Atheros"
-//------------------------------------------------------------------------------
-
-#ifndef __ADDRS_H__
-#define __ADDRS_H__
-
-/*
- * Special AR6002 Addresses that may be needed by special
- * applications (e.g. ART) on the Host as well as Target.
- */
-
-#if defined(AR6002_REV2)
-#define AR6K_RAM_START 0x00500000
-#define TARG_RAM_OFFSET(vaddr) ((u32)(vaddr) & 0xfffff)
-#define TARG_RAM_SZ (184*1024)
-#define TARG_ROM_SZ (80*1024)
-#endif
-#if defined(AR6002_REV4) || defined(AR6003)
-#define AR6K_RAM_START 0x00540000
-#define TARG_RAM_OFFSET(vaddr) (((u32)(vaddr) & 0xfffff) - 0x40000)
-#define TARG_RAM_SZ (256*1024)
-#define TARG_ROM_SZ (256*1024)
-#endif
-
-#define AR6002_BOARD_DATA_SZ 768
-#define AR6002_BOARD_EXT_DATA_SZ 0
-#define AR6003_BOARD_DATA_SZ 1024
-#define AR6003_BOARD_EXT_DATA_SZ 768
-
-#define AR6K_RAM_ADDR(byte_offset) (AR6K_RAM_START+(byte_offset))
-#define TARG_RAM_ADDRS(byte_offset) AR6K_RAM_ADDR(byte_offset)
-
-#define AR6K_ROM_START 0x004e0000
-#define TARG_ROM_OFFSET(vaddr) (((u32)(vaddr) & 0x1fffff) - 0xe0000)
-#define AR6K_ROM_ADDR(byte_offset) (AR6K_ROM_START+(byte_offset))
-#define TARG_ROM_ADDRS(byte_offset) AR6K_ROM_ADDR(byte_offset)
-
-/*
- * At this ROM address is a pointer to the start of the ROM DataSet Index.
- * If there are no ROM DataSets, there's a 0 at this address.
- */
-#define ROM_DATASET_INDEX_ADDR (TARG_ROM_ADDRS(TARG_ROM_SZ)-8)
-#define ROM_MBIST_CKSUM_ADDR (TARG_ROM_ADDRS(TARG_ROM_SZ)-4)
-
-/*
- * The API A_BOARD_DATA_ADDR() is the proper way to get a read pointer to
- * board data.
- */
-
-/* Size of Board Data, in bytes */
-#if defined(AR6002_REV4) || defined(AR6003)
-#define BOARD_DATA_SZ AR6003_BOARD_DATA_SZ
-#else
-#define BOARD_DATA_SZ AR6002_BOARD_DATA_SZ
-#endif
-
-
-/*
- * Constants used by ASM code to access fields of host_interest_s,
- * which is at a fixed location in RAM.
- */
-#if defined(AR6002_REV4) || defined(AR6003)
-#define HOST_INTEREST_FLASH_IS_PRESENT_ADDR (AR6K_RAM_START + 0x60c)
-#else
-#define HOST_INTEREST_FLASH_IS_PRESENT_ADDR (AR6K_RAM_START + 0x40c)
-#endif
-#define FLASH_IS_PRESENT_TARGADDR HOST_INTEREST_FLASH_IS_PRESENT_ADDR
-
-#endif /* __ADDRS_H__ */
-
-
-
diff --git a/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/apb_athr_wlan_map.h b/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/apb_athr_wlan_map.h
deleted file mode 100644
index 609eb9841f59..000000000000
--- a/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/apb_athr_wlan_map.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// ------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-// ------------------------------------------------------------------
-//===================================================================
-// Author(s): ="Atheros"
-//===================================================================
-
-
-#ifndef _APB_ATHR_WLAN_MAP_H_
-#define _APB_ATHR_WLAN_MAP_H_
-
-#define WLAN_RTC_BASE_ADDRESS 0x00004000
-#define WLAN_VMC_BASE_ADDRESS 0x00008000
-#define WLAN_UART_BASE_ADDRESS 0x0000c000
-#define WLAN_DBG_UART_BASE_ADDRESS 0x0000d000
-#define WLAN_UMBOX_BASE_ADDRESS 0x0000e000
-#define WLAN_SI_BASE_ADDRESS 0x00010000
-#define WLAN_GPIO_BASE_ADDRESS 0x00014000
-#define WLAN_MBOX_BASE_ADDRESS 0x00018000
-#define WLAN_ANALOG_INTF_BASE_ADDRESS 0x0001c000
-#define WLAN_MAC_BASE_ADDRESS 0x00020000
-#define WLAN_RDMA_BASE_ADDRESS 0x00030100
-#define EFUSE_BASE_ADDRESS 0x00031000
-
-#endif /* _APB_ATHR_WLAN_MAP_REG_H_ */
diff --git a/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/apb_map.h b/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/apb_map.h
deleted file mode 100644
index 0068ca31b051..000000000000
--- a/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/apb_map.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// ------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-// ------------------------------------------------------------------
-//===================================================================
-// Author(s): ="Atheros"
-//===================================================================
-
-
-#include "apb_athr_wlan_map.h"
-
-#ifndef BT_HEADERS
-
-#define RTC_BASE_ADDRESS WLAN_RTC_BASE_ADDRESS
-#define VMC_BASE_ADDRESS WLAN_VMC_BASE_ADDRESS
-#define UART_BASE_ADDRESS WLAN_UART_BASE_ADDRESS
-#define DBG_UART_BASE_ADDRESS WLAN_DBG_UART_BASE_ADDRESS
-#define UMBOX_BASE_ADDRESS WLAN_UMBOX_BASE_ADDRESS
-#define SI_BASE_ADDRESS WLAN_SI_BASE_ADDRESS
-#define GPIO_BASE_ADDRESS WLAN_GPIO_BASE_ADDRESS
-#define MBOX_BASE_ADDRESS WLAN_MBOX_BASE_ADDRESS
-#define ANALOG_INTF_BASE_ADDRESS WLAN_ANALOG_INTF_BASE_ADDRESS
-#define MAC_BASE_ADDRESS WLAN_MAC_BASE_ADDRESS
-#define RDMA_BASE_ADDRESS WLAN_RDMA_BASE_ADDRESS
-
-#endif
diff --git a/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/mbox_host_reg.h b/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/mbox_host_reg.h
deleted file mode 100644
index 109f24e10a65..000000000000
--- a/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/mbox_host_reg.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// ------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-// ------------------------------------------------------------------
-//===================================================================
-// Author(s): ="Atheros"
-//===================================================================
-
-
-#include "mbox_wlan_host_reg.h"
diff --git a/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/mbox_reg.h b/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/mbox_reg.h
deleted file mode 100644
index 72fa483450d6..000000000000
--- a/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/mbox_reg.h
+++ /dev/null
@@ -1,552 +0,0 @@
-// ------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-// ------------------------------------------------------------------
-//===================================================================
-// Author(s): ="Atheros"
-//===================================================================
-
-
-#include "mbox_wlan_reg.h"
-
-#ifndef BT_HEADERS
-
-#define MBOX_FIFO_ADDRESS WLAN_MBOX_FIFO_ADDRESS
-#define MBOX_FIFO_OFFSET WLAN_MBOX_FIFO_OFFSET
-#define MBOX_FIFO_DATA_MSB WLAN_MBOX_FIFO_DATA_MSB
-#define MBOX_FIFO_DATA_LSB WLAN_MBOX_FIFO_DATA_LSB
-#define MBOX_FIFO_DATA_MASK WLAN_MBOX_FIFO_DATA_MASK
-#define MBOX_FIFO_DATA_GET(x) WLAN_MBOX_FIFO_DATA_GET(x)
-#define MBOX_FIFO_DATA_SET(x) WLAN_MBOX_FIFO_DATA_SET(x)
-#define MBOX_FIFO_STATUS_ADDRESS WLAN_MBOX_FIFO_STATUS_ADDRESS
-#define MBOX_FIFO_STATUS_OFFSET WLAN_MBOX_FIFO_STATUS_OFFSET
-#define MBOX_FIFO_STATUS_EMPTY_MSB WLAN_MBOX_FIFO_STATUS_EMPTY_MSB
-#define MBOX_FIFO_STATUS_EMPTY_LSB WLAN_MBOX_FIFO_STATUS_EMPTY_LSB
-#define MBOX_FIFO_STATUS_EMPTY_MASK WLAN_MBOX_FIFO_STATUS_EMPTY_MASK
-#define MBOX_FIFO_STATUS_EMPTY_GET(x) WLAN_MBOX_FIFO_STATUS_EMPTY_GET(x)
-#define MBOX_FIFO_STATUS_EMPTY_SET(x) WLAN_MBOX_FIFO_STATUS_EMPTY_SET(x)
-#define MBOX_FIFO_STATUS_FULL_MSB WLAN_MBOX_FIFO_STATUS_FULL_MSB
-#define MBOX_FIFO_STATUS_FULL_LSB WLAN_MBOX_FIFO_STATUS_FULL_LSB
-#define MBOX_FIFO_STATUS_FULL_MASK WLAN_MBOX_FIFO_STATUS_FULL_MASK
-#define MBOX_FIFO_STATUS_FULL_GET(x) WLAN_MBOX_FIFO_STATUS_FULL_GET(x)
-#define MBOX_FIFO_STATUS_FULL_SET(x) WLAN_MBOX_FIFO_STATUS_FULL_SET(x)
-#define MBOX_DMA_POLICY_ADDRESS WLAN_MBOX_DMA_POLICY_ADDRESS
-#define MBOX_DMA_POLICY_OFFSET WLAN_MBOX_DMA_POLICY_OFFSET
-#define MBOX_DMA_POLICY_TX_QUANTUM_MSB WLAN_MBOX_DMA_POLICY_TX_QUANTUM_MSB
-#define MBOX_DMA_POLICY_TX_QUANTUM_LSB WLAN_MBOX_DMA_POLICY_TX_QUANTUM_LSB
-#define MBOX_DMA_POLICY_TX_QUANTUM_MASK WLAN_MBOX_DMA_POLICY_TX_QUANTUM_MASK
-#define MBOX_DMA_POLICY_TX_QUANTUM_GET(x) WLAN_MBOX_DMA_POLICY_TX_QUANTUM_GET(x)
-#define MBOX_DMA_POLICY_TX_QUANTUM_SET(x) WLAN_MBOX_DMA_POLICY_TX_QUANTUM_SET(x)
-#define MBOX_DMA_POLICY_TX_ORDER_MSB WLAN_MBOX_DMA_POLICY_TX_ORDER_MSB
-#define MBOX_DMA_POLICY_TX_ORDER_LSB WLAN_MBOX_DMA_POLICY_TX_ORDER_LSB
-#define MBOX_DMA_POLICY_TX_ORDER_MASK WLAN_MBOX_DMA_POLICY_TX_ORDER_MASK
-#define MBOX_DMA_POLICY_TX_ORDER_GET(x) WLAN_MBOX_DMA_POLICY_TX_ORDER_GET(x)
-#define MBOX_DMA_POLICY_TX_ORDER_SET(x) WLAN_MBOX_DMA_POLICY_TX_ORDER_SET(x)
-#define MBOX_DMA_POLICY_RX_QUANTUM_MSB WLAN_MBOX_DMA_POLICY_RX_QUANTUM_MSB
-#define MBOX_DMA_POLICY_RX_QUANTUM_LSB WLAN_MBOX_DMA_POLICY_RX_QUANTUM_LSB
-#define MBOX_DMA_POLICY_RX_QUANTUM_MASK WLAN_MBOX_DMA_POLICY_RX_QUANTUM_MASK
-#define MBOX_DMA_POLICY_RX_QUANTUM_GET(x) WLAN_MBOX_DMA_POLICY_RX_QUANTUM_GET(x)
-#define MBOX_DMA_POLICY_RX_QUANTUM_SET(x) WLAN_MBOX_DMA_POLICY_RX_QUANTUM_SET(x)
-#define MBOX_DMA_POLICY_RX_ORDER_MSB WLAN_MBOX_DMA_POLICY_RX_ORDER_MSB
-#define MBOX_DMA_POLICY_RX_ORDER_LSB WLAN_MBOX_DMA_POLICY_RX_ORDER_LSB
-#define MBOX_DMA_POLICY_RX_ORDER_MASK WLAN_MBOX_DMA_POLICY_RX_ORDER_MASK
-#define MBOX_DMA_POLICY_RX_ORDER_GET(x) WLAN_MBOX_DMA_POLICY_RX_ORDER_GET(x)
-#define MBOX_DMA_POLICY_RX_ORDER_SET(x) WLAN_MBOX_DMA_POLICY_RX_ORDER_SET(x)
-#define MBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS WLAN_MBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS
-#define MBOX0_DMA_RX_DESCRIPTOR_BASE_OFFSET WLAN_MBOX0_DMA_RX_DESCRIPTOR_BASE_OFFSET
-#define MBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MSB WLAN_MBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MSB
-#define MBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB WLAN_MBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB
-#define MBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK WLAN_MBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK
-#define MBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_GET(x) WLAN_MBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_GET(x)
-#define MBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_SET(x) WLAN_MBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_SET(x)
-#define MBOX0_DMA_RX_CONTROL_ADDRESS WLAN_MBOX0_DMA_RX_CONTROL_ADDRESS
-#define MBOX0_DMA_RX_CONTROL_OFFSET WLAN_MBOX0_DMA_RX_CONTROL_OFFSET
-#define MBOX0_DMA_RX_CONTROL_RESUME_MSB WLAN_MBOX0_DMA_RX_CONTROL_RESUME_MSB
-#define MBOX0_DMA_RX_CONTROL_RESUME_LSB WLAN_MBOX0_DMA_RX_CONTROL_RESUME_LSB
-#define MBOX0_DMA_RX_CONTROL_RESUME_MASK WLAN_MBOX0_DMA_RX_CONTROL_RESUME_MASK
-#define MBOX0_DMA_RX_CONTROL_RESUME_GET(x) WLAN_MBOX0_DMA_RX_CONTROL_RESUME_GET(x)
-#define MBOX0_DMA_RX_CONTROL_RESUME_SET(x) WLAN_MBOX0_DMA_RX_CONTROL_RESUME_SET(x)
-#define MBOX0_DMA_RX_CONTROL_START_MSB WLAN_MBOX0_DMA_RX_CONTROL_START_MSB
-#define MBOX0_DMA_RX_CONTROL_START_LSB WLAN_MBOX0_DMA_RX_CONTROL_START_LSB
-#define MBOX0_DMA_RX_CONTROL_START_MASK WLAN_MBOX0_DMA_RX_CONTROL_START_MASK
-#define MBOX0_DMA_RX_CONTROL_START_GET(x) WLAN_MBOX0_DMA_RX_CONTROL_START_GET(x)
-#define MBOX0_DMA_RX_CONTROL_START_SET(x) WLAN_MBOX0_DMA_RX_CONTROL_START_SET(x)
-#define MBOX0_DMA_RX_CONTROL_STOP_MSB WLAN_MBOX0_DMA_RX_CONTROL_STOP_MSB
-#define MBOX0_DMA_RX_CONTROL_STOP_LSB WLAN_MBOX0_DMA_RX_CONTROL_STOP_LSB
-#define MBOX0_DMA_RX_CONTROL_STOP_MASK WLAN_MBOX0_DMA_RX_CONTROL_STOP_MASK
-#define MBOX0_DMA_RX_CONTROL_STOP_GET(x) WLAN_MBOX0_DMA_RX_CONTROL_STOP_GET(x)
-#define MBOX0_DMA_RX_CONTROL_STOP_SET(x) WLAN_MBOX0_DMA_RX_CONTROL_STOP_SET(x)
-#define MBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS WLAN_MBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS
-#define MBOX0_DMA_TX_DESCRIPTOR_BASE_OFFSET WLAN_MBOX0_DMA_TX_DESCRIPTOR_BASE_OFFSET
-#define MBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MSB WLAN_MBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MSB
-#define MBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB WLAN_MBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB
-#define MBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK WLAN_MBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK
-#define MBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_GET(x) WLAN_MBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_GET(x)
-#define MBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_SET(x) WLAN_MBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_SET(x)
-#define MBOX0_DMA_TX_CONTROL_ADDRESS WLAN_MBOX0_DMA_TX_CONTROL_ADDRESS
-#define MBOX0_DMA_TX_CONTROL_OFFSET WLAN_MBOX0_DMA_TX_CONTROL_OFFSET
-#define MBOX0_DMA_TX_CONTROL_RESUME_MSB WLAN_MBOX0_DMA_TX_CONTROL_RESUME_MSB
-#define MBOX0_DMA_TX_CONTROL_RESUME_LSB WLAN_MBOX0_DMA_TX_CONTROL_RESUME_LSB
-#define MBOX0_DMA_TX_CONTROL_RESUME_MASK WLAN_MBOX0_DMA_TX_CONTROL_RESUME_MASK
-#define MBOX0_DMA_TX_CONTROL_RESUME_GET(x) WLAN_MBOX0_DMA_TX_CONTROL_RESUME_GET(x)
-#define MBOX0_DMA_TX_CONTROL_RESUME_SET(x) WLAN_MBOX0_DMA_TX_CONTROL_RESUME_SET(x)
-#define MBOX0_DMA_TX_CONTROL_START_MSB WLAN_MBOX0_DMA_TX_CONTROL_START_MSB
-#define MBOX0_DMA_TX_CONTROL_START_LSB WLAN_MBOX0_DMA_TX_CONTROL_START_LSB
-#define MBOX0_DMA_TX_CONTROL_START_MASK WLAN_MBOX0_DMA_TX_CONTROL_START_MASK
-#define MBOX0_DMA_TX_CONTROL_START_GET(x) WLAN_MBOX0_DMA_TX_CONTROL_START_GET(x)
-#define MBOX0_DMA_TX_CONTROL_START_SET(x) WLAN_MBOX0_DMA_TX_CONTROL_START_SET(x)
-#define MBOX0_DMA_TX_CONTROL_STOP_MSB WLAN_MBOX0_DMA_TX_CONTROL_STOP_MSB
-#define MBOX0_DMA_TX_CONTROL_STOP_LSB WLAN_MBOX0_DMA_TX_CONTROL_STOP_LSB
-#define MBOX0_DMA_TX_CONTROL_STOP_MASK WLAN_MBOX0_DMA_TX_CONTROL_STOP_MASK
-#define MBOX0_DMA_TX_CONTROL_STOP_GET(x) WLAN_MBOX0_DMA_TX_CONTROL_STOP_GET(x)
-#define MBOX0_DMA_TX_CONTROL_STOP_SET(x) WLAN_MBOX0_DMA_TX_CONTROL_STOP_SET(x)
-#define MBOX1_DMA_RX_DESCRIPTOR_BASE_ADDRESS WLAN_MBOX1_DMA_RX_DESCRIPTOR_BASE_ADDRESS
-#define MBOX1_DMA_RX_DESCRIPTOR_BASE_OFFSET WLAN_MBOX1_DMA_RX_DESCRIPTOR_BASE_OFFSET
-#define MBOX1_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MSB WLAN_MBOX1_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MSB
-#define MBOX1_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB WLAN_MBOX1_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB
-#define MBOX1_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK WLAN_MBOX1_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK
-#define MBOX1_DMA_RX_DESCRIPTOR_BASE_ADDRESS_GET(x) WLAN_MBOX1_DMA_RX_DESCRIPTOR_BASE_ADDRESS_GET(x)
-#define MBOX1_DMA_RX_DESCRIPTOR_BASE_ADDRESS_SET(x) WLAN_MBOX1_DMA_RX_DESCRIPTOR_BASE_ADDRESS_SET(x)
-#define MBOX1_DMA_RX_CONTROL_ADDRESS WLAN_MBOX1_DMA_RX_CONTROL_ADDRESS
-#define MBOX1_DMA_RX_CONTROL_OFFSET WLAN_MBOX1_DMA_RX_CONTROL_OFFSET
-#define MBOX1_DMA_RX_CONTROL_RESUME_MSB WLAN_MBOX1_DMA_RX_CONTROL_RESUME_MSB
-#define MBOX1_DMA_RX_CONTROL_RESUME_LSB WLAN_MBOX1_DMA_RX_CONTROL_RESUME_LSB
-#define MBOX1_DMA_RX_CONTROL_RESUME_MASK WLAN_MBOX1_DMA_RX_CONTROL_RESUME_MASK
-#define MBOX1_DMA_RX_CONTROL_RESUME_GET(x) WLAN_MBOX1_DMA_RX_CONTROL_RESUME_GET(x)
-#define MBOX1_DMA_RX_CONTROL_RESUME_SET(x) WLAN_MBOX1_DMA_RX_CONTROL_RESUME_SET(x)
-#define MBOX1_DMA_RX_CONTROL_START_MSB WLAN_MBOX1_DMA_RX_CONTROL_START_MSB
-#define MBOX1_DMA_RX_CONTROL_START_LSB WLAN_MBOX1_DMA_RX_CONTROL_START_LSB
-#define MBOX1_DMA_RX_CONTROL_START_MASK WLAN_MBOX1_DMA_RX_CONTROL_START_MASK
-#define MBOX1_DMA_RX_CONTROL_START_GET(x) WLAN_MBOX1_DMA_RX_CONTROL_START_GET(x)
-#define MBOX1_DMA_RX_CONTROL_START_SET(x) WLAN_MBOX1_DMA_RX_CONTROL_START_SET(x)
-#define MBOX1_DMA_RX_CONTROL_STOP_MSB WLAN_MBOX1_DMA_RX_CONTROL_STOP_MSB
-#define MBOX1_DMA_RX_CONTROL_STOP_LSB WLAN_MBOX1_DMA_RX_CONTROL_STOP_LSB
-#define MBOX1_DMA_RX_CONTROL_STOP_MASK WLAN_MBOX1_DMA_RX_CONTROL_STOP_MASK
-#define MBOX1_DMA_RX_CONTROL_STOP_GET(x) WLAN_MBOX1_DMA_RX_CONTROL_STOP_GET(x)
-#define MBOX1_DMA_RX_CONTROL_STOP_SET(x) WLAN_MBOX1_DMA_RX_CONTROL_STOP_SET(x)
-#define MBOX1_DMA_TX_DESCRIPTOR_BASE_ADDRESS WLAN_MBOX1_DMA_TX_DESCRIPTOR_BASE_ADDRESS
-#define MBOX1_DMA_TX_DESCRIPTOR_BASE_OFFSET WLAN_MBOX1_DMA_TX_DESCRIPTOR_BASE_OFFSET
-#define MBOX1_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MSB WLAN_MBOX1_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MSB
-#define MBOX1_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB WLAN_MBOX1_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB
-#define MBOX1_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK WLAN_MBOX1_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK
-#define MBOX1_DMA_TX_DESCRIPTOR_BASE_ADDRESS_GET(x) WLAN_MBOX1_DMA_TX_DESCRIPTOR_BASE_ADDRESS_GET(x)
-#define MBOX1_DMA_TX_DESCRIPTOR_BASE_ADDRESS_SET(x) WLAN_MBOX1_DMA_TX_DESCRIPTOR_BASE_ADDRESS_SET(x)
-#define MBOX1_DMA_TX_CONTROL_ADDRESS WLAN_MBOX1_DMA_TX_CONTROL_ADDRESS
-#define MBOX1_DMA_TX_CONTROL_OFFSET WLAN_MBOX1_DMA_TX_CONTROL_OFFSET
-#define MBOX1_DMA_TX_CONTROL_RESUME_MSB WLAN_MBOX1_DMA_TX_CONTROL_RESUME_MSB
-#define MBOX1_DMA_TX_CONTROL_RESUME_LSB WLAN_MBOX1_DMA_TX_CONTROL_RESUME_LSB
-#define MBOX1_DMA_TX_CONTROL_RESUME_MASK WLAN_MBOX1_DMA_TX_CONTROL_RESUME_MASK
-#define MBOX1_DMA_TX_CONTROL_RESUME_GET(x) WLAN_MBOX1_DMA_TX_CONTROL_RESUME_GET(x)
-#define MBOX1_DMA_TX_CONTROL_RESUME_SET(x) WLAN_MBOX1_DMA_TX_CONTROL_RESUME_SET(x)
-#define MBOX1_DMA_TX_CONTROL_START_MSB WLAN_MBOX1_DMA_TX_CONTROL_START_MSB
-#define MBOX1_DMA_TX_CONTROL_START_LSB WLAN_MBOX1_DMA_TX_CONTROL_START_LSB
-#define MBOX1_DMA_TX_CONTROL_START_MASK WLAN_MBOX1_DMA_TX_CONTROL_START_MASK
-#define MBOX1_DMA_TX_CONTROL_START_GET(x) WLAN_MBOX1_DMA_TX_CONTROL_START_GET(x)
-#define MBOX1_DMA_TX_CONTROL_START_SET(x) WLAN_MBOX1_DMA_TX_CONTROL_START_SET(x)
-#define MBOX1_DMA_TX_CONTROL_STOP_MSB WLAN_MBOX1_DMA_TX_CONTROL_STOP_MSB
-#define MBOX1_DMA_TX_CONTROL_STOP_LSB WLAN_MBOX1_DMA_TX_CONTROL_STOP_LSB
-#define MBOX1_DMA_TX_CONTROL_STOP_MASK WLAN_MBOX1_DMA_TX_CONTROL_STOP_MASK
-#define MBOX1_DMA_TX_CONTROL_STOP_GET(x) WLAN_MBOX1_DMA_TX_CONTROL_STOP_GET(x)
-#define MBOX1_DMA_TX_CONTROL_STOP_SET(x) WLAN_MBOX1_DMA_TX_CONTROL_STOP_SET(x)
-#define MBOX2_DMA_RX_DESCRIPTOR_BASE_ADDRESS WLAN_MBOX2_DMA_RX_DESCRIPTOR_BASE_ADDRESS
-#define MBOX2_DMA_RX_DESCRIPTOR_BASE_OFFSET WLAN_MBOX2_DMA_RX_DESCRIPTOR_BASE_OFFSET
-#define MBOX2_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MSB WLAN_MBOX2_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MSB
-#define MBOX2_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB WLAN_MBOX2_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB
-#define MBOX2_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK WLAN_MBOX2_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK
-#define MBOX2_DMA_RX_DESCRIPTOR_BASE_ADDRESS_GET(x) WLAN_MBOX2_DMA_RX_DESCRIPTOR_BASE_ADDRESS_GET(x)
-#define MBOX2_DMA_RX_DESCRIPTOR_BASE_ADDRESS_SET(x) WLAN_MBOX2_DMA_RX_DESCRIPTOR_BASE_ADDRESS_SET(x)
-#define MBOX2_DMA_RX_CONTROL_ADDRESS WLAN_MBOX2_DMA_RX_CONTROL_ADDRESS
-#define MBOX2_DMA_RX_CONTROL_OFFSET WLAN_MBOX2_DMA_RX_CONTROL_OFFSET
-#define MBOX2_DMA_RX_CONTROL_RESUME_MSB WLAN_MBOX2_DMA_RX_CONTROL_RESUME_MSB
-#define MBOX2_DMA_RX_CONTROL_RESUME_LSB WLAN_MBOX2_DMA_RX_CONTROL_RESUME_LSB
-#define MBOX2_DMA_RX_CONTROL_RESUME_MASK WLAN_MBOX2_DMA_RX_CONTROL_RESUME_MASK
-#define MBOX2_DMA_RX_CONTROL_RESUME_GET(x) WLAN_MBOX2_DMA_RX_CONTROL_RESUME_GET(x)
-#define MBOX2_DMA_RX_CONTROL_RESUME_SET(x) WLAN_MBOX2_DMA_RX_CONTROL_RESUME_SET(x)
-#define MBOX2_DMA_RX_CONTROL_START_MSB WLAN_MBOX2_DMA_RX_CONTROL_START_MSB
-#define MBOX2_DMA_RX_CONTROL_START_LSB WLAN_MBOX2_DMA_RX_CONTROL_START_LSB
-#define MBOX2_DMA_RX_CONTROL_START_MASK WLAN_MBOX2_DMA_RX_CONTROL_START_MASK
-#define MBOX2_DMA_RX_CONTROL_START_GET(x) WLAN_MBOX2_DMA_RX_CONTROL_START_GET(x)
-#define MBOX2_DMA_RX_CONTROL_START_SET(x) WLAN_MBOX2_DMA_RX_CONTROL_START_SET(x)
-#define MBOX2_DMA_RX_CONTROL_STOP_MSB WLAN_MBOX2_DMA_RX_CONTROL_STOP_MSB
-#define MBOX2_DMA_RX_CONTROL_STOP_LSB WLAN_MBOX2_DMA_RX_CONTROL_STOP_LSB
-#define MBOX2_DMA_RX_CONTROL_STOP_MASK WLAN_MBOX2_DMA_RX_CONTROL_STOP_MASK
-#define MBOX2_DMA_RX_CONTROL_STOP_GET(x) WLAN_MBOX2_DMA_RX_CONTROL_STOP_GET(x)
-#define MBOX2_DMA_RX_CONTROL_STOP_SET(x) WLAN_MBOX2_DMA_RX_CONTROL_STOP_SET(x)
-#define MBOX2_DMA_TX_DESCRIPTOR_BASE_ADDRESS WLAN_MBOX2_DMA_TX_DESCRIPTOR_BASE_ADDRESS
-#define MBOX2_DMA_TX_DESCRIPTOR_BASE_OFFSET WLAN_MBOX2_DMA_TX_DESCRIPTOR_BASE_OFFSET
-#define MBOX2_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MSB WLAN_MBOX2_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MSB
-#define MBOX2_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB WLAN_MBOX2_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB
-#define MBOX2_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK WLAN_MBOX2_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK
-#define MBOX2_DMA_TX_DESCRIPTOR_BASE_ADDRESS_GET(x) WLAN_MBOX2_DMA_TX_DESCRIPTOR_BASE_ADDRESS_GET(x)
-#define MBOX2_DMA_TX_DESCRIPTOR_BASE_ADDRESS_SET(x) WLAN_MBOX2_DMA_TX_DESCRIPTOR_BASE_ADDRESS_SET(x)
-#define MBOX2_DMA_TX_CONTROL_ADDRESS WLAN_MBOX2_DMA_TX_CONTROL_ADDRESS
-#define MBOX2_DMA_TX_CONTROL_OFFSET WLAN_MBOX2_DMA_TX_CONTROL_OFFSET
-#define MBOX2_DMA_TX_CONTROL_RESUME_MSB WLAN_MBOX2_DMA_TX_CONTROL_RESUME_MSB
-#define MBOX2_DMA_TX_CONTROL_RESUME_LSB WLAN_MBOX2_DMA_TX_CONTROL_RESUME_LSB
-#define MBOX2_DMA_TX_CONTROL_RESUME_MASK WLAN_MBOX2_DMA_TX_CONTROL_RESUME_MASK
-#define MBOX2_DMA_TX_CONTROL_RESUME_GET(x) WLAN_MBOX2_DMA_TX_CONTROL_RESUME_GET(x)
-#define MBOX2_DMA_TX_CONTROL_RESUME_SET(x) WLAN_MBOX2_DMA_TX_CONTROL_RESUME_SET(x)
-#define MBOX2_DMA_TX_CONTROL_START_MSB WLAN_MBOX2_DMA_TX_CONTROL_START_MSB
-#define MBOX2_DMA_TX_CONTROL_START_LSB WLAN_MBOX2_DMA_TX_CONTROL_START_LSB
-#define MBOX2_DMA_TX_CONTROL_START_MASK WLAN_MBOX2_DMA_TX_CONTROL_START_MASK
-#define MBOX2_DMA_TX_CONTROL_START_GET(x) WLAN_MBOX2_DMA_TX_CONTROL_START_GET(x)
-#define MBOX2_DMA_TX_CONTROL_START_SET(x) WLAN_MBOX2_DMA_TX_CONTROL_START_SET(x)
-#define MBOX2_DMA_TX_CONTROL_STOP_MSB WLAN_MBOX2_DMA_TX_CONTROL_STOP_MSB
-#define MBOX2_DMA_TX_CONTROL_STOP_LSB WLAN_MBOX2_DMA_TX_CONTROL_STOP_LSB
-#define MBOX2_DMA_TX_CONTROL_STOP_MASK WLAN_MBOX2_DMA_TX_CONTROL_STOP_MASK
-#define MBOX2_DMA_TX_CONTROL_STOP_GET(x) WLAN_MBOX2_DMA_TX_CONTROL_STOP_GET(x)
-#define MBOX2_DMA_TX_CONTROL_STOP_SET(x) WLAN_MBOX2_DMA_TX_CONTROL_STOP_SET(x)
-#define MBOX3_DMA_RX_DESCRIPTOR_BASE_ADDRESS WLAN_MBOX3_DMA_RX_DESCRIPTOR_BASE_ADDRESS
-#define MBOX3_DMA_RX_DESCRIPTOR_BASE_OFFSET WLAN_MBOX3_DMA_RX_DESCRIPTOR_BASE_OFFSET
-#define MBOX3_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MSB WLAN_MBOX3_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MSB
-#define MBOX3_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB WLAN_MBOX3_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB
-#define MBOX3_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK WLAN_MBOX3_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK
-#define MBOX3_DMA_RX_DESCRIPTOR_BASE_ADDRESS_GET(x) WLAN_MBOX3_DMA_RX_DESCRIPTOR_BASE_ADDRESS_GET(x)
-#define MBOX3_DMA_RX_DESCRIPTOR_BASE_ADDRESS_SET(x) WLAN_MBOX3_DMA_RX_DESCRIPTOR_BASE_ADDRESS_SET(x)
-#define MBOX3_DMA_RX_CONTROL_ADDRESS WLAN_MBOX3_DMA_RX_CONTROL_ADDRESS
-#define MBOX3_DMA_RX_CONTROL_OFFSET WLAN_MBOX3_DMA_RX_CONTROL_OFFSET
-#define MBOX3_DMA_RX_CONTROL_RESUME_MSB WLAN_MBOX3_DMA_RX_CONTROL_RESUME_MSB
-#define MBOX3_DMA_RX_CONTROL_RESUME_LSB WLAN_MBOX3_DMA_RX_CONTROL_RESUME_LSB
-#define MBOX3_DMA_RX_CONTROL_RESUME_MASK WLAN_MBOX3_DMA_RX_CONTROL_RESUME_MASK
-#define MBOX3_DMA_RX_CONTROL_RESUME_GET(x) WLAN_MBOX3_DMA_RX_CONTROL_RESUME_GET(x)
-#define MBOX3_DMA_RX_CONTROL_RESUME_SET(x) WLAN_MBOX3_DMA_RX_CONTROL_RESUME_SET(x)
-#define MBOX3_DMA_RX_CONTROL_START_MSB WLAN_MBOX3_DMA_RX_CONTROL_START_MSB
-#define MBOX3_DMA_RX_CONTROL_START_LSB WLAN_MBOX3_DMA_RX_CONTROL_START_LSB
-#define MBOX3_DMA_RX_CONTROL_START_MASK WLAN_MBOX3_DMA_RX_CONTROL_START_MASK
-#define MBOX3_DMA_RX_CONTROL_START_GET(x) WLAN_MBOX3_DMA_RX_CONTROL_START_GET(x)
-#define MBOX3_DMA_RX_CONTROL_START_SET(x) WLAN_MBOX3_DMA_RX_CONTROL_START_SET(x)
-#define MBOX3_DMA_RX_CONTROL_STOP_MSB WLAN_MBOX3_DMA_RX_CONTROL_STOP_MSB
-#define MBOX3_DMA_RX_CONTROL_STOP_LSB WLAN_MBOX3_DMA_RX_CONTROL_STOP_LSB
-#define MBOX3_DMA_RX_CONTROL_STOP_MASK WLAN_MBOX3_DMA_RX_CONTROL_STOP_MASK
-#define MBOX3_DMA_RX_CONTROL_STOP_GET(x) WLAN_MBOX3_DMA_RX_CONTROL_STOP_GET(x)
-#define MBOX3_DMA_RX_CONTROL_STOP_SET(x) WLAN_MBOX3_DMA_RX_CONTROL_STOP_SET(x)
-#define MBOX3_DMA_TX_DESCRIPTOR_BASE_ADDRESS WLAN_MBOX3_DMA_TX_DESCRIPTOR_BASE_ADDRESS
-#define MBOX3_DMA_TX_DESCRIPTOR_BASE_OFFSET WLAN_MBOX3_DMA_TX_DESCRIPTOR_BASE_OFFSET
-#define MBOX3_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MSB WLAN_MBOX3_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MSB
-#define MBOX3_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB WLAN_MBOX3_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB
-#define MBOX3_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK WLAN_MBOX3_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK
-#define MBOX3_DMA_TX_DESCRIPTOR_BASE_ADDRESS_GET(x) WLAN_MBOX3_DMA_TX_DESCRIPTOR_BASE_ADDRESS_GET(x)
-#define MBOX3_DMA_TX_DESCRIPTOR_BASE_ADDRESS_SET(x) WLAN_MBOX3_DMA_TX_DESCRIPTOR_BASE_ADDRESS_SET(x)
-#define MBOX3_DMA_TX_CONTROL_ADDRESS WLAN_MBOX3_DMA_TX_CONTROL_ADDRESS
-#define MBOX3_DMA_TX_CONTROL_OFFSET WLAN_MBOX3_DMA_TX_CONTROL_OFFSET
-#define MBOX3_DMA_TX_CONTROL_RESUME_MSB WLAN_MBOX3_DMA_TX_CONTROL_RESUME_MSB
-#define MBOX3_DMA_TX_CONTROL_RESUME_LSB WLAN_MBOX3_DMA_TX_CONTROL_RESUME_LSB
-#define MBOX3_DMA_TX_CONTROL_RESUME_MASK WLAN_MBOX3_DMA_TX_CONTROL_RESUME_MASK
-#define MBOX3_DMA_TX_CONTROL_RESUME_GET(x) WLAN_MBOX3_DMA_TX_CONTROL_RESUME_GET(x)
-#define MBOX3_DMA_TX_CONTROL_RESUME_SET(x) WLAN_MBOX3_DMA_TX_CONTROL_RESUME_SET(x)
-#define MBOX3_DMA_TX_CONTROL_START_MSB WLAN_MBOX3_DMA_TX_CONTROL_START_MSB
-#define MBOX3_DMA_TX_CONTROL_START_LSB WLAN_MBOX3_DMA_TX_CONTROL_START_LSB
-#define MBOX3_DMA_TX_CONTROL_START_MASK WLAN_MBOX3_DMA_TX_CONTROL_START_MASK
-#define MBOX3_DMA_TX_CONTROL_START_GET(x) WLAN_MBOX3_DMA_TX_CONTROL_START_GET(x)
-#define MBOX3_DMA_TX_CONTROL_START_SET(x) WLAN_MBOX3_DMA_TX_CONTROL_START_SET(x)
-#define MBOX3_DMA_TX_CONTROL_STOP_MSB WLAN_MBOX3_DMA_TX_CONTROL_STOP_MSB
-#define MBOX3_DMA_TX_CONTROL_STOP_LSB WLAN_MBOX3_DMA_TX_CONTROL_STOP_LSB
-#define MBOX3_DMA_TX_CONTROL_STOP_MASK WLAN_MBOX3_DMA_TX_CONTROL_STOP_MASK
-#define MBOX3_DMA_TX_CONTROL_STOP_GET(x) WLAN_MBOX3_DMA_TX_CONTROL_STOP_GET(x)
-#define MBOX3_DMA_TX_CONTROL_STOP_SET(x) WLAN_MBOX3_DMA_TX_CONTROL_STOP_SET(x)
-#define MBOX_INT_STATUS_ADDRESS WLAN_MBOX_INT_STATUS_ADDRESS
-#define MBOX_INT_STATUS_OFFSET WLAN_MBOX_INT_STATUS_OFFSET
-#define MBOX_INT_STATUS_RX_DMA_COMPLETE_MSB WLAN_MBOX_INT_STATUS_RX_DMA_COMPLETE_MSB
-#define MBOX_INT_STATUS_RX_DMA_COMPLETE_LSB WLAN_MBOX_INT_STATUS_RX_DMA_COMPLETE_LSB
-#define MBOX_INT_STATUS_RX_DMA_COMPLETE_MASK WLAN_MBOX_INT_STATUS_RX_DMA_COMPLETE_MASK
-#define MBOX_INT_STATUS_RX_DMA_COMPLETE_GET(x) WLAN_MBOX_INT_STATUS_RX_DMA_COMPLETE_GET(x)
-#define MBOX_INT_STATUS_RX_DMA_COMPLETE_SET(x) WLAN_MBOX_INT_STATUS_RX_DMA_COMPLETE_SET(x)
-#define MBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_MSB WLAN_MBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_MSB
-#define MBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_LSB WLAN_MBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_LSB
-#define MBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_MASK WLAN_MBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_MASK
-#define MBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_GET(x) WLAN_MBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_GET(x)
-#define MBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_SET(x) WLAN_MBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_SET(x)
-#define MBOX_INT_STATUS_TX_DMA_COMPLETE_MSB WLAN_MBOX_INT_STATUS_TX_DMA_COMPLETE_MSB
-#define MBOX_INT_STATUS_TX_DMA_COMPLETE_LSB WLAN_MBOX_INT_STATUS_TX_DMA_COMPLETE_LSB
-#define MBOX_INT_STATUS_TX_DMA_COMPLETE_MASK WLAN_MBOX_INT_STATUS_TX_DMA_COMPLETE_MASK
-#define MBOX_INT_STATUS_TX_DMA_COMPLETE_GET(x) WLAN_MBOX_INT_STATUS_TX_DMA_COMPLETE_GET(x)
-#define MBOX_INT_STATUS_TX_DMA_COMPLETE_SET(x) WLAN_MBOX_INT_STATUS_TX_DMA_COMPLETE_SET(x)
-#define MBOX_INT_STATUS_TX_OVERFLOW_MSB WLAN_MBOX_INT_STATUS_TX_OVERFLOW_MSB
-#define MBOX_INT_STATUS_TX_OVERFLOW_LSB WLAN_MBOX_INT_STATUS_TX_OVERFLOW_LSB
-#define MBOX_INT_STATUS_TX_OVERFLOW_MASK WLAN_MBOX_INT_STATUS_TX_OVERFLOW_MASK
-#define MBOX_INT_STATUS_TX_OVERFLOW_GET(x) WLAN_MBOX_INT_STATUS_TX_OVERFLOW_GET(x)
-#define MBOX_INT_STATUS_TX_OVERFLOW_SET(x) WLAN_MBOX_INT_STATUS_TX_OVERFLOW_SET(x)
-#define MBOX_INT_STATUS_RX_UNDERFLOW_MSB WLAN_MBOX_INT_STATUS_RX_UNDERFLOW_MSB
-#define MBOX_INT_STATUS_RX_UNDERFLOW_LSB WLAN_MBOX_INT_STATUS_RX_UNDERFLOW_LSB
-#define MBOX_INT_STATUS_RX_UNDERFLOW_MASK WLAN_MBOX_INT_STATUS_RX_UNDERFLOW_MASK
-#define MBOX_INT_STATUS_RX_UNDERFLOW_GET(x) WLAN_MBOX_INT_STATUS_RX_UNDERFLOW_GET(x)
-#define MBOX_INT_STATUS_RX_UNDERFLOW_SET(x) WLAN_MBOX_INT_STATUS_RX_UNDERFLOW_SET(x)
-#define MBOX_INT_STATUS_TX_NOT_EMPTY_MSB WLAN_MBOX_INT_STATUS_TX_NOT_EMPTY_MSB
-#define MBOX_INT_STATUS_TX_NOT_EMPTY_LSB WLAN_MBOX_INT_STATUS_TX_NOT_EMPTY_LSB
-#define MBOX_INT_STATUS_TX_NOT_EMPTY_MASK WLAN_MBOX_INT_STATUS_TX_NOT_EMPTY_MASK
-#define MBOX_INT_STATUS_TX_NOT_EMPTY_GET(x) WLAN_MBOX_INT_STATUS_TX_NOT_EMPTY_GET(x)
-#define MBOX_INT_STATUS_TX_NOT_EMPTY_SET(x) WLAN_MBOX_INT_STATUS_TX_NOT_EMPTY_SET(x)
-#define MBOX_INT_STATUS_RX_NOT_FULL_MSB WLAN_MBOX_INT_STATUS_RX_NOT_FULL_MSB
-#define MBOX_INT_STATUS_RX_NOT_FULL_LSB WLAN_MBOX_INT_STATUS_RX_NOT_FULL_LSB
-#define MBOX_INT_STATUS_RX_NOT_FULL_MASK WLAN_MBOX_INT_STATUS_RX_NOT_FULL_MASK
-#define MBOX_INT_STATUS_RX_NOT_FULL_GET(x) WLAN_MBOX_INT_STATUS_RX_NOT_FULL_GET(x)
-#define MBOX_INT_STATUS_RX_NOT_FULL_SET(x) WLAN_MBOX_INT_STATUS_RX_NOT_FULL_SET(x)
-#define MBOX_INT_STATUS_HOST_MSB WLAN_MBOX_INT_STATUS_HOST_MSB
-#define MBOX_INT_STATUS_HOST_LSB WLAN_MBOX_INT_STATUS_HOST_LSB
-#define MBOX_INT_STATUS_HOST_MASK WLAN_MBOX_INT_STATUS_HOST_MASK
-#define MBOX_INT_STATUS_HOST_GET(x) WLAN_MBOX_INT_STATUS_HOST_GET(x)
-#define MBOX_INT_STATUS_HOST_SET(x) WLAN_MBOX_INT_STATUS_HOST_SET(x)
-#define MBOX_INT_ENABLE_ADDRESS WLAN_MBOX_INT_ENABLE_ADDRESS
-#define MBOX_INT_ENABLE_OFFSET WLAN_MBOX_INT_ENABLE_OFFSET
-#define MBOX_INT_ENABLE_RX_DMA_COMPLETE_MSB WLAN_MBOX_INT_ENABLE_RX_DMA_COMPLETE_MSB
-#define MBOX_INT_ENABLE_RX_DMA_COMPLETE_LSB WLAN_MBOX_INT_ENABLE_RX_DMA_COMPLETE_LSB
-#define MBOX_INT_ENABLE_RX_DMA_COMPLETE_MASK WLAN_MBOX_INT_ENABLE_RX_DMA_COMPLETE_MASK
-#define MBOX_INT_ENABLE_RX_DMA_COMPLETE_GET(x) WLAN_MBOX_INT_ENABLE_RX_DMA_COMPLETE_GET(x)
-#define MBOX_INT_ENABLE_RX_DMA_COMPLETE_SET(x) WLAN_MBOX_INT_ENABLE_RX_DMA_COMPLETE_SET(x)
-#define MBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_MSB WLAN_MBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_MSB
-#define MBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_LSB WLAN_MBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_LSB
-#define MBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_MASK WLAN_MBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_MASK
-#define MBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_GET(x) WLAN_MBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_GET(x)
-#define MBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_SET(x) WLAN_MBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_SET(x)
-#define MBOX_INT_ENABLE_TX_DMA_COMPLETE_MSB WLAN_MBOX_INT_ENABLE_TX_DMA_COMPLETE_MSB
-#define MBOX_INT_ENABLE_TX_DMA_COMPLETE_LSB WLAN_MBOX_INT_ENABLE_TX_DMA_COMPLETE_LSB
-#define MBOX_INT_ENABLE_TX_DMA_COMPLETE_MASK WLAN_MBOX_INT_ENABLE_TX_DMA_COMPLETE_MASK
-#define MBOX_INT_ENABLE_TX_DMA_COMPLETE_GET(x) WLAN_MBOX_INT_ENABLE_TX_DMA_COMPLETE_GET(x)
-#define MBOX_INT_ENABLE_TX_DMA_COMPLETE_SET(x) WLAN_MBOX_INT_ENABLE_TX_DMA_COMPLETE_SET(x)
-#define MBOX_INT_ENABLE_TX_OVERFLOW_MSB WLAN_MBOX_INT_ENABLE_TX_OVERFLOW_MSB
-#define MBOX_INT_ENABLE_TX_OVERFLOW_LSB WLAN_MBOX_INT_ENABLE_TX_OVERFLOW_LSB
-#define MBOX_INT_ENABLE_TX_OVERFLOW_MASK WLAN_MBOX_INT_ENABLE_TX_OVERFLOW_MASK
-#define MBOX_INT_ENABLE_TX_OVERFLOW_GET(x) WLAN_MBOX_INT_ENABLE_TX_OVERFLOW_GET(x)
-#define MBOX_INT_ENABLE_TX_OVERFLOW_SET(x) WLAN_MBOX_INT_ENABLE_TX_OVERFLOW_SET(x)
-#define MBOX_INT_ENABLE_RX_UNDERFLOW_MSB WLAN_MBOX_INT_ENABLE_RX_UNDERFLOW_MSB
-#define MBOX_INT_ENABLE_RX_UNDERFLOW_LSB WLAN_MBOX_INT_ENABLE_RX_UNDERFLOW_LSB
-#define MBOX_INT_ENABLE_RX_UNDERFLOW_MASK WLAN_MBOX_INT_ENABLE_RX_UNDERFLOW_MASK
-#define MBOX_INT_ENABLE_RX_UNDERFLOW_GET(x) WLAN_MBOX_INT_ENABLE_RX_UNDERFLOW_GET(x)
-#define MBOX_INT_ENABLE_RX_UNDERFLOW_SET(x) WLAN_MBOX_INT_ENABLE_RX_UNDERFLOW_SET(x)
-#define MBOX_INT_ENABLE_TX_NOT_EMPTY_MSB WLAN_MBOX_INT_ENABLE_TX_NOT_EMPTY_MSB
-#define MBOX_INT_ENABLE_TX_NOT_EMPTY_LSB WLAN_MBOX_INT_ENABLE_TX_NOT_EMPTY_LSB
-#define MBOX_INT_ENABLE_TX_NOT_EMPTY_MASK WLAN_MBOX_INT_ENABLE_TX_NOT_EMPTY_MASK
-#define MBOX_INT_ENABLE_TX_NOT_EMPTY_GET(x) WLAN_MBOX_INT_ENABLE_TX_NOT_EMPTY_GET(x)
-#define MBOX_INT_ENABLE_TX_NOT_EMPTY_SET(x) WLAN_MBOX_INT_ENABLE_TX_NOT_EMPTY_SET(x)
-#define MBOX_INT_ENABLE_RX_NOT_FULL_MSB WLAN_MBOX_INT_ENABLE_RX_NOT_FULL_MSB
-#define MBOX_INT_ENABLE_RX_NOT_FULL_LSB WLAN_MBOX_INT_ENABLE_RX_NOT_FULL_LSB
-#define MBOX_INT_ENABLE_RX_NOT_FULL_MASK WLAN_MBOX_INT_ENABLE_RX_NOT_FULL_MASK
-#define MBOX_INT_ENABLE_RX_NOT_FULL_GET(x) WLAN_MBOX_INT_ENABLE_RX_NOT_FULL_GET(x)
-#define MBOX_INT_ENABLE_RX_NOT_FULL_SET(x) WLAN_MBOX_INT_ENABLE_RX_NOT_FULL_SET(x)
-#define MBOX_INT_ENABLE_HOST_MSB WLAN_MBOX_INT_ENABLE_HOST_MSB
-#define MBOX_INT_ENABLE_HOST_LSB WLAN_MBOX_INT_ENABLE_HOST_LSB
-#define MBOX_INT_ENABLE_HOST_MASK WLAN_MBOX_INT_ENABLE_HOST_MASK
-#define MBOX_INT_ENABLE_HOST_GET(x) WLAN_MBOX_INT_ENABLE_HOST_GET(x)
-#define MBOX_INT_ENABLE_HOST_SET(x) WLAN_MBOX_INT_ENABLE_HOST_SET(x)
-#define INT_HOST_ADDRESS WLAN_INT_HOST_ADDRESS
-#define INT_HOST_OFFSET WLAN_INT_HOST_OFFSET
-#define INT_HOST_VECTOR_MSB WLAN_INT_HOST_VECTOR_MSB
-#define INT_HOST_VECTOR_LSB WLAN_INT_HOST_VECTOR_LSB
-#define INT_HOST_VECTOR_MASK WLAN_INT_HOST_VECTOR_MASK
-#define INT_HOST_VECTOR_GET(x) WLAN_INT_HOST_VECTOR_GET(x)
-#define INT_HOST_VECTOR_SET(x) WLAN_INT_HOST_VECTOR_SET(x)
-#define LOCAL_COUNT_ADDRESS WLAN_LOCAL_COUNT_ADDRESS
-#define LOCAL_COUNT_OFFSET WLAN_LOCAL_COUNT_OFFSET
-#define LOCAL_COUNT_VALUE_MSB WLAN_LOCAL_COUNT_VALUE_MSB
-#define LOCAL_COUNT_VALUE_LSB WLAN_LOCAL_COUNT_VALUE_LSB
-#define LOCAL_COUNT_VALUE_MASK WLAN_LOCAL_COUNT_VALUE_MASK
-#define LOCAL_COUNT_VALUE_GET(x) WLAN_LOCAL_COUNT_VALUE_GET(x)
-#define LOCAL_COUNT_VALUE_SET(x) WLAN_LOCAL_COUNT_VALUE_SET(x)
-#define COUNT_INC_ADDRESS WLAN_COUNT_INC_ADDRESS
-#define COUNT_INC_OFFSET WLAN_COUNT_INC_OFFSET
-#define COUNT_INC_VALUE_MSB WLAN_COUNT_INC_VALUE_MSB
-#define COUNT_INC_VALUE_LSB WLAN_COUNT_INC_VALUE_LSB
-#define COUNT_INC_VALUE_MASK WLAN_COUNT_INC_VALUE_MASK
-#define COUNT_INC_VALUE_GET(x) WLAN_COUNT_INC_VALUE_GET(x)
-#define COUNT_INC_VALUE_SET(x) WLAN_COUNT_INC_VALUE_SET(x)
-#define LOCAL_SCRATCH_ADDRESS WLAN_LOCAL_SCRATCH_ADDRESS
-#define LOCAL_SCRATCH_OFFSET WLAN_LOCAL_SCRATCH_OFFSET
-#define LOCAL_SCRATCH_VALUE_MSB WLAN_LOCAL_SCRATCH_VALUE_MSB
-#define LOCAL_SCRATCH_VALUE_LSB WLAN_LOCAL_SCRATCH_VALUE_LSB
-#define LOCAL_SCRATCH_VALUE_MASK WLAN_LOCAL_SCRATCH_VALUE_MASK
-#define LOCAL_SCRATCH_VALUE_GET(x) WLAN_LOCAL_SCRATCH_VALUE_GET(x)
-#define LOCAL_SCRATCH_VALUE_SET(x) WLAN_LOCAL_SCRATCH_VALUE_SET(x)
-#define USE_LOCAL_BUS_ADDRESS WLAN_USE_LOCAL_BUS_ADDRESS
-#define USE_LOCAL_BUS_OFFSET WLAN_USE_LOCAL_BUS_OFFSET
-#define USE_LOCAL_BUS_PIN_INIT_MSB WLAN_USE_LOCAL_BUS_PIN_INIT_MSB
-#define USE_LOCAL_BUS_PIN_INIT_LSB WLAN_USE_LOCAL_BUS_PIN_INIT_LSB
-#define USE_LOCAL_BUS_PIN_INIT_MASK WLAN_USE_LOCAL_BUS_PIN_INIT_MASK
-#define USE_LOCAL_BUS_PIN_INIT_GET(x) WLAN_USE_LOCAL_BUS_PIN_INIT_GET(x)
-#define USE_LOCAL_BUS_PIN_INIT_SET(x) WLAN_USE_LOCAL_BUS_PIN_INIT_SET(x)
-#define SDIO_CONFIG_ADDRESS WLAN_SDIO_CONFIG_ADDRESS
-#define SDIO_CONFIG_OFFSET WLAN_SDIO_CONFIG_OFFSET
-#define SDIO_CONFIG_CCCR_IOR1_MSB WLAN_SDIO_CONFIG_CCCR_IOR1_MSB
-#define SDIO_CONFIG_CCCR_IOR1_LSB WLAN_SDIO_CONFIG_CCCR_IOR1_LSB
-#define SDIO_CONFIG_CCCR_IOR1_MASK WLAN_SDIO_CONFIG_CCCR_IOR1_MASK
-#define SDIO_CONFIG_CCCR_IOR1_GET(x) WLAN_SDIO_CONFIG_CCCR_IOR1_GET(x)
-#define SDIO_CONFIG_CCCR_IOR1_SET(x) WLAN_SDIO_CONFIG_CCCR_IOR1_SET(x)
-#define MBOX_DEBUG_ADDRESS WLAN_MBOX_DEBUG_ADDRESS
-#define MBOX_DEBUG_OFFSET WLAN_MBOX_DEBUG_OFFSET
-#define MBOX_DEBUG_SEL_MSB WLAN_MBOX_DEBUG_SEL_MSB
-#define MBOX_DEBUG_SEL_LSB WLAN_MBOX_DEBUG_SEL_LSB
-#define MBOX_DEBUG_SEL_MASK WLAN_MBOX_DEBUG_SEL_MASK
-#define MBOX_DEBUG_SEL_GET(x) WLAN_MBOX_DEBUG_SEL_GET(x)
-#define MBOX_DEBUG_SEL_SET(x) WLAN_MBOX_DEBUG_SEL_SET(x)
-#define MBOX_FIFO_RESET_ADDRESS WLAN_MBOX_FIFO_RESET_ADDRESS
-#define MBOX_FIFO_RESET_OFFSET WLAN_MBOX_FIFO_RESET_OFFSET
-#define MBOX_FIFO_RESET_INIT_MSB WLAN_MBOX_FIFO_RESET_INIT_MSB
-#define MBOX_FIFO_RESET_INIT_LSB WLAN_MBOX_FIFO_RESET_INIT_LSB
-#define MBOX_FIFO_RESET_INIT_MASK WLAN_MBOX_FIFO_RESET_INIT_MASK
-#define MBOX_FIFO_RESET_INIT_GET(x) WLAN_MBOX_FIFO_RESET_INIT_GET(x)
-#define MBOX_FIFO_RESET_INIT_SET(x) WLAN_MBOX_FIFO_RESET_INIT_SET(x)
-#define MBOX_TXFIFO_POP_ADDRESS WLAN_MBOX_TXFIFO_POP_ADDRESS
-#define MBOX_TXFIFO_POP_OFFSET WLAN_MBOX_TXFIFO_POP_OFFSET
-#define MBOX_TXFIFO_POP_DATA_MSB WLAN_MBOX_TXFIFO_POP_DATA_MSB
-#define MBOX_TXFIFO_POP_DATA_LSB WLAN_MBOX_TXFIFO_POP_DATA_LSB
-#define MBOX_TXFIFO_POP_DATA_MASK WLAN_MBOX_TXFIFO_POP_DATA_MASK
-#define MBOX_TXFIFO_POP_DATA_GET(x) WLAN_MBOX_TXFIFO_POP_DATA_GET(x)
-#define MBOX_TXFIFO_POP_DATA_SET(x) WLAN_MBOX_TXFIFO_POP_DATA_SET(x)
-#define MBOX_RXFIFO_POP_ADDRESS WLAN_MBOX_RXFIFO_POP_ADDRESS
-#define MBOX_RXFIFO_POP_OFFSET WLAN_MBOX_RXFIFO_POP_OFFSET
-#define MBOX_RXFIFO_POP_DATA_MSB WLAN_MBOX_RXFIFO_POP_DATA_MSB
-#define MBOX_RXFIFO_POP_DATA_LSB WLAN_MBOX_RXFIFO_POP_DATA_LSB
-#define MBOX_RXFIFO_POP_DATA_MASK WLAN_MBOX_RXFIFO_POP_DATA_MASK
-#define MBOX_RXFIFO_POP_DATA_GET(x) WLAN_MBOX_RXFIFO_POP_DATA_GET(x)
-#define MBOX_RXFIFO_POP_DATA_SET(x) WLAN_MBOX_RXFIFO_POP_DATA_SET(x)
-#define SDIO_DEBUG_ADDRESS WLAN_SDIO_DEBUG_ADDRESS
-#define SDIO_DEBUG_OFFSET WLAN_SDIO_DEBUG_OFFSET
-#define SDIO_DEBUG_SEL_MSB WLAN_SDIO_DEBUG_SEL_MSB
-#define SDIO_DEBUG_SEL_LSB WLAN_SDIO_DEBUG_SEL_LSB
-#define SDIO_DEBUG_SEL_MASK WLAN_SDIO_DEBUG_SEL_MASK
-#define SDIO_DEBUG_SEL_GET(x) WLAN_SDIO_DEBUG_SEL_GET(x)
-#define SDIO_DEBUG_SEL_SET(x) WLAN_SDIO_DEBUG_SEL_SET(x)
-#define GMBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS WLAN_GMBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS
-#define GMBOX0_DMA_RX_DESCRIPTOR_BASE_OFFSET WLAN_GMBOX0_DMA_RX_DESCRIPTOR_BASE_OFFSET
-#define GMBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MSB WLAN_GMBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MSB
-#define GMBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB WLAN_GMBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB
-#define GMBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK WLAN_GMBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK
-#define GMBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_GET(x) WLAN_GMBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_GET(x)
-#define GMBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_SET(x) WLAN_GMBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_SET(x)
-#define GMBOX0_DMA_RX_CONTROL_ADDRESS WLAN_GMBOX0_DMA_RX_CONTROL_ADDRESS
-#define GMBOX0_DMA_RX_CONTROL_OFFSET WLAN_GMBOX0_DMA_RX_CONTROL_OFFSET
-#define GMBOX0_DMA_RX_CONTROL_RESUME_MSB WLAN_GMBOX0_DMA_RX_CONTROL_RESUME_MSB
-#define GMBOX0_DMA_RX_CONTROL_RESUME_LSB WLAN_GMBOX0_DMA_RX_CONTROL_RESUME_LSB
-#define GMBOX0_DMA_RX_CONTROL_RESUME_MASK WLAN_GMBOX0_DMA_RX_CONTROL_RESUME_MASK
-#define GMBOX0_DMA_RX_CONTROL_RESUME_GET(x) WLAN_GMBOX0_DMA_RX_CONTROL_RESUME_GET(x)
-#define GMBOX0_DMA_RX_CONTROL_RESUME_SET(x) WLAN_GMBOX0_DMA_RX_CONTROL_RESUME_SET(x)
-#define GMBOX0_DMA_RX_CONTROL_START_MSB WLAN_GMBOX0_DMA_RX_CONTROL_START_MSB
-#define GMBOX0_DMA_RX_CONTROL_START_LSB WLAN_GMBOX0_DMA_RX_CONTROL_START_LSB
-#define GMBOX0_DMA_RX_CONTROL_START_MASK WLAN_GMBOX0_DMA_RX_CONTROL_START_MASK
-#define GMBOX0_DMA_RX_CONTROL_START_GET(x) WLAN_GMBOX0_DMA_RX_CONTROL_START_GET(x)
-#define GMBOX0_DMA_RX_CONTROL_START_SET(x) WLAN_GMBOX0_DMA_RX_CONTROL_START_SET(x)
-#define GMBOX0_DMA_RX_CONTROL_STOP_MSB WLAN_GMBOX0_DMA_RX_CONTROL_STOP_MSB
-#define GMBOX0_DMA_RX_CONTROL_STOP_LSB WLAN_GMBOX0_DMA_RX_CONTROL_STOP_LSB
-#define GMBOX0_DMA_RX_CONTROL_STOP_MASK WLAN_GMBOX0_DMA_RX_CONTROL_STOP_MASK
-#define GMBOX0_DMA_RX_CONTROL_STOP_GET(x) WLAN_GMBOX0_DMA_RX_CONTROL_STOP_GET(x)
-#define GMBOX0_DMA_RX_CONTROL_STOP_SET(x) WLAN_GMBOX0_DMA_RX_CONTROL_STOP_SET(x)
-#define GMBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS WLAN_GMBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS
-#define GMBOX0_DMA_TX_DESCRIPTOR_BASE_OFFSET WLAN_GMBOX0_DMA_TX_DESCRIPTOR_BASE_OFFSET
-#define GMBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MSB WLAN_GMBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MSB
-#define GMBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB WLAN_GMBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB
-#define GMBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK WLAN_GMBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK
-#define GMBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_GET(x) WLAN_GMBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_GET(x)
-#define GMBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_SET(x) WLAN_GMBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_SET(x)
-#define GMBOX0_DMA_TX_CONTROL_ADDRESS WLAN_GMBOX0_DMA_TX_CONTROL_ADDRESS
-#define GMBOX0_DMA_TX_CONTROL_OFFSET WLAN_GMBOX0_DMA_TX_CONTROL_OFFSET
-#define GMBOX0_DMA_TX_CONTROL_RESUME_MSB WLAN_GMBOX0_DMA_TX_CONTROL_RESUME_MSB
-#define GMBOX0_DMA_TX_CONTROL_RESUME_LSB WLAN_GMBOX0_DMA_TX_CONTROL_RESUME_LSB
-#define GMBOX0_DMA_TX_CONTROL_RESUME_MASK WLAN_GMBOX0_DMA_TX_CONTROL_RESUME_MASK
-#define GMBOX0_DMA_TX_CONTROL_RESUME_GET(x) WLAN_GMBOX0_DMA_TX_CONTROL_RESUME_GET(x)
-#define GMBOX0_DMA_TX_CONTROL_RESUME_SET(x) WLAN_GMBOX0_DMA_TX_CONTROL_RESUME_SET(x)
-#define GMBOX0_DMA_TX_CONTROL_START_MSB WLAN_GMBOX0_DMA_TX_CONTROL_START_MSB
-#define GMBOX0_DMA_TX_CONTROL_START_LSB WLAN_GMBOX0_DMA_TX_CONTROL_START_LSB
-#define GMBOX0_DMA_TX_CONTROL_START_MASK WLAN_GMBOX0_DMA_TX_CONTROL_START_MASK
-#define GMBOX0_DMA_TX_CONTROL_START_GET(x) WLAN_GMBOX0_DMA_TX_CONTROL_START_GET(x)
-#define GMBOX0_DMA_TX_CONTROL_START_SET(x) WLAN_GMBOX0_DMA_TX_CONTROL_START_SET(x)
-#define GMBOX0_DMA_TX_CONTROL_STOP_MSB WLAN_GMBOX0_DMA_TX_CONTROL_STOP_MSB
-#define GMBOX0_DMA_TX_CONTROL_STOP_LSB WLAN_GMBOX0_DMA_TX_CONTROL_STOP_LSB
-#define GMBOX0_DMA_TX_CONTROL_STOP_MASK WLAN_GMBOX0_DMA_TX_CONTROL_STOP_MASK
-#define GMBOX0_DMA_TX_CONTROL_STOP_GET(x) WLAN_GMBOX0_DMA_TX_CONTROL_STOP_GET(x)
-#define GMBOX0_DMA_TX_CONTROL_STOP_SET(x) WLAN_GMBOX0_DMA_TX_CONTROL_STOP_SET(x)
-#define GMBOX_INT_STATUS_ADDRESS WLAN_GMBOX_INT_STATUS_ADDRESS
-#define GMBOX_INT_STATUS_OFFSET WLAN_GMBOX_INT_STATUS_OFFSET
-#define GMBOX_INT_STATUS_TX_OVERFLOW_MSB WLAN_GMBOX_INT_STATUS_TX_OVERFLOW_MSB
-#define GMBOX_INT_STATUS_TX_OVERFLOW_LSB WLAN_GMBOX_INT_STATUS_TX_OVERFLOW_LSB
-#define GMBOX_INT_STATUS_TX_OVERFLOW_MASK WLAN_GMBOX_INT_STATUS_TX_OVERFLOW_MASK
-#define GMBOX_INT_STATUS_TX_OVERFLOW_GET(x) WLAN_GMBOX_INT_STATUS_TX_OVERFLOW_GET(x)
-#define GMBOX_INT_STATUS_TX_OVERFLOW_SET(x) WLAN_GMBOX_INT_STATUS_TX_OVERFLOW_SET(x)
-#define GMBOX_INT_STATUS_RX_UNDERFLOW_MSB WLAN_GMBOX_INT_STATUS_RX_UNDERFLOW_MSB
-#define GMBOX_INT_STATUS_RX_UNDERFLOW_LSB WLAN_GMBOX_INT_STATUS_RX_UNDERFLOW_LSB
-#define GMBOX_INT_STATUS_RX_UNDERFLOW_MASK WLAN_GMBOX_INT_STATUS_RX_UNDERFLOW_MASK
-#define GMBOX_INT_STATUS_RX_UNDERFLOW_GET(x) WLAN_GMBOX_INT_STATUS_RX_UNDERFLOW_GET(x)
-#define GMBOX_INT_STATUS_RX_UNDERFLOW_SET(x) WLAN_GMBOX_INT_STATUS_RX_UNDERFLOW_SET(x)
-#define GMBOX_INT_STATUS_RX_DMA_COMPLETE_MSB WLAN_GMBOX_INT_STATUS_RX_DMA_COMPLETE_MSB
-#define GMBOX_INT_STATUS_RX_DMA_COMPLETE_LSB WLAN_GMBOX_INT_STATUS_RX_DMA_COMPLETE_LSB
-#define GMBOX_INT_STATUS_RX_DMA_COMPLETE_MASK WLAN_GMBOX_INT_STATUS_RX_DMA_COMPLETE_MASK
-#define GMBOX_INT_STATUS_RX_DMA_COMPLETE_GET(x) WLAN_GMBOX_INT_STATUS_RX_DMA_COMPLETE_GET(x)
-#define GMBOX_INT_STATUS_RX_DMA_COMPLETE_SET(x) WLAN_GMBOX_INT_STATUS_RX_DMA_COMPLETE_SET(x)
-#define GMBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_MSB WLAN_GMBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_MSB
-#define GMBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_LSB WLAN_GMBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_LSB
-#define GMBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_MASK WLAN_GMBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_MASK
-#define GMBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_GET(x) WLAN_GMBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_GET(x)
-#define GMBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_SET(x) WLAN_GMBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_SET(x)
-#define GMBOX_INT_STATUS_TX_DMA_COMPLETE_MSB WLAN_GMBOX_INT_STATUS_TX_DMA_COMPLETE_MSB
-#define GMBOX_INT_STATUS_TX_DMA_COMPLETE_LSB WLAN_GMBOX_INT_STATUS_TX_DMA_COMPLETE_LSB
-#define GMBOX_INT_STATUS_TX_DMA_COMPLETE_MASK WLAN_GMBOX_INT_STATUS_TX_DMA_COMPLETE_MASK
-#define GMBOX_INT_STATUS_TX_DMA_COMPLETE_GET(x) WLAN_GMBOX_INT_STATUS_TX_DMA_COMPLETE_GET(x)
-#define GMBOX_INT_STATUS_TX_DMA_COMPLETE_SET(x) WLAN_GMBOX_INT_STATUS_TX_DMA_COMPLETE_SET(x)
-#define GMBOX_INT_STATUS_TX_NOT_EMPTY_MSB WLAN_GMBOX_INT_STATUS_TX_NOT_EMPTY_MSB
-#define GMBOX_INT_STATUS_TX_NOT_EMPTY_LSB WLAN_GMBOX_INT_STATUS_TX_NOT_EMPTY_LSB
-#define GMBOX_INT_STATUS_TX_NOT_EMPTY_MASK WLAN_GMBOX_INT_STATUS_TX_NOT_EMPTY_MASK
-#define GMBOX_INT_STATUS_TX_NOT_EMPTY_GET(x) WLAN_GMBOX_INT_STATUS_TX_NOT_EMPTY_GET(x)
-#define GMBOX_INT_STATUS_TX_NOT_EMPTY_SET(x) WLAN_GMBOX_INT_STATUS_TX_NOT_EMPTY_SET(x)
-#define GMBOX_INT_STATUS_RX_NOT_FULL_MSB WLAN_GMBOX_INT_STATUS_RX_NOT_FULL_MSB
-#define GMBOX_INT_STATUS_RX_NOT_FULL_LSB WLAN_GMBOX_INT_STATUS_RX_NOT_FULL_LSB
-#define GMBOX_INT_STATUS_RX_NOT_FULL_MASK WLAN_GMBOX_INT_STATUS_RX_NOT_FULL_MASK
-#define GMBOX_INT_STATUS_RX_NOT_FULL_GET(x) WLAN_GMBOX_INT_STATUS_RX_NOT_FULL_GET(x)
-#define GMBOX_INT_STATUS_RX_NOT_FULL_SET(x) WLAN_GMBOX_INT_STATUS_RX_NOT_FULL_SET(x)
-#define GMBOX_INT_ENABLE_ADDRESS WLAN_GMBOX_INT_ENABLE_ADDRESS
-#define GMBOX_INT_ENABLE_OFFSET WLAN_GMBOX_INT_ENABLE_OFFSET
-#define GMBOX_INT_ENABLE_TX_OVERFLOW_MSB WLAN_GMBOX_INT_ENABLE_TX_OVERFLOW_MSB
-#define GMBOX_INT_ENABLE_TX_OVERFLOW_LSB WLAN_GMBOX_INT_ENABLE_TX_OVERFLOW_LSB
-#define GMBOX_INT_ENABLE_TX_OVERFLOW_MASK WLAN_GMBOX_INT_ENABLE_TX_OVERFLOW_MASK
-#define GMBOX_INT_ENABLE_TX_OVERFLOW_GET(x) WLAN_GMBOX_INT_ENABLE_TX_OVERFLOW_GET(x)
-#define GMBOX_INT_ENABLE_TX_OVERFLOW_SET(x) WLAN_GMBOX_INT_ENABLE_TX_OVERFLOW_SET(x)
-#define GMBOX_INT_ENABLE_RX_UNDERFLOW_MSB WLAN_GMBOX_INT_ENABLE_RX_UNDERFLOW_MSB
-#define GMBOX_INT_ENABLE_RX_UNDERFLOW_LSB WLAN_GMBOX_INT_ENABLE_RX_UNDERFLOW_LSB
-#define GMBOX_INT_ENABLE_RX_UNDERFLOW_MASK WLAN_GMBOX_INT_ENABLE_RX_UNDERFLOW_MASK
-#define GMBOX_INT_ENABLE_RX_UNDERFLOW_GET(x) WLAN_GMBOX_INT_ENABLE_RX_UNDERFLOW_GET(x)
-#define GMBOX_INT_ENABLE_RX_UNDERFLOW_SET(x) WLAN_GMBOX_INT_ENABLE_RX_UNDERFLOW_SET(x)
-#define GMBOX_INT_ENABLE_RX_DMA_COMPLETE_MSB WLAN_GMBOX_INT_ENABLE_RX_DMA_COMPLETE_MSB
-#define GMBOX_INT_ENABLE_RX_DMA_COMPLETE_LSB WLAN_GMBOX_INT_ENABLE_RX_DMA_COMPLETE_LSB
-#define GMBOX_INT_ENABLE_RX_DMA_COMPLETE_MASK WLAN_GMBOX_INT_ENABLE_RX_DMA_COMPLETE_MASK
-#define GMBOX_INT_ENABLE_RX_DMA_COMPLETE_GET(x) WLAN_GMBOX_INT_ENABLE_RX_DMA_COMPLETE_GET(x)
-#define GMBOX_INT_ENABLE_RX_DMA_COMPLETE_SET(x) WLAN_GMBOX_INT_ENABLE_RX_DMA_COMPLETE_SET(x)
-#define GMBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_MSB WLAN_GMBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_MSB
-#define GMBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_LSB WLAN_GMBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_LSB
-#define GMBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_MASK WLAN_GMBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_MASK
-#define GMBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_GET(x) WLAN_GMBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_GET(x)
-#define GMBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_SET(x) WLAN_GMBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_SET(x)
-#define GMBOX_INT_ENABLE_TX_DMA_COMPLETE_MSB WLAN_GMBOX_INT_ENABLE_TX_DMA_COMPLETE_MSB
-#define GMBOX_INT_ENABLE_TX_DMA_COMPLETE_LSB WLAN_GMBOX_INT_ENABLE_TX_DMA_COMPLETE_LSB
-#define GMBOX_INT_ENABLE_TX_DMA_COMPLETE_MASK WLAN_GMBOX_INT_ENABLE_TX_DMA_COMPLETE_MASK
-#define GMBOX_INT_ENABLE_TX_DMA_COMPLETE_GET(x) WLAN_GMBOX_INT_ENABLE_TX_DMA_COMPLETE_GET(x)
-#define GMBOX_INT_ENABLE_TX_DMA_COMPLETE_SET(x) WLAN_GMBOX_INT_ENABLE_TX_DMA_COMPLETE_SET(x)
-#define GMBOX_INT_ENABLE_TX_NOT_EMPTY_MSB WLAN_GMBOX_INT_ENABLE_TX_NOT_EMPTY_MSB
-#define GMBOX_INT_ENABLE_TX_NOT_EMPTY_LSB WLAN_GMBOX_INT_ENABLE_TX_NOT_EMPTY_LSB
-#define GMBOX_INT_ENABLE_TX_NOT_EMPTY_MASK WLAN_GMBOX_INT_ENABLE_TX_NOT_EMPTY_MASK
-#define GMBOX_INT_ENABLE_TX_NOT_EMPTY_GET(x) WLAN_GMBOX_INT_ENABLE_TX_NOT_EMPTY_GET(x)
-#define GMBOX_INT_ENABLE_TX_NOT_EMPTY_SET(x) WLAN_GMBOX_INT_ENABLE_TX_NOT_EMPTY_SET(x)
-#define GMBOX_INT_ENABLE_RX_NOT_FULL_MSB WLAN_GMBOX_INT_ENABLE_RX_NOT_FULL_MSB
-#define GMBOX_INT_ENABLE_RX_NOT_FULL_LSB WLAN_GMBOX_INT_ENABLE_RX_NOT_FULL_LSB
-#define GMBOX_INT_ENABLE_RX_NOT_FULL_MASK WLAN_GMBOX_INT_ENABLE_RX_NOT_FULL_MASK
-#define GMBOX_INT_ENABLE_RX_NOT_FULL_GET(x) WLAN_GMBOX_INT_ENABLE_RX_NOT_FULL_GET(x)
-#define GMBOX_INT_ENABLE_RX_NOT_FULL_SET(x) WLAN_GMBOX_INT_ENABLE_RX_NOT_FULL_SET(x)
-#define HOST_IF_WINDOW_ADDRESS WLAN_HOST_IF_WINDOW_ADDRESS
-#define HOST_IF_WINDOW_OFFSET WLAN_HOST_IF_WINDOW_OFFSET
-#define HOST_IF_WINDOW_DATA_MSB WLAN_HOST_IF_WINDOW_DATA_MSB
-#define HOST_IF_WINDOW_DATA_LSB WLAN_HOST_IF_WINDOW_DATA_LSB
-#define HOST_IF_WINDOW_DATA_MASK WLAN_HOST_IF_WINDOW_DATA_MASK
-#define HOST_IF_WINDOW_DATA_GET(x) WLAN_HOST_IF_WINDOW_DATA_GET(x)
-#define HOST_IF_WINDOW_DATA_SET(x) WLAN_HOST_IF_WINDOW_DATA_SET(x)
-
-#endif
diff --git a/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/mbox_wlan_host_reg.h b/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/mbox_wlan_host_reg.h
deleted file mode 100644
index 038d0d019273..000000000000
--- a/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/mbox_wlan_host_reg.h
+++ /dev/null
@@ -1,471 +0,0 @@
-// ------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-// ------------------------------------------------------------------
-//===================================================================
-// Author(s): ="Atheros"
-//===================================================================
-
-
-#ifndef _MBOX_WLAN_HOST_REG_REG_H_
-#define _MBOX_WLAN_HOST_REG_REG_H_
-
-#define HOST_INT_STATUS_ADDRESS 0x00000400
-#define HOST_INT_STATUS_OFFSET 0x00000400
-#define HOST_INT_STATUS_ERROR_MSB 7
-#define HOST_INT_STATUS_ERROR_LSB 7
-#define HOST_INT_STATUS_ERROR_MASK 0x00000080
-#define HOST_INT_STATUS_ERROR_GET(x) (((x) & HOST_INT_STATUS_ERROR_MASK) >> HOST_INT_STATUS_ERROR_LSB)
-#define HOST_INT_STATUS_ERROR_SET(x) (((x) << HOST_INT_STATUS_ERROR_LSB) & HOST_INT_STATUS_ERROR_MASK)
-#define HOST_INT_STATUS_CPU_MSB 6
-#define HOST_INT_STATUS_CPU_LSB 6
-#define HOST_INT_STATUS_CPU_MASK 0x00000040
-#define HOST_INT_STATUS_CPU_GET(x) (((x) & HOST_INT_STATUS_CPU_MASK) >> HOST_INT_STATUS_CPU_LSB)
-#define HOST_INT_STATUS_CPU_SET(x) (((x) << HOST_INT_STATUS_CPU_LSB) & HOST_INT_STATUS_CPU_MASK)
-#define HOST_INT_STATUS_INT_MSB 5
-#define HOST_INT_STATUS_INT_LSB 5
-#define HOST_INT_STATUS_INT_MASK 0x00000020
-#define HOST_INT_STATUS_INT_GET(x) (((x) & HOST_INT_STATUS_INT_MASK) >> HOST_INT_STATUS_INT_LSB)
-#define HOST_INT_STATUS_INT_SET(x) (((x) << HOST_INT_STATUS_INT_LSB) & HOST_INT_STATUS_INT_MASK)
-#define HOST_INT_STATUS_COUNTER_MSB 4
-#define HOST_INT_STATUS_COUNTER_LSB 4
-#define HOST_INT_STATUS_COUNTER_MASK 0x00000010
-#define HOST_INT_STATUS_COUNTER_GET(x) (((x) & HOST_INT_STATUS_COUNTER_MASK) >> HOST_INT_STATUS_COUNTER_LSB)
-#define HOST_INT_STATUS_COUNTER_SET(x) (((x) << HOST_INT_STATUS_COUNTER_LSB) & HOST_INT_STATUS_COUNTER_MASK)
-#define HOST_INT_STATUS_MBOX_DATA_MSB 3
-#define HOST_INT_STATUS_MBOX_DATA_LSB 0
-#define HOST_INT_STATUS_MBOX_DATA_MASK 0x0000000f
-#define HOST_INT_STATUS_MBOX_DATA_GET(x) (((x) & HOST_INT_STATUS_MBOX_DATA_MASK) >> HOST_INT_STATUS_MBOX_DATA_LSB)
-#define HOST_INT_STATUS_MBOX_DATA_SET(x) (((x) << HOST_INT_STATUS_MBOX_DATA_LSB) & HOST_INT_STATUS_MBOX_DATA_MASK)
-
-#define CPU_INT_STATUS_ADDRESS 0x00000401
-#define CPU_INT_STATUS_OFFSET 0x00000401
-#define CPU_INT_STATUS_BIT_MSB 7
-#define CPU_INT_STATUS_BIT_LSB 0
-#define CPU_INT_STATUS_BIT_MASK 0x000000ff
-#define CPU_INT_STATUS_BIT_GET(x) (((x) & CPU_INT_STATUS_BIT_MASK) >> CPU_INT_STATUS_BIT_LSB)
-#define CPU_INT_STATUS_BIT_SET(x) (((x) << CPU_INT_STATUS_BIT_LSB) & CPU_INT_STATUS_BIT_MASK)
-
-#define ERROR_INT_STATUS_ADDRESS 0x00000402
-#define ERROR_INT_STATUS_OFFSET 0x00000402
-#define ERROR_INT_STATUS_UART_HCI_FRAMER_SYNC_ERROR_MSB 6
-#define ERROR_INT_STATUS_UART_HCI_FRAMER_SYNC_ERROR_LSB 6
-#define ERROR_INT_STATUS_UART_HCI_FRAMER_SYNC_ERROR_MASK 0x00000040
-#define ERROR_INT_STATUS_UART_HCI_FRAMER_SYNC_ERROR_GET(x) (((x) & ERROR_INT_STATUS_UART_HCI_FRAMER_SYNC_ERROR_MASK) >> ERROR_INT_STATUS_UART_HCI_FRAMER_SYNC_ERROR_LSB)
-#define ERROR_INT_STATUS_UART_HCI_FRAMER_SYNC_ERROR_SET(x) (((x) << ERROR_INT_STATUS_UART_HCI_FRAMER_SYNC_ERROR_LSB) & ERROR_INT_STATUS_UART_HCI_FRAMER_SYNC_ERROR_MASK)
-#define ERROR_INT_STATUS_UART_HCI_FRAMER_OVERFLOW_MSB 5
-#define ERROR_INT_STATUS_UART_HCI_FRAMER_OVERFLOW_LSB 5
-#define ERROR_INT_STATUS_UART_HCI_FRAMER_OVERFLOW_MASK 0x00000020
-#define ERROR_INT_STATUS_UART_HCI_FRAMER_OVERFLOW_GET(x) (((x) & ERROR_INT_STATUS_UART_HCI_FRAMER_OVERFLOW_MASK) >> ERROR_INT_STATUS_UART_HCI_FRAMER_OVERFLOW_LSB)
-#define ERROR_INT_STATUS_UART_HCI_FRAMER_OVERFLOW_SET(x) (((x) << ERROR_INT_STATUS_UART_HCI_FRAMER_OVERFLOW_LSB) & ERROR_INT_STATUS_UART_HCI_FRAMER_OVERFLOW_MASK)
-#define ERROR_INT_STATUS_UART_HCI_FRAMER_UNDERFLOW_MSB 4
-#define ERROR_INT_STATUS_UART_HCI_FRAMER_UNDERFLOW_LSB 4
-#define ERROR_INT_STATUS_UART_HCI_FRAMER_UNDERFLOW_MASK 0x00000010
-#define ERROR_INT_STATUS_UART_HCI_FRAMER_UNDERFLOW_GET(x) (((x) & ERROR_INT_STATUS_UART_HCI_FRAMER_UNDERFLOW_MASK) >> ERROR_INT_STATUS_UART_HCI_FRAMER_UNDERFLOW_LSB)
-#define ERROR_INT_STATUS_UART_HCI_FRAMER_UNDERFLOW_SET(x) (((x) << ERROR_INT_STATUS_UART_HCI_FRAMER_UNDERFLOW_LSB) & ERROR_INT_STATUS_UART_HCI_FRAMER_UNDERFLOW_MASK)
-#define ERROR_INT_STATUS_SPI_MSB 3
-#define ERROR_INT_STATUS_SPI_LSB 3
-#define ERROR_INT_STATUS_SPI_MASK 0x00000008
-#define ERROR_INT_STATUS_SPI_GET(x) (((x) & ERROR_INT_STATUS_SPI_MASK) >> ERROR_INT_STATUS_SPI_LSB)
-#define ERROR_INT_STATUS_SPI_SET(x) (((x) << ERROR_INT_STATUS_SPI_LSB) & ERROR_INT_STATUS_SPI_MASK)
-#define ERROR_INT_STATUS_WAKEUP_MSB 2
-#define ERROR_INT_STATUS_WAKEUP_LSB 2
-#define ERROR_INT_STATUS_WAKEUP_MASK 0x00000004
-#define ERROR_INT_STATUS_WAKEUP_GET(x) (((x) & ERROR_INT_STATUS_WAKEUP_MASK) >> ERROR_INT_STATUS_WAKEUP_LSB)
-#define ERROR_INT_STATUS_WAKEUP_SET(x) (((x) << ERROR_INT_STATUS_WAKEUP_LSB) & ERROR_INT_STATUS_WAKEUP_MASK)
-#define ERROR_INT_STATUS_RX_UNDERFLOW_MSB 1
-#define ERROR_INT_STATUS_RX_UNDERFLOW_LSB 1
-#define ERROR_INT_STATUS_RX_UNDERFLOW_MASK 0x00000002
-#define ERROR_INT_STATUS_RX_UNDERFLOW_GET(x) (((x) & ERROR_INT_STATUS_RX_UNDERFLOW_MASK) >> ERROR_INT_STATUS_RX_UNDERFLOW_LSB)
-#define ERROR_INT_STATUS_RX_UNDERFLOW_SET(x) (((x) << ERROR_INT_STATUS_RX_UNDERFLOW_LSB) & ERROR_INT_STATUS_RX_UNDERFLOW_MASK)
-#define ERROR_INT_STATUS_TX_OVERFLOW_MSB 0
-#define ERROR_INT_STATUS_TX_OVERFLOW_LSB 0
-#define ERROR_INT_STATUS_TX_OVERFLOW_MASK 0x00000001
-#define ERROR_INT_STATUS_TX_OVERFLOW_GET(x) (((x) & ERROR_INT_STATUS_TX_OVERFLOW_MASK) >> ERROR_INT_STATUS_TX_OVERFLOW_LSB)
-#define ERROR_INT_STATUS_TX_OVERFLOW_SET(x) (((x) << ERROR_INT_STATUS_TX_OVERFLOW_LSB) & ERROR_INT_STATUS_TX_OVERFLOW_MASK)
-
-#define COUNTER_INT_STATUS_ADDRESS 0x00000403
-#define COUNTER_INT_STATUS_OFFSET 0x00000403
-#define COUNTER_INT_STATUS_COUNTER_MSB 7
-#define COUNTER_INT_STATUS_COUNTER_LSB 0
-#define COUNTER_INT_STATUS_COUNTER_MASK 0x000000ff
-#define COUNTER_INT_STATUS_COUNTER_GET(x) (((x) & COUNTER_INT_STATUS_COUNTER_MASK) >> COUNTER_INT_STATUS_COUNTER_LSB)
-#define COUNTER_INT_STATUS_COUNTER_SET(x) (((x) << COUNTER_INT_STATUS_COUNTER_LSB) & COUNTER_INT_STATUS_COUNTER_MASK)
-
-#define MBOX_FRAME_ADDRESS 0x00000404
-#define MBOX_FRAME_OFFSET 0x00000404
-#define MBOX_FRAME_RX_EOM_MSB 7
-#define MBOX_FRAME_RX_EOM_LSB 4
-#define MBOX_FRAME_RX_EOM_MASK 0x000000f0
-#define MBOX_FRAME_RX_EOM_GET(x) (((x) & MBOX_FRAME_RX_EOM_MASK) >> MBOX_FRAME_RX_EOM_LSB)
-#define MBOX_FRAME_RX_EOM_SET(x) (((x) << MBOX_FRAME_RX_EOM_LSB) & MBOX_FRAME_RX_EOM_MASK)
-#define MBOX_FRAME_RX_SOM_MSB 3
-#define MBOX_FRAME_RX_SOM_LSB 0
-#define MBOX_FRAME_RX_SOM_MASK 0x0000000f
-#define MBOX_FRAME_RX_SOM_GET(x) (((x) & MBOX_FRAME_RX_SOM_MASK) >> MBOX_FRAME_RX_SOM_LSB)
-#define MBOX_FRAME_RX_SOM_SET(x) (((x) << MBOX_FRAME_RX_SOM_LSB) & MBOX_FRAME_RX_SOM_MASK)
-
-#define RX_LOOKAHEAD_VALID_ADDRESS 0x00000405
-#define RX_LOOKAHEAD_VALID_OFFSET 0x00000405
-#define RX_LOOKAHEAD_VALID_MBOX_MSB 3
-#define RX_LOOKAHEAD_VALID_MBOX_LSB 0
-#define RX_LOOKAHEAD_VALID_MBOX_MASK 0x0000000f
-#define RX_LOOKAHEAD_VALID_MBOX_GET(x) (((x) & RX_LOOKAHEAD_VALID_MBOX_MASK) >> RX_LOOKAHEAD_VALID_MBOX_LSB)
-#define RX_LOOKAHEAD_VALID_MBOX_SET(x) (((x) << RX_LOOKAHEAD_VALID_MBOX_LSB) & RX_LOOKAHEAD_VALID_MBOX_MASK)
-
-#define HOST_INT_STATUS2_ADDRESS 0x00000406
-#define HOST_INT_STATUS2_OFFSET 0x00000406
-#define HOST_INT_STATUS2_GMBOX_RX_UNDERFLOW_MSB 2
-#define HOST_INT_STATUS2_GMBOX_RX_UNDERFLOW_LSB 2
-#define HOST_INT_STATUS2_GMBOX_RX_UNDERFLOW_MASK 0x00000004
-#define HOST_INT_STATUS2_GMBOX_RX_UNDERFLOW_GET(x) (((x) & HOST_INT_STATUS2_GMBOX_RX_UNDERFLOW_MASK) >> HOST_INT_STATUS2_GMBOX_RX_UNDERFLOW_LSB)
-#define HOST_INT_STATUS2_GMBOX_RX_UNDERFLOW_SET(x) (((x) << HOST_INT_STATUS2_GMBOX_RX_UNDERFLOW_LSB) & HOST_INT_STATUS2_GMBOX_RX_UNDERFLOW_MASK)
-#define HOST_INT_STATUS2_GMBOX_TX_OVERFLOW_MSB 1
-#define HOST_INT_STATUS2_GMBOX_TX_OVERFLOW_LSB 1
-#define HOST_INT_STATUS2_GMBOX_TX_OVERFLOW_MASK 0x00000002
-#define HOST_INT_STATUS2_GMBOX_TX_OVERFLOW_GET(x) (((x) & HOST_INT_STATUS2_GMBOX_TX_OVERFLOW_MASK) >> HOST_INT_STATUS2_GMBOX_TX_OVERFLOW_LSB)
-#define HOST_INT_STATUS2_GMBOX_TX_OVERFLOW_SET(x) (((x) << HOST_INT_STATUS2_GMBOX_TX_OVERFLOW_LSB) & HOST_INT_STATUS2_GMBOX_TX_OVERFLOW_MASK)
-#define HOST_INT_STATUS2_GMBOX_DATA_MSB 0
-#define HOST_INT_STATUS2_GMBOX_DATA_LSB 0
-#define HOST_INT_STATUS2_GMBOX_DATA_MASK 0x00000001
-#define HOST_INT_STATUS2_GMBOX_DATA_GET(x) (((x) & HOST_INT_STATUS2_GMBOX_DATA_MASK) >> HOST_INT_STATUS2_GMBOX_DATA_LSB)
-#define HOST_INT_STATUS2_GMBOX_DATA_SET(x) (((x) << HOST_INT_STATUS2_GMBOX_DATA_LSB) & HOST_INT_STATUS2_GMBOX_DATA_MASK)
-
-#define GMBOX_RX_AVAIL_ADDRESS 0x00000407
-#define GMBOX_RX_AVAIL_OFFSET 0x00000407
-#define GMBOX_RX_AVAIL_BYTE_MSB 6
-#define GMBOX_RX_AVAIL_BYTE_LSB 0
-#define GMBOX_RX_AVAIL_BYTE_MASK 0x0000007f
-#define GMBOX_RX_AVAIL_BYTE_GET(x) (((x) & GMBOX_RX_AVAIL_BYTE_MASK) >> GMBOX_RX_AVAIL_BYTE_LSB)
-#define GMBOX_RX_AVAIL_BYTE_SET(x) (((x) << GMBOX_RX_AVAIL_BYTE_LSB) & GMBOX_RX_AVAIL_BYTE_MASK)
-
-#define RX_LOOKAHEAD0_ADDRESS 0x00000408
-#define RX_LOOKAHEAD0_OFFSET 0x00000408
-#define RX_LOOKAHEAD0_DATA_MSB 7
-#define RX_LOOKAHEAD0_DATA_LSB 0
-#define RX_LOOKAHEAD0_DATA_MASK 0x000000ff
-#define RX_LOOKAHEAD0_DATA_GET(x) (((x) & RX_LOOKAHEAD0_DATA_MASK) >> RX_LOOKAHEAD0_DATA_LSB)
-#define RX_LOOKAHEAD0_DATA_SET(x) (((x) << RX_LOOKAHEAD0_DATA_LSB) & RX_LOOKAHEAD0_DATA_MASK)
-
-#define RX_LOOKAHEAD1_ADDRESS 0x0000040c
-#define RX_LOOKAHEAD1_OFFSET 0x0000040c
-#define RX_LOOKAHEAD1_DATA_MSB 7
-#define RX_LOOKAHEAD1_DATA_LSB 0
-#define RX_LOOKAHEAD1_DATA_MASK 0x000000ff
-#define RX_LOOKAHEAD1_DATA_GET(x) (((x) & RX_LOOKAHEAD1_DATA_MASK) >> RX_LOOKAHEAD1_DATA_LSB)
-#define RX_LOOKAHEAD1_DATA_SET(x) (((x) << RX_LOOKAHEAD1_DATA_LSB) & RX_LOOKAHEAD1_DATA_MASK)
-
-#define RX_LOOKAHEAD2_ADDRESS 0x00000410
-#define RX_LOOKAHEAD2_OFFSET 0x00000410
-#define RX_LOOKAHEAD2_DATA_MSB 7
-#define RX_LOOKAHEAD2_DATA_LSB 0
-#define RX_LOOKAHEAD2_DATA_MASK 0x000000ff
-#define RX_LOOKAHEAD2_DATA_GET(x) (((x) & RX_LOOKAHEAD2_DATA_MASK) >> RX_LOOKAHEAD2_DATA_LSB)
-#define RX_LOOKAHEAD2_DATA_SET(x) (((x) << RX_LOOKAHEAD2_DATA_LSB) & RX_LOOKAHEAD2_DATA_MASK)
-
-#define RX_LOOKAHEAD3_ADDRESS 0x00000414
-#define RX_LOOKAHEAD3_OFFSET 0x00000414
-#define RX_LOOKAHEAD3_DATA_MSB 7
-#define RX_LOOKAHEAD3_DATA_LSB 0
-#define RX_LOOKAHEAD3_DATA_MASK 0x000000ff
-#define RX_LOOKAHEAD3_DATA_GET(x) (((x) & RX_LOOKAHEAD3_DATA_MASK) >> RX_LOOKAHEAD3_DATA_LSB)
-#define RX_LOOKAHEAD3_DATA_SET(x) (((x) << RX_LOOKAHEAD3_DATA_LSB) & RX_LOOKAHEAD3_DATA_MASK)
-
-#define INT_STATUS_ENABLE_ADDRESS 0x00000418
-#define INT_STATUS_ENABLE_OFFSET 0x00000418
-#define INT_STATUS_ENABLE_ERROR_MSB 7
-#define INT_STATUS_ENABLE_ERROR_LSB 7
-#define INT_STATUS_ENABLE_ERROR_MASK 0x00000080
-#define INT_STATUS_ENABLE_ERROR_GET(x) (((x) & INT_STATUS_ENABLE_ERROR_MASK) >> INT_STATUS_ENABLE_ERROR_LSB)
-#define INT_STATUS_ENABLE_ERROR_SET(x) (((x) << INT_STATUS_ENABLE_ERROR_LSB) & INT_STATUS_ENABLE_ERROR_MASK)
-#define INT_STATUS_ENABLE_CPU_MSB 6
-#define INT_STATUS_ENABLE_CPU_LSB 6
-#define INT_STATUS_ENABLE_CPU_MASK 0x00000040
-#define INT_STATUS_ENABLE_CPU_GET(x) (((x) & INT_STATUS_ENABLE_CPU_MASK) >> INT_STATUS_ENABLE_CPU_LSB)
-#define INT_STATUS_ENABLE_CPU_SET(x) (((x) << INT_STATUS_ENABLE_CPU_LSB) & INT_STATUS_ENABLE_CPU_MASK)
-#define INT_STATUS_ENABLE_INT_MSB 5
-#define INT_STATUS_ENABLE_INT_LSB 5
-#define INT_STATUS_ENABLE_INT_MASK 0x00000020
-#define INT_STATUS_ENABLE_INT_GET(x) (((x) & INT_STATUS_ENABLE_INT_MASK) >> INT_STATUS_ENABLE_INT_LSB)
-#define INT_STATUS_ENABLE_INT_SET(x) (((x) << INT_STATUS_ENABLE_INT_LSB) & INT_STATUS_ENABLE_INT_MASK)
-#define INT_STATUS_ENABLE_COUNTER_MSB 4
-#define INT_STATUS_ENABLE_COUNTER_LSB 4
-#define INT_STATUS_ENABLE_COUNTER_MASK 0x00000010
-#define INT_STATUS_ENABLE_COUNTER_GET(x) (((x) & INT_STATUS_ENABLE_COUNTER_MASK) >> INT_STATUS_ENABLE_COUNTER_LSB)
-#define INT_STATUS_ENABLE_COUNTER_SET(x) (((x) << INT_STATUS_ENABLE_COUNTER_LSB) & INT_STATUS_ENABLE_COUNTER_MASK)
-#define INT_STATUS_ENABLE_MBOX_DATA_MSB 3
-#define INT_STATUS_ENABLE_MBOX_DATA_LSB 0
-#define INT_STATUS_ENABLE_MBOX_DATA_MASK 0x0000000f
-#define INT_STATUS_ENABLE_MBOX_DATA_GET(x) (((x) & INT_STATUS_ENABLE_MBOX_DATA_MASK) >> INT_STATUS_ENABLE_MBOX_DATA_LSB)
-#define INT_STATUS_ENABLE_MBOX_DATA_SET(x) (((x) << INT_STATUS_ENABLE_MBOX_DATA_LSB) & INT_STATUS_ENABLE_MBOX_DATA_MASK)
-
-#define CPU_INT_STATUS_ENABLE_ADDRESS 0x00000419
-#define CPU_INT_STATUS_ENABLE_OFFSET 0x00000419
-#define CPU_INT_STATUS_ENABLE_BIT_MSB 7
-#define CPU_INT_STATUS_ENABLE_BIT_LSB 0
-#define CPU_INT_STATUS_ENABLE_BIT_MASK 0x000000ff
-#define CPU_INT_STATUS_ENABLE_BIT_GET(x) (((x) & CPU_INT_STATUS_ENABLE_BIT_MASK) >> CPU_INT_STATUS_ENABLE_BIT_LSB)
-#define CPU_INT_STATUS_ENABLE_BIT_SET(x) (((x) << CPU_INT_STATUS_ENABLE_BIT_LSB) & CPU_INT_STATUS_ENABLE_BIT_MASK)
-
-#define ERROR_STATUS_ENABLE_ADDRESS 0x0000041a
-#define ERROR_STATUS_ENABLE_OFFSET 0x0000041a
-#define ERROR_STATUS_ENABLE_UART_HCI_FRAMER_SYNC_ERROR_MSB 6
-#define ERROR_STATUS_ENABLE_UART_HCI_FRAMER_SYNC_ERROR_LSB 6
-#define ERROR_STATUS_ENABLE_UART_HCI_FRAMER_SYNC_ERROR_MASK 0x00000040
-#define ERROR_STATUS_ENABLE_UART_HCI_FRAMER_SYNC_ERROR_GET(x) (((x) & ERROR_STATUS_ENABLE_UART_HCI_FRAMER_SYNC_ERROR_MASK) >> ERROR_STATUS_ENABLE_UART_HCI_FRAMER_SYNC_ERROR_LSB)
-#define ERROR_STATUS_ENABLE_UART_HCI_FRAMER_SYNC_ERROR_SET(x) (((x) << ERROR_STATUS_ENABLE_UART_HCI_FRAMER_SYNC_ERROR_LSB) & ERROR_STATUS_ENABLE_UART_HCI_FRAMER_SYNC_ERROR_MASK)
-#define ERROR_STATUS_ENABLE_UART_HCI_FRAMER_OVERFLOW_MSB 5
-#define ERROR_STATUS_ENABLE_UART_HCI_FRAMER_OVERFLOW_LSB 5
-#define ERROR_STATUS_ENABLE_UART_HCI_FRAMER_OVERFLOW_MASK 0x00000020
-#define ERROR_STATUS_ENABLE_UART_HCI_FRAMER_OVERFLOW_GET(x) (((x) & ERROR_STATUS_ENABLE_UART_HCI_FRAMER_OVERFLOW_MASK) >> ERROR_STATUS_ENABLE_UART_HCI_FRAMER_OVERFLOW_LSB)
-#define ERROR_STATUS_ENABLE_UART_HCI_FRAMER_OVERFLOW_SET(x) (((x) << ERROR_STATUS_ENABLE_UART_HCI_FRAMER_OVERFLOW_LSB) & ERROR_STATUS_ENABLE_UART_HCI_FRAMER_OVERFLOW_MASK)
-#define ERROR_STATUS_ENABLE_UART_HCI_FRAMER_UNDERFLOW_MSB 4
-#define ERROR_STATUS_ENABLE_UART_HCI_FRAMER_UNDERFLOW_LSB 4
-#define ERROR_STATUS_ENABLE_UART_HCI_FRAMER_UNDERFLOW_MASK 0x00000010
-#define ERROR_STATUS_ENABLE_UART_HCI_FRAMER_UNDERFLOW_GET(x) (((x) & ERROR_STATUS_ENABLE_UART_HCI_FRAMER_UNDERFLOW_MASK) >> ERROR_STATUS_ENABLE_UART_HCI_FRAMER_UNDERFLOW_LSB)
-#define ERROR_STATUS_ENABLE_UART_HCI_FRAMER_UNDERFLOW_SET(x) (((x) << ERROR_STATUS_ENABLE_UART_HCI_FRAMER_UNDERFLOW_LSB) & ERROR_STATUS_ENABLE_UART_HCI_FRAMER_UNDERFLOW_MASK)
-#define ERROR_STATUS_ENABLE_WAKEUP_MSB 2
-#define ERROR_STATUS_ENABLE_WAKEUP_LSB 2
-#define ERROR_STATUS_ENABLE_WAKEUP_MASK 0x00000004
-#define ERROR_STATUS_ENABLE_WAKEUP_GET(x) (((x) & ERROR_STATUS_ENABLE_WAKEUP_MASK) >> ERROR_STATUS_ENABLE_WAKEUP_LSB)
-#define ERROR_STATUS_ENABLE_WAKEUP_SET(x) (((x) << ERROR_STATUS_ENABLE_WAKEUP_LSB) & ERROR_STATUS_ENABLE_WAKEUP_MASK)
-#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_MSB 1
-#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB 1
-#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK 0x00000002
-#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_GET(x) (((x) & ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK) >> ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB)
-#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_SET(x) (((x) << ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB) & ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK)
-#define ERROR_STATUS_ENABLE_TX_OVERFLOW_MSB 0
-#define ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB 0
-#define ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK 0x00000001
-#define ERROR_STATUS_ENABLE_TX_OVERFLOW_GET(x) (((x) & ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK) >> ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB)
-#define ERROR_STATUS_ENABLE_TX_OVERFLOW_SET(x) (((x) << ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB) & ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK)
-
-#define COUNTER_INT_STATUS_ENABLE_ADDRESS 0x0000041b
-#define COUNTER_INT_STATUS_ENABLE_OFFSET 0x0000041b
-#define COUNTER_INT_STATUS_ENABLE_BIT_MSB 7
-#define COUNTER_INT_STATUS_ENABLE_BIT_LSB 0
-#define COUNTER_INT_STATUS_ENABLE_BIT_MASK 0x000000ff
-#define COUNTER_INT_STATUS_ENABLE_BIT_GET(x) (((x) & COUNTER_INT_STATUS_ENABLE_BIT_MASK) >> COUNTER_INT_STATUS_ENABLE_BIT_LSB)
-#define COUNTER_INT_STATUS_ENABLE_BIT_SET(x) (((x) << COUNTER_INT_STATUS_ENABLE_BIT_LSB) & COUNTER_INT_STATUS_ENABLE_BIT_MASK)
-
-#define COUNT_ADDRESS 0x00000420
-#define COUNT_OFFSET 0x00000420
-#define COUNT_VALUE_MSB 7
-#define COUNT_VALUE_LSB 0
-#define COUNT_VALUE_MASK 0x000000ff
-#define COUNT_VALUE_GET(x) (((x) & COUNT_VALUE_MASK) >> COUNT_VALUE_LSB)
-#define COUNT_VALUE_SET(x) (((x) << COUNT_VALUE_LSB) & COUNT_VALUE_MASK)
-
-#define COUNT_DEC_ADDRESS 0x00000440
-#define COUNT_DEC_OFFSET 0x00000440
-#define COUNT_DEC_VALUE_MSB 7
-#define COUNT_DEC_VALUE_LSB 0
-#define COUNT_DEC_VALUE_MASK 0x000000ff
-#define COUNT_DEC_VALUE_GET(x) (((x) & COUNT_DEC_VALUE_MASK) >> COUNT_DEC_VALUE_LSB)
-#define COUNT_DEC_VALUE_SET(x) (((x) << COUNT_DEC_VALUE_LSB) & COUNT_DEC_VALUE_MASK)
-
-#define SCRATCH_ADDRESS 0x00000460
-#define SCRATCH_OFFSET 0x00000460
-#define SCRATCH_VALUE_MSB 7
-#define SCRATCH_VALUE_LSB 0
-#define SCRATCH_VALUE_MASK 0x000000ff
-#define SCRATCH_VALUE_GET(x) (((x) & SCRATCH_VALUE_MASK) >> SCRATCH_VALUE_LSB)
-#define SCRATCH_VALUE_SET(x) (((x) << SCRATCH_VALUE_LSB) & SCRATCH_VALUE_MASK)
-
-#define FIFO_TIMEOUT_ADDRESS 0x00000468
-#define FIFO_TIMEOUT_OFFSET 0x00000468
-#define FIFO_TIMEOUT_VALUE_MSB 7
-#define FIFO_TIMEOUT_VALUE_LSB 0
-#define FIFO_TIMEOUT_VALUE_MASK 0x000000ff
-#define FIFO_TIMEOUT_VALUE_GET(x) (((x) & FIFO_TIMEOUT_VALUE_MASK) >> FIFO_TIMEOUT_VALUE_LSB)
-#define FIFO_TIMEOUT_VALUE_SET(x) (((x) << FIFO_TIMEOUT_VALUE_LSB) & FIFO_TIMEOUT_VALUE_MASK)
-
-#define FIFO_TIMEOUT_ENABLE_ADDRESS 0x00000469
-#define FIFO_TIMEOUT_ENABLE_OFFSET 0x00000469
-#define FIFO_TIMEOUT_ENABLE_SET_MSB 0
-#define FIFO_TIMEOUT_ENABLE_SET_LSB 0
-#define FIFO_TIMEOUT_ENABLE_SET_MASK 0x00000001
-#define FIFO_TIMEOUT_ENABLE_SET_GET(x) (((x) & FIFO_TIMEOUT_ENABLE_SET_MASK) >> FIFO_TIMEOUT_ENABLE_SET_LSB)
-#define FIFO_TIMEOUT_ENABLE_SET_SET(x) (((x) << FIFO_TIMEOUT_ENABLE_SET_LSB) & FIFO_TIMEOUT_ENABLE_SET_MASK)
-
-#define DISABLE_SLEEP_ADDRESS 0x0000046a
-#define DISABLE_SLEEP_OFFSET 0x0000046a
-#define DISABLE_SLEEP_FOR_INT_MSB 1
-#define DISABLE_SLEEP_FOR_INT_LSB 1
-#define DISABLE_SLEEP_FOR_INT_MASK 0x00000002
-#define DISABLE_SLEEP_FOR_INT_GET(x) (((x) & DISABLE_SLEEP_FOR_INT_MASK) >> DISABLE_SLEEP_FOR_INT_LSB)
-#define DISABLE_SLEEP_FOR_INT_SET(x) (((x) << DISABLE_SLEEP_FOR_INT_LSB) & DISABLE_SLEEP_FOR_INT_MASK)
-#define DISABLE_SLEEP_ON_MSB 0
-#define DISABLE_SLEEP_ON_LSB 0
-#define DISABLE_SLEEP_ON_MASK 0x00000001
-#define DISABLE_SLEEP_ON_GET(x) (((x) & DISABLE_SLEEP_ON_MASK) >> DISABLE_SLEEP_ON_LSB)
-#define DISABLE_SLEEP_ON_SET(x) (((x) << DISABLE_SLEEP_ON_LSB) & DISABLE_SLEEP_ON_MASK)
-
-#define LOCAL_BUS_ADDRESS 0x00000470
-#define LOCAL_BUS_OFFSET 0x00000470
-#define LOCAL_BUS_STATE_MSB 1
-#define LOCAL_BUS_STATE_LSB 0
-#define LOCAL_BUS_STATE_MASK 0x00000003
-#define LOCAL_BUS_STATE_GET(x) (((x) & LOCAL_BUS_STATE_MASK) >> LOCAL_BUS_STATE_LSB)
-#define LOCAL_BUS_STATE_SET(x) (((x) << LOCAL_BUS_STATE_LSB) & LOCAL_BUS_STATE_MASK)
-
-#define INT_WLAN_ADDRESS 0x00000472
-#define INT_WLAN_OFFSET 0x00000472
-#define INT_WLAN_VECTOR_MSB 7
-#define INT_WLAN_VECTOR_LSB 0
-#define INT_WLAN_VECTOR_MASK 0x000000ff
-#define INT_WLAN_VECTOR_GET(x) (((x) & INT_WLAN_VECTOR_MASK) >> INT_WLAN_VECTOR_LSB)
-#define INT_WLAN_VECTOR_SET(x) (((x) << INT_WLAN_VECTOR_LSB) & INT_WLAN_VECTOR_MASK)
-
-#define WINDOW_DATA_ADDRESS 0x00000474
-#define WINDOW_DATA_OFFSET 0x00000474
-#define WINDOW_DATA_DATA_MSB 7
-#define WINDOW_DATA_DATA_LSB 0
-#define WINDOW_DATA_DATA_MASK 0x000000ff
-#define WINDOW_DATA_DATA_GET(x) (((x) & WINDOW_DATA_DATA_MASK) >> WINDOW_DATA_DATA_LSB)
-#define WINDOW_DATA_DATA_SET(x) (((x) << WINDOW_DATA_DATA_LSB) & WINDOW_DATA_DATA_MASK)
-
-#define WINDOW_WRITE_ADDR_ADDRESS 0x00000478
-#define WINDOW_WRITE_ADDR_OFFSET 0x00000478
-#define WINDOW_WRITE_ADDR_ADDR_MSB 7
-#define WINDOW_WRITE_ADDR_ADDR_LSB 0
-#define WINDOW_WRITE_ADDR_ADDR_MASK 0x000000ff
-#define WINDOW_WRITE_ADDR_ADDR_GET(x) (((x) & WINDOW_WRITE_ADDR_ADDR_MASK) >> WINDOW_WRITE_ADDR_ADDR_LSB)
-#define WINDOW_WRITE_ADDR_ADDR_SET(x) (((x) << WINDOW_WRITE_ADDR_ADDR_LSB) & WINDOW_WRITE_ADDR_ADDR_MASK)
-
-#define WINDOW_READ_ADDR_ADDRESS 0x0000047c
-#define WINDOW_READ_ADDR_OFFSET 0x0000047c
-#define WINDOW_READ_ADDR_ADDR_MSB 7
-#define WINDOW_READ_ADDR_ADDR_LSB 0
-#define WINDOW_READ_ADDR_ADDR_MASK 0x000000ff
-#define WINDOW_READ_ADDR_ADDR_GET(x) (((x) & WINDOW_READ_ADDR_ADDR_MASK) >> WINDOW_READ_ADDR_ADDR_LSB)
-#define WINDOW_READ_ADDR_ADDR_SET(x) (((x) << WINDOW_READ_ADDR_ADDR_LSB) & WINDOW_READ_ADDR_ADDR_MASK)
-
-#define HOST_CTRL_SPI_CONFIG_ADDRESS 0x00000480
-#define HOST_CTRL_SPI_CONFIG_OFFSET 0x00000480
-#define HOST_CTRL_SPI_CONFIG_SPI_RESET_MSB 4
-#define HOST_CTRL_SPI_CONFIG_SPI_RESET_LSB 4
-#define HOST_CTRL_SPI_CONFIG_SPI_RESET_MASK 0x00000010
-#define HOST_CTRL_SPI_CONFIG_SPI_RESET_GET(x) (((x) & HOST_CTRL_SPI_CONFIG_SPI_RESET_MASK) >> HOST_CTRL_SPI_CONFIG_SPI_RESET_LSB)
-#define HOST_CTRL_SPI_CONFIG_SPI_RESET_SET(x) (((x) << HOST_CTRL_SPI_CONFIG_SPI_RESET_LSB) & HOST_CTRL_SPI_CONFIG_SPI_RESET_MASK)
-#define HOST_CTRL_SPI_CONFIG_INTERRUPT_ENABLE_MSB 3
-#define HOST_CTRL_SPI_CONFIG_INTERRUPT_ENABLE_LSB 3
-#define HOST_CTRL_SPI_CONFIG_INTERRUPT_ENABLE_MASK 0x00000008
-#define HOST_CTRL_SPI_CONFIG_INTERRUPT_ENABLE_GET(x) (((x) & HOST_CTRL_SPI_CONFIG_INTERRUPT_ENABLE_MASK) >> HOST_CTRL_SPI_CONFIG_INTERRUPT_ENABLE_LSB)
-#define HOST_CTRL_SPI_CONFIG_INTERRUPT_ENABLE_SET(x) (((x) << HOST_CTRL_SPI_CONFIG_INTERRUPT_ENABLE_LSB) & HOST_CTRL_SPI_CONFIG_INTERRUPT_ENABLE_MASK)
-#define HOST_CTRL_SPI_CONFIG_TEST_MODE_MSB 2
-#define HOST_CTRL_SPI_CONFIG_TEST_MODE_LSB 2
-#define HOST_CTRL_SPI_CONFIG_TEST_MODE_MASK 0x00000004
-#define HOST_CTRL_SPI_CONFIG_TEST_MODE_GET(x) (((x) & HOST_CTRL_SPI_CONFIG_TEST_MODE_MASK) >> HOST_CTRL_SPI_CONFIG_TEST_MODE_LSB)
-#define HOST_CTRL_SPI_CONFIG_TEST_MODE_SET(x) (((x) << HOST_CTRL_SPI_CONFIG_TEST_MODE_LSB) & HOST_CTRL_SPI_CONFIG_TEST_MODE_MASK)
-#define HOST_CTRL_SPI_CONFIG_DATA_SIZE_MSB 1
-#define HOST_CTRL_SPI_CONFIG_DATA_SIZE_LSB 0
-#define HOST_CTRL_SPI_CONFIG_DATA_SIZE_MASK 0x00000003
-#define HOST_CTRL_SPI_CONFIG_DATA_SIZE_GET(x) (((x) & HOST_CTRL_SPI_CONFIG_DATA_SIZE_MASK) >> HOST_CTRL_SPI_CONFIG_DATA_SIZE_LSB)
-#define HOST_CTRL_SPI_CONFIG_DATA_SIZE_SET(x) (((x) << HOST_CTRL_SPI_CONFIG_DATA_SIZE_LSB) & HOST_CTRL_SPI_CONFIG_DATA_SIZE_MASK)
-
-#define HOST_CTRL_SPI_STATUS_ADDRESS 0x00000481
-#define HOST_CTRL_SPI_STATUS_OFFSET 0x00000481
-#define HOST_CTRL_SPI_STATUS_ADDR_ERR_MSB 3
-#define HOST_CTRL_SPI_STATUS_ADDR_ERR_LSB 3
-#define HOST_CTRL_SPI_STATUS_ADDR_ERR_MASK 0x00000008
-#define HOST_CTRL_SPI_STATUS_ADDR_ERR_GET(x) (((x) & HOST_CTRL_SPI_STATUS_ADDR_ERR_MASK) >> HOST_CTRL_SPI_STATUS_ADDR_ERR_LSB)
-#define HOST_CTRL_SPI_STATUS_ADDR_ERR_SET(x) (((x) << HOST_CTRL_SPI_STATUS_ADDR_ERR_LSB) & HOST_CTRL_SPI_STATUS_ADDR_ERR_MASK)
-#define HOST_CTRL_SPI_STATUS_RD_ERR_MSB 2
-#define HOST_CTRL_SPI_STATUS_RD_ERR_LSB 2
-#define HOST_CTRL_SPI_STATUS_RD_ERR_MASK 0x00000004
-#define HOST_CTRL_SPI_STATUS_RD_ERR_GET(x) (((x) & HOST_CTRL_SPI_STATUS_RD_ERR_MASK) >> HOST_CTRL_SPI_STATUS_RD_ERR_LSB)
-#define HOST_CTRL_SPI_STATUS_RD_ERR_SET(x) (((x) << HOST_CTRL_SPI_STATUS_RD_ERR_LSB) & HOST_CTRL_SPI_STATUS_RD_ERR_MASK)
-#define HOST_CTRL_SPI_STATUS_WR_ERR_MSB 1
-#define HOST_CTRL_SPI_STATUS_WR_ERR_LSB 1
-#define HOST_CTRL_SPI_STATUS_WR_ERR_MASK 0x00000002
-#define HOST_CTRL_SPI_STATUS_WR_ERR_GET(x) (((x) & HOST_CTRL_SPI_STATUS_WR_ERR_MASK) >> HOST_CTRL_SPI_STATUS_WR_ERR_LSB)
-#define HOST_CTRL_SPI_STATUS_WR_ERR_SET(x) (((x) << HOST_CTRL_SPI_STATUS_WR_ERR_LSB) & HOST_CTRL_SPI_STATUS_WR_ERR_MASK)
-#define HOST_CTRL_SPI_STATUS_READY_MSB 0
-#define HOST_CTRL_SPI_STATUS_READY_LSB 0
-#define HOST_CTRL_SPI_STATUS_READY_MASK 0x00000001
-#define HOST_CTRL_SPI_STATUS_READY_GET(x) (((x) & HOST_CTRL_SPI_STATUS_READY_MASK) >> HOST_CTRL_SPI_STATUS_READY_LSB)
-#define HOST_CTRL_SPI_STATUS_READY_SET(x) (((x) << HOST_CTRL_SPI_STATUS_READY_LSB) & HOST_CTRL_SPI_STATUS_READY_MASK)
-
-#define NON_ASSOC_SLEEP_EN_ADDRESS 0x00000482
-#define NON_ASSOC_SLEEP_EN_OFFSET 0x00000482
-#define NON_ASSOC_SLEEP_EN_BIT_MSB 0
-#define NON_ASSOC_SLEEP_EN_BIT_LSB 0
-#define NON_ASSOC_SLEEP_EN_BIT_MASK 0x00000001
-#define NON_ASSOC_SLEEP_EN_BIT_GET(x) (((x) & NON_ASSOC_SLEEP_EN_BIT_MASK) >> NON_ASSOC_SLEEP_EN_BIT_LSB)
-#define NON_ASSOC_SLEEP_EN_BIT_SET(x) (((x) << NON_ASSOC_SLEEP_EN_BIT_LSB) & NON_ASSOC_SLEEP_EN_BIT_MASK)
-
-#define CPU_DBG_SEL_ADDRESS 0x00000483
-#define CPU_DBG_SEL_OFFSET 0x00000483
-#define CPU_DBG_SEL_BIT_MSB 5
-#define CPU_DBG_SEL_BIT_LSB 0
-#define CPU_DBG_SEL_BIT_MASK 0x0000003f
-#define CPU_DBG_SEL_BIT_GET(x) (((x) & CPU_DBG_SEL_BIT_MASK) >> CPU_DBG_SEL_BIT_LSB)
-#define CPU_DBG_SEL_BIT_SET(x) (((x) << CPU_DBG_SEL_BIT_LSB) & CPU_DBG_SEL_BIT_MASK)
-
-#define CPU_DBG_ADDRESS 0x00000484
-#define CPU_DBG_OFFSET 0x00000484
-#define CPU_DBG_DATA_MSB 7
-#define CPU_DBG_DATA_LSB 0
-#define CPU_DBG_DATA_MASK 0x000000ff
-#define CPU_DBG_DATA_GET(x) (((x) & CPU_DBG_DATA_MASK) >> CPU_DBG_DATA_LSB)
-#define CPU_DBG_DATA_SET(x) (((x) << CPU_DBG_DATA_LSB) & CPU_DBG_DATA_MASK)
-
-#define INT_STATUS2_ENABLE_ADDRESS 0x00000488
-#define INT_STATUS2_ENABLE_OFFSET 0x00000488
-#define INT_STATUS2_ENABLE_GMBOX_RX_UNDERFLOW_MSB 2
-#define INT_STATUS2_ENABLE_GMBOX_RX_UNDERFLOW_LSB 2
-#define INT_STATUS2_ENABLE_GMBOX_RX_UNDERFLOW_MASK 0x00000004
-#define INT_STATUS2_ENABLE_GMBOX_RX_UNDERFLOW_GET(x) (((x) & INT_STATUS2_ENABLE_GMBOX_RX_UNDERFLOW_MASK) >> INT_STATUS2_ENABLE_GMBOX_RX_UNDERFLOW_LSB)
-#define INT_STATUS2_ENABLE_GMBOX_RX_UNDERFLOW_SET(x) (((x) << INT_STATUS2_ENABLE_GMBOX_RX_UNDERFLOW_LSB) & INT_STATUS2_ENABLE_GMBOX_RX_UNDERFLOW_MASK)
-#define INT_STATUS2_ENABLE_GMBOX_TX_OVERFLOW_MSB 1
-#define INT_STATUS2_ENABLE_GMBOX_TX_OVERFLOW_LSB 1
-#define INT_STATUS2_ENABLE_GMBOX_TX_OVERFLOW_MASK 0x00000002
-#define INT_STATUS2_ENABLE_GMBOX_TX_OVERFLOW_GET(x) (((x) & INT_STATUS2_ENABLE_GMBOX_TX_OVERFLOW_MASK) >> INT_STATUS2_ENABLE_GMBOX_TX_OVERFLOW_LSB)
-#define INT_STATUS2_ENABLE_GMBOX_TX_OVERFLOW_SET(x) (((x) << INT_STATUS2_ENABLE_GMBOX_TX_OVERFLOW_LSB) & INT_STATUS2_ENABLE_GMBOX_TX_OVERFLOW_MASK)
-#define INT_STATUS2_ENABLE_GMBOX_DATA_MSB 0
-#define INT_STATUS2_ENABLE_GMBOX_DATA_LSB 0
-#define INT_STATUS2_ENABLE_GMBOX_DATA_MASK 0x00000001
-#define INT_STATUS2_ENABLE_GMBOX_DATA_GET(x) (((x) & INT_STATUS2_ENABLE_GMBOX_DATA_MASK) >> INT_STATUS2_ENABLE_GMBOX_DATA_LSB)
-#define INT_STATUS2_ENABLE_GMBOX_DATA_SET(x) (((x) << INT_STATUS2_ENABLE_GMBOX_DATA_LSB) & INT_STATUS2_ENABLE_GMBOX_DATA_MASK)
-
-#define GMBOX_RX_LOOKAHEAD_ADDRESS 0x00000490
-#define GMBOX_RX_LOOKAHEAD_OFFSET 0x00000490
-#define GMBOX_RX_LOOKAHEAD_DATA_MSB 7
-#define GMBOX_RX_LOOKAHEAD_DATA_LSB 0
-#define GMBOX_RX_LOOKAHEAD_DATA_MASK 0x000000ff
-#define GMBOX_RX_LOOKAHEAD_DATA_GET(x) (((x) & GMBOX_RX_LOOKAHEAD_DATA_MASK) >> GMBOX_RX_LOOKAHEAD_DATA_LSB)
-#define GMBOX_RX_LOOKAHEAD_DATA_SET(x) (((x) << GMBOX_RX_LOOKAHEAD_DATA_LSB) & GMBOX_RX_LOOKAHEAD_DATA_MASK)
-
-#define GMBOX_RX_LOOKAHEAD_MUX_ADDRESS 0x00000498
-#define GMBOX_RX_LOOKAHEAD_MUX_OFFSET 0x00000498
-#define GMBOX_RX_LOOKAHEAD_MUX_SEL_MSB 0
-#define GMBOX_RX_LOOKAHEAD_MUX_SEL_LSB 0
-#define GMBOX_RX_LOOKAHEAD_MUX_SEL_MASK 0x00000001
-#define GMBOX_RX_LOOKAHEAD_MUX_SEL_GET(x) (((x) & GMBOX_RX_LOOKAHEAD_MUX_SEL_MASK) >> GMBOX_RX_LOOKAHEAD_MUX_SEL_LSB)
-#define GMBOX_RX_LOOKAHEAD_MUX_SEL_SET(x) (((x) << GMBOX_RX_LOOKAHEAD_MUX_SEL_LSB) & GMBOX_RX_LOOKAHEAD_MUX_SEL_MASK)
-
-#define CIS_WINDOW_ADDRESS 0x00000600
-#define CIS_WINDOW_OFFSET 0x00000600
-#define CIS_WINDOW_DATA_MSB 7
-#define CIS_WINDOW_DATA_LSB 0
-#define CIS_WINDOW_DATA_MASK 0x000000ff
-#define CIS_WINDOW_DATA_GET(x) (((x) & CIS_WINDOW_DATA_MASK) >> CIS_WINDOW_DATA_LSB)
-#define CIS_WINDOW_DATA_SET(x) (((x) << CIS_WINDOW_DATA_LSB) & CIS_WINDOW_DATA_MASK)
-
-
-#endif /* _MBOX_WLAN_HOST_REG_H_ */
diff --git a/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/mbox_wlan_reg.h b/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/mbox_wlan_reg.h
deleted file mode 100644
index f5167b9ae8d0..000000000000
--- a/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/mbox_wlan_reg.h
+++ /dev/null
@@ -1,589 +0,0 @@
-// ------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-// ------------------------------------------------------------------
-//===================================================================
-// Author(s): ="Atheros"
-//===================================================================
-
-
-#ifndef _MBOX_WLAN_REG_REG_H_
-#define _MBOX_WLAN_REG_REG_H_
-
-#define WLAN_MBOX_FIFO_ADDRESS 0x00000000
-#define WLAN_MBOX_FIFO_OFFSET 0x00000000
-#define WLAN_MBOX_FIFO_DATA_MSB 19
-#define WLAN_MBOX_FIFO_DATA_LSB 0
-#define WLAN_MBOX_FIFO_DATA_MASK 0x000fffff
-#define WLAN_MBOX_FIFO_DATA_GET(x) (((x) & WLAN_MBOX_FIFO_DATA_MASK) >> WLAN_MBOX_FIFO_DATA_LSB)
-#define WLAN_MBOX_FIFO_DATA_SET(x) (((x) << WLAN_MBOX_FIFO_DATA_LSB) & WLAN_MBOX_FIFO_DATA_MASK)
-
-#define WLAN_MBOX_FIFO_STATUS_ADDRESS 0x00000010
-#define WLAN_MBOX_FIFO_STATUS_OFFSET 0x00000010
-#define WLAN_MBOX_FIFO_STATUS_EMPTY_MSB 19
-#define WLAN_MBOX_FIFO_STATUS_EMPTY_LSB 16
-#define WLAN_MBOX_FIFO_STATUS_EMPTY_MASK 0x000f0000
-#define WLAN_MBOX_FIFO_STATUS_EMPTY_GET(x) (((x) & WLAN_MBOX_FIFO_STATUS_EMPTY_MASK) >> WLAN_MBOX_FIFO_STATUS_EMPTY_LSB)
-#define WLAN_MBOX_FIFO_STATUS_EMPTY_SET(x) (((x) << WLAN_MBOX_FIFO_STATUS_EMPTY_LSB) & WLAN_MBOX_FIFO_STATUS_EMPTY_MASK)
-#define WLAN_MBOX_FIFO_STATUS_FULL_MSB 15
-#define WLAN_MBOX_FIFO_STATUS_FULL_LSB 12
-#define WLAN_MBOX_FIFO_STATUS_FULL_MASK 0x0000f000
-#define WLAN_MBOX_FIFO_STATUS_FULL_GET(x) (((x) & WLAN_MBOX_FIFO_STATUS_FULL_MASK) >> WLAN_MBOX_FIFO_STATUS_FULL_LSB)
-#define WLAN_MBOX_FIFO_STATUS_FULL_SET(x) (((x) << WLAN_MBOX_FIFO_STATUS_FULL_LSB) & WLAN_MBOX_FIFO_STATUS_FULL_MASK)
-
-#define WLAN_MBOX_DMA_POLICY_ADDRESS 0x00000014
-#define WLAN_MBOX_DMA_POLICY_OFFSET 0x00000014
-#define WLAN_MBOX_DMA_POLICY_TX_QUANTUM_MSB 3
-#define WLAN_MBOX_DMA_POLICY_TX_QUANTUM_LSB 3
-#define WLAN_MBOX_DMA_POLICY_TX_QUANTUM_MASK 0x00000008
-#define WLAN_MBOX_DMA_POLICY_TX_QUANTUM_GET(x) (((x) & WLAN_MBOX_DMA_POLICY_TX_QUANTUM_MASK) >> WLAN_MBOX_DMA_POLICY_TX_QUANTUM_LSB)
-#define WLAN_MBOX_DMA_POLICY_TX_QUANTUM_SET(x) (((x) << WLAN_MBOX_DMA_POLICY_TX_QUANTUM_LSB) & WLAN_MBOX_DMA_POLICY_TX_QUANTUM_MASK)
-#define WLAN_MBOX_DMA_POLICY_TX_ORDER_MSB 2
-#define WLAN_MBOX_DMA_POLICY_TX_ORDER_LSB 2
-#define WLAN_MBOX_DMA_POLICY_TX_ORDER_MASK 0x00000004
-#define WLAN_MBOX_DMA_POLICY_TX_ORDER_GET(x) (((x) & WLAN_MBOX_DMA_POLICY_TX_ORDER_MASK) >> WLAN_MBOX_DMA_POLICY_TX_ORDER_LSB)
-#define WLAN_MBOX_DMA_POLICY_TX_ORDER_SET(x) (((x) << WLAN_MBOX_DMA_POLICY_TX_ORDER_LSB) & WLAN_MBOX_DMA_POLICY_TX_ORDER_MASK)
-#define WLAN_MBOX_DMA_POLICY_RX_QUANTUM_MSB 1
-#define WLAN_MBOX_DMA_POLICY_RX_QUANTUM_LSB 1
-#define WLAN_MBOX_DMA_POLICY_RX_QUANTUM_MASK 0x00000002
-#define WLAN_MBOX_DMA_POLICY_RX_QUANTUM_GET(x) (((x) & WLAN_MBOX_DMA_POLICY_RX_QUANTUM_MASK) >> WLAN_MBOX_DMA_POLICY_RX_QUANTUM_LSB)
-#define WLAN_MBOX_DMA_POLICY_RX_QUANTUM_SET(x) (((x) << WLAN_MBOX_DMA_POLICY_RX_QUANTUM_LSB) & WLAN_MBOX_DMA_POLICY_RX_QUANTUM_MASK)
-#define WLAN_MBOX_DMA_POLICY_RX_ORDER_MSB 0
-#define WLAN_MBOX_DMA_POLICY_RX_ORDER_LSB 0
-#define WLAN_MBOX_DMA_POLICY_RX_ORDER_MASK 0x00000001
-#define WLAN_MBOX_DMA_POLICY_RX_ORDER_GET(x) (((x) & WLAN_MBOX_DMA_POLICY_RX_ORDER_MASK) >> WLAN_MBOX_DMA_POLICY_RX_ORDER_LSB)
-#define WLAN_MBOX_DMA_POLICY_RX_ORDER_SET(x) (((x) << WLAN_MBOX_DMA_POLICY_RX_ORDER_LSB) & WLAN_MBOX_DMA_POLICY_RX_ORDER_MASK)
-
-#define WLAN_MBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS 0x00000018
-#define WLAN_MBOX0_DMA_RX_DESCRIPTOR_BASE_OFFSET 0x00000018
-#define WLAN_MBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MSB 27
-#define WLAN_MBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB 2
-#define WLAN_MBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK 0x0ffffffc
-#define WLAN_MBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_GET(x) (((x) & WLAN_MBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK) >> WLAN_MBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB)
-#define WLAN_MBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_SET(x) (((x) << WLAN_MBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB) & WLAN_MBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK)
-
-#define WLAN_MBOX0_DMA_RX_CONTROL_ADDRESS 0x0000001c
-#define WLAN_MBOX0_DMA_RX_CONTROL_OFFSET 0x0000001c
-#define WLAN_MBOX0_DMA_RX_CONTROL_RESUME_MSB 2
-#define WLAN_MBOX0_DMA_RX_CONTROL_RESUME_LSB 2
-#define WLAN_MBOX0_DMA_RX_CONTROL_RESUME_MASK 0x00000004
-#define WLAN_MBOX0_DMA_RX_CONTROL_RESUME_GET(x) (((x) & WLAN_MBOX0_DMA_RX_CONTROL_RESUME_MASK) >> WLAN_MBOX0_DMA_RX_CONTROL_RESUME_LSB)
-#define WLAN_MBOX0_DMA_RX_CONTROL_RESUME_SET(x) (((x) << WLAN_MBOX0_DMA_RX_CONTROL_RESUME_LSB) & WLAN_MBOX0_DMA_RX_CONTROL_RESUME_MASK)
-#define WLAN_MBOX0_DMA_RX_CONTROL_START_MSB 1
-#define WLAN_MBOX0_DMA_RX_CONTROL_START_LSB 1
-#define WLAN_MBOX0_DMA_RX_CONTROL_START_MASK 0x00000002
-#define WLAN_MBOX0_DMA_RX_CONTROL_START_GET(x) (((x) & WLAN_MBOX0_DMA_RX_CONTROL_START_MASK) >> WLAN_MBOX0_DMA_RX_CONTROL_START_LSB)
-#define WLAN_MBOX0_DMA_RX_CONTROL_START_SET(x) (((x) << WLAN_MBOX0_DMA_RX_CONTROL_START_LSB) & WLAN_MBOX0_DMA_RX_CONTROL_START_MASK)
-#define WLAN_MBOX0_DMA_RX_CONTROL_STOP_MSB 0
-#define WLAN_MBOX0_DMA_RX_CONTROL_STOP_LSB 0
-#define WLAN_MBOX0_DMA_RX_CONTROL_STOP_MASK 0x00000001
-#define WLAN_MBOX0_DMA_RX_CONTROL_STOP_GET(x) (((x) & WLAN_MBOX0_DMA_RX_CONTROL_STOP_MASK) >> WLAN_MBOX0_DMA_RX_CONTROL_STOP_LSB)
-#define WLAN_MBOX0_DMA_RX_CONTROL_STOP_SET(x) (((x) << WLAN_MBOX0_DMA_RX_CONTROL_STOP_LSB) & WLAN_MBOX0_DMA_RX_CONTROL_STOP_MASK)
-
-#define WLAN_MBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS 0x00000020
-#define WLAN_MBOX0_DMA_TX_DESCRIPTOR_BASE_OFFSET 0x00000020
-#define WLAN_MBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MSB 27
-#define WLAN_MBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB 2
-#define WLAN_MBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK 0x0ffffffc
-#define WLAN_MBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_GET(x) (((x) & WLAN_MBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK) >> WLAN_MBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB)
-#define WLAN_MBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_SET(x) (((x) << WLAN_MBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB) & WLAN_MBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK)
-
-#define WLAN_MBOX0_DMA_TX_CONTROL_ADDRESS 0x00000024
-#define WLAN_MBOX0_DMA_TX_CONTROL_OFFSET 0x00000024
-#define WLAN_MBOX0_DMA_TX_CONTROL_RESUME_MSB 2
-#define WLAN_MBOX0_DMA_TX_CONTROL_RESUME_LSB 2
-#define WLAN_MBOX0_DMA_TX_CONTROL_RESUME_MASK 0x00000004
-#define WLAN_MBOX0_DMA_TX_CONTROL_RESUME_GET(x) (((x) & WLAN_MBOX0_DMA_TX_CONTROL_RESUME_MASK) >> WLAN_MBOX0_DMA_TX_CONTROL_RESUME_LSB)
-#define WLAN_MBOX0_DMA_TX_CONTROL_RESUME_SET(x) (((x) << WLAN_MBOX0_DMA_TX_CONTROL_RESUME_LSB) & WLAN_MBOX0_DMA_TX_CONTROL_RESUME_MASK)
-#define WLAN_MBOX0_DMA_TX_CONTROL_START_MSB 1
-#define WLAN_MBOX0_DMA_TX_CONTROL_START_LSB 1
-#define WLAN_MBOX0_DMA_TX_CONTROL_START_MASK 0x00000002
-#define WLAN_MBOX0_DMA_TX_CONTROL_START_GET(x) (((x) & WLAN_MBOX0_DMA_TX_CONTROL_START_MASK) >> WLAN_MBOX0_DMA_TX_CONTROL_START_LSB)
-#define WLAN_MBOX0_DMA_TX_CONTROL_START_SET(x) (((x) << WLAN_MBOX0_DMA_TX_CONTROL_START_LSB) & WLAN_MBOX0_DMA_TX_CONTROL_START_MASK)
-#define WLAN_MBOX0_DMA_TX_CONTROL_STOP_MSB 0
-#define WLAN_MBOX0_DMA_TX_CONTROL_STOP_LSB 0
-#define WLAN_MBOX0_DMA_TX_CONTROL_STOP_MASK 0x00000001
-#define WLAN_MBOX0_DMA_TX_CONTROL_STOP_GET(x) (((x) & WLAN_MBOX0_DMA_TX_CONTROL_STOP_MASK) >> WLAN_MBOX0_DMA_TX_CONTROL_STOP_LSB)
-#define WLAN_MBOX0_DMA_TX_CONTROL_STOP_SET(x) (((x) << WLAN_MBOX0_DMA_TX_CONTROL_STOP_LSB) & WLAN_MBOX0_DMA_TX_CONTROL_STOP_MASK)
-
-#define WLAN_MBOX1_DMA_RX_DESCRIPTOR_BASE_ADDRESS 0x00000028
-#define WLAN_MBOX1_DMA_RX_DESCRIPTOR_BASE_OFFSET 0x00000028
-#define WLAN_MBOX1_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MSB 27
-#define WLAN_MBOX1_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB 2
-#define WLAN_MBOX1_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK 0x0ffffffc
-#define WLAN_MBOX1_DMA_RX_DESCRIPTOR_BASE_ADDRESS_GET(x) (((x) & WLAN_MBOX1_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK) >> WLAN_MBOX1_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB)
-#define WLAN_MBOX1_DMA_RX_DESCRIPTOR_BASE_ADDRESS_SET(x) (((x) << WLAN_MBOX1_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB) & WLAN_MBOX1_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK)
-
-#define WLAN_MBOX1_DMA_RX_CONTROL_ADDRESS 0x0000002c
-#define WLAN_MBOX1_DMA_RX_CONTROL_OFFSET 0x0000002c
-#define WLAN_MBOX1_DMA_RX_CONTROL_RESUME_MSB 2
-#define WLAN_MBOX1_DMA_RX_CONTROL_RESUME_LSB 2
-#define WLAN_MBOX1_DMA_RX_CONTROL_RESUME_MASK 0x00000004
-#define WLAN_MBOX1_DMA_RX_CONTROL_RESUME_GET(x) (((x) & WLAN_MBOX1_DMA_RX_CONTROL_RESUME_MASK) >> WLAN_MBOX1_DMA_RX_CONTROL_RESUME_LSB)
-#define WLAN_MBOX1_DMA_RX_CONTROL_RESUME_SET(x) (((x) << WLAN_MBOX1_DMA_RX_CONTROL_RESUME_LSB) & WLAN_MBOX1_DMA_RX_CONTROL_RESUME_MASK)
-#define WLAN_MBOX1_DMA_RX_CONTROL_START_MSB 1
-#define WLAN_MBOX1_DMA_RX_CONTROL_START_LSB 1
-#define WLAN_MBOX1_DMA_RX_CONTROL_START_MASK 0x00000002
-#define WLAN_MBOX1_DMA_RX_CONTROL_START_GET(x) (((x) & WLAN_MBOX1_DMA_RX_CONTROL_START_MASK) >> WLAN_MBOX1_DMA_RX_CONTROL_START_LSB)
-#define WLAN_MBOX1_DMA_RX_CONTROL_START_SET(x) (((x) << WLAN_MBOX1_DMA_RX_CONTROL_START_LSB) & WLAN_MBOX1_DMA_RX_CONTROL_START_MASK)
-#define WLAN_MBOX1_DMA_RX_CONTROL_STOP_MSB 0
-#define WLAN_MBOX1_DMA_RX_CONTROL_STOP_LSB 0
-#define WLAN_MBOX1_DMA_RX_CONTROL_STOP_MASK 0x00000001
-#define WLAN_MBOX1_DMA_RX_CONTROL_STOP_GET(x) (((x) & WLAN_MBOX1_DMA_RX_CONTROL_STOP_MASK) >> WLAN_MBOX1_DMA_RX_CONTROL_STOP_LSB)
-#define WLAN_MBOX1_DMA_RX_CONTROL_STOP_SET(x) (((x) << WLAN_MBOX1_DMA_RX_CONTROL_STOP_LSB) & WLAN_MBOX1_DMA_RX_CONTROL_STOP_MASK)
-
-#define WLAN_MBOX1_DMA_TX_DESCRIPTOR_BASE_ADDRESS 0x00000030
-#define WLAN_MBOX1_DMA_TX_DESCRIPTOR_BASE_OFFSET 0x00000030
-#define WLAN_MBOX1_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MSB 27
-#define WLAN_MBOX1_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB 2
-#define WLAN_MBOX1_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK 0x0ffffffc
-#define WLAN_MBOX1_DMA_TX_DESCRIPTOR_BASE_ADDRESS_GET(x) (((x) & WLAN_MBOX1_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK) >> WLAN_MBOX1_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB)
-#define WLAN_MBOX1_DMA_TX_DESCRIPTOR_BASE_ADDRESS_SET(x) (((x) << WLAN_MBOX1_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB) & WLAN_MBOX1_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK)
-
-#define WLAN_MBOX1_DMA_TX_CONTROL_ADDRESS 0x00000034
-#define WLAN_MBOX1_DMA_TX_CONTROL_OFFSET 0x00000034
-#define WLAN_MBOX1_DMA_TX_CONTROL_RESUME_MSB 2
-#define WLAN_MBOX1_DMA_TX_CONTROL_RESUME_LSB 2
-#define WLAN_MBOX1_DMA_TX_CONTROL_RESUME_MASK 0x00000004
-#define WLAN_MBOX1_DMA_TX_CONTROL_RESUME_GET(x) (((x) & WLAN_MBOX1_DMA_TX_CONTROL_RESUME_MASK) >> WLAN_MBOX1_DMA_TX_CONTROL_RESUME_LSB)
-#define WLAN_MBOX1_DMA_TX_CONTROL_RESUME_SET(x) (((x) << WLAN_MBOX1_DMA_TX_CONTROL_RESUME_LSB) & WLAN_MBOX1_DMA_TX_CONTROL_RESUME_MASK)
-#define WLAN_MBOX1_DMA_TX_CONTROL_START_MSB 1
-#define WLAN_MBOX1_DMA_TX_CONTROL_START_LSB 1
-#define WLAN_MBOX1_DMA_TX_CONTROL_START_MASK 0x00000002
-#define WLAN_MBOX1_DMA_TX_CONTROL_START_GET(x) (((x) & WLAN_MBOX1_DMA_TX_CONTROL_START_MASK) >> WLAN_MBOX1_DMA_TX_CONTROL_START_LSB)
-#define WLAN_MBOX1_DMA_TX_CONTROL_START_SET(x) (((x) << WLAN_MBOX1_DMA_TX_CONTROL_START_LSB) & WLAN_MBOX1_DMA_TX_CONTROL_START_MASK)
-#define WLAN_MBOX1_DMA_TX_CONTROL_STOP_MSB 0
-#define WLAN_MBOX1_DMA_TX_CONTROL_STOP_LSB 0
-#define WLAN_MBOX1_DMA_TX_CONTROL_STOP_MASK 0x00000001
-#define WLAN_MBOX1_DMA_TX_CONTROL_STOP_GET(x) (((x) & WLAN_MBOX1_DMA_TX_CONTROL_STOP_MASK) >> WLAN_MBOX1_DMA_TX_CONTROL_STOP_LSB)
-#define WLAN_MBOX1_DMA_TX_CONTROL_STOP_SET(x) (((x) << WLAN_MBOX1_DMA_TX_CONTROL_STOP_LSB) & WLAN_MBOX1_DMA_TX_CONTROL_STOP_MASK)
-
-#define WLAN_MBOX2_DMA_RX_DESCRIPTOR_BASE_ADDRESS 0x00000038
-#define WLAN_MBOX2_DMA_RX_DESCRIPTOR_BASE_OFFSET 0x00000038
-#define WLAN_MBOX2_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MSB 27
-#define WLAN_MBOX2_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB 2
-#define WLAN_MBOX2_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK 0x0ffffffc
-#define WLAN_MBOX2_DMA_RX_DESCRIPTOR_BASE_ADDRESS_GET(x) (((x) & WLAN_MBOX2_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK) >> WLAN_MBOX2_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB)
-#define WLAN_MBOX2_DMA_RX_DESCRIPTOR_BASE_ADDRESS_SET(x) (((x) << WLAN_MBOX2_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB) & WLAN_MBOX2_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK)
-
-#define WLAN_MBOX2_DMA_RX_CONTROL_ADDRESS 0x0000003c
-#define WLAN_MBOX2_DMA_RX_CONTROL_OFFSET 0x0000003c
-#define WLAN_MBOX2_DMA_RX_CONTROL_RESUME_MSB 2
-#define WLAN_MBOX2_DMA_RX_CONTROL_RESUME_LSB 2
-#define WLAN_MBOX2_DMA_RX_CONTROL_RESUME_MASK 0x00000004
-#define WLAN_MBOX2_DMA_RX_CONTROL_RESUME_GET(x) (((x) & WLAN_MBOX2_DMA_RX_CONTROL_RESUME_MASK) >> WLAN_MBOX2_DMA_RX_CONTROL_RESUME_LSB)
-#define WLAN_MBOX2_DMA_RX_CONTROL_RESUME_SET(x) (((x) << WLAN_MBOX2_DMA_RX_CONTROL_RESUME_LSB) & WLAN_MBOX2_DMA_RX_CONTROL_RESUME_MASK)
-#define WLAN_MBOX2_DMA_RX_CONTROL_START_MSB 1
-#define WLAN_MBOX2_DMA_RX_CONTROL_START_LSB 1
-#define WLAN_MBOX2_DMA_RX_CONTROL_START_MASK 0x00000002
-#define WLAN_MBOX2_DMA_RX_CONTROL_START_GET(x) (((x) & WLAN_MBOX2_DMA_RX_CONTROL_START_MASK) >> WLAN_MBOX2_DMA_RX_CONTROL_START_LSB)
-#define WLAN_MBOX2_DMA_RX_CONTROL_START_SET(x) (((x) << WLAN_MBOX2_DMA_RX_CONTROL_START_LSB) & WLAN_MBOX2_DMA_RX_CONTROL_START_MASK)
-#define WLAN_MBOX2_DMA_RX_CONTROL_STOP_MSB 0
-#define WLAN_MBOX2_DMA_RX_CONTROL_STOP_LSB 0
-#define WLAN_MBOX2_DMA_RX_CONTROL_STOP_MASK 0x00000001
-#define WLAN_MBOX2_DMA_RX_CONTROL_STOP_GET(x) (((x) & WLAN_MBOX2_DMA_RX_CONTROL_STOP_MASK) >> WLAN_MBOX2_DMA_RX_CONTROL_STOP_LSB)
-#define WLAN_MBOX2_DMA_RX_CONTROL_STOP_SET(x) (((x) << WLAN_MBOX2_DMA_RX_CONTROL_STOP_LSB) & WLAN_MBOX2_DMA_RX_CONTROL_STOP_MASK)
-
-#define WLAN_MBOX2_DMA_TX_DESCRIPTOR_BASE_ADDRESS 0x00000040
-#define WLAN_MBOX2_DMA_TX_DESCRIPTOR_BASE_OFFSET 0x00000040
-#define WLAN_MBOX2_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MSB 27
-#define WLAN_MBOX2_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB 2
-#define WLAN_MBOX2_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK 0x0ffffffc
-#define WLAN_MBOX2_DMA_TX_DESCRIPTOR_BASE_ADDRESS_GET(x) (((x) & WLAN_MBOX2_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK) >> WLAN_MBOX2_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB)
-#define WLAN_MBOX2_DMA_TX_DESCRIPTOR_BASE_ADDRESS_SET(x) (((x) << WLAN_MBOX2_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB) & WLAN_MBOX2_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK)
-
-#define WLAN_MBOX2_DMA_TX_CONTROL_ADDRESS 0x00000044
-#define WLAN_MBOX2_DMA_TX_CONTROL_OFFSET 0x00000044
-#define WLAN_MBOX2_DMA_TX_CONTROL_RESUME_MSB 2
-#define WLAN_MBOX2_DMA_TX_CONTROL_RESUME_LSB 2
-#define WLAN_MBOX2_DMA_TX_CONTROL_RESUME_MASK 0x00000004
-#define WLAN_MBOX2_DMA_TX_CONTROL_RESUME_GET(x) (((x) & WLAN_MBOX2_DMA_TX_CONTROL_RESUME_MASK) >> WLAN_MBOX2_DMA_TX_CONTROL_RESUME_LSB)
-#define WLAN_MBOX2_DMA_TX_CONTROL_RESUME_SET(x) (((x) << WLAN_MBOX2_DMA_TX_CONTROL_RESUME_LSB) & WLAN_MBOX2_DMA_TX_CONTROL_RESUME_MASK)
-#define WLAN_MBOX2_DMA_TX_CONTROL_START_MSB 1
-#define WLAN_MBOX2_DMA_TX_CONTROL_START_LSB 1
-#define WLAN_MBOX2_DMA_TX_CONTROL_START_MASK 0x00000002
-#define WLAN_MBOX2_DMA_TX_CONTROL_START_GET(x) (((x) & WLAN_MBOX2_DMA_TX_CONTROL_START_MASK) >> WLAN_MBOX2_DMA_TX_CONTROL_START_LSB)
-#define WLAN_MBOX2_DMA_TX_CONTROL_START_SET(x) (((x) << WLAN_MBOX2_DMA_TX_CONTROL_START_LSB) & WLAN_MBOX2_DMA_TX_CONTROL_START_MASK)
-#define WLAN_MBOX2_DMA_TX_CONTROL_STOP_MSB 0
-#define WLAN_MBOX2_DMA_TX_CONTROL_STOP_LSB 0
-#define WLAN_MBOX2_DMA_TX_CONTROL_STOP_MASK 0x00000001
-#define WLAN_MBOX2_DMA_TX_CONTROL_STOP_GET(x) (((x) & WLAN_MBOX2_DMA_TX_CONTROL_STOP_MASK) >> WLAN_MBOX2_DMA_TX_CONTROL_STOP_LSB)
-#define WLAN_MBOX2_DMA_TX_CONTROL_STOP_SET(x) (((x) << WLAN_MBOX2_DMA_TX_CONTROL_STOP_LSB) & WLAN_MBOX2_DMA_TX_CONTROL_STOP_MASK)
-
-#define WLAN_MBOX3_DMA_RX_DESCRIPTOR_BASE_ADDRESS 0x00000048
-#define WLAN_MBOX3_DMA_RX_DESCRIPTOR_BASE_OFFSET 0x00000048
-#define WLAN_MBOX3_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MSB 27
-#define WLAN_MBOX3_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB 2
-#define WLAN_MBOX3_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK 0x0ffffffc
-#define WLAN_MBOX3_DMA_RX_DESCRIPTOR_BASE_ADDRESS_GET(x) (((x) & WLAN_MBOX3_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK) >> WLAN_MBOX3_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB)
-#define WLAN_MBOX3_DMA_RX_DESCRIPTOR_BASE_ADDRESS_SET(x) (((x) << WLAN_MBOX3_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB) & WLAN_MBOX3_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK)
-
-#define WLAN_MBOX3_DMA_RX_CONTROL_ADDRESS 0x0000004c
-#define WLAN_MBOX3_DMA_RX_CONTROL_OFFSET 0x0000004c
-#define WLAN_MBOX3_DMA_RX_CONTROL_RESUME_MSB 2
-#define WLAN_MBOX3_DMA_RX_CONTROL_RESUME_LSB 2
-#define WLAN_MBOX3_DMA_RX_CONTROL_RESUME_MASK 0x00000004
-#define WLAN_MBOX3_DMA_RX_CONTROL_RESUME_GET(x) (((x) & WLAN_MBOX3_DMA_RX_CONTROL_RESUME_MASK) >> WLAN_MBOX3_DMA_RX_CONTROL_RESUME_LSB)
-#define WLAN_MBOX3_DMA_RX_CONTROL_RESUME_SET(x) (((x) << WLAN_MBOX3_DMA_RX_CONTROL_RESUME_LSB) & WLAN_MBOX3_DMA_RX_CONTROL_RESUME_MASK)
-#define WLAN_MBOX3_DMA_RX_CONTROL_START_MSB 1
-#define WLAN_MBOX3_DMA_RX_CONTROL_START_LSB 1
-#define WLAN_MBOX3_DMA_RX_CONTROL_START_MASK 0x00000002
-#define WLAN_MBOX3_DMA_RX_CONTROL_START_GET(x) (((x) & WLAN_MBOX3_DMA_RX_CONTROL_START_MASK) >> WLAN_MBOX3_DMA_RX_CONTROL_START_LSB)
-#define WLAN_MBOX3_DMA_RX_CONTROL_START_SET(x) (((x) << WLAN_MBOX3_DMA_RX_CONTROL_START_LSB) & WLAN_MBOX3_DMA_RX_CONTROL_START_MASK)
-#define WLAN_MBOX3_DMA_RX_CONTROL_STOP_MSB 0
-#define WLAN_MBOX3_DMA_RX_CONTROL_STOP_LSB 0
-#define WLAN_MBOX3_DMA_RX_CONTROL_STOP_MASK 0x00000001
-#define WLAN_MBOX3_DMA_RX_CONTROL_STOP_GET(x) (((x) & WLAN_MBOX3_DMA_RX_CONTROL_STOP_MASK) >> WLAN_MBOX3_DMA_RX_CONTROL_STOP_LSB)
-#define WLAN_MBOX3_DMA_RX_CONTROL_STOP_SET(x) (((x) << WLAN_MBOX3_DMA_RX_CONTROL_STOP_LSB) & WLAN_MBOX3_DMA_RX_CONTROL_STOP_MASK)
-
-#define WLAN_MBOX3_DMA_TX_DESCRIPTOR_BASE_ADDRESS 0x00000050
-#define WLAN_MBOX3_DMA_TX_DESCRIPTOR_BASE_OFFSET 0x00000050
-#define WLAN_MBOX3_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MSB 27
-#define WLAN_MBOX3_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB 2
-#define WLAN_MBOX3_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK 0x0ffffffc
-#define WLAN_MBOX3_DMA_TX_DESCRIPTOR_BASE_ADDRESS_GET(x) (((x) & WLAN_MBOX3_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK) >> WLAN_MBOX3_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB)
-#define WLAN_MBOX3_DMA_TX_DESCRIPTOR_BASE_ADDRESS_SET(x) (((x) << WLAN_MBOX3_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB) & WLAN_MBOX3_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK)
-
-#define WLAN_MBOX3_DMA_TX_CONTROL_ADDRESS 0x00000054
-#define WLAN_MBOX3_DMA_TX_CONTROL_OFFSET 0x00000054
-#define WLAN_MBOX3_DMA_TX_CONTROL_RESUME_MSB 2
-#define WLAN_MBOX3_DMA_TX_CONTROL_RESUME_LSB 2
-#define WLAN_MBOX3_DMA_TX_CONTROL_RESUME_MASK 0x00000004
-#define WLAN_MBOX3_DMA_TX_CONTROL_RESUME_GET(x) (((x) & WLAN_MBOX3_DMA_TX_CONTROL_RESUME_MASK) >> WLAN_MBOX3_DMA_TX_CONTROL_RESUME_LSB)
-#define WLAN_MBOX3_DMA_TX_CONTROL_RESUME_SET(x) (((x) << WLAN_MBOX3_DMA_TX_CONTROL_RESUME_LSB) & WLAN_MBOX3_DMA_TX_CONTROL_RESUME_MASK)
-#define WLAN_MBOX3_DMA_TX_CONTROL_START_MSB 1
-#define WLAN_MBOX3_DMA_TX_CONTROL_START_LSB 1
-#define WLAN_MBOX3_DMA_TX_CONTROL_START_MASK 0x00000002
-#define WLAN_MBOX3_DMA_TX_CONTROL_START_GET(x) (((x) & WLAN_MBOX3_DMA_TX_CONTROL_START_MASK) >> WLAN_MBOX3_DMA_TX_CONTROL_START_LSB)
-#define WLAN_MBOX3_DMA_TX_CONTROL_START_SET(x) (((x) << WLAN_MBOX3_DMA_TX_CONTROL_START_LSB) & WLAN_MBOX3_DMA_TX_CONTROL_START_MASK)
-#define WLAN_MBOX3_DMA_TX_CONTROL_STOP_MSB 0
-#define WLAN_MBOX3_DMA_TX_CONTROL_STOP_LSB 0
-#define WLAN_MBOX3_DMA_TX_CONTROL_STOP_MASK 0x00000001
-#define WLAN_MBOX3_DMA_TX_CONTROL_STOP_GET(x) (((x) & WLAN_MBOX3_DMA_TX_CONTROL_STOP_MASK) >> WLAN_MBOX3_DMA_TX_CONTROL_STOP_LSB)
-#define WLAN_MBOX3_DMA_TX_CONTROL_STOP_SET(x) (((x) << WLAN_MBOX3_DMA_TX_CONTROL_STOP_LSB) & WLAN_MBOX3_DMA_TX_CONTROL_STOP_MASK)
-
-#define WLAN_MBOX_INT_STATUS_ADDRESS 0x00000058
-#define WLAN_MBOX_INT_STATUS_OFFSET 0x00000058
-#define WLAN_MBOX_INT_STATUS_RX_DMA_COMPLETE_MSB 31
-#define WLAN_MBOX_INT_STATUS_RX_DMA_COMPLETE_LSB 28
-#define WLAN_MBOX_INT_STATUS_RX_DMA_COMPLETE_MASK 0xf0000000
-#define WLAN_MBOX_INT_STATUS_RX_DMA_COMPLETE_GET(x) (((x) & WLAN_MBOX_INT_STATUS_RX_DMA_COMPLETE_MASK) >> WLAN_MBOX_INT_STATUS_RX_DMA_COMPLETE_LSB)
-#define WLAN_MBOX_INT_STATUS_RX_DMA_COMPLETE_SET(x) (((x) << WLAN_MBOX_INT_STATUS_RX_DMA_COMPLETE_LSB) & WLAN_MBOX_INT_STATUS_RX_DMA_COMPLETE_MASK)
-#define WLAN_MBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_MSB 27
-#define WLAN_MBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_LSB 24
-#define WLAN_MBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_MASK 0x0f000000
-#define WLAN_MBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_GET(x) (((x) & WLAN_MBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_MASK) >> WLAN_MBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_LSB)
-#define WLAN_MBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_SET(x) (((x) << WLAN_MBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_LSB) & WLAN_MBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_MASK)
-#define WLAN_MBOX_INT_STATUS_TX_DMA_COMPLETE_MSB 23
-#define WLAN_MBOX_INT_STATUS_TX_DMA_COMPLETE_LSB 20
-#define WLAN_MBOX_INT_STATUS_TX_DMA_COMPLETE_MASK 0x00f00000
-#define WLAN_MBOX_INT_STATUS_TX_DMA_COMPLETE_GET(x) (((x) & WLAN_MBOX_INT_STATUS_TX_DMA_COMPLETE_MASK) >> WLAN_MBOX_INT_STATUS_TX_DMA_COMPLETE_LSB)
-#define WLAN_MBOX_INT_STATUS_TX_DMA_COMPLETE_SET(x) (((x) << WLAN_MBOX_INT_STATUS_TX_DMA_COMPLETE_LSB) & WLAN_MBOX_INT_STATUS_TX_DMA_COMPLETE_MASK)
-#define WLAN_MBOX_INT_STATUS_TX_OVERFLOW_MSB 17
-#define WLAN_MBOX_INT_STATUS_TX_OVERFLOW_LSB 17
-#define WLAN_MBOX_INT_STATUS_TX_OVERFLOW_MASK 0x00020000
-#define WLAN_MBOX_INT_STATUS_TX_OVERFLOW_GET(x) (((x) & WLAN_MBOX_INT_STATUS_TX_OVERFLOW_MASK) >> WLAN_MBOX_INT_STATUS_TX_OVERFLOW_LSB)
-#define WLAN_MBOX_INT_STATUS_TX_OVERFLOW_SET(x) (((x) << WLAN_MBOX_INT_STATUS_TX_OVERFLOW_LSB) & WLAN_MBOX_INT_STATUS_TX_OVERFLOW_MASK)
-#define WLAN_MBOX_INT_STATUS_RX_UNDERFLOW_MSB 16
-#define WLAN_MBOX_INT_STATUS_RX_UNDERFLOW_LSB 16
-#define WLAN_MBOX_INT_STATUS_RX_UNDERFLOW_MASK 0x00010000
-#define WLAN_MBOX_INT_STATUS_RX_UNDERFLOW_GET(x) (((x) & WLAN_MBOX_INT_STATUS_RX_UNDERFLOW_MASK) >> WLAN_MBOX_INT_STATUS_RX_UNDERFLOW_LSB)
-#define WLAN_MBOX_INT_STATUS_RX_UNDERFLOW_SET(x) (((x) << WLAN_MBOX_INT_STATUS_RX_UNDERFLOW_LSB) & WLAN_MBOX_INT_STATUS_RX_UNDERFLOW_MASK)
-#define WLAN_MBOX_INT_STATUS_TX_NOT_EMPTY_MSB 15
-#define WLAN_MBOX_INT_STATUS_TX_NOT_EMPTY_LSB 12
-#define WLAN_MBOX_INT_STATUS_TX_NOT_EMPTY_MASK 0x0000f000
-#define WLAN_MBOX_INT_STATUS_TX_NOT_EMPTY_GET(x) (((x) & WLAN_MBOX_INT_STATUS_TX_NOT_EMPTY_MASK) >> WLAN_MBOX_INT_STATUS_TX_NOT_EMPTY_LSB)
-#define WLAN_MBOX_INT_STATUS_TX_NOT_EMPTY_SET(x) (((x) << WLAN_MBOX_INT_STATUS_TX_NOT_EMPTY_LSB) & WLAN_MBOX_INT_STATUS_TX_NOT_EMPTY_MASK)
-#define WLAN_MBOX_INT_STATUS_RX_NOT_FULL_MSB 11
-#define WLAN_MBOX_INT_STATUS_RX_NOT_FULL_LSB 8
-#define WLAN_MBOX_INT_STATUS_RX_NOT_FULL_MASK 0x00000f00
-#define WLAN_MBOX_INT_STATUS_RX_NOT_FULL_GET(x) (((x) & WLAN_MBOX_INT_STATUS_RX_NOT_FULL_MASK) >> WLAN_MBOX_INT_STATUS_RX_NOT_FULL_LSB)
-#define WLAN_MBOX_INT_STATUS_RX_NOT_FULL_SET(x) (((x) << WLAN_MBOX_INT_STATUS_RX_NOT_FULL_LSB) & WLAN_MBOX_INT_STATUS_RX_NOT_FULL_MASK)
-#define WLAN_MBOX_INT_STATUS_HOST_MSB 7
-#define WLAN_MBOX_INT_STATUS_HOST_LSB 0
-#define WLAN_MBOX_INT_STATUS_HOST_MASK 0x000000ff
-#define WLAN_MBOX_INT_STATUS_HOST_GET(x) (((x) & WLAN_MBOX_INT_STATUS_HOST_MASK) >> WLAN_MBOX_INT_STATUS_HOST_LSB)
-#define WLAN_MBOX_INT_STATUS_HOST_SET(x) (((x) << WLAN_MBOX_INT_STATUS_HOST_LSB) & WLAN_MBOX_INT_STATUS_HOST_MASK)
-
-#define WLAN_MBOX_INT_ENABLE_ADDRESS 0x0000005c
-#define WLAN_MBOX_INT_ENABLE_OFFSET 0x0000005c
-#define WLAN_MBOX_INT_ENABLE_RX_DMA_COMPLETE_MSB 31
-#define WLAN_MBOX_INT_ENABLE_RX_DMA_COMPLETE_LSB 28
-#define WLAN_MBOX_INT_ENABLE_RX_DMA_COMPLETE_MASK 0xf0000000
-#define WLAN_MBOX_INT_ENABLE_RX_DMA_COMPLETE_GET(x) (((x) & WLAN_MBOX_INT_ENABLE_RX_DMA_COMPLETE_MASK) >> WLAN_MBOX_INT_ENABLE_RX_DMA_COMPLETE_LSB)
-#define WLAN_MBOX_INT_ENABLE_RX_DMA_COMPLETE_SET(x) (((x) << WLAN_MBOX_INT_ENABLE_RX_DMA_COMPLETE_LSB) & WLAN_MBOX_INT_ENABLE_RX_DMA_COMPLETE_MASK)
-#define WLAN_MBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_MSB 27
-#define WLAN_MBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_LSB 24
-#define WLAN_MBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_MASK 0x0f000000
-#define WLAN_MBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_GET(x) (((x) & WLAN_MBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_MASK) >> WLAN_MBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_LSB)
-#define WLAN_MBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_SET(x) (((x) << WLAN_MBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_LSB) & WLAN_MBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_MASK)
-#define WLAN_MBOX_INT_ENABLE_TX_DMA_COMPLETE_MSB 23
-#define WLAN_MBOX_INT_ENABLE_TX_DMA_COMPLETE_LSB 20
-#define WLAN_MBOX_INT_ENABLE_TX_DMA_COMPLETE_MASK 0x00f00000
-#define WLAN_MBOX_INT_ENABLE_TX_DMA_COMPLETE_GET(x) (((x) & WLAN_MBOX_INT_ENABLE_TX_DMA_COMPLETE_MASK) >> WLAN_MBOX_INT_ENABLE_TX_DMA_COMPLETE_LSB)
-#define WLAN_MBOX_INT_ENABLE_TX_DMA_COMPLETE_SET(x) (((x) << WLAN_MBOX_INT_ENABLE_TX_DMA_COMPLETE_LSB) & WLAN_MBOX_INT_ENABLE_TX_DMA_COMPLETE_MASK)
-#define WLAN_MBOX_INT_ENABLE_TX_OVERFLOW_MSB 17
-#define WLAN_MBOX_INT_ENABLE_TX_OVERFLOW_LSB 17
-#define WLAN_MBOX_INT_ENABLE_TX_OVERFLOW_MASK 0x00020000
-#define WLAN_MBOX_INT_ENABLE_TX_OVERFLOW_GET(x) (((x) & WLAN_MBOX_INT_ENABLE_TX_OVERFLOW_MASK) >> WLAN_MBOX_INT_ENABLE_TX_OVERFLOW_LSB)
-#define WLAN_MBOX_INT_ENABLE_TX_OVERFLOW_SET(x) (((x) << WLAN_MBOX_INT_ENABLE_TX_OVERFLOW_LSB) & WLAN_MBOX_INT_ENABLE_TX_OVERFLOW_MASK)
-#define WLAN_MBOX_INT_ENABLE_RX_UNDERFLOW_MSB 16
-#define WLAN_MBOX_INT_ENABLE_RX_UNDERFLOW_LSB 16
-#define WLAN_MBOX_INT_ENABLE_RX_UNDERFLOW_MASK 0x00010000
-#define WLAN_MBOX_INT_ENABLE_RX_UNDERFLOW_GET(x) (((x) & WLAN_MBOX_INT_ENABLE_RX_UNDERFLOW_MASK) >> WLAN_MBOX_INT_ENABLE_RX_UNDERFLOW_LSB)
-#define WLAN_MBOX_INT_ENABLE_RX_UNDERFLOW_SET(x) (((x) << WLAN_MBOX_INT_ENABLE_RX_UNDERFLOW_LSB) & WLAN_MBOX_INT_ENABLE_RX_UNDERFLOW_MASK)
-#define WLAN_MBOX_INT_ENABLE_TX_NOT_EMPTY_MSB 15
-#define WLAN_MBOX_INT_ENABLE_TX_NOT_EMPTY_LSB 12
-#define WLAN_MBOX_INT_ENABLE_TX_NOT_EMPTY_MASK 0x0000f000
-#define WLAN_MBOX_INT_ENABLE_TX_NOT_EMPTY_GET(x) (((x) & WLAN_MBOX_INT_ENABLE_TX_NOT_EMPTY_MASK) >> WLAN_MBOX_INT_ENABLE_TX_NOT_EMPTY_LSB)
-#define WLAN_MBOX_INT_ENABLE_TX_NOT_EMPTY_SET(x) (((x) << WLAN_MBOX_INT_ENABLE_TX_NOT_EMPTY_LSB) & WLAN_MBOX_INT_ENABLE_TX_NOT_EMPTY_MASK)
-#define WLAN_MBOX_INT_ENABLE_RX_NOT_FULL_MSB 11
-#define WLAN_MBOX_INT_ENABLE_RX_NOT_FULL_LSB 8
-#define WLAN_MBOX_INT_ENABLE_RX_NOT_FULL_MASK 0x00000f00
-#define WLAN_MBOX_INT_ENABLE_RX_NOT_FULL_GET(x) (((x) & WLAN_MBOX_INT_ENABLE_RX_NOT_FULL_MASK) >> WLAN_MBOX_INT_ENABLE_RX_NOT_FULL_LSB)
-#define WLAN_MBOX_INT_ENABLE_RX_NOT_FULL_SET(x) (((x) << WLAN_MBOX_INT_ENABLE_RX_NOT_FULL_LSB) & WLAN_MBOX_INT_ENABLE_RX_NOT_FULL_MASK)
-#define WLAN_MBOX_INT_ENABLE_HOST_MSB 7
-#define WLAN_MBOX_INT_ENABLE_HOST_LSB 0
-#define WLAN_MBOX_INT_ENABLE_HOST_MASK 0x000000ff
-#define WLAN_MBOX_INT_ENABLE_HOST_GET(x) (((x) & WLAN_MBOX_INT_ENABLE_HOST_MASK) >> WLAN_MBOX_INT_ENABLE_HOST_LSB)
-#define WLAN_MBOX_INT_ENABLE_HOST_SET(x) (((x) << WLAN_MBOX_INT_ENABLE_HOST_LSB) & WLAN_MBOX_INT_ENABLE_HOST_MASK)
-
-#define WLAN_INT_HOST_ADDRESS 0x00000060
-#define WLAN_INT_HOST_OFFSET 0x00000060
-#define WLAN_INT_HOST_VECTOR_MSB 7
-#define WLAN_INT_HOST_VECTOR_LSB 0
-#define WLAN_INT_HOST_VECTOR_MASK 0x000000ff
-#define WLAN_INT_HOST_VECTOR_GET(x) (((x) & WLAN_INT_HOST_VECTOR_MASK) >> WLAN_INT_HOST_VECTOR_LSB)
-#define WLAN_INT_HOST_VECTOR_SET(x) (((x) << WLAN_INT_HOST_VECTOR_LSB) & WLAN_INT_HOST_VECTOR_MASK)
-
-#define WLAN_LOCAL_COUNT_ADDRESS 0x00000080
-#define WLAN_LOCAL_COUNT_OFFSET 0x00000080
-#define WLAN_LOCAL_COUNT_VALUE_MSB 7
-#define WLAN_LOCAL_COUNT_VALUE_LSB 0
-#define WLAN_LOCAL_COUNT_VALUE_MASK 0x000000ff
-#define WLAN_LOCAL_COUNT_VALUE_GET(x) (((x) & WLAN_LOCAL_COUNT_VALUE_MASK) >> WLAN_LOCAL_COUNT_VALUE_LSB)
-#define WLAN_LOCAL_COUNT_VALUE_SET(x) (((x) << WLAN_LOCAL_COUNT_VALUE_LSB) & WLAN_LOCAL_COUNT_VALUE_MASK)
-
-#define WLAN_COUNT_INC_ADDRESS 0x000000a0
-#define WLAN_COUNT_INC_OFFSET 0x000000a0
-#define WLAN_COUNT_INC_VALUE_MSB 7
-#define WLAN_COUNT_INC_VALUE_LSB 0
-#define WLAN_COUNT_INC_VALUE_MASK 0x000000ff
-#define WLAN_COUNT_INC_VALUE_GET(x) (((x) & WLAN_COUNT_INC_VALUE_MASK) >> WLAN_COUNT_INC_VALUE_LSB)
-#define WLAN_COUNT_INC_VALUE_SET(x) (((x) << WLAN_COUNT_INC_VALUE_LSB) & WLAN_COUNT_INC_VALUE_MASK)
-
-#define WLAN_LOCAL_SCRATCH_ADDRESS 0x000000c0
-#define WLAN_LOCAL_SCRATCH_OFFSET 0x000000c0
-#define WLAN_LOCAL_SCRATCH_VALUE_MSB 7
-#define WLAN_LOCAL_SCRATCH_VALUE_LSB 0
-#define WLAN_LOCAL_SCRATCH_VALUE_MASK 0x000000ff
-#define WLAN_LOCAL_SCRATCH_VALUE_GET(x) (((x) & WLAN_LOCAL_SCRATCH_VALUE_MASK) >> WLAN_LOCAL_SCRATCH_VALUE_LSB)
-#define WLAN_LOCAL_SCRATCH_VALUE_SET(x) (((x) << WLAN_LOCAL_SCRATCH_VALUE_LSB) & WLAN_LOCAL_SCRATCH_VALUE_MASK)
-
-#define WLAN_USE_LOCAL_BUS_ADDRESS 0x000000e0
-#define WLAN_USE_LOCAL_BUS_OFFSET 0x000000e0
-#define WLAN_USE_LOCAL_BUS_PIN_INIT_MSB 0
-#define WLAN_USE_LOCAL_BUS_PIN_INIT_LSB 0
-#define WLAN_USE_LOCAL_BUS_PIN_INIT_MASK 0x00000001
-#define WLAN_USE_LOCAL_BUS_PIN_INIT_GET(x) (((x) & WLAN_USE_LOCAL_BUS_PIN_INIT_MASK) >> WLAN_USE_LOCAL_BUS_PIN_INIT_LSB)
-#define WLAN_USE_LOCAL_BUS_PIN_INIT_SET(x) (((x) << WLAN_USE_LOCAL_BUS_PIN_INIT_LSB) & WLAN_USE_LOCAL_BUS_PIN_INIT_MASK)
-
-#define WLAN_SDIO_CONFIG_ADDRESS 0x000000e4
-#define WLAN_SDIO_CONFIG_OFFSET 0x000000e4
-#define WLAN_SDIO_CONFIG_CCCR_IOR1_MSB 0
-#define WLAN_SDIO_CONFIG_CCCR_IOR1_LSB 0
-#define WLAN_SDIO_CONFIG_CCCR_IOR1_MASK 0x00000001
-#define WLAN_SDIO_CONFIG_CCCR_IOR1_GET(x) (((x) & WLAN_SDIO_CONFIG_CCCR_IOR1_MASK) >> WLAN_SDIO_CONFIG_CCCR_IOR1_LSB)
-#define WLAN_SDIO_CONFIG_CCCR_IOR1_SET(x) (((x) << WLAN_SDIO_CONFIG_CCCR_IOR1_LSB) & WLAN_SDIO_CONFIG_CCCR_IOR1_MASK)
-
-#define WLAN_MBOX_DEBUG_ADDRESS 0x000000e8
-#define WLAN_MBOX_DEBUG_OFFSET 0x000000e8
-#define WLAN_MBOX_DEBUG_SEL_MSB 2
-#define WLAN_MBOX_DEBUG_SEL_LSB 0
-#define WLAN_MBOX_DEBUG_SEL_MASK 0x00000007
-#define WLAN_MBOX_DEBUG_SEL_GET(x) (((x) & WLAN_MBOX_DEBUG_SEL_MASK) >> WLAN_MBOX_DEBUG_SEL_LSB)
-#define WLAN_MBOX_DEBUG_SEL_SET(x) (((x) << WLAN_MBOX_DEBUG_SEL_LSB) & WLAN_MBOX_DEBUG_SEL_MASK)
-
-#define WLAN_MBOX_FIFO_RESET_ADDRESS 0x000000ec
-#define WLAN_MBOX_FIFO_RESET_OFFSET 0x000000ec
-#define WLAN_MBOX_FIFO_RESET_INIT_MSB 0
-#define WLAN_MBOX_FIFO_RESET_INIT_LSB 0
-#define WLAN_MBOX_FIFO_RESET_INIT_MASK 0x00000001
-#define WLAN_MBOX_FIFO_RESET_INIT_GET(x) (((x) & WLAN_MBOX_FIFO_RESET_INIT_MASK) >> WLAN_MBOX_FIFO_RESET_INIT_LSB)
-#define WLAN_MBOX_FIFO_RESET_INIT_SET(x) (((x) << WLAN_MBOX_FIFO_RESET_INIT_LSB) & WLAN_MBOX_FIFO_RESET_INIT_MASK)
-
-#define WLAN_MBOX_TXFIFO_POP_ADDRESS 0x000000f0
-#define WLAN_MBOX_TXFIFO_POP_OFFSET 0x000000f0
-#define WLAN_MBOX_TXFIFO_POP_DATA_MSB 0
-#define WLAN_MBOX_TXFIFO_POP_DATA_LSB 0
-#define WLAN_MBOX_TXFIFO_POP_DATA_MASK 0x00000001
-#define WLAN_MBOX_TXFIFO_POP_DATA_GET(x) (((x) & WLAN_MBOX_TXFIFO_POP_DATA_MASK) >> WLAN_MBOX_TXFIFO_POP_DATA_LSB)
-#define WLAN_MBOX_TXFIFO_POP_DATA_SET(x) (((x) << WLAN_MBOX_TXFIFO_POP_DATA_LSB) & WLAN_MBOX_TXFIFO_POP_DATA_MASK)
-
-#define WLAN_MBOX_RXFIFO_POP_ADDRESS 0x00000100
-#define WLAN_MBOX_RXFIFO_POP_OFFSET 0x00000100
-#define WLAN_MBOX_RXFIFO_POP_DATA_MSB 0
-#define WLAN_MBOX_RXFIFO_POP_DATA_LSB 0
-#define WLAN_MBOX_RXFIFO_POP_DATA_MASK 0x00000001
-#define WLAN_MBOX_RXFIFO_POP_DATA_GET(x) (((x) & WLAN_MBOX_RXFIFO_POP_DATA_MASK) >> WLAN_MBOX_RXFIFO_POP_DATA_LSB)
-#define WLAN_MBOX_RXFIFO_POP_DATA_SET(x) (((x) << WLAN_MBOX_RXFIFO_POP_DATA_LSB) & WLAN_MBOX_RXFIFO_POP_DATA_MASK)
-
-#define WLAN_SDIO_DEBUG_ADDRESS 0x00000110
-#define WLAN_SDIO_DEBUG_OFFSET 0x00000110
-#define WLAN_SDIO_DEBUG_SEL_MSB 3
-#define WLAN_SDIO_DEBUG_SEL_LSB 0
-#define WLAN_SDIO_DEBUG_SEL_MASK 0x0000000f
-#define WLAN_SDIO_DEBUG_SEL_GET(x) (((x) & WLAN_SDIO_DEBUG_SEL_MASK) >> WLAN_SDIO_DEBUG_SEL_LSB)
-#define WLAN_SDIO_DEBUG_SEL_SET(x) (((x) << WLAN_SDIO_DEBUG_SEL_LSB) & WLAN_SDIO_DEBUG_SEL_MASK)
-
-#define WLAN_GMBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS 0x00000114
-#define WLAN_GMBOX0_DMA_RX_DESCRIPTOR_BASE_OFFSET 0x00000114
-#define WLAN_GMBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MSB 27
-#define WLAN_GMBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB 2
-#define WLAN_GMBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK 0x0ffffffc
-#define WLAN_GMBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_GET(x) (((x) & WLAN_GMBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK) >> WLAN_GMBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB)
-#define WLAN_GMBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_SET(x) (((x) << WLAN_GMBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_LSB) & WLAN_GMBOX0_DMA_RX_DESCRIPTOR_BASE_ADDRESS_MASK)
-
-#define WLAN_GMBOX0_DMA_RX_CONTROL_ADDRESS 0x00000118
-#define WLAN_GMBOX0_DMA_RX_CONTROL_OFFSET 0x00000118
-#define WLAN_GMBOX0_DMA_RX_CONTROL_RESUME_MSB 2
-#define WLAN_GMBOX0_DMA_RX_CONTROL_RESUME_LSB 2
-#define WLAN_GMBOX0_DMA_RX_CONTROL_RESUME_MASK 0x00000004
-#define WLAN_GMBOX0_DMA_RX_CONTROL_RESUME_GET(x) (((x) & WLAN_GMBOX0_DMA_RX_CONTROL_RESUME_MASK) >> WLAN_GMBOX0_DMA_RX_CONTROL_RESUME_LSB)
-#define WLAN_GMBOX0_DMA_RX_CONTROL_RESUME_SET(x) (((x) << WLAN_GMBOX0_DMA_RX_CONTROL_RESUME_LSB) & WLAN_GMBOX0_DMA_RX_CONTROL_RESUME_MASK)
-#define WLAN_GMBOX0_DMA_RX_CONTROL_START_MSB 1
-#define WLAN_GMBOX0_DMA_RX_CONTROL_START_LSB 1
-#define WLAN_GMBOX0_DMA_RX_CONTROL_START_MASK 0x00000002
-#define WLAN_GMBOX0_DMA_RX_CONTROL_START_GET(x) (((x) & WLAN_GMBOX0_DMA_RX_CONTROL_START_MASK) >> WLAN_GMBOX0_DMA_RX_CONTROL_START_LSB)
-#define WLAN_GMBOX0_DMA_RX_CONTROL_START_SET(x) (((x) << WLAN_GMBOX0_DMA_RX_CONTROL_START_LSB) & WLAN_GMBOX0_DMA_RX_CONTROL_START_MASK)
-#define WLAN_GMBOX0_DMA_RX_CONTROL_STOP_MSB 0
-#define WLAN_GMBOX0_DMA_RX_CONTROL_STOP_LSB 0
-#define WLAN_GMBOX0_DMA_RX_CONTROL_STOP_MASK 0x00000001
-#define WLAN_GMBOX0_DMA_RX_CONTROL_STOP_GET(x) (((x) & WLAN_GMBOX0_DMA_RX_CONTROL_STOP_MASK) >> WLAN_GMBOX0_DMA_RX_CONTROL_STOP_LSB)
-#define WLAN_GMBOX0_DMA_RX_CONTROL_STOP_SET(x) (((x) << WLAN_GMBOX0_DMA_RX_CONTROL_STOP_LSB) & WLAN_GMBOX0_DMA_RX_CONTROL_STOP_MASK)
-
-#define WLAN_GMBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS 0x0000011c
-#define WLAN_GMBOX0_DMA_TX_DESCRIPTOR_BASE_OFFSET 0x0000011c
-#define WLAN_GMBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MSB 27
-#define WLAN_GMBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB 2
-#define WLAN_GMBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK 0x0ffffffc
-#define WLAN_GMBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_GET(x) (((x) & WLAN_GMBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK) >> WLAN_GMBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB)
-#define WLAN_GMBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_SET(x) (((x) << WLAN_GMBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_LSB) & WLAN_GMBOX0_DMA_TX_DESCRIPTOR_BASE_ADDRESS_MASK)
-
-#define WLAN_GMBOX0_DMA_TX_CONTROL_ADDRESS 0x00000120
-#define WLAN_GMBOX0_DMA_TX_CONTROL_OFFSET 0x00000120
-#define WLAN_GMBOX0_DMA_TX_CONTROL_RESUME_MSB 2
-#define WLAN_GMBOX0_DMA_TX_CONTROL_RESUME_LSB 2
-#define WLAN_GMBOX0_DMA_TX_CONTROL_RESUME_MASK 0x00000004
-#define WLAN_GMBOX0_DMA_TX_CONTROL_RESUME_GET(x) (((x) & WLAN_GMBOX0_DMA_TX_CONTROL_RESUME_MASK) >> WLAN_GMBOX0_DMA_TX_CONTROL_RESUME_LSB)
-#define WLAN_GMBOX0_DMA_TX_CONTROL_RESUME_SET(x) (((x) << WLAN_GMBOX0_DMA_TX_CONTROL_RESUME_LSB) & WLAN_GMBOX0_DMA_TX_CONTROL_RESUME_MASK)
-#define WLAN_GMBOX0_DMA_TX_CONTROL_START_MSB 1
-#define WLAN_GMBOX0_DMA_TX_CONTROL_START_LSB 1
-#define WLAN_GMBOX0_DMA_TX_CONTROL_START_MASK 0x00000002
-#define WLAN_GMBOX0_DMA_TX_CONTROL_START_GET(x) (((x) & WLAN_GMBOX0_DMA_TX_CONTROL_START_MASK) >> WLAN_GMBOX0_DMA_TX_CONTROL_START_LSB)
-#define WLAN_GMBOX0_DMA_TX_CONTROL_START_SET(x) (((x) << WLAN_GMBOX0_DMA_TX_CONTROL_START_LSB) & WLAN_GMBOX0_DMA_TX_CONTROL_START_MASK)
-#define WLAN_GMBOX0_DMA_TX_CONTROL_STOP_MSB 0
-#define WLAN_GMBOX0_DMA_TX_CONTROL_STOP_LSB 0
-#define WLAN_GMBOX0_DMA_TX_CONTROL_STOP_MASK 0x00000001
-#define WLAN_GMBOX0_DMA_TX_CONTROL_STOP_GET(x) (((x) & WLAN_GMBOX0_DMA_TX_CONTROL_STOP_MASK) >> WLAN_GMBOX0_DMA_TX_CONTROL_STOP_LSB)
-#define WLAN_GMBOX0_DMA_TX_CONTROL_STOP_SET(x) (((x) << WLAN_GMBOX0_DMA_TX_CONTROL_STOP_LSB) & WLAN_GMBOX0_DMA_TX_CONTROL_STOP_MASK)
-
-#define WLAN_GMBOX_INT_STATUS_ADDRESS 0x00000124
-#define WLAN_GMBOX_INT_STATUS_OFFSET 0x00000124
-#define WLAN_GMBOX_INT_STATUS_TX_OVERFLOW_MSB 6
-#define WLAN_GMBOX_INT_STATUS_TX_OVERFLOW_LSB 6
-#define WLAN_GMBOX_INT_STATUS_TX_OVERFLOW_MASK 0x00000040
-#define WLAN_GMBOX_INT_STATUS_TX_OVERFLOW_GET(x) (((x) & WLAN_GMBOX_INT_STATUS_TX_OVERFLOW_MASK) >> WLAN_GMBOX_INT_STATUS_TX_OVERFLOW_LSB)
-#define WLAN_GMBOX_INT_STATUS_TX_OVERFLOW_SET(x) (((x) << WLAN_GMBOX_INT_STATUS_TX_OVERFLOW_LSB) & WLAN_GMBOX_INT_STATUS_TX_OVERFLOW_MASK)
-#define WLAN_GMBOX_INT_STATUS_RX_UNDERFLOW_MSB 5
-#define WLAN_GMBOX_INT_STATUS_RX_UNDERFLOW_LSB 5
-#define WLAN_GMBOX_INT_STATUS_RX_UNDERFLOW_MASK 0x00000020
-#define WLAN_GMBOX_INT_STATUS_RX_UNDERFLOW_GET(x) (((x) & WLAN_GMBOX_INT_STATUS_RX_UNDERFLOW_MASK) >> WLAN_GMBOX_INT_STATUS_RX_UNDERFLOW_LSB)
-#define WLAN_GMBOX_INT_STATUS_RX_UNDERFLOW_SET(x) (((x) << WLAN_GMBOX_INT_STATUS_RX_UNDERFLOW_LSB) & WLAN_GMBOX_INT_STATUS_RX_UNDERFLOW_MASK)
-#define WLAN_GMBOX_INT_STATUS_RX_DMA_COMPLETE_MSB 4
-#define WLAN_GMBOX_INT_STATUS_RX_DMA_COMPLETE_LSB 4
-#define WLAN_GMBOX_INT_STATUS_RX_DMA_COMPLETE_MASK 0x00000010
-#define WLAN_GMBOX_INT_STATUS_RX_DMA_COMPLETE_GET(x) (((x) & WLAN_GMBOX_INT_STATUS_RX_DMA_COMPLETE_MASK) >> WLAN_GMBOX_INT_STATUS_RX_DMA_COMPLETE_LSB)
-#define WLAN_GMBOX_INT_STATUS_RX_DMA_COMPLETE_SET(x) (((x) << WLAN_GMBOX_INT_STATUS_RX_DMA_COMPLETE_LSB) & WLAN_GMBOX_INT_STATUS_RX_DMA_COMPLETE_MASK)
-#define WLAN_GMBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_MSB 3
-#define WLAN_GMBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_LSB 3
-#define WLAN_GMBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_MASK 0x00000008
-#define WLAN_GMBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_GET(x) (((x) & WLAN_GMBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_MASK) >> WLAN_GMBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_LSB)
-#define WLAN_GMBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_SET(x) (((x) << WLAN_GMBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_LSB) & WLAN_GMBOX_INT_STATUS_TX_DMA_EOM_COMPLETE_MASK)
-#define WLAN_GMBOX_INT_STATUS_TX_DMA_COMPLETE_MSB 2
-#define WLAN_GMBOX_INT_STATUS_TX_DMA_COMPLETE_LSB 2
-#define WLAN_GMBOX_INT_STATUS_TX_DMA_COMPLETE_MASK 0x00000004
-#define WLAN_GMBOX_INT_STATUS_TX_DMA_COMPLETE_GET(x) (((x) & WLAN_GMBOX_INT_STATUS_TX_DMA_COMPLETE_MASK) >> WLAN_GMBOX_INT_STATUS_TX_DMA_COMPLETE_LSB)
-#define WLAN_GMBOX_INT_STATUS_TX_DMA_COMPLETE_SET(x) (((x) << WLAN_GMBOX_INT_STATUS_TX_DMA_COMPLETE_LSB) & WLAN_GMBOX_INT_STATUS_TX_DMA_COMPLETE_MASK)
-#define WLAN_GMBOX_INT_STATUS_TX_NOT_EMPTY_MSB 1
-#define WLAN_GMBOX_INT_STATUS_TX_NOT_EMPTY_LSB 1
-#define WLAN_GMBOX_INT_STATUS_TX_NOT_EMPTY_MASK 0x00000002
-#define WLAN_GMBOX_INT_STATUS_TX_NOT_EMPTY_GET(x) (((x) & WLAN_GMBOX_INT_STATUS_TX_NOT_EMPTY_MASK) >> WLAN_GMBOX_INT_STATUS_TX_NOT_EMPTY_LSB)
-#define WLAN_GMBOX_INT_STATUS_TX_NOT_EMPTY_SET(x) (((x) << WLAN_GMBOX_INT_STATUS_TX_NOT_EMPTY_LSB) & WLAN_GMBOX_INT_STATUS_TX_NOT_EMPTY_MASK)
-#define WLAN_GMBOX_INT_STATUS_RX_NOT_FULL_MSB 0
-#define WLAN_GMBOX_INT_STATUS_RX_NOT_FULL_LSB 0
-#define WLAN_GMBOX_INT_STATUS_RX_NOT_FULL_MASK 0x00000001
-#define WLAN_GMBOX_INT_STATUS_RX_NOT_FULL_GET(x) (((x) & WLAN_GMBOX_INT_STATUS_RX_NOT_FULL_MASK) >> WLAN_GMBOX_INT_STATUS_RX_NOT_FULL_LSB)
-#define WLAN_GMBOX_INT_STATUS_RX_NOT_FULL_SET(x) (((x) << WLAN_GMBOX_INT_STATUS_RX_NOT_FULL_LSB) & WLAN_GMBOX_INT_STATUS_RX_NOT_FULL_MASK)
-
-#define WLAN_GMBOX_INT_ENABLE_ADDRESS 0x00000128
-#define WLAN_GMBOX_INT_ENABLE_OFFSET 0x00000128
-#define WLAN_GMBOX_INT_ENABLE_TX_OVERFLOW_MSB 6
-#define WLAN_GMBOX_INT_ENABLE_TX_OVERFLOW_LSB 6
-#define WLAN_GMBOX_INT_ENABLE_TX_OVERFLOW_MASK 0x00000040
-#define WLAN_GMBOX_INT_ENABLE_TX_OVERFLOW_GET(x) (((x) & WLAN_GMBOX_INT_ENABLE_TX_OVERFLOW_MASK) >> WLAN_GMBOX_INT_ENABLE_TX_OVERFLOW_LSB)
-#define WLAN_GMBOX_INT_ENABLE_TX_OVERFLOW_SET(x) (((x) << WLAN_GMBOX_INT_ENABLE_TX_OVERFLOW_LSB) & WLAN_GMBOX_INT_ENABLE_TX_OVERFLOW_MASK)
-#define WLAN_GMBOX_INT_ENABLE_RX_UNDERFLOW_MSB 5
-#define WLAN_GMBOX_INT_ENABLE_RX_UNDERFLOW_LSB 5
-#define WLAN_GMBOX_INT_ENABLE_RX_UNDERFLOW_MASK 0x00000020
-#define WLAN_GMBOX_INT_ENABLE_RX_UNDERFLOW_GET(x) (((x) & WLAN_GMBOX_INT_ENABLE_RX_UNDERFLOW_MASK) >> WLAN_GMBOX_INT_ENABLE_RX_UNDERFLOW_LSB)
-#define WLAN_GMBOX_INT_ENABLE_RX_UNDERFLOW_SET(x) (((x) << WLAN_GMBOX_INT_ENABLE_RX_UNDERFLOW_LSB) & WLAN_GMBOX_INT_ENABLE_RX_UNDERFLOW_MASK)
-#define WLAN_GMBOX_INT_ENABLE_RX_DMA_COMPLETE_MSB 4
-#define WLAN_GMBOX_INT_ENABLE_RX_DMA_COMPLETE_LSB 4
-#define WLAN_GMBOX_INT_ENABLE_RX_DMA_COMPLETE_MASK 0x00000010
-#define WLAN_GMBOX_INT_ENABLE_RX_DMA_COMPLETE_GET(x) (((x) & WLAN_GMBOX_INT_ENABLE_RX_DMA_COMPLETE_MASK) >> WLAN_GMBOX_INT_ENABLE_RX_DMA_COMPLETE_LSB)
-#define WLAN_GMBOX_INT_ENABLE_RX_DMA_COMPLETE_SET(x) (((x) << WLAN_GMBOX_INT_ENABLE_RX_DMA_COMPLETE_LSB) & WLAN_GMBOX_INT_ENABLE_RX_DMA_COMPLETE_MASK)
-#define WLAN_GMBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_MSB 3
-#define WLAN_GMBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_LSB 3
-#define WLAN_GMBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_MASK 0x00000008
-#define WLAN_GMBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_GET(x) (((x) & WLAN_GMBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_MASK) >> WLAN_GMBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_LSB)
-#define WLAN_GMBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_SET(x) (((x) << WLAN_GMBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_LSB) & WLAN_GMBOX_INT_ENABLE_TX_DMA_EOM_COMPLETE_MASK)
-#define WLAN_GMBOX_INT_ENABLE_TX_DMA_COMPLETE_MSB 2
-#define WLAN_GMBOX_INT_ENABLE_TX_DMA_COMPLETE_LSB 2
-#define WLAN_GMBOX_INT_ENABLE_TX_DMA_COMPLETE_MASK 0x00000004
-#define WLAN_GMBOX_INT_ENABLE_TX_DMA_COMPLETE_GET(x) (((x) & WLAN_GMBOX_INT_ENABLE_TX_DMA_COMPLETE_MASK) >> WLAN_GMBOX_INT_ENABLE_TX_DMA_COMPLETE_LSB)
-#define WLAN_GMBOX_INT_ENABLE_TX_DMA_COMPLETE_SET(x) (((x) << WLAN_GMBOX_INT_ENABLE_TX_DMA_COMPLETE_LSB) & WLAN_GMBOX_INT_ENABLE_TX_DMA_COMPLETE_MASK)
-#define WLAN_GMBOX_INT_ENABLE_TX_NOT_EMPTY_MSB 1
-#define WLAN_GMBOX_INT_ENABLE_TX_NOT_EMPTY_LSB 1
-#define WLAN_GMBOX_INT_ENABLE_TX_NOT_EMPTY_MASK 0x00000002
-#define WLAN_GMBOX_INT_ENABLE_TX_NOT_EMPTY_GET(x) (((x) & WLAN_GMBOX_INT_ENABLE_TX_NOT_EMPTY_MASK) >> WLAN_GMBOX_INT_ENABLE_TX_NOT_EMPTY_LSB)
-#define WLAN_GMBOX_INT_ENABLE_TX_NOT_EMPTY_SET(x) (((x) << WLAN_GMBOX_INT_ENABLE_TX_NOT_EMPTY_LSB) & WLAN_GMBOX_INT_ENABLE_TX_NOT_EMPTY_MASK)
-#define WLAN_GMBOX_INT_ENABLE_RX_NOT_FULL_MSB 0
-#define WLAN_GMBOX_INT_ENABLE_RX_NOT_FULL_LSB 0
-#define WLAN_GMBOX_INT_ENABLE_RX_NOT_FULL_MASK 0x00000001
-#define WLAN_GMBOX_INT_ENABLE_RX_NOT_FULL_GET(x) (((x) & WLAN_GMBOX_INT_ENABLE_RX_NOT_FULL_MASK) >> WLAN_GMBOX_INT_ENABLE_RX_NOT_FULL_LSB)
-#define WLAN_GMBOX_INT_ENABLE_RX_NOT_FULL_SET(x) (((x) << WLAN_GMBOX_INT_ENABLE_RX_NOT_FULL_LSB) & WLAN_GMBOX_INT_ENABLE_RX_NOT_FULL_MASK)
-
-#define WLAN_HOST_IF_WINDOW_ADDRESS 0x00002000
-#define WLAN_HOST_IF_WINDOW_OFFSET 0x00002000
-#define WLAN_HOST_IF_WINDOW_DATA_MSB 7
-#define WLAN_HOST_IF_WINDOW_DATA_LSB 0
-#define WLAN_HOST_IF_WINDOW_DATA_MASK 0x000000ff
-#define WLAN_HOST_IF_WINDOW_DATA_GET(x) (((x) & WLAN_HOST_IF_WINDOW_DATA_MASK) >> WLAN_HOST_IF_WINDOW_DATA_LSB)
-#define WLAN_HOST_IF_WINDOW_DATA_SET(x) (((x) << WLAN_HOST_IF_WINDOW_DATA_LSB) & WLAN_HOST_IF_WINDOW_DATA_MASK)
-
-#endif /* _MBOX_WLAN_REG_H_ */
diff --git a/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/rtc_reg.h b/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/rtc_reg.h
deleted file mode 100644
index fcafec88a6b9..000000000000
--- a/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/rtc_reg.h
+++ /dev/null
@@ -1,187 +0,0 @@
-// ------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-// ------------------------------------------------------------------
-//===================================================================
-// Author(s): ="Atheros"
-//===================================================================
-
-
-#include "rtc_wlan_reg.h"
-
-#ifndef BT_HEADERS
-
-#define RESET_CONTROL_ADDRESS WLAN_RESET_CONTROL_ADDRESS
-#define RESET_CONTROL_OFFSET WLAN_RESET_CONTROL_OFFSET
-#define RESET_CONTROL_DEBUG_UART_RST_MSB WLAN_RESET_CONTROL_DEBUG_UART_RST_MSB
-#define RESET_CONTROL_DEBUG_UART_RST_LSB WLAN_RESET_CONTROL_DEBUG_UART_RST_LSB
-#define RESET_CONTROL_DEBUG_UART_RST_MASK WLAN_RESET_CONTROL_DEBUG_UART_RST_MASK
-#define RESET_CONTROL_DEBUG_UART_RST_GET(x) WLAN_RESET_CONTROL_DEBUG_UART_RST_GET(x)
-#define RESET_CONTROL_DEBUG_UART_RST_SET(x) WLAN_RESET_CONTROL_DEBUG_UART_RST_SET(x)
-#define RESET_CONTROL_BB_COLD_RST_MSB WLAN_RESET_CONTROL_BB_COLD_RST_MSB
-#define RESET_CONTROL_BB_COLD_RST_LSB WLAN_RESET_CONTROL_BB_COLD_RST_LSB
-#define RESET_CONTROL_BB_COLD_RST_MASK WLAN_RESET_CONTROL_BB_COLD_RST_MASK
-#define RESET_CONTROL_BB_COLD_RST_GET(x) WLAN_RESET_CONTROL_BB_COLD_RST_GET(x)
-#define RESET_CONTROL_BB_COLD_RST_SET(x) WLAN_RESET_CONTROL_BB_COLD_RST_SET(x)
-#define RESET_CONTROL_BB_WARM_RST_MSB WLAN_RESET_CONTROL_BB_WARM_RST_MSB
-#define RESET_CONTROL_BB_WARM_RST_LSB WLAN_RESET_CONTROL_BB_WARM_RST_LSB
-#define RESET_CONTROL_BB_WARM_RST_MASK WLAN_RESET_CONTROL_BB_WARM_RST_MASK
-#define RESET_CONTROL_BB_WARM_RST_GET(x) WLAN_RESET_CONTROL_BB_WARM_RST_GET(x)
-#define RESET_CONTROL_BB_WARM_RST_SET(x) WLAN_RESET_CONTROL_BB_WARM_RST_SET(x)
-#define RESET_CONTROL_CPU_INIT_RESET_MSB WLAN_RESET_CONTROL_CPU_INIT_RESET_MSB
-#define RESET_CONTROL_CPU_INIT_RESET_LSB WLAN_RESET_CONTROL_CPU_INIT_RESET_LSB
-#define RESET_CONTROL_CPU_INIT_RESET_MASK WLAN_RESET_CONTROL_CPU_INIT_RESET_MASK
-#define RESET_CONTROL_CPU_INIT_RESET_GET(x) WLAN_RESET_CONTROL_CPU_INIT_RESET_GET(x)
-#define RESET_CONTROL_CPU_INIT_RESET_SET(x) WLAN_RESET_CONTROL_CPU_INIT_RESET_SET(x)
-#define RESET_CONTROL_VMC_REMAP_RESET_MSB WLAN_RESET_CONTROL_VMC_REMAP_RESET_MSB
-#define RESET_CONTROL_VMC_REMAP_RESET_LSB WLAN_RESET_CONTROL_VMC_REMAP_RESET_LSB
-#define RESET_CONTROL_VMC_REMAP_RESET_MASK WLAN_RESET_CONTROL_VMC_REMAP_RESET_MASK
-#define RESET_CONTROL_VMC_REMAP_RESET_GET(x) WLAN_RESET_CONTROL_VMC_REMAP_RESET_GET(x)
-#define RESET_CONTROL_VMC_REMAP_RESET_SET(x) WLAN_RESET_CONTROL_VMC_REMAP_RESET_SET(x)
-#define RESET_CONTROL_RST_OUT_MSB WLAN_RESET_CONTROL_RST_OUT_MSB
-#define RESET_CONTROL_RST_OUT_LSB WLAN_RESET_CONTROL_RST_OUT_LSB
-#define RESET_CONTROL_RST_OUT_MASK WLAN_RESET_CONTROL_RST_OUT_MASK
-#define RESET_CONTROL_RST_OUT_GET(x) WLAN_RESET_CONTROL_RST_OUT_GET(x)
-#define RESET_CONTROL_RST_OUT_SET(x) WLAN_RESET_CONTROL_RST_OUT_SET(x)
-#define RESET_CONTROL_COLD_RST_MSB WLAN_RESET_CONTROL_COLD_RST_MSB
-#define RESET_CONTROL_COLD_RST_LSB WLAN_RESET_CONTROL_COLD_RST_LSB
-#define RESET_CONTROL_COLD_RST_MASK WLAN_RESET_CONTROL_COLD_RST_MASK
-#define RESET_CONTROL_COLD_RST_GET(x) WLAN_RESET_CONTROL_COLD_RST_GET(x)
-#define RESET_CONTROL_COLD_RST_SET(x) WLAN_RESET_CONTROL_COLD_RST_SET(x)
-#define RESET_CONTROL_WARM_RST_MSB WLAN_RESET_CONTROL_WARM_RST_MSB
-#define RESET_CONTROL_WARM_RST_LSB WLAN_RESET_CONTROL_WARM_RST_LSB
-#define RESET_CONTROL_WARM_RST_MASK WLAN_RESET_CONTROL_WARM_RST_MASK
-#define RESET_CONTROL_WARM_RST_GET(x) WLAN_RESET_CONTROL_WARM_RST_GET(x)
-#define RESET_CONTROL_WARM_RST_SET(x) WLAN_RESET_CONTROL_WARM_RST_SET(x)
-#define RESET_CONTROL_CPU_WARM_RST_MSB WLAN_RESET_CONTROL_CPU_WARM_RST_MSB
-#define RESET_CONTROL_CPU_WARM_RST_LSB WLAN_RESET_CONTROL_CPU_WARM_RST_LSB
-#define RESET_CONTROL_CPU_WARM_RST_MASK WLAN_RESET_CONTROL_CPU_WARM_RST_MASK
-#define RESET_CONTROL_CPU_WARM_RST_GET(x) WLAN_RESET_CONTROL_CPU_WARM_RST_GET(x)
-#define RESET_CONTROL_CPU_WARM_RST_SET(x) WLAN_RESET_CONTROL_CPU_WARM_RST_SET(x)
-#define RESET_CONTROL_MAC_COLD_RST_MSB WLAN_RESET_CONTROL_MAC_COLD_RST_MSB
-#define RESET_CONTROL_MAC_COLD_RST_LSB WLAN_RESET_CONTROL_MAC_COLD_RST_LSB
-#define RESET_CONTROL_MAC_COLD_RST_MASK WLAN_RESET_CONTROL_MAC_COLD_RST_MASK
-#define RESET_CONTROL_MAC_COLD_RST_GET(x) WLAN_RESET_CONTROL_MAC_COLD_RST_GET(x)
-#define RESET_CONTROL_MAC_COLD_RST_SET(x) WLAN_RESET_CONTROL_MAC_COLD_RST_SET(x)
-#define RESET_CONTROL_MAC_WARM_RST_MSB WLAN_RESET_CONTROL_MAC_WARM_RST_MSB
-#define RESET_CONTROL_MAC_WARM_RST_LSB WLAN_RESET_CONTROL_MAC_WARM_RST_LSB
-#define RESET_CONTROL_MAC_WARM_RST_MASK WLAN_RESET_CONTROL_MAC_WARM_RST_MASK
-#define RESET_CONTROL_MAC_WARM_RST_GET(x) WLAN_RESET_CONTROL_MAC_WARM_RST_GET(x)
-#define RESET_CONTROL_MAC_WARM_RST_SET(x) WLAN_RESET_CONTROL_MAC_WARM_RST_SET(x)
-#define RESET_CONTROL_MBOX_RST_MSB WLAN_RESET_CONTROL_MBOX_RST_MSB
-#define RESET_CONTROL_MBOX_RST_LSB WLAN_RESET_CONTROL_MBOX_RST_LSB
-#define RESET_CONTROL_MBOX_RST_MASK WLAN_RESET_CONTROL_MBOX_RST_MASK
-#define RESET_CONTROL_MBOX_RST_GET(x) WLAN_RESET_CONTROL_MBOX_RST_GET(x)
-#define RESET_CONTROL_MBOX_RST_SET(x) WLAN_RESET_CONTROL_MBOX_RST_SET(x)
-#define RESET_CONTROL_UART_RST_MSB WLAN_RESET_CONTROL_UART_RST_MSB
-#define RESET_CONTROL_UART_RST_LSB WLAN_RESET_CONTROL_UART_RST_LSB
-#define RESET_CONTROL_UART_RST_MASK WLAN_RESET_CONTROL_UART_RST_MASK
-#define RESET_CONTROL_UART_RST_GET(x) WLAN_RESET_CONTROL_UART_RST_GET(x)
-#define RESET_CONTROL_UART_RST_SET(x) WLAN_RESET_CONTROL_UART_RST_SET(x)
-#define RESET_CONTROL_SI0_RST_MSB WLAN_RESET_CONTROL_SI0_RST_MSB
-#define RESET_CONTROL_SI0_RST_LSB WLAN_RESET_CONTROL_SI0_RST_LSB
-#define RESET_CONTROL_SI0_RST_MASK WLAN_RESET_CONTROL_SI0_RST_MASK
-#define RESET_CONTROL_SI0_RST_GET(x) WLAN_RESET_CONTROL_SI0_RST_GET(x)
-#define RESET_CONTROL_SI0_RST_SET(x) WLAN_RESET_CONTROL_SI0_RST_SET(x)
-#define CPU_CLOCK_ADDRESS WLAN_CPU_CLOCK_ADDRESS
-#define CPU_CLOCK_OFFSET WLAN_CPU_CLOCK_OFFSET
-#define CPU_CLOCK_STANDARD_MSB WLAN_CPU_CLOCK_STANDARD_MSB
-#define CPU_CLOCK_STANDARD_LSB WLAN_CPU_CLOCK_STANDARD_LSB
-#define CPU_CLOCK_STANDARD_MASK WLAN_CPU_CLOCK_STANDARD_MASK
-#define CPU_CLOCK_STANDARD_GET(x) WLAN_CPU_CLOCK_STANDARD_GET(x)
-#define CPU_CLOCK_STANDARD_SET(x) WLAN_CPU_CLOCK_STANDARD_SET(x)
-#define CLOCK_OUT_ADDRESS WLAN_CLOCK_OUT_ADDRESS
-#define CLOCK_OUT_OFFSET WLAN_CLOCK_OUT_OFFSET
-#define CLOCK_OUT_SELECT_MSB WLAN_CLOCK_OUT_SELECT_MSB
-#define CLOCK_OUT_SELECT_LSB WLAN_CLOCK_OUT_SELECT_LSB
-#define CLOCK_OUT_SELECT_MASK WLAN_CLOCK_OUT_SELECT_MASK
-#define CLOCK_OUT_SELECT_GET(x) WLAN_CLOCK_OUT_SELECT_GET(x)
-#define CLOCK_OUT_SELECT_SET(x) WLAN_CLOCK_OUT_SELECT_SET(x)
-#define CLOCK_CONTROL_ADDRESS WLAN_CLOCK_CONTROL_ADDRESS
-#define CLOCK_CONTROL_OFFSET WLAN_CLOCK_CONTROL_OFFSET
-#define CLOCK_CONTROL_LF_CLK32_MSB WLAN_CLOCK_CONTROL_LF_CLK32_MSB
-#define CLOCK_CONTROL_LF_CLK32_LSB WLAN_CLOCK_CONTROL_LF_CLK32_LSB
-#define CLOCK_CONTROL_LF_CLK32_MASK WLAN_CLOCK_CONTROL_LF_CLK32_MASK
-#define CLOCK_CONTROL_LF_CLK32_GET(x) WLAN_CLOCK_CONTROL_LF_CLK32_GET(x)
-#define CLOCK_CONTROL_LF_CLK32_SET(x) WLAN_CLOCK_CONTROL_LF_CLK32_SET(x)
-#define CLOCK_CONTROL_SI0_CLK_MSB WLAN_CLOCK_CONTROL_SI0_CLK_MSB
-#define CLOCK_CONTROL_SI0_CLK_LSB WLAN_CLOCK_CONTROL_SI0_CLK_LSB
-#define CLOCK_CONTROL_SI0_CLK_MASK WLAN_CLOCK_CONTROL_SI0_CLK_MASK
-#define CLOCK_CONTROL_SI0_CLK_GET(x) WLAN_CLOCK_CONTROL_SI0_CLK_GET(x)
-#define CLOCK_CONTROL_SI0_CLK_SET(x) WLAN_CLOCK_CONTROL_SI0_CLK_SET(x)
-#define RESET_CAUSE_ADDRESS WLAN_RESET_CAUSE_ADDRESS
-#define RESET_CAUSE_OFFSET WLAN_RESET_CAUSE_OFFSET
-#define RESET_CAUSE_LAST_MSB WLAN_RESET_CAUSE_LAST_MSB
-#define RESET_CAUSE_LAST_LSB WLAN_RESET_CAUSE_LAST_LSB
-#define RESET_CAUSE_LAST_MASK WLAN_RESET_CAUSE_LAST_MASK
-#define RESET_CAUSE_LAST_GET(x) WLAN_RESET_CAUSE_LAST_GET(x)
-#define RESET_CAUSE_LAST_SET(x) WLAN_RESET_CAUSE_LAST_SET(x)
-#define SYSTEM_SLEEP_ADDRESS WLAN_SYSTEM_SLEEP_ADDRESS
-#define SYSTEM_SLEEP_OFFSET WLAN_SYSTEM_SLEEP_OFFSET
-#define SYSTEM_SLEEP_HOST_IF_MSB WLAN_SYSTEM_SLEEP_HOST_IF_MSB
-#define SYSTEM_SLEEP_HOST_IF_LSB WLAN_SYSTEM_SLEEP_HOST_IF_LSB
-#define SYSTEM_SLEEP_HOST_IF_MASK WLAN_SYSTEM_SLEEP_HOST_IF_MASK
-#define SYSTEM_SLEEP_HOST_IF_GET(x) WLAN_SYSTEM_SLEEP_HOST_IF_GET(x)
-#define SYSTEM_SLEEP_HOST_IF_SET(x) WLAN_SYSTEM_SLEEP_HOST_IF_SET(x)
-#define SYSTEM_SLEEP_MBOX_MSB WLAN_SYSTEM_SLEEP_MBOX_MSB
-#define SYSTEM_SLEEP_MBOX_LSB WLAN_SYSTEM_SLEEP_MBOX_LSB
-#define SYSTEM_SLEEP_MBOX_MASK WLAN_SYSTEM_SLEEP_MBOX_MASK
-#define SYSTEM_SLEEP_MBOX_GET(x) WLAN_SYSTEM_SLEEP_MBOX_GET(x)
-#define SYSTEM_SLEEP_MBOX_SET(x) WLAN_SYSTEM_SLEEP_MBOX_SET(x)
-#define SYSTEM_SLEEP_MAC_IF_MSB WLAN_SYSTEM_SLEEP_MAC_IF_MSB
-#define SYSTEM_SLEEP_MAC_IF_LSB WLAN_SYSTEM_SLEEP_MAC_IF_LSB
-#define SYSTEM_SLEEP_MAC_IF_MASK WLAN_SYSTEM_SLEEP_MAC_IF_MASK
-#define SYSTEM_SLEEP_MAC_IF_GET(x) WLAN_SYSTEM_SLEEP_MAC_IF_GET(x)
-#define SYSTEM_SLEEP_MAC_IF_SET(x) WLAN_SYSTEM_SLEEP_MAC_IF_SET(x)
-#define SYSTEM_SLEEP_LIGHT_MSB WLAN_SYSTEM_SLEEP_LIGHT_MSB
-#define SYSTEM_SLEEP_LIGHT_LSB WLAN_SYSTEM_SLEEP_LIGHT_LSB
-#define SYSTEM_SLEEP_LIGHT_MASK WLAN_SYSTEM_SLEEP_LIGHT_MASK
-#define SYSTEM_SLEEP_LIGHT_GET(x) WLAN_SYSTEM_SLEEP_LIGHT_GET(x)
-#define SYSTEM_SLEEP_LIGHT_SET(x) WLAN_SYSTEM_SLEEP_LIGHT_SET(x)
-#define SYSTEM_SLEEP_DISABLE_MSB WLAN_SYSTEM_SLEEP_DISABLE_MSB
-#define SYSTEM_SLEEP_DISABLE_LSB WLAN_SYSTEM_SLEEP_DISABLE_LSB
-#define SYSTEM_SLEEP_DISABLE_MASK WLAN_SYSTEM_SLEEP_DISABLE_MASK
-#define SYSTEM_SLEEP_DISABLE_GET(x) WLAN_SYSTEM_SLEEP_DISABLE_GET(x)
-#define SYSTEM_SLEEP_DISABLE_SET(x) WLAN_SYSTEM_SLEEP_DISABLE_SET(x)
-#define LPO_INIT_DIVIDEND_INT_ADDRESS WLAN_LPO_INIT_DIVIDEND_INT_ADDRESS
-#define LPO_INIT_DIVIDEND_INT_OFFSET WLAN_LPO_INIT_DIVIDEND_INT_OFFSET
-#define LPO_INIT_DIVIDEND_INT_VALUE_MSB WLAN_LPO_INIT_DIVIDEND_INT_VALUE_MSB
-#define LPO_INIT_DIVIDEND_INT_VALUE_LSB WLAN_LPO_INIT_DIVIDEND_INT_VALUE_LSB
-#define LPO_INIT_DIVIDEND_INT_VALUE_MASK WLAN_LPO_INIT_DIVIDEND_INT_VALUE_MASK
-#define LPO_INIT_DIVIDEND_INT_VALUE_GET(x) WLAN_LPO_INIT_DIVIDEND_INT_VALUE_GET(x)
-#define LPO_INIT_DIVIDEND_INT_VALUE_SET(x) WLAN_LPO_INIT_DIVIDEND_INT_VALUE_SET(x)
-#define LPO_INIT_DIVIDEND_FRACTION_ADDRESS WLAN_LPO_INIT_DIVIDEND_FRACTION_ADDRESS
-#define LPO_INIT_DIVIDEND_FRACTION_OFFSET WLAN_LPO_INIT_DIVIDEND_FRACTION_OFFSET
-#define LPO_INIT_DIVIDEND_FRACTION_VALUE_MSB WLAN_LPO_INIT_DIVIDEND_FRACTION_VALUE_MSB
-#define LPO_INIT_DIVIDEND_FRACTION_VALUE_LSB WLAN_LPO_INIT_DIVIDEND_FRACTION_VALUE_LSB
-#define LPO_INIT_DIVIDEND_FRACTION_VALUE_MASK WLAN_LPO_INIT_DIVIDEND_FRACTION_VALUE_MASK
-#define LPO_INIT_DIVIDEND_FRACTION_VALUE_GET(x) WLAN_LPO_INIT_DIVIDEND_FRACTION_VALUE_GET(x)
-#define LPO_INIT_DIVIDEND_FRACTION_VALUE_SET(x) WLAN_LPO_INIT_DIVIDEND_FRACTION_VALUE_SET(x)
-#define LPO_CAL_ADDRESS WLAN_LPO_CAL_ADDRESS
-#define LPO_CAL_OFFSET WLAN_LPO_CAL_OFFSET
-#define LPO_CAL_ENABLE_MSB WLAN_LPO_CAL_ENABLE_MSB
-#define LPO_CAL_ENABLE_LSB WLAN_LPO_CAL_ENABLE_LSB
-#define LPO_CAL_ENABLE_MASK WLAN_LPO_CAL_ENABLE_MASK
-#define LPO_CAL_ENABLE_GET(x) WLAN_LPO_CAL_ENABLE_GET(x)
-#define LPO_CAL_ENABLE_SET(x) WLAN_LPO_CAL_ENABLE_SET(x)
-#define LPO_CAL_COUNT_MSB WLAN_LPO_CAL_COUNT_MSB
-#define LPO_CAL_COUNT_LSB WLAN_LPO_CAL_COUNT_LSB
-#define LPO_CAL_COUNT_MASK WLAN_LPO_CAL_COUNT_MASK
-#define LPO_CAL_COUNT_GET(x) WLAN_LPO_CAL_COUNT_GET(x)
-#define LPO_CAL_COUNT_SET(x) WLAN_LPO_CAL_COUNT_SET(x)
-
-#endif
diff --git a/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/rtc_wlan_reg.h b/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/rtc_wlan_reg.h
deleted file mode 100644
index 5c048ff51b07..000000000000
--- a/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/rtc_wlan_reg.h
+++ /dev/null
@@ -1,162 +0,0 @@
-// ------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-// ------------------------------------------------------------------
-//===================================================================
-// Author(s): ="Atheros"
-//===================================================================
-
-
-#ifndef _RTC_WLAN_REG_REG_H_
-#define _RTC_WLAN_REG_REG_H_
-
-#define WLAN_RESET_CONTROL_ADDRESS 0x00000000
-#define WLAN_RESET_CONTROL_OFFSET 0x00000000
-#define WLAN_RESET_CONTROL_DEBUG_UART_RST_MSB 14
-#define WLAN_RESET_CONTROL_DEBUG_UART_RST_LSB 14
-#define WLAN_RESET_CONTROL_DEBUG_UART_RST_MASK 0x00004000
-#define WLAN_RESET_CONTROL_DEBUG_UART_RST_GET(x) (((x) & WLAN_RESET_CONTROL_DEBUG_UART_RST_MASK) >> WLAN_RESET_CONTROL_DEBUG_UART_RST_LSB)
-#define WLAN_RESET_CONTROL_DEBUG_UART_RST_SET(x) (((x) << WLAN_RESET_CONTROL_DEBUG_UART_RST_LSB) & WLAN_RESET_CONTROL_DEBUG_UART_RST_MASK)
-#define WLAN_RESET_CONTROL_BB_COLD_RST_MSB 13
-#define WLAN_RESET_CONTROL_BB_COLD_RST_LSB 13
-#define WLAN_RESET_CONTROL_BB_COLD_RST_MASK 0x00002000
-#define WLAN_RESET_CONTROL_BB_COLD_RST_GET(x) (((x) & WLAN_RESET_CONTROL_BB_COLD_RST_MASK) >> WLAN_RESET_CONTROL_BB_COLD_RST_LSB)
-#define WLAN_RESET_CONTROL_BB_COLD_RST_SET(x) (((x) << WLAN_RESET_CONTROL_BB_COLD_RST_LSB) & WLAN_RESET_CONTROL_BB_COLD_RST_MASK)
-#define WLAN_RESET_CONTROL_BB_WARM_RST_MSB 12
-#define WLAN_RESET_CONTROL_BB_WARM_RST_LSB 12
-#define WLAN_RESET_CONTROL_BB_WARM_RST_MASK 0x00001000
-#define WLAN_RESET_CONTROL_BB_WARM_RST_GET(x) (((x) & WLAN_RESET_CONTROL_BB_WARM_RST_MASK) >> WLAN_RESET_CONTROL_BB_WARM_RST_LSB)
-#define WLAN_RESET_CONTROL_BB_WARM_RST_SET(x) (((x) << WLAN_RESET_CONTROL_BB_WARM_RST_LSB) & WLAN_RESET_CONTROL_BB_WARM_RST_MASK)
-#define WLAN_RESET_CONTROL_CPU_INIT_RESET_MSB 11
-#define WLAN_RESET_CONTROL_CPU_INIT_RESET_LSB 11
-#define WLAN_RESET_CONTROL_CPU_INIT_RESET_MASK 0x00000800
-#define WLAN_RESET_CONTROL_CPU_INIT_RESET_GET(x) (((x) & WLAN_RESET_CONTROL_CPU_INIT_RESET_MASK) >> WLAN_RESET_CONTROL_CPU_INIT_RESET_LSB)
-#define WLAN_RESET_CONTROL_CPU_INIT_RESET_SET(x) (((x) << WLAN_RESET_CONTROL_CPU_INIT_RESET_LSB) & WLAN_RESET_CONTROL_CPU_INIT_RESET_MASK)
-#define WLAN_RESET_CONTROL_VMC_REMAP_RESET_MSB 10
-#define WLAN_RESET_CONTROL_VMC_REMAP_RESET_LSB 10
-#define WLAN_RESET_CONTROL_VMC_REMAP_RESET_MASK 0x00000400
-#define WLAN_RESET_CONTROL_VMC_REMAP_RESET_GET(x) (((x) & WLAN_RESET_CONTROL_VMC_REMAP_RESET_MASK) >> WLAN_RESET_CONTROL_VMC_REMAP_RESET_LSB)
-#define WLAN_RESET_CONTROL_VMC_REMAP_RESET_SET(x) (((x) << WLAN_RESET_CONTROL_VMC_REMAP_RESET_LSB) & WLAN_RESET_CONTROL_VMC_REMAP_RESET_MASK)
-#define WLAN_RESET_CONTROL_RST_OUT_MSB 9
-#define WLAN_RESET_CONTROL_RST_OUT_LSB 9
-#define WLAN_RESET_CONTROL_RST_OUT_MASK 0x00000200
-#define WLAN_RESET_CONTROL_RST_OUT_GET(x) (((x) & WLAN_RESET_CONTROL_RST_OUT_MASK) >> WLAN_RESET_CONTROL_RST_OUT_LSB)
-#define WLAN_RESET_CONTROL_RST_OUT_SET(x) (((x) << WLAN_RESET_CONTROL_RST_OUT_LSB) & WLAN_RESET_CONTROL_RST_OUT_MASK)
-#define WLAN_RESET_CONTROL_COLD_RST_MSB 8
-#define WLAN_RESET_CONTROL_COLD_RST_LSB 8
-#define WLAN_RESET_CONTROL_COLD_RST_MASK 0x00000100
-#define WLAN_RESET_CONTROL_COLD_RST_GET(x) (((x) & WLAN_RESET_CONTROL_COLD_RST_MASK) >> WLAN_RESET_CONTROL_COLD_RST_LSB)
-#define WLAN_RESET_CONTROL_COLD_RST_SET(x) (((x) << WLAN_RESET_CONTROL_COLD_RST_LSB) & WLAN_RESET_CONTROL_COLD_RST_MASK)
-#define WLAN_RESET_CONTROL_WARM_RST_MSB 7
-#define WLAN_RESET_CONTROL_WARM_RST_LSB 7
-#define WLAN_RESET_CONTROL_WARM_RST_MASK 0x00000080
-#define WLAN_RESET_CONTROL_WARM_RST_GET(x) (((x) & WLAN_RESET_CONTROL_WARM_RST_MASK) >> WLAN_RESET_CONTROL_WARM_RST_LSB)
-#define WLAN_RESET_CONTROL_WARM_RST_SET(x) (((x) << WLAN_RESET_CONTROL_WARM_RST_LSB) & WLAN_RESET_CONTROL_WARM_RST_MASK)
-#define WLAN_RESET_CONTROL_CPU_WARM_RST_MSB 6
-#define WLAN_RESET_CONTROL_CPU_WARM_RST_LSB 6
-#define WLAN_RESET_CONTROL_CPU_WARM_RST_MASK 0x00000040
-#define WLAN_RESET_CONTROL_CPU_WARM_RST_GET(x) (((x) & WLAN_RESET_CONTROL_CPU_WARM_RST_MASK) >> WLAN_RESET_CONTROL_CPU_WARM_RST_LSB)
-#define WLAN_RESET_CONTROL_CPU_WARM_RST_SET(x) (((x) << WLAN_RESET_CONTROL_CPU_WARM_RST_LSB) & WLAN_RESET_CONTROL_CPU_WARM_RST_MASK)
-#define WLAN_RESET_CONTROL_MAC_COLD_RST_MSB 5
-#define WLAN_RESET_CONTROL_MAC_COLD_RST_LSB 5
-#define WLAN_RESET_CONTROL_MAC_COLD_RST_MASK 0x00000020
-#define WLAN_RESET_CONTROL_MAC_COLD_RST_GET(x) (((x) & WLAN_RESET_CONTROL_MAC_COLD_RST_MASK) >> WLAN_RESET_CONTROL_MAC_COLD_RST_LSB)
-#define WLAN_RESET_CONTROL_MAC_COLD_RST_SET(x) (((x) << WLAN_RESET_CONTROL_MAC_COLD_RST_LSB) & WLAN_RESET_CONTROL_MAC_COLD_RST_MASK)
-#define WLAN_RESET_CONTROL_MAC_WARM_RST_MSB 4
-#define WLAN_RESET_CONTROL_MAC_WARM_RST_LSB 4
-#define WLAN_RESET_CONTROL_MAC_WARM_RST_MASK 0x00000010
-#define WLAN_RESET_CONTROL_MAC_WARM_RST_GET(x) (((x) & WLAN_RESET_CONTROL_MAC_WARM_RST_MASK) >> WLAN_RESET_CONTROL_MAC_WARM_RST_LSB)
-#define WLAN_RESET_CONTROL_MAC_WARM_RST_SET(x) (((x) << WLAN_RESET_CONTROL_MAC_WARM_RST_LSB) & WLAN_RESET_CONTROL_MAC_WARM_RST_MASK)
-#define WLAN_RESET_CONTROL_MBOX_RST_MSB 2
-#define WLAN_RESET_CONTROL_MBOX_RST_LSB 2
-#define WLAN_RESET_CONTROL_MBOX_RST_MASK 0x00000004
-#define WLAN_RESET_CONTROL_MBOX_RST_GET(x) (((x) & WLAN_RESET_CONTROL_MBOX_RST_MASK) >> WLAN_RESET_CONTROL_MBOX_RST_LSB)
-#define WLAN_RESET_CONTROL_MBOX_RST_SET(x) (((x) << WLAN_RESET_CONTROL_MBOX_RST_LSB) & WLAN_RESET_CONTROL_MBOX_RST_MASK)
-#define WLAN_RESET_CONTROL_UART_RST_MSB 1
-#define WLAN_RESET_CONTROL_UART_RST_LSB 1
-#define WLAN_RESET_CONTROL_UART_RST_MASK 0x00000002
-#define WLAN_RESET_CONTROL_UART_RST_GET(x) (((x) & WLAN_RESET_CONTROL_UART_RST_MASK) >> WLAN_RESET_CONTROL_UART_RST_LSB)
-#define WLAN_RESET_CONTROL_UART_RST_SET(x) (((x) << WLAN_RESET_CONTROL_UART_RST_LSB) & WLAN_RESET_CONTROL_UART_RST_MASK)
-#define WLAN_RESET_CONTROL_SI0_RST_MSB 0
-#define WLAN_RESET_CONTROL_SI0_RST_LSB 0
-#define WLAN_RESET_CONTROL_SI0_RST_MASK 0x00000001
-#define WLAN_RESET_CONTROL_SI0_RST_GET(x) (((x) & WLAN_RESET_CONTROL_SI0_RST_MASK) >> WLAN_RESET_CONTROL_SI0_RST_LSB)
-#define WLAN_RESET_CONTROL_SI0_RST_SET(x) (((x) << WLAN_RESET_CONTROL_SI0_RST_LSB) & WLAN_RESET_CONTROL_SI0_RST_MASK)
-
-#define WLAN_CPU_CLOCK_ADDRESS 0x00000020
-#define WLAN_CPU_CLOCK_OFFSET 0x00000020
-#define WLAN_CPU_CLOCK_STANDARD_MSB 1
-#define WLAN_CPU_CLOCK_STANDARD_LSB 0
-#define WLAN_CPU_CLOCK_STANDARD_MASK 0x00000003
-#define WLAN_CPU_CLOCK_STANDARD_GET(x) (((x) & WLAN_CPU_CLOCK_STANDARD_MASK) >> WLAN_CPU_CLOCK_STANDARD_LSB)
-#define WLAN_CPU_CLOCK_STANDARD_SET(x) (((x) << WLAN_CPU_CLOCK_STANDARD_LSB) & WLAN_CPU_CLOCK_STANDARD_MASK)
-
-#define WLAN_CLOCK_CONTROL_ADDRESS 0x00000028
-#define WLAN_CLOCK_CONTROL_OFFSET 0x00000028
-#define WLAN_CLOCK_CONTROL_LF_CLK32_MSB 2
-#define WLAN_CLOCK_CONTROL_LF_CLK32_LSB 2
-#define WLAN_CLOCK_CONTROL_LF_CLK32_MASK 0x00000004
-#define WLAN_CLOCK_CONTROL_LF_CLK32_GET(x) (((x) & WLAN_CLOCK_CONTROL_LF_CLK32_MASK) >> WLAN_CLOCK_CONTROL_LF_CLK32_LSB)
-#define WLAN_CLOCK_CONTROL_LF_CLK32_SET(x) (((x) << WLAN_CLOCK_CONTROL_LF_CLK32_LSB) & WLAN_CLOCK_CONTROL_LF_CLK32_MASK)
-#define WLAN_CLOCK_CONTROL_SI0_CLK_MSB 0
-#define WLAN_CLOCK_CONTROL_SI0_CLK_LSB 0
-#define WLAN_CLOCK_CONTROL_SI0_CLK_MASK 0x00000001
-#define WLAN_CLOCK_CONTROL_SI0_CLK_GET(x) (((x) & WLAN_CLOCK_CONTROL_SI0_CLK_MASK) >> WLAN_CLOCK_CONTROL_SI0_CLK_LSB)
-#define WLAN_CLOCK_CONTROL_SI0_CLK_SET(x) (((x) << WLAN_CLOCK_CONTROL_SI0_CLK_LSB) & WLAN_CLOCK_CONTROL_SI0_CLK_MASK)
-
-#define WLAN_SYSTEM_SLEEP_ADDRESS 0x000000c4
-#define WLAN_SYSTEM_SLEEP_OFFSET 0x000000c4
-#define WLAN_SYSTEM_SLEEP_HOST_IF_MSB 4
-#define WLAN_SYSTEM_SLEEP_HOST_IF_LSB 4
-#define WLAN_SYSTEM_SLEEP_HOST_IF_MASK 0x00000010
-#define WLAN_SYSTEM_SLEEP_HOST_IF_GET(x) (((x) & WLAN_SYSTEM_SLEEP_HOST_IF_MASK) >> WLAN_SYSTEM_SLEEP_HOST_IF_LSB)
-#define WLAN_SYSTEM_SLEEP_HOST_IF_SET(x) (((x) << WLAN_SYSTEM_SLEEP_HOST_IF_LSB) & WLAN_SYSTEM_SLEEP_HOST_IF_MASK)
-#define WLAN_SYSTEM_SLEEP_MBOX_MSB 3
-#define WLAN_SYSTEM_SLEEP_MBOX_LSB 3
-#define WLAN_SYSTEM_SLEEP_MBOX_MASK 0x00000008
-#define WLAN_SYSTEM_SLEEP_MBOX_GET(x) (((x) & WLAN_SYSTEM_SLEEP_MBOX_MASK) >> WLAN_SYSTEM_SLEEP_MBOX_LSB)
-#define WLAN_SYSTEM_SLEEP_MBOX_SET(x) (((x) << WLAN_SYSTEM_SLEEP_MBOX_LSB) & WLAN_SYSTEM_SLEEP_MBOX_MASK)
-#define WLAN_SYSTEM_SLEEP_MAC_IF_MSB 2
-#define WLAN_SYSTEM_SLEEP_MAC_IF_LSB 2
-#define WLAN_SYSTEM_SLEEP_MAC_IF_MASK 0x00000004
-#define WLAN_SYSTEM_SLEEP_MAC_IF_GET(x) (((x) & WLAN_SYSTEM_SLEEP_MAC_IF_MASK) >> WLAN_SYSTEM_SLEEP_MAC_IF_LSB)
-#define WLAN_SYSTEM_SLEEP_MAC_IF_SET(x) (((x) << WLAN_SYSTEM_SLEEP_MAC_IF_LSB) & WLAN_SYSTEM_SLEEP_MAC_IF_MASK)
-#define WLAN_SYSTEM_SLEEP_LIGHT_MSB 1
-#define WLAN_SYSTEM_SLEEP_LIGHT_LSB 1
-#define WLAN_SYSTEM_SLEEP_LIGHT_MASK 0x00000002
-#define WLAN_SYSTEM_SLEEP_LIGHT_GET(x) (((x) & WLAN_SYSTEM_SLEEP_LIGHT_MASK) >> WLAN_SYSTEM_SLEEP_LIGHT_LSB)
-#define WLAN_SYSTEM_SLEEP_LIGHT_SET(x) (((x) << WLAN_SYSTEM_SLEEP_LIGHT_LSB) & WLAN_SYSTEM_SLEEP_LIGHT_MASK)
-#define WLAN_SYSTEM_SLEEP_DISABLE_MSB 0
-#define WLAN_SYSTEM_SLEEP_DISABLE_LSB 0
-#define WLAN_SYSTEM_SLEEP_DISABLE_MASK 0x00000001
-#define WLAN_SYSTEM_SLEEP_DISABLE_GET(x) (((x) & WLAN_SYSTEM_SLEEP_DISABLE_MASK) >> WLAN_SYSTEM_SLEEP_DISABLE_LSB)
-#define WLAN_SYSTEM_SLEEP_DISABLE_SET(x) (((x) << WLAN_SYSTEM_SLEEP_DISABLE_LSB) & WLAN_SYSTEM_SLEEP_DISABLE_MASK)
-
-#define WLAN_LPO_CAL_ADDRESS 0x000000e0
-#define WLAN_LPO_CAL_OFFSET 0x000000e0
-#define WLAN_LPO_CAL_ENABLE_MSB 20
-#define WLAN_LPO_CAL_ENABLE_LSB 20
-#define WLAN_LPO_CAL_ENABLE_MASK 0x00100000
-#define WLAN_LPO_CAL_ENABLE_GET(x) (((x) & WLAN_LPO_CAL_ENABLE_MASK) >> WLAN_LPO_CAL_ENABLE_LSB)
-#define WLAN_LPO_CAL_ENABLE_SET(x) (((x) << WLAN_LPO_CAL_ENABLE_LSB) & WLAN_LPO_CAL_ENABLE_MASK)
-#define WLAN_LPO_CAL_COUNT_MSB 19
-#define WLAN_LPO_CAL_COUNT_LSB 0
-#define WLAN_LPO_CAL_COUNT_MASK 0x000fffff
-#define WLAN_LPO_CAL_COUNT_GET(x) (((x) & WLAN_LPO_CAL_COUNT_MASK) >> WLAN_LPO_CAL_COUNT_LSB)
-#define WLAN_LPO_CAL_COUNT_SET(x) (((x) << WLAN_LPO_CAL_COUNT_LSB) & WLAN_LPO_CAL_COUNT_MASK)
-
-#endif /* _RTC_WLAN_REG_H_ */
diff --git a/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/uart_reg.h b/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/uart_reg.h
deleted file mode 100644
index 302b20bc1bad..000000000000
--- a/drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/uart_reg.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// ------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-// ------------------------------------------------------------------
-//===================================================================
-// Author(s): ="Atheros"
-//===================================================================
-
-
-#ifndef _UART_REG_REG_H_
-#define _UART_REG_REG_H_
-
-#define UART_CLKDIV_ADDRESS 0x00000008
-#define UART_CLKDIV_OFFSET 0x00000008
-#define UART_CLKDIV_CLK_SCALE_MSB 23
-#define UART_CLKDIV_CLK_SCALE_LSB 16
-#define UART_CLKDIV_CLK_SCALE_MASK 0x00ff0000
-#define UART_CLKDIV_CLK_SCALE_GET(x) (((x) & UART_CLKDIV_CLK_SCALE_MASK) >> UART_CLKDIV_CLK_SCALE_LSB)
-#define UART_CLKDIV_CLK_SCALE_SET(x) (((x) << UART_CLKDIV_CLK_SCALE_LSB) & UART_CLKDIV_CLK_SCALE_MASK)
-#define UART_CLKDIV_CLK_STEP_MSB 15
-#define UART_CLKDIV_CLK_STEP_LSB 0
-#define UART_CLKDIV_CLK_STEP_MASK 0x0000ffff
-#define UART_CLKDIV_CLK_STEP_GET(x) (((x) & UART_CLKDIV_CLK_STEP_MASK) >> UART_CLKDIV_CLK_STEP_LSB)
-#define UART_CLKDIV_CLK_STEP_SET(x) (((x) << UART_CLKDIV_CLK_STEP_LSB) & UART_CLKDIV_CLK_STEP_MASK)
-
-#endif /* _UART_REG_H_ */
diff --git a/drivers/staging/ath6kl/include/common/athdefs.h b/drivers/staging/ath6kl/include/common/athdefs.h
deleted file mode 100644
index 74922481e065..000000000000
--- a/drivers/staging/ath6kl/include/common/athdefs.h
+++ /dev/null
@@ -1,75 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="athdefs.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef __ATHDEFS_H__
-#define __ATHDEFS_H__
-
-/*
- * This file contains definitions that may be used across both
- * Host and Target software. Nothing here is module-dependent
- * or platform-dependent.
- */
-
-/*
- * Generic error codes that can be used by hw, sta, ap, sim, dk
- * and any other environments.
- * Feel free to add any more non-zero codes that you need.
- */
-
-#define A_ERROR (-1) /* Generic error return */
-#define A_DEVICE_NOT_FOUND 1 /* not able to find PCI device */
-#define A_NO_MEMORY 2 /* not able to allocate memory,
- * not avail#defineable */
-#define A_MEMORY_NOT_AVAIL 3 /* memory region is not free for
- * mapping */
-#define A_NO_FREE_DESC 4 /* no free descriptors available */
-#define A_BAD_ADDRESS 5 /* address does not match descriptor */
-#define A_WIN_DRIVER_ERROR 6 /* used in NT_HW version,
- * if problem at init */
-#define A_REGS_NOT_MAPPED 7 /* registers not correctly mapped */
-#define A_EPERM 8 /* Not superuser */
-#define A_EACCES 0 /* Access denied */
-#define A_ENOENT 10 /* No such entry, search failed, etc. */
-#define A_EEXIST 11 /* The object already exists
- * (can't create) */
-#define A_EFAULT 12 /* Bad address fault */
-#define A_EBUSY 13 /* Object is busy */
-#define A_EINVAL 14 /* Invalid parameter */
-#define A_EMSGSIZE 15 /* Bad message buffer length */
-#define A_ECANCELED 16 /* Operation canceled */
-#define A_ENOTSUP 17 /* Operation not supported */
-#define A_ECOMM 18 /* Communication error on send */
-#define A_EPROTO 19 /* Protocol error */
-#define A_ENODEV 20 /* No such device */
-#define A_EDEVNOTUP 21 /* device is not UP */
-#define A_NO_RESOURCE 22 /* No resources for
- * requested operation */
-#define A_HARDWARE 23 /* Hardware failure */
-#define A_PENDING 24 /* Asynchronous routine; will send up
- * results later
- * (typically in callback) */
-#define A_EBADCHANNEL 25 /* The channel cannot be used */
-#define A_DECRYPT_ERROR 26 /* Decryption error */
-#define A_PHY_ERROR 27 /* RX PHY error */
-#define A_CONSUMED 28 /* Object was consumed */
-
-#endif /* __ATHDEFS_H__ */
diff --git a/drivers/staging/ath6kl/include/common/bmi_msg.h b/drivers/staging/ath6kl/include/common/bmi_msg.h
deleted file mode 100644
index 84e8db569a9f..000000000000
--- a/drivers/staging/ath6kl/include/common/bmi_msg.h
+++ /dev/null
@@ -1,233 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//
-// Author(s): ="Atheros"
-//------------------------------------------------------------------------------
-
-#ifndef __BMI_MSG_H__
-#define __BMI_MSG_H__
-
-/*
- * Bootloader Messaging Interface (BMI)
- *
- * BMI is a very simple messaging interface used during initialization
- * to read memory, write memory, execute code, and to define an
- * application entry PC.
- *
- * It is used to download an application to AR6K, to provide
- * patches to code that is already resident on AR6K, and generally
- * to examine and modify state. The Host has an opportunity to use
- * BMI only once during bootup. Once the Host issues a BMI_DONE
- * command, this opportunity ends.
- *
- * The Host writes BMI requests to mailbox0, and reads BMI responses
- * from mailbox0. BMI requests all begin with a command
- * (see below for specific commands), and are followed by
- * command-specific data.
- *
- * Flow control:
- * The Host can only issue a command once the Target gives it a
- * "BMI Command Credit", using AR6K Counter #4. As soon as the
- * Target has completed a command, it issues another BMI Command
- * Credit (so the Host can issue the next command).
- *
- * BMI handles all required Target-side cache flushing.
- */
-
-
-/* Maximum data size used for BMI transfers */
-#define BMI_DATASZ_MAX 256
-
-/* BMI Commands */
-
-#define BMI_NO_COMMAND 0
-
-#define BMI_DONE 1
- /*
- * Semantics: Host is done using BMI
- * Request format:
- * u32 command (BMI_DONE)
- * Response format: none
- */
-
-#define BMI_READ_MEMORY 2
- /*
- * Semantics: Host reads AR6K memory
- * Request format:
- * u32 command (BMI_READ_MEMORY)
- * u32 address
- * u32 length, at most BMI_DATASZ_MAX
- * Response format:
- * u8 data[length]
- */
-
-#define BMI_WRITE_MEMORY 3
- /*
- * Semantics: Host writes AR6K memory
- * Request format:
- * u32 command (BMI_WRITE_MEMORY)
- * u32 address
- * u32 length, at most BMI_DATASZ_MAX
- * u8 data[length]
- * Response format: none
- */
-
-#define BMI_EXECUTE 4
- /*
- * Semantics: Causes AR6K to execute code
- * Request format:
- * u32 command (BMI_EXECUTE)
- * u32 address
- * u32 parameter
- * Response format:
- * u32 return value
- */
-
-#define BMI_SET_APP_START 5
- /*
- * Semantics: Set Target application starting address
- * Request format:
- * u32 command (BMI_SET_APP_START)
- * u32 address
- * Response format: none
- */
-
-#define BMI_READ_SOC_REGISTER 6
- /*
- * Semantics: Read a 32-bit Target SOC register.
- * Request format:
- * u32 command (BMI_READ_REGISTER)
- * u32 address
- * Response format:
- * u32 value
- */
-
-#define BMI_WRITE_SOC_REGISTER 7
- /*
- * Semantics: Write a 32-bit Target SOC register.
- * Request format:
- * u32 command (BMI_WRITE_REGISTER)
- * u32 address
- * u32 value
- *
- * Response format: none
- */
-
-#define BMI_GET_TARGET_ID 8
-#define BMI_GET_TARGET_INFO 8
- /*
- * Semantics: Fetch the 4-byte Target information
- * Request format:
- * u32 command (BMI_GET_TARGET_ID/INFO)
- * Response format1 (old firmware):
- * u32 TargetVersionID
- * Response format2 (newer firmware):
- * u32 TARGET_VERSION_SENTINAL
- * struct bmi_target_info;
- */
-
-PREPACK struct bmi_target_info {
- u32 target_info_byte_count; /* size of this structure */
- u32 target_ver; /* Target Version ID */
- u32 target_type; /* Target type */
-} POSTPACK;
-#define TARGET_VERSION_SENTINAL 0xffffffff
-#define TARGET_TYPE_AR6001 1
-#define TARGET_TYPE_AR6002 2
-#define TARGET_TYPE_AR6003 3
-
-
-#define BMI_ROMPATCH_INSTALL 9
- /*
- * Semantics: Install a ROM Patch.
- * Request format:
- * u32 command (BMI_ROMPATCH_INSTALL)
- * u32 Target ROM Address
- * u32 Target RAM Address or Value (depending on Target Type)
- * u32 Size, in bytes
- * u32 Activate? 1-->activate;
- * 0-->install but do not activate
- * Response format:
- * u32 PatchID
- */
-
-#define BMI_ROMPATCH_UNINSTALL 10
- /*
- * Semantics: Uninstall a previously-installed ROM Patch,
- * automatically deactivating, if necessary.
- * Request format:
- * u32 command (BMI_ROMPATCH_UNINSTALL)
- * u32 PatchID
- *
- * Response format: none
- */
-
-#define BMI_ROMPATCH_ACTIVATE 11
- /*
- * Semantics: Activate a list of previously-installed ROM Patches.
- * Request format:
- * u32 command (BMI_ROMPATCH_ACTIVATE)
- * u32 rompatch_count
- * u32 PatchID[rompatch_count]
- *
- * Response format: none
- */
-
-#define BMI_ROMPATCH_DEACTIVATE 12
- /*
- * Semantics: Deactivate a list of active ROM Patches.
- * Request format:
- * u32 command (BMI_ROMPATCH_DEACTIVATE)
- * u32 rompatch_count
- * u32 PatchID[rompatch_count]
- *
- * Response format: none
- */
-
-
-#define BMI_LZ_STREAM_START 13
- /*
- * Semantics: Begin an LZ-compressed stream of input
- * which is to be uncompressed by the Target to an
- * output buffer at address. The output buffer must
- * be sufficiently large to hold the uncompressed
- * output from the compressed input stream. This BMI
- * command should be followed by a series of 1 or more
- * BMI_LZ_DATA commands.
- * u32 command (BMI_LZ_STREAM_START)
- * u32 address
- * Note: Not supported on all versions of ROM firmware.
- */
-
-#define BMI_LZ_DATA 14
- /*
- * Semantics: Host writes AR6K memory with LZ-compressed
- * data which is uncompressed by the Target. This command
- * must be preceded by a BMI_LZ_STREAM_START command. A series
- * of BMI_LZ_DATA commands are considered part of a single
- * input stream until another BMI_LZ_STREAM_START is issued.
- * Request format:
- * u32 command (BMI_LZ_DATA)
- * u32 length (of compressed data),
- * at most BMI_DATASZ_MAX
- * u8 CompressedData[length]
- * Response format: none
- * Note: Not supported on all versions of ROM firmware.
- */
-
-#endif /* __BMI_MSG_H__ */
diff --git a/drivers/staging/ath6kl/include/common/cnxmgmt.h b/drivers/staging/ath6kl/include/common/cnxmgmt.h
deleted file mode 100644
index 7a902cb54831..000000000000
--- a/drivers/staging/ath6kl/include/common/cnxmgmt.h
+++ /dev/null
@@ -1,36 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="cnxmgmt.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-
-#ifndef _CNXMGMT_H_
-#define _CNXMGMT_H_
-
-typedef enum {
- CM_CONNECT_WITHOUT_SCAN = 0x0001,
- CM_CONNECT_ASSOC_POLICY_USER = 0x0002,
- CM_CONNECT_SEND_REASSOC = 0x0004,
- CM_CONNECT_WITHOUT_ROAMTABLE_UPDATE = 0x0008,
- CM_CONNECT_DO_WPA_OFFLOAD = 0x0010,
- CM_CONNECT_DO_NOT_DEAUTH = 0x0020,
-} CM_CONNECT_TYPE;
-
-#endif /* _CNXMGMT_H_ */
diff --git a/drivers/staging/ath6kl/include/common/dbglog.h b/drivers/staging/ath6kl/include/common/dbglog.h
deleted file mode 100644
index 5566e568b83d..000000000000
--- a/drivers/staging/ath6kl/include/common/dbglog.h
+++ /dev/null
@@ -1,126 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="dbglog.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-
-#ifndef _DBGLOG_H_
-#define _DBGLOG_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define DBGLOG_TIMESTAMP_OFFSET 0
-#define DBGLOG_TIMESTAMP_MASK 0x0000FFFF /* Bit 0-15. Contains bit
- 8-23 of the LF0 timer */
-#define DBGLOG_DBGID_OFFSET 16
-#define DBGLOG_DBGID_MASK 0x03FF0000 /* Bit 16-25 */
-#define DBGLOG_DBGID_NUM_MAX 256 /* Upper limit is width of mask */
-
-#define DBGLOG_MODULEID_OFFSET 26
-#define DBGLOG_MODULEID_MASK 0x3C000000 /* Bit 26-29 */
-#define DBGLOG_MODULEID_NUM_MAX 16 /* Upper limit is width of mask */
-
-/*
- * Please ensure that the definition of any new module introduced is captured
- * between the DBGLOG_MODULEID_START and DBGLOG_MODULEID_END defines. The
- * structure is required for the parser to correctly pick up the values for
- * different modules.
- */
-#define DBGLOG_MODULEID_START
-#define DBGLOG_MODULEID_INF 0
-#define DBGLOG_MODULEID_WMI 1
-#define DBGLOG_MODULEID_MISC 2
-#define DBGLOG_MODULEID_PM 3
-#define DBGLOG_MODULEID_TXRX_MGMTBUF 4
-#define DBGLOG_MODULEID_TXRX_TXBUF 5
-#define DBGLOG_MODULEID_TXRX_RXBUF 6
-#define DBGLOG_MODULEID_WOW 7
-#define DBGLOG_MODULEID_WHAL 8
-#define DBGLOG_MODULEID_DC 9
-#define DBGLOG_MODULEID_CO 10
-#define DBGLOG_MODULEID_RO 11
-#define DBGLOG_MODULEID_CM 12
-#define DBGLOG_MODULEID_MGMT 13
-#define DBGLOG_MODULEID_TMR 14
-#define DBGLOG_MODULEID_BTCOEX 15
-#define DBGLOG_MODULEID_END
-
-#define DBGLOG_NUM_ARGS_OFFSET 30
-#define DBGLOG_NUM_ARGS_MASK 0xC0000000 /* Bit 30-31 */
-#define DBGLOG_NUM_ARGS_MAX 2 /* Upper limit is width of mask */
-
-#define DBGLOG_MODULE_LOG_ENABLE_OFFSET 0
-#define DBGLOG_MODULE_LOG_ENABLE_MASK 0x0000FFFF
-
-#define DBGLOG_REPORTING_ENABLED_OFFSET 16
-#define DBGLOG_REPORTING_ENABLED_MASK 0x00010000
-
-#define DBGLOG_TIMESTAMP_RESOLUTION_OFFSET 17
-#define DBGLOG_TIMESTAMP_RESOLUTION_MASK 0x000E0000
-
-#define DBGLOG_REPORT_SIZE_OFFSET 20
-#define DBGLOG_REPORT_SIZE_MASK 0x3FF00000
-
-#define DBGLOG_LOG_BUFFER_SIZE 1500
-#define DBGLOG_DBGID_DEFINITION_LEN_MAX 90
-
-PREPACK struct dbglog_buf_s {
- struct dbglog_buf_s *next;
- u8 *buffer;
- u32 bufsize;
- u32 length;
- u32 count;
- u32 free;
-} POSTPACK;
-
-PREPACK struct dbglog_hdr_s {
- struct dbglog_buf_s *dbuf;
- u32 dropped;
-} POSTPACK;
-
-PREPACK struct dbglog_config_s {
- u32 cfgvalid; /* Mask with valid config bits */
- union {
- /* TODO: Take care of endianness */
- struct {
- u32 mmask:16; /* Mask of modules with logging on */
- u32 rep:1; /* Reporting enabled or not */
- u32 tsr:3; /* Time stamp resolution. Def: 1 ms */
- u32 size:10; /* Report size in number of messages */
- u32 reserved:2;
- } dbglog_config;
-
- u32 value;
- } u;
-} POSTPACK;
-
-#define cfgmmask u.dbglog_config.mmask
-#define cfgrep u.dbglog_config.rep
-#define cfgtsr u.dbglog_config.tsr
-#define cfgsize u.dbglog_config.size
-#define cfgvalue u.value
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _DBGLOG_H_ */
diff --git a/drivers/staging/ath6kl/include/common/dbglog_id.h b/drivers/staging/ath6kl/include/common/dbglog_id.h
deleted file mode 100644
index 15ef829cab20..000000000000
--- a/drivers/staging/ath6kl/include/common/dbglog_id.h
+++ /dev/null
@@ -1,558 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="dbglog_id.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-
-#ifndef _DBGLOG_ID_H_
-#define _DBGLOG_ID_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * The nomenclature for the debug identifiers is MODULE_DESCRIPTION.
- * Please ensure that the definition of any new debugid introduced is captured
- * between the <MODULE>_DBGID_DEFINITION_START and
- * <MODULE>_DBGID_DEFINITION_END defines. The structure is required for the
- * parser to correctly pick up the values for different debug identifiers.
- */
-
-/* INF debug identifier definitions */
-#define INF_DBGID_DEFINITION_START
-#define INF_ASSERTION_FAILED 1
-#define INF_TARGET_ID 2
-#define INF_DBGID_DEFINITION_END
-
-/* WMI debug identifier definitions */
-#define WMI_DBGID_DEFINITION_START
-#define WMI_CMD_RX_XTND_PKT_TOO_SHORT 1
-#define WMI_EXTENDED_CMD_NOT_HANDLED 2
-#define WMI_CMD_RX_PKT_TOO_SHORT 3
-#define WMI_CALLING_WMI_EXTENSION_FN 4
-#define WMI_CMD_NOT_HANDLED 5
-#define WMI_IN_SYNC 6
-#define WMI_TARGET_WMI_SYNC_CMD 7
-#define WMI_SET_SNR_THRESHOLD_PARAMS 8
-#define WMI_SET_RSSI_THRESHOLD_PARAMS 9
-#define WMI_SET_LQ_TRESHOLD_PARAMS 10
-#define WMI_TARGET_CREATE_PSTREAM_CMD 11
-#define WMI_WI_DTM_INUSE 12
-#define WMI_TARGET_DELETE_PSTREAM_CMD 13
-#define WMI_TARGET_IMPLICIT_DELETE_PSTREAM_CMD 14
-#define WMI_TARGET_GET_BIT_RATE_CMD 15
-#define WMI_GET_RATE_MASK_CMD_FIX_RATE_MASK_IS 16
-#define WMI_TARGET_GET_AVAILABLE_CHANNELS_CMD 17
-#define WMI_TARGET_GET_TX_PWR_CMD 18
-#define WMI_FREE_EVBUF_WMIBUF 19
-#define WMI_FREE_EVBUF_DATABUF 20
-#define WMI_FREE_EVBUF_BADFLAG 21
-#define WMI_HTC_RX_ERROR_DATA_PACKET 22
-#define WMI_HTC_RX_SYNC_PAUSING_FOR_MBOX 23
-#define WMI_INCORRECT_WMI_DATA_HDR_DROPPING_PKT 24
-#define WMI_SENDING_READY_EVENT 25
-#define WMI_SETPOWER_MDOE_TO_MAXPERF 26
-#define WMI_SETPOWER_MDOE_TO_REC 27
-#define WMI_BSSINFO_EVENT_FROM 28
-#define WMI_TARGET_GET_STATS_CMD 29
-#define WMI_SENDING_SCAN_COMPLETE_EVENT 30
-#define WMI_SENDING_RSSI_INDB_THRESHOLD_EVENT 31
-#define WMI_SENDING_RSSI_INDBM_THRESHOLD_EVENT 32
-#define WMI_SENDING_LINK_QUALITY_THRESHOLD_EVENT 33
-#define WMI_SENDING_ERROR_REPORT_EVENT 34
-#define WMI_SENDING_CAC_EVENT 35
-#define WMI_TARGET_GET_ROAM_TABLE_CMD 36
-#define WMI_TARGET_GET_ROAM_DATA_CMD 37
-#define WMI_SENDING_GPIO_INTR_EVENT 38
-#define WMI_SENDING_GPIO_ACK_EVENT 39
-#define WMI_SENDING_GPIO_DATA_EVENT 40
-#define WMI_CMD_RX 41
-#define WMI_CMD_RX_XTND 42
-#define WMI_EVENT_SEND 43
-#define WMI_EVENT_SEND_XTND 44
-#define WMI_CMD_PARAMS_DUMP_START 45
-#define WMI_CMD_PARAMS_DUMP_END 46
-#define WMI_CMD_PARAMS 47
-#define WMI_DBGID_DEFINITION_END
-
-/* MISC debug identifier definitions */
-#define MISC_DBGID_DEFINITION_START
-#define MISC_WLAN_SCHEDULER_EVENT_REGISTER_ERROR 1
-#define TLPM_INIT 2
-#define TLPM_FILTER_POWER_STATE 3
-#define TLPM_NOTIFY_NOT_IDLE 4
-#define TLPM_TIMEOUT_IDLE_HANDLER 5
-#define TLPM_TIMEOUT_WAKEUP_HANDLER 6
-#define TLPM_WAKEUP_SIGNAL_HANDLER 7
-#define TLPM_UNEXPECTED_GPIO_INTR_ERROR 8
-#define TLPM_BREAK_ON_NOT_RECEIVED_ERROR 9
-#define TLPM_BREAK_OFF_NOT_RECIVED_ERROR 10
-#define TLPM_ACK_GPIO_INTR 11
-#define TLPM_ON 12
-#define TLPM_OFF 13
-#define TLPM_WAKEUP_FROM_HOST 14
-#define TLPM_WAKEUP_FROM_BT 15
-#define TLPM_TX_BREAK_RECIVED 16
-#define TLPM_IDLE_TIMER_NOT_RUNNING 17
-#define MISC_DBGID_DEFINITION_END
-
-/* TXRX debug identifier definitions */
-#define TXRX_TXBUF_DBGID_DEFINITION_START
-#define TXRX_TXBUF_ALLOCATE_BUF 1
-#define TXRX_TXBUF_QUEUE_BUF_TO_MBOX 2
-#define TXRX_TXBUF_QUEUE_BUF_TO_TXQ 3
-#define TXRX_TXBUF_TXQ_DEPTH 4
-#define TXRX_TXBUF_IBSS_QUEUE_TO_SFQ 5
-#define TXRX_TXBUF_IBSS_QUEUE_TO_TXQ_FRM_SFQ 6
-#define TXRX_TXBUF_INITIALIZE_TIMER 7
-#define TXRX_TXBUF_ARM_TIMER 8
-#define TXRX_TXBUF_DISARM_TIMER 9
-#define TXRX_TXBUF_UNINITIALIZE_TIMER 10
-#define TXRX_TXBUF_DBGID_DEFINITION_END
-
-#define TXRX_RXBUF_DBGID_DEFINITION_START
-#define TXRX_RXBUF_ALLOCATE_BUF 1
-#define TXRX_RXBUF_QUEUE_TO_HOST 2
-#define TXRX_RXBUF_QUEUE_TO_WLAN 3
-#define TXRX_RXBUF_ZERO_LEN_BUF 4
-#define TXRX_RXBUF_QUEUE_TO_HOST_LASTBUF_IN_RXCHAIN 5
-#define TXRX_RXBUF_LASTBUF_IN_RXCHAIN_ZEROBUF 6
-#define TXRX_RXBUF_QUEUE_EMPTY_QUEUE_TO_WLAN 7
-#define TXRX_RXBUF_SEND_TO_RECV_MGMT 8
-#define TXRX_RXBUF_SEND_TO_IEEE_LAYER 9
-#define TXRX_RXBUF_REQUEUE_ERROR 10
-#define TXRX_RXBUF_DBGID_DEFINITION_END
-
-#define TXRX_MGMTBUF_DBGID_DEFINITION_START
-#define TXRX_MGMTBUF_ALLOCATE_BUF 1
-#define TXRX_MGMTBUF_ALLOCATE_SM_BUF 2
-#define TXRX_MGMTBUF_ALLOCATE_RMBUF 3
-#define TXRX_MGMTBUF_GET_BUF 4
-#define TXRX_MGMTBUF_GET_SM_BUF 5
-#define TXRX_MGMTBUF_QUEUE_BUF_TO_TXQ 6
-#define TXRX_MGMTBUF_REAPED_BUF 7
-#define TXRX_MGMTBUF_REAPED_SM_BUF 8
-#define TXRX_MGMTBUF_WAIT_FOR_TXQ_DRAIN 9
-#define TXRX_MGMTBUF_WAIT_FOR_TXQ_SFQ_DRAIN 10
-#define TXRX_MGMTBUF_ENQUEUE_INTO_DATA_SFQ 11
-#define TXRX_MGMTBUF_DEQUEUE_FROM_DATA_SFQ 12
-#define TXRX_MGMTBUF_PAUSE_DATA_TXQ 13
-#define TXRX_MGMTBUF_RESUME_DATA_TXQ 14
-#define TXRX_MGMTBUF_WAIT_FORTXQ_DRAIN_TIMEOUT 15
-#define TXRX_MGMTBUF_DRAINQ 16
-#define TXRX_MGMTBUF_INDICATE_Q_DRAINED 17
-#define TXRX_MGMTBUF_ENQUEUE_INTO_HW_SFQ 18
-#define TXRX_MGMTBUF_DEQUEUE_FROM_HW_SFQ 19
-#define TXRX_MGMTBUF_PAUSE_HW_TXQ 20
-#define TXRX_MGMTBUF_RESUME_HW_TXQ 21
-#define TXRX_MGMTBUF_TEAR_DOWN_BA 22
-#define TXRX_MGMTBUF_PROCESS_ADDBA_REQ 23
-#define TXRX_MGMTBUF_PROCESS_DELBA 24
-#define TXRX_MGMTBUF_PERFORM_BA 25
-#define TXRX_MGMTBUF_WLAN_RESET_ON_ERROR 26
-#define TXRX_MGMTBUF_DBGID_DEFINITION_END
-
-/* PM (Power Module) debug identifier definitions */
-#define PM_DBGID_DEFINITION_START
-#define PM_INIT 1
-#define PM_ENABLE 2
-#define PM_SET_STATE 3
-#define PM_SET_POWERMODE 4
-#define PM_CONN_NOTIFY 5
-#define PM_REF_COUNT_NEGATIVE 6
-#define PM_INFRA_STA_APSD_ENABLE 7
-#define PM_INFRA_STA_UPDATE_APSD_STATE 8
-#define PM_CHAN_OP_REQ 9
-#define PM_SET_MY_BEACON_POLICY 10
-#define PM_SET_ALL_BEACON_POLICY 11
-#define PM_INFRA_STA_SET_PM_PARAMS1 12
-#define PM_INFRA_STA_SET_PM_PARAMS2 13
-#define PM_ADHOC_SET_PM_CAPS_FAIL 14
-#define PM_ADHOC_UNKNOWN_IBSS_ATTRIB_ID 15
-#define PM_ADHOC_SET_PM_PARAMS 16
-#define PM_ADHOC_STATE1 18
-#define PM_ADHOC_STATE2 19
-#define PM_ADHOC_CONN_MAP 20
-#define PM_FAKE_SLEEP 21
-#define PM_AP_STATE1 22
-#define PM_AP_SET_PM_PARAMS 23
-#define PM_DBGID_DEFINITION_END
-
-/* Wake on Wireless debug identifier definitions */
-#define WOW_DBGID_DEFINITION_START
-#define WOW_INIT 1
-#define WOW_GET_CONFIG_DSET 2
-#define WOW_NO_CONFIG_DSET 3
-#define WOW_INVALID_CONFIG_DSET 4
-#define WOW_USE_DEFAULT_CONFIG 5
-#define WOW_SETUP_GPIO 6
-#define WOW_INIT_DONE 7
-#define WOW_SET_GPIO_PIN 8
-#define WOW_CLEAR_GPIO_PIN 9
-#define WOW_SET_WOW_MODE_CMD 10
-#define WOW_SET_HOST_MODE_CMD 11
-#define WOW_ADD_WOW_PATTERN_CMD 12
-#define WOW_NEW_WOW_PATTERN_AT_INDEX 13
-#define WOW_DEL_WOW_PATTERN_CMD 14
-#define WOW_LIST_CONTAINS_PATTERNS 15
-#define WOW_GET_WOW_LIST_CMD 16
-#define WOW_INVALID_FILTER_ID 17
-#define WOW_INVALID_FILTER_LISTID 18
-#define WOW_NO_VALID_FILTER_AT_ID 19
-#define WOW_NO_VALID_LIST_AT_ID 20
-#define WOW_NUM_PATTERNS_EXCEEDED 21
-#define WOW_NUM_LISTS_EXCEEDED 22
-#define WOW_GET_WOW_STATS 23
-#define WOW_CLEAR_WOW_STATS 24
-#define WOW_WAKEUP_HOST 25
-#define WOW_EVENT_WAKEUP_HOST 26
-#define WOW_EVENT_DISCARD 27
-#define WOW_PATTERN_MATCH 28
-#define WOW_PATTERN_NOT_MATCH 29
-#define WOW_PATTERN_NOT_MATCH_OFFSET 30
-#define WOW_DISABLED_HOST_ASLEEP 31
-#define WOW_ENABLED_HOST_ASLEEP_NO_PATTERNS 32
-#define WOW_ENABLED_HOST_ASLEEP_NO_MATCH_FOUND 33
-#define WOW_DBGID_DEFINITION_END
-
-/* WHAL debug identifier definitions */
-#define WHAL_DBGID_DEFINITION_START
-#define WHAL_ERROR_ANI_CONTROL 1
-#define WHAL_ERROR_CHIP_TEST1 2
-#define WHAL_ERROR_CHIP_TEST2 3
-#define WHAL_ERROR_EEPROM_CHECKSUM 4
-#define WHAL_ERROR_EEPROM_MACADDR 5
-#define WHAL_ERROR_INTERRUPT_HIU 6
-#define WHAL_ERROR_KEYCACHE_RESET 7
-#define WHAL_ERROR_KEYCACHE_SET 8
-#define WHAL_ERROR_KEYCACHE_TYPE 9
-#define WHAL_ERROR_KEYCACHE_TKIPENTRY 10
-#define WHAL_ERROR_KEYCACHE_WEPLENGTH 11
-#define WHAL_ERROR_PHY_INVALID_CHANNEL 12
-#define WHAL_ERROR_POWER_AWAKE 13
-#define WHAL_ERROR_POWER_SET 14
-#define WHAL_ERROR_RECV_STOPDMA 15
-#define WHAL_ERROR_RECV_STOPPCU 16
-#define WHAL_ERROR_RESET_CHANNF1 17
-#define WHAL_ERROR_RESET_CHANNF2 18
-#define WHAL_ERROR_RESET_PM 19
-#define WHAL_ERROR_RESET_OFFSETCAL 20
-#define WHAL_ERROR_RESET_RFGRANT 21
-#define WHAL_ERROR_RESET_RXFRAME 22
-#define WHAL_ERROR_RESET_STOPDMA 23
-#define WHAL_ERROR_RESET_RECOVER 24
-#define WHAL_ERROR_XMIT_COMPUTE 25
-#define WHAL_ERROR_XMIT_NOQUEUE 26
-#define WHAL_ERROR_XMIT_ACTIVEQUEUE 27
-#define WHAL_ERROR_XMIT_BADTYPE 28
-#define WHAL_ERROR_XMIT_STOPDMA 29
-#define WHAL_ERROR_INTERRUPT_BB_PANIC 30
-#define WHAL_ERROR_RESET_TXIQCAL 31
-#define WHAL_ERROR_PAPRD_MAXGAIN_ABOVE_WINDOW 32
-#define WHAL_DBGID_DEFINITION_END
-
-/* DC debug identifier definitions */
-#define DC_DBGID_DEFINITION_START
-#define DC_SCAN_CHAN_START 1
-#define DC_SCAN_CHAN_FINISH 2
-#define DC_BEACON_RECEIVE7 3
-#define DC_SSID_PROBE_CB 4
-#define DC_SEND_NEXT_SSID_PROBE 5
-#define DC_START_SEARCH 6
-#define DC_CANCEL_SEARCH_CB 7
-#define DC_STOP_SEARCH 8
-#define DC_END_SEARCH 9
-#define DC_MIN_CHDWELL_TIMEOUT 10
-#define DC_START_SEARCH_CANCELED 11
-#define DC_SET_POWER_MODE 12
-#define DC_INIT 13
-#define DC_SEARCH_OPPORTUNITY 14
-#define DC_RECEIVED_ANY_BEACON 15
-#define DC_RECEIVED_MY_BEACON 16
-#define DC_PROFILE_IS_ADHOC_BUT_BSS_IS_INFRA 17
-#define DC_PS_ENABLED_BUT_ATHEROS_IE_ABSENT 18
-#define DC_BSS_ADHOC_CHANNEL_NOT_ALLOWED 19
-#define DC_SET_BEACON_UPDATE 20
-#define DC_BEACON_UPDATE_COMPLETE 21
-#define DC_END_SEARCH_BEACON_UPDATE_COMP_CB 22
-#define DC_BSSINFO_EVENT_DROPPED 23
-#define DC_IEEEPS_ENABLED_BUT_ATIM_ABSENT 24
-#define DC_DBGID_DEFINITION_END
-
-/* CO debug identifier definitions */
-#define CO_DBGID_DEFINITION_START
-#define CO_INIT 1
-#define CO_ACQUIRE_LOCK 2
-#define CO_START_OP1 3
-#define CO_START_OP2 4
-#define CO_DRAIN_TX_COMPLETE_CB 5
-#define CO_CHANGE_CHANNEL_CB 6
-#define CO_RETURN_TO_HOME_CHANNEL 7
-#define CO_FINISH_OP_TIMEOUT 8
-#define CO_OP_END 9
-#define CO_CANCEL_OP 10
-#define CO_CHANGE_CHANNEL 11
-#define CO_RELEASE_LOCK 12
-#define CO_CHANGE_STATE 13
-#define CO_DBGID_DEFINITION_END
-
-/* RO debug identifier definitions */
-#define RO_DBGID_DEFINITION_START
-#define RO_REFRESH_ROAM_TABLE 1
-#define RO_UPDATE_ROAM_CANDIDATE 2
-#define RO_UPDATE_ROAM_CANDIDATE_CB 3
-#define RO_UPDATE_ROAM_CANDIDATE_FINISH 4
-#define RO_REFRESH_ROAM_TABLE_DONE 5
-#define RO_PERIODIC_SEARCH_CB 6
-#define RO_PERIODIC_SEARCH_TIMEOUT 7
-#define RO_INIT 8
-#define RO_BMISS_STATE1 9
-#define RO_BMISS_STATE2 10
-#define RO_SET_PERIODIC_SEARCH_ENABLE 11
-#define RO_SET_PERIODIC_SEARCH_DISABLE 12
-#define RO_ENABLE_SQ_THRESHOLD 13
-#define RO_DISABLE_SQ_THRESHOLD 14
-#define RO_ADD_BSS_TO_ROAM_TABLE 15
-#define RO_SET_PERIODIC_SEARCH_MODE 16
-#define RO_CONFIGURE_SQ_THRESHOLD1 17
-#define RO_CONFIGURE_SQ_THRESHOLD2 18
-#define RO_CONFIGURE_SQ_PARAMS 19
-#define RO_LOW_SIGNAL_QUALITY_EVENT 20
-#define RO_HIGH_SIGNAL_QUALITY_EVENT 21
-#define RO_REMOVE_BSS_FROM_ROAM_TABLE 22
-#define RO_UPDATE_CONNECTION_STATE_METRIC 23
-#define RO_DBGID_DEFINITION_END
-
-/* CM debug identifier definitions */
-#define CM_DBGID_DEFINITION_START
-#define CM_INITIATE_HANDOFF 1
-#define CM_INITIATE_HANDOFF_CB 2
-#define CM_CONNECT_EVENT 3
-#define CM_DISCONNECT_EVENT 4
-#define CM_INIT 5
-#define CM_HANDOFF_SOURCE 6
-#define CM_SET_HANDOFF_TRIGGERS 7
-#define CM_CONNECT_REQUEST 8
-#define CM_CONNECT_REQUEST_CB 9
-#define CM_CONTINUE_SCAN_CB 10
-#define CM_DBGID_DEFINITION_END
-
-
-/* mgmt debug identifier definitions */
-#define MGMT_DBGID_DEFINITION_START
-#define KEYMGMT_CONNECTION_INIT 1
-#define KEYMGMT_CONNECTION_COMPLETE 2
-#define KEYMGMT_CONNECTION_CLOSE 3
-#define KEYMGMT_ADD_KEY 4
-#define MLME_NEW_STATE 5
-#define MLME_CONN_INIT 6
-#define MLME_CONN_COMPLETE 7
-#define MLME_CONN_CLOSE 8
-#define MGMT_DBGID_DEFINITION_END
-
-/* TMR debug identifier definitions */
-#define TMR_DBGID_DEFINITION_START
-#define TMR_HANG_DETECTED 1
-#define TMR_WDT_TRIGGERED 2
-#define TMR_WDT_RESET 3
-#define TMR_HANDLER_ENTRY 4
-#define TMR_HANDLER_EXIT 5
-#define TMR_SAVED_START 6
-#define TMR_SAVED_END 7
-#define TMR_DBGID_DEFINITION_END
-
-/* BTCOEX debug identifier definitions */
-#define BTCOEX_DBGID_DEFINITION_START
-#define BTCOEX_STATUS_CMD 1
-#define BTCOEX_PARAMS_CMD 2
-#define BTCOEX_ANT_CONFIG 3
-#define BTCOEX_COLOCATED_BT_DEVICE 4
-#define BTCOEX_CLOSE_RANGE_SCO_ON 5
-#define BTCOEX_CLOSE_RANGE_SCO_OFF 6
-#define BTCOEX_CLOSE_RANGE_A2DP_ON 7
-#define BTCOEX_CLOSE_RANGE_A2DP_OFF 8
-#define BTCOEX_A2DP_PROTECT_ON 9
-#define BTCOEX_A2DP_PROTECT_OFF 10
-#define BTCOEX_SCO_PROTECT_ON 11
-#define BTCOEX_SCO_PROTECT_OFF 12
-#define BTCOEX_CLOSE_RANGE_DETECTOR_START 13
-#define BTCOEX_CLOSE_RANGE_DETECTOR_STOP 14
-#define BTCOEX_CLOSE_RANGE_TOGGLE 15
-#define BTCOEX_CLOSE_RANGE_TOGGLE_RSSI_LRCNT 16
-#define BTCOEX_CLOSE_RANGE_RSSI_THRESH 17
-#define BTCOEX_CLOSE_RANGE_LOW_RATE_THRESH 18
-#define BTCOEX_PTA_PRI_INTR_HANDLER 19
-#define BTCOEX_PSPOLL_QUEUED 20
-#define BTCOEX_PSPOLL_COMPLETE 21
-#define BTCOEX_DBG_PM_AWAKE 22
-#define BTCOEX_DBG_PM_SLEEP 23
-#define BTCOEX_DBG_SCO_COEX_ON 24
-#define BTCOEX_SCO_DATARECEIVE 25
-#define BTCOEX_INTR_INIT 26
-#define BTCOEX_PTA_PRI_DIFF 27
-#define BTCOEX_TIM_NOTIFICATION 28
-#define BTCOEX_SCO_WAKEUP_ON_DATA 29
-#define BTCOEX_SCO_SLEEP 30
-#define BTCOEX_SET_WEIGHTS 31
-#define BTCOEX_SCO_DATARECEIVE_LATENCY_VAL 32
-#define BTCOEX_SCO_MEASURE_TIME_DIFF 33
-#define BTCOEX_SET_EOL_VAL 34
-#define BTCOEX_OPT_DETECT_HANDLER 35
-#define BTCOEX_SCO_TOGGLE_STATE 36
-#define BTCOEX_SCO_STOMP 37
-#define BTCOEX_NULL_COMP_CALLBACK 38
-#define BTCOEX_RX_INCOMING 39
-#define BTCOEX_RX_INCOMING_CTL 40
-#define BTCOEX_RX_INCOMING_MGMT 41
-#define BTCOEX_RX_INCOMING_DATA 42
-#define BTCOEX_RTS_RECEPTION 43
-#define BTCOEX_FRAME_PRI_LOW_RATE_THRES 44
-#define BTCOEX_PM_FAKE_SLEEP 45
-#define BTCOEX_ACL_COEX_STATUS 46
-#define BTCOEX_ACL_COEX_DETECTION 47
-#define BTCOEX_A2DP_COEX_STATUS 48
-#define BTCOEX_SCO_STATUS 49
-#define BTCOEX_WAKEUP_ON_DATA 50
-#define BTCOEX_DATARECEIVE 51
-#define BTCOEX_GET_MAX_AGGR_SIZE 53
-#define BTCOEX_MAX_AGGR_AVAIL_TIME 54
-#define BTCOEX_DBG_WBTIMER_INTR 55
-#define BTCOEX_DBG_SCO_SYNC 57
-#define BTCOEX_UPLINK_QUEUED_RATE 59
-#define BTCOEX_DBG_UPLINK_ENABLE_EOL 60
-#define BTCOEX_UPLINK_FRAME_DURATION 61
-#define BTCOEX_UPLINK_SET_EOL 62
-#define BTCOEX_DBG_EOL_EXPIRED 63
-#define BTCOEX_DBG_DATA_COMPLETE 64
-#define BTCOEX_UPLINK_QUEUED_TIMESTAMP 65
-#define BTCOEX_DBG_DATA_COMPLETE_TIME 66
-#define BTCOEX_DBG_A2DP_ROLE_IS_SLAVE 67
-#define BTCOEX_DBG_A2DP_ROLE_IS_MASTER 68
-#define BTCOEX_DBG_UPLINK_SEQ_NUM 69
-#define BTCOEX_UPLINK_AGGR_SEQ 70
-#define BTCOEX_DBG_TX_COMP_SEQ_NO 71
-#define BTCOEX_DBG_MAX_AGGR_PAUSE_STATE 72
-#define BTCOEX_DBG_ACL_TRAFFIC 73
-#define BTCOEX_CURR_AGGR_PROP 74
-#define BTCOEX_DBG_SCO_GET_PER_TIME_DIFF 75
-#define BTCOEX_PSPOLL_PROCESS 76
-#define BTCOEX_RETURN_FROM_MAC 77
-#define BTCOEX_FREED_REQUEUED_CNT 78
-#define BTCOEX_DBG_TOGGLE_LOW_RATES 79
-#define BTCOEX_MAC_GOES_TO_SLEEP 80
-#define BTCOEX_DBG_A2DP_NO_SYNC 81
-#define BTCOEX_RETURN_FROM_MAC_HOLD_Q_INFO 82
-#define BTCOEX_RETURN_FROM_MAC_AC 83
-#define BTCOEX_DBG_DTIM_RECV 84
-#define BTCOEX_IS_PRE_UPDATE 86
-#define BTCOEX_ENQUEUED_BIT_MAP 87
-#define BTCOEX_TX_COMPLETE_FIRST_DESC_STATS 88
-#define BTCOEX_UPLINK_DESC 89
-#define BTCOEX_SCO_GET_PER_FIRST_FRM_TIMESTAMP 90
-#define BTCOEX_DBG_RECV_ACK 94
-#define BTCOEX_DBG_ADDBA_INDICATION 95
-#define BTCOEX_TX_COMPLETE_EOL_FAILED 96
-#define BTCOEX_DBG_A2DP_USAGE_COMPLETE 97
-#define BTCOEX_DBG_A2DP_STOMP_FOR_BCN_HANDLER 98
-#define BTCOEX_DBG_A2DP_SYNC_INTR 99
-#define BTCOEX_DBG_A2DP_STOMP_FOR_BCN_RECEPTION 100
-#define BTCOEX_FORM_AGGR_CURR_AGGR 101
-#define BTCOEX_DBG_TOGGLE_A2DP_BURST_CNT 102
-#define BTCOEX_DBG_BT_TRAFFIC 103
-#define BTCOEX_DBG_STOMP_BT_TRAFFIC 104
-#define BTCOEX_RECV_NULL 105
-#define BTCOEX_DBG_A2DP_MASTER_BT_END 106
-#define BTCOEX_DBG_A2DP_BT_START 107
-#define BTCOEX_DBG_A2DP_SLAVE_BT_END 108
-#define BTCOEX_DBG_A2DP_STOMP_BT 109
-#define BTCOEX_DBG_GO_TO_SLEEP 110
-#define BTCOEX_DBG_A2DP_PKT 111
-#define BTCOEX_DBG_A2DP_PSPOLL_DATA_RECV 112
-#define BTCOEX_DBG_A2DP_NULL 113
-#define BTCOEX_DBG_UPLINK_DATA 114
-#define BTCOEX_DBG_A2DP_STOMP_LOW_PRIO_NULL 115
-#define BTCOEX_DBG_ADD_BA_RESP_TIMEOUT 116
-#define BTCOEX_DBG_TXQ_STATE 117
-#define BTCOEX_DBG_ALLOW_SCAN 118
-#define BTCOEX_DBG_SCAN_REQUEST 119
-#define BTCOEX_A2DP_SLEEP 127
-#define BTCOEX_DBG_DATA_ACTIV_TIMEOUT 128
-#define BTCOEX_DBG_SWITCH_TO_PSPOLL_ON_MODE 129
-#define BTCOEX_DBG_SWITCH_TO_PSPOLL_OFF_MODE 130
-#define BTCOEX_DATARECEIVE_AGGR 131
-#define BTCOEX_DBG_DATA_RECV_SLEEPING_PENDING 132
-#define BTCOEX_DBG_DATARESP_TIMEOUT 133
-#define BTCOEX_BDG_BMISS 134
-#define BTCOEX_DBG_DATA_RECV_WAKEUP_TIM 135
-#define BTCOEX_DBG_SECOND_BMISS 136
-#define BTCOEX_DBG_SET_WLAN_STATE 138
-#define BTCOEX_BDG_FIRST_BMISS 139
-#define BTCOEX_DBG_A2DP_CHAN_OP 140
-#define BTCOEX_DBG_A2DP_INTR 141
-#define BTCOEX_DBG_BT_INQUIRY 142
-#define BTCOEX_DBG_BT_INQUIRY_DATA_FETCH 143
-#define BTCOEX_DBG_POST_INQUIRY_FINISH 144
-#define BTCOEX_DBG_SCO_OPT_MODE_TIMER_HANDLER 145
-#define BTCOEX_DBG_NULL_FRAME_SLEEP 146
-#define BTCOEX_DBG_NULL_FRAME_AWAKE 147
-#define BTCOEX_DBG_SET_AGGR_SIZE 152
-#define BTCOEX_DBG_TEAR_BA_TIMEOUT 153
-#define BTCOEX_DBG_MGMT_FRAME_SEQ_NO 154
-#define BTCOEX_DBG_SCO_STOMP_HIGH_PRI 155
-#define BTCOEX_DBG_COLOCATED_BT_DEV 156
-#define BTCOEX_DBG_FE_ANT_TYPE 157
-#define BTCOEX_DBG_BT_INQUIRY_CMD 158
-#define BTCOEX_DBG_SCO_CONFIG 159
-#define BTCOEX_DBG_SCO_PSPOLL_CONFIG 160
-#define BTCOEX_DBG_SCO_OPTMODE_CONFIG 161
-#define BTCOEX_DBG_A2DP_CONFIG 162
-#define BTCOEX_DBG_A2DP_PSPOLL_CONFIG 163
-#define BTCOEX_DBG_A2DP_OPTMODE_CONFIG 164
-#define BTCOEX_DBG_ACLCOEX_CONFIG 165
-#define BTCOEX_DBG_ACLCOEX_PSPOLL_CONFIG 166
-#define BTCOEX_DBG_ACLCOEX_OPTMODE_CONFIG 167
-#define BTCOEX_DBG_DEBUG_CMD 168
-#define BTCOEX_DBG_SET_BT_OPERATING_STATUS 169
-#define BTCOEX_DBG_GET_CONFIG 170
-#define BTCOEX_DBG_GET_STATS 171
-#define BTCOEX_DBG_BT_OPERATING_STATUS 172
-#define BTCOEX_DBG_PERFORM_RECONNECT 173
-#define BTCOEX_DBG_ACL_WLAN_MED 175
-#define BTCOEX_DBG_ACL_BT_MED 176
-#define BTCOEX_DBG_WLAN_CONNECT 177
-#define BTCOEX_DBG_A2DP_DUAL_START 178
-#define BTCOEX_DBG_PMAWAKE_NOTIFY 179
-#define BTCOEX_DBG_BEACON_SCAN_ENABLE 180
-#define BTCOEX_DBG_BEACON_SCAN_DISABLE 181
-#define BTCOEX_DBG_RX_NOTIFY 182
-#define BTCOEX_SCO_GET_PER_SECOND_FRM_TIMESTAMP 183
-#define BTCOEX_DBG_TXQ_DETAILS 184
-#define BTCOEX_DBG_SCO_STOMP_LOW_PRI 185
-#define BTCOEX_DBG_A2DP_FORCE_SCAN 186
-#define BTCOEX_DBG_DTIM_STOMP_COMP 187
-#define BTCOEX_ACL_PRESENCE_TIMER 188
-#define BTCOEX_DBGID_DEFINITION_END
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _DBGLOG_ID_H_ */
diff --git a/drivers/staging/ath6kl/include/common/discovery.h b/drivers/staging/ath6kl/include/common/discovery.h
deleted file mode 100644
index da1b33245069..000000000000
--- a/drivers/staging/ath6kl/include/common/discovery.h
+++ /dev/null
@@ -1,75 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="discovery.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-
-#ifndef _DISCOVERY_H_
-#define _DISCOVERY_H_
-
-/*
- * DC_SCAN_PRIORITY is an 8-bit bitmap of the scan priority of a channel
- */
-typedef enum {
- DEFAULT_SCPRI = 0x01,
- POPULAR_SCPRI = 0x02,
- SSIDS_SCPRI = 0x04,
- PROF_SCPRI = 0x08,
-} DC_SCAN_PRIORITY;
-
-/* The following search type construct can be used to manipulate the behavior of the search module based on different bits set */
-typedef enum {
- SCAN_RESET = 0,
- SCAN_ALL = (DEFAULT_SCPRI | POPULAR_SCPRI | \
- SSIDS_SCPRI | PROF_SCPRI),
-
- SCAN_POPULAR = (POPULAR_SCPRI | SSIDS_SCPRI | PROF_SCPRI),
- SCAN_SSIDS = (SSIDS_SCPRI | PROF_SCPRI),
- SCAN_PROF_MASK = (PROF_SCPRI),
- SCAN_MULTI_CHANNEL = 0x000100,
- SCAN_DETERMINISTIC = 0x000200,
- SCAN_PROFILE_MATCH_TERMINATED = 0x000400,
- SCAN_HOME_CHANNEL_SKIP = 0x000800,
- SCAN_CHANNEL_LIST_CONTINUE = 0x001000,
- SCAN_CURRENT_SSID_SKIP = 0x002000,
- SCAN_ACTIVE_PROBE_DISABLE = 0x004000,
- SCAN_CHANNEL_HINT_ONLY = 0x008000,
- SCAN_ACTIVE_CHANNELS_ONLY = 0x010000,
- SCAN_UNUSED1 = 0x020000, /* unused */
- SCAN_PERIODIC = 0x040000,
- SCAN_FIXED_DURATION = 0x080000,
- SCAN_AP_ASSISTED = 0x100000,
-} DC_SCAN_TYPE;
-
-typedef enum {
- BSS_REPORTING_DEFAULT = 0x0,
- EXCLUDE_NON_SCAN_RESULTS = 0x1, /* Exclude results outside of scan */
-} DC_BSS_REPORTING_POLICY;
-
-typedef enum {
- DC_IGNORE_WPAx_GROUP_CIPHER = 0x01,
- DC_PROFILE_MATCH_DONE = 0x02,
- DC_IGNORE_AAC_BEACON = 0x04,
- DC_CSA_FOLLOW_BSS = 0x08,
-} DC_PROFILE_FILTER;
-
-#define DEFAULT_DC_PROFILE_FILTER (DC_CSA_FOLLOW_BSS)
-
-#endif /* _DISCOVERY_H_ */
diff --git a/drivers/staging/ath6kl/include/common/epping_test.h b/drivers/staging/ath6kl/include/common/epping_test.h
deleted file mode 100644
index 9eb5fdfa746a..000000000000
--- a/drivers/staging/ath6kl/include/common/epping_test.h
+++ /dev/null
@@ -1,111 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2009-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//
-
-/* This file contains shared definitions for the host/target endpoint ping test */
-
-#ifndef EPPING_TEST_H_
-#define EPPING_TEST_H_
-
- /* alignment to 4-bytes */
-#define EPPING_ALIGNMENT_PAD (((sizeof(struct htc_frame_hdr) + 3) & (~0x3)) - sizeof(struct htc_frame_hdr))
-
-#ifndef A_OFFSETOF
-#define A_OFFSETOF(type,field) (int)(&(((type *)NULL)->field))
-#endif
-
-#define EPPING_RSVD_FILL 0xCC
-
-#define HCI_RSVD_EXPECTED_PKT_TYPE_RECV_OFFSET 7
-
-typedef PREPACK struct {
- u8 _HCIRsvd[8]; /* reserved for HCI packet header (GMBOX) testing */
- u8 StreamEcho_h; /* stream no. to echo this packet on (filled by host) */
- u8 StreamEchoSent_t; /* stream no. packet was echoed to (filled by target)
- When echoed: StreamEchoSent_t == StreamEcho_h */
- u8 StreamRecv_t; /* stream no. that target received this packet on (filled by target) */
- u8 StreamNo_h; /* stream number to send on (filled by host) */
- u8 Magic_h[4]; /* magic number to filter for this packet on the host*/
- u8 _rsvd[6]; /* reserved fields that must be set to a "reserved" value
- since this packet maps to a 14-byte ethernet frame we want
- to make sure ethertype field is set to something unknown */
-
- u8 _pad[2]; /* padding for alignment */
- u8 TimeStamp[8]; /* timestamp of packet (host or target) */
- u32 HostContext_h; /* 4 byte host context, target echos this back */
- u32 SeqNo; /* sequence number (set by host or target) */
- u16 Cmd_h; /* ping command (filled by host) */
- u16 CmdFlags_h; /* optional flags */
- u8 CmdBuffer_h[8]; /* buffer for command (host -> target) */
- u8 CmdBuffer_t[8]; /* buffer for command (target -> host) */
- u16 DataLength; /* length of data */
- u16 DataCRC; /* 16 bit CRC of data */
- u16 HeaderCRC; /* header CRC (fields : StreamNo_h to end, minus HeaderCRC) */
-} POSTPACK EPPING_HEADER;
-
-#define EPPING_PING_MAGIC_0 0xAA
-#define EPPING_PING_MAGIC_1 0x55
-#define EPPING_PING_MAGIC_2 0xCE
-#define EPPING_PING_MAGIC_3 0xEC
-
-
-
-#define IS_EPPING_PACKET(pPkt) (((pPkt)->Magic_h[0] == EPPING_PING_MAGIC_0) && \
- ((pPkt)->Magic_h[1] == EPPING_PING_MAGIC_1) && \
- ((pPkt)->Magic_h[2] == EPPING_PING_MAGIC_2) && \
- ((pPkt)->Magic_h[3] == EPPING_PING_MAGIC_3))
-
-#define SET_EPPING_PACKET_MAGIC(pPkt) { (pPkt)->Magic_h[0] = EPPING_PING_MAGIC_0; \
- (pPkt)->Magic_h[1] = EPPING_PING_MAGIC_1; \
- (pPkt)->Magic_h[2] = EPPING_PING_MAGIC_2; \
- (pPkt)->Magic_h[3] = EPPING_PING_MAGIC_3;}
-
-#define CMD_FLAGS_DATA_CRC (1 << 0) /* DataCRC field is valid */
-#define CMD_FLAGS_DELAY_ECHO (1 << 1) /* delay the echo of the packet */
-#define CMD_FLAGS_NO_DROP (1 << 2) /* do not drop at HTC layer no matter what the stream is */
-
-#define IS_EPING_PACKET_NO_DROP(pPkt) ((pPkt)->CmdFlags_h & CMD_FLAGS_NO_DROP)
-
-#define EPPING_CMD_ECHO_PACKET 1 /* echo packet test */
-#define EPPING_CMD_RESET_RECV_CNT 2 /* reset recv count */
-#define EPPING_CMD_CAPTURE_RECV_CNT 3 /* fetch recv count, 4-byte count returned in CmdBuffer_t */
-#define EPPING_CMD_NO_ECHO 4 /* non-echo packet test (tx-only) */
-#define EPPING_CMD_CONT_RX_START 5 /* continuous RX packets, parameters are in CmdBuffer_h */
-#define EPPING_CMD_CONT_RX_STOP 6 /* stop continuous RX packet transmission */
-
- /* test command parameters may be no more than 8 bytes */
-typedef PREPACK struct {
- u16 BurstCnt; /* number of packets to burst together (for HTC 2.1 testing) */
- u16 PacketLength; /* length of packet to generate including header */
- u16 Flags; /* flags */
-
-#define EPPING_CONT_RX_DATA_CRC (1 << 0) /* Add CRC to all data */
-#define EPPING_CONT_RX_RANDOM_DATA (1 << 1) /* randomize the data pattern */
-#define EPPING_CONT_RX_RANDOM_LEN (1 << 2) /* randomize the packet lengths */
-} POSTPACK EPPING_CONT_RX_PARAMS;
-
-#define EPPING_HDR_CRC_OFFSET A_OFFSETOF(EPPING_HEADER,StreamNo_h)
-#define EPPING_HDR_BYTES_CRC (sizeof(EPPING_HEADER) - EPPING_HDR_CRC_OFFSET - (sizeof(u16)))
-
-#define HCI_TRANSPORT_STREAM_NUM 16 /* this number is higher than the define WMM AC classes so we
- can use this to distinguish packets */
-
-#endif /*EPPING_TEST_H_*/
diff --git a/drivers/staging/ath6kl/include/common/gmboxif.h b/drivers/staging/ath6kl/include/common/gmboxif.h
deleted file mode 100644
index ea11c14def43..000000000000
--- a/drivers/staging/ath6kl/include/common/gmboxif.h
+++ /dev/null
@@ -1,70 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2009-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-
-#ifndef __GMBOXIF_H__
-#define __GMBOXIF_H__
-
-/* GMBOX interface definitions */
-
-#define AR6K_GMBOX_CREDIT_COUNTER 1 /* we use credit counter 1 to track credits */
-#define AR6K_GMBOX_CREDIT_SIZE_COUNTER 2 /* credit counter 2 is used to pass the size of each credit */
-
-
- /* HCI UART transport definitions when used over GMBOX interface */
-#define HCI_UART_COMMAND_PKT 0x01
-#define HCI_UART_ACL_PKT 0x02
-#define HCI_UART_SCO_PKT 0x03
-#define HCI_UART_EVENT_PKT 0x04
-
- /* definitions for BT HCI packets */
-typedef PREPACK struct {
- u16 Flags_ConnHandle;
- u16 Length;
-} POSTPACK BT_HCI_ACL_HEADER;
-
-typedef PREPACK struct {
- u16 Flags_ConnHandle;
- u8 Length;
-} POSTPACK BT_HCI_SCO_HEADER;
-
-typedef PREPACK struct {
- u16 OpCode;
- u8 ParamLength;
-} POSTPACK BT_HCI_COMMAND_HEADER;
-
-typedef PREPACK struct {
- u8 EventCode;
- u8 ParamLength;
-} POSTPACK BT_HCI_EVENT_HEADER;
-
-/* MBOX host interrupt signal assignments */
-
-#define MBOX_SIG_HCI_BRIDGE_MAX 8
-#define MBOX_SIG_HCI_BRIDGE_BT_ON 0
-#define MBOX_SIG_HCI_BRIDGE_BT_OFF 1
-#define MBOX_SIG_HCI_BRIDGE_BAUD_SET 2
-#define MBOX_SIG_HCI_BRIDGE_PWR_SAV_ON 3
-#define MBOX_SIG_HCI_BRIDGE_PWR_SAV_OFF 4
-
-
-#endif /* __GMBOXIF_H__ */
-
diff --git a/drivers/staging/ath6kl/include/common/gpio_reg.h b/drivers/staging/ath6kl/include/common/gpio_reg.h
deleted file mode 100644
index f9d425d48dc2..000000000000
--- a/drivers/staging/ath6kl/include/common/gpio_reg.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef _GPIO_REG_REG_H_
-#define _GPIO_REG_REG_H_
-
-#define GPIO_PIN10_ADDRESS 0x00000050
-#define GPIO_PIN11_ADDRESS 0x00000054
-#define GPIO_PIN12_ADDRESS 0x00000058
-#define GPIO_PIN13_ADDRESS 0x0000005c
-
-#endif /* _GPIO_REG_H_ */
diff --git a/drivers/staging/ath6kl/include/common/htc.h b/drivers/staging/ath6kl/include/common/htc.h
deleted file mode 100644
index 85cbfa89d670..000000000000
--- a/drivers/staging/ath6kl/include/common/htc.h
+++ /dev/null
@@ -1,227 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="htc.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-
-#ifndef __HTC_H__
-#define __HTC_H__
-
-#define A_OFFSETOF(type,field) (unsigned long)(&(((type *)NULL)->field))
-
-#define ASSEMBLE_UNALIGNED_UINT16(p,highbyte,lowbyte) \
- (((u16)(((u8 *)(p))[(highbyte)])) << 8 | (u16)(((u8 *)(p))[(lowbyte)]))
-
-/* alignment independent macros (little-endian) to fetch UINT16s or UINT8s from a
- * structure using only the type and field name.
- * Use these macros if there is the potential for unaligned buffer accesses. */
-#define A_GET_UINT16_FIELD(p,type,field) \
- ASSEMBLE_UNALIGNED_UINT16(p,\
- A_OFFSETOF(type,field) + 1, \
- A_OFFSETOF(type,field))
-
-#define A_SET_UINT16_FIELD(p,type,field,value) \
-{ \
- ((u8 *)(p))[A_OFFSETOF(type,field)] = (u8)(value); \
- ((u8 *)(p))[A_OFFSETOF(type,field) + 1] = (u8)((value) >> 8); \
-}
-
-#define A_GET_UINT8_FIELD(p,type,field) \
- ((u8 *)(p))[A_OFFSETOF(type,field)]
-
-#define A_SET_UINT8_FIELD(p,type,field,value) \
- ((u8 *)(p))[A_OFFSETOF(type,field)] = (value)
-
-/****** DANGER DANGER ***************
- *
- * The frame header length and message formats defined herein were
- * selected to accommodate optimal alignment for target processing. This reduces code
- * size and improves performance.
- *
- * Any changes to the header length may alter the alignment and cause exceptions
- * on the target. When adding to the message structures insure that fields are
- * properly aligned.
- *
- */
-
-/* HTC frame header */
-PREPACK struct htc_frame_hdr {
- /* do not remove or re-arrange these fields, these are minimally required
- * to take advantage of 4-byte lookaheads in some hardware implementations */
- u8 EndpointID;
- u8 Flags;
- u16 PayloadLen; /* length of data (including trailer) that follows the header */
-
- /***** end of 4-byte lookahead ****/
-
- u8 ControlBytes[2];
-
- /* message payload starts after the header */
-
-} POSTPACK;
-
-/* frame header flags */
-
- /* send direction */
-#define HTC_FLAGS_NEED_CREDIT_UPDATE (1 << 0)
-#define HTC_FLAGS_SEND_BUNDLE (1 << 1) /* start or part of bundle */
- /* receive direction */
-#define HTC_FLAGS_RECV_UNUSED_0 (1 << 0) /* bit 0 unused */
-#define HTC_FLAGS_RECV_TRAILER (1 << 1) /* bit 1 trailer data present */
-#define HTC_FLAGS_RECV_UNUSED_2 (1 << 0) /* bit 2 unused */
-#define HTC_FLAGS_RECV_UNUSED_3 (1 << 0) /* bit 3 unused */
-#define HTC_FLAGS_RECV_BUNDLE_CNT_MASK (0xF0) /* bits 7..4 */
-#define HTC_FLAGS_RECV_BUNDLE_CNT_SHIFT 4
-
-#define HTC_HDR_LENGTH (sizeof(struct htc_frame_hdr))
-#define HTC_MAX_TRAILER_LENGTH 255
-#define HTC_MAX_PAYLOAD_LENGTH (4096 - sizeof(struct htc_frame_hdr))
-
-/* HTC control message IDs */
-
-#define HTC_MSG_READY_ID 1
-#define HTC_MSG_CONNECT_SERVICE_ID 2
-#define HTC_MSG_CONNECT_SERVICE_RESPONSE_ID 3
-#define HTC_MSG_SETUP_COMPLETE_ID 4
-#define HTC_MSG_SETUP_COMPLETE_EX_ID 5
-
-#define HTC_MAX_CONTROL_MESSAGE_LENGTH 256
-
-/* base message ID header */
-typedef PREPACK struct {
- u16 MessageID;
-} POSTPACK HTC_UNKNOWN_MSG;
-
-/* HTC ready message
- * direction : target-to-host */
-typedef PREPACK struct {
- u16 MessageID; /* ID */
- u16 CreditCount; /* number of credits the target can offer */
- u16 CreditSize; /* size of each credit */
- u8 MaxEndpoints; /* maximum number of endpoints the target has resources for */
- u8 _Pad1;
-} POSTPACK HTC_READY_MSG;
-
- /* extended HTC ready message */
-typedef PREPACK struct {
- HTC_READY_MSG Version2_0_Info; /* legacy version 2.0 information at the front... */
- /* extended information */
- u8 HTCVersion;
- u8 MaxMsgsPerHTCBundle;
-} POSTPACK HTC_READY_EX_MSG;
-
-#define HTC_VERSION_2P0 0x00
-#define HTC_VERSION_2P1 0x01 /* HTC 2.1 */
-
-#define HTC_SERVICE_META_DATA_MAX_LENGTH 128
-
-/* connect service
- * direction : host-to-target */
-typedef PREPACK struct {
- u16 MessageID;
- u16 ServiceID; /* service ID of the service to connect to */
- u16 ConnectionFlags; /* connection flags */
-
-#define HTC_CONNECT_FLAGS_REDUCE_CREDIT_DRIBBLE (1 << 2) /* reduce credit dribbling when
- the host needs credits */
-#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_MASK (0x3)
-#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_ONE_FOURTH 0x0
-#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_ONE_HALF 0x1
-#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_THREE_FOURTHS 0x2
-#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_UNITY 0x3
-
- u8 ServiceMetaLength; /* length of meta data that follows */
- u8 _Pad1;
-
- /* service-specific meta data starts after the header */
-
-} POSTPACK HTC_CONNECT_SERVICE_MSG;
-
-/* connect response
- * direction : target-to-host */
-typedef PREPACK struct {
- u16 MessageID;
- u16 ServiceID; /* service ID that the connection request was made */
- u8 Status; /* service connection status */
- u8 EndpointID; /* assigned endpoint ID */
- u16 MaxMsgSize; /* maximum expected message size on this endpoint */
- u8 ServiceMetaLength; /* length of meta data that follows */
- u8 _Pad1;
-
- /* service-specific meta data starts after the header */
-
-} POSTPACK HTC_CONNECT_SERVICE_RESPONSE_MSG;
-
-typedef PREPACK struct {
- u16 MessageID;
- /* currently, no other fields */
-} POSTPACK HTC_SETUP_COMPLETE_MSG;
-
- /* extended setup completion message */
-typedef PREPACK struct {
- u16 MessageID;
- u32 SetupFlags;
- u8 MaxMsgsPerBundledRecv;
- u8 Rsvd[3];
-} POSTPACK HTC_SETUP_COMPLETE_EX_MSG;
-
-#define HTC_SETUP_COMPLETE_FLAGS_ENABLE_BUNDLE_RECV (1 << 0)
-
-/* connect response status codes */
-#define HTC_SERVICE_SUCCESS 0 /* success */
-#define HTC_SERVICE_NOT_FOUND 1 /* service could not be found */
-#define HTC_SERVICE_FAILED 2 /* specific service failed the connect */
-#define HTC_SERVICE_NO_RESOURCES 3 /* no resources (i.e. no more endpoints) */
-#define HTC_SERVICE_NO_MORE_EP 4 /* specific service is not allowing any more
- endpoints */
-
-/* report record IDs */
-
-#define HTC_RECORD_NULL 0
-#define HTC_RECORD_CREDITS 1
-#define HTC_RECORD_LOOKAHEAD 2
-#define HTC_RECORD_LOOKAHEAD_BUNDLE 3
-
-typedef PREPACK struct {
- u8 RecordID; /* Record ID */
- u8 Length; /* Length of record */
-} POSTPACK HTC_RECORD_HDR;
-
-typedef PREPACK struct {
- u8 EndpointID; /* Endpoint that owns these credits */
- u8 Credits; /* credits to report since last report */
-} POSTPACK HTC_CREDIT_REPORT;
-
-typedef PREPACK struct {
- u8 PreValid; /* pre valid guard */
- u8 LookAhead[4]; /* 4 byte lookahead */
- u8 PostValid; /* post valid guard */
-
- /* NOTE: the LookAhead array is guarded by a PreValid and Post Valid guard bytes.
- * The PreValid bytes must equal the inverse of the PostValid byte */
-
-} POSTPACK HTC_LOOKAHEAD_REPORT;
-
-typedef PREPACK struct {
- u8 LookAhead[4]; /* 4 byte lookahead */
-} POSTPACK HTC_BUNDLED_LOOKAHEAD_REPORT;
-
-#endif /* __HTC_H__ */
-
diff --git a/drivers/staging/ath6kl/include/common/htc_services.h b/drivers/staging/ath6kl/include/common/htc_services.h
deleted file mode 100644
index fb22268a8d84..000000000000
--- a/drivers/staging/ath6kl/include/common/htc_services.h
+++ /dev/null
@@ -1,52 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="htc_services.h" company="Atheros">
-// Copyright (c) 2007 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-
-#ifndef __HTC_SERVICES_H__
-#define __HTC_SERVICES_H__
-
-/* Current service IDs */
-
-typedef enum {
- RSVD_SERVICE_GROUP = 0,
- WMI_SERVICE_GROUP = 1,
-
- HTC_TEST_GROUP = 254,
- HTC_SERVICE_GROUP_LAST = 255
-}HTC_SERVICE_GROUP_IDS;
-
-#define MAKE_SERVICE_ID(group,index) \
- (int)(((int)group << 8) | (int)(index))
-
-/* NOTE: service ID of 0x0000 is reserved and should never be used */
-#define HTC_CTRL_RSVD_SVC MAKE_SERVICE_ID(RSVD_SERVICE_GROUP,1)
-#define WMI_CONTROL_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,0)
-#define WMI_DATA_BE_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,1)
-#define WMI_DATA_BK_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,2)
-#define WMI_DATA_VI_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,3)
-#define WMI_DATA_VO_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,4)
-#define WMI_MAX_SERVICES 5
-
-/* raw stream service (i.e. flash, tcmd, calibration apps) */
-#define HTC_RAW_STREAMS_SVC MAKE_SERVICE_ID(HTC_TEST_GROUP,0)
-
-#endif /*HTC_SERVICES_H_*/
diff --git a/drivers/staging/ath6kl/include/common/pkt_log.h b/drivers/staging/ath6kl/include/common/pkt_log.h
deleted file mode 100644
index a3719adf54ca..000000000000
--- a/drivers/staging/ath6kl/include/common/pkt_log.h
+++ /dev/null
@@ -1,45 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2005-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-
-#ifndef __PKT_LOG_H__
-#define __PKT_LOG_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/* Pkt log info */
-typedef PREPACK struct pkt_log_t {
- struct info_t {
- u16 st;
- u16 end;
- u16 cur;
- }info[4096];
- u16 last_idx;
-}POSTPACK PACKET_LOG;
-
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* __PKT_LOG_H__ */
diff --git a/drivers/staging/ath6kl/include/common/roaming.h b/drivers/staging/ath6kl/include/common/roaming.h
deleted file mode 100644
index 8019850a0571..000000000000
--- a/drivers/staging/ath6kl/include/common/roaming.h
+++ /dev/null
@@ -1,41 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="roaming.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-
-#ifndef _ROAMING_H_
-#define _ROAMING_H_
-
-/*
- * The signal quality could be in terms of either snr or rssi. We should
- * have an enum for both of them. For the time being, we are going to move
- * it to wmi.h that is shared by both host and the target, since we are
- * repartitioning the code to the host
- */
-#define SIGNAL_QUALITY_NOISE_FLOOR -96
-#define SIGNAL_QUALITY_METRICS_NUM_MAX 2
-typedef enum {
- SIGNAL_QUALITY_METRICS_SNR = 0,
- SIGNAL_QUALITY_METRICS_RSSI,
- SIGNAL_QUALITY_METRICS_ALL,
-} SIGNAL_QUALITY_METRICS_TYPE;
-
-#endif /* _ROAMING_H_ */
diff --git a/drivers/staging/ath6kl/include/common/targaddrs.h b/drivers/staging/ath6kl/include/common/targaddrs.h
deleted file mode 100644
index c866cefbd8fd..000000000000
--- a/drivers/staging/ath6kl/include/common/targaddrs.h
+++ /dev/null
@@ -1,395 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//
-// Author(s): ="Atheros"
-//------------------------------------------------------------------------------
-
-#ifndef __TARGADDRS_H__
-#define __TARGADDRS_H__
-
-#if defined(AR6002)
-#include "AR6002/addrs.h"
-#endif
-
-/*
- * AR6K option bits, to enable/disable various features.
- * By default, all option bits are 0.
- * These bits can be set in LOCAL_SCRATCH register 0.
- */
-#define AR6K_OPTION_BMI_DISABLE 0x01 /* Disable BMI comm with Host */
-#define AR6K_OPTION_SERIAL_ENABLE 0x02 /* Enable serial port msgs */
-#define AR6K_OPTION_WDT_DISABLE 0x04 /* WatchDog Timer override */
-#define AR6K_OPTION_SLEEP_DISABLE 0x08 /* Disable system sleep */
-#define AR6K_OPTION_STOP_BOOT 0x10 /* Stop boot processes (for ATE) */
-#define AR6K_OPTION_ENABLE_NOANI 0x20 /* Operate without ANI */
-#define AR6K_OPTION_DSET_DISABLE 0x40 /* Ignore DataSets */
-#define AR6K_OPTION_IGNORE_FLASH 0x80 /* Ignore flash during bootup */
-
-/*
- * xxx_HOST_INTEREST_ADDRESS is the address in Target RAM of the
- * host_interest structure. It must match the address of the _host_interest
- * symbol (see linker script).
- *
- * Host Interest is shared between Host and Target in order to coordinate
- * between the two, and is intended to remain constant (with additions only
- * at the end) across software releases.
- *
- * All addresses are available here so that it's possible to
- * write a single binary that works with all Target Types.
- * May be used in assembler code as well as C.
- */
-#define AR6002_HOST_INTEREST_ADDRESS 0x00500400
-#define AR6003_HOST_INTEREST_ADDRESS 0x00540600
-
-
-#define HOST_INTEREST_MAX_SIZE 0x100
-
-#if !defined(__ASSEMBLER__)
-struct register_dump_s;
-struct dbglog_hdr_s;
-
-/*
- * These are items that the Host may need to access
- * via BMI or via the Diagnostic Window. The position
- * of items in this structure must remain constant
- * across firmware revisions!
- *
- * Types for each item must be fixed size across
- * target and host platforms.
- *
- * More items may be added at the end.
- */
-PREPACK struct host_interest_s {
- /*
- * Pointer to application-defined area, if any.
- * Set by Target application during startup.
- */
- u32 hi_app_host_interest; /* 0x00 */
-
- /* Pointer to register dump area, valid after Target crash. */
- u32 hi_failure_state; /* 0x04 */
-
- /* Pointer to debug logging header */
- u32 hi_dbglog_hdr; /* 0x08 */
-
- u32 hi_unused1; /* 0x0c */
-
- /*
- * General-purpose flag bits, similar to AR6000_OPTION_* flags.
- * Can be used by application rather than by OS.
- */
- u32 hi_option_flag; /* 0x10 */
-
- /*
- * Boolean that determines whether or not to
- * display messages on the serial port.
- */
- u32 hi_serial_enable; /* 0x14 */
-
- /* Start address of DataSet index, if any */
- u32 hi_dset_list_head; /* 0x18 */
-
- /* Override Target application start address */
- u32 hi_app_start; /* 0x1c */
-
- /* Clock and voltage tuning */
- u32 hi_skip_clock_init; /* 0x20 */
- u32 hi_core_clock_setting; /* 0x24 */
- u32 hi_cpu_clock_setting; /* 0x28 */
- u32 hi_system_sleep_setting; /* 0x2c */
- u32 hi_xtal_control_setting; /* 0x30 */
- u32 hi_pll_ctrl_setting_24ghz; /* 0x34 */
- u32 hi_pll_ctrl_setting_5ghz; /* 0x38 */
- u32 hi_ref_voltage_trim_setting; /* 0x3c */
- u32 hi_clock_info; /* 0x40 */
-
- /*
- * Flash configuration overrides, used only
- * when firmware is not executing from flash.
- * (When using flash, modify the global variables
- * with equivalent names.)
- */
- u32 hi_bank0_addr_value; /* 0x44 */
- u32 hi_bank0_read_value; /* 0x48 */
- u32 hi_bank0_write_value; /* 0x4c */
- u32 hi_bank0_config_value; /* 0x50 */
-
- /* Pointer to Board Data */
- u32 hi_board_data; /* 0x54 */
- u32 hi_board_data_initialized; /* 0x58 */
-
- u32 hi_dset_RAM_index_table; /* 0x5c */
-
- u32 hi_desired_baud_rate; /* 0x60 */
- u32 hi_dbglog_config; /* 0x64 */
- u32 hi_end_RAM_reserve_sz; /* 0x68 */
- u32 hi_mbox_io_block_sz; /* 0x6c */
-
- u32 hi_num_bpatch_streams; /* 0x70 -- unused */
- u32 hi_mbox_isr_yield_limit; /* 0x74 */
-
- u32 hi_refclk_hz; /* 0x78 */
- u32 hi_ext_clk_detected; /* 0x7c */
- u32 hi_dbg_uart_txpin; /* 0x80 */
- u32 hi_dbg_uart_rxpin; /* 0x84 */
- u32 hi_hci_uart_baud; /* 0x88 */
- u32 hi_hci_uart_pin_assignments; /* 0x8C */
- /* NOTE: byte [0] = tx pin, [1] = rx pin, [2] = rts pin, [3] = cts pin */
- u32 hi_hci_uart_baud_scale_val; /* 0x90 */
- u32 hi_hci_uart_baud_step_val; /* 0x94 */
-
- u32 hi_allocram_start; /* 0x98 */
- u32 hi_allocram_sz; /* 0x9c */
- u32 hi_hci_bridge_flags; /* 0xa0 */
- u32 hi_hci_uart_support_pins; /* 0xa4 */
- /* NOTE: byte [0] = RESET pin (bit 7 is polarity), bytes[1]..bytes[3] are for future use */
- u32 hi_hci_uart_pwr_mgmt_params; /* 0xa8 */
- /*
- * 0xa8 - [1]: 0 = UART FC active low, 1 = UART FC active high
- * [31:16]: wakeup timeout in ms
- */
-
- /* Pointer to extended board data */
- u32 hi_board_ext_data; /* 0xac */
- u32 hi_board_ext_data_config; /* 0xb0 */
-
- /*
- * Bit [0] : valid
- * Bit[31:16: size
- */
- /*
- * hi_reset_flag is used to do some stuff when target reset.
- * such as restore app_start after warm reset or
- * preserve host Interest area, or preserve ROM data, literals etc.
- */
- u32 hi_reset_flag; /* 0xb4 */
- /* indicate hi_reset_flag is valid */
- u32 hi_reset_flag_valid; /* 0xb8 */
- u32 hi_hci_uart_pwr_mgmt_params_ext; /* 0xbc */
- /*
- * 0xbc - [31:0]: idle timeout in ms
- */
- /* ACS flags */
- u32 hi_acs_flags; /* 0xc0 */
- u32 hi_console_flags; /* 0xc4 */
- u32 hi_nvram_state; /* 0xc8 */
- u32 hi_option_flag2; /* 0xcc */
-
- /* If non-zero, override values sent to Host in WMI_READY event. */
- u32 hi_sw_version_override; /* 0xd0 */
- u32 hi_abi_version_override; /* 0xd4 */
-
- /*
- * Percentage of high priority RX traffic to total expected RX traffic -
- * applicable only to ar6004
- */
- u32 hi_hp_rx_traffic_ratio; /* 0xd8 */
-
- /* test applications flags */
- u32 hi_test_apps_related ; /* 0xdc */
- /* location of test script */
- u32 hi_ota_testscript; /* 0xe0 */
- /* location of CAL data */
- u32 hi_cal_data; /* 0xe4 */
- /* Number of packet log buffers */
- u32 hi_pktlog_num_buffers; /* 0xe8 */
-
-} POSTPACK;
-
-/* Bits defined in hi_option_flag */
-#define HI_OPTION_TIMER_WAR 0x01 /* Enable timer workaround */
-#define HI_OPTION_BMI_CRED_LIMIT 0x02 /* Limit BMI command credits */
-#define HI_OPTION_RELAY_DOT11_HDR 0x04 /* Relay Dot11 hdr to/from host */
-/* MAC addr method 0-locally administred 1-globally unique addrs */
-#define HI_OPTION_MAC_ADDR_METHOD 0x08
-#define HI_OPTION_FW_BRIDGE 0x10 /* Firmware Bridging */
-#define HI_OPTION_ENABLE_PROFILE 0x20 /* Enable CPU profiling */
-#define HI_OPTION_DISABLE_DBGLOG 0x40 /* Disable debug logging */
-#define HI_OPTION_SKIP_ERA_TRACKING 0x80 /* Skip Era Tracking */
-#define HI_OPTION_PAPRD_DISABLE 0x100 /* Disable PAPRD (debug) */
-#define HI_OPTION_NUM_DEV_LSB 0x200
-#define HI_OPTION_NUM_DEV_MSB 0x800
-#define HI_OPTION_DEV_MODE_LSB 0x1000
-#define HI_OPTION_DEV_MODE_MSB 0x8000000
-/* Disable LowFreq Timer Stabilization */
-#define HI_OPTION_NO_LFT_STBL 0x10000000
-#define HI_OPTION_SKIP_REG_SCAN 0x20000000 /* Skip regulatory scan */
-/* Do regulatory scan during init beforesending WMI ready event to host */
-#define HI_OPTION_INIT_REG_SCAN 0x40000000
-#define HI_OPTION_SKIP_MEMMAP 0x80000000 /* REV6: Do not adjust memory
- map */
-
-/* hi_option_flag2 options */
-#define HI_OPTION_OFFLOAD_AMSDU 0x01
-#define HI_OPTION_DFS_SUPPORT 0x02 /* Enable DFS support */
-
-#define HI_OPTION_MAC_ADDR_METHOD_SHIFT 3
-
-/* 2 bits of hi_option_flag are used to represent 3 modes */
-#define HI_OPTION_FW_MODE_IBSS 0x0 /* IBSS Mode */
-#define HI_OPTION_FW_MODE_BSS_STA 0x1 /* STA Mode */
-#define HI_OPTION_FW_MODE_AP 0x2 /* AP Mode */
-
-/* 2 bits of hi_option flag are usedto represent 4 submodes */
-#define HI_OPTION_FW_SUBMODE_NONE 0x0 /* Normal mode */
-#define HI_OPTION_FW_SUBMODE_P2PDEV 0x1 /* p2p device mode */
-#define HI_OPTION_FW_SUBMODE_P2PCLIENT 0x2 /* p2p client mode */
-#define HI_OPTION_FW_SUBMODE_P2PGO 0x3 /* p2p go mode */
-
-/* Num dev Mask */
-#define HI_OPTION_NUM_DEV_MASK 0x7
-#define HI_OPTION_NUM_DEV_SHIFT 0x9
-
-/* firmware bridging */
-#define HI_OPTION_FW_BRIDGE_SHIFT 0x04
-
-/* Fw Mode/SubMode Mask
-|------------------------------------------------------------------------------|
-| SUB | SUB | SUB | SUB | | | |
-| MODE[3] | MODE[2] | MODE[1] | MODE[0] | MODE[3] | MODE[2] | MODE[1] | MODE[0|
-| (2) | (2) | (2) | (2) | (2) | (2) | (2) | (2)
-|------------------------------------------------------------------------------|
-*/
-#define HI_OPTION_FW_MODE_BITS 0x2
-#define HI_OPTION_FW_MODE_MASK 0x3
-#define HI_OPTION_FW_MODE_SHIFT 0xC
-#define HI_OPTION_ALL_FW_MODE_MASK 0xFF
-
-#define HI_OPTION_FW_SUBMODE_BITS 0x2
-#define HI_OPTION_FW_SUBMODE_MASK 0x3
-#define HI_OPTION_FW_SUBMODE_SHIFT 0x14
-#define HI_OPTION_ALL_FW_SUBMODE_MASK 0xFF00
-#define HI_OPTION_ALL_FW_SUBMODE_SHIFT 0x8
-
-/* hi_reset_flag */
-
-/* preserve App Start address */
-#define HI_RESET_FLAG_PRESERVE_APP_START 0x01
-/* preserve host interest */
-#define HI_RESET_FLAG_PRESERVE_HOST_INTEREST 0x02
-#define HI_RESET_FLAG_PRESERVE_ROMDATA 0x04 /* preserve ROM data */
-#define HI_RESET_FLAG_PRESERVE_NVRAM_STATE 0x08
-#define HI_RESET_FLAG_PRESERVE_BOOT_INFO 0x10
-
-#define HI_RESET_FLAG_IS_VALID 0x12345678 /* indicate the reset flag is
-valid */
-
-#define ON_RESET_FLAGS_VALID() \
- (HOST_INTEREST->hi_reset_flag_valid == HI_RESET_FLAG_IS_VALID)
-
-#define RESET_FLAGS_VALIDATE() \
- (HOST_INTEREST->hi_reset_flag_valid = HI_RESET_FLAG_IS_VALID)
-
-#define RESET_FLAGS_INVALIDATE() \
- (HOST_INTEREST->hi_reset_flag_valid = 0)
-
-#define ON_RESET_PRESERVE_APP_START() \
- (HOST_INTEREST->hi_reset_flag & HI_RESET_FLAG_PRESERVE_APP_START)
-
-#define ON_RESET_PRESERVE_NVRAM_STATE() \
- (HOST_INTEREST->hi_reset_flag & HI_RESET_FLAG_PRESERVE_NVRAM_STATE)
-
-#define ON_RESET_PRESERVE_HOST_INTEREST() \
- (HOST_INTEREST->hi_reset_flag & HI_RESET_FLAG_PRESERVE_HOST_INTEREST)
-
-#define ON_RESET_PRESERVE_ROMDATA() \
- (HOST_INTEREST->hi_reset_flag & HI_RESET_FLAG_PRESERVE_ROMDATA)
-
-#define ON_RESET_PRESERVE_BOOT_INFO() \
- (HOST_INTEREST->hi_reset_flag & HI_RESET_FLAG_PRESERVE_BOOT_INFO)
-
-#define HI_ACS_FLAGS_ENABLED (1 << 0) /* ACS is enabled */
-#define HI_ACS_FLAGS_USE_WWAN (1 << 1) /* Use physical WWAN device */
-#define HI_ACS_FLAGS_TEST_VAP (1 << 2) /* Use test VAP */
-
-/* CONSOLE FLAGS
- *
- * Bit Range Meaning
- * --------- --------------------------------
- * 2..0 UART ID (0 = Default)
- * 3 Baud Select (0 = 9600, 1 = 115200)
- * 30..4 Reserved
- * 31 Enable Console
- *
- */
-
-#define HI_CONSOLE_FLAGS_ENABLE (1 << 31)
-#define HI_CONSOLE_FLAGS_UART_MASK (0x7)
-#define HI_CONSOLE_FLAGS_UART_SHIFT 0
-#define HI_CONSOLE_FLAGS_BAUD_SELECT (1 << 3)
-
-/*
- * Intended for use by Host software, this macro returns the Target RAM
- * address of any item in the host_interest structure.
- * Example: target_addr = AR6002_HOST_INTEREST_ITEM_ADDRESS(hi_board_data);
- */
-#define AR6002_HOST_INTEREST_ITEM_ADDRESS(item) \
- (u32)((unsigned long)&((((struct host_interest_s *)(AR6002_HOST_INTEREST_ADDRESS))->item)))
-
-#define AR6003_HOST_INTEREST_ITEM_ADDRESS(item) \
- (u32)((unsigned long)&((((struct host_interest_s *)(AR6003_HOST_INTEREST_ADDRESS))->item)))
-
-#define AR6004_HOST_INTEREST_ITEM_ADDRESS(item) \
- ((u32)&((((struct host_interest_s *)(AR6004_HOST_INTEREST_ADDRESS))->item)))
-
-
-#define HOST_INTEREST_DBGLOG_IS_ENABLED() \
- (!(HOST_INTEREST->hi_option_flag & HI_OPTION_DISABLE_DBGLOG))
-
-#define HOST_INTEREST_PKTLOG_IS_ENABLED() \
- ((HOST_INTEREST->hi_pktlog_num_buffers))
-
-
-#define HOST_INTEREST_PROFILE_IS_ENABLED() \
- (HOST_INTEREST->hi_option_flag & HI_OPTION_ENABLE_PROFILE)
-
-#define LF_TIMER_STABILIZATION_IS_ENABLED() \
- (!(HOST_INTEREST->hi_option_flag & HI_OPTION_NO_LFT_STBL))
-
-#define IS_AMSDU_OFFLAOD_ENABLED() \
- ((HOST_INTEREST->hi_option_flag2 & HI_OPTION_OFFLOAD_AMSDU))
-
-#define HOST_INTEREST_DFS_IS_ENABLED() \
- ((HOST_INTEREST->hi_option_flag2 & HI_OPTION_DFS_SUPPORT))
-
-/* Convert a Target virtual address into a Target physical address */
-#define AR6002_VTOP(vaddr) ((vaddr) & 0x001fffff)
-#define AR6003_VTOP(vaddr) ((vaddr) & 0x001fffff)
-#define TARG_VTOP(TargetType, vaddr) \
- (((TargetType) == TARGET_TYPE_AR6002) ? AR6002_VTOP(vaddr) : AR6003_VTOP(vaddr))
-
-#define AR6003_REV2_APP_START_OVERRIDE 0x944C00
-#define AR6003_REV2_APP_LOAD_ADDRESS 0x543180
-#define AR6003_REV2_BOARD_EXT_DATA_ADDRESS 0x57E500
-#define AR6003_REV2_DATASET_PATCH_ADDRESS 0x57e884
-#define AR6003_REV2_RAM_RESERVE_SIZE 6912
-
-#define AR6003_REV3_APP_START_OVERRIDE 0x945d00
-#define AR6003_REV3_APP_LOAD_ADDRESS 0x545000
-#define AR6003_REV3_BOARD_EXT_DATA_ADDRESS 0x542330
-#define AR6003_REV3_DATASET_PATCH_ADDRESS 0x57FF74
-#define AR6003_REV3_RAM_RESERVE_SIZE 512
-
-#define AR6003_BOARD_EXT_DATA_ADDRESS 0x57E600
-
-/* # of u32 entries in targregs, used by DIAG_FETCH_TARG_REGS */
-#define AR6003_FETCH_TARG_REGS_COUNT 64
-
-#endif /* !__ASSEMBLER__ */
-
-#endif /* __TARGADDRS_H__ */
diff --git a/drivers/staging/ath6kl/include/common/testcmd.h b/drivers/staging/ath6kl/include/common/testcmd.h
deleted file mode 100644
index 7d94aee508b3..000000000000
--- a/drivers/staging/ath6kl/include/common/testcmd.h
+++ /dev/null
@@ -1,185 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="testcmd.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-
-#ifndef TESTCMD_H_
-#define TESTCMD_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef AR6002_REV2
-#define TCMD_MAX_RATES 12
-#else
-#define TCMD_MAX_RATES 28
-#endif
-
-typedef enum {
- ZEROES_PATTERN = 0,
- ONES_PATTERN,
- REPEATING_10,
- PN7_PATTERN,
- PN9_PATTERN,
- PN15_PATTERN
-}TX_DATA_PATTERN;
-
-/* Continuous tx
- mode : TCMD_CONT_TX_OFF - Disabling continuous tx
- TCMD_CONT_TX_SINE - Enable continuous unmodulated tx
- TCMD_CONT_TX_FRAME- Enable continuous modulated tx
- freq : Channel freq in Mhz. (e.g 2412 for channel 1 in 11 g)
-dataRate: 0 - 1 Mbps
- 1 - 2 Mbps
- 2 - 5.5 Mbps
- 3 - 11 Mbps
- 4 - 6 Mbps
- 5 - 9 Mbps
- 6 - 12 Mbps
- 7 - 18 Mbps
- 8 - 24 Mbps
- 9 - 36 Mbps
- 10 - 28 Mbps
- 11 - 54 Mbps
- txPwr: Tx power in dBm[5 -11] for unmod Tx, [5-14] for mod Tx
-antenna: 1 - one antenna
- 2 - two antenna
-Note : Enable/disable continuous tx test cmd works only when target is awake.
-*/
-
-typedef enum {
- TCMD_CONT_TX_OFF = 0,
- TCMD_CONT_TX_SINE,
- TCMD_CONT_TX_FRAME,
- TCMD_CONT_TX_TX99,
- TCMD_CONT_TX_TX100
-} TCMD_CONT_TX_MODE;
-
-typedef enum {
- TCMD_WLAN_MODE_NOHT = 0,
- TCMD_WLAN_MODE_HT20 = 1,
- TCMD_WLAN_MODE_HT40PLUS = 2,
- TCMD_WLAN_MODE_HT40MINUS = 3,
-} TCMD_WLAN_MODE;
-
-typedef PREPACK struct {
- u32 testCmdId;
- u32 mode;
- u32 freq;
- u32 dataRate;
- s32 txPwr;
- u32 antenna;
- u32 enANI;
- u32 scramblerOff;
- u32 aifsn;
- u16 pktSz;
- u16 txPattern;
- u32 shortGuard;
- u32 numPackets;
- u32 wlanMode;
-} POSTPACK TCMD_CONT_TX;
-
-#define TCMD_TXPATTERN_ZERONE 0x1
-#define TCMD_TXPATTERN_ZERONE_DIS_SCRAMBLE 0x2
-
-/* Continuous Rx
- act: TCMD_CONT_RX_PROMIS - promiscuous mode (accept all incoming frames)
- TCMD_CONT_RX_FILTER - filter mode (accept only frames with dest
- address equal specified
- mac address (set via act =3)
- TCMD_CONT_RX_REPORT off mode (disable cont rx mode and get the
- report from the last cont
- Rx test)
-
- TCMD_CONT_RX_SETMAC - set MacAddr mode (sets the MAC address for the
- target. This Overrides
- the default MAC address.)
-
-*/
-typedef enum {
- TCMD_CONT_RX_PROMIS =0,
- TCMD_CONT_RX_FILTER,
- TCMD_CONT_RX_REPORT,
- TCMD_CONT_RX_SETMAC,
- TCMD_CONT_RX_SET_ANT_SWITCH_TABLE
-} TCMD_CONT_RX_ACT;
-
-typedef PREPACK struct {
- u32 testCmdId;
- u32 act;
- u32 enANI;
- PREPACK union {
- struct PREPACK TCMD_CONT_RX_PARA {
- u32 freq;
- u32 antenna;
- u32 wlanMode;
- } POSTPACK para;
- struct PREPACK TCMD_CONT_RX_REPORT {
- u32 totalPkt;
- s32 rssiInDBm;
- u32 crcErrPkt;
- u32 secErrPkt;
- u16 rateCnt[TCMD_MAX_RATES];
- u16 rateCntShortGuard[TCMD_MAX_RATES];
- } POSTPACK report;
- struct PREPACK TCMD_CONT_RX_MAC {
- u8 addr[ATH_MAC_LEN];
- } POSTPACK mac;
- struct PREPACK TCMD_CONT_RX_ANT_SWITCH_TABLE {
- u32 antswitch1;
- u32 antswitch2;
- }POSTPACK antswitchtable;
- } POSTPACK u;
-} POSTPACK TCMD_CONT_RX;
-
-/* Force sleep/wake test cmd
- mode: TCMD_PM_WAKEUP - Wakeup the target
- TCMD_PM_SLEEP - Force the target to sleep.
- */
-typedef enum {
- TCMD_PM_WAKEUP = 1, /* be consistent with target */
- TCMD_PM_SLEEP,
- TCMD_PM_DEEPSLEEP
-} TCMD_PM_MODE;
-
-typedef PREPACK struct {
- u32 testCmdId;
- u32 mode;
-} POSTPACK TCMD_PM;
-
-typedef enum {
- TCMD_CONT_TX_ID,
- TCMD_CONT_RX_ID,
- TCMD_PM_ID
-} TCMD_ID;
-
-typedef PREPACK union {
- TCMD_CONT_TX contTx;
- TCMD_CONT_RX contRx;
- TCMD_PM pm;
-} POSTPACK TEST_CMD;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* TESTCMD_H_ */
diff --git a/drivers/staging/ath6kl/include/common/tlpm.h b/drivers/staging/ath6kl/include/common/tlpm.h
deleted file mode 100644
index 659b1c07ba90..000000000000
--- a/drivers/staging/ath6kl/include/common/tlpm.h
+++ /dev/null
@@ -1,38 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-
-#ifndef __TLPM_H__
-#define __TLPM_H__
-
-/* idle timeout in 16-bit value as in HOST_INTEREST hi_hci_uart_pwr_mgmt_params */
-#define TLPM_DEFAULT_IDLE_TIMEOUT_MS 1000
-/* hex in LSB and MSB for HCI command */
-#define TLPM_DEFAULT_IDLE_TIMEOUT_LSB 0xE8
-#define TLPM_DEFAULT_IDLE_TIMEOUT_MSB 0x3
-
-/* wakeup timeout in 8-bit value as in HOST_INTEREST hi_hci_uart_pwr_mgmt_params */
-#define TLPM_DEFAULT_WAKEUP_TIMEOUT_MS 10
-
-/* default UART FC polarity is low */
-#define TLPM_DEFAULT_UART_FC_POLARITY 0
-
-#endif
diff --git a/drivers/staging/ath6kl/include/common/wlan_defs.h b/drivers/staging/ath6kl/include/common/wlan_defs.h
deleted file mode 100644
index 03e4d23788ce..000000000000
--- a/drivers/staging/ath6kl/include/common/wlan_defs.h
+++ /dev/null
@@ -1,79 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="wlan_defs.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef __WLAN_DEFS_H__
-#define __WLAN_DEFS_H__
-
-/*
- * This file contains WLAN definitions that may be used across both
- * Host and Target software.
- */
-
-typedef enum {
- MODE_11A = 0, /* 11a Mode */
- MODE_11G = 1, /* 11b/g Mode */
- MODE_11B = 2, /* 11b Mode */
- MODE_11GONLY = 3, /* 11g only Mode */
-#ifdef SUPPORT_11N
- MODE_11NA_HT20 = 4, /* 11a HT20 mode */
- MODE_11NG_HT20 = 5, /* 11g HT20 mode */
- MODE_11NA_HT40 = 6, /* 11a HT40 mode */
- MODE_11NG_HT40 = 7, /* 11g HT40 mode */
- MODE_UNKNOWN = 8,
- MODE_MAX = 8
-#else
- MODE_UNKNOWN = 4,
- MODE_MAX = 4
-#endif
-} WLAN_PHY_MODE;
-
-typedef enum {
- WLAN_11A_CAPABILITY = 1,
- WLAN_11G_CAPABILITY = 2,
- WLAN_11AG_CAPABILITY = 3,
-}WLAN_CAPABILITY;
-
-#ifdef SUPPORT_11N
-typedef unsigned long A_RATEMASK;
-#else
-typedef unsigned short A_RATEMASK;
-#endif
-
-#ifdef SUPPORT_11N
-#define IS_MODE_11A(mode) (((mode) == MODE_11A) || \
- ((mode) == MODE_11NA_HT20) || \
- ((mode) == MODE_11NA_HT40))
-#define IS_MODE_11B(mode) ((mode) == MODE_11B)
-#define IS_MODE_11G(mode) (((mode) == MODE_11G) || \
- ((mode) == MODE_11GONLY) || \
- ((mode) == MODE_11NG_HT20) || \
- ((mode) == MODE_11NG_HT40))
-#define IS_MODE_11GONLY(mode) ((mode) == MODE_11GONLY)
-#else
-#define IS_MODE_11A(mode) ((mode) == MODE_11A)
-#define IS_MODE_11B(mode) ((mode) == MODE_11B)
-#define IS_MODE_11G(mode) (((mode) == MODE_11G) || \
- ((mode) == MODE_11GONLY))
-#define IS_MODE_11GONLY(mode) ((mode) == MODE_11GONLY)
-#endif /* SUPPORT_11N */
-
-#endif /* __WLANDEFS_H__ */
diff --git a/drivers/staging/ath6kl/include/common/wmi.h b/drivers/staging/ath6kl/include/common/wmi.h
deleted file mode 100644
index d9687443d32c..000000000000
--- a/drivers/staging/ath6kl/include/common/wmi.h
+++ /dev/null
@@ -1,3220 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//
-// Author(s): ="Atheros"
-//------------------------------------------------------------------------------
-
-/*
- * This file contains the definitions of the WMI protocol specified in the
- * Wireless Module Interface (WMI). It includes definitions of all the
- * commands and events. Commands are messages from the host to the WM.
- * Events and Replies are messages from the WM to the host.
- *
- * Ownership of correctness in regards to commands
- * belongs to the host driver and the WMI is not required to validate
- * parameters for value, proper range, or any other checking.
- *
- */
-
-#ifndef _WMI_H_
-#define _WMI_H_
-
-#include "wmix.h"
-#include "wlan_defs.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define HTC_PROTOCOL_VERSION 0x0002
-#define HTC_PROTOCOL_REVISION 0x0000
-
-#define WMI_PROTOCOL_VERSION 0x0002
-#define WMI_PROTOCOL_REVISION 0x0000
-
-#define ATH_MAC_LEN 6 /* length of mac in bytes */
-#define WMI_CMD_MAX_LEN 100
-#define WMI_CONTROL_MSG_MAX_LEN 256
-#define WMI_OPT_CONTROL_MSG_MAX_LEN 1536
-#define IS_ETHERTYPE(_typeOrLen) ((_typeOrLen) >= 0x0600)
-#define RFC1042OUI {0x00, 0x00, 0x00}
-
-#define IP_ETHERTYPE 0x0800
-
-#define WMI_IMPLICIT_PSTREAM 0xFF
-#define WMI_MAX_THINSTREAM 15
-
-#ifdef AR6002_REV2
-#define IBSS_MAX_NUM_STA 4
-#else
-#define IBSS_MAX_NUM_STA 8
-#endif
-
-PREPACK struct host_app_area_s {
- u32 wmi_protocol_ver;
-} POSTPACK;
-
-/*
- * Data Path
- */
-typedef PREPACK struct {
- u8 dstMac[ATH_MAC_LEN];
- u8 srcMac[ATH_MAC_LEN];
- u16 typeOrLen;
-} POSTPACK ATH_MAC_HDR;
-
-typedef PREPACK struct {
- u8 dsap;
- u8 ssap;
- u8 cntl;
- u8 orgCode[3];
- u16 etherType;
-} POSTPACK ATH_LLC_SNAP_HDR;
-
-typedef enum {
- DATA_MSGTYPE = 0x0,
- CNTL_MSGTYPE,
- SYNC_MSGTYPE,
- OPT_MSGTYPE,
-} WMI_MSG_TYPE;
-
-
-/*
- * Macros for operating on WMI_DATA_HDR (info) field
- */
-
-#define WMI_DATA_HDR_MSG_TYPE_MASK 0x03
-#define WMI_DATA_HDR_MSG_TYPE_SHIFT 0
-#define WMI_DATA_HDR_UP_MASK 0x07
-#define WMI_DATA_HDR_UP_SHIFT 2
-/* In AP mode, the same bit (b5) is used to indicate Power save state in
- * the Rx dir and More data bit state in the tx direction.
- */
-#define WMI_DATA_HDR_PS_MASK 0x1
-#define WMI_DATA_HDR_PS_SHIFT 5
-
-#define WMI_DATA_HDR_MORE_MASK 0x1
-#define WMI_DATA_HDR_MORE_SHIFT 5
-
-typedef enum {
- WMI_DATA_HDR_DATA_TYPE_802_3 = 0,
- WMI_DATA_HDR_DATA_TYPE_802_11,
- WMI_DATA_HDR_DATA_TYPE_ACL, /* used to be used for the PAL */
-} WMI_DATA_HDR_DATA_TYPE;
-
-#define WMI_DATA_HDR_DATA_TYPE_MASK 0x3
-#define WMI_DATA_HDR_DATA_TYPE_SHIFT 6
-
-#define WMI_DATA_HDR_SET_MORE_BIT(h) ((h)->info |= (WMI_DATA_HDR_MORE_MASK << WMI_DATA_HDR_MORE_SHIFT))
-
-#define WMI_DATA_HDR_IS_MSG_TYPE(h, t) (((h)->info & (WMI_DATA_HDR_MSG_TYPE_MASK)) == (t))
-#define WMI_DATA_HDR_SET_MSG_TYPE(h, t) (h)->info = (((h)->info & ~(WMI_DATA_HDR_MSG_TYPE_MASK << WMI_DATA_HDR_MSG_TYPE_SHIFT)) | (t << WMI_DATA_HDR_MSG_TYPE_SHIFT))
-#define WMI_DATA_HDR_GET_UP(h) (((h)->info >> WMI_DATA_HDR_UP_SHIFT) & WMI_DATA_HDR_UP_MASK)
-#define WMI_DATA_HDR_SET_UP(h, p) (h)->info = (((h)->info & ~(WMI_DATA_HDR_UP_MASK << WMI_DATA_HDR_UP_SHIFT)) | (p << WMI_DATA_HDR_UP_SHIFT))
-
-#define WMI_DATA_HDR_GET_DATA_TYPE(h) (((h)->info >> WMI_DATA_HDR_DATA_TYPE_SHIFT) & WMI_DATA_HDR_DATA_TYPE_MASK)
-#define WMI_DATA_HDR_SET_DATA_TYPE(h, p) (h)->info = (((h)->info & ~(WMI_DATA_HDR_DATA_TYPE_MASK << WMI_DATA_HDR_DATA_TYPE_SHIFT)) | ((p) << WMI_DATA_HDR_DATA_TYPE_SHIFT))
-
-#define WMI_DATA_HDR_GET_DOT11(h) (WMI_DATA_HDR_GET_DATA_TYPE((h)) == WMI_DATA_HDR_DATA_TYPE_802_11)
-#define WMI_DATA_HDR_SET_DOT11(h, p) WMI_DATA_HDR_SET_DATA_TYPE((h), (p))
-
-/* Macros for operating on WMI_DATA_HDR (info2) field */
-#define WMI_DATA_HDR_SEQNO_MASK 0xFFF
-#define WMI_DATA_HDR_SEQNO_SHIFT 0
-
-#define WMI_DATA_HDR_AMSDU_MASK 0x1
-#define WMI_DATA_HDR_AMSDU_SHIFT 12
-
-#define WMI_DATA_HDR_META_MASK 0x7
-#define WMI_DATA_HDR_META_SHIFT 13
-
-#define GET_SEQ_NO(_v) ((_v) & WMI_DATA_HDR_SEQNO_MASK)
-#define GET_ISMSDU(_v) ((_v) & WMI_DATA_HDR_AMSDU_MASK)
-
-#define WMI_DATA_HDR_GET_SEQNO(h) GET_SEQ_NO((h)->info2 >> WMI_DATA_HDR_SEQNO_SHIFT)
-#define WMI_DATA_HDR_SET_SEQNO(h, _v) ((h)->info2 = ((h)->info2 & ~(WMI_DATA_HDR_SEQNO_MASK << WMI_DATA_HDR_SEQNO_SHIFT)) | (GET_SEQ_NO(_v) << WMI_DATA_HDR_SEQNO_SHIFT))
-
-#define WMI_DATA_HDR_IS_AMSDU(h) GET_ISMSDU((h)->info2 >> WMI_DATA_HDR_AMSDU_SHIFT)
-#define WMI_DATA_HDR_SET_AMSDU(h, _v) ((h)->info2 = ((h)->info2 & ~(WMI_DATA_HDR_AMSDU_MASK << WMI_DATA_HDR_AMSDU_SHIFT)) | (GET_ISMSDU(_v) << WMI_DATA_HDR_AMSDU_SHIFT))
-
-#define WMI_DATA_HDR_GET_META(h) (((h)->info2 >> WMI_DATA_HDR_META_SHIFT) & WMI_DATA_HDR_META_MASK)
-#define WMI_DATA_HDR_SET_META(h, _v) ((h)->info2 = ((h)->info2 & ~(WMI_DATA_HDR_META_MASK << WMI_DATA_HDR_META_SHIFT)) | ((_v) << WMI_DATA_HDR_META_SHIFT))
-
-/* Macros for operating on WMI_DATA_HDR (info3) field */
-#define WMI_DATA_HDR_DEVID_MASK 0xF
-#define WMI_DATA_HDR_DEVID_SHIFT 0
-#define GET_DEVID(_v) ((_v) & WMI_DATA_HDR_DEVID_MASK)
-
-#define WMI_DATA_HDR_GET_DEVID(h) \
- (((h)->info3 >> WMI_DATA_HDR_DEVID_SHIFT) & WMI_DATA_HDR_DEVID_MASK)
-#define WMI_DATA_HDR_SET_DEVID(h, _v) \
- ((h)->info3 = ((h)->info3 & ~(WMI_DATA_HDR_DEVID_MASK << WMI_DATA_HDR_DEVID_SHIFT)) | (GET_DEVID(_v) << WMI_DATA_HDR_DEVID_SHIFT))
-
-typedef PREPACK struct {
- s8 rssi;
- u8 info; /* usage of 'info' field(8-bit):
- * b1:b0 - WMI_MSG_TYPE
- * b4:b3:b2 - UP(tid)
- * b5 - Used in AP mode. More-data in tx dir, PS in rx.
- * b7:b6 - Dot3 header(0),
- * Dot11 Header(1),
- * ACL data(2)
- */
-
- u16 info2; /* usage of 'info2' field(16-bit):
- * b11:b0 - seq_no
- * b12 - A-MSDU?
- * b15:b13 - META_DATA_VERSION 0 - 7
- */
- u16 info3;
-} POSTPACK WMI_DATA_HDR;
-
-/*
- * TX META VERSION DEFINITIONS
- */
-#define WMI_MAX_TX_META_SZ (12)
-#define WMI_MAX_TX_META_VERSION (7)
-#define WMI_META_VERSION_1 (0x01)
-#define WMI_META_VERSION_2 (0X02)
-
-#define WMI_ACL_TO_DOT11_HEADROOM 36
-
-#if 0 /* removed to prevent compile errors for WM.. */
-typedef PREPACK struct {
-/* intentionally empty. Default version is no meta data. */
-} POSTPACK WMI_TX_META_V0;
-#endif
-
-typedef PREPACK struct {
- u8 pktID; /* The packet ID to identify the tx request */
- u8 ratePolicyID; /* The rate policy to be used for the tx of this frame */
-} POSTPACK WMI_TX_META_V1;
-
-
-#define WMI_CSUM_DIR_TX (0x1)
-#define TX_CSUM_CALC_FILL (0x1)
-typedef PREPACK struct {
- u8 csumStart; /*Offset from start of the WMI header for csum calculation to begin */
- u8 csumDest; /*Offset from start of WMI header where final csum goes*/
- u8 csumFlags; /*number of bytes over which csum is calculated*/
-} POSTPACK WMI_TX_META_V2;
-
-
-/*
- * RX META VERSION DEFINITIONS
- */
-/* if RX meta data is present at all then the meta data field
- * will consume WMI_MAX_RX_META_SZ bytes of space between the
- * WMI_DATA_HDR and the payload. How much of the available
- * Meta data is actually used depends on which meta data
- * version is active. */
-#define WMI_MAX_RX_META_SZ (12)
-#define WMI_MAX_RX_META_VERSION (7)
-
-#define WMI_RX_STATUS_OK 0 /* success */
-#define WMI_RX_STATUS_DECRYPT_ERR 1 /* decrypt error */
-#define WMI_RX_STATUS_MIC_ERR 2 /* tkip MIC error */
-#define WMI_RX_STATUS_ERR 3 /* undefined error */
-
-#define WMI_RX_FLAGS_AGGR 0x0001 /* part of AGGR */
-#define WMI_RX_FlAGS_STBC 0x0002 /* used STBC */
-#define WMI_RX_FLAGS_SGI 0x0004 /* used SGI */
-#define WMI_RX_FLAGS_HT 0x0008 /* is HT packet */
-/* the flags field is also used to store the CRYPTO_TYPE of the frame
- * that value is shifted by WMI_RX_FLAGS_CRYPTO_SHIFT */
-#define WMI_RX_FLAGS_CRYPTO_SHIFT 4
-#define WMI_RX_FLAGS_CRYPTO_MASK 0x1f
-#define WMI_RX_META_GET_CRYPTO(flags) (((flags) >> WMI_RX_FLAGS_CRYPTO_SHIFT) & WMI_RX_FLAGS_CRYPTO_MASK)
-
-#if 0 /* removed to prevent compile errors for WM.. */
-typedef PREPACK struct {
-/* intentionally empty. Default version is no meta data. */
-} POSTPACK WMI_RX_META_VERSION_0;
-#endif
-
-typedef PREPACK struct {
- u8 status; /* one of WMI_RX_STATUS_... */
- u8 rix; /* rate index mapped to rate at which this packet was received. */
- u8 rssi; /* rssi of packet */
- u8 channel;/* rf channel during packet reception */
- u16 flags; /* a combination of WMI_RX_FLAGS_... */
-} POSTPACK WMI_RX_META_V1;
-
-#define RX_CSUM_VALID_FLAG (0x1)
-typedef PREPACK struct {
- u16 csum;
- u8 csumFlags;/* bit 0 set -partial csum valid
- bit 1 set -test mode */
-} POSTPACK WMI_RX_META_V2;
-
-
-
-#define WMI_GET_DEVICE_ID(info1) ((info1) & 0xF)
-/* Macros for operating on WMI_CMD_HDR (info1) field */
-#define WMI_CMD_HDR_DEVID_MASK 0xF
-#define WMI_CMD_HDR_DEVID_SHIFT 0
-#define GET_CMD_DEVID(_v) ((_v) & WMI_CMD_HDR_DEVID_MASK)
-
-#define WMI_CMD_HDR_GET_DEVID(h) \
- (((h)->info1 >> WMI_CMD_HDR_DEVID_SHIFT) & WMI_CMD_HDR_DEVID_MASK)
-#define WMI_CMD_HDR_SET_DEVID(h, _v) \
- ((h)->info1 = ((h)->info1 & \
- ~(WMI_CMD_HDR_DEVID_MASK << WMI_CMD_HDR_DEVID_SHIFT)) | \
- (GET_CMD_DEVID(_v) << WMI_CMD_HDR_DEVID_SHIFT))
-
-/*
- * Control Path
- */
-typedef PREPACK struct {
- u16 commandId;
-/*
- * info1 - 16 bits
- * b03:b00 - id
- * b15:b04 - unused
- */
- u16 info1;
-
- u16 reserved; /* For alignment */
-} POSTPACK WMI_CMD_HDR; /* used for commands and events */
-
-/*
- * List of Commnands
- */
-typedef enum {
- WMI_CONNECT_CMDID = 0x0001,
- WMI_RECONNECT_CMDID,
- WMI_DISCONNECT_CMDID,
- WMI_SYNCHRONIZE_CMDID,
- WMI_CREATE_PSTREAM_CMDID,
- WMI_DELETE_PSTREAM_CMDID,
- WMI_START_SCAN_CMDID,
- WMI_SET_SCAN_PARAMS_CMDID,
- WMI_SET_BSS_FILTER_CMDID,
- WMI_SET_PROBED_SSID_CMDID, /* 10 */
- WMI_SET_LISTEN_INT_CMDID,
- WMI_SET_BMISS_TIME_CMDID,
- WMI_SET_DISC_TIMEOUT_CMDID,
- WMI_GET_CHANNEL_LIST_CMDID,
- WMI_SET_BEACON_INT_CMDID,
- WMI_GET_STATISTICS_CMDID,
- WMI_SET_CHANNEL_PARAMS_CMDID,
- WMI_SET_POWER_MODE_CMDID,
- WMI_SET_IBSS_PM_CAPS_CMDID,
- WMI_SET_POWER_PARAMS_CMDID, /* 20 */
- WMI_SET_POWERSAVE_TIMERS_POLICY_CMDID,
- WMI_ADD_CIPHER_KEY_CMDID,
- WMI_DELETE_CIPHER_KEY_CMDID,
- WMI_ADD_KRK_CMDID,
- WMI_DELETE_KRK_CMDID,
- WMI_SET_PMKID_CMDID,
- WMI_SET_TX_PWR_CMDID,
- WMI_GET_TX_PWR_CMDID,
- WMI_SET_ASSOC_INFO_CMDID,
- WMI_ADD_BAD_AP_CMDID, /* 30 */
- WMI_DELETE_BAD_AP_CMDID,
- WMI_SET_TKIP_COUNTERMEASURES_CMDID,
- WMI_RSSI_THRESHOLD_PARAMS_CMDID,
- WMI_TARGET_ERROR_REPORT_BITMASK_CMDID,
- WMI_SET_ACCESS_PARAMS_CMDID,
- WMI_SET_RETRY_LIMITS_CMDID,
- WMI_SET_OPT_MODE_CMDID,
- WMI_OPT_TX_FRAME_CMDID,
- WMI_SET_VOICE_PKT_SIZE_CMDID,
- WMI_SET_MAX_SP_LEN_CMDID, /* 40 */
- WMI_SET_ROAM_CTRL_CMDID,
- WMI_GET_ROAM_TBL_CMDID,
- WMI_GET_ROAM_DATA_CMDID,
- WMI_ENABLE_RM_CMDID,
- WMI_SET_MAX_OFFHOME_DURATION_CMDID,
- WMI_EXTENSION_CMDID, /* Non-wireless extensions */
- WMI_SNR_THRESHOLD_PARAMS_CMDID,
- WMI_LQ_THRESHOLD_PARAMS_CMDID,
- WMI_SET_LPREAMBLE_CMDID,
- WMI_SET_RTS_CMDID, /* 50 */
- WMI_CLR_RSSI_SNR_CMDID,
- WMI_SET_FIXRATES_CMDID,
- WMI_GET_FIXRATES_CMDID,
- WMI_SET_AUTH_MODE_CMDID,
- WMI_SET_REASSOC_MODE_CMDID,
- WMI_SET_WMM_CMDID,
- WMI_SET_WMM_TXOP_CMDID,
- WMI_TEST_CMDID,
- /* COEX AR6002 only*/
- WMI_SET_BT_STATUS_CMDID,
- WMI_SET_BT_PARAMS_CMDID, /* 60 */
-
- WMI_SET_KEEPALIVE_CMDID,
- WMI_GET_KEEPALIVE_CMDID,
- WMI_SET_APPIE_CMDID,
- WMI_GET_APPIE_CMDID,
- WMI_SET_WSC_STATUS_CMDID,
-
- /* Wake on Wireless */
- WMI_SET_HOST_SLEEP_MODE_CMDID,
- WMI_SET_WOW_MODE_CMDID,
- WMI_GET_WOW_LIST_CMDID,
- WMI_ADD_WOW_PATTERN_CMDID,
- WMI_DEL_WOW_PATTERN_CMDID, /* 70 */
-
- WMI_SET_FRAMERATES_CMDID,
- WMI_SET_AP_PS_CMDID,
- WMI_SET_QOS_SUPP_CMDID,
- /* WMI_THIN_RESERVED_... mark the start and end
- * values for WMI_THIN_RESERVED command IDs. These
- * command IDs can be found in wmi_thin.h */
- WMI_THIN_RESERVED_START = 0x8000,
- WMI_THIN_RESERVED_END = 0x8fff,
- /*
- * Developer commands starts at 0xF000
- */
- WMI_SET_BITRATE_CMDID = 0xF000,
- WMI_GET_BITRATE_CMDID,
- WMI_SET_WHALPARAM_CMDID,
-
-
- /*Should add the new command to the tail for compatible with
- * etna.
- */
- WMI_SET_MAC_ADDRESS_CMDID,
- WMI_SET_AKMP_PARAMS_CMDID,
- WMI_SET_PMKID_LIST_CMDID,
- WMI_GET_PMKID_LIST_CMDID,
- WMI_ABORT_SCAN_CMDID,
- WMI_SET_TARGET_EVENT_REPORT_CMDID,
-
- // Unused
- WMI_UNUSED1,
- WMI_UNUSED2,
-
- /*
- * AP mode commands
- */
- WMI_AP_HIDDEN_SSID_CMDID,
- WMI_AP_SET_NUM_STA_CMDID,
- WMI_AP_ACL_POLICY_CMDID,
- WMI_AP_ACL_MAC_LIST_CMDID,
- WMI_AP_CONFIG_COMMIT_CMDID,
- WMI_AP_SET_MLME_CMDID,
- WMI_AP_SET_PVB_CMDID,
- WMI_AP_CONN_INACT_CMDID,
- WMI_AP_PROT_SCAN_TIME_CMDID,
- WMI_AP_SET_COUNTRY_CMDID,
- WMI_AP_SET_DTIM_CMDID,
- WMI_AP_MODE_STAT_CMDID,
-
- WMI_SET_IP_CMDID,
- WMI_SET_PARAMS_CMDID,
- WMI_SET_MCAST_FILTER_CMDID,
- WMI_DEL_MCAST_FILTER_CMDID,
-
- WMI_ALLOW_AGGR_CMDID,
- WMI_ADDBA_REQ_CMDID,
- WMI_DELBA_REQ_CMDID,
- WMI_SET_HT_CAP_CMDID,
- WMI_SET_HT_OP_CMDID,
- WMI_SET_TX_SELECT_RATES_CMDID,
- WMI_SET_TX_SGI_PARAM_CMDID,
- WMI_SET_RATE_POLICY_CMDID,
-
- WMI_HCI_CMD_CMDID,
- WMI_RX_FRAME_FORMAT_CMDID,
- WMI_SET_THIN_MODE_CMDID,
- WMI_SET_BT_WLAN_CONN_PRECEDENCE_CMDID,
-
- WMI_AP_SET_11BG_RATESET_CMDID,
- WMI_SET_PMK_CMDID,
- WMI_MCAST_FILTER_CMDID,
- /* COEX CMDID AR6003*/
- WMI_SET_BTCOEX_FE_ANT_CMDID,
- WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMDID,
- WMI_SET_BTCOEX_SCO_CONFIG_CMDID,
- WMI_SET_BTCOEX_A2DP_CONFIG_CMDID,
- WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMDID,
- WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG_CMDID,
- WMI_SET_BTCOEX_DEBUG_CMDID,
- WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMDID,
- WMI_GET_BTCOEX_STATS_CMDID,
- WMI_GET_BTCOEX_CONFIG_CMDID,
-
- WMI_SET_DFS_ENABLE_CMDID, /* F034 */
- WMI_SET_DFS_MINRSSITHRESH_CMDID,
- WMI_SET_DFS_MAXPULSEDUR_CMDID,
- WMI_DFS_RADAR_DETECTED_CMDID,
-
- /* P2P CMDS */
- WMI_P2P_SET_CONFIG_CMDID, /* F038 */
- WMI_WPS_SET_CONFIG_CMDID,
- WMI_SET_REQ_DEV_ATTR_CMDID,
- WMI_P2P_FIND_CMDID,
- WMI_P2P_STOP_FIND_CMDID,
- WMI_P2P_GO_NEG_START_CMDID,
- WMI_P2P_LISTEN_CMDID,
-
- WMI_CONFIG_TX_MAC_RULES_CMDID, /* F040 */
- WMI_SET_PROMISCUOUS_MODE_CMDID,
- WMI_RX_FRAME_FILTER_CMDID,
- WMI_SET_CHANNEL_CMDID,
-
- /* WAC commands */
- WMI_ENABLE_WAC_CMDID,
- WMI_WAC_SCAN_REPLY_CMDID,
- WMI_WAC_CTRL_REQ_CMDID,
- WMI_SET_DIV_PARAMS_CMDID,
-
- WMI_GET_PMK_CMDID,
- WMI_SET_PASSPHRASE_CMDID,
- WMI_SEND_ASSOC_RES_CMDID,
- WMI_SET_ASSOC_REQ_RELAY_CMDID,
- WMI_GET_RFKILL_MODE_CMDID,
-
- /* ACS command, consists of sub-commands */
- WMI_ACS_CTRL_CMDID,
-
- /* Ultra low power store / recall commands */
- WMI_STORERECALL_CONFIGURE_CMDID,
- WMI_STORERECALL_RECALL_CMDID,
- WMI_STORERECALL_HOST_READY_CMDID,
- WMI_FORCE_TARGET_ASSERT_CMDID,
- WMI_SET_EXCESS_TX_RETRY_THRES_CMDID,
-} WMI_COMMAND_ID;
-
-/*
- * Frame Types
- */
-typedef enum {
- WMI_FRAME_BEACON = 0,
- WMI_FRAME_PROBE_REQ,
- WMI_FRAME_PROBE_RESP,
- WMI_FRAME_ASSOC_REQ,
- WMI_FRAME_ASSOC_RESP,
- WMI_NUM_MGMT_FRAME
-} WMI_MGMT_FRAME_TYPE;
-
-/*
- * Connect Command
- */
-typedef enum {
- INFRA_NETWORK = 0x01,
- ADHOC_NETWORK = 0x02,
- ADHOC_CREATOR = 0x04,
- AP_NETWORK = 0x10,
-} NETWORK_TYPE;
-
-typedef enum {
- OPEN_AUTH = 0x01,
- SHARED_AUTH = 0x02,
- LEAP_AUTH = 0x04, /* different from IEEE_AUTH_MODE definitions */
-} DOT11_AUTH_MODE;
-
-enum {
- AUTH_IDLE,
- AUTH_OPEN_IN_PROGRESS,
-};
-
-typedef enum {
- NONE_AUTH = 0x01,
- WPA_AUTH = 0x02,
- WPA2_AUTH = 0x04,
- WPA_PSK_AUTH = 0x08,
- WPA2_PSK_AUTH = 0x10,
- WPA_AUTH_CCKM = 0x20,
- WPA2_AUTH_CCKM = 0x40,
-} AUTH_MODE;
-
-typedef enum {
- NONE_CRYPT = 0x01,
- WEP_CRYPT = 0x02,
- TKIP_CRYPT = 0x04,
- AES_CRYPT = 0x08,
-#ifdef WAPI_ENABLE
- WAPI_CRYPT = 0x10,
-#endif /*WAPI_ENABLE*/
-} CRYPTO_TYPE;
-
-#define WMI_MIN_CRYPTO_TYPE NONE_CRYPT
-#define WMI_MAX_CRYPTO_TYPE (AES_CRYPT + 1)
-
-#ifdef WAPI_ENABLE
-#undef WMI_MAX_CRYPTO_TYPE
-#define WMI_MAX_CRYPTO_TYPE (WAPI_CRYPT + 1)
-#endif /* WAPI_ENABLE */
-
-#ifdef WAPI_ENABLE
-#define IW_ENCODE_ALG_SM4 0x20
-#define IW_AUTH_WAPI_ENABLED 0x20
-#endif
-
-#define WMI_MIN_KEY_INDEX 0
-#define WMI_MAX_KEY_INDEX 3
-
-#ifdef WAPI_ENABLE
-#undef WMI_MAX_KEY_INDEX
-#define WMI_MAX_KEY_INDEX 7 /* wapi grpKey 0-3, prwKey 4-7 */
-#endif /* WAPI_ENABLE */
-
-#define WMI_MAX_KEY_LEN 32
-
-#define WMI_MAX_SSID_LEN 32
-
-typedef enum {
- CONNECT_ASSOC_POLICY_USER = 0x0001,
- CONNECT_SEND_REASSOC = 0x0002,
- CONNECT_IGNORE_WPAx_GROUP_CIPHER = 0x0004,
- CONNECT_PROFILE_MATCH_DONE = 0x0008,
- CONNECT_IGNORE_AAC_BEACON = 0x0010,
- CONNECT_CSA_FOLLOW_BSS = 0x0020,
- CONNECT_DO_WPA_OFFLOAD = 0x0040,
- CONNECT_DO_NOT_DEAUTH = 0x0080,
-} WMI_CONNECT_CTRL_FLAGS_BITS;
-
-#define DEFAULT_CONNECT_CTRL_FLAGS (CONNECT_CSA_FOLLOW_BSS)
-
-typedef PREPACK struct {
- u8 networkType;
- u8 dot11AuthMode;
- u8 authMode;
- u8 pairwiseCryptoType;
- u8 pairwiseCryptoLen;
- u8 groupCryptoType;
- u8 groupCryptoLen;
- u8 ssidLength;
- u8 ssid[WMI_MAX_SSID_LEN];
- u16 channel;
- u8 bssid[ATH_MAC_LEN];
- u32 ctrl_flags;
-} POSTPACK WMI_CONNECT_CMD;
-
-/*
- * WMI_RECONNECT_CMDID
- */
-typedef PREPACK struct {
- u16 channel; /* hint */
- u8 bssid[ATH_MAC_LEN]; /* mandatory if set */
-} POSTPACK WMI_RECONNECT_CMD;
-
-#define WMI_PMK_LEN 32
-typedef PREPACK struct {
- u8 pmk[WMI_PMK_LEN];
-} POSTPACK WMI_SET_PMK_CMD;
-
-/*
- * WMI_SET_EXCESS_TX_RETRY_THRES_CMDID
- */
-typedef PREPACK struct {
- u32 threshold;
-} POSTPACK WMI_SET_EXCESS_TX_RETRY_THRES_CMD;
-
-/*
- * WMI_ADD_CIPHER_KEY_CMDID
- */
-typedef enum {
- PAIRWISE_USAGE = 0x00,
- GROUP_USAGE = 0x01,
- TX_USAGE = 0x02, /* default Tx Key - Static WEP only */
-} KEY_USAGE;
-
-/*
- * Bit Flag
- * Bit 0 - Initialise TSC - default is Initialize
- */
-#define KEY_OP_INIT_TSC 0x01
-#define KEY_OP_INIT_RSC 0x02
-#ifdef WAPI_ENABLE
-#define KEY_OP_INIT_WAPIPN 0x10
-#endif /* WAPI_ENABLE */
-
-#define KEY_OP_INIT_VAL 0x03 /* Default Initialise the TSC & RSC */
-#define KEY_OP_VALID_MASK 0x03
-
-typedef PREPACK struct {
- u8 keyIndex;
- u8 keyType;
- u8 keyUsage; /* KEY_USAGE */
- u8 keyLength;
- u8 keyRSC[8]; /* key replay sequence counter */
- u8 key[WMI_MAX_KEY_LEN];
- u8 key_op_ctrl; /* Additional Key Control information */
- u8 key_macaddr[ATH_MAC_LEN];
-} POSTPACK WMI_ADD_CIPHER_KEY_CMD;
-
-/*
- * WMI_DELETE_CIPHER_KEY_CMDID
- */
-typedef PREPACK struct {
- u8 keyIndex;
-} POSTPACK WMI_DELETE_CIPHER_KEY_CMD;
-
-#define WMI_KRK_LEN 16
-/*
- * WMI_ADD_KRK_CMDID
- */
-typedef PREPACK struct {
- u8 krk[WMI_KRK_LEN];
-} POSTPACK WMI_ADD_KRK_CMD;
-
-/*
- * WMI_SET_TKIP_COUNTERMEASURES_CMDID
- */
-typedef enum {
- WMI_TKIP_CM_DISABLE = 0x0,
- WMI_TKIP_CM_ENABLE = 0x1,
-} WMI_TKIP_CM_CONTROL;
-
-typedef PREPACK struct {
- u8 cm_en; /* WMI_TKIP_CM_CONTROL */
-} POSTPACK WMI_SET_TKIP_COUNTERMEASURES_CMD;
-
-/*
- * WMI_SET_PMKID_CMDID
- */
-
-#define WMI_PMKID_LEN 16
-
-typedef enum {
- PMKID_DISABLE = 0,
- PMKID_ENABLE = 1,
-} PMKID_ENABLE_FLG;
-
-typedef PREPACK struct {
- u8 bssid[ATH_MAC_LEN];
- u8 enable; /* PMKID_ENABLE_FLG */
- u8 pmkid[WMI_PMKID_LEN];
-} POSTPACK WMI_SET_PMKID_CMD;
-
-/*
- * WMI_START_SCAN_CMD
- */
-typedef enum {
- WMI_LONG_SCAN = 0,
- WMI_SHORT_SCAN = 1,
-} WMI_SCAN_TYPE;
-
-typedef PREPACK struct {
- u32 forceFgScan;
- u32 isLegacy; /* For Legacy Cisco AP compatibility */
- u32 homeDwellTime; /* Maximum duration in the home channel(milliseconds) */
- u32 forceScanInterval; /* Time interval between scans (milliseconds)*/
- u8 scanType; /* WMI_SCAN_TYPE */
- u8 numChannels; /* how many channels follow */
- u16 channelList[1]; /* channels in Mhz */
-} POSTPACK WMI_START_SCAN_CMD;
-
-/*
- * WMI_SET_SCAN_PARAMS_CMDID
- */
-#define WMI_SHORTSCANRATIO_DEFAULT 3
-/*
- * Warning: ScanCtrlFlag value of 0xFF is used to disable all flags in WMI_SCAN_PARAMS_CMD
- * Do not add any more flags to WMI_SCAN_CTRL_FLAG_BITS
- */
-typedef enum {
- CONNECT_SCAN_CTRL_FLAGS = 0x01, /* set if can scan in the Connect cmd */
- SCAN_CONNECTED_CTRL_FLAGS = 0x02, /* set if scan for the SSID it is */
- /* already connected to */
- ACTIVE_SCAN_CTRL_FLAGS = 0x04, /* set if enable active scan */
- ROAM_SCAN_CTRL_FLAGS = 0x08, /* set if enable roam scan when bmiss and lowrssi */
- REPORT_BSSINFO_CTRL_FLAGS = 0x10, /* set if follows customer BSSINFO reporting rule */
- ENABLE_AUTO_CTRL_FLAGS = 0x20, /* if disabled, target doesn't
- scan after a disconnect event */
- ENABLE_SCAN_ABORT_EVENT = 0x40 /* Scan complete event with canceled status will be generated when a scan is prempted before it gets completed */
-} WMI_SCAN_CTRL_FLAGS_BITS;
-
-#define CAN_SCAN_IN_CONNECT(flags) (flags & CONNECT_SCAN_CTRL_FLAGS)
-#define CAN_SCAN_CONNECTED(flags) (flags & SCAN_CONNECTED_CTRL_FLAGS)
-#define ENABLE_ACTIVE_SCAN(flags) (flags & ACTIVE_SCAN_CTRL_FLAGS)
-#define ENABLE_ROAM_SCAN(flags) (flags & ROAM_SCAN_CTRL_FLAGS)
-#define CONFIG_REPORT_BSSINFO(flags) (flags & REPORT_BSSINFO_CTRL_FLAGS)
-#define IS_AUTO_SCAN_ENABLED(flags) (flags & ENABLE_AUTO_CTRL_FLAGS)
-#define SCAN_ABORT_EVENT_ENABLED(flags) (flags & ENABLE_SCAN_ABORT_EVENT)
-
-#define DEFAULT_SCAN_CTRL_FLAGS (CONNECT_SCAN_CTRL_FLAGS| SCAN_CONNECTED_CTRL_FLAGS| ACTIVE_SCAN_CTRL_FLAGS| ROAM_SCAN_CTRL_FLAGS | ENABLE_AUTO_CTRL_FLAGS)
-
-
-typedef PREPACK struct {
- u16 fg_start_period; /* seconds */
- u16 fg_end_period; /* seconds */
- u16 bg_period; /* seconds */
- u16 maxact_chdwell_time; /* msec */
- u16 pas_chdwell_time; /* msec */
- u8 shortScanRatio; /* how many shorts scan for one long */
- u8 scanCtrlFlags;
- u16 minact_chdwell_time; /* msec */
- u16 maxact_scan_per_ssid; /* max active scans per ssid */
- u32 max_dfsch_act_time; /* msecs */
-} POSTPACK WMI_SCAN_PARAMS_CMD;
-
-/*
- * WMI_SET_BSS_FILTER_CMDID
- */
-typedef enum {
- NONE_BSS_FILTER = 0x0, /* no beacons forwarded */
- ALL_BSS_FILTER, /* all beacons forwarded */
- PROFILE_FILTER, /* only beacons matching profile */
- ALL_BUT_PROFILE_FILTER, /* all but beacons matching profile */
- CURRENT_BSS_FILTER, /* only beacons matching current BSS */
- ALL_BUT_BSS_FILTER, /* all but beacons matching BSS */
- PROBED_SSID_FILTER, /* beacons matching probed ssid */
- LAST_BSS_FILTER, /* marker only */
-} WMI_BSS_FILTER;
-
-typedef PREPACK struct {
- u8 bssFilter; /* see WMI_BSS_FILTER */
- u8 reserved1; /* For alignment */
- u16 reserved2; /* For alignment */
- u32 ieMask;
-} POSTPACK WMI_BSS_FILTER_CMD;
-
-/*
- * WMI_SET_PROBED_SSID_CMDID
- */
-#define MAX_PROBED_SSID_INDEX 9
-
-typedef enum {
- DISABLE_SSID_FLAG = 0, /* disables entry */
- SPECIFIC_SSID_FLAG = 0x01, /* probes specified ssid */
- ANY_SSID_FLAG = 0x02, /* probes for any ssid */
-} WMI_SSID_FLAG;
-
-typedef PREPACK struct {
- u8 entryIndex; /* 0 to MAX_PROBED_SSID_INDEX */
- u8 flag; /* WMI_SSID_FLG */
- u8 ssidLength;
- u8 ssid[32];
-} POSTPACK WMI_PROBED_SSID_CMD;
-
-/*
- * WMI_SET_LISTEN_INT_CMDID
- * The Listen interval is between 15 and 3000 TUs
- */
-#define MIN_LISTEN_INTERVAL 15
-#define MAX_LISTEN_INTERVAL 5000
-#define MIN_LISTEN_BEACONS 1
-#define MAX_LISTEN_BEACONS 50
-
-typedef PREPACK struct {
- u16 listenInterval;
- u16 numBeacons;
-} POSTPACK WMI_LISTEN_INT_CMD;
-
-/*
- * WMI_SET_BEACON_INT_CMDID
- */
-typedef PREPACK struct {
- u16 beaconInterval;
-} POSTPACK WMI_BEACON_INT_CMD;
-
-/*
- * WMI_SET_BMISS_TIME_CMDID
- * valid values are between 1000 and 5000 TUs
- */
-
-#define MIN_BMISS_TIME 1000
-#define MAX_BMISS_TIME 5000
-#define MIN_BMISS_BEACONS 1
-#define MAX_BMISS_BEACONS 50
-
-typedef PREPACK struct {
- u16 bmissTime;
- u16 numBeacons;
-} POSTPACK WMI_BMISS_TIME_CMD;
-
-/*
- * WMI_SET_POWER_MODE_CMDID
- */
-typedef enum {
- REC_POWER = 0x01,
- MAX_PERF_POWER,
-} WMI_POWER_MODE;
-
-typedef PREPACK struct {
- u8 powerMode; /* WMI_POWER_MODE */
-} POSTPACK WMI_POWER_MODE_CMD;
-
-typedef PREPACK struct {
- s8 status; /* WMI_SET_PARAMS_REPLY */
-} POSTPACK WMI_SET_PARAMS_REPLY;
-
-typedef PREPACK struct {
- u32 opcode;
- u32 length;
- char buffer[1]; /* WMI_SET_PARAMS */
-} POSTPACK WMI_SET_PARAMS_CMD;
-
-typedef PREPACK struct {
- u8 multicast_mac[ATH_MAC_LEN]; /* WMI_SET_MCAST_FILTER */
-} POSTPACK WMI_SET_MCAST_FILTER_CMD;
-
-typedef PREPACK struct {
- u8 enable; /* WMI_MCAST_FILTER */
-} POSTPACK WMI_MCAST_FILTER_CMD;
-
-/*
- * WMI_SET_POWER_PARAMS_CMDID
- */
-typedef enum {
- IGNORE_DTIM = 0x01,
- NORMAL_DTIM = 0x02,
- STICK_DTIM = 0x03,
- AUTO_DTIM = 0x04,
-} WMI_DTIM_POLICY;
-
-/* Policy to determnine whether TX should wakeup WLAN if sleeping */
-typedef enum {
- TX_WAKEUP_UPON_SLEEP = 1,
- TX_DONT_WAKEUP_UPON_SLEEP = 2
-} WMI_TX_WAKEUP_POLICY_UPON_SLEEP;
-
-/*
- * Policy to determnine whether power save failure event should be sent to
- * host during scanning
- */
-typedef enum {
- SEND_POWER_SAVE_FAIL_EVENT_ALWAYS = 1,
- IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN = 2,
-} POWER_SAVE_FAIL_EVENT_POLICY;
-
-typedef PREPACK struct {
- u16 idle_period; /* msec */
- u16 pspoll_number;
- u16 dtim_policy;
- u16 tx_wakeup_policy;
- u16 num_tx_to_wakeup;
- u16 ps_fail_event_policy;
-} POSTPACK WMI_POWER_PARAMS_CMD;
-
-/* Adhoc power save types */
-typedef enum {
- ADHOC_PS_DISABLE=1,
- ADHOC_PS_ATH=2,
- ADHOC_PS_IEEE=3,
- ADHOC_PS_OTHER=4,
-} WMI_ADHOC_PS_TYPE;
-
-typedef PREPACK struct {
- u8 power_saving;
- u8 ttl; /* number of beacon periods */
- u16 atim_windows; /* msec */
- u16 timeout_value; /* msec */
-} POSTPACK WMI_IBSS_PM_CAPS_CMD;
-
-/* AP power save types */
-typedef enum {
- AP_PS_DISABLE=1,
- AP_PS_ATH=2,
-} WMI_AP_PS_TYPE;
-
-typedef PREPACK struct {
- u32 idle_time; /* in msec */
- u32 ps_period; /* in usec */
- u8 sleep_period; /* in ps periods */
- u8 psType;
-} POSTPACK WMI_AP_PS_CMD;
-
-/*
- * WMI_SET_POWERSAVE_TIMERS_POLICY_CMDID
- */
-typedef enum {
- IGNORE_TIM_ALL_QUEUES_APSD = 0,
- PROCESS_TIM_ALL_QUEUES_APSD = 1,
- IGNORE_TIM_SIMULATED_APSD = 2,
- PROCESS_TIM_SIMULATED_APSD = 3,
-} APSD_TIM_POLICY;
-
-typedef PREPACK struct {
- u16 psPollTimeout; /* msec */
- u16 triggerTimeout; /* msec */
- u32 apsdTimPolicy; /* TIM behavior with ques APSD enabled. Default is IGNORE_TIM_ALL_QUEUES_APSD */
- u32 simulatedAPSDTimPolicy; /* TIM behavior with simulated APSD enabled. Default is PROCESS_TIM_SIMULATED_APSD */
-} POSTPACK WMI_POWERSAVE_TIMERS_POLICY_CMD;
-
-/*
- * WMI_SET_VOICE_PKT_SIZE_CMDID
- */
-typedef PREPACK struct {
- u16 voicePktSize;
-} POSTPACK WMI_SET_VOICE_PKT_SIZE_CMD;
-
-/*
- * WMI_SET_MAX_SP_LEN_CMDID
- */
-typedef enum {
- DELIVER_ALL_PKT = 0x0,
- DELIVER_2_PKT = 0x1,
- DELIVER_4_PKT = 0x2,
- DELIVER_6_PKT = 0x3,
-} APSD_SP_LEN_TYPE;
-
-typedef PREPACK struct {
- u8 maxSPLen;
-} POSTPACK WMI_SET_MAX_SP_LEN_CMD;
-
-/*
- * WMI_SET_DISC_TIMEOUT_CMDID
- */
-typedef PREPACK struct {
- u8 disconnectTimeout; /* seconds */
-} POSTPACK WMI_DISC_TIMEOUT_CMD;
-
-typedef enum {
- UPLINK_TRAFFIC = 0,
- DNLINK_TRAFFIC = 1,
- BIDIR_TRAFFIC = 2,
-} DIR_TYPE;
-
-typedef enum {
- DISABLE_FOR_THIS_AC = 0,
- ENABLE_FOR_THIS_AC = 1,
- ENABLE_FOR_ALL_AC = 2,
-} VOICEPS_CAP_TYPE;
-
-typedef enum {
- TRAFFIC_TYPE_APERIODIC = 0,
- TRAFFIC_TYPE_PERIODIC = 1,
-}TRAFFIC_TYPE;
-
-/*
- * WMI_SYNCHRONIZE_CMDID
- */
-typedef PREPACK struct {
- u8 dataSyncMap;
-} POSTPACK WMI_SYNC_CMD;
-
-/*
- * WMI_CREATE_PSTREAM_CMDID
- */
-typedef PREPACK struct {
- u32 minServiceInt; /* in milli-sec */
- u32 maxServiceInt; /* in milli-sec */
- u32 inactivityInt; /* in milli-sec */
- u32 suspensionInt; /* in milli-sec */
- u32 serviceStartTime;
- u32 minDataRate; /* in bps */
- u32 meanDataRate; /* in bps */
- u32 peakDataRate; /* in bps */
- u32 maxBurstSize;
- u32 delayBound;
- u32 minPhyRate; /* in bps */
- u32 sba;
- u32 mediumTime;
- u16 nominalMSDU; /* in octects */
- u16 maxMSDU; /* in octects */
- u8 trafficClass;
- u8 trafficDirection; /* DIR_TYPE */
- u8 rxQueueNum;
- u8 trafficType; /* TRAFFIC_TYPE */
- u8 voicePSCapability; /* VOICEPS_CAP_TYPE */
- u8 tsid;
- u8 userPriority; /* 802.1D user priority */
- u8 nominalPHY; /* nominal phy rate */
-} POSTPACK WMI_CREATE_PSTREAM_CMD;
-
-/*
- * WMI_DELETE_PSTREAM_CMDID
- */
-typedef PREPACK struct {
- u8 txQueueNumber;
- u8 rxQueueNumber;
- u8 trafficDirection;
- u8 trafficClass;
- u8 tsid;
-} POSTPACK WMI_DELETE_PSTREAM_CMD;
-
-/*
- * WMI_SET_CHANNEL_PARAMS_CMDID
- */
-typedef enum {
- WMI_11A_MODE = 0x1,
- WMI_11G_MODE = 0x2,
- WMI_11AG_MODE = 0x3,
- WMI_11B_MODE = 0x4,
- WMI_11GONLY_MODE = 0x5,
-} WMI_PHY_MODE;
-
-#define WMI_MAX_CHANNELS 32
-
-typedef PREPACK struct {
- u8 reserved1;
- u8 scanParam; /* set if enable scan */
- u8 phyMode; /* see WMI_PHY_MODE */
- u8 numChannels; /* how many channels follow */
- u16 channelList[1]; /* channels in Mhz */
-} POSTPACK WMI_CHANNEL_PARAMS_CMD;
-
-
-/*
- * WMI_RSSI_THRESHOLD_PARAMS_CMDID
- * Setting the polltime to 0 would disable polling.
- * Threshold values are in the ascending order, and should agree to:
- * (lowThreshold_lowerVal < lowThreshold_upperVal < highThreshold_lowerVal
- * < highThreshold_upperVal)
- */
-
-typedef PREPACK struct WMI_RSSI_THRESHOLD_PARAMS{
- u32 pollTime; /* Polling time as a factor of LI */
- s16 thresholdAbove1_Val; /* lowest of upper */
- s16 thresholdAbove2_Val;
- s16 thresholdAbove3_Val;
- s16 thresholdAbove4_Val;
- s16 thresholdAbove5_Val;
- s16 thresholdAbove6_Val; /* highest of upper */
- s16 thresholdBelow1_Val; /* lowest of bellow */
- s16 thresholdBelow2_Val;
- s16 thresholdBelow3_Val;
- s16 thresholdBelow4_Val;
- s16 thresholdBelow5_Val;
- s16 thresholdBelow6_Val; /* highest of bellow */
- u8 weight; /* "alpha" */
- u8 reserved[3];
-} POSTPACK WMI_RSSI_THRESHOLD_PARAMS_CMD;
-
-/*
- * WMI_SNR_THRESHOLD_PARAMS_CMDID
- * Setting the polltime to 0 would disable polling.
- */
-
-typedef PREPACK struct WMI_SNR_THRESHOLD_PARAMS{
- u32 pollTime; /* Polling time as a factor of LI */
- u8 weight; /* "alpha" */
- u8 thresholdAbove1_Val; /* lowest of uppper*/
- u8 thresholdAbove2_Val;
- u8 thresholdAbove3_Val;
- u8 thresholdAbove4_Val; /* highest of upper */
- u8 thresholdBelow1_Val; /* lowest of bellow */
- u8 thresholdBelow2_Val;
- u8 thresholdBelow3_Val;
- u8 thresholdBelow4_Val; /* highest of bellow */
- u8 reserved[3];
-} POSTPACK WMI_SNR_THRESHOLD_PARAMS_CMD;
-
-/*
- * WMI_LQ_THRESHOLD_PARAMS_CMDID
- */
-typedef PREPACK struct WMI_LQ_THRESHOLD_PARAMS {
- u8 enable;
- u8 thresholdAbove1_Val;
- u8 thresholdAbove2_Val;
- u8 thresholdAbove3_Val;
- u8 thresholdAbove4_Val;
- u8 thresholdBelow1_Val;
- u8 thresholdBelow2_Val;
- u8 thresholdBelow3_Val;
- u8 thresholdBelow4_Val;
- u8 reserved[3];
-} POSTPACK WMI_LQ_THRESHOLD_PARAMS_CMD;
-
-typedef enum {
- WMI_LPREAMBLE_DISABLED = 0,
- WMI_LPREAMBLE_ENABLED
-} WMI_LPREAMBLE_STATUS;
-
-typedef enum {
- WMI_IGNORE_BARKER_IN_ERP = 0,
- WMI_DONOT_IGNORE_BARKER_IN_ERP
-} WMI_PREAMBLE_POLICY;
-
-typedef PREPACK struct {
- u8 status;
- u8 preamblePolicy;
-}POSTPACK WMI_SET_LPREAMBLE_CMD;
-
-typedef PREPACK struct {
- u16 threshold;
-}POSTPACK WMI_SET_RTS_CMD;
-
-/*
- * WMI_TARGET_ERROR_REPORT_BITMASK_CMDID
- * Sets the error reporting event bitmask in target. Target clears it
- * upon an error. Subsequent errors are counted, but not reported
- * via event, unless the bitmask is set again.
- */
-typedef PREPACK struct {
- u32 bitmask;
-} POSTPACK WMI_TARGET_ERROR_REPORT_BITMASK;
-
-/*
- * WMI_SET_TX_PWR_CMDID
- */
-typedef PREPACK struct {
- u8 dbM; /* in dbM units */
-} POSTPACK WMI_SET_TX_PWR_CMD, WMI_TX_PWR_REPLY;
-
-/*
- * WMI_SET_ASSOC_INFO_CMDID
- *
- * A maximum of 2 private IEs can be sent in the [Re]Assoc request.
- * A 3rd one, the CCX version IE can also be set from the host.
- */
-#define WMI_MAX_ASSOC_INFO_TYPE 2
-#define WMI_CCX_VER_IE 2 /* ieType to set CCX Version IE */
-
-#define WMI_MAX_ASSOC_INFO_LEN 240
-
-typedef PREPACK struct {
- u8 ieType;
- u8 bufferSize;
- u8 assocInfo[1]; /* up to WMI_MAX_ASSOC_INFO_LEN */
-} POSTPACK WMI_SET_ASSOC_INFO_CMD;
-
-
-/*
- * WMI_GET_TX_PWR_CMDID does not take any parameters
- */
-
-/*
- * WMI_ADD_BAD_AP_CMDID
- */
-#define WMI_MAX_BAD_AP_INDEX 1
-
-typedef PREPACK struct {
- u8 badApIndex; /* 0 to WMI_MAX_BAD_AP_INDEX */
- u8 bssid[ATH_MAC_LEN];
-} POSTPACK WMI_ADD_BAD_AP_CMD;
-
-/*
- * WMI_DELETE_BAD_AP_CMDID
- */
-typedef PREPACK struct {
- u8 badApIndex; /* 0 to WMI_MAX_BAD_AP_INDEX */
-} POSTPACK WMI_DELETE_BAD_AP_CMD;
-
-/*
- * WMI_SET_ACCESS_PARAMS_CMDID
- */
-#define WMI_DEFAULT_TXOP_ACPARAM 0 /* implies one MSDU */
-#define WMI_DEFAULT_ECWMIN_ACPARAM 4 /* corresponds to CWmin of 15 */
-#define WMI_DEFAULT_ECWMAX_ACPARAM 10 /* corresponds to CWmax of 1023 */
-#define WMI_MAX_CW_ACPARAM 15 /* maximum eCWmin or eCWmax */
-#define WMI_DEFAULT_AIFSN_ACPARAM 2
-#define WMI_MAX_AIFSN_ACPARAM 15
-typedef PREPACK struct {
- u16 txop; /* in units of 32 usec */
- u8 eCWmin;
- u8 eCWmax;
- u8 aifsn;
- u8 ac;
-} POSTPACK WMI_SET_ACCESS_PARAMS_CMD;
-
-
-/*
- * WMI_SET_RETRY_LIMITS_CMDID
- *
- * This command is used to customize the number of retries the
- * wlan device will perform on a given frame.
- */
-#define WMI_MIN_RETRIES 2
-#define WMI_MAX_RETRIES 13
-typedef enum {
- MGMT_FRAMETYPE = 0,
- CONTROL_FRAMETYPE = 1,
- DATA_FRAMETYPE = 2
-} WMI_FRAMETYPE;
-
-typedef PREPACK struct {
- u8 frameType; /* WMI_FRAMETYPE */
- u8 trafficClass; /* applies only to DATA_FRAMETYPE */
- u8 maxRetries;
- u8 enableNotify;
-} POSTPACK WMI_SET_RETRY_LIMITS_CMD;
-
-/*
- * WMI_SET_ROAM_CTRL_CMDID
- *
- * This command is used to influence the Roaming behaviour
- * Set the host biases of the BSSs before setting the roam mode as bias
- * based.
- */
-
-/*
- * Different types of Roam Control
- */
-
-typedef enum {
- WMI_FORCE_ROAM = 1, /* Roam to the specified BSSID */
- WMI_SET_ROAM_MODE = 2, /* default ,progd bias, no roam */
- WMI_SET_HOST_BIAS = 3, /* Set the Host Bias */
- WMI_SET_LOWRSSI_SCAN_PARAMS = 4, /* Set lowrssi Scan parameters */
-} WMI_ROAM_CTRL_TYPE;
-
-#define WMI_MIN_ROAM_CTRL_TYPE WMI_FORCE_ROAM
-#define WMI_MAX_ROAM_CTRL_TYPE WMI_SET_LOWRSSI_SCAN_PARAMS
-
-/*
- * ROAM MODES
- */
-
-typedef enum {
- WMI_DEFAULT_ROAM_MODE = 1, /* RSSI based ROAM */
- WMI_HOST_BIAS_ROAM_MODE = 2, /* HOST BIAS based ROAM */
- WMI_LOCK_BSS_MODE = 3 /* Lock to the Current BSS - no Roam */
-} WMI_ROAM_MODE;
-
-/*
- * BSS HOST BIAS INFO
- */
-
-typedef PREPACK struct {
- u8 bssid[ATH_MAC_LEN];
- s8 bias;
-} POSTPACK WMI_BSS_BIAS;
-
-typedef PREPACK struct {
- u8 numBss;
- WMI_BSS_BIAS bssBias[1];
-} POSTPACK WMI_BSS_BIAS_INFO;
-
-typedef PREPACK struct WMI_LOWRSSI_SCAN_PARAMS {
- u16 lowrssi_scan_period;
- s16 lowrssi_scan_threshold;
- s16 lowrssi_roam_threshold;
- u8 roam_rssi_floor;
- u8 reserved[1]; /* For alignment */
-} POSTPACK WMI_LOWRSSI_SCAN_PARAMS;
-
-typedef PREPACK struct {
- PREPACK union {
- u8 bssid[ATH_MAC_LEN]; /* WMI_FORCE_ROAM */
- u8 roamMode; /* WMI_SET_ROAM_MODE */
- WMI_BSS_BIAS_INFO bssBiasInfo; /* WMI_SET_HOST_BIAS */
- WMI_LOWRSSI_SCAN_PARAMS lrScanParams;
- } POSTPACK info;
- u8 roamCtrlType ;
-} POSTPACK WMI_SET_ROAM_CTRL_CMD;
-
-/*
- * WMI_SET_BT_WLAN_CONN_PRECEDENCE_CMDID
- */
-typedef enum {
- BT_WLAN_CONN_PRECDENCE_WLAN=0, /* Default */
- BT_WLAN_CONN_PRECDENCE_PAL,
-} BT_WLAN_CONN_PRECEDENCE;
-
-typedef PREPACK struct {
- u8 precedence;
-} POSTPACK WMI_SET_BT_WLAN_CONN_PRECEDENCE;
-
-/*
- * WMI_ENABLE_RM_CMDID
- */
-typedef PREPACK struct {
- u32 enable_radio_measurements;
-} POSTPACK WMI_ENABLE_RM_CMD;
-
-/*
- * WMI_SET_MAX_OFFHOME_DURATION_CMDID
- */
-typedef PREPACK struct {
- u8 max_offhome_duration;
-} POSTPACK WMI_SET_MAX_OFFHOME_DURATION_CMD;
-
-typedef PREPACK struct {
- u32 frequency;
- u8 threshold;
-} POSTPACK WMI_SET_HB_CHALLENGE_RESP_PARAMS_CMD;
-/*---------------------- BTCOEX RELATED -------------------------------------*/
-/*----------------------COMMON to AR6002 and AR6003 -------------------------*/
-typedef enum {
- BT_STREAM_UNDEF = 0,
- BT_STREAM_SCO, /* SCO stream */
- BT_STREAM_A2DP, /* A2DP stream */
- BT_STREAM_SCAN, /* BT Discovery or Page */
- BT_STREAM_ESCO,
- BT_STREAM_MAX
-} BT_STREAM_TYPE;
-
-typedef enum {
- BT_PARAM_SCO_PSPOLL_LATENCY_ONE_FOURTH =1,
- BT_PARAM_SCO_PSPOLL_LATENCY_HALF,
- BT_PARAM_SCO_PSPOLL_LATENCY_THREE_FOURTH,
-} BT_PARAMS_SCO_PSPOLL_LATENCY;
-
-typedef enum {
- BT_PARAMS_SCO_STOMP_SCO_NEVER =1,
- BT_PARAMS_SCO_STOMP_SCO_ALWAYS,
- BT_PARAMS_SCO_STOMP_SCO_IN_LOWRSSI,
-} BT_PARAMS_SCO_STOMP_RULES;
-
-typedef enum {
- BT_STATUS_UNDEF = 0,
- BT_STATUS_ON,
- BT_STATUS_OFF,
- BT_STATUS_MAX
-} BT_STREAM_STATUS;
-
-typedef PREPACK struct {
- u8 streamType;
- u8 status;
-} POSTPACK WMI_SET_BT_STATUS_CMD;
-
-typedef enum {
- BT_ANT_TYPE_UNDEF=0,
- BT_ANT_TYPE_DUAL,
- BT_ANT_TYPE_SPLITTER,
- BT_ANT_TYPE_SWITCH,
- BT_ANT_TYPE_HIGH_ISO_DUAL
-} BT_ANT_FRONTEND_CONFIG;
-
-typedef enum {
- BT_COLOCATED_DEV_BTS4020=0,
- BT_COLCATED_DEV_CSR ,
- BT_COLOCATED_DEV_VALKYRIE
-} BT_COLOCATED_DEV_TYPE;
-
-/*********************** Applicable to AR6002 ONLY ******************************/
-
-typedef enum {
- BT_PARAM_SCO = 1, /* SCO stream parameters */
- BT_PARAM_A2DP ,
- BT_PARAM_ANTENNA_CONFIG,
- BT_PARAM_COLOCATED_BT_DEVICE,
- BT_PARAM_ACLCOEX,
- BT_PARAM_11A_SEPARATE_ANT,
- BT_PARAM_MAX
-} BT_PARAM_TYPE;
-
-
-#define BT_SCO_ALLOW_CLOSE_RANGE_OPT (1 << 0)
-#define BT_SCO_FORCE_AWAKE_OPT (1 << 1)
-#define BT_SCO_SET_RSSI_OVERRIDE(flags) ((flags) |= (1 << 2))
-#define BT_SCO_GET_RSSI_OVERRIDE(flags) (((flags) >> 2) & 0x1)
-#define BT_SCO_SET_RTS_OVERRIDE(flags) ((flags) |= (1 << 3))
-#define BT_SCO_GET_RTS_OVERRIDE(flags) (((flags) >> 3) & 0x1)
-#define BT_SCO_GET_MIN_LOW_RATE_CNT(flags) (((flags) >> 8) & 0xFF)
-#define BT_SCO_GET_MAX_LOW_RATE_CNT(flags) (((flags) >> 16) & 0xFF)
-#define BT_SCO_SET_MIN_LOW_RATE_CNT(flags,val) (flags) |= (((val) & 0xFF) << 8)
-#define BT_SCO_SET_MAX_LOW_RATE_CNT(flags,val) (flags) |= (((val) & 0xFF) << 16)
-
-typedef PREPACK struct {
- u32 numScoCyclesForceTrigger; /* Number SCO cycles after which
- force a pspoll. default = 10 */
- u32 dataResponseTimeout; /* Timeout Waiting for Downlink pkt
- in response for ps-poll,
- default = 10 msecs */
- u32 stompScoRules;
- u32 scoOptFlags; /* SCO Options Flags :
- bits: meaning:
- 0 Allow Close Range Optimization
- 1 Force awake during close range
- 2 If set use host supplied RSSI for OPT
- 3 If set use host supplied RTS COUNT for OPT
- 4..7 Unused
- 8..15 Low Data Rate Min Cnt
- 16..23 Low Data Rate Max Cnt
- */
-
- u8 stompDutyCyleVal; /* Sco cycles to limit ps-poll queuing
- if stomped */
- u8 stompDutyCyleMaxVal; /*firm ware increases stomp duty cycle
- gradually uptill this value on need basis*/
- u8 psPollLatencyFraction; /* Fraction of idle
- period, within which
- additional ps-polls
- can be queued */
- u8 noSCOSlots; /* Number of SCO Tx/Rx slots.
- HVx, EV3, 2EV3 = 2 */
- u8 noIdleSlots; /* Number of Bluetooth idle slots between
- consecutive SCO Tx/Rx slots
- HVx, EV3 = 4
- 2EV3 = 10 */
- u8 scoOptOffRssi;/*RSSI value below which we go to ps poll*/
- u8 scoOptOnRssi; /*RSSI value above which we reenter opt mode*/
- u8 scoOptRtsCount;
-} POSTPACK BT_PARAMS_SCO;
-
-#define BT_A2DP_ALLOW_CLOSE_RANGE_OPT (1 << 0)
-#define BT_A2DP_FORCE_AWAKE_OPT (1 << 1)
-#define BT_A2DP_SET_RSSI_OVERRIDE(flags) ((flags) |= (1 << 2))
-#define BT_A2DP_GET_RSSI_OVERRIDE(flags) (((flags) >> 2) & 0x1)
-#define BT_A2DP_SET_RTS_OVERRIDE(flags) ((flags) |= (1 << 3))
-#define BT_A2DP_GET_RTS_OVERRIDE(flags) (((flags) >> 3) & 0x1)
-#define BT_A2DP_GET_MIN_LOW_RATE_CNT(flags) (((flags) >> 8) & 0xFF)
-#define BT_A2DP_GET_MAX_LOW_RATE_CNT(flags) (((flags) >> 16) & 0xFF)
-#define BT_A2DP_SET_MIN_LOW_RATE_CNT(flags,val) (flags) |= (((val) & 0xFF) << 8)
-#define BT_A2DP_SET_MAX_LOW_RATE_CNT(flags,val) (flags) |= (((val) & 0xFF) << 16)
-
-typedef PREPACK struct {
- u32 a2dpWlanUsageLimit; /* MAX time firmware uses the medium for
- wlan, after it identifies the idle time
- default (30 msecs) */
- u32 a2dpBurstCntMin; /* Minimum number of bluetooth data frames
- to replenish Wlan Usage limit (default 3) */
- u32 a2dpDataRespTimeout;
- u32 a2dpOptFlags; /* A2DP Option flags:
- bits: meaning:
- 0 Allow Close Range Optimization
- 1 Force awake during close range
- 2 If set use host supplied RSSI for OPT
- 3 If set use host supplied RTS COUNT for OPT
- 4..7 Unused
- 8..15 Low Data Rate Min Cnt
- 16..23 Low Data Rate Max Cnt
- */
- u8 isCoLocatedBtRoleMaster;
- u8 a2dpOptOffRssi;/*RSSI value below which we go to ps poll*/
- u8 a2dpOptOnRssi; /*RSSI value above which we reenter opt mode*/
- u8 a2dpOptRtsCount;
-}POSTPACK BT_PARAMS_A2DP;
-
-/* During BT ftp/ BT OPP or any another data based acl profile on bluetooth
- (non a2dp).*/
-typedef PREPACK struct {
- u32 aclWlanMediumUsageTime; /* Wlan usage time during Acl (non-a2dp)
- coexistence (default 30 msecs) */
- u32 aclBtMediumUsageTime; /* Bt usage time during acl coexistence
- (default 30 msecs)*/
- u32 aclDataRespTimeout;
- u32 aclDetectTimeout; /* ACL coexistence enabled if we get
- 10 Pkts in X msec(default 100 msecs) */
- u32 aclmaxPktCnt; /* No of ACL pkts to receive before
- enabling ACL coex */
-
-}POSTPACK BT_PARAMS_ACLCOEX;
-
-typedef PREPACK struct {
- PREPACK union {
- BT_PARAMS_SCO scoParams;
- BT_PARAMS_A2DP a2dpParams;
- BT_PARAMS_ACLCOEX aclCoexParams;
- u8 antType; /* 0 -Disabled (default)
- 1 - BT_ANT_TYPE_DUAL
- 2 - BT_ANT_TYPE_SPLITTER
- 3 - BT_ANT_TYPE_SWITCH */
- u8 coLocatedBtDev; /* 0 - BT_COLOCATED_DEV_BTS4020 (default)
- 1 - BT_COLCATED_DEV_CSR
- 2 - BT_COLOCATED_DEV_VALKYRIe
- */
- } POSTPACK info;
- u8 paramType ;
-} POSTPACK WMI_SET_BT_PARAMS_CMD;
-
-/************************ END AR6002 BTCOEX *******************************/
-/*-----------------------AR6003 BTCOEX -----------------------------------*/
-
-/* ---------------WMI_SET_BTCOEX_FE_ANT_CMDID --------------------------*/
-/* Indicates front end antenna configuration. This command needs to be issued
- * right after initialization and after WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMDID.
- * AR6003 enables coexistence and antenna switching based on the configuration.
- */
-typedef enum {
- WMI_BTCOEX_NOT_ENABLED = 0,
- WMI_BTCOEX_FE_ANT_SINGLE =1,
- WMI_BTCOEX_FE_ANT_DUAL=2,
- WMI_BTCOEX_FE_ANT_DUAL_HIGH_ISO=3,
- WMI_BTCOEX_FE_ANT_TYPE_MAX
-}WMI_BTCOEX_FE_ANT_TYPE;
-
-typedef PREPACK struct {
- u8 btcoexFeAntType; /* 1 - WMI_BTCOEX_FE_ANT_SINGLE for single antenna front end
- 2 - WMI_BTCOEX_FE_ANT_DUAL for dual antenna front end
- (for isolations less 35dB, for higher isolation there
- is not need to pass this command).
- (not implemented)
- */
-}POSTPACK WMI_SET_BTCOEX_FE_ANT_CMD;
-
-/* -------------WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMDID ----------------*/
-/* Indicate the bluetooth chip to the firmware. Firmware can have different algorithm based
- * bluetooth chip type.Based on bluetooth device, different coexistence protocol would be used.
- */
-typedef PREPACK struct {
- u8 btcoexCoLocatedBTdev; /*1 - Qcom BT (3 -wire PTA)
- 2 - CSR BT (3 wire PTA)
- 3 - Atheros 3001 BT (3 wire PTA)
- 4 - STE bluetooth (4-wire ePTA)
- 5 - Atheros 3002 BT (4-wire MCI)
- defaults= 3 (Atheros 3001 BT )
- */
-}POSTPACK WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMD;
-
-/* -------------WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG_CMDID ------------*/
-/* Configuration parameters during bluetooth inquiry and page. Page configuration
- * is applicable only on interfaces which can distinguish page (applicable only for ePTA -
- * STE bluetooth).
- * Bluetooth inquiry start and end is indicated via WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMDID.
- * During this the station will be power-save mode.
- */
-typedef PREPACK struct {
- u32 btInquiryDataFetchFrequency;/* The frequency of querying the AP for data
- (via pspoll) is configured by this parameter.
- "default = 10 ms" */
-
- u32 protectBmissDurPostBtInquiry;/* The firmware will continue to be in inquiry state
- for configured duration, after inquiry completion
- . This is to ensure other bluetooth transactions
- (RDP, SDP profiles, link key exchange ...etc)
- goes through smoothly without wifi stomping.
- default = 10 secs*/
-
- u32 maxpageStomp; /*Applicable only for STE-BT interface. Currently not
- used */
- u32 btInquiryPageFlag; /* Not used */
-}POSTPACK WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG_CMD;
-
-/*---------------------WMI_SET_BTCOEX_SCO_CONFIG_CMDID ---------------*/
-/* Configure SCO parameters. These parameters would be used whenever firmware is indicated
- * of (e)SCO profile on bluetooth ( via WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMDID).
- * Configration of BTCOEX_SCO_CONFIG data structure are common configuration and applies
- * ps-poll mode and opt mode.
- * Ps-poll Mode - Station is in power-save and retrieves downlink data between sco gaps.
- * Opt Mode - station is in awake state and access point can send data to station any time.
- * BTCOEX_PSPOLLMODE_SCO_CONFIG - Configuration applied only during ps-poll mode.
- * BTCOEX_OPTMODE_SCO_CONFIG - Configuration applied only during opt mode.
- */
-#define WMI_SCO_CONFIG_FLAG_ALLOW_OPTIMIZATION (1 << 0)
-#define WMI_SCO_CONFIG_FLAG_IS_EDR_CAPABLE (1 << 1)
-#define WMI_SCO_CONFIG_FLAG_IS_BT_MASTER (1 << 2)
-#define WMI_SCO_CONFIG_FLAG_FW_DETECT_OF_PER (1 << 3)
-typedef PREPACK struct {
- u32 scoSlots; /* Number of SCO Tx/Rx slots.
- HVx, EV3, 2EV3 = 2 */
- u32 scoIdleSlots; /* Number of Bluetooth idle slots between
- consecutive SCO Tx/Rx slots
- HVx, EV3 = 4
- 2EV3 = 10
- */
- u32 scoFlags; /* SCO Options Flags :
- bits: meaning:
- 0 Allow Close Range Optimization
- 1 Is EDR capable or Not
- 2 IS Co-located Bt role Master
- 3 Firmware determines the periodicity of SCO.
- */
-
- u32 linkId; /* applicable to STE-BT - not used */
-}POSTPACK BTCOEX_SCO_CONFIG;
-
-typedef PREPACK struct {
- u32 scoCyclesForceTrigger; /* Number SCO cycles after which
- force a pspoll. default = 10 */
- u32 scoDataResponseTimeout; /* Timeout Waiting for Downlink pkt
- in response for ps-poll,
- default = 20 msecs */
-
- u32 scoStompDutyCyleVal; /* not implemented */
-
- u32 scoStompDutyCyleMaxVal; /*Not implemented */
-
- u32 scoPsPollLatencyFraction; /* Fraction of idle
- period, within which
- additional ps-polls can be queued
- 1 - 1/4 of idle duration
- 2 - 1/2 of idle duration
- 3 - 3/4 of idle duration
- default =2 (1/2)
- */
-}POSTPACK BTCOEX_PSPOLLMODE_SCO_CONFIG;
-
-typedef PREPACK struct {
- u32 scoStompCntIn100ms;/*max number of SCO stomp in 100ms allowed in
- opt mode. If exceeds the configured value,
- switch to ps-poll mode
- default = 3 */
-
- u32 scoContStompMax; /* max number of continuous stomp allowed in opt mode.
- if exceeded switch to pspoll mode
- default = 3 */
-
- u32 scoMinlowRateMbps; /* Low rate threshold */
-
- u32 scoLowRateCnt; /* number of low rate pkts (< scoMinlowRateMbps) allowed in 100 ms.
- If exceeded switch/stay to ps-poll mode, lower stay in opt mode.
- default = 36
- */
-
- u32 scoHighPktRatio; /*(Total Rx pkts in 100 ms + 1)/
- ((Total tx pkts in 100 ms - No of high rate pkts in 100 ms) + 1) in 100 ms,
- if exceeded switch/stay in opt mode and if lower switch/stay in pspoll mode.
- default = 5 (80% of high rates)
- */
-
- u32 scoMaxAggrSize; /* Max number of Rx subframes allowed in this mode. (Firmware re-negogiates
- max number of aggregates if it was negogiated to higher value
- default = 1
- Recommended value Basic rate headsets = 1, EDR (2-EV3) =4.
- */
-}POSTPACK BTCOEX_OPTMODE_SCO_CONFIG;
-
-typedef PREPACK struct {
- u32 scanInterval;
- u32 maxScanStompCnt;
-}POSTPACK BTCOEX_WLANSCAN_SCO_CONFIG;
-
-typedef PREPACK struct {
- BTCOEX_SCO_CONFIG scoConfig;
- BTCOEX_PSPOLLMODE_SCO_CONFIG scoPspollConfig;
- BTCOEX_OPTMODE_SCO_CONFIG scoOptModeConfig;
- BTCOEX_WLANSCAN_SCO_CONFIG scoWlanScanConfig;
-}POSTPACK WMI_SET_BTCOEX_SCO_CONFIG_CMD;
-
-/* ------------------WMI_SET_BTCOEX_A2DP_CONFIG_CMDID -------------------*/
-/* Configure A2DP profile parameters. These parameters would be used whenver firmware is indicated
- * of A2DP profile on bluetooth ( via WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMDID).
- * Configuration of BTCOEX_A2DP_CONFIG data structure are common configuration and applies to
- * ps-poll mode and opt mode.
- * Ps-poll Mode - Station is in power-save and retrieves downlink data between a2dp data bursts.
- * Opt Mode - station is in power save during a2dp bursts and awake in the gaps.
- * BTCOEX_PSPOLLMODE_A2DP_CONFIG - Configuration applied only during ps-poll mode.
- * BTCOEX_OPTMODE_A2DP_CONFIG - Configuration applied only during opt mode.
- */
-
-#define WMI_A2DP_CONFIG_FLAG_ALLOW_OPTIMIZATION (1 << 0)
-#define WMI_A2DP_CONFIG_FLAG_IS_EDR_CAPABLE (1 << 1)
-#define WMI_A2DP_CONFIG_FLAG_IS_BT_ROLE_MASTER (1 << 2)
-#define WMI_A2DP_CONFIG_FLAG_IS_A2DP_HIGH_PRI (1 << 3)
-#define WMI_A2DP_CONFIG_FLAG_FIND_BT_ROLE (1 << 4)
-
-typedef PREPACK struct {
- u32 a2dpFlags; /* A2DP Option flags:
- bits: meaning:
- 0 Allow Close Range Optimization
- 1 IS EDR capable
- 2 IS Co-located Bt role Master
- 3 a2dp traffic is high priority
- 4 Fw detect the role of bluetooth.
- */
- u32 linkId; /* Applicable only to STE-BT - not used */
-
-}POSTPACK BTCOEX_A2DP_CONFIG;
-
-typedef PREPACK struct {
- u32 a2dpWlanMaxDur; /* MAX time firmware uses the medium for
- wlan, after it identifies the idle time
- default (30 msecs) */
-
- u32 a2dpMinBurstCnt; /* Minimum number of bluetooth data frames
- to replenish Wlan Usage limit (default 3) */
-
- u32 a2dpDataRespTimeout; /* Max duration firmware waits for downlink
- by stomping on bluetooth
- after ps-poll is acknowledged.
- default = 20 ms
- */
-}POSTPACK BTCOEX_PSPOLLMODE_A2DP_CONFIG;
-
-typedef PREPACK struct {
- u32 a2dpMinlowRateMbps; /* Low rate threshold */
-
- u32 a2dpLowRateCnt; /* number of low rate pkts (< a2dpMinlowRateMbps) allowed in 100 ms.
- If exceeded switch/stay to ps-poll mode, lower stay in opt mode.
- default = 36
- */
-
- u32 a2dpHighPktRatio; /*(Total Rx pkts in 100 ms + 1)/
- ((Total tx pkts in 100 ms - No of high rate pkts in 100 ms) + 1) in 100 ms,
- if exceeded switch/stay in opt mode and if lower switch/stay in pspoll mode.
- default = 5 (80% of high rates)
- */
-
- u32 a2dpMaxAggrSize; /* Max number of Rx subframes allowed in this mode. (Firmware re-negogiates
- max number of aggregates if it was negogiated to higher value
- default = 1
- Recommended value Basic rate headsets = 1, EDR (2-EV3) =8.
- */
- u32 a2dpPktStompCnt; /*number of a2dp pkts that can be stomped per burst.
- default = 6*/
-
-}POSTPACK BTCOEX_OPTMODE_A2DP_CONFIG;
-
-typedef PREPACK struct {
- BTCOEX_A2DP_CONFIG a2dpConfig;
- BTCOEX_PSPOLLMODE_A2DP_CONFIG a2dppspollConfig;
- BTCOEX_OPTMODE_A2DP_CONFIG a2dpOptConfig;
-}POSTPACK WMI_SET_BTCOEX_A2DP_CONFIG_CMD;
-
-/*------------ WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMDID---------------------*/
-/* Configure non-A2dp ACL profile parameters.The starts of ACL profile can either be
- * indicated via WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMDID orenabled via firmware detection
- * which is configured via "aclCoexFlags".
- * Configration of BTCOEX_ACLCOEX_CONFIG data structure are common configuration and applies
- * ps-poll mode and opt mode.
- * Ps-poll Mode - Station is in power-save and retrieves downlink data during wlan medium.
- * Opt Mode - station is in power save during bluetooth medium time and awake during wlan duration.
- * (Not implemented yet)
- *
- * BTCOEX_PSPOLLMODE_ACLCOEX_CONFIG - Configuration applied only during ps-poll mode.
- * BTCOEX_OPTMODE_ACLCOEX_CONFIG - Configuration applied only during opt mode.
- */
-
-#define WMI_ACLCOEX_FLAGS_ALLOW_OPTIMIZATION (1 << 0)
-#define WMI_ACLCOEX_FLAGS_DISABLE_FW_DETECTION (1 << 1)
-
-typedef PREPACK struct {
- u32 aclWlanMediumDur; /* Wlan usage time during Acl (non-a2dp)
- coexistence (default 30 msecs)
- */
-
- u32 aclBtMediumDur; /* Bt usage time during acl coexistence
- (default 30 msecs)
- */
-
- u32 aclDetectTimeout; /* BT activity observation time limit.
- In this time duration, number of bt pkts are counted.
- If the Cnt reaches "aclPktCntLowerLimit" value
- for "aclIterToEnableCoex" iteration continuously,
- firmware gets into ACL coexistence mode.
- Similarly, if bt traffic count during ACL coexistence
- has not reached "aclPktCntLowerLimit" continuously
- for "aclIterToEnableCoex", then ACL coexistence is
- disabled.
- -default 100 msecs
- */
-
- u32 aclPktCntLowerLimit; /* Acl Pkt Cnt to be received in duration of
- "aclDetectTimeout" for
- "aclIterForEnDis" times to enabling ACL coex.
- Similar logic is used to disable acl coexistence.
- (If "aclPktCntLowerLimit" cnt of acl pkts
- are not seen by the for "aclIterForEnDis"
- then acl coexistence is disabled).
- default = 10
- */
-
- u32 aclIterForEnDis; /* number of Iteration of "aclPktCntLowerLimit" for Enabling and
- Disabling Acl Coexistence.
- default = 3
- */
-
- u32 aclPktCntUpperLimit; /* This is upperBound limit, if there is more than
- "aclPktCntUpperLimit" seen in "aclDetectTimeout",
- ACL coexistence is enabled right away.
- - default 15*/
-
- u32 aclCoexFlags; /* A2DP Option flags:
- bits: meaning:
- 0 Allow Close Range Optimization
- 1 disable Firmware detection
- (Currently supported configuration is aclCoexFlags =0)
- */
- u32 linkId; /* Applicable only for STE-BT - not used */
-
-}POSTPACK BTCOEX_ACLCOEX_CONFIG;
-
-typedef PREPACK struct {
- u32 aclDataRespTimeout; /* Max duration firmware waits for downlink
- by stomping on bluetooth
- after ps-poll is acknowledged.
- default = 20 ms */
-
-}POSTPACK BTCOEX_PSPOLLMODE_ACLCOEX_CONFIG;
-
-
-/* Not implemented yet*/
-typedef PREPACK struct {
- u32 aclCoexMinlowRateMbps;
- u32 aclCoexLowRateCnt;
- u32 aclCoexHighPktRatio;
- u32 aclCoexMaxAggrSize;
- u32 aclPktStompCnt;
-}POSTPACK BTCOEX_OPTMODE_ACLCOEX_CONFIG;
-
-typedef PREPACK struct {
- BTCOEX_ACLCOEX_CONFIG aclCoexConfig;
- BTCOEX_PSPOLLMODE_ACLCOEX_CONFIG aclCoexPspollConfig;
- BTCOEX_OPTMODE_ACLCOEX_CONFIG aclCoexOptConfig;
-}POSTPACK WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMD;
-
-/* -----------WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMDID ------------------*/
-typedef enum {
- WMI_BTCOEX_BT_PROFILE_SCO =1,
- WMI_BTCOEX_BT_PROFILE_A2DP,
- WMI_BTCOEX_BT_PROFILE_INQUIRY_PAGE,
- WMI_BTCOEX_BT_PROFILE_ACLCOEX,
-}WMI_BTCOEX_BT_PROFILE;
-
-typedef PREPACK struct {
- u32 btProfileType;
- u32 btOperatingStatus;
- u32 btLinkId;
-}WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMD;
-
-/*--------------------- WMI_SET_BTCOEX_DEBUG_CMDID ---------------------*/
-/* Used for firmware development and debugging */
-typedef PREPACK struct {
- u32 btcoexDbgParam1;
- u32 btcoexDbgParam2;
- u32 btcoexDbgParam3;
- u32 btcoexDbgParam4;
- u32 btcoexDbgParam5;
-}WMI_SET_BTCOEX_DEBUG_CMD;
-
-/*---------------------WMI_GET_BTCOEX_CONFIG_CMDID --------------------- */
-/* Command to firmware to get configuration parameters of the bt profile
- * reported via WMI_BTCOEX_CONFIG_EVENTID */
-typedef PREPACK struct {
- u32 btProfileType; /* 1 - SCO
- 2 - A2DP
- 3 - INQUIRY_PAGE
- 4 - ACLCOEX
- */
- u32 linkId; /* not used */
-}WMI_GET_BTCOEX_CONFIG_CMD;
-
-/*------------------WMI_REPORT_BTCOEX_CONFIG_EVENTID------------------- */
-/* Event from firmware to host, sent in response to WMI_GET_BTCOEX_CONFIG_CMDID
- * */
-typedef PREPACK struct {
- u32 btProfileType;
- u32 linkId; /* not used */
- PREPACK union {
- WMI_SET_BTCOEX_SCO_CONFIG_CMD scoConfigCmd;
- WMI_SET_BTCOEX_A2DP_CONFIG_CMD a2dpConfigCmd;
- WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMD aclcoexConfig;
- WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG_CMD btinquiryPageConfigCmd;
- } POSTPACK info;
-} POSTPACK WMI_BTCOEX_CONFIG_EVENT;
-
-/*------------- WMI_REPORT_BTCOEX_BTCOEX_STATS_EVENTID--------------------*/
-/* Used for firmware development and debugging*/
-typedef PREPACK struct {
- u32 highRatePktCnt;
- u32 firstBmissCnt;
- u32 psPollFailureCnt;
- u32 nullFrameFailureCnt;
- u32 optModeTransitionCnt;
-}BTCOEX_GENERAL_STATS;
-
-typedef PREPACK struct {
- u32 scoStompCntAvg;
- u32 scoStompIn100ms;
- u32 scoMaxContStomp;
- u32 scoAvgNoRetries;
- u32 scoMaxNoRetriesIn100ms;
-}BTCOEX_SCO_STATS;
-
-typedef PREPACK struct {
- u32 a2dpBurstCnt;
- u32 a2dpMaxBurstCnt;
- u32 a2dpAvgIdletimeIn100ms;
- u32 a2dpAvgStompCnt;
-}BTCOEX_A2DP_STATS;
-
-typedef PREPACK struct {
- u32 aclPktCntInBtTime;
- u32 aclStompCntInWlanTime;
- u32 aclPktCntIn100ms;
-}BTCOEX_ACLCOEX_STATS;
-
-typedef PREPACK struct {
- BTCOEX_GENERAL_STATS coexStats;
- BTCOEX_SCO_STATS scoStats;
- BTCOEX_A2DP_STATS a2dpStats;
- BTCOEX_ACLCOEX_STATS aclCoexStats;
-}WMI_BTCOEX_STATS_EVENT;
-
-
-/*--------------------------END OF BTCOEX -------------------------------------*/
-typedef PREPACK struct {
- u32 sleepState;
-}WMI_REPORT_SLEEP_STATE_EVENT;
-
-typedef enum {
- WMI_REPORT_SLEEP_STATUS_IS_DEEP_SLEEP =0,
- WMI_REPORT_SLEEP_STATUS_IS_AWAKE
-} WMI_REPORT_SLEEP_STATUS;
-typedef enum {
- DISCONN_EVT_IN_RECONN = 0, /* default */
- NO_DISCONN_EVT_IN_RECONN
-} TARGET_EVENT_REPORT_CONFIG;
-
-typedef PREPACK struct {
- u32 evtConfig;
-} POSTPACK WMI_SET_TARGET_EVENT_REPORT_CMD;
-
-
-typedef PREPACK struct {
- u16 cmd_buf_sz; /* HCI cmd buffer size */
- u8 buf[1]; /* Absolute HCI cmd */
-} POSTPACK WMI_HCI_CMD;
-
-/*
- * Command Replies
- */
-
-/*
- * WMI_GET_CHANNEL_LIST_CMDID reply
- */
-typedef PREPACK struct {
- u8 reserved1;
- u8 numChannels; /* number of channels in reply */
- u16 channelList[1]; /* channel in Mhz */
-} POSTPACK WMI_CHANNEL_LIST_REPLY;
-
-typedef enum {
- A_SUCCEEDED = 0,
- A_FAILED_DELETE_STREAM_DOESNOT_EXIST=250,
- A_SUCCEEDED_MODIFY_STREAM=251,
- A_FAILED_INVALID_STREAM = 252,
- A_FAILED_MAX_THINSTREAMS = 253,
- A_FAILED_CREATE_REMOVE_PSTREAM_FIRST = 254,
-} PSTREAM_REPLY_STATUS;
-
-typedef PREPACK struct {
- u8 status; /* PSTREAM_REPLY_STATUS */
- u8 txQueueNumber;
- u8 rxQueueNumber;
- u8 trafficClass;
- u8 trafficDirection; /* DIR_TYPE */
-} POSTPACK WMI_CRE_PRIORITY_STREAM_REPLY;
-
-typedef PREPACK struct {
- u8 status; /* PSTREAM_REPLY_STATUS */
- u8 txQueueNumber;
- u8 rxQueueNumber;
- u8 trafficDirection; /* DIR_TYPE */
- u8 trafficClass;
-} POSTPACK WMI_DEL_PRIORITY_STREAM_REPLY;
-
-/*
- * List of Events (target to host)
- */
-typedef enum {
- WMI_READY_EVENTID = 0x1001,
- WMI_CONNECT_EVENTID,
- WMI_DISCONNECT_EVENTID,
- WMI_BSSINFO_EVENTID,
- WMI_CMDERROR_EVENTID,
- WMI_REGDOMAIN_EVENTID,
- WMI_PSTREAM_TIMEOUT_EVENTID,
- WMI_NEIGHBOR_REPORT_EVENTID,
- WMI_TKIP_MICERR_EVENTID,
- WMI_SCAN_COMPLETE_EVENTID, /* 0x100a */
- WMI_REPORT_STATISTICS_EVENTID,
- WMI_RSSI_THRESHOLD_EVENTID,
- WMI_ERROR_REPORT_EVENTID,
- WMI_OPT_RX_FRAME_EVENTID,
- WMI_REPORT_ROAM_TBL_EVENTID,
- WMI_EXTENSION_EVENTID,
- WMI_CAC_EVENTID,
- WMI_SNR_THRESHOLD_EVENTID,
- WMI_LQ_THRESHOLD_EVENTID,
- WMI_TX_RETRY_ERR_EVENTID, /* 0x1014 */
- WMI_REPORT_ROAM_DATA_EVENTID,
- WMI_TEST_EVENTID,
- WMI_APLIST_EVENTID,
- WMI_GET_WOW_LIST_EVENTID,
- WMI_GET_PMKID_LIST_EVENTID,
- WMI_CHANNEL_CHANGE_EVENTID,
- WMI_PEER_NODE_EVENTID,
- WMI_PSPOLL_EVENTID,
- WMI_DTIMEXPIRY_EVENTID,
- WMI_WLAN_VERSION_EVENTID,
- WMI_SET_PARAMS_REPLY_EVENTID,
- WMI_ADDBA_REQ_EVENTID, /*0x1020 */
- WMI_ADDBA_RESP_EVENTID,
- WMI_DELBA_REQ_EVENTID,
- WMI_TX_COMPLETE_EVENTID,
- WMI_HCI_EVENT_EVENTID,
- WMI_ACL_DATA_EVENTID,
- WMI_REPORT_SLEEP_STATE_EVENTID,
-#ifdef WAPI_ENABLE
- WMI_WAPI_REKEY_EVENTID,
-#endif
- WMI_REPORT_BTCOEX_STATS_EVENTID,
- WMI_REPORT_BTCOEX_CONFIG_EVENTID,
- WMI_GET_PMK_EVENTID,
-
- /* DFS Events */
- WMI_DFS_HOST_ATTACH_EVENTID,
- WMI_DFS_HOST_INIT_EVENTID,
- WMI_DFS_RESET_DELAYLINES_EVENTID,
- WMI_DFS_RESET_RADARQ_EVENTID,
- WMI_DFS_RESET_AR_EVENTID,
- WMI_DFS_RESET_ARQ_EVENTID,
- WMI_DFS_SET_DUR_MULTIPLIER_EVENTID,
- WMI_DFS_SET_BANGRADAR_EVENTID,
- WMI_DFS_SET_DEBUGLEVEL_EVENTID,
- WMI_DFS_PHYERR_EVENTID,
- /* CCX Evants */
- WMI_CCX_RM_STATUS_EVENTID,
-
- /* P2P Events */
- WMI_P2P_GO_NEG_RESULT_EVENTID,
-
- WMI_WAC_SCAN_DONE_EVENTID,
- WMI_WAC_REPORT_BSS_EVENTID,
- WMI_WAC_START_WPS_EVENTID,
- WMI_WAC_CTRL_REQ_REPLY_EVENTID,
-
- /* RFKILL Events */
- WMI_RFKILL_STATE_CHANGE_EVENTID,
- WMI_RFKILL_GET_MODE_CMD_EVENTID,
- WMI_THIN_RESERVED_START_EVENTID = 0x8000,
-
- /*
- * Events in this range are reserved for thinmode
- * See wmi_thin.h for actual definitions
- */
- WMI_THIN_RESERVED_END_EVENTID = 0x8fff,
-
- WMI_SET_CHANNEL_EVENTID,
- WMI_ASSOC_REQ_EVENTID,
-
- /* generic ACS event */
- WMI_ACS_EVENTID,
- WMI_REPORT_WMM_PARAMS_EVENTID
-} WMI_EVENT_ID;
-
-
-typedef enum {
- WMI_11A_CAPABILITY = 1,
- WMI_11G_CAPABILITY = 2,
- WMI_11AG_CAPABILITY = 3,
- WMI_11NA_CAPABILITY = 4,
- WMI_11NG_CAPABILITY = 5,
- WMI_11NAG_CAPABILITY = 6,
- // END CAPABILITY
- WMI_11N_CAPABILITY_OFFSET = (WMI_11NA_CAPABILITY - WMI_11A_CAPABILITY),
-} WMI_PHY_CAPABILITY;
-
-typedef PREPACK struct {
- u8 macaddr[ATH_MAC_LEN];
- u8 phyCapability; /* WMI_PHY_CAPABILITY */
-} POSTPACK WMI_READY_EVENT_1;
-
-typedef PREPACK struct {
- u32 sw_version;
- u32 abi_version;
- u8 macaddr[ATH_MAC_LEN];
- u8 phyCapability; /* WMI_PHY_CAPABILITY */
-} POSTPACK WMI_READY_EVENT_2;
-
-#if defined(ATH_TARGET)
-#ifdef AR6002_REV2
-#define WMI_READY_EVENT WMI_READY_EVENT_1 /* AR6002_REV2 target code */
-#else
-#define WMI_READY_EVENT WMI_READY_EVENT_2 /* AR6001, AR6002_REV4, AR6002_REV5 */
-#endif
-#else
-#define WMI_READY_EVENT WMI_READY_EVENT_2 /* host code */
-#endif
-
-
-/*
- * Connect Event
- */
-typedef PREPACK struct {
- u16 channel;
- u8 bssid[ATH_MAC_LEN];
- u16 listenInterval;
- u16 beaconInterval;
- u32 networkType;
- u8 beaconIeLen;
- u8 assocReqLen;
- u8 assocRespLen;
- u8 assocInfo[1];
-} POSTPACK WMI_CONNECT_EVENT;
-
-/*
- * Disconnect Event
- */
-typedef enum {
- NO_NETWORK_AVAIL = 0x01,
- LOST_LINK = 0x02, /* bmiss */
- DISCONNECT_CMD = 0x03,
- BSS_DISCONNECTED = 0x04,
- AUTH_FAILED = 0x05,
- ASSOC_FAILED = 0x06,
- NO_RESOURCES_AVAIL = 0x07,
- CSERV_DISCONNECT = 0x08,
- INVALID_PROFILE = 0x0a,
- DOT11H_CHANNEL_SWITCH = 0x0b,
- PROFILE_MISMATCH = 0x0c,
- CONNECTION_EVICTED = 0x0d,
- IBSS_MERGE = 0xe,
-} WMI_DISCONNECT_REASON;
-
-typedef PREPACK struct {
- u16 protocolReasonStatus; /* reason code, see 802.11 spec. */
- u8 bssid[ATH_MAC_LEN]; /* set if known */
- u8 disconnectReason ; /* see WMI_DISCONNECT_REASON */
- u8 assocRespLen;
- u8 assocInfo[1];
-} POSTPACK WMI_DISCONNECT_EVENT;
-
-/*
- * BSS Info Event.
- * Mechanism used to inform host of the presence and characteristic of
- * wireless networks present. Consists of bss info header followed by
- * the beacon or probe-response frame body. The 802.11 header is not included.
- */
-typedef enum {
- BEACON_FTYPE = 0x1,
- PROBERESP_FTYPE,
- ACTION_MGMT_FTYPE,
- PROBEREQ_FTYPE,
-} WMI_BI_FTYPE;
-
-enum {
- BSS_ELEMID_CHANSWITCH = 0x01,
- BSS_ELEMID_ATHEROS = 0x02,
-};
-
-typedef PREPACK struct {
- u16 channel;
- u8 frameType; /* see WMI_BI_FTYPE */
- u8 snr;
- s16 rssi;
- u8 bssid[ATH_MAC_LEN];
- u32 ieMask;
-} POSTPACK WMI_BSS_INFO_HDR;
-
-/*
- * BSS INFO HDR version 2.0
- * With 6 bytes HTC header and 6 bytes of WMI header
- * WMI_BSS_INFO_HDR cannot be accommodated in the removed 802.11 management
- * header space.
- * - Reduce the ieMask to 2 bytes as only two bit flags are used
- * - Remove rssi and compute it on the host. rssi = snr - 95
- */
-typedef PREPACK struct {
- u16 channel;
- u8 frameType; /* see WMI_BI_FTYPE */
- u8 snr;
- u8 bssid[ATH_MAC_LEN];
- u16 ieMask;
-} POSTPACK WMI_BSS_INFO_HDR2;
-
-/*
- * Command Error Event
- */
-typedef enum {
- INVALID_PARAM = 0x01,
- ILLEGAL_STATE = 0x02,
- INTERNAL_ERROR = 0x03,
-} WMI_ERROR_CODE;
-
-typedef PREPACK struct {
- u16 commandId;
- u8 errorCode;
-} POSTPACK WMI_CMD_ERROR_EVENT;
-
-/*
- * New Regulatory Domain Event
- */
-typedef PREPACK struct {
- u32 regDomain;
-} POSTPACK WMI_REG_DOMAIN_EVENT;
-
-typedef PREPACK struct {
- u8 txQueueNumber;
- u8 rxQueueNumber;
- u8 trafficDirection;
- u8 trafficClass;
-} POSTPACK WMI_PSTREAM_TIMEOUT_EVENT;
-
-typedef PREPACK struct {
- u8 reserve1;
- u8 reserve2;
- u8 reserve3;
- u8 trafficClass;
-} POSTPACK WMI_ACM_REJECT_EVENT;
-
-/*
- * The WMI_NEIGHBOR_REPORT Event is generated by the target to inform
- * the host of BSS's it has found that matches the current profile.
- * It can be used by the host to cache PMKs and/to initiate pre-authentication
- * if the BSS supports it. The first bssid is always the current associated
- * BSS.
- * The bssid and bssFlags information repeats according to the number
- * or APs reported.
- */
-typedef enum {
- WMI_DEFAULT_BSS_FLAGS = 0x00,
- WMI_PREAUTH_CAPABLE_BSS = 0x01,
- WMI_PMKID_VALID_BSS = 0x02,
-} WMI_BSS_FLAGS;
-
-typedef PREPACK struct {
- u8 bssid[ATH_MAC_LEN];
- u8 bssFlags; /* see WMI_BSS_FLAGS */
-} POSTPACK WMI_NEIGHBOR_INFO;
-
-typedef PREPACK struct {
- s8 numberOfAps;
- WMI_NEIGHBOR_INFO neighbor[1];
-} POSTPACK WMI_NEIGHBOR_REPORT_EVENT;
-
-/*
- * TKIP MIC Error Event
- */
-typedef PREPACK struct {
- u8 keyid;
- u8 ismcast;
-} POSTPACK WMI_TKIP_MICERR_EVENT;
-
-/*
- * WMI_SCAN_COMPLETE_EVENTID - no parameters (old), staus parameter (new)
- */
-typedef PREPACK struct {
- s32 status;
-} POSTPACK WMI_SCAN_COMPLETE_EVENT;
-
-#define MAX_OPT_DATA_LEN 1400
-
-/*
- * WMI_SET_ADHOC_BSSID_CMDID
- */
-typedef PREPACK struct {
- u8 bssid[ATH_MAC_LEN];
-} POSTPACK WMI_SET_ADHOC_BSSID_CMD;
-
-/*
- * WMI_SET_OPT_MODE_CMDID
- */
-typedef enum {
- SPECIAL_OFF,
- SPECIAL_ON,
-} OPT_MODE_TYPE;
-
-typedef PREPACK struct {
- u8 optMode;
-} POSTPACK WMI_SET_OPT_MODE_CMD;
-
-/*
- * WMI_TX_OPT_FRAME_CMDID
- */
-typedef enum {
- OPT_PROBE_REQ = 0x01,
- OPT_PROBE_RESP = 0x02,
- OPT_CPPP_START = 0x03,
- OPT_CPPP_STOP = 0x04,
-} WMI_OPT_FTYPE;
-
-typedef PREPACK struct {
- u16 optIEDataLen;
- u8 frmType;
- u8 dstAddr[ATH_MAC_LEN];
- u8 bssid[ATH_MAC_LEN];
- u8 reserved; /* For alignment */
- u8 optIEData[1];
-} POSTPACK WMI_OPT_TX_FRAME_CMD;
-
-/*
- * Special frame receive Event.
- * Mechanism used to inform host of the receiption of the special frames.
- * Consists of special frame info header followed by special frame body.
- * The 802.11 header is not included.
- */
-typedef PREPACK struct {
- u16 channel;
- u8 frameType; /* see WMI_OPT_FTYPE */
- s8 snr;
- u8 srcAddr[ATH_MAC_LEN];
- u8 bssid[ATH_MAC_LEN];
-} POSTPACK WMI_OPT_RX_INFO_HDR;
-
-/*
- * Reporting statistics.
- */
-typedef PREPACK struct {
- u32 tx_packets;
- u32 tx_bytes;
- u32 tx_unicast_pkts;
- u32 tx_unicast_bytes;
- u32 tx_multicast_pkts;
- u32 tx_multicast_bytes;
- u32 tx_broadcast_pkts;
- u32 tx_broadcast_bytes;
- u32 tx_rts_success_cnt;
- u32 tx_packet_per_ac[4];
- u32 tx_errors_per_ac[4];
-
- u32 tx_errors;
- u32 tx_failed_cnt;
- u32 tx_retry_cnt;
- u32 tx_mult_retry_cnt;
- u32 tx_rts_fail_cnt;
- s32 tx_unicast_rate;
-}POSTPACK tx_stats_t;
-
-typedef PREPACK struct {
- u32 rx_packets;
- u32 rx_bytes;
- u32 rx_unicast_pkts;
- u32 rx_unicast_bytes;
- u32 rx_multicast_pkts;
- u32 rx_multicast_bytes;
- u32 rx_broadcast_pkts;
- u32 rx_broadcast_bytes;
- u32 rx_fragment_pkt;
-
- u32 rx_errors;
- u32 rx_crcerr;
- u32 rx_key_cache_miss;
- u32 rx_decrypt_err;
- u32 rx_duplicate_frames;
- s32 rx_unicast_rate;
-}POSTPACK rx_stats_t;
-
-typedef PREPACK struct {
- u32 tkip_local_mic_failure;
- u32 tkip_counter_measures_invoked;
- u32 tkip_replays;
- u32 tkip_format_errors;
- u32 ccmp_format_errors;
- u32 ccmp_replays;
-}POSTPACK tkip_ccmp_stats_t;
-
-typedef PREPACK struct {
- u32 power_save_failure_cnt;
- u16 stop_tx_failure_cnt;
- u16 atim_tx_failure_cnt;
- u16 atim_rx_failure_cnt;
- u16 bcn_rx_failure_cnt;
-}POSTPACK pm_stats_t;
-
-typedef PREPACK struct {
- u32 cs_bmiss_cnt;
- u32 cs_lowRssi_cnt;
- u16 cs_connect_cnt;
- u16 cs_disconnect_cnt;
- s16 cs_aveBeacon_rssi;
- u16 cs_roam_count;
- s16 cs_rssi;
- u8 cs_snr;
- u8 cs_aveBeacon_snr;
- u8 cs_lastRoam_msec;
-} POSTPACK cserv_stats_t;
-
-typedef PREPACK struct {
- tx_stats_t tx_stats;
- rx_stats_t rx_stats;
- tkip_ccmp_stats_t tkipCcmpStats;
-}POSTPACK wlan_net_stats_t;
-
-typedef PREPACK struct {
- u32 arp_received;
- u32 arp_matched;
- u32 arp_replied;
-} POSTPACK arp_stats_t;
-
-typedef PREPACK struct {
- u32 wow_num_pkts_dropped;
- u16 wow_num_events_discarded;
- u8 wow_num_host_pkt_wakeups;
- u8 wow_num_host_event_wakeups;
-} POSTPACK wlan_wow_stats_t;
-
-typedef PREPACK struct {
- u32 lqVal;
- s32 noise_floor_calibation;
- pm_stats_t pmStats;
- wlan_net_stats_t txrxStats;
- wlan_wow_stats_t wowStats;
- arp_stats_t arpStats;
- cserv_stats_t cservStats;
-} POSTPACK WMI_TARGET_STATS;
-
-/*
- * WMI_RSSI_THRESHOLD_EVENTID.
- * Indicate the RSSI events to host. Events are indicated when we breach a
- * thresold value.
- */
-typedef enum{
- WMI_RSSI_THRESHOLD1_ABOVE = 0,
- WMI_RSSI_THRESHOLD2_ABOVE,
- WMI_RSSI_THRESHOLD3_ABOVE,
- WMI_RSSI_THRESHOLD4_ABOVE,
- WMI_RSSI_THRESHOLD5_ABOVE,
- WMI_RSSI_THRESHOLD6_ABOVE,
- WMI_RSSI_THRESHOLD1_BELOW,
- WMI_RSSI_THRESHOLD2_BELOW,
- WMI_RSSI_THRESHOLD3_BELOW,
- WMI_RSSI_THRESHOLD4_BELOW,
- WMI_RSSI_THRESHOLD5_BELOW,
- WMI_RSSI_THRESHOLD6_BELOW
-}WMI_RSSI_THRESHOLD_VAL;
-
-typedef PREPACK struct {
- s16 rssi;
- u8 range;
-}POSTPACK WMI_RSSI_THRESHOLD_EVENT;
-
-/*
- * WMI_ERROR_REPORT_EVENTID
- */
-typedef enum{
- WMI_TARGET_PM_ERR_FAIL = 0x00000001,
- WMI_TARGET_KEY_NOT_FOUND = 0x00000002,
- WMI_TARGET_DECRYPTION_ERR = 0x00000004,
- WMI_TARGET_BMISS = 0x00000008,
- WMI_PSDISABLE_NODE_JOIN = 0x00000010,
- WMI_TARGET_COM_ERR = 0x00000020,
- WMI_TARGET_FATAL_ERR = 0x00000040
-} WMI_TARGET_ERROR_VAL;
-
-typedef PREPACK struct {
- u32 errorVal;
-}POSTPACK WMI_TARGET_ERROR_REPORT_EVENT;
-
-typedef PREPACK struct {
- u8 retrys;
-}POSTPACK WMI_TX_RETRY_ERR_EVENT;
-
-typedef enum{
- WMI_SNR_THRESHOLD1_ABOVE = 1,
- WMI_SNR_THRESHOLD1_BELOW,
- WMI_SNR_THRESHOLD2_ABOVE,
- WMI_SNR_THRESHOLD2_BELOW,
- WMI_SNR_THRESHOLD3_ABOVE,
- WMI_SNR_THRESHOLD3_BELOW,
- WMI_SNR_THRESHOLD4_ABOVE,
- WMI_SNR_THRESHOLD4_BELOW
-} WMI_SNR_THRESHOLD_VAL;
-
-typedef PREPACK struct {
- u8 range; /* WMI_SNR_THRESHOLD_VAL */
- u8 snr;
-}POSTPACK WMI_SNR_THRESHOLD_EVENT;
-
-typedef enum{
- WMI_LQ_THRESHOLD1_ABOVE = 1,
- WMI_LQ_THRESHOLD1_BELOW,
- WMI_LQ_THRESHOLD2_ABOVE,
- WMI_LQ_THRESHOLD2_BELOW,
- WMI_LQ_THRESHOLD3_ABOVE,
- WMI_LQ_THRESHOLD3_BELOW,
- WMI_LQ_THRESHOLD4_ABOVE,
- WMI_LQ_THRESHOLD4_BELOW
-} WMI_LQ_THRESHOLD_VAL;
-
-typedef PREPACK struct {
- s32 lq;
- u8 range; /* WMI_LQ_THRESHOLD_VAL */
-}POSTPACK WMI_LQ_THRESHOLD_EVENT;
-/*
- * WMI_REPORT_ROAM_TBL_EVENTID
- */
-#define MAX_ROAM_TBL_CAND 5
-
-typedef PREPACK struct {
- s32 roam_util;
- u8 bssid[ATH_MAC_LEN];
- s8 rssi;
- s8 rssidt;
- s8 last_rssi;
- s8 util;
- s8 bias;
- u8 reserved; /* For alignment */
-} POSTPACK WMI_BSS_ROAM_INFO;
-
-
-typedef PREPACK struct {
- u16 roamMode;
- u16 numEntries;
- WMI_BSS_ROAM_INFO bssRoamInfo[1];
-} POSTPACK WMI_TARGET_ROAM_TBL;
-
-/*
- * WMI_HCI_EVENT_EVENTID
- */
-typedef PREPACK struct {
- u16 evt_buf_sz; /* HCI event buffer size */
- u8 buf[1]; /* HCI event */
-} POSTPACK WMI_HCI_EVENT;
-
-/*
- * WMI_CAC_EVENTID
- */
-typedef enum {
- CAC_INDICATION_ADMISSION = 0x00,
- CAC_INDICATION_ADMISSION_RESP = 0x01,
- CAC_INDICATION_DELETE = 0x02,
- CAC_INDICATION_NO_RESP = 0x03,
-}CAC_INDICATION;
-
-#define WMM_TSPEC_IE_LEN 63
-
-typedef PREPACK struct {
- u8 ac;
- u8 cac_indication;
- u8 statusCode;
- u8 tspecSuggestion[WMM_TSPEC_IE_LEN];
-}POSTPACK WMI_CAC_EVENT;
-
-/*
- * WMI_APLIST_EVENTID
- */
-
-typedef enum {
- APLIST_VER1 = 1,
-} APLIST_VER;
-
-typedef PREPACK struct {
- u8 bssid[ATH_MAC_LEN];
- u16 channel;
-} POSTPACK WMI_AP_INFO_V1;
-
-typedef PREPACK union {
- WMI_AP_INFO_V1 apInfoV1;
-} POSTPACK WMI_AP_INFO;
-
-typedef PREPACK struct {
- u8 apListVer;
- u8 numAP;
- WMI_AP_INFO apList[1];
-} POSTPACK WMI_APLIST_EVENT;
-
-/*
- * developer commands
- */
-
-/*
- * WMI_SET_BITRATE_CMDID
- *
- * Get bit rate cmd uses same definition as set bit rate cmd
- */
-typedef enum {
- RATE_AUTO = -1,
- RATE_1Mb = 0,
- RATE_2Mb = 1,
- RATE_5_5Mb = 2,
- RATE_11Mb = 3,
- RATE_6Mb = 4,
- RATE_9Mb = 5,
- RATE_12Mb = 6,
- RATE_18Mb = 7,
- RATE_24Mb = 8,
- RATE_36Mb = 9,
- RATE_48Mb = 10,
- RATE_54Mb = 11,
- RATE_MCS_0_20 = 12,
- RATE_MCS_1_20 = 13,
- RATE_MCS_2_20 = 14,
- RATE_MCS_3_20 = 15,
- RATE_MCS_4_20 = 16,
- RATE_MCS_5_20 = 17,
- RATE_MCS_6_20 = 18,
- RATE_MCS_7_20 = 19,
- RATE_MCS_0_40 = 20,
- RATE_MCS_1_40 = 21,
- RATE_MCS_2_40 = 22,
- RATE_MCS_3_40 = 23,
- RATE_MCS_4_40 = 24,
- RATE_MCS_5_40 = 25,
- RATE_MCS_6_40 = 26,
- RATE_MCS_7_40 = 27,
-} WMI_BIT_RATE;
-
-typedef PREPACK struct {
- s8 rateIndex; /* see WMI_BIT_RATE */
- s8 mgmtRateIndex;
- s8 ctlRateIndex;
-} POSTPACK WMI_BIT_RATE_CMD;
-
-
-typedef PREPACK struct {
- s8 rateIndex; /* see WMI_BIT_RATE */
-} POSTPACK WMI_BIT_RATE_REPLY;
-
-
-/*
- * WMI_SET_FIXRATES_CMDID
- *
- * Get fix rates cmd uses same definition as set fix rates cmd
- */
-#define FIX_RATE_1Mb ((u32)0x1)
-#define FIX_RATE_2Mb ((u32)0x2)
-#define FIX_RATE_5_5Mb ((u32)0x4)
-#define FIX_RATE_11Mb ((u32)0x8)
-#define FIX_RATE_6Mb ((u32)0x10)
-#define FIX_RATE_9Mb ((u32)0x20)
-#define FIX_RATE_12Mb ((u32)0x40)
-#define FIX_RATE_18Mb ((u32)0x80)
-#define FIX_RATE_24Mb ((u32)0x100)
-#define FIX_RATE_36Mb ((u32)0x200)
-#define FIX_RATE_48Mb ((u32)0x400)
-#define FIX_RATE_54Mb ((u32)0x800)
-#define FIX_RATE_MCS_0_20 ((u32)0x1000)
-#define FIX_RATE_MCS_1_20 ((u32)0x2000)
-#define FIX_RATE_MCS_2_20 ((u32)0x4000)
-#define FIX_RATE_MCS_3_20 ((u32)0x8000)
-#define FIX_RATE_MCS_4_20 ((u32)0x10000)
-#define FIX_RATE_MCS_5_20 ((u32)0x20000)
-#define FIX_RATE_MCS_6_20 ((u32)0x40000)
-#define FIX_RATE_MCS_7_20 ((u32)0x80000)
-#define FIX_RATE_MCS_0_40 ((u32)0x100000)
-#define FIX_RATE_MCS_1_40 ((u32)0x200000)
-#define FIX_RATE_MCS_2_40 ((u32)0x400000)
-#define FIX_RATE_MCS_3_40 ((u32)0x800000)
-#define FIX_RATE_MCS_4_40 ((u32)0x1000000)
-#define FIX_RATE_MCS_5_40 ((u32)0x2000000)
-#define FIX_RATE_MCS_6_40 ((u32)0x4000000)
-#define FIX_RATE_MCS_7_40 ((u32)0x8000000)
-
-typedef PREPACK struct {
- u32 fixRateMask; /* see WMI_BIT_RATE */
-} POSTPACK WMI_FIX_RATES_CMD, WMI_FIX_RATES_REPLY;
-
-typedef PREPACK struct {
- u8 bEnableMask;
- u8 frameType; /*type and subtype*/
- u32 frameRateMask; /* see WMI_BIT_RATE */
-} POSTPACK WMI_FRAME_RATES_CMD, WMI_FRAME_RATES_REPLY;
-
-/*
- * WMI_SET_RECONNECT_AUTH_MODE_CMDID
- *
- * Set authentication mode
- */
-typedef enum {
- RECONN_DO_AUTH = 0x00,
- RECONN_NOT_AUTH = 0x01
-} WMI_AUTH_MODE;
-
-typedef PREPACK struct {
- u8 mode;
-} POSTPACK WMI_SET_AUTH_MODE_CMD;
-
-/*
- * WMI_SET_REASSOC_MODE_CMDID
- *
- * Set authentication mode
- */
-typedef enum {
- REASSOC_DO_DISASSOC = 0x00,
- REASSOC_DONOT_DISASSOC = 0x01
-} WMI_REASSOC_MODE;
-
-typedef PREPACK struct {
- u8 mode;
-}POSTPACK WMI_SET_REASSOC_MODE_CMD;
-
-typedef enum {
- ROAM_DATA_TIME = 1, /* Get The Roam Time Data */
-} ROAM_DATA_TYPE;
-
-typedef PREPACK struct {
- u32 disassoc_time;
- u32 no_txrx_time;
- u32 assoc_time;
- u32 allow_txrx_time;
- u8 disassoc_bssid[ATH_MAC_LEN];
- s8 disassoc_bss_rssi;
- u8 assoc_bssid[ATH_MAC_LEN];
- s8 assoc_bss_rssi;
-} POSTPACK WMI_TARGET_ROAM_TIME;
-
-typedef PREPACK struct {
- PREPACK union {
- WMI_TARGET_ROAM_TIME roamTime;
- } POSTPACK u;
- u8 roamDataType ;
-} POSTPACK WMI_TARGET_ROAM_DATA;
-
-typedef enum {
- WMI_WMM_DISABLED = 0,
- WMI_WMM_ENABLED
-} WMI_WMM_STATUS;
-
-typedef PREPACK struct {
- u8 status;
-}POSTPACK WMI_SET_WMM_CMD;
-
-typedef PREPACK struct {
- u8 status;
-}POSTPACK WMI_SET_QOS_SUPP_CMD;
-
-typedef enum {
- WMI_TXOP_DISABLED = 0,
- WMI_TXOP_ENABLED
-} WMI_TXOP_CFG;
-
-typedef PREPACK struct {
- u8 txopEnable;
-}POSTPACK WMI_SET_WMM_TXOP_CMD;
-
-typedef PREPACK struct {
- u8 keepaliveInterval;
-} POSTPACK WMI_SET_KEEPALIVE_CMD;
-
-typedef PREPACK struct {
- u32 configured;
- u8 keepaliveInterval;
-} POSTPACK WMI_GET_KEEPALIVE_CMD;
-
-/*
- * Add Application specified IE to a management frame
- */
-#define WMI_MAX_IE_LEN 255
-
-typedef PREPACK struct {
- u8 mgmtFrmType; /* one of WMI_MGMT_FRAME_TYPE */
- u8 ieLen; /* Length of the IE that should be added to the MGMT frame */
- u8 ieInfo[1];
-} POSTPACK WMI_SET_APPIE_CMD;
-
-/*
- * Notify the WSC registration status to the target
- */
-#define WSC_REG_ACTIVE 1
-#define WSC_REG_INACTIVE 0
-/* Generic Hal Interface for setting hal paramters. */
-/* Add new Set HAL Param cmdIds here for newer params */
-typedef enum {
- WHAL_SETCABTO_CMDID = 1,
-}WHAL_CMDID;
-
-typedef PREPACK struct {
- u8 cabTimeOut;
-} POSTPACK WHAL_SETCABTO_PARAM;
-
-typedef PREPACK struct {
- u8 whalCmdId;
- u8 data[1];
-} POSTPACK WHAL_PARAMCMD;
-
-
-#define WOW_MAX_FILTER_LISTS 1 /*4*/
-#define WOW_MAX_FILTERS_PER_LIST 4
-#define WOW_PATTERN_SIZE 64
-#define WOW_MASK_SIZE 64
-
-#define MAC_MAX_FILTERS_PER_LIST 4
-
-typedef PREPACK struct {
- u8 wow_valid_filter;
- u8 wow_filter_id;
- u8 wow_filter_size;
- u8 wow_filter_offset;
- u8 wow_filter_mask[WOW_MASK_SIZE];
- u8 wow_filter_pattern[WOW_PATTERN_SIZE];
-} POSTPACK WOW_FILTER;
-
-
-typedef PREPACK struct {
- u8 wow_valid_list;
- u8 wow_list_id;
- u8 wow_num_filters;
- u8 wow_total_list_size;
- WOW_FILTER list[WOW_MAX_FILTERS_PER_LIST];
-} POSTPACK WOW_FILTER_LIST;
-
-typedef PREPACK struct {
- u8 valid_filter;
- u8 mac_addr[ATH_MAC_LEN];
-} POSTPACK MAC_FILTER;
-
-
-typedef PREPACK struct {
- u8 total_list_size;
- u8 enable;
- MAC_FILTER list[MAC_MAX_FILTERS_PER_LIST];
-} POSTPACK MAC_FILTER_LIST;
-
-#define MAX_IP_ADDRS 2
-typedef PREPACK struct {
- u32 ips[MAX_IP_ADDRS]; /* IP in Network Byte Order */
-} POSTPACK WMI_SET_IP_CMD;
-
-typedef PREPACK struct {
- u32 awake;
- u32 asleep;
-} POSTPACK WMI_SET_HOST_SLEEP_MODE_CMD;
-
-typedef enum {
- WOW_FILTER_SSID = 0x1
-} WMI_WOW_FILTER;
-
-typedef PREPACK struct {
- u32 enable_wow;
- WMI_WOW_FILTER filter;
- u16 hostReqDelay;
-} POSTPACK WMI_SET_WOW_MODE_CMD;
-
-typedef PREPACK struct {
- u8 filter_list_id;
-} POSTPACK WMI_GET_WOW_LIST_CMD;
-
-/*
- * WMI_GET_WOW_LIST_CMD reply
- */
-typedef PREPACK struct {
- u8 num_filters; /* number of patterns in reply */
- u8 this_filter_num; /* this is filter # x of total num_filters */
- u8 wow_mode;
- u8 host_mode;
- WOW_FILTER wow_filters[1];
-} POSTPACK WMI_GET_WOW_LIST_REPLY;
-
-typedef PREPACK struct {
- u8 filter_list_id;
- u8 filter_size;
- u8 filter_offset;
- u8 filter[1];
-} POSTPACK WMI_ADD_WOW_PATTERN_CMD;
-
-typedef PREPACK struct {
- u16 filter_list_id;
- u16 filter_id;
-} POSTPACK WMI_DEL_WOW_PATTERN_CMD;
-
-typedef PREPACK struct {
- u8 macaddr[ATH_MAC_LEN];
-} POSTPACK WMI_SET_MAC_ADDRESS_CMD;
-
-/*
- * WMI_SET_AKMP_PARAMS_CMD
- */
-
-#define WMI_AKMP_MULTI_PMKID_EN 0x000001
-
-typedef PREPACK struct {
- u32 akmpInfo;
-} POSTPACK WMI_SET_AKMP_PARAMS_CMD;
-
-typedef PREPACK struct {
- u8 pmkid[WMI_PMKID_LEN];
-} POSTPACK WMI_PMKID;
-
-/*
- * WMI_SET_PMKID_LIST_CMD
- */
-#define WMI_MAX_PMKID_CACHE 8
-
-typedef PREPACK struct {
- u32 numPMKID;
- WMI_PMKID pmkidList[WMI_MAX_PMKID_CACHE];
-} POSTPACK WMI_SET_PMKID_LIST_CMD;
-
-/*
- * WMI_GET_PMKID_LIST_CMD Reply
- * Following the Number of PMKIDs is the list of PMKIDs
- */
-typedef PREPACK struct {
- u32 numPMKID;
- u8 bssidList[ATH_MAC_LEN][1];
- WMI_PMKID pmkidList[1];
-} POSTPACK WMI_PMKID_LIST_REPLY;
-
-typedef PREPACK struct {
- u16 oldChannel;
- u32 newChannel;
-} POSTPACK WMI_CHANNEL_CHANGE_EVENT;
-
-typedef PREPACK struct {
- u32 version;
-} POSTPACK WMI_WLAN_VERSION_EVENT;
-
-
-/* WMI_ADDBA_REQ_EVENTID */
-typedef PREPACK struct {
- u8 tid;
- u8 win_sz;
- u16 st_seq_no;
- u8 status; /* f/w response for ADDBA Req; OK(0) or failure(!=0) */
-} POSTPACK WMI_ADDBA_REQ_EVENT;
-
-/* WMI_ADDBA_RESP_EVENTID */
-typedef PREPACK struct {
- u8 tid;
- u8 status; /* OK(0), failure (!=0) */
- u16 amsdu_sz; /* Three values: Not supported(0), 3839, 8k */
-} POSTPACK WMI_ADDBA_RESP_EVENT;
-
-/* WMI_DELBA_EVENTID
- * f/w received a DELBA for peer and processed it.
- * Host is notified of this
- */
-typedef PREPACK struct {
- u8 tid;
- u8 is_peer_initiator;
- u16 reason_code;
-} POSTPACK WMI_DELBA_EVENT;
-
-
-#ifdef WAPI_ENABLE
-#define WAPI_REKEY_UCAST 1
-#define WAPI_REKEY_MCAST 2
-typedef PREPACK struct {
- u8 type;
- u8 macAddr[ATH_MAC_LEN];
-} POSTPACK WMI_WAPIREKEY_EVENT;
-#endif
-
-
-/* WMI_ALLOW_AGGR_CMDID
- * Configures tid's to allow ADDBA negotiations
- * on each tid, in each direction
- */
-typedef PREPACK struct {
- u16 tx_allow_aggr; /* 16-bit mask to allow uplink ADDBA negotiation - bit position indicates tid*/
- u16 rx_allow_aggr; /* 16-bit mask to allow donwlink ADDBA negotiation - bit position indicates tid*/
-} POSTPACK WMI_ALLOW_AGGR_CMD;
-
-/* WMI_ADDBA_REQ_CMDID
- * f/w starts performing ADDBA negotiations with peer
- * on the given tid
- */
-typedef PREPACK struct {
- u8 tid;
-} POSTPACK WMI_ADDBA_REQ_CMD;
-
-/* WMI_DELBA_REQ_CMDID
- * f/w would teardown BA with peer.
- * is_send_initiator indicates if it's or tx or rx side
- */
-typedef PREPACK struct {
- u8 tid;
- u8 is_sender_initiator;
-
-} POSTPACK WMI_DELBA_REQ_CMD;
-
-#define PEER_NODE_JOIN_EVENT 0x00
-#define PEER_NODE_LEAVE_EVENT 0x01
-#define PEER_FIRST_NODE_JOIN_EVENT 0x10
-#define PEER_LAST_NODE_LEAVE_EVENT 0x11
-typedef PREPACK struct {
- u8 eventCode;
- u8 peerMacAddr[ATH_MAC_LEN];
-} POSTPACK WMI_PEER_NODE_EVENT;
-
-#define IEEE80211_FRAME_TYPE_MGT 0x00
-#define IEEE80211_FRAME_TYPE_CTL 0x04
-
-/*
- * Transmit complete event data structure(s)
- */
-
-
-typedef PREPACK struct {
-#define TX_COMPLETE_STATUS_SUCCESS 0
-#define TX_COMPLETE_STATUS_RETRIES 1
-#define TX_COMPLETE_STATUS_NOLINK 2
-#define TX_COMPLETE_STATUS_TIMEOUT 3
-#define TX_COMPLETE_STATUS_OTHER 4
-
- u8 status; /* one of TX_COMPLETE_STATUS_... */
- u8 pktID; /* packet ID to identify parent packet */
- u8 rateIdx; /* rate index on successful transmission */
- u8 ackFailures; /* number of ACK failures in tx attempt */
-#if 0 /* optional params currently omitted. */
- u32 queueDelay; // usec delay measured Tx Start time - host delivery time
- u32 mediaDelay; // usec delay measured ACK rx time - host delivery time
-#endif
-} POSTPACK TX_COMPLETE_MSG_V1; /* version 1 of tx complete msg */
-
-typedef PREPACK struct {
- u8 numMessages; /* number of tx comp msgs following this struct */
- u8 msgLen; /* length in bytes for each individual msg following this struct */
- u8 msgType; /* version of tx complete msg data following this struct */
- u8 reserved; /* individual messages follow this header */
-} POSTPACK WMI_TX_COMPLETE_EVENT;
-
-#define WMI_TXCOMPLETE_VERSION_1 (0x01)
-
-
-/*
- * ------- AP Mode definitions --------------
- */
-
-/*
- * !!! Warning !!!
- * -Changing the following values needs compilation of both driver and firmware
- */
-#ifdef AR6002_REV2
-#define AP_MAX_NUM_STA 4
-#else
-#define AP_MAX_NUM_STA 8
-#endif
-#define AP_ACL_SIZE 10
-#define IEEE80211_MAX_IE 256
-#define MCAST_AID 0xFF /* Spl. AID used to set DTIM flag in the beacons */
-#define DEF_AP_COUNTRY_CODE "US "
-#define DEF_AP_WMODE_G WMI_11G_MODE
-#define DEF_AP_WMODE_AG WMI_11AG_MODE
-#define DEF_AP_DTIM 5
-#define DEF_BEACON_INTERVAL 100
-
-/* AP mode disconnect reasons */
-#define AP_DISCONNECT_STA_LEFT 101
-#define AP_DISCONNECT_FROM_HOST 102
-#define AP_DISCONNECT_COMM_TIMEOUT 103
-
-/*
- * Used with WMI_AP_HIDDEN_SSID_CMDID
- */
-#define HIDDEN_SSID_FALSE 0
-#define HIDDEN_SSID_TRUE 1
-typedef PREPACK struct {
- u8 hidden_ssid;
-} POSTPACK WMI_AP_HIDDEN_SSID_CMD;
-
-/*
- * Used with WMI_AP_ACL_POLICY_CMDID
- */
-#define AP_ACL_DISABLE 0x00
-#define AP_ACL_ALLOW_MAC 0x01
-#define AP_ACL_DENY_MAC 0x02
-#define AP_ACL_RETAIN_LIST_MASK 0x80
-typedef PREPACK struct {
- u8 policy;
-} POSTPACK WMI_AP_ACL_POLICY_CMD;
-
-/*
- * Used with WMI_AP_ACL_MAC_LIST_CMDID
- */
-#define ADD_MAC_ADDR 1
-#define DEL_MAC_ADDR 2
-typedef PREPACK struct {
- u8 action;
- u8 index;
- u8 mac[ATH_MAC_LEN];
- u8 wildcard;
-} POSTPACK WMI_AP_ACL_MAC_CMD;
-
-typedef PREPACK struct {
- u16 index;
- u8 acl_mac[AP_ACL_SIZE][ATH_MAC_LEN];
- u8 wildcard[AP_ACL_SIZE];
- u8 policy;
-} POSTPACK WMI_AP_ACL;
-
-/*
- * Used with WMI_AP_SET_NUM_STA_CMDID
- */
-typedef PREPACK struct {
- u8 num_sta;
-} POSTPACK WMI_AP_SET_NUM_STA_CMD;
-
-/*
- * Used with WMI_AP_SET_MLME_CMDID
- */
-typedef PREPACK struct {
- u8 mac[ATH_MAC_LEN];
- u16 reason; /* 802.11 reason code */
- u8 cmd; /* operation to perform */
-#define WMI_AP_MLME_ASSOC 1 /* associate station */
-#define WMI_AP_DISASSOC 2 /* disassociate station */
-#define WMI_AP_DEAUTH 3 /* deauthenticate station */
-#define WMI_AP_MLME_AUTHORIZE 4 /* authorize station */
-#define WMI_AP_MLME_UNAUTHORIZE 5 /* unauthorize station */
-} POSTPACK WMI_AP_SET_MLME_CMD;
-
-typedef PREPACK struct {
- u32 period;
-} POSTPACK WMI_AP_CONN_INACT_CMD;
-
-typedef PREPACK struct {
- u32 period_min;
- u32 dwell_ms;
-} POSTPACK WMI_AP_PROT_SCAN_TIME_CMD;
-
-typedef PREPACK struct {
- u32 flag;
- u16 aid;
-} POSTPACK WMI_AP_SET_PVB_CMD;
-
-#define WMI_DISABLE_REGULATORY_CODE "FF"
-
-typedef PREPACK struct {
- u8 countryCode[3];
-} POSTPACK WMI_AP_SET_COUNTRY_CMD;
-
-typedef PREPACK struct {
- u8 dtim;
-} POSTPACK WMI_AP_SET_DTIM_CMD;
-
-typedef PREPACK struct {
- u8 band; /* specifies which band to apply these values */
- u8 enable; /* allows 11n to be disabled on a per band basis */
- u8 chan_width_40M_supported;
- u8 short_GI_20MHz;
- u8 short_GI_40MHz;
- u8 intolerance_40MHz;
- u8 max_ampdu_len_exp;
-} POSTPACK WMI_SET_HT_CAP_CMD;
-
-typedef PREPACK struct {
- u8 sta_chan_width;
-} POSTPACK WMI_SET_HT_OP_CMD;
-
-typedef PREPACK struct {
- u32 rateMasks[8];
-} POSTPACK WMI_SET_TX_SELECT_RATES_CMD;
-
-typedef PREPACK struct {
- u32 sgiMask;
- u8 sgiPERThreshold;
-} POSTPACK WMI_SET_TX_SGI_PARAM_CMD;
-
-#define DEFAULT_SGI_MASK 0x08080000
-#define DEFAULT_SGI_PER 10
-
-typedef PREPACK struct {
- u32 rateField; /* 1 bit per rate corresponding to index */
- u8 id;
- u8 shortTrys;
- u8 longTrys;
- u8 reserved; /* padding */
-} POSTPACK WMI_SET_RATE_POLICY_CMD;
-
-typedef PREPACK struct {
- u8 metaVersion; /* version of meta data for rx packets <0 = default> (0-7 = valid) */
- u8 dot11Hdr; /* 1 == leave .11 header intact , 0 == replace .11 header with .3 <default> */
- u8 defragOnHost; /* 1 == defragmentation is performed by host, 0 == performed by target <default> */
- u8 reserved[1]; /* alignment */
-} POSTPACK WMI_RX_FRAME_FORMAT_CMD;
-
-
-typedef PREPACK struct {
- u8 enable; /* 1 == device operates in thin mode , 0 == normal mode <default> */
- u8 reserved[3];
-} POSTPACK WMI_SET_THIN_MODE_CMD;
-
-/* AP mode events */
-/* WMI_PS_POLL_EVENT */
-typedef PREPACK struct {
- u16 aid;
-} POSTPACK WMI_PSPOLL_EVENT;
-
-typedef PREPACK struct {
- u32 tx_bytes;
- u32 tx_pkts;
- u32 tx_error;
- u32 tx_discard;
- u32 rx_bytes;
- u32 rx_pkts;
- u32 rx_error;
- u32 rx_discard;
- u32 aid;
-} POSTPACK WMI_PER_STA_STAT;
-
-#define AP_GET_STATS 0
-#define AP_CLEAR_STATS 1
-
-typedef PREPACK struct {
- u32 action;
- WMI_PER_STA_STAT sta[AP_MAX_NUM_STA+1];
-} POSTPACK WMI_AP_MODE_STAT;
-#define WMI_AP_MODE_STAT_SIZE(numSta) (sizeof(u32) + ((numSta + 1) * sizeof(WMI_PER_STA_STAT)))
-
-#define AP_11BG_RATESET1 1
-#define AP_11BG_RATESET2 2
-#define DEF_AP_11BG_RATESET AP_11BG_RATESET1
-typedef PREPACK struct {
- u8 rateset;
-} POSTPACK WMI_AP_SET_11BG_RATESET_CMD;
-/*
- * End of AP mode definitions
- */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _WMI_H_ */
diff --git a/drivers/staging/ath6kl/include/common/wmix.h b/drivers/staging/ath6kl/include/common/wmix.h
deleted file mode 100644
index 9435eab1b7f5..000000000000
--- a/drivers/staging/ath6kl/include/common/wmix.h
+++ /dev/null
@@ -1,271 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="wmix.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-
-/*
- * This file contains extensions of the WMI protocol specified in the
- * Wireless Module Interface (WMI). It includes definitions of all
- * extended commands and events. Extensions include useful commands
- * that are not directly related to wireless activities. They may
- * be hardware-specific, and they might not be supported on all
- * implementations.
- *
- * Extended WMIX commands are encapsulated in a WMI message with
- * cmd=WMI_EXTENSION_CMD.
- */
-
-#ifndef _WMIX_H_
-#define _WMIX_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "dbglog.h"
-
-/*
- * Extended WMI commands are those that are needed during wireless
- * operation, but which are not really wireless commands. This allows,
- * for instance, platform-specific commands. Extended WMI commands are
- * embedded in a WMI command message with WMI_COMMAND_ID=WMI_EXTENSION_CMDID.
- * Extended WMI events are similarly embedded in a WMI event message with
- * WMI_EVENT_ID=WMI_EXTENSION_EVENTID.
- */
-typedef PREPACK struct {
- u32 commandId;
-} POSTPACK WMIX_CMD_HDR;
-
-typedef enum {
- WMIX_DSETOPEN_REPLY_CMDID = 0x2001,
- WMIX_DSETDATA_REPLY_CMDID,
- WMIX_GPIO_OUTPUT_SET_CMDID,
- WMIX_GPIO_INPUT_GET_CMDID,
- WMIX_GPIO_REGISTER_SET_CMDID,
- WMIX_GPIO_REGISTER_GET_CMDID,
- WMIX_GPIO_INTR_ACK_CMDID,
- WMIX_HB_CHALLENGE_RESP_CMDID,
- WMIX_DBGLOG_CFG_MODULE_CMDID,
- WMIX_PROF_CFG_CMDID, /* 0x200a */
- WMIX_PROF_ADDR_SET_CMDID,
- WMIX_PROF_START_CMDID,
- WMIX_PROF_STOP_CMDID,
- WMIX_PROF_COUNT_GET_CMDID,
-} WMIX_COMMAND_ID;
-
-typedef enum {
- WMIX_DSETOPENREQ_EVENTID = 0x3001,
- WMIX_DSETCLOSE_EVENTID,
- WMIX_DSETDATAREQ_EVENTID,
- WMIX_GPIO_INTR_EVENTID,
- WMIX_GPIO_DATA_EVENTID,
- WMIX_GPIO_ACK_EVENTID,
- WMIX_HB_CHALLENGE_RESP_EVENTID,
- WMIX_DBGLOG_EVENTID,
- WMIX_PROF_COUNT_EVENTID,
-} WMIX_EVENT_ID;
-
-/*
- * =============DataSet support=================
- */
-
-/*
- * WMIX_DSETOPENREQ_EVENTID
- * DataSet Open Request Event
- */
-typedef PREPACK struct {
- u32 dset_id;
- u32 targ_dset_handle; /* echo'ed, not used by Host, */
- u32 targ_reply_fn; /* echo'ed, not used by Host, */
- u32 targ_reply_arg; /* echo'ed, not used by Host, */
-} POSTPACK WMIX_DSETOPENREQ_EVENT;
-
-/*
- * WMIX_DSETCLOSE_EVENTID
- * DataSet Close Event
- */
-typedef PREPACK struct {
- u32 access_cookie;
-} POSTPACK WMIX_DSETCLOSE_EVENT;
-
-/*
- * WMIX_DSETDATAREQ_EVENTID
- * DataSet Data Request Event
- */
-typedef PREPACK struct {
- u32 access_cookie;
- u32 offset;
- u32 length;
- u32 targ_buf; /* echo'ed, not used by Host, */
- u32 targ_reply_fn; /* echo'ed, not used by Host, */
- u32 targ_reply_arg; /* echo'ed, not used by Host, */
-} POSTPACK WMIX_DSETDATAREQ_EVENT;
-
-typedef PREPACK struct {
- u32 status;
- u32 targ_dset_handle;
- u32 targ_reply_fn;
- u32 targ_reply_arg;
- u32 access_cookie;
- u32 size;
- u32 version;
-} POSTPACK WMIX_DSETOPEN_REPLY_CMD;
-
-typedef PREPACK struct {
- u32 status;
- u32 targ_buf;
- u32 targ_reply_fn;
- u32 targ_reply_arg;
- u32 length;
- u8 buf[1];
-} POSTPACK WMIX_DSETDATA_REPLY_CMD;
-
-
-/*
- * =============GPIO support=================
- * All masks are 18-bit masks with bit N operating on GPIO pin N.
- */
-
-
-/*
- * Set GPIO pin output state.
- * In order for output to be driven, a pin must be enabled for output.
- * This can be done during initialization through the GPIO Configuration
- * DataSet, or during operation with the enable_mask.
- *
- * If a request is made to simultaneously set/clear or set/disable or
- * clear/disable or disable/enable, results are undefined.
- */
-typedef PREPACK struct {
- u32 set_mask; /* pins to set */
- u32 clear_mask; /* pins to clear */
- u32 enable_mask; /* pins to enable for output */
- u32 disable_mask; /* pins to disable/tristate */
-} POSTPACK WMIX_GPIO_OUTPUT_SET_CMD;
-
-/*
- * Set a GPIO register. For debug/exceptional cases.
- * Values for gpioreg_id are GPIO_REGISTER_IDs, defined in a
- * platform-dependent header.
- */
-typedef PREPACK struct {
- u32 gpioreg_id; /* GPIO register ID */
- u32 value; /* value to write */
-} POSTPACK WMIX_GPIO_REGISTER_SET_CMD;
-
-/* Get a GPIO register. For debug/exceptional cases. */
-typedef PREPACK struct {
- u32 gpioreg_id; /* GPIO register to read */
-} POSTPACK WMIX_GPIO_REGISTER_GET_CMD;
-
-/*
- * Host acknowledges and re-arms GPIO interrupts. A single
- * message should be used to acknowledge all interrupts that
- * were delivered in an earlier WMIX_GPIO_INTR_EVENT message.
- */
-typedef PREPACK struct {
- u32 ack_mask; /* interrupts to acknowledge */
-} POSTPACK WMIX_GPIO_INTR_ACK_CMD;
-
-/*
- * Target informs Host of GPIO interrupts that have occurred since the
- * last WMIX_GIPO_INTR_ACK_CMD was received. Additional information --
- * the current GPIO input values is provided -- in order to support
- * use of a GPIO interrupt as a Data Valid signal for other GPIO pins.
- */
-typedef PREPACK struct {
- u32 intr_mask; /* pending GPIO interrupts */
- u32 input_values; /* recent GPIO input values */
-} POSTPACK WMIX_GPIO_INTR_EVENT;
-
-/*
- * Target responds to Host's earlier WMIX_GPIO_INPUT_GET_CMDID request
- * using a GPIO_DATA_EVENT with
- * value set to the mask of GPIO pin inputs and
- * reg_id set to GPIO_ID_NONE
- *
- *
- * Target responds to Hosts's earlier WMIX_GPIO_REGISTER_GET_CMDID request
- * using a GPIO_DATA_EVENT with
- * value set to the value of the requested register and
- * reg_id identifying the register (reflects the original request)
- * NB: reg_id supports the future possibility of unsolicited
- * WMIX_GPIO_DATA_EVENTs (for polling GPIO input), and it may
- * simplify Host GPIO support.
- */
-typedef PREPACK struct {
- u32 value;
- u32 reg_id;
-} POSTPACK WMIX_GPIO_DATA_EVENT;
-
-/*
- * =============Error Detection support=================
- */
-
-/*
- * WMIX_HB_CHALLENGE_RESP_CMDID
- * Heartbeat Challenge Response command
- */
-typedef PREPACK struct {
- u32 cookie;
- u32 source;
-} POSTPACK WMIX_HB_CHALLENGE_RESP_CMD;
-
-/*
- * WMIX_HB_CHALLENGE_RESP_EVENTID
- * Heartbeat Challenge Response Event
- */
-#define WMIX_HB_CHALLENGE_RESP_EVENT WMIX_HB_CHALLENGE_RESP_CMD
-
-typedef PREPACK struct {
- struct dbglog_config_s config;
-} POSTPACK WMIX_DBGLOG_CFG_MODULE_CMD;
-
-/*
- * =============Target Profiling support=================
- */
-
-typedef PREPACK struct {
- u32 period; /* Time (in 30.5us ticks) between samples */
- u32 nbins;
-} POSTPACK WMIX_PROF_CFG_CMD;
-
-typedef PREPACK struct {
- u32 addr;
-} POSTPACK WMIX_PROF_ADDR_SET_CMD;
-
-/*
- * Target responds to Hosts's earlier WMIX_PROF_COUNT_GET_CMDID request
- * using a WMIX_PROF_COUNT_EVENT with
- * addr set to the next address
- * count set to the corresponding count
- */
-typedef PREPACK struct {
- u32 addr;
- u32 count;
-} POSTPACK WMIX_PROF_COUNT_EVENT;
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _WMIX_H_ */
diff --git a/drivers/staging/ath6kl/include/common_drv.h b/drivers/staging/ath6kl/include/common_drv.h
deleted file mode 100644
index 34db29958bcb..000000000000
--- a/drivers/staging/ath6kl/include/common_drv.h
+++ /dev/null
@@ -1,104 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef COMMON_DRV_H_
-#define COMMON_DRV_H_
-
-#include "hif.h"
-#include "htc_packet.h"
-#include "htc_api.h"
-
-/* structure that is the state information for the default credit distribution callback
- * drivers should instantiate (zero-init as well) this structure in their driver instance
- * and pass it as a context to the HTC credit distribution functions */
-struct common_credit_state_info {
- int TotalAvailableCredits; /* total credits in the system at startup */
- int CurrentFreeCredits; /* credits available in the pool that have not been
- given out to endpoints */
- struct htc_endpoint_credit_dist *pLowestPriEpDist; /* pointer to the lowest priority endpoint dist struct */
-};
-
-struct hci_transport_callbacks {
- s32 (*setupTransport)(void *ar);
- void (*cleanupTransport)(void *ar);
-};
-
-struct hci_transport_misc_handles {
- void *netDevice;
- void *hifDevice;
- void *htcHandle;
-};
-
-/* HTC TX packet tagging definitions */
-#define AR6K_CONTROL_PKT_TAG HTC_TX_PACKET_TAG_USER_DEFINED
-#define AR6K_DATA_PKT_TAG (AR6K_CONTROL_PKT_TAG + 1)
-
-#define AR6002_VERSION_REV1 0x20000086
-#define AR6002_VERSION_REV2 0x20000188
-#define AR6003_VERSION_REV1 0x300002ba
-#define AR6003_VERSION_REV2 0x30000384
-
-#define AR6002_CUST_DATA_SIZE 112
-#define AR6003_CUST_DATA_SIZE 16
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* OS-independent APIs */
-int ar6000_setup_credit_dist(HTC_HANDLE HTCHandle, struct common_credit_state_info *pCredInfo);
-
-int ar6000_ReadRegDiag(struct hif_device *hifDevice, u32 *address, u32 *data);
-
-int ar6000_WriteRegDiag(struct hif_device *hifDevice, u32 *address, u32 *data);
-
-int ar6000_ReadDataDiag(struct hif_device *hifDevice, u32 address, u8 *data, u32 length);
-
-int ar6000_reset_device(struct hif_device *hifDevice, u32 TargetType, bool waitForCompletion, bool coldReset);
-
-void ar6000_dump_target_assert_info(struct hif_device *hifDevice, u32 TargetType);
-
-int ar6000_set_htc_params(struct hif_device *hifDevice,
- u32 TargetType,
- u32 MboxIsrYieldValue,
- u8 HtcControlBuffers);
-
-int ar6000_set_hci_bridge_flags(struct hif_device *hifDevice,
- u32 TargetType,
- u32 Flags);
-
-void ar6000_copy_cust_data_from_target(struct hif_device *hifDevice, u32 TargetType);
-
-u8 *ar6000_get_cust_data_buffer(u32 TargetType);
-
-int ar6000_setBTState(void *context, u8 *pInBuf, u32 InBufSize);
-
-int ar6000_setDevicePowerState(void *context, u8 *pInBuf, u32 InBufSize);
-
-int ar6000_setWowMode(void *context, u8 *pInBuf, u32 InBufSize);
-
-int ar6000_setHostMode(void *context, u8 *pInBuf, u32 InBufSize);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /*COMMON_DRV_H_*/
diff --git a/drivers/staging/ath6kl/include/dbglog_api.h b/drivers/staging/ath6kl/include/dbglog_api.h
deleted file mode 100644
index a53aed316e3b..000000000000
--- a/drivers/staging/ath6kl/include/dbglog_api.h
+++ /dev/null
@@ -1,52 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="dbglog_api.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// This file contains host side debug primitives.
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _DBGLOG_API_H_
-#define _DBGLOG_API_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "dbglog.h"
-
-#define DBGLOG_HOST_LOG_BUFFER_SIZE DBGLOG_LOG_BUFFER_SIZE
-
-#define DBGLOG_GET_DBGID(arg) \
- ((arg & DBGLOG_DBGID_MASK) >> DBGLOG_DBGID_OFFSET)
-
-#define DBGLOG_GET_MODULEID(arg) \
- ((arg & DBGLOG_MODULEID_MASK) >> DBGLOG_MODULEID_OFFSET)
-
-#define DBGLOG_GET_NUMARGS(arg) \
- ((arg & DBGLOG_NUM_ARGS_MASK) >> DBGLOG_NUM_ARGS_OFFSET)
-
-#define DBGLOG_GET_TIMESTAMP(arg) \
- ((arg & DBGLOG_TIMESTAMP_MASK) >> DBGLOG_TIMESTAMP_OFFSET)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _DBGLOG_API_H_ */
diff --git a/drivers/staging/ath6kl/include/dl_list.h b/drivers/staging/ath6kl/include/dl_list.h
deleted file mode 100644
index 13b1e6956c22..000000000000
--- a/drivers/staging/ath6kl/include/dl_list.h
+++ /dev/null
@@ -1,153 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="dl_list.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Double-link list definitions (adapted from Atheros SDIO stack)
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef __DL_LIST_H___
-#define __DL_LIST_H___
-
-#include "a_osapi.h"
-
-#define A_CONTAINING_STRUCT(address, struct_type, field_name)\
- ((struct_type *)((unsigned long)(address) - (unsigned long)(&((struct_type *)0)->field_name)))
-
-/* list functions */
-/* pointers for the list */
-struct dl_list {
- struct dl_list *pPrev;
- struct dl_list *pNext;
-};
-/*
- * DL_LIST_INIT , initialize doubly linked list
-*/
-#define DL_LIST_INIT(pList)\
- {(pList)->pPrev = pList; (pList)->pNext = pList;}
-
-/* faster macro to init list and add a single item */
-#define DL_LIST_INIT_AND_ADD(pList,pItem) \
-{ (pList)->pPrev = (pItem); \
- (pList)->pNext = (pItem); \
- (pItem)->pNext = (pList); \
- (pItem)->pPrev = (pList); \
-}
-
-#define DL_LIST_IS_EMPTY(pList) (((pList)->pPrev == (pList)) && ((pList)->pNext == (pList)))
-#define DL_LIST_GET_ITEM_AT_HEAD(pList) (pList)->pNext
-#define DL_LIST_GET_ITEM_AT_TAIL(pList) (pList)->pPrev
-/*
- * ITERATE_OVER_LIST pStart is the list, pTemp is a temp list member
- * NOT: do not use this function if the items in the list are deleted inside the
- * iteration loop
-*/
-#define ITERATE_OVER_LIST(pStart, pTemp) \
- for((pTemp) =(pStart)->pNext; pTemp != (pStart); (pTemp) = (pTemp)->pNext)
-
-
-/* safe iterate macro that allows the item to be removed from the list
- * the iteration continues to the next item in the list
- */
-#define ITERATE_OVER_LIST_ALLOW_REMOVE(pStart,pItem,st,offset) \
-{ \
- struct dl_list * pTemp; \
- pTemp = (pStart)->pNext; \
- while (pTemp != (pStart)) { \
- (pItem) = A_CONTAINING_STRUCT(pTemp,st,offset); \
- pTemp = pTemp->pNext; \
-
-#define ITERATE_END }}
-
-/*
- * DL_ListInsertTail - insert pAdd to the end of the list
-*/
-static INLINE struct dl_list *DL_ListInsertTail(struct dl_list *pList, struct dl_list *pAdd) {
- /* insert at tail */
- pAdd->pPrev = pList->pPrev;
- pAdd->pNext = pList;
- pList->pPrev->pNext = pAdd;
- pList->pPrev = pAdd;
- return pAdd;
-}
-
-/*
- * DL_ListInsertHead - insert pAdd into the head of the list
-*/
-static INLINE struct dl_list * DL_ListInsertHead(struct dl_list * pList, struct dl_list * pAdd) {
- /* insert at head */
- pAdd->pPrev = pList;
- pAdd->pNext = pList->pNext;
- pList->pNext->pPrev = pAdd;
- pList->pNext = pAdd;
- return pAdd;
-}
-
-#define DL_ListAdd(pList,pItem) DL_ListInsertHead((pList),(pItem))
-/*
- * DL_ListRemove - remove pDel from list
-*/
-static INLINE struct dl_list * DL_ListRemove(struct dl_list * pDel) {
- pDel->pNext->pPrev = pDel->pPrev;
- pDel->pPrev->pNext = pDel->pNext;
- /* point back to itself just to be safe, incase remove is called again */
- pDel->pNext = pDel;
- pDel->pPrev = pDel;
- return pDel;
-}
-
-/*
- * DL_ListRemoveItemFromHead - get a list item from the head
-*/
-static INLINE struct dl_list * DL_ListRemoveItemFromHead(struct dl_list * pList) {
- struct dl_list * pItem = NULL;
- if (pList->pNext != pList) {
- pItem = pList->pNext;
- /* remove the first item from head */
- DL_ListRemove(pItem);
- }
- return pItem;
-}
-
-static INLINE struct dl_list * DL_ListRemoveItemFromTail(struct dl_list * pList) {
- struct dl_list * pItem = NULL;
- if (pList->pPrev != pList) {
- pItem = pList->pPrev;
- /* remove the item from tail */
- DL_ListRemove(pItem);
- }
- return pItem;
-}
-
-/* transfer src list items to the tail of the destination list */
-static INLINE void DL_ListTransferItemsToTail(struct dl_list * pDest, struct dl_list * pSrc) {
- /* only concatenate if src is not empty */
- if (!DL_LIST_IS_EMPTY(pSrc)) {
- /* cut out circular list in src and re-attach to end of dest */
- pSrc->pPrev->pNext = pDest;
- pSrc->pNext->pPrev = pDest->pPrev;
- pDest->pPrev->pNext = pSrc->pNext;
- pDest->pPrev = pSrc->pPrev;
- /* terminate src list, it is now empty */
- pSrc->pPrev = pSrc;
- pSrc->pNext = pSrc;
- }
-}
-
-#endif /* __DL_LIST_H___ */
diff --git a/drivers/staging/ath6kl/include/dset_api.h b/drivers/staging/ath6kl/include/dset_api.h
deleted file mode 100644
index fe901ba40ec6..000000000000
--- a/drivers/staging/ath6kl/include/dset_api.h
+++ /dev/null
@@ -1,65 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="dset_api.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Host-side DataSet API.
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _DSET_API_H_
-#define _DSET_API_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-/*
- * Host-side DataSet support is optional, and is not
- * currently required for correct operation. To disable
- * Host-side DataSet support, set this to 0.
- */
-#ifndef CONFIG_HOST_DSET_SUPPORT
-#define CONFIG_HOST_DSET_SUPPORT 1
-#endif
-
-/* Called to send a DataSet Open Reply back to the Target. */
-int wmi_dset_open_reply(struct wmi_t *wmip,
- u32 status,
- u32 access_cookie,
- u32 size,
- u32 version,
- u32 targ_handle,
- u32 targ_reply_fn,
- u32 targ_reply_arg);
-
-/* Called to send a DataSet Data Reply back to the Target. */
-int wmi_dset_data_reply(struct wmi_t *wmip,
- u32 status,
- u8 *host_buf,
- u32 length,
- u32 targ_buf,
- u32 targ_reply_fn,
- u32 targ_reply_arg);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-#endif /* _DSET_API_H_ */
diff --git a/drivers/staging/ath6kl/include/hci_transport_api.h b/drivers/staging/ath6kl/include/hci_transport_api.h
deleted file mode 100644
index 5e903fad23fc..000000000000
--- a/drivers/staging/ath6kl/include/hci_transport_api.h
+++ /dev/null
@@ -1,259 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2009-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _HCI_TRANSPORT_API_H_
-#define _HCI_TRANSPORT_API_H_
-
- /* Bluetooth HCI packets are stored in HTC packet containers */
-#include "htc_packet.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-typedef void *HCI_TRANSPORT_HANDLE;
-
-typedef HTC_ENDPOINT_ID HCI_TRANSPORT_PACKET_TYPE;
-
- /* we map each HCI packet class to a static Endpoint ID */
-#define HCI_COMMAND_TYPE ENDPOINT_1
-#define HCI_EVENT_TYPE ENDPOINT_2
-#define HCI_ACL_TYPE ENDPOINT_3
-#define HCI_PACKET_INVALID ENDPOINT_MAX
-
-#define HCI_GET_PACKET_TYPE(pP) (pP)->Endpoint
-#define HCI_SET_PACKET_TYPE(pP,s) (pP)->Endpoint = (s)
-
-/* callback when an HCI packet was completely sent */
-typedef void (*HCI_TRANSPORT_SEND_PKT_COMPLETE)(void *, struct htc_packet *);
-/* callback when an HCI packet is received */
-typedef void (*HCI_TRANSPORT_RECV_PKT)(void *, struct htc_packet *);
-/* Optional receive buffer re-fill callback,
- * On some OSes (like Linux) packets are allocated from a global pool and indicated up
- * to the network stack. The driver never gets the packets back from the OS. For these OSes
- * a refill callback can be used to allocate and re-queue buffers into HTC.
- * A refill callback is used for the reception of ACL and EVENT packets. The caller must
- * set the watermark trigger point to cause a refill.
- */
-typedef void (*HCI_TRANSPORT_RECV_REFILL)(void *, HCI_TRANSPORT_PACKET_TYPE Type, int BuffersAvailable);
-/* Optional receive packet refill
- * On some systems packet buffers are an extremely limited resource. Rather than
- * queue largest-possible-sized buffers to the HCI bridge, some systems would rather
- * allocate a specific size as the packet is received. The trade off is
- * slightly more processing (callback invoked for each RX packet)
- * for the benefit of committing fewer buffer resources into the bridge.
- *
- * The callback is provided the length of the pending packet to fetch. This includes the
- * full transport header, HCI header, plus the length of payload. The callback can return a pointer to
- * the allocated HTC packet for immediate use.
- *
- * NOTE*** This callback is mutually exclusive with the the refill callback above.
- *
- * */
-typedef struct htc_packet *(*HCI_TRANSPORT_RECV_ALLOC)(void *, HCI_TRANSPORT_PACKET_TYPE Type, int Length);
-
-typedef enum _HCI_SEND_FULL_ACTION {
- HCI_SEND_FULL_KEEP = 0, /* packet that overflowed should be kept in the queue */
- HCI_SEND_FULL_DROP = 1, /* packet that overflowed should be dropped */
-} HCI_SEND_FULL_ACTION;
-
-/* callback when an HCI send queue exceeds the caller's MaxSendQueueDepth threshold,
- * the callback must return the send full action to take (either DROP or KEEP) */
-typedef HCI_SEND_FULL_ACTION (*HCI_TRANSPORT_SEND_FULL)(void *, struct htc_packet *);
-
-struct hci_transport_properties {
- int HeadRoom; /* number of bytes in front of HCI packet for header space */
- int TailRoom; /* number of bytes at the end of the HCI packet for tail space */
- int IOBlockPad; /* I/O block padding required (always a power of 2) */
-};
-
-struct hci_transport_config_info {
- int ACLRecvBufferWaterMark; /* low watermark to trigger recv refill */
- int EventRecvBufferWaterMark; /* low watermark to trigger recv refill */
- int MaxSendQueueDepth; /* max number of packets in the single send queue */
- void *pContext; /* context for all callbacks */
- void (*TransportFailure)(void *pContext, int Status); /* transport failure callback */
- int (*TransportReady)(HCI_TRANSPORT_HANDLE, struct hci_transport_properties *,void *pContext); /* transport is ready */
- void (*TransportRemoved)(void *pContext); /* transport was removed */
- /* packet processing callbacks */
- HCI_TRANSPORT_SEND_PKT_COMPLETE pHCISendComplete;
- HCI_TRANSPORT_RECV_PKT pHCIPktRecv;
- HCI_TRANSPORT_RECV_REFILL pHCIPktRecvRefill;
- HCI_TRANSPORT_RECV_ALLOC pHCIPktRecvAlloc;
- HCI_TRANSPORT_SEND_FULL pHCISendFull;
-};
-
-/* ------ Function Prototypes ------ */
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Attach to the HCI transport module
- @function name: HCI_TransportAttach
- @input: HTCHandle - HTC handle (see HTC apis)
- pInfo - initialization information
- @output:
- @return: HCI_TRANSPORT_HANDLE on success, NULL on failure
- @notes: The HTC module provides HCI transport services.
- @example:
- @see also: HCI_TransportDetach
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-HCI_TRANSPORT_HANDLE HCI_TransportAttach(void *HTCHandle, struct hci_transport_config_info *pInfo);
-
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Detach from the HCI transport module
- @function name: HCI_TransportDetach
- @input: HciTrans - HCI transport handle
- pInfo - initialization information
- @output:
- @return:
- @notes:
- @example:
- @see also:
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-void HCI_TransportDetach(HCI_TRANSPORT_HANDLE HciTrans);
-
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Add receive packets to the HCI transport
- @function name: HCI_TransportAddReceivePkts
- @input: HciTrans - HCI transport handle
- pQueue - a queue holding one or more packets
- @output:
- @return: 0 on success
- @notes: user must supply HTC packets for capturing incomming HCI packets. The caller
- must initialize each HTC packet using the SET_HTC_PACKET_INFO_RX_REFILL()
- macro. Each packet in the queue must be of the same type and length
- @example:
- @see also:
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-int HCI_TransportAddReceivePkts(HCI_TRANSPORT_HANDLE HciTrans, struct htc_packet_queue *pQueue);
-
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Send an HCI packet packet
- @function name: HCI_TransportSendPkt
- @input: HciTrans - HCI transport handle
- pPacket - packet to send
- Synchronous - send the packet synchronously (blocking)
- @output:
- @return: 0
- @notes: Caller must initialize packet using SET_HTC_PACKET_INFO_TX() and
- HCI_SET_PACKET_TYPE() macros to prepare the packet.
- If Synchronous is set to false the call is fully asynchronous. On error or completion,
- the registered send complete callback will be called.
- If Synchronous is set to true, the call will block until the packet is sent, if the
- interface cannot send the packet within a 2 second timeout, the function will return
- the failure code : A_EBUSY.
-
- Synchronous Mode should only be used at start-up to initialize the HCI device using
- custom HCI commands. It should NOT be mixed with Asynchronous operations. Mixed synchronous
- and asynchronous operation behavior is undefined.
-
- @example:
- @see also:
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-int HCI_TransportSendPkt(HCI_TRANSPORT_HANDLE HciTrans, struct htc_packet *pPacket, bool Synchronous);
-
-
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Stop HCI transport
- @function name: HCI_TransportStop
- @input: HciTrans - hci transport handle
- @output:
- @return:
- @notes: HCI transport communication will be halted. All receive and pending TX packets will
- be flushed.
- @example:
- @see also:
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-void HCI_TransportStop(HCI_TRANSPORT_HANDLE HciTrans);
-
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Start the HCI transport
- @function name: HCI_TransportStart
- @input: HciTrans - hci transport handle
- @output:
- @return: 0 on success
- @notes: HCI transport communication will begin, the caller can expect the arrival
- of HCI recv packets as soon as this call returns.
- @example:
- @see also:
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-int HCI_TransportStart(HCI_TRANSPORT_HANDLE HciTrans);
-
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Enable or Disable Asynchronous Recv
- @function name: HCI_TransportEnableDisableAsyncRecv
- @input: HciTrans - hci transport handle
- Enable - enable or disable asynchronous recv
- @output:
- @return: 0 on success
- @notes: This API must be called when HCI recv is handled synchronously
- @example:
- @see also:
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-int HCI_TransportEnableDisableAsyncRecv(HCI_TRANSPORT_HANDLE HciTrans, bool Enable);
-
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Receive an event packet from the HCI transport synchronously using polling
- @function name: HCI_TransportRecvHCIEventSync
- @input: HciTrans - hci transport handle
- pPacket - HTC packet to hold the recv data
- MaxPollMS - maximum polling duration in Milliseconds;
- @output:
- @return: 0 on success
- @notes: This API should be used only during HCI device initialization, the caller must call
- HCI_TransportEnableDisableAsyncRecv with Enable=false prior to using this API.
- This API will only capture HCI Event packets.
- @example:
- @see also: HCI_TransportEnableDisableAsyncRecv
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-int HCI_TransportRecvHCIEventSync(HCI_TRANSPORT_HANDLE HciTrans,
- struct htc_packet *pPacket,
- int MaxPollMS);
-
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Set the desired baud rate for the underlying transport layer
- @function name: HCI_TransportSetBaudRate
- @input: HciTrans - hci transport handle
- Baud - baud rate in bps
- @output:
- @return: 0 on success
- @notes: This API should be used only after HCI device initialization
- @example:
- @see also:
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-int HCI_TransportSetBaudRate(HCI_TRANSPORT_HANDLE HciTrans, u32 Baud);
-
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Enable/Disable HCI Transport Power Management
- @function name: HCI_TransportEnablePowerMgmt
- @input: HciTrans - hci transport handle
- Enable - 1 = Enable, 0 = Disable
- @output:
- @return: 0 on success
- @notes:
- @example:
- @see also:
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-int HCI_TransportEnablePowerMgmt(HCI_TRANSPORT_HANDLE HciTrans, bool Enable);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _HCI_TRANSPORT_API_H_ */
diff --git a/drivers/staging/ath6kl/include/hif.h b/drivers/staging/ath6kl/include/hif.h
deleted file mode 100644
index 24200e778c3b..000000000000
--- a/drivers/staging/ath6kl/include/hif.h
+++ /dev/null
@@ -1,456 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="hif.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// HIF specific declarations and prototypes
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _HIF_H_
-#define _HIF_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-/* Header files */
-#include "a_config.h"
-#include "athdefs.h"
-#include "a_osapi.h"
-#include "dl_list.h"
-
-
-typedef struct htc_callbacks HTC_CALLBACKS;
-struct hif_device;
-
-/*
- * direction - Direction of transfer (HIF_READ/HIF_WRITE).
- */
-#define HIF_READ 0x00000001
-#define HIF_WRITE 0x00000002
-#define HIF_DIR_MASK (HIF_READ | HIF_WRITE)
-
-/*
- * type - An interface may support different kind of read/write commands.
- * For example: SDIO supports CMD52/CMD53s. In case of MSIO it
- * translates to using different kinds of TPCs. The command type
- * is thus divided into a basic and an extended command and can
- * be specified using HIF_BASIC_IO/HIF_EXTENDED_IO.
- */
-#define HIF_BASIC_IO 0x00000004
-#define HIF_EXTENDED_IO 0x00000008
-#define HIF_TYPE_MASK (HIF_BASIC_IO | HIF_EXTENDED_IO)
-
-/*
- * emode - This indicates the whether the command is to be executed in a
- * blocking or non-blocking fashion (HIF_SYNCHRONOUS/
- * HIF_ASYNCHRONOUS). The read/write data paths in HTC have been
- * implemented using the asynchronous mode allowing the the bus
- * driver to indicate the completion of operation through the
- * registered callback routine. The requirement primarily comes
- * from the contexts these operations get called from (a driver's
- * transmit context or the ISR context in case of receive).
- * Support for both of these modes is essential.
- */
-#define HIF_SYNCHRONOUS 0x00000010
-#define HIF_ASYNCHRONOUS 0x00000020
-#define HIF_EMODE_MASK (HIF_SYNCHRONOUS | HIF_ASYNCHRONOUS)
-
-/*
- * dmode - An interface may support different kinds of commands based on
- * the tradeoff between the amount of data it can carry and the
- * setup time. Byte and Block modes are supported (HIF_BYTE_BASIS/
- * HIF_BLOCK_BASIS). In case of latter, the data is rounded off
- * to the nearest block size by padding. The size of the block is
- * configurable at compile time using the HIF_BLOCK_SIZE and is
- * negotiated with the target during initialization after the
- * AR6000 interrupts are enabled.
- */
-#define HIF_BYTE_BASIS 0x00000040
-#define HIF_BLOCK_BASIS 0x00000080
-#define HIF_DMODE_MASK (HIF_BYTE_BASIS | HIF_BLOCK_BASIS)
-
-/*
- * amode - This indicates if the address has to be incremented on AR6000
- * after every read/write operation (HIF?FIXED_ADDRESS/
- * HIF_INCREMENTAL_ADDRESS).
- */
-#define HIF_FIXED_ADDRESS 0x00000100
-#define HIF_INCREMENTAL_ADDRESS 0x00000200
-#define HIF_AMODE_MASK (HIF_FIXED_ADDRESS | HIF_INCREMENTAL_ADDRESS)
-
-#define HIF_WR_ASYNC_BYTE_FIX \
- (HIF_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
-#define HIF_WR_ASYNC_BYTE_INC \
- (HIF_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
-#define HIF_WR_ASYNC_BLOCK_INC \
- (HIF_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
-#define HIF_WR_SYNC_BYTE_FIX \
- (HIF_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
-#define HIF_WR_SYNC_BYTE_INC \
- (HIF_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
-#define HIF_WR_SYNC_BLOCK_INC \
- (HIF_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
-#define HIF_WR_ASYNC_BLOCK_FIX \
- (HIF_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS)
-#define HIF_WR_SYNC_BLOCK_FIX \
- (HIF_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS)
-#define HIF_RD_SYNC_BYTE_INC \
- (HIF_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
-#define HIF_RD_SYNC_BYTE_FIX \
- (HIF_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
-#define HIF_RD_ASYNC_BYTE_FIX \
- (HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
-#define HIF_RD_ASYNC_BLOCK_FIX \
- (HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS)
-#define HIF_RD_ASYNC_BYTE_INC \
- (HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
-#define HIF_RD_ASYNC_BLOCK_INC \
- (HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
-#define HIF_RD_SYNC_BLOCK_INC \
- (HIF_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
-#define HIF_RD_SYNC_BLOCK_FIX \
- (HIF_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS)
-
-typedef enum {
- HIF_DEVICE_POWER_STATE = 0,
- HIF_DEVICE_GET_MBOX_BLOCK_SIZE,
- HIF_DEVICE_GET_MBOX_ADDR,
- HIF_DEVICE_GET_PENDING_EVENTS_FUNC,
- HIF_DEVICE_GET_IRQ_PROC_MODE,
- HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC,
- HIF_DEVICE_POWER_STATE_CHANGE,
- HIF_DEVICE_GET_IRQ_YIELD_PARAMS,
- HIF_CONFIGURE_QUERY_SCATTER_REQUEST_SUPPORT,
- HIF_DEVICE_GET_OS_DEVICE,
- HIF_DEVICE_DEBUG_BUS_STATE,
-} HIF_DEVICE_CONFIG_OPCODE;
-
-/*
- * HIF CONFIGURE definitions:
- *
- * HIF_DEVICE_GET_MBOX_BLOCK_SIZE
- * input : none
- * output : array of 4 u32s
- * notes: block size is returned for each mailbox (4)
- *
- * HIF_DEVICE_GET_MBOX_ADDR
- * input : none
- * output : struct hif_device_mbox_info
- * notes:
- *
- * HIF_DEVICE_GET_PENDING_EVENTS_FUNC
- * input : none
- * output: HIF_PENDING_EVENTS_FUNC function pointer
- * notes: this is optional for the HIF layer, if the request is
- * not handled then it indicates that the upper layer can use
- * the standard device methods to get pending events (IRQs, mailbox messages etc..)
- * otherwise it can call the function pointer to check pending events.
- *
- * HIF_DEVICE_GET_IRQ_PROC_MODE
- * input : none
- * output : HIF_DEVICE_IRQ_PROCESSING_MODE (interrupt processing mode)
- * note: the hif layer interfaces with the underlying OS-specific bus driver. The HIF
- * layer can report whether IRQ processing is requires synchronous behavior or
- * can be processed using asynchronous bus requests (typically faster).
- *
- * HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC
- * input :
- * output : HIF_MASK_UNMASK_RECV_EVENT function pointer
- * notes: this is optional for the HIF layer. The HIF layer may require a special mechanism
- * to mask receive message events. The upper layer can call this pointer when it needs
- * to mask/unmask receive events (in case it runs out of buffers).
- *
- * HIF_DEVICE_POWER_STATE_CHANGE
- *
- * input : HIF_DEVICE_POWER_CHANGE_TYPE
- * output : none
- * note: this is optional for the HIF layer. The HIF layer can handle power on/off state change
- * requests in an interconnect specific way. This is highly OS and bus driver dependent.
- * The caller must guarantee that no HIF read/write requests will be made after the device
- * is powered down.
- *
- * HIF_DEVICE_GET_IRQ_YIELD_PARAMS
- *
- * input : none
- * output : struct hif_device_irq_yield_params
- * note: This query checks if the HIF layer wishes to impose a processing yield count for the DSR handler.
- * The DSR callback handler will exit after a fixed number of RX packets or events are processed.
- * This query is only made if the device reports an IRQ processing mode of HIF_DEVICE_IRQ_SYNC_ONLY.
- * The HIF implementation can ignore this command if it does not desire the DSR callback to yield.
- * The HIF layer can indicate the maximum number of IRQ processing units (RX packets) before the
- * DSR handler callback must yield and return control back to the HIF layer. When a yield limit is
- * used the DSR callback will not call HIFAckInterrupts() as it would normally do before returning.
- * The HIF implementation that requires a yield count must call HIFAckInterrupt() when it is prepared
- * to process interrupts again.
- *
- * HIF_CONFIGURE_QUERY_SCATTER_REQUEST_SUPPORT
- * input : none
- * output : struct hif_device_scatter_support_info
- * note: This query checks if the HIF layer implements the SCATTER request interface. Scatter requests
- * allows upper layers to submit mailbox I/O operations using a list of buffers. This is useful for
- * multi-message transfers that can better utilize the bus interconnect.
- *
- *
- * HIF_DEVICE_GET_OS_DEVICE
- * intput : none
- * output : struct hif_device_os_device_info;
- * note: On some operating systems, the HIF layer has a parent device object for the bus. This object
- * may be required to register certain types of logical devices.
- *
- * HIF_DEVICE_DEBUG_BUS_STATE
- * input : none
- * output : none
- * note: This configure option triggers the HIF interface to dump as much bus interface state. This
- * configuration request is optional (No-OP on some HIF implementations)
- *
- */
-
-struct hif_mbox_properties {
- u32 ExtendedAddress; /* extended address for larger writes */
- u32 ExtendedSize;
-};
-
-#define HIF_MBOX_FLAG_NO_BUNDLING (1 << 0) /* do not allow bundling over the mailbox */
-
-typedef enum _MBOX_BUF_IF_TYPE {
- MBOX_BUS_IF_SDIO = 0,
- MBOX_BUS_IF_SPI = 1,
-} MBOX_BUF_IF_TYPE;
-
-struct hif_device_mbox_info {
- u32 MboxAddresses[4]; /* must be first element for legacy HIFs that return the address in
- and ARRAY of 32-bit words */
-
- /* the following describe extended mailbox properties */
- struct hif_mbox_properties MboxProp[4];
- /* if the HIF supports the GMbox extended address region it can report it
- * here, some interfaces cannot support the GMBOX address range and not set this */
- u32 GMboxAddress;
- u32 GMboxSize;
- u32 Flags; /* flags to describe mbox behavior or usage */
- MBOX_BUF_IF_TYPE MboxBusIFType; /* mailbox bus interface type */
-};
-
-typedef enum {
- HIF_DEVICE_IRQ_SYNC_ONLY, /* for HIF implementations that require the DSR to process all
- interrupts before returning */
- HIF_DEVICE_IRQ_ASYNC_SYNC, /* for HIF implementations that allow DSR to process interrupts
- using ASYNC I/O (that is HIFAckInterrupt can be called at a
- later time */
-} HIF_DEVICE_IRQ_PROCESSING_MODE;
-
-typedef enum {
- HIF_DEVICE_POWER_UP, /* HIF layer should power up interface and/or module */
- HIF_DEVICE_POWER_DOWN, /* HIF layer should initiate bus-specific measures to minimize power */
- HIF_DEVICE_POWER_CUT /* HIF layer should initiate bus-specific AND/OR platform-specific measures
- to completely power-off the module and associated hardware (i.e. cut power supplies)
- */
-} HIF_DEVICE_POWER_CHANGE_TYPE;
-
-struct hif_device_irq_yield_params {
- int RecvPacketYieldCount; /* max number of packets to force DSR to return */
-};
-
-
-struct hif_scatter_item {
- u8 *pBuffer; /* CPU accessible address of buffer */
- int Length; /* length of transfer to/from this buffer */
- void *pCallerContexts[2]; /* space for caller to insert a context associated with this item */
-};
-
-struct hif_scatter_req;
-typedef void ( *HIF_SCATTER_COMP_CB)(struct hif_scatter_req *);
-
-typedef enum _HIF_SCATTER_METHOD {
- HIF_SCATTER_NONE = 0,
- HIF_SCATTER_DMA_REAL, /* Real SG support no restrictions */
- HIF_SCATTER_DMA_BOUNCE, /* Uses SG DMA but HIF layer uses an internal bounce buffer */
-} HIF_SCATTER_METHOD;
-
-struct hif_scatter_req {
- struct dl_list ListLink; /* link management */
- u32 Address; /* address for the read/write operation */
- u32 Request; /* request flags */
- u32 TotalLength; /* total length of entire transfer */
- u32 CallerFlags; /* caller specific flags can be stored here */
- HIF_SCATTER_COMP_CB CompletionRoutine; /* completion routine set by caller */
- int CompletionStatus; /* status of completion */
- void *Context; /* caller context for this request */
- int ValidScatterEntries; /* number of valid entries set by caller */
- HIF_SCATTER_METHOD ScatterMethod; /* scatter method handled by HIF */
- void *HIFPrivate[4]; /* HIF private area */
- u8 *pScatterBounceBuffer; /* bounce buffer for upper layers to copy to/from */
- struct hif_scatter_item ScatterList[1]; /* start of scatter list */
-};
-
-typedef struct hif_scatter_req * ( *HIF_ALLOCATE_SCATTER_REQUEST)(struct hif_device *device);
-typedef void ( *HIF_FREE_SCATTER_REQUEST)(struct hif_device *device, struct hif_scatter_req *request);
-typedef int ( *HIF_READWRITE_SCATTER)(struct hif_device *device, struct hif_scatter_req *request);
-
-struct hif_device_scatter_support_info {
- /* information returned from HIF layer */
- HIF_ALLOCATE_SCATTER_REQUEST pAllocateReqFunc;
- HIF_FREE_SCATTER_REQUEST pFreeReqFunc;
- HIF_READWRITE_SCATTER pReadWriteScatterFunc;
- int MaxScatterEntries;
- int MaxTransferSizePerScatterReq;
-};
-
-struct hif_device_os_device_info {
- void *pOSDevice;
-};
-
-#define HIF_MAX_DEVICES 1
-
-struct htc_callbacks {
- void *context; /* context to pass to the dsrhandler
- note : rwCompletionHandler is provided the context passed to HIFReadWrite */
- int (* rwCompletionHandler)(void *rwContext, int status);
- int (* dsrHandler)(void *context);
-};
-
-typedef struct osdrv_callbacks {
- void *context; /* context to pass for all callbacks except deviceRemovedHandler
- the deviceRemovedHandler is only called if the device is claimed */
- int (* deviceInsertedHandler)(void *context, void *hif_handle);
- int (* deviceRemovedHandler)(void *claimedContext, void *hif_handle);
- int (* deviceSuspendHandler)(void *context);
- int (* deviceResumeHandler)(void *context);
- int (* deviceWakeupHandler)(void *context);
- int (* devicePowerChangeHandler)(void *context, HIF_DEVICE_POWER_CHANGE_TYPE config);
-} OSDRV_CALLBACKS;
-
-#define HIF_OTHER_EVENTS (1 << 0) /* other interrupts (non-Recv) are pending, host
- needs to read the register table to figure out what */
-#define HIF_RECV_MSG_AVAIL (1 << 1) /* pending recv packet */
-
-struct hif_pending_events_info {
- u32 Events;
- u32 LookAhead;
- u32 AvailableRecvBytes;
-#ifdef THREAD_X
- u32 Polling;
- u32 INT_CAUSE_REG;
-#endif
-};
-
- /* function to get pending events , some HIF modules use special mechanisms
- * to detect packet available and other interrupts */
-typedef int ( *HIF_PENDING_EVENTS_FUNC)(struct hif_device *device,
- struct hif_pending_events_info *pEvents,
- void *AsyncContext);
-
-#define HIF_MASK_RECV true
-#define HIF_UNMASK_RECV false
- /* function to mask recv events */
-typedef int ( *HIF_MASK_UNMASK_RECV_EVENT)(struct hif_device *device,
- bool Mask,
- void *AsyncContext);
-
-
-/*
- * This API is used to perform any global initialization of the HIF layer
- * and to set OS driver callbacks (i.e. insertion/removal) to the HIF layer
- *
- */
-int HIFInit(OSDRV_CALLBACKS *callbacks);
-
-/* This API claims the HIF device and provides a context for handling removal.
- * The device removal callback is only called when the OSDRV layer claims
- * a device. The claimed context must be non-NULL */
-void HIFClaimDevice(struct hif_device *device, void *claimedContext);
-/* release the claimed device */
-void HIFReleaseDevice(struct hif_device *device);
-
-/* This API allows the HTC layer to attach to the HIF device */
-int HIFAttachHTC(struct hif_device *device, HTC_CALLBACKS *callbacks);
-/* This API detaches the HTC layer from the HIF device */
-void HIFDetachHTC(struct hif_device *device);
-
-/*
- * This API is used to provide the read/write interface over the specific bus
- * interface.
- * address - Starting address in the AR6000's address space. For mailbox
- * writes, it refers to the start of the mbox boundary. It should
- * be ensured that the last byte falls on the mailbox's EOM. For
- * mailbox reads, it refers to the end of the mbox boundary.
- * buffer - Pointer to the buffer containg the data to be transmitted or
- * received.
- * length - Amount of data to be transmitted or received.
- * request - Characterizes the attributes of the command.
- */
-int
-HIFReadWrite(struct hif_device *device,
- u32 address,
- u8 *buffer,
- u32 length,
- u32 request,
- void *context);
-
-/*
- * This can be initiated from the unload driver context when the OSDRV layer has no more use for
- * the device.
- */
-void HIFShutDownDevice(struct hif_device *device);
-
-/*
- * This should translate to an acknowledgment to the bus driver indicating that
- * the previous interrupt request has been serviced and the all the relevant
- * sources have been cleared. HTC is ready to process more interrupts.
- * This should prevent the bus driver from raising an interrupt unless the
- * previous one has been serviced and acknowledged using the previous API.
- */
-void HIFAckInterrupt(struct hif_device *device);
-
-void HIFMaskInterrupt(struct hif_device *device);
-
-void HIFUnMaskInterrupt(struct hif_device *device);
-
-#ifdef THREAD_X
-/*
- * This set of functions are to be used by the bus driver to notify
- * the HIF module about various events.
- * These are not implemented if the bus driver provides an alternative
- * way for this notification though callbacks for instance.
- */
-int HIFInsertEventNotify(void);
-
-int HIFRemoveEventNotify(void);
-
-int HIFIRQEventNotify(void);
-
-int HIFRWCompleteEventNotify(void);
-#endif
-
-int
-HIFConfigureDevice(struct hif_device *device, HIF_DEVICE_CONFIG_OPCODE opcode,
- void *config, u32 configLen);
-
-/*
- * This API wait for the remaining MBOX messages to be drained
- * This should be moved to HTC AR6K layer
- */
-int hifWaitForPendingRecv(struct hif_device *device);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _HIF_H_ */
diff --git a/drivers/staging/ath6kl/include/host_version.h b/drivers/staging/ath6kl/include/host_version.h
deleted file mode 100644
index 74f1982c681b..000000000000
--- a/drivers/staging/ath6kl/include/host_version.h
+++ /dev/null
@@ -1,52 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="host_version.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// This file contains version information for the sample host driver for the
-// AR6000 chip
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _HOST_VERSION_H_
-#define _HOST_VERSION_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <AR6002/AR6K_version.h>
-
-/*
- * The version number is made up of major, minor, patch and build
- * numbers. These are 16 bit numbers. The build and release script will
- * set the build number using a Perforce counter. Here the build number is
- * set to 9999 so that builds done without the build-release script are easily
- * identifiable.
- */
-
-#define ATH_SW_VER_MAJOR __VER_MAJOR_
-#define ATH_SW_VER_MINOR __VER_MINOR_
-#define ATH_SW_VER_PATCH __VER_PATCH_
-#define ATH_SW_VER_BUILD __BUILD_NUMBER_
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _HOST_VERSION_H_ */
diff --git a/drivers/staging/ath6kl/include/htc_api.h b/drivers/staging/ath6kl/include/htc_api.h
deleted file mode 100644
index 4fb767559f82..000000000000
--- a/drivers/staging/ath6kl/include/htc_api.h
+++ /dev/null
@@ -1,575 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="htc_api.h" company="Atheros">
-// Copyright (c) 2007-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _HTC_API_H_
-#define _HTC_API_H_
-
-#include "htc_packet.h"
-#include <htc.h>
-#include <htc_services.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-/* TODO.. for BMI */
-#define ENDPOINT1 0
-// TODO -remove me, but we have to fix BMI first
-#define HTC_MAILBOX_NUM_MAX 4
-
-/* this is the amount of header room required by users of HTC */
-#define HTC_HEADER_LEN HTC_HDR_LENGTH
-
-typedef void *HTC_HANDLE;
-
-typedef u16 HTC_SERVICE_ID;
-
-struct htc_init_info {
- void *pContext; /* context for target failure notification */
- void (*TargetFailure)(void *Instance, int Status);
-};
-
-/* per service connection send completion */
-typedef void (*HTC_EP_SEND_PKT_COMPLETE)(void *,struct htc_packet *);
-/* per service connection callback when a plurality of packets have been sent
- * The struct htc_packet_queue is a temporary queue object (e.g. freed on return from the callback)
- * to hold a list of completed send packets.
- * If the handler cannot fully traverse the packet queue before returning, it should
- * transfer the items of the queue into the caller's private queue using:
- * HTC_PACKET_ENQUEUE() */
-typedef void (*HTC_EP_SEND_PKT_COMP_MULTIPLE)(void *,struct htc_packet_queue *);
-/* per service connection pkt received */
-typedef void (*HTC_EP_RECV_PKT)(void *,struct htc_packet *);
-/* per service connection callback when a plurality of packets are received
- * The struct htc_packet_queue is a temporary queue object (e.g. freed on return from the callback)
- * to hold a list of recv packets.
- * If the handler cannot fully traverse the packet queue before returning, it should
- * transfer the items of the queue into the caller's private queue using:
- * HTC_PACKET_ENQUEUE() */
-typedef void (*HTC_EP_RECV_PKT_MULTIPLE)(void *,struct htc_packet_queue *);
-
-/* Optional per service connection receive buffer re-fill callback,
- * On some OSes (like Linux) packets are allocated from a global pool and indicated up
- * to the network stack. The driver never gets the packets back from the OS. For these OSes
- * a refill callback can be used to allocate and re-queue buffers into HTC.
- *
- * On other OSes, the network stack can call into the driver's OS-specifc "return_packet" handler and
- * the driver can re-queue these buffers into HTC. In this regard a refill callback is
- * unnecessary */
-typedef void (*HTC_EP_RECV_REFILL)(void *, HTC_ENDPOINT_ID Endpoint);
-
-/* Optional per service connection receive buffer allocation callback.
- * On some systems packet buffers are an extremely limited resource. Rather than
- * queue largest-possible-sized buffers to HTC, some systems would rather
- * allocate a specific size as the packet is received. The trade off is
- * slightly more processing (callback invoked for each RX packet)
- * for the benefit of committing fewer buffer resources into HTC.
- *
- * The callback is provided the length of the pending packet to fetch. This includes the
- * HTC header length plus the length of payload. The callback can return a pointer to
- * the allocated HTC packet for immediate use.
- *
- * Alternatively a variant of this handler can be used to allocate large receive packets as needed.
- * For example an application can use the refill mechanism for normal packets and the recv-alloc mechanism to
- * handle the case where a large packet buffer is required. This can significantly reduce the
- * amount of "committed" memory used to receive packets.
- *
- * */
-typedef struct htc_packet *(*HTC_EP_RECV_ALLOC)(void *, HTC_ENDPOINT_ID Endpoint, int Length);
-
-typedef enum _HTC_SEND_FULL_ACTION {
- HTC_SEND_FULL_KEEP = 0, /* packet that overflowed should be kept in the queue */
- HTC_SEND_FULL_DROP = 1, /* packet that overflowed should be dropped */
-} HTC_SEND_FULL_ACTION;
-
-/* Optional per service connection callback when a send queue is full. This can occur if the
- * host continues queueing up TX packets faster than credits can arrive
- * To prevent the host (on some Oses like Linux) from continuously queueing packets
- * and consuming resources, this callback is provided so that that the host
- * can disable TX in the subsystem (i.e. network stack).
- * This callback is invoked for each packet that "overflows" the HTC queue. The callback can
- * determine whether the new packet that overflowed the queue can be kept (HTC_SEND_FULL_KEEP) or
- * dropped (HTC_SEND_FULL_DROP). If a packet is dropped, the EpTxComplete handler will be called
- * and the packet's status field will be set to A_NO_RESOURCE.
- * Other OSes require a "per-packet" indication for each completed TX packet, this
- * closed loop mechanism will prevent the network stack from overunning the NIC
- * The packet to keep or drop is passed for inspection to the registered handler the handler
- * must ONLY inspect the packet, it may not free or reclaim the packet. */
-typedef HTC_SEND_FULL_ACTION (*HTC_EP_SEND_QUEUE_FULL)(void *, struct htc_packet *pPacket);
-
-struct htc_ep_callbacks {
- void *pContext; /* context for each callback */
- HTC_EP_SEND_PKT_COMPLETE EpTxComplete; /* tx completion callback for connected endpoint */
- HTC_EP_RECV_PKT EpRecv; /* receive callback for connected endpoint */
- HTC_EP_RECV_REFILL EpRecvRefill; /* OPTIONAL receive re-fill callback for connected endpoint */
- HTC_EP_SEND_QUEUE_FULL EpSendFull; /* OPTIONAL send full callback */
- HTC_EP_RECV_ALLOC EpRecvAlloc; /* OPTIONAL recv allocation callback */
- HTC_EP_RECV_ALLOC EpRecvAllocThresh; /* OPTIONAL recv allocation callback based on a threshold */
- HTC_EP_SEND_PKT_COMP_MULTIPLE EpTxCompleteMultiple; /* OPTIONAL completion handler for multiple complete
- indications (EpTxComplete must be NULL) */
- HTC_EP_RECV_PKT_MULTIPLE EpRecvPktMultiple; /* OPTIONAL completion handler for multiple
- recv packet indications (EpRecv must be NULL) */
- int RecvAllocThreshold; /* if EpRecvAllocThresh is non-NULL, HTC will compare the
- threshold value to the current recv packet length and invoke
- the EpRecvAllocThresh callback to acquire a packet buffer */
- int RecvRefillWaterMark; /* if a EpRecvRefill handler is provided, this value
- can be used to set a trigger refill callback
- when the recv queue drops below this value
- if set to 0, the refill is only called when packets
- are empty */
-};
-
-/* service connection information */
-struct htc_service_connect_req {
- HTC_SERVICE_ID ServiceID; /* service ID to connect to */
- u16 ConnectionFlags; /* connection flags, see htc protocol definition */
- u8 *pMetaData; /* ptr to optional service-specific meta-data */
- u8 MetaDataLength; /* optional meta data length */
- struct htc_ep_callbacks EpCallbacks; /* endpoint callbacks */
- int MaxSendQueueDepth; /* maximum depth of any send queue */
- u32 LocalConnectionFlags; /* HTC flags for the host-side (local) connection */
- unsigned int MaxSendMsgSize; /* override max message size in send direction */
-};
-
-#define HTC_LOCAL_CONN_FLAGS_ENABLE_SEND_BUNDLE_PADDING (1 << 0) /* enable send bundle padding for this endpoint */
-
-/* service connection response information */
-struct htc_service_connect_resp {
- u8 *pMetaData; /* caller supplied buffer to optional meta-data */
- u8 BufferLength; /* length of caller supplied buffer */
- u8 ActualLength; /* actual length of meta data */
- HTC_ENDPOINT_ID Endpoint; /* endpoint to communicate over */
- unsigned int MaxMsgLength; /* max length of all messages over this endpoint */
- u8 ConnectRespCode; /* connect response code from target */
-};
-
-/* endpoint distribution structure */
-struct htc_endpoint_credit_dist {
- struct htc_endpoint_credit_dist *pNext;
- struct htc_endpoint_credit_dist *pPrev;
- HTC_SERVICE_ID ServiceID; /* Service ID (set by HTC) */
- HTC_ENDPOINT_ID Endpoint; /* endpoint for this distribution struct (set by HTC) */
- u32 DistFlags; /* distribution flags, distribution function can
- set default activity using SET_EP_ACTIVE() macro */
- int TxCreditsNorm; /* credits for normal operation, anything above this
- indicates the endpoint is over-subscribed, this field
- is only relevant to the credit distribution function */
- int TxCreditsMin; /* floor for credit distribution, this field is
- only relevant to the credit distribution function */
- int TxCreditsAssigned; /* number of credits assigned to this EP, this field
- is only relevant to the credit dist function */
- int TxCredits; /* current credits available, this field is used by
- HTC to determine whether a message can be sent or
- must be queued */
- int TxCreditsToDist; /* pending credits to distribute on this endpoint, this
- is set by HTC when credit reports arrive.
- The credit distribution functions sets this to zero
- when it distributes the credits */
- int TxCreditsSeek; /* this is the number of credits that the current pending TX
- packet needs to transmit. This is set by HTC when
- and endpoint needs credits in order to transmit */
- int TxCreditSize; /* size in bytes of each credit (set by HTC) */
- int TxCreditsPerMaxMsg; /* credits required for a maximum sized messages (set by HTC) */
- void *pHTCReserved; /* reserved for HTC use */
- int TxQueueDepth; /* current depth of TX queue , i.e. messages waiting for credits
- This field is valid only when HTC_CREDIT_DIST_ACTIVITY_CHANGE
- or HTC_CREDIT_DIST_SEND_COMPLETE is indicated on an endpoint
- that has non-zero credits to recover
- */
-};
-
-#define HTC_EP_ACTIVE ((u32) (1u << 31))
-
-/* macro to check if an endpoint has gone active, useful for credit
- * distributions */
-#define IS_EP_ACTIVE(epDist) ((epDist)->DistFlags & HTC_EP_ACTIVE)
-#define SET_EP_ACTIVE(epDist) (epDist)->DistFlags |= HTC_EP_ACTIVE
-
- /* credit distibution code that is passed into the distrbution function,
- * there are mandatory and optional codes that must be handled */
-typedef enum _HTC_CREDIT_DIST_REASON {
- HTC_CREDIT_DIST_SEND_COMPLETE = 0, /* credits available as a result of completed
- send operations (MANDATORY) resulting in credit reports */
- HTC_CREDIT_DIST_ACTIVITY_CHANGE = 1, /* a change in endpoint activity occurred (OPTIONAL) */
- HTC_CREDIT_DIST_SEEK_CREDITS, /* an endpoint needs to "seek" credits (OPTIONAL) */
- HTC_DUMP_CREDIT_STATE /* for debugging, dump any state information that is kept by
- the distribution function */
-} HTC_CREDIT_DIST_REASON;
-
-typedef void (*HTC_CREDIT_DIST_CALLBACK)(void *Context,
- struct htc_endpoint_credit_dist *pEPList,
- HTC_CREDIT_DIST_REASON Reason);
-
-typedef void (*HTC_CREDIT_INIT_CALLBACK)(void *Context,
- struct htc_endpoint_credit_dist *pEPList,
- int TotalCredits);
-
- /* endpoint statistics action */
-typedef enum _HTC_ENDPOINT_STAT_ACTION {
- HTC_EP_STAT_SAMPLE = 0, /* only read statistics */
- HTC_EP_STAT_SAMPLE_AND_CLEAR = 1, /* sample and immediately clear statistics */
- HTC_EP_STAT_CLEAR /* clear only */
-} HTC_ENDPOINT_STAT_ACTION;
-
- /* endpoint statistics */
-struct htc_endpoint_stats {
- u32 TxCreditLowIndications; /* number of times the host set the credit-low flag in a send message on
- this endpoint */
- u32 TxIssued; /* running count of total TX packets issued */
- u32 TxPacketsBundled; /* running count of TX packets that were issued in bundles */
- u32 TxBundles; /* running count of TX bundles that were issued */
- u32 TxDropped; /* tx packets that were dropped */
- u32 TxCreditRpts; /* running count of total credit reports received for this endpoint */
- u32 TxCreditRptsFromRx; /* credit reports received from this endpoint's RX packets */
- u32 TxCreditRptsFromOther; /* credit reports received from RX packets of other endpoints */
- u32 TxCreditRptsFromEp0; /* credit reports received from endpoint 0 RX packets */
- u32 TxCreditsFromRx; /* count of credits received via Rx packets on this endpoint */
- u32 TxCreditsFromOther; /* count of credits received via another endpoint */
- u32 TxCreditsFromEp0; /* count of credits received via another endpoint */
- u32 TxCreditsConsummed; /* count of consummed credits */
- u32 TxCreditsReturned; /* count of credits returned */
- u32 RxReceived; /* count of RX packets received */
- u32 RxLookAheads; /* count of lookahead records
- found in messages received on this endpoint */
- u32 RxPacketsBundled; /* count of recv packets received in a bundle */
- u32 RxBundleLookAheads; /* count of number of bundled lookaheads */
- u32 RxBundleIndFromHdr; /* count of the number of bundle indications from the HTC header */
- u32 RxAllocThreshHit; /* count of the number of times the recv allocation threshold was hit */
- u32 RxAllocThreshBytes; /* total number of bytes */
-};
-
-/* ------ Function Prototypes ------ */
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Create an instance of HTC over the underlying HIF device
- @function name: HTCCreate
- @input: HifDevice - hif device handle,
- pInfo - initialization information
- @output:
- @return: HTC_HANDLE on success, NULL on failure
- @notes:
- @example:
- @see also: HTCDestroy
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-HTC_HANDLE HTCCreate(void *HifDevice, struct htc_init_info *pInfo);
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Get the underlying HIF device handle
- @function name: HTCGetHifDevice
- @input: HTCHandle - handle passed into the AddInstance callback
- @output:
- @return: opaque HIF device handle usable in HIF API calls.
- @notes:
- @example:
- @see also:
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-void *HTCGetHifDevice(HTC_HANDLE HTCHandle);
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Set credit distribution parameters
- @function name: HTCSetCreditDistribution
- @input: HTCHandle - HTC handle
- pCreditDistCont - caller supplied context to pass into distribution functions
- CreditDistFunc - Distribution function callback
- CreditDistInit - Credit Distribution initialization callback
- ServicePriorityOrder - Array containing list of service IDs, lowest index is highest
- priority
- ListLength - number of elements in ServicePriorityOrder
- @output:
- @return:
- @notes: The user can set a custom credit distribution function to handle special requirements
- for each endpoint. A default credit distribution routine can be used by setting
- CreditInitFunc to NULL. The default credit distribution is only provided for simple
- "fair" credit distribution without regard to any prioritization.
-
- @example:
- @see also:
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-void HTCSetCreditDistribution(HTC_HANDLE HTCHandle,
- void *pCreditDistContext,
- HTC_CREDIT_DIST_CALLBACK CreditDistFunc,
- HTC_CREDIT_INIT_CALLBACK CreditInitFunc,
- HTC_SERVICE_ID ServicePriorityOrder[],
- int ListLength);
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Wait for the target to indicate the HTC layer is ready
- @function name: HTCWaitTarget
- @input: HTCHandle - HTC handle
- @output:
- @return:
- @notes: This API blocks until the target responds with an HTC ready message.
- The caller should not connect services until the target has indicated it is
- ready.
- @example:
- @see also: HTCConnectService
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-int HTCWaitTarget(HTC_HANDLE HTCHandle);
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Start target service communications
- @function name: HTCStart
- @input: HTCHandle - HTC handle
- @output:
- @return:
- @notes: This API indicates to the target that the service connection phase is complete
- and the target can freely start all connected services. This API should only be
- called AFTER all service connections have been made. TCStart will issue a
- SETUP_COMPLETE message to the target to indicate that all service connections
- have been made and the target can start communicating over the endpoints.
- @example:
- @see also: HTCConnectService
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-int HTCStart(HTC_HANDLE HTCHandle);
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Add receive packet to HTC
- @function name: HTCAddReceivePkt
- @input: HTCHandle - HTC handle
- pPacket - HTC receive packet to add
- @output:
- @return: 0 on success
- @notes: user must supply HTC packets for capturing incomming HTC frames. The caller
- must initialize each HTC packet using the SET_HTC_PACKET_INFO_RX_REFILL()
- macro.
- @example:
- @see also:
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-int HTCAddReceivePkt(HTC_HANDLE HTCHandle, struct htc_packet *pPacket);
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Connect to an HTC service
- @function name: HTCConnectService
- @input: HTCHandle - HTC handle
- pReq - connection details
- @output: pResp - connection response
- @return:
- @notes: Service connections must be performed before HTCStart. User provides callback handlers
- for various endpoint events.
- @example:
- @see also: HTCStart
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-int HTCConnectService(HTC_HANDLE HTCHandle,
- struct htc_service_connect_req *pReq,
- struct htc_service_connect_resp *pResp);
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Send an HTC packet
- @function name: HTCSendPkt
- @input: HTCHandle - HTC handle
- pPacket - packet to send
- @output:
- @return: 0
- @notes: Caller must initialize packet using SET_HTC_PACKET_INFO_TX() macro.
- This interface is fully asynchronous. On error, HTC SendPkt will
- call the registered Endpoint callback to cleanup the packet.
- @example:
- @see also: HTCFlushEndpoint
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-int HTCSendPkt(HTC_HANDLE HTCHandle, struct htc_packet *pPacket);
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Stop HTC service communications
- @function name: HTCStop
- @input: HTCHandle - HTC handle
- @output:
- @return:
- @notes: HTC communications is halted. All receive and pending TX packets will
- be flushed.
- @example:
- @see also:
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-void HTCStop(HTC_HANDLE HTCHandle);
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Destroy HTC service
- @function name: HTCDestroy
- @input: HTCHandle
- @output:
- @return:
- @notes: This cleans up all resources allocated by HTCCreate().
- @example:
- @see also: HTCCreate
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-void HTCDestroy(HTC_HANDLE HTCHandle);
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Flush pending TX packets
- @function name: HTCFlushEndpoint
- @input: HTCHandle - HTC handle
- Endpoint - Endpoint to flush
- Tag - flush tag
- @output:
- @return:
- @notes: The Tag parameter is used to selectively flush packets with matching tags.
- The value of 0 forces all packets to be flush regardless of tag.
- @example:
- @see also: HTCSendPkt
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-void HTCFlushEndpoint(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint, HTC_TX_TAG Tag);
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Dump credit distribution state
- @function name: HTCDumpCreditStates
- @input: HTCHandle - HTC handle
- @output:
- @return:
- @notes: This dumps all credit distribution information to the debugger
- @example:
- @see also:
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-void HTCDumpCreditStates(HTC_HANDLE HTCHandle);
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Indicate a traffic activity change on an endpoint
- @function name: HTCIndicateActivityChange
- @input: HTCHandle - HTC handle
- Endpoint - endpoint in which activity has changed
- Active - true if active, false if it has become inactive
- @output:
- @return:
- @notes: This triggers the registered credit distribution function to
- re-adjust credits for active/inactive endpoints.
- @example:
- @see also:
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-void HTCIndicateActivityChange(HTC_HANDLE HTCHandle,
- HTC_ENDPOINT_ID Endpoint,
- bool Active);
-
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Get endpoint statistics
- @function name: HTCGetEndpointStatistics
- @input: HTCHandle - HTC handle
- Endpoint - Endpoint identifier
- Action - action to take with statistics
- @output:
- pStats - statistics that were sampled (can be NULL if Action is HTC_EP_STAT_CLEAR)
-
- @return: true if statistics profiling is enabled, otherwise false.
-
- @notes: Statistics is a compile-time option and this function may return false
- if HTC is not compiled with profiling.
-
- The caller can specify the statistic "action" to take when sampling
- the statistics. This includes:
-
- HTC_EP_STAT_SAMPLE: The pStats structure is filled with the current values.
- HTC_EP_STAT_SAMPLE_AND_CLEAR: The structure is filled and the current statistics
- are cleared.
- HTC_EP_STAT_CLEA : the statistics are cleared, the called can pass a NULL value for
- pStats
-
- @example:
- @see also:
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-bool HTCGetEndpointStatistics(HTC_HANDLE HTCHandle,
- HTC_ENDPOINT_ID Endpoint,
- HTC_ENDPOINT_STAT_ACTION Action,
- struct htc_endpoint_stats *pStats);
-
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Unblock HTC message reception
- @function name: HTCUnblockRecv
- @input: HTCHandle - HTC handle
- @output:
- @return:
- @notes:
- HTC will block the receiver if the EpRecvAlloc callback fails to provide a packet.
- The caller can use this API to indicate to HTC when resources (buffers) are available
- such that the receiver can be unblocked and HTC may re-attempt fetching the pending message.
-
- This API is not required if the user uses the EpRecvRefill callback or uses the HTCAddReceivePacket()
- API to recycle or provide receive packets to HTC.
-
- @example:
- @see also:
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-void HTCUnblockRecv(HTC_HANDLE HTCHandle);
-
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: send a series of HTC packets
- @function name: HTCSendPktsMultiple
- @input: HTCHandle - HTC handle
- pPktQueue - local queue holding packets to send
- @output:
- @return: 0
- @notes: Caller must initialize each packet using SET_HTC_PACKET_INFO_TX() macro.
- The queue must only contain packets directed at the same endpoint.
- Caller supplies a pointer to an struct htc_packet_queue structure holding the TX packets in FIFO order.
- This API will remove the packets from the pkt queue and place them into the HTC Tx Queue
- and bundle messages where possible.
- The caller may allocate the pkt queue on the stack to hold the packets.
- This interface is fully asynchronous. On error, HTCSendPkts will
- call the registered Endpoint callback to cleanup the packet.
- @example:
- @see also: HTCFlushEndpoint
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-int HTCSendPktsMultiple(HTC_HANDLE HTCHandle, struct htc_packet_queue *pPktQueue);
-
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Add multiple receive packets to HTC
- @function name: HTCAddReceivePktMultiple
- @input: HTCHandle - HTC handle
- pPktQueue - HTC receive packet queue holding packets to add
- @output:
- @return: 0 on success
- @notes: user must supply HTC packets for capturing incomming HTC frames. The caller
- must initialize each HTC packet using the SET_HTC_PACKET_INFO_RX_REFILL()
- macro. The queue must only contain recv packets for the same endpoint.
- Caller supplies a pointer to an struct htc_packet_queue structure holding the recv packet.
- This API will remove the packets from the pkt queue and place them into internal
- recv packet list.
- The caller may allocate the pkt queue on the stack to hold the packets.
- @example:
- @see also:
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-int HTCAddReceivePktMultiple(HTC_HANDLE HTCHandle, struct htc_packet_queue *pPktQueue);
-
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Check if an endpoint is marked active
- @function name: HTCIsEndpointActive
- @input: HTCHandle - HTC handle
- Endpoint - endpoint to check for active state
- @output:
- @return: returns true if Endpoint is Active
- @notes:
- @example:
- @see also:
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-bool HTCIsEndpointActive(HTC_HANDLE HTCHandle,
- HTC_ENDPOINT_ID Endpoint);
-
-
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @desc: Get the number of recv buffers currently queued into an HTC endpoint
- @function name: HTCGetNumRecvBuffers
- @input: HTCHandle - HTC handle
- Endpoint - endpoint to check
- @output:
- @return: returns number of buffers in queue
- @notes:
- @example:
- @see also:
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
-int HTCGetNumRecvBuffers(HTC_HANDLE HTCHandle,
- HTC_ENDPOINT_ID Endpoint);
-
-/* internally used functions for testing... */
-void HTCEnableRecv(HTC_HANDLE HTCHandle);
-void HTCDisableRecv(HTC_HANDLE HTCHandle);
-int HTCWaitForPendingRecv(HTC_HANDLE HTCHandle,
- u32 TimeoutInMs,
- bool *pbIsRecvPending);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _HTC_API_H_ */
diff --git a/drivers/staging/ath6kl/include/htc_packet.h b/drivers/staging/ath6kl/include/htc_packet.h
deleted file mode 100644
index ba65c34ebc9c..000000000000
--- a/drivers/staging/ath6kl/include/htc_packet.h
+++ /dev/null
@@ -1,227 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="htc_packet.h" company="Atheros">
-// Copyright (c) 2007-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef HTC_PACKET_H_
-#define HTC_PACKET_H_
-
-
-#include "dl_list.h"
-
-/* ------ Endpoint IDS ------ */
-typedef enum
-{
- ENDPOINT_UNUSED = -1,
- ENDPOINT_0 = 0,
- ENDPOINT_1 = 1,
- ENDPOINT_2 = 2,
- ENDPOINT_3,
- ENDPOINT_4,
- ENDPOINT_5,
- ENDPOINT_6,
- ENDPOINT_7,
- ENDPOINT_8,
- ENDPOINT_MAX,
-} HTC_ENDPOINT_ID;
-
-struct htc_packet;
-
-typedef void (* HTC_PACKET_COMPLETION)(void *,struct htc_packet *);
-
-typedef u16 HTC_TX_TAG;
-
-struct htc_tx_packet_info {
- HTC_TX_TAG Tag; /* tag used to selective flush packets */
- int CreditsUsed; /* number of credits used for this TX packet (HTC internal) */
- u8 SendFlags; /* send flags (HTC internal) */
- int SeqNo; /* internal seq no for debugging (HTC internal) */
-};
-
-#define HTC_TX_PACKET_TAG_ALL 0 /* a tag of zero is reserved and used to flush ALL packets */
-#define HTC_TX_PACKET_TAG_INTERNAL 1 /* internal tags start here */
-#define HTC_TX_PACKET_TAG_USER_DEFINED (HTC_TX_PACKET_TAG_INTERNAL + 9) /* user-defined tags start here */
-
-struct htc_rx_packet_info {
- u32 ExpectedHdr; /* HTC internal use */
- u32 HTCRxFlags; /* HTC internal use */
- u32 IndicationFlags; /* indication flags set on each RX packet indication */
-};
-
-#define HTC_RX_FLAGS_INDICATE_MORE_PKTS (1 << 0) /* more packets on this endpoint are being fetched */
-
-/* wrapper around endpoint-specific packets */
-struct htc_packet {
- struct dl_list ListLink; /* double link */
- void *pPktContext; /* caller's per packet specific context */
-
- u8 *pBufferStart; /* the true buffer start , the caller can
- store the real buffer start here. In
- receive callbacks, the HTC layer sets pBuffer
- to the start of the payload past the header. This
- field allows the caller to reset pBuffer when it
- recycles receive packets back to HTC */
- /*
- * Pointer to the start of the buffer. In the transmit
- * direction this points to the start of the payload. In the
- * receive direction, however, the buffer when queued up
- * points to the start of the HTC header but when returned
- * to the caller points to the start of the payload
- */
- u8 *pBuffer; /* payload start (RX/TX) */
- u32 BufferLength; /* length of buffer */
- u32 ActualLength; /* actual length of payload */
- HTC_ENDPOINT_ID Endpoint; /* endpoint that this packet was sent/recv'd from */
- int Status; /* completion status */
- union {
- struct htc_tx_packet_info AsTx; /* Tx Packet specific info */
- struct htc_rx_packet_info AsRx; /* Rx Packet specific info */
- } PktInfo;
-
- /* the following fields are for internal HTC use */
- HTC_PACKET_COMPLETION Completion; /* completion */
- void *pContext; /* HTC private completion context */
-};
-
-
-
-#define COMPLETE_HTC_PACKET(p,status) \
-{ \
- (p)->Status = (status); \
- (p)->Completion((p)->pContext,(p)); \
-}
-
-#define INIT_HTC_PACKET_INFO(p,b,len) \
-{ \
- (p)->pBufferStart = (b); \
- (p)->BufferLength = (len); \
-}
-
-/* macro to set an initial RX packet for refilling HTC */
-#define SET_HTC_PACKET_INFO_RX_REFILL(p,c,b,len,ep) \
-{ \
- (p)->pPktContext = (c); \
- (p)->pBuffer = (b); \
- (p)->pBufferStart = (b); \
- (p)->BufferLength = (len); \
- (p)->Endpoint = (ep); \
-}
-
-/* fast macro to recycle an RX packet that will be re-queued to HTC */
-#define HTC_PACKET_RESET_RX(p) \
- { (p)->pBuffer = (p)->pBufferStart; (p)->ActualLength = 0; }
-
-/* macro to set packet parameters for TX */
-#define SET_HTC_PACKET_INFO_TX(p,c,b,len,ep,tag) \
-{ \
- (p)->pPktContext = (c); \
- (p)->pBuffer = (b); \
- (p)->ActualLength = (len); \
- (p)->Endpoint = (ep); \
- (p)->PktInfo.AsTx.Tag = (tag); \
-}
-
-/* HTC Packet Queueing Macros */
-struct htc_packet_queue {
- struct dl_list QueueHead;
- int Depth;
-};
-
-/* initialize queue */
-#define INIT_HTC_PACKET_QUEUE(pQ) \
-{ \
- DL_LIST_INIT(&(pQ)->QueueHead); \
- (pQ)->Depth = 0; \
-}
-
-/* enqueue HTC packet to the tail of the queue */
-#define HTC_PACKET_ENQUEUE(pQ,p) \
-{ DL_ListInsertTail(&(pQ)->QueueHead,&(p)->ListLink); \
- (pQ)->Depth++; \
-}
-
-/* enqueue HTC packet to the tail of the queue */
-#define HTC_PACKET_ENQUEUE_TO_HEAD(pQ,p) \
-{ DL_ListInsertHead(&(pQ)->QueueHead,&(p)->ListLink); \
- (pQ)->Depth++; \
-}
-/* test if a queue is empty */
-#define HTC_QUEUE_EMPTY(pQ) ((pQ)->Depth == 0)
-/* get packet at head without removing it */
-static INLINE struct htc_packet *HTC_GET_PKT_AT_HEAD(struct htc_packet_queue *queue) {
- if (queue->Depth == 0) {
- return NULL;
- }
- return A_CONTAINING_STRUCT((DL_LIST_GET_ITEM_AT_HEAD(&queue->QueueHead)),struct htc_packet,ListLink);
-}
-/* remove a packet from a queue, where-ever it is in the queue */
-#define HTC_PACKET_REMOVE(pQ,p) \
-{ \
- DL_ListRemove(&(p)->ListLink); \
- (pQ)->Depth--; \
-}
-
-/* dequeue an HTC packet from the head of the queue */
-static INLINE struct htc_packet *HTC_PACKET_DEQUEUE(struct htc_packet_queue *queue) {
- struct dl_list *pItem = DL_ListRemoveItemFromHead(&queue->QueueHead);
- if (pItem != NULL) {
- queue->Depth--;
- return A_CONTAINING_STRUCT(pItem, struct htc_packet, ListLink);
- }
- return NULL;
-}
-
-/* dequeue an HTC packet from the tail of the queue */
-static INLINE struct htc_packet *HTC_PACKET_DEQUEUE_TAIL(struct htc_packet_queue *queue) {
- struct dl_list *pItem = DL_ListRemoveItemFromTail(&queue->QueueHead);
- if (pItem != NULL) {
- queue->Depth--;
- return A_CONTAINING_STRUCT(pItem, struct htc_packet, ListLink);
- }
- return NULL;
-}
-
-#define HTC_PACKET_QUEUE_DEPTH(pQ) (pQ)->Depth
-
-
-#define HTC_GET_ENDPOINT_FROM_PKT(p) (p)->Endpoint
-#define HTC_GET_TAG_FROM_PKT(p) (p)->PktInfo.AsTx.Tag
-
- /* transfer the packets from one queue to the tail of another queue */
-#define HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(pQDest,pQSrc) \
-{ \
- DL_ListTransferItemsToTail(&(pQDest)->QueueHead,&(pQSrc)->QueueHead); \
- (pQDest)->Depth += (pQSrc)->Depth; \
- (pQSrc)->Depth = 0; \
-}
-
- /* fast version to init and add a single packet to a queue */
-#define INIT_HTC_PACKET_QUEUE_AND_ADD(pQ,pP) \
-{ \
- DL_LIST_INIT_AND_ADD(&(pQ)->QueueHead,&(pP)->ListLink) \
- (pQ)->Depth = 1; \
-}
-
-#define HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pQ, pPTemp) \
- ITERATE_OVER_LIST_ALLOW_REMOVE(&(pQ)->QueueHead,(pPTemp), struct htc_packet, ListLink)
-
-#define HTC_PACKET_QUEUE_ITERATE_END ITERATE_END
-
-#endif /*HTC_PACKET_H_*/
diff --git a/drivers/staging/ath6kl/include/wlan_api.h b/drivers/staging/ath6kl/include/wlan_api.h
deleted file mode 100644
index 9eea5875dd38..000000000000
--- a/drivers/staging/ath6kl/include/wlan_api.h
+++ /dev/null
@@ -1,128 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// This file contains the API for the host wlan module
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _HOST_WLAN_API_H_
-#define _HOST_WLAN_API_H_
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <a_osapi.h>
-
-struct ieee80211_node_table;
-struct ieee80211_frame;
-
-struct ieee80211_common_ie {
- u16 ie_chan;
- u8 *ie_tstamp;
- u8 *ie_ssid;
- u8 *ie_rates;
- u8 *ie_xrates;
- u8 *ie_country;
- u8 *ie_wpa;
- u8 *ie_rsn;
- u8 *ie_wmm;
- u8 *ie_ath;
- u16 ie_capInfo;
- u16 ie_beaconInt;
- u8 *ie_tim;
- u8 *ie_chswitch;
- u8 ie_erp;
- u8 *ie_wsc;
- u8 *ie_htcap;
- u8 *ie_htop;
-#ifdef WAPI_ENABLE
- u8 *ie_wapi;
-#endif
-};
-
-typedef struct bss {
- u8 ni_macaddr[6];
- u8 ni_snr;
- s16 ni_rssi;
- struct bss *ni_list_next;
- struct bss *ni_list_prev;
- struct bss *ni_hash_next;
- struct bss *ni_hash_prev;
- struct ieee80211_common_ie ni_cie;
- u8 *ni_buf;
- u16 ni_framelen;
- struct ieee80211_node_table *ni_table;
- u32 ni_refcnt;
- int ni_scangen;
-
- u32 ni_tstamp;
- u32 ni_actcnt;
-#ifdef OS_ROAM_MANAGEMENT
- u32 ni_si_gen;
-#endif
-} bss_t;
-
-typedef void wlan_node_iter_func(void *arg, bss_t *);
-
-bss_t *wlan_node_alloc(struct ieee80211_node_table *nt, int wh_size);
-void wlan_node_free(bss_t *ni);
-void wlan_setup_node(struct ieee80211_node_table *nt, bss_t *ni,
- const u8 *macaddr);
-bss_t *wlan_find_node(struct ieee80211_node_table *nt, const u8 *macaddr);
-void wlan_node_reclaim(struct ieee80211_node_table *nt, bss_t *ni);
-void wlan_free_allnodes(struct ieee80211_node_table *nt);
-void wlan_iterate_nodes(struct ieee80211_node_table *nt, wlan_node_iter_func *f,
- void *arg);
-
-void wlan_node_table_init(void *wmip, struct ieee80211_node_table *nt);
-void wlan_node_table_reset(struct ieee80211_node_table *nt);
-void wlan_node_table_cleanup(struct ieee80211_node_table *nt);
-
-int wlan_parse_beacon(u8 *buf, int framelen,
- struct ieee80211_common_ie *cie);
-
-u16 wlan_ieee2freq(int chan);
-u32 wlan_freq2ieee(u16 freq);
-
-void wlan_set_nodeage(struct ieee80211_node_table *nt, u32 nodeAge);
-
-void
-wlan_refresh_inactive_nodes (struct ieee80211_node_table *nt);
-
-bss_t *
-wlan_find_Ssidnode (struct ieee80211_node_table *nt, u8 *pSsid,
- u32 ssidLength, bool bIsWPA2, bool bMatchSSID);
-
-void
-wlan_node_return (struct ieee80211_node_table *nt, bss_t *ni);
-
-bss_t *wlan_node_remove(struct ieee80211_node_table *nt, u8 *bssid);
-
-bss_t *
-wlan_find_matching_Ssidnode (struct ieee80211_node_table *nt, u8 *pSsid,
- u32 ssidLength, u32 dot11AuthMode, u32 authMode,
- u32 pairwiseCryptoType, u32 grpwiseCryptoTyp);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _HOST_WLAN_API_H_ */
diff --git a/drivers/staging/ath6kl/include/wmi_api.h b/drivers/staging/ath6kl/include/wmi_api.h
deleted file mode 100644
index c8583e0c4a96..000000000000
--- a/drivers/staging/ath6kl/include/wmi_api.h
+++ /dev/null
@@ -1,441 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="wmi_api.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// This file contains the definitions for the Wireless Module Interface (WMI).
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _WMI_API_H_
-#define _WMI_API_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
- /* WMI converts a dix frame with an ethernet payload (up to 1500 bytes)
- * to an 802.3 frame (adds SNAP header) and adds on a WMI data header */
-#define WMI_MAX_TX_DATA_FRAME_LENGTH (1500 + sizeof(WMI_DATA_HDR) + sizeof(ATH_MAC_HDR) + sizeof(ATH_LLC_SNAP_HDR))
-
- /* A normal WMI data frame */
-#define WMI_MAX_NORMAL_RX_DATA_FRAME_LENGTH (1500 + sizeof(WMI_DATA_HDR) + sizeof(ATH_MAC_HDR) + sizeof(ATH_LLC_SNAP_HDR))
-
- /* An AMSDU frame */ /* The MAX AMSDU length of AR6003 is 3839 */
-#define WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH (3840 + sizeof(WMI_DATA_HDR) + sizeof(ATH_MAC_HDR) + sizeof(ATH_LLC_SNAP_HDR))
-
-/*
- * IP QoS Field definitions according to 802.1p
- */
-#define BEST_EFFORT_PRI 0
-#define BACKGROUND_PRI 1
-#define EXCELLENT_EFFORT_PRI 3
-#define CONTROLLED_LOAD_PRI 4
-#define VIDEO_PRI 5
-#define VOICE_PRI 6
-#define NETWORK_CONTROL_PRI 7
-#define MAX_NUM_PRI 8
-
-#define UNDEFINED_PRI (0xff)
-
-#define WMI_IMPLICIT_PSTREAM_INACTIVITY_INT 5000 /* 5 seconds */
-
-#define A_ROUND_UP(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
-
-typedef enum {
- ATHEROS_COMPLIANCE = 0x1,
-}TSPEC_PARAM_COMPLIANCE;
-
-struct wmi_t;
-
-void *wmi_init(void *devt);
-
-void wmi_qos_state_init(struct wmi_t *wmip);
-void wmi_shutdown(struct wmi_t *wmip);
-HTC_ENDPOINT_ID wmi_get_control_ep(struct wmi_t * wmip);
-void wmi_set_control_ep(struct wmi_t * wmip, HTC_ENDPOINT_ID eid);
-u16 wmi_get_mapped_qos_queue(struct wmi_t *, u8 );
-int wmi_dix_2_dot3(struct wmi_t *wmip, void *osbuf);
-int wmi_data_hdr_add(struct wmi_t *wmip, void *osbuf, u8 msgType, bool bMoreData, WMI_DATA_HDR_DATA_TYPE data_type,u8 metaVersion, void *pTxMetaS);
-int wmi_dot3_2_dix(void *osbuf);
-
-int wmi_dot11_hdr_remove (struct wmi_t *wmip, void *osbuf);
-int wmi_dot11_hdr_add(struct wmi_t *wmip, void *osbuf, NETWORK_TYPE mode);
-
-int wmi_data_hdr_remove(struct wmi_t *wmip, void *osbuf);
-int wmi_syncpoint(struct wmi_t *wmip);
-int wmi_syncpoint_reset(struct wmi_t *wmip);
-u8 wmi_implicit_create_pstream(struct wmi_t *wmip, void *osbuf, u32 layer2Priority, bool wmmEnabled);
-
-u8 wmi_determine_userPriority (u8 *pkt, u32 layer2Pri);
-
-int wmi_control_rx(struct wmi_t *wmip, void *osbuf);
-void wmi_iterate_nodes(struct wmi_t *wmip, wlan_node_iter_func *f, void *arg);
-void wmi_free_allnodes(struct wmi_t *wmip);
-bss_t *wmi_find_node(struct wmi_t *wmip, const u8 *macaddr);
-void wmi_free_node(struct wmi_t *wmip, const u8 *macaddr);
-
-
-typedef enum {
- NO_SYNC_WMIFLAG = 0,
- SYNC_BEFORE_WMIFLAG, /* transmit all queued data before cmd */
- SYNC_AFTER_WMIFLAG, /* any new data waits until cmd execs */
- SYNC_BOTH_WMIFLAG,
- END_WMIFLAG /* end marker */
-} WMI_SYNC_FLAG;
-
-int wmi_cmd_send(struct wmi_t *wmip, void *osbuf, WMI_COMMAND_ID cmdId,
- WMI_SYNC_FLAG flag);
-
-int wmi_connect_cmd(struct wmi_t *wmip,
- NETWORK_TYPE netType,
- DOT11_AUTH_MODE dot11AuthMode,
- AUTH_MODE authMode,
- CRYPTO_TYPE pairwiseCrypto,
- u8 pairwiseCryptoLen,
- CRYPTO_TYPE groupCrypto,
- u8 groupCryptoLen,
- int ssidLength,
- u8 *ssid,
- u8 *bssid,
- u16 channel,
- u32 ctrl_flags);
-
-int wmi_reconnect_cmd(struct wmi_t *wmip,
- u8 *bssid,
- u16 channel);
-int wmi_disconnect_cmd(struct wmi_t *wmip);
-int wmi_getrev_cmd(struct wmi_t *wmip);
-int wmi_startscan_cmd(struct wmi_t *wmip, WMI_SCAN_TYPE scanType,
- u32 forceFgScan, u32 isLegacy,
- u32 homeDwellTime, u32 forceScanInterval,
- s8 numChan, u16 *channelList);
-int wmi_scanparams_cmd(struct wmi_t *wmip, u16 fg_start_sec,
- u16 fg_end_sec, u16 bg_sec,
- u16 minact_chdw_msec,
- u16 maxact_chdw_msec, u16 pas_chdw_msec,
- u8 shScanRatio, u8 scanCtrlFlags,
- u32 max_dfsch_act_time,
- u16 maxact_scan_per_ssid);
-int wmi_bssfilter_cmd(struct wmi_t *wmip, u8 filter, u32 ieMask);
-int wmi_probedSsid_cmd(struct wmi_t *wmip, u8 index, u8 flag,
- u8 ssidLength, u8 *ssid);
-int wmi_listeninterval_cmd(struct wmi_t *wmip, u16 listenInterval, u16 listenBeacons);
-int wmi_bmisstime_cmd(struct wmi_t *wmip, u16 bmisstime, u16 bmissbeacons);
-int wmi_associnfo_cmd(struct wmi_t *wmip, u8 ieType,
- u8 ieLen, u8 *ieInfo);
-int wmi_powermode_cmd(struct wmi_t *wmip, u8 powerMode);
-int wmi_ibsspmcaps_cmd(struct wmi_t *wmip, u8 pmEnable, u8 ttl,
- u16 atim_windows, u16 timeout_value);
-int wmi_apps_cmd(struct wmi_t *wmip, u8 psType, u32 idle_time,
- u32 ps_period, u8 sleep_period);
-int wmi_pmparams_cmd(struct wmi_t *wmip, u16 idlePeriod,
- u16 psPollNum, u16 dtimPolicy,
- u16 wakup_tx_policy, u16 num_tx_to_wakeup,
- u16 ps_fail_event_policy);
-int wmi_disctimeout_cmd(struct wmi_t *wmip, u8 timeout);
-int wmi_sync_cmd(struct wmi_t *wmip, u8 syncNumber);
-int wmi_create_pstream_cmd(struct wmi_t *wmip, WMI_CREATE_PSTREAM_CMD *pstream);
-int wmi_delete_pstream_cmd(struct wmi_t *wmip, u8 trafficClass, u8 streamID);
-int wmi_set_framerate_cmd(struct wmi_t *wmip, u8 bEnable, u8 type, u8 subType, u16 rateMask);
-int wmi_set_bitrate_cmd(struct wmi_t *wmip, s32 dataRate, s32 mgmtRate, s32 ctlRate);
-int wmi_get_bitrate_cmd(struct wmi_t *wmip);
-s8 wmi_validate_bitrate(struct wmi_t *wmip, s32 rate, s8 *rate_idx);
-int wmi_get_regDomain_cmd(struct wmi_t *wmip);
-int wmi_get_channelList_cmd(struct wmi_t *wmip);
-int wmi_set_channelParams_cmd(struct wmi_t *wmip, u8 scanParam,
- WMI_PHY_MODE mode, s8 numChan,
- u16 *channelList);
-
-int wmi_set_snr_threshold_params(struct wmi_t *wmip,
- WMI_SNR_THRESHOLD_PARAMS_CMD *snrCmd);
-int wmi_set_rssi_threshold_params(struct wmi_t *wmip,
- WMI_RSSI_THRESHOLD_PARAMS_CMD *rssiCmd);
-int wmi_clr_rssi_snr(struct wmi_t *wmip);
-int wmi_set_lq_threshold_params(struct wmi_t *wmip,
- WMI_LQ_THRESHOLD_PARAMS_CMD *lqCmd);
-int wmi_set_rts_cmd(struct wmi_t *wmip, u16 threshold);
-int wmi_set_lpreamble_cmd(struct wmi_t *wmip, u8 status, u8 preamblePolicy);
-
-int wmi_set_error_report_bitmask(struct wmi_t *wmip, u32 bitmask);
-
-int wmi_get_challenge_resp_cmd(struct wmi_t *wmip, u32 cookie,
- u32 source);
-
-int wmi_config_debug_module_cmd(struct wmi_t *wmip, u16 mmask,
- u16 tsr, bool rep, u16 size,
- u32 valid);
-
-int wmi_get_stats_cmd(struct wmi_t *wmip);
-
-int wmi_addKey_cmd(struct wmi_t *wmip, u8 keyIndex,
- CRYPTO_TYPE keyType, u8 keyUsage,
- u8 keyLength,u8 *keyRSC,
- u8 *keyMaterial, u8 key_op_ctrl, u8 *mac,
- WMI_SYNC_FLAG sync_flag);
-int wmi_add_krk_cmd(struct wmi_t *wmip, u8 *krk);
-int wmi_delete_krk_cmd(struct wmi_t *wmip);
-int wmi_deleteKey_cmd(struct wmi_t *wmip, u8 keyIndex);
-int wmi_set_akmp_params_cmd(struct wmi_t *wmip,
- WMI_SET_AKMP_PARAMS_CMD *akmpParams);
-int wmi_get_pmkid_list_cmd(struct wmi_t *wmip);
-int wmi_set_pmkid_list_cmd(struct wmi_t *wmip,
- WMI_SET_PMKID_LIST_CMD *pmkInfo);
-int wmi_abort_scan_cmd(struct wmi_t *wmip);
-int wmi_set_txPwr_cmd(struct wmi_t *wmip, u8 dbM);
-int wmi_get_txPwr_cmd(struct wmi_t *wmip);
-int wmi_addBadAp_cmd(struct wmi_t *wmip, u8 apIndex, u8 *bssid);
-int wmi_deleteBadAp_cmd(struct wmi_t *wmip, u8 apIndex);
-int wmi_set_tkip_countermeasures_cmd(struct wmi_t *wmip, bool en);
-int wmi_setPmkid_cmd(struct wmi_t *wmip, u8 *bssid, u8 *pmkId,
- bool set);
-int wmi_set_access_params_cmd(struct wmi_t *wmip, u8 ac, u16 txop,
- u8 eCWmin, u8 eCWmax,
- u8 aifsn);
-int wmi_set_retry_limits_cmd(struct wmi_t *wmip, u8 frameType,
- u8 trafficClass, u8 maxRetries,
- u8 enableNotify);
-
-void wmi_get_current_bssid(struct wmi_t *wmip, u8 *bssid);
-
-int wmi_get_roam_tbl_cmd(struct wmi_t *wmip);
-int wmi_get_roam_data_cmd(struct wmi_t *wmip, u8 roamDataType);
-int wmi_set_roam_ctrl_cmd(struct wmi_t *wmip, WMI_SET_ROAM_CTRL_CMD *p,
- u8 size);
-int wmi_set_powersave_timers_cmd(struct wmi_t *wmip,
- WMI_POWERSAVE_TIMERS_POLICY_CMD *pCmd,
- u8 size);
-
-int wmi_set_opt_mode_cmd(struct wmi_t *wmip, u8 optMode);
-int wmi_opt_tx_frame_cmd(struct wmi_t *wmip,
- u8 frmType,
- u8 *dstMacAddr,
- u8 *bssid,
- u16 optIEDataLen,
- u8 *optIEData);
-
-int wmi_set_adhoc_bconIntvl_cmd(struct wmi_t *wmip, u16 intvl);
-int wmi_set_voice_pkt_size_cmd(struct wmi_t *wmip, u16 voicePktSize);
-int wmi_set_max_sp_len_cmd(struct wmi_t *wmip, u8 maxSpLen);
-u8 convert_userPriority_to_trafficClass(u8 userPriority);
-u8 wmi_get_power_mode_cmd(struct wmi_t *wmip);
-int wmi_verify_tspec_params(WMI_CREATE_PSTREAM_CMD *pCmd, int tspecCompliance);
-
-#ifdef CONFIG_HOST_TCMD_SUPPORT
-int wmi_test_cmd(struct wmi_t *wmip, u8 *buf, u32 len);
-#endif
-
-int wmi_set_bt_status_cmd(struct wmi_t *wmip, u8 streamType, u8 status);
-int wmi_set_bt_params_cmd(struct wmi_t *wmip, WMI_SET_BT_PARAMS_CMD* cmd);
-
-int wmi_set_btcoex_fe_ant_cmd(struct wmi_t *wmip, WMI_SET_BTCOEX_FE_ANT_CMD * cmd);
-
-int wmi_set_btcoex_colocated_bt_dev_cmd(struct wmi_t *wmip,
- WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMD * cmd);
-
-int wmi_set_btcoex_btinquiry_page_config_cmd(struct wmi_t *wmip,
- WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG_CMD *cmd);
-
-int wmi_set_btcoex_sco_config_cmd(struct wmi_t *wmip,
- WMI_SET_BTCOEX_SCO_CONFIG_CMD * cmd);
-
-int wmi_set_btcoex_a2dp_config_cmd(struct wmi_t *wmip,
- WMI_SET_BTCOEX_A2DP_CONFIG_CMD* cmd);
-
-
-int wmi_set_btcoex_aclcoex_config_cmd(struct wmi_t *wmip, WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMD* cmd);
-
-int wmi_set_btcoex_debug_cmd(struct wmi_t *wmip, WMI_SET_BTCOEX_DEBUG_CMD * cmd);
-
-int wmi_set_btcoex_bt_operating_status_cmd(struct wmi_t * wmip,
- WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMD * cmd);
-
-int wmi_get_btcoex_config_cmd(struct wmi_t * wmip, WMI_GET_BTCOEX_CONFIG_CMD * cmd);
-
-int wmi_get_btcoex_stats_cmd(struct wmi_t * wmip);
-
-int wmi_SGI_cmd(struct wmi_t *wmip, u32 sgiMask, u8 sgiPERThreshold);
-
-/*
- * This function is used to configure the fix rates mask to the target.
- */
-int wmi_set_fixrates_cmd(struct wmi_t *wmip, u32 fixRatesMask);
-int wmi_get_ratemask_cmd(struct wmi_t *wmip);
-
-int wmi_set_authmode_cmd(struct wmi_t *wmip, u8 mode);
-
-int wmi_set_reassocmode_cmd(struct wmi_t *wmip, u8 mode);
-
-int wmi_set_qos_supp_cmd(struct wmi_t *wmip,u8 status);
-int wmi_set_wmm_cmd(struct wmi_t *wmip, WMI_WMM_STATUS status);
-int wmi_set_wmm_txop(struct wmi_t *wmip, WMI_TXOP_CFG txEnable);
-int wmi_set_country(struct wmi_t *wmip, u8 *countryCode);
-
-int wmi_get_keepalive_configured(struct wmi_t *wmip);
-u8 wmi_get_keepalive_cmd(struct wmi_t *wmip);
-int wmi_set_keepalive_cmd(struct wmi_t *wmip, u8 keepaliveInterval);
-
-int wmi_set_appie_cmd(struct wmi_t *wmip, u8 mgmtFrmType,
- u8 ieLen,u8 *ieInfo);
-
-int wmi_set_halparam_cmd(struct wmi_t *wmip, u8 *cmd, u16 dataLen);
-
-s32 wmi_get_rate(s8 rateindex);
-
-int wmi_set_ip_cmd(struct wmi_t *wmip, WMI_SET_IP_CMD *cmd);
-
-/*Wake on Wireless WMI commands*/
-int wmi_set_host_sleep_mode_cmd(struct wmi_t *wmip, WMI_SET_HOST_SLEEP_MODE_CMD *cmd);
-int wmi_set_wow_mode_cmd(struct wmi_t *wmip, WMI_SET_WOW_MODE_CMD *cmd);
-int wmi_get_wow_list_cmd(struct wmi_t *wmip, WMI_GET_WOW_LIST_CMD *cmd);
-int wmi_add_wow_pattern_cmd(struct wmi_t *wmip,
- WMI_ADD_WOW_PATTERN_CMD *cmd, u8 *pattern, u8 *mask, u8 pattern_size);
-int wmi_del_wow_pattern_cmd(struct wmi_t *wmip,
- WMI_DEL_WOW_PATTERN_CMD *cmd);
-int wmi_set_wsc_status_cmd(struct wmi_t *wmip, u32 status);
-
-int
-wmi_set_params_cmd(struct wmi_t *wmip, u32 opcode, u32 length, char *buffer);
-
-int
-wmi_set_mcast_filter_cmd(struct wmi_t *wmip, u8 dot1, u8 dot2, u8 dot3, u8 dot4);
-
-int
-wmi_del_mcast_filter_cmd(struct wmi_t *wmip, u8 dot1, u8 dot2, u8 dot3, u8 dot4);
-
-int
-wmi_mcast_filter_cmd(struct wmi_t *wmip, u8 enable);
-
-bss_t *
-wmi_find_Ssidnode (struct wmi_t *wmip, u8 *pSsid,
- u32 ssidLength, bool bIsWPA2, bool bMatchSSID);
-
-
-void
-wmi_node_return (struct wmi_t *wmip, bss_t *bss);
-
-void
-wmi_set_nodeage(struct wmi_t *wmip, u32 nodeAge);
-
-#if defined(CONFIG_TARGET_PROFILE_SUPPORT)
-int wmi_prof_cfg_cmd(struct wmi_t *wmip, u32 period, u32 nbins);
-int wmi_prof_addr_set_cmd(struct wmi_t *wmip, u32 addr);
-int wmi_prof_start_cmd(struct wmi_t *wmip);
-int wmi_prof_stop_cmd(struct wmi_t *wmip);
-int wmi_prof_count_get_cmd(struct wmi_t *wmip);
-#endif /* CONFIG_TARGET_PROFILE_SUPPORT */
-#ifdef OS_ROAM_MANAGEMENT
-void wmi_scan_indication (struct wmi_t *wmip);
-#endif
-
-int
-wmi_set_target_event_report_cmd(struct wmi_t *wmip, WMI_SET_TARGET_EVENT_REPORT_CMD* cmd);
-
-bss_t *wmi_rm_current_bss (struct wmi_t *wmip, u8 *id);
-int wmi_add_current_bss (struct wmi_t *wmip, u8 *id, bss_t *bss);
-
-
-/*
- * AP mode
- */
-int
-wmi_ap_profile_commit(struct wmi_t *wmip, WMI_CONNECT_CMD *p);
-
-int
-wmi_ap_set_hidden_ssid(struct wmi_t *wmip, u8 hidden_ssid);
-
-int
-wmi_ap_set_num_sta(struct wmi_t *wmip, u8 num_sta);
-
-int
-wmi_ap_set_acl_policy(struct wmi_t *wmip, u8 policy);
-
-int
-wmi_ap_acl_mac_list(struct wmi_t *wmip, WMI_AP_ACL_MAC_CMD *a);
-
-u8 acl_add_del_mac(WMI_AP_ACL *a, WMI_AP_ACL_MAC_CMD *acl);
-
-int
-wmi_ap_set_mlme(struct wmi_t *wmip, u8 cmd, u8 *mac, u16 reason);
-
-int
-wmi_set_pvb_cmd(struct wmi_t *wmip, u16 aid, bool flag);
-
-int
-wmi_ap_conn_inact_time(struct wmi_t *wmip, u32 period);
-
-int
-wmi_ap_bgscan_time(struct wmi_t *wmip, u32 period, u32 dwell);
-
-int
-wmi_ap_set_dtim(struct wmi_t *wmip, u8 dtim);
-
-int
-wmi_ap_set_rateset(struct wmi_t *wmip, u8 rateset);
-
-int
-wmi_set_ht_cap_cmd(struct wmi_t *wmip, WMI_SET_HT_CAP_CMD *cmd);
-
-int
-wmi_set_ht_op_cmd(struct wmi_t *wmip, u8 sta_chan_width);
-
-int
-wmi_send_hci_cmd(struct wmi_t *wmip, u8 *buf, u16 sz);
-
-int
-wmi_set_tx_select_rates_cmd(struct wmi_t *wmip, u32 *pMaskArray);
-
-int
-wmi_setup_aggr_cmd(struct wmi_t *wmip, u8 tid);
-
-int
-wmi_delete_aggr_cmd(struct wmi_t *wmip, u8 tid, bool uplink);
-
-int
-wmi_allow_aggr_cmd(struct wmi_t *wmip, u16 tx_tidmask, u16 rx_tidmask);
-
-int
-wmi_set_rx_frame_format_cmd(struct wmi_t *wmip, u8 rxMetaVersion, bool rxDot11Hdr, bool defragOnHost);
-
-int
-wmi_set_thin_mode_cmd(struct wmi_t *wmip, bool bThinMode);
-
-int
-wmi_set_wlan_conn_precedence_cmd(struct wmi_t *wmip, BT_WLAN_CONN_PRECEDENCE precedence);
-
-int
-wmi_set_pmk_cmd(struct wmi_t *wmip, u8 *pmk);
-
-int
-wmi_set_excess_tx_retry_thres_cmd(struct wmi_t *wmip, WMI_SET_EXCESS_TX_RETRY_THRES_CMD *cmd);
-
-u16 wmi_ieee2freq (int chan);
-
-u32 wmi_freq2ieee (u16 freq);
-
-bss_t *
-wmi_find_matching_Ssidnode (struct wmi_t *wmip, u8 *pSsid,
- u32 ssidLength,
- u32 dot11AuthMode, u32 authMode,
- u32 pairwiseCryptoType, u32 grpwiseCryptoTyp);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _WMI_API_H_ */
diff --git a/drivers/staging/ath6kl/miscdrv/ar3kconfig.c b/drivers/staging/ath6kl/miscdrv/ar3kconfig.c
deleted file mode 100644
index e0ea2183019d..000000000000
--- a/drivers/staging/ath6kl/miscdrv/ar3kconfig.c
+++ /dev/null
@@ -1,565 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2009-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// AR3K configuration implementation
-//
-// Author(s): ="Atheros"
-//==============================================================================
-
-#include "a_config.h"
-#include "athdefs.h"
-#include "a_osapi.h"
-#define ATH_MODULE_NAME misc
-#include "a_debug.h"
-#include "common_drv.h"
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
-#include "export_hci_transport.h"
-#else
-#include "hci_transport_api.h"
-#endif
-#include "ar3kconfig.h"
-#include "tlpm.h"
-
-#define BAUD_CHANGE_COMMAND_STATUS_OFFSET 5
-#define HCI_EVENT_RESP_TIMEOUTMS 3000
-#define HCI_CMD_OPCODE_BYTE_LOW_OFFSET 0
-#define HCI_CMD_OPCODE_BYTE_HI_OFFSET 1
-#define HCI_EVENT_OPCODE_BYTE_LOW 3
-#define HCI_EVENT_OPCODE_BYTE_HI 4
-#define HCI_CMD_COMPLETE_EVENT_CODE 0xE
-#define HCI_MAX_EVT_RECV_LENGTH 257
-#define EXIT_MIN_BOOT_COMMAND_STATUS_OFFSET 5
-
-int AthPSInitialize(struct ar3k_config_info *hdev);
-
-static int SendHCICommand(struct ar3k_config_info *pConfig,
- u8 *pBuffer,
- int Length)
-{
- struct htc_packet *pPacket = NULL;
- int status = 0;
-
- do {
-
- pPacket = (struct htc_packet *)A_MALLOC(sizeof(struct htc_packet));
- if (NULL == pPacket) {
- status = A_NO_MEMORY;
- break;
- }
-
- A_MEMZERO(pPacket,sizeof(struct htc_packet));
- SET_HTC_PACKET_INFO_TX(pPacket,
- NULL,
- pBuffer,
- Length,
- HCI_COMMAND_TYPE,
- AR6K_CONTROL_PKT_TAG);
-
- /* issue synchronously */
- status = HCI_TransportSendPkt(pConfig->pHCIDev,pPacket,true);
-
- } while (false);
-
- if (pPacket != NULL) {
- kfree(pPacket);
- }
-
- return status;
-}
-
-static int RecvHCIEvent(struct ar3k_config_info *pConfig,
- u8 *pBuffer,
- int *pLength)
-{
- int status = 0;
- struct htc_packet *pRecvPacket = NULL;
-
- do {
-
- pRecvPacket = (struct htc_packet *)A_MALLOC(sizeof(struct htc_packet));
- if (NULL == pRecvPacket) {
- status = A_NO_MEMORY;
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to alloc HTC struct \n"));
- break;
- }
-
- A_MEMZERO(pRecvPacket,sizeof(struct htc_packet));
-
- SET_HTC_PACKET_INFO_RX_REFILL(pRecvPacket,NULL,pBuffer,*pLength,HCI_EVENT_TYPE);
-
- status = HCI_TransportRecvHCIEventSync(pConfig->pHCIDev,
- pRecvPacket,
- HCI_EVENT_RESP_TIMEOUTMS);
- if (status) {
- break;
- }
-
- *pLength = pRecvPacket->ActualLength;
-
- } while (false);
-
- if (pRecvPacket != NULL) {
- kfree(pRecvPacket);
- }
-
- return status;
-}
-
-int SendHCICommandWaitCommandComplete(struct ar3k_config_info *pConfig,
- u8 *pHCICommand,
- int CmdLength,
- u8 **ppEventBuffer,
- u8 **ppBufferToFree)
-{
- int status = 0;
- u8 *pBuffer = NULL;
- u8 *pTemp;
- int length;
- bool commandComplete = false;
- u8 opCodeBytes[2];
-
- do {
-
- length = max(HCI_MAX_EVT_RECV_LENGTH,CmdLength);
- length += pConfig->pHCIProps->HeadRoom + pConfig->pHCIProps->TailRoom;
- length += pConfig->pHCIProps->IOBlockPad;
-
- pBuffer = (u8 *)A_MALLOC(length);
- if (NULL == pBuffer) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Failed to allocate bt buffer \n"));
- status = A_NO_MEMORY;
- break;
- }
-
- /* get the opcodes to check the command complete event */
- opCodeBytes[0] = pHCICommand[HCI_CMD_OPCODE_BYTE_LOW_OFFSET];
- opCodeBytes[1] = pHCICommand[HCI_CMD_OPCODE_BYTE_HI_OFFSET];
-
- /* copy HCI command */
- memcpy(pBuffer + pConfig->pHCIProps->HeadRoom,pHCICommand,CmdLength);
- /* send command */
- status = SendHCICommand(pConfig,
- pBuffer + pConfig->pHCIProps->HeadRoom,
- CmdLength);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Failed to send HCI Command (%d) \n", status));
- AR_DEBUG_PRINTBUF(pHCICommand,CmdLength,"HCI Bridge Failed HCI Command");
- break;
- }
-
- /* reuse buffer to capture command complete event */
- A_MEMZERO(pBuffer,length);
- status = RecvHCIEvent(pConfig,pBuffer,&length);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: HCI event recv failed \n"));
- AR_DEBUG_PRINTBUF(pHCICommand,CmdLength,"HCI Bridge Failed HCI Command");
- break;
- }
-
- pTemp = pBuffer + pConfig->pHCIProps->HeadRoom;
- if (pTemp[0] == HCI_CMD_COMPLETE_EVENT_CODE) {
- if ((pTemp[HCI_EVENT_OPCODE_BYTE_LOW] == opCodeBytes[0]) &&
- (pTemp[HCI_EVENT_OPCODE_BYTE_HI] == opCodeBytes[1])) {
- commandComplete = true;
- }
- }
-
- if (!commandComplete) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Unexpected HCI event : %d \n",pTemp[0]));
- AR_DEBUG_PRINTBUF(pTemp,pTemp[1],"Unexpected HCI event");
- status = A_ECOMM;
- break;
- }
-
- if (ppEventBuffer != NULL) {
- /* caller wants to look at the event */
- *ppEventBuffer = pTemp;
- if (ppBufferToFree == NULL) {
- status = A_EINVAL;
- break;
- }
- /* caller must free the buffer */
- *ppBufferToFree = pBuffer;
- pBuffer = NULL;
- }
-
- } while (false);
-
- if (pBuffer != NULL) {
- kfree(pBuffer);
- }
-
- return status;
-}
-
-static int AR3KConfigureHCIBaud(struct ar3k_config_info *pConfig)
-{
- int status = 0;
- u8 hciBaudChangeCommand[] = {0x0c,0xfc,0x2,0,0};
- u16 baudVal;
- u8 *pEvent = NULL;
- u8 *pBufferToFree = NULL;
-
- do {
-
- if (pConfig->Flags & AR3K_CONFIG_FLAG_SET_AR3K_BAUD) {
- baudVal = (u16)(pConfig->AR3KBaudRate / 100);
- hciBaudChangeCommand[3] = (u8)baudVal;
- hciBaudChangeCommand[4] = (u8)(baudVal >> 8);
-
- status = SendHCICommandWaitCommandComplete(pConfig,
- hciBaudChangeCommand,
- sizeof(hciBaudChangeCommand),
- &pEvent,
- &pBufferToFree);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Baud rate change failed! \n"));
- break;
- }
-
- if (pEvent[BAUD_CHANGE_COMMAND_STATUS_OFFSET] != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("AR3K Config: Baud change command event status failed: %d \n",
- pEvent[BAUD_CHANGE_COMMAND_STATUS_OFFSET]));
- status = A_ECOMM;
- break;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
- ("AR3K Config: Baud Changed to %d \n",pConfig->AR3KBaudRate));
- }
-
- if (pConfig->Flags & AR3K_CONFIG_FLAG_AR3K_BAUD_CHANGE_DELAY) {
- /* some versions of AR3K do not switch baud immediately, up to 300MS */
- A_MDELAY(325);
- }
-
- if (pConfig->Flags & AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP) {
- /* Tell target to change UART baud rate for AR6K */
- status = HCI_TransportSetBaudRate(pConfig->pHCIDev, pConfig->AR3KBaudRate);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("AR3K Config: failed to set scale and step values: %d \n", status));
- break;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
- ("AR3K Config: Baud changed to %d for AR6K\n", pConfig->AR3KBaudRate));
- }
-
- } while (false);
-
- if (pBufferToFree != NULL) {
- kfree(pBufferToFree);
- }
-
- return status;
-}
-
-static int AR3KExitMinBoot(struct ar3k_config_info *pConfig)
-{
- int status;
- char exitMinBootCmd[] = {0x25,0xFC,0x0c,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00};
- u8 *pEvent = NULL;
- u8 *pBufferToFree = NULL;
-
- status = SendHCICommandWaitCommandComplete(pConfig,
- exitMinBootCmd,
- sizeof(exitMinBootCmd),
- &pEvent,
- &pBufferToFree);
-
- if (!status) {
- if (pEvent[EXIT_MIN_BOOT_COMMAND_STATUS_OFFSET] != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("AR3K Config: MinBoot exit command event status failed: %d \n",
- pEvent[EXIT_MIN_BOOT_COMMAND_STATUS_OFFSET]));
- status = A_ECOMM;
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,
- ("AR3K Config: MinBoot Exit Command Complete (Success) \n"));
- A_MDELAY(1);
- }
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: MinBoot Exit Failed! \n"));
- }
-
- if (pBufferToFree != NULL) {
- kfree(pBufferToFree);
- }
-
- return status;
-}
-
-static int AR3KConfigureSendHCIReset(struct ar3k_config_info *pConfig)
-{
- int status = 0;
- u8 hciResetCommand[] = {0x03,0x0c,0x0};
- u8 *pEvent = NULL;
- u8 *pBufferToFree = NULL;
-
- status = SendHCICommandWaitCommandComplete( pConfig,
- hciResetCommand,
- sizeof(hciResetCommand),
- &pEvent,
- &pBufferToFree );
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: HCI reset failed! \n"));
- }
-
- if (pBufferToFree != NULL) {
- kfree(pBufferToFree);
- }
-
- return status;
-}
-
-static int AR3KEnableTLPM(struct ar3k_config_info *pConfig)
-{
- int status;
- /* AR3K vendor specific command for Host Wakeup Config */
- char hostWakeupConfig[] = {0x31,0xFC,0x18,
- 0x02,0x00,0x00,0x00,
- 0x01,0x00,0x00,0x00,
- TLPM_DEFAULT_IDLE_TIMEOUT_LSB,TLPM_DEFAULT_IDLE_TIMEOUT_MSB,0x00,0x00, //idle timeout in ms
- 0x00,0x00,0x00,0x00,
- TLPM_DEFAULT_WAKEUP_TIMEOUT_MS,0x00,0x00,0x00, //wakeup timeout in ms
- 0x00,0x00,0x00,0x00};
- /* AR3K vendor specific command for Target Wakeup Config */
- char targetWakeupConfig[] = {0x31,0xFC,0x18,
- 0x04,0x00,0x00,0x00,
- 0x01,0x00,0x00,0x00,
- TLPM_DEFAULT_IDLE_TIMEOUT_LSB,TLPM_DEFAULT_IDLE_TIMEOUT_MSB,0x00,0x00, //idle timeout in ms
- 0x00,0x00,0x00,0x00,
- TLPM_DEFAULT_WAKEUP_TIMEOUT_MS,0x00,0x00,0x00, //wakeup timeout in ms
- 0x00,0x00,0x00,0x00};
- /* AR3K vendor specific command for Host Wakeup Enable */
- char hostWakeupEnable[] = {0x31,0xFC,0x4,
- 0x01,0x00,0x00,0x00};
- /* AR3K vendor specific command for Target Wakeup Enable */
- char targetWakeupEnable[] = {0x31,0xFC,0x4,
- 0x06,0x00,0x00,0x00};
- /* AR3K vendor specific command for Sleep Enable */
- char sleepEnable[] = {0x4,0xFC,0x1,
- 0x1};
- u8 *pEvent = NULL;
- u8 *pBufferToFree = NULL;
-
- if (0 != pConfig->IdleTimeout) {
- u8 idle_lsb = pConfig->IdleTimeout & 0xFF;
- u8 idle_msb = (pConfig->IdleTimeout & 0xFF00) >> 8;
- hostWakeupConfig[11] = targetWakeupConfig[11] = idle_lsb;
- hostWakeupConfig[12] = targetWakeupConfig[12] = idle_msb;
- }
-
- if (0 != pConfig->WakeupTimeout) {
- hostWakeupConfig[19] = targetWakeupConfig[19] = (pConfig->WakeupTimeout & 0xFF);
- }
-
- status = SendHCICommandWaitCommandComplete(pConfig,
- hostWakeupConfig,
- sizeof(hostWakeupConfig),
- &pEvent,
- &pBufferToFree);
- if (pBufferToFree != NULL) {
- kfree(pBufferToFree);
- }
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HostWakeup Config Failed! \n"));
- return status;
- }
-
- pEvent = NULL;
- pBufferToFree = NULL;
- status = SendHCICommandWaitCommandComplete(pConfig,
- targetWakeupConfig,
- sizeof(targetWakeupConfig),
- &pEvent,
- &pBufferToFree);
- if (pBufferToFree != NULL) {
- kfree(pBufferToFree);
- }
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Target Wakeup Config Failed! \n"));
- return status;
- }
-
- pEvent = NULL;
- pBufferToFree = NULL;
- status = SendHCICommandWaitCommandComplete(pConfig,
- hostWakeupEnable,
- sizeof(hostWakeupEnable),
- &pEvent,
- &pBufferToFree);
- if (pBufferToFree != NULL) {
- kfree(pBufferToFree);
- }
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HostWakeup Enable Failed! \n"));
- return status;
- }
-
- pEvent = NULL;
- pBufferToFree = NULL;
- status = SendHCICommandWaitCommandComplete(pConfig,
- targetWakeupEnable,
- sizeof(targetWakeupEnable),
- &pEvent,
- &pBufferToFree);
- if (pBufferToFree != NULL) {
- kfree(pBufferToFree);
- }
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Target Wakeup Enable Failed! \n"));
- return status;
- }
-
- pEvent = NULL;
- pBufferToFree = NULL;
- status = SendHCICommandWaitCommandComplete(pConfig,
- sleepEnable,
- sizeof(sleepEnable),
- &pEvent,
- &pBufferToFree);
- if (pBufferToFree != NULL) {
- kfree(pBufferToFree);
- }
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Sleep Enable Failed! \n"));
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Enable TLPM Completed (status = %d) \n",status));
-
- return status;
-}
-
-int AR3KConfigure(struct ar3k_config_info *pConfig)
-{
- int status = 0;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Configuring AR3K ...\n"));
-
- do {
-
- if ((pConfig->pHCIDev == NULL) || (pConfig->pHCIProps == NULL) || (pConfig->pHIFDevice == NULL)) {
- status = A_EINVAL;
- break;
- }
-
- /* disable asynchronous recv while we issue commands and receive events synchronously */
- status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,false);
- if (status) {
- break;
- }
-
- if (pConfig->Flags & AR3K_CONFIG_FLAG_FORCE_MINBOOT_EXIT) {
- status = AR3KExitMinBoot(pConfig);
- if (status) {
- break;
- }
- }
-
-
- /* Load patching and PST file if available*/
- if (0 != AthPSInitialize(pConfig)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Patch Download Failed!\n"));
- }
-
- /* Send HCI reset to make PS tags take effect*/
- AR3KConfigureSendHCIReset(pConfig);
-
- if (pConfig->Flags &
- (AR3K_CONFIG_FLAG_SET_AR3K_BAUD | AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP)) {
- status = AR3KConfigureHCIBaud(pConfig);
- if (status) {
- break;
- }
- }
-
-
-
- if (pConfig->PwrMgmtEnabled) {
- /* the delay is required after the previous HCI reset before further
- * HCI commands can be issued
- */
- A_MDELAY(200);
- AR3KEnableTLPM(pConfig);
- }
-
- /* re-enable asynchronous recv */
- status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,true);
- if (status) {
- break;
- }
-
-
- } while (false);
-
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Configuration Complete (status = %d) \n",status));
-
- return status;
-}
-
-int AR3KConfigureExit(void *config)
-{
- int status = 0;
- struct ar3k_config_info *pConfig = (struct ar3k_config_info *)config;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Cleaning up AR3K ...\n"));
-
- do {
-
- if ((pConfig->pHCIDev == NULL) || (pConfig->pHCIProps == NULL) || (pConfig->pHIFDevice == NULL)) {
- status = A_EINVAL;
- break;
- }
-
- /* disable asynchronous recv while we issue commands and receive events synchronously */
- status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,false);
- if (status) {
- break;
- }
-
- if (pConfig->Flags &
- (AR3K_CONFIG_FLAG_SET_AR3K_BAUD | AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP)) {
- status = AR3KConfigureHCIBaud(pConfig);
- if (status) {
- break;
- }
- }
-
- /* re-enable asynchronous recv */
- status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,true);
- if (status) {
- break;
- }
-
-
- } while (false);
-
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Cleanup Complete (status = %d) \n",status));
-
- return status;
-}
-
diff --git a/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c
deleted file mode 100644
index 282ceac597b8..000000000000
--- a/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c
+++ /dev/null
@@ -1,572 +0,0 @@
-/*
- * Copyright (c) 2004-2010 Atheros Communications Inc.
- * All rights reserved.
- *
- * This file implements the Atheros PS and patch downloaded for HCI UART Transport driver.
- * This file can be used for HCI SDIO transport implementation for AR6002 with HCI_TRANSPORT_SDIO
- * defined.
- *
- *
- * ar3kcpsconfig.c
- *
- *
- *
- * The software source and binaries included in this development package are
- * licensed, not sold. You, or your company, received the package under one
- * or more license agreements. The rights granted to you are specifically
- * listed in these license agreement(s). All other rights remain with Atheros
- * Communications, Inc., its subsidiaries, or the respective owner including
- * those listed on the included copyright notices.. Distribution of any
- * portion of this package must be in strict compliance with the license
- * agreement(s) terms.
- *
- *
- *
- */
-
-
-
-#include "ar3kpsconfig.h"
-#ifndef HCI_TRANSPORT_SDIO
-#include "hci_ath.h"
-#include "hci_uart.h"
-#endif /* #ifndef HCI_TRANSPORT_SDIO */
-
-#define MAX_FW_PATH_LEN 50
-#define MAX_BDADDR_FORMAT_LENGTH 30
-
-/*
- * Structure used to send HCI packet, hci packet length and device info
- * together as parameter to PSThread.
- */
-typedef struct {
-
- struct ps_cmd_packet *HciCmdList;
- u32 num_packets;
- struct ar3k_config_info *dev;
-}HciCommandListParam;
-
-int SendHCICommandWaitCommandComplete(struct ar3k_config_info *pConfig,
- u8 *pHCICommand,
- int CmdLength,
- u8 **ppEventBuffer,
- u8 **ppBufferToFree);
-
-u32 Rom_Version;
-u32 Build_Version;
-extern bool BDADDR;
-
-int getDeviceType(struct ar3k_config_info *pConfig, u32 *code);
-int ReadVersionInfo(struct ar3k_config_info *pConfig);
-#ifndef HCI_TRANSPORT_SDIO
-
-DECLARE_WAIT_QUEUE_HEAD(PsCompleteEvent);
-DECLARE_WAIT_QUEUE_HEAD(HciEvent);
-u8 *HciEventpacket;
-rwlock_t syncLock;
-wait_queue_t Eventwait;
-
-int PSHciWritepacket(struct hci_dev*,u8* Data, u32 len);
-extern char *bdaddr;
-#endif /* HCI_TRANSPORT_SDIO */
-
-int write_bdaddr(struct ar3k_config_info *pConfig,u8 *bdaddr,int type);
-
-int PSSendOps(void *arg);
-
-#ifdef BT_PS_DEBUG
-void Hci_log(u8 * log_string,u8 *data,u32 len)
-{
- int i;
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s : ",log_string));
- for (i = 0; i < len; i++) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("0x%02x ", data[i]));
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("\n...................................\n"));
-}
-#else
-#define Hci_log(string,data,len)
-#endif /* BT_PS_DEBUG */
-
-
-
-
-int AthPSInitialize(struct ar3k_config_info *hdev)
-{
- int status = 0;
- if(hdev == NULL) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Invalid Device handle received\n"));
- return A_ERROR;
- }
-
-#ifndef HCI_TRANSPORT_SDIO
- DECLARE_WAITQUEUE(wait, current);
-#endif /* HCI_TRANSPORT_SDIO */
-
-
-#ifdef HCI_TRANSPORT_SDIO
- status = PSSendOps((void*)hdev);
-#else
- if(InitPSState(hdev) == -1) {
- return A_ERROR;
- }
- allow_signal(SIGKILL);
- add_wait_queue(&PsCompleteEvent,&wait);
- set_current_state(TASK_INTERRUPTIBLE);
- if(!kernel_thread(PSSendOps,(void*)hdev,CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Kthread Failed\n"));
- remove_wait_queue(&PsCompleteEvent,&wait);
- return A_ERROR;
- }
- wait_event_interruptible(PsCompleteEvent,(PSTagMode == false));
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&PsCompleteEvent,&wait);
-
-#endif /* HCI_TRANSPORT_SDIO */
-
-
- return status;
-
-}
-
-int PSSendOps(void *arg)
-{
- int i;
- int status = 0;
- struct ps_cmd_packet *HciCmdList; /* List storing the commands */
- const struct firmware* firmware;
- u32 numCmds;
- u8 *event;
- u8 *bufferToFree;
- struct hci_dev *device;
- u8 *buffer;
- u32 len;
- u32 DevType;
- u8 *PsFileName;
- u8 *patchFileName;
- u8 *path = NULL;
- u8 *config_path = NULL;
- u8 config_bdaddr[MAX_BDADDR_FORMAT_LENGTH];
- struct ar3k_config_info *hdev = (struct ar3k_config_info*)arg;
- struct device *firmwareDev = NULL;
- status = 0;
- HciCmdList = NULL;
-#ifdef HCI_TRANSPORT_SDIO
- device = hdev->pBtStackHCIDev;
- firmwareDev = device->parent;
-#else
- device = hdev;
- firmwareDev = &device->dev;
- AthEnableSyncCommandOp(true);
-#endif /* HCI_TRANSPORT_SDIO */
- /* First verify if the controller is an FPGA or ASIC, so depending on the device type the PS file to be written will be different.
- */
-
- path =(u8 *)A_MALLOC(MAX_FW_PATH_LEN);
- if(path == NULL) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Malloc failed to allocate %d bytes for path\n", MAX_FW_PATH_LEN));
- goto complete;
- }
- config_path = (u8 *) A_MALLOC(MAX_FW_PATH_LEN);
- if(config_path == NULL) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Malloc failed to allocate %d bytes for config_path\n", MAX_FW_PATH_LEN));
- goto complete;
- }
-
- if(A_ERROR == getDeviceType(hdev,&DevType)) {
- status = 1;
- goto complete;
- }
- if(A_ERROR == ReadVersionInfo(hdev)) {
- status = 1;
- goto complete;
- }
-
- patchFileName = PATCH_FILE;
- snprintf(path, MAX_FW_PATH_LEN, "%s/%xcoex/",CONFIG_PATH,Rom_Version);
- if(DevType){
- if(DevType == 0xdeadc0de){
- PsFileName = PS_ASIC_FILE;
- } else{
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" FPGA Test Image : %x %x \n",Rom_Version,Build_Version));
- if((Rom_Version == 0x99999999) && (Build_Version == 1)){
-
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("FPGA Test Image : Skipping Patch File load\n"));
- patchFileName = NULL;
- }
- PsFileName = PS_FPGA_FILE;
- }
- }
- else{
- PsFileName = PS_ASIC_FILE;
- }
-
- snprintf(config_path, MAX_FW_PATH_LEN, "%s%s",path,PsFileName);
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%x: FPGA/ASIC PS File Name %s\n", DevType,config_path));
- /* Read the PS file to a dynamically allocated buffer */
- if(A_REQUEST_FIRMWARE(&firmware,config_path,firmwareDev) < 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: firmware file open error\n", __FUNCTION__ ));
- status = 1;
- goto complete;
-
- }
- if(NULL == firmware || firmware->size == 0) {
- status = 1;
- goto complete;
- }
- buffer = (u8 *)A_MALLOC(firmware->size);
- if(buffer != NULL) {
- /* Copy the read file to a local Dynamic buffer */
- memcpy(buffer,firmware->data,firmware->size);
- len = firmware->size;
- A_RELEASE_FIRMWARE(firmware);
- /* Parse the PS buffer to a global variable */
- status = AthDoParsePS(buffer,len);
- kfree(buffer);
- } else {
- A_RELEASE_FIRMWARE(firmware);
- }
-
-
- /* Read the patch file to a dynamically allocated buffer */
- if(patchFileName != NULL)
- snprintf(config_path,
- MAX_FW_PATH_LEN, "%s%s",path,patchFileName);
- else {
- status = 0;
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Patch File Name %s\n", config_path));
- if((patchFileName == NULL) || (A_REQUEST_FIRMWARE(&firmware,config_path,firmwareDev) < 0)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: firmware file open error\n", __FUNCTION__ ));
- /*
- * It is not necessary that Patch file be available, continue with PS Operations if.
- * failed.
- */
- status = 0;
-
- } else {
- if(NULL == firmware || firmware->size == 0) {
- status = 0;
- } else {
- buffer = (u8 *)A_MALLOC(firmware->size);
- if(buffer != NULL) {
- /* Copy the read file to a local Dynamic buffer */
- memcpy(buffer,firmware->data,firmware->size);
- len = firmware->size;
- A_RELEASE_FIRMWARE(firmware);
- /* parse and store the Patch file contents to a global variables */
- status = AthDoParsePatch(buffer,len);
- kfree(buffer);
- } else {
- A_RELEASE_FIRMWARE(firmware);
- }
- }
- }
-
- /* Create an HCI command list from the parsed PS and patch information */
- AthCreateCommandList(&HciCmdList,&numCmds);
-
- /* Form the parameter for PSSendOps() API */
-
-
- /*
- * First Send the CRC packet,
- * We have to continue with the PS operations only if the CRC packet has been replied with
- * a Command complete event with status Error.
- */
-
- if(SendHCICommandWaitCommandComplete
- (hdev,
- HciCmdList[0].Hcipacket,
- HciCmdList[0].packetLen,
- &event,
- &bufferToFree) == 0) {
- if(ReadPSEvent(event) == 0) { /* Exit if the status is success */
- if(bufferToFree != NULL) {
- kfree(bufferToFree);
- }
-
-#ifndef HCI_TRANSPORT_SDIO
- if(bdaddr && bdaddr[0] !='\0') {
- write_bdaddr(hdev,bdaddr,BDADDR_TYPE_STRING);
- }
-#endif
- status = 1;
- goto complete;
- }
- if(bufferToFree != NULL) {
- kfree(bufferToFree);
- }
- } else {
- status = 0;
- goto complete;
- }
-
- for(i = 1; i <numCmds; i++) {
-
- if(SendHCICommandWaitCommandComplete
- (hdev,
- HciCmdList[i].Hcipacket,
- HciCmdList[i].packetLen,
- &event,
- &bufferToFree) == 0) {
- if(ReadPSEvent(event) != 0) { /* Exit if the status is success */
- if(bufferToFree != NULL) {
- kfree(bufferToFree);
- }
- status = 1;
- goto complete;
- }
- if(bufferToFree != NULL) {
- kfree(bufferToFree);
- }
- } else {
- status = 0;
- goto complete;
- }
- }
-#ifdef HCI_TRANSPORT_SDIO
- if(BDADDR == false)
- if(hdev->bdaddr[0] !=0x00 ||
- hdev->bdaddr[1] !=0x00 ||
- hdev->bdaddr[2] !=0x00 ||
- hdev->bdaddr[3] !=0x00 ||
- hdev->bdaddr[4] !=0x00 ||
- hdev->bdaddr[5] !=0x00)
- write_bdaddr(hdev,hdev->bdaddr,BDADDR_TYPE_HEX);
-
-#ifndef HCI_TRANSPORT_SDIO
-
- if(bdaddr && bdaddr[0] != '\0') {
- write_bdaddr(hdev,bdaddr,BDADDR_TYPE_STRING);
- } else
-#endif /* HCI_TRANSPORT_SDIO */
- /* Write BDADDR Read from OTP here */
-
-
-
-#endif
-
- {
- /* Read Contents of BDADDR file if user has not provided any option */
- snprintf(config_path,MAX_FW_PATH_LEN, "%s%s",path,BDADDR_FILE);
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Patch File Name %s\n", config_path));
- if(A_REQUEST_FIRMWARE(&firmware,config_path,firmwareDev) < 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: firmware file open error\n", __FUNCTION__ ));
- status = 1;
- goto complete;
- }
- if(NULL == firmware || firmware->size == 0) {
- status = 1;
- goto complete;
- }
- len = min_t(size_t, firmware->size, MAX_BDADDR_FORMAT_LENGTH - 1);
- memcpy(config_bdaddr, firmware->data, len);
- config_bdaddr[len] = '\0';
- write_bdaddr(hdev,config_bdaddr,BDADDR_TYPE_STRING);
- A_RELEASE_FIRMWARE(firmware);
- }
-complete:
-#ifndef HCI_TRANSPORT_SDIO
- AthEnableSyncCommandOp(false);
- PSTagMode = false;
- wake_up_interruptible(&PsCompleteEvent);
-#endif /* HCI_TRANSPORT_SDIO */
- if(NULL != HciCmdList) {
- AthFreeCommandList(&HciCmdList,numCmds);
- }
- if(path) {
- kfree(path);
- }
- if(config_path) {
- kfree(config_path);
- }
- return status;
-}
-#ifndef HCI_TRANSPORT_SDIO
-/*
- * This API is used to send the HCI command to controller and return
- * with a HCI Command Complete event.
- * For HCI SDIO transport, this will be internally defined.
- */
-int SendHCICommandWaitCommandComplete(struct ar3k_config_info *pConfig,
- u8 *pHCICommand,
- int CmdLength,
- u8 **ppEventBuffer,
- u8 **ppBufferToFree)
-{
- if(CmdLength == 0) {
- return A_ERROR;
- }
- Hci_log("COM Write -->",pHCICommand,CmdLength);
- PSAcked = false;
- if(PSHciWritepacket(pConfig,pHCICommand,CmdLength) == 0) {
- /* If the controller is not available, return Error */
- return A_ERROR;
- }
- //add_timer(&psCmdTimer);
- wait_event_interruptible(HciEvent,(PSAcked == true));
- if(NULL != HciEventpacket) {
- *ppEventBuffer = HciEventpacket;
- *ppBufferToFree = HciEventpacket;
- } else {
- /* Did not get an event from controller. return error */
- *ppBufferToFree = NULL;
- return A_ERROR;
- }
-
- return 0;
-}
-#endif /* HCI_TRANSPORT_SDIO */
-
-int ReadPSEvent(u8* Data){
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" PS Event %x %x %x\n",Data[4],Data[5],Data[3]));
-
- if(Data[4] == 0xFC && Data[5] == 0x00)
- {
- switch(Data[3]){
- case 0x0B:
- return 0;
- break;
- case 0x0C:
- /* Change Baudrate */
- return 0;
- break;
- case 0x04:
- return 0;
- break;
- case 0x1E:
- Rom_Version = Data[9];
- Rom_Version = ((Rom_Version << 8) |Data[8]);
- Rom_Version = ((Rom_Version << 8) |Data[7]);
- Rom_Version = ((Rom_Version << 8) |Data[6]);
-
- Build_Version = Data[13];
- Build_Version = ((Build_Version << 8) |Data[12]);
- Build_Version = ((Build_Version << 8) |Data[11]);
- Build_Version = ((Build_Version << 8) |Data[10]);
- return 0;
- break;
-
-
- }
- }
-
- return A_ERROR;
-}
-int str2ba(unsigned char *str_bdaddr,unsigned char *bdaddr)
-{
- unsigned char bdbyte[3];
- unsigned char *str_byte = str_bdaddr;
- int i,j;
- unsigned char colon_present = 0;
-
- if(NULL != strstr(str_bdaddr,":")) {
- colon_present = 1;
- }
-
-
- bdbyte[2] = '\0';
-
- for( i = 0,j = 5; i < 6; i++, j--) {
- bdbyte[0] = str_byte[0];
- bdbyte[1] = str_byte[1];
- bdaddr[j] = A_STRTOL(bdbyte,NULL,16);
- if(colon_present == 1) {
- str_byte+=3;
- } else {
- str_byte+=2;
- }
- }
- return 0;
-}
-
-int write_bdaddr(struct ar3k_config_info *pConfig,u8 *bdaddr,int type)
-{
- u8 bdaddr_cmd[] = { 0x0B, 0xFC, 0x0A, 0x01, 0x01,
- 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
- u8 *event;
- u8 *bufferToFree = NULL;
- int result = A_ERROR;
- int inc,outc;
-
- if (type == BDADDR_TYPE_STRING)
- str2ba(bdaddr,&bdaddr_cmd[7]);
- else {
- /* Bdaddr has to be sent as LAP first */
- for(inc = 5 ,outc = 7; inc >=0; inc--, outc++)
- bdaddr_cmd[outc] = bdaddr[inc];
- }
-
- if(0 == SendHCICommandWaitCommandComplete(pConfig,bdaddr_cmd,
- sizeof(bdaddr_cmd),
- &event,&bufferToFree)) {
-
- if(event[4] == 0xFC && event[5] == 0x00){
- if(event[3] == 0x0B){
- result = 0;
- }
- }
-
- }
- if(bufferToFree != NULL) {
- kfree(bufferToFree);
- }
- return result;
-
-}
-int ReadVersionInfo(struct ar3k_config_info *pConfig)
-{
- u8 hciCommand[] = {0x1E,0xfc,0x00};
- u8 *event;
- u8 *bufferToFree = NULL;
- int result = A_ERROR;
- if(0 == SendHCICommandWaitCommandComplete(pConfig,hciCommand,sizeof(hciCommand),&event,&bufferToFree)) {
- result = ReadPSEvent(event);
-
- }
- if(bufferToFree != NULL) {
- kfree(bufferToFree);
- }
- return result;
-}
-int getDeviceType(struct ar3k_config_info *pConfig, u32 *code)
-{
- u8 hciCommand[] = {0x05,0xfc,0x05,0x00,0x00,0x00,0x00,0x04};
- u8 *event;
- u8 *bufferToFree = NULL;
- u32 reg;
- int result = A_ERROR;
- *code = 0;
- hciCommand[3] = (u8)(FPGA_REGISTER & 0xFF);
- hciCommand[4] = (u8)((FPGA_REGISTER >> 8) & 0xFF);
- hciCommand[5] = (u8)((FPGA_REGISTER >> 16) & 0xFF);
- hciCommand[6] = (u8)((FPGA_REGISTER >> 24) & 0xFF);
- if(0 == SendHCICommandWaitCommandComplete(pConfig,hciCommand,sizeof(hciCommand),&event,&bufferToFree)) {
-
- if(event[4] == 0xFC && event[5] == 0x00){
- switch(event[3]){
- case 0x05:
- reg = event[9];
- reg = ((reg << 8) |event[8]);
- reg = ((reg << 8) |event[7]);
- reg = ((reg << 8) |event[6]);
- *code = reg;
- result = 0;
-
- break;
- case 0x06:
- //Sleep(500);
- break;
- }
- }
-
- }
- if(bufferToFree != NULL) {
- kfree(bufferToFree);
- }
- return result;
-}
-
-
diff --git a/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.h b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.h
deleted file mode 100644
index d44351307807..000000000000
--- a/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (c) 2004-2010 Atheros Communications Inc.
- * All rights reserved.
- *
- * This file defines the symbols exported by Atheros PS and patch download module.
- * define the constant HCI_TRANSPORT_SDIO if the module is being used for HCI SDIO transport.
- * defined.
- *
- *
- * ar3kcpsconfig.h
- *
- *
- *
- * The software source and binaries included in this development package are
- * licensed, not sold. You, or your company, received the package under one
- * or more license agreements. The rights granted to you are specifically
- * listed in these license agreement(s). All other rights remain with Atheros
- * Communications, Inc., its subsidiaries, or the respective owner including
- * those listed on the included copyright notices.. Distribution of any
- * portion of this package must be in strict compliance with the license
- * agreement(s) terms.
- *
- *
- *
- */
-
-
-
-#ifndef __AR3KPSCONFIG_H
-#define __AR3KPSCONFIG_H
-
-/*
- * Define the flag HCI_TRANSPORT_SDIO and undefine HCI_TRANSPORT_UART if the transport being used is SDIO.
- */
-#undef HCI_TRANSPORT_UART
-
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-
-
-#include <linux/ioctl.h>
-#include <linux/firmware.h>
-
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-
-#include "ar3kpsparser.h"
-
-#define FPGA_REGISTER 0x4FFC
-#define BDADDR_TYPE_STRING 0
-#define BDADDR_TYPE_HEX 1
-#define CONFIG_PATH "ar3k"
-
-#define PS_ASIC_FILE "PS_ASIC.pst"
-#define PS_FPGA_FILE "PS_FPGA.pst"
-
-#define PATCH_FILE "RamPatch.txt"
-#define BDADDR_FILE "ar3kbdaddr.pst"
-
-#define ROM_VER_AR3001_3_1_0 30000
-#define ROM_VER_AR3001_3_1_1 30101
-
-
-#ifndef HCI_TRANSPORT_SDIO
-#define struct ar3k_config_info struct hci_dev
-extern wait_queue_head_t HciEvent;
-extern wait_queue_t Eventwait;
-extern u8 *HciEventpacket;
-#endif /* #ifndef HCI_TRANSPORT_SDIO */
-
-int AthPSInitialize(struct ar3k_config_info *hdev);
-int ReadPSEvent(u8* Data);
-#endif /* __AR3KPSCONFIG_H */
diff --git a/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c
deleted file mode 100644
index b99a11a9dd69..000000000000
--- a/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c
+++ /dev/null
@@ -1,969 +0,0 @@
-/*
- * Copyright (c) 2004-2010 Atheros Communications Inc.
- * All rights reserved.
- *
- * This file implements the Atheros PS and patch parser.
- * It implements APIs to parse data buffer with patch and PS information and convert it to HCI commands.
- *
- *
- *
- * ar3kpsparser.c
- *
- *
- *
- * The software source and binaries included in this development package are
- * licensed, not sold. You, or your company, received the package under one
- * or more license agreements. The rights granted to you are specifically
- * listed in these license agreement(s). All other rights remain with Atheros
- * Communications, Inc., its subsidiaries, or the respective owner including
- * those listed on the included copyright notices.. Distribution of any
- * portion of this package must be in strict compliance with the license
- * agreement(s) terms.
- *
- *
- *
- */
-
-
-#include "ar3kpsparser.h"
-
-#include <linux/ctype.h>
-#include <linux/kernel.h>
-
-#define BD_ADDR_SIZE 6
-#define WRITE_PATCH 8
-#define ENABLE_PATCH 11
-#define PS_RESET 2
-#define PS_WRITE 1
-#define PS_VERIFY_CRC 9
-#define CHANGE_BDADDR 15
-
-#define HCI_COMMAND_HEADER 7
-
-#define HCI_EVENT_SIZE 7
-
-#define WRITE_PATCH_COMMAND_STATUS_OFFSET 5
-
-#define PS_RAM_SIZE 2048
-
-#define RAM_PS_REGION (1<<0)
-#define RAM_PATCH_REGION (1<<1)
-#define RAMPS_MAX_PS_DATA_PER_TAG 20000
-#define MAX_RADIO_CFG_TABLE_SIZE 244
-#define RAMPS_MAX_PS_TAGS_PER_FILE 50
-
-#define PS_MAX_LEN 500
-#define LINE_SIZE_MAX (PS_MAX_LEN *2)
-
-/* Constant values used by parser */
-#define BYTES_OF_PS_DATA_PER_LINE 16
-#define RAMPS_MAX_PS_DATA_PER_TAG 20000
-
-
-/* Number pf PS/Patch entries in an HCI packet */
-#define MAX_BYTE_LENGTH 244
-
-#define SKIP_BLANKS(str) while (*str == ' ') str++
-
-enum MinBootFileFormatE
-{
- MB_FILEFORMAT_RADIOTBL,
- MB_FILEFORMAT_PATCH,
- MB_FILEFORMAT_COEXCONFIG
-};
-
-enum RamPsSection
-{
- RAM_PS_SECTION,
- RAM_PATCH_SECTION,
- RAM_DYN_MEM_SECTION
-};
-
-enum eType {
- eHex,
- edecimal
-};
-
-
-typedef struct tPsTagEntry
-{
- u32 TagId;
- u32 TagLen;
- u8 *TagData;
-} tPsTagEntry, *tpPsTagEntry;
-
-typedef struct tRamPatch
-{
- u16 Len;
- u8 *Data;
-} tRamPatch, *ptRamPatch;
-
-
-
-struct st_ps_data_format {
- enum eType eDataType;
- bool bIsArray;
-};
-
-struct st_read_status {
- unsigned uTagID;
- unsigned uSection;
- unsigned uLineCount;
- unsigned uCharCount;
- unsigned uByteCount;
-};
-
-
-/* Stores the number of PS Tags */
-static u32 Tag_Count = 0;
-
-/* Stores the number of patch commands */
-static u32 Patch_Count = 0;
-static u32 Total_tag_lenght = 0;
-bool BDADDR = false;
-u32 StartTagId;
-
-tPsTagEntry PsTagEntry[RAMPS_MAX_PS_TAGS_PER_FILE];
-tRamPatch RamPatch[MAX_NUM_PATCH_ENTRY];
-
-
-int AthParseFilesUnified(u8 *srcbuffer,u32 srclen, int FileFormat);
-char AthReadChar(u8 *buffer, u32 len,u32 *pos);
-char *AthGetLine(char *buffer, int maxlen, u8 *srcbuffer,u32 len,u32 *pos);
-static int AthPSCreateHCICommand(u8 Opcode, u32 Param1,struct ps_cmd_packet *PSPatchPacket,u32 *index);
-
-/* Function to reads the next character from the input buffer */
-char AthReadChar(u8 *buffer, u32 len,u32 *pos)
-{
- char Ch;
- if(buffer == NULL || *pos >=len )
- {
- return '\0';
- } else {
- Ch = buffer[*pos];
- (*pos)++;
- return Ch;
- }
-}
-/* PS parser helper function */
-unsigned int uGetInputDataFormat(char *pCharLine, struct st_ps_data_format *pstFormat)
-{
- if(pCharLine[0] != '[') {
- pstFormat->eDataType = eHex;
- pstFormat->bIsArray = true;
- return 0;
- }
- switch(pCharLine[1]) {
- case 'H':
- case 'h':
- if(pCharLine[2]==':') {
- if((pCharLine[3]== 'a') || (pCharLine[3]== 'A')) {
- if(pCharLine[4] == ']') {
- pstFormat->eDataType = eHex;
- pstFormat->bIsArray = true;
- pCharLine += 5;
- return 0;
- }
- else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format\n")); //[H:A
- return 1;
- }
- }
- if((pCharLine[3]== 'S') || (pCharLine[3]== 's')) {
- if(pCharLine[4] == ']') {
- pstFormat->eDataType = eHex;
- pstFormat->bIsArray = false;
- pCharLine += 5;
- return 0;
- }
- else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format\n")); //[H:A
- return 1;
- }
- }
- else if(pCharLine[3] == ']') { //[H:]
- pstFormat->eDataType = eHex;
- pstFormat->bIsArray = true;
- pCharLine += 4;
- return 0;
- }
- else { //[H:
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format\n"));
- return 1;
- }
- }
- else if(pCharLine[2]==']') { //[H]
- pstFormat->eDataType = eHex;
- pstFormat->bIsArray = true;
- pCharLine += 3;
- return 0;
- }
- else { //[H
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format\n"));
- return 1;
- }
- break;
-
- case 'A':
- case 'a':
- if(pCharLine[2]==':') {
- if((pCharLine[3]== 'h') || (pCharLine[3]== 'H')) {
- if(pCharLine[4] == ']') {
- pstFormat->eDataType = eHex;
- pstFormat->bIsArray = true;
- pCharLine += 5;
- return 0;
- }
- else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format 1\n")); //[A:H
- return 1;
- }
- }
- else if(pCharLine[3]== ']') { //[A:]
- pstFormat->eDataType = eHex;
- pstFormat->bIsArray = true;
- pCharLine += 4;
- return 0;
- }
- else { //[A:
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format 2\n"));
- return 1;
- }
- }
- else if(pCharLine[2]==']') { //[H]
- pstFormat->eDataType = eHex;
- pstFormat->bIsArray = true;
- pCharLine += 3;
- return 0;
- }
- else { //[H
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format 3\n"));
- return 1;
- }
- break;
-
- case 'S':
- case 's':
- if(pCharLine[2]==':') {
- if((pCharLine[3]== 'h') || (pCharLine[3]== 'H')) {
- if(pCharLine[4] == ']') {
- pstFormat->eDataType = eHex;
- pstFormat->bIsArray = true;
- pCharLine += 5;
- return 0;
- }
- else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format 5\n")); //[A:H
- return 1;
- }
- }
- else if(pCharLine[3]== ']') { //[A:]
- pstFormat->eDataType = eHex;
- pstFormat->bIsArray = true;
- pCharLine += 4;
- return 0;
- }
- else { //[A:
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format 6\n"));
- return 1;
- }
- }
- else if(pCharLine[2]==']') { //[H]
- pstFormat->eDataType = eHex;
- pstFormat->bIsArray = true;
- pCharLine += 3;
- return 0;
- }
- else { //[H
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format 7\n"));
- return 1;
- }
- break;
-
- default:
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format 8\n"));
- return 1;
- }
-}
-
-unsigned int uReadDataInSection(char *pCharLine, struct st_ps_data_format stPS_DataFormat)
-{
- char *pTokenPtr = pCharLine;
-
- if(pTokenPtr[0] == '[') {
- while(pTokenPtr[0] != ']' && pTokenPtr[0] != '\0') {
- pTokenPtr++;
- }
- if(pTokenPtr[0] == '\0') {
- return (0x0FFF);
- }
- pTokenPtr++;
-
-
- }
- if(stPS_DataFormat.eDataType == eHex) {
- if(stPS_DataFormat.bIsArray == true) {
- //Not implemented
- return (0x0FFF);
- }
- else {
- return (A_STRTOL(pTokenPtr, NULL, 16));
- }
- }
- else {
- //Not implemented
- return (0x0FFF);
- }
-}
-int AthParseFilesUnified(u8 *srcbuffer,u32 srclen, int FileFormat)
-{
- char *Buffer;
- char *pCharLine;
- u8 TagCount;
- u16 ByteCount;
- u8 ParseSection=RAM_PS_SECTION;
- u32 pos;
-
-
-
- int uReadCount;
- struct st_ps_data_format stPS_DataFormat;
- struct st_read_status stReadStatus = {0, 0, 0,0};
- pos = 0;
- Buffer = NULL;
-
- if (srcbuffer == NULL || srclen == 0)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Could not open .\n"));
- return A_ERROR;
- }
- TagCount = 0;
- ByteCount = 0;
- Buffer = A_MALLOC(LINE_SIZE_MAX + 1);
- if(NULL == Buffer) {
- return A_ERROR;
- }
- if (FileFormat == MB_FILEFORMAT_PATCH)
- {
- int LineRead = 0;
- while((pCharLine = AthGetLine(Buffer, LINE_SIZE_MAX, srcbuffer,srclen,&pos)) != NULL)
- {
-
- SKIP_BLANKS(pCharLine);
-
- // Comment line or empty line
- if ((pCharLine[0] == '/') && (pCharLine[1] == '/'))
- {
- continue;
- }
-
- if ((pCharLine[0] == '#')) {
- if (stReadStatus.uSection != 0)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("error\n"));
- if(Buffer != NULL) {
- kfree(Buffer);
- }
- return A_ERROR;
- }
- else {
- stReadStatus.uSection = 1;
- continue;
- }
- }
- if ((pCharLine[0] == '/') && (pCharLine[1] == '*'))
- {
- pCharLine+=2;
- SKIP_BLANKS(pCharLine);
-
- if(!strncmp(pCharLine,"PA",2)||!strncmp(pCharLine,"Pa",2)||!strncmp(pCharLine,"pa",2))
- ParseSection=RAM_PATCH_SECTION;
-
- if(!strncmp(pCharLine,"DY",2)||!strncmp(pCharLine,"Dy",2)||!strncmp(pCharLine,"dy",2))
- ParseSection=RAM_DYN_MEM_SECTION;
-
- if(!strncmp(pCharLine,"PS",2)||!strncmp(pCharLine,"Ps",2)||!strncmp(pCharLine,"ps",2))
- ParseSection=RAM_PS_SECTION;
-
- LineRead = 0;
- stReadStatus.uSection = 0;
-
- continue;
- }
-
- switch(ParseSection)
- {
- case RAM_PS_SECTION:
- {
- if (stReadStatus.uSection == 1) //TagID
- {
- SKIP_BLANKS(pCharLine);
- if(uGetInputDataFormat(pCharLine, &stPS_DataFormat)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("uGetInputDataFormat fail\n"));
- if(Buffer != NULL) {
- kfree(Buffer);
- }
- return A_ERROR;
- }
- //pCharLine +=5;
- PsTagEntry[TagCount].TagId = uReadDataInSection(pCharLine, stPS_DataFormat);
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" TAG ID %d \n",PsTagEntry[TagCount].TagId));
-
- //AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("tag # %x\n", PsTagEntry[TagCount].TagId);
- if (TagCount == 0)
- {
- StartTagId = PsTagEntry[TagCount].TagId;
- }
- stReadStatus.uSection = 2;
- }
- else if (stReadStatus.uSection == 2) //TagLength
- {
-
- if(uGetInputDataFormat(pCharLine, &stPS_DataFormat)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("uGetInputDataFormat fail \n"));
- if(Buffer != NULL) {
- kfree(Buffer);
- }
- return A_ERROR;
- }
- //pCharLine +=5;
- ByteCount = uReadDataInSection(pCharLine, stPS_DataFormat);
-
- //AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("tag length %x\n", ByteCount));
- if (ByteCount > LINE_SIZE_MAX/2)
- {
- if(Buffer != NULL) {
- kfree(Buffer);
- }
- return A_ERROR;
- }
- PsTagEntry[TagCount].TagLen = ByteCount;
- PsTagEntry[TagCount].TagData = (u8 *)A_MALLOC(ByteCount);
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" TAG Length %d Tag Index %d \n",PsTagEntry[TagCount].TagLen,TagCount));
- stReadStatus.uSection = 3;
- stReadStatus.uLineCount = 0;
- }
- else if( stReadStatus.uSection == 3) { //Data
-
- if(stReadStatus.uLineCount == 0) {
- if(uGetInputDataFormat(pCharLine,&stPS_DataFormat)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("uGetInputDataFormat Fail\n"));
- if(Buffer != NULL) {
- kfree(Buffer);
- }
- return A_ERROR;
- }
- //pCharLine +=5;
- }
- SKIP_BLANKS(pCharLine);
- stReadStatus.uCharCount = 0;
- if(pCharLine[stReadStatus.uCharCount] == '[') {
- while(pCharLine[stReadStatus.uCharCount] != ']' && pCharLine[stReadStatus.uCharCount] != '\0' ) {
- stReadStatus.uCharCount++;
- }
- if(pCharLine[stReadStatus.uCharCount] == ']' ) {
- stReadStatus.uCharCount++;
- } else {
- stReadStatus.uCharCount = 0;
- }
- }
- uReadCount = (ByteCount > BYTES_OF_PS_DATA_PER_LINE)? BYTES_OF_PS_DATA_PER_LINE: ByteCount;
- //AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" "));
- if((stPS_DataFormat.eDataType == eHex) && stPS_DataFormat.bIsArray == true) {
- while(uReadCount > 0) {
- PsTagEntry[TagCount].TagData[stReadStatus.uByteCount] =
- (u8)(hex_to_bin(pCharLine[stReadStatus.uCharCount]) << 4)
- | (u8)(hex_to_bin(pCharLine[stReadStatus.uCharCount + 1]));
-
- PsTagEntry[TagCount].TagData[stReadStatus.uByteCount+1] =
- (u8)(hex_to_bin(pCharLine[stReadStatus.uCharCount + 3]) << 4)
- | (u8)(hex_to_bin(pCharLine[stReadStatus.uCharCount + 4]));
-
- stReadStatus.uCharCount += 6; // read two bytes, plus a space;
- stReadStatus.uByteCount += 2;
- uReadCount -= 2;
- }
- if(ByteCount > BYTES_OF_PS_DATA_PER_LINE) {
- ByteCount -= BYTES_OF_PS_DATA_PER_LINE;
- }
- else {
- ByteCount = 0;
- }
- }
- else {
- //to be implemented
- }
-
- stReadStatus.uLineCount++;
-
- if(ByteCount == 0) {
- stReadStatus.uSection = 0;
- stReadStatus.uCharCount = 0;
- stReadStatus.uLineCount = 0;
- stReadStatus.uByteCount = 0;
- }
- else {
- stReadStatus.uCharCount = 0;
- }
-
- if((stReadStatus.uSection == 0)&&(++TagCount == RAMPS_MAX_PS_TAGS_PER_FILE))
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("\n Buffer over flow PS File too big!!!"));
- if(Buffer != NULL) {
- kfree(Buffer);
- }
- return A_ERROR;
- //Sleep (3000);
- //exit(1);
- }
-
- }
- }
-
- break;
- default:
- {
- if(Buffer != NULL) {
- kfree(Buffer);
- }
- return A_ERROR;
- }
- break;
- }
- LineRead++;
- }
- Tag_Count = TagCount;
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Number of Tags %d\n", Tag_Count));
- }
-
-
- if (TagCount > RAMPS_MAX_PS_TAGS_PER_FILE)
- {
-
- if(Buffer != NULL) {
- kfree(Buffer);
- }
- return A_ERROR;
- }
-
- if(Buffer != NULL) {
- kfree(Buffer);
- }
- return 0;
-
-}
-
-
-
-/********************/
-
-
-int GetNextTwoChar(u8 *srcbuffer,u32 len, u32 *pos, char *buffer)
-{
- unsigned char ch;
-
- ch = AthReadChar(srcbuffer,len,pos);
- if(ch != '\0' && isxdigit(ch)) {
- buffer[0] = ch;
- } else
- {
- return A_ERROR;
- }
- ch = AthReadChar(srcbuffer,len,pos);
- if(ch != '\0' && isxdigit(ch)) {
- buffer[1] = ch;
- } else
- {
- return A_ERROR;
- }
- return 0;
-}
-
-int AthDoParsePatch(u8 *patchbuffer, u32 patchlen)
-{
-
- char Byte[3];
- char Line[MAX_BYTE_LENGTH + 1];
- int ByteCount,ByteCount_Org;
- int count;
- int i,j,k;
- int data;
- u32 filepos;
- Byte[2] = '\0';
- j = 0;
- filepos = 0;
- Patch_Count = 0;
-
- while(NULL != AthGetLine(Line,MAX_BYTE_LENGTH,patchbuffer,patchlen,&filepos)) {
- if(strlen(Line) <= 1 || !isxdigit(Line[0])) {
- continue;
- } else {
- break;
- }
- }
- ByteCount = A_STRTOL(Line, NULL, 16);
- ByteCount_Org = ByteCount;
-
- while(ByteCount > MAX_BYTE_LENGTH){
-
- /* Handle case when the number of patch buffer is more than the 20K */
- if(MAX_NUM_PATCH_ENTRY == Patch_Count) {
- for(i = 0; i < Patch_Count; i++) {
- kfree(RamPatch[i].Data);
- }
- return A_ERROR;
- }
- RamPatch[Patch_Count].Len= MAX_BYTE_LENGTH;
- RamPatch[Patch_Count].Data = (u8 *)A_MALLOC(MAX_BYTE_LENGTH);
- Patch_Count ++;
-
-
- ByteCount= ByteCount - MAX_BYTE_LENGTH;
- }
-
- RamPatch[Patch_Count].Len= (ByteCount & 0xFF);
- if(ByteCount != 0) {
- RamPatch[Patch_Count].Data = (u8 *)A_MALLOC(ByteCount);
- Patch_Count ++;
- }
- count = 0;
- while(ByteCount_Org > MAX_BYTE_LENGTH){
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" Index [%d]\n",j));
- for (i = 0,k=0; i < MAX_BYTE_LENGTH*2; i += 2,k++,count +=2) {
- if(GetNextTwoChar(patchbuffer,patchlen,&filepos,Byte) == A_ERROR) {
- return A_ERROR;
- }
- data = A_STRTOUL(&Byte[0], NULL, 16);
- RamPatch[j].Data[k] = (data & 0xFF);
-
-
- }
- j++;
- ByteCount_Org = ByteCount_Org - MAX_BYTE_LENGTH;
- }
- if(j == 0){
- j++;
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" Index [%d]\n",j));
- for (k=0; k < ByteCount_Org; i += 2,k++,count+=2) {
- if(GetNextTwoChar(patchbuffer,patchlen,&filepos,Byte) == A_ERROR) {
- return A_ERROR;
- }
- data = A_STRTOUL(Byte, NULL, 16);
- RamPatch[j].Data[k] = (data & 0xFF);
-
-
- }
- return 0;
-}
-
-
-/********************/
-int AthDoParsePS(u8 *srcbuffer, u32 srclen)
-{
- int status;
- int i;
- bool BDADDR_Present = false;
-
- Tag_Count = 0;
-
- Total_tag_lenght = 0;
- BDADDR = false;
-
-
- status = A_ERROR;
-
- if(NULL != srcbuffer && srclen != 0)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("File Open Operation Successful\n"));
-
- status = AthParseFilesUnified(srcbuffer,srclen,MB_FILEFORMAT_PATCH);
- }
-
-
-
- if(Tag_Count == 0){
- Total_tag_lenght = 10;
-
- }
- else{
- for(i=0; i<Tag_Count; i++){
- if(PsTagEntry[i].TagId == 1){
- BDADDR_Present = true;
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BD ADDR is present in Patch File \r\n"));
-
- }
- if(PsTagEntry[i].TagLen % 2 == 1){
- Total_tag_lenght = Total_tag_lenght + PsTagEntry[i].TagLen + 1;
- }
- else{
- Total_tag_lenght = Total_tag_lenght + PsTagEntry[i].TagLen;
- }
-
- }
- }
-
- if(Tag_Count > 0 && !BDADDR_Present){
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BD ADDR is not present adding 10 extra bytes \r\n"));
- Total_tag_lenght=Total_tag_lenght + 10;
- }
- Total_tag_lenght = Total_tag_lenght+ 10 + (Tag_Count*4);
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("** Total Length %d\n",Total_tag_lenght));
-
-
- return status;
-}
-char *AthGetLine(char *buffer, int maxlen, u8 *srcbuffer,u32 len,u32 *pos)
-{
-
- int count;
- static short flag;
- char CharRead;
- count = 0;
- flag = A_ERROR;
-
- do
- {
- CharRead = AthReadChar(srcbuffer,len,pos);
- if( CharRead == '\0' ) {
- buffer[count+1] = '\0';
- if(count == 0) {
- return NULL;
- }
- else {
- return buffer;
- }
- }
-
- if(CharRead == 13) {
- } else if(CharRead == 10) {
- buffer[count] ='\0';
- flag = A_ERROR;
- return buffer;
- }else {
- buffer[count++] = CharRead;
- }
-
- }
- while(count < maxlen-1 && CharRead != '\0');
- buffer[count] = '\0';
-
- return buffer;
-}
-
-static void LoadHeader(u8 *HCI_PS_Command,u8 opcode,int length,int index){
-
- HCI_PS_Command[0]= 0x0B;
- HCI_PS_Command[1]= 0xFC;
- HCI_PS_Command[2]= length + 4;
- HCI_PS_Command[3]= opcode;
- HCI_PS_Command[4]= (index & 0xFF);
- HCI_PS_Command[5]= ((index>>8) & 0xFF);
- HCI_PS_Command[6]= length;
-}
-
-/////////////////////////
-//
-int AthCreateCommandList(struct ps_cmd_packet **HciPacketList, u32 *numPackets)
-{
-
- u8 count;
- u32 NumcmdEntry = 0;
-
- u32 Crc = 0;
- *numPackets = 0;
-
-
- if(Patch_Count > 0)
- Crc |= RAM_PATCH_REGION;
- if(Tag_Count > 0)
- Crc |= RAM_PS_REGION;
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("PS Thread Started CRC %x Patch Count %d Tag Count %d \n",Crc,Patch_Count,Tag_Count));
-
- if(Patch_Count || Tag_Count ){
- NumcmdEntry+=(2 + Patch_Count + Tag_Count); /* CRC Packet + PS Reset Packet + Patch List + PS List*/
- if(Patch_Count > 0) {
- NumcmdEntry++; /* Patch Enable Command */
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Num Cmd Entries %d Size %d \r\n",NumcmdEntry,(u32)sizeof(struct ps_cmd_packet) * NumcmdEntry));
- (*HciPacketList) = A_MALLOC(sizeof(struct ps_cmd_packet) * NumcmdEntry);
- if(NULL == *HciPacketList) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("memory allocation failed \r\n"));
- }
- AthPSCreateHCICommand(PS_VERIFY_CRC,Crc,*HciPacketList,numPackets);
- if(Patch_Count > 0){
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("*** Write Patch**** \r\n"));
- AthPSCreateHCICommand(WRITE_PATCH,Patch_Count,*HciPacketList,numPackets);
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("*** Enable Patch**** \r\n"));
- AthPSCreateHCICommand(ENABLE_PATCH,0,*HciPacketList,numPackets);
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("*** PS Reset**** %d[0x%x] \r\n",PS_RAM_SIZE,PS_RAM_SIZE));
- AthPSCreateHCICommand(PS_RESET,PS_RAM_SIZE,*HciPacketList,numPackets);
- if(Tag_Count > 0){
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("*** PS Write**** \r\n"));
- AthPSCreateHCICommand(PS_WRITE,Tag_Count,*HciPacketList,numPackets);
- }
- }
- if(!BDADDR){
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BD ADDR not present \r\n"));
-
- }
- for(count = 0; count < Patch_Count; count++) {
-
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Freeing Patch Buffer %d \r\n",count));
- kfree(RamPatch[count].Data);
- }
-
- for(count = 0; count < Tag_Count; count++) {
-
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Freeing PS Buffer %d \r\n",count));
- kfree(PsTagEntry[count].TagData);
- }
-
-/*
- * SDIO Transport uses synchronous mode of data transfer
- * So, AthPSOperations() call returns only after receiving the
- * command complete event.
- */
- return *numPackets;
-}
-
-
-////////////////////////
-
-/////////////
-static int AthPSCreateHCICommand(u8 Opcode, u32 Param1,struct ps_cmd_packet *PSPatchPacket,u32 *index)
-{
- u8 *HCI_PS_Command;
- u32 Length;
- int i,j;
-
- switch(Opcode)
- {
- case WRITE_PATCH:
-
-
- for(i=0;i< Param1;i++){
-
- HCI_PS_Command = (u8 *) A_MALLOC(RamPatch[i].Len+HCI_COMMAND_HEADER);
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Allocated Buffer Size %d\n",RamPatch[i].Len+HCI_COMMAND_HEADER));
- if(HCI_PS_Command == NULL){
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("MALLOC Failed\r\n"));
- return A_ERROR;
- }
- memset (HCI_PS_Command, 0, RamPatch[i].Len+HCI_COMMAND_HEADER);
- LoadHeader(HCI_PS_Command,Opcode,RamPatch[i].Len,i);
- for(j=0;j<RamPatch[i].Len;j++){
- HCI_PS_Command[HCI_COMMAND_HEADER+j]=RamPatch[i].Data[j];
- }
- PSPatchPacket[*index].Hcipacket = HCI_PS_Command;
- PSPatchPacket[*index].packetLen = RamPatch[i].Len+HCI_COMMAND_HEADER;
- (*index)++;
-
-
- }
-
- break;
-
- case ENABLE_PATCH:
-
-
- Length = 0;
- i= 0;
- HCI_PS_Command = (u8 *) A_MALLOC(Length+HCI_COMMAND_HEADER);
- if(HCI_PS_Command == NULL){
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("MALLOC Failed\r\n"));
- return A_ERROR;
- }
-
- memset (HCI_PS_Command, 0, Length+HCI_COMMAND_HEADER);
- LoadHeader(HCI_PS_Command,Opcode,Length,i);
- PSPatchPacket[*index].Hcipacket = HCI_PS_Command;
- PSPatchPacket[*index].packetLen = Length+HCI_COMMAND_HEADER;
- (*index)++;
-
- break;
-
- case PS_RESET:
- Length = 0x06;
- i=0;
- HCI_PS_Command = (u8 *) A_MALLOC(Length+HCI_COMMAND_HEADER);
- if(HCI_PS_Command == NULL){
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("MALLOC Failed\r\n"));
- return A_ERROR;
- }
- memset (HCI_PS_Command, 0, Length+HCI_COMMAND_HEADER);
- LoadHeader(HCI_PS_Command,Opcode,Length,i);
- HCI_PS_Command[7]= 0x00;
- HCI_PS_Command[Length+HCI_COMMAND_HEADER -2]= (Param1 & 0xFF);
- HCI_PS_Command[Length+HCI_COMMAND_HEADER -1]= ((Param1 >> 8) & 0xFF);
- PSPatchPacket[*index].Hcipacket = HCI_PS_Command;
- PSPatchPacket[*index].packetLen = Length+HCI_COMMAND_HEADER;
- (*index)++;
-
- break;
-
- case PS_WRITE:
- for(i=0;i< Param1;i++){
- if(PsTagEntry[i].TagId ==1)
- BDADDR = true;
-
- HCI_PS_Command = (u8 *) A_MALLOC(PsTagEntry[i].TagLen+HCI_COMMAND_HEADER);
- if(HCI_PS_Command == NULL){
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("MALLOC Failed\r\n"));
- return A_ERROR;
- }
-
- memset (HCI_PS_Command, 0, PsTagEntry[i].TagLen+HCI_COMMAND_HEADER);
- LoadHeader(HCI_PS_Command,Opcode,PsTagEntry[i].TagLen,PsTagEntry[i].TagId);
-
- for(j=0;j<PsTagEntry[i].TagLen;j++){
- HCI_PS_Command[HCI_COMMAND_HEADER+j]=PsTagEntry[i].TagData[j];
- }
-
- PSPatchPacket[*index].Hcipacket = HCI_PS_Command;
- PSPatchPacket[*index].packetLen = PsTagEntry[i].TagLen+HCI_COMMAND_HEADER;
- (*index)++;
-
- }
-
- break;
-
-
- case PS_VERIFY_CRC:
- Length = 0x0;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("VALUE of CRC:%d At index %d\r\n",Param1,*index));
-
- HCI_PS_Command = (u8 *) A_MALLOC(Length+HCI_COMMAND_HEADER);
- if(HCI_PS_Command == NULL){
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("MALLOC Failed\r\n"));
- return A_ERROR;
- }
- memset (HCI_PS_Command, 0, Length+HCI_COMMAND_HEADER);
- LoadHeader(HCI_PS_Command,Opcode,Length,Param1);
-
- PSPatchPacket[*index].Hcipacket = HCI_PS_Command;
- PSPatchPacket[*index].packetLen = Length+HCI_COMMAND_HEADER;
- (*index)++;
-
- break;
-
- case CHANGE_BDADDR:
- break;
- }
- return 0;
-}
-int AthFreeCommandList(struct ps_cmd_packet **HciPacketList, u32 numPackets)
-{
- int i;
- if(*HciPacketList == NULL) {
- return A_ERROR;
- }
- for(i = 0; i < numPackets;i++) {
- kfree((*HciPacketList)[i].Hcipacket);
- }
- kfree(*HciPacketList);
- return 0;
-}
diff --git a/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.h b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.h
deleted file mode 100644
index 4e0f2f713a40..000000000000
--- a/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.h
+++ /dev/null
@@ -1,113 +0,0 @@
-//------------------------------------------------------------------------------
-//
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//
-// This file is the include file for Atheros PS and patch parser.
-// It implements APIs to parse data buffer with patch and PS information and convert it to HCI commands.
-//
-
-#ifndef __AR3KPSPARSER_H
-#define __AR3KPSPARSER_H
-
-
-
-
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include "athdefs.h"
-#ifdef HCI_TRANSPORT_SDIO
-#include "a_config.h"
-#include "a_osapi.h"
-#define ATH_MODULE_NAME misc
-#include "a_debug.h"
-#include "common_drv.h"
-#include "hci_transport_api.h"
-#include "ar3kconfig.h"
-#else
-#ifndef A_PRINTF
-#define A_PRINTF(args...) printk(KERN_ALERT args)
-#endif /* A_PRINTF */
-#include "debug_linux.h"
-
-/* Helper data type declaration */
-
-#define ATH_DEBUG_ERR (1 << 0)
-#define ATH_DEBUG_WARN (1 << 1)
-#define ATH_DEBUG_INFO (1 << 2)
-
-
-
-#define false 0
-#define true 1
-
-#ifndef A_MALLOC
-#define A_MALLOC(size) kmalloc((size),GFP_KERNEL)
-#endif /* A_MALLOC */
-#endif /* HCI_TRANSPORT_UART */
-
-/* String manipulation APIs */
-#ifndef A_STRTOUL
-#define A_STRTOUL simple_strtoul
-#endif /* A_STRTOL */
-
-#ifndef A_STRTOL
-#define A_STRTOL simple_strtol
-#endif /* A_STRTOL */
-
-
-/* The maximum number of bytes possible in a patch entry */
-#define MAX_PATCH_SIZE 20000
-
-/* Maximum HCI packets that will be formed from the Patch file */
-#define MAX_NUM_PATCH_ENTRY (MAX_PATCH_SIZE/MAX_BYTE_LENGTH) + 1
-
-
-
-
-
-
-
-struct ps_cmd_packet
-{
- u8 *Hcipacket;
- int packetLen;
-};
-
-/* Parses a Patch information buffer and store it in global structure */
-int AthDoParsePatch(u8 *, u32 );
-
-/* parses a PS information buffer and stores it in a global structure */
-int AthDoParsePS(u8 *, u32 );
-
-/*
- * Uses the output of Both AthDoParsePS and AthDoParsePatch APIs to form HCI command array with
- * all the PS and patch commands.
- * The list will have the below mentioned commands in order.
- * CRC command packet
- * Download patch command(s)
- * Enable patch Command
- * PS Reset Command
- * PS Tag Command(s)
- *
- */
-int AthCreateCommandList(struct ps_cmd_packet **, u32 *);
-
-/* Cleanup the dynamically allicated HCI command list */
-int AthFreeCommandList(struct ps_cmd_packet **HciPacketList, u32 numPackets);
-#endif /* __AR3KPSPARSER_H */
diff --git a/drivers/staging/ath6kl/miscdrv/common_drv.c b/drivers/staging/ath6kl/miscdrv/common_drv.c
deleted file mode 100644
index 1ce539aa019b..000000000000
--- a/drivers/staging/ath6kl/miscdrv/common_drv.c
+++ /dev/null
@@ -1,910 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="common_drv.c" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-
-#include "a_config.h"
-#include "athdefs.h"
-
-#include "hw/mbox_host_reg.h"
-#include "gpio_reg.h"
-#include "hw/rtc_reg.h"
-#include "hw/mbox_reg.h"
-#include "hw/apb_map.h"
-
-#include "a_osapi.h"
-#include "targaddrs.h"
-#include "hif.h"
-#include "htc_api.h"
-#include "wmi.h"
-#include "bmi.h"
-#include "bmi_msg.h"
-#include "common_drv.h"
-#define ATH_MODULE_NAME misc
-#include "a_debug.h"
-#include "ar6000_diag.h"
-
-static ATH_DEBUG_MODULE_DBG_INFO *g_pModuleInfoHead = NULL;
-static A_MUTEX_T g_ModuleListLock;
-static bool g_ModuleDebugInit = false;
-
-#ifdef ATH_DEBUG_MODULE
-
-ATH_DEBUG_INSTANTIATE_MODULE_VAR(misc,
- "misc",
- "Common and misc APIs",
- ATH_DEBUG_MASK_DEFAULTS,
- 0,
- NULL);
-
-#endif
-
-#define HOST_INTEREST_ITEM_ADDRESS(target, item) \
- ((((target) == TARGET_TYPE_AR6002) ? AR6002_HOST_INTEREST_ITEM_ADDRESS(item) : \
- (((target) == TARGET_TYPE_AR6003) ? AR6003_HOST_INTEREST_ITEM_ADDRESS(item) : 0)))
-
-
-#define AR6001_LOCAL_COUNT_ADDRESS 0x0c014080
-#define AR6002_LOCAL_COUNT_ADDRESS 0x00018080
-#define AR6003_LOCAL_COUNT_ADDRESS 0x00018080
-#define CPU_DBG_SEL_ADDRESS 0x00000483
-#define CPU_DBG_ADDRESS 0x00000484
-
-static u8 custDataAR6002[AR6002_CUST_DATA_SIZE];
-static u8 custDataAR6003[AR6003_CUST_DATA_SIZE];
-
-/* Compile the 4BYTE version of the window register setup routine,
- * This mitigates host interconnect issues with non-4byte aligned bus requests, some
- * interconnects use bus adapters that impose strict limitations.
- * Since diag window access is not intended for performance critical operations, the 4byte mode should
- * be satisfactory even though it generates 4X the bus activity. */
-
-#ifdef USE_4BYTE_REGISTER_ACCESS
-
- /* set the window address register (using 4-byte register access ). */
-int ar6000_SetAddressWindowRegister(struct hif_device *hifDevice, u32 RegisterAddr, u32 Address)
-{
- int status;
- u8 addrValue[4];
- s32 i;
-
- /* write bytes 1,2,3 of the register to set the upper address bytes, the LSB is written
- * last to initiate the access cycle */
-
- for (i = 1; i <= 3; i++) {
- /* fill the buffer with the address byte value we want to hit 4 times*/
- addrValue[0] = ((u8 *)&Address)[i];
- addrValue[1] = addrValue[0];
- addrValue[2] = addrValue[0];
- addrValue[3] = addrValue[0];
-
- /* hit each byte of the register address with a 4-byte write operation to the same address,
- * this is a harmless operation */
- status = HIFReadWrite(hifDevice,
- RegisterAddr+i,
- addrValue,
- 4,
- HIF_WR_SYNC_BYTE_FIX,
- NULL);
- if (status) {
- break;
- }
- }
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write initial bytes of 0x%x to window reg: 0x%X \n",
- Address, RegisterAddr));
- return status;
- }
-
- /* write the address register again, this time write the whole 4-byte value.
- * The effect here is that the LSB write causes the cycle to start, the extra
- * 3 byte write to bytes 1,2,3 has no effect since we are writing the same values again */
- status = HIFReadWrite(hifDevice,
- RegisterAddr,
- (u8 *)(&Address),
- 4,
- HIF_WR_SYNC_BYTE_INC,
- NULL);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write 0x%x to window reg: 0x%X \n",
- Address, RegisterAddr));
- return status;
- }
-
- return 0;
-
-
-
-}
-
-
-#else
-
- /* set the window address register */
-int ar6000_SetAddressWindowRegister(struct hif_device *hifDevice, u32 RegisterAddr, u32 Address)
-{
- int status;
-
- /* write bytes 1,2,3 of the register to set the upper address bytes, the LSB is written
- * last to initiate the access cycle */
- status = HIFReadWrite(hifDevice,
- RegisterAddr+1, /* write upper 3 bytes */
- ((u8 *)(&Address))+1,
- sizeof(u32)-1,
- HIF_WR_SYNC_BYTE_INC,
- NULL);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write initial bytes of 0x%x to window reg: 0x%X \n",
- RegisterAddr, Address));
- return status;
- }
-
- /* write the LSB of the register, this initiates the operation */
- status = HIFReadWrite(hifDevice,
- RegisterAddr,
- (u8 *)(&Address),
- sizeof(u8),
- HIF_WR_SYNC_BYTE_INC,
- NULL);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write 0x%x to window reg: 0x%X \n",
- RegisterAddr, Address));
- return status;
- }
-
- return 0;
-}
-
-#endif
-
-/*
- * Read from the AR6000 through its diagnostic window.
- * No cooperation from the Target is required for this.
- */
-int
-ar6000_ReadRegDiag(struct hif_device *hifDevice, u32 *address, u32 *data)
-{
- int status;
-
- /* set window register to start read cycle */
- status = ar6000_SetAddressWindowRegister(hifDevice,
- WINDOW_READ_ADDR_ADDRESS,
- *address);
-
- if (status) {
- return status;
- }
-
- /* read the data */
- status = HIFReadWrite(hifDevice,
- WINDOW_DATA_ADDRESS,
- (u8 *)data,
- sizeof(u32),
- HIF_RD_SYNC_BYTE_INC,
- NULL);
- if (status) {
- AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot read from WINDOW_DATA_ADDRESS\n"));
- return status;
- }
-
- return status;
-}
-
-
-/*
- * Write to the AR6000 through its diagnostic window.
- * No cooperation from the Target is required for this.
- */
-int
-ar6000_WriteRegDiag(struct hif_device *hifDevice, u32 *address, u32 *data)
-{
- int status;
-
- /* set write data */
- status = HIFReadWrite(hifDevice,
- WINDOW_DATA_ADDRESS,
- (u8 *)data,
- sizeof(u32),
- HIF_WR_SYNC_BYTE_INC,
- NULL);
- if (status) {
- AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write 0x%x to WINDOW_DATA_ADDRESS\n", *data));
- return status;
- }
-
- /* set window register, which starts the write cycle */
- return ar6000_SetAddressWindowRegister(hifDevice,
- WINDOW_WRITE_ADDR_ADDRESS,
- *address);
- }
-
-int
-ar6000_ReadDataDiag(struct hif_device *hifDevice, u32 address,
- u8 *data, u32 length)
-{
- u32 count;
- int status = 0;
-
- for (count = 0; count < length; count += 4, address += 4) {
- if ((status = ar6000_ReadRegDiag(hifDevice, &address,
- (u32 *)&data[count])) != 0)
- {
- break;
- }
- }
-
- return status;
-}
-
-int
-ar6000_WriteDataDiag(struct hif_device *hifDevice, u32 address,
- u8 *data, u32 length)
-{
- u32 count;
- int status = 0;
-
- for (count = 0; count < length; count += 4, address += 4) {
- if ((status = ar6000_WriteRegDiag(hifDevice, &address,
- (u32 *)&data[count])) != 0)
- {
- break;
- }
- }
-
- return status;
-}
-
-int
-ar6k_ReadTargetRegister(struct hif_device *hifDevice, int regsel, u32 *regval)
-{
- int status;
- u8 vals[4];
- u8 register_selection[4];
-
- register_selection[0] = register_selection[1] = register_selection[2] = register_selection[3] = (regsel & 0xff);
- status = HIFReadWrite(hifDevice,
- CPU_DBG_SEL_ADDRESS,
- register_selection,
- 4,
- HIF_WR_SYNC_BYTE_FIX,
- NULL);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write CPU_DBG_SEL (%d)\n", regsel));
- return status;
- }
-
- status = HIFReadWrite(hifDevice,
- CPU_DBG_ADDRESS,
- (u8 *)vals,
- sizeof(vals),
- HIF_RD_SYNC_BYTE_INC,
- NULL);
- if (status) {
- AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot read from CPU_DBG_ADDRESS\n"));
- return status;
- }
-
- *regval = vals[0]<<0 | vals[1]<<8 | vals[2]<<16 | vals[3]<<24;
-
- return status;
-}
-
-void
-ar6k_FetchTargetRegs(struct hif_device *hifDevice, u32 *targregs)
-{
- int i;
- u32 val;
-
- for (i=0; i<AR6003_FETCH_TARG_REGS_COUNT; i++) {
- val=0xffffffff;
- (void)ar6k_ReadTargetRegister(hifDevice, i, &val);
- targregs[i] = val;
- }
-}
-
-#if 0
-static int
-_do_write_diag(struct hif_device *hifDevice, u32 addr, u32 value)
-{
- int status;
-
- status = ar6000_WriteRegDiag(hifDevice, &addr, &value);
- if (status)
- {
- AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot force Target to execute ROM!\n"));
- }
-
- return status;
-}
-#endif
-
-
-/*
- * Delay up to wait_msecs millisecs to allow Target to enter BMI phase,
- * which is a good sign that it's alive and well. This is used after
- * explicitly forcing the Target to reset.
- *
- * The wait_msecs time should be sufficiently long to cover any reasonable
- * boot-time delay. For instance, AR6001 firmware allow one second for a
- * low frequency crystal to settle before it calibrates the refclk frequency.
- *
- * TBD: Might want to add special handling for AR6K_OPTION_BMI_DISABLE.
- */
-#if 0
-static int
-_delay_until_target_alive(struct hif_device *hifDevice, s32 wait_msecs, u32 TargetType)
-{
- s32 actual_wait;
- s32 i;
- u32 address;
-
- actual_wait = 0;
-
- /* Hardcode the address of LOCAL_COUNT_ADDRESS based on the target type */
- if (TargetType == TARGET_TYPE_AR6002) {
- address = AR6002_LOCAL_COUNT_ADDRESS;
- } else if (TargetType == TARGET_TYPE_AR6003) {
- address = AR6003_LOCAL_COUNT_ADDRESS;
- } else {
- A_ASSERT(0);
- }
- address += 0x10;
- for (i=0; actual_wait < wait_msecs; i++) {
- u32 data;
-
- A_MDELAY(100);
- actual_wait += 100;
-
- data = 0;
- if (ar6000_ReadRegDiag(hifDevice, &address, &data) != 0) {
- return A_ERROR;
- }
-
- if (data != 0) {
- /* No need to wait longer -- we have a BMI credit */
- return 0;
- }
- }
- return A_ERROR; /* timed out */
-}
-#endif
-
-#define AR6001_RESET_CONTROL_ADDRESS 0x0C000000
-#define AR6002_RESET_CONTROL_ADDRESS 0x00004000
-#define AR6003_RESET_CONTROL_ADDRESS 0x00004000
-/* reset device */
-int ar6000_reset_device(struct hif_device *hifDevice, u32 TargetType, bool waitForCompletion, bool coldReset)
-{
- int status = 0;
- u32 address;
- u32 data;
-
- do {
-// Workaround BEGIN
- // address = RESET_CONTROL_ADDRESS;
-
- if (coldReset) {
- data = RESET_CONTROL_COLD_RST_MASK;
- }
- else {
- data = RESET_CONTROL_MBOX_RST_MASK;
- }
-
- /* Hardcode the address of RESET_CONTROL_ADDRESS based on the target type */
- if (TargetType == TARGET_TYPE_AR6002) {
- address = AR6002_RESET_CONTROL_ADDRESS;
- } else if (TargetType == TARGET_TYPE_AR6003) {
- address = AR6003_RESET_CONTROL_ADDRESS;
- } else {
- A_ASSERT(0);
- }
-
-
- status = ar6000_WriteRegDiag(hifDevice, &address, &data);
-
- if (status) {
- break;
- }
-
- if (!waitForCompletion) {
- break;
- }
-
-#if 0
- /* Up to 2 second delay to allow things to settle down */
- (void)_delay_until_target_alive(hifDevice, 2000, TargetType);
-
- /*
- * Read back the RESET CAUSE register to ensure that the cold reset
- * went through.
- */
-
- // address = RESET_CAUSE_ADDRESS;
- /* Hardcode the address of RESET_CAUSE_ADDRESS based on the target type */
- if (TargetType == TARGET_TYPE_AR6002) {
- address = 0x000040C0;
- } else if (TargetType == TARGET_TYPE_AR6003) {
- address = 0x000040C0;
- } else {
- A_ASSERT(0);
- }
-
- data = 0;
- status = ar6000_ReadRegDiag(hifDevice, &address, &data);
-
- if (status) {
- break;
- }
-
- AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Reset Cause readback: 0x%X \n",data));
- data &= RESET_CAUSE_LAST_MASK;
- if (data != 2) {
- AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Unable to cold reset the target \n"));
- }
-#endif
-// Workaroud END
-
- } while (false);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Failed to reset target \n"));
- }
-
- return 0;
-}
-
-/* This should be called in BMI phase after firmware is downloaded */
-void
-ar6000_copy_cust_data_from_target(struct hif_device *hifDevice, u32 TargetType)
-{
- u32 eepHeaderAddr;
- u8 AR6003CustDataShadow[AR6003_CUST_DATA_SIZE+4];
- s32 i;
-
- if (BMIReadMemory(hifDevice,
- HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_board_data),
- (u8 *)&eepHeaderAddr,
- 4)!= 0)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMIReadMemory for reading board data address failed \n"));
- return;
- }
-
- if (TargetType == TARGET_TYPE_AR6003) {
- eepHeaderAddr += 36; /* AR6003 customer data section offset is 37 */
-
- for (i=0; i<AR6003_CUST_DATA_SIZE+4; i+=4){
- if (BMIReadSOCRegister(hifDevice, eepHeaderAddr, (u32 *)&AR6003CustDataShadow[i])!= 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMIReadSOCRegister () failed \n"));
- return ;
- }
- eepHeaderAddr +=4;
- }
-
- memcpy(custDataAR6003, AR6003CustDataShadow+1, AR6003_CUST_DATA_SIZE);
- }
-
- if (TargetType == TARGET_TYPE_AR6002) {
- eepHeaderAddr += 64; /* AR6002 customer data sectioin offset is 64 */
-
- for (i=0; i<AR6002_CUST_DATA_SIZE; i+=4){
- if (BMIReadSOCRegister(hifDevice, eepHeaderAddr, (u32 *)&custDataAR6002[i])!= 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMIReadSOCRegister () failed \n"));
- return ;
- }
- eepHeaderAddr +=4;
- }
- }
-
- return;
-}
-
-/* This is the function to call when need to use the cust data */
-u8 *ar6000_get_cust_data_buffer(u32 TargetType)
-{
- if (TargetType == TARGET_TYPE_AR6003)
- return custDataAR6003;
-
- if (TargetType == TARGET_TYPE_AR6002)
- return custDataAR6002;
-
- return NULL;
-}
-
-#define REG_DUMP_COUNT_AR6001 38 /* WORDs, derived from AR600x_regdump.h */
-#define REG_DUMP_COUNT_AR6002 60
-#define REG_DUMP_COUNT_AR6003 60
-#define REGISTER_DUMP_LEN_MAX 60
-#if REG_DUMP_COUNT_AR6001 > REGISTER_DUMP_LEN_MAX
-#error "REG_DUMP_COUNT_AR6001 too large"
-#endif
-#if REG_DUMP_COUNT_AR6002 > REGISTER_DUMP_LEN_MAX
-#error "REG_DUMP_COUNT_AR6002 too large"
-#endif
-#if REG_DUMP_COUNT_AR6003 > REGISTER_DUMP_LEN_MAX
-#error "REG_DUMP_COUNT_AR6003 too large"
-#endif
-
-
-void ar6000_dump_target_assert_info(struct hif_device *hifDevice, u32 TargetType)
-{
- u32 address;
- u32 regDumpArea = 0;
- int status;
- u32 regDumpValues[REGISTER_DUMP_LEN_MAX];
- u32 regDumpCount = 0;
- u32 i;
-
- do {
-
- /* the reg dump pointer is copied to the host interest area */
- address = HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_failure_state);
- address = TARG_VTOP(TargetType, address);
-
- if (TargetType == TARGET_TYPE_AR6002) {
- regDumpCount = REG_DUMP_COUNT_AR6002;
- } else if (TargetType == TARGET_TYPE_AR6003) {
- regDumpCount = REG_DUMP_COUNT_AR6003;
- } else {
- A_ASSERT(0);
- }
-
- /* read RAM location through diagnostic window */
- status = ar6000_ReadRegDiag(hifDevice, &address, &regDumpArea);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Failed to get ptr to register dump area \n"));
- break;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Location of register dump data: 0x%X \n",regDumpArea));
-
- if (regDumpArea == 0) {
- /* no reg dump */
- break;
- }
-
- regDumpArea = TARG_VTOP(TargetType, regDumpArea);
-
- /* fetch register dump data */
- status = ar6000_ReadDataDiag(hifDevice,
- regDumpArea,
- (u8 *)&regDumpValues[0],
- regDumpCount * (sizeof(u32)));
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Failed to get register dump \n"));
- break;
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Register Dump: \n"));
-
- for (i = 0; i < regDumpCount; i++) {
- //ATHR_DISPLAY_MSG (_T(" %d : 0x%8.8X \n"), i, regDumpValues[i]);
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" %d : 0x%8.8X \n",i, regDumpValues[i]));
-
-#ifdef UNDER_CE
- /*
- * For Every logPrintf() Open the File so that in case of Crashes
- * We will have until the Last Message Flushed on to the File
- * So use logPrintf Sparingly..!!
- */
- tgtassertPrintf (ATH_DEBUG_TRC," %d: 0x%8.8X \n",i, regDumpValues[i]);
-#endif
- }
-
- } while (false);
-
-}
-
-/* set HTC/Mbox operational parameters, this can only be called when the target is in the
- * BMI phase */
-int ar6000_set_htc_params(struct hif_device *hifDevice,
- u32 TargetType,
- u32 MboxIsrYieldValue,
- u8 HtcControlBuffers)
-{
- int status;
- u32 blocksizes[HTC_MAILBOX_NUM_MAX];
-
- do {
- /* get the block sizes */
- status = HIFConfigureDevice(hifDevice, HIF_DEVICE_GET_MBOX_BLOCK_SIZE,
- blocksizes, sizeof(blocksizes));
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_LOG_ERR,("Failed to get block size info from HIF layer...\n"));
- break;
- }
- /* note: we actually get the block size for mailbox 1, for SDIO the block
- * size on mailbox 0 is artificially set to 1 */
- /* must be a power of 2 */
- A_ASSERT((blocksizes[1] & (blocksizes[1] - 1)) == 0);
-
- if (HtcControlBuffers != 0) {
- /* set override for number of control buffers to use */
- blocksizes[1] |= ((u32)HtcControlBuffers) << 16;
- }
-
- /* set the host interest area for the block size */
- status = BMIWriteMemory(hifDevice,
- HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_mbox_io_block_sz),
- (u8 *)&blocksizes[1],
- 4);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_LOG_ERR,("BMIWriteMemory for IO block size failed \n"));
- break;
- }
-
- AR_DEBUG_PRINTF(ATH_LOG_INF,("Block Size Set: %d (target address:0x%X)\n",
- blocksizes[1], HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_mbox_io_block_sz)));
-
- if (MboxIsrYieldValue != 0) {
- /* set the host interest area for the mbox ISR yield limit */
- status = BMIWriteMemory(hifDevice,
- HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_mbox_isr_yield_limit),
- (u8 *)&MboxIsrYieldValue,
- 4);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_LOG_ERR,("BMIWriteMemory for yield limit failed \n"));
- break;
- }
- }
-
- } while (false);
-
- return status;
-}
-
-void DebugDumpBytes(u8 *buffer, u16 length, char *pDescription)
-{
- char stream[60];
- char byteOffsetStr[10];
- u32 i;
- u16 offset, count, byteOffset;
-
- A_PRINTF("<---------Dumping %d Bytes : %s ------>\n", length, pDescription);
-
- count = 0;
- offset = 0;
- byteOffset = 0;
- for(i = 0; i < length; i++) {
- A_SPRINTF(stream + offset, "%2.2X ", buffer[i]);
- count ++;
- offset += 3;
-
- if(count == 16) {
- count = 0;
- offset = 0;
- A_SPRINTF(byteOffsetStr,"%4.4X",byteOffset);
- A_PRINTF("[%s]: %s\n", byteOffsetStr, stream);
- A_MEMZERO(stream, 60);
- byteOffset += 16;
- }
- }
-
- if(offset != 0) {
- A_SPRINTF(byteOffsetStr,"%4.4X",byteOffset);
- A_PRINTF("[%s]: %s\n", byteOffsetStr, stream);
- }
-
- A_PRINTF("<------------------------------------------------->\n");
-}
-
-void a_dump_module_debug_info(ATH_DEBUG_MODULE_DBG_INFO *pInfo)
-{
- int i;
- struct ath_debug_mask_description *pDesc;
-
- if (pInfo == NULL) {
- return;
- }
-
- pDesc = pInfo->pMaskDescriptions;
-
- A_PRINTF("========================================================\n\n");
- A_PRINTF("Module Debug Info => Name : %s \n", pInfo->ModuleName);
- A_PRINTF(" => Descr. : %s \n", pInfo->ModuleDescription);
- A_PRINTF("\n Current mask => 0x%8.8X \n", pInfo->CurrentMask);
- A_PRINTF("\n Avail. Debug Masks :\n\n");
-
- for (i = 0; i < pInfo->MaxDescriptions; i++,pDesc++) {
- A_PRINTF(" => 0x%8.8X -- %s \n", pDesc->Mask, pDesc->Description);
- }
-
- if (0 == i) {
- A_PRINTF(" => * none defined * \n");
- }
-
- A_PRINTF("\n Standard Debug Masks :\n\n");
- /* print standard masks */
- A_PRINTF(" => 0x%8.8X -- Errors \n", ATH_DEBUG_ERR);
- A_PRINTF(" => 0x%8.8X -- Warnings \n", ATH_DEBUG_WARN);
- A_PRINTF(" => 0x%8.8X -- Informational \n", ATH_DEBUG_INFO);
- A_PRINTF(" => 0x%8.8X -- Tracing \n", ATH_DEBUG_TRC);
- A_PRINTF("\n========================================================\n");
-
-}
-
-
-static ATH_DEBUG_MODULE_DBG_INFO *FindModule(char *module_name)
-{
- ATH_DEBUG_MODULE_DBG_INFO *pInfo = g_pModuleInfoHead;
-
- if (!g_ModuleDebugInit) {
- return NULL;
- }
-
- while (pInfo != NULL) {
- /* TODO: need to use something other than strlen */
- if (memcmp(pInfo->ModuleName,module_name,strlen(module_name)) == 0) {
- break;
- }
- pInfo = pInfo->pNext;
- }
-
- return pInfo;
-}
-
-
-void a_register_module_debug_info(ATH_DEBUG_MODULE_DBG_INFO *pInfo)
-{
- if (!g_ModuleDebugInit) {
- return;
- }
-
- A_MUTEX_LOCK(&g_ModuleListLock);
-
- if (!(pInfo->Flags & ATH_DEBUG_INFO_FLAGS_REGISTERED)) {
- if (g_pModuleInfoHead == NULL) {
- g_pModuleInfoHead = pInfo;
- } else {
- pInfo->pNext = g_pModuleInfoHead;
- g_pModuleInfoHead = pInfo;
- }
- pInfo->Flags |= ATH_DEBUG_INFO_FLAGS_REGISTERED;
- }
-
- A_MUTEX_UNLOCK(&g_ModuleListLock);
-}
-
-void a_dump_module_debug_info_by_name(char *module_name)
-{
- ATH_DEBUG_MODULE_DBG_INFO *pInfo = g_pModuleInfoHead;
-
- if (!g_ModuleDebugInit) {
- return;
- }
-
- if (memcmp(module_name,"all",3) == 0) {
- /* dump all */
- while (pInfo != NULL) {
- a_dump_module_debug_info(pInfo);
- pInfo = pInfo->pNext;
- }
- return;
- }
-
- pInfo = FindModule(module_name);
-
- if (pInfo != NULL) {
- a_dump_module_debug_info(pInfo);
- }
-
-}
-
-int a_get_module_mask(char *module_name, u32 *pMask)
-{
- ATH_DEBUG_MODULE_DBG_INFO *pInfo = FindModule(module_name);
-
- if (NULL == pInfo) {
- return A_ERROR;
- }
-
- *pMask = pInfo->CurrentMask;
- return 0;
-}
-
-int a_set_module_mask(char *module_name, u32 Mask)
-{
- ATH_DEBUG_MODULE_DBG_INFO *pInfo = FindModule(module_name);
-
- if (NULL == pInfo) {
- return A_ERROR;
- }
-
- pInfo->CurrentMask = Mask;
- A_PRINTF("Module %s, new mask: 0x%8.8X \n",module_name,pInfo->CurrentMask);
- return 0;
-}
-
-
-void a_module_debug_support_init(void)
-{
- if (g_ModuleDebugInit) {
- return;
- }
- A_MUTEX_INIT(&g_ModuleListLock);
- g_pModuleInfoHead = NULL;
- g_ModuleDebugInit = true;
- A_REGISTER_MODULE_DEBUG_INFO(misc);
-}
-
-void a_module_debug_support_cleanup(void)
-{
- ATH_DEBUG_MODULE_DBG_INFO *pInfo = g_pModuleInfoHead;
- ATH_DEBUG_MODULE_DBG_INFO *pCur;
-
- if (!g_ModuleDebugInit) {
- return;
- }
-
- g_ModuleDebugInit = false;
-
- A_MUTEX_LOCK(&g_ModuleListLock);
-
- while (pInfo != NULL) {
- pCur = pInfo;
- pInfo = pInfo->pNext;
- pCur->pNext = NULL;
- /* clear registered flag */
- pCur->Flags &= ~ATH_DEBUG_INFO_FLAGS_REGISTERED;
- }
-
- A_MUTEX_UNLOCK(&g_ModuleListLock);
-
- A_MUTEX_DELETE(&g_ModuleListLock);
- g_pModuleInfoHead = NULL;
-}
-
- /* can only be called during bmi init stage */
-int ar6000_set_hci_bridge_flags(struct hif_device *hifDevice,
- u32 TargetType,
- u32 Flags)
-{
- int status = 0;
-
- do {
-
- if (TargetType != TARGET_TYPE_AR6003) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("Target Type:%d, does not support HCI bridging! \n",
- TargetType));
- break;
- }
-
- /* set hci bridge flags */
- status = BMIWriteMemory(hifDevice,
- HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_hci_bridge_flags),
- (u8 *)&Flags,
- 4);
-
-
- } while (false);
-
- return status;
-}
-
diff --git a/drivers/staging/ath6kl/miscdrv/credit_dist.c b/drivers/staging/ath6kl/miscdrv/credit_dist.c
deleted file mode 100644
index c777e98a756e..000000000000
--- a/drivers/staging/ath6kl/miscdrv/credit_dist.c
+++ /dev/null
@@ -1,417 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="credit_dist.c" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-
-#include "a_config.h"
-#include "athdefs.h"
-#include "a_osapi.h"
-#define ATH_MODULE_NAME misc
-#include "a_debug.h"
-#include "htc_api.h"
-#include "common_drv.h"
-
-/********* CREDIT DISTRIBUTION FUNCTIONS ******************************************/
-
-#define NO_VO_SERVICE 1 /* currently WMI only uses 3 data streams, so we leave VO service inactive */
-#define CONFIG_GIVE_LOW_PRIORITY_STREAMS_MIN_CREDITS 1
-
-#ifdef NO_VO_SERVICE
-#define DATA_SVCS_USED 3
-#else
-#define DATA_SVCS_USED 4
-#endif
-
-static void RedistributeCredits(struct common_credit_state_info *pCredInfo,
- struct htc_endpoint_credit_dist *pEPDistList);
-
-static void SeekCredits(struct common_credit_state_info *pCredInfo,
- struct htc_endpoint_credit_dist *pEPDistList);
-
-/* reduce an ep's credits back to a set limit */
-static INLINE void ReduceCredits(struct common_credit_state_info *pCredInfo,
- struct htc_endpoint_credit_dist *pEpDist,
- int Limit)
-{
- int credits;
-
- /* set the new limit */
- pEpDist->TxCreditsAssigned = Limit;
-
- if (pEpDist->TxCredits <= Limit) {
- return;
- }
-
- /* figure out how much to take away */
- credits = pEpDist->TxCredits - Limit;
- /* take them away */
- pEpDist->TxCredits -= credits;
- pCredInfo->CurrentFreeCredits += credits;
-}
-
-/* give an endpoint some credits from the free credit pool */
-#define GiveCredits(pCredInfo,pEpDist,credits) \
-{ \
- (pEpDist)->TxCredits += (credits); \
- (pEpDist)->TxCreditsAssigned += (credits); \
- (pCredInfo)->CurrentFreeCredits -= (credits); \
-}
-
-
-/* default credit init callback.
- * This function is called in the context of HTCStart() to setup initial (application-specific)
- * credit distributions */
-static void ar6000_credit_init(void *Context,
- struct htc_endpoint_credit_dist *pEPList,
- int TotalCredits)
-{
- struct htc_endpoint_credit_dist *pCurEpDist;
- int count;
- struct common_credit_state_info *pCredInfo = (struct common_credit_state_info *)Context;
-
- pCredInfo->CurrentFreeCredits = TotalCredits;
- pCredInfo->TotalAvailableCredits = TotalCredits;
-
- pCurEpDist = pEPList;
-
- /* run through the list and initialize */
- while (pCurEpDist != NULL) {
-
- /* set minimums for each endpoint */
- pCurEpDist->TxCreditsMin = pCurEpDist->TxCreditsPerMaxMsg;
-
-#ifdef CONFIG_GIVE_LOW_PRIORITY_STREAMS_MIN_CREDITS
-
- if (TotalCredits > 4)
- {
- if ((pCurEpDist->ServiceID == WMI_DATA_BK_SVC) || (pCurEpDist->ServiceID == WMI_DATA_BE_SVC)){
- /* assign at least min credits to lower than VO priority services */
- GiveCredits(pCredInfo,pCurEpDist,pCurEpDist->TxCreditsMin);
- /* force active */
- SET_EP_ACTIVE(pCurEpDist);
- }
- }
-
-#endif
-
- if (pCurEpDist->ServiceID == WMI_CONTROL_SVC) {
- /* give control service some credits */
- GiveCredits(pCredInfo,pCurEpDist,pCurEpDist->TxCreditsMin);
- /* control service is always marked active, it never goes inactive EVER */
- SET_EP_ACTIVE(pCurEpDist);
- } else if (pCurEpDist->ServiceID == WMI_DATA_BK_SVC) {
- /* this is the lowest priority data endpoint, save this off for easy access */
- pCredInfo->pLowestPriEpDist = pCurEpDist;
- }
-
- /* Streams have to be created (explicit | implicit)for all kinds
- * of traffic. BE endpoints are also inactive in the beginning.
- * When BE traffic starts it creates implicit streams that
- * redistributes credits.
- */
-
- /* note, all other endpoints have minimums set but are initially given NO credits.
- * Credits will be distributed as traffic activity demands */
- pCurEpDist = pCurEpDist->pNext;
- }
-
- if (pCredInfo->CurrentFreeCredits <= 0) {
- AR_DEBUG_PRINTF(ATH_LOG_INF, ("Not enough credits (%d) to do credit distributions \n", TotalCredits));
- A_ASSERT(false);
- return;
- }
-
- /* reset list */
- pCurEpDist = pEPList;
- /* now run through the list and set max operating credit limits for everyone */
- while (pCurEpDist != NULL) {
- if (pCurEpDist->ServiceID == WMI_CONTROL_SVC) {
- /* control service max is just 1 max message */
- pCurEpDist->TxCreditsNorm = pCurEpDist->TxCreditsPerMaxMsg;
- } else {
- /* for the remaining data endpoints, we assume that each TxCreditsPerMaxMsg are
- * the same.
- * We use a simple calculation here, we take the remaining credits and
- * determine how many max messages this can cover and then set each endpoint's
- * normal value equal to 3/4 this amount.
- * */
- count = (pCredInfo->CurrentFreeCredits/pCurEpDist->TxCreditsPerMaxMsg) * pCurEpDist->TxCreditsPerMaxMsg;
- count = (count * 3) >> 2;
- count = max(count,pCurEpDist->TxCreditsPerMaxMsg);
- /* set normal */
- pCurEpDist->TxCreditsNorm = count;
-
- }
- pCurEpDist = pCurEpDist->pNext;
- }
-
-}
-
-
-/* default credit distribution callback
- * This callback is invoked whenever endpoints require credit distributions.
- * A lock is held while this function is invoked, this function shall NOT block.
- * The pEPDistList is a list of distribution structures in prioritized order as
- * defined by the call to the HTCSetCreditDistribution() api.
- *
- */
-static void ar6000_credit_distribute(void *Context,
- struct htc_endpoint_credit_dist *pEPDistList,
- HTC_CREDIT_DIST_REASON Reason)
-{
- struct htc_endpoint_credit_dist *pCurEpDist;
- struct common_credit_state_info *pCredInfo = (struct common_credit_state_info *)Context;
-
- switch (Reason) {
- case HTC_CREDIT_DIST_SEND_COMPLETE :
- pCurEpDist = pEPDistList;
- /* we are given the start of the endpoint distribution list.
- * There may be one or more endpoints to service.
- * Run through the list and distribute credits */
- while (pCurEpDist != NULL) {
-
- if (pCurEpDist->TxCreditsToDist > 0) {
- /* return the credits back to the endpoint */
- pCurEpDist->TxCredits += pCurEpDist->TxCreditsToDist;
- /* always zero out when we are done */
- pCurEpDist->TxCreditsToDist = 0;
-
- if (pCurEpDist->TxCredits > pCurEpDist->TxCreditsAssigned) {
- /* reduce to the assigned limit, previous credit reductions
- * could have caused the limit to change */
- ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsAssigned);
- }
-
- if (pCurEpDist->TxCredits > pCurEpDist->TxCreditsNorm) {
- /* oversubscribed endpoints need to reduce back to normal */
- ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsNorm);
- }
-
- if (!IS_EP_ACTIVE(pCurEpDist)) {
- /* endpoint is inactive, now check for messages waiting for credits */
- if (pCurEpDist->TxQueueDepth == 0) {
- /* EP is inactive and there are no pending messages,
- * reduce credits back to zero to recover credits */
- ReduceCredits(pCredInfo, pCurEpDist, 0);
- }
- }
- }
-
- pCurEpDist = pCurEpDist->pNext;
- }
-
- break;
-
- case HTC_CREDIT_DIST_ACTIVITY_CHANGE :
- RedistributeCredits(pCredInfo,pEPDistList);
- break;
- case HTC_CREDIT_DIST_SEEK_CREDITS :
- SeekCredits(pCredInfo,pEPDistList);
- break;
- case HTC_DUMP_CREDIT_STATE :
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Credit Distribution, total : %d, free : %d\n",
- pCredInfo->TotalAvailableCredits, pCredInfo->CurrentFreeCredits));
- break;
- default:
- break;
-
- }
-
- /* sanity checks done after each distribution action */
- A_ASSERT(pCredInfo->CurrentFreeCredits <= pCredInfo->TotalAvailableCredits);
- A_ASSERT(pCredInfo->CurrentFreeCredits >= 0);
-
-}
-
-/* redistribute credits based on activity change */
-static void RedistributeCredits(struct common_credit_state_info *pCredInfo,
- struct htc_endpoint_credit_dist *pEPDistList)
-{
- struct htc_endpoint_credit_dist *pCurEpDist = pEPDistList;
-
- /* walk through the list and remove credits from inactive endpoints */
- while (pCurEpDist != NULL) {
-
-#ifdef CONFIG_GIVE_LOW_PRIORITY_STREAMS_MIN_CREDITS
-
- if ((pCurEpDist->ServiceID == WMI_DATA_BK_SVC) || (pCurEpDist->ServiceID == WMI_DATA_BE_SVC)) {
- /* force low priority streams to always be active to retain their minimum credit distribution */
- SET_EP_ACTIVE(pCurEpDist);
- }
-#endif
-
- if (pCurEpDist->ServiceID != WMI_CONTROL_SVC) {
- if (!IS_EP_ACTIVE(pCurEpDist)) {
- if (pCurEpDist->TxQueueDepth == 0) {
- /* EP is inactive and there are no pending messages, reduce credits back to zero */
- ReduceCredits(pCredInfo, pCurEpDist, 0);
- } else {
- /* we cannot zero the credits assigned to this EP, but to keep
- * the credits available for these leftover packets, reduce to
- * a minimum */
- ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsMin);
- }
- }
- }
-
- /* NOTE in the active case, we do not need to do anything further,
- * when an EP goes active and needs credits, HTC will call into
- * our distribution function using a reason code of HTC_CREDIT_DIST_SEEK_CREDITS */
-
- pCurEpDist = pCurEpDist->pNext;
- }
-
-}
-
-/* HTC has an endpoint that needs credits, pEPDist is the endpoint in question */
-static void SeekCredits(struct common_credit_state_info *pCredInfo,
- struct htc_endpoint_credit_dist *pEPDist)
-{
- struct htc_endpoint_credit_dist *pCurEpDist;
- int credits = 0;
- int need;
-
- do {
-
- if (pEPDist->ServiceID == WMI_CONTROL_SVC) {
- /* we never oversubscribe on the control service, this is not
- * a high performance path and the target never holds onto control
- * credits for too long */
- break;
- }
-
-#ifdef CONFIG_GIVE_LOW_PRIORITY_STREAMS_MIN_CREDITS
- if (pEPDist->ServiceID == WMI_DATA_VI_SVC) {
- if ((pEPDist->TxCreditsAssigned >= pEPDist->TxCreditsNorm)) {
- /* limit VI service from oversubscribing */
- break;
- }
- }
-
- if (pEPDist->ServiceID == WMI_DATA_VO_SVC) {
- if ((pEPDist->TxCreditsAssigned >= pEPDist->TxCreditsNorm)) {
- /* limit VO service from oversubscribing */
- break;
- }
- }
-#else
- if (pEPDist->ServiceID == WMI_DATA_VI_SVC) {
- if ((pEPDist->TxCreditsAssigned >= pEPDist->TxCreditsNorm) ||
- (pCredInfo->CurrentFreeCredits <= pEPDist->TxCreditsPerMaxMsg)) {
- /* limit VI service from oversubscribing */
- /* at least one free credit will not be used by VI */
- break;
- }
- }
-
- if (pEPDist->ServiceID == WMI_DATA_VO_SVC) {
- if ((pEPDist->TxCreditsAssigned >= pEPDist->TxCreditsNorm) ||
- (pCredInfo->CurrentFreeCredits <= pEPDist->TxCreditsPerMaxMsg)) {
- /* limit VO service from oversubscribing */
- /* at least one free credit will not be used by VO */
- break;
- }
- }
-#endif
-
- /* for all other services, we follow a simple algorithm of
- * 1. checking the free pool for credits
- * 2. checking lower priority endpoints for credits to take */
-
- /* give what we can */
- credits = min(pCredInfo->CurrentFreeCredits,pEPDist->TxCreditsSeek);
-
- if (credits >= pEPDist->TxCreditsSeek) {
- /* we found some to fulfill the seek request */
- break;
- }
-
- /* we don't have enough in the free pool, try taking away from lower priority services
- *
- * The rule for taking away credits:
- * 1. Only take from lower priority endpoints
- * 2. Only take what is allocated above the minimum (never starve an endpoint completely)
- * 3. Only take what you need.
- *
- * */
-
- /* starting at the lowest priority */
- pCurEpDist = pCredInfo->pLowestPriEpDist;
-
- /* work backwards until we hit the endpoint again */
- while (pCurEpDist != pEPDist) {
- /* calculate how many we need so far */
- need = pEPDist->TxCreditsSeek - pCredInfo->CurrentFreeCredits;
-
- if ((pCurEpDist->TxCreditsAssigned - need) >= pCurEpDist->TxCreditsMin) {
- /* the current one has been allocated more than it's minimum and it
- * has enough credits assigned above it's minimum to fulfill our need
- * try to take away just enough to fulfill our need */
- ReduceCredits(pCredInfo,
- pCurEpDist,
- pCurEpDist->TxCreditsAssigned - need);
-
- if (pCredInfo->CurrentFreeCredits >= pEPDist->TxCreditsSeek) {
- /* we have enough */
- break;
- }
- }
-
- pCurEpDist = pCurEpDist->pPrev;
- }
-
- /* return what we can get */
- credits = min(pCredInfo->CurrentFreeCredits,pEPDist->TxCreditsSeek);
-
- } while (false);
-
- /* did we find some credits? */
- if (credits) {
- /* give what we can */
- GiveCredits(pCredInfo, pEPDist, credits);
- }
-
-}
-
-/* initialize and setup credit distribution */
-int ar6000_setup_credit_dist(HTC_HANDLE HTCHandle, struct common_credit_state_info *pCredInfo)
-{
- HTC_SERVICE_ID servicepriority[5];
-
- A_MEMZERO(pCredInfo,sizeof(struct common_credit_state_info));
-
- servicepriority[0] = WMI_CONTROL_SVC; /* highest */
- servicepriority[1] = WMI_DATA_VO_SVC;
- servicepriority[2] = WMI_DATA_VI_SVC;
- servicepriority[3] = WMI_DATA_BE_SVC;
- servicepriority[4] = WMI_DATA_BK_SVC; /* lowest */
-
- /* set callbacks and priority list */
- HTCSetCreditDistribution(HTCHandle,
- pCredInfo,
- ar6000_credit_distribute,
- ar6000_credit_init,
- servicepriority,
- 5);
-
- return 0;
-}
-
diff --git a/drivers/staging/ath6kl/miscdrv/miscdrv.h b/drivers/staging/ath6kl/miscdrv/miscdrv.h
deleted file mode 100644
index 41be5670db42..000000000000
--- a/drivers/staging/ath6kl/miscdrv/miscdrv.h
+++ /dev/null
@@ -1,42 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="miscdrv.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _MISCDRV_H
-#define _MISCDRV_H
-
-
-#define HOST_INTEREST_ITEM_ADDRESS(target, item) \
- AR6002_HOST_INTEREST_ITEM_ADDRESS(item)
-
-u32 ar6kRev2Array[][128] = {
- {0xFFFF, 0xFFFF}, // No Patches
- };
-
-#define CFG_REV2_ITEMS 0 // no patches so far
-#define AR6K_RESET_ADDR 0x4000
-#define AR6K_RESET_VAL 0x100
-
-#define EEPROM_SZ 768
-#define EEPROM_WAIT_LIMIT 4
-
-#endif
-
diff --git a/drivers/staging/ath6kl/os/linux/ar6000_drv.c b/drivers/staging/ath6kl/os/linux/ar6000_drv.c
deleted file mode 100644
index 32ee39ad00df..000000000000
--- a/drivers/staging/ath6kl/os/linux/ar6000_drv.c
+++ /dev/null
@@ -1,6267 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Communications Inc.
-// All rights reserved.
-//
-//
-//
-// 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.
-//
-//
-//
-// Author(s): ="Atheros"
-//------------------------------------------------------------------------------
-
-/*
- * This driver is a pseudo ethernet driver to access the Atheros AR6000
- * WLAN Device
- */
-
-#include "ar6000_drv.h"
-#include "cfg80211.h"
-#include "htc.h"
-#include "wmi_filter_linux.h"
-#include "epping_test.h"
-#include "wlan_config.h"
-#include "ar3kconfig.h"
-#include "ar6k_pal.h"
-#include "AR6002/addrs.h"
-
-
-/* LINUX_HACK_FUDGE_FACTOR -- this is used to provide a workaround for linux behavior. When
- * the meta data was added to the header it was found that linux did not correctly provide
- * enough headroom. However when more headroom was requested beyond what was truly needed
- * Linux gave the requested headroom. Therefore to get the necessary headroom from Linux
- * the driver requests more than is needed by the amount = LINUX_HACK_FUDGE_FACTOR */
-#define LINUX_HACK_FUDGE_FACTOR 16
-#define BDATA_BDADDR_OFFSET 28
-
-u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-u8 null_mac[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
-
-#ifdef DEBUG
-
-#define ATH_DEBUG_DBG_LOG ATH_DEBUG_MAKE_MODULE_MASK(0)
-#define ATH_DEBUG_WLAN_CONNECT ATH_DEBUG_MAKE_MODULE_MASK(1)
-#define ATH_DEBUG_WLAN_SCAN ATH_DEBUG_MAKE_MODULE_MASK(2)
-#define ATH_DEBUG_WLAN_TX ATH_DEBUG_MAKE_MODULE_MASK(3)
-#define ATH_DEBUG_WLAN_RX ATH_DEBUG_MAKE_MODULE_MASK(4)
-#define ATH_DEBUG_HTC_RAW ATH_DEBUG_MAKE_MODULE_MASK(5)
-#define ATH_DEBUG_HCI_BRIDGE ATH_DEBUG_MAKE_MODULE_MASK(6)
-
-static struct ath_debug_mask_description driver_debug_desc[] = {
- { ATH_DEBUG_DBG_LOG , "Target Debug Logs"},
- { ATH_DEBUG_WLAN_CONNECT , "WLAN connect"},
- { ATH_DEBUG_WLAN_SCAN , "WLAN scan"},
- { ATH_DEBUG_WLAN_TX , "WLAN Tx"},
- { ATH_DEBUG_WLAN_RX , "WLAN Rx"},
- { ATH_DEBUG_HTC_RAW , "HTC Raw IF tracing"},
- { ATH_DEBUG_HCI_BRIDGE , "HCI Bridge Setup"},
- { ATH_DEBUG_HCI_RECV , "HCI Recv tracing"},
- { ATH_DEBUG_HCI_DUMP , "HCI Packet dumps"},
-};
-
-ATH_DEBUG_INSTANTIATE_MODULE_VAR(driver,
- "driver",
- "Linux Driver Interface",
- ATH_DEBUG_MASK_DEFAULTS | ATH_DEBUG_WLAN_SCAN |
- ATH_DEBUG_HCI_BRIDGE,
- ATH_DEBUG_DESCRIPTION_COUNT(driver_debug_desc),
- driver_debug_desc);
-
-#endif
-
-
-#define IS_MAC_NULL(mac) (mac[0]==0 && mac[1]==0 && mac[2]==0 && mac[3]==0 && mac[4]==0 && mac[5]==0)
-#define IS_MAC_BCAST(mac) (*mac==0xff)
-
-#define DESCRIPTION "Driver to access the Atheros AR600x Device, version " __stringify(__VER_MAJOR_) "." __stringify(__VER_MINOR_) "." __stringify(__VER_PATCH_) "." __stringify(__BUILD_NUMBER_)
-
-MODULE_AUTHOR("Atheros Communications, Inc.");
-MODULE_DESCRIPTION(DESCRIPTION);
-MODULE_LICENSE("Dual BSD/GPL");
-
-#ifndef REORG_APTC_HEURISTICS
-#undef ADAPTIVE_POWER_THROUGHPUT_CONTROL
-#endif /* REORG_APTC_HEURISTICS */
-
-#ifdef ADAPTIVE_POWER_THROUGHPUT_CONTROL
-#define APTC_TRAFFIC_SAMPLING_INTERVAL 100 /* msec */
-#define APTC_UPPER_THROUGHPUT_THRESHOLD 3000 /* Kbps */
-#define APTC_LOWER_THROUGHPUT_THRESHOLD 2000 /* Kbps */
-
-typedef struct aptc_traffic_record {
- bool timerScheduled;
- struct timeval samplingTS;
- unsigned long bytesReceived;
- unsigned long bytesTransmitted;
-} APTC_TRAFFIC_RECORD;
-
-A_TIMER aptcTimer;
-APTC_TRAFFIC_RECORD aptcTR;
-#endif /* ADAPTIVE_POWER_THROUGHPUT_CONTROL */
-
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
-// callbacks registered by HCI transport driver
-struct hci_transport_callbacks ar6kHciTransCallbacks = { NULL };
-#endif
-
-unsigned int processDot11Hdr = 0;
-
-char ifname[IFNAMSIZ] = {0,};
-
-int wlaninitmode = WLAN_INIT_MODE_DEFAULT;
-static bool bypasswmi;
-unsigned int debuglevel = 0;
-int tspecCompliance = ATHEROS_COMPLIANCE;
-unsigned int busspeedlow = 0;
-unsigned int onebitmode = 0;
-unsigned int skipflash = 0;
-unsigned int wmitimeout = 2;
-unsigned int wlanNodeCaching = 1;
-unsigned int enableuartprint = ENABLEUARTPRINT_DEFAULT;
-unsigned int logWmiRawMsgs = 0;
-unsigned int enabletimerwar = 0;
-unsigned int num_device = 1;
-unsigned int regscanmode;
-unsigned int fwmode = 1;
-unsigned int mbox_yield_limit = 99;
-unsigned int enablerssicompensation = 0;
-int reduce_credit_dribble = 1 + HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_ONE_HALF;
-int allow_trace_signal = 0;
-#ifdef CONFIG_HOST_TCMD_SUPPORT
-unsigned int testmode =0;
-#endif
-
-unsigned int irqprocmode = HIF_DEVICE_IRQ_SYNC_ONLY;//HIF_DEVICE_IRQ_ASYNC_SYNC;
-unsigned int panic_on_assert = 1;
-unsigned int nohifscattersupport = NOHIFSCATTERSUPPORT_DEFAULT;
-
-unsigned int setuphci = SETUPHCI_DEFAULT;
-unsigned int loghci = 0;
-unsigned int setupbtdev = SETUPBTDEV_DEFAULT;
-#ifndef EXPORT_HCI_BRIDGE_INTERFACE
-unsigned int ar3khcibaud = AR3KHCIBAUD_DEFAULT;
-unsigned int hciuartscale = HCIUARTSCALE_DEFAULT;
-unsigned int hciuartstep = HCIUARTSTEP_DEFAULT;
-#endif
-unsigned int csumOffload=0;
-unsigned int csumOffloadTest=0;
-unsigned int eppingtest=0;
-unsigned int mac_addr_method;
-unsigned int firmware_bridge;
-
-module_param_string(ifname, ifname, sizeof(ifname), 0644);
-module_param(wlaninitmode, int, 0644);
-module_param(bypasswmi, bool, 0644);
-module_param(debuglevel, uint, 0644);
-module_param(tspecCompliance, int, 0644);
-module_param(onebitmode, uint, 0644);
-module_param(busspeedlow, uint, 0644);
-module_param(skipflash, uint, 0644);
-module_param(wmitimeout, uint, 0644);
-module_param(wlanNodeCaching, uint, 0644);
-module_param(logWmiRawMsgs, uint, 0644);
-module_param(enableuartprint, uint, 0644);
-module_param(enabletimerwar, uint, 0644);
-module_param(fwmode, uint, 0644);
-module_param(mbox_yield_limit, uint, 0644);
-module_param(reduce_credit_dribble, int, 0644);
-module_param(allow_trace_signal, int, 0644);
-module_param(enablerssicompensation, uint, 0644);
-module_param(processDot11Hdr, uint, 0644);
-module_param(csumOffload, uint, 0644);
-#ifdef CONFIG_HOST_TCMD_SUPPORT
-module_param(testmode, uint, 0644);
-#endif
-module_param(irqprocmode, uint, 0644);
-module_param(nohifscattersupport, uint, 0644);
-module_param(panic_on_assert, uint, 0644);
-module_param(setuphci, uint, 0644);
-module_param(loghci, uint, 0644);
-module_param(setupbtdev, uint, 0644);
-#ifndef EXPORT_HCI_BRIDGE_INTERFACE
-module_param(ar3khcibaud, uint, 0644);
-module_param(hciuartscale, uint, 0644);
-module_param(hciuartstep, uint, 0644);
-#endif
-module_param(eppingtest, uint, 0644);
-
-/* in 2.6.10 and later this is now a pointer to a uint */
-unsigned int _mboxnum = HTC_MAILBOX_NUM_MAX;
-#define mboxnum &_mboxnum
-
-#ifdef DEBUG
-u32 g_dbg_flags = DBG_DEFAULTS;
-unsigned int debugflags = 0;
-int debugdriver = 0;
-unsigned int debughtc = 0;
-unsigned int debugbmi = 0;
-unsigned int debughif = 0;
-unsigned int txcreditsavailable[HTC_MAILBOX_NUM_MAX] = {0};
-unsigned int txcreditsconsumed[HTC_MAILBOX_NUM_MAX] = {0};
-unsigned int txcreditintrenable[HTC_MAILBOX_NUM_MAX] = {0};
-unsigned int txcreditintrenableaggregate[HTC_MAILBOX_NUM_MAX] = {0};
-module_param(debugflags, uint, 0644);
-module_param(debugdriver, int, 0644);
-module_param(debughtc, uint, 0644);
-module_param(debugbmi, uint, 0644);
-module_param(debughif, uint, 0644);
-module_param_array(txcreditsavailable, uint, mboxnum, 0644);
-module_param_array(txcreditsconsumed, uint, mboxnum, 0644);
-module_param_array(txcreditintrenable, uint, mboxnum, 0644);
-module_param_array(txcreditintrenableaggregate, uint, mboxnum, 0644);
-
-#endif /* DEBUG */
-
-unsigned int resetok = 1;
-unsigned int tx_attempt[HTC_MAILBOX_NUM_MAX] = {0};
-unsigned int tx_post[HTC_MAILBOX_NUM_MAX] = {0};
-unsigned int tx_complete[HTC_MAILBOX_NUM_MAX] = {0};
-unsigned int hifBusRequestNumMax = 40;
-unsigned int war23838_disabled = 0;
-#ifdef ADAPTIVE_POWER_THROUGHPUT_CONTROL
-unsigned int enableAPTCHeuristics = 1;
-#endif /* ADAPTIVE_POWER_THROUGHPUT_CONTROL */
-module_param_array(tx_attempt, uint, mboxnum, 0644);
-module_param_array(tx_post, uint, mboxnum, 0644);
-module_param_array(tx_complete, uint, mboxnum, 0644);
-module_param(hifBusRequestNumMax, uint, 0644);
-module_param(war23838_disabled, uint, 0644);
-module_param(resetok, uint, 0644);
-#ifdef ADAPTIVE_POWER_THROUGHPUT_CONTROL
-module_param(enableAPTCHeuristics, uint, 0644);
-#endif /* ADAPTIVE_POWER_THROUGHPUT_CONTROL */
-
-#ifdef BLOCK_TX_PATH_FLAG
-int blocktx = 0;
-module_param(blocktx, int, 0644);
-#endif /* BLOCK_TX_PATH_FLAG */
-
-typedef struct user_rssi_compensation_t {
- u16 customerID;
- union {
- u16 a_enable;
- u16 bg_enable;
- u16 enable;
- };
- s16 bg_param_a;
- s16 bg_param_b;
- s16 a_param_a;
- s16 a_param_b;
- u32 reserved;
-} USER_RSSI_CPENSATION;
-
-static USER_RSSI_CPENSATION rssi_compensation_param;
-
-static s16 rssi_compensation_table[96];
-
-int reconnect_flag = 0;
-static ar6k_pal_config_t ar6k_pal_config_g;
-
-/* Function declarations */
-static int ar6000_init_module(void);
-static void ar6000_cleanup_module(void);
-
-int ar6000_init(struct net_device *dev);
-static int ar6000_open(struct net_device *dev);
-static int ar6000_close(struct net_device *dev);
-static void ar6000_init_control_info(struct ar6_softc *ar);
-static int ar6000_data_tx(struct sk_buff *skb, struct net_device *dev);
-
-void ar6000_destroy(struct net_device *dev, unsigned int unregister);
-static void ar6000_detect_error(unsigned long ptr);
-static void ar6000_set_multicast_list(struct net_device *dev);
-static struct net_device_stats *ar6000_get_stats(struct net_device *dev);
-
-static void disconnect_timer_handler(unsigned long ptr);
-
-void read_rssi_compensation_param(struct ar6_softc *ar);
-
-/*
- * HTC service connection handlers
- */
-static int ar6000_avail_ev(void *context, void *hif_handle);
-
-static int ar6000_unavail_ev(void *context, void *hif_handle);
-
-int ar6000_configure_target(struct ar6_softc *ar);
-
-static void ar6000_target_failure(void *Instance, int Status);
-
-static void ar6000_rx(void *Context, struct htc_packet *pPacket);
-
-static void ar6000_rx_refill(void *Context,HTC_ENDPOINT_ID Endpoint);
-
-static void ar6000_tx_complete(void *Context, struct htc_packet_queue *pPackets);
-
-static HTC_SEND_FULL_ACTION ar6000_tx_queue_full(void *Context, struct htc_packet *pPacket);
-
-static void ar6000_alloc_netbufs(A_NETBUF_QUEUE_T *q, u16 num);
-static void ar6000_deliver_frames_to_nw_stack(void * dev, void *osbuf);
-//static void ar6000_deliver_frames_to_bt_stack(void * dev, void *osbuf);
-
-static struct htc_packet *ar6000_alloc_amsdu_rxbuf(void *Context, HTC_ENDPOINT_ID Endpoint, int Length);
-
-static void ar6000_refill_amsdu_rxbufs(struct ar6_softc *ar, int Count);
-
-static void ar6000_cleanup_amsdu_rxbufs(struct ar6_softc *ar);
-
-static ssize_t
-ar6000_sysfs_bmi_read(struct file *fp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t pos, size_t count);
-
-static ssize_t
-ar6000_sysfs_bmi_write(struct file *fp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t pos, size_t count);
-
-static int
-ar6000_sysfs_bmi_init(struct ar6_softc *ar);
-
-void ar6k_cleanup_hci_pal(struct ar6_softc *ar);
-
-static void
-ar6000_sysfs_bmi_deinit(struct ar6_softc *ar);
-
-int
-ar6000_sysfs_bmi_get_config(struct ar6_softc *ar, u32 mode);
-
-/*
- * Static variables
- */
-
-struct net_device *ar6000_devices[MAX_AR6000];
-static int is_netdev_registered;
-DECLARE_WAIT_QUEUE_HEAD(arEvent);
-static void ar6000_cookie_init(struct ar6_softc *ar);
-static void ar6000_cookie_cleanup(struct ar6_softc *ar);
-static void ar6000_free_cookie(struct ar6_softc *ar, struct ar_cookie * cookie);
-static struct ar_cookie *ar6000_alloc_cookie(struct ar6_softc *ar);
-
-static int ar6000_reinstall_keys(struct ar6_softc *ar,u8 key_op_ctrl);
-
-#ifdef CONFIG_AP_VIRTUAL_ADAPTER_SUPPORT
-struct net_device *arApNetDev;
-#endif /* CONFIG_AP_VIRTUAL_ADAPTER_SUPPORT */
-
-static struct ar_cookie s_ar_cookie_mem[MAX_COOKIE_NUM];
-
-#define HOST_INTEREST_ITEM_ADDRESS(ar, item) \
- (((ar)->arTargetType == TARGET_TYPE_AR6002) ? AR6002_HOST_INTEREST_ITEM_ADDRESS(item) : \
- (((ar)->arTargetType == TARGET_TYPE_AR6003) ? AR6003_HOST_INTEREST_ITEM_ADDRESS(item) : 0))
-
-
-static struct net_device_ops ar6000_netdev_ops = {
- .ndo_init = NULL,
- .ndo_open = ar6000_open,
- .ndo_stop = ar6000_close,
- .ndo_get_stats = ar6000_get_stats,
- .ndo_start_xmit = ar6000_data_tx,
- .ndo_set_multicast_list = ar6000_set_multicast_list,
-};
-
-/* Debug log support */
-
-/*
- * Flag to govern whether the debug logs should be parsed in the kernel
- * or reported to the application.
- */
-#define REPORT_DEBUG_LOGS_TO_APP
-
-int
-ar6000_set_host_app_area(struct ar6_softc *ar)
-{
- u32 address, data;
- struct host_app_area_s host_app_area;
-
- /* Fetch the address of the host_app_area_s instance in the host interest area */
- address = TARG_VTOP(ar->arTargetType, HOST_INTEREST_ITEM_ADDRESS(ar, hi_app_host_interest));
- if (ar6000_ReadRegDiag(ar->arHifDevice, &address, &data) != 0) {
- return A_ERROR;
- }
- address = TARG_VTOP(ar->arTargetType, data);
- host_app_area.wmi_protocol_ver = WMI_PROTOCOL_VERSION;
- if (ar6000_WriteDataDiag(ar->arHifDevice, address,
- (u8 *)&host_app_area,
- sizeof(struct host_app_area_s)) != 0)
- {
- return A_ERROR;
- }
-
- return 0;
-}
-
-u32 dbglog_get_debug_hdr_ptr(struct ar6_softc *ar)
-{
- u32 param;
- u32 address;
- int status;
-
- address = TARG_VTOP(ar->arTargetType, HOST_INTEREST_ITEM_ADDRESS(ar, hi_dbglog_hdr));
- if ((status = ar6000_ReadDataDiag(ar->arHifDevice, address,
- (u8 *)&param, 4)) != 0)
- {
- param = 0;
- }
-
- return param;
-}
-
-/*
- * The dbglog module has been initialized. Its ok to access the relevant
- * data stuctures over the diagnostic window.
- */
-void
-ar6000_dbglog_init_done(struct ar6_softc *ar)
-{
- ar->dbglog_init_done = true;
-}
-
-u32 dbglog_get_debug_fragment(s8 *datap, u32 len, u32 limit)
-{
- s32 *buffer;
- u32 count;
- u32 numargs;
- u32 length;
- u32 fraglen;
-
- count = fraglen = 0;
- buffer = (s32 *)datap;
- length = (limit >> 2);
-
- if (len <= limit) {
- fraglen = len;
- } else {
- while (count < length) {
- numargs = DBGLOG_GET_NUMARGS(buffer[count]);
- fraglen = (count << 2);
- count += numargs + 1;
- }
- }
-
- return fraglen;
-}
-
-void
-dbglog_parse_debug_logs(s8 *datap, u32 len)
-{
- s32 *buffer;
- u32 count;
- u32 timestamp;
- u32 debugid;
- u32 moduleid;
- u32 numargs;
- u32 length;
-
- count = 0;
- buffer = (s32 *)datap;
- length = (len >> 2);
- while (count < length) {
- debugid = DBGLOG_GET_DBGID(buffer[count]);
- moduleid = DBGLOG_GET_MODULEID(buffer[count]);
- numargs = DBGLOG_GET_NUMARGS(buffer[count]);
- timestamp = DBGLOG_GET_TIMESTAMP(buffer[count]);
- switch (numargs) {
- case 0:
- AR_DEBUG_PRINTF(ATH_DEBUG_DBG_LOG,("%d %d (%d)\n", moduleid, debugid, timestamp));
- break;
-
- case 1:
- AR_DEBUG_PRINTF(ATH_DEBUG_DBG_LOG,("%d %d (%d): 0x%x\n", moduleid, debugid,
- timestamp, buffer[count+1]));
- break;
-
- case 2:
- AR_DEBUG_PRINTF(ATH_DEBUG_DBG_LOG,("%d %d (%d): 0x%x, 0x%x\n", moduleid, debugid,
- timestamp, buffer[count+1], buffer[count+2]));
- break;
-
- default:
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Invalid args: %d\n", numargs));
- }
- count += numargs + 1;
- }
-}
-
-int
-ar6000_dbglog_get_debug_logs(struct ar6_softc *ar)
-{
- u32 data[8]; /* Should be able to accommodate struct dbglog_buf_s */
- u32 address;
- u32 length;
- u32 dropped;
- u32 firstbuf;
- u32 debug_hdr_ptr;
-
- if (!ar->dbglog_init_done) return A_ERROR;
-
-
- AR6000_SPIN_LOCK(&ar->arLock, 0);
-
- if (ar->dbgLogFetchInProgress) {
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
- return A_EBUSY;
- }
-
- /* block out others */
- ar->dbgLogFetchInProgress = true;
-
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
-
- debug_hdr_ptr = dbglog_get_debug_hdr_ptr(ar);
- printk("debug_hdr_ptr: 0x%x\n", debug_hdr_ptr);
-
- /* Get the contents of the ring buffer */
- if (debug_hdr_ptr) {
- address = TARG_VTOP(ar->arTargetType, debug_hdr_ptr);
- length = 4 /* sizeof(dbuf) */ + 4 /* sizeof(dropped) */;
- A_MEMZERO(data, sizeof(data));
- ar6000_ReadDataDiag(ar->arHifDevice, address, (u8 *)data, length);
- address = TARG_VTOP(ar->arTargetType, data[0] /* dbuf */);
- firstbuf = address;
- dropped = data[1]; /* dropped */
- length = 4 /* sizeof(next) */ + 4 /* sizeof(buffer) */ + 4 /* sizeof(bufsize) */ + 4 /* sizeof(length) */ + 4 /* sizeof(count) */ + 4 /* sizeof(free) */;
- A_MEMZERO(data, sizeof(data));
- ar6000_ReadDataDiag(ar->arHifDevice, address, (u8 *)&data, length);
-
- do {
- address = TARG_VTOP(ar->arTargetType, data[1] /* buffer*/);
- length = data[3]; /* length */
- if ((length) && (length <= data[2] /* bufsize*/)) {
- /* Rewind the index if it is about to overrun the buffer */
- if (ar->log_cnt > (DBGLOG_HOST_LOG_BUFFER_SIZE - length)) {
- ar->log_cnt = 0;
- }
- if(0 != ar6000_ReadDataDiag(ar->arHifDevice, address,
- (u8 *)&ar->log_buffer[ar->log_cnt], length))
- {
- break;
- }
- ar6000_dbglog_event(ar, dropped, (s8 *)&ar->log_buffer[ar->log_cnt], length);
- ar->log_cnt += length;
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_DBG_LOG,("Length: %d (Total size: %d)\n",
- data[3], data[2]));
- }
-
- address = TARG_VTOP(ar->arTargetType, data[0] /* next */);
- length = 4 /* sizeof(next) */ + 4 /* sizeof(buffer) */ + 4 /* sizeof(bufsize) */ + 4 /* sizeof(length) */ + 4 /* sizeof(count) */ + 4 /* sizeof(free) */;
- A_MEMZERO(data, sizeof(data));
- if(0 != ar6000_ReadDataDiag(ar->arHifDevice, address,
- (u8 *)&data, length))
- {
- break;
- }
-
- } while (address != firstbuf);
- }
-
- ar->dbgLogFetchInProgress = false;
-
- return 0;
-}
-
-void
-ar6000_dbglog_event(struct ar6_softc *ar, u32 dropped,
- s8 *buffer, u32 length)
-{
-#ifdef REPORT_DEBUG_LOGS_TO_APP
- #define MAX_WIRELESS_EVENT_SIZE 252
- /*
- * Break it up into chunks of MAX_WIRELESS_EVENT_SIZE bytes of messages.
- * There seems to be a limitation on the length of message that could be
- * transmitted to the user app via this mechanism.
- */
- u32 send, sent;
-
- sent = 0;
- send = dbglog_get_debug_fragment(&buffer[sent], length - sent,
- MAX_WIRELESS_EVENT_SIZE);
- while (send) {
- sent += send;
- send = dbglog_get_debug_fragment(&buffer[sent], length - sent,
- MAX_WIRELESS_EVENT_SIZE);
- }
-#else
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Dropped logs: 0x%x\nDebug info length: %d\n",
- dropped, length));
-
- /* Interpret the debug logs */
- dbglog_parse_debug_logs((s8 *)buffer, length);
-#endif /* REPORT_DEBUG_LOGS_TO_APP */
-}
-
-
-static int __init
-ar6000_init_module(void)
-{
- static int probed = 0;
- int r;
- OSDRV_CALLBACKS osdrvCallbacks;
-
- a_module_debug_support_init();
-
-#ifdef DEBUG
- /* check for debug mask overrides */
- if (debughtc != 0) {
- ATH_DEBUG_SET_DEBUG_MASK(htc,debughtc);
- }
- if (debugbmi != 0) {
- ATH_DEBUG_SET_DEBUG_MASK(bmi,debugbmi);
- }
- if (debughif != 0) {
- ATH_DEBUG_SET_DEBUG_MASK(hif,debughif);
- }
- if (debugdriver != 0) {
- ATH_DEBUG_SET_DEBUG_MASK(driver,debugdriver);
- }
-
-#endif
-
- A_REGISTER_MODULE_DEBUG_INFO(driver);
-
- A_MEMZERO(&osdrvCallbacks,sizeof(osdrvCallbacks));
- osdrvCallbacks.deviceInsertedHandler = ar6000_avail_ev;
- osdrvCallbacks.deviceRemovedHandler = ar6000_unavail_ev;
-#ifdef CONFIG_PM
- osdrvCallbacks.deviceSuspendHandler = ar6000_suspend_ev;
- osdrvCallbacks.deviceResumeHandler = ar6000_resume_ev;
- osdrvCallbacks.devicePowerChangeHandler = ar6000_power_change_ev;
-#endif
-
-#ifdef DEBUG
- /* Set the debug flags if specified at load time */
- if(debugflags != 0)
- {
- g_dbg_flags = debugflags;
- }
-#endif
-
- if (probed) {
- return -ENODEV;
- }
- probed++;
-
-#ifdef ADAPTIVE_POWER_THROUGHPUT_CONTROL
- memset(&aptcTR, 0, sizeof(APTC_TRAFFIC_RECORD));
-#endif /* ADAPTIVE_POWER_THROUGHPUT_CONTROL */
-
- r = HIFInit(&osdrvCallbacks);
- if (r)
- return r;
-
- return 0;
-}
-
-static void __exit
-ar6000_cleanup_module(void)
-{
- int i = 0;
- struct net_device *ar6000_netdev;
-
-#ifdef ADAPTIVE_POWER_THROUGHPUT_CONTROL
- /* Delete the Adaptive Power Control timer */
- if (timer_pending(&aptcTimer)) {
- del_timer_sync(&aptcTimer);
- }
-#endif /* ADAPTIVE_POWER_THROUGHPUT_CONTROL */
-
- for (i=0; i < MAX_AR6000; i++) {
- if (ar6000_devices[i] != NULL) {
- ar6000_netdev = ar6000_devices[i];
- ar6000_devices[i] = NULL;
- ar6000_destroy(ar6000_netdev, 1);
- }
- }
-
- HIFShutDownDevice(NULL);
-
- a_module_debug_support_cleanup();
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("ar6000_cleanup: success\n"));
-}
-
-#ifdef ADAPTIVE_POWER_THROUGHPUT_CONTROL
-void
-aptcTimerHandler(unsigned long arg)
-{
- u32 numbytes;
- u32 throughput;
- struct ar6_softc *ar;
- int status;
-
- ar = (struct ar6_softc *)arg;
- A_ASSERT(ar != NULL);
- A_ASSERT(!timer_pending(&aptcTimer));
-
- AR6000_SPIN_LOCK(&ar->arLock, 0);
-
- /* Get the number of bytes transferred */
- numbytes = aptcTR.bytesTransmitted + aptcTR.bytesReceived;
- aptcTR.bytesTransmitted = aptcTR.bytesReceived = 0;
-
- /* Calculate and decide based on throughput thresholds */
- throughput = ((numbytes * 8)/APTC_TRAFFIC_SAMPLING_INTERVAL); /* Kbps */
- if (throughput < APTC_LOWER_THROUGHPUT_THRESHOLD) {
- /* Enable Sleep and delete the timer */
- A_ASSERT(ar->arWmiReady == true);
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
- status = wmi_powermode_cmd(ar->arWmi, REC_POWER);
- AR6000_SPIN_LOCK(&ar->arLock, 0);
- A_ASSERT(status == 0);
- aptcTR.timerScheduled = false;
- } else {
- A_TIMEOUT_MS(&aptcTimer, APTC_TRAFFIC_SAMPLING_INTERVAL, 0);
- }
-
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
-}
-#endif /* ADAPTIVE_POWER_THROUGHPUT_CONTROL */
-
-static void
-ar6000_alloc_netbufs(A_NETBUF_QUEUE_T *q, u16 num)
-{
- void * osbuf;
-
- while(num) {
- if((osbuf = A_NETBUF_ALLOC(AR6000_BUFFER_SIZE))) {
- A_NETBUF_ENQUEUE(q, osbuf);
- } else {
- break;
- }
- num--;
- }
-
- if(num) {
- A_PRINTF("%s(), allocation of netbuf failed", __func__);
- }
-}
-
-static struct bin_attribute bmi_attr = {
- .attr = {.name = "bmi", .mode = 0600},
- .read = ar6000_sysfs_bmi_read,
- .write = ar6000_sysfs_bmi_write,
-};
-
-static ssize_t
-ar6000_sysfs_bmi_read(struct file *fp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t pos, size_t count)
-{
- int index;
- struct ar6_softc *ar;
- struct hif_device_os_device_info *osDevInfo;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("BMI: Read %d bytes\n", (u32)count));
- for (index=0; index < MAX_AR6000; index++) {
- ar = (struct ar6_softc *)ar6k_priv(ar6000_devices[index]);
- osDevInfo = &ar->osDevInfo;
- if (kobj == (&(((struct device *)osDevInfo->pOSDevice)->kobj))) {
- break;
- }
- }
-
- if (index == MAX_AR6000) return 0;
-
- if ((BMIRawRead(ar->arHifDevice, (u8*)buf, count, true)) != 0) {
- return 0;
- }
-
- return count;
-}
-
-static ssize_t
-ar6000_sysfs_bmi_write(struct file *fp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t pos, size_t count)
-{
- int index;
- struct ar6_softc *ar;
- struct hif_device_os_device_info *osDevInfo;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("BMI: Write %d bytes\n", (u32)count));
- for (index=0; index < MAX_AR6000; index++) {
- ar = (struct ar6_softc *)ar6k_priv(ar6000_devices[index]);
- osDevInfo = &ar->osDevInfo;
- if (kobj == (&(((struct device *)osDevInfo->pOSDevice)->kobj))) {
- break;
- }
- }
-
- if (index == MAX_AR6000) return 0;
-
- if ((BMIRawWrite(ar->arHifDevice, (u8*)buf, count)) != 0) {
- return 0;
- }
-
- return count;
-}
-
-static int
-ar6000_sysfs_bmi_init(struct ar6_softc *ar)
-{
- int status;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("BMI: Creating sysfs entry\n"));
- A_MEMZERO(&ar->osDevInfo, sizeof(struct hif_device_os_device_info));
-
- /* Get the underlying OS device */
- status = HIFConfigureDevice(ar->arHifDevice,
- HIF_DEVICE_GET_OS_DEVICE,
- &ar->osDevInfo,
- sizeof(struct hif_device_os_device_info));
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI: Failed to get OS device info from HIF\n"));
- return A_ERROR;
- }
-
- /* Create a bmi entry in the sysfs filesystem */
- if ((sysfs_create_bin_file(&(((struct device *)ar->osDevInfo.pOSDevice)->kobj), &bmi_attr)) < 0)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BMI: Failed to create entry for bmi in sysfs filesystem\n"));
- return A_ERROR;
- }
-
- return 0;
-}
-
-static void
-ar6000_sysfs_bmi_deinit(struct ar6_softc *ar)
-{
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("BMI: Deleting sysfs entry\n"));
-
- sysfs_remove_bin_file(&(((struct device *)ar->osDevInfo.pOSDevice)->kobj), &bmi_attr);
-}
-
-#define bmifn(fn) do { \
- if ((fn) < 0) { \
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI operation failed: %d\n", __LINE__)); \
- return A_ERROR; \
- } \
-} while(0)
-
-#ifdef SOFTMAC_FILE_USED
-#define AR6002_MAC_ADDRESS_OFFSET 0x0A
-#define AR6003_MAC_ADDRESS_OFFSET 0x16
-static
-void calculate_crc(u32 TargetType, u8 *eeprom_data)
-{
- u16 *ptr_crc;
- u16 *ptr16_eeprom;
- u16 checksum;
- u32 i;
- u32 eeprom_size;
-
- if (TargetType == TARGET_TYPE_AR6001)
- {
- eeprom_size = 512;
- ptr_crc = (u16 *)eeprom_data;
- }
- else if (TargetType == TARGET_TYPE_AR6003)
- {
- eeprom_size = 1024;
- ptr_crc = (u16 *)((u8 *)eeprom_data + 0x04);
- }
- else
- {
- eeprom_size = 768;
- ptr_crc = (u16 *)((u8 *)eeprom_data + 0x04);
- }
-
-
- // Clear the crc
- *ptr_crc = 0;
-
- // Recalculate new CRC
- checksum = 0;
- ptr16_eeprom = (u16 *)eeprom_data;
- for (i = 0;i < eeprom_size; i += 2)
- {
- checksum = checksum ^ (*ptr16_eeprom);
- ptr16_eeprom++;
- }
- checksum = 0xFFFF ^ checksum;
- *ptr_crc = checksum;
-}
-
-static void
-ar6000_softmac_update(struct ar6_softc *ar, u8 *eeprom_data, size_t size)
-{
- const char *source = "random generated";
- const struct firmware *softmac_entry;
- u8 *ptr_mac;
- switch (ar->arTargetType) {
- case TARGET_TYPE_AR6002:
- ptr_mac = (u8 *)((u8 *)eeprom_data + AR6002_MAC_ADDRESS_OFFSET);
- break;
- case TARGET_TYPE_AR6003:
- ptr_mac = (u8 *)((u8 *)eeprom_data + AR6003_MAC_ADDRESS_OFFSET);
- break;
- default:
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Invalid Target Type\n"));
- return;
- }
- printk(KERN_DEBUG "MAC from EEPROM %pM\n", ptr_mac);
-
- /* create a random MAC in case we cannot read file from system */
- ptr_mac[0] = 0;
- ptr_mac[1] = 0x03;
- ptr_mac[2] = 0x7F;
- ptr_mac[3] = random32() & 0xff;
- ptr_mac[4] = random32() & 0xff;
- ptr_mac[5] = random32() & 0xff;
- if ((A_REQUEST_FIRMWARE(&softmac_entry, "softmac", ((struct device *)ar->osDevInfo.pOSDevice))) == 0)
- {
- char *macbuf = A_MALLOC_NOWAIT(softmac_entry->size+1);
- if (macbuf) {
- unsigned int softmac[6];
- memcpy(macbuf, softmac_entry->data, softmac_entry->size);
- macbuf[softmac_entry->size] = '\0';
- if (sscanf(macbuf, "%02x:%02x:%02x:%02x:%02x:%02x",
- &softmac[0], &softmac[1], &softmac[2],
- &softmac[3], &softmac[4], &softmac[5])==6) {
- int i;
- for (i=0; i<6; ++i) {
- ptr_mac[i] = softmac[i] & 0xff;
- }
- source = "softmac file";
- }
- kfree(macbuf);
- }
- A_RELEASE_FIRMWARE(softmac_entry);
- }
- printk(KERN_DEBUG "MAC from %s %pM\n", source, ptr_mac);
- calculate_crc(ar->arTargetType, eeprom_data);
-}
-#endif /* SOFTMAC_FILE_USED */
-
-static int
-ar6000_transfer_bin_file(struct ar6_softc *ar, AR6K_BIN_FILE file, u32 address, bool compressed)
-{
- int status;
- const char *filename;
- const struct firmware *fw_entry;
- u32 fw_entry_size;
- u8 **buf;
- size_t *buf_len;
-
- switch (file) {
- case AR6K_OTP_FILE:
- buf = &ar->fw_otp;
- buf_len = &ar->fw_otp_len;
- if (ar->arVersion.target_ver == AR6003_REV1_VERSION) {
- filename = AR6003_REV1_OTP_FILE;
- } else if (ar->arVersion.target_ver == AR6003_REV2_VERSION) {
- filename = AR6003_REV2_OTP_FILE;
- } else if (ar->arVersion.target_ver == AR6003_REV3_VERSION) {
- filename = AR6003_REV3_OTP_FILE;
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unknown firmware revision: %d\n", ar->arVersion.target_ver));
- return A_ERROR;
- }
- break;
-
- case AR6K_FIRMWARE_FILE:
- buf = &ar->fw;
- buf_len = &ar->fw_len;
- if (ar->arVersion.target_ver == AR6003_REV1_VERSION) {
- filename = AR6003_REV1_FIRMWARE_FILE;
- } else if (ar->arVersion.target_ver == AR6003_REV2_VERSION) {
- filename = AR6003_REV2_FIRMWARE_FILE;
- } else if (ar->arVersion.target_ver == AR6003_REV3_VERSION) {
- filename = AR6003_REV3_FIRMWARE_FILE;
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unknown firmware revision: %d\n", ar->arVersion.target_ver));
- return A_ERROR;
- }
-
- if (eppingtest) {
- bypasswmi = true;
- if (ar->arVersion.target_ver == AR6003_REV1_VERSION) {
- filename = AR6003_REV1_EPPING_FIRMWARE_FILE;
- } else if (ar->arVersion.target_ver == AR6003_REV2_VERSION) {
- filename = AR6003_REV2_EPPING_FIRMWARE_FILE;
- } else if (ar->arVersion.target_ver == AR6003_REV3_VERSION) {
- filename = AR6003_REV3_EPPING_FIRMWARE_FILE;
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("eppingtest : unsupported firmware revision: %d\n",
- ar->arVersion.target_ver));
- return A_ERROR;
- }
- compressed = false;
- }
-
-#ifdef CONFIG_HOST_TCMD_SUPPORT
- if(testmode) {
- if (ar->arVersion.target_ver == AR6003_REV1_VERSION) {
- filename = AR6003_REV1_TCMD_FIRMWARE_FILE;
- } else if (ar->arVersion.target_ver == AR6003_REV2_VERSION) {
- filename = AR6003_REV2_TCMD_FIRMWARE_FILE;
- } else if (ar->arVersion.target_ver == AR6003_REV3_VERSION) {
- filename = AR6003_REV3_TCMD_FIRMWARE_FILE;
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unknown firmware revision: %d\n", ar->arVersion.target_ver));
- return A_ERROR;
- }
- compressed = false;
- }
-#endif
-#ifdef HTC_RAW_INTERFACE
- if (!eppingtest && bypasswmi) {
- if (ar->arVersion.target_ver == AR6003_REV1_VERSION) {
- filename = AR6003_REV1_ART_FIRMWARE_FILE;
- } else if (ar->arVersion.target_ver == AR6003_REV2_VERSION) {
- filename = AR6003_REV2_ART_FIRMWARE_FILE;
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unknown firmware revision: %d\n", ar->arVersion.target_ver));
- return A_ERROR;
- }
- compressed = false;
- }
-#endif
- break;
-
- case AR6K_PATCH_FILE:
- buf = &ar->fw_patch;
- buf_len = &ar->fw_patch_len;
- if (ar->arVersion.target_ver == AR6003_REV1_VERSION) {
- filename = AR6003_REV1_PATCH_FILE;
- } else if (ar->arVersion.target_ver == AR6003_REV2_VERSION) {
- filename = AR6003_REV2_PATCH_FILE;
- } else if (ar->arVersion.target_ver == AR6003_REV3_VERSION) {
- filename = AR6003_REV3_PATCH_FILE;
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unknown firmware revision: %d\n", ar->arVersion.target_ver));
- return A_ERROR;
- }
- break;
-
- case AR6K_BOARD_DATA_FILE:
- buf = &ar->fw_data;
- buf_len = &ar->fw_data_len;
- if (ar->arVersion.target_ver == AR6003_REV1_VERSION) {
- filename = AR6003_REV1_BOARD_DATA_FILE;
- } else if (ar->arVersion.target_ver == AR6003_REV2_VERSION) {
- filename = AR6003_REV2_BOARD_DATA_FILE;
- } else if (ar->arVersion.target_ver == AR6003_REV3_VERSION) {
- filename = AR6003_REV3_BOARD_DATA_FILE;
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unknown firmware revision: %d\n", ar->arVersion.target_ver));
- return A_ERROR;
- }
- break;
-
- default:
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unknown file type: %d\n", file));
- return A_ERROR;
- }
-
- if (*buf == NULL) {
- if ((A_REQUEST_FIRMWARE(&fw_entry, filename, ((struct device *)ar->osDevInfo.pOSDevice))) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to get %s\n", filename));
- return A_ENOENT;
- }
-
- *buf = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
- *buf_len = fw_entry->size;
- A_RELEASE_FIRMWARE(fw_entry);
- }
-
-#ifdef SOFTMAC_FILE_USED
- if (file==AR6K_BOARD_DATA_FILE && *buf_len) {
- ar6000_softmac_update(ar, *buf, *buf_len);
- }
-#endif
-
-
- fw_entry_size = *buf_len;
-
- /* Load extended board data for AR6003 */
- if ((file==AR6K_BOARD_DATA_FILE) && *buf) {
- u32 board_ext_address;
- u32 board_ext_data_size;
- u32 board_data_size;
-
- board_ext_data_size = (((ar)->arTargetType == TARGET_TYPE_AR6002) ? AR6002_BOARD_EXT_DATA_SZ : \
- (((ar)->arTargetType == TARGET_TYPE_AR6003) ? AR6003_BOARD_EXT_DATA_SZ : 0));
-
- board_data_size = (((ar)->arTargetType == TARGET_TYPE_AR6002) ? AR6002_BOARD_DATA_SZ : \
- (((ar)->arTargetType == TARGET_TYPE_AR6003) ? AR6003_BOARD_DATA_SZ : 0));
-
- /* Determine where in Target RAM to write Board Data */
- bmifn(BMIReadMemory(ar->arHifDevice, HOST_INTEREST_ITEM_ADDRESS(ar, hi_board_ext_data), (u8 *)&board_ext_address, 4));
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("Board extended Data download address: 0x%x\n", board_ext_address));
-
- /* check whether the target has allocated memory for extended board data and file contains extended board data */
- if ((board_ext_address) && (*buf_len == (board_data_size + board_ext_data_size))) {
- u32 param;
-
- status = BMIWriteMemory(ar->arHifDevice, board_ext_address, (u8 *)(*buf + board_data_size), board_ext_data_size);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI operation failed: %d\n", __LINE__));
- return A_ERROR;
- }
-
- /* Record the fact that extended board Data IS initialized */
- param = (board_ext_data_size << 16) | 1;
- bmifn(BMIWriteMemory(ar->arHifDevice,
- HOST_INTEREST_ITEM_ADDRESS(ar, hi_board_ext_data_config),
- (unsigned char *)&param, 4));
- }
- fw_entry_size = board_data_size;
- }
-
- if (compressed) {
- status = BMIFastDownload(ar->arHifDevice, address, *buf, fw_entry_size);
- } else {
- status = BMIWriteMemory(ar->arHifDevice, address, *buf, fw_entry_size);
- }
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI operation failed: %d\n", __LINE__));
- return A_ERROR;
- }
-
- return 0;
-}
-
-int
-ar6000_update_bdaddr(struct ar6_softc *ar)
-{
-
- if (setupbtdev != 0) {
- u32 address;
-
- if (BMIReadMemory(ar->arHifDevice,
- HOST_INTEREST_ITEM_ADDRESS(ar, hi_board_data), (u8 *)&address, 4) != 0)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BMIReadMemory for hi_board_data failed\n"));
- return A_ERROR;
- }
-
- if (BMIReadMemory(ar->arHifDevice, address + BDATA_BDADDR_OFFSET, (u8 *)ar->bdaddr, 6) != 0)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BMIReadMemory for BD address failed\n"));
- return A_ERROR;
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BDADDR 0x%x:0x%x:0x%x:0x%x:0x%x:0x%x\n", ar->bdaddr[0],
- ar->bdaddr[1], ar->bdaddr[2], ar->bdaddr[3],
- ar->bdaddr[4], ar->bdaddr[5]));
- }
-
-return 0;
-}
-
-int
-ar6000_sysfs_bmi_get_config(struct ar6_softc *ar, u32 mode)
-{
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("BMI: Requesting device specific configuration\n"));
-
- if (mode == WLAN_INIT_MODE_UDEV) {
- char version[16];
- const struct firmware *fw_entry;
-
- /* Get config using udev through a script in user space */
- sprintf(version, "%2.2x", ar->arVersion.target_ver);
- if ((A_REQUEST_FIRMWARE(&fw_entry, version, ((struct device *)ar->osDevInfo.pOSDevice))) != 0)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI: Failure to get configuration for target version: %s\n", version));
- return A_ERROR;
- }
-
- A_RELEASE_FIRMWARE(fw_entry);
- } else {
- /* The config is contained within the driver itself */
- int status;
- u32 param, options, sleep, address;
-
- /* Temporarily disable system sleep */
- address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS;
- bmifn(BMIReadSOCRegister(ar->arHifDevice, address, &param));
- options = param;
- param |= AR6K_OPTION_SLEEP_DISABLE;
- bmifn(BMIWriteSOCRegister(ar->arHifDevice, address, param));
-
- address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS;
- bmifn(BMIReadSOCRegister(ar->arHifDevice, address, &param));
- sleep = param;
- param |= WLAN_SYSTEM_SLEEP_DISABLE_SET(1);
- bmifn(BMIWriteSOCRegister(ar->arHifDevice, address, param));
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("old options: %d, old sleep: %d\n", options, sleep));
-
- if (ar->arTargetType == TARGET_TYPE_AR6003) {
- /* Program analog PLL register */
- bmifn(BMIWriteSOCRegister(ar->arHifDevice, ANALOG_INTF_BASE_ADDRESS + 0x284, 0xF9104001));
- /* Run at 80/88MHz by default */
- param = CPU_CLOCK_STANDARD_SET(1);
- } else {
- /* Run at 40/44MHz by default */
- param = CPU_CLOCK_STANDARD_SET(0);
- }
- address = RTC_BASE_ADDRESS + CPU_CLOCK_ADDRESS;
- bmifn(BMIWriteSOCRegister(ar->arHifDevice, address, param));
-
- param = 0;
- if (ar->arTargetType == TARGET_TYPE_AR6002) {
- bmifn(BMIReadMemory(ar->arHifDevice, HOST_INTEREST_ITEM_ADDRESS(ar, hi_ext_clk_detected), (u8 *)&param, 4));
- }
-
- /* LPO_CAL.ENABLE = 1 if no external clk is detected */
- if (param != 1) {
- address = RTC_BASE_ADDRESS + LPO_CAL_ADDRESS;
- param = LPO_CAL_ENABLE_SET(1);
- bmifn(BMIWriteSOCRegister(ar->arHifDevice, address, param));
- }
-
- /* Venus2.0: Lower SDIO pad drive strength,
- * temporary WAR to avoid SDIO CRC error */
- if (ar->arVersion.target_ver == AR6003_REV2_VERSION) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("AR6K: Temporary WAR to avoid SDIO CRC error\n"));
- param = 0x20;
- address = GPIO_BASE_ADDRESS + GPIO_PIN10_ADDRESS;
- bmifn(BMIWriteSOCRegister(ar->arHifDevice, address, param));
-
- address = GPIO_BASE_ADDRESS + GPIO_PIN11_ADDRESS;
- bmifn(BMIWriteSOCRegister(ar->arHifDevice, address, param));
-
- address = GPIO_BASE_ADDRESS + GPIO_PIN12_ADDRESS;
- bmifn(BMIWriteSOCRegister(ar->arHifDevice, address, param));
-
- address = GPIO_BASE_ADDRESS + GPIO_PIN13_ADDRESS;
- bmifn(BMIWriteSOCRegister(ar->arHifDevice, address, param));
- }
-
-#ifdef FORCE_INTERNAL_CLOCK
- /* Ignore external clock, if any, and force use of internal clock */
- if (ar->arTargetType == TARGET_TYPE_AR6003) {
- /* hi_ext_clk_detected = 0 */
- param = 0;
- bmifn(BMIWriteMemory(ar->arHifDevice, HOST_INTEREST_ITEM_ADDRESS(ar, hi_ext_clk_detected), (u8 *)&param, 4));
-
- /* CLOCK_CONTROL &= ~LF_CLK32 */
- address = RTC_BASE_ADDRESS + CLOCK_CONTROL_ADDRESS;
- bmifn(BMIReadSOCRegister(ar->arHifDevice, address, &param));
- param &= (~CLOCK_CONTROL_LF_CLK32_SET(1));
- bmifn(BMIWriteSOCRegister(ar->arHifDevice, address, param));
- }
-#endif /* FORCE_INTERNAL_CLOCK */
-
- /* Transfer Board Data from Target EEPROM to Target RAM */
- if (ar->arTargetType == TARGET_TYPE_AR6003) {
- /* Determine where in Target RAM to write Board Data */
- bmifn(BMIReadMemory(ar->arHifDevice, HOST_INTEREST_ITEM_ADDRESS(ar, hi_board_data), (u8 *)&address, 4));
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("Board Data download address: 0x%x\n", address));
-
- /* Write EEPROM data to Target RAM */
- if ((ar6000_transfer_bin_file(ar, AR6K_BOARD_DATA_FILE, address, false)) != 0) {
- return A_ERROR;
- }
-
- /* Record the fact that Board Data IS initialized */
- param = 1;
- bmifn(BMIWriteMemory(ar->arHifDevice, HOST_INTEREST_ITEM_ADDRESS(ar, hi_board_data_initialized), (u8 *)&param, 4));
-
- /* Transfer One time Programmable data */
- AR6K_APP_LOAD_ADDRESS(address, ar->arVersion.target_ver);
- if (ar->arVersion.target_ver == AR6003_REV3_VERSION)
- address = 0x1234;
- status = ar6000_transfer_bin_file(ar, AR6K_OTP_FILE, address, true);
- if (status == 0) {
- /* Execute the OTP code */
- param = 0;
- AR6K_APP_START_OVERRIDE_ADDRESS(address, ar->arVersion.target_ver);
- bmifn(BMIExecute(ar->arHifDevice, address, &param));
- } else if (status != A_ENOENT) {
- return A_ERROR;
- }
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Programming of board data for chip %d not supported\n", ar->arTargetType));
- return A_ERROR;
- }
-
- /* Download Target firmware */
- AR6K_APP_LOAD_ADDRESS(address, ar->arVersion.target_ver);
- if (ar->arVersion.target_ver == AR6003_REV3_VERSION)
- address = 0x1234;
- if ((ar6000_transfer_bin_file(ar, AR6K_FIRMWARE_FILE, address, true)) != 0) {
- return A_ERROR;
- }
-
- /* Set starting address for firmware */
- AR6K_APP_START_OVERRIDE_ADDRESS(address, ar->arVersion.target_ver);
- bmifn(BMISetAppStart(ar->arHifDevice, address));
-
- if(ar->arTargetType == TARGET_TYPE_AR6003) {
- AR6K_DATASET_PATCH_ADDRESS(address, ar->arVersion.target_ver);
- if ((ar6000_transfer_bin_file(ar, AR6K_PATCH_FILE,
- address, false)) != 0)
- return A_ERROR;
- param = address;
- bmifn(BMIWriteMemory(ar->arHifDevice,
- HOST_INTEREST_ITEM_ADDRESS(ar, hi_dset_list_head),
- (unsigned char *)&param, 4));
- }
-
- /* Restore system sleep */
- address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS;
- bmifn(BMIWriteSOCRegister(ar->arHifDevice, address, sleep));
-
- address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS;
- param = options | 0x20;
- bmifn(BMIWriteSOCRegister(ar->arHifDevice, address, param));
-
- if (ar->arTargetType == TARGET_TYPE_AR6003) {
- /* Configure GPIO AR6003 UART */
-#ifndef CONFIG_AR600x_DEBUG_UART_TX_PIN
-#define CONFIG_AR600x_DEBUG_UART_TX_PIN 8
-#endif
- param = CONFIG_AR600x_DEBUG_UART_TX_PIN;
- bmifn(BMIWriteMemory(ar->arHifDevice, HOST_INTEREST_ITEM_ADDRESS(ar, hi_dbg_uart_txpin), (u8 *)&param, 4));
-
-#if (CONFIG_AR600x_DEBUG_UART_TX_PIN == 23)
- {
- address = GPIO_BASE_ADDRESS + CLOCK_GPIO_ADDRESS;
- bmifn(BMIReadSOCRegister(ar->arHifDevice, address, &param));
- param |= CLOCK_GPIO_BT_CLK_OUT_EN_SET(1);
- bmifn(BMIWriteSOCRegister(ar->arHifDevice, address, param));
- }
-#endif
-
- /* Configure GPIO for BT Reset */
-#ifdef ATH6KL_CONFIG_GPIO_BT_RESET
-#define CONFIG_AR600x_BT_RESET_PIN 0x16
- param = CONFIG_AR600x_BT_RESET_PIN;
- bmifn(BMIWriteMemory(ar->arHifDevice, HOST_INTEREST_ITEM_ADDRESS(ar, hi_hci_uart_support_pins), (u8 *)&param, 4));
-#endif /* ATH6KL_CONFIG_GPIO_BT_RESET */
-
- /* Configure UART flow control polarity */
-#ifndef CONFIG_ATH6KL_BT_UART_FC_POLARITY
-#define CONFIG_ATH6KL_BT_UART_FC_POLARITY 0
-#endif
-
-#if (CONFIG_ATH6KL_BT_UART_FC_POLARITY == 1)
- if (ar->arVersion.target_ver == AR6003_REV2_VERSION) {
- param = ((CONFIG_ATH6KL_BT_UART_FC_POLARITY << 1) & 0x2);
- bmifn(BMIWriteMemory(ar->arHifDevice, HOST_INTEREST_ITEM_ADDRESS(ar, hi_hci_uart_pwr_mgmt_params), (u8 *)&param, 4));
- }
-#endif /* CONFIG_ATH6KL_BT_UART_FC_POLARITY */
- }
-
-#ifdef HTC_RAW_INTERFACE
- if (!eppingtest && bypasswmi) {
- /* Don't run BMIDone for ART mode and force resetok=0 */
- resetok = 0;
- msleep(1000);
- }
-#endif /* HTC_RAW_INTERFACE */
- }
-
- return 0;
-}
-
-int
-ar6000_configure_target(struct ar6_softc *ar)
-{
- u32 param;
- if (enableuartprint) {
- param = 1;
- if (BMIWriteMemory(ar->arHifDevice,
- HOST_INTEREST_ITEM_ADDRESS(ar, hi_serial_enable),
- (u8 *)&param,
- 4)!= 0)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BMIWriteMemory for enableuartprint failed \n"));
- return A_ERROR;
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("Serial console prints enabled\n"));
- }
-
- /* Tell target which HTC version it is used*/
- param = HTC_PROTOCOL_VERSION;
- if (BMIWriteMemory(ar->arHifDevice,
- HOST_INTEREST_ITEM_ADDRESS(ar, hi_app_host_interest),
- (u8 *)&param,
- 4)!= 0)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BMIWriteMemory for htc version failed \n"));
- return A_ERROR;
- }
-
-#ifdef CONFIG_HOST_TCMD_SUPPORT
- if(testmode) {
- ar->arTargetMode = AR6000_TCMD_MODE;
- }else {
- ar->arTargetMode = AR6000_WLAN_MODE;
- }
-#endif
- if (enabletimerwar) {
- u32 param;
-
- if (BMIReadMemory(ar->arHifDevice,
- HOST_INTEREST_ITEM_ADDRESS(ar, hi_option_flag),
- (u8 *)&param,
- 4)!= 0)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BMIReadMemory for enabletimerwar failed \n"));
- return A_ERROR;
- }
-
- param |= HI_OPTION_TIMER_WAR;
-
- if (BMIWriteMemory(ar->arHifDevice,
- HOST_INTEREST_ITEM_ADDRESS(ar, hi_option_flag),
- (u8 *)&param,
- 4) != 0)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BMIWriteMemory for enabletimerwar failed \n"));
- return A_ERROR;
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("Timer WAR enabled\n"));
- }
-
- /* set the firmware mode to STA/IBSS/AP */
- {
- u32 param;
-
- if (BMIReadMemory(ar->arHifDevice,
- HOST_INTEREST_ITEM_ADDRESS(ar, hi_option_flag),
- (u8 *)&param,
- 4)!= 0)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BMIReadMemory for setting fwmode failed \n"));
- return A_ERROR;
- }
-
- param |= (num_device << HI_OPTION_NUM_DEV_SHIFT);
- param |= (fwmode << HI_OPTION_FW_MODE_SHIFT);
- param |= (mac_addr_method << HI_OPTION_MAC_ADDR_METHOD_SHIFT);
- param |= (firmware_bridge << HI_OPTION_FW_BRIDGE_SHIFT);
-
-
- if (BMIWriteMemory(ar->arHifDevice,
- HOST_INTEREST_ITEM_ADDRESS(ar, hi_option_flag),
- (u8 *)&param,
- 4) != 0)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BMIWriteMemory for setting fwmode failed \n"));
- return A_ERROR;
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("Firmware mode set\n"));
- }
-
-#ifdef ATH6KL_DISABLE_TARGET_DBGLOGS
- {
- u32 param;
-
- if (BMIReadMemory(ar->arHifDevice,
- HOST_INTEREST_ITEM_ADDRESS(ar, hi_option_flag),
- (u8 *)&param,
- 4)!= 0)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BMIReadMemory for disabling debug logs failed\n"));
- return A_ERROR;
- }
-
- param |= HI_OPTION_DISABLE_DBGLOG;
-
- if (BMIWriteMemory(ar->arHifDevice,
- HOST_INTEREST_ITEM_ADDRESS(ar, hi_option_flag),
- (u8 *)&param,
- 4) != 0)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BMIWriteMemory for HI_OPTION_DISABLE_DBGLOG\n"));
- return A_ERROR;
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("Firmware mode set\n"));
- }
-#endif /* ATH6KL_DISABLE_TARGET_DBGLOGS */
-
- /*
- * Hardcode the address use for the extended board data
- * Ideally this should be pre-allocate by the OS at boot time
- * But since it is a new feature and board data is loaded
- * at init time, we have to workaround this from host.
- * It is difficult to patch the firmware boot code,
- * but possible in theory.
- */
-
- if (ar->arTargetType == TARGET_TYPE_AR6003) {
- u32 ramReservedSz;
- if (ar->arVersion.target_ver == AR6003_REV2_VERSION) {
- param = AR6003_REV2_BOARD_EXT_DATA_ADDRESS;
- ramReservedSz = AR6003_REV2_RAM_RESERVE_SIZE;
- } else {
- param = AR6003_REV3_BOARD_EXT_DATA_ADDRESS;
- ramReservedSz = AR6003_REV3_RAM_RESERVE_SIZE;
- }
- if (BMIWriteMemory(ar->arHifDevice,
- HOST_INTEREST_ITEM_ADDRESS(ar, hi_board_ext_data),
- (u8 *)&param, 4) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("BMIWriteMemory for "
- "hi_board_ext_data failed\n"));
- return A_ERROR;
- }
- if (BMIWriteMemory(ar->arHifDevice,
- HOST_INTEREST_ITEM_ADDRESS(ar,
- hi_end_RAM_reserve_sz),
- (u8 *)&ramReservedSz, 4) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR ,
- ("BMIWriteMemory for "
- "hi_end_RAM_reserve_sz failed\n"));
- return A_ERROR;
- }
- }
-
- /* since BMIInit is called in the driver layer, we have to set the block
- * size here for the target */
-
- if (ar6000_set_htc_params(ar->arHifDevice, ar->arTargetType,
- mbox_yield_limit, 0)) {
- /* use default number of control buffers */
- return A_ERROR;
- }
-
- if (setupbtdev != 0) {
- if (ar6000_set_hci_bridge_flags(ar->arHifDevice,
- ar->arTargetType,
- setupbtdev)) {
- return A_ERROR;
- }
- }
- return 0;
-}
-
-static void
-init_netdev(struct net_device *dev, char *name)
-{
- dev->netdev_ops = &ar6000_netdev_ops;
- dev->watchdog_timeo = AR6000_TX_TIMEOUT;
-
- /*
- * We need the OS to provide us with more headroom in order to
- * perform dix to 802.3, WMI header encap, and the HTC header
- */
- if (processDot11Hdr) {
- dev->hard_header_len = sizeof(struct ieee80211_qosframe) + sizeof(ATH_LLC_SNAP_HDR) + sizeof(WMI_DATA_HDR) + HTC_HEADER_LEN + WMI_MAX_TX_META_SZ + LINUX_HACK_FUDGE_FACTOR;
- } else {
- dev->hard_header_len = ETH_HLEN + sizeof(ATH_LLC_SNAP_HDR) +
- sizeof(WMI_DATA_HDR) + HTC_HEADER_LEN + WMI_MAX_TX_META_SZ + LINUX_HACK_FUDGE_FACTOR;
- }
-
- if (name[0])
- {
- strcpy(dev->name, name);
- }
-
-#ifdef CONFIG_CHECKSUM_OFFLOAD
- if(csumOffload){
- dev->features |= NETIF_F_IP_CSUM; /*advertise kernel capability to do TCP/UDP CSUM offload for IPV4*/
- }
-#endif
-
- return;
-}
-
-static int __ath6kl_init_netdev(struct net_device *dev)
-{
- int r;
-
- rtnl_lock();
- r = ar6000_init(dev);
- rtnl_unlock();
-
- if (r) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("ar6000_avail: ar6000_init\n"));
- return r;
- }
-
- return 0;
-}
-
-#ifdef HTC_RAW_INTERFACE
-static int ath6kl_init_netdev_wmi(struct net_device *dev)
-{
- if (!eppingtest && bypasswmi)
- return 0;
-
- return __ath6kl_init_netdev(dev);
-}
-#else
-static int ath6kl_init_netdev_wmi(struct net_device *dev)
-{
- return __ath6kl_init_netdev(dev);
-}
-#endif
-
-static int ath6kl_init_netdev(struct ar6_softc *ar)
-{
- int r;
-
- r = ar6000_sysfs_bmi_get_config(ar, wlaninitmode);
- if (r) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("ar6000_avail: "
- "ar6000_sysfs_bmi_get_config failed\n"));
- return r;
- }
-
- return ath6kl_init_netdev_wmi(ar->arNetDev);
-}
-
-/*
- * HTC Event handlers
- */
-static int
-ar6000_avail_ev(void *context, void *hif_handle)
-{
- int i;
- struct net_device *dev;
- void *ar_netif;
- struct ar6_softc *ar;
- int device_index = 0;
- struct htc_init_info htcInfo;
- struct wireless_dev *wdev;
- int r = 0;
- struct hif_device_os_device_info osDevInfo;
-
- memset(&osDevInfo, 0, sizeof(osDevInfo));
- if (HIFConfigureDevice(hif_handle, HIF_DEVICE_GET_OS_DEVICE,
- &osDevInfo, sizeof(osDevInfo))) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: Failed to get OS device instance\n", __func__));
- return A_ERROR;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("ar6000_available\n"));
-
- for (i=0; i < MAX_AR6000; i++) {
- if (ar6000_devices[i] == NULL) {
- break;
- }
- }
-
- if (i == MAX_AR6000) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("ar6000_available: max devices reached\n"));
- return A_ERROR;
- }
-
- /* Save this. It gives a bit better readability especially since */
- /* we use another local "i" variable below. */
- device_index = i;
-
- wdev = ar6k_cfg80211_init(osDevInfo.pOSDevice);
- if (IS_ERR(wdev)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: ar6k_cfg80211_init failed\n", __func__));
- return A_ERROR;
- }
- ar_netif = wdev_priv(wdev);
-
- if (ar_netif == NULL) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Can't allocate ar6k priv memory\n", __func__));
- return A_ERROR;
- }
-
- A_MEMZERO(ar_netif, sizeof(struct ar6_softc));
- ar = (struct ar6_softc *)ar_netif;
-
- ar->wdev = wdev;
- wdev->iftype = NL80211_IFTYPE_STATION;
-
- dev = alloc_netdev_mq(0, "wlan%d", ether_setup, 1);
- if (!dev) {
- printk(KERN_CRIT "AR6K: no memory for network device instance\n");
- ar6k_cfg80211_deinit(ar);
- return A_ERROR;
- }
-
- dev->ieee80211_ptr = wdev;
- SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy));
- wdev->netdev = dev;
- ar->arNetworkType = INFRA_NETWORK;
- ar->smeState = SME_DISCONNECTED;
- ar->arAutoAuthStage = AUTH_IDLE;
-
- init_netdev(dev, ifname);
-
-
- ar->arNetDev = dev;
- ar->arHifDevice = hif_handle;
- ar->arWlanState = WLAN_ENABLED;
- ar->arDeviceIndex = device_index;
-
- ar->arWlanPowerState = WLAN_POWER_STATE_ON;
- ar->arWlanOff = false; /* We are in ON state */
-#ifdef CONFIG_PM
- ar->arWowState = WLAN_WOW_STATE_NONE;
- ar->arBTOff = true; /* BT chip assumed to be OFF */
- ar->arBTSharing = WLAN_CONFIG_BT_SHARING;
- ar->arWlanOffConfig = WLAN_CONFIG_WLAN_OFF;
- ar->arSuspendConfig = WLAN_CONFIG_PM_SUSPEND;
- ar->arWow2Config = WLAN_CONFIG_PM_WOW2;
-#endif /* CONFIG_PM */
-
- A_INIT_TIMER(&ar->arHBChallengeResp.timer, ar6000_detect_error, dev);
- ar->arHBChallengeResp.seqNum = 0;
- ar->arHBChallengeResp.outstanding = false;
- ar->arHBChallengeResp.missCnt = 0;
- ar->arHBChallengeResp.frequency = AR6000_HB_CHALLENGE_RESP_FREQ_DEFAULT;
- ar->arHBChallengeResp.missThres = AR6000_HB_CHALLENGE_RESP_MISS_THRES_DEFAULT;
-
- ar6000_init_control_info(ar);
- init_waitqueue_head(&arEvent);
- sema_init(&ar->arSem, 1);
- ar->bIsDestroyProgress = false;
-
- INIT_HTC_PACKET_QUEUE(&ar->amsdu_rx_buffer_queue);
-
-#ifdef ADAPTIVE_POWER_THROUGHPUT_CONTROL
- A_INIT_TIMER(&aptcTimer, aptcTimerHandler, ar);
-#endif /* ADAPTIVE_POWER_THROUGHPUT_CONTROL */
-
- A_INIT_TIMER(&ar->disconnect_timer, disconnect_timer_handler, dev);
-
- BMIInit();
-
- ar6000_sysfs_bmi_init(ar);
-
- {
- struct bmi_target_info targ_info;
-
- r = BMIGetTargetInfo(ar->arHifDevice, &targ_info);
- if (r)
- goto avail_ev_failed;
-
- ar->arVersion.target_ver = targ_info.target_ver;
- ar->arTargetType = targ_info.target_type;
- wdev->wiphy->hw_version = targ_info.target_ver;
- }
-
- r = ar6000_configure_target(ar);
- if (r)
- goto avail_ev_failed;
-
- A_MEMZERO(&htcInfo,sizeof(htcInfo));
- htcInfo.pContext = ar;
- htcInfo.TargetFailure = ar6000_target_failure;
-
- ar->arHtcTarget = HTCCreate(ar->arHifDevice,&htcInfo);
-
- if (!ar->arHtcTarget) {
- r = -ENOMEM;
- goto avail_ev_failed;
- }
-
- spin_lock_init(&ar->arLock);
-
-#ifdef WAPI_ENABLE
- ar->arWapiEnable = 0;
-#endif
-
-
- if(csumOffload){
- /*if external frame work is also needed, change and use an extended rxMetaVerion*/
- ar->rxMetaVersion=WMI_META_VERSION_2;
- }
-
- ar->aggr_cntxt = aggr_init(ar6000_alloc_netbufs);
- if (!ar->aggr_cntxt) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s() Failed to initialize aggr.\n", __func__));
- r = -ENOMEM;
- goto avail_ev_failed;
- }
-
- aggr_register_rx_dispatcher(ar->aggr_cntxt, (void *)dev, ar6000_deliver_frames_to_nw_stack);
-
- HIFClaimDevice(ar->arHifDevice, ar);
-
- /* We only register the device in the global list if we succeed. */
- /* If the device is in the global list, it will be destroyed */
- /* when the module is unloaded. */
- ar6000_devices[device_index] = dev;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("BMI enabled: %d\n", wlaninitmode));
- if ((wlaninitmode == WLAN_INIT_MODE_UDEV) ||
- (wlaninitmode == WLAN_INIT_MODE_DRV)) {
- r = ath6kl_init_netdev(ar);
- if (r)
- goto avail_ev_failed;
- }
-
- /* This runs the init function if registered */
- r = register_netdev(dev);
- if (r) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("ar6000_avail: register_netdev failed\n"));
- ar6000_destroy(dev, 0);
- return r;
- }
-
- is_netdev_registered = 1;
-
-#ifdef CONFIG_AP_VIRTUAL_ADAPTER_SUPPORT
- arApNetDev = NULL;
-#endif /* CONFIG_AP_VIRTUAL_ADAPTER_SUPPORT */
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("ar6000_avail: name=%s hifdevice=0x%lx, dev=0x%lx (%d), ar=0x%lx\n",
- dev->name, (unsigned long)ar->arHifDevice, (unsigned long)dev, device_index,
- (unsigned long)ar));
-
-avail_ev_failed :
- if (r)
- ar6000_sysfs_bmi_deinit(ar);
-
- return r;
-}
-
-static void ar6000_target_failure(void *Instance, int Status)
-{
- struct ar6_softc *ar = (struct ar6_softc *)Instance;
- WMI_TARGET_ERROR_REPORT_EVENT errEvent;
- static bool sip = false;
-
- if (Status != 0) {
-
- printk(KERN_ERR "ar6000_target_failure: target asserted \n");
-
- if (timer_pending(&ar->arHBChallengeResp.timer)) {
- A_UNTIMEOUT(&ar->arHBChallengeResp.timer);
- }
-
- /* try dumping target assertion information (if any) */
- ar6000_dump_target_assert_info(ar->arHifDevice,ar->arTargetType);
-
- /*
- * Fetch the logs from the target via the diagnostic
- * window.
- */
- ar6000_dbglog_get_debug_logs(ar);
-
- /* Report the error only once */
- if (!sip) {
- sip = true;
- errEvent.errorVal = WMI_TARGET_COM_ERR |
- WMI_TARGET_FATAL_ERR;
- }
- }
-}
-
-static int
-ar6000_unavail_ev(void *context, void *hif_handle)
-{
- struct ar6_softc *ar = (struct ar6_softc *)context;
- /* NULL out it's entry in the global list */
- ar6000_devices[ar->arDeviceIndex] = NULL;
- ar6000_destroy(ar->arNetDev, 1);
-
- return 0;
-}
-
-void
-ar6000_restart_endpoint(struct net_device *dev)
-{
- int status = 0;
- struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev);
-
- BMIInit();
- do {
- if ( (status=ar6000_configure_target(ar))!= 0)
- break;
- if ( (status=ar6000_sysfs_bmi_get_config(ar, wlaninitmode)) != 0)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("ar6000_avail: ar6000_sysfs_bmi_get_config failed\n"));
- break;
- }
- rtnl_lock();
- status = (ar6000_init(dev)==0) ? 0 : A_ERROR;
- rtnl_unlock();
-
- if (status) {
- break;
- }
- if (ar->arSsidLen && ar->arWlanState == WLAN_ENABLED) {
- ar6000_connect_to_ap(ar);
- }
- } while (0);
-
- if (status== 0) {
- return;
- }
-
- ar6000_devices[ar->arDeviceIndex] = NULL;
- ar6000_destroy(ar->arNetDev, 1);
-}
-
-void
-ar6000_stop_endpoint(struct net_device *dev, bool keepprofile, bool getdbglogs)
-{
- struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev);
-
- /* Stop the transmit queues */
- netif_stop_queue(dev);
-
- /* Disable the target and the interrupts associated with it */
- if (ar->arWmiReady == true)
- {
- if (!bypasswmi)
- {
- bool disconnectIssued;
-
- disconnectIssued = (ar->arConnected) || (ar->arConnectPending);
- ar6000_disconnect(ar);
- if (!keepprofile) {
- ar6000_init_profile_info(ar);
- }
-
- A_UNTIMEOUT(&ar->disconnect_timer);
-
- if (getdbglogs) {
- ar6000_dbglog_get_debug_logs(ar);
- }
-
- ar->arWmiReady = false;
- wmi_shutdown(ar->arWmi);
- ar->arWmiEnabled = false;
- ar->arWmi = NULL;
- /*
- * After wmi_shudown all WMI events will be dropped.
- * We need to cleanup the buffers allocated in AP mode
- * and give disconnect notification to stack, which usually
- * happens in the disconnect_event.
- * Simulate the disconnect_event by calling the function directly.
- * Sometimes disconnect_event will be received when the debug logs
- * are collected.
- */
- if (disconnectIssued) {
- if(ar->arNetworkType & AP_NETWORK) {
- ar6000_disconnect_event(ar, DISCONNECT_CMD, bcast_mac, 0, NULL, 0);
- } else {
- ar6000_disconnect_event(ar, DISCONNECT_CMD, ar->arBssid, 0, NULL, 0);
- }
- }
- ar->user_savedkeys_stat = USER_SAVEDKEYS_STAT_INIT;
- ar->user_key_ctrl = 0;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("%s(): WMI stopped\n", __func__));
- }
- else
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("%s(): WMI not ready 0x%lx 0x%lx\n",
- __func__, (unsigned long) ar, (unsigned long) ar->arWmi));
-
- /* Shut down WMI if we have started it */
- if(ar->arWmiEnabled == true)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("%s(): Shut down WMI\n", __func__));
- wmi_shutdown(ar->arWmi);
- ar->arWmiEnabled = false;
- ar->arWmi = NULL;
- }
- }
-
- if (ar->arHtcTarget != NULL) {
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
- if (NULL != ar6kHciTransCallbacks.cleanupTransport) {
- ar6kHciTransCallbacks.cleanupTransport(NULL);
- }
-#else
- // FIXME: workaround to reset BT's UART baud rate to default
- if (NULL != ar->exitCallback) {
- struct ar3k_config_info ar3kconfig;
- int status;
-
- A_MEMZERO(&ar3kconfig,sizeof(ar3kconfig));
- ar6000_set_default_ar3kconfig(ar, (void *)&ar3kconfig);
- status = ar->exitCallback(&ar3kconfig);
- if (0 != status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to reset AR3K baud rate! \n"));
- }
- }
- // END workaround
- if (setuphci)
- ar6000_cleanup_hci(ar);
-#endif
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,(" Shutting down HTC .... \n"));
- /* stop HTC */
- HTCStop(ar->arHtcTarget);
- }
-
- if (resetok) {
- /* try to reset the device if we can
- * The driver may have been configure NOT to reset the target during
- * a debug session */
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,(" Attempting to reset target on instance destroy.... \n"));
- if (ar->arHifDevice != NULL) {
- bool coldReset = (ar->arTargetType == TARGET_TYPE_AR6003) ? true: false;
- ar6000_reset_device(ar->arHifDevice, ar->arTargetType, true, coldReset);
- }
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,(" Host does not want target reset. \n"));
- }
- /* Done with cookies */
- ar6000_cookie_cleanup(ar);
-
- /* cleanup any allocated AMSDU buffers */
- ar6000_cleanup_amsdu_rxbufs(ar);
-}
-/*
- * We need to differentiate between the surprise and planned removal of the
- * device because of the following consideration:
- * - In case of surprise removal, the hcd already frees up the pending
- * for the device and hence there is no need to unregister the function
- * driver inorder to get these requests. For planned removal, the function
- * driver has to explicitly unregister itself to have the hcd return all the
- * pending requests before the data structures for the devices are freed up.
- * Note that as per the current implementation, the function driver will
- * end up releasing all the devices since there is no API to selectively
- * release a particular device.
- * - Certain commands issued to the target can be skipped for surprise
- * removal since they will anyway not go through.
- */
-void
-ar6000_destroy(struct net_device *dev, unsigned int unregister)
-{
- struct ar6_softc *ar;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("+ar6000_destroy \n"));
-
- if((dev == NULL) || ((ar = ar6k_priv(dev)) == NULL))
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s(): Failed to get device structure.\n", __func__));
- return;
- }
-
- ar->bIsDestroyProgress = true;
-
- if (down_interruptible(&ar->arSem)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s(): down_interruptible failed \n", __func__));
- return;
- }
-
- if (ar->arWlanPowerState != WLAN_POWER_STATE_CUT_PWR) {
- /* only stop endpoint if we are not stop it in suspend_ev */
- ar6000_stop_endpoint(dev, false, true);
- }
-
- ar->arWlanState = WLAN_DISABLED;
- if (ar->arHtcTarget != NULL) {
- /* destroy HTC */
- HTCDestroy(ar->arHtcTarget);
- }
- if (ar->arHifDevice != NULL) {
- /*release the device so we do not get called back on remove incase we
- * we're explicity destroyed by module unload */
- HIFReleaseDevice(ar->arHifDevice);
- HIFShutDownDevice(ar->arHifDevice);
- }
- aggr_module_destroy(ar->aggr_cntxt);
-
- /* Done with cookies */
- ar6000_cookie_cleanup(ar);
-
- /* cleanup any allocated AMSDU buffers */
- ar6000_cleanup_amsdu_rxbufs(ar);
-
- ar6000_sysfs_bmi_deinit(ar);
-
- /* Cleanup BMI */
- BMICleanup();
-
- /* Clear the tx counters */
- memset(tx_attempt, 0, sizeof(tx_attempt));
- memset(tx_post, 0, sizeof(tx_post));
- memset(tx_complete, 0, sizeof(tx_complete));
-
-#ifdef HTC_RAW_INTERFACE
- if (ar->arRawHtc) {
- kfree(ar->arRawHtc);
- ar->arRawHtc = NULL;
- }
-#endif
- /* Free up the device data structure */
- if (unregister && is_netdev_registered) {
- unregister_netdev(dev);
- is_netdev_registered = 0;
- }
- free_netdev(dev);
-
- ar6k_cfg80211_deinit(ar);
-
-#ifdef CONFIG_AP_VIRTUL_ADAPTER_SUPPORT
- ar6000_remove_ap_interface();
-#endif /*CONFIG_AP_VIRTUAL_ADAPTER_SUPPORT */
-
- kfree(ar->fw_otp);
- kfree(ar->fw);
- kfree(ar->fw_patch);
- kfree(ar->fw_data);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("-ar6000_destroy \n"));
-}
-
-static void disconnect_timer_handler(unsigned long ptr)
-{
- struct net_device *dev = (struct net_device *)ptr;
- struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev);
-
- A_UNTIMEOUT(&ar->disconnect_timer);
-
- ar6000_init_profile_info(ar);
- ar6000_disconnect(ar);
-}
-
-static void ar6000_detect_error(unsigned long ptr)
-{
- struct net_device *dev = (struct net_device *)ptr;
- struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev);
- WMI_TARGET_ERROR_REPORT_EVENT errEvent;
-
- AR6000_SPIN_LOCK(&ar->arLock, 0);
-
- if (ar->arHBChallengeResp.outstanding) {
- ar->arHBChallengeResp.missCnt++;
- } else {
- ar->arHBChallengeResp.missCnt = 0;
- }
-
- if (ar->arHBChallengeResp.missCnt > ar->arHBChallengeResp.missThres) {
- /* Send Error Detect event to the application layer and do not reschedule the error detection module timer */
- ar->arHBChallengeResp.missCnt = 0;
- ar->arHBChallengeResp.seqNum = 0;
- errEvent.errorVal = WMI_TARGET_COM_ERR | WMI_TARGET_FATAL_ERR;
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
- return;
- }
-
- /* Generate the sequence number for the next challenge */
- ar->arHBChallengeResp.seqNum++;
- ar->arHBChallengeResp.outstanding = true;
-
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
-
- /* Send the challenge on the control channel */
- if (wmi_get_challenge_resp_cmd(ar->arWmi, ar->arHBChallengeResp.seqNum, DRV_HB_CHALLENGE) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Unable to send heart beat challenge\n"));
- }
-
-
- /* Reschedule the timer for the next challenge */
- A_TIMEOUT_MS(&ar->arHBChallengeResp.timer, ar->arHBChallengeResp.frequency * 1000, 0);
-}
-
-void ar6000_init_profile_info(struct ar6_softc *ar)
-{
- ar->arSsidLen = 0;
- A_MEMZERO(ar->arSsid, sizeof(ar->arSsid));
-
- switch(fwmode) {
- case HI_OPTION_FW_MODE_IBSS:
- ar->arNetworkType = ar->arNextMode = ADHOC_NETWORK;
- break;
- case HI_OPTION_FW_MODE_BSS_STA:
- ar->arNetworkType = ar->arNextMode = INFRA_NETWORK;
- break;
- case HI_OPTION_FW_MODE_AP:
- ar->arNetworkType = ar->arNextMode = AP_NETWORK;
- break;
- }
-
- ar->arDot11AuthMode = OPEN_AUTH;
- ar->arAuthMode = NONE_AUTH;
- ar->arPairwiseCrypto = NONE_CRYPT;
- ar->arPairwiseCryptoLen = 0;
- ar->arGroupCrypto = NONE_CRYPT;
- ar->arGroupCryptoLen = 0;
- A_MEMZERO(ar->arWepKeyList, sizeof(ar->arWepKeyList));
- A_MEMZERO(ar->arReqBssid, sizeof(ar->arReqBssid));
- A_MEMZERO(ar->arBssid, sizeof(ar->arBssid));
- ar->arBssChannel = 0;
-}
-
-static void
-ar6000_init_control_info(struct ar6_softc *ar)
-{
- ar->arWmiEnabled = false;
- ar6000_init_profile_info(ar);
- ar->arDefTxKeyIndex = 0;
- A_MEMZERO(ar->arWepKeyList, sizeof(ar->arWepKeyList));
- ar->arChannelHint = 0;
- ar->arListenIntervalT = A_DEFAULT_LISTEN_INTERVAL;
- ar->arListenIntervalB = 0;
- ar->arVersion.host_ver = AR6K_SW_VERSION;
- ar->arRssi = 0;
- ar->arTxPwr = 0;
- ar->arTxPwrSet = false;
- ar->arSkipScan = 0;
- ar->arBeaconInterval = 0;
- ar->arBitRate = 0;
- ar->arMaxRetries = 0;
- ar->arWmmEnabled = true;
- ar->intra_bss = 1;
- ar->scan_triggered = 0;
- A_MEMZERO(&ar->scParams, sizeof(ar->scParams));
- ar->scParams.shortScanRatio = WMI_SHORTSCANRATIO_DEFAULT;
- ar->scParams.scanCtrlFlags = DEFAULT_SCAN_CTRL_FLAGS;
-
- /* Initialize the AP mode state info */
- {
- u8 ctr;
- A_MEMZERO((u8 *)ar->sta_list, AP_MAX_NUM_STA * sizeof(sta_t));
-
- /* init the Mutexes */
- A_MUTEX_INIT(&ar->mcastpsqLock);
-
- /* Init the PS queues */
- for (ctr=0; ctr < AP_MAX_NUM_STA ; ctr++) {
- A_MUTEX_INIT(&ar->sta_list[ctr].psqLock);
- A_NETBUF_QUEUE_INIT(&ar->sta_list[ctr].psq);
- }
-
- ar->ap_profile_flag = 0;
- A_NETBUF_QUEUE_INIT(&ar->mcastpsq);
-
- memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
- ar->ap_wmode = DEF_AP_WMODE_G;
- ar->ap_dtim_period = DEF_AP_DTIM;
- ar->ap_beacon_interval = DEF_BEACON_INTERVAL;
- }
-}
-
-static int
-ar6000_open(struct net_device *dev)
-{
- unsigned long flags;
- struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev);
-
- spin_lock_irqsave(&ar->arLock, flags);
-
- if(ar->arWlanState == WLAN_DISABLED) {
- ar->arWlanState = WLAN_ENABLED;
- }
-
- if( ar->arConnected || bypasswmi) {
- netif_carrier_on(dev);
- /* Wake up the queues */
- netif_wake_queue(dev);
- }
- else
- netif_carrier_off(dev);
-
- spin_unlock_irqrestore(&ar->arLock, flags);
- return 0;
-}
-
-static int
-ar6000_close(struct net_device *dev)
-{
- struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev);
- netif_stop_queue(dev);
-
- ar6000_disconnect(ar);
-
- if(ar->arWmiReady == true) {
- if (wmi_scanparams_cmd(ar->arWmi, 0xFFFF, 0,
- 0, 0, 0, 0, 0, 0, 0, 0) != 0) {
- return -EIO;
- }
- ar->arWlanState = WLAN_DISABLED;
- }
- ar6k_cfg80211_scanComplete_event(ar, A_ECANCELED);
-
- return 0;
-}
-
-/* connect to a service */
-static int ar6000_connectservice(struct ar6_softc *ar,
- struct htc_service_connect_req *pConnect,
- char *pDesc)
-{
- int status;
- struct htc_service_connect_resp response;
-
- do {
-
- A_MEMZERO(&response,sizeof(response));
-
- status = HTCConnectService(ar->arHtcTarget,
- pConnect,
- &response);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" Failed to connect to %s service status:%d \n",
- pDesc, status));
- break;
- }
- switch (pConnect->ServiceID) {
- case WMI_CONTROL_SVC :
- if (ar->arWmiEnabled) {
- /* set control endpoint for WMI use */
- wmi_set_control_ep(ar->arWmi, response.Endpoint);
- }
- /* save EP for fast lookup */
- ar->arControlEp = response.Endpoint;
- break;
- case WMI_DATA_BE_SVC :
- arSetAc2EndpointIDMap(ar, WMM_AC_BE, response.Endpoint);
- break;
- case WMI_DATA_BK_SVC :
- arSetAc2EndpointIDMap(ar, WMM_AC_BK, response.Endpoint);
- break;
- case WMI_DATA_VI_SVC :
- arSetAc2EndpointIDMap(ar, WMM_AC_VI, response.Endpoint);
- break;
- case WMI_DATA_VO_SVC :
- arSetAc2EndpointIDMap(ar, WMM_AC_VO, response.Endpoint);
- break;
- default:
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("ServiceID not mapped %d\n", pConnect->ServiceID));
- status = A_EINVAL;
- break;
- }
-
- } while (false);
-
- return status;
-}
-
-void ar6000_TxDataCleanup(struct ar6_softc *ar)
-{
- /* flush all the data (non-control) streams
- * we only flush packets that are tagged as data, we leave any control packets that
- * were in the TX queues alone */
- HTCFlushEndpoint(ar->arHtcTarget,
- arAc2EndpointID(ar, WMM_AC_BE),
- AR6K_DATA_PKT_TAG);
- HTCFlushEndpoint(ar->arHtcTarget,
- arAc2EndpointID(ar, WMM_AC_BK),
- AR6K_DATA_PKT_TAG);
- HTCFlushEndpoint(ar->arHtcTarget,
- arAc2EndpointID(ar, WMM_AC_VI),
- AR6K_DATA_PKT_TAG);
- HTCFlushEndpoint(ar->arHtcTarget,
- arAc2EndpointID(ar, WMM_AC_VO),
- AR6K_DATA_PKT_TAG);
-}
-
-HTC_ENDPOINT_ID
-ar6000_ac2_endpoint_id ( void * devt, u8 ac)
-{
- struct ar6_softc *ar = (struct ar6_softc *) devt;
- return(arAc2EndpointID(ar, ac));
-}
-
-u8 ar6000_endpoint_id2_ac(void * devt, HTC_ENDPOINT_ID ep )
-{
- struct ar6_softc *ar = (struct ar6_softc *) devt;
- return(arEndpoint2Ac(ar, ep ));
-}
-
-#if defined(CONFIG_ATH6KL_ENABLE_COEXISTENCE)
-static int ath6kl_config_btcoex_params(struct ar6_softc *ar)
-{
- int r;
- WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMD sbcb_cmd;
- WMI_SET_BTCOEX_FE_ANT_CMD sbfa_cmd;
-
- /* Configure the type of BT collocated with WLAN */
- memset(&sbcb_cmd, 0, sizeof(WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMD));
- sbcb_cmd.btcoexCoLocatedBTdev = ATH6KL_BT_DEV;
-
- r = wmi_set_btcoex_colocated_bt_dev_cmd(ar->arWmi, &sbcb_cmd);
-
- if (r) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("Unable to set collocated BT type\n"));
- return r;
- }
-
- /* Configure the type of BT collocated with WLAN */
- memset(&sbfa_cmd, 0, sizeof(WMI_SET_BTCOEX_FE_ANT_CMD));
-
- sbfa_cmd.btcoexFeAntType = ATH6KL_BT_ANTENNA;
-
- r = wmi_set_btcoex_fe_ant_cmd(ar->arWmi, &sbfa_cmd);
- if (r) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("Unable to set fornt end antenna configuration\n"));
- return r;
- }
-
- return 0;
-}
-#else
-static int ath6kl_config_btcoex_params(struct ar6_softc *ar)
-{
- return 0;
-}
-#endif /* CONFIG_ATH6KL_ENABLE_COEXISTENCE */
-
-/*
- * This function applies WLAN specific configuration defined in wlan_config.h
- */
-int ar6000_target_config_wlan_params(struct ar6_softc *ar)
-{
- int status = 0;
-
-#ifdef CONFIG_HOST_TCMD_SUPPORT
- if (ar->arTargetMode != AR6000_WLAN_MODE) {
- return 0;
- }
-#endif /* CONFIG_HOST_TCMD_SUPPORT */
-
- /*
- * configure the device for rx dot11 header rules 0,0 are the default values
- * therefore this command can be skipped if the inputs are 0,FALSE,FALSE.Required
- * if checksum offload is needed. Set RxMetaVersion to 2
- */
- if ((wmi_set_rx_frame_format_cmd(ar->arWmi,ar->rxMetaVersion, processDot11Hdr, processDot11Hdr)) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Unable to set the rx frame format.\n"));
- status = A_ERROR;
- }
-
- status = ath6kl_config_btcoex_params(ar);
- if (status)
- return status;
-
-#if WLAN_CONFIG_IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN
- if ((wmi_pmparams_cmd(ar->arWmi, 0, 1, 0, 0, 1, IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN)) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Unable to set power save fail event policy\n"));
- status = A_ERROR;
- }
-#endif
-
-#if WLAN_CONFIG_DONOT_IGNORE_BARKER_IN_ERP
- if ((wmi_set_lpreamble_cmd(ar->arWmi, 0, WMI_DONOT_IGNORE_BARKER_IN_ERP)) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Unable to set barker preamble policy\n"));
- status = A_ERROR;
- }
-#endif
-
- if ((wmi_set_keepalive_cmd(ar->arWmi, WLAN_CONFIG_KEEP_ALIVE_INTERVAL)) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Unable to set keep alive interval\n"));
- status = A_ERROR;
- }
-
-#if WLAN_CONFIG_DISABLE_11N
- {
- WMI_SET_HT_CAP_CMD htCap;
-
- memset(&htCap, 0, sizeof(WMI_SET_HT_CAP_CMD));
- htCap.band = 0;
- if ((wmi_set_ht_cap_cmd(ar->arWmi, &htCap)) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Unable to set ht capabilities \n"));
- status = A_ERROR;
- }
-
- htCap.band = 1;
- if ((wmi_set_ht_cap_cmd(ar->arWmi, &htCap)) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Unable to set ht capabilities \n"));
- status = A_ERROR;
- }
- }
-#endif /* WLAN_CONFIG_DISABLE_11N */
-
-#ifdef ATH6K_CONFIG_OTA_MODE
- if ((wmi_powermode_cmd(ar->arWmi, MAX_PERF_POWER)) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Unable to set power mode \n"));
- status = A_ERROR;
- }
-#endif
-
- if ((wmi_disctimeout_cmd(ar->arWmi, WLAN_CONFIG_DISCONNECT_TIMEOUT)) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Unable to set disconnect timeout \n"));
- status = A_ERROR;
- }
-
-#if WLAN_CONFIG_DISABLE_TX_BURSTING
- if ((wmi_set_wmm_txop(ar->arWmi, WMI_TXOP_DISABLED)) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Unable to set txop bursting \n"));
- status = A_ERROR;
- }
-#endif
-
- return status;
-}
-
-/* This function does one time initialization for the lifetime of the device */
-int ar6000_init(struct net_device *dev)
-{
- struct ar6_softc *ar;
- int status;
- s32 timeleft;
- s16 i;
- int ret = 0;
-
- if((ar = ar6k_priv(dev)) == NULL)
- {
- return -EIO;
- }
-
- if (wlaninitmode == WLAN_INIT_MODE_USR || wlaninitmode == WLAN_INIT_MODE_DRV) {
-
- ar6000_update_bdaddr(ar);
-
- if (enablerssicompensation) {
- ar6000_copy_cust_data_from_target(ar->arHifDevice, ar->arTargetType);
- read_rssi_compensation_param(ar);
- for (i=-95; i<=0; i++) {
- rssi_compensation_table[0-i] = rssi_compensation_calc(ar,i);
- }
- }
- }
-
- dev_hold(dev);
- rtnl_unlock();
-
- /* Do we need to finish the BMI phase */
- if ((wlaninitmode == WLAN_INIT_MODE_USR || wlaninitmode == WLAN_INIT_MODE_DRV) &&
- (BMIDone(ar->arHifDevice) != 0))
- {
- ret = -EIO;
- goto ar6000_init_done;
- }
-
- if (!bypasswmi)
- {
-#if 0 /* TBDXXX */
- if (ar->arVersion.host_ver != ar->arVersion.target_ver) {
- A_PRINTF("WARNING: Host version 0x%x does not match Target "
- " version 0x%x!\n",
- ar->arVersion.host_ver, ar->arVersion.target_ver);
- }
-#endif
-
- /* Indicate that WMI is enabled (although not ready yet) */
- ar->arWmiEnabled = true;
- if ((ar->arWmi = wmi_init((void *) ar)) == NULL)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s() Failed to initialize WMI.\n", __func__));
- ret = -EIO;
- goto ar6000_init_done;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s() Got WMI @ 0x%lx.\n", __func__,
- (unsigned long) ar->arWmi));
- }
-
- do {
- struct htc_service_connect_req connect;
-
- /* the reason we have to wait for the target here is that the driver layer
- * has to init BMI in order to set the host block size,
- */
- status = HTCWaitTarget(ar->arHtcTarget);
-
- if (status) {
- break;
- }
-
- A_MEMZERO(&connect,sizeof(connect));
- /* meta data is unused for now */
- connect.pMetaData = NULL;
- connect.MetaDataLength = 0;
- /* these fields are the same for all service endpoints */
- connect.EpCallbacks.pContext = ar;
- connect.EpCallbacks.EpTxCompleteMultiple = ar6000_tx_complete;
- connect.EpCallbacks.EpRecv = ar6000_rx;
- connect.EpCallbacks.EpRecvRefill = ar6000_rx_refill;
- connect.EpCallbacks.EpSendFull = ar6000_tx_queue_full;
- /* set the max queue depth so that our ar6000_tx_queue_full handler gets called.
- * Linux has the peculiarity of not providing flow control between the
- * NIC and the network stack. There is no API to indicate that a TX packet
- * was sent which could provide some back pressure to the network stack.
- * Under linux you would have to wait till the network stack consumed all sk_buffs
- * before any back-flow kicked in. Which isn't very friendly.
- * So we have to manage this ourselves */
- connect.MaxSendQueueDepth = MAX_DEFAULT_SEND_QUEUE_DEPTH;
- connect.EpCallbacks.RecvRefillWaterMark = AR6000_MAX_RX_BUFFERS / 4; /* set to 25 % */
- if (0 == connect.EpCallbacks.RecvRefillWaterMark) {
- connect.EpCallbacks.RecvRefillWaterMark++;
- }
- /* connect to control service */
- connect.ServiceID = WMI_CONTROL_SVC;
- status = ar6000_connectservice(ar,
- &connect,
- "WMI CONTROL");
- if (status) {
- break;
- }
-
- connect.LocalConnectionFlags |= HTC_LOCAL_CONN_FLAGS_ENABLE_SEND_BUNDLE_PADDING;
- /* limit the HTC message size on the send path, although we can receive A-MSDU frames of
- * 4K, we will only send ethernet-sized (802.3) frames on the send path. */
- connect.MaxSendMsgSize = WMI_MAX_TX_DATA_FRAME_LENGTH;
-
- /* to reduce the amount of committed memory for larger A_MSDU frames, use the recv-alloc threshold
- * mechanism for larger packets */
- connect.EpCallbacks.RecvAllocThreshold = AR6000_BUFFER_SIZE;
- connect.EpCallbacks.EpRecvAllocThresh = ar6000_alloc_amsdu_rxbuf;
-
- /* for the remaining data services set the connection flag to reduce dribbling,
- * if configured to do so */
- if (reduce_credit_dribble) {
- connect.ConnectionFlags |= HTC_CONNECT_FLAGS_REDUCE_CREDIT_DRIBBLE;
- /* the credit dribble trigger threshold is (reduce_credit_dribble - 1) for a value
- * of 0-3 */
- connect.ConnectionFlags &= ~HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_MASK;
- connect.ConnectionFlags |=
- ((u16)reduce_credit_dribble - 1) & HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_MASK;
- }
- /* connect to best-effort service */
- connect.ServiceID = WMI_DATA_BE_SVC;
-
- status = ar6000_connectservice(ar,
- &connect,
- "WMI DATA BE");
- if (status) {
- break;
- }
-
- /* connect to back-ground
- * map this to WMI LOW_PRI */
- connect.ServiceID = WMI_DATA_BK_SVC;
- status = ar6000_connectservice(ar,
- &connect,
- "WMI DATA BK");
- if (status) {
- break;
- }
-
- /* connect to Video service, map this to
- * to HI PRI */
- connect.ServiceID = WMI_DATA_VI_SVC;
- status = ar6000_connectservice(ar,
- &connect,
- "WMI DATA VI");
- if (status) {
- break;
- }
-
- /* connect to VO service, this is currently not
- * mapped to a WMI priority stream due to historical reasons.
- * WMI originally defined 3 priorities over 3 mailboxes
- * We can change this when WMI is reworked so that priorities are not
- * dependent on mailboxes */
- connect.ServiceID = WMI_DATA_VO_SVC;
- status = ar6000_connectservice(ar,
- &connect,
- "WMI DATA VO");
- if (status) {
- break;
- }
-
- A_ASSERT(arAc2EndpointID(ar,WMM_AC_BE) != 0);
- A_ASSERT(arAc2EndpointID(ar,WMM_AC_BK) != 0);
- A_ASSERT(arAc2EndpointID(ar,WMM_AC_VI) != 0);
- A_ASSERT(arAc2EndpointID(ar,WMM_AC_VO) != 0);
-
- /* setup access class priority mappings */
- ar->arAcStreamPriMap[WMM_AC_BK] = 0; /* lowest */
- ar->arAcStreamPriMap[WMM_AC_BE] = 1; /* */
- ar->arAcStreamPriMap[WMM_AC_VI] = 2; /* */
- ar->arAcStreamPriMap[WMM_AC_VO] = 3; /* highest */
-
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
- if (setuphci && (NULL != ar6kHciTransCallbacks.setupTransport)) {
- struct hci_transport_misc_handles hciHandles;
-
- hciHandles.netDevice = ar->arNetDev;
- hciHandles.hifDevice = ar->arHifDevice;
- hciHandles.htcHandle = ar->arHtcTarget;
- status = (int)(ar6kHciTransCallbacks.setupTransport(&hciHandles));
- }
-#else
- if (setuphci) {
- /* setup HCI */
- status = ar6000_setup_hci(ar);
- }
-#endif
-
- } while (false);
-
- if (status) {
- ret = -EIO;
- goto ar6000_init_done;
- }
-
- if (regscanmode) {
- u32 param;
-
- if (BMIReadMemory(ar->arHifDevice,
- HOST_INTEREST_ITEM_ADDRESS(ar,
- hi_option_flag),
- (u8 *)&param,
- 4) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("BMIReadMemory forsetting "
- "regscanmode failed\n"));
- return A_ERROR;
- }
-
- if (regscanmode == 1)
- param |= HI_OPTION_SKIP_REG_SCAN;
- else if (regscanmode == 2)
- param |= HI_OPTION_INIT_REG_SCAN;
-
- if (BMIWriteMemory(ar->arHifDevice,
- HOST_INTEREST_ITEM_ADDRESS(ar,
- hi_option_flag),
- (u8 *)&param,
- 4) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("BMIWriteMemory forsetting "
- "regscanmode failed\n"));
- return A_ERROR;
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("Regulatory scan mode set\n"));
- }
-
- /*
- * give our connected endpoints some buffers
- */
-
- ar6000_rx_refill(ar, ar->arControlEp);
- ar6000_rx_refill(ar, arAc2EndpointID(ar,WMM_AC_BE));
-
- /*
- * We will post the receive buffers only for SPE or endpoint ping testing so we are
- * making it conditional on the 'bypasswmi' flag.
- */
- if (bypasswmi) {
- ar6000_rx_refill(ar,arAc2EndpointID(ar,WMM_AC_BK));
- ar6000_rx_refill(ar,arAc2EndpointID(ar,WMM_AC_VI));
- ar6000_rx_refill(ar,arAc2EndpointID(ar,WMM_AC_VO));
- }
-
- /* allocate some buffers that handle larger AMSDU frames */
- ar6000_refill_amsdu_rxbufs(ar,AR6000_MAX_AMSDU_RX_BUFFERS);
-
- /* setup credit distribution */
- ar6000_setup_credit_dist(ar->arHtcTarget, &ar->arCreditStateInfo);
-
- /* Since cookies are used for HTC transports, they should be */
- /* initialized prior to enabling HTC. */
- ar6000_cookie_init(ar);
-
- /* start HTC */
- status = HTCStart(ar->arHtcTarget);
-
- if (status) {
- if (ar->arWmiEnabled == true) {
- wmi_shutdown(ar->arWmi);
- ar->arWmiEnabled = false;
- ar->arWmi = NULL;
- }
- ar6000_cookie_cleanup(ar);
- ret = -EIO;
- goto ar6000_init_done;
- }
-
- if (!bypasswmi) {
- /* Wait for Wmi event to be ready */
- timeleft = wait_event_interruptible_timeout(arEvent,
- (ar->arWmiReady == true), wmitimeout * HZ);
-
- if (ar->arVersion.abi_ver != AR6K_ABI_VERSION) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("ABI Version mismatch: Host(0x%x), Target(0x%x)\n", AR6K_ABI_VERSION, ar->arVersion.abi_ver));
-#ifndef ATH6K_SKIP_ABI_VERSION_CHECK
- ret = -EIO;
- goto ar6000_init_done;
-#endif /* ATH6K_SKIP_ABI_VERSION_CHECK */
- }
-
- if(!timeleft || signal_pending(current))
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("WMI is not ready or wait was interrupted\n"));
- ret = -EIO;
- goto ar6000_init_done;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s() WMI is ready\n", __func__));
-
- /* Communicate the wmi protocol verision to the target */
- if ((ar6000_set_host_app_area(ar)) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Unable to set the host app area\n"));
- }
- ar6000_target_config_wlan_params(ar);
- }
-
- ar->arNumDataEndPts = 1;
-
- if (bypasswmi) {
- /* for tests like endpoint ping, the MAC address needs to be non-zero otherwise
- * the data path through a raw socket is disabled */
- dev->dev_addr[0] = 0x00;
- dev->dev_addr[1] = 0x01;
- dev->dev_addr[2] = 0x02;
- dev->dev_addr[3] = 0xAA;
- dev->dev_addr[4] = 0xBB;
- dev->dev_addr[5] = 0xCC;
- }
-
-ar6000_init_done:
- rtnl_lock();
- dev_put(dev);
-
- return ret;
-}
-
-
-void
-ar6000_bitrate_rx(void *devt, s32 rateKbps)
-{
- struct ar6_softc *ar = (struct ar6_softc *)devt;
-
- ar->arBitRate = rateKbps;
- wake_up(&arEvent);
-}
-
-void
-ar6000_ratemask_rx(void *devt, u32 ratemask)
-{
- struct ar6_softc *ar = (struct ar6_softc *)devt;
-
- ar->arRateMask = ratemask;
- wake_up(&arEvent);
-}
-
-void
-ar6000_txPwr_rx(void *devt, u8 txPwr)
-{
- struct ar6_softc *ar = (struct ar6_softc *)devt;
-
- ar->arTxPwr = txPwr;
- wake_up(&arEvent);
-}
-
-
-void
-ar6000_channelList_rx(void *devt, s8 numChan, u16 *chanList)
-{
- struct ar6_softc *ar = (struct ar6_softc *)devt;
-
- memcpy(ar->arChannelList, chanList, numChan * sizeof (u16));
- ar->arNumChannels = numChan;
-
- wake_up(&arEvent);
-}
-
-u8 ar6000_ibss_map_epid(struct sk_buff *skb, struct net_device *dev, u32 *mapNo)
-{
- struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev);
- u8 *datap;
- ATH_MAC_HDR *macHdr;
- u32 i, eptMap;
-
- (*mapNo) = 0;
- datap = A_NETBUF_DATA(skb);
- macHdr = (ATH_MAC_HDR *)(datap + sizeof(WMI_DATA_HDR));
- if (IEEE80211_IS_MULTICAST(macHdr->dstMac)) {
- return ENDPOINT_2;
- }
-
- eptMap = -1;
- for (i = 0; i < ar->arNodeNum; i ++) {
- if (IEEE80211_ADDR_EQ(macHdr->dstMac, ar->arNodeMap[i].macAddress)) {
- (*mapNo) = i + 1;
- ar->arNodeMap[i].txPending ++;
- return ar->arNodeMap[i].epId;
- }
-
- if ((eptMap == -1) && !ar->arNodeMap[i].txPending) {
- eptMap = i;
- }
- }
-
- if (eptMap == -1) {
- eptMap = ar->arNodeNum;
- ar->arNodeNum ++;
- A_ASSERT(ar->arNodeNum <= MAX_NODE_NUM);
- }
-
- memcpy(ar->arNodeMap[eptMap].macAddress, macHdr->dstMac, IEEE80211_ADDR_LEN);
-
- for (i = ENDPOINT_2; i <= ENDPOINT_5; i ++) {
- if (!ar->arTxPending[i]) {
- ar->arNodeMap[eptMap].epId = i;
- break;
- }
- // No free endpoint is available, start redistribution on the inuse endpoints.
- if (i == ENDPOINT_5) {
- ar->arNodeMap[eptMap].epId = ar->arNexEpId;
- ar->arNexEpId ++;
- if (ar->arNexEpId > ENDPOINT_5) {
- ar->arNexEpId = ENDPOINT_2;
- }
- }
- }
-
- (*mapNo) = eptMap + 1;
- ar->arNodeMap[eptMap].txPending ++;
-
- return ar->arNodeMap[eptMap].epId;
-}
-
-#ifdef DEBUG
-static void ar6000_dump_skb(struct sk_buff *skb)
-{
- u_char *ch;
- for (ch = A_NETBUF_DATA(skb);
- (unsigned long)ch < ((unsigned long)A_NETBUF_DATA(skb) +
- A_NETBUF_LEN(skb)); ch++)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN,("%2.2x ", *ch));
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN,("\n"));
-}
-#endif
-
-#ifdef HTC_TEST_SEND_PKTS
-static void DoHTCSendPktsTest(struct ar6_softc *ar, int MapNo, HTC_ENDPOINT_ID eid, struct sk_buff *skb);
-#endif
-
-static int
-ar6000_data_tx(struct sk_buff *skb, struct net_device *dev)
-{
-#define AC_NOT_MAPPED 99
- struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev);
- u8 ac = AC_NOT_MAPPED;
- HTC_ENDPOINT_ID eid = ENDPOINT_UNUSED;
- u32 mapNo = 0;
- int len;
- struct ar_cookie *cookie;
- bool checkAdHocPsMapping = false,bMoreData = false;
- HTC_TX_TAG htc_tag = AR6K_DATA_PKT_TAG;
- u8 dot11Hdr = processDot11Hdr;
-#ifdef CONFIG_PM
- if (ar->arWowState != WLAN_WOW_STATE_NONE) {
- A_NETBUF_FREE(skb);
- return 0;
- }
-#endif /* CONFIG_PM */
-
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_TX,("ar6000_data_tx start - skb=0x%lx, data=0x%lx, len=0x%x\n",
- (unsigned long)skb, (unsigned long)A_NETBUF_DATA(skb),
- A_NETBUF_LEN(skb)));
-
- /* If target is not associated */
- if( (!ar->arConnected && !bypasswmi)
-#ifdef CONFIG_HOST_TCMD_SUPPORT
- /* TCMD doesn't support any data, free the buf and return */
- || (ar->arTargetMode == AR6000_TCMD_MODE)
-#endif
- ) {
- A_NETBUF_FREE(skb);
- return 0;
- }
-
- do {
-
- if (ar->arWmiReady == false && bypasswmi == 0) {
- break;
- }
-
-#ifdef BLOCK_TX_PATH_FLAG
- if (blocktx) {
- break;
- }
-#endif /* BLOCK_TX_PATH_FLAG */
-
- /* AP mode Power save processing */
- /* If the dst STA is in sleep state, queue the pkt in its PS queue */
-
- if (ar->arNetworkType == AP_NETWORK) {
- ATH_MAC_HDR *datap = (ATH_MAC_HDR *)A_NETBUF_DATA(skb);
- sta_t *conn = NULL;
-
- /* If the dstMac is a Multicast address & atleast one of the
- * associated STA is in PS mode, then queue the pkt to the
- * mcastq
- */
- if (IEEE80211_IS_MULTICAST(datap->dstMac)) {
- u8 ctr=0;
- bool qMcast=false;
-
-
- for (ctr=0; ctr<AP_MAX_NUM_STA; ctr++) {
- if (STA_IS_PWR_SLEEP((&ar->sta_list[ctr]))) {
- qMcast = true;
- }
- }
- if(qMcast) {
-
- /* If this transmit is not because of a Dtim Expiry q it */
- if (ar->DTIMExpired == false) {
- bool isMcastqEmpty = false;
-
- A_MUTEX_LOCK(&ar->mcastpsqLock);
- isMcastqEmpty = A_NETBUF_QUEUE_EMPTY(&ar->mcastpsq);
- A_NETBUF_ENQUEUE(&ar->mcastpsq, skb);
- A_MUTEX_UNLOCK(&ar->mcastpsqLock);
-
- /* If this is the first Mcast pkt getting queued
- * indicate to the target to set the BitmapControl LSB
- * of the TIM IE.
- */
- if (isMcastqEmpty) {
- wmi_set_pvb_cmd(ar->arWmi, MCAST_AID, 1);
- }
- return 0;
- } else {
- /* This transmit is because of Dtim expiry. Determine if
- * MoreData bit has to be set.
- */
- A_MUTEX_LOCK(&ar->mcastpsqLock);
- if(!A_NETBUF_QUEUE_EMPTY(&ar->mcastpsq)) {
- bMoreData = true;
- }
- A_MUTEX_UNLOCK(&ar->mcastpsqLock);
- }
- }
- } else {
- conn = ieee80211_find_conn(ar, datap->dstMac);
- if (conn) {
- if (STA_IS_PWR_SLEEP(conn)) {
- /* If this transmit is not because of a PsPoll q it*/
- if (!STA_IS_PS_POLLED(conn)) {
- bool isPsqEmpty = false;
- /* Queue the frames if the STA is sleeping */
- A_MUTEX_LOCK(&conn->psqLock);
- isPsqEmpty = A_NETBUF_QUEUE_EMPTY(&conn->psq);
- A_NETBUF_ENQUEUE(&conn->psq, skb);
- A_MUTEX_UNLOCK(&conn->psqLock);
-
- /* If this is the first pkt getting queued
- * for this STA, update the PVB for this STA
- */
- if (isPsqEmpty) {
- wmi_set_pvb_cmd(ar->arWmi, conn->aid, 1);
- }
-
- return 0;
- } else {
- /* This tx is because of a PsPoll. Determine if
- * MoreData bit has to be set
- */
- A_MUTEX_LOCK(&conn->psqLock);
- if (!A_NETBUF_QUEUE_EMPTY(&conn->psq)) {
- bMoreData = true;
- }
- A_MUTEX_UNLOCK(&conn->psqLock);
- }
- }
- } else {
-
- /* non existent STA. drop the frame */
- A_NETBUF_FREE(skb);
- return 0;
- }
- }
- }
-
- if (ar->arWmiEnabled) {
- u8 csumStart=0;
- u8 csumDest=0;
- u8 csum=skb->ip_summed;
- if(csumOffload && (csum==CHECKSUM_PARTIAL)){
- csumStart = (skb->head + skb->csum_start - skb_network_header(skb) +
- sizeof(ATH_LLC_SNAP_HDR));
- csumDest=skb->csum_offset+csumStart;
- }
- if (A_NETBUF_HEADROOM(skb) < dev->hard_header_len - LINUX_HACK_FUDGE_FACTOR) {
- struct sk_buff *newbuf;
-
- /*
- * We really should have gotten enough headroom but sometimes
- * we still get packets with not enough headroom. Copy the packet.
- */
- len = A_NETBUF_LEN(skb);
- newbuf = A_NETBUF_ALLOC(len);
- if (newbuf == NULL) {
- break;
- }
- A_NETBUF_PUT(newbuf, len);
- memcpy(A_NETBUF_DATA(newbuf), A_NETBUF_DATA(skb), len);
- A_NETBUF_FREE(skb);
- skb = newbuf;
- /* fall through and assemble header */
- }
-
- if (dot11Hdr) {
- if (wmi_dot11_hdr_add(ar->arWmi,skb,ar->arNetworkType) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("ar6000_data_tx-wmi_dot11_hdr_add failed\n"));
- break;
- }
- } else {
- if (wmi_dix_2_dot3(ar->arWmi, skb) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("ar6000_data_tx - wmi_dix_2_dot3 failed\n"));
- break;
- }
- }
- if(csumOffload && (csum ==CHECKSUM_PARTIAL)){
- WMI_TX_META_V2 metaV2;
- metaV2.csumStart =csumStart;
- metaV2.csumDest = csumDest;
- metaV2.csumFlags = 0x1;/*instruct target to calculate checksum*/
- if (wmi_data_hdr_add(ar->arWmi, skb, DATA_MSGTYPE, bMoreData, dot11Hdr,
- WMI_META_VERSION_2,&metaV2) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("ar6000_data_tx - wmi_data_hdr_add failed\n"));
- break;
- }
-
- }
- else
- {
- if (wmi_data_hdr_add(ar->arWmi, skb, DATA_MSGTYPE, bMoreData, dot11Hdr,0,NULL) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("ar6000_data_tx - wmi_data_hdr_add failed\n"));
- break;
- }
- }
-
-
- if ((ar->arNetworkType == ADHOC_NETWORK) &&
- ar->arIbssPsEnable && ar->arConnected) {
- /* flag to check adhoc mapping once we take the lock below: */
- checkAdHocPsMapping = true;
-
- } else {
- /* get the stream mapping */
- ac = wmi_implicit_create_pstream(ar->arWmi, skb, 0, ar->arWmmEnabled);
- }
-
- } else {
- EPPING_HEADER *eppingHdr;
-
- eppingHdr = A_NETBUF_DATA(skb);
-
- if (IS_EPPING_PACKET(eppingHdr)) {
- /* the stream ID is mapped to an access class */
- ac = eppingHdr->StreamNo_h;
- /* some EPPING packets cannot be dropped no matter what access class it was
- * sent on. We can change the packet tag to guarantee it will not get dropped */
- if (IS_EPING_PACKET_NO_DROP(eppingHdr)) {
- htc_tag = AR6K_CONTROL_PKT_TAG;
- }
-
- if (ac == HCI_TRANSPORT_STREAM_NUM) {
- /* pass this to HCI */
-#ifndef EXPORT_HCI_BRIDGE_INTERFACE
- if (!hci_test_send(ar,skb)) {
- return 0;
- }
-#endif
- /* set AC to discard this skb */
- ac = AC_NOT_MAPPED;
- } else {
- /* a quirk of linux, the payload of the frame is 32-bit aligned and thus the addition
- * of the HTC header will mis-align the start of the HTC frame, so we add some
- * padding which will be stripped off in the target */
- if (EPPING_ALIGNMENT_PAD > 0) {
- A_NETBUF_PUSH(skb, EPPING_ALIGNMENT_PAD);
- }
- }
-
- } else {
- /* not a ping packet, drop it */
- ac = AC_NOT_MAPPED;
- }
- }
-
- } while (false);
-
- /* did we succeed ? */
- if ((ac == AC_NOT_MAPPED) && !checkAdHocPsMapping) {
- /* cleanup and exit */
- A_NETBUF_FREE(skb);
- AR6000_STAT_INC(ar, tx_dropped);
- AR6000_STAT_INC(ar, tx_aborted_errors);
- return 0;
- }
-
- cookie = NULL;
-
- /* take the lock to protect driver data */
- AR6000_SPIN_LOCK(&ar->arLock, 0);
-
- do {
-
- if (checkAdHocPsMapping) {
- eid = ar6000_ibss_map_epid(skb, dev, &mapNo);
- }else {
- eid = arAc2EndpointID (ar, ac);
- }
- /* validate that the endpoint is connected */
- if (eid == 0 || eid == ENDPOINT_UNUSED ) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" eid %d is NOT mapped!\n", eid));
- break;
- }
- /* allocate resource for this packet */
- cookie = ar6000_alloc_cookie(ar);
-
- if (cookie != NULL) {
- /* update counts while the lock is held */
- ar->arTxPending[eid]++;
- ar->arTotalTxDataPending++;
- }
-
- } while (false);
-
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
-
- if (cookie != NULL) {
- cookie->arc_bp[0] = (unsigned long)skb;
- cookie->arc_bp[1] = mapNo;
- SET_HTC_PACKET_INFO_TX(&cookie->HtcPkt,
- cookie,
- A_NETBUF_DATA(skb),
- A_NETBUF_LEN(skb),
- eid,
- htc_tag);
-
-#ifdef DEBUG
- if (debugdriver >= 3) {
- ar6000_dump_skb(skb);
- }
-#endif
-#ifdef HTC_TEST_SEND_PKTS
- DoHTCSendPktsTest(ar,mapNo,eid,skb);
-#endif
- /* HTC interface is asynchronous, if this fails, cleanup will happen in
- * the ar6000_tx_complete callback */
- HTCSendPkt(ar->arHtcTarget, &cookie->HtcPkt);
- } else {
- /* no packet to send, cleanup */
- A_NETBUF_FREE(skb);
- AR6000_STAT_INC(ar, tx_dropped);
- AR6000_STAT_INC(ar, tx_aborted_errors);
- }
-
- return 0;
-}
-
-int
-ar6000_acl_data_tx(struct sk_buff *skb, struct net_device *dev)
-{
- struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev);
- struct ar_cookie *cookie;
- HTC_ENDPOINT_ID eid = ENDPOINT_UNUSED;
-
- cookie = NULL;
- AR6000_SPIN_LOCK(&ar->arLock, 0);
-
- /* For now we send ACL on BE endpoint: We can also have a dedicated EP */
- eid = arAc2EndpointID (ar, 0);
- /* allocate resource for this packet */
- cookie = ar6000_alloc_cookie(ar);
-
- if (cookie != NULL) {
- /* update counts while the lock is held */
- ar->arTxPending[eid]++;
- ar->arTotalTxDataPending++;
- }
-
-
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
-
- if (cookie != NULL) {
- cookie->arc_bp[0] = (unsigned long)skb;
- cookie->arc_bp[1] = 0;
- SET_HTC_PACKET_INFO_TX(&cookie->HtcPkt,
- cookie,
- A_NETBUF_DATA(skb),
- A_NETBUF_LEN(skb),
- eid,
- AR6K_DATA_PKT_TAG);
-
- /* HTC interface is asynchronous, if this fails, cleanup will happen in
- * the ar6000_tx_complete callback */
- HTCSendPkt(ar->arHtcTarget, &cookie->HtcPkt);
- } else {
- /* no packet to send, cleanup */
- A_NETBUF_FREE(skb);
- AR6000_STAT_INC(ar, tx_dropped);
- AR6000_STAT_INC(ar, tx_aborted_errors);
- }
- return 0;
-}
-
-
-#ifdef ADAPTIVE_POWER_THROUGHPUT_CONTROL
-static void
-tvsub(register struct timeval *out, register struct timeval *in)
-{
- if((out->tv_usec -= in->tv_usec) < 0) {
- out->tv_sec--;
- out->tv_usec += 1000000;
- }
- out->tv_sec -= in->tv_sec;
-}
-
-void
-applyAPTCHeuristics(struct ar6_softc *ar)
-{
- u32 duration;
- u32 numbytes;
- u32 throughput;
- struct timeval ts;
- int status;
-
- AR6000_SPIN_LOCK(&ar->arLock, 0);
-
- if ((enableAPTCHeuristics) && (!aptcTR.timerScheduled)) {
- do_gettimeofday(&ts);
- tvsub(&ts, &aptcTR.samplingTS);
- duration = ts.tv_sec * 1000 + ts.tv_usec / 1000; /* ms */
- numbytes = aptcTR.bytesTransmitted + aptcTR.bytesReceived;
-
- if (duration > APTC_TRAFFIC_SAMPLING_INTERVAL) {
- /* Initialize the time stamp and byte count */
- aptcTR.bytesTransmitted = aptcTR.bytesReceived = 0;
- do_gettimeofday(&aptcTR.samplingTS);
-
- /* Calculate and decide based on throughput thresholds */
- throughput = ((numbytes * 8) / duration);
- if (throughput > APTC_UPPER_THROUGHPUT_THRESHOLD) {
- /* Disable Sleep and schedule a timer */
- A_ASSERT(ar->arWmiReady == true);
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
- status = wmi_powermode_cmd(ar->arWmi, MAX_PERF_POWER);
- AR6000_SPIN_LOCK(&ar->arLock, 0);
- A_TIMEOUT_MS(&aptcTimer, APTC_TRAFFIC_SAMPLING_INTERVAL, 0);
- aptcTR.timerScheduled = true;
- }
- }
- }
-
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
-}
-#endif /* ADAPTIVE_POWER_THROUGHPUT_CONTROL */
-
-static HTC_SEND_FULL_ACTION ar6000_tx_queue_full(void *Context, struct htc_packet *pPacket)
-{
- struct ar6_softc *ar = (struct ar6_softc *)Context;
- HTC_SEND_FULL_ACTION action = HTC_SEND_FULL_KEEP;
- bool stopNet = false;
- HTC_ENDPOINT_ID Endpoint = HTC_GET_ENDPOINT_FROM_PKT(pPacket);
-
- do {
-
- if (bypasswmi) {
- int accessClass;
-
- if (HTC_GET_TAG_FROM_PKT(pPacket) == AR6K_CONTROL_PKT_TAG) {
- /* don't drop special control packets */
- break;
- }
-
- accessClass = arEndpoint2Ac(ar,Endpoint);
- /* for endpoint ping testing drop Best Effort and Background */
- if ((accessClass == WMM_AC_BE) || (accessClass == WMM_AC_BK)) {
- action = HTC_SEND_FULL_DROP;
- stopNet = false;
- } else {
- /* keep but stop the netqueues */
- stopNet = true;
- }
- break;
- }
-
- if (Endpoint == ar->arControlEp) {
- /* under normal WMI if this is getting full, then something is running rampant
- * the host should not be exhausting the WMI queue with too many commands
- * the only exception to this is during testing using endpointping */
- AR6000_SPIN_LOCK(&ar->arLock, 0);
- /* set flag to handle subsequent messages */
- ar->arWMIControlEpFull = true;
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("WMI Control Endpoint is FULL!!! \n"));
- /* no need to stop the network */
- stopNet = false;
- break;
- }
-
- /* if we get here, we are dealing with data endpoints getting full */
-
- if (HTC_GET_TAG_FROM_PKT(pPacket) == AR6K_CONTROL_PKT_TAG) {
- /* don't drop control packets issued on ANY data endpoint */
- break;
- }
-
- if (ar->arNetworkType == ADHOC_NETWORK) {
- /* in adhoc mode, we cannot differentiate traffic priorities so there is no need to
- * continue, however we should stop the network */
- stopNet = true;
- break;
- }
- /* the last MAX_HI_COOKIE_NUM "batch" of cookies are reserved for the highest
- * active stream */
- if (ar->arAcStreamPriMap[arEndpoint2Ac(ar,Endpoint)] < ar->arHiAcStreamActivePri &&
- ar->arCookieCount <= MAX_HI_COOKIE_NUM) {
- /* this stream's priority is less than the highest active priority, we
- * give preference to the highest priority stream by directing
- * HTC to drop the packet that overflowed */
- action = HTC_SEND_FULL_DROP;
- /* since we are dropping packets, no need to stop the network */
- stopNet = false;
- break;
- }
-
- } while (false);
-
- if (stopNet) {
- AR6000_SPIN_LOCK(&ar->arLock, 0);
- ar->arNetQueueStopped = true;
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
- /* one of the data endpoints queues is getting full..need to stop network stack
- * the queue will resume in ar6000_tx_complete() */
- netif_stop_queue(ar->arNetDev);
- }
-
- return action;
-}
-
-
-static void
-ar6000_tx_complete(void *Context, struct htc_packet_queue *pPacketQueue)
-{
- struct ar6_softc *ar = (struct ar6_softc *)Context;
- u32 mapNo = 0;
- int status;
- struct ar_cookie * ar_cookie;
- HTC_ENDPOINT_ID eid;
- bool wakeEvent = false;
- struct sk_buff_head skb_queue;
- struct htc_packet *pPacket;
- struct sk_buff *pktSkb;
- bool flushing = false;
-
- skb_queue_head_init(&skb_queue);
-
- /* lock the driver as we update internal state */
- AR6000_SPIN_LOCK(&ar->arLock, 0);
-
- /* reap completed packets */
- while (!HTC_QUEUE_EMPTY(pPacketQueue)) {
-
- pPacket = HTC_PACKET_DEQUEUE(pPacketQueue);
-
- ar_cookie = (struct ar_cookie *)pPacket->pPktContext;
- A_ASSERT(ar_cookie);
-
- status = pPacket->Status;
- pktSkb = (struct sk_buff *)ar_cookie->arc_bp[0];
- eid = pPacket->Endpoint;
- mapNo = ar_cookie->arc_bp[1];
-
- A_ASSERT(pktSkb);
- A_ASSERT(pPacket->pBuffer == A_NETBUF_DATA(pktSkb));
-
- /* add this to the list, use faster non-lock API */
- __skb_queue_tail(&skb_queue,pktSkb);
-
- if (!status) {
- A_ASSERT(pPacket->ActualLength == A_NETBUF_LEN(pktSkb));
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_TX,("ar6000_tx_complete skb=0x%lx data=0x%lx len=0x%x eid=%d ",
- (unsigned long)pktSkb, (unsigned long)pPacket->pBuffer,
- pPacket->ActualLength,
- eid));
-
- ar->arTxPending[eid]--;
-
- if ((eid != ar->arControlEp) || bypasswmi) {
- ar->arTotalTxDataPending--;
- }
-
- if (eid == ar->arControlEp)
- {
- if (ar->arWMIControlEpFull) {
- /* since this packet completed, the WMI EP is no longer full */
- ar->arWMIControlEpFull = false;
- }
-
- if (ar->arTxPending[eid] == 0) {
- wakeEvent = true;
- }
- }
-
- if (status) {
- if (status == A_ECANCELED) {
- /* a packet was flushed */
- flushing = true;
- }
- AR6000_STAT_INC(ar, tx_errors);
- if (status != A_NO_RESOURCE) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s() -TX ERROR, status: 0x%x\n", __func__,
- status));
- }
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_TX,("OK\n"));
- flushing = false;
- AR6000_STAT_INC(ar, tx_packets);
- ar->arNetStats.tx_bytes += A_NETBUF_LEN(pktSkb);
-#ifdef ADAPTIVE_POWER_THROUGHPUT_CONTROL
- aptcTR.bytesTransmitted += a_netbuf_to_len(pktSkb);
- applyAPTCHeuristics(ar);
-#endif /* ADAPTIVE_POWER_THROUGHPUT_CONTROL */
- }
-
- // TODO this needs to be looked at
- if ((ar->arNetworkType == ADHOC_NETWORK) && ar->arIbssPsEnable
- && (eid != ar->arControlEp) && mapNo)
- {
- mapNo --;
- ar->arNodeMap[mapNo].txPending --;
-
- if (!ar->arNodeMap[mapNo].txPending && (mapNo == (ar->arNodeNum - 1))) {
- u32 i;
- for (i = ar->arNodeNum; i > 0; i --) {
- if (!ar->arNodeMap[i - 1].txPending) {
- A_MEMZERO(&ar->arNodeMap[i - 1], sizeof(struct ar_node_mapping));
- ar->arNodeNum --;
- } else {
- break;
- }
- }
- }
- }
-
- ar6000_free_cookie(ar, ar_cookie);
-
- if (ar->arNetQueueStopped) {
- ar->arNetQueueStopped = false;
- }
- }
-
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
-
- /* lock is released, we can freely call other kernel APIs */
-
- /* free all skbs in our local list */
- while (!skb_queue_empty(&skb_queue)) {
- /* use non-lock version */
- pktSkb = __skb_dequeue(&skb_queue);
- A_NETBUF_FREE(pktSkb);
- }
-
- if ((ar->arConnected == true) || bypasswmi) {
- if (!flushing) {
- /* don't wake the queue if we are flushing, other wise it will just
- * keep queueing packets, which will keep failing */
- netif_wake_queue(ar->arNetDev);
- }
- }
-
- if (wakeEvent) {
- wake_up(&arEvent);
- }
-
-}
-
-sta_t *
-ieee80211_find_conn(struct ar6_softc *ar, u8 *node_addr)
-{
- sta_t *conn = NULL;
- u8 i, max_conn;
-
- switch(ar->arNetworkType) {
- case AP_NETWORK:
- max_conn = AP_MAX_NUM_STA;
- break;
- default:
- max_conn=0;
- break;
- }
-
- for (i = 0; i < max_conn; i++) {
- if (IEEE80211_ADDR_EQ(node_addr, ar->sta_list[i].mac)) {
- conn = &ar->sta_list[i];
- break;
- }
- }
-
- return conn;
-}
-
-sta_t *ieee80211_find_conn_for_aid(struct ar6_softc *ar, u8 aid)
-{
- sta_t *conn = NULL;
- u8 ctr;
-
- for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
- if (ar->sta_list[ctr].aid == aid) {
- conn = &ar->sta_list[ctr];
- break;
- }
- }
- return conn;
-}
-
-/*
- * Receive event handler. This is called by HTC when a packet is received
- */
-int pktcount;
-static void
-ar6000_rx(void *Context, struct htc_packet *pPacket)
-{
- struct ar6_softc *ar = (struct ar6_softc *)Context;
- struct sk_buff *skb = (struct sk_buff *)pPacket->pPktContext;
- int minHdrLen;
- u8 containsDot11Hdr = 0;
- int status = pPacket->Status;
- HTC_ENDPOINT_ID ept = pPacket->Endpoint;
-
- A_ASSERT((status) ||
- (pPacket->pBuffer == (A_NETBUF_DATA(skb) + HTC_HEADER_LEN)));
-
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_RX,("ar6000_rx ar=0x%lx eid=%d, skb=0x%lx, data=0x%lx, len=0x%x status:%d",
- (unsigned long)ar, ept, (unsigned long)skb, (unsigned long)pPacket->pBuffer,
- pPacket->ActualLength, status));
- if (status) {
- if (status != A_ECANCELED) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("RX ERR (%d) \n",status));
- }
- }
-
- /* take lock to protect buffer counts
- * and adaptive power throughput state */
- AR6000_SPIN_LOCK(&ar->arLock, 0);
-
- if (!status) {
- AR6000_STAT_INC(ar, rx_packets);
- ar->arNetStats.rx_bytes += pPacket->ActualLength;
-#ifdef ADAPTIVE_POWER_THROUGHPUT_CONTROL
- aptcTR.bytesReceived += a_netbuf_to_len(skb);
- applyAPTCHeuristics(ar);
-#endif /* ADAPTIVE_POWER_THROUGHPUT_CONTROL */
-
- A_NETBUF_PUT(skb, pPacket->ActualLength + HTC_HEADER_LEN);
- A_NETBUF_PULL(skb, HTC_HEADER_LEN);
-
-#ifdef DEBUG
- if (debugdriver >= 2) {
- ar6000_dump_skb(skb);
- }
-#endif /* DEBUG */
- }
-
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
-
- skb->dev = ar->arNetDev;
- if (status) {
- AR6000_STAT_INC(ar, rx_errors);
- A_NETBUF_FREE(skb);
- } else if (ar->arWmiEnabled == true) {
- if (ept == ar->arControlEp) {
- /*
- * this is a wmi control msg
- */
-#ifdef CONFIG_PM
- ar6000_check_wow_status(ar, skb, true);
-#endif /* CONFIG_PM */
- wmi_control_rx(ar->arWmi, skb);
- } else {
- WMI_DATA_HDR *dhdr = (WMI_DATA_HDR *)A_NETBUF_DATA(skb);
- bool is_amsdu;
- u8 tid;
-
- /*
- * This check can be removed if after a while we do not
- * see the warning. For now we leave it to ensure
- * we drop these frames accordingly in case the
- * target generates them for some reason. These
- * were used for an internal PAL but that's not
- * used or supported anymore. These frames should
- * not come up from the target.
- */
- if (WARN_ON(WMI_DATA_HDR_GET_DATA_TYPE(dhdr) ==
- WMI_DATA_HDR_DATA_TYPE_ACL)) {
- AR6000_STAT_INC(ar, rx_errors);
- A_NETBUF_FREE(skb);
- return;
- }
-
-#ifdef CONFIG_PM
- ar6000_check_wow_status(ar, NULL, false);
-#endif /* CONFIG_PM */
- /*
- * this is a wmi data packet
- */
- // NWF
-
- if (processDot11Hdr) {
- minHdrLen = sizeof(WMI_DATA_HDR) + sizeof(struct ieee80211_frame) + sizeof(ATH_LLC_SNAP_HDR);
- } else {
- minHdrLen = sizeof (WMI_DATA_HDR) + sizeof(ATH_MAC_HDR) +
- sizeof(ATH_LLC_SNAP_HDR);
- }
-
- /* In the case of AP mode we may receive NULL data frames
- * that do not have LLC hdr. They are 16 bytes in size.
- * Allow these frames in the AP mode.
- * ACL data frames don't follow ethernet frame bounds for
- * min length
- */
- if (ar->arNetworkType != AP_NETWORK &&
- ((pPacket->ActualLength < minHdrLen) ||
- (pPacket->ActualLength > AR6000_MAX_RX_MESSAGE_SIZE)))
- {
- /*
- * packet is too short or too long
- */
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("TOO SHORT or TOO LONG\n"));
- AR6000_STAT_INC(ar, rx_errors);
- AR6000_STAT_INC(ar, rx_length_errors);
- A_NETBUF_FREE(skb);
- } else {
- u16 seq_no;
- u8 meta_type;
-
-#if 0
- /* Access RSSI values here */
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("RSSI %d\n",
- ((WMI_DATA_HDR *) A_NETBUF_DATA(skb))->rssi));
-#endif
- /* Get the Power save state of the STA */
- if (ar->arNetworkType == AP_NETWORK) {
- sta_t *conn = NULL;
- u8 psState=0,prevPsState;
- ATH_MAC_HDR *datap=NULL;
- u16 offset;
-
- meta_type = WMI_DATA_HDR_GET_META(dhdr);
-
- psState = (((WMI_DATA_HDR *)A_NETBUF_DATA(skb))->info
- >> WMI_DATA_HDR_PS_SHIFT) & WMI_DATA_HDR_PS_MASK;
-
- offset = sizeof(WMI_DATA_HDR);
-
- switch (meta_type) {
- case 0:
- break;
- case WMI_META_VERSION_1:
- offset += sizeof(WMI_RX_META_V1);
- break;
- case WMI_META_VERSION_2:
- offset += sizeof(WMI_RX_META_V2);
- break;
- default:
- break;
- }
-
- datap = (ATH_MAC_HDR *)(A_NETBUF_DATA(skb)+offset);
- conn = ieee80211_find_conn(ar, datap->srcMac);
-
- if (conn) {
- /* if there is a change in PS state of the STA,
- * take appropriate steps.
- * 1. If Sleep-->Awake, flush the psq for the STA
- * Clear the PVB for the STA.
- * 2. If Awake-->Sleep, Starting queueing frames
- * the STA.
- */
- prevPsState = STA_IS_PWR_SLEEP(conn);
- if (psState) {
- STA_SET_PWR_SLEEP(conn);
- } else {
- STA_CLR_PWR_SLEEP(conn);
- }
-
- if (prevPsState ^ STA_IS_PWR_SLEEP(conn)) {
-
- if (!STA_IS_PWR_SLEEP(conn)) {
-
- A_MUTEX_LOCK(&conn->psqLock);
- while (!A_NETBUF_QUEUE_EMPTY(&conn->psq)) {
- struct sk_buff *skb=NULL;
-
- skb = A_NETBUF_DEQUEUE(&conn->psq);
- A_MUTEX_UNLOCK(&conn->psqLock);
- ar6000_data_tx(skb,ar->arNetDev);
- A_MUTEX_LOCK(&conn->psqLock);
- }
- A_MUTEX_UNLOCK(&conn->psqLock);
- /* Clear the PVB for this STA */
- wmi_set_pvb_cmd(ar->arWmi, conn->aid, 0);
- }
- }
- } else {
- /* This frame is from a STA that is not associated*/
- A_ASSERT(false);
- }
-
- /* Drop NULL data frames here */
- if((pPacket->ActualLength < minHdrLen) ||
- (pPacket->ActualLength > AR6000_MAX_RX_MESSAGE_SIZE)) {
- A_NETBUF_FREE(skb);
- goto rx_done;
- }
- }
-
- is_amsdu = WMI_DATA_HDR_IS_AMSDU(dhdr) ? true : false;
- tid = WMI_DATA_HDR_GET_UP(dhdr);
- seq_no = WMI_DATA_HDR_GET_SEQNO(dhdr);
- meta_type = WMI_DATA_HDR_GET_META(dhdr);
- containsDot11Hdr = WMI_DATA_HDR_GET_DOT11(dhdr);
-
- wmi_data_hdr_remove(ar->arWmi, skb);
-
- switch (meta_type) {
- case WMI_META_VERSION_1:
- {
- WMI_RX_META_V1 *pMeta = (WMI_RX_META_V1 *)A_NETBUF_DATA(skb);
- A_PRINTF("META %d %d %d %d %x\n", pMeta->status, pMeta->rix, pMeta->rssi, pMeta->channel, pMeta->flags);
- A_NETBUF_PULL((void*)skb, sizeof(WMI_RX_META_V1));
- break;
- }
- case WMI_META_VERSION_2:
- {
- WMI_RX_META_V2 *pMeta = (WMI_RX_META_V2 *)A_NETBUF_DATA(skb);
- if(pMeta->csumFlags & 0x1){
- skb->ip_summed=CHECKSUM_COMPLETE;
- skb->csum=(pMeta->csum);
- }
- A_NETBUF_PULL((void*)skb, sizeof(WMI_RX_META_V2));
- break;
- }
- default:
- break;
- }
-
- A_ASSERT(status == 0);
-
- /* NWF: print the 802.11 hdr bytes */
- if(containsDot11Hdr) {
- status = wmi_dot11_hdr_remove(ar->arWmi,skb);
- } else if(!is_amsdu) {
- status = wmi_dot3_2_dix(skb);
- }
-
- if (status) {
- /* Drop frames that could not be processed (lack of memory, etc.) */
- A_NETBUF_FREE(skb);
- goto rx_done;
- }
-
- if ((ar->arNetDev->flags & IFF_UP) == IFF_UP) {
- if (ar->arNetworkType == AP_NETWORK) {
- struct sk_buff *skb1 = NULL;
- ATH_MAC_HDR *datap;
-
- datap = (ATH_MAC_HDR *)A_NETBUF_DATA(skb);
- if (IEEE80211_IS_MULTICAST(datap->dstMac)) {
- /* Bcast/Mcast frames should be sent to the OS
- * stack as well as on the air.
- */
- skb1 = skb_copy(skb,GFP_ATOMIC);
- } else {
- /* Search for a connected STA with dstMac as
- * the Mac address. If found send the frame to
- * it on the air else send the frame up the
- * stack
- */
- sta_t *conn = NULL;
- conn = ieee80211_find_conn(ar, datap->dstMac);
-
- if (conn && ar->intra_bss) {
- skb1 = skb;
- skb = NULL;
- } else if(conn && !ar->intra_bss) {
- A_NETBUF_FREE(skb);
- skb = NULL;
- }
- }
- if (skb1) {
- ar6000_data_tx(skb1, ar->arNetDev);
- }
- }
- }
- aggr_process_recv_frm(ar->aggr_cntxt, tid, seq_no, is_amsdu, (void **)&skb);
- ar6000_deliver_frames_to_nw_stack((void *) ar->arNetDev, (void *)skb);
- }
- }
- } else {
- if (EPPING_ALIGNMENT_PAD > 0) {
- A_NETBUF_PULL(skb, EPPING_ALIGNMENT_PAD);
- }
- ar6000_deliver_frames_to_nw_stack((void *)ar->arNetDev, (void *)skb);
- }
-
-rx_done:
-
- return;
-}
-
-static void
-ar6000_deliver_frames_to_nw_stack(void *dev, void *osbuf)
-{
- struct sk_buff *skb = (struct sk_buff *)osbuf;
-
- if(skb) {
- skb->dev = dev;
- if ((skb->dev->flags & IFF_UP) == IFF_UP) {
-#ifdef CONFIG_PM
- ar6000_check_wow_status((struct ar6_softc *)ar6k_priv(dev), skb, false);
-#endif /* CONFIG_PM */
- skb->protocol = eth_type_trans(skb, skb->dev);
- /*
- * If this routine is called on a ISR (Hard IRQ) or DSR (Soft IRQ)
- * or tasklet use the netif_rx to deliver the packet to the stack
- * netif_rx will queue the packet onto the receive queue and mark
- * the softirq thread has a pending action to complete. Kernel will
- * schedule the softIrq kernel thread after processing the DSR.
- *
- * If this routine is called on a process context, use netif_rx_ni
- * which will schedle the softIrq kernel thread after queuing the packet.
- */
- if (in_interrupt()) {
- netif_rx(skb);
- } else {
- netif_rx_ni(skb);
- }
- } else {
- A_NETBUF_FREE(skb);
- }
- }
-}
-
-#if 0
-static void
-ar6000_deliver_frames_to_bt_stack(void *dev, void *osbuf)
-{
- struct sk_buff *skb = (struct sk_buff *)osbuf;
-
- if(skb) {
- skb->dev = dev;
- if ((skb->dev->flags & IFF_UP) == IFF_UP) {
- skb->protocol = htons(ETH_P_CONTROL);
- netif_rx(skb);
- } else {
- A_NETBUF_FREE(skb);
- }
- }
-}
-#endif
-
-static void
-ar6000_rx_refill(void *Context, HTC_ENDPOINT_ID Endpoint)
-{
- struct ar6_softc *ar = (struct ar6_softc *)Context;
- void *osBuf;
- int RxBuffers;
- int buffersToRefill;
- struct htc_packet *pPacket;
- struct htc_packet_queue queue;
-
- buffersToRefill = (int)AR6000_MAX_RX_BUFFERS -
- HTCGetNumRecvBuffers(ar->arHtcTarget, Endpoint);
-
- if (buffersToRefill <= 0) {
- /* fast return, nothing to fill */
- return;
- }
-
- INIT_HTC_PACKET_QUEUE(&queue);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_RX,("ar6000_rx_refill: providing htc with %d buffers at eid=%d\n",
- buffersToRefill, Endpoint));
-
- for (RxBuffers = 0; RxBuffers < buffersToRefill; RxBuffers++) {
- osBuf = A_NETBUF_ALLOC(AR6000_BUFFER_SIZE);
- if (NULL == osBuf) {
- break;
- }
- /* the HTC packet wrapper is at the head of the reserved area
- * in the skb */
- pPacket = (struct htc_packet *)(A_NETBUF_HEAD(osBuf));
- /* set re-fill info */
- SET_HTC_PACKET_INFO_RX_REFILL(pPacket,osBuf,A_NETBUF_DATA(osBuf),AR6000_BUFFER_SIZE,Endpoint);
- /* add to queue */
- HTC_PACKET_ENQUEUE(&queue,pPacket);
- }
-
- if (!HTC_QUEUE_EMPTY(&queue)) {
- /* add packets */
- HTCAddReceivePktMultiple(ar->arHtcTarget, &queue);
- }
-
-}
-
- /* clean up our amsdu buffer list */
-static void ar6000_cleanup_amsdu_rxbufs(struct ar6_softc *ar)
-{
- struct htc_packet *pPacket;
- void *osBuf;
-
- /* empty AMSDU buffer queue and free OS bufs */
- while (true) {
-
- AR6000_SPIN_LOCK(&ar->arLock, 0);
- pPacket = HTC_PACKET_DEQUEUE(&ar->amsdu_rx_buffer_queue);
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
-
- if (NULL == pPacket) {
- break;
- }
-
- osBuf = pPacket->pPktContext;
- if (NULL == osBuf) {
- A_ASSERT(false);
- break;
- }
-
- A_NETBUF_FREE(osBuf);
- }
-
-}
-
-
- /* refill the amsdu buffer list */
-static void ar6000_refill_amsdu_rxbufs(struct ar6_softc *ar, int Count)
-{
- struct htc_packet *pPacket;
- void *osBuf;
-
- while (Count > 0) {
- osBuf = A_NETBUF_ALLOC(AR6000_AMSDU_BUFFER_SIZE);
- if (NULL == osBuf) {
- break;
- }
- /* the HTC packet wrapper is at the head of the reserved area
- * in the skb */
- pPacket = (struct htc_packet *)(A_NETBUF_HEAD(osBuf));
- /* set re-fill info */
- SET_HTC_PACKET_INFO_RX_REFILL(pPacket,osBuf,A_NETBUF_DATA(osBuf),AR6000_AMSDU_BUFFER_SIZE,0);
-
- AR6000_SPIN_LOCK(&ar->arLock, 0);
- /* put it in the list */
- HTC_PACKET_ENQUEUE(&ar->amsdu_rx_buffer_queue,pPacket);
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
- Count--;
- }
-
-}
-
- /* callback to allocate a large receive buffer for a pending packet. This function is called when
- * an HTC packet arrives whose length exceeds a threshold value
- *
- * We use a pre-allocated list of buffers of maximum AMSDU size (4K). Under linux it is more optimal to
- * keep the allocation size the same to optimize cached-slab allocations.
- *
- * */
-static struct htc_packet *ar6000_alloc_amsdu_rxbuf(void *Context, HTC_ENDPOINT_ID Endpoint, int Length)
-{
- struct htc_packet *pPacket = NULL;
- struct ar6_softc *ar = (struct ar6_softc *)Context;
- int refillCount = 0;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_RX,("ar6000_alloc_amsdu_rxbuf: eid=%d, Length:%d\n",Endpoint,Length));
-
- do {
-
- if (Length <= AR6000_BUFFER_SIZE) {
- /* shouldn't be getting called on normal sized packets */
- A_ASSERT(false);
- break;
- }
-
- if (Length > AR6000_AMSDU_BUFFER_SIZE) {
- A_ASSERT(false);
- break;
- }
-
- AR6000_SPIN_LOCK(&ar->arLock, 0);
- /* allocate a packet from the list */
- pPacket = HTC_PACKET_DEQUEUE(&ar->amsdu_rx_buffer_queue);
- /* see if we need to refill again */
- refillCount = AR6000_MAX_AMSDU_RX_BUFFERS - HTC_PACKET_QUEUE_DEPTH(&ar->amsdu_rx_buffer_queue);
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
-
- if (NULL == pPacket) {
- break;
- }
- /* set actual endpoint ID */
- pPacket->Endpoint = Endpoint;
-
- } while (false);
-
- if (refillCount >= AR6000_AMSDU_REFILL_THRESHOLD) {
- ar6000_refill_amsdu_rxbufs(ar,refillCount);
- }
-
- return pPacket;
-}
-
-static void
-ar6000_set_multicast_list(struct net_device *dev)
-{
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("ar6000: Multicast filter not supported\n"));
-}
-
-static struct net_device_stats *
-ar6000_get_stats(struct net_device *dev)
-{
- struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev);
- return &ar->arNetStats;
-}
-
-void
-ar6000_ready_event(void *devt, u8 *datap, u8 phyCap, u32 sw_ver, u32 abi_ver)
-{
- struct ar6_softc *ar = (struct ar6_softc *)devt;
- struct net_device *dev = ar->arNetDev;
-
- memcpy(dev->dev_addr, datap, AR6000_ETH_ADDR_LEN);
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("mac address = %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5]));
-
- ar->arPhyCapability = phyCap;
- ar->arVersion.wlan_ver = sw_ver;
- ar->arVersion.abi_ver = abi_ver;
-
- snprintf(ar->wdev->wiphy->fw_version, sizeof(ar->wdev->wiphy->fw_version),
- "%u:%u:%u:%u",
- (ar->arVersion.wlan_ver & 0xf0000000) >> 28,
- (ar->arVersion.wlan_ver & 0x0f000000) >> 24,
- (ar->arVersion.wlan_ver & 0x00ff0000) >> 16,
- (ar->arVersion.wlan_ver & 0x0000ffff));
-
- /* Indicate to the waiting thread that the ready event was received */
- ar->arWmiReady = true;
- wake_up(&arEvent);
-}
-
-void ar6000_install_static_wep_keys(struct ar6_softc *ar)
-{
- u8 index;
- u8 keyUsage;
-
- for (index = WMI_MIN_KEY_INDEX; index <= WMI_MAX_KEY_INDEX; index++) {
- if (ar->arWepKeyList[index].arKeyLen) {
- keyUsage = GROUP_USAGE;
- if (index == ar->arDefTxKeyIndex) {
- keyUsage |= TX_USAGE;
- }
- wmi_addKey_cmd(ar->arWmi,
- index,
- WEP_CRYPT,
- keyUsage,
- ar->arWepKeyList[index].arKeyLen,
- NULL,
- ar->arWepKeyList[index].arKey, KEY_OP_INIT_VAL, NULL,
- NO_SYNC_WMIFLAG);
- }
- }
-}
-
-void
-add_new_sta(struct ar6_softc *ar, u8 *mac, u16 aid, u8 *wpaie,
- u8 ielen, u8 keymgmt, u8 ucipher, u8 auth)
-{
- u8 free_slot=aid-1;
-
- memcpy(ar->sta_list[free_slot].mac, mac, ATH_MAC_LEN);
- memcpy(ar->sta_list[free_slot].wpa_ie, wpaie, ielen);
- ar->sta_list[free_slot].aid = aid;
- ar->sta_list[free_slot].keymgmt = keymgmt;
- ar->sta_list[free_slot].ucipher = ucipher;
- ar->sta_list[free_slot].auth = auth;
- ar->sta_list_index = ar->sta_list_index | (1 << free_slot);
- ar->arAPStats.sta[free_slot].aid = aid;
-}
-
-void
-ar6000_connect_event(struct ar6_softc *ar, u16 channel, u8 *bssid,
- u16 listenInterval, u16 beaconInterval,
- NETWORK_TYPE networkType, u8 beaconIeLen,
- u8 assocReqLen, u8 assocRespLen,
- u8 *assocInfo)
-{
- union iwreq_data wrqu;
- int i, beacon_ie_pos, assoc_resp_ie_pos, assoc_req_ie_pos;
- static const char *tag1 = "ASSOCINFO(ReqIEs=";
- static const char *tag2 = "ASSOCRESPIE=";
- static const char *beaconIetag = "BEACONIE=";
- char buf[WMI_CONTROL_MSG_MAX_LEN * 2 + strlen(tag1) + 1];
- char *pos;
- u8 key_op_ctrl;
- unsigned long flags;
- struct ieee80211req_key *ik;
- CRYPTO_TYPE keyType = NONE_CRYPT;
-
- if(ar->arNetworkType & AP_NETWORK) {
- struct net_device *dev = ar->arNetDev;
- if(memcmp(dev->dev_addr, bssid, ATH_MAC_LEN)==0) {
- ar->arACS = channel;
- ik = &ar->ap_mode_bkey;
-
- switch(ar->arAuthMode) {
- case NONE_AUTH:
- if(ar->arPairwiseCrypto == WEP_CRYPT) {
- ar6000_install_static_wep_keys(ar);
- }
-#ifdef WAPI_ENABLE
- else if(ar->arPairwiseCrypto == WAPI_CRYPT) {
- ap_set_wapi_key(ar, ik);
- }
-#endif
- break;
- case WPA_PSK_AUTH:
- case WPA2_PSK_AUTH:
- case (WPA_PSK_AUTH|WPA2_PSK_AUTH):
- switch (ik->ik_type) {
- case IEEE80211_CIPHER_TKIP:
- keyType = TKIP_CRYPT;
- break;
- case IEEE80211_CIPHER_AES_CCM:
- keyType = AES_CRYPT;
- break;
- default:
- goto skip_key;
- }
- wmi_addKey_cmd(ar->arWmi, ik->ik_keyix, keyType, GROUP_USAGE,
- ik->ik_keylen, (u8 *)&ik->ik_keyrsc,
- ik->ik_keydata, KEY_OP_INIT_VAL, ik->ik_macaddr,
- SYNC_BOTH_WMIFLAG);
-
- break;
- }
-skip_key:
- ar->arConnected = true;
- return;
- }
-
- A_PRINTF("NEW STA %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x \n "
- " AID=%d \n", bssid[0], bssid[1], bssid[2],
- bssid[3], bssid[4], bssid[5], channel);
- switch ((listenInterval>>8)&0xFF) {
- case OPEN_AUTH:
- A_PRINTF("AUTH: OPEN\n");
- break;
- case SHARED_AUTH:
- A_PRINTF("AUTH: SHARED\n");
- break;
- default:
- A_PRINTF("AUTH: Unknown\n");
- break;
- }
- switch (listenInterval&0xFF) {
- case WPA_PSK_AUTH:
- A_PRINTF("KeyMgmt: WPA-PSK\n");
- break;
- case WPA2_PSK_AUTH:
- A_PRINTF("KeyMgmt: WPA2-PSK\n");
- break;
- default:
- A_PRINTF("KeyMgmt: NONE\n");
- break;
- }
- switch (beaconInterval) {
- case AES_CRYPT:
- A_PRINTF("Cipher: AES\n");
- break;
- case TKIP_CRYPT:
- A_PRINTF("Cipher: TKIP\n");
- break;
- case WEP_CRYPT:
- A_PRINTF("Cipher: WEP\n");
- break;
-#ifdef WAPI_ENABLE
- case WAPI_CRYPT:
- A_PRINTF("Cipher: WAPI\n");
- break;
-#endif
- default:
- A_PRINTF("Cipher: NONE\n");
- break;
- }
-
- add_new_sta(ar, bssid, channel /*aid*/,
- assocInfo /* WPA IE */, assocRespLen /* IE len */,
- listenInterval&0xFF /* Keymgmt */, beaconInterval /* cipher */,
- (listenInterval>>8)&0xFF /* auth alg */);
-
- /* Send event to application */
- A_MEMZERO(&wrqu, sizeof(wrqu));
- memcpy(wrqu.addr.sa_data, bssid, ATH_MAC_LEN);
- wireless_send_event(ar->arNetDev, IWEVREGISTERED, &wrqu, NULL);
- /* In case the queue is stopped when we switch modes, this will
- * wake it up
- */
- netif_wake_queue(ar->arNetDev);
- return;
- }
-
- ar6k_cfg80211_connect_event(ar, channel, bssid,
- listenInterval, beaconInterval,
- networkType, beaconIeLen,
- assocReqLen, assocRespLen,
- assocInfo);
-
- memcpy(ar->arBssid, bssid, sizeof(ar->arBssid));
- ar->arBssChannel = channel;
-
- A_PRINTF("AR6000 connected event on freq %d ", channel);
- A_PRINTF("with bssid %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x "
- " listenInterval=%d, beaconInterval = %d, beaconIeLen = %d assocReqLen=%d"
- " assocRespLen =%d\n",
- bssid[0], bssid[1], bssid[2],
- bssid[3], bssid[4], bssid[5],
- listenInterval, beaconInterval,
- beaconIeLen, assocReqLen, assocRespLen);
- if (networkType & ADHOC_NETWORK) {
- if (networkType & ADHOC_CREATOR) {
- A_PRINTF("Network: Adhoc (Creator)\n");
- } else {
- A_PRINTF("Network: Adhoc (Joiner)\n");
- }
- } else {
- A_PRINTF("Network: Infrastructure\n");
- }
-
- if ((ar->arNetworkType == INFRA_NETWORK)) {
- wmi_listeninterval_cmd(ar->arWmi, ar->arListenIntervalT, ar->arListenIntervalB);
- }
-
- if (beaconIeLen && (sizeof(buf) > (9 + beaconIeLen * 2))) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_CONNECT,("\nBeaconIEs= "));
-
- beacon_ie_pos = 0;
- A_MEMZERO(buf, sizeof(buf));
- sprintf(buf, "%s", beaconIetag);
- pos = buf + 9;
- for (i = beacon_ie_pos; i < beacon_ie_pos + beaconIeLen; i++) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_CONNECT,("%2.2x ", assocInfo[i]));
- sprintf(pos, "%2.2x", assocInfo[i]);
- pos += 2;
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_CONNECT,("\n"));
-
- A_MEMZERO(&wrqu, sizeof(wrqu));
- wrqu.data.length = strlen(buf);
- wireless_send_event(ar->arNetDev, IWEVCUSTOM, &wrqu, buf);
- }
-
- if (assocRespLen && (sizeof(buf) > (12 + (assocRespLen * 2))))
- {
- assoc_resp_ie_pos = beaconIeLen + assocReqLen +
- sizeof(u16) + /* capinfo*/
- sizeof(u16) + /* status Code */
- sizeof(u16) ; /* associd */
- A_MEMZERO(buf, sizeof(buf));
- sprintf(buf, "%s", tag2);
- pos = buf + 12;
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_CONNECT,("\nAssocRespIEs= "));
- /*
- * The Association Response Frame w.o. the WLAN header is delivered to
- * the host, so skip over to the IEs
- */
- for (i = assoc_resp_ie_pos; i < assoc_resp_ie_pos + assocRespLen - 6; i++)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_CONNECT,("%2.2x ", assocInfo[i]));
- sprintf(pos, "%2.2x", assocInfo[i]);
- pos += 2;
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_CONNECT,("\n"));
-
- A_MEMZERO(&wrqu, sizeof(wrqu));
- wrqu.data.length = strlen(buf);
- wireless_send_event(ar->arNetDev, IWEVCUSTOM, &wrqu, buf);
- }
-
- if (assocReqLen && (sizeof(buf) > (17 + (assocReqLen * 2)))) {
- /*
- * assoc Request includes capability and listen interval. Skip these.
- */
- assoc_req_ie_pos = beaconIeLen +
- sizeof(u16) + /* capinfo*/
- sizeof(u16); /* listen interval */
-
- A_MEMZERO(buf, sizeof(buf));
- sprintf(buf, "%s", tag1);
- pos = buf + 17;
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_CONNECT,("AssocReqIEs= "));
- for (i = assoc_req_ie_pos; i < assoc_req_ie_pos + assocReqLen - 4; i++) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_CONNECT,("%2.2x ", assocInfo[i]));
- sprintf(pos, "%2.2x", assocInfo[i]);
- pos += 2;
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_CONNECT,("\n"));
-
- A_MEMZERO(&wrqu, sizeof(wrqu));
- wrqu.data.length = strlen(buf);
- wireless_send_event(ar->arNetDev, IWEVCUSTOM, &wrqu, buf);
- }
-
- if (ar->user_savedkeys_stat == USER_SAVEDKEYS_STAT_RUN &&
- ar->user_saved_keys.keyOk == true)
- {
- key_op_ctrl = KEY_OP_VALID_MASK & ~KEY_OP_INIT_TSC;
-
- if (ar->user_key_ctrl & AR6000_USER_SETKEYS_RSC_UNCHANGED) {
- key_op_ctrl &= ~KEY_OP_INIT_RSC;
- } else {
- key_op_ctrl |= KEY_OP_INIT_RSC;
- }
- ar6000_reinstall_keys(ar, key_op_ctrl);
- }
-
- netif_wake_queue(ar->arNetDev);
-
- /* Update connect & link status atomically */
- spin_lock_irqsave(&ar->arLock, flags);
- ar->arConnected = true;
- ar->arConnectPending = false;
- netif_carrier_on(ar->arNetDev);
- spin_unlock_irqrestore(&ar->arLock, flags);
- /* reset the rx aggr state */
- aggr_reset_state(ar->aggr_cntxt);
- reconnect_flag = 0;
-
- A_MEMZERO(&wrqu, sizeof(wrqu));
- memcpy(wrqu.addr.sa_data, bssid, IEEE80211_ADDR_LEN);
- wrqu.addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(ar->arNetDev, SIOCGIWAP, &wrqu, NULL);
- if ((ar->arNetworkType == ADHOC_NETWORK) && ar->arIbssPsEnable) {
- A_MEMZERO(ar->arNodeMap, sizeof(ar->arNodeMap));
- ar->arNodeNum = 0;
- ar->arNexEpId = ENDPOINT_2;
- }
- if (!ar->arUserBssFilter) {
- wmi_bssfilter_cmd(ar->arWmi, NONE_BSS_FILTER, 0);
- }
-
-}
-
-void ar6000_set_numdataendpts(struct ar6_softc *ar, u32 num)
-{
- A_ASSERT(num <= (HTC_MAILBOX_NUM_MAX - 1));
- ar->arNumDataEndPts = num;
-}
-
-void
-sta_cleanup(struct ar6_softc *ar, u8 i)
-{
- struct sk_buff *skb;
-
- /* empty the queued pkts in the PS queue if any */
- A_MUTEX_LOCK(&ar->sta_list[i].psqLock);
- while (!A_NETBUF_QUEUE_EMPTY(&ar->sta_list[i].psq)) {
- skb = A_NETBUF_DEQUEUE(&ar->sta_list[i].psq);
- A_NETBUF_FREE(skb);
- }
- A_MUTEX_UNLOCK(&ar->sta_list[i].psqLock);
-
- /* Zero out the state fields */
- A_MEMZERO(&ar->arAPStats.sta[ar->sta_list[i].aid-1], sizeof(WMI_PER_STA_STAT));
- A_MEMZERO(&ar->sta_list[i].mac, ATH_MAC_LEN);
- A_MEMZERO(&ar->sta_list[i].wpa_ie, IEEE80211_MAX_IE);
- ar->sta_list[i].aid = 0;
- ar->sta_list[i].flags = 0;
-
- ar->sta_list_index = ar->sta_list_index & ~(1 << i);
-
-}
-
-u8 remove_sta(struct ar6_softc *ar, u8 *mac, u16 reason)
-{
- u8 i, removed=0;
-
- if(IS_MAC_NULL(mac)) {
- return removed;
- }
-
- if(IS_MAC_BCAST(mac)) {
- A_PRINTF("DEL ALL STA\n");
- for(i=0; i < AP_MAX_NUM_STA; i++) {
- if(!IS_MAC_NULL(ar->sta_list[i].mac)) {
- sta_cleanup(ar, i);
- removed = 1;
- }
- }
- } else {
- for(i=0; i < AP_MAX_NUM_STA; i++) {
- if(memcmp(ar->sta_list[i].mac, mac, ATH_MAC_LEN)==0) {
- A_PRINTF("DEL STA %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x "
- " aid=%d REASON=%d\n", mac[0], mac[1], mac[2],
- mac[3], mac[4], mac[5], ar->sta_list[i].aid, reason);
-
- sta_cleanup(ar, i);
- removed = 1;
- break;
- }
- }
- }
- return removed;
-}
-
-void
-ar6000_disconnect_event(struct ar6_softc *ar, u8 reason, u8 *bssid,
- u8 assocRespLen, u8 *assocInfo, u16 protocolReasonStatus)
-{
- u8 i;
- unsigned long flags;
- union iwreq_data wrqu;
-
- if(ar->arNetworkType & AP_NETWORK) {
- union iwreq_data wrqu;
- struct sk_buff *skb;
-
- if(!remove_sta(ar, bssid, protocolReasonStatus)) {
- return;
- }
-
- /* If there are no more associated STAs, empty the mcast PS q */
- if (ar->sta_list_index == 0) {
- A_MUTEX_LOCK(&ar->mcastpsqLock);
- while (!A_NETBUF_QUEUE_EMPTY(&ar->mcastpsq)) {
- skb = A_NETBUF_DEQUEUE(&ar->mcastpsq);
- A_NETBUF_FREE(skb);
- }
- A_MUTEX_UNLOCK(&ar->mcastpsqLock);
-
- /* Clear the LSB of the BitMapCtl field of the TIM IE */
- if (ar->arWmiReady) {
- wmi_set_pvb_cmd(ar->arWmi, MCAST_AID, 0);
- }
- }
-
- if(!IS_MAC_BCAST(bssid)) {
- /* Send event to application */
- A_MEMZERO(&wrqu, sizeof(wrqu));
- memcpy(wrqu.addr.sa_data, bssid, ATH_MAC_LEN);
- wireless_send_event(ar->arNetDev, IWEVEXPIRED, &wrqu, NULL);
- }
-
- ar->arConnected = false;
- return;
- }
-
- ar6k_cfg80211_disconnect_event(ar, reason, bssid,
- assocRespLen, assocInfo,
- protocolReasonStatus);
-
- /* Send disconnect event to supplicant */
- A_MEMZERO(&wrqu, sizeof(wrqu));
- wrqu.addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(ar->arNetDev, SIOCGIWAP, &wrqu, NULL);
-
- /* it is necessary to clear the host-side rx aggregation state */
- aggr_reset_state(ar->aggr_cntxt);
-
- A_UNTIMEOUT(&ar->disconnect_timer);
-
- A_PRINTF("AR6000 disconnected");
- if (bssid[0] || bssid[1] || bssid[2] || bssid[3] || bssid[4] || bssid[5]) {
- A_PRINTF(" from %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x ",
- bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_CONNECT,("\nDisconnect Reason is %d", reason));
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_CONNECT,("\nProtocol Reason/Status Code is %d", protocolReasonStatus));
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_CONNECT,("\nAssocResp Frame = %s",
- assocRespLen ? " " : "NULL"));
- for (i = 0; i < assocRespLen; i++) {
- if (!(i % 0x10)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_CONNECT,("\n"));
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_CONNECT,("%2.2x ", assocInfo[i]));
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_CONNECT,("\n"));
- /*
- * If the event is due to disconnect cmd from the host, only they the target
- * would stop trying to connect. Under any other condition, target would
- * keep trying to connect.
- *
- */
- if( reason == DISCONNECT_CMD)
- {
- if ((!ar->arUserBssFilter) && (ar->arWmiReady)) {
- wmi_bssfilter_cmd(ar->arWmi, NONE_BSS_FILTER, 0);
- }
- } else {
- ar->arConnectPending = true;
- if (((reason == ASSOC_FAILED) && (protocolReasonStatus == 0x11)) ||
- ((reason == ASSOC_FAILED) && (protocolReasonStatus == 0x0) && (reconnect_flag == 1))) {
- ar->arConnected = true;
- return;
- }
- }
-
- if ((reason == NO_NETWORK_AVAIL) && (ar->arWmiReady))
- {
- bss_t *pWmiSsidnode = NULL;
-
- /* remove the current associated bssid node */
- wmi_free_node (ar->arWmi, bssid);
-
- /*
- * In case any other same SSID nodes are present
- * remove it, since those nodes also not available now
- */
- do
- {
- /*
- * Find the nodes based on SSID and remove it
- * NOTE :: This case will not work out for Hidden-SSID
- */
- pWmiSsidnode = wmi_find_Ssidnode (ar->arWmi, ar->arSsid, ar->arSsidLen, false, true);
-
- if (pWmiSsidnode)
- {
- wmi_free_node (ar->arWmi, pWmiSsidnode->ni_macaddr);
- }
-
- } while (pWmiSsidnode);
- }
-
- /* Update connect & link status atomically */
- spin_lock_irqsave(&ar->arLock, flags);
- ar->arConnected = false;
- netif_carrier_off(ar->arNetDev);
- spin_unlock_irqrestore(&ar->arLock, flags);
-
- if( (reason != CSERV_DISCONNECT) || (reconnect_flag != 1) ) {
- reconnect_flag = 0;
- }
-
- if (reason != CSERV_DISCONNECT)
- {
- ar->user_savedkeys_stat = USER_SAVEDKEYS_STAT_INIT;
- ar->user_key_ctrl = 0;
- }
-
- netif_stop_queue(ar->arNetDev);
- A_MEMZERO(ar->arBssid, sizeof(ar->arBssid));
- ar->arBssChannel = 0;
- ar->arBeaconInterval = 0;
-
- ar6000_TxDataCleanup(ar);
-}
-
-void
-ar6000_regDomain_event(struct ar6_softc *ar, u32 regCode)
-{
- A_PRINTF("AR6000 Reg Code = 0x%x\n", regCode);
- ar->arRegCode = regCode;
-}
-
-void
-ar6000_aggr_rcv_addba_req_evt(struct ar6_softc *ar, WMI_ADDBA_REQ_EVENT *evt)
-{
- if(evt->status == 0) {
- aggr_recv_addba_req_evt(ar->aggr_cntxt, evt->tid, evt->st_seq_no, evt->win_sz);
- }
-}
-
-void
-ar6000_aggr_rcv_addba_resp_evt(struct ar6_softc *ar, WMI_ADDBA_RESP_EVENT *evt)
-{
- A_PRINTF("ADDBA RESP. tid %d status %d, sz %d\n", evt->tid, evt->status, evt->amsdu_sz);
- if(evt->status == 0) {
- }
-}
-
-void
-ar6000_aggr_rcv_delba_req_evt(struct ar6_softc *ar, WMI_DELBA_EVENT *evt)
-{
- aggr_recv_delba_req_evt(ar->aggr_cntxt, evt->tid);
-}
-
-void register_pal_cb(ar6k_pal_config_t *palConfig_p)
-{
- ar6k_pal_config_g = *palConfig_p;
-}
-
-void
-ar6000_hci_event_rcv_evt(struct ar6_softc *ar, WMI_HCI_EVENT *cmd)
-{
- void *osbuf = NULL;
- s8 i;
- u8 size, *buf;
- int ret = 0;
-
- size = cmd->evt_buf_sz + 4;
- osbuf = A_NETBUF_ALLOC(size);
- if (osbuf == NULL) {
- ret = A_NO_MEMORY;
- A_PRINTF("Error in allocating netbuf \n");
- return;
- }
-
- A_NETBUF_PUT(osbuf, size);
- buf = (u8 *)A_NETBUF_DATA(osbuf);
- /* First 2-bytes carry HCI event/ACL data type
- * the next 2 are free
- */
- *((short *)buf) = WMI_HCI_EVENT_EVENTID;
- buf += sizeof(int);
- memcpy(buf, cmd->buf, cmd->evt_buf_sz);
-
- ar6000_deliver_frames_to_nw_stack(ar->arNetDev, osbuf);
- if(loghci) {
- A_PRINTF_LOG("HCI Event From PAL <-- \n");
- for(i = 0; i < cmd->evt_buf_sz; i++) {
- A_PRINTF_LOG("0x%02x ", cmd->buf[i]);
- if((i % 10) == 0) {
- A_PRINTF_LOG("\n");
- }
- }
- A_PRINTF_LOG("\n");
- A_PRINTF_LOG("==================================\n");
- }
-}
-
-void
-ar6000_neighborReport_event(struct ar6_softc *ar, int numAps, WMI_NEIGHBOR_INFO *info)
-{
-#if WIRELESS_EXT >= 18
- struct iw_pmkid_cand *pmkcand;
-#else /* WIRELESS_EXT >= 18 */
- static const char *tag = "PRE-AUTH";
- char buf[128];
-#endif /* WIRELESS_EXT >= 18 */
-
- union iwreq_data wrqu;
- int i;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_SCAN,("AR6000 Neighbor Report Event\n"));
- for (i=0; i < numAps; info++, i++) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_SCAN,("bssid %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x ",
- info->bssid[0], info->bssid[1], info->bssid[2],
- info->bssid[3], info->bssid[4], info->bssid[5]));
- if (info->bssFlags & WMI_PREAUTH_CAPABLE_BSS) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_SCAN,("preauth-cap"));
- }
- if (info->bssFlags & WMI_PMKID_VALID_BSS) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_SCAN,(" pmkid-valid\n"));
- continue; /* we skip bss if the pmkid is already valid */
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_SCAN,("\n"));
- A_MEMZERO(&wrqu, sizeof(wrqu));
-#if WIRELESS_EXT >= 18
- pmkcand = A_MALLOC_NOWAIT(sizeof(struct iw_pmkid_cand));
- A_MEMZERO(pmkcand, sizeof(struct iw_pmkid_cand));
- pmkcand->index = i;
- pmkcand->flags = info->bssFlags;
- memcpy(pmkcand->bssid.sa_data, info->bssid, ATH_MAC_LEN);
- wrqu.data.length = sizeof(struct iw_pmkid_cand);
- wireless_send_event(ar->arNetDev, IWEVPMKIDCAND, &wrqu, (char *)pmkcand);
- kfree(pmkcand);
-#else /* WIRELESS_EXT >= 18 */
- snprintf(buf, sizeof(buf), "%s%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
- tag,
- info->bssid[0], info->bssid[1], info->bssid[2],
- info->bssid[3], info->bssid[4], info->bssid[5],
- i, info->bssFlags);
- wrqu.data.length = strlen(buf);
- wireless_send_event(ar->arNetDev, IWEVCUSTOM, &wrqu, buf);
-#endif /* WIRELESS_EXT >= 18 */
- }
-}
-
-void
-ar6000_tkip_micerr_event(struct ar6_softc *ar, u8 keyid, bool ismcast)
-{
- static const char *tag = "MLME-MICHAELMICFAILURE.indication";
- char buf[128];
- union iwreq_data wrqu;
-
- /*
- * For AP case, keyid will have aid of STA which sent pkt with
- * MIC error. Use this aid to get MAC & send it to hostapd.
- */
- if (ar->arNetworkType == AP_NETWORK) {
- sta_t *s = ieee80211_find_conn_for_aid(ar, (keyid >> 2));
- if(!s){
- A_PRINTF("AP TKIP MIC error received from Invalid aid / STA not found =%d\n", keyid);
- return;
- }
- A_PRINTF("AP TKIP MIC error received from aid=%d\n", keyid);
- snprintf(buf,sizeof(buf), "%s addr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
- tag, s->mac[0],s->mac[1],s->mac[2],s->mac[3],s->mac[4],s->mac[5]);
- } else {
-
- ar6k_cfg80211_tkip_micerr_event(ar, keyid, ismcast);
-
- A_PRINTF("AR6000 TKIP MIC error received for keyid %d %scast\n",
- keyid & 0x3, ismcast ? "multi": "uni");
- snprintf(buf, sizeof(buf), "%s(keyid=%d %sicast)", tag, keyid & 0x3,
- ismcast ? "mult" : "un");
- }
-
- memset(&wrqu, 0, sizeof(wrqu));
- wrqu.data.length = strlen(buf);
- wireless_send_event(ar->arNetDev, IWEVCUSTOM, &wrqu, buf);
-}
-
-void
-ar6000_scanComplete_event(struct ar6_softc *ar, int status)
-{
-
- ar6k_cfg80211_scanComplete_event(ar, status);
-
- if (!ar->arUserBssFilter) {
- wmi_bssfilter_cmd(ar->arWmi, NONE_BSS_FILTER, 0);
- }
- if (ar->scan_triggered) {
- if (status== 0) {
- union iwreq_data wrqu;
- A_MEMZERO(&wrqu, sizeof(wrqu));
- wireless_send_event(ar->arNetDev, SIOCGIWSCAN, &wrqu, NULL);
- }
- ar->scan_triggered = 0;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_SCAN,( "AR6000 scan complete: %d\n", status));
-}
-
-void
-ar6000_targetStats_event(struct ar6_softc *ar, u8 *ptr, u32 len)
-{
- u8 ac;
-
- if(ar->arNetworkType == AP_NETWORK) {
- WMI_AP_MODE_STAT *p = (WMI_AP_MODE_STAT *)ptr;
- WMI_AP_MODE_STAT *ap = &ar->arAPStats;
-
- if (len < sizeof(*p)) {
- return;
- }
-
- for(ac=0;ac<AP_MAX_NUM_STA;ac++) {
- ap->sta[ac].tx_bytes += p->sta[ac].tx_bytes;
- ap->sta[ac].tx_pkts += p->sta[ac].tx_pkts;
- ap->sta[ac].tx_error += p->sta[ac].tx_error;
- ap->sta[ac].tx_discard += p->sta[ac].tx_discard;
- ap->sta[ac].rx_bytes += p->sta[ac].rx_bytes;
- ap->sta[ac].rx_pkts += p->sta[ac].rx_pkts;
- ap->sta[ac].rx_error += p->sta[ac].rx_error;
- ap->sta[ac].rx_discard += p->sta[ac].rx_discard;
- }
-
- } else {
- WMI_TARGET_STATS *pTarget = (WMI_TARGET_STATS *)ptr;
- TARGET_STATS *pStats = &ar->arTargetStats;
-
- if (len < sizeof(*pTarget)) {
- return;
- }
-
- // Update the RSSI of the connected bss.
- if (ar->arConnected) {
- bss_t *pConnBss = NULL;
-
- pConnBss = wmi_find_node(ar->arWmi,ar->arBssid);
- if (pConnBss)
- {
- pConnBss->ni_rssi = pTarget->cservStats.cs_aveBeacon_rssi;
- pConnBss->ni_snr = pTarget->cservStats.cs_aveBeacon_snr;
- wmi_node_return(ar->arWmi, pConnBss);
- }
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR6000 updating target stats\n"));
- pStats->tx_packets += pTarget->txrxStats.tx_stats.tx_packets;
- pStats->tx_bytes += pTarget->txrxStats.tx_stats.tx_bytes;
- pStats->tx_unicast_pkts += pTarget->txrxStats.tx_stats.tx_unicast_pkts;
- pStats->tx_unicast_bytes += pTarget->txrxStats.tx_stats.tx_unicast_bytes;
- pStats->tx_multicast_pkts += pTarget->txrxStats.tx_stats.tx_multicast_pkts;
- pStats->tx_multicast_bytes += pTarget->txrxStats.tx_stats.tx_multicast_bytes;
- pStats->tx_broadcast_pkts += pTarget->txrxStats.tx_stats.tx_broadcast_pkts;
- pStats->tx_broadcast_bytes += pTarget->txrxStats.tx_stats.tx_broadcast_bytes;
- pStats->tx_rts_success_cnt += pTarget->txrxStats.tx_stats.tx_rts_success_cnt;
- for(ac = 0; ac < WMM_NUM_AC; ac++)
- pStats->tx_packet_per_ac[ac] += pTarget->txrxStats.tx_stats.tx_packet_per_ac[ac];
- pStats->tx_errors += pTarget->txrxStats.tx_stats.tx_errors;
- pStats->tx_failed_cnt += pTarget->txrxStats.tx_stats.tx_failed_cnt;
- pStats->tx_retry_cnt += pTarget->txrxStats.tx_stats.tx_retry_cnt;
- pStats->tx_mult_retry_cnt += pTarget->txrxStats.tx_stats.tx_mult_retry_cnt;
- pStats->tx_rts_fail_cnt += pTarget->txrxStats.tx_stats.tx_rts_fail_cnt;
- pStats->tx_unicast_rate = wmi_get_rate(pTarget->txrxStats.tx_stats.tx_unicast_rate);
-
- pStats->rx_packets += pTarget->txrxStats.rx_stats.rx_packets;
- pStats->rx_bytes += pTarget->txrxStats.rx_stats.rx_bytes;
- pStats->rx_unicast_pkts += pTarget->txrxStats.rx_stats.rx_unicast_pkts;
- pStats->rx_unicast_bytes += pTarget->txrxStats.rx_stats.rx_unicast_bytes;
- pStats->rx_multicast_pkts += pTarget->txrxStats.rx_stats.rx_multicast_pkts;
- pStats->rx_multicast_bytes += pTarget->txrxStats.rx_stats.rx_multicast_bytes;
- pStats->rx_broadcast_pkts += pTarget->txrxStats.rx_stats.rx_broadcast_pkts;
- pStats->rx_broadcast_bytes += pTarget->txrxStats.rx_stats.rx_broadcast_bytes;
- pStats->rx_fragment_pkt += pTarget->txrxStats.rx_stats.rx_fragment_pkt;
- pStats->rx_errors += pTarget->txrxStats.rx_stats.rx_errors;
- pStats->rx_crcerr += pTarget->txrxStats.rx_stats.rx_crcerr;
- pStats->rx_key_cache_miss += pTarget->txrxStats.rx_stats.rx_key_cache_miss;
- pStats->rx_decrypt_err += pTarget->txrxStats.rx_stats.rx_decrypt_err;
- pStats->rx_duplicate_frames += pTarget->txrxStats.rx_stats.rx_duplicate_frames;
- pStats->rx_unicast_rate = wmi_get_rate(pTarget->txrxStats.rx_stats.rx_unicast_rate);
-
-
- pStats->tkip_local_mic_failure
- += pTarget->txrxStats.tkipCcmpStats.tkip_local_mic_failure;
- pStats->tkip_counter_measures_invoked
- += pTarget->txrxStats.tkipCcmpStats.tkip_counter_measures_invoked;
- pStats->tkip_replays += pTarget->txrxStats.tkipCcmpStats.tkip_replays;
- pStats->tkip_format_errors += pTarget->txrxStats.tkipCcmpStats.tkip_format_errors;
- pStats->ccmp_format_errors += pTarget->txrxStats.tkipCcmpStats.ccmp_format_errors;
- pStats->ccmp_replays += pTarget->txrxStats.tkipCcmpStats.ccmp_replays;
-
- pStats->power_save_failure_cnt += pTarget->pmStats.power_save_failure_cnt;
- pStats->noise_floor_calibation = pTarget->noise_floor_calibation;
-
- pStats->cs_bmiss_cnt += pTarget->cservStats.cs_bmiss_cnt;
- pStats->cs_lowRssi_cnt += pTarget->cservStats.cs_lowRssi_cnt;
- pStats->cs_connect_cnt += pTarget->cservStats.cs_connect_cnt;
- pStats->cs_disconnect_cnt += pTarget->cservStats.cs_disconnect_cnt;
- pStats->cs_aveBeacon_snr = pTarget->cservStats.cs_aveBeacon_snr;
- pStats->cs_aveBeacon_rssi = pTarget->cservStats.cs_aveBeacon_rssi;
-
- if (enablerssicompensation) {
- pStats->cs_aveBeacon_rssi =
- rssi_compensation_calc(ar, pStats->cs_aveBeacon_rssi);
- }
- pStats->cs_lastRoam_msec = pTarget->cservStats.cs_lastRoam_msec;
- pStats->cs_snr = pTarget->cservStats.cs_snr;
- pStats->cs_rssi = pTarget->cservStats.cs_rssi;
-
- pStats->lq_val = pTarget->lqVal;
-
- pStats->wow_num_pkts_dropped += pTarget->wowStats.wow_num_pkts_dropped;
- pStats->wow_num_host_pkt_wakeups += pTarget->wowStats.wow_num_host_pkt_wakeups;
- pStats->wow_num_host_event_wakeups += pTarget->wowStats.wow_num_host_event_wakeups;
- pStats->wow_num_events_discarded += pTarget->wowStats.wow_num_events_discarded;
- pStats->arp_received += pTarget->arpStats.arp_received;
- pStats->arp_matched += pTarget->arpStats.arp_matched;
- pStats->arp_replied += pTarget->arpStats.arp_replied;
-
- if (ar->statsUpdatePending) {
- ar->statsUpdatePending = false;
- wake_up(&arEvent);
- }
- }
-}
-
-void
-ar6000_rssiThreshold_event(struct ar6_softc *ar, WMI_RSSI_THRESHOLD_VAL newThreshold, s16 rssi)
-{
- USER_RSSI_THOLD userRssiThold;
-
- rssi = rssi + SIGNAL_QUALITY_NOISE_FLOOR;
-
- if (enablerssicompensation) {
- rssi = rssi_compensation_calc(ar, rssi);
- }
-
- /* Send an event to the app */
- userRssiThold.tag = ar->rssi_map[newThreshold].tag;
- userRssiThold.rssi = rssi;
- A_PRINTF("rssi Threshold range = %d tag = %d rssi = %d\n", newThreshold,
- userRssiThold.tag, userRssiThold.rssi);
-}
-
-
-void
-ar6000_hbChallengeResp_event(struct ar6_softc *ar, u32 cookie, u32 source)
-{
- if (source != APP_HB_CHALLENGE) {
- /* This would ignore the replys that come in after their due time */
- if (cookie == ar->arHBChallengeResp.seqNum) {
- ar->arHBChallengeResp.outstanding = false;
- }
- }
-}
-
-
-void
-ar6000_reportError_event(struct ar6_softc *ar, WMI_TARGET_ERROR_VAL errorVal)
-{
- static const char * const errString[] = {
- [WMI_TARGET_PM_ERR_FAIL] "WMI_TARGET_PM_ERR_FAIL",
- [WMI_TARGET_KEY_NOT_FOUND] "WMI_TARGET_KEY_NOT_FOUND",
- [WMI_TARGET_DECRYPTION_ERR] "WMI_TARGET_DECRYPTION_ERR",
- [WMI_TARGET_BMISS] "WMI_TARGET_BMISS",
- [WMI_PSDISABLE_NODE_JOIN] "WMI_PSDISABLE_NODE_JOIN"
- };
-
- A_PRINTF("AR6000 Error on Target. Error = 0x%x\n", errorVal);
-
- /* One error is reported at a time, and errorval is a bitmask */
- if(errorVal & (errorVal - 1))
- return;
-
- A_PRINTF("AR6000 Error type = ");
- switch(errorVal)
- {
- case WMI_TARGET_PM_ERR_FAIL:
- case WMI_TARGET_KEY_NOT_FOUND:
- case WMI_TARGET_DECRYPTION_ERR:
- case WMI_TARGET_BMISS:
- case WMI_PSDISABLE_NODE_JOIN:
- A_PRINTF("%s\n", errString[errorVal]);
- break;
- default:
- A_PRINTF("INVALID\n");
- break;
- }
-
-}
-
-
-void
-ar6000_cac_event(struct ar6_softc *ar, u8 ac, u8 cacIndication,
- u8 statusCode, u8 *tspecSuggestion)
-{
- WMM_TSPEC_IE *tspecIe;
-
- /*
- * This is the TSPEC IE suggestion from AP.
- * Suggestion provided by AP under some error
- * cases, could be helpful for the host app.
- * Check documentation.
- */
- tspecIe = (WMM_TSPEC_IE *)tspecSuggestion;
-
- /*
- * What do we do, if we get TSPEC rejection? One thought
- * that comes to mind is implictly delete the pstream...
- */
- A_PRINTF("AR6000 CAC notification. "
- "AC = %d, cacIndication = 0x%x, statusCode = 0x%x\n",
- ac, cacIndication, statusCode);
-}
-
-void
-ar6000_channel_change_event(struct ar6_softc *ar, u16 oldChannel,
- u16 newChannel)
-{
- A_PRINTF("Channel Change notification\nOld Channel: %d, New Channel: %d\n",
- oldChannel, newChannel);
-}
-
-#define AR6000_PRINT_BSSID(_pBss) do { \
- A_PRINTF("%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x ",\
- (_pBss)[0],(_pBss)[1],(_pBss)[2],(_pBss)[3],\
- (_pBss)[4],(_pBss)[5]); \
-} while(0)
-
-void
-ar6000_roam_tbl_event(struct ar6_softc *ar, WMI_TARGET_ROAM_TBL *pTbl)
-{
- u8 i;
-
- A_PRINTF("ROAM TABLE NO OF ENTRIES is %d ROAM MODE is %d\n",
- pTbl->numEntries, pTbl->roamMode);
- for (i= 0; i < pTbl->numEntries; i++) {
- A_PRINTF("[%d]bssid %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x ", i,
- pTbl->bssRoamInfo[i].bssid[0], pTbl->bssRoamInfo[i].bssid[1],
- pTbl->bssRoamInfo[i].bssid[2],
- pTbl->bssRoamInfo[i].bssid[3],
- pTbl->bssRoamInfo[i].bssid[4],
- pTbl->bssRoamInfo[i].bssid[5]);
- A_PRINTF("RSSI %d RSSIDT %d LAST RSSI %d UTIL %d ROAM_UTIL %d"
- " BIAS %d\n",
- pTbl->bssRoamInfo[i].rssi,
- pTbl->bssRoamInfo[i].rssidt,
- pTbl->bssRoamInfo[i].last_rssi,
- pTbl->bssRoamInfo[i].util,
- pTbl->bssRoamInfo[i].roam_util,
- pTbl->bssRoamInfo[i].bias);
- }
-}
-
-void
-ar6000_wow_list_event(struct ar6_softc *ar, u8 num_filters, WMI_GET_WOW_LIST_REPLY *wow_reply)
-{
- u8 i,j;
-
- /*Each event now contains exactly one filter, see bug 26613*/
- A_PRINTF("WOW pattern %d of %d patterns\n", wow_reply->this_filter_num, wow_reply->num_filters);
- A_PRINTF("wow mode = %s host mode = %s\n",
- (wow_reply->wow_mode == 0? "disabled":"enabled"),
- (wow_reply->host_mode == 1 ? "awake":"asleep"));
-
-
- /*If there are no patterns, the reply will only contain generic
- WoW information. Pattern information will exist only if there are
- patterns present. Bug 26716*/
-
- /* If this event contains pattern information, display it*/
- if (wow_reply->this_filter_num) {
- i=0;
- A_PRINTF("id=%d size=%d offset=%d\n",
- wow_reply->wow_filters[i].wow_filter_id,
- wow_reply->wow_filters[i].wow_filter_size,
- wow_reply->wow_filters[i].wow_filter_offset);
- A_PRINTF("wow pattern = ");
- for (j=0; j< wow_reply->wow_filters[i].wow_filter_size; j++) {
- A_PRINTF("%2.2x",wow_reply->wow_filters[i].wow_filter_pattern[j]);
- }
-
- A_PRINTF("\nwow mask = ");
- for (j=0; j< wow_reply->wow_filters[i].wow_filter_size; j++) {
- A_PRINTF("%2.2x",wow_reply->wow_filters[i].wow_filter_mask[j]);
- }
- A_PRINTF("\n");
- }
-}
-
-/*
- * Report the Roaming related data collected on the target
- */
-void
-ar6000_display_roam_time(WMI_TARGET_ROAM_TIME *p)
-{
- A_PRINTF("Disconnect Data : BSSID: ");
- AR6000_PRINT_BSSID(p->disassoc_bssid);
- A_PRINTF(" RSSI %d DISASSOC Time %d NO_TXRX_TIME %d\n",
- p->disassoc_bss_rssi,p->disassoc_time,
- p->no_txrx_time);
- A_PRINTF("Connect Data: BSSID: ");
- AR6000_PRINT_BSSID(p->assoc_bssid);
- A_PRINTF(" RSSI %d ASSOC Time %d TXRX_TIME %d\n",
- p->assoc_bss_rssi,p->assoc_time,
- p->allow_txrx_time);
-}
-
-void
-ar6000_roam_data_event(struct ar6_softc *ar, WMI_TARGET_ROAM_DATA *p)
-{
- switch (p->roamDataType) {
- case ROAM_DATA_TIME:
- ar6000_display_roam_time(&p->u.roamTime);
- break;
- default:
- break;
- }
-}
-
-void
-ar6000_bssInfo_event_rx(struct ar6_softc *ar, u8 *datap, int len)
-{
- struct sk_buff *skb;
- WMI_BSS_INFO_HDR *bih = (WMI_BSS_INFO_HDR *)datap;
-
-
- if (!ar->arMgmtFilter) {
- return;
- }
- if (((ar->arMgmtFilter & IEEE80211_FILTER_TYPE_BEACON) &&
- (bih->frameType != BEACON_FTYPE)) ||
- ((ar->arMgmtFilter & IEEE80211_FILTER_TYPE_PROBE_RESP) &&
- (bih->frameType != PROBERESP_FTYPE)))
- {
- return;
- }
-
- if ((skb = A_NETBUF_ALLOC_RAW(len)) != NULL) {
-
- A_NETBUF_PUT(skb, len);
- memcpy(A_NETBUF_DATA(skb), datap, len);
- skb->dev = ar->arNetDev;
- memcpy(skb_mac_header(skb), A_NETBUF_DATA(skb), 6);
- skb->ip_summed = CHECKSUM_NONE;
- skb->pkt_type = PACKET_OTHERHOST;
- skb->protocol = __constant_htons(0x0019);
- netif_rx(skb);
- }
-}
-
-u32 wmiSendCmdNum;
-
-int
-ar6000_control_tx(void *devt, void *osbuf, HTC_ENDPOINT_ID eid)
-{
- struct ar6_softc *ar = (struct ar6_softc *)devt;
- int status = 0;
- struct ar_cookie *cookie = NULL;
- int i;
-#ifdef CONFIG_PM
- if (ar->arWowState != WLAN_WOW_STATE_NONE) {
- A_NETBUF_FREE(osbuf);
- return A_EACCES;
- }
-#endif /* CONFIG_PM */
- /* take lock to protect ar6000_alloc_cookie() */
- AR6000_SPIN_LOCK(&ar->arLock, 0);
-
- do {
-
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_TX,("ar_contrstatus = ol_tx: skb=0x%lx, len=0x%x eid =%d\n",
- (unsigned long)osbuf, A_NETBUF_LEN(osbuf), eid));
-
- if (ar->arWMIControlEpFull && (eid == ar->arControlEp)) {
- /* control endpoint is full, don't allocate resources, we
- * are just going to drop this packet */
- cookie = NULL;
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" WMI Control EP full, dropping packet : 0x%lX, len:%d \n",
- (unsigned long)osbuf, A_NETBUF_LEN(osbuf)));
- } else {
- cookie = ar6000_alloc_cookie(ar);
- }
-
- if (cookie == NULL) {
- status = A_NO_MEMORY;
- break;
- }
-
- if(logWmiRawMsgs) {
- A_PRINTF("WMI cmd send, msgNo %d :", wmiSendCmdNum);
- for(i = 0; i < a_netbuf_to_len(osbuf); i++)
- A_PRINTF("%x ", ((u8 *)a_netbuf_to_data(osbuf))[i]);
- A_PRINTF("\n");
- }
-
- wmiSendCmdNum++;
-
- } while (false);
-
- if (cookie != NULL) {
- /* got a structure to send it out on */
- ar->arTxPending[eid]++;
-
- if (eid != ar->arControlEp) {
- ar->arTotalTxDataPending++;
- }
- }
-
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
-
- if (cookie != NULL) {
- cookie->arc_bp[0] = (unsigned long)osbuf;
- cookie->arc_bp[1] = 0;
- SET_HTC_PACKET_INFO_TX(&cookie->HtcPkt,
- cookie,
- A_NETBUF_DATA(osbuf),
- A_NETBUF_LEN(osbuf),
- eid,
- AR6K_CONTROL_PKT_TAG);
- /* this interface is asynchronous, if there is an error, cleanup will happen in the
- * TX completion callback */
- HTCSendPkt(ar->arHtcTarget, &cookie->HtcPkt);
- status = 0;
- }
-
- if (status) {
- A_NETBUF_FREE(osbuf);
- }
- return status;
-}
-
-/* indicate tx activity or inactivity on a WMI stream */
-void ar6000_indicate_tx_activity(void *devt, u8 TrafficClass, bool Active)
-{
- struct ar6_softc *ar = (struct ar6_softc *)devt;
- HTC_ENDPOINT_ID eid ;
- int i;
-
- if (ar->arWmiEnabled) {
- eid = arAc2EndpointID(ar, TrafficClass);
-
- AR6000_SPIN_LOCK(&ar->arLock, 0);
-
- ar->arAcStreamActive[TrafficClass] = Active;
-
- if (Active) {
- /* when a stream goes active, keep track of the active stream with the highest priority */
-
- if (ar->arAcStreamPriMap[TrafficClass] > ar->arHiAcStreamActivePri) {
- /* set the new highest active priority */
- ar->arHiAcStreamActivePri = ar->arAcStreamPriMap[TrafficClass];
- }
-
- } else {
- /* when a stream goes inactive, we may have to search for the next active stream
- * that is the highest priority */
-
- if (ar->arHiAcStreamActivePri == ar->arAcStreamPriMap[TrafficClass]) {
-
- /* the highest priority stream just went inactive */
-
- /* reset and search for the "next" highest "active" priority stream */
- ar->arHiAcStreamActivePri = 0;
- for (i = 0; i < WMM_NUM_AC; i++) {
- if (ar->arAcStreamActive[i]) {
- if (ar->arAcStreamPriMap[i] > ar->arHiAcStreamActivePri) {
- /* set the new highest active priority */
- ar->arHiAcStreamActivePri = ar->arAcStreamPriMap[i];
- }
- }
- }
- }
- }
-
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
-
- } else {
- /* for mbox ping testing, the traffic class is mapped directly as a stream ID,
- * see handling of AR6000_XIOCTL_TRAFFIC_ACTIVITY_CHANGE in ioctl.c
- * convert the stream ID to a endpoint */
- eid = arAc2EndpointID(ar, TrafficClass);
- }
-
- /* notify HTC, this may cause credit distribution changes */
-
- HTCIndicateActivityChange(ar->arHtcTarget,
- eid,
- Active);
-
-}
-
-void
-ar6000_btcoex_config_event(struct ar6_softc *ar, u8 *ptr, u32 len)
-{
-
- WMI_BTCOEX_CONFIG_EVENT *pBtcoexConfig = (WMI_BTCOEX_CONFIG_EVENT *)ptr;
- WMI_BTCOEX_CONFIG_EVENT *pArbtcoexConfig =&ar->arBtcoexConfig;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR6000 BTCOEX CONFIG EVENT \n"));
-
- A_PRINTF("received config event\n");
- pArbtcoexConfig->btProfileType = pBtcoexConfig->btProfileType;
- pArbtcoexConfig->linkId = pBtcoexConfig->linkId;
-
- switch (pBtcoexConfig->btProfileType) {
- case WMI_BTCOEX_BT_PROFILE_SCO:
- memcpy(&pArbtcoexConfig->info.scoConfigCmd, &pBtcoexConfig->info.scoConfigCmd,
- sizeof(WMI_SET_BTCOEX_SCO_CONFIG_CMD));
- break;
- case WMI_BTCOEX_BT_PROFILE_A2DP:
- memcpy(&pArbtcoexConfig->info.a2dpConfigCmd, &pBtcoexConfig->info.a2dpConfigCmd,
- sizeof(WMI_SET_BTCOEX_A2DP_CONFIG_CMD));
- break;
- case WMI_BTCOEX_BT_PROFILE_ACLCOEX:
- memcpy(&pArbtcoexConfig->info.aclcoexConfig, &pBtcoexConfig->info.aclcoexConfig,
- sizeof(WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMD));
- break;
- case WMI_BTCOEX_BT_PROFILE_INQUIRY_PAGE:
- memcpy(&pArbtcoexConfig->info.btinquiryPageConfigCmd, &pBtcoexConfig->info.btinquiryPageConfigCmd,
- sizeof(WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMD));
- break;
- }
- if (ar->statsUpdatePending) {
- ar->statsUpdatePending = false;
- wake_up(&arEvent);
- }
-}
-
-void
-ar6000_btcoex_stats_event(struct ar6_softc *ar, u8 *ptr, u32 len)
-{
- WMI_BTCOEX_STATS_EVENT *pBtcoexStats = (WMI_BTCOEX_STATS_EVENT *)ptr;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR6000 BTCOEX CONFIG EVENT \n"));
-
- memcpy(&ar->arBtcoexStats, pBtcoexStats, sizeof(WMI_BTCOEX_STATS_EVENT));
-
- if (ar->statsUpdatePending) {
- ar->statsUpdatePending = false;
- wake_up(&arEvent);
- }
-
-}
-module_init(ar6000_init_module);
-module_exit(ar6000_cleanup_module);
-
-/* Init cookie queue */
-static void
-ar6000_cookie_init(struct ar6_softc *ar)
-{
- u32 i;
-
- ar->arCookieList = NULL;
- ar->arCookieCount = 0;
-
- A_MEMZERO(s_ar_cookie_mem, sizeof(s_ar_cookie_mem));
-
- for (i = 0; i < MAX_COOKIE_NUM; i++) {
- ar6000_free_cookie(ar, &s_ar_cookie_mem[i]);
- }
-}
-
-/* cleanup cookie queue */
-static void
-ar6000_cookie_cleanup(struct ar6_softc *ar)
-{
- /* It is gone .... */
- ar->arCookieList = NULL;
- ar->arCookieCount = 0;
-}
-
-/* Init cookie queue */
-static void
-ar6000_free_cookie(struct ar6_softc *ar, struct ar_cookie * cookie)
-{
- /* Insert first */
- A_ASSERT(ar != NULL);
- A_ASSERT(cookie != NULL);
-
- cookie->arc_list_next = ar->arCookieList;
- ar->arCookieList = cookie;
- ar->arCookieCount++;
-}
-
-/* cleanup cookie queue */
-static struct ar_cookie *
-ar6000_alloc_cookie(struct ar6_softc *ar)
-{
- struct ar_cookie *cookie;
-
- cookie = ar->arCookieList;
- if(cookie != NULL)
- {
- ar->arCookieList = cookie->arc_list_next;
- ar->arCookieCount--;
- }
-
- return cookie;
-}
-
-void
-ar6000_tx_retry_err_event(void *devt)
-{
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Tx retries reach maximum!\n"));
-}
-
-void
-ar6000_snrThresholdEvent_rx(void *devt, WMI_SNR_THRESHOLD_VAL newThreshold, u8 snr)
-{
- WMI_SNR_THRESHOLD_EVENT event;
-
- event.range = newThreshold;
- event.snr = snr;
-}
-
-void
-ar6000_lqThresholdEvent_rx(void *devt, WMI_LQ_THRESHOLD_VAL newThreshold, u8 lq)
-{
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("lq threshold range %d, lq %d\n", newThreshold, lq));
-}
-
-
-
-u32 a_copy_to_user(void *to, const void *from, u32 n)
-{
- return(copy_to_user(to, from, n));
-}
-
-u32 a_copy_from_user(void *to, const void *from, u32 n)
-{
- return(copy_from_user(to, from, n));
-}
-
-
-int
-ar6000_get_driver_cfg(struct net_device *dev,
- u16 cfgParam,
- void *result)
-{
-
- int ret = 0;
-
- switch(cfgParam)
- {
- case AR6000_DRIVER_CFG_GET_WLANNODECACHING:
- *((u32 *)result) = wlanNodeCaching;
- break;
- case AR6000_DRIVER_CFG_LOG_RAW_WMI_MSGS:
- *((u32 *)result) = logWmiRawMsgs;
- break;
- default:
- ret = EINVAL;
- break;
- }
-
- return ret;
-}
-
-void
-ar6000_keepalive_rx(void *devt, u8 configured)
-{
- struct ar6_softc *ar = (struct ar6_softc *)devt;
-
- ar->arKeepaliveConfigured = configured;
- wake_up(&arEvent);
-}
-
-void
-ar6000_pmkid_list_event(void *devt, u8 numPMKID, WMI_PMKID *pmkidList,
- u8 *bssidList)
-{
- u8 i, j;
-
- A_PRINTF("Number of Cached PMKIDs is %d\n", numPMKID);
-
- for (i = 0; i < numPMKID; i++) {
- A_PRINTF("\nBSSID %d ", i);
- for (j = 0; j < ATH_MAC_LEN; j++) {
- A_PRINTF("%2.2x", bssidList[j]);
- }
- bssidList += (ATH_MAC_LEN + WMI_PMKID_LEN);
- A_PRINTF("\nPMKID %d ", i);
- for (j = 0; j < WMI_PMKID_LEN; j++) {
- A_PRINTF("%2.2x", pmkidList->pmkid[j]);
- }
- pmkidList = (WMI_PMKID *)((u8 *)pmkidList + ATH_MAC_LEN +
- WMI_PMKID_LEN);
- }
-}
-
-void ar6000_pspoll_event(struct ar6_softc *ar,u8 aid)
-{
- sta_t *conn=NULL;
- bool isPsqEmpty = false;
-
- conn = ieee80211_find_conn_for_aid(ar, aid);
-
- /* If the PS q for this STA is not empty, dequeue and send a pkt from
- * the head of the q. Also update the More data bit in the WMI_DATA_HDR
- * if there are more pkts for this STA in the PS q. If there are no more
- * pkts for this STA, update the PVB for this STA.
- */
- A_MUTEX_LOCK(&conn->psqLock);
- isPsqEmpty = A_NETBUF_QUEUE_EMPTY(&conn->psq);
- A_MUTEX_UNLOCK(&conn->psqLock);
-
- if (isPsqEmpty) {
- /* TODO:No buffered pkts for this STA. Send out a NULL data frame */
- } else {
- struct sk_buff *skb = NULL;
-
- A_MUTEX_LOCK(&conn->psqLock);
- skb = A_NETBUF_DEQUEUE(&conn->psq);
- A_MUTEX_UNLOCK(&conn->psqLock);
- /* Set the STA flag to PSPolled, so that the frame will go out */
- STA_SET_PS_POLLED(conn);
- ar6000_data_tx(skb, ar->arNetDev);
- STA_CLR_PS_POLLED(conn);
-
- /* Clear the PVB for this STA if the queue has become empty */
- A_MUTEX_LOCK(&conn->psqLock);
- isPsqEmpty = A_NETBUF_QUEUE_EMPTY(&conn->psq);
- A_MUTEX_UNLOCK(&conn->psqLock);
-
- if (isPsqEmpty) {
- wmi_set_pvb_cmd(ar->arWmi, conn->aid, 0);
- }
- }
-}
-
-void ar6000_dtimexpiry_event(struct ar6_softc *ar)
-{
- bool isMcastQueued = false;
- struct sk_buff *skb = NULL;
-
- /* If there are no associated STAs, ignore the DTIM expiry event.
- * There can be potential race conditions where the last associated
- * STA may disconnect & before the host could clear the 'Indicate DTIM'
- * request to the firmware, the firmware would have just indicated a DTIM
- * expiry event. The race is between 'clear DTIM expiry cmd' going
- * from the host to the firmware & the DTIM expiry event happening from
- * the firmware to the host.
- */
- if (ar->sta_list_index == 0) {
- return;
- }
-
- A_MUTEX_LOCK(&ar->mcastpsqLock);
- isMcastQueued = A_NETBUF_QUEUE_EMPTY(&ar->mcastpsq);
- A_MUTEX_UNLOCK(&ar->mcastpsqLock);
-
- A_ASSERT(isMcastQueued == false);
-
- /* Flush the mcast psq to the target */
- /* Set the STA flag to DTIMExpired, so that the frame will go out */
- ar->DTIMExpired = true;
-
- A_MUTEX_LOCK(&ar->mcastpsqLock);
- while (!A_NETBUF_QUEUE_EMPTY(&ar->mcastpsq)) {
- skb = A_NETBUF_DEQUEUE(&ar->mcastpsq);
- A_MUTEX_UNLOCK(&ar->mcastpsqLock);
-
- ar6000_data_tx(skb, ar->arNetDev);
-
- A_MUTEX_LOCK(&ar->mcastpsqLock);
- }
- A_MUTEX_UNLOCK(&ar->mcastpsqLock);
-
- /* Reset the DTIMExpired flag back to 0 */
- ar->DTIMExpired = false;
-
- /* Clear the LSB of the BitMapCtl field of the TIM IE */
- wmi_set_pvb_cmd(ar->arWmi, MCAST_AID, 0);
-}
-
-void
-read_rssi_compensation_param(struct ar6_softc *ar)
-{
- u8 *cust_data_ptr;
-
-//#define RSSICOMPENSATION_PRINT
-
-#ifdef RSSICOMPENSATION_PRINT
- s16 i;
- cust_data_ptr = ar6000_get_cust_data_buffer(ar->arTargetType);
- for (i=0; i<16; i++) {
- A_PRINTF("cust_data_%d = %x \n", i, *(u8 *)cust_data_ptr);
- cust_data_ptr += 1;
- }
-#endif
-
- cust_data_ptr = ar6000_get_cust_data_buffer(ar->arTargetType);
-
- rssi_compensation_param.customerID = *(u16 *)cust_data_ptr & 0xffff;
- rssi_compensation_param.enable = *(u16 *)(cust_data_ptr+2) & 0xffff;
- rssi_compensation_param.bg_param_a = *(u16 *)(cust_data_ptr+4) & 0xffff;
- rssi_compensation_param.bg_param_b = *(u16 *)(cust_data_ptr+6) & 0xffff;
- rssi_compensation_param.a_param_a = *(u16 *)(cust_data_ptr+8) & 0xffff;
- rssi_compensation_param.a_param_b = *(u16 *)(cust_data_ptr+10) &0xffff;
- rssi_compensation_param.reserved = *(u32 *)(cust_data_ptr+12);
-
-#ifdef RSSICOMPENSATION_PRINT
- A_PRINTF("customerID = 0x%x \n", rssi_compensation_param.customerID);
- A_PRINTF("enable = 0x%x \n", rssi_compensation_param.enable);
- A_PRINTF("bg_param_a = 0x%x and %d \n", rssi_compensation_param.bg_param_a, rssi_compensation_param.bg_param_a);
- A_PRINTF("bg_param_b = 0x%x and %d \n", rssi_compensation_param.bg_param_b, rssi_compensation_param.bg_param_b);
- A_PRINTF("a_param_a = 0x%x and %d \n", rssi_compensation_param.a_param_a, rssi_compensation_param.a_param_a);
- A_PRINTF("a_param_b = 0x%x and %d \n", rssi_compensation_param.a_param_b, rssi_compensation_param.a_param_b);
- A_PRINTF("Last 4 bytes = 0x%x \n", rssi_compensation_param.reserved);
-#endif
-
- if (rssi_compensation_param.enable != 0x1) {
- rssi_compensation_param.enable = 0;
- }
-
- return;
-}
-
-s32 rssi_compensation_calc_tcmd(u32 freq, s32 rssi, u32 totalPkt)
-{
-
- if (freq > 5000)
- {
- if (rssi_compensation_param.enable)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, (">>> 11a\n"));
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("rssi before compensation = %d, totalPkt = %d\n", rssi,totalPkt));
- rssi = rssi * rssi_compensation_param.a_param_a + totalPkt * rssi_compensation_param.a_param_b;
- rssi = (rssi-50) /100;
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("rssi after compensation = %d\n", rssi));
- }
- }
- else
- {
- if (rssi_compensation_param.enable)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, (">>> 11bg\n"));
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("rssi before compensation = %d, totalPkt = %d\n", rssi,totalPkt));
- rssi = rssi * rssi_compensation_param.bg_param_a + totalPkt * rssi_compensation_param.bg_param_b;
- rssi = (rssi-50) /100;
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("rssi after compensation = %d\n", rssi));
- }
- }
-
- return rssi;
-}
-
-s16 rssi_compensation_calc(struct ar6_softc *ar, s16 rssi)
-{
- if (ar->arBssChannel > 5000)
- {
- if (rssi_compensation_param.enable)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, (">>> 11a\n"));
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("rssi before compensation = %d\n", rssi));
- rssi = rssi * rssi_compensation_param.a_param_a + rssi_compensation_param.a_param_b;
- rssi = (rssi-50) /100;
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("rssi after compensation = %d\n", rssi));
- }
- }
- else
- {
- if (rssi_compensation_param.enable)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, (">>> 11bg\n"));
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("rssi before compensation = %d\n", rssi));
- rssi = rssi * rssi_compensation_param.bg_param_a + rssi_compensation_param.bg_param_b;
- rssi = (rssi-50) /100;
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("rssi after compensation = %d\n", rssi));
- }
- }
-
- return rssi;
-}
-
-s16 rssi_compensation_reverse_calc(struct ar6_softc *ar, s16 rssi, bool Above)
-{
- s16 i;
-
- if (ar->arBssChannel > 5000)
- {
- if (rssi_compensation_param.enable)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, (">>> 11a\n"));
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("rssi before rev compensation = %d\n", rssi));
- rssi = rssi * 100;
- rssi = (rssi - rssi_compensation_param.a_param_b) / rssi_compensation_param.a_param_a;
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("rssi after rev compensation = %d\n", rssi));
- }
- }
- else
- {
- if (rssi_compensation_param.enable)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, (">>> 11bg\n"));
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("rssi before rev compensation = %d\n", rssi));
-
- if (Above) {
- for (i=95; i>=0; i--) {
- if (rssi <= rssi_compensation_table[i]) {
- rssi = 0 - i;
- break;
- }
- }
- } else {
- for (i=0; i<=95; i++) {
- if (rssi >= rssi_compensation_table[i]) {
- rssi = 0 - i;
- break;
- }
- }
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("rssi after rev compensation = %d\n", rssi));
- }
- }
-
- return rssi;
-}
-
-#ifdef WAPI_ENABLE
-void ap_wapi_rekey_event(struct ar6_softc *ar, u8 type, u8 *mac)
-{
- union iwreq_data wrqu;
- char buf[20];
-
- A_MEMZERO(buf, sizeof(buf));
-
- strcpy(buf, "WAPI_REKEY");
- buf[10] = type;
- memcpy(&buf[11], mac, ATH_MAC_LEN);
-
- A_MEMZERO(&wrqu, sizeof(wrqu));
- wrqu.data.length = 10+1+ATH_MAC_LEN;
- wireless_send_event(ar->arNetDev, IWEVCUSTOM, &wrqu, buf);
-
- A_PRINTF("WAPI REKEY - %d - %02x:%02x\n", type, mac[4], mac[5]);
-}
-#endif
-
-static int
-ar6000_reinstall_keys(struct ar6_softc *ar, u8 key_op_ctrl)
-{
- int status = 0;
- struct ieee80211req_key *uik = &ar->user_saved_keys.ucast_ik;
- struct ieee80211req_key *bik = &ar->user_saved_keys.bcast_ik;
- CRYPTO_TYPE keyType = ar->user_saved_keys.keyType;
-
- if (IEEE80211_CIPHER_CCKM_KRK != uik->ik_type) {
- if (NONE_CRYPT == keyType) {
- goto _reinstall_keys_out;
- }
-
- if (uik->ik_keylen) {
- status = wmi_addKey_cmd(ar->arWmi, uik->ik_keyix,
- ar->user_saved_keys.keyType, PAIRWISE_USAGE,
- uik->ik_keylen, (u8 *)&uik->ik_keyrsc,
- uik->ik_keydata, key_op_ctrl, uik->ik_macaddr, SYNC_BEFORE_WMIFLAG);
- }
-
- } else {
- status = wmi_add_krk_cmd(ar->arWmi, uik->ik_keydata);
- }
-
- if (IEEE80211_CIPHER_CCKM_KRK != bik->ik_type) {
- if (NONE_CRYPT == keyType) {
- goto _reinstall_keys_out;
- }
-
- if (bik->ik_keylen) {
- status = wmi_addKey_cmd(ar->arWmi, bik->ik_keyix,
- ar->user_saved_keys.keyType, GROUP_USAGE,
- bik->ik_keylen, (u8 *)&bik->ik_keyrsc,
- bik->ik_keydata, key_op_ctrl, bik->ik_macaddr, NO_SYNC_WMIFLAG);
- }
- } else {
- status = wmi_add_krk_cmd(ar->arWmi, bik->ik_keydata);
- }
-
-_reinstall_keys_out:
- ar->user_savedkeys_stat = USER_SAVEDKEYS_STAT_INIT;
- ar->user_key_ctrl = 0;
-
- return status;
-}
-
-
-void
-ar6000_dset_open_req(
- void *context,
- u32 id,
- u32 targHandle,
- u32 targReplyFn,
- u32 targReplyArg)
-{
-}
-
-void
-ar6000_dset_close(
- void *context,
- u32 access_cookie)
-{
- return;
-}
-
-void
-ar6000_dset_data_req(
- void *context,
- u32 accessCookie,
- u32 offset,
- u32 length,
- u32 targBuf,
- u32 targReplyFn,
- u32 targReplyArg)
-{
-}
-
-int
-ar6000_ap_mode_profile_commit(struct ar6_softc *ar)
-{
- WMI_CONNECT_CMD p;
- unsigned long flags;
-
- /* No change in AP's profile configuration */
- if(ar->ap_profile_flag==0) {
- A_PRINTF("COMMIT: No change in profile!!!\n");
- return -ENODATA;
- }
-
- if(!ar->arSsidLen) {
- A_PRINTF("SSID not set!!!\n");
- return -ECHRNG;
- }
-
- switch(ar->arAuthMode) {
- case NONE_AUTH:
- if((ar->arPairwiseCrypto != NONE_CRYPT) &&
-#ifdef WAPI_ENABLE
- (ar->arPairwiseCrypto != WAPI_CRYPT) &&
-#endif
- (ar->arPairwiseCrypto != WEP_CRYPT)) {
- A_PRINTF("Cipher not supported in AP mode Open auth\n");
- return -EOPNOTSUPP;
- }
- break;
- case WPA_PSK_AUTH:
- case WPA2_PSK_AUTH:
- case (WPA_PSK_AUTH|WPA2_PSK_AUTH):
- break;
- default:
- A_PRINTF("This key mgmt type not supported in AP mode\n");
- return -EOPNOTSUPP;
- }
-
- /* Update the arNetworkType */
- ar->arNetworkType = ar->arNextMode;
-
- A_MEMZERO(&p,sizeof(p));
- p.ssidLength = ar->arSsidLen;
- memcpy(p.ssid,ar->arSsid,p.ssidLength);
- p.channel = ar->arChannelHint;
- p.networkType = ar->arNetworkType;
-
- p.dot11AuthMode = ar->arDot11AuthMode;
- p.authMode = ar->arAuthMode;
- p.pairwiseCryptoType = ar->arPairwiseCrypto;
- p.pairwiseCryptoLen = ar->arPairwiseCryptoLen;
- p.groupCryptoType = ar->arGroupCrypto;
- p.groupCryptoLen = ar->arGroupCryptoLen;
- p.ctrl_flags = ar->arConnectCtrlFlags;
-
- wmi_ap_profile_commit(ar->arWmi, &p);
- spin_lock_irqsave(&ar->arLock, flags);
- ar->arConnected = true;
- netif_carrier_on(ar->arNetDev);
- spin_unlock_irqrestore(&ar->arLock, flags);
- ar->ap_profile_flag = 0;
- return 0;
-}
-
-int
-ar6000_connect_to_ap(struct ar6_softc *ar)
-{
- /* The ssid length check prevents second "essid off" from the user,
- to be treated as a connect cmd. The second "essid off" is ignored.
- */
- if((ar->arWmiReady == true) && (ar->arSsidLen > 0) && ar->arNetworkType!=AP_NETWORK)
- {
- int status;
- if((ADHOC_NETWORK != ar->arNetworkType) &&
- (NONE_AUTH==ar->arAuthMode) &&
- (WEP_CRYPT==ar->arPairwiseCrypto)) {
- ar6000_install_static_wep_keys(ar);
- }
-
- if (!ar->arUserBssFilter) {
- if (wmi_bssfilter_cmd(ar->arWmi, ALL_BSS_FILTER, 0) != 0) {
- return -EIO;
- }
- }
-#ifdef WAPI_ENABLE
- if (ar->arWapiEnable) {
- ar->arPairwiseCrypto = WAPI_CRYPT;
- ar->arPairwiseCryptoLen = 0;
- ar->arGroupCrypto = WAPI_CRYPT;
- ar->arGroupCryptoLen = 0;
- ar->arAuthMode = NONE_AUTH;
- ar->arConnectCtrlFlags |= CONNECT_IGNORE_WPAx_GROUP_CIPHER;
- }
-#endif
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_CONNECT,("Connect called with authmode %d dot11 auth %d"\
- " PW crypto %d PW crypto Len %d GRP crypto %d"\
- " GRP crypto Len %d\n",
- ar->arAuthMode, ar->arDot11AuthMode,
- ar->arPairwiseCrypto, ar->arPairwiseCryptoLen,
- ar->arGroupCrypto, ar->arGroupCryptoLen));
- reconnect_flag = 0;
- /* Set the listen interval into 1000TUs or more. This value will be indicated to Ap in the conn.
- later set it back locally at the STA to 100/1000 TUs depending on the power mode */
- if ((ar->arNetworkType == INFRA_NETWORK)) {
- wmi_listeninterval_cmd(ar->arWmi, max(ar->arListenIntervalT, (u16)A_MAX_WOW_LISTEN_INTERVAL), 0);
- }
- status = wmi_connect_cmd(ar->arWmi, ar->arNetworkType,
- ar->arDot11AuthMode, ar->arAuthMode,
- ar->arPairwiseCrypto, ar->arPairwiseCryptoLen,
- ar->arGroupCrypto,ar->arGroupCryptoLen,
- ar->arSsidLen, ar->arSsid,
- ar->arReqBssid, ar->arChannelHint,
- ar->arConnectCtrlFlags);
- if (status) {
- wmi_listeninterval_cmd(ar->arWmi, ar->arListenIntervalT, ar->arListenIntervalB);
- if (!ar->arUserBssFilter) {
- wmi_bssfilter_cmd(ar->arWmi, NONE_BSS_FILTER, 0);
- }
- return status;
- }
-
- if ((!(ar->arConnectCtrlFlags & CONNECT_DO_WPA_OFFLOAD)) &&
- ((WPA_PSK_AUTH == ar->arAuthMode) || (WPA2_PSK_AUTH == ar->arAuthMode)))
- {
- A_TIMEOUT_MS(&ar->disconnect_timer, A_DISCONNECT_TIMER_INTERVAL, 0);
- }
-
- ar->arConnectCtrlFlags &= ~CONNECT_DO_WPA_OFFLOAD;
-
- ar->arConnectPending = true;
- return status;
- }
- return A_ERROR;
-}
-
-int
-ar6000_disconnect(struct ar6_softc *ar)
-{
- if ((ar->arConnected == true) || (ar->arConnectPending == true)) {
- wmi_disconnect_cmd(ar->arWmi);
- /*
- * Disconnect cmd is issued, clear connectPending.
- * arConnected will be cleard in disconnect_event notification.
- */
- ar->arConnectPending = false;
- }
-
- return 0;
-}
-
-int
-ar6000_ap_mode_get_wpa_ie(struct ar6_softc *ar, struct ieee80211req_wpaie *wpaie)
-{
- sta_t *conn = NULL;
- conn = ieee80211_find_conn(ar, wpaie->wpa_macaddr);
-
- A_MEMZERO(wpaie->wpa_ie, IEEE80211_MAX_IE);
- A_MEMZERO(wpaie->rsn_ie, IEEE80211_MAX_IE);
-
- if(conn) {
- memcpy(wpaie->wpa_ie, conn->wpa_ie, IEEE80211_MAX_IE);
- }
-
- return 0;
-}
-
-int
-is_iwioctl_allowed(u8 mode, u16 cmd)
-{
- if(cmd >= SIOCSIWCOMMIT && cmd <= SIOCGIWPOWER) {
- cmd -= SIOCSIWCOMMIT;
- if(sioctl_filter[cmd] == 0xFF) return 0;
- if(sioctl_filter[cmd] & mode) return 0;
- } else if(cmd >= SIOCIWFIRSTPRIV && cmd <= (SIOCIWFIRSTPRIV+30)) {
- cmd -= SIOCIWFIRSTPRIV;
- if(pioctl_filter[cmd] == 0xFF) return 0;
- if(pioctl_filter[cmd] & mode) return 0;
- } else {
- return A_ERROR;
- }
- return A_ENOTSUP;
-}
-
-int
-is_xioctl_allowed(u8 mode, int cmd)
-{
- if(sizeof(xioctl_filter)-1 < cmd) {
- A_PRINTF("Filter for this cmd=%d not defined\n",cmd);
- return 0;
- }
- if(xioctl_filter[cmd] == 0xFF) return 0;
- if(xioctl_filter[cmd] & mode) return 0;
- return A_ERROR;
-}
-
-#ifdef WAPI_ENABLE
-int
-ap_set_wapi_key(struct ar6_softc *ar, void *ikey)
-{
- struct ieee80211req_key *ik = (struct ieee80211req_key *)ikey;
- KEY_USAGE keyUsage = 0;
- int status;
-
- if (memcmp(ik->ik_macaddr, bcast_mac, IEEE80211_ADDR_LEN) == 0) {
- keyUsage = GROUP_USAGE;
- } else {
- keyUsage = PAIRWISE_USAGE;
- }
- A_PRINTF("WAPI_KEY: Type:%d ix:%d mac:%02x:%02x len:%d\n",
- keyUsage, ik->ik_keyix, ik->ik_macaddr[4], ik->ik_macaddr[5],
- ik->ik_keylen);
-
- status = wmi_addKey_cmd(ar->arWmi, ik->ik_keyix, WAPI_CRYPT, keyUsage,
- ik->ik_keylen, (u8 *)&ik->ik_keyrsc,
- ik->ik_keydata, KEY_OP_INIT_VAL, ik->ik_macaddr,
- SYNC_BOTH_WMIFLAG);
-
- if (0 != status) {
- return -EIO;
- }
- return 0;
-}
-#endif
-
-void ar6000_peer_event(
- void *context,
- u8 eventCode,
- u8 *macAddr)
-{
- u8 pos;
-
- for (pos=0;pos<6;pos++)
- printk("%02x: ",*(macAddr+pos));
- printk("\n");
-}
-
-#ifdef HTC_TEST_SEND_PKTS
-#define HTC_TEST_DUPLICATE 8
-static void DoHTCSendPktsTest(struct ar6_softc *ar, int MapNo, HTC_ENDPOINT_ID eid, struct sk_buff *dupskb)
-{
- struct ar_cookie *cookie;
- struct ar_cookie *cookieArray[HTC_TEST_DUPLICATE];
- struct sk_buff *new_skb;
- int i;
- int pkts = 0;
- struct htc_packet_queue pktQueue;
- EPPING_HEADER *eppingHdr;
-
- eppingHdr = A_NETBUF_DATA(dupskb);
-
- if (eppingHdr->Cmd_h == EPPING_CMD_NO_ECHO) {
- /* skip test if this is already a tx perf test */
- return;
- }
-
- for (i = 0; i < HTC_TEST_DUPLICATE; i++,pkts++) {
- AR6000_SPIN_LOCK(&ar->arLock, 0);
- cookie = ar6000_alloc_cookie(ar);
- if (cookie != NULL) {
- ar->arTxPending[eid]++;
- ar->arTotalTxDataPending++;
- }
-
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
-
- if (NULL == cookie) {
- break;
- }
-
- new_skb = A_NETBUF_ALLOC(A_NETBUF_LEN(dupskb));
-
- if (new_skb == NULL) {
- AR6000_SPIN_LOCK(&ar->arLock, 0);
- ar6000_free_cookie(ar,cookie);
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
- break;
- }
-
- A_NETBUF_PUT_DATA(new_skb, A_NETBUF_DATA(dupskb), A_NETBUF_LEN(dupskb));
- cookie->arc_bp[0] = (unsigned long)new_skb;
- cookie->arc_bp[1] = MapNo;
- SET_HTC_PACKET_INFO_TX(&cookie->HtcPkt,
- cookie,
- A_NETBUF_DATA(new_skb),
- A_NETBUF_LEN(new_skb),
- eid,
- AR6K_DATA_PKT_TAG);
-
- cookieArray[i] = cookie;
-
- {
- EPPING_HEADER *pHdr = (EPPING_HEADER *)A_NETBUF_DATA(new_skb);
- pHdr->Cmd_h = EPPING_CMD_NO_ECHO; /* do not echo the packet */
- }
- }
-
- if (pkts == 0) {
- return;
- }
-
- INIT_HTC_PACKET_QUEUE(&pktQueue);
-
- for (i = 0; i < pkts; i++) {
- HTC_PACKET_ENQUEUE(&pktQueue,&cookieArray[i]->HtcPkt);
- }
-
- HTCSendPktsMultiple(ar->arHtcTarget, &pktQueue);
-
-}
-#endif
-
-#ifdef CONFIG_AP_VIRTUAL_ADAPTER_SUPPORT
-/*
- * Add support for adding and removing a virtual adapter for soft AP.
- * Some OS requires different adapters names for station and soft AP mode.
- * To support these requirement, create and destroy a netdevice instance
- * when the AP mode is operational. A full fledged support for virual device
- * is not implemented. Rather a virtual interface is created and is linked
- * with the existing physical device instance during the operation of the
- * AP mode.
- */
-
-int ar6000_start_ap_interface(struct ar6_softc *ar)
-{
- struct ar_virtual_interface *arApDev;
-
- /* Change net_device to point to AP instance */
- arApDev = (struct ar_virtual_interface *)ar->arApDev;
- ar->arNetDev = arApDev->arNetDev;
-
- return 0;
-}
-
-int ar6000_stop_ap_interface(struct ar6_softc *ar)
-{
- struct ar_virtual_interface *arApDev;
-
- /* Change net_device to point to sta instance */
- arApDev = (struct ar_virtual_interface *)ar->arApDev;
- if (arApDev) {
- ar->arNetDev = arApDev->arStaNetDev;
- }
-
- return 0;
-}
-
-
-int ar6000_create_ap_interface(struct ar6_softc *ar, char *ap_ifname)
-{
- struct net_device *dev;
- struct ar_virtual_interface *arApDev;
-
- dev = alloc_etherdev(sizeof(struct ar_virtual_interface));
- if (dev == NULL) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("ar6000_create_ap_interface: can't alloc etherdev\n"));
- return A_ERROR;
- }
-
- ether_setup(dev);
- init_netdev(dev, ap_ifname);
- dev->priv_flags &= ~IFF_TX_SKB_SHARING;
-
- if (register_netdev(dev)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("ar6000_create_ap_interface: register_netdev failed\n"));
- return A_ERROR;
- }
-
- arApDev = netdev_priv(dev);
- arApDev->arDev = ar;
- arApDev->arNetDev = dev;
- arApDev->arStaNetDev = ar->arNetDev;
-
- ar->arApDev = arApDev;
- arApNetDev = dev;
-
- /* Copy the MAC address */
- memcpy(dev->dev_addr, ar->arNetDev->dev_addr, AR6000_ETH_ADDR_LEN);
-
- return 0;
-}
-
-int ar6000_add_ap_interface(struct ar6_softc *ar, char *ap_ifname)
-{
- /* Interface already added, need not proceed further */
- if (ar->arApDev != NULL) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("ar6000_add_ap_interface: interface already present \n"));
- return 0;
- }
-
- if (ar6000_create_ap_interface(ar, ap_ifname) != 0) {
- return A_ERROR;
- }
-
- A_PRINTF("Add AP interface %s \n",ap_ifname);
-
- return ar6000_start_ap_interface(ar);
-}
-
-int ar6000_remove_ap_interface(struct ar6_softc *ar)
-{
- if (arApNetDev) {
- ar6000_stop_ap_interface(ar);
-
- unregister_netdev(arApNetDev);
- free_netdev(apApNetDev);
-
- A_PRINTF("Remove AP interface\n");
- }
- ar->arApDev = NULL;
- arApNetDev = NULL;
-
-
- return 0;
-}
-#endif /* CONFIG_AP_VIRTUAL_ADAPTER_SUPPORT */
-
-
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
-EXPORT_SYMBOL(setupbtdev);
-#endif
diff --git a/drivers/staging/ath6kl/os/linux/ar6000_pm.c b/drivers/staging/ath6kl/os/linux/ar6000_pm.c
deleted file mode 100644
index 1e0ace8b6d13..000000000000
--- a/drivers/staging/ath6kl/os/linux/ar6000_pm.c
+++ /dev/null
@@ -1,626 +0,0 @@
-/*
- *
- * Copyright (c) 2004-2010 Atheros Communications Inc.
- * All rights reserved.
- *
- *
-//
-// 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.
-//
-//
- *
- */
-
-/*
- * Implementation of system power management
- */
-
-#include "ar6000_drv.h"
-#include <linux/inetdevice.h>
-#include <linux/platform_device.h>
-#include "wlan_config.h"
-
-#define WOW_ENABLE_MAX_INTERVAL 0
-#define WOW_SET_SCAN_PARAMS 0
-
-extern unsigned int wmitimeout;
-extern wait_queue_head_t arEvent;
-
-#undef ATH_MODULE_NAME
-#define ATH_MODULE_NAME pm
-#define ATH_DEBUG_PM ATH_DEBUG_MAKE_MODULE_MASK(0)
-
-#ifdef DEBUG
-static struct ath_debug_mask_description pm_debug_desc[] = {
- { ATH_DEBUG_PM , "System power management"},
-};
-
-ATH_DEBUG_INSTANTIATE_MODULE_VAR(pm,
- "pm",
- "System Power Management",
- ATH_DEBUG_MASK_DEFAULTS | ATH_DEBUG_PM,
- ATH_DEBUG_DESCRIPTION_COUNT(pm_debug_desc),
- pm_debug_desc);
-
-#endif /* DEBUG */
-
-int ar6000_exit_cut_power_state(struct ar6_softc *ar);
-
-#ifdef CONFIG_PM
-static void ar6k_send_asleep_event_to_app(struct ar6_softc *ar, bool asleep)
-{
- char buf[128];
- union iwreq_data wrqu;
-
- snprintf(buf, sizeof(buf), "HOST_ASLEEP=%s", asleep ? "asleep" : "awake");
- A_MEMZERO(&wrqu, sizeof(wrqu));
- wrqu.data.length = strlen(buf);
- wireless_send_event(ar->arNetDev, IWEVCUSTOM, &wrqu, buf);
-}
-
-static void ar6000_wow_resume(struct ar6_softc *ar)
-{
- if (ar->arWowState!= WLAN_WOW_STATE_NONE) {
- u16 fg_start_period = (ar->scParams.fg_start_period==0) ? 1 : ar->scParams.fg_start_period;
- u16 bg_period = (ar->scParams.bg_period==0) ? 60 : ar->scParams.bg_period;
- WMI_SET_HOST_SLEEP_MODE_CMD hostSleepMode = {true, false};
- ar->arWowState = WLAN_WOW_STATE_NONE;
- if (wmi_set_host_sleep_mode_cmd(ar->arWmi, &hostSleepMode)!= 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to setup restore host awake\n"));
- }
-#if WOW_SET_SCAN_PARAMS
- wmi_scanparams_cmd(ar->arWmi, fg_start_period,
- ar->scParams.fg_end_period,
- bg_period,
- ar->scParams.minact_chdwell_time,
- ar->scParams.maxact_chdwell_time,
- ar->scParams.pas_chdwell_time,
- ar->scParams.shortScanRatio,
- ar->scParams.scanCtrlFlags,
- ar->scParams.max_dfsch_act_time,
- ar->scParams.maxact_scan_per_ssid);
-#else
- (void)fg_start_period;
- (void)bg_period;
-#endif
-
-
-#if WOW_ENABLE_MAX_INTERVAL /* we don't do it if the power consumption is already good enough. */
- if (wmi_listeninterval_cmd(ar->arWmi, ar->arListenIntervalT, ar->arListenIntervalB) == 0) {
- }
-#endif
- ar6k_send_asleep_event_to_app(ar, false);
- AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("Resume WoW successfully\n"));
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("WoW does not invoked. skip resume"));
- }
- ar->arWlanPowerState = WLAN_POWER_STATE_ON;
-}
-
-static void ar6000_wow_suspend(struct ar6_softc *ar)
-{
-#define WOW_LIST_ID 1
- if (ar->arNetworkType != AP_NETWORK) {
- /* Setup WoW for unicast & Arp request for our own IP
- disable background scan. Set listen interval into 1000 TUs
- Enable keepliave for 110 seconds
- */
- struct in_ifaddr **ifap = NULL;
- struct in_ifaddr *ifa = NULL;
- struct in_device *in_dev;
- u8 macMask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- int status;
- WMI_ADD_WOW_PATTERN_CMD addWowCmd = { .filter = { 0 } };
- WMI_DEL_WOW_PATTERN_CMD delWowCmd;
- WMI_SET_HOST_SLEEP_MODE_CMD hostSleepMode = {false, true};
- WMI_SET_WOW_MODE_CMD wowMode = { .enable_wow = true,
- .hostReqDelay = 500 };/*500 ms delay*/
-
- if (ar->arWowState!= WLAN_WOW_STATE_NONE) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("System already go into wow mode!\n"));
- return;
- }
-
- ar6000_TxDataCleanup(ar); /* IMPORTANT, otherwise there will be 11mA after listen interval as 1000*/
-
-#if WOW_ENABLE_MAX_INTERVAL /* we don't do it if the power consumption is already good enough. */
- if (wmi_listeninterval_cmd(ar->arWmi, A_MAX_WOW_LISTEN_INTERVAL, 0) == 0) {
- }
-#endif
-
-#if WOW_SET_SCAN_PARAMS
- status = wmi_scanparams_cmd(ar->arWmi, 0xFFFF, 0, 0xFFFF, 0, 0, 0, 0, 0, 0, 0);
-#endif
- /* clear up our WoW pattern first */
- delWowCmd.filter_list_id = WOW_LIST_ID;
- delWowCmd.filter_id = 0;
- wmi_del_wow_pattern_cmd(ar->arWmi, &delWowCmd);
-
- /* setup unicast packet pattern for WoW */
- if (ar->arNetDev->dev_addr[1]) {
- addWowCmd.filter_list_id = WOW_LIST_ID;
- addWowCmd.filter_size = 6; /* MAC address */
- addWowCmd.filter_offset = 0;
- status = wmi_add_wow_pattern_cmd(ar->arWmi, &addWowCmd, ar->arNetDev->dev_addr, macMask, addWowCmd.filter_size);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to add WoW pattern\n"));
- }
- }
- /* setup ARP request for our own IP */
- if ((in_dev = __in_dev_get_rtnl(ar->arNetDev)) != NULL) {
- for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; ifap = &ifa->ifa_next) {
- if (!strcmp(ar->arNetDev->name, ifa->ifa_label)) {
- break; /* found */
- }
- }
- }
- if (ifa && ifa->ifa_local) {
- WMI_SET_IP_CMD ipCmd;
- memset(&ipCmd, 0, sizeof(ipCmd));
- ipCmd.ips[0] = ifa->ifa_local;
- status = wmi_set_ip_cmd(ar->arWmi, &ipCmd);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to setup IP for ARP agent\n"));
- }
- }
-
-#ifndef ATH6K_CONFIG_OTA_MODE
- wmi_powermode_cmd(ar->arWmi, REC_POWER);
-#endif
-
- status = wmi_set_wow_mode_cmd(ar->arWmi, &wowMode);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to enable wow mode\n"));
- }
- ar6k_send_asleep_event_to_app(ar, true);
-
- status = wmi_set_host_sleep_mode_cmd(ar->arWmi, &hostSleepMode);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to set host asleep\n"));
- }
-
- ar->arWowState = WLAN_WOW_STATE_SUSPENDING;
- if (ar->arTxPending[ar->arControlEp]) {
- u32 timeleft = wait_event_interruptible_timeout(arEvent,
- ar->arTxPending[ar->arControlEp] == 0, wmitimeout * HZ);
- if (!timeleft || signal_pending(current)) {
- /* what can I do? wow resume at once */
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to setup WoW. Pending wmi control data %d\n", ar->arTxPending[ar->arControlEp]));
- }
- }
-
- status = hifWaitForPendingRecv(ar->arHifDevice);
-
- ar->arWowState = WLAN_WOW_STATE_SUSPENDED;
- ar->arWlanPowerState = WLAN_POWER_STATE_WOW;
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Not allowed to go to WOW at this moment.\n"));
- }
-}
-
-int ar6000_suspend_ev(void *context)
-{
- int status = 0;
- struct ar6_softc *ar = (struct ar6_softc *)context;
- s16 pmmode = ar->arSuspendConfig;
-wow_not_connected:
- switch (pmmode) {
- case WLAN_SUSPEND_WOW:
- if (ar->arWmiReady && ar->arWlanState==WLAN_ENABLED && ar->arConnected) {
- ar6000_wow_suspend(ar);
- AR_DEBUG_PRINTF(ATH_DEBUG_PM,("%s:Suspend for wow mode %d\n", __func__, ar->arWlanPowerState));
- } else {
- pmmode = ar->arWow2Config;
- goto wow_not_connected;
- }
- break;
- case WLAN_SUSPEND_CUT_PWR:
- /* fall through */
- case WLAN_SUSPEND_CUT_PWR_IF_BT_OFF:
- /* fall through */
- case WLAN_SUSPEND_DEEP_SLEEP:
- /* fall through */
- default:
- status = ar6000_update_wlan_pwr_state(ar, WLAN_DISABLED, true);
- if (ar->arWlanPowerState==WLAN_POWER_STATE_ON ||
- ar->arWlanPowerState==WLAN_POWER_STATE_WOW) {
- AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("Strange suspend state for not wow mode %d", ar->arWlanPowerState));
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_PM,("%s:Suspend for %d mode pwr %d status %d\n", __func__, pmmode, ar->arWlanPowerState, status));
- status = (ar->arWlanPowerState == WLAN_POWER_STATE_CUT_PWR) ? 0 : A_EBUSY;
- break;
- }
-
- ar->scan_triggered = 0;
- return status;
-}
-
-int ar6000_resume_ev(void *context)
-{
- struct ar6_softc *ar = (struct ar6_softc *)context;
- u16 powerState = ar->arWlanPowerState;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("%s: enter previous state %d wowState %d\n", __func__, powerState, ar->arWowState));
- switch (powerState) {
- case WLAN_POWER_STATE_WOW:
- ar6000_wow_resume(ar);
- break;
- case WLAN_POWER_STATE_CUT_PWR:
- /* fall through */
- case WLAN_POWER_STATE_DEEP_SLEEP:
- ar6000_update_wlan_pwr_state(ar, WLAN_ENABLED, true);
- AR_DEBUG_PRINTF(ATH_DEBUG_PM,("%s:Resume for %d mode pwr %d\n", __func__, powerState, ar->arWlanPowerState));
- break;
- case WLAN_POWER_STATE_ON:
- break;
- default:
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Strange SDIO bus power mode!!\n"));
- break;
- }
- return 0;
-}
-
-void ar6000_check_wow_status(struct ar6_softc *ar, struct sk_buff *skb, bool isEvent)
-{
- if (ar->arWowState!=WLAN_WOW_STATE_NONE) {
- if (ar->arWowState==WLAN_WOW_STATE_SUSPENDING) {
- AR_DEBUG_PRINTF(ATH_DEBUG_PM,("\n%s: Received IRQ while we are wow suspending!!!\n\n", __func__));
- return;
- }
- /* Wow resume from irq interrupt */
- AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("%s: WoW resume from irq thread status %d\n", __func__, ar->arWlanPowerState));
- ar6000_wow_resume(ar);
- }
-}
-
-int ar6000_power_change_ev(void *context, u32 config)
-{
- struct ar6_softc *ar = (struct ar6_softc *)context;
- int status = 0;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("%s: power change event callback %d \n", __func__, config));
- switch (config) {
- case HIF_DEVICE_POWER_UP:
- ar6000_restart_endpoint(ar->arNetDev);
- status = 0;
- break;
- case HIF_DEVICE_POWER_DOWN:
- case HIF_DEVICE_POWER_CUT:
- status = 0;
- break;
- }
- return status;
-}
-
-#endif /* CONFIG_PM */
-
-int
-ar6000_setup_cut_power_state(struct ar6_softc *ar, AR6000_WLAN_STATE state)
-{
- int status = 0;
- HIF_DEVICE_POWER_CHANGE_TYPE config;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("%s: Cut power %d %d \n", __func__,state, ar->arWlanPowerState));
-#ifdef CONFIG_PM
- AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("Wlan OFF %d BT OFf %d \n", ar->arWlanOff, ar->arBTOff));
-#endif
- do {
- if (state == WLAN_ENABLED) {
- /* Not in cut power state.. exit */
- if (ar->arWlanPowerState != WLAN_POWER_STATE_CUT_PWR) {
- break;
- }
-
- /* Change the state to ON */
- ar->arWlanPowerState = WLAN_POWER_STATE_ON;
-
-
- /* Indicate POWER_UP to HIF */
- config = HIF_DEVICE_POWER_UP;
- status = HIFConfigureDevice(ar->arHifDevice,
- HIF_DEVICE_POWER_STATE_CHANGE,
- &config,
- sizeof(HIF_DEVICE_POWER_CHANGE_TYPE));
-
- if (status == A_PENDING) {
- } else if (status == 0) {
- ar6000_restart_endpoint(ar->arNetDev);
- status = 0;
- }
- } else if (state == WLAN_DISABLED) {
-
-
- /* Already in cut power state.. exit */
- if (ar->arWlanPowerState == WLAN_POWER_STATE_CUT_PWR) {
- break;
- }
- ar6000_stop_endpoint(ar->arNetDev, true, false);
-
- config = HIF_DEVICE_POWER_CUT;
- status = HIFConfigureDevice(ar->arHifDevice,
- HIF_DEVICE_POWER_STATE_CHANGE,
- &config,
- sizeof(HIF_DEVICE_POWER_CHANGE_TYPE));
-
- ar->arWlanPowerState = WLAN_POWER_STATE_CUT_PWR;
- }
- } while (0);
-
- return status;
-}
-
-int
-ar6000_setup_deep_sleep_state(struct ar6_softc *ar, AR6000_WLAN_STATE state)
-{
- int status = 0;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("%s: Deep sleep %d %d \n", __func__,state, ar->arWlanPowerState));
-#ifdef CONFIG_PM
- AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("Wlan OFF %d BT OFf %d \n", ar->arWlanOff, ar->arBTOff));
-#endif
- do {
- WMI_SET_HOST_SLEEP_MODE_CMD hostSleepMode;
-
- if (state == WLAN_ENABLED) {
- u16 fg_start_period;
-
- /* Not in deep sleep state.. exit */
- if (ar->arWlanPowerState != WLAN_POWER_STATE_DEEP_SLEEP) {
- if (ar->arWlanPowerState != WLAN_POWER_STATE_ON) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Strange state when we resume from deep sleep %d\n", ar->arWlanPowerState));
- }
- break;
- }
-
- fg_start_period = (ar->scParams.fg_start_period==0) ? 1 : ar->scParams.fg_start_period;
- hostSleepMode.awake = true;
- hostSleepMode.asleep = false;
-
- if ((status=wmi_set_host_sleep_mode_cmd(ar->arWmi, &hostSleepMode)) != 0) {
- break;
- }
-
- /* Change the state to ON */
- ar->arWlanPowerState = WLAN_POWER_STATE_ON;
-
- /* Enable foreground scanning */
- if ((status=wmi_scanparams_cmd(ar->arWmi, fg_start_period,
- ar->scParams.fg_end_period,
- ar->scParams.bg_period,
- ar->scParams.minact_chdwell_time,
- ar->scParams.maxact_chdwell_time,
- ar->scParams.pas_chdwell_time,
- ar->scParams.shortScanRatio,
- ar->scParams.scanCtrlFlags,
- ar->scParams.max_dfsch_act_time,
- ar->scParams.maxact_scan_per_ssid)) != 0)
- {
- break;
- }
-
- if (ar->arNetworkType != AP_NETWORK)
- {
- if (ar->arSsidLen) {
- if (ar6000_connect_to_ap(ar) != 0) {
- /* no need to report error if connection failed */
- break;
- }
- }
- }
- } else if (state == WLAN_DISABLED){
- WMI_SET_WOW_MODE_CMD wowMode = { .enable_wow = false };
-
- /* Already in deep sleep state.. exit */
- if (ar->arWlanPowerState != WLAN_POWER_STATE_ON) {
- if (ar->arWlanPowerState != WLAN_POWER_STATE_DEEP_SLEEP) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Strange state when we suspend for deep sleep %d\n", ar->arWlanPowerState));
- }
- break;
- }
-
- if (ar->arNetworkType != AP_NETWORK)
- {
- /* Disconnect from the AP and disable foreground scanning */
- AR6000_SPIN_LOCK(&ar->arLock, 0);
- if (ar->arConnected == true || ar->arConnectPending == true) {
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
- wmi_disconnect_cmd(ar->arWmi);
- } else {
- AR6000_SPIN_UNLOCK(&ar->arLock, 0);
- }
- }
-
- ar->scan_triggered = 0;
-
- if ((status=wmi_scanparams_cmd(ar->arWmi, 0xFFFF, 0, 0, 0, 0, 0, 0, 0, 0, 0)) != 0) {
- break;
- }
-
- /* make sure we disable wow for deep sleep */
- if ((status=wmi_set_wow_mode_cmd(ar->arWmi, &wowMode))!= 0)
- {
- break;
- }
-
- ar6000_TxDataCleanup(ar);
-#ifndef ATH6K_CONFIG_OTA_MODE
- wmi_powermode_cmd(ar->arWmi, REC_POWER);
-#endif
-
- hostSleepMode.awake = false;
- hostSleepMode.asleep = true;
- if ((status=wmi_set_host_sleep_mode_cmd(ar->arWmi, &hostSleepMode))!= 0) {
- break;
- }
- if (ar->arTxPending[ar->arControlEp]) {
- u32 timeleft = wait_event_interruptible_timeout(arEvent,
- ar->arTxPending[ar->arControlEp] == 0, wmitimeout * HZ);
- if (!timeleft || signal_pending(current)) {
- status = A_ERROR;
- break;
- }
- }
- status = hifWaitForPendingRecv(ar->arHifDevice);
-
- ar->arWlanPowerState = WLAN_POWER_STATE_DEEP_SLEEP;
- }
- } while (0);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to enter/exit deep sleep %d\n", state));
- }
-
- return status;
-}
-
-int
-ar6000_update_wlan_pwr_state(struct ar6_softc *ar, AR6000_WLAN_STATE state, bool pmEvent)
-{
- int status = 0;
- u16 powerState, oldPowerState;
- AR6000_WLAN_STATE oldstate = ar->arWlanState;
- bool wlanOff = ar->arWlanOff;
-#ifdef CONFIG_PM
- bool btOff = ar->arBTOff;
-#endif /* CONFIG_PM */
-
- if ((state!=WLAN_DISABLED && state!=WLAN_ENABLED)) {
- return A_ERROR;
- }
-
- if (ar->bIsDestroyProgress) {
- return A_EBUSY;
- }
-
- if (down_interruptible(&ar->arSem)) {
- return A_ERROR;
- }
-
- if (ar->bIsDestroyProgress) {
- up(&ar->arSem);
- return A_EBUSY;
- }
-
- ar->arWlanState = wlanOff ? WLAN_DISABLED : state;
- oldPowerState = ar->arWlanPowerState;
- if (state == WLAN_ENABLED) {
- powerState = ar->arWlanPowerState;
- AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("WLAN PWR set to ENABLE^^\n"));
- if (!wlanOff) {
- if (powerState == WLAN_POWER_STATE_DEEP_SLEEP) {
- status = ar6000_setup_deep_sleep_state(ar, WLAN_ENABLED);
- } else if (powerState == WLAN_POWER_STATE_CUT_PWR) {
- status = ar6000_setup_cut_power_state(ar, WLAN_ENABLED);
- }
- }
-#ifdef CONFIG_PM
- else if (pmEvent && wlanOff) {
- bool allowCutPwr = ((!ar->arBTSharing) || btOff);
- if ((powerState==WLAN_POWER_STATE_CUT_PWR) && (!allowCutPwr)) {
- /* Come out of cut power */
- ar6000_setup_cut_power_state(ar, WLAN_ENABLED);
- status = ar6000_setup_deep_sleep_state(ar, WLAN_DISABLED);
- }
- }
-#endif /* CONFIG_PM */
- } else if (state == WLAN_DISABLED) {
- AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("WLAN PWR set to DISABLED~\n"));
- powerState = WLAN_POWER_STATE_DEEP_SLEEP;
-#ifdef CONFIG_PM
- if (pmEvent) { /* disable due to suspend */
- bool suspendCutPwr = (ar->arSuspendConfig == WLAN_SUSPEND_CUT_PWR ||
- (ar->arSuspendConfig == WLAN_SUSPEND_WOW &&
- ar->arWow2Config==WLAN_SUSPEND_CUT_PWR));
- bool suspendCutIfBtOff = ((ar->arSuspendConfig ==
- WLAN_SUSPEND_CUT_PWR_IF_BT_OFF ||
- (ar->arSuspendConfig == WLAN_SUSPEND_WOW &&
- ar->arWow2Config==WLAN_SUSPEND_CUT_PWR_IF_BT_OFF)) &&
- (!ar->arBTSharing || btOff));
- if ((suspendCutPwr) ||
- (suspendCutIfBtOff) ||
- (ar->arWlanState==WLAN_POWER_STATE_CUT_PWR))
- {
- powerState = WLAN_POWER_STATE_CUT_PWR;
- }
- } else {
- if ((wlanOff) &&
- (ar->arWlanOffConfig == WLAN_OFF_CUT_PWR) &&
- (!ar->arBTSharing || btOff))
- {
- /* For BT clock sharing designs, CUT_POWER depend on BT state */
- powerState = WLAN_POWER_STATE_CUT_PWR;
- }
- }
-#endif /* CONFIG_PM */
-
- if (powerState == WLAN_POWER_STATE_DEEP_SLEEP) {
- if (ar->arWlanPowerState == WLAN_POWER_STATE_CUT_PWR) {
- AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("Load firmware before set to deep sleep\n"));
- ar6000_setup_cut_power_state(ar, WLAN_ENABLED);
- }
- status = ar6000_setup_deep_sleep_state(ar, WLAN_DISABLED);
- } else if (powerState == WLAN_POWER_STATE_CUT_PWR) {
- status = ar6000_setup_cut_power_state(ar, WLAN_DISABLED);
- }
-
- }
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to setup WLAN state %d\n", ar->arWlanState));
- ar->arWlanState = oldstate;
- } else if (status == 0) {
- WMI_REPORT_SLEEP_STATE_EVENT wmiSleepEvent, *pSleepEvent = NULL;
- if ((ar->arWlanPowerState == WLAN_POWER_STATE_ON) && (oldPowerState != WLAN_POWER_STATE_ON)) {
- wmiSleepEvent.sleepState = WMI_REPORT_SLEEP_STATUS_IS_AWAKE;
- pSleepEvent = &wmiSleepEvent;
- } else if ((ar->arWlanPowerState != WLAN_POWER_STATE_ON) && (oldPowerState == WLAN_POWER_STATE_ON)) {
- wmiSleepEvent.sleepState = WMI_REPORT_SLEEP_STATUS_IS_DEEP_SLEEP;
- pSleepEvent = &wmiSleepEvent;
- }
- if (pSleepEvent) {
- AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("SENT WLAN Sleep Event %d\n", wmiSleepEvent.sleepState));
- }
- }
- up(&ar->arSem);
- return status;
-}
-
-int
-ar6000_set_bt_hw_state(struct ar6_softc *ar, u32 enable)
-{
-#ifdef CONFIG_PM
- bool off = (enable == 0);
- int status;
- if (ar->arBTOff == off) {
- return 0;
- }
- ar->arBTOff = off;
- status = ar6000_update_wlan_pwr_state(ar, ar->arWlanOff ? WLAN_DISABLED : WLAN_ENABLED, false);
- return status;
-#else
- return 0;
-#endif
-}
-
-int
-ar6000_set_wlan_state(struct ar6_softc *ar, AR6000_WLAN_STATE state)
-{
- int status;
- bool off = (state == WLAN_DISABLED);
- if (ar->arWlanOff == off) {
- return 0;
- }
- ar->arWlanOff = off;
- status = ar6000_update_wlan_pwr_state(ar, state, false);
- return status;
-}
diff --git a/drivers/staging/ath6kl/os/linux/ar6000_raw_if.c b/drivers/staging/ath6kl/os/linux/ar6000_raw_if.c
deleted file mode 100644
index ae7c1dd96d83..000000000000
--- a/drivers/staging/ath6kl/os/linux/ar6000_raw_if.c
+++ /dev/null
@@ -1,455 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Communications Inc.
-// All rights reserved.
-//
-//
-//
-// 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.
-//
-//
-//
-// Author(s): ="Atheros"
-//------------------------------------------------------------------------------
-
-#include "ar6000_drv.h"
-
-#ifdef HTC_RAW_INTERFACE
-
-static void
-ar6000_htc_raw_read_cb(void *Context, struct htc_packet *pPacket)
-{
- struct ar6_softc *ar = (struct ar6_softc *)Context;
- raw_htc_buffer *busy;
- HTC_RAW_STREAM_ID streamID;
- AR_RAW_HTC_T *arRaw = ar->arRawHtc;
-
- busy = (raw_htc_buffer *)pPacket->pPktContext;
- A_ASSERT(busy != NULL);
-
- if (pPacket->Status == A_ECANCELED) {
- /*
- * HTC provides A_ECANCELED status when it doesn't want to be refilled
- * (probably due to a shutdown)
- */
- return;
- }
-
- streamID = arEndpoint2RawStreamID(ar,pPacket->Endpoint);
- A_ASSERT(streamID != HTC_RAW_STREAM_NOT_MAPPED);
-
-#ifdef CF
- if (down_trylock(&arRaw->raw_htc_read_sem[streamID])) {
-#else
- if (down_interruptible(&arRaw->raw_htc_read_sem[streamID])) {
-#endif /* CF */
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Unable to down the semaphore\n"));
- }
-
- A_ASSERT((pPacket->Status != 0) ||
- (pPacket->pBuffer == (busy->data + HTC_HEADER_LEN)));
-
- busy->length = pPacket->ActualLength + HTC_HEADER_LEN;
- busy->currPtr = HTC_HEADER_LEN;
- arRaw->read_buffer_available[streamID] = true;
- //AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("raw read cb: 0x%X 0x%X \n", busy->currPtr,busy->length);
- up(&arRaw->raw_htc_read_sem[streamID]);
-
- /* Signal the waiting process */
- AR_DEBUG_PRINTF(ATH_DEBUG_HTC_RAW,("Waking up the StreamID(%d) read process\n", streamID));
- wake_up_interruptible(&arRaw->raw_htc_read_queue[streamID]);
-}
-
-static void
-ar6000_htc_raw_write_cb(void *Context, struct htc_packet *pPacket)
-{
- struct ar6_softc *ar = (struct ar6_softc *)Context;
- raw_htc_buffer *free;
- HTC_RAW_STREAM_ID streamID;
- AR_RAW_HTC_T *arRaw = ar->arRawHtc;
-
- free = (raw_htc_buffer *)pPacket->pPktContext;
- A_ASSERT(free != NULL);
-
- if (pPacket->Status == A_ECANCELED) {
- /*
- * HTC provides A_ECANCELED status when it doesn't want to be refilled
- * (probably due to a shutdown)
- */
- return;
- }
-
- streamID = arEndpoint2RawStreamID(ar,pPacket->Endpoint);
- A_ASSERT(streamID != HTC_RAW_STREAM_NOT_MAPPED);
-
-#ifdef CF
- if (down_trylock(&arRaw->raw_htc_write_sem[streamID])) {
-#else
- if (down_interruptible(&arRaw->raw_htc_write_sem[streamID])) {
-#endif
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Unable to down the semaphore\n"));
- }
-
- A_ASSERT(pPacket->pBuffer == (free->data + HTC_HEADER_LEN));
-
- free->length = 0;
- arRaw->write_buffer_available[streamID] = true;
- up(&arRaw->raw_htc_write_sem[streamID]);
-
- /* Signal the waiting process */
- AR_DEBUG_PRINTF(ATH_DEBUG_HTC_RAW,("Waking up the StreamID(%d) write process\n", streamID));
- wake_up_interruptible(&arRaw->raw_htc_write_queue[streamID]);
-}
-
-/* connect to a service */
-static int ar6000_connect_raw_service(struct ar6_softc *ar,
- HTC_RAW_STREAM_ID StreamID)
-{
- int status;
- struct htc_service_connect_resp response;
- u8 streamNo;
- struct htc_service_connect_req connect;
-
- do {
-
- A_MEMZERO(&connect,sizeof(connect));
- /* pass the stream ID as meta data to the RAW streams service */
- streamNo = (u8)StreamID;
- connect.pMetaData = &streamNo;
- connect.MetaDataLength = sizeof(u8);
- /* these fields are the same for all endpoints */
- connect.EpCallbacks.pContext = ar;
- connect.EpCallbacks.EpTxComplete = ar6000_htc_raw_write_cb;
- connect.EpCallbacks.EpRecv = ar6000_htc_raw_read_cb;
- /* simple interface, we don't need these optional callbacks */
- connect.EpCallbacks.EpRecvRefill = NULL;
- connect.EpCallbacks.EpSendFull = NULL;
- connect.MaxSendQueueDepth = RAW_HTC_WRITE_BUFFERS_NUM;
-
- /* connect to the raw streams service, we may be able to get 1 or more
- * connections, depending on WHAT is running on the target */
- connect.ServiceID = HTC_RAW_STREAMS_SVC;
-
- A_MEMZERO(&response,sizeof(response));
-
- /* try to connect to the raw stream, it is okay if this fails with
- * status HTC_SERVICE_NO_MORE_EP */
- status = HTCConnectService(ar->arHtcTarget,
- &connect,
- &response);
-
- if (status) {
- if (response.ConnectRespCode == HTC_SERVICE_NO_MORE_EP) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HTC RAW , No more streams allowed \n"));
- status = 0;
- }
- break;
- }
-
- /* set endpoint mapping for the RAW HTC streams */
- arSetRawStream2EndpointIDMap(ar,StreamID,response.Endpoint);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_HTC_RAW,("HTC RAW : stream ID: %d, endpoint: %d\n",
- StreamID, arRawStream2EndpointID(ar,StreamID)));
-
- } while (false);
-
- return status;
-}
-
-int ar6000_htc_raw_open(struct ar6_softc *ar)
-{
- int status;
- int streamID, endPt, count2;
- raw_htc_buffer *buffer;
- HTC_SERVICE_ID servicepriority;
- AR_RAW_HTC_T *arRaw = ar->arRawHtc;
- if (!arRaw) {
- arRaw = ar->arRawHtc = A_MALLOC(sizeof(AR_RAW_HTC_T));
- if (arRaw) {
- A_MEMZERO(arRaw, sizeof(AR_RAW_HTC_T));
- }
- }
- A_ASSERT(ar->arHtcTarget != NULL);
- if (!arRaw) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Faile to allocate memory for HTC RAW interface\n"));
- return -ENOMEM;
- }
- /* wait for target */
- status = HTCWaitTarget(ar->arHtcTarget);
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HTCWaitTarget failed (%d)\n", status));
- return -ENODEV;
- }
-
- for (endPt = 0; endPt < ENDPOINT_MAX; endPt++) {
- arRaw->arEp2RawMapping[endPt] = HTC_RAW_STREAM_NOT_MAPPED;
- }
-
- for (streamID = HTC_RAW_STREAM_0; streamID < HTC_RAW_STREAM_NUM_MAX; streamID++) {
- /* Initialize the data structures */
- sema_init(&arRaw->raw_htc_read_sem[streamID], 1);
- sema_init(&arRaw->raw_htc_write_sem[streamID], 1);
- init_waitqueue_head(&arRaw->raw_htc_read_queue[streamID]);
- init_waitqueue_head(&arRaw->raw_htc_write_queue[streamID]);
-
- /* try to connect to the raw service */
- status = ar6000_connect_raw_service(ar,streamID);
-
- if (status) {
- break;
- }
-
- if (arRawStream2EndpointID(ar,streamID) == 0) {
- break;
- }
-
- for (count2 = 0; count2 < RAW_HTC_READ_BUFFERS_NUM; count2 ++) {
- /* Initialize the receive buffers */
- buffer = &arRaw->raw_htc_write_buffer[streamID][count2];
- memset(buffer, 0, sizeof(raw_htc_buffer));
- buffer = &arRaw->raw_htc_read_buffer[streamID][count2];
- memset(buffer, 0, sizeof(raw_htc_buffer));
-
- SET_HTC_PACKET_INFO_RX_REFILL(&buffer->HTCPacket,
- buffer,
- buffer->data,
- HTC_RAW_BUFFER_SIZE,
- arRawStream2EndpointID(ar,streamID));
-
- /* Queue buffers to HTC for receive */
- if ((status = HTCAddReceivePkt(ar->arHtcTarget, &buffer->HTCPacket)) != 0)
- {
- BMIInit();
- return -EIO;
- }
- }
-
- for (count2 = 0; count2 < RAW_HTC_WRITE_BUFFERS_NUM; count2 ++) {
- /* Initialize the receive buffers */
- buffer = &arRaw->raw_htc_write_buffer[streamID][count2];
- memset(buffer, 0, sizeof(raw_htc_buffer));
- }
-
- arRaw->read_buffer_available[streamID] = false;
- arRaw->write_buffer_available[streamID] = true;
- }
-
- if (status) {
- return -EIO;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("HTC RAW, number of streams the target supports: %d \n", streamID));
-
- servicepriority = HTC_RAW_STREAMS_SVC; /* only 1 */
-
- /* set callbacks and priority list */
- HTCSetCreditDistribution(ar->arHtcTarget,
- ar,
- NULL, /* use default */
- NULL, /* use default */
- &servicepriority,
- 1);
-
- /* Start the HTC component */
- if ((status = HTCStart(ar->arHtcTarget)) != 0) {
- BMIInit();
- return -EIO;
- }
-
- (ar)->arRawIfInit = true;
-
- return 0;
-}
-
-int ar6000_htc_raw_close(struct ar6_softc *ar)
-{
- A_PRINTF("ar6000_htc_raw_close called \n");
- HTCStop(ar->arHtcTarget);
-
- /* reset the device */
- ar6000_reset_device(ar->arHifDevice, ar->arTargetType, true, false);
- /* Initialize the BMI component */
- BMIInit();
-
- return 0;
-}
-
-raw_htc_buffer *
-get_filled_buffer(struct ar6_softc *ar, HTC_RAW_STREAM_ID StreamID)
-{
- int count;
- raw_htc_buffer *busy;
- AR_RAW_HTC_T *arRaw = ar->arRawHtc;
-
- /* Check for data */
- for (count = 0; count < RAW_HTC_READ_BUFFERS_NUM; count ++) {
- busy = &arRaw->raw_htc_read_buffer[StreamID][count];
- if (busy->length) {
- break;
- }
- }
- if (busy->length) {
- arRaw->read_buffer_available[StreamID] = true;
- } else {
- arRaw->read_buffer_available[StreamID] = false;
- }
-
- return busy;
-}
-
-ssize_t ar6000_htc_raw_read(struct ar6_softc *ar, HTC_RAW_STREAM_ID StreamID,
- char __user *buffer, size_t length)
-{
- int readPtr;
- raw_htc_buffer *busy;
- AR_RAW_HTC_T *arRaw = ar->arRawHtc;
-
- if (arRawStream2EndpointID(ar,StreamID) == 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("StreamID(%d) not connected! \n", StreamID));
- return -EFAULT;
- }
-
- if (down_interruptible(&arRaw->raw_htc_read_sem[StreamID])) {
- return -ERESTARTSYS;
- }
-
- busy = get_filled_buffer(ar,StreamID);
- while (!arRaw->read_buffer_available[StreamID]) {
- up(&arRaw->raw_htc_read_sem[StreamID]);
-
- /* Wait for the data */
- AR_DEBUG_PRINTF(ATH_DEBUG_HTC_RAW,("Sleeping StreamID(%d) read process\n", StreamID));
- if (wait_event_interruptible(arRaw->raw_htc_read_queue[StreamID],
- arRaw->read_buffer_available[StreamID]))
- {
- return -EINTR;
- }
- if (down_interruptible(&arRaw->raw_htc_read_sem[StreamID])) {
- return -ERESTARTSYS;
- }
- busy = get_filled_buffer(ar,StreamID);
- }
-
- /* Read the data */
- readPtr = busy->currPtr;
- if (length > busy->length - HTC_HEADER_LEN) {
- length = busy->length - HTC_HEADER_LEN;
- }
- if (copy_to_user(buffer, &busy->data[readPtr], length)) {
- up(&arRaw->raw_htc_read_sem[StreamID]);
- return -EFAULT;
- }
-
- busy->currPtr += length;
-
- if (busy->currPtr == busy->length)
- {
- busy->currPtr = 0;
- busy->length = 0;
- HTC_PACKET_RESET_RX(&busy->HTCPacket);
- //AR_DEBUG_PRINTF(ATH_DEBUG_HTC_RAW,("raw read ioctl: ep for packet:%d \n", busy->HTCPacket.Endpoint));
- HTCAddReceivePkt(ar->arHtcTarget, &busy->HTCPacket);
- }
- arRaw->read_buffer_available[StreamID] = false;
- up(&arRaw->raw_htc_read_sem[StreamID]);
-
- return length;
-}
-
-static raw_htc_buffer *
-get_free_buffer(struct ar6_softc *ar, HTC_ENDPOINT_ID StreamID)
-{
- int count;
- raw_htc_buffer *free;
- AR_RAW_HTC_T *arRaw = ar->arRawHtc;
-
- free = NULL;
- for (count = 0; count < RAW_HTC_WRITE_BUFFERS_NUM; count ++) {
- free = &arRaw->raw_htc_write_buffer[StreamID][count];
- if (free->length == 0) {
- break;
- }
- }
- if (!free->length) {
- arRaw->write_buffer_available[StreamID] = true;
- } else {
- arRaw->write_buffer_available[StreamID] = false;
- }
-
- return free;
-}
-
-ssize_t ar6000_htc_raw_write(struct ar6_softc *ar, HTC_RAW_STREAM_ID StreamID,
- char __user *buffer, size_t length)
-{
- int writePtr;
- raw_htc_buffer *free;
- AR_RAW_HTC_T *arRaw = ar->arRawHtc;
- if (arRawStream2EndpointID(ar,StreamID) == 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("StreamID(%d) not connected! \n", StreamID));
- return -EFAULT;
- }
-
- if (down_interruptible(&arRaw->raw_htc_write_sem[StreamID])) {
- return -ERESTARTSYS;
- }
-
- /* Search for a free buffer */
- free = get_free_buffer(ar,StreamID);
-
- /* Check if there is space to write else wait */
- while (!arRaw->write_buffer_available[StreamID]) {
- up(&arRaw->raw_htc_write_sem[StreamID]);
-
- /* Wait for buffer to become free */
- AR_DEBUG_PRINTF(ATH_DEBUG_HTC_RAW,("Sleeping StreamID(%d) write process\n", StreamID));
- if (wait_event_interruptible(arRaw->raw_htc_write_queue[StreamID],
- arRaw->write_buffer_available[StreamID]))
- {
- return -EINTR;
- }
- if (down_interruptible(&arRaw->raw_htc_write_sem[StreamID])) {
- return -ERESTARTSYS;
- }
- free = get_free_buffer(ar,StreamID);
- }
-
- /* Send the data */
- writePtr = HTC_HEADER_LEN;
- if (length > (HTC_RAW_BUFFER_SIZE - HTC_HEADER_LEN)) {
- length = HTC_RAW_BUFFER_SIZE - HTC_HEADER_LEN;
- }
-
- if (copy_from_user(&free->data[writePtr], buffer, length)) {
- up(&arRaw->raw_htc_read_sem[StreamID]);
- return -EFAULT;
- }
-
- free->length = length;
-
- SET_HTC_PACKET_INFO_TX(&free->HTCPacket,
- free,
- &free->data[writePtr],
- length,
- arRawStream2EndpointID(ar,StreamID),
- AR6K_DATA_PKT_TAG);
-
- HTCSendPkt(ar->arHtcTarget,&free->HTCPacket);
-
- arRaw->write_buffer_available[StreamID] = false;
- up(&arRaw->raw_htc_write_sem[StreamID]);
-
- return length;
-}
-#endif /* HTC_RAW_INTERFACE */
diff --git a/drivers/staging/ath6kl/os/linux/cfg80211.c b/drivers/staging/ath6kl/os/linux/cfg80211.c
deleted file mode 100644
index 5fdda4aa2fee..000000000000
--- a/drivers/staging/ath6kl/os/linux/cfg80211.c
+++ /dev/null
@@ -1,1892 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Communications Inc.
-// All rights reserved.
-//
-//
-//
-// 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.
-//
-//
-//
-// Author(s): ="Atheros"
-//------------------------------------------------------------------------------
-
-#include <linux/wireless.h>
-#include <linux/ieee80211.h>
-#include <net/cfg80211.h>
-#include <net/netlink.h>
-
-#include "ar6000_drv.h"
-
-
-extern A_WAITQUEUE_HEAD arEvent;
-extern unsigned int wmitimeout;
-extern int reconnect_flag;
-
-
-#define RATETAB_ENT(_rate, _rateid, _flags) { \
- .bitrate = (_rate), \
- .flags = (_flags), \
- .hw_value = (_rateid), \
-}
-
-#define CHAN2G(_channel, _freq, _flags) { \
- .band = IEEE80211_BAND_2GHZ, \
- .hw_value = (_channel), \
- .center_freq = (_freq), \
- .flags = (_flags), \
- .max_antenna_gain = 0, \
- .max_power = 30, \
-}
-
-#define CHAN5G(_channel, _flags) { \
- .band = IEEE80211_BAND_5GHZ, \
- .hw_value = (_channel), \
- .center_freq = 5000 + (5 * (_channel)), \
- .flags = (_flags), \
- .max_antenna_gain = 0, \
- .max_power = 30, \
-}
-
-static struct
-ieee80211_rate ar6k_rates[] = {
- RATETAB_ENT(10, 0x1, 0),
- RATETAB_ENT(20, 0x2, 0),
- RATETAB_ENT(55, 0x4, 0),
- RATETAB_ENT(110, 0x8, 0),
- RATETAB_ENT(60, 0x10, 0),
- RATETAB_ENT(90, 0x20, 0),
- RATETAB_ENT(120, 0x40, 0),
- RATETAB_ENT(180, 0x80, 0),
- RATETAB_ENT(240, 0x100, 0),
- RATETAB_ENT(360, 0x200, 0),
- RATETAB_ENT(480, 0x400, 0),
- RATETAB_ENT(540, 0x800, 0),
-};
-
-#define ar6k_a_rates (ar6k_rates + 4)
-#define ar6k_a_rates_size 8
-#define ar6k_g_rates (ar6k_rates + 0)
-#define ar6k_g_rates_size 12
-
-static struct
-ieee80211_channel ar6k_2ghz_channels[] = {
- CHAN2G(1, 2412, 0),
- CHAN2G(2, 2417, 0),
- CHAN2G(3, 2422, 0),
- CHAN2G(4, 2427, 0),
- CHAN2G(5, 2432, 0),
- CHAN2G(6, 2437, 0),
- CHAN2G(7, 2442, 0),
- CHAN2G(8, 2447, 0),
- CHAN2G(9, 2452, 0),
- CHAN2G(10, 2457, 0),
- CHAN2G(11, 2462, 0),
- CHAN2G(12, 2467, 0),
- CHAN2G(13, 2472, 0),
- CHAN2G(14, 2484, 0),
-};
-
-static struct
-ieee80211_channel ar6k_5ghz_a_channels[] = {
- CHAN5G(34, 0), CHAN5G(36, 0),
- CHAN5G(38, 0), CHAN5G(40, 0),
- CHAN5G(42, 0), CHAN5G(44, 0),
- CHAN5G(46, 0), CHAN5G(48, 0),
- CHAN5G(52, 0), CHAN5G(56, 0),
- CHAN5G(60, 0), CHAN5G(64, 0),
- CHAN5G(100, 0), CHAN5G(104, 0),
- CHAN5G(108, 0), CHAN5G(112, 0),
- CHAN5G(116, 0), CHAN5G(120, 0),
- CHAN5G(124, 0), CHAN5G(128, 0),
- CHAN5G(132, 0), CHAN5G(136, 0),
- CHAN5G(140, 0), CHAN5G(149, 0),
- CHAN5G(153, 0), CHAN5G(157, 0),
- CHAN5G(161, 0), CHAN5G(165, 0),
- CHAN5G(184, 0), CHAN5G(188, 0),
- CHAN5G(192, 0), CHAN5G(196, 0),
- CHAN5G(200, 0), CHAN5G(204, 0),
- CHAN5G(208, 0), CHAN5G(212, 0),
- CHAN5G(216, 0),
-};
-
-static struct
-ieee80211_supported_band ar6k_band_2ghz = {
- .n_channels = ARRAY_SIZE(ar6k_2ghz_channels),
- .channels = ar6k_2ghz_channels,
- .n_bitrates = ar6k_g_rates_size,
- .bitrates = ar6k_g_rates,
-};
-
-static struct
-ieee80211_supported_band ar6k_band_5ghz = {
- .n_channels = ARRAY_SIZE(ar6k_5ghz_a_channels),
- .channels = ar6k_5ghz_a_channels,
- .n_bitrates = ar6k_a_rates_size,
- .bitrates = ar6k_a_rates,
-};
-
-static int
-ar6k_set_wpa_version(struct ar6_softc *ar, enum nl80211_wpa_versions wpa_version)
-{
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: %u\n", __func__, wpa_version));
-
- if (!wpa_version) {
- ar->arAuthMode = NONE_AUTH;
- } else if (wpa_version & NL80211_WPA_VERSION_1) {
- ar->arAuthMode = WPA_AUTH;
- } else if (wpa_version & NL80211_WPA_VERSION_2) {
- ar->arAuthMode = WPA2_AUTH;
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("%s: %u not spported\n", __func__, wpa_version));
- return -ENOTSUPP;
- }
-
- return 0;
-}
-
-static int
-ar6k_set_auth_type(struct ar6_softc *ar, enum nl80211_auth_type auth_type)
-{
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: 0x%x\n", __func__, auth_type));
-
- switch (auth_type) {
- case NL80211_AUTHTYPE_OPEN_SYSTEM:
- ar->arDot11AuthMode = OPEN_AUTH;
- break;
- case NL80211_AUTHTYPE_SHARED_KEY:
- ar->arDot11AuthMode = SHARED_AUTH;
- break;
- case NL80211_AUTHTYPE_NETWORK_EAP:
- ar->arDot11AuthMode = LEAP_AUTH;
- break;
-
- case NL80211_AUTHTYPE_AUTOMATIC:
- ar->arDot11AuthMode = OPEN_AUTH;
- ar->arAutoAuthStage = AUTH_OPEN_IN_PROGRESS;
- break;
-
- default:
- ar->arDot11AuthMode = OPEN_AUTH;
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,
- ("%s: 0x%x not spported\n", __func__, auth_type));
- return -ENOTSUPP;
- }
-
- return 0;
-}
-
-static int
-ar6k_set_cipher(struct ar6_softc *ar, u32 cipher, bool ucast)
-{
- u8 *ar_cipher = ucast ? &ar->arPairwiseCrypto :
- &ar->arGroupCrypto;
- u8 *ar_cipher_len = ucast ? &ar->arPairwiseCryptoLen :
- &ar->arGroupCryptoLen;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,
- ("%s: cipher 0x%x, ucast %u\n", __func__, cipher, ucast));
-
- switch (cipher) {
- case 0:
- case IW_AUTH_CIPHER_NONE:
- *ar_cipher = NONE_CRYPT;
- *ar_cipher_len = 0;
- break;
- case WLAN_CIPHER_SUITE_WEP40:
- *ar_cipher = WEP_CRYPT;
- *ar_cipher_len = 5;
- break;
- case WLAN_CIPHER_SUITE_WEP104:
- *ar_cipher = WEP_CRYPT;
- *ar_cipher_len = 13;
- break;
- case WLAN_CIPHER_SUITE_TKIP:
- *ar_cipher = TKIP_CRYPT;
- *ar_cipher_len = 0;
- break;
- case WLAN_CIPHER_SUITE_CCMP:
- *ar_cipher = AES_CRYPT;
- *ar_cipher_len = 0;
- break;
- default:
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("%s: cipher 0x%x not supported\n", __func__, cipher));
- return -ENOTSUPP;
- }
-
- return 0;
-}
-
-static void
-ar6k_set_key_mgmt(struct ar6_softc *ar, u32 key_mgmt)
-{
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: 0x%x\n", __func__, key_mgmt));
-
- if (WLAN_AKM_SUITE_PSK == key_mgmt) {
- if (WPA_AUTH == ar->arAuthMode) {
- ar->arAuthMode = WPA_PSK_AUTH;
- } else if (WPA2_AUTH == ar->arAuthMode) {
- ar->arAuthMode = WPA2_PSK_AUTH;
- }
- } else if (WLAN_AKM_SUITE_8021X != key_mgmt) {
- ar->arAuthMode = NONE_AUTH;
- }
-}
-
-static int
-ar6k_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
- struct cfg80211_connect_params *sme)
-{
- struct ar6_softc *ar = ar6k_priv(dev);
- int status;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: \n", __func__));
- ar->smeState = SME_CONNECTING;
-
- if(ar->arWmiReady == false) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wmi not ready yet\n", __func__));
- return -EIO;
- }
-
- if(ar->arWlanState == WLAN_DISABLED) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wlan disabled\n", __func__));
- return -EIO;
- }
-
- if(ar->bIsDestroyProgress) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: destroy in progress\n", __func__));
- return -EBUSY;
- }
-
- if(!sme->ssid_len || IEEE80211_MAX_SSID_LEN < sme->ssid_len) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: ssid invalid\n", __func__));
- return -EINVAL;
- }
-
- if(ar->arSkipScan == true &&
- ((sme->channel && sme->channel->center_freq == 0) ||
- (sme->bssid && !sme->bssid[0] && !sme->bssid[1] && !sme->bssid[2] &&
- !sme->bssid[3] && !sme->bssid[4] && !sme->bssid[5])))
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s:SkipScan: channel or bssid invalid\n", __func__));
- return -EINVAL;
- }
-
- if(down_interruptible(&ar->arSem)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: busy, couldn't get access\n", __func__));
- return -ERESTARTSYS;
- }
-
- if(ar->bIsDestroyProgress) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: busy, destroy in progress\n", __func__));
- up(&ar->arSem);
- return -EBUSY;
- }
-
- if(ar->arTxPending[wmi_get_control_ep(ar->arWmi)]) {
- /*
- * sleep until the command queue drains
- */
- wait_event_interruptible_timeout(arEvent,
- ar->arTxPending[wmi_get_control_ep(ar->arWmi)] == 0, wmitimeout * HZ);
- if (signal_pending(current)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: cmd queue drain timeout\n", __func__));
- up(&ar->arSem);
- return -EINTR;
- }
- }
-
- if(ar->arConnected == true &&
- ar->arSsidLen == sme->ssid_len &&
- !memcmp(ar->arSsid, sme->ssid, ar->arSsidLen)) {
- reconnect_flag = true;
- status = wmi_reconnect_cmd(ar->arWmi,
- ar->arReqBssid,
- ar->arChannelHint);
-
- up(&ar->arSem);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: wmi_reconnect_cmd failed\n", __func__));
- return -EIO;
- }
- return 0;
- } else if(ar->arSsidLen == sme->ssid_len &&
- !memcmp(ar->arSsid, sme->ssid, ar->arSsidLen)) {
- ar6000_disconnect(ar);
- }
-
- A_MEMZERO(ar->arSsid, sizeof(ar->arSsid));
- ar->arSsidLen = sme->ssid_len;
- memcpy(ar->arSsid, sme->ssid, sme->ssid_len);
-
- if(sme->channel){
- ar->arChannelHint = sme->channel->center_freq;
- }
-
- A_MEMZERO(ar->arReqBssid, sizeof(ar->arReqBssid));
- if(sme->bssid){
- if(memcmp(&sme->bssid, bcast_mac, AR6000_ETH_ADDR_LEN)) {
- memcpy(ar->arReqBssid, sme->bssid, sizeof(ar->arReqBssid));
- }
- }
-
- ar6k_set_wpa_version(ar, sme->crypto.wpa_versions);
- ar6k_set_auth_type(ar, sme->auth_type);
-
- if(sme->crypto.n_ciphers_pairwise) {
- ar6k_set_cipher(ar, sme->crypto.ciphers_pairwise[0], true);
- } else {
- ar6k_set_cipher(ar, IW_AUTH_CIPHER_NONE, true);
- }
- ar6k_set_cipher(ar, sme->crypto.cipher_group, false);
-
- if(sme->crypto.n_akm_suites) {
- ar6k_set_key_mgmt(ar, sme->crypto.akm_suites[0]);
- }
-
- if((sme->key_len) &&
- (NONE_AUTH == ar->arAuthMode) &&
- (WEP_CRYPT == ar->arPairwiseCrypto)) {
- struct ar_key *key = NULL;
-
- if(sme->key_idx < WMI_MIN_KEY_INDEX || sme->key_idx > WMI_MAX_KEY_INDEX) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("%s: key index %d out of bounds\n", __func__, sme->key_idx));
- up(&ar->arSem);
- return -ENOENT;
- }
-
- key = &ar->keys[sme->key_idx];
- key->key_len = sme->key_len;
- memcpy(key->key, sme->key, key->key_len);
- key->cipher = ar->arPairwiseCrypto;
- ar->arDefTxKeyIndex = sme->key_idx;
-
- wmi_addKey_cmd(ar->arWmi, sme->key_idx,
- ar->arPairwiseCrypto,
- GROUP_USAGE | TX_USAGE,
- key->key_len,
- NULL,
- key->key, KEY_OP_INIT_VAL, NULL,
- NO_SYNC_WMIFLAG);
- }
-
- if (!ar->arUserBssFilter) {
- if (wmi_bssfilter_cmd(ar->arWmi, ALL_BSS_FILTER, 0) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Couldn't set bss filtering\n", __func__));
- up(&ar->arSem);
- return -EIO;
- }
- }
-
- ar->arNetworkType = ar->arNextMode;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: Connect called with authmode %d dot11 auth %d"\
- " PW crypto %d PW crypto Len %d GRP crypto %d"\
- " GRP crypto Len %d channel hint %u\n",
- __func__, ar->arAuthMode, ar->arDot11AuthMode,
- ar->arPairwiseCrypto, ar->arPairwiseCryptoLen,
- ar->arGroupCrypto, ar->arGroupCryptoLen, ar->arChannelHint));
-
- reconnect_flag = 0;
- status = wmi_connect_cmd(ar->arWmi, ar->arNetworkType,
- ar->arDot11AuthMode, ar->arAuthMode,
- ar->arPairwiseCrypto, ar->arPairwiseCryptoLen,
- ar->arGroupCrypto,ar->arGroupCryptoLen,
- ar->arSsidLen, ar->arSsid,
- ar->arReqBssid, ar->arChannelHint,
- ar->arConnectCtrlFlags);
-
- up(&ar->arSem);
-
- if (A_EINVAL == status) {
- A_MEMZERO(ar->arSsid, sizeof(ar->arSsid));
- ar->arSsidLen = 0;
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Invalid request\n", __func__));
- return -ENOENT;
- } else if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: wmi_connect_cmd failed\n", __func__));
- return -EIO;
- }
-
- if ((!(ar->arConnectCtrlFlags & CONNECT_DO_WPA_OFFLOAD)) &&
- ((WPA_PSK_AUTH == ar->arAuthMode) || (WPA2_PSK_AUTH == ar->arAuthMode)))
- {
- A_TIMEOUT_MS(&ar->disconnect_timer, A_DISCONNECT_TIMER_INTERVAL, 0);
- }
-
- ar->arConnectCtrlFlags &= ~CONNECT_DO_WPA_OFFLOAD;
- ar->arConnectPending = true;
-
- return 0;
-}
-
-void
-ar6k_cfg80211_connect_event(struct ar6_softc *ar, u16 channel,
- u8 *bssid, u16 listenInterval,
- u16 beaconInterval,NETWORK_TYPE networkType,
- u8 beaconIeLen, u8 assocReqLen,
- u8 assocRespLen, u8 *assocInfo)
-{
- u16 size = 0;
- u16 capability = 0;
- struct cfg80211_bss *bss = NULL;
- struct ieee80211_mgmt *mgmt = NULL;
- struct ieee80211_channel *ibss_channel = NULL;
- s32 signal = 50 * 100;
- u8 ie_buf_len = 0;
- unsigned char ie_buf[256];
- unsigned char *ptr_ie_buf = ie_buf;
- unsigned char *ieeemgmtbuf = NULL;
- u8 source_mac[ATH_MAC_LEN];
-
- u8 assocReqIeOffset = sizeof(u16) + /* capinfo*/
- sizeof(u16); /* listen interval */
- u8 assocRespIeOffset = sizeof(u16) + /* capinfo*/
- sizeof(u16) + /* status Code */
- sizeof(u16); /* associd */
- u8 *assocReqIe = assocInfo + beaconIeLen + assocReqIeOffset;
- u8 *assocRespIe = assocInfo + beaconIeLen + assocReqLen + assocRespIeOffset;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: \n", __func__));
-
- assocReqLen -= assocReqIeOffset;
- assocRespLen -= assocRespIeOffset;
-
- ar->arAutoAuthStage = AUTH_IDLE;
-
- if((ADHOC_NETWORK & networkType)) {
- if(NL80211_IFTYPE_ADHOC != ar->wdev->iftype) {
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,
- ("%s: ath6k not in ibss mode\n", __func__));
- return;
- }
- }
-
- if((INFRA_NETWORK & networkType)) {
- if(NL80211_IFTYPE_STATION != ar->wdev->iftype) {
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,
- ("%s: ath6k not in station mode\n", __func__));
- return;
- }
- }
-
- /* Before informing the join/connect event, make sure that
- * bss entry is present in scan list, if it not present
- * construct and insert into scan list, otherwise that
- * event will be dropped on the way by cfg80211, due to
- * this keys will not be plumbed in case of WEP and
- * application will not be aware of join/connect status. */
- bss = cfg80211_get_bss(ar->wdev->wiphy, NULL, bssid,
- ar->wdev->ssid, ar->wdev->ssid_len,
- ((ADHOC_NETWORK & networkType) ? WLAN_CAPABILITY_IBSS : WLAN_CAPABILITY_ESS),
- ((ADHOC_NETWORK & networkType) ? WLAN_CAPABILITY_IBSS : WLAN_CAPABILITY_ESS));
-
- /*
- * Earlier we were updating the cfg about bss by making a beacon frame
- * only if the entry for bss is not there. This can have some issue if
- * ROAM event is generated and a heavy traffic is ongoing. The ROAM
- * event is handled through a work queue and by the time it really gets
- * handled, BSS would have been aged out. So it is better to update the
- * cfg about BSS irrespective of its entry being present right now or
- * not.
- */
-
- if (ADHOC_NETWORK & networkType) {
- /* construct 802.11 mgmt beacon */
- if(ptr_ie_buf) {
- *ptr_ie_buf++ = WLAN_EID_SSID;
- *ptr_ie_buf++ = ar->arSsidLen;
- memcpy(ptr_ie_buf, ar->arSsid, ar->arSsidLen);
- ptr_ie_buf +=ar->arSsidLen;
-
- *ptr_ie_buf++ = WLAN_EID_IBSS_PARAMS;
- *ptr_ie_buf++ = 2; /* length */
- *ptr_ie_buf++ = 0; /* ATIM window */
- *ptr_ie_buf++ = 0; /* ATIM window */
-
- /* TODO: update ibss params and include supported rates,
- * DS param set, extened support rates, wmm. */
-
- ie_buf_len = ptr_ie_buf - ie_buf;
- }
-
- capability |= IEEE80211_CAPINFO_IBSS;
- if(WEP_CRYPT == ar->arPairwiseCrypto) {
- capability |= IEEE80211_CAPINFO_PRIVACY;
- }
- memcpy(source_mac, ar->arNetDev->dev_addr, ATH_MAC_LEN);
- ptr_ie_buf = ie_buf;
- } else {
- capability = *(u16 *)(&assocInfo[beaconIeLen]);
- memcpy(source_mac, bssid, ATH_MAC_LEN);
- ptr_ie_buf = assocReqIe;
- ie_buf_len = assocReqLen;
- }
-
- size = offsetof(struct ieee80211_mgmt, u)
- + sizeof(mgmt->u.beacon)
- + ie_buf_len;
-
- ieeemgmtbuf = A_MALLOC_NOWAIT(size);
- if(!ieeemgmtbuf) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("%s: ieeeMgmtbuf alloc error\n", __func__));
- cfg80211_put_bss(bss);
- return;
- }
-
- A_MEMZERO(ieeemgmtbuf, size);
- mgmt = (struct ieee80211_mgmt *)ieeemgmtbuf;
- mgmt->frame_control = (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON);
- memcpy(mgmt->da, bcast_mac, ATH_MAC_LEN);
- memcpy(mgmt->sa, source_mac, ATH_MAC_LEN);
- memcpy(mgmt->bssid, bssid, ATH_MAC_LEN);
- mgmt->u.beacon.beacon_int = beaconInterval;
- mgmt->u.beacon.capab_info = capability;
- memcpy(mgmt->u.beacon.variable, ptr_ie_buf, ie_buf_len);
-
- ibss_channel = ieee80211_get_channel(ar->wdev->wiphy, (int)channel);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,
- ("%s: inform bss with bssid %pM channel %d beaconInterval %d "
- "capability 0x%x\n", __func__, mgmt->bssid,
- ibss_channel->hw_value, beaconInterval, capability));
-
- bss = cfg80211_inform_bss_frame(ar->wdev->wiphy,
- ibss_channel, mgmt,
- le16_to_cpu(size),
- signal, GFP_KERNEL);
- kfree(ieeemgmtbuf);
- cfg80211_put_bss(bss);
-
- if((ADHOC_NETWORK & networkType)) {
- cfg80211_ibss_joined(ar->arNetDev, bssid, GFP_KERNEL);
- return;
- }
-
- if (false == ar->arConnected) {
- /* inform connect result to cfg80211 */
- ar->smeState = SME_DISCONNECTED;
- cfg80211_connect_result(ar->arNetDev, bssid,
- assocReqIe, assocReqLen,
- assocRespIe, assocRespLen,
- WLAN_STATUS_SUCCESS, GFP_KERNEL);
- } else {
- /* inform roam event to cfg80211 */
- cfg80211_roamed(ar->arNetDev, ibss_channel, bssid,
- assocReqIe, assocReqLen,
- assocRespIe, assocRespLen,
- GFP_KERNEL);
- }
-}
-
-static int
-ar6k_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
- u16 reason_code)
-{
- struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: reason=%u\n", __func__, reason_code));
-
- if(ar->arWmiReady == false) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wmi not ready\n", __func__));
- return -EIO;
- }
-
- if(ar->arWlanState == WLAN_DISABLED) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wlan disabled\n", __func__));
- return -EIO;
- }
-
- if(ar->bIsDestroyProgress) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: busy, destroy in progress\n", __func__));
- return -EBUSY;
- }
-
- if(down_interruptible(&ar->arSem)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: busy, couldn't get access\n", __func__));
- return -ERESTARTSYS;
- }
-
- reconnect_flag = 0;
- ar6000_disconnect(ar);
- A_MEMZERO(ar->arSsid, sizeof(ar->arSsid));
- ar->arSsidLen = 0;
-
- if (ar->arSkipScan == false) {
- A_MEMZERO(ar->arReqBssid, sizeof(ar->arReqBssid));
- }
-
- up(&ar->arSem);
-
- return 0;
-}
-
-void
-ar6k_cfg80211_disconnect_event(struct ar6_softc *ar, u8 reason,
- u8 *bssid, u8 assocRespLen,
- u8 *assocInfo, u16 protocolReasonStatus)
-{
-
- u16 status;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: reason=%u\n", __func__, reason));
-
- if (ar->scan_request) {
- cfg80211_scan_done(ar->scan_request, true);
- ar->scan_request = NULL;
- }
- if((ADHOC_NETWORK & ar->arNetworkType)) {
- if(NL80211_IFTYPE_ADHOC != ar->wdev->iftype) {
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,
- ("%s: ath6k not in ibss mode\n", __func__));
- return;
- }
- A_MEMZERO(bssid, ETH_ALEN);
- cfg80211_ibss_joined(ar->arNetDev, bssid, GFP_KERNEL);
- return;
- }
-
- if((INFRA_NETWORK & ar->arNetworkType)) {
- if(NL80211_IFTYPE_STATION != ar->wdev->iftype) {
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,
- ("%s: ath6k not in station mode\n", __func__));
- return;
- }
- }
-
- if(true == ar->arConnectPending) {
- if(NO_NETWORK_AVAIL == reason) {
- /* connect cmd failed */
- wmi_disconnect_cmd(ar->arWmi);
- } else if (reason == DISCONNECT_CMD) {
- if (ar->arAutoAuthStage) {
- /*
- * If the current auth algorithm is open try shared
- * and make autoAuthStage idle. We do not make it
- * leap for now being.
- */
- if (ar->arDot11AuthMode == OPEN_AUTH) {
- struct ar_key *key = NULL;
- key = &ar->keys[ar->arDefTxKeyIndex];
- if (down_interruptible(&ar->arSem)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: busy, couldn't get access\n", __func__));
- return;
- }
-
-
- ar->arDot11AuthMode = SHARED_AUTH;
- ar->arAutoAuthStage = AUTH_IDLE;
-
- wmi_addKey_cmd(ar->arWmi, ar->arDefTxKeyIndex,
- ar->arPairwiseCrypto,
- GROUP_USAGE | TX_USAGE,
- key->key_len,
- NULL,
- key->key, KEY_OP_INIT_VAL, NULL,
- NO_SYNC_WMIFLAG);
-
- status = wmi_connect_cmd(ar->arWmi,
- ar->arNetworkType,
- ar->arDot11AuthMode,
- ar->arAuthMode,
- ar->arPairwiseCrypto,
- ar->arPairwiseCryptoLen,
- ar->arGroupCrypto,
- ar->arGroupCryptoLen,
- ar->arSsidLen,
- ar->arSsid,
- ar->arReqBssid,
- ar->arChannelHint,
- ar->arConnectCtrlFlags);
- up(&ar->arSem);
-
- } else if (ar->arDot11AuthMode == SHARED_AUTH) {
- /* should not reach here */
- }
- } else {
- ar->arConnectPending = false;
- if (ar->smeState == SME_CONNECTING) {
- cfg80211_connect_result(ar->arNetDev, bssid,
- NULL, 0,
- NULL, 0,
- WLAN_STATUS_UNSPECIFIED_FAILURE,
- GFP_KERNEL);
- } else {
- cfg80211_disconnected(ar->arNetDev,
- reason,
- NULL, 0,
- GFP_KERNEL);
- }
- ar->smeState = SME_DISCONNECTED;
- }
- }
- } else {
- if (reason != DISCONNECT_CMD)
- wmi_disconnect_cmd(ar->arWmi);
- }
-}
-
-void
-ar6k_cfg80211_scan_node(void *arg, bss_t *ni)
-{
- struct wiphy *wiphy = (struct wiphy *)arg;
- u16 size;
- unsigned char *ieeemgmtbuf = NULL;
- struct ieee80211_mgmt *mgmt;
- struct ieee80211_channel *channel;
- struct ieee80211_supported_band *band;
- struct ieee80211_common_ie *cie;
- s32 signal;
- int freq;
-
- cie = &ni->ni_cie;
-
-#define CHAN_IS_11A(x) (!((x >= 2412) && (x <= 2484)))
- if(CHAN_IS_11A(cie->ie_chan)) {
- /* 11a */
- band = wiphy->bands[IEEE80211_BAND_5GHZ];
- } else if((cie->ie_erp) || (cie->ie_xrates)) {
- /* 11g */
- band = wiphy->bands[IEEE80211_BAND_2GHZ];
- } else {
- /* 11b */
- band = wiphy->bands[IEEE80211_BAND_2GHZ];
- }
-
- size = ni->ni_framelen + offsetof(struct ieee80211_mgmt, u);
- ieeemgmtbuf = A_MALLOC_NOWAIT(size);
- if(!ieeemgmtbuf)
- {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: ieeeMgmtbuf alloc error\n", __func__));
- return;
- }
-
- /* Note:
- TODO: Update target to include 802.11 mac header while sending bss info.
- Target removes 802.11 mac header while sending the bss info to host,
- cfg80211 needs it, for time being just filling the da, sa and bssid fields alone.
- */
- mgmt = (struct ieee80211_mgmt *)ieeemgmtbuf;
- memcpy(mgmt->da, bcast_mac, ATH_MAC_LEN);
- memcpy(mgmt->sa, ni->ni_macaddr, ATH_MAC_LEN);
- memcpy(mgmt->bssid, ni->ni_macaddr, ATH_MAC_LEN);
- memcpy(ieeemgmtbuf + offsetof(struct ieee80211_mgmt, u),
- ni->ni_buf, ni->ni_framelen);
-
- freq = cie->ie_chan;
- channel = ieee80211_get_channel(wiphy, freq);
- signal = ni->ni_snr * 100;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,
- ("%s: bssid %pM channel %d freq %d size %d\n", __func__,
- mgmt->bssid, channel->hw_value, freq, size));
- cfg80211_inform_bss_frame(wiphy, channel, mgmt,
- le16_to_cpu(size),
- signal, GFP_KERNEL);
-
- kfree (ieeemgmtbuf);
-}
-
-static int
-ar6k_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
- struct cfg80211_scan_request *request)
-{
- struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(ndev);
- int ret = 0;
- u32 forceFgScan = 0;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: \n", __func__));
-
- if(ar->arWmiReady == false) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wmi not ready\n", __func__));
- return -EIO;
- }
-
- if(ar->arWlanState == WLAN_DISABLED) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wlan disabled\n", __func__));
- return -EIO;
- }
-
- if (!ar->arUserBssFilter) {
- if (wmi_bssfilter_cmd(ar->arWmi,
- (ar->arConnected ? ALL_BUT_BSS_FILTER : ALL_BSS_FILTER),
- 0) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Couldn't set bss filtering\n", __func__));
- return -EIO;
- }
- }
-
- if(request->n_ssids &&
- request->ssids[0].ssid_len) {
- u8 i;
-
- if(request->n_ssids > (MAX_PROBED_SSID_INDEX - 1)) {
- request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
- }
-
- for (i = 0; i < request->n_ssids; i++) {
- wmi_probedSsid_cmd(ar->arWmi, i+1, SPECIFIC_SSID_FLAG,
- request->ssids[i].ssid_len,
- request->ssids[i].ssid);
- }
- }
-
- if(ar->arConnected) {
- forceFgScan = 1;
- }
-
- if(wmi_startscan_cmd(ar->arWmi, WMI_LONG_SCAN, forceFgScan, false, \
- 0, 0, 0, NULL) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: wmi_startscan_cmd failed\n", __func__));
- ret = -EIO;
- }
-
- ar->scan_request = request;
-
- return ret;
-}
-
-void
-ar6k_cfg80211_scanComplete_event(struct ar6_softc *ar, int status)
-{
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: status %d\n", __func__, status));
-
- if (!ar->scan_request)
- return;
-
- if ((status == A_ECANCELED) || (status == A_EBUSY)) {
- cfg80211_scan_done(ar->scan_request, true);
- goto out;
- }
-
- /* Translate data to cfg80211 mgmt format */
- wmi_iterate_nodes(ar->arWmi, ar6k_cfg80211_scan_node, ar->wdev->wiphy);
-
- cfg80211_scan_done(ar->scan_request, false);
-
- if(ar->scan_request->n_ssids &&
- ar->scan_request->ssids[0].ssid_len) {
- u8 i;
-
- for (i = 0; i < ar->scan_request->n_ssids; i++) {
- wmi_probedSsid_cmd(ar->arWmi, i+1, DISABLE_SSID_FLAG,
- 0, NULL);
- }
- }
-
-out:
- ar->scan_request = NULL;
-}
-
-static int
-ar6k_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
- u8 key_index, bool pairwise, const u8 *mac_addr,
- struct key_params *params)
-{
- struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(ndev);
- struct ar_key *key = NULL;
- u8 key_usage;
- u8 key_type;
- int status = 0;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s:\n", __func__));
-
- if(ar->arWmiReady == false) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wmi not ready\n", __func__));
- return -EIO;
- }
-
- if(ar->arWlanState == WLAN_DISABLED) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wlan disabled\n", __func__));
- return -EIO;
- }
-
- if(key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,
- ("%s: key index %d out of bounds\n", __func__, key_index));
- return -ENOENT;
- }
-
- key = &ar->keys[key_index];
- A_MEMZERO(key, sizeof(struct ar_key));
-
- if(!mac_addr || is_broadcast_ether_addr(mac_addr)) {
- key_usage = GROUP_USAGE;
- } else {
- key_usage = PAIRWISE_USAGE;
- }
-
- if(params) {
- if(params->key_len > WLAN_MAX_KEY_LEN ||
- params->seq_len > IW_ENCODE_SEQ_MAX_SIZE)
- return -EINVAL;
-
- key->key_len = params->key_len;
- memcpy(key->key, params->key, key->key_len);
- key->seq_len = params->seq_len;
- memcpy(key->seq, params->seq, key->seq_len);
- key->cipher = params->cipher;
- }
-
- switch (key->cipher) {
- case WLAN_CIPHER_SUITE_WEP40:
- case WLAN_CIPHER_SUITE_WEP104:
- key_type = WEP_CRYPT;
- break;
-
- case WLAN_CIPHER_SUITE_TKIP:
- key_type = TKIP_CRYPT;
- break;
-
- case WLAN_CIPHER_SUITE_CCMP:
- key_type = AES_CRYPT;
- break;
-
- default:
- return -ENOTSUPP;
- }
-
- if (((WPA_PSK_AUTH == ar->arAuthMode) || (WPA2_PSK_AUTH == ar->arAuthMode)) &&
- (GROUP_USAGE & key_usage))
- {
- A_UNTIMEOUT(&ar->disconnect_timer);
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,
- ("%s: index %d, key_len %d, key_type 0x%x,"\
- " key_usage 0x%x, seq_len %d\n",
- __func__, key_index, key->key_len, key_type,
- key_usage, key->seq_len));
-
- ar->arDefTxKeyIndex = key_index;
- status = wmi_addKey_cmd(ar->arWmi, ar->arDefTxKeyIndex, key_type, key_usage,
- key->key_len, key->seq, key->key, KEY_OP_INIT_VAL,
- (u8 *)mac_addr, SYNC_BOTH_WMIFLAG);
-
-
- if (status) {
- return -EIO;
- }
-
- return 0;
-}
-
-static int
-ar6k_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
- u8 key_index, bool pairwise, const u8 *mac_addr)
-{
- struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(ndev);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: index %d\n", __func__, key_index));
-
- if(ar->arWmiReady == false) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wmi not ready\n", __func__));
- return -EIO;
- }
-
- if(ar->arWlanState == WLAN_DISABLED) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wlan disabled\n", __func__));
- return -EIO;
- }
-
- if(key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,
- ("%s: key index %d out of bounds\n", __func__, key_index));
- return -ENOENT;
- }
-
- if(!ar->keys[key_index].key_len) {
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: index %d is empty\n", __func__, key_index));
- return 0;
- }
-
- ar->keys[key_index].key_len = 0;
-
- return wmi_deleteKey_cmd(ar->arWmi, key_index);
-}
-
-
-static int
-ar6k_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
- u8 key_index, bool pairwise, const u8 *mac_addr,
- void *cookie,
- void (*callback)(void *cookie, struct key_params*))
-{
- struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(ndev);
- struct ar_key *key = NULL;
- struct key_params params;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: index %d\n", __func__, key_index));
-
- if(ar->arWmiReady == false) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wmi not ready\n", __func__));
- return -EIO;
- }
-
- if(ar->arWlanState == WLAN_DISABLED) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wlan disabled\n", __func__));
- return -EIO;
- }
-
- if(key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,
- ("%s: key index %d out of bounds\n", __func__, key_index));
- return -ENOENT;
- }
-
- key = &ar->keys[key_index];
- A_MEMZERO(&params, sizeof(params));
- params.cipher = key->cipher;
- params.key_len = key->key_len;
- params.seq_len = key->seq_len;
- params.seq = key->seq;
- params.key = key->key;
-
- callback(cookie, &params);
-
- return key->key_len ? 0 : -ENOENT;
-}
-
-
-static int
-ar6k_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *ndev,
- u8 key_index, bool unicast, bool multicast)
-{
- struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(ndev);
- struct ar_key *key = NULL;
- int status = 0;
- u8 key_usage;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: index %d\n", __func__, key_index));
-
- if(ar->arWmiReady == false) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wmi not ready\n", __func__));
- return -EIO;
- }
-
- if(ar->arWlanState == WLAN_DISABLED) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wlan disabled\n", __func__));
- return -EIO;
- }
-
- if(key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,
- ("%s: key index %d out of bounds\n",
- __func__, key_index));
- return -ENOENT;
- }
-
- if(!ar->keys[key_index].key_len) {
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: invalid key index %d\n",
- __func__, key_index));
- return -EINVAL;
- }
-
- ar->arDefTxKeyIndex = key_index;
- key = &ar->keys[ar->arDefTxKeyIndex];
- key_usage = GROUP_USAGE;
- if (WEP_CRYPT == ar->arPairwiseCrypto) {
- key_usage |= TX_USAGE;
- }
-
- status = wmi_addKey_cmd(ar->arWmi, ar->arDefTxKeyIndex,
- ar->arPairwiseCrypto, key_usage,
- key->key_len, key->seq, key->key, KEY_OP_INIT_VAL,
- NULL, SYNC_BOTH_WMIFLAG);
- if (status) {
- return -EIO;
- }
-
- return 0;
-}
-
-static int
-ar6k_cfg80211_set_default_mgmt_key(struct wiphy *wiphy, struct net_device *ndev,
- u8 key_index)
-{
- struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(ndev);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: index %d\n", __func__, key_index));
-
- if(ar->arWmiReady == false) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wmi not ready\n", __func__));
- return -EIO;
- }
-
- if(ar->arWlanState == WLAN_DISABLED) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wlan disabled\n", __func__));
- return -EIO;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: not supported\n", __func__));
- return -ENOTSUPP;
-}
-
-void
-ar6k_cfg80211_tkip_micerr_event(struct ar6_softc *ar, u8 keyid, bool ismcast)
-{
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO,
- ("%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast));
-
- cfg80211_michael_mic_failure(ar->arNetDev, ar->arBssid,
- (ismcast ? NL80211_KEYTYPE_GROUP : NL80211_KEYTYPE_PAIRWISE),
- keyid, NULL, GFP_KERNEL);
-}
-
-static int
-ar6k_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
-{
- struct ar6_softc *ar = (struct ar6_softc *)wiphy_priv(wiphy);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: changed 0x%x\n", __func__, changed));
-
- if(ar->arWmiReady == false) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wmi not ready\n", __func__));
- return -EIO;
- }
-
- if(ar->arWlanState == WLAN_DISABLED) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wlan disabled\n", __func__));
- return -EIO;
- }
-
- if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
- if (wmi_set_rts_cmd(ar->arWmi,wiphy->rts_threshold) != 0){
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: wmi_set_rts_cmd failed\n", __func__));
- return -EIO;
- }
- }
-
- return 0;
-}
-
-static int
-ar6k_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev,
- const u8 *peer,
- const struct cfg80211_bitrate_mask *mask)
-{
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Setting rates: Not supported\n"));
- return -EIO;
-}
-
-/* The type nl80211_tx_power_setting replaces the following data type from 2.6.36 onwards */
-static int
-ar6k_cfg80211_set_txpower(struct wiphy *wiphy, enum nl80211_tx_power_setting type, int dbm)
-{
- struct ar6_softc *ar = (struct ar6_softc *)wiphy_priv(wiphy);
- u8 ar_dbm;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: type 0x%x, dbm %d\n", __func__, type, dbm));
-
- if(ar->arWmiReady == false) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wmi not ready\n", __func__));
- return -EIO;
- }
-
- if(ar->arWlanState == WLAN_DISABLED) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wlan disabled\n", __func__));
- return -EIO;
- }
-
- ar->arTxPwrSet = false;
- switch(type) {
- case NL80211_TX_POWER_AUTOMATIC:
- return 0;
- case NL80211_TX_POWER_LIMITED:
- ar->arTxPwr = ar_dbm = dbm;
- ar->arTxPwrSet = true;
- break;
- default:
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: type 0x%x not supported\n", __func__, type));
- return -EOPNOTSUPP;
- }
-
- wmi_set_txPwr_cmd(ar->arWmi, ar_dbm);
-
- return 0;
-}
-
-static int
-ar6k_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
-{
- struct ar6_softc *ar = (struct ar6_softc *)wiphy_priv(wiphy);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: \n", __func__));
-
- if(ar->arWmiReady == false) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wmi not ready\n", __func__));
- return -EIO;
- }
-
- if(ar->arWlanState == WLAN_DISABLED) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wlan disabled\n", __func__));
- return -EIO;
- }
-
- if((ar->arConnected == true)) {
- ar->arTxPwr = 0;
-
- if(wmi_get_txPwr_cmd(ar->arWmi) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: wmi_get_txPwr_cmd failed\n", __func__));
- return -EIO;
- }
-
- wait_event_interruptible_timeout(arEvent, ar->arTxPwr != 0, 5 * HZ);
-
- if(signal_pending(current)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Target did not respond\n", __func__));
- return -EINTR;
- }
- }
-
- *dbm = ar->arTxPwr;
- return 0;
-}
-
-static int
-ar6k_cfg80211_set_power_mgmt(struct wiphy *wiphy,
- struct net_device *dev,
- bool pmgmt, int timeout)
-{
- struct ar6_softc *ar = ar6k_priv(dev);
- WMI_POWER_MODE_CMD pwrMode;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: pmgmt %d, timeout %d\n", __func__, pmgmt, timeout));
-
- if(ar->arWmiReady == false) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wmi not ready\n", __func__));
- return -EIO;
- }
-
- if(ar->arWlanState == WLAN_DISABLED) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wlan disabled\n", __func__));
- return -EIO;
- }
-
- if(pmgmt) {
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: Max Perf\n", __func__));
- pwrMode.powerMode = REC_POWER;
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: Rec Power\n", __func__));
- pwrMode.powerMode = MAX_PERF_POWER;
- }
-
- if(wmi_powermode_cmd(ar->arWmi, pwrMode.powerMode) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: wmi_powermode_cmd failed\n", __func__));
- return -EIO;
- }
-
- return 0;
-}
-
-static struct net_device *
-ar6k_cfg80211_add_virtual_intf(struct wiphy *wiphy, char *name,
- enum nl80211_iftype type, u32 *flags,
- struct vif_params *params)
-{
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: not supported\n", __func__));
-
- /* Multiple virtual interface is not supported.
- * The default interface supports STA and IBSS type
- */
- return ERR_PTR(-EOPNOTSUPP);
-}
-
-static int
-ar6k_cfg80211_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev)
-{
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: not supported\n", __func__));
-
- /* Multiple virtual interface is not supported.
- * The default interface supports STA and IBSS type
- */
- return -EOPNOTSUPP;
-}
-
-static int
-ar6k_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
- enum nl80211_iftype type, u32 *flags,
- struct vif_params *params)
-{
- struct ar6_softc *ar = ar6k_priv(ndev);
- struct wireless_dev *wdev = ar->wdev;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: type %u\n", __func__, type));
-
- if(ar->arWmiReady == false) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wmi not ready\n", __func__));
- return -EIO;
- }
-
- if(ar->arWlanState == WLAN_DISABLED) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wlan disabled\n", __func__));
- return -EIO;
- }
-
- switch (type) {
- case NL80211_IFTYPE_STATION:
- ar->arNextMode = INFRA_NETWORK;
- break;
- case NL80211_IFTYPE_ADHOC:
- ar->arNextMode = ADHOC_NETWORK;
- break;
- default:
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: type %u\n", __func__, type));
- return -EOPNOTSUPP;
- }
-
- wdev->iftype = type;
-
- return 0;
-}
-
-static int
-ar6k_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
- struct cfg80211_ibss_params *ibss_param)
-{
- struct ar6_softc *ar = ar6k_priv(dev);
- int status;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: \n", __func__));
-
- if(ar->arWmiReady == false) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wmi not ready\n", __func__));
- return -EIO;
- }
-
- if(ar->arWlanState == WLAN_DISABLED) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wlan disabled\n", __func__));
- return -EIO;
- }
-
- if(!ibss_param->ssid_len || IEEE80211_MAX_SSID_LEN < ibss_param->ssid_len) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: ssid invalid\n", __func__));
- return -EINVAL;
- }
-
- ar->arSsidLen = ibss_param->ssid_len;
- memcpy(ar->arSsid, ibss_param->ssid, ar->arSsidLen);
-
- if(ibss_param->channel) {
- ar->arChannelHint = ibss_param->channel->center_freq;
- }
-
- if(ibss_param->channel_fixed) {
- /* TODO: channel_fixed: The channel should be fixed, do not search for
- * IBSSs to join on other channels. Target firmware does not support this
- * feature, needs to be updated.*/
- }
-
- A_MEMZERO(ar->arReqBssid, sizeof(ar->arReqBssid));
- if(ibss_param->bssid) {
- if(memcmp(&ibss_param->bssid, bcast_mac, AR6000_ETH_ADDR_LEN)) {
- memcpy(ar->arReqBssid, ibss_param->bssid, sizeof(ar->arReqBssid));
- }
- }
-
- ar6k_set_wpa_version(ar, 0);
- ar6k_set_auth_type(ar, NL80211_AUTHTYPE_OPEN_SYSTEM);
-
- if(ibss_param->privacy) {
- ar6k_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, true);
- ar6k_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, false);
- } else {
- ar6k_set_cipher(ar, IW_AUTH_CIPHER_NONE, true);
- ar6k_set_cipher(ar, IW_AUTH_CIPHER_NONE, false);
- }
-
- ar->arNetworkType = ar->arNextMode;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: Connect called with authmode %d dot11 auth %d"\
- " PW crypto %d PW crypto Len %d GRP crypto %d"\
- " GRP crypto Len %d channel hint %u\n",
- __func__, ar->arAuthMode, ar->arDot11AuthMode,
- ar->arPairwiseCrypto, ar->arPairwiseCryptoLen,
- ar->arGroupCrypto, ar->arGroupCryptoLen, ar->arChannelHint));
-
- status = wmi_connect_cmd(ar->arWmi, ar->arNetworkType,
- ar->arDot11AuthMode, ar->arAuthMode,
- ar->arPairwiseCrypto, ar->arPairwiseCryptoLen,
- ar->arGroupCrypto,ar->arGroupCryptoLen,
- ar->arSsidLen, ar->arSsid,
- ar->arReqBssid, ar->arChannelHint,
- ar->arConnectCtrlFlags);
- ar->arConnectPending = true;
-
- return 0;
-}
-
-static int
-ar6k_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
-{
- struct ar6_softc *ar = (struct ar6_softc *)ar6k_priv(dev);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: \n", __func__));
-
- if(ar->arWmiReady == false) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wmi not ready\n", __func__));
- return -EIO;
- }
-
- if(ar->arWlanState == WLAN_DISABLED) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Wlan disabled\n", __func__));
- return -EIO;
- }
-
- ar6000_disconnect(ar);
- A_MEMZERO(ar->arSsid, sizeof(ar->arSsid));
- ar->arSsidLen = 0;
-
- return 0;
-}
-
-#ifdef CONFIG_NL80211_TESTMODE
-enum ar6k_testmode_attr {
- __AR6K_TM_ATTR_INVALID = 0,
- AR6K_TM_ATTR_CMD = 1,
- AR6K_TM_ATTR_DATA = 2,
-
- /* keep last */
- __AR6K_TM_ATTR_AFTER_LAST,
- AR6K_TM_ATTR_MAX = __AR6K_TM_ATTR_AFTER_LAST - 1
-};
-
-enum ar6k_testmode_cmd {
- AR6K_TM_CMD_TCMD = 0,
- AR6K_TM_CMD_RX_REPORT = 1,
-};
-
-#define AR6K_TM_DATA_MAX_LEN 5000
-
-static const struct nla_policy ar6k_testmode_policy[AR6K_TM_ATTR_MAX + 1] = {
- [AR6K_TM_ATTR_CMD] = { .type = NLA_U32 },
- [AR6K_TM_ATTR_DATA] = { .type = NLA_BINARY,
- .len = AR6K_TM_DATA_MAX_LEN },
-};
-
-void ar6000_testmode_rx_report_event(struct ar6_softc *ar, void *buf,
- int buf_len)
-{
- if (down_interruptible(&ar->arSem))
- return;
-
- kfree(ar->tcmd_rx_report);
-
- ar->tcmd_rx_report = kmemdup(buf, buf_len, GFP_KERNEL);
- ar->tcmd_rx_report_len = buf_len;
-
- up(&ar->arSem);
-
- wake_up(&arEvent);
-}
-
-static int ar6000_testmode_rx_report(struct ar6_softc *ar, void *buf,
- int buf_len, struct sk_buff *skb)
-{
- int ret = 0;
- long left;
-
- if (down_interruptible(&ar->arSem))
- return -ERESTARTSYS;
-
- if (ar->arWmiReady == false) {
- ret = -EIO;
- goto out;
- }
-
- if (ar->bIsDestroyProgress) {
- ret = -EBUSY;
- goto out;
- }
-
- WARN_ON(ar->tcmd_rx_report != NULL);
- WARN_ON(ar->tcmd_rx_report_len > 0);
-
- if (wmi_test_cmd(ar->arWmi, buf, buf_len) < 0) {
- up(&ar->arSem);
- return -EIO;
- }
-
- left = wait_event_interruptible_timeout(arEvent,
- ar->tcmd_rx_report != NULL,
- wmitimeout * HZ);
-
- if (left == 0) {
- ret = -ETIMEDOUT;
- goto out;
- } else if (left < 0) {
- ret = left;
- goto out;
- }
-
- if (ar->tcmd_rx_report == NULL || ar->tcmd_rx_report_len == 0) {
- ret = -EINVAL;
- goto out;
- }
-
- NLA_PUT(skb, AR6K_TM_ATTR_DATA, ar->tcmd_rx_report_len,
- ar->tcmd_rx_report);
-
- kfree(ar->tcmd_rx_report);
- ar->tcmd_rx_report = NULL;
-
-out:
- up(&ar->arSem);
-
- return ret;
-
-nla_put_failure:
- ret = -ENOBUFS;
- goto out;
-}
-
-static int ar6k_testmode_cmd(struct wiphy *wiphy, void *data, int len)
-{
- struct ar6_softc *ar = wiphy_priv(wiphy);
- struct nlattr *tb[AR6K_TM_ATTR_MAX + 1];
- int err, buf_len, reply_len;
- struct sk_buff *skb;
- void *buf;
-
- err = nla_parse(tb, AR6K_TM_ATTR_MAX, data, len,
- ar6k_testmode_policy);
- if (err)
- return err;
-
- if (!tb[AR6K_TM_ATTR_CMD])
- return -EINVAL;
-
- switch (nla_get_u32(tb[AR6K_TM_ATTR_CMD])) {
- case AR6K_TM_CMD_TCMD:
- if (!tb[AR6K_TM_ATTR_DATA])
- return -EINVAL;
-
- buf = nla_data(tb[AR6K_TM_ATTR_DATA]);
- buf_len = nla_len(tb[AR6K_TM_ATTR_DATA]);
-
- wmi_test_cmd(ar->arWmi, buf, buf_len);
-
- return 0;
-
- break;
- case AR6K_TM_CMD_RX_REPORT:
- if (!tb[AR6K_TM_ATTR_DATA])
- return -EINVAL;
-
- buf = nla_data(tb[AR6K_TM_ATTR_DATA]);
- buf_len = nla_len(tb[AR6K_TM_ATTR_DATA]);
-
- reply_len = nla_total_size(AR6K_TM_DATA_MAX_LEN);
- skb = cfg80211_testmode_alloc_reply_skb(wiphy, reply_len);
- if (!skb)
- return -ENOMEM;
-
- err = ar6000_testmode_rx_report(ar, buf, buf_len, skb);
- if (err < 0) {
- kfree_skb(skb);
- return err;
- }
-
- return cfg80211_testmode_reply(skb);
- default:
- return -EOPNOTSUPP;
- }
-}
-#endif
-
-static const
-u32 cipher_suites[] = {
- WLAN_CIPHER_SUITE_WEP40,
- WLAN_CIPHER_SUITE_WEP104,
- WLAN_CIPHER_SUITE_TKIP,
- WLAN_CIPHER_SUITE_CCMP,
-};
-
-bool is_rate_legacy(s32 rate)
-{
- static const s32 legacy[] = { 1000, 2000, 5500, 11000,
- 6000, 9000, 12000, 18000, 24000,
- 36000, 48000, 54000 };
- u8 i;
-
- for (i = 0; i < ARRAY_SIZE(legacy); i++) {
- if (rate == legacy[i])
- return true;
- }
-
- return false;
-}
-
-bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi)
-{
- static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000,
- 52000, 58500, 65000, 72200 };
- u8 i;
-
- for (i = 0; i < ARRAY_SIZE(ht20); i++) {
- if (rate == ht20[i]) {
- if (i == ARRAY_SIZE(ht20) - 1)
- /* last rate uses sgi */
- *sgi = true;
- else
- *sgi = false;
-
- *mcs = i;
- return true;
- }
- }
- return false;
-}
-
-bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)
-{
- static const s32 ht40[] = { 13500, 27000, 40500, 54000,
- 81000, 108000, 121500, 135000,
- 150000 };
- u8 i;
-
- for (i = 0; i < ARRAY_SIZE(ht40); i++) {
- if (rate == ht40[i]) {
- if (i == ARRAY_SIZE(ht40) - 1)
- /* last rate uses sgi */
- *sgi = true;
- else
- *sgi = false;
-
- *mcs = i;
- return true;
- }
- }
-
- return false;
-}
-
-static int ar6k_get_station(struct wiphy *wiphy, struct net_device *dev,
- u8 *mac, struct station_info *sinfo)
-{
- struct ar6_softc *ar = ar6k_priv(dev);
- long left;
- bool sgi;
- s32 rate;
- int ret;
- u8 mcs;
-
- if (memcmp(mac, ar->arBssid, ETH_ALEN) != 0)
- return -ENOENT;
-
- if (down_interruptible(&ar->arSem))
- return -EBUSY;
-
- ar->statsUpdatePending = true;
-
- ret = wmi_get_stats_cmd(ar->arWmi);
-
- if (ret != 0) {
- up(&ar->arSem);
- return -EIO;
- }
-
- left = wait_event_interruptible_timeout(arEvent,
- ar->statsUpdatePending == false,
- wmitimeout * HZ);
-
- up(&ar->arSem);
-
- if (left == 0)
- return -ETIMEDOUT;
- else if (left < 0)
- return left;
-
- if (ar->arTargetStats.rx_bytes) {
- sinfo->rx_bytes = ar->arTargetStats.rx_bytes;
- sinfo->filled |= STATION_INFO_RX_BYTES;
- sinfo->rx_packets = ar->arTargetStats.rx_packets;
- sinfo->filled |= STATION_INFO_RX_PACKETS;
- }
-
- if (ar->arTargetStats.tx_bytes) {
- sinfo->tx_bytes = ar->arTargetStats.tx_bytes;
- sinfo->filled |= STATION_INFO_TX_BYTES;
- sinfo->tx_packets = ar->arTargetStats.tx_packets;
- sinfo->filled |= STATION_INFO_TX_PACKETS;
- }
-
- sinfo->signal = ar->arTargetStats.cs_rssi;
- sinfo->filled |= STATION_INFO_SIGNAL;
-
- rate = ar->arTargetStats.tx_unicast_rate;
-
- if (is_rate_legacy(rate)) {
- sinfo->txrate.legacy = rate / 100;
- } else if (is_rate_ht20(rate, &mcs, &sgi)) {
- if (sgi) {
- sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
- sinfo->txrate.mcs = mcs - 1;
- } else {
- sinfo->txrate.mcs = mcs;
- }
-
- sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
- } else if (is_rate_ht40(rate, &mcs, &sgi)) {
- if (sgi) {
- sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
- sinfo->txrate.mcs = mcs - 1;
- } else {
- sinfo->txrate.mcs = mcs;
- }
-
- sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
- sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
- } else {
- WARN(1, "invalid rate: %d", rate);
- return 0;
- }
-
- sinfo->filled |= STATION_INFO_TX_BITRATE;
-
- return 0;
-}
-
-static int ar6k_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
- struct cfg80211_pmksa *pmksa)
-{
- struct ar6_softc *ar = ar6k_priv(netdev);
- return wmi_setPmkid_cmd(ar->arWmi, pmksa->bssid, pmksa->pmkid, true);
-}
-
-static int ar6k_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
- struct cfg80211_pmksa *pmksa)
-{
- struct ar6_softc *ar = ar6k_priv(netdev);
- return wmi_setPmkid_cmd(ar->arWmi, pmksa->bssid, pmksa->pmkid, false);
-}
-
-static int ar6k_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
-{
- struct ar6_softc *ar = ar6k_priv(netdev);
- if (ar->arConnected)
- return wmi_setPmkid_cmd(ar->arWmi, ar->arBssid, NULL, false);
- return 0;
-}
-
-static struct
-cfg80211_ops ar6k_cfg80211_ops = {
- .change_virtual_intf = ar6k_cfg80211_change_iface,
- .add_virtual_intf = ar6k_cfg80211_add_virtual_intf,
- .del_virtual_intf = ar6k_cfg80211_del_virtual_intf,
- .scan = ar6k_cfg80211_scan,
- .connect = ar6k_cfg80211_connect,
- .disconnect = ar6k_cfg80211_disconnect,
- .add_key = ar6k_cfg80211_add_key,
- .get_key = ar6k_cfg80211_get_key,
- .del_key = ar6k_cfg80211_del_key,
- .set_default_key = ar6k_cfg80211_set_default_key,
- .set_default_mgmt_key = ar6k_cfg80211_set_default_mgmt_key,
- .set_wiphy_params = ar6k_cfg80211_set_wiphy_params,
- .set_bitrate_mask = ar6k_cfg80211_set_bitrate_mask,
- .set_tx_power = ar6k_cfg80211_set_txpower,
- .get_tx_power = ar6k_cfg80211_get_txpower,
- .set_power_mgmt = ar6k_cfg80211_set_power_mgmt,
- .join_ibss = ar6k_cfg80211_join_ibss,
- .leave_ibss = ar6k_cfg80211_leave_ibss,
- .get_station = ar6k_get_station,
- .set_pmksa = ar6k_set_pmksa,
- .del_pmksa = ar6k_del_pmksa,
- .flush_pmksa = ar6k_flush_pmksa,
- CFG80211_TESTMODE_CMD(ar6k_testmode_cmd)
-};
-
-struct wireless_dev *
-ar6k_cfg80211_init(struct device *dev)
-{
- int ret = 0;
- struct wireless_dev *wdev;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: \n", __func__));
-
- wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
- if(!wdev) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("%s: Couldn't allocate wireless device\n", __func__));
- return ERR_PTR(-ENOMEM);
- }
-
- /* create a new wiphy for use with cfg80211 */
- wdev->wiphy = wiphy_new(&ar6k_cfg80211_ops, sizeof(struct ar6_softc));
- if(!wdev->wiphy) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("%s: Couldn't allocate wiphy device\n", __func__));
- kfree(wdev);
- return ERR_PTR(-ENOMEM);
- }
-
- /* set device pointer for wiphy */
- set_wiphy_dev(wdev->wiphy, dev);
-
- wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC);
- /* max num of ssids that can be probed during scanning */
- wdev->wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
- wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &ar6k_band_2ghz;
- wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &ar6k_band_5ghz;
- wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
-
- wdev->wiphy->cipher_suites = cipher_suites;
- wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
-
- ret = wiphy_register(wdev->wiphy);
- if(ret < 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
- ("%s: Couldn't register wiphy device\n", __func__));
- wiphy_free(wdev->wiphy);
- return ERR_PTR(ret);
- }
-
- return wdev;
-}
-
-void
-ar6k_cfg80211_deinit(struct ar6_softc *ar)
-{
- struct wireless_dev *wdev = ar->wdev;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s: \n", __func__));
-
- if(ar->scan_request) {
- cfg80211_scan_done(ar->scan_request, true);
- ar->scan_request = NULL;
- }
-
- if(!wdev)
- return;
-
- wiphy_unregister(wdev->wiphy);
- wiphy_free(wdev->wiphy);
- kfree(wdev);
-}
-
-
-
-
-
-
-
diff --git a/drivers/staging/ath6kl/os/linux/export_hci_transport.c b/drivers/staging/ath6kl/os/linux/export_hci_transport.c
deleted file mode 100644
index 430998edacc4..000000000000
--- a/drivers/staging/ath6kl/os/linux/export_hci_transport.c
+++ /dev/null
@@ -1,124 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2009-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// HCI bridge implementation
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#include <a_config.h>
-#include <athdefs.h>
-#include "a_osapi.h"
-#include "htc_api.h"
-#include "a_drv.h"
-#include "hif.h"
-#include "common_drv.h"
-#include "a_debug.h"
-#include "hci_transport_api.h"
-
-#include "AR6002/hw4.0/hw/apb_athr_wlan_map.h"
-#include "AR6002/hw4.0/hw/uart_reg.h"
-#include "AR6002/hw4.0/hw/rtc_wlan_reg.h"
-
-HCI_TRANSPORT_HANDLE (*_HCI_TransportAttach)(void *HTCHandle, struct hci_transport_config_info *pInfo);
-void (*_HCI_TransportDetach)(HCI_TRANSPORT_HANDLE HciTrans);
-int (*_HCI_TransportAddReceivePkts)(HCI_TRANSPORT_HANDLE HciTrans, struct htc_packet_queue *pQueue);
-int (*_HCI_TransportSendPkt)(HCI_TRANSPORT_HANDLE HciTrans, struct htc_packet *pPacket, bool Synchronous);
-void (*_HCI_TransportStop)(HCI_TRANSPORT_HANDLE HciTrans);
-int (*_HCI_TransportStart)(HCI_TRANSPORT_HANDLE HciTrans);
-int (*_HCI_TransportEnableDisableAsyncRecv)(HCI_TRANSPORT_HANDLE HciTrans, bool Enable);
-int (*_HCI_TransportRecvHCIEventSync)(HCI_TRANSPORT_HANDLE HciTrans,
- struct htc_packet *pPacket,
- int MaxPollMS);
-int (*_HCI_TransportSetBaudRate)(HCI_TRANSPORT_HANDLE HciTrans, u32 Baud);
-int (*_HCI_TransportEnablePowerMgmt)(HCI_TRANSPORT_HANDLE HciTrans, bool Enable);
-
-extern struct hci_transport_callbacks ar6kHciTransCallbacks;
-
-int ar6000_register_hci_transport(struct hci_transport_callbacks *hciTransCallbacks)
-{
- ar6kHciTransCallbacks = *hciTransCallbacks;
-
- _HCI_TransportAttach = HCI_TransportAttach;
- _HCI_TransportDetach = HCI_TransportDetach;
- _HCI_TransportAddReceivePkts = HCI_TransportAddReceivePkts;
- _HCI_TransportSendPkt = HCI_TransportSendPkt;
- _HCI_TransportStop = HCI_TransportStop;
- _HCI_TransportStart = HCI_TransportStart;
- _HCI_TransportEnableDisableAsyncRecv = HCI_TransportEnableDisableAsyncRecv;
- _HCI_TransportRecvHCIEventSync = HCI_TransportRecvHCIEventSync;
- _HCI_TransportSetBaudRate = HCI_TransportSetBaudRate;
- _HCI_TransportEnablePowerMgmt = HCI_TransportEnablePowerMgmt;
-
- return 0;
-}
-
-int
-ar6000_get_hif_dev(struct hif_device *device, void *config)
-{
- int status;
-
- status = HIFConfigureDevice(device,
- HIF_DEVICE_GET_OS_DEVICE,
- (struct hif_device_os_device_info *)config,
- sizeof(struct hif_device_os_device_info));
- return status;
-}
-
-int ar6000_set_uart_config(struct hif_device *hifDevice,
- u32 scale,
- u32 step)
-{
- u32 regAddress;
- u32 regVal;
- int status;
-
- regAddress = WLAN_UART_BASE_ADDRESS | UART_CLKDIV_ADDRESS;
- regVal = ((u32)scale << 16) | step;
- /* change the HCI UART scale/step values through the diagnostic window */
- status = ar6000_WriteRegDiag(hifDevice, &regAddress, &regVal);
-
- return status;
-}
-
-int ar6000_get_core_clock_config(struct hif_device *hifDevice, u32 *data)
-{
- u32 regAddress;
- int status;
-
- regAddress = WLAN_RTC_BASE_ADDRESS | WLAN_CPU_CLOCK_ADDRESS;
- /* read CPU clock settings*/
- status = ar6000_ReadRegDiag(hifDevice, &regAddress, data);
-
- return status;
-}
-
-EXPORT_SYMBOL(ar6000_register_hci_transport);
-EXPORT_SYMBOL(ar6000_get_hif_dev);
-EXPORT_SYMBOL(ar6000_set_uart_config);
-EXPORT_SYMBOL(ar6000_get_core_clock_config);
-EXPORT_SYMBOL(_HCI_TransportAttach);
-EXPORT_SYMBOL(_HCI_TransportDetach);
-EXPORT_SYMBOL(_HCI_TransportAddReceivePkts);
-EXPORT_SYMBOL(_HCI_TransportSendPkt);
-EXPORT_SYMBOL(_HCI_TransportStop);
-EXPORT_SYMBOL(_HCI_TransportStart);
-EXPORT_SYMBOL(_HCI_TransportEnableDisableAsyncRecv);
-EXPORT_SYMBOL(_HCI_TransportRecvHCIEventSync);
-EXPORT_SYMBOL(_HCI_TransportSetBaudRate);
-EXPORT_SYMBOL(_HCI_TransportEnablePowerMgmt);
diff --git a/drivers/staging/ath6kl/os/linux/hci_bridge.c b/drivers/staging/ath6kl/os/linux/hci_bridge.c
deleted file mode 100644
index 6087edcb1d6a..000000000000
--- a/drivers/staging/ath6kl/os/linux/hci_bridge.c
+++ /dev/null
@@ -1,1141 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2009-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// HCI bridge implementation
-//
-// Author(s): ="Atheros"
-//==============================================================================
-
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
-#include <linux/etherdevice.h>
-#include <a_config.h>
-#include <athdefs.h>
-#include "a_osapi.h"
-#include "htc_api.h"
-#include "wmi.h"
-#include "a_drv.h"
-#include "hif.h"
-#include "common_drv.h"
-#include "a_debug.h"
-#define ATH_DEBUG_HCI_BRIDGE ATH_DEBUG_MAKE_MODULE_MASK(6)
-#define ATH_DEBUG_HCI_RECV ATH_DEBUG_MAKE_MODULE_MASK(7)
-#define ATH_DEBUG_HCI_SEND ATH_DEBUG_MAKE_MODULE_MASK(8)
-#define ATH_DEBUG_HCI_DUMP ATH_DEBUG_MAKE_MODULE_MASK(9)
-#else
-#include "ar6000_drv.h"
-#endif /* EXPORT_HCI_BRIDGE_INTERFACE */
-
-#ifdef ATH_AR6K_ENABLE_GMBOX
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
-#include "export_hci_transport.h"
-#else
-#include "hci_transport_api.h"
-#endif
-#include "epping_test.h"
-#include "gmboxif.h"
-#include "ar3kconfig.h"
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-
- /* only build on newer kernels which have BT configured */
-#if defined(CONFIG_BT_MODULE) || defined(CONFIG_BT)
-#define CONFIG_BLUEZ_HCI_BRIDGE
-#endif
-
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
-unsigned int ar3khcibaud = 0;
-unsigned int hciuartscale = 0;
-unsigned int hciuartstep = 0;
-
-module_param(ar3khcibaud, int, 0644);
-module_param(hciuartscale, int, 0644);
-module_param(hciuartstep, int, 0644);
-#else
-extern unsigned int ar3khcibaud;
-extern unsigned int hciuartscale;
-extern unsigned int hciuartstep;
-#endif /* EXPORT_HCI_BRIDGE_INTERFACE */
-
-struct ar6k_hci_bridge_info {
- void *pHCIDev; /* HCI bridge device */
- struct hci_transport_properties HCIProps; /* HCI bridge props */
- struct hci_dev *pBtStackHCIDev; /* BT Stack HCI dev */
- bool HciNormalMode; /* Actual HCI mode enabled (non-TEST)*/
- bool HciRegistered; /* HCI device registered with stack */
- struct htc_packet_queue HTCPacketStructHead;
- u8 *pHTCStructAlloc;
- spinlock_t BridgeLock;
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
- struct hci_transport_misc_handles HCITransHdl;
-#else
- struct ar6_softc *ar;
-#endif /* EXPORT_HCI_BRIDGE_INTERFACE */
-};
-
-#define MAX_ACL_RECV_BUFS 16
-#define MAX_EVT_RECV_BUFS 8
-#define MAX_HCI_WRITE_QUEUE_DEPTH 32
-#define MAX_ACL_RECV_LENGTH 1200
-#define MAX_EVT_RECV_LENGTH 257
-#define TX_PACKET_RSV_OFFSET 32
-#define NUM_HTC_PACKET_STRUCTS ((MAX_ACL_RECV_BUFS + MAX_EVT_RECV_BUFS + MAX_HCI_WRITE_QUEUE_DEPTH) * 2)
-
-#define HCI_GET_OP_CODE(p) (((u16)((p)[1])) << 8) | ((u16)((p)[0]))
-
-extern unsigned int setupbtdev;
-struct ar3k_config_info ar3kconfig;
-
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
-struct ar6k_hci_bridge_info *g_pHcidevInfo;
-#endif
-
-static int bt_setup_hci(struct ar6k_hci_bridge_info *pHcidevInfo);
-static void bt_cleanup_hci(struct ar6k_hci_bridge_info *pHcidevInfo);
-static int bt_register_hci(struct ar6k_hci_bridge_info *pHcidevInfo);
-static bool bt_indicate_recv(struct ar6k_hci_bridge_info *pHcidevInfo,
- HCI_TRANSPORT_PACKET_TYPE Type,
- struct sk_buff *skb);
-static struct sk_buff *bt_alloc_buffer(struct ar6k_hci_bridge_info *pHcidevInfo, int Length);
-static void bt_free_buffer(struct ar6k_hci_bridge_info *pHcidevInfo, struct sk_buff *skb);
-
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
-int ar6000_setup_hci(void *ar);
-void ar6000_cleanup_hci(void *ar);
-int hci_test_send(void *ar, struct sk_buff *skb);
-#else
-int ar6000_setup_hci(struct ar6_softc *ar);
-void ar6000_cleanup_hci(struct ar6_softc *ar);
-/* HCI bridge testing */
-int hci_test_send(struct ar6_softc *ar, struct sk_buff *skb);
-#endif /* EXPORT_HCI_BRIDGE_INTERFACE */
-
-#define LOCK_BRIDGE(dev) spin_lock_bh(&(dev)->BridgeLock)
-#define UNLOCK_BRIDGE(dev) spin_unlock_bh(&(dev)->BridgeLock)
-
-static inline void FreeBtOsBuf(struct ar6k_hci_bridge_info *pHcidevInfo, void *osbuf)
-{
- if (pHcidevInfo->HciNormalMode) {
- bt_free_buffer(pHcidevInfo, (struct sk_buff *)osbuf);
- } else {
- /* in test mode, these are just ordinary netbuf allocations */
- A_NETBUF_FREE(osbuf);
- }
-}
-
-static void FreeHTCStruct(struct ar6k_hci_bridge_info *pHcidevInfo, struct htc_packet *pPacket)
-{
- LOCK_BRIDGE(pHcidevInfo);
- HTC_PACKET_ENQUEUE(&pHcidevInfo->HTCPacketStructHead,pPacket);
- UNLOCK_BRIDGE(pHcidevInfo);
-}
-
-static struct htc_packet * AllocHTCStruct(struct ar6k_hci_bridge_info *pHcidevInfo)
-{
- struct htc_packet *pPacket = NULL;
- LOCK_BRIDGE(pHcidevInfo);
- pPacket = HTC_PACKET_DEQUEUE(&pHcidevInfo->HTCPacketStructHead);
- UNLOCK_BRIDGE(pHcidevInfo);
- return pPacket;
-}
-
-#define BLOCK_ROUND_UP_PWR2(x, align) (((int) (x) + ((align)-1)) & ~((align)-1))
-
-static void RefillRecvBuffers(struct ar6k_hci_bridge_info *pHcidevInfo,
- HCI_TRANSPORT_PACKET_TYPE Type,
- int NumBuffers)
-{
- int length, i;
- void *osBuf = NULL;
- struct htc_packet_queue queue;
- struct htc_packet *pPacket;
-
- INIT_HTC_PACKET_QUEUE(&queue);
-
- if (Type == HCI_ACL_TYPE) {
- if (pHcidevInfo->HciNormalMode) {
- length = HCI_MAX_FRAME_SIZE;
- } else {
- length = MAX_ACL_RECV_LENGTH;
- }
- } else {
- length = MAX_EVT_RECV_LENGTH;
- }
-
- /* add on transport head and tail room */
- length += pHcidevInfo->HCIProps.HeadRoom + pHcidevInfo->HCIProps.TailRoom;
- /* round up to the required I/O padding */
- length = BLOCK_ROUND_UP_PWR2(length,pHcidevInfo->HCIProps.IOBlockPad);
-
- for (i = 0; i < NumBuffers; i++) {
-
- if (pHcidevInfo->HciNormalMode) {
- osBuf = bt_alloc_buffer(pHcidevInfo,length);
- } else {
- osBuf = A_NETBUF_ALLOC(length);
- }
-
- if (NULL == osBuf) {
- break;
- }
-
- pPacket = AllocHTCStruct(pHcidevInfo);
- if (NULL == pPacket) {
- FreeBtOsBuf(pHcidevInfo,osBuf);
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to alloc HTC struct \n"));
- break;
- }
-
- SET_HTC_PACKET_INFO_RX_REFILL(pPacket,osBuf,A_NETBUF_DATA(osBuf),length,Type);
- /* add to queue */
- HTC_PACKET_ENQUEUE(&queue,pPacket);
- }
-
- if (i > 0) {
- HCI_TransportAddReceivePkts(pHcidevInfo->pHCIDev, &queue);
- }
-}
-
-#define HOST_INTEREST_ITEM_ADDRESS(ar, item) \
- (((ar)->arTargetType == TARGET_TYPE_AR6002) ? AR6002_HOST_INTEREST_ITEM_ADDRESS(item) : \
- (((ar)->arTargetType == TARGET_TYPE_AR6003) ? AR6003_HOST_INTEREST_ITEM_ADDRESS(item) : 0))
-static int ar6000_hci_transport_ready(HCI_TRANSPORT_HANDLE HCIHandle,
- struct hci_transport_properties *pProps,
- void *pContext)
-{
- struct ar6k_hci_bridge_info *pHcidevInfo = (struct ar6k_hci_bridge_info *)pContext;
- int status;
- u32 address, hci_uart_pwr_mgmt_params;
-// struct ar3k_config_info ar3kconfig;
-
- pHcidevInfo->pHCIDev = HCIHandle;
-
- memcpy(&pHcidevInfo->HCIProps,pProps,sizeof(*pProps));
-
- AR_DEBUG_PRINTF(ATH_DEBUG_HCI_BRIDGE,("HCI ready (hci:0x%lX, headroom:%d, tailroom:%d blockpad:%d) \n",
- (unsigned long)HCIHandle,
- pHcidevInfo->HCIProps.HeadRoom,
- pHcidevInfo->HCIProps.TailRoom,
- pHcidevInfo->HCIProps.IOBlockPad));
-
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
- A_ASSERT((pProps->HeadRoom + pProps->TailRoom) <= (struct net_device *)(pHcidevInfo->HCITransHdl.netDevice)->hard_header_len);
-#else
- A_ASSERT((pProps->HeadRoom + pProps->TailRoom) <= pHcidevInfo->ar->arNetDev->hard_header_len);
-#endif
-
- /* provide buffers */
- RefillRecvBuffers(pHcidevInfo, HCI_ACL_TYPE, MAX_ACL_RECV_BUFS);
- RefillRecvBuffers(pHcidevInfo, HCI_EVENT_TYPE, MAX_EVT_RECV_BUFS);
-
- do {
- /* start transport */
- status = HCI_TransportStart(pHcidevInfo->pHCIDev);
-
- if (status) {
- break;
- }
-
- if (!pHcidevInfo->HciNormalMode) {
- /* in test mode, no need to go any further */
- break;
- }
-
- // The delay is required when AR6K is driving the BT reset line
- // where time is needed after the BT chip is out of reset (HCI_TransportStart)
- // and before the first HCI command is issued (AR3KConfigure)
- // FIXME
- // The delay should be configurable and be only applied when AR6K driving the BT
- // reset line. This could be done by some module parameter or based on some HW config
- // info. For now apply 100ms delay blindly
- A_MDELAY(100);
-
- A_MEMZERO(&ar3kconfig,sizeof(ar3kconfig));
- ar3kconfig.pHCIDev = pHcidevInfo->pHCIDev;
- ar3kconfig.pHCIProps = &pHcidevInfo->HCIProps;
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
- ar3kconfig.pHIFDevice = (struct hif_device *)(pHcidevInfo->HCITransHdl.hifDevice);
-#else
- ar3kconfig.pHIFDevice = pHcidevInfo->ar->arHifDevice;
-#endif
- ar3kconfig.pBtStackHCIDev = pHcidevInfo->pBtStackHCIDev;
-
- if (ar3khcibaud != 0) {
- /* user wants ar3k baud rate change */
- ar3kconfig.Flags |= AR3K_CONFIG_FLAG_SET_AR3K_BAUD;
- ar3kconfig.Flags |= AR3K_CONFIG_FLAG_AR3K_BAUD_CHANGE_DELAY;
- ar3kconfig.AR3KBaudRate = ar3khcibaud;
- }
-
- if ((hciuartscale != 0) || (hciuartstep != 0)) {
- /* user wants to tune HCI bridge UART scale/step values */
- ar3kconfig.AR6KScale = (u16)hciuartscale;
- ar3kconfig.AR6KStep = (u16)hciuartstep;
- ar3kconfig.Flags |= AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP;
- }
-
- /* Fetch the address of the hi_hci_uart_pwr_mgmt_params instance in the host interest area */
- address = TARG_VTOP(pHcidevInfo->ar->arTargetType,
- HOST_INTEREST_ITEM_ADDRESS(pHcidevInfo->ar, hi_hci_uart_pwr_mgmt_params));
- status = ar6000_ReadRegDiag(pHcidevInfo->ar->arHifDevice, &address, &hci_uart_pwr_mgmt_params);
- if (0 == status) {
- ar3kconfig.PwrMgmtEnabled = (hci_uart_pwr_mgmt_params & 0x1);
- ar3kconfig.IdleTimeout = (hci_uart_pwr_mgmt_params & 0xFFFF0000) >> 16;
- ar3kconfig.WakeupTimeout = (hci_uart_pwr_mgmt_params & 0xFF00) >> 8;
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge: failed to read hci_uart_pwr_mgmt_params! \n"));
- }
- /* configure the AR3K device */
- memcpy(ar3kconfig.bdaddr,pHcidevInfo->ar->bdaddr,6);
- status = AR3KConfigure(&ar3kconfig);
- if (status) {
- break;
- }
-
- /* Make sure both AR6K and AR3K have power management enabled */
- if (ar3kconfig.PwrMgmtEnabled) {
- status = HCI_TransportEnablePowerMgmt(pHcidevInfo->pHCIDev, true);
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge: failed to enable TLPM for AR6K! \n"));
- }
- }
-
- status = bt_register_hci(pHcidevInfo);
-
- } while (false);
-
- return status;
-}
-
-static void ar6000_hci_transport_failure(void *pContext, int Status)
-{
- struct ar6k_hci_bridge_info *pHcidevInfo = (struct ar6k_hci_bridge_info *)pContext;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge: transport failure! \n"));
-
- if (pHcidevInfo->HciNormalMode) {
- /* TODO .. */
- }
-}
-
-static void ar6000_hci_transport_removed(void *pContext)
-{
- struct ar6k_hci_bridge_info *pHcidevInfo = (struct ar6k_hci_bridge_info *)pContext;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_HCI_BRIDGE, ("HCI Bridge: transport removed. \n"));
-
- A_ASSERT(pHcidevInfo->pHCIDev != NULL);
-
- HCI_TransportDetach(pHcidevInfo->pHCIDev);
- bt_cleanup_hci(pHcidevInfo);
- pHcidevInfo->pHCIDev = NULL;
-}
-
-static void ar6000_hci_send_complete(void *pContext, struct htc_packet *pPacket)
-{
- struct ar6k_hci_bridge_info *pHcidevInfo = (struct ar6k_hci_bridge_info *)pContext;
- void *osbuf = pPacket->pPktContext;
- A_ASSERT(osbuf != NULL);
- A_ASSERT(pHcidevInfo != NULL);
-
- if (pPacket->Status) {
- if ((pPacket->Status != A_ECANCELED) && (pPacket->Status != A_NO_RESOURCE)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge: Send Packet Failed: %d \n",pPacket->Status));
- }
- }
-
- FreeHTCStruct(pHcidevInfo,pPacket);
- FreeBtOsBuf(pHcidevInfo,osbuf);
-
-}
-
-static void ar6000_hci_pkt_recv(void *pContext, struct htc_packet *pPacket)
-{
- struct ar6k_hci_bridge_info *pHcidevInfo = (struct ar6k_hci_bridge_info *)pContext;
- struct sk_buff *skb;
-
- A_ASSERT(pHcidevInfo != NULL);
- skb = (struct sk_buff *)pPacket->pPktContext;
- A_ASSERT(skb != NULL);
-
- do {
-
- if (pPacket->Status) {
- break;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_HCI_RECV,
- ("HCI Bridge, packet received type : %d len:%d \n",
- HCI_GET_PACKET_TYPE(pPacket),pPacket->ActualLength));
-
- /* set the actual buffer position in the os buffer, HTC recv buffers posted to HCI are set
- * to fill the front of the buffer */
- A_NETBUF_PUT(skb,pPacket->ActualLength + pHcidevInfo->HCIProps.HeadRoom);
- A_NETBUF_PULL(skb,pHcidevInfo->HCIProps.HeadRoom);
-
- if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_HCI_DUMP)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("<<< Recv HCI %s packet len:%d \n",
- (HCI_GET_PACKET_TYPE(pPacket) == HCI_EVENT_TYPE) ? "EVENT" : "ACL",
- skb->len));
- AR_DEBUG_PRINTBUF(skb->data, skb->len,"BT HCI RECV Packet Dump");
- }
-
- if (pHcidevInfo->HciNormalMode) {
- /* indicate the packet */
- if (bt_indicate_recv(pHcidevInfo,HCI_GET_PACKET_TYPE(pPacket),skb)) {
- /* bt stack accepted the packet */
- skb = NULL;
- }
- break;
- }
-
- /* for testing, indicate packet to the network stack */
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
- skb->dev = (struct net_device *)(pHcidevInfo->HCITransHdl.netDevice);
- if ((((struct net_device *)pHcidevInfo->HCITransHdl.netDevice)->flags & IFF_UP) == IFF_UP) {
- skb->protocol = eth_type_trans(skb, (struct net_device *)(pHcidevInfo->HCITransHdl.netDevice));
-#else
- skb->dev = pHcidevInfo->ar->arNetDev;
- if ((pHcidevInfo->ar->arNetDev->flags & IFF_UP) == IFF_UP) {
- skb->protocol = eth_type_trans(skb, pHcidevInfo->ar->arNetDev);
-#endif
- netif_rx(skb);
- skb = NULL;
- }
-
- } while (false);
-
- FreeHTCStruct(pHcidevInfo,pPacket);
-
- if (skb != NULL) {
- /* packet was not accepted, free it */
- FreeBtOsBuf(pHcidevInfo,skb);
- }
-
-}
-
-static void ar6000_hci_pkt_refill(void *pContext, HCI_TRANSPORT_PACKET_TYPE Type, int BuffersAvailable)
-{
- struct ar6k_hci_bridge_info *pHcidevInfo = (struct ar6k_hci_bridge_info *)pContext;
- int refillCount;
-
- if (Type == HCI_ACL_TYPE) {
- refillCount = MAX_ACL_RECV_BUFS - BuffersAvailable;
- } else {
- refillCount = MAX_EVT_RECV_BUFS - BuffersAvailable;
- }
-
- if (refillCount > 0) {
- RefillRecvBuffers(pHcidevInfo,Type,refillCount);
- }
-
-}
-
-static HCI_SEND_FULL_ACTION ar6000_hci_pkt_send_full(void *pContext, struct htc_packet *pPacket)
-{
- struct ar6k_hci_bridge_info *pHcidevInfo = (struct ar6k_hci_bridge_info *)pContext;
- HCI_SEND_FULL_ACTION action = HCI_SEND_FULL_KEEP;
-
- if (!pHcidevInfo->HciNormalMode) {
- /* for epping testing, check packet tag, some epping packets are
- * special and cannot be dropped */
- if (HTC_GET_TAG_FROM_PKT(pPacket) == AR6K_DATA_PKT_TAG) {
- action = HCI_SEND_FULL_DROP;
- }
- }
-
- return action;
-}
-
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
-int ar6000_setup_hci(void *ar)
-#else
-int ar6000_setup_hci(struct ar6_softc *ar)
-#endif
-{
- struct hci_transport_config_info config;
- int status = 0;
- int i;
- struct htc_packet *pPacket;
- struct ar6k_hci_bridge_info *pHcidevInfo;
-
-
- do {
-
- pHcidevInfo = (struct ar6k_hci_bridge_info *)A_MALLOC(sizeof(struct ar6k_hci_bridge_info));
-
- if (NULL == pHcidevInfo) {
- status = A_NO_MEMORY;
- break;
- }
-
- A_MEMZERO(pHcidevInfo, sizeof(struct ar6k_hci_bridge_info));
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
- g_pHcidevInfo = pHcidevInfo;
- pHcidevInfo->HCITransHdl = *(struct hci_transport_misc_handles *)ar;
-#else
- ar->hcidev_info = pHcidevInfo;
- pHcidevInfo->ar = ar;
-#endif
- spin_lock_init(&pHcidevInfo->BridgeLock);
- INIT_HTC_PACKET_QUEUE(&pHcidevInfo->HTCPacketStructHead);
-
- ar->exitCallback = AR3KConfigureExit;
-
- status = bt_setup_hci(pHcidevInfo);
- if (status) {
- break;
- }
-
- if (pHcidevInfo->HciNormalMode) {
- AR_DEBUG_PRINTF(ATH_DEBUG_HCI_BRIDGE, ("HCI Bridge: running in normal mode... \n"));
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_HCI_BRIDGE, ("HCI Bridge: running in test mode... \n"));
- }
-
- pHcidevInfo->pHTCStructAlloc = (u8 *)A_MALLOC((sizeof(struct htc_packet)) * NUM_HTC_PACKET_STRUCTS);
-
- if (NULL == pHcidevInfo->pHTCStructAlloc) {
- status = A_NO_MEMORY;
- break;
- }
-
- pPacket = (struct htc_packet *)pHcidevInfo->pHTCStructAlloc;
- for (i = 0; i < NUM_HTC_PACKET_STRUCTS; i++,pPacket++) {
- FreeHTCStruct(pHcidevInfo,pPacket);
- }
-
- A_MEMZERO(&config,sizeof(struct hci_transport_config_info));
- config.ACLRecvBufferWaterMark = MAX_ACL_RECV_BUFS / 2;
- config.EventRecvBufferWaterMark = MAX_EVT_RECV_BUFS / 2;
- config.MaxSendQueueDepth = MAX_HCI_WRITE_QUEUE_DEPTH;
- config.pContext = pHcidevInfo;
- config.TransportFailure = ar6000_hci_transport_failure;
- config.TransportReady = ar6000_hci_transport_ready;
- config.TransportRemoved = ar6000_hci_transport_removed;
- config.pHCISendComplete = ar6000_hci_send_complete;
- config.pHCIPktRecv = ar6000_hci_pkt_recv;
- config.pHCIPktRecvRefill = ar6000_hci_pkt_refill;
- config.pHCISendFull = ar6000_hci_pkt_send_full;
-
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
- pHcidevInfo->pHCIDev = HCI_TransportAttach(pHcidevInfo->HCITransHdl.htcHandle, &config);
-#else
- pHcidevInfo->pHCIDev = HCI_TransportAttach(ar->arHtcTarget, &config);
-#endif
-
- if (NULL == pHcidevInfo->pHCIDev) {
- status = A_ERROR;
- }
-
- } while (false);
-
- if (status) {
- if (pHcidevInfo != NULL) {
- if (NULL == pHcidevInfo->pHCIDev) {
- /* GMBOX may not be present in older chips */
- /* just return success */
- status = 0;
- }
- }
- ar6000_cleanup_hci(ar);
- }
-
- return status;
-}
-
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
-void ar6000_cleanup_hci(void *ar)
-#else
-void ar6000_cleanup_hci(struct ar6_softc *ar)
-#endif
-{
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
- struct ar6k_hci_bridge_info *pHcidevInfo = g_pHcidevInfo;
-#else
- struct ar6k_hci_bridge_info *pHcidevInfo = (struct ar6k_hci_bridge_info *)ar->hcidev_info;
-#endif
-
- if (pHcidevInfo != NULL) {
- bt_cleanup_hci(pHcidevInfo);
-
- if (pHcidevInfo->pHCIDev != NULL) {
- HCI_TransportStop(pHcidevInfo->pHCIDev);
- HCI_TransportDetach(pHcidevInfo->pHCIDev);
- pHcidevInfo->pHCIDev = NULL;
- }
-
- if (pHcidevInfo->pHTCStructAlloc != NULL) {
- kfree(pHcidevInfo->pHTCStructAlloc);
- pHcidevInfo->pHTCStructAlloc = NULL;
- }
-
- kfree(pHcidevInfo);
-#ifndef EXPORT_HCI_BRIDGE_INTERFACE
- ar->hcidev_info = NULL;
-#endif
- }
-
-
-}
-
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
-int hci_test_send(void *ar, struct sk_buff *skb)
-#else
-int hci_test_send(struct ar6_softc *ar, struct sk_buff *skb)
-#endif
-{
- int status = 0;
- int length;
- EPPING_HEADER *pHeader;
- struct htc_packet *pPacket;
- HTC_TX_TAG htc_tag = AR6K_DATA_PKT_TAG;
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
- struct ar6k_hci_bridge_info *pHcidevInfo = g_pHcidevInfo;
-#else
- struct ar6k_hci_bridge_info *pHcidevInfo = (struct ar6k_hci_bridge_info *)ar->hcidev_info;
-#endif
-
- do {
-
- if (NULL == pHcidevInfo) {
- status = A_ERROR;
- break;
- }
-
- if (NULL == pHcidevInfo->pHCIDev) {
- status = A_ERROR;
- break;
- }
-
- if (pHcidevInfo->HciNormalMode) {
- /* this interface cannot run when normal WMI is running */
- status = A_ERROR;
- break;
- }
-
- pHeader = (EPPING_HEADER *)A_NETBUF_DATA(skb);
-
- if (!IS_EPPING_PACKET(pHeader)) {
- status = A_EINVAL;
- break;
- }
-
- if (IS_EPING_PACKET_NO_DROP(pHeader)) {
- htc_tag = AR6K_CONTROL_PKT_TAG;
- }
-
- length = sizeof(EPPING_HEADER) + pHeader->DataLength;
-
- pPacket = AllocHTCStruct(pHcidevInfo);
- if (NULL == pPacket) {
- status = A_NO_MEMORY;
- break;
- }
-
- SET_HTC_PACKET_INFO_TX(pPacket,
- skb,
- A_NETBUF_DATA(skb),
- length,
- HCI_ACL_TYPE, /* send every thing out as ACL */
- htc_tag);
-
- HCI_TransportSendPkt(pHcidevInfo->pHCIDev,pPacket,false);
- pPacket = NULL;
-
- } while (false);
-
- return status;
-}
-
-void ar6000_set_default_ar3kconfig(struct ar6_softc *ar, void *ar3kconfig)
-{
- struct ar6k_hci_bridge_info *pHcidevInfo = (struct ar6k_hci_bridge_info *)ar->hcidev_info;
- struct ar3k_config_info *config = (struct ar3k_config_info *)ar3kconfig;
-
- config->pHCIDev = pHcidevInfo->pHCIDev;
- config->pHCIProps = &pHcidevInfo->HCIProps;
- config->pHIFDevice = ar->arHifDevice;
- config->pBtStackHCIDev = pHcidevInfo->pBtStackHCIDev;
- config->Flags |= AR3K_CONFIG_FLAG_SET_AR3K_BAUD;
- config->AR3KBaudRate = 115200;
-}
-
-#ifdef CONFIG_BLUEZ_HCI_BRIDGE
-/*** BT Stack Entrypoints *******/
-
-/*
- * bt_open - open a handle to the device
-*/
-static int bt_open(struct hci_dev *hdev)
-{
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HCI Bridge: bt_open - enter - x\n"));
- set_bit(HCI_RUNNING, &hdev->flags);
- set_bit(HCI_UP, &hdev->flags);
- set_bit(HCI_INIT, &hdev->flags);
- return 0;
-}
-
-/*
- * bt_close - close handle to the device
-*/
-static int bt_close(struct hci_dev *hdev)
-{
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HCI Bridge: bt_close - enter\n"));
- clear_bit(HCI_RUNNING, &hdev->flags);
- return 0;
-}
-
-/*
- * bt_send_frame - send data frames
-*/
-static int bt_send_frame(struct sk_buff *skb)
-{
- struct hci_dev *hdev = (struct hci_dev *)skb->dev;
- HCI_TRANSPORT_PACKET_TYPE type;
- struct ar6k_hci_bridge_info *pHcidevInfo;
- struct htc_packet *pPacket;
- int status = 0;
- struct sk_buff *txSkb = NULL;
-
- if (!hdev) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("HCI Bridge: bt_send_frame - no device\n"));
- return -ENODEV;
- }
-
- if (!test_bit(HCI_RUNNING, &hdev->flags)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HCI Bridge: bt_send_frame - not open\n"));
- return -EBUSY;
- }
-
- pHcidevInfo = (struct ar6k_hci_bridge_info *)hdev->driver_data;
- A_ASSERT(pHcidevInfo != NULL);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_HCI_SEND, ("+bt_send_frame type: %d \n",bt_cb(skb)->pkt_type));
- type = HCI_COMMAND_TYPE;
-
- switch (bt_cb(skb)->pkt_type) {
- case HCI_COMMAND_PKT:
- type = HCI_COMMAND_TYPE;
- hdev->stat.cmd_tx++;
- break;
-
- case HCI_ACLDATA_PKT:
- type = HCI_ACL_TYPE;
- hdev->stat.acl_tx++;
- break;
-
- case HCI_SCODATA_PKT:
- /* we don't support SCO over the bridge */
- kfree_skb(skb);
- return 0;
- default:
- A_ASSERT(false);
- kfree_skb(skb);
- return 0;
- }
-
- if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_HCI_DUMP)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,(">>> Send HCI %s packet len: %d\n",
- (type == HCI_COMMAND_TYPE) ? "COMMAND" : "ACL",
- skb->len));
- if (type == HCI_COMMAND_TYPE) {
- u16 opcode = HCI_GET_OP_CODE(skb->data);
- AR_DEBUG_PRINTF(ATH_DEBUG_ANY,(" HCI Command: OGF:0x%X OCF:0x%X \r\n",
- opcode >> 10, opcode & 0x3FF));
- }
- AR_DEBUG_PRINTBUF(skb->data,skb->len,"BT HCI SEND Packet Dump");
- }
-
- do {
-
- txSkb = bt_skb_alloc(TX_PACKET_RSV_OFFSET + pHcidevInfo->HCIProps.HeadRoom +
- pHcidevInfo->HCIProps.TailRoom + skb->len,
- GFP_ATOMIC);
-
- if (txSkb == NULL) {
- status = A_NO_MEMORY;
- break;
- }
-
- bt_cb(txSkb)->pkt_type = bt_cb(skb)->pkt_type;
- txSkb->dev = (void *)pHcidevInfo->pBtStackHCIDev;
- skb_reserve(txSkb, TX_PACKET_RSV_OFFSET + pHcidevInfo->HCIProps.HeadRoom);
- memcpy(txSkb->data, skb->data, skb->len);
- skb_put(txSkb,skb->len);
-
- pPacket = AllocHTCStruct(pHcidevInfo);
- if (NULL == pPacket) {
- status = A_NO_MEMORY;
- break;
- }
-
- /* HCI packet length here doesn't include the 1-byte transport header which
- * will be handled by the HCI transport layer. Enough headroom has already
- * been reserved above for the transport header
- */
- SET_HTC_PACKET_INFO_TX(pPacket,
- txSkb,
- txSkb->data,
- txSkb->len,
- type,
- AR6K_CONTROL_PKT_TAG); /* HCI packets cannot be dropped */
-
- AR_DEBUG_PRINTF(ATH_DEBUG_HCI_SEND, ("HCI Bridge: bt_send_frame skb:0x%lX \n",(unsigned long)txSkb));
- AR_DEBUG_PRINTF(ATH_DEBUG_HCI_SEND, ("HCI Bridge: type:%d, Total Length:%d Bytes \n",
- type, txSkb->len));
-
- status = HCI_TransportSendPkt(pHcidevInfo->pHCIDev,pPacket,false);
- pPacket = NULL;
- txSkb = NULL;
-
- } while (false);
-
- if (txSkb != NULL) {
- kfree_skb(txSkb);
- }
-
- kfree_skb(skb);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_HCI_SEND, ("-bt_send_frame \n"));
- return 0;
-}
-
-/*
- * bt_ioctl - ioctl processing
-*/
-static int bt_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
-{
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HCI Bridge: bt_ioctl - enter\n"));
- return -ENOIOCTLCMD;
-}
-
-/*
- * bt_flush - flush outstandingbpackets
-*/
-static int bt_flush(struct hci_dev *hdev)
-{
- struct ar6k_hci_bridge_info *pHcidevInfo;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HCI Bridge: bt_flush - enter\n"));
-
- pHcidevInfo = (struct ar6k_hci_bridge_info *)hdev->driver_data;
-
- /* TODO??? */
-
- return 0;
-}
-
-
-/*
- * bt_destruct -
-*/
-static void bt_destruct(struct hci_dev *hdev)
-{
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HCI Bridge: bt_destruct - enter\n"));
- /* nothing to do here */
-}
-
-static int bt_setup_hci(struct ar6k_hci_bridge_info *pHcidevInfo)
-{
- int status = 0;
- struct hci_dev *pHciDev = NULL;
- struct hif_device_os_device_info osDevInfo;
-
- if (!setupbtdev) {
- return 0;
- }
-
- do {
-
- A_MEMZERO(&osDevInfo,sizeof(osDevInfo));
- /* get the underlying OS device */
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
- status = ar6000_get_hif_dev((struct hif_device *)(pHcidevInfo->HCITransHdl.hifDevice),
- &osDevInfo);
-#else
- status = HIFConfigureDevice(pHcidevInfo->ar->arHifDevice,
- HIF_DEVICE_GET_OS_DEVICE,
- &osDevInfo,
- sizeof(osDevInfo));
-#endif
-
- if (status) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to OS device info from HIF\n"));
- break;
- }
-
- /* allocate a BT HCI struct for this device */
- pHciDev = hci_alloc_dev();
- if (NULL == pHciDev) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge - failed to allocate bt struct \n"));
- status = A_NO_MEMORY;
- break;
- }
- /* save the device, we'll register this later */
- pHcidevInfo->pBtStackHCIDev = pHciDev;
- SET_HCIDEV_DEV(pHciDev,osDevInfo.pOSDevice);
- SET_HCI_BUS_TYPE(pHciDev, HCI_VIRTUAL, HCI_BREDR);
- pHciDev->driver_data = pHcidevInfo;
- pHciDev->open = bt_open;
- pHciDev->close = bt_close;
- pHciDev->send = bt_send_frame;
- pHciDev->ioctl = bt_ioctl;
- pHciDev->flush = bt_flush;
- pHciDev->destruct = bt_destruct;
- pHciDev->owner = THIS_MODULE;
- /* driver is running in normal BT mode */
- pHcidevInfo->HciNormalMode = true;
-
- } while (false);
-
- if (status) {
- bt_cleanup_hci(pHcidevInfo);
- }
-
- return status;
-}
-
-static void bt_cleanup_hci(struct ar6k_hci_bridge_info *pHcidevInfo)
-{
- int err;
-
- if (pHcidevInfo->HciRegistered) {
- pHcidevInfo->HciRegistered = false;
- clear_bit(HCI_RUNNING, &pHcidevInfo->pBtStackHCIDev->flags);
- clear_bit(HCI_UP, &pHcidevInfo->pBtStackHCIDev->flags);
- clear_bit(HCI_INIT, &pHcidevInfo->pBtStackHCIDev->flags);
- A_ASSERT(pHcidevInfo->pBtStackHCIDev != NULL);
- /* unregister */
- if ((err = hci_unregister_dev(pHcidevInfo->pBtStackHCIDev)) < 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge: failed to unregister with bluetooth %d\n",err));
- }
- }
-
- kfree(pHcidevInfo->pBtStackHCIDev);
- pHcidevInfo->pBtStackHCIDev = NULL;
-}
-
-static int bt_register_hci(struct ar6k_hci_bridge_info *pHcidevInfo)
-{
- int err;
- int status = 0;
-
- do {
- AR_DEBUG_PRINTF(ATH_DEBUG_HCI_BRIDGE, ("HCI Bridge: registering HCI... \n"));
- A_ASSERT(pHcidevInfo->pBtStackHCIDev != NULL);
- /* mark that we are registered */
- pHcidevInfo->HciRegistered = true;
- if ((err = hci_register_dev(pHcidevInfo->pBtStackHCIDev)) < 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge: failed to register with bluetooth %d\n",err));
- pHcidevInfo->HciRegistered = false;
- status = A_ERROR;
- break;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_HCI_BRIDGE, ("HCI Bridge: HCI registered \n"));
-
- } while (false);
-
- return status;
-}
-
-static bool bt_indicate_recv(struct ar6k_hci_bridge_info *pHcidevInfo,
- HCI_TRANSPORT_PACKET_TYPE Type,
- struct sk_buff *skb)
-{
- u8 btType;
- int len;
- bool success = false;
- BT_HCI_EVENT_HEADER *pEvent;
-
- do {
-
- if (!test_bit(HCI_RUNNING, &pHcidevInfo->pBtStackHCIDev->flags)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("HCI Bridge: bt_indicate_recv - not running\n"));
- break;
- }
-
- switch (Type) {
- case HCI_ACL_TYPE:
- btType = HCI_ACLDATA_PKT;
- break;
- case HCI_EVENT_TYPE:
- btType = HCI_EVENT_PKT;
- break;
- default:
- btType = 0;
- A_ASSERT(false);
- break;
- }
-
- if (0 == btType) {
- break;
- }
-
- /* set the final type */
- bt_cb(skb)->pkt_type = btType;
- /* set dev */
- skb->dev = (void *)pHcidevInfo->pBtStackHCIDev;
- len = skb->len;
-
- if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_HCI_RECV)) {
- if (bt_cb(skb)->pkt_type == HCI_EVENT_PKT) {
- pEvent = (BT_HCI_EVENT_HEADER *)skb->data;
- AR_DEBUG_PRINTF(ATH_DEBUG_HCI_RECV, ("BT HCI EventCode: %d, len:%d \n",
- pEvent->EventCode, pEvent->ParamLength));
- }
- }
-
- /* pass receive packet up the stack */
- if (hci_recv_frame(skb) != 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge: hci_recv_frame failed \n"));
- break;
- } else {
- AR_DEBUG_PRINTF(ATH_DEBUG_HCI_RECV,
- ("HCI Bridge: Indicated RCV of type:%d, Length:%d \n",btType,len));
- }
-
- success = true;
-
- } while (false);
-
- return success;
-}
-
-static struct sk_buff* bt_alloc_buffer(struct ar6k_hci_bridge_info *pHcidevInfo, int Length)
-{
- struct sk_buff *skb;
- /* in normal HCI mode we need to alloc from the bt core APIs */
- skb = bt_skb_alloc(Length, GFP_ATOMIC);
- if (NULL == skb) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to alloc bt sk_buff \n"));
- }
- return skb;
-}
-
-static void bt_free_buffer(struct ar6k_hci_bridge_info *pHcidevInfo, struct sk_buff *skb)
-{
- kfree_skb(skb);
-}
-
-#else // { CONFIG_BLUEZ_HCI_BRIDGE
-
- /* stubs when we only want to test the HCI bridging Interface without the HT stack */
-static int bt_setup_hci(struct ar6k_hci_bridge_info *pHcidevInfo)
-{
- return 0;
-}
-static void bt_cleanup_hci(struct ar6k_hci_bridge_info *pHcidevInfo)
-{
-
-}
-static int bt_register_hci(struct ar6k_hci_bridge_info *pHcidevInfo)
-{
- A_ASSERT(false);
- return A_ERROR;
-}
-
-static bool bt_indicate_recv(struct ar6k_hci_bridge_info *pHcidevInfo,
- HCI_TRANSPORT_PACKET_TYPE Type,
- struct sk_buff *skb)
-{
- A_ASSERT(false);
- return false;
-}
-
-static struct sk_buff* bt_alloc_buffer(struct ar6k_hci_bridge_info *pHcidevInfo, int Length)
-{
- A_ASSERT(false);
- return NULL;
-}
-static void bt_free_buffer(struct ar6k_hci_bridge_info *pHcidevInfo, struct sk_buff *skb)
-{
- A_ASSERT(false);
-}
-
-#endif // } CONFIG_BLUEZ_HCI_BRIDGE
-
-#else // { ATH_AR6K_ENABLE_GMBOX
-
- /* stubs when GMBOX support is not needed */
-
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
-int ar6000_setup_hci(void *ar)
-#else
-int ar6000_setup_hci(struct ar6_softc *ar)
-#endif
-{
- return 0;
-}
-
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
-void ar6000_cleanup_hci(void *ar)
-#else
-void ar6000_cleanup_hci(struct ar6_softc *ar)
-#endif
-{
- return;
-}
-
-#ifndef EXPORT_HCI_BRIDGE_INTERFACE
-void ar6000_set_default_ar3kconfig(struct ar6_softc *ar, void *ar3kconfig)
-{
- return;
-}
-#endif
-
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
-int hci_test_send(void *ar, struct sk_buff *skb)
-#else
-int hci_test_send(struct ar6_softc *ar, struct sk_buff *skb)
-#endif
-{
- return -EOPNOTSUPP;
-}
-
-#endif // } ATH_AR6K_ENABLE_GMBOX
-
-
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
-static int __init
-hcibridge_init_module(void)
-{
- int status;
- struct hci_transport_callbacks hciTransCallbacks;
-
- hciTransCallbacks.setupTransport = ar6000_setup_hci;
- hciTransCallbacks.cleanupTransport = ar6000_cleanup_hci;
-
- status = ar6000_register_hci_transport(&hciTransCallbacks);
- if (status)
- return -ENODEV;
-
- return 0;
-}
-
-static void __exit
-hcibridge_cleanup_module(void)
-{
-}
-
-module_init(hcibridge_init_module);
-module_exit(hcibridge_cleanup_module);
-MODULE_LICENSE("Dual BSD/GPL");
-#endif
diff --git a/drivers/staging/ath6kl/os/linux/include/ar6000_drv.h b/drivers/staging/ath6kl/os/linux/include/ar6000_drv.h
deleted file mode 100644
index 80cef77738fb..000000000000
--- a/drivers/staging/ath6kl/os/linux/include/ar6000_drv.h
+++ /dev/null
@@ -1,776 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Communications Inc.
-// All rights reserved.
-//
-//
-//
-// 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.
-//
-//
-//
-// Author(s): ="Atheros"
-//------------------------------------------------------------------------------
-
-#ifndef _AR6000_H_
-#define _AR6000_H_
-
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/if_ether.h>
-#include <linux/etherdevice.h>
-#include <net/iw_handler.h>
-#include <linux/if_arp.h>
-#include <linux/ip.h>
-#include <linux/wireless.h>
-#include <net/cfg80211.h>
-#include <linux/module.h>
-#include <asm/io.h>
-
-#include <a_config.h>
-#include <athdefs.h>
-#include "a_osapi.h"
-#include "htc_api.h"
-#include "wmi.h"
-#include "a_drv.h"
-#include "bmi.h"
-#include <ieee80211.h>
-#include <ieee80211_ioctl.h>
-#include <wlan_api.h>
-#include <wmi_api.h>
-#include "pkt_log.h"
-#include "aggr_recv_api.h"
-#include <host_version.h>
-#include <linux/rtnetlink.h>
-#include <linux/moduleparam.h>
-#include "ar6000_api.h"
-#ifdef CONFIG_HOST_TCMD_SUPPORT
-#include <testcmd.h>
-#endif
-#include <linux/firmware.h>
-
-#include "targaddrs.h"
-#include "dbglog_api.h"
-#include "ar6000_diag.h"
-#include "common_drv.h"
-#include "roaming.h"
-#include "hci_transport_api.h"
-#define ATH_MODULE_NAME driver
-#include "a_debug.h"
-#include "hw/apb_map.h"
-#include "hw/rtc_reg.h"
-#include "hw/mbox_reg.h"
-#include "gpio_reg.h"
-
-#define ATH_DEBUG_DBG_LOG ATH_DEBUG_MAKE_MODULE_MASK(0)
-#define ATH_DEBUG_WLAN_CONNECT ATH_DEBUG_MAKE_MODULE_MASK(1)
-#define ATH_DEBUG_WLAN_SCAN ATH_DEBUG_MAKE_MODULE_MASK(2)
-#define ATH_DEBUG_WLAN_TX ATH_DEBUG_MAKE_MODULE_MASK(3)
-#define ATH_DEBUG_WLAN_RX ATH_DEBUG_MAKE_MODULE_MASK(4)
-#define ATH_DEBUG_HTC_RAW ATH_DEBUG_MAKE_MODULE_MASK(5)
-#define ATH_DEBUG_HCI_BRIDGE ATH_DEBUG_MAKE_MODULE_MASK(6)
-#define ATH_DEBUG_HCI_RECV ATH_DEBUG_MAKE_MODULE_MASK(7)
-#define ATH_DEBUG_HCI_SEND ATH_DEBUG_MAKE_MODULE_MASK(8)
-#define ATH_DEBUG_HCI_DUMP ATH_DEBUG_MAKE_MODULE_MASK(9)
-
-#ifndef __dev_put
-#define __dev_put(dev) dev_put(dev)
-#endif
-
-
-#define USER_SAVEDKEYS_STAT_INIT 0
-#define USER_SAVEDKEYS_STAT_RUN 1
-
-// TODO this needs to move into the AR_SOFTC struct
-struct USER_SAVEDKEYS {
- struct ieee80211req_key ucast_ik;
- struct ieee80211req_key bcast_ik;
- CRYPTO_TYPE keyType;
- bool keyOk;
-};
-
-#define DBG_INFO 0x00000001
-#define DBG_ERROR 0x00000002
-#define DBG_WARNING 0x00000004
-#define DBG_SDIO 0x00000008
-#define DBG_HIF 0x00000010
-#define DBG_HTC 0x00000020
-#define DBG_WMI 0x00000040
-#define DBG_WMI2 0x00000080
-#define DBG_DRIVER 0x00000100
-
-#define DBG_DEFAULTS (DBG_ERROR|DBG_WARNING)
-
-
-int ar6000_ReadRegDiag(struct hif_device *hifDevice, u32 *address, u32 *data);
-int ar6000_WriteRegDiag(struct hif_device *hifDevice, u32 *address, u32 *data);
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define MAX_AR6000 1
-#define AR6000_MAX_RX_BUFFERS 16
-#define AR6000_BUFFER_SIZE 1664
-#define AR6000_MAX_AMSDU_RX_BUFFERS 4
-#define AR6000_AMSDU_REFILL_THRESHOLD 3
-#define AR6000_AMSDU_BUFFER_SIZE (WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH + 128)
-#define AR6000_MAX_RX_MESSAGE_SIZE (max(WMI_MAX_NORMAL_RX_DATA_FRAME_LENGTH,WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH))
-
-#define AR6000_TX_TIMEOUT 10
-#define AR6000_ETH_ADDR_LEN 6
-#define AR6000_MAX_ENDPOINTS 4
-#define MAX_NODE_NUM 15
-/* MAX_HI_COOKIE_NUM are reserved for high priority traffic */
-#define MAX_DEF_COOKIE_NUM 180
-#define MAX_HI_COOKIE_NUM 18 /* 10% of MAX_COOKIE_NUM */
-#define MAX_COOKIE_NUM (MAX_DEF_COOKIE_NUM + MAX_HI_COOKIE_NUM)
-
-/* MAX_DEFAULT_SEND_QUEUE_DEPTH is used to set the default queue depth for the
- * WMM send queues. If a queue exceeds this depth htc will query back to the
- * OS specific layer by calling EpSendFull(). This gives the OS layer the
- * opportunity to drop the packet if desired. Therefore changing
- * MAX_DEFAULT_SEND_QUEUE_DEPTH does not affect resource utilization but
- * does impact the threshold used to identify if a packet should be
- * dropped. */
-#define MAX_DEFAULT_SEND_QUEUE_DEPTH (MAX_DEF_COOKIE_NUM / WMM_NUM_AC)
-
-#define AR6000_HB_CHALLENGE_RESP_FREQ_DEFAULT 1
-#define AR6000_HB_CHALLENGE_RESP_MISS_THRES_DEFAULT 1
-#define A_DISCONNECT_TIMER_INTERVAL 10 * 1000
-#define A_DEFAULT_LISTEN_INTERVAL 100
-#define A_MAX_WOW_LISTEN_INTERVAL 1000
-
-enum {
- DRV_HB_CHALLENGE = 0,
- APP_HB_CHALLENGE
-};
-
-enum {
- WLAN_INIT_MODE_NONE = 0,
- WLAN_INIT_MODE_USR,
- WLAN_INIT_MODE_UDEV,
- WLAN_INIT_MODE_DRV
-};
-
-/* Suspend - configuration */
-enum {
- WLAN_SUSPEND_CUT_PWR = 0,
- WLAN_SUSPEND_DEEP_SLEEP,
- WLAN_SUSPEND_WOW,
- WLAN_SUSPEND_CUT_PWR_IF_BT_OFF
-};
-
-/* WiFi OFF - configuration */
-enum {
- WLAN_OFF_CUT_PWR = 0,
- WLAN_OFF_DEEP_SLEEP,
-};
-
-/* WLAN low power state */
-enum {
- WLAN_POWER_STATE_ON = 0,
- WLAN_POWER_STATE_CUT_PWR = 1,
- WLAN_POWER_STATE_DEEP_SLEEP,
- WLAN_POWER_STATE_WOW
-};
-
-/* WLAN WoW State */
-enum {
- WLAN_WOW_STATE_NONE = 0,
- WLAN_WOW_STATE_SUSPENDED,
- WLAN_WOW_STATE_SUSPENDING
-};
-
-
-typedef enum _AR6K_BIN_FILE {
- AR6K_OTP_FILE,
- AR6K_FIRMWARE_FILE,
- AR6K_PATCH_FILE,
- AR6K_BOARD_DATA_FILE,
-} AR6K_BIN_FILE;
-
-#ifdef SETUPHCI_ENABLED
-#define SETUPHCI_DEFAULT 1
-#else
-#define SETUPHCI_DEFAULT 0
-#endif /* SETUPHCI_ENABLED */
-
-#ifdef SETUPBTDEV_ENABLED
-#define SETUPBTDEV_DEFAULT 1
-#else
-#define SETUPBTDEV_DEFAULT 0
-#endif /* SETUPBTDEV_ENABLED */
-
-#ifdef ENABLEUARTPRINT_SET
-#define ENABLEUARTPRINT_DEFAULT 1
-#else
-#define ENABLEUARTPRINT_DEFAULT 0
-#endif /* ENABLEARTPRINT_SET */
-
-#ifdef ATH6KL_CONFIG_HIF_VIRTUAL_SCATTER
-#define NOHIFSCATTERSUPPORT_DEFAULT 1
-#else /* ATH6KL_CONFIG_HIF_VIRTUAL_SCATTER */
-#define NOHIFSCATTERSUPPORT_DEFAULT 0
-#endif /* ATH6KL_CONFIG_HIF_VIRTUAL_SCATTER */
-
-
-#if defined(CONFIG_ATH6KL_ENABLE_COEXISTENCE)
-
-#ifdef CONFIG_AR600x_BT_QCOM
-#define ATH6KL_BT_DEV 1
-#elif defined(CONFIG_AR600x_BT_CSR)
-#define ATH6KL_BT_DEV 2
-#else
-#define ATH6KL_BT_DEV 3
-#endif
-
-#ifdef CONFIG_AR600x_DUAL_ANTENNA
-#define ATH6KL_BT_ANTENNA 2
-#else
-#define ATH6KL_BT_ANTENNA 1
-#endif
-
-#endif /* CONFIG_ATH6KL_ENABLE_COEXISTENCE */
-
-#ifdef AR600x_BT_AR3001
-#define AR3KHCIBAUD_DEFAULT 3000000
-#define HCIUARTSCALE_DEFAULT 1
-#define HCIUARTSTEP_DEFAULT 8937
-#else
-#define AR3KHCIBAUD_DEFAULT 0
-#define HCIUARTSCALE_DEFAULT 0
-#define HCIUARTSTEP_DEFAULT 0
-#endif /* AR600x_BT_AR3001 */
-
-#define WLAN_INIT_MODE_DEFAULT WLAN_INIT_MODE_DRV
-
-#define AR6K_PATCH_DOWNLOAD_ADDRESS(_param, _ver) do { \
- if ((_ver) == AR6003_REV1_VERSION) { \
- (_param) = AR6003_REV1_PATCH_DOWNLOAD_ADDRESS; \
- } else if ((_ver) == AR6003_REV2_VERSION) { \
- (_param) = AR6003_REV2_PATCH_DOWNLOAD_ADDRESS; \
- } else { \
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unknown Version: %d\n", _ver)); \
- A_ASSERT(0); \
- } \
-} while (0)
-
-#define AR6K_DATA_DOWNLOAD_ADDRESS(_param, _ver) do { \
- if ((_ver) == AR6003_REV1_VERSION) { \
- (_param) = AR6003_REV1_DATA_DOWNLOAD_ADDRESS; \
- } else if ((_ver) == AR6003_REV2_VERSION) { \
- (_param) = AR6003_REV2_DATA_DOWNLOAD_ADDRESS; \
- } else { \
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unknown Version: %d\n", _ver)); \
- A_ASSERT(0); \
- } \
-} while (0)
-
-#define AR6K_DATASET_PATCH_ADDRESS(_param, _ver) do { \
- if ((_ver) == AR6003_REV2_VERSION) { \
- (_param) = AR6003_REV2_DATASET_PATCH_ADDRESS; \
- } else if ((_ver) == AR6003_REV3_VERSION) { \
- (_param) = AR6003_REV3_DATASET_PATCH_ADDRESS; \
- } else { \
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unknown Version: %d\n", _ver)); \
- A_ASSERT(0); \
- } \
-} while (0)
-
-#define AR6K_APP_LOAD_ADDRESS(_param, _ver) do { \
- if ((_ver) == AR6003_REV2_VERSION) { \
- (_param) = AR6003_REV2_APP_LOAD_ADDRESS; \
- } else if ((_ver) == AR6003_REV3_VERSION) { \
- (_param) = AR6003_REV3_APP_LOAD_ADDRESS; \
- } else { \
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unknown Version: %d\n", _ver)); \
- A_ASSERT(0); \
- } \
-} while (0)
-
-#define AR6K_APP_START_OVERRIDE_ADDRESS(_param, _ver) do { \
- if ((_ver) == AR6003_REV2_VERSION) { \
- (_param) = AR6003_REV2_APP_START_OVERRIDE; \
- } else if ((_ver) == AR6003_REV3_VERSION) { \
- (_param) = AR6003_REV3_APP_START_OVERRIDE; \
- } else { \
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unknown Version: %d\n", _ver)); \
- A_ASSERT(0); \
- } \
-} while (0)
-
-/* AR6003 1.0 definitions */
-#define AR6003_REV1_VERSION 0x300002ba
-#define AR6003_REV1_DATA_DOWNLOAD_ADDRESS AR6003_REV1_OTP_DATA_ADDRESS
-#define AR6003_REV1_PATCH_DOWNLOAD_ADDRESS 0x57ea6c
-#define AR6003_REV1_OTP_FILE "ath6k/AR6003/hw1.0/otp.bin.z77"
-#define AR6003_REV1_FIRMWARE_FILE "ath6k/AR6003/hw1.0/athwlan.bin.z77"
-#define AR6003_REV1_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw1.0/athtcmd_ram.bin"
-#define AR6003_REV1_ART_FIRMWARE_FILE "ath6k/AR6003/hw1.0/device.bin"
-#define AR6003_REV1_PATCH_FILE "ath6k/AR6003/hw1.0/data.patch.bin"
-#define AR6003_REV1_EPPING_FIRMWARE_FILE "ath6k/AR6003/hw1.0/endpointping.bin"
-#ifdef CONFIG_AR600x_SD31_XXX
-#define AR6003_REV1_BOARD_DATA_FILE "ath6k/AR6003/hw1.0/bdata.SD31.bin"
-#elif defined(CONFIG_AR600x_SD32_XXX)
-#define AR6003_REV1_BOARD_DATA_FILE "ath6k/AR6003/hw1.0/bdata.SD32.bin"
-#elif defined(CONFIG_AR600x_WB31_XXX)
-#define AR6003_REV1_BOARD_DATA_FILE "ath6k/AR6003/hw1.0/bdata.WB31.bin"
-#else
-#define AR6003_REV1_BOARD_DATA_FILE "ath6k/AR6003/hw1.0/bdata.CUSTOM.bin"
-#endif /* Board Data File */
-
-/* AR6003 2.0 definitions */
-#define AR6003_REV2_VERSION 0x30000384
-#define AR6003_REV2_DATA_DOWNLOAD_ADDRESS AR6003_REV2_OTP_DATA_ADDRESS
-#define AR6003_REV2_PATCH_DOWNLOAD_ADDRESS 0x57e910
-#define AR6003_REV2_OTP_FILE "ath6k/AR6003/hw2.0/otp.bin.z77"
-#define AR6003_REV2_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athwlan.bin.z77"
-#define AR6003_REV2_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athtcmd_ram.bin"
-#define AR6003_REV2_ART_FIRMWARE_FILE "ath6k/AR6003/hw2.0/device.bin"
-#define AR6003_REV2_PATCH_FILE "ath6k/AR6003/hw2.0/data.patch.bin"
-#define AR6003_REV2_EPPING_FIRMWARE_FILE "ath6k/AR6003/hw2.0/endpointping.bin"
-#ifdef CONFIG_AR600x_SD31_XXX
-#define AR6003_REV2_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.SD31.bin"
-#elif defined(CONFIG_AR600x_SD32_XXX)
-#define AR6003_REV2_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.SD32.bin"
-#elif defined(CONFIG_AR600x_WB31_XXX)
-#define AR6003_REV2_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.WB31.bin"
-#else
-#define AR6003_REV2_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.CUSTOM.bin"
-#endif /* Board Data File */
-
-/* AR6003 3.0 definitions */
-#define AR6003_REV3_VERSION 0x30000582
-#define AR6003_REV3_OTP_FILE "ath6k/AR6003/hw2.1.1/otp.bin"
-#define AR6003_REV3_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athwlan.bin"
-#define AR6003_REV3_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athtcmd_ram.bin"
-#define AR6003_REV3_ART_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/device.bin"
-#define AR6003_REV3_PATCH_FILE "ath6k/AR6003/hw2.1.1/data.patch.bin"
-#define AR6003_REV3_EPPING_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/endpointping.bin"
-#ifdef CONFIG_AR600x_SD31_XXX
-#define AR6003_REV3_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.SD31.bin"
-#elif defined(CONFIG_AR600x_SD32_XXX)
-#define AR6003_REV3_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.SD32.bin"
-#elif defined(CONFIG_AR600x_WB31_XXX)
-#define AR6003_REV3_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.WB31.bin"
-#else
-#define AR6003_REV3_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.CUSTOM.bin"
-#endif /* Board Data File */
-
-
-/* Power states */
-enum {
- WLAN_PWR_CTRL_UP = 0,
- WLAN_PWR_CTRL_CUT_PWR,
- WLAN_PWR_CTRL_DEEP_SLEEP,
- WLAN_PWR_CTRL_WOW,
- WLAN_PWR_CTRL_DEEP_SLEEP_DISABLED
-};
-
-/* HTC RAW streams */
-typedef enum _HTC_RAW_STREAM_ID {
- HTC_RAW_STREAM_NOT_MAPPED = -1,
- HTC_RAW_STREAM_0 = 0,
- HTC_RAW_STREAM_1 = 1,
- HTC_RAW_STREAM_2 = 2,
- HTC_RAW_STREAM_3 = 3,
- HTC_RAW_STREAM_NUM_MAX
-} HTC_RAW_STREAM_ID;
-
-#define RAW_HTC_READ_BUFFERS_NUM 4
-#define RAW_HTC_WRITE_BUFFERS_NUM 4
-
-#define HTC_RAW_BUFFER_SIZE 1664
-
-typedef struct {
- int currPtr;
- int length;
- unsigned char data[HTC_RAW_BUFFER_SIZE];
- struct htc_packet HTCPacket;
-} raw_htc_buffer;
-
-#ifdef CONFIG_HOST_TCMD_SUPPORT
-/*
- * add TCMD_MODE besides wmi and bypasswmi
- * in TCMD_MODE, only few TCMD releated wmi commands
- * counld be hanlder
- */
-enum {
- AR6000_WMI_MODE = 0,
- AR6000_BYPASS_MODE,
- AR6000_TCMD_MODE,
- AR6000_WLAN_MODE
-};
-#endif /* CONFIG_HOST_TCMD_SUPPORT */
-
-struct ar_wep_key {
- u8 arKeyIndex;
- u8 arKeyLen;
- u8 arKey[64];
-} ;
-
-struct ar_key {
- u8 key[WLAN_MAX_KEY_LEN];
- u8 key_len;
- u8 seq[IW_ENCODE_SEQ_MAX_SIZE];
- u8 seq_len;
- u32 cipher;
-};
-
-enum {
- SME_DISCONNECTED,
- SME_CONNECTING,
- SME_CONNECTED
-};
-
-struct ar_node_mapping {
- u8 macAddress[6];
- u8 epId;
- u8 txPending;
-};
-
-struct ar_cookie {
- unsigned long arc_bp[2]; /* Must be first field */
- struct htc_packet HtcPkt; /* HTC packet wrapper */
- struct ar_cookie *arc_list_next;
-};
-
-struct ar_hb_chlng_resp {
- A_TIMER timer;
- u32 frequency;
- u32 seqNum;
- bool outstanding;
- u8 missCnt;
- u8 missThres;
-};
-
-/* Per STA data, used in AP mode */
-/*TODO: All this should move to OS independent dir */
-
-#define STA_PWR_MGMT_MASK 0x1
-#define STA_PWR_MGMT_SHIFT 0x0
-#define STA_PWR_MGMT_AWAKE 0x0
-#define STA_PWR_MGMT_SLEEP 0x1
-
-#define STA_SET_PWR_SLEEP(sta) (sta->flags |= (STA_PWR_MGMT_MASK << STA_PWR_MGMT_SHIFT))
-#define STA_CLR_PWR_SLEEP(sta) (sta->flags &= ~(STA_PWR_MGMT_MASK << STA_PWR_MGMT_SHIFT))
-#define STA_IS_PWR_SLEEP(sta) ((sta->flags >> STA_PWR_MGMT_SHIFT) & STA_PWR_MGMT_MASK)
-
-#define STA_PS_POLLED_MASK 0x1
-#define STA_PS_POLLED_SHIFT 0x1
-#define STA_SET_PS_POLLED(sta) (sta->flags |= (STA_PS_POLLED_MASK << STA_PS_POLLED_SHIFT))
-#define STA_CLR_PS_POLLED(sta) (sta->flags &= ~(STA_PS_POLLED_MASK << STA_PS_POLLED_SHIFT))
-#define STA_IS_PS_POLLED(sta) (sta->flags & (STA_PS_POLLED_MASK << STA_PS_POLLED_SHIFT))
-
-typedef struct {
- u16 flags;
- u8 mac[ATH_MAC_LEN];
- u8 aid;
- u8 keymgmt;
- u8 ucipher;
- u8 auth;
- u8 wpa_ie[IEEE80211_MAX_IE];
- A_NETBUF_QUEUE_T psq; /* power save q */
- A_MUTEX_T psqLock;
-} sta_t;
-
-typedef struct ar6_raw_htc {
- HTC_ENDPOINT_ID arRaw2EpMapping[HTC_RAW_STREAM_NUM_MAX];
- HTC_RAW_STREAM_ID arEp2RawMapping[ENDPOINT_MAX];
- struct semaphore raw_htc_read_sem[HTC_RAW_STREAM_NUM_MAX];
- struct semaphore raw_htc_write_sem[HTC_RAW_STREAM_NUM_MAX];
- wait_queue_head_t raw_htc_read_queue[HTC_RAW_STREAM_NUM_MAX];
- wait_queue_head_t raw_htc_write_queue[HTC_RAW_STREAM_NUM_MAX];
- raw_htc_buffer raw_htc_read_buffer[HTC_RAW_STREAM_NUM_MAX][RAW_HTC_READ_BUFFERS_NUM];
- raw_htc_buffer raw_htc_write_buffer[HTC_RAW_STREAM_NUM_MAX][RAW_HTC_WRITE_BUFFERS_NUM];
- bool write_buffer_available[HTC_RAW_STREAM_NUM_MAX];
- bool read_buffer_available[HTC_RAW_STREAM_NUM_MAX];
-} AR_RAW_HTC_T;
-
-struct ar6_softc {
- struct net_device *arNetDev; /* net_device pointer */
- void *arWmi;
- int arTxPending[ENDPOINT_MAX];
- int arTotalTxDataPending;
- u8 arNumDataEndPts;
- bool arWmiEnabled;
- bool arWmiReady;
- bool arConnected;
- HTC_HANDLE arHtcTarget;
- void *arHifDevice;
- spinlock_t arLock;
- struct semaphore arSem;
- int arSsidLen;
- u_char arSsid[32];
- u8 arNextMode;
- u8 arNetworkType;
- u8 arDot11AuthMode;
- u8 arAuthMode;
- u8 arPairwiseCrypto;
- u8 arPairwiseCryptoLen;
- u8 arGroupCrypto;
- u8 arGroupCryptoLen;
- u8 arDefTxKeyIndex;
- struct ar_wep_key arWepKeyList[WMI_MAX_KEY_INDEX + 1];
- u8 arBssid[6];
- u8 arReqBssid[6];
- u16 arChannelHint;
- u16 arBssChannel;
- u16 arListenIntervalB;
- u16 arListenIntervalT;
- struct ar6000_version arVersion;
- u32 arTargetType;
- s8 arRssi;
- u8 arTxPwr;
- bool arTxPwrSet;
- s32 arBitRate;
- struct net_device_stats arNetStats;
- struct iw_statistics arIwStats;
- s8 arNumChannels;
- u16 arChannelList[32];
- u32 arRegCode;
- bool statsUpdatePending;
- TARGET_STATS arTargetStats;
- s8 arMaxRetries;
- u8 arPhyCapability;
-#ifdef CONFIG_HOST_TCMD_SUPPORT
- u32 arTargetMode;
- void *tcmd_rx_report;
- int tcmd_rx_report_len;
-#endif
- AR6000_WLAN_STATE arWlanState;
- struct ar_node_mapping arNodeMap[MAX_NODE_NUM];
- u8 arIbssPsEnable;
- u8 arNodeNum;
- u8 arNexEpId;
- struct ar_cookie *arCookieList;
- u32 arCookieCount;
- u32 arRateMask;
- u8 arSkipScan;
- u16 arBeaconInterval;
- bool arConnectPending;
- bool arWmmEnabled;
- struct ar_hb_chlng_resp arHBChallengeResp;
- u8 arKeepaliveConfigured;
- u32 arMgmtFilter;
- HTC_ENDPOINT_ID arAc2EpMapping[WMM_NUM_AC];
- bool arAcStreamActive[WMM_NUM_AC];
- u8 arAcStreamPriMap[WMM_NUM_AC];
- u8 arHiAcStreamActivePri;
- u8 arEp2AcMapping[ENDPOINT_MAX];
- HTC_ENDPOINT_ID arControlEp;
-#ifdef HTC_RAW_INTERFACE
- AR_RAW_HTC_T *arRawHtc;
-#endif
- bool arNetQueueStopped;
- bool arRawIfInit;
- int arDeviceIndex;
- struct common_credit_state_info arCreditStateInfo;
- bool arWMIControlEpFull;
- bool dbgLogFetchInProgress;
- u8 log_buffer[DBGLOG_HOST_LOG_BUFFER_SIZE];
- u32 log_cnt;
- u32 dbglog_init_done;
- u32 arConnectCtrlFlags;
- s32 user_savedkeys_stat;
- u32 user_key_ctrl;
- struct USER_SAVEDKEYS user_saved_keys;
- USER_RSSI_THOLD rssi_map[12];
- u8 arUserBssFilter;
- u16 ap_profile_flag; /* AP mode */
- WMI_AP_ACL g_acl; /* AP mode */
- sta_t sta_list[AP_MAX_NUM_STA]; /* AP mode */
- u8 sta_list_index; /* AP mode */
- struct ieee80211req_key ap_mode_bkey; /* AP mode */
- A_NETBUF_QUEUE_T mcastpsq; /* power save q for Mcast frames */
- A_MUTEX_T mcastpsqLock;
- bool DTIMExpired; /* flag to indicate DTIM expired */
- u8 intra_bss; /* enable/disable intra bss data forward */
- void *aggr_cntxt;
-#ifndef EXPORT_HCI_BRIDGE_INTERFACE
- void *hcidev_info;
-#endif
- WMI_AP_MODE_STAT arAPStats;
- u8 ap_hidden_ssid;
- u8 ap_country_code[3];
- u8 ap_wmode;
- u8 ap_dtim_period;
- u16 ap_beacon_interval;
- u16 arRTS;
- u16 arACS; /* AP mode - Auto Channel Selection */
- struct htc_packet_queue amsdu_rx_buffer_queue;
- bool bIsDestroyProgress; /* flag to indicate ar6k destroy is in progress */
- A_TIMER disconnect_timer;
- u8 rxMetaVersion;
-#ifdef WAPI_ENABLE
- u8 arWapiEnable;
-#endif
- WMI_BTCOEX_CONFIG_EVENT arBtcoexConfig;
- WMI_BTCOEX_STATS_EVENT arBtcoexStats;
- s32 (*exitCallback)(void *config); /* generic callback at AR6K exit */
- struct hif_device_os_device_info osDevInfo;
- struct wireless_dev *wdev;
- struct cfg80211_scan_request *scan_request;
- struct ar_key keys[WMI_MAX_KEY_INDEX + 1];
- u32 smeState;
- u16 arWlanPowerState;
- bool arWlanOff;
-#ifdef CONFIG_PM
- u16 arWowState;
- bool arBTOff;
- bool arBTSharing;
- u16 arSuspendConfig;
- u16 arWlanOffConfig;
- u16 arWow2Config;
-#endif
- u8 scan_triggered;
- WMI_SCAN_PARAMS_CMD scParams;
-#define AR_MCAST_FILTER_MAC_ADDR_SIZE 4
- u8 mcast_filters[MAC_MAX_FILTERS_PER_LIST][AR_MCAST_FILTER_MAC_ADDR_SIZE];
- u8 bdaddr[6];
- bool scanSpecificSsid;
-#ifdef CONFIG_AP_VIRTUAL_ADAPTER_SUPPORT
- void *arApDev;
-#endif
- u8 arAutoAuthStage;
-
- u8 *fw_otp;
- size_t fw_otp_len;
- u8 *fw;
- size_t fw_len;
- u8 *fw_patch;
- size_t fw_patch_len;
- u8 *fw_data;
- size_t fw_data_len;
-};
-
-#ifdef CONFIG_AP_VIRTUAL_ADAPTER_SUPPORT
-struct ar_virtual_interface {
- struct net_device *arNetDev; /* net_device pointer */
- struct ar6_softc *arDev; /* ar device pointer */
- struct net_device *arStaNetDev; /* net_device pointer */
-};
-#endif /* CONFIG_AP_VIRTUAL_ADAPTER_SUPPORT */
-
-static inline void *ar6k_priv(struct net_device *dev)
-{
- return (wdev_priv(dev->ieee80211_ptr));
-}
-
-#define SET_HCI_BUS_TYPE(pHciDev, __bus, __type) do { \
- (pHciDev)->bus = (__bus); \
- (pHciDev)->dev_type = (__type); \
-} while(0)
-
-#define GET_INODE_FROM_FILEP(filp) \
- (filp)->f_path.dentry->d_inode
-
-#define arAc2EndpointID(ar,ac) (ar)->arAc2EpMapping[(ac)]
-#define arSetAc2EndpointIDMap(ar,ac,ep) \
-{ (ar)->arAc2EpMapping[(ac)] = (ep); \
- (ar)->arEp2AcMapping[(ep)] = (ac); }
-#define arEndpoint2Ac(ar,ep) (ar)->arEp2AcMapping[(ep)]
-
-#define arRawIfEnabled(ar) (ar)->arRawIfInit
-#define arRawStream2EndpointID(ar,raw) (ar)->arRawHtc->arRaw2EpMapping[(raw)]
-#define arSetRawStream2EndpointIDMap(ar,raw,ep) \
-{ (ar)->arRawHtc->arRaw2EpMapping[(raw)] = (ep); \
- (ar)->arRawHtc->arEp2RawMapping[(ep)] = (raw); }
-#define arEndpoint2RawStreamID(ar,ep) (ar)->arRawHtc->arEp2RawMapping[(ep)]
-
-struct ar_giwscan_param {
- char *current_ev;
- char *end_buf;
- u32 bytes_needed;
- struct iw_request_info *info;
-};
-
-#define AR6000_STAT_INC(ar, stat) (ar->arNetStats.stat++)
-
-#define AR6000_SPIN_LOCK(lock, param) do { \
- if (irqs_disabled()) { \
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("IRQs disabled:AR6000_LOCK\n")); \
- } \
- spin_lock_bh(lock); \
-} while (0)
-
-#define AR6000_SPIN_UNLOCK(lock, param) do { \
- if (irqs_disabled()) { \
- AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("IRQs disabled: AR6000_UNLOCK\n")); \
- } \
- spin_unlock_bh(lock); \
-} while (0)
-
-void ar6000_init_profile_info(struct ar6_softc *ar);
-void ar6000_install_static_wep_keys(struct ar6_softc *ar);
-int ar6000_init(struct net_device *dev);
-int ar6000_dbglog_get_debug_logs(struct ar6_softc *ar);
-void ar6000_TxDataCleanup(struct ar6_softc *ar);
-int ar6000_acl_data_tx(struct sk_buff *skb, struct net_device *dev);
-void ar6000_restart_endpoint(struct net_device *dev);
-void ar6000_stop_endpoint(struct net_device *dev, bool keepprofile, bool getdbglogs);
-
-#ifdef HTC_RAW_INTERFACE
-
-#ifndef __user
-#define __user
-#endif
-
-int ar6000_htc_raw_open(struct ar6_softc *ar);
-int ar6000_htc_raw_close(struct ar6_softc *ar);
-ssize_t ar6000_htc_raw_read(struct ar6_softc *ar,
- HTC_RAW_STREAM_ID StreamID,
- char __user *buffer, size_t count);
-ssize_t ar6000_htc_raw_write(struct ar6_softc *ar,
- HTC_RAW_STREAM_ID StreamID,
- char __user *buffer, size_t count);
-
-#endif /* HTC_RAW_INTERFACE */
-
-/* AP mode */
-/*TODO: These routines should be moved to a file that is common across OS */
-sta_t *
-ieee80211_find_conn(struct ar6_softc *ar, u8 *node_addr);
-
-sta_t *
-ieee80211_find_conn_for_aid(struct ar6_softc *ar, u8 aid);
-
-u8 remove_sta(struct ar6_softc *ar, u8 *mac, u16 reason);
-
-/* HCI support */
-
-#ifndef EXPORT_HCI_BRIDGE_INTERFACE
-int ar6000_setup_hci(struct ar6_softc *ar);
-void ar6000_cleanup_hci(struct ar6_softc *ar);
-void ar6000_set_default_ar3kconfig(struct ar6_softc *ar, void *ar3kconfig);
-
-/* HCI bridge testing */
-int hci_test_send(struct ar6_softc *ar, struct sk_buff *skb);
-#endif
-
-ATH_DEBUG_DECLARE_EXTERN(htc);
-ATH_DEBUG_DECLARE_EXTERN(wmi);
-ATH_DEBUG_DECLARE_EXTERN(bmi);
-ATH_DEBUG_DECLARE_EXTERN(hif);
-ATH_DEBUG_DECLARE_EXTERN(wlan);
-ATH_DEBUG_DECLARE_EXTERN(misc);
-
-extern u8 bcast_mac[];
-extern u8 null_mac[];
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _AR6000_H_ */
diff --git a/drivers/staging/ath6kl/os/linux/include/ar6k_pal.h b/drivers/staging/ath6kl/os/linux/include/ar6k_pal.h
deleted file mode 100644
index 39e0873aff24..000000000000
--- a/drivers/staging/ath6kl/os/linux/include/ar6k_pal.h
+++ /dev/null
@@ -1,36 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2009-2010 Atheros Corporation. All rights reserved.
-//
-// The software source and binaries included in this development package are
-// licensed, not sold. You, or your company, received the package under one
-// or more license agreements. The rights granted to you are specifically
-// listed in these license agreement(s). All other rights remain with Atheros
-// Communications, Inc., its subsidiaries, or the respective owner including
-// those listed on the included copyright notices. Distribution of any
-// portion of this package must be in strict compliance with the license
-// agreement(s) terms.
-// </copyright>
-//
-// <summary>
-// PAL driver for AR6003
-// </summary>
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _AR6K_PAL_H_
-#define _AR6K_PAL_H_
-#define HCI_GET_OP_CODE(p) (((u16)((p)[1])) << 8) | ((u16)((p)[0]))
-
-/* transmit packet reserve offset */
-#define TX_PACKET_RSV_OFFSET 32
-/* pal specific config structure */
-typedef bool (*ar6k_pal_recv_pkt_t)(void *pHciPalInfo, void *skb);
-typedef struct ar6k_pal_config_s
-{
- ar6k_pal_recv_pkt_t fpar6k_pal_recv_pkt;
-}ar6k_pal_config_t;
-
-void register_pal_cb(ar6k_pal_config_t *palConfig_p);
-#endif /* _AR6K_PAL_H_ */
diff --git a/drivers/staging/ath6kl/os/linux/include/ar6xapi_linux.h b/drivers/staging/ath6kl/os/linux/include/ar6xapi_linux.h
deleted file mode 100644
index 184dbdb50495..000000000000
--- a/drivers/staging/ath6kl/os/linux/include/ar6xapi_linux.h
+++ /dev/null
@@ -1,190 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Communications Inc.
-// All rights reserved.
-//
-//
-//
-// 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.
-//
-//
-//
-// Author(s): ="Atheros"
-//------------------------------------------------------------------------------
-
-#ifndef _AR6XAPI_LINUX_H
-#define _AR6XAPI_LINUX_H
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct ar6_softc;
-
-void ar6000_ready_event(void *devt, u8 *datap, u8 phyCap,
- u32 sw_ver, u32 abi_ver);
-int ar6000_control_tx(void *devt, void *osbuf, HTC_ENDPOINT_ID eid);
-void ar6000_connect_event(struct ar6_softc *ar, u16 channel,
- u8 *bssid, u16 listenInterval,
- u16 beaconInterval, NETWORK_TYPE networkType,
- u8 beaconIeLen, u8 assocReqLen,
- u8 assocRespLen,u8 *assocInfo);
-void ar6000_disconnect_event(struct ar6_softc *ar, u8 reason,
- u8 *bssid, u8 assocRespLen,
- u8 *assocInfo, u16 protocolReasonStatus);
-void ar6000_tkip_micerr_event(struct ar6_softc *ar, u8 keyid,
- bool ismcast);
-void ar6000_bitrate_rx(void *devt, s32 rateKbps);
-void ar6000_channelList_rx(void *devt, s8 numChan, u16 *chanList);
-void ar6000_regDomain_event(struct ar6_softc *ar, u32 regCode);
-void ar6000_txPwr_rx(void *devt, u8 txPwr);
-void ar6000_keepalive_rx(void *devt, u8 configured);
-void ar6000_neighborReport_event(struct ar6_softc *ar, int numAps,
- WMI_NEIGHBOR_INFO *info);
-void ar6000_set_numdataendpts(struct ar6_softc *ar, u32 num);
-void ar6000_scanComplete_event(struct ar6_softc *ar, int status);
-void ar6000_targetStats_event(struct ar6_softc *ar, u8 *ptr, u32 len);
-void ar6000_rssiThreshold_event(struct ar6_softc *ar,
- WMI_RSSI_THRESHOLD_VAL newThreshold,
- s16 rssi);
-void ar6000_reportError_event(struct ar6_softc *, WMI_TARGET_ERROR_VAL errorVal);
-void ar6000_cac_event(struct ar6_softc *ar, u8 ac, u8 cac_indication,
- u8 statusCode, u8 *tspecSuggestion);
-void ar6000_channel_change_event(struct ar6_softc *ar, u16 oldChannel, u16 newChannel);
-void ar6000_hbChallengeResp_event(struct ar6_softc *, u32 cookie, u32 source);
-void
-ar6000_roam_tbl_event(struct ar6_softc *ar, WMI_TARGET_ROAM_TBL *pTbl);
-
-void
-ar6000_roam_data_event(struct ar6_softc *ar, WMI_TARGET_ROAM_DATA *p);
-
-void
-ar6000_wow_list_event(struct ar6_softc *ar, u8 num_filters,
- WMI_GET_WOW_LIST_REPLY *wow_reply);
-
-void ar6000_pmkid_list_event(void *devt, u8 numPMKID,
- WMI_PMKID *pmkidList, u8 *bssidList);
-
-void ar6000_gpio_intr_rx(u32 intr_mask, u32 input_values);
-void ar6000_gpio_data_rx(u32 reg_id, u32 value);
-void ar6000_gpio_ack_rx(void);
-
-s32 rssi_compensation_calc_tcmd(u32 freq, s32 rssi, u32 totalPkt);
-s16 rssi_compensation_calc(struct ar6_softc *ar, s16 rssi);
-s16 rssi_compensation_reverse_calc(struct ar6_softc *ar, s16 rssi, bool Above);
-
-void ar6000_dbglog_init_done(struct ar6_softc *ar);
-
-#ifdef CONFIG_HOST_TCMD_SUPPORT
-void ar6000_tcmd_rx_report_event(void *devt, u8 *results, int len);
-#endif
-
-void ar6000_tx_retry_err_event(void *devt);
-
-void ar6000_snrThresholdEvent_rx(void *devt,
- WMI_SNR_THRESHOLD_VAL newThreshold,
- u8 snr);
-
-void ar6000_lqThresholdEvent_rx(void *devt, WMI_LQ_THRESHOLD_VAL range, u8 lqVal);
-
-
-void ar6000_ratemask_rx(void *devt, u32 ratemask);
-
-int ar6000_get_driver_cfg(struct net_device *dev,
- u16 cfgParam,
- void *result);
-void ar6000_bssInfo_event_rx(struct ar6_softc *ar, u8 *data, int len);
-
-void ar6000_dbglog_event(struct ar6_softc *ar, u32 dropped,
- s8 *buffer, u32 length);
-
-int ar6000_dbglog_get_debug_logs(struct ar6_softc *ar);
-
-void ar6000_peer_event(void *devt, u8 eventCode, u8 *bssid);
-
-void ar6000_indicate_tx_activity(void *devt, u8 trafficClass, bool Active);
-HTC_ENDPOINT_ID ar6000_ac2_endpoint_id ( void * devt, u8 ac);
-u8 ar6000_endpoint_id2_ac (void * devt, HTC_ENDPOINT_ID ep );
-
-void ar6000_btcoex_config_event(struct ar6_softc *ar, u8 *ptr, u32 len);
-
-void ar6000_btcoex_stats_event(struct ar6_softc *ar, u8 *ptr, u32 len) ;
-
-void ar6000_dset_open_req(void *devt,
- u32 id,
- u32 targ_handle,
- u32 targ_reply_fn,
- u32 targ_reply_arg);
-void ar6000_dset_close(void *devt, u32 access_cookie);
-void ar6000_dset_data_req(void *devt,
- u32 access_cookie,
- u32 offset,
- u32 length,
- u32 targ_buf,
- u32 targ_reply_fn,
- u32 targ_reply_arg);
-
-
-#if defined(CONFIG_TARGET_PROFILE_SUPPORT)
-void prof_count_rx(unsigned int addr, unsigned int count);
-#endif
-
-u32 ar6000_getnodeAge (void);
-
-u32 ar6000_getclkfreq (void);
-
-int ar6000_ap_mode_profile_commit(struct ar6_softc *ar);
-
-struct ieee80211req_wpaie;
-int
-ar6000_ap_mode_get_wpa_ie(struct ar6_softc *ar, struct ieee80211req_wpaie *wpaie);
-
-int is_iwioctl_allowed(u8 mode, u16 cmd);
-
-int is_xioctl_allowed(u8 mode, int cmd);
-
-void ar6000_pspoll_event(struct ar6_softc *ar,u8 aid);
-
-void ar6000_dtimexpiry_event(struct ar6_softc *ar);
-
-void ar6000_aggr_rcv_addba_req_evt(struct ar6_softc *ar, WMI_ADDBA_REQ_EVENT *cmd);
-void ar6000_aggr_rcv_addba_resp_evt(struct ar6_softc *ar, WMI_ADDBA_RESP_EVENT *cmd);
-void ar6000_aggr_rcv_delba_req_evt(struct ar6_softc *ar, WMI_DELBA_EVENT *cmd);
-void ar6000_hci_event_rcv_evt(struct ar6_softc *ar, WMI_HCI_EVENT *cmd);
-
-#ifdef WAPI_ENABLE
-int ap_set_wapi_key(struct ar6_softc *ar, void *ik);
-void ap_wapi_rekey_event(struct ar6_softc *ar, u8 type, u8 *mac);
-#endif
-
-int ar6000_connect_to_ap(struct ar6_softc *ar);
-int ar6000_disconnect(struct ar6_softc *ar);
-int ar6000_update_wlan_pwr_state(struct ar6_softc *ar, AR6000_WLAN_STATE state, bool suspending);
-int ar6000_set_wlan_state(struct ar6_softc *ar, AR6000_WLAN_STATE state);
-int ar6000_set_bt_hw_state(struct ar6_softc *ar, u32 state);
-
-#ifdef CONFIG_PM
-int ar6000_suspend_ev(void *context);
-int ar6000_resume_ev(void *context);
-int ar6000_power_change_ev(void *context, u32 config);
-void ar6000_check_wow_status(struct ar6_softc *ar, struct sk_buff *skb, bool isEvent);
-#endif
-
-#ifdef CONFIG_AP_VIRTUAL_ADAPTER_SUPPORT
-int ar6000_add_ap_interface(struct ar6_softc *ar, char *ifname);
-int ar6000_remove_ap_interface(struct ar6_softc *ar);
-#endif /* CONFIG_AP_VIRTUAL_ADAPTER_SUPPORT */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/drivers/staging/ath6kl/os/linux/include/athdrv_linux.h b/drivers/staging/ath6kl/os/linux/include/athdrv_linux.h
deleted file mode 100644
index 3d5f01da543f..000000000000
--- a/drivers/staging/ath6kl/os/linux/include/athdrv_linux.h
+++ /dev/null
@@ -1,1217 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Communications Inc.
-// All rights reserved.
-//
-//
-//
-// 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.
-//
-//
-//
-// Author(s): ="Atheros"
-//------------------------------------------------------------------------------
-
-#ifndef _ATHDRV_LINUX_H
-#define _ATHDRV_LINUX_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/*
- * There are two types of ioctl's here: Standard ioctls and
- * eXtended ioctls. All extended ioctls (XIOCTL) are multiplexed
- * off of the single ioctl command, AR6000_IOCTL_EXTENDED. The
- * arguments for every XIOCTL starts with a 32-bit command word
- * that is used to select which extended ioctl is in use. After
- * the command word are command-specific arguments.
- */
-
-/* Linux standard Wireless Extensions, private ioctl interfaces */
-#define IEEE80211_IOCTL_SETPARAM (SIOCIWFIRSTPRIV+0)
-#define IEEE80211_IOCTL_SETKEY (SIOCIWFIRSTPRIV+1)
-#define IEEE80211_IOCTL_DELKEY (SIOCIWFIRSTPRIV+2)
-#define IEEE80211_IOCTL_SETMLME (SIOCIWFIRSTPRIV+3)
-#define IEEE80211_IOCTL_ADDPMKID (SIOCIWFIRSTPRIV+4)
-#define IEEE80211_IOCTL_SETOPTIE (SIOCIWFIRSTPRIV+5)
-//#define IEEE80211_IOCTL_GETPARAM (SIOCIWFIRSTPRIV+6)
-//#define IEEE80211_IOCTL_SETWMMPARAMS (SIOCIWFIRSTPRIV+7)
-//#define IEEE80211_IOCTL_GETWMMPARAMS (SIOCIWFIRSTPRIV+8)
-//#define IEEE80211_IOCTL_GETOPTIE (SIOCIWFIRSTPRIV+9)
-//#define IEEE80211_IOCTL_SETAUTHALG (SIOCIWFIRSTPRIV+10)
-#define IEEE80211_IOCTL_LASTONE (SIOCIWFIRSTPRIV+10)
-
-
-
-/* ====WMI Ioctls==== */
-/*
- *
- * Many ioctls simply provide WMI services to application code:
- * an application makes such an ioctl call with a set of arguments
- * that are packaged into the corresponding WMI message, and sent
- * to the Target.
- */
-
-#define AR6000_IOCTL_WMI_GETREV (SIOCIWFIRSTPRIV+11)
-/*
- * arguments:
- * ar6000_version *revision
- */
-
-#define AR6000_IOCTL_WMI_SETPWR (SIOCIWFIRSTPRIV+12)
-/*
- * arguments:
- * WMI_POWER_MODE_CMD pwrModeCmd (see include/wmi.h)
- * uses: WMI_SET_POWER_MODE_CMDID
- */
-
-#define AR6000_IOCTL_WMI_SETSCAN (SIOCIWFIRSTPRIV+13)
-/*
- * arguments:
- * WMI_SCAN_PARAMS_CMD scanParams (see include/wmi.h)
- * uses: WMI_SET_SCAN_PARAMS_CMDID
- */
-
-#define AR6000_IOCTL_WMI_SETLISTENINT (SIOCIWFIRSTPRIV+14)
-/*
- * arguments:
- * UINT32 listenInterval
- * uses: WMI_SET_LISTEN_INT_CMDID
- */
-
-#define AR6000_IOCTL_WMI_SETBSSFILTER (SIOCIWFIRSTPRIV+15)
-/*
- * arguments:
- * WMI_BSS_FILTER filter (see include/wmi.h)
- * uses: WMI_SET_BSS_FILTER_CMDID
- */
-
-#define AR6000_IOCTL_WMI_SET_CHANNELPARAMS (SIOCIWFIRSTPRIV+16)
-/*
- * arguments:
- * WMI_CHANNEL_PARAMS_CMD chParams
- * uses: WMI_SET_CHANNEL_PARAMS_CMDID
- */
-
-#define AR6000_IOCTL_WMI_SET_PROBEDSSID (SIOCIWFIRSTPRIV+17)
-/*
- * arguments:
- * WMI_PROBED_SSID_CMD probedSsids (see include/wmi.h)
- * uses: WMI_SETPROBED_SSID_CMDID
- */
-
-#define AR6000_IOCTL_WMI_SET_PMPARAMS (SIOCIWFIRSTPRIV+18)
-/*
- * arguments:
- * WMI_POWER_PARAMS_CMD powerParams (see include/wmi.h)
- * uses: WMI_SET_POWER_PARAMS_CMDID
- */
-
-#define AR6000_IOCTL_WMI_SET_BADAP (SIOCIWFIRSTPRIV+19)
-/*
- * arguments:
- * WMI_ADD_BAD_AP_CMD badAPs (see include/wmi.h)
- * uses: WMI_ADD_BAD_AP_CMDID
- */
-
-#define AR6000_IOCTL_WMI_GET_QOS_QUEUE (SIOCIWFIRSTPRIV+20)
-/*
- * arguments:
- * ar6000_queuereq queueRequest (see below)
- */
-
-#define AR6000_IOCTL_WMI_CREATE_QOS (SIOCIWFIRSTPRIV+21)
-/*
- * arguments:
- * WMI_CREATE_PSTREAM createPstreamCmd (see include/wmi.h)
- * uses: WMI_CREATE_PSTREAM_CMDID
- */
-
-#define AR6000_IOCTL_WMI_DELETE_QOS (SIOCIWFIRSTPRIV+22)
-/*
- * arguments:
- * WMI_DELETE_PSTREAM_CMD deletePstreamCmd (see include/wmi.h)
- * uses: WMI_DELETE_PSTREAM_CMDID
- */
-
-#define AR6000_IOCTL_WMI_SET_SNRTHRESHOLD (SIOCIWFIRSTPRIV+23)
-/*
- * arguments:
- * WMI_SNR_THRESHOLD_PARAMS_CMD thresholdParams (see include/wmi.h)
- * uses: WMI_SNR_THRESHOLD_PARAMS_CMDID
- */
-
-#define AR6000_IOCTL_WMI_SET_ERROR_REPORT_BITMASK (SIOCIWFIRSTPRIV+24)
-/*
- * arguments:
- * WMI_TARGET_ERROR_REPORT_BITMASK errorReportBitMask (see include/wmi.h)
- * uses: WMI_TARGET_ERROR_REPORT_BITMASK_CMDID
- */
-
-#define AR6000_IOCTL_WMI_GET_TARGET_STATS (SIOCIWFIRSTPRIV+25)
-/*
- * arguments:
- * TARGET_STATS *targetStats (see below)
- * uses: WMI_GET_STATISTICS_CMDID
- */
-
-#define AR6000_IOCTL_WMI_SET_ASSOC_INFO (SIOCIWFIRSTPRIV+26)
-/*
- * arguments:
- * WMI_SET_ASSOC_INFO_CMD setAssocInfoCmd
- * uses: WMI_SET_ASSOC_INFO_CMDID
- */
-
-#define AR6000_IOCTL_WMI_SET_ACCESS_PARAMS (SIOCIWFIRSTPRIV+27)
-/*
- * arguments:
- * WMI_SET_ACCESS_PARAMS_CMD setAccessParams (see include/wmi.h)
- * uses: WMI_SET_ACCESS_PARAMS_CMDID
- */
-
-#define AR6000_IOCTL_WMI_SET_BMISS_TIME (SIOCIWFIRSTPRIV+28)
-/*
- * arguments:
- * UINT32 beaconMissTime
- * uses: WMI_SET_BMISS_TIME_CMDID
- */
-
-#define AR6000_IOCTL_WMI_SET_DISC_TIMEOUT (SIOCIWFIRSTPRIV+29)
-/*
- * arguments:
- * WMI_DISC_TIMEOUT_CMD disconnectTimeoutCmd (see include/wmi.h)
- * uses: WMI_SET_DISC_TIMEOUT_CMDID
- */
-
-#define AR6000_IOCTL_WMI_SET_IBSS_PM_CAPS (SIOCIWFIRSTPRIV+30)
-/*
- * arguments:
- * WMI_IBSS_PM_CAPS_CMD ibssPowerMgmtCapsCmd
- * uses: WMI_SET_IBSS_PM_CAPS_CMDID
- */
-
-/*
- * There is a very small space available for driver-private
- * wireless ioctls. In order to circumvent this limitation,
- * we multiplex a bunch of ioctls (XIOCTLs) on top of a
- * single AR6000_IOCTL_EXTENDED ioctl.
- */
-#define AR6000_IOCTL_EXTENDED (SIOCIWFIRSTPRIV+31)
-
-
-/* ====BMI Extended Ioctls==== */
-
-#define AR6000_XIOCTL_BMI_DONE 1
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_BMI_DONE)
- * uses: BMI_DONE
- */
-
-#define AR6000_XIOCTL_BMI_READ_MEMORY 2
-/*
- * arguments:
- * union {
- * struct {
- * UINT32 cmd (AR6000_XIOCTL_BMI_READ_MEMORY)
- * UINT32 address
- * UINT32 length
- * }
- * char results[length]
- * }
- * uses: BMI_READ_MEMORY
- */
-
-#define AR6000_XIOCTL_BMI_WRITE_MEMORY 3
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_BMI_WRITE_MEMORY)
- * UINT32 address
- * UINT32 length
- * char data[length]
- * uses: BMI_WRITE_MEMORY
- */
-
-#define AR6000_XIOCTL_BMI_EXECUTE 4
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_BMI_EXECUTE)
- * UINT32 TargetAddress
- * UINT32 parameter
- * uses: BMI_EXECUTE
- */
-
-#define AR6000_XIOCTL_BMI_SET_APP_START 5
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_BMI_SET_APP_START)
- * UINT32 TargetAddress
- * uses: BMI_SET_APP_START
- */
-
-#define AR6000_XIOCTL_BMI_READ_SOC_REGISTER 6
-/*
- * arguments:
- * union {
- * struct {
- * UINT32 cmd (AR6000_XIOCTL_BMI_READ_SOC_REGISTER)
- * UINT32 TargetAddress, 32-bit aligned
- * }
- * UINT32 result
- * }
- * uses: BMI_READ_SOC_REGISTER
- */
-
-#define AR6000_XIOCTL_BMI_WRITE_SOC_REGISTER 7
-/*
- * arguments:
- * struct {
- * UINT32 cmd (AR6000_XIOCTL_BMI_WRITE_SOC_REGISTER)
- * UINT32 TargetAddress, 32-bit aligned
- * UINT32 newValue
- * }
- * uses: BMI_WRITE_SOC_REGISTER
- */
-
-#define AR6000_XIOCTL_BMI_TEST 8
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_BMI_TEST)
- * UINT32 address
- * UINT32 length
- * UINT32 count
- */
-
-
-
-/* Historical Host-side DataSet support */
-#define AR6000_XIOCTL_UNUSED9 9
-#define AR6000_XIOCTL_UNUSED10 10
-#define AR6000_XIOCTL_UNUSED11 11
-
-/* ====Misc Extended Ioctls==== */
-
-#define AR6000_XIOCTL_FORCE_TARGET_RESET 12
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_FORCE_TARGET_RESET)
- */
-
-
-#ifdef HTC_RAW_INTERFACE
-/* HTC Raw Interface Ioctls */
-#define AR6000_XIOCTL_HTC_RAW_OPEN 13
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_HTC_RAW_OPEN)
- */
-
-#define AR6000_XIOCTL_HTC_RAW_CLOSE 14
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_HTC_RAW_CLOSE)
- */
-
-#define AR6000_XIOCTL_HTC_RAW_READ 15
-/*
- * arguments:
- * union {
- * struct {
- * UINT32 cmd (AR6000_XIOCTL_HTC_RAW_READ)
- * UINT32 mailboxID
- * UINT32 length
- * }
- * results[length]
- * }
- */
-
-#define AR6000_XIOCTL_HTC_RAW_WRITE 16
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_HTC_RAW_WRITE)
- * UINT32 mailboxID
- * UINT32 length
- * char buffer[length]
- */
-#endif /* HTC_RAW_INTERFACE */
-
-#define AR6000_XIOCTL_CHECK_TARGET_READY 17
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_CHECK_TARGET_READY)
- */
-
-
-
-/* ====GPIO (General Purpose I/O) Extended Ioctls==== */
-
-#define AR6000_XIOCTL_GPIO_OUTPUT_SET 18
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_GPIO_OUTPUT_SET)
- * ar6000_gpio_output_set_cmd_s (see below)
- * uses: WMIX_GPIO_OUTPUT_SET_CMDID
- */
-
-#define AR6000_XIOCTL_GPIO_INPUT_GET 19
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_GPIO_INPUT_GET)
- * uses: WMIX_GPIO_INPUT_GET_CMDID
- */
-
-#define AR6000_XIOCTL_GPIO_REGISTER_SET 20
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_GPIO_REGISTER_SET)
- * ar6000_gpio_register_cmd_s (see below)
- * uses: WMIX_GPIO_REGISTER_SET_CMDID
- */
-
-#define AR6000_XIOCTL_GPIO_REGISTER_GET 21
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_GPIO_REGISTER_GET)
- * ar6000_gpio_register_cmd_s (see below)
- * uses: WMIX_GPIO_REGISTER_GET_CMDID
- */
-
-#define AR6000_XIOCTL_GPIO_INTR_ACK 22
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_GPIO_INTR_ACK)
- * ar6000_cpio_intr_ack_cmd_s (see below)
- * uses: WMIX_GPIO_INTR_ACK_CMDID
- */
-
-#define AR6000_XIOCTL_GPIO_INTR_WAIT 23
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_GPIO_INTR_WAIT)
- */
-
-
-
-/* ====more wireless commands==== */
-
-#define AR6000_XIOCTL_SET_ADHOC_BSSID 24
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_SET_ADHOC_BSSID)
- * WMI_SET_ADHOC_BSSID_CMD setAdHocBssidCmd (see include/wmi.h)
- */
-
-#define AR6000_XIOCTL_SET_OPT_MODE 25
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_SET_OPT_MODE)
- * WMI_SET_OPT_MODE_CMD setOptModeCmd (see include/wmi.h)
- * uses: WMI_SET_OPT_MODE_CMDID
- */
-
-#define AR6000_XIOCTL_OPT_SEND_FRAME 26
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_OPT_SEND_FRAME)
- * WMI_OPT_TX_FRAME_CMD optTxFrameCmd (see include/wmi.h)
- * uses: WMI_OPT_TX_FRAME_CMDID
- */
-
-#define AR6000_XIOCTL_SET_BEACON_INTVAL 27
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_SET_BEACON_INTVAL)
- * WMI_BEACON_INT_CMD beaconIntCmd (see include/wmi.h)
- * uses: WMI_SET_BEACON_INT_CMDID
- */
-
-
-#define IEEE80211_IOCTL_SETAUTHALG 28
-
-
-#define AR6000_XIOCTL_SET_VOICE_PKT_SIZE 29
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_SET_VOICE_PKT_SIZE)
- * WMI_SET_VOICE_PKT_SIZE_CMD setVoicePktSizeCmd (see include/wmi.h)
- * uses: WMI_SET_VOICE_PKT_SIZE_CMDID
- */
-
-
-#define AR6000_XIOCTL_SET_MAX_SP 30
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_SET_MAX_SP)
- * WMI_SET_MAX_SP_LEN_CMD maxSPLen(see include/wmi.h)
- * uses: WMI_SET_MAX_SP_LEN_CMDID
- */
-
-#define AR6000_XIOCTL_WMI_GET_ROAM_TBL 31
-
-#define AR6000_XIOCTL_WMI_SET_ROAM_CTRL 32
-
-#define AR6000_XIOCTRL_WMI_SET_POWERSAVE_TIMERS 33
-
-
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTRL_WMI_SET_POWERSAVE_TIMERS)
- * WMI_SET_POWERSAVE_TIMERS_CMD powerSaveTimers(see include/wmi.h)
- * WMI_SET_POWERSAVE_TIMERS_CMDID
- */
-
-#define AR6000_XIOCTRL_WMI_GET_POWER_MODE 34
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTRL_WMI_GET_POWER_MODE)
- */
-
-#define AR6000_XIOCTRL_WMI_SET_WLAN_STATE 35
-typedef enum {
- WLAN_DISABLED,
- WLAN_ENABLED
-} AR6000_WLAN_STATE;
-/*
- * arguments:
- * enable/disable
- */
-
-#define AR6000_XIOCTL_WMI_GET_ROAM_DATA 36
-
-#define AR6000_XIOCTL_WMI_SETRETRYLIMITS 37
-/*
- * arguments:
- * WMI_SET_RETRY_LIMITS_CMD ibssSetRetryLimitsCmd
- * uses: WMI_SET_RETRY_LIMITS_CMDID
- */
-
-#ifdef CONFIG_HOST_TCMD_SUPPORT
-/* ====extended commands for radio test ==== */
-
-#define AR6000_XIOCTL_TCMD_CONT_TX 38
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_TCMD_CONT_TX)
- * WMI_TCMD_CONT_TX_CMD contTxCmd (see include/wmi.h)
- * uses: WMI_TCMD_CONT_TX_CMDID
- */
-
-#define AR6000_XIOCTL_TCMD_CONT_RX 39
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_TCMD_CONT_RX)
- * WMI_TCMD_CONT_RX_CMD rxCmd (see include/wmi.h)
- * uses: WMI_TCMD_CONT_RX_CMDID
- */
-
-#define AR6000_XIOCTL_TCMD_PM 40
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_TCMD_PM)
- * WMI_TCMD_PM_CMD pmCmd (see include/wmi.h)
- * uses: WMI_TCMD_PM_CMDID
- */
-
-#endif /* CONFIG_HOST_TCMD_SUPPORT */
-
-#define AR6000_XIOCTL_WMI_STARTSCAN 41
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_WMI_STARTSCAN)
- * UINT8 scanType
- * UINT8 scanConnected
- * u32 forceFgScan
- * uses: WMI_START_SCAN_CMDID
- */
-
-#define AR6000_XIOCTL_WMI_SETFIXRATES 42
-
-#define AR6000_XIOCTL_WMI_GETFIXRATES 43
-
-
-#define AR6000_XIOCTL_WMI_SET_RSSITHRESHOLD 44
-/*
- * arguments:
- * WMI_RSSI_THRESHOLD_PARAMS_CMD thresholdParams (see include/wmi.h)
- * uses: WMI_RSSI_THRESHOLD_PARAMS_CMDID
- */
-
-#define AR6000_XIOCTL_WMI_CLR_RSSISNR 45
-/*
- * arguments:
- * WMI_CLR_RSSISNR_CMD thresholdParams (see include/wmi.h)
- * uses: WMI_CLR_RSSISNR_CMDID
- */
-
-#define AR6000_XIOCTL_WMI_SET_LQTHRESHOLD 46
-/*
- * arguments:
- * WMI_LQ_THRESHOLD_PARAMS_CMD thresholdParams (see include/wmi.h)
- * uses: WMI_LQ_THRESHOLD_PARAMS_CMDID
- */
-
-#define AR6000_XIOCTL_WMI_SET_RTS 47
-/*
- * arguments:
- * WMI_SET_RTS_MODE_CMD (see include/wmi.h)
- * uses: WMI_SET_RTS_MODE_CMDID
- */
-
-#define AR6000_XIOCTL_WMI_SET_LPREAMBLE 48
-
-#define AR6000_XIOCTL_WMI_SET_AUTHMODE 49
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_WMI_SET_AUTHMODE)
- * UINT8 mode
- * uses: WMI_SET_RECONNECT_AUTH_MODE_CMDID
- */
-
-#define AR6000_XIOCTL_WMI_SET_REASSOCMODE 50
-
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_WMI_SET_WMM)
- * UINT8 mode
- * uses: WMI_SET_WMM_CMDID
- */
-#define AR6000_XIOCTL_WMI_SET_WMM 51
-
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_WMI_SET_HB_CHALLENGE_RESP_PARAMS)
- * UINT32 frequency
- * UINT8 threshold
- */
-#define AR6000_XIOCTL_WMI_SET_HB_CHALLENGE_RESP_PARAMS 52
-
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_WMI_GET_HB_CHALLENGE_RESP)
- * UINT32 cookie
- */
-#define AR6000_XIOCTL_WMI_GET_HB_CHALLENGE_RESP 53
-
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_WMI_GET_RD)
- * UINT32 regDomain
- */
-#define AR6000_XIOCTL_WMI_GET_RD 54
-
-#define AR6000_XIOCTL_DIAG_READ 55
-
-#define AR6000_XIOCTL_DIAG_WRITE 56
-
-/*
- * arguments cmd (AR6000_XIOCTL_SET_TXOP)
- * WMI_TXOP_CFG txopEnable
- */
-#define AR6000_XIOCTL_WMI_SET_TXOP 57
-
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_USER_SETKEYS)
- * UINT32 keyOpCtrl
- * uses struct ar6000_user_setkeys_info
- */
-#define AR6000_XIOCTL_USER_SETKEYS 58
-
-#define AR6000_XIOCTL_WMI_SET_KEEPALIVE 59
-/*
- * arguments:
- * UINT8 cmd (AR6000_XIOCTL_WMI_SET_KEEPALIVE)
- * UINT8 keepaliveInterval
- * uses: WMI_SET_KEEPALIVE_CMDID
- */
-
-#define AR6000_XIOCTL_WMI_GET_KEEPALIVE 60
-/*
- * arguments:
- * UINT8 cmd (AR6000_XIOCTL_WMI_GET_KEEPALIVE)
- * UINT8 keepaliveInterval
- * u32 configured
- * uses: WMI_GET_KEEPALIVE_CMDID
- */
-
-/* ====ROM Patching Extended Ioctls==== */
-
-#define AR6000_XIOCTL_BMI_ROMPATCH_INSTALL 61
-/*
- * arguments:
- * union {
- * struct {
- * UINT32 cmd (AR6000_XIOCTL_BMI_ROMPATCH_INSTALL)
- * UINT32 ROM Address
- * UINT32 RAM Address
- * UINT32 number of bytes
- * UINT32 activate? (0 or 1)
- * }
- * u32 resulting rompatch ID
- * }
- * uses: BMI_ROMPATCH_INSTALL
- */
-
-#define AR6000_XIOCTL_BMI_ROMPATCH_UNINSTALL 62
-/*
- * arguments:
- * struct {
- * UINT32 cmd (AR6000_XIOCTL_BMI_ROMPATCH_UNINSTALL)
- * UINT32 rompatch ID
- * }
- * uses: BMI_ROMPATCH_UNINSTALL
- */
-
-#define AR6000_XIOCTL_BMI_ROMPATCH_ACTIVATE 63
-/*
- * arguments:
- * struct {
- * UINT32 cmd (AR6000_XIOCTL_BMI_ROMPATCH_ACTIVATE)
- * UINT32 rompatch count
- * UINT32 rompatch IDs[rompatch count]
- * }
- * uses: BMI_ROMPATCH_ACTIVATE
- */
-
-#define AR6000_XIOCTL_BMI_ROMPATCH_DEACTIVATE 64
-/*
- * arguments:
- * struct {
- * UINT32 cmd (AR6000_XIOCTL_BMI_ROMPATCH_DEACTIVATE)
- * UINT32 rompatch count
- * UINT32 rompatch IDs[rompatch count]
- * }
- * uses: BMI_ROMPATCH_DEACTIVATE
- */
-
-#define AR6000_XIOCTL_WMI_SET_APPIE 65
-/*
- * arguments:
- * struct {
- * UINT32 cmd (AR6000_XIOCTL_WMI_SET_APPIE)
- * UINT32 app_frmtype;
- * UINT32 app_buflen;
- * UINT8 app_buf[];
- * }
- */
-#define AR6000_XIOCTL_WMI_SET_MGMT_FRM_RX_FILTER 66
-/*
- * arguments:
- * u32 filter_type;
- */
-
-#define AR6000_XIOCTL_DBGLOG_CFG_MODULE 67
-
-#define AR6000_XIOCTL_DBGLOG_GET_DEBUG_LOGS 68
-
-#define AR6000_XIOCTL_WMI_SET_WSC_STATUS 70
-/*
- * arguments:
- * u32 wsc_status;
- * (WSC_REG_INACTIVE or WSC_REG_ACTIVE)
- */
-
-/*
- * arguments:
- * struct {
- * u8 streamType;
- * u8 status;
- * }
- * uses: WMI_SET_BT_STATUS_CMDID
- */
-#define AR6000_XIOCTL_WMI_SET_BT_STATUS 71
-
-/*
- * arguments:
- * struct {
- * u8 paramType;
- * union {
- * u8 noSCOPkts;
- * BT_PARAMS_A2DP a2dpParams;
- * BT_COEX_REGS regs;
- * };
- * }
- * uses: WMI_SET_BT_PARAM_CMDID
- */
-#define AR6000_XIOCTL_WMI_SET_BT_PARAMS 72
-
-#define AR6000_XIOCTL_WMI_SET_HOST_SLEEP_MODE 73
-#define AR6000_XIOCTL_WMI_SET_WOW_MODE 74
-#define AR6000_XIOCTL_WMI_GET_WOW_LIST 75
-#define AR6000_XIOCTL_WMI_ADD_WOW_PATTERN 76
-#define AR6000_XIOCTL_WMI_DEL_WOW_PATTERN 77
-
-
-
-#define AR6000_XIOCTL_TARGET_INFO 78
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_TARGET_INFO)
- * u32 TargetVersion (returned)
- * u32 TargetType (returned)
- * (See also bmi_msg.h target_ver and target_type)
- */
-
-#define AR6000_XIOCTL_DUMP_HTC_CREDIT_STATE 79
-/*
- * arguments:
- * none
- */
-
-#define AR6000_XIOCTL_TRAFFIC_ACTIVITY_CHANGE 80
-/*
- * This ioctl is used to emulate traffic activity
- * timeouts. Activity/inactivity will trigger the driver
- * to re-balance credits.
- *
- * arguments:
- * ar6000_traffic_activity_change
- */
-
-#define AR6000_XIOCTL_WMI_SET_CONNECT_CTRL_FLAGS 81
-/*
- * This ioctl is used to set the connect control flags
- *
- * arguments:
- * u32 connectCtrlFlags
- */
-
-#define AR6000_XIOCTL_WMI_SET_AKMP_PARAMS 82
-/*
- * This IOCTL sets any Authentication,Key Management and Protection
- * related parameters. This is used along with the information set in
- * Connect Command.
- * Currently this enables Multiple PMKIDs to an AP.
- *
- * arguments:
- * struct {
- * u32 akmpInfo;
- * }
- * uses: WMI_SET_AKMP_PARAMS_CMD
- */
-
-#define AR6000_XIOCTL_WMI_GET_PMKID_LIST 83
-
-#define AR6000_XIOCTL_WMI_SET_PMKID_LIST 84
-/*
- * This IOCTL is used to set a list of PMKIDs. This list of
- * PMKIDs is used in the [Re]AssocReq Frame. This list is used
- * only if the MultiPMKID option is enabled via the
- * AR6000_XIOCTL_WMI_SET_AKMP_PARAMS IOCTL.
- *
- * arguments:
- * struct {
- * u32 numPMKID;
- * WMI_PMKID pmkidList[WMI_MAX_PMKID_CACHE];
- * }
- * uses: WMI_SET_PMKIDLIST_CMD
- */
-
-#define AR6000_XIOCTL_WMI_SET_PARAMS 85
-#define AR6000_XIOCTL_WMI_SET_MCAST_FILTER 86
-#define AR6000_XIOCTL_WMI_DEL_MCAST_FILTER 87
-
-
-/* Historical DSETPATCH support for INI patches */
-#define AR6000_XIOCTL_UNUSED90 90
-
-
-/* Support LZ-compressed firmware download */
-#define AR6000_XIOCTL_BMI_LZ_STREAM_START 91
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_BMI_LZ_STREAM_START)
- * UINT32 address
- * uses: BMI_LZ_STREAM_START
- */
-
-#define AR6000_XIOCTL_BMI_LZ_DATA 92
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_BMI_LZ_DATA)
- * UINT32 length
- * char data[length]
- * uses: BMI_LZ_DATA
- */
-
-#define AR6000_XIOCTL_PROF_CFG 93
-/*
- * arguments:
- * u32 period
- * u32 nbins
- */
-
-#define AR6000_XIOCTL_PROF_ADDR_SET 94
-/*
- * arguments:
- * u32 Target address
- */
-
-#define AR6000_XIOCTL_PROF_START 95
-
-#define AR6000_XIOCTL_PROF_STOP 96
-
-#define AR6000_XIOCTL_PROF_COUNT_GET 97
-
-#define AR6000_XIOCTL_WMI_ABORT_SCAN 98
-
-/*
- * AP mode
- */
-#define AR6000_XIOCTL_AP_GET_STA_LIST 99
-
-#define AR6000_XIOCTL_AP_HIDDEN_SSID 100
-
-#define AR6000_XIOCTL_AP_SET_NUM_STA 101
-
-#define AR6000_XIOCTL_AP_SET_ACL_MAC 102
-
-#define AR6000_XIOCTL_AP_GET_ACL_LIST 103
-
-#define AR6000_XIOCTL_AP_COMMIT_CONFIG 104
-
-#define IEEE80211_IOCTL_GETWPAIE 105
-
-#define AR6000_XIOCTL_AP_CONN_INACT_TIME 106
-
-#define AR6000_XIOCTL_AP_PROT_SCAN_TIME 107
-
-#define AR6000_XIOCTL_AP_SET_COUNTRY 108
-
-#define AR6000_XIOCTL_AP_SET_DTIM 109
-
-
-
-
-#define AR6000_XIOCTL_WMI_TARGET_EVENT_REPORT 110
-
-#define AR6000_XIOCTL_SET_IP 111
-
-#define AR6000_XIOCTL_AP_SET_ACL_POLICY 112
-
-#define AR6000_XIOCTL_AP_INTRA_BSS_COMM 113
-
-#define AR6000_XIOCTL_DUMP_MODULE_DEBUG_INFO 114
-
-#define AR6000_XIOCTL_MODULE_DEBUG_SET_MASK 115
-
-#define AR6000_XIOCTL_MODULE_DEBUG_GET_MASK 116
-
-#define AR6000_XIOCTL_DUMP_RCV_AGGR_STATS 117
-
-#define AR6000_XIOCTL_SET_HT_CAP 118
-
-#define AR6000_XIOCTL_SET_HT_OP 119
-
-#define AR6000_XIOCTL_AP_GET_STAT 120
-
-#define AR6000_XIOCTL_SET_TX_SELECT_RATES 121
-
-#define AR6000_XIOCTL_SETUP_AGGR 122
-
-#define AR6000_XIOCTL_ALLOW_AGGR 123
-
-#define AR6000_XIOCTL_AP_GET_HIDDEN_SSID 124
-
-#define AR6000_XIOCTL_AP_GET_COUNTRY 125
-
-#define AR6000_XIOCTL_AP_GET_WMODE 126
-
-#define AR6000_XIOCTL_AP_GET_DTIM 127
-
-#define AR6000_XIOCTL_AP_GET_BINTVL 128
-
-#define AR6000_XIOCTL_AP_GET_RTS 129
-
-#define AR6000_XIOCTL_DELE_AGGR 130
-
-#define AR6000_XIOCTL_FETCH_TARGET_REGS 131
-
-#define AR6000_XIOCTL_HCI_CMD 132
-
-#define AR6000_XIOCTL_ACL_DATA 133 /* used to be used for PAL */
-
-#define AR6000_XIOCTL_WLAN_CONN_PRECEDENCE 134
-
-#define AR6000_XIOCTL_AP_SET_11BG_RATESET 135
-
-/*
- * arguments:
- * WMI_AP_PS_CMD apPsCmd
- * uses: WMI_AP_PS_CMDID
- */
-
-#define AR6000_XIOCTL_WMI_SET_AP_PS 136
-
-#define AR6000_XIOCTL_WMI_MCAST_FILTER 137
-
-#define AR6000_XIOCTL_WMI_SET_BTCOEX_FE_ANT 138
-
-#define AR6000_XIOCTL_WMI_SET_BTCOEX_COLOCATED_BT_DEV 139
-
-#define AR6000_XIOCTL_WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG 140
-
-#define AR6000_XIOCTL_WMI_SET_BTCOEX_SCO_CONFIG 141
-
-#define AR6000_XIOCTL_WMI_SET_BTCOEX_A2DP_CONFIG 142
-
-#define AR6000_XIOCTL_WMI_SET_BTCOEX_ACLCOEX_CONFIG 143
-
-#define AR6000_XIOCTL_WMI_SET_BTCOEX_DEBUG 144
-
-#define AR6000_XIOCTL_WMI_SET_BT_OPERATING_STATUS 145
-
-#define AR6000_XIOCTL_WMI_GET_BTCOEX_CONFIG 146
-
-#define AR6000_XIOCTL_WMI_GET_BTCOEX_STATS 147
-/*
- * arguments:
- * UINT32 cmd (AR6000_XIOCTL_WMI_SET_QOS_SUPP)
- * UINT8 mode
- * uses: WMI_SET_QOS_SUPP_CMDID
- */
-#define AR6000_XIOCTL_WMI_SET_QOS_SUPP 148
-
-#define AR6000_XIOCTL_GET_WLAN_SLEEP_STATE 149
-
-#define AR6000_XIOCTL_SET_BT_HW_POWER_STATE 150
-
-#define AR6000_XIOCTL_GET_BT_HW_POWER_STATE 151
-
-#define AR6000_XIOCTL_ADD_AP_INTERFACE 152
-
-#define AR6000_XIOCTL_REMOVE_AP_INTERFACE 153
-
-#define AR6000_XIOCTL_WMI_SET_TX_SGI_PARAM 154
-
-#define AR6000_XIOCTL_WMI_SET_EXCESS_TX_RETRY_THRES 161
-
-/* used by AR6000_IOCTL_WMI_GETREV */
-struct ar6000_version {
- u32 host_ver;
- u32 target_ver;
- u32 wlan_ver;
- u32 abi_ver;
-};
-
-/* used by AR6000_IOCTL_WMI_GET_QOS_QUEUE */
-struct ar6000_queuereq {
- u8 trafficClass;
- u16 activeTsids;
-};
-
-/* used by AR6000_IOCTL_WMI_GET_TARGET_STATS */
-typedef struct targetStats_t {
- u64 tx_packets;
- u64 tx_bytes;
- u64 tx_unicast_pkts;
- u64 tx_unicast_bytes;
- u64 tx_multicast_pkts;
- u64 tx_multicast_bytes;
- u64 tx_broadcast_pkts;
- u64 tx_broadcast_bytes;
- u64 tx_rts_success_cnt;
- u64 tx_packet_per_ac[4];
-
- u64 tx_errors;
- u64 tx_failed_cnt;
- u64 tx_retry_cnt;
- u64 tx_mult_retry_cnt;
- u64 tx_rts_fail_cnt;
-
- u64 rx_packets;
- u64 rx_bytes;
- u64 rx_unicast_pkts;
- u64 rx_unicast_bytes;
- u64 rx_multicast_pkts;
- u64 rx_multicast_bytes;
- u64 rx_broadcast_pkts;
- u64 rx_broadcast_bytes;
- u64 rx_fragment_pkt;
-
- u64 rx_errors;
- u64 rx_crcerr;
- u64 rx_key_cache_miss;
- u64 rx_decrypt_err;
- u64 rx_duplicate_frames;
-
- u64 tkip_local_mic_failure;
- u64 tkip_counter_measures_invoked;
- u64 tkip_replays;
- u64 tkip_format_errors;
- u64 ccmp_format_errors;
- u64 ccmp_replays;
-
- u64 power_save_failure_cnt;
-
- u64 cs_bmiss_cnt;
- u64 cs_lowRssi_cnt;
- u64 cs_connect_cnt;
- u64 cs_disconnect_cnt;
-
- s32 tx_unicast_rate;
- s32 rx_unicast_rate;
-
- u32 lq_val;
-
- u32 wow_num_pkts_dropped;
- u16 wow_num_events_discarded;
-
- s16 noise_floor_calibation;
- s16 cs_rssi;
- s16 cs_aveBeacon_rssi;
- u8 cs_aveBeacon_snr;
- u8 cs_lastRoam_msec;
- u8 cs_snr;
-
- u8 wow_num_host_pkt_wakeups;
- u8 wow_num_host_event_wakeups;
-
- u32 arp_received;
- u32 arp_matched;
- u32 arp_replied;
-}TARGET_STATS;
-
-typedef struct targetStats_cmd_t {
- TARGET_STATS targetStats;
- int clearStats;
-} TARGET_STATS_CMD;
-
-/* used by AR6000_XIOCTL_USER_SETKEYS */
-
-/*
- * Setting this bit to 1 doesnot initialize the RSC on the firmware
- */
-#define AR6000_XIOCTL_USER_SETKEYS_RSC_CTRL 1
-#define AR6000_USER_SETKEYS_RSC_UNCHANGED 0x00000002
-
-struct ar6000_user_setkeys_info {
- u32 keyOpCtrl; /* Bit Map of Key Mgmt Ctrl Flags */
-}; /* XXX: unused !? */
-
-/* used by AR6000_XIOCTL_GPIO_OUTPUT_SET */
-struct ar6000_gpio_output_set_cmd_s {
- u32 set_mask;
- u32 clear_mask;
- u32 enable_mask;
- u32 disable_mask;
-};
-
-/*
- * used by AR6000_XIOCTL_GPIO_REGISTER_GET and AR6000_XIOCTL_GPIO_REGISTER_SET
- */
-struct ar6000_gpio_register_cmd_s {
- u32 gpioreg_id;
- u32 value;
-};
-
-/* used by AR6000_XIOCTL_GPIO_INTR_ACK */
-struct ar6000_gpio_intr_ack_cmd_s {
- u32 ack_mask;
-};
-
-/* used by AR6000_XIOCTL_GPIO_INTR_WAIT */
-struct ar6000_gpio_intr_wait_cmd_s {
- u32 intr_mask;
- u32 input_values;
-};
-
-/* used by the AR6000_XIOCTL_DBGLOG_CFG_MODULE */
-typedef struct ar6000_dbglog_module_config_s {
- u32 valid;
- u16 mmask;
- u16 tsr;
- u32 rep;
- u16 size;
-} DBGLOG_MODULE_CONFIG;
-
-typedef struct user_rssi_thold_t {
- s16 tag;
- s16 rssi;
-} USER_RSSI_THOLD;
-
-typedef struct user_rssi_params_t {
- u8 weight;
- u32 pollTime;
- USER_RSSI_THOLD tholds[12];
-} USER_RSSI_PARAMS;
-
-typedef struct ar6000_get_btcoex_config_cmd_t{
- u32 btProfileType;
- u32 linkId;
- }AR6000_GET_BTCOEX_CONFIG_CMD;
-
-typedef struct ar6000_btcoex_config_t {
- AR6000_GET_BTCOEX_CONFIG_CMD configCmd;
- u32 *configEvent;
-} AR6000_BTCOEX_CONFIG;
-
-typedef struct ar6000_btcoex_stats_t {
- u32 *statsEvent;
- }AR6000_BTCOEX_STATS;
-/*
- * Host driver may have some config parameters. Typically, these
- * config params are one time config parameters. These could
- * correspond to any of the underlying modules. Host driver exposes
- * an api for the underlying modules to get this config.
- */
-#define AR6000_DRIVER_CFG_BASE 0x8000
-
-/* Should driver perform wlan node caching? */
-#define AR6000_DRIVER_CFG_GET_WLANNODECACHING 0x8001
-/*Should we log raw WMI msgs */
-#define AR6000_DRIVER_CFG_LOG_RAW_WMI_MSGS 0x8002
-
-/* used by AR6000_XIOCTL_DIAG_READ & AR6000_XIOCTL_DIAG_WRITE */
-struct ar6000_diag_window_cmd_s {
- unsigned int addr;
- unsigned int value;
-};
-
-
-struct ar6000_traffic_activity_change {
- u32 StreamID; /* stream ID to indicate activity change */
- u32 Active; /* active (1) or inactive (0) */
-};
-
-/* Used with AR6000_XIOCTL_PROF_COUNT_GET */
-struct prof_count_s {
- u32 addr; /* bin start address */
- u32 count; /* hit count */
-};
-
-
-/* used by AR6000_XIOCTL_MODULE_DEBUG_SET_MASK */
-/* AR6000_XIOCTL_MODULE_DEBUG_GET_MASK */
-/* AR6000_XIOCTL_DUMP_MODULE_DEBUG_INFO */
-struct drv_debug_module_s {
- char modulename[128]; /* name of module */
- u32 mask; /* new mask to set .. or .. current mask */
-};
-
-
-/* All HCI related rx events are sent up to the host app
- * via a wmi event id. It can contain ACL data or HCI event,
- * based on which it will be de-multiplexed.
- */
-typedef enum {
- PAL_HCI_EVENT = 0,
- PAL_HCI_RX_DATA,
-} WMI_PAL_EVENT_INFO;
-
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/drivers/staging/ath6kl/os/linux/include/cfg80211.h b/drivers/staging/ath6kl/os/linux/include/cfg80211.h
deleted file mode 100644
index d5253207b198..000000000000
--- a/drivers/staging/ath6kl/os/linux/include/cfg80211.h
+++ /dev/null
@@ -1,61 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Communications Inc.
-// All rights reserved.
-//
-//
-//
-// 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.
-//
-//
-//
-// Author(s): ="Atheros"
-//------------------------------------------------------------------------------
-
-#ifndef _AR6K_CFG80211_H_
-#define _AR6K_CFG80211_H_
-
-struct wireless_dev *ar6k_cfg80211_init(struct device *dev);
-void ar6k_cfg80211_deinit(struct ar6_softc *ar);
-
-void ar6k_cfg80211_scanComplete_event(struct ar6_softc *ar, int status);
-
-void ar6k_cfg80211_connect_event(struct ar6_softc *ar, u16 channel,
- u8 *bssid, u16 listenInterval,
- u16 beaconInterval,NETWORK_TYPE networkType,
- u8 beaconIeLen, u8 assocReqLen,
- u8 assocRespLen, u8 *assocInfo);
-
-void ar6k_cfg80211_disconnect_event(struct ar6_softc *ar, u8 reason,
- u8 *bssid, u8 assocRespLen,
- u8 *assocInfo, u16 protocolReasonStatus);
-
-void ar6k_cfg80211_tkip_micerr_event(struct ar6_softc *ar, u8 keyid, bool ismcast);
-
-#ifdef CONFIG_NL80211_TESTMODE
-void ar6000_testmode_rx_report_event(struct ar6_softc *ar, void *buf,
- int buf_len);
-#else
-static inline void ar6000_testmode_rx_report_event(struct ar6_softc *ar,
- void *buf, int buf_len)
-{
-}
-#endif
-
-
-#endif /* _AR6K_CFG80211_H_ */
-
-
-
-
-
-
diff --git a/drivers/staging/ath6kl/os/linux/include/config_linux.h b/drivers/staging/ath6kl/os/linux/include/config_linux.h
deleted file mode 100644
index dbbe1a00b92c..000000000000
--- a/drivers/staging/ath6kl/os/linux/include/config_linux.h
+++ /dev/null
@@ -1,51 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Communications Inc.
-// All rights reserved.
-//
-//
-//
-// 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.
-//
-//
-//
-// Author(s): ="Atheros"
-//------------------------------------------------------------------------------
-
-#ifndef _CONFIG_LINUX_H_
-#define _CONFIG_LINUX_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Host side Test Command support
- */
-#define CONFIG_HOST_TCMD_SUPPORT
-
-#define USE_4BYTE_REGISTER_ACCESS
-
-/* Host-side support for Target-side profiling */
-#undef CONFIG_TARGET_PROFILE_SUPPORT
-
-/* IP/TCP checksum offload */
-/* Checksum offload is currently not supported for 64 bit platforms */
-#ifndef __LP64__
-#define CONFIG_CHECKSUM_OFFLOAD
-#endif /* __LP64__ */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/drivers/staging/ath6kl/os/linux/include/debug_linux.h b/drivers/staging/ath6kl/os/linux/include/debug_linux.h
deleted file mode 100644
index b8dba52badce..000000000000
--- a/drivers/staging/ath6kl/os/linux/include/debug_linux.h
+++ /dev/null
@@ -1,50 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Communications Inc.
-// All rights reserved.
-//
-//
-//
-// 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.
-//
-//
-//
-// Author(s): ="Atheros"
-//------------------------------------------------------------------------------
-
-#ifndef _DEBUG_LINUX_H_
-#define _DEBUG_LINUX_H_
-
- /* macro to remove parens */
-#define ATH_PRINTX_ARG(arg...) arg
-
-#ifdef DEBUG
- /* NOTE: the AR_DEBUG_PRINTF macro is defined here to handle special handling of variable arg macros
- * which may be compiler dependent. */
-#define AR_DEBUG_PRINTF(mask, args) do { \
- if (GET_ATH_MODULE_DEBUG_VAR_MASK(ATH_MODULE_NAME) & (mask)) { \
- A_LOGGER(mask, ATH_MODULE_NAME, ATH_PRINTX_ARG args); \
- } \
-} while (0)
-#else
- /* on non-debug builds, keep in error and warning messages in the driver, all other
- * message tracing will get compiled out */
-#define AR_DEBUG_PRINTF(mask, args) \
- if ((mask) & (ATH_DEBUG_ERR | ATH_DEBUG_WARN)) { A_PRINTF(ATH_PRINTX_ARG args); }
-
-#endif
-
- /* compile specific macro to get the function name string */
-#define _A_FUNCNAME_ __func__
-
-
-#endif /* _DEBUG_LINUX_H_ */
diff --git a/drivers/staging/ath6kl/os/linux/include/export_hci_transport.h b/drivers/staging/ath6kl/os/linux/include/export_hci_transport.h
deleted file mode 100644
index 74f986183347..000000000000
--- a/drivers/staging/ath6kl/os/linux/include/export_hci_transport.h
+++ /dev/null
@@ -1,76 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2009-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// HCI bridge implementation
-//
-// Author(s): ="Atheros"
-//==============================================================================
-
-#include "hci_transport_api.h"
-#include "common_drv.h"
-
-extern HCI_TRANSPORT_HANDLE (*_HCI_TransportAttach)(void *HTCHandle, struct hci_transport_config_info *pInfo);
-extern void (*_HCI_TransportDetach)(HCI_TRANSPORT_HANDLE HciTrans);
-extern int (*_HCI_TransportAddReceivePkts)(HCI_TRANSPORT_HANDLE HciTrans, struct htc_packet_queue *pQueue);
-extern int (*_HCI_TransportSendPkt)(HCI_TRANSPORT_HANDLE HciTrans, struct htc_packet *pPacket, bool Synchronous);
-extern void (*_HCI_TransportStop)(HCI_TRANSPORT_HANDLE HciTrans);
-extern int (*_HCI_TransportStart)(HCI_TRANSPORT_HANDLE HciTrans);
-extern int (*_HCI_TransportEnableDisableAsyncRecv)(HCI_TRANSPORT_HANDLE HciTrans, bool Enable);
-extern int (*_HCI_TransportRecvHCIEventSync)(HCI_TRANSPORT_HANDLE HciTrans,
- struct htc_packet *pPacket,
- int MaxPollMS);
-extern int (*_HCI_TransportSetBaudRate)(HCI_TRANSPORT_HANDLE HciTrans, u32 Baud);
-extern int (*_HCI_TransportEnablePowerMgmt)(HCI_TRANSPORT_HANDLE HciTrans, bool Enable);
-
-
-#define HCI_TransportAttach(HTCHandle, pInfo) \
- _HCI_TransportAttach((HTCHandle), (pInfo))
-#define HCI_TransportDetach(HciTrans) \
- _HCI_TransportDetach(HciTrans)
-#define HCI_TransportAddReceivePkts(HciTrans, pQueue) \
- _HCI_TransportAddReceivePkts((HciTrans), (pQueue))
-#define HCI_TransportSendPkt(HciTrans, pPacket, Synchronous) \
- _HCI_TransportSendPkt((HciTrans), (pPacket), (Synchronous))
-#define HCI_TransportStop(HciTrans) \
- _HCI_TransportStop((HciTrans))
-#define HCI_TransportStart(HciTrans) \
- _HCI_TransportStart((HciTrans))
-#define HCI_TransportEnableDisableAsyncRecv(HciTrans, Enable) \
- _HCI_TransportEnableDisableAsyncRecv((HciTrans), (Enable))
-#define HCI_TransportRecvHCIEventSync(HciTrans, pPacket, MaxPollMS) \
- _HCI_TransportRecvHCIEventSync((HciTrans), (pPacket), (MaxPollMS))
-#define HCI_TransportSetBaudRate(HciTrans, Baud) \
- _HCI_TransportSetBaudRate((HciTrans), (Baud))
-#define HCI_TransportEnablePowerMgmt(HciTrans, Enable) \
- _HCI_TransportEnablePowerMgmt((HciTrans), (Enable))
-
-
-extern int ar6000_register_hci_transport(struct hci_transport_callbacks *hciTransCallbacks);
-
-extern int ar6000_get_hif_dev(struct hif_device *device, void *config);
-
-extern int ar6000_set_uart_config(struct hif_device *hifDevice, u32 scale, u32 step);
-
-/* get core clock register settings
- * data: 0 - 40/44MHz
- * 1 - 80/88MHz
- * where (5G band/2.4G band)
- * assume 2.4G band for now
- */
-extern int ar6000_get_core_clock_config(struct hif_device *hifDevice, u32 *data);
diff --git a/drivers/staging/ath6kl/os/linux/include/ieee80211_ioctl.h b/drivers/staging/ath6kl/os/linux/include/ieee80211_ioctl.h
deleted file mode 100644
index e6e96de3fc6b..000000000000
--- a/drivers/staging/ath6kl/os/linux/include/ieee80211_ioctl.h
+++ /dev/null
@@ -1,177 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Communications Inc.
-// All rights reserved.
-//
-//
-//
-// 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.
-//
-//
-//
-// Author(s): ="Atheros"
-//------------------------------------------------------------------------------
-
-#ifndef _IEEE80211_IOCTL_H_
-#define _IEEE80211_IOCTL_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Extracted from the MADWIFI net80211/ieee80211_ioctl.h
- */
-
-/*
- * WPA/RSN get/set key request. Specify the key/cipher
- * type and whether the key is to be used for sending and/or
- * receiving. The key index should be set only when working
- * with global keys (use IEEE80211_KEYIX_NONE for ``no index'').
- * Otherwise a unicast/pairwise key is specified by the bssid
- * (on a station) or mac address (on an ap). They key length
- * must include any MIC key data; otherwise it should be no
- more than IEEE80211_KEYBUF_SIZE.
- */
-struct ieee80211req_key {
- u_int8_t ik_type; /* key/cipher type */
- u_int8_t ik_pad;
- u_int16_t ik_keyix; /* key index */
- u_int8_t ik_keylen; /* key length in bytes */
- u_int8_t ik_flags;
-#define IEEE80211_KEY_XMIT 0x01
-#define IEEE80211_KEY_RECV 0x02
-#define IEEE80211_KEY_DEFAULT 0x80 /* default xmit key */
- u_int8_t ik_macaddr[IEEE80211_ADDR_LEN];
- u_int64_t ik_keyrsc; /* key receive sequence counter */
- u_int64_t ik_keytsc; /* key transmit sequence counter */
- u_int8_t ik_keydata[IEEE80211_KEYBUF_SIZE+IEEE80211_MICBUF_SIZE];
-};
-/*
- * Delete a key either by index or address. Set the index
- * to IEEE80211_KEYIX_NONE when deleting a unicast key.
- */
-struct ieee80211req_del_key {
- u_int8_t idk_keyix; /* key index */
- u_int8_t idk_macaddr[IEEE80211_ADDR_LEN];
-};
-/*
- * MLME state manipulation request. IEEE80211_MLME_ASSOC
- * only makes sense when operating as a station. The other
- * requests can be used when operating as a station or an
- * ap (to effect a station).
- */
-struct ieee80211req_mlme {
- u_int8_t im_op; /* operation to perform */
-#define IEEE80211_MLME_ASSOC 1 /* associate station */
-#define IEEE80211_MLME_DISASSOC 2 /* disassociate station */
-#define IEEE80211_MLME_DEAUTH 3 /* deauthenticate station */
-#define IEEE80211_MLME_AUTHORIZE 4 /* authorize station */
-#define IEEE80211_MLME_UNAUTHORIZE 5 /* unauthorize station */
- u_int16_t im_reason; /* 802.11 reason code */
- u_int8_t im_macaddr[IEEE80211_ADDR_LEN];
-};
-
-struct ieee80211req_addpmkid {
- u_int8_t pi_bssid[IEEE80211_ADDR_LEN];
- u_int8_t pi_enable;
- u_int8_t pi_pmkid[16];
-};
-
-#define AUTH_ALG_OPEN_SYSTEM 0x01
-#define AUTH_ALG_SHARED_KEY 0x02
-#define AUTH_ALG_LEAP 0x04
-
-struct ieee80211req_authalg {
- u_int8_t auth_alg;
-};
-
-/*
- * Request to add an IE to a Management Frame
- */
-enum{
- IEEE80211_APPIE_FRAME_BEACON = 0,
- IEEE80211_APPIE_FRAME_PROBE_REQ = 1,
- IEEE80211_APPIE_FRAME_PROBE_RESP = 2,
- IEEE80211_APPIE_FRAME_ASSOC_REQ = 3,
- IEEE80211_APPIE_FRAME_ASSOC_RESP = 4,
- IEEE80211_APPIE_NUM_OF_FRAME = 5
-};
-
-/*
- * The Maximum length of the IE that can be added to a Management frame
- */
-#define IEEE80211_APPIE_FRAME_MAX_LEN 200
-
-struct ieee80211req_getset_appiebuf {
- u_int32_t app_frmtype; /* management frame type for which buffer is added */
- u_int32_t app_buflen; /*application supplied buffer length */
- u_int8_t app_buf[];
-};
-
-/*
- * The following definitions are used by an application to set filter
- * for receiving management frames
- */
-enum {
- IEEE80211_FILTER_TYPE_BEACON = 0x1,
- IEEE80211_FILTER_TYPE_PROBE_REQ = 0x2,
- IEEE80211_FILTER_TYPE_PROBE_RESP = 0x4,
- IEEE80211_FILTER_TYPE_ASSOC_REQ = 0x8,
- IEEE80211_FILTER_TYPE_ASSOC_RESP = 0x10,
- IEEE80211_FILTER_TYPE_AUTH = 0x20,
- IEEE80211_FILTER_TYPE_DEAUTH = 0x40,
- IEEE80211_FILTER_TYPE_DISASSOC = 0x80,
- IEEE80211_FILTER_TYPE_ALL = 0xFF /* used to check the valid filter bits */
-};
-
-struct ieee80211req_set_filter {
- u_int32_t app_filterype; /* management frame filter type */
-};
-
-enum {
- IEEE80211_PARAM_AUTHMODE = 3, /* Authentication Mode */
- IEEE80211_PARAM_MCASTCIPHER = 5,
- IEEE80211_PARAM_MCASTKEYLEN = 6, /* multicast key length */
- IEEE80211_PARAM_UCASTCIPHER = 8,
- IEEE80211_PARAM_UCASTKEYLEN = 9, /* unicast key length */
- IEEE80211_PARAM_WPA = 10, /* WPA mode (0,1,2) */
- IEEE80211_PARAM_ROAMING = 12, /* roaming mode */
- IEEE80211_PARAM_PRIVACY = 13, /* privacy invoked */
- IEEE80211_PARAM_COUNTERMEASURES = 14, /* WPA/TKIP countermeasures */
- IEEE80211_PARAM_DROPUNENCRYPTED = 15, /* discard unencrypted frames */
- IEEE80211_PARAM_WAPI = 16, /* WAPI policy from wapid */
-};
-
-/*
- * Values for IEEE80211_PARAM_WPA
- */
-#define WPA_MODE_WPA1 1
-#define WPA_MODE_WPA2 2
-#define WPA_MODE_AUTO 3
-#define WPA_MODE_NONE 4
-
-struct ieee80211req_wpaie {
- u_int8_t wpa_macaddr[IEEE80211_ADDR_LEN];
- u_int8_t wpa_ie[IEEE80211_MAX_IE];
- u_int8_t rsn_ie[IEEE80211_MAX_IE];
-};
-
-#ifndef IW_ENCODE_ALG_PMK
-#define IW_ENCODE_ALG_PMK 4
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _IEEE80211_IOCTL_H_ */
diff --git a/drivers/staging/ath6kl/os/linux/include/osapi_linux.h b/drivers/staging/ath6kl/os/linux/include/osapi_linux.h
deleted file mode 100644
index 41f437307727..000000000000
--- a/drivers/staging/ath6kl/os/linux/include/osapi_linux.h
+++ /dev/null
@@ -1,339 +0,0 @@
-//------------------------------------------------------------------------------
-// This file contains the definitions of the basic atheros data types.
-// It is used to map the data types in atheros files to a platform specific
-// type.
-// Copyright (c) 2004-2010 Atheros Communications Inc.
-// All rights reserved.
-//
-//
-//
-// 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.
-//
-//
-//
-// Author(s): ="Atheros"
-//------------------------------------------------------------------------------
-
-#ifndef _OSAPI_LINUX_H_
-#define _OSAPI_LINUX_H_
-
-#ifdef __KERNEL__
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/jiffies.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/wait.h>
-#include <linux/semaphore.h>
-#include <linux/cache.h>
-
-#ifdef __GNUC__
-#define __ATTRIB_PACK __attribute__ ((packed))
-#define __ATTRIB_PRINTF __attribute__ ((format (printf, 1, 2)))
-#define __ATTRIB_NORETURN __attribute__ ((noreturn))
-#ifndef INLINE
-#define INLINE __inline__
-#endif
-#else /* Not GCC */
-#define __ATTRIB_PACK
-#define __ATTRIB_PRINTF
-#define __ATTRIB_NORETURN
-#ifndef INLINE
-#define INLINE __inline
-#endif
-#endif /* End __GNUC__ */
-
-#define PREPACK
-#define POSTPACK __ATTRIB_PACK
-
-/*
- * Endianes macros
- */
-#define A_BE2CPU8(x) ntohb(x)
-#define A_BE2CPU16(x) ntohs(x)
-#define A_BE2CPU32(x) ntohl(x)
-
-#define A_LE2CPU8(x) (x)
-#define A_LE2CPU16(x) (x)
-#define A_LE2CPU32(x) (x)
-
-#define A_CPU2BE8(x) htonb(x)
-#define A_CPU2BE16(x) htons(x)
-#define A_CPU2BE32(x) htonl(x)
-
-#define A_MEMZERO(addr, len) memset(addr, 0, len)
-#define A_MALLOC(size) kmalloc((size), GFP_KERNEL)
-#define A_MALLOC_NOWAIT(size) kmalloc((size), GFP_ATOMIC)
-
-#define A_LOGGER(mask, mod, args...) printk(KERN_ALERT args)
-#define A_PRINTF(args...) printk(KERN_ALERT args)
-
-#define A_PRINTF_LOG(args...) printk(args)
-#define A_SPRINTF(buf, args...) sprintf (buf, args)
-
-/* Mutual Exclusion */
-typedef spinlock_t A_MUTEX_T;
-#define A_MUTEX_INIT(mutex) spin_lock_init(mutex)
-#define A_MUTEX_LOCK(mutex) spin_lock_bh(mutex)
-#define A_MUTEX_UNLOCK(mutex) spin_unlock_bh(mutex)
-#define A_IS_MUTEX_VALID(mutex) true /* okay to return true, since A_MUTEX_DELETE does nothing */
-#define A_MUTEX_DELETE(mutex) /* spin locks are not kernel resources so nothing to free.. */
-
-/* Get current time in ms adding a constant offset (in ms) */
-#define A_GET_MS(offset) \
- (((jiffies / HZ) * 1000) + (offset))
-
-/*
- * Timer Functions
- */
-#define A_MDELAY(msecs) mdelay(msecs)
-typedef struct timer_list A_TIMER;
-
-#define A_INIT_TIMER(pTimer, pFunction, pArg) do { \
- init_timer(pTimer); \
- (pTimer)->function = (pFunction); \
- (pTimer)->data = (unsigned long)(pArg); \
-} while (0)
-
-/*
- * Start a Timer that elapses after 'periodMSec' milli-seconds
- * Support is provided for a one-shot timer. The 'repeatFlag' is
- * ignored.
- */
-#define A_TIMEOUT_MS(pTimer, periodMSec, repeatFlag) do { \
- if (repeatFlag) { \
- printk("\n" __FILE__ ":%d: Timer Repeat requested\n",__LINE__); \
- panic("Timer Repeat"); \
- } \
- mod_timer((pTimer), jiffies + HZ * (periodMSec) / 1000); \
-} while (0)
-
-/*
- * Cancel the Timer.
- */
-#define A_UNTIMEOUT(pTimer) do { \
- del_timer((pTimer)); \
-} while (0)
-
-#define A_DELETE_TIMER(pTimer) do { \
-} while (0)
-
-/*
- * Wait Queue related functions
- */
-typedef wait_queue_head_t A_WAITQUEUE_HEAD;
-#define A_INIT_WAITQUEUE_HEAD(head) init_waitqueue_head(head)
-#ifndef wait_event_interruptible_timeout
-#define __wait_event_interruptible_timeout(wq, condition, ret) \
-do { \
- wait_queue_t __wait; \
- init_waitqueue_entry(&__wait, current); \
- \
- add_wait_queue(&wq, &__wait); \
- for (;;) { \
- set_current_state(TASK_INTERRUPTIBLE); \
- if (condition) \
- break; \
- if (!signal_pending(current)) { \
- ret = schedule_timeout(ret); \
- if (!ret) \
- break; \
- continue; \
- } \
- ret = -ERESTARTSYS; \
- break; \
- } \
- current->state = TASK_RUNNING; \
- remove_wait_queue(&wq, &__wait); \
-} while (0)
-
-#define wait_event_interruptible_timeout(wq, condition, timeout) \
-({ \
- long __ret = timeout; \
- if (!(condition)) \
- __wait_event_interruptible_timeout(wq, condition, __ret); \
- __ret; \
-})
-#endif /* wait_event_interruptible_timeout */
-
-#define A_WAIT_EVENT_INTERRUPTIBLE_TIMEOUT(head, condition, timeout) do { \
- wait_event_interruptible_timeout(head, condition, timeout); \
-} while (0)
-
-#define A_WAKE_UP(head) wake_up(head)
-
-#ifdef DEBUG
-extern unsigned int panic_on_assert;
-#define A_ASSERT(expr) \
- if (!(expr)) { \
- printk(KERN_ALERT"Debug Assert Caught, File %s, Line: %d, Test:%s \n",__FILE__, __LINE__,#expr); \
- if (panic_on_assert) panic(#expr); \
- }
-#else
-#define A_ASSERT(expr)
-#endif /* DEBUG */
-
-#define A_REQUEST_FIRMWARE(_ppf, _pfile, _dev) request_firmware(_ppf, _pfile, _dev)
-#define A_RELEASE_FIRMWARE(_pf) release_firmware(_pf)
-
-/*
- * Initialization of the network buffer subsystem
- */
-#define A_NETBUF_INIT()
-
-/*
- * Network buffer queue support
- */
-typedef struct sk_buff_head A_NETBUF_QUEUE_T;
-
-#define A_NETBUF_QUEUE_INIT(q) \
- a_netbuf_queue_init(q)
-
-#define A_NETBUF_ENQUEUE(q, pkt) \
- a_netbuf_enqueue((q), (pkt))
-#define A_NETBUF_PREQUEUE(q, pkt) \
- a_netbuf_prequeue((q), (pkt))
-#define A_NETBUF_DEQUEUE(q) \
- (a_netbuf_dequeue(q))
-#define A_NETBUF_QUEUE_SIZE(q) \
- a_netbuf_queue_size(q)
-#define A_NETBUF_QUEUE_EMPTY(q) \
- (a_netbuf_queue_empty(q) ? true : false)
-
-/*
- * Network buffer support
- */
-#define A_NETBUF_ALLOC(size) \
- a_netbuf_alloc(size)
-#define A_NETBUF_ALLOC_RAW(size) \
- a_netbuf_alloc_raw(size)
-#define A_NETBUF_FREE(bufPtr) \
- a_netbuf_free(bufPtr)
-#define A_NETBUF_DATA(bufPtr) \
- a_netbuf_to_data(bufPtr)
-#define A_NETBUF_LEN(bufPtr) \
- a_netbuf_to_len(bufPtr)
-#define A_NETBUF_PUSH(bufPtr, len) \
- a_netbuf_push(bufPtr, len)
-#define A_NETBUF_PUT(bufPtr, len) \
- a_netbuf_put(bufPtr, len)
-#define A_NETBUF_TRIM(bufPtr,len) \
- a_netbuf_trim(bufPtr, len)
-#define A_NETBUF_PULL(bufPtr, len) \
- a_netbuf_pull(bufPtr, len)
-#define A_NETBUF_HEADROOM(bufPtr)\
- a_netbuf_headroom(bufPtr)
-#define A_NETBUF_SETLEN(bufPtr,len) \
- a_netbuf_setlen(bufPtr, len)
-
-/* Add data to end of a buffer */
-#define A_NETBUF_PUT_DATA(bufPtr, srcPtr, len) \
- a_netbuf_put_data(bufPtr, srcPtr, len)
-
-/* Add data to start of the buffer */
-#define A_NETBUF_PUSH_DATA(bufPtr, srcPtr, len) \
- a_netbuf_push_data(bufPtr, srcPtr, len)
-
-/* Remove data at start of the buffer */
-#define A_NETBUF_PULL_DATA(bufPtr, dstPtr, len) \
- a_netbuf_pull_data(bufPtr, dstPtr, len)
-
-/* Remove data from the end of the buffer */
-#define A_NETBUF_TRIM_DATA(bufPtr, dstPtr, len) \
- a_netbuf_trim_data(bufPtr, dstPtr, len)
-
-/* View data as "size" contiguous bytes of type "t" */
-#define A_NETBUF_VIEW_DATA(bufPtr, t, size) \
- (t )( ((struct skbuf *)(bufPtr))->data)
-
-/* return the beginning of the headroom for the buffer */
-#define A_NETBUF_HEAD(bufPtr) \
- ((((struct sk_buff *)(bufPtr))->head))
-
-/*
- * OS specific network buffer access routines
- */
-void *a_netbuf_alloc(int size);
-void *a_netbuf_alloc_raw(int size);
-void a_netbuf_free(void *bufPtr);
-void *a_netbuf_to_data(void *bufPtr);
-u32 a_netbuf_to_len(void *bufPtr);
-int a_netbuf_push(void *bufPtr, s32 len);
-int a_netbuf_push_data(void *bufPtr, char *srcPtr, s32 len);
-int a_netbuf_put(void *bufPtr, s32 len);
-int a_netbuf_put_data(void *bufPtr, char *srcPtr, s32 len);
-int a_netbuf_pull(void *bufPtr, s32 len);
-int a_netbuf_pull_data(void *bufPtr, char *dstPtr, s32 len);
-int a_netbuf_trim(void *bufPtr, s32 len);
-int a_netbuf_trim_data(void *bufPtr, char *dstPtr, s32 len);
-int a_netbuf_setlen(void *bufPtr, s32 len);
-s32 a_netbuf_headroom(void *bufPtr);
-void a_netbuf_enqueue(A_NETBUF_QUEUE_T *q, void *pkt);
-void a_netbuf_prequeue(A_NETBUF_QUEUE_T *q, void *pkt);
-void *a_netbuf_dequeue(A_NETBUF_QUEUE_T *q);
-int a_netbuf_queue_size(A_NETBUF_QUEUE_T *q);
-int a_netbuf_queue_empty(A_NETBUF_QUEUE_T *q);
-int a_netbuf_queue_empty(A_NETBUF_QUEUE_T *q);
-void a_netbuf_queue_init(A_NETBUF_QUEUE_T *q);
-
-/*
- * Kernel v.s User space functions
- */
-u32 a_copy_to_user(void *to, const void *from, u32 n);
-u32 a_copy_from_user(void *to, const void *from, u32 n);
-
-/* In linux, WLAN Rx and Tx run in different contexts, so no need to check
- * for any commands/data queued for WLAN */
-#define A_CHECK_DRV_TX()
-
-#define A_GET_CACHE_LINE_BYTES() L1_CACHE_BYTES
-
-#define A_CACHE_LINE_PAD 128
-
-static inline void *A_ALIGN_TO_CACHE_LINE(void *ptr) {
- return (void *)L1_CACHE_ALIGN((unsigned long)ptr);
-}
-
-#else /* __KERNEL__ */
-
-#ifdef __GNUC__
-#define __ATTRIB_PACK __attribute__ ((packed))
-#define __ATTRIB_PRINTF __attribute__ ((format (printf, 1, 2)))
-#define __ATTRIB_NORETURN __attribute__ ((noreturn))
-#ifndef INLINE
-#define INLINE __inline__
-#endif
-#else /* Not GCC */
-#define __ATTRIB_PACK
-#define __ATTRIB_PRINTF
-#define __ATTRIB_NORETURN
-#ifndef INLINE
-#define INLINE __inline
-#endif
-#endif /* End __GNUC__ */
-
-#define PREPACK
-#define POSTPACK __ATTRIB_PACK
-
-#define A_MEMZERO(addr, len) memset((addr), 0, (len))
-#define A_MALLOC(size) malloc(size)
-
-#include <err.h>
-
-#endif /* __KERNEL__ */
-
-#endif /* _OSAPI_LINUX_H_ */
diff --git a/drivers/staging/ath6kl/os/linux/include/wlan_config.h b/drivers/staging/ath6kl/os/linux/include/wlan_config.h
deleted file mode 100644
index c1fe0c6e4fa1..000000000000
--- a/drivers/staging/ath6kl/os/linux/include/wlan_config.h
+++ /dev/null
@@ -1,108 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// This file contains the tunable configuration items for the WLAN module
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _HOST_WLAN_CONFIG_H_
-#define _HOST_WLAN_CONFIG_H_
-
-/* Include definitions here that can be used to tune the WLAN module behavior.
- * Different customers can tune the behavior as per their needs, here.
- */
-
-/* This configuration item when defined will consider the barker preamble
- * mentioned in the ERP IE of the beacons from the AP to determine the short
- * preamble support sent in the (Re)Assoc request frames.
- */
-#define WLAN_CONFIG_DONOT_IGNORE_BARKER_IN_ERP 0
-
-/* This config item when defined will not send the power module state transition
- * failure events that happen during scan, to the host.
- */
-#define WLAN_CONFIG_IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN 0
-
-/*
- * This configuration item enable/disable keepalive support.
- * Keepalive support: In the absence of any data traffic to AP, null
- * frames will be sent to the AP at periodic interval, to keep the association
- * active. This configuration item defines the periodic interval.
- * Use value of zero to disable keepalive support
- * Default: 60 seconds
- */
-#define WLAN_CONFIG_KEEP_ALIVE_INTERVAL 60
-
-/*
- * This configuration item sets the value of disconnect timeout
- * Firmware delays sending the disconnec event to the host for this
- * timeout after is gets disconnected from the current AP.
- * If the firmware successly roams within the disconnect timeout
- * it sends a new connect event
- */
-#define WLAN_CONFIG_DISCONNECT_TIMEOUT 10
-
-/*
- * This configuration item disables 11n support.
- * 0 - Enable
- * 1 - Disable
- */
-#define WLAN_CONFIG_DISABLE_11N 0
-
-/*
- * This configuration item enable BT clock sharing support
- * 1 - Enable
- * 0 - Disable (Default)
- */
-#define WLAN_CONFIG_BT_SHARING 0
-
-/*
- * This configuration item sets WIFI OFF policy
- * 0 - CUT_POWER
- * 1 - DEEP_SLEEP (Default)
- */
-#define WLAN_CONFIG_WLAN_OFF 1
-
-/*
- * This configuration item sets suspend policy
- * 0 - CUT_POWER (Default)
- * 1 - DEEP_SLEEP
- * 2 - WoW
- * 3 - CUT_POWER if BT OFF (clock sharing designs only)
- */
-#define WLAN_CONFIG_PM_SUSPEND 0
-
-/*
- * This configuration item sets suspend policy to use if PM_SUSPEND is
- * set to WoW and device is not connected at the time of suspend
- * 0 - CUT_POWER (Default)
- * 1 - DEEP_SLEEP
- * 2 - WoW
- * 3 - CUT_POWER if BT OFF (clock sharing designs only)
- */
-#define WLAN_CONFIG_PM_WOW2 0
-
-/*
- * This configuration item enables/disables transmit bursting
- * 0 - Enable tx Bursting (default)
- * 1 - Disable tx bursting
- */
-#define WLAN_CONFIG_DISABLE_TX_BURSTING 0
-
-#endif /* _HOST_WLAN_CONFIG_H_ */
diff --git a/drivers/staging/ath6kl/os/linux/include/wmi_filter_linux.h b/drivers/staging/ath6kl/os/linux/include/wmi_filter_linux.h
deleted file mode 100644
index 1eb6f822d64e..000000000000
--- a/drivers/staging/ath6kl/os/linux/include/wmi_filter_linux.h
+++ /dev/null
@@ -1,300 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Communications Inc.
-// All rights reserved.
-//
-//
-//
-// 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.
-//
-//
-//
-// Author(s): ="Atheros"
-//------------------------------------------------------------------------------
-
-#ifndef _WMI_FILTER_LINUX_H_
-#define _WMI_FILTER_LINUX_H_
-
-/*
- * sioctl_filter - Standard ioctl
- * pioctl_filter - Priv ioctl
- * xioctl_filter - eXtended ioctl
- *
- * ---- Possible values for the WMI filter ---------------
- * (0) - Block this cmd always (or) not implemented
- * (INFRA_NETWORK) - Allow this cmd only in STA mode
- * (ADHOC_NETWORK) - Allow this cmd only in IBSS mode
- * (AP_NETWORK) - Allow this cmd only in AP mode
- * (INFRA_NETWORK | ADHOC_NETWORK) - Block this cmd in AP mode
- * (ADHOC_NETWORK | AP_NETWORK) - Block this cmd in STA mode
- * (INFRA_NETWORK | AP_NETWORK) - Block this cmd in IBSS mode
- * (INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK)- allow only when mode is set
- * (0xFF) - Allow this cmd always irrespective of mode
- */
-
-u8 sioctl_filter[] = {
-(AP_NETWORK), /* SIOCSIWCOMMIT 0x8B00 */
-(0xFF), /* SIOCGIWNAME 0x8B01 */
-(0), /* SIOCSIWNWID 0x8B02 */
-(0), /* SIOCGIWNWID 0x8B03 */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* SIOCSIWFREQ 0x8B04 */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* SIOCGIWFREQ 0x8B05 */
-(0xFF), /* SIOCSIWMODE 0x8B06 */
-(0xFF), /* SIOCGIWMODE 0x8B07 */
-(0), /* SIOCSIWSENS 0x8B08 */
-(0), /* SIOCGIWSENS 0x8B09 */
-(0), /* SIOCSIWRANGE 0x8B0A */
-(0xFF), /* SIOCGIWRANGE 0x8B0B */
-(0), /* SIOCSIWPRIV 0x8B0C */
-(0), /* SIOCGIWPRIV 0x8B0D */
-(0), /* SIOCSIWSTATS 0x8B0E */
-(0), /* SIOCGIWSTATS 0x8B0F */
-(0), /* SIOCSIWSPY 0x8B10 */
-(0), /* SIOCGIWSPY 0x8B11 */
-(0), /* SIOCSIWTHRSPY 0x8B12 */
-(0), /* SIOCGIWTHRSPY 0x8B13 */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* SIOCSIWAP 0x8B14 */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* SIOCGIWAP 0x8B15 */
-#if (WIRELESS_EXT >= 18)
-(INFRA_NETWORK | ADHOC_NETWORK), /* SIOCSIWMLME 0X8B16 */
-#else
-(0), /* Dummy 0 */
-#endif /* WIRELESS_EXT */
-(0), /* SIOCGIWAPLIST 0x8B17 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* SIOCSIWSCAN 0x8B18 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* SIOCGIWSCAN 0x8B19 */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* SIOCSIWESSID 0x8B1A */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* SIOCGIWESSID 0x8B1B */
-(0), /* SIOCSIWNICKN 0x8B1C */
-(0), /* SIOCGIWNICKN 0x8B1D */
-(0), /* Dummy 0 */
-(0), /* Dummy 0 */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* SIOCSIWRATE 0x8B20 */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* SIOCGIWRATE 0x8B21 */
-(0), /* SIOCSIWRTS 0x8B22 */
-(0), /* SIOCGIWRTS 0x8B23 */
-(0), /* SIOCSIWFRAG 0x8B24 */
-(0), /* SIOCGIWFRAG 0x8B25 */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* SIOCSIWTXPOW 0x8B26 */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* SIOCGIWTXPOW 0x8B27 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* SIOCSIWRETRY 0x8B28 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* SIOCGIWRETRY 0x8B29 */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* SIOCSIWENCODE 0x8B2A */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* SIOCGIWENCODE 0x8B2B */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* SIOCSIWPOWER 0x8B2C */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* SIOCGIWPOWER 0x8B2D */
-};
-
-
-
-u8 pioctl_filter[] = {
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* IEEE80211_IOCTL_SETPARAM (SIOCIWFIRSTPRIV+0) */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* IEEE80211_IOCTL_SETKEY (SIOCIWFIRSTPRIV+1) */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* IEEE80211_IOCTL_DELKEY (SIOCIWFIRSTPRIV+2) */
-(AP_NETWORK), /* IEEE80211_IOCTL_SETMLME (SIOCIWFIRSTPRIV+3) */
-(INFRA_NETWORK), /* IEEE80211_IOCTL_ADDPMKID (SIOCIWFIRSTPRIV+4) */
-(0), /* IEEE80211_IOCTL_SETOPTIE (SIOCIWFIRSTPRIV+5) */
-(0), /* (SIOCIWFIRSTPRIV+6) */
-(0), /* (SIOCIWFIRSTPRIV+7) */
-(0), /* (SIOCIWFIRSTPRIV+8) */
-(0), /* (SIOCIWFIRSTPRIV+9) */
-(0), /* IEEE80211_IOCTL_LASTONE (SIOCIWFIRSTPRIV+10) */
-(0xFF), /* AR6000_IOCTL_WMI_GETREV (SIOCIWFIRSTPRIV+11) */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* AR6000_IOCTL_WMI_SETPWR (SIOCIWFIRSTPRIV+12) */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_IOCTL_WMI_SETSCAN (SIOCIWFIRSTPRIV+13) */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_IOCTL_WMI_SETLISTENINT (SIOCIWFIRSTPRIV+14) */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_IOCTL_WMI_SETBSSFILTER (SIOCIWFIRSTPRIV+15) */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* AR6000_IOCTL_WMI_SET_CHANNELPARAMS (SIOCIWFIRSTPRIV+16) */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_IOCTL_WMI_SET_PROBEDSSID (SIOCIWFIRSTPRIV+17) */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_IOCTL_WMI_SET_PMPARAMS (SIOCIWFIRSTPRIV+18) */
-(INFRA_NETWORK), /* AR6000_IOCTL_WMI_SET_BADAP (SIOCIWFIRSTPRIV+19) */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_IOCTL_WMI_GET_QOS_QUEUE (SIOCIWFIRSTPRIV+20) */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_IOCTL_WMI_CREATE_QOS (SIOCIWFIRSTPRIV+21) */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_IOCTL_WMI_DELETE_QOS (SIOCIWFIRSTPRIV+22) */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_IOCTL_WMI_SET_SNRTHRESHOLD (SIOCIWFIRSTPRIV+23) */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_IOCTL_WMI_SET_ERROR_REPORT_BITMASK (SIOCIWFIRSTPRIV+24)*/
-(0xFF), /* AR6000_IOCTL_WMI_GET_TARGET_STATS (SIOCIWFIRSTPRIV+25) */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_IOCTL_WMI_SET_ASSOC_INFO (SIOCIWFIRSTPRIV+26) */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_IOCTL_WMI_SET_ACCESS_PARAMS (SIOCIWFIRSTPRIV+27) */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_IOCTL_WMI_SET_BMISS_TIME (SIOCIWFIRSTPRIV+28) */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_IOCTL_WMI_SET_DISC_TIMEOUT (SIOCIWFIRSTPRIV+29) */
-(ADHOC_NETWORK), /* AR6000_IOCTL_WMI_SET_IBSS_PM_CAPS (SIOCIWFIRSTPRIV+30) */
-};
-
-
-
-u8 xioctl_filter[] = {
-(0xFF), /* Dummy 0 */
-(0xFF), /* AR6000_XIOCTL_BMI_DONE 1 */
-(0xFF), /* AR6000_XIOCTL_BMI_READ_MEMORY 2 */
-(0xFF), /* AR6000_XIOCTL_BMI_WRITE_MEMORY 3 */
-(0xFF), /* AR6000_XIOCTL_BMI_EXECUTE 4 */
-(0xFF), /* AR6000_XIOCTL_BMI_SET_APP_START 5 */
-(0xFF), /* AR6000_XIOCTL_BMI_READ_SOC_REGISTER 6 */
-(0xFF), /* AR6000_XIOCTL_BMI_WRITE_SOC_REGISTER 7 */
-(0xFF), /* AR6000_XIOCTL_BMI_TEST 8 */
-(0xFF), /* AR6000_XIOCTL_UNUSED9 9 */
-(0xFF), /* AR6000_XIOCTL_UNUSED10 10 */
-(0xFF), /* AR6000_XIOCTL_UNUSED11 11 */
-(0xFF), /* AR6000_XIOCTL_FORCE_TARGET_RESET 12 */
-(0xFF), /* AR6000_XIOCTL_HTC_RAW_OPEN 13 */
-(0xFF), /* AR6000_XIOCTL_HTC_RAW_CLOSE 14 */
-(0xFF), /* AR6000_XIOCTL_HTC_RAW_READ 15 */
-(0xFF), /* AR6000_XIOCTL_HTC_RAW_WRITE 16 */
-(0xFF), /* AR6000_XIOCTL_CHECK_TARGET_READY 17 */
-(0xFF), /* AR6000_XIOCTL_GPIO_OUTPUT_SET 18 */
-(0xFF), /* AR6000_XIOCTL_GPIO_INPUT_GET 19 */
-(0xFF), /* AR6000_XIOCTL_GPIO_REGISTER_SET 20 */
-(0xFF), /* AR6000_XIOCTL_GPIO_REGISTER_GET 21 */
-(0xFF), /* AR6000_XIOCTL_GPIO_INTR_ACK 22 */
-(0xFF), /* AR6000_XIOCTL_GPIO_INTR_WAIT 23 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_SET_ADHOC_BSSID 24 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_SET_OPT_MODE 25 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_OPT_SEND_FRAME 26 */
-(ADHOC_NETWORK | AP_NETWORK), /* AR6000_XIOCTL_SET_BEACON_INTVAL 27 */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* IEEE80211_IOCTL_SETAUTHALG 28 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_SET_VOICE_PKT_SIZE 29 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_SET_MAX_SP 30 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_GET_ROAM_TBL 31 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_ROAM_CTRL 32 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTRL_WMI_SET_POWERSAVE_TIMERS 33 */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* AR6000_XIOCTRL_WMI_GET_POWER_MODE 34 */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* AR6000_XIOCTRL_WMI_SET_WLAN_STATE 35 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_GET_ROAM_DATA 36 */
-(0xFF), /* AR6000_XIOCTL_WMI_SETRETRYLIMITS 37 */
-(0xFF), /* AR6000_XIOCTL_TCMD_CONT_TX 38 */
-(0xFF), /* AR6000_XIOCTL_TCMD_CONT_RX 39 */
-(0xFF), /* AR6000_XIOCTL_TCMD_PM 40 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_STARTSCAN 41 */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* AR6000_XIOCTL_WMI_SETFIXRATES 42 */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* AR6000_XIOCTL_WMI_GETFIXRATES 43 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_RSSITHRESHOLD 44 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_CLR_RSSISNR 45 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_LQTHRESHOLD 46 */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* AR6000_XIOCTL_WMI_SET_RTS 47 */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* AR6000_XIOCTL_WMI_SET_LPREAMBLE 48 */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* AR6000_XIOCTL_WMI_SET_AUTHMODE 49 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_REASSOCMODE 50 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_WMM 51 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_HB_CHALLENGE_RESP_PARAMS 52 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_GET_HB_CHALLENGE_RESP 53 */
-(INFRA_NETWORK | ADHOC_NETWORK | AP_NETWORK), /* AR6000_XIOCTL_WMI_GET_RD 54 */
-(0xFF), /* AR6000_XIOCTL_DIAG_READ 55 */
-(0xFF), /* AR6000_XIOCTL_DIAG_WRITE 56 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_TXOP 57 */
-(INFRA_NETWORK), /* AR6000_XIOCTL_USER_SETKEYS 58 */
-(INFRA_NETWORK), /* AR6000_XIOCTL_WMI_SET_KEEPALIVE 59 */
-(INFRA_NETWORK), /* AR6000_XIOCTL_WMI_GET_KEEPALIVE 60 */
-(0xFF), /* AR6000_XIOCTL_BMI_ROMPATCH_INSTALL 61 */
-(0xFF), /* AR6000_XIOCTL_BMI_ROMPATCH_UNINSTALL 62 */
-(0xFF), /* AR6000_XIOCTL_BMI_ROMPATCH_ACTIVATE 63 */
-(0xFF), /* AR6000_XIOCTL_BMI_ROMPATCH_DEACTIVATE 64 */
-(0xFF), /* AR6000_XIOCTL_WMI_SET_APPIE 65 */
-(0xFF), /* AR6000_XIOCTL_WMI_SET_MGMT_FRM_RX_FILTER 66 */
-(0xFF), /* AR6000_XIOCTL_DBGLOG_CFG_MODULE 67 */
-(0xFF), /* AR6000_XIOCTL_DBGLOG_GET_DEBUG_LOGS 68 */
-(0xFF), /* Dummy 69 */
-(0xFF), /* AR6000_XIOCTL_WMI_SET_WSC_STATUS 70 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_BT_STATUS 71 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_BT_PARAMS 72 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_HOST_SLEEP_MODE 73 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_WOW_MODE 74 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_GET_WOW_LIST 75 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_ADD_WOW_PATTERN 76 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_DEL_WOW_PATTERN 77 */
-(0xFF), /* AR6000_XIOCTL_TARGET_INFO 78 */
-(0xFF), /* AR6000_XIOCTL_DUMP_HTC_CREDIT_STATE 79 */
-(0xFF), /* AR6000_XIOCTL_TRAFFIC_ACTIVITY_CHANGE 80 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_CONNECT_CTRL_FLAGS 81 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_AKMP_PARAMS 82 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_GET_PMKID_LIST 83 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_PMKID_LIST 84 */
-(0xFF), /* Dummy 85 */
-(0xFF), /* Dummy 86 */
-(0xFF), /* Dummy 87 */
-(0xFF), /* Dummy 88 */
-(0xFF), /* Dummy 89 */
-(0xFF), /* AR6000_XIOCTL_UNUSED90 90 */
-(0xFF), /* AR6000_XIOCTL_BMI_LZ_STREAM_START 91 */
-(0xFF), /* AR6000_XIOCTL_BMI_LZ_DATA 92 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_PROF_CFG 93 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_PROF_ADDR_SET 94 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_PROF_START 95 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_PROF_STOP 96 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_PROF_COUNT_GET 97 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_ABORT_SCAN 98 */
-(AP_NETWORK), /* AR6000_XIOCTL_AP_GET_STA_LIST 99 */
-(AP_NETWORK), /* AR6000_XIOCTL_AP_HIDDEN_SSID 100 */
-(AP_NETWORK), /* AR6000_XIOCTL_AP_SET_NUM_STA 101 */
-(AP_NETWORK), /* AR6000_XIOCTL_AP_SET_ACL_MAC 102 */
-(AP_NETWORK), /* AR6000_XIOCTL_AP_GET_ACL_LIST 103 */
-(AP_NETWORK), /* AR6000_XIOCTL_AP_COMMIT_CONFIG 104 */
-(AP_NETWORK), /* IEEE80211_IOCTL_GETWPAIE 105 */
-(AP_NETWORK), /* AR6000_XIOCTL_AP_CONN_INACT_TIME 106 */
-(AP_NETWORK), /* AR6000_XIOCTL_AP_PROT_SCAN_TIME 107 */
-(AP_NETWORK), /* AR6000_XIOCTL_WMI_SET_COUNTRY 108 */
-(AP_NETWORK), /* AR6000_XIOCTL_AP_SET_DTIM 109 */
-(0xFF), /* AR6000_XIOCTL_WMI_TARGET_EVENT_REPORT 110 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_SET_IP 111 */
-(AP_NETWORK), /* AR6000_XIOCTL_AP_SET_ACL_POLICY 112 */
-(AP_NETWORK), /* AR6000_XIOCTL_AP_INTRA_BSS_COMM 113 */
-(0xFF), /* AR6000_XIOCTL_DUMP_MODULE_DEBUG_INFO 114 */
-(0xFF), /* AR6000_XIOCTL_MODULE_DEBUG_SET_MASK 115 */
-(0xFF), /* AR6000_XIOCTL_MODULE_DEBUG_GET_MASK 116 */
-(0xFF), /* AR6000_XIOCTL_DUMP_RCV_AGGR_STATS 117 */
-(0xFF), /* AR6000_XIOCTL_SET_HT_CAP 118 */
-(0xFF), /* AR6000_XIOCTL_SET_HT_OP 119 */
-(AP_NETWORK), /* AR6000_XIOCTL_AP_GET_STAT 120 */
-(0xFF), /* AR6000_XIOCTL_SET_TX_SELECT_RATES 121 */
-(0xFF), /* AR6000_XIOCTL_SETUP_AGGR 122 */
-(0xFF), /* AR6000_XIOCTL_ALLOW_AGGR 123 */
-(AP_NETWORK), /* AR6000_XIOCTL_AP_GET_HIDDEN_SSID 124 */
-(AP_NETWORK), /* AR6000_XIOCTL_AP_GET_COUNTRY 125 */
-(AP_NETWORK), /* AR6000_XIOCTL_AP_GET_WMODE 126 */
-(AP_NETWORK), /* AR6000_XIOCTL_AP_GET_DTIM 127 */
-(AP_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_AP_GET_BINTVL 128 */
-(0xFF), /* AR6000_XIOCTL_AP_GET_RTS 129 */
-(0xFF), /* AR6000_XIOCTL_DELE_AGGR 130 */
-(0xFF), /* AR6000_XIOCTL_FETCH_TARGET_REGS 131 */
-(0xFF), /* AR6000_XIOCTL_HCI_CMD 132 */
-(0xFF), /* AR6000_XIOCTL_ACL_DATA(used to be used for PAL) 133 */
-(0xFF), /* AR6000_XIOCTL_WLAN_CONN_PRECEDENCE 134 */
-(AP_NETWORK), /* AR6000_XIOCTL_AP_SET_11BG_RATESET 135 */
-(0xFF),
-(0xFF),
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_BTCOEX_FE_ANT 138 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_BTCOEX_COLOCATED_BT_DEV 139 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG 140 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_BTCOEX_SCO_CONFIG 141 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_BTCOEX_A2DP_CONFIG 142 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_BTCOEX_ACLCOEX_CONFIG 143 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_BTCOEX_DEBUG 144 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_BT_OPERATING_STATUS 145 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_GET_BTCOEX_CONFIG 146 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_GET_BTCOEX_GET_STATS 147 */
-(0xFF), /* AR6000_XIOCTL_WMI_SET_QOS_SUPP 148 */
-(0xFF), /* AR6000_XIOCTL_GET_WLAN_SLEEP_STATE 149 */
-(0xFF), /* AR6000_XIOCTL_SET_BT_HW_POWER_STATE 150 */
-(0xFF), /* AR6000_XIOCTL_GET_BT_HW_POWER_STATE 151 */
-(0xFF), /* AR6000_XIOCTL_ADD_AP_INTERFACE 152 */
-(0xFF), /* AR6000_XIOCTL_REMOVE_AP_INTERFACE 153 */
-(0xFF), /* AR6000_XIOCTL_WMI_SET_TX_SGI_PARAM 154 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_WPA_OFFLOAD_STATE 155 */
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_PASSPHRASE 156 */
-(0xFF),
-(0xFF),
-(0xFF),
-(0xFF),
-(INFRA_NETWORK | ADHOC_NETWORK), /* AR6000_XIOCTL_WMI_SET_EXCESS_TX_RETRY_THRES 161 */
-};
-
-#endif /*_WMI_FILTER_LINUX_H_*/
diff --git a/drivers/staging/ath6kl/os/linux/netbuf.c b/drivers/staging/ath6kl/os/linux/netbuf.c
deleted file mode 100644
index 963a2fb76a92..000000000000
--- a/drivers/staging/ath6kl/os/linux/netbuf.c
+++ /dev/null
@@ -1,231 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Communications Inc.
-// All rights reserved.
-//
-//
-//
-// 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.
-//
-//
-//
-// Author(s): ="Atheros"
-//------------------------------------------------------------------------------
-#include <a_config.h>
-#include "athdefs.h"
-#include "a_osapi.h"
-#include "htc_packet.h"
-
-#define AR6000_DATA_OFFSET 64
-
-void a_netbuf_enqueue(A_NETBUF_QUEUE_T *q, void *pkt)
-{
- skb_queue_tail((struct sk_buff_head *) q, (struct sk_buff *) pkt);
-}
-
-void a_netbuf_prequeue(A_NETBUF_QUEUE_T *q, void *pkt)
-{
- skb_queue_head((struct sk_buff_head *) q, (struct sk_buff *) pkt);
-}
-
-void *a_netbuf_dequeue(A_NETBUF_QUEUE_T *q)
-{
- return((void *) skb_dequeue((struct sk_buff_head *) q));
-}
-
-int a_netbuf_queue_size(A_NETBUF_QUEUE_T *q)
-{
- return(skb_queue_len((struct sk_buff_head *) q));
-}
-
-int a_netbuf_queue_empty(A_NETBUF_QUEUE_T *q)
-{
- return(skb_queue_empty((struct sk_buff_head *) q));
-}
-
-void a_netbuf_queue_init(A_NETBUF_QUEUE_T *q)
-{
- skb_queue_head_init((struct sk_buff_head *) q);
-}
-
-void *
-a_netbuf_alloc(int size)
-{
- struct sk_buff *skb;
- size += 2 * (A_GET_CACHE_LINE_BYTES()); /* add some cacheline space at front and back of buffer */
- skb = dev_alloc_skb(AR6000_DATA_OFFSET + sizeof(struct htc_packet) + size);
- skb_reserve(skb, AR6000_DATA_OFFSET + sizeof(struct htc_packet) + A_GET_CACHE_LINE_BYTES());
- return ((void *)skb);
-}
-
-/*
- * Allocate an SKB w.o. any encapsulation requirement.
- */
-void *
-a_netbuf_alloc_raw(int size)
-{
- struct sk_buff *skb;
-
- skb = dev_alloc_skb(size);
-
- return ((void *)skb);
-}
-
-void
-a_netbuf_free(void *bufPtr)
-{
- struct sk_buff *skb = (struct sk_buff *)bufPtr;
-
- dev_kfree_skb(skb);
-}
-
-u32 a_netbuf_to_len(void *bufPtr)
-{
- return (((struct sk_buff *)bufPtr)->len);
-}
-
-void *
-a_netbuf_to_data(void *bufPtr)
-{
- return (((struct sk_buff *)bufPtr)->data);
-}
-
-/*
- * Add len # of bytes to the beginning of the network buffer
- * pointed to by bufPtr
- */
-int
-a_netbuf_push(void *bufPtr, s32 len)
-{
- skb_push((struct sk_buff *)bufPtr, len);
-
- return 0;
-}
-
-/*
- * Add len # of bytes to the beginning of the network buffer
- * pointed to by bufPtr and also fill with data
- */
-int
-a_netbuf_push_data(void *bufPtr, char *srcPtr, s32 len)
-{
- skb_push((struct sk_buff *) bufPtr, len);
- memcpy(((struct sk_buff *)bufPtr)->data, srcPtr, len);
-
- return 0;
-}
-
-/*
- * Add len # of bytes to the end of the network buffer
- * pointed to by bufPtr
- */
-int
-a_netbuf_put(void *bufPtr, s32 len)
-{
- skb_put((struct sk_buff *)bufPtr, len);
-
- return 0;
-}
-
-/*
- * Add len # of bytes to the end of the network buffer
- * pointed to by bufPtr and also fill with data
- */
-int
-a_netbuf_put_data(void *bufPtr, char *srcPtr, s32 len)
-{
- char *start = (char*)(((struct sk_buff *)bufPtr)->data +
- ((struct sk_buff *)bufPtr)->len);
- skb_put((struct sk_buff *)bufPtr, len);
- memcpy(start, srcPtr, len);
-
- return 0;
-}
-
-
-/*
- * Trim the network buffer pointed to by bufPtr to len # of bytes
- */
-int
-a_netbuf_setlen(void *bufPtr, s32 len)
-{
- skb_trim((struct sk_buff *)bufPtr, len);
-
- return 0;
-}
-
-/*
- * Chop of len # of bytes from the end of the buffer.
- */
-int
-a_netbuf_trim(void *bufPtr, s32 len)
-{
- skb_trim((struct sk_buff *)bufPtr, ((struct sk_buff *)bufPtr)->len - len);
-
- return 0;
-}
-
-/*
- * Chop of len # of bytes from the end of the buffer and return the data.
- */
-int
-a_netbuf_trim_data(void *bufPtr, char *dstPtr, s32 len)
-{
- char *start = (char*)(((struct sk_buff *)bufPtr)->data +
- (((struct sk_buff *)bufPtr)->len - len));
-
- memcpy(dstPtr, start, len);
- skb_trim((struct sk_buff *)bufPtr, ((struct sk_buff *)bufPtr)->len - len);
-
- return 0;
-}
-
-
-/*
- * Returns the number of bytes available to a a_netbuf_push()
- */
-s32 a_netbuf_headroom(void *bufPtr)
-{
- return (skb_headroom((struct sk_buff *)bufPtr));
-}
-
-/*
- * Removes specified number of bytes from the beginning of the buffer
- */
-int
-a_netbuf_pull(void *bufPtr, s32 len)
-{
- skb_pull((struct sk_buff *)bufPtr, len);
-
- return 0;
-}
-
-/*
- * Removes specified number of bytes from the beginning of the buffer
- * and return the data
- */
-int
-a_netbuf_pull_data(void *bufPtr, char *dstPtr, s32 len)
-{
- memcpy(dstPtr, ((struct sk_buff *)bufPtr)->data, len);
- skb_pull((struct sk_buff *)bufPtr, len);
-
- return 0;
-}
-
-#ifdef EXPORT_HCI_BRIDGE_INTERFACE
-EXPORT_SYMBOL(a_netbuf_to_data);
-EXPORT_SYMBOL(a_netbuf_put);
-EXPORT_SYMBOL(a_netbuf_pull);
-EXPORT_SYMBOL(a_netbuf_alloc);
-EXPORT_SYMBOL(a_netbuf_free);
-#endif
diff --git a/drivers/staging/ath6kl/reorder/aggr_rx_internal.h b/drivers/staging/ath6kl/reorder/aggr_rx_internal.h
deleted file mode 100644
index 11125967d53d..000000000000
--- a/drivers/staging/ath6kl/reorder/aggr_rx_internal.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- *
- * Copyright (c) 2004-2010 Atheros Communications Inc.
- * All rights reserved.
- *
- *
-//
-// 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 __AGGR_RX_INTERNAL_H__
-#define __AGGR_RX_INTERNAL_H__
-
-#include "a_osapi.h"
-#include "aggr_recv_api.h"
-
-#define AGGR_WIN_IDX(x, y) ((x) % (y))
-#define AGGR_INCR_IDX(x, y) AGGR_WIN_IDX(((x)+1), (y))
-#define AGGR_DCRM_IDX(x, y) AGGR_WIN_IDX(((x)-1), (y))
-#define IEEE80211_MAX_SEQ_NO 0xFFF
-#define IEEE80211_NEXT_SEQ_NO(x) (((x) + 1) & IEEE80211_MAX_SEQ_NO)
-
-
-#define NUM_OF_TIDS 8
-#define AGGR_SZ_DEFAULT 8
-
-#define AGGR_WIN_SZ_MIN 2
-#define AGGR_WIN_SZ_MAX 8
-/* TID Window sz is double of what is negotiated. Derive TID_WINDOW_SZ from win_sz, per tid */
-#define TID_WINDOW_SZ(_x) ((_x) << 1)
-
-#define AGGR_NUM_OF_FREE_NETBUFS 16
-
-#define AGGR_GET_RXTID_STATS(_p, _x) (&(_p->stat[(_x)]))
-#define AGGR_GET_RXTID(_p, _x) (&(_p->RxTid[(_x)]))
-
-/* Hold q is a function of win_sz, which is negotiated per tid */
-#define HOLD_Q_SZ(_x) (TID_WINDOW_SZ((_x))*sizeof(struct osbuf_hold_q))
-/* AGGR_RX_TIMEOUT value is important as a (too) small value can cause frames to be
- * delivered out of order and a (too) large value can cause undesirable latency in
- * certain situations. */
-#define AGGR_RX_TIMEOUT 400 /* Timeout(in ms) for delivery of frames, if they are stuck */
-
-typedef enum {
- ALL_SEQNO = 0,
- CONTIGUOUS_SEQNO = 1,
-}DELIVERY_ORDER;
-
-struct osbuf_hold_q {
- void *osbuf;
- bool is_amsdu;
- u16 seq_no;
-};
-
-
-#if 0
-/* XXX: unused ? */
-struct window_snapshot {
- u16 seqno_st;
- u16 seqno_end;
-};
-#endif
-
-struct rxtid {
- bool aggr; /* is it ON or OFF */
- bool progress; /* true when frames have arrived after a timer start */
- bool timerMon; /* true if the timer started for the sake of this TID */
- u16 win_sz; /* negotiated window size */
- u16 seq_next; /* Next seq no, in current window */
- u32 hold_q_sz; /* Num of frames that can be held in hold q */
- struct osbuf_hold_q *hold_q; /* Hold q for re-order */
-#if 0
- struct window_snapshot old_win; /* Sliding window snapshot - for timeout */
-#endif
- A_NETBUF_QUEUE_T q; /* q head for enqueuing frames for dispatch */
- A_MUTEX_T lock;
-};
-
-struct rxtid_stats {
- u32 num_into_aggr; /* hitting at the input of this module */
- u32 num_dups; /* duplicate */
- u32 num_oow; /* out of window */
- u32 num_mpdu; /* single payload 802.3/802.11 frame */
- u32 num_amsdu; /* AMSDU */
- u32 num_delivered; /* frames delivered to IP stack */
- u32 num_timeouts; /* num of timeouts, during which frames delivered */
- u32 num_hole; /* frame not present, when window moved over */
- u32 num_bar; /* num of resets of seq_num, via BAR */
-};
-
-struct aggr_info {
- u8 aggr_sz; /* config value of aggregation size */
- u8 timerScheduled;
- A_TIMER timer; /* timer for returning held up pkts in re-order que */
- void *dev; /* dev handle */
- RX_CALLBACK rx_fn; /* callback function to return frames; to upper layer */
- struct rxtid RxTid[NUM_OF_TIDS]; /* Per tid window */
- ALLOC_NETBUFS netbuf_allocator; /* OS netbuf alloc fn */
- A_NETBUF_QUEUE_T freeQ; /* pre-allocated buffers - for A_MSDU slicing */
- struct rxtid_stats stat[NUM_OF_TIDS]; /* Tid based statistics */
- PACKET_LOG pkt_log; /* Log info of the packets */
-};
-
-#endif /* __AGGR_RX_INTERNAL_H__ */
diff --git a/drivers/staging/ath6kl/reorder/rcv_aggr.c b/drivers/staging/ath6kl/reorder/rcv_aggr.c
deleted file mode 100644
index 9b1509ec5a7b..000000000000
--- a/drivers/staging/ath6kl/reorder/rcv_aggr.c
+++ /dev/null
@@ -1,661 +0,0 @@
-/*
- *
- * Copyright (c) 2010 Atheros Communications Inc.
- * All rights reserved.
- *
- *
-//
-// 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 <a_config.h>
-#include <athdefs.h>
-#include <a_osapi.h>
-#include <a_debug.h>
-#include "pkt_log.h"
-#include "aggr_recv_api.h"
-#include "aggr_rx_internal.h"
-#include "wmi.h"
-
-extern int
-wmi_dot3_2_dix(void *osbuf);
-
-static void
-aggr_slice_amsdu(struct aggr_info *p_aggr, struct rxtid *rxtid, void **osbuf);
-
-static void
-aggr_timeout(unsigned long arg);
-
-static void
-aggr_deque_frms(struct aggr_info *p_aggr, u8 tid, u16 seq_no, u8 order);
-
-static void
-aggr_dispatch_frames(struct aggr_info *p_aggr, A_NETBUF_QUEUE_T *q);
-
-static void *
-aggr_get_osbuf(struct aggr_info *p_aggr);
-
-void *
-aggr_init(ALLOC_NETBUFS netbuf_allocator)
-{
- struct aggr_info *p_aggr = NULL;
- struct rxtid *rxtid;
- u8 i;
- int status = 0;
-
- A_PRINTF("In aggr_init..\n");
-
- do {
- p_aggr = A_MALLOC(sizeof(struct aggr_info));
- if(!p_aggr) {
- A_PRINTF("Failed to allocate memory for aggr_node\n");
- status = A_ERROR;
- break;
- }
-
- /* Init timer and data structures */
- A_MEMZERO(p_aggr, sizeof(struct aggr_info));
- p_aggr->aggr_sz = AGGR_SZ_DEFAULT;
- A_INIT_TIMER(&p_aggr->timer, aggr_timeout, p_aggr);
- p_aggr->timerScheduled = false;
- A_NETBUF_QUEUE_INIT(&p_aggr->freeQ);
-
- p_aggr->netbuf_allocator = netbuf_allocator;
- p_aggr->netbuf_allocator(&p_aggr->freeQ, AGGR_NUM_OF_FREE_NETBUFS);
-
- for(i = 0; i < NUM_OF_TIDS; i++) {
- rxtid = AGGR_GET_RXTID(p_aggr, i);
- rxtid->aggr = false;
- rxtid->progress = false;
- rxtid->timerMon = false;
- A_NETBUF_QUEUE_INIT(&rxtid->q);
- A_MUTEX_INIT(&rxtid->lock);
- }
- }while(false);
-
- A_PRINTF("going out of aggr_init..status %s\n",
- (status == 0) ? "OK":"Error");
-
- if (status) {
- /* Cleanup */
- aggr_module_destroy(p_aggr);
- }
- return ((status == 0) ? p_aggr : NULL);
-}
-
-/* utility function to clear rx hold_q for a tid */
-static void
-aggr_delete_tid_state(struct aggr_info *p_aggr, u8 tid)
-{
- struct rxtid *rxtid;
- struct rxtid_stats *stats;
-
- A_ASSERT(tid < NUM_OF_TIDS && p_aggr);
-
- rxtid = AGGR_GET_RXTID(p_aggr, tid);
- stats = AGGR_GET_RXTID_STATS(p_aggr, tid);
-
- if(rxtid->aggr) {
- aggr_deque_frms(p_aggr, tid, 0, ALL_SEQNO);
- }
-
- rxtid->aggr = false;
- rxtid->progress = false;
- rxtid->timerMon = false;
- rxtid->win_sz = 0;
- rxtid->seq_next = 0;
- rxtid->hold_q_sz = 0;
-
- if(rxtid->hold_q) {
- kfree(rxtid->hold_q);
- rxtid->hold_q = NULL;
- }
-
- A_MEMZERO(stats, sizeof(struct rxtid_stats));
-}
-
-void
-aggr_module_destroy(void *cntxt)
-{
- struct aggr_info *p_aggr = (struct aggr_info *)cntxt;
- struct rxtid *rxtid;
- u8 i, k;
- A_PRINTF("%s(): aggr = %p\n",_A_FUNCNAME_, p_aggr);
- A_ASSERT(p_aggr);
-
- if(p_aggr) {
- if(p_aggr->timerScheduled) {
- A_UNTIMEOUT(&p_aggr->timer);
- p_aggr->timerScheduled = false;
- }
-
- for(i = 0; i < NUM_OF_TIDS; i++) {
- rxtid = AGGR_GET_RXTID(p_aggr, i);
- /* Free the hold q contents and hold_q*/
- if(rxtid->hold_q) {
- for(k = 0; k< rxtid->hold_q_sz; k++) {
- if(rxtid->hold_q[k].osbuf) {
- A_NETBUF_FREE(rxtid->hold_q[k].osbuf);
- }
- }
- kfree(rxtid->hold_q);
- }
- /* Free the dispatch q contents*/
- while(A_NETBUF_QUEUE_SIZE(&rxtid->q)) {
- A_NETBUF_FREE(A_NETBUF_DEQUEUE(&rxtid->q));
- }
- if (A_IS_MUTEX_VALID(&rxtid->lock)) {
- A_MUTEX_DELETE(&rxtid->lock);
- }
- }
- /* free the freeQ and its contents*/
- while(A_NETBUF_QUEUE_SIZE(&p_aggr->freeQ)) {
- A_NETBUF_FREE(A_NETBUF_DEQUEUE(&p_aggr->freeQ));
- }
- kfree(p_aggr);
- }
- A_PRINTF("out aggr_module_destroy\n");
-}
-
-
-void
-aggr_register_rx_dispatcher(void *cntxt, void * dev, RX_CALLBACK fn)
-{
- struct aggr_info *p_aggr = (struct aggr_info *)cntxt;
-
- A_ASSERT(p_aggr && fn && dev);
-
- p_aggr->rx_fn = fn;
- p_aggr->dev = dev;
-}
-
-
-void
-aggr_process_bar(void *cntxt, u8 tid, u16 seq_no)
-{
- struct aggr_info *p_aggr = (struct aggr_info *)cntxt;
- struct rxtid_stats *stats;
-
- A_ASSERT(p_aggr);
- stats = AGGR_GET_RXTID_STATS(p_aggr, tid);
- stats->num_bar++;
-
- aggr_deque_frms(p_aggr, tid, seq_no, ALL_SEQNO);
-}
-
-
-void
-aggr_recv_addba_req_evt(void *cntxt, u8 tid, u16 seq_no, u8 win_sz)
-{
- struct aggr_info *p_aggr = (struct aggr_info *)cntxt;
- struct rxtid *rxtid;
- struct rxtid_stats *stats;
-
- A_ASSERT(p_aggr);
- rxtid = AGGR_GET_RXTID(p_aggr, tid);
- stats = AGGR_GET_RXTID_STATS(p_aggr, tid);
-
- A_PRINTF("%s(): win_sz = %d aggr %d\n", _A_FUNCNAME_, win_sz, rxtid->aggr);
- if(win_sz < AGGR_WIN_SZ_MIN || win_sz > AGGR_WIN_SZ_MAX) {
- A_PRINTF("win_sz %d, tid %d\n", win_sz, tid);
- }
-
- if(rxtid->aggr) {
- /* Just go and deliver all the frames up from this
- * queue, as if we got DELBA and re-initialize the queue
- */
- aggr_delete_tid_state(p_aggr, tid);
- }
-
- rxtid->seq_next = seq_no;
- /* create these queues, only upon receiving of ADDBA for a
- * tid, reducing memory requirement
- */
- rxtid->hold_q = A_MALLOC(HOLD_Q_SZ(win_sz));
- if((rxtid->hold_q == NULL)) {
- A_PRINTF("Failed to allocate memory, tid = %d\n", tid);
- A_ASSERT(0);
- }
- A_MEMZERO(rxtid->hold_q, HOLD_Q_SZ(win_sz));
-
- /* Update rxtid for the window sz */
- rxtid->win_sz = win_sz;
- /* hold_q_sz inicates the depth of holding q - which is
- * a factor of win_sz. Compute once, as it will be used often
- */
- rxtid->hold_q_sz = TID_WINDOW_SZ(win_sz);
- /* There should be no frames on q - even when second ADDBA comes in.
- * If aggr was previously ON on this tid, we would have cleaned up
- * the q
- */
- if(A_NETBUF_QUEUE_SIZE(&rxtid->q) != 0) {
- A_PRINTF("ERROR: Frames still on queue ?\n");
- A_ASSERT(0);
- }
-
- rxtid->aggr = true;
-}
-
-void
-aggr_recv_delba_req_evt(void *cntxt, u8 tid)
-{
- struct aggr_info *p_aggr = (struct aggr_info *)cntxt;
- struct rxtid *rxtid;
-
- A_ASSERT(p_aggr);
- A_PRINTF("%s(): tid %d\n", _A_FUNCNAME_, tid);
-
- rxtid = AGGR_GET_RXTID(p_aggr, tid);
-
- if(rxtid->aggr) {
- aggr_delete_tid_state(p_aggr, tid);
- }
-}
-
-static void
-aggr_deque_frms(struct aggr_info *p_aggr, u8 tid, u16 seq_no, u8 order)
-{
- struct rxtid *rxtid;
- struct osbuf_hold_q *node;
- u16 idx, idx_end, seq_end;
- struct rxtid_stats *stats;
-
- A_ASSERT(p_aggr);
- rxtid = AGGR_GET_RXTID(p_aggr, tid);
- stats = AGGR_GET_RXTID_STATS(p_aggr, tid);
-
- /* idx is absolute location for first frame */
- idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz);
-
- /* idx_end is typically the last possible frame in the window,
- * but changes to 'the' seq_no, when BAR comes. If seq_no
- * is non-zero, we will go up to that and stop.
- * Note: last seq no in current window will occupy the same
- * index position as index that is just previous to start.
- * An imp point : if win_sz is 7, for seq_no space of 4095,
- * then, there would be holes when sequence wrap around occurs.
- * Target should judiciously choose the win_sz, based on
- * this condition. For 4095, (TID_WINDOW_SZ = 2 x win_sz
- * 2, 4, 8, 16 win_sz works fine).
- * We must deque from "idx" to "idx_end", including both.
- */
- seq_end = (seq_no) ? seq_no : rxtid->seq_next;
- idx_end = AGGR_WIN_IDX(seq_end, rxtid->hold_q_sz);
-
- /* Critical section begins */
- A_MUTEX_LOCK(&rxtid->lock);
- do {
-
- node = &rxtid->hold_q[idx];
-
- if((order == CONTIGUOUS_SEQNO) && (!node->osbuf))
- break;
-
- /* chain frames and deliver frames bcos:
- * 1. either the frames are in order and window is contiguous, OR
- * 2. we need to deque frames, irrespective of holes
- */
- if(node->osbuf) {
- if(node->is_amsdu) {
- aggr_slice_amsdu(p_aggr, rxtid, &node->osbuf);
- } else {
- A_NETBUF_ENQUEUE(&rxtid->q, node->osbuf);
- }
- node->osbuf = NULL;
- } else {
- stats->num_hole++;
- }
-
- /* window is moving */
- rxtid->seq_next = IEEE80211_NEXT_SEQ_NO(rxtid->seq_next);
- idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz);
- } while(idx != idx_end);
- /* Critical section ends */
- A_MUTEX_UNLOCK(&rxtid->lock);
-
- stats->num_delivered += A_NETBUF_QUEUE_SIZE(&rxtid->q);
- aggr_dispatch_frames(p_aggr, &rxtid->q);
-}
-
-static void *
-aggr_get_osbuf(struct aggr_info *p_aggr)
-{
- void *buf = NULL;
-
- /* Starving for buffers? get more from OS
- * check for low netbuffers( < 1/4 AGGR_NUM_OF_FREE_NETBUFS) :
- * re-allocate bufs if so
- * allocate a free buf from freeQ
- */
- if (A_NETBUF_QUEUE_SIZE(&p_aggr->freeQ) < (AGGR_NUM_OF_FREE_NETBUFS >> 2)) {
- p_aggr->netbuf_allocator(&p_aggr->freeQ, AGGR_NUM_OF_FREE_NETBUFS);
- }
-
- if (A_NETBUF_QUEUE_SIZE(&p_aggr->freeQ)) {
- buf = A_NETBUF_DEQUEUE(&p_aggr->freeQ);
- }
-
- return buf;
-}
-
-
-static void
-aggr_slice_amsdu(struct aggr_info *p_aggr, struct rxtid *rxtid, void **osbuf)
-{
- void *new_buf;
- u16 frame_8023_len, payload_8023_len, mac_hdr_len, amsdu_len;
- u8 *framep;
-
- /* Frame format at this point:
- * [DIX hdr | 802.3 | 802.3 | ... | 802.3]
- *
- * Strip the DIX header.
- * Iterate through the osbuf and do:
- * grab a free netbuf from freeQ
- * find the start and end of a frame
- * copy it to netbuf(Vista can do better here)
- * convert all msdu's(802.3) frames to upper layer format - os routine
- * -for now lets convert from 802.3 to dix
- * enque this to dispatch q of tid
- * repeat
- * free the osbuf - to OS. It's been sliced.
- */
-
- mac_hdr_len = sizeof(ATH_MAC_HDR);
- framep = A_NETBUF_DATA(*osbuf) + mac_hdr_len;
- amsdu_len = A_NETBUF_LEN(*osbuf) - mac_hdr_len;
-
- while(amsdu_len > mac_hdr_len) {
- /* Begin of a 802.3 frame */
- payload_8023_len = A_BE2CPU16(((ATH_MAC_HDR *)framep)->typeOrLen);
-#define MAX_MSDU_SUBFRAME_PAYLOAD_LEN 1508
-#define MIN_MSDU_SUBFRAME_PAYLOAD_LEN 46
- if(payload_8023_len < MIN_MSDU_SUBFRAME_PAYLOAD_LEN || payload_8023_len > MAX_MSDU_SUBFRAME_PAYLOAD_LEN) {
- A_PRINTF("802.3 AMSDU frame bound check failed. len %d\n", payload_8023_len);
- break;
- }
- frame_8023_len = payload_8023_len + mac_hdr_len;
- new_buf = aggr_get_osbuf(p_aggr);
- if(new_buf == NULL) {
- A_PRINTF("No buffer available \n");
- break;
- }
-
- memcpy(A_NETBUF_DATA(new_buf), framep, frame_8023_len);
- A_NETBUF_PUT(new_buf, frame_8023_len);
- if (wmi_dot3_2_dix(new_buf) != 0) {
- A_PRINTF("dot3_2_dix err..\n");
- A_NETBUF_FREE(new_buf);
- break;
- }
-
- A_NETBUF_ENQUEUE(&rxtid->q, new_buf);
-
- /* Is this the last subframe within this aggregate ? */
- if ((amsdu_len - frame_8023_len) == 0) {
- break;
- }
-
- /* Add the length of A-MSDU subframe padding bytes -
- * Round to nearest word.
- */
- frame_8023_len = ((frame_8023_len + 3) & ~3);
-
- framep += frame_8023_len;
- amsdu_len -= frame_8023_len;
- }
-
- A_NETBUF_FREE(*osbuf);
- *osbuf = NULL;
-}
-
-void
-aggr_process_recv_frm(void *cntxt, u8 tid, u16 seq_no, bool is_amsdu, void **osbuf)
-{
- struct aggr_info *p_aggr = (struct aggr_info *)cntxt;
- struct rxtid *rxtid;
- struct rxtid_stats *stats;
- u16 idx, st, cur, end;
- u16 *log_idx;
- struct osbuf_hold_q *node;
- PACKET_LOG *log;
-
- A_ASSERT(p_aggr);
- A_ASSERT(tid < NUM_OF_TIDS);
-
- rxtid = AGGR_GET_RXTID(p_aggr, tid);
- stats = AGGR_GET_RXTID_STATS(p_aggr, tid);
-
- stats->num_into_aggr++;
-
- if(!rxtid->aggr) {
- if(is_amsdu) {
- aggr_slice_amsdu(p_aggr, rxtid, osbuf);
- stats->num_amsdu++;
- aggr_dispatch_frames(p_aggr, &rxtid->q);
- }
- return;
- }
-
- /* Check the incoming sequence no, if it's in the window */
- st = rxtid->seq_next;
- cur = seq_no;
- end = (st + rxtid->hold_q_sz-1) & IEEE80211_MAX_SEQ_NO;
- /* Log the pkt info for future analysis */
- log = &p_aggr->pkt_log;
- log_idx = &log->last_idx;
- log->info[*log_idx].cur = cur;
- log->info[*log_idx].st = st;
- log->info[*log_idx].end = end;
- *log_idx = IEEE80211_NEXT_SEQ_NO(*log_idx);
-
- if(((st < end) && (cur < st || cur > end)) ||
- ((st > end) && (cur > end) && (cur < st))) {
- /* the cur frame is outside the window. Since we know
- * our target would not do this without reason it must
- * be assumed that the window has moved for some valid reason.
- * Therefore, we dequeue all frames and start fresh.
- */
- u16 extended_end;
-
- extended_end = (end + rxtid->hold_q_sz-1) & IEEE80211_MAX_SEQ_NO;
-
- if(((end < extended_end) && (cur < end || cur > extended_end)) ||
- ((end > extended_end) && (cur > extended_end) && (cur < end))) {
- // dequeue all frames in queue and shift window to new frame
- aggr_deque_frms(p_aggr, tid, 0, ALL_SEQNO);
- //set window start so that new frame is last frame in window
- if(cur >= rxtid->hold_q_sz-1) {
- rxtid->seq_next = cur - (rxtid->hold_q_sz-1);
- }else{
- rxtid->seq_next = IEEE80211_MAX_SEQ_NO - (rxtid->hold_q_sz-2 - cur);
- }
- } else {
- // dequeue only those frames that are outside the new shifted window
- if(cur >= rxtid->hold_q_sz-1) {
- st = cur - (rxtid->hold_q_sz-1);
- }else{
- st = IEEE80211_MAX_SEQ_NO - (rxtid->hold_q_sz-2 - cur);
- }
-
- aggr_deque_frms(p_aggr, tid, st, ALL_SEQNO);
- }
-
- stats->num_oow++;
- }
-
- idx = AGGR_WIN_IDX(seq_no, rxtid->hold_q_sz);
-
- /*enque the frame, in hold_q */
- node = &rxtid->hold_q[idx];
-
- A_MUTEX_LOCK(&rxtid->lock);
- if(node->osbuf) {
- /* Is the cur frame duplicate or something beyond our
- * window(hold_q -> which is 2x, already)?
- * 1. Duplicate is easy - drop incoming frame.
- * 2. Not falling in current sliding window.
- * 2a. is the frame_seq_no preceding current tid_seq_no?
- * -> drop the frame. perhaps sender did not get our ACK.
- * this is taken care of above.
- * 2b. is the frame_seq_no beyond window(st, TID_WINDOW_SZ);
- * -> Taken care of it above, by moving window forward.
- *
- */
- A_NETBUF_FREE(node->osbuf);
- stats->num_dups++;
- }
-
- node->osbuf = *osbuf;
- node->is_amsdu = is_amsdu;
- node->seq_no = seq_no;
- if(node->is_amsdu) {
- stats->num_amsdu++;
- } else {
- stats->num_mpdu++;
- }
- A_MUTEX_UNLOCK(&rxtid->lock);
-
- *osbuf = NULL;
- aggr_deque_frms(p_aggr, tid, 0, CONTIGUOUS_SEQNO);
-
- if(p_aggr->timerScheduled) {
- rxtid->progress = true;
- }else{
- for(idx=0 ; idx<rxtid->hold_q_sz ; idx++) {
- if(rxtid->hold_q[idx].osbuf) {
- /* there is a frame in the queue and no timer so
- * start a timer to ensure that the frame doesn't remain
- * stuck forever. */
- p_aggr->timerScheduled = true;
- A_TIMEOUT_MS(&p_aggr->timer, AGGR_RX_TIMEOUT, 0);
- rxtid->progress = false;
- rxtid->timerMon = true;
- break;
- }
- }
- }
-}
-
-/*
- * aggr_reset_state -- Called when it is deemed necessary to clear the aggregate
- * hold Q state. Examples include when a Connect event or disconnect event is
- * received.
- */
-void
-aggr_reset_state(void *cntxt)
-{
- u8 tid;
- struct aggr_info *p_aggr = (struct aggr_info *)cntxt;
-
- A_ASSERT(p_aggr);
-
- for(tid=0 ; tid<NUM_OF_TIDS ; tid++) {
- aggr_delete_tid_state(p_aggr, tid);
- }
-}
-
-
-static void
-aggr_timeout(unsigned long arg)
-{
- u8 i,j;
- struct aggr_info *p_aggr = (struct aggr_info *)arg;
- struct rxtid *rxtid;
- struct rxtid_stats *stats;
- /*
- * If the q for which the timer was originally started has
- * not progressed then it is necessary to dequeue all the
- * contained frames so that they are not held forever.
- */
- for(i = 0; i < NUM_OF_TIDS; i++) {
- rxtid = AGGR_GET_RXTID(p_aggr, i);
- stats = AGGR_GET_RXTID_STATS(p_aggr, i);
-
- if(rxtid->aggr == false ||
- rxtid->timerMon == false ||
- rxtid->progress == true) {
- continue;
- }
- // dequeue all frames in for this tid
- stats->num_timeouts++;
- A_PRINTF("TO: st %d end %d\n", rxtid->seq_next, ((rxtid->seq_next + rxtid->hold_q_sz-1) & IEEE80211_MAX_SEQ_NO));
- aggr_deque_frms(p_aggr, i, 0, ALL_SEQNO);
- }
-
- p_aggr->timerScheduled = false;
- // determine whether a new timer should be started.
- for(i = 0; i < NUM_OF_TIDS; i++) {
- rxtid = AGGR_GET_RXTID(p_aggr, i);
-
- if(rxtid->aggr == true && rxtid->hold_q) {
- for(j = 0 ; j < rxtid->hold_q_sz ; j++)
- {
- if(rxtid->hold_q[j].osbuf)
- {
- p_aggr->timerScheduled = true;
- rxtid->timerMon = true;
- rxtid->progress = false;
- break;
- }
- }
-
- if(j >= rxtid->hold_q_sz) {
- rxtid->timerMon = false;
- }
- }
- }
-
- if(p_aggr->timerScheduled) {
- /* Rearm the timer*/
- A_TIMEOUT_MS(&p_aggr->timer, AGGR_RX_TIMEOUT, 0);
- }
-
-}
-
-static void
-aggr_dispatch_frames(struct aggr_info *p_aggr, A_NETBUF_QUEUE_T *q)
-{
- void *osbuf;
-
- while((osbuf = A_NETBUF_DEQUEUE(q))) {
- p_aggr->rx_fn(p_aggr->dev, osbuf);
- }
-}
-
-void
-aggr_dump_stats(void *cntxt, PACKET_LOG **log_buf)
-{
- struct aggr_info *p_aggr = (struct aggr_info *)cntxt;
- struct rxtid *rxtid;
- struct rxtid_stats *stats;
- u8 i;
-
- *log_buf = &p_aggr->pkt_log;
- A_PRINTF("\n\n================================================\n");
- A_PRINTF("tid: num_into_aggr, dups, oow, mpdu, amsdu, delivered, timeouts, holes, bar, seq_next\n");
- for(i = 0; i < NUM_OF_TIDS; i++) {
- stats = AGGR_GET_RXTID_STATS(p_aggr, i);
- rxtid = AGGR_GET_RXTID(p_aggr, i);
- A_PRINTF("%d: %d %d %d %d %d %d %d %d %d : %d\n", i, stats->num_into_aggr, stats->num_dups,
- stats->num_oow, stats->num_mpdu,
- stats->num_amsdu, stats->num_delivered, stats->num_timeouts,
- stats->num_hole, stats->num_bar,
- rxtid->seq_next);
- }
- A_PRINTF("================================================\n\n");
-
-}
diff --git a/drivers/staging/ath6kl/wlan/include/ieee80211.h b/drivers/staging/ath6kl/wlan/include/ieee80211.h
deleted file mode 100644
index cf47d0657e70..000000000000
--- a/drivers/staging/ath6kl/wlan/include/ieee80211.h
+++ /dev/null
@@ -1,397 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="ieee80211.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _NET80211_IEEE80211_H_
-#define _NET80211_IEEE80211_H_
-
-/*
- * 802.11 protocol definitions.
- */
-#define IEEE80211_WEP_KEYLEN 5 /* 40bit */
-#define IEEE80211_WEP_IVLEN 3 /* 24bit */
-#define IEEE80211_WEP_KIDLEN 1 /* 1 octet */
-#define IEEE80211_WEP_CRCLEN 4 /* CRC-32 */
-#define IEEE80211_WEP_NKID 4 /* number of key ids */
-
-/*
- * 802.11i defines an extended IV for use with non-WEP ciphers.
- * When the EXTIV bit is set in the key id byte an additional
- * 4 bytes immediately follow the IV for TKIP. For CCMP the
- * EXTIV bit is likewise set but the 8 bytes represent the
- * CCMP header rather than IV+extended-IV.
- */
-#define IEEE80211_WEP_EXTIV 0x20
-#define IEEE80211_WEP_EXTIVLEN 4 /* extended IV length */
-#define IEEE80211_WEP_MICLEN 8 /* trailing MIC */
-
-#define IEEE80211_CRC_LEN 4
-
-#ifdef WAPI_ENABLE
-#define IEEE80211_WAPI_EXTIVLEN 10 /* extended IV length */
-#endif /* WAPI ENABLE */
-
-
-#define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */
-/* is 802.11 address multicast/broadcast? */
-#define IEEE80211_IS_MULTICAST(_a) (*(_a) & 0x01)
-#define IEEE80211_IS_BROADCAST(_a) (*(_a) == 0xFF)
-#define WEP_HEADER (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN)
-#define WEP_TRAILER IEEE80211_WEP_CRCLEN
-#define CCMP_HEADER (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + \
- IEEE80211_WEP_EXTIVLEN)
-#define CCMP_TRAILER IEEE80211_WEP_MICLEN
-#define TKIP_HEADER (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + \
- IEEE80211_WEP_EXTIVLEN)
-#define TKIP_TRAILER IEEE80211_WEP_CRCLEN
-#define TKIP_MICLEN IEEE80211_WEP_MICLEN
-
-
-#define IEEE80211_ADDR_EQ(addr1, addr2) \
- (memcmp(addr1, addr2, IEEE80211_ADDR_LEN) == 0)
-
-#define IEEE80211_ADDR_COPY(dst,src) memcpy(dst,src,IEEE80211_ADDR_LEN)
-
-#define IEEE80211_KEYBUF_SIZE 16
-#define IEEE80211_MICBUF_SIZE (8+8) /* space for both tx and rx */
-
-/*
- * NB: these values are ordered carefully; there are lots of
- * of implications in any reordering. In particular beware
- * that 4 is not used to avoid conflicting with IEEE80211_F_PRIVACY.
- */
-#define IEEE80211_CIPHER_WEP 0
-#define IEEE80211_CIPHER_TKIP 1
-#define IEEE80211_CIPHER_AES_OCB 2
-#define IEEE80211_CIPHER_AES_CCM 3
-#define IEEE80211_CIPHER_CKIP 5
-#define IEEE80211_CIPHER_CCKM_KRK 6
-#define IEEE80211_CIPHER_NONE 7 /* pseudo value */
-
-#define IEEE80211_CIPHER_MAX (IEEE80211_CIPHER_NONE+1)
-
-#define IEEE80211_IS_VALID_WEP_CIPHER_LEN(len) \
- (((len) == 5) || ((len) == 13) || ((len) == 16))
-
-
-
-/*
- * generic definitions for IEEE 802.11 frames
- */
-PREPACK struct ieee80211_frame {
- u8 i_fc[2];
- u8 i_dur[2];
- u8 i_addr1[IEEE80211_ADDR_LEN];
- u8 i_addr2[IEEE80211_ADDR_LEN];
- u8 i_addr3[IEEE80211_ADDR_LEN];
- u8 i_seq[2];
- /* possibly followed by addr4[IEEE80211_ADDR_LEN]; */
- /* see below */
-} POSTPACK;
-
-PREPACK struct ieee80211_qosframe {
- u8 i_fc[2];
- u8 i_dur[2];
- u8 i_addr1[IEEE80211_ADDR_LEN];
- u8 i_addr2[IEEE80211_ADDR_LEN];
- u8 i_addr3[IEEE80211_ADDR_LEN];
- u8 i_seq[2];
- u8 i_qos[2];
-} POSTPACK;
-
-#define IEEE80211_FC0_VERSION_MASK 0x03
-#define IEEE80211_FC0_VERSION_SHIFT 0
-#define IEEE80211_FC0_VERSION_0 0x00
-#define IEEE80211_FC0_TYPE_MASK 0x0c
-#define IEEE80211_FC0_TYPE_SHIFT 2
-#define IEEE80211_FC0_TYPE_MGT 0x00
-#define IEEE80211_FC0_TYPE_CTL 0x04
-#define IEEE80211_FC0_TYPE_DATA 0x08
-
-#define IEEE80211_FC0_SUBTYPE_MASK 0xf0
-#define IEEE80211_FC0_SUBTYPE_SHIFT 4
-/* for TYPE_MGT */
-#define IEEE80211_FC0_SUBTYPE_ASSOC_REQ 0x00
-#define IEEE80211_FC0_SUBTYPE_ASSOC_RESP 0x10
-#define IEEE80211_FC0_SUBTYPE_REASSOC_REQ 0x20
-#define IEEE80211_FC0_SUBTYPE_REASSOC_RESP 0x30
-#define IEEE80211_FC0_SUBTYPE_PROBE_REQ 0x40
-#define IEEE80211_FC0_SUBTYPE_PROBE_RESP 0x50
-#define IEEE80211_FC0_SUBTYPE_BEACON 0x80
-#define IEEE80211_FC0_SUBTYPE_ATIM 0x90
-#define IEEE80211_FC0_SUBTYPE_DISASSOC 0xa0
-#define IEEE80211_FC0_SUBTYPE_AUTH 0xb0
-#define IEEE80211_FC0_SUBTYPE_DEAUTH 0xc0
-/* for TYPE_CTL */
-#define IEEE80211_FC0_SUBTYPE_PS_POLL 0xa0
-#define IEEE80211_FC0_SUBTYPE_RTS 0xb0
-#define IEEE80211_FC0_SUBTYPE_CTS 0xc0
-#define IEEE80211_FC0_SUBTYPE_ACK 0xd0
-#define IEEE80211_FC0_SUBTYPE_CF_END 0xe0
-#define IEEE80211_FC0_SUBTYPE_CF_END_ACK 0xf0
-/* for TYPE_DATA (bit combination) */
-#define IEEE80211_FC0_SUBTYPE_DATA 0x00
-#define IEEE80211_FC0_SUBTYPE_CF_ACK 0x10
-#define IEEE80211_FC0_SUBTYPE_CF_POLL 0x20
-#define IEEE80211_FC0_SUBTYPE_CF_ACPL 0x30
-#define IEEE80211_FC0_SUBTYPE_NODATA 0x40
-#define IEEE80211_FC0_SUBTYPE_CFACK 0x50
-#define IEEE80211_FC0_SUBTYPE_CFPOLL 0x60
-#define IEEE80211_FC0_SUBTYPE_CF_ACK_CF_ACK 0x70
-#define IEEE80211_FC0_SUBTYPE_QOS 0x80
-#define IEEE80211_FC0_SUBTYPE_QOS_NULL 0xc0
-
-#define IEEE80211_FC1_DIR_MASK 0x03
-#define IEEE80211_FC1_DIR_NODS 0x00 /* STA->STA */
-#define IEEE80211_FC1_DIR_TODS 0x01 /* STA->AP */
-#define IEEE80211_FC1_DIR_FROMDS 0x02 /* AP ->STA */
-#define IEEE80211_FC1_DIR_DSTODS 0x03 /* AP ->AP */
-
-#define IEEE80211_FC1_MORE_FRAG 0x04
-#define IEEE80211_FC1_RETRY 0x08
-#define IEEE80211_FC1_PWR_MGT 0x10
-#define IEEE80211_FC1_MORE_DATA 0x20
-#define IEEE80211_FC1_WEP 0x40
-#define IEEE80211_FC1_ORDER 0x80
-
-#define IEEE80211_SEQ_FRAG_MASK 0x000f
-#define IEEE80211_SEQ_FRAG_SHIFT 0
-#define IEEE80211_SEQ_SEQ_MASK 0xfff0
-#define IEEE80211_SEQ_SEQ_SHIFT 4
-
-#define IEEE80211_NWID_LEN 32
-
-/*
- * 802.11 rate set.
- */
-#define IEEE80211_RATE_SIZE 8 /* 802.11 standard */
-#define IEEE80211_RATE_MAXSIZE 15 /* max rates we'll handle */
-
-#define WMM_NUM_AC 4 /* 4 AC categories */
-
-#define WMM_PARAM_ACI_M 0x60 /* Mask for ACI field */
-#define WMM_PARAM_ACI_S 5 /* Shift for ACI field */
-#define WMM_PARAM_ACM_M 0x10 /* Mask for ACM bit */
-#define WMM_PARAM_ACM_S 4 /* Shift for ACM bit */
-#define WMM_PARAM_AIFSN_M 0x0f /* Mask for aifsn field */
-#define WMM_PARAM_LOGCWMIN_M 0x0f /* Mask for CwMin field (in log) */
-#define WMM_PARAM_LOGCWMAX_M 0xf0 /* Mask for CwMax field (in log) */
-#define WMM_PARAM_LOGCWMAX_S 4 /* Shift for CwMax field */
-
-#define WMM_AC_TO_TID(_ac) ( \
- ((_ac) == WMM_AC_VO) ? 6 : \
- ((_ac) == WMM_AC_VI) ? 5 : \
- ((_ac) == WMM_AC_BK) ? 1 : \
- 0)
-
-#define TID_TO_WMM_AC(_tid) ( \
- ((_tid) < 1) ? WMM_AC_BE : \
- ((_tid) < 3) ? WMM_AC_BK : \
- ((_tid) < 6) ? WMM_AC_VI : \
- WMM_AC_VO)
-/*
- * Management information element payloads.
- */
-
-enum {
- IEEE80211_ELEMID_SSID = 0,
- IEEE80211_ELEMID_RATES = 1,
- IEEE80211_ELEMID_FHPARMS = 2,
- IEEE80211_ELEMID_DSPARMS = 3,
- IEEE80211_ELEMID_CFPARMS = 4,
- IEEE80211_ELEMID_TIM = 5,
- IEEE80211_ELEMID_IBSSPARMS = 6,
- IEEE80211_ELEMID_COUNTRY = 7,
- IEEE80211_ELEMID_CHALLENGE = 16,
- /* 17-31 reserved for challenge text extension */
- IEEE80211_ELEMID_PWRCNSTR = 32,
- IEEE80211_ELEMID_PWRCAP = 33,
- IEEE80211_ELEMID_TPCREQ = 34,
- IEEE80211_ELEMID_TPCREP = 35,
- IEEE80211_ELEMID_SUPPCHAN = 36,
- IEEE80211_ELEMID_CHANSWITCH = 37,
- IEEE80211_ELEMID_MEASREQ = 38,
- IEEE80211_ELEMID_MEASREP = 39,
- IEEE80211_ELEMID_QUIET = 40,
- IEEE80211_ELEMID_IBSSDFS = 41,
- IEEE80211_ELEMID_ERP = 42,
- IEEE80211_ELEMID_HTCAP_ANA = 45, /* Address ANA, and non-ANA story, for interop. CL#171733 */
- IEEE80211_ELEMID_RSN = 48,
- IEEE80211_ELEMID_XRATES = 50,
- IEEE80211_ELEMID_HTINFO_ANA = 61,
-#ifdef WAPI_ENABLE
- IEEE80211_ELEMID_WAPI = 68,
-#endif
- IEEE80211_ELEMID_TPC = 150,
- IEEE80211_ELEMID_CCKM = 156,
- IEEE80211_ELEMID_VENDOR = 221, /* vendor private */
-};
-
-#define ATH_OUI 0x7f0300 /* Atheros OUI */
-#define ATH_OUI_TYPE 0x01
-#define ATH_OUI_SUBTYPE 0x01
-#define ATH_OUI_VERSION 0x00
-
-#define WPA_OUI 0xf25000
-#define WPA_OUI_TYPE 0x01
-#define WPA_VERSION 1 /* current supported version */
-
-#define WPA_CSE_NULL 0x00
-#define WPA_CSE_WEP40 0x01
-#define WPA_CSE_TKIP 0x02
-#define WPA_CSE_CCMP 0x04
-#define WPA_CSE_WEP104 0x05
-
-#define WPA_ASE_NONE 0x00
-#define WPA_ASE_8021X_UNSPEC 0x01
-#define WPA_ASE_8021X_PSK 0x02
-
-#define RSN_OUI 0xac0f00
-#define RSN_VERSION 1 /* current supported version */
-
-#define RSN_CSE_NULL 0x00
-#define RSN_CSE_WEP40 0x01
-#define RSN_CSE_TKIP 0x02
-#define RSN_CSE_WRAP 0x03
-#define RSN_CSE_CCMP 0x04
-#define RSN_CSE_WEP104 0x05
-
-#define RSN_ASE_NONE 0x00
-#define RSN_ASE_8021X_UNSPEC 0x01
-#define RSN_ASE_8021X_PSK 0x02
-
-#define RSN_CAP_PREAUTH 0x01
-
-#define WMM_OUI 0xf25000
-#define WMM_OUI_TYPE 0x02
-#define WMM_INFO_OUI_SUBTYPE 0x00
-#define WMM_PARAM_OUI_SUBTYPE 0x01
-#define WMM_VERSION 1
-
-/* WMM stream classes */
-#define WMM_NUM_AC 4
-#define WMM_AC_BE 0 /* best effort */
-#define WMM_AC_BK 1 /* background */
-#define WMM_AC_VI 2 /* video */
-#define WMM_AC_VO 3 /* voice */
-
-/* TSPEC related */
-#define ACTION_CATEGORY_CODE_TSPEC 17
-#define ACTION_CODE_TSPEC_ADDTS 0
-#define ACTION_CODE_TSPEC_ADDTS_RESP 1
-#define ACTION_CODE_TSPEC_DELTS 2
-
-typedef enum {
- TSPEC_STATUS_CODE_ADMISSION_ACCEPTED = 0,
- TSPEC_STATUS_CODE_ADDTS_INVALID_PARAMS = 0x1,
- TSPEC_STATUS_CODE_ADDTS_REQUEST_REFUSED = 0x3,
- TSPEC_STATUS_CODE_UNSPECIFIED_QOS_RELATED_FAILURE = 0xC8,
- TSPEC_STATUS_CODE_REQUESTED_REFUSED_POLICY_CONFIGURATION = 0xC9,
- TSPEC_STATUS_CODE_INSUFFCIENT_BANDWIDTH = 0xCA,
- TSPEC_STATUS_CODE_INVALID_PARAMS = 0xCB,
- TSPEC_STATUS_CODE_DELTS_SENT = 0x30,
- TSPEC_STATUS_CODE_DELTS_RECV = 0x31,
-} TSPEC_STATUS_CODE;
-
-#define TSPEC_TSID_MASK 0xF
-#define TSPEC_TSID_S 1
-
-/*
- * WMM/802.11e Tspec Element
- */
-typedef PREPACK struct wmm_tspec_ie_t {
- u8 elementId;
- u8 len;
- u8 oui[3];
- u8 ouiType;
- u8 ouiSubType;
- u8 version;
- u16 tsInfo_info;
- u8 tsInfo_reserved;
- u16 nominalMSDU;
- u16 maxMSDU;
- u32 minServiceInt;
- u32 maxServiceInt;
- u32 inactivityInt;
- u32 suspensionInt;
- u32 serviceStartTime;
- u32 minDataRate;
- u32 meanDataRate;
- u32 peakDataRate;
- u32 maxBurstSize;
- u32 delayBound;
- u32 minPhyRate;
- u16 sba;
- u16 mediumTime;
-} POSTPACK WMM_TSPEC_IE;
-
-
-/*
- * BEACON management packets
- *
- * octet timestamp[8]
- * octet beacon interval[2]
- * octet capability information[2]
- * information element
- * octet elemid
- * octet length
- * octet information[length]
- */
-
-#define IEEE80211_BEACON_INTERVAL(beacon) \
- ((beacon)[8] | ((beacon)[9] << 8))
-#define IEEE80211_BEACON_CAPABILITY(beacon) \
- ((beacon)[10] | ((beacon)[11] << 8))
-
-#define IEEE80211_CAPINFO_ESS 0x0001
-#define IEEE80211_CAPINFO_IBSS 0x0002
-#define IEEE80211_CAPINFO_CF_POLLABLE 0x0004
-#define IEEE80211_CAPINFO_CF_POLLREQ 0x0008
-#define IEEE80211_CAPINFO_PRIVACY 0x0010
-#define IEEE80211_CAPINFO_SHORT_PREAMBLE 0x0020
-#define IEEE80211_CAPINFO_PBCC 0x0040
-#define IEEE80211_CAPINFO_CHNL_AGILITY 0x0080
-/* bits 8-9 are reserved */
-#define IEEE80211_CAPINFO_SHORT_SLOTTIME 0x0400
-#define IEEE80211_CAPINFO_APSD 0x0800
-/* bit 12 is reserved */
-#define IEEE80211_CAPINFO_DSSSOFDM 0x2000
-/* bits 14-15 are reserved */
-
-/*
- * Authentication Modes
- */
-
-enum ieee80211_authmode {
- IEEE80211_AUTH_NONE = 0,
- IEEE80211_AUTH_OPEN = 1,
- IEEE80211_AUTH_SHARED = 2,
- IEEE80211_AUTH_8021X = 3,
- IEEE80211_AUTH_AUTO = 4, /* auto-select/accept */
- /* NB: these are used only for ioctls */
- IEEE80211_AUTH_WPA = 5, /* WPA/RSN w/ 802.1x */
- IEEE80211_AUTH_WPA_PSK = 6, /* WPA/RSN w/ PSK */
- IEEE80211_AUTH_WPA_CCKM = 7, /* WPA/RSN IE w/ CCKM */
-};
-
-#define IEEE80211_PS_MAX_QUEUE 50 /*Maximum no of buffers that can be queues for PS*/
-
-#endif /* _NET80211_IEEE80211_H_ */
diff --git a/drivers/staging/ath6kl/wlan/include/ieee80211_node.h b/drivers/staging/ath6kl/wlan/include/ieee80211_node.h
deleted file mode 100644
index 1cb01671c0d3..000000000000
--- a/drivers/staging/ath6kl/wlan/include/ieee80211_node.h
+++ /dev/null
@@ -1,93 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="ieee80211_node.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _IEEE80211_NODE_H_
-#define _IEEE80211_NODE_H_
-
-/*
- * Node locking definitions.
- */
-#define IEEE80211_NODE_LOCK_INIT(_nt) A_MUTEX_INIT(&(_nt)->nt_nodelock)
-#define IEEE80211_NODE_LOCK_DESTROY(_nt) if (A_IS_MUTEX_VALID(&(_nt)->nt_nodelock)) { \
- A_MUTEX_DELETE(&(_nt)->nt_nodelock); }
-
-#define IEEE80211_NODE_LOCK(_nt) A_MUTEX_LOCK(&(_nt)->nt_nodelock)
-#define IEEE80211_NODE_UNLOCK(_nt) A_MUTEX_UNLOCK(&(_nt)->nt_nodelock)
-#define IEEE80211_NODE_LOCK_BH(_nt) A_MUTEX_LOCK(&(_nt)->nt_nodelock)
-#define IEEE80211_NODE_UNLOCK_BH(_nt) A_MUTEX_UNLOCK(&(_nt)->nt_nodelock)
-#define IEEE80211_NODE_LOCK_ASSERT(_nt)
-
-/*
- * Node reference counting definitions.
- *
- * ieee80211_node_initref initialize the reference count to 1
- * ieee80211_node_incref add a reference
- * ieee80211_node_decref remove a reference
- * ieee80211_node_dectestref remove a reference and return 1 if this
- * is the last reference, otherwise 0
- * ieee80211_node_refcnt reference count for printing (only)
- */
-#define ieee80211_node_initref(_ni) ((_ni)->ni_refcnt = 1)
-#define ieee80211_node_incref(_ni) ((_ni)->ni_refcnt++)
-#define ieee80211_node_decref(_ni) ((_ni)->ni_refcnt--)
-#define ieee80211_node_dectestref(_ni) (((_ni)->ni_refcnt--) == 1)
-#define ieee80211_node_refcnt(_ni) ((_ni)->ni_refcnt)
-
-#define IEEE80211_NODE_HASHSIZE 32
-/* simple hash is enough for variation of macaddr */
-#define IEEE80211_NODE_HASH(addr) \
- (((const u8 *)(addr))[IEEE80211_ADDR_LEN - 1] % \
- IEEE80211_NODE_HASHSIZE)
-
-/*
- * Table of ieee80211_node instances. Each ieee80211com
- * has at least one for holding the scan candidates.
- * When operating as an access point or in ibss mode there
- * is a second table for associated stations or neighbors.
- */
-struct ieee80211_node_table {
- void *nt_wmip; /* back reference */
- A_MUTEX_T nt_nodelock; /* on node table */
- struct bss *nt_node_first; /* information of all nodes */
- struct bss *nt_node_last; /* information of all nodes */
- struct bss *nt_hash[IEEE80211_NODE_HASHSIZE];
- const char *nt_name; /* for debugging */
- u32 nt_scangen; /* gen# for timeout scan */
-#ifdef THREAD_X
- A_TIMER nt_inact_timer;
- u8 isTimerArmed; /* is the node timer armed */
-#endif
- u32 nt_nodeAge; /* node aging time */
-#ifdef OS_ROAM_MANAGEMENT
- u32 nt_si_gen; /* gen# for scan indication*/
-#endif
-};
-
-#ifdef THREAD_X
-#define WLAN_NODE_INACT_TIMEOUT_MSEC 20000
-#else
-#define WLAN_NODE_INACT_TIMEOUT_MSEC 120000
-#endif
-
-#define WLAN_NODE_INACT_CNT 4
-
-#endif /* _IEEE80211_NODE_H_ */
diff --git a/drivers/staging/ath6kl/wlan/src/wlan_node.c b/drivers/staging/ath6kl/wlan/src/wlan_node.c
deleted file mode 100644
index 0fe5f4b1346c..000000000000
--- a/drivers/staging/ath6kl/wlan/src/wlan_node.c
+++ /dev/null
@@ -1,636 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="wlan_node.c" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// IEEE 802.11 node handling support.
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#include <a_config.h>
-#include <athdefs.h>
-#include <a_osapi.h>
-#define ATH_MODULE_NAME wlan
-#include <a_debug.h>
-#include "htc.h"
-#include "htc_api.h"
-#include <wmi.h>
-#include <ieee80211.h>
-#include <wlan_api.h>
-#include <wmi_api.h>
-#include <ieee80211_node.h>
-
-#define ATH_DEBUG_WLAN ATH_DEBUG_MAKE_MODULE_MASK(0)
-
-#ifdef ATH_DEBUG_MODULE
-
-static struct ath_debug_mask_description wlan_debug_desc[] = {
- { ATH_DEBUG_WLAN , "General WLAN Node Tracing"},
-};
-
-ATH_DEBUG_INSTANTIATE_MODULE_VAR(wlan,
- "wlan",
- "WLAN Node Management",
- ATH_DEBUG_MASK_DEFAULTS,
- ATH_DEBUG_DESCRIPTION_COUNT(wlan_debug_desc),
- wlan_debug_desc);
-
-#endif
-
-#ifdef THREAD_X
-static void wlan_node_timeout(unsigned long arg);
-#endif
-
-static bss_t * _ieee80211_find_node (struct ieee80211_node_table *nt,
- const u8 *macaddr);
-
-bss_t *
-wlan_node_alloc(struct ieee80211_node_table *nt, int wh_size)
-{
- bss_t *ni;
-
- ni = A_MALLOC_NOWAIT(sizeof(bss_t));
-
- if (ni != NULL) {
- if (wh_size)
- {
- ni->ni_buf = A_MALLOC_NOWAIT(wh_size);
- if (ni->ni_buf == NULL) {
- kfree(ni);
- ni = NULL;
- return ni;
- }
- }
- } else {
- return ni;
- }
-
- /* Make sure our lists are clean */
- ni->ni_list_next = NULL;
- ni->ni_list_prev = NULL;
- ni->ni_hash_next = NULL;
- ni->ni_hash_prev = NULL;
-
- //
- // ni_scangen never initialized before and during suspend/resume of winmobile,
- // that some junk has been stored in this, due to this scan list didn't properly updated
- //
- ni->ni_scangen = 0;
-
-#ifdef OS_ROAM_MANAGEMENT
- ni->ni_si_gen = 0;
-#endif
-
- return ni;
-}
-
-void
-wlan_node_free(bss_t *ni)
-{
- if (ni->ni_buf != NULL) {
- kfree(ni->ni_buf);
- }
- kfree(ni);
-}
-
-void
-wlan_setup_node(struct ieee80211_node_table *nt, bss_t *ni,
- const u8 *macaddr)
-{
- int hash;
- u32 timeoutValue = 0;
-
- memcpy(ni->ni_macaddr, macaddr, IEEE80211_ADDR_LEN);
- hash = IEEE80211_NODE_HASH (macaddr);
- ieee80211_node_initref (ni); /* mark referenced */
-
- timeoutValue = nt->nt_nodeAge;
-
- ni->ni_tstamp = A_GET_MS (0);
- ni->ni_actcnt = WLAN_NODE_INACT_CNT;
-
- IEEE80211_NODE_LOCK_BH(nt);
-
- /* Insert at the end of the node list */
- ni->ni_list_next = NULL;
- ni->ni_list_prev = nt->nt_node_last;
- if(nt->nt_node_last != NULL)
- {
- nt->nt_node_last->ni_list_next = ni;
- }
- nt->nt_node_last = ni;
- if(nt->nt_node_first == NULL)
- {
- nt->nt_node_first = ni;
- }
-
- /* Insert into the hash list i.e. the bucket */
- if((ni->ni_hash_next = nt->nt_hash[hash]) != NULL)
- {
- nt->nt_hash[hash]->ni_hash_prev = ni;
- }
- ni->ni_hash_prev = NULL;
- nt->nt_hash[hash] = ni;
-
-#ifdef THREAD_X
- if (!nt->isTimerArmed) {
- A_TIMEOUT_MS(&nt->nt_inact_timer, timeoutValue, 0);
- nt->isTimerArmed = true;
- }
-#endif
-
- IEEE80211_NODE_UNLOCK_BH(nt);
-}
-
-static bss_t *
-_ieee80211_find_node(struct ieee80211_node_table *nt,
- const u8 *macaddr)
-{
- bss_t *ni;
- int hash;
-
- IEEE80211_NODE_LOCK_ASSERT(nt);
-
- hash = IEEE80211_NODE_HASH(macaddr);
- for(ni = nt->nt_hash[hash]; ni; ni = ni->ni_hash_next) {
- if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) {
- ieee80211_node_incref(ni); /* mark referenced */
- return ni;
- }
- }
- return NULL;
-}
-
-bss_t *
-wlan_find_node(struct ieee80211_node_table *nt, const u8 *macaddr)
-{
- bss_t *ni;
-
- IEEE80211_NODE_LOCK(nt);
- ni = _ieee80211_find_node(nt, macaddr);
- IEEE80211_NODE_UNLOCK(nt);
- return ni;
-}
-
-/*
- * Reclaim a node. If this is the last reference count then
- * do the normal free work. Otherwise remove it from the node
- * table and mark it gone by clearing the back-reference.
- */
-void
-wlan_node_reclaim(struct ieee80211_node_table *nt, bss_t *ni)
-{
- IEEE80211_NODE_LOCK(nt);
-
- if(ni->ni_list_prev == NULL)
- {
- /* First in list so fix the list head */
- nt->nt_node_first = ni->ni_list_next;
- }
- else
- {
- ni->ni_list_prev->ni_list_next = ni->ni_list_next;
- }
-
- if(ni->ni_list_next == NULL)
- {
- /* Last in list so fix list tail */
- nt->nt_node_last = ni->ni_list_prev;
- }
- else
- {
- ni->ni_list_next->ni_list_prev = ni->ni_list_prev;
- }
-
- if(ni->ni_hash_prev == NULL)
- {
- /* First in list so fix the list head */
- int hash;
- hash = IEEE80211_NODE_HASH(ni->ni_macaddr);
- nt->nt_hash[hash] = ni->ni_hash_next;
- }
- else
- {
- ni->ni_hash_prev->ni_hash_next = ni->ni_hash_next;
- }
-
- if(ni->ni_hash_next != NULL)
- {
- ni->ni_hash_next->ni_hash_prev = ni->ni_hash_prev;
- }
- wlan_node_free(ni);
-
- IEEE80211_NODE_UNLOCK(nt);
-}
-
-static void
-wlan_node_dec_free(bss_t *ni)
-{
- if (ieee80211_node_dectestref(ni)) {
- wlan_node_free(ni);
- }
-}
-
-void
-wlan_free_allnodes(struct ieee80211_node_table *nt)
-{
- bss_t *ni;
-
- while ((ni = nt->nt_node_first) != NULL) {
- wlan_node_reclaim(nt, ni);
- }
-}
-
-void
-wlan_iterate_nodes(struct ieee80211_node_table *nt, wlan_node_iter_func *f,
- void *arg)
-{
- bss_t *ni;
- u32 gen;
-
- gen = ++nt->nt_scangen;
-
- IEEE80211_NODE_LOCK(nt);
- for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) {
- if (ni->ni_scangen != gen) {
- ni->ni_scangen = gen;
- (void) ieee80211_node_incref(ni);
- (*f)(arg, ni);
- wlan_node_dec_free(ni);
- }
- }
- IEEE80211_NODE_UNLOCK(nt);
-}
-
-/*
- * Node table support.
- */
-void
-wlan_node_table_init(void *wmip, struct ieee80211_node_table *nt)
-{
- int i;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_WLAN, ("node table = 0x%lx\n", (unsigned long)nt));
- IEEE80211_NODE_LOCK_INIT(nt);
-
- A_REGISTER_MODULE_DEBUG_INFO(wlan);
-
- nt->nt_node_first = nt->nt_node_last = NULL;
- for(i = 0; i < IEEE80211_NODE_HASHSIZE; i++)
- {
- nt->nt_hash[i] = NULL;
- }
-
-#ifdef THREAD_X
- A_INIT_TIMER(&nt->nt_inact_timer, wlan_node_timeout, nt);
- nt->isTimerArmed = false;
-#endif
- nt->nt_wmip = wmip;
- nt->nt_nodeAge = WLAN_NODE_INACT_TIMEOUT_MSEC;
-
- //
- // nt_scangen never initialized before and during suspend/resume of winmobile,
- // that some junk has been stored in this, due to this scan list didn't properly updated
- //
- nt->nt_scangen = 0;
-
-#ifdef OS_ROAM_MANAGEMENT
- nt->nt_si_gen = 0;
-#endif
-}
-
-void
-wlan_set_nodeage(struct ieee80211_node_table *nt, u32 nodeAge)
-{
- nt->nt_nodeAge = nodeAge;
- return;
-}
-void
-wlan_refresh_inactive_nodes (struct ieee80211_node_table *nt)
-{
-#ifdef THREAD_X
- bss_t *bss, *nextBss;
- u8 myBssid[IEEE80211_ADDR_LEN], reArmTimer = false;
-
- wmi_get_current_bssid(nt->nt_wmip, myBssid);
-
- bss = nt->nt_node_first;
- while (bss != NULL)
- {
- nextBss = bss->ni_list_next;
- if (memcmp(myBssid, bss->ni_macaddr, sizeof(myBssid)) != 0)
- {
- /*
- * free up all but the current bss - if set
- */
- wlan_node_reclaim(nt, bss);
-
- }
- bss = nextBss;
- }
-#else
- bss_t *bss, *nextBss;
- u8 myBssid[IEEE80211_ADDR_LEN];
- u32 timeoutValue = 0;
- u32 now = A_GET_MS(0);
- timeoutValue = nt->nt_nodeAge;
-
- wmi_get_current_bssid(nt->nt_wmip, myBssid);
-
- bss = nt->nt_node_first;
- while (bss != NULL)
- {
- nextBss = bss->ni_list_next;
- if (memcmp(myBssid, bss->ni_macaddr, sizeof(myBssid)) != 0)
- {
-
- if (((now - bss->ni_tstamp) > timeoutValue) || --bss->ni_actcnt == 0)
- {
- /*
- * free up all but the current bss - if set
- */
- wlan_node_reclaim(nt, bss);
- }
- }
- bss = nextBss;
- }
-#endif
-}
-
-#ifdef THREAD_X
-static void
-wlan_node_timeout (unsigned long arg)
-{
- struct ieee80211_node_table *nt = (struct ieee80211_node_table *)arg;
- bss_t *bss, *nextBss;
- u8 myBssid[IEEE80211_ADDR_LEN], reArmTimer = false;
- u32 timeoutValue = 0;
- u32 now = A_GET_MS(0);
-
- timeoutValue = nt->nt_nodeAge;
-
- wmi_get_current_bssid(nt->nt_wmip, myBssid);
-
- bss = nt->nt_node_first;
- while (bss != NULL)
- {
- nextBss = bss->ni_list_next;
- if (memcmp(myBssid, bss->ni_macaddr, sizeof(myBssid)) != 0)
- {
-
- if ((now - bss->ni_tstamp) > timeoutValue)
- {
- /*
- * free up all but the current bss - if set
- */
- wlan_node_reclaim(nt, bss);
- }
- else
- {
- /*
- * Re-arm timer, only when we have a bss other than
- * current bss AND it is not aged-out.
- */
- reArmTimer = true;
- }
- }
- bss = nextBss;
- }
-
- if (reArmTimer)
- A_TIMEOUT_MS (&nt->nt_inact_timer, timeoutValue, 0);
-
- nt->isTimerArmed = reArmTimer;
-}
-#endif
-
-void
-wlan_node_table_cleanup(struct ieee80211_node_table *nt)
-{
-#ifdef THREAD_X
- A_UNTIMEOUT(&nt->nt_inact_timer);
- A_DELETE_TIMER(&nt->nt_inact_timer);
-#endif
- wlan_free_allnodes(nt);
- IEEE80211_NODE_LOCK_DESTROY(nt);
-}
-
-bss_t *
-wlan_find_Ssidnode (struct ieee80211_node_table *nt, u8 *pSsid,
- u32 ssidLength, bool bIsWPA2, bool bMatchSSID)
-{
- bss_t *ni = NULL;
- u8 *pIESsid = NULL;
-
- IEEE80211_NODE_LOCK (nt);
-
- for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) {
- pIESsid = ni->ni_cie.ie_ssid;
- if (pIESsid[1] <= 32) {
-
- // Step 1 : Check SSID
- if (0x00 == memcmp (pSsid, &pIESsid[2], ssidLength)) {
-
- //
- // Step 2.1 : Check MatchSSID is true, if so, return Matched SSID
- // Profile, otherwise check whether WPA2 or WPA
- //
- if (true == bMatchSSID) {
- ieee80211_node_incref (ni); /* mark referenced */
- IEEE80211_NODE_UNLOCK (nt);
- return ni;
- }
-
- // Step 2 : if SSID matches, check WPA or WPA2
- if (true == bIsWPA2 && NULL != ni->ni_cie.ie_rsn) {
- ieee80211_node_incref (ni); /* mark referenced */
- IEEE80211_NODE_UNLOCK (nt);
- return ni;
- }
- if (false == bIsWPA2 && NULL != ni->ni_cie.ie_wpa) {
- ieee80211_node_incref(ni); /* mark referenced */
- IEEE80211_NODE_UNLOCK (nt);
- return ni;
- }
- }
- }
- }
-
- IEEE80211_NODE_UNLOCK (nt);
-
- return NULL;
-}
-
-void
-wlan_node_return (struct ieee80211_node_table *nt, bss_t *ni)
-{
- IEEE80211_NODE_LOCK (nt);
- wlan_node_dec_free (ni);
- IEEE80211_NODE_UNLOCK (nt);
-}
-
-void
-wlan_node_remove_core (struct ieee80211_node_table *nt, bss_t *ni)
-{
- if(ni->ni_list_prev == NULL)
- {
- /* First in list so fix the list head */
- nt->nt_node_first = ni->ni_list_next;
- }
- else
- {
- ni->ni_list_prev->ni_list_next = ni->ni_list_next;
- }
-
- if(ni->ni_list_next == NULL)
- {
- /* Last in list so fix list tail */
- nt->nt_node_last = ni->ni_list_prev;
- }
- else
- {
- ni->ni_list_next->ni_list_prev = ni->ni_list_prev;
- }
-
- if(ni->ni_hash_prev == NULL)
- {
- /* First in list so fix the list head */
- int hash;
- hash = IEEE80211_NODE_HASH(ni->ni_macaddr);
- nt->nt_hash[hash] = ni->ni_hash_next;
- }
- else
- {
- ni->ni_hash_prev->ni_hash_next = ni->ni_hash_next;
- }
-
- if(ni->ni_hash_next != NULL)
- {
- ni->ni_hash_next->ni_hash_prev = ni->ni_hash_prev;
- }
-}
-
-bss_t *
-wlan_node_remove(struct ieee80211_node_table *nt, u8 *bssid)
-{
- bss_t *bss, *nextBss;
-
- IEEE80211_NODE_LOCK(nt);
-
- bss = nt->nt_node_first;
-
- while (bss != NULL)
- {
- nextBss = bss->ni_list_next;
-
- if (memcmp(bssid, bss->ni_macaddr, 6) == 0)
- {
- wlan_node_remove_core (nt, bss);
- IEEE80211_NODE_UNLOCK(nt);
- return bss;
- }
-
- bss = nextBss;
- }
-
- IEEE80211_NODE_UNLOCK(nt);
- return NULL;
-}
-
-bss_t *
-wlan_find_matching_Ssidnode (struct ieee80211_node_table *nt, u8 *pSsid,
- u32 ssidLength, u32 dot11AuthMode, u32 authMode,
- u32 pairwiseCryptoType, u32 grpwiseCryptoTyp)
-{
- bss_t *ni = NULL;
- bss_t *best_ni = NULL;
- u8 *pIESsid = NULL;
-
- IEEE80211_NODE_LOCK (nt);
-
- for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) {
- pIESsid = ni->ni_cie.ie_ssid;
- if (pIESsid[1] <= 32) {
-
- // Step 1 : Check SSID
- if (0x00 == memcmp (pSsid, &pIESsid[2], ssidLength)) {
-
- if (ni->ni_cie.ie_capInfo & 0x10)
- {
-
- if ((NULL != ni->ni_cie.ie_rsn) && (WPA2_PSK_AUTH == authMode))
- {
- /* WPA2 */
- if (NULL == best_ni)
- {
- best_ni = ni;
- }
- else if (ni->ni_rssi > best_ni->ni_rssi)
- {
- best_ni = ni;
- }
- }
- else if ((NULL != ni->ni_cie.ie_wpa) && (WPA_PSK_AUTH == authMode))
- {
- /* WPA */
- if (NULL == best_ni)
- {
- best_ni = ni;
- }
- else if (ni->ni_rssi > best_ni->ni_rssi)
- {
- best_ni = ni;
- }
- }
- else if (WEP_CRYPT == pairwiseCryptoType)
- {
- /* WEP */
- if (NULL == best_ni)
- {
- best_ni = ni;
- }
- else if (ni->ni_rssi > best_ni->ni_rssi)
- {
- best_ni = ni;
- }
- }
- }
- else
- {
- /* open AP */
- if ((OPEN_AUTH == authMode) && (NONE_CRYPT == pairwiseCryptoType))
- {
- if (NULL == best_ni)
- {
- best_ni = ni;
- }
- else if (ni->ni_rssi > best_ni->ni_rssi)
- {
- best_ni = ni;
- }
- }
- }
- }
- }
- }
-
- IEEE80211_NODE_UNLOCK (nt);
-
- return best_ni;
-}
-
diff --git a/drivers/staging/ath6kl/wlan/src/wlan_recv_beacon.c b/drivers/staging/ath6kl/wlan/src/wlan_recv_beacon.c
deleted file mode 100644
index 07b8313b16e8..000000000000
--- a/drivers/staging/ath6kl/wlan/src/wlan_recv_beacon.c
+++ /dev/null
@@ -1,199 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="wlan_recv_beacon.c" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// IEEE 802.11 input handling.
-//
-// Author(s): ="Atheros"
-//==============================================================================
-
-#include "a_config.h"
-#include "athdefs.h"
-#include "a_osapi.h"
-#include <wmi.h>
-#include <ieee80211.h>
-#include <wlan_api.h>
-
-#define IEEE80211_VERIFY_LENGTH(_len, _minlen) do { \
- if ((_len) < (_minlen)) { \
- return A_EINVAL; \
- } \
-} while (0)
-
-#define IEEE80211_VERIFY_ELEMENT(__elem, __maxlen) do { \
- if ((__elem) == NULL) { \
- return A_EINVAL; \
- } \
- if ((__elem)[1] > (__maxlen)) { \
- return A_EINVAL; \
- } \
-} while (0)
-
-
-/* unaligned little endian access */
-#define LE_READ_2(p) \
- ((u16) \
- ((((u8 *)(p))[0] ) | (((u8 *)(p))[1] << 8)))
-
-#define LE_READ_4(p) \
- ((u32) \
- ((((u8 *)(p))[0] ) | (((u8 *)(p))[1] << 8) | \
- (((u8 *)(p))[2] << 16) | (((u8 *)(p))[3] << 24)))
-
-
-static int __inline
-iswpaoui(const u8 *frm)
-{
- return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
-}
-
-static int __inline
-iswmmoui(const u8 *frm)
-{
- return frm[1] > 3 && LE_READ_4(frm+2) == ((WMM_OUI_TYPE<<24)|WMM_OUI);
-}
-
-/* unused functions for now */
-#if 0
-static int __inline
-iswmmparam(const u8 *frm)
-{
- return frm[1] > 5 && frm[6] == WMM_PARAM_OUI_SUBTYPE;
-}
-
-static int __inline
-iswmminfo(const u8 *frm)
-{
- return frm[1] > 5 && frm[6] == WMM_INFO_OUI_SUBTYPE;
-}
-#endif
-
-static int __inline
-isatherosoui(const u8 *frm)
-{
- return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
-}
-
-static int __inline
-iswscoui(const u8 *frm)
-{
- return frm[1] > 3 && LE_READ_4(frm+2) == ((0x04<<24)|WPA_OUI);
-}
-
-int
-wlan_parse_beacon(u8 *buf, int framelen, struct ieee80211_common_ie *cie)
-{
- u8 *frm, *efrm;
- u8 elemid_ssid = false;
-
- frm = buf;
- efrm = (u8 *) (frm + framelen);
-
- /*
- * beacon/probe response frame format
- * [8] time stamp
- * [2] beacon interval
- * [2] capability information
- * [tlv] ssid
- * [tlv] supported rates
- * [tlv] country information
- * [tlv] parameter set (FH/DS)
- * [tlv] erp information
- * [tlv] extended supported rates
- * [tlv] WMM
- * [tlv] WPA or RSN
- * [tlv] Atheros Advanced Capabilities
- */
- IEEE80211_VERIFY_LENGTH(efrm - frm, 12);
- A_MEMZERO(cie, sizeof(*cie));
-
- cie->ie_tstamp = frm; frm += 8;
- cie->ie_beaconInt = A_LE2CPU16(*(u16 *)frm); frm += 2;
- cie->ie_capInfo = A_LE2CPU16(*(u16 *)frm); frm += 2;
- cie->ie_chan = 0;
-
- while (frm < efrm) {
- switch (*frm) {
- case IEEE80211_ELEMID_SSID:
- if (!elemid_ssid) {
- cie->ie_ssid = frm;
- elemid_ssid = true;
- }
- break;
- case IEEE80211_ELEMID_RATES:
- cie->ie_rates = frm;
- break;
- case IEEE80211_ELEMID_COUNTRY:
- cie->ie_country = frm;
- break;
- case IEEE80211_ELEMID_FHPARMS:
- break;
- case IEEE80211_ELEMID_DSPARMS:
- cie->ie_chan = frm[2];
- break;
- case IEEE80211_ELEMID_TIM:
- cie->ie_tim = frm;
- break;
- case IEEE80211_ELEMID_IBSSPARMS:
- break;
- case IEEE80211_ELEMID_XRATES:
- cie->ie_xrates = frm;
- break;
- case IEEE80211_ELEMID_ERP:
- if (frm[1] != 1) {
- //A_PRINTF("Discarding ERP Element - Bad Len\n");
- return A_EINVAL;
- }
- cie->ie_erp = frm[2];
- break;
- case IEEE80211_ELEMID_RSN:
- cie->ie_rsn = frm;
- break;
- case IEEE80211_ELEMID_HTCAP_ANA:
- cie->ie_htcap = frm;
- break;
- case IEEE80211_ELEMID_HTINFO_ANA:
- cie->ie_htop = frm;
- break;
-#ifdef WAPI_ENABLE
- case IEEE80211_ELEMID_WAPI:
- cie->ie_wapi = frm;
- break;
-#endif
- case IEEE80211_ELEMID_VENDOR:
- if (iswpaoui(frm)) {
- cie->ie_wpa = frm;
- } else if (iswmmoui(frm)) {
- cie->ie_wmm = frm;
- } else if (isatherosoui(frm)) {
- cie->ie_ath = frm;
- } else if(iswscoui(frm)) {
- cie->ie_wsc = frm;
- }
- break;
- default:
- break;
- }
- frm += frm[1] + 2;
- }
- IEEE80211_VERIFY_ELEMENT(cie->ie_rates, IEEE80211_RATE_MAXSIZE);
- IEEE80211_VERIFY_ELEMENT(cie->ie_ssid, IEEE80211_NWID_LEN);
-
- return 0;
-}
diff --git a/drivers/staging/ath6kl/wlan/src/wlan_utils.c b/drivers/staging/ath6kl/wlan/src/wlan_utils.c
deleted file mode 100644
index bc91599d9bf6..000000000000
--- a/drivers/staging/ath6kl/wlan/src/wlan_utils.c
+++ /dev/null
@@ -1,58 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="wlan_utils.c" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// This module implements frequently used wlan utilies
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#include <a_config.h>
-#include <athdefs.h>
-#include <a_osapi.h>
-
-/*
- * converts ieee channel number to frequency
- */
-u16 wlan_ieee2freq(int chan)
-{
- if (chan == 14) {
- return 2484;
- }
- if (chan < 14) { /* 0-13 */
- return (2407 + (chan*5));
- }
- if (chan < 27) { /* 15-26 */
- return (2512 + ((chan-15)*20));
- }
- return (5000 + (chan*5));
-}
-
-/*
- * Converts MHz frequency to IEEE channel number.
- */
-u32 wlan_freq2ieee(u16 freq)
-{
- if (freq == 2484)
- return 14;
- if (freq < 2484)
- return (freq - 2407) / 5;
- if (freq < 5000)
- return 15 + ((freq - 2512) / 20);
- return (freq - 5000) / 5;
-}
diff --git a/drivers/staging/ath6kl/wmi/wmi.c b/drivers/staging/ath6kl/wmi/wmi.c
deleted file mode 100644
index c7b5e5cf9df7..000000000000
--- a/drivers/staging/ath6kl/wmi/wmi.c
+++ /dev/null
@@ -1,6444 +0,0 @@
-//------------------------------------------------------------------------------
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// This module implements the hardware independent layer of the
-// Wireless Module Interface (WMI) protocol.
-//
-// Author(s): ="Atheros"
-//==============================================================================
-
-#include <a_config.h>
-#include <athdefs.h>
-#include <a_osapi.h>
-#include "htc.h"
-#include "htc_api.h"
-#include "wmi.h"
-#include <wlan_api.h>
-#include <wmi_api.h>
-#include <ieee80211.h>
-#include <ieee80211_node.h>
-#include "dset_api.h"
-#include "wmi_host.h"
-#include "a_drv.h"
-#include "a_drv_api.h"
-#define ATH_MODULE_NAME wmi
-#include "a_debug.h"
-#include "dbglog_api.h"
-#include "roaming.h"
-#include "cfg80211.h"
-
-#define ATH_DEBUG_WMI ATH_DEBUG_MAKE_MODULE_MASK(0)
-
-#ifdef ATH_DEBUG_MODULE
-
-static struct ath_debug_mask_description wmi_debug_desc[] = {
- { ATH_DEBUG_WMI , "General WMI Tracing"},
-};
-
-ATH_DEBUG_INSTANTIATE_MODULE_VAR(wmi,
- "wmi",
- "Wireless Module Interface",
- ATH_DEBUG_MASK_DEFAULTS,
- ATH_DEBUG_DESCRIPTION_COUNT(wmi_debug_desc),
- wmi_debug_desc);
-
-#endif
-
-#ifndef REXOS
-#define DBGARG _A_FUNCNAME_
-#define DBGFMT "%s() : "
-#define DBG_WMI ATH_DEBUG_WMI
-#define DBG_ERROR ATH_DEBUG_ERR
-#define DBG_WMI2 ATH_DEBUG_WMI
-#define A_DPRINTF AR_DEBUG_PRINTF
-#endif
-
-static int wmi_ready_event_rx(struct wmi_t *wmip, u8 *datap, int len);
-
-static int wmi_connect_event_rx(struct wmi_t *wmip, u8 *datap,
- int len);
-static int wmi_disconnect_event_rx(struct wmi_t *wmip, u8 *datap,
- int len);
-
-static int wmi_tkip_micerr_event_rx(struct wmi_t *wmip, u8 *datap,
- int len);
-static int wmi_bssInfo_event_rx(struct wmi_t *wmip, u8 *datap,
- int len);
-static int wmi_opt_frame_event_rx(struct wmi_t *wmip, u8 *datap,
- int len);
-static int wmi_pstream_timeout_event_rx(struct wmi_t *wmip, u8 *datap,
- int len);
-static int wmi_sync_point(struct wmi_t *wmip);
-
-static int wmi_bitrate_reply_rx(struct wmi_t *wmip, u8 *datap,
- int len);
-static int wmi_ratemask_reply_rx(struct wmi_t *wmip, u8 *datap,
- int len);
-static int wmi_channelList_reply_rx(struct wmi_t *wmip, u8 *datap,
- int len);
-static int wmi_regDomain_event_rx(struct wmi_t *wmip, u8 *datap,
- int len);
-static int wmi_txPwr_reply_rx(struct wmi_t *wmip, u8 *datap, int len);
-static int wmi_neighborReport_event_rx(struct wmi_t *wmip, u8 *datap,
- int len);
-
-static int wmi_dset_open_req_rx(struct wmi_t *wmip, u8 *datap,
- int len);
-#ifdef CONFIG_HOST_DSET_SUPPORT
-static int wmi_dset_close_rx(struct wmi_t *wmip, u8 *datap, int len);
-static int wmi_dset_data_req_rx(struct wmi_t *wmip, u8 *datap,
- int len);
-#endif /* CONFIG_HOST_DSET_SUPPORT */
-
-
-static int wmi_scanComplete_rx(struct wmi_t *wmip, u8 *datap,
- int len);
-static int wmi_errorEvent_rx(struct wmi_t *wmip, u8 *datap, int len);
-static int wmi_statsEvent_rx(struct wmi_t *wmip, u8 *datap, int len);
-static int wmi_rssiThresholdEvent_rx(struct wmi_t *wmip, u8 *datap, int len);
-static int wmi_hbChallengeResp_rx(struct wmi_t *wmip, u8 *datap, int len);
-static int wmi_reportErrorEvent_rx(struct wmi_t *wmip, u8 *datap, int len);
-static int wmi_cac_event_rx(struct wmi_t *wmip, u8 *datap, int len);
-static int wmi_channel_change_event_rx(struct wmi_t *wmip, u8 *datap, int len);
-static int wmi_roam_tbl_event_rx(struct wmi_t *wmip, u8 *datap,
- int len);
-static int wmi_roam_data_event_rx(struct wmi_t *wmip, u8 *datap,
- int len);
-static int wmi_get_wow_list_event_rx(struct wmi_t *wmip, u8 *datap,
- int len);
-static int
-wmi_get_pmkid_list_event_rx(struct wmi_t *wmip, u8 *datap, u32 len);
-
-static int
-wmi_set_params_event_rx(struct wmi_t *wmip, u8 *datap, u32 len);
-
-
-#ifdef CONFIG_HOST_TCMD_SUPPORT
-static int
-wmi_tcmd_test_report_rx(struct wmi_t *wmip, u8 *datap, int len);
-#endif
-
-static int
-wmi_txRetryErrEvent_rx(struct wmi_t *wmip, u8 *datap, int len);
-
-static int
-wmi_snrThresholdEvent_rx(struct wmi_t *wmip, u8 *datap, int len);
-
-static int
-wmi_lqThresholdEvent_rx(struct wmi_t *wmip, u8 *datap, int len);
-
-static bool
-wmi_is_bitrate_index_valid(struct wmi_t *wmip, s32 rateIndex);
-
-static int
-wmi_aplistEvent_rx(struct wmi_t *wmip, u8 *datap, int len);
-
-static int
-wmi_dbglog_event_rx(struct wmi_t *wmip, u8 *datap, int len);
-
-static int wmi_keepalive_reply_rx(struct wmi_t *wmip, u8 *datap, int len);
-
-int wmi_cmd_send_xtnd(struct wmi_t *wmip, void *osbuf, WMIX_COMMAND_ID cmdId,
- WMI_SYNC_FLAG syncflag);
-
-u8 ar6000_get_upper_threshold(s16 rssi, SQ_THRESHOLD_PARAMS *sq_thresh, u32 size);
-u8 ar6000_get_lower_threshold(s16 rssi, SQ_THRESHOLD_PARAMS *sq_thresh, u32 size);
-
-void wmi_cache_configure_rssithreshold(struct wmi_t *wmip, WMI_RSSI_THRESHOLD_PARAMS_CMD *rssiCmd);
-void wmi_cache_configure_snrthreshold(struct wmi_t *wmip, WMI_SNR_THRESHOLD_PARAMS_CMD *snrCmd);
-static int wmi_send_rssi_threshold_params(struct wmi_t *wmip,
- WMI_RSSI_THRESHOLD_PARAMS_CMD *rssiCmd);
-static int wmi_send_snr_threshold_params(struct wmi_t *wmip,
- WMI_SNR_THRESHOLD_PARAMS_CMD *snrCmd);
-#if defined(CONFIG_TARGET_PROFILE_SUPPORT)
-static int
-wmi_prof_count_rx(struct wmi_t *wmip, u8 *datap, int len);
-#endif /* CONFIG_TARGET_PROFILE_SUPPORT */
-
-static int wmi_pspoll_event_rx(struct wmi_t *wmip, u8 *datap,
- int len);
-static int wmi_dtimexpiry_event_rx(struct wmi_t *wmip, u8 *datap,
- int len);
-
-static int wmi_peer_node_event_rx (struct wmi_t *wmip, u8 *datap,
- int len);
-static int wmi_addba_req_event_rx(struct wmi_t *, u8 *, int);
-static int wmi_addba_resp_event_rx(struct wmi_t *, u8 *, int);
-static int wmi_delba_req_event_rx(struct wmi_t *, u8 *, int);
-static int wmi_btcoex_config_event_rx(struct wmi_t *wmip, u8 *datap, int len);
-static int wmi_btcoex_stats_event_rx(struct wmi_t *wmip, u8 *datap, int len);
-static int wmi_hci_event_rx(struct wmi_t *, u8 *, int);
-
-#ifdef WAPI_ENABLE
-static int wmi_wapi_rekey_event_rx(struct wmi_t *wmip, u8 *datap,
- int len);
-#endif
-
-#if defined(UNDER_CE)
-#if defined(NDIS51_MINIPORT)
-unsigned int processDot11Hdr = 0;
-#else
-unsigned int processDot11Hdr = 1;
-#endif
-#else
-extern unsigned int processDot11Hdr;
-#endif
-
-int wps_enable;
-static const s32 wmi_rateTable[][2] = {
- //{W/O SGI, with SGI}
- {1000, 1000},
- {2000, 2000},
- {5500, 5500},
- {11000, 11000},
- {6000, 6000},
- {9000, 9000},
- {12000, 12000},
- {18000, 18000},
- {24000, 24000},
- {36000, 36000},
- {48000, 48000},
- {54000, 54000},
- {6500, 7200},
- {13000, 14400},
- {19500, 21700},
- {26000, 28900},
- {39000, 43300},
- {52000, 57800},
- {58500, 65000},
- {65000, 72200},
- {13500, 15000},
- {27000, 30000},
- {40500, 45000},
- {54000, 60000},
- {81000, 90000},
- {108000, 120000},
- {121500, 135000},
- {135000, 150000},
- {0, 0}};
-
-#define MODE_A_SUPPORT_RATE_START ((s32) 4)
-#define MODE_A_SUPPORT_RATE_STOP ((s32) 11)
-
-#define MODE_GONLY_SUPPORT_RATE_START MODE_A_SUPPORT_RATE_START
-#define MODE_GONLY_SUPPORT_RATE_STOP MODE_A_SUPPORT_RATE_STOP
-
-#define MODE_B_SUPPORT_RATE_START ((s32) 0)
-#define MODE_B_SUPPORT_RATE_STOP ((s32) 3)
-
-#define MODE_G_SUPPORT_RATE_START ((s32) 0)
-#define MODE_G_SUPPORT_RATE_STOP ((s32) 11)
-
-#define MODE_GHT20_SUPPORT_RATE_START ((s32) 0)
-#define MODE_GHT20_SUPPORT_RATE_STOP ((s32) 19)
-
-#define MAX_NUMBER_OF_SUPPORT_RATES (MODE_GHT20_SUPPORT_RATE_STOP + 1)
-
-/* 802.1d to AC mapping. Refer pg 57 of WMM-test-plan-v1.2 */
-const u8 up_to_ac[]= {
- WMM_AC_BE,
- WMM_AC_BK,
- WMM_AC_BK,
- WMM_AC_BE,
- WMM_AC_VI,
- WMM_AC_VI,
- WMM_AC_VO,
- WMM_AC_VO,
- };
-
-/* This stuff is used when we want a simple layer-3 visibility */
-typedef PREPACK struct _iphdr {
- u8 ip_ver_hdrlen; /* version and hdr length */
- u8 ip_tos; /* type of service */
- u16 ip_len; /* total length */
- u16 ip_id; /* identification */
- s16 ip_off; /* fragment offset field */
-#define IP_DF 0x4000 /* dont fragment flag */
-#define IP_MF 0x2000 /* more fragments flag */
-#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
- u8 ip_ttl; /* time to live */
- u8 ip_p; /* protocol */
- u16 ip_sum; /* checksum */
- u8 ip_src[4]; /* source and dest address */
- u8 ip_dst[4];
-} POSTPACK iphdr;
-
-static s16 rssi_event_value = 0;
-static s16 snr_event_value = 0;
-
-bool is_probe_ssid = false;
-
-void *
-wmi_init(void *devt)
-{
- struct wmi_t *wmip;
-
- A_REGISTER_MODULE_DEBUG_INFO(wmi);
-
- wmip = A_MALLOC (sizeof(struct wmi_t));
- if (wmip == NULL) {
- return (NULL);
- }
- A_MEMZERO(wmip, sizeof(struct wmi_t ));
-#ifdef THREAD_X
- INIT_WMI_LOCK(wmip);
-#else
- A_MUTEX_INIT(&wmip->wmi_lock);
-#endif
- wmip->wmi_devt = devt;
- wlan_node_table_init(wmip, &wmip->wmi_scan_table);
- wmi_qos_state_init(wmip);
-
- wmip->wmi_powerMode = REC_POWER;
- wmip->wmi_phyMode = WMI_11G_MODE;
-
- wmip->wmi_pair_crypto_type = NONE_CRYPT;
- wmip->wmi_grp_crypto_type = NONE_CRYPT;
-
- wmip->wmi_ht_allowed[A_BAND_24GHZ] = 1;
- wmip->wmi_ht_allowed[A_BAND_5GHZ] = 1;
-
- return (wmip);
-}
-
-void
-wmi_qos_state_init(struct wmi_t *wmip)
-{
- u8 i;
-
- if (wmip == NULL) {
- return;
- }
- LOCK_WMI(wmip);
-
- /* Initialize QoS States */
- wmip->wmi_numQoSStream = 0;
-
- wmip->wmi_fatPipeExists = 0;
-
- for (i=0; i < WMM_NUM_AC; i++) {
- wmip->wmi_streamExistsForAC[i]=0;
- }
-
- UNLOCK_WMI(wmip);
-
- A_WMI_SET_NUMDATAENDPTS(wmip->wmi_devt, 1);
-}
-
-void
-wmi_set_control_ep(struct wmi_t * wmip, HTC_ENDPOINT_ID eid)
-{
- A_ASSERT( eid != ENDPOINT_UNUSED);
- wmip->wmi_endpoint_id = eid;
-}
-
-HTC_ENDPOINT_ID
-wmi_get_control_ep(struct wmi_t * wmip)
-{
- return(wmip->wmi_endpoint_id);
-}
-
-void
-wmi_shutdown(struct wmi_t *wmip)
-{
- if (wmip != NULL) {
- wlan_node_table_cleanup(&wmip->wmi_scan_table);
- if (A_IS_MUTEX_VALID(&wmip->wmi_lock)) {
-#ifdef THREAD_X
- DELETE_WMI_LOCK(&wmip);
-#else
- A_MUTEX_DELETE(&wmip->wmi_lock);
-#endif
- }
- kfree(wmip);
- }
-}
-
-/*
- * performs DIX to 802.3 encapsulation for transmit packets.
- * uses passed in buffer. Returns buffer or NULL if failed.
- * Assumes the entire DIX header is contigous and that there is
- * enough room in the buffer for a 802.3 mac header and LLC+SNAP headers.
- */
-int
-wmi_dix_2_dot3(struct wmi_t *wmip, void *osbuf)
-{
- u8 *datap;
- u16 typeorlen;
- ATH_MAC_HDR macHdr;
- ATH_LLC_SNAP_HDR *llcHdr;
-
- A_ASSERT(osbuf != NULL);
-
- if (A_NETBUF_HEADROOM(osbuf) <
- (sizeof(ATH_LLC_SNAP_HDR) + sizeof(WMI_DATA_HDR)))
- {
- return A_NO_MEMORY;
- }
-
- datap = A_NETBUF_DATA(osbuf);
-
- typeorlen = *(u16 *)(datap + ATH_MAC_LEN + ATH_MAC_LEN);
-
- if (!IS_ETHERTYPE(A_BE2CPU16(typeorlen))) {
- /*
- * packet is already in 802.3 format - return success
- */
- A_DPRINTF(DBG_WMI, (DBGFMT "packet already 802.3\n", DBGARG));
- return (0);
- }
-
- /*
- * Save mac fields and length to be inserted later
- */
- memcpy(macHdr.dstMac, datap, ATH_MAC_LEN);
- memcpy(macHdr.srcMac, datap + ATH_MAC_LEN, ATH_MAC_LEN);
- macHdr.typeOrLen = A_CPU2BE16(A_NETBUF_LEN(osbuf) - sizeof(ATH_MAC_HDR) +
- sizeof(ATH_LLC_SNAP_HDR));
-
- /*
- * Make room for LLC+SNAP headers
- */
- if (A_NETBUF_PUSH(osbuf, sizeof(ATH_LLC_SNAP_HDR)) != 0) {
- return A_NO_MEMORY;
- }
- datap = A_NETBUF_DATA(osbuf);
-
- memcpy(datap, &macHdr, sizeof (ATH_MAC_HDR));
-
- llcHdr = (ATH_LLC_SNAP_HDR *)(datap + sizeof(ATH_MAC_HDR));
- llcHdr->dsap = 0xAA;
- llcHdr->ssap = 0xAA;
- llcHdr->cntl = 0x03;
- llcHdr->orgCode[0] = 0x0;
- llcHdr->orgCode[1] = 0x0;
- llcHdr->orgCode[2] = 0x0;
- llcHdr->etherType = typeorlen;
-
- return (0);
-}
-
-int wmi_meta_add(struct wmi_t *wmip, void *osbuf, u8 *pVersion,void *pTxMetaS)
-{
- switch(*pVersion){
- case 0:
- return (0);
- case WMI_META_VERSION_1:
- {
- WMI_TX_META_V1 *pV1= NULL;
- A_ASSERT(osbuf != NULL);
- if (A_NETBUF_PUSH(osbuf, WMI_MAX_TX_META_SZ) != 0) {
- return A_NO_MEMORY;
- }
-
- pV1 = (WMI_TX_META_V1 *)A_NETBUF_DATA(osbuf);
- /* the pktID is used in conjunction with txComplete messages
- * allowing the target to notify which tx requests have been
- * completed and how. */
- pV1->pktID = 0;
- /* the ratePolicyID allows the host to specify which rate policy
- * to use for transmitting this packet. 0 means use default behavior. */
- pV1->ratePolicyID = 0;
- A_ASSERT(pVersion != NULL);
- /* the version must be used to populate the meta field of the WMI_DATA_HDR */
- *pVersion = WMI_META_VERSION_1;
- return (0);
- }
- case WMI_META_VERSION_2:
- {
- WMI_TX_META_V2 *pV2 ;
- A_ASSERT(osbuf != NULL);
- if (A_NETBUF_PUSH(osbuf, WMI_MAX_TX_META_SZ) != 0) {
- return A_NO_MEMORY;
- }
- pV2 = (WMI_TX_META_V2 *)A_NETBUF_DATA(osbuf);
- memcpy(pV2,(WMI_TX_META_V2 *)pTxMetaS,sizeof(WMI_TX_META_V2));
- return (0);
- }
- default:
- return (0);
- }
-}
-
-/* Adds a WMI data header */
-int
-wmi_data_hdr_add(struct wmi_t *wmip, void *osbuf, u8 msgType, bool bMoreData,
- WMI_DATA_HDR_DATA_TYPE data_type,u8 metaVersion, void *pTxMetaS)
-{
- WMI_DATA_HDR *dtHdr;
-// u8 metaVersion = 0;
- int status;
-
- A_ASSERT(osbuf != NULL);
-
- /* adds the meta data field after the wmi data hdr. If metaVersion
- * is returns 0 then no meta field was added. */
- if ((status = wmi_meta_add(wmip, osbuf, &metaVersion,pTxMetaS)) != 0) {
- return status;
- }
-
- if (A_NETBUF_PUSH(osbuf, sizeof(WMI_DATA_HDR)) != 0) {
- return A_NO_MEMORY;
- }
-
- dtHdr = (WMI_DATA_HDR *)A_NETBUF_DATA(osbuf);
- A_MEMZERO(dtHdr, sizeof(WMI_DATA_HDR));
-
- WMI_DATA_HDR_SET_MSG_TYPE(dtHdr, msgType);
- WMI_DATA_HDR_SET_DATA_TYPE(dtHdr, data_type);
-
- if (bMoreData) {
- WMI_DATA_HDR_SET_MORE_BIT(dtHdr);
- }
-
- WMI_DATA_HDR_SET_META(dtHdr, metaVersion);
-
- dtHdr->info3 = 0;
-
- return (0);
-}
-
-
-u8 wmi_implicit_create_pstream(struct wmi_t *wmip, void *osbuf, u32 layer2Priority, bool wmmEnabled)
-{
- u8 *datap;
- u8 trafficClass = WMM_AC_BE;
- u16 ipType = IP_ETHERTYPE;
- WMI_DATA_HDR *dtHdr;
- u8 streamExists = 0;
- u8 userPriority;
- u32 hdrsize, metasize;
- ATH_LLC_SNAP_HDR *llcHdr;
-
- WMI_CREATE_PSTREAM_CMD cmd;
-
- A_ASSERT(osbuf != NULL);
-
- //
- // Initialize header size
- //
- hdrsize = 0;
-
- datap = A_NETBUF_DATA(osbuf);
- dtHdr = (WMI_DATA_HDR *)datap;
- metasize = (WMI_DATA_HDR_GET_META(dtHdr))? WMI_MAX_TX_META_SZ : 0;
-
- if (!wmmEnabled)
- {
- /* If WMM is disabled all traffic goes as BE traffic */
- userPriority = 0;
- }
- else
- {
- if (processDot11Hdr)
- {
- hdrsize = A_ROUND_UP(sizeof(struct ieee80211_qosframe),sizeof(u32));
- llcHdr = (ATH_LLC_SNAP_HDR *)(datap + sizeof(WMI_DATA_HDR) + metasize +
- hdrsize);
-
-
- }
- else
- {
- llcHdr = (ATH_LLC_SNAP_HDR *)(datap + sizeof(WMI_DATA_HDR) + metasize +
- sizeof(ATH_MAC_HDR));
- }
-
- if (llcHdr->etherType == A_CPU2BE16(ipType))
- {
- /* Extract the endpoint info from the TOS field in the IP header */
-
- userPriority = wmi_determine_userPriority (((u8 *)llcHdr) + sizeof(ATH_LLC_SNAP_HDR),layer2Priority);
- }
- else
- {
- userPriority = layer2Priority & 0x7;
- }
- }
-
-
- /* workaround for WMM S5 */
- if ((WMM_AC_VI == wmip->wmi_traffic_class) && ((5 == userPriority) || (4 == userPriority)))
- {
- userPriority = 1;
- }
-
- trafficClass = convert_userPriority_to_trafficClass(userPriority);
-
- WMI_DATA_HDR_SET_UP(dtHdr, userPriority);
- /* lower 3-bits are 802.1d priority */
- //dtHdr->info |= (userPriority & WMI_DATA_HDR_UP_MASK) << WMI_DATA_HDR_UP_SHIFT;
-
- LOCK_WMI(wmip);
- streamExists = wmip->wmi_fatPipeExists;
- UNLOCK_WMI(wmip);
-
- if (!(streamExists & (1 << trafficClass)))
- {
-
- A_MEMZERO(&cmd, sizeof(cmd));
- cmd.trafficClass = trafficClass;
- cmd.userPriority = userPriority;
- cmd.inactivityInt = WMI_IMPLICIT_PSTREAM_INACTIVITY_INT;
- /* Implicit streams are created with TSID 0xFF */
-
- cmd.tsid = WMI_IMPLICIT_PSTREAM;
- wmi_create_pstream_cmd(wmip, &cmd);
- }
-
- return trafficClass;
-}
-
-int
-wmi_dot11_hdr_add (struct wmi_t *wmip, void *osbuf, NETWORK_TYPE mode)
-{
- u8 *datap;
- u16 typeorlen;
- ATH_MAC_HDR macHdr;
- ATH_LLC_SNAP_HDR *llcHdr;
- struct ieee80211_frame *wh;
- u32 hdrsize;
-
- A_ASSERT(osbuf != NULL);
-
- if (A_NETBUF_HEADROOM(osbuf) <
- (sizeof(struct ieee80211_qosframe) + sizeof(ATH_LLC_SNAP_HDR) + sizeof(WMI_DATA_HDR)))
- {
- return A_NO_MEMORY;
- }
-
- datap = A_NETBUF_DATA(osbuf);
-
- typeorlen = *(u16 *)(datap + ATH_MAC_LEN + ATH_MAC_LEN);
-
- if (!IS_ETHERTYPE(A_BE2CPU16(typeorlen))) {
-/*
- * packet is already in 802.3 format - return success
- */
- A_DPRINTF(DBG_WMI, (DBGFMT "packet already 802.3\n", DBGARG));
- goto AddDot11Hdr;
- }
-
- /*
- * Save mac fields and length to be inserted later
- */
- memcpy(macHdr.dstMac, datap, ATH_MAC_LEN);
- memcpy(macHdr.srcMac, datap + ATH_MAC_LEN, ATH_MAC_LEN);
- macHdr.typeOrLen = A_CPU2BE16(A_NETBUF_LEN(osbuf) - sizeof(ATH_MAC_HDR) +
- sizeof(ATH_LLC_SNAP_HDR));
-
- // Remove the Ethernet hdr
- A_NETBUF_PULL(osbuf, sizeof(ATH_MAC_HDR));
- /*
- * Make room for LLC+SNAP headers
- */
- if (A_NETBUF_PUSH(osbuf, sizeof(ATH_LLC_SNAP_HDR)) != 0) {
- return A_NO_MEMORY;
- }
- datap = A_NETBUF_DATA(osbuf);
-
- llcHdr = (ATH_LLC_SNAP_HDR *)(datap);
- llcHdr->dsap = 0xAA;
- llcHdr->ssap = 0xAA;
- llcHdr->cntl = 0x03;
- llcHdr->orgCode[0] = 0x0;
- llcHdr->orgCode[1] = 0x0;
- llcHdr->orgCode[2] = 0x0;
- llcHdr->etherType = typeorlen;
-
-AddDot11Hdr:
- /* Make room for 802.11 hdr */
- if (wmip->wmi_is_wmm_enabled)
- {
- hdrsize = A_ROUND_UP(sizeof(struct ieee80211_qosframe),sizeof(u32));
- if (A_NETBUF_PUSH(osbuf, hdrsize) != 0)
- {
- return A_NO_MEMORY;
- }
- wh = (struct ieee80211_frame *) A_NETBUF_DATA(osbuf);
- wh->i_fc[0] = IEEE80211_FC0_SUBTYPE_QOS;
- }
- else
- {
- hdrsize = A_ROUND_UP(sizeof(struct ieee80211_frame),sizeof(u32));
- if (A_NETBUF_PUSH(osbuf, hdrsize) != 0)
- {
- return A_NO_MEMORY;
- }
- wh = (struct ieee80211_frame *) A_NETBUF_DATA(osbuf);
- wh->i_fc[0] = IEEE80211_FC0_SUBTYPE_DATA;
- }
- /* Setup the SA & DA */
- IEEE80211_ADDR_COPY(wh->i_addr2, macHdr.srcMac);
-
- if (mode == INFRA_NETWORK) {
- IEEE80211_ADDR_COPY(wh->i_addr3, macHdr.dstMac);
- }
- else if (mode == ADHOC_NETWORK) {
- IEEE80211_ADDR_COPY(wh->i_addr1, macHdr.dstMac);
- }
-
- return (0);
-}
-
-int
-wmi_dot11_hdr_remove(struct wmi_t *wmip, void *osbuf)
-{
- u8 *datap;
- struct ieee80211_frame *pwh,wh;
- u8 type,subtype;
- ATH_LLC_SNAP_HDR *llcHdr;
- ATH_MAC_HDR macHdr;
- u32 hdrsize;
-
- A_ASSERT(osbuf != NULL);
- datap = A_NETBUF_DATA(osbuf);
-
- pwh = (struct ieee80211_frame *)datap;
- type = pwh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
- subtype = pwh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
-
- memcpy((u8 *)&wh, datap, sizeof(struct ieee80211_frame));
-
- /* strip off the 802.11 hdr*/
- if (subtype == IEEE80211_FC0_SUBTYPE_QOS) {
- hdrsize = A_ROUND_UP(sizeof(struct ieee80211_qosframe),sizeof(u32));
- A_NETBUF_PULL(osbuf, hdrsize);
- } else if (subtype == IEEE80211_FC0_SUBTYPE_DATA) {
- A_NETBUF_PULL(osbuf, sizeof(struct ieee80211_frame));
- }
-
- datap = A_NETBUF_DATA(osbuf);
- llcHdr = (ATH_LLC_SNAP_HDR *)(datap);
-
- macHdr.typeOrLen = llcHdr->etherType;
- A_MEMZERO(macHdr.dstMac, sizeof(macHdr.dstMac));
- A_MEMZERO(macHdr.srcMac, sizeof(macHdr.srcMac));
-
- switch (wh.i_fc[1] & IEEE80211_FC1_DIR_MASK) {
- case IEEE80211_FC1_DIR_NODS:
- IEEE80211_ADDR_COPY(macHdr.dstMac, wh.i_addr1);
- IEEE80211_ADDR_COPY(macHdr.srcMac, wh.i_addr2);
- break;
- case IEEE80211_FC1_DIR_TODS:
- IEEE80211_ADDR_COPY(macHdr.dstMac, wh.i_addr3);
- IEEE80211_ADDR_COPY(macHdr.srcMac, wh.i_addr2);
- break;
- case IEEE80211_FC1_DIR_FROMDS:
- IEEE80211_ADDR_COPY(macHdr.dstMac, wh.i_addr1);
- IEEE80211_ADDR_COPY(macHdr.srcMac, wh.i_addr3);
- break;
- case IEEE80211_FC1_DIR_DSTODS:
- break;
- }
-
- // Remove the LLC Hdr.
- A_NETBUF_PULL(osbuf, sizeof(ATH_LLC_SNAP_HDR));
-
- // Insert the ATH MAC hdr.
-
- A_NETBUF_PUSH(osbuf, sizeof(ATH_MAC_HDR));
- datap = A_NETBUF_DATA(osbuf);
-
- memcpy (datap, &macHdr, sizeof(ATH_MAC_HDR));
-
- return 0;
-}
-
-/*
- * performs 802.3 to DIX encapsulation for received packets.
- * Assumes the entire 802.3 header is contigous.
- */
-int
-wmi_dot3_2_dix(void *osbuf)
-{
- u8 *datap;
- ATH_MAC_HDR macHdr;
- ATH_LLC_SNAP_HDR *llcHdr;
-
- A_ASSERT(osbuf != NULL);
- datap = A_NETBUF_DATA(osbuf);
-
- memcpy(&macHdr, datap, sizeof(ATH_MAC_HDR));
- llcHdr = (ATH_LLC_SNAP_HDR *)(datap + sizeof(ATH_MAC_HDR));
- macHdr.typeOrLen = llcHdr->etherType;
-
- if (A_NETBUF_PULL(osbuf, sizeof(ATH_LLC_SNAP_HDR)) != 0) {
- return A_NO_MEMORY;
- }
-
- datap = A_NETBUF_DATA(osbuf);
-
- memcpy(datap, &macHdr, sizeof (ATH_MAC_HDR));
-
- return (0);
-}
-
-/*
- * Removes a WMI data header
- */
-int
-wmi_data_hdr_remove(struct wmi_t *wmip, void *osbuf)
-{
- A_ASSERT(osbuf != NULL);
-
- return (A_NETBUF_PULL(osbuf, sizeof(WMI_DATA_HDR)));
-}
-
-void
-wmi_iterate_nodes(struct wmi_t *wmip, wlan_node_iter_func *f, void *arg)
-{
- wlan_iterate_nodes(&wmip->wmi_scan_table, f, arg);
-}
-
-/*
- * WMI Extended Event received from Target.
- */
-int
-wmi_control_rx_xtnd(struct wmi_t *wmip, void *osbuf)
-{
- WMIX_CMD_HDR *cmd;
- u16 id;
- u8 *datap;
- u32 len;
- int status = 0;
-
- if (A_NETBUF_LEN(osbuf) < sizeof(WMIX_CMD_HDR)) {
- A_DPRINTF(DBG_WMI, (DBGFMT "bad packet 1\n", DBGARG));
- wmip->wmi_stats.cmd_len_err++;
- return A_ERROR;
- }
-
- cmd = (WMIX_CMD_HDR *)A_NETBUF_DATA(osbuf);
- id = cmd->commandId;
-
- if (A_NETBUF_PULL(osbuf, sizeof(WMIX_CMD_HDR)) != 0) {
- A_DPRINTF(DBG_WMI, (DBGFMT "bad packet 2\n", DBGARG));
- wmip->wmi_stats.cmd_len_err++;
- return A_ERROR;
- }
-
- datap = A_NETBUF_DATA(osbuf);
- len = A_NETBUF_LEN(osbuf);
-
- switch (id) {
- case (WMIX_DSETOPENREQ_EVENTID):
- status = wmi_dset_open_req_rx(wmip, datap, len);
- break;
-#ifdef CONFIG_HOST_DSET_SUPPORT
- case (WMIX_DSETCLOSE_EVENTID):
- status = wmi_dset_close_rx(wmip, datap, len);
- break;
- case (WMIX_DSETDATAREQ_EVENTID):
- status = wmi_dset_data_req_rx(wmip, datap, len);
- break;
-#endif /* CONFIG_HOST_DSET_SUPPORT */
- case (WMIX_HB_CHALLENGE_RESP_EVENTID):
- wmi_hbChallengeResp_rx(wmip, datap, len);
- break;
- case (WMIX_DBGLOG_EVENTID):
- wmi_dbglog_event_rx(wmip, datap, len);
- break;
-#if defined(CONFIG_TARGET_PROFILE_SUPPORT)
- case (WMIX_PROF_COUNT_EVENTID):
- wmi_prof_count_rx(wmip, datap, len);
- break;
-#endif /* CONFIG_TARGET_PROFILE_SUPPORT */
- default:
- A_DPRINTF(DBG_WMI|DBG_ERROR,
- (DBGFMT "Unknown id 0x%x\n", DBGARG, id));
- wmip->wmi_stats.cmd_id_err++;
- status = A_ERROR;
- break;
- }
-
- return status;
-}
-
-/*
- * Control Path
- */
-u32 cmdRecvNum;
-
-int
-wmi_control_rx(struct wmi_t *wmip, void *osbuf)
-{
- WMI_CMD_HDR *cmd;
- u16 id;
- u8 *datap;
- u32 len, i, loggingReq;
- int status = 0;
-
- A_ASSERT(osbuf != NULL);
- if (A_NETBUF_LEN(osbuf) < sizeof(WMI_CMD_HDR)) {
- A_NETBUF_FREE(osbuf);
- A_DPRINTF(DBG_WMI, (DBGFMT "bad packet 1\n", DBGARG));
- wmip->wmi_stats.cmd_len_err++;
- return A_ERROR;
- }
-
- cmd = (WMI_CMD_HDR *)A_NETBUF_DATA(osbuf);
- id = cmd->commandId;
-
- if (A_NETBUF_PULL(osbuf, sizeof(WMI_CMD_HDR)) != 0) {
- A_NETBUF_FREE(osbuf);
- A_DPRINTF(DBG_WMI, (DBGFMT "bad packet 2\n", DBGARG));
- wmip->wmi_stats.cmd_len_err++;
- return A_ERROR;
- }
-
- datap = A_NETBUF_DATA(osbuf);
- len = A_NETBUF_LEN(osbuf);
-
- loggingReq = 0;
-
- ar6000_get_driver_cfg(wmip->wmi_devt,
- AR6000_DRIVER_CFG_LOG_RAW_WMI_MSGS,
- &loggingReq);
-
- if(loggingReq) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("WMI %d \n",id));
- AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("WMI recv, MsgNo %d : ", cmdRecvNum));
- for(i = 0; i < len; i++)
- AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("%x ", datap[i]));
- AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("\n"));
- }
-
- LOCK_WMI(wmip);
- cmdRecvNum++;
- UNLOCK_WMI(wmip);
-
- switch (id) {
- case (WMI_GET_BITRATE_CMDID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_GET_BITRATE_CMDID\n", DBGARG));
- status = wmi_bitrate_reply_rx(wmip, datap, len);
- break;
- case (WMI_GET_CHANNEL_LIST_CMDID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_GET_CHANNEL_LIST_CMDID\n", DBGARG));
- status = wmi_channelList_reply_rx(wmip, datap, len);
- break;
- case (WMI_GET_TX_PWR_CMDID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_GET_TX_PWR_CMDID\n", DBGARG));
- status = wmi_txPwr_reply_rx(wmip, datap, len);
- break;
- case (WMI_READY_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_READY_EVENTID\n", DBGARG));
- status = wmi_ready_event_rx(wmip, datap, len);
- A_WMI_DBGLOG_INIT_DONE(wmip->wmi_devt);
- break;
- case (WMI_CONNECT_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_CONNECT_EVENTID\n", DBGARG));
- status = wmi_connect_event_rx(wmip, datap, len);
- break;
- case (WMI_DISCONNECT_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_DISCONNECT_EVENTID\n", DBGARG));
- status = wmi_disconnect_event_rx(wmip, datap, len);
- break;
- case (WMI_PEER_NODE_EVENTID):
- A_DPRINTF (DBG_WMI, (DBGFMT "WMI_PEER_NODE_EVENTID\n", DBGARG));
- status = wmi_peer_node_event_rx(wmip, datap, len);
- break;
- case (WMI_TKIP_MICERR_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_TKIP_MICERR_EVENTID\n", DBGARG));
- status = wmi_tkip_micerr_event_rx(wmip, datap, len);
- break;
- case (WMI_BSSINFO_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_BSSINFO_EVENTID\n", DBGARG));
- {
- /*
- * convert WMI_BSS_INFO_HDR2 to WMI_BSS_INFO_HDR
- * Take a local copy of the WMI_BSS_INFO_HDR2 from the wmi buffer
- * and reconstruct the WMI_BSS_INFO_HDR in its place
- */
- WMI_BSS_INFO_HDR2 bih2;
- WMI_BSS_INFO_HDR *bih;
- memcpy(&bih2, datap, sizeof(WMI_BSS_INFO_HDR2));
-
- A_NETBUF_PUSH(osbuf, 4);
- datap = A_NETBUF_DATA(osbuf);
- len = A_NETBUF_LEN(osbuf);
- bih = (WMI_BSS_INFO_HDR *)datap;
-
- bih->channel = bih2.channel;
- bih->frameType = bih2.frameType;
- bih->snr = bih2.snr;
- bih->rssi = bih2.snr - 95;
- bih->ieMask = bih2.ieMask;
- memcpy(bih->bssid, bih2.bssid, ATH_MAC_LEN);
-
- status = wmi_bssInfo_event_rx(wmip, datap, len);
- }
- break;
- case (WMI_REGDOMAIN_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_REGDOMAIN_EVENTID\n", DBGARG));
- status = wmi_regDomain_event_rx(wmip, datap, len);
- break;
- case (WMI_PSTREAM_TIMEOUT_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_PSTREAM_TIMEOUT_EVENTID\n", DBGARG));
- status = wmi_pstream_timeout_event_rx(wmip, datap, len);
- break;
- case (WMI_NEIGHBOR_REPORT_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_NEIGHBOR_REPORT_EVENTID\n", DBGARG));
- status = wmi_neighborReport_event_rx(wmip, datap, len);
- break;
- case (WMI_SCAN_COMPLETE_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_SCAN_COMPLETE_EVENTID\n", DBGARG));
- status = wmi_scanComplete_rx(wmip, datap, len);
- break;
- case (WMI_CMDERROR_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_CMDERROR_EVENTID\n", DBGARG));
- status = wmi_errorEvent_rx(wmip, datap, len);
- break;
- case (WMI_REPORT_STATISTICS_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_REPORT_STATISTICS_EVENTID\n", DBGARG));
- status = wmi_statsEvent_rx(wmip, datap, len);
- break;
- case (WMI_RSSI_THRESHOLD_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_RSSI_THRESHOLD_EVENTID\n", DBGARG));
- status = wmi_rssiThresholdEvent_rx(wmip, datap, len);
- break;
- case (WMI_ERROR_REPORT_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_ERROR_REPORT_EVENTID\n", DBGARG));
- status = wmi_reportErrorEvent_rx(wmip, datap, len);
- break;
- case (WMI_OPT_RX_FRAME_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_OPT_RX_FRAME_EVENTID\n", DBGARG));
- status = wmi_opt_frame_event_rx(wmip, datap, len);
- break;
- case (WMI_REPORT_ROAM_TBL_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_REPORT_ROAM_TBL_EVENTID\n", DBGARG));
- status = wmi_roam_tbl_event_rx(wmip, datap, len);
- break;
- case (WMI_EXTENSION_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_EXTENSION_EVENTID\n", DBGARG));
- status = wmi_control_rx_xtnd(wmip, osbuf);
- break;
- case (WMI_CAC_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_CAC_EVENTID\n", DBGARG));
- status = wmi_cac_event_rx(wmip, datap, len);
- break;
- case (WMI_CHANNEL_CHANGE_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_CHANNEL_CHANGE_EVENTID\n", DBGARG));
- status = wmi_channel_change_event_rx(wmip, datap, len);
- break;
- case (WMI_REPORT_ROAM_DATA_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_REPORT_ROAM_DATA_EVENTID\n", DBGARG));
- status = wmi_roam_data_event_rx(wmip, datap, len);
- break;
-#ifdef CONFIG_HOST_TCMD_SUPPORT
- case (WMI_TEST_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_TEST_EVENTID\n", DBGARG));
- status = wmi_tcmd_test_report_rx(wmip, datap, len);
- break;
-#endif
- case (WMI_GET_FIXRATES_CMDID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_GET_FIXRATES_CMDID\n", DBGARG));
- status = wmi_ratemask_reply_rx(wmip, datap, len);
- break;
- case (WMI_TX_RETRY_ERR_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_TX_RETRY_ERR_EVENTID\n", DBGARG));
- status = wmi_txRetryErrEvent_rx(wmip, datap, len);
- break;
- case (WMI_SNR_THRESHOLD_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_SNR_THRESHOLD_EVENTID\n", DBGARG));
- status = wmi_snrThresholdEvent_rx(wmip, datap, len);
- break;
- case (WMI_LQ_THRESHOLD_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_LQ_THRESHOLD_EVENTID\n", DBGARG));
- status = wmi_lqThresholdEvent_rx(wmip, datap, len);
- break;
- case (WMI_APLIST_EVENTID):
- AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("Received APLIST Event\n"));
- status = wmi_aplistEvent_rx(wmip, datap, len);
- break;
- case (WMI_GET_KEEPALIVE_CMDID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_GET_KEEPALIVE_CMDID\n", DBGARG));
- status = wmi_keepalive_reply_rx(wmip, datap, len);
- break;
- case (WMI_GET_WOW_LIST_EVENTID):
- status = wmi_get_wow_list_event_rx(wmip, datap, len);
- break;
- case (WMI_GET_PMKID_LIST_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_GET_PMKID_LIST Event\n", DBGARG));
- status = wmi_get_pmkid_list_event_rx(wmip, datap, len);
- break;
- case (WMI_PSPOLL_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_PSPOLL_EVENT\n", DBGARG));
- status = wmi_pspoll_event_rx(wmip, datap, len);
- break;
- case (WMI_DTIMEXPIRY_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_DTIMEXPIRY_EVENT\n", DBGARG));
- status = wmi_dtimexpiry_event_rx(wmip, datap, len);
- break;
- case (WMI_SET_PARAMS_REPLY_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_SET_PARAMS_REPLY Event\n", DBGARG));
- status = wmi_set_params_event_rx(wmip, datap, len);
- break;
- case (WMI_ADDBA_REQ_EVENTID):
- status = wmi_addba_req_event_rx(wmip, datap, len);
- break;
- case (WMI_ADDBA_RESP_EVENTID):
- status = wmi_addba_resp_event_rx(wmip, datap, len);
- break;
- case (WMI_DELBA_REQ_EVENTID):
- status = wmi_delba_req_event_rx(wmip, datap, len);
- break;
- case (WMI_REPORT_BTCOEX_CONFIG_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_BTCOEX_CONFIG_EVENTID", DBGARG));
- status = wmi_btcoex_config_event_rx(wmip, datap, len);
- break;
- case (WMI_REPORT_BTCOEX_STATS_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_BTCOEX_STATS_EVENTID", DBGARG));
- status = wmi_btcoex_stats_event_rx(wmip, datap, len);
- break;
- case (WMI_TX_COMPLETE_EVENTID):
- {
- int index;
- TX_COMPLETE_MSG_V1 *pV1;
- WMI_TX_COMPLETE_EVENT *pEv = (WMI_TX_COMPLETE_EVENT *)datap;
- A_PRINTF("comp: %d %d %d\n", pEv->numMessages, pEv->msgLen, pEv->msgType);
-
- for(index = 0 ; index < pEv->numMessages ; index++) {
- pV1 = (TX_COMPLETE_MSG_V1 *)(datap + sizeof(WMI_TX_COMPLETE_EVENT) + index*sizeof(TX_COMPLETE_MSG_V1));
- A_PRINTF("msg: %d %d %d %d\n", pV1->status, pV1->pktID, pV1->rateIdx, pV1->ackFailures);
- }
- }
- break;
- case (WMI_HCI_EVENT_EVENTID):
- status = wmi_hci_event_rx(wmip, datap, len);
- break;
-#ifdef WAPI_ENABLE
- case (WMI_WAPI_REKEY_EVENTID):
- A_DPRINTF(DBG_WMI, (DBGFMT "WMI_WAPI_REKEY_EVENTID", DBGARG));
- status = wmi_wapi_rekey_event_rx(wmip, datap, len);
- break;
-#endif
- default:
- A_DPRINTF(DBG_WMI|DBG_ERROR,
- (DBGFMT "Unknown id 0x%x\n", DBGARG, id));
- wmip->wmi_stats.cmd_id_err++;
- status = A_ERROR;
- break;
- }
-
- A_NETBUF_FREE(osbuf);
-
- return status;
-}
-
-/* Send a "simple" wmi command -- one with no arguments */
-static int
-wmi_simple_cmd(struct wmi_t *wmip, WMI_COMMAND_ID cmdid)
-{
- void *osbuf;
-
- osbuf = A_NETBUF_ALLOC(0);
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- return (wmi_cmd_send(wmip, osbuf, cmdid, NO_SYNC_WMIFLAG));
-}
-
-/* Send a "simple" extended wmi command -- one with no arguments.
- Enabling this command only if GPIO or profiling support is enabled.
- This is to suppress warnings on some platforms */
-#if defined(CONFIG_TARGET_PROFILE_SUPPORT)
-static int
-wmi_simple_cmd_xtnd(struct wmi_t *wmip, WMIX_COMMAND_ID cmdid)
-{
- void *osbuf;
-
- osbuf = A_NETBUF_ALLOC(0);
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- return (wmi_cmd_send_xtnd(wmip, osbuf, cmdid, NO_SYNC_WMIFLAG));
-}
-#endif
-
-static int
-wmi_ready_event_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_READY_EVENT *ev = (WMI_READY_EVENT *)datap;
-
- if (len < sizeof(WMI_READY_EVENT)) {
- return A_EINVAL;
- }
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
- wmip->wmi_ready = true;
- A_WMI_READY_EVENT(wmip->wmi_devt, ev->macaddr, ev->phyCapability,
- ev->sw_version, ev->abi_version);
-
- return 0;
-}
-
-#define LE_READ_4(p) \
- ((u32) \
- ((((u8 *)(p))[0] ) | (((u8 *)(p))[1] << 8) | \
- (((u8 *)(p))[2] << 16) | (((u8 *)(p))[3] << 24)))
-
-static int __inline
-iswmmoui(const u8 *frm)
-{
- return frm[1] > 3 && LE_READ_4(frm+2) == ((WMM_OUI_TYPE<<24)|WMM_OUI);
-}
-
-static int __inline
-iswmmparam(const u8 *frm)
-{
- return frm[1] > 5 && frm[6] == WMM_PARAM_OUI_SUBTYPE;
-}
-
-
-static int
-wmi_connect_event_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_CONNECT_EVENT *ev;
- u8 *pie,*peie;
-
- if (len < sizeof(WMI_CONNECT_EVENT))
- {
- return A_EINVAL;
- }
- ev = (WMI_CONNECT_EVENT *)datap;
-
- A_DPRINTF(DBG_WMI,
- (DBGFMT "freq %d bssid %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
- DBGARG, ev->channel,
- ev->bssid[0], ev->bssid[1], ev->bssid[2],
- ev->bssid[3], ev->bssid[4], ev->bssid[5]));
-
- memcpy(wmip->wmi_bssid, ev->bssid, ATH_MAC_LEN);
-
- /* initialize pointer to start of assoc rsp IEs */
- pie = ev->assocInfo + ev->beaconIeLen + ev->assocReqLen +
- sizeof(u16) + /* capinfo*/
- sizeof(u16) + /* status Code */
- sizeof(u16) ; /* associd */
-
- /* initialize pointer to end of assoc rsp IEs */
- peie = ev->assocInfo + ev->beaconIeLen + ev->assocReqLen + ev->assocRespLen;
-
- while (pie < peie)
- {
- switch (*pie)
- {
- case IEEE80211_ELEMID_VENDOR:
- if (iswmmoui(pie))
- {
- if(iswmmparam (pie))
- {
- wmip->wmi_is_wmm_enabled = true;
- }
- }
- break;
- }
-
- if (wmip->wmi_is_wmm_enabled)
- {
- break;
- }
- pie += pie[1] + 2;
- }
-
- A_WMI_CONNECT_EVENT(wmip->wmi_devt, ev->channel, ev->bssid,
- ev->listenInterval, ev->beaconInterval,
- (NETWORK_TYPE) ev->networkType, ev->beaconIeLen,
- ev->assocReqLen, ev->assocRespLen,
- ev->assocInfo);
-
- return 0;
-}
-
-static int
-wmi_regDomain_event_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_REG_DOMAIN_EVENT *ev;
-
- if (len < sizeof(*ev)) {
- return A_EINVAL;
- }
- ev = (WMI_REG_DOMAIN_EVENT *)datap;
-
- A_WMI_REGDOMAIN_EVENT(wmip->wmi_devt, ev->regDomain);
-
- return 0;
-}
-
-static int
-wmi_neighborReport_event_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_NEIGHBOR_REPORT_EVENT *ev;
- int numAps;
-
- if (len < sizeof(*ev)) {
- return A_EINVAL;
- }
- ev = (WMI_NEIGHBOR_REPORT_EVENT *)datap;
- numAps = ev->numberOfAps;
-
- if (len < (int)(sizeof(*ev) + ((numAps - 1) * sizeof(WMI_NEIGHBOR_INFO)))) {
- return A_EINVAL;
- }
-
- A_WMI_NEIGHBORREPORT_EVENT(wmip->wmi_devt, numAps, ev->neighbor);
-
- return 0;
-}
-
-static int
-wmi_disconnect_event_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_DISCONNECT_EVENT *ev;
- wmip->wmi_traffic_class = 100;
-
- if (len < sizeof(WMI_DISCONNECT_EVENT)) {
- return A_EINVAL;
- }
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
-
- ev = (WMI_DISCONNECT_EVENT *)datap;
-
- A_MEMZERO(wmip->wmi_bssid, sizeof(wmip->wmi_bssid));
-
- wmip->wmi_is_wmm_enabled = false;
- wmip->wmi_pair_crypto_type = NONE_CRYPT;
- wmip->wmi_grp_crypto_type = NONE_CRYPT;
-
- A_WMI_DISCONNECT_EVENT(wmip->wmi_devt, ev->disconnectReason, ev->bssid,
- ev->assocRespLen, ev->assocInfo, ev->protocolReasonStatus);
-
- return 0;
-}
-
-static int
-wmi_peer_node_event_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_PEER_NODE_EVENT *ev;
-
- if (len < sizeof(WMI_PEER_NODE_EVENT)) {
- return A_EINVAL;
- }
- ev = (WMI_PEER_NODE_EVENT *)datap;
- if (ev->eventCode == PEER_NODE_JOIN_EVENT) {
- A_DPRINTF (DBG_WMI, (DBGFMT "Joined node with Macaddr: ", DBGARG));
- } else if(ev->eventCode == PEER_NODE_LEAVE_EVENT) {
- A_DPRINTF (DBG_WMI, (DBGFMT "left node with Macaddr: ", DBGARG));
- }
-
- A_WMI_PEER_EVENT (wmip->wmi_devt, ev->eventCode, ev->peerMacAddr);
-
- return 0;
-}
-
-static int
-wmi_tkip_micerr_event_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_TKIP_MICERR_EVENT *ev;
-
- if (len < sizeof(*ev)) {
- return A_EINVAL;
- }
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
-
- ev = (WMI_TKIP_MICERR_EVENT *)datap;
- A_WMI_TKIP_MICERR_EVENT(wmip->wmi_devt, ev->keyid, ev->ismcast);
-
- return 0;
-}
-
-static int
-wmi_bssInfo_event_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- bss_t *bss = NULL;
- WMI_BSS_INFO_HDR *bih;
- u8 *buf;
- u32 nodeCachingAllowed = 1;
- u8 cached_ssid_len = 0;
- u8 cached_ssid_buf[IEEE80211_NWID_LEN] = {0};
- u8 beacon_ssid_len = 0;
-
- if (len <= sizeof(WMI_BSS_INFO_HDR)) {
- return A_EINVAL;
- }
-
- bih = (WMI_BSS_INFO_HDR *)datap;
- bss = wlan_find_node(&wmip->wmi_scan_table, bih->bssid);
-
- if (bih->rssi > 0) {
- if (NULL == bss)
- return 0; //no node found in the table, just drop the node with incorrect RSSI
- else
- bih->rssi = bss->ni_rssi; //Adjust RSSI in datap in case it is used in A_WMI_BSSINFO_EVENT_RX
- }
-
- A_WMI_BSSINFO_EVENT_RX(wmip->wmi_devt, datap, len);
- /* What is driver config for wlan node caching? */
- if(ar6000_get_driver_cfg(wmip->wmi_devt,
- AR6000_DRIVER_CFG_GET_WLANNODECACHING,
- &nodeCachingAllowed) != 0) {
- wmi_node_return(wmip, bss);
- return A_EINVAL;
- }
-
- if(!nodeCachingAllowed) {
- wmi_node_return(wmip, bss);
- return 0;
- }
-
- buf = datap + sizeof(WMI_BSS_INFO_HDR);
- len -= sizeof(WMI_BSS_INFO_HDR);
-
- A_DPRINTF(DBG_WMI2, (DBGFMT "bssInfo event - ch %u, rssi %02x, "
- "bssid \"%pM\"\n", DBGARG, bih->channel,
- (unsigned char) bih->rssi, bih->bssid));
-
- if(wps_enable && (bih->frameType == PROBERESP_FTYPE) ) {
- wmi_node_return(wmip, bss);
- return 0;
- }
-
- if (bss != NULL) {
- /*
- * Free up the node. Not the most efficient process given
- * we are about to allocate a new node but it is simple and should be
- * adequate.
- */
-
- /* In case of hidden AP, beacon will not have ssid,
- * but a directed probe response will have it,
- * so cache the probe-resp-ssid if already present. */
- if ((true == is_probe_ssid) && (BEACON_FTYPE == bih->frameType))
- {
- u8 *ie_ssid;
-
- ie_ssid = bss->ni_cie.ie_ssid;
- if(ie_ssid && (ie_ssid[1] <= IEEE80211_NWID_LEN) && (ie_ssid[2] != 0))
- {
- cached_ssid_len = ie_ssid[1];
- memcpy(cached_ssid_buf, ie_ssid + 2, cached_ssid_len);
- }
- }
-
- /*
- * Use the current average rssi of associated AP base on assumpiton
- * 1. Most os with GUI will update RSSI by wmi_get_stats_cmd() periodically
- * 2. wmi_get_stats_cmd(..) will be called when calling wmi_startscan_cmd(...)
- * The average value of RSSI give end-user better feeling for instance value of scan result
- * It also sync up RSSI info in GUI between scan result and RSSI signal icon
- */
- if (IEEE80211_ADDR_EQ(wmip->wmi_bssid, bih->bssid)) {
- bih->rssi = bss->ni_rssi;
- bih->snr = bss->ni_snr;
- }
-
- wlan_node_reclaim(&wmip->wmi_scan_table, bss);
- }
-
- /* beacon/probe response frame format
- * [8] time stamp
- * [2] beacon interval
- * [2] capability information
- * [tlv] ssid */
- beacon_ssid_len = buf[SSID_IE_LEN_INDEX];
-
- /* If ssid is cached for this hidden AP, then change buffer len accordingly. */
- if ((true == is_probe_ssid) && (BEACON_FTYPE == bih->frameType) &&
- (0 != cached_ssid_len) &&
- (0 == beacon_ssid_len || (cached_ssid_len > beacon_ssid_len && 0 == buf[SSID_IE_LEN_INDEX + 1])))
- {
- len += (cached_ssid_len - beacon_ssid_len);
- }
-
- bss = wlan_node_alloc(&wmip->wmi_scan_table, len);
- if (bss == NULL) {
- return A_NO_MEMORY;
- }
-
- bss->ni_snr = bih->snr;
- bss->ni_rssi = bih->rssi;
- A_ASSERT(bss->ni_buf != NULL);
-
- /* In case of hidden AP, beacon will not have ssid,
- * but a directed probe response will have it,
- * so place the cached-ssid(probe-resp) in the bssinfo. */
- if ((true == is_probe_ssid) && (BEACON_FTYPE == bih->frameType) &&
- (0 != cached_ssid_len) &&
- (0 == beacon_ssid_len || (beacon_ssid_len && 0 == buf[SSID_IE_LEN_INDEX + 1])))
- {
- u8 *ni_buf = bss->ni_buf;
- int buf_len = len;
-
- /* copy the first 14 bytes such as
- * time-stamp(8), beacon-interval(2), cap-info(2), ssid-id(1), ssid-len(1). */
- memcpy(ni_buf, buf, SSID_IE_LEN_INDEX + 1);
-
- ni_buf[SSID_IE_LEN_INDEX] = cached_ssid_len;
- ni_buf += (SSID_IE_LEN_INDEX + 1);
-
- buf += (SSID_IE_LEN_INDEX + 1);
- buf_len -= (SSID_IE_LEN_INDEX + 1);
-
- /* copy the cached ssid */
- memcpy(ni_buf, cached_ssid_buf, cached_ssid_len);
- ni_buf += cached_ssid_len;
-
- buf += beacon_ssid_len;
- buf_len -= beacon_ssid_len;
-
- if (cached_ssid_len > beacon_ssid_len)
- buf_len -= (cached_ssid_len - beacon_ssid_len);
-
- /* now copy the rest of bytes */
- memcpy(ni_buf, buf, buf_len);
- }
- else
- memcpy(bss->ni_buf, buf, len);
-
- bss->ni_framelen = len;
- if (wlan_parse_beacon(bss->ni_buf, len, &bss->ni_cie) != 0) {
- wlan_node_free(bss);
- return A_EINVAL;
- }
-
- /*
- * Update the frequency in ie_chan, overwriting of channel number
- * which is done in wlan_parse_beacon
- */
- bss->ni_cie.ie_chan = bih->channel;
- wlan_setup_node(&wmip->wmi_scan_table, bss, bih->bssid);
-
- return 0;
-}
-
-static int
-wmi_opt_frame_event_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- bss_t *bss;
- WMI_OPT_RX_INFO_HDR *bih;
- u8 *buf;
-
- if (len <= sizeof(WMI_OPT_RX_INFO_HDR)) {
- return A_EINVAL;
- }
-
- bih = (WMI_OPT_RX_INFO_HDR *)datap;
- buf = datap + sizeof(WMI_OPT_RX_INFO_HDR);
- len -= sizeof(WMI_OPT_RX_INFO_HDR);
-
- A_DPRINTF(DBG_WMI2, (DBGFMT "opt frame event %2.2x:%2.2x\n", DBGARG,
- bih->bssid[4], bih->bssid[5]));
-
- bss = wlan_find_node(&wmip->wmi_scan_table, bih->bssid);
- if (bss != NULL) {
- /*
- * Free up the node. Not the most efficient process given
- * we are about to allocate a new node but it is simple and should be
- * adequate.
- */
- wlan_node_reclaim(&wmip->wmi_scan_table, bss);
- }
-
- bss = wlan_node_alloc(&wmip->wmi_scan_table, len);
- if (bss == NULL) {
- return A_NO_MEMORY;
- }
-
- bss->ni_snr = bih->snr;
- bss->ni_cie.ie_chan = bih->channel;
- A_ASSERT(bss->ni_buf != NULL);
- memcpy(bss->ni_buf, buf, len);
- wlan_setup_node(&wmip->wmi_scan_table, bss, bih->bssid);
-
- return 0;
-}
-
- /* This event indicates inactivity timeout of a fatpipe(pstream)
- * at the target
- */
-static int
-wmi_pstream_timeout_event_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_PSTREAM_TIMEOUT_EVENT *ev;
-
- if (len < sizeof(WMI_PSTREAM_TIMEOUT_EVENT)) {
- return A_EINVAL;
- }
-
- A_DPRINTF(DBG_WMI, (DBGFMT "wmi_pstream_timeout_event_rx\n", DBGARG));
-
- ev = (WMI_PSTREAM_TIMEOUT_EVENT *)datap;
-
- /* When the pstream (fat pipe == AC) timesout, it means there were no
- * thinStreams within this pstream & it got implicitly created due to
- * data flow on this AC. We start the inactivity timer only for
- * implicitly created pstream. Just reset the host state.
- */
- /* Set the activeTsids for this AC to 0 */
- LOCK_WMI(wmip);
- wmip->wmi_streamExistsForAC[ev->trafficClass]=0;
- wmip->wmi_fatPipeExists &= ~(1 << ev->trafficClass);
- UNLOCK_WMI(wmip);
-
- /*Indicate inactivity to driver layer for this fatpipe (pstream)*/
- A_WMI_STREAM_TX_INACTIVE(wmip->wmi_devt, ev->trafficClass);
-
- return 0;
-}
-
-static int
-wmi_bitrate_reply_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_BIT_RATE_REPLY *reply;
- s32 rate;
- u32 sgi,index;
- /* 54149:
- * WMI_BIT_RATE_CMD structure is changed to WMI_BIT_RATE_REPLY.
- * since there is difference in the length and to avoid returning
- * error value.
- */
- if (len < sizeof(WMI_BIT_RATE_REPLY)) {
- return A_EINVAL;
- }
- reply = (WMI_BIT_RATE_REPLY *)datap;
- A_DPRINTF(DBG_WMI,
- (DBGFMT "Enter - rateindex %d\n", DBGARG, reply->rateIndex));
-
- if (reply->rateIndex == (s8) RATE_AUTO) {
- rate = RATE_AUTO;
- } else {
- // the SGI state is stored as the MSb of the rateIndex
- index = reply->rateIndex & 0x7f;
- sgi = (reply->rateIndex & 0x80)? 1:0;
- rate = wmi_rateTable[index][sgi];
- }
-
- A_WMI_BITRATE_RX(wmip->wmi_devt, rate);
- return 0;
-}
-
-static int
-wmi_ratemask_reply_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_FIX_RATES_REPLY *reply;
-
- if (len < sizeof(WMI_FIX_RATES_REPLY)) {
- return A_EINVAL;
- }
- reply = (WMI_FIX_RATES_REPLY *)datap;
- A_DPRINTF(DBG_WMI,
- (DBGFMT "Enter - fixed rate mask %x\n", DBGARG, reply->fixRateMask));
-
- A_WMI_RATEMASK_RX(wmip->wmi_devt, reply->fixRateMask);
-
- return 0;
-}
-
-static int
-wmi_channelList_reply_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_CHANNEL_LIST_REPLY *reply;
-
- if (len < sizeof(WMI_CHANNEL_LIST_REPLY)) {
- return A_EINVAL;
- }
- reply = (WMI_CHANNEL_LIST_REPLY *)datap;
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
-
- A_WMI_CHANNELLIST_RX(wmip->wmi_devt, reply->numChannels,
- reply->channelList);
-
- return 0;
-}
-
-static int
-wmi_txPwr_reply_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_TX_PWR_REPLY *reply;
-
- if (len < sizeof(*reply)) {
- return A_EINVAL;
- }
- reply = (WMI_TX_PWR_REPLY *)datap;
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
-
- A_WMI_TXPWR_RX(wmip->wmi_devt, reply->dbM);
-
- return 0;
-}
-static int
-wmi_keepalive_reply_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_GET_KEEPALIVE_CMD *reply;
-
- if (len < sizeof(*reply)) {
- return A_EINVAL;
- }
- reply = (WMI_GET_KEEPALIVE_CMD *)datap;
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
-
- A_WMI_KEEPALIVE_RX(wmip->wmi_devt, reply->configured);
-
- return 0;
-}
-
-
-static int
-wmi_dset_open_req_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMIX_DSETOPENREQ_EVENT *dsetopenreq;
-
- if (len < sizeof(WMIX_DSETOPENREQ_EVENT)) {
- return A_EINVAL;
- }
- dsetopenreq = (WMIX_DSETOPENREQ_EVENT *)datap;
- A_DPRINTF(DBG_WMI,
- (DBGFMT "Enter - dset_id=0x%x\n", DBGARG, dsetopenreq->dset_id));
- A_WMI_DSET_OPEN_REQ(wmip->wmi_devt,
- dsetopenreq->dset_id,
- dsetopenreq->targ_dset_handle,
- dsetopenreq->targ_reply_fn,
- dsetopenreq->targ_reply_arg);
-
- return 0;
-}
-
-#ifdef CONFIG_HOST_DSET_SUPPORT
-static int
-wmi_dset_close_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMIX_DSETCLOSE_EVENT *dsetclose;
-
- if (len < sizeof(WMIX_DSETCLOSE_EVENT)) {
- return A_EINVAL;
- }
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
-
- dsetclose = (WMIX_DSETCLOSE_EVENT *)datap;
- A_WMI_DSET_CLOSE(wmip->wmi_devt, dsetclose->access_cookie);
-
- return 0;
-}
-
-static int
-wmi_dset_data_req_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMIX_DSETDATAREQ_EVENT *dsetdatareq;
-
- if (len < sizeof(WMIX_DSETDATAREQ_EVENT)) {
- return A_EINVAL;
- }
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
-
- dsetdatareq = (WMIX_DSETDATAREQ_EVENT *)datap;
- A_WMI_DSET_DATA_REQ(wmip->wmi_devt,
- dsetdatareq->access_cookie,
- dsetdatareq->offset,
- dsetdatareq->length,
- dsetdatareq->targ_buf,
- dsetdatareq->targ_reply_fn,
- dsetdatareq->targ_reply_arg);
-
- return 0;
-}
-#endif /* CONFIG_HOST_DSET_SUPPORT */
-
-static int
-wmi_scanComplete_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_SCAN_COMPLETE_EVENT *ev;
-
- ev = (WMI_SCAN_COMPLETE_EVENT *)datap;
- if ((int)ev->status == 0) {
- wlan_refresh_inactive_nodes(&wmip->wmi_scan_table);
- }
- A_WMI_SCANCOMPLETE_EVENT(wmip->wmi_devt, (int) ev->status);
- is_probe_ssid = false;
-
- return 0;
-}
-
-/*
- * Target is reporting a programming error. This is for
- * developer aid only. Target only checks a few common violations
- * and it is responsibility of host to do all error checking.
- * Behavior of target after wmi error event is undefined.
- * A reset is recommended.
- */
-static int
-wmi_errorEvent_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_CMD_ERROR_EVENT *ev;
-
- ev = (WMI_CMD_ERROR_EVENT *)datap;
- AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("Programming Error: cmd=%d ", ev->commandId));
- switch (ev->errorCode) {
- case (INVALID_PARAM):
- AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("Illegal Parameter\n"));
- break;
- case (ILLEGAL_STATE):
- AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("Illegal State\n"));
- break;
- case (INTERNAL_ERROR):
- AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("Internal Error\n"));
- break;
- }
-
- return 0;
-}
-
-
-static int
-wmi_statsEvent_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
-
- A_WMI_TARGETSTATS_EVENT(wmip->wmi_devt, datap, len);
-
- return 0;
-}
-
-static int
-wmi_rssiThresholdEvent_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_RSSI_THRESHOLD_EVENT *reply;
- WMI_RSSI_THRESHOLD_VAL newThreshold;
- WMI_RSSI_THRESHOLD_PARAMS_CMD cmd;
- SQ_THRESHOLD_PARAMS *sq_thresh =
- &wmip->wmi_SqThresholdParams[SIGNAL_QUALITY_METRICS_RSSI];
- u8 upper_rssi_threshold, lower_rssi_threshold;
- s16 rssi;
-
- if (len < sizeof(*reply)) {
- return A_EINVAL;
- }
- reply = (WMI_RSSI_THRESHOLD_EVENT *)datap;
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
- newThreshold = (WMI_RSSI_THRESHOLD_VAL) reply->range;
- rssi = reply->rssi;
-
- /*
- * Identify the threshold breached and communicate that to the app. After
- * that install a new set of thresholds based on the signal quality
- * reported by the target
- */
- if (newThreshold) {
- /* Upper threshold breached */
- if (rssi < sq_thresh->upper_threshold[0]) {
- A_DPRINTF(DBG_WMI, (DBGFMT "Spurious upper RSSI threshold event: "
- " %d\n", DBGARG, rssi));
- } else if ((rssi < sq_thresh->upper_threshold[1]) &&
- (rssi >= sq_thresh->upper_threshold[0]))
- {
- newThreshold = WMI_RSSI_THRESHOLD1_ABOVE;
- } else if ((rssi < sq_thresh->upper_threshold[2]) &&
- (rssi >= sq_thresh->upper_threshold[1]))
- {
- newThreshold = WMI_RSSI_THRESHOLD2_ABOVE;
- } else if ((rssi < sq_thresh->upper_threshold[3]) &&
- (rssi >= sq_thresh->upper_threshold[2]))
- {
- newThreshold = WMI_RSSI_THRESHOLD3_ABOVE;
- } else if ((rssi < sq_thresh->upper_threshold[4]) &&
- (rssi >= sq_thresh->upper_threshold[3]))
- {
- newThreshold = WMI_RSSI_THRESHOLD4_ABOVE;
- } else if ((rssi < sq_thresh->upper_threshold[5]) &&
- (rssi >= sq_thresh->upper_threshold[4]))
- {
- newThreshold = WMI_RSSI_THRESHOLD5_ABOVE;
- } else if (rssi >= sq_thresh->upper_threshold[5]) {
- newThreshold = WMI_RSSI_THRESHOLD6_ABOVE;
- }
- } else {
- /* Lower threshold breached */
- if (rssi > sq_thresh->lower_threshold[0]) {
- A_DPRINTF(DBG_WMI, (DBGFMT "Spurious lower RSSI threshold event: "
- "%d %d\n", DBGARG, rssi, sq_thresh->lower_threshold[0]));
- } else if ((rssi > sq_thresh->lower_threshold[1]) &&
- (rssi <= sq_thresh->lower_threshold[0]))
- {
- newThreshold = WMI_RSSI_THRESHOLD6_BELOW;
- } else if ((rssi > sq_thresh->lower_threshold[2]) &&
- (rssi <= sq_thresh->lower_threshold[1]))
- {
- newThreshold = WMI_RSSI_THRESHOLD5_BELOW;
- } else if ((rssi > sq_thresh->lower_threshold[3]) &&
- (rssi <= sq_thresh->lower_threshold[2]))
- {
- newThreshold = WMI_RSSI_THRESHOLD4_BELOW;
- } else if ((rssi > sq_thresh->lower_threshold[4]) &&
- (rssi <= sq_thresh->lower_threshold[3]))
- {
- newThreshold = WMI_RSSI_THRESHOLD3_BELOW;
- } else if ((rssi > sq_thresh->lower_threshold[5]) &&
- (rssi <= sq_thresh->lower_threshold[4]))
- {
- newThreshold = WMI_RSSI_THRESHOLD2_BELOW;
- } else if (rssi <= sq_thresh->lower_threshold[5]) {
- newThreshold = WMI_RSSI_THRESHOLD1_BELOW;
- }
- }
- /* Calculate and install the next set of thresholds */
- lower_rssi_threshold = ar6000_get_lower_threshold(rssi, sq_thresh,
- sq_thresh->lower_threshold_valid_count);
- upper_rssi_threshold = ar6000_get_upper_threshold(rssi, sq_thresh,
- sq_thresh->upper_threshold_valid_count);
- /* Issue a wmi command to install the thresholds */
- cmd.thresholdAbove1_Val = upper_rssi_threshold;
- cmd.thresholdBelow1_Val = lower_rssi_threshold;
- cmd.weight = sq_thresh->weight;
- cmd.pollTime = sq_thresh->polling_interval;
-
- rssi_event_value = rssi;
-
- if (wmi_send_rssi_threshold_params(wmip, &cmd) != 0) {
- A_DPRINTF(DBG_WMI, (DBGFMT "Unable to configure the RSSI thresholds\n",
- DBGARG));
- }
-
- A_WMI_RSSI_THRESHOLD_EVENT(wmip->wmi_devt, newThreshold, reply->rssi);
-
- return 0;
-}
-
-
-static int
-wmi_reportErrorEvent_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_TARGET_ERROR_REPORT_EVENT *reply;
-
- if (len < sizeof(*reply)) {
- return A_EINVAL;
- }
- reply = (WMI_TARGET_ERROR_REPORT_EVENT *)datap;
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
-
- A_WMI_REPORT_ERROR_EVENT(wmip->wmi_devt, (WMI_TARGET_ERROR_VAL) reply->errorVal);
-
- return 0;
-}
-
-static int
-wmi_cac_event_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_CAC_EVENT *reply;
- WMM_TSPEC_IE *tspec_ie;
- u16 activeTsids;
-
- if (len < sizeof(*reply)) {
- return A_EINVAL;
- }
- reply = (WMI_CAC_EVENT *)datap;
-
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
-
- if ((reply->cac_indication == CAC_INDICATION_ADMISSION_RESP) &&
- (reply->statusCode != TSPEC_STATUS_CODE_ADMISSION_ACCEPTED)) {
- tspec_ie = (WMM_TSPEC_IE *) &(reply->tspecSuggestion);
-
- wmi_delete_pstream_cmd(wmip, reply->ac,
- (tspec_ie->tsInfo_info >> TSPEC_TSID_S) & TSPEC_TSID_MASK);
- }
- else if (reply->cac_indication == CAC_INDICATION_NO_RESP) {
- u8 i;
-
- /* following assumes that there is only one outstanding ADDTS request
- when this event is received */
- LOCK_WMI(wmip);
- activeTsids = wmip->wmi_streamExistsForAC[reply->ac];
- UNLOCK_WMI(wmip);
-
- for (i = 0; i < sizeof(activeTsids) * 8; i++) {
- if ((activeTsids >> i) & 1) {
- break;
- }
- }
- if (i < (sizeof(activeTsids) * 8)) {
- wmi_delete_pstream_cmd(wmip, reply->ac, i);
- }
- }
- /*
- * Ev#72990: Clear active tsids and Add missing handling
- * for delete qos stream from AP
- */
- else if (reply->cac_indication == CAC_INDICATION_DELETE) {
- u8 tsid = 0;
-
- tspec_ie = (WMM_TSPEC_IE *) &(reply->tspecSuggestion);
- tsid= ((tspec_ie->tsInfo_info >> TSPEC_TSID_S) & TSPEC_TSID_MASK);
- LOCK_WMI(wmip);
- wmip->wmi_streamExistsForAC[reply->ac] &= ~(1<<tsid);
- activeTsids = wmip->wmi_streamExistsForAC[reply->ac];
- UNLOCK_WMI(wmip);
-
-
- /* Indicate stream inactivity to driver layer only if all tsids
- * within this AC are deleted.
- */
- if (!activeTsids) {
- A_WMI_STREAM_TX_INACTIVE(wmip->wmi_devt, reply->ac);
- wmip->wmi_fatPipeExists &= ~(1 << reply->ac);
- }
- }
-
- A_WMI_CAC_EVENT(wmip->wmi_devt, reply->ac,
- reply->cac_indication, reply->statusCode,
- reply->tspecSuggestion);
-
- return 0;
-}
-
-static int
-wmi_channel_change_event_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_CHANNEL_CHANGE_EVENT *reply;
-
- if (len < sizeof(*reply)) {
- return A_EINVAL;
- }
- reply = (WMI_CHANNEL_CHANGE_EVENT *)datap;
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
-
- A_WMI_CHANNEL_CHANGE_EVENT(wmip->wmi_devt, reply->oldChannel,
- reply->newChannel);
-
- return 0;
-}
-
-static int
-wmi_hbChallengeResp_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMIX_HB_CHALLENGE_RESP_EVENT *reply;
-
- if (len < sizeof(*reply)) {
- return A_EINVAL;
- }
- reply = (WMIX_HB_CHALLENGE_RESP_EVENT *)datap;
- A_DPRINTF(DBG_WMI, (DBGFMT "wmi: challenge response event\n", DBGARG));
-
- A_WMI_HBCHALLENGERESP_EVENT(wmip->wmi_devt, reply->cookie, reply->source);
-
- return 0;
-}
-
-static int
-wmi_roam_tbl_event_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_TARGET_ROAM_TBL *reply;
-
- if (len < sizeof(*reply)) {
- return A_EINVAL;
- }
- reply = (WMI_TARGET_ROAM_TBL *)datap;
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
-
- A_WMI_ROAM_TABLE_EVENT(wmip->wmi_devt, reply);
-
- return 0;
-}
-
-static int
-wmi_roam_data_event_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_TARGET_ROAM_DATA *reply;
-
- if (len < sizeof(*reply)) {
- return A_EINVAL;
- }
- reply = (WMI_TARGET_ROAM_DATA *)datap;
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
-
- A_WMI_ROAM_DATA_EVENT(wmip->wmi_devt, reply);
-
- return 0;
-}
-
-static int
-wmi_txRetryErrEvent_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- if (len < sizeof(WMI_TX_RETRY_ERR_EVENT)) {
- return A_EINVAL;
- }
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
-
- A_WMI_TX_RETRY_ERR_EVENT(wmip->wmi_devt);
-
- return 0;
-}
-
-static int
-wmi_snrThresholdEvent_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_SNR_THRESHOLD_EVENT *reply;
- SQ_THRESHOLD_PARAMS *sq_thresh =
- &wmip->wmi_SqThresholdParams[SIGNAL_QUALITY_METRICS_SNR];
- WMI_SNR_THRESHOLD_VAL newThreshold;
- WMI_SNR_THRESHOLD_PARAMS_CMD cmd;
- u8 upper_snr_threshold, lower_snr_threshold;
- s16 snr;
-
- if (len < sizeof(*reply)) {
- return A_EINVAL;
- }
- reply = (WMI_SNR_THRESHOLD_EVENT *)datap;
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
-
- newThreshold = (WMI_SNR_THRESHOLD_VAL) reply->range;
- snr = reply->snr;
- /*
- * Identify the threshold breached and communicate that to the app. After
- * that install a new set of thresholds based on the signal quality
- * reported by the target
- */
- if (newThreshold) {
- /* Upper threshold breached */
- if (snr < sq_thresh->upper_threshold[0]) {
- A_DPRINTF(DBG_WMI, (DBGFMT "Spurious upper SNR threshold event: "
- "%d\n", DBGARG, snr));
- } else if ((snr < sq_thresh->upper_threshold[1]) &&
- (snr >= sq_thresh->upper_threshold[0]))
- {
- newThreshold = WMI_SNR_THRESHOLD1_ABOVE;
- } else if ((snr < sq_thresh->upper_threshold[2]) &&
- (snr >= sq_thresh->upper_threshold[1]))
- {
- newThreshold = WMI_SNR_THRESHOLD2_ABOVE;
- } else if ((snr < sq_thresh->upper_threshold[3]) &&
- (snr >= sq_thresh->upper_threshold[2]))
- {
- newThreshold = WMI_SNR_THRESHOLD3_ABOVE;
- } else if (snr >= sq_thresh->upper_threshold[3]) {
- newThreshold = WMI_SNR_THRESHOLD4_ABOVE;
- }
- } else {
- /* Lower threshold breached */
- if (snr > sq_thresh->lower_threshold[0]) {
- A_DPRINTF(DBG_WMI, (DBGFMT "Spurious lower SNR threshold event: "
- "%d %d\n", DBGARG, snr, sq_thresh->lower_threshold[0]));
- } else if ((snr > sq_thresh->lower_threshold[1]) &&
- (snr <= sq_thresh->lower_threshold[0]))
- {
- newThreshold = WMI_SNR_THRESHOLD4_BELOW;
- } else if ((snr > sq_thresh->lower_threshold[2]) &&
- (snr <= sq_thresh->lower_threshold[1]))
- {
- newThreshold = WMI_SNR_THRESHOLD3_BELOW;
- } else if ((snr > sq_thresh->lower_threshold[3]) &&
- (snr <= sq_thresh->lower_threshold[2]))
- {
- newThreshold = WMI_SNR_THRESHOLD2_BELOW;
- } else if (snr <= sq_thresh->lower_threshold[3]) {
- newThreshold = WMI_SNR_THRESHOLD1_BELOW;
- }
- }
-
- /* Calculate and install the next set of thresholds */
- lower_snr_threshold = ar6000_get_lower_threshold(snr, sq_thresh,
- sq_thresh->lower_threshold_valid_count);
- upper_snr_threshold = ar6000_get_upper_threshold(snr, sq_thresh,
- sq_thresh->upper_threshold_valid_count);
-
- /* Issue a wmi command to install the thresholds */
- cmd.thresholdAbove1_Val = upper_snr_threshold;
- cmd.thresholdBelow1_Val = lower_snr_threshold;
- cmd.weight = sq_thresh->weight;
- cmd.pollTime = sq_thresh->polling_interval;
-
- A_DPRINTF(DBG_WMI, (DBGFMT "snr: %d, threshold: %d, lower: %d, upper: %d\n"
- ,DBGARG, snr, newThreshold, lower_snr_threshold,
- upper_snr_threshold));
-
- snr_event_value = snr;
-
- if (wmi_send_snr_threshold_params(wmip, &cmd) != 0) {
- A_DPRINTF(DBG_WMI, (DBGFMT "Unable to configure the SNR thresholds\n",
- DBGARG));
- }
- A_WMI_SNR_THRESHOLD_EVENT_RX(wmip->wmi_devt, newThreshold, reply->snr);
-
- return 0;
-}
-
-static int
-wmi_lqThresholdEvent_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_LQ_THRESHOLD_EVENT *reply;
-
- if (len < sizeof(*reply)) {
- return A_EINVAL;
- }
- reply = (WMI_LQ_THRESHOLD_EVENT *)datap;
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
-
- A_WMI_LQ_THRESHOLD_EVENT_RX(wmip->wmi_devt,
- (WMI_LQ_THRESHOLD_VAL) reply->range,
- reply->lq);
-
- return 0;
-}
-
-static int
-wmi_aplistEvent_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- u16 ap_info_entry_size;
- WMI_APLIST_EVENT *ev = (WMI_APLIST_EVENT *)datap;
- WMI_AP_INFO_V1 *ap_info_v1;
- u8 i;
-
- if (len < sizeof(WMI_APLIST_EVENT)) {
- return A_EINVAL;
- }
-
- if (ev->apListVer == APLIST_VER1) {
- ap_info_entry_size = sizeof(WMI_AP_INFO_V1);
- ap_info_v1 = (WMI_AP_INFO_V1 *)ev->apList;
- } else {
- return A_EINVAL;
- }
-
- AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("Number of APs in APLIST Event is %d\n", ev->numAP));
- if (len < (int)(sizeof(WMI_APLIST_EVENT) +
- (ev->numAP - 1) * ap_info_entry_size))
- {
- return A_EINVAL;
- }
-
- /*
- * AP List Ver1 Contents
- */
- for (i = 0; i < ev->numAP; i++) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("AP#%d BSSID %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x "\
- "Channel %d\n", i,
- ap_info_v1->bssid[0], ap_info_v1->bssid[1],
- ap_info_v1->bssid[2], ap_info_v1->bssid[3],
- ap_info_v1->bssid[4], ap_info_v1->bssid[5],
- ap_info_v1->channel));
- ap_info_v1++;
- }
- return 0;
-}
-
-static int
-wmi_dbglog_event_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- u32 dropped;
-
- dropped = *((u32 *)datap);
- datap += sizeof(dropped);
- len -= sizeof(dropped);
- A_WMI_DBGLOG_EVENT(wmip->wmi_devt, dropped, (s8 *)datap, len);
- return 0;
-}
-
-/*
- * Called to send a wmi command. Command specific data is already built
- * on osbuf and current osbuf->data points to it.
- */
-int
-wmi_cmd_send(struct wmi_t *wmip, void *osbuf, WMI_COMMAND_ID cmdId,
- WMI_SYNC_FLAG syncflag)
-{
- int status;
-#define IS_OPT_TX_CMD(cmdId) ((cmdId == WMI_OPT_TX_FRAME_CMDID))
- WMI_CMD_HDR *cHdr;
- HTC_ENDPOINT_ID eid = wmip->wmi_endpoint_id;
-
- A_ASSERT(osbuf != NULL);
-
- if (syncflag >= END_WMIFLAG) {
- A_NETBUF_FREE(osbuf);
- return A_EINVAL;
- }
-
- if ((syncflag == SYNC_BEFORE_WMIFLAG) || (syncflag == SYNC_BOTH_WMIFLAG)) {
- /*
- * We want to make sure all data currently queued is transmitted before
- * the cmd execution. Establish a new sync point.
- */
- wmi_sync_point(wmip);
- }
-
- if (A_NETBUF_PUSH(osbuf, sizeof(WMI_CMD_HDR)) != 0) {
- A_NETBUF_FREE(osbuf);
- return A_NO_MEMORY;
- }
-
- cHdr = (WMI_CMD_HDR *)A_NETBUF_DATA(osbuf);
- cHdr->commandId = (u16) cmdId;
- cHdr->info1 = 0; // added for virtual interface
-
- /*
- * Only for OPT_TX_CMD, use BE endpoint.
- */
- if (IS_OPT_TX_CMD(cmdId)) {
- if ((status=wmi_data_hdr_add(wmip, osbuf, OPT_MSGTYPE, false, false,0,NULL)) != 0) {
- A_NETBUF_FREE(osbuf);
- return status;
- }
- eid = A_WMI_Ac2EndpointID(wmip->wmi_devt, WMM_AC_BE);
- }
- A_WMI_CONTROL_TX(wmip->wmi_devt, osbuf, eid);
-
- if ((syncflag == SYNC_AFTER_WMIFLAG) || (syncflag == SYNC_BOTH_WMIFLAG)) {
- /*
- * We want to make sure all new data queued waits for the command to
- * execute. Establish a new sync point.
- */
- wmi_sync_point(wmip);
- }
- return (0);
-#undef IS_OPT_TX_CMD
-}
-
-int
-wmi_cmd_send_xtnd(struct wmi_t *wmip, void *osbuf, WMIX_COMMAND_ID cmdId,
- WMI_SYNC_FLAG syncflag)
-{
- WMIX_CMD_HDR *cHdr;
-
- if (A_NETBUF_PUSH(osbuf, sizeof(WMIX_CMD_HDR)) != 0) {
- A_NETBUF_FREE(osbuf);
- return A_NO_MEMORY;
- }
-
- cHdr = (WMIX_CMD_HDR *)A_NETBUF_DATA(osbuf);
- cHdr->commandId = (u32) cmdId;
-
- return wmi_cmd_send(wmip, osbuf, WMI_EXTENSION_CMDID, syncflag);
-}
-
-int
-wmi_connect_cmd(struct wmi_t *wmip, NETWORK_TYPE netType,
- DOT11_AUTH_MODE dot11AuthMode, AUTH_MODE authMode,
- CRYPTO_TYPE pairwiseCrypto, u8 pairwiseCryptoLen,
- CRYPTO_TYPE groupCrypto, u8 groupCryptoLen,
- int ssidLength, u8 *ssid,
- u8 *bssid, u16 channel, u32 ctrl_flags)
-{
- void *osbuf;
- WMI_CONNECT_CMD *cc;
- wmip->wmi_traffic_class = 100;
-
- if ((pairwiseCrypto == NONE_CRYPT) && (groupCrypto != NONE_CRYPT)) {
- return A_EINVAL;
- }
- if ((pairwiseCrypto != NONE_CRYPT) && (groupCrypto == NONE_CRYPT)) {
- return A_EINVAL;
- }
-
- osbuf = A_NETBUF_ALLOC(sizeof(WMI_CONNECT_CMD));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(WMI_CONNECT_CMD));
-
- cc = (WMI_CONNECT_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cc, sizeof(*cc));
-
- if (ssidLength)
- {
- memcpy(cc->ssid, ssid, ssidLength);
- }
-
- cc->ssidLength = ssidLength;
- cc->networkType = netType;
- cc->dot11AuthMode = dot11AuthMode;
- cc->authMode = authMode;
- cc->pairwiseCryptoType = pairwiseCrypto;
- cc->pairwiseCryptoLen = pairwiseCryptoLen;
- cc->groupCryptoType = groupCrypto;
- cc->groupCryptoLen = groupCryptoLen;
- cc->channel = channel;
- cc->ctrl_flags = ctrl_flags;
-
- if (bssid != NULL) {
- memcpy(cc->bssid, bssid, ATH_MAC_LEN);
- }
-
- wmip->wmi_pair_crypto_type = pairwiseCrypto;
- wmip->wmi_grp_crypto_type = groupCrypto;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_CONNECT_CMDID, NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_reconnect_cmd(struct wmi_t *wmip, u8 *bssid, u16 channel)
-{
- void *osbuf;
- WMI_RECONNECT_CMD *cc;
- wmip->wmi_traffic_class = 100;
-
- osbuf = A_NETBUF_ALLOC(sizeof(WMI_RECONNECT_CMD));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(WMI_RECONNECT_CMD));
-
- cc = (WMI_RECONNECT_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cc, sizeof(*cc));
-
- cc->channel = channel;
-
- if (bssid != NULL) {
- memcpy(cc->bssid, bssid, ATH_MAC_LEN);
- }
-
- return (wmi_cmd_send(wmip, osbuf, WMI_RECONNECT_CMDID, NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_disconnect_cmd(struct wmi_t *wmip)
-{
- int status;
- wmip->wmi_traffic_class = 100;
-
- /* Bug fix for 24817(elevator bug) - the disconnect command does not
- need to do a SYNC before.*/
- status = wmi_simple_cmd(wmip, WMI_DISCONNECT_CMDID);
-
- return status;
-}
-
-int
-wmi_startscan_cmd(struct wmi_t *wmip, WMI_SCAN_TYPE scanType,
- u32 forceFgScan, u32 isLegacy,
- u32 homeDwellTime, u32 forceScanInterval,
- s8 numChan, u16 *channelList)
-{
- void *osbuf;
- WMI_START_SCAN_CMD *sc;
- s8 size;
-
- size = sizeof (*sc);
-
- if ((scanType != WMI_LONG_SCAN) && (scanType != WMI_SHORT_SCAN)) {
- return A_EINVAL;
- }
-
- if (numChan) {
- if (numChan > WMI_MAX_CHANNELS) {
- return A_EINVAL;
- }
- size += sizeof(u16) * (numChan - 1);
- }
-
- osbuf = A_NETBUF_ALLOC(size);
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, size);
-
- sc = (WMI_START_SCAN_CMD *)(A_NETBUF_DATA(osbuf));
- sc->scanType = scanType;
- sc->forceFgScan = forceFgScan;
- sc->isLegacy = isLegacy;
- sc->homeDwellTime = homeDwellTime;
- sc->forceScanInterval = forceScanInterval;
- sc->numChannels = numChan;
- if (numChan) {
- memcpy(sc->channelList, channelList, numChan * sizeof(u16));
- }
-
- return (wmi_cmd_send(wmip, osbuf, WMI_START_SCAN_CMDID, NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_scanparams_cmd(struct wmi_t *wmip, u16 fg_start_sec,
- u16 fg_end_sec, u16 bg_sec,
- u16 minact_chdw_msec, u16 maxact_chdw_msec,
- u16 pas_chdw_msec,
- u8 shScanRatio, u8 scanCtrlFlags,
- u32 max_dfsch_act_time, u16 maxact_scan_per_ssid)
-{
- void *osbuf;
- WMI_SCAN_PARAMS_CMD *sc;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*sc));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*sc));
-
- sc = (WMI_SCAN_PARAMS_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(sc, sizeof(*sc));
- sc->fg_start_period = fg_start_sec;
- sc->fg_end_period = fg_end_sec;
- sc->bg_period = bg_sec;
- sc->minact_chdwell_time = minact_chdw_msec;
- sc->maxact_chdwell_time = maxact_chdw_msec;
- sc->pas_chdwell_time = pas_chdw_msec;
- sc->shortScanRatio = shScanRatio;
- sc->scanCtrlFlags = scanCtrlFlags;
- sc->max_dfsch_act_time = max_dfsch_act_time;
- sc->maxact_scan_per_ssid = maxact_scan_per_ssid;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_SCAN_PARAMS_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_bssfilter_cmd(struct wmi_t *wmip, u8 filter, u32 ieMask)
-{
- void *osbuf;
- WMI_BSS_FILTER_CMD *cmd;
-
- if (filter >= LAST_BSS_FILTER) {
- return A_EINVAL;
- }
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_BSS_FILTER_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->bssFilter = filter;
- cmd->ieMask = ieMask;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_BSS_FILTER_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_probedSsid_cmd(struct wmi_t *wmip, u8 index, u8 flag,
- u8 ssidLength, u8 *ssid)
-{
- void *osbuf;
- WMI_PROBED_SSID_CMD *cmd;
-
- if (index > MAX_PROBED_SSID_INDEX) {
- return A_EINVAL;
- }
- if (ssidLength > sizeof(cmd->ssid)) {
- return A_EINVAL;
- }
- if ((flag & (DISABLE_SSID_FLAG | ANY_SSID_FLAG)) && (ssidLength > 0)) {
- return A_EINVAL;
- }
- if ((flag & SPECIFIC_SSID_FLAG) && !ssidLength) {
- return A_EINVAL;
- }
-
- if (flag & SPECIFIC_SSID_FLAG) {
- is_probe_ssid = true;
- }
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_PROBED_SSID_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->entryIndex = index;
- cmd->flag = flag;
- cmd->ssidLength = ssidLength;
- memcpy(cmd->ssid, ssid, ssidLength);
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_PROBED_SSID_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_listeninterval_cmd(struct wmi_t *wmip, u16 listenInterval, u16 listenBeacons)
-{
- void *osbuf;
- WMI_LISTEN_INT_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_LISTEN_INT_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->listenInterval = listenInterval;
- cmd->numBeacons = listenBeacons;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_LISTEN_INT_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_bmisstime_cmd(struct wmi_t *wmip, u16 bmissTime, u16 bmissBeacons)
-{
- void *osbuf;
- WMI_BMISS_TIME_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_BMISS_TIME_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->bmissTime = bmissTime;
- cmd->numBeacons = bmissBeacons;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_BMISS_TIME_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_associnfo_cmd(struct wmi_t *wmip, u8 ieType,
- u8 ieLen, u8 *ieInfo)
-{
- void *osbuf;
- WMI_SET_ASSOC_INFO_CMD *cmd;
- u16 cmdLen;
-
- cmdLen = sizeof(*cmd) + ieLen - 1;
- osbuf = A_NETBUF_ALLOC(cmdLen);
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, cmdLen);
-
- cmd = (WMI_SET_ASSOC_INFO_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, cmdLen);
- cmd->ieType = ieType;
- cmd->bufferSize = ieLen;
- memcpy(cmd->assocInfo, ieInfo, ieLen);
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_ASSOC_INFO_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_powermode_cmd(struct wmi_t *wmip, u8 powerMode)
-{
- void *osbuf;
- WMI_POWER_MODE_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_POWER_MODE_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->powerMode = powerMode;
- wmip->wmi_powerMode = powerMode;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_POWER_MODE_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_ibsspmcaps_cmd(struct wmi_t *wmip, u8 pmEnable, u8 ttl,
- u16 atim_windows, u16 timeout_value)
-{
- void *osbuf;
- WMI_IBSS_PM_CAPS_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_IBSS_PM_CAPS_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->power_saving = pmEnable;
- cmd->ttl = ttl;
- cmd->atim_windows = atim_windows;
- cmd->timeout_value = timeout_value;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_IBSS_PM_CAPS_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_apps_cmd(struct wmi_t *wmip, u8 psType, u32 idle_time,
- u32 ps_period, u8 sleep_period)
-{
- void *osbuf;
- WMI_AP_PS_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_AP_PS_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->psType = psType;
- cmd->idle_time = idle_time;
- cmd->ps_period = ps_period;
- cmd->sleep_period = sleep_period;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_AP_PS_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_pmparams_cmd(struct wmi_t *wmip, u16 idlePeriod,
- u16 psPollNum, u16 dtimPolicy,
- u16 tx_wakeup_policy, u16 num_tx_to_wakeup,
- u16 ps_fail_event_policy)
-{
- void *osbuf;
- WMI_POWER_PARAMS_CMD *pm;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*pm));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*pm));
-
- pm = (WMI_POWER_PARAMS_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(pm, sizeof(*pm));
- pm->idle_period = idlePeriod;
- pm->pspoll_number = psPollNum;
- pm->dtim_policy = dtimPolicy;
- pm->tx_wakeup_policy = tx_wakeup_policy;
- pm->num_tx_to_wakeup = num_tx_to_wakeup;
- pm->ps_fail_event_policy = ps_fail_event_policy;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_POWER_PARAMS_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_disctimeout_cmd(struct wmi_t *wmip, u8 timeout)
-{
- void *osbuf;
- WMI_DISC_TIMEOUT_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_DISC_TIMEOUT_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->disconnectTimeout = timeout;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_DISC_TIMEOUT_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_addKey_cmd(struct wmi_t *wmip, u8 keyIndex, CRYPTO_TYPE keyType,
- u8 keyUsage, u8 keyLength, u8 *keyRSC,
- u8 *keyMaterial, u8 key_op_ctrl, u8 *macAddr,
- WMI_SYNC_FLAG sync_flag)
-{
- void *osbuf;
- WMI_ADD_CIPHER_KEY_CMD *cmd;
-
- if ((keyIndex > WMI_MAX_KEY_INDEX) || (keyLength > WMI_MAX_KEY_LEN) ||
- (keyMaterial == NULL))
- {
- return A_EINVAL;
- }
-
- if ((WEP_CRYPT != keyType) && (NULL == keyRSC)) {
- return A_EINVAL;
- }
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_ADD_CIPHER_KEY_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->keyIndex = keyIndex;
- cmd->keyType = keyType;
- cmd->keyUsage = keyUsage;
- cmd->keyLength = keyLength;
- memcpy(cmd->key, keyMaterial, keyLength);
-#ifdef WAPI_ENABLE
- if (NULL != keyRSC && key_op_ctrl != KEY_OP_INIT_WAPIPN) {
-#else
- if (NULL != keyRSC) {
-#endif // WAPI_ENABLE
- memcpy(cmd->keyRSC, keyRSC, sizeof(cmd->keyRSC));
- }
- cmd->key_op_ctrl = key_op_ctrl;
-
- if(macAddr) {
- memcpy(cmd->key_macaddr,macAddr,IEEE80211_ADDR_LEN);
- }
-
- return (wmi_cmd_send(wmip, osbuf, WMI_ADD_CIPHER_KEY_CMDID, sync_flag));
-}
-
-int
-wmi_add_krk_cmd(struct wmi_t *wmip, u8 *krk)
-{
- void *osbuf;
- WMI_ADD_KRK_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_ADD_KRK_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- memcpy(cmd->krk, krk, WMI_KRK_LEN);
-
- return (wmi_cmd_send(wmip, osbuf, WMI_ADD_KRK_CMDID, NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_delete_krk_cmd(struct wmi_t *wmip)
-{
- return wmi_simple_cmd(wmip, WMI_DELETE_KRK_CMDID);
-}
-
-int
-wmi_deleteKey_cmd(struct wmi_t *wmip, u8 keyIndex)
-{
- void *osbuf;
- WMI_DELETE_CIPHER_KEY_CMD *cmd;
-
- if (keyIndex > WMI_MAX_KEY_INDEX) {
- return A_EINVAL;
- }
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_DELETE_CIPHER_KEY_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->keyIndex = keyIndex;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_DELETE_CIPHER_KEY_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_setPmkid_cmd(struct wmi_t *wmip, u8 *bssid, u8 *pmkId,
- bool set)
-{
- void *osbuf;
- WMI_SET_PMKID_CMD *cmd;
-
- if (bssid == NULL) {
- return A_EINVAL;
- }
-
- if ((set == true) && (pmkId == NULL)) {
- return A_EINVAL;
- }
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_SET_PMKID_CMD *)(A_NETBUF_DATA(osbuf));
- memcpy(cmd->bssid, bssid, sizeof(cmd->bssid));
- if (set == true) {
- memcpy(cmd->pmkid, pmkId, sizeof(cmd->pmkid));
- cmd->enable = PMKID_ENABLE;
- } else {
- A_MEMZERO(cmd->pmkid, sizeof(cmd->pmkid));
- cmd->enable = PMKID_DISABLE;
- }
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_PMKID_CMDID, NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_tkip_countermeasures_cmd(struct wmi_t *wmip, bool en)
-{
- void *osbuf;
- WMI_SET_TKIP_COUNTERMEASURES_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_SET_TKIP_COUNTERMEASURES_CMD *)(A_NETBUF_DATA(osbuf));
- cmd->cm_en = (en == true)? WMI_TKIP_CM_ENABLE : WMI_TKIP_CM_DISABLE;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_TKIP_COUNTERMEASURES_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_akmp_params_cmd(struct wmi_t *wmip,
- WMI_SET_AKMP_PARAMS_CMD *akmpParams)
-{
- void *osbuf;
- WMI_SET_AKMP_PARAMS_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
- cmd = (WMI_SET_AKMP_PARAMS_CMD *)(A_NETBUF_DATA(osbuf));
- cmd->akmpInfo = akmpParams->akmpInfo;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_AKMP_PARAMS_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_pmkid_list_cmd(struct wmi_t *wmip,
- WMI_SET_PMKID_LIST_CMD *pmkInfo)
-{
- void *osbuf;
- WMI_SET_PMKID_LIST_CMD *cmd;
- u16 cmdLen;
- u8 i;
-
- cmdLen = sizeof(pmkInfo->numPMKID) +
- pmkInfo->numPMKID * sizeof(WMI_PMKID);
-
- osbuf = A_NETBUF_ALLOC(cmdLen);
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, cmdLen);
- cmd = (WMI_SET_PMKID_LIST_CMD *)(A_NETBUF_DATA(osbuf));
- cmd->numPMKID = pmkInfo->numPMKID;
-
- for (i = 0; i < cmd->numPMKID; i++) {
- memcpy(&cmd->pmkidList[i], &pmkInfo->pmkidList[i],
- WMI_PMKID_LEN);
- }
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_PMKID_LIST_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_get_pmkid_list_cmd(struct wmi_t *wmip)
-{
- return wmi_simple_cmd(wmip, WMI_GET_PMKID_LIST_CMDID);
-}
-
-int
-wmi_dataSync_send(struct wmi_t *wmip, void *osbuf, HTC_ENDPOINT_ID eid)
-{
- WMI_DATA_HDR *dtHdr;
-
- A_ASSERT( eid != wmip->wmi_endpoint_id);
- A_ASSERT(osbuf != NULL);
-
- if (A_NETBUF_PUSH(osbuf, sizeof(WMI_DATA_HDR)) != 0) {
- return A_NO_MEMORY;
- }
-
- dtHdr = (WMI_DATA_HDR *)A_NETBUF_DATA(osbuf);
- dtHdr->info =
- (SYNC_MSGTYPE & WMI_DATA_HDR_MSG_TYPE_MASK) << WMI_DATA_HDR_MSG_TYPE_SHIFT;
-
- dtHdr->info3 = 0;
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter - eid %d\n", DBGARG, eid));
-
- return (A_WMI_CONTROL_TX(wmip->wmi_devt, osbuf, eid));
-}
-
-typedef struct _WMI_DATA_SYNC_BUFS {
- u8 trafficClass;
- void *osbuf;
-}WMI_DATA_SYNC_BUFS;
-
-static int
-wmi_sync_point(struct wmi_t *wmip)
-{
- void *cmd_osbuf;
- WMI_SYNC_CMD *cmd;
- WMI_DATA_SYNC_BUFS dataSyncBufs[WMM_NUM_AC];
- u8 i,numPriStreams=0;
- int status = 0;
-
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
-
- memset(dataSyncBufs,0,sizeof(dataSyncBufs));
-
- /* lock out while we walk through the priority list and assemble our local array */
- LOCK_WMI(wmip);
-
- for (i=0; i < WMM_NUM_AC ; i++) {
- if (wmip->wmi_fatPipeExists & (1 << i)) {
- numPriStreams++;
- dataSyncBufs[numPriStreams-1].trafficClass = i;
- }
- }
-
- UNLOCK_WMI(wmip);
-
- /* dataSyncBufs is now filled with entries (starting at index 0) containing valid streamIDs */
-
- do {
- /*
- * We allocate all network buffers needed so we will be able to
- * send all required frames.
- */
- cmd_osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (cmd_osbuf == NULL) {
- status = A_NO_MEMORY;
- break;
- }
-
- A_NETBUF_PUT(cmd_osbuf, sizeof(*cmd));
-
- cmd = (WMI_SYNC_CMD *)(A_NETBUF_DATA(cmd_osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
-
- /* In the SYNC cmd sent on the control Ep, send a bitmap of the data
- * eps on which the Data Sync will be sent
- */
- cmd->dataSyncMap = wmip->wmi_fatPipeExists;
-
- for (i=0; i < numPriStreams ; i++) {
- dataSyncBufs[i].osbuf = A_NETBUF_ALLOC(0);
- if (dataSyncBufs[i].osbuf == NULL) {
- status = A_NO_MEMORY;
- break;
- }
- } //end for
-
- /* if Buffer allocation for any of the dataSync fails, then do not
- * send the Synchronize cmd on the control ep
- */
- if (status) {
- break;
- }
-
- /*
- * Send sync cmd followed by sync data messages on all endpoints being
- * used
- */
- status = wmi_cmd_send(wmip, cmd_osbuf, WMI_SYNCHRONIZE_CMDID,
- NO_SYNC_WMIFLAG);
-
- if (status) {
- break;
- }
- /* cmd buffer sent, we no longer own it */
- cmd_osbuf = NULL;
-
- for(i=0; i < numPriStreams; i++) {
- A_ASSERT(dataSyncBufs[i].osbuf != NULL);
- status = wmi_dataSync_send(wmip,
- dataSyncBufs[i].osbuf,
- A_WMI_Ac2EndpointID(wmip->wmi_devt,
- dataSyncBufs[i].
- trafficClass)
- );
-
- if (status) {
- break;
- }
- /* we don't own this buffer anymore, NULL it out of the array so it
- * won't get cleaned up */
- dataSyncBufs[i].osbuf = NULL;
- } //end for
-
- } while(false);
-
- /* free up any resources left over (possibly due to an error) */
-
- if (cmd_osbuf != NULL) {
- A_NETBUF_FREE(cmd_osbuf);
- }
-
- for (i = 0; i < numPriStreams; i++) {
- if (dataSyncBufs[i].osbuf != NULL) {
- A_NETBUF_FREE(dataSyncBufs[i].osbuf);
- }
- }
-
- return (status);
-}
-
-int
-wmi_create_pstream_cmd(struct wmi_t *wmip, WMI_CREATE_PSTREAM_CMD *params)
-{
- void *osbuf;
- WMI_CREATE_PSTREAM_CMD *cmd;
- u8 fatPipeExistsForAC=0;
- s32 minimalPHY = 0;
- s32 nominalPHY = 0;
-
- /* Validate all the parameters. */
- if( !((params->userPriority < 8) &&
- (params->userPriority <= 0x7) &&
- (convert_userPriority_to_trafficClass(params->userPriority) == params->trafficClass) &&
- (params->trafficDirection == UPLINK_TRAFFIC ||
- params->trafficDirection == DNLINK_TRAFFIC ||
- params->trafficDirection == BIDIR_TRAFFIC) &&
- (params->trafficType == TRAFFIC_TYPE_APERIODIC ||
- params->trafficType == TRAFFIC_TYPE_PERIODIC ) &&
- (params->voicePSCapability == DISABLE_FOR_THIS_AC ||
- params->voicePSCapability == ENABLE_FOR_THIS_AC ||
- params->voicePSCapability == ENABLE_FOR_ALL_AC) &&
- (params->tsid == WMI_IMPLICIT_PSTREAM || params->tsid <= WMI_MAX_THINSTREAM)) )
- {
- return A_EINVAL;
- }
-
- //
- // check nominal PHY rate is >= minimalPHY, so that DUT
- // can allow TSRS IE
- //
-
- // get the physical rate
- minimalPHY = ((params->minPhyRate / 1000)/1000); // unit of bps
-
- // check minimal phy < nominal phy rate
- //
- if (params->nominalPHY >= minimalPHY)
- {
- nominalPHY = (params->nominalPHY * 1000)/500; // unit of 500 kbps
- A_DPRINTF(DBG_WMI,
- (DBGFMT "TSRS IE Enabled::MinPhy %x->NominalPhy ===> %x\n", DBGARG,
- minimalPHY, nominalPHY));
-
- params->nominalPHY = nominalPHY;
- }
- else
- {
- params->nominalPHY = 0;
- }
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- A_DPRINTF(DBG_WMI,
- (DBGFMT "Sending create_pstream_cmd: ac=%d tsid:%d\n", DBGARG,
- params->trafficClass, params->tsid));
-
- cmd = (WMI_CREATE_PSTREAM_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- memcpy(cmd, params, sizeof(*cmd));
-
- /* this is an implicitly created Fat pipe */
- if ((u32)params->tsid == (u32)WMI_IMPLICIT_PSTREAM) {
- LOCK_WMI(wmip);
- fatPipeExistsForAC = (wmip->wmi_fatPipeExists & (1 << params->trafficClass));
- wmip->wmi_fatPipeExists |= (1<<params->trafficClass);
- UNLOCK_WMI(wmip);
- } else {
- /* this is an explicitly created thin stream within a fat pipe */
- LOCK_WMI(wmip);
- fatPipeExistsForAC = (wmip->wmi_fatPipeExists & (1 << params->trafficClass));
- wmip->wmi_streamExistsForAC[params->trafficClass] |= (1<<params->tsid);
- /* if a thinstream becomes active, the fat pipe automatically
- * becomes active
- */
- wmip->wmi_fatPipeExists |= (1<<params->trafficClass);
- UNLOCK_WMI(wmip);
- }
-
- /* Indicate activty change to driver layer only if this is the
- * first TSID to get created in this AC explicitly or an implicit
- * fat pipe is getting created.
- */
- if (!fatPipeExistsForAC) {
- A_WMI_STREAM_TX_ACTIVE(wmip->wmi_devt, params->trafficClass);
- }
-
- /* mike: should be SYNC_BEFORE_WMIFLAG */
- return (wmi_cmd_send(wmip, osbuf, WMI_CREATE_PSTREAM_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_delete_pstream_cmd(struct wmi_t *wmip, u8 trafficClass, u8 tsid)
-{
- void *osbuf;
- WMI_DELETE_PSTREAM_CMD *cmd;
- int status;
- u16 activeTsids=0;
-
- /* validate the parameters */
- if (trafficClass > 3) {
- A_DPRINTF(DBG_WMI, (DBGFMT "Invalid trafficClass: %d\n", DBGARG, trafficClass));
- return A_EINVAL;
- }
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_DELETE_PSTREAM_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
-
- cmd->trafficClass = trafficClass;
- cmd->tsid = tsid;
-
- LOCK_WMI(wmip);
- activeTsids = wmip->wmi_streamExistsForAC[trafficClass];
- UNLOCK_WMI(wmip);
-
- /* Check if the tsid was created & exists */
- if (!(activeTsids & (1<<tsid))) {
-
- A_NETBUF_FREE(osbuf);
- A_DPRINTF(DBG_WMI,
- (DBGFMT "TSID %d does'nt exist for trafficClass: %d\n", DBGARG, tsid, trafficClass));
- /* TODO: return a more appropriate err code */
- return A_ERROR;
- }
-
- A_DPRINTF(DBG_WMI,
- (DBGFMT "Sending delete_pstream_cmd: trafficClass: %d tsid=%d\n", DBGARG, trafficClass, tsid));
-
- status = (wmi_cmd_send(wmip, osbuf, WMI_DELETE_PSTREAM_CMDID,
- SYNC_BEFORE_WMIFLAG));
-
- LOCK_WMI(wmip);
- wmip->wmi_streamExistsForAC[trafficClass] &= ~(1<<tsid);
- activeTsids = wmip->wmi_streamExistsForAC[trafficClass];
- UNLOCK_WMI(wmip);
-
-
- /* Indicate stream inactivity to driver layer only if all tsids
- * within this AC are deleted.
- */
- if(!activeTsids) {
- A_WMI_STREAM_TX_INACTIVE(wmip->wmi_devt, trafficClass);
- wmip->wmi_fatPipeExists &= ~(1<<trafficClass);
- }
-
- return status;
-}
-
-int
-wmi_set_framerate_cmd(struct wmi_t *wmip, u8 bEnable, u8 type, u8 subType, u16 rateMask)
-{
- void *osbuf;
- WMI_FRAME_RATES_CMD *cmd;
- u8 frameType;
-
- A_DPRINTF(DBG_WMI,
- (DBGFMT " type %02X, subType %02X, rateMask %04x\n", DBGARG, type, subType, rateMask));
-
- if((type != IEEE80211_FRAME_TYPE_MGT && type != IEEE80211_FRAME_TYPE_CTL) ||
- (subType > 15)){
-
- return A_EINVAL;
- }
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_FRAME_RATES_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
-
- frameType = (u8)((subType << 4) | type);
-
- cmd->bEnableMask = bEnable;
- cmd->frameType = frameType;
- cmd->frameRateMask = rateMask;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_FRAMERATES_CMDID, NO_SYNC_WMIFLAG));
-}
-
-/*
- * used to set the bit rate. rate is in Kbps. If rate == -1
- * then auto selection is used.
- */
-int
-wmi_set_bitrate_cmd(struct wmi_t *wmip, s32 dataRate, s32 mgmtRate, s32 ctlRate)
-{
- void *osbuf;
- WMI_BIT_RATE_CMD *cmd;
- s8 drix, mrix, crix, ret_val;
-
- if (dataRate != -1) {
- ret_val = wmi_validate_bitrate(wmip, dataRate, &drix);
- if(ret_val == A_EINVAL){
- return A_EINVAL;
- }
- } else {
- drix = -1;
- }
-
- if (mgmtRate != -1) {
- ret_val = wmi_validate_bitrate(wmip, mgmtRate, &mrix);
- if(ret_val == A_EINVAL){
- return A_EINVAL;
- }
- } else {
- mrix = -1;
- }
- if (ctlRate != -1) {
- ret_val = wmi_validate_bitrate(wmip, ctlRate, &crix);
- if(ret_val == A_EINVAL){
- return A_EINVAL;
- }
- } else {
- crix = -1;
- }
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_BIT_RATE_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
-
- cmd->rateIndex = drix;
- cmd->mgmtRateIndex = mrix;
- cmd->ctlRateIndex = crix;
-
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_BITRATE_CMDID, NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_get_bitrate_cmd(struct wmi_t *wmip)
-{
- return wmi_simple_cmd(wmip, WMI_GET_BITRATE_CMDID);
-}
-
-/*
- * Returns true iff the given rate index is legal in the current PHY mode.
- */
-bool
-wmi_is_bitrate_index_valid(struct wmi_t *wmip, s32 rateIndex)
-{
- WMI_PHY_MODE phyMode = (WMI_PHY_MODE) wmip->wmi_phyMode;
- bool isValid = true;
- switch(phyMode) {
- case WMI_11A_MODE:
- if (wmip->wmi_ht_allowed[A_BAND_5GHZ]){
- if ((rateIndex < MODE_A_SUPPORT_RATE_START) || (rateIndex > MODE_GHT20_SUPPORT_RATE_STOP)) {
- isValid = false;
- }
- } else {
- if ((rateIndex < MODE_A_SUPPORT_RATE_START) || (rateIndex > MODE_A_SUPPORT_RATE_STOP)) {
- isValid = false;
- }
- }
- break;
-
- case WMI_11B_MODE:
- if ((rateIndex < MODE_B_SUPPORT_RATE_START) || (rateIndex > MODE_B_SUPPORT_RATE_STOP)) {
- isValid = false;
- }
- break;
-
- case WMI_11GONLY_MODE:
- if (wmip->wmi_ht_allowed[A_BAND_24GHZ]){
- if ((rateIndex < MODE_GONLY_SUPPORT_RATE_START) || (rateIndex > MODE_GHT20_SUPPORT_RATE_STOP)) {
- isValid = false;
- }
- } else {
- if ((rateIndex < MODE_GONLY_SUPPORT_RATE_START) || (rateIndex > MODE_GONLY_SUPPORT_RATE_STOP)) {
- isValid = false;
- }
- }
- break;
-
- case WMI_11G_MODE:
- case WMI_11AG_MODE:
- if (wmip->wmi_ht_allowed[A_BAND_24GHZ]){
- if ((rateIndex < MODE_G_SUPPORT_RATE_START) || (rateIndex > MODE_GHT20_SUPPORT_RATE_STOP)) {
- isValid = false;
- }
- } else {
- if ((rateIndex < MODE_G_SUPPORT_RATE_START) || (rateIndex > MODE_G_SUPPORT_RATE_STOP)) {
- isValid = false;
- }
- }
- break;
- default:
- A_ASSERT(false);
- break;
- }
-
- return isValid;
-}
-
-s8 wmi_validate_bitrate(struct wmi_t *wmip, s32 rate, s8 *rate_idx)
-{
- s8 i;
-
- for (i=0;;i++)
- {
- if (wmi_rateTable[(u32) i][0] == 0) {
- return A_EINVAL;
- }
- if (wmi_rateTable[(u32) i][0] == rate) {
- break;
- }
- }
-
- if(wmi_is_bitrate_index_valid(wmip, (s32) i) != true) {
- return A_EINVAL;
- }
-
- *rate_idx = i;
- return 0;
-}
-
-int
-wmi_set_fixrates_cmd(struct wmi_t *wmip, u32 fixRatesMask)
-{
- void *osbuf;
- WMI_FIX_RATES_CMD *cmd;
-#if 0
- s32 rateIndex;
-/* This check does not work for AR6003 as the HT modes are enabled only when
- * the STA is connected to a HT_BSS and is not based only on channel. It is
- * safe to skip this check however because rate control will only use rates
- * that are permitted by the valid rate mask and the fix rate mask. Meaning
- * the fix rate mask is not sufficient by itself to cause an invalid rate
- * to be used. */
- /* Make sure all rates in the mask are valid in the current PHY mode */
- for(rateIndex = 0; rateIndex < MAX_NUMBER_OF_SUPPORT_RATES; rateIndex++) {
- if((1 << rateIndex) & (u32)fixRatesMask) {
- if(wmi_is_bitrate_index_valid(wmip, rateIndex) != true) {
- A_DPRINTF(DBG_WMI, (DBGFMT "Set Fix Rates command failed: Given rate is illegal in current PHY mode\n", DBGARG));
- return A_EINVAL;
- }
- }
- }
-#endif
-
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_FIX_RATES_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
-
- cmd->fixRateMask = fixRatesMask;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_FIXRATES_CMDID, NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_get_ratemask_cmd(struct wmi_t *wmip)
-{
- return wmi_simple_cmd(wmip, WMI_GET_FIXRATES_CMDID);
-}
-
-int
-wmi_get_channelList_cmd(struct wmi_t *wmip)
-{
- return wmi_simple_cmd(wmip, WMI_GET_CHANNEL_LIST_CMDID);
-}
-
-/*
- * used to generate a wmi sey channel Parameters cmd.
- * mode should always be specified and corresponds to the phy mode of the
- * wlan.
- * numChan should alway sbe specified. If zero indicates that all available
- * channels should be used.
- * channelList is an array of channel frequencies (in Mhz) which the radio
- * should limit its operation to. It should be NULL if numChan == 0. Size of
- * array should correspond to numChan entries.
- */
-int
-wmi_set_channelParams_cmd(struct wmi_t *wmip, u8 scanParam,
- WMI_PHY_MODE mode, s8 numChan,
- u16 *channelList)
-{
- void *osbuf;
- WMI_CHANNEL_PARAMS_CMD *cmd;
- s8 size;
-
- size = sizeof (*cmd);
-
- if (numChan) {
- if (numChan > WMI_MAX_CHANNELS) {
- return A_EINVAL;
- }
- size += sizeof(u16) * (numChan - 1);
- }
-
- osbuf = A_NETBUF_ALLOC(size);
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, size);
-
- cmd = (WMI_CHANNEL_PARAMS_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, size);
-
- wmip->wmi_phyMode = mode;
- cmd->scanParam = scanParam;
- cmd->phyMode = mode;
- cmd->numChannels = numChan;
- memcpy(cmd->channelList, channelList, numChan * sizeof(u16));
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_CHANNEL_PARAMS_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-void
-wmi_cache_configure_rssithreshold(struct wmi_t *wmip, WMI_RSSI_THRESHOLD_PARAMS_CMD *rssiCmd)
-{
- SQ_THRESHOLD_PARAMS *sq_thresh =
- &wmip->wmi_SqThresholdParams[SIGNAL_QUALITY_METRICS_RSSI];
- /*
- * Parse the command and store the threshold values here. The checks
- * for valid values can be put here
- */
- sq_thresh->weight = rssiCmd->weight;
- sq_thresh->polling_interval = rssiCmd->pollTime;
-
- sq_thresh->upper_threshold[0] = rssiCmd->thresholdAbove1_Val - SIGNAL_QUALITY_NOISE_FLOOR;
- sq_thresh->upper_threshold[1] = rssiCmd->thresholdAbove2_Val - SIGNAL_QUALITY_NOISE_FLOOR;
- sq_thresh->upper_threshold[2] = rssiCmd->thresholdAbove3_Val - SIGNAL_QUALITY_NOISE_FLOOR;
- sq_thresh->upper_threshold[3] = rssiCmd->thresholdAbove4_Val - SIGNAL_QUALITY_NOISE_FLOOR;
- sq_thresh->upper_threshold[4] = rssiCmd->thresholdAbove5_Val - SIGNAL_QUALITY_NOISE_FLOOR;
- sq_thresh->upper_threshold[5] = rssiCmd->thresholdAbove6_Val - SIGNAL_QUALITY_NOISE_FLOOR;
- sq_thresh->upper_threshold_valid_count = 6;
-
- /* List sorted in descending order */
- sq_thresh->lower_threshold[0] = rssiCmd->thresholdBelow6_Val - SIGNAL_QUALITY_NOISE_FLOOR;
- sq_thresh->lower_threshold[1] = rssiCmd->thresholdBelow5_Val - SIGNAL_QUALITY_NOISE_FLOOR;
- sq_thresh->lower_threshold[2] = rssiCmd->thresholdBelow4_Val - SIGNAL_QUALITY_NOISE_FLOOR;
- sq_thresh->lower_threshold[3] = rssiCmd->thresholdBelow3_Val - SIGNAL_QUALITY_NOISE_FLOOR;
- sq_thresh->lower_threshold[4] = rssiCmd->thresholdBelow2_Val - SIGNAL_QUALITY_NOISE_FLOOR;
- sq_thresh->lower_threshold[5] = rssiCmd->thresholdBelow1_Val - SIGNAL_QUALITY_NOISE_FLOOR;
- sq_thresh->lower_threshold_valid_count = 6;
-
- if (!rssi_event_value) {
- /*
- * Configuring the thresholds to their extremes allows the host to get an
- * event from the target which is used for the configuring the correct
- * thresholds
- */
- rssiCmd->thresholdAbove1_Val = sq_thresh->upper_threshold[0];
- rssiCmd->thresholdBelow1_Val = sq_thresh->lower_threshold[0];
- } else {
- /*
- * In case the user issues multiple times of rssi_threshold_setting,
- * we should not use the extreames anymore, the target does not expect that.
- */
- rssiCmd->thresholdAbove1_Val = ar6000_get_upper_threshold(rssi_event_value, sq_thresh,
- sq_thresh->upper_threshold_valid_count);
- rssiCmd->thresholdBelow1_Val = ar6000_get_lower_threshold(rssi_event_value, sq_thresh,
- sq_thresh->lower_threshold_valid_count);
-}
-}
-
-int
-wmi_set_rssi_threshold_params(struct wmi_t *wmip,
- WMI_RSSI_THRESHOLD_PARAMS_CMD *rssiCmd)
-{
-
- /* Check these values are in ascending order */
- if( rssiCmd->thresholdAbove6_Val <= rssiCmd->thresholdAbove5_Val ||
- rssiCmd->thresholdAbove5_Val <= rssiCmd->thresholdAbove4_Val ||
- rssiCmd->thresholdAbove4_Val <= rssiCmd->thresholdAbove3_Val ||
- rssiCmd->thresholdAbove3_Val <= rssiCmd->thresholdAbove2_Val ||
- rssiCmd->thresholdAbove2_Val <= rssiCmd->thresholdAbove1_Val ||
- rssiCmd->thresholdBelow6_Val <= rssiCmd->thresholdBelow5_Val ||
- rssiCmd->thresholdBelow5_Val <= rssiCmd->thresholdBelow4_Val ||
- rssiCmd->thresholdBelow4_Val <= rssiCmd->thresholdBelow3_Val ||
- rssiCmd->thresholdBelow3_Val <= rssiCmd->thresholdBelow2_Val ||
- rssiCmd->thresholdBelow2_Val <= rssiCmd->thresholdBelow1_Val)
- {
- return A_EINVAL;
- }
-
- wmi_cache_configure_rssithreshold(wmip, rssiCmd);
-
- return (wmi_send_rssi_threshold_params(wmip, rssiCmd));
-}
-
-int
-wmi_set_ip_cmd(struct wmi_t *wmip, WMI_SET_IP_CMD *ipCmd)
-{
- void *osbuf;
- WMI_SET_IP_CMD *cmd;
-
- /* Multicast address are not valid */
- if((*((u8 *)&ipCmd->ips[0]) >= 0xE0) ||
- (*((u8 *)&ipCmd->ips[1]) >= 0xE0)) {
- return A_EINVAL;
- }
-
- osbuf = A_NETBUF_ALLOC(sizeof(WMI_SET_IP_CMD));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(WMI_SET_IP_CMD));
- cmd = (WMI_SET_IP_CMD *)(A_NETBUF_DATA(osbuf));
- memcpy(cmd, ipCmd, sizeof(WMI_SET_IP_CMD));
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_IP_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_host_sleep_mode_cmd(struct wmi_t *wmip,
- WMI_SET_HOST_SLEEP_MODE_CMD *hostModeCmd)
-{
- void *osbuf;
- s8 size;
- WMI_SET_HOST_SLEEP_MODE_CMD *cmd;
- u16 activeTsids=0;
- u8 streamExists=0;
- u8 i;
-
- if( hostModeCmd->awake == hostModeCmd->asleep) {
- return A_EINVAL;
- }
-
- size = sizeof (*cmd);
-
- osbuf = A_NETBUF_ALLOC(size);
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, size);
-
- cmd = (WMI_SET_HOST_SLEEP_MODE_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, size);
- memcpy(cmd, hostModeCmd, sizeof(WMI_SET_HOST_SLEEP_MODE_CMD));
-
- if(hostModeCmd->asleep) {
- /*
- * Relinquish credits from all implicitly created pstreams since when we
- * go to sleep. If user created explicit thinstreams exists with in a
- * fatpipe leave them intact for the user to delete
- */
- LOCK_WMI(wmip);
- streamExists = wmip->wmi_fatPipeExists;
- UNLOCK_WMI(wmip);
-
- for(i=0;i< WMM_NUM_AC;i++) {
- if (streamExists & (1<<i)) {
- LOCK_WMI(wmip);
- activeTsids = wmip->wmi_streamExistsForAC[i];
- UNLOCK_WMI(wmip);
- /* If there are no user created thin streams delete the fatpipe */
- if(!activeTsids) {
- streamExists &= ~(1<<i);
- /*Indicate inactivity to drv layer for this fatpipe(pstream)*/
- A_WMI_STREAM_TX_INACTIVE(wmip->wmi_devt,i);
- }
- }
- }
-
- /* Update the fatpipes that exists*/
- LOCK_WMI(wmip);
- wmip->wmi_fatPipeExists = streamExists;
- UNLOCK_WMI(wmip);
- }
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_HOST_SLEEP_MODE_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_wow_mode_cmd(struct wmi_t *wmip,
- WMI_SET_WOW_MODE_CMD *wowModeCmd)
-{
- void *osbuf;
- s8 size;
- WMI_SET_WOW_MODE_CMD *cmd;
-
- size = sizeof (*cmd);
-
- osbuf = A_NETBUF_ALLOC(size);
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, size);
-
- cmd = (WMI_SET_WOW_MODE_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, size);
- memcpy(cmd, wowModeCmd, sizeof(WMI_SET_WOW_MODE_CMD));
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_WOW_MODE_CMDID,
- NO_SYNC_WMIFLAG));
-
-}
-
-int
-wmi_get_wow_list_cmd(struct wmi_t *wmip,
- WMI_GET_WOW_LIST_CMD *wowListCmd)
-{
- void *osbuf;
- s8 size;
- WMI_GET_WOW_LIST_CMD *cmd;
-
- size = sizeof (*cmd);
-
- osbuf = A_NETBUF_ALLOC(size);
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, size);
-
- cmd = (WMI_GET_WOW_LIST_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, size);
- memcpy(cmd, wowListCmd, sizeof(WMI_GET_WOW_LIST_CMD));
-
- return (wmi_cmd_send(wmip, osbuf, WMI_GET_WOW_LIST_CMDID,
- NO_SYNC_WMIFLAG));
-
-}
-
-static int
-wmi_get_wow_list_event_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_GET_WOW_LIST_REPLY *reply;
-
- if (len < sizeof(WMI_GET_WOW_LIST_REPLY)) {
- return A_EINVAL;
- }
- reply = (WMI_GET_WOW_LIST_REPLY *)datap;
-
- A_WMI_WOW_LIST_EVENT(wmip->wmi_devt, reply->num_filters,
- reply);
-
- return 0;
-}
-
-int wmi_add_wow_pattern_cmd(struct wmi_t *wmip,
- WMI_ADD_WOW_PATTERN_CMD *addWowCmd,
- u8 *pattern, u8 *mask,
- u8 pattern_size)
-{
- void *osbuf;
- s8 size;
- WMI_ADD_WOW_PATTERN_CMD *cmd;
- u8 *filter_mask = NULL;
-
- size = sizeof (*cmd);
-
- size += ((2 * addWowCmd->filter_size)* sizeof(u8));
- osbuf = A_NETBUF_ALLOC(size);
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, size);
-
- cmd = (WMI_ADD_WOW_PATTERN_CMD *)(A_NETBUF_DATA(osbuf));
- cmd->filter_list_id = addWowCmd->filter_list_id;
- cmd->filter_offset = addWowCmd->filter_offset;
- cmd->filter_size = addWowCmd->filter_size;
-
- memcpy(cmd->filter, pattern, addWowCmd->filter_size);
-
- filter_mask = (u8 *)(cmd->filter + cmd->filter_size);
- memcpy(filter_mask, mask, addWowCmd->filter_size);
-
-
- return (wmi_cmd_send(wmip, osbuf, WMI_ADD_WOW_PATTERN_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_del_wow_pattern_cmd(struct wmi_t *wmip,
- WMI_DEL_WOW_PATTERN_CMD *delWowCmd)
-{
- void *osbuf;
- s8 size;
- WMI_DEL_WOW_PATTERN_CMD *cmd;
-
- size = sizeof (*cmd);
-
- osbuf = A_NETBUF_ALLOC(size);
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, size);
-
- cmd = (WMI_DEL_WOW_PATTERN_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, size);
- memcpy(cmd, delWowCmd, sizeof(WMI_DEL_WOW_PATTERN_CMD));
-
- return (wmi_cmd_send(wmip, osbuf, WMI_DEL_WOW_PATTERN_CMDID,
- NO_SYNC_WMIFLAG));
-
-}
-
-void
-wmi_cache_configure_snrthreshold(struct wmi_t *wmip, WMI_SNR_THRESHOLD_PARAMS_CMD *snrCmd)
-{
- SQ_THRESHOLD_PARAMS *sq_thresh =
- &wmip->wmi_SqThresholdParams[SIGNAL_QUALITY_METRICS_SNR];
- /*
- * Parse the command and store the threshold values here. The checks
- * for valid values can be put here
- */
- sq_thresh->weight = snrCmd->weight;
- sq_thresh->polling_interval = snrCmd->pollTime;
-
- sq_thresh->upper_threshold[0] = snrCmd->thresholdAbove1_Val;
- sq_thresh->upper_threshold[1] = snrCmd->thresholdAbove2_Val;
- sq_thresh->upper_threshold[2] = snrCmd->thresholdAbove3_Val;
- sq_thresh->upper_threshold[3] = snrCmd->thresholdAbove4_Val;
- sq_thresh->upper_threshold_valid_count = 4;
-
- /* List sorted in descending order */
- sq_thresh->lower_threshold[0] = snrCmd->thresholdBelow4_Val;
- sq_thresh->lower_threshold[1] = snrCmd->thresholdBelow3_Val;
- sq_thresh->lower_threshold[2] = snrCmd->thresholdBelow2_Val;
- sq_thresh->lower_threshold[3] = snrCmd->thresholdBelow1_Val;
- sq_thresh->lower_threshold_valid_count = 4;
-
- if (!snr_event_value) {
- /*
- * Configuring the thresholds to their extremes allows the host to get an
- * event from the target which is used for the configuring the correct
- * thresholds
- */
- snrCmd->thresholdAbove1_Val = (u8)sq_thresh->upper_threshold[0];
- snrCmd->thresholdBelow1_Val = (u8)sq_thresh->lower_threshold[0];
- } else {
- /*
- * In case the user issues multiple times of snr_threshold_setting,
- * we should not use the extreames anymore, the target does not expect that.
- */
- snrCmd->thresholdAbove1_Val = ar6000_get_upper_threshold(snr_event_value, sq_thresh,
- sq_thresh->upper_threshold_valid_count);
- snrCmd->thresholdBelow1_Val = ar6000_get_lower_threshold(snr_event_value, sq_thresh,
- sq_thresh->lower_threshold_valid_count);
- }
-
-}
-int
-wmi_set_snr_threshold_params(struct wmi_t *wmip,
- WMI_SNR_THRESHOLD_PARAMS_CMD *snrCmd)
-{
- if( snrCmd->thresholdAbove4_Val <= snrCmd->thresholdAbove3_Val ||
- snrCmd->thresholdAbove3_Val <= snrCmd->thresholdAbove2_Val ||
- snrCmd->thresholdAbove2_Val <= snrCmd->thresholdAbove1_Val ||
- snrCmd->thresholdBelow4_Val <= snrCmd->thresholdBelow3_Val ||
- snrCmd->thresholdBelow3_Val <= snrCmd->thresholdBelow2_Val ||
- snrCmd->thresholdBelow2_Val <= snrCmd->thresholdBelow1_Val)
- {
- return A_EINVAL;
- }
- wmi_cache_configure_snrthreshold(wmip, snrCmd);
- return (wmi_send_snr_threshold_params(wmip, snrCmd));
-}
-
-int
-wmi_clr_rssi_snr(struct wmi_t *wmip)
-{
- void *osbuf;
-
- osbuf = A_NETBUF_ALLOC(sizeof(int));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- return (wmi_cmd_send(wmip, osbuf, WMI_CLR_RSSI_SNR_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_lq_threshold_params(struct wmi_t *wmip,
- WMI_LQ_THRESHOLD_PARAMS_CMD *lqCmd)
-{
- void *osbuf;
- s8 size;
- WMI_LQ_THRESHOLD_PARAMS_CMD *cmd;
- /* These values are in ascending order */
- if( lqCmd->thresholdAbove4_Val <= lqCmd->thresholdAbove3_Val ||
- lqCmd->thresholdAbove3_Val <= lqCmd->thresholdAbove2_Val ||
- lqCmd->thresholdAbove2_Val <= lqCmd->thresholdAbove1_Val ||
- lqCmd->thresholdBelow4_Val <= lqCmd->thresholdBelow3_Val ||
- lqCmd->thresholdBelow3_Val <= lqCmd->thresholdBelow2_Val ||
- lqCmd->thresholdBelow2_Val <= lqCmd->thresholdBelow1_Val ) {
-
- return A_EINVAL;
- }
-
- size = sizeof (*cmd);
-
- osbuf = A_NETBUF_ALLOC(size);
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, size);
-
- cmd = (WMI_LQ_THRESHOLD_PARAMS_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, size);
- memcpy(cmd, lqCmd, sizeof(WMI_LQ_THRESHOLD_PARAMS_CMD));
-
- return (wmi_cmd_send(wmip, osbuf, WMI_LQ_THRESHOLD_PARAMS_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_error_report_bitmask(struct wmi_t *wmip, u32 mask)
-{
- void *osbuf;
- s8 size;
- WMI_TARGET_ERROR_REPORT_BITMASK *cmd;
-
- size = sizeof (*cmd);
-
- osbuf = A_NETBUF_ALLOC(size);
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, size);
-
- cmd = (WMI_TARGET_ERROR_REPORT_BITMASK *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, size);
-
- cmd->bitmask = mask;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_TARGET_ERROR_REPORT_BITMASK_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_get_challenge_resp_cmd(struct wmi_t *wmip, u32 cookie, u32 source)
-{
- void *osbuf;
- WMIX_HB_CHALLENGE_RESP_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMIX_HB_CHALLENGE_RESP_CMD *)(A_NETBUF_DATA(osbuf));
- cmd->cookie = cookie;
- cmd->source = source;
-
- return (wmi_cmd_send_xtnd(wmip, osbuf, WMIX_HB_CHALLENGE_RESP_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_config_debug_module_cmd(struct wmi_t *wmip, u16 mmask,
- u16 tsr, bool rep, u16 size,
- u32 valid)
-{
- void *osbuf;
- WMIX_DBGLOG_CFG_MODULE_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMIX_DBGLOG_CFG_MODULE_CMD *)(A_NETBUF_DATA(osbuf));
- cmd->config.cfgmmask = mmask;
- cmd->config.cfgtsr = tsr;
- cmd->config.cfgrep = rep;
- cmd->config.cfgsize = size;
- cmd->config.cfgvalid = valid;
-
- return (wmi_cmd_send_xtnd(wmip, osbuf, WMIX_DBGLOG_CFG_MODULE_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_get_stats_cmd(struct wmi_t *wmip)
-{
- return wmi_simple_cmd(wmip, WMI_GET_STATISTICS_CMDID);
-}
-
-int
-wmi_addBadAp_cmd(struct wmi_t *wmip, u8 apIndex, u8 *bssid)
-{
- void *osbuf;
- WMI_ADD_BAD_AP_CMD *cmd;
-
- if ((bssid == NULL) || (apIndex > WMI_MAX_BAD_AP_INDEX)) {
- return A_EINVAL;
- }
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_ADD_BAD_AP_CMD *)(A_NETBUF_DATA(osbuf));
- cmd->badApIndex = apIndex;
- memcpy(cmd->bssid, bssid, sizeof(cmd->bssid));
-
- return (wmi_cmd_send(wmip, osbuf, WMI_ADD_BAD_AP_CMDID, SYNC_BEFORE_WMIFLAG));
-}
-
-int
-wmi_deleteBadAp_cmd(struct wmi_t *wmip, u8 apIndex)
-{
- void *osbuf;
- WMI_DELETE_BAD_AP_CMD *cmd;
-
- if (apIndex > WMI_MAX_BAD_AP_INDEX) {
- return A_EINVAL;
- }
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_DELETE_BAD_AP_CMD *)(A_NETBUF_DATA(osbuf));
- cmd->badApIndex = apIndex;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_DELETE_BAD_AP_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_abort_scan_cmd(struct wmi_t *wmip)
-{
- return wmi_simple_cmd(wmip, WMI_ABORT_SCAN_CMDID);
-}
-
-int
-wmi_set_txPwr_cmd(struct wmi_t *wmip, u8 dbM)
-{
- void *osbuf;
- WMI_SET_TX_PWR_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_SET_TX_PWR_CMD *)(A_NETBUF_DATA(osbuf));
- cmd->dbM = dbM;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_TX_PWR_CMDID, NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_get_txPwr_cmd(struct wmi_t *wmip)
-{
- return wmi_simple_cmd(wmip, WMI_GET_TX_PWR_CMDID);
-}
-
-u16 wmi_get_mapped_qos_queue(struct wmi_t *wmip, u8 trafficClass)
-{
- u16 activeTsids=0;
-
- LOCK_WMI(wmip);
- activeTsids = wmip->wmi_streamExistsForAC[trafficClass];
- UNLOCK_WMI(wmip);
-
- return activeTsids;
-}
-
-int
-wmi_get_roam_tbl_cmd(struct wmi_t *wmip)
-{
- return wmi_simple_cmd(wmip, WMI_GET_ROAM_TBL_CMDID);
-}
-
-int
-wmi_get_roam_data_cmd(struct wmi_t *wmip, u8 roamDataType)
-{
- void *osbuf;
- u32 size = sizeof(u8);
- WMI_TARGET_ROAM_DATA *cmd;
-
- osbuf = A_NETBUF_ALLOC(size); /* no payload */
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, size);
-
- cmd = (WMI_TARGET_ROAM_DATA *)(A_NETBUF_DATA(osbuf));
- cmd->roamDataType = roamDataType;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_GET_ROAM_DATA_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_roam_ctrl_cmd(struct wmi_t *wmip, WMI_SET_ROAM_CTRL_CMD *p,
- u8 size)
-{
- void *osbuf;
- WMI_SET_ROAM_CTRL_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(size);
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, size);
-
- cmd = (WMI_SET_ROAM_CTRL_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, size);
-
- memcpy(cmd, p, size);
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_ROAM_CTRL_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_powersave_timers_cmd(struct wmi_t *wmip,
- WMI_POWERSAVE_TIMERS_POLICY_CMD *pCmd,
- u8 size)
-{
- void *osbuf;
- WMI_POWERSAVE_TIMERS_POLICY_CMD *cmd;
-
- /* These timers can't be zero */
- if(!pCmd->psPollTimeout || !pCmd->triggerTimeout ||
- !(pCmd->apsdTimPolicy == IGNORE_TIM_ALL_QUEUES_APSD ||
- pCmd->apsdTimPolicy == PROCESS_TIM_ALL_QUEUES_APSD) ||
- !(pCmd->simulatedAPSDTimPolicy == IGNORE_TIM_SIMULATED_APSD ||
- pCmd->simulatedAPSDTimPolicy == PROCESS_TIM_SIMULATED_APSD))
- return A_EINVAL;
-
- osbuf = A_NETBUF_ALLOC(size);
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, size);
-
- cmd = (WMI_POWERSAVE_TIMERS_POLICY_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, size);
-
- memcpy(cmd, pCmd, size);
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_POWERSAVE_TIMERS_POLICY_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_access_params_cmd(struct wmi_t *wmip, u8 ac, u16 txop, u8 eCWmin,
- u8 eCWmax, u8 aifsn)
-{
- void *osbuf;
- WMI_SET_ACCESS_PARAMS_CMD *cmd;
-
- if ((eCWmin > WMI_MAX_CW_ACPARAM) || (eCWmax > WMI_MAX_CW_ACPARAM) ||
- (aifsn > WMI_MAX_AIFSN_ACPARAM) || (ac >= WMM_NUM_AC))
- {
- return A_EINVAL;
- }
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_SET_ACCESS_PARAMS_CMD *)(A_NETBUF_DATA(osbuf));
- cmd->txop = txop;
- cmd->eCWmin = eCWmin;
- cmd->eCWmax = eCWmax;
- cmd->aifsn = aifsn;
- cmd->ac = ac;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_ACCESS_PARAMS_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_retry_limits_cmd(struct wmi_t *wmip, u8 frameType,
- u8 trafficClass, u8 maxRetries,
- u8 enableNotify)
-{
- void *osbuf;
- WMI_SET_RETRY_LIMITS_CMD *cmd;
-
- if ((frameType != MGMT_FRAMETYPE) && (frameType != CONTROL_FRAMETYPE) &&
- (frameType != DATA_FRAMETYPE))
- {
- return A_EINVAL;
- }
-
- if (maxRetries > WMI_MAX_RETRIES) {
- return A_EINVAL;
- }
-
- if (frameType != DATA_FRAMETYPE) {
- trafficClass = 0;
- }
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_SET_RETRY_LIMITS_CMD *)(A_NETBUF_DATA(osbuf));
- cmd->frameType = frameType;
- cmd->trafficClass = trafficClass;
- cmd->maxRetries = maxRetries;
- cmd->enableNotify = enableNotify;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_RETRY_LIMITS_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-void
-wmi_get_current_bssid(struct wmi_t *wmip, u8 *bssid)
-{
- if (bssid != NULL) {
- memcpy(bssid, wmip->wmi_bssid, ATH_MAC_LEN);
- }
-}
-
-int
-wmi_set_opt_mode_cmd(struct wmi_t *wmip, u8 optMode)
-{
- void *osbuf;
- WMI_SET_OPT_MODE_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_SET_OPT_MODE_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->optMode = optMode;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_OPT_MODE_CMDID,
- SYNC_BOTH_WMIFLAG));
-}
-
-int
-wmi_opt_tx_frame_cmd(struct wmi_t *wmip,
- u8 frmType,
- u8 *dstMacAddr,
- u8 *bssid,
- u16 optIEDataLen,
- u8 *optIEData)
-{
- void *osbuf;
- WMI_OPT_TX_FRAME_CMD *cmd;
- osbuf = A_NETBUF_ALLOC(optIEDataLen + sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, (optIEDataLen + sizeof(*cmd)));
-
- cmd = (WMI_OPT_TX_FRAME_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, (optIEDataLen + sizeof(*cmd)-1));
-
- cmd->frmType = frmType;
- cmd->optIEDataLen = optIEDataLen;
- //cmd->optIEData = (u8 *)((int)cmd + sizeof(*cmd));
- memcpy(cmd->bssid, bssid, sizeof(cmd->bssid));
- memcpy(cmd->dstAddr, dstMacAddr, sizeof(cmd->dstAddr));
- memcpy(&cmd->optIEData[0], optIEData, optIEDataLen);
-
- return (wmi_cmd_send(wmip, osbuf, WMI_OPT_TX_FRAME_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_adhoc_bconIntvl_cmd(struct wmi_t *wmip, u16 intvl)
-{
- void *osbuf;
- WMI_BEACON_INT_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_BEACON_INT_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->beaconInterval = intvl;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_BEACON_INT_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-
-int
-wmi_set_voice_pkt_size_cmd(struct wmi_t *wmip, u16 voicePktSize)
-{
- void *osbuf;
- WMI_SET_VOICE_PKT_SIZE_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_SET_VOICE_PKT_SIZE_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->voicePktSize = voicePktSize;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_VOICE_PKT_SIZE_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-
-int
-wmi_set_max_sp_len_cmd(struct wmi_t *wmip, u8 maxSPLen)
-{
- void *osbuf;
- WMI_SET_MAX_SP_LEN_CMD *cmd;
-
- /* maxSPLen is a two-bit value. If user trys to set anything
- * other than this, then its invalid
- */
- if(maxSPLen & ~0x03)
- return A_EINVAL;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_SET_MAX_SP_LEN_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->maxSPLen = maxSPLen;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_MAX_SP_LEN_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-u8 wmi_determine_userPriority(
- u8 *pkt,
- u32 layer2Pri)
-{
- u8 ipPri;
- iphdr *ipHdr = (iphdr *)pkt;
-
- /* Determine IPTOS priority */
- /*
- * IP Tos format :
- * (Refer Pg 57 WMM-test-plan-v1.2)
- * IP-TOS - 8bits
- * : DSCP(6-bits) ECN(2-bits)
- * : DSCP - P2 P1 P0 X X X
- * where (P2 P1 P0) form 802.1D
- */
- ipPri = ipHdr->ip_tos >> 5;
- ipPri &= 0x7;
-
- if ((layer2Pri & 0x7) > ipPri)
- return ((u8)layer2Pri & 0x7);
- else
- return ipPri;
-}
-
-u8 convert_userPriority_to_trafficClass(u8 userPriority)
-{
- return (up_to_ac[userPriority & 0x7]);
-}
-
-u8 wmi_get_power_mode_cmd(struct wmi_t *wmip)
-{
- return wmip->wmi_powerMode;
-}
-
-int
-wmi_verify_tspec_params(WMI_CREATE_PSTREAM_CMD *pCmd, int tspecCompliance)
-{
- int ret = 0;
-
-#define TSPEC_SUSPENSION_INTERVAL_ATHEROS_DEF (~0)
-#define TSPEC_SERVICE_START_TIME_ATHEROS_DEF 0
-#define TSPEC_MAX_BURST_SIZE_ATHEROS_DEF 0
-#define TSPEC_DELAY_BOUND_ATHEROS_DEF 0
-#define TSPEC_MEDIUM_TIME_ATHEROS_DEF 0
-#define TSPEC_SBA_ATHEROS_DEF 0x2000 /* factor is 1 */
-
- /* Verify TSPEC params for ATHEROS compliance */
- if(tspecCompliance == ATHEROS_COMPLIANCE) {
- if ((pCmd->suspensionInt != TSPEC_SUSPENSION_INTERVAL_ATHEROS_DEF) ||
- (pCmd->serviceStartTime != TSPEC_SERVICE_START_TIME_ATHEROS_DEF) ||
- (pCmd->minDataRate != pCmd->meanDataRate) ||
- (pCmd->minDataRate != pCmd->peakDataRate) ||
- (pCmd->maxBurstSize != TSPEC_MAX_BURST_SIZE_ATHEROS_DEF) ||
- (pCmd->delayBound != TSPEC_DELAY_BOUND_ATHEROS_DEF) ||
- (pCmd->sba != TSPEC_SBA_ATHEROS_DEF) ||
- (pCmd->mediumTime != TSPEC_MEDIUM_TIME_ATHEROS_DEF)) {
-
- A_DPRINTF(DBG_WMI, (DBGFMT "Invalid TSPEC params\n", DBGARG));
- //A_PRINTF("%s: Invalid TSPEC params\n", __func__);
- ret = A_EINVAL;
- }
- }
-
- return ret;
-}
-
-#ifdef CONFIG_HOST_TCMD_SUPPORT
-static int
-wmi_tcmd_test_report_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- ar6000_testmode_rx_report_event(wmip->wmi_devt, datap, len);
-
- return 0;
-}
-
-#endif /* CONFIG_HOST_TCMD_SUPPORT*/
-
-int
-wmi_set_authmode_cmd(struct wmi_t *wmip, u8 mode)
-{
- void *osbuf;
- WMI_SET_AUTH_MODE_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_SET_AUTH_MODE_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->mode = mode;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_AUTH_MODE_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_reassocmode_cmd(struct wmi_t *wmip, u8 mode)
-{
- void *osbuf;
- WMI_SET_REASSOC_MODE_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_SET_REASSOC_MODE_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->mode = mode;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_REASSOC_MODE_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_lpreamble_cmd(struct wmi_t *wmip, u8 status, u8 preamblePolicy)
-{
- void *osbuf;
- WMI_SET_LPREAMBLE_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_SET_LPREAMBLE_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->status = status;
- cmd->preamblePolicy = preamblePolicy;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_LPREAMBLE_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_rts_cmd(struct wmi_t *wmip, u16 threshold)
-{
- void *osbuf;
- WMI_SET_RTS_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_SET_RTS_CMD*)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->threshold = threshold;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_RTS_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_wmm_cmd(struct wmi_t *wmip, WMI_WMM_STATUS status)
-{
- void *osbuf;
- WMI_SET_WMM_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_SET_WMM_CMD*)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->status = status;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_WMM_CMDID,
- NO_SYNC_WMIFLAG));
-
-}
-
-int
-wmi_set_qos_supp_cmd(struct wmi_t *wmip, u8 status)
-{
- void *osbuf;
- WMI_SET_QOS_SUPP_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_SET_QOS_SUPP_CMD*)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->status = status;
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_QOS_SUPP_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-
-int
-wmi_set_wmm_txop(struct wmi_t *wmip, WMI_TXOP_CFG cfg)
-{
- void *osbuf;
- WMI_SET_WMM_TXOP_CMD *cmd;
-
- if( !((cfg == WMI_TXOP_DISABLED) || (cfg == WMI_TXOP_ENABLED)) )
- return A_EINVAL;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_SET_WMM_TXOP_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->txopEnable = cfg;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_WMM_TXOP_CMDID,
- NO_SYNC_WMIFLAG));
-
-}
-
-int
-wmi_set_country(struct wmi_t *wmip, u8 *countryCode)
-{
- void *osbuf;
- WMI_AP_SET_COUNTRY_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_AP_SET_COUNTRY_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- memcpy(cmd->countryCode,countryCode,3);
-
- return (wmi_cmd_send(wmip, osbuf, WMI_AP_SET_COUNTRY_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-#ifdef CONFIG_HOST_TCMD_SUPPORT
-/* WMI layer doesn't need to know the data type of the test cmd.
- This would be beneficial for customers like Qualcomm, who might
- have different test command requirements from different manufacturers
- */
-int
-wmi_test_cmd(struct wmi_t *wmip, u8 *buf, u32 len)
-{
- void *osbuf;
- char *data;
-
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
-
- osbuf= A_NETBUF_ALLOC(len);
- if(osbuf == NULL)
- {
- return A_NO_MEMORY;
- }
- A_NETBUF_PUT(osbuf, len);
- data = A_NETBUF_DATA(osbuf);
- memcpy(data, buf, len);
-
- return(wmi_cmd_send(wmip, osbuf, WMI_TEST_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-#endif
-
-int
-wmi_set_bt_status_cmd(struct wmi_t *wmip, u8 streamType, u8 status)
-{
- void *osbuf;
- WMI_SET_BT_STATUS_CMD *cmd;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("Enter - streamType=%d, status=%d\n", streamType, status));
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_SET_BT_STATUS_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->streamType = streamType;
- cmd->status = status;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_BT_STATUS_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_bt_params_cmd(struct wmi_t *wmip, WMI_SET_BT_PARAMS_CMD* cmd)
-{
- void *osbuf;
- WMI_SET_BT_PARAMS_CMD* alloc_cmd;
-
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("cmd params is %d\n", cmd->paramType));
-
- if (cmd->paramType == BT_PARAM_SCO) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("sco params %d %d %d %d %d %d %d %d %d %d %d %d\n", cmd->info.scoParams.numScoCyclesForceTrigger,
- cmd->info.scoParams.dataResponseTimeout,
- cmd->info.scoParams.stompScoRules,
- cmd->info.scoParams.scoOptFlags,
- cmd->info.scoParams.stompDutyCyleVal,
- cmd->info.scoParams.stompDutyCyleMaxVal,
- cmd->info.scoParams.psPollLatencyFraction,
- cmd->info.scoParams.noSCOSlots,
- cmd->info.scoParams.noIdleSlots,
- cmd->info.scoParams.scoOptOffRssi,
- cmd->info.scoParams.scoOptOnRssi,
- cmd->info.scoParams.scoOptRtsCount));
- }
- else if (cmd->paramType == BT_PARAM_A2DP) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("A2DP params %d %d %d %d %d %d %d %d\n", cmd->info.a2dpParams.a2dpWlanUsageLimit,
- cmd->info.a2dpParams.a2dpBurstCntMin,
- cmd->info.a2dpParams.a2dpDataRespTimeout,
- cmd->info.a2dpParams.a2dpOptFlags,
- cmd->info.a2dpParams.isCoLocatedBtRoleMaster,
- cmd->info.a2dpParams.a2dpOptOffRssi,
- cmd->info.a2dpParams.a2dpOptOnRssi,
- cmd->info.a2dpParams.a2dpOptRtsCount));
- }
- else if (cmd->paramType == BT_PARAM_ANTENNA_CONFIG) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("Ant config %d\n", cmd->info.antType));
- }
- else if (cmd->paramType == BT_PARAM_COLOCATED_BT_DEVICE) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("co-located BT %d\n", cmd->info.coLocatedBtDev));
- }
- else if (cmd->paramType == BT_PARAM_ACLCOEX) {
- AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("ACL params %d %d %d\n", cmd->info.aclCoexParams.aclWlanMediumUsageTime,
- cmd->info.aclCoexParams.aclBtMediumUsageTime,
- cmd->info.aclCoexParams.aclDataRespTimeout));
- }
- else if (cmd->paramType == BT_PARAM_11A_SEPARATE_ANT) {
- A_DPRINTF(DBG_WMI, (DBGFMT "11A ant\n", DBGARG));
- }
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- alloc_cmd = (WMI_SET_BT_PARAMS_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(alloc_cmd, sizeof(*cmd));
- memcpy(alloc_cmd, cmd, sizeof(*cmd));
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_BT_PARAMS_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_btcoex_fe_ant_cmd(struct wmi_t *wmip, WMI_SET_BTCOEX_FE_ANT_CMD * cmd)
-{
- void *osbuf;
- WMI_SET_BTCOEX_FE_ANT_CMD *alloc_cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
- alloc_cmd = (WMI_SET_BTCOEX_FE_ANT_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(alloc_cmd, sizeof(*cmd));
- memcpy(alloc_cmd,cmd,sizeof(WMI_SET_BTCOEX_FE_ANT_CMD));
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_BTCOEX_FE_ANT_CMDID,
- NO_SYNC_WMIFLAG));
-
-}
-
-
-int
-wmi_set_btcoex_colocated_bt_dev_cmd(struct wmi_t *wmip,
- WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMD * cmd)
-{
- void *osbuf;
- WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMD *alloc_cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
- alloc_cmd = (WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(alloc_cmd, sizeof(*cmd));
- memcpy(alloc_cmd,cmd,sizeof(WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMD));
- A_PRINTF("colocated bt = %d\n", alloc_cmd->btcoexCoLocatedBTdev);
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMDID,
- NO_SYNC_WMIFLAG));
-
-}
-
-int
-wmi_set_btcoex_btinquiry_page_config_cmd(struct wmi_t *wmip,
- WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG_CMD* cmd)
-{
- void *osbuf;
- WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG_CMD *alloc_cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
- alloc_cmd = (WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(alloc_cmd, sizeof(*cmd));
- memcpy(alloc_cmd,cmd,sizeof(WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG_CMD));
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG_CMDID,
- NO_SYNC_WMIFLAG));
-
-}
-
-int
-wmi_set_btcoex_sco_config_cmd(struct wmi_t *wmip,
- WMI_SET_BTCOEX_SCO_CONFIG_CMD * cmd)
-{
- void *osbuf;
- WMI_SET_BTCOEX_SCO_CONFIG_CMD *alloc_cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
- alloc_cmd = (WMI_SET_BTCOEX_SCO_CONFIG_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(alloc_cmd, sizeof(*cmd));
- memcpy(alloc_cmd,cmd,sizeof(WMI_SET_BTCOEX_SCO_CONFIG_CMD));
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_BTCOEX_SCO_CONFIG_CMDID ,
- NO_SYNC_WMIFLAG));
-
-}
-
-int
-wmi_set_btcoex_a2dp_config_cmd(struct wmi_t *wmip,
- WMI_SET_BTCOEX_A2DP_CONFIG_CMD * cmd)
-{
- void *osbuf;
- WMI_SET_BTCOEX_A2DP_CONFIG_CMD *alloc_cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
- alloc_cmd = (WMI_SET_BTCOEX_A2DP_CONFIG_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(alloc_cmd, sizeof(*cmd));
- memcpy(alloc_cmd,cmd,sizeof(WMI_SET_BTCOEX_A2DP_CONFIG_CMD));
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_BTCOEX_A2DP_CONFIG_CMDID ,
- NO_SYNC_WMIFLAG));
-
-}
-
-int
-wmi_set_btcoex_aclcoex_config_cmd(struct wmi_t *wmip,
- WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMD * cmd)
-{
- void *osbuf;
- WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMD *alloc_cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
- alloc_cmd = (WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(alloc_cmd, sizeof(*cmd));
- memcpy(alloc_cmd,cmd,sizeof(WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMD));
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMDID ,
- NO_SYNC_WMIFLAG));
-
-}
-
-int
-wmi_set_btcoex_debug_cmd(struct wmi_t *wmip, WMI_SET_BTCOEX_DEBUG_CMD * cmd)
-{
- void *osbuf;
- WMI_SET_BTCOEX_DEBUG_CMD *alloc_cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
- alloc_cmd = (WMI_SET_BTCOEX_DEBUG_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(alloc_cmd, sizeof(*cmd));
- memcpy(alloc_cmd,cmd,sizeof(WMI_SET_BTCOEX_DEBUG_CMD));
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_BTCOEX_DEBUG_CMDID ,
- NO_SYNC_WMIFLAG));
-
-}
-
-int
-wmi_set_btcoex_bt_operating_status_cmd(struct wmi_t * wmip,
- WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMD * cmd)
-{
- void *osbuf;
- WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMD *alloc_cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
- alloc_cmd = (WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(alloc_cmd, sizeof(*cmd));
- memcpy(alloc_cmd,cmd,sizeof(WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMD));
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMDID ,
- NO_SYNC_WMIFLAG));
-
-}
-
-int
-wmi_get_btcoex_config_cmd(struct wmi_t * wmip, WMI_GET_BTCOEX_CONFIG_CMD * cmd)
-{
- void *osbuf;
- WMI_GET_BTCOEX_CONFIG_CMD *alloc_cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
- alloc_cmd = (WMI_GET_BTCOEX_CONFIG_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(alloc_cmd, sizeof(*cmd));
- memcpy(alloc_cmd,cmd,sizeof(WMI_GET_BTCOEX_CONFIG_CMD));
- return (wmi_cmd_send(wmip, osbuf, WMI_GET_BTCOEX_CONFIG_CMDID ,
- NO_SYNC_WMIFLAG));
-
-}
-
-int
-wmi_get_btcoex_stats_cmd(struct wmi_t *wmip)
-{
-
- return wmi_simple_cmd(wmip, WMI_GET_BTCOEX_STATS_CMDID);
-
-}
-
-int
-wmi_get_keepalive_configured(struct wmi_t *wmip)
-{
- void *osbuf;
- WMI_GET_KEEPALIVE_CMD *cmd;
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
- cmd = (WMI_GET_KEEPALIVE_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- return (wmi_cmd_send(wmip, osbuf, WMI_GET_KEEPALIVE_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-u8 wmi_get_keepalive_cmd(struct wmi_t *wmip)
-{
- return wmip->wmi_keepaliveInterval;
-}
-
-int
-wmi_set_keepalive_cmd(struct wmi_t *wmip, u8 keepaliveInterval)
-{
- void *osbuf;
- WMI_SET_KEEPALIVE_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_SET_KEEPALIVE_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->keepaliveInterval = keepaliveInterval;
- wmip->wmi_keepaliveInterval = keepaliveInterval;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_KEEPALIVE_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_params_cmd(struct wmi_t *wmip, u32 opcode, u32 length, char *buffer)
-{
- void *osbuf;
- WMI_SET_PARAMS_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd) + length);
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd) + length);
-
- cmd = (WMI_SET_PARAMS_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->opcode = opcode;
- cmd->length = length;
- memcpy(cmd->buffer, buffer, length);
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_PARAMS_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-
-int
-wmi_set_mcast_filter_cmd(struct wmi_t *wmip, u8 dot1, u8 dot2, u8 dot3, u8 dot4)
-{
- void *osbuf;
- WMI_SET_MCAST_FILTER_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_SET_MCAST_FILTER_CMD *)(A_NETBUF_DATA(osbuf));
- cmd->multicast_mac[0] = 0x01;
- cmd->multicast_mac[1] = 0x00;
- cmd->multicast_mac[2] = 0x5e;
- cmd->multicast_mac[3] = dot2&0x7F;
- cmd->multicast_mac[4] = dot3;
- cmd->multicast_mac[5] = dot4;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_MCAST_FILTER_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-
-int
-wmi_del_mcast_filter_cmd(struct wmi_t *wmip, u8 dot1, u8 dot2, u8 dot3, u8 dot4)
-{
- void *osbuf;
- WMI_SET_MCAST_FILTER_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_SET_MCAST_FILTER_CMD *)(A_NETBUF_DATA(osbuf));
- cmd->multicast_mac[0] = 0x01;
- cmd->multicast_mac[1] = 0x00;
- cmd->multicast_mac[2] = 0x5e;
- cmd->multicast_mac[3] = dot2&0x7F;
- cmd->multicast_mac[4] = dot3;
- cmd->multicast_mac[5] = dot4;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_DEL_MCAST_FILTER_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_mcast_filter_cmd(struct wmi_t *wmip, u8 enable)
-{
- void *osbuf;
- WMI_MCAST_FILTER_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_MCAST_FILTER_CMD *)(A_NETBUF_DATA(osbuf));
- cmd->enable = enable;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_MCAST_FILTER_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_appie_cmd(struct wmi_t *wmip, u8 mgmtFrmType, u8 ieLen,
- u8 *ieInfo)
-{
- void *osbuf;
- WMI_SET_APPIE_CMD *cmd;
- u16 cmdLen;
-
- cmdLen = sizeof(*cmd) + ieLen - 1;
- osbuf = A_NETBUF_ALLOC(cmdLen);
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, cmdLen);
-
- cmd = (WMI_SET_APPIE_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, cmdLen);
-
- cmd->mgmtFrmType = mgmtFrmType;
- cmd->ieLen = ieLen;
- memcpy(cmd->ieInfo, ieInfo, ieLen);
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_APPIE_CMDID, NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_halparam_cmd(struct wmi_t *wmip, u8 *cmd, u16 dataLen)
-{
- void *osbuf;
- u8 *data;
-
- osbuf = A_NETBUF_ALLOC(dataLen);
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, dataLen);
-
- data = A_NETBUF_DATA(osbuf);
-
- memcpy(data, cmd, dataLen);
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_WHALPARAM_CMDID, NO_SYNC_WMIFLAG));
-}
-
-s32 wmi_get_rate(s8 rateindex)
-{
- if (rateindex == RATE_AUTO) {
- return 0;
- } else {
- return(wmi_rateTable[(u32) rateindex][0]);
- }
-}
-
-void
-wmi_node_return (struct wmi_t *wmip, bss_t *bss)
-{
- if (NULL != bss)
- {
- wlan_node_return (&wmip->wmi_scan_table, bss);
- }
-}
-
-void
-wmi_set_nodeage(struct wmi_t *wmip, u32 nodeAge)
-{
- wlan_set_nodeage(&wmip->wmi_scan_table,nodeAge);
-}
-
-bss_t *
-wmi_find_Ssidnode (struct wmi_t *wmip, u8 *pSsid,
- u32 ssidLength, bool bIsWPA2, bool bMatchSSID)
-{
- bss_t *node = NULL;
- node = wlan_find_Ssidnode (&wmip->wmi_scan_table, pSsid,
- ssidLength, bIsWPA2, bMatchSSID);
- return node;
-}
-
-
-#ifdef THREAD_X
-void
-wmi_refresh_scan_table (struct wmi_t *wmip)
-{
- wlan_refresh_inactive_nodes (&wmip->wmi_scan_table);
-}
-#endif
-
-void
-wmi_free_allnodes(struct wmi_t *wmip)
-{
- wlan_free_allnodes(&wmip->wmi_scan_table);
-}
-
-bss_t *
-wmi_find_node(struct wmi_t *wmip, const u8 *macaddr)
-{
- bss_t *ni=NULL;
- ni=wlan_find_node(&wmip->wmi_scan_table,macaddr);
- return ni;
-}
-
-void
-wmi_free_node(struct wmi_t *wmip, const u8 *macaddr)
-{
- bss_t *ni=NULL;
-
- ni=wlan_find_node(&wmip->wmi_scan_table,macaddr);
- if (ni != NULL) {
- wlan_node_reclaim(&wmip->wmi_scan_table, ni);
- }
-
- return;
-}
-
-int
-wmi_dset_open_reply(struct wmi_t *wmip,
- u32 status,
- u32 access_cookie,
- u32 dset_size,
- u32 dset_version,
- u32 targ_handle,
- u32 targ_reply_fn,
- u32 targ_reply_arg)
-{
- void *osbuf;
- WMIX_DSETOPEN_REPLY_CMD *open_reply;
-
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter - wmip=0x%lx\n", DBGARG, (unsigned long)wmip));
-
- osbuf = A_NETBUF_ALLOC(sizeof(*open_reply));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*open_reply));
- open_reply = (WMIX_DSETOPEN_REPLY_CMD *)(A_NETBUF_DATA(osbuf));
-
- open_reply->status = status;
- open_reply->targ_dset_handle = targ_handle;
- open_reply->targ_reply_fn = targ_reply_fn;
- open_reply->targ_reply_arg = targ_reply_arg;
- open_reply->access_cookie = access_cookie;
- open_reply->size = dset_size;
- open_reply->version = dset_version;
-
- return (wmi_cmd_send_xtnd(wmip, osbuf, WMIX_DSETOPEN_REPLY_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-static int
-wmi_get_pmkid_list_event_rx(struct wmi_t *wmip, u8 *datap, u32 len)
-{
- WMI_PMKID_LIST_REPLY *reply;
- u32 expected_len;
-
- if (len < sizeof(WMI_PMKID_LIST_REPLY)) {
- return A_EINVAL;
- }
- reply = (WMI_PMKID_LIST_REPLY *)datap;
- expected_len = sizeof(reply->numPMKID) + reply->numPMKID * WMI_PMKID_LEN;
-
- if (len < expected_len) {
- return A_EINVAL;
- }
-
- A_WMI_PMKID_LIST_EVENT(wmip->wmi_devt, reply->numPMKID,
- reply->pmkidList, reply->bssidList[0]);
-
- return 0;
-}
-
-
-static int
-wmi_set_params_event_rx(struct wmi_t *wmip, u8 *datap, u32 len)
-{
- WMI_SET_PARAMS_REPLY *reply;
-
- if (len < sizeof(WMI_SET_PARAMS_REPLY)) {
- return A_EINVAL;
- }
- reply = (WMI_SET_PARAMS_REPLY *)datap;
-
- if (0 == reply->status)
- {
-
- }
- else
- {
-
- }
-
- return 0;
-}
-
-
-#ifdef CONFIG_HOST_DSET_SUPPORT
-int
-wmi_dset_data_reply(struct wmi_t *wmip,
- u32 status,
- u8 *user_buf,
- u32 length,
- u32 targ_buf,
- u32 targ_reply_fn,
- u32 targ_reply_arg)
-{
- void *osbuf;
- WMIX_DSETDATA_REPLY_CMD *data_reply;
- u32 size;
-
- size = sizeof(*data_reply) + length;
-
- if (size <= length) {
- return A_ERROR;
- }
-
- A_DPRINTF(DBG_WMI,
- (DBGFMT "Enter - length=%d status=%d\n", DBGARG, length, status));
-
- osbuf = A_NETBUF_ALLOC(size);
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
- A_NETBUF_PUT(osbuf, size);
- data_reply = (WMIX_DSETDATA_REPLY_CMD *)(A_NETBUF_DATA(osbuf));
-
- data_reply->status = status;
- data_reply->targ_buf = targ_buf;
- data_reply->targ_reply_fn = targ_reply_fn;
- data_reply->targ_reply_arg = targ_reply_arg;
- data_reply->length = length;
-
- if (status == 0) {
- if (a_copy_from_user(data_reply->buf, user_buf, length)) {
- A_NETBUF_FREE(osbuf);
- return A_ERROR;
- }
- }
-
- return (wmi_cmd_send_xtnd(wmip, osbuf, WMIX_DSETDATA_REPLY_CMDID,
- NO_SYNC_WMIFLAG));
-}
-#endif /* CONFIG_HOST_DSET_SUPPORT */
-
-int
-wmi_set_wsc_status_cmd(struct wmi_t *wmip, u32 status)
-{
- void *osbuf;
- char *cmd;
-
- wps_enable = status;
-
- osbuf = a_netbuf_alloc(sizeof(1));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- a_netbuf_put(osbuf, sizeof(1));
-
- cmd = (char *)(a_netbuf_to_data(osbuf));
-
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd[0] = (status?1:0);
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_WSC_STATUS_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-#if defined(CONFIG_TARGET_PROFILE_SUPPORT)
-int
-wmi_prof_cfg_cmd(struct wmi_t *wmip,
- u32 period,
- u32 nbins)
-{
- void *osbuf;
- WMIX_PROF_CFG_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMIX_PROF_CFG_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->period = period;
- cmd->nbins = nbins;
-
- return (wmi_cmd_send_xtnd(wmip, osbuf, WMIX_PROF_CFG_CMDID, NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_prof_addr_set_cmd(struct wmi_t *wmip, u32 addr)
-{
- void *osbuf;
- WMIX_PROF_ADDR_SET_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMIX_PROF_ADDR_SET_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->addr = addr;
-
- return (wmi_cmd_send_xtnd(wmip, osbuf, WMIX_PROF_ADDR_SET_CMDID, NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_prof_start_cmd(struct wmi_t *wmip)
-{
- return wmi_simple_cmd_xtnd(wmip, WMIX_PROF_START_CMDID);
-}
-
-int
-wmi_prof_stop_cmd(struct wmi_t *wmip)
-{
- return wmi_simple_cmd_xtnd(wmip, WMIX_PROF_STOP_CMDID);
-}
-
-int
-wmi_prof_count_get_cmd(struct wmi_t *wmip)
-{
- return wmi_simple_cmd_xtnd(wmip, WMIX_PROF_COUNT_GET_CMDID);
-}
-
-/* Called to handle WMIX_PROF_CONT_EVENTID */
-static int
-wmi_prof_count_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMIX_PROF_COUNT_EVENT *prof_data = (WMIX_PROF_COUNT_EVENT *)datap;
-
- A_DPRINTF(DBG_WMI,
- (DBGFMT "Enter - addr=0x%x count=%d\n", DBGARG,
- prof_data->addr, prof_data->count));
-
- A_WMI_PROF_COUNT_RX(prof_data->addr, prof_data->count);
-
- return 0;
-}
-#endif /* CONFIG_TARGET_PROFILE_SUPPORT */
-
-#ifdef OS_ROAM_MANAGEMENT
-
-#define ETHERNET_MAC_ADDRESS_LENGTH 6
-
-void
-wmi_scan_indication (struct wmi_t *wmip)
-{
- struct ieee80211_node_table *nt;
- u32 gen;
- u32 size;
- u32 bsssize;
- bss_t *bss;
- u32 numbss;
- PNDIS_802_11_BSSID_SCAN_INFO psi;
- PBYTE pie;
- NDIS_802_11_FIXED_IEs *pFixed;
- NDIS_802_11_VARIABLE_IEs *pVar;
- u32 RateSize;
-
- struct ar6kScanIndication
- {
- NDIS_802_11_STATUS_INDICATION ind;
- NDIS_802_11_BSSID_SCAN_INFO_LIST slist;
- } *pAr6kScanIndEvent;
-
- nt = &wmip->wmi_scan_table;
-
- ++nt->nt_si_gen;
-
-
- gen = nt->nt_si_gen;
-
- size = offsetof(struct ar6kScanIndication, slist) +
- offsetof(NDIS_802_11_BSSID_SCAN_INFO_LIST, BssidScanInfo);
-
- numbss = 0;
-
- IEEE80211_NODE_LOCK(nt);
-
- //calc size
- for (bss = nt->nt_node_first; bss; bss = bss->ni_list_next) {
- if (bss->ni_si_gen != gen) {
- bsssize = offsetof(NDIS_802_11_BSSID_SCAN_INFO, Bssid) + offsetof(NDIS_WLAN_BSSID_EX, IEs);
- bsssize = bsssize + sizeof(NDIS_802_11_FIXED_IEs);
-
-#ifdef SUPPORT_WPA2
- if (bss->ni_cie.ie_rsn) {
- bsssize = bsssize + bss->ni_cie.ie_rsn[1] + 2;
- }
-#endif
- if (bss->ni_cie.ie_wpa) {
- bsssize = bsssize + bss->ni_cie.ie_wpa[1] + 2;
- }
-
- // bsssize must be a multiple of 4 to maintain alignment.
- bsssize = (bsssize + 3) & ~3;
-
- size += bsssize;
-
- numbss++;
- }
- }
-
- if (0 == numbss)
- {
-// RETAILMSG(1, (L"AR6K: scan indication: 0 bss\n"));
- ar6000_scan_indication (wmip->wmi_devt, NULL, 0);
- IEEE80211_NODE_UNLOCK (nt);
- return;
- }
-
- pAr6kScanIndEvent = A_MALLOC(size);
-
- if (NULL == pAr6kScanIndEvent)
- {
- IEEE80211_NODE_UNLOCK(nt);
- return;
- }
-
- A_MEMZERO(pAr6kScanIndEvent, size);
-
- //copy data
- pAr6kScanIndEvent->ind.StatusType = Ndis802_11StatusType_BssidScanInfoList;
- pAr6kScanIndEvent->slist.Version = 1;
- pAr6kScanIndEvent->slist.NumItems = numbss;
-
- psi = &pAr6kScanIndEvent->slist.BssidScanInfo[0];
-
- for (bss = nt->nt_node_first; bss; bss = bss->ni_list_next) {
- if (bss->ni_si_gen != gen) {
-
- bss->ni_si_gen = gen;
-
- //Set scan time
- psi->ScanTime = bss->ni_tstamp - WLAN_NODE_INACT_TIMEOUT_MSEC;
-
- // Copy data to bssid_ex
- bsssize = offsetof(NDIS_WLAN_BSSID_EX, IEs);
- bsssize = bsssize + sizeof(NDIS_802_11_FIXED_IEs);
-
-#ifdef SUPPORT_WPA2
- if (bss->ni_cie.ie_rsn) {
- bsssize = bsssize + bss->ni_cie.ie_rsn[1] + 2;
- }
-#endif
- if (bss->ni_cie.ie_wpa) {
- bsssize = bsssize + bss->ni_cie.ie_wpa[1] + 2;
- }
-
- // bsssize must be a multiple of 4 to maintain alignment.
- bsssize = (bsssize + 3) & ~3;
-
- psi->Bssid.Length = bsssize;
-
- memcpy (psi->Bssid.MacAddress, bss->ni_macaddr, ETHERNET_MAC_ADDRESS_LENGTH);
-
-
-//if (((bss->ni_macaddr[3] == 0xCE) && (bss->ni_macaddr[4] == 0xF0) && (bss->ni_macaddr[5] == 0xE7)) ||
-// ((bss->ni_macaddr[3] == 0x03) && (bss->ni_macaddr[4] == 0xE2) && (bss->ni_macaddr[5] == 0x70)))
-// RETAILMSG (1, (L"%x\n",bss->ni_macaddr[5]));
-
- psi->Bssid.Ssid.SsidLength = 0;
- pie = bss->ni_cie.ie_ssid;
-
- if (pie) {
- // Format of SSID IE is:
- // Type (1 octet)
- // Length (1 octet)
- // SSID (Length octets)
- //
- // Validation of the IE should have occurred within WMI.
- //
- if (pie[1] <= 32) {
- psi->Bssid.Ssid.SsidLength = pie[1];
- memcpy(psi->Bssid.Ssid.Ssid, &pie[2], psi->Bssid.Ssid.SsidLength);
- }
- }
- psi->Bssid.Privacy = (bss->ni_cie.ie_capInfo & 0x10) ? 1 : 0;
-
- //Post the RSSI value relative to the Standard Noise floor value.
- psi->Bssid.Rssi = bss->ni_rssi;
-
- if (bss->ni_cie.ie_chan >= 2412 && bss->ni_cie.ie_chan <= 2484) {
-
- if (bss->ni_cie.ie_rates && bss->ni_cie.ie_xrates) {
- psi->Bssid.NetworkTypeInUse = Ndis802_11OFDM24;
- }
- else {
- psi->Bssid.NetworkTypeInUse = Ndis802_11DS;
- }
- }
- else {
- psi->Bssid.NetworkTypeInUse = Ndis802_11OFDM5;
- }
-
- psi->Bssid.Configuration.Length = sizeof(psi->Bssid.Configuration);
- psi->Bssid.Configuration.BeaconPeriod = bss->ni_cie.ie_beaconInt; // Units are Kmicroseconds (1024 us)
- psi->Bssid.Configuration.ATIMWindow = 0;
- psi->Bssid.Configuration.DSConfig = bss->ni_cie.ie_chan * 1000;
- psi->Bssid.InfrastructureMode = ((bss->ni_cie.ie_capInfo & 0x03) == 0x01 ) ? Ndis802_11Infrastructure : Ndis802_11IBSS;
-
- RateSize = 0;
- pie = bss->ni_cie.ie_rates;
- if (pie) {
- RateSize = (pie[1] < NDIS_802_11_LENGTH_RATES_EX) ? pie[1] : NDIS_802_11_LENGTH_RATES_EX;
- memcpy(psi->Bssid.SupportedRates, &pie[2], RateSize);
- }
- pie = bss->ni_cie.ie_xrates;
- if (pie && RateSize < NDIS_802_11_LENGTH_RATES_EX) {
- memcpy(psi->Bssid.SupportedRates + RateSize, &pie[2],
- (pie[1] < (NDIS_802_11_LENGTH_RATES_EX - RateSize)) ? pie[1] : (NDIS_802_11_LENGTH_RATES_EX - RateSize));
- }
-
- // Copy the fixed IEs
- psi->Bssid.IELength = sizeof(NDIS_802_11_FIXED_IEs);
-
- pFixed = (NDIS_802_11_FIXED_IEs *)psi->Bssid.IEs;
- memcpy(pFixed->Timestamp, bss->ni_cie.ie_tstamp, sizeof(pFixed->Timestamp));
- pFixed->BeaconInterval = bss->ni_cie.ie_beaconInt;
- pFixed->Capabilities = bss->ni_cie.ie_capInfo;
-
- // Copy selected variable IEs
-
- pVar = (NDIS_802_11_VARIABLE_IEs *)((PBYTE)pFixed + sizeof(NDIS_802_11_FIXED_IEs));
-
-#ifdef SUPPORT_WPA2
- // Copy the WPAv2 IE
- if (bss->ni_cie.ie_rsn) {
- pie = bss->ni_cie.ie_rsn;
- psi->Bssid.IELength += pie[1] + 2;
- memcpy(pVar, pie, pie[1] + 2);
- pVar = (NDIS_802_11_VARIABLE_IEs *)((PBYTE)pVar + pie[1] + 2);
- }
-#endif
- // Copy the WPAv1 IE
- if (bss->ni_cie.ie_wpa) {
- pie = bss->ni_cie.ie_wpa;
- psi->Bssid.IELength += pie[1] + 2;
- memcpy(pVar, pie, pie[1] + 2);
- pVar = (NDIS_802_11_VARIABLE_IEs *)((PBYTE)pVar + pie[1] + 2);
- }
-
- // Advance buffer pointer
- psi = (PNDIS_802_11_BSSID_SCAN_INFO)((BYTE*)psi + bsssize + FIELD_OFFSET(NDIS_802_11_BSSID_SCAN_INFO, Bssid));
- }
- }
-
- IEEE80211_NODE_UNLOCK(nt);
-
-// wmi_free_allnodes(wmip);
-
-// RETAILMSG(1, (L"AR6K: scan indication: %u bss\n", numbss));
-
- ar6000_scan_indication (wmip->wmi_devt, pAr6kScanIndEvent, size);
-
- kfree(pAr6kScanIndEvent);
-}
-#endif
-
-u8 ar6000_get_upper_threshold(s16 rssi, SQ_THRESHOLD_PARAMS *sq_thresh,
- u32 size)
-{
- u32 index;
- u8 threshold = (u8)sq_thresh->upper_threshold[size - 1];
-
- /* The list is already in sorted order. Get the next lower value */
- for (index = 0; index < size; index ++) {
- if (rssi < sq_thresh->upper_threshold[index]) {
- threshold = (u8)sq_thresh->upper_threshold[index];
- break;
- }
- }
-
- return threshold;
-}
-
-u8 ar6000_get_lower_threshold(s16 rssi, SQ_THRESHOLD_PARAMS *sq_thresh,
- u32 size)
-{
- u32 index;
- u8 threshold = (u8)sq_thresh->lower_threshold[size - 1];
-
- /* The list is already in sorted order. Get the next lower value */
- for (index = 0; index < size; index ++) {
- if (rssi > sq_thresh->lower_threshold[index]) {
- threshold = (u8)sq_thresh->lower_threshold[index];
- break;
- }
- }
-
- return threshold;
-}
-static int
-wmi_send_rssi_threshold_params(struct wmi_t *wmip,
- WMI_RSSI_THRESHOLD_PARAMS_CMD *rssiCmd)
-{
- void *osbuf;
- s8 size;
- WMI_RSSI_THRESHOLD_PARAMS_CMD *cmd;
-
- size = sizeof (*cmd);
-
- osbuf = A_NETBUF_ALLOC(size);
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, size);
-
- cmd = (WMI_RSSI_THRESHOLD_PARAMS_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, size);
- memcpy(cmd, rssiCmd, sizeof(WMI_RSSI_THRESHOLD_PARAMS_CMD));
-
- return (wmi_cmd_send(wmip, osbuf, WMI_RSSI_THRESHOLD_PARAMS_CMDID,
- NO_SYNC_WMIFLAG));
-}
-static int
-wmi_send_snr_threshold_params(struct wmi_t *wmip,
- WMI_SNR_THRESHOLD_PARAMS_CMD *snrCmd)
-{
- void *osbuf;
- s8 size;
- WMI_SNR_THRESHOLD_PARAMS_CMD *cmd;
-
- size = sizeof (*cmd);
-
- osbuf = A_NETBUF_ALLOC(size);
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, size);
- cmd = (WMI_SNR_THRESHOLD_PARAMS_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, size);
- memcpy(cmd, snrCmd, sizeof(WMI_SNR_THRESHOLD_PARAMS_CMD));
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SNR_THRESHOLD_PARAMS_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_target_event_report_cmd(struct wmi_t *wmip, WMI_SET_TARGET_EVENT_REPORT_CMD* cmd)
-{
- void *osbuf;
- WMI_SET_TARGET_EVENT_REPORT_CMD* alloc_cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- alloc_cmd = (WMI_SET_TARGET_EVENT_REPORT_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(alloc_cmd, sizeof(*cmd));
- memcpy(alloc_cmd, cmd, sizeof(*cmd));
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_TARGET_EVENT_REPORT_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-bss_t *wmi_rm_current_bss (struct wmi_t *wmip, u8 *id)
-{
- wmi_get_current_bssid (wmip, id);
- return wlan_node_remove (&wmip->wmi_scan_table, id);
-}
-
-int wmi_add_current_bss (struct wmi_t *wmip, u8 *id, bss_t *bss)
-{
- wlan_setup_node (&wmip->wmi_scan_table, bss, id);
- return 0;
-}
-
-static int
-wmi_addba_req_event_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_ADDBA_REQ_EVENT *cmd = (WMI_ADDBA_REQ_EVENT *)datap;
-
- A_WMI_AGGR_RECV_ADDBA_REQ_EVT(wmip->wmi_devt, cmd);
-
- return 0;
-}
-
-
-static int
-wmi_addba_resp_event_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_ADDBA_RESP_EVENT *cmd = (WMI_ADDBA_RESP_EVENT *)datap;
-
- A_WMI_AGGR_RECV_ADDBA_RESP_EVT(wmip->wmi_devt, cmd);
-
- return 0;
-}
-
-static int
-wmi_delba_req_event_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_DELBA_EVENT *cmd = (WMI_DELBA_EVENT *)datap;
-
- A_WMI_AGGR_RECV_DELBA_REQ_EVT(wmip->wmi_devt, cmd);
-
- return 0;
-}
-
-int
-wmi_btcoex_config_event_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
-
- A_WMI_BTCOEX_CONFIG_EVENT(wmip->wmi_devt, datap, len);
-
- return 0;
-}
-
-
-int
-wmi_btcoex_stats_event_rx(struct wmi_t * wmip,u8 *datap,int len)
-{
- A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
-
- A_WMI_BTCOEX_STATS_EVENT(wmip->wmi_devt, datap, len);
-
- return 0;
-
-}
-
-static int
-wmi_hci_event_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_HCI_EVENT *cmd = (WMI_HCI_EVENT *)datap;
- A_WMI_HCI_EVENT_EVT(wmip->wmi_devt, cmd);
-
- return 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//// ////
-//// AP mode functions ////
-//// ////
-////////////////////////////////////////////////////////////////////////////////
-/*
- * IOCTL: AR6000_XIOCTL_AP_COMMIT_CONFIG
- *
- * When AR6K in AP mode, This command will be called after
- * changing ssid, channel etc. It will pass the profile to
- * target with a flag which will indicate which parameter changed,
- * also if this flag is 0, there was no change in parametes, so
- * commit cmd will not be sent to target. Without calling this IOCTL
- * the changes will not take effect.
- */
-int
-wmi_ap_profile_commit(struct wmi_t *wmip, WMI_CONNECT_CMD *p)
-{
- void *osbuf;
- WMI_CONNECT_CMD *cm;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cm));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cm));
- cm = (WMI_CONNECT_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cm, sizeof(*cm));
-
- memcpy(cm,p,sizeof(*cm));
-
- return (wmi_cmd_send(wmip, osbuf, WMI_AP_CONFIG_COMMIT_CMDID, NO_SYNC_WMIFLAG));
-}
-
-/*
- * IOCTL: AR6000_XIOCTL_AP_HIDDEN_SSID
- *
- * This command will be used to enable/disable hidden ssid functioanlity of
- * beacon. If it is enabled, ssid will be NULL in beacon.
- */
-int
-wmi_ap_set_hidden_ssid(struct wmi_t *wmip, u8 hidden_ssid)
-{
- void *osbuf;
- WMI_AP_HIDDEN_SSID_CMD *hs;
-
- osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_HIDDEN_SSID_CMD));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(WMI_AP_HIDDEN_SSID_CMD));
- hs = (WMI_AP_HIDDEN_SSID_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(hs, sizeof(*hs));
-
- hs->hidden_ssid = hidden_ssid;
-
- A_DPRINTF(DBG_WMI, (DBGFMT "AR6000_XIOCTL_AP_HIDDEN_SSID %d\n", DBGARG , hidden_ssid));
- return (wmi_cmd_send(wmip, osbuf, WMI_AP_HIDDEN_SSID_CMDID, NO_SYNC_WMIFLAG));
-}
-
-/*
- * IOCTL: AR6000_XIOCTL_AP_SET_MAX_NUM_STA
- *
- * This command is used to limit max num of STA that can connect
- * with this AP. This value should not exceed AP_MAX_NUM_STA (this
- * is max num of STA supported by AP). Value was already validated
- * in ioctl.c
- */
-int
-wmi_ap_set_num_sta(struct wmi_t *wmip, u8 num_sta)
-{
- void *osbuf;
- WMI_AP_SET_NUM_STA_CMD *ns;
-
- osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_SET_NUM_STA_CMD));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(WMI_AP_SET_NUM_STA_CMD));
- ns = (WMI_AP_SET_NUM_STA_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(ns, sizeof(*ns));
-
- ns->num_sta = num_sta;
-
- A_DPRINTF(DBG_WMI, (DBGFMT "AR6000_XIOCTL_AP_SET_MAX_NUM_STA %d\n", DBGARG , num_sta));
- return (wmi_cmd_send(wmip, osbuf, WMI_AP_SET_NUM_STA_CMDID, NO_SYNC_WMIFLAG));
-}
-
-/*
- * IOCTL: AR6000_XIOCTL_AP_SET_ACL_MAC
- *
- * This command is used to send list of mac of STAs which will
- * be allowed to connect with this AP. When this list is empty
- * firware will allow all STAs till the count reaches AP_MAX_NUM_STA.
- */
-int
-wmi_ap_acl_mac_list(struct wmi_t *wmip, WMI_AP_ACL_MAC_CMD *acl)
-{
- void *osbuf;
- WMI_AP_ACL_MAC_CMD *a;
-
- osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_ACL_MAC_CMD));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(WMI_AP_ACL_MAC_CMD));
- a = (WMI_AP_ACL_MAC_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(a, sizeof(*a));
- memcpy(a,acl,sizeof(*acl));
-
- return (wmi_cmd_send(wmip, osbuf, WMI_AP_ACL_MAC_LIST_CMDID, NO_SYNC_WMIFLAG));
-}
-
-/*
- * IOCTL: AR6000_XIOCTL_AP_SET_MLME
- *
- * This command is used to send list of mac of STAs which will
- * be allowed to connect with this AP. When this list is empty
- * firware will allow all STAs till the count reaches AP_MAX_NUM_STA.
- */
-int
-wmi_ap_set_mlme(struct wmi_t *wmip, u8 cmd, u8 *mac, u16 reason)
-{
- void *osbuf;
- WMI_AP_SET_MLME_CMD *mlme;
-
- osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_SET_MLME_CMD));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(WMI_AP_SET_MLME_CMD));
- mlme = (WMI_AP_SET_MLME_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(mlme, sizeof(*mlme));
-
- mlme->cmd = cmd;
- memcpy(mlme->mac, mac, ATH_MAC_LEN);
- mlme->reason = reason;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_AP_SET_MLME_CMDID, NO_SYNC_WMIFLAG));
-}
-
-static int
-wmi_pspoll_event_rx(struct wmi_t *wmip, u8 *datap, int len)
-{
- WMI_PSPOLL_EVENT *ev;
-
- if (len < sizeof(WMI_PSPOLL_EVENT)) {
- return A_EINVAL;
- }
- ev = (WMI_PSPOLL_EVENT *)datap;
-
- A_WMI_PSPOLL_EVENT(wmip->wmi_devt, ev->aid);
- return 0;
-}
-
-static int
-wmi_dtimexpiry_event_rx(struct wmi_t *wmip, u8 *datap,int len)
-{
- A_WMI_DTIMEXPIRY_EVENT(wmip->wmi_devt);
- return 0;
-}
-
-#ifdef WAPI_ENABLE
-static int
-wmi_wapi_rekey_event_rx(struct wmi_t *wmip, u8 *datap,int len)
-{
- u8 *ev;
-
- if (len < 7) {
- return A_EINVAL;
- }
- ev = (u8 *)datap;
-
- A_WMI_WAPI_REKEY_EVENT(wmip->wmi_devt, *ev, &ev[1]);
- return 0;
-}
-#endif
-
-int
-wmi_set_pvb_cmd(struct wmi_t *wmip, u16 aid, bool flag)
-{
- WMI_AP_SET_PVB_CMD *cmd;
- void *osbuf = NULL;
-
- osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_SET_PVB_CMD));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(WMI_AP_SET_PVB_CMD));
- cmd = (WMI_AP_SET_PVB_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
-
- cmd->aid = aid;
- cmd->flag = flag;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_AP_SET_PVB_CMDID, NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_ap_conn_inact_time(struct wmi_t *wmip, u32 period)
-{
- WMI_AP_CONN_INACT_CMD *cmd;
- void *osbuf = NULL;
-
- osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_CONN_INACT_CMD));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(WMI_AP_CONN_INACT_CMD));
- cmd = (WMI_AP_CONN_INACT_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
-
- cmd->period = period;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_AP_CONN_INACT_CMDID, NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_ap_bgscan_time(struct wmi_t *wmip, u32 period, u32 dwell)
-{
- WMI_AP_PROT_SCAN_TIME_CMD *cmd;
- void *osbuf = NULL;
-
- osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_PROT_SCAN_TIME_CMD));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(WMI_AP_PROT_SCAN_TIME_CMD));
- cmd = (WMI_AP_PROT_SCAN_TIME_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
-
- cmd->period_min = period;
- cmd->dwell_ms = dwell;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_AP_PROT_SCAN_TIME_CMDID, NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_ap_set_dtim(struct wmi_t *wmip, u8 dtim)
-{
- WMI_AP_SET_DTIM_CMD *cmd;
- void *osbuf = NULL;
-
- osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_SET_DTIM_CMD));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(WMI_AP_SET_DTIM_CMD));
- cmd = (WMI_AP_SET_DTIM_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
-
- cmd->dtim = dtim;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_AP_SET_DTIM_CMDID, NO_SYNC_WMIFLAG));
-}
-
-/*
- * IOCTL: AR6000_XIOCTL_AP_SET_ACL_POLICY
- *
- * This command is used to set ACL policay. While changing policy, if you
- * want to retain the existing MAC addresses in the ACL list, policy should be
- * OR with AP_ACL_RETAIN_LIST_MASK, else the existing list will be cleared.
- * If there is no chage in policy, the list will be intact.
- */
-int
-wmi_ap_set_acl_policy(struct wmi_t *wmip, u8 policy)
-{
- void *osbuf;
- WMI_AP_ACL_POLICY_CMD *po;
-
- osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_ACL_POLICY_CMD));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
-}
-
- A_NETBUF_PUT(osbuf, sizeof(WMI_AP_ACL_POLICY_CMD));
- po = (WMI_AP_ACL_POLICY_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(po, sizeof(*po));
-
- po->policy = policy;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_AP_ACL_POLICY_CMDID, NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_ap_set_rateset(struct wmi_t *wmip, u8 rateset)
-{
- void *osbuf;
- WMI_AP_SET_11BG_RATESET_CMD *rs;
-
- osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_SET_11BG_RATESET_CMD));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(WMI_AP_SET_11BG_RATESET_CMD));
- rs = (WMI_AP_SET_11BG_RATESET_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(rs, sizeof(*rs));
-
- rs->rateset = rateset;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_AP_SET_11BG_RATESET_CMDID, NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_ht_cap_cmd(struct wmi_t *wmip, WMI_SET_HT_CAP_CMD *cmd)
-{
- void *osbuf;
- WMI_SET_HT_CAP_CMD *htCap;
- u8 band;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*htCap));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*htCap));
-
- band = (cmd->band)? A_BAND_5GHZ : A_BAND_24GHZ;
- wmip->wmi_ht_allowed[band] = (cmd->enable)? 1:0;
-
- htCap = (WMI_SET_HT_CAP_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(htCap, sizeof(*htCap));
- memcpy(htCap, cmd, sizeof(*htCap));
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_HT_CAP_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_ht_op_cmd(struct wmi_t *wmip, u8 sta_chan_width)
-{
- void *osbuf;
- WMI_SET_HT_OP_CMD *htInfo;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*htInfo));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*htInfo));
-
- htInfo = (WMI_SET_HT_OP_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(htInfo, sizeof(*htInfo));
- htInfo->sta_chan_width = sta_chan_width;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_HT_OP_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_tx_select_rates_cmd(struct wmi_t *wmip, u32 *pMaskArray)
-{
- void *osbuf;
- WMI_SET_TX_SELECT_RATES_CMD *pData;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*pData));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*pData));
-
- pData = (WMI_SET_TX_SELECT_RATES_CMD *)(A_NETBUF_DATA(osbuf));
- memcpy(pData, pMaskArray, sizeof(*pData));
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_TX_SELECT_RATES_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-
-int
-wmi_send_hci_cmd(struct wmi_t *wmip, u8 *buf, u16 sz)
-{
- void *osbuf;
- WMI_HCI_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd) + sz);
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd) + sz);
- cmd = (WMI_HCI_CMD *)(A_NETBUF_DATA(osbuf));
-
- cmd->cmd_buf_sz = sz;
- memcpy(cmd->buf, buf, sz);
- return (wmi_cmd_send(wmip, osbuf, WMI_HCI_CMD_CMDID, NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_allow_aggr_cmd(struct wmi_t *wmip, u16 tx_tidmask, u16 rx_tidmask)
-{
- void *osbuf;
- WMI_ALLOW_AGGR_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_ALLOW_AGGR_CMD *)(A_NETBUF_DATA(osbuf));
- cmd->tx_allow_aggr = tx_tidmask;
- cmd->rx_allow_aggr = rx_tidmask;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_ALLOW_AGGR_CMDID, NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_setup_aggr_cmd(struct wmi_t *wmip, u8 tid)
-{
- void *osbuf;
- WMI_ADDBA_REQ_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_ADDBA_REQ_CMD *)(A_NETBUF_DATA(osbuf));
- cmd->tid = tid;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_ADDBA_REQ_CMDID, NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_delete_aggr_cmd(struct wmi_t *wmip, u8 tid, bool uplink)
-{
- void *osbuf;
- WMI_DELBA_REQ_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_DELBA_REQ_CMD *)(A_NETBUF_DATA(osbuf));
- cmd->tid = tid;
- cmd->is_sender_initiator = uplink; /* uplink =1 - uplink direction, 0=downlink direction */
-
- /* Delete the local aggr state, on host */
- return (wmi_cmd_send(wmip, osbuf, WMI_DELBA_REQ_CMDID, NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_rx_frame_format_cmd(struct wmi_t *wmip, u8 rxMetaVersion,
- bool rxDot11Hdr, bool defragOnHost)
-{
- void *osbuf;
- WMI_RX_FRAME_FORMAT_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_RX_FRAME_FORMAT_CMD *)(A_NETBUF_DATA(osbuf));
- cmd->dot11Hdr = (rxDot11Hdr==true)? 1:0;
- cmd->defragOnHost = (defragOnHost==true)? 1:0;
- cmd->metaVersion = rxMetaVersion; /* */
-
- /* Delete the local aggr state, on host */
- return (wmi_cmd_send(wmip, osbuf, WMI_RX_FRAME_FORMAT_CMDID, NO_SYNC_WMIFLAG));
-}
-
-
-int
-wmi_set_thin_mode_cmd(struct wmi_t *wmip, bool bThinMode)
-{
- void *osbuf;
- WMI_SET_THIN_MODE_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_SET_THIN_MODE_CMD *)(A_NETBUF_DATA(osbuf));
- cmd->enable = (bThinMode==true)? 1:0;
-
- /* Delete the local aggr state, on host */
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_THIN_MODE_CMDID, NO_SYNC_WMIFLAG));
-}
-
-
-int
-wmi_set_wlan_conn_precedence_cmd(struct wmi_t *wmip, BT_WLAN_CONN_PRECEDENCE precedence)
-{
- void *osbuf;
- WMI_SET_BT_WLAN_CONN_PRECEDENCE *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_SET_BT_WLAN_CONN_PRECEDENCE *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->precedence = precedence;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_BT_WLAN_CONN_PRECEDENCE_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_pmk_cmd(struct wmi_t *wmip, u8 *pmk)
-{
- void *osbuf;
- WMI_SET_PMK_CMD *p;
-
- osbuf = A_NETBUF_ALLOC(sizeof(WMI_SET_PMK_CMD));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(WMI_SET_PMK_CMD));
-
- p = (WMI_SET_PMK_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(p, sizeof(*p));
-
- memcpy(p->pmk, pmk, WMI_PMK_LEN);
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_PMK_CMDID, NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_set_excess_tx_retry_thres_cmd(struct wmi_t *wmip, WMI_SET_EXCESS_TX_RETRY_THRES_CMD *cmd)
-{
- void *osbuf;
- WMI_SET_EXCESS_TX_RETRY_THRES_CMD *p;
-
- osbuf = A_NETBUF_ALLOC(sizeof(WMI_SET_EXCESS_TX_RETRY_THRES_CMD));
- if (osbuf == NULL) {
- return A_NO_MEMORY;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(WMI_SET_EXCESS_TX_RETRY_THRES_CMD));
-
- p = (WMI_SET_EXCESS_TX_RETRY_THRES_CMD *)(A_NETBUF_DATA(osbuf));
- memset(p, 0, sizeof(*p));
-
- p->threshold = cmd->threshold;
-
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_EXCESS_TX_RETRY_THRES_CMDID, NO_SYNC_WMIFLAG));
-}
-
-int
-wmi_SGI_cmd(struct wmi_t *wmip, u32 sgiMask, u8 sgiPERThreshold)
-{
- void *osbuf;
- WMI_SET_TX_SGI_PARAM_CMD *cmd;
-
- osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
- if (osbuf == NULL) {
- return A_NO_MEMORY ;
- }
-
- A_NETBUF_PUT(osbuf, sizeof(*cmd));
-
- cmd = (WMI_SET_TX_SGI_PARAM_CMD *)(A_NETBUF_DATA(osbuf));
- A_MEMZERO(cmd, sizeof(*cmd));
- cmd->sgiMask = sgiMask;
- cmd->sgiPERThreshold = sgiPERThreshold;
- return (wmi_cmd_send(wmip, osbuf, WMI_SET_TX_SGI_PARAM_CMDID,
- NO_SYNC_WMIFLAG));
-}
-
-bss_t *
-wmi_find_matching_Ssidnode (struct wmi_t *wmip, u8 *pSsid,
- u32 ssidLength,
- u32 dot11AuthMode, u32 authMode,
- u32 pairwiseCryptoType, u32 grpwiseCryptoTyp)
-{
- bss_t *node = NULL;
- node = wlan_find_matching_Ssidnode (&wmip->wmi_scan_table, pSsid,
- ssidLength, dot11AuthMode, authMode, pairwiseCryptoType, grpwiseCryptoTyp);
-
- return node;
-}
-
-u16 wmi_ieee2freq (int chan)
-{
- u16 freq = 0;
- freq = wlan_ieee2freq (chan);
- return freq;
-
-}
-
-u32 wmi_freq2ieee (u16 freq)
-{
- u16 chan = 0;
- chan = wlan_freq2ieee (freq);
- return chan;
-}
diff --git a/drivers/staging/ath6kl/wmi/wmi_host.h b/drivers/staging/ath6kl/wmi/wmi_host.h
deleted file mode 100644
index 53e4f085dfe6..000000000000
--- a/drivers/staging/ath6kl/wmi/wmi_host.h
+++ /dev/null
@@ -1,102 +0,0 @@
-//------------------------------------------------------------------------------
-// <copyright file="wmi_host.h" company="Atheros">
-// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
-//
-//
-// 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.
-//
-//
-//------------------------------------------------------------------------------
-//==============================================================================
-// This file contains local definitios for the wmi host module.
-//
-// Author(s): ="Atheros"
-//==============================================================================
-#ifndef _WMI_HOST_H_
-#define _WMI_HOST_H_
-
-#include "roaming.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct wmi_stats {
- u32 cmd_len_err;
- u32 cmd_id_err;
-};
-
-#define SSID_IE_LEN_INDEX 13
-
-/* Host side link management data structures */
-#define SIGNAL_QUALITY_THRESHOLD_LEVELS 6
-#define SIGNAL_QUALITY_UPPER_THRESHOLD_LEVELS SIGNAL_QUALITY_THRESHOLD_LEVELS
-#define SIGNAL_QUALITY_LOWER_THRESHOLD_LEVELS SIGNAL_QUALITY_THRESHOLD_LEVELS
-typedef struct sq_threshold_params_s {
- s16 upper_threshold[SIGNAL_QUALITY_UPPER_THRESHOLD_LEVELS];
- s16 lower_threshold[SIGNAL_QUALITY_LOWER_THRESHOLD_LEVELS];
- u32 upper_threshold_valid_count;
- u32 lower_threshold_valid_count;
- u32 polling_interval;
- u8 weight;
- u8 last_rssi; //normally you would expect this to be bss specific but we keep only one instance because its only valid when the device is in a connected state. Not sure if it belongs to host or target.
- u8 last_rssi_poll_event; //Not sure if it belongs to host or target
-} SQ_THRESHOLD_PARAMS;
-
-/*
- * These constants are used with A_WLAN_BAND_SET.
- */
-#define A_BAND_24GHZ 0
-#define A_BAND_5GHZ 1
-#define A_NUM_BANDS 2
-
-struct wmi_t {
- bool wmi_ready;
- bool wmi_numQoSStream;
- u16 wmi_streamExistsForAC[WMM_NUM_AC];
- u8 wmi_fatPipeExists;
- void *wmi_devt;
- struct wmi_stats wmi_stats;
- struct ieee80211_node_table wmi_scan_table;
- u8 wmi_bssid[ATH_MAC_LEN];
- u8 wmi_powerMode;
- u8 wmi_phyMode;
- u8 wmi_keepaliveInterval;
-#ifdef THREAD_X
- A_CSECT_T wmi_lock;
-#else
- A_MUTEX_T wmi_lock;
-#endif
- HTC_ENDPOINT_ID wmi_endpoint_id;
- SQ_THRESHOLD_PARAMS wmi_SqThresholdParams[SIGNAL_QUALITY_METRICS_NUM_MAX];
- CRYPTO_TYPE wmi_pair_crypto_type;
- CRYPTO_TYPE wmi_grp_crypto_type;
- bool wmi_is_wmm_enabled;
- u8 wmi_ht_allowed[A_NUM_BANDS];
- u8 wmi_traffic_class;
-};
-
-#ifdef THREAD_X
-#define INIT_WMI_LOCK(w) A_CSECT_INIT(&(w)->wmi_lock)
-#define LOCK_WMI(w) A_CSECT_ENTER(&(w)->wmi_lock);
-#define UNLOCK_WMI(w) A_CSECT_LEAVE(&(w)->wmi_lock);
-#define DELETE_WMI_LOCK(w) A_CSECT_DELETE(&(w)->wmi_lock);
-#else
-#define LOCK_WMI(w) A_MUTEX_LOCK(&(w)->wmi_lock);
-#define UNLOCK_WMI(w) A_MUTEX_UNLOCK(&(w)->wmi_lock);
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _WMI_HOST_H_ */
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c
index 05dada98eb6b..b1294017dd7b 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c
@@ -1437,7 +1437,7 @@ static struct net_device_ops brcmf_netdev_ops_pri = {
.ndo_do_ioctl = brcmf_netdev_ioctl_entry,
.ndo_start_xmit = brcmf_netdev_start_xmit,
.ndo_set_mac_address = brcmf_netdev_set_mac_address,
- .ndo_set_multicast_list = brcmf_netdev_set_multicast_list
+ .ndo_set_rx_mode = brcmf_netdev_set_multicast_list,
};
int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx)
diff --git a/drivers/staging/brcm80211/brcmsmac/mac80211_if.c b/drivers/staging/brcm80211/brcmsmac/mac80211_if.c
index d6de44e430d3..6d71cba3a0a5 100644
--- a/drivers/staging/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/staging/brcm80211/brcmsmac/mac80211_if.c
@@ -133,16 +133,19 @@ static int brcms_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
bool set);
static void brcms_ops_sw_scan_start(struct ieee80211_hw *hw);
static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw);
-static void brcms_ops_set_tsf(struct ieee80211_hw *hw, u64 tsf);
+static void brcms_ops_set_tsf(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u64 tsf);
static int brcms_ops_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats);
static void brcms_ops_sta_notify(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum sta_notify_cmd cmd,
struct ieee80211_sta *sta);
-static int brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue,
- const struct ieee80211_tx_queue_params *params);
-static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw);
+static int brcms_ops_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 queue,
+ const struct ieee80211_tx_queue_params *params);
+static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif);
static int brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
static int brcms_ops_sta_remove(struct ieee80211_hw *hw,
@@ -516,7 +519,8 @@ static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw)
return;
}
-static void brcms_ops_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+static void brcms_ops_set_tsf(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u64 tsf)
{
wiphy_err(hw->wiphy, "%s: Enter\n", __func__);
return;
@@ -553,7 +557,7 @@ brcms_ops_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
}
static int
-brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue,
+brcms_ops_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct brcms_info *wl = hw->priv;
@@ -565,7 +569,8 @@ brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue,
return 0;
}
-static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw)
+static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
{
wiphy_err(hw->wiphy, "%s: Enter\n", __func__);
return 0;
diff --git a/drivers/staging/brcm80211/brcmsmac/otp.c b/drivers/staging/brcm80211/brcmsmac/otp.c
index 34253cf37812..4a70180eba5d 100644
--- a/drivers/staging/brcm80211/brcmsmac/otp.c
+++ b/drivers/staging/brcm80211/brcmsmac/otp.c
@@ -16,6 +16,7 @@
#include <linux/io.h>
#include <linux/errno.h>
+#include <linux/string.h>
#include <brcm_hw_ids.h>
#include <chipcommon.h>
diff --git a/drivers/staging/brcm80211/brcmsmac/types.h b/drivers/staging/brcm80211/brcmsmac/types.h
index bbf21897ae0e..823b5e4672e2 100644
--- a/drivers/staging/brcm80211/brcmsmac/types.h
+++ b/drivers/staging/brcm80211/brcmsmac/types.h
@@ -18,6 +18,7 @@
#define _BRCM_TYPES_H_
#include <linux/types.h>
+#include <linux/io.h>
/* Bus types */
#define SI_BUS 0 /* SOC Interconnect */
diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c
index 6859af0778cf..7611def97d06 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.c
+++ b/drivers/staging/comedi/drivers/ni_labpc.c
@@ -241,8 +241,10 @@ static int labpc_eeprom_write_insn(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data);
static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd);
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_ISA_DMA_API
static unsigned int labpc_suggest_transfer_size(struct comedi_cmd cmd);
+#endif
+#ifdef CONFIG_COMEDI_PCI
static int labpc_find_device(struct comedi_device *dev, int bus, int slot);
#endif
static int labpc_dio_mem_callback(int dir, int port, int data,
diff --git a/drivers/staging/cxt1e1/Kconfig b/drivers/staging/cxt1e1/Kconfig
index 73430ef6ae2b..947f42a65c59 100644
--- a/drivers/staging/cxt1e1/Kconfig
+++ b/drivers/staging/cxt1e1/Kconfig
@@ -6,8 +6,7 @@ config CXT1E1
channelized stream WAN adapter card which contains a HDLC/Transparent
mode controller.
- If you want to compile this driver as a module
- say M here and read <file:Documentation/modules.txt>.
+ If you want to compile this driver as a module say M here.
The module will be called 'cxt1e1'.
If unsure, say N.
diff --git a/drivers/staging/et131x/et1310_tx.c b/drivers/staging/et131x/et1310_tx.c
index 8fb3051fe288..e4f51e64c7a8 100644
--- a/drivers/staging/et131x/et1310_tx.c
+++ b/drivers/staging/et131x/et1310_tx.c
@@ -519,12 +519,12 @@ static int nic_send_packet(struct et131x_adapter *etdev, struct tcb *tcb)
* returned by pci_map_page() is always 32-bit
* addressable (as defined by the pci/dma subsystem)
*/
- desc[frag++].addr_lo =
- pci_map_page(etdev->pdev,
- frags[i - 1].page,
- frags[i - 1].page_offset,
- frags[i - 1].size,
- PCI_DMA_TODEVICE);
+ desc[frag++].addr_lo = skb_frag_dma_map(
+ &etdev->pdev->dev,
+ &frags[i - 1],
+ 0,
+ frags[i - 1].size,
+ DMA_TO_DEVICE);
}
}
diff --git a/drivers/staging/et131x/et131x_netdev.c b/drivers/staging/et131x/et131x_netdev.c
index 5f25bbad36b6..4406630b0c6f 100644
--- a/drivers/staging/et131x/et131x_netdev.c
+++ b/drivers/staging/et131x/et131x_netdev.c
@@ -638,7 +638,7 @@ static const struct net_device_ops et131x_netdev_ops = {
.ndo_open = et131x_open,
.ndo_stop = et131x_close,
.ndo_start_xmit = et131x_tx,
- .ndo_set_multicast_list = et131x_multicast,
+ .ndo_set_rx_mode = et131x_multicast,
.ndo_tx_timeout = et131x_tx_timeout,
.ndo_change_mtu = et131x_change_mtu,
.ndo_set_mac_address = et131x_set_mac_addr,
diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c
index 61989f0d9f0d..4c7739f929ef 100644
--- a/drivers/staging/hv/netvsc_drv.c
+++ b/drivers/staging/hv/netvsc_drv.c
@@ -169,11 +169,11 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
/* Additional fragments are after SKB data */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- skb_frag_t *f = &skb_shinfo(skb)->frags[i];
+ const skb_frag_t *f = &skb_shinfo(skb)->frags[i];
- packet->page_buf[i+2].pfn = page_to_pfn(f->page);
+ packet->page_buf[i+2].pfn = page_to_pfn(skb_frag_page(f));
packet->page_buf[i+2].offset = f->page_offset;
- packet->page_buf[i+2].len = f->size;
+ packet->page_buf[i+2].len = skb_frag_size(f);
}
/* Set the completion routine */
@@ -307,7 +307,7 @@ static const struct net_device_ops device_ops = {
.ndo_open = netvsc_open,
.ndo_stop = netvsc_close,
.ndo_start_xmit = netvsc_start_xmit,
- .ndo_set_multicast_list = netvsc_set_multicast_list,
+ .ndo_set_rx_mode = netvsc_set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
diff --git a/drivers/staging/iio/addac/adt7316-i2c.c b/drivers/staging/iio/addac/adt7316-i2c.c
index 52d1ea349635..1c86cf11ab94 100644
--- a/drivers/staging/iio/addac/adt7316-i2c.c
+++ b/drivers/staging/iio/addac/adt7316-i2c.c
@@ -109,7 +109,7 @@ static int __devinit adt7316_i2c_probe(struct i2c_client *client,
static int __devexit adt7316_i2c_remove(struct i2c_client *client)
{
- return adt7316_remove(&client->dev);;
+ return adt7316_remove(&client->dev);
}
static const struct i2c_device_id adt7316_i2c_id[] = {
diff --git a/drivers/staging/iio/dds/ad9832.c b/drivers/staging/iio/dds/ad9832.c
index e3e61a469bb8..6f0efe6580e7 100644
--- a/drivers/staging/iio/dds/ad9832.c
+++ b/drivers/staging/iio/dds/ad9832.c
@@ -52,7 +52,7 @@ static int ad9832_write_frequency(struct ad9832_state *st,
((addr - 3) << ADD_SHIFT) |
((regval >> 0) & 0xFF));
- return spi_sync(st->spi, &st->freq_msg);;
+ return spi_sync(st->spi, &st->freq_msg);
}
static int ad9832_write_phase(struct ad9832_state *st,
diff --git a/drivers/staging/octeon/ethernet-rgmii.c b/drivers/staging/octeon/ethernet-rgmii.c
index 9c0d2936e486..c3d73f8431ae 100644
--- a/drivers/staging/octeon/ethernet-rgmii.c
+++ b/drivers/staging/octeon/ethernet-rgmii.c
@@ -26,6 +26,7 @@
**********************************************************************/
#include <linux/kernel.h>
#include <linux/netdevice.h>
+#include <linux/interrupt.h>
#include <linux/phy.h>
#include <linux/ratelimit.h>
#include <net/dst.h>
diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c
index 1a7c19ae766f..8b307b428791 100644
--- a/drivers/staging/octeon/ethernet-rx.c
+++ b/drivers/staging/octeon/ethernet-rx.c
@@ -411,7 +411,8 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget)
skb->protocol = eth_type_trans(skb, dev);
skb->dev = dev;
- if (unlikely(work->word2.s.not_IP || work->word2.s.IP_exc || work->word2.s.L4_error))
+ if (unlikely(work->word2.s.not_IP || work->word2.s.IP_exc ||
+ work->word2.s.L4_error || !work->word2.s.tcp_or_udp))
skb->ip_summed = CHECKSUM_NONE;
else
skb->ip_summed = CHECKSUM_UNNECESSARY;
diff --git a/drivers/staging/octeon/ethernet-spi.c b/drivers/staging/octeon/ethernet-spi.c
index 970825421884..d0e2d514968a 100644
--- a/drivers/staging/octeon/ethernet-spi.c
+++ b/drivers/staging/octeon/ethernet-spi.c
@@ -26,6 +26,7 @@
**********************************************************************/
#include <linux/kernel.h>
#include <linux/netdevice.h>
+#include <linux/interrupt.h>
#include <net/dst.h>
#include <asm/octeon/octeon.h>
diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c
index a8f780e95e0a..076f86675ce6 100644
--- a/drivers/staging/octeon/ethernet.c
+++ b/drivers/staging/octeon/ethernet.c
@@ -512,7 +512,7 @@ static const struct net_device_ops cvm_oct_npi_netdev_ops = {
.ndo_init = cvm_oct_common_init,
.ndo_uninit = cvm_oct_common_uninit,
.ndo_start_xmit = cvm_oct_xmit,
- .ndo_set_multicast_list = cvm_oct_common_set_multicast_list,
+ .ndo_set_rx_mode = cvm_oct_common_set_multicast_list,
.ndo_set_mac_address = cvm_oct_common_set_mac_address,
.ndo_do_ioctl = cvm_oct_ioctl,
.ndo_change_mtu = cvm_oct_common_change_mtu,
@@ -527,7 +527,7 @@ static const struct net_device_ops cvm_oct_xaui_netdev_ops = {
.ndo_open = cvm_oct_xaui_open,
.ndo_stop = cvm_oct_xaui_stop,
.ndo_start_xmit = cvm_oct_xmit,
- .ndo_set_multicast_list = cvm_oct_common_set_multicast_list,
+ .ndo_set_rx_mode = cvm_oct_common_set_multicast_list,
.ndo_set_mac_address = cvm_oct_common_set_mac_address,
.ndo_do_ioctl = cvm_oct_ioctl,
.ndo_change_mtu = cvm_oct_common_change_mtu,
@@ -542,7 +542,7 @@ static const struct net_device_ops cvm_oct_sgmii_netdev_ops = {
.ndo_open = cvm_oct_sgmii_open,
.ndo_stop = cvm_oct_sgmii_stop,
.ndo_start_xmit = cvm_oct_xmit,
- .ndo_set_multicast_list = cvm_oct_common_set_multicast_list,
+ .ndo_set_rx_mode = cvm_oct_common_set_multicast_list,
.ndo_set_mac_address = cvm_oct_common_set_mac_address,
.ndo_do_ioctl = cvm_oct_ioctl,
.ndo_change_mtu = cvm_oct_common_change_mtu,
@@ -555,7 +555,7 @@ static const struct net_device_ops cvm_oct_spi_netdev_ops = {
.ndo_init = cvm_oct_spi_init,
.ndo_uninit = cvm_oct_spi_uninit,
.ndo_start_xmit = cvm_oct_xmit,
- .ndo_set_multicast_list = cvm_oct_common_set_multicast_list,
+ .ndo_set_rx_mode = cvm_oct_common_set_multicast_list,
.ndo_set_mac_address = cvm_oct_common_set_mac_address,
.ndo_do_ioctl = cvm_oct_ioctl,
.ndo_change_mtu = cvm_oct_common_change_mtu,
@@ -570,7 +570,7 @@ static const struct net_device_ops cvm_oct_rgmii_netdev_ops = {
.ndo_open = cvm_oct_rgmii_open,
.ndo_stop = cvm_oct_rgmii_stop,
.ndo_start_xmit = cvm_oct_xmit,
- .ndo_set_multicast_list = cvm_oct_common_set_multicast_list,
+ .ndo_set_rx_mode = cvm_oct_common_set_multicast_list,
.ndo_set_mac_address = cvm_oct_common_set_mac_address,
.ndo_do_ioctl = cvm_oct_ioctl,
.ndo_change_mtu = cvm_oct_common_change_mtu,
@@ -582,7 +582,7 @@ static const struct net_device_ops cvm_oct_rgmii_netdev_ops = {
static const struct net_device_ops cvm_oct_pow_netdev_ops = {
.ndo_init = cvm_oct_common_init,
.ndo_start_xmit = cvm_oct_xmit_pow,
- .ndo_set_multicast_list = cvm_oct_common_set_multicast_list,
+ .ndo_set_rx_mode = cvm_oct_common_set_multicast_list,
.ndo_set_mac_address = cvm_oct_common_set_mac_address,
.ndo_do_ioctl = cvm_oct_ioctl,
.ndo_change_mtu = cvm_oct_common_change_mtu,
diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c
index 4c6651aac307..04c23919f4d6 100644
--- a/drivers/staging/rtl8187se/r8180_core.c
+++ b/drivers/staging/rtl8187se/r8180_core.c
@@ -3534,7 +3534,7 @@ static const struct net_device_ops rtl8180_netdev_ops = {
.ndo_get_stats = rtl8180_stats,
.ndo_tx_timeout = rtl8180_restart,
.ndo_do_ioctl = rtl8180_ioctl,
- .ndo_set_multicast_list = r8180_set_multicast,
+ .ndo_set_rx_mode = r8180_set_multicast,
.ndo_set_mac_address = r8180_set_mac_adr,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/staging/rtl8192e/r8192E_core.c b/drivers/staging/rtl8192e/r8192E_core.c
index 94d9c8d5d090..b418fed703c6 100644
--- a/drivers/staging/rtl8192e/r8192E_core.c
+++ b/drivers/staging/rtl8192e/r8192E_core.c
@@ -4519,7 +4519,7 @@ static const struct net_device_ops rtl8192_netdev_ops = {
.ndo_stop = rtl8192_close,
.ndo_tx_timeout = tx_timeout,
.ndo_do_ioctl = rtl8192_ioctl,
- .ndo_set_multicast_list = r8192_set_multicast,
+ .ndo_set_rx_mode = r8192_set_multicast,
.ndo_set_mac_address = r8192_set_mac_adr,
.ndo_start_xmit = ieee80211_rtl_xmit,
};
diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c
index ee86fe8509ed..c09be0a66467 100644
--- a/drivers/staging/rtl8192u/r8192U_core.c
+++ b/drivers/staging/rtl8192u/r8192U_core.c
@@ -5739,7 +5739,7 @@ static const struct net_device_ops rtl8192_netdev_ops = {
.ndo_get_stats = rtl8192_stats,
.ndo_tx_timeout = tx_timeout,
.ndo_do_ioctl = rtl8192_ioctl,
- .ndo_set_multicast_list = r8192_set_multicast,
+ .ndo_set_rx_mode = r8192_set_multicast,
.ndo_set_mac_address = r8192_set_mac_adr,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = eth_change_mtu,
diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c
index 18f11039bb5f..77a0751a31ad 100644
--- a/drivers/staging/slicoss/slicoss.c
+++ b/drivers/staging/slicoss/slicoss.c
@@ -3724,7 +3724,7 @@ static const struct net_device_ops slic_netdev_ops = {
.ndo_do_ioctl = slic_ioctl,
.ndo_set_mac_address = slic_mac_set_address,
.ndo_get_stats = slic_get_stats,
- .ndo_set_multicast_list = slic_mcast_set_list,
+ .ndo_set_rx_mode = slic_mcast_set_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = eth_change_mtu,
};
diff --git a/drivers/staging/tidspbridge/core/dsp-clock.c b/drivers/staging/tidspbridge/core/dsp-clock.c
index 589a0554332e..3d1279c424a8 100644
--- a/drivers/staging/tidspbridge/core/dsp-clock.c
+++ b/drivers/staging/tidspbridge/core/dsp-clock.c
@@ -209,7 +209,6 @@ int dsp_clk_enable(enum dsp_clk_id clk_id)
break;
#ifdef CONFIG_OMAP_MCBSP
case MCBSP_CLK:
- omap_mcbsp_set_io_type(MCBSP_ID(clk_id), OMAP_MCBSP_POLL_IO);
omap_mcbsp_request(MCBSP_ID(clk_id));
omap2_mcbsp_set_clks_src(MCBSP_ID(clk_id), MCBSP_CLKS_PAD_SRC);
break;
diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c
index 3d2a9ba16b15..8cb9116c44f8 100644
--- a/drivers/staging/vt6655/device_main.c
+++ b/drivers/staging/vt6655/device_main.c
@@ -911,7 +911,7 @@ static const struct net_device_ops device_netdev_ops = {
.ndo_do_ioctl = device_ioctl,
.ndo_get_stats = device_get_stats,
.ndo_start_xmit = device_xmit,
- .ndo_set_multicast_list = device_set_multi,
+ .ndo_set_rx_mode = device_set_multi,
};
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c
index e18efd43e3e0..1ff394074cba 100644
--- a/drivers/staging/vt6656/main_usb.c
+++ b/drivers/staging/vt6656/main_usb.c
@@ -753,7 +753,7 @@ static const struct net_device_ops device_netdev_ops = {
.ndo_do_ioctl = device_ioctl,
.ndo_get_stats = device_get_stats,
.ndo_start_xmit = device_xmit,
- .ndo_set_multicast_list = device_set_multi,
+ .ndo_set_rx_mode = device_set_multi,
};
static int __devinit
diff --git a/drivers/staging/winbond/wbusb.c b/drivers/staging/winbond/wbusb.c
index 3724e1e67ec2..a2e8bd452ed9 100644
--- a/drivers/staging/winbond/wbusb.c
+++ b/drivers/staging/winbond/wbusb.c
@@ -277,7 +277,7 @@ static int wbsoft_config(struct ieee80211_hw *dev, u32 changed)
return 0;
}
-static u64 wbsoft_get_tsf(struct ieee80211_hw *dev)
+static u64 wbsoft_get_tsf(struct ieee80211_hw *dev, struct ieee80211_vif *vif)
{
printk("wbsoft_get_tsf called\n");
return 0;
diff --git a/drivers/staging/wlags49_h2/wl_netdev.c b/drivers/staging/wlags49_h2/wl_netdev.c
index cf917e613f22..b21515ff678a 100644
--- a/drivers/staging/wlags49_h2/wl_netdev.c
+++ b/drivers/staging/wlags49_h2/wl_netdev.c
@@ -1179,7 +1179,7 @@ static const struct net_device_ops wl_netdev_ops =
.ndo_set_config = &wl_config,
.ndo_get_stats = &wl_stats,
- .ndo_set_multicast_list = &wl_multicast,
+ .ndo_set_rx_mode = &wl_multicast,
.ndo_init = &wl_insert,
.ndo_open = &wl_adapter_open,
diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c
index b0af292bc7e3..14bfeb2e704c 100644
--- a/drivers/staging/wlan-ng/p80211netdev.c
+++ b/drivers/staging/wlan-ng/p80211netdev.c
@@ -715,7 +715,7 @@ static const struct net_device_ops p80211_netdev_ops = {
.ndo_stop = p80211knetdev_stop,
.ndo_get_stats = p80211knetdev_get_stats,
.ndo_start_xmit = p80211knetdev_hard_start_xmit,
- .ndo_set_multicast_list = p80211knetdev_set_multicast_list,
+ .ndo_set_rx_mode = p80211knetdev_set_multicast_list,
.ndo_do_ioctl = p80211knetdev_do_ioctl,
.ndo_set_mac_address = p80211knetdev_set_mac_address,
.ndo_tx_timeout = p80211knetdev_tx_timeout,
diff --git a/drivers/staging/zcache/tmem.c b/drivers/staging/zcache/tmem.c
index 975e34bcd722..1ca66ea9b281 100644
--- a/drivers/staging/zcache/tmem.c
+++ b/drivers/staging/zcache/tmem.c
@@ -604,7 +604,7 @@ int tmem_get(struct tmem_pool *pool, struct tmem_oid *oidp, uint32_t index,
struct tmem_obj *obj;
void *pampd;
bool ephemeral = is_ephemeral(pool);
- uint32_t ret = -1;
+ int ret = -1;
struct tmem_hashbucket *hb;
bool free = (get_and_free == 1) || ((get_and_free == 0) && ephemeral);
bool lock_held = false;
diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c
index 855a5bb56a47..462fbc20561f 100644
--- a/drivers/staging/zcache/zcache-main.c
+++ b/drivers/staging/zcache/zcache-main.c
@@ -1158,7 +1158,7 @@ static void *zcache_pampd_create(char *data, size_t size, bool raw, int eph,
size_t clen;
int ret;
unsigned long count;
- struct page *page = virt_to_page(data);
+ struct page *page = (struct page *)(data);
struct zcache_client *cli = pool->client;
uint16_t client_id = get_client_id_from_client(cli);
unsigned long zv_mean_zsize;
@@ -1227,7 +1227,7 @@ static int zcache_pampd_get_data(char *data, size_t *bufsize, bool raw,
int ret = 0;
BUG_ON(is_ephemeral(pool));
- zv_decompress(virt_to_page(data), pampd);
+ zv_decompress((struct page *)(data), pampd);
return ret;
}
@@ -1242,7 +1242,7 @@ static int zcache_pampd_get_data_and_free(char *data, size_t *bufsize, bool raw,
int ret = 0;
BUG_ON(!is_ephemeral(pool));
- zbud_decompress(virt_to_page(data), pampd);
+ zbud_decompress((struct page *)(data), pampd);
zbud_free_and_delist((struct zbud_hdr *)pampd);
atomic_dec(&zcache_curr_eph_pampd_count);
return ret;
@@ -1539,7 +1539,7 @@ static int zcache_put_page(int cli_id, int pool_id, struct tmem_oid *oidp,
goto out;
if (!zcache_freeze && zcache_do_preload(pool) == 0) {
/* preload does preempt_disable on success */
- ret = tmem_put(pool, oidp, index, page_address(page),
+ ret = tmem_put(pool, oidp, index, (char *)(page),
PAGE_SIZE, 0, is_ephemeral(pool));
if (ret < 0) {
if (is_ephemeral(pool))
@@ -1572,7 +1572,7 @@ static int zcache_get_page(int cli_id, int pool_id, struct tmem_oid *oidp,
pool = zcache_get_pool_by_id(cli_id, pool_id);
if (likely(pool != NULL)) {
if (atomic_read(&pool->obj_count) > 0)
- ret = tmem_get(pool, oidp, index, page_address(page),
+ ret = tmem_get(pool, oidp, index, (char *)(page),
&size, 0, is_ephemeral(pool));
zcache_put_pool(pool);
}
diff --git a/drivers/target/Makefile b/drivers/target/Makefile
index 1060c7b7f803..62e54053bcd8 100644
--- a/drivers/target/Makefile
+++ b/drivers/target/Makefile
@@ -6,7 +6,6 @@ target_core_mod-y := target_core_configfs.o \
target_core_hba.o \
target_core_pr.o \
target_core_alua.o \
- target_core_scdb.o \
target_core_tmr.o \
target_core_tpg.o \
target_core_transport.o \
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index c24fb10de60b..4d01768fcd90 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -765,7 +765,7 @@ static int iscsit_allocate_iovecs(struct iscsi_cmd *cmd)
u32 iov_count = (cmd->se_cmd.t_data_nents == 0) ? 1 :
cmd->se_cmd.t_data_nents;
- iov_count += TRANSPORT_IOV_DATA_BUFFER;
+ iov_count += ISCSI_IOV_DATA_BUFFER;
cmd->iov_data = kzalloc(iov_count * sizeof(struct kvec), GFP_KERNEL);
if (!cmd->iov_data) {
@@ -2243,7 +2243,6 @@ static int iscsit_handle_snack(
case 0:
return iscsit_handle_recovery_datain_or_r2t(conn, buf,
hdr->itt, hdr->ttt, hdr->begrun, hdr->runlength);
- return 0;
case ISCSI_FLAG_SNACK_TYPE_STATUS:
return iscsit_handle_status_snack(conn, hdr->itt, hdr->ttt,
hdr->begrun, hdr->runlength);
@@ -3539,16 +3538,8 @@ get_immediate:
spin_lock_bh(&conn->cmd_lock);
list_del(&cmd->i_list);
spin_unlock_bh(&conn->cmd_lock);
- /*
- * Determine if a struct se_cmd is assoicated with
- * this struct iscsi_cmd.
- */
- if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) &&
- !(cmd->tmr_req))
- iscsit_release_cmd(cmd);
- else
- transport_generic_free_cmd(&cmd->se_cmd,
- 1, 0);
+
+ iscsit_free_cmd(cmd);
goto get_immediate;
case ISTATE_SEND_NOPIN_WANT_RESPONSE:
spin_unlock_bh(&cmd->istate_lock);
@@ -3941,7 +3932,6 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
{
struct iscsi_cmd *cmd = NULL, *cmd_tmp = NULL;
struct iscsi_session *sess = conn->sess;
- struct se_cmd *se_cmd;
/*
* We expect this function to only ever be called from either RX or TX
* thread context via iscsit_close_connection() once the other context
@@ -3949,35 +3939,13 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
*/
spin_lock_bh(&conn->cmd_lock);
list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_list) {
- if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD)) {
- list_del(&cmd->i_list);
- spin_unlock_bh(&conn->cmd_lock);
- iscsit_increment_maxcmdsn(cmd, sess);
- se_cmd = &cmd->se_cmd;
- /*
- * Special cases for active iSCSI TMR, and
- * transport_lookup_cmd_lun() failing from
- * iscsit_get_lun_for_cmd() in iscsit_handle_scsi_cmd().
- */
- if (cmd->tmr_req && se_cmd->transport_wait_for_tasks)
- se_cmd->transport_wait_for_tasks(se_cmd, 1, 1);
- else if (cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD)
- transport_release_cmd(se_cmd);
- else
- iscsit_release_cmd(cmd);
-
- spin_lock_bh(&conn->cmd_lock);
- continue;
- }
list_del(&cmd->i_list);
spin_unlock_bh(&conn->cmd_lock);
iscsit_increment_maxcmdsn(cmd, sess);
- se_cmd = &cmd->se_cmd;
- if (se_cmd->transport_wait_for_tasks)
- se_cmd->transport_wait_for_tasks(se_cmd, 1, 1);
+ iscsit_free_cmd(cmd);
spin_lock_bh(&conn->cmd_lock);
}
diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c
index 11fd74307811..beb39469e7f1 100644
--- a/drivers/target/iscsi/iscsi_target_auth.c
+++ b/drivers/target/iscsi/iscsi_target_auth.c
@@ -18,6 +18,7 @@
* GNU General Public License for more details.
******************************************************************************/
+#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/crypto.h>
#include <linux/err.h>
@@ -27,40 +28,11 @@
#include "iscsi_target_nego.h"
#include "iscsi_target_auth.h"
-static unsigned char chap_asciihex_to_binaryhex(unsigned char val[2])
-{
- unsigned char result = 0;
- /*
- * MSB
- */
- if ((val[0] >= 'a') && (val[0] <= 'f'))
- result = ((val[0] - 'a' + 10) & 0xf) << 4;
- else
- if ((val[0] >= 'A') && (val[0] <= 'F'))
- result = ((val[0] - 'A' + 10) & 0xf) << 4;
- else /* digit */
- result = ((val[0] - '0') & 0xf) << 4;
- /*
- * LSB
- */
- if ((val[1] >= 'a') && (val[1] <= 'f'))
- result |= ((val[1] - 'a' + 10) & 0xf);
- else
- if ((val[1] >= 'A') && (val[1] <= 'F'))
- result |= ((val[1] - 'A' + 10) & 0xf);
- else /* digit */
- result |= ((val[1] - '0') & 0xf);
-
- return result;
-}
-
static int chap_string_to_hex(unsigned char *dst, unsigned char *src, int len)
{
- int i, j = 0;
+ int j = DIV_ROUND_UP(len, 2);
- for (i = 0; i < len; i += 2) {
- dst[j++] = (unsigned char) chap_asciihex_to_binaryhex(&src[i]);
- }
+ hex2bin(dst, src, j);
dst[j] = '\0';
return j;
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index f095e65b1ccf..f1643dbf6a92 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -268,7 +268,7 @@ struct se_tpg_np *lio_target_call_addnptotpg(
ISCSI_TCP);
if (IS_ERR(tpg_np)) {
iscsit_put_tpg(tpg);
- return ERR_PTR(PTR_ERR(tpg_np));
+ return ERR_CAST(tpg_np);
}
pr_debug("LIO_Target_ConfigFS: addnptotpg done!\n");
@@ -1285,7 +1285,7 @@ struct se_wwn *lio_target_call_coreaddtiqn(
tiqn = iscsit_add_tiqn((unsigned char *)name);
if (IS_ERR(tiqn))
- return ERR_PTR(PTR_ERR(tiqn));
+ return ERR_CAST(tiqn);
/*
* Setup struct iscsi_wwn_stat_grps for se_wwn->fabric_stat_group.
*/
diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h
index 470ed551eeb5..3723d90d5ae5 100644
--- a/drivers/target/iscsi/iscsi_target_core.h
+++ b/drivers/target/iscsi/iscsi_target_core.h
@@ -57,6 +57,9 @@
#define TA_PROD_MODE_WRITE_PROTECT 0
#define TA_CACHE_CORE_NPS 0
+
+#define ISCSI_IOV_DATA_BUFFER 5
+
enum tpg_np_network_transport_table {
ISCSI_TCP = 0,
ISCSI_SCTP_TCP = 1,
@@ -425,7 +428,6 @@ struct iscsi_cmd {
/* Number of times struct iscsi_cmd is present in immediate queue */
atomic_t immed_queue_count;
atomic_t response_queue_count;
- atomic_t transport_sent;
spinlock_t datain_lock;
spinlock_t dataout_timeout_lock;
/* spinlock for protecting struct iscsi_cmd->i_state */
diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c
index 980650792cf6..c4c68da3e500 100644
--- a/drivers/target/iscsi/iscsi_target_erl1.c
+++ b/drivers/target/iscsi/iscsi_target_erl1.c
@@ -834,7 +834,7 @@ static int iscsit_attach_ooo_cmdsn(
*/
list_for_each_entry(ooo_tmp, &sess->sess_ooo_cmdsn_list,
ooo_list) {
- while (ooo_tmp->cmdsn < ooo_cmdsn->cmdsn)
+ if (ooo_tmp->cmdsn < ooo_cmdsn->cmdsn)
continue;
list_add(&ooo_cmdsn->ooo_list,
diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c
index 91a4d170bda4..0b8404c30125 100644
--- a/drivers/target/iscsi/iscsi_target_erl2.c
+++ b/drivers/target/iscsi/iscsi_target_erl2.c
@@ -143,12 +143,7 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess)
list_del(&cmd->i_list);
cmd->conn = NULL;
spin_unlock(&cr->conn_recovery_cmd_lock);
- if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
- !(cmd->se_cmd.transport_wait_for_tasks))
- iscsit_release_cmd(cmd);
- else
- cmd->se_cmd.transport_wait_for_tasks(
- &cmd->se_cmd, 1, 1);
+ iscsit_free_cmd(cmd);
spin_lock(&cr->conn_recovery_cmd_lock);
}
spin_unlock(&cr->conn_recovery_cmd_lock);
@@ -170,12 +165,7 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess)
list_del(&cmd->i_list);
cmd->conn = NULL;
spin_unlock(&cr->conn_recovery_cmd_lock);
- if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
- !(cmd->se_cmd.transport_wait_for_tasks))
- iscsit_release_cmd(cmd);
- else
- cmd->se_cmd.transport_wait_for_tasks(
- &cmd->se_cmd, 1, 1);
+ iscsit_free_cmd(cmd);
spin_lock(&cr->conn_recovery_cmd_lock);
}
spin_unlock(&cr->conn_recovery_cmd_lock);
@@ -260,12 +250,7 @@ void iscsit_discard_cr_cmds_by_expstatsn(
iscsit_remove_cmd_from_connection_recovery(cmd, sess);
spin_unlock(&cr->conn_recovery_cmd_lock);
- if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
- !(cmd->se_cmd.transport_wait_for_tasks))
- iscsit_release_cmd(cmd);
- else
- cmd->se_cmd.transport_wait_for_tasks(
- &cmd->se_cmd, 1, 0);
+ iscsit_free_cmd(cmd);
spin_lock(&cr->conn_recovery_cmd_lock);
}
spin_unlock(&cr->conn_recovery_cmd_lock);
@@ -319,12 +304,7 @@ int iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(struct iscsi_conn *conn)
list_del(&cmd->i_list);
spin_unlock_bh(&conn->cmd_lock);
- if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
- !(cmd->se_cmd.transport_wait_for_tasks))
- iscsit_release_cmd(cmd);
- else
- cmd->se_cmd.transport_wait_for_tasks(
- &cmd->se_cmd, 1, 1);
+ iscsit_free_cmd(cmd);
spin_lock_bh(&conn->cmd_lock);
}
spin_unlock_bh(&conn->cmd_lock);
@@ -377,13 +357,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
list_del(&cmd->i_list);
spin_unlock_bh(&conn->cmd_lock);
-
- if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
- !(cmd->se_cmd.transport_wait_for_tasks))
- iscsit_release_cmd(cmd);
- else
- cmd->se_cmd.transport_wait_for_tasks(
- &cmd->se_cmd, 1, 0);
+ iscsit_free_cmd(cmd);
spin_lock_bh(&conn->cmd_lock);
continue;
}
@@ -403,13 +377,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
(cmd->cmd_sn >= conn->sess->exp_cmd_sn)) {
list_del(&cmd->i_list);
spin_unlock_bh(&conn->cmd_lock);
-
- if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
- !(cmd->se_cmd.transport_wait_for_tasks))
- iscsit_release_cmd(cmd);
- else
- cmd->se_cmd.transport_wait_for_tasks(
- &cmd->se_cmd, 1, 1);
+ iscsit_free_cmd(cmd);
spin_lock_bh(&conn->cmd_lock);
continue;
}
@@ -434,10 +402,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
iscsit_free_all_datain_reqs(cmd);
- if ((cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) &&
- cmd->se_cmd.transport_wait_for_tasks)
- cmd->se_cmd.transport_wait_for_tasks(&cmd->se_cmd,
- 0, 0);
+ transport_wait_for_tasks(&cmd->se_cmd);
/*
* Add the struct iscsi_cmd to the connection recovery cmd list
*/
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index bcaf82f47037..daad362a93ce 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -1013,19 +1013,9 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
ISCSI_LOGIN_STATUS_TARGET_ERROR);
goto new_sess_out;
}
-#if 0
- if (!iscsi_ntop6((const unsigned char *)
- &sock_in6.sin6_addr.in6_u,
- (char *)&conn->ipv6_login_ip[0],
- IPV6_ADDRESS_SPACE)) {
- pr_err("iscsi_ntop6() failed\n");
- iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
- ISCSI_LOGIN_STATUS_TARGET_ERROR);
- goto new_sess_out;
- }
-#else
- pr_debug("Skipping iscsi_ntop6()\n");
-#endif
+ snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c",
+ &sock_in6.sin6_addr.in6_u);
+ conn->login_port = ntohs(sock_in6.sin6_port);
} else {
memset(&sock_in, 0, sizeof(struct sockaddr_in));
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
index 4d087ac11067..426cd4bf6a9a 100644
--- a/drivers/target/iscsi/iscsi_target_nego.c
+++ b/drivers/target/iscsi/iscsi_target_nego.c
@@ -504,7 +504,7 @@ static int iscsi_target_do_authentication(
break;
case 1:
pr_debug("iSCSI security negotiation"
- " completed sucessfully.\n");
+ " completed successfully.\n");
login->auth_complete = 1;
if ((login_req->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE1) &&
(login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)) {
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index 252e246cf51e..5b773160200f 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -545,13 +545,13 @@ int iscsi_copy_param_list(
struct iscsi_param_list *src_param_list,
int leading)
{
- struct iscsi_param *new_param = NULL, *param = NULL;
+ struct iscsi_param *param = NULL;
+ struct iscsi_param *new_param = NULL;
struct iscsi_param_list *param_list = NULL;
param_list = kzalloc(sizeof(struct iscsi_param_list), GFP_KERNEL);
if (!param_list) {
- pr_err("Unable to allocate memory for"
- " struct iscsi_param_list.\n");
+ pr_err("Unable to allocate memory for struct iscsi_param_list.\n");
goto err_out;
}
INIT_LIST_HEAD(&param_list->param_list);
@@ -567,8 +567,17 @@ int iscsi_copy_param_list(
new_param = kzalloc(sizeof(struct iscsi_param), GFP_KERNEL);
if (!new_param) {
- pr_err("Unable to allocate memory for"
- " struct iscsi_param.\n");
+ pr_err("Unable to allocate memory for struct iscsi_param.\n");
+ goto err_out;
+ }
+
+ new_param->name = kstrdup(param->name, GFP_KERNEL);
+ new_param->value = kstrdup(param->value, GFP_KERNEL);
+ if (!new_param->value || !new_param->name) {
+ kfree(new_param->value);
+ kfree(new_param->name);
+ kfree(new_param);
+ pr_err("Unable to allocate memory for parameter name/value.\n");
goto err_out;
}
@@ -580,32 +589,12 @@ int iscsi_copy_param_list(
new_param->use = param->use;
new_param->type_range = param->type_range;
- new_param->name = kzalloc(strlen(param->name) + 1, GFP_KERNEL);
- if (!new_param->name) {
- pr_err("Unable to allocate memory for"
- " parameter name.\n");
- goto err_out;
- }
-
- new_param->value = kzalloc(strlen(param->value) + 1,
- GFP_KERNEL);
- if (!new_param->value) {
- pr_err("Unable to allocate memory for"
- " parameter value.\n");
- goto err_out;
- }
-
- memcpy(new_param->name, param->name, strlen(param->name));
- new_param->name[strlen(param->name)] = '\0';
- memcpy(new_param->value, param->value, strlen(param->value));
- new_param->value[strlen(param->value)] = '\0';
-
list_add_tail(&new_param->p_list, &param_list->param_list);
}
- if (!list_empty(&param_list->param_list))
+ if (!list_empty(&param_list->param_list)) {
*dst_param_list = param_list;
- else {
+ } else {
pr_err("No parameters allocated.\n");
goto err_out;
}
@@ -1441,7 +1430,7 @@ static int iscsi_enforce_integrity_rules(
u8 DataSequenceInOrder = 0;
u8 ErrorRecoveryLevel = 0, SessionType = 0;
u8 IFMarker = 0, OFMarker = 0;
- u8 IFMarkInt_Reject = 0, OFMarkInt_Reject = 0;
+ u8 IFMarkInt_Reject = 1, OFMarkInt_Reject = 1;
u32 FirstBurstLength = 0, MaxBurstLength = 0;
struct iscsi_param *param = NULL;
diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c
index db1fe1ec84df..490207eacde9 100644
--- a/drivers/target/iscsi/iscsi_target_tmr.c
+++ b/drivers/target/iscsi/iscsi_target_tmr.c
@@ -250,7 +250,7 @@ static int iscsit_task_reassign_complete_write(
* so if we have received all DataOUT we can safety ignore Initiator.
*/
if (cmd->cmd_flags & ICF_GOT_LAST_DATAOUT) {
- if (!atomic_read(&cmd->transport_sent)) {
+ if (!atomic_read(&cmd->se_cmd.t_transport_sent)) {
pr_debug("WRITE ITT: 0x%08x: t_state: %d"
" never sent to transport\n",
cmd->init_task_tag, cmd->se_cmd.t_state);
@@ -314,11 +314,11 @@ static int iscsit_task_reassign_complete_read(
cmd->acked_data_sn = (tmr_req->exp_data_sn - 1);
}
- if (!atomic_read(&cmd->transport_sent)) {
+ if (!atomic_read(&cmd->se_cmd.t_transport_sent)) {
pr_debug("READ ITT: 0x%08x: t_state: %d never sent to"
" transport\n", cmd->init_task_tag,
cmd->se_cmd.t_state);
- transport_generic_handle_cdb(se_cmd);
+ transport_handle_cdb_direct(se_cmd);
return 0;
}
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index a1acb0167902..02348f727bd4 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -243,7 +243,7 @@ struct iscsi_cmd *iscsit_allocate_se_cmd_for_tmr(
if (!cmd->tmr_req) {
pr_err("Unable to allocate memory for"
" Task Management command!\n");
- return NULL;
+ goto out;
}
/*
* TASK_REASSIGN for ERL=2 / connection stays inside of
@@ -289,7 +289,8 @@ struct iscsi_cmd *iscsit_allocate_se_cmd_for_tmr(
}
se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd,
- (void *)cmd->tmr_req, tcm_function);
+ (void *)cmd->tmr_req, tcm_function,
+ GFP_KERNEL);
if (!se_cmd->se_tmr_req)
goto out;
@@ -298,8 +299,6 @@ struct iscsi_cmd *iscsit_allocate_se_cmd_for_tmr(
return cmd;
out:
iscsit_release_cmd(cmd);
- if (se_cmd)
- transport_free_se_cmd(se_cmd);
return NULL;
}
@@ -841,6 +840,23 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd)
kmem_cache_free(lio_cmd_cache, cmd);
}
+void iscsit_free_cmd(struct iscsi_cmd *cmd)
+{
+ /*
+ * Determine if a struct se_cmd is assoicated with
+ * this struct iscsi_cmd.
+ */
+ switch (cmd->iscsi_opcode) {
+ case ISCSI_OP_SCSI_CMD:
+ case ISCSI_OP_SCSI_TMFUNC:
+ transport_generic_free_cmd(&cmd->se_cmd, 1);
+ break;
+ default:
+ iscsit_release_cmd(cmd);
+ break;
+ }
+}
+
int iscsit_check_session_usage_count(struct iscsi_session *sess)
{
spin_lock_bh(&sess->session_usage_lock);
@@ -877,40 +893,6 @@ void iscsit_inc_session_usage_count(struct iscsi_session *sess)
}
/*
- * Used before iscsi_do[rx,tx]_data() to determine iov and [rx,tx]_marker
- * array counts needed for sync and steering.
- */
-static int iscsit_determine_sync_and_steering_counts(
- struct iscsi_conn *conn,
- struct iscsi_data_count *count)
-{
- u32 length = count->data_length;
- u32 marker, markint;
-
- count->sync_and_steering = 1;
-
- marker = (count->type == ISCSI_RX_DATA) ?
- conn->of_marker : conn->if_marker;
- markint = (count->type == ISCSI_RX_DATA) ?
- (conn->conn_ops->OFMarkInt * 4) :
- (conn->conn_ops->IFMarkInt * 4);
- count->ss_iov_count = count->iov_count;
-
- while (length > 0) {
- if (length >= marker) {
- count->ss_iov_count += 3;
- count->ss_marker_count += 2;
-
- length -= marker;
- marker = markint;
- } else
- length = 0;
- }
-
- return 0;
-}
-
-/*
* Setup conn->if_marker and conn->of_marker values based upon
* the initial marker-less interval. (see iSCSI v19 A.2)
*/
@@ -1292,7 +1274,7 @@ int iscsit_fe_sendpage_sg(
struct kvec iov;
u32 tx_hdr_size, data_len;
u32 offset = cmd->first_data_sg_off;
- int tx_sent;
+ int tx_sent, iov_off;
send_hdr:
tx_hdr_size = ISCSI_HDR_LEN;
@@ -1312,9 +1294,19 @@ send_hdr:
}
data_len = cmd->tx_size - tx_hdr_size - cmd->padding;
- if (conn->conn_ops->DataDigest)
+ /*
+ * Set iov_off used by padding and data digest tx_data() calls below
+ * in order to determine proper offset into cmd->iov_data[]
+ */
+ if (conn->conn_ops->DataDigest) {
data_len -= ISCSI_CRC_LEN;
-
+ if (cmd->padding)
+ iov_off = (cmd->iov_data_count - 2);
+ else
+ iov_off = (cmd->iov_data_count - 1);
+ } else {
+ iov_off = (cmd->iov_data_count - 1);
+ }
/*
* Perform sendpage() for each page in the scatterlist
*/
@@ -1343,8 +1335,7 @@ send_pg:
send_padding:
if (cmd->padding) {
- struct kvec *iov_p =
- &cmd->iov_data[cmd->iov_data_count-1];
+ struct kvec *iov_p = &cmd->iov_data[iov_off++];
tx_sent = tx_data(conn, iov_p, 1, cmd->padding);
if (cmd->padding != tx_sent) {
@@ -1358,8 +1349,7 @@ send_padding:
send_datacrc:
if (conn->conn_ops->DataDigest) {
- struct kvec *iov_d =
- &cmd->iov_data[cmd->iov_data_count];
+ struct kvec *iov_d = &cmd->iov_data[iov_off];
tx_sent = tx_data(conn, iov_d, 1, ISCSI_CRC_LEN);
if (ISCSI_CRC_LEN != tx_sent) {
@@ -1433,8 +1423,7 @@ static int iscsit_do_rx_data(
struct iscsi_data_count *count)
{
int data = count->data_length, rx_loop = 0, total_rx = 0, iov_len;
- u32 rx_marker_val[count->ss_marker_count], rx_marker_iov = 0;
- struct kvec iov[count->ss_iov_count], *iov_p;
+ struct kvec *iov_p;
struct msghdr msg;
if (!conn || !conn->sock || !conn->conn_ops)
@@ -1442,93 +1431,8 @@ static int iscsit_do_rx_data(
memset(&msg, 0, sizeof(struct msghdr));
- if (count->sync_and_steering) {
- int size = 0;
- u32 i, orig_iov_count = 0;
- u32 orig_iov_len = 0, orig_iov_loc = 0;
- u32 iov_count = 0, per_iov_bytes = 0;
- u32 *rx_marker, old_rx_marker = 0;
- struct kvec *iov_record;
-
- memset(&rx_marker_val, 0,
- count->ss_marker_count * sizeof(u32));
- memset(&iov, 0, count->ss_iov_count * sizeof(struct kvec));
-
- iov_record = count->iov;
- orig_iov_count = count->iov_count;
- rx_marker = &conn->of_marker;
-
- i = 0;
- size = data;
- orig_iov_len = iov_record[orig_iov_loc].iov_len;
- while (size > 0) {
- pr_debug("rx_data: #1 orig_iov_len %u,"
- " orig_iov_loc %u\n", orig_iov_len, orig_iov_loc);
- pr_debug("rx_data: #2 rx_marker %u, size"
- " %u\n", *rx_marker, size);
-
- if (orig_iov_len >= *rx_marker) {
- iov[iov_count].iov_len = *rx_marker;
- iov[iov_count++].iov_base =
- (iov_record[orig_iov_loc].iov_base +
- per_iov_bytes);
-
- iov[iov_count].iov_len = (MARKER_SIZE / 2);
- iov[iov_count++].iov_base =
- &rx_marker_val[rx_marker_iov++];
- iov[iov_count].iov_len = (MARKER_SIZE / 2);
- iov[iov_count++].iov_base =
- &rx_marker_val[rx_marker_iov++];
- old_rx_marker = *rx_marker;
-
- /*
- * OFMarkInt is in 32-bit words.
- */
- *rx_marker = (conn->conn_ops->OFMarkInt * 4);
- size -= old_rx_marker;
- orig_iov_len -= old_rx_marker;
- per_iov_bytes += old_rx_marker;
-
- pr_debug("rx_data: #3 new_rx_marker"
- " %u, size %u\n", *rx_marker, size);
- } else {
- iov[iov_count].iov_len = orig_iov_len;
- iov[iov_count++].iov_base =
- (iov_record[orig_iov_loc].iov_base +
- per_iov_bytes);
-
- per_iov_bytes = 0;
- *rx_marker -= orig_iov_len;
- size -= orig_iov_len;
-
- if (size)
- orig_iov_len =
- iov_record[++orig_iov_loc].iov_len;
-
- pr_debug("rx_data: #4 new_rx_marker"
- " %u, size %u\n", *rx_marker, size);
- }
- }
- data += (rx_marker_iov * (MARKER_SIZE / 2));
-
- iov_p = &iov[0];
- iov_len = iov_count;
-
- if (iov_count > count->ss_iov_count) {
- pr_err("iov_count: %d, count->ss_iov_count:"
- " %d\n", iov_count, count->ss_iov_count);
- return -1;
- }
- if (rx_marker_iov > count->ss_marker_count) {
- pr_err("rx_marker_iov: %d, count->ss_marker"
- "_count: %d\n", rx_marker_iov,
- count->ss_marker_count);
- return -1;
- }
- } else {
- iov_p = count->iov;
- iov_len = count->iov_count;
- }
+ iov_p = count->iov;
+ iov_len = count->iov_count;
while (total_rx < data) {
rx_loop = kernel_recvmsg(conn->sock, &msg, iov_p, iov_len,
@@ -1543,16 +1447,6 @@ static int iscsit_do_rx_data(
rx_loop, total_rx, data);
}
- if (count->sync_and_steering) {
- int j;
- for (j = 0; j < rx_marker_iov; j++) {
- pr_debug("rx_data: #5 j: %d, offset: %d\n",
- j, rx_marker_val[j]);
- conn->of_marker_offset = rx_marker_val[j];
- }
- total_rx -= (rx_marker_iov * (MARKER_SIZE / 2));
- }
-
return total_rx;
}
@@ -1561,8 +1455,7 @@ static int iscsit_do_tx_data(
struct iscsi_data_count *count)
{
int data = count->data_length, total_tx = 0, tx_loop = 0, iov_len;
- u32 tx_marker_val[count->ss_marker_count], tx_marker_iov = 0;
- struct kvec iov[count->ss_iov_count], *iov_p;
+ struct kvec *iov_p;
struct msghdr msg;
if (!conn || !conn->sock || !conn->conn_ops)
@@ -1575,98 +1468,8 @@ static int iscsit_do_tx_data(
memset(&msg, 0, sizeof(struct msghdr));
- if (count->sync_and_steering) {
- int size = 0;
- u32 i, orig_iov_count = 0;
- u32 orig_iov_len = 0, orig_iov_loc = 0;
- u32 iov_count = 0, per_iov_bytes = 0;
- u32 *tx_marker, old_tx_marker = 0;
- struct kvec *iov_record;
-
- memset(&tx_marker_val, 0,
- count->ss_marker_count * sizeof(u32));
- memset(&iov, 0, count->ss_iov_count * sizeof(struct kvec));
-
- iov_record = count->iov;
- orig_iov_count = count->iov_count;
- tx_marker = &conn->if_marker;
-
- i = 0;
- size = data;
- orig_iov_len = iov_record[orig_iov_loc].iov_len;
- while (size > 0) {
- pr_debug("tx_data: #1 orig_iov_len %u,"
- " orig_iov_loc %u\n", orig_iov_len, orig_iov_loc);
- pr_debug("tx_data: #2 tx_marker %u, size"
- " %u\n", *tx_marker, size);
-
- if (orig_iov_len >= *tx_marker) {
- iov[iov_count].iov_len = *tx_marker;
- iov[iov_count++].iov_base =
- (iov_record[orig_iov_loc].iov_base +
- per_iov_bytes);
-
- tx_marker_val[tx_marker_iov] =
- (size - *tx_marker);
- iov[iov_count].iov_len = (MARKER_SIZE / 2);
- iov[iov_count++].iov_base =
- &tx_marker_val[tx_marker_iov++];
- iov[iov_count].iov_len = (MARKER_SIZE / 2);
- iov[iov_count++].iov_base =
- &tx_marker_val[tx_marker_iov++];
- old_tx_marker = *tx_marker;
-
- /*
- * IFMarkInt is in 32-bit words.
- */
- *tx_marker = (conn->conn_ops->IFMarkInt * 4);
- size -= old_tx_marker;
- orig_iov_len -= old_tx_marker;
- per_iov_bytes += old_tx_marker;
-
- pr_debug("tx_data: #3 new_tx_marker"
- " %u, size %u\n", *tx_marker, size);
- pr_debug("tx_data: #4 offset %u\n",
- tx_marker_val[tx_marker_iov-1]);
- } else {
- iov[iov_count].iov_len = orig_iov_len;
- iov[iov_count++].iov_base
- = (iov_record[orig_iov_loc].iov_base +
- per_iov_bytes);
-
- per_iov_bytes = 0;
- *tx_marker -= orig_iov_len;
- size -= orig_iov_len;
-
- if (size)
- orig_iov_len =
- iov_record[++orig_iov_loc].iov_len;
-
- pr_debug("tx_data: #5 new_tx_marker"
- " %u, size %u\n", *tx_marker, size);
- }
- }
-
- data += (tx_marker_iov * (MARKER_SIZE / 2));
-
- iov_p = &iov[0];
- iov_len = iov_count;
-
- if (iov_count > count->ss_iov_count) {
- pr_err("iov_count: %d, count->ss_iov_count:"
- " %d\n", iov_count, count->ss_iov_count);
- return -1;
- }
- if (tx_marker_iov > count->ss_marker_count) {
- pr_err("tx_marker_iov: %d, count->ss_marker"
- "_count: %d\n", tx_marker_iov,
- count->ss_marker_count);
- return -1;
- }
- } else {
- iov_p = count->iov;
- iov_len = count->iov_count;
- }
+ iov_p = count->iov;
+ iov_len = count->iov_count;
while (total_tx < data) {
tx_loop = kernel_sendmsg(conn->sock, &msg, iov_p, iov_len,
@@ -1681,9 +1484,6 @@ static int iscsit_do_tx_data(
tx_loop, total_tx, data);
}
- if (count->sync_and_steering)
- total_tx -= (tx_marker_iov * (MARKER_SIZE / 2));
-
return total_tx;
}
@@ -1704,12 +1504,6 @@ int rx_data(
c.data_length = data;
c.type = ISCSI_RX_DATA;
- if (conn->conn_ops->OFMarker &&
- (conn->conn_state >= TARG_CONN_STATE_LOGGED_IN)) {
- if (iscsit_determine_sync_and_steering_counts(conn, &c) < 0)
- return -1;
- }
-
return iscsit_do_rx_data(conn, &c);
}
@@ -1730,12 +1524,6 @@ int tx_data(
c.data_length = data;
c.type = ISCSI_TX_DATA;
- if (conn->conn_ops->IFMarker &&
- (conn->conn_state >= TARG_CONN_STATE_LOGGED_IN)) {
- if (iscsit_determine_sync_and_steering_counts(conn, &c) < 0)
- return -1;
- }
-
return iscsit_do_tx_data(conn, &c);
}
diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h
index 2cd49d607bda..835bf7de0281 100644
--- a/drivers/target/iscsi/iscsi_target_util.h
+++ b/drivers/target/iscsi/iscsi_target_util.h
@@ -30,6 +30,7 @@ extern struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_c
extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_conn *);
extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *);
extern void iscsit_release_cmd(struct iscsi_cmd *);
+extern void iscsit_free_cmd(struct iscsi_cmd *);
extern int iscsit_check_session_usage_count(struct iscsi_session *);
extern void iscsit_dec_session_usage_count(struct iscsi_session *);
extern void iscsit_inc_session_usage_count(struct iscsi_session *);
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index aa2d67997235..b15d8cbf630b 100644
--- a/drivers/target/loopback/tcm_loop.c
+++ b/drivers/target/loopback/tcm_loop.c
@@ -200,7 +200,7 @@ static void tcm_loop_check_stop_free(struct se_cmd *se_cmd)
* Release the struct se_cmd, which will make a callback to release
* struct tcm_loop_cmd * in tcm_loop_deallocate_core_cmd()
*/
- transport_generic_free_cmd(se_cmd, 0, 0);
+ transport_generic_free_cmd(se_cmd, 0);
}
static void tcm_loop_release_cmd(struct se_cmd *se_cmd)
@@ -290,6 +290,15 @@ static int tcm_loop_queuecommand(
*/
tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host);
tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id];
+ /*
+ * Ensure that this tl_tpg reference from the incoming sc->device->id
+ * has already been configured via tcm_loop_make_naa_tpg().
+ */
+ if (!tl_tpg->tl_hba) {
+ set_host_byte(sc, DID_NO_CONNECT);
+ sc->scsi_done(sc);
+ return 0;
+ }
se_tpg = &tl_tpg->tl_se_tpg;
/*
* Determine the SAM Task Attribute and allocate tl_cmd and
@@ -366,7 +375,7 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc)
* Allocate the LUN_RESET TMR
*/
se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd, tl_tmr,
- TMR_LUN_RESET);
+ TMR_LUN_RESET, GFP_KERNEL);
if (IS_ERR(se_cmd->se_tmr_req))
goto release;
/*
@@ -388,7 +397,7 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc)
SUCCESS : FAILED;
release:
if (se_cmd)
- transport_generic_free_cmd(se_cmd, 1, 0);
+ transport_generic_free_cmd(se_cmd, 1);
else
kmem_cache_free(tcm_loop_cmd_cache, tl_cmd);
kfree(tl_tmr);
@@ -1245,6 +1254,9 @@ void tcm_loop_drop_naa_tpg(
*/
core_tpg_deregister(se_tpg);
+ tl_tpg->tl_hba = NULL;
+ tl_tpg->tl_tpgt = 0;
+
pr_debug("TCM_Loop_ConfigFS: Deallocated Emulated %s"
" Target Port %s,t,0x%04x\n", tcm_loop_dump_proto_id(tl_hba),
config_item_name(&wwn->wwn_group.cg_item), tpgt);
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index 98c98a3a0250..8f4447749c71 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -24,7 +24,6 @@
*
******************************************************************************/
-#include <linux/version.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/configfs.h>
@@ -68,6 +67,15 @@ int core_emulate_report_target_port_groups(struct se_cmd *cmd)
unsigned char *buf;
u32 rd_len = 0, off = 4; /* Skip over RESERVED area to first
Target port group descriptor */
+ /*
+ * Need at least 4 bytes of response data or else we can't
+ * even fit the return data length.
+ */
+ if (cmd->data_length < 4) {
+ pr_warn("REPORT TARGET PORT GROUPS allocation length %u"
+ " too small\n", cmd->data_length);
+ return -EINVAL;
+ }
buf = transport_kmap_first_data_page(cmd);
@@ -75,6 +83,17 @@ int core_emulate_report_target_port_groups(struct se_cmd *cmd)
list_for_each_entry(tg_pt_gp, &su_dev->t10_alua.tg_pt_gps_list,
tg_pt_gp_list) {
/*
+ * Check if the Target port group and Target port descriptor list
+ * based on tg_pt_gp_members count will fit into the response payload.
+ * Otherwise, bump rd_len to let the initiator know we have exceeded
+ * the allocation length and the response is truncated.
+ */
+ if ((off + 8 + (tg_pt_gp->tg_pt_gp_members * 4)) >
+ cmd->data_length) {
+ rd_len += 8 + (tg_pt_gp->tg_pt_gp_members * 4);
+ continue;
+ }
+ /*
* PREF: Preferred target port bit, determine if this
* bit should be set for port group.
*/
diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c
index 8ae09a1bdf74..38535eb13929 100644
--- a/drivers/target/target_core_cdb.c
+++ b/drivers/target/target_core_cdb.c
@@ -24,6 +24,7 @@
*/
#include <linux/kernel.h>
+#include <linux/module.h>
#include <asm/unaligned.h>
#include <scsi/scsi.h>
@@ -67,6 +68,7 @@ target_emulate_inquiry_std(struct se_cmd *cmd)
{
struct se_lun *lun = cmd->se_lun;
struct se_device *dev = cmd->se_dev;
+ struct se_portal_group *tpg = lun->lun_sep->sep_tpg;
unsigned char *buf;
/*
@@ -81,9 +83,13 @@ target_emulate_inquiry_std(struct se_cmd *cmd)
buf = transport_kmap_first_data_page(cmd);
- buf[0] = dev->transport->get_device_type(dev);
- if (buf[0] == TYPE_TAPE)
- buf[1] = 0x80;
+ if (dev == tpg->tpg_virt_lun0.lun_se_dev) {
+ buf[0] = 0x3f; /* Not connected */
+ } else {
+ buf[0] = dev->transport->get_device_type(dev);
+ if (buf[0] == TYPE_TAPE)
+ buf[1] = 0x80;
+ }
buf[2] = dev->transport->get_device_rev(dev);
/*
@@ -149,6 +155,37 @@ target_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf)
return 0;
}
+static void
+target_parse_naa_6h_vendor_specific(struct se_device *dev, unsigned char *buf)
+{
+ unsigned char *p = &dev->se_sub_dev->t10_wwn.unit_serial[0];
+ int cnt;
+ bool next = true;
+
+ /*
+ * Generate up to 36 bits of VENDOR SPECIFIC IDENTIFIER starting on
+ * byte 3 bit 3-0 for NAA IEEE Registered Extended DESIGNATOR field
+ * format, followed by 64 bits of VENDOR SPECIFIC IDENTIFIER EXTENSION
+ * to complete the payload. These are based from VPD=0x80 PRODUCT SERIAL
+ * NUMBER set via vpd_unit_serial in target_core_configfs.c to ensure
+ * per device uniqeness.
+ */
+ for (cnt = 0; *p && cnt < 13; p++) {
+ int val = hex_to_bin(*p);
+
+ if (val < 0)
+ continue;
+
+ if (next) {
+ next = false;
+ buf[cnt++] |= val;
+ } else {
+ next = true;
+ buf[cnt] = val << 4;
+ }
+ }
+}
+
/*
* Device identification VPD, for a complete list of
* DESIGNATOR TYPEs see spc4r17 Table 459.
@@ -214,8 +251,7 @@ target_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf)
* VENDOR_SPECIFIC_IDENTIFIER and
* VENDOR_SPECIFIC_IDENTIFIER_EXTENTION
*/
- buf[off++] |= hex_to_bin(dev->se_sub_dev->t10_wwn.unit_serial[0]);
- hex2bin(&buf[off], &dev->se_sub_dev->t10_wwn.unit_serial[1], 12);
+ target_parse_naa_6h_vendor_specific(dev, &buf[off]);
len = 20;
off = (len + 4);
@@ -915,8 +951,8 @@ target_emulate_modesense(struct se_cmd *cmd, int ten)
length += target_modesense_control(dev, &buf[offset+length]);
break;
default:
- pr_err("Got Unknown Mode Page: 0x%02x\n",
- cdb[2] & 0x3f);
+ pr_err("MODE SENSE: unimplemented page/subpage: 0x%02x/0x%02x\n",
+ cdb[2] & 0x3f, cdb[3]);
return PYX_TRANSPORT_UNKNOWN_MODE_PAGE;
}
offset += length;
@@ -1072,8 +1108,6 @@ target_emulate_unmap(struct se_task *task)
size -= 16;
}
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
err:
transport_kunmap_first_data_page(cmd);
@@ -1085,24 +1119,17 @@ err:
* Note this is not used for TCM/pSCSI passthrough
*/
static int
-target_emulate_write_same(struct se_task *task, int write_same32)
+target_emulate_write_same(struct se_task *task, u32 num_blocks)
{
struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
sector_t range;
sector_t lba = cmd->t_task_lba;
- unsigned int num_blocks;
int ret;
/*
- * Extract num_blocks from the WRITE_SAME_* CDB. Then use the explict
- * range when non zero is supplied, otherwise calculate the remaining
- * range based on ->get_blocks() - starting LBA.
+ * Use the explicit range when non zero is supplied, otherwise calculate
+ * the remaining range based on ->get_blocks() - starting LBA.
*/
- if (write_same32)
- num_blocks = get_unaligned_be32(&cmd->t_task_cdb[28]);
- else
- num_blocks = get_unaligned_be32(&cmd->t_task_cdb[10]);
-
if (num_blocks != 0)
range = num_blocks;
else
@@ -1117,8 +1144,6 @@ target_emulate_write_same(struct se_task *task, int write_same32)
return ret;
}
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
return 0;
}
@@ -1165,13 +1190,23 @@ transport_emulate_control_cdb(struct se_task *task)
}
ret = target_emulate_unmap(task);
break;
+ case WRITE_SAME:
+ if (!dev->transport->do_discard) {
+ pr_err("WRITE_SAME emulation not supported"
+ " for: %s\n", dev->transport->name);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+ ret = target_emulate_write_same(task,
+ get_unaligned_be16(&cmd->t_task_cdb[7]));
+ break;
case WRITE_SAME_16:
if (!dev->transport->do_discard) {
pr_err("WRITE_SAME_16 emulation not supported"
" for: %s\n", dev->transport->name);
return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
}
- ret = target_emulate_write_same(task, 0);
+ ret = target_emulate_write_same(task,
+ get_unaligned_be32(&cmd->t_task_cdb[10]));
break;
case VARIABLE_LENGTH_CMD:
service_action =
@@ -1184,7 +1219,8 @@ transport_emulate_control_cdb(struct se_task *task)
dev->transport->name);
return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
}
- ret = target_emulate_write_same(task, 1);
+ ret = target_emulate_write_same(task,
+ get_unaligned_be32(&cmd->t_task_cdb[28]));
break;
default:
pr_err("Unsupported VARIABLE_LENGTH_CMD SA:"
@@ -1219,8 +1255,63 @@ transport_emulate_control_cdb(struct se_task *task)
if (ret < 0)
return ret;
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
+ /*
+ * Handle the successful completion here unless a caller
+ * has explictly requested an asychronous completion.
+ */
+ if (!(cmd->se_cmd_flags & SCF_EMULATE_CDB_ASYNC)) {
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ }
return PYX_TRANSPORT_SENT_TO_TRANSPORT;
}
+
+/*
+ * Write a CDB into @cdb that is based on the one the intiator sent us,
+ * but updated to only cover the sectors that the current task handles.
+ */
+void target_get_task_cdb(struct se_task *task, unsigned char *cdb)
+{
+ struct se_cmd *cmd = task->task_se_cmd;
+ unsigned int cdb_len = scsi_command_size(cmd->t_task_cdb);
+
+ memcpy(cdb, cmd->t_task_cdb, cdb_len);
+ if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) {
+ unsigned long long lba = task->task_lba;
+ u32 sectors = task->task_sectors;
+
+ switch (cdb_len) {
+ case 6:
+ /* 21-bit LBA and 8-bit sectors */
+ cdb[1] = (lba >> 16) & 0x1f;
+ cdb[2] = (lba >> 8) & 0xff;
+ cdb[3] = lba & 0xff;
+ cdb[4] = sectors & 0xff;
+ break;
+ case 10:
+ /* 32-bit LBA and 16-bit sectors */
+ put_unaligned_be32(lba, &cdb[2]);
+ put_unaligned_be16(sectors, &cdb[7]);
+ break;
+ case 12:
+ /* 32-bit LBA and 32-bit sectors */
+ put_unaligned_be32(lba, &cdb[2]);
+ put_unaligned_be32(sectors, &cdb[6]);
+ break;
+ case 16:
+ /* 64-bit LBA and 32-bit sectors */
+ put_unaligned_be64(lba, &cdb[2]);
+ put_unaligned_be32(sectors, &cdb[10]);
+ break;
+ case 32:
+ /* 64-bit LBA and 32-bit sectors, extended CDB */
+ put_unaligned_be64(lba, &cdb[12]);
+ put_unaligned_be32(sectors, &cdb[28]);
+ break;
+ default:
+ BUG();
+ }
+ }
+}
+EXPORT_SYMBOL(target_get_task_cdb);
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index b2575d8568cc..e0c1e8a8dd4e 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -23,7 +23,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/version.h>
#include <generated/utsrelease.h>
#include <linux/utsname.h>
#include <linux/init.h>
@@ -133,14 +132,6 @@ static struct config_group *target_core_register_fabric(
pr_debug("Target_Core_ConfigFS: REGISTER -> group: %p name:"
" %s\n", group, name);
/*
- * Ensure that TCM subsystem plugins are loaded at this point for
- * using the RAMDISK_DR virtual LUN 0 and all other struct se_port
- * LUN symlinks.
- */
- if (transport_subsystem_check_init() < 0)
- return ERR_PTR(-EINVAL);
-
- /*
* Below are some hardcoded request_module() calls to automatically
* local fabric modules when the following is called:
*
@@ -725,9 +716,6 @@ SE_DEV_ATTR_RO(hw_queue_depth);
DEF_DEV_ATTRIB(queue_depth);
SE_DEV_ATTR(queue_depth, S_IRUGO | S_IWUSR);
-DEF_DEV_ATTRIB(task_timeout);
-SE_DEV_ATTR(task_timeout, S_IRUGO | S_IWUSR);
-
DEF_DEV_ATTRIB(max_unmap_lba_count);
SE_DEV_ATTR(max_unmap_lba_count, S_IRUGO | S_IWUSR);
@@ -761,7 +749,6 @@ static struct configfs_attribute *target_core_dev_attrib_attrs[] = {
&target_core_dev_attrib_optimal_sectors.attr,
&target_core_dev_attrib_hw_queue_depth.attr,
&target_core_dev_attrib_queue_depth.attr,
- &target_core_dev_attrib_task_timeout.attr,
&target_core_dev_attrib_max_unmap_lba_count.attr,
&target_core_dev_attrib_max_unmap_block_desc_count.attr,
&target_core_dev_attrib_unmap_granularity.attr,
@@ -3080,8 +3067,7 @@ static struct config_group *target_core_call_addhbatotarget(
/*
* Load up TCM subsystem plugins if they have not already been loaded.
*/
- if (transport_subsystem_check_init() < 0)
- return ERR_PTR(-EINVAL);
+ transport_subsystem_check_init();
hba = core_alloc_hba(se_plugin_str, plugin_dep_id, 0);
if (IS_ERR(hba))
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index b38b6c993e65..f870c3bcfd82 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -472,9 +472,9 @@ void core_clear_lun_from_tpg(struct se_lun *lun, struct se_portal_group *tpg)
struct se_dev_entry *deve;
u32 i;
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
list_for_each_entry(nacl, &tpg->acl_node_list, acl_list) {
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
spin_lock_irq(&nacl->device_list_lock);
for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
@@ -491,9 +491,9 @@ void core_clear_lun_from_tpg(struct se_lun *lun, struct se_portal_group *tpg)
}
spin_unlock_irq(&nacl->device_list_lock);
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
}
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
}
static struct se_port *core_alloc_port(struct se_device *dev)
@@ -839,6 +839,24 @@ int se_dev_check_shutdown(struct se_device *dev)
return ret;
}
+u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size)
+{
+ u32 tmp, aligned_max_sectors;
+ /*
+ * Limit max_sectors to a PAGE_SIZE aligned value for modern
+ * transport_allocate_data_tasks() operation.
+ */
+ tmp = rounddown((max_sectors * block_size), PAGE_SIZE);
+ aligned_max_sectors = (tmp / block_size);
+ if (max_sectors != aligned_max_sectors) {
+ printk(KERN_INFO "Rounding down aligned max_sectors from %u"
+ " to %u\n", max_sectors, aligned_max_sectors);
+ return aligned_max_sectors;
+ }
+
+ return max_sectors;
+}
+
void se_dev_set_default_attribs(
struct se_device *dev,
struct se_dev_limits *dev_limits)
@@ -878,6 +896,11 @@ void se_dev_set_default_attribs(
* max_sectors is based on subsystem plugin dependent requirements.
*/
dev->se_sub_dev->se_dev_attrib.hw_max_sectors = limits->max_hw_sectors;
+ /*
+ * Align max_sectors down to PAGE_SIZE to follow transport_allocate_data_tasks()
+ */
+ limits->max_sectors = se_dev_align_max_sectors(limits->max_sectors,
+ limits->logical_block_size);
dev->se_sub_dev->se_dev_attrib.max_sectors = limits->max_sectors;
/*
* Set optimal_sectors from max_sectors, which can be lowered via
@@ -891,21 +914,6 @@ void se_dev_set_default_attribs(
dev->se_sub_dev->se_dev_attrib.queue_depth = dev_limits->queue_depth;
}
-int se_dev_set_task_timeout(struct se_device *dev, u32 task_timeout)
-{
- if (task_timeout > DA_TASK_TIMEOUT_MAX) {
- pr_err("dev[%p]: Passed task_timeout: %u larger then"
- " DA_TASK_TIMEOUT_MAX\n", dev, task_timeout);
- return -EINVAL;
- } else {
- dev->se_sub_dev->se_dev_attrib.task_timeout = task_timeout;
- pr_debug("dev[%p]: Set SE Device task_timeout: %u\n",
- dev, task_timeout);
- }
-
- return 0;
-}
-
int se_dev_set_max_unmap_lba_count(
struct se_device *dev,
u32 max_unmap_lba_count)
@@ -949,36 +957,24 @@ int se_dev_set_unmap_granularity_alignment(
int se_dev_set_emulate_dpo(struct se_device *dev, int flag)
{
- if ((flag != 0) && (flag != 1)) {
+ if (flag != 0 && flag != 1) {
pr_err("Illegal value %d\n", flag);
return -EINVAL;
}
- if (dev->transport->dpo_emulated == NULL) {
- pr_err("dev->transport->dpo_emulated is NULL\n");
- return -EINVAL;
- }
- if (dev->transport->dpo_emulated(dev) == 0) {
- pr_err("dev->transport->dpo_emulated not supported\n");
- return -EINVAL;
- }
- dev->se_sub_dev->se_dev_attrib.emulate_dpo = flag;
- pr_debug("dev[%p]: SE Device Page Out (DPO) Emulation"
- " bit: %d\n", dev, dev->se_sub_dev->se_dev_attrib.emulate_dpo);
- return 0;
+
+ pr_err("dpo_emulated not supported\n");
+ return -EINVAL;
}
int se_dev_set_emulate_fua_write(struct se_device *dev, int flag)
{
- if ((flag != 0) && (flag != 1)) {
+ if (flag != 0 && flag != 1) {
pr_err("Illegal value %d\n", flag);
return -EINVAL;
}
- if (dev->transport->fua_write_emulated == NULL) {
- pr_err("dev->transport->fua_write_emulated is NULL\n");
- return -EINVAL;
- }
- if (dev->transport->fua_write_emulated(dev) == 0) {
- pr_err("dev->transport->fua_write_emulated not supported\n");
+
+ if (dev->transport->fua_write_emulated == 0) {
+ pr_err("fua_write_emulated not supported\n");
return -EINVAL;
}
dev->se_sub_dev->se_dev_attrib.emulate_fua_write = flag;
@@ -989,36 +985,23 @@ int se_dev_set_emulate_fua_write(struct se_device *dev, int flag)
int se_dev_set_emulate_fua_read(struct se_device *dev, int flag)
{
- if ((flag != 0) && (flag != 1)) {
+ if (flag != 0 && flag != 1) {
pr_err("Illegal value %d\n", flag);
return -EINVAL;
}
- if (dev->transport->fua_read_emulated == NULL) {
- pr_err("dev->transport->fua_read_emulated is NULL\n");
- return -EINVAL;
- }
- if (dev->transport->fua_read_emulated(dev) == 0) {
- pr_err("dev->transport->fua_read_emulated not supported\n");
- return -EINVAL;
- }
- dev->se_sub_dev->se_dev_attrib.emulate_fua_read = flag;
- pr_debug("dev[%p]: SE Device Forced Unit Access READs: %d\n",
- dev, dev->se_sub_dev->se_dev_attrib.emulate_fua_read);
- return 0;
+
+ pr_err("ua read emulated not supported\n");
+ return -EINVAL;
}
int se_dev_set_emulate_write_cache(struct se_device *dev, int flag)
{
- if ((flag != 0) && (flag != 1)) {
+ if (flag != 0 && flag != 1) {
pr_err("Illegal value %d\n", flag);
return -EINVAL;
}
- if (dev->transport->write_cache_emulated == NULL) {
- pr_err("dev->transport->write_cache_emulated is NULL\n");
- return -EINVAL;
- }
- if (dev->transport->write_cache_emulated(dev) == 0) {
- pr_err("dev->transport->write_cache_emulated not supported\n");
+ if (dev->transport->write_cache_emulated == 0) {
+ pr_err("write_cache_emulated not supported\n");
return -EINVAL;
}
dev->se_sub_dev->se_dev_attrib.emulate_write_cache = flag;
@@ -1242,6 +1225,11 @@ int se_dev_set_max_sectors(struct se_device *dev, u32 max_sectors)
return -EINVAL;
}
}
+ /*
+ * Align max_sectors down to PAGE_SIZE to follow transport_allocate_data_tasks()
+ */
+ max_sectors = se_dev_align_max_sectors(max_sectors,
+ dev->se_sub_dev->se_dev_attrib.block_size);
dev->se_sub_dev->se_dev_attrib.max_sectors = max_sectors;
pr_debug("dev[%p]: SE Device max_sectors changed to %u\n",
@@ -1344,15 +1332,17 @@ struct se_lun *core_dev_add_lun(
*/
if (tpg->se_tpg_tfo->tpg_check_demo_mode(tpg)) {
struct se_node_acl *acl;
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
list_for_each_entry(acl, &tpg->acl_node_list, acl_list) {
- if (acl->dynamic_node_acl) {
- spin_unlock_bh(&tpg->acl_node_lock);
+ if (acl->dynamic_node_acl &&
+ (!tpg->se_tpg_tfo->tpg_check_demo_mode_login_only ||
+ !tpg->se_tpg_tfo->tpg_check_demo_mode_login_only(tpg))) {
+ spin_unlock_irq(&tpg->acl_node_lock);
core_tpg_add_node_to_devs(acl, tpg);
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
}
}
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
}
return lun_p;
diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c
index f1654694f4ea..09b6f8729f91 100644
--- a/drivers/target/target_core_fabric_configfs.c
+++ b/drivers/target/target_core_fabric_configfs.c
@@ -22,7 +22,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/version.h>
#include <generated/utsrelease.h>
#include <linux/utsname.h>
#include <linux/init.h>
@@ -481,7 +480,7 @@ static struct config_group *target_fabric_make_nodeacl(
se_nacl = tf->tf_ops.fabric_make_nodeacl(se_tpg, group, name);
if (IS_ERR(se_nacl))
- return ERR_PTR(PTR_ERR(se_nacl));
+ return ERR_CAST(se_nacl);
nacl_cg = &se_nacl->acl_group;
nacl_cg->default_groups = se_nacl->acl_default_groups;
diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c
index c4ea3a9a555b..39f021b855ef 100644
--- a/drivers/target/target_core_fabric_lib.c
+++ b/drivers/target/target_core_fabric_lib.c
@@ -63,6 +63,7 @@ u32 sas_get_pr_transport_id(
unsigned char *buf)
{
unsigned char *ptr;
+ int ret;
/*
* Set PROTOCOL IDENTIFIER to 6h for SAS
@@ -74,7 +75,9 @@ u32 sas_get_pr_transport_id(
*/
ptr = &se_nacl->initiatorname[4]; /* Skip over 'naa. prefix */
- hex2bin(&buf[4], ptr, 8);
+ ret = hex2bin(&buf[4], ptr, 8);
+ if (ret < 0)
+ pr_debug("sas transport_id: invalid hex string\n");
/*
* The SAS Transport ID is a hardcoded 24-byte length
@@ -156,8 +159,9 @@ u32 fc_get_pr_transport_id(
unsigned char *buf)
{
unsigned char *ptr;
- int i;
+ int i, ret;
u32 off = 8;
+
/*
* PROTOCOL IDENTIFIER is 0h for FCP-2
*
@@ -174,7 +178,9 @@ u32 fc_get_pr_transport_id(
i++;
continue;
}
- hex2bin(&buf[off++], &ptr[i], 1);
+ ret = hex2bin(&buf[off++], &ptr[i], 1);
+ if (ret < 0)
+ pr_debug("fc transport_id: invalid hex string\n");
i += 2;
}
/*
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index bc1b33639b8d..19a0be9c6570 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -26,7 +26,6 @@
*
******************************************************************************/
-#include <linux/version.h>
#include <linux/string.h>
#include <linux/parser.h>
#include <linux/timer.h>
@@ -273,13 +272,14 @@ fd_alloc_task(unsigned char *cdb)
static int fd_do_readv(struct se_task *task)
{
struct fd_request *req = FILE_REQ(task);
- struct fd_dev *dev = req->fd_task.se_dev->dev_ptr;
+ struct se_device *se_dev = req->fd_task.task_se_cmd->se_dev;
+ struct fd_dev *dev = se_dev->dev_ptr;
struct file *fd = dev->fd_file;
struct scatterlist *sg = task->task_sg;
struct iovec *iov;
mm_segment_t old_fs;
loff_t pos = (task->task_lba *
- task->se_dev->se_sub_dev->se_dev_attrib.block_size);
+ se_dev->se_sub_dev->se_dev_attrib.block_size);
int ret = 0, i;
iov = kzalloc(sizeof(struct iovec) * task->task_sg_nents, GFP_KERNEL);
@@ -325,13 +325,14 @@ static int fd_do_readv(struct se_task *task)
static int fd_do_writev(struct se_task *task)
{
struct fd_request *req = FILE_REQ(task);
- struct fd_dev *dev = req->fd_task.se_dev->dev_ptr;
+ struct se_device *se_dev = req->fd_task.task_se_cmd->se_dev;
+ struct fd_dev *dev = se_dev->dev_ptr;
struct file *fd = dev->fd_file;
struct scatterlist *sg = task->task_sg;
struct iovec *iov;
mm_segment_t old_fs;
loff_t pos = (task->task_lba *
- task->se_dev->se_sub_dev->se_dev_attrib.block_size);
+ se_dev->se_sub_dev->se_dev_attrib.block_size);
int ret, i = 0;
iov = kzalloc(sizeof(struct iovec) * task->task_sg_nents, GFP_KERNEL);
@@ -399,33 +400,6 @@ static void fd_emulate_sync_cache(struct se_task *task)
}
/*
- * Tell TCM Core that we are capable of WriteCache emulation for
- * an underlying struct se_device.
- */
-static int fd_emulated_write_cache(struct se_device *dev)
-{
- return 1;
-}
-
-static int fd_emulated_dpo(struct se_device *dev)
-{
- return 0;
-}
-/*
- * Tell TCM Core that we will be emulating Forced Unit Access (FUA) for WRITEs
- * for TYPE_DISK.
- */
-static int fd_emulated_fua_write(struct se_device *dev)
-{
- return 1;
-}
-
-static int fd_emulated_fua_read(struct se_device *dev)
-{
- return 0;
-}
-
-/*
* WRITE Force Unit Access (FUA) emulation on a per struct se_task
* LBA range basis..
*/
@@ -608,17 +582,6 @@ static ssize_t fd_show_configfs_dev_params(
return bl;
}
-/* fd_get_cdb(): (Part of se_subsystem_api_t template)
- *
- *
- */
-static unsigned char *fd_get_cdb(struct se_task *task)
-{
- struct fd_request *req = FILE_REQ(task);
-
- return req->fd_scsi_cdb;
-}
-
/* fd_get_device_rev(): (Part of se_subsystem_api_t template)
*
*
@@ -650,15 +613,13 @@ static struct se_subsystem_api fileio_template = {
.name = "fileio",
.owner = THIS_MODULE,
.transport_type = TRANSPORT_PLUGIN_VHBA_PDEV,
+ .write_cache_emulated = 1,
+ .fua_write_emulated = 1,
.attach_hba = fd_attach_hba,
.detach_hba = fd_detach_hba,
.allocate_virtdevice = fd_allocate_virtdevice,
.create_virtdevice = fd_create_virtdevice,
.free_device = fd_free_device,
- .dpo_emulated = fd_emulated_dpo,
- .fua_write_emulated = fd_emulated_fua_write,
- .fua_read_emulated = fd_emulated_fua_read,
- .write_cache_emulated = fd_emulated_write_cache,
.alloc_task = fd_alloc_task,
.do_task = fd_do_task,
.do_sync_cache = fd_emulate_sync_cache,
@@ -666,7 +627,6 @@ static struct se_subsystem_api fileio_template = {
.check_configfs_dev_params = fd_check_configfs_dev_params,
.set_configfs_dev_params = fd_set_configfs_dev_params,
.show_configfs_dev_params = fd_show_configfs_dev_params,
- .get_cdb = fd_get_cdb,
.get_device_rev = fd_get_device_rev,
.get_device_type = fd_get_device_type,
.get_blocks = fd_get_blocks,
diff --git a/drivers/target/target_core_file.h b/drivers/target/target_core_file.h
index daebd710b893..59e6e73106c2 100644
--- a/drivers/target/target_core_file.h
+++ b/drivers/target/target_core_file.h
@@ -14,9 +14,7 @@
struct fd_request {
struct se_task fd_task;
- /* SCSI CDB from iSCSI Command PDU */
- unsigned char fd_scsi_cdb[TCM_MAX_COMMAND_SIZE];
-} ____cacheline_aligned;
+};
#define FBDF_HAS_PATH 0x01
#define FBDF_HAS_SIZE 0x02
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index 7e1234105442..41ad02b5fb87 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -27,7 +27,6 @@
*
******************************************************************************/
-#include <linux/version.h>
#include <linux/string.h>
#include <linux/parser.h>
#include <linux/timer.h>
@@ -314,104 +313,42 @@ static unsigned long long iblock_emulate_read_cap_with_block_size(
return blocks_long;
}
+static void iblock_end_io_flush(struct bio *bio, int err)
+{
+ struct se_cmd *cmd = bio->bi_private;
+
+ if (err)
+ pr_err("IBLOCK: cache flush failed: %d\n", err);
+
+ if (cmd)
+ transport_complete_sync_cache(cmd, err == 0);
+ bio_put(bio);
+}
+
/*
- * Emulate SYCHRONIZE_CACHE_*
+ * Implement SYCHRONIZE CACHE. Note that we can't handle lba ranges and must
+ * always flush the whole cache.
*/
static void iblock_emulate_sync_cache(struct se_task *task)
{
struct se_cmd *cmd = task->task_se_cmd;
struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr;
int immed = (cmd->t_task_cdb[1] & 0x2);
- sector_t error_sector;
- int ret;
+ struct bio *bio;
/*
* If the Immediate bit is set, queue up the GOOD response
- * for this SYNCHRONIZE_CACHE op
+ * for this SYNCHRONIZE_CACHE op.
*/
if (immed)
transport_complete_sync_cache(cmd, 1);
- /*
- * blkdev_issue_flush() does not support a specifying a range, so
- * we have to flush the entire cache.
- */
- ret = blkdev_issue_flush(ib_dev->ibd_bd, GFP_KERNEL, &error_sector);
- if (ret != 0) {
- pr_err("IBLOCK: block_issue_flush() failed: %d "
- " error_sector: %llu\n", ret,
- (unsigned long long)error_sector);
- }
-
+ bio = bio_alloc(GFP_KERNEL, 0);
+ bio->bi_end_io = iblock_end_io_flush;
+ bio->bi_bdev = ib_dev->ibd_bd;
if (!immed)
- transport_complete_sync_cache(cmd, ret == 0);
-}
-
-/*
- * Tell TCM Core that we are capable of WriteCache emulation for
- * an underlying struct se_device.
- */
-static int iblock_emulated_write_cache(struct se_device *dev)
-{
- return 1;
-}
-
-static int iblock_emulated_dpo(struct se_device *dev)
-{
- return 0;
-}
-
-/*
- * Tell TCM Core that we will be emulating Forced Unit Access (FUA) for WRITEs
- * for TYPE_DISK.
- */
-static int iblock_emulated_fua_write(struct se_device *dev)
-{
- return 1;
-}
-
-static int iblock_emulated_fua_read(struct se_device *dev)
-{
- return 0;
-}
-
-static int iblock_do_task(struct se_task *task)
-{
- struct se_device *dev = task->task_se_cmd->se_dev;
- struct iblock_req *req = IBLOCK_REQ(task);
- struct bio *bio = req->ib_bio, *nbio = NULL;
- struct blk_plug plug;
- int rw;
-
- if (task->task_data_direction == DMA_TO_DEVICE) {
- /*
- * Force data to disk if we pretend to not have a volatile
- * write cache, or the initiator set the Force Unit Access bit.
- */
- if (dev->se_sub_dev->se_dev_attrib.emulate_write_cache == 0 ||
- (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0 &&
- task->task_se_cmd->t_tasks_fua))
- rw = WRITE_FUA;
- else
- rw = WRITE;
- } else {
- rw = READ;
- }
-
- blk_start_plug(&plug);
- while (bio) {
- nbio = bio->bi_next;
- bio->bi_next = NULL;
- pr_debug("Calling submit_bio() task: %p bio: %p"
- " bio->bi_sector: %llu\n", task, bio,
- (unsigned long long)bio->bi_sector);
-
- submit_bio(rw, bio);
- bio = nbio;
- }
- blk_finish_plug(&plug);
-
- return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+ bio->bi_private = cmd;
+ submit_bio(WRITE_FLUSH, bio);
}
static int iblock_do_discard(struct se_device *dev, sector_t lba, u32 range)
@@ -425,20 +362,7 @@ static int iblock_do_discard(struct se_device *dev, sector_t lba, u32 range)
static void iblock_free_task(struct se_task *task)
{
- struct iblock_req *req = IBLOCK_REQ(task);
- struct bio *bio, *hbio = req->ib_bio;
- /*
- * We only release the bio(s) here if iblock_bio_done() has not called
- * bio_put() -> iblock_bio_destructor().
- */
- while (hbio != NULL) {
- bio = hbio;
- hbio = hbio->bi_next;
- bio->bi_next = NULL;
- bio_put(bio);
- }
-
- kfree(req);
+ kfree(IBLOCK_REQ(task));
}
enum {
@@ -552,25 +476,21 @@ static ssize_t iblock_show_configfs_dev_params(
static void iblock_bio_destructor(struct bio *bio)
{
struct se_task *task = bio->bi_private;
- struct iblock_dev *ib_dev = task->se_dev->dev_ptr;
+ struct iblock_dev *ib_dev = task->task_se_cmd->se_dev->dev_ptr;
bio_free(bio, ib_dev->ibd_bio_set);
}
-static struct bio *iblock_get_bio(
- struct se_task *task,
- struct iblock_req *ib_req,
- struct iblock_dev *ib_dev,
- int *ret,
- sector_t lba,
- u32 sg_num)
+static struct bio *
+iblock_get_bio(struct se_task *task, sector_t lba, u32 sg_num)
{
+ struct iblock_dev *ib_dev = task->task_se_cmd->se_dev->dev_ptr;
+ struct iblock_req *ib_req = IBLOCK_REQ(task);
struct bio *bio;
bio = bio_alloc_bioset(GFP_NOIO, sg_num, ib_dev->ibd_bio_set);
if (!bio) {
pr_err("Unable to allocate memory for bio\n");
- *ret = PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
return NULL;
}
@@ -591,17 +511,33 @@ static struct bio *iblock_get_bio(
return bio;
}
-static int iblock_map_data_SG(struct se_task *task)
+static int iblock_do_task(struct se_task *task)
{
struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
- struct iblock_dev *ib_dev = task->se_dev->dev_ptr;
- struct iblock_req *ib_req = IBLOCK_REQ(task);
- struct bio *bio = NULL, *hbio = NULL, *tbio = NULL;
+ struct bio *bio;
+ struct bio_list list;
struct scatterlist *sg;
- int ret = 0;
u32 i, sg_num = task->task_sg_nents;
sector_t block_lba;
+ struct blk_plug plug;
+ int rw;
+
+ if (task->task_data_direction == DMA_TO_DEVICE) {
+ /*
+ * Force data to disk if we pretend to not have a volatile
+ * write cache, or the initiator set the Force Unit Access bit.
+ */
+ if (dev->se_sub_dev->se_dev_attrib.emulate_write_cache == 0 ||
+ (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0 &&
+ task->task_se_cmd->t_tasks_fua))
+ rw = WRITE_FUA;
+ else
+ rw = WRITE;
+ } else {
+ rw = READ;
+ }
+
/*
* Do starting conversion up from non 512-byte blocksize with
* struct se_task SCSI blocksize into Linux/Block 512 units for BIO.
@@ -620,68 +556,43 @@ static int iblock_map_data_SG(struct se_task *task)
return PYX_TRANSPORT_LU_COMM_FAILURE;
}
- bio = iblock_get_bio(task, ib_req, ib_dev, &ret, block_lba, sg_num);
+ bio = iblock_get_bio(task, block_lba, sg_num);
if (!bio)
- return ret;
+ return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
+
+ bio_list_init(&list);
+ bio_list_add(&list, bio);
- ib_req->ib_bio = bio;
- hbio = tbio = bio;
- /*
- * Use fs/bio.c:bio_add_pages() to setup the bio_vec maplist
- * from task->task_sg -> struct scatterlist memory.
- */
for_each_sg(task->task_sg, sg, task->task_sg_nents, i) {
- pr_debug("task: %p bio: %p Calling bio_add_page(): page:"
- " %p len: %u offset: %u\n", task, bio, sg_page(sg),
- sg->length, sg->offset);
-again:
- ret = bio_add_page(bio, sg_page(sg), sg->length, sg->offset);
- if (ret != sg->length) {
-
- pr_debug("*** Set bio->bi_sector: %llu\n",
- (unsigned long long)bio->bi_sector);
- pr_debug("** task->task_size: %u\n",
- task->task_size);
- pr_debug("*** bio->bi_max_vecs: %u\n",
- bio->bi_max_vecs);
- pr_debug("*** bio->bi_vcnt: %u\n",
- bio->bi_vcnt);
-
- bio = iblock_get_bio(task, ib_req, ib_dev, &ret,
- block_lba, sg_num);
+ /*
+ * XXX: if the length the device accepts is shorter than the
+ * length of the S/G list entry this will cause and
+ * endless loop. Better hope no driver uses huge pages.
+ */
+ while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset)
+ != sg->length) {
+ bio = iblock_get_bio(task, block_lba, sg_num);
if (!bio)
goto fail;
-
- tbio = tbio->bi_next = bio;
- pr_debug("-----------------> Added +1 bio: %p to"
- " list, Going to again\n", bio);
- goto again;
+ bio_list_add(&list, bio);
}
+
/* Always in 512 byte units for Linux/Block */
block_lba += sg->length >> IBLOCK_LBA_SHIFT;
sg_num--;
- pr_debug("task: %p bio-add_page() passed!, decremented"
- " sg_num to %u\n", task, sg_num);
- pr_debug("task: %p bio_add_page() passed!, increased lba"
- " to %llu\n", task, (unsigned long long)block_lba);
- pr_debug("task: %p bio_add_page() passed!, bio->bi_vcnt:"
- " %u\n", task, bio->bi_vcnt);
}
- return 0;
+ blk_start_plug(&plug);
+ while ((bio = bio_list_pop(&list)))
+ submit_bio(rw, bio);
+ blk_finish_plug(&plug);
+
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+
fail:
- while (hbio) {
- bio = hbio;
- hbio = hbio->bi_next;
- bio->bi_next = NULL;
+ while ((bio = bio_list_pop(&list)))
bio_put(bio);
- }
- return ret;
-}
-
-static unsigned char *iblock_get_cdb(struct se_task *task)
-{
- return IBLOCK_REQ(task)->ib_scsi_cdb;
+ return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
}
static u32 iblock_get_device_rev(struct se_device *dev)
@@ -707,6 +618,7 @@ static void iblock_bio_done(struct bio *bio, int err)
{
struct se_task *task = bio->bi_private;
struct iblock_req *ibr = IBLOCK_REQ(task);
+
/*
* Set -EIO if !BIO_UPTODATE and the passed is still err=0
*/
@@ -721,50 +633,31 @@ static void iblock_bio_done(struct bio *bio, int err)
*/
atomic_inc(&ibr->ib_bio_err_cnt);
smp_mb__after_atomic_inc();
- bio_put(bio);
- /*
- * Wait to complete the task until the last bio as completed.
- */
- if (!atomic_dec_and_test(&ibr->ib_bio_cnt))
- return;
-
- ibr->ib_bio = NULL;
- transport_complete_task(task, 0);
- return;
}
- pr_debug("done[%p] bio: %p task_lba: %llu bio_lba: %llu err=%d\n",
- task, bio, task->task_lba, (unsigned long long)bio->bi_sector, err);
- /*
- * bio_put() will call iblock_bio_destructor() to release the bio back
- * to ibr->ib_bio_set.
- */
+
bio_put(bio);
- /*
- * Wait to complete the task until the last bio as completed.
- */
+
if (!atomic_dec_and_test(&ibr->ib_bio_cnt))
return;
- /*
- * Return GOOD status for task if zero ib_bio_err_cnt exists.
- */
- ibr->ib_bio = NULL;
- transport_complete_task(task, (!atomic_read(&ibr->ib_bio_err_cnt)));
+
+ pr_debug("done[%p] bio: %p task_lba: %llu bio_lba: %llu err=%d\n",
+ task, bio, task->task_lba,
+ (unsigned long long)bio->bi_sector, err);
+
+ transport_complete_task(task, !atomic_read(&ibr->ib_bio_err_cnt));
}
static struct se_subsystem_api iblock_template = {
.name = "iblock",
.owner = THIS_MODULE,
.transport_type = TRANSPORT_PLUGIN_VHBA_PDEV,
- .map_data_SG = iblock_map_data_SG,
+ .write_cache_emulated = 1,
+ .fua_write_emulated = 1,
.attach_hba = iblock_attach_hba,
.detach_hba = iblock_detach_hba,
.allocate_virtdevice = iblock_allocate_virtdevice,
.create_virtdevice = iblock_create_virtdevice,
.free_device = iblock_free_device,
- .dpo_emulated = iblock_emulated_dpo,
- .fua_write_emulated = iblock_emulated_fua_write,
- .fua_read_emulated = iblock_emulated_fua_read,
- .write_cache_emulated = iblock_emulated_write_cache,
.alloc_task = iblock_alloc_task,
.do_task = iblock_do_task,
.do_discard = iblock_do_discard,
@@ -773,7 +666,6 @@ static struct se_subsystem_api iblock_template = {
.check_configfs_dev_params = iblock_check_configfs_dev_params,
.set_configfs_dev_params = iblock_set_configfs_dev_params,
.show_configfs_dev_params = iblock_show_configfs_dev_params,
- .get_cdb = iblock_get_cdb,
.get_device_rev = iblock_get_device_rev,
.get_device_type = iblock_get_device_type,
.get_blocks = iblock_get_blocks,
diff --git a/drivers/target/target_core_iblock.h b/drivers/target/target_core_iblock.h
index a121cd1b6575..5cf1860c10d0 100644
--- a/drivers/target/target_core_iblock.h
+++ b/drivers/target/target_core_iblock.h
@@ -8,10 +8,8 @@
struct iblock_req {
struct se_task ib_task;
- unsigned char ib_scsi_cdb[TCM_MAX_COMMAND_SIZE];
atomic_t ib_bio_cnt;
atomic_t ib_bio_err_cnt;
- struct bio *ib_bio;
} ____cacheline_aligned;
#define IBDF_HAS_UDEV_PATH 0x01
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 1c1b849cd4fb..0c4f783f924c 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -25,7 +25,6 @@
*
******************************************************************************/
-#include <linux/version.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/list.h>
@@ -1598,14 +1597,14 @@ static int core_scsi3_decode_spec_i_port(
* from the decoded fabric module specific TransportID
* at *i_str.
*/
- spin_lock_bh(&tmp_tpg->acl_node_lock);
+ spin_lock_irq(&tmp_tpg->acl_node_lock);
dest_node_acl = __core_tpg_get_initiator_node_acl(
tmp_tpg, i_str);
if (dest_node_acl) {
atomic_inc(&dest_node_acl->acl_pr_ref_count);
smp_mb__after_atomic_inc();
}
- spin_unlock_bh(&tmp_tpg->acl_node_lock);
+ spin_unlock_irq(&tmp_tpg->acl_node_lock);
if (!dest_node_acl) {
core_scsi3_tpg_undepend_item(tmp_tpg);
@@ -3496,14 +3495,14 @@ after_iport_check:
/*
* Locate the destination struct se_node_acl from the received Transport ID
*/
- spin_lock_bh(&dest_se_tpg->acl_node_lock);
+ spin_lock_irq(&dest_se_tpg->acl_node_lock);
dest_node_acl = __core_tpg_get_initiator_node_acl(dest_se_tpg,
initiator_str);
if (dest_node_acl) {
atomic_inc(&dest_node_acl->acl_pr_ref_count);
smp_mb__after_atomic_inc();
}
- spin_unlock_bh(&dest_se_tpg->acl_node_lock);
+ spin_unlock_irq(&dest_se_tpg->acl_node_lock);
if (!dest_node_acl) {
pr_err("Unable to locate %s dest_node_acl for"
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
index 2b7b0da9146d..dad671dee9e9 100644
--- a/drivers/target/target_core_pscsi.c
+++ b/drivers/target/target_core_pscsi.c
@@ -26,7 +26,6 @@
*
******************************************************************************/
-#include <linux/version.h>
#include <linux/string.h>
#include <linux/parser.h>
#include <linux/timer.h>
@@ -567,7 +566,7 @@ static struct se_device *pscsi_create_virtdevice(
if (IS_ERR(sh)) {
pr_err("pSCSI: Unable to locate"
" pdv_host_id: %d\n", pdv->pdv_host_id);
- return (struct se_device *) sh;
+ return ERR_CAST(sh);
}
}
} else {
@@ -677,7 +676,7 @@ static inline struct pscsi_plugin_task *PSCSI_TASK(struct se_task *task)
*/
static int pscsi_transport_complete(struct se_task *task)
{
- struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
+ struct pscsi_dev_virt *pdv = task->task_se_cmd->se_dev->dev_ptr;
struct scsi_device *sd = pdv->pdv_sd;
int result;
struct pscsi_plugin_task *pt = PSCSI_TASK(task);
@@ -777,95 +776,6 @@ pscsi_alloc_task(unsigned char *cdb)
return &pt->pscsi_task;
}
-static inline void pscsi_blk_init_request(
- struct se_task *task,
- struct pscsi_plugin_task *pt,
- struct request *req,
- int bidi_read)
-{
- /*
- * Defined as "scsi command" in include/linux/blkdev.h.
- */
- req->cmd_type = REQ_TYPE_BLOCK_PC;
- /*
- * For the extra BIDI-COMMAND READ struct request we do not
- * need to setup the remaining structure members
- */
- if (bidi_read)
- return;
- /*
- * Setup the done function pointer for struct request,
- * also set the end_io_data pointer.to struct se_task.
- */
- req->end_io = pscsi_req_done;
- req->end_io_data = task;
- /*
- * Load the referenced struct se_task's SCSI CDB into
- * include/linux/blkdev.h:struct request->cmd
- */
- req->cmd_len = scsi_command_size(pt->pscsi_cdb);
- req->cmd = &pt->pscsi_cdb[0];
- /*
- * Setup pointer for outgoing sense data.
- */
- req->sense = &pt->pscsi_sense[0];
- req->sense_len = 0;
-}
-
-/*
- * Used for pSCSI data payloads for all *NON* SCF_SCSI_DATA_SG_IO_CDB
-*/
-static int pscsi_blk_get_request(struct se_task *task)
-{
- struct pscsi_plugin_task *pt = PSCSI_TASK(task);
- struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
-
- pt->pscsi_req = blk_get_request(pdv->pdv_sd->request_queue,
- (task->task_data_direction == DMA_TO_DEVICE),
- GFP_KERNEL);
- if (!pt->pscsi_req || IS_ERR(pt->pscsi_req)) {
- pr_err("PSCSI: blk_get_request() failed: %ld\n",
- IS_ERR(pt->pscsi_req));
- return PYX_TRANSPORT_LU_COMM_FAILURE;
- }
- /*
- * Setup the newly allocated struct request for REQ_TYPE_BLOCK_PC,
- * and setup rq callback, CDB and sense.
- */
- pscsi_blk_init_request(task, pt, pt->pscsi_req, 0);
- return 0;
-}
-
-/* pscsi_do_task(): (Part of se_subsystem_api_t template)
- *
- *
- */
-static int pscsi_do_task(struct se_task *task)
-{
- struct pscsi_plugin_task *pt = PSCSI_TASK(task);
- struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
- /*
- * Set the struct request->timeout value based on peripheral
- * device type from SCSI.
- */
- if (pdv->pdv_sd->type == TYPE_DISK)
- pt->pscsi_req->timeout = PS_TIMEOUT_DISK;
- else
- pt->pscsi_req->timeout = PS_TIMEOUT_OTHER;
-
- pt->pscsi_req->retries = PS_RETRY;
- /*
- * Queue the struct request into the struct scsi_device->request_queue.
- * Also check for HEAD_OF_QUEUE SAM TASK attr from received se_cmd
- * descriptor
- */
- blk_execute_rq_nowait(pdv->pdv_sd->request_queue, NULL, pt->pscsi_req,
- (task->task_se_cmd->sam_task_attr == MSG_HEAD_TAG),
- pscsi_req_done);
-
- return PYX_TRANSPORT_SENT_TO_TRANSPORT;
-}
-
static void pscsi_free_task(struct se_task *task)
{
struct pscsi_plugin_task *pt = PSCSI_TASK(task);
@@ -1049,15 +959,12 @@ static inline struct bio *pscsi_get_bio(int sg_num)
return bio;
}
-static int __pscsi_map_SG(
- struct se_task *task,
- struct scatterlist *task_sg,
- u32 task_sg_num,
- int bidi_read)
+static int pscsi_map_sg(struct se_task *task, struct scatterlist *task_sg,
+ struct bio **hbio)
{
- struct pscsi_plugin_task *pt = PSCSI_TASK(task);
- struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
- struct bio *bio = NULL, *hbio = NULL, *tbio = NULL;
+ struct pscsi_dev_virt *pdv = task->task_se_cmd->se_dev->dev_ptr;
+ u32 task_sg_num = task->task_sg_nents;
+ struct bio *bio = NULL, *tbio = NULL;
struct page *page;
struct scatterlist *sg;
u32 data_len = task->task_size, i, len, bytes, off;
@@ -1066,19 +973,8 @@ static int __pscsi_map_SG(
int nr_vecs = 0, rc, ret = PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
int rw = (task->task_data_direction == DMA_TO_DEVICE);
- if (!task->task_size)
- return 0;
- /*
- * For SCF_SCSI_DATA_SG_IO_CDB, Use fs/bio.c:bio_add_page() to setup
- * the bio_vec maplist from task->task_sg ->
- * struct scatterlist memory. The struct se_task->task_sg[] currently needs
- * to be attached to struct bios for submission to Linux/SCSI using
- * struct request to struct scsi_device->request_queue.
- *
- * Note that this will be changing post v2.6.28 as Target_Core_Mod/pSCSI
- * is ported to upstream SCSI passthrough functionality that accepts
- * struct scatterlist->page_link or struct page as a paraemeter.
- */
+ *hbio = NULL;
+
pr_debug("PSCSI: nr_pages: %d\n", nr_pages);
for_each_sg(task_sg, sg, task_sg_num, i) {
@@ -1115,8 +1011,8 @@ static int __pscsi_map_SG(
* bios need to be added to complete a given
* struct se_task
*/
- if (!hbio)
- hbio = tbio = bio;
+ if (!*hbio)
+ *hbio = tbio = bio;
else
tbio = tbio->bi_next = bio;
}
@@ -1152,92 +1048,82 @@ static int __pscsi_map_SG(
off = 0;
}
}
- /*
- * Setup the primary pt->pscsi_req used for non BIDI and BIDI-COMMAND
- * primary SCSI WRITE poayload mapped for struct se_task->task_sg[]
- */
- if (!bidi_read) {
- /*
- * Starting with v2.6.31, call blk_make_request() passing in *hbio to
- * allocate the pSCSI task a struct request.
- */
- pt->pscsi_req = blk_make_request(pdv->pdv_sd->request_queue,
- hbio, GFP_KERNEL);
- if (!pt->pscsi_req) {
- pr_err("pSCSI: blk_make_request() failed\n");
- goto fail;
- }
- /*
- * Setup the newly allocated struct request for REQ_TYPE_BLOCK_PC,
- * and setup rq callback, CDB and sense.
- */
- pscsi_blk_init_request(task, pt, pt->pscsi_req, 0);
-
- return task->task_sg_nents;
- }
- /*
- * Setup the secondary pt->pscsi_req->next_rq used for the extra BIDI-COMMAND
- * SCSI READ paylaod mapped for struct se_task->task_sg_bidi[]
- */
- pt->pscsi_req->next_rq = blk_make_request(pdv->pdv_sd->request_queue,
- hbio, GFP_KERNEL);
- if (!pt->pscsi_req->next_rq) {
- pr_err("pSCSI: blk_make_request() failed for BIDI\n");
- goto fail;
- }
- pscsi_blk_init_request(task, pt, pt->pscsi_req->next_rq, 1);
return task->task_sg_nents;
fail:
- while (hbio) {
- bio = hbio;
- hbio = hbio->bi_next;
+ while (*hbio) {
+ bio = *hbio;
+ *hbio = (*hbio)->bi_next;
bio->bi_next = NULL;
- bio_endio(bio, 0);
+ bio_endio(bio, 0); /* XXX: should be error */
}
return ret;
}
-/*
- * pSCSI maps both ->map_control_SG() and ->map_data_SG() to a single call.
- */
-static int pscsi_map_SG(struct se_task *task)
+static int pscsi_do_task(struct se_task *task)
{
+ struct pscsi_dev_virt *pdv = task->task_se_cmd->se_dev->dev_ptr;
+ struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+ struct request *req;
+ struct bio *hbio;
int ret;
- /*
- * Setup the main struct request for the task->task_sg[] payload
- */
+ target_get_task_cdb(task, pt->pscsi_cdb);
+
+ if (task->task_se_cmd->se_cmd_flags & SCF_SCSI_NON_DATA_CDB) {
+ req = blk_get_request(pdv->pdv_sd->request_queue,
+ (task->task_data_direction == DMA_TO_DEVICE),
+ GFP_KERNEL);
+ if (!req || IS_ERR(req)) {
+ pr_err("PSCSI: blk_get_request() failed: %ld\n",
+ req ? IS_ERR(req) : -ENOMEM);
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ } else {
+ BUG_ON(!task->task_size);
- ret = __pscsi_map_SG(task, task->task_sg, task->task_sg_nents, 0);
- if (ret >= 0 && task->task_sg_bidi) {
/*
- * If present, set up the extra BIDI-COMMAND SCSI READ
- * struct request and payload.
+ * Setup the main struct request for the task->task_sg[] payload
*/
- ret = __pscsi_map_SG(task, task->task_sg_bidi,
- task->task_sg_nents, 1);
+ ret = pscsi_map_sg(task, task->task_sg, &hbio);
+ if (ret < 0)
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+
+ req = blk_make_request(pdv->pdv_sd->request_queue, hbio,
+ GFP_KERNEL);
+ if (!req) {
+ pr_err("pSCSI: blk_make_request() failed\n");
+ goto fail;
+ }
}
- if (ret < 0)
- return PYX_TRANSPORT_LU_COMM_FAILURE;
- return 0;
-}
+ req->cmd_type = REQ_TYPE_BLOCK_PC;
+ req->end_io = pscsi_req_done;
+ req->end_io_data = task;
+ req->cmd_len = scsi_command_size(pt->pscsi_cdb);
+ req->cmd = &pt->pscsi_cdb[0];
+ req->sense = &pt->pscsi_sense[0];
+ req->sense_len = 0;
+ if (pdv->pdv_sd->type == TYPE_DISK)
+ req->timeout = PS_TIMEOUT_DISK;
+ else
+ req->timeout = PS_TIMEOUT_OTHER;
+ req->retries = PS_RETRY;
-static int pscsi_CDB_none(struct se_task *task)
-{
- return pscsi_blk_get_request(task);
-}
+ blk_execute_rq_nowait(pdv->pdv_sd->request_queue, NULL, req,
+ (task->task_se_cmd->sam_task_attr == MSG_HEAD_TAG),
+ pscsi_req_done);
-/* pscsi_get_cdb():
- *
- *
- */
-static unsigned char *pscsi_get_cdb(struct se_task *task)
-{
- struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
- return pt->pscsi_cdb;
+fail:
+ while (hbio) {
+ struct bio *bio = hbio;
+ hbio = hbio->bi_next;
+ bio->bi_next = NULL;
+ bio_endio(bio, 0); /* XXX: should be error */
+ }
+ return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
}
/* pscsi_get_sense_buffer():
@@ -1328,23 +1214,13 @@ static void pscsi_req_done(struct request *req, int uptodate)
pt->pscsi_resid = req->resid_len;
pscsi_process_SAM_status(task, pt);
- /*
- * Release BIDI-READ if present
- */
- if (req->next_rq != NULL)
- __blk_put_request(req->q, req->next_rq);
-
__blk_put_request(req->q, req);
- pt->pscsi_req = NULL;
}
static struct se_subsystem_api pscsi_template = {
.name = "pscsi",
.owner = THIS_MODULE,
.transport_type = TRANSPORT_PLUGIN_PHBA_PDEV,
- .cdb_none = pscsi_CDB_none,
- .map_control_SG = pscsi_map_SG,
- .map_data_SG = pscsi_map_SG,
.attach_hba = pscsi_attach_hba,
.detach_hba = pscsi_detach_hba,
.pmode_enable_hba = pscsi_pmode_enable_hba,
@@ -1358,7 +1234,6 @@ static struct se_subsystem_api pscsi_template = {
.check_configfs_dev_params = pscsi_check_configfs_dev_params,
.set_configfs_dev_params = pscsi_set_configfs_dev_params,
.show_configfs_dev_params = pscsi_show_configfs_dev_params,
- .get_cdb = pscsi_get_cdb,
.get_sense_buffer = pscsi_get_sense_buffer,
.get_device_rev = pscsi_get_device_rev,
.get_device_type = pscsi_get_device_type,
diff --git a/drivers/target/target_core_pscsi.h b/drivers/target/target_core_pscsi.h
index ebf4f1ae2c83..fdc17b6aefb3 100644
--- a/drivers/target/target_core_pscsi.h
+++ b/drivers/target/target_core_pscsi.h
@@ -27,7 +27,6 @@ struct pscsi_plugin_task {
int pscsi_direction;
int pscsi_result;
u32 pscsi_resid;
- struct request *pscsi_req;
unsigned char pscsi_cdb[0];
} ____cacheline_aligned;
diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c
index 3dd81d24d9a9..5158d3846f19 100644
--- a/drivers/target/target_core_rd.c
+++ b/drivers/target/target_core_rd.c
@@ -27,7 +27,6 @@
*
******************************************************************************/
-#include <linux/version.h>
#include <linux/string.h>
#include <linux/parser.h>
#include <linux/timer.h>
@@ -351,7 +350,7 @@ static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page)
static int rd_MEMCPY_read(struct rd_request *req)
{
struct se_task *task = &req->rd_task;
- struct rd_dev *dev = req->rd_task.se_dev->dev_ptr;
+ struct rd_dev *dev = req->rd_task.task_se_cmd->se_dev->dev_ptr;
struct rd_dev_sg_table *table;
struct scatterlist *sg_d, *sg_s;
void *dst, *src;
@@ -390,12 +389,10 @@ static int rd_MEMCPY_read(struct rd_request *req)
length = req->rd_size;
dst = sg_virt(&sg_d[i++]) + dst_offset;
- if (!dst)
- BUG();
+ BUG_ON(!dst);
src = sg_virt(&sg_s[j]) + src_offset;
- if (!src)
- BUG();
+ BUG_ON(!src);
dst_offset = 0;
src_offset = length;
@@ -415,8 +412,7 @@ static int rd_MEMCPY_read(struct rd_request *req)
length = req->rd_size;
dst = sg_virt(&sg_d[i]) + dst_offset;
- if (!dst)
- BUG();
+ BUG_ON(!dst);
if (sg_d[i].length == length) {
i++;
@@ -425,8 +421,7 @@ static int rd_MEMCPY_read(struct rd_request *req)
dst_offset = length;
src = sg_virt(&sg_s[j++]) + src_offset;
- if (!src)
- BUG();
+ BUG_ON(!src);
src_offset = 0;
page_end = 1;
@@ -471,7 +466,7 @@ static int rd_MEMCPY_read(struct rd_request *req)
static int rd_MEMCPY_write(struct rd_request *req)
{
struct se_task *task = &req->rd_task;
- struct rd_dev *dev = req->rd_task.se_dev->dev_ptr;
+ struct rd_dev *dev = req->rd_task.task_se_cmd->se_dev->dev_ptr;
struct rd_dev_sg_table *table;
struct scatterlist *sg_d, *sg_s;
void *dst, *src;
@@ -510,12 +505,10 @@ static int rd_MEMCPY_write(struct rd_request *req)
length = req->rd_size;
src = sg_virt(&sg_s[i++]) + src_offset;
- if (!src)
- BUG();
+ BUG_ON(!src);
dst = sg_virt(&sg_d[j]) + dst_offset;
- if (!dst)
- BUG();
+ BUG_ON(!dst);
src_offset = 0;
dst_offset = length;
@@ -535,8 +528,7 @@ static int rd_MEMCPY_write(struct rd_request *req)
length = req->rd_size;
src = sg_virt(&sg_s[i]) + src_offset;
- if (!src)
- BUG();
+ BUG_ON(!src);
if (sg_s[i].length == length) {
i++;
@@ -545,8 +537,7 @@ static int rd_MEMCPY_write(struct rd_request *req)
src_offset = length;
dst = sg_virt(&sg_d[j++]) + dst_offset;
- if (!dst)
- BUG();
+ BUG_ON(!dst);
dst_offset = 0;
page_end = 1;
@@ -590,7 +581,7 @@ static int rd_MEMCPY_write(struct rd_request *req)
*/
static int rd_MEMCPY_do_task(struct se_task *task)
{
- struct se_device *dev = task->se_dev;
+ struct se_device *dev = task->task_se_cmd->se_dev;
struct rd_request *req = RD_REQ(task);
unsigned long long lba;
int ret;
@@ -700,17 +691,6 @@ static ssize_t rd_show_configfs_dev_params(
return bl;
}
-/* rd_get_cdb(): (Part of se_subsystem_api_t template)
- *
- *
- */
-static unsigned char *rd_get_cdb(struct se_task *task)
-{
- struct rd_request *req = RD_REQ(task);
-
- return req->rd_scsi_cdb;
-}
-
static u32 rd_get_device_rev(struct se_device *dev)
{
return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */
@@ -744,7 +724,6 @@ static struct se_subsystem_api rd_mcp_template = {
.check_configfs_dev_params = rd_check_configfs_dev_params,
.set_configfs_dev_params = rd_set_configfs_dev_params,
.show_configfs_dev_params = rd_show_configfs_dev_params,
- .get_cdb = rd_get_cdb,
.get_device_rev = rd_get_device_rev,
.get_device_type = rd_get_device_type,
.get_blocks = rd_get_blocks,
diff --git a/drivers/target/target_core_rd.h b/drivers/target/target_core_rd.h
index 0d027732cd00..784e56a04100 100644
--- a/drivers/target/target_core_rd.h
+++ b/drivers/target/target_core_rd.h
@@ -22,8 +22,6 @@ void rd_module_exit(void);
struct rd_request {
struct se_task rd_task;
- /* SCSI CDB from iSCSI Command PDU */
- unsigned char rd_scsi_cdb[TCM_MAX_COMMAND_SIZE];
/* Offset from start of page */
u32 rd_offset;
/* Starting page in Ramdisk for request */
diff --git a/drivers/target/target_core_scdb.c b/drivers/target/target_core_scdb.c
deleted file mode 100644
index 72843441d4fa..000000000000
--- a/drivers/target/target_core_scdb.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/*******************************************************************************
- * Filename: target_core_scdb.c
- *
- * This file contains the generic target engine Split CDB related functions.
- *
- * Copyright (c) 2004-2005 PyX Technologies, Inc.
- * Copyright (c) 2005, 2006, 2007 SBE, Inc.
- * Copyright (c) 2007-2010 Rising Tide Systems
- * Copyright (c) 2008-2010 Linux-iSCSI.org
- *
- * Nicholas A. Bellinger <nab@kernel.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- ******************************************************************************/
-
-#include <linux/net.h>
-#include <linux/string.h>
-#include <scsi/scsi.h>
-#include <asm/unaligned.h>
-
-#include <target/target_core_base.h>
-#include <target/target_core_transport.h>
-
-#include "target_core_scdb.h"
-
-/* split_cdb_XX_6():
- *
- * 21-bit LBA w/ 8-bit SECTORS
- */
-void split_cdb_XX_6(
- unsigned long long lba,
- u32 sectors,
- unsigned char *cdb)
-{
- cdb[1] = (lba >> 16) & 0x1f;
- cdb[2] = (lba >> 8) & 0xff;
- cdb[3] = lba & 0xff;
- cdb[4] = sectors & 0xff;
-}
-
-/* split_cdb_XX_10():
- *
- * 32-bit LBA w/ 16-bit SECTORS
- */
-void split_cdb_XX_10(
- unsigned long long lba,
- u32 sectors,
- unsigned char *cdb)
-{
- put_unaligned_be32(lba, &cdb[2]);
- put_unaligned_be16(sectors, &cdb[7]);
-}
-
-/* split_cdb_XX_12():
- *
- * 32-bit LBA w/ 32-bit SECTORS
- */
-void split_cdb_XX_12(
- unsigned long long lba,
- u32 sectors,
- unsigned char *cdb)
-{
- put_unaligned_be32(lba, &cdb[2]);
- put_unaligned_be32(sectors, &cdb[6]);
-}
-
-/* split_cdb_XX_16():
- *
- * 64-bit LBA w/ 32-bit SECTORS
- */
-void split_cdb_XX_16(
- unsigned long long lba,
- u32 sectors,
- unsigned char *cdb)
-{
- put_unaligned_be64(lba, &cdb[2]);
- put_unaligned_be32(sectors, &cdb[10]);
-}
-
-/*
- * split_cdb_XX_32():
- *
- * 64-bit LBA w/ 32-bit SECTORS such as READ_32, WRITE_32 and emulated XDWRITEREAD_32
- */
-void split_cdb_XX_32(
- unsigned long long lba,
- u32 sectors,
- unsigned char *cdb)
-{
- put_unaligned_be64(lba, &cdb[12]);
- put_unaligned_be32(sectors, &cdb[28]);
-}
diff --git a/drivers/target/target_core_scdb.h b/drivers/target/target_core_scdb.h
deleted file mode 100644
index 48e9ccc9585e..000000000000
--- a/drivers/target/target_core_scdb.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef TARGET_CORE_SCDB_H
-#define TARGET_CORE_SCDB_H
-
-extern void split_cdb_XX_6(unsigned long long, u32, unsigned char *);
-extern void split_cdb_XX_10(unsigned long long, u32, unsigned char *);
-extern void split_cdb_XX_12(unsigned long long, u32, unsigned char *);
-extern void split_cdb_XX_16(unsigned long long, u32, unsigned char *);
-extern void split_cdb_XX_32(unsigned long long, u32, unsigned char *);
-
-#endif /* TARGET_CORE_SCDB_H */
diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c
index a8d6e1dee938..874152aed94a 100644
--- a/drivers/target/target_core_stat.c
+++ b/drivers/target/target_core_stat.c
@@ -32,7 +32,6 @@
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/string.h>
-#include <linux/version.h>
#include <generated/utsrelease.h>
#include <linux/utsname.h>
#include <linux/proc_fs.h>
diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c
index 27d4925e51c3..570b144a1edb 100644
--- a/drivers/target/target_core_tmr.c
+++ b/drivers/target/target_core_tmr.c
@@ -24,7 +24,6 @@
*
******************************************************************************/
-#include <linux/version.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/list.h>
@@ -44,12 +43,12 @@
struct se_tmr_req *core_tmr_alloc_req(
struct se_cmd *se_cmd,
void *fabric_tmr_ptr,
- u8 function)
+ u8 function,
+ gfp_t gfp_flags)
{
struct se_tmr_req *tmr;
- tmr = kmem_cache_zalloc(se_tmr_req_cache, (in_interrupt()) ?
- GFP_ATOMIC : GFP_KERNEL);
+ tmr = kmem_cache_zalloc(se_tmr_req_cache, gfp_flags);
if (!tmr) {
pr_err("Unable to allocate struct se_tmr_req\n");
return ERR_PTR(-ENOMEM);
@@ -67,15 +66,16 @@ void core_tmr_release_req(
struct se_tmr_req *tmr)
{
struct se_device *dev = tmr->tmr_dev;
+ unsigned long flags;
if (!dev) {
kmem_cache_free(se_tmr_req_cache, tmr);
return;
}
- spin_lock_irq(&dev->se_tmr_lock);
+ spin_lock_irqsave(&dev->se_tmr_lock, flags);
list_del(&tmr->tmr_list);
- spin_unlock_irq(&dev->se_tmr_lock);
+ spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
kmem_cache_free(se_tmr_req_cache, tmr);
}
@@ -100,54 +100,20 @@ static void core_tmr_handle_tas_abort(
transport_cmd_finish_abort(cmd, 0);
}
-int core_tmr_lun_reset(
+static void core_tmr_drain_tmr_list(
struct se_device *dev,
struct se_tmr_req *tmr,
- struct list_head *preempt_and_abort_list,
- struct se_cmd *prout_cmd)
+ struct list_head *preempt_and_abort_list)
{
- struct se_cmd *cmd, *tcmd;
- struct se_node_acl *tmr_nacl = NULL;
- struct se_portal_group *tmr_tpg = NULL;
- struct se_queue_obj *qobj = &dev->dev_queue_obj;
+ LIST_HEAD(drain_tmr_list);
struct se_tmr_req *tmr_p, *tmr_pp;
- struct se_task *task, *task_tmp;
+ struct se_cmd *cmd;
unsigned long flags;
- int fe_count, tas;
- /*
- * TASK_ABORTED status bit, this is configurable via ConfigFS
- * struct se_device attributes. spc4r17 section 7.4.6 Control mode page
- *
- * A task aborted status (TAS) bit set to zero specifies that aborted
- * tasks shall be terminated by the device server without any response
- * to the application client. A TAS bit set to one specifies that tasks
- * aborted by the actions of an I_T nexus other than the I_T nexus on
- * which the command was received shall be completed with TASK ABORTED
- * status (see SAM-4).
- */
- tas = dev->se_sub_dev->se_dev_attrib.emulate_tas;
- /*
- * Determine if this se_tmr is coming from a $FABRIC_MOD
- * or struct se_device passthrough..
- */
- if (tmr && tmr->task_cmd && tmr->task_cmd->se_sess) {
- tmr_nacl = tmr->task_cmd->se_sess->se_node_acl;
- tmr_tpg = tmr->task_cmd->se_sess->se_tpg;
- if (tmr_nacl && tmr_tpg) {
- pr_debug("LUN_RESET: TMR caller fabric: %s"
- " initiator port %s\n",
- tmr_tpg->se_tpg_tfo->get_fabric_name(),
- tmr_nacl->initiatorname);
- }
- }
- pr_debug("LUN_RESET: %s starting for [%s], tas: %d\n",
- (preempt_and_abort_list) ? "Preempt" : "TMR",
- dev->transport->name, tas);
/*
* Release all pending and outgoing TMRs aside from the received
* LUN_RESET tmr..
*/
- spin_lock_irq(&dev->se_tmr_lock);
+ spin_lock_irqsave(&dev->se_tmr_lock, flags);
list_for_each_entry_safe(tmr_p, tmr_pp, &dev->dev_tmr_list, tmr_list) {
/*
* Allow the received TMR to return with FUNCTION_COMPLETE.
@@ -169,29 +135,48 @@ int core_tmr_lun_reset(
(core_scsi3_check_cdb_abort_and_preempt(
preempt_and_abort_list, cmd) != 0))
continue;
- spin_unlock_irq(&dev->se_tmr_lock);
- spin_lock_irqsave(&cmd->t_state_lock, flags);
+ spin_lock(&cmd->t_state_lock);
if (!atomic_read(&cmd->t_transport_active)) {
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- spin_lock_irq(&dev->se_tmr_lock);
+ spin_unlock(&cmd->t_state_lock);
continue;
}
if (cmd->t_state == TRANSPORT_ISTATE_PROCESSING) {
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- spin_lock_irq(&dev->se_tmr_lock);
+ spin_unlock(&cmd->t_state_lock);
continue;
}
+ spin_unlock(&cmd->t_state_lock);
+
+ list_move_tail(&tmr->tmr_list, &drain_tmr_list);
+ }
+ spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
+
+ while (!list_empty(&drain_tmr_list)) {
+ tmr = list_entry(drain_tmr_list.next, struct se_tmr_req, tmr_list);
+ list_del(&tmr->tmr_list);
+ cmd = tmr_p->task_cmd;
+
pr_debug("LUN_RESET: %s releasing TMR %p Function: 0x%02x,"
" Response: 0x%02x, t_state: %d\n",
- (preempt_and_abort_list) ? "Preempt" : "", tmr_p,
- tmr_p->function, tmr_p->response, cmd->t_state);
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+ (preempt_and_abort_list) ? "Preempt" : "", tmr,
+ tmr->function, tmr->response, cmd->t_state);
- transport_cmd_finish_abort_tmr(cmd);
- spin_lock_irq(&dev->se_tmr_lock);
+ transport_cmd_finish_abort(cmd, 1);
}
- spin_unlock_irq(&dev->se_tmr_lock);
+}
+
+static void core_tmr_drain_task_list(
+ struct se_device *dev,
+ struct se_cmd *prout_cmd,
+ struct se_node_acl *tmr_nacl,
+ int tas,
+ struct list_head *preempt_and_abort_list)
+{
+ LIST_HEAD(drain_task_list);
+ struct se_cmd *cmd;
+ struct se_task *task, *task_tmp;
+ unsigned long flags;
+ int fe_count;
/*
* Complete outstanding struct se_task CDBs with TASK_ABORTED SAM status.
* This is following sam4r17, section 5.6 Aborting commands, Table 38
@@ -236,18 +221,28 @@ int core_tmr_lun_reset(
if (prout_cmd == cmd)
continue;
- list_del(&task->t_state_list);
+ list_move_tail(&task->t_state_list, &drain_task_list);
atomic_set(&task->task_state_active, 0);
- spin_unlock_irqrestore(&dev->execute_task_lock, flags);
+ /*
+ * Remove from task execute list before processing drain_task_list
+ */
+ if (!list_empty(&task->t_execute_list))
+ __transport_remove_task_from_execute_queue(task, dev);
+ }
+ spin_unlock_irqrestore(&dev->execute_task_lock, flags);
+
+ while (!list_empty(&drain_task_list)) {
+ task = list_entry(drain_task_list.next, struct se_task, t_state_list);
+ list_del(&task->t_state_list);
+ cmd = task->task_se_cmd;
- spin_lock_irqsave(&cmd->t_state_lock, flags);
pr_debug("LUN_RESET: %s cmd: %p task: %p"
- " ITT/CmdSN: 0x%08x/0x%08x, i_state: %d, t_state/"
- "def_t_state: %d/%d cdb: 0x%02x\n",
+ " ITT/CmdSN: 0x%08x/0x%08x, i_state: %d, t_state: %d"
+ "cdb: 0x%02x\n",
(preempt_and_abort_list) ? "Preempt" : "", cmd, task,
cmd->se_tfo->get_task_tag(cmd), 0,
cmd->se_tfo->get_cmd_state(cmd), cmd->t_state,
- cmd->deferred_t_state, cmd->t_task_cdb[0]);
+ cmd->t_task_cdb[0]);
pr_debug("LUN_RESET: ITT[0x%08x] - pr_res_key: 0x%016Lx"
" t_task_cdbs: %d t_task_cdbs_left: %d"
" t_task_cdbs_sent: %d -- t_transport_active: %d"
@@ -260,35 +255,24 @@ int core_tmr_lun_reset(
atomic_read(&cmd->t_transport_stop),
atomic_read(&cmd->t_transport_sent));
- if (atomic_read(&task->task_active)) {
- atomic_set(&task->task_stop, 1);
- spin_unlock_irqrestore(
- &cmd->t_state_lock, flags);
-
- pr_debug("LUN_RESET: Waiting for task: %p to shutdown"
- " for dev: %p\n", task, dev);
- wait_for_completion(&task->task_stop_comp);
- pr_debug("LUN_RESET Completed task: %p shutdown for"
- " dev: %p\n", task, dev);
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- atomic_dec(&cmd->t_task_cdbs_left);
-
- atomic_set(&task->task_active, 0);
- atomic_set(&task->task_stop, 0);
- } else {
- if (atomic_read(&task->task_execute_queue) != 0)
- transport_remove_task_from_execute_queue(task, dev);
- }
- __transport_stop_task_timer(task, &flags);
+ /*
+ * If the command may be queued onto a workqueue cancel it now.
+ *
+ * This is equivalent to removal from the execute queue in the
+ * loop above, but we do it down here given that
+ * cancel_work_sync may block.
+ */
+ if (cmd->t_state == TRANSPORT_COMPLETE)
+ cancel_work_sync(&cmd->work);
+
+ spin_lock_irqsave(&cmd->t_state_lock, flags);
+ target_stop_task(task, &flags);
if (!atomic_dec_and_test(&cmd->t_task_cdbs_ex_left)) {
- spin_unlock_irqrestore(
- &cmd->t_state_lock, flags);
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
pr_debug("LUN_RESET: Skipping task: %p, dev: %p for"
" t_task_cdbs_ex_left: %d\n", task, dev,
atomic_read(&cmd->t_task_cdbs_ex_left));
-
- spin_lock_irqsave(&dev->execute_task_lock, flags);
continue;
}
fe_count = atomic_read(&cmd->t_fe_count);
@@ -298,22 +282,31 @@ int core_tmr_lun_reset(
" task: %p, t_fe_count: %d dev: %p\n", task,
fe_count, dev);
atomic_set(&cmd->t_transport_aborted, 1);
- spin_unlock_irqrestore(&cmd->t_state_lock,
- flags);
- core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- spin_lock_irqsave(&dev->execute_task_lock, flags);
+ core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
continue;
}
pr_debug("LUN_RESET: Got t_transport_active = 0 for task: %p,"
" t_fe_count: %d dev: %p\n", task, fe_count, dev);
atomic_set(&cmd->t_transport_aborted, 1);
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
- spin_lock_irqsave(&dev->execute_task_lock, flags);
+ core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
}
- spin_unlock_irqrestore(&dev->execute_task_lock, flags);
+}
+
+static void core_tmr_drain_cmd_list(
+ struct se_device *dev,
+ struct se_cmd *prout_cmd,
+ struct se_node_acl *tmr_nacl,
+ int tas,
+ struct list_head *preempt_and_abort_list)
+{
+ LIST_HEAD(drain_cmd_list);
+ struct se_queue_obj *qobj = &dev->dev_queue_obj;
+ struct se_cmd *cmd, *tcmd;
+ unsigned long flags;
/*
* Release all commands remaining in the struct se_device cmd queue.
*
@@ -337,11 +330,26 @@ int core_tmr_lun_reset(
*/
if (prout_cmd == cmd)
continue;
+ /*
+ * Skip direct processing of TRANSPORT_FREE_CMD_INTR for
+ * HW target mode fabrics.
+ */
+ spin_lock(&cmd->t_state_lock);
+ if (cmd->t_state == TRANSPORT_FREE_CMD_INTR) {
+ spin_unlock(&cmd->t_state_lock);
+ continue;
+ }
+ spin_unlock(&cmd->t_state_lock);
- atomic_dec(&cmd->t_transport_queue_active);
+ atomic_set(&cmd->t_transport_queue_active, 0);
atomic_dec(&qobj->queue_cnt);
- list_del(&cmd->se_queue_node);
- spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
+ list_move_tail(&cmd->se_queue_node, &drain_cmd_list);
+ }
+ spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
+
+ while (!list_empty(&drain_cmd_list)) {
+ cmd = list_entry(drain_cmd_list.next, struct se_cmd, se_queue_node);
+ list_del_init(&cmd->se_queue_node);
pr_debug("LUN_RESET: %s from Device Queue: cmd: %p t_state:"
" %d t_fe_count: %d\n", (preempt_and_abort_list) ?
@@ -354,9 +362,53 @@ int core_tmr_lun_reset(
core_tmr_handle_tas_abort(tmr_nacl, cmd, tas,
atomic_read(&cmd->t_fe_count));
- spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
}
- spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
+}
+
+int core_tmr_lun_reset(
+ struct se_device *dev,
+ struct se_tmr_req *tmr,
+ struct list_head *preempt_and_abort_list,
+ struct se_cmd *prout_cmd)
+{
+ struct se_node_acl *tmr_nacl = NULL;
+ struct se_portal_group *tmr_tpg = NULL;
+ int tas;
+ /*
+ * TASK_ABORTED status bit, this is configurable via ConfigFS
+ * struct se_device attributes. spc4r17 section 7.4.6 Control mode page
+ *
+ * A task aborted status (TAS) bit set to zero specifies that aborted
+ * tasks shall be terminated by the device server without any response
+ * to the application client. A TAS bit set to one specifies that tasks
+ * aborted by the actions of an I_T nexus other than the I_T nexus on
+ * which the command was received shall be completed with TASK ABORTED
+ * status (see SAM-4).
+ */
+ tas = dev->se_sub_dev->se_dev_attrib.emulate_tas;
+ /*
+ * Determine if this se_tmr is coming from a $FABRIC_MOD
+ * or struct se_device passthrough..
+ */
+ if (tmr && tmr->task_cmd && tmr->task_cmd->se_sess) {
+ tmr_nacl = tmr->task_cmd->se_sess->se_node_acl;
+ tmr_tpg = tmr->task_cmd->se_sess->se_tpg;
+ if (tmr_nacl && tmr_tpg) {
+ pr_debug("LUN_RESET: TMR caller fabric: %s"
+ " initiator port %s\n",
+ tmr_tpg->se_tpg_tfo->get_fabric_name(),
+ tmr_nacl->initiatorname);
+ }
+ }
+ pr_debug("LUN_RESET: %s starting for [%s], tas: %d\n",
+ (preempt_and_abort_list) ? "Preempt" : "TMR",
+ dev->transport->name, tas);
+
+ core_tmr_drain_tmr_list(dev, tmr, preempt_and_abort_list);
+ core_tmr_drain_task_list(dev, prout_cmd, tmr_nacl, tas,
+ preempt_and_abort_list);
+ core_tmr_drain_cmd_list(dev, prout_cmd, tmr_nacl, tas,
+ preempt_and_abort_list);
/*
* Clear any legacy SPC-2 reservation when called during
* LOGICAL UNIT RESET
@@ -379,3 +431,4 @@ int core_tmr_lun_reset(
dev->transport->name);
return 0;
}
+
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index 4f1ba4c5ef11..49fd0a9b0a56 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -137,15 +137,15 @@ struct se_node_acl *core_tpg_get_initiator_node_acl(
{
struct se_node_acl *acl;
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
list_for_each_entry(acl, &tpg->acl_node_list, acl_list) {
if (!strcmp(acl->initiatorname, initiatorname) &&
!acl->dynamic_node_acl) {
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
return acl;
}
}
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
return NULL;
}
@@ -298,13 +298,21 @@ struct se_node_acl *core_tpg_check_initiator_node_acl(
tpg->se_tpg_tfo->tpg_release_fabric_acl(tpg, acl);
return NULL;
}
+ /*
+ * Here we only create demo-mode MappedLUNs from the active
+ * TPG LUNs if the fabric is not explictly asking for
+ * tpg_check_demo_mode_login_only() == 1.
+ */
+ if ((tpg->se_tpg_tfo->tpg_check_demo_mode_login_only != NULL) &&
+ (tpg->se_tpg_tfo->tpg_check_demo_mode_login_only(tpg) == 1))
+ do { ; } while (0);
+ else
+ core_tpg_add_node_to_devs(acl, tpg);
- core_tpg_add_node_to_devs(acl, tpg);
-
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
list_add_tail(&acl->acl_list, &tpg->acl_node_list);
tpg->num_node_acls++;
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
pr_debug("%s_TPG[%u] - Added DYNAMIC ACL with TCQ Depth: %d for %s"
" Initiator Node: %s\n", tpg->se_tpg_tfo->get_fabric_name(),
@@ -354,7 +362,7 @@ struct se_node_acl *core_tpg_add_initiator_node_acl(
{
struct se_node_acl *acl = NULL;
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname);
if (acl) {
if (acl->dynamic_node_acl) {
@@ -362,7 +370,7 @@ struct se_node_acl *core_tpg_add_initiator_node_acl(
pr_debug("%s_TPG[%u] - Replacing dynamic ACL"
" for %s\n", tpg->se_tpg_tfo->get_fabric_name(),
tpg->se_tpg_tfo->tpg_get_tag(tpg), initiatorname);
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
/*
* Release the locally allocated struct se_node_acl
* because * core_tpg_add_initiator_node_acl() returned
@@ -378,10 +386,10 @@ struct se_node_acl *core_tpg_add_initiator_node_acl(
" Node %s already exists for TPG %u, ignoring"
" request.\n", tpg->se_tpg_tfo->get_fabric_name(),
initiatorname, tpg->se_tpg_tfo->tpg_get_tag(tpg));
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
return ERR_PTR(-EEXIST);
}
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
if (!se_nacl) {
pr_err("struct se_node_acl pointer is NULL\n");
@@ -418,10 +426,10 @@ struct se_node_acl *core_tpg_add_initiator_node_acl(
return ERR_PTR(-EINVAL);
}
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
list_add_tail(&acl->acl_list, &tpg->acl_node_list);
tpg->num_node_acls++;
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
done:
pr_debug("%s_TPG[%hu] - Added ACL with TCQ Depth: %d for %s"
@@ -445,14 +453,14 @@ int core_tpg_del_initiator_node_acl(
struct se_session *sess, *sess_tmp;
int dynamic_acl = 0;
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
if (acl->dynamic_node_acl) {
acl->dynamic_node_acl = 0;
dynamic_acl = 1;
}
list_del(&acl->acl_list);
tpg->num_node_acls--;
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
spin_lock_bh(&tpg->session_lock);
list_for_each_entry_safe(sess, sess_tmp,
@@ -503,21 +511,21 @@ int core_tpg_set_initiator_node_queue_depth(
struct se_node_acl *acl;
int dynamic_acl = 0;
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname);
if (!acl) {
pr_err("Access Control List entry for %s Initiator"
" Node %s does not exists for TPG %hu, ignoring"
" request.\n", tpg->se_tpg_tfo->get_fabric_name(),
initiatorname, tpg->se_tpg_tfo->tpg_get_tag(tpg));
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
return -ENODEV;
}
if (acl->dynamic_node_acl) {
acl->dynamic_node_acl = 0;
dynamic_acl = 1;
}
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
spin_lock_bh(&tpg->session_lock);
list_for_each_entry(sess, &tpg->tpg_sess_list, sess_list) {
@@ -533,10 +541,10 @@ int core_tpg_set_initiator_node_queue_depth(
tpg->se_tpg_tfo->get_fabric_name(), initiatorname);
spin_unlock_bh(&tpg->session_lock);
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
if (dynamic_acl)
acl->dynamic_node_acl = 1;
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
return -EEXIST;
}
/*
@@ -571,10 +579,10 @@ int core_tpg_set_initiator_node_queue_depth(
if (init_sess)
tpg->se_tpg_tfo->close_session(init_sess);
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
if (dynamic_acl)
acl->dynamic_node_acl = 1;
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
return -EINVAL;
}
spin_unlock_bh(&tpg->session_lock);
@@ -585,15 +593,15 @@ int core_tpg_set_initiator_node_queue_depth(
if (init_sess)
tpg->se_tpg_tfo->close_session(init_sess);
- pr_debug("Successfuly changed queue depth to: %d for Initiator"
+ pr_debug("Successfully changed queue depth to: %d for Initiator"
" Node: %s on %s Target Portal Group: %u\n", queue_depth,
initiatorname, tpg->se_tpg_tfo->get_fabric_name(),
tpg->se_tpg_tfo->tpg_get_tag(tpg));
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
if (dynamic_acl)
acl->dynamic_node_acl = 1;
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
return 0;
}
@@ -717,20 +725,20 @@ int core_tpg_deregister(struct se_portal_group *se_tpg)
* not been released because of TFO->tpg_check_demo_mode_cache() == 1
* in transport_deregister_session().
*/
- spin_lock_bh(&se_tpg->acl_node_lock);
+ spin_lock_irq(&se_tpg->acl_node_lock);
list_for_each_entry_safe(nacl, nacl_tmp, &se_tpg->acl_node_list,
acl_list) {
list_del(&nacl->acl_list);
se_tpg->num_node_acls--;
- spin_unlock_bh(&se_tpg->acl_node_lock);
+ spin_unlock_irq(&se_tpg->acl_node_lock);
core_tpg_wait_for_nacl_pr_ref(nacl);
core_free_device_list_for_node(nacl, se_tpg);
se_tpg->se_tpg_tfo->tpg_release_fabric_acl(se_tpg, nacl);
- spin_lock_bh(&se_tpg->acl_node_lock);
+ spin_lock_irq(&se_tpg->acl_node_lock);
}
- spin_unlock_bh(&se_tpg->acl_node_lock);
+ spin_unlock_irq(&se_tpg->acl_node_lock);
if (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL)
core_tpg_release_virtual_lun0(se_tpg);
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 89760329d5d0..d75255804481 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -26,7 +26,6 @@
*
******************************************************************************/
-#include <linux/version.h>
#include <linux/net.h>
#include <linux/delay.h>
#include <linux/string.h>
@@ -55,11 +54,11 @@
#include "target_core_alua.h"
#include "target_core_hba.h"
#include "target_core_pr.h"
-#include "target_core_scdb.h"
#include "target_core_ua.h"
static int sub_api_initialized;
+static struct workqueue_struct *target_completion_wq;
static struct kmem_cache *se_cmd_cache;
static struct kmem_cache *se_sess_cache;
struct kmem_cache *se_tmr_req_cache;
@@ -70,30 +69,19 @@ struct kmem_cache *t10_alua_lu_gp_mem_cache;
struct kmem_cache *t10_alua_tg_pt_gp_cache;
struct kmem_cache *t10_alua_tg_pt_gp_mem_cache;
-/* Used for transport_dev_get_map_*() */
-typedef int (*map_func_t)(struct se_task *, u32);
-
static int transport_generic_write_pending(struct se_cmd *);
static int transport_processing_thread(void *param);
static int __transport_execute_tasks(struct se_device *dev);
static void transport_complete_task_attr(struct se_cmd *cmd);
-static int transport_complete_qf(struct se_cmd *cmd);
static void transport_handle_queue_full(struct se_cmd *cmd,
- struct se_device *dev, int (*qf_callback)(struct se_cmd *));
-static void transport_direct_request_timeout(struct se_cmd *cmd);
+ struct se_device *dev);
static void transport_free_dev_tasks(struct se_cmd *cmd);
-static u32 transport_allocate_tasks(struct se_cmd *cmd,
- unsigned long long starting_lba,
- enum dma_data_direction data_direction,
- struct scatterlist *sgl, unsigned int nents);
static int transport_generic_get_mem(struct se_cmd *cmd);
-static int transport_generic_remove(struct se_cmd *cmd,
- int session_reinstatement);
-static void transport_release_fe_cmd(struct se_cmd *cmd);
-static void transport_remove_cmd_from_queue(struct se_cmd *cmd,
- struct se_queue_obj *qobj);
+static void transport_put_cmd(struct se_cmd *cmd);
+static void transport_remove_cmd_from_queue(struct se_cmd *cmd);
static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq);
-static void transport_stop_all_task_timers(struct se_cmd *cmd);
+static void transport_generic_request_failure(struct se_cmd *, int, int);
+static void target_complete_ok_work(struct work_struct *work);
int init_se_kmem_caches(void)
{
@@ -109,7 +97,7 @@ int init_se_kmem_caches(void)
if (!se_tmr_req_cache) {
pr_err("kmem_cache_create() for struct se_tmr_req"
" failed\n");
- goto out;
+ goto out_free_cmd_cache;
}
se_sess_cache = kmem_cache_create("se_sess_cache",
sizeof(struct se_session), __alignof__(struct se_session),
@@ -117,14 +105,14 @@ int init_se_kmem_caches(void)
if (!se_sess_cache) {
pr_err("kmem_cache_create() for struct se_session"
" failed\n");
- goto out;
+ goto out_free_tmr_req_cache;
}
se_ua_cache = kmem_cache_create("se_ua_cache",
sizeof(struct se_ua), __alignof__(struct se_ua),
0, NULL);
if (!se_ua_cache) {
pr_err("kmem_cache_create() for struct se_ua failed\n");
- goto out;
+ goto out_free_sess_cache;
}
t10_pr_reg_cache = kmem_cache_create("t10_pr_reg_cache",
sizeof(struct t10_pr_registration),
@@ -132,7 +120,7 @@ int init_se_kmem_caches(void)
if (!t10_pr_reg_cache) {
pr_err("kmem_cache_create() for struct t10_pr_registration"
" failed\n");
- goto out;
+ goto out_free_ua_cache;
}
t10_alua_lu_gp_cache = kmem_cache_create("t10_alua_lu_gp_cache",
sizeof(struct t10_alua_lu_gp), __alignof__(struct t10_alua_lu_gp),
@@ -140,7 +128,7 @@ int init_se_kmem_caches(void)
if (!t10_alua_lu_gp_cache) {
pr_err("kmem_cache_create() for t10_alua_lu_gp_cache"
" failed\n");
- goto out;
+ goto out_free_pr_reg_cache;
}
t10_alua_lu_gp_mem_cache = kmem_cache_create("t10_alua_lu_gp_mem_cache",
sizeof(struct t10_alua_lu_gp_member),
@@ -148,7 +136,7 @@ int init_se_kmem_caches(void)
if (!t10_alua_lu_gp_mem_cache) {
pr_err("kmem_cache_create() for t10_alua_lu_gp_mem_"
"cache failed\n");
- goto out;
+ goto out_free_lu_gp_cache;
}
t10_alua_tg_pt_gp_cache = kmem_cache_create("t10_alua_tg_pt_gp_cache",
sizeof(struct t10_alua_tg_pt_gp),
@@ -156,7 +144,7 @@ int init_se_kmem_caches(void)
if (!t10_alua_tg_pt_gp_cache) {
pr_err("kmem_cache_create() for t10_alua_tg_pt_gp_"
"cache failed\n");
- goto out;
+ goto out_free_lu_gp_mem_cache;
}
t10_alua_tg_pt_gp_mem_cache = kmem_cache_create(
"t10_alua_tg_pt_gp_mem_cache",
@@ -166,34 +154,41 @@ int init_se_kmem_caches(void)
if (!t10_alua_tg_pt_gp_mem_cache) {
pr_err("kmem_cache_create() for t10_alua_tg_pt_gp_"
"mem_t failed\n");
- goto out;
+ goto out_free_tg_pt_gp_cache;
}
+ target_completion_wq = alloc_workqueue("target_completion",
+ WQ_MEM_RECLAIM, 0);
+ if (!target_completion_wq)
+ goto out_free_tg_pt_gp_mem_cache;
+
return 0;
+
+out_free_tg_pt_gp_mem_cache:
+ kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache);
+out_free_tg_pt_gp_cache:
+ kmem_cache_destroy(t10_alua_tg_pt_gp_cache);
+out_free_lu_gp_mem_cache:
+ kmem_cache_destroy(t10_alua_lu_gp_mem_cache);
+out_free_lu_gp_cache:
+ kmem_cache_destroy(t10_alua_lu_gp_cache);
+out_free_pr_reg_cache:
+ kmem_cache_destroy(t10_pr_reg_cache);
+out_free_ua_cache:
+ kmem_cache_destroy(se_ua_cache);
+out_free_sess_cache:
+ kmem_cache_destroy(se_sess_cache);
+out_free_tmr_req_cache:
+ kmem_cache_destroy(se_tmr_req_cache);
+out_free_cmd_cache:
+ kmem_cache_destroy(se_cmd_cache);
out:
- if (se_cmd_cache)
- kmem_cache_destroy(se_cmd_cache);
- if (se_tmr_req_cache)
- kmem_cache_destroy(se_tmr_req_cache);
- if (se_sess_cache)
- kmem_cache_destroy(se_sess_cache);
- if (se_ua_cache)
- kmem_cache_destroy(se_ua_cache);
- if (t10_pr_reg_cache)
- kmem_cache_destroy(t10_pr_reg_cache);
- if (t10_alua_lu_gp_cache)
- kmem_cache_destroy(t10_alua_lu_gp_cache);
- if (t10_alua_lu_gp_mem_cache)
- kmem_cache_destroy(t10_alua_lu_gp_mem_cache);
- if (t10_alua_tg_pt_gp_cache)
- kmem_cache_destroy(t10_alua_tg_pt_gp_cache);
- if (t10_alua_tg_pt_gp_mem_cache)
- kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache);
return -ENOMEM;
}
void release_se_kmem_caches(void)
{
+ destroy_workqueue(target_completion_wq);
kmem_cache_destroy(se_cmd_cache);
kmem_cache_destroy(se_tmr_req_cache);
kmem_cache_destroy(se_sess_cache);
@@ -234,10 +229,13 @@ void transport_init_queue_obj(struct se_queue_obj *qobj)
}
EXPORT_SYMBOL(transport_init_queue_obj);
-static int transport_subsystem_reqmods(void)
+void transport_subsystem_check_init(void)
{
int ret;
+ if (sub_api_initialized)
+ return;
+
ret = request_module("target_core_iblock");
if (ret != 0)
pr_err("Unable to load target_core_iblock\n");
@@ -254,24 +252,8 @@ static int transport_subsystem_reqmods(void)
if (ret != 0)
pr_err("Unable to load target_core_stgt\n");
- return 0;
-}
-
-int transport_subsystem_check_init(void)
-{
- int ret;
-
- if (sub_api_initialized)
- return 0;
- /*
- * Request the loading of known TCM subsystem plugins..
- */
- ret = transport_subsystem_reqmods();
- if (ret < 0)
- return ret;
-
sub_api_initialized = 1;
- return 0;
+ return;
}
struct se_session *transport_init_session(void)
@@ -389,17 +371,18 @@ void transport_deregister_session(struct se_session *se_sess)
{
struct se_portal_group *se_tpg = se_sess->se_tpg;
struct se_node_acl *se_nacl;
+ unsigned long flags;
if (!se_tpg) {
transport_free_session(se_sess);
return;
}
- spin_lock_bh(&se_tpg->session_lock);
+ spin_lock_irqsave(&se_tpg->session_lock, flags);
list_del(&se_sess->sess_list);
se_sess->se_tpg = NULL;
se_sess->fabric_sess_ptr = NULL;
- spin_unlock_bh(&se_tpg->session_lock);
+ spin_unlock_irqrestore(&se_tpg->session_lock, flags);
/*
* Determine if we need to do extra work for this initiator node's
@@ -407,22 +390,22 @@ void transport_deregister_session(struct se_session *se_sess)
*/
se_nacl = se_sess->se_node_acl;
if (se_nacl) {
- spin_lock_bh(&se_tpg->acl_node_lock);
+ spin_lock_irqsave(&se_tpg->acl_node_lock, flags);
if (se_nacl->dynamic_node_acl) {
if (!se_tpg->se_tpg_tfo->tpg_check_demo_mode_cache(
se_tpg)) {
list_del(&se_nacl->acl_list);
se_tpg->num_node_acls--;
- spin_unlock_bh(&se_tpg->acl_node_lock);
+ spin_unlock_irqrestore(&se_tpg->acl_node_lock, flags);
core_tpg_wait_for_nacl_pr_ref(se_nacl);
core_free_device_list_for_node(se_nacl, se_tpg);
se_tpg->se_tpg_tfo->tpg_release_fabric_acl(se_tpg,
se_nacl);
- spin_lock_bh(&se_tpg->acl_node_lock);
+ spin_lock_irqsave(&se_tpg->acl_node_lock, flags);
}
}
- spin_unlock_bh(&se_tpg->acl_node_lock);
+ spin_unlock_irqrestore(&se_tpg->acl_node_lock, flags);
}
transport_free_session(se_sess);
@@ -437,16 +420,15 @@ EXPORT_SYMBOL(transport_deregister_session);
*/
static void transport_all_task_dev_remove_state(struct se_cmd *cmd)
{
- struct se_device *dev;
+ struct se_device *dev = cmd->se_dev;
struct se_task *task;
unsigned long flags;
- list_for_each_entry(task, &cmd->t_task_list, t_list) {
- dev = task->se_dev;
- if (!dev)
- continue;
+ if (!dev)
+ return;
- if (atomic_read(&task->task_active))
+ list_for_each_entry(task, &cmd->t_task_list, t_list) {
+ if (task->task_flags & TF_ACTIVE)
continue;
if (!atomic_read(&task->task_state_active))
@@ -488,8 +470,6 @@ static int transport_cmd_check_stop(
" == TRUE for ITT: 0x%08x\n", __func__, __LINE__,
cmd->se_tfo->get_task_tag(cmd));
- cmd->deferred_t_state = cmd->t_state;
- cmd->t_state = TRANSPORT_DEFERRED_CMD;
atomic_set(&cmd->t_transport_active, 0);
if (transport_off == 2)
transport_all_task_dev_remove_state(cmd);
@@ -507,8 +487,6 @@ static int transport_cmd_check_stop(
" TRUE for ITT: 0x%08x\n", __func__, __LINE__,
cmd->se_tfo->get_task_tag(cmd));
- cmd->deferred_t_state = cmd->t_state;
- cmd->t_state = TRANSPORT_DEFERRED_CMD;
if (transport_off == 2)
transport_all_task_dev_remove_state(cmd);
@@ -593,35 +571,24 @@ check_lun:
void transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
{
- transport_remove_cmd_from_queue(cmd, &cmd->se_dev->dev_queue_obj);
- transport_lun_remove_cmd(cmd);
-
- if (transport_cmd_check_stop_to_fabric(cmd))
- return;
- if (remove)
- transport_generic_remove(cmd, 0);
-}
-
-void transport_cmd_finish_abort_tmr(struct se_cmd *cmd)
-{
- transport_remove_cmd_from_queue(cmd, &cmd->se_dev->dev_queue_obj);
+ if (!cmd->se_tmr_req)
+ transport_lun_remove_cmd(cmd);
if (transport_cmd_check_stop_to_fabric(cmd))
return;
-
- transport_generic_remove(cmd, 0);
+ if (remove) {
+ transport_remove_cmd_from_queue(cmd);
+ transport_put_cmd(cmd);
+ }
}
-static void transport_add_cmd_to_queue(
- struct se_cmd *cmd,
- int t_state)
+static void transport_add_cmd_to_queue(struct se_cmd *cmd, int t_state,
+ bool at_head)
{
struct se_device *dev = cmd->se_dev;
struct se_queue_obj *qobj = &dev->dev_queue_obj;
unsigned long flags;
- INIT_LIST_HEAD(&cmd->se_queue_node);
-
if (t_state) {
spin_lock_irqsave(&cmd->t_state_lock, flags);
cmd->t_state = t_state;
@@ -630,15 +597,20 @@ static void transport_add_cmd_to_queue(
}
spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
- if (cmd->se_cmd_flags & SCF_EMULATE_QUEUE_FULL) {
- cmd->se_cmd_flags &= ~SCF_EMULATE_QUEUE_FULL;
+
+ /* If the cmd is already on the list, remove it before we add it */
+ if (!list_empty(&cmd->se_queue_node))
+ list_del(&cmd->se_queue_node);
+ else
+ atomic_inc(&qobj->queue_cnt);
+
+ if (at_head)
list_add(&cmd->se_queue_node, &qobj->qobj_list);
- } else
+ else
list_add_tail(&cmd->se_queue_node, &qobj->qobj_list);
- atomic_inc(&cmd->t_transport_queue_active);
+ atomic_set(&cmd->t_transport_queue_active, 1);
spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
- atomic_inc(&qobj->queue_cnt);
wake_up_interruptible(&qobj->thread_wq);
}
@@ -655,19 +627,18 @@ transport_get_cmd_from_queue(struct se_queue_obj *qobj)
}
cmd = list_first_entry(&qobj->qobj_list, struct se_cmd, se_queue_node);
- atomic_dec(&cmd->t_transport_queue_active);
+ atomic_set(&cmd->t_transport_queue_active, 0);
- list_del(&cmd->se_queue_node);
+ list_del_init(&cmd->se_queue_node);
atomic_dec(&qobj->queue_cnt);
spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
return cmd;
}
-static void transport_remove_cmd_from_queue(struct se_cmd *cmd,
- struct se_queue_obj *qobj)
+static void transport_remove_cmd_from_queue(struct se_cmd *cmd)
{
- struct se_cmd *t;
+ struct se_queue_obj *qobj = &cmd->se_dev->dev_queue_obj;
unsigned long flags;
spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
@@ -675,14 +646,9 @@ static void transport_remove_cmd_from_queue(struct se_cmd *cmd,
spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
return;
}
-
- list_for_each_entry(t, &qobj->qobj_list, se_queue_node)
- if (t == cmd) {
- atomic_dec(&cmd->t_transport_queue_active);
- atomic_dec(&qobj->queue_cnt);
- list_del(&cmd->se_queue_node);
- break;
- }
+ atomic_set(&cmd->t_transport_queue_active, 0);
+ atomic_dec(&qobj->queue_cnt);
+ list_del_init(&cmd->se_queue_node);
spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
if (atomic_read(&cmd->t_transport_queue_active)) {
@@ -715,6 +681,13 @@ void transport_complete_sync_cache(struct se_cmd *cmd, int good)
}
EXPORT_SYMBOL(transport_complete_sync_cache);
+static void target_complete_failure_work(struct work_struct *work)
+{
+ struct se_cmd *cmd = container_of(work, struct se_cmd, work);
+
+ transport_generic_request_failure(cmd, 1, 1);
+}
+
/* transport_complete_task():
*
* Called from interrupt and non interrupt context depending
@@ -723,8 +696,7 @@ EXPORT_SYMBOL(transport_complete_sync_cache);
void transport_complete_task(struct se_task *task, int success)
{
struct se_cmd *cmd = task->task_se_cmd;
- struct se_device *dev = task->se_dev;
- int t_state;
+ struct se_device *dev = cmd->se_dev;
unsigned long flags;
#if 0
pr_debug("task: %p CDB: 0x%02x obj_ptr: %p\n", task,
@@ -734,7 +706,7 @@ void transport_complete_task(struct se_task *task, int success)
atomic_inc(&dev->depth_left);
spin_lock_irqsave(&cmd->t_state_lock, flags);
- atomic_set(&task->task_active, 0);
+ task->task_flags &= ~TF_ACTIVE;
/*
* See if any sense data exists, if so set the TASK_SENSE flag.
@@ -753,68 +725,39 @@ void transport_complete_task(struct se_task *task, int success)
* See if we are waiting for outstanding struct se_task
* to complete for an exception condition
*/
- if (atomic_read(&task->task_stop)) {
- /*
- * Decrement cmd->t_se_count if this task had
- * previously thrown its timeout exception handler.
- */
- if (atomic_read(&task->task_timeout)) {
- atomic_dec(&cmd->t_se_count);
- atomic_set(&task->task_timeout, 0);
- }
+ if (task->task_flags & TF_REQUEST_STOP) {
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
complete(&task->task_stop_comp);
return;
}
/*
- * If the task's timeout handler has fired, use the t_task_cdbs_timeout
- * left counter to determine when the struct se_cmd is ready to be queued to
- * the processing thread.
- */
- if (atomic_read(&task->task_timeout)) {
- if (!atomic_dec_and_test(
- &cmd->t_task_cdbs_timeout_left)) {
- spin_unlock_irqrestore(&cmd->t_state_lock,
- flags);
- return;
- }
- t_state = TRANSPORT_COMPLETE_TIMEOUT;
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
- transport_add_cmd_to_queue(cmd, t_state);
- return;
- }
- atomic_dec(&cmd->t_task_cdbs_timeout_left);
-
- /*
* Decrement the outstanding t_task_cdbs_left count. The last
* struct se_task from struct se_cmd will complete itself into the
* device queue depending upon int success.
*/
if (!atomic_dec_and_test(&cmd->t_task_cdbs_left)) {
- if (!success)
- cmd->t_tasks_failed = 1;
-
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
return;
}
if (!success || cmd->t_tasks_failed) {
- t_state = TRANSPORT_COMPLETE_FAILURE;
if (!task->task_error_status) {
task->task_error_status =
PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
cmd->transport_error_status =
PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
}
+ INIT_WORK(&cmd->work, target_complete_failure_work);
} else {
atomic_set(&cmd->t_transport_complete, 1);
- t_state = TRANSPORT_COMPLETE_OK;
+ INIT_WORK(&cmd->work, target_complete_ok_work);
}
+
+ cmd->t_state = TRANSPORT_COMPLETE;
+ atomic_set(&cmd->t_transport_active, 1);
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- transport_add_cmd_to_queue(cmd, t_state);
+ queue_work(target_completion_wq, &cmd->work);
}
EXPORT_SYMBOL(transport_complete_task);
@@ -901,14 +844,12 @@ static void __transport_add_task_to_execute_queue(
static void transport_add_tasks_to_state_queue(struct se_cmd *cmd)
{
- struct se_device *dev;
+ struct se_device *dev = cmd->se_dev;
struct se_task *task;
unsigned long flags;
spin_lock_irqsave(&cmd->t_state_lock, flags);
list_for_each_entry(task, &cmd->t_task_list, t_list) {
- dev = task->se_dev;
-
if (atomic_read(&task->task_state_active))
continue;
@@ -933,38 +874,36 @@ static void transport_add_tasks_from_cmd(struct se_cmd *cmd)
spin_lock_irqsave(&dev->execute_task_lock, flags);
list_for_each_entry(task, &cmd->t_task_list, t_list) {
- if (atomic_read(&task->task_execute_queue))
+ if (!list_empty(&task->t_execute_list))
continue;
/*
* __transport_add_task_to_execute_queue() handles the
* SAM Task Attribute emulation if enabled
*/
__transport_add_task_to_execute_queue(task, task_prev, dev);
- atomic_set(&task->task_execute_queue, 1);
task_prev = task;
}
spin_unlock_irqrestore(&dev->execute_task_lock, flags);
}
-/* transport_remove_task_from_execute_queue():
- *
- *
- */
+void __transport_remove_task_from_execute_queue(struct se_task *task,
+ struct se_device *dev)
+{
+ list_del_init(&task->t_execute_list);
+ atomic_dec(&dev->execute_tasks);
+}
+
void transport_remove_task_from_execute_queue(
struct se_task *task,
struct se_device *dev)
{
unsigned long flags;
- if (atomic_read(&task->task_execute_queue) == 0) {
- dump_stack();
+ if (WARN_ON(list_empty(&task->t_execute_list)))
return;
- }
spin_lock_irqsave(&dev->execute_task_lock, flags);
- list_del(&task->t_execute_list);
- atomic_set(&task->task_execute_queue, 0);
- atomic_dec(&dev->execute_tasks);
+ __transport_remove_task_from_execute_queue(task, dev);
spin_unlock_irqrestore(&dev->execute_task_lock, flags);
}
@@ -976,30 +915,26 @@ static void target_qf_do_work(struct work_struct *work)
{
struct se_device *dev = container_of(work, struct se_device,
qf_work_queue);
+ LIST_HEAD(qf_cmd_list);
struct se_cmd *cmd, *cmd_tmp;
spin_lock_irq(&dev->qf_cmd_lock);
- list_for_each_entry_safe(cmd, cmd_tmp, &dev->qf_cmd_list, se_qf_node) {
+ list_splice_init(&dev->qf_cmd_list, &qf_cmd_list);
+ spin_unlock_irq(&dev->qf_cmd_lock);
+ list_for_each_entry_safe(cmd, cmd_tmp, &qf_cmd_list, se_qf_node) {
list_del(&cmd->se_qf_node);
atomic_dec(&dev->dev_qf_count);
smp_mb__after_atomic_dec();
- spin_unlock_irq(&dev->qf_cmd_lock);
pr_debug("Processing %s cmd: %p QUEUE_FULL in work queue"
" context: %s\n", cmd->se_tfo->get_fabric_name(), cmd,
- (cmd->t_state == TRANSPORT_COMPLETE_OK) ? "COMPLETE_OK" :
+ (cmd->t_state == TRANSPORT_COMPLETE_QF_OK) ? "COMPLETE_OK" :
(cmd->t_state == TRANSPORT_COMPLETE_QF_WP) ? "WRITE_PENDING"
: "UNKNOWN");
- /*
- * The SCF_EMULATE_QUEUE_FULL flag will be cleared once se_cmd
- * has been added to head of queue
- */
- transport_add_cmd_to_queue(cmd, cmd->t_state);
- spin_lock_irq(&dev->qf_cmd_lock);
+ transport_add_cmd_to_queue(cmd, cmd->t_state, true);
}
- spin_unlock_irq(&dev->qf_cmd_lock);
}
unsigned char *transport_dump_cmd_direction(struct se_cmd *cmd)
@@ -1053,41 +988,6 @@ void transport_dump_dev_state(
*bl += sprintf(b + *bl, " ");
}
-/* transport_release_all_cmds():
- *
- *
- */
-static void transport_release_all_cmds(struct se_device *dev)
-{
- struct se_cmd *cmd, *tcmd;
- int bug_out = 0, t_state;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->dev_queue_obj.cmd_queue_lock, flags);
- list_for_each_entry_safe(cmd, tcmd, &dev->dev_queue_obj.qobj_list,
- se_queue_node) {
- t_state = cmd->t_state;
- list_del(&cmd->se_queue_node);
- spin_unlock_irqrestore(&dev->dev_queue_obj.cmd_queue_lock,
- flags);
-
- pr_err("Releasing ITT: 0x%08x, i_state: %u,"
- " t_state: %u directly\n",
- cmd->se_tfo->get_task_tag(cmd),
- cmd->se_tfo->get_cmd_state(cmd), t_state);
-
- transport_release_fe_cmd(cmd);
- bug_out = 1;
-
- spin_lock_irqsave(&dev->dev_queue_obj.cmd_queue_lock, flags);
- }
- spin_unlock_irqrestore(&dev->dev_queue_obj.cmd_queue_lock, flags);
-#if 0
- if (bug_out)
- BUG();
-#endif
-}
-
void transport_dump_vpd_proto_id(
struct t10_vpd *vpd,
unsigned char *p_buf,
@@ -1573,7 +1473,6 @@ transport_generic_get_task(struct se_cmd *cmd,
INIT_LIST_HEAD(&task->t_state_list);
init_completion(&task->task_stop_comp);
task->task_se_cmd = cmd;
- task->se_dev = dev;
task->task_data_direction = data_direction;
return task;
@@ -1598,6 +1497,7 @@ void transport_init_se_cmd(
INIT_LIST_HEAD(&cmd->se_delayed_node);
INIT_LIST_HEAD(&cmd->se_ordered_node);
INIT_LIST_HEAD(&cmd->se_qf_node);
+ INIT_LIST_HEAD(&cmd->se_queue_node);
INIT_LIST_HEAD(&cmd->t_task_list);
init_completion(&cmd->transport_lun_fe_stop_comp);
@@ -1641,21 +1541,6 @@ static int transport_check_alloc_task_attr(struct se_cmd *cmd)
return 0;
}
-void transport_free_se_cmd(
- struct se_cmd *se_cmd)
-{
- if (se_cmd->se_tmr_req)
- core_tmr_release_req(se_cmd->se_tmr_req);
- /*
- * Check and free any extended CDB buffer that was allocated
- */
- if (se_cmd->t_task_cdb != se_cmd->__t_task_cdb)
- kfree(se_cmd->t_task_cdb);
-}
-EXPORT_SYMBOL(transport_free_se_cmd);
-
-static void transport_generic_wait_for_tasks(struct se_cmd *, int, int);
-
/* transport_generic_allocate_tasks():
*
* Called from fabric RX Thread.
@@ -1667,12 +1552,6 @@ int transport_generic_allocate_tasks(
int ret;
transport_generic_prepare_cdb(cdb);
-
- /*
- * This is needed for early exceptions.
- */
- cmd->transport_wait_for_tasks = &transport_generic_wait_for_tasks;
-
/*
* Ensure that the received CDB is less than the max (252 + 8) bytes
* for VARIABLE_LENGTH_CMD
@@ -1730,26 +1609,6 @@ int transport_generic_allocate_tasks(
EXPORT_SYMBOL(transport_generic_allocate_tasks);
/*
- * Used by fabric module frontends not defining a TFO->new_cmd_map()
- * to queue up a newly setup se_cmd w/ TRANSPORT_NEW_CMD statis
- */
-int transport_generic_handle_cdb(
- struct se_cmd *cmd)
-{
- if (!cmd->se_lun) {
- dump_stack();
- pr_err("cmd->se_lun is NULL\n");
- return -EINVAL;
- }
-
- transport_add_cmd_to_queue(cmd, TRANSPORT_NEW_CMD);
- return 0;
-}
-EXPORT_SYMBOL(transport_generic_handle_cdb);
-
-static void transport_generic_request_failure(struct se_cmd *,
- struct se_device *, int, int);
-/*
* Used by fabric module frontends to queue tasks directly.
* Many only be used from process context only
*/
@@ -1773,7 +1632,7 @@ int transport_handle_cdb_direct(
* Set TRANSPORT_NEW_CMD state and cmd->t_transport_active=1 following
* transport_generic_handle_cdb*() -> transport_add_cmd_to_queue()
* in existing usage to ensure that outstanding descriptors are handled
- * correctly during shutdown via transport_generic_wait_for_tasks()
+ * correctly during shutdown via transport_wait_for_tasks()
*
* Also, we don't take cmd->t_state_lock here as we only expect
* this to be called for initial descriptor submission.
@@ -1790,7 +1649,7 @@ int transport_handle_cdb_direct(
return 0;
else if (ret < 0) {
cmd->transport_error_status = ret;
- transport_generic_request_failure(cmd, NULL, 0,
+ transport_generic_request_failure(cmd, 0,
(cmd->data_direction != DMA_TO_DEVICE));
}
return 0;
@@ -1811,7 +1670,7 @@ int transport_generic_handle_cdb_map(
return -EINVAL;
}
- transport_add_cmd_to_queue(cmd, TRANSPORT_NEW_CMD_MAP);
+ transport_add_cmd_to_queue(cmd, TRANSPORT_NEW_CMD_MAP, false);
return 0;
}
EXPORT_SYMBOL(transport_generic_handle_cdb_map);
@@ -1841,7 +1700,7 @@ int transport_generic_handle_data(
if (transport_check_aborted_status(cmd, 1) != 0)
return 0;
- transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_WRITE);
+ transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_WRITE, false);
return 0;
}
EXPORT_SYMBOL(transport_generic_handle_data);
@@ -1853,12 +1712,7 @@ EXPORT_SYMBOL(transport_generic_handle_data);
int transport_generic_handle_tmr(
struct se_cmd *cmd)
{
- /*
- * This is needed for early exceptions.
- */
- cmd->transport_wait_for_tasks = &transport_generic_wait_for_tasks;
-
- transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_TMR);
+ transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_TMR, false);
return 0;
}
EXPORT_SYMBOL(transport_generic_handle_tmr);
@@ -1866,10 +1720,36 @@ EXPORT_SYMBOL(transport_generic_handle_tmr);
void transport_generic_free_cmd_intr(
struct se_cmd *cmd)
{
- transport_add_cmd_to_queue(cmd, TRANSPORT_FREE_CMD_INTR);
+ transport_add_cmd_to_queue(cmd, TRANSPORT_FREE_CMD_INTR, false);
}
EXPORT_SYMBOL(transport_generic_free_cmd_intr);
+/*
+ * If the task is active, request it to be stopped and sleep until it
+ * has completed.
+ */
+bool target_stop_task(struct se_task *task, unsigned long *flags)
+{
+ struct se_cmd *cmd = task->task_se_cmd;
+ bool was_active = false;
+
+ if (task->task_flags & TF_ACTIVE) {
+ task->task_flags |= TF_REQUEST_STOP;
+ spin_unlock_irqrestore(&cmd->t_state_lock, *flags);
+
+ pr_debug("Task %p waiting to complete\n", task);
+ wait_for_completion(&task->task_stop_comp);
+ pr_debug("Task %p stopped successfully\n", task);
+
+ spin_lock_irqsave(&cmd->t_state_lock, *flags);
+ atomic_dec(&cmd->t_task_cdbs_left);
+ task->task_flags &= ~(TF_ACTIVE | TF_REQUEST_STOP);
+ was_active = true;
+ }
+
+ return was_active;
+}
+
static int transport_stop_tasks_for_cmd(struct se_cmd *cmd)
{
struct se_task *task, *task_tmp;
@@ -1885,51 +1765,26 @@ static int transport_stop_tasks_for_cmd(struct se_cmd *cmd)
spin_lock_irqsave(&cmd->t_state_lock, flags);
list_for_each_entry_safe(task, task_tmp,
&cmd->t_task_list, t_list) {
- pr_debug("task_no[%d] - Processing task %p\n",
- task->task_no, task);
+ pr_debug("Processing task %p\n", task);
/*
* If the struct se_task has not been sent and is not active,
* remove the struct se_task from the execution queue.
*/
- if (!atomic_read(&task->task_sent) &&
- !atomic_read(&task->task_active)) {
+ if (!(task->task_flags & (TF_ACTIVE | TF_SENT))) {
spin_unlock_irqrestore(&cmd->t_state_lock,
flags);
transport_remove_task_from_execute_queue(task,
- task->se_dev);
+ cmd->se_dev);
- pr_debug("task_no[%d] - Removed from execute queue\n",
- task->task_no);
+ pr_debug("Task %p removed from execute queue\n", task);
spin_lock_irqsave(&cmd->t_state_lock, flags);
continue;
}
- /*
- * If the struct se_task is active, sleep until it is returned
- * from the plugin.
- */
- if (atomic_read(&task->task_active)) {
- atomic_set(&task->task_stop, 1);
- spin_unlock_irqrestore(&cmd->t_state_lock,
- flags);
-
- pr_debug("task_no[%d] - Waiting to complete\n",
- task->task_no);
- wait_for_completion(&task->task_stop_comp);
- pr_debug("task_no[%d] - Stopped successfully\n",
- task->task_no);
-
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- atomic_dec(&cmd->t_task_cdbs_left);
-
- atomic_set(&task->task_active, 0);
- atomic_set(&task->task_stop, 0);
- } else {
- pr_debug("task_no[%d] - Did nothing\n", task->task_no);
+ if (!target_stop_task(task, &flags)) {
+ pr_debug("Task %p - did nothing\n", task);
ret++;
}
-
- __transport_stop_task_timer(task, &flags);
}
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
@@ -1941,7 +1796,6 @@ static int transport_stop_tasks_for_cmd(struct se_cmd *cmd)
*/
static void transport_generic_request_failure(
struct se_cmd *cmd,
- struct se_device *dev,
int complete,
int sc)
{
@@ -1950,10 +1804,9 @@ static void transport_generic_request_failure(
pr_debug("-----[ Storage Engine Exception for cmd: %p ITT: 0x%08x"
" CDB: 0x%02x\n", cmd, cmd->se_tfo->get_task_tag(cmd),
cmd->t_task_cdb[0]);
- pr_debug("-----[ i_state: %d t_state/def_t_state:"
- " %d/%d transport_error_status: %d\n",
+ pr_debug("-----[ i_state: %d t_state: %d transport_error_status: %d\n",
cmd->se_tfo->get_cmd_state(cmd),
- cmd->t_state, cmd->deferred_t_state,
+ cmd->t_state,
cmd->transport_error_status);
pr_debug("-----[ t_tasks: %d t_task_cdbs_left: %d"
" t_task_cdbs_sent: %d t_task_cdbs_ex_left: %d --"
@@ -1966,10 +1819,6 @@ static void transport_generic_request_failure(
atomic_read(&cmd->t_transport_stop),
atomic_read(&cmd->t_transport_sent));
- transport_stop_all_task_timers(cmd);
-
- if (dev)
- atomic_inc(&dev->depth_left);
/*
* For SAM Task Attribute emulation for failed struct se_cmd
*/
@@ -1977,7 +1826,6 @@ static void transport_generic_request_failure(
transport_complete_task_attr(cmd);
if (complete) {
- transport_direct_request_timeout(cmd);
cmd->transport_error_status = PYX_TRANSPORT_LU_COMM_FAILURE;
}
@@ -2053,8 +1901,14 @@ static void transport_generic_request_failure(
cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
break;
}
-
- if (!sc)
+ /*
+ * If a fabric does not define a cmd->se_tfo->new_cmd_map caller,
+ * make the call to transport_send_check_condition_and_sense()
+ * directly. Otherwise expect the fabric to make the call to
+ * transport_send_check_condition_and_sense() after handling
+ * possible unsoliticied write data payloads.
+ */
+ if (!sc && !cmd->se_tfo->new_cmd_map)
transport_new_cmd_failure(cmd);
else {
ret = transport_send_check_condition_and_sense(cmd,
@@ -2070,46 +1924,8 @@ check_stop:
return;
queue_full:
- cmd->t_state = TRANSPORT_COMPLETE_OK;
- transport_handle_queue_full(cmd, cmd->se_dev, transport_complete_qf);
-}
-
-static void transport_direct_request_timeout(struct se_cmd *cmd)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- if (!atomic_read(&cmd->t_transport_timeout)) {
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- return;
- }
- if (atomic_read(&cmd->t_task_cdbs_timeout_left)) {
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- return;
- }
-
- atomic_sub(atomic_read(&cmd->t_transport_timeout),
- &cmd->t_se_count);
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-}
-
-static void transport_generic_request_timeout(struct se_cmd *cmd)
-{
- unsigned long flags;
-
- /*
- * Reset cmd->t_se_count to allow transport_generic_remove()
- * to allow last call to free memory resources.
- */
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- if (atomic_read(&cmd->t_transport_timeout) > 1) {
- int tmp = (atomic_read(&cmd->t_transport_timeout) - 1);
-
- atomic_sub(tmp, &cmd->t_se_count);
- }
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
- transport_generic_remove(cmd, 0);
+ cmd->t_state = TRANSPORT_COMPLETE_QF_OK;
+ transport_handle_queue_full(cmd, cmd->se_dev);
}
static inline u32 transport_lba_21(unsigned char *cdb)
@@ -2154,127 +1970,6 @@ static void transport_set_supported_SAM_opcode(struct se_cmd *se_cmd)
spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
}
-/*
- * Called from interrupt context.
- */
-static void transport_task_timeout_handler(unsigned long data)
-{
- struct se_task *task = (struct se_task *)data;
- struct se_cmd *cmd = task->task_se_cmd;
- unsigned long flags;
-
- pr_debug("transport task timeout fired! task: %p cmd: %p\n", task, cmd);
-
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- if (task->task_flags & TF_STOP) {
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- return;
- }
- task->task_flags &= ~TF_RUNNING;
-
- /*
- * Determine if transport_complete_task() has already been called.
- */
- if (!atomic_read(&task->task_active)) {
- pr_debug("transport task: %p cmd: %p timeout task_active"
- " == 0\n", task, cmd);
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- return;
- }
-
- atomic_inc(&cmd->t_se_count);
- atomic_inc(&cmd->t_transport_timeout);
- cmd->t_tasks_failed = 1;
-
- atomic_set(&task->task_timeout, 1);
- task->task_error_status = PYX_TRANSPORT_TASK_TIMEOUT;
- task->task_scsi_status = 1;
-
- if (atomic_read(&task->task_stop)) {
- pr_debug("transport task: %p cmd: %p timeout task_stop"
- " == 1\n", task, cmd);
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- complete(&task->task_stop_comp);
- return;
- }
-
- if (!atomic_dec_and_test(&cmd->t_task_cdbs_left)) {
- pr_debug("transport task: %p cmd: %p timeout non zero"
- " t_task_cdbs_left\n", task, cmd);
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- return;
- }
- pr_debug("transport task: %p cmd: %p timeout ZERO t_task_cdbs_left\n",
- task, cmd);
-
- cmd->t_state = TRANSPORT_COMPLETE_FAILURE;
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
- transport_add_cmd_to_queue(cmd, TRANSPORT_COMPLETE_FAILURE);
-}
-
-/*
- * Called with cmd->t_state_lock held.
- */
-static void transport_start_task_timer(struct se_task *task)
-{
- struct se_device *dev = task->se_dev;
- int timeout;
-
- if (task->task_flags & TF_RUNNING)
- return;
- /*
- * If the task_timeout is disabled, exit now.
- */
- timeout = dev->se_sub_dev->se_dev_attrib.task_timeout;
- if (!timeout)
- return;
-
- init_timer(&task->task_timer);
- task->task_timer.expires = (get_jiffies_64() + timeout * HZ);
- task->task_timer.data = (unsigned long) task;
- task->task_timer.function = transport_task_timeout_handler;
-
- task->task_flags |= TF_RUNNING;
- add_timer(&task->task_timer);
-#if 0
- pr_debug("Starting task timer for cmd: %p task: %p seconds:"
- " %d\n", task->task_se_cmd, task, timeout);
-#endif
-}
-
-/*
- * Called with spin_lock_irq(&cmd->t_state_lock) held.
- */
-void __transport_stop_task_timer(struct se_task *task, unsigned long *flags)
-{
- struct se_cmd *cmd = task->task_se_cmd;
-
- if (!task->task_flags & TF_RUNNING)
- return;
-
- task->task_flags |= TF_STOP;
- spin_unlock_irqrestore(&cmd->t_state_lock, *flags);
-
- del_timer_sync(&task->task_timer);
-
- spin_lock_irqsave(&cmd->t_state_lock, *flags);
- task->task_flags &= ~TF_RUNNING;
- task->task_flags &= ~TF_STOP;
-}
-
-static void transport_stop_all_task_timers(struct se_cmd *cmd)
-{
- struct se_task *task = NULL, *task_tmp;
- unsigned long flags;
-
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- list_for_each_entry_safe(task, task_tmp,
- &cmd->t_task_list, t_list)
- __transport_stop_task_timer(task, &flags);
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-}
-
static inline int transport_tcq_window_closed(struct se_device *dev)
{
if (dev->dev_tcq_window_closed++ <
@@ -2379,7 +2074,7 @@ static int transport_execute_tasks(struct se_cmd *cmd)
if (se_dev_check_online(cmd->se_orig_obj_ptr) != 0) {
cmd->transport_error_status = PYX_TRANSPORT_LU_COMM_FAILURE;
- transport_generic_request_failure(cmd, NULL, 0, 1);
+ transport_generic_request_failure(cmd, 0, 1);
return 0;
}
@@ -2442,9 +2137,7 @@ check_depth:
}
task = list_first_entry(&dev->execute_task_list,
struct se_task, t_execute_list);
- list_del(&task->t_execute_list);
- atomic_set(&task->task_execute_queue, 0);
- atomic_dec(&dev->execute_tasks);
+ __transport_remove_task_from_execute_queue(task, dev);
spin_unlock_irq(&dev->execute_task_lock);
atomic_dec(&dev->depth_left);
@@ -2452,15 +2145,13 @@ check_depth:
cmd = task->task_se_cmd;
spin_lock_irqsave(&cmd->t_state_lock, flags);
- atomic_set(&task->task_active, 1);
- atomic_set(&task->task_sent, 1);
+ task->task_flags |= (TF_ACTIVE | TF_SENT);
atomic_inc(&cmd->t_task_cdbs_sent);
if (atomic_read(&cmd->t_task_cdbs_sent) ==
cmd->t_task_list_num)
- atomic_set(&cmd->transport_sent, 1);
+ atomic_set(&cmd->t_transport_sent, 1);
- transport_start_task_timer(task);
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
/*
* The struct se_cmd->transport_emulate_cdb() function pointer is used
@@ -2471,10 +2162,13 @@ check_depth:
error = cmd->transport_emulate_cdb(cmd);
if (error != 0) {
cmd->transport_error_status = error;
- atomic_set(&task->task_active, 0);
- atomic_set(&cmd->transport_sent, 0);
+ spin_lock_irqsave(&cmd->t_state_lock, flags);
+ task->task_flags &= ~TF_ACTIVE;
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+ atomic_set(&cmd->t_transport_sent, 0);
transport_stop_tasks_for_cmd(cmd);
- transport_generic_request_failure(cmd, dev, 0, 1);
+ atomic_inc(&dev->depth_left);
+ transport_generic_request_failure(cmd, 0, 1);
goto check_depth;
}
/*
@@ -2507,10 +2201,13 @@ check_depth:
if (error != 0) {
cmd->transport_error_status = error;
- atomic_set(&task->task_active, 0);
- atomic_set(&cmd->transport_sent, 0);
+ spin_lock_irqsave(&cmd->t_state_lock, flags);
+ task->task_flags &= ~TF_ACTIVE;
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+ atomic_set(&cmd->t_transport_sent, 0);
transport_stop_tasks_for_cmd(cmd);
- transport_generic_request_failure(cmd, dev, 0, 1);
+ atomic_inc(&dev->depth_left);
+ transport_generic_request_failure(cmd, 0, 1);
}
}
@@ -2532,8 +2229,6 @@ void transport_new_cmd_failure(struct se_cmd *se_cmd)
spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
}
-static void transport_nop_wait_for_tasks(struct se_cmd *, int, int);
-
static inline u32 transport_get_sectors_6(
unsigned char *cdb,
struct se_cmd *cmd,
@@ -2746,13 +2441,16 @@ out:
static int transport_get_sense_data(struct se_cmd *cmd)
{
unsigned char *buffer = cmd->sense_buffer, *sense_buffer = NULL;
- struct se_device *dev;
+ struct se_device *dev = cmd->se_dev;
struct se_task *task = NULL, *task_tmp;
unsigned long flags;
u32 offset = 0;
WARN_ON(!cmd->se_lun);
+ if (!dev)
+ return 0;
+
spin_lock_irqsave(&cmd->t_state_lock, flags);
if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
@@ -2761,14 +2459,9 @@ static int transport_get_sense_data(struct se_cmd *cmd)
list_for_each_entry_safe(task, task_tmp,
&cmd->t_task_list, t_list) {
-
if (!task->task_sense)
continue;
- dev = task->se_dev;
- if (!dev)
- continue;
-
if (!dev->transport->get_sense_buffer) {
pr_err("dev->transport->get_sense_buffer"
" is NULL\n");
@@ -2777,9 +2470,9 @@ static int transport_get_sense_data(struct se_cmd *cmd)
sense_buffer = dev->transport->get_sense_buffer(task);
if (!sense_buffer) {
- pr_err("ITT[0x%08x]_TASK[%d]: Unable to locate"
+ pr_err("ITT[0x%08x]_TASK[%p]: Unable to locate"
" sense buffer for task with sense\n",
- cmd->se_tfo->get_task_tag(cmd), task->task_no);
+ cmd->se_tfo->get_task_tag(cmd), task);
continue;
}
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
@@ -2808,7 +2501,6 @@ static int transport_get_sense_data(struct se_cmd *cmd)
static int
transport_handle_reservation_conflict(struct se_cmd *cmd)
{
- cmd->transport_wait_for_tasks = &transport_nop_wait_for_tasks;
cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
cmd->se_cmd_flags |= SCF_SCSI_RESERVATION_CONFLICT;
cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
@@ -2847,12 +2539,42 @@ static int transport_cmd_get_valid_sectors(struct se_cmd *cmd)
" transport_dev_end_lba(): %llu\n",
cmd->t_task_lba, sectors,
transport_dev_end_lba(dev));
- pr_err(" We should return CHECK_CONDITION"
- " but we don't yet\n");
- return 0;
+ return -EINVAL;
}
- return sectors;
+ return 0;
+}
+
+static int target_check_write_same_discard(unsigned char *flags, struct se_device *dev)
+{
+ /*
+ * Determine if the received WRITE_SAME is used to for direct
+ * passthrough into Linux/SCSI with struct request via TCM/pSCSI
+ * or we are signaling the use of internal WRITE_SAME + UNMAP=1
+ * emulation for -> Linux/BLOCK disbard with TCM/IBLOCK code.
+ */
+ int passthrough = (dev->transport->transport_type ==
+ TRANSPORT_PLUGIN_PHBA_PDEV);
+
+ if (!passthrough) {
+ if ((flags[0] & 0x04) || (flags[0] & 0x02)) {
+ pr_err("WRITE_SAME PBDATA and LBDATA"
+ " bits not supported for Block Discard"
+ " Emulation\n");
+ return -ENOSYS;
+ }
+ /*
+ * Currently for the emulated case we only accept
+ * tpws with the UNMAP=1 bit set.
+ */
+ if (!(flags[0] & 0x08)) {
+ pr_err("WRITE_SAME w/o UNMAP bit not"
+ " supported for Block Discard Emulation\n");
+ return -ENOSYS;
+ }
+ }
+
+ return 0;
}
/* transport_generic_cmd_sequencer():
@@ -2879,8 +2601,6 @@ static int transport_generic_cmd_sequencer(
* Check for an existing UNIT ATTENTION condition
*/
if (core_scsi3_ua_check(cmd, cdb) < 0) {
- cmd->transport_wait_for_tasks =
- &transport_nop_wait_for_tasks;
cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
cmd->scsi_sense_reason = TCM_CHECK_CONDITION_UNIT_ATTENTION;
return -EINVAL;
@@ -2890,7 +2610,6 @@ static int transport_generic_cmd_sequencer(
*/
ret = su_dev->t10_alua.alua_state_check(cmd, cdb, &alua_ascq);
if (ret != 0) {
- cmd->transport_wait_for_tasks = &transport_nop_wait_for_tasks;
/*
* Set SCSI additional sense code (ASC) to 'LUN Not Accessible';
* The ALUA additional sense code qualifier (ASCQ) is determined
@@ -2929,7 +2648,6 @@ static int transport_generic_cmd_sequencer(
if (sector_ret)
goto out_unsupported_cdb;
size = transport_get_size(sectors, cdb, cmd);
- cmd->transport_split_cdb = &split_cdb_XX_6;
cmd->t_task_lba = transport_lba_21(cdb);
cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
break;
@@ -2938,7 +2656,6 @@ static int transport_generic_cmd_sequencer(
if (sector_ret)
goto out_unsupported_cdb;
size = transport_get_size(sectors, cdb, cmd);
- cmd->transport_split_cdb = &split_cdb_XX_10;
cmd->t_task_lba = transport_lba_32(cdb);
cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
break;
@@ -2947,7 +2664,6 @@ static int transport_generic_cmd_sequencer(
if (sector_ret)
goto out_unsupported_cdb;
size = transport_get_size(sectors, cdb, cmd);
- cmd->transport_split_cdb = &split_cdb_XX_12;
cmd->t_task_lba = transport_lba_32(cdb);
cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
break;
@@ -2956,7 +2672,6 @@ static int transport_generic_cmd_sequencer(
if (sector_ret)
goto out_unsupported_cdb;
size = transport_get_size(sectors, cdb, cmd);
- cmd->transport_split_cdb = &split_cdb_XX_16;
cmd->t_task_lba = transport_lba_64(cdb);
cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
break;
@@ -2965,7 +2680,6 @@ static int transport_generic_cmd_sequencer(
if (sector_ret)
goto out_unsupported_cdb;
size = transport_get_size(sectors, cdb, cmd);
- cmd->transport_split_cdb = &split_cdb_XX_6;
cmd->t_task_lba = transport_lba_21(cdb);
cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
break;
@@ -2974,7 +2688,6 @@ static int transport_generic_cmd_sequencer(
if (sector_ret)
goto out_unsupported_cdb;
size = transport_get_size(sectors, cdb, cmd);
- cmd->transport_split_cdb = &split_cdb_XX_10;
cmd->t_task_lba = transport_lba_32(cdb);
cmd->t_tasks_fua = (cdb[1] & 0x8);
cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
@@ -2984,7 +2697,6 @@ static int transport_generic_cmd_sequencer(
if (sector_ret)
goto out_unsupported_cdb;
size = transport_get_size(sectors, cdb, cmd);
- cmd->transport_split_cdb = &split_cdb_XX_12;
cmd->t_task_lba = transport_lba_32(cdb);
cmd->t_tasks_fua = (cdb[1] & 0x8);
cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
@@ -2994,7 +2706,6 @@ static int transport_generic_cmd_sequencer(
if (sector_ret)
goto out_unsupported_cdb;
size = transport_get_size(sectors, cdb, cmd);
- cmd->transport_split_cdb = &split_cdb_XX_16;
cmd->t_task_lba = transport_lba_64(cdb);
cmd->t_tasks_fua = (cdb[1] & 0x8);
cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
@@ -3007,18 +2718,14 @@ static int transport_generic_cmd_sequencer(
if (sector_ret)
goto out_unsupported_cdb;
size = transport_get_size(sectors, cdb, cmd);
- cmd->transport_split_cdb = &split_cdb_XX_10;
cmd->t_task_lba = transport_lba_32(cdb);
cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
- passthrough = (dev->transport->transport_type ==
- TRANSPORT_PLUGIN_PHBA_PDEV);
- /*
- * Skip the remaining assignments for TCM/PSCSI passthrough
- */
- if (passthrough)
- break;
+
+ if (dev->transport->transport_type ==
+ TRANSPORT_PLUGIN_PHBA_PDEV)
+ goto out_unsupported_cdb;
/*
- * Setup BIDI XOR callback to be run during transport_generic_complete_ok()
+ * Setup BIDI XOR callback to be run after I/O completion.
*/
cmd->transport_complete_callback = &transport_xor_callback;
cmd->t_tasks_fua = (cdb[1] & 0x8);
@@ -3042,19 +2749,14 @@ static int transport_generic_cmd_sequencer(
* Use WRITE_32 and READ_32 opcodes for the emulated
* XDWRITE_READ_32 logic.
*/
- cmd->transport_split_cdb = &split_cdb_XX_32;
cmd->t_task_lba = transport_lba_64_ext(cdb);
cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
- /*
- * Skip the remaining assignments for TCM/PSCSI passthrough
- */
if (passthrough)
- break;
-
+ goto out_unsupported_cdb;
/*
- * Setup BIDI XOR callback to be run during
- * transport_generic_complete_ok()
+ * Setup BIDI XOR callback to be run during after I/O
+ * completion.
*/
cmd->transport_complete_callback = &transport_xor_callback;
cmd->t_tasks_fua = (cdb[10] & 0x8);
@@ -3065,7 +2767,7 @@ static int transport_generic_cmd_sequencer(
goto out_unsupported_cdb;
if (sectors)
- size = transport_get_size(sectors, cdb, cmd);
+ size = transport_get_size(1, cdb, cmd);
else {
pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not"
" supported\n");
@@ -3075,27 +2777,9 @@ static int transport_generic_cmd_sequencer(
cmd->t_task_lba = get_unaligned_be64(&cdb[12]);
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
- /*
- * Skip the remaining assignments for TCM/PSCSI passthrough
- */
- if (passthrough)
- break;
-
- if ((cdb[10] & 0x04) || (cdb[10] & 0x02)) {
- pr_err("WRITE_SAME PBDATA and LBDATA"
- " bits not supported for Block Discard"
- " Emulation\n");
+ if (target_check_write_same_discard(&cdb[10], dev) < 0)
goto out_invalid_cdb_field;
- }
- /*
- * Currently for the emulated case we only accept
- * tpws with the UNMAP=1 bit set.
- */
- if (!(cdb[10] & 0x08)) {
- pr_err("WRITE_SAME w/o UNMAP bit not"
- " supported for Block Discard Emulation\n");
- goto out_invalid_cdb_field;
- }
+
break;
default:
pr_err("VARIABLE_LENGTH_CMD service action"
@@ -3330,10 +3014,12 @@ static int transport_generic_cmd_sequencer(
cmd->se_cmd_flags |= SCF_EMULATE_CDB_ASYNC;
/*
* Check to ensure that LBA + Range does not exceed past end of
- * device.
+ * device for IBLOCK and FILEIO ->do_sync_cache() backend calls
*/
- if (!transport_cmd_get_valid_sectors(cmd))
- goto out_invalid_cdb_field;
+ if ((cmd->t_task_lba != 0) || (sectors != 0)) {
+ if (transport_cmd_get_valid_sectors(cmd) < 0)
+ goto out_invalid_cdb_field;
+ }
break;
case UNMAP:
size = get_unaligned_be16(&cdb[7]);
@@ -3345,40 +3031,38 @@ static int transport_generic_cmd_sequencer(
goto out_unsupported_cdb;
if (sectors)
- size = transport_get_size(sectors, cdb, cmd);
+ size = transport_get_size(1, cdb, cmd);
else {
pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n");
goto out_invalid_cdb_field;
}
cmd->t_task_lba = get_unaligned_be64(&cdb[2]);
- passthrough = (dev->transport->transport_type ==
- TRANSPORT_PLUGIN_PHBA_PDEV);
- /*
- * Determine if the received WRITE_SAME_16 is used to for direct
- * passthrough into Linux/SCSI with struct request via TCM/pSCSI
- * or we are signaling the use of internal WRITE_SAME + UNMAP=1
- * emulation for -> Linux/BLOCK disbard with TCM/IBLOCK and
- * TCM/FILEIO subsystem plugin backstores.
- */
- if (!passthrough) {
- if ((cdb[1] & 0x04) || (cdb[1] & 0x02)) {
- pr_err("WRITE_SAME PBDATA and LBDATA"
- " bits not supported for Block Discard"
- " Emulation\n");
- goto out_invalid_cdb_field;
- }
- /*
- * Currently for the emulated case we only accept
- * tpws with the UNMAP=1 bit set.
- */
- if (!(cdb[1] & 0x08)) {
- pr_err("WRITE_SAME w/o UNMAP bit not "
- " supported for Block Discard Emulation\n");
- goto out_invalid_cdb_field;
- }
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+
+ if (target_check_write_same_discard(&cdb[1], dev) < 0)
+ goto out_invalid_cdb_field;
+ break;
+ case WRITE_SAME:
+ sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+
+ if (sectors)
+ size = transport_get_size(1, cdb, cmd);
+ else {
+ pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n");
+ goto out_invalid_cdb_field;
}
+
+ cmd->t_task_lba = get_unaligned_be32(&cdb[2]);
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+ /*
+ * Follow sbcr26 with WRITE_SAME (10) and check for the existence
+ * of byte 1 bit 3 UNMAP instead of original reserved field
+ */
+ if (target_check_write_same_discard(&cdb[1], dev) < 0)
+ goto out_invalid_cdb_field;
break;
case ALLOW_MEDIUM_REMOVAL:
case GPCMD_CLOSE_TRACK:
@@ -3412,7 +3096,6 @@ static int transport_generic_cmd_sequencer(
pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode"
" 0x%02x, sending CHECK_CONDITION.\n",
cmd->se_tfo->get_fabric_name(), cdb[0]);
- cmd->transport_wait_for_tasks = &transport_nop_wait_for_tasks;
goto out_unsupported_cdb;
}
@@ -3470,8 +3153,7 @@ out_invalid_cdb_field:
}
/*
- * Called from transport_generic_complete_ok() and
- * transport_generic_request_failure() to determine which dormant/delayed
+ * Called from I/O completion to determine which dormant/delayed
* and ordered cmds need to have their tasks added to the execution queue.
*/
static void transport_complete_task_attr(struct se_cmd *cmd)
@@ -3539,12 +3221,18 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
wake_up_interruptible(&dev->dev_queue_obj.thread_wq);
}
-static int transport_complete_qf(struct se_cmd *cmd)
+static void transport_complete_qf(struct se_cmd *cmd)
{
int ret = 0;
- if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE)
- return cmd->se_tfo->queue_status(cmd);
+ if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
+ transport_complete_task_attr(cmd);
+
+ if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) {
+ ret = cmd->se_tfo->queue_status(cmd);
+ if (ret)
+ goto out;
+ }
switch (cmd->data_direction) {
case DMA_FROM_DEVICE:
@@ -3554,7 +3242,7 @@ static int transport_complete_qf(struct se_cmd *cmd)
if (cmd->t_bidi_data_sg) {
ret = cmd->se_tfo->queue_data_in(cmd);
if (ret < 0)
- return ret;
+ break;
}
/* Fall through for DMA_TO_DEVICE */
case DMA_NONE:
@@ -3564,17 +3252,20 @@ static int transport_complete_qf(struct se_cmd *cmd)
break;
}
- return ret;
+out:
+ if (ret < 0) {
+ transport_handle_queue_full(cmd, cmd->se_dev);
+ return;
+ }
+ transport_lun_remove_cmd(cmd);
+ transport_cmd_check_stop_to_fabric(cmd);
}
static void transport_handle_queue_full(
struct se_cmd *cmd,
- struct se_device *dev,
- int (*qf_callback)(struct se_cmd *))
+ struct se_device *dev)
{
spin_lock_irq(&dev->qf_cmd_lock);
- cmd->se_cmd_flags |= SCF_EMULATE_QUEUE_FULL;
- cmd->transport_qf_callback = qf_callback;
list_add_tail(&cmd->se_qf_node, &cmd->se_dev->qf_cmd_list);
atomic_inc(&dev->dev_qf_count);
smp_mb__after_atomic_inc();
@@ -3583,9 +3274,11 @@ static void transport_handle_queue_full(
schedule_work(&cmd->se_dev->qf_work_queue);
}
-static void transport_generic_complete_ok(struct se_cmd *cmd)
+static void target_complete_ok_work(struct work_struct *work)
{
+ struct se_cmd *cmd = container_of(work, struct se_cmd, work);
int reason = 0, ret;
+
/*
* Check if we need to move delayed/dormant tasks from cmds on the
* delayed execution list after a HEAD_OF_QUEUE or ORDERED Task
@@ -3600,14 +3293,6 @@ static void transport_generic_complete_ok(struct se_cmd *cmd)
if (atomic_read(&cmd->se_dev->dev_qf_count) != 0)
schedule_work(&cmd->se_dev->qf_work_queue);
- if (cmd->transport_qf_callback) {
- ret = cmd->transport_qf_callback(cmd);
- if (ret < 0)
- goto queue_full;
-
- cmd->transport_qf_callback = NULL;
- goto done;
- }
/*
* Check if we need to retrieve a sense buffer from
* the struct se_cmd in question.
@@ -3683,7 +3368,6 @@ static void transport_generic_complete_ok(struct se_cmd *cmd)
break;
}
-done:
transport_lun_remove_cmd(cmd);
transport_cmd_check_stop_to_fabric(cmd);
return;
@@ -3691,34 +3375,35 @@ done:
queue_full:
pr_debug("Handling complete_ok QUEUE_FULL: se_cmd: %p,"
" data_direction: %d\n", cmd, cmd->data_direction);
- transport_handle_queue_full(cmd, cmd->se_dev, transport_complete_qf);
+ cmd->t_state = TRANSPORT_COMPLETE_QF_OK;
+ transport_handle_queue_full(cmd, cmd->se_dev);
}
static void transport_free_dev_tasks(struct se_cmd *cmd)
{
struct se_task *task, *task_tmp;
unsigned long flags;
+ LIST_HEAD(dispose_list);
spin_lock_irqsave(&cmd->t_state_lock, flags);
list_for_each_entry_safe(task, task_tmp,
&cmd->t_task_list, t_list) {
- if (atomic_read(&task->task_active))
- continue;
+ if (!(task->task_flags & TF_ACTIVE))
+ list_move_tail(&task->t_list, &dispose_list);
+ }
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- kfree(task->task_sg_bidi);
- kfree(task->task_sg);
+ while (!list_empty(&dispose_list)) {
+ task = list_first_entry(&dispose_list, struct se_task, t_list);
+
+ if (task->task_sg != cmd->t_data_sg &&
+ task->task_sg != cmd->t_bidi_data_sg)
+ kfree(task->task_sg);
list_del(&task->t_list);
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- if (task->se_dev)
- task->se_dev->transport->free_task(task);
- else
- pr_err("task[%u] - task->se_dev is NULL\n",
- task->task_no);
- spin_lock_irqsave(&cmd->t_state_lock, flags);
+ cmd->se_dev->transport->free_task(task);
}
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
}
static inline void transport_free_sgl(struct scatterlist *sgl, int nents)
@@ -3746,89 +3431,43 @@ static inline void transport_free_pages(struct se_cmd *cmd)
cmd->t_bidi_data_nents = 0;
}
-static inline void transport_release_tasks(struct se_cmd *cmd)
-{
- transport_free_dev_tasks(cmd);
-}
-
-static inline int transport_dec_and_check(struct se_cmd *cmd)
+/**
+ * transport_put_cmd - release a reference to a command
+ * @cmd: command to release
+ *
+ * This routine releases our reference to the command and frees it if possible.
+ */
+static void transport_put_cmd(struct se_cmd *cmd)
{
unsigned long flags;
+ int free_tasks = 0;
spin_lock_irqsave(&cmd->t_state_lock, flags);
if (atomic_read(&cmd->t_fe_count)) {
- if (!atomic_dec_and_test(&cmd->t_fe_count)) {
- spin_unlock_irqrestore(&cmd->t_state_lock,
- flags);
- return 1;
- }
+ if (!atomic_dec_and_test(&cmd->t_fe_count))
+ goto out_busy;
}
if (atomic_read(&cmd->t_se_count)) {
- if (!atomic_dec_and_test(&cmd->t_se_count)) {
- spin_unlock_irqrestore(&cmd->t_state_lock,
- flags);
- return 1;
- }
+ if (!atomic_dec_and_test(&cmd->t_se_count))
+ goto out_busy;
}
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- return 0;
-}
-
-static void transport_release_fe_cmd(struct se_cmd *cmd)
-{
- unsigned long flags;
-
- if (transport_dec_and_check(cmd))
- return;
-
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- if (!atomic_read(&cmd->transport_dev_active)) {
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- goto free_pages;
- }
- atomic_set(&cmd->transport_dev_active, 0);
- transport_all_task_dev_remove_state(cmd);
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
- transport_release_tasks(cmd);
-free_pages:
- transport_free_pages(cmd);
- transport_free_se_cmd(cmd);
- cmd->se_tfo->release_cmd(cmd);
-}
-
-static int
-transport_generic_remove(struct se_cmd *cmd, int session_reinstatement)
-{
- unsigned long flags;
-
- if (transport_dec_and_check(cmd)) {
- if (session_reinstatement) {
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- transport_all_task_dev_remove_state(cmd);
- spin_unlock_irqrestore(&cmd->t_state_lock,
- flags);
- }
- return 1;
- }
-
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- if (!atomic_read(&cmd->transport_dev_active)) {
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- goto free_pages;
+ if (atomic_read(&cmd->transport_dev_active)) {
+ atomic_set(&cmd->transport_dev_active, 0);
+ transport_all_task_dev_remove_state(cmd);
+ free_tasks = 1;
}
- atomic_set(&cmd->transport_dev_active, 0);
- transport_all_task_dev_remove_state(cmd);
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- transport_release_tasks(cmd);
+ if (free_tasks != 0)
+ transport_free_dev_tasks(cmd);
-free_pages:
transport_free_pages(cmd);
transport_release_cmd(cmd);
- return 0;
+ return;
+out_busy:
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
}
/*
@@ -3870,64 +3509,6 @@ int transport_generic_map_mem_to_cmd(
}
EXPORT_SYMBOL(transport_generic_map_mem_to_cmd);
-static int transport_new_cmd_obj(struct se_cmd *cmd)
-{
- struct se_device *dev = cmd->se_dev;
- u32 task_cdbs;
- u32 rc;
- int set_counts = 1;
-
- /*
- * Setup any BIDI READ tasks and memory from
- * cmd->t_mem_bidi_list so the READ struct se_tasks
- * are queued first for the non pSCSI passthrough case.
- */
- if (cmd->t_bidi_data_sg &&
- (dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV)) {
- rc = transport_allocate_tasks(cmd,
- cmd->t_task_lba,
- DMA_FROM_DEVICE,
- cmd->t_bidi_data_sg,
- cmd->t_bidi_data_nents);
- if (rc <= 0) {
- cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
- cmd->scsi_sense_reason =
- TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
- return PYX_TRANSPORT_LU_COMM_FAILURE;
- }
- atomic_inc(&cmd->t_fe_count);
- atomic_inc(&cmd->t_se_count);
- set_counts = 0;
- }
- /*
- * Setup the tasks and memory from cmd->t_mem_list
- * Note for BIDI transfers this will contain the WRITE payload
- */
- task_cdbs = transport_allocate_tasks(cmd,
- cmd->t_task_lba,
- cmd->data_direction,
- cmd->t_data_sg,
- cmd->t_data_nents);
- if (task_cdbs <= 0) {
- cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
- cmd->scsi_sense_reason =
- TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
- return PYX_TRANSPORT_LU_COMM_FAILURE;
- }
-
- if (set_counts) {
- atomic_inc(&cmd->t_fe_count);
- atomic_inc(&cmd->t_se_count);
- }
-
- cmd->t_task_list_num = task_cdbs;
-
- atomic_set(&cmd->t_task_cdbs_left, task_cdbs);
- atomic_set(&cmd->t_task_cdbs_ex_left, task_cdbs);
- atomic_set(&cmd->t_task_cdbs_timeout_left, task_cdbs);
- return 0;
-}
-
void *transport_kmap_first_data_page(struct se_cmd *cmd)
{
struct scatterlist *sg = cmd->t_data_sg;
@@ -4028,8 +3609,6 @@ void transport_do_task_sg_chain(struct se_cmd *cmd)
if (!task->task_sg)
continue;
- BUG_ON(!task->task_padded_sg);
-
if (!sg_first) {
sg_first = task->task_sg;
chained_nents = task->task_sg_nents;
@@ -4037,9 +3616,17 @@ void transport_do_task_sg_chain(struct se_cmd *cmd)
sg_chain(sg_prev, sg_prev_nents, task->task_sg);
chained_nents += task->task_sg_nents;
}
-
+ /*
+ * For the padded tasks, use the extra SGL vector allocated
+ * in transport_allocate_data_tasks() for the sg_prev_nents
+ * offset into sg_chain() above.
+ *
+ * We do not need the padding for the last task (or a single
+ * task), but in that case we will never use the sg_prev_nents
+ * value below which would be incorrect.
+ */
+ sg_prev_nents = (task->task_sg_nents + 1);
sg_prev = task->task_sg;
- sg_prev_nents = task->task_sg_nents;
}
/*
* Setup the starting pointer and total t_tasks_sg_linked_no including
@@ -4068,72 +3655,96 @@ EXPORT_SYMBOL(transport_do_task_sg_chain);
/*
* Break up cmd into chunks transport can handle
*/
-static int transport_allocate_data_tasks(
- struct se_cmd *cmd,
- unsigned long long lba,
+static int
+transport_allocate_data_tasks(struct se_cmd *cmd,
enum dma_data_direction data_direction,
- struct scatterlist *sgl,
- unsigned int sgl_nents)
+ struct scatterlist *cmd_sg, unsigned int sgl_nents)
{
- unsigned char *cdb = NULL;
- struct se_task *task;
struct se_device *dev = cmd->se_dev;
- unsigned long flags;
- int task_count, i, ret;
- sector_t sectors, dev_max_sectors = dev->se_sub_dev->se_dev_attrib.max_sectors;
- u32 sector_size = dev->se_sub_dev->se_dev_attrib.block_size;
- struct scatterlist *sg;
- struct scatterlist *cmd_sg;
+ int task_count, i;
+ unsigned long long lba;
+ sector_t sectors, dev_max_sectors;
+ u32 sector_size;
+
+ if (transport_cmd_get_valid_sectors(cmd) < 0)
+ return -EINVAL;
+
+ dev_max_sectors = dev->se_sub_dev->se_dev_attrib.max_sectors;
+ sector_size = dev->se_sub_dev->se_dev_attrib.block_size;
WARN_ON(cmd->data_length % sector_size);
+
+ lba = cmd->t_task_lba;
sectors = DIV_ROUND_UP(cmd->data_length, sector_size);
task_count = DIV_ROUND_UP_SECTOR_T(sectors, dev_max_sectors);
-
- cmd_sg = sgl;
- for (i = 0; i < task_count; i++) {
- unsigned int task_size;
- int count;
+
+ /*
+ * If we need just a single task reuse the SG list in the command
+ * and avoid a lot of work.
+ */
+ if (task_count == 1) {
+ struct se_task *task;
+ unsigned long flags;
task = transport_generic_get_task(cmd, data_direction);
if (!task)
return -ENOMEM;
+ task->task_sg = cmd_sg;
+ task->task_sg_nents = sgl_nents;
+
task->task_lba = lba;
- task->task_sectors = min(sectors, dev_max_sectors);
+ task->task_sectors = sectors;
task->task_size = task->task_sectors * sector_size;
- cdb = dev->transport->get_cdb(task);
- BUG_ON(!cdb);
+ spin_lock_irqsave(&cmd->t_state_lock, flags);
+ list_add_tail(&task->t_list, &cmd->t_task_list);
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- memcpy(cdb, cmd->t_task_cdb,
- scsi_command_size(cmd->t_task_cdb));
+ return task_count;
+ }
- /* Update new cdb with updated lba/sectors */
- cmd->transport_split_cdb(task->task_lba, task->task_sectors, cdb);
+ for (i = 0; i < task_count; i++) {
+ struct se_task *task;
+ unsigned int task_size, task_sg_nents_padded;
+ struct scatterlist *sg;
+ unsigned long flags;
+ int count;
+
+ task = transport_generic_get_task(cmd, data_direction);
+ if (!task)
+ return -ENOMEM;
+
+ task->task_lba = lba;
+ task->task_sectors = min(sectors, dev_max_sectors);
+ task->task_size = task->task_sectors * sector_size;
/*
+ * This now assumes that passed sg_ents are in PAGE_SIZE chunks
+ * in order to calculate the number per task SGL entries
+ */
+ task->task_sg_nents = DIV_ROUND_UP(task->task_size, PAGE_SIZE);
+ /*
* Check if the fabric module driver is requesting that all
* struct se_task->task_sg[] be chained together.. If so,
* then allocate an extra padding SG entry for linking and
- * marking the end of the chained SGL.
- * Possibly over-allocate task sgl size by using cmd sgl size.
- * It's so much easier and only a waste when task_count > 1.
- * That is extremely rare.
+ * marking the end of the chained SGL for every task except
+ * the last one for (task_count > 1) operation, or skipping
+ * the extra padding for the (task_count == 1) case.
*/
- task->task_sg_nents = sgl_nents;
- if (cmd->se_tfo->task_sg_chaining) {
- task->task_sg_nents++;
- task->task_padded_sg = 1;
- }
+ if (cmd->se_tfo->task_sg_chaining && (i < (task_count - 1))) {
+ task_sg_nents_padded = (task->task_sg_nents + 1);
+ } else
+ task_sg_nents_padded = task->task_sg_nents;
task->task_sg = kmalloc(sizeof(struct scatterlist) *
- task->task_sg_nents, GFP_KERNEL);
+ task_sg_nents_padded, GFP_KERNEL);
if (!task->task_sg) {
cmd->se_dev->transport->free_task(task);
return -ENOMEM;
}
- sg_init_table(task->task_sg, task->task_sg_nents);
+ sg_init_table(task->task_sg, task_sg_nents_padded);
task_size = task->task_size;
@@ -4154,20 +3765,6 @@ static int transport_allocate_data_tasks(
list_add_tail(&task->t_list, &cmd->t_task_list);
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
}
- /*
- * Now perform the memory map of task->task_sg[] into backend
- * subsystem memory..
- */
- list_for_each_entry(task, &cmd->t_task_list, t_list) {
- if (atomic_read(&task->task_sent))
- continue;
- if (!dev->transport->map_data_SG)
- continue;
-
- ret = dev->transport->map_data_SG(task);
- if (ret < 0)
- return 0;
- }
return task_count;
}
@@ -4175,30 +3772,14 @@ static int transport_allocate_data_tasks(
static int
transport_allocate_control_task(struct se_cmd *cmd)
{
- struct se_device *dev = cmd->se_dev;
- unsigned char *cdb;
struct se_task *task;
unsigned long flags;
- int ret = 0;
task = transport_generic_get_task(cmd, cmd->data_direction);
if (!task)
return -ENOMEM;
- cdb = dev->transport->get_cdb(task);
- BUG_ON(!cdb);
- memcpy(cdb, cmd->t_task_cdb,
- scsi_command_size(cmd->t_task_cdb));
-
- task->task_sg = kmalloc(sizeof(struct scatterlist) * cmd->t_data_nents,
- GFP_KERNEL);
- if (!task->task_sg) {
- cmd->se_dev->transport->free_task(task);
- return -ENOMEM;
- }
-
- memcpy(task->task_sg, cmd->t_data_sg,
- sizeof(struct scatterlist) * cmd->t_data_nents);
+ task->task_sg = cmd->t_data_sg;
task->task_size = cmd->data_length;
task->task_sg_nents = cmd->t_data_nents;
@@ -4206,50 +3787,20 @@ transport_allocate_control_task(struct se_cmd *cmd)
list_add_tail(&task->t_list, &cmd->t_task_list);
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- if (cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) {
- if (dev->transport->map_control_SG)
- ret = dev->transport->map_control_SG(task);
- } else if (cmd->se_cmd_flags & SCF_SCSI_NON_DATA_CDB) {
- if (dev->transport->cdb_none)
- ret = dev->transport->cdb_none(task);
- } else {
- pr_err("target: Unknown control cmd type!\n");
- BUG();
- }
-
/* Success! Return number of tasks allocated */
- if (ret == 0)
- return 1;
- return ret;
-}
-
-static u32 transport_allocate_tasks(
- struct se_cmd *cmd,
- unsigned long long lba,
- enum dma_data_direction data_direction,
- struct scatterlist *sgl,
- unsigned int sgl_nents)
-{
- if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)
- return transport_allocate_data_tasks(cmd, lba, data_direction,
- sgl, sgl_nents);
- else
- return transport_allocate_control_task(cmd);
-
+ return 1;
}
-
-/* transport_generic_new_cmd(): Called from transport_processing_thread()
- *
- * Allocate storage transport resources from a set of values predefined
- * by transport_generic_cmd_sequencer() from the iSCSI Target RX process.
- * Any non zero return here is treated as an "out of resource' op here.
+/*
+ * Allocate any required ressources to execute the command, and either place
+ * it on the execution queue if possible. For writes we might not have the
+ * payload yet, thus notify the fabric via a call to ->write_pending instead.
*/
- /*
- * Generate struct se_task(s) and/or their payloads for this CDB.
- */
int transport_generic_new_cmd(struct se_cmd *cmd)
{
+ struct se_device *dev = cmd->se_dev;
+ int task_cdbs, task_cdbs_bidi = 0;
+ int set_counts = 1;
int ret = 0;
/*
@@ -4263,16 +3814,45 @@ int transport_generic_new_cmd(struct se_cmd *cmd)
if (ret < 0)
return ret;
}
+
/*
- * Call transport_new_cmd_obj() to invoke transport_allocate_tasks() for
- * control or data CDB types, and perform the map to backend subsystem
- * code from SGL memory allocated here by transport_generic_get_mem(), or
- * via pre-existing SGL memory setup explictly by fabric module code with
- * transport_generic_map_mem_to_cmd().
+ * For BIDI command set up the read tasks first.
*/
- ret = transport_new_cmd_obj(cmd);
- if (ret < 0)
- return ret;
+ if (cmd->t_bidi_data_sg &&
+ dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) {
+ BUG_ON(!(cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB));
+
+ task_cdbs_bidi = transport_allocate_data_tasks(cmd,
+ DMA_FROM_DEVICE, cmd->t_bidi_data_sg,
+ cmd->t_bidi_data_nents);
+ if (task_cdbs_bidi <= 0)
+ goto out_fail;
+
+ atomic_inc(&cmd->t_fe_count);
+ atomic_inc(&cmd->t_se_count);
+ set_counts = 0;
+ }
+
+ if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) {
+ task_cdbs = transport_allocate_data_tasks(cmd,
+ cmd->data_direction, cmd->t_data_sg,
+ cmd->t_data_nents);
+ } else {
+ task_cdbs = transport_allocate_control_task(cmd);
+ }
+
+ if (task_cdbs <= 0)
+ goto out_fail;
+
+ if (set_counts) {
+ atomic_inc(&cmd->t_fe_count);
+ atomic_inc(&cmd->t_se_count);
+ }
+
+ cmd->t_task_list_num = (task_cdbs + task_cdbs_bidi);
+ atomic_set(&cmd->t_task_cdbs_left, cmd->t_task_list_num);
+ atomic_set(&cmd->t_task_cdbs_ex_left, cmd->t_task_list_num);
+
/*
* For WRITEs, let the fabric know its buffer is ready..
* This WRITE struct se_cmd (and all of its associated struct se_task's)
@@ -4290,6 +3870,11 @@ int transport_generic_new_cmd(struct se_cmd *cmd)
*/
transport_execute_tasks(cmd);
return 0;
+
+out_fail:
+ cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+ return -EINVAL;
}
EXPORT_SYMBOL(transport_generic_new_cmd);
@@ -4303,15 +3888,15 @@ void transport_generic_process_write(struct se_cmd *cmd)
}
EXPORT_SYMBOL(transport_generic_process_write);
-static int transport_write_pending_qf(struct se_cmd *cmd)
+static void transport_write_pending_qf(struct se_cmd *cmd)
{
- return cmd->se_tfo->write_pending(cmd);
+ if (cmd->se_tfo->write_pending(cmd) == -EAGAIN) {
+ pr_debug("Handling write_pending QUEUE__FULL: se_cmd: %p\n",
+ cmd);
+ transport_handle_queue_full(cmd, cmd->se_dev);
+ }
}
-/* transport_generic_write_pending():
- *
- *
- */
static int transport_generic_write_pending(struct se_cmd *cmd)
{
unsigned long flags;
@@ -4321,17 +3906,6 @@ static int transport_generic_write_pending(struct se_cmd *cmd)
cmd->t_state = TRANSPORT_WRITE_PENDING;
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- if (cmd->transport_qf_callback) {
- ret = cmd->transport_qf_callback(cmd);
- if (ret == -EAGAIN)
- goto queue_full;
- else if (ret < 0)
- return ret;
-
- cmd->transport_qf_callback = NULL;
- return 0;
- }
-
/*
* Clear the se_cmd for WRITE_PENDING status in order to set
* cmd->t_transport_active=0 so that transport_generic_handle_data
@@ -4356,61 +3930,52 @@ static int transport_generic_write_pending(struct se_cmd *cmd)
queue_full:
pr_debug("Handling write_pending QUEUE__FULL: se_cmd: %p\n", cmd);
cmd->t_state = TRANSPORT_COMPLETE_QF_WP;
- transport_handle_queue_full(cmd, cmd->se_dev,
- transport_write_pending_qf);
+ transport_handle_queue_full(cmd, cmd->se_dev);
return ret;
}
+/**
+ * transport_release_cmd - free a command
+ * @cmd: command to free
+ *
+ * This routine unconditionally frees a command, and reference counting
+ * or list removal must be done in the caller.
+ */
void transport_release_cmd(struct se_cmd *cmd)
{
BUG_ON(!cmd->se_tfo);
- transport_free_se_cmd(cmd);
+ if (cmd->se_tmr_req)
+ core_tmr_release_req(cmd->se_tmr_req);
+ if (cmd->t_task_cdb != cmd->__t_task_cdb)
+ kfree(cmd->t_task_cdb);
cmd->se_tfo->release_cmd(cmd);
}
EXPORT_SYMBOL(transport_release_cmd);
-/* transport_generic_free_cmd():
- *
- * Called from processing frontend to release storage engine resources
- */
-void transport_generic_free_cmd(
- struct se_cmd *cmd,
- int wait_for_tasks,
- int session_reinstatement)
+void transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
{
- if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD))
+ if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) {
+ if (wait_for_tasks && cmd->se_tmr_req)
+ transport_wait_for_tasks(cmd);
+
transport_release_cmd(cmd);
- else {
+ } else {
+ if (wait_for_tasks)
+ transport_wait_for_tasks(cmd);
+
core_dec_lacl_count(cmd->se_sess->se_node_acl, cmd);
- if (cmd->se_lun) {
-#if 0
- pr_debug("cmd: %p ITT: 0x%08x contains"
- " cmd->se_lun\n", cmd,
- cmd->se_tfo->get_task_tag(cmd));
-#endif
+ if (cmd->se_lun)
transport_lun_remove_cmd(cmd);
- }
-
- if (wait_for_tasks && cmd->transport_wait_for_tasks)
- cmd->transport_wait_for_tasks(cmd, 0, 0);
transport_free_dev_tasks(cmd);
- transport_generic_remove(cmd, session_reinstatement);
+ transport_put_cmd(cmd);
}
}
EXPORT_SYMBOL(transport_generic_free_cmd);
-static void transport_nop_wait_for_tasks(
- struct se_cmd *cmd,
- int remove_cmd,
- int session_reinstatement)
-{
- return;
-}
-
/* transport_lun_wait_for_tasks():
*
* Called from ConfigFS context to stop the passed struct se_cmd to allow
@@ -4449,7 +4014,7 @@ static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun)
pr_debug("ConfigFS: ITT[0x%08x] - stopped cmd....\n",
cmd->se_tfo->get_task_tag(cmd));
}
- transport_remove_cmd_from_queue(cmd, &cmd->se_dev->dev_queue_obj);
+ transport_remove_cmd_from_queue(cmd);
return 0;
}
@@ -4580,22 +4145,30 @@ int transport_clear_lun_from_sessions(struct se_lun *lun)
return 0;
}
-/* transport_generic_wait_for_tasks():
+/**
+ * transport_wait_for_tasks - wait for completion to occur
+ * @cmd: command to wait
*
- * Called from frontend or passthrough context to wait for storage engine
- * to pause and/or release frontend generated struct se_cmd.
+ * Called from frontend fabric context to wait for storage engine
+ * to pause and/or release frontend generated struct se_cmd.
*/
-static void transport_generic_wait_for_tasks(
- struct se_cmd *cmd,
- int remove_cmd,
- int session_reinstatement)
+void transport_wait_for_tasks(struct se_cmd *cmd)
{
unsigned long flags;
- if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) && !(cmd->se_tmr_req))
- return;
-
spin_lock_irqsave(&cmd->t_state_lock, flags);
+ if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) && !(cmd->se_tmr_req)) {
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+ return;
+ }
+ /*
+ * Only perform a possible wait_for_tasks if SCF_SUPPORTED_SAM_OPCODE
+ * has been set in transport_set_supported_SAM_opcode().
+ */
+ if (!(cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) && !cmd->se_tmr_req) {
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+ return;
+ }
/*
* If we are already stopped due to an external event (ie: LUN shutdown)
* sleep until the connection can have the passed struct se_cmd back.
@@ -4635,16 +4208,17 @@ static void transport_generic_wait_for_tasks(
atomic_set(&cmd->transport_lun_stop, 0);
}
if (!atomic_read(&cmd->t_transport_active) ||
- atomic_read(&cmd->t_transport_aborted))
- goto remove;
+ atomic_read(&cmd->t_transport_aborted)) {
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+ return;
+ }
atomic_set(&cmd->t_transport_stop, 1);
pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08x"
- " i_state: %d, t_state/def_t_state: %d/%d, t_transport_stop"
- " = TRUE\n", cmd, cmd->se_tfo->get_task_tag(cmd),
- cmd->se_tfo->get_cmd_state(cmd), cmd->t_state,
- cmd->deferred_t_state);
+ " i_state: %d, t_state: %d, t_transport_stop = TRUE\n",
+ cmd, cmd->se_tfo->get_task_tag(cmd),
+ cmd->se_tfo->get_cmd_state(cmd), cmd->t_state);
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
@@ -4659,13 +4233,10 @@ static void transport_generic_wait_for_tasks(
pr_debug("wait_for_tasks: Stopped wait_for_compltion("
"&cmd->t_transport_stop_comp) for ITT: 0x%08x\n",
cmd->se_tfo->get_task_tag(cmd));
-remove:
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- if (!remove_cmd)
- return;
- transport_generic_free_cmd(cmd, 0, session_reinstatement);
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
}
+EXPORT_SYMBOL(transport_wait_for_tasks);
static int transport_get_sense_codes(
struct se_cmd *cmd,
@@ -4726,6 +4297,13 @@ int transport_send_check_condition_and_sense(
*/
switch (reason) {
case TCM_NON_EXISTENT_LUN:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* ILLEGAL REQUEST */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+ /* LOGICAL UNIT NOT SUPPORTED */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x25;
+ break;
case TCM_UNSUPPORTED_SCSI_OPCODE:
case TCM_SECTOR_COUNT_TOO_MANY:
/* CURRENT ERROR */
@@ -4883,6 +4461,15 @@ EXPORT_SYMBOL(transport_check_aborted_status);
void transport_send_task_abort(struct se_cmd *cmd)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cmd->t_state_lock, flags);
+ if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+
/*
* If there are still expected incoming fabric WRITEs, we wait
* until until they have completed before sending a TASK_ABORTED
@@ -4947,184 +4534,10 @@ int transport_generic_do_tmr(struct se_cmd *cmd)
cmd->t_state = TRANSPORT_ISTATE_PROCESSING;
cmd->se_tfo->queue_tm_rsp(cmd);
- transport_cmd_check_stop(cmd, 2, 0);
+ transport_cmd_check_stop_to_fabric(cmd);
return 0;
}
-/*
- * Called with spin_lock_irq(&dev->execute_task_lock); held
- *
- */
-static struct se_task *
-transport_get_task_from_state_list(struct se_device *dev)
-{
- struct se_task *task;
-
- if (list_empty(&dev->state_task_list))
- return NULL;
-
- list_for_each_entry(task, &dev->state_task_list, t_state_list)
- break;
-
- list_del(&task->t_state_list);
- atomic_set(&task->task_state_active, 0);
-
- return task;
-}
-
-static void transport_processing_shutdown(struct se_device *dev)
-{
- struct se_cmd *cmd;
- struct se_task *task;
- unsigned long flags;
- /*
- * Empty the struct se_device's struct se_task state list.
- */
- spin_lock_irqsave(&dev->execute_task_lock, flags);
- while ((task = transport_get_task_from_state_list(dev))) {
- if (!task->task_se_cmd) {
- pr_err("task->task_se_cmd is NULL!\n");
- continue;
- }
- cmd = task->task_se_cmd;
-
- spin_unlock_irqrestore(&dev->execute_task_lock, flags);
-
- spin_lock_irqsave(&cmd->t_state_lock, flags);
-
- pr_debug("PT: cmd: %p task: %p ITT: 0x%08x,"
- " i_state: %d, t_state/def_t_state:"
- " %d/%d cdb: 0x%02x\n", cmd, task,
- cmd->se_tfo->get_task_tag(cmd),
- cmd->se_tfo->get_cmd_state(cmd),
- cmd->t_state, cmd->deferred_t_state,
- cmd->t_task_cdb[0]);
- pr_debug("PT: ITT[0x%08x] - t_tasks: %d t_task_cdbs_left:"
- " %d t_task_cdbs_sent: %d -- t_transport_active: %d"
- " t_transport_stop: %d t_transport_sent: %d\n",
- cmd->se_tfo->get_task_tag(cmd),
- cmd->t_task_list_num,
- atomic_read(&cmd->t_task_cdbs_left),
- atomic_read(&cmd->t_task_cdbs_sent),
- atomic_read(&cmd->t_transport_active),
- atomic_read(&cmd->t_transport_stop),
- atomic_read(&cmd->t_transport_sent));
-
- if (atomic_read(&task->task_active)) {
- atomic_set(&task->task_stop, 1);
- spin_unlock_irqrestore(
- &cmd->t_state_lock, flags);
-
- pr_debug("Waiting for task: %p to shutdown for dev:"
- " %p\n", task, dev);
- wait_for_completion(&task->task_stop_comp);
- pr_debug("Completed task: %p shutdown for dev: %p\n",
- task, dev);
-
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- atomic_dec(&cmd->t_task_cdbs_left);
-
- atomic_set(&task->task_active, 0);
- atomic_set(&task->task_stop, 0);
- } else {
- if (atomic_read(&task->task_execute_queue) != 0)
- transport_remove_task_from_execute_queue(task, dev);
- }
- __transport_stop_task_timer(task, &flags);
-
- if (!atomic_dec_and_test(&cmd->t_task_cdbs_ex_left)) {
- spin_unlock_irqrestore(
- &cmd->t_state_lock, flags);
-
- pr_debug("Skipping task: %p, dev: %p for"
- " t_task_cdbs_ex_left: %d\n", task, dev,
- atomic_read(&cmd->t_task_cdbs_ex_left));
-
- spin_lock_irqsave(&dev->execute_task_lock, flags);
- continue;
- }
-
- if (atomic_read(&cmd->t_transport_active)) {
- pr_debug("got t_transport_active = 1 for task: %p, dev:"
- " %p\n", task, dev);
-
- if (atomic_read(&cmd->t_fe_count)) {
- spin_unlock_irqrestore(
- &cmd->t_state_lock, flags);
- transport_send_check_condition_and_sense(
- cmd, TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE,
- 0);
- transport_remove_cmd_from_queue(cmd,
- &cmd->se_dev->dev_queue_obj);
-
- transport_lun_remove_cmd(cmd);
- transport_cmd_check_stop(cmd, 1, 0);
- } else {
- spin_unlock_irqrestore(
- &cmd->t_state_lock, flags);
-
- transport_remove_cmd_from_queue(cmd,
- &cmd->se_dev->dev_queue_obj);
-
- transport_lun_remove_cmd(cmd);
-
- if (transport_cmd_check_stop(cmd, 1, 0))
- transport_generic_remove(cmd, 0);
- }
-
- spin_lock_irqsave(&dev->execute_task_lock, flags);
- continue;
- }
- pr_debug("Got t_transport_active = 0 for task: %p, dev: %p\n",
- task, dev);
-
- if (atomic_read(&cmd->t_fe_count)) {
- spin_unlock_irqrestore(
- &cmd->t_state_lock, flags);
- transport_send_check_condition_and_sense(cmd,
- TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
- transport_remove_cmd_from_queue(cmd,
- &cmd->se_dev->dev_queue_obj);
-
- transport_lun_remove_cmd(cmd);
- transport_cmd_check_stop(cmd, 1, 0);
- } else {
- spin_unlock_irqrestore(
- &cmd->t_state_lock, flags);
-
- transport_remove_cmd_from_queue(cmd,
- &cmd->se_dev->dev_queue_obj);
- transport_lun_remove_cmd(cmd);
-
- if (transport_cmd_check_stop(cmd, 1, 0))
- transport_generic_remove(cmd, 0);
- }
-
- spin_lock_irqsave(&dev->execute_task_lock, flags);
- }
- spin_unlock_irqrestore(&dev->execute_task_lock, flags);
- /*
- * Empty the struct se_device's struct se_cmd list.
- */
- while ((cmd = transport_get_cmd_from_queue(&dev->dev_queue_obj))) {
-
- pr_debug("From Device Queue: cmd: %p t_state: %d\n",
- cmd, cmd->t_state);
-
- if (atomic_read(&cmd->t_fe_count)) {
- transport_send_check_condition_and_sense(cmd,
- TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
-
- transport_lun_remove_cmd(cmd);
- transport_cmd_check_stop(cmd, 1, 0);
- } else {
- transport_lun_remove_cmd(cmd);
- if (transport_cmd_check_stop(cmd, 1, 0))
- transport_generic_remove(cmd, 0);
- }
- }
-}
-
/* transport_processing_thread():
*
*
@@ -5144,14 +4557,6 @@ static int transport_processing_thread(void *param)
if (ret < 0)
goto out;
- spin_lock_irq(&dev->dev_status_lock);
- if (dev->dev_status & TRANSPORT_DEVICE_SHUTDOWN) {
- spin_unlock_irq(&dev->dev_status_lock);
- transport_processing_shutdown(dev);
- continue;
- }
- spin_unlock_irq(&dev->dev_status_lock);
-
get_cmd:
__transport_execute_tasks(dev);
@@ -5160,6 +4565,9 @@ get_cmd:
continue;
switch (cmd->t_state) {
+ case TRANSPORT_NEW_CMD:
+ BUG();
+ break;
case TRANSPORT_NEW_CMD_MAP:
if (!cmd->se_tfo->new_cmd_map) {
pr_err("cmd->se_tfo->new_cmd_map is"
@@ -5169,19 +4577,17 @@ get_cmd:
ret = cmd->se_tfo->new_cmd_map(cmd);
if (ret < 0) {
cmd->transport_error_status = ret;
- transport_generic_request_failure(cmd, NULL,
+ transport_generic_request_failure(cmd,
0, (cmd->data_direction !=
DMA_TO_DEVICE));
break;
}
- /* Fall through */
- case TRANSPORT_NEW_CMD:
ret = transport_generic_new_cmd(cmd);
if (ret == -EAGAIN)
break;
else if (ret < 0) {
cmd->transport_error_status = ret;
- transport_generic_request_failure(cmd, NULL,
+ transport_generic_request_failure(cmd,
0, (cmd->data_direction !=
DMA_TO_DEVICE));
}
@@ -5189,33 +4595,22 @@ get_cmd:
case TRANSPORT_PROCESS_WRITE:
transport_generic_process_write(cmd);
break;
- case TRANSPORT_COMPLETE_OK:
- transport_stop_all_task_timers(cmd);
- transport_generic_complete_ok(cmd);
- break;
- case TRANSPORT_REMOVE:
- transport_generic_remove(cmd, 0);
- break;
case TRANSPORT_FREE_CMD_INTR:
- transport_generic_free_cmd(cmd, 0, 0);
+ transport_generic_free_cmd(cmd, 0);
break;
case TRANSPORT_PROCESS_TMR:
transport_generic_do_tmr(cmd);
break;
- case TRANSPORT_COMPLETE_FAILURE:
- transport_generic_request_failure(cmd, NULL, 1, 1);
- break;
- case TRANSPORT_COMPLETE_TIMEOUT:
- transport_stop_all_task_timers(cmd);
- transport_generic_request_timeout(cmd);
- break;
case TRANSPORT_COMPLETE_QF_WP:
- transport_generic_write_pending(cmd);
+ transport_write_pending_qf(cmd);
+ break;
+ case TRANSPORT_COMPLETE_QF_OK:
+ transport_complete_qf(cmd);
break;
default:
- pr_err("Unknown t_state: %d deferred_t_state:"
- " %d for ITT: 0x%08x i_state: %d on SE LUN:"
- " %u\n", cmd->t_state, cmd->deferred_t_state,
+ pr_err("Unknown t_state: %d for ITT: 0x%08x "
+ "i_state: %d on SE LUN: %u\n",
+ cmd->t_state,
cmd->se_tfo->get_task_tag(cmd),
cmd->se_tfo->get_cmd_state(cmd),
cmd->se_lun->unpacked_lun);
@@ -5226,7 +4621,8 @@ get_cmd:
}
out:
- transport_release_all_cmds(dev);
+ WARN_ON(!list_empty(&dev->state_task_list));
+ WARN_ON(!list_empty(&dev->dev_queue_obj.qobj_list));
dev->process_thread = NULL;
return 0;
}
diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c
index 31e3c652527e..50a480db7a66 100644
--- a/drivers/target/target_core_ua.c
+++ b/drivers/target/target_core_ua.c
@@ -24,7 +24,6 @@
*
******************************************************************************/
-#include <linux/version.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <scsi/scsi.h>
diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h
index bd4fe21a23b8..3749d8b4b423 100644
--- a/drivers/target/tcm_fc/tcm_fc.h
+++ b/drivers/target/tcm_fc/tcm_fc.h
@@ -98,8 +98,7 @@ struct ft_tpg {
struct list_head list; /* linkage in ft_lport_acl tpg_list */
struct list_head lun_list; /* head of LUNs */
struct se_portal_group se_tpg;
- struct task_struct *thread; /* processing thread */
- struct se_queue_obj qobj; /* queue for processing thread */
+ struct workqueue_struct *workqueue;
};
struct ft_lport_acl {
@@ -110,16 +109,10 @@ struct ft_lport_acl {
struct se_wwn fc_lport_wwn;
};
-enum ft_cmd_state {
- FC_CMD_ST_NEW = 0,
- FC_CMD_ST_REJ
-};
-
/*
* Commands
*/
struct ft_cmd {
- enum ft_cmd_state state;
u32 lun; /* LUN from request */
struct ft_sess *sess; /* session held for cmd */
struct fc_seq *seq; /* sequence in exchange mgr */
@@ -127,7 +120,7 @@ struct ft_cmd {
struct fc_frame *req_frame;
unsigned char *cdb; /* pointer to CDB inside frame */
u32 write_data_len; /* data received on writes */
- struct se_queue_req se_req;
+ struct work_struct work;
/* Local sense buffer */
unsigned char ft_sense_buffer[TRANSPORT_SENSE_BUFFER];
u32 was_ddp_setup:1; /* Set only if ddp is setup */
@@ -177,7 +170,6 @@ int ft_is_state_remove(struct se_cmd *);
/*
* other internal functions.
*/
-int ft_thread(void *);
void ft_recv_req(struct ft_sess *, struct fc_frame *);
struct ft_tpg *ft_lport_find_tpg(struct fc_lport *);
struct ft_node_acl *ft_acl_get(struct ft_tpg *, struct fc_rport_priv *);
diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c
index 5654dc22f7ae..6195026cc7b0 100644
--- a/drivers/target/tcm_fc/tfc_cmd.c
+++ b/drivers/target/tcm_fc/tfc_cmd.c
@@ -19,7 +19,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/version.h>
#include <generated/utsrelease.h>
#include <linux/utsname.h>
#include <linux/init.h>
@@ -62,8 +61,8 @@ void ft_dump_cmd(struct ft_cmd *cmd, const char *caller)
int count;
se_cmd = &cmd->se_cmd;
- pr_debug("%s: cmd %p state %d sess %p seq %p se_cmd %p\n",
- caller, cmd, cmd->state, cmd->sess, cmd->seq, se_cmd);
+ pr_debug("%s: cmd %p sess %p seq %p se_cmd %p\n",
+ caller, cmd, cmd->sess, cmd->seq, se_cmd);
pr_debug("%s: cmd %p cdb %p\n",
caller, cmd, cmd->cdb);
pr_debug("%s: cmd %p lun %d\n", caller, cmd, cmd->lun);
@@ -90,38 +89,6 @@ void ft_dump_cmd(struct ft_cmd *cmd, const char *caller)
16, 4, cmd->cdb, MAX_COMMAND_SIZE, 0);
}
-static void ft_queue_cmd(struct ft_sess *sess, struct ft_cmd *cmd)
-{
- struct ft_tpg *tpg = sess->tport->tpg;
- struct se_queue_obj *qobj = &tpg->qobj;
- unsigned long flags;
-
- qobj = &sess->tport->tpg->qobj;
- spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
- list_add_tail(&cmd->se_req.qr_list, &qobj->qobj_list);
- atomic_inc(&qobj->queue_cnt);
- spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
-
- wake_up_process(tpg->thread);
-}
-
-static struct ft_cmd *ft_dequeue_cmd(struct se_queue_obj *qobj)
-{
- unsigned long flags;
- struct se_queue_req *qr;
-
- spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
- if (list_empty(&qobj->qobj_list)) {
- spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
- return NULL;
- }
- qr = list_first_entry(&qobj->qobj_list, struct se_queue_req, qr_list);
- list_del(&qr->qr_list);
- atomic_dec(&qobj->queue_cnt);
- spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
- return container_of(qr, struct ft_cmd, se_req);
-}
-
static void ft_free_cmd(struct ft_cmd *cmd)
{
struct fc_frame *fp;
@@ -147,7 +114,7 @@ void ft_release_cmd(struct se_cmd *se_cmd)
void ft_check_stop_free(struct se_cmd *se_cmd)
{
- transport_generic_free_cmd(se_cmd, 0, 0);
+ transport_generic_free_cmd(se_cmd, 0);
}
/*
@@ -282,9 +249,7 @@ u32 ft_get_task_tag(struct se_cmd *se_cmd)
int ft_get_cmd_state(struct se_cmd *se_cmd)
{
- struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd);
-
- return cmd->state;
+ return 0;
}
int ft_is_state_remove(struct se_cmd *se_cmd)
@@ -302,9 +267,8 @@ static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg)
if (IS_ERR(fp)) {
/* XXX need to find cmd if queued */
- cmd->se_cmd.t_state = TRANSPORT_REMOVE;
cmd->seq = NULL;
- transport_generic_free_cmd(&cmd->se_cmd, 0, 0);
+ transport_generic_free_cmd(&cmd->se_cmd, 0);
return;
}
@@ -322,7 +286,7 @@ static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg)
__func__, fh->fh_r_ctl);
ft_invl_hw_context(cmd);
fc_frame_free(fp);
- transport_generic_free_cmd(&cmd->se_cmd, 0, 0);
+ transport_generic_free_cmd(&cmd->se_cmd, 0);
break;
}
}
@@ -431,7 +395,7 @@ static void ft_send_tm(struct ft_cmd *cmd)
}
pr_debug("alloc tm cmd fn %d\n", tm_func);
- tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func);
+ tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func, GFP_KERNEL);
if (!tmr) {
pr_debug("alloc failed\n");
ft_send_resp_code_and_free(cmd, FCP_TMF_FAILED);
@@ -455,7 +419,7 @@ static void ft_send_tm(struct ft_cmd *cmd)
sess = cmd->sess;
transport_send_check_condition_and_sense(&cmd->se_cmd,
cmd->se_cmd.scsi_sense_reason, 0);
- transport_generic_free_cmd(&cmd->se_cmd, 0, 0);
+ transport_generic_free_cmd(&cmd->se_cmd, 0);
ft_sess_put(sess);
return;
}
@@ -505,6 +469,8 @@ int ft_queue_tm_resp(struct se_cmd *se_cmd)
return 0;
}
+static void ft_send_work(struct work_struct *work);
+
/*
* Handle incoming FCP command.
*/
@@ -523,7 +489,9 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp)
goto busy;
}
cmd->req_frame = fp; /* hold frame during cmd */
- ft_queue_cmd(sess, cmd);
+
+ INIT_WORK(&cmd->work, ft_send_work);
+ queue_work(sess->tport->tpg->workqueue, &cmd->work);
return;
busy:
@@ -563,12 +531,13 @@ void ft_recv_req(struct ft_sess *sess, struct fc_frame *fp)
/*
* Send new command to target.
*/
-static void ft_send_cmd(struct ft_cmd *cmd)
+static void ft_send_work(struct work_struct *work)
{
+ struct ft_cmd *cmd = container_of(work, struct ft_cmd, work);
struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame);
struct se_cmd *se_cmd;
struct fcp_cmnd *fcp;
- int data_dir;
+ int data_dir = 0;
u32 data_len;
int task_attr;
int ret;
@@ -657,7 +626,7 @@ static void ft_send_cmd(struct ft_cmd *cmd)
if (ret == -ENOMEM) {
transport_send_check_condition_and_sense(se_cmd,
TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
- transport_generic_free_cmd(se_cmd, 0, 0);
+ transport_generic_free_cmd(se_cmd, 0);
return;
}
if (ret == -EINVAL) {
@@ -666,51 +635,12 @@ static void ft_send_cmd(struct ft_cmd *cmd)
else
transport_send_check_condition_and_sense(se_cmd,
se_cmd->scsi_sense_reason, 0);
- transport_generic_free_cmd(se_cmd, 0, 0);
+ transport_generic_free_cmd(se_cmd, 0);
return;
}
- transport_generic_handle_cdb(se_cmd);
+ transport_handle_cdb_direct(se_cmd);
return;
err:
ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID);
}
-
-/*
- * Handle request in the command thread.
- */
-static void ft_exec_req(struct ft_cmd *cmd)
-{
- pr_debug("cmd state %x\n", cmd->state);
- switch (cmd->state) {
- case FC_CMD_ST_NEW:
- ft_send_cmd(cmd);
- break;
- default:
- break;
- }
-}
-
-/*
- * Processing thread.
- * Currently one thread per tpg.
- */
-int ft_thread(void *arg)
-{
- struct ft_tpg *tpg = arg;
- struct se_queue_obj *qobj = &tpg->qobj;
- struct ft_cmd *cmd;
-
- while (!kthread_should_stop()) {
- schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT);
- if (kthread_should_stop())
- goto out;
-
- cmd = ft_dequeue_cmd(qobj);
- if (cmd)
- ft_exec_req(cmd);
- }
-
-out:
- return 0;
-}
diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c
index 8781d1e423df..5f770412ca40 100644
--- a/drivers/target/tcm_fc/tfc_conf.c
+++ b/drivers/target/tcm_fc/tfc_conf.c
@@ -23,7 +23,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/version.h>
#include <generated/utsrelease.h>
#include <linux/utsname.h>
#include <linux/init.h>
@@ -32,6 +31,7 @@
#include <linux/types.h>
#include <linux/string.h>
#include <linux/configfs.h>
+#include <linux/kernel.h>
#include <linux/ctype.h>
#include <asm/unaligned.h>
#include <scsi/scsi.h>
@@ -71,10 +71,10 @@ static ssize_t ft_parse_wwn(const char *name, u64 *wwn, int strict)
{
const char *cp;
char c;
- u32 nibble;
u32 byte = 0;
u32 pos = 0;
u32 err;
+ int val;
*wwn = 0;
for (cp = name; cp < &name[FT_NAMELEN - 1]; cp++) {
@@ -95,13 +95,10 @@ static ssize_t ft_parse_wwn(const char *name, u64 *wwn, int strict)
return cp - name;
}
err = 3;
- if (isdigit(c))
- nibble = c - '0';
- else if (isxdigit(c) && (islower(c) || !strict))
- nibble = tolower(c) - 'a' + 10;
- else
+ val = hex_to_bin(c);
+ if (val < 0 || (strict && isupper(c)))
goto fail;
- *wwn = (*wwn << 4) | nibble;
+ *wwn = (*wwn << 4) | val;
}
err = 4;
fail:
@@ -256,7 +253,7 @@ struct ft_node_acl *ft_acl_get(struct ft_tpg *tpg, struct fc_rport_priv *rdata)
struct se_portal_group *se_tpg = &tpg->se_tpg;
struct se_node_acl *se_acl;
- spin_lock_bh(&se_tpg->acl_node_lock);
+ spin_lock_irq(&se_tpg->acl_node_lock);
list_for_each_entry(se_acl, &se_tpg->acl_node_list, acl_list) {
acl = container_of(se_acl, struct ft_node_acl, se_node_acl);
pr_debug("acl %p port_name %llx\n",
@@ -270,7 +267,7 @@ struct ft_node_acl *ft_acl_get(struct ft_tpg *tpg, struct fc_rport_priv *rdata)
break;
}
}
- spin_unlock_bh(&se_tpg->acl_node_lock);
+ spin_unlock_irq(&se_tpg->acl_node_lock);
return found;
}
@@ -327,7 +324,6 @@ static struct se_portal_group *ft_add_tpg(
tpg->index = index;
tpg->lport_acl = lacl;
INIT_LIST_HEAD(&tpg->lun_list);
- transport_init_queue_obj(&tpg->qobj);
ret = core_tpg_register(&ft_configfs->tf_ops, wwn, &tpg->se_tpg,
tpg, TRANSPORT_TPG_TYPE_NORMAL);
@@ -336,8 +332,8 @@ static struct se_portal_group *ft_add_tpg(
return NULL;
}
- tpg->thread = kthread_run(ft_thread, tpg, "ft_tpg%lu", index);
- if (IS_ERR(tpg->thread)) {
+ tpg->workqueue = alloc_workqueue("tcm_fc", 0, 1);
+ if (!tpg->workqueue) {
kfree(tpg);
return NULL;
}
@@ -356,7 +352,7 @@ static void ft_del_tpg(struct se_portal_group *se_tpg)
pr_debug("del tpg %s\n",
config_item_name(&tpg->se_tpg.tpg_group.cg_item));
- kthread_stop(tpg->thread);
+ destroy_workqueue(tpg->workqueue);
/* Wait for sessions to be freed thru RCU, for BUG_ON below */
synchronize_rcu();
@@ -655,9 +651,7 @@ static void __exit ft_exit(void)
synchronize_rcu();
}
-#ifdef MODULE
MODULE_DESCRIPTION("FC TCM fabric driver " FT_VERSION);
MODULE_LICENSE("GPL");
module_init(ft_init);
module_exit(ft_exit);
-#endif /* MODULE */
diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c
index c37f4cd96452..1369b1cb103d 100644
--- a/drivers/target/tcm_fc/tfc_io.c
+++ b/drivers/target/tcm_fc/tfc_io.c
@@ -28,7 +28,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/version.h>
#include <generated/utsrelease.h>
#include <linux/utsname.h>
#include <linux/init.h>
@@ -219,43 +218,41 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp)
if (cmd->was_ddp_setup) {
BUG_ON(!ep);
BUG_ON(!lport);
- }
-
- /*
- * Doesn't expect payload if DDP is setup. Payload
- * is expected to be copied directly to user buffers
- * due to DDP (Large Rx offload),
- */
- buf = fc_frame_payload_get(fp, 1);
- if (buf)
- pr_err("%s: xid 0x%x, f_ctl 0x%x, cmd->sg %p, "
+ /*
+ * Since DDP (Large Rx offload) was setup for this request,
+ * payload is expected to be copied directly to user buffers.
+ */
+ buf = fc_frame_payload_get(fp, 1);
+ if (buf)
+ pr_err("%s: xid 0x%x, f_ctl 0x%x, cmd->sg %p, "
"cmd->sg_cnt 0x%x. DDP was setup"
" hence not expected to receive frame with "
- "payload, Frame will be dropped if "
- "'Sequence Initiative' bit in f_ctl is "
+ "payload, Frame will be dropped if"
+ "'Sequence Initiative' bit in f_ctl is"
"not set\n", __func__, ep->xid, f_ctl,
cmd->sg, cmd->sg_cnt);
- /*
- * Invalidate HW DDP context if it was setup for respective
- * command. Invalidation of HW DDP context is requited in both
- * situation (success and error).
- */
- ft_invl_hw_context(cmd);
+ /*
+ * Invalidate HW DDP context if it was setup for respective
+ * command. Invalidation of HW DDP context is requited in both
+ * situation (success and error).
+ */
+ ft_invl_hw_context(cmd);
- /*
- * If "Sequence Initiative (TSI)" bit set in f_ctl, means last
- * write data frame is received successfully where payload is
- * posted directly to user buffer and only the last frame's
- * header is posted in receive queue.
- *
- * If "Sequence Initiative (TSI)" bit is not set, means error
- * condition w.r.t. DDP, hence drop the packet and let explict
- * ABORTS from other end of exchange timer trigger the recovery.
- */
- if (f_ctl & FC_FC_SEQ_INIT)
- goto last_frame;
- else
- goto drop;
+ /*
+ * If "Sequence Initiative (TSI)" bit set in f_ctl, means last
+ * write data frame is received successfully where payload is
+ * posted directly to user buffer and only the last frame's
+ * header is posted in receive queue.
+ *
+ * If "Sequence Initiative (TSI)" bit is not set, means error
+ * condition w.r.t. DDP, hence drop the packet and let explict
+ * ABORTS from other end of exchange timer trigger the recovery.
+ */
+ if (f_ctl & FC_FC_SEQ_INIT)
+ goto last_frame;
+ else
+ goto drop;
+ }
rel_off = ntohl(fh->fh_parm_offset);
frame_len = fr_len(fp);
diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c
index dbb5eaeee399..326921385aff 100644
--- a/drivers/target/tcm_fc/tfc_sess.c
+++ b/drivers/target/tcm_fc/tfc_sess.c
@@ -19,7 +19,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/version.h>
#include <generated/utsrelease.h>
#include <linux/utsname.h>
#include <linux/init.h>
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig
index f1ea59b09444..8816f53e004d 100644
--- a/drivers/tty/Kconfig
+++ b/drivers/tty/Kconfig
@@ -60,9 +60,13 @@ config VT_CONSOLE
If unsure, say Y.
+config VT_CONSOLE_SLEEP
+ def_bool y
+ depends on VT_CONSOLE && PM_SLEEP
+
config HW_CONSOLE
bool
- depends on VT && !S390 && !UML
+ depends on VT && !UML
default y
config VT_HW_CONSOLE_BINDING
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 2feea63d497a..e18604b3fc7d 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -446,8 +446,19 @@ static inline void legacy_pty_init(void) { }
int pty_limit = NR_UNIX98_PTY_DEFAULT;
static int pty_limit_min;
static int pty_limit_max = NR_UNIX98_PTY_MAX;
+static int tty_count;
static int pty_count;
+static inline void pty_inc_count(void)
+{
+ pty_count = (++tty_count) / 2;
+}
+
+static inline void pty_dec_count(void)
+{
+ pty_count = (--tty_count) / 2;
+}
+
static struct cdev ptmx_cdev;
static struct ctl_table pty_table[] = {
@@ -542,6 +553,7 @@ static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
static void pty_unix98_shutdown(struct tty_struct *tty)
{
+ tty_driver_remove_tty(tty->driver, tty);
/* We have our own method as we don't use the tty index */
kfree(tty->termios);
}
@@ -588,7 +600,8 @@ static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
*/
tty_driver_kref_get(driver);
tty->count++;
- pty_count++;
+ pty_inc_count(); /* tty */
+ pty_inc_count(); /* tty->link */
return 0;
err_free_mem:
deinitialize_tty_struct(o_tty);
@@ -602,7 +615,7 @@ err_free_tty:
static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
{
- pty_count--;
+ pty_dec_count();
}
static const struct tty_operations ptm_unix98_ops = {
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c
index 076e9c6269d3..a87a56cb5417 100644
--- a/drivers/tty/serial/8250.c
+++ b/drivers/tty/serial/8250.c
@@ -1795,6 +1795,8 @@ static void serial8250_backup_timeout(unsigned long data)
unsigned int iir, ier = 0, lsr;
unsigned long flags;
+ spin_lock_irqsave(&up->port.lock, flags);
+
/*
* Must disable interrupts or else we risk racing with the interrupt
* based handler.
@@ -1812,10 +1814,8 @@ static void serial8250_backup_timeout(unsigned long data)
* the "Diva" UART used on the management processor on many HP
* ia64 and parisc boxes.
*/
- spin_lock_irqsave(&up->port.lock, flags);
lsr = serial_in(up, UART_LSR);
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
- spin_unlock_irqrestore(&up->port.lock, flags);
if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
(!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) &&
(lsr & UART_LSR_THRE)) {
@@ -1824,11 +1824,13 @@ static void serial8250_backup_timeout(unsigned long data)
}
if (!(iir & UART_IIR_NO_INT))
- serial8250_handle_port(up);
+ transmit_chars(up);
if (is_real_interrupt(up->port.irq))
serial_out(up, UART_IER, ier);
+ spin_unlock_irqrestore(&up->port.lock, flags);
+
/* Standard timer interval plus 0.2s to keep the port running */
mod_timer(&up->timer,
jiffies + uart_poll_timeout(&up->port) + HZ / 5);
diff --git a/drivers/tty/serial/8250_pci.c b/drivers/tty/serial/8250_pci.c
index 1b449b759990..825937a5f210 100644
--- a/drivers/tty/serial/8250_pci.c
+++ b/drivers/tty/serial/8250_pci.c
@@ -1641,12 +1641,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
- {
- .vendor = 0x10DB,
- .device = 0x800D,
- .init = pci_eg20t_init,
- .setup = pci_default_setup,
- },
/*
* Cronyx Omega PCI (PLX-chip based)
*/
@@ -4064,7 +4058,7 @@ static struct pci_device_id serial_pci_tbl[] = {
0, 0, pbn_NETMOS9900_2s_115200 },
/*
- * Best Connectivity PCI Multi I/O cards
+ * Best Connectivity and Rosewill PCI Multi I/O cards
*/
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
@@ -4072,6 +4066,10 @@ static struct pci_device_id serial_pci_tbl[] = {
0, 0, pbn_b0_1_115200 },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
+ 0xA000, 0x3002,
+ 0, 0, pbn_b0_bt_2_115200 },
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
0xA000, 0x3004,
0, 0, pbn_b0_bt_4_115200 },
/* Intel CE4100 */
diff --git a/drivers/tty/serial/8250_pnp.c b/drivers/tty/serial/8250_pnp.c
index fc301f6722e1..a2f236510ff1 100644
--- a/drivers/tty/serial/8250_pnp.c
+++ b/drivers/tty/serial/8250_pnp.c
@@ -109,6 +109,9 @@ static const struct pnp_device_id pnp_dev_table[] = {
/* IBM */
/* IBM Thinkpad 701 Internal Modem Voice */
{ "IBM0033", 0 },
+ /* Intermec */
+ /* Intermec CV60 touchscreen port */
+ { "PNP4972", 0 },
/* Intertex */
/* Intertex 28k8 33k6 Voice EXT PnP */
{ "IXDC801", 0 },
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 358bbb279d2b..9988c0c305c2 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -1671,7 +1671,9 @@ static struct console atmel_console = {
static int __init atmel_console_init(void)
{
if (atmel_default_console_device) {
- int id = atmel_default_console_device->id;
+ struct atmel_uart_data *pdata =
+ atmel_default_console_device->dev.platform_data;
+ int id = pdata->num;
struct atmel_uart_port *port = &atmel_ports[id];
port->backup_imr = 0;
diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index 9e2d42bfa557..96c1cacc7360 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -478,8 +478,10 @@ lqasc_set_termios(struct uart_port *port,
spin_unlock_irqrestore(&ltq_asc_lock, flags);
/* Don't rewrite B0 */
- if (tty_termios_baud_rate(new))
+ if (tty_termios_baud_rate(new))
tty_termios_encode_baud_rate(new, baud, baud);
+
+ uart_update_timeout(port, cflag, baud);
}
static const char*
diff --git a/drivers/tty/serial/max3107-aava.c b/drivers/tty/serial/max3107-aava.c
index a1fe304f2f52..d73aadd7a9ad 100644
--- a/drivers/tty/serial/max3107-aava.c
+++ b/drivers/tty/serial/max3107-aava.c
@@ -340,5 +340,5 @@ module_exit(max3107_exit);
MODULE_DESCRIPTION("MAX3107 driver");
MODULE_AUTHOR("Aavamobile");
-MODULE_ALIAS("aava-max3107-spi");
+MODULE_ALIAS("spi:aava-max3107");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/max3107.c b/drivers/tty/serial/max3107.c
index 47602a227afe..db00b595cab0 100644
--- a/drivers/tty/serial/max3107.c
+++ b/drivers/tty/serial/max3107.c
@@ -1211,5 +1211,5 @@ module_exit(max3107_exit);
MODULE_DESCRIPTION("MAX3107 driver");
MODULE_AUTHOR("Aavamobile");
-MODULE_ALIAS("max3107-spi");
+MODULE_ALIAS("spi:max3107");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c
index 1aa2c3cd2146..4c309e869903 100644
--- a/drivers/tty/serial/mrst_max3110.c
+++ b/drivers/tty/serial/mrst_max3110.c
@@ -23,7 +23,7 @@
* 1 word. If SPI master controller doesn't support sclk frequency change,
* then the char need be sent out one by one with some delay
*
- * 2. Currently only RX available interrrupt is used, no need for waiting TXE
+ * 2. Currently only RX available interrupt is used, no need for waiting TXE
* interrupt for a low speed UART device
*/
@@ -910,4 +910,4 @@ module_init(serial_m3110_init);
module_exit(serial_m3110_exit);
MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("max3110-uart");
+MODULE_ALIAS("spi:max3110-uart");
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index c37df8d0fa28..5e713d3ef1f4 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -806,8 +806,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
serial_omap_set_mctrl(&up->port, up->port.mctrl);
/* Software Flow Control Configuration */
- if (termios->c_iflag & (IXON | IXOFF))
- serial_omap_configure_xonxoff(up, termios);
+ serial_omap_configure_xonxoff(up, termios);
spin_unlock_irqrestore(&up->port.lock, flags);
dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->pdev->id);
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index ecc8506f3b42..21febef926aa 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -600,7 +600,8 @@ static void pch_request_dma(struct uart_port *port)
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
- dma_dev = pci_get_bus_and_slot(2, PCI_DEVFN(0xa, 0)); /* Get DMA's dev
+ dma_dev = pci_get_bus_and_slot(priv->pdev->bus->number,
+ PCI_DEVFN(0xa, 0)); /* Get DMA's dev
information */
/* Set Tx DMA */
param = &priv->param_tx;
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 9b8465487253..b31f1c3a2c4c 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -1308,15 +1308,19 @@ static const struct dev_pm_ops s3c24xx_serial_pm_ops = {
.suspend = s3c24xx_serial_suspend,
.resume = s3c24xx_serial_resume,
};
+#define SERIAL_SAMSUNG_PM_OPS (&s3c24xx_serial_pm_ops)
+
#else /* !CONFIG_PM_SLEEP */
-#define s3c24xx_serial_pm_ops NULL
+
+#define SERIAL_SAMSUNG_PM_OPS NULL
#endif /* CONFIG_PM_SLEEP */
int s3c24xx_serial_init(struct platform_driver *drv,
struct s3c24xx_uart_info *info)
{
dbg("s3c24xx_serial_init(%p,%p)\n", drv, info);
- drv->driver.pm = &s3c24xx_serial_pm_ops;
+
+ drv->driver.pm = SERIAL_SAMSUNG_PM_OPS;
return platform_driver_register(drv);
}
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 9f72be28e6f2..0406d7ff505e 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -194,6 +194,11 @@ static int uart_startup(struct tty_struct *tty, struct uart_state *state, int in
clear_bit(TTY_IO_ERROR, &tty->flags);
}
+ /*
+ * This is to allow setserial on this port. People may want to set
+ * port/irq/type and then reconfigure the port properly if it failed
+ * now.
+ */
if (retval && capable(CAP_SYS_ADMIN))
retval = 0;
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index ca1a4c385d40..9871c57b348e 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -47,6 +47,7 @@
#include <linux/ctype.h>
#include <linux/err.h>
#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
@@ -95,6 +96,12 @@ struct sci_port {
#endif
struct notifier_block freq_transition;
+
+#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+ unsigned short saved_smr;
+ unsigned short saved_fcr;
+ unsigned char saved_brr;
+#endif
};
/* Function prototypes */
@@ -1076,7 +1083,7 @@ static unsigned int sci_get_mctrl(struct uart_port *port)
/* This routine is used for getting signals of: DTR, DCD, DSR, RI,
and CTS/RTS */
- return TIOCM_DTR | TIOCM_RTS | TIOCM_DSR;
+ return TIOCM_DTR | TIOCM_RTS | TIOCM_CTS | TIOCM_DSR;
}
#ifdef CONFIG_SERIAL_SH_SCI_DMA
@@ -1633,11 +1640,25 @@ static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps,
return ((freq + 16 * bps) / (32 * bps) - 1);
}
+static void sci_reset(struct uart_port *port)
+{
+ unsigned int status;
+
+ do {
+ status = sci_in(port, SCxSR);
+ } while (!(status & SCxSR_TEND(port)));
+
+ sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */
+
+ if (port->type != PORT_SCI)
+ sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
+}
+
static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
struct sci_port *s = to_sci_port(port);
- unsigned int status, baud, smr_val, max_baud;
+ unsigned int baud, smr_val, max_baud;
int t = -1;
u16 scfcr = 0;
@@ -1657,14 +1678,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
sci_port_enable(s);
- do {
- status = sci_in(port, SCxSR);
- } while (!(status & SCxSR_TEND(port)));
-
- sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */
-
- if (port->type != PORT_SCI)
- sci_out(port, SCFCR, scfcr | SCFCR_RFRST | SCFCR_TFRST);
+ sci_reset(port);
smr_val = sci_in(port, SCSMR) & 3;
@@ -1913,6 +1927,7 @@ static int __devinit sci_init_single(struct platform_device *dev,
port->dev = &dev->dev;
+ pm_runtime_irq_safe(&dev->dev);
pm_runtime_enable(&dev->dev);
}
@@ -2036,7 +2051,8 @@ static int __devinit serial_console_setup(struct console *co, char *options)
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
- /* TODO: disable clock */
+ sci_port_disable(sci_port);
+
return uart_set_options(port, co, baud, parity, bits, flow);
}
@@ -2079,6 +2095,36 @@ static int __devinit sci_probe_earlyprintk(struct platform_device *pdev)
return 0;
}
+#define uart_console(port) ((port)->cons->index == (port)->line)
+
+static int sci_runtime_suspend(struct device *dev)
+{
+ struct sci_port *sci_port = dev_get_drvdata(dev);
+ struct uart_port *port = &sci_port->port;
+
+ if (uart_console(port)) {
+ sci_port->saved_smr = sci_in(port, SCSMR);
+ sci_port->saved_brr = sci_in(port, SCBRR);
+ sci_port->saved_fcr = sci_in(port, SCFCR);
+ }
+ return 0;
+}
+
+static int sci_runtime_resume(struct device *dev)
+{
+ struct sci_port *sci_port = dev_get_drvdata(dev);
+ struct uart_port *port = &sci_port->port;
+
+ if (uart_console(port)) {
+ sci_reset(port);
+ sci_out(port, SCSMR, sci_port->saved_smr);
+ sci_out(port, SCBRR, sci_port->saved_brr);
+ sci_out(port, SCFCR, sci_port->saved_fcr);
+ sci_out(port, SCSCR, sci_port->cfg->scscr);
+ }
+ return 0;
+}
+
#define SCI_CONSOLE (&serial_console)
#else
@@ -2088,6 +2134,8 @@ static inline int __devinit sci_probe_earlyprintk(struct platform_device *pdev)
}
#define SCI_CONSOLE NULL
+#define sci_runtime_suspend NULL
+#define sci_runtime_resume NULL
#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
@@ -2203,6 +2251,8 @@ static int sci_resume(struct device *dev)
}
static const struct dev_pm_ops sci_dev_pm_ops = {
+ .runtime_suspend = sci_runtime_suspend,
+ .runtime_resume = sci_runtime_resume,
.suspend = sci_suspend,
.resume = sci_resume,
};
diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c
index 97b67241a783..cea8918b8233 100644
--- a/drivers/tty/serial/ucc_uart.c
+++ b/drivers/tty/serial/ucc_uart.c
@@ -237,7 +237,7 @@ static inline void *qe2cpu_addr(dma_addr_t addr, struct uart_qe_port *qe_port)
return qe_port->bd_virt + (addr - qe_port->bd_dma_addr);
/* something nasty happened */
- printk(KERN_ERR "%s: addr=%x\n", __func__, addr);
+ printk(KERN_ERR "%s: addr=%llx\n", __func__, (u64)addr);
BUG();
return NULL;
}
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 767ecbb4761a..05085beb83db 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -1314,8 +1314,7 @@ static int tty_driver_install_tty(struct tty_driver *driver,
*
* Locking: tty_mutex for now
*/
-static void tty_driver_remove_tty(struct tty_driver *driver,
- struct tty_struct *tty)
+void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct *tty)
{
if (driver->ops->remove)
driver->ops->remove(driver, tty);
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index d2efe823c20d..a783d533a1a6 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -69,7 +69,7 @@ static ssize_t map_name_show(struct uio_mem *mem, char *buf)
static ssize_t map_addr_show(struct uio_mem *mem, char *buf)
{
- return sprintf(buf, "0x%lx\n", mem->addr);
+ return sprintf(buf, "0x%llx\n", (unsigned long long)mem->addr);
}
static ssize_t map_size_show(struct uio_mem *mem, char *buf)
@@ -79,7 +79,7 @@ static ssize_t map_size_show(struct uio_mem *mem, char *buf)
static ssize_t map_offset_show(struct uio_mem *mem, char *buf)
{
- return sprintf(buf, "0x%lx\n", mem->addr & ~PAGE_MASK);
+ return sprintf(buf, "0x%llx\n", (unsigned long long)mem->addr & ~PAGE_MASK);
}
struct map_sysfs_entry {
@@ -634,8 +634,7 @@ static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL)
page = virt_to_page(idev->info->mem[mi].addr + offset);
else
- page = vmalloc_to_page((void *)idev->info->mem[mi].addr
- + offset);
+ page = vmalloc_to_page((void *)(unsigned long)idev->info->mem[mi].addr + offset);
get_page(page);
vmf->page = page;
return 0;
@@ -750,14 +749,13 @@ static int uio_major_init(void)
uio_major = MAJOR(uio_dev);
uio_cdev = cdev;
- result = 0;
-out:
- return result;
+ return 0;
out_put:
kobject_put(&cdev->kobj);
out_unregister:
unregister_chrdev_region(uio_dev, UIO_MAX_DEVICES);
- goto out;
+out:
+ return result;
}
static void uio_major_cleanup(void)
diff --git a/drivers/uio/uio_pci_generic.c b/drivers/uio/uio_pci_generic.c
index fc22e1e6f215..02bd47bdee1c 100644
--- a/drivers/uio/uio_pci_generic.c
+++ b/drivers/uio/uio_pci_generic.c
@@ -24,7 +24,6 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/uio_driver.h>
-#include <linux/spinlock.h>
#define DRIVER_VERSION "0.01.0"
#define DRIVER_AUTHOR "Michael S. Tsirkin <mst@redhat.com>"
@@ -33,7 +32,6 @@
struct uio_pci_generic_dev {
struct uio_info info;
struct pci_dev *pdev;
- spinlock_t lock; /* guards command register accesses */
};
static inline struct uio_pci_generic_dev *
@@ -57,7 +55,6 @@ static irqreturn_t irqhandler(int irq, struct uio_info *info)
BUILD_BUG_ON(PCI_COMMAND % 4);
BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS);
- spin_lock_irq(&gdev->lock);
pci_block_user_cfg_access(pdev);
/* Read both command and status registers in a single 32-bit operation.
@@ -83,7 +80,6 @@ static irqreturn_t irqhandler(int irq, struct uio_info *info)
done:
pci_unblock_user_cfg_access(pdev);
- spin_unlock_irq(&gdev->lock);
return ret;
}
@@ -158,7 +154,6 @@ static int __devinit probe(struct pci_dev *pdev,
gdev->info.irq_flags = IRQF_SHARED;
gdev->info.handler = irqhandler;
gdev->pdev = pdev;
- spin_lock_init(&gdev->lock);
if (uio_register_device(&pdev->dev, &gdev->info))
goto err_register;
diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c
index bae96d246760..0b2ed71e3bfa 100644
--- a/drivers/uio/uio_pdrv_genirq.c
+++ b/drivers/uio/uio_pdrv_genirq.c
@@ -253,7 +253,7 @@ static const struct dev_pm_ops uio_pdrv_genirq_dev_pm_ops = {
};
#ifdef CONFIG_OF
-static const struct of_device_id __devinitconst uio_of_genirq_match[] = {
+static const struct of_device_id uio_of_genirq_match[] = {
{ /* empty for now */ },
};
MODULE_DEVICE_TABLE(of, uio_of_genirq_match);
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 48f1781352f1..4ac2750491de 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -12,6 +12,11 @@ menuconfig USB_SUPPORT
if USB_SUPPORT
+config USB_COMMON
+ tristate
+ default y
+ depends on USB || USB_GADGET
+
# Host-side USB depends on having a host controller
# NOTE: dummy_hcd is always an option, but it's ignored here ...
# NOTE: SL-811 option should be board-specific ...
@@ -19,6 +24,7 @@ config USB_ARCH_HAS_HCD
boolean
default y if USB_ARCH_HAS_OHCI
default y if USB_ARCH_HAS_EHCI
+ default y if USB_ARCH_HAS_XHCI
default y if PCMCIA && !M32R # sl811_cs
default y if ARM # SL-811
default y if BLACKFIN # SL-811
@@ -54,7 +60,7 @@ config USB_ARCH_HAS_OHCI
# some non-PCI hcds implement EHCI
config USB_ARCH_HAS_EHCI
boolean
- default y if PPC_83xx
+ default y if FSL_SOC
default y if PPC_MPC512x
default y if SOC_AU1200
default y if ARCH_IXP4XX
@@ -69,6 +75,12 @@ config USB_ARCH_HAS_EHCI
default y if ARCH_MSM
default y if MICROBLAZE
default y if SPARC_LEON
+ default y if ARCH_MMP
+ default PCI
+
+# some non-PCI HCDs implement xHCI
+config USB_ARCH_HAS_XHCI
+ boolean
default PCI
# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
@@ -110,6 +122,8 @@ config USB
source "drivers/usb/core/Kconfig"
+source "drivers/usb/dwc3/Kconfig"
+
source "drivers/usb/mon/Kconfig"
source "drivers/usb/wusbcore/Kconfig"
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 30ddf8dc4f72..75eca7645227 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -6,6 +6,8 @@
obj-$(CONFIG_USB) += core/
+obj-$(CONFIG_USB_DWC3) += dwc3/
+
obj-$(CONFIG_USB_MON) += mon/
obj-$(CONFIG_PCI) += host/
@@ -51,3 +53,5 @@ obj-$(CONFIG_USB_MUSB_HDRC) += musb/
obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/
obj-$(CONFIG_USB_OTG_UTILS) += otg/
obj-$(CONFIG_USB_GADGET) += gadget/
+
+obj-$(CONFIG_USB_COMMON) += usb-common.o
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index dac7676ce21b..6960715c5063 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1058,11 +1058,11 @@ made_compressed_probe:
goto alloc_fail;
}
- ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
- readsize = le16_to_cpu(epread->wMaxPacketSize) *
+ ctrlsize = usb_endpoint_maxp(epctrl);
+ readsize = usb_endpoint_maxp(epread) *
(quirks == SINGLE_RX_URB ? 1 : 2);
acm->combined_interfaces = combined_interfaces;
- acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20;
+ acm->writesize = usb_endpoint_maxp(epwrite) * 20;
acm->control = control_interface;
acm->data = data_interface;
acm->minor = minor;
@@ -1305,7 +1305,7 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
struct acm *acm = usb_get_intfdata(intf);
int cnt;
- if (message.event & PM_EVENT_AUTO) {
+ if (PMSG_IS_AUTO(message)) {
int b;
spin_lock_irq(&acm->write_lock);
@@ -1534,6 +1534,9 @@ static const struct usb_device_id acm_ids[] = {
{ NOKIA_PCSUITE_ACM_INFO(0x03cd), }, /* Nokia C7 */
{ SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) */
+ /* Support for Owen devices */
+ { USB_DEVICE(0x03eb, 0x0030), }, /* Owen SI30 */
+
/* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */
/* Support Lego NXT using pbLua firmware */
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 2b9ff518b509..efe684908c1f 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -682,7 +682,7 @@ next_desc:
if (!ep || !usb_endpoint_is_int_in(ep))
goto err;
- desc->wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize);
+ desc->wMaxPacketSize = usb_endpoint_maxp(ep);
desc->bMaxPacketSize0 = udev->descriptor.bMaxPacketSize0;
desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
@@ -798,11 +798,11 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor);
/* if this is an autosuspend the caller does the locking */
- if (!(message.event & PM_EVENT_AUTO))
+ if (!PMSG_IS_AUTO(message))
mutex_lock(&desc->lock);
spin_lock_irq(&desc->iuspin);
- if ((message.event & PM_EVENT_AUTO) &&
+ if (PMSG_IS_AUTO(message) &&
(test_bit(WDM_IN_USE, &desc->flags)
|| test_bit(WDM_RESPONDING, &desc->flags))) {
spin_unlock_irq(&desc->iuspin);
@@ -815,7 +815,7 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
kill_urbs(desc);
cancel_work_sync(&desc->rxwork);
}
- if (!(message.event & PM_EVENT_AUTO))
+ if (!PMSG_IS_AUTO(message))
mutex_unlock(&desc->lock);
return rv;
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 3f94ac34dce3..12cf5e7395a8 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -186,8 +186,7 @@ static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data)
for (n = 0; n < current_setting->desc.bNumEndpoints; n++)
if (current_setting->endpoint[n].desc.bEndpointAddress ==
data->bulk_in)
- max_size = le16_to_cpu(current_setting->endpoint[n].
- desc.wMaxPacketSize);
+ max_size = usb_endpoint_maxp(&current_setting->endpoint[n].desc);
if (max_size == 0) {
dev_err(dev, "Couldn't get wMaxPacketSize\n");
@@ -636,7 +635,7 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data *data)
for (n = 0; n < current_setting->desc.bNumEndpoints; n++) {
desc = &current_setting->endpoint[n].desc;
if (desc->bEndpointAddress == data->bulk_in)
- max_size = le16_to_cpu(desc->wMaxPacketSize);
+ max_size = usb_endpoint_maxp(desc);
}
if (max_size == 0) {
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 26678cadfb21..f4bdd0ce8d56 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -124,9 +124,9 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
if (usb_endpoint_xfer_isoc(&ep->desc))
max_tx = (desc->bMaxBurst + 1) * (desc->bmAttributes + 1) *
- le16_to_cpu(ep->desc.wMaxPacketSize);
+ usb_endpoint_maxp(&ep->desc);
else if (usb_endpoint_xfer_int(&ep->desc))
- max_tx = le16_to_cpu(ep->desc.wMaxPacketSize) *
+ max_tx = usb_endpoint_maxp(&ep->desc) *
(desc->bMaxBurst + 1);
else
max_tx = 999999;
@@ -241,7 +241,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
cfgno, inum, asnum, d->bEndpointAddress);
endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT;
endpoint->desc.bInterval = 1;
- if (le16_to_cpu(endpoint->desc.wMaxPacketSize) > 8)
+ if (usb_endpoint_maxp(&endpoint->desc) > 8)
endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
}
@@ -254,7 +254,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
&& usb_endpoint_xfer_bulk(d)) {
unsigned maxp;
- maxp = le16_to_cpu(endpoint->desc.wMaxPacketSize) & 0x07ff;
+ maxp = usb_endpoint_maxp(&endpoint->desc) & 0x07ff;
if (maxp != 512)
dev_warn(ddev, "config %d interface %d altsetting %d "
"bulk endpoint 0x%X has invalid maxpacket %d\n",
@@ -755,3 +755,106 @@ err2:
dev_err(ddev, "out of memory\n");
return result;
}
+
+void usb_release_bos_descriptor(struct usb_device *dev)
+{
+ if (dev->bos) {
+ kfree(dev->bos->desc);
+ kfree(dev->bos);
+ dev->bos = NULL;
+ }
+}
+
+/* Get BOS descriptor set */
+int usb_get_bos_descriptor(struct usb_device *dev)
+{
+ struct device *ddev = &dev->dev;
+ struct usb_bos_descriptor *bos;
+ struct usb_dev_cap_header *cap;
+ unsigned char *buffer;
+ int length, total_len, num, i;
+ int ret;
+
+ bos = kzalloc(sizeof(struct usb_bos_descriptor), GFP_KERNEL);
+ if (!bos)
+ return -ENOMEM;
+
+ /* Get BOS descriptor */
+ ret = usb_get_descriptor(dev, USB_DT_BOS, 0, bos, USB_DT_BOS_SIZE);
+ if (ret < USB_DT_BOS_SIZE) {
+ dev_err(ddev, "unable to get BOS descriptor\n");
+ if (ret >= 0)
+ ret = -ENOMSG;
+ kfree(bos);
+ return ret;
+ }
+
+ length = bos->bLength;
+ total_len = le16_to_cpu(bos->wTotalLength);
+ num = bos->bNumDeviceCaps;
+ kfree(bos);
+ if (total_len < length)
+ return -EINVAL;
+
+ dev->bos = kzalloc(sizeof(struct usb_host_bos), GFP_KERNEL);
+ if (!dev->bos)
+ return -ENOMEM;
+
+ /* Now let's get the whole BOS descriptor set */
+ buffer = kzalloc(total_len, GFP_KERNEL);
+ if (!buffer) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ dev->bos->desc = (struct usb_bos_descriptor *)buffer;
+
+ ret = usb_get_descriptor(dev, USB_DT_BOS, 0, buffer, total_len);
+ if (ret < total_len) {
+ dev_err(ddev, "unable to get BOS descriptor set\n");
+ if (ret >= 0)
+ ret = -ENOMSG;
+ goto err;
+ }
+ total_len -= length;
+
+ for (i = 0; i < num; i++) {
+ buffer += length;
+ cap = (struct usb_dev_cap_header *)buffer;
+ length = cap->bLength;
+
+ if (total_len < length)
+ break;
+ total_len -= length;
+
+ if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) {
+ dev_warn(ddev, "descriptor type invalid, skip\n");
+ continue;
+ }
+
+ switch (cap->bDevCapabilityType) {
+ case USB_CAP_TYPE_WIRELESS_USB:
+ /* Wireless USB cap descriptor is handled by wusb */
+ break;
+ case USB_CAP_TYPE_EXT:
+ dev->bos->ext_cap =
+ (struct usb_ext_cap_descriptor *)buffer;
+ break;
+ case USB_SS_CAP_TYPE:
+ dev->bos->ss_cap =
+ (struct usb_ss_cap_descriptor *)buffer;
+ break;
+ case CONTAINER_ID_TYPE:
+ dev->bos->ss_id =
+ (struct usb_ss_container_id_descriptor *)buffer;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+
+err:
+ usb_release_bos_descriptor(dev);
+ return ret;
+}
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index 0149c0976e9c..d95696584762 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -190,7 +190,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
dir = usb_endpoint_dir_in(desc) ? 'I' : 'O';
if (speed == USB_SPEED_HIGH) {
- switch (le16_to_cpu(desc->wMaxPacketSize) & (0x03 << 11)) {
+ switch (usb_endpoint_maxp(desc) & (0x03 << 11)) {
case 1 << 11:
bandwidth = 2; break;
case 2 << 11:
@@ -240,7 +240,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
start += sprintf(start, format_endpt, desc->bEndpointAddress, dir,
desc->bmAttributes, type,
- (le16_to_cpu(desc->wMaxPacketSize) & 0x07ff) *
+ (usb_endpoint_maxp(desc) & 0x07ff) *
bandwidth,
interval, unit);
return start;
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 37518dfdeb98..e3beaf229ee3 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -46,6 +46,7 @@
#include <linux/cdev.h>
#include <linux/notifier.h>
#include <linux/security.h>
+#include <linux/user_namespace.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
#include <linux/moduleparam.h>
@@ -68,7 +69,7 @@ struct dev_state {
wait_queue_head_t wait; /* wake up if a request completed */
unsigned int discsignr;
struct pid *disc_pid;
- uid_t disc_uid, disc_euid;
+ const struct cred *cred;
void __user *disccontext;
unsigned long ifclaimed;
u32 secid;
@@ -79,7 +80,7 @@ struct async {
struct list_head asynclist;
struct dev_state *ps;
struct pid *pid;
- uid_t uid, euid;
+ const struct cred *cred;
unsigned int signr;
unsigned int ifnum;
void __user *userbuffer;
@@ -248,6 +249,7 @@ static struct async *alloc_async(unsigned int numisoframes)
static void free_async(struct async *as)
{
put_pid(as->pid);
+ put_cred(as->cred);
kfree(as->urb->transfer_buffer);
kfree(as->urb->setup_packet);
usb_free_urb(as->urb);
@@ -393,9 +395,8 @@ static void async_completed(struct urb *urb)
struct dev_state *ps = as->ps;
struct siginfo sinfo;
struct pid *pid = NULL;
- uid_t uid = 0;
- uid_t euid = 0;
u32 secid = 0;
+ const struct cred *cred = NULL;
int signr;
spin_lock(&ps->lock);
@@ -407,9 +408,8 @@ static void async_completed(struct urb *urb)
sinfo.si_errno = as->status;
sinfo.si_code = SI_ASYNCIO;
sinfo.si_addr = as->userurb;
- pid = as->pid;
- uid = as->uid;
- euid = as->euid;
+ pid = get_pid(as->pid);
+ cred = get_cred(as->cred);
secid = as->secid;
}
snoop(&urb->dev->dev, "urb complete\n");
@@ -422,9 +422,11 @@ static void async_completed(struct urb *urb)
cancel_bulk_urbs(ps, as->bulk_addr);
spin_unlock(&ps->lock);
- if (signr)
- kill_pid_info_as_uid(sinfo.si_signo, &sinfo, pid, uid,
- euid, secid);
+ if (signr) {
+ kill_pid_info_as_cred(sinfo.si_signo, &sinfo, pid, cred, secid);
+ put_pid(pid);
+ put_cred(cred);
+ }
wake_up(&ps->wait);
}
@@ -607,9 +609,10 @@ static int findintfep(struct usb_device *dev, unsigned int ep)
}
static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,
- unsigned int index)
+ unsigned int request, unsigned int index)
{
int ret = 0;
+ struct usb_host_interface *alt_setting;
if (ps->dev->state != USB_STATE_UNAUTHENTICATED
&& ps->dev->state != USB_STATE_ADDRESS
@@ -618,6 +621,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,
if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype))
return 0;
+ /*
+ * check for the special corner case 'get_device_id' in the printer
+ * class specification, where wIndex is (interface << 8 | altsetting)
+ * instead of just interface
+ */
+ if (requesttype == 0xa1 && request == 0) {
+ alt_setting = usb_find_alt_setting(ps->dev->actconfig,
+ index >> 8, index & 0xff);
+ if (alt_setting
+ && alt_setting->desc.bInterfaceClass == USB_CLASS_PRINTER)
+ index >>= 8;
+ }
+
index &= 0xff;
switch (requesttype & USB_RECIP_MASK) {
case USB_RECIP_ENDPOINT:
@@ -656,7 +672,6 @@ static int usbdev_open(struct inode *inode, struct file *file)
{
struct usb_device *dev = NULL;
struct dev_state *ps;
- const struct cred *cred = current_cred();
int ret;
ret = -ENOMEM;
@@ -706,8 +721,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
init_waitqueue_head(&ps->wait);
ps->discsignr = 0;
ps->disc_pid = get_pid(task_pid(current));
- ps->disc_uid = cred->uid;
- ps->disc_euid = cred->euid;
+ ps->cred = get_current_cred();
ps->disccontext = NULL;
ps->ifclaimed = 0;
security_task_getsecid(current, &ps->secid);
@@ -749,6 +763,7 @@ static int usbdev_release(struct inode *inode, struct file *file)
usb_unlock_device(dev);
usb_put_dev(dev);
put_pid(ps->disc_pid);
+ put_cred(ps->cred);
as = async_getcompleted(ps);
while (as) {
@@ -770,7 +785,8 @@ static int proc_control(struct dev_state *ps, void __user *arg)
if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
return -EFAULT;
- ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex);
+ ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.bRequest,
+ ctrl.wIndex);
if (ret)
return ret;
wLength = ctrl.wLength; /* To suppress 64k PAGE_SIZE warning */
@@ -1048,7 +1064,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
struct usb_host_endpoint *ep;
struct async *as;
struct usb_ctrlrequest *dr = NULL;
- const struct cred *cred = current_cred();
unsigned int u, totlen, isofrmlen;
int ret, ifnum = -1;
int is_in;
@@ -1100,7 +1115,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
kfree(dr);
return -EINVAL;
}
- ret = check_ctrlrecip(ps, dr->bRequestType,
+ ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest,
le16_to_cpup(&dr->wIndex));
if (ret) {
kfree(dr);
@@ -1262,8 +1277,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
as->signr = uurb->signr;
as->ifnum = ifnum;
as->pid = get_pid(task_pid(current));
- as->uid = cred->uid;
- as->euid = cred->euid;
+ as->cred = get_current_cred();
security_task_getsecid(current, &as->secid);
if (!is_in && uurb->buffer_length > 0) {
if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
@@ -1981,9 +1995,8 @@ static void usbdev_remove(struct usb_device *udev)
sinfo.si_errno = EPIPE;
sinfo.si_code = SI_ASYNCIO;
sinfo.si_addr = ps->disccontext;
- kill_pid_info_as_uid(ps->discsignr, &sinfo,
- ps->disc_pid, ps->disc_uid,
- ps->disc_euid, ps->secid);
+ kill_pid_info_as_cred(ps->discsignr, &sinfo,
+ ps->disc_pid, ps->cred, ps->secid);
}
}
}
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 34e3da5aa72a..3b029a0a4787 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1046,8 +1046,7 @@ static int usb_resume_device(struct usb_device *udev, pm_message_t msg)
/* Non-root devices on a full/low-speed bus must wait for their
* companion high-speed root hub, in case a handoff is needed.
*/
- if (!(msg.event & PM_EVENT_AUTO) && udev->parent &&
- udev->bus->hs_companion)
+ if (!PMSG_IS_AUTO(msg) && udev->parent && udev->bus->hs_companion)
device_pm_wait_for_dev(&udev->dev,
&udev->bus->hs_companion->root_hub->dev);
@@ -1075,7 +1074,7 @@ static int usb_suspend_interface(struct usb_device *udev,
if (driver->suspend) {
status = driver->suspend(intf, msg);
- if (status && !(msg.event & PM_EVENT_AUTO))
+ if (status && !PMSG_IS_AUTO(msg))
dev_err(&intf->dev, "%s error %d\n",
"suspend", status);
} else {
@@ -1189,7 +1188,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
status = usb_suspend_interface(udev, intf, msg);
/* Ignore errors during system sleep transitions */
- if (!(msg.event & PM_EVENT_AUTO))
+ if (!PMSG_IS_AUTO(msg))
status = 0;
if (status != 0)
break;
@@ -1199,7 +1198,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
status = usb_suspend_device(udev, msg);
/* Again, ignore errors during system sleep transitions */
- if (!(msg.event & PM_EVENT_AUTO))
+ if (!PMSG_IS_AUTO(msg))
status = 0;
}
@@ -1583,7 +1582,7 @@ int usb_autopm_get_interface_async(struct usb_interface *intf)
dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
__func__, atomic_read(&intf->dev.power.usage_count),
status);
- if (status > 0)
+ if (status > 0 || status == -EINPROGRESS)
status = 0;
return status;
}
@@ -1700,6 +1699,20 @@ int usb_runtime_idle(struct device *dev)
return 0;
}
+int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ int ret = -EPERM;
+
+ if (hcd->driver->set_usb2_hw_lpm) {
+ ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, enable);
+ if (!ret)
+ udev->usb2_hw_lpm_enabled = enable;
+ }
+
+ return ret;
+}
+
#endif /* CONFIG_USB_SUSPEND */
struct bus_type usb_bus_type = {
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index df502a98d0df..db7fe50c23d4 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -56,7 +56,7 @@ static ssize_t show_ep_wMaxPacketSize(struct device *dev,
{
struct ep_device *ep = to_ep_device(dev);
return sprintf(buf, "%04x\n",
- le16_to_cpu(ep->desc->wMaxPacketSize) & 0x07ff);
+ usb_endpoint_maxp(ep->desc) & 0x07ff);
}
static DEVICE_ATTR(wMaxPacketSize, S_IRUGO, show_ep_wMaxPacketSize, NULL);
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index ce22f4a84ed0..a004db35f6d0 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -242,7 +242,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
pci_set_master(dev);
- retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED);
+ retval = usb_add_hcd(hcd, dev->irq, IRQF_SHARED);
if (retval != 0)
goto unmap_registers;
set_hs_companion(dev, hcd);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 8669ba3fe794..13222d352a61 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -442,7 +442,11 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
struct usb_ctrlrequest *cmd;
u16 typeReq, wValue, wIndex, wLength;
u8 *ubuf = urb->transfer_buffer;
- u8 tbuf [sizeof (struct usb_hub_descriptor)]
+ /*
+ * tbuf should be as big as the BOS descriptor and
+ * the USB hub descriptor.
+ */
+ u8 tbuf[USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE]
__attribute__((aligned(4)));
const u8 *bufp = tbuf;
unsigned len = 0;
@@ -562,6 +566,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
else /* unsupported IDs --> "protocol stall" */
goto error;
break;
+ case USB_DT_BOS << 8:
+ goto nongeneric;
default:
goto error;
}
@@ -596,6 +602,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
/* CLASS REQUESTS (and errors) */
default:
+nongeneric:
/* non-generic request */
switch (typeReq) {
case GetHubStatus:
@@ -605,6 +612,9 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
case GetHubDescriptor:
len = sizeof (struct usb_hub_descriptor);
break;
+ case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+ /* len is returned by hub_control */
+ break;
}
status = hcd->driver->hub_control (hcd,
typeReq, wValue, wIndex,
@@ -615,7 +625,7 @@ error:
status = -EPIPE;
}
- if (status) {
+ if (status < 0) {
len = 0;
if (status != -EPIPE) {
dev_dbg (hcd->self.controller,
@@ -624,6 +634,10 @@ error:
typeReq, wValue, wIndex,
wLength, status);
}
+ } else if (status > 0) {
+ /* hub_control may return the length of data copied. */
+ len = status;
+ status = 0;
}
if (len) {
if (urb->transfer_buffer_length < len)
@@ -1775,6 +1789,8 @@ int usb_hcd_alloc_bandwidth(struct usb_device *udev,
struct usb_interface *iface = usb_ifnum_to_if(udev,
cur_alt->desc.bInterfaceNumber);
+ if (!iface)
+ return -EINVAL;
if (iface->resetting_device) {
/*
* The USB core just reset the device, so the xHCI host
@@ -1959,8 +1975,9 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)
int status;
int old_state = hcd->state;
- dev_dbg(&rhdev->dev, "bus %s%s\n",
- (msg.event & PM_EVENT_AUTO ? "auto-" : ""), "suspend");
+ dev_dbg(&rhdev->dev, "bus %ssuspend, wakeup %d\n",
+ (PMSG_IS_AUTO(msg) ? "auto-" : ""),
+ rhdev->do_remote_wakeup);
if (HCD_DEAD(hcd)) {
dev_dbg(&rhdev->dev, "skipped %s of dead bus\n", "suspend");
return 0;
@@ -1995,8 +2012,8 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
int status;
int old_state = hcd->state;
- dev_dbg(&rhdev->dev, "usb %s%s\n",
- (msg.event & PM_EVENT_AUTO ? "auto-" : ""), "resume");
+ dev_dbg(&rhdev->dev, "usb %sresume\n",
+ (PMSG_IS_AUTO(msg) ? "auto-" : ""));
if (HCD_DEAD(hcd)) {
dev_dbg(&rhdev->dev, "skipped %s of dead bus\n", "resume");
return 0;
@@ -2427,7 +2444,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
* but drivers can override it in reset() if needed, along with
* recording the overall controller's system wakeup capability.
*/
- device_init_wakeup(&rhdev->dev, 1);
+ device_set_wakeup_capable(&rhdev->dev, 1);
/* HCD_FLAG_RH_RUNNING doesn't matter until the root hub is
* registered. But since the controller can die at any time,
@@ -2476,6 +2493,13 @@ int usb_add_hcd(struct usb_hcd *hcd,
}
if (hcd->uses_new_polling && HCD_POLL_RH(hcd))
usb_hcd_poll_rh_status(hcd);
+
+ /*
+ * Host controllers don't generate their own wakeup requests;
+ * they only forward requests from the root hub. Therefore
+ * controllers should always be enabled for remote wakeup.
+ */
+ device_wakeup_enable(hcd->self.controller);
return retval;
error_create_attr_group:
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index a428aa080a36..96f05b29c9ad 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1636,11 +1636,6 @@ void usb_disconnect(struct usb_device **pdev)
int i;
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
- if (!udev) {
- pr_debug ("%s nodev\n", __func__);
- return;
- }
-
/* mark the device as inactive, so any further urb submissions for
* this device (and any of its children) will fail immediately.
* this quiesces everything except pending urbs.
@@ -2030,11 +2025,23 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
#define HUB_ROOT_RESET_TIME 50 /* times are in msec */
#define HUB_SHORT_RESET_TIME 10
+#define HUB_BH_RESET_TIME 50
#define HUB_LONG_RESET_TIME 200
#define HUB_RESET_TIMEOUT 500
+static int hub_port_reset(struct usb_hub *hub, int port1,
+ struct usb_device *udev, unsigned int delay, bool warm);
+
+/* Is a USB 3.0 port in the Inactive state? */
+static bool hub_port_inactive(struct usb_hub *hub, u16 portstatus)
+{
+ return hub_is_superspeed(hub->hdev) &&
+ (portstatus & USB_PORT_STAT_LINK_STATE) ==
+ USB_SS_PORT_LS_SS_INACTIVE;
+}
+
static int hub_port_wait_reset(struct usb_hub *hub, int port1,
- struct usb_device *udev, unsigned int delay)
+ struct usb_device *udev, unsigned int delay, bool warm)
{
int delay_time, ret;
u16 portstatus;
@@ -2051,28 +2058,71 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
if (ret < 0)
return ret;
- /* Device went away? */
- if (!(portstatus & USB_PORT_STAT_CONNECTION))
- return -ENOTCONN;
-
- /* bomb out completely if the connection bounced */
- if ((portchange & USB_PORT_STAT_C_CONNECTION))
- return -ENOTCONN;
-
- /* if we`ve finished resetting, then break out of the loop */
- if (!(portstatus & USB_PORT_STAT_RESET) &&
- (portstatus & USB_PORT_STAT_ENABLE)) {
- if (hub_is_wusb(hub))
- udev->speed = USB_SPEED_WIRELESS;
- else if (hub_is_superspeed(hub->hdev))
- udev->speed = USB_SPEED_SUPER;
- else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
- udev->speed = USB_SPEED_HIGH;
- else if (portstatus & USB_PORT_STAT_LOW_SPEED)
- udev->speed = USB_SPEED_LOW;
- else
- udev->speed = USB_SPEED_FULL;
- return 0;
+ /*
+ * Some buggy devices require a warm reset to be issued even
+ * when the port appears not to be connected.
+ */
+ if (!warm) {
+ /*
+ * Some buggy devices can cause an NEC host controller
+ * to transition to the "Error" state after a hot port
+ * reset. This will show up as the port state in
+ * "Inactive", and the port may also report a
+ * disconnect. Forcing a warm port reset seems to make
+ * the device work.
+ *
+ * See https://bugzilla.kernel.org/show_bug.cgi?id=41752
+ */
+ if (hub_port_inactive(hub, portstatus)) {
+ int ret;
+
+ if ((portchange & USB_PORT_STAT_C_CONNECTION))
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_CONNECTION);
+ if (portchange & USB_PORT_STAT_C_LINK_STATE)
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_PORT_LINK_STATE);
+ if (portchange & USB_PORT_STAT_C_RESET)
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_RESET);
+ dev_dbg(hub->intfdev, "hot reset failed, warm reset port %d\n",
+ port1);
+ ret = hub_port_reset(hub, port1,
+ udev, HUB_BH_RESET_TIME,
+ true);
+ if ((portchange & USB_PORT_STAT_C_CONNECTION))
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_CONNECTION);
+ return ret;
+ }
+ /* Device went away? */
+ if (!(portstatus & USB_PORT_STAT_CONNECTION))
+ return -ENOTCONN;
+
+ /* bomb out completely if the connection bounced */
+ if ((portchange & USB_PORT_STAT_C_CONNECTION))
+ return -ENOTCONN;
+
+ /* if we`ve finished resetting, then break out of
+ * the loop
+ */
+ if (!(portstatus & USB_PORT_STAT_RESET) &&
+ (portstatus & USB_PORT_STAT_ENABLE)) {
+ if (hub_is_wusb(hub))
+ udev->speed = USB_SPEED_WIRELESS;
+ else if (hub_is_superspeed(hub->hdev))
+ udev->speed = USB_SPEED_SUPER;
+ else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
+ udev->speed = USB_SPEED_HIGH;
+ else if (portstatus & USB_PORT_STAT_LOW_SPEED)
+ udev->speed = USB_SPEED_LOW;
+ else
+ udev->speed = USB_SPEED_FULL;
+ return 0;
+ }
+ } else {
+ if (portchange & USB_PORT_STAT_C_BH_RESET)
+ return 0;
}
/* switch to the long delay after two short delay failures */
@@ -2080,35 +2130,84 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
delay = HUB_LONG_RESET_TIME;
dev_dbg (hub->intfdev,
- "port %d not reset yet, waiting %dms\n",
- port1, delay);
+ "port %d not %sreset yet, waiting %dms\n",
+ port1, warm ? "warm " : "", delay);
}
return -EBUSY;
}
+static void hub_port_finish_reset(struct usb_hub *hub, int port1,
+ struct usb_device *udev, int *status, bool warm)
+{
+ switch (*status) {
+ case 0:
+ if (!warm) {
+ struct usb_hcd *hcd;
+ /* TRSTRCY = 10 ms; plus some extra */
+ msleep(10 + 40);
+ update_devnum(udev, 0);
+ hcd = bus_to_hcd(udev->bus);
+ if (hcd->driver->reset_device) {
+ *status = hcd->driver->reset_device(hcd, udev);
+ if (*status < 0) {
+ dev_err(&udev->dev, "Cannot reset "
+ "HCD device state\n");
+ break;
+ }
+ }
+ }
+ /* FALL THROUGH */
+ case -ENOTCONN:
+ case -ENODEV:
+ clear_port_feature(hub->hdev,
+ port1, USB_PORT_FEAT_C_RESET);
+ /* FIXME need disconnect() for NOTATTACHED device */
+ if (warm) {
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_BH_PORT_RESET);
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_PORT_LINK_STATE);
+ } else {
+ usb_set_device_state(udev, *status
+ ? USB_STATE_NOTATTACHED
+ : USB_STATE_DEFAULT);
+ }
+ break;
+ }
+}
+
+/* Handle port reset and port warm(BH) reset (for USB3 protocol ports) */
static int hub_port_reset(struct usb_hub *hub, int port1,
- struct usb_device *udev, unsigned int delay)
+ struct usb_device *udev, unsigned int delay, bool warm)
{
int i, status;
- struct usb_hcd *hcd;
- hcd = bus_to_hcd(udev->bus);
- /* Block EHCI CF initialization during the port reset.
- * Some companion controllers don't like it when they mix.
- */
- down_read(&ehci_cf_port_reset_rwsem);
+ if (!warm) {
+ /* Block EHCI CF initialization during the port reset.
+ * Some companion controllers don't like it when they mix.
+ */
+ down_read(&ehci_cf_port_reset_rwsem);
+ } else {
+ if (!hub_is_superspeed(hub->hdev)) {
+ dev_err(hub->intfdev, "only USB3 hub support "
+ "warm reset\n");
+ return -EINVAL;
+ }
+ }
/* Reset the port */
for (i = 0; i < PORT_RESET_TRIES; i++) {
- status = set_port_feature(hub->hdev,
- port1, USB_PORT_FEAT_RESET);
- if (status)
+ status = set_port_feature(hub->hdev, port1, (warm ?
+ USB_PORT_FEAT_BH_PORT_RESET :
+ USB_PORT_FEAT_RESET));
+ if (status) {
dev_err(hub->intfdev,
- "cannot reset port %d (err = %d)\n",
- port1, status);
- else {
- status = hub_port_wait_reset(hub, port1, udev, delay);
+ "cannot %sreset port %d (err = %d)\n",
+ warm ? "warm " : "", port1, status);
+ } else {
+ status = hub_port_wait_reset(hub, port1, udev, delay,
+ warm);
if (status && status != -ENOTCONN)
dev_dbg(hub->intfdev,
"port_wait_reset: err = %d\n",
@@ -2116,34 +2215,14 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
}
/* return on disconnect or reset */
- switch (status) {
- case 0:
- /* TRSTRCY = 10 ms; plus some extra */
- msleep(10 + 40);
- update_devnum(udev, 0);
- if (hcd->driver->reset_device) {
- status = hcd->driver->reset_device(hcd, udev);
- if (status < 0) {
- dev_err(&udev->dev, "Cannot reset "
- "HCD device state\n");
- break;
- }
- }
- /* FALL THROUGH */
- case -ENOTCONN:
- case -ENODEV:
- clear_port_feature(hub->hdev,
- port1, USB_PORT_FEAT_C_RESET);
- /* FIXME need disconnect() for NOTATTACHED device */
- usb_set_device_state(udev, status
- ? USB_STATE_NOTATTACHED
- : USB_STATE_DEFAULT);
+ if (status == 0 || status == -ENOTCONN || status == -ENODEV) {
+ hub_port_finish_reset(hub, port1, udev, &status, warm);
goto done;
}
dev_dbg (hub->intfdev,
- "port %d not enabled, trying reset again...\n",
- port1);
+ "port %d not enabled, trying %sreset again...\n",
+ port1, warm ? "warm " : "");
delay = HUB_LONG_RESET_TIME;
}
@@ -2151,45 +2230,11 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
"Cannot enable port %i. Maybe the USB cable is bad?\n",
port1);
- done:
- up_read(&ehci_cf_port_reset_rwsem);
- return status;
-}
-
-/* Warm reset a USB3 protocol port */
-static int hub_port_warm_reset(struct usb_hub *hub, int port)
-{
- int ret;
- u16 portstatus, portchange;
-
- if (!hub_is_superspeed(hub->hdev)) {
- dev_err(hub->intfdev, "only USB3 hub support warm reset\n");
- return -EINVAL;
- }
-
- /* Warm reset the port */
- ret = set_port_feature(hub->hdev,
- port, USB_PORT_FEAT_BH_PORT_RESET);
- if (ret) {
- dev_err(hub->intfdev, "cannot warm reset port %d\n", port);
- return ret;
- }
-
- msleep(20);
- ret = hub_port_status(hub, port, &portstatus, &portchange);
-
- if (portchange & USB_PORT_STAT_C_RESET)
- clear_port_feature(hub->hdev, port, USB_PORT_FEAT_C_RESET);
-
- if (portchange & USB_PORT_STAT_C_BH_RESET)
- clear_port_feature(hub->hdev, port,
- USB_PORT_FEAT_C_BH_PORT_RESET);
-
- if (portchange & USB_PORT_STAT_C_LINK_STATE)
- clear_port_feature(hub->hdev, port,
- USB_PORT_FEAT_C_PORT_LINK_STATE);
+done:
+ if (!warm)
+ up_read(&ehci_cf_port_reset_rwsem);
- return ret;
+ return status;
}
/* Check if a port is power on */
@@ -2324,8 +2369,6 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
int port1 = udev->portnum;
int status;
- // dev_dbg(hub->intfdev, "suspend port %d\n", port1);
-
/* enable remote wakeup when appropriate; this lets the device
* wake up the upstream hub (including maybe the root hub).
*
@@ -2342,11 +2385,15 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
dev_dbg(&udev->dev, "won't remote wakeup, status %d\n",
status);
/* bail if autosuspend is requested */
- if (msg.event & PM_EVENT_AUTO)
+ if (PMSG_IS_AUTO(msg))
return status;
}
}
+ /* disable USB2 hardware LPM */
+ if (udev->usb2_hw_lpm_enabled == 1)
+ usb_set_usb2_hardware_lpm(udev, 0);
+
/* see 7.1.7.6 */
if (hub_is_superspeed(hub->hdev))
status = set_port_feature(hub->hdev,
@@ -2367,12 +2414,13 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
USB_CTRL_SET_TIMEOUT);
/* System sleep transitions should never fail */
- if (!(msg.event & PM_EVENT_AUTO))
+ if (!PMSG_IS_AUTO(msg))
status = 0;
} else {
/* device has up to 10 msec to fully suspend */
- dev_dbg(&udev->dev, "usb %ssuspend\n",
- (msg.event & PM_EVENT_AUTO ? "auto-" : ""));
+ dev_dbg(&udev->dev, "usb %ssuspend, wakeup %d\n",
+ (PMSG_IS_AUTO(msg) ? "auto-" : ""),
+ udev->do_remote_wakeup);
usb_set_device_state(udev, USB_STATE_SUSPENDED);
msleep(10);
}
@@ -2523,7 +2571,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
} else {
/* drive resume for at least 20 msec */
dev_dbg(&udev->dev, "usb %sresume\n",
- (msg.event & PM_EVENT_AUTO ? "auto-" : ""));
+ (PMSG_IS_AUTO(msg) ? "auto-" : ""));
msleep(25);
/* Virtual root hubs can trigger on GET_PORT_STATUS to
@@ -2558,7 +2606,12 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
if (status < 0) {
dev_dbg(&udev->dev, "can't resume, status %d\n", status);
hub_port_logical_disconnect(hub, port1);
+ } else {
+ /* Try to enable USB2 hardware LPM */
+ if (udev->usb2_hw_lpm_capable == 1)
+ usb_set_usb2_hardware_lpm(udev, 1);
}
+
return status;
}
@@ -2625,7 +2678,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
udev = hdev->children [port1-1];
if (udev && udev->can_submit) {
dev_warn(&intf->dev, "port %d nyet suspended\n", port1);
- if (msg.event & PM_EVENT_AUTO)
+ if (PMSG_IS_AUTO(msg))
return -EBUSY;
}
}
@@ -2798,7 +2851,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
int i, j, retval;
unsigned delay = HUB_SHORT_RESET_TIME;
enum usb_device_speed oldspeed = udev->speed;
- char *speed, *type;
+ const char *speed;
int devnum = udev->devnum;
/* root hub ports have a slightly longer reset period
@@ -2819,7 +2872,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
/* Reset the device; full speed may morph to high speed */
/* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
- retval = hub_port_reset(hub, port1, udev, delay);
+ retval = hub_port_reset(hub, port1, udev, delay, false);
if (retval < 0) /* error or disconnect */
goto fail;
/* success, speed is known */
@@ -2858,25 +2911,16 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
default:
goto fail;
}
-
- type = "";
- switch (udev->speed) {
- case USB_SPEED_LOW: speed = "low"; break;
- case USB_SPEED_FULL: speed = "full"; break;
- case USB_SPEED_HIGH: speed = "high"; break;
- case USB_SPEED_SUPER:
- speed = "super";
- break;
- case USB_SPEED_WIRELESS:
- speed = "variable";
- type = "Wireless ";
- break;
- default: speed = "?"; break;
- }
+
+ if (udev->speed == USB_SPEED_WIRELESS)
+ speed = "variable speed Wireless";
+ else
+ speed = usb_speed_string(udev->speed);
+
if (udev->speed != USB_SPEED_SUPER)
dev_info(&udev->dev,
- "%s %s speed %sUSB device number %d using %s\n",
- (udev->config) ? "reset" : "new", speed, type,
+ "%s %s USB device number %d using %s\n",
+ (udev->config) ? "reset" : "new", speed,
devnum, udev->bus->controller->driver->name);
/* Set up TT records, if needed */
@@ -2949,7 +2993,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
buf->bMaxPacketSize0;
kfree(buf);
- retval = hub_port_reset(hub, port1, udev, delay);
+ retval = hub_port_reset(hub, port1, udev, delay, false);
if (retval < 0) /* error or disconnect */
goto fail;
if (oldspeed != udev->speed) {
@@ -3023,7 +3067,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
i = 512;
else
i = udev->descriptor.bMaxPacketSize0;
- if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {
+ if (usb_endpoint_maxp(&udev->ep0.desc) != i) {
if (udev->speed == USB_SPEED_LOW ||
!(i == 8 || i == 16 || i == 32 || i == 64)) {
dev_err(&udev->dev, "Invalid ep0 maxpacket: %d\n", i);
@@ -3047,6 +3091,15 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
goto fail;
}
+ if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) {
+ retval = usb_get_bos_descriptor(udev);
+ if (!retval) {
+ if (udev->bos->ext_cap && (USB_LPM_SUPPORT &
+ le32_to_cpu(udev->bos->ext_cap->bmAttributes)))
+ udev->lpm_capable = 1;
+ }
+ }
+
retval = 0;
/* notify HCD that we have a device connected and addressed */
if (hcd->driver->update_device)
@@ -3570,7 +3623,8 @@ static void hub_events(void)
(portstatus & USB_PORT_STAT_LINK_STATE)
== USB_SS_PORT_LS_SS_INACTIVE) {
dev_dbg(hub_dev, "warm reset port %d\n", i);
- hub_port_warm_reset(hub, i);
+ hub_port_reset(hub, i, NULL,
+ HUB_BH_RESET_TIME, true);
}
if (connect_change)
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 0b5ec234c787..b3bdfede45e6 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -435,7 +435,7 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
len = sg->length;
if (length) {
- len = min_t(unsigned, len, length);
+ len = min_t(size_t, len, length);
length -= len;
if (length == 0)
io->entries = i + 1;
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 81ce6a8e1d94..d6a8d8269bfb 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -38,6 +38,27 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Creative SB Audigy 2 NX */
{ USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
+ /* Logitech Webcam C200 */
+ { USB_DEVICE(0x046d, 0x0802), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Webcam C250 */
+ { USB_DEVICE(0x046d, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Webcam C300 */
+ { USB_DEVICE(0x046d, 0x0805), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Webcam B/C500 */
+ { USB_DEVICE(0x046d, 0x0807), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Webcam Pro 9000 */
+ { USB_DEVICE(0x046d, 0x0809), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Webcam C310 */
+ { USB_DEVICE(0x046d, 0x081b), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Logitech Webcam C270 */
+ { USB_DEVICE(0x046d, 0x0825), .driver_info = USB_QUIRK_RESET_RESUME },
+
/* Logitech Harmony 700-series */
{ USB_DEVICE(0x046d, 0xc122), .driver_info = USB_QUIRK_DELAY_INIT },
@@ -69,6 +90,9 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x06a3, 0x0006), .driver_info =
USB_QUIRK_CONFIG_INTF_STRINGS },
+ /* Guillemot Webcam Hercules Dualpix Exchange*/
+ { USB_DEVICE(0x06f8, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME },
+
/* M-Systems Flash Disk Pioneers */
{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index cf05b97693ea..662c0cf3a3e1 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -412,6 +412,56 @@ set_level(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level);
+static ssize_t
+show_usb2_hardware_lpm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ const char *p;
+
+ if (udev->usb2_hw_lpm_enabled == 1)
+ p = "enabled";
+ else
+ p = "disabled";
+
+ return sprintf(buf, "%s\n", p);
+}
+
+static ssize_t
+set_usb2_hardware_lpm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ bool value;
+ int ret;
+
+ usb_lock_device(udev);
+
+ ret = strtobool(buf, &value);
+
+ if (!ret)
+ ret = usb_set_usb2_hardware_lpm(udev, value);
+
+ usb_unlock_device(udev);
+
+ if (!ret)
+ return count;
+
+ return ret;
+}
+
+static DEVICE_ATTR(usb2_hardware_lpm, S_IRUGO | S_IWUSR, show_usb2_hardware_lpm,
+ set_usb2_hardware_lpm);
+
+static struct attribute *usb2_hardware_lpm_attr[] = {
+ &dev_attr_usb2_hardware_lpm.attr,
+ NULL,
+};
+static struct attribute_group usb2_hardware_lpm_attr_group = {
+ .name = power_group_name,
+ .attrs = usb2_hardware_lpm_attr,
+};
+
static struct attribute *power_attrs[] = {
&dev_attr_autosuspend.attr,
&dev_attr_level.attr,
@@ -428,13 +478,20 @@ static int add_power_attributes(struct device *dev)
{
int rc = 0;
- if (is_usb_device(dev))
+ if (is_usb_device(dev)) {
+ struct usb_device *udev = to_usb_device(dev);
rc = sysfs_merge_group(&dev->kobj, &power_attr_group);
+ if (udev->usb2_hw_lpm_capable == 1)
+ rc = sysfs_merge_group(&dev->kobj,
+ &usb2_hardware_lpm_attr_group);
+ }
+
return rc;
}
static void remove_power_attributes(struct device *dev)
{
+ sysfs_unmerge_group(&dev->kobj, &usb2_hardware_lpm_attr_group);
sysfs_unmerge_group(&dev->kobj, &power_attr_group);
}
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index ae334b067c13..909625b91eb3 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -350,7 +350,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
dev->state < USB_STATE_CONFIGURED)
return -ENODEV;
- max = le16_to_cpu(ep->desc.wMaxPacketSize);
+ max = usb_endpoint_maxp(&ep->desc);
if (max <= 0) {
dev_dbg(&dev->dev,
"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 8706fc97e60f..73cd90012ec5 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -225,6 +225,7 @@ static void usb_release_dev(struct device *dev)
hcd = bus_to_hcd(udev->bus);
usb_destroy_configuration(udev);
+ usb_release_bos_descriptor(udev);
usb_put_hcd(hcd);
kfree(udev->product);
kfree(udev->manufacturer);
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index d44d4b7bbf17..3888778582c4 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -28,6 +28,8 @@ extern int usb_remove_device(struct usb_device *udev);
extern int usb_get_device_descriptor(struct usb_device *dev,
unsigned int size);
+extern int usb_get_bos_descriptor(struct usb_device *dev);
+extern void usb_release_bos_descriptor(struct usb_device *dev);
extern char *usb_cache_string(struct usb_device *udev, int index);
extern int usb_set_configuration(struct usb_device *dev, int configuration);
extern int usb_choose_configuration(struct usb_device *udev);
@@ -80,6 +82,7 @@ extern int usb_remote_wakeup(struct usb_device *dev);
extern int usb_runtime_suspend(struct device *dev);
extern int usb_runtime_resume(struct device *dev);
extern int usb_runtime_idle(struct device *dev);
+extern int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable);
#else
@@ -94,6 +97,10 @@ static inline int usb_remote_wakeup(struct usb_device *udev)
return 0;
}
+static inline int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
+{
+ return 0;
+}
#endif
extern struct bus_type usb_bus_type;
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
new file mode 100644
index 000000000000..3c1d67d324fd
--- /dev/null
+++ b/drivers/usb/dwc3/Kconfig
@@ -0,0 +1,25 @@
+config USB_DWC3
+ tristate "DesignWare USB3 DRD Core Support"
+ depends on (USB || USB_GADGET)
+ select USB_OTG_UTILS
+ help
+ Say Y or M here if your system has a Dual Role SuperSpeed
+ USB controller based on the DesignWare USB3 IP Core.
+
+ If you choose to build this driver is a dynamically linked
+ module, the module will be called dwc3.ko.
+
+if USB_DWC3
+
+config USB_DWC3_DEBUG
+ bool "Enable Debugging Messages"
+ help
+ Say Y here to enable debugging messages on DWC3 Driver.
+
+config USB_DWC3_VERBOSE
+ bool "Enable Verbose Debugging Messages"
+ depends on USB_DWC3_DEBUG
+ help
+ Say Y here to enable verbose debugging messages on DWC3 Driver.
+
+endif
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
new file mode 100644
index 000000000000..593d1dbc465b
--- /dev/null
+++ b/drivers/usb/dwc3/Makefile
@@ -0,0 +1,36 @@
+ccflags-$(CONFIG_USB_DWC3_DEBUG) := -DDEBUG
+ccflags-$(CONFIG_USB_DWC3_VERBOSE) += -DVERBOSE_DEBUG
+
+obj-$(CONFIG_USB_DWC3) += dwc3.o
+
+dwc3-y := core.o
+
+ifneq ($(CONFIG_USB_GADGET_DWC3),)
+ dwc3-y += gadget.o ep0.o
+endif
+
+ifneq ($(CONFIG_DEBUG_FS),)
+ dwc3-y += debugfs.o
+endif
+
+##
+# Platform-specific glue layers go here
+#
+# NOTICE: Make sure your glue layer doesn't depend on anything
+# which is arch-specific and that it compiles on all situations.
+#
+# We want to keep this requirement in order to be able to compile
+# the entire driver (with all its glue layers) on several architectures
+# and make sure it compiles fine. This will also help with allmodconfig
+# and allyesconfig builds.
+#
+# The only exception is the PCI glue layer, but that's only because
+# PCI doesn't provide nops if CONFIG_PCI isn't enabled.
+##
+
+obj-$(CONFIG_USB_DWC3) += dwc3-omap.o
+
+ifneq ($(CONFIG_PCI),)
+ obj-$(CONFIG_USB_DWC3) += dwc3-pci.o
+endif
+
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
new file mode 100644
index 000000000000..717ebc9ff941
--- /dev/null
+++ b/drivers/usb/dwc3/core.c
@@ -0,0 +1,484 @@
+/**
+ * core.c - DesignWare USB3 DRD Controller Core file
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/module.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+#include "debug.h"
+
+/**
+ * dwc3_core_soft_reset - Issues core soft reset and PHY reset
+ * @dwc: pointer to our context structure
+ */
+static void dwc3_core_soft_reset(struct dwc3 *dwc)
+{
+ u32 reg;
+
+ /* Before Resetting PHY, put Core in Reset */
+ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+ reg |= DWC3_GCTL_CORESOFTRESET;
+ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+ /* Assert USB3 PHY reset */
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+ reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
+ dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+
+ /* Assert USB2 PHY reset */
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+ reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+ mdelay(100);
+
+ /* Clear USB3 PHY reset */
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+ reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
+ dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+
+ /* Clear USB2 PHY reset */
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+ reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+ /* After PHYs are stable we can take Core out of reset state */
+ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+ reg &= ~DWC3_GCTL_CORESOFTRESET;
+ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+}
+
+/**
+ * dwc3_free_one_event_buffer - Frees one event buffer
+ * @dwc: Pointer to our controller context structure
+ * @evt: Pointer to event buffer to be freed
+ */
+static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
+ struct dwc3_event_buffer *evt)
+{
+ dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma);
+ kfree(evt);
+}
+
+/**
+ * dwc3_alloc_one_event_buffer - Allocated one event buffer structure
+ * @dwc: Pointer to our controller context structure
+ * @length: size of the event buffer
+ *
+ * Returns a pointer to the allocated event buffer structure on succes
+ * otherwise ERR_PTR(errno).
+ */
+static struct dwc3_event_buffer *__devinit
+dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned length)
+{
+ struct dwc3_event_buffer *evt;
+
+ evt = kzalloc(sizeof(*evt), GFP_KERNEL);
+ if (!evt)
+ return ERR_PTR(-ENOMEM);
+
+ evt->dwc = dwc;
+ evt->length = length;
+ evt->buf = dma_alloc_coherent(dwc->dev, length,
+ &evt->dma, GFP_KERNEL);
+ if (!evt->buf) {
+ kfree(evt);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ return evt;
+}
+
+/**
+ * dwc3_free_event_buffers - frees all allocated event buffers
+ * @dwc: Pointer to our controller context structure
+ */
+static void dwc3_free_event_buffers(struct dwc3 *dwc)
+{
+ struct dwc3_event_buffer *evt;
+ int i;
+
+ for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) {
+ evt = dwc->ev_buffs[i];
+ if (evt) {
+ dwc3_free_one_event_buffer(dwc, evt);
+ dwc->ev_buffs[i] = NULL;
+ }
+ }
+}
+
+/**
+ * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
+ * @dwc: Pointer to out controller context structure
+ * @num: number of event buffers to allocate
+ * @length: size of event buffer
+ *
+ * Returns 0 on success otherwise negative errno. In error the case, dwc
+ * may contain some buffers allocated but not all which were requested.
+ */
+static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned num,
+ unsigned length)
+{
+ int i;
+
+ for (i = 0; i < num; i++) {
+ struct dwc3_event_buffer *evt;
+
+ evt = dwc3_alloc_one_event_buffer(dwc, length);
+ if (IS_ERR(evt)) {
+ dev_err(dwc->dev, "can't allocate event buffer\n");
+ return PTR_ERR(evt);
+ }
+ dwc->ev_buffs[i] = evt;
+ }
+
+ return 0;
+}
+
+/**
+ * dwc3_event_buffers_setup - setup our allocated event buffers
+ * @dwc: Pointer to out controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc)
+{
+ struct dwc3_event_buffer *evt;
+ int n;
+
+ for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) {
+ evt = dwc->ev_buffs[n];
+ dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
+ evt->buf, (unsigned long long) evt->dma,
+ evt->length);
+
+ dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
+ lower_32_bits(evt->dma));
+ dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
+ upper_32_bits(evt->dma));
+ dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
+ evt->length & 0xffff);
+ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
+ }
+
+ return 0;
+}
+
+static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
+{
+ struct dwc3_event_buffer *evt;
+ int n;
+
+ for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) {
+ evt = dwc->ev_buffs[n];
+ dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
+ dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
+ dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0);
+ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
+ }
+}
+
+static void __devinit dwc3_cache_hwparams(struct dwc3 *dwc)
+{
+ struct dwc3_hwparams *parms = &dwc->hwparams;
+
+ parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
+ parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
+ parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
+ parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
+ parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
+ parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
+ parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
+ parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
+ parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
+}
+
+/**
+ * dwc3_core_init - Low-level initialization of DWC3 Core
+ * @dwc: Pointer to our controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int __devinit dwc3_core_init(struct dwc3 *dwc)
+{
+ unsigned long timeout;
+ u32 reg;
+ int ret;
+
+ reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
+ /* This should read as U3 followed by revision number */
+ if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) {
+ dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
+ ret = -ENODEV;
+ goto err0;
+ }
+ dwc->revision = reg & DWC3_GSNPSREV_MASK;
+
+ dwc3_core_soft_reset(dwc);
+
+ /* issue device SoftReset too */
+ timeout = jiffies + msecs_to_jiffies(500);
+ dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
+ do {
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ if (!(reg & DWC3_DCTL_CSFTRST))
+ break;
+
+ if (time_after(jiffies, timeout)) {
+ dev_err(dwc->dev, "Reset Timed Out\n");
+ ret = -ETIMEDOUT;
+ goto err0;
+ }
+
+ cpu_relax();
+ } while (true);
+
+ ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_NUM,
+ DWC3_EVENT_BUFFERS_SIZE);
+ if (ret) {
+ dev_err(dwc->dev, "failed to allocate event buffers\n");
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ ret = dwc3_event_buffers_setup(dwc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to setup event buffers\n");
+ goto err1;
+ }
+
+ dwc3_cache_hwparams(dwc);
+
+ return 0;
+
+err1:
+ dwc3_free_event_buffers(dwc);
+
+err0:
+ return ret;
+}
+
+static void dwc3_core_exit(struct dwc3 *dwc)
+{
+ dwc3_event_buffers_cleanup(dwc);
+ dwc3_free_event_buffers(dwc);
+}
+
+#define DWC3_ALIGN_MASK (16 - 1)
+
+static int __devinit dwc3_probe(struct platform_device *pdev)
+{
+ const struct platform_device_id *id = platform_get_device_id(pdev);
+ struct resource *res;
+ struct dwc3 *dwc;
+ void __iomem *regs;
+ unsigned int features = id->driver_data;
+ int ret = -ENOMEM;
+ int irq;
+ void *mem;
+
+ mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
+ if (!mem) {
+ dev_err(&pdev->dev, "not enough memory\n");
+ goto err0;
+ }
+ dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
+ dwc->mem = mem;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "missing resource\n");
+ goto err1;
+ }
+
+ res = request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev));
+ if (!res) {
+ dev_err(&pdev->dev, "can't request mem region\n");
+ goto err1;
+ }
+
+ regs = ioremap(res->start, resource_size(res));
+ if (!regs) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ goto err2;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "missing IRQ\n");
+ goto err3;
+ }
+
+ spin_lock_init(&dwc->lock);
+ platform_set_drvdata(pdev, dwc);
+
+ dwc->regs = regs;
+ dwc->regs_size = resource_size(res);
+ dwc->dev = &pdev->dev;
+ dwc->irq = irq;
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+ pm_runtime_forbid(&pdev->dev);
+
+ ret = dwc3_core_init(dwc);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to initialize core\n");
+ goto err3;
+ }
+
+ if (features & DWC3_HAS_PERIPHERAL) {
+ ret = dwc3_gadget_init(dwc);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to initialized gadget\n");
+ goto err4;
+ }
+ }
+
+ ret = dwc3_debugfs_init(dwc);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to initialize debugfs\n");
+ goto err5;
+ }
+
+ pm_runtime_allow(&pdev->dev);
+
+ return 0;
+
+err5:
+ if (features & DWC3_HAS_PERIPHERAL)
+ dwc3_gadget_exit(dwc);
+
+err4:
+ dwc3_core_exit(dwc);
+
+err3:
+ iounmap(regs);
+
+err2:
+ release_mem_region(res->start, resource_size(res));
+
+err1:
+ kfree(dwc->mem);
+
+err0:
+ return ret;
+}
+
+static int __devexit dwc3_remove(struct platform_device *pdev)
+{
+ const struct platform_device_id *id = platform_get_device_id(pdev);
+ struct dwc3 *dwc = platform_get_drvdata(pdev);
+ struct resource *res;
+ unsigned int features = id->driver_data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+ dwc3_debugfs_exit(dwc);
+
+ if (features & DWC3_HAS_PERIPHERAL)
+ dwc3_gadget_exit(dwc);
+
+ dwc3_core_exit(dwc);
+ release_mem_region(res->start, resource_size(res));
+ iounmap(dwc->regs);
+ kfree(dwc->mem);
+
+ return 0;
+}
+
+static const struct platform_device_id dwc3_id_table[] __devinitconst = {
+ {
+ .name = "dwc3-omap",
+ .driver_data = (DWC3_HAS_PERIPHERAL
+ | DWC3_HAS_XHCI
+ | DWC3_HAS_OTG),
+ },
+ {
+ .name = "dwc3-pci",
+ .driver_data = DWC3_HAS_PERIPHERAL,
+ },
+ { }, /* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(platform, dwc3_id_table);
+
+static struct platform_driver dwc3_driver = {
+ .probe = dwc3_probe,
+ .remove = __devexit_p(dwc3_remove),
+ .driver = {
+ .name = "dwc3",
+ },
+ .id_table = dwc3_id_table,
+};
+
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
+
+static int __devinit dwc3_init(void)
+{
+ return platform_driver_register(&dwc3_driver);
+}
+module_init(dwc3_init);
+
+static void __exit dwc3_exit(void)
+{
+ platform_driver_unregister(&dwc3_driver);
+}
+module_exit(dwc3_exit);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
new file mode 100644
index 000000000000..29a8e1679e12
--- /dev/null
+++ b/drivers/usb/dwc3/core.h
@@ -0,0 +1,768 @@
+/**
+ * core.h - DesignWare USB3 DRD Core Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * 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 __DRIVERS_USB_DWC3_CORE_H
+#define __DRIVERS_USB_DWC3_CORE_H
+
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/debugfs.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/* Global constants */
+#define DWC3_ENDPOINTS_NUM 32
+
+#define DWC3_EVENT_BUFFERS_NUM 2
+#define DWC3_EVENT_BUFFERS_SIZE PAGE_SIZE
+#define DWC3_EVENT_TYPE_MASK 0xfe
+
+#define DWC3_EVENT_TYPE_DEV 0
+#define DWC3_EVENT_TYPE_CARKIT 3
+#define DWC3_EVENT_TYPE_I2C 4
+
+#define DWC3_DEVICE_EVENT_DISCONNECT 0
+#define DWC3_DEVICE_EVENT_RESET 1
+#define DWC3_DEVICE_EVENT_CONNECT_DONE 2
+#define DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE 3
+#define DWC3_DEVICE_EVENT_WAKEUP 4
+#define DWC3_DEVICE_EVENT_EOPF 6
+#define DWC3_DEVICE_EVENT_SOF 7
+#define DWC3_DEVICE_EVENT_ERRATIC_ERROR 9
+#define DWC3_DEVICE_EVENT_CMD_CMPL 10
+#define DWC3_DEVICE_EVENT_OVERFLOW 11
+
+#define DWC3_GEVNTCOUNT_MASK 0xfffc
+#define DWC3_GSNPSID_MASK 0xffff0000
+#define DWC3_GSNPSREV_MASK 0xffff
+
+/* Global Registers */
+#define DWC3_GSBUSCFG0 0xc100
+#define DWC3_GSBUSCFG1 0xc104
+#define DWC3_GTXTHRCFG 0xc108
+#define DWC3_GRXTHRCFG 0xc10c
+#define DWC3_GCTL 0xc110
+#define DWC3_GEVTEN 0xc114
+#define DWC3_GSTS 0xc118
+#define DWC3_GSNPSID 0xc120
+#define DWC3_GGPIO 0xc124
+#define DWC3_GUID 0xc128
+#define DWC3_GUCTL 0xc12c
+#define DWC3_GBUSERRADDR0 0xc130
+#define DWC3_GBUSERRADDR1 0xc134
+#define DWC3_GPRTBIMAP0 0xc138
+#define DWC3_GPRTBIMAP1 0xc13c
+#define DWC3_GHWPARAMS0 0xc140
+#define DWC3_GHWPARAMS1 0xc144
+#define DWC3_GHWPARAMS2 0xc148
+#define DWC3_GHWPARAMS3 0xc14c
+#define DWC3_GHWPARAMS4 0xc150
+#define DWC3_GHWPARAMS5 0xc154
+#define DWC3_GHWPARAMS6 0xc158
+#define DWC3_GHWPARAMS7 0xc15c
+#define DWC3_GDBGFIFOSPACE 0xc160
+#define DWC3_GDBGLTSSM 0xc164
+#define DWC3_GPRTBIMAP_HS0 0xc180
+#define DWC3_GPRTBIMAP_HS1 0xc184
+#define DWC3_GPRTBIMAP_FS0 0xc188
+#define DWC3_GPRTBIMAP_FS1 0xc18c
+
+#define DWC3_GUSB2PHYCFG(n) (0xc200 + (n * 0x04))
+#define DWC3_GUSB2I2CCTL(n) (0xc240 + (n * 0x04))
+
+#define DWC3_GUSB2PHYACC(n) (0xc280 + (n * 0x04))
+
+#define DWC3_GUSB3PIPECTL(n) (0xc2c0 + (n * 0x04))
+
+#define DWC3_GTXFIFOSIZ(n) (0xc300 + (n * 0x04))
+#define DWC3_GRXFIFOSIZ(n) (0xc380 + (n * 0x04))
+
+#define DWC3_GEVNTADRLO(n) (0xc400 + (n * 0x10))
+#define DWC3_GEVNTADRHI(n) (0xc404 + (n * 0x10))
+#define DWC3_GEVNTSIZ(n) (0xc408 + (n * 0x10))
+#define DWC3_GEVNTCOUNT(n) (0xc40c + (n * 0x10))
+
+#define DWC3_GHWPARAMS8 0xc600
+
+/* Device Registers */
+#define DWC3_DCFG 0xc700
+#define DWC3_DCTL 0xc704
+#define DWC3_DEVTEN 0xc708
+#define DWC3_DSTS 0xc70c
+#define DWC3_DGCMDPAR 0xc710
+#define DWC3_DGCMD 0xc714
+#define DWC3_DALEPENA 0xc720
+#define DWC3_DEPCMDPAR2(n) (0xc800 + (n * 0x10))
+#define DWC3_DEPCMDPAR1(n) (0xc804 + (n * 0x10))
+#define DWC3_DEPCMDPAR0(n) (0xc808 + (n * 0x10))
+#define DWC3_DEPCMD(n) (0xc80c + (n * 0x10))
+
+/* OTG Registers */
+#define DWC3_OCFG 0xcc00
+#define DWC3_OCTL 0xcc04
+#define DWC3_OEVTEN 0xcc08
+#define DWC3_OSTS 0xcc0C
+
+/* Bit fields */
+
+/* Global Configuration Register */
+#define DWC3_GCTL_PWRDNSCALE(n) (n << 19)
+#define DWC3_GCTL_U2RSTECN (1 << 16)
+#define DWC3_GCTL_RAMCLKSEL(x) ((x & DWC3_GCTL_CLK_MASK) << 6)
+#define DWC3_GCTL_CLK_BUS (0)
+#define DWC3_GCTL_CLK_PIPE (1)
+#define DWC3_GCTL_CLK_PIPEHALF (2)
+#define DWC3_GCTL_CLK_MASK (3)
+
+#define DWC3_GCTL_PRTCAPDIR(n) (n << 12)
+#define DWC3_GCTL_PRTCAP_HOST 1
+#define DWC3_GCTL_PRTCAP_DEVICE 2
+#define DWC3_GCTL_PRTCAP_OTG 3
+
+#define DWC3_GCTL_CORESOFTRESET (1 << 11)
+#define DWC3_GCTL_SCALEDOWN(n) (n << 4)
+#define DWC3_GCTL_DISSCRAMBLE (1 << 3)
+#define DWC3_GCTL_DSBLCLKGTNG (1 << 0)
+
+/* Global USB2 PHY Configuration Register */
+#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
+#define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6)
+
+/* Global USB3 PIPE Control Register */
+#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
+#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
+
+/* Global HWPARAMS1 Register */
+#define DWC3_GHWPARAMS1_EN_PWROPT(n) ((n & (3 << 24)) >> 24)
+#define DWC3_GHWPARAMS1_EN_PWROPT_NO 0
+#define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1
+
+/* Device Configuration Register */
+#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3)
+#define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
+
+#define DWC3_DCFG_SPEED_MASK (7 << 0)
+#define DWC3_DCFG_SUPERSPEED (4 << 0)
+#define DWC3_DCFG_HIGHSPEED (0 << 0)
+#define DWC3_DCFG_FULLSPEED2 (1 << 0)
+#define DWC3_DCFG_LOWSPEED (2 << 0)
+#define DWC3_DCFG_FULLSPEED1 (3 << 0)
+
+/* Device Control Register */
+#define DWC3_DCTL_RUN_STOP (1 << 31)
+#define DWC3_DCTL_CSFTRST (1 << 30)
+#define DWC3_DCTL_LSFTRST (1 << 29)
+
+#define DWC3_DCTL_HIRD_THRES_MASK (0x1f << 24)
+#define DWC3_DCTL_HIRD_THRES(n) (((n) & DWC3_DCTL_HIRD_THRES_MASK) >> 24)
+
+#define DWC3_DCTL_APPL1RES (1 << 23)
+
+#define DWC3_DCTL_INITU2ENA (1 << 12)
+#define DWC3_DCTL_ACCEPTU2ENA (1 << 11)
+#define DWC3_DCTL_INITU1ENA (1 << 10)
+#define DWC3_DCTL_ACCEPTU1ENA (1 << 9)
+#define DWC3_DCTL_TSTCTRL_MASK (0xf << 1)
+
+#define DWC3_DCTL_ULSTCHNGREQ_MASK (0x0f << 5)
+#define DWC3_DCTL_ULSTCHNGREQ(n) (((n) << 5) & DWC3_DCTL_ULSTCHNGREQ_MASK)
+
+#define DWC3_DCTL_ULSTCHNG_NO_ACTION (DWC3_DCTL_ULSTCHNGREQ(0))
+#define DWC3_DCTL_ULSTCHNG_SS_DISABLED (DWC3_DCTL_ULSTCHNGREQ(4))
+#define DWC3_DCTL_ULSTCHNG_RX_DETECT (DWC3_DCTL_ULSTCHNGREQ(5))
+#define DWC3_DCTL_ULSTCHNG_SS_INACTIVE (DWC3_DCTL_ULSTCHNGREQ(6))
+#define DWC3_DCTL_ULSTCHNG_RECOVERY (DWC3_DCTL_ULSTCHNGREQ(8))
+#define DWC3_DCTL_ULSTCHNG_COMPLIANCE (DWC3_DCTL_ULSTCHNGREQ(10))
+#define DWC3_DCTL_ULSTCHNG_LOOPBACK (DWC3_DCTL_ULSTCHNGREQ(11))
+
+/* Device Event Enable Register */
+#define DWC3_DEVTEN_VNDRDEVTSTRCVEDEN (1 << 12)
+#define DWC3_DEVTEN_EVNTOVERFLOWEN (1 << 11)
+#define DWC3_DEVTEN_CMDCMPLTEN (1 << 10)
+#define DWC3_DEVTEN_ERRTICERREN (1 << 9)
+#define DWC3_DEVTEN_SOFEN (1 << 7)
+#define DWC3_DEVTEN_EOPFEN (1 << 6)
+#define DWC3_DEVTEN_WKUPEVTEN (1 << 4)
+#define DWC3_DEVTEN_ULSTCNGEN (1 << 3)
+#define DWC3_DEVTEN_CONNECTDONEEN (1 << 2)
+#define DWC3_DEVTEN_USBRSTEN (1 << 1)
+#define DWC3_DEVTEN_DISCONNEVTEN (1 << 0)
+
+/* Device Status Register */
+#define DWC3_DSTS_PWRUPREQ (1 << 24)
+#define DWC3_DSTS_COREIDLE (1 << 23)
+#define DWC3_DSTS_DEVCTRLHLT (1 << 22)
+
+#define DWC3_DSTS_USBLNKST_MASK (0x0f << 18)
+#define DWC3_DSTS_USBLNKST(n) (((n) & DWC3_DSTS_USBLNKST_MASK) >> 18)
+
+#define DWC3_DSTS_RXFIFOEMPTY (1 << 17)
+
+#define DWC3_DSTS_SOFFN_MASK (0x3ff << 3)
+#define DWC3_DSTS_SOFFN(n) (((n) & DWC3_DSTS_SOFFN_MASK) >> 3)
+
+#define DWC3_DSTS_CONNECTSPD (7 << 0)
+
+#define DWC3_DSTS_SUPERSPEED (4 << 0)
+#define DWC3_DSTS_HIGHSPEED (0 << 0)
+#define DWC3_DSTS_FULLSPEED2 (1 << 0)
+#define DWC3_DSTS_LOWSPEED (2 << 0)
+#define DWC3_DSTS_FULLSPEED1 (3 << 0)
+
+/* Device Generic Command Register */
+#define DWC3_DGCMD_SET_LMP 0x01
+#define DWC3_DGCMD_SET_PERIODIC_PAR 0x02
+#define DWC3_DGCMD_XMIT_FUNCTION 0x03
+#define DWC3_DGCMD_SELECTED_FIFO_FLUSH 0x09
+#define DWC3_DGCMD_ALL_FIFO_FLUSH 0x0a
+#define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c
+#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK 0x10
+
+/* Device Endpoint Command Register */
+#define DWC3_DEPCMD_PARAM_SHIFT 16
+#define DWC3_DEPCMD_PARAM(x) (x << DWC3_DEPCMD_PARAM_SHIFT)
+#define DWC3_DEPCMD_GET_RSC_IDX(x) ((x >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
+#define DWC3_DEPCMD_STATUS_MASK (0x0f << 12)
+#define DWC3_DEPCMD_STATUS(x) ((x & DWC3_DEPCMD_STATUS_MASK) >> 12)
+#define DWC3_DEPCMD_HIPRI_FORCERM (1 << 11)
+#define DWC3_DEPCMD_CMDACT (1 << 10)
+#define DWC3_DEPCMD_CMDIOC (1 << 8)
+
+#define DWC3_DEPCMD_DEPSTARTCFG (0x09 << 0)
+#define DWC3_DEPCMD_ENDTRANSFER (0x08 << 0)
+#define DWC3_DEPCMD_UPDATETRANSFER (0x07 << 0)
+#define DWC3_DEPCMD_STARTTRANSFER (0x06 << 0)
+#define DWC3_DEPCMD_CLEARSTALL (0x05 << 0)
+#define DWC3_DEPCMD_SETSTALL (0x04 << 0)
+#define DWC3_DEPCMD_GETSEQNUMBER (0x03 << 0)
+#define DWC3_DEPCMD_SETTRANSFRESOURCE (0x02 << 0)
+#define DWC3_DEPCMD_SETEPCONFIG (0x01 << 0)
+
+/* The EP number goes 0..31 so ep0 is always out and ep1 is always in */
+#define DWC3_DALEPENA_EP(n) (1 << n)
+
+#define DWC3_DEPCMD_TYPE_CONTROL 0
+#define DWC3_DEPCMD_TYPE_ISOC 1
+#define DWC3_DEPCMD_TYPE_BULK 2
+#define DWC3_DEPCMD_TYPE_INTR 3
+
+/* Structures */
+
+struct dwc3_trb_hw;
+
+/**
+ * struct dwc3_event_buffer - Software event buffer representation
+ * @list: a list of event buffers
+ * @buf: _THE_ buffer
+ * @length: size of this buffer
+ * @dma: dma_addr_t
+ * @dwc: pointer to DWC controller
+ */
+struct dwc3_event_buffer {
+ void *buf;
+ unsigned length;
+ unsigned int lpos;
+
+ dma_addr_t dma;
+
+ struct dwc3 *dwc;
+};
+
+#define DWC3_EP_FLAG_STALLED (1 << 0)
+#define DWC3_EP_FLAG_WEDGED (1 << 1)
+
+#define DWC3_EP_DIRECTION_TX true
+#define DWC3_EP_DIRECTION_RX false
+
+#define DWC3_TRB_NUM 32
+#define DWC3_TRB_MASK (DWC3_TRB_NUM - 1)
+
+/**
+ * struct dwc3_ep - device side endpoint representation
+ * @endpoint: usb endpoint
+ * @request_list: list of requests for this endpoint
+ * @req_queued: list of requests on this ep which have TRBs setup
+ * @trb_pool: array of transaction buffers
+ * @trb_pool_dma: dma address of @trb_pool
+ * @free_slot: next slot which is going to be used
+ * @busy_slot: first slot which is owned by HW
+ * @desc: usb_endpoint_descriptor pointer
+ * @dwc: pointer to DWC controller
+ * @flags: endpoint flags (wedged, stalled, ...)
+ * @current_trb: index of current used trb
+ * @number: endpoint number (1 - 15)
+ * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
+ * @res_trans_idx: Resource transfer index
+ * @interval: the intervall on which the ISOC transfer is started
+ * @name: a human readable name e.g. ep1out-bulk
+ * @direction: true for TX, false for RX
+ * @stream_capable: true when streams are enabled
+ */
+struct dwc3_ep {
+ struct usb_ep endpoint;
+ struct list_head request_list;
+ struct list_head req_queued;
+
+ struct dwc3_trb_hw *trb_pool;
+ dma_addr_t trb_pool_dma;
+ u32 free_slot;
+ u32 busy_slot;
+ const struct usb_endpoint_descriptor *desc;
+ struct dwc3 *dwc;
+
+ unsigned flags;
+#define DWC3_EP_ENABLED (1 << 0)
+#define DWC3_EP_STALL (1 << 1)
+#define DWC3_EP_WEDGE (1 << 2)
+#define DWC3_EP_BUSY (1 << 4)
+#define DWC3_EP_PENDING_REQUEST (1 << 5)
+
+ /* This last one is specific to EP0 */
+#define DWC3_EP0_DIR_IN (1 << 31)
+
+ unsigned current_trb;
+
+ u8 number;
+ u8 type;
+ u8 res_trans_idx;
+ u32 interval;
+
+ char name[20];
+
+ unsigned direction:1;
+ unsigned stream_capable:1;
+};
+
+enum dwc3_phy {
+ DWC3_PHY_UNKNOWN = 0,
+ DWC3_PHY_USB3,
+ DWC3_PHY_USB2,
+};
+
+enum dwc3_ep0_next {
+ DWC3_EP0_UNKNOWN = 0,
+ DWC3_EP0_COMPLETE,
+ DWC3_EP0_NRDY_SETUP,
+ DWC3_EP0_NRDY_DATA,
+ DWC3_EP0_NRDY_STATUS,
+};
+
+enum dwc3_ep0_state {
+ EP0_UNCONNECTED = 0,
+ EP0_SETUP_PHASE,
+ EP0_DATA_PHASE,
+ EP0_STATUS_PHASE,
+};
+
+enum dwc3_link_state {
+ /* In SuperSpeed */
+ DWC3_LINK_STATE_U0 = 0x00, /* in HS, means ON */
+ DWC3_LINK_STATE_U1 = 0x01,
+ DWC3_LINK_STATE_U2 = 0x02, /* in HS, means SLEEP */
+ DWC3_LINK_STATE_U3 = 0x03, /* in HS, means SUSPEND */
+ DWC3_LINK_STATE_SS_DIS = 0x04,
+ DWC3_LINK_STATE_RX_DET = 0x05, /* in HS, means Early Suspend */
+ DWC3_LINK_STATE_SS_INACT = 0x06,
+ DWC3_LINK_STATE_POLL = 0x07,
+ DWC3_LINK_STATE_RECOV = 0x08,
+ DWC3_LINK_STATE_HRESET = 0x09,
+ DWC3_LINK_STATE_CMPLY = 0x0a,
+ DWC3_LINK_STATE_LPBK = 0x0b,
+ DWC3_LINK_STATE_MASK = 0x0f,
+};
+
+enum dwc3_device_state {
+ DWC3_DEFAULT_STATE,
+ DWC3_ADDRESS_STATE,
+ DWC3_CONFIGURED_STATE,
+};
+
+/**
+ * struct dwc3_trb - transfer request block
+ * @bpl: lower 32bit of the buffer
+ * @bph: higher 32bit of the buffer
+ * @length: buffer size (up to 16mb - 1)
+ * @pcm1: packet count m1
+ * @trbsts: trb status
+ * 0 = ok
+ * 1 = missed isoc
+ * 2 = setup pending
+ * @hwo: hardware owner of descriptor
+ * @lst: last trb
+ * @chn: chain buffers
+ * @csp: continue on short packets (only supported on isoc eps)
+ * @trbctl: trb control
+ * 1 = normal
+ * 2 = control-setup
+ * 3 = control-status-2
+ * 4 = control-status-3
+ * 5 = control-data (first trb of data stage)
+ * 6 = isochronous-first (first trb of service interval)
+ * 7 = isochronous
+ * 8 = link trb
+ * others = reserved
+ * @isp_imi: interrupt on short packet / interrupt on missed isoc
+ * @ioc: interrupt on complete
+ * @sid_sofn: Stream ID / SOF Number
+ */
+struct dwc3_trb {
+ u64 bplh;
+
+ union {
+ struct {
+ u32 length:24;
+ u32 pcm1:2;
+ u32 reserved27_26:2;
+ u32 trbsts:4;
+#define DWC3_TRB_STS_OKAY 0
+#define DWC3_TRB_STS_MISSED_ISOC 1
+#define DWC3_TRB_STS_SETUP_PENDING 2
+ };
+ u32 len_pcm;
+ };
+
+ union {
+ struct {
+ u32 hwo:1;
+ u32 lst:1;
+ u32 chn:1;
+ u32 csp:1;
+ u32 trbctl:6;
+ u32 isp_imi:1;
+ u32 ioc:1;
+ u32 reserved13_12:2;
+ u32 sid_sofn:16;
+ u32 reserved31_30:2;
+ };
+ u32 control;
+ };
+} __packed;
+
+/**
+ * struct dwc3_trb_hw - transfer request block (hw format)
+ * @bpl: DW0-3
+ * @bph: DW4-7
+ * @size: DW8-B
+ * @trl: DWC-F
+ */
+struct dwc3_trb_hw {
+ __le32 bpl;
+ __le32 bph;
+ __le32 size;
+ __le32 ctrl;
+} __packed;
+
+static inline void dwc3_trb_to_hw(struct dwc3_trb *nat, struct dwc3_trb_hw *hw)
+{
+ hw->bpl = cpu_to_le32(lower_32_bits(nat->bplh));
+ hw->bph = cpu_to_le32(upper_32_bits(nat->bplh));
+ hw->size = cpu_to_le32p(&nat->len_pcm);
+ /* HWO is written last */
+ hw->ctrl = cpu_to_le32p(&nat->control);
+}
+
+static inline void dwc3_trb_to_nat(struct dwc3_trb_hw *hw, struct dwc3_trb *nat)
+{
+ u64 bplh;
+
+ bplh = le32_to_cpup(&hw->bpl);
+ bplh |= (u64) le32_to_cpup(&hw->bph) << 32;
+ nat->bplh = bplh;
+
+ nat->len_pcm = le32_to_cpup(&hw->size);
+ nat->control = le32_to_cpup(&hw->ctrl);
+}
+
+/**
+ * dwc3_hwparams - copy of HWPARAMS registers
+ * @hwparams0 - GHWPARAMS0
+ * @hwparams1 - GHWPARAMS1
+ * @hwparams2 - GHWPARAMS2
+ * @hwparams3 - GHWPARAMS3
+ * @hwparams4 - GHWPARAMS4
+ * @hwparams5 - GHWPARAMS5
+ * @hwparams6 - GHWPARAMS6
+ * @hwparams7 - GHWPARAMS7
+ * @hwparams8 - GHWPARAMS8
+ */
+struct dwc3_hwparams {
+ u32 hwparams0;
+ u32 hwparams1;
+ u32 hwparams2;
+ u32 hwparams3;
+ u32 hwparams4;
+ u32 hwparams5;
+ u32 hwparams6;
+ u32 hwparams7;
+ u32 hwparams8;
+};
+
+/**
+ * struct dwc3 - representation of our controller
+ * @ctrl_req: usb control request which is used for ep0
+ * @ep0_trb: trb which is used for the ctrl_req
+ * @ep0_bounce: bounce buffer for ep0
+ * @setup_buf: used while precessing STD USB requests
+ * @ctrl_req_addr: dma address of ctrl_req
+ * @ep0_trb: dma address of ep0_trb
+ * @ep0_usb_req: dummy req used while handling STD USB requests
+ * @setup_buf_addr: dma address of setup_buf
+ * @ep0_bounce_addr: dma address of ep0_bounce
+ * @lock: for synchronizing
+ * @dev: pointer to our struct device
+ * @event_buffer_list: a list of event buffers
+ * @gadget: device side representation of the peripheral controller
+ * @gadget_driver: pointer to the gadget driver
+ * @regs: base address for our registers
+ * @regs_size: address space size
+ * @irq: IRQ number
+ * @revision: revision register contents
+ * @is_selfpowered: true when we are selfpowered
+ * @three_stage_setup: set if we perform a three phase setup
+ * @ep0_status_pending: ep0 status response without a req is pending
+ * @ep0_bounced: true when we used bounce buffer
+ * @ep0_expect_in: true when we expect a DATA IN transfer
+ * @start_config_issued: true when StartConfig command has been issued
+ * @ep0_next_event: hold the next expected event
+ * @ep0state: state of endpoint zero
+ * @link_state: link state
+ * @speed: device speed (super, high, full, low)
+ * @mem: points to start of memory which is used for this struct.
+ * @hwparams: copy of hwparams registers
+ * @root: debugfs root folder pointer
+ */
+struct dwc3 {
+ struct usb_ctrlrequest *ctrl_req;
+ struct dwc3_trb_hw *ep0_trb;
+ void *ep0_bounce;
+ u8 *setup_buf;
+ dma_addr_t ctrl_req_addr;
+ dma_addr_t ep0_trb_addr;
+ dma_addr_t setup_buf_addr;
+ dma_addr_t ep0_bounce_addr;
+ struct usb_request ep0_usb_req;
+ /* device lock */
+ spinlock_t lock;
+ struct device *dev;
+
+ struct dwc3_event_buffer *ev_buffs[DWC3_EVENT_BUFFERS_NUM];
+ struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM];
+
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *gadget_driver;
+
+ void __iomem *regs;
+ size_t regs_size;
+
+ int irq;
+
+ u32 revision;
+
+#define DWC3_REVISION_173A 0x5533173a
+#define DWC3_REVISION_175A 0x5533175a
+#define DWC3_REVISION_180A 0x5533180a
+#define DWC3_REVISION_183A 0x5533183a
+#define DWC3_REVISION_185A 0x5533185a
+#define DWC3_REVISION_188A 0x5533188a
+#define DWC3_REVISION_190A 0x5533190a
+
+ unsigned is_selfpowered:1;
+ unsigned three_stage_setup:1;
+ unsigned ep0_status_pending:1;
+ unsigned ep0_bounced:1;
+ unsigned ep0_expect_in:1;
+ unsigned start_config_issued:1;
+
+ enum dwc3_ep0_next ep0_next_event;
+ enum dwc3_ep0_state ep0state;
+ enum dwc3_link_state link_state;
+ enum dwc3_device_state dev_state;
+
+ u8 speed;
+ void *mem;
+
+ struct dwc3_hwparams hwparams;
+ struct dentry *root;
+};
+
+/* -------------------------------------------------------------------------- */
+
+#define DWC3_TRBSTS_OK 0
+#define DWC3_TRBSTS_MISSED_ISOC 1
+#define DWC3_TRBSTS_SETUP_PENDING 2
+
+#define DWC3_TRBCTL_NORMAL 1
+#define DWC3_TRBCTL_CONTROL_SETUP 2
+#define DWC3_TRBCTL_CONTROL_STATUS2 3
+#define DWC3_TRBCTL_CONTROL_STATUS3 4
+#define DWC3_TRBCTL_CONTROL_DATA 5
+#define DWC3_TRBCTL_ISOCHRONOUS_FIRST 6
+#define DWC3_TRBCTL_ISOCHRONOUS 7
+#define DWC3_TRBCTL_LINK_TRB 8
+
+/* -------------------------------------------------------------------------- */
+
+struct dwc3_event_type {
+ u32 is_devspec:1;
+ u32 type:6;
+ u32 reserved8_31:25;
+} __packed;
+
+#define DWC3_DEPEVT_XFERCOMPLETE 0x01
+#define DWC3_DEPEVT_XFERINPROGRESS 0x02
+#define DWC3_DEPEVT_XFERNOTREADY 0x03
+#define DWC3_DEPEVT_RXTXFIFOEVT 0x04
+#define DWC3_DEPEVT_STREAMEVT 0x06
+#define DWC3_DEPEVT_EPCMDCMPLT 0x07
+
+/**
+ * struct dwc3_event_depvt - Device Endpoint Events
+ * @one_bit: indicates this is an endpoint event (not used)
+ * @endpoint_number: number of the endpoint
+ * @endpoint_event: The event we have:
+ * 0x00 - Reserved
+ * 0x01 - XferComplete
+ * 0x02 - XferInProgress
+ * 0x03 - XferNotReady
+ * 0x04 - RxTxFifoEvt (IN->Underrun, OUT->Overrun)
+ * 0x05 - Reserved
+ * 0x06 - StreamEvt
+ * 0x07 - EPCmdCmplt
+ * @reserved11_10: Reserved, don't use.
+ * @status: Indicates the status of the event. Refer to databook for
+ * more information.
+ * @parameters: Parameters of the current event. Refer to databook for
+ * more information.
+ */
+struct dwc3_event_depevt {
+ u32 one_bit:1;
+ u32 endpoint_number:5;
+ u32 endpoint_event:4;
+ u32 reserved11_10:2;
+ u32 status:4;
+#define DEPEVT_STATUS_BUSERR (1 << 0)
+#define DEPEVT_STATUS_SHORT (1 << 1)
+#define DEPEVT_STATUS_IOC (1 << 2)
+#define DEPEVT_STATUS_LST (1 << 3)
+
+/* Stream event only */
+#define DEPEVT_STREAMEVT_FOUND 1
+#define DEPEVT_STREAMEVT_NOTFOUND 2
+
+/* Control-only Status */
+#define DEPEVT_STATUS_CONTROL_SETUP 0
+#define DEPEVT_STATUS_CONTROL_DATA 1
+#define DEPEVT_STATUS_CONTROL_STATUS 2
+
+ u32 parameters:16;
+} __packed;
+
+/**
+ * struct dwc3_event_devt - Device Events
+ * @one_bit: indicates this is a non-endpoint event (not used)
+ * @device_event: indicates it's a device event. Should read as 0x00
+ * @type: indicates the type of device event.
+ * 0 - DisconnEvt
+ * 1 - USBRst
+ * 2 - ConnectDone
+ * 3 - ULStChng
+ * 4 - WkUpEvt
+ * 5 - Reserved
+ * 6 - EOPF
+ * 7 - SOF
+ * 8 - Reserved
+ * 9 - ErrticErr
+ * 10 - CmdCmplt
+ * 11 - EvntOverflow
+ * 12 - VndrDevTstRcved
+ * @reserved15_12: Reserved, not used
+ * @event_info: Information about this event
+ * @reserved31_24: Reserved, not used
+ */
+struct dwc3_event_devt {
+ u32 one_bit:1;
+ u32 device_event:7;
+ u32 type:4;
+ u32 reserved15_12:4;
+ u32 event_info:8;
+ u32 reserved31_24:8;
+} __packed;
+
+/**
+ * struct dwc3_event_gevt - Other Core Events
+ * @one_bit: indicates this is a non-endpoint event (not used)
+ * @device_event: indicates it's (0x03) Carkit or (0x04) I2C event.
+ * @phy_port_number: self-explanatory
+ * @reserved31_12: Reserved, not used.
+ */
+struct dwc3_event_gevt {
+ u32 one_bit:1;
+ u32 device_event:7;
+ u32 phy_port_number:4;
+ u32 reserved31_12:20;
+} __packed;
+
+/**
+ * union dwc3_event - representation of Event Buffer contents
+ * @raw: raw 32-bit event
+ * @type: the type of the event
+ * @depevt: Device Endpoint Event
+ * @devt: Device Event
+ * @gevt: Global Event
+ */
+union dwc3_event {
+ u32 raw;
+ struct dwc3_event_type type;
+ struct dwc3_event_depevt depevt;
+ struct dwc3_event_devt devt;
+ struct dwc3_event_gevt gevt;
+};
+
+/*
+ * DWC3 Features to be used as Driver Data
+ */
+
+#define DWC3_HAS_PERIPHERAL BIT(0)
+#define DWC3_HAS_XHCI BIT(1)
+#define DWC3_HAS_OTG BIT(3)
+
+#endif /* __DRIVERS_USB_DWC3_CORE_H */
diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h
new file mode 100644
index 000000000000..5894ee8222af
--- /dev/null
+++ b/drivers/usb/dwc3/debug.h
@@ -0,0 +1,50 @@
+/**
+ * debug.h - DesignWare USB3 DRD Controller Debug Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * 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 "core.h"
+
+#ifdef CONFIG_DEBUG_FS
+extern int dwc3_debugfs_init(struct dwc3 *);
+extern void dwc3_debugfs_exit(struct dwc3 *);
+#else
+static inline int dwc3_debugfs_init(struct dwc3 *d)
+{ return 0; }
+static inline void dwc3_debugfs_exit(struct dwc3 *d)
+{ }
+#endif
+
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
new file mode 100644
index 000000000000..da1ad77d8d51
--- /dev/null
+++ b/drivers/usb/dwc3/debugfs.c
@@ -0,0 +1,441 @@
+/**
+ * debugfs.c - DesignWare USB3 DRD Controller DebugFS file
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * 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/kernel.h>
+#include <linux/slab.h>
+#include <linux/ptrace.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/delay.h>
+
+#include <asm/uaccess.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+struct dwc3_register {
+ const char *name;
+ u32 offset;
+};
+
+#define dump_register(nm) \
+{ \
+ .name = __stringify(nm), \
+ .offset = DWC3_ ##nm, \
+}
+
+static const struct dwc3_register dwc3_regs[] = {
+ dump_register(GSBUSCFG0),
+ dump_register(GSBUSCFG1),
+ dump_register(GTXTHRCFG),
+ dump_register(GRXTHRCFG),
+ dump_register(GCTL),
+ dump_register(GEVTEN),
+ dump_register(GSTS),
+ dump_register(GSNPSID),
+ dump_register(GGPIO),
+ dump_register(GUID),
+ dump_register(GUCTL),
+ dump_register(GBUSERRADDR0),
+ dump_register(GBUSERRADDR1),
+ dump_register(GPRTBIMAP0),
+ dump_register(GPRTBIMAP1),
+ dump_register(GHWPARAMS0),
+ dump_register(GHWPARAMS1),
+ dump_register(GHWPARAMS2),
+ dump_register(GHWPARAMS3),
+ dump_register(GHWPARAMS4),
+ dump_register(GHWPARAMS5),
+ dump_register(GHWPARAMS6),
+ dump_register(GHWPARAMS7),
+ dump_register(GDBGFIFOSPACE),
+ dump_register(GDBGLTSSM),
+ dump_register(GPRTBIMAP_HS0),
+ dump_register(GPRTBIMAP_HS1),
+ dump_register(GPRTBIMAP_FS0),
+ dump_register(GPRTBIMAP_FS1),
+
+ dump_register(GUSB2PHYCFG(0)),
+ dump_register(GUSB2PHYCFG(1)),
+ dump_register(GUSB2PHYCFG(2)),
+ dump_register(GUSB2PHYCFG(3)),
+ dump_register(GUSB2PHYCFG(4)),
+ dump_register(GUSB2PHYCFG(5)),
+ dump_register(GUSB2PHYCFG(6)),
+ dump_register(GUSB2PHYCFG(7)),
+ dump_register(GUSB2PHYCFG(8)),
+ dump_register(GUSB2PHYCFG(9)),
+ dump_register(GUSB2PHYCFG(10)),
+ dump_register(GUSB2PHYCFG(11)),
+ dump_register(GUSB2PHYCFG(12)),
+ dump_register(GUSB2PHYCFG(13)),
+ dump_register(GUSB2PHYCFG(14)),
+ dump_register(GUSB2PHYCFG(15)),
+
+ dump_register(GUSB2I2CCTL(0)),
+ dump_register(GUSB2I2CCTL(1)),
+ dump_register(GUSB2I2CCTL(2)),
+ dump_register(GUSB2I2CCTL(3)),
+ dump_register(GUSB2I2CCTL(4)),
+ dump_register(GUSB2I2CCTL(5)),
+ dump_register(GUSB2I2CCTL(6)),
+ dump_register(GUSB2I2CCTL(7)),
+ dump_register(GUSB2I2CCTL(8)),
+ dump_register(GUSB2I2CCTL(9)),
+ dump_register(GUSB2I2CCTL(10)),
+ dump_register(GUSB2I2CCTL(11)),
+ dump_register(GUSB2I2CCTL(12)),
+ dump_register(GUSB2I2CCTL(13)),
+ dump_register(GUSB2I2CCTL(14)),
+ dump_register(GUSB2I2CCTL(15)),
+
+ dump_register(GUSB2PHYACC(0)),
+ dump_register(GUSB2PHYACC(1)),
+ dump_register(GUSB2PHYACC(2)),
+ dump_register(GUSB2PHYACC(3)),
+ dump_register(GUSB2PHYACC(4)),
+ dump_register(GUSB2PHYACC(5)),
+ dump_register(GUSB2PHYACC(6)),
+ dump_register(GUSB2PHYACC(7)),
+ dump_register(GUSB2PHYACC(8)),
+ dump_register(GUSB2PHYACC(9)),
+ dump_register(GUSB2PHYACC(10)),
+ dump_register(GUSB2PHYACC(11)),
+ dump_register(GUSB2PHYACC(12)),
+ dump_register(GUSB2PHYACC(13)),
+ dump_register(GUSB2PHYACC(14)),
+ dump_register(GUSB2PHYACC(15)),
+
+ dump_register(GUSB3PIPECTL(0)),
+ dump_register(GUSB3PIPECTL(1)),
+ dump_register(GUSB3PIPECTL(2)),
+ dump_register(GUSB3PIPECTL(3)),
+ dump_register(GUSB3PIPECTL(4)),
+ dump_register(GUSB3PIPECTL(5)),
+ dump_register(GUSB3PIPECTL(6)),
+ dump_register(GUSB3PIPECTL(7)),
+ dump_register(GUSB3PIPECTL(8)),
+ dump_register(GUSB3PIPECTL(9)),
+ dump_register(GUSB3PIPECTL(10)),
+ dump_register(GUSB3PIPECTL(11)),
+ dump_register(GUSB3PIPECTL(12)),
+ dump_register(GUSB3PIPECTL(13)),
+ dump_register(GUSB3PIPECTL(14)),
+ dump_register(GUSB3PIPECTL(15)),
+
+ dump_register(GTXFIFOSIZ(0)),
+ dump_register(GTXFIFOSIZ(1)),
+ dump_register(GTXFIFOSIZ(2)),
+ dump_register(GTXFIFOSIZ(3)),
+ dump_register(GTXFIFOSIZ(4)),
+ dump_register(GTXFIFOSIZ(5)),
+ dump_register(GTXFIFOSIZ(6)),
+ dump_register(GTXFIFOSIZ(7)),
+ dump_register(GTXFIFOSIZ(8)),
+ dump_register(GTXFIFOSIZ(9)),
+ dump_register(GTXFIFOSIZ(10)),
+ dump_register(GTXFIFOSIZ(11)),
+ dump_register(GTXFIFOSIZ(12)),
+ dump_register(GTXFIFOSIZ(13)),
+ dump_register(GTXFIFOSIZ(14)),
+ dump_register(GTXFIFOSIZ(15)),
+ dump_register(GTXFIFOSIZ(16)),
+ dump_register(GTXFIFOSIZ(17)),
+ dump_register(GTXFIFOSIZ(18)),
+ dump_register(GTXFIFOSIZ(19)),
+ dump_register(GTXFIFOSIZ(20)),
+ dump_register(GTXFIFOSIZ(21)),
+ dump_register(GTXFIFOSIZ(22)),
+ dump_register(GTXFIFOSIZ(23)),
+ dump_register(GTXFIFOSIZ(24)),
+ dump_register(GTXFIFOSIZ(25)),
+ dump_register(GTXFIFOSIZ(26)),
+ dump_register(GTXFIFOSIZ(27)),
+ dump_register(GTXFIFOSIZ(28)),
+ dump_register(GTXFIFOSIZ(29)),
+ dump_register(GTXFIFOSIZ(30)),
+ dump_register(GTXFIFOSIZ(31)),
+
+ dump_register(GRXFIFOSIZ(0)),
+ dump_register(GRXFIFOSIZ(1)),
+ dump_register(GRXFIFOSIZ(2)),
+ dump_register(GRXFIFOSIZ(3)),
+ dump_register(GRXFIFOSIZ(4)),
+ dump_register(GRXFIFOSIZ(5)),
+ dump_register(GRXFIFOSIZ(6)),
+ dump_register(GRXFIFOSIZ(7)),
+ dump_register(GRXFIFOSIZ(8)),
+ dump_register(GRXFIFOSIZ(9)),
+ dump_register(GRXFIFOSIZ(10)),
+ dump_register(GRXFIFOSIZ(11)),
+ dump_register(GRXFIFOSIZ(12)),
+ dump_register(GRXFIFOSIZ(13)),
+ dump_register(GRXFIFOSIZ(14)),
+ dump_register(GRXFIFOSIZ(15)),
+ dump_register(GRXFIFOSIZ(16)),
+ dump_register(GRXFIFOSIZ(17)),
+ dump_register(GRXFIFOSIZ(18)),
+ dump_register(GRXFIFOSIZ(19)),
+ dump_register(GRXFIFOSIZ(20)),
+ dump_register(GRXFIFOSIZ(21)),
+ dump_register(GRXFIFOSIZ(22)),
+ dump_register(GRXFIFOSIZ(23)),
+ dump_register(GRXFIFOSIZ(24)),
+ dump_register(GRXFIFOSIZ(25)),
+ dump_register(GRXFIFOSIZ(26)),
+ dump_register(GRXFIFOSIZ(27)),
+ dump_register(GRXFIFOSIZ(28)),
+ dump_register(GRXFIFOSIZ(29)),
+ dump_register(GRXFIFOSIZ(30)),
+ dump_register(GRXFIFOSIZ(31)),
+
+ dump_register(GEVNTADRLO(0)),
+ dump_register(GEVNTADRHI(0)),
+ dump_register(GEVNTSIZ(0)),
+ dump_register(GEVNTCOUNT(0)),
+
+ dump_register(GHWPARAMS8),
+ dump_register(DCFG),
+ dump_register(DCTL),
+ dump_register(DEVTEN),
+ dump_register(DSTS),
+ dump_register(DGCMDPAR),
+ dump_register(DGCMD),
+ dump_register(DALEPENA),
+
+ dump_register(DEPCMDPAR2(0)),
+ dump_register(DEPCMDPAR2(1)),
+ dump_register(DEPCMDPAR2(2)),
+ dump_register(DEPCMDPAR2(3)),
+ dump_register(DEPCMDPAR2(4)),
+ dump_register(DEPCMDPAR2(5)),
+ dump_register(DEPCMDPAR2(6)),
+ dump_register(DEPCMDPAR2(7)),
+ dump_register(DEPCMDPAR2(8)),
+ dump_register(DEPCMDPAR2(9)),
+ dump_register(DEPCMDPAR2(10)),
+ dump_register(DEPCMDPAR2(11)),
+ dump_register(DEPCMDPAR2(12)),
+ dump_register(DEPCMDPAR2(13)),
+ dump_register(DEPCMDPAR2(14)),
+ dump_register(DEPCMDPAR2(15)),
+ dump_register(DEPCMDPAR2(16)),
+ dump_register(DEPCMDPAR2(17)),
+ dump_register(DEPCMDPAR2(18)),
+ dump_register(DEPCMDPAR2(19)),
+ dump_register(DEPCMDPAR2(20)),
+ dump_register(DEPCMDPAR2(21)),
+ dump_register(DEPCMDPAR2(22)),
+ dump_register(DEPCMDPAR2(23)),
+ dump_register(DEPCMDPAR2(24)),
+ dump_register(DEPCMDPAR2(25)),
+ dump_register(DEPCMDPAR2(26)),
+ dump_register(DEPCMDPAR2(27)),
+ dump_register(DEPCMDPAR2(28)),
+ dump_register(DEPCMDPAR2(29)),
+ dump_register(DEPCMDPAR2(30)),
+ dump_register(DEPCMDPAR2(31)),
+
+ dump_register(DEPCMDPAR1(0)),
+ dump_register(DEPCMDPAR1(1)),
+ dump_register(DEPCMDPAR1(2)),
+ dump_register(DEPCMDPAR1(3)),
+ dump_register(DEPCMDPAR1(4)),
+ dump_register(DEPCMDPAR1(5)),
+ dump_register(DEPCMDPAR1(6)),
+ dump_register(DEPCMDPAR1(7)),
+ dump_register(DEPCMDPAR1(8)),
+ dump_register(DEPCMDPAR1(9)),
+ dump_register(DEPCMDPAR1(10)),
+ dump_register(DEPCMDPAR1(11)),
+ dump_register(DEPCMDPAR1(12)),
+ dump_register(DEPCMDPAR1(13)),
+ dump_register(DEPCMDPAR1(14)),
+ dump_register(DEPCMDPAR1(15)),
+ dump_register(DEPCMDPAR1(16)),
+ dump_register(DEPCMDPAR1(17)),
+ dump_register(DEPCMDPAR1(18)),
+ dump_register(DEPCMDPAR1(19)),
+ dump_register(DEPCMDPAR1(20)),
+ dump_register(DEPCMDPAR1(21)),
+ dump_register(DEPCMDPAR1(22)),
+ dump_register(DEPCMDPAR1(23)),
+ dump_register(DEPCMDPAR1(24)),
+ dump_register(DEPCMDPAR1(25)),
+ dump_register(DEPCMDPAR1(26)),
+ dump_register(DEPCMDPAR1(27)),
+ dump_register(DEPCMDPAR1(28)),
+ dump_register(DEPCMDPAR1(29)),
+ dump_register(DEPCMDPAR1(30)),
+ dump_register(DEPCMDPAR1(31)),
+
+ dump_register(DEPCMDPAR0(0)),
+ dump_register(DEPCMDPAR0(1)),
+ dump_register(DEPCMDPAR0(2)),
+ dump_register(DEPCMDPAR0(3)),
+ dump_register(DEPCMDPAR0(4)),
+ dump_register(DEPCMDPAR0(5)),
+ dump_register(DEPCMDPAR0(6)),
+ dump_register(DEPCMDPAR0(7)),
+ dump_register(DEPCMDPAR0(8)),
+ dump_register(DEPCMDPAR0(9)),
+ dump_register(DEPCMDPAR0(10)),
+ dump_register(DEPCMDPAR0(11)),
+ dump_register(DEPCMDPAR0(12)),
+ dump_register(DEPCMDPAR0(13)),
+ dump_register(DEPCMDPAR0(14)),
+ dump_register(DEPCMDPAR0(15)),
+ dump_register(DEPCMDPAR0(16)),
+ dump_register(DEPCMDPAR0(17)),
+ dump_register(DEPCMDPAR0(18)),
+ dump_register(DEPCMDPAR0(19)),
+ dump_register(DEPCMDPAR0(20)),
+ dump_register(DEPCMDPAR0(21)),
+ dump_register(DEPCMDPAR0(22)),
+ dump_register(DEPCMDPAR0(23)),
+ dump_register(DEPCMDPAR0(24)),
+ dump_register(DEPCMDPAR0(25)),
+ dump_register(DEPCMDPAR0(26)),
+ dump_register(DEPCMDPAR0(27)),
+ dump_register(DEPCMDPAR0(28)),
+ dump_register(DEPCMDPAR0(29)),
+ dump_register(DEPCMDPAR0(30)),
+ dump_register(DEPCMDPAR0(31)),
+
+ dump_register(DEPCMD(0)),
+ dump_register(DEPCMD(1)),
+ dump_register(DEPCMD(2)),
+ dump_register(DEPCMD(3)),
+ dump_register(DEPCMD(4)),
+ dump_register(DEPCMD(5)),
+ dump_register(DEPCMD(6)),
+ dump_register(DEPCMD(7)),
+ dump_register(DEPCMD(8)),
+ dump_register(DEPCMD(9)),
+ dump_register(DEPCMD(10)),
+ dump_register(DEPCMD(11)),
+ dump_register(DEPCMD(12)),
+ dump_register(DEPCMD(13)),
+ dump_register(DEPCMD(14)),
+ dump_register(DEPCMD(15)),
+ dump_register(DEPCMD(16)),
+ dump_register(DEPCMD(17)),
+ dump_register(DEPCMD(18)),
+ dump_register(DEPCMD(19)),
+ dump_register(DEPCMD(20)),
+ dump_register(DEPCMD(21)),
+ dump_register(DEPCMD(22)),
+ dump_register(DEPCMD(23)),
+ dump_register(DEPCMD(24)),
+ dump_register(DEPCMD(25)),
+ dump_register(DEPCMD(26)),
+ dump_register(DEPCMD(27)),
+ dump_register(DEPCMD(28)),
+ dump_register(DEPCMD(29)),
+ dump_register(DEPCMD(30)),
+ dump_register(DEPCMD(31)),
+
+ dump_register(OCFG),
+ dump_register(OCTL),
+ dump_register(OEVTEN),
+ dump_register(OSTS),
+};
+
+static int dwc3_regdump_show(struct seq_file *s, void *unused)
+{
+ struct dwc3 *dwc = s->private;
+ int i;
+
+ seq_printf(s, "DesignWare USB3 Core Register Dump\n");
+
+ for (i = 0; i < ARRAY_SIZE(dwc3_regs); i++) {
+ seq_printf(s, "%-20s : %08x\n", dwc3_regs[i].name,
+ dwc3_readl(dwc->regs, dwc3_regs[i].offset));
+ }
+
+ return 0;
+}
+
+static int dwc3_regdump_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dwc3_regdump_show, inode->i_private);
+}
+
+static const struct file_operations dwc3_regdump_fops = {
+ .open = dwc3_regdump_open,
+ .read = seq_read,
+ .release = single_release,
+};
+
+int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
+{
+ struct dentry *root;
+ struct dentry *file;
+ int ret;
+
+ root = debugfs_create_dir(dev_name(dwc->dev), NULL);
+ if (IS_ERR(root)){
+ ret = PTR_ERR(root);
+ goto err0;
+ }
+
+ dwc->root = root;
+
+ file = debugfs_create_file("regdump", S_IRUGO, root, dwc,
+ &dwc3_regdump_fops);
+ if (IS_ERR(file)) {
+ ret = PTR_ERR(file);
+ goto err1;
+ }
+ return 0;
+
+err1:
+ debugfs_remove_recursive(root);
+
+err0:
+ return ret;
+}
+
+void __devexit dwc3_debugfs_exit(struct dwc3 *dwc)
+{
+ debugfs_remove_recursive(dwc->root);
+ dwc->root = NULL;
+}
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
new file mode 100644
index 000000000000..062552b5fc8a
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -0,0 +1,401 @@
+/**
+ * dwc3-omap.c - OMAP Specific Glue layer
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/dwc3-omap.h>
+#include <linux/dma-mapping.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/module.h>
+
+#include "io.h"
+
+/*
+ * All these registers belong to OMAP's Wrapper around the
+ * DesignWare USB3 Core.
+ */
+
+#define USBOTGSS_REVISION 0x0000
+#define USBOTGSS_SYSCONFIG 0x0010
+#define USBOTGSS_IRQ_EOI 0x0020
+#define USBOTGSS_IRQSTATUS_RAW_0 0x0024
+#define USBOTGSS_IRQSTATUS_0 0x0028
+#define USBOTGSS_IRQENABLE_SET_0 0x002c
+#define USBOTGSS_IRQENABLE_CLR_0 0x0030
+#define USBOTGSS_IRQSTATUS_RAW_1 0x0034
+#define USBOTGSS_IRQSTATUS_1 0x0038
+#define USBOTGSS_IRQENABLE_SET_1 0x003c
+#define USBOTGSS_IRQENABLE_CLR_1 0x0040
+#define USBOTGSS_UTMI_OTG_CTRL 0x0080
+#define USBOTGSS_UTMI_OTG_STATUS 0x0084
+#define USBOTGSS_MMRAM_OFFSET 0x0100
+#define USBOTGSS_FLADJ 0x0104
+#define USBOTGSS_DEBUG_CFG 0x0108
+#define USBOTGSS_DEBUG_DATA 0x010c
+
+/* SYSCONFIG REGISTER */
+#define USBOTGSS_SYSCONFIG_DMADISABLE (1 << 16)
+#define USBOTGSS_SYSCONFIG_STANDBYMODE(x) ((x) << 4)
+
+#define USBOTGSS_STANDBYMODE_FORCE_STANDBY 0
+#define USBOTGSS_STANDBYMODE_NO_STANDBY 1
+#define USBOTGSS_STANDBYMODE_SMART_STANDBY 2
+#define USBOTGSS_STANDBYMODE_SMART_WAKEUP 3
+
+#define USBOTGSS_STANDBYMODE_MASK (0x03 << 4)
+
+#define USBOTGSS_SYSCONFIG_IDLEMODE(x) ((x) << 2)
+
+#define USBOTGSS_IDLEMODE_FORCE_IDLE 0
+#define USBOTGSS_IDLEMODE_NO_IDLE 1
+#define USBOTGSS_IDLEMODE_SMART_IDLE 2
+#define USBOTGSS_IDLEMODE_SMART_WAKEUP 3
+
+#define USBOTGSS_IDLEMODE_MASK (0x03 << 2)
+
+/* IRQ_EOI REGISTER */
+#define USBOTGSS_IRQ_EOI_LINE_NUMBER (1 << 0)
+
+/* IRQS0 BITS */
+#define USBOTGSS_IRQO_COREIRQ_ST (1 << 0)
+
+/* IRQ1 BITS */
+#define USBOTGSS_IRQ1_DMADISABLECLR (1 << 17)
+#define USBOTGSS_IRQ1_OEVT (1 << 16)
+#define USBOTGSS_IRQ1_DRVVBUS_RISE (1 << 13)
+#define USBOTGSS_IRQ1_CHRGVBUS_RISE (1 << 12)
+#define USBOTGSS_IRQ1_DISCHRGVBUS_RISE (1 << 11)
+#define USBOTGSS_IRQ1_IDPULLUP_RISE (1 << 8)
+#define USBOTGSS_IRQ1_DRVVBUS_FALL (1 << 5)
+#define USBOTGSS_IRQ1_CHRGVBUS_FALL (1 << 4)
+#define USBOTGSS_IRQ1_DISCHRGVBUS_FALL (1 << 3)
+#define USBOTGSS_IRQ1_IDPULLUP_FALL (1 << 0)
+
+/* UTMI_OTG_CTRL REGISTER */
+#define USBOTGSS_UTMI_OTG_CTRL_DRVVBUS (1 << 5)
+#define USBOTGSS_UTMI_OTG_CTRL_CHRGVBUS (1 << 4)
+#define USBOTGSS_UTMI_OTG_CTRL_DISCHRGVBUS (1 << 3)
+#define USBOTGSS_UTMI_OTG_CTRL_IDPULLUP (1 << 0)
+
+/* UTMI_OTG_STATUS REGISTER */
+#define USBOTGSS_UTMI_OTG_STATUS_SW_MODE (1 << 31)
+#define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT (1 << 9)
+#define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE (1 << 8)
+#define USBOTGSS_UTMI_OTG_STATUS_IDDIG (1 << 4)
+#define USBOTGSS_UTMI_OTG_STATUS_SESSEND (1 << 3)
+#define USBOTGSS_UTMI_OTG_STATUS_SESSVALID (1 << 2)
+#define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID (1 << 1)
+
+struct dwc3_omap {
+ /* device lock */
+ spinlock_t lock;
+
+ struct platform_device *dwc3;
+ struct device *dev;
+
+ int irq;
+ void __iomem *base;
+
+ void *context;
+ u32 resource_size;
+
+ u32 dma_status:1;
+};
+
+static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
+{
+ struct dwc3_omap *omap = _omap;
+ u32 reg;
+
+ spin_lock(&omap->lock);
+
+ reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_1);
+
+ if (reg & USBOTGSS_IRQ1_DMADISABLECLR) {
+ dev_dbg(omap->dev, "DMA Disable was Cleared\n");
+ omap->dma_status = false;
+ }
+
+ if (reg & USBOTGSS_IRQ1_OEVT)
+ dev_dbg(omap->dev, "OTG Event\n");
+
+ if (reg & USBOTGSS_IRQ1_DRVVBUS_RISE)
+ dev_dbg(omap->dev, "DRVVBUS Rise\n");
+
+ if (reg & USBOTGSS_IRQ1_CHRGVBUS_RISE)
+ dev_dbg(omap->dev, "CHRGVBUS Rise\n");
+
+ if (reg & USBOTGSS_IRQ1_DISCHRGVBUS_RISE)
+ dev_dbg(omap->dev, "DISCHRGVBUS Rise\n");
+
+ if (reg & USBOTGSS_IRQ1_IDPULLUP_RISE)
+ dev_dbg(omap->dev, "IDPULLUP Rise\n");
+
+ if (reg & USBOTGSS_IRQ1_DRVVBUS_FALL)
+ dev_dbg(omap->dev, "DRVVBUS Fall\n");
+
+ if (reg & USBOTGSS_IRQ1_CHRGVBUS_FALL)
+ dev_dbg(omap->dev, "CHRGVBUS Fall\n");
+
+ if (reg & USBOTGSS_IRQ1_DISCHRGVBUS_FALL)
+ dev_dbg(omap->dev, "DISCHRGVBUS Fall\n");
+
+ if (reg & USBOTGSS_IRQ1_IDPULLUP_FALL)
+ dev_dbg(omap->dev, "IDPULLUP Fall\n");
+
+ dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg);
+
+ reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_0);
+ dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg);
+
+ spin_unlock(&omap->lock);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit dwc3_omap_probe(struct platform_device *pdev)
+{
+ struct dwc3_omap_data *pdata = pdev->dev.platform_data;
+ struct platform_device *dwc3;
+ struct dwc3_omap *omap;
+ struct resource *res;
+
+ int ret = -ENOMEM;
+ int irq;
+
+ u32 reg;
+
+ void __iomem *base;
+ void *context;
+
+ omap = kzalloc(sizeof(*omap), GFP_KERNEL);
+ if (!omap) {
+ dev_err(&pdev->dev, "not enough memory\n");
+ goto err0;
+ }
+
+ platform_set_drvdata(pdev, omap);
+
+ irq = platform_get_irq(pdev, 1);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "missing IRQ resource\n");
+ ret = -EINVAL;
+ goto err1;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res) {
+ dev_err(&pdev->dev, "missing memory base resource\n");
+ ret = -EINVAL;
+ goto err1;
+ }
+
+ base = ioremap_nocache(res->start, resource_size(res));
+ if (!base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ goto err1;
+ }
+
+ dwc3 = platform_device_alloc("dwc3-omap", -1);
+ if (!dwc3) {
+ dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
+ goto err2;
+ }
+
+ context = kzalloc(resource_size(res), GFP_KERNEL);
+ if (!context) {
+ dev_err(&pdev->dev, "couldn't allocate dwc3 context memory\n");
+ goto err3;
+ }
+
+ spin_lock_init(&omap->lock);
+ dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
+
+ dwc3->dev.parent = &pdev->dev;
+ dwc3->dev.dma_mask = pdev->dev.dma_mask;
+ dwc3->dev.dma_parms = pdev->dev.dma_parms;
+ omap->resource_size = resource_size(res);
+ omap->context = context;
+ omap->dev = &pdev->dev;
+ omap->irq = irq;
+ omap->base = base;
+ omap->dwc3 = dwc3;
+
+ reg = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
+
+ if (!pdata) {
+ dev_dbg(&pdev->dev, "missing platform data\n");
+ } else {
+ switch (pdata->utmi_mode) {
+ case DWC3_OMAP_UTMI_MODE_SW:
+ reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+ break;
+ case DWC3_OMAP_UTMI_MODE_HW:
+ reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+ break;
+ default:
+ dev_dbg(&pdev->dev, "UNKNOWN utmi mode %d\n",
+ pdata->utmi_mode);
+ }
+ }
+
+ dwc3_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
+
+ /* check the DMA Status */
+ reg = dwc3_readl(omap->base, USBOTGSS_SYSCONFIG);
+ omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
+
+ /* Set No-Idle and No-Standby */
+ reg &= ~(USBOTGSS_STANDBYMODE_MASK
+ | USBOTGSS_IDLEMODE_MASK);
+
+ reg |= (USBOTGSS_SYSCONFIG_STANDBYMODE(USBOTGSS_STANDBYMODE_NO_STANDBY)
+ | USBOTGSS_SYSCONFIG_IDLEMODE(USBOTGSS_IDLEMODE_NO_IDLE));
+
+ dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
+
+ ret = request_irq(omap->irq, dwc3_omap_interrupt, 0,
+ "dwc3-omap", omap);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request IRQ #%d --> %d\n",
+ omap->irq, ret);
+ goto err4;
+ }
+
+ /* enable all IRQs */
+ reg = USBOTGSS_IRQO_COREIRQ_ST;
+ dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
+
+ reg = (USBOTGSS_IRQ1_OEVT |
+ USBOTGSS_IRQ1_DRVVBUS_RISE |
+ USBOTGSS_IRQ1_CHRGVBUS_RISE |
+ USBOTGSS_IRQ1_DISCHRGVBUS_RISE |
+ USBOTGSS_IRQ1_IDPULLUP_RISE |
+ USBOTGSS_IRQ1_DRVVBUS_FALL |
+ USBOTGSS_IRQ1_CHRGVBUS_FALL |
+ USBOTGSS_IRQ1_DISCHRGVBUS_FALL |
+ USBOTGSS_IRQ1_IDPULLUP_FALL);
+
+ dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
+
+ ret = platform_device_add_resources(dwc3, pdev->resource,
+ pdev->num_resources);
+ if (ret) {
+ dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
+ goto err5;
+ }
+
+ ret = platform_device_add(dwc3);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register dwc3 device\n");
+ goto err5;
+ }
+
+ return 0;
+
+err5:
+ free_irq(omap->irq, omap);
+
+err4:
+ kfree(omap->context);
+
+err3:
+ platform_device_put(dwc3);
+
+err2:
+ iounmap(base);
+
+err1:
+ kfree(omap);
+
+err0:
+ return ret;
+}
+
+static int __devexit dwc3_omap_remove(struct platform_device *pdev)
+{
+ struct dwc3_omap *omap = platform_get_drvdata(pdev);
+
+ platform_device_unregister(omap->dwc3);
+
+ free_irq(omap->irq, omap);
+ iounmap(omap->base);
+
+ kfree(omap->context);
+ kfree(omap);
+
+ return 0;
+}
+
+static const struct of_device_id of_dwc3_matach[] = {
+ {
+ "ti,dwc3",
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, of_dwc3_matach);
+
+static struct platform_driver dwc3_omap_driver = {
+ .probe = dwc3_omap_probe,
+ .remove = __devexit_p(dwc3_omap_remove),
+ .driver = {
+ .name = "omap-dwc3",
+ .of_match_table = of_dwc3_matach,
+ },
+};
+
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("DesignWare USB3 OMAP Glue Layer");
+
+static int __devinit dwc3_omap_init(void)
+{
+ return platform_driver_register(&dwc3_omap_driver);
+}
+module_init(dwc3_omap_init);
+
+static void __exit dwc3_omap_exit(void)
+{
+ platform_driver_unregister(&dwc3_omap_driver);
+}
+module_exit(dwc3_omap_exit);
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
new file mode 100644
index 000000000000..f77c00042685
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -0,0 +1,219 @@
+/**
+ * dwc3-pci.c - PCI Specific glue layer
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+/* FIXME define these in <linux/pci_ids.h> */
+#define PCI_VENDOR_ID_SYNOPSYS 0x16c3
+#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
+
+#define DWC3_PCI_DEVS_POSSIBLE 32
+
+struct dwc3_pci {
+ struct device *dev;
+ struct platform_device *dwc3;
+};
+
+static DECLARE_BITMAP(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
+
+static int dwc3_pci_get_device_id(struct dwc3_pci *glue)
+{
+ int id;
+
+again:
+ id = find_first_zero_bit(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
+ if (id < DWC3_PCI_DEVS_POSSIBLE) {
+ int old;
+
+ old = test_and_set_bit(id, dwc3_pci_devs);
+ if (old)
+ goto again;
+ } else {
+ dev_err(glue->dev, "no space for new device\n");
+ id = -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void dwc3_pci_put_device_id(struct dwc3_pci *glue, int id)
+{
+ int ret;
+
+ if (id < 0)
+ return;
+
+ ret = test_bit(id, dwc3_pci_devs);
+ WARN(!ret, "Device: %s\nID %d not in use\n",
+ dev_driver_string(glue->dev), id);
+ clear_bit(id, dwc3_pci_devs);
+}
+
+static int __devinit dwc3_pci_probe(struct pci_dev *pci,
+ const struct pci_device_id *id)
+{
+ struct resource res[2];
+ struct platform_device *dwc3;
+ struct dwc3_pci *glue;
+ int ret = -ENOMEM;
+ int devid;
+
+ glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ if (!glue) {
+ dev_err(&pci->dev, "not enough memory\n");
+ goto err0;
+ }
+
+ glue->dev = &pci->dev;
+
+ ret = pci_enable_device(pci);
+ if (ret) {
+ dev_err(&pci->dev, "failed to enable pci device\n");
+ goto err1;
+ }
+
+ pci_set_power_state(pci, PCI_D0);
+ pci_set_master(pci);
+
+ devid = dwc3_pci_get_device_id(glue);
+ if (devid < 0)
+ goto err2;
+
+ dwc3 = platform_device_alloc("dwc3-pci", devid);
+ if (!dwc3) {
+ dev_err(&pci->dev, "couldn't allocate dwc3 device\n");
+ goto err3;
+ }
+
+ memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
+
+ res[0].start = pci_resource_start(pci, 0);
+ res[0].end = pci_resource_end(pci, 0);
+ res[0].name = "dwc_usb3";
+ res[0].flags = IORESOURCE_MEM;
+
+ res[1].start = pci->irq;
+ res[1].name = "dwc_usb3";
+ res[1].flags = IORESOURCE_IRQ;
+
+ ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
+ if (ret) {
+ dev_err(&pci->dev, "couldn't add resources to dwc3 device\n");
+ goto err4;
+ }
+
+ pci_set_drvdata(pci, glue);
+
+ dma_set_coherent_mask(&dwc3->dev, pci->dev.coherent_dma_mask);
+
+ dwc3->dev.dma_mask = pci->dev.dma_mask;
+ dwc3->dev.dma_parms = pci->dev.dma_parms;
+ dwc3->dev.parent = &pci->dev;
+ glue->dwc3 = dwc3;
+
+ ret = platform_device_add(dwc3);
+ if (ret) {
+ dev_err(&pci->dev, "failed to register dwc3 device\n");
+ goto err4;
+ }
+
+ return 0;
+
+err4:
+ pci_set_drvdata(pci, NULL);
+ platform_device_put(dwc3);
+
+err3:
+ dwc3_pci_put_device_id(glue, devid);
+
+err2:
+ pci_disable_device(pci);
+
+err1:
+ kfree(pci);
+
+err0:
+ return ret;
+}
+
+static void __devexit dwc3_pci_remove(struct pci_dev *pci)
+{
+ struct dwc3_pci *glue = pci_get_drvdata(pci);
+
+ dwc3_pci_put_device_id(glue, glue->dwc3->id);
+ platform_device_unregister(glue->dwc3);
+ pci_set_drvdata(pci, NULL);
+ pci_disable_device(pci);
+ kfree(glue);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
+ PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
+ },
+ { } /* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
+
+static struct pci_driver dwc3_pci_driver = {
+ .name = "pci-dwc3",
+ .id_table = dwc3_pci_id_table,
+ .probe = dwc3_pci_probe,
+ .remove = __devexit_p(dwc3_pci_remove),
+};
+
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");
+
+static int __devinit dwc3_pci_init(void)
+{
+ return pci_register_driver(&dwc3_pci_driver);
+}
+module_init(dwc3_pci_init);
+
+static void __exit dwc3_pci_exit(void)
+{
+ pci_unregister_driver(&dwc3_pci_driver);
+}
+module_exit(dwc3_pci_exit);
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
new file mode 100644
index 000000000000..69a4e43ddf59
--- /dev/null
+++ b/drivers/usb/dwc3/ep0.c
@@ -0,0 +1,804 @@
+/**
+ * ep0.c - DesignWare USB3 DRD Controller Endpoint 0 Handling
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * 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/kernel.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
+ const struct dwc3_event_depevt *event);
+
+static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
+{
+ switch (state) {
+ case EP0_UNCONNECTED:
+ return "Unconnected";
+ case EP0_SETUP_PHASE:
+ return "Setup Phase";
+ case EP0_DATA_PHASE:
+ return "Data Phase";
+ case EP0_STATUS_PHASE:
+ return "Status Phase";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
+ u32 len, u32 type)
+{
+ struct dwc3_gadget_ep_cmd_params params;
+ struct dwc3_trb_hw *trb_hw;
+ struct dwc3_trb trb;
+ struct dwc3_ep *dep;
+
+ int ret;
+
+ dep = dwc->eps[epnum];
+ if (dep->flags & DWC3_EP_BUSY) {
+ dev_vdbg(dwc->dev, "%s: still busy\n", dep->name);
+ return 0;
+ }
+
+ trb_hw = dwc->ep0_trb;
+ memset(&trb, 0, sizeof(trb));
+
+ trb.trbctl = type;
+ trb.bplh = buf_dma;
+ trb.length = len;
+
+ trb.hwo = 1;
+ trb.lst = 1;
+ trb.ioc = 1;
+ trb.isp_imi = 1;
+
+ dwc3_trb_to_hw(&trb, trb_hw);
+
+ memset(&params, 0, sizeof(params));
+ params.param0 = upper_32_bits(dwc->ep0_trb_addr);
+ params.param1 = lower_32_bits(dwc->ep0_trb_addr);
+
+ ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+ DWC3_DEPCMD_STARTTRANSFER, &params);
+ if (ret < 0) {
+ dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n");
+ return ret;
+ }
+
+ dep->flags |= DWC3_EP_BUSY;
+ dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
+ dep->number);
+
+ dwc->ep0_next_event = DWC3_EP0_COMPLETE;
+
+ return 0;
+}
+
+static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
+ struct dwc3_request *req)
+{
+ int ret = 0;
+
+ req->request.actual = 0;
+ req->request.status = -EINPROGRESS;
+ req->epnum = dep->number;
+
+ list_add_tail(&req->list, &dep->request_list);
+
+ /*
+ * Gadget driver might not be quick enough to queue a request
+ * before we get a Transfer Not Ready event on this endpoint.
+ *
+ * In that case, we will set DWC3_EP_PENDING_REQUEST. When that
+ * flag is set, it's telling us that as soon as Gadget queues the
+ * required request, we should kick the transfer here because the
+ * IRQ we were waiting for is long gone.
+ */
+ if (dep->flags & DWC3_EP_PENDING_REQUEST) {
+ struct dwc3 *dwc = dep->dwc;
+ unsigned direction;
+ u32 type;
+
+ direction = !!(dep->flags & DWC3_EP0_DIR_IN);
+
+ if (dwc->ep0state == EP0_STATUS_PHASE) {
+ type = dwc->three_stage_setup
+ ? DWC3_TRBCTL_CONTROL_STATUS3
+ : DWC3_TRBCTL_CONTROL_STATUS2;
+ } else if (dwc->ep0state == EP0_DATA_PHASE) {
+ type = DWC3_TRBCTL_CONTROL_DATA;
+ } else {
+ /* should never happen */
+ WARN_ON(1);
+ return 0;
+ }
+
+ ret = dwc3_ep0_start_trans(dwc, direction,
+ req->request.dma, req->request.length, type);
+ dep->flags &= ~(DWC3_EP_PENDING_REQUEST |
+ DWC3_EP0_DIR_IN);
+ }
+
+ return ret;
+}
+
+int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
+ gfp_t gfp_flags)
+{
+ struct dwc3_request *req = to_dwc3_request(request);
+ struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
+
+ unsigned long flags;
+
+ int ret;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ if (!dep->desc) {
+ dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
+ request, dep->name);
+ ret = -ESHUTDOWN;
+ goto out;
+ }
+
+ /* we share one TRB for ep0/1 */
+ if (!list_empty(&dwc->eps[0]->request_list) ||
+ !list_empty(&dwc->eps[1]->request_list) ||
+ dwc->ep0_status_pending) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ dev_vdbg(dwc->dev, "queueing request %p to %s length %d, state '%s'\n",
+ request, dep->name, request->length,
+ dwc3_ep0_state_string(dwc->ep0state));
+
+ ret = __dwc3_gadget_ep0_queue(dep, req);
+
+out:
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
+static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
+{
+ struct dwc3_ep *dep = dwc->eps[0];
+
+ /* stall is always issued on EP0 */
+ __dwc3_gadget_ep_set_halt(dwc->eps[0], 1);
+ dwc->eps[0]->flags = DWC3_EP_ENABLED;
+
+ if (!list_empty(&dep->request_list)) {
+ struct dwc3_request *req;
+
+ req = next_request(&dep->request_list);
+ dwc3_gadget_giveback(dep, req, -ECONNRESET);
+ }
+
+ dwc->ep0state = EP0_SETUP_PHASE;
+ dwc3_ep0_out_start(dwc);
+}
+
+void dwc3_ep0_out_start(struct dwc3 *dwc)
+{
+ int ret;
+
+ ret = dwc3_ep0_start_trans(dwc, 0, dwc->ctrl_req_addr, 8,
+ DWC3_TRBCTL_CONTROL_SETUP);
+ WARN_ON(ret < 0);
+}
+
+static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le)
+{
+ struct dwc3_ep *dep;
+ u32 windex = le16_to_cpu(wIndex_le);
+ u32 epnum;
+
+ epnum = (windex & USB_ENDPOINT_NUMBER_MASK) << 1;
+ if ((windex & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
+ epnum |= 1;
+
+ dep = dwc->eps[epnum];
+ if (dep->flags & DWC3_EP_ENABLED)
+ return dep;
+
+ return NULL;
+}
+
+static void dwc3_ep0_send_status_response(struct dwc3 *dwc)
+{
+ dwc3_ep0_start_trans(dwc, 1, dwc->setup_buf_addr,
+ dwc->ep0_usb_req.length,
+ DWC3_TRBCTL_CONTROL_DATA);
+}
+
+/*
+ * ch 9.4.5
+ */
+static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+ struct dwc3_ep *dep;
+ u32 recip;
+ u16 usb_status = 0;
+ __le16 *response_pkt;
+
+ recip = ctrl->bRequestType & USB_RECIP_MASK;
+ switch (recip) {
+ case USB_RECIP_DEVICE:
+ /*
+ * We are self-powered. U1/U2/LTM will be set later
+ * once we handle this states. RemoteWakeup is 0 on SS
+ */
+ usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED;
+ break;
+
+ case USB_RECIP_INTERFACE:
+ /*
+ * Function Remote Wake Capable D0
+ * Function Remote Wakeup D1
+ */
+ break;
+
+ case USB_RECIP_ENDPOINT:
+ dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
+ if (!dep)
+ return -EINVAL;
+
+ if (dep->flags & DWC3_EP_STALL)
+ usb_status = 1 << USB_ENDPOINT_HALT;
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ response_pkt = (__le16 *) dwc->setup_buf;
+ *response_pkt = cpu_to_le16(usb_status);
+ dwc->ep0_usb_req.length = sizeof(*response_pkt);
+ dwc->ep0_status_pending = 1;
+
+ return 0;
+}
+
+static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
+ struct usb_ctrlrequest *ctrl, int set)
+{
+ struct dwc3_ep *dep;
+ u32 recip;
+ u32 wValue;
+ u32 wIndex;
+ u32 reg;
+ int ret;
+ u32 mode;
+
+ wValue = le16_to_cpu(ctrl->wValue);
+ wIndex = le16_to_cpu(ctrl->wIndex);
+ recip = ctrl->bRequestType & USB_RECIP_MASK;
+ switch (recip) {
+ case USB_RECIP_DEVICE:
+
+ /*
+ * 9.4.1 says only only for SS, in AddressState only for
+ * default control pipe
+ */
+ switch (wValue) {
+ case USB_DEVICE_U1_ENABLE:
+ case USB_DEVICE_U2_ENABLE:
+ case USB_DEVICE_LTM_ENABLE:
+ if (dwc->dev_state != DWC3_CONFIGURED_STATE)
+ return -EINVAL;
+ if (dwc->speed != DWC3_DSTS_SUPERSPEED)
+ return -EINVAL;
+ }
+
+ /* XXX add U[12] & LTM */
+ switch (wValue) {
+ case USB_DEVICE_REMOTE_WAKEUP:
+ break;
+ case USB_DEVICE_U1_ENABLE:
+ break;
+ case USB_DEVICE_U2_ENABLE:
+ break;
+ case USB_DEVICE_LTM_ENABLE:
+ break;
+
+ case USB_DEVICE_TEST_MODE:
+ if ((wIndex & 0xff) != 0)
+ return -EINVAL;
+ if (!set)
+ return -EINVAL;
+
+ mode = wIndex >> 8;
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ reg &= ~DWC3_DCTL_TSTCTRL_MASK;
+
+ switch (mode) {
+ case TEST_J:
+ case TEST_K:
+ case TEST_SE0_NAK:
+ case TEST_PACKET:
+ case TEST_FORCE_EN:
+ reg |= mode << 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ case USB_RECIP_INTERFACE:
+ switch (wValue) {
+ case USB_INTRF_FUNC_SUSPEND:
+ if (wIndex & USB_INTRF_FUNC_SUSPEND_LP)
+ /* XXX enable Low power suspend */
+ ;
+ if (wIndex & USB_INTRF_FUNC_SUSPEND_RW)
+ /* XXX enable remote wakeup */
+ ;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ case USB_RECIP_ENDPOINT:
+ switch (wValue) {
+ case USB_ENDPOINT_HALT:
+
+ dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
+ if (!dep)
+ return -EINVAL;
+ ret = __dwc3_gadget_ep_set_halt(dep, set);
+ if (ret)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ };
+
+ return 0;
+}
+
+static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+ u32 addr;
+ u32 reg;
+
+ addr = le16_to_cpu(ctrl->wValue);
+ if (addr > 127)
+ return -EINVAL;
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+ reg &= ~(DWC3_DCFG_DEVADDR_MASK);
+ reg |= DWC3_DCFG_DEVADDR(addr);
+ dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+ if (addr)
+ dwc->dev_state = DWC3_ADDRESS_STATE;
+ else
+ dwc->dev_state = DWC3_DEFAULT_STATE;
+
+ return 0;
+}
+
+static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+ int ret;
+
+ spin_unlock(&dwc->lock);
+ ret = dwc->gadget_driver->setup(&dwc->gadget, ctrl);
+ spin_lock(&dwc->lock);
+ return ret;
+}
+
+static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+ u32 cfg;
+ int ret;
+
+ dwc->start_config_issued = false;
+ cfg = le16_to_cpu(ctrl->wValue);
+
+ switch (dwc->dev_state) {
+ case DWC3_DEFAULT_STATE:
+ return -EINVAL;
+ break;
+
+ case DWC3_ADDRESS_STATE:
+ ret = dwc3_ep0_delegate_req(dwc, ctrl);
+ /* if the cfg matches and the cfg is non zero */
+ if (!ret && cfg)
+ dwc->dev_state = DWC3_CONFIGURED_STATE;
+ break;
+
+ case DWC3_CONFIGURED_STATE:
+ ret = dwc3_ep0_delegate_req(dwc, ctrl);
+ if (!cfg)
+ dwc->dev_state = DWC3_ADDRESS_STATE;
+ break;
+ }
+ return 0;
+}
+
+static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+ int ret;
+
+ switch (ctrl->bRequest) {
+ case USB_REQ_GET_STATUS:
+ dev_vdbg(dwc->dev, "USB_REQ_GET_STATUS\n");
+ ret = dwc3_ep0_handle_status(dwc, ctrl);
+ break;
+ case USB_REQ_CLEAR_FEATURE:
+ dev_vdbg(dwc->dev, "USB_REQ_CLEAR_FEATURE\n");
+ ret = dwc3_ep0_handle_feature(dwc, ctrl, 0);
+ break;
+ case USB_REQ_SET_FEATURE:
+ dev_vdbg(dwc->dev, "USB_REQ_SET_FEATURE\n");
+ ret = dwc3_ep0_handle_feature(dwc, ctrl, 1);
+ break;
+ case USB_REQ_SET_ADDRESS:
+ dev_vdbg(dwc->dev, "USB_REQ_SET_ADDRESS\n");
+ ret = dwc3_ep0_set_address(dwc, ctrl);
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ dev_vdbg(dwc->dev, "USB_REQ_SET_CONFIGURATION\n");
+ ret = dwc3_ep0_set_config(dwc, ctrl);
+ break;
+ default:
+ dev_vdbg(dwc->dev, "Forwarding to gadget driver\n");
+ ret = dwc3_ep0_delegate_req(dwc, ctrl);
+ break;
+ };
+
+ return ret;
+}
+
+static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
+ const struct dwc3_event_depevt *event)
+{
+ struct usb_ctrlrequest *ctrl = dwc->ctrl_req;
+ int ret;
+ u32 len;
+
+ if (!dwc->gadget_driver)
+ goto err;
+
+ len = le16_to_cpu(ctrl->wLength);
+ if (!len) {
+ dwc->three_stage_setup = false;
+ dwc->ep0_expect_in = false;
+ dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
+ } else {
+ dwc->three_stage_setup = true;
+ dwc->ep0_expect_in = !!(ctrl->bRequestType & USB_DIR_IN);
+ dwc->ep0_next_event = DWC3_EP0_NRDY_DATA;
+ }
+
+ if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
+ ret = dwc3_ep0_std_request(dwc, ctrl);
+ else
+ ret = dwc3_ep0_delegate_req(dwc, ctrl);
+
+ if (ret >= 0)
+ return;
+
+err:
+ dwc3_ep0_stall_and_restart(dwc);
+}
+
+static void dwc3_ep0_complete_data(struct dwc3 *dwc,
+ const struct dwc3_event_depevt *event)
+{
+ struct dwc3_request *r = NULL;
+ struct usb_request *ur;
+ struct dwc3_trb trb;
+ struct dwc3_ep *dep;
+ u32 transferred;
+ u8 epnum;
+
+ epnum = event->endpoint_number;
+ dep = dwc->eps[epnum];
+
+ dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
+
+ if (!dwc->ep0_status_pending) {
+ r = next_request(&dwc->eps[0]->request_list);
+ ur = &r->request;
+ } else {
+ ur = &dwc->ep0_usb_req;
+ dwc->ep0_status_pending = 0;
+ }
+
+ dwc3_trb_to_nat(dwc->ep0_trb, &trb);
+
+ if (dwc->ep0_bounced) {
+ struct dwc3_ep *ep0 = dwc->eps[0];
+
+ transferred = min_t(u32, ur->length,
+ ep0->endpoint.maxpacket - trb.length);
+ memcpy(ur->buf, dwc->ep0_bounce, transferred);
+ dwc->ep0_bounced = false;
+ } else {
+ transferred = ur->length - trb.length;
+ ur->actual += transferred;
+ }
+
+ if ((epnum & 1) && ur->actual < ur->length) {
+ /* for some reason we did not get everything out */
+
+ dwc3_ep0_stall_and_restart(dwc);
+ } else {
+ /*
+ * handle the case where we have to send a zero packet. This
+ * seems to be case when req.length > maxpacket. Could it be?
+ */
+ if (r)
+ dwc3_gadget_giveback(dep, r, 0);
+ }
+}
+
+static void dwc3_ep0_complete_req(struct dwc3 *dwc,
+ const struct dwc3_event_depevt *event)
+{
+ struct dwc3_request *r;
+ struct dwc3_ep *dep;
+
+ dep = dwc->eps[0];
+
+ if (!list_empty(&dep->request_list)) {
+ r = next_request(&dep->request_list);
+
+ dwc3_gadget_giveback(dep, r, 0);
+ }
+
+ dwc->ep0state = EP0_SETUP_PHASE;
+ dwc3_ep0_out_start(dwc);
+}
+
+static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
+ const struct dwc3_event_depevt *event)
+{
+ struct dwc3_ep *dep = dwc->eps[event->endpoint_number];
+
+ dep->flags &= ~DWC3_EP_BUSY;
+
+ switch (dwc->ep0state) {
+ case EP0_SETUP_PHASE:
+ dev_vdbg(dwc->dev, "Inspecting Setup Bytes\n");
+ dwc3_ep0_inspect_setup(dwc, event);
+ break;
+
+ case EP0_DATA_PHASE:
+ dev_vdbg(dwc->dev, "Data Phase\n");
+ dwc3_ep0_complete_data(dwc, event);
+ break;
+
+ case EP0_STATUS_PHASE:
+ dev_vdbg(dwc->dev, "Status Phase\n");
+ dwc3_ep0_complete_req(dwc, event);
+ break;
+ default:
+ WARN(true, "UNKNOWN ep0state %d\n", dwc->ep0state);
+ }
+}
+
+static void dwc3_ep0_do_control_setup(struct dwc3 *dwc,
+ const struct dwc3_event_depevt *event)
+{
+ dwc->ep0state = EP0_SETUP_PHASE;
+ dwc3_ep0_out_start(dwc);
+}
+
+static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
+ const struct dwc3_event_depevt *event)
+{
+ struct dwc3_ep *dep;
+ struct dwc3_request *req;
+ int ret;
+
+ dep = dwc->eps[0];
+ dwc->ep0state = EP0_DATA_PHASE;
+
+ if (dwc->ep0_status_pending) {
+ dwc3_ep0_send_status_response(dwc);
+ return;
+ }
+
+ if (list_empty(&dep->request_list)) {
+ dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n");
+ dep->flags |= DWC3_EP_PENDING_REQUEST;
+
+ if (event->endpoint_number)
+ dep->flags |= DWC3_EP0_DIR_IN;
+ return;
+ }
+
+ req = next_request(&dep->request_list);
+ req->direction = !!event->endpoint_number;
+
+ dwc->ep0state = EP0_DATA_PHASE;
+ if (req->request.length == 0) {
+ ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
+ dwc->ctrl_req_addr, 0,
+ DWC3_TRBCTL_CONTROL_DATA);
+ } else if ((req->request.length % dep->endpoint.maxpacket)
+ && (event->endpoint_number == 0)) {
+ dwc3_map_buffer_to_dma(req);
+
+ WARN_ON(req->request.length > dep->endpoint.maxpacket);
+
+ dwc->ep0_bounced = true;
+
+ /*
+ * REVISIT in case request length is bigger than EP0
+ * wMaxPacketSize, we will need two chained TRBs to handle
+ * the transfer.
+ */
+ ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
+ dwc->ep0_bounce_addr, dep->endpoint.maxpacket,
+ DWC3_TRBCTL_CONTROL_DATA);
+ } else {
+ dwc3_map_buffer_to_dma(req);
+
+ ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
+ req->request.dma, req->request.length,
+ DWC3_TRBCTL_CONTROL_DATA);
+ }
+
+ WARN_ON(ret < 0);
+}
+
+static void dwc3_ep0_do_control_status(struct dwc3 *dwc,
+ const struct dwc3_event_depevt *event)
+{
+ u32 type;
+ int ret;
+
+ dwc->ep0state = EP0_STATUS_PHASE;
+
+ type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3
+ : DWC3_TRBCTL_CONTROL_STATUS2;
+
+ ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
+ dwc->ctrl_req_addr, 0, type);
+
+ WARN_ON(ret < 0);
+}
+
+static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
+ const struct dwc3_event_depevt *event)
+{
+ switch (event->status) {
+ case DEPEVT_STATUS_CONTROL_SETUP:
+ dev_vdbg(dwc->dev, "Control Setup\n");
+ dwc3_ep0_do_control_setup(dwc, event);
+ break;
+
+ case DEPEVT_STATUS_CONTROL_DATA:
+ dev_vdbg(dwc->dev, "Control Data\n");
+
+ if (dwc->ep0_next_event != DWC3_EP0_NRDY_DATA) {
+ dev_vdbg(dwc->dev, "Expected %d got %d\n",
+ dwc->ep0_next_event,
+ DWC3_EP0_NRDY_DATA);
+
+ dwc3_ep0_stall_and_restart(dwc);
+ return;
+ }
+
+ /*
+ * One of the possible error cases is when Host _does_
+ * request for Data Phase, but it does so on the wrong
+ * direction.
+ *
+ * Here, we already know ep0_next_event is DATA (see above),
+ * so we only need to check for direction.
+ */
+ if (dwc->ep0_expect_in != event->endpoint_number) {
+ dev_vdbg(dwc->dev, "Wrong direction for Data phase\n");
+ dwc3_ep0_stall_and_restart(dwc);
+ return;
+ }
+
+ dwc3_ep0_do_control_data(dwc, event);
+ break;
+
+ case DEPEVT_STATUS_CONTROL_STATUS:
+ dev_vdbg(dwc->dev, "Control Status\n");
+
+ if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) {
+ dev_vdbg(dwc->dev, "Expected %d got %d\n",
+ dwc->ep0_next_event,
+ DWC3_EP0_NRDY_STATUS);
+
+ dwc3_ep0_stall_and_restart(dwc);
+ return;
+ }
+ dwc3_ep0_do_control_status(dwc, event);
+ }
+}
+
+void dwc3_ep0_interrupt(struct dwc3 *dwc,
+ const const struct dwc3_event_depevt *event)
+{
+ u8 epnum = event->endpoint_number;
+
+ dev_dbg(dwc->dev, "%s while ep%d%s in state '%s'\n",
+ dwc3_ep_event_string(event->endpoint_event),
+ epnum >> 1, (epnum & 1) ? "in" : "out",
+ dwc3_ep0_state_string(dwc->ep0state));
+
+ switch (event->endpoint_event) {
+ case DWC3_DEPEVT_XFERCOMPLETE:
+ dwc3_ep0_xfer_complete(dwc, event);
+ break;
+
+ case DWC3_DEPEVT_XFERNOTREADY:
+ dwc3_ep0_xfernotready(dwc, event);
+ break;
+
+ case DWC3_DEPEVT_XFERINPROGRESS:
+ case DWC3_DEPEVT_RXTXFIFOEVT:
+ case DWC3_DEPEVT_STREAMEVT:
+ case DWC3_DEPEVT_EPCMDCMPLT:
+ break;
+ }
+}
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
new file mode 100644
index 000000000000..fa824cfdd2eb
--- /dev/null
+++ b/drivers/usb/dwc3/gadget.c
@@ -0,0 +1,2104 @@
+/**
+ * gadget.c - DesignWare USB3 DRD Controller Gadget Framework Link
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * 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/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+
+void dwc3_map_buffer_to_dma(struct dwc3_request *req)
+{
+ struct dwc3 *dwc = req->dep->dwc;
+
+ if (req->request.length == 0) {
+ /* req->request.dma = dwc->setup_buf_addr; */
+ return;
+ }
+
+ if (req->request.dma == DMA_ADDR_INVALID) {
+ req->request.dma = dma_map_single(dwc->dev, req->request.buf,
+ req->request.length, req->direction
+ ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ req->mapped = true;
+ }
+}
+
+void dwc3_unmap_buffer_from_dma(struct dwc3_request *req)
+{
+ struct dwc3 *dwc = req->dep->dwc;
+
+ if (req->request.length == 0) {
+ req->request.dma = DMA_ADDR_INVALID;
+ return;
+ }
+
+ if (req->mapped) {
+ dma_unmap_single(dwc->dev, req->request.dma,
+ req->request.length, req->direction
+ ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ req->mapped = 0;
+ req->request.dma = DMA_ADDR_INVALID;
+ }
+}
+
+void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
+ int status)
+{
+ struct dwc3 *dwc = dep->dwc;
+
+ if (req->queued) {
+ dep->busy_slot++;
+ /*
+ * Skip LINK TRB. We can't use req->trb and check for
+ * DWC3_TRBCTL_LINK_TRB because it points the TRB we just
+ * completed (not the LINK TRB).
+ */
+ if (((dep->busy_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
+ usb_endpoint_xfer_isoc(dep->desc))
+ dep->busy_slot++;
+ }
+ list_del(&req->list);
+
+ if (req->request.status == -EINPROGRESS)
+ req->request.status = status;
+
+ dwc3_unmap_buffer_from_dma(req);
+
+ dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n",
+ req, dep->name, req->request.actual,
+ req->request.length, status);
+
+ spin_unlock(&dwc->lock);
+ req->request.complete(&req->dep->endpoint, &req->request);
+ spin_lock(&dwc->lock);
+}
+
+static const char *dwc3_gadget_ep_cmd_string(u8 cmd)
+{
+ switch (cmd) {
+ case DWC3_DEPCMD_DEPSTARTCFG:
+ return "Start New Configuration";
+ case DWC3_DEPCMD_ENDTRANSFER:
+ return "End Transfer";
+ case DWC3_DEPCMD_UPDATETRANSFER:
+ return "Update Transfer";
+ case DWC3_DEPCMD_STARTTRANSFER:
+ return "Start Transfer";
+ case DWC3_DEPCMD_CLEARSTALL:
+ return "Clear Stall";
+ case DWC3_DEPCMD_SETSTALL:
+ return "Set Stall";
+ case DWC3_DEPCMD_GETSEQNUMBER:
+ return "Get Data Sequence Number";
+ case DWC3_DEPCMD_SETTRANSFRESOURCE:
+ return "Set Endpoint Transfer Resource";
+ case DWC3_DEPCMD_SETEPCONFIG:
+ return "Set Endpoint Configuration";
+ default:
+ return "UNKNOWN command";
+ }
+}
+
+int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
+ unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
+{
+ struct dwc3_ep *dep = dwc->eps[ep];
+ u32 timeout = 500;
+ u32 reg;
+
+ dev_vdbg(dwc->dev, "%s: cmd '%s' params %08x %08x %08x\n",
+ dep->name,
+ dwc3_gadget_ep_cmd_string(cmd), params->param0,
+ params->param1, params->param2);
+
+ dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0);
+ dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1);
+ dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2);
+
+ dwc3_writel(dwc->regs, DWC3_DEPCMD(ep), cmd | DWC3_DEPCMD_CMDACT);
+ do {
+ reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep));
+ if (!(reg & DWC3_DEPCMD_CMDACT)) {
+ dev_vdbg(dwc->dev, "Command Complete --> %d\n",
+ DWC3_DEPCMD_STATUS(reg));
+ return 0;
+ }
+
+ /*
+ * We can't sleep here, because it is also called from
+ * interrupt context.
+ */
+ timeout--;
+ if (!timeout)
+ return -ETIMEDOUT;
+
+ udelay(1);
+ } while (1);
+}
+
+static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
+ struct dwc3_trb_hw *trb)
+{
+ u32 offset = (char *) trb - (char *) dep->trb_pool;
+
+ return dep->trb_pool_dma + offset;
+}
+
+static int dwc3_alloc_trb_pool(struct dwc3_ep *dep)
+{
+ struct dwc3 *dwc = dep->dwc;
+
+ if (dep->trb_pool)
+ return 0;
+
+ if (dep->number == 0 || dep->number == 1)
+ return 0;
+
+ dep->trb_pool = dma_alloc_coherent(dwc->dev,
+ sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
+ &dep->trb_pool_dma, GFP_KERNEL);
+ if (!dep->trb_pool) {
+ dev_err(dep->dwc->dev, "failed to allocate trb pool for %s\n",
+ dep->name);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void dwc3_free_trb_pool(struct dwc3_ep *dep)
+{
+ struct dwc3 *dwc = dep->dwc;
+
+ dma_free_coherent(dwc->dev, sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
+ dep->trb_pool, dep->trb_pool_dma);
+
+ dep->trb_pool = NULL;
+ dep->trb_pool_dma = 0;
+}
+
+static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+ struct dwc3_gadget_ep_cmd_params params;
+ u32 cmd;
+
+ memset(&params, 0x00, sizeof(params));
+
+ if (dep->number != 1) {
+ cmd = DWC3_DEPCMD_DEPSTARTCFG;
+ /* XferRscIdx == 0 for ep0 and 2 for the remaining */
+ if (dep->number > 1) {
+ if (dwc->start_config_issued)
+ return 0;
+ dwc->start_config_issued = true;
+ cmd |= DWC3_DEPCMD_PARAM(2);
+ }
+
+ return dwc3_send_gadget_ep_cmd(dwc, 0, cmd, &params);
+ }
+
+ return 0;
+}
+
+static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct dwc3_gadget_ep_cmd_params params;
+
+ memset(&params, 0x00, sizeof(params));
+
+ params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc))
+ | DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc))
+ | DWC3_DEPCFG_BURST_SIZE(dep->endpoint.maxburst);
+
+ params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN
+ | DWC3_DEPCFG_XFER_NOT_READY_EN;
+
+ if (usb_endpoint_xfer_bulk(desc) && dep->endpoint.max_streams) {
+ params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE
+ | DWC3_DEPCFG_STREAM_EVENT_EN;
+ dep->stream_capable = true;
+ }
+
+ if (usb_endpoint_xfer_isoc(desc))
+ params.param1 |= DWC3_DEPCFG_XFER_IN_PROGRESS_EN;
+
+ /*
+ * We are doing 1:1 mapping for endpoints, meaning
+ * Physical Endpoints 2 maps to Logical Endpoint 2 and
+ * so on. We consider the direction bit as part of the physical
+ * endpoint number. So USB endpoint 0x81 is 0x03.
+ */
+ params.param1 |= DWC3_DEPCFG_EP_NUMBER(dep->number);
+
+ /*
+ * We must use the lower 16 TX FIFOs even though
+ * HW might have more
+ */
+ if (dep->direction)
+ params.param0 |= DWC3_DEPCFG_FIFO_NUMBER(dep->number >> 1);
+
+ if (desc->bInterval) {
+ params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(desc->bInterval - 1);
+ dep->interval = 1 << (desc->bInterval - 1);
+ }
+
+ return dwc3_send_gadget_ep_cmd(dwc, dep->number,
+ DWC3_DEPCMD_SETEPCONFIG, &params);
+}
+
+static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+ struct dwc3_gadget_ep_cmd_params params;
+
+ memset(&params, 0x00, sizeof(params));
+
+ params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1);
+
+ return dwc3_send_gadget_ep_cmd(dwc, dep->number,
+ DWC3_DEPCMD_SETTRANSFRESOURCE, &params);
+}
+
+/**
+ * __dwc3_gadget_ep_enable - Initializes a HW endpoint
+ * @dep: endpoint to be initialized
+ * @desc: USB Endpoint Descriptor
+ *
+ * Caller should take care of locking
+ */
+static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct dwc3 *dwc = dep->dwc;
+ u32 reg;
+ int ret = -ENOMEM;
+
+ if (!(dep->flags & DWC3_EP_ENABLED)) {
+ ret = dwc3_gadget_start_config(dwc, dep);
+ if (ret)
+ return ret;
+ }
+
+ ret = dwc3_gadget_set_ep_config(dwc, dep, desc);
+ if (ret)
+ return ret;
+
+ if (!(dep->flags & DWC3_EP_ENABLED)) {
+ struct dwc3_trb_hw *trb_st_hw;
+ struct dwc3_trb_hw *trb_link_hw;
+ struct dwc3_trb trb_link;
+
+ ret = dwc3_gadget_set_xfer_resource(dwc, dep);
+ if (ret)
+ return ret;
+
+ dep->desc = desc;
+ dep->type = usb_endpoint_type(desc);
+ dep->flags |= DWC3_EP_ENABLED;
+
+ reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
+ reg |= DWC3_DALEPENA_EP(dep->number);
+ dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
+
+ if (!usb_endpoint_xfer_isoc(desc))
+ return 0;
+
+ memset(&trb_link, 0, sizeof(trb_link));
+
+ /* Link TRB for ISOC. The HWO but is never reset */
+ trb_st_hw = &dep->trb_pool[0];
+
+ trb_link.bplh = dwc3_trb_dma_offset(dep, trb_st_hw);
+ trb_link.trbctl = DWC3_TRBCTL_LINK_TRB;
+ trb_link.hwo = true;
+
+ trb_link_hw = &dep->trb_pool[DWC3_TRB_NUM - 1];
+ dwc3_trb_to_hw(&trb_link, trb_link_hw);
+ }
+
+ return 0;
+}
+
+static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum);
+static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+ struct dwc3_request *req;
+
+ if (!list_empty(&dep->req_queued))
+ dwc3_stop_active_transfer(dwc, dep->number);
+
+ while (!list_empty(&dep->request_list)) {
+ req = next_request(&dep->request_list);
+
+ dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
+ }
+}
+
+/**
+ * __dwc3_gadget_ep_disable - Disables a HW endpoint
+ * @dep: the endpoint to disable
+ *
+ * This function also removes requests which are currently processed ny the
+ * hardware and those which are not yet scheduled.
+ * Caller should take care of locking.
+ */
+static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
+{
+ struct dwc3 *dwc = dep->dwc;
+ u32 reg;
+
+ dwc3_remove_requests(dwc, dep);
+
+ reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
+ reg &= ~DWC3_DALEPENA_EP(dep->number);
+ dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
+
+ dep->stream_capable = false;
+ dep->desc = NULL;
+ dep->type = 0;
+ dep->flags = 0;
+
+ return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int dwc3_gadget_ep0_enable(struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ return -EINVAL;
+}
+
+static int dwc3_gadget_ep0_disable(struct usb_ep *ep)
+{
+ return -EINVAL;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int dwc3_gadget_ep_enable(struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct dwc3_ep *dep;
+ struct dwc3 *dwc;
+ unsigned long flags;
+ int ret;
+
+ if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) {
+ pr_debug("dwc3: invalid parameters\n");
+ return -EINVAL;
+ }
+
+ if (!desc->wMaxPacketSize) {
+ pr_debug("dwc3: missing wMaxPacketSize\n");
+ return -EINVAL;
+ }
+
+ dep = to_dwc3_ep(ep);
+ dwc = dep->dwc;
+
+ switch (usb_endpoint_type(desc)) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ strncat(dep->name, "-control", sizeof(dep->name));
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ strncat(dep->name, "-isoc", sizeof(dep->name));
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ strncat(dep->name, "-bulk", sizeof(dep->name));
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ strncat(dep->name, "-int", sizeof(dep->name));
+ break;
+ default:
+ dev_err(dwc->dev, "invalid endpoint transfer type\n");
+ }
+
+ if (dep->flags & DWC3_EP_ENABLED) {
+ dev_WARN_ONCE(dwc->dev, true, "%s is already enabled\n",
+ dep->name);
+ return 0;
+ }
+
+ dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ ret = __dwc3_gadget_ep_enable(dep, desc);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
+static int dwc3_gadget_ep_disable(struct usb_ep *ep)
+{
+ struct dwc3_ep *dep;
+ struct dwc3 *dwc;
+ unsigned long flags;
+ int ret;
+
+ if (!ep) {
+ pr_debug("dwc3: invalid parameters\n");
+ return -EINVAL;
+ }
+
+ dep = to_dwc3_ep(ep);
+ dwc = dep->dwc;
+
+ if (!(dep->flags & DWC3_EP_ENABLED)) {
+ dev_WARN_ONCE(dwc->dev, true, "%s is already disabled\n",
+ dep->name);
+ return 0;
+ }
+
+ snprintf(dep->name, sizeof(dep->name), "ep%d%s",
+ dep->number >> 1,
+ (dep->number & 1) ? "in" : "out");
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ ret = __dwc3_gadget_ep_disable(dep);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
+static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep,
+ gfp_t gfp_flags)
+{
+ struct dwc3_request *req;
+ struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
+
+ req = kzalloc(sizeof(*req), gfp_flags);
+ if (!req) {
+ dev_err(dwc->dev, "not enough memory\n");
+ return NULL;
+ }
+
+ req->epnum = dep->number;
+ req->dep = dep;
+ req->request.dma = DMA_ADDR_INVALID;
+
+ return &req->request;
+}
+
+static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
+ struct usb_request *request)
+{
+ struct dwc3_request *req = to_dwc3_request(request);
+
+ kfree(req);
+}
+
+/*
+ * dwc3_prepare_trbs - setup TRBs from requests
+ * @dep: endpoint for which requests are being prepared
+ * @starting: true if the endpoint is idle and no requests are queued.
+ *
+ * The functions goes through the requests list and setups TRBs for the
+ * transfers. The functions returns once there are not more TRBs available or
+ * it run out of requests.
+ */
+static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep,
+ bool starting)
+{
+ struct dwc3_request *req, *n, *ret = NULL;
+ struct dwc3_trb_hw *trb_hw;
+ struct dwc3_trb trb;
+ u32 trbs_left;
+
+ BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
+
+ /* the first request must not be queued */
+ trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
+ /*
+ * if busy & slot are equal than it is either full or empty. If we are
+ * starting to proceed requests then we are empty. Otherwise we ar
+ * full and don't do anything
+ */
+ if (!trbs_left) {
+ if (!starting)
+ return NULL;
+ trbs_left = DWC3_TRB_NUM;
+ /*
+ * In case we start from scratch, we queue the ISOC requests
+ * starting from slot 1. This is done because we use ring
+ * buffer and have no LST bit to stop us. Instead, we place
+ * IOC bit TRB_NUM/4. We try to avoid to having an interrupt
+ * after the first request so we start at slot 1 and have
+ * 7 requests proceed before we hit the first IOC.
+ * Other transfer types don't use the ring buffer and are
+ * processed from the first TRB until the last one. Since we
+ * don't wrap around we have to start at the beginning.
+ */
+ if (usb_endpoint_xfer_isoc(dep->desc)) {
+ dep->busy_slot = 1;
+ dep->free_slot = 1;
+ } else {
+ dep->busy_slot = 0;
+ dep->free_slot = 0;
+ }
+ }
+
+ /* The last TRB is a link TRB, not used for xfer */
+ if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->desc))
+ return NULL;
+
+ list_for_each_entry_safe(req, n, &dep->request_list, list) {
+ unsigned int last_one = 0;
+ unsigned int cur_slot;
+
+ trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+ cur_slot = dep->free_slot;
+ dep->free_slot++;
+
+ /* Skip the LINK-TRB on ISOC */
+ if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
+ usb_endpoint_xfer_isoc(dep->desc))
+ continue;
+
+ dwc3_gadget_move_request_queued(req);
+ memset(&trb, 0, sizeof(trb));
+ trbs_left--;
+
+ /* Is our TRB pool empty? */
+ if (!trbs_left)
+ last_one = 1;
+ /* Is this the last request? */
+ if (list_empty(&dep->request_list))
+ last_one = 1;
+
+ /*
+ * FIXME we shouldn't need to set LST bit always but we are
+ * facing some weird problem with the Hardware where it doesn't
+ * complete even though it has been previously started.
+ *
+ * While we're debugging the problem, as a workaround to
+ * multiple TRBs handling, use only one TRB at a time.
+ */
+ last_one = 1;
+
+ req->trb = trb_hw;
+ if (!ret)
+ ret = req;
+
+ trb.bplh = req->request.dma;
+
+ if (usb_endpoint_xfer_isoc(dep->desc)) {
+ trb.isp_imi = true;
+ trb.csp = true;
+ } else {
+ trb.lst = last_one;
+ }
+
+ if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
+ trb.sid_sofn = req->request.stream_id;
+
+ switch (usb_endpoint_type(dep->desc)) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
+ break;
+
+ case USB_ENDPOINT_XFER_ISOC:
+ trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
+
+ /* IOC every DWC3_TRB_NUM / 4 so we can refill */
+ if (!(cur_slot % (DWC3_TRB_NUM / 4)))
+ trb.ioc = last_one;
+ break;
+
+ case USB_ENDPOINT_XFER_BULK:
+ case USB_ENDPOINT_XFER_INT:
+ trb.trbctl = DWC3_TRBCTL_NORMAL;
+ break;
+ default:
+ /*
+ * This is only possible with faulty memory because we
+ * checked it already :)
+ */
+ BUG();
+ }
+
+ trb.length = req->request.length;
+ trb.hwo = true;
+
+ dwc3_trb_to_hw(&trb, trb_hw);
+ req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw);
+
+ if (last_one)
+ break;
+ }
+
+ return ret;
+}
+
+static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
+ int start_new)
+{
+ struct dwc3_gadget_ep_cmd_params params;
+ struct dwc3_request *req;
+ struct dwc3 *dwc = dep->dwc;
+ int ret;
+ u32 cmd;
+
+ if (start_new && (dep->flags & DWC3_EP_BUSY)) {
+ dev_vdbg(dwc->dev, "%s: endpoint busy\n", dep->name);
+ return -EBUSY;
+ }
+ dep->flags &= ~DWC3_EP_PENDING_REQUEST;
+
+ /*
+ * If we are getting here after a short-out-packet we don't enqueue any
+ * new requests as we try to set the IOC bit only on the last request.
+ */
+ if (start_new) {
+ if (list_empty(&dep->req_queued))
+ dwc3_prepare_trbs(dep, start_new);
+
+ /* req points to the first request which will be sent */
+ req = next_request(&dep->req_queued);
+ } else {
+ /*
+ * req points to the first request where HWO changed
+ * from 0 to 1
+ */
+ req = dwc3_prepare_trbs(dep, start_new);
+ }
+ if (!req) {
+ dep->flags |= DWC3_EP_PENDING_REQUEST;
+ return 0;
+ }
+
+ memset(&params, 0, sizeof(params));
+ params.param0 = upper_32_bits(req->trb_dma);
+ params.param1 = lower_32_bits(req->trb_dma);
+
+ if (start_new)
+ cmd = DWC3_DEPCMD_STARTTRANSFER;
+ else
+ cmd = DWC3_DEPCMD_UPDATETRANSFER;
+
+ cmd |= DWC3_DEPCMD_PARAM(cmd_param);
+ ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
+ if (ret < 0) {
+ dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n");
+
+ /*
+ * FIXME we need to iterate over the list of requests
+ * here and stop, unmap, free and del each of the linked
+ * requests instead of we do now.
+ */
+ dwc3_unmap_buffer_from_dma(req);
+ list_del(&req->list);
+ return ret;
+ }
+
+ dep->flags |= DWC3_EP_BUSY;
+ dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
+ dep->number);
+ if (!dep->res_trans_idx)
+ printk_once(KERN_ERR "%s() res_trans_idx is invalid\n", __func__);
+ return 0;
+}
+
+static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
+{
+ req->request.actual = 0;
+ req->request.status = -EINPROGRESS;
+ req->direction = dep->direction;
+ req->epnum = dep->number;
+
+ /*
+ * We only add to our list of requests now and
+ * start consuming the list once we get XferNotReady
+ * IRQ.
+ *
+ * That way, we avoid doing anything that we don't need
+ * to do now and defer it until the point we receive a
+ * particular token from the Host side.
+ *
+ * This will also avoid Host cancelling URBs due to too
+ * many NACKs.
+ */
+ dwc3_map_buffer_to_dma(req);
+ list_add_tail(&req->list, &dep->request_list);
+
+ /*
+ * There is one special case: XferNotReady with
+ * empty list of requests. We need to kick the
+ * transfer here in that situation, otherwise
+ * we will be NAKing forever.
+ *
+ * If we get XferNotReady before gadget driver
+ * has a chance to queue a request, we will ACK
+ * the IRQ but won't be able to receive the data
+ * until the next request is queued. The following
+ * code is handling exactly that.
+ */
+ if (dep->flags & DWC3_EP_PENDING_REQUEST) {
+ int ret;
+ int start_trans;
+
+ start_trans = 1;
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+ dep->flags & DWC3_EP_BUSY)
+ start_trans = 0;
+
+ ret = __dwc3_gadget_kick_transfer(dep, 0, start_trans);
+ if (ret && ret != -EBUSY) {
+ struct dwc3 *dwc = dep->dwc;
+
+ dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
+ dep->name);
+ }
+ };
+
+ return 0;
+}
+
+static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
+ gfp_t gfp_flags)
+{
+ struct dwc3_request *req = to_dwc3_request(request);
+ struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
+
+ unsigned long flags;
+
+ int ret;
+
+ if (!dep->desc) {
+ dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
+ request, ep->name);
+ return -ESHUTDOWN;
+ }
+
+ dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
+ request, ep->name, request->length);
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ ret = __dwc3_gadget_ep_queue(dep, req);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
+static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
+ struct usb_request *request)
+{
+ struct dwc3_request *req = to_dwc3_request(request);
+ struct dwc3_request *r = NULL;
+
+ struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
+
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+
+ list_for_each_entry(r, &dep->request_list, list) {
+ if (r == req)
+ break;
+ }
+
+ if (r != req) {
+ list_for_each_entry(r, &dep->req_queued, list) {
+ if (r == req)
+ break;
+ }
+ if (r == req) {
+ /* wait until it is processed */
+ dwc3_stop_active_transfer(dwc, dep->number);
+ goto out0;
+ }
+ dev_err(dwc->dev, "request %p was not queued to %s\n",
+ request, ep->name);
+ ret = -EINVAL;
+ goto out0;
+ }
+
+ /* giveback the request */
+ dwc3_gadget_giveback(dep, req, -ECONNRESET);
+
+out0:
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
+int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value)
+{
+ struct dwc3_gadget_ep_cmd_params params;
+ struct dwc3 *dwc = dep->dwc;
+ int ret;
+
+ memset(&params, 0x00, sizeof(params));
+
+ if (value) {
+ if (dep->number == 0 || dep->number == 1) {
+ /*
+ * Whenever EP0 is stalled, we will restart
+ * the state machine, thus moving back to
+ * Setup Phase
+ */
+ dwc->ep0state = EP0_SETUP_PHASE;
+ }
+
+ ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+ DWC3_DEPCMD_SETSTALL, &params);
+ if (ret)
+ dev_err(dwc->dev, "failed to %s STALL on %s\n",
+ value ? "set" : "clear",
+ dep->name);
+ else
+ dep->flags |= DWC3_EP_STALL;
+ } else {
+ if (dep->flags & DWC3_EP_WEDGE)
+ return 0;
+
+ ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+ DWC3_DEPCMD_CLEARSTALL, &params);
+ if (ret)
+ dev_err(dwc->dev, "failed to %s STALL on %s\n",
+ value ? "set" : "clear",
+ dep->name);
+ else
+ dep->flags &= ~DWC3_EP_STALL;
+ }
+
+ return ret;
+}
+
+static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value)
+{
+ struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
+
+ unsigned long flags;
+
+ int ret;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+
+ if (usb_endpoint_xfer_isoc(dep->desc)) {
+ dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = __dwc3_gadget_ep_set_halt(dep, value);
+out:
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
+static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep)
+{
+ struct dwc3_ep *dep = to_dwc3_ep(ep);
+
+ dep->flags |= DWC3_EP_WEDGE;
+
+ return dwc3_gadget_ep_set_halt(ep, 1);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static struct usb_endpoint_descriptor dwc3_gadget_ep0_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+};
+
+static const struct usb_ep_ops dwc3_gadget_ep0_ops = {
+ .enable = dwc3_gadget_ep0_enable,
+ .disable = dwc3_gadget_ep0_disable,
+ .alloc_request = dwc3_gadget_ep_alloc_request,
+ .free_request = dwc3_gadget_ep_free_request,
+ .queue = dwc3_gadget_ep0_queue,
+ .dequeue = dwc3_gadget_ep_dequeue,
+ .set_halt = dwc3_gadget_ep_set_halt,
+ .set_wedge = dwc3_gadget_ep_set_wedge,
+};
+
+static const struct usb_ep_ops dwc3_gadget_ep_ops = {
+ .enable = dwc3_gadget_ep_enable,
+ .disable = dwc3_gadget_ep_disable,
+ .alloc_request = dwc3_gadget_ep_alloc_request,
+ .free_request = dwc3_gadget_ep_free_request,
+ .queue = dwc3_gadget_ep_queue,
+ .dequeue = dwc3_gadget_ep_dequeue,
+ .set_halt = dwc3_gadget_ep_set_halt,
+ .set_wedge = dwc3_gadget_ep_set_wedge,
+};
+
+/* -------------------------------------------------------------------------- */
+
+static int dwc3_gadget_get_frame(struct usb_gadget *g)
+{
+ struct dwc3 *dwc = gadget_to_dwc(g);
+ u32 reg;
+
+ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+ return DWC3_DSTS_SOFFN(reg);
+}
+
+static int dwc3_gadget_wakeup(struct usb_gadget *g)
+{
+ struct dwc3 *dwc = gadget_to_dwc(g);
+
+ unsigned long timeout;
+ unsigned long flags;
+
+ u32 reg;
+
+ int ret = 0;
+
+ u8 link_state;
+ u8 speed;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+
+ /*
+ * According to the Databook Remote wakeup request should
+ * be issued only when the device is in early suspend state.
+ *
+ * We can check that via USB Link State bits in DSTS register.
+ */
+ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+
+ speed = reg & DWC3_DSTS_CONNECTSPD;
+ if (speed == DWC3_DSTS_SUPERSPEED) {
+ dev_dbg(dwc->dev, "no wakeup on SuperSpeed\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ link_state = DWC3_DSTS_USBLNKST(reg);
+
+ switch (link_state) {
+ case DWC3_LINK_STATE_RX_DET: /* in HS, means Early Suspend */
+ case DWC3_LINK_STATE_U3: /* in HS, means SUSPEND */
+ break;
+ default:
+ dev_dbg(dwc->dev, "can't wakeup from link state %d\n",
+ link_state);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+
+ /*
+ * Switch link state to Recovery. In HS/FS/LS this means
+ * RemoteWakeup Request
+ */
+ reg |= DWC3_DCTL_ULSTCHNG_RECOVERY;
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+ /* wait for at least 2000us */
+ usleep_range(2000, 2500);
+
+ /* write zeroes to Link Change Request */
+ reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+ /* pool until Link State change to ON */
+ timeout = jiffies + msecs_to_jiffies(100);
+
+ while (!(time_after(jiffies, timeout))) {
+ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+
+ /* in HS, means ON */
+ if (DWC3_DSTS_USBLNKST(reg) == DWC3_LINK_STATE_U0)
+ break;
+ }
+
+ if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) {
+ dev_err(dwc->dev, "failed to send remote wakeup\n");
+ ret = -EINVAL;
+ }
+
+out:
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
+static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
+ int is_selfpowered)
+{
+ struct dwc3 *dwc = gadget_to_dwc(g);
+
+ dwc->is_selfpowered = !!is_selfpowered;
+
+ return 0;
+}
+
+static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
+{
+ u32 reg;
+ u32 timeout = 500;
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ if (is_on)
+ reg |= DWC3_DCTL_RUN_STOP;
+ else
+ reg &= ~DWC3_DCTL_RUN_STOP;
+
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+ do {
+ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+ if (is_on) {
+ if (!(reg & DWC3_DSTS_DEVCTRLHLT))
+ break;
+ } else {
+ if (reg & DWC3_DSTS_DEVCTRLHLT)
+ break;
+ }
+ timeout--;
+ if (!timeout)
+ break;
+ udelay(1);
+ } while (1);
+
+ dev_vdbg(dwc->dev, "gadget %s data soft-%s\n",
+ dwc->gadget_driver
+ ? dwc->gadget_driver->function : "no-function",
+ is_on ? "connect" : "disconnect");
+}
+
+static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
+{
+ struct dwc3 *dwc = gadget_to_dwc(g);
+ unsigned long flags;
+
+ is_on = !!is_on;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ dwc3_gadget_run_stop(dwc, is_on);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return 0;
+}
+
+static int dwc3_gadget_start(struct usb_gadget *g,
+ struct usb_gadget_driver *driver)
+{
+ struct dwc3 *dwc = gadget_to_dwc(g);
+ struct dwc3_ep *dep;
+ unsigned long flags;
+ int ret = 0;
+ u32 reg;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+
+ if (dwc->gadget_driver) {
+ dev_err(dwc->dev, "%s is already bound to %s\n",
+ dwc->gadget.name,
+ dwc->gadget_driver->driver.name);
+ ret = -EBUSY;
+ goto err0;
+ }
+
+ dwc->gadget_driver = driver;
+ dwc->gadget.dev.driver = &driver->driver;
+
+ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+
+ reg &= ~DWC3_GCTL_SCALEDOWN(3);
+ reg &= ~DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG);
+ reg &= ~DWC3_GCTL_DISSCRAMBLE;
+ reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_DEVICE);
+
+ switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams0)) {
+ case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
+ reg &= ~DWC3_GCTL_DSBLCLKGTNG;
+ break;
+ default:
+ dev_dbg(dwc->dev, "No power optimization available\n");
+ }
+
+ /*
+ * WORKAROUND: DWC3 revisions <1.90a have a bug
+ * when The device fails to connect at SuperSpeed
+ * and falls back to high-speed mode which causes
+ * the device to enter in a Connect/Disconnect loop
+ */
+ if (dwc->revision < DWC3_REVISION_190A)
+ reg |= DWC3_GCTL_U2RSTECN;
+
+ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+ reg &= ~(DWC3_DCFG_SPEED_MASK);
+ reg |= DWC3_DCFG_SUPERSPEED;
+ dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+ dwc->start_config_issued = false;
+
+ /* Start with SuperSpeed Default */
+ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+
+ dep = dwc->eps[0];
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+ goto err0;
+ }
+
+ dep = dwc->eps[1];
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+ goto err1;
+ }
+
+ /* begin to receive SETUP packets */
+ dwc->ep0state = EP0_SETUP_PHASE;
+ dwc3_ep0_out_start(dwc);
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return 0;
+
+err1:
+ __dwc3_gadget_ep_disable(dwc->eps[0]);
+
+err0:
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
+static int dwc3_gadget_stop(struct usb_gadget *g,
+ struct usb_gadget_driver *driver)
+{
+ struct dwc3 *dwc = gadget_to_dwc(g);
+ unsigned long flags;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+
+ __dwc3_gadget_ep_disable(dwc->eps[0]);
+ __dwc3_gadget_ep_disable(dwc->eps[1]);
+
+ dwc->gadget_driver = NULL;
+ dwc->gadget.dev.driver = NULL;
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return 0;
+}
+static const struct usb_gadget_ops dwc3_gadget_ops = {
+ .get_frame = dwc3_gadget_get_frame,
+ .wakeup = dwc3_gadget_wakeup,
+ .set_selfpowered = dwc3_gadget_set_selfpowered,
+ .pullup = dwc3_gadget_pullup,
+ .udc_start = dwc3_gadget_start,
+ .udc_stop = dwc3_gadget_stop,
+};
+
+/* -------------------------------------------------------------------------- */
+
+static int __devinit dwc3_gadget_init_endpoints(struct dwc3 *dwc)
+{
+ struct dwc3_ep *dep;
+ u8 epnum;
+
+ INIT_LIST_HEAD(&dwc->gadget.ep_list);
+
+ for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+ dep = kzalloc(sizeof(*dep), GFP_KERNEL);
+ if (!dep) {
+ dev_err(dwc->dev, "can't allocate endpoint %d\n",
+ epnum);
+ return -ENOMEM;
+ }
+
+ dep->dwc = dwc;
+ dep->number = epnum;
+ dwc->eps[epnum] = dep;
+
+ snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1,
+ (epnum & 1) ? "in" : "out");
+ dep->endpoint.name = dep->name;
+ dep->direction = (epnum & 1);
+
+ if (epnum == 0 || epnum == 1) {
+ dep->endpoint.maxpacket = 512;
+ dep->endpoint.ops = &dwc3_gadget_ep0_ops;
+ if (!epnum)
+ dwc->gadget.ep0 = &dep->endpoint;
+ } else {
+ int ret;
+
+ dep->endpoint.maxpacket = 1024;
+ dep->endpoint.ops = &dwc3_gadget_ep_ops;
+ list_add_tail(&dep->endpoint.ep_list,
+ &dwc->gadget.ep_list);
+
+ ret = dwc3_alloc_trb_pool(dep);
+ if (ret) {
+ dev_err(dwc->dev, "%s: failed to allocate TRB pool\n", dep->name);
+ return ret;
+ }
+ }
+ INIT_LIST_HEAD(&dep->request_list);
+ INIT_LIST_HEAD(&dep->req_queued);
+ }
+
+ return 0;
+}
+
+static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
+{
+ struct dwc3_ep *dep;
+ u8 epnum;
+
+ for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+ dep = dwc->eps[epnum];
+ dwc3_free_trb_pool(dep);
+
+ if (epnum != 0 && epnum != 1)
+ list_del(&dep->endpoint.ep_list);
+
+ kfree(dep);
+ }
+}
+
+static void dwc3_gadget_release(struct device *dev)
+{
+ dev_dbg(dev, "%s\n", __func__);
+}
+
+/* -------------------------------------------------------------------------- */
+static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
+ const struct dwc3_event_depevt *event, int status)
+{
+ struct dwc3_request *req;
+ struct dwc3_trb trb;
+ unsigned int count;
+ unsigned int s_pkt = 0;
+
+ do {
+ req = next_request(&dep->req_queued);
+ if (!req)
+ break;
+
+ dwc3_trb_to_nat(req->trb, &trb);
+
+ if (trb.hwo && status != -ESHUTDOWN)
+ /*
+ * We continue despite the error. There is not much we
+ * can do. If we don't clean in up we loop for ever. If
+ * we skip the TRB than it gets overwritten reused after
+ * a while since we use them in a ring buffer. a BUG()
+ * would help. Lets hope that if this occures, someone
+ * fixes the root cause instead of looking away :)
+ */
+ dev_err(dwc->dev, "%s's TRB (%p) still owned by HW\n",
+ dep->name, req->trb);
+ count = trb.length;
+
+ if (dep->direction) {
+ if (count) {
+ dev_err(dwc->dev, "incomplete IN transfer %s\n",
+ dep->name);
+ status = -ECONNRESET;
+ }
+ } else {
+ if (count && (event->status & DEPEVT_STATUS_SHORT))
+ s_pkt = 1;
+ }
+
+ /*
+ * We assume here we will always receive the entire data block
+ * which we should receive. Meaning, if we program RX to
+ * receive 4K but we receive only 2K, we assume that's all we
+ * should receive and we simply bounce the request back to the
+ * gadget driver for further processing.
+ */
+ req->request.actual += req->request.length - count;
+ dwc3_gadget_giveback(dep, req, status);
+ if (s_pkt)
+ break;
+ if ((event->status & DEPEVT_STATUS_LST) && trb.lst)
+ break;
+ if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
+ break;
+ } while (1);
+
+ if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
+ return 0;
+ return 1;
+}
+
+static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
+ struct dwc3_ep *dep, const struct dwc3_event_depevt *event,
+ int start_new)
+{
+ unsigned status = 0;
+ int clean_busy;
+
+ if (event->status & DEPEVT_STATUS_BUSERR)
+ status = -ECONNRESET;
+
+ clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status);
+ if (clean_busy) {
+ dep->flags &= ~DWC3_EP_BUSY;
+ dep->res_trans_idx = 0;
+ }
+}
+
+static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
+ struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
+{
+ u32 uf;
+
+ if (list_empty(&dep->request_list)) {
+ dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
+ dep->name);
+ return;
+ }
+
+ if (event->parameters) {
+ u32 mask;
+
+ mask = ~(dep->interval - 1);
+ uf = event->parameters & mask;
+ /* 4 micro frames in the future */
+ uf += dep->interval * 4;
+ } else {
+ uf = 0;
+ }
+
+ __dwc3_gadget_kick_transfer(dep, uf, 1);
+}
+
+static void dwc3_process_ep_cmd_complete(struct dwc3_ep *dep,
+ const struct dwc3_event_depevt *event)
+{
+ struct dwc3 *dwc = dep->dwc;
+ struct dwc3_event_depevt mod_ev = *event;
+
+ /*
+ * We were asked to remove one requests. It is possible that this
+ * request and a few other were started together and have the same
+ * transfer index. Since we stopped the complete endpoint we don't
+ * know how many requests were already completed (and not yet)
+ * reported and how could be done (later). We purge them all until
+ * the end of the list.
+ */
+ mod_ev.status = DEPEVT_STATUS_LST;
+ dwc3_cleanup_done_reqs(dwc, dep, &mod_ev, -ESHUTDOWN);
+ dep->flags &= ~DWC3_EP_BUSY;
+ /* pending requets are ignored and are queued on XferNotReady */
+}
+
+static void dwc3_ep_cmd_compl(struct dwc3_ep *dep,
+ const struct dwc3_event_depevt *event)
+{
+ u32 param = event->parameters;
+ u32 cmd_type = (param >> 8) & ((1 << 5) - 1);
+
+ switch (cmd_type) {
+ case DWC3_DEPCMD_ENDTRANSFER:
+ dwc3_process_ep_cmd_complete(dep, event);
+ break;
+ case DWC3_DEPCMD_STARTTRANSFER:
+ dep->res_trans_idx = param & 0x7f;
+ break;
+ default:
+ printk(KERN_ERR "%s() unknown /unexpected type: %d\n",
+ __func__, cmd_type);
+ break;
+ };
+}
+
+static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
+ const struct dwc3_event_depevt *event)
+{
+ struct dwc3_ep *dep;
+ u8 epnum = event->endpoint_number;
+
+ dep = dwc->eps[epnum];
+
+ dev_vdbg(dwc->dev, "%s: %s\n", dep->name,
+ dwc3_ep_event_string(event->endpoint_event));
+
+ if (epnum == 0 || epnum == 1) {
+ dwc3_ep0_interrupt(dwc, event);
+ return;
+ }
+
+ switch (event->endpoint_event) {
+ case DWC3_DEPEVT_XFERCOMPLETE:
+ if (usb_endpoint_xfer_isoc(dep->desc)) {
+ dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n",
+ dep->name);
+ return;
+ }
+
+ dwc3_endpoint_transfer_complete(dwc, dep, event, 1);
+ break;
+ case DWC3_DEPEVT_XFERINPROGRESS:
+ if (!usb_endpoint_xfer_isoc(dep->desc)) {
+ dev_dbg(dwc->dev, "%s is not an Isochronous endpoint\n",
+ dep->name);
+ return;
+ }
+
+ dwc3_endpoint_transfer_complete(dwc, dep, event, 0);
+ break;
+ case DWC3_DEPEVT_XFERNOTREADY:
+ if (usb_endpoint_xfer_isoc(dep->desc)) {
+ dwc3_gadget_start_isoc(dwc, dep, event);
+ } else {
+ int ret;
+
+ dev_vdbg(dwc->dev, "%s: reason %s\n",
+ dep->name, event->status
+ ? "Transfer Active"
+ : "Transfer Not Active");
+
+ ret = __dwc3_gadget_kick_transfer(dep, 0, 1);
+ if (!ret || ret == -EBUSY)
+ return;
+
+ dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
+ dep->name);
+ }
+
+ break;
+ case DWC3_DEPEVT_STREAMEVT:
+ if (!usb_endpoint_xfer_bulk(dep->desc)) {
+ dev_err(dwc->dev, "Stream event for non-Bulk %s\n",
+ dep->name);
+ return;
+ }
+
+ switch (event->status) {
+ case DEPEVT_STREAMEVT_FOUND:
+ dev_vdbg(dwc->dev, "Stream %d found and started\n",
+ event->parameters);
+
+ break;
+ case DEPEVT_STREAMEVT_NOTFOUND:
+ /* FALLTHROUGH */
+ default:
+ dev_dbg(dwc->dev, "Couldn't find suitable stream\n");
+ }
+ break;
+ case DWC3_DEPEVT_RXTXFIFOEVT:
+ dev_dbg(dwc->dev, "%s FIFO Overrun\n", dep->name);
+ break;
+ case DWC3_DEPEVT_EPCMDCMPLT:
+ dwc3_ep_cmd_compl(dep, event);
+ break;
+ }
+}
+
+static void dwc3_disconnect_gadget(struct dwc3 *dwc)
+{
+ if (dwc->gadget_driver && dwc->gadget_driver->disconnect) {
+ spin_unlock(&dwc->lock);
+ dwc->gadget_driver->disconnect(&dwc->gadget);
+ spin_lock(&dwc->lock);
+ }
+}
+
+static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
+{
+ struct dwc3_ep *dep;
+ struct dwc3_gadget_ep_cmd_params params;
+ u32 cmd;
+ int ret;
+
+ dep = dwc->eps[epnum];
+
+ WARN_ON(!dep->res_trans_idx);
+ if (dep->res_trans_idx) {
+ cmd = DWC3_DEPCMD_ENDTRANSFER;
+ cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC;
+ cmd |= DWC3_DEPCMD_PARAM(dep->res_trans_idx);
+ memset(&params, 0, sizeof(params));
+ ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
+ WARN_ON_ONCE(ret);
+ dep->res_trans_idx = 0;
+ }
+}
+
+static void dwc3_stop_active_transfers(struct dwc3 *dwc)
+{
+ u32 epnum;
+
+ for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+ struct dwc3_ep *dep;
+
+ dep = dwc->eps[epnum];
+ if (!(dep->flags & DWC3_EP_ENABLED))
+ continue;
+
+ dwc3_remove_requests(dwc, dep);
+ }
+}
+
+static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
+{
+ u32 epnum;
+
+ for (epnum = 1; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+ struct dwc3_ep *dep;
+ struct dwc3_gadget_ep_cmd_params params;
+ int ret;
+
+ dep = dwc->eps[epnum];
+
+ if (!(dep->flags & DWC3_EP_STALL))
+ continue;
+
+ dep->flags &= ~DWC3_EP_STALL;
+
+ memset(&params, 0, sizeof(params));
+ ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+ DWC3_DEPCMD_CLEARSTALL, &params);
+ WARN_ON_ONCE(ret);
+ }
+}
+
+static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
+{
+ dev_vdbg(dwc->dev, "%s\n", __func__);
+#if 0
+ XXX
+ U1/U2 is powersave optimization. Skip it for now. Anyway we need to
+ enable it before we can disable it.
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ reg &= ~DWC3_DCTL_INITU1ENA;
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+ reg &= ~DWC3_DCTL_INITU2ENA;
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+#endif
+
+ dwc3_stop_active_transfers(dwc);
+ dwc3_disconnect_gadget(dwc);
+ dwc->start_config_issued = false;
+
+ dwc->gadget.speed = USB_SPEED_UNKNOWN;
+}
+
+static void dwc3_gadget_usb3_phy_power(struct dwc3 *dwc, int on)
+{
+ u32 reg;
+
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+
+ if (on)
+ reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
+ else
+ reg |= DWC3_GUSB3PIPECTL_SUSPHY;
+
+ dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+}
+
+static void dwc3_gadget_usb2_phy_power(struct dwc3 *dwc, int on)
+{
+ u32 reg;
+
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+
+ if (on)
+ reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+ else
+ reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+}
+
+static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
+{
+ u32 reg;
+
+ dev_vdbg(dwc->dev, "%s\n", __func__);
+
+ /* Enable PHYs */
+ dwc3_gadget_usb2_phy_power(dwc, true);
+ dwc3_gadget_usb3_phy_power(dwc, true);
+
+ if (dwc->gadget.speed != USB_SPEED_UNKNOWN)
+ dwc3_disconnect_gadget(dwc);
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ reg &= ~DWC3_DCTL_TSTCTRL_MASK;
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+ dwc3_stop_active_transfers(dwc);
+ dwc3_clear_stall_all_ep(dwc);
+ dwc->start_config_issued = false;
+
+ /* Reset device address to zero */
+ reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+ reg &= ~(DWC3_DCFG_DEVADDR_MASK);
+ dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+}
+
+static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed)
+{
+ u32 reg;
+ u32 usb30_clock = DWC3_GCTL_CLK_BUS;
+
+ /*
+ * We change the clock only at SS but I dunno why I would want to do
+ * this. Maybe it becomes part of the power saving plan.
+ */
+
+ if (speed != DWC3_DSTS_SUPERSPEED)
+ return;
+
+ /*
+ * RAMClkSel is reset to 0 after USB reset, so it must be reprogrammed
+ * each time on Connect Done.
+ */
+ if (!usb30_clock)
+ return;
+
+ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+ reg |= DWC3_GCTL_RAMCLKSEL(usb30_clock);
+ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+}
+
+static void dwc3_gadget_disable_phy(struct dwc3 *dwc, u8 speed)
+{
+ switch (speed) {
+ case USB_SPEED_SUPER:
+ dwc3_gadget_usb2_phy_power(dwc, false);
+ break;
+ case USB_SPEED_HIGH:
+ case USB_SPEED_FULL:
+ case USB_SPEED_LOW:
+ dwc3_gadget_usb3_phy_power(dwc, false);
+ break;
+ }
+}
+
+static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
+{
+ struct dwc3_gadget_ep_cmd_params params;
+ struct dwc3_ep *dep;
+ int ret;
+ u32 reg;
+ u8 speed;
+
+ dev_vdbg(dwc->dev, "%s\n", __func__);
+
+ memset(&params, 0x00, sizeof(params));
+
+ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+ speed = reg & DWC3_DSTS_CONNECTSPD;
+ dwc->speed = speed;
+
+ dwc3_update_ram_clk_sel(dwc, speed);
+
+ switch (speed) {
+ case DWC3_DCFG_SUPERSPEED:
+ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+ dwc->gadget.ep0->maxpacket = 512;
+ dwc->gadget.speed = USB_SPEED_SUPER;
+ break;
+ case DWC3_DCFG_HIGHSPEED:
+ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
+ dwc->gadget.ep0->maxpacket = 64;
+ dwc->gadget.speed = USB_SPEED_HIGH;
+ break;
+ case DWC3_DCFG_FULLSPEED2:
+ case DWC3_DCFG_FULLSPEED1:
+ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
+ dwc->gadget.ep0->maxpacket = 64;
+ dwc->gadget.speed = USB_SPEED_FULL;
+ break;
+ case DWC3_DCFG_LOWSPEED:
+ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(8);
+ dwc->gadget.ep0->maxpacket = 8;
+ dwc->gadget.speed = USB_SPEED_LOW;
+ break;
+ }
+
+ /* Disable unneded PHY */
+ dwc3_gadget_disable_phy(dwc, dwc->gadget.speed);
+
+ dep = dwc->eps[0];
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+ return;
+ }
+
+ dep = dwc->eps[1];
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+ return;
+ }
+
+ /*
+ * Configure PHY via GUSB3PIPECTLn if required.
+ *
+ * Update GTXFIFOSIZn
+ *
+ * In both cases reset values should be sufficient.
+ */
+}
+
+static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
+{
+ dev_vdbg(dwc->dev, "%s\n", __func__);
+
+ /*
+ * TODO take core out of low power mode when that's
+ * implemented.
+ */
+
+ dwc->gadget_driver->resume(&dwc->gadget);
+}
+
+static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
+ unsigned int evtinfo)
+{
+ /* The fith bit says SuperSpeed yes or no. */
+ dwc->link_state = evtinfo & DWC3_LINK_STATE_MASK;
+
+ dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
+}
+
+static void dwc3_gadget_interrupt(struct dwc3 *dwc,
+ const struct dwc3_event_devt *event)
+{
+ switch (event->type) {
+ case DWC3_DEVICE_EVENT_DISCONNECT:
+ dwc3_gadget_disconnect_interrupt(dwc);
+ break;
+ case DWC3_DEVICE_EVENT_RESET:
+ dwc3_gadget_reset_interrupt(dwc);
+ break;
+ case DWC3_DEVICE_EVENT_CONNECT_DONE:
+ dwc3_gadget_conndone_interrupt(dwc);
+ break;
+ case DWC3_DEVICE_EVENT_WAKEUP:
+ dwc3_gadget_wakeup_interrupt(dwc);
+ break;
+ case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
+ dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
+ break;
+ case DWC3_DEVICE_EVENT_EOPF:
+ dev_vdbg(dwc->dev, "End of Periodic Frame\n");
+ break;
+ case DWC3_DEVICE_EVENT_SOF:
+ dev_vdbg(dwc->dev, "Start of Periodic Frame\n");
+ break;
+ case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
+ dev_vdbg(dwc->dev, "Erratic Error\n");
+ break;
+ case DWC3_DEVICE_EVENT_CMD_CMPL:
+ dev_vdbg(dwc->dev, "Command Complete\n");
+ break;
+ case DWC3_DEVICE_EVENT_OVERFLOW:
+ dev_vdbg(dwc->dev, "Overflow\n");
+ break;
+ default:
+ dev_dbg(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
+ }
+}
+
+static void dwc3_process_event_entry(struct dwc3 *dwc,
+ const union dwc3_event *event)
+{
+ /* Endpoint IRQ, handle it and return early */
+ if (event->type.is_devspec == 0) {
+ /* depevt */
+ return dwc3_endpoint_interrupt(dwc, &event->depevt);
+ }
+
+ switch (event->type.type) {
+ case DWC3_EVENT_TYPE_DEV:
+ dwc3_gadget_interrupt(dwc, &event->devt);
+ break;
+ /* REVISIT what to do with Carkit and I2C events ? */
+ default:
+ dev_err(dwc->dev, "UNKNOWN IRQ type %d\n", event->raw);
+ }
+}
+
+static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
+{
+ struct dwc3_event_buffer *evt;
+ int left;
+ u32 count;
+
+ count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf));
+ count &= DWC3_GEVNTCOUNT_MASK;
+ if (!count)
+ return IRQ_NONE;
+
+ evt = dwc->ev_buffs[buf];
+ left = count;
+
+ while (left > 0) {
+ union dwc3_event event;
+
+ memcpy(&event.raw, (evt->buf + evt->lpos), sizeof(event.raw));
+ dwc3_process_event_entry(dwc, &event);
+ /*
+ * XXX we wrap around correctly to the next entry as almost all
+ * entries are 4 bytes in size. There is one entry which has 12
+ * bytes which is a regular entry followed by 8 bytes data. ATM
+ * I don't know how things are organized if were get next to the
+ * a boundary so I worry about that once we try to handle that.
+ */
+ evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
+ left -= 4;
+
+ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
+{
+ struct dwc3 *dwc = _dwc;
+ int i;
+ irqreturn_t ret = IRQ_NONE;
+
+ spin_lock(&dwc->lock);
+
+ for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) {
+ irqreturn_t status;
+
+ status = dwc3_process_event_buf(dwc, i);
+ if (status == IRQ_HANDLED)
+ ret = status;
+ }
+
+ spin_unlock(&dwc->lock);
+
+ return ret;
+}
+
+/**
+ * dwc3_gadget_init - Initializes gadget related registers
+ * @dwc: Pointer to out controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+int __devinit dwc3_gadget_init(struct dwc3 *dwc)
+{
+ u32 reg;
+ int ret;
+ int irq;
+
+ dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
+ &dwc->ctrl_req_addr, GFP_KERNEL);
+ if (!dwc->ctrl_req) {
+ dev_err(dwc->dev, "failed to allocate ctrl request\n");
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ dwc->ep0_trb = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+ &dwc->ep0_trb_addr, GFP_KERNEL);
+ if (!dwc->ep0_trb) {
+ dev_err(dwc->dev, "failed to allocate ep0 trb\n");
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ dwc->setup_buf = dma_alloc_coherent(dwc->dev,
+ sizeof(*dwc->setup_buf) * 2,
+ &dwc->setup_buf_addr, GFP_KERNEL);
+ if (!dwc->setup_buf) {
+ dev_err(dwc->dev, "failed to allocate setup buffer\n");
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ dwc->ep0_bounce = dma_alloc_coherent(dwc->dev,
+ 512, &dwc->ep0_bounce_addr, GFP_KERNEL);
+ if (!dwc->ep0_bounce) {
+ dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n");
+ ret = -ENOMEM;
+ goto err3;
+ }
+
+ dev_set_name(&dwc->gadget.dev, "gadget");
+
+ dwc->gadget.ops = &dwc3_gadget_ops;
+ dwc->gadget.is_dualspeed = true;
+ dwc->gadget.speed = USB_SPEED_UNKNOWN;
+ dwc->gadget.dev.parent = dwc->dev;
+
+ dma_set_coherent_mask(&dwc->gadget.dev, dwc->dev->coherent_dma_mask);
+
+ dwc->gadget.dev.dma_parms = dwc->dev->dma_parms;
+ dwc->gadget.dev.dma_mask = dwc->dev->dma_mask;
+ dwc->gadget.dev.release = dwc3_gadget_release;
+ dwc->gadget.name = "dwc3-gadget";
+
+ /*
+ * REVISIT: Here we should clear all pending IRQs to be
+ * sure we're starting from a well known location.
+ */
+
+ ret = dwc3_gadget_init_endpoints(dwc);
+ if (ret)
+ goto err4;
+
+ irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+
+ ret = request_irq(irq, dwc3_interrupt, IRQF_SHARED,
+ "dwc3", dwc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
+ irq, ret);
+ goto err5;
+ }
+
+ /* Enable all but Start and End of Frame IRQs */
+ reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
+ DWC3_DEVTEN_EVNTOVERFLOWEN |
+ DWC3_DEVTEN_CMDCMPLTEN |
+ DWC3_DEVTEN_ERRTICERREN |
+ DWC3_DEVTEN_WKUPEVTEN |
+ DWC3_DEVTEN_ULSTCNGEN |
+ DWC3_DEVTEN_CONNECTDONEEN |
+ DWC3_DEVTEN_USBRSTEN |
+ DWC3_DEVTEN_DISCONNEVTEN);
+ dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
+
+ ret = device_register(&dwc->gadget.dev);
+ if (ret) {
+ dev_err(dwc->dev, "failed to register gadget device\n");
+ put_device(&dwc->gadget.dev);
+ goto err6;
+ }
+
+ ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
+ if (ret) {
+ dev_err(dwc->dev, "failed to register udc\n");
+ goto err7;
+ }
+
+ return 0;
+
+err7:
+ device_unregister(&dwc->gadget.dev);
+
+err6:
+ dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
+ free_irq(irq, dwc);
+
+err5:
+ dwc3_gadget_free_endpoints(dwc);
+
+err4:
+ dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
+ dwc->ep0_bounce_addr);
+
+err3:
+ dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
+ dwc->setup_buf, dwc->setup_buf_addr);
+
+err2:
+ dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+ dwc->ep0_trb, dwc->ep0_trb_addr);
+
+err1:
+ dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
+ dwc->ctrl_req, dwc->ctrl_req_addr);
+
+err0:
+ return ret;
+}
+
+void dwc3_gadget_exit(struct dwc3 *dwc)
+{
+ int irq;
+ int i;
+
+ usb_del_gadget_udc(&dwc->gadget);
+ irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+
+ dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
+ free_irq(irq, dwc);
+
+ for (i = 0; i < ARRAY_SIZE(dwc->eps); i++)
+ __dwc3_gadget_ep_disable(dwc->eps[i]);
+
+ dwc3_gadget_free_endpoints(dwc);
+
+ dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
+ dwc->ep0_bounce_addr);
+
+ dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
+ dwc->setup_buf, dwc->setup_buf_addr);
+
+ dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+ dwc->ep0_trb, dwc->ep0_trb_addr);
+
+ dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
+ dwc->ctrl_req, dwc->ctrl_req_addr);
+
+ device_unregister(&dwc->gadget.dev);
+}
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
new file mode 100644
index 000000000000..71145a449d99
--- /dev/null
+++ b/drivers/usb/dwc3/gadget.h
@@ -0,0 +1,211 @@
+/**
+ * gadget.h - DesignWare USB3 DRD Gadget Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * 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 __DRIVERS_USB_DWC3_GADGET_H
+#define __DRIVERS_USB_DWC3_GADGET_H
+
+#include <linux/list.h>
+#include <linux/usb/gadget.h>
+#include "io.h"
+
+struct dwc3;
+#define to_dwc3_ep(ep) (container_of(ep, struct dwc3_ep, endpoint))
+#define gadget_to_dwc(g) (container_of(g, struct dwc3, gadget))
+
+/* DEPCFG parameter 1 */
+#define DWC3_DEPCFG_INT_NUM(n) ((n) << 0)
+#define DWC3_DEPCFG_XFER_COMPLETE_EN (1 << 8)
+#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN (1 << 9)
+#define DWC3_DEPCFG_XFER_NOT_READY_EN (1 << 10)
+#define DWC3_DEPCFG_FIFO_ERROR_EN (1 << 11)
+#define DWC3_DEPCFG_STREAM_EVENT_EN (1 << 13)
+#define DWC3_DEPCFG_BINTERVAL_M1(n) ((n) << 16)
+#define DWC3_DEPCFG_STREAM_CAPABLE (1 << 24)
+#define DWC3_DEPCFG_EP_NUMBER(n) ((n) << 25)
+#define DWC3_DEPCFG_BULK_BASED (1 << 30)
+#define DWC3_DEPCFG_FIFO_BASED (1 << 31)
+
+/* DEPCFG parameter 0 */
+#define DWC3_DEPCFG_EP_TYPE(n) ((n) << 1)
+#define DWC3_DEPCFG_MAX_PACKET_SIZE(n) ((n) << 3)
+#define DWC3_DEPCFG_FIFO_NUMBER(n) ((n) << 17)
+#define DWC3_DEPCFG_BURST_SIZE(n) ((n) << 22)
+#define DWC3_DEPCFG_DATA_SEQ_NUM(n) ((n) << 26)
+#define DWC3_DEPCFG_IGN_SEQ_NUM (1 << 31)
+
+/* DEPXFERCFG parameter 0 */
+#define DWC3_DEPXFERCFG_NUM_XFER_RES(n) ((n) & 0xffff)
+
+struct dwc3_gadget_ep_cmd_params {
+ u32 param2;
+ u32 param1;
+ u32 param0;
+};
+
+/* -------------------------------------------------------------------------- */
+
+struct dwc3_request {
+ struct usb_request request;
+ struct list_head list;
+ struct dwc3_ep *dep;
+
+ u8 epnum;
+ struct dwc3_trb_hw *trb;
+ dma_addr_t trb_dma;
+
+ unsigned direction:1;
+ unsigned mapped:1;
+ unsigned queued:1;
+};
+#define to_dwc3_request(r) (container_of(r, struct dwc3_request, request))
+
+static inline struct dwc3_request *next_request(struct list_head *list)
+{
+ if (list_empty(list))
+ return NULL;
+
+ return list_first_entry(list, struct dwc3_request, list);
+}
+
+static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)
+{
+ struct dwc3_ep *dep = req->dep;
+
+ req->queued = true;
+ list_move_tail(&req->list, &dep->req_queued);
+}
+
+#if defined(CONFIG_USB_GADGET_DWC3) || defined(CONFIG_USB_GADGET_DWC3_MODULE)
+int dwc3_gadget_init(struct dwc3 *dwc);
+void dwc3_gadget_exit(struct dwc3 *dwc);
+#else
+static inline int dwc3_gadget_init(struct dwc3 *dwc) { return 0; }
+static inline void dwc3_gadget_exit(struct dwc3 *dwc) { }
+static inline int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
+ unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
+{
+ return 0;
+}
+#endif
+
+void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
+ int status);
+
+void dwc3_ep0_interrupt(struct dwc3 *dwc, const struct dwc3_event_depevt *event);
+void dwc3_ep0_out_start(struct dwc3 *dwc);
+int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
+ gfp_t gfp_flags);
+int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
+int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
+ unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
+void dwc3_map_buffer_to_dma(struct dwc3_request *req);
+void dwc3_unmap_buffer_from_dma(struct dwc3_request *req);
+
+/**
+ * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
+ * @dwc: DesignWare USB3 Pointer
+ * @number: DWC endpoint number
+ *
+ * Caller should take care of locking
+ */
+static inline u32 dwc3_gadget_ep_get_transfer_index(struct dwc3 *dwc, u8 number)
+{
+ u32 res_id;
+
+ res_id = dwc3_readl(dwc->regs, DWC3_DEPCMD(number));
+
+ return DWC3_DEPCMD_GET_RSC_IDX(res_id);
+}
+
+/**
+ * dwc3_gadget_event_string - returns event name
+ * @event: the event code
+ */
+static inline const char *dwc3_gadget_event_string(u8 event)
+{
+ switch (event) {
+ case DWC3_DEVICE_EVENT_DISCONNECT:
+ return "Disconnect";
+ case DWC3_DEVICE_EVENT_RESET:
+ return "Reset";
+ case DWC3_DEVICE_EVENT_CONNECT_DONE:
+ return "Connection Done";
+ case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
+ return "Link Status Change";
+ case DWC3_DEVICE_EVENT_WAKEUP:
+ return "WakeUp";
+ case DWC3_DEVICE_EVENT_EOPF:
+ return "End-Of-Frame";
+ case DWC3_DEVICE_EVENT_SOF:
+ return "Start-Of-Frame";
+ case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
+ return "Erratic Error";
+ case DWC3_DEVICE_EVENT_CMD_CMPL:
+ return "Command Complete";
+ case DWC3_DEVICE_EVENT_OVERFLOW:
+ return "Overflow";
+ }
+
+ return "UNKNOWN";
+}
+
+/**
+ * dwc3_ep_event_string - returns event name
+ * @event: then event code
+ */
+static inline const char *dwc3_ep_event_string(u8 event)
+{
+ switch (event) {
+ case DWC3_DEPEVT_XFERCOMPLETE:
+ return "Transfer Complete";
+ case DWC3_DEPEVT_XFERINPROGRESS:
+ return "Transfer In-Progress";
+ case DWC3_DEPEVT_XFERNOTREADY:
+ return "Transfer Not Ready";
+ case DWC3_DEPEVT_RXTXFIFOEVT:
+ return "FIFO";
+ case DWC3_DEPEVT_STREAMEVT:
+ return "Stream";
+ case DWC3_DEPEVT_EPCMDCMPLT:
+ return "Endpoint Command Complete";
+ }
+
+ return "UNKNOWN";
+}
+
+#endif /* __DRIVERS_USB_DWC3_GADGET_H */
diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h
new file mode 100644
index 000000000000..bc957db1ea4b
--- /dev/null
+++ b/drivers/usb/dwc3/io.h
@@ -0,0 +1,54 @@
+/**
+ * io.h - DesignWare USB3 DRD IO Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * 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 __DRIVERS_USB_DWC3_IO_H
+#define __DRIVERS_USB_DWC3_IO_H
+
+#include <asm/io.h>
+
+static inline u32 dwc3_readl(void __iomem *base, u32 offset)
+{
+ return readl(base + offset);
+}
+
+static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
+{
+ writel(value, base + offset);
+}
+
+#endif /* __DRIVERS_USB_DWC3_IO_H */
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 5a084b9cfa3c..b21cd376c11a 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -96,6 +96,22 @@ config USB_GADGET_VBUS_DRAW
This value will be used except for system-specific gadget
drivers that have more specific information.
+config USB_GADGET_STORAGE_NUM_BUFFERS
+ int "Number of storage pipeline buffers"
+ range 2 4
+ default 2
+ help
+ Usually 2 buffers are enough to establish a good buffering
+ pipeline. The number may be increased in order to compensate
+ for a bursty VFS behaviour. For instance there may be CPU wake up
+ latencies that makes the VFS to appear bursty in a system with
+ an CPU on-demand governor. Especially if DMA is doing IO to
+ offload the CPU. In this case the CPU will go into power
+ save often and spin up occasionally to move data within VFS.
+ If selecting USB_GADGET_DEBUG_FILES this value may be set by
+ a module parameter as well.
+ If unsure, say 2.
+
#
# USB Peripheral Controller Support
#
@@ -255,12 +271,11 @@ config USB_S3C_HSOTG
integrated into the S3C64XX series SoC.
config USB_IMX
- tristate "Freescale IMX USB Peripheral Controller"
- depends on ARCH_MX1
+ tristate "Freescale i.MX1 USB Peripheral Controller"
+ depends on ARCH_MXC
help
- Freescale's IMX series include an integrated full speed
- USB 1.1 device controller. The controller in the IMX series
- is register-compatible.
+ Freescale's i.MX1 includes an integrated full speed
+ USB 1.1 device controller.
It has Six fixed-function endpoints, as well as endpoint
zero (for control transfers).
@@ -303,6 +318,18 @@ config USB_PXA_U2O
PXA9xx Processor series include a high speed USB2.0 device
controller, which support high speed and full speed USB peripheral.
+config USB_GADGET_DWC3
+ tristate "DesignWare USB3.0 (DRD) Controller"
+ depends on USB_DWC3
+ select USB_GADGET_DUALSPEED
+ select USB_GADGET_SUPERSPEED
+ help
+ DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller
+ which can be configured for peripheral-only, host-only, hub-only
+ and Dual-Role operation. This Controller was first integrated into
+ the OMAP5 series of processors. More information about the OMAP5
+ version of this controller, refer to http://www.ti.com/omap5.
+
#
# Controllers available in both integrated and discrete versions
#
@@ -846,6 +873,16 @@ config USB_G_NOKIA
It's only really useful for N900 hardware. If you're building
a kernel for N900, say Y or M here. If unsure, say N.
+config USB_G_ACM_MS
+ tristate "CDC Composite Device (ACM and mass storage)"
+ depends on BLOCK
+ help
+ This driver provides two functions in one configuration:
+ a mass storage, and a CDC ACM (serial port) link.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "g_acm_ms".
+
config USB_G_MULTI
tristate "Multifunction Composite Gadget (EXPERIMENTAL)"
depends on BLOCK && NET
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 9ba725af4a08..b54ac6190890 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -28,7 +28,7 @@ obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o
obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o
obj-$(CONFIG_USB_EG20T) += pch_udc.o
obj-$(CONFIG_USB_PXA_U2O) += mv_udc.o
-mv_udc-y := mv_udc_core.o mv_udc_phy.o
+mv_udc-y := mv_udc_core.o
obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o
obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o
@@ -51,6 +51,7 @@ g_dbgp-y := dbgp.o
g_nokia-y := nokia.o
g_webcam-y := webcam.o
g_ncm-y := ncm.o
+g_acm_ms-y := acm_ms.o
obj-$(CONFIG_USB_ZERO) += g_zero.o
obj-$(CONFIG_USB_AUDIO) += g_audio.o
@@ -69,3 +70,4 @@ obj-$(CONFIG_USB_G_MULTI) += g_multi.o
obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o
obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o
obj-$(CONFIG_USB_G_NCM) += g_ncm.o
+obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o
diff --git a/drivers/usb/gadget/acm_ms.c b/drivers/usb/gadget/acm_ms.c
new file mode 100644
index 000000000000..fdb7aec3bd0c
--- /dev/null
+++ b/drivers/usb/gadget/acm_ms.c
@@ -0,0 +1,256 @@
+/*
+ * acm_ms.c -- Composite driver, with ACM and mass storage support
+ *
+ * Copyright (C) 2008 David Brownell
+ * Copyright (C) 2008 Nokia Corporation
+ * Author: David Brownell
+ * Modified: Klaus Schwarzkopf <schwarzkopf@sensortherm.de>
+ *
+ * Heavily based on multi.c and cdc2.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/utsname.h>
+
+#include "u_serial.h"
+
+#define DRIVER_DESC "Composite Gadget (ACM + MS)"
+#define DRIVER_VERSION "2011/10/10"
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
+ * Instead: allocate your own, using normal USB-IF procedures.
+ */
+#define ACM_MS_VENDOR_NUM 0x1d6b /* Linux Foundation */
+#define ACM_MS_PRODUCT_NUM 0x0106 /* Composite Gadget: ACM + MS*/
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Kbuild is not very cooperative with respect to linking separately
+ * compiled library objects into one module. So for now we won't use
+ * separate compilation ... ensuring init/exit sections work to shrink
+ * the runtime footprint, and giving us at least some parts of what
+ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
+ */
+
+#include "composite.c"
+#include "usbstring.c"
+#include "config.c"
+#include "epautoconf.c"
+#include "u_serial.c"
+#include "f_acm.c"
+#include "f_mass_storage.c"
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_device_descriptor device_desc = {
+ .bLength = sizeof device_desc,
+ .bDescriptorType = USB_DT_DEVICE,
+
+ .bcdUSB = cpu_to_le16(0x0200),
+
+ .bDeviceClass = USB_CLASS_MISC /* 0xEF */,
+ .bDeviceSubClass = 2,
+ .bDeviceProtocol = 1,
+
+ /* .bMaxPacketSize0 = f(hardware) */
+
+ /* Vendor and product id can be overridden by module parameters. */
+ .idVendor = cpu_to_le16(ACM_MS_VENDOR_NUM),
+ .idProduct = cpu_to_le16(ACM_MS_PRODUCT_NUM),
+ /* .bcdDevice = f(hardware) */
+ /* .iManufacturer = DYNAMIC */
+ /* .iProduct = DYNAMIC */
+ /* NO SERIAL NUMBER */
+ /*.bNumConfigurations = DYNAMIC*/
+};
+
+static struct usb_otg_descriptor otg_descriptor = {
+ .bLength = sizeof otg_descriptor,
+ .bDescriptorType = USB_DT_OTG,
+
+ /*
+ * REVISIT SRP-only hardware is possible, although
+ * it would not be called "OTG" ...
+ */
+ .bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
+};
+
+static const struct usb_descriptor_header *otg_desc[] = {
+ (struct usb_descriptor_header *) &otg_descriptor,
+ NULL,
+};
+
+
+/* string IDs are assigned dynamically */
+
+#define STRING_MANUFACTURER_IDX 0
+#define STRING_PRODUCT_IDX 1
+
+static char manufacturer[50];
+
+static struct usb_string strings_dev[] = {
+ [STRING_MANUFACTURER_IDX].s = manufacturer,
+ [STRING_PRODUCT_IDX].s = DRIVER_DESC,
+ { } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+ .language = 0x0409, /* en-us */
+ .strings = strings_dev,
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+ &stringtab_dev,
+ NULL,
+};
+
+/****************************** Configurations ******************************/
+
+static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
+FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
+
+static struct fsg_common fsg_common;
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * We _always_ have both ACM and mass storage functions.
+ */
+static int __init acm_ms_do_config(struct usb_configuration *c)
+{
+ int status;
+
+ if (gadget_is_otg(c->cdev->gadget)) {
+ c->descriptors = otg_desc;
+ c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ }
+
+
+ status = acm_bind_config(c, 0);
+ if (status < 0)
+ return status;
+
+ status = fsg_bind_config(c->cdev, c, &fsg_common);
+ if (status < 0)
+ return status;
+
+ return 0;
+}
+
+static struct usb_configuration acm_ms_config_driver = {
+ .label = DRIVER_DESC,
+ .bConfigurationValue = 1,
+ /* .iConfiguration = DYNAMIC */
+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init acm_ms_bind(struct usb_composite_dev *cdev)
+{
+ int gcnum;
+ struct usb_gadget *gadget = cdev->gadget;
+ int status;
+ void *retp;
+
+ /* set up serial link layer */
+ status = gserial_setup(cdev->gadget, 1);
+ if (status < 0)
+ return status;
+
+ /* set up mass storage function */
+ retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data);
+ if (IS_ERR(retp)) {
+ status = PTR_ERR(retp);
+ goto fail0;
+ }
+
+ /* set bcdDevice */
+ gcnum = usb_gadget_controller_number(gadget);
+ if (gcnum >= 0) {
+ device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
+ } else {
+ WARNING(cdev, "controller '%s' not recognized; trying %s\n",
+ gadget->name,
+ acm_ms_config_driver.label);
+ device_desc.bcdDevice =
+ cpu_to_le16(0x0300 | 0x0099);
+ }
+
+ /*
+ * Allocate string descriptor numbers ... note that string
+ * contents can be overridden by the composite_dev glue.
+ */
+
+ /* device descriptor strings: manufacturer, product */
+ snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
+ init_utsname()->sysname, init_utsname()->release,
+ gadget->name);
+ status = usb_string_id(cdev);
+ if (status < 0)
+ goto fail1;
+ strings_dev[STRING_MANUFACTURER_IDX].id = status;
+ device_desc.iManufacturer = status;
+
+ status = usb_string_id(cdev);
+ if (status < 0)
+ goto fail1;
+ strings_dev[STRING_PRODUCT_IDX].id = status;
+ device_desc.iProduct = status;
+
+ /* register our configuration */
+ status = usb_add_config(cdev, &acm_ms_config_driver, acm_ms_do_config);
+ if (status < 0)
+ goto fail1;
+
+ dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
+ DRIVER_DESC);
+ fsg_common_put(&fsg_common);
+ return 0;
+
+ /* error recovery */
+fail1:
+ fsg_common_put(&fsg_common);
+fail0:
+ gserial_cleanup();
+ return status;
+}
+
+static int __exit acm_ms_unbind(struct usb_composite_dev *cdev)
+{
+ gserial_cleanup();
+
+ return 0;
+}
+
+static struct usb_composite_driver acm_ms_driver = {
+ .name = "g_acm_ms",
+ .dev = &device_desc,
+ .strings = dev_strings,
+ .unbind = __exit_p(acm_ms_unbind),
+};
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Klaus Schwarzkopf <schwarzkopf@sensortherm.de>");
+MODULE_LICENSE("GPL v2");
+
+static int __init init(void)
+{
+ return usb_composite_probe(&acm_ms_driver, acm_ms_bind);
+}
+module_init(init);
+
+static void __exit cleanup(void)
+{
+ usb_composite_unregister(&acm_ms_driver);
+}
+module_exit(cleanup);
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index 70f2b376c86d..4730016d7cd4 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -8,15 +8,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
@@ -354,7 +345,7 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
writel(tmp, &dev->ep[ep->num].regs->ctl);
/* set max packet size */
- maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+ maxpacket = usb_endpoint_maxp(desc);
tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt);
tmp = AMD_ADDBITS(tmp, maxpacket, UDC_EP_MAX_PKT_SIZE);
ep->ep.maxpacket = maxpacket;
@@ -3014,13 +3005,8 @@ __acquires(dev->lock)
/* link up all endpoints */
udc_setup_endpoints(dev);
- if (dev->gadget.speed == USB_SPEED_HIGH) {
- dev_info(&dev->pdev->dev, "Connect: speed = %s\n",
- "high");
- } else if (dev->gadget.speed == USB_SPEED_FULL) {
- dev_info(&dev->pdev->dev, "Connect: speed = %s\n",
- "full");
- }
+ dev_info(&dev->pdev->dev, "Connect: %s\n",
+ usb_speed_string(dev->gadget.speed));
/* init ep 0 */
activate_control_endpoints(dev);
diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h
index 1d1c7543468e..f87e29c65325 100644
--- a/drivers/usb/gadget/amd5536udc.h
+++ b/drivers/usb/gadget/amd5536udc.h
@@ -8,15 +8,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef AMD5536UDC_H
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index ddb118a76807..8efe0fa9228d 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -9,16 +9,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
*/
#undef VERBOSE_DEBUG
@@ -460,7 +450,7 @@ static void nuke(struct at91_ep *ep, int status)
{
struct at91_request *req;
- // terminer chaque requete dans la queue
+ /* terminate any request in the queue */
ep->stopped = 1;
if (list_empty(&ep->queue))
return;
@@ -487,7 +477,7 @@ static int at91_ep_enable(struct usb_ep *_ep,
|| !desc || ep->desc
|| _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT
- || (maxpacket = le16_to_cpu(desc->wMaxPacketSize)) == 0
+ || (maxpacket = usb_endpoint_maxp(desc)) == 0
|| maxpacket > ep->maxpacket) {
DBG("bad ep or descriptor\n");
return -EINVAL;
@@ -788,7 +778,7 @@ static const struct usb_ep_ops at91_ep_ops = {
.queue = at91_ep_queue,
.dequeue = at91_ep_dequeue,
.set_halt = at91_ep_set_halt,
- // there's only imprecise fifo status reporting
+ /* there's only imprecise fifo status reporting */
};
/*-------------------------------------------------------------------------*/
@@ -846,7 +836,7 @@ static void udc_reinit(struct at91_udc *udc)
ep->fifo_bank = 0;
ep->ep.maxpacket = ep->maxpacket;
ep->creg = (void __iomem *) udc->udp_baseaddr + AT91_UDP_CSR(i);
- // initialiser une queue par endpoint
+ /* initialize one queue per endpoint */
INIT_LIST_HEAD(&ep->queue);
}
}
@@ -952,7 +942,7 @@ static int at91_vbus_session(struct usb_gadget *gadget, int is_active)
struct at91_udc *udc = to_udc(gadget);
unsigned long flags;
- // VDBG("vbus %s\n", is_active ? "on" : "off");
+ /* VDBG("vbus %s\n", is_active ? "on" : "off"); */
spin_lock_irqsave(&udc->lock, flags);
udc->vbus = (is_active != 0);
if (udc->driver)
@@ -1003,7 +993,7 @@ static const struct usb_gadget_ops at91_udc_ops = {
* VBUS-powered devices may also also want to support bigger
* power budgets after an appropriate SET_CONFIGURATION.
*/
- // .vbus_power = at91_vbus_power,
+ /* .vbus_power = at91_vbus_power, */
};
/*-------------------------------------------------------------------------*/
@@ -1072,7 +1062,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
ep->is_in = 0;
}
} else {
- // REVISIT this happens sometimes under load; why??
+ /* REVISIT this happens sometimes under load; why?? */
ERR("SETUP len %d, csr %08x\n", rxcount, csr);
status = -EINVAL;
}
@@ -1451,7 +1441,7 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc)
at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXSUSP);
at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXRSM);
at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXSUSP);
- // VDBG("bus suspend\n");
+ /* VDBG("bus suspend\n"); */
if (udc->suspended)
continue;
udc->suspended = 1;
@@ -1473,7 +1463,7 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc)
at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM);
at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXSUSP);
at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM);
- // VDBG("bus resume\n");
+ /* VDBG("bus resume\n"); */
if (!udc->suspended)
continue;
udc->suspended = 0;
@@ -1820,7 +1810,7 @@ static int __init at91udc_probe(struct platform_device *pdev)
/* request UDC and maybe VBUS irqs */
udc->udp_irq = platform_get_irq(pdev, 0);
retval = request_irq(udc->udp_irq, at91_udc_irq,
- IRQF_DISABLED, driver_name, udc);
+ 0, driver_name, udc);
if (retval < 0) {
DBG("request irq %d failed\n", udc->udp_irq);
goto fail1;
@@ -1848,7 +1838,7 @@ static int __init at91udc_probe(struct platform_device *pdev)
jiffies + VBUS_POLL_TIMEOUT);
} else {
if (request_irq(udc->board.vbus_pin, at91_vbus_irq,
- IRQF_DISABLED, driver_name, udc)) {
+ 0, driver_name, udc)) {
DBG("request vbus irq %d failed\n",
udc->board.vbus_pin);
retval = -EBUSY;
diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
index 108ca54f9092..3c0315b86ace 100644
--- a/drivers/usb/gadget/at91_udc.h
+++ b/drivers/usb/gadget/at91_udc.h
@@ -7,16 +7,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the
- * Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef AT91_UDC_H
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index 5b1665eb1bef..271a9d873608 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -527,7 +527,7 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc);
- maxpacket = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
+ maxpacket = usb_endpoint_maxp(desc) & 0x7ff;
if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index)
|| ep->index == 0
@@ -571,7 +571,7 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
* Bits 11:12 specify number of _additional_
* transactions per microframe.
*/
- nr_trans = ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 3) + 1;
+ nr_trans = ((usb_endpoint_maxp(desc) >> 11) & 3) + 1;
if (nr_trans > 3)
return -EINVAL;
@@ -1718,13 +1718,12 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
spin_lock(&udc->lock);
}
- if (status & USBA_HIGH_SPEED) {
- DBG(DBG_BUS, "High-speed bus reset detected\n");
+ if (status & USBA_HIGH_SPEED)
udc->gadget.speed = USB_SPEED_HIGH;
- } else {
- DBG(DBG_BUS, "Full-speed bus reset detected\n");
+ else
udc->gadget.speed = USB_SPEED_FULL;
- }
+ DBG(DBG_BUS, "%s bus reset detected\n",
+ usb_speed_string(udc->gadget.speed));
ep0 = &usba_ep[0];
ep0->desc = &usba_ep0_desc;
diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c
index b1c1afbb8750..672674c2fb3d 100644
--- a/drivers/usb/gadget/cdc2.c
+++ b/drivers/usb/gadget/cdc2.c
@@ -8,15 +8,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index 470981ad6f77..4eedfe557154 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -3,17 +3,6 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
*/
#include <linux/module.h>
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 1265a8502ea0..83428f56253b 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2101,7 +2101,7 @@ static int ep_enable(struct usb_ep *ep,
mEp->num = usb_endpoint_num(desc);
mEp->type = usb_endpoint_type(desc);
- mEp->ep.maxpacket = __constant_le16_to_cpu(desc->wMaxPacketSize);
+ mEp->ep.maxpacket = usb_endpoint_maxp(desc);
dbg_event(_usb_addr(mEp), "ENABLE", 0);
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index aef47414f5d5..8a5529d214fb 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -7,15 +7,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* #define VERBOSE_DEBUG */
@@ -164,7 +155,7 @@ int config_ep_by_speed(struct usb_gadget *g,
ep_found:
/* commit results */
- _ep->maxpacket = le16_to_cpu(chosen_desc->wMaxPacketSize);
+ _ep->maxpacket = usb_endpoint_maxp(chosen_desc);
_ep->desc = chosen_desc;
_ep->comp_desc = NULL;
_ep->maxburst = 0;
@@ -551,9 +542,9 @@ static int bos_desc(struct usb_composite_dev *cdev)
if (cdev->gadget->ops->get_config_params)
cdev->gadget->ops->get_config_params(&dcd_config_params);
else {
- dcd_config_params.bU1devExitLat = USB_DEFULT_U1_DEV_EXIT_LAT;
+ dcd_config_params.bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT;
dcd_config_params.bU2DevExitLat =
- cpu_to_le16(USB_DEFULT_U2_DEV_EXIT_LAT);
+ cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
}
ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
@@ -626,25 +617,9 @@ static int set_config(struct usb_composite_dev *cdev,
result = 0;
}
- INFO(cdev, "%s speed config #%d: %s\n",
- ({ char *speed;
- switch (gadget->speed) {
- case USB_SPEED_LOW:
- speed = "low";
- break;
- case USB_SPEED_FULL:
- speed = "full";
- break;
- case USB_SPEED_HIGH:
- speed = "high";
- break;
- case USB_SPEED_SUPER:
- speed = "super";
- break;
- default:
- speed = "?";
- break;
- } ; speed; }), number, c ? c->label : "unconfigured");
+ INFO(cdev, "%s config #%d: %s\n",
+ usb_speed_string(gadget->speed),
+ number, c ? c->label : "unconfigured");
if (!c)
goto done;
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
index b2c001334876..7542a72ce51a 100644
--- a/drivers/usb/gadget/config.c
+++ b/drivers/usb/gadget/config.c
@@ -7,15 +7,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/errno.h>
diff --git a/drivers/usb/gadget/dbgp.c b/drivers/usb/gadget/dbgp.c
index 8beefdd36787..f855ecf7a637 100644
--- a/drivers/usb/gadget/dbgp.c
+++ b/drivers/usb/gadget/dbgp.c
@@ -4,7 +4,6 @@
* Copyright (C) 2010 Stephane Duverger
*
* Released under the GPLv2.
- *
*/
/* verbose messages */
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index e755a9d267fc..ab8f1b488d54 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -10,15 +10,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -439,7 +430,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
* maximum packet size.
* For SS devices the wMaxPacketSize is limited by 1024.
*/
- max = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
+ max = usb_endpoint_maxp(desc) & 0x7ff;
/* drivers must not request bad settings, since lower levels
* (hardware or its drivers) may not check. some endpoints
@@ -1277,7 +1268,7 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
int tmp;
/* high bandwidth mode */
- tmp = le16_to_cpu(ep->desc->wMaxPacketSize);
+ tmp = usb_endpoint_maxp(ep->desc);
tmp = (tmp >> 11) & 0x03;
tmp *= 8 /* applies to entire frame */;
limit += limit * tmp;
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 7a7e6b7e1fd6..596a0b464e61 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -7,16 +7,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
#include <linux/kernel.h>
@@ -158,7 +148,7 @@ ep_matches (
* where it's an output parameter representing the full speed limit.
* the usb spec fixes high speed bulk maxpacket at 512 bytes.
*/
- max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);
+ max = 0x7ff & usb_endpoint_maxp(desc);
switch (type) {
case USB_ENDPOINT_XFER_INT:
/* INT: limit 64 bytes full speed, 1024 high/super speed */
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index aafc84f33e26..0cd764d59351 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -9,15 +9,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* #define VERBOSE_DEBUG */
diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c
index a9a4eade7e80..ec7ffcd0d0cd 100644
--- a/drivers/usb/gadget/f_audio.c
+++ b/drivers/usb/gadget/f_audio.c
@@ -460,7 +460,7 @@ static int audio_set_endpoint_req(struct usb_function *f,
switch (ctrl->bRequest) {
case UAC_SET_CUR:
- value = 0;
+ value = len;
break;
case UAC_SET_MIN:
@@ -499,7 +499,7 @@ static int audio_get_endpoint_req(struct usb_function *f,
case UAC_GET_MIN:
case UAC_GET_MAX:
case UAC_GET_RES:
- value = 3;
+ value = len;
break;
case UAC_GET_MEM:
break;
@@ -681,17 +681,18 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
status = -ENOMEM;
- /* supcard all relevant hardware speeds... we expect that when
+ /* copy descriptors, and track endpoint copies */
+ f->descriptors = usb_copy_descriptors(f_audio_desc);
+
+ /*
+ * support all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at
* both speeds
*/
-
- /* copy descriptors, and track endpoint copies */
if (gadget_is_dualspeed(c->cdev->gadget)) {
c->highspeed = true;
f->hs_descriptors = usb_copy_descriptors(f_audio_desc);
- } else
- f->descriptors = usb_copy_descriptors(f_audio_desc);
+ }
return 0;
diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c
index 3691a0cb9465..11c07cb7d337 100644
--- a/drivers/usb/gadget/f_ecm.c
+++ b/drivers/usb/gadget/f_ecm.c
@@ -8,15 +8,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* #define VERBOSE_DEBUG */
diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c
index 046c6d0e6960..1a7b2dd7d408 100644
--- a/drivers/usb/gadget/f_eem.c
+++ b/drivers/usb/gadget/f_eem.c
@@ -9,15 +9,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index c161a9aaeb7e..6b1c20b6c9b2 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -12,15 +12,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c
index 83a266bdb40e..b2113420b806 100644
--- a/drivers/usb/gadget/f_hid.c
+++ b/drivers/usb/gadget/f_hid.c
@@ -7,15 +7,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c
index ca660d40b11a..6d87f288df4e 100644
--- a/drivers/usb/gadget/f_loopback.c
+++ b/drivers/usb/gadget/f_loopback.c
@@ -8,15 +8,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* #define VERBOSE_DEBUG */
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 5b9339582007..52583a235330 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -112,8 +112,7 @@
* is not loaded (an empty string as "filename" in the fsg_config
* structure causes error). The CD-ROM emulation includes a single
* data track and no audio tracks; hence there need be only one
- * backing file per LUN. Note also that the CD-ROM block length is
- * set to 512 rather than the more common value 2048.
+ * backing file per LUN.
*
*
* MSF includes support for module parameters. If gadget using it
@@ -363,7 +362,7 @@ struct fsg_common {
struct fsg_buffhd *next_buffhd_to_fill;
struct fsg_buffhd *next_buffhd_to_drain;
- struct fsg_buffhd buffhds[FSG_NUM_BUFFERS];
+ struct fsg_buffhd *buffhds;
int cmnd_size;
u8 cmnd[MAX_COMMAND_SIZE];
@@ -745,7 +744,6 @@ static int do_read(struct fsg_common *common)
u32 amount_left;
loff_t file_offset, file_offset_tmp;
unsigned int amount;
- unsigned int partial_page;
ssize_t nread;
/*
@@ -771,7 +769,7 @@ static int do_read(struct fsg_common *common)
curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
return -EINVAL;
}
- file_offset = ((loff_t) lba) << 9;
+ file_offset = ((loff_t) lba) << curlun->blkbits;
/* Carry out the file reads */
amount_left = common->data_size_from_cmnd;
@@ -784,18 +782,10 @@ static int do_read(struct fsg_common *common)
* Try to read the remaining amount.
* But don't read more than the buffer size.
* And don't try to read past the end of the file.
- * Finally, if we're not at a page boundary, don't read past
- * the next page.
- * If this means reading 0 then we were asked to read past
- * the end of file.
*/
amount = min(amount_left, FSG_BUFLEN);
amount = min((loff_t)amount,
curlun->file_length - file_offset);
- partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
- if (partial_page > 0)
- amount = min(amount, (unsigned int)PAGE_CACHE_SIZE -
- partial_page);
/* Wait for the next buffer to become available */
bh = common->next_buffhd_to_fill;
@@ -812,7 +802,8 @@ static int do_read(struct fsg_common *common)
if (amount == 0) {
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info =
+ file_offset >> curlun->blkbits;
curlun->info_valid = 1;
bh->inreq->length = 0;
bh->state = BUF_STATE_FULL;
@@ -835,18 +826,25 @@ static int do_read(struct fsg_common *common)
} else if (nread < amount) {
LDBG(curlun, "partial file read: %d/%u\n",
(int)nread, amount);
- nread -= (nread & 511); /* Round down to a block */
+ nread = round_down(nread, curlun->blksize);
}
file_offset += nread;
amount_left -= nread;
common->residue -= nread;
+
+ /*
+ * Except at the end of the transfer, nread will be
+ * equal to the buffer size, which is divisible by the
+ * bulk-in maxpacket size.
+ */
bh->inreq->length = nread;
bh->state = BUF_STATE_FULL;
/* If an error occurred, report it and its position */
if (nread < amount) {
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info =
+ file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -877,7 +875,6 @@ static int do_write(struct fsg_common *common)
u32 amount_left_to_req, amount_left_to_write;
loff_t usb_offset, file_offset, file_offset_tmp;
unsigned int amount;
- unsigned int partial_page;
ssize_t nwritten;
int rc;
@@ -921,7 +918,7 @@ static int do_write(struct fsg_common *common)
/* Carry out the file writes */
get_some_more = 1;
- file_offset = usb_offset = ((loff_t) lba) << 9;
+ file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
amount_left_to_req = common->data_size_from_cmnd;
amount_left_to_write = common->data_size_from_cmnd;
@@ -933,41 +930,21 @@ static int do_write(struct fsg_common *common)
/*
* Figure out how much we want to get:
- * Try to get the remaining amount.
- * But don't get more than the buffer size.
- * And don't try to go past the end of the file.
- * If we're not at a page boundary,
- * don't go past the next page.
- * If this means getting 0, then we were asked
- * to write past the end of file.
- * Finally, round down to a block boundary.
+ * Try to get the remaining amount,
+ * but not more than the buffer size.
*/
amount = min(amount_left_to_req, FSG_BUFLEN);
- amount = min((loff_t)amount,
- curlun->file_length - usb_offset);
- partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
- if (partial_page > 0)
- amount = min(amount,
- (unsigned int)PAGE_CACHE_SIZE - partial_page);
-
- if (amount == 0) {
+
+ /* Beyond the end of the backing file? */
+ if (usb_offset >= curlun->file_length) {
get_some_more = 0;
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- curlun->sense_data_info = usb_offset >> 9;
+ curlun->sense_data_info =
+ usb_offset >> curlun->blkbits;
curlun->info_valid = 1;
continue;
}
- amount -= amount & 511;
- if (amount == 0) {
-
- /*
- * Why were we were asked to transfer a
- * partial block?
- */
- get_some_more = 0;
- continue;
- }
/* Get the next buffer */
usb_offset += amount;
@@ -977,12 +954,11 @@ static int do_write(struct fsg_common *common)
get_some_more = 0;
/*
- * amount is always divisible by 512, hence by
- * the bulk-out maxpacket size
+ * Except at the end of the transfer, amount will be
+ * equal to the buffer size, which is divisible by
+ * the bulk-out maxpacket size.
*/
- bh->outreq->length = amount;
- bh->bulk_out_intended_length = amount;
- bh->outreq->short_not_ok = 1;
+ set_bulk_out_req_length(common, bh, amount);
if (!start_out_transfer(common, bh))
/* Dunno what to do if common->fsg is NULL */
return -EIO;
@@ -1002,7 +978,8 @@ static int do_write(struct fsg_common *common)
/* Did something go wrong with the transfer? */
if (bh->outreq->status != 0) {
curlun->sense_data = SS_COMMUNICATION_FAILURE;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info =
+ file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1016,6 +993,16 @@ static int do_write(struct fsg_common *common)
amount = curlun->file_length - file_offset;
}
+ /* Don't accept excess data. The spec doesn't say
+ * what to do in this case. We'll ignore the error.
+ */
+ amount = min(amount, bh->bulk_out_intended_length);
+
+ /* Don't write a partial block */
+ amount = round_down(amount, curlun->blksize);
+ if (amount == 0)
+ goto empty_write;
+
/* Perform the write */
file_offset_tmp = file_offset;
nwritten = vfs_write(curlun->filp,
@@ -1033,8 +1020,7 @@ static int do_write(struct fsg_common *common)
} else if (nwritten < amount) {
LDBG(curlun, "partial file write: %d/%u\n",
(int)nwritten, amount);
- nwritten -= (nwritten & 511);
- /* Round down to a block */
+ nwritten = round_down(nwritten, curlun->blksize);
}
file_offset += nwritten;
amount_left_to_write -= nwritten;
@@ -1043,13 +1029,15 @@ static int do_write(struct fsg_common *common)
/* If an error occurred, report it and its position */
if (nwritten < amount) {
curlun->sense_data = SS_WRITE_ERROR;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info =
+ file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
+ empty_write:
/* Did the host decide to stop early? */
- if (bh->outreq->actual != bh->outreq->length) {
+ if (bh->outreq->actual < bh->bulk_out_intended_length) {
common->short_packet_received = 1;
break;
}
@@ -1129,8 +1117,8 @@ static int do_verify(struct fsg_common *common)
return -EIO; /* No default reply */
/* Prepare to carry out the file verify */
- amount_left = verification_length << 9;
- file_offset = ((loff_t) lba) << 9;
+ amount_left = verification_length << curlun->blkbits;
+ file_offset = ((loff_t) lba) << curlun->blkbits;
/* Write out all the dirty buffers before invalidating them */
fsg_lun_fsync_sub(curlun);
@@ -1148,8 +1136,6 @@ static int do_verify(struct fsg_common *common)
* Try to read the remaining amount, but not more than
* the buffer size.
* And don't try to read past the end of the file.
- * If this means reading 0 then we were asked to read
- * past the end of file.
*/
amount = min(amount_left, FSG_BUFLEN);
amount = min((loff_t)amount,
@@ -1157,7 +1143,8 @@ static int do_verify(struct fsg_common *common)
if (amount == 0) {
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info =
+ file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1179,11 +1166,12 @@ static int do_verify(struct fsg_common *common)
} else if (nread < amount) {
LDBG(curlun, "partial file verify: %d/%u\n",
(int)nread, amount);
- nread -= nread & 511; /* Round down to a sector */
+ nread = round_down(nread, curlun->blksize);
}
if (nread == 0) {
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info =
+ file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1289,7 +1277,7 @@ static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh)
put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
/* Max logical block */
- put_unaligned_be32(512, &buf[4]); /* Block length */
+ put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */
return 8;
}
@@ -1527,7 +1515,7 @@ static int do_read_format_capacities(struct fsg_common *common,
put_unaligned_be32(curlun->num_sectors, &buf[0]);
/* Number of blocks */
- put_unaligned_be32(512, &buf[4]); /* Block length */
+ put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */
buf[4] = 0x02; /* Current capacity */
return 12;
}
@@ -1607,7 +1595,7 @@ static int throw_away_data(struct fsg_common *common)
common->next_buffhd_to_drain = bh->next;
/* A short packet or an error ends everything */
- if (bh->outreq->actual != bh->outreq->length ||
+ if (bh->outreq->actual < bh->bulk_out_intended_length ||
bh->outreq->status != 0) {
raise_exception(common,
FSG_STATE_ABORT_BULK_OUT);
@@ -1623,12 +1611,11 @@ static int throw_away_data(struct fsg_common *common)
amount = min(common->usb_amount_left, FSG_BUFLEN);
/*
- * amount is always divisible by 512, hence by
+ * Except at the end of the transfer, amount will be
+ * equal to the buffer size, which is divisible by
* the bulk-out maxpacket size.
*/
- bh->outreq->length = amount;
- bh->bulk_out_intended_length = amount;
- bh->outreq->short_not_ok = 1;
+ set_bulk_out_req_length(common, bh, amount);
if (!start_out_transfer(common, bh))
/* Dunno what to do if common->fsg is NULL */
return -EIO;
@@ -2022,7 +2009,8 @@ static int do_scsi_command(struct fsg_common *common)
case READ_6:
i = common->cmnd[4];
- common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+ common->data_size_from_cmnd = (i == 0 ? 256 : i) <<
+ common->curlun->blkbits;
reply = check_command(common, 6, DATA_DIR_TO_HOST,
(7<<1) | (1<<4), 1,
"READ(6)");
@@ -2032,7 +2020,8 @@ static int do_scsi_command(struct fsg_common *common)
case READ_10:
common->data_size_from_cmnd =
- get_unaligned_be16(&common->cmnd[7]) << 9;
+ get_unaligned_be16(&common->cmnd[7]) <<
+ common->curlun->blkbits;
reply = check_command(common, 10, DATA_DIR_TO_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1,
"READ(10)");
@@ -2042,7 +2031,8 @@ static int do_scsi_command(struct fsg_common *common)
case READ_12:
common->data_size_from_cmnd =
- get_unaligned_be32(&common->cmnd[6]) << 9;
+ get_unaligned_be32(&common->cmnd[6]) <<
+ common->curlun->blkbits;
reply = check_command(common, 12, DATA_DIR_TO_HOST,
(1<<1) | (0xf<<2) | (0xf<<6), 1,
"READ(12)");
@@ -2142,7 +2132,8 @@ static int do_scsi_command(struct fsg_common *common)
case WRITE_6:
i = common->cmnd[4];
- common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+ common->data_size_from_cmnd = (i == 0 ? 256 : i) <<
+ common->curlun->blkbits;
reply = check_command(common, 6, DATA_DIR_FROM_HOST,
(7<<1) | (1<<4), 1,
"WRITE(6)");
@@ -2152,7 +2143,8 @@ static int do_scsi_command(struct fsg_common *common)
case WRITE_10:
common->data_size_from_cmnd =
- get_unaligned_be16(&common->cmnd[7]) << 9;
+ get_unaligned_be16(&common->cmnd[7]) <<
+ common->curlun->blkbits;
reply = check_command(common, 10, DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1,
"WRITE(10)");
@@ -2162,7 +2154,8 @@ static int do_scsi_command(struct fsg_common *common)
case WRITE_12:
common->data_size_from_cmnd =
- get_unaligned_be32(&common->cmnd[6]) << 9;
+ get_unaligned_be32(&common->cmnd[6]) <<
+ common->curlun->blkbits;
reply = check_command(common, 12, DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (0xf<<6), 1,
"WRITE(12)");
@@ -2297,7 +2290,6 @@ static int get_next_command(struct fsg_common *common)
/* Queue a request to read a Bulk-only CBW */
set_bulk_out_req_length(common, bh, USB_BULK_CB_WRAP_LEN);
- bh->outreq->short_not_ok = 1;
if (!start_out_transfer(common, bh))
/* Don't know what to do if common->fsg is NULL */
return -EIO;
@@ -2348,7 +2340,7 @@ reset:
if (common->fsg) {
fsg = common->fsg;
- for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+ for (i = 0; i < fsg_num_buffers; ++i) {
struct fsg_buffhd *bh = &common->buffhds[i];
if (bh->inreq) {
@@ -2401,12 +2393,11 @@ reset:
goto reset;
fsg->bulk_out->driver_data = common;
fsg->bulk_out_enabled = 1;
- common->bulk_out_maxpacket =
- le16_to_cpu(fsg->bulk_out->desc->wMaxPacketSize);
+ common->bulk_out_maxpacket = usb_endpoint_maxp(fsg->bulk_out->desc);
clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
/* Allocate the requests */
- for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+ for (i = 0; i < fsg_num_buffers; ++i) {
struct fsg_buffhd *bh = &common->buffhds[i];
rc = alloc_request(common, fsg->bulk_in, &bh->inreq);
@@ -2475,7 +2466,7 @@ static void handle_exception(struct fsg_common *common)
/* Cancel all the pending transfers */
if (likely(common->fsg)) {
- for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+ for (i = 0; i < fsg_num_buffers; ++i) {
bh = &common->buffhds[i];
if (bh->inreq_busy)
usb_ep_dequeue(common->fsg->bulk_in, bh->inreq);
@@ -2487,7 +2478,7 @@ static void handle_exception(struct fsg_common *common)
/* Wait until everything is idle */
for (;;) {
int num_active = 0;
- for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+ for (i = 0; i < fsg_num_buffers; ++i) {
bh = &common->buffhds[i];
num_active += bh->inreq_busy + bh->outreq_busy;
}
@@ -2510,7 +2501,7 @@ static void handle_exception(struct fsg_common *common)
*/
spin_lock_irq(&common->lock);
- for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+ for (i = 0; i < fsg_num_buffers; ++i) {
bh = &common->buffhds[i];
bh->state = BUF_STATE_EMPTY;
}
@@ -2719,6 +2710,10 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
int nluns, i, rc;
char *pathbuf;
+ rc = fsg_num_buffers_validate();
+ if (rc != 0)
+ return ERR_PTR(rc);
+
/* Find out how many LUNs there should be */
nluns = cfg->nluns;
if (nluns < 1 || nluns > FSG_MAX_LUNS) {
@@ -2737,6 +2732,14 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
common->free_storage_on_release = 0;
}
+ common->buffhds = kcalloc(fsg_num_buffers,
+ sizeof *(common->buffhds), GFP_KERNEL);
+ if (!common->buffhds) {
+ if (common->free_storage_on_release)
+ kfree(common);
+ return ERR_PTR(-ENOMEM);
+ }
+
common->ops = cfg->ops;
common->private_data = cfg->private_data;
@@ -2814,7 +2817,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
/* Data buffers cyclic list */
bh = common->buffhds;
- i = FSG_NUM_BUFFERS;
+ i = fsg_num_buffers;
goto buffhds_first_it;
do {
bh->next = bh + 1;
@@ -2940,12 +2943,13 @@ static void fsg_common_release(struct kref *ref)
{
struct fsg_buffhd *bh = common->buffhds;
- unsigned i = FSG_NUM_BUFFERS;
+ unsigned i = fsg_num_buffers;
do {
kfree(bh->buf);
} while (++bh, --i);
}
+ kfree(common->buffhds);
if (common->free_storage_on_release)
kfree(common);
}
@@ -3019,6 +3023,28 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
}
}
+ if (gadget_is_superspeed(gadget)) {
+ unsigned max_burst;
+
+ /* Calculate bMaxBurst, we know packet size is 1024 */
+ max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15);
+
+ fsg_ss_bulk_in_desc.bEndpointAddress =
+ fsg_fs_bulk_in_desc.bEndpointAddress;
+ fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
+
+ fsg_ss_bulk_out_desc.bEndpointAddress =
+ fsg_fs_bulk_out_desc.bEndpointAddress;
+ fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
+
+ f->ss_descriptors = usb_copy_descriptors(fsg_ss_function);
+ if (unlikely(!f->ss_descriptors)) {
+ usb_free_descriptors(f->hs_descriptors);
+ usb_free_descriptors(f->descriptors);
+ return -ENOMEM;
+ }
+ }
+
return 0;
autoconf_fail:
diff --git a/drivers/usb/gadget/f_midi.c b/drivers/usb/gadget/f_midi.c
new file mode 100644
index 000000000000..67b222908cf9
--- /dev/null
+++ b/drivers/usb/gadget/f_midi.c
@@ -0,0 +1,998 @@
+/*
+ * f_midi.c -- USB MIDI class function driver
+ *
+ * Copyright (C) 2006 Thumtronics Pty Ltd.
+ * Developed for Thumtronics by Grey Innovation
+ * Ben Williamson <ben.williamson@greyinnovation.com>
+ *
+ * Rewritten for the composite framework
+ * Copyright (C) 2011 Daniel Mack <zonque@gmail.com>
+ *
+ * Based on drivers/usb/gadget/f_audio.c,
+ * Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
+ * Copyright (C) 2008 Analog Devices, Inc
+ *
+ * and drivers/usb/gadget/midi.c,
+ * Copyright (C) 2006 Thumtronics Pty Ltd.
+ * Ben Williamson <ben.williamson@greyinnovation.com>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/utsname.h>
+#include <linux/device.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/rawmidi.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/audio.h>
+#include <linux/usb/midi.h>
+
+MODULE_AUTHOR("Ben Williamson");
+MODULE_LICENSE("GPL v2");
+
+static const char f_midi_shortname[] = "f_midi";
+static const char f_midi_longname[] = "MIDI Gadget";
+
+/*
+ * We can only handle 16 cables on one single endpoint, as cable numbers are
+ * stored in 4-bit fields. And as the interface currently only holds one
+ * single endpoint, this is the maximum number of ports we can allow.
+ */
+#define MAX_PORTS 16
+
+/*
+ * This is a gadget, and the IN/OUT naming is from the host's perspective.
+ * USB -> OUT endpoint -> rawmidi
+ * USB <- IN endpoint <- rawmidi
+ */
+struct gmidi_in_port {
+ struct f_midi *midi;
+ int active;
+ uint8_t cable;
+ uint8_t state;
+#define STATE_UNKNOWN 0
+#define STATE_1PARAM 1
+#define STATE_2PARAM_1 2
+#define STATE_2PARAM_2 3
+#define STATE_SYSEX_0 4
+#define STATE_SYSEX_1 5
+#define STATE_SYSEX_2 6
+ uint8_t data[2];
+};
+
+struct f_midi {
+ struct usb_function func;
+ struct usb_gadget *gadget;
+ struct usb_ep *in_ep, *out_ep;
+ struct snd_card *card;
+ struct snd_rawmidi *rmidi;
+
+ struct snd_rawmidi_substream *in_substream[MAX_PORTS];
+ struct snd_rawmidi_substream *out_substream[MAX_PORTS];
+ struct gmidi_in_port *in_port[MAX_PORTS];
+
+ unsigned long out_triggered;
+ struct tasklet_struct tasklet;
+ unsigned int in_ports;
+ unsigned int out_ports;
+ int index;
+ char *id;
+ unsigned int buflen, qlen;
+};
+
+static inline struct f_midi *func_to_midi(struct usb_function *f)
+{
+ return container_of(f, struct f_midi, func);
+}
+
+static void f_midi_transmit(struct f_midi *midi, struct usb_request *req);
+
+DECLARE_UAC_AC_HEADER_DESCRIPTOR(1);
+DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1);
+DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(16);
+DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(16);
+
+/* B.3.1 Standard AC Interface Descriptor */
+static struct usb_interface_descriptor ac_interface_desc __initdata = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ /* .bInterfaceNumber = DYNAMIC */
+ /* .bNumEndpoints = DYNAMIC */
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
+ /* .iInterface = DYNAMIC */
+};
+
+/* B.3.2 Class-Specific AC Interface Descriptor */
+static struct uac1_ac_header_descriptor_1 ac_header_desc __initdata = {
+ .bLength = UAC_DT_AC_HEADER_SIZE(1),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = USB_MS_HEADER,
+ .bcdADC = cpu_to_le16(0x0100),
+ .wTotalLength = cpu_to_le16(UAC_DT_AC_HEADER_SIZE(1)),
+ .bInCollection = 1,
+ /* .baInterfaceNr = DYNAMIC */
+};
+
+/* B.4.1 Standard MS Interface Descriptor */
+static struct usb_interface_descriptor ms_interface_desc __initdata = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ /* .bInterfaceNumber = DYNAMIC */
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING,
+ /* .iInterface = DYNAMIC */
+};
+
+/* B.4.2 Class-Specific MS Interface Descriptor */
+static struct usb_ms_header_descriptor ms_header_desc __initdata = {
+ .bLength = USB_DT_MS_HEADER_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = USB_MS_HEADER,
+ .bcdMSC = cpu_to_le16(0x0100),
+ /* .wTotalLength = DYNAMIC */
+};
+
+/* B.4.3 Embedded MIDI IN Jack Descriptor */
+static struct usb_midi_in_jack_descriptor jack_in_emb_desc = {
+ .bLength = USB_DT_MIDI_IN_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = USB_MS_MIDI_IN_JACK,
+ .bJackType = USB_MS_EMBEDDED,
+ /* .bJackID = DYNAMIC */
+};
+
+/* B.4.4 Embedded MIDI OUT Jack Descriptor */
+static struct usb_midi_out_jack_descriptor_16 jack_out_emb_desc = {
+ /* .bLength = DYNAMIC */
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = USB_MS_MIDI_OUT_JACK,
+ .bJackType = USB_MS_EMBEDDED,
+ /* .bJackID = DYNAMIC */
+ /* .bNrInputPins = DYNAMIC */
+ /* .pins = DYNAMIC */
+};
+
+/* B.5.1 Standard Bulk OUT Endpoint Descriptor */
+static struct usb_endpoint_descriptor bulk_out_desc = {
+ .bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+/* B.5.2 Class-specific MS Bulk OUT Endpoint Descriptor */
+static struct usb_ms_endpoint_descriptor_16 ms_out_desc = {
+ /* .bLength = DYNAMIC */
+ .bDescriptorType = USB_DT_CS_ENDPOINT,
+ .bDescriptorSubtype = USB_MS_GENERAL,
+ /* .bNumEmbMIDIJack = DYNAMIC */
+ /* .baAssocJackID = DYNAMIC */
+};
+
+/* B.6.1 Standard Bulk IN Endpoint Descriptor */
+static struct usb_endpoint_descriptor bulk_in_desc = {
+ .bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+/* B.6.2 Class-specific MS Bulk IN Endpoint Descriptor */
+static struct usb_ms_endpoint_descriptor_16 ms_in_desc = {
+ /* .bLength = DYNAMIC */
+ .bDescriptorType = USB_DT_CS_ENDPOINT,
+ .bDescriptorSubtype = USB_MS_GENERAL,
+ /* .bNumEmbMIDIJack = DYNAMIC */
+ /* .baAssocJackID = DYNAMIC */
+};
+
+/* string IDs are assigned dynamically */
+
+#define STRING_FUNC_IDX 0
+
+static struct usb_string midi_string_defs[] = {
+ [STRING_FUNC_IDX].s = "MIDI function",
+ { } /* end of list */
+};
+
+static struct usb_gadget_strings midi_stringtab = {
+ .language = 0x0409, /* en-us */
+ .strings = midi_string_defs,
+};
+
+static struct usb_gadget_strings *midi_strings[] = {
+ &midi_stringtab,
+ NULL,
+};
+
+static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
+{
+ struct usb_request *req;
+
+ req = usb_ep_alloc_request(ep, GFP_ATOMIC);
+ if (req) {
+ req->length = length;
+ req->buf = kmalloc(length, GFP_ATOMIC);
+ if (!req->buf) {
+ usb_ep_free_request(ep, req);
+ req = NULL;
+ }
+ }
+ return req;
+}
+
+static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
+{
+ kfree(req->buf);
+ usb_ep_free_request(ep, req);
+}
+
+static const uint8_t f_midi_cin_length[] = {
+ 0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1
+};
+
+/*
+ * Receives a chunk of MIDI data.
+ */
+static void f_midi_read_data(struct usb_ep *ep, int cable,
+ uint8_t *data, int length)
+{
+ struct f_midi *midi = ep->driver_data;
+ struct snd_rawmidi_substream *substream = midi->out_substream[cable];
+
+ if (!substream)
+ /* Nobody is listening - throw it on the floor. */
+ return;
+
+ if (!test_bit(cable, &midi->out_triggered))
+ return;
+
+ snd_rawmidi_receive(substream, data, length);
+}
+
+static void f_midi_handle_out_data(struct usb_ep *ep, struct usb_request *req)
+{
+ unsigned int i;
+ u8 *buf = req->buf;
+
+ for (i = 0; i + 3 < req->actual; i += 4)
+ if (buf[i] != 0) {
+ int cable = buf[i] >> 4;
+ int length = f_midi_cin_length[buf[i] & 0x0f];
+ f_midi_read_data(ep, cable, &buf[i + 1], length);
+ }
+}
+
+static void
+f_midi_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct f_midi *midi = ep->driver_data;
+ struct usb_composite_dev *cdev = midi->func.config->cdev;
+ int status = req->status;
+
+ switch (status) {
+ case 0: /* normal completion */
+ if (ep == midi->out_ep) {
+ /* We received stuff. req is queued again, below */
+ f_midi_handle_out_data(ep, req);
+ } else if (ep == midi->in_ep) {
+ /* Our transmit completed. See if there's more to go.
+ * f_midi_transmit eats req, don't queue it again. */
+ f_midi_transmit(midi, req);
+ return;
+ }
+ break;
+
+ /* this endpoint is normally active while we're configured */
+ case -ECONNABORTED: /* hardware forced ep reset */
+ case -ECONNRESET: /* request dequeued */
+ case -ESHUTDOWN: /* disconnect from host */
+ VDBG(cdev, "%s gone (%d), %d/%d\n", ep->name, status,
+ req->actual, req->length);
+ if (ep == midi->out_ep)
+ f_midi_handle_out_data(ep, req);
+
+ free_ep_req(ep, req);
+ return;
+
+ case -EOVERFLOW: /* buffer overrun on read means that
+ * we didn't provide a big enough buffer.
+ */
+ default:
+ DBG(cdev, "%s complete --> %d, %d/%d\n", ep->name,
+ status, req->actual, req->length);
+ break;
+ case -EREMOTEIO: /* short read */
+ break;
+ }
+
+ status = usb_ep_queue(ep, req, GFP_ATOMIC);
+ if (status) {
+ ERROR(cdev, "kill %s: resubmit %d bytes --> %d\n",
+ ep->name, req->length, status);
+ usb_ep_set_halt(ep);
+ /* FIXME recover later ... somehow */
+ }
+}
+
+static int f_midi_start_ep(struct f_midi *midi,
+ struct usb_function *f,
+ struct usb_ep *ep)
+{
+ int err;
+ struct usb_composite_dev *cdev = f->config->cdev;
+
+ if (ep->driver_data)
+ usb_ep_disable(ep);
+
+ err = config_ep_by_speed(midi->gadget, f, ep);
+ if (err) {
+ ERROR(cdev, "can't configure %s: %d\n", ep->name, err);
+ return err;
+ }
+
+ err = usb_ep_enable(ep);
+ if (err) {
+ ERROR(cdev, "can't start %s: %d\n", ep->name, err);
+ return err;
+ }
+
+ ep->driver_data = midi;
+
+ return 0;
+}
+
+static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+ struct f_midi *midi = func_to_midi(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
+ unsigned i;
+ int err;
+
+ err = f_midi_start_ep(midi, f, midi->in_ep);
+ if (err)
+ return err;
+
+ err = f_midi_start_ep(midi, f, midi->out_ep);
+ if (err)
+ return err;
+
+ if (midi->out_ep->driver_data)
+ usb_ep_disable(midi->out_ep);
+
+ err = config_ep_by_speed(midi->gadget, f, midi->out_ep);
+ if (err) {
+ ERROR(cdev, "can't configure %s: %d\n",
+ midi->out_ep->name, err);
+ return err;
+ }
+
+ err = usb_ep_enable(midi->out_ep);
+ if (err) {
+ ERROR(cdev, "can't start %s: %d\n",
+ midi->out_ep->name, err);
+ return err;
+ }
+
+ midi->out_ep->driver_data = midi;
+
+ /* allocate a bunch of read buffers and queue them all at once. */
+ for (i = 0; i < midi->qlen && err == 0; i++) {
+ struct usb_request *req =
+ alloc_ep_req(midi->out_ep, midi->buflen);
+ if (req == NULL)
+ return -ENOMEM;
+
+ req->complete = f_midi_complete;
+ err = usb_ep_queue(midi->out_ep, req, GFP_ATOMIC);
+ if (err) {
+ ERROR(midi, "%s queue req: %d\n",
+ midi->out_ep->name, err);
+ }
+ }
+
+ return 0;
+}
+
+static void f_midi_disable(struct usb_function *f)
+{
+ struct f_midi *midi = func_to_midi(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
+
+ DBG(cdev, "disable\n");
+
+ /*
+ * just disable endpoints, forcing completion of pending i/o.
+ * all our completion handlers free their requests in this case.
+ */
+ usb_ep_disable(midi->in_ep);
+ usb_ep_disable(midi->out_ep);
+}
+
+static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct usb_composite_dev *cdev = f->config->cdev;
+ struct f_midi *midi = func_to_midi(f);
+ struct snd_card *card;
+
+ DBG(cdev, "unbind\n");
+
+ /* just to be sure */
+ f_midi_disable(f);
+
+ card = midi->card;
+ midi->card = NULL;
+ if (card)
+ snd_card_free(card);
+
+ kfree(midi->id);
+ midi->id = NULL;
+
+ usb_free_descriptors(f->descriptors);
+ kfree(midi);
+}
+
+static int f_midi_snd_free(struct snd_device *device)
+{
+ return 0;
+}
+
+static void f_midi_transmit_packet(struct usb_request *req, uint8_t p0,
+ uint8_t p1, uint8_t p2, uint8_t p3)
+{
+ unsigned length = req->length;
+ u8 *buf = (u8 *)req->buf + length;
+
+ buf[0] = p0;
+ buf[1] = p1;
+ buf[2] = p2;
+ buf[3] = p3;
+ req->length = length + 4;
+}
+
+/*
+ * Converts MIDI commands to USB MIDI packets.
+ */
+static void f_midi_transmit_byte(struct usb_request *req,
+ struct gmidi_in_port *port, uint8_t b)
+{
+ uint8_t p0 = port->cable << 4;
+
+ if (b >= 0xf8) {
+ f_midi_transmit_packet(req, p0 | 0x0f, b, 0, 0);
+ } else if (b >= 0xf0) {
+ switch (b) {
+ case 0xf0:
+ port->data[0] = b;
+ port->state = STATE_SYSEX_1;
+ break;
+ case 0xf1:
+ case 0xf3:
+ port->data[0] = b;
+ port->state = STATE_1PARAM;
+ break;
+ case 0xf2:
+ port->data[0] = b;
+ port->state = STATE_2PARAM_1;
+ break;
+ case 0xf4:
+ case 0xf5:
+ port->state = STATE_UNKNOWN;
+ break;
+ case 0xf6:
+ f_midi_transmit_packet(req, p0 | 0x05, 0xf6, 0, 0);
+ port->state = STATE_UNKNOWN;
+ break;
+ case 0xf7:
+ switch (port->state) {
+ case STATE_SYSEX_0:
+ f_midi_transmit_packet(req,
+ p0 | 0x05, 0xf7, 0, 0);
+ break;
+ case STATE_SYSEX_1:
+ f_midi_transmit_packet(req,
+ p0 | 0x06, port->data[0], 0xf7, 0);
+ break;
+ case STATE_SYSEX_2:
+ f_midi_transmit_packet(req,
+ p0 | 0x07, port->data[0],
+ port->data[1], 0xf7);
+ break;
+ }
+ port->state = STATE_UNKNOWN;
+ break;
+ }
+ } else if (b >= 0x80) {
+ port->data[0] = b;
+ if (b >= 0xc0 && b <= 0xdf)
+ port->state = STATE_1PARAM;
+ else
+ port->state = STATE_2PARAM_1;
+ } else { /* b < 0x80 */
+ switch (port->state) {
+ case STATE_1PARAM:
+ if (port->data[0] < 0xf0) {
+ p0 |= port->data[0] >> 4;
+ } else {
+ p0 |= 0x02;
+ port->state = STATE_UNKNOWN;
+ }
+ f_midi_transmit_packet(req, p0, port->data[0], b, 0);
+ break;
+ case STATE_2PARAM_1:
+ port->data[1] = b;
+ port->state = STATE_2PARAM_2;
+ break;
+ case STATE_2PARAM_2:
+ if (port->data[0] < 0xf0) {
+ p0 |= port->data[0] >> 4;
+ port->state = STATE_2PARAM_1;
+ } else {
+ p0 |= 0x03;
+ port->state = STATE_UNKNOWN;
+ }
+ f_midi_transmit_packet(req,
+ p0, port->data[0], port->data[1], b);
+ break;
+ case STATE_SYSEX_0:
+ port->data[0] = b;
+ port->state = STATE_SYSEX_1;
+ break;
+ case STATE_SYSEX_1:
+ port->data[1] = b;
+ port->state = STATE_SYSEX_2;
+ break;
+ case STATE_SYSEX_2:
+ f_midi_transmit_packet(req,
+ p0 | 0x04, port->data[0], port->data[1], b);
+ port->state = STATE_SYSEX_0;
+ break;
+ }
+ }
+}
+
+static void f_midi_transmit(struct f_midi *midi, struct usb_request *req)
+{
+ struct usb_ep *ep = midi->in_ep;
+ int i;
+
+ if (!ep)
+ return;
+
+ if (!req)
+ req = alloc_ep_req(ep, midi->buflen);
+
+ if (!req) {
+ ERROR(midi, "gmidi_transmit: alloc_ep_request failed\n");
+ return;
+ }
+ req->length = 0;
+ req->complete = f_midi_complete;
+
+ for (i = 0; i < MAX_PORTS; i++) {
+ struct gmidi_in_port *port = midi->in_port[i];
+ struct snd_rawmidi_substream *substream = midi->in_substream[i];
+
+ if (!port || !port->active || !substream)
+ continue;
+
+ while (req->length + 3 < midi->buflen) {
+ uint8_t b;
+ if (snd_rawmidi_transmit(substream, &b, 1) != 1) {
+ port->active = 0;
+ break;
+ }
+ f_midi_transmit_byte(req, port, b);
+ }
+ }
+
+ if (req->length > 0)
+ usb_ep_queue(ep, req, GFP_ATOMIC);
+ else
+ free_ep_req(ep, req);
+}
+
+static void f_midi_in_tasklet(unsigned long data)
+{
+ struct f_midi *midi = (struct f_midi *) data;
+ f_midi_transmit(midi, NULL);
+}
+
+static int f_midi_in_open(struct snd_rawmidi_substream *substream)
+{
+ struct f_midi *midi = substream->rmidi->private_data;
+
+ if (!midi->in_port[substream->number])
+ return -EINVAL;
+
+ VDBG(midi, "%s()\n", __func__);
+ midi->in_substream[substream->number] = substream;
+ midi->in_port[substream->number]->state = STATE_UNKNOWN;
+ return 0;
+}
+
+static int f_midi_in_close(struct snd_rawmidi_substream *substream)
+{
+ struct f_midi *midi = substream->rmidi->private_data;
+
+ VDBG(midi, "%s()\n", __func__);
+ return 0;
+}
+
+static void f_midi_in_trigger(struct snd_rawmidi_substream *substream, int up)
+{
+ struct f_midi *midi = substream->rmidi->private_data;
+
+ if (!midi->in_port[substream->number])
+ return;
+
+ VDBG(midi, "%s() %d\n", __func__, up);
+ midi->in_port[substream->number]->active = up;
+ if (up)
+ tasklet_hi_schedule(&midi->tasklet);
+}
+
+static int f_midi_out_open(struct snd_rawmidi_substream *substream)
+{
+ struct f_midi *midi = substream->rmidi->private_data;
+
+ if (substream->number >= MAX_PORTS)
+ return -EINVAL;
+
+ VDBG(midi, "%s()\n", __func__);
+ midi->out_substream[substream->number] = substream;
+ return 0;
+}
+
+static int f_midi_out_close(struct snd_rawmidi_substream *substream)
+{
+ struct f_midi *midi = substream->rmidi->private_data;
+
+ VDBG(midi, "%s()\n", __func__);
+ return 0;
+}
+
+static void f_midi_out_trigger(struct snd_rawmidi_substream *substream, int up)
+{
+ struct f_midi *midi = substream->rmidi->private_data;
+
+ VDBG(midi, "%s()\n", __func__);
+
+ if (up)
+ set_bit(substream->number, &midi->out_triggered);
+ else
+ clear_bit(substream->number, &midi->out_triggered);
+}
+
+static struct snd_rawmidi_ops gmidi_in_ops = {
+ .open = f_midi_in_open,
+ .close = f_midi_in_close,
+ .trigger = f_midi_in_trigger,
+};
+
+static struct snd_rawmidi_ops gmidi_out_ops = {
+ .open = f_midi_out_open,
+ .close = f_midi_out_close,
+ .trigger = f_midi_out_trigger
+};
+
+/* register as a sound "card" */
+static int f_midi_register_card(struct f_midi *midi)
+{
+ struct snd_card *card;
+ struct snd_rawmidi *rmidi;
+ int err;
+ static struct snd_device_ops ops = {
+ .dev_free = f_midi_snd_free,
+ };
+
+ err = snd_card_create(midi->index, midi->id, THIS_MODULE, 0, &card);
+ if (err < 0) {
+ ERROR(midi, "snd_card_create() failed\n");
+ goto fail;
+ }
+ midi->card = card;
+
+ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, midi, &ops);
+ if (err < 0) {
+ ERROR(midi, "snd_device_new() failed: error %d\n", err);
+ goto fail;
+ }
+
+ strcpy(card->driver, f_midi_longname);
+ strcpy(card->longname, f_midi_longname);
+ strcpy(card->shortname, f_midi_shortname);
+
+ /* Set up rawmidi */
+ snd_component_add(card, "MIDI");
+ err = snd_rawmidi_new(card, card->longname, 0,
+ midi->out_ports, midi->in_ports, &rmidi);
+ if (err < 0) {
+ ERROR(midi, "snd_rawmidi_new() failed: error %d\n", err);
+ goto fail;
+ }
+ midi->rmidi = rmidi;
+ strcpy(rmidi->name, card->shortname);
+ rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
+ SNDRV_RAWMIDI_INFO_INPUT |
+ SNDRV_RAWMIDI_INFO_DUPLEX;
+ rmidi->private_data = midi;
+
+ /*
+ * Yes, rawmidi OUTPUT = USB IN, and rawmidi INPUT = USB OUT.
+ * It's an upside-down world being a gadget.
+ */
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &gmidi_in_ops);
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &gmidi_out_ops);
+
+ snd_card_set_dev(card, &midi->gadget->dev);
+
+ /* register it - we're ready to go */
+ err = snd_card_register(card);
+ if (err < 0) {
+ ERROR(midi, "snd_card_register() failed\n");
+ goto fail;
+ }
+
+ VDBG(midi, "%s() finished ok\n", __func__);
+ return 0;
+
+fail:
+ if (midi->card) {
+ snd_card_free(midi->card);
+ midi->card = NULL;
+ }
+ return err;
+}
+
+/* MIDI function driver setup/binding */
+
+static int __init
+f_midi_bind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct usb_descriptor_header *midi_function[(MAX_PORTS * 2) + 12];
+ struct usb_midi_in_jack_descriptor jack_in_ext_desc[MAX_PORTS];
+ struct usb_midi_out_jack_descriptor_1 jack_out_ext_desc[MAX_PORTS];
+ struct usb_composite_dev *cdev = c->cdev;
+ struct f_midi *midi = func_to_midi(f);
+ int status, n, jack = 1, i = 0;
+
+ /* maybe allocate device-global string ID */
+ if (midi_string_defs[0].id == 0) {
+ status = usb_string_id(c->cdev);
+ if (status < 0)
+ goto fail;
+ midi_string_defs[0].id = status;
+ }
+
+ /* We have two interfaces, AudioControl and MIDIStreaming */
+ status = usb_interface_id(c, f);
+ if (status < 0)
+ goto fail;
+ ac_interface_desc.bInterfaceNumber = status;
+
+ status = usb_interface_id(c, f);
+ if (status < 0)
+ goto fail;
+ ms_interface_desc.bInterfaceNumber = status;
+ ac_header_desc.baInterfaceNr[0] = status;
+
+ status = -ENODEV;
+
+ /* allocate instance-specific endpoints */
+ midi->in_ep = usb_ep_autoconfig(cdev->gadget, &bulk_in_desc);
+ if (!midi->in_ep)
+ goto fail;
+ midi->in_ep->driver_data = cdev; /* claim */
+
+ midi->out_ep = usb_ep_autoconfig(cdev->gadget, &bulk_out_desc);
+ if (!midi->out_ep)
+ goto fail;
+ midi->out_ep->driver_data = cdev; /* claim */
+
+ /*
+ * construct the function's descriptor set. As the number of
+ * input and output MIDI ports is configurable, we have to do
+ * it that way.
+ */
+
+ /* add the headers - these are always the same */
+ midi_function[i++] = (struct usb_descriptor_header *) &ac_interface_desc;
+ midi_function[i++] = (struct usb_descriptor_header *) &ac_header_desc;
+ midi_function[i++] = (struct usb_descriptor_header *) &ms_interface_desc;
+
+ /* calculate the header's wTotalLength */
+ n = USB_DT_MS_HEADER_SIZE
+ + (1 + midi->in_ports) * USB_DT_MIDI_IN_SIZE
+ + (1 + midi->out_ports) * USB_DT_MIDI_OUT_SIZE(1);
+ ms_header_desc.wTotalLength = cpu_to_le16(n);
+
+ midi_function[i++] = (struct usb_descriptor_header *) &ms_header_desc;
+
+ /* we have one embedded IN jack */
+ jack_in_emb_desc.bJackID = jack++;
+ midi_function[i++] = (struct usb_descriptor_header *) &jack_in_emb_desc;
+
+ /* and a dynamic amount of external IN jacks */
+ for (n = 0; n < midi->in_ports; n++) {
+ struct usb_midi_in_jack_descriptor *ext = &jack_in_ext_desc[n];
+
+ ext->bLength = USB_DT_MIDI_IN_SIZE;
+ ext->bDescriptorType = USB_DT_CS_INTERFACE;
+ ext->bDescriptorSubtype = USB_MS_MIDI_IN_JACK;
+ ext->bJackType = USB_MS_EXTERNAL;
+ ext->bJackID = jack++;
+ ext->iJack = 0;
+
+ midi_function[i++] = (struct usb_descriptor_header *) ext;
+ }
+
+ /* one embedded OUT jack ... */
+ jack_out_emb_desc.bLength = USB_DT_MIDI_OUT_SIZE(midi->in_ports);
+ jack_out_emb_desc.bJackID = jack++;
+ jack_out_emb_desc.bNrInputPins = midi->in_ports;
+ /* ... which referencess all external IN jacks */
+ for (n = 0; n < midi->in_ports; n++) {
+ jack_out_emb_desc.pins[n].baSourceID = jack_in_ext_desc[n].bJackID;
+ jack_out_emb_desc.pins[n].baSourcePin = 1;
+ }
+
+ midi_function[i++] = (struct usb_descriptor_header *) &jack_out_emb_desc;
+
+ /* and multiple external OUT jacks ... */
+ for (n = 0; n < midi->out_ports; n++) {
+ struct usb_midi_out_jack_descriptor_1 *ext = &jack_out_ext_desc[n];
+ int m;
+
+ ext->bLength = USB_DT_MIDI_OUT_SIZE(1);
+ ext->bDescriptorType = USB_DT_CS_INTERFACE;
+ ext->bDescriptorSubtype = USB_MS_MIDI_OUT_JACK;
+ ext->bJackType = USB_MS_EXTERNAL;
+ ext->bJackID = jack++;
+ ext->bNrInputPins = 1;
+ ext->iJack = 0;
+ /* ... which all reference the same embedded IN jack */
+ for (m = 0; m < midi->out_ports; m++) {
+ ext->pins[m].baSourceID = jack_in_emb_desc.bJackID;
+ ext->pins[m].baSourcePin = 1;
+ }
+
+ midi_function[i++] = (struct usb_descriptor_header *) ext;
+ }
+
+ /* configure the endpoint descriptors ... */
+ ms_out_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->in_ports);
+ ms_out_desc.bNumEmbMIDIJack = midi->in_ports;
+ for (n = 0; n < midi->in_ports; n++)
+ ms_out_desc.baAssocJackID[n] = jack_in_emb_desc.bJackID;
+
+ ms_in_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->out_ports);
+ ms_in_desc.bNumEmbMIDIJack = midi->out_ports;
+ for (n = 0; n < midi->out_ports; n++)
+ ms_in_desc.baAssocJackID[n] = jack_out_emb_desc.bJackID;
+
+ /* ... and add them to the list */
+ midi_function[i++] = (struct usb_descriptor_header *) &bulk_out_desc;
+ midi_function[i++] = (struct usb_descriptor_header *) &ms_out_desc;
+ midi_function[i++] = (struct usb_descriptor_header *) &bulk_in_desc;
+ midi_function[i++] = (struct usb_descriptor_header *) &ms_in_desc;
+ midi_function[i++] = NULL;
+
+ /*
+ * support all relevant hardware speeds... we expect that when
+ * hardware is dual speed, all bulk-capable endpoints work at
+ * both speeds
+ */
+ /* copy descriptors, and track endpoint copies */
+ if (gadget_is_dualspeed(c->cdev->gadget)) {
+ c->highspeed = true;
+ bulk_in_desc.wMaxPacketSize = cpu_to_le16(512);
+ bulk_out_desc.wMaxPacketSize = cpu_to_le16(512);
+ f->hs_descriptors = usb_copy_descriptors(midi_function);
+ } else {
+ f->descriptors = usb_copy_descriptors(midi_function);
+ }
+
+ return 0;
+
+fail:
+ /* we might as well release our claims on endpoints */
+ if (midi->out_ep)
+ midi->out_ep->driver_data = NULL;
+ if (midi->in_ep)
+ midi->in_ep->driver_data = NULL;
+
+ ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
+
+ return status;
+}
+
+/**
+ * f_midi_bind_config - add USB MIDI function to a configuration
+ * @c: the configuration to supcard the USB audio function
+ * @index: the soundcard index to use for the ALSA device creation
+ * @id: the soundcard id to use for the ALSA device creation
+ * @buflen: the buffer length to use
+ * @qlen the number of read requests to pre-allocate
+ * Context: single threaded during gadget setup
+ *
+ * Returns zero on success, else negative errno.
+ */
+int __init f_midi_bind_config(struct usb_configuration *c,
+ int index, char *id,
+ unsigned int in_ports,
+ unsigned int out_ports,
+ unsigned int buflen,
+ unsigned int qlen)
+{
+ struct f_midi *midi;
+ int status, i;
+
+ /* sanity check */
+ if (in_ports > MAX_PORTS || out_ports > MAX_PORTS)
+ return -EINVAL;
+
+ /* allocate and initialize one new instance */
+ midi = kzalloc(sizeof *midi, GFP_KERNEL);
+ if (!midi) {
+ status = -ENOMEM;
+ goto fail;
+ }
+
+ for (i = 0; i < in_ports; i++) {
+ struct gmidi_in_port *port = kzalloc(sizeof(*port), GFP_KERNEL);
+ if (!port) {
+ status = -ENOMEM;
+ goto setup_fail;
+ }
+
+ port->midi = midi;
+ port->active = 0;
+ port->cable = i;
+ midi->in_port[i] = port;
+ }
+
+ midi->gadget = c->cdev->gadget;
+ tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi);
+
+ /* set up ALSA midi devices */
+ midi->in_ports = in_ports;
+ midi->out_ports = out_ports;
+ status = f_midi_register_card(midi);
+ if (status < 0)
+ goto setup_fail;
+
+ midi->func.name = "gmidi function";
+ midi->func.strings = midi_strings;
+ midi->func.bind = f_midi_bind;
+ midi->func.unbind = f_midi_unbind;
+ midi->func.set_alt = f_midi_set_alt;
+ midi->func.disable = f_midi_disable;
+
+ midi->id = kstrdup(id, GFP_KERNEL);
+ midi->index = index;
+ midi->buflen = buflen;
+ midi->qlen = qlen;
+
+ status = usb_add_function(c, &midi->func);
+ if (status)
+ goto setup_fail;
+
+ return 0;
+
+setup_fail:
+ for (--i; i >= 0; i--)
+ kfree(midi->in_port[i]);
+ kfree(midi);
+fail:
+ return status;
+}
+
diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c
index ae69ed7e6b99..aab8eded045b 100644
--- a/drivers/usb/gadget/f_ncm.c
+++ b/drivers/usb/gadget/f_ncm.c
@@ -13,15 +13,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c
index 394502abeb96..e3f74bf5da2d 100644
--- a/drivers/usb/gadget/f_obex.c
+++ b/drivers/usb/gadget/f_obex.c
@@ -10,15 +10,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* #define VERBOSE_DEBUG */
diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c
index 8f8d3f6cd89e..349077033338 100644
--- a/drivers/usb/gadget/f_phonet.c
+++ b/drivers/usb/gadget/f_phonet.c
@@ -8,16 +8,6 @@
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
*/
#include <linux/mm.h>
@@ -434,6 +424,7 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
config_ep_by_speed(gadget, f, fp->out_ep)) {
fp->in_ep->desc = NULL;
fp->out_ep->desc = NULL;
+ spin_unlock(&port->lock);
return -EINVAL;
}
usb_ep_enable(fp->out_ep);
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index 3ea4666be3d0..704d1d94f72a 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -11,15 +11,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* #define VERBOSE_DEBUG */
diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c
index e18b4f520951..168906d2b5d4 100644
--- a/drivers/usb/gadget/f_sourcesink.c
+++ b/drivers/usb/gadget/f_sourcesink.c
@@ -8,15 +8,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* #define VERBOSE_DEBUG */
diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c
index 3dc53754ab60..c1540648125a 100644
--- a/drivers/usb/gadget/f_subset.c
+++ b/drivers/usb/gadget/f_subset.c
@@ -8,15 +8,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/slab.h>
diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c
index 7a8b9aa4aea5..2022fe492148 100644
--- a/drivers/usb/gadget/f_uvc.c
+++ b/drivers/usb/gadget/f_uvc.c
@@ -8,7 +8,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/usb/gadget/f_uvc.h b/drivers/usb/gadget/f_uvc.h
index e18a6636c283..abf832935134 100644
--- a/drivers/usb/gadget/f_uvc.h
+++ b/drivers/usb/gadget/f_uvc.h
@@ -8,7 +8,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
*/
#ifndef _F_UVC_H_
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 639e14a2fd15..3ac4f51cd0bb 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -69,8 +69,7 @@
* each LUN would be settable independently as a disk drive or a CD-ROM
* drive, but currently all LUNs have to be the same type. The CD-ROM
* emulation includes a single data track and no audio tracks; hence there
- * need be only one backing file per LUN. Note also that the CD-ROM block
- * length is set to 512 rather than the more common value 2048.
+ * need be only one backing file per LUN.
*
* Requirements are modest; only a bulk-in and a bulk-out endpoint are
* needed (an interrupt-out endpoint is also needed for CBI). The memory
@@ -461,7 +460,6 @@ struct fsg_dev {
struct fsg_buffhd *next_buffhd_to_fill;
struct fsg_buffhd *next_buffhd_to_drain;
- struct fsg_buffhd buffhds[FSG_NUM_BUFFERS];
int thread_wakeup_needed;
struct completion thread_notifier;
@@ -488,6 +486,8 @@ struct fsg_dev {
unsigned int nluns;
struct fsg_lun *luns;
struct fsg_lun *curlun;
+ /* Must be the last entry */
+ struct fsg_buffhd buffhds[];
};
typedef void (*fsg_routine_t)(struct fsg_dev *);
@@ -586,7 +586,19 @@ dev_qualifier = {
.bNumConfigurations = 1,
};
+static int populate_bos(struct fsg_dev *fsg, u8 *buf)
+{
+ memcpy(buf, &fsg_bos_desc, USB_DT_BOS_SIZE);
+ buf += USB_DT_BOS_SIZE;
+
+ memcpy(buf, &fsg_ext_cap_desc, USB_DT_USB_EXT_CAP_SIZE);
+ buf += USB_DT_USB_EXT_CAP_SIZE;
+ memcpy(buf, &fsg_ss_cap_desc, USB_DT_USB_SS_CAP_SIZE);
+
+ return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE
+ + USB_DT_USB_EXT_CAP_SIZE;
+}
/*
* Config descriptors must agree with the code that sets configurations
@@ -935,7 +947,8 @@ static int standard_setup_req(struct fsg_dev *fsg,
break;
case USB_DT_DEVICE_QUALIFIER:
VDBG(fsg, "get device qualifier\n");
- if (!gadget_is_dualspeed(fsg->gadget))
+ if (!gadget_is_dualspeed(fsg->gadget) ||
+ fsg->gadget->speed == USB_SPEED_SUPER)
break;
/*
* Assume ep0 uses the same maxpacket value for both
@@ -948,7 +961,8 @@ static int standard_setup_req(struct fsg_dev *fsg,
case USB_DT_OTHER_SPEED_CONFIG:
VDBG(fsg, "get other-speed config descriptor\n");
- if (!gadget_is_dualspeed(fsg->gadget))
+ if (!gadget_is_dualspeed(fsg->gadget) ||
+ fsg->gadget->speed == USB_SPEED_SUPER)
break;
goto get_config;
case USB_DT_CONFIG:
@@ -967,7 +981,15 @@ get_config:
value = usb_gadget_get_string(&fsg_stringtab,
w_value & 0xff, req->buf);
break;
+
+ case USB_DT_BOS:
+ VDBG(fsg, "get bos descriptor\n");
+
+ if (gadget_is_superspeed(fsg->gadget))
+ value = populate_bos(fsg, req->buf);
+ break;
}
+
break;
/* One config, two speeds */
@@ -1136,7 +1158,6 @@ static int do_read(struct fsg_dev *fsg)
u32 amount_left;
loff_t file_offset, file_offset_tmp;
unsigned int amount;
- unsigned int partial_page;
ssize_t nread;
/* Get the starting Logical Block Address and check that it's
@@ -1158,7 +1179,7 @@ static int do_read(struct fsg_dev *fsg)
curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
return -EINVAL;
}
- file_offset = ((loff_t) lba) << 9;
+ file_offset = ((loff_t) lba) << curlun->blkbits;
/* Carry out the file reads */
amount_left = fsg->data_size_from_cmnd;
@@ -1171,17 +1192,10 @@ static int do_read(struct fsg_dev *fsg)
* Try to read the remaining amount.
* But don't read more than the buffer size.
* And don't try to read past the end of the file.
- * Finally, if we're not at a page boundary, don't read past
- * the next page.
- * If this means reading 0 then we were asked to read past
- * the end of file. */
+ */
amount = min((unsigned int) amount_left, mod_data.buflen);
amount = min((loff_t) amount,
curlun->file_length - file_offset);
- partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
- if (partial_page > 0)
- amount = min(amount, (unsigned int) PAGE_CACHE_SIZE -
- partial_page);
/* Wait for the next buffer to become available */
bh = fsg->next_buffhd_to_fill;
@@ -1196,7 +1210,7 @@ static int do_read(struct fsg_dev *fsg)
if (amount == 0) {
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info = file_offset >> curlun->blkbits;
curlun->info_valid = 1;
bh->inreq->length = 0;
bh->state = BUF_STATE_FULL;
@@ -1221,18 +1235,23 @@ static int do_read(struct fsg_dev *fsg)
} else if (nread < amount) {
LDBG(curlun, "partial file read: %d/%u\n",
(int) nread, amount);
- nread -= (nread & 511); // Round down to a block
+ nread = round_down(nread, curlun->blksize);
}
file_offset += nread;
amount_left -= nread;
fsg->residue -= nread;
+
+ /* Except at the end of the transfer, nread will be
+ * equal to the buffer size, which is divisible by the
+ * bulk-in maxpacket size.
+ */
bh->inreq->length = nread;
bh->state = BUF_STATE_FULL;
/* If an error occurred, report it and its position */
if (nread < amount) {
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info = file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1262,7 +1281,6 @@ static int do_write(struct fsg_dev *fsg)
u32 amount_left_to_req, amount_left_to_write;
loff_t usb_offset, file_offset, file_offset_tmp;
unsigned int amount;
- unsigned int partial_page;
ssize_t nwritten;
int rc;
@@ -1303,7 +1321,7 @@ static int do_write(struct fsg_dev *fsg)
/* Carry out the file writes */
get_some_more = 1;
- file_offset = usb_offset = ((loff_t) lba) << 9;
+ file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd;
while (amount_left_to_write > 0) {
@@ -1313,38 +1331,20 @@ static int do_write(struct fsg_dev *fsg)
if (bh->state == BUF_STATE_EMPTY && get_some_more) {
/* Figure out how much we want to get:
- * Try to get the remaining amount.
- * But don't get more than the buffer size.
- * And don't try to go past the end of the file.
- * If we're not at a page boundary,
- * don't go past the next page.
- * If this means getting 0, then we were asked
- * to write past the end of file.
- * Finally, round down to a block boundary. */
+ * Try to get the remaining amount,
+ * but not more than the buffer size.
+ */
amount = min(amount_left_to_req, mod_data.buflen);
- amount = min((loff_t) amount, curlun->file_length -
- usb_offset);
- partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
- if (partial_page > 0)
- amount = min(amount,
- (unsigned int) PAGE_CACHE_SIZE - partial_page);
-
- if (amount == 0) {
+
+ /* Beyond the end of the backing file? */
+ if (usb_offset >= curlun->file_length) {
get_some_more = 0;
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- curlun->sense_data_info = usb_offset >> 9;
+ curlun->sense_data_info = usb_offset >> curlun->blkbits;
curlun->info_valid = 1;
continue;
}
- amount -= (amount & 511);
- if (amount == 0) {
-
- /* Why were we were asked to transfer a
- * partial block? */
- get_some_more = 0;
- continue;
- }
/* Get the next buffer */
usb_offset += amount;
@@ -1353,11 +1353,11 @@ static int do_write(struct fsg_dev *fsg)
if (amount_left_to_req == 0)
get_some_more = 0;
- /* amount is always divisible by 512, hence by
- * the bulk-out maxpacket size */
- bh->outreq->length = bh->bulk_out_intended_length =
- amount;
- bh->outreq->short_not_ok = 1;
+ /* Except at the end of the transfer, amount will be
+ * equal to the buffer size, which is divisible by
+ * the bulk-out maxpacket size.
+ */
+ set_bulk_out_req_length(fsg, bh, amount);
start_transfer(fsg, fsg->bulk_out, bh->outreq,
&bh->outreq_busy, &bh->state);
fsg->next_buffhd_to_fill = bh->next;
@@ -1376,7 +1376,7 @@ static int do_write(struct fsg_dev *fsg)
/* Did something go wrong with the transfer? */
if (bh->outreq->status != 0) {
curlun->sense_data = SS_COMMUNICATION_FAILURE;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info = file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1390,6 +1390,16 @@ static int do_write(struct fsg_dev *fsg)
amount = curlun->file_length - file_offset;
}
+ /* Don't accept excess data. The spec doesn't say
+ * what to do in this case. We'll ignore the error.
+ */
+ amount = min(amount, bh->bulk_out_intended_length);
+
+ /* Don't write a partial block */
+ amount = round_down(amount, curlun->blksize);
+ if (amount == 0)
+ goto empty_write;
+
/* Perform the write */
file_offset_tmp = file_offset;
nwritten = vfs_write(curlun->filp,
@@ -1408,8 +1418,7 @@ static int do_write(struct fsg_dev *fsg)
} else if (nwritten < amount) {
LDBG(curlun, "partial file write: %d/%u\n",
(int) nwritten, amount);
- nwritten -= (nwritten & 511);
- // Round down to a block
+ nwritten = round_down(nwritten, curlun->blksize);
}
file_offset += nwritten;
amount_left_to_write -= nwritten;
@@ -1418,13 +1427,14 @@ static int do_write(struct fsg_dev *fsg)
/* If an error occurred, report it and its position */
if (nwritten < amount) {
curlun->sense_data = SS_WRITE_ERROR;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info = file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
+ empty_write:
/* Did the host decide to stop early? */
- if (bh->outreq->actual != bh->outreq->length) {
+ if (bh->outreq->actual < bh->bulk_out_intended_length) {
fsg->short_packet_received = 1;
break;
}
@@ -1500,8 +1510,8 @@ static int do_verify(struct fsg_dev *fsg)
return -EIO; // No default reply
/* Prepare to carry out the file verify */
- amount_left = verification_length << 9;
- file_offset = ((loff_t) lba) << 9;
+ amount_left = verification_length << curlun->blkbits;
+ file_offset = ((loff_t) lba) << curlun->blkbits;
/* Write out all the dirty buffers before invalidating them */
fsg_lun_fsync_sub(curlun);
@@ -1519,15 +1529,14 @@ static int do_verify(struct fsg_dev *fsg)
* Try to read the remaining amount, but not more than
* the buffer size.
* And don't try to read past the end of the file.
- * If this means reading 0 then we were asked to read
- * past the end of file. */
+ */
amount = min((unsigned int) amount_left, mod_data.buflen);
amount = min((loff_t) amount,
curlun->file_length - file_offset);
if (amount == 0) {
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info = file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1550,11 +1559,11 @@ static int do_verify(struct fsg_dev *fsg)
} else if (nread < amount) {
LDBG(curlun, "partial file verify: %d/%u\n",
(int) nread, amount);
- nread -= (nread & 511); // Round down to a sector
+ nread = round_down(nread, curlun->blksize);
}
if (nread == 0) {
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info = file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1668,7 +1677,7 @@ static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
/* Max logical block */
- put_unaligned_be32(512, &buf[4]); /* Block length */
+ put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
return 8;
}
@@ -1890,7 +1899,7 @@ static int do_read_format_capacities(struct fsg_dev *fsg,
put_unaligned_be32(curlun->num_sectors, &buf[0]);
/* Number of blocks */
- put_unaligned_be32(512, &buf[4]); /* Block length */
+ put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
buf[4] = 0x02; /* Current capacity */
return 12;
}
@@ -1969,7 +1978,7 @@ static int throw_away_data(struct fsg_dev *fsg)
fsg->next_buffhd_to_drain = bh->next;
/* A short packet or an error ends everything */
- if (bh->outreq->actual != bh->outreq->length ||
+ if (bh->outreq->actual < bh->bulk_out_intended_length ||
bh->outreq->status != 0) {
raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
return -EINTR;
@@ -1983,11 +1992,11 @@ static int throw_away_data(struct fsg_dev *fsg)
amount = min(fsg->usb_amount_left,
(u32) mod_data.buflen);
- /* amount is always divisible by 512, hence by
- * the bulk-out maxpacket size */
- bh->outreq->length = bh->bulk_out_intended_length =
- amount;
- bh->outreq->short_not_ok = 1;
+ /* Except at the end of the transfer, amount will be
+ * equal to the buffer size, which is divisible by
+ * the bulk-out maxpacket size.
+ */
+ set_bulk_out_req_length(fsg, bh, amount);
start_transfer(fsg, fsg->bulk_out, bh->outreq,
&bh->outreq_busy, &bh->state);
fsg->next_buffhd_to_fill = bh->next;
@@ -2415,7 +2424,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
case READ_6:
i = fsg->cmnd[4];
- fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+ fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
(7<<1) | (1<<4), 1,
"READ(6)")) == 0)
@@ -2424,7 +2433,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
case READ_10:
fsg->data_size_from_cmnd =
- get_unaligned_be16(&fsg->cmnd[7]) << 9;
+ get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1,
"READ(10)")) == 0)
@@ -2433,7 +2442,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
case READ_12:
fsg->data_size_from_cmnd =
- get_unaligned_be32(&fsg->cmnd[6]) << 9;
+ get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST,
(1<<1) | (0xf<<2) | (0xf<<6), 1,
"READ(12)")) == 0)
@@ -2519,7 +2528,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
case WRITE_6:
i = fsg->cmnd[4];
- fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+ fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
(7<<1) | (1<<4), 1,
"WRITE(6)")) == 0)
@@ -2528,7 +2537,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
case WRITE_10:
fsg->data_size_from_cmnd =
- get_unaligned_be16(&fsg->cmnd[7]) << 9;
+ get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1,
"WRITE(10)")) == 0)
@@ -2537,7 +2546,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
case WRITE_12:
fsg->data_size_from_cmnd =
- get_unaligned_be32(&fsg->cmnd[6]) << 9;
+ get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (0xf<<6), 1,
"WRITE(12)")) == 0)
@@ -2666,7 +2675,6 @@ static int get_next_command(struct fsg_dev *fsg)
/* Queue a request to read a Bulk-only CBW */
set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN);
- bh->outreq->short_not_ok = 1;
start_transfer(fsg, fsg->bulk_out, bh->outreq,
&bh->outreq_busy, &bh->state);
@@ -2752,7 +2760,7 @@ static int do_set_interface(struct fsg_dev *fsg, int altsetting)
reset:
/* Deallocate the requests */
- for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+ for (i = 0; i < fsg_num_buffers; ++i) {
struct fsg_buffhd *bh = &fsg->buffhds[i];
if (bh->inreq) {
@@ -2791,29 +2799,32 @@ reset:
/* Enable the endpoints */
d = fsg_ep_desc(fsg->gadget,
- &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc);
+ &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc,
+ &fsg_ss_bulk_in_desc);
if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0)
goto reset;
fsg->bulk_in_enabled = 1;
d = fsg_ep_desc(fsg->gadget,
- &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc);
+ &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc,
+ &fsg_ss_bulk_out_desc);
if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0)
goto reset;
fsg->bulk_out_enabled = 1;
- fsg->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize);
+ fsg->bulk_out_maxpacket = usb_endpoint_maxp(d);
clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
if (transport_is_cbi()) {
d = fsg_ep_desc(fsg->gadget,
- &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc);
+ &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc,
+ &fsg_ss_intr_in_desc);
if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0)
goto reset;
fsg->intr_in_enabled = 1;
}
/* Allocate the requests */
- for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+ for (i = 0; i < fsg_num_buffers; ++i) {
struct fsg_buffhd *bh = &fsg->buffhds[i];
if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0)
@@ -2862,17 +2873,10 @@ static int do_set_config(struct fsg_dev *fsg, u8 new_config)
fsg->config = new_config;
if ((rc = do_set_interface(fsg, 0)) != 0)
fsg->config = 0; // Reset on errors
- else {
- char *speed;
-
- switch (fsg->gadget->speed) {
- case USB_SPEED_LOW: speed = "low"; break;
- case USB_SPEED_FULL: speed = "full"; break;
- case USB_SPEED_HIGH: speed = "high"; break;
- default: speed = "?"; break;
- }
- INFO(fsg, "%s speed config #%d\n", speed, fsg->config);
- }
+ else
+ INFO(fsg, "%s config #%d\n",
+ usb_speed_string(fsg->gadget->speed),
+ fsg->config);
}
return rc;
}
@@ -2909,7 +2913,7 @@ static void handle_exception(struct fsg_dev *fsg)
/* Cancel all the pending transfers */
if (fsg->intreq_busy)
usb_ep_dequeue(fsg->intr_in, fsg->intreq);
- for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+ for (i = 0; i < fsg_num_buffers; ++i) {
bh = &fsg->buffhds[i];
if (bh->inreq_busy)
usb_ep_dequeue(fsg->bulk_in, bh->inreq);
@@ -2920,7 +2924,7 @@ static void handle_exception(struct fsg_dev *fsg)
/* Wait until everything is idle */
for (;;) {
num_active = fsg->intreq_busy;
- for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+ for (i = 0; i < fsg_num_buffers; ++i) {
bh = &fsg->buffhds[i];
num_active += bh->inreq_busy + bh->outreq_busy;
}
@@ -2942,7 +2946,7 @@ static void handle_exception(struct fsg_dev *fsg)
* state, and the exception. Then invoke the handler. */
spin_lock_irq(&fsg->lock);
- for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+ for (i = 0; i < fsg_num_buffers; ++i) {
bh = &fsg->buffhds[i];
bh->state = BUF_STATE_EMPTY;
}
@@ -3149,6 +3153,15 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
DBG(fsg, "unbind\n");
clear_bit(REGISTERED, &fsg->atomic_bitflags);
+ /* If the thread isn't already dead, tell it to exit now */
+ if (fsg->state != FSG_STATE_TERMINATED) {
+ raise_exception(fsg, FSG_STATE_EXIT);
+ wait_for_completion(&fsg->thread_notifier);
+
+ /* The cleanup routine waits for this completion also */
+ complete(&fsg->thread_notifier);
+ }
+
/* Unregister the sysfs attribute files and the LUNs */
for (i = 0; i < fsg->nluns; ++i) {
curlun = &fsg->luns[i];
@@ -3162,17 +3175,8 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
}
}
- /* If the thread isn't already dead, tell it to exit now */
- if (fsg->state != FSG_STATE_TERMINATED) {
- raise_exception(fsg, FSG_STATE_EXIT);
- wait_for_completion(&fsg->thread_notifier);
-
- /* The cleanup routine waits for this completion also */
- complete(&fsg->thread_notifier);
- }
-
/* Free the data buffers */
- for (i = 0; i < FSG_NUM_BUFFERS; ++i)
+ for (i = 0; i < fsg_num_buffers; ++i)
kfree(fsg->buffhds[i].buf);
/* Free the request and buffer for endpoint 0 */
@@ -3445,6 +3449,24 @@ static int __init fsg_bind(struct usb_gadget *gadget)
fsg_fs_intr_in_desc.bEndpointAddress;
}
+ if (gadget_is_superspeed(gadget)) {
+ unsigned max_burst;
+
+ fsg_ss_function[i + FSG_SS_FUNCTION_PRE_EP_ENTRIES] = NULL;
+
+ /* Calculate bMaxBurst, we know packet size is 1024 */
+ max_burst = min_t(unsigned, mod_data.buflen / 1024, 15);
+
+ /* Assume endpoint addresses are the same for both speeds */
+ fsg_ss_bulk_in_desc.bEndpointAddress =
+ fsg_fs_bulk_in_desc.bEndpointAddress;
+ fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
+
+ fsg_ss_bulk_out_desc.bEndpointAddress =
+ fsg_fs_bulk_out_desc.bEndpointAddress;
+ fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
+ }
+
if (gadget_is_otg(gadget))
fsg_otg_desc.bmAttributes |= USB_OTG_HNP;
@@ -3460,7 +3482,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
req->complete = ep0_complete;
/* Allocate the data buffers */
- for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+ for (i = 0; i < fsg_num_buffers; ++i) {
struct fsg_buffhd *bh = &fsg->buffhds[i];
/* Allocate for the bulk-in endpoint. We assume that
@@ -3471,7 +3493,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
goto out;
bh->next = bh + 1;
}
- fsg->buffhds[FSG_NUM_BUFFERS - 1].next = &fsg->buffhds[0];
+ fsg->buffhds[fsg_num_buffers - 1].next = &fsg->buffhds[0];
/* This should reflect the actual gadget power source */
usb_gadget_set_selfpowered(gadget);
@@ -3561,11 +3583,7 @@ static void fsg_resume(struct usb_gadget *gadget)
/*-------------------------------------------------------------------------*/
static struct usb_gadget_driver fsg_driver = {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- .speed = USB_SPEED_HIGH,
-#else
- .speed = USB_SPEED_FULL,
-#endif
+ .speed = USB_SPEED_SUPER,
.function = (char *) fsg_string_product,
.unbind = fsg_unbind,
.disconnect = fsg_disconnect,
@@ -3587,7 +3605,9 @@ static int __init fsg_alloc(void)
{
struct fsg_dev *fsg;
- fsg = kzalloc(sizeof *fsg, GFP_KERNEL);
+ fsg = kzalloc(sizeof *fsg +
+ fsg_num_buffers * sizeof *(fsg->buffhds), GFP_KERNEL);
+
if (!fsg)
return -ENOMEM;
spin_lock_init(&fsg->lock);
@@ -3605,6 +3625,10 @@ static int __init fsg_init(void)
int rc;
struct fsg_dev *fsg;
+ rc = fsg_num_buffers_validate();
+ if (rc != 0)
+ return rc;
+
if ((rc = fsg_alloc()) != 0)
return rc;
fsg = the_fsg;
diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c
index 3bf872e1ad39..2a03e4de11c1 100644
--- a/drivers/usb/gadget/fsl_qe_udc.c
+++ b/drivers/usb/gadget/fsl_qe_udc.c
@@ -540,7 +540,7 @@ static int qe_ep_init(struct qe_udc *udc,
int reval = 0;
u16 max = 0;
- max = le16_to_cpu(desc->wMaxPacketSize);
+ max = usb_endpoint_maxp(desc);
/* check the max package size validate for this endpoint */
/* Refer to USB2.0 spec table 9-13,
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index de24a4233c25..b2c44e1d5813 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -559,7 +559,7 @@ static int fsl_ep_enable(struct usb_ep *_ep,
if (!udc->driver || (udc->gadget.speed == USB_SPEED_UNKNOWN))
return -ESHUTDOWN;
- max = le16_to_cpu(desc->wMaxPacketSize);
+ max = usb_endpoint_maxp(desc);
/* Disable automatic zlp generation. Driver is responsible to indicate
* explicitly through req->req.zero. This is needed to enable multi-td
@@ -1715,34 +1715,31 @@ static void dtd_complete_irq(struct fsl_udc *udc)
}
}
+static inline enum usb_device_speed portscx_device_speed(u32 reg)
+{
+ switch (speed & PORTSCX_PORT_SPEED_MASK) {
+ case PORTSCX_PORT_SPEED_HIGH:
+ return USB_SPEED_HIGH;
+ case PORTSCX_PORT_SPEED_FULL:
+ return USB_SPEED_FULL;
+ case PORTSCX_PORT_SPEED_LOW:
+ return USB_SPEED_LOW;
+ default:
+ return USB_SPEED_UNKNOWN;
+ }
+}
+
/* Process a port change interrupt */
static void port_change_irq(struct fsl_udc *udc)
{
- u32 speed;
-
if (udc->bus_reset)
udc->bus_reset = 0;
/* Bus resetting is finished */
- if (!(fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET)) {
+ if (!(fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET))
/* Get the speed */
- speed = (fsl_readl(&dr_regs->portsc1)
- & PORTSCX_PORT_SPEED_MASK);
- switch (speed) {
- case PORTSCX_PORT_SPEED_HIGH:
- udc->gadget.speed = USB_SPEED_HIGH;
- break;
- case PORTSCX_PORT_SPEED_FULL:
- udc->gadget.speed = USB_SPEED_FULL;
- break;
- case PORTSCX_PORT_SPEED_LOW:
- udc->gadget.speed = USB_SPEED_LOW;
- break;
- default:
- udc->gadget.speed = USB_SPEED_UNKNOWN;
- break;
- }
- }
+ udc->gadget.speed =
+ portscx_device_speed(fsl_readl(&dr_regs->portsc1));
/* Update USB state */
if (!udc->resume_state)
@@ -2167,20 +2164,8 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
default:
s = "None"; break;
}
- s;} ), ( {
- char *s;
- switch (tmp_reg & PORTSCX_PORT_SPEED_UNDEF) {
- case PORTSCX_PORT_SPEED_FULL:
- s = "Full Speed"; break;
- case PORTSCX_PORT_SPEED_LOW:
- s = "Low Speed"; break;
- case PORTSCX_PORT_SPEED_HIGH:
- s = "High Speed"; break;
- default:
- s = "Undefined"; break;
- }
- s;
- } ),
+ s;} ),
+ usb_speed_string(portscx_device_speed(tmp_reg)),
(tmp_reg & PORTSCX_PHY_LOW_POWER_SPD) ?
"Normal PHY mode" : "Low power mode",
(tmp_reg & PORTSCX_PORT_RESET) ? "In Reset" :
diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c
index 4ec888f90002..e593f2849fa9 100644
--- a/drivers/usb/gadget/fusb300_udc.c
+++ b/drivers/usb/gadget/fusb300_udc.c
@@ -8,16 +8,6 @@
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include <linux/dma-mapping.h>
#include <linux/err.h>
@@ -220,7 +210,7 @@ static int config_ep(struct fusb300_ep *ep,
info.type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
info.dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0;
- info.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+ info.maxpacket = usb_endpoint_maxp(desc);
info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
if ((info.type == USB_ENDPOINT_XFER_INT) ||
@@ -1479,7 +1469,7 @@ static int __init fusb300_probe(struct platform_device *pdev)
fusb300->gadget.name = udc_name;
fusb300->reg = reg;
- ret = request_irq(ires->start, fusb300_irq, IRQF_DISABLED | IRQF_SHARED,
+ ret = request_irq(ires->start, fusb300_irq, IRQF_SHARED,
udc_name, fusb300);
if (ret < 0) {
pr_err("request_irq error (%d)\n", ret);
@@ -1487,7 +1477,7 @@ static int __init fusb300_probe(struct platform_device *pdev)
}
ret = request_irq(ires1->start, fusb300_irq,
- IRQF_DISABLED | IRQF_SHARED, udc_name, fusb300);
+ IRQF_SHARED, udc_name, fusb300);
if (ret < 0) {
pr_err("request_irq1 error (%d)\n", ret);
goto clean_up;
diff --git a/drivers/usb/gadget/fusb300_udc.h b/drivers/usb/gadget/fusb300_udc.h
index f51aa2ef1f90..92745bd03064 100644
--- a/drivers/usb/gadget/fusb300_udc.h
+++ b/drivers/usb/gadget/fusb300_udc.h
@@ -8,16 +8,6 @@
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c
index 704c2800ac00..0519d77915ec 100644
--- a/drivers/usb/gadget/g_ffs.c
+++ b/drivers/usb/gadget/g_ffs.c
@@ -8,15 +8,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define pr_fmt(fmt) "g_ffs: " fmt
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index f3a83cd0ef50..a8855d0b7f3b 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -31,6 +31,7 @@
#define gadget_is_ci13xxx_msm(g) (!strcmp("ci13xxx_msm", (g)->name))
#define gadget_is_ci13xxx_pci(g) (!strcmp("ci13xxx_pci", (g)->name))
#define gadget_is_dummy(g) (!strcmp("dummy_udc", (g)->name))
+#define gadget_is_dwc3(g) (!strcmp("dwc3-gadget", (g)->name))
#define gadget_is_fsl_qe(g) (!strcmp("fsl_qe_udc", (g)->name))
#define gadget_is_fsl_usb2(g) (!strcmp("fsl-usb2-udc", (g)->name))
#define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name))
@@ -115,6 +116,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x30;
else if (gadget_is_net2272(gadget))
return 0x31;
+ else if (gadget_is_dwc3(gadget))
+ return 0x32;
return -ENOENT;
}
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index 8b9220e128a7..8fcde37aa6d4 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -36,134 +36,43 @@
#include "gadget_chips.h"
-
-/*
- * Kbuild is not very cooperative with respect to linking separately
- * compiled library objects into one module. So for now we won't use
- * separate compilation ... ensuring init/exit sections work to shrink
- * the runtime footprint, and giving us at least some parts of what
- * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
- */
+#include "composite.c"
#include "usbstring.c"
#include "config.c"
#include "epautoconf.c"
+#include "f_midi.c"
/*-------------------------------------------------------------------------*/
-
MODULE_AUTHOR("Ben Williamson");
MODULE_LICENSE("GPL v2");
-#define DRIVER_VERSION "25 Jul 2006"
-
static const char shortname[] = "g_midi";
static const char longname[] = "MIDI Gadget";
static int index = SNDRV_DEFAULT_IDX1;
-static char *id = SNDRV_DEFAULT_STR1;
-
-module_param(index, int, 0444);
+module_param(index, int, S_IRUGO);
MODULE_PARM_DESC(index, "Index value for the USB MIDI Gadget adapter.");
-module_param(id, charp, 0444);
-MODULE_PARM_DESC(id, "ID string for the USB MIDI Gadget adapter.");
-
-/* Some systems will want different product identifiers published in the
- * device descriptor, either numbers or strings or both. These string
- * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
- */
-
-static ushort idVendor;
-module_param(idVendor, ushort, S_IRUGO);
-MODULE_PARM_DESC(idVendor, "USB Vendor ID");
-
-static ushort idProduct;
-module_param(idProduct, ushort, S_IRUGO);
-MODULE_PARM_DESC(idProduct, "USB Product ID");
-
-static ushort bcdDevice;
-module_param(bcdDevice, ushort, S_IRUGO);
-MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
-
-static char *iManufacturer;
-module_param(iManufacturer, charp, S_IRUGO);
-MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
-
-static char *iProduct;
-module_param(iProduct, charp, S_IRUGO);
-MODULE_PARM_DESC(iProduct, "USB Product string");
-
-static char *iSerialNumber;
-module_param(iSerialNumber, charp, S_IRUGO);
-MODULE_PARM_DESC(iSerialNumber, "SerialNumber");
-
-/*
- * this version autoconfigures as much as possible,
- * which is reasonable for most "bulk-only" drivers.
- */
-static const char *EP_IN_NAME;
-static const char *EP_OUT_NAME;
+static char *id = SNDRV_DEFAULT_STR1;
+module_param(id, charp, S_IRUGO);
+MODULE_PARM_DESC(id, "ID string for the USB MIDI Gadget adapter.");
-/* big enough to hold our biggest descriptor */
-#define USB_BUFSIZ 256
-
-
-/* This is a gadget, and the IN/OUT naming is from the host's perspective.
- USB -> OUT endpoint -> rawmidi
- USB <- IN endpoint <- rawmidi */
-struct gmidi_in_port {
- struct gmidi_device* dev;
- int active;
- uint8_t cable; /* cable number << 4 */
- uint8_t state;
-#define STATE_UNKNOWN 0
-#define STATE_1PARAM 1
-#define STATE_2PARAM_1 2
-#define STATE_2PARAM_2 3
-#define STATE_SYSEX_0 4
-#define STATE_SYSEX_1 5
-#define STATE_SYSEX_2 6
- uint8_t data[2];
-};
-
-struct gmidi_device {
- spinlock_t lock;
- struct usb_gadget *gadget;
- struct usb_request *req; /* for control responses */
- u8 config;
- struct usb_ep *in_ep, *out_ep;
- struct snd_card *card;
- struct snd_rawmidi *rmidi;
- struct snd_rawmidi_substream *in_substream;
- struct snd_rawmidi_substream *out_substream;
-
- /* For the moment we only support one port in
- each direction, but in_port is kept as a
- separate struct so we can have more later. */
- struct gmidi_in_port in_port;
- unsigned long out_triggered;
- struct tasklet_struct tasklet;
-};
-
-static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req);
-
-
-#define DBG(d, fmt, args...) \
- dev_dbg(&(d)->gadget->dev , fmt , ## args)
-#define VDBG(d, fmt, args...) \
- dev_vdbg(&(d)->gadget->dev , fmt , ## args)
-#define ERROR(d, fmt, args...) \
- dev_err(&(d)->gadget->dev , fmt , ## args)
-#define INFO(d, fmt, args...) \
- dev_info(&(d)->gadget->dev , fmt , ## args)
-
-
-static unsigned buflen = 256;
-static unsigned qlen = 32;
-
+static unsigned int buflen = 256;
module_param(buflen, uint, S_IRUGO);
+MODULE_PARM_DESC(buflen, "MIDI buffer length");
+
+static unsigned int qlen = 32;
module_param(qlen, uint, S_IRUGO);
+MODULE_PARM_DESC(qlen, "USB read request queue length");
+static unsigned int in_ports = 1;
+module_param(in_ports, uint, S_IRUGO);
+MODULE_PARM_DESC(in_ports, "Number of MIDI input ports");
+
+static unsigned int out_ports = 1;
+module_param(out_ports, uint, S_IRUGO);
+MODULE_PARM_DESC(out_ports, "Number of MIDI output ports");
/* Thanks to Grey Innovation for donating this product ID.
*
@@ -173,1149 +82,124 @@ module_param(qlen, uint, S_IRUGO);
#define DRIVER_VENDOR_NUM 0x17b3 /* Grey Innovation */
#define DRIVER_PRODUCT_NUM 0x0004 /* Linux-USB "MIDI Gadget" */
+/* string IDs are assigned dynamically */
-/*
- * DESCRIPTORS ... most are static, but strings and (full)
- * configuration descriptors are built on demand.
- */
-
-#define STRING_MANUFACTURER 25
-#define STRING_PRODUCT 42
-#define STRING_SERIAL 101
-#define STRING_MIDI_GADGET 250
+#define STRING_MANUFACTURER_IDX 0
+#define STRING_PRODUCT_IDX 1
+#define STRING_DESCRIPTION_IDX 2
-/* We only have the one configuration, it's number 1. */
-#define GMIDI_CONFIG 1
-
-/* We have two interfaces- AudioControl and MIDIStreaming */
-#define GMIDI_AC_INTERFACE 0
-#define GMIDI_MS_INTERFACE 1
-#define GMIDI_NUM_INTERFACES 2
-
-DECLARE_UAC_AC_HEADER_DESCRIPTOR(1);
-DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1);
-DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(1);
-
-/* B.1 Device Descriptor */
static struct usb_device_descriptor device_desc = {
.bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = cpu_to_le16(0x0200),
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
.bDeviceClass = USB_CLASS_PER_INTERFACE,
- .idVendor = cpu_to_le16(DRIVER_VENDOR_NUM),
- .idProduct = cpu_to_le16(DRIVER_PRODUCT_NUM),
- .iManufacturer = STRING_MANUFACTURER,
- .iProduct = STRING_PRODUCT,
+ .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_NUM),
+ .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_NUM),
+ /* .iManufacturer = DYNAMIC */
+ /* .iProduct = DYNAMIC */
.bNumConfigurations = 1,
};
-/* B.2 Configuration Descriptor */
-static struct usb_config_descriptor config_desc = {
- .bLength = USB_DT_CONFIG_SIZE,
- .bDescriptorType = USB_DT_CONFIG,
- /* compute wTotalLength on the fly */
- .bNumInterfaces = GMIDI_NUM_INTERFACES,
- .bConfigurationValue = GMIDI_CONFIG,
- .iConfiguration = STRING_MIDI_GADGET,
- /*
- * FIXME: When embedding this driver in a device,
- * these need to be set to reflect the actual
- * power properties of the device. Is it selfpowered?
- */
- .bmAttributes = USB_CONFIG_ATT_ONE,
- .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2,
-};
-
-/* B.3.1 Standard AC Interface Descriptor */
-static const struct usb_interface_descriptor ac_interface_desc = {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = GMIDI_AC_INTERFACE,
- .bNumEndpoints = 0,
- .bInterfaceClass = USB_CLASS_AUDIO,
- .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
- .iInterface = STRING_MIDI_GADGET,
-};
-
-/* B.3.2 Class-Specific AC Interface Descriptor */
-static const struct uac1_ac_header_descriptor_1 ac_header_desc = {
- .bLength = UAC_DT_AC_HEADER_SIZE(1),
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubtype = USB_MS_HEADER,
- .bcdADC = cpu_to_le16(0x0100),
- .wTotalLength = cpu_to_le16(UAC_DT_AC_HEADER_SIZE(1)),
- .bInCollection = 1,
- .baInterfaceNr = {
- [0] = GMIDI_MS_INTERFACE,
- }
-};
-
-/* B.4.1 Standard MS Interface Descriptor */
-static const struct usb_interface_descriptor ms_interface_desc = {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = GMIDI_MS_INTERFACE,
- .bNumEndpoints = 2,
- .bInterfaceClass = USB_CLASS_AUDIO,
- .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING,
- .iInterface = STRING_MIDI_GADGET,
+static struct usb_string strings_dev[] = {
+ [STRING_MANUFACTURER_IDX].s = "Grey Innovation",
+ [STRING_PRODUCT_IDX].s = "MIDI Gadget",
+ [STRING_DESCRIPTION_IDX].s = "MIDI",
+ { } /* end of list */
};
-/* B.4.2 Class-Specific MS Interface Descriptor */
-static const struct usb_ms_header_descriptor ms_header_desc = {
- .bLength = USB_DT_MS_HEADER_SIZE,
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubtype = USB_MS_HEADER,
- .bcdMSC = cpu_to_le16(0x0100),
- .wTotalLength = cpu_to_le16(USB_DT_MS_HEADER_SIZE
- + 2*USB_DT_MIDI_IN_SIZE
- + 2*USB_DT_MIDI_OUT_SIZE(1)),
-};
-
-#define JACK_IN_EMB 1
-#define JACK_IN_EXT 2
-#define JACK_OUT_EMB 3
-#define JACK_OUT_EXT 4
-
-/* B.4.3 MIDI IN Jack Descriptors */
-static const struct usb_midi_in_jack_descriptor jack_in_emb_desc = {
- .bLength = USB_DT_MIDI_IN_SIZE,
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubtype = USB_MS_MIDI_IN_JACK,
- .bJackType = USB_MS_EMBEDDED,
- .bJackID = JACK_IN_EMB,
-};
-
-static const struct usb_midi_in_jack_descriptor jack_in_ext_desc = {
- .bLength = USB_DT_MIDI_IN_SIZE,
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubtype = USB_MS_MIDI_IN_JACK,
- .bJackType = USB_MS_EXTERNAL,
- .bJackID = JACK_IN_EXT,
-};
-
-/* B.4.4 MIDI OUT Jack Descriptors */
-static const struct usb_midi_out_jack_descriptor_1 jack_out_emb_desc = {
- .bLength = USB_DT_MIDI_OUT_SIZE(1),
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubtype = USB_MS_MIDI_OUT_JACK,
- .bJackType = USB_MS_EMBEDDED,
- .bJackID = JACK_OUT_EMB,
- .bNrInputPins = 1,
- .pins = {
- [0] = {
- .baSourceID = JACK_IN_EXT,
- .baSourcePin = 1,
- }
- }
-};
-
-static const struct usb_midi_out_jack_descriptor_1 jack_out_ext_desc = {
- .bLength = USB_DT_MIDI_OUT_SIZE(1),
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubtype = USB_MS_MIDI_OUT_JACK,
- .bJackType = USB_MS_EXTERNAL,
- .bJackID = JACK_OUT_EXT,
- .bNrInputPins = 1,
- .pins = {
- [0] = {
- .baSourceID = JACK_IN_EMB,
- .baSourcePin = 1,
- }
- }
-};
-
-/* B.5.1 Standard Bulk OUT Endpoint Descriptor */
-static struct usb_endpoint_descriptor bulk_out_desc = {
- .bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
-};
-
-/* B.5.2 Class-specific MS Bulk OUT Endpoint Descriptor */
-static const struct usb_ms_endpoint_descriptor_1 ms_out_desc = {
- .bLength = USB_DT_MS_ENDPOINT_SIZE(1),
- .bDescriptorType = USB_DT_CS_ENDPOINT,
- .bDescriptorSubtype = USB_MS_GENERAL,
- .bNumEmbMIDIJack = 1,
- .baAssocJackID = {
- [0] = JACK_IN_EMB,
- }
-};
-
-/* B.6.1 Standard Bulk IN Endpoint Descriptor */
-static struct usb_endpoint_descriptor bulk_in_desc = {
- .bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
-};
-
-/* B.6.2 Class-specific MS Bulk IN Endpoint Descriptor */
-static const struct usb_ms_endpoint_descriptor_1 ms_in_desc = {
- .bLength = USB_DT_MS_ENDPOINT_SIZE(1),
- .bDescriptorType = USB_DT_CS_ENDPOINT,
- .bDescriptorSubtype = USB_MS_GENERAL,
- .bNumEmbMIDIJack = 1,
- .baAssocJackID = {
- [0] = JACK_OUT_EMB,
- }
-};
-
-static const struct usb_descriptor_header *gmidi_function [] = {
- (struct usb_descriptor_header *)&ac_interface_desc,
- (struct usb_descriptor_header *)&ac_header_desc,
- (struct usb_descriptor_header *)&ms_interface_desc,
-
- (struct usb_descriptor_header *)&ms_header_desc,
- (struct usb_descriptor_header *)&jack_in_emb_desc,
- (struct usb_descriptor_header *)&jack_in_ext_desc,
- (struct usb_descriptor_header *)&jack_out_emb_desc,
- (struct usb_descriptor_header *)&jack_out_ext_desc,
- /* If you add more jacks, update ms_header_desc.wTotalLength */
-
- (struct usb_descriptor_header *)&bulk_out_desc,
- (struct usb_descriptor_header *)&ms_out_desc,
- (struct usb_descriptor_header *)&bulk_in_desc,
- (struct usb_descriptor_header *)&ms_in_desc,
- NULL,
-};
-
-static char manufacturer[50];
-static char product_desc[40] = "MIDI Gadget";
-static char serial_number[20];
-
-/* static strings, in UTF-8 */
-static struct usb_string strings [] = {
- { STRING_MANUFACTURER, manufacturer, },
- { STRING_PRODUCT, product_desc, },
- { STRING_SERIAL, serial_number, },
- { STRING_MIDI_GADGET, longname, },
- { } /* end of list */
-};
-
-static struct usb_gadget_strings stringtab = {
+static struct usb_gadget_strings stringtab_dev = {
.language = 0x0409, /* en-us */
- .strings = strings,
+ .strings = strings_dev,
};
-static int config_buf(struct usb_gadget *gadget,
- u8 *buf, u8 type, unsigned index)
-{
- int len;
-
- /* only one configuration */
- if (index != 0) {
- return -EINVAL;
- }
- len = usb_gadget_config_buf(&config_desc,
- buf, USB_BUFSIZ, gmidi_function);
- if (len < 0) {
- return len;
- }
- ((struct usb_config_descriptor *)buf)->bDescriptorType = type;
- return len;
-}
-
-static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
-{
- struct usb_request *req;
-
- req = usb_ep_alloc_request(ep, GFP_ATOMIC);
- if (req) {
- req->length = length;
- req->buf = kmalloc(length, GFP_ATOMIC);
- if (!req->buf) {
- usb_ep_free_request(ep, req);
- req = NULL;
- }
- }
- return req;
-}
-
-static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
-{
- kfree(req->buf);
- usb_ep_free_request(ep, req);
-}
-
-static const uint8_t gmidi_cin_length[] = {
- 0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1
+static struct usb_gadget_strings *dev_strings[] = {
+ &stringtab_dev,
+ NULL,
};
-/*
- * Receives a chunk of MIDI data.
- */
-static void gmidi_read_data(struct usb_ep *ep, int cable,
- uint8_t *data, int length)
-{
- struct gmidi_device *dev = ep->driver_data;
- /* cable is ignored, because for now we only have one. */
-
- if (!dev->out_substream) {
- /* Nobody is listening - throw it on the floor. */
- return;
- }
- if (!test_bit(dev->out_substream->number, &dev->out_triggered)) {
- return;
- }
- snd_rawmidi_receive(dev->out_substream, data, length);
-}
-
-static void gmidi_handle_out_data(struct usb_ep *ep, struct usb_request *req)
-{
- unsigned i;
- u8 *buf = req->buf;
-
- for (i = 0; i + 3 < req->actual; i += 4) {
- if (buf[i] != 0) {
- int cable = buf[i] >> 4;
- int length = gmidi_cin_length[buf[i] & 0x0f];
- gmidi_read_data(ep, cable, &buf[i + 1], length);
- }
- }
-}
-
-static void gmidi_complete(struct usb_ep *ep, struct usb_request *req)
-{
- struct gmidi_device *dev = ep->driver_data;
- int status = req->status;
-
- switch (status) {
- case 0: /* normal completion */
- if (ep == dev->out_ep) {
- /* we received stuff.
- req is queued again, below */
- gmidi_handle_out_data(ep, req);
- } else if (ep == dev->in_ep) {
- /* our transmit completed.
- see if there's more to go.
- gmidi_transmit eats req, don't queue it again. */
- gmidi_transmit(dev, req);
- return;
- }
- break;
-
- /* this endpoint is normally active while we're configured */
- case -ECONNABORTED: /* hardware forced ep reset */
- case -ECONNRESET: /* request dequeued */
- case -ESHUTDOWN: /* disconnect from host */
- VDBG(dev, "%s gone (%d), %d/%d\n", ep->name, status,
- req->actual, req->length);
- if (ep == dev->out_ep) {
- gmidi_handle_out_data(ep, req);
- }
- free_ep_req(ep, req);
- return;
-
- case -EOVERFLOW: /* buffer overrun on read means that
- * we didn't provide a big enough
- * buffer.
- */
- default:
- DBG(dev, "%s complete --> %d, %d/%d\n", ep->name,
- status, req->actual, req->length);
- break;
- case -EREMOTEIO: /* short read */
- break;
- }
-
- status = usb_ep_queue(ep, req, GFP_ATOMIC);
- if (status) {
- ERROR(dev, "kill %s: resubmit %d bytes --> %d\n",
- ep->name, req->length, status);
- usb_ep_set_halt(ep);
- /* FIXME recover later ... somehow */
- }
-}
-
-static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags)
-{
- int err = 0;
- struct usb_request *req;
- struct usb_ep *ep;
- unsigned i;
-
- dev->in_ep->desc = &bulk_in_desc;
- err = usb_ep_enable(dev->in_ep);
- if (err) {
- ERROR(dev, "can't start %s: %d\n", dev->in_ep->name, err);
- goto fail;
- }
- dev->in_ep->driver_data = dev;
-
- dev->out_ep->desc = &bulk_out_desc;
- err = usb_ep_enable(dev->out_ep);
- if (err) {
- ERROR(dev, "can't start %s: %d\n", dev->out_ep->name, err);
- goto fail;
- }
- dev->out_ep->driver_data = dev;
-
- /* allocate a bunch of read buffers and queue them all at once. */
- ep = dev->out_ep;
- for (i = 0; i < qlen && err == 0; i++) {
- req = alloc_ep_req(ep, buflen);
- if (req) {
- req->complete = gmidi_complete;
- err = usb_ep_queue(ep, req, GFP_ATOMIC);
- if (err) {
- DBG(dev, "%s queue req: %d\n", ep->name, err);
- }
- } else {
- err = -ENOMEM;
- }
- }
-fail:
- /* caller is responsible for cleanup on error */
- return err;
-}
-
-
-static void gmidi_reset_config(struct gmidi_device *dev)
-{
- if (dev->config == 0) {
- return;
- }
-
- DBG(dev, "reset config\n");
-
- /* just disable endpoints, forcing completion of pending i/o.
- * all our completion handlers free their requests in this case.
- */
- usb_ep_disable(dev->in_ep);
- usb_ep_disable(dev->out_ep);
- dev->config = 0;
-}
-
-/* change our operational config. this code must agree with the code
- * that returns config descriptors, and altsetting code.
- *
- * it's also responsible for power management interactions. some
- * configurations might not work with our current power sources.
- *
- * note that some device controller hardware will constrain what this
- * code can do, perhaps by disallowing more than one configuration or
- * by limiting configuration choices (like the pxa2xx).
- */
-static int
-gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags)
-{
- int result = 0;
- struct usb_gadget *gadget = dev->gadget;
-
-#if 0
- /* FIXME */
- /* Hacking this bit out fixes a bug where on receipt of two
- USB_REQ_SET_CONFIGURATION messages, we end up with no
- buffered OUT requests waiting for data. This is clearly
- hiding a bug elsewhere, because if the config didn't
- change then we really shouldn't do anything. */
- /* Having said that, when we do "change" from config 1
- to config 1, we at least gmidi_reset_config() which
- clears out any requests on endpoints, so it's not like
- we leak or anything. */
- if (number == dev->config) {
- return 0;
- }
-#endif
-
- gmidi_reset_config(dev);
-
- switch (number) {
- case GMIDI_CONFIG:
- result = set_gmidi_config(dev, gfp_flags);
- break;
- default:
- result = -EINVAL;
- /* FALL THROUGH */
- case 0:
- return result;
- }
-
- if (!result && (!dev->in_ep || !dev->out_ep)) {
- result = -ENODEV;
- }
- if (result) {
- gmidi_reset_config(dev);
- } else {
- char *speed;
-
- switch (gadget->speed) {
- case USB_SPEED_LOW: speed = "low"; break;
- case USB_SPEED_FULL: speed = "full"; break;
- case USB_SPEED_HIGH: speed = "high"; break;
- default: speed = "?"; break;
- }
-
- dev->config = number;
- INFO(dev, "%s speed\n", speed);
- }
- return result;
-}
-
-
-static void gmidi_setup_complete(struct usb_ep *ep, struct usb_request *req)
-{
- if (req->status || req->actual != req->length) {
- DBG((struct gmidi_device *) ep->driver_data,
- "setup complete --> %d, %d/%d\n",
- req->status, req->actual, req->length);
- }
-}
-
-/*
- * The setup() callback implements all the ep0 functionality that's
- * not handled lower down, in hardware or the hardware driver (like
- * device and endpoint feature flags, and their status). It's all
- * housekeeping for the gadget function we're implementing. Most of
- * the work is in config-specific setup.
- */
-static int gmidi_setup(struct usb_gadget *gadget,
- const struct usb_ctrlrequest *ctrl)
-{
- struct gmidi_device *dev = get_gadget_data(gadget);
- struct usb_request *req = dev->req;
- int value = -EOPNOTSUPP;
- u16 w_index = le16_to_cpu(ctrl->wIndex);
- u16 w_value = le16_to_cpu(ctrl->wValue);
- u16 w_length = le16_to_cpu(ctrl->wLength);
-
- /* usually this stores reply data in the pre-allocated ep0 buffer,
- * but config change events will reconfigure hardware.
- */
- req->zero = 0;
- switch (ctrl->bRequest) {
-
- case USB_REQ_GET_DESCRIPTOR:
- if (ctrl->bRequestType != USB_DIR_IN) {
- goto unknown;
- }
- switch (w_value >> 8) {
-
- case USB_DT_DEVICE:
- device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
- value = min(w_length, (u16) sizeof(device_desc));
- memcpy(req->buf, &device_desc, value);
- break;
- case USB_DT_CONFIG:
- value = config_buf(gadget, req->buf,
- w_value >> 8,
- w_value & 0xff);
- if (value >= 0) {
- value = min(w_length, (u16)value);
- }
- break;
-
- case USB_DT_STRING:
- /* wIndex == language code.
- * this driver only handles one language, you can
- * add string tables for other languages, using
- * any UTF-8 characters
- */
- value = usb_gadget_get_string(&stringtab,
- w_value & 0xff, req->buf);
- if (value >= 0) {
- value = min(w_length, (u16)value);
- }
- break;
- }
- break;
-
- /* currently two configs, two speeds */
- case USB_REQ_SET_CONFIGURATION:
- if (ctrl->bRequestType != 0) {
- goto unknown;
- }
- if (gadget->a_hnp_support) {
- DBG(dev, "HNP available\n");
- } else if (gadget->a_alt_hnp_support) {
- DBG(dev, "HNP needs a different root port\n");
- } else {
- VDBG(dev, "HNP inactive\n");
- }
- spin_lock(&dev->lock);
- value = gmidi_set_config(dev, w_value, GFP_ATOMIC);
- spin_unlock(&dev->lock);
- break;
- case USB_REQ_GET_CONFIGURATION:
- if (ctrl->bRequestType != USB_DIR_IN) {
- goto unknown;
- }
- *(u8 *)req->buf = dev->config;
- value = min(w_length, (u16)1);
- break;
-
- /* until we add altsetting support, or other interfaces,
- * only 0/0 are possible. pxa2xx only supports 0/0 (poorly)
- * and already killed pending endpoint I/O.
- */
- case USB_REQ_SET_INTERFACE:
- if (ctrl->bRequestType != USB_RECIP_INTERFACE) {
- goto unknown;
- }
- spin_lock(&dev->lock);
- if (dev->config && w_index < GMIDI_NUM_INTERFACES
- && w_value == 0)
- {
- u8 config = dev->config;
-
- /* resets interface configuration, forgets about
- * previous transaction state (queued bufs, etc)
- * and re-inits endpoint state (toggle etc)
- * no response queued, just zero status == success.
- * if we had more than one interface we couldn't
- * use this "reset the config" shortcut.
- */
- gmidi_reset_config(dev);
- gmidi_set_config(dev, config, GFP_ATOMIC);
- value = 0;
- }
- spin_unlock(&dev->lock);
- break;
- case USB_REQ_GET_INTERFACE:
- if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) {
- goto unknown;
- }
- if (!dev->config) {
- break;
- }
- if (w_index >= GMIDI_NUM_INTERFACES) {
- value = -EDOM;
- break;
- }
- *(u8 *)req->buf = 0;
- value = min(w_length, (u16)1);
- break;
-
- default:
-unknown:
- VDBG(dev, "unknown control req%02x.%02x v%04x i%04x l%d\n",
- ctrl->bRequestType, ctrl->bRequest,
- w_value, w_index, w_length);
- }
-
- /* respond with data transfer before status phase? */
- if (value >= 0) {
- req->length = value;
- req->zero = value < w_length;
- value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
- if (value < 0) {
- DBG(dev, "ep_queue --> %d\n", value);
- req->status = 0;
- gmidi_setup_complete(gadget->ep0, req);
- }
- }
-
- /* device either stalls (value < 0) or reports success */
- return value;
-}
-
-static void gmidi_disconnect(struct usb_gadget *gadget)
-{
- struct gmidi_device *dev = get_gadget_data(gadget);
- unsigned long flags;
-
- spin_lock_irqsave(&dev->lock, flags);
- gmidi_reset_config(dev);
-
- /* a more significant application might have some non-usb
- * activities to quiesce here, saving resources like power
- * or pushing the notification up a network stack.
- */
- spin_unlock_irqrestore(&dev->lock, flags);
-
- /* next we may get setup() calls to enumerate new connections;
- * or an unbind() during shutdown (including removing module).
- */
-}
-
-static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget)
-{
- struct gmidi_device *dev = get_gadget_data(gadget);
- struct snd_card *card;
-
- DBG(dev, "unbind\n");
-
- card = dev->card;
- dev->card = NULL;
- if (card) {
- snd_card_free(card);
- }
-
- /* we've already been disconnected ... no i/o is active */
- if (dev->req) {
- dev->req->length = USB_BUFSIZ;
- free_ep_req(gadget->ep0, dev->req);
- }
- kfree(dev);
- set_gadget_data(gadget, NULL);
-}
-
-static int gmidi_snd_free(struct snd_device *device)
+static int __exit midi_unbind(struct usb_composite_dev *dev)
{
return 0;
}
-static void gmidi_transmit_packet(struct usb_request *req, uint8_t p0,
- uint8_t p1, uint8_t p2, uint8_t p3)
-{
- unsigned length = req->length;
- u8 *buf = (u8 *)req->buf + length;
-
- buf[0] = p0;
- buf[1] = p1;
- buf[2] = p2;
- buf[3] = p3;
- req->length = length + 4;
-}
-
-/*
- * Converts MIDI commands to USB MIDI packets.
- */
-static void gmidi_transmit_byte(struct usb_request *req,
- struct gmidi_in_port *port, uint8_t b)
-{
- uint8_t p0 = port->cable;
-
- if (b >= 0xf8) {
- gmidi_transmit_packet(req, p0 | 0x0f, b, 0, 0);
- } else if (b >= 0xf0) {
- switch (b) {
- case 0xf0:
- port->data[0] = b;
- port->state = STATE_SYSEX_1;
- break;
- case 0xf1:
- case 0xf3:
- port->data[0] = b;
- port->state = STATE_1PARAM;
- break;
- case 0xf2:
- port->data[0] = b;
- port->state = STATE_2PARAM_1;
- break;
- case 0xf4:
- case 0xf5:
- port->state = STATE_UNKNOWN;
- break;
- case 0xf6:
- gmidi_transmit_packet(req, p0 | 0x05, 0xf6, 0, 0);
- port->state = STATE_UNKNOWN;
- break;
- case 0xf7:
- switch (port->state) {
- case STATE_SYSEX_0:
- gmidi_transmit_packet(req,
- p0 | 0x05, 0xf7, 0, 0);
- break;
- case STATE_SYSEX_1:
- gmidi_transmit_packet(req,
- p0 | 0x06, port->data[0], 0xf7, 0);
- break;
- case STATE_SYSEX_2:
- gmidi_transmit_packet(req,
- p0 | 0x07, port->data[0],
- port->data[1], 0xf7);
- break;
- }
- port->state = STATE_UNKNOWN;
- break;
- }
- } else if (b >= 0x80) {
- port->data[0] = b;
- if (b >= 0xc0 && b <= 0xdf)
- port->state = STATE_1PARAM;
- else
- port->state = STATE_2PARAM_1;
- } else { /* b < 0x80 */
- switch (port->state) {
- case STATE_1PARAM:
- if (port->data[0] < 0xf0) {
- p0 |= port->data[0] >> 4;
- } else {
- p0 |= 0x02;
- port->state = STATE_UNKNOWN;
- }
- gmidi_transmit_packet(req, p0, port->data[0], b, 0);
- break;
- case STATE_2PARAM_1:
- port->data[1] = b;
- port->state = STATE_2PARAM_2;
- break;
- case STATE_2PARAM_2:
- if (port->data[0] < 0xf0) {
- p0 |= port->data[0] >> 4;
- port->state = STATE_2PARAM_1;
- } else {
- p0 |= 0x03;
- port->state = STATE_UNKNOWN;
- }
- gmidi_transmit_packet(req,
- p0, port->data[0], port->data[1], b);
- break;
- case STATE_SYSEX_0:
- port->data[0] = b;
- port->state = STATE_SYSEX_1;
- break;
- case STATE_SYSEX_1:
- port->data[1] = b;
- port->state = STATE_SYSEX_2;
- break;
- case STATE_SYSEX_2:
- gmidi_transmit_packet(req,
- p0 | 0x04, port->data[0], port->data[1], b);
- port->state = STATE_SYSEX_0;
- break;
- }
- }
-}
-
-static void gmidi_transmit(struct gmidi_device *dev, struct usb_request *req)
-{
- struct usb_ep *ep = dev->in_ep;
- struct gmidi_in_port *port = &dev->in_port;
-
- if (!ep) {
- return;
- }
- if (!req) {
- req = alloc_ep_req(ep, buflen);
- }
- if (!req) {
- ERROR(dev, "gmidi_transmit: alloc_ep_request failed\n");
- return;
- }
- req->length = 0;
- req->complete = gmidi_complete;
-
- if (port->active) {
- while (req->length + 3 < buflen) {
- uint8_t b;
- if (snd_rawmidi_transmit(dev->in_substream, &b, 1)
- != 1)
- {
- port->active = 0;
- break;
- }
- gmidi_transmit_byte(req, port, b);
- }
- }
- if (req->length > 0) {
- usb_ep_queue(ep, req, GFP_ATOMIC);
- } else {
- free_ep_req(ep, req);
- }
-}
-
-static void gmidi_in_tasklet(unsigned long data)
-{
- struct gmidi_device *dev = (struct gmidi_device *)data;
-
- gmidi_transmit(dev, NULL);
-}
-
-static int gmidi_in_open(struct snd_rawmidi_substream *substream)
-{
- struct gmidi_device *dev = substream->rmidi->private_data;
-
- VDBG(dev, "gmidi_in_open\n");
- dev->in_substream = substream;
- dev->in_port.state = STATE_UNKNOWN;
- return 0;
-}
-
-static int gmidi_in_close(struct snd_rawmidi_substream *substream)
-{
- struct gmidi_device *dev = substream->rmidi->private_data;
-
- VDBG(dev, "gmidi_in_close\n");
- return 0;
-}
-
-static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
-{
- struct gmidi_device *dev = substream->rmidi->private_data;
-
- VDBG(dev, "gmidi_in_trigger %d\n", up);
- dev->in_port.active = up;
- if (up) {
- tasklet_hi_schedule(&dev->tasklet);
- }
-}
-
-static int gmidi_out_open(struct snd_rawmidi_substream *substream)
-{
- struct gmidi_device *dev = substream->rmidi->private_data;
-
- VDBG(dev, "gmidi_out_open\n");
- dev->out_substream = substream;
- return 0;
-}
-
-static int gmidi_out_close(struct snd_rawmidi_substream *substream)
-{
- struct gmidi_device *dev = substream->rmidi->private_data;
-
- VDBG(dev, "gmidi_out_close\n");
- return 0;
-}
-
-static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up)
-{
- struct gmidi_device *dev = substream->rmidi->private_data;
-
- VDBG(dev, "gmidi_out_trigger %d\n", up);
- if (up) {
- set_bit(substream->number, &dev->out_triggered);
- } else {
- clear_bit(substream->number, &dev->out_triggered);
- }
-}
-
-static struct snd_rawmidi_ops gmidi_in_ops = {
- .open = gmidi_in_open,
- .close = gmidi_in_close,
- .trigger = gmidi_in_trigger,
+static struct usb_configuration midi_config = {
+ .label = "MIDI Gadget",
+ .bConfigurationValue = 1,
+ /* .iConfiguration = DYNAMIC */
+ .bmAttributes = USB_CONFIG_ATT_ONE,
+ .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2,
};
-static struct snd_rawmidi_ops gmidi_out_ops = {
- .open = gmidi_out_open,
- .close = gmidi_out_close,
- .trigger = gmidi_out_trigger
-};
-
-/* register as a sound "card" */
-static int gmidi_register_card(struct gmidi_device *dev)
+static int __init midi_bind_config(struct usb_configuration *c)
{
- struct snd_card *card;
- struct snd_rawmidi *rmidi;
- int err;
- int out_ports = 1;
- int in_ports = 1;
- static struct snd_device_ops ops = {
- .dev_free = gmidi_snd_free,
- };
-
- err = snd_card_create(index, id, THIS_MODULE, 0, &card);
- if (err < 0) {
- ERROR(dev, "snd_card_create failed\n");
- goto fail;
- }
- dev->card = card;
-
- err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, dev, &ops);
- if (err < 0) {
- ERROR(dev, "snd_device_new failed: error %d\n", err);
- goto fail;
- }
-
- strcpy(card->driver, longname);
- strcpy(card->longname, longname);
- strcpy(card->shortname, shortname);
-
- /* Set up rawmidi */
- dev->in_port.dev = dev;
- dev->in_port.active = 0;
- snd_component_add(card, "MIDI");
- err = snd_rawmidi_new(card, "USB MIDI Gadget", 0,
- out_ports, in_ports, &rmidi);
- if (err < 0) {
- ERROR(dev, "snd_rawmidi_new failed: error %d\n", err);
- goto fail;
- }
- dev->rmidi = rmidi;
- strcpy(rmidi->name, card->shortname);
- rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
- SNDRV_RAWMIDI_INFO_INPUT |
- SNDRV_RAWMIDI_INFO_DUPLEX;
- rmidi->private_data = dev;
-
- /* Yes, rawmidi OUTPUT = USB IN, and rawmidi INPUT = USB OUT.
- It's an upside-down world being a gadget. */
- snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &gmidi_in_ops);
- snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &gmidi_out_ops);
-
- snd_card_set_dev(card, &dev->gadget->dev);
-
- /* register it - we're ready to go */
- err = snd_card_register(card);
- if (err < 0) {
- ERROR(dev, "snd_card_register failed\n");
- goto fail;
- }
-
- VDBG(dev, "gmidi_register_card finished ok\n");
- return 0;
-
-fail:
- if (dev->card) {
- snd_card_free(dev->card);
- dev->card = NULL;
- }
- return err;
+ return f_midi_bind_config(c, index, id,
+ in_ports, out_ports,
+ buflen, qlen);
}
-/*
- * Creates an output endpoint, and initializes output ports.
- */
-static int __init gmidi_bind(struct usb_gadget *gadget)
+static int __init midi_bind(struct usb_composite_dev *cdev)
{
- struct gmidi_device *dev;
- struct usb_ep *in_ep, *out_ep;
- int gcnum, err = 0;
+ struct usb_gadget *gadget = cdev->gadget;
+ int gcnum, status;
- /* support optional vendor/distro customization */
- if (idVendor) {
- if (!idProduct) {
- pr_err("idVendor needs idProduct!\n");
- return -ENODEV;
- }
- device_desc.idVendor = cpu_to_le16(idVendor);
- device_desc.idProduct = cpu_to_le16(idProduct);
- if (bcdDevice) {
- device_desc.bcdDevice = cpu_to_le16(bcdDevice);
- }
- }
- if (iManufacturer) {
- strlcpy(manufacturer, iManufacturer, sizeof(manufacturer));
- } else {
- snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s",
- init_utsname()->sysname, init_utsname()->release,
- gadget->name);
- }
- if (iProduct) {
- strlcpy(product_desc, iProduct, sizeof(product_desc));
- }
- if (iSerialNumber) {
- device_desc.iSerialNumber = STRING_SERIAL,
- strlcpy(serial_number, iSerialNumber, sizeof(serial_number));
- }
+ status = usb_string_id(cdev);
+ if (status < 0)
+ return status;
+ strings_dev[STRING_MANUFACTURER_IDX].id = status;
+ device_desc.iManufacturer = status;
- /* Bulk-only drivers like this one SHOULD be able to
- * autoconfigure on any sane usb controller driver,
- * but there may also be important quirks to address.
- */
- usb_ep_autoconfig_reset(gadget);
- in_ep = usb_ep_autoconfig(gadget, &bulk_in_desc);
- if (!in_ep) {
-autoconf_fail:
- pr_err("%s: can't autoconfigure on %s\n",
- shortname, gadget->name);
- return -ENODEV;
- }
- EP_IN_NAME = in_ep->name;
- in_ep->driver_data = in_ep; /* claim */
+ status = usb_string_id(cdev);
+ if (status < 0)
+ return status;
+ strings_dev[STRING_PRODUCT_IDX].id = status;
+ device_desc.iProduct = status;
- out_ep = usb_ep_autoconfig(gadget, &bulk_out_desc);
- if (!out_ep) {
- goto autoconf_fail;
- }
- EP_OUT_NAME = out_ep->name;
- out_ep->driver_data = out_ep; /* claim */
+ /* config description */
+ status = usb_string_id(cdev);
+ if (status < 0)
+ return status;
+ strings_dev[STRING_DESCRIPTION_IDX].id = status;
+
+ midi_config.iConfiguration = status;
gcnum = usb_gadget_controller_number(gadget);
- if (gcnum >= 0) {
- device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
- } else {
+ if (gcnum < 0) {
/* gmidi is so simple (no altsettings) that
* it SHOULD NOT have problems with bulk-capable hardware.
* so warn about unrecognized controllers, don't panic.
*/
pr_warning("%s: controller '%s' not recognized\n",
- shortname, gadget->name);
+ __func__, gadget->name);
device_desc.bcdDevice = cpu_to_le16(0x9999);
+ } else {
+ device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
}
+ status = usb_add_config(cdev, &midi_config, midi_bind_config);
+ if (status < 0)
+ return status;
- /* ok, we made sense of the hardware ... */
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev) {
- return -ENOMEM;
- }
- spin_lock_init(&dev->lock);
- dev->gadget = gadget;
- dev->in_ep = in_ep;
- dev->out_ep = out_ep;
- set_gadget_data(gadget, dev);
- tasklet_init(&dev->tasklet, gmidi_in_tasklet, (unsigned long)dev);
-
- /* preallocate control response and buffer */
- dev->req = alloc_ep_req(gadget->ep0, USB_BUFSIZ);
- if (!dev->req) {
- err = -ENOMEM;
- goto fail;
- }
-
- dev->req->complete = gmidi_setup_complete;
-
- gadget->ep0->driver_data = dev;
-
- INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname);
- INFO(dev, "using %s, OUT %s IN %s\n", gadget->name,
- EP_OUT_NAME, EP_IN_NAME);
-
- /* register as an ALSA sound card */
- err = gmidi_register_card(dev);
- if (err < 0) {
- goto fail;
- }
-
- VDBG(dev, "gmidi_bind finished ok\n");
+ pr_info("%s\n", longname);
return 0;
-
-fail:
- gmidi_unbind(gadget);
- return err;
-}
-
-
-static void gmidi_suspend(struct usb_gadget *gadget)
-{
- struct gmidi_device *dev = get_gadget_data(gadget);
-
- if (gadget->speed == USB_SPEED_UNKNOWN) {
- return;
- }
-
- DBG(dev, "suspend\n");
-}
-
-static void gmidi_resume(struct usb_gadget *gadget)
-{
- struct gmidi_device *dev = get_gadget_data(gadget);
-
- DBG(dev, "resume\n");
}
-
-static struct usb_gadget_driver gmidi_driver = {
- .speed = USB_SPEED_FULL,
- .function = (char *)longname,
- .unbind = gmidi_unbind,
-
- .setup = gmidi_setup,
- .disconnect = gmidi_disconnect,
-
- .suspend = gmidi_suspend,
- .resume = gmidi_resume,
-
- .driver = {
- .name = (char *)shortname,
- .owner = THIS_MODULE,
- },
+static struct usb_composite_driver midi_driver = {
+ .name = (char *) longname,
+ .dev = &device_desc,
+ .strings = dev_strings,
+ .max_speed = USB_SPEED_HIGH,
+ .unbind = __exit_p(midi_unbind),
};
-static int __init gmidi_init(void)
+static int __init midi_init(void)
{
- return usb_gadget_probe_driver(&gmidi_driver, gmidi_bind);
+ return usb_composite_probe(&midi_driver, midi_bind);
}
-module_init(gmidi_init);
+module_init(midi_init);
-static void __exit gmidi_cleanup(void)
+static void __exit midi_cleanup(void)
{
- usb_gadget_unregister_driver(&gmidi_driver);
+ usb_composite_unregister(&midi_driver);
}
-module_exit(gmidi_cleanup);
+module_exit(midi_cleanup);
diff --git a/drivers/usb/gadget/hid.c b/drivers/usb/gadget/hid.c
index 9fb575034a0e..f888c3ede860 100644
--- a/drivers/usb/gadget/hid.c
+++ b/drivers/usb/gadget/hid.c
@@ -9,15 +9,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c
index 692fd9b2248b..2d978c0e7ced 100644
--- a/drivers/usb/gadget/imx_udc.c
+++ b/drivers/usb/gadget/imx_udc.c
@@ -689,7 +689,7 @@ static int imx_ep_enable(struct usb_ep *usb_ep,
return -EINVAL;
}
- if (imx_ep->fifosize < le16_to_cpu(desc->wMaxPacketSize)) {
+ if (imx_ep->fifosize < usb_endpoint_maxp(desc)) {
D_ERR(imx_usb->dev,
"<%s> bad %s maxpacket\n", __func__, usb_ep->name);
return -ERANGE;
@@ -1478,7 +1478,7 @@ static int __init imx_udc_probe(struct platform_device *pdev)
for (i = 0; i < IMX_USB_NB_EP + 1; i++) {
ret = request_irq(imx_usb->usbd_int[i], intr_handler(i),
- IRQF_DISABLED, driver_name, imx_usb);
+ 0, driver_name, imx_usb);
if (ret) {
dev_err(&pdev->dev, "can't get irq %i, err %d\n",
imx_usb->usbd_int[i], ret);
diff --git a/drivers/usb/gadget/imx_udc.h b/drivers/usb/gadget/imx_udc.h
index 7136c242b4ec..d118fb777840 100644
--- a/drivers/usb/gadget/imx_udc.h
+++ b/drivers/usb/gadget/imx_udc.h
@@ -8,11 +8,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#ifndef __LINUX_USB_GADGET_IMX_H
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 1b240990448f..a392ec0d2d51 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -8,15 +8,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c
index a06e2c27b435..c9fa3bf5b377 100644
--- a/drivers/usb/gadget/langwell_udc.c
+++ b/drivers/usb/gadget/langwell_udc.c
@@ -5,16 +5,6 @@
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
*/
@@ -60,9 +50,6 @@ static const char driver_name[] = "langwell_udc";
static const char driver_desc[] = DRIVER_DESC;
-/* controller device global variable */
-static struct langwell_udc *the_controller;
-
/* for endpoint 0 operations */
static const struct usb_endpoint_descriptor
langwell_ep0_desc = {
@@ -283,7 +270,7 @@ static int langwell_ep_enable(struct usb_ep *_ep,
if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
return -ESHUTDOWN;
- max = le16_to_cpu(desc->wMaxPacketSize);
+ max = usb_endpoint_maxp(desc);
/*
* disable HW zero length termination select
@@ -1321,9 +1308,12 @@ static int langwell_pullup(struct usb_gadget *_gadget, int is_on)
return 0;
}
-static int langwell_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *));
-static int langwell_stop(struct usb_gadget_driver *driver);
+static int langwell_start(struct usb_gadget *g,
+ struct usb_gadget_driver *driver);
+
+static int langwell_stop(struct usb_gadget *g,
+ struct usb_gadget_driver *driver);
+
/* device controller usb_gadget_ops structure */
static const struct usb_gadget_ops langwell_ops = {
@@ -1345,8 +1335,8 @@ static const struct usb_gadget_ops langwell_ops = {
/* D+ pullup, software-controlled connect/disconnect to USB host */
.pullup = langwell_pullup,
- .start = langwell_start,
- .stop = langwell_stop,
+ .udc_start = langwell_start,
+ .udc_stop = langwell_stop,
};
@@ -1561,7 +1551,7 @@ static void stop_activity(struct langwell_udc *dev,
static ssize_t show_function(struct device *_dev,
struct device_attribute *attr, char *buf)
{
- struct langwell_udc *dev = the_controller;
+ struct langwell_udc *dev = dev_get_drvdata(_dev);
if (!dev->driver || !dev->driver->function
|| strlen(dev->driver->function) > PAGE_SIZE)
@@ -1572,11 +1562,25 @@ static ssize_t show_function(struct device *_dev,
static DEVICE_ATTR(function, S_IRUGO, show_function, NULL);
+static inline enum usb_device_speed lpm_device_speed(u32 reg)
+{
+ switch (LPM_PSPD(reg)) {
+ case LPM_SPEED_HIGH:
+ return USB_SPEED_HIGH;
+ case LPM_SPEED_FULL:
+ return USB_SPEED_FULL;
+ case LPM_SPEED_LOW:
+ return USB_SPEED_LOW;
+ default:
+ return USB_SPEED_UNKNOWN;
+ }
+}
+
/* device "langwell_udc" sysfs attribute file */
static ssize_t show_langwell_udc(struct device *_dev,
struct device_attribute *attr, char *buf)
{
- struct langwell_udc *dev = the_controller;
+ struct langwell_udc *dev = dev_get_drvdata(_dev);
struct langwell_request *req;
struct langwell_ep *ep = NULL;
char *next;
@@ -1700,20 +1704,7 @@ static ssize_t show_langwell_udc(struct device *_dev,
"BmAttributes: %d\n\n",
LPM_PTS(tmp_reg),
(tmp_reg & LPM_STS) ? 1 : 0,
- ({
- char *s;
- switch (LPM_PSPD(tmp_reg)) {
- case LPM_SPEED_FULL:
- s = "Full Speed"; break;
- case LPM_SPEED_LOW:
- s = "Low Speed"; break;
- case LPM_SPEED_HIGH:
- s = "High Speed"; break;
- default:
- s = "Unknown Speed"; break;
- }
- s;
- }),
+ usb_speed_string(lpm_device_speed(tmp_reg)),
(tmp_reg & LPM_PFSC) ? "Force Full Speed" : "Not Force",
(tmp_reg & LPM_PHCD) ? "Disabled" : "Enabled",
LPM_BA(tmp_reg));
@@ -1821,7 +1812,7 @@ static DEVICE_ATTR(langwell_udc, S_IRUGO, show_langwell_udc, NULL);
static ssize_t store_remote_wakeup(struct device *_dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct langwell_udc *dev = the_controller;
+ struct langwell_udc *dev = dev_get_drvdata(_dev);
unsigned long flags;
ssize_t rc = count;
@@ -1857,21 +1848,15 @@ static DEVICE_ATTR(remote_wakeup, S_IWUSR, NULL, store_remote_wakeup);
* the driver might get unbound.
*/
-static int langwell_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *))
+static int langwell_start(struct usb_gadget *g,
+ struct usb_gadget_driver *driver)
{
- struct langwell_udc *dev = the_controller;
+ struct langwell_udc *dev = gadget_to_langwell(g);
unsigned long flags;
int retval;
- if (!dev)
- return -ENODEV;
-
dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
- if (dev->driver)
- return -EBUSY;
-
spin_lock_irqsave(&dev->lock, flags);
/* hook up the driver ... */
@@ -1881,18 +1866,9 @@ static int langwell_start(struct usb_gadget_driver *driver,
spin_unlock_irqrestore(&dev->lock, flags);
- retval = bind(&dev->gadget);
- if (retval) {
- dev_dbg(&dev->pdev->dev, "bind to driver %s --> %d\n",
- driver->driver.name, retval);
- dev->driver = NULL;
- dev->gadget.dev.driver = NULL;
- return retval;
- }
-
retval = device_create_file(&dev->pdev->dev, &dev_attr_function);
if (retval)
- goto err_unbind;
+ goto err;
dev->usb_state = USB_STATE_ATTACHED;
dev->ep0_state = WAIT_FOR_SETUP;
@@ -1909,31 +1885,27 @@ static int langwell_start(struct usb_gadget_driver *driver,
dev_info(&dev->pdev->dev, "register driver: %s\n",
driver->driver.name);
dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
+
return 0;
-err_unbind:
- driver->unbind(&dev->gadget);
+err:
dev->gadget.dev.driver = NULL;
dev->driver = NULL;
dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
+
return retval;
}
/* unregister gadget driver */
-static int langwell_stop(struct usb_gadget_driver *driver)
+static int langwell_stop(struct usb_gadget *g,
+ struct usb_gadget_driver *driver)
{
- struct langwell_udc *dev = the_controller;
+ struct langwell_udc *dev = gadget_to_langwell(g);
unsigned long flags;
- if (!dev)
- return -ENODEV;
-
dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
- if (unlikely(!driver || !driver->unbind))
- return -EINVAL;
-
/* exit PHY low power suspend */
if (dev->pdev->device != 0x0829)
langwell_phy_low_power(dev, 0);
@@ -1956,8 +1928,6 @@ static int langwell_stop(struct usb_gadget_driver *driver)
stop_activity(dev, driver);
spin_unlock_irqrestore(&dev->lock, flags);
- /* unbind gadget driver */
- driver->unbind(&dev->gadget);
dev->gadget.dev.driver = NULL;
dev->driver = NULL;
@@ -1966,6 +1936,7 @@ static int langwell_stop(struct usb_gadget_driver *driver)
dev_info(&dev->pdev->dev, "unregistered driver '%s'\n",
driver->driver.name);
dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
+
return 0;
}
@@ -2657,12 +2628,10 @@ done:
dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
}
-
/* port change detect interrupt handler */
static void handle_port_change(struct langwell_udc *dev)
{
u32 portsc1, devlc;
- u32 speed;
dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
@@ -2677,24 +2646,9 @@ static void handle_port_change(struct langwell_udc *dev)
/* bus reset is finished */
if (!(portsc1 & PORTS_PR)) {
/* get the speed */
- speed = LPM_PSPD(devlc);
- switch (speed) {
- case LPM_SPEED_HIGH:
- dev->gadget.speed = USB_SPEED_HIGH;
- break;
- case LPM_SPEED_FULL:
- dev->gadget.speed = USB_SPEED_FULL;
- break;
- case LPM_SPEED_LOW:
- dev->gadget.speed = USB_SPEED_LOW;
- break;
- default:
- dev->gadget.speed = USB_SPEED_UNKNOWN;
- break;
- }
- dev_vdbg(&dev->pdev->dev,
- "speed = %d, dev->gadget.speed = %d\n",
- speed, dev->gadget.speed);
+ dev->gadget.speed = lpm_device_speed(devlc);
+ dev_vdbg(&dev->pdev->dev, "dev->gadget.speed = %d\n",
+ dev->gadget.speed);
}
/* LPM L0 to L1 */
@@ -2969,7 +2923,7 @@ static irqreturn_t langwell_irq(int irq, void *_dev)
handle_port_change(dev);
}
- /* suspend interrrupt */
+ /* suspend interrupt */
if (irq_sts & STS_SLI) {
dev_vdbg(&dev->pdev->dev, "suspend interrupt\n");
handle_bus_suspend(dev);
@@ -2999,7 +2953,7 @@ static irqreturn_t langwell_irq(int irq, void *_dev)
/* release device structure */
static void gadget_release(struct device *_dev)
{
- struct langwell_udc *dev = the_controller;
+ struct langwell_udc *dev = dev_get_drvdata(_dev);
dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
@@ -3057,7 +3011,7 @@ static void sram_deinit(struct langwell_udc *dev)
/* tear down the binding between this driver and the pci device */
static void langwell_udc_remove(struct pci_dev *pdev)
{
- struct langwell_udc *dev = the_controller;
+ struct langwell_udc *dev = pci_get_drvdata(pdev);
DECLARE_COMPLETION(done);
@@ -3124,8 +3078,6 @@ static void langwell_udc_remove(struct pci_dev *pdev)
/* free dev, wait for the release() finished */
wait_for_completion(&done);
-
- the_controller = NULL;
}
@@ -3144,11 +3096,6 @@ static int langwell_udc_probe(struct pci_dev *pdev,
size_t size;
int retval;
- if (the_controller) {
- dev_warn(&pdev->dev, "ignoring\n");
- return -EBUSY;
- }
-
/* alloc, and start init */
dev = kzalloc(sizeof *dev, GFP_KERNEL);
if (dev == NULL) {
@@ -3368,8 +3315,6 @@ static int langwell_udc_probe(struct pci_dev *pdev,
"After langwell_udc_probe(), print all registers:\n");
print_all_registers(dev);
- the_controller = dev;
-
retval = device_register(&dev->gadget.dev);
if (retval)
goto error;
@@ -3404,7 +3349,7 @@ error:
/* device controller suspend */
static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state)
{
- struct langwell_udc *dev = the_controller;
+ struct langwell_udc *dev = pci_get_drvdata(pdev);
dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
@@ -3452,7 +3397,7 @@ static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state)
/* device controller resume */
static int langwell_udc_resume(struct pci_dev *pdev)
{
- struct langwell_udc *dev = the_controller;
+ struct langwell_udc *dev = pci_get_drvdata(pdev);
size_t size;
dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
@@ -3534,7 +3479,7 @@ static int langwell_udc_resume(struct pci_dev *pdev)
/* pci driver shutdown */
static void langwell_udc_shutdown(struct pci_dev *pdev)
{
- struct langwell_udc *dev = the_controller;
+ struct langwell_udc *dev = pci_get_drvdata(pdev);
u32 usbmode;
dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
diff --git a/drivers/usb/gadget/langwell_udc.h b/drivers/usb/gadget/langwell_udc.h
index f1d9c1bb04f3..ef79e242b7b0 100644
--- a/drivers/usb/gadget/langwell_udc.h
+++ b/drivers/usb/gadget/langwell_udc.h
@@ -5,16 +5,6 @@
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
*/
#include <linux/usb/langwell_udc.h>
@@ -231,3 +221,5 @@ struct langwell_udc {
u16 dev_status;
};
+#define gadget_to_langwell(g) container_of((g), struct langwell_udc, gadget)
+
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index 491f825ed5c9..91d0af2a24a8 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -8,16 +8,6 @@
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include <linux/module.h>
@@ -370,7 +360,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
ep->pipectr = get_pipectr_addr(pipenum);
ep->pipenum = pipenum;
- ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+ ep->ep.maxpacket = usb_endpoint_maxp(desc);
m66592->pipenum2ep[pipenum] = ep;
m66592->epaddr2ep[desc->bEndpointAddress&USB_ENDPOINT_NUMBER_MASK] = ep;
INIT_LIST_HEAD(&ep->queue);
@@ -447,7 +437,7 @@ static int alloc_pipe_config(struct m66592_ep *ep,
ep->type = info.type;
info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
- info.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+ info.maxpacket = usb_endpoint_maxp(desc);
info.interval = desc->bInterval;
if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
info.dir_in = 1;
@@ -1674,7 +1664,7 @@ static int __init m66592_probe(struct platform_device *pdev)
m66592->timer.data = (unsigned long)m66592;
m66592->reg = reg;
- ret = request_irq(ires->start, m66592_irq, IRQF_DISABLED | IRQF_SHARED,
+ ret = request_irq(ires->start, m66592_irq, IRQF_SHARED,
udc_name, m66592);
if (ret < 0) {
pr_err("request_irq error (%d)\n", ret);
diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h
index 7b93d579af37..9d9f7e39f037 100644
--- a/drivers/usb/gadget/m66592-udc.h
+++ b/drivers/usb/gadget/m66592-udc.h
@@ -8,16 +8,6 @@
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#ifndef __M66592_UDC_H__
diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c
index d3eb27427c58..e24f72f82a47 100644
--- a/drivers/usb/gadget/mass_storage.c
+++ b/drivers/usb/gadget/mass_storage.c
@@ -10,15 +10,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -169,7 +160,7 @@ static struct usb_composite_driver msg_driver = {
.name = "g_mass_storage",
.dev = &msg_device_desc,
.iProduct = DRIVER_DESC,
- .max_speed = USB_SPEED_HIGH,
+ .max_speed = USB_SPEED_SUPER,
.needs_serial = 1,
};
diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
index 8c7b74717d85..7e7f515b8b19 100644
--- a/drivers/usb/gadget/multi.c
+++ b/drivers/usb/gadget/multi.c
@@ -10,15 +10,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/mv_udc.h
index 65f1f7c3bd4e..daa75c12f336 100644
--- a/drivers/usb/gadget/mv_udc.h
+++ b/drivers/usb/gadget/mv_udc.h
@@ -1,3 +1,11 @@
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
#ifndef __MV_UDC_H
#define __MV_UDC_H
@@ -194,14 +202,25 @@ struct mv_udc {
unsigned int ep0_dir;
unsigned int dev_addr;
+ unsigned int test_mode;
int errors;
unsigned softconnect:1,
vbus_active:1,
remote_wakeup:1,
softconnected:1,
- force_fs:1;
- struct clk *clk;
+ force_fs:1,
+ clock_gating:1,
+ active:1;
+
+ struct work_struct vbus_work;
+ struct workqueue_struct *qwork;
+
+ struct mv_usb_platform_data *pdata;
+
+ /* some SOC has mutiple clock sources for USB*/
+ unsigned int clknum;
+ struct clk *clk[0];
};
/* endpoint data structure */
@@ -225,6 +244,7 @@ struct mv_req {
struct mv_dtd *dtd, *head, *tail;
struct mv_ep *ep;
struct list_head queue;
+ unsigned int test_mode;
unsigned dtd_count;
unsigned mapped:1;
};
@@ -289,6 +309,4 @@ struct mv_dtd {
struct mv_dtd *next_dtd_virt;
};
-extern int mv_udc_phy_init(unsigned int base);
-
#endif
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index ce1ac2bcb314..892412103dd8 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -1,3 +1,14 @@
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ * Author: Chao Xie <chao.xie@marvell.com>
+ * Neil Zhang <zhangwm@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
@@ -22,6 +33,7 @@
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/platform_data/mv_usb.h>
#include <asm/system.h>
#include <asm/unaligned.h>
@@ -45,6 +57,8 @@
#define LOOPS_USEC (1 << LOOPS_USEC_SHIFT)
#define LOOPS(timeout) ((timeout) >> LOOPS_USEC_SHIFT)
+static DECLARE_COMPLETION(release_done);
+
static const char driver_name[] = "mv_udc";
static const char driver_desc[] = DRIVER_DESC;
@@ -53,6 +67,7 @@ static struct mv_udc *the_controller;
int mv_usb_otgsc;
static void nuke(struct mv_ep *ep, int status);
+static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver);
/* for endpoint 0 operations */
static const struct usb_endpoint_descriptor mv_ep0_desc = {
@@ -82,14 +97,16 @@ static void ep0_reset(struct mv_udc *udc)
(EP0_MAX_PKT_SIZE << EP_QUEUE_HEAD_MAX_PKT_LEN_POS)
| EP_QUEUE_HEAD_IOS;
+ ep->dqh->next_dtd_ptr = EP_QUEUE_HEAD_NEXT_TERMINATE;
+
epctrlx = readl(&udc->op_regs->epctrlx[0]);
if (i) { /* TX */
- epctrlx |= EPCTRL_TX_ENABLE | EPCTRL_TX_DATA_TOGGLE_RST
+ epctrlx |= EPCTRL_TX_ENABLE
| (USB_ENDPOINT_XFER_CONTROL
<< EPCTRL_TX_EP_TYPE_SHIFT);
} else { /* RX */
- epctrlx |= EPCTRL_RX_ENABLE | EPCTRL_RX_DATA_TOGGLE_RST
+ epctrlx |= EPCTRL_RX_ENABLE
| (USB_ENDPOINT_XFER_CONTROL
<< EPCTRL_RX_EP_TYPE_SHIFT);
}
@@ -122,6 +139,7 @@ static int process_ep_req(struct mv_udc *udc, int index,
int i, direction;
int retval = 0;
u32 errors;
+ u32 bit_pos;
curr_dqh = &udc->ep_dqh[index];
direction = index % 2;
@@ -139,10 +157,20 @@ static int process_ep_req(struct mv_udc *udc, int index,
errors = curr_dtd->size_ioc_sts & DTD_ERROR_MASK;
if (!errors) {
- remaining_length +=
+ remaining_length =
(curr_dtd->size_ioc_sts & DTD_PACKET_SIZE)
>> DTD_LENGTH_BIT_POS;
actual -= remaining_length;
+
+ if (remaining_length) {
+ if (direction) {
+ dev_dbg(&udc->dev->dev,
+ "TX dTD remains data\n");
+ retval = -EPROTO;
+ break;
+ } else
+ break;
+ }
} else {
dev_info(&udc->dev->dev,
"complete_tr error: ep=%d %s: error = 0x%x\n",
@@ -164,6 +192,20 @@ static int process_ep_req(struct mv_udc *udc, int index,
if (retval)
return retval;
+ if (direction == EP_DIR_OUT)
+ bit_pos = 1 << curr_req->ep->ep_num;
+ else
+ bit_pos = 1 << (16 + curr_req->ep->ep_num);
+
+ while ((curr_dqh->curr_dtd_ptr == curr_dtd->td_dma)) {
+ if (curr_dtd->dtd_next == EP_QUEUE_HEAD_NEXT_TERMINATE) {
+ while (readl(&udc->op_regs->epstatus) & bit_pos)
+ udelay(1);
+ break;
+ }
+ udelay(1);
+ }
+
curr_req->req.actual = actual;
return 0;
@@ -335,7 +377,7 @@ static int queue_dtd(struct mv_ep *ep, struct mv_req *req)
} else {
/* Write dQH next pointer and terminate bit to 0 */
dqh->next_dtd_ptr = req->head->td_dma
- & EP_QUEUE_HEAD_NEXT_POINTER_MASK;;
+ & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
dqh->size_ioc_int_sts = 0;
/* Ensure that updates to the QH will occur before priming. */
@@ -376,7 +418,7 @@ static int queue_dtd(struct mv_ep *ep, struct mv_req *req)
}
}
done:
- return retval;;
+ return retval;
}
static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length,
@@ -481,6 +523,7 @@ static int mv_ep_enable(struct usb_ep *_ep,
u16 max = 0;
u32 bit_pos, epctrlx, direction;
unsigned char zlt = 0, ios = 0, mult = 0;
+ unsigned long flags;
ep = container_of(_ep, struct mv_ep, ep);
udc = ep->udc;
@@ -493,7 +536,7 @@ static int mv_ep_enable(struct usb_ep *_ep,
return -ESHUTDOWN;
direction = ep_dir(ep);
- max = le16_to_cpu(desc->wMaxPacketSize);
+ max = usb_endpoint_maxp(desc);
/*
* disable HW zero length termination select
@@ -501,9 +544,6 @@ static int mv_ep_enable(struct usb_ep *_ep,
*/
zlt = 1;
- /* Get the endpoint queue head address */
- dqh = (struct mv_dqh *)ep->dqh;
-
bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num);
/* Check if the Endpoint is Primed */
@@ -532,7 +572,7 @@ static int mv_ep_enable(struct usb_ep *_ep,
case USB_ENDPOINT_XFER_ISOC:
/* Calculate transactions needed for high bandwidth iso */
mult = (unsigned char)(1 + ((max >> 11) & 0x03));
- max = max & 0x8ff; /* bit 0~10 */
+ max = max & 0x7ff; /* bit 0~10 */
/* 3 transactions at most */
if (mult > 3)
goto en_done;
@@ -540,6 +580,10 @@ static int mv_ep_enable(struct usb_ep *_ep,
default:
goto en_done;
}
+
+ spin_lock_irqsave(&udc->lock, flags);
+ /* Get the endpoint queue head address */
+ dqh = ep->dqh;
dqh->max_packet_length = (max << EP_QUEUE_HEAD_MAX_PKT_LEN_POS)
| (mult << EP_QUEUE_HEAD_MULT_POS)
| (zlt ? EP_QUEUE_HEAD_ZLT_SEL : 0)
@@ -572,18 +616,20 @@ static int mv_ep_enable(struct usb_ep *_ep,
*/
epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]);
if ((epctrlx & EPCTRL_RX_ENABLE) == 0) {
- epctrlx |= ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ epctrlx |= (USB_ENDPOINT_XFER_BULK
<< EPCTRL_RX_EP_TYPE_SHIFT);
writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
}
epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]);
if ((epctrlx & EPCTRL_TX_ENABLE) == 0) {
- epctrlx |= ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ epctrlx |= (USB_ENDPOINT_XFER_BULK
<< EPCTRL_TX_EP_TYPE_SHIFT);
writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
}
+ spin_unlock_irqrestore(&udc->lock, flags);
+
return 0;
en_done:
return -EINVAL;
@@ -595,6 +641,7 @@ static int mv_ep_disable(struct usb_ep *_ep)
struct mv_ep *ep;
struct mv_dqh *dqh;
u32 bit_pos, epctrlx, direction;
+ unsigned long flags;
ep = container_of(_ep, struct mv_ep, ep);
if ((_ep == NULL) || !ep->desc)
@@ -605,6 +652,8 @@ static int mv_ep_disable(struct usb_ep *_ep)
/* Get the endpoint queue head address */
dqh = ep->dqh;
+ spin_lock_irqsave(&udc->lock, flags);
+
direction = ep_dir(ep);
bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num);
@@ -623,6 +672,9 @@ static int mv_ep_disable(struct usb_ep *_ep)
ep->desc = NULL;
ep->stopped = 1;
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
return 0;
}
@@ -655,37 +707,28 @@ static void mv_ep_fifo_flush(struct usb_ep *_ep)
{
struct mv_udc *udc;
u32 bit_pos, direction;
- struct mv_ep *ep = container_of(_ep, struct mv_ep, ep);
+ struct mv_ep *ep;
unsigned int loops;
+ if (!_ep)
+ return;
+
+ ep = container_of(_ep, struct mv_ep, ep);
+ if (!ep->desc)
+ return;
+
udc = ep->udc;
direction = ep_dir(ep);
- bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num);
- /*
- * Flushing will halt the pipe
- * Write 1 to the Flush register
- */
- writel(bit_pos, &udc->op_regs->epflush);
- /* Wait until flushing completed */
- loops = LOOPS(FLUSH_TIMEOUT);
- while (readl(&udc->op_regs->epflush) & bit_pos) {
- /*
- * ENDPTFLUSH bit should be cleared to indicate this
- * operation is complete
- */
- if (loops == 0) {
- dev_err(&udc->dev->dev,
- "TIMEOUT for ENDPTFLUSH=0x%x, bit_pos=0x%x\n",
- (unsigned)readl(&udc->op_regs->epflush),
- (unsigned)bit_pos);
- return;
- }
- loops--;
- udelay(LOOPS_USEC);
- }
+ if (ep->ep_num == 0)
+ bit_pos = (1 << 16) | 1;
+ else if (direction == EP_DIR_OUT)
+ bit_pos = 1 << ep->ep_num;
+ else
+ bit_pos = 1 << (16 + ep->ep_num);
+
loops = LOOPS(EPSTATUS_TIMEOUT);
- while (readl(&udc->op_regs->epstatus) & bit_pos) {
+ do {
unsigned int inter_loops;
if (loops == 0) {
@@ -700,7 +743,7 @@ static void mv_ep_fifo_flush(struct usb_ep *_ep)
/* Wait until flushing completed */
inter_loops = LOOPS(FLUSH_TIMEOUT);
- while (readl(&udc->op_regs->epflush) & bit_pos) {
+ while (readl(&udc->op_regs->epflush)) {
/*
* ENDPTFLUSH bit should be cleared to indicate this
* operation is complete
@@ -717,7 +760,7 @@ static void mv_ep_fifo_flush(struct usb_ep *_ep)
udelay(LOOPS_USEC);
}
loops--;
- }
+ } while (readl(&udc->op_regs->epstatus) & bit_pos);
}
/* queues (submits) an I/O request to an endpoint */
@@ -987,6 +1030,22 @@ static struct usb_ep_ops mv_ep_ops = {
.fifo_flush = mv_ep_fifo_flush, /* flush fifo */
};
+static void udc_clock_enable(struct mv_udc *udc)
+{
+ unsigned int i;
+
+ for (i = 0; i < udc->clknum; i++)
+ clk_enable(udc->clk[i]);
+}
+
+static void udc_clock_disable(struct mv_udc *udc)
+{
+ unsigned int i;
+
+ for (i = 0; i < udc->clknum; i++)
+ clk_disable(udc->clk[i]);
+}
+
static void udc_stop(struct mv_udc *udc)
{
u32 tmp;
@@ -1075,6 +1134,40 @@ static int udc_reset(struct mv_udc *udc)
return 0;
}
+static int mv_udc_enable(struct mv_udc *udc)
+{
+ int retval;
+
+ if (udc->clock_gating == 0 || udc->active)
+ return 0;
+
+ dev_dbg(&udc->dev->dev, "enable udc\n");
+ udc_clock_enable(udc);
+ if (udc->pdata->phy_init) {
+ retval = udc->pdata->phy_init(udc->phy_regs);
+ if (retval) {
+ dev_err(&udc->dev->dev,
+ "init phy error %d\n", retval);
+ udc_clock_disable(udc);
+ return retval;
+ }
+ }
+ udc->active = 1;
+
+ return 0;
+}
+
+static void mv_udc_disable(struct mv_udc *udc)
+{
+ if (udc->clock_gating && udc->active) {
+ dev_dbg(&udc->dev->dev, "disable udc\n");
+ if (udc->pdata->phy_deinit)
+ udc->pdata->phy_deinit(udc->phy_regs);
+ udc_clock_disable(udc);
+ udc->active = 0;
+ }
+}
+
static int mv_udc_get_frame(struct usb_gadget *gadget)
{
struct mv_udc *udc;
@@ -1110,22 +1203,68 @@ static int mv_udc_wakeup(struct usb_gadget *gadget)
return 0;
}
+static int mv_udc_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+ struct mv_udc *udc;
+ unsigned long flags;
+ int retval = 0;
+
+ udc = container_of(gadget, struct mv_udc, gadget);
+ spin_lock_irqsave(&udc->lock, flags);
+
+ dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n",
+ __func__, udc->softconnect, udc->vbus_active);
+
+ udc->vbus_active = (is_active != 0);
+ if (udc->driver && udc->softconnect && udc->vbus_active) {
+ retval = mv_udc_enable(udc);
+ if (retval == 0) {
+ /* Clock is disabled, need re-init registers */
+ udc_reset(udc);
+ ep0_reset(udc);
+ udc_start(udc);
+ }
+ } else if (udc->driver && udc->softconnect) {
+ /* stop all the transfer in queue*/
+ stop_activity(udc, udc->driver);
+ udc_stop(udc);
+ mv_udc_disable(udc);
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return retval;
+}
+
static int mv_udc_pullup(struct usb_gadget *gadget, int is_on)
{
struct mv_udc *udc;
unsigned long flags;
+ int retval = 0;
udc = container_of(gadget, struct mv_udc, gadget);
spin_lock_irqsave(&udc->lock, flags);
+ dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n",
+ __func__, udc->softconnect, udc->vbus_active);
+
udc->softconnect = (is_on != 0);
- if (udc->driver && udc->softconnect)
- udc_start(udc);
- else
+ if (udc->driver && udc->softconnect && udc->vbus_active) {
+ retval = mv_udc_enable(udc);
+ if (retval == 0) {
+ /* Clock is disabled, need re-init registers */
+ udc_reset(udc);
+ ep0_reset(udc);
+ udc_start(udc);
+ }
+ } else if (udc->driver && udc->vbus_active) {
+ /* stop all the transfer in queue*/
+ stop_activity(udc, udc->driver);
udc_stop(udc);
+ mv_udc_disable(udc);
+ }
spin_unlock_irqrestore(&udc->lock, flags);
- return 0;
+ return retval;
}
static int mv_udc_start(struct usb_gadget_driver *driver,
@@ -1140,17 +1279,15 @@ static const struct usb_gadget_ops mv_ops = {
/* tries to wake up the host connected to this gadget */
.wakeup = mv_udc_wakeup,
+ /* notify controller that VBUS is powered or not */
+ .vbus_session = mv_udc_vbus_session,
+
/* D+ pullup, software-controlled connect/disconnect to USB host */
.pullup = mv_udc_pullup,
.start = mv_udc_start,
.stop = mv_udc_stop,
};
-static void mv_udc_testmode(struct mv_udc *udc, u16 index, bool enter)
-{
- dev_info(&udc->dev->dev, "Test Mode is not support yet\n");
-}
-
static int eps_init(struct mv_udc *udc)
{
struct mv_ep *ep;
@@ -1257,7 +1394,7 @@ static int mv_udc_start(struct usb_gadget_driver *driver,
udc->usb_state = USB_STATE_ATTACHED;
udc->ep0_state = WAIT_FOR_SETUP;
- udc->ep0_dir = USB_DIR_OUT;
+ udc->ep0_dir = EP_DIR_OUT;
spin_unlock_irqrestore(&udc->lock, flags);
@@ -1269,9 +1406,13 @@ static int mv_udc_start(struct usb_gadget_driver *driver,
udc->gadget.dev.driver = NULL;
return retval;
}
- udc_reset(udc);
- ep0_reset(udc);
- udc_start(udc);
+
+ /* pullup is always on */
+ mv_udc_pullup(&udc->gadget, 1);
+
+ /* When boot with cable attached, there will be no vbus irq occurred */
+ if (udc->qwork)
+ queue_work(udc->qwork, &udc->vbus_work);
return 0;
}
@@ -1284,13 +1425,16 @@ static int mv_udc_stop(struct usb_gadget_driver *driver)
if (!udc)
return -ENODEV;
- udc_stop(udc);
-
spin_lock_irqsave(&udc->lock, flags);
+ mv_udc_enable(udc);
+ udc_stop(udc);
+
/* stop all usb activities */
udc->gadget.speed = USB_SPEED_UNKNOWN;
stop_activity(udc, driver);
+ mv_udc_disable(udc);
+
spin_unlock_irqrestore(&udc->lock, flags);
/* unbind gadget driver */
@@ -1301,6 +1445,31 @@ static int mv_udc_stop(struct usb_gadget_driver *driver)
return 0;
}
+static void mv_set_ptc(struct mv_udc *udc, u32 mode)
+{
+ u32 portsc;
+
+ portsc = readl(&udc->op_regs->portsc[0]);
+ portsc |= mode << 16;
+ writel(portsc, &udc->op_regs->portsc[0]);
+}
+
+static void prime_status_complete(struct usb_ep *ep, struct usb_request *_req)
+{
+ struct mv_udc *udc = the_controller;
+ struct mv_req *req = container_of(_req, struct mv_req, req);
+ unsigned long flags;
+
+ dev_info(&udc->dev->dev, "switch to test mode %d\n", req->test_mode);
+
+ spin_lock_irqsave(&udc->lock, flags);
+ if (req->test_mode) {
+ mv_set_ptc(udc, req->test_mode);
+ req->test_mode = 0;
+ }
+ spin_unlock_irqrestore(&udc->lock, flags);
+}
+
static int
udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty)
{
@@ -1310,6 +1479,7 @@ udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty)
ep = &udc->eps[0];
udc->ep0_dir = direction;
+ udc->ep0_state = WAIT_FOR_OUT_STATUS;
req = udc->status_req;
@@ -1323,9 +1493,21 @@ udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty)
req->ep = ep;
req->req.status = -EINPROGRESS;
req->req.actual = 0;
- req->req.complete = NULL;
+ if (udc->test_mode) {
+ req->req.complete = prime_status_complete;
+ req->test_mode = udc->test_mode;
+ udc->test_mode = 0;
+ } else
+ req->req.complete = NULL;
req->dtd_count = 0;
+ if (req->req.dma == DMA_ADDR_INVALID) {
+ req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
+ req->req.buf, req->req.length,
+ ep_dir(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ req->mapped = 1;
+ }
+
/* prime the data phase */
if (!req_to_dtd(req))
retval = queue_dtd(ep, req);
@@ -1346,6 +1528,17 @@ out:
return retval;
}
+static void mv_udc_testmode(struct mv_udc *udc, u16 index)
+{
+ if (index <= TEST_FORCE_EN) {
+ udc->test_mode = index;
+ if (udc_prime_status(udc, EP_DIR_IN, 0, true))
+ ep0_stall(udc);
+ } else
+ dev_err(&udc->dev->dev,
+ "This test mode(%d) is not supported\n", index);
+}
+
static void ch9setaddress(struct mv_udc *udc, struct usb_ctrlrequest *setup)
{
udc->dev_addr = (u8)setup->wValue;
@@ -1360,7 +1553,7 @@ static void ch9setaddress(struct mv_udc *udc, struct usb_ctrlrequest *setup)
static void ch9getstatus(struct mv_udc *udc, u8 ep_num,
struct usb_ctrlrequest *setup)
{
- u16 status;
+ u16 status = 0;
int retval;
if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK))
@@ -1388,6 +1581,8 @@ static void ch9getstatus(struct mv_udc *udc, u8 ep_num,
retval = udc_prime_status(udc, EP_DIR_IN, status, false);
if (retval)
ep0_stall(udc);
+ else
+ udc->ep0_state = DATA_STATE_XMIT;
}
static void ch9clearfeature(struct mv_udc *udc, struct usb_ctrlrequest *setup)
@@ -1402,9 +1597,6 @@ static void ch9clearfeature(struct mv_udc *udc, struct usb_ctrlrequest *setup)
case USB_DEVICE_REMOTE_WAKEUP:
udc->remote_wakeup = 0;
break;
- case USB_DEVICE_TEST_MODE:
- mv_udc_testmode(udc, 0, false);
- break;
default:
goto out;
}
@@ -1433,8 +1625,6 @@ static void ch9clearfeature(struct mv_udc *udc, struct usb_ctrlrequest *setup)
if (udc_prime_status(udc, EP_DIR_IN, 0, true))
ep0_stall(udc);
- else
- udc->ep0_state = DATA_STATE_XMIT;
out:
return;
}
@@ -1452,16 +1642,16 @@ static void ch9setfeature(struct mv_udc *udc, struct usb_ctrlrequest *setup)
break;
case USB_DEVICE_TEST_MODE:
if (setup->wIndex & 0xFF
- && udc->gadget.speed != USB_SPEED_HIGH)
- goto out;
- if (udc->usb_state == USB_STATE_CONFIGURED
- || udc->usb_state == USB_STATE_ADDRESS
- || udc->usb_state == USB_STATE_DEFAULT)
- mv_udc_testmode(udc,
- setup->wIndex & 0xFF00, true);
- else
- goto out;
- break;
+ || udc->gadget.speed != USB_SPEED_HIGH)
+ ep0_stall(udc);
+
+ if (udc->usb_state != USB_STATE_CONFIGURED
+ && udc->usb_state != USB_STATE_ADDRESS
+ && udc->usb_state != USB_STATE_DEFAULT)
+ ep0_stall(udc);
+
+ mv_udc_testmode(udc, (setup->wIndex >> 8));
+ goto out;
default:
goto out;
}
@@ -1599,8 +1789,7 @@ static void get_setup_data(struct mv_udc *udc, u8 ep_num, u8 *buffer_ptr)
dqh = &udc->ep_dqh[ep_num * 2 + EP_DIR_OUT];
/* Clear bit in ENDPTSETUPSTAT */
- temp = readl(&udc->op_regs->epsetupstat);
- writel(temp | (1 << ep_num), &udc->op_regs->epsetupstat);
+ writel((1 << ep_num), &udc->op_regs->epsetupstat);
/* while a hazard exists when setup package arrives */
do {
@@ -1871,23 +2060,57 @@ static irqreturn_t mv_udc_irq(int irq, void *dev)
return IRQ_HANDLED;
}
+static irqreturn_t mv_udc_vbus_irq(int irq, void *dev)
+{
+ struct mv_udc *udc = (struct mv_udc *)dev;
+
+ /* polling VBUS and init phy may cause too much time*/
+ if (udc->qwork)
+ queue_work(udc->qwork, &udc->vbus_work);
+
+ return IRQ_HANDLED;
+}
+
+static void mv_udc_vbus_work(struct work_struct *work)
+{
+ struct mv_udc *udc;
+ unsigned int vbus;
+
+ udc = container_of(work, struct mv_udc, vbus_work);
+ if (!udc->pdata->vbus)
+ return;
+
+ vbus = udc->pdata->vbus->poll();
+ dev_info(&udc->dev->dev, "vbus is %d\n", vbus);
+
+ if (vbus == VBUS_HIGH)
+ mv_udc_vbus_session(&udc->gadget, 1);
+ else if (vbus == VBUS_LOW)
+ mv_udc_vbus_session(&udc->gadget, 0);
+}
+
/* release device structure */
static void gadget_release(struct device *_dev)
{
struct mv_udc *udc = the_controller;
complete(udc->done);
- kfree(udc);
}
-static int mv_udc_remove(struct platform_device *dev)
+static int __devexit mv_udc_remove(struct platform_device *dev)
{
struct mv_udc *udc = the_controller;
- DECLARE_COMPLETION(done);
+ int clk_i;
usb_del_gadget_udc(&udc->gadget);
- udc->done = &done;
+ if (udc->qwork) {
+ flush_workqueue(udc->qwork);
+ destroy_workqueue(udc->qwork);
+ }
+
+ if (udc->pdata && udc->pdata->vbus && udc->clock_gating)
+ free_irq(udc->pdata->vbus->irq, &dev->dev);
/* free memory allocated in probe */
if (udc->dtd_pool)
@@ -1902,6 +2125,8 @@ static int mv_udc_remove(struct platform_device *dev)
if (udc->irq)
free_irq(udc->irq, &dev->dev);
+ mv_udc_disable(udc);
+
if (udc->cap_regs)
iounmap(udc->cap_regs);
udc->cap_regs = NULL;
@@ -1915,45 +2140,62 @@ static int mv_udc_remove(struct platform_device *dev)
kfree(udc->status_req);
}
+ for (clk_i = 0; clk_i <= udc->clknum; clk_i++)
+ clk_put(udc->clk[clk_i]);
+
device_unregister(&udc->gadget.dev);
/* free dev, wait for the release() finished */
- wait_for_completion(&done);
+ wait_for_completion(udc->done);
+ kfree(udc);
the_controller = NULL;
return 0;
}
-int mv_udc_probe(struct platform_device *dev)
+static int __devinit mv_udc_probe(struct platform_device *dev)
{
+ struct mv_usb_platform_data *pdata = dev->dev.platform_data;
struct mv_udc *udc;
int retval = 0;
+ int clk_i = 0;
struct resource *r;
size_t size;
- udc = kzalloc(sizeof *udc, GFP_KERNEL);
+ if (pdata == NULL) {
+ dev_err(&dev->dev, "missing platform_data\n");
+ return -ENODEV;
+ }
+
+ size = sizeof(*udc) + sizeof(struct clk *) * pdata->clknum;
+ udc = kzalloc(size, GFP_KERNEL);
if (udc == NULL) {
dev_err(&dev->dev, "failed to allocate memory for udc\n");
- retval = -ENOMEM;
- goto error;
+ return -ENOMEM;
}
+ the_controller = udc;
+ udc->done = &release_done;
+ udc->pdata = dev->dev.platform_data;
spin_lock_init(&udc->lock);
udc->dev = dev;
- udc->clk = clk_get(&dev->dev, "U2OCLK");
- if (IS_ERR(udc->clk)) {
- retval = PTR_ERR(udc->clk);
- goto error;
+ udc->clknum = pdata->clknum;
+ for (clk_i = 0; clk_i < udc->clknum; clk_i++) {
+ udc->clk[clk_i] = clk_get(&dev->dev, pdata->clkname[clk_i]);
+ if (IS_ERR(udc->clk[clk_i])) {
+ retval = PTR_ERR(udc->clk[clk_i]);
+ goto err_put_clk;
+ }
}
- r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "u2o");
+ r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "capregs");
if (r == NULL) {
dev_err(&dev->dev, "no I/O memory resource defined\n");
retval = -ENODEV;
- goto error;
+ goto err_put_clk;
}
udc->cap_regs = (struct mv_cap_regs __iomem *)
@@ -1961,29 +2203,31 @@ int mv_udc_probe(struct platform_device *dev)
if (udc->cap_regs == NULL) {
dev_err(&dev->dev, "failed to map I/O memory\n");
retval = -EBUSY;
- goto error;
+ goto err_put_clk;
}
- r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "u2ophy");
+ r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "phyregs");
if (r == NULL) {
dev_err(&dev->dev, "no phy I/O memory resource defined\n");
retval = -ENODEV;
- goto error;
+ goto err_iounmap_capreg;
}
udc->phy_regs = (unsigned int)ioremap(r->start, resource_size(r));
if (udc->phy_regs == 0) {
dev_err(&dev->dev, "failed to map phy I/O memory\n");
retval = -EBUSY;
- goto error;
+ goto err_iounmap_capreg;
}
/* we will acces controller register, so enable the clk */
- clk_enable(udc->clk);
- retval = mv_udc_phy_init(udc->phy_regs);
- if (retval) {
- dev_err(&dev->dev, "phy initialization error %d\n", retval);
- goto error;
+ udc_clock_enable(udc);
+ if (pdata->phy_init) {
+ retval = pdata->phy_init(udc->phy_regs);
+ if (retval) {
+ dev_err(&dev->dev, "phy init error %d\n", retval);
+ goto err_iounmap_phyreg;
+ }
}
udc->op_regs = (struct mv_op_regs __iomem *)((u32)udc->cap_regs
@@ -1991,6 +2235,13 @@ int mv_udc_probe(struct platform_device *dev)
& CAPLENGTH_MASK));
udc->max_eps = readl(&udc->cap_regs->dccparams) & DCCPARAMS_DEN_MASK;
+ /*
+ * some platform will use usb to download image, it may not disconnect
+ * usb gadget before loading kernel. So first stop udc here.
+ */
+ udc_stop(udc);
+ writel(0xFFFFFFFF, &udc->op_regs->usbsts);
+
size = udc->max_eps * sizeof(struct mv_dqh) *2;
size = (size + DQH_ALIGNMENT - 1) & ~(DQH_ALIGNMENT - 1);
udc->ep_dqh = dma_alloc_coherent(&dev->dev, size,
@@ -1999,7 +2250,7 @@ int mv_udc_probe(struct platform_device *dev)
if (udc->ep_dqh == NULL) {
dev_err(&dev->dev, "allocate dQH memory failed\n");
retval = -ENOMEM;
- goto error;
+ goto err_disable_clock;
}
udc->ep_dqh_size = size;
@@ -2012,7 +2263,7 @@ int mv_udc_probe(struct platform_device *dev)
if (!udc->dtd_pool) {
retval = -ENOMEM;
- goto error;
+ goto err_free_dma;
}
size = udc->max_eps * sizeof(struct mv_ep) *2;
@@ -2020,7 +2271,7 @@ int mv_udc_probe(struct platform_device *dev)
if (udc->eps == NULL) {
dev_err(&dev->dev, "allocate ep memory failed\n");
retval = -ENOMEM;
- goto error;
+ goto err_destroy_dma;
}
/* initialize ep0 status request structure */
@@ -2028,13 +2279,13 @@ int mv_udc_probe(struct platform_device *dev)
if (!udc->status_req) {
dev_err(&dev->dev, "allocate status_req memory failed\n");
retval = -ENOMEM;
- goto error;
+ goto err_free_eps;
}
INIT_LIST_HEAD(&udc->status_req->queue);
/* allocate a small amount of memory to get valid address */
udc->status_req->req.buf = kzalloc(8, GFP_KERNEL);
- udc->status_req->req.dma = virt_to_phys(udc->status_req->req.buf);
+ udc->status_req->req.dma = DMA_ADDR_INVALID;
udc->resume_state = USB_STATE_NOTATTACHED;
udc->usb_state = USB_STATE_POWERED;
@@ -2045,15 +2296,15 @@ int mv_udc_probe(struct platform_device *dev)
if (r == NULL) {
dev_err(&dev->dev, "no IRQ resource defined\n");
retval = -ENODEV;
- goto error;
+ goto err_free_status_req;
}
udc->irq = r->start;
if (request_irq(udc->irq, mv_udc_irq,
- IRQF_DISABLED | IRQF_SHARED, driver_name, udc)) {
+ IRQF_SHARED, driver_name, udc)) {
dev_err(&dev->dev, "Request irq %d for UDC failed\n",
udc->irq);
retval = -ENODEV;
- goto error;
+ goto err_free_status_req;
}
/* initialize gadget structure */
@@ -2072,18 +2323,82 @@ int mv_udc_probe(struct platform_device *dev)
retval = device_register(&udc->gadget.dev);
if (retval)
- goto error;
+ goto err_free_irq;
eps_init(udc);
- the_controller = udc;
+ /* VBUS detect: we can disable/enable clock on demand.*/
+ if (pdata->vbus) {
+ udc->clock_gating = 1;
+ retval = request_threaded_irq(pdata->vbus->irq, NULL,
+ mv_udc_vbus_irq, IRQF_ONESHOT, "vbus", udc);
+ if (retval) {
+ dev_info(&dev->dev,
+ "Can not request irq for VBUS, "
+ "disable clock gating\n");
+ udc->clock_gating = 0;
+ }
+
+ udc->qwork = create_singlethread_workqueue("mv_udc_queue");
+ if (!udc->qwork) {
+ dev_err(&dev->dev, "cannot create workqueue\n");
+ retval = -ENOMEM;
+ goto err_unregister;
+ }
+
+ INIT_WORK(&udc->vbus_work, mv_udc_vbus_work);
+ }
+
+ /*
+ * When clock gating is supported, we can disable clk and phy.
+ * If not, it means that VBUS detection is not supported, we
+ * have to enable vbus active all the time to let controller work.
+ */
+ if (udc->clock_gating) {
+ if (udc->pdata->phy_deinit)
+ udc->pdata->phy_deinit(udc->phy_regs);
+ udc_clock_disable(udc);
+ } else
+ udc->vbus_active = 1;
retval = usb_add_gadget_udc(&dev->dev, &udc->gadget);
- if (!retval)
- return retval;
-error:
- if (udc)
- mv_udc_remove(udc->dev);
+ if (retval)
+ goto err_unregister;
+
+ dev_info(&dev->dev, "successful probe UDC device %s clock gating.\n",
+ udc->clock_gating ? "with" : "without");
+
+ return 0;
+
+err_unregister:
+ if (udc->pdata && udc->pdata->vbus && udc->clock_gating)
+ free_irq(pdata->vbus->irq, &dev->dev);
+ device_unregister(&udc->gadget.dev);
+err_free_irq:
+ free_irq(udc->irq, &dev->dev);
+err_free_status_req:
+ kfree(udc->status_req->req.buf);
+ kfree(udc->status_req);
+err_free_eps:
+ kfree(udc->eps);
+err_destroy_dma:
+ dma_pool_destroy(udc->dtd_pool);
+err_free_dma:
+ dma_free_coherent(&dev->dev, udc->ep_dqh_size,
+ udc->ep_dqh, udc->ep_dqh_dma);
+err_disable_clock:
+ if (udc->pdata->phy_deinit)
+ udc->pdata->phy_deinit(udc->phy_regs);
+ udc_clock_disable(udc);
+err_iounmap_phyreg:
+ iounmap((void *)udc->phy_regs);
+err_iounmap_capreg:
+ iounmap(udc->cap_regs);
+err_put_clk:
+ for (clk_i--; clk_i >= 0; clk_i--)
+ clk_put(udc->clk[clk_i]);
+ the_controller = NULL;
+ kfree(udc);
return retval;
}
@@ -2102,11 +2417,16 @@ static int mv_udc_resume(struct device *_dev)
struct mv_udc *udc = the_controller;
int retval;
- retval = mv_udc_phy_init(udc->phy_regs);
- if (retval) {
- dev_err(_dev, "phy initialization error %d\n", retval);
- return retval;
+ if (udc->pdata->phy_init) {
+ retval = udc->pdata->phy_init(udc->phy_regs);
+ if (retval) {
+ dev_err(&udc->dev->dev,
+ "init phy error %d when resume back\n",
+ retval);
+ return retval;
+ }
}
+
udc_reset(udc);
ep0_reset(udc);
udc_start(udc);
@@ -2120,9 +2440,21 @@ static const struct dev_pm_ops mv_udc_pm_ops = {
};
#endif
+static void mv_udc_shutdown(struct platform_device *dev)
+{
+ struct mv_udc *udc = the_controller;
+ u32 mode;
+
+ /* reset controller mode to IDLE */
+ mode = readl(&udc->op_regs->usbmode);
+ mode &= ~3;
+ writel(mode, &udc->op_regs->usbmode);
+}
+
static struct platform_driver udc_driver = {
.probe = mv_udc_probe,
.remove = __exit_p(mv_udc_remove),
+ .shutdown = mv_udc_shutdown,
.driver = {
.owner = THIS_MODULE,
.name = "pxa-u2o",
diff --git a/drivers/usb/gadget/mv_udc_phy.c b/drivers/usb/gadget/mv_udc_phy.c
deleted file mode 100644
index d4dea97e38a5..000000000000
--- a/drivers/usb/gadget/mv_udc_phy.c
+++ /dev/null
@@ -1,214 +0,0 @@
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/io.h>
-#include <linux/errno.h>
-
-#include <mach/cputype.h>
-
-#ifdef CONFIG_ARCH_MMP
-
-#define UTMI_REVISION 0x0
-#define UTMI_CTRL 0x4
-#define UTMI_PLL 0x8
-#define UTMI_TX 0xc
-#define UTMI_RX 0x10
-#define UTMI_IVREF 0x14
-#define UTMI_T0 0x18
-#define UTMI_T1 0x1c
-#define UTMI_T2 0x20
-#define UTMI_T3 0x24
-#define UTMI_T4 0x28
-#define UTMI_T5 0x2c
-#define UTMI_RESERVE 0x30
-#define UTMI_USB_INT 0x34
-#define UTMI_DBG_CTL 0x38
-#define UTMI_OTG_ADDON 0x3c
-
-/* For UTMICTRL Register */
-#define UTMI_CTRL_USB_CLK_EN (1 << 31)
-/* pxa168 */
-#define UTMI_CTRL_SUSPEND_SET1 (1 << 30)
-#define UTMI_CTRL_SUSPEND_SET2 (1 << 29)
-#define UTMI_CTRL_RXBUF_PDWN (1 << 24)
-#define UTMI_CTRL_TXBUF_PDWN (1 << 11)
-
-#define UTMI_CTRL_INPKT_DELAY_SHIFT 30
-#define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT 28
-#define UTMI_CTRL_PU_REF_SHIFT 20
-#define UTMI_CTRL_ARC_PULLDN_SHIFT 12
-#define UTMI_CTRL_PLL_PWR_UP_SHIFT 1
-#define UTMI_CTRL_PWR_UP_SHIFT 0
-/* For UTMI_PLL Register */
-#define UTMI_PLL_CLK_BLK_EN_SHIFT 24
-#define UTMI_PLL_FBDIV_SHIFT 4
-#define UTMI_PLL_REFDIV_SHIFT 0
-#define UTMI_PLL_FBDIV_MASK 0x00000FF0
-#define UTMI_PLL_REFDIV_MASK 0x0000000F
-#define UTMI_PLL_ICP_MASK 0x00007000
-#define UTMI_PLL_KVCO_MASK 0x00031000
-#define UTMI_PLL_PLLCALI12_SHIFT 29
-#define UTMI_PLL_PLLCALI12_MASK (0x3 << 29)
-#define UTMI_PLL_PLLVDD18_SHIFT 27
-#define UTMI_PLL_PLLVDD18_MASK (0x3 << 27)
-#define UTMI_PLL_PLLVDD12_SHIFT 25
-#define UTMI_PLL_PLLVDD12_MASK (0x3 << 25)
-#define UTMI_PLL_KVCO_SHIFT 15
-#define UTMI_PLL_ICP_SHIFT 12
-/* For UTMI_TX Register */
-#define UTMI_TX_REG_EXT_FS_RCAL_SHIFT 27
-#define UTMI_TX_REG_EXT_FS_RCAL_MASK (0xf << 27)
-#define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK 26
-#define UTMI_TX_REG_EXT_FS_RCAL_EN (0x1 << 26)
-#define UTMI_TX_LOW_VDD_EN_SHIFT 11
-#define UTMI_TX_IMPCAL_VTH_SHIFT 14
-#define UTMI_TX_IMPCAL_VTH_MASK (0x7 << 14)
-#define UTMI_TX_CK60_PHSEL_SHIFT 17
-#define UTMI_TX_CK60_PHSEL_MASK (0xf << 17)
-#define UTMI_TX_TXVDD12_SHIFT 22
-#define UTMI_TX_TXVDD12_MASK (0x3 << 22)
-#define UTMI_TX_AMP_SHIFT 0
-#define UTMI_TX_AMP_MASK (0x7 << 0)
-/* For UTMI_RX Register */
-#define UTMI_RX_SQ_THRESH_SHIFT 4
-#define UTMI_RX_SQ_THRESH_MASK (0xf << 4)
-#define UTMI_REG_SQ_LENGTH_SHIFT 15
-#define UTMI_REG_SQ_LENGTH_MASK (0x3 << 15)
-
-#define REG_RCAL_START 0x00001000
-#define VCOCAL_START 0x00200000
-#define KVCO_EXT 0x00400000
-#define PLL_READY 0x00800000
-#define CLK_BLK_EN 0x01000000
-#endif
-
-static unsigned int u2o_read(unsigned int base, unsigned int offset)
-{
- return readl(base + offset);
-}
-
-static void u2o_set(unsigned int base, unsigned int offset, unsigned int value)
-{
- unsigned int reg;
-
- reg = readl(base + offset);
- reg |= value;
- writel(reg, base + offset);
- readl(base + offset);
-}
-
-static void u2o_clear(unsigned int base, unsigned int offset,
- unsigned int value)
-{
- unsigned int reg;
-
- reg = readl(base + offset);
- reg &= ~value;
- writel(reg, base + offset);
- readl(base + offset);
-}
-
-static void u2o_write(unsigned int base, unsigned int offset,
- unsigned int value)
-{
- writel(value, base + offset);
- readl(base + offset);
-}
-
-#ifdef CONFIG_ARCH_MMP
-int mv_udc_phy_init(unsigned int base)
-{
- unsigned long timeout;
-
- /* Initialize the USB PHY power */
- if (cpu_is_pxa910()) {
- u2o_set(base, UTMI_CTRL, (1 << UTMI_CTRL_INPKT_DELAY_SOF_SHIFT)
- | (1 << UTMI_CTRL_PU_REF_SHIFT));
- }
-
- u2o_set(base, UTMI_CTRL, 1 << UTMI_CTRL_PLL_PWR_UP_SHIFT);
- u2o_set(base, UTMI_CTRL, 1 << UTMI_CTRL_PWR_UP_SHIFT);
-
- /* UTMI_PLL settings */
- u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK
- | UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK
- | UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK
- | UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK);
-
- u2o_set(base, UTMI_PLL, (0xee << UTMI_PLL_FBDIV_SHIFT)
- | (0xb << UTMI_PLL_REFDIV_SHIFT)
- | (3 << UTMI_PLL_PLLVDD18_SHIFT)
- | (3 << UTMI_PLL_PLLVDD12_SHIFT)
- | (3 << UTMI_PLL_PLLCALI12_SHIFT)
- | (1 << UTMI_PLL_ICP_SHIFT) | (3 << UTMI_PLL_KVCO_SHIFT));
-
- /* UTMI_TX */
- u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK
- | UTMI_TX_TXVDD12_MASK
- | UTMI_TX_CK60_PHSEL_MASK | UTMI_TX_IMPCAL_VTH_MASK
- | UTMI_TX_REG_EXT_FS_RCAL_MASK | UTMI_TX_AMP_MASK);
- u2o_set(base, UTMI_TX, (3 << UTMI_TX_TXVDD12_SHIFT)
- | (4 << UTMI_TX_CK60_PHSEL_SHIFT)
- | (4 << UTMI_TX_IMPCAL_VTH_SHIFT)
- | (8 << UTMI_TX_REG_EXT_FS_RCAL_SHIFT)
- | (3 << UTMI_TX_AMP_SHIFT));
-
- /* UTMI_RX */
- u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK
- | UTMI_REG_SQ_LENGTH_MASK);
- if (cpu_is_pxa168())
- u2o_set(base, UTMI_RX, (7 << UTMI_RX_SQ_THRESH_SHIFT)
- | (2 << UTMI_REG_SQ_LENGTH_SHIFT));
- else
- u2o_set(base, UTMI_RX, (0x7 << UTMI_RX_SQ_THRESH_SHIFT)
- | (2 << UTMI_REG_SQ_LENGTH_SHIFT));
-
- /* UTMI_IVREF */
- if (cpu_is_pxa168())
- /*
- * fixing Microsoft Altair board interface with NEC hub issue -
- * Set UTMI_IVREF from 0x4a3 to 0x4bf
- */
- u2o_write(base, UTMI_IVREF, 0x4bf);
-
- /* calibrate */
- timeout = jiffies + 100;
- while ((u2o_read(base, UTMI_PLL) & PLL_READY) == 0) {
- if (time_after(jiffies, timeout))
- return -ETIME;
- cpu_relax();
- }
-
- /* toggle VCOCAL_START bit of UTMI_PLL */
- udelay(200);
- u2o_set(base, UTMI_PLL, VCOCAL_START);
- udelay(40);
- u2o_clear(base, UTMI_PLL, VCOCAL_START);
-
- /* toggle REG_RCAL_START bit of UTMI_TX */
- udelay(200);
- u2o_set(base, UTMI_TX, REG_RCAL_START);
- udelay(40);
- u2o_clear(base, UTMI_TX, REG_RCAL_START);
- udelay(200);
-
- /* make sure phy is ready */
- timeout = jiffies + 100;
- while ((u2o_read(base, UTMI_PLL) & PLL_READY) == 0) {
- if (time_after(jiffies, timeout))
- return -ETIME;
- cpu_relax();
- }
-
- if (cpu_is_pxa168()) {
- u2o_set(base, UTMI_RESERVE, 1 << 5);
- /* Turn on UTMI PHY OTG extension */
- u2o_write(base, UTMI_OTG_ADDON, 1);
- }
- return 0;
-}
-#else
-int mv_udc_phy_init(unsigned int base)
-{
- return 0;
-}
-#endif
diff --git a/drivers/usb/gadget/ncm.c b/drivers/usb/gadget/ncm.c
index 62ee5087dcac..89530034dff1 100644
--- a/drivers/usb/gadget/ncm.c
+++ b/drivers/usb/gadget/ncm.c
@@ -14,15 +14,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* #define DEBUG */
diff --git a/drivers/usb/gadget/ndis.h b/drivers/usb/gadget/ndis.h
index df886cec5ef4..b0e52fc277b4 100644
--- a/drivers/usb/gadget/ndis.h
+++ b/drivers/usb/gadget/ndis.h
@@ -10,12 +10,6 @@
*
* This source code is offered for use in the public domain. You may
* use, modify or distribute it freely.
- *
- * This code is distributed in the hope that it will be useful but
- * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
- * DISCLAIMED. This includes but is not limited to warranties of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
*/
#ifndef _LINUX_NDIS_H
diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c
index ab98ea926a11..d1b76368472f 100644
--- a/drivers/usb/gadget/net2272.c
+++ b/drivers/usb/gadget/net2272.c
@@ -204,7 +204,7 @@ net2272_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
return -ESHUTDOWN;
- max = le16_to_cpu(desc->wMaxPacketSize) & 0x1fff;
+ max = usb_endpoint_maxp(desc) & 0x1fff;
spin_lock_irqsave(&dev->lock, flags);
_ep->maxpacket = max & 0x7fff;
@@ -1172,17 +1172,18 @@ net2272_pullup(struct usb_gadget *_gadget, int is_on)
return 0;
}
-static int net2272_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *));
-static int net2272_stop(struct usb_gadget_driver *driver);
+static int net2272_start(struct usb_gadget *_gadget,
+ struct usb_gadget_driver *driver);
+static int net2272_stop(struct usb_gadget *_gadget,
+ struct usb_gadget_driver *driver);
static const struct usb_gadget_ops net2272_ops = {
- .get_frame = net2272_get_frame,
- .wakeup = net2272_wakeup,
+ .get_frame = net2272_get_frame,
+ .wakeup = net2272_wakeup,
.set_selfpowered = net2272_set_selfpowered,
- .pullup = net2272_pullup,
- .start = net2272_start,
- .stop = net2272_stop,
+ .pullup = net2272_pullup,
+ .udc_start = net2272_start,
+ .udc_stop = net2272_stop,
};
/*---------------------------------------------------------------------------*/
@@ -1356,8 +1357,6 @@ net2272_set_fifo_mode(struct net2272 *dev, int mode)
/*---------------------------------------------------------------------------*/
-static struct net2272 *the_controller;
-
static void
net2272_usb_reset(struct net2272 *dev)
{
@@ -1453,20 +1452,17 @@ net2272_ep0_start(struct net2272 *dev)
* disconnect is reported. then a host may connect again, or
* the driver might get unbound.
*/
-static int net2272_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *))
+static int net2272_start(struct usb_gadget *_gadget,
+ struct usb_gadget_driver *driver)
{
- struct net2272 *dev = the_controller;
- int ret;
+ struct net2272 *dev;
unsigned i;
- if (!driver || !bind || !driver->unbind || !driver->setup ||
+ if (!driver || !driver->unbind || !driver->setup ||
driver->speed != USB_SPEED_HIGH)
return -EINVAL;
- if (!dev)
- return -ENODEV;
- if (dev->driver)
- return -EBUSY;
+
+ dev = container_of(_gadget, struct net2272, gadget);
for (i = 0; i < 4; ++i)
dev->ep[i].irqs = 0;
@@ -1475,14 +1471,6 @@ static int net2272_start(struct usb_gadget_driver *driver,
driver->driver.bus = NULL;
dev->driver = driver;
dev->gadget.dev.driver = &driver->driver;
- ret = bind(&dev->gadget);
- if (ret) {
- dev_dbg(dev->dev, "bind to driver %s --> %d\n",
- driver->driver.name, ret);
- dev->driver = NULL;
- dev->gadget.dev.driver = NULL;
- return ret;
- }
/* ... then enable host detection and ep0; and we're ready
* for set_configuration as well as eventual disconnect.
@@ -1510,33 +1498,21 @@ stop_activity(struct net2272 *dev, struct usb_gadget_driver *driver)
for (i = 0; i < 4; ++i)
net2272_dequeue_all(&dev->ep[i]);
- /* report disconnect; the driver is already quiesced */
- if (driver) {
- spin_unlock(&dev->lock);
- driver->disconnect(&dev->gadget);
- spin_lock(&dev->lock);
-
- }
net2272_usb_reinit(dev);
}
-static int net2272_stop(struct usb_gadget_driver *driver)
+static int net2272_stop(struct usb_gadget *_gadget,
+ struct usb_gadget_driver *driver)
{
- struct net2272 *dev = the_controller;
+ struct net2272 *dev;
unsigned long flags;
- if (!dev)
- return -ENODEV;
- if (!driver || driver != dev->driver)
- return -EINVAL;
+ dev = container_of(_gadget, struct net2272, gadget);
spin_lock_irqsave(&dev->lock, flags);
stop_activity(dev, driver);
spin_unlock_irqrestore(&dev->lock, flags);
- net2272_pullup(&dev->gadget, 0);
-
- driver->unbind(&dev->gadget);
dev->gadget.dev.driver = NULL;
dev->driver = NULL;
@@ -1764,8 +1740,8 @@ net2272_handle_stat0_irqs(struct net2272 *dev, u8 stat)
dev->gadget.speed = USB_SPEED_HIGH;
else
dev->gadget.speed = USB_SPEED_FULL;
- dev_dbg(dev->dev, "%s speed\n",
- (dev->gadget.speed == USB_SPEED_HIGH) ? "high" : "full");
+ dev_dbg(dev->dev, "%s\n",
+ usb_speed_string(dev->gadget.speed));
}
ep = &dev->ep[0];
@@ -2238,7 +2214,6 @@ net2272_remove(struct net2272 *dev)
device_remove_file(dev->dev, &dev_attr_registers);
dev_info(dev->dev, "unbind\n");
- the_controller = NULL;
}
static struct net2272 * __devinit
@@ -2246,11 +2221,6 @@ net2272_probe_init(struct device *dev, unsigned int irq)
{
struct net2272 *ret;
- if (the_controller) {
- dev_warn(dev, "ignoring\n");
- return ERR_PTR(-EBUSY);
- }
-
if (!irq) {
dev_dbg(dev, "No IRQ!\n");
return ERR_PTR(-ENODEV);
@@ -2307,8 +2277,6 @@ net2272_probe_fin(struct net2272 *dev, unsigned int irqflags)
dma_mode_string());
dev_info(dev->dev, "version: %s\n", driver_vers);
- the_controller = dev;
-
ret = device_register(&dev->gadget.dev);
if (ret)
goto err_irq;
@@ -2684,8 +2652,6 @@ net2272_plat_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "running in 16-bit, %sbyte swap local bus mode\n",
(net2272_read(dev, LOCCTL) & (1 << BYTE_SWAP)) ? "" : "no ");
- the_controller = dev;
-
return 0;
err_io:
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 3dd40b4e675c..7f1bc9a73cda 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -33,15 +33,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#undef DEBUG /* messages on error and most fault paths */
@@ -169,7 +160,7 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
return -EDOM;
/* sanity check ep-e/ep-f since their fifos are small */
- max = le16_to_cpu (desc->wMaxPacketSize) & 0x1fff;
+ max = usb_endpoint_maxp (desc) & 0x1fff;
if (ep->num > 4 && max > 64)
return -ERANGE;
@@ -1410,17 +1401,18 @@ static int net2280_pullup(struct usb_gadget *_gadget, int is_on)
return 0;
}
-static int net2280_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *));
-static int net2280_stop(struct usb_gadget_driver *driver);
+static int net2280_start(struct usb_gadget *_gadget,
+ struct usb_gadget_driver *driver);
+static int net2280_stop(struct usb_gadget *_gadget,
+ struct usb_gadget_driver *driver);
static const struct usb_gadget_ops net2280_ops = {
.get_frame = net2280_get_frame,
.wakeup = net2280_wakeup,
.set_selfpowered = net2280_set_selfpowered,
.pullup = net2280_pullup,
- .start = net2280_start,
- .stop = net2280_stop,
+ .udc_start = net2280_start,
+ .udc_stop = net2280_stop,
};
/*-------------------------------------------------------------------------*/
@@ -1640,7 +1632,7 @@ show_queues (struct device *_dev, struct device_attribute *attr, char *buf)
default:
val = "iso"; break;
}; val; }),
- le16_to_cpu (d->wMaxPacketSize) & 0x1fff,
+ usb_endpoint_maxp (d) & 0x1fff,
ep->dma ? "dma" : "pio", ep->fifo_size
);
} else /* ep0 should only have one transfer queued */
@@ -1753,8 +1745,6 @@ static void set_fifo_mode (struct net2280 *dev, int mode)
* perhaps to bind specific drivers to specific devices.
*/
-static struct net2280 *the_controller;
-
static void usb_reset (struct net2280 *dev)
{
u32 tmp;
@@ -1880,10 +1870,10 @@ static void ep0_start (struct net2280 *dev)
* disconnect is reported. then a host may connect again, or
* the driver might get unbound.
*/
-static int net2280_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *))
+static int net2280_start(struct usb_gadget *_gadget,
+ struct usb_gadget_driver *driver)
{
- struct net2280 *dev = the_controller;
+ struct net2280 *dev;
int retval;
unsigned i;
@@ -1891,14 +1881,11 @@ static int net2280_start(struct usb_gadget_driver *driver,
* (dev->usb->xcvrdiag & FORCE_FULL_SPEED_MODE)
* "must not be used in normal operation"
*/
- if (!driver
- || driver->speed != USB_SPEED_HIGH
- || !bind || !driver->setup)
+ if (!driver || driver->speed != USB_SPEED_HIGH
+ || !driver->setup)
return -EINVAL;
- if (!dev)
- return -ENODEV;
- if (dev->driver)
- return -EBUSY;
+
+ dev = container_of (_gadget, struct net2280, gadget);
for (i = 0; i < 7; i++)
dev->ep [i].irqs = 0;
@@ -1908,14 +1895,6 @@ static int net2280_start(struct usb_gadget_driver *driver,
driver->driver.bus = NULL;
dev->driver = driver;
dev->gadget.dev.driver = &driver->driver;
- retval = bind(&dev->gadget);
- if (retval) {
- DEBUG (dev, "bind to driver %s --> %d\n",
- driver->driver.name, retval);
- dev->driver = NULL;
- dev->gadget.dev.driver = NULL;
- return retval;
- }
retval = device_create_file (&dev->pdev->dev, &dev_attr_function);
if (retval) goto err_unbind;
@@ -1961,33 +1940,21 @@ stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver)
for (i = 0; i < 7; i++)
nuke (&dev->ep [i]);
- /* report disconnect; the driver is already quiesced */
- if (driver) {
- spin_unlock (&dev->lock);
- driver->disconnect (&dev->gadget);
- spin_lock (&dev->lock);
- }
-
usb_reinit (dev);
}
-static int net2280_stop(struct usb_gadget_driver *driver)
+static int net2280_stop(struct usb_gadget *_gadget,
+ struct usb_gadget_driver *driver)
{
- struct net2280 *dev = the_controller;
+ struct net2280 *dev;
unsigned long flags;
- if (!dev)
- return -ENODEV;
- if (!driver || driver != dev->driver || !driver->unbind)
- return -EINVAL;
+ dev = container_of (_gadget, struct net2280, gadget);
spin_lock_irqsave (&dev->lock, flags);
stop_activity (dev, driver);
spin_unlock_irqrestore (&dev->lock, flags);
- net2280_pullup (&dev->gadget, 0);
-
- driver->unbind (&dev->gadget);
dev->gadget.dev.driver = NULL;
dev->driver = NULL;
@@ -2266,9 +2233,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
else
dev->gadget.speed = USB_SPEED_FULL;
net2280_led_speed (dev, dev->gadget.speed);
- DEBUG (dev, "%s speed\n",
- (dev->gadget.speed == USB_SPEED_HIGH)
- ? "high" : "full");
+ DEBUG(dev, "%s\n", usb_speed_string(dev->gadget.speed));
}
ep = &dev->ep [0];
@@ -2481,7 +2446,7 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat)
mask = (1 << HIGH_SPEED) | (1 << FULL_SPEED);
/* VBUS disconnect is indicated by VBUS_PIN and VBUS_INTERRUPT set.
- * Root Port Reset is indicated by ROOT_PORT_RESET_INTERRRUPT set and
+ * Root Port Reset is indicated by ROOT_PORT_RESET_INTERRUPT set and
* both HIGH_SPEED and FULL_SPEED clear (as ROOT_PORT_RESET_INTERRUPT
* only indicates a change in the reset state).
*/
@@ -2709,8 +2674,6 @@ static void net2280_remove (struct pci_dev *pdev)
pci_set_drvdata (pdev, NULL);
INFO (dev, "unbind\n");
-
- the_controller = NULL;
}
/* wrap this driver around the specified device, but
@@ -2724,14 +2687,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
void __iomem *base = NULL;
int retval, i;
- /* if you want to support more than one controller in a system,
- * usb_gadget_driver_{register,unregister}() must change.
- */
- if (the_controller) {
- dev_warn (&pdev->dev, "ignoring\n");
- return -EBUSY;
- }
-
/* alloc, and start init */
dev = kzalloc (sizeof *dev, GFP_KERNEL);
if (dev == NULL){
@@ -2858,8 +2813,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
use_dma
? (use_dma_chaining ? "chaining" : "enabled")
: "disabled");
- the_controller = dev;
-
retval = device_register (&dev->gadget.dev);
if (retval) goto done;
retval = device_create_file (&pdev->dev, &dev_attr_registers);
diff --git a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h
index c36852263d93..a844be0d683a 100644
--- a/drivers/usb/gadget/net2280.h
+++ b/drivers/usb/gadget/net2280.h
@@ -11,15 +11,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/usb/net2280.h>
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 740c7daed279..788989a10223 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -10,15 +10,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#undef DEBUG
@@ -166,15 +157,14 @@ static int omap_ep_enable(struct usb_ep *_ep,
if (!_ep || !desc || ep->desc
|| desc->bDescriptorType != USB_DT_ENDPOINT
|| ep->bEndpointAddress != desc->bEndpointAddress
- || ep->maxpacket < le16_to_cpu
- (desc->wMaxPacketSize)) {
+ || ep->maxpacket < usb_endpoint_maxp(desc)) {
DBG("%s, bad ep or descriptor\n", __func__);
return -EINVAL;
}
- maxp = le16_to_cpu (desc->wMaxPacketSize);
+ maxp = usb_endpoint_maxp(desc);
if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
&& maxp != ep->maxpacket)
- || le16_to_cpu(desc->wMaxPacketSize) > ep->maxpacket
+ || usb_endpoint_maxp(desc) > ep->maxpacket
|| !desc->wMaxPacketSize) {
DBG("%s, bad %s maxpacket\n", __func__, _ep->name);
return -ERANGE;
@@ -2968,7 +2958,7 @@ known:
}
#ifdef USE_ISO
status = request_irq(pdev->resource[3].start, omap_udc_iso_irq,
- IRQF_DISABLED, "omap_udc iso", udc);
+ 0, "omap_udc iso", udc);
if (status != 0) {
ERR("can't get irq %d, err %d\n",
(int) pdev->resource[3].start, status);
diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
index f96615ab6b77..550d6dcdf104 100644
--- a/drivers/usb/gadget/pch_udc.c
+++ b/drivers/usb/gadget/pch_udc.c
@@ -4,15 +4,6 @@
* 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
@@ -947,7 +938,7 @@ static void pch_udc_ep_enable(struct pch_udc_ep *ep,
else
buff_size = UDC_EPOUT_BUFF_SIZE;
pch_udc_ep_set_bufsz(ep, buff_size, ep->in);
- pch_udc_ep_set_maxpkt(ep, le16_to_cpu(desc->wMaxPacketSize));
+ pch_udc_ep_set_maxpkt(ep, usb_endpoint_maxp(desc));
pch_udc_ep_set_nak(ep);
pch_udc_ep_fifo_flush(ep, ep->in);
/* Configure the endpoint */
@@ -957,7 +948,7 @@ static void pch_udc_ep_enable(struct pch_udc_ep *ep,
(cfg->cur_cfg << UDC_CSR_NE_CFG_SHIFT) |
(cfg->cur_intf << UDC_CSR_NE_INTF_SHIFT) |
(cfg->cur_alt << UDC_CSR_NE_ALT_SHIFT) |
- le16_to_cpu(desc->wMaxPacketSize) << UDC_CSR_NE_MAX_PKT_SHIFT;
+ usb_endpoint_maxp(desc) << UDC_CSR_NE_MAX_PKT_SHIFT;
if (ep->in)
pch_udc_write_csr(ep->dev, val, UDC_EPIN_IDX(ep->num));
@@ -1466,7 +1457,7 @@ static int pch_udc_pcd_ep_enable(struct usb_ep *usbep,
ep->desc = desc;
ep->halted = 0;
pch_udc_ep_enable(ep, &ep->dev->cfg_data, desc);
- ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+ ep->ep.maxpacket = usb_endpoint_maxp(desc);
pch_udc_enable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num));
spin_unlock_irqrestore(&dev->lock, iflags);
return 0;
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
index a341dde6f9c3..65a8834f274b 100644
--- a/drivers/usb/gadget/printer.c
+++ b/drivers/usb/gadget/printer.c
@@ -8,15 +8,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
@@ -971,23 +962,15 @@ printer_set_config(struct printer_dev *dev, unsigned number)
usb_gadget_vbus_draw(dev->gadget,
dev->gadget->is_otg ? 8 : 100);
} else {
- char *speed;
unsigned power;
power = 2 * config_desc.bMaxPower;
usb_gadget_vbus_draw(dev->gadget, power);
- switch (gadget->speed) {
- case USB_SPEED_FULL: speed = "full"; break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- case USB_SPEED_HIGH: speed = "high"; break;
-#endif
- default: speed = "?"; break;
- }
-
dev->config = number;
- INFO(dev, "%s speed config #%d: %d mA, %s\n",
- speed, number, power, driver_desc);
+ INFO(dev, "%s config #%d: %d mA, %s\n",
+ usb_speed_string(gadget->speed),
+ number, power, driver_desc);
}
return result;
}
@@ -1611,7 +1594,7 @@ cleanup(void)
if (status)
ERROR(dev, "usb_gadget_unregister_driver %x\n", status);
- unregister_chrdev_region(g_printer_devno, 2);
+ unregister_chrdev_region(g_printer_devno, 1);
class_destroy(usb_gadget_class);
mutex_unlock(&usb_printer_gadget.lock_printer_io);
}
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index e4e59b4de25d..c090a7e3ecf8 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -11,16 +11,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
/* #define VERBOSE_DEBUG */
@@ -232,8 +222,7 @@ static int pxa25x_ep_enable (struct usb_ep *_ep,
if (!_ep || !desc || ep->desc || _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT
|| ep->bEndpointAddress != desc->bEndpointAddress
- || ep->fifo_size < le16_to_cpu
- (desc->wMaxPacketSize)) {
+ || ep->fifo_size < usb_endpoint_maxp (desc)) {
DMSG("%s, bad ep or descriptor\n", __func__);
return -EINVAL;
}
@@ -248,7 +237,7 @@ static int pxa25x_ep_enable (struct usb_ep *_ep,
/* hardware _could_ do smaller, but driver doesn't */
if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
- && le16_to_cpu (desc->wMaxPacketSize)
+ && usb_endpoint_maxp (desc)
!= BULK_FIFO_SIZE)
|| !desc->wMaxPacketSize) {
DMSG("%s, bad %s maxpacket\n", __func__, _ep->name);
@@ -264,7 +253,7 @@ static int pxa25x_ep_enable (struct usb_ep *_ep,
ep->desc = desc;
ep->stopped = 0;
ep->pio_irqs = 0;
- ep->ep.maxpacket = le16_to_cpu (desc->wMaxPacketSize);
+ ep->ep.maxpacket = usb_endpoint_maxp (desc);
/* flush fifo (mostly for OUT buffers) */
pxa25x_ep_fifo_flush (_ep);
@@ -401,7 +390,7 @@ write_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
{
unsigned max;
- max = le16_to_cpu(ep->desc->wMaxPacketSize);
+ max = usb_endpoint_maxp(ep->desc);
do {
unsigned count;
int is_last, is_short;
@@ -671,8 +660,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
* we can report per-packet status. that also helps with dma.
*/
if (unlikely (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
- && req->req.length > le16_to_cpu
- (ep->desc->wMaxPacketSize)))
+ && req->req.length > usb_endpoint_maxp (ep->desc)))
return -EMSGSIZE;
DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n",
@@ -1105,7 +1093,7 @@ udc_seq_show(struct seq_file *m, void *_d)
tmp = *dev->ep [i].reg_udccs;
seq_printf(m,
"%s max %d %s udccs %02x irqs %lu\n",
- ep->ep.name, le16_to_cpu(desc->wMaxPacketSize),
+ ep->ep.name, usb_endpoint_maxp(desc),
"pio", tmp, ep->pio_irqs);
/* TODO translate all five groups of udccs bits! */
@@ -2202,7 +2190,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
/* irq setup after old hardware state is cleaned up */
retval = request_irq(irq, pxa25x_udc_irq,
- IRQF_DISABLED, driver_name, dev);
+ 0, driver_name, dev);
if (retval != 0) {
pr_err("%s: can't get irq %d, err %d\n",
driver_name, irq, retval);
@@ -2214,7 +2202,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
if (machine_is_lubbock()) {
retval = request_irq(LUBBOCK_USB_DISC_IRQ,
lubbock_vbus_irq,
- IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
+ IRQF_SAMPLE_RANDOM,
driver_name, dev);
if (retval != 0) {
pr_err("%s: can't get irq %i, err %d\n",
@@ -2223,7 +2211,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
}
retval = request_irq(LUBBOCK_USB_IRQ,
lubbock_vbus_irq,
- IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
+ IRQF_SAMPLE_RANDOM,
driver_name, dev);
if (retval != 0) {
pr_err("%s: can't get irq %i, err %d\n",
diff --git a/drivers/usb/gadget/pxa25x_udc.h b/drivers/usb/gadget/pxa25x_udc.h
index f572c5617462..8eaf4e43726b 100644
--- a/drivers/usb/gadget/pxa25x_udc.h
+++ b/drivers/usb/gadget/pxa25x_udc.h
@@ -9,15 +9,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __LINUX_USB_GADGET_PXA25X_H
@@ -161,8 +152,6 @@ static struct pxa25x_udc *the_controller;
#ifdef DEBUG
-static int is_vbus_present(void);
-
static const char *state_name[] = {
"EP0_IDLE",
"EP0_IN_DATA_PHASE", "EP0_OUT_DATA_PHASE",
@@ -214,8 +203,7 @@ dump_state(struct pxa25x_udc *dev)
u32 tmp;
unsigned i;
- DMSG("%s %s, uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n",
- is_vbus_present() ? "host " : "disconnected",
+ DMSG("%s, uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n",
state_name[dev->ep0state],
UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL);
dump_udccr("udccr");
@@ -232,9 +220,6 @@ dump_state(struct pxa25x_udc *dev)
} else
DMSG("ep0 driver '%s'\n", dev->driver->driver.name);
- if (!is_vbus_present())
- return;
-
dump_udccs0 ("udccs0");
DMSG("ep0 IN %lu/%lu, OUT %lu/%lu\n",
dev->stats.write.bytes, dev->stats.write.ops,
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index 85b68c75dc9d..18b6b091f2a6 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -8,16 +8,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
#include <linux/module.h>
#include <linux/kernel.h>
@@ -1439,7 +1429,7 @@ static int pxa_ep_enable(struct usb_ep *_ep,
return -EINVAL;
}
- if (ep->fifo_size < le16_to_cpu(desc->wMaxPacketSize)) {
+ if (ep->fifo_size < usb_endpoint_maxp(desc)) {
ep_err(ep, "bad maxpacket\n");
return -ERANGE;
}
diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/pxa27x_udc.h
index b01696eab068..7f4e8f424e80 100644
--- a/drivers/usb/gadget/pxa27x_udc.h
+++ b/drivers/usb/gadget/pxa27x_udc.h
@@ -9,15 +9,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __LINUX_USB_GADGET_PXA27X_H
diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c
index 50991e5bd5e8..68a826a1b866 100644
--- a/drivers/usb/gadget/r8a66597-udc.c
+++ b/drivers/usb/gadget/r8a66597-udc.c
@@ -8,16 +8,6 @@
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include <linux/module.h>
@@ -28,13 +18,14 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/slab.h>
+#include <linux/dma-mapping.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include "r8a66597-udc.h"
-#define DRIVER_VERSION "2009-08-18"
+#define DRIVER_VERSION "2011-09-26"
static const char udc_name[] = "r8a66597_udc";
static const char *r8a66597_ep_name[] = {
@@ -115,13 +106,15 @@ static inline u16 control_reg_get_pid(struct r8a66597 *r8a66597, u16 pipenum)
u16 pid = 0;
unsigned long offset;
- if (pipenum == 0)
+ if (pipenum == 0) {
pid = r8a66597_read(r8a66597, DCPCTR) & PID;
- else if (pipenum < R8A66597_MAX_NUM_PIPE) {
+ } else if (pipenum < R8A66597_MAX_NUM_PIPE) {
offset = get_pipectr_addr(pipenum);
pid = r8a66597_read(r8a66597, offset) & PID;
- } else
- printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
+ } else {
+ dev_err(r8a66597_to_dev(r8a66597), "unexpect pipe num (%d)\n",
+ pipenum);
+ }
return pid;
}
@@ -131,13 +124,15 @@ static inline void control_reg_set_pid(struct r8a66597 *r8a66597, u16 pipenum,
{
unsigned long offset;
- if (pipenum == 0)
+ if (pipenum == 0) {
r8a66597_mdfy(r8a66597, pid, PID, DCPCTR);
- else if (pipenum < R8A66597_MAX_NUM_PIPE) {
+ } else if (pipenum < R8A66597_MAX_NUM_PIPE) {
offset = get_pipectr_addr(pipenum);
r8a66597_mdfy(r8a66597, pid, PID, offset);
- } else
- printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
+ } else {
+ dev_err(r8a66597_to_dev(r8a66597), "unexpect pipe num (%d)\n",
+ pipenum);
+ }
}
static inline void pipe_start(struct r8a66597 *r8a66597, u16 pipenum)
@@ -160,13 +155,15 @@ static inline u16 control_reg_get(struct r8a66597 *r8a66597, u16 pipenum)
u16 ret = 0;
unsigned long offset;
- if (pipenum == 0)
+ if (pipenum == 0) {
ret = r8a66597_read(r8a66597, DCPCTR);
- else if (pipenum < R8A66597_MAX_NUM_PIPE) {
+ } else if (pipenum < R8A66597_MAX_NUM_PIPE) {
offset = get_pipectr_addr(pipenum);
ret = r8a66597_read(r8a66597, offset);
- } else
- printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
+ } else {
+ dev_err(r8a66597_to_dev(r8a66597), "unexpect pipe num (%d)\n",
+ pipenum);
+ }
return ret;
}
@@ -177,13 +174,63 @@ static inline void control_reg_sqclr(struct r8a66597 *r8a66597, u16 pipenum)
pipe_stop(r8a66597, pipenum);
- if (pipenum == 0)
+ if (pipenum == 0) {
r8a66597_bset(r8a66597, SQCLR, DCPCTR);
- else if (pipenum < R8A66597_MAX_NUM_PIPE) {
+ } else if (pipenum < R8A66597_MAX_NUM_PIPE) {
offset = get_pipectr_addr(pipenum);
r8a66597_bset(r8a66597, SQCLR, offset);
- } else
- printk(KERN_ERR "unexpect pipe num(%d)\n", pipenum);
+ } else {
+ dev_err(r8a66597_to_dev(r8a66597), "unexpect pipe num (%d)\n",
+ pipenum);
+ }
+}
+
+static void control_reg_sqset(struct r8a66597 *r8a66597, u16 pipenum)
+{
+ unsigned long offset;
+
+ pipe_stop(r8a66597, pipenum);
+
+ if (pipenum == 0) {
+ r8a66597_bset(r8a66597, SQSET, DCPCTR);
+ } else if (pipenum < R8A66597_MAX_NUM_PIPE) {
+ offset = get_pipectr_addr(pipenum);
+ r8a66597_bset(r8a66597, SQSET, offset);
+ } else {
+ dev_err(r8a66597_to_dev(r8a66597),
+ "unexpect pipe num(%d)\n", pipenum);
+ }
+}
+
+static u16 control_reg_sqmon(struct r8a66597 *r8a66597, u16 pipenum)
+{
+ unsigned long offset;
+
+ if (pipenum == 0) {
+ return r8a66597_read(r8a66597, DCPCTR) & SQMON;
+ } else if (pipenum < R8A66597_MAX_NUM_PIPE) {
+ offset = get_pipectr_addr(pipenum);
+ return r8a66597_read(r8a66597, offset) & SQMON;
+ } else {
+ dev_err(r8a66597_to_dev(r8a66597),
+ "unexpect pipe num(%d)\n", pipenum);
+ }
+
+ return 0;
+}
+
+static u16 save_usb_toggle(struct r8a66597 *r8a66597, u16 pipenum)
+{
+ return control_reg_sqmon(r8a66597, pipenum);
+}
+
+static void restore_usb_toggle(struct r8a66597 *r8a66597, u16 pipenum,
+ u16 toggle)
+{
+ if (toggle)
+ control_reg_sqset(r8a66597, pipenum);
+ else
+ control_reg_sqclr(r8a66597, pipenum);
}
static inline int get_buffer_size(struct r8a66597 *r8a66597, u16 pipenum)
@@ -222,18 +269,51 @@ static inline unsigned short mbw_value(struct r8a66597 *r8a66597)
return MBW_16;
}
+static void r8a66597_change_curpipe(struct r8a66597 *r8a66597, u16 pipenum,
+ u16 isel, u16 fifosel)
+{
+ u16 tmp, mask, loop;
+ int i = 0;
+
+ if (!pipenum) {
+ mask = ISEL | CURPIPE;
+ loop = isel;
+ } else {
+ mask = CURPIPE;
+ loop = pipenum;
+ }
+ r8a66597_mdfy(r8a66597, loop, mask, fifosel);
+
+ do {
+ tmp = r8a66597_read(r8a66597, fifosel);
+ if (i++ > 1000000) {
+ dev_err(r8a66597_to_dev(r8a66597),
+ "r8a66597: register%x, loop %x "
+ "is timeout\n", fifosel, loop);
+ break;
+ }
+ ndelay(1);
+ } while ((tmp & mask) != loop);
+}
+
static inline void pipe_change(struct r8a66597 *r8a66597, u16 pipenum)
{
struct r8a66597_ep *ep = r8a66597->pipenum2ep[pipenum];
if (ep->use_dma)
- return;
+ r8a66597_bclr(r8a66597, DREQE, ep->fifosel);
r8a66597_mdfy(r8a66597, pipenum, CURPIPE, ep->fifosel);
ndelay(450);
- r8a66597_bset(r8a66597, mbw_value(r8a66597), ep->fifosel);
+ if (r8a66597_is_sudmac(r8a66597) && ep->use_dma)
+ r8a66597_bclr(r8a66597, mbw_value(r8a66597), ep->fifosel);
+ else
+ r8a66597_bset(r8a66597, mbw_value(r8a66597), ep->fifosel);
+
+ if (ep->use_dma)
+ r8a66597_bset(r8a66597, DREQE, ep->fifosel);
}
static int pipe_buffer_setting(struct r8a66597 *r8a66597,
@@ -297,17 +377,18 @@ static void pipe_buffer_release(struct r8a66597 *r8a66597,
if (info->pipe == 0)
return;
- if (is_bulk_pipe(info->pipe))
+ if (is_bulk_pipe(info->pipe)) {
r8a66597->bulk--;
- else if (is_interrupt_pipe(info->pipe))
+ } else if (is_interrupt_pipe(info->pipe)) {
r8a66597->interrupt--;
- else if (is_isoc_pipe(info->pipe)) {
+ } else if (is_isoc_pipe(info->pipe)) {
r8a66597->isochronous--;
if (info->type == R8A66597_BULK)
r8a66597->bulk--;
- } else
- printk(KERN_ERR "ep_release: unexpect pipenum (%d)\n",
- info->pipe);
+ } else {
+ dev_err(r8a66597_to_dev(r8a66597),
+ "ep_release: unexpect pipenum (%d)\n", info->pipe);
+ }
}
static void pipe_initialize(struct r8a66597_ep *ep)
@@ -337,11 +418,17 @@ static void r8a66597_ep_setting(struct r8a66597 *r8a66597,
ep->fifoaddr = CFIFO;
ep->fifosel = CFIFOSEL;
ep->fifoctr = CFIFOCTR;
- ep->fifotrn = 0;
ep->pipectr = get_pipectr_addr(pipenum);
+ if (is_bulk_pipe(pipenum) || is_isoc_pipe(pipenum)) {
+ ep->pipetre = get_pipetre_addr(pipenum);
+ ep->pipetrn = get_pipetrn_addr(pipenum);
+ } else {
+ ep->pipetre = 0;
+ ep->pipetrn = 0;
+ }
ep->pipenum = pipenum;
- ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+ ep->ep.maxpacket = usb_endpoint_maxp(desc);
r8a66597->pipenum2ep[pipenum] = ep;
r8a66597->epaddr2ep[desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK]
= ep;
@@ -381,7 +468,8 @@ static int alloc_pipe_config(struct r8a66597_ep *ep,
case USB_ENDPOINT_XFER_BULK:
if (r8a66597->bulk >= R8A66597_MAX_NUM_BULK) {
if (r8a66597->isochronous >= R8A66597_MAX_NUM_ISOC) {
- printk(KERN_ERR "bulk pipe is insufficient\n");
+ dev_err(r8a66597_to_dev(r8a66597),
+ "bulk pipe is insufficient\n");
return -ENODEV;
} else {
info.pipe = R8A66597_BASE_PIPENUM_ISOC
@@ -397,7 +485,8 @@ static int alloc_pipe_config(struct r8a66597_ep *ep,
break;
case USB_ENDPOINT_XFER_INT:
if (r8a66597->interrupt >= R8A66597_MAX_NUM_INT) {
- printk(KERN_ERR "interrupt pipe is insufficient\n");
+ dev_err(r8a66597_to_dev(r8a66597),
+ "interrupt pipe is insufficient\n");
return -ENODEV;
}
info.pipe = R8A66597_BASE_PIPENUM_INT + r8a66597->interrupt;
@@ -406,7 +495,8 @@ static int alloc_pipe_config(struct r8a66597_ep *ep,
break;
case USB_ENDPOINT_XFER_ISOC:
if (r8a66597->isochronous >= R8A66597_MAX_NUM_ISOC) {
- printk(KERN_ERR "isochronous pipe is insufficient\n");
+ dev_err(r8a66597_to_dev(r8a66597),
+ "isochronous pipe is insufficient\n");
return -ENODEV;
}
info.pipe = R8A66597_BASE_PIPENUM_ISOC + r8a66597->isochronous;
@@ -414,13 +504,13 @@ static int alloc_pipe_config(struct r8a66597_ep *ep,
counter = &r8a66597->isochronous;
break;
default:
- printk(KERN_ERR "unexpect xfer type\n");
+ dev_err(r8a66597_to_dev(r8a66597), "unexpect xfer type\n");
return -EINVAL;
}
ep->type = info.type;
info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
- info.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+ info.maxpacket = usb_endpoint_maxp(desc);
info.interval = desc->bInterval;
if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
info.dir_in = 1;
@@ -429,7 +519,8 @@ static int alloc_pipe_config(struct r8a66597_ep *ep,
ret = pipe_buffer_setting(r8a66597, &info);
if (ret < 0) {
- printk(KERN_ERR "pipe_buffer_setting fail\n");
+ dev_err(r8a66597_to_dev(r8a66597),
+ "pipe_buffer_setting fail\n");
return ret;
}
@@ -495,6 +586,124 @@ static void start_ep0_write(struct r8a66597_ep *ep,
}
}
+static void disable_fifosel(struct r8a66597 *r8a66597, u16 pipenum,
+ u16 fifosel)
+{
+ u16 tmp;
+
+ tmp = r8a66597_read(r8a66597, fifosel) & CURPIPE;
+ if (tmp == pipenum)
+ r8a66597_change_curpipe(r8a66597, 0, 0, fifosel);
+}
+
+static void change_bfre_mode(struct r8a66597 *r8a66597, u16 pipenum,
+ int enable)
+{
+ struct r8a66597_ep *ep = r8a66597->pipenum2ep[pipenum];
+ u16 tmp, toggle;
+
+ /* check current BFRE bit */
+ r8a66597_write(r8a66597, pipenum, PIPESEL);
+ tmp = r8a66597_read(r8a66597, PIPECFG) & R8A66597_BFRE;
+ if ((enable && tmp) || (!enable && !tmp))
+ return;
+
+ /* change BFRE bit */
+ pipe_stop(r8a66597, pipenum);
+ disable_fifosel(r8a66597, pipenum, CFIFOSEL);
+ disable_fifosel(r8a66597, pipenum, D0FIFOSEL);
+ disable_fifosel(r8a66597, pipenum, D1FIFOSEL);
+
+ toggle = save_usb_toggle(r8a66597, pipenum);
+
+ r8a66597_write(r8a66597, pipenum, PIPESEL);
+ if (enable)
+ r8a66597_bset(r8a66597, R8A66597_BFRE, PIPECFG);
+ else
+ r8a66597_bclr(r8a66597, R8A66597_BFRE, PIPECFG);
+
+ /* initialize for internal BFRE flag */
+ r8a66597_bset(r8a66597, ACLRM, ep->pipectr);
+ r8a66597_bclr(r8a66597, ACLRM, ep->pipectr);
+
+ restore_usb_toggle(r8a66597, pipenum, toggle);
+}
+
+static int sudmac_alloc_channel(struct r8a66597 *r8a66597,
+ struct r8a66597_ep *ep,
+ struct r8a66597_request *req)
+{
+ struct r8a66597_dma *dma;
+
+ if (!r8a66597_is_sudmac(r8a66597))
+ return -ENODEV;
+
+ /* Check transfer type */
+ if (!is_bulk_pipe(ep->pipenum))
+ return -EIO;
+
+ if (r8a66597->dma.used)
+ return -EBUSY;
+
+ /* set SUDMAC parameters */
+ dma = &r8a66597->dma;
+ dma->used = 1;
+ if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+ dma->dir = 1;
+ } else {
+ dma->dir = 0;
+ change_bfre_mode(r8a66597, ep->pipenum, 1);
+ }
+
+ /* set r8a66597_ep paramters */
+ ep->use_dma = 1;
+ ep->dma = dma;
+ ep->fifoaddr = D0FIFO;
+ ep->fifosel = D0FIFOSEL;
+ ep->fifoctr = D0FIFOCTR;
+
+ /* dma mapping */
+ req->req.dma = dma_map_single(r8a66597_to_dev(ep->r8a66597),
+ req->req.buf, req->req.length,
+ dma->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+ return 0;
+}
+
+static void sudmac_free_channel(struct r8a66597 *r8a66597,
+ struct r8a66597_ep *ep,
+ struct r8a66597_request *req)
+{
+ if (!r8a66597_is_sudmac(r8a66597))
+ return;
+
+ dma_unmap_single(r8a66597_to_dev(ep->r8a66597),
+ req->req.dma, req->req.length,
+ ep->dma->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+ r8a66597_bclr(r8a66597, DREQE, ep->fifosel);
+ r8a66597_change_curpipe(r8a66597, 0, 0, ep->fifosel);
+
+ ep->dma->used = 0;
+ ep->use_dma = 0;
+ ep->fifoaddr = CFIFO;
+ ep->fifosel = CFIFOSEL;
+ ep->fifoctr = CFIFOCTR;
+}
+
+static void sudmac_start(struct r8a66597 *r8a66597, struct r8a66597_ep *ep,
+ struct r8a66597_request *req)
+{
+ BUG_ON(req->req.length == 0);
+
+ r8a66597_sudmac_write(r8a66597, LBA_WAIT, CH0CFG);
+ r8a66597_sudmac_write(r8a66597, req->req.dma, CH0BA);
+ r8a66597_sudmac_write(r8a66597, req->req.length, CH0BBC);
+ r8a66597_sudmac_write(r8a66597, CH0ENDE, DINTCTRL);
+
+ r8a66597_sudmac_write(r8a66597, DEN, CH0DEN);
+}
+
static void start_packet_write(struct r8a66597_ep *ep,
struct r8a66597_request *req)
{
@@ -505,11 +714,29 @@ static void start_packet_write(struct r8a66597_ep *ep,
disable_irq_empty(r8a66597, ep->pipenum);
pipe_start(r8a66597, ep->pipenum);
- tmp = r8a66597_read(r8a66597, ep->fifoctr);
- if (unlikely((tmp & FRDY) == 0))
- pipe_irq_enable(r8a66597, ep->pipenum);
- else
- irq_packet_write(ep, req);
+ if (req->req.length == 0) {
+ transfer_complete(ep, req, 0);
+ } else {
+ r8a66597_write(r8a66597, ~(1 << ep->pipenum), BRDYSTS);
+ if (sudmac_alloc_channel(r8a66597, ep, req) < 0) {
+ /* PIO mode */
+ pipe_change(r8a66597, ep->pipenum);
+ disable_irq_empty(r8a66597, ep->pipenum);
+ pipe_start(r8a66597, ep->pipenum);
+ tmp = r8a66597_read(r8a66597, ep->fifoctr);
+ if (unlikely((tmp & FRDY) == 0))
+ pipe_irq_enable(r8a66597, ep->pipenum);
+ else
+ irq_packet_write(ep, req);
+ } else {
+ /* DMA mode */
+ pipe_change(r8a66597, ep->pipenum);
+ disable_irq_nrdy(r8a66597, ep->pipenum);
+ pipe_start(r8a66597, ep->pipenum);
+ enable_irq_nrdy(r8a66597, ep->pipenum);
+ sudmac_start(r8a66597, ep, req);
+ }
+ }
}
static void start_packet_read(struct r8a66597_ep *ep,
@@ -524,17 +751,26 @@ static void start_packet_read(struct r8a66597_ep *ep,
pipe_start(r8a66597, pipenum);
pipe_irq_enable(r8a66597, pipenum);
} else {
- if (ep->use_dma) {
- r8a66597_bset(r8a66597, TRCLR, ep->fifosel);
- pipe_change(r8a66597, pipenum);
- r8a66597_bset(r8a66597, TRENB, ep->fifosel);
+ pipe_stop(r8a66597, pipenum);
+ if (ep->pipetre) {
+ enable_irq_nrdy(r8a66597, pipenum);
+ r8a66597_write(r8a66597, TRCLR, ep->pipetre);
r8a66597_write(r8a66597,
- (req->req.length + ep->ep.maxpacket - 1)
- / ep->ep.maxpacket,
- ep->fifotrn);
+ DIV_ROUND_UP(req->req.length, ep->ep.maxpacket),
+ ep->pipetrn);
+ r8a66597_bset(r8a66597, TRENB, ep->pipetre);
+ }
+
+ if (sudmac_alloc_channel(r8a66597, ep, req) < 0) {
+ /* PIO mode */
+ change_bfre_mode(r8a66597, ep->pipenum, 0);
+ pipe_start(r8a66597, pipenum); /* trigger once */
+ pipe_irq_enable(r8a66597, pipenum);
+ } else {
+ pipe_change(r8a66597, pipenum);
+ sudmac_start(r8a66597, ep, req);
+ pipe_start(r8a66597, pipenum); /* trigger once */
}
- pipe_start(r8a66597, pipenum); /* trigger once */
- pipe_irq_enable(r8a66597, pipenum);
}
}
@@ -564,7 +800,8 @@ static void start_ep0(struct r8a66597_ep *ep, struct r8a66597_request *req)
control_end(ep->r8a66597, 0);
break;
default:
- printk(KERN_ERR "start_ep0: unexpect ctsq(%x)\n", ctsq);
+ dev_err(r8a66597_to_dev(ep->r8a66597),
+ "start_ep0: unexpect ctsq(%x)\n", ctsq);
break;
}
}
@@ -690,6 +927,9 @@ __acquires(r8a66597->lock)
if (!list_empty(&ep->queue))
restart = 1;
+ if (ep->use_dma)
+ sudmac_free_channel(ep->r8a66597, ep, req);
+
spin_unlock(&ep->r8a66597->lock);
req->req.complete(&ep->ep, &req->req);
spin_lock(&ep->r8a66597->lock);
@@ -718,7 +958,8 @@ static void irq_ep0_write(struct r8a66597_ep *ep, struct r8a66597_request *req)
do {
tmp = r8a66597_read(r8a66597, ep->fifoctr);
if (i++ > 100000) {
- printk(KERN_ERR "pipe0 is busy. maybe cpu i/o bus"
+ dev_err(r8a66597_to_dev(r8a66597),
+ "pipe0 is busy. maybe cpu i/o bus "
"conflict. please power off this controller.");
return;
}
@@ -733,7 +974,7 @@ static void irq_ep0_write(struct r8a66597_ep *ep, struct r8a66597_request *req)
/* write fifo */
if (req->req.buf) {
if (size > 0)
- r8a66597_write_fifo(r8a66597, ep->fifoaddr, buf, size);
+ r8a66597_write_fifo(r8a66597, ep, buf, size);
if ((size == 0) || ((size % ep->ep.maxpacket) != 0))
r8a66597_bset(r8a66597, BVAL, ep->fifoctr);
}
@@ -769,7 +1010,8 @@ static void irq_packet_write(struct r8a66597_ep *ep,
if (unlikely((tmp & FRDY) == 0)) {
pipe_stop(r8a66597, pipenum);
pipe_irq_disable(r8a66597, pipenum);
- printk(KERN_ERR "write fifo not ready. pipnum=%d\n", pipenum);
+ dev_err(r8a66597_to_dev(r8a66597),
+ "write fifo not ready. pipnum=%d\n", pipenum);
return;
}
@@ -780,7 +1022,7 @@ static void irq_packet_write(struct r8a66597_ep *ep,
/* write fifo */
if (req->req.buf) {
- r8a66597_write_fifo(r8a66597, ep->fifoaddr, buf, size);
+ r8a66597_write_fifo(r8a66597, ep, buf, size);
if ((size == 0)
|| ((size % ep->ep.maxpacket) != 0)
|| ((bufsize != ep->ep.maxpacket)
@@ -819,7 +1061,7 @@ static void irq_packet_read(struct r8a66597_ep *ep,
req->req.status = -EPIPE;
pipe_stop(r8a66597, pipenum);
pipe_irq_disable(r8a66597, pipenum);
- printk(KERN_ERR "read fifo not ready");
+ dev_err(r8a66597_to_dev(r8a66597), "read fifo not ready");
return;
}
@@ -1095,7 +1337,7 @@ static void r8a66597_update_usb_speed(struct r8a66597 *r8a66597)
break;
default:
r8a66597->gadget.speed = USB_SPEED_UNKNOWN;
- printk(KERN_ERR "USB speed unknown\n");
+ dev_err(r8a66597_to_dev(r8a66597), "USB speed unknown\n");
}
}
@@ -1158,11 +1400,71 @@ __acquires(r8a66597->lock)
control_end(r8a66597, 0);
break;
default:
- printk(KERN_ERR "ctrl_stage: unexpect ctsq(%x)\n", ctsq);
+ dev_err(r8a66597_to_dev(r8a66597),
+ "ctrl_stage: unexpect ctsq(%x)\n", ctsq);
break;
}
}
+static void sudmac_finish(struct r8a66597 *r8a66597, struct r8a66597_ep *ep)
+{
+ u16 pipenum;
+ struct r8a66597_request *req;
+ u32 len;
+ int i = 0;
+
+ pipenum = ep->pipenum;
+ pipe_change(r8a66597, pipenum);
+
+ while (!(r8a66597_read(r8a66597, ep->fifoctr) & FRDY)) {
+ udelay(1);
+ if (unlikely(i++ >= 10000)) { /* timeout = 10 msec */
+ dev_err(r8a66597_to_dev(r8a66597),
+ "%s: FRDY was not set (%d)\n",
+ __func__, pipenum);
+ return;
+ }
+ }
+
+ r8a66597_bset(r8a66597, BCLR, ep->fifoctr);
+ req = get_request_from_ep(ep);
+
+ /* prepare parameters */
+ len = r8a66597_sudmac_read(r8a66597, CH0CBC);
+ req->req.actual += len;
+
+ /* clear */
+ r8a66597_sudmac_write(r8a66597, CH0STCLR, DSTSCLR);
+
+ /* check transfer finish */
+ if ((!req->req.zero && (req->req.actual == req->req.length))
+ || (len % ep->ep.maxpacket)) {
+ if (ep->dma->dir) {
+ disable_irq_ready(r8a66597, pipenum);
+ enable_irq_empty(r8a66597, pipenum);
+ } else {
+ /* Clear the interrupt flag for next transfer */
+ r8a66597_write(r8a66597, ~(1 << pipenum), BRDYSTS);
+ transfer_complete(ep, req, 0);
+ }
+ }
+}
+
+static void r8a66597_sudmac_irq(struct r8a66597 *r8a66597)
+{
+ u32 irqsts;
+ struct r8a66597_ep *ep;
+ u16 pipenum;
+
+ irqsts = r8a66597_sudmac_read(r8a66597, DINTSTS);
+ if (irqsts & CH0ENDS) {
+ r8a66597_sudmac_write(r8a66597, CH0ENDC, DINTSTSCLR);
+ pipenum = (r8a66597_read(r8a66597, D0FIFOSEL) & CURPIPE);
+ ep = r8a66597->pipenum2ep[pipenum];
+ sudmac_finish(r8a66597, ep);
+ }
+}
+
static irqreturn_t r8a66597_irq(int irq, void *_r8a66597)
{
struct r8a66597 *r8a66597 = _r8a66597;
@@ -1173,6 +1475,9 @@ static irqreturn_t r8a66597_irq(int irq, void *_r8a66597)
u16 savepipe;
u16 mask0;
+ if (r8a66597_is_sudmac(r8a66597))
+ r8a66597_sudmac_irq(r8a66597);
+
spin_lock(&r8a66597->lock);
intsts0 = r8a66597_read(r8a66597, INTSTS0);
@@ -1433,23 +1738,18 @@ static struct usb_ep_ops r8a66597_ep_ops = {
};
/*-------------------------------------------------------------------------*/
-static struct r8a66597 *the_controller;
-
-static int r8a66597_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *))
+static int r8a66597_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
- struct r8a66597 *r8a66597 = the_controller;
+ struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget);
int retval;
if (!driver
|| driver->speed != USB_SPEED_HIGH
- || !bind
|| !driver->setup)
return -EINVAL;
if (!r8a66597)
return -ENODEV;
- if (r8a66597->driver)
- return -EBUSY;
/* hook up the driver */
driver->driver.bus = NULL;
@@ -1458,14 +1758,8 @@ static int r8a66597_start(struct usb_gadget_driver *driver,
retval = device_add(&r8a66597->gadget.dev);
if (retval) {
- printk(KERN_ERR "device_add error (%d)\n", retval);
- goto error;
- }
-
- retval = bind(&r8a66597->gadget);
- if (retval) {
- printk(KERN_ERR "bind to driver error (%d)\n", retval);
- device_del(&r8a66597->gadget.dev);
+ dev_err(r8a66597_to_dev(r8a66597), "device_add error (%d)\n",
+ retval);
goto error;
}
@@ -1489,23 +1783,17 @@ error:
return retval;
}
-static int r8a66597_stop(struct usb_gadget_driver *driver)
+static int r8a66597_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
- struct r8a66597 *r8a66597 = the_controller;
+ struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget);
unsigned long flags;
- if (driver != r8a66597->driver || !driver->unbind)
- return -EINVAL;
-
spin_lock_irqsave(&r8a66597->lock, flags);
- if (r8a66597->gadget.speed != USB_SPEED_UNKNOWN)
- r8a66597_usb_disconnect(r8a66597);
r8a66597_bclr(r8a66597, VBSE, INTENB0);
disable_controller(r8a66597);
spin_unlock_irqrestore(&r8a66597->lock, flags);
- driver->unbind(&r8a66597->gadget);
-
device_del(&r8a66597->gadget.dev);
r8a66597->driver = NULL;
return 0;
@@ -1535,8 +1823,8 @@ static int r8a66597_pullup(struct usb_gadget *gadget, int is_on)
static struct usb_gadget_ops r8a66597_gadget_ops = {
.get_frame = r8a66597_get_frame,
- .start = r8a66597_start,
- .stop = r8a66597_stop,
+ .udc_start = r8a66597_start,
+ .udc_stop = r8a66597_stop,
.pullup = r8a66597_pullup,
};
@@ -1547,6 +1835,8 @@ static int __exit r8a66597_remove(struct platform_device *pdev)
usb_del_gadget_udc(&r8a66597->gadget);
del_timer_sync(&r8a66597->timer);
iounmap(r8a66597->reg);
+ if (r8a66597->pdata->sudmac)
+ iounmap(r8a66597->sudmac_reg);
free_irq(platform_get_irq(pdev, 0), r8a66597);
r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req);
#ifdef CONFIG_HAVE_CLK
@@ -1563,6 +1853,26 @@ static void nop_completion(struct usb_ep *ep, struct usb_request *r)
{
}
+static int __init r8a66597_sudmac_ioremap(struct r8a66597 *r8a66597,
+ struct platform_device *pdev)
+{
+ struct resource *res;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sudmac");
+ if (!res) {
+ dev_err(&pdev->dev, "platform_get_resource error(sudmac).\n");
+ return -ENODEV;
+ }
+
+ r8a66597->sudmac_reg = ioremap(res->start, resource_size(res));
+ if (r8a66597->sudmac_reg == NULL) {
+ dev_err(&pdev->dev, "ioremap error(sudmac).\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
static int __init r8a66597_probe(struct platform_device *pdev)
{
#ifdef CONFIG_HAVE_CLK
@@ -1579,7 +1889,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENODEV;
- printk(KERN_ERR "platform_get_resource error.\n");
+ dev_err(&pdev->dev, "platform_get_resource error.\n");
goto clean_up;
}
@@ -1589,14 +1899,14 @@ static int __init r8a66597_probe(struct platform_device *pdev)
if (irq < 0) {
ret = -ENODEV;
- printk(KERN_ERR "platform_get_irq error.\n");
+ dev_err(&pdev->dev, "platform_get_irq error.\n");
goto clean_up;
}
reg = ioremap(res->start, resource_size(res));
if (reg == NULL) {
ret = -ENOMEM;
- printk(KERN_ERR "ioremap error.\n");
+ dev_err(&pdev->dev, "ioremap error.\n");
goto clean_up;
}
@@ -1604,7 +1914,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)
r8a66597 = kzalloc(sizeof(struct r8a66597), GFP_KERNEL);
if (r8a66597 == NULL) {
ret = -ENOMEM;
- printk(KERN_ERR "kzalloc error\n");
+ dev_err(&pdev->dev, "kzalloc error\n");
goto clean_up;
}
@@ -1640,13 +1950,18 @@ static int __init r8a66597_probe(struct platform_device *pdev)
clk_enable(r8a66597->clk);
}
#endif
+ if (r8a66597->pdata->sudmac) {
+ ret = r8a66597_sudmac_ioremap(r8a66597, pdev);
+ if (ret < 0)
+ goto clean_up2;
+ }
disable_controller(r8a66597); /* make sure controller is disabled */
- ret = request_irq(irq, r8a66597_irq, IRQF_DISABLED | IRQF_SHARED,
+ ret = request_irq(irq, r8a66597_irq, IRQF_SHARED,
udc_name, r8a66597);
if (ret < 0) {
- printk(KERN_ERR "request_irq error (%d)\n", ret);
+ dev_err(&pdev->dev, "request_irq error (%d)\n", ret);
goto clean_up2;
}
@@ -1672,13 +1987,10 @@ static int __init r8a66597_probe(struct platform_device *pdev)
r8a66597->ep[0].fifoaddr = CFIFO;
r8a66597->ep[0].fifosel = CFIFOSEL;
r8a66597->ep[0].fifoctr = CFIFOCTR;
- r8a66597->ep[0].fifotrn = 0;
r8a66597->ep[0].pipectr = get_pipectr_addr(0);
r8a66597->pipenum2ep[0] = &r8a66597->ep[0];
r8a66597->epaddr2ep[0] = &r8a66597->ep[0];
- the_controller = r8a66597;
-
r8a66597->ep0_req = r8a66597_alloc_request(&r8a66597->ep[0].ep,
GFP_KERNEL);
if (r8a66597->ep0_req == NULL)
@@ -1705,6 +2017,8 @@ clean_up2:
#endif
clean_up:
if (r8a66597) {
+ if (r8a66597->sudmac_reg)
+ iounmap(r8a66597->sudmac_reg);
if (r8a66597->ep0_req)
r8a66597_free_request(&r8a66597->ep[0].ep,
r8a66597->ep0_req);
diff --git a/drivers/usb/gadget/r8a66597-udc.h b/drivers/usb/gadget/r8a66597-udc.h
index 503f766c23a7..8e3de61cd4b8 100644
--- a/drivers/usb/gadget/r8a66597-udc.h
+++ b/drivers/usb/gadget/r8a66597-udc.h
@@ -8,16 +8,6 @@
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#ifndef __R8A66597_H__
@@ -53,6 +43,7 @@
((pipenum >= R8A66597_BASE_PIPENUM_ISOC) && \
(pipenum < (R8A66597_BASE_PIPENUM_ISOC + R8A66597_MAX_NUM_ISOC)))
+#define r8a66597_is_sudmac(r8a66597) (r8a66597->pdata->sudmac)
struct r8a66597_pipe_info {
u16 pipe;
u16 epnum;
@@ -70,6 +61,7 @@ struct r8a66597_request {
struct r8a66597_ep {
struct usb_ep ep;
struct r8a66597 *r8a66597;
+ struct r8a66597_dma *dma;
struct list_head queue;
unsigned busy:1;
@@ -85,13 +77,20 @@ struct r8a66597_ep {
unsigned char fifoaddr;
unsigned char fifosel;
unsigned char fifoctr;
- unsigned char fifotrn;
unsigned char pipectr;
+ unsigned char pipetre;
+ unsigned char pipetrn;
+};
+
+struct r8a66597_dma {
+ unsigned used:1;
+ unsigned dir:1; /* 1 = IN(write), 0 = OUT(read) */
};
struct r8a66597 {
spinlock_t lock;
void __iomem *reg;
+ void __iomem *sudmac_reg;
#ifdef CONFIG_HAVE_CLK
struct clk *clk;
@@ -104,6 +103,7 @@ struct r8a66597 {
struct r8a66597_ep ep[R8A66597_MAX_NUM_PIPE];
struct r8a66597_ep *pipenum2ep[R8A66597_MAX_NUM_PIPE];
struct r8a66597_ep *epaddr2ep[16];
+ struct r8a66597_dma dma;
struct timer_list timer;
struct usb_request *ep0_req; /* for internal request */
@@ -124,6 +124,7 @@ struct r8a66597 {
#define gadget_to_r8a66597(_gadget) \
container_of(_gadget, struct r8a66597, gadget)
#define r8a66597_to_gadget(r8a66597) (&r8a66597->gadget)
+#define r8a66597_to_dev(r8a66597) (r8a66597->gadget.dev.parent)
static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset)
{
@@ -182,12 +183,27 @@ static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
iowrite16(val, r8a66597->reg + offset);
}
+static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
+ u16 val, u16 pat, unsigned long offset)
+{
+ u16 tmp;
+ tmp = r8a66597_read(r8a66597, offset);
+ tmp = tmp & (~pat);
+ tmp = tmp | val;
+ r8a66597_write(r8a66597, tmp, offset);
+}
+
+#define r8a66597_bclr(r8a66597, val, offset) \
+ r8a66597_mdfy(r8a66597, 0, val, offset)
+#define r8a66597_bset(r8a66597, val, offset) \
+ r8a66597_mdfy(r8a66597, val, 0, offset)
+
static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
- unsigned long offset,
+ struct r8a66597_ep *ep,
unsigned char *buf,
int len)
{
- void __iomem *fifoaddr = r8a66597->reg + offset;
+ void __iomem *fifoaddr = r8a66597->reg + ep->fifoaddr;
int adj = 0;
int i;
@@ -215,18 +231,12 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
adj = 0x01; /* 16-bit wide */
}
+ if (r8a66597->pdata->wr0_shorted_to_wr1)
+ r8a66597_bclr(r8a66597, MBW_16, ep->fifosel);
for (i = 0; i < len; i++)
iowrite8(buf[i], fifoaddr + adj - (i & adj));
-}
-
-static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
- u16 val, u16 pat, unsigned long offset)
-{
- u16 tmp;
- tmp = r8a66597_read(r8a66597, offset);
- tmp = tmp & (~pat);
- tmp = tmp | val;
- r8a66597_write(r8a66597, tmp, offset);
+ if (r8a66597->pdata->wr0_shorted_to_wr1)
+ r8a66597_bclr(r8a66597, MBW_16, ep->fifosel);
}
static inline u16 get_xtal_from_pdata(struct r8a66597_platdata *pdata)
@@ -251,12 +261,21 @@ static inline u16 get_xtal_from_pdata(struct r8a66597_platdata *pdata)
return clock;
}
-#define r8a66597_bclr(r8a66597, val, offset) \
- r8a66597_mdfy(r8a66597, 0, val, offset)
-#define r8a66597_bset(r8a66597, val, offset) \
- r8a66597_mdfy(r8a66597, val, 0, offset)
+static inline u32 r8a66597_sudmac_read(struct r8a66597 *r8a66597,
+ unsigned long offset)
+{
+ return ioread32(r8a66597->sudmac_reg + offset);
+}
+
+static inline void r8a66597_sudmac_write(struct r8a66597 *r8a66597, u32 val,
+ unsigned long offset)
+{
+ iowrite32(val, r8a66597->sudmac_reg + offset);
+}
#define get_pipectr_addr(pipenum) (PIPE1CTR + (pipenum - 1) * 2)
+#define get_pipetre_addr(pipenum) (PIPE1TRE + (pipenum - 1) * 4)
+#define get_pipetrn_addr(pipenum) (PIPE1TRN + (pipenum - 1) * 4)
#define enable_irq_ready(r8a66597, pipenum) \
enable_pipe_irq(r8a66597, pipenum, BRDYENB)
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
index 8bdee67ce09a..a552453dc946 100644
--- a/drivers/usb/gadget/s3c-hsotg.c
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -1951,30 +1951,26 @@ static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg)
case S3C_DSTS_EnumSpd_FS:
case S3C_DSTS_EnumSpd_FS48:
hsotg->gadget.speed = USB_SPEED_FULL;
- dev_info(hsotg->dev, "new device is full-speed\n");
-
ep0_mps = EP0_MPS_LIMIT;
ep_mps = 64;
break;
case S3C_DSTS_EnumSpd_HS:
- dev_info(hsotg->dev, "new device is high-speed\n");
hsotg->gadget.speed = USB_SPEED_HIGH;
-
ep0_mps = EP0_MPS_LIMIT;
ep_mps = 512;
break;
case S3C_DSTS_EnumSpd_LS:
hsotg->gadget.speed = USB_SPEED_LOW;
- dev_info(hsotg->dev, "new device is low-speed\n");
-
/* note, we don't actually support LS in this driver at the
* moment, and the documentation seems to imply that it isn't
* supported by the PHYs on some of the devices.
*/
break;
}
+ dev_info(hsotg->dev, "new device is %s\n",
+ usb_speed_string(hsotg->gadget.speed));
/* we should now know the maximum packet size for an
* endpoint, so set the endpoints to a default value. */
@@ -2297,7 +2293,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
return -EINVAL;
}
- mps = le16_to_cpu(desc->wMaxPacketSize);
+ mps = usb_endpoint_maxp(desc);
/* note, we handle this here instead of s3c_hsotg_set_ep_maxpacket */
diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c
index 3fa717c5f4bc..8d54f893cefe 100644
--- a/drivers/usb/gadget/s3c-hsudc.c
+++ b/drivers/usb/gadget/s3c-hsudc.c
@@ -26,6 +26,7 @@
#include <linux/clk.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
#include <linux/prefetch.h>
#include <mach/regs-s3c2443-clock.h>
@@ -137,6 +138,7 @@ struct s3c_hsudc {
struct usb_gadget_driver *driver;
struct device *dev;
struct s3c24xx_hsudc_platdata *pd;
+ struct otg_transceiver *transceiver;
spinlock_t lock;
void __iomem *regs;
struct resource *mem_rsrc;
@@ -759,11 +761,11 @@ static int s3c_hsudc_ep_enable(struct usb_ep *_ep,
if (!_ep || !desc || hsep->desc || _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT
|| hsep->bEndpointAddress != desc->bEndpointAddress
- || ep_maxpacket(hsep) < le16_to_cpu(desc->wMaxPacketSize))
+ || ep_maxpacket(hsep) < usb_endpoint_maxp(desc))
return -EINVAL;
if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
- && le16_to_cpu(desc->wMaxPacketSize) != ep_maxpacket(hsep))
+ && usb_endpoint_maxp(desc) != ep_maxpacket(hsep))
|| !desc->wMaxPacketSize)
return -ERANGE;
@@ -779,7 +781,7 @@ static int s3c_hsudc_ep_enable(struct usb_ep *_ep,
hsep->stopped = hsep->wedge = 0;
hsep->desc = desc;
- hsep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+ hsep->ep.maxpacket = usb_endpoint_maxp(desc);
s3c_hsudc_set_halt(_ep, 0);
__set_bit(ep_index(hsep), hsudc->regs + S3C_EIER);
@@ -1171,6 +1173,22 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver,
return ret;
}
+ /* connect to bus through transceiver */
+ if (hsudc->transceiver) {
+ ret = otg_set_peripheral(hsudc->transceiver, &hsudc->gadget);
+ if (ret) {
+ dev_err(hsudc->dev, "%s: can't bind to transceiver\n",
+ hsudc->gadget.name);
+ driver->unbind(&hsudc->gadget);
+
+ device_del(&hsudc->gadget.dev);
+
+ hsudc->driver = NULL;
+ hsudc->gadget.dev.driver = NULL;
+ return ret;
+ }
+ }
+
enable_irq(hsudc->irq);
dev_info(hsudc->dev, "bound driver %s\n", driver->driver.name);
@@ -1201,6 +1219,9 @@ static int s3c_hsudc_stop(struct usb_gadget_driver *driver)
s3c_hsudc_stop_activity(hsudc, driver);
spin_unlock_irqrestore(&hsudc->lock, flags);
+ if (hsudc->transceiver)
+ (void) otg_set_peripheral(hsudc->transceiver, NULL);
+
driver->unbind(&hsudc->gadget);
device_del(&hsudc->gadget.dev);
disable_irq(hsudc->irq);
@@ -1220,10 +1241,24 @@ static int s3c_hsudc_gadget_getframe(struct usb_gadget *gadget)
return s3c_hsudc_read_frameno(to_hsudc(gadget));
}
+static int s3c_hsudc_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+ struct s3c_hsudc *hsudc = the_controller;
+
+ if (!hsudc)
+ return -ENODEV;
+
+ if (hsudc->transceiver)
+ return otg_set_power(hsudc->transceiver, mA);
+
+ return -EOPNOTSUPP;
+}
+
static struct usb_gadget_ops s3c_hsudc_gadget_ops = {
.get_frame = s3c_hsudc_gadget_getframe,
.start = s3c_hsudc_start,
.stop = s3c_hsudc_stop,
+ .vbus_draw = s3c_hsudc_vbus_draw,
};
static int s3c_hsudc_probe(struct platform_device *pdev)
@@ -1247,6 +1282,8 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
hsudc->dev = dev;
hsudc->pd = pdev->dev.platform_data;
+ hsudc->transceiver = otg_get_transceiver();
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "unable to obtain driver resource data\n");
@@ -1269,19 +1306,6 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
goto err_remap;
}
- ret = platform_get_irq(pdev, 0);
- if (ret < 0) {
- dev_err(dev, "unable to obtain IRQ number\n");
- goto err_irq;
- }
- hsudc->irq = ret;
-
- ret = request_irq(hsudc->irq, s3c_hsudc_irq, 0, driver_name, hsudc);
- if (ret < 0) {
- dev_err(dev, "irq request failed\n");
- goto err_irq;
- }
-
spin_lock_init(&hsudc->lock);
device_initialize(&hsudc->gadget.dev);
@@ -1299,6 +1323,19 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
s3c_hsudc_setup_ep(hsudc);
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0) {
+ dev_err(dev, "unable to obtain IRQ number\n");
+ goto err_irq;
+ }
+ hsudc->irq = ret;
+
+ ret = request_irq(hsudc->irq, s3c_hsudc_irq, 0, driver_name, hsudc);
+ if (ret < 0) {
+ dev_err(dev, "irq request failed\n");
+ goto err_irq;
+ }
+
hsudc->uclk = clk_get(&pdev->dev, "usb-device");
if (IS_ERR(hsudc->uclk)) {
dev_err(dev, "failed to find usb-device clock source\n");
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index 8d31848aab09..b8643771fa80 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -10,16 +10,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
#include <linux/module.h>
@@ -1082,7 +1072,7 @@ static int s3c2410_udc_ep_enable(struct usb_ep *_ep,
if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
return -ESHUTDOWN;
- max = le16_to_cpu(desc->wMaxPacketSize) & 0x1fff;
+ max = usb_endpoint_maxp(desc) & 0x1fff;
local_irq_save (flags);
_ep->maxpacket = max & 0x7ff;
@@ -1903,7 +1893,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
/* irq setup after old hardware state is cleaned up */
retval = request_irq(IRQ_USBD, s3c2410_udc_irq,
- IRQF_DISABLED, gadget_name, udc);
+ 0, gadget_name, udc);
if (retval != 0) {
dev_err(dev, "cannot get irq %i, err %d\n", IRQ_USBD, retval);
@@ -1927,7 +1917,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
}
retval = request_irq(irq, s3c2410_udc_vbus_irq,
- IRQF_DISABLED | IRQF_TRIGGER_RISING
+ IRQF_TRIGGER_RISING
| IRQF_TRIGGER_FALLING | IRQF_SHARED,
gadget_name, udc);
diff --git a/drivers/usb/gadget/s3c2410_udc.h b/drivers/usb/gadget/s3c2410_udc.h
index 9e0bece4f241..a48f619cb1cc 100644
--- a/drivers/usb/gadget/s3c2410_udc.h
+++ b/drivers/usb/gadget/s3c2410_udc.h
@@ -9,16 +9,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
#ifndef _S3C2410_UDC_H
diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
index d3dd227a2bfc..c7f291a331df 100644
--- a/drivers/usb/gadget/storage_common.c
+++ b/drivers/usb/gadget/storage_common.c
@@ -9,15 +9,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -52,6 +43,12 @@
* characters rather then a pointer to void.
*/
+/*
+ * When USB_GADGET_DEBUG_FILES is defined the module param num_buffers
+ * sets the number of pipeline buffers (length of the fsg_buffhd array).
+ * The valid range of num_buffers is: num >= 2 && num <= 4.
+ */
+
#include <linux/usb/storage.h>
#include <scsi/scsi.h>
@@ -247,6 +244,8 @@ struct fsg_lun {
u32 sense_data_info;
u32 unit_attention_data;
+ unsigned int blkbits; /* Bits of logical block size of bound block device */
+ unsigned int blksize; /* logical block size of bound block device */
struct device dev;
};
@@ -262,8 +261,31 @@ static struct fsg_lun *fsg_lun_from_dev(struct device *dev)
#define EP0_BUFSIZE 256
#define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */
-/* Number of buffers we will use. 2 is enough for double-buffering */
-#define FSG_NUM_BUFFERS 2
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+
+static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS;
+module_param_named(num_buffers, fsg_num_buffers, uint, S_IRUGO);
+MODULE_PARM_DESC(num_buffers, "Number of pipeline buffers");
+
+#else
+
+/*
+ * Number of buffers we will use.
+ * 2 is usually enough for good buffering pipeline
+ */
+#define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
+
+#endif /* CONFIG_USB_DEBUG */
+
+/* check if fsg_num_buffers is within a valid range */
+static inline int fsg_num_buffers_validate(void)
+{
+ if (fsg_num_buffers >= 2 && fsg_num_buffers <= 4)
+ return 0;
+ pr_err("fsg_num_buffers %u is out of range (%d to %d)\n",
+ fsg_num_buffers, 2 ,4);
+ return -EINVAL;
+}
/* Default size of buffer length. */
#define FSG_BUFLEN ((u32)16384)
@@ -493,12 +515,128 @@ static struct usb_descriptor_header *fsg_hs_function[] = {
NULL,
};
+static struct usb_endpoint_descriptor
+fsg_ss_bulk_in_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = {
+ .bLength = sizeof(fsg_ss_bulk_in_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+
+ /*.bMaxBurst = DYNAMIC, */
+};
+
+static struct usb_endpoint_descriptor
+fsg_ss_bulk_out_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = {
+ .bLength = sizeof(fsg_ss_bulk_in_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+
+ /*.bMaxBurst = DYNAMIC, */
+};
+
+#ifndef FSG_NO_INTR_EP
+
+static struct usb_endpoint_descriptor
+fsg_ss_intr_in_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = cpu_to_le16(2),
+ .bInterval = 9, /* 2**(9-1) = 256 uframes -> 32 ms */
+};
+
+static struct usb_ss_ep_comp_descriptor fsg_ss_intr_in_comp_desc = {
+ .bLength = sizeof(fsg_ss_bulk_in_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+
+ .wBytesPerInterval = cpu_to_le16(2),
+};
+
+#ifndef FSG_NO_OTG
+# define FSG_SS_FUNCTION_PRE_EP_ENTRIES 2
+#else
+# define FSG_SS_FUNCTION_PRE_EP_ENTRIES 1
+#endif
+
+#endif
+
+static __maybe_unused struct usb_ext_cap_descriptor fsg_ext_cap_desc = {
+ .bLength = USB_DT_USB_EXT_CAP_SIZE,
+ .bDescriptorType = USB_DT_DEVICE_CAPABILITY,
+ .bDevCapabilityType = USB_CAP_TYPE_EXT,
+
+ .bmAttributes = cpu_to_le32(USB_LPM_SUPPORT),
+};
+
+static __maybe_unused struct usb_ss_cap_descriptor fsg_ss_cap_desc = {
+ .bLength = USB_DT_USB_SS_CAP_SIZE,
+ .bDescriptorType = USB_DT_DEVICE_CAPABILITY,
+ .bDevCapabilityType = USB_SS_CAP_TYPE,
+
+ /* .bmAttributes = LTM is not supported yet */
+
+ .wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION
+ | USB_FULL_SPEED_OPERATION
+ | USB_HIGH_SPEED_OPERATION
+ | USB_5GBPS_OPERATION),
+ .bFunctionalitySupport = USB_LOW_SPEED_OPERATION,
+ .bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT,
+ .bU2DevExitLat = USB_DEFAULT_U2_DEV_EXIT_LAT,
+};
+
+static __maybe_unused struct usb_bos_descriptor fsg_bos_desc = {
+ .bLength = USB_DT_BOS_SIZE,
+ .bDescriptorType = USB_DT_BOS,
+
+ .wTotalLength = USB_DT_BOS_SIZE
+ + USB_DT_USB_EXT_CAP_SIZE
+ + USB_DT_USB_SS_CAP_SIZE,
+
+ .bNumDeviceCaps = 2,
+};
+
+static struct usb_descriptor_header *fsg_ss_function[] = {
+#ifndef FSG_NO_OTG
+ (struct usb_descriptor_header *) &fsg_otg_desc,
+#endif
+ (struct usb_descriptor_header *) &fsg_intf_desc,
+ (struct usb_descriptor_header *) &fsg_ss_bulk_in_desc,
+ (struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc,
+ (struct usb_descriptor_header *) &fsg_ss_bulk_out_desc,
+ (struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc,
+#ifndef FSG_NO_INTR_EP
+ (struct usb_descriptor_header *) &fsg_ss_intr_in_desc,
+ (struct usb_descriptor_header *) &fsg_ss_intr_in_comp_desc,
+#endif
+ NULL,
+};
+
/* Maxpacket and other transfer characteristics vary by speed. */
static __maybe_unused struct usb_endpoint_descriptor *
fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
- struct usb_endpoint_descriptor *hs)
+ struct usb_endpoint_descriptor *hs,
+ struct usb_endpoint_descriptor *ss)
{
- if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+ if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
+ return ss;
+ else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
return hs;
return fs;
}
@@ -580,13 +718,24 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
rc = (int) size;
goto out;
}
- num_sectors = size >> 9; /* File size in 512-byte blocks */
+
+ if (curlun->cdrom) {
+ curlun->blksize = 2048;
+ curlun->blkbits = 11;
+ } else if (inode->i_bdev) {
+ curlun->blksize = bdev_logical_block_size(inode->i_bdev);
+ curlun->blkbits = blksize_bits(curlun->blksize);
+ } else {
+ curlun->blksize = 512;
+ curlun->blkbits = 9;
+ }
+
+ num_sectors = size >> curlun->blkbits; /* File size in logic-block-size blocks */
min_sectors = 1;
if (curlun->cdrom) {
- num_sectors &= ~3; /* Reduce to a multiple of 2048 */
- min_sectors = 300*4; /* Smallest track is 300 frames */
- if (num_sectors >= 256*60*75*4) {
- num_sectors = (256*60*75 - 1) * 4;
+ min_sectors = 300; /* Smallest track is 300 frames */
+ if (num_sectors >= 256*60*75) {
+ num_sectors = 256*60*75 - 1;
LINFO(curlun, "file too big: %s\n", filename);
LINFO(curlun, "using only first %d blocks\n",
(int) num_sectors);
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index dfed4c1d96c0..29c854bbca44 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -9,15 +9,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* #define VERBOSE_DEBUG */
diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index c966440ddd70..8012357e98aa 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -9,15 +9,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __U_ETHER_H
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index a8aa46962d81..3a4a664bab44 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -552,9 +552,8 @@ recycle:
/* Push from tty to ldisc; without low_latency set this is handled by
* a workqueue, so we won't get callbacks and can hold port_lock
*/
- if (tty && do_push) {
+ if (tty && do_push)
tty_flip_buffer_push(tty);
- }
/* We want our data queue to become empty ASAP, keeping data
diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
index 05ba47214361..022baeca7c94 100644
--- a/drivers/usb/gadget/udc-core.c
+++ b/drivers/usb/gadget/udc-core.c
@@ -356,7 +356,7 @@ static DEVICE_ATTR(srp, S_IWUSR, NULL, usb_udc_srp_store);
static ssize_t usb_udc_softconn_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t n)
{
- struct usb_udc *udc = dev_get_drvdata(dev);
+ struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
if (sysfs_streq(buf, "connect")) {
usb_gadget_connect(udc->gadget);
@@ -375,23 +375,8 @@ static ssize_t usb_udc_speed_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
- struct usb_gadget *gadget = udc->gadget;
-
- switch (gadget->speed) {
- case USB_SPEED_LOW:
- return snprintf(buf, PAGE_SIZE, "low-speed\n");
- case USB_SPEED_FULL:
- return snprintf(buf, PAGE_SIZE, "full-speed\n");
- case USB_SPEED_HIGH:
- return snprintf(buf, PAGE_SIZE, "high-speed\n");
- case USB_SPEED_WIRELESS:
- return snprintf(buf, PAGE_SIZE, "wireless\n");
- case USB_SPEED_SUPER:
- return snprintf(buf, PAGE_SIZE, "super-speed\n");
- case USB_SPEED_UNKNOWN: /* FALLTHROUGH */
- default:
- return snprintf(buf, PAGE_SIZE, "UNKNOWN\n");
- }
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ usb_speed_string(udc->gadget->speed));
}
static DEVICE_ATTR(speed, S_IRUSR, usb_udc_speed_show, NULL);
diff --git a/drivers/usb/gadget/uvc.h b/drivers/usb/gadget/uvc.h
index 5b7919460fd2..bc78c606c12b 100644
--- a/drivers/usb/gadget/uvc.h
+++ b/drivers/usb/gadget/uvc.h
@@ -8,7 +8,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
*/
#ifndef _UVC_GADGET_H_
@@ -56,6 +55,7 @@ struct uvc_event
#include <linux/usb.h> /* For usb_endpoint_* */
#include <linux/usb/gadget.h>
#include <linux/videodev2.h>
+#include <linux/version.h>
#include <media/v4l2-fh.h>
#include "uvc_queue.h"
diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c
index aa0ad34e0f1f..d776adb2da67 100644
--- a/drivers/usb/gadget/uvc_queue.c
+++ b/drivers/usb/gadget/uvc_queue.c
@@ -8,7 +8,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/usb/gadget/uvc_v4l2.c b/drivers/usb/gadget/uvc_v4l2.c
index 52f8f9e513af..f6e083b50191 100644
--- a/drivers/usb/gadget/uvc_v4l2.c
+++ b/drivers/usb/gadget/uvc_v4l2.c
@@ -8,7 +8,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
*/
#include <linux/kernel.h>
@@ -16,7 +15,6 @@
#include <linux/errno.h>
#include <linux/list.h>
#include <linux/mutex.h>
-#include <linux/version.h>
#include <linux/videodev2.h>
#include <linux/vmalloc.h>
#include <linux/wait.h>
diff --git a/drivers/usb/gadget/uvc_video.c b/drivers/usb/gadget/uvc_video.c
index b08f35438d70..b0e53a8ea4f7 100644
--- a/drivers/usb/gadget/uvc_video.c
+++ b/drivers/usb/gadget/uvc_video.c
@@ -8,7 +8,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/usb/gadget/webcam.c b/drivers/usb/gadget/webcam.c
index df6882de50bf..668fe128f2ef 100644
--- a/drivers/usb/gadget/webcam.c
+++ b/drivers/usb/gadget/webcam.c
@@ -8,8 +8,8 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
*/
+
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/usb/video.h>
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 00e2fd2d4791..20697cc132d1 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -8,15 +8,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index ab085f12d570..060e0e2b1ae6 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -19,7 +19,7 @@ config USB_C67X00_HCD
config USB_XHCI_HCD
tristate "xHCI HCD (USB 3.0) support (EXPERIMENTAL)"
- depends on USB && PCI && EXPERIMENTAL
+ depends on USB && USB_ARCH_HAS_XHCI && EXPERIMENTAL
---help---
The eXtensible Host Controller Interface (xHCI) is standard for USB 3.0
"SuperSpeed" host controller hardware.
@@ -515,6 +515,19 @@ config USB_R8A66597_HCD
To compile this driver as a module, choose M here: the
module will be called r8a66597-hcd.
+config USB_RENESAS_USBHS_HCD
+ tristate "Renesas USBHS HCD support"
+ depends on USB
+ depends on USB_RENESAS_USBHS
+ help
+ The Renesas USBHS is a USB 2.0 host and peripheral controller.
+
+ Enable this option if your board has this chip, and you want
+ to use it as a host controller. If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called renesas-usbhs.
+
config USB_WHCI_HCD
tristate "Wireless USB Host Controller Interface (WHCI) driver (EXPERIMENTAL)"
depends on EXPERIMENTAL
@@ -544,11 +557,11 @@ config USB_HWA_HCD
will be called "hwa-hc".
config USB_IMX21_HCD
- tristate "iMX21 HCD support"
- depends on USB && ARM && MACH_MX21
+ tristate "i.MX21 HCD support"
+ depends on USB && ARM && ARCH_MXC
help
This driver enables support for the on-chip USB host in the
- iMX21 processor.
+ i.MX21 processor.
To compile this driver as a module, choose M here: the
module will be called "imx21-hcd".
@@ -578,3 +591,10 @@ config USB_OCTEON_OHCI
config USB_OCTEON2_COMMON
bool
default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI
+
+config USB_PXA168_EHCI
+ bool "Marvell PXA168 on-chip EHCI HCD support"
+ depends on USB_EHCI_HCD && ARCH_MMP
+ help
+ Enable support for Marvell PXA168 SoC's on-chip EHCI
+ host controller
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 624a362f2fee..ed48a5d79e16 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -11,8 +11,9 @@ fhci-y += fhci-mem.o fhci-tds.o fhci-sched.o
fhci-$(CONFIG_FHCI_DEBUG) += fhci-dbg.o
-xhci-hcd-y := xhci.o xhci-mem.o xhci-pci.o
+xhci-hcd-y := xhci.o xhci-mem.o
xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o
+xhci-hcd-$(CONFIG_PCI) += xhci-pci.o
obj-$(CONFIG_USB_WHCI_HCD) += whci/
diff --git a/drivers/usb/host/ehci-ath79.c b/drivers/usb/host/ehci-ath79.c
index 4d2e88d04dab..afb6743cf094 100644
--- a/drivers/usb/host/ehci-ath79.c
+++ b/drivers/usb/host/ehci-ath79.c
@@ -163,7 +163,7 @@ static int ehci_ath79_probe(struct platform_device *pdev)
goto err_release_region;
}
- ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret)
goto err_iounmap;
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
index 42ae57409908..65719e8d24e4 100644
--- a/drivers/usb/host/ehci-au1xxx.c
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -181,7 +181,7 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
ehci->hcs_params = readl(&ehci->caps->hcs_params);
ret = usb_add_hcd(hcd, pdev->resource[1].start,
- IRQF_DISABLED | IRQF_SHARED);
+ IRQF_SHARED);
if (ret == 0) {
platform_set_drvdata(pdev, hcd);
return ret;
@@ -293,7 +293,7 @@ static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
/* here we "know" root ports should always stay powered */
ehci_port_power(ehci, 1);
- hcd->state = HC_STATE_SUSPENDED;
+ ehci->rh_state = EHCI_RH_SUSPENDED;
return 0;
}
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 40a844c1dbb4..d6d74d2e09f4 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -697,6 +697,19 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
}
#undef DBG_SCHED_LIMIT
+static const char *rh_state_string(struct ehci_hcd *ehci)
+{
+ switch (ehci->rh_state) {
+ case EHCI_RH_HALTED:
+ return "halted";
+ case EHCI_RH_SUSPENDED:
+ return "suspended";
+ case EHCI_RH_RUNNING:
+ return "running";
+ }
+ return "?";
+}
+
static ssize_t fill_registers_buffer(struct debug_buffer *buf)
{
struct usb_hcd *hcd;
@@ -730,11 +743,11 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
temp = scnprintf (next, size,
"bus %s, device %s\n"
"%s\n"
- "EHCI %x.%02x, hcd state %d\n",
+ "EHCI %x.%02x, rh state %s\n",
hcd->self.controller->bus->name,
dev_name(hcd->self.controller),
hcd->product_desc,
- i >> 8, i & 0x0ff, hcd->state);
+ i >> 8, i & 0x0ff, rh_state_string(ehci));
size -= temp;
next += temp;
@@ -808,7 +821,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
next += temp;
temp = scnprintf (next, size, "uframe %04x\n",
- ehci_readl(ehci, &ehci->regs->frame_index));
+ ehci_read_frame_index(ehci));
size -= temp;
next += temp;
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 34a3140d1e5f..e90344a17631 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -134,7 +134,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
/* Don't need to set host mode here. It will be done by tdi_reset() */
- retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (retval != 0)
goto err4;
@@ -392,7 +392,7 @@ static int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
dev_dbg(dev, "suspending...\n");
- hcd->state = HC_STATE_SUSPENDED;
+ ehci->rh_state = EHCI_RH_SUSPENDED;
dev->power.power_state = PMSG_SUSPEND;
/* ignore non-host interrupts */
@@ -481,7 +481,7 @@ static int ehci_fsl_mpc512x_drv_resume(struct device *dev)
ehci_writel(ehci, pdata->pm_portsc, &ehci->regs->port_status[0]);
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
- hcd->state = HC_STATE_RUNNING;
+ ehci->rh_state = EHCI_RH_RUNNING;
dev->power.power_state = PMSG_ON;
tmp = ehci_readl(ehci, &ehci->regs->command);
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index f72ae0b6ee7f..59e81615e09c 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -95,7 +95,7 @@ static const char hcd_name [] = "ehci_hcd";
#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
#define EHCI_SHRINK_JIFFIES (DIV_ROUND_UP(HZ, 200) + 1)
- /* 200-ms async qh unlink delay */
+ /* 5-ms async qh unlink delay */
/* Initial IRQ latency: faster than hw default */
static int log2_irq_thresh = 0; // 0 to 6
@@ -238,7 +238,7 @@ static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,
error = handshake(ehci, ptr, mask, done, usec);
if (error) {
ehci_halt(ehci);
- ehci_to_hcd(ehci)->state = HC_STATE_HALT;
+ ehci->rh_state = EHCI_RH_HALTED;
ehci_err(ehci, "force halt; handshake %p %08x %08x -> %d\n",
ptr, mask, done, error);
}
@@ -278,7 +278,7 @@ static int ehci_reset (struct ehci_hcd *ehci)
command |= CMD_RESET;
dbg_cmd (ehci, "reset", command);
ehci_writel(ehci, command, &ehci->regs->command);
- ehci_to_hcd(ehci)->state = HC_STATE_HALT;
+ ehci->rh_state = EHCI_RH_HALTED;
ehci->next_statechange = jiffies;
retval = handshake (ehci, &ehci->regs->command,
CMD_RESET, 0, 250 * 1000);
@@ -307,7 +307,7 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
u32 temp;
#ifdef DEBUG
- if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
+ if (ehci->rh_state != EHCI_RH_RUNNING)
BUG ();
#endif
@@ -356,7 +356,7 @@ static void ehci_iaa_watchdog(unsigned long param)
*/
if (ehci->reclaim
&& !timer_pending(&ehci->iaa_watchdog)
- && HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
+ && ehci->rh_state == EHCI_RH_RUNNING) {
u32 cmd, status;
/* If we get here, IAA is *REALLY* late. It's barely
@@ -496,7 +496,7 @@ static void ehci_work (struct ehci_hcd *ehci)
* misplace IRQs, and should let us run completely without IRQs.
* such lossage has been observed on both VT6202 and VT8235.
*/
- if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state) &&
+ if (ehci->rh_state == EHCI_RH_RUNNING &&
(ehci->async->qh_next.ptr != NULL ||
ehci->periodic_sched != 0))
timer_action (ehci, TIMER_IO_WATCHDOG);
@@ -516,7 +516,7 @@ static void ehci_stop (struct usb_hcd *hcd)
del_timer_sync(&ehci->iaa_watchdog);
spin_lock_irq(&ehci->lock);
- if (HC_IS_RUNNING (hcd->state))
+ if (ehci->rh_state == EHCI_RH_RUNNING)
ehci_quiesce (ehci);
ehci_silence_controller(ehci);
@@ -741,7 +741,7 @@ static int ehci_run (struct usb_hcd *hcd)
* be started before the port switching actions could complete.
*/
down_write(&ehci_cf_port_reset_rwsem);
- hcd->state = HC_STATE_RUNNING;
+ ehci->rh_state = EHCI_RH_RUNNING;
ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
msleep(5);
@@ -768,6 +768,35 @@ static int ehci_run (struct usb_hcd *hcd)
return 0;
}
+static int __maybe_unused ehci_setup (struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int retval;
+
+ ehci->regs = (void __iomem *)ehci->caps +
+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
+ dbg_hcs_params(ehci, "reset");
+ dbg_hcc_params(ehci, "reset");
+
+ /* cache this readonly data; minimize chip reads */
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+ ehci->sbrn = HCD_USB2;
+
+ retval = ehci_halt(ehci);
+ if (retval)
+ return retval;
+
+ /* data structure init */
+ retval = ehci_init(hcd);
+ if (retval)
+ return retval;
+
+ ehci_reset(ehci);
+
+ return 0;
+}
+
/*-------------------------------------------------------------------------*/
static irqreturn_t ehci_irq (struct usb_hcd *hcd)
@@ -788,7 +817,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* Shared IRQ? */
masked_status = status & INTR_MASK;
- if (!masked_status || unlikely(hcd->state == HC_STATE_HALT)) {
+ if (!masked_status || unlikely(ehci->rh_state == EHCI_RH_HALTED)) {
spin_unlock(&ehci->lock);
return IRQ_NONE;
}
@@ -952,7 +981,7 @@ static int ehci_urb_enqueue (
static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
/* failfast */
- if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state) && ehci->reclaim)
+ if (ehci->rh_state != EHCI_RH_RUNNING && ehci->reclaim)
end_unlink_async(ehci);
/* If the QH isn't linked then there's nothing we can do
@@ -1079,7 +1108,7 @@ rescan:
goto idle_timeout;
}
- if (!HC_IS_RUNNING (hcd->state))
+ if (ehci->rh_state != EHCI_RH_RUNNING)
qh->qh_state = QH_STATE_IDLE;
switch (qh->qh_state) {
case QH_STATE_LINKED:
@@ -1166,8 +1195,7 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
static int ehci_get_frame (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
- return (ehci_readl(ehci, &ehci->regs->frame_index) >> 3) %
- ehci->periodic_size;
+ return (ehci_read_frame_index(ehci) >> 3) % ehci->periodic_size;
}
/*-------------------------------------------------------------------------*/
@@ -1291,6 +1319,16 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_grlib_driver
#endif
+#ifdef CONFIG_USB_PXA168_EHCI
+#include "ehci-pxa168.c"
+#define PLATFORM_DRIVER ehci_pxa168_driver
+#endif
+
+#ifdef CONFIG_NLM_XLR
+#include "ehci-xls.c"
+#define PLATFORM_DRIVER ehci_xls_driver
+#endif
+
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
!defined(XILINX_OF_PLATFORM_DRIVER)
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index e051b30c1847..77bbb2357e47 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -236,10 +236,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
}
/* stop schedules, clean any completed work */
- if (HC_IS_RUNNING(hcd->state)) {
+ if (ehci->rh_state == EHCI_RH_RUNNING)
ehci_quiesce (ehci);
- hcd->state = HC_STATE_QUIESCING;
- }
ehci->command = ehci_readl(ehci, &ehci->regs->command);
ehci_work(ehci);
@@ -313,7 +311,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
/* turn off now-idle HC */
ehci_halt (ehci);
- hcd->state = HC_STATE_SUSPENDED;
+ ehci->rh_state = EHCI_RH_SUSPENDED;
if (ehci->reclaim)
end_unlink_async(ehci);
@@ -343,7 +341,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
u32 temp;
u32 power_okay;
int i;
- u8 resume_needed = 0;
+ unsigned long resume_needed = 0;
if (time_before (jiffies, ehci->next_statechange))
msleep(5);
@@ -382,6 +380,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
/* restore CMD_RUN, framelist size, and irq threshold */
ehci_writel(ehci, ehci->command, &ehci->regs->command);
+ ehci->rh_state = EHCI_RH_RUNNING;
/* Some controller/firmware combinations need a delay during which
* they set up the port statuses. See Bugzilla #8190. */
@@ -416,7 +415,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
if (test_bit(i, &ehci->bus_suspended) &&
(temp & PORT_SUSPEND)) {
temp |= PORT_RESUME;
- resume_needed = 1;
+ set_bit(i, &resume_needed);
}
ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
}
@@ -431,8 +430,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
i = HCS_N_PORTS (ehci->hcs_params);
while (i--) {
temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
- if (test_bit(i, &ehci->bus_suspended) &&
- (temp & PORT_SUSPEND)) {
+ if (test_bit(i, &resume_needed)) {
temp &= ~(PORT_RWC_BITS | PORT_RESUME);
ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
ehci_vdbg (ehci, "resumed port %d\n", i + 1);
@@ -452,7 +450,6 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
}
ehci->next_statechange = jiffies + msecs_to_jiffies(5);
- hcd->state = HC_STATE_RUNNING;
/* Now we can safely re-enable irqs */
ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
@@ -564,7 +561,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
u32 ppcd = 0;
/* if !USB_SUSPEND, root hub timers won't get shut down ... */
- if (!HC_IS_RUNNING(hcd->state))
+ if (ehci->rh_state != EHCI_RH_RUNNING)
return 0;
/* init status to no-changes */
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c
index 555a73c864b5..55978fcfa4b2 100644
--- a/drivers/usb/host/ehci-mxc.c
+++ b/drivers/usb/host/ehci-mxc.c
@@ -236,7 +236,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
priv->hcd = hcd;
platform_set_drvdata(pdev, priv);
- ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret)
goto err_add;
diff --git a/drivers/usb/host/ehci-octeon.c b/drivers/usb/host/ehci-octeon.c
index c3ba3ed5f3a6..ba1f51361134 100644
--- a/drivers/usb/host/ehci-octeon.c
+++ b/drivers/usb/host/ehci-octeon.c
@@ -155,7 +155,7 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev)
/* cache this readonly data; minimize chip reads */
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
- ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret) {
dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
goto err3;
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index 45240321ca09..e39b0297bad1 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -228,7 +228,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
/* cache this readonly data; minimize chip reads */
omap_ehci->hcs_params = readl(&omap_ehci->caps->hcs_params);
- ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret) {
dev_err(dev, "failed to add hcd with err %d\n", ret);
goto err_add_hcd;
diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c
index 395bdb0248d5..a68a2a5c4b83 100644
--- a/drivers/usb/host/ehci-orion.c
+++ b/drivers/usb/host/ehci-orion.c
@@ -277,7 +277,7 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev)
printk(KERN_WARNING "Orion ehci -USB phy version isn't supported.\n");
}
- err = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_DISABLED);
+ err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err)
goto err4;
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 1102ce65a3a9..f4b627d343ac 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -224,6 +224,11 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
pci_dev_put(p_smbus);
}
break;
+ case PCI_VENDOR_ID_NETMOS:
+ /* MosChip frame-index-register bug */
+ ehci_info(ehci, "applying MosChip frame-index workaround\n");
+ ehci->frame_index_bug = 1;
+ break;
}
/* optional debug port, normally in the first BAR */
@@ -439,7 +444,7 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
/* here we "know" root ports should always stay powered */
ehci_port_power(ehci, 1);
- hcd->state = HC_STATE_SUSPENDED;
+ ehci->rh_state = EHCI_RH_SUSPENDED;
return 0;
}
#endif
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
index 64626a777d61..2dc32da75cfc 100644
--- a/drivers/usb/host/ehci-ps3.c
+++ b/drivers/usb/host/ehci-ps3.c
@@ -167,7 +167,7 @@ static int __devinit ps3_ehci_probe(struct ps3_system_bus_device *dev)
ps3_system_bus_set_drvdata(dev, hcd);
- result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
+ result = usb_add_hcd(hcd, virq, 0);
if (result) {
dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
diff --git a/drivers/usb/host/ehci-pxa168.c b/drivers/usb/host/ehci-pxa168.c
new file mode 100644
index 000000000000..ac0c16e8f539
--- /dev/null
+++ b/drivers/usb/host/ehci-pxa168.c
@@ -0,0 +1,363 @@
+/*
+ * drivers/usb/host/ehci-pxa168.c
+ *
+ * Tanmay Upadhyay <tanmay.upadhyay@einfochips.com>
+ *
+ * Based on drivers/usb/host/ehci-orion.c
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <mach/pxa168.h>
+
+#define USB_PHY_CTRL_REG 0x4
+#define USB_PHY_PLL_REG 0x8
+#define USB_PHY_TX_REG 0xc
+
+#define FBDIV_SHIFT 4
+
+#define ICP_SHIFT 12
+#define ICP_15 2
+#define ICP_20 3
+#define ICP_25 4
+
+#define KVCO_SHIFT 15
+
+#define PLLCALI12_SHIFT 25
+#define CALI12_VDD 0
+#define CALI12_09 1
+#define CALI12_10 2
+#define CALI12_11 3
+
+#define PLLVDD12_SHIFT 27
+#define VDD12_VDD 0
+#define VDD12_10 1
+#define VDD12_11 2
+#define VDD12_12 3
+
+#define PLLVDD18_SHIFT 29
+#define VDD18_19 0
+#define VDD18_20 1
+#define VDD18_21 2
+#define VDD18_22 3
+
+
+#define PLL_READY (1 << 23)
+#define VCOCAL_START (1 << 21)
+#define REG_RCAL_START (1 << 12)
+
+struct pxa168_usb_drv_data {
+ struct ehci_hcd ehci;
+ struct clk *pxa168_usb_clk;
+ struct resource *usb_phy_res;
+ void __iomem *usb_phy_reg_base;
+};
+
+static int ehci_pxa168_setup(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int retval;
+
+ ehci_reset(ehci);
+ retval = ehci_halt(ehci);
+ if (retval)
+ return retval;
+
+ /*
+ * data structure init
+ */
+ retval = ehci_init(hcd);
+ if (retval)
+ return retval;
+
+ hcd->has_tt = 1;
+
+ ehci_port_power(ehci, 0);
+
+ return retval;
+}
+
+static const struct hc_driver ehci_pxa168_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "Marvell PXA168 EHCI",
+ .hcd_priv_size = sizeof(struct pxa168_usb_drv_data),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = ehci_pxa168_setup,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ehci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+};
+
+static int pxa168_usb_phy_init(struct platform_device *pdev)
+{
+ struct resource *res;
+ void __iomem *usb_phy_reg_base;
+ struct pxa168_usb_pdata *pdata;
+ struct pxa168_usb_drv_data *drv_data;
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ unsigned long reg_val;
+ int pll_retry_cont = 10000, err = 0;
+
+ drv_data = (struct pxa168_usb_drv_data *)hcd->hcd_priv;
+ pdata = (struct pxa168_usb_pdata *)pdev->dev.platform_data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res) {
+ dev_err(&pdev->dev,
+ "Found HC with no PHY register addr. Check %s setup!\n",
+ dev_name(&pdev->dev));
+ return -ENODEV;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res),
+ ehci_pxa168_hc_driver.description)) {
+ dev_dbg(&pdev->dev, "controller already in use\n");
+ return -EBUSY;
+ }
+
+ usb_phy_reg_base = ioremap(res->start, resource_size(res));
+ if (usb_phy_reg_base == NULL) {
+ dev_dbg(&pdev->dev, "error mapping memory\n");
+ err = -EFAULT;
+ goto err1;
+ }
+ drv_data->usb_phy_reg_base = usb_phy_reg_base;
+ drv_data->usb_phy_res = res;
+
+ /* If someone wants to init USB phy in board specific way */
+ if (pdata && pdata->phy_init)
+ return pdata->phy_init(usb_phy_reg_base);
+
+ /* Power up the PHY and PLL */
+ writel(readl(usb_phy_reg_base + USB_PHY_CTRL_REG) | 0x3,
+ usb_phy_reg_base + USB_PHY_CTRL_REG);
+
+ /* Configure PHY PLL */
+ reg_val = readl(usb_phy_reg_base + USB_PHY_PLL_REG) & ~(0x7e03ffff);
+ reg_val |= (VDD18_22 << PLLVDD18_SHIFT | VDD12_12 << PLLVDD12_SHIFT |
+ CALI12_11 << PLLCALI12_SHIFT | 3 << KVCO_SHIFT |
+ ICP_15 << ICP_SHIFT | 0xee << FBDIV_SHIFT | 0xb);
+ writel(reg_val, usb_phy_reg_base + USB_PHY_PLL_REG);
+
+ /* Make sure PHY PLL is ready */
+ while (!(readl(usb_phy_reg_base + USB_PHY_PLL_REG) & PLL_READY)) {
+ if (!(pll_retry_cont--)) {
+ dev_dbg(&pdev->dev, "USB PHY PLL not ready\n");
+ err = -EIO;
+ goto err2;
+ }
+ }
+
+ /* Toggle VCOCAL_START bit of U2PLL for PLL calibration */
+ udelay(200);
+ writel(readl(usb_phy_reg_base + USB_PHY_PLL_REG) | VCOCAL_START,
+ usb_phy_reg_base + USB_PHY_PLL_REG);
+ udelay(40);
+ writel(readl(usb_phy_reg_base + USB_PHY_PLL_REG) & ~VCOCAL_START,
+ usb_phy_reg_base + USB_PHY_PLL_REG);
+
+ /* Toggle REG_RCAL_START bit of U2PTX for impedance calibration */
+ udelay(400);
+ writel(readl(usb_phy_reg_base + USB_PHY_TX_REG) | REG_RCAL_START,
+ usb_phy_reg_base + USB_PHY_TX_REG);
+ udelay(40);
+ writel(readl(usb_phy_reg_base + USB_PHY_TX_REG) & ~REG_RCAL_START,
+ usb_phy_reg_base + USB_PHY_TX_REG);
+
+ /* Make sure PHY PLL is ready again */
+ pll_retry_cont = 0;
+ while (!(readl(usb_phy_reg_base + USB_PHY_PLL_REG) & PLL_READY)) {
+ if (!(pll_retry_cont--)) {
+ dev_dbg(&pdev->dev, "USB PHY PLL not ready\n");
+ err = -EIO;
+ goto err2;
+ }
+ }
+
+ return 0;
+err2:
+ iounmap(usb_phy_reg_base);
+err1:
+ release_mem_region(res->start, resource_size(res));
+ return err;
+}
+
+static int __devinit ehci_pxa168_drv_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct usb_hcd *hcd;
+ struct ehci_hcd *ehci;
+ struct pxa168_usb_drv_data *drv_data;
+ void __iomem *regs;
+ int irq, err = 0;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ pr_debug("Initializing pxa168-SoC USB Host Controller\n");
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(&pdev->dev,
+ "Found HC with no IRQ. Check %s setup!\n",
+ dev_name(&pdev->dev));
+ err = -ENODEV;
+ goto err1;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev,
+ "Found HC with no register addr. Check %s setup!\n",
+ dev_name(&pdev->dev));
+ err = -ENODEV;
+ goto err1;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res),
+ ehci_pxa168_hc_driver.description)) {
+ dev_dbg(&pdev->dev, "controller already in use\n");
+ err = -EBUSY;
+ goto err1;
+ }
+
+ regs = ioremap(res->start, resource_size(res));
+ if (regs == NULL) {
+ dev_dbg(&pdev->dev, "error mapping memory\n");
+ err = -EFAULT;
+ goto err2;
+ }
+
+ hcd = usb_create_hcd(&ehci_pxa168_hc_driver,
+ &pdev->dev, dev_name(&pdev->dev));
+ if (!hcd) {
+ err = -ENOMEM;
+ goto err3;
+ }
+
+ drv_data = (struct pxa168_usb_drv_data *)hcd->hcd_priv;
+
+ /* Enable USB clock */
+ drv_data->pxa168_usb_clk = clk_get(&pdev->dev, "PXA168-USBCLK");
+ if (IS_ERR(drv_data->pxa168_usb_clk)) {
+ dev_err(&pdev->dev, "Couldn't get USB clock\n");
+ err = PTR_ERR(drv_data->pxa168_usb_clk);
+ goto err4;
+ }
+ clk_enable(drv_data->pxa168_usb_clk);
+
+ err = pxa168_usb_phy_init(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "USB PHY initialization failed\n");
+ goto err5;
+ }
+
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+ hcd->regs = regs;
+
+ ehci = hcd_to_ehci(hcd);
+ ehci->caps = hcd->regs + 0x100;
+ ehci->regs = hcd->regs + 0x100 +
+ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+ hcd->has_tt = 1;
+ ehci->sbrn = 0x20;
+
+ err = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_DISABLED);
+ if (err)
+ goto err5;
+
+ return 0;
+
+err5:
+ clk_disable(drv_data->pxa168_usb_clk);
+ clk_put(drv_data->pxa168_usb_clk);
+err4:
+ usb_put_hcd(hcd);
+err3:
+ iounmap(regs);
+err2:
+ release_mem_region(res->start, resource_size(res));
+err1:
+ dev_err(&pdev->dev, "init %s fail, %d\n",
+ dev_name(&pdev->dev), err);
+
+ return err;
+}
+
+static int __exit ehci_pxa168_drv_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct pxa168_usb_drv_data *drv_data =
+ (struct pxa168_usb_drv_data *)hcd->hcd_priv;
+
+ usb_remove_hcd(hcd);
+
+ /* Power down PHY & PLL */
+ writel(readl(drv_data->usb_phy_reg_base + USB_PHY_CTRL_REG) & (~0x3),
+ drv_data->usb_phy_reg_base + USB_PHY_CTRL_REG);
+
+ clk_disable(drv_data->pxa168_usb_clk);
+ clk_put(drv_data->pxa168_usb_clk);
+
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+ iounmap(drv_data->usb_phy_reg_base);
+ release_mem_region(drv_data->usb_phy_res->start,
+ resource_size(drv_data->usb_phy_res));
+
+ usb_put_hcd(hcd);
+
+ return 0;
+}
+
+MODULE_ALIAS("platform:pxa168-ehci");
+
+static struct platform_driver ehci_pxa168_driver = {
+ .probe = ehci_pxa168_drv_probe,
+ .remove = __exit_p(ehci_pxa168_drv_remove),
+ .shutdown = usb_hcd_platform_shutdown,
+ .driver.name = "pxa168-ehci",
+};
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 0917e3a32465..4e4066c35a09 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -111,8 +111,6 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
}
}
- /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
- wmb ();
hw->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING);
}
@@ -153,7 +151,7 @@ static void ehci_clear_tt_buffer_complete(struct usb_hcd *hcd,
spin_lock_irqsave(&ehci->lock, flags);
qh->clearing_tt = 0;
if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list)
- && HC_IS_RUNNING(hcd->state))
+ && ehci->rh_state == EHCI_RH_RUNNING)
qh_link_async(ehci, qh);
spin_unlock_irqrestore(&ehci->lock, flags);
}
@@ -425,7 +423,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* stop scanning when we reach qtds the hc is using */
} else if (likely (!stopped
- && HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) {
+ && ehci->rh_state == EHCI_RH_RUNNING)) {
break;
/* scan the whole queue for unlinks whenever it stops */
@@ -433,7 +431,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
stopped = 1;
/* cancel everything if we halt, suspend, etc */
- if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state))
+ if (ehci->rh_state != EHCI_RH_RUNNING)
last_status = -ESHUTDOWN;
/* this qtd is active; skip it unless a previous qtd
@@ -724,7 +722,8 @@ qh_urb_transaction (
/*
* control requests may need a terminating data "status" ack;
- * bulk ones may need a terminating short packet (zero length).
+ * other OUT ones may need a terminating short packet
+ * (zero length).
*/
if (likely (urb->transfer_buffer_length != 0)) {
int one_more = 0;
@@ -733,7 +732,7 @@ qh_urb_transaction (
one_more = 1;
token ^= 0x0100; /* "in" <--> "out" */
token |= QTD_TOGGLE; /* force DATA1 */
- } else if (usb_pipebulk (urb->pipe)
+ } else if (usb_pipeout(urb->pipe)
&& (urb->transfer_flags & URB_ZERO_PACKET)
&& !(urb->transfer_buffer_length % maxpacket)) {
one_more = 1;
@@ -977,9 +976,8 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* in case a clear of CMD_ASE didn't take yet */
(void)handshake(ehci, &ehci->regs->status,
STS_ASS, 0, 150);
- cmd |= CMD_ASE | CMD_RUN;
+ cmd |= CMD_ASE;
ehci_writel(ehci, cmd, &ehci->regs->command);
- ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
/* posted write need not be known to HC yet ... */
}
}
@@ -1058,7 +1056,7 @@ static struct ehci_qh *qh_append_tds (
*/
token = qtd->hw_token;
qtd->hw_token = HALT_BIT(ehci);
- wmb ();
+
dummy = qh->dummy;
dma = dummy->qtd_dma;
@@ -1168,14 +1166,13 @@ static void end_unlink_async (struct ehci_hcd *ehci)
qh_completions (ehci, qh);
- if (!list_empty (&qh->qtd_list)
- && HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
+ if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) {
qh_link_async (ehci, qh);
- else {
+ } else {
/* it's not free to turn the async schedule on/off; leave it
* active but idle for a while once it empties.
*/
- if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state)
+ if (ehci->rh_state == EHCI_RH_RUNNING
&& ehci->async->qh_next.qh == NULL)
timer_action (ehci, TIMER_ASYNC_OFF);
}
@@ -1211,7 +1208,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* stop async schedule right now? */
if (unlikely (qh == ehci->async)) {
/* can't get here without STS_ASS set */
- if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
+ if (ehci->rh_state != EHCI_RH_HALTED
&& !ehci->reclaim) {
/* ... and CMD_IAAD clear */
ehci_writel(ehci, cmd & ~CMD_ASE,
@@ -1237,7 +1234,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
wmb ();
/* If the controller isn't running, we don't have to wait for it */
- if (unlikely(!HC_IS_RUNNING(ehci_to_hcd(ehci)->state))) {
+ if (unlikely(ehci->rh_state != EHCI_RH_RUNNING)) {
/* if (unlikely (qh->reclaim != 0))
* this will recurse, probably not much
*/
@@ -1260,7 +1257,7 @@ static void scan_async (struct ehci_hcd *ehci)
enum ehci_timer_action action = TIMER_IO_WATCHDOG;
timer_action_done (ehci, TIMER_ASYNC_SHRINK);
- stopped = !HC_IS_RUNNING(ehci_to_hcd(ehci)->state);
+ stopped = (ehci->rh_state != EHCI_RH_RUNNING);
ehci->qh_scan_next = ehci->async->qh_next.qh;
while (ehci->qh_scan_next) {
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
index b3958b3d3163..024b65c4990d 100644
--- a/drivers/usb/host/ehci-s5p.c
+++ b/drivers/usb/host/ehci-s5p.c
@@ -86,6 +86,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
goto fail_hcd;
}
+ s5p_ehci->hcd = hcd;
s5p_ehci->clk = clk_get(&pdev->dev, "usbhost");
if (IS_ERR(s5p_ehci->clk)) {
@@ -135,7 +136,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
/* cache this readonly data; minimize chip reads */
ehci->hcs_params = readl(&ehci->caps->hcs_params);
- err = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err) {
dev_err(&pdev->dev, "Failed to add USB HCD\n");
goto fail;
@@ -269,7 +270,7 @@ static int s5p_ehci_resume(struct device *dev)
/* here we "know" root ports should always stay powered */
ehci_port_power(ehci, 1);
- hcd->state = HC_STATE_SUSPENDED;
+ ehci->rh_state = EHCI_RH_SUSPENDED;
return 0;
}
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 2abf8543f083..2e829fae6482 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -36,6 +36,27 @@
static int ehci_get_frame (struct usb_hcd *hcd);
+#ifdef CONFIG_PCI
+
+static unsigned ehci_read_frame_index(struct ehci_hcd *ehci)
+{
+ unsigned uf;
+
+ /*
+ * The MosChip MCS9990 controller updates its microframe counter
+ * a little before the frame counter, and occasionally we will read
+ * the invalid intermediate value. Avoid problems by checking the
+ * microframe number (the low-order 3 bits); if they are 0 then
+ * re-read the register to get the correct value.
+ */
+ uf = ehci_readl(ehci, &ehci->regs->frame_index);
+ if (unlikely(ehci->frame_index_bug && ((uf & 7) == 0)))
+ uf = ehci_readl(ehci, &ehci->regs->frame_index);
+ return uf;
+}
+
+#endif
+
/*-------------------------------------------------------------------------*/
/*
@@ -479,10 +500,9 @@ static int enable_periodic (struct ehci_hcd *ehci)
cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
ehci_writel(ehci, cmd, &ehci->regs->command);
/* posted write ... PSS happens later */
- ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
/* make sure ehci_work scans these */
- ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index)
+ ehci->next_uframe = ehci_read_frame_index(ehci)
% (ehci->periodic_size << 3);
if (unlikely(ehci->broken_periodic))
ehci->last_periodic_enable = ktime_get_real();
@@ -677,7 +697,7 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* reschedule QH iff another request is queued */
if (!list_empty(&qh->qtd_list) &&
- HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
+ ehci->rh_state == EHCI_RH_RUNNING) {
rc = qh_schedule(ehci, qh);
/* An error here likely indicates handshake failure
@@ -1409,7 +1429,7 @@ iso_stream_schedule (
goto fail;
}
- now = ehci_readl(ehci, &ehci->regs->frame_index) & (mod - 1);
+ now = ehci_read_frame_index(ehci) & (mod - 1);
/* Typical case: reuse current schedule, stream is still active.
* Hopefully there are no gaps from the host falling behind
@@ -2275,8 +2295,8 @@ scan_periodic (struct ehci_hcd *ehci)
* Touches as few pages as possible: cache-friendly.
*/
now_uframe = ehci->next_uframe;
- if (HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
- clock = ehci_readl(ehci, &ehci->regs->frame_index);
+ if (ehci->rh_state == EHCI_RH_RUNNING) {
+ clock = ehci_read_frame_index(ehci);
clock_frame = (clock >> 3) & (ehci->periodic_size - 1);
} else {
clock = now_uframe + mod - 1;
@@ -2310,7 +2330,7 @@ restart:
union ehci_shadow temp;
int live;
- live = HC_IS_RUNNING (ehci_to_hcd(ehci)->state);
+ live = (ehci->rh_state == EHCI_RH_RUNNING);
switch (hc32_to_cpu(ehci, type)) {
case Q_TYPE_QH:
/* handle any completions */
@@ -2435,7 +2455,7 @@ restart:
* We can't advance our scan without collecting the ISO
* transfers that are still pending in this frame.
*/
- if (incomplete && HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
+ if (incomplete && ehci->rh_state == EHCI_RH_RUNNING) {
ehci->next_uframe = now_uframe;
break;
}
@@ -2451,12 +2471,11 @@ restart:
if (now_uframe == clock) {
unsigned now;
- if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)
+ if (ehci->rh_state != EHCI_RH_RUNNING
|| ehci->periodic_sched == 0)
break;
ehci->next_uframe = now_uframe;
- now = ehci_readl(ehci, &ehci->regs->frame_index) &
- (mod - 1);
+ now = ehci_read_frame_index(ehci) & (mod - 1);
if (now_uframe == now)
break;
diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c
index 86a95bb80a61..9d9cf47d80da 100644
--- a/drivers/usb/host/ehci-sh.c
+++ b/drivers/usb/host/ehci-sh.c
@@ -168,7 +168,7 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev)
clk_enable(priv->fclk);
clk_enable(priv->iclk);
- ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to add hcd");
goto fail_add_hcd;
diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c
index dbf1e4ef3c17..b115b0b76e33 100644
--- a/drivers/usb/host/ehci-spear.c
+++ b/drivers/usb/host/ehci-spear.c
@@ -154,7 +154,7 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)
ehci->clk = usbh_clk;
spear_start_ehci(ehci);
- retval = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_DISABLED);
+ retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (retval)
goto fail_add_hcd;
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 02b2bfd49a10..db9d1b4bfbdc 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -674,7 +674,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
}
#endif
- err = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err) {
dev_err(&pdev->dev, "Failed to add USB HCD\n");
goto fail;
diff --git a/drivers/usb/host/ehci-vt8500.c b/drivers/usb/host/ehci-vt8500.c
index 47d749631bc7..54d1ab8aec49 100644
--- a/drivers/usb/host/ehci-vt8500.c
+++ b/drivers/usb/host/ehci-vt8500.c
@@ -133,7 +133,7 @@ static int vt8500_ehci_drv_probe(struct platform_device *pdev)
ehci_port_power(ehci, 1);
ret = usb_add_hcd(hcd, pdev->resource[1].start,
- IRQF_DISABLED | IRQF_SHARED);
+ IRQF_SHARED);
if (ret == 0) {
platform_set_drvdata(pdev, hcd);
return ret;
diff --git a/drivers/usb/host/ehci-xls.c b/drivers/usb/host/ehci-xls.c
new file mode 100644
index 000000000000..fe74bd676018
--- /dev/null
+++ b/drivers/usb/host/ehci-xls.c
@@ -0,0 +1,161 @@
+/*
+ * EHCI HCD for Netlogic XLS processors.
+ *
+ * (C) Copyright 2011 Netlogic Microsystems Inc.
+ *
+ * Based on various ehci-*.c drivers
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/platform_device.h>
+
+static int ehci_xls_setup(struct usb_hcd *hcd)
+{
+ int retval;
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+ ehci->caps = hcd->regs;
+ ehci->regs = hcd->regs +
+ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+ dbg_hcs_params(ehci, "reset");
+ dbg_hcc_params(ehci, "reset");
+
+ /* cache this readonly data; minimize chip reads */
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+ retval = ehci_halt(ehci);
+ if (retval)
+ return retval;
+
+ /* data structure init */
+ retval = ehci_init(hcd);
+ if (retval)
+ return retval;
+
+ ehci_reset(ehci);
+
+ return retval;
+}
+
+int ehci_xls_probe_internal(const struct hc_driver *driver,
+ struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ struct resource *res;
+ int retval, irq;
+
+ /* Get our IRQ from an earlier registered Platform Resource */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "Found HC with no IRQ. Check %s setup!\n",
+ dev_name(&pdev->dev));
+ return -ENODEV;
+ }
+
+ /* Get our Memory Handle */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Error: MMIO Handle %s setup!\n",
+ dev_name(&pdev->dev));
+ return -ENODEV;
+ }
+ hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
+ if (!hcd) {
+ retval = -ENOMEM;
+ goto err1;
+ }
+
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = res->end - res->start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+ driver->description)) {
+ dev_dbg(&pdev->dev, "controller already in use\n");
+ retval = -EBUSY;
+ goto err2;
+ }
+ hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+
+ if (hcd->regs == NULL) {
+ dev_dbg(&pdev->dev, "error mapping memory\n");
+ retval = -EFAULT;
+ goto err3;
+ }
+
+ retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ if (retval != 0)
+ goto err4;
+ return retval;
+
+err4:
+ iounmap(hcd->regs);
+err3:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err2:
+ usb_put_hcd(hcd);
+err1:
+ dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev),
+ retval);
+ return retval;
+}
+
+static struct hc_driver ehci_xls_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "XLS EHCI Host Controller",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+ .irq = ehci_irq,
+ .flags = HCD_USB2 | HCD_MEMORY,
+ .reset = ehci_xls_setup,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
+
+ .get_frame_number = ehci_get_frame,
+
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+};
+
+static int ehci_xls_probe(struct platform_device *pdev)
+{
+ if (usb_disabled())
+ return -ENODEV;
+
+ return ehci_xls_probe_internal(&ehci_xls_hc_driver, pdev);
+}
+
+static int ehci_xls_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+ return 0;
+}
+
+MODULE_ALIAS("ehci-xls");
+
+static struct platform_driver ehci_xls_driver = {
+ .probe = ehci_xls_probe,
+ .remove = ehci_xls_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+ .driver = {
+ .name = "ehci-xls",
+ },
+};
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index cc7d337ec355..0a5fda73b3f2 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -62,6 +62,12 @@ struct ehci_stats {
#define EHCI_MAX_ROOT_PORTS 15 /* see HCS_N_PORTS */
+enum ehci_rh_state {
+ EHCI_RH_HALTED,
+ EHCI_RH_SUSPENDED,
+ EHCI_RH_RUNNING
+};
+
struct ehci_hcd { /* one per controller */
/* glue to PCI and HCD framework */
struct ehci_caps __iomem *caps;
@@ -70,6 +76,7 @@ struct ehci_hcd { /* one per controller */
__u32 hcs_params; /* cached register copy */
spinlock_t lock;
+ enum ehci_rh_state rh_state;
/* async schedule support */
struct ehci_qh *async;
@@ -139,6 +146,7 @@ struct ehci_hcd { /* one per controller */
unsigned fs_i_thresh:1; /* Intel iso scheduling */
unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/
unsigned has_synopsys_hc_bug:1; /* Synopsys HC */
+ unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */
/* required for usb32 quirk */
#define OHCI_CTRL_HCFS (3 << 6)
@@ -740,6 +748,22 @@ static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x)
/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_PCI
+
+/* For working around the MosChip frame-index-register bug */
+static unsigned ehci_read_frame_index(struct ehci_hcd *ehci);
+
+#else
+
+static inline unsigned ehci_read_frame_index(struct ehci_hcd *ehci)
+{
+ return ehci_readl(ehci, &ehci->regs->frame_index);
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
#ifndef DEBUG
#define STUB_DEBUG_FILES
#endif /* DEBUG */
diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c
index 572ea53b0226..4ed6d19f2a54 100644
--- a/drivers/usb/host/fhci-hcd.c
+++ b/drivers/usb/host/fhci-hcd.c
@@ -621,12 +621,15 @@ static int __devinit of_fhci_probe(struct platform_device *ofdev)
goto err_pram;
}
- pram_addr = cpm_muram_alloc_fixed(iprop[2], FHCI_PRAM_SIZE);
+ pram_addr = cpm_muram_alloc(FHCI_PRAM_SIZE, 64);
if (IS_ERR_VALUE(pram_addr)) {
dev_err(dev, "failed to allocate usb pram\n");
ret = -ENOMEM;
goto err_pram;
}
+
+ qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, QE_CR_SUBBLOCK_USB,
+ QE_CR_PROTOCOL_UNSPECIFIED, pram_addr);
fhci->pram = cpm_muram_addr(pram_addr);
/* GPIOs and pins */
@@ -686,7 +689,7 @@ static int __devinit of_fhci_probe(struct platform_device *ofdev)
}
ret = request_irq(fhci->timer->irq, fhci_frame_limit_timer_irq,
- IRQF_DISABLED, "qe timer (usb)", hcd);
+ 0, "qe timer (usb)", hcd);
if (ret) {
dev_err(dev, "failed to request timer irq");
goto err_timer_irq;
@@ -745,7 +748,7 @@ static int __devinit of_fhci_probe(struct platform_device *ofdev)
out_be16(&fhci->regs->usb_event, 0xffff);
out_be16(&fhci->regs->usb_mask, 0);
- ret = usb_add_hcd(hcd, usb_irq, IRQF_DISABLED);
+ ret = usb_add_hcd(hcd, usb_irq, 0);
if (ret < 0)
goto err_add_hcd;
diff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c
index a42ef380e917..2df851b4bc7c 100644
--- a/drivers/usb/host/fhci-sched.c
+++ b/drivers/usb/host/fhci-sched.c
@@ -1,7 +1,7 @@
/*
* Freescale QUICC Engine USB Host Controller Driver
*
- * Copyright (c) Freescale Semicondutor, Inc. 2006.
+ * Copyright (c) Freescale Semicondutor, Inc. 2006, 2011.
* Shlomi Gridish <gridish@freescale.com>
* Jerry Huang <Chang-Ming.Huang@freescale.com>
* Copyright (c) Logic Product Development, Inc. 2007
@@ -810,9 +810,11 @@ void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb)
ed->dev_addr = usb_pipedevice(urb->pipe);
ed->max_pkt_size = usb_maxpacket(urb->dev, urb->pipe,
usb_pipeout(urb->pipe));
+ /* setup stage */
td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, FHCI_TA_SETUP,
USB_TD_TOGGLE_DATA0, urb->setup_packet, 8, 0, 0, true);
+ /* data stage */
if (data_len > 0) {
td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++,
usb_pipeout(urb->pipe) ? FHCI_TA_OUT :
@@ -820,9 +822,18 @@ void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb)
USB_TD_TOGGLE_DATA1, data, data_len, 0, 0,
true);
}
- td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++,
- usb_pipeout(urb->pipe) ? FHCI_TA_IN : FHCI_TA_OUT,
- USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true);
+
+ /* status stage */
+ if (data_len > 0)
+ td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++,
+ (usb_pipeout(urb->pipe) ? FHCI_TA_IN :
+ FHCI_TA_OUT),
+ USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true);
+ else
+ td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++,
+ FHCI_TA_IN,
+ USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true);
+
urb_state = US_CTRL_SETUP;
break;
case FHCI_TF_ISO:
diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c
index af05718bdc73..2ee18cfa1efe 100644
--- a/drivers/usb/host/imx21-hcd.c
+++ b/drivers/usb/host/imx21-hcd.c
@@ -1891,7 +1891,7 @@ static int imx21_probe(struct platform_device *pdev)
dev_info(imx21->dev, "Hardware HC revision: 0x%02X\n",
(readl(imx21->regs + USBOTG_HWMODE) >> 16) & 0xFF);
- ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+ ret = usb_add_hcd(hcd, irq, 0);
if (ret != 0) {
dev_err(imx21->dev, "usb_add_hcd() returned %d\n", ret);
goto failed_add_hcd;
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index baae4ccd16ac..d91e5f211a76 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -1639,7 +1639,7 @@ static int __devinit isp116x_probe(struct platform_device *pdev)
goto err6;
}
- ret = usb_add_hcd(hcd, irq, irqflags | IRQF_DISABLED);
+ ret = usb_add_hcd(hcd, irq, irqflags);
if (ret)
goto err6;
diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c
index 9c37dad3e816..e5fd8aa57af1 100644
--- a/drivers/usb/host/isp1362-hcd.c
+++ b/drivers/usb/host/isp1362-hcd.c
@@ -2358,7 +2358,7 @@ static int isp1362_hc_reset(struct usb_hcd *hcd)
unsigned long flags;
int clkrdy = 0;
- pr_info("%s:\n", __func__);
+ pr_debug("%s:\n", __func__);
if (isp1362_hcd->board && isp1362_hcd->board->reset) {
isp1362_hcd->board->reset(hcd->self.controller, 1);
@@ -2395,7 +2395,7 @@ static void isp1362_hc_stop(struct usb_hcd *hcd)
unsigned long flags;
u32 tmp;
- pr_info("%s:\n", __func__);
+ pr_debug("%s:\n", __func__);
del_timer_sync(&hcd->rh_timer);
@@ -2523,7 +2523,7 @@ static int isp1362_hc_start(struct usb_hcd *hcd)
u16 chipid;
unsigned long flags;
- pr_info("%s:\n", __func__);
+ pr_debug("%s:\n", __func__);
spin_lock_irqsave(&isp1362_hcd->lock, flags);
chipid = isp1362_read_reg16(isp1362_hcd, HCCHIPID);
@@ -2773,7 +2773,7 @@ static int __devinit isp1362_probe(struct platform_device *pdev)
if (irq_res->flags & IORESOURCE_IRQ_LOWLEVEL)
irq_flags |= IRQF_TRIGGER_LOW;
- retval = usb_add_hcd(hcd, irq, irq_flags | IRQF_DISABLED | IRQF_SHARED);
+ retval = usb_add_hcd(hcd, irq, irq_flags | IRQF_SHARED);
if (retval != 0)
goto err6;
pr_info("%s, irq %d\n", hcd->product_desc, irq);
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
index 840beda66dd9..27dfab80ed8f 100644
--- a/drivers/usb/host/isp1760-hcd.c
+++ b/drivers/usb/host/isp1760-hcd.c
@@ -21,8 +21,10 @@
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/mm.h>
+#include <linux/timer.h>
#include <asm/unaligned.h>
#include <asm/cacheflush.h>
+#include <linux/gpio.h>
#include "isp1760-hcd.h"
@@ -39,7 +41,6 @@ struct isp1760_hcd {
int int_done_map;
struct memory_chunk memory_pool[BLOCKS];
struct list_head controlqhs, bulkqhs, interruptqhs;
- int active_ptds;
/* periodic schedule support */
#define DEFAULT_I_TDPS 1024
@@ -48,6 +49,8 @@ struct isp1760_hcd {
unsigned long reset_done;
unsigned long next_statechange;
unsigned int devflags;
+
+ int rst_gpio;
};
static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd)
@@ -114,6 +117,7 @@ struct isp1760_qh {
u32 toggle;
u32 ping;
int slot;
+ int tt_buffer_dirty; /* See USB2.0 spec section 11.17.5 */
};
struct urb_listitem {
@@ -432,6 +436,18 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
int result;
u32 scratch, hwmode;
+ /* low-level chip reset */
+ if (gpio_is_valid(priv->rst_gpio)) {
+ unsigned int rst_lvl;
+
+ rst_lvl = (priv->devflags &
+ ISP1760_FLAG_RESET_ACTIVE_HIGH) ? 1 : 0;
+
+ gpio_set_value(priv->rst_gpio, rst_lvl);
+ mdelay(50);
+ gpio_set_value(priv->rst_gpio, !rst_lvl);
+ }
+
/* Setup HW Mode Control: This assumes a level active-low interrupt */
hwmode = HW_DATA_BUS_32BIT;
@@ -489,10 +505,6 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
16 : 32, (priv->devflags & ISP1760_FLAG_ANALOG_OC) ?
"analog" : "digital");
- /* This is weird: at the first plug-in of a device there seems to be
- one packet queued that never gets returned? */
- priv->active_ptds = -1;
-
/* ATL reset */
reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode | ALL_ATX_RESET);
mdelay(10);
@@ -514,83 +526,6 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
return priv_init(hcd);
}
-static void isp1760_init_maps(struct usb_hcd *hcd)
-{
- /*set last maps, for iso its only 1, else 32 tds bitmap*/
- reg_write32(hcd->regs, HC_ATL_PTD_LASTPTD_REG, 0x80000000);
- reg_write32(hcd->regs, HC_INT_PTD_LASTPTD_REG, 0x80000000);
- reg_write32(hcd->regs, HC_ISO_PTD_LASTPTD_REG, 0x00000001);
-
- reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, 0xffffffff);
- reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, 0xffffffff);
- reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, 0xffffffff);
-
- reg_write32(hcd->regs, HC_BUFFER_STATUS_REG,
- ATL_BUF_FILL | INT_BUF_FILL);
-}
-
-static void isp1760_enable_interrupts(struct usb_hcd *hcd)
-{
- reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_REG, 0);
- reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0xffffffff);
- reg_write32(hcd->regs, HC_INT_IRQ_MASK_AND_REG, 0);
- reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0xffffffff);
- reg_write32(hcd->regs, HC_ISO_IRQ_MASK_AND_REG, 0);
- reg_write32(hcd->regs, HC_ISO_IRQ_MASK_OR_REG, 0xffffffff);
- /* step 23 passed */
-}
-
-static int isp1760_run(struct usb_hcd *hcd)
-{
- int retval;
- u32 temp;
- u32 command;
- u32 chipid;
-
- hcd->uses_new_polling = 1;
-
- hcd->state = HC_STATE_RUNNING;
- isp1760_enable_interrupts(hcd);
- temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
- reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp | HW_GLOBAL_INTR_EN);
-
- command = reg_read32(hcd->regs, HC_USBCMD);
- command &= ~(CMD_LRESET|CMD_RESET);
- command |= CMD_RUN;
- reg_write32(hcd->regs, HC_USBCMD, command);
-
- retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000);
- if (retval)
- return retval;
-
- /*
- * XXX
- * Spec says to write FLAG_CF as last config action, priv code grabs
- * the semaphore while doing so.
- */
- down_write(&ehci_cf_port_reset_rwsem);
- reg_write32(hcd->regs, HC_CONFIGFLAG, FLAG_CF);
-
- retval = handshake(hcd, HC_CONFIGFLAG, FLAG_CF, FLAG_CF, 250 * 1000);
- up_write(&ehci_cf_port_reset_rwsem);
- if (retval)
- return retval;
-
- chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG);
- dev_info(hcd->self.controller, "USB ISP %04x HW rev. %d started\n",
- chipid & 0xffff, chipid >> 16);
-
- /* PTD Register Init Part 2, Step 28 */
- /* enable INTs */
- isp1760_init_maps(hcd);
-
- /* GRR this is run-once init(), being done every time the HC starts.
- * So long as they're part of class devices, we can't do it init()
- * since the class device isn't created that early.
- */
- return 0;
-}
-
static u32 base_to_chip(u32 base)
{
return ((base - 0x400) >> 3);
@@ -813,28 +748,29 @@ static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot,
WARN_ON(slots[slot].qh);
WARN_ON(qtd->status != QTD_PAYLOAD_ALLOC);
- slots[slot].qtd = qtd;
- slots[slot].qh = qh;
- qh->slot = slot;
- qtd->status = QTD_XFER_STARTED; /* Set this before writing ptd, since
- interrupt routine may preempt and expects this value. */
- ptd_write(hcd->regs, ptd_offset, slot, ptd);
- priv->active_ptds++;
-
/* Make sure done map has not triggered from some unlinked transfer */
if (ptd_offset == ATL_PTD_OFFSET) {
priv->atl_done_map |= reg_read32(hcd->regs,
HC_ATL_PTD_DONEMAP_REG);
- priv->atl_done_map &= ~(1 << qh->slot);
+ priv->atl_done_map &= ~(1 << slot);
+ } else {
+ priv->int_done_map |= reg_read32(hcd->regs,
+ HC_INT_PTD_DONEMAP_REG);
+ priv->int_done_map &= ~(1 << slot);
+ }
+
+ qh->slot = slot;
+ qtd->status = QTD_XFER_STARTED;
+ slots[slot].timestamp = jiffies;
+ slots[slot].qtd = qtd;
+ slots[slot].qh = qh;
+ ptd_write(hcd->regs, ptd_offset, slot, ptd);
+ if (ptd_offset == ATL_PTD_OFFSET) {
skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
skip_map &= ~(1 << qh->slot);
reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
} else {
- priv->int_done_map |= reg_read32(hcd->regs,
- HC_INT_PTD_DONEMAP_REG);
- priv->int_done_map &= ~(1 << qh->slot);
-
skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
skip_map &= ~(1 << qh->slot);
reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
@@ -858,10 +794,7 @@ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
if (qtd->status < QTD_XFER_COMPLETE)
break;
- if (list_is_last(&qtd->qtd_list, &qh->qtd_list))
- last_qtd = 1;
- else
- last_qtd = qtd->urb != qtd_next->urb;
+ last_qtd = last_qtd_of_urb(qtd, qh);
if ((!last_qtd) && (qtd->status == QTD_RETIRE))
qtd_next->status = QTD_RETIRE;
@@ -902,7 +835,7 @@ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
urb_listitem = kmem_cache_zalloc(urb_listitem_cachep,
GFP_ATOMIC);
if (unlikely(!urb_listitem))
- break;
+ break; /* Try again on next call */
urb_listitem->urb = qtd->urb;
list_add_tail(&urb_listitem->urb_list, urb_list);
}
@@ -928,6 +861,10 @@ static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
return;
}
+ /* Make sure this endpoint's TT buffer is clean before queueing ptds */
+ if (qh->tt_buffer_dirty)
+ return;
+
if (usb_pipeint(list_entry(qh->qtd_list.next, struct isp1760_qtd,
qtd_list)->urb->pipe)) {
ptd_offset = INT_PTD_OFFSET;
@@ -1168,11 +1105,9 @@ static int check_atl_transfer(struct usb_hcd *hcd, struct ptd *ptd,
return PTD_STATE_QTD_DONE;
}
-static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
+static void handle_done_ptds(struct usb_hcd *hcd)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
- u32 imask;
- irqreturn_t irqret = IRQ_NONE;
struct ptd ptd;
struct isp1760_qh *qh;
int slot;
@@ -1181,27 +1116,14 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
u32 ptd_offset;
struct isp1760_qtd *qtd;
int modified;
- static int last_active_ptds;
- int int_skip_map, atl_skip_map;
-
- spin_lock(&priv->lock);
-
- if (!(hcd->state & HC_STATE_RUNNING))
- goto leave;
-
- imask = reg_read32(hcd->regs, HC_INTERRUPT_REG);
- if (unlikely(!imask))
- goto leave;
- reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */
+ int skip_map;
- int_skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
- atl_skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
- priv->int_done_map |= reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG);
- priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG);
- priv->int_done_map &= ~int_skip_map;
- priv->atl_done_map &= ~atl_skip_map;
+ skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
+ priv->int_done_map &= ~skip_map;
+ skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
+ priv->atl_done_map &= ~skip_map;
- modified = priv->int_done_map | priv->atl_done_map;
+ modified = priv->int_done_map || priv->atl_done_map;
while (priv->int_done_map || priv->atl_done_map) {
if (priv->int_done_map) {
@@ -1240,7 +1162,6 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
slots[slot].qtd = NULL;
qh = slots[slot].qh;
slots[slot].qh = NULL;
- priv->active_ptds--;
qh->slot = -1;
WARN_ON(qtd->status != QTD_XFER_STARTED);
@@ -1281,6 +1202,15 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
case PTD_STATE_URB_RETIRE:
qtd->status = QTD_RETIRE;
+ if ((qtd->urb->dev->speed != USB_SPEED_HIGH) &&
+ (qtd->urb->status != -EPIPE) &&
+ (qtd->urb->status != -EREMOTEIO)) {
+ qh->tt_buffer_dirty = 1;
+ if (usb_hub_clear_tt_buffer(qtd->urb))
+ /* Clear failed; let's hope things work
+ anyway */
+ qh->tt_buffer_dirty = 0;
+ }
qtd = NULL;
qh->toggle = 0;
qh->ping = 0;
@@ -1311,22 +1241,28 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
if (modified)
schedule_ptds(hcd);
+}
- /* ISP1760 Errata 2 explains that interrupts may be missed (or not
- happen?) if two USB devices are running simultaneously. Perhaps
- this happens when a PTD is finished during interrupt handling;
- enable SOF interrupts if PTDs are still scheduled when exiting this
- interrupt handler, just to be safe. */
+static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 imask;
+ irqreturn_t irqret = IRQ_NONE;
- if (priv->active_ptds != last_active_ptds) {
- if (priv->active_ptds > 0)
- reg_write32(hcd->regs, HC_INTERRUPT_ENABLE,
- INTERRUPT_ENABLE_SOT_MASK);
- else
- reg_write32(hcd->regs, HC_INTERRUPT_ENABLE,
- INTERRUPT_ENABLE_MASK);
- last_active_ptds = priv->active_ptds;
- }
+ spin_lock(&priv->lock);
+
+ if (!(hcd->state & HC_STATE_RUNNING))
+ goto leave;
+
+ imask = reg_read32(hcd->regs, HC_INTERRUPT_REG);
+ if (unlikely(!imask))
+ goto leave;
+ reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */
+
+ priv->int_done_map |= reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG);
+ priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG);
+
+ handle_done_ptds(hcd);
irqret = IRQ_HANDLED;
leave:
@@ -1335,6 +1271,138 @@ leave:
return irqret;
}
+/*
+ * Workaround for problem described in chip errata 2:
+ *
+ * Sometimes interrupts are not generated when ATL (not INT?) completion occurs.
+ * One solution suggested in the errata is to use SOF interrupts _instead_of_
+ * ATL done interrupts (the "instead of" might be important since it seems
+ * enabling ATL interrupts also causes the chip to sometimes - rarely - "forget"
+ * to set the PTD's done bit in addition to not generating an interrupt!).
+ *
+ * So if we use SOF + ATL interrupts, we sometimes get stale PTDs since their
+ * done bit is not being set. This is bad - it blocks the endpoint until reboot.
+ *
+ * If we use SOF interrupts only, we get latency between ptd completion and the
+ * actual handling. This is very noticeable in testusb runs which takes several
+ * minutes longer without ATL interrupts.
+ *
+ * A better solution is to run the code below every SLOT_CHECK_PERIOD ms. If it
+ * finds active ATL slots which are older than SLOT_TIMEOUT ms, it checks the
+ * slot's ACTIVE and VALID bits. If these are not set, the ptd is considered
+ * completed and its done map bit is set.
+ *
+ * The values of SLOT_TIMEOUT and SLOT_CHECK_PERIOD have been arbitrarily chosen
+ * not to cause too much lag when this HW bug occurs, while still hopefully
+ * ensuring that the check does not falsely trigger.
+ */
+#define SLOT_TIMEOUT 300
+#define SLOT_CHECK_PERIOD 200
+static struct timer_list errata2_timer;
+
+void errata2_function(unsigned long data)
+{
+ struct usb_hcd *hcd = (struct usb_hcd *) data;
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int slot;
+ struct ptd ptd;
+ unsigned long spinflags;
+
+ spin_lock_irqsave(&priv->lock, spinflags);
+
+ for (slot = 0; slot < 32; slot++)
+ if (priv->atl_slots[slot].qh && time_after(jiffies,
+ priv->atl_slots[slot].timestamp +
+ SLOT_TIMEOUT * HZ / 1000)) {
+ ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
+ if (!FROM_DW0_VALID(ptd.dw0) &&
+ !FROM_DW3_ACTIVE(ptd.dw3))
+ priv->atl_done_map |= 1 << slot;
+ }
+
+ if (priv->atl_done_map)
+ handle_done_ptds(hcd);
+
+ spin_unlock_irqrestore(&priv->lock, spinflags);
+
+ errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000;
+ add_timer(&errata2_timer);
+}
+
+static int isp1760_run(struct usb_hcd *hcd)
+{
+ int retval;
+ u32 temp;
+ u32 command;
+ u32 chipid;
+
+ hcd->uses_new_polling = 1;
+
+ hcd->state = HC_STATE_RUNNING;
+
+ /* Set PTD interrupt AND & OR maps */
+ reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_REG, 0);
+ reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0xffffffff);
+ reg_write32(hcd->regs, HC_INT_IRQ_MASK_AND_REG, 0);
+ reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0xffffffff);
+ reg_write32(hcd->regs, HC_ISO_IRQ_MASK_AND_REG, 0);
+ reg_write32(hcd->regs, HC_ISO_IRQ_MASK_OR_REG, 0xffffffff);
+ /* step 23 passed */
+
+ temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
+ reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp | HW_GLOBAL_INTR_EN);
+
+ command = reg_read32(hcd->regs, HC_USBCMD);
+ command &= ~(CMD_LRESET|CMD_RESET);
+ command |= CMD_RUN;
+ reg_write32(hcd->regs, HC_USBCMD, command);
+
+ retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000);
+ if (retval)
+ return retval;
+
+ /*
+ * XXX
+ * Spec says to write FLAG_CF as last config action, priv code grabs
+ * the semaphore while doing so.
+ */
+ down_write(&ehci_cf_port_reset_rwsem);
+ reg_write32(hcd->regs, HC_CONFIGFLAG, FLAG_CF);
+
+ retval = handshake(hcd, HC_CONFIGFLAG, FLAG_CF, FLAG_CF, 250 * 1000);
+ up_write(&ehci_cf_port_reset_rwsem);
+ if (retval)
+ return retval;
+
+ init_timer(&errata2_timer);
+ errata2_timer.function = errata2_function;
+ errata2_timer.data = (unsigned long) hcd;
+ errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000;
+ add_timer(&errata2_timer);
+
+ chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG);
+ dev_info(hcd->self.controller, "USB ISP %04x HW rev. %d started\n",
+ chipid & 0xffff, chipid >> 16);
+
+ /* PTD Register Init Part 2, Step 28 */
+
+ /* Setup registers controlling PTD checking */
+ reg_write32(hcd->regs, HC_ATL_PTD_LASTPTD_REG, 0x80000000);
+ reg_write32(hcd->regs, HC_INT_PTD_LASTPTD_REG, 0x80000000);
+ reg_write32(hcd->regs, HC_ISO_PTD_LASTPTD_REG, 0x00000001);
+ reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, 0xffffffff);
+ reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, 0xffffffff);
+ reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, 0xffffffff);
+ reg_write32(hcd->regs, HC_BUFFER_STATUS_REG,
+ ATL_BUF_FILL | INT_BUF_FILL);
+
+ /* GRR this is run-once init(), being done every time the HC starts.
+ * So long as they're part of class devices, we can't do it init()
+ * since the class device isn't created that early.
+ */
+ return 0;
+}
+
static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len)
{
qtd->data_buffer = databuffer;
@@ -1503,7 +1571,6 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
packetize_urb(hcd, urb, &new_qtds, mem_flags);
if (list_empty(&new_qtds))
return -ENOMEM;
- urb->hcpriv = NULL; /* Used to signal unlink to interrupt handler */
retval = 0;
spin_lock_irqsave(&priv->lock, spinflags);
@@ -1531,6 +1598,7 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
qh = qh_alloc(GFP_ATOMIC);
if (!qh) {
retval = -ENOMEM;
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
goto out;
}
list_add_tail(&qh->qh_list, ep_queue);
@@ -1570,7 +1638,41 @@ static void kill_transfer(struct usb_hcd *hcd, struct urb *urb,
}
qh->slot = -1;
- priv->active_ptds--;
+}
+
+/*
+ * Retire the qtds beginning at 'qtd' and belonging all to the same urb, killing
+ * any active transfer belonging to the urb in the process.
+ */
+static void dequeue_urb_from_qtd(struct usb_hcd *hcd, struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd)
+{
+ struct urb *urb;
+ int urb_was_running;
+
+ urb = qtd->urb;
+ urb_was_running = 0;
+ list_for_each_entry_from(qtd, &qh->qtd_list, qtd_list) {
+ if (qtd->urb != urb)
+ break;
+
+ if (qtd->status >= QTD_XFER_STARTED)
+ urb_was_running = 1;
+ if (last_qtd_of_urb(qtd, qh) &&
+ (qtd->status >= QTD_XFER_COMPLETE))
+ urb_was_running = 0;
+
+ if (qtd->status == QTD_XFER_STARTED)
+ kill_transfer(hcd, urb, qh);
+ qtd->status = QTD_RETIRE;
+ }
+
+ if ((urb->dev->speed != USB_SPEED_HIGH) && urb_was_running) {
+ qh->tt_buffer_dirty = 1;
+ if (usb_hub_clear_tt_buffer(urb))
+ /* Clear failed; let's hope things work anyway */
+ qh->tt_buffer_dirty = 0;
+ }
}
static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
@@ -1595,9 +1697,8 @@ static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
list_for_each_entry(qtd, &qh->qtd_list, qtd_list)
if (qtd->urb == urb) {
- if (qtd->status == QTD_XFER_STARTED)
- kill_transfer(hcd, urb, qh);
- qtd->status = QTD_RETIRE;
+ dequeue_urb_from_qtd(hcd, qh, qtd);
+ break;
}
urb->status = status;
@@ -1622,12 +1723,11 @@ static void isp1760_endpoint_disable(struct usb_hcd *hcd,
if (!qh)
goto out;
- list_for_each_entry(qtd, &qh->qtd_list, qtd_list) {
- if (qtd->status == QTD_XFER_STARTED)
- kill_transfer(hcd, qtd->urb, qh);
- qtd->status = QTD_RETIRE;
- qtd->urb->status = -ECONNRESET;
- }
+ list_for_each_entry(qtd, &qh->qtd_list, qtd_list)
+ if (qtd->status != QTD_RETIRE) {
+ dequeue_urb_from_qtd(hcd, qh, qtd);
+ qtd->urb->status = -ECONNRESET;
+ }
ep->hcpriv = NULL;
/* Cannot free qh here since it will be parsed by schedule_ptds() */
@@ -2021,6 +2121,8 @@ static void isp1760_stop(struct usb_hcd *hcd)
struct isp1760_hcd *priv = hcd_to_priv(hcd);
u32 temp;
+ del_timer(&errata2_timer);
+
isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, 1,
NULL, 0);
mdelay(20);
@@ -2048,6 +2150,23 @@ static void isp1760_shutdown(struct usb_hcd *hcd)
reg_write32(hcd->regs, HC_USBCMD, command);
}
+static void isp1760_clear_tt_buffer_complete(struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ struct isp1760_qh *qh = ep->hcpriv;
+ unsigned long spinflags;
+
+ if (!qh)
+ return;
+
+ spin_lock_irqsave(&priv->lock, spinflags);
+ qh->tt_buffer_dirty = 0;
+ schedule_ptds(hcd);
+ spin_unlock_irqrestore(&priv->lock, spinflags);
+}
+
+
static const struct hc_driver isp1760_hc_driver = {
.description = "isp1760-hcd",
.product_desc = "NXP ISP1760 USB Host Controller",
@@ -2064,6 +2183,7 @@ static const struct hc_driver isp1760_hc_driver = {
.get_frame_number = isp1760_get_frame,
.hub_status_data = isp1760_hub_status_data,
.hub_control = isp1760_hub_control,
+ .clear_tt_buffer_complete = isp1760_clear_tt_buffer_complete,
};
int __init init_kmem_once(void)
@@ -2102,6 +2222,7 @@ void deinit_kmem_cache(void)
struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
int irq, unsigned long irqflags,
+ int rst_gpio,
struct device *dev, const char *busname,
unsigned int devflags)
{
@@ -2121,6 +2242,7 @@ struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
priv = hcd_to_priv(hcd);
priv->devflags = devflags;
+ priv->rst_gpio = rst_gpio;
init_memory(priv);
hcd->regs = ioremap(res_start, res_len);
if (!hcd->regs) {
diff --git a/drivers/usb/host/isp1760-hcd.h b/drivers/usb/host/isp1760-hcd.h
index 014a7dfadf91..33dc79ccaa6b 100644
--- a/drivers/usb/host/isp1760-hcd.h
+++ b/drivers/usb/host/isp1760-hcd.h
@@ -4,6 +4,7 @@
/* exports for if */
struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
int irq, unsigned long irqflags,
+ int rst_gpio,
struct device *dev, const char *busname,
unsigned int devflags);
int init_kmem_once(void);
@@ -73,7 +74,6 @@ void deinit_kmem_cache(void);
#define HC_EOT_INT (1 << 3)
#define HC_SOT_INT (1 << 1)
#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT)
-#define INTERRUPT_ENABLE_SOT_MASK (HC_SOT_INT)
#define HC_ISO_IRQ_MASK_OR_REG 0x318
#define HC_INT_IRQ_MASK_OR_REG 0x31C
@@ -107,6 +107,7 @@ struct ptd {
struct slotinfo {
struct isp1760_qh *qh;
struct isp1760_qtd *qtd;
+ unsigned long timestamp;
};
@@ -126,6 +127,7 @@ typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
#define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */
#define ISP1760_FLAG_INTR_POL_HIGH 0x00000080 /* Interrupt polarity active high */
#define ISP1760_FLAG_INTR_EDGE_TRIG 0x00000100 /* Interrupt edge triggered */
+#define ISP1760_FLAG_RESET_ACTIVE_HIGH 0x80000000 /* RESET GPIO active high */
/* chip memory management */
struct memory_chunk {
@@ -188,6 +190,7 @@ struct memory_chunk {
#define DW3_BABBLE_BIT (1 << 29)
#define DW3_HALT_BIT (1 << 30)
#define DW3_ACTIVE_BIT (1 << 31)
+#define FROM_DW3_ACTIVE(x) (((x) >> 31) & 0x01)
#define INT_UNDERRUN (1 << 2)
#define INT_BABBLE (1 << 1)
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
index 7ee30056f373..2c7fc830c9e4 100644
--- a/drivers/usb/host/isp1760-if.c
+++ b/drivers/usb/host/isp1760-if.c
@@ -17,19 +17,28 @@
#include "isp1760-hcd.h"
-#ifdef CONFIG_PPC_OF
+#ifdef CONFIG_OF
+#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
#endif
#ifdef CONFIG_PCI
#include <linux/pci.h>
#endif
-#ifdef CONFIG_PPC_OF
+#ifdef CONFIG_OF
+struct isp1760 {
+ struct usb_hcd *hcd;
+ int rst_gpio;
+};
+
static int of_isp1760_probe(struct platform_device *dev)
{
- struct usb_hcd *hcd;
+ struct isp1760 *drvdata;
struct device_node *dp = dev->dev.of_node;
struct resource *res;
struct resource memory;
@@ -39,6 +48,11 @@ static int of_isp1760_probe(struct platform_device *dev)
int ret;
const unsigned int *prop;
unsigned int devflags = 0;
+ enum of_gpio_flags gpio_flags;
+
+ drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
ret = of_address_to_resource(dp, 0, &memory);
if (ret)
@@ -78,32 +92,57 @@ static int of_isp1760_probe(struct platform_device *dev)
if (of_get_property(dp, "dreq-polarity", NULL) != NULL)
devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
- hcd = isp1760_register(memory.start, res_len, virq,
- IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev_name(&dev->dev),
- devflags);
- if (IS_ERR(hcd)) {
- ret = PTR_ERR(hcd);
- goto release_reg;
+ drvdata->rst_gpio = of_get_gpio_flags(dp, 0, &gpio_flags);
+ if (gpio_is_valid(drvdata->rst_gpio)) {
+ ret = gpio_request(drvdata->rst_gpio, dev_name(&dev->dev));
+ if (!ret) {
+ if (!(gpio_flags & OF_GPIO_ACTIVE_LOW)) {
+ devflags |= ISP1760_FLAG_RESET_ACTIVE_HIGH;
+ gpio_direction_output(drvdata->rst_gpio, 0);
+ } else {
+ gpio_direction_output(drvdata->rst_gpio, 1);
+ }
+ } else {
+ drvdata->rst_gpio = ret;
+ }
}
- dev_set_drvdata(&dev->dev, hcd);
+ drvdata->hcd = isp1760_register(memory.start, res_len, virq,
+ IRQF_SHARED, drvdata->rst_gpio,
+ &dev->dev, dev_name(&dev->dev),
+ devflags);
+ if (IS_ERR(drvdata->hcd)) {
+ ret = PTR_ERR(drvdata->hcd);
+ goto free_gpio;
+ }
+
+ dev_set_drvdata(&dev->dev, drvdata);
return ret;
+free_gpio:
+ if (gpio_is_valid(drvdata->rst_gpio))
+ gpio_free(drvdata->rst_gpio);
release_reg:
release_mem_region(memory.start, res_len);
+ kfree(drvdata);
return ret;
}
static int of_isp1760_remove(struct platform_device *dev)
{
- struct usb_hcd *hcd = dev_get_drvdata(&dev->dev);
+ struct isp1760 *drvdata = dev_get_drvdata(&dev->dev);
dev_set_drvdata(&dev->dev, NULL);
- usb_remove_hcd(hcd);
- iounmap(hcd->regs);
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
- usb_put_hcd(hcd);
+ usb_remove_hcd(drvdata->hcd);
+ iounmap(drvdata->hcd->regs);
+ release_mem_region(drvdata->hcd->rsrc_start, drvdata->hcd->rsrc_len);
+ usb_put_hcd(drvdata->hcd);
+
+ if (gpio_is_valid(drvdata->rst_gpio))
+ gpio_free(drvdata->rst_gpio);
+
+ kfree(drvdata);
return 0;
}
@@ -240,7 +279,7 @@ static int __devinit isp1761_pci_probe(struct pci_dev *dev,
dev->dev.dma_mask = NULL;
hcd = isp1760_register(pci_mem_phy0, memlength, dev->irq,
- IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev_name(&dev->dev),
+ IRQF_SHARED, -ENOENT, &dev->dev, dev_name(&dev->dev),
devflags);
if (IS_ERR(hcd)) {
ret_status = -ENODEV;
@@ -313,7 +352,7 @@ static int __devinit isp1760_plat_probe(struct platform_device *pdev)
resource_size_t mem_size;
struct isp1760_platform_data *priv = pdev->dev.platform_data;
unsigned int devflags = 0;
- unsigned long irqflags = IRQF_SHARED | IRQF_DISABLED;
+ unsigned long irqflags = IRQF_SHARED;
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem_res) {
@@ -351,7 +390,8 @@ static int __devinit isp1760_plat_probe(struct platform_device *pdev)
}
hcd = isp1760_register(mem_res->start, mem_size, irq_res->start,
- irqflags, &pdev->dev, dev_name(&pdev->dev), devflags);
+ irqflags, -ENOENT,
+ &pdev->dev, dev_name(&pdev->dev), devflags);
if (IS_ERR(hcd)) {
pr_warning("isp1760: Failed to register the HCD device\n");
ret = -ENODEV;
@@ -396,7 +436,7 @@ static int __init isp1760_init(void)
ret = platform_driver_register(&isp1760_plat_driver);
if (!ret)
any_ret = 0;
-#ifdef CONFIG_PPC_OF
+#ifdef CONFIG_OF
ret = platform_driver_register(&isp1760_of_driver);
if (!ret)
any_ret = 0;
@@ -416,7 +456,7 @@ module_init(isp1760_init);
static void __exit isp1760_exit(void)
{
platform_driver_unregister(&isp1760_plat_driver);
-#ifdef CONFIG_PPC_OF
+#ifdef CONFIG_OF
platform_driver_unregister(&isp1760_of_driver);
#endif
#ifdef CONFIG_PCI
diff --git a/drivers/usb/host/ohci-ath79.c b/drivers/usb/host/ohci-ath79.c
index c620c50f6770..18d574d6958b 100644
--- a/drivers/usb/host/ohci-ath79.c
+++ b/drivers/usb/host/ohci-ath79.c
@@ -111,7 +111,7 @@ static int ohci_ath79_probe(struct platform_device *pdev)
ohci_hcd_init(hcd_to_ohci(hcd));
- ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+ ret = usb_add_hcd(hcd, irq, 0);
if (ret)
goto err_stop_hcd;
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index 958d985f2951..6b7bc50dfeaa 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -218,7 +218,7 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
ohci_hcd_init(hcd_to_ohci(hcd));
ret = usb_add_hcd(hcd, pdev->resource[1].start,
- IRQF_DISABLED | IRQF_SHARED);
+ IRQF_SHARED);
if (ret == 0) {
platform_set_drvdata(pdev, hcd);
return ret;
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c
index 6aca2c4453f7..843509778a33 100644
--- a/drivers/usb/host/ohci-da8xx.c
+++ b/drivers/usb/host/ohci-da8xx.c
@@ -344,7 +344,7 @@ static int usb_hcd_da8xx_probe(const struct hc_driver *driver,
error = -ENODEV;
goto err4;
}
- error = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+ error = usb_add_hcd(hcd, irq, 0);
if (error)
goto err4;
diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
index 4e681613e7ae..dc45d489d00e 100644
--- a/drivers/usb/host/ohci-ep93xx.c
+++ b/drivers/usb/host/ohci-ep93xx.c
@@ -81,7 +81,7 @@ static int usb_hcd_ep93xx_probe(const struct hc_driver *driver,
ohci_hcd_init(hcd_to_ohci(hcd));
- retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED);
+ retval = usb_add_hcd(hcd, pdev->resource[1].start, 0);
if (retval == 0)
return retval;
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index f9cf3f04b742..34efd479e068 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1114,6 +1114,11 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ohci_hcd_ath79_driver
#endif
+#ifdef CONFIG_NLM_XLR
+#include "ohci-xls.c"
+#define PLATFORM_DRIVER ohci_xls_driver
+#endif
+
#if !defined(PCI_DRIVER) && \
!defined(PLATFORM_DRIVER) && \
!defined(OMAP1_PLATFORM_DRIVER) && \
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 9154615292db..2f00040fc408 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -356,10 +356,7 @@ static void ohci_finish_controller_resume(struct usb_hcd *hcd)
msleep(20);
}
- /* Does the root hub have a port wakeup pending? */
- if (ohci_readl(ohci, &ohci->regs->intrstatus) &
- (OHCI_INTR_RD | OHCI_INTR_RHSC))
- usb_hcd_resume_root_hub(hcd);
+ usb_hcd_resume_root_hub(hcd);
}
/* Carry out polling-, autostop-, and autoresume-related state changes */
diff --git a/drivers/usb/host/ohci-octeon.c b/drivers/usb/host/ohci-octeon.c
index d8b45647d1dc..d469bf9b9e54 100644
--- a/drivers/usb/host/ohci-octeon.c
+++ b/drivers/usb/host/ohci-octeon.c
@@ -164,7 +164,7 @@ static int ohci_octeon_drv_probe(struct platform_device *pdev)
ohci_hcd_init(ohci);
- ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret) {
dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
goto err3;
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 5645f70b9214..e4b8782cc6e2 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -14,7 +14,7 @@
* This file is licenced under the GPL.
*/
-#include <linux/signal.h> /* IRQF_DISABLED */
+#include <linux/signal.h>
#include <linux/jiffies.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
@@ -363,7 +363,7 @@ static int usb_hcd_omap_probe (const struct hc_driver *driver,
retval = -ENXIO;
goto err3;
}
- retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+ retval = usb_add_hcd(hcd, irq, 0);
if (retval)
goto err3;
diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c
index 6048f2f64f73..516ebc4d6cc2 100644
--- a/drivers/usb/host/ohci-omap3.c
+++ b/drivers/usb/host/ohci-omap3.c
@@ -149,7 +149,7 @@ static int __devinit ohci_hcd_omap3_probe(struct platform_device *pdev)
res = platform_get_resource_byname(pdev,
IORESOURCE_MEM, "ohci");
- if (!ret) {
+ if (!res) {
dev_err(dev, "UHH OHCI get resource failed\n");
return -ENOMEM;
}
@@ -180,7 +180,7 @@ static int __devinit ohci_hcd_omap3_probe(struct platform_device *pdev)
ohci_hcd_init(hcd_to_ohci(hcd));
- ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+ ret = usb_add_hcd(hcd, irq, 0);
if (ret) {
dev_dbg(dev, "failed to add hcd with err %d\n", ret);
goto err_add_hcd;
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
index 653d6a60edb5..9ad8bee22c15 100644
--- a/drivers/usb/host/ohci-pnx4008.c
+++ b/drivers/usb/host/ohci-pnx4008.c
@@ -398,7 +398,7 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
ohci_hcd_init(ohci);
dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq);
- ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+ ret = usb_add_hcd(hcd, irq, 0);
if (ret == 0)
return ret;
diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c
index 28467e288a93..f13d08f94d6b 100644
--- a/drivers/usb/host/ohci-pnx8550.c
+++ b/drivers/usb/host/ohci-pnx8550.c
@@ -107,7 +107,7 @@ int usb_hcd_pnx8550_probe (const struct hc_driver *driver,
ohci_hcd_init(hcd_to_ohci(hcd));
- retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED);
+ retval = usb_add_hcd(hcd, dev->resource[1].start, 0);
if (retval == 0)
return retval;
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index 0c12f4e14dcd..d24cc89de16f 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -143,7 +143,7 @@ static int __devinit ohci_hcd_ppc_of_probe(struct platform_device *op)
ohci_hcd_init(ohci);
- rv = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+ rv = usb_add_hcd(hcd, irq, 0);
if (rv == 0)
return 0;
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index c0f595c44487..1514b7067470 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -80,7 +80,7 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
#endif
ohci_hcd_init(ohci);
- retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+ retval = usb_add_hcd(hcd, irq, 0);
if (retval == 0)
return retval;
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
index 700950455f4d..6fd4fa1f19bb 100644
--- a/drivers/usb/host/ohci-ps3.c
+++ b/drivers/usb/host/ohci-ps3.c
@@ -164,7 +164,7 @@ static int __devinit ps3_ohci_probe(struct ps3_system_bus_device *dev)
ps3_system_bus_set_drvdata(dev, hcd);
- result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
+ result = usb_add_hcd(hcd, virq, 0);
if (result) {
dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 80be5472783a..29dfefe1c726 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -359,7 +359,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
ohci_hcd_init(hcd_to_ohci(hcd));
- retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+ retval = usb_add_hcd(hcd, irq, 0);
if (retval == 0)
return retval;
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index dd24fc115e48..15dc51ded61a 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -428,7 +428,7 @@ static struct ed *ed_get (
ed->type = usb_pipetype(pipe);
info |= (ep->desc.bEndpointAddress & ~USB_DIR_IN) << 7;
- info |= le16_to_cpu(ep->desc.wMaxPacketSize) << 16;
+ info |= usb_endpoint_maxp(&ep->desc) << 16;
if (udev->speed == USB_SPEED_LOW)
info |= ED_LOWSPEED;
/* only control transfers store pids in tds */
@@ -444,7 +444,7 @@ static struct ed *ed_get (
ed->load = usb_calc_bus_time (
udev->speed, !is_out,
ed->type == PIPE_ISOCHRONOUS,
- le16_to_cpu(ep->desc.wMaxPacketSize))
+ usb_endpoint_maxp(&ep->desc))
/ 1000;
}
}
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index 7c9a4d55526b..a1877c47601e 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -384,7 +384,7 @@ static int usb_hcd_s3c2410_probe(const struct hc_driver *driver,
ohci_hcd_init(hcd_to_ohci(hcd));
- retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED);
+ retval = usb_add_hcd(hcd, dev->resource[1].start, 0);
if (retval != 0)
goto err_ioremap;
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index 4204d9720d23..4bde4f9821ba 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -143,7 +143,7 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver,
sa1111_start_hc(dev);
ohci_hcd_init(hcd_to_ohci(hcd));
- retval = usb_add_hcd(hcd, dev->irq[1], IRQF_DISABLED);
+ retval = usb_add_hcd(hcd, dev->irq[1], 0);
if (retval == 0)
return retval;
diff --git a/drivers/usb/host/ohci-sh.c b/drivers/usb/host/ohci-sh.c
index 14cecb52a9fe..afc4eb6bb9d0 100644
--- a/drivers/usb/host/ohci-sh.c
+++ b/drivers/usb/host/ohci-sh.c
@@ -109,7 +109,7 @@ static int ohci_hcd_sh_probe(struct platform_device *pdev)
hcd->regs = (void __iomem *)res->start;
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
- ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret != 0) {
err("Failed to add hcd");
usb_put_hcd(hcd);
diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c
index 78918ca0da23..968cea2b6d4e 100644
--- a/drivers/usb/host/ohci-sm501.c
+++ b/drivers/usb/host/ohci-sm501.c
@@ -165,7 +165,7 @@ static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev)
ohci_hcd_init(hcd_to_ohci(hcd));
- retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (retval)
goto err5;
diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c
index 4fd4bea9ac7a..69874654f3b5 100644
--- a/drivers/usb/host/ohci-spear.c
+++ b/drivers/usb/host/ohci-spear.c
@@ -152,7 +152,7 @@ static int spear_ohci_hcd_drv_probe(struct platform_device *pdev)
spear_start_ohci(ohci_p);
ohci_hcd_init(hcd_to_ohci(hcd));
- retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), IRQF_DISABLED);
+ retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), 0);
if (retval == 0)
return retval;
diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c
index c4aea3b8315e..5ba18595d6f7 100644
--- a/drivers/usb/host/ohci-ssb.c
+++ b/drivers/usb/host/ohci-ssb.c
@@ -169,7 +169,7 @@ static int ssb_ohci_attach(struct ssb_device *dev)
hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
if (!hcd->regs)
goto err_put_hcd;
- err = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED);
+ err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED);
if (err)
goto err_iounmap;
diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c
index 57ad1271fc9b..06331d931171 100644
--- a/drivers/usb/host/ohci-tmio.c
+++ b/drivers/usb/host/ohci-tmio.c
@@ -244,7 +244,7 @@ static int __devinit ohci_hcd_tmio_drv_probe(struct platform_device *dev)
ohci = hcd_to_ohci(hcd);
ohci_hcd_init(ohci);
- ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+ ret = usb_add_hcd(hcd, irq, 0);
if (ret)
goto err_add_hcd;
diff --git a/drivers/usb/host/ohci-xls.c b/drivers/usb/host/ohci-xls.c
new file mode 100644
index 000000000000..a3a9c6f45b91
--- /dev/null
+++ b/drivers/usb/host/ohci-xls.c
@@ -0,0 +1,151 @@
+/*
+ * OHCI HCD for Netlogic XLS processors.
+ *
+ * (C) Copyright 2011 Netlogic Microsystems Inc.
+ *
+ * Based on ohci-au1xxx.c, and other Linux OHCI drivers.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/signal.h>
+
+static int ohci_xls_probe_internal(const struct hc_driver *driver,
+ struct platform_device *dev)
+{
+ struct resource *res;
+ struct usb_hcd *hcd;
+ int retval, irq;
+
+ /* Get our IRQ from an earlier registered Platform Resource */
+ irq = platform_get_irq(dev, 0);
+ if (irq < 0) {
+ dev_err(&dev->dev, "Found HC with no IRQ\n");
+ return -ENODEV;
+ }
+
+ /* Get our Memory Handle */
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&dev->dev, "MMIO Handle incorrect!\n");
+ return -ENODEV;
+ }
+
+ hcd = usb_create_hcd(driver, &dev->dev, "XLS");
+ if (!hcd) {
+ retval = -ENOMEM;
+ goto err1;
+ }
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = res->end - res->start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+ driver->description)) {
+ dev_dbg(&dev->dev, "Controller already in use\n");
+ retval = -EBUSY;
+ goto err2;
+ }
+
+ hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+ if (hcd->regs == NULL) {
+ dev_dbg(&dev->dev, "error mapping memory\n");
+ retval = -EFAULT;
+ goto err3;
+ }
+
+ retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ if (retval != 0)
+ goto err4;
+ return retval;
+
+err4:
+ iounmap(hcd->regs);
+err3:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err2:
+ usb_put_hcd(hcd);
+err1:
+ dev_err(&dev->dev, "init fail, %d\n", retval);
+ return retval;
+}
+
+static int ohci_xls_reset(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+ ohci_hcd_init(ohci);
+ return ohci_init(ohci);
+}
+
+static int __devinit ohci_xls_start(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci;
+ int ret;
+
+ ohci = hcd_to_ohci(hcd);
+ ret = ohci_run(ohci);
+ if (ret < 0) {
+ err("can't start %s", hcd->self.bus_name);
+ ohci_stop(hcd);
+ return ret;
+ }
+ return 0;
+}
+
+static struct hc_driver ohci_xls_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "XLS OHCI Host Controller",
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+ .irq = ohci_irq,
+ .flags = HCD_MEMORY | HCD_USB11,
+ .reset = ohci_xls_reset,
+ .start = ohci_xls_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+ .get_frame_number = ohci_get_frame,
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+#ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+#endif
+ .start_port_reset = ohci_start_port_reset,
+};
+
+static int ohci_xls_probe(struct platform_device *dev)
+{
+ int ret;
+
+ pr_debug("In ohci_xls_probe");
+ if (usb_disabled())
+ return -ENODEV;
+ ret = ohci_xls_probe_internal(&ohci_xls_hc_driver, dev);
+ return ret;
+}
+
+static int ohci_xls_remove(struct platform_device *dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+ return 0;
+}
+
+static struct platform_driver ohci_xls_driver = {
+ .probe = ohci_xls_probe,
+ .remove = ohci_xls_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+ .driver = {
+ .name = "ohci-xls-0",
+ .owner = THIS_MODULE,
+ },
+};
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 40a0d8b03ad7..e84ca1928dbf 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -959,7 +959,7 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb,
info.pipenum = get_empty_pipenum(r8a66597, ep);
info.address = get_urb_to_r8a66597_addr(r8a66597, urb);
info.epnum = usb_endpoint_num(ep);
- info.maxpacket = le16_to_cpu(ep->wMaxPacketSize);
+ info.maxpacket = usb_endpoint_maxp(ep);
info.type = get_r8a66597_type(usb_endpoint_type(ep));
info.bufnum = get_bufnum(info.pipenum);
info.buf_bsize = get_buf_bsize(info.pipenum);
@@ -2519,7 +2519,7 @@ static int __devinit r8a66597_probe(struct platform_device *pdev)
hcd->rsrc_start = res->start;
hcd->has_tt = 1;
- ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | irq_trigger);
+ ret = usb_add_hcd(hcd, irq, irq_trigger);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to add hcd\n");
goto clean_up3;
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 1a996245ab98..961d6638d8f9 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -1729,7 +1729,7 @@ sl811h_probe(struct platform_device *dev)
* Use resource IRQ flags if set by platform device setup.
*/
irqflags |= IRQF_SHARED;
- retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | irqflags);
+ retval = usb_add_hcd(hcd, irq, irqflags);
if (retval != 0)
goto err6;
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index fba99b120588..c8ae199cfbb8 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -294,50 +294,50 @@ __acquires(uhci->lock)
* and that remote wakeups should be enabled.
*/
egsm_enable = USBCMD_EGSM;
- uhci->RD_enable = 1;
int_enable = USBINTR_RESUME;
wakeup_enable = 1;
- /* In auto-stop mode wakeups must always be detected, but
- * Resume-Detect interrupts may be prohibited. (In the absence
- * of CONFIG_PM, they are always disallowed.)
+ /*
+ * In auto-stop mode, we must be able to detect new connections.
+ * The user can force us to poll by disabling remote wakeup;
+ * otherwise we will use the EGSM/RD mechanism.
*/
if (auto_stop) {
if (!device_may_wakeup(&rhdev->dev))
- int_enable = 0;
+ egsm_enable = int_enable = 0;
+ }
- /* In bus-suspend mode wakeups may be disabled, but if they are
- * allowed then so are Resume-Detect interrupts.
- */
- } else {
#ifdef CONFIG_PM
+ /*
+ * In bus-suspend mode, we use the wakeup setting specified
+ * for the root hub.
+ */
+ else {
if (!rhdev->do_remote_wakeup)
wakeup_enable = 0;
-#endif
}
+#endif
- /* EGSM causes the root hub to echo a 'K' signal (resume) out any
- * port which requests a remote wakeup. According to the USB spec,
- * every hub is supposed to do this. But if we are ignoring
- * remote-wakeup requests anyway then there's no point to it.
- * We also shouldn't enable EGSM if it's broken.
- */
- if (!wakeup_enable || global_suspend_mode_is_broken(uhci))
- egsm_enable = 0;
-
- /* If we're ignoring wakeup events then there's no reason to
- * enable Resume-Detect interrupts. We also shouldn't enable
- * them if they are broken or disallowed.
+ /*
+ * UHCI doesn't distinguish between wakeup requests from downstream
+ * devices and local connect/disconnect events. There's no way to
+ * enable one without the other; both are controlled by EGSM. Thus
+ * if wakeups are disallowed then EGSM must be turned off -- in which
+ * case remote wakeup requests from downstream during system sleep
+ * will be lost.
+ *
+ * In addition, if EGSM is broken then we can't use it. Likewise,
+ * if Resume-Detect interrupts are broken then we can't use them.
*
- * This logic may lead us to enabling RD but not EGSM. The UHCI
- * spec foolishly says that RD works only when EGSM is on, but
- * there's no harm in enabling it anyway -- perhaps some chips
- * will implement it!
+ * Finally, neither EGSM nor RD is useful by itself. Without EGSM,
+ * the RD status bit will never get set. Without RD, the controller
+ * won't generate interrupts to tell the system about wakeup events.
*/
- if (!wakeup_enable || resume_detect_interrupts_are_broken(uhci) ||
- !int_enable)
- uhci->RD_enable = int_enable = 0;
+ if (!wakeup_enable || global_suspend_mode_is_broken(uhci) ||
+ resume_detect_interrupts_are_broken(uhci))
+ egsm_enable = int_enable = 0;
+ uhci->RD_enable = !!int_enable;
uhci_writew(uhci, int_enable, USBINTR);
uhci_writew(uhci, egsm_enable | USBCMD_CF, USBCMD);
mb();
@@ -364,10 +364,12 @@ __acquires(uhci->lock)
uhci->rh_state = new_state;
uhci->is_stopped = UHCI_IS_STOPPED;
- /* If interrupts don't work and remote wakeup is enabled then
- * the suspended root hub needs to be polled.
+ /*
+ * If remote wakeup is enabled but either EGSM or RD interrupts
+ * doesn't work, then we won't get an interrupt when a wakeup event
+ * occurs. Thus the suspended root hub needs to be polled.
*/
- if (!int_enable && wakeup_enable)
+ if (wakeup_enable && (!int_enable || !egsm_enable))
set_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags);
else
clear_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags);
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 84ed28b34f93..f6ca80ee4cec 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -280,7 +280,7 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
qh->load = usb_calc_bus_time(udev->speed,
usb_endpoint_dir_in(&hep->desc),
qh->type == USB_ENDPOINT_XFER_ISOC,
- le16_to_cpu(hep->desc.wMaxPacketSize))
+ usb_endpoint_maxp(&hep->desc))
/ 1000 + 1;
} else { /* Skeleton QH */
@@ -792,7 +792,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
{
struct uhci_td *td;
unsigned long destination, status;
- int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
+ int maxsze = usb_endpoint_maxp(&qh->hep->desc);
int len = urb->transfer_buffer_length;
dma_addr_t data = urb->transfer_dma;
__hc32 *plink;
@@ -918,7 +918,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
{
struct uhci_td *td;
unsigned long destination, status;
- int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
+ int maxsze = usb_endpoint_maxp(&qh->hep->desc);
int len = urb->transfer_buffer_length;
int this_sg_len;
dma_addr_t data;
diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h
index ce5c9e51748e..c7f33123d4c0 100644
--- a/drivers/usb/host/xhci-ext-caps.h
+++ b/drivers/usb/host/xhci-ext-caps.h
@@ -65,6 +65,12 @@
/* bits 1:2, 5:12, and 17:19 need to be preserved; bits 21:28 should be zero */
#define XHCI_LEGACY_DISABLE_SMI ((0x3 << 1) + (0xff << 5) + (0x7 << 17))
+/* USB 2.0 xHCI 0.96 L1C capability - section 7.2.2.1.3.2 */
+#define XHCI_L1C (1 << 16)
+
+/* USB 2.0 xHCI 1.0 hardware LMP capability - section 7.2.2.1.3.2 */
+#define XHCI_HLC (1 << 19)
+
/* command register values to disable interrupts and halt the HC */
/* start/stop HC execution - do not write unless HC is halted*/
#define XHCI_CMD_RUN (1 << 0)
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 0be788cc2fdb..431efe72b1f7 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -28,6 +28,25 @@
#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \
PORT_RC | PORT_PLC | PORT_PE)
+/* usb 1.1 root hub device descriptor */
+static u8 usb_bos_descriptor [] = {
+ USB_DT_BOS_SIZE, /* __u8 bLength, 5 bytes */
+ USB_DT_BOS, /* __u8 bDescriptorType */
+ 0x0F, 0x00, /* __le16 wTotalLength, 15 bytes */
+ 0x1, /* __u8 bNumDeviceCaps */
+ /* First device capability */
+ USB_DT_USB_SS_CAP_SIZE, /* __u8 bLength, 10 bytes */
+ USB_DT_DEVICE_CAPABILITY, /* Device Capability */
+ USB_SS_CAP_TYPE, /* bDevCapabilityType, SUPERSPEED_USB */
+ 0x00, /* bmAttributes, LTM off by default */
+ USB_5GBPS_OPERATION, 0x00, /* wSpeedsSupported, 5Gbps only */
+ 0x03, /* bFunctionalitySupport,
+ USB 3.0 speed only */
+ 0x00, /* bU1DevExitLat, set later. */
+ 0x00, 0x00 /* __le16 bU2DevExitLat, set later. */
+};
+
+
static void xhci_common_hub_descriptor(struct xhci_hcd *xhci,
struct usb_hub_descriptor *desc, int ports)
{
@@ -232,7 +251,7 @@ int xhci_find_slot_id_by_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
continue;
speed = xhci->devs[i]->udev->speed;
if (((speed == USB_SPEED_SUPER) == (hcd->speed == HCD_USB3))
- && xhci->devs[i]->port == port) {
+ && xhci->devs[i]->fake_port == port) {
slot_id = i;
break;
}
@@ -392,13 +411,39 @@ static int xhci_get_ports(struct usb_hcd *hcd, __le32 __iomem ***port_array)
return max_ports;
}
+void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
+ int port_id, u32 link_state)
+{
+ u32 temp;
+
+ temp = xhci_readl(xhci, port_array[port_id]);
+ temp = xhci_port_state_to_neutral(temp);
+ temp &= ~PORT_PLS_MASK;
+ temp |= PORT_LINK_STROBE | link_state;
+ xhci_writel(xhci, temp, port_array[port_id]);
+}
+
+/* Test and clear port RWC bit */
+void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
+ int port_id, u32 port_bit)
+{
+ u32 temp;
+
+ temp = xhci_readl(xhci, port_array[port_id]);
+ if (temp & port_bit) {
+ temp = xhci_port_state_to_neutral(temp);
+ temp |= port_bit;
+ xhci_writel(xhci, temp, port_array[port_id]);
+ }
+}
+
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
int max_ports;
unsigned long flags;
- u32 temp, temp1, status;
+ u32 temp, status;
int retval = 0;
__le32 __iomem **port_array;
int slot_id;
@@ -429,6 +474,21 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
xhci_hub_descriptor(hcd, xhci,
(struct usb_hub_descriptor *) buf);
break;
+ case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+ if ((wValue & 0xff00) != (USB_DT_BOS << 8))
+ goto error;
+
+ if (hcd->speed != HCD_USB3)
+ goto error;
+
+ memcpy(buf, &usb_bos_descriptor,
+ USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE);
+ temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3);
+ buf[12] = HCS_U1_LATENCY(temp);
+ put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]);
+
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE;
case GetPortStatus:
if (!wIndex || wIndex > max_ports)
goto error;
@@ -463,19 +523,17 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
&& (temp & PORT_POWER))
status |= USB_PORT_STAT_SUSPEND;
}
- if ((temp & PORT_PLS_MASK) == XDEV_RESUME) {
+ if ((temp & PORT_PLS_MASK) == XDEV_RESUME &&
+ !DEV_SUPERSPEED(temp)) {
if ((temp & PORT_RESET) || !(temp & PORT_PE))
goto error;
- if (!DEV_SUPERSPEED(temp) && time_after_eq(jiffies,
- bus_state->resume_done[wIndex])) {
+ if (time_after_eq(jiffies,
+ bus_state->resume_done[wIndex])) {
xhci_dbg(xhci, "Resume USB2 port %d\n",
wIndex + 1);
bus_state->resume_done[wIndex] = 0;
- temp1 = xhci_port_state_to_neutral(temp);
- temp1 &= ~PORT_PLS_MASK;
- temp1 |= PORT_LINK_STROBE | XDEV_U0;
- xhci_writel(xhci, temp1, port_array[wIndex]);
-
+ xhci_set_link_state(xhci, port_array, wIndex,
+ XDEV_U0);
xhci_dbg(xhci, "set port %d resume\n",
wIndex + 1);
slot_id = xhci_find_slot_id_by_port(hcd, xhci,
@@ -487,6 +545,14 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
xhci_ring_device(xhci, slot_id);
bus_state->port_c_suspend |= 1 << wIndex;
bus_state->suspended_ports &= ~(1 << wIndex);
+ } else {
+ /*
+ * The resume has been signaling for less than
+ * 20ms. Report the port status as SUSPEND,
+ * let the usbcore check port status again
+ * and clear resume signaling later.
+ */
+ status |= USB_PORT_STAT_SUSPEND;
}
}
if ((temp & PORT_PLS_MASK) == XDEV_U0
@@ -542,10 +608,19 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
temp = xhci_readl(xhci, port_array[wIndex]);
+ if ((temp & PORT_PLS_MASK) != XDEV_U0) {
+ /* Resume the port to U0 first */
+ xhci_set_link_state(xhci, port_array, wIndex,
+ XDEV_U0);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ msleep(10);
+ spin_lock_irqsave(&xhci->lock, flags);
+ }
/* In spec software should not attempt to suspend
* a port unless the port reports that it is in the
* enabled (PED = ‘1’,PLS < ‘3’) state.
*/
+ temp = xhci_readl(xhci, port_array[wIndex]);
if ((temp & PORT_PE) == 0 || (temp & PORT_RESET)
|| (temp & PORT_PLS_MASK) >= XDEV_U3) {
xhci_warn(xhci, "USB core suspending device "
@@ -564,10 +639,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
xhci_stop_device(xhci, slot_id, 1);
spin_lock_irqsave(&xhci->lock, flags);
- temp = xhci_port_state_to_neutral(temp);
- temp &= ~PORT_PLS_MASK;
- temp |= PORT_LINK_STROBE | XDEV_U3;
- xhci_writel(xhci, temp, port_array[wIndex]);
+ xhci_set_link_state(xhci, port_array, wIndex, XDEV_U3);
spin_unlock_irqrestore(&xhci->lock, flags);
msleep(10); /* wait device to enter */
@@ -601,10 +673,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
}
}
- temp = xhci_port_state_to_neutral(temp);
- temp &= ~PORT_PLS_MASK;
- temp |= PORT_LINK_STROBE | link_state;
- xhci_writel(xhci, temp, port_array[wIndex]);
+ xhci_set_link_state(xhci, port_array, wIndex,
+ link_state);
spin_unlock_irqrestore(&xhci->lock, flags);
msleep(20); /* wait device to enter */
@@ -664,28 +734,17 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
xhci_dbg(xhci, "PORTSC %04x\n", temp);
if (temp & PORT_RESET)
goto error;
- if (temp & XDEV_U3) {
+ if ((temp & PORT_PLS_MASK) == XDEV_U3) {
if ((temp & PORT_PE) == 0)
goto error;
- temp = xhci_port_state_to_neutral(temp);
- temp &= ~PORT_PLS_MASK;
- temp |= PORT_LINK_STROBE | XDEV_RESUME;
- xhci_writel(xhci, temp,
- port_array[wIndex]);
-
- spin_unlock_irqrestore(&xhci->lock,
- flags);
+ xhci_set_link_state(xhci, port_array, wIndex,
+ XDEV_RESUME);
+ spin_unlock_irqrestore(&xhci->lock, flags);
msleep(20);
spin_lock_irqsave(&xhci->lock, flags);
-
- temp = xhci_readl(xhci,
- port_array[wIndex]);
- temp = xhci_port_state_to_neutral(temp);
- temp &= ~PORT_PLS_MASK;
- temp |= PORT_LINK_STROBE | XDEV_U0;
- xhci_writel(xhci, temp,
- port_array[wIndex]);
+ xhci_set_link_state(xhci, port_array, wIndex,
+ XDEV_U0);
}
bus_state->port_c_suspend |= 1 << wIndex;
@@ -752,7 +811,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
memset(buf, 0, retval);
status = 0;
- mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC;
+ mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC;
spin_lock_irqsave(&xhci->lock, flags);
/* For each port, did anything change? If so, set that bit in buf. */
@@ -901,25 +960,18 @@ int xhci_bus_resume(struct usb_hcd *hcd)
if (test_bit(port_index, &bus_state->bus_suspended) &&
(temp & PORT_PLS_MASK)) {
if (DEV_SUPERSPEED(temp)) {
- temp = xhci_port_state_to_neutral(temp);
- temp &= ~PORT_PLS_MASK;
- temp |= PORT_LINK_STROBE | XDEV_U0;
- xhci_writel(xhci, temp, port_array[port_index]);
+ xhci_set_link_state(xhci, port_array,
+ port_index, XDEV_U0);
} else {
- temp = xhci_port_state_to_neutral(temp);
- temp &= ~PORT_PLS_MASK;
- temp |= PORT_LINK_STROBE | XDEV_RESUME;
- xhci_writel(xhci, temp, port_array[port_index]);
+ xhci_set_link_state(xhci, port_array,
+ port_index, XDEV_RESUME);
spin_unlock_irqrestore(&xhci->lock, flags);
msleep(20);
spin_lock_irqsave(&xhci->lock, flags);
- temp = xhci_readl(xhci, port_array[port_index]);
- temp = xhci_port_state_to_neutral(temp);
- temp &= ~PORT_PLS_MASK;
- temp |= PORT_LINK_STROBE | XDEV_U0;
- xhci_writel(xhci, temp, port_array[port_index]);
+ xhci_set_link_state(xhci, port_array,
+ port_index, XDEV_U0);
}
/* wait for the port to enter U0 and report port link
* state change.
@@ -929,12 +981,8 @@ int xhci_bus_resume(struct usb_hcd *hcd)
spin_lock_irqsave(&xhci->lock, flags);
/* Clear PLC */
- temp = xhci_readl(xhci, port_array[port_index]);
- if (temp & PORT_PLC) {
- temp = xhci_port_state_to_neutral(temp);
- temp |= PORT_PLC;
- xhci_writel(xhci, temp, port_array[port_index]);
- }
+ xhci_test_and_clear_bit(xhci, port_array, port_index,
+ PORT_PLC);
slot_id = xhci_find_slot_id_by_port(hcd,
xhci, port_index + 1);
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index d446886b22b0..42a22b8e6922 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -61,8 +61,6 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, gfp_t flag
static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg)
{
- if (!seg)
- return;
if (seg->trbs) {
xhci_dbg(xhci, "Freeing DMA segment at %p (virtual) 0x%llx (DMA)\n",
seg->trbs, (unsigned long long)seg->dma);
@@ -81,7 +79,7 @@ static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg)
* related flags, such as End TRB, Toggle Cycle, and no snoop.
*/
static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
- struct xhci_segment *next, bool link_trbs)
+ struct xhci_segment *next, bool link_trbs, bool isoc)
{
u32 val;
@@ -97,7 +95,9 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
val &= ~TRB_TYPE_BITMASK;
val |= TRB_TYPE(TRB_LINK);
/* Always set the chain bit with 0.95 hardware */
- if (xhci_link_trb_quirk(xhci))
+ /* Set chain bit for isoc rings on AMD 0.96 host */
+ if (xhci_link_trb_quirk(xhci) ||
+ (isoc && (xhci->quirks & XHCI_AMD_0x96_HOST)))
val |= TRB_CHAIN;
prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val);
}
@@ -112,18 +112,20 @@ void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring)
struct xhci_segment *seg;
struct xhci_segment *first_seg;
- if (!ring || !ring->first_seg)
+ if (!ring)
return;
- first_seg = ring->first_seg;
- seg = first_seg->next;
- xhci_dbg(xhci, "Freeing ring at %p\n", ring);
- while (seg != first_seg) {
- struct xhci_segment *next = seg->next;
- xhci_segment_free(xhci, seg);
- seg = next;
+ if (ring->first_seg) {
+ first_seg = ring->first_seg;
+ seg = first_seg->next;
+ xhci_dbg(xhci, "Freeing ring at %p\n", ring);
+ while (seg != first_seg) {
+ struct xhci_segment *next = seg->next;
+ xhci_segment_free(xhci, seg);
+ seg = next;
+ }
+ xhci_segment_free(xhci, first_seg);
+ ring->first_seg = NULL;
}
- xhci_segment_free(xhci, first_seg);
- ring->first_seg = NULL;
kfree(ring);
}
@@ -152,7 +154,7 @@ static void xhci_initialize_ring_info(struct xhci_ring *ring)
* See section 4.9.1 and figures 15 and 16.
*/
static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
- unsigned int num_segs, bool link_trbs, gfp_t flags)
+ unsigned int num_segs, bool link_trbs, bool isoc, gfp_t flags)
{
struct xhci_ring *ring;
struct xhci_segment *prev;
@@ -178,12 +180,12 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
next = xhci_segment_alloc(xhci, flags);
if (!next)
goto fail;
- xhci_link_segments(xhci, prev, next, link_trbs);
+ xhci_link_segments(xhci, prev, next, link_trbs, isoc);
prev = next;
num_segs--;
}
- xhci_link_segments(xhci, prev, ring->first_seg, link_trbs);
+ xhci_link_segments(xhci, prev, ring->first_seg, link_trbs, isoc);
if (link_trbs) {
/* See section 4.9.2.1 and 6.4.4.1 */
@@ -229,14 +231,14 @@ void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
* pointers to the beginning of the ring.
*/
static void xhci_reinit_cached_ring(struct xhci_hcd *xhci,
- struct xhci_ring *ring)
+ struct xhci_ring *ring, bool isoc)
{
struct xhci_segment *seg = ring->first_seg;
do {
memset(seg->trbs, 0,
sizeof(union xhci_trb)*TRBS_PER_SEGMENT);
/* All endpoint rings have link TRBs */
- xhci_link_segments(xhci, seg, seg->next, 1);
+ xhci_link_segments(xhci, seg, seg->next, 1, isoc);
seg = seg->next;
} while (seg != ring->first_seg);
xhci_initialize_ring_info(ring);
@@ -315,7 +317,7 @@ static void xhci_free_stream_ctx(struct xhci_hcd *xhci,
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
if (num_stream_ctxs > MEDIUM_STREAM_ARRAY_SIZE)
- pci_free_consistent(pdev,
+ dma_free_coherent(&pdev->dev,
sizeof(struct xhci_stream_ctx)*num_stream_ctxs,
stream_ctx, dma);
else if (num_stream_ctxs <= SMALL_STREAM_ARRAY_SIZE)
@@ -343,9 +345,9 @@ static struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci,
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
if (num_stream_ctxs > MEDIUM_STREAM_ARRAY_SIZE)
- return pci_alloc_consistent(pdev,
+ return dma_alloc_coherent(&pdev->dev,
sizeof(struct xhci_stream_ctx)*num_stream_ctxs,
- dma);
+ dma, mem_flags);
else if (num_stream_ctxs <= SMALL_STREAM_ARRAY_SIZE)
return dma_pool_alloc(xhci->small_streams_pool,
mem_flags, dma);
@@ -540,7 +542,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
*/
for (cur_stream = 1; cur_stream < num_streams; cur_stream++) {
stream_info->stream_rings[cur_stream] =
- xhci_ring_alloc(xhci, 1, true, mem_flags);
+ xhci_ring_alloc(xhci, 1, true, false, mem_flags);
cur_ring = stream_info->stream_rings[cur_stream];
if (!cur_ring)
goto cleanup_rings;
@@ -687,11 +689,103 @@ static void xhci_init_endpoint_timer(struct xhci_hcd *xhci,
ep->xhci = xhci;
}
-/* All the xhci_tds in the ring's TD list should be freed at this point */
+static void xhci_free_tt_info(struct xhci_hcd *xhci,
+ struct xhci_virt_device *virt_dev,
+ int slot_id)
+{
+ struct list_head *tt;
+ struct list_head *tt_list_head;
+ struct list_head *tt_next;
+ struct xhci_tt_bw_info *tt_info;
+
+ /* If the device never made it past the Set Address stage,
+ * it may not have the real_port set correctly.
+ */
+ if (virt_dev->real_port == 0 ||
+ virt_dev->real_port > HCS_MAX_PORTS(xhci->hcs_params1)) {
+ xhci_dbg(xhci, "Bad real port.\n");
+ return;
+ }
+
+ tt_list_head = &(xhci->rh_bw[virt_dev->real_port - 1].tts);
+ if (list_empty(tt_list_head))
+ return;
+
+ list_for_each(tt, tt_list_head) {
+ tt_info = list_entry(tt, struct xhci_tt_bw_info, tt_list);
+ if (tt_info->slot_id == slot_id)
+ break;
+ }
+ /* Cautionary measure in case the hub was disconnected before we
+ * stored the TT information.
+ */
+ if (tt_info->slot_id != slot_id)
+ return;
+
+ tt_next = tt->next;
+ tt_info = list_entry(tt, struct xhci_tt_bw_info,
+ tt_list);
+ /* Multi-TT hubs will have more than one entry */
+ do {
+ list_del(tt);
+ kfree(tt_info);
+ tt = tt_next;
+ if (list_empty(tt_list_head))
+ break;
+ tt_next = tt->next;
+ tt_info = list_entry(tt, struct xhci_tt_bw_info,
+ tt_list);
+ } while (tt_info->slot_id == slot_id);
+}
+
+int xhci_alloc_tt_info(struct xhci_hcd *xhci,
+ struct xhci_virt_device *virt_dev,
+ struct usb_device *hdev,
+ struct usb_tt *tt, gfp_t mem_flags)
+{
+ struct xhci_tt_bw_info *tt_info;
+ unsigned int num_ports;
+ int i, j;
+
+ if (!tt->multi)
+ num_ports = 1;
+ else
+ num_ports = hdev->maxchild;
+
+ for (i = 0; i < num_ports; i++, tt_info++) {
+ struct xhci_interval_bw_table *bw_table;
+
+ tt_info = kzalloc(sizeof(*tt_info), mem_flags);
+ if (!tt_info)
+ goto free_tts;
+ INIT_LIST_HEAD(&tt_info->tt_list);
+ list_add(&tt_info->tt_list,
+ &xhci->rh_bw[virt_dev->real_port - 1].tts);
+ tt_info->slot_id = virt_dev->udev->slot_id;
+ if (tt->multi)
+ tt_info->ttport = i+1;
+ bw_table = &tt_info->bw_table;
+ for (j = 0; j < XHCI_MAX_INTERVAL; j++)
+ INIT_LIST_HEAD(&bw_table->interval_bw[j].endpoints);
+ }
+ return 0;
+
+free_tts:
+ xhci_free_tt_info(xhci, virt_dev, virt_dev->udev->slot_id);
+ return -ENOMEM;
+}
+
+
+/* All the xhci_tds in the ring's TD list should be freed at this point.
+ * Should be called with xhci->lock held if there is any chance the TT lists
+ * will be manipulated by the configure endpoint, allocate device, or update
+ * hub functions while this function is removing the TT entries from the list.
+ */
void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
{
struct xhci_virt_device *dev;
int i;
+ int old_active_eps = 0;
/* Slot ID 0 is reserved */
if (slot_id == 0 || !xhci->devs[slot_id])
@@ -702,13 +796,29 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
if (!dev)
return;
+ if (dev->tt_info)
+ old_active_eps = dev->tt_info->active_eps;
+
for (i = 0; i < 31; ++i) {
if (dev->eps[i].ring)
xhci_ring_free(xhci, dev->eps[i].ring);
if (dev->eps[i].stream_info)
xhci_free_stream_info(xhci,
dev->eps[i].stream_info);
+ /* Endpoints on the TT/root port lists should have been removed
+ * when usb_disable_device() was called for the device.
+ * We can't drop them anyway, because the udev might have gone
+ * away by this point, and we can't tell what speed it was.
+ */
+ if (!list_empty(&dev->eps[i].bw_endpoint_list))
+ xhci_warn(xhci, "Slot %u endpoint %u "
+ "not removed from BW list!\n",
+ slot_id, i);
}
+ /* If this is a hub, free the TT(s) from the TT list */
+ xhci_free_tt_info(xhci, dev, slot_id);
+ /* If necessary, update the number of active TTs on this root port */
+ xhci_update_tt_active_eps(xhci, dev, old_active_eps);
if (dev->ring_cache) {
for (i = 0; i < dev->num_rings_cached; i++)
@@ -762,10 +872,11 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
for (i = 0; i < 31; i++) {
xhci_init_endpoint_timer(xhci, &dev->eps[i]);
INIT_LIST_HEAD(&dev->eps[i].cancelled_td_list);
+ INIT_LIST_HEAD(&dev->eps[i].bw_endpoint_list);
}
/* Allocate endpoint 0 ring */
- dev->eps[0].ring = xhci_ring_alloc(xhci, 1, true, flags);
+ dev->eps[0].ring = xhci_ring_alloc(xhci, 1, true, false, flags);
if (!dev->eps[0].ring)
goto fail;
@@ -921,9 +1032,40 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
for (top_dev = udev; top_dev->parent && top_dev->parent->parent;
top_dev = top_dev->parent)
/* Found device below root hub */;
- dev->port = top_dev->portnum;
+ dev->fake_port = top_dev->portnum;
+ dev->real_port = port_num;
xhci_dbg(xhci, "Set root hub portnum to %d\n", port_num);
- xhci_dbg(xhci, "Set fake root hub portnum to %d\n", dev->port);
+ xhci_dbg(xhci, "Set fake root hub portnum to %d\n", dev->fake_port);
+
+ /* Find the right bandwidth table that this device will be a part of.
+ * If this is a full speed device attached directly to a root port (or a
+ * decendent of one), it counts as a primary bandwidth domain, not a
+ * secondary bandwidth domain under a TT. An xhci_tt_info structure
+ * will never be created for the HS root hub.
+ */
+ if (!udev->tt || !udev->tt->hub->parent) {
+ dev->bw_table = &xhci->rh_bw[port_num - 1].bw_table;
+ } else {
+ struct xhci_root_port_bw_info *rh_bw;
+ struct xhci_tt_bw_info *tt_bw;
+
+ rh_bw = &xhci->rh_bw[port_num - 1];
+ /* Find the right TT. */
+ list_for_each_entry(tt_bw, &rh_bw->tts, tt_list) {
+ if (tt_bw->slot_id != udev->tt->hub->slot_id)
+ continue;
+
+ if (!dev->udev->tt->multi ||
+ (udev->tt->multi &&
+ tt_bw->ttport == dev->udev->ttport)) {
+ dev->bw_table = &tt_bw->bw_table;
+ dev->tt_info = tt_bw;
+ break;
+ }
+ }
+ if (!dev->tt_info)
+ xhci_warn(xhci, "WARN: Didn't find a matching TT\n");
+ }
/* Is this a LS/FS device under an external HS hub? */
if (udev->tt && udev->tt->hub->parent) {
@@ -1141,8 +1283,8 @@ static u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci,
if (udev->speed == USB_SPEED_SUPER)
return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval);
- max_packet = GET_MAX_PACKET(le16_to_cpu(ep->desc.wMaxPacketSize));
- max_burst = (le16_to_cpu(ep->desc.wMaxPacketSize) & 0x1800) >> 11;
+ max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc));
+ max_burst = (usb_endpoint_maxp(&ep->desc) & 0x1800) >> 11;
/* A 0 in max burst means 1 transfer per ESIT */
return max_packet * (max_burst + 1);
}
@@ -1175,10 +1317,10 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
*/
if (usb_endpoint_xfer_isoc(&ep->desc))
virt_dev->eps[ep_index].new_ring =
- xhci_ring_alloc(xhci, 8, true, mem_flags);
+ xhci_ring_alloc(xhci, 8, true, true, mem_flags);
else
virt_dev->eps[ep_index].new_ring =
- xhci_ring_alloc(xhci, 1, true, mem_flags);
+ xhci_ring_alloc(xhci, 1, true, false, mem_flags);
if (!virt_dev->eps[ep_index].new_ring) {
/* Attempt to use the ring cache */
if (virt_dev->num_rings_cached == 0)
@@ -1187,7 +1329,8 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
virt_dev->ring_cache[virt_dev->num_rings_cached];
virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL;
virt_dev->num_rings_cached--;
- xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring);
+ xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring,
+ usb_endpoint_xfer_isoc(&ep->desc) ? true : false);
}
virt_dev->eps[ep_index].skip = false;
ep_ring = virt_dev->eps[ep_index].new_ring;
@@ -1211,7 +1354,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
/* Set the max packet size and max burst */
switch (udev->speed) {
case USB_SPEED_SUPER:
- max_packet = le16_to_cpu(ep->desc.wMaxPacketSize);
+ max_packet = usb_endpoint_maxp(&ep->desc);
ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet));
/* dig out max burst from ep companion desc */
max_packet = ep->ss_ep_comp.bMaxBurst;
@@ -1223,14 +1366,14 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
*/
if (usb_endpoint_xfer_isoc(&ep->desc) ||
usb_endpoint_xfer_int(&ep->desc)) {
- max_burst = (le16_to_cpu(ep->desc.wMaxPacketSize)
+ max_burst = (usb_endpoint_maxp(&ep->desc)
& 0x1800) >> 11;
ep_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(max_burst));
}
/* Fall through */
case USB_SPEED_FULL:
case USB_SPEED_LOW:
- max_packet = GET_MAX_PACKET(le16_to_cpu(ep->desc.wMaxPacketSize));
+ max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc));
ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet));
break;
default:
@@ -1286,6 +1429,70 @@ void xhci_endpoint_zero(struct xhci_hcd *xhci,
*/
}
+void xhci_clear_endpoint_bw_info(struct xhci_bw_info *bw_info)
+{
+ bw_info->ep_interval = 0;
+ bw_info->mult = 0;
+ bw_info->num_packets = 0;
+ bw_info->max_packet_size = 0;
+ bw_info->type = 0;
+ bw_info->max_esit_payload = 0;
+}
+
+void xhci_update_bw_info(struct xhci_hcd *xhci,
+ struct xhci_container_ctx *in_ctx,
+ struct xhci_input_control_ctx *ctrl_ctx,
+ struct xhci_virt_device *virt_dev)
+{
+ struct xhci_bw_info *bw_info;
+ struct xhci_ep_ctx *ep_ctx;
+ unsigned int ep_type;
+ int i;
+
+ for (i = 1; i < 31; ++i) {
+ bw_info = &virt_dev->eps[i].bw_info;
+
+ /* We can't tell what endpoint type is being dropped, but
+ * unconditionally clearing the bandwidth info for non-periodic
+ * endpoints should be harmless because the info will never be
+ * set in the first place.
+ */
+ if (!EP_IS_ADDED(ctrl_ctx, i) && EP_IS_DROPPED(ctrl_ctx, i)) {
+ /* Dropped endpoint */
+ xhci_clear_endpoint_bw_info(bw_info);
+ continue;
+ }
+
+ if (EP_IS_ADDED(ctrl_ctx, i)) {
+ ep_ctx = xhci_get_ep_ctx(xhci, in_ctx, i);
+ ep_type = CTX_TO_EP_TYPE(le32_to_cpu(ep_ctx->ep_info2));
+
+ /* Ignore non-periodic endpoints */
+ if (ep_type != ISOC_OUT_EP && ep_type != INT_OUT_EP &&
+ ep_type != ISOC_IN_EP &&
+ ep_type != INT_IN_EP)
+ continue;
+
+ /* Added or changed endpoint */
+ bw_info->ep_interval = CTX_TO_EP_INTERVAL(
+ le32_to_cpu(ep_ctx->ep_info));
+ /* Number of packets and mult are zero-based in the
+ * input context, but we want one-based for the
+ * interval table.
+ */
+ bw_info->mult = CTX_TO_EP_MULT(
+ le32_to_cpu(ep_ctx->ep_info)) + 1;
+ bw_info->num_packets = CTX_TO_MAX_BURST(
+ le32_to_cpu(ep_ctx->ep_info2)) + 1;
+ bw_info->max_packet_size = MAX_PACKET_DECODED(
+ le32_to_cpu(ep_ctx->ep_info2));
+ bw_info->type = ep_type;
+ bw_info->max_esit_payload = CTX_TO_MAX_ESIT_PAYLOAD(
+ le32_to_cpu(ep_ctx->tx_info));
+ }
+ }
+}
+
/* Copy output xhci_ep_ctx to the input xhci_ep_ctx copy.
* Useful when you want to change one particular aspect of the endpoint and then
* issue a configure endpoint command.
@@ -1344,10 +1551,9 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
if (!xhci->scratchpad)
goto fail_sp;
- xhci->scratchpad->sp_array =
- pci_alloc_consistent(to_pci_dev(dev),
+ xhci->scratchpad->sp_array = dma_alloc_coherent(dev,
num_sp * sizeof(u64),
- &xhci->scratchpad->sp_dma);
+ &xhci->scratchpad->sp_dma, flags);
if (!xhci->scratchpad->sp_array)
goto fail_sp2;
@@ -1364,8 +1570,8 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
xhci->dcbaa->dev_context_ptrs[0] = cpu_to_le64(xhci->scratchpad->sp_dma);
for (i = 0; i < num_sp; i++) {
dma_addr_t dma;
- void *buf = pci_alloc_consistent(to_pci_dev(dev),
- xhci->page_size, &dma);
+ void *buf = dma_alloc_coherent(dev, xhci->page_size, &dma,
+ flags);
if (!buf)
goto fail_sp5;
@@ -1378,7 +1584,7 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
fail_sp5:
for (i = i - 1; i >= 0; i--) {
- pci_free_consistent(to_pci_dev(dev), xhci->page_size,
+ dma_free_coherent(dev, xhci->page_size,
xhci->scratchpad->sp_buffers[i],
xhci->scratchpad->sp_dma_buffers[i]);
}
@@ -1388,7 +1594,7 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
kfree(xhci->scratchpad->sp_buffers);
fail_sp3:
- pci_free_consistent(to_pci_dev(dev), num_sp * sizeof(u64),
+ dma_free_coherent(dev, num_sp * sizeof(u64),
xhci->scratchpad->sp_array,
xhci->scratchpad->sp_dma);
@@ -1412,13 +1618,13 @@ static void scratchpad_free(struct xhci_hcd *xhci)
num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2);
for (i = 0; i < num_sp; i++) {
- pci_free_consistent(pdev, xhci->page_size,
+ dma_free_coherent(&pdev->dev, xhci->page_size,
xhci->scratchpad->sp_buffers[i],
xhci->scratchpad->sp_dma_buffers[i]);
}
kfree(xhci->scratchpad->sp_dma_buffers);
kfree(xhci->scratchpad->sp_buffers);
- pci_free_consistent(pdev, num_sp * sizeof(u64),
+ dma_free_coherent(&pdev->dev, num_sp * sizeof(u64),
xhci->scratchpad->sp_array,
xhci->scratchpad->sp_dma);
kfree(xhci->scratchpad);
@@ -1463,18 +1669,10 @@ struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
void xhci_urb_free_priv(struct xhci_hcd *xhci, struct urb_priv *urb_priv)
{
- int last;
-
- if (!urb_priv)
- return;
-
- last = urb_priv->length - 1;
- if (last >= 0) {
- int i;
- for (i = 0; i <= last; i++)
- kfree(urb_priv->td[i]);
+ if (urb_priv) {
+ kfree(urb_priv->td[0]);
+ kfree(urb_priv);
}
- kfree(urb_priv);
}
void xhci_free_command(struct xhci_hcd *xhci,
@@ -1489,6 +1687,8 @@ void xhci_free_command(struct xhci_hcd *xhci,
void xhci_mem_cleanup(struct xhci_hcd *xhci)
{
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
+ struct dev_info *dev_info, *next;
+ unsigned long flags;
int size;
int i;
@@ -1500,7 +1700,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
}
size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
if (xhci->erst.entries)
- pci_free_consistent(pdev, size,
+ dma_free_coherent(&pdev->dev, size,
xhci->erst.entries, xhci->erst.erst_dma_addr);
xhci->erst.entries = NULL;
xhci_dbg(xhci, "Freed ERST\n");
@@ -1540,17 +1740,25 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci_write_64(xhci, 0, &xhci->op_regs->dcbaa_ptr);
if (xhci->dcbaa)
- pci_free_consistent(pdev, sizeof(*xhci->dcbaa),
+ dma_free_coherent(&pdev->dev, sizeof(*xhci->dcbaa),
xhci->dcbaa, xhci->dcbaa->dma);
xhci->dcbaa = NULL;
scratchpad_free(xhci);
+ spin_lock_irqsave(&xhci->lock, flags);
+ list_for_each_entry_safe(dev_info, next, &xhci->lpm_failed_devs, list) {
+ list_del(&dev_info->list);
+ kfree(dev_info);
+ }
+ spin_unlock_irqrestore(&xhci->lock, flags);
+
xhci->num_usb2_ports = 0;
xhci->num_usb3_ports = 0;
kfree(xhci->usb2_ports);
kfree(xhci->usb3_ports);
kfree(xhci->port_array);
+ kfree(xhci->rh_bw);
xhci->page_size = 0;
xhci->page_shift = 0;
@@ -1762,6 +1970,23 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
if (port_offset == 0 || (port_offset + port_count - 1) > num_ports)
/* WTF? "Valid values are ‘1’ to MaxPorts" */
return;
+
+ /* Check the host's USB2 LPM capability */
+ if ((xhci->hci_version == 0x96) && (major_revision != 0x03) &&
+ (temp & XHCI_L1C)) {
+ xhci_dbg(xhci, "xHCI 0.96: support USB2 software lpm\n");
+ xhci->sw_lpm_support = 1;
+ }
+
+ if ((xhci->hci_version >= 0x100) && (major_revision != 0x03)) {
+ xhci_dbg(xhci, "xHCI 1.0: support USB2 software lpm\n");
+ xhci->sw_lpm_support = 1;
+ if (temp & XHCI_HLC) {
+ xhci_dbg(xhci, "xHCI 1.0: support USB2 hardware lpm\n");
+ xhci->hw_lpm_support = 1;
+ }
+ }
+
port_offset--;
for (i = port_offset; i < (port_offset + port_count); i++) {
/* Duplicate entry. Ignore the port if the revisions differ. */
@@ -1806,7 +2031,7 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
__le32 __iomem *addr;
u32 offset;
unsigned int num_ports;
- int i, port_index;
+ int i, j, port_index;
addr = &xhci->cap_regs->hcc_params;
offset = XHCI_HCC_EXT_CAPS(xhci_readl(xhci, addr));
@@ -1821,6 +2046,18 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
if (!xhci->port_array)
return -ENOMEM;
+ xhci->rh_bw = kzalloc(sizeof(*xhci->rh_bw)*num_ports, flags);
+ if (!xhci->rh_bw)
+ return -ENOMEM;
+ for (i = 0; i < num_ports; i++) {
+ struct xhci_interval_bw_table *bw_table;
+
+ INIT_LIST_HEAD(&xhci->rh_bw[i].tts);
+ bw_table = &xhci->rh_bw[i].bw_table;
+ for (j = 0; j < XHCI_MAX_INTERVAL; j++)
+ INIT_LIST_HEAD(&bw_table->interval_bw[j].endpoints);
+ }
+
/*
* For whatever reason, the first capability offset is from the
* capability register base, not from the HCCPARAMS register.
@@ -1959,8 +2196,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
* Section 5.4.8 - doorbell array must be
* "physically contiguous and 64-byte (cache line) aligned".
*/
- xhci->dcbaa = pci_alloc_consistent(to_pci_dev(dev),
- sizeof(*xhci->dcbaa), &dma);
+ xhci->dcbaa = dma_alloc_coherent(dev, sizeof(*xhci->dcbaa), &dma,
+ GFP_KERNEL);
if (!xhci->dcbaa)
goto fail;
memset(xhci->dcbaa, 0, sizeof *(xhci->dcbaa));
@@ -1994,14 +2231,14 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
dma_pool_create("xHCI 1KB stream ctx arrays",
dev, MEDIUM_STREAM_ARRAY_SIZE, 16, 0);
/* Any stream context array bigger than MEDIUM_STREAM_ARRAY_SIZE
- * will be allocated with pci_alloc_consistent()
+ * will be allocated with dma_alloc_coherent()
*/
if (!xhci->small_streams_pool || !xhci->medium_streams_pool)
goto fail;
/* Set up the command ring to have one segments for now. */
- xhci->cmd_ring = xhci_ring_alloc(xhci, 1, true, flags);
+ xhci->cmd_ring = xhci_ring_alloc(xhci, 1, true, false, flags);
if (!xhci->cmd_ring)
goto fail;
xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring);
@@ -2032,14 +2269,16 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
* the event ring segment table (ERST). Section 4.9.3.
*/
xhci_dbg(xhci, "// Allocating event ring\n");
- xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, false, flags);
+ xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, false, false,
+ flags);
if (!xhci->event_ring)
goto fail;
if (xhci_check_trb_in_td_math(xhci, flags) < 0)
goto fail;
- xhci->erst.entries = pci_alloc_consistent(to_pci_dev(dev),
- sizeof(struct xhci_erst_entry)*ERST_NUM_SEGS, &dma);
+ xhci->erst.entries = dma_alloc_coherent(dev,
+ sizeof(struct xhci_erst_entry) * ERST_NUM_SEGS, &dma,
+ GFP_KERNEL);
if (!xhci->erst.entries)
goto fail;
xhci_dbg(xhci, "// Allocated event ring segment table at 0x%llx\n",
@@ -2102,6 +2341,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
if (xhci_setup_port_arrays(xhci, flags))
goto fail;
+ INIT_LIST_HEAD(&xhci->lpm_failed_devs);
+
return 0;
fail:
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index cb16de213f64..9f51f88cc0f5 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -51,61 +51,9 @@ static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev)
return 0;
}
-/* called during probe() after chip reset completes */
-static int xhci_pci_setup(struct usb_hcd *hcd)
+static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
{
- struct xhci_hcd *xhci;
- struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
- int retval;
- u32 temp;
-
- hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2;
-
- if (usb_hcd_is_primary_hcd(hcd)) {
- xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL);
- if (!xhci)
- return -ENOMEM;
- *((struct xhci_hcd **) hcd->hcd_priv) = xhci;
- xhci->main_hcd = hcd;
- /* Mark the first roothub as being USB 2.0.
- * The xHCI driver will register the USB 3.0 roothub.
- */
- hcd->speed = HCD_USB2;
- hcd->self.root_hub->speed = USB_SPEED_HIGH;
- /*
- * USB 2.0 roothub under xHCI has an integrated TT,
- * (rate matching hub) as opposed to having an OHCI/UHCI
- * companion controller.
- */
- hcd->has_tt = 1;
- } else {
- /* xHCI private pointer was set in xhci_pci_probe for the second
- * registered roothub.
- */
- xhci = hcd_to_xhci(hcd);
- temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
- if (HCC_64BIT_ADDR(temp)) {
- xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
- dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64));
- } else {
- dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32));
- }
- return 0;
- }
-
- xhci->cap_regs = hcd->regs;
- xhci->op_regs = hcd->regs +
- HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase));
- xhci->run_regs = hcd->regs +
- (xhci_readl(xhci, &xhci->cap_regs->run_regs_off) & RTSOFF_MASK);
- /* Cache read-only capability registers */
- xhci->hcs_params1 = xhci_readl(xhci, &xhci->cap_regs->hcs_params1);
- xhci->hcs_params2 = xhci_readl(xhci, &xhci->cap_regs->hcs_params2);
- xhci->hcs_params3 = xhci_readl(xhci, &xhci->cap_regs->hcs_params3);
- xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hc_capbase);
- xhci->hci_version = HC_VERSION(xhci->hcc_params);
- xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
- xhci_print_registers(xhci);
+ struct pci_dev *pdev = to_pci_dev(dev);
/* Look for vendor-specific quirks */
if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC &&
@@ -128,6 +76,9 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
if (pdev->vendor == PCI_VENDOR_ID_NEC)
xhci->quirks |= XHCI_NEC_HOST;
+ if (pdev->vendor == PCI_VENDOR_ID_AMD && xhci->hci_version == 0x96)
+ xhci->quirks |= XHCI_AMD_0x96_HOST;
+
/* AMD PLL quirk */
if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info())
xhci->quirks |= XHCI_AMD_PLL_FIX;
@@ -136,39 +87,29 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
xhci->quirks |= XHCI_EP_LIMIT_QUIRK;
xhci->limit_active_eps = 64;
+ xhci->quirks |= XHCI_SW_BW_CHECKING;
}
if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
pdev->device == PCI_DEVICE_ID_ASROCK_P67) {
xhci->quirks |= XHCI_RESET_ON_RESUME;
xhci_dbg(xhci, "QUIRK: Resetting on resume\n");
}
+}
- /* Make sure the HC is halted. */
- retval = xhci_halt(xhci);
- if (retval)
- goto error;
+/* called during probe() after chip reset completes */
+static int xhci_pci_setup(struct usb_hcd *hcd)
+{
+ struct xhci_hcd *xhci;
+ struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+ int retval;
- xhci_dbg(xhci, "Resetting HCD\n");
- /* Reset the internal HC memory state and registers. */
- retval = xhci_reset(xhci);
+ retval = xhci_gen_setup(hcd, xhci_pci_quirks);
if (retval)
- goto error;
- xhci_dbg(xhci, "Reset complete\n");
-
- temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
- if (HCC_64BIT_ADDR(temp)) {
- xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
- dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64));
- } else {
- dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32));
- }
+ return retval;
- xhci_dbg(xhci, "Calling HCD init\n");
- /* Initialize HCD and host controller data structures. */
- retval = xhci_init(hcd);
- if (retval)
- goto error;
- xhci_dbg(xhci, "Called HCD init\n");
+ xhci = hcd_to_xhci(hcd);
+ if (!usb_hcd_is_primary_hcd(hcd))
+ return 0;
pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn);
xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn);
@@ -178,7 +119,6 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
if (!retval)
return retval;
-error:
kfree(xhci);
return retval;
}
@@ -222,7 +162,7 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
*((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci;
retval = usb_add_hcd(xhci->shared_hcd, dev->irq,
- IRQF_DISABLED | IRQF_SHARED);
+ IRQF_SHARED);
if (retval)
goto put_usb3_hcd;
/* Roothub already marked as USB 3.0 speed */
@@ -344,6 +284,11 @@ static const struct hc_driver xhci_pci_hc_driver = {
.hub_status_data = xhci_hub_status_data,
.bus_suspend = xhci_bus_suspend,
.bus_resume = xhci_bus_resume,
+ /*
+ * call back when device connected and addressed
+ */
+ .update_device = xhci_update_device,
+ .set_usb2_hw_lpm = xhci_set_usb2_hardware_lpm,
};
/*-------------------------------------------------------------------------*/
@@ -375,12 +320,12 @@ static struct pci_driver xhci_pci_driver = {
#endif
};
-int xhci_register_pci(void)
+int __init xhci_register_pci(void)
{
return pci_register_driver(&xhci_pci_driver);
}
-void xhci_unregister_pci(void)
+void __exit xhci_unregister_pci(void)
{
pci_unregister_driver(&xhci_pci_driver);
}
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 7113d16e2d3a..940321b3ec68 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -185,7 +185,7 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
* prepare_transfer()?
*/
static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
- bool consumer, bool more_trbs_coming)
+ bool consumer, bool more_trbs_coming, bool isoc)
{
u32 chain;
union xhci_trb *next;
@@ -212,11 +212,13 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
if (!chain && !more_trbs_coming)
break;
- /* If we're not dealing with 0.95 hardware,
+ /* If we're not dealing with 0.95 hardware or
+ * isoc rings on AMD 0.96 host,
* carry over the chain bit of the previous TRB
* (which may mean the chain bit is cleared).
*/
- if (!xhci_link_trb_quirk(xhci)) {
+ if (!(isoc && (xhci->quirks & XHCI_AMD_0x96_HOST))
+ && !xhci_link_trb_quirk(xhci)) {
next->link.control &=
cpu_to_le32(~TRB_CHAIN);
next->link.control |=
@@ -514,8 +516,12 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
(unsigned long long) addr);
}
+/* flip_cycle means flip the cycle bit of all but the first and last TRB.
+ * (The last TRB actually points to the ring enqueue pointer, which is not part
+ * of this TD.) This is used to remove partially enqueued isoc TDs from a ring.
+ */
static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
- struct xhci_td *cur_td)
+ struct xhci_td *cur_td, bool flip_cycle)
{
struct xhci_segment *cur_seg;
union xhci_trb *cur_trb;
@@ -528,6 +534,12 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
* leave the pointers intact.
*/
cur_trb->generic.field[3] &= cpu_to_le32(~TRB_CHAIN);
+ /* Flip the cycle bit (link TRBs can't be the first
+ * or last TRB).
+ */
+ if (flip_cycle)
+ cur_trb->generic.field[3] ^=
+ cpu_to_le32(TRB_CYCLE);
xhci_dbg(xhci, "Cancel (unchain) link TRB\n");
xhci_dbg(xhci, "Address = %p (0x%llx dma); "
"in seg %p (0x%llx dma)\n",
@@ -541,6 +553,11 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
cur_trb->generic.field[2] = 0;
/* Preserve only the cycle bit of this TRB */
cur_trb->generic.field[3] &= cpu_to_le32(TRB_CYCLE);
+ /* Flip the cycle bit except on the first or last TRB */
+ if (flip_cycle && cur_trb != cur_td->first_trb &&
+ cur_trb != cur_td->last_trb)
+ cur_trb->generic.field[3] ^=
+ cpu_to_le32(TRB_CYCLE);
cur_trb->generic.field[3] |= cpu_to_le32(
TRB_TYPE(TRB_TR_NOOP));
xhci_dbg(xhci, "Cancel TRB %p (0x%llx dma) "
@@ -719,14 +736,14 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
cur_td->urb->stream_id,
cur_td, &deq_state);
else
- td_to_noop(xhci, ep_ring, cur_td);
+ td_to_noop(xhci, ep_ring, cur_td, false);
remove_finished_td:
/*
* The event handler won't see a completion for this TD anymore,
* so remove it from the endpoint ring's TD list. Keep it in
* the cancelled TD list for URB completion later.
*/
- list_del(&cur_td->td_list);
+ list_del_init(&cur_td->td_list);
}
last_unlinked_td = cur_td;
xhci_stop_watchdog_timer_in_irq(xhci, ep);
@@ -754,7 +771,7 @@ remove_finished_td:
do {
cur_td = list_entry(ep->cancelled_td_list.next,
struct xhci_td, cancelled_td_list);
- list_del(&cur_td->cancelled_td_list);
+ list_del_init(&cur_td->cancelled_td_list);
/* Clean up the cancelled URB */
/* Doesn't matter what we pass for status, since the core will
@@ -862,9 +879,9 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
cur_td = list_first_entry(&ring->td_list,
struct xhci_td,
td_list);
- list_del(&cur_td->td_list);
+ list_del_init(&cur_td->td_list);
if (!list_empty(&cur_td->cancelled_td_list))
- list_del(&cur_td->cancelled_td_list);
+ list_del_init(&cur_td->cancelled_td_list);
xhci_giveback_urb_in_irq(xhci, cur_td,
-ESHUTDOWN, "killed");
}
@@ -873,7 +890,7 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
&temp_ep->cancelled_td_list,
struct xhci_td,
cancelled_td_list);
- list_del(&cur_td->cancelled_td_list);
+ list_del_init(&cur_td->cancelled_td_list);
xhci_giveback_urb_in_irq(xhci, cur_td,
-ESHUTDOWN, "killed");
}
@@ -1314,10 +1331,8 @@ static void handle_port_status(struct xhci_hcd *xhci,
if (DEV_SUPERSPEED(temp)) {
xhci_dbg(xhci, "resume SS port %d\n", port_id);
- temp = xhci_port_state_to_neutral(temp);
- temp &= ~PORT_PLS_MASK;
- temp |= PORT_LINK_STROBE | XDEV_U0;
- xhci_writel(xhci, temp, port_array[faked_port_index]);
+ xhci_set_link_state(xhci, port_array, faked_port_index,
+ XDEV_U0);
slot_id = xhci_find_slot_id_by_port(hcd, xhci,
faked_port_index);
if (!slot_id) {
@@ -1327,10 +1342,8 @@ static void handle_port_status(struct xhci_hcd *xhci,
xhci_ring_device(xhci, slot_id);
xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
/* Clear PORT_PLC */
- temp = xhci_readl(xhci, port_array[faked_port_index]);
- temp = xhci_port_state_to_neutral(temp);
- temp |= PORT_PLC;
- xhci_writel(xhci, temp, port_array[faked_port_index]);
+ xhci_test_and_clear_bit(xhci, port_array,
+ faked_port_index, PORT_PLC);
} else {
xhci_dbg(xhci, "resume HS port %d\n", port_id);
bus_state->resume_done[faked_port_index] = jiffies +
@@ -1341,6 +1354,10 @@ static void handle_port_status(struct xhci_hcd *xhci,
}
}
+ if (hcd->speed != HCD_USB3)
+ xhci_test_and_clear_bit(xhci, port_array, faked_port_index,
+ PORT_PLC);
+
cleanup:
/* Update event ring dequeue pointer before dropping the lock */
inc_deq(xhci, xhci->event_ring, true);
@@ -1565,10 +1582,10 @@ td_cleanup:
else
*status = 0;
}
- list_del(&td->td_list);
+ list_del_init(&td->td_list);
/* Was this TD slated to be cancelled but completed anyway? */
if (!list_empty(&td->cancelled_td_list))
- list_del(&td->cancelled_td_list);
+ list_del_init(&td->cancelled_td_list);
urb_priv->td_cnt++;
/* Giveback the urb when all the tds are completed */
@@ -1919,8 +1936,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
int status = -EINPROGRESS;
struct urb_priv *urb_priv;
struct xhci_ep_ctx *ep_ctx;
+ struct list_head *tmp;
u32 trb_comp_code;
int ret = 0;
+ int td_num = 0;
slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
xdev = xhci->devs[slot_id];
@@ -1942,6 +1961,12 @@ static int handle_tx_event(struct xhci_hcd *xhci,
return -ENODEV;
}
+ /* Count current td numbers if ep->skip is set */
+ if (ep->skip) {
+ list_for_each(tmp, &ep_ring->td_list)
+ td_num++;
+ }
+
event_dma = le64_to_cpu(event->buffer);
trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
/* Look for common error cases */
@@ -2053,7 +2078,18 @@ static int handle_tx_event(struct xhci_hcd *xhci,
goto cleanup;
}
+ /* We've skipped all the TDs on the ep ring when ep->skip set */
+ if (ep->skip && td_num == 0) {
+ ep->skip = false;
+ xhci_dbg(xhci, "All tds on the ep_ring skipped. "
+ "Clear skip flag.\n");
+ ret = 0;
+ goto cleanup;
+ }
+
td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list);
+ if (ep->skip)
+ td_num--;
/* Is this a TRB in the currently executing TD? */
event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue,
@@ -2158,7 +2194,8 @@ cleanup:
if ((urb->actual_length != urb->transfer_buffer_length &&
(urb->transfer_flags &
URB_SHORT_NOT_OK)) ||
- status != 0)
+ (status != 0 &&
+ !usb_endpoint_xfer_isoc(&urb->ep->desc)))
xhci_dbg(xhci, "Giveback URB %p, len = %d, "
"expected = %x, status = %d\n",
urb, urb->actual_length,
@@ -2375,7 +2412,7 @@ irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd)
* prepare_transfer()?
*/
static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
- bool consumer, bool more_trbs_coming,
+ bool consumer, bool more_trbs_coming, bool isoc,
u32 field1, u32 field2, u32 field3, u32 field4)
{
struct xhci_generic_trb *trb;
@@ -2385,7 +2422,7 @@ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
trb->field[1] = cpu_to_le32(field2);
trb->field[2] = cpu_to_le32(field3);
trb->field[3] = cpu_to_le32(field4);
- inc_enq(xhci, ring, consumer, more_trbs_coming);
+ inc_enq(xhci, ring, consumer, more_trbs_coming, isoc);
}
/*
@@ -2393,7 +2430,7 @@ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
* FIXME allocate segments if the ring is full.
*/
static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
- u32 ep_state, unsigned int num_trbs, gfp_t mem_flags)
+ u32 ep_state, unsigned int num_trbs, bool isoc, gfp_t mem_flags)
{
/* Make sure the endpoint has been added to xHC schedule */
switch (ep_state) {
@@ -2435,10 +2472,11 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
next = ring->enqueue;
while (last_trb(xhci, ring, ring->enq_seg, next)) {
- /* If we're not dealing with 0.95 hardware,
- * clear the chain bit.
+ /* If we're not dealing with 0.95 hardware or isoc rings
+ * on AMD 0.96 host, clear the chain bit.
*/
- if (!xhci_link_trb_quirk(xhci))
+ if (!xhci_link_trb_quirk(xhci) && !(isoc &&
+ (xhci->quirks & XHCI_AMD_0x96_HOST)))
next->link.control &= cpu_to_le32(~TRB_CHAIN);
else
next->link.control |= cpu_to_le32(TRB_CHAIN);
@@ -2471,6 +2509,7 @@ static int prepare_transfer(struct xhci_hcd *xhci,
unsigned int num_trbs,
struct urb *urb,
unsigned int td_index,
+ bool isoc,
gfp_t mem_flags)
{
int ret;
@@ -2488,7 +2527,7 @@ static int prepare_transfer(struct xhci_hcd *xhci,
ret = prepare_ring(xhci, ep_ring,
le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK,
- num_trbs, mem_flags);
+ num_trbs, isoc, mem_flags);
if (ret)
return ret;
@@ -2500,11 +2539,8 @@ static int prepare_transfer(struct xhci_hcd *xhci,
if (td_index == 0) {
ret = usb_hcd_link_urb_to_ep(bus_to_hcd(urb->dev->bus), urb);
- if (unlikely(ret)) {
- xhci_urb_free_priv(xhci, urb_priv);
- urb->hcpriv = NULL;
+ if (unlikely(ret))
return ret;
- }
}
td->urb = urb;
@@ -2672,11 +2708,15 @@ static u32 xhci_v1_0_td_remainder(int running_total, int trb_buff_len,
{
int packets_transferred;
+ /* One TRB with a zero-length data packet. */
+ if (running_total == 0 && trb_buff_len == 0)
+ return 0;
+
/* All the TRB queueing functions don't count the current TRB in
* running_total.
*/
packets_transferred = (running_total + trb_buff_len) /
- le16_to_cpu(urb->ep->desc.wMaxPacketSize);
+ usb_endpoint_maxp(&urb->ep->desc);
return xhci_td_remainder(total_packet_count - packets_transferred);
}
@@ -2706,11 +2746,11 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
num_trbs = count_sg_trbs_needed(xhci, urb);
num_sgs = urb->num_sgs;
total_packet_count = roundup(urb->transfer_buffer_length,
- le16_to_cpu(urb->ep->desc.wMaxPacketSize));
+ usb_endpoint_maxp(&urb->ep->desc));
trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id],
ep_index, urb->stream_id,
- num_trbs, urb, 0, mem_flags);
+ num_trbs, urb, 0, false, mem_flags);
if (trb_buff_len < 0)
return trb_buff_len;
@@ -2805,7 +2845,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
more_trbs_coming = true;
else
more_trbs_coming = false;
- queue_trb(xhci, ep_ring, false, more_trbs_coming,
+ queue_trb(xhci, ep_ring, false, more_trbs_coming, false,
lower_32_bits(addr),
upper_32_bits(addr),
length_field,
@@ -2896,7 +2936,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
ret = prepare_transfer(xhci, xhci->devs[slot_id],
ep_index, urb->stream_id,
- num_trbs, urb, 0, mem_flags);
+ num_trbs, urb, 0, false, mem_flags);
if (ret < 0)
return ret;
@@ -2913,7 +2953,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
running_total = 0;
total_packet_count = roundup(urb->transfer_buffer_length,
- le16_to_cpu(urb->ep->desc.wMaxPacketSize));
+ usb_endpoint_maxp(&urb->ep->desc));
/* How much data is in the first TRB? */
addr = (u64) urb->transfer_dma;
trb_buff_len = TRB_MAX_BUFF_SIZE -
@@ -2968,7 +3008,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
more_trbs_coming = true;
else
more_trbs_coming = false;
- queue_trb(xhci, ep_ring, false, more_trbs_coming,
+ queue_trb(xhci, ep_ring, false, more_trbs_coming, false,
lower_32_bits(addr),
upper_32_bits(addr),
length_field,
@@ -3028,7 +3068,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
num_trbs++;
ret = prepare_transfer(xhci, xhci->devs[slot_id],
ep_index, urb->stream_id,
- num_trbs, urb, 0, mem_flags);
+ num_trbs, urb, 0, false, mem_flags);
if (ret < 0)
return ret;
@@ -3061,7 +3101,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
}
}
- queue_trb(xhci, ep_ring, false, true,
+ queue_trb(xhci, ep_ring, false, true, false,
setup->bRequestType | setup->bRequest << 8 | le16_to_cpu(setup->wValue) << 16,
le16_to_cpu(setup->wIndex) | le16_to_cpu(setup->wLength) << 16,
TRB_LEN(8) | TRB_INTR_TARGET(0),
@@ -3081,7 +3121,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
if (urb->transfer_buffer_length > 0) {
if (setup->bRequestType & USB_DIR_IN)
field |= TRB_DIR_IN;
- queue_trb(xhci, ep_ring, false, true,
+ queue_trb(xhci, ep_ring, false, true, false,
lower_32_bits(urb->transfer_dma),
upper_32_bits(urb->transfer_dma),
length_field,
@@ -3097,7 +3137,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
field = 0;
else
field = TRB_DIR_IN;
- queue_trb(xhci, ep_ring, false, false,
+ queue_trb(xhci, ep_ring, false, false, false,
0,
0,
TRB_INTR_TARGET(0),
@@ -3113,21 +3153,16 @@ static int count_isoc_trbs_needed(struct xhci_hcd *xhci,
struct urb *urb, int i)
{
int num_trbs = 0;
- u64 addr, td_len, running_total;
+ u64 addr, td_len;
addr = (u64) (urb->transfer_dma + urb->iso_frame_desc[i].offset);
td_len = urb->iso_frame_desc[i].length;
- running_total = TRB_MAX_BUFF_SIZE - (addr & (TRB_MAX_BUFF_SIZE - 1));
- running_total &= TRB_MAX_BUFF_SIZE - 1;
- if (running_total != 0)
+ num_trbs = DIV_ROUND_UP(td_len + (addr & (TRB_MAX_BUFF_SIZE - 1)),
+ TRB_MAX_BUFF_SIZE);
+ if (num_trbs == 0)
num_trbs++;
- while (running_total < td_len) {
- num_trbs++;
- running_total += TRB_MAX_BUFF_SIZE;
- }
-
return num_trbs;
}
@@ -3226,6 +3261,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
start_trb = &ep_ring->enqueue->generic;
start_cycle = ep_ring->cycle_state;
+ urb_priv = urb->hcpriv;
/* Queue the first TRB, even if it's zero-length */
for (i = 0; i < num_tds; i++) {
unsigned int total_packet_count;
@@ -3237,9 +3273,11 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
addr = start_addr + urb->iso_frame_desc[i].offset;
td_len = urb->iso_frame_desc[i].length;
td_remain_len = td_len;
- /* FIXME: Ignoring zero-length packets, can those happen? */
total_packet_count = roundup(td_len,
- le16_to_cpu(urb->ep->desc.wMaxPacketSize));
+ usb_endpoint_maxp(&urb->ep->desc));
+ /* A zero-length transfer still involves at least one packet. */
+ if (total_packet_count == 0)
+ total_packet_count++;
burst_count = xhci_get_burst_count(xhci, urb->dev, urb,
total_packet_count);
residue = xhci_get_last_burst_packet_count(xhci,
@@ -3248,13 +3286,15 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
trbs_per_td = count_isoc_trbs_needed(xhci, urb, i);
ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index,
- urb->stream_id, trbs_per_td, urb, i, mem_flags);
- if (ret < 0)
- return ret;
+ urb->stream_id, trbs_per_td, urb, i, true,
+ mem_flags);
+ if (ret < 0) {
+ if (i == 0)
+ return ret;
+ goto cleanup;
+ }
- urb_priv = urb->hcpriv;
td = urb_priv->td[i];
-
for (j = 0; j < trbs_per_td; j++) {
u32 remainder = 0;
field = TRB_TBC(burst_count) | TRB_TLBPC(residue);
@@ -3317,7 +3357,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
remainder |
TRB_INTR_TARGET(0);
- queue_trb(xhci, ep_ring, false, more_trbs_coming,
+ queue_trb(xhci, ep_ring, false, more_trbs_coming, true,
lower_32_bits(addr),
upper_32_bits(addr),
length_field,
@@ -3344,6 +3384,27 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
start_cycle, start_trb);
return 0;
+cleanup:
+ /* Clean up a partially enqueued isoc transfer. */
+
+ for (i--; i >= 0; i--)
+ list_del_init(&urb_priv->td[i]->td_list);
+
+ /* Use the first TD as a temporary variable to turn the TDs we've queued
+ * into No-ops with a software-owned cycle bit. That way the hardware
+ * won't accidentally start executing bogus TDs when we partially
+ * overwrite them. td->first_trb and td->start_seg are already set.
+ */
+ urb_priv->td[0]->last_trb = ep_ring->enqueue;
+ /* Every TRB except the first & last will have its cycle bit flipped. */
+ td_to_noop(xhci, ep_ring, urb_priv->td[0], true);
+
+ /* Reset the ring enqueue back to the first TRB and its cycle bit. */
+ ep_ring->enqueue = urb_priv->td[0]->first_trb;
+ ep_ring->enq_seg = urb_priv->td[0]->start_seg;
+ ep_ring->cycle_state = start_cycle;
+ usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
+ return ret;
}
/*
@@ -3378,7 +3439,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
* Do not insert any td of the urb to the ring if the check failed.
*/
ret = prepare_ring(xhci, ep_ring, le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK,
- num_trbs, mem_flags);
+ num_trbs, true, mem_flags);
if (ret)
return ret;
@@ -3437,7 +3498,7 @@ static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2,
reserved_trbs++;
ret = prepare_ring(xhci, xhci->cmd_ring, EP_STATE_RUNNING,
- reserved_trbs, GFP_ATOMIC);
+ reserved_trbs, false, GFP_ATOMIC);
if (ret < 0) {
xhci_err(xhci, "ERR: No room for command on command ring\n");
if (command_must_succeed)
@@ -3445,8 +3506,8 @@ static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2,
"unfailable commands failed.\n");
return ret;
}
- queue_trb(xhci, xhci->cmd_ring, false, false, field1, field2, field3,
- field4 | xhci->cmd_ring->cycle_state);
+ queue_trb(xhci, xhci->cmd_ring, false, false, false, field1, field2,
+ field3, field4 | xhci->cmd_ring->cycle_state);
return 0;
}
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 1c4432d8fc10..1ff95a0df576 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -175,28 +175,19 @@ int xhci_reset(struct xhci_hcd *xhci)
return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000);
}
-/*
- * Free IRQs
- * free all IRQs request
- */
-static void xhci_free_irq(struct xhci_hcd *xhci)
+#ifdef CONFIG_PCI
+static int xhci_free_msi(struct xhci_hcd *xhci)
{
int i;
- struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
- /* return if using legacy interrupt */
- if (xhci_to_hcd(xhci)->irq >= 0)
- return;
-
- if (xhci->msix_entries) {
- for (i = 0; i < xhci->msix_count; i++)
- if (xhci->msix_entries[i].vector)
- free_irq(xhci->msix_entries[i].vector,
- xhci_to_hcd(xhci));
- } else if (pdev->irq >= 0)
- free_irq(pdev->irq, xhci_to_hcd(xhci));
+ if (!xhci->msix_entries)
+ return -EINVAL;
- return;
+ for (i = 0; i < xhci->msix_count; i++)
+ if (xhci->msix_entries[i].vector)
+ free_irq(xhci->msix_entries[i].vector,
+ xhci_to_hcd(xhci));
+ return 0;
}
/*
@@ -224,6 +215,28 @@ static int xhci_setup_msi(struct xhci_hcd *xhci)
}
/*
+ * Free IRQs
+ * free all IRQs request
+ */
+static void xhci_free_irq(struct xhci_hcd *xhci)
+{
+ struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
+ int ret;
+
+ /* return if using legacy interrupt */
+ if (xhci_to_hcd(xhci)->irq >= 0)
+ return;
+
+ ret = xhci_free_msi(xhci);
+ if (!ret)
+ return;
+ if (pdev->irq >= 0)
+ free_irq(pdev->irq, xhci_to_hcd(xhci));
+
+ return;
+}
+
+/*
* Set up MSI-X
*/
static int xhci_setup_msix(struct xhci_hcd *xhci)
@@ -302,6 +315,72 @@ static void xhci_cleanup_msix(struct xhci_hcd *xhci)
return;
}
+static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
+{
+ int i;
+
+ if (xhci->msix_entries) {
+ for (i = 0; i < xhci->msix_count; i++)
+ synchronize_irq(xhci->msix_entries[i].vector);
+ }
+}
+
+static int xhci_try_enable_msi(struct usb_hcd *hcd)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
+ int ret;
+
+ /*
+ * Some Fresco Logic host controllers advertise MSI, but fail to
+ * generate interrupts. Don't even try to enable MSI.
+ */
+ if (xhci->quirks & XHCI_BROKEN_MSI)
+ return 0;
+
+ /* unregister the legacy interrupt */
+ if (hcd->irq)
+ free_irq(hcd->irq, hcd);
+ hcd->irq = -1;
+
+ ret = xhci_setup_msix(xhci);
+ if (ret)
+ /* fall back to msi*/
+ ret = xhci_setup_msi(xhci);
+
+ if (!ret)
+ /* hcd->irq is -1, we have MSI */
+ return 0;
+
+ /* fall back to legacy interrupt*/
+ ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED,
+ hcd->irq_descr, hcd);
+ if (ret) {
+ xhci_err(xhci, "request interrupt %d failed\n",
+ pdev->irq);
+ return ret;
+ }
+ hcd->irq = pdev->irq;
+ return 0;
+}
+
+#else
+
+static int xhci_try_enable_msi(struct usb_hcd *hcd)
+{
+ return 0;
+}
+
+static void xhci_cleanup_msix(struct xhci_hcd *xhci)
+{
+}
+
+static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
+{
+}
+
+#endif
+
/*
* Initialize memory for HCD and xHC (one-time init).
*
@@ -316,7 +395,7 @@ int xhci_init(struct usb_hcd *hcd)
xhci_dbg(xhci, "xhci_init\n");
spin_lock_init(&xhci->lock);
- if (link_quirk) {
+ if (xhci->hci_version == 0x95 && link_quirk) {
xhci_dbg(xhci, "QUIRK: Not clearing Link TRB chain bits.\n");
xhci->quirks |= XHCI_LINK_TRB_QUIRK;
} else {
@@ -413,9 +492,8 @@ int xhci_run(struct usb_hcd *hcd)
{
u32 temp;
u64 temp_64;
- u32 ret;
+ int ret;
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
/* Start the xHCI host controller running only after the USB 2.0 roothub
* is setup.
@@ -426,34 +504,10 @@ int xhci_run(struct usb_hcd *hcd)
return xhci_run_finished(xhci);
xhci_dbg(xhci, "xhci_run\n");
- /* unregister the legacy interrupt */
- if (hcd->irq)
- free_irq(hcd->irq, hcd);
- hcd->irq = -1;
- /* Some Fresco Logic host controllers advertise MSI, but fail to
- * generate interrupts. Don't even try to enable MSI.
- */
- if (xhci->quirks & XHCI_BROKEN_MSI)
- goto legacy_irq;
-
- ret = xhci_setup_msix(xhci);
+ ret = xhci_try_enable_msi(hcd);
if (ret)
- /* fall back to msi*/
- ret = xhci_setup_msi(xhci);
-
- if (ret) {
-legacy_irq:
- /* fall back to legacy interrupt*/
- ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED,
- hcd->irq_descr, hcd);
- if (ret) {
- xhci_err(xhci, "request interrupt %d failed\n",
- pdev->irq);
- return ret;
- }
- hcd->irq = pdev->irq;
- }
+ return ret;
#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
init_timer(&xhci->event_ring_timer);
@@ -694,7 +748,6 @@ int xhci_suspend(struct xhci_hcd *xhci)
int rc = 0;
struct usb_hcd *hcd = xhci_to_hcd(xhci);
u32 command;
- int i;
spin_lock_irq(&xhci->lock);
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
@@ -730,10 +783,7 @@ int xhci_suspend(struct xhci_hcd *xhci)
/* step 5: remove core well power */
/* synchronize irq when using MSI-X */
- if (xhci->msix_entries) {
- for (i = 0; i < xhci->msix_count; i++)
- synchronize_irq(xhci->msix_entries[i].vector);
- }
+ xhci_msix_sync_irqs(xhci);
return rc;
}
@@ -945,8 +995,7 @@ static int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
return -ENODEV;
if (check_virt_dev) {
- if (!udev->slot_id || !xhci->devs
- || !xhci->devs[udev->slot_id]) {
+ if (!udev->slot_id || !xhci->devs[udev->slot_id]) {
printk(KERN_DEBUG "xHCI %s called with unaddressed "
"device\n", func);
return -EINVAL;
@@ -987,7 +1036,7 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
out_ctx = xhci->devs[slot_id]->out_ctx;
ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index);
hw_max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2));
- max_packet_size = le16_to_cpu(urb->dev->ep0.desc.wMaxPacketSize);
+ max_packet_size = usb_endpoint_maxp(&urb->dev->ep0.desc);
if (hw_max_packet_size != max_packet_size) {
xhci_dbg(xhci, "Max Packet Size for ep 0 changed.\n");
xhci_dbg(xhci, "Max packet size in usb_device = %d\n",
@@ -1035,6 +1084,7 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct xhci_td *buffer;
unsigned long flags;
int ret = 0;
unsigned int slot_id, ep_index;
@@ -1065,13 +1115,15 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
if (!urb_priv)
return -ENOMEM;
+ buffer = kzalloc(size * sizeof(struct xhci_td), mem_flags);
+ if (!buffer) {
+ kfree(urb_priv);
+ return -ENOMEM;
+ }
+
for (i = 0; i < size; i++) {
- urb_priv->td[i] = kzalloc(sizeof(struct xhci_td), mem_flags);
- if (!urb_priv->td[i]) {
- urb_priv->length = i;
- xhci_urb_free_priv(xhci, urb_priv);
- return -ENOMEM;
- }
+ urb_priv->td[i] = buffer;
+ buffer++;
}
urb_priv->length = size;
@@ -1085,8 +1137,11 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
if (urb->dev->speed == USB_SPEED_FULL) {
ret = xhci_check_maxpacket(xhci, slot_id,
ep_index, urb);
- if (ret < 0)
+ if (ret < 0) {
+ xhci_urb_free_priv(xhci, urb_priv);
+ urb->hcpriv = NULL;
return ret;
+ }
}
/* We have a spinlock and interrupts disabled, so we must pass
@@ -1097,6 +1152,8 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
goto dying;
ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb,
slot_id, ep_index);
+ if (ret)
+ goto free_priv;
spin_unlock_irqrestore(&xhci->lock, flags);
} else if (usb_endpoint_xfer_bulk(&urb->ep->desc)) {
spin_lock_irqsave(&xhci->lock, flags);
@@ -1117,6 +1174,8 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb,
slot_id, ep_index);
}
+ if (ret)
+ goto free_priv;
spin_unlock_irqrestore(&xhci->lock, flags);
} else if (usb_endpoint_xfer_int(&urb->ep->desc)) {
spin_lock_irqsave(&xhci->lock, flags);
@@ -1124,6 +1183,8 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
goto dying;
ret = xhci_queue_intr_tx(xhci, GFP_ATOMIC, urb,
slot_id, ep_index);
+ if (ret)
+ goto free_priv;
spin_unlock_irqrestore(&xhci->lock, flags);
} else {
spin_lock_irqsave(&xhci->lock, flags);
@@ -1131,18 +1192,22 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
goto dying;
ret = xhci_queue_isoc_tx_prepare(xhci, GFP_ATOMIC, urb,
slot_id, ep_index);
+ if (ret)
+ goto free_priv;
spin_unlock_irqrestore(&xhci->lock, flags);
}
exit:
return ret;
dying:
- xhci_urb_free_priv(xhci, urb_priv);
- urb->hcpriv = NULL;
xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for "
"non-responsive xHCI host.\n",
urb->ep->desc.bEndpointAddress, urb);
+ ret = -ESHUTDOWN;
+free_priv:
+ xhci_urb_free_priv(xhci, urb_priv);
+ urb->hcpriv = NULL;
spin_unlock_irqrestore(&xhci->lock, flags);
- return -ESHUTDOWN;
+ return ret;
}
/* Get the right ring for the given URB.
@@ -1239,6 +1304,13 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED)) {
xhci_dbg(xhci, "HW died, freeing TD.\n");
urb_priv = urb->hcpriv;
+ for (i = urb_priv->td_cnt; i < urb_priv->length; i++) {
+ td = urb_priv->td[i];
+ if (!list_empty(&td->td_list))
+ list_del_init(&td->td_list);
+ if (!list_empty(&td->cancelled_td_list))
+ list_del_init(&td->cancelled_td_list);
+ }
usb_hcd_unlink_urb_from_ep(hcd, urb);
spin_unlock_irqrestore(&xhci->lock, flags);
@@ -1727,6 +1799,564 @@ static void xhci_finish_resource_reservation(struct xhci_hcd *xhci,
xhci->num_active_eps);
}
+unsigned int xhci_get_block_size(struct usb_device *udev)
+{
+ switch (udev->speed) {
+ case USB_SPEED_LOW:
+ case USB_SPEED_FULL:
+ return FS_BLOCK;
+ case USB_SPEED_HIGH:
+ return HS_BLOCK;
+ case USB_SPEED_SUPER:
+ return SS_BLOCK;
+ case USB_SPEED_UNKNOWN:
+ case USB_SPEED_WIRELESS:
+ default:
+ /* Should never happen */
+ return 1;
+ }
+}
+
+unsigned int xhci_get_largest_overhead(struct xhci_interval_bw *interval_bw)
+{
+ if (interval_bw->overhead[LS_OVERHEAD_TYPE])
+ return LS_OVERHEAD;
+ if (interval_bw->overhead[FS_OVERHEAD_TYPE])
+ return FS_OVERHEAD;
+ return HS_OVERHEAD;
+}
+
+/* If we are changing a LS/FS device under a HS hub,
+ * make sure (if we are activating a new TT) that the HS bus has enough
+ * bandwidth for this new TT.
+ */
+static int xhci_check_tt_bw_table(struct xhci_hcd *xhci,
+ struct xhci_virt_device *virt_dev,
+ int old_active_eps)
+{
+ struct xhci_interval_bw_table *bw_table;
+ struct xhci_tt_bw_info *tt_info;
+
+ /* Find the bandwidth table for the root port this TT is attached to. */
+ bw_table = &xhci->rh_bw[virt_dev->real_port - 1].bw_table;
+ tt_info = virt_dev->tt_info;
+ /* If this TT already had active endpoints, the bandwidth for this TT
+ * has already been added. Removing all periodic endpoints (and thus
+ * making the TT enactive) will only decrease the bandwidth used.
+ */
+ if (old_active_eps)
+ return 0;
+ if (old_active_eps == 0 && tt_info->active_eps != 0) {
+ if (bw_table->bw_used + TT_HS_OVERHEAD > HS_BW_LIMIT)
+ return -ENOMEM;
+ return 0;
+ }
+ /* Not sure why we would have no new active endpoints...
+ *
+ * Maybe because of an Evaluate Context change for a hub update or a
+ * control endpoint 0 max packet size change?
+ * FIXME: skip the bandwidth calculation in that case.
+ */
+ return 0;
+}
+
+static int xhci_check_ss_bw(struct xhci_hcd *xhci,
+ struct xhci_virt_device *virt_dev)
+{
+ unsigned int bw_reserved;
+
+ bw_reserved = DIV_ROUND_UP(SS_BW_RESERVED*SS_BW_LIMIT_IN, 100);
+ if (virt_dev->bw_table->ss_bw_in > (SS_BW_LIMIT_IN - bw_reserved))
+ return -ENOMEM;
+
+ bw_reserved = DIV_ROUND_UP(SS_BW_RESERVED*SS_BW_LIMIT_OUT, 100);
+ if (virt_dev->bw_table->ss_bw_out > (SS_BW_LIMIT_OUT - bw_reserved))
+ return -ENOMEM;
+
+ return 0;
+}
+
+/*
+ * This algorithm is a very conservative estimate of the worst-case scheduling
+ * scenario for any one interval. The hardware dynamically schedules the
+ * packets, so we can't tell which microframe could be the limiting factor in
+ * the bandwidth scheduling. This only takes into account periodic endpoints.
+ *
+ * Obviously, we can't solve an NP complete problem to find the minimum worst
+ * case scenario. Instead, we come up with an estimate that is no less than
+ * the worst case bandwidth used for any one microframe, but may be an
+ * over-estimate.
+ *
+ * We walk the requirements for each endpoint by interval, starting with the
+ * smallest interval, and place packets in the schedule where there is only one
+ * possible way to schedule packets for that interval. In order to simplify
+ * this algorithm, we record the largest max packet size for each interval, and
+ * assume all packets will be that size.
+ *
+ * For interval 0, we obviously must schedule all packets for each interval.
+ * The bandwidth for interval 0 is just the amount of data to be transmitted
+ * (the sum of all max ESIT payload sizes, plus any overhead per packet times
+ * the number of packets).
+ *
+ * For interval 1, we have two possible microframes to schedule those packets
+ * in. For this algorithm, if we can schedule the same number of packets for
+ * each possible scheduling opportunity (each microframe), we will do so. The
+ * remaining number of packets will be saved to be transmitted in the gaps in
+ * the next interval's scheduling sequence.
+ *
+ * As we move those remaining packets to be scheduled with interval 2 packets,
+ * we have to double the number of remaining packets to transmit. This is
+ * because the intervals are actually powers of 2, and we would be transmitting
+ * the previous interval's packets twice in this interval. We also have to be
+ * sure that when we look at the largest max packet size for this interval, we
+ * also look at the largest max packet size for the remaining packets and take
+ * the greater of the two.
+ *
+ * The algorithm continues to evenly distribute packets in each scheduling
+ * opportunity, and push the remaining packets out, until we get to the last
+ * interval. Then those packets and their associated overhead are just added
+ * to the bandwidth used.
+ */
+static int xhci_check_bw_table(struct xhci_hcd *xhci,
+ struct xhci_virt_device *virt_dev,
+ int old_active_eps)
+{
+ unsigned int bw_reserved;
+ unsigned int max_bandwidth;
+ unsigned int bw_used;
+ unsigned int block_size;
+ struct xhci_interval_bw_table *bw_table;
+ unsigned int packet_size = 0;
+ unsigned int overhead = 0;
+ unsigned int packets_transmitted = 0;
+ unsigned int packets_remaining = 0;
+ unsigned int i;
+
+ if (virt_dev->udev->speed == USB_SPEED_SUPER)
+ return xhci_check_ss_bw(xhci, virt_dev);
+
+ if (virt_dev->udev->speed == USB_SPEED_HIGH) {
+ max_bandwidth = HS_BW_LIMIT;
+ /* Convert percent of bus BW reserved to blocks reserved */
+ bw_reserved = DIV_ROUND_UP(HS_BW_RESERVED * max_bandwidth, 100);
+ } else {
+ max_bandwidth = FS_BW_LIMIT;
+ bw_reserved = DIV_ROUND_UP(FS_BW_RESERVED * max_bandwidth, 100);
+ }
+
+ bw_table = virt_dev->bw_table;
+ /* We need to translate the max packet size and max ESIT payloads into
+ * the units the hardware uses.
+ */
+ block_size = xhci_get_block_size(virt_dev->udev);
+
+ /* If we are manipulating a LS/FS device under a HS hub, double check
+ * that the HS bus has enough bandwidth if we are activing a new TT.
+ */
+ if (virt_dev->tt_info) {
+ xhci_dbg(xhci, "Recalculating BW for rootport %u\n",
+ virt_dev->real_port);
+ if (xhci_check_tt_bw_table(xhci, virt_dev, old_active_eps)) {
+ xhci_warn(xhci, "Not enough bandwidth on HS bus for "
+ "newly activated TT.\n");
+ return -ENOMEM;
+ }
+ xhci_dbg(xhci, "Recalculating BW for TT slot %u port %u\n",
+ virt_dev->tt_info->slot_id,
+ virt_dev->tt_info->ttport);
+ } else {
+ xhci_dbg(xhci, "Recalculating BW for rootport %u\n",
+ virt_dev->real_port);
+ }
+
+ /* Add in how much bandwidth will be used for interval zero, or the
+ * rounded max ESIT payload + number of packets * largest overhead.
+ */
+ bw_used = DIV_ROUND_UP(bw_table->interval0_esit_payload, block_size) +
+ bw_table->interval_bw[0].num_packets *
+ xhci_get_largest_overhead(&bw_table->interval_bw[0]);
+
+ for (i = 1; i < XHCI_MAX_INTERVAL; i++) {
+ unsigned int bw_added;
+ unsigned int largest_mps;
+ unsigned int interval_overhead;
+
+ /*
+ * How many packets could we transmit in this interval?
+ * If packets didn't fit in the previous interval, we will need
+ * to transmit that many packets twice within this interval.
+ */
+ packets_remaining = 2 * packets_remaining +
+ bw_table->interval_bw[i].num_packets;
+
+ /* Find the largest max packet size of this or the previous
+ * interval.
+ */
+ if (list_empty(&bw_table->interval_bw[i].endpoints))
+ largest_mps = 0;
+ else {
+ struct xhci_virt_ep *virt_ep;
+ struct list_head *ep_entry;
+
+ ep_entry = bw_table->interval_bw[i].endpoints.next;
+ virt_ep = list_entry(ep_entry,
+ struct xhci_virt_ep, bw_endpoint_list);
+ /* Convert to blocks, rounding up */
+ largest_mps = DIV_ROUND_UP(
+ virt_ep->bw_info.max_packet_size,
+ block_size);
+ }
+ if (largest_mps > packet_size)
+ packet_size = largest_mps;
+
+ /* Use the larger overhead of this or the previous interval. */
+ interval_overhead = xhci_get_largest_overhead(
+ &bw_table->interval_bw[i]);
+ if (interval_overhead > overhead)
+ overhead = interval_overhead;
+
+ /* How many packets can we evenly distribute across
+ * (1 << (i + 1)) possible scheduling opportunities?
+ */
+ packets_transmitted = packets_remaining >> (i + 1);
+
+ /* Add in the bandwidth used for those scheduled packets */
+ bw_added = packets_transmitted * (overhead + packet_size);
+
+ /* How many packets do we have remaining to transmit? */
+ packets_remaining = packets_remaining % (1 << (i + 1));
+
+ /* What largest max packet size should those packets have? */
+ /* If we've transmitted all packets, don't carry over the
+ * largest packet size.
+ */
+ if (packets_remaining == 0) {
+ packet_size = 0;
+ overhead = 0;
+ } else if (packets_transmitted > 0) {
+ /* Otherwise if we do have remaining packets, and we've
+ * scheduled some packets in this interval, take the
+ * largest max packet size from endpoints with this
+ * interval.
+ */
+ packet_size = largest_mps;
+ overhead = interval_overhead;
+ }
+ /* Otherwise carry over packet_size and overhead from the last
+ * time we had a remainder.
+ */
+ bw_used += bw_added;
+ if (bw_used > max_bandwidth) {
+ xhci_warn(xhci, "Not enough bandwidth. "
+ "Proposed: %u, Max: %u\n",
+ bw_used, max_bandwidth);
+ return -ENOMEM;
+ }
+ }
+ /*
+ * Ok, we know we have some packets left over after even-handedly
+ * scheduling interval 15. We don't know which microframes they will
+ * fit into, so we over-schedule and say they will be scheduled every
+ * microframe.
+ */
+ if (packets_remaining > 0)
+ bw_used += overhead + packet_size;
+
+ if (!virt_dev->tt_info && virt_dev->udev->speed == USB_SPEED_HIGH) {
+ unsigned int port_index = virt_dev->real_port - 1;
+
+ /* OK, we're manipulating a HS device attached to a
+ * root port bandwidth domain. Include the number of active TTs
+ * in the bandwidth used.
+ */
+ bw_used += TT_HS_OVERHEAD *
+ xhci->rh_bw[port_index].num_active_tts;
+ }
+
+ xhci_dbg(xhci, "Final bandwidth: %u, Limit: %u, Reserved: %u, "
+ "Available: %u " "percent\n",
+ bw_used, max_bandwidth, bw_reserved,
+ (max_bandwidth - bw_used - bw_reserved) * 100 /
+ max_bandwidth);
+
+ bw_used += bw_reserved;
+ if (bw_used > max_bandwidth) {
+ xhci_warn(xhci, "Not enough bandwidth. Proposed: %u, Max: %u\n",
+ bw_used, max_bandwidth);
+ return -ENOMEM;
+ }
+
+ bw_table->bw_used = bw_used;
+ return 0;
+}
+
+static bool xhci_is_async_ep(unsigned int ep_type)
+{
+ return (ep_type != ISOC_OUT_EP && ep_type != INT_OUT_EP &&
+ ep_type != ISOC_IN_EP &&
+ ep_type != INT_IN_EP);
+}
+
+static bool xhci_is_sync_in_ep(unsigned int ep_type)
+{
+ return (ep_type == ISOC_IN_EP || ep_type != INT_IN_EP);
+}
+
+static unsigned int xhci_get_ss_bw_consumed(struct xhci_bw_info *ep_bw)
+{
+ unsigned int mps = DIV_ROUND_UP(ep_bw->max_packet_size, SS_BLOCK);
+
+ if (ep_bw->ep_interval == 0)
+ return SS_OVERHEAD_BURST +
+ (ep_bw->mult * ep_bw->num_packets *
+ (SS_OVERHEAD + mps));
+ return DIV_ROUND_UP(ep_bw->mult * ep_bw->num_packets *
+ (SS_OVERHEAD + mps + SS_OVERHEAD_BURST),
+ 1 << ep_bw->ep_interval);
+
+}
+
+void xhci_drop_ep_from_interval_table(struct xhci_hcd *xhci,
+ struct xhci_bw_info *ep_bw,
+ struct xhci_interval_bw_table *bw_table,
+ struct usb_device *udev,
+ struct xhci_virt_ep *virt_ep,
+ struct xhci_tt_bw_info *tt_info)
+{
+ struct xhci_interval_bw *interval_bw;
+ int normalized_interval;
+
+ if (xhci_is_async_ep(ep_bw->type))
+ return;
+
+ if (udev->speed == USB_SPEED_SUPER) {
+ if (xhci_is_sync_in_ep(ep_bw->type))
+ xhci->devs[udev->slot_id]->bw_table->ss_bw_in -=
+ xhci_get_ss_bw_consumed(ep_bw);
+ else
+ xhci->devs[udev->slot_id]->bw_table->ss_bw_out -=
+ xhci_get_ss_bw_consumed(ep_bw);
+ return;
+ }
+
+ /* SuperSpeed endpoints never get added to intervals in the table, so
+ * this check is only valid for HS/FS/LS devices.
+ */
+ if (list_empty(&virt_ep->bw_endpoint_list))
+ return;
+ /* For LS/FS devices, we need to translate the interval expressed in
+ * microframes to frames.
+ */
+ if (udev->speed == USB_SPEED_HIGH)
+ normalized_interval = ep_bw->ep_interval;
+ else
+ normalized_interval = ep_bw->ep_interval - 3;
+
+ if (normalized_interval == 0)
+ bw_table->interval0_esit_payload -= ep_bw->max_esit_payload;
+ interval_bw = &bw_table->interval_bw[normalized_interval];
+ interval_bw->num_packets -= ep_bw->num_packets;
+ switch (udev->speed) {
+ case USB_SPEED_LOW:
+ interval_bw->overhead[LS_OVERHEAD_TYPE] -= 1;
+ break;
+ case USB_SPEED_FULL:
+ interval_bw->overhead[FS_OVERHEAD_TYPE] -= 1;
+ break;
+ case USB_SPEED_HIGH:
+ interval_bw->overhead[HS_OVERHEAD_TYPE] -= 1;
+ break;
+ case USB_SPEED_SUPER:
+ case USB_SPEED_UNKNOWN:
+ case USB_SPEED_WIRELESS:
+ /* Should never happen because only LS/FS/HS endpoints will get
+ * added to the endpoint list.
+ */
+ return;
+ }
+ if (tt_info)
+ tt_info->active_eps -= 1;
+ list_del_init(&virt_ep->bw_endpoint_list);
+}
+
+static void xhci_add_ep_to_interval_table(struct xhci_hcd *xhci,
+ struct xhci_bw_info *ep_bw,
+ struct xhci_interval_bw_table *bw_table,
+ struct usb_device *udev,
+ struct xhci_virt_ep *virt_ep,
+ struct xhci_tt_bw_info *tt_info)
+{
+ struct xhci_interval_bw *interval_bw;
+ struct xhci_virt_ep *smaller_ep;
+ int normalized_interval;
+
+ if (xhci_is_async_ep(ep_bw->type))
+ return;
+
+ if (udev->speed == USB_SPEED_SUPER) {
+ if (xhci_is_sync_in_ep(ep_bw->type))
+ xhci->devs[udev->slot_id]->bw_table->ss_bw_in +=
+ xhci_get_ss_bw_consumed(ep_bw);
+ else
+ xhci->devs[udev->slot_id]->bw_table->ss_bw_out +=
+ xhci_get_ss_bw_consumed(ep_bw);
+ return;
+ }
+
+ /* For LS/FS devices, we need to translate the interval expressed in
+ * microframes to frames.
+ */
+ if (udev->speed == USB_SPEED_HIGH)
+ normalized_interval = ep_bw->ep_interval;
+ else
+ normalized_interval = ep_bw->ep_interval - 3;
+
+ if (normalized_interval == 0)
+ bw_table->interval0_esit_payload += ep_bw->max_esit_payload;
+ interval_bw = &bw_table->interval_bw[normalized_interval];
+ interval_bw->num_packets += ep_bw->num_packets;
+ switch (udev->speed) {
+ case USB_SPEED_LOW:
+ interval_bw->overhead[LS_OVERHEAD_TYPE] += 1;
+ break;
+ case USB_SPEED_FULL:
+ interval_bw->overhead[FS_OVERHEAD_TYPE] += 1;
+ break;
+ case USB_SPEED_HIGH:
+ interval_bw->overhead[HS_OVERHEAD_TYPE] += 1;
+ break;
+ case USB_SPEED_SUPER:
+ case USB_SPEED_UNKNOWN:
+ case USB_SPEED_WIRELESS:
+ /* Should never happen because only LS/FS/HS endpoints will get
+ * added to the endpoint list.
+ */
+ return;
+ }
+
+ if (tt_info)
+ tt_info->active_eps += 1;
+ /* Insert the endpoint into the list, largest max packet size first. */
+ list_for_each_entry(smaller_ep, &interval_bw->endpoints,
+ bw_endpoint_list) {
+ if (ep_bw->max_packet_size >=
+ smaller_ep->bw_info.max_packet_size) {
+ /* Add the new ep before the smaller endpoint */
+ list_add_tail(&virt_ep->bw_endpoint_list,
+ &smaller_ep->bw_endpoint_list);
+ return;
+ }
+ }
+ /* Add the new endpoint at the end of the list. */
+ list_add_tail(&virt_ep->bw_endpoint_list,
+ &interval_bw->endpoints);
+}
+
+void xhci_update_tt_active_eps(struct xhci_hcd *xhci,
+ struct xhci_virt_device *virt_dev,
+ int old_active_eps)
+{
+ struct xhci_root_port_bw_info *rh_bw_info;
+ if (!virt_dev->tt_info)
+ return;
+
+ rh_bw_info = &xhci->rh_bw[virt_dev->real_port - 1];
+ if (old_active_eps == 0 &&
+ virt_dev->tt_info->active_eps != 0) {
+ rh_bw_info->num_active_tts += 1;
+ rh_bw_info->bw_table.bw_used += TT_HS_OVERHEAD;
+ } else if (old_active_eps != 0 &&
+ virt_dev->tt_info->active_eps == 0) {
+ rh_bw_info->num_active_tts -= 1;
+ rh_bw_info->bw_table.bw_used -= TT_HS_OVERHEAD;
+ }
+}
+
+static int xhci_reserve_bandwidth(struct xhci_hcd *xhci,
+ struct xhci_virt_device *virt_dev,
+ struct xhci_container_ctx *in_ctx)
+{
+ struct xhci_bw_info ep_bw_info[31];
+ int i;
+ struct xhci_input_control_ctx *ctrl_ctx;
+ int old_active_eps = 0;
+
+ if (virt_dev->tt_info)
+ old_active_eps = virt_dev->tt_info->active_eps;
+
+ ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
+
+ for (i = 0; i < 31; i++) {
+ if (!EP_IS_ADDED(ctrl_ctx, i) && !EP_IS_DROPPED(ctrl_ctx, i))
+ continue;
+
+ /* Make a copy of the BW info in case we need to revert this */
+ memcpy(&ep_bw_info[i], &virt_dev->eps[i].bw_info,
+ sizeof(ep_bw_info[i]));
+ /* Drop the endpoint from the interval table if the endpoint is
+ * being dropped or changed.
+ */
+ if (EP_IS_DROPPED(ctrl_ctx, i))
+ xhci_drop_ep_from_interval_table(xhci,
+ &virt_dev->eps[i].bw_info,
+ virt_dev->bw_table,
+ virt_dev->udev,
+ &virt_dev->eps[i],
+ virt_dev->tt_info);
+ }
+ /* Overwrite the information stored in the endpoints' bw_info */
+ xhci_update_bw_info(xhci, virt_dev->in_ctx, ctrl_ctx, virt_dev);
+ for (i = 0; i < 31; i++) {
+ /* Add any changed or added endpoints to the interval table */
+ if (EP_IS_ADDED(ctrl_ctx, i))
+ xhci_add_ep_to_interval_table(xhci,
+ &virt_dev->eps[i].bw_info,
+ virt_dev->bw_table,
+ virt_dev->udev,
+ &virt_dev->eps[i],
+ virt_dev->tt_info);
+ }
+
+ if (!xhci_check_bw_table(xhci, virt_dev, old_active_eps)) {
+ /* Ok, this fits in the bandwidth we have.
+ * Update the number of active TTs.
+ */
+ xhci_update_tt_active_eps(xhci, virt_dev, old_active_eps);
+ return 0;
+ }
+
+ /* We don't have enough bandwidth for this, revert the stored info. */
+ for (i = 0; i < 31; i++) {
+ if (!EP_IS_ADDED(ctrl_ctx, i) && !EP_IS_DROPPED(ctrl_ctx, i))
+ continue;
+
+ /* Drop the new copies of any added or changed endpoints from
+ * the interval table.
+ */
+ if (EP_IS_ADDED(ctrl_ctx, i)) {
+ xhci_drop_ep_from_interval_table(xhci,
+ &virt_dev->eps[i].bw_info,
+ virt_dev->bw_table,
+ virt_dev->udev,
+ &virt_dev->eps[i],
+ virt_dev->tt_info);
+ }
+ /* Revert the endpoint back to its old information */
+ memcpy(&virt_dev->eps[i].bw_info, &ep_bw_info[i],
+ sizeof(ep_bw_info[i]));
+ /* Add any changed or dropped endpoints back into the table */
+ if (EP_IS_DROPPED(ctrl_ctx, i))
+ xhci_add_ep_to_interval_table(xhci,
+ &virt_dev->eps[i].bw_info,
+ virt_dev->bw_table,
+ virt_dev->udev,
+ &virt_dev->eps[i],
+ virt_dev->tt_info);
+ }
+ return -ENOMEM;
+}
+
+
/* Issue a configure endpoint command or evaluate context command
* and wait for it to finish.
*/
@@ -1745,17 +2375,30 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
spin_lock_irqsave(&xhci->lock, flags);
virt_dev = xhci->devs[udev->slot_id];
- if (command) {
+
+ if (command)
in_ctx = command->in_ctx;
- if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK) &&
- xhci_reserve_host_resources(xhci, in_ctx)) {
- spin_unlock_irqrestore(&xhci->lock, flags);
- xhci_warn(xhci, "Not enough host resources, "
- "active endpoint contexts = %u\n",
- xhci->num_active_eps);
- return -ENOMEM;
- }
+ else
+ in_ctx = virt_dev->in_ctx;
+
+ if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK) &&
+ xhci_reserve_host_resources(xhci, in_ctx)) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ xhci_warn(xhci, "Not enough host resources, "
+ "active endpoint contexts = %u\n",
+ xhci->num_active_eps);
+ return -ENOMEM;
+ }
+ if ((xhci->quirks & XHCI_SW_BW_CHECKING) &&
+ xhci_reserve_bandwidth(xhci, virt_dev, in_ctx)) {
+ if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK))
+ xhci_free_host_resources(xhci, in_ctx);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ xhci_warn(xhci, "Not enough bandwidth\n");
+ return -ENOMEM;
+ }
+ if (command) {
cmd_completion = command->completion;
cmd_status = &command->status;
command->command_trb = xhci->cmd_ring->enqueue;
@@ -1769,15 +2412,6 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
list_add_tail(&command->cmd_list, &virt_dev->cmd_list);
} else {
- in_ctx = virt_dev->in_ctx;
- if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK) &&
- xhci_reserve_host_resources(xhci, in_ctx)) {
- spin_unlock_irqrestore(&xhci->lock, flags);
- xhci_warn(xhci, "Not enough host resources, "
- "active endpoint contexts = %u\n",
- xhci->num_active_eps);
- return -ENOMEM;
- }
cmd_completion = &virt_dev->cmd_completion;
cmd_status = &virt_dev->cmd_status;
}
@@ -1868,6 +2502,12 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG);
ctrl_ctx->add_flags &= cpu_to_le32(~EP0_FLAG);
ctrl_ctx->drop_flags &= cpu_to_le32(~(SLOT_FLAG | EP0_FLAG));
+
+ /* Don't issue the command if there's no endpoints to update. */
+ if (ctrl_ctx->add_flags == cpu_to_le32(SLOT_FLAG) &&
+ ctrl_ctx->drop_flags == 0)
+ return 0;
+
xhci_dbg(xhci, "New Input Control Context:\n");
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
xhci_dbg_ctx(xhci, virt_dev->in_ctx,
@@ -2505,6 +3145,7 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
int timeleft;
int last_freed_endpoint;
struct xhci_slot_ctx *slot_ctx;
+ int old_active_eps = 0;
ret = xhci_check_args(hcd, udev, NULL, 0, false, __func__);
if (ret <= 0)
@@ -2646,7 +3287,18 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
last_freed_endpoint = i;
}
- }
+ if (!list_empty(&virt_dev->eps[i].bw_endpoint_list))
+ xhci_drop_ep_from_interval_table(xhci,
+ &virt_dev->eps[i].bw_info,
+ virt_dev->bw_table,
+ udev,
+ &virt_dev->eps[i],
+ virt_dev->tt_info);
+ xhci_clear_endpoint_bw_info(&virt_dev->eps[i].bw_info);
+ }
+ /* If necessary, update the number of active TTs on this root port */
+ xhci_update_tt_active_eps(xhci, virt_dev, old_active_eps);
+
xhci_dbg(xhci, "Output context after successful reset device cmd:\n");
xhci_dbg_ctx(xhci, virt_dev->out_ctx, last_freed_endpoint);
ret = 0;
@@ -2684,6 +3336,11 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
del_timer_sync(&virt_dev->eps[i].stop_cmd_timer);
}
+ if (udev->usb2_hw_lpm_enabled) {
+ xhci_set_usb2_hardware_lpm(hcd, udev, 0);
+ udev->usb2_hw_lpm_enabled = 0;
+ }
+
spin_lock_irqsave(&xhci->lock, flags);
/* Don't disable the slot if the host controller is dead. */
state = xhci_readl(xhci, &xhci->op_regs->status);
@@ -2869,7 +3526,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
* command on a timeout.
*/
if (timeleft <= 0) {
- xhci_warn(xhci, "%s while waiting for a slot\n",
+ xhci_warn(xhci, "%s while waiting for address device command\n",
timeleft == 0 ? "Timeout" : "Signal");
/* FIXME cancel the address device command */
return -ETIME;
@@ -2937,6 +3594,254 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
return 0;
}
+#ifdef CONFIG_USB_SUSPEND
+
+/* BESL to HIRD Encoding array for USB2 LPM */
+static int xhci_besl_encoding[16] = {125, 150, 200, 300, 400, 500, 1000, 2000,
+ 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000};
+
+/* Calculate HIRD/BESL for USB2 PORTPMSC*/
+static int xhci_calculate_hird_besl(int u2del, bool use_besl)
+{
+ int hird;
+
+ if (use_besl) {
+ for (hird = 0; hird < 16; hird++) {
+ if (xhci_besl_encoding[hird] >= u2del)
+ break;
+ }
+ } else {
+ if (u2del <= 50)
+ hird = 0;
+ else
+ hird = (u2del - 51) / 75 + 1;
+
+ if (hird > 15)
+ hird = 15;
+ }
+
+ return hird;
+}
+
+static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd,
+ struct usb_device *udev)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct dev_info *dev_info;
+ __le32 __iomem **port_array;
+ __le32 __iomem *addr, *pm_addr;
+ u32 temp, dev_id;
+ unsigned int port_num;
+ unsigned long flags;
+ int u2del, hird;
+ int ret;
+
+ if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support ||
+ !udev->lpm_capable)
+ return -EINVAL;
+
+ /* we only support lpm for non-hub device connected to root hub yet */
+ if (!udev->parent || udev->parent->parent ||
+ udev->descriptor.bDeviceClass == USB_CLASS_HUB)
+ return -EINVAL;
+
+ spin_lock_irqsave(&xhci->lock, flags);
+
+ /* Look for devices in lpm_failed_devs list */
+ dev_id = le16_to_cpu(udev->descriptor.idVendor) << 16 |
+ le16_to_cpu(udev->descriptor.idProduct);
+ list_for_each_entry(dev_info, &xhci->lpm_failed_devs, list) {
+ if (dev_info->dev_id == dev_id) {
+ ret = -EINVAL;
+ goto finish;
+ }
+ }
+
+ port_array = xhci->usb2_ports;
+ port_num = udev->portnum - 1;
+
+ if (port_num > HCS_MAX_PORTS(xhci->hcs_params1)) {
+ xhci_dbg(xhci, "invalid port number %d\n", udev->portnum);
+ ret = -EINVAL;
+ goto finish;
+ }
+
+ /*
+ * Test USB 2.0 software LPM.
+ * FIXME: some xHCI 1.0 hosts may implement a new register to set up
+ * hardware-controlled USB 2.0 LPM. See section 5.4.11 and 4.23.5.1.1.1
+ * in the June 2011 errata release.
+ */
+ xhci_dbg(xhci, "test port %d software LPM\n", port_num);
+ /*
+ * Set L1 Device Slot and HIRD/BESL.
+ * Check device's USB 2.0 extension descriptor to determine whether
+ * HIRD or BESL shoule be used. See USB2.0 LPM errata.
+ */
+ pm_addr = port_array[port_num] + 1;
+ u2del = HCS_U2_LATENCY(xhci->hcs_params3);
+ if (le32_to_cpu(udev->bos->ext_cap->bmAttributes) & (1 << 2))
+ hird = xhci_calculate_hird_besl(u2del, 1);
+ else
+ hird = xhci_calculate_hird_besl(u2del, 0);
+
+ temp = PORT_L1DS(udev->slot_id) | PORT_HIRD(hird);
+ xhci_writel(xhci, temp, pm_addr);
+
+ /* Set port link state to U2(L1) */
+ addr = port_array[port_num];
+ xhci_set_link_state(xhci, port_array, port_num, XDEV_U2);
+
+ /* wait for ACK */
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ msleep(10);
+ spin_lock_irqsave(&xhci->lock, flags);
+
+ /* Check L1 Status */
+ ret = handshake(xhci, pm_addr, PORT_L1S_MASK, PORT_L1S_SUCCESS, 125);
+ if (ret != -ETIMEDOUT) {
+ /* enter L1 successfully */
+ temp = xhci_readl(xhci, addr);
+ xhci_dbg(xhci, "port %d entered L1 state, port status 0x%x\n",
+ port_num, temp);
+ ret = 0;
+ } else {
+ temp = xhci_readl(xhci, pm_addr);
+ xhci_dbg(xhci, "port %d software lpm failed, L1 status %d\n",
+ port_num, temp & PORT_L1S_MASK);
+ ret = -EINVAL;
+ }
+
+ /* Resume the port */
+ xhci_set_link_state(xhci, port_array, port_num, XDEV_U0);
+
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ msleep(10);
+ spin_lock_irqsave(&xhci->lock, flags);
+
+ /* Clear PLC */
+ xhci_test_and_clear_bit(xhci, port_array, port_num, PORT_PLC);
+
+ /* Check PORTSC to make sure the device is in the right state */
+ if (!ret) {
+ temp = xhci_readl(xhci, addr);
+ xhci_dbg(xhci, "resumed port %d status 0x%x\n", port_num, temp);
+ if (!(temp & PORT_CONNECT) || !(temp & PORT_PE) ||
+ (temp & PORT_PLS_MASK) != XDEV_U0) {
+ xhci_dbg(xhci, "port L1 resume fail\n");
+ ret = -EINVAL;
+ }
+ }
+
+ if (ret) {
+ /* Insert dev to lpm_failed_devs list */
+ xhci_warn(xhci, "device LPM test failed, may disconnect and "
+ "re-enumerate\n");
+ dev_info = kzalloc(sizeof(struct dev_info), GFP_ATOMIC);
+ if (!dev_info) {
+ ret = -ENOMEM;
+ goto finish;
+ }
+ dev_info->dev_id = dev_id;
+ INIT_LIST_HEAD(&dev_info->list);
+ list_add(&dev_info->list, &xhci->lpm_failed_devs);
+ } else {
+ xhci_ring_device(xhci, udev->slot_id);
+ }
+
+finish:
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ return ret;
+}
+
+int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
+ struct usb_device *udev, int enable)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ __le32 __iomem **port_array;
+ __le32 __iomem *pm_addr;
+ u32 temp;
+ unsigned int port_num;
+ unsigned long flags;
+ int u2del, hird;
+
+ if (hcd->speed == HCD_USB3 || !xhci->hw_lpm_support ||
+ !udev->lpm_capable)
+ return -EPERM;
+
+ if (!udev->parent || udev->parent->parent ||
+ udev->descriptor.bDeviceClass == USB_CLASS_HUB)
+ return -EPERM;
+
+ if (udev->usb2_hw_lpm_capable != 1)
+ return -EPERM;
+
+ spin_lock_irqsave(&xhci->lock, flags);
+
+ port_array = xhci->usb2_ports;
+ port_num = udev->portnum - 1;
+ pm_addr = port_array[port_num] + 1;
+ temp = xhci_readl(xhci, pm_addr);
+
+ xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n",
+ enable ? "enable" : "disable", port_num);
+
+ u2del = HCS_U2_LATENCY(xhci->hcs_params3);
+ if (le32_to_cpu(udev->bos->ext_cap->bmAttributes) & (1 << 2))
+ hird = xhci_calculate_hird_besl(u2del, 1);
+ else
+ hird = xhci_calculate_hird_besl(u2del, 0);
+
+ if (enable) {
+ temp &= ~PORT_HIRD_MASK;
+ temp |= PORT_HIRD(hird) | PORT_RWE;
+ xhci_writel(xhci, temp, pm_addr);
+ temp = xhci_readl(xhci, pm_addr);
+ temp |= PORT_HLE;
+ xhci_writel(xhci, temp, pm_addr);
+ } else {
+ temp &= ~(PORT_HLE | PORT_RWE | PORT_HIRD_MASK);
+ xhci_writel(xhci, temp, pm_addr);
+ }
+
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ return 0;
+}
+
+int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ int ret;
+
+ ret = xhci_usb2_software_lpm_test(hcd, udev);
+ if (!ret) {
+ xhci_dbg(xhci, "software LPM test succeed\n");
+ if (xhci->hw_lpm_support == 1) {
+ udev->usb2_hw_lpm_capable = 1;
+ ret = xhci_set_usb2_hardware_lpm(hcd, udev, 1);
+ if (!ret)
+ udev->usb2_hw_lpm_enabled = 1;
+ }
+ }
+
+ return 0;
+}
+
+#else
+
+int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
+ struct usb_device *udev, int enable)
+{
+ return 0;
+}
+
+int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
+{
+ return 0;
+}
+
+#endif /* CONFIG_USB_SUSPEND */
+
/* Once a hub descriptor is fetched for a device, we need to update the xHC's
* internal data structures for the device.
*/
@@ -2968,6 +3873,14 @@ int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
}
spin_lock_irqsave(&xhci->lock, flags);
+ if (hdev->speed == USB_SPEED_HIGH &&
+ xhci_alloc_tt_info(xhci, vdev, hdev, tt, GFP_ATOMIC)) {
+ xhci_dbg(xhci, "Could not allocate xHCI TT structure.\n");
+ xhci_free_command(xhci, config_cmd);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ return -ENOMEM;
+ }
+
xhci_slot_copy(xhci, config_cmd->in_ctx, vdev->out_ctx);
ctrl_ctx = xhci_get_input_control_ctx(xhci, config_cmd->in_ctx);
ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG);
@@ -3031,22 +3944,108 @@ int xhci_get_frame(struct usb_hcd *hcd)
return xhci_readl(xhci, &xhci->run_regs->microframe_index) >> 3;
}
+int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
+{
+ struct xhci_hcd *xhci;
+ struct device *dev = hcd->self.controller;
+ int retval;
+ u32 temp;
+
+ hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2;
+
+ if (usb_hcd_is_primary_hcd(hcd)) {
+ xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL);
+ if (!xhci)
+ return -ENOMEM;
+ *((struct xhci_hcd **) hcd->hcd_priv) = xhci;
+ xhci->main_hcd = hcd;
+ /* Mark the first roothub as being USB 2.0.
+ * The xHCI driver will register the USB 3.0 roothub.
+ */
+ hcd->speed = HCD_USB2;
+ hcd->self.root_hub->speed = USB_SPEED_HIGH;
+ /*
+ * USB 2.0 roothub under xHCI has an integrated TT,
+ * (rate matching hub) as opposed to having an OHCI/UHCI
+ * companion controller.
+ */
+ hcd->has_tt = 1;
+ } else {
+ /* xHCI private pointer was set in xhci_pci_probe for the second
+ * registered roothub.
+ */
+ xhci = hcd_to_xhci(hcd);
+ temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
+ if (HCC_64BIT_ADDR(temp)) {
+ xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
+ dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64));
+ } else {
+ dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32));
+ }
+ return 0;
+ }
+
+ xhci->cap_regs = hcd->regs;
+ xhci->op_regs = hcd->regs +
+ HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase));
+ xhci->run_regs = hcd->regs +
+ (xhci_readl(xhci, &xhci->cap_regs->run_regs_off) & RTSOFF_MASK);
+ /* Cache read-only capability registers */
+ xhci->hcs_params1 = xhci_readl(xhci, &xhci->cap_regs->hcs_params1);
+ xhci->hcs_params2 = xhci_readl(xhci, &xhci->cap_regs->hcs_params2);
+ xhci->hcs_params3 = xhci_readl(xhci, &xhci->cap_regs->hcs_params3);
+ xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hc_capbase);
+ xhci->hci_version = HC_VERSION(xhci->hcc_params);
+ xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
+ xhci_print_registers(xhci);
+
+ get_quirks(dev, xhci);
+
+ /* Make sure the HC is halted. */
+ retval = xhci_halt(xhci);
+ if (retval)
+ goto error;
+
+ xhci_dbg(xhci, "Resetting HCD\n");
+ /* Reset the internal HC memory state and registers. */
+ retval = xhci_reset(xhci);
+ if (retval)
+ goto error;
+ xhci_dbg(xhci, "Reset complete\n");
+
+ temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
+ if (HCC_64BIT_ADDR(temp)) {
+ xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
+ dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64));
+ } else {
+ dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32));
+ }
+
+ xhci_dbg(xhci, "Calling HCD init\n");
+ /* Initialize HCD and host controller data structures. */
+ retval = xhci_init(hcd);
+ if (retval)
+ goto error;
+ xhci_dbg(xhci, "Called HCD init\n");
+ return 0;
+error:
+ kfree(xhci);
+ return retval;
+}
+
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_LICENSE("GPL");
static int __init xhci_hcd_init(void)
{
-#ifdef CONFIG_PCI
- int retval = 0;
+ int retval;
retval = xhci_register_pci();
-
if (retval < 0) {
printk(KERN_DEBUG "Problem registering PCI driver.");
return retval;
}
-#endif
/*
* Check the compiler generated sizes of structures that must be laid
* out in specific ways for hardware access.
@@ -3071,8 +4070,6 @@ module_init(xhci_hcd_init);
static void __exit xhci_hcd_cleanup(void)
{
-#ifdef CONFIG_PCI
xhci_unregister_pci();
-#endif
}
module_exit(xhci_hcd_cleanup);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index cae8e23308bf..3c8fbd2772ea 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -272,6 +272,7 @@ struct xhci_op_regs {
*/
#define PORT_PLS_MASK (0xf << 5)
#define XDEV_U0 (0x0 << 5)
+#define XDEV_U2 (0x2 << 5)
#define XDEV_U3 (0x3 << 5)
#define XDEV_RESUME (0xf << 5)
/* true: port has power (see HCC_PPC) */
@@ -362,7 +363,13 @@ struct xhci_op_regs {
/* Bits 24:31 for port testing */
/* USB2 Protocol PORTSPMSC */
-#define PORT_RWE (1 << 0x3)
+#define PORT_L1S_MASK 7
+#define PORT_L1S_SUCCESS 1
+#define PORT_RWE (1 << 3)
+#define PORT_HIRD(p) (((p) & 0xf) << 4)
+#define PORT_HIRD_MASK (0xf << 4)
+#define PORT_L1DS(p) (((p) & 0xff) << 8)
+#define PORT_HLE (1 << 16)
/**
* struct xhci_intr_reg - Interrupt Register Set
@@ -611,11 +618,13 @@ struct xhci_ep_ctx {
#define EP_STATE_ERROR 4
/* Mult - Max number of burtst within an interval, in EP companion desc. */
#define EP_MULT(p) (((p) & 0x3) << 8)
+#define CTX_TO_EP_MULT(p) (((p) >> 8) & 0x3)
/* bits 10:14 are Max Primary Streams */
/* bit 15 is Linear Stream Array */
/* Interval - period between requests to an endpoint - 125u increments. */
#define EP_INTERVAL(p) (((p) & 0xff) << 16)
#define EP_INTERVAL_TO_UFRAMES(p) (1 << (((p) >> 16) & 0xff))
+#define CTX_TO_EP_INTERVAL(p) (((p) >> 16) & 0xff)
#define EP_MAXPSTREAMS_MASK (0x1f << 10)
#define EP_MAXPSTREAMS(p) (((p) << 10) & EP_MAXPSTREAMS_MASK)
/* Endpoint is set up with a Linear Stream Array (vs. Secondary Stream Array) */
@@ -640,6 +649,7 @@ struct xhci_ep_ctx {
/* bit 6 reserved */
/* bit 7 is Host Initiate Disable - for disabling stream selection */
#define MAX_BURST(p) (((p)&0xff) << 8)
+#define CTX_TO_MAX_BURST(p) (((p) >> 8) & 0xff)
#define MAX_PACKET(p) (((p)&0xffff) << 16)
#define MAX_PACKET_MASK (0xffff << 16)
#define MAX_PACKET_DECODED(p) (((p) >> 16) & 0xffff)
@@ -652,6 +662,7 @@ struct xhci_ep_ctx {
/* tx_info bitmasks */
#define AVG_TRB_LENGTH_FOR_EP(p) ((p) & 0xffff)
#define MAX_ESIT_PAYLOAD_FOR_EP(p) (((p) & 0xffff) << 16)
+#define CTX_TO_MAX_ESIT_PAYLOAD(p) (((p) >> 16) & 0xffff)
/* deq bitmasks */
#define EP_CTX_CYCLE_MASK (1 << 0)
@@ -670,6 +681,11 @@ struct xhci_input_control_ctx {
__le32 rsvd2[6];
};
+#define EP_IS_ADDED(ctrl_ctx, i) \
+ (le32_to_cpu(ctrl_ctx->add_flags) & (1 << (i + 1)))
+#define EP_IS_DROPPED(ctrl_ctx, i) \
+ (le32_to_cpu(ctrl_ctx->drop_flags) & (1 << (i + 1)))
+
/* Represents everything that is needed to issue a command on the command ring.
* It's useful to pre-allocate these for commands that cannot fail due to
* out-of-memory errors, like freeing streams.
@@ -731,6 +747,67 @@ struct xhci_stream_info {
#define SMALL_STREAM_ARRAY_SIZE 256
#define MEDIUM_STREAM_ARRAY_SIZE 1024
+/* Some Intel xHCI host controllers need software to keep track of the bus
+ * bandwidth. Keep track of endpoint info here. Each root port is allocated
+ * the full bus bandwidth. We must also treat TTs (including each port under a
+ * multi-TT hub) as a separate bandwidth domain. The direct memory interface
+ * (DMI) also limits the total bandwidth (across all domains) that can be used.
+ */
+struct xhci_bw_info {
+ /* ep_interval is zero-based */
+ unsigned int ep_interval;
+ /* mult and num_packets are one-based */
+ unsigned int mult;
+ unsigned int num_packets;
+ unsigned int max_packet_size;
+ unsigned int max_esit_payload;
+ unsigned int type;
+};
+
+/* "Block" sizes in bytes the hardware uses for different device speeds.
+ * The logic in this part of the hardware limits the number of bits the hardware
+ * can use, so must represent bandwidth in a less precise manner to mimic what
+ * the scheduler hardware computes.
+ */
+#define FS_BLOCK 1
+#define HS_BLOCK 4
+#define SS_BLOCK 16
+#define DMI_BLOCK 32
+
+/* Each device speed has a protocol overhead (CRC, bit stuffing, etc) associated
+ * with each byte transferred. SuperSpeed devices have an initial overhead to
+ * set up bursts. These are in blocks, see above. LS overhead has already been
+ * translated into FS blocks.
+ */
+#define DMI_OVERHEAD 8
+#define DMI_OVERHEAD_BURST 4
+#define SS_OVERHEAD 8
+#define SS_OVERHEAD_BURST 32
+#define HS_OVERHEAD 26
+#define FS_OVERHEAD 20
+#define LS_OVERHEAD 128
+/* The TTs need to claim roughly twice as much bandwidth (94 bytes per
+ * microframe ~= 24Mbps) of the HS bus as the devices can actually use because
+ * of overhead associated with split transfers crossing microframe boundaries.
+ * 31 blocks is pure protocol overhead.
+ */
+#define TT_HS_OVERHEAD (31 + 94)
+#define TT_DMI_OVERHEAD (25 + 12)
+
+/* Bandwidth limits in blocks */
+#define FS_BW_LIMIT 1285
+#define TT_BW_LIMIT 1320
+#define HS_BW_LIMIT 1607
+#define SS_BW_LIMIT_IN 3906
+#define DMI_BW_LIMIT_IN 3906
+#define SS_BW_LIMIT_OUT 3906
+#define DMI_BW_LIMIT_OUT 3906
+
+/* Percentage of bus bandwidth reserved for non-periodic transfers */
+#define FS_BW_RESERVED 10
+#define HS_BW_RESERVED 20
+#define SS_BW_RESERVED 10
+
struct xhci_virt_ep {
struct xhci_ring *ring;
/* Related to endpoints that are configured to use stream IDs only */
@@ -772,8 +849,39 @@ struct xhci_virt_ep {
* process the missed tds on the endpoint ring.
*/
bool skip;
+ /* Bandwidth checking storage */
+ struct xhci_bw_info bw_info;
+ struct list_head bw_endpoint_list;
+};
+
+enum xhci_overhead_type {
+ LS_OVERHEAD_TYPE = 0,
+ FS_OVERHEAD_TYPE,
+ HS_OVERHEAD_TYPE,
+};
+
+struct xhci_interval_bw {
+ unsigned int num_packets;
+ /* Sorted by max packet size.
+ * Head of the list is the greatest max packet size.
+ */
+ struct list_head endpoints;
+ /* How many endpoints of each speed are present. */
+ unsigned int overhead[3];
+};
+
+#define XHCI_MAX_INTERVAL 16
+
+struct xhci_interval_bw_table {
+ unsigned int interval0_esit_payload;
+ struct xhci_interval_bw interval_bw[XHCI_MAX_INTERVAL];
+ /* Includes reserved bandwidth for async endpoints */
+ unsigned int bw_used;
+ unsigned int ss_bw_in;
+ unsigned int ss_bw_out;
};
+
struct xhci_virt_device {
struct usb_device *udev;
/*
@@ -798,7 +906,32 @@ struct xhci_virt_device {
/* Status of the last command issued for this device */
u32 cmd_status;
struct list_head cmd_list;
- u8 port;
+ u8 fake_port;
+ u8 real_port;
+ struct xhci_interval_bw_table *bw_table;
+ struct xhci_tt_bw_info *tt_info;
+};
+
+/*
+ * For each roothub, keep track of the bandwidth information for each periodic
+ * interval.
+ *
+ * If a high speed hub is attached to the roothub, each TT associated with that
+ * hub is a separate bandwidth domain. The interval information for the
+ * endpoints on the devices under that TT will appear in the TT structure.
+ */
+struct xhci_root_port_bw_info {
+ struct list_head tts;
+ unsigned int num_active_tts;
+ struct xhci_interval_bw_table bw_table;
+};
+
+struct xhci_tt_bw_info {
+ struct list_head tt_list;
+ int slot_id;
+ int ttport;
+ struct xhci_interval_bw_table bw_table;
+ int active_eps;
};
@@ -1198,6 +1331,12 @@ struct s3_save {
u64 erst_dequeue;
};
+/* Use for lpm */
+struct dev_info {
+ u32 dev_id;
+ struct list_head list;
+};
+
struct xhci_bus_state {
unsigned long bus_suspended;
unsigned long next_statechange;
@@ -1261,12 +1400,16 @@ struct xhci_hcd {
struct xhci_erst erst;
/* Scratchpad */
struct xhci_scratchpad *scratchpad;
+ /* Store LPM test failed devices' information */
+ struct list_head lpm_failed_devs;
/* slot enabling and address device helpers */
struct completion addr_dev;
int slot_id;
/* Internal mirror of the HW's dcbaa */
struct xhci_virt_device *devs[MAX_HC_SLOTS];
+ /* For keeping track of bandwidth domains per roothub. */
+ struct xhci_root_port_bw_info *rh_bw;
/* DMA pools */
struct dma_pool *device_pool;
@@ -1318,6 +1461,8 @@ struct xhci_hcd {
#define XHCI_EP_LIMIT_QUIRK (1 << 5)
#define XHCI_BROKEN_MSI (1 << 6)
#define XHCI_RESET_ON_RESUME (1 << 7)
+#define XHCI_SW_BW_CHECKING (1 << 8)
+#define XHCI_AMD_0x96_HOST (1 << 9)
unsigned int num_active_eps;
unsigned int limit_active_eps;
/* There are two roothubs to keep track of bus suspend info for */
@@ -1330,6 +1475,10 @@ struct xhci_hcd {
/* Array of pointers to USB 2.0 PORTSC registers */
__le32 __iomem **usb2_ports;
unsigned int num_usb2_ports;
+ /* support xHCI 0.96 spec USB2 software LPM */
+ unsigned sw_lpm_support:1;
+ /* support xHCI 1.0 spec USB2 hardware LPM */
+ unsigned hw_lpm_support:1;
};
/* convert between an HCD pointer and the corresponding EHCI_HCD */
@@ -1401,9 +1550,7 @@ static inline void xhci_write_64(struct xhci_hcd *xhci,
static inline int xhci_link_trb_quirk(struct xhci_hcd *xhci)
{
- u32 temp = xhci_readl(xhci, &xhci->cap_regs->hc_capbase);
- return ((HC_VERSION(temp) == 0x95) &&
- (xhci->quirks & XHCI_LINK_TRB_QUIRK));
+ return xhci->quirks & XHCI_LINK_TRB_QUIRK;
}
/* xHCI debugging */
@@ -1438,6 +1585,20 @@ unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc);
unsigned int xhci_get_endpoint_flag_from_index(unsigned int ep_index);
unsigned int xhci_last_valid_endpoint(u32 added_ctxs);
void xhci_endpoint_zero(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, struct usb_host_endpoint *ep);
+void xhci_drop_ep_from_interval_table(struct xhci_hcd *xhci,
+ struct xhci_bw_info *ep_bw,
+ struct xhci_interval_bw_table *bw_table,
+ struct usb_device *udev,
+ struct xhci_virt_ep *virt_ep,
+ struct xhci_tt_bw_info *tt_info);
+void xhci_update_tt_active_eps(struct xhci_hcd *xhci,
+ struct xhci_virt_device *virt_dev,
+ int old_active_eps);
+void xhci_clear_endpoint_bw_info(struct xhci_bw_info *bw_info);
+void xhci_update_bw_info(struct xhci_hcd *xhci,
+ struct xhci_container_ctx *in_ctx,
+ struct xhci_input_control_ctx *ctrl_ctx,
+ struct xhci_virt_device *virt_dev);
void xhci_endpoint_copy(struct xhci_hcd *xhci,
struct xhci_container_ctx *in_ctx,
struct xhci_container_ctx *out_ctx,
@@ -1483,9 +1644,13 @@ void xhci_free_command(struct xhci_hcd *xhci,
/* xHCI PCI glue */
int xhci_register_pci(void);
void xhci_unregister_pci(void);
+#else
+static inline int xhci_register_pci(void) { return 0; }
+static inline void xhci_unregister_pci(void) {}
#endif
/* xHCI host controller glue */
+typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
void xhci_quiesce(struct xhci_hcd *xhci);
int xhci_halt(struct xhci_hcd *xhci);
int xhci_reset(struct xhci_hcd *xhci);
@@ -1493,6 +1658,7 @@ int xhci_init(struct usb_hcd *hcd);
int xhci_run(struct usb_hcd *hcd);
void xhci_stop(struct usb_hcd *hcd);
void xhci_shutdown(struct usb_hcd *hcd);
+int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks);
#ifdef CONFIG_PM
int xhci_suspend(struct xhci_hcd *xhci);
@@ -1507,6 +1673,10 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd);
irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd);
int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev);
void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev);
+int xhci_alloc_tt_info(struct xhci_hcd *xhci,
+ struct xhci_virt_device *virt_dev,
+ struct usb_device *hdev,
+ struct usb_tt *tt, gfp_t mem_flags);
int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
struct usb_host_endpoint **eps, unsigned int num_eps,
unsigned int num_streams, gfp_t mem_flags);
@@ -1514,6 +1684,9 @@ int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
struct usb_host_endpoint **eps, unsigned int num_eps,
gfp_t mem_flags);
int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev);
+int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev);
+int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
+ struct usb_device *udev, int enable);
int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
struct usb_tt *tt, gfp_t mem_flags);
int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
@@ -1572,6 +1745,10 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
unsigned int ep_index, unsigned int stream_id);
/* xHCI roothub code */
+void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
+ int port_id, u32 link_state);
+void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
+ int port_id, u32 port_bit);
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
char *buf, u16 wLength);
int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index a6afd15f6a46..fe858711651c 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -213,7 +213,7 @@ static void adu_interrupt_in_callback(struct urb *urb)
if (urb->actual_length > 0 && dev->interrupt_in_buffer[0] != 0x00) {
if (dev->read_buffer_length <
- (4 * le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize)) -
+ (4 * usb_endpoint_maxp(dev->interrupt_in_endpoint)) -
(urb->actual_length)) {
memcpy (dev->read_buffer_primary +
dev->read_buffer_length,
@@ -315,7 +315,7 @@ static int adu_open(struct inode *inode, struct file *file)
usb_rcvintpipe(dev->udev,
dev->interrupt_in_endpoint->bEndpointAddress),
dev->interrupt_in_buffer,
- le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
+ usb_endpoint_maxp(dev->interrupt_in_endpoint),
adu_interrupt_in_callback, dev,
dev->interrupt_in_endpoint->bInterval);
dev->read_urb_finished = 0;
@@ -483,7 +483,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
usb_rcvintpipe(dev->udev,
dev->interrupt_in_endpoint->bEndpointAddress),
dev->interrupt_in_buffer,
- le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
+ usb_endpoint_maxp(dev->interrupt_in_endpoint),
adu_interrupt_in_callback,
dev,
dev->interrupt_in_endpoint->bInterval);
@@ -536,7 +536,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
usb_rcvintpipe(dev->udev,
dev->interrupt_in_endpoint->bEndpointAddress),
dev->interrupt_in_buffer,
- le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
+ usb_endpoint_maxp(dev->interrupt_in_endpoint),
adu_interrupt_in_callback,
dev,
dev->interrupt_in_endpoint->bInterval);
@@ -622,7 +622,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
dbg(4," %s : sending, count = %Zd", __func__, count);
/* write the data into interrupt_out_buffer from userspace */
- buffer_size = le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize);
+ buffer_size = usb_endpoint_maxp(dev->interrupt_out_endpoint);
bytes_to_write = count > buffer_size ? buffer_size : count;
dbg(4," %s : buffer_size = %Zd, count = %Zd, bytes_to_write = %Zd",
__func__, buffer_size, count, bytes_to_write);
@@ -752,8 +752,8 @@ static int adu_probe(struct usb_interface *interface,
goto error;
}
- in_end_size = le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize);
- out_end_size = le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize);
+ in_end_size = usb_endpoint_maxp(dev->interrupt_in_endpoint);
+ out_end_size = usb_endpoint_maxp(dev->interrupt_out_endpoint);
dev->read_buffer_primary = kmalloc((4 * in_end_size), GFP_KERNEL);
if (!dev->read_buffer_primary) {
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index 2f41089cd854..2dbe600fbc11 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -2777,7 +2777,7 @@ static int ftdi_elan_probe(struct usb_interface *interface,
endpoint = &iface_desc->endpoint[i].desc;
if (!ftdi->bulk_in_endpointAddr &&
usb_endpoint_is_bulk_in(endpoint)) {
- buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ buffer_size = usb_endpoint_maxp(endpoint);
ftdi->bulk_in_size = buffer_size;
ftdi->bulk_in_endpointAddr = endpoint->bEndpointAddress;
ftdi->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index c6184b4d1695..515b67fffab1 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -359,7 +359,7 @@ static int idmouse_probe(struct usb_interface *interface,
endpoint = &iface_desc->endpoint[0].desc;
if (!dev->bulk_in_endpointAddr && usb_endpoint_is_bulk_in(endpoint)) {
/* we found a bulk in endpoint */
- dev->orig_bi_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ dev->orig_bi_size = usb_endpoint_maxp(endpoint);
dev->bulk_in_size = 0x200; /* works _much_ faster */
dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
dev->bulk_in_buffer =
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index a2190b983f52..81457904d6ba 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -803,7 +803,7 @@ static int iowarrior_probe(struct usb_interface *interface,
dev->int_out_endpoint = endpoint;
}
/* we have to check the report_size often, so remember it in the endianess suitable for our machine */
- dev->report_size = le16_to_cpu(dev->int_in_endpoint->wMaxPacketSize);
+ dev->report_size = usb_endpoint_maxp(dev->int_in_endpoint);
if ((dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) &&
(dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56))
/* IOWarrior56 has wMaxPacketSize different from report size */
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index cb4096201e29..48c166f0d764 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -721,7 +721,7 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
if (dev->interrupt_out_endpoint == NULL)
dev_warn(&intf->dev, "Interrupt out endpoint not found (using control endpoint instead)\n");
- dev->interrupt_in_endpoint_size = le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize);
+ dev->interrupt_in_endpoint_size = usb_endpoint_maxp(dev->interrupt_in_endpoint);
dev->ring_buffer = kmalloc(ring_buffer_size*(sizeof(size_t)+dev->interrupt_in_endpoint_size), GFP_KERNEL);
if (!dev->ring_buffer) {
dev_err(&intf->dev, "Couldn't allocate ring_buffer\n");
@@ -737,7 +737,7 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
dev_err(&intf->dev, "Couldn't allocate interrupt_in_urb\n");
goto error;
}
- dev->interrupt_out_endpoint_size = dev->interrupt_out_endpoint ? le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize) :
+ dev->interrupt_out_endpoint_size = dev->interrupt_out_endpoint ? usb_endpoint_maxp(dev->interrupt_out_endpoint) :
udev->descriptor.bMaxPacketSize0;
dev->interrupt_out_buffer = kmalloc(write_buffer_size*dev->interrupt_out_endpoint_size, GFP_KERNEL);
if (!dev->interrupt_out_buffer) {
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 6482c6e2e6bd..a989356f693e 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -409,7 +409,7 @@ static int tower_open (struct inode *inode, struct file *file)
dev->udev,
usb_rcvintpipe(dev->udev, dev->interrupt_in_endpoint->bEndpointAddress),
dev->interrupt_in_buffer,
- le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
+ usb_endpoint_maxp(dev->interrupt_in_endpoint),
tower_interrupt_in_callback,
dev,
dev->interrupt_in_interval);
@@ -928,7 +928,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
err("Couldn't allocate read_buffer");
goto error;
}
- dev->interrupt_in_buffer = kmalloc (le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize), GFP_KERNEL);
+ dev->interrupt_in_buffer = kmalloc (usb_endpoint_maxp(dev->interrupt_in_endpoint), GFP_KERNEL);
if (!dev->interrupt_in_buffer) {
err("Couldn't allocate interrupt_in_buffer");
goto error;
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index 51648154bb44..1871cdf10da3 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -18,7 +18,7 @@
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/mutex.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/usb.h>
#define DRIVER_VERSION "USBLCD Driver Version 1.05"
@@ -34,22 +34,29 @@ static const struct usb_device_id id_table[] = {
{ .idVendor = 0x10D2, .match_flags = USB_DEVICE_ID_MATCH_VENDOR, },
{ },
};
-MODULE_DEVICE_TABLE (usb, id_table);
+MODULE_DEVICE_TABLE(usb, id_table);
static DEFINE_MUTEX(open_disc_mutex);
struct usb_lcd {
- struct usb_device * udev; /* init: probe_lcd */
- struct usb_interface * interface; /* the interface for this device */
- unsigned char * bulk_in_buffer; /* the buffer to receive data */
- size_t bulk_in_size; /* the size of the receive buffer */
- __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
- __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */
+ struct usb_device *udev; /* init: probe_lcd */
+ struct usb_interface *interface; /* the interface for
+ this device */
+ unsigned char *bulk_in_buffer; /* the buffer to receive
+ data */
+ size_t bulk_in_size; /* the size of the
+ receive buffer */
+ __u8 bulk_in_endpointAddr; /* the address of the
+ bulk in endpoint */
+ __u8 bulk_out_endpointAddr; /* the address of the
+ bulk out endpoint */
struct kref kref;
- struct semaphore limit_sem; /* to stop writes at full throttle from
- * using up all RAM */
- struct usb_anchor submitted; /* URBs to wait for before suspend */
+ struct semaphore limit_sem; /* to stop writes at
+ full throttle from
+ using up all RAM */
+ struct usb_anchor submitted; /* URBs to wait for
+ before suspend */
};
#define to_lcd_dev(d) container_of(d, struct usb_lcd, kref)
@@ -63,8 +70,8 @@ static void lcd_delete(struct kref *kref)
struct usb_lcd *dev = to_lcd_dev(kref);
usb_put_dev(dev->udev);
- kfree (dev->bulk_in_buffer);
- kfree (dev);
+ kfree(dev->bulk_in_buffer);
+ kfree(dev);
}
@@ -80,7 +87,7 @@ static int lcd_open(struct inode *inode, struct file *file)
interface = usb_find_interface(&lcd_driver, subminor);
if (!interface) {
mutex_unlock(&lcd_mutex);
- err ("USBLCD: %s - error, can't find device for minor %d",
+ err("USBLCD: %s - error, can't find device for minor %d",
__func__, subminor);
return -ENODEV;
}
@@ -126,7 +133,8 @@ static int lcd_release(struct inode *inode, struct file *file)
return 0;
}
-static ssize_t lcd_read(struct file *file, char __user * buffer, size_t count, loff_t *ppos)
+static ssize_t lcd_read(struct file *file, char __user * buffer,
+ size_t count, loff_t *ppos)
{
struct usb_lcd *dev;
int retval = 0;
@@ -135,8 +143,9 @@ static ssize_t lcd_read(struct file *file, char __user * buffer, size_t count, l
dev = file->private_data;
/* do a blocking bulk read to get data from the device */
- retval = usb_bulk_msg(dev->udev,
- usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
+ retval = usb_bulk_msg(dev->udev,
+ usb_rcvbulkpipe(dev->udev,
+ dev->bulk_in_endpointAddr),
dev->bulk_in_buffer,
min(dev->bulk_in_size, count),
&bytes_read, 10000);
@@ -161,23 +170,23 @@ static long lcd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
dev = file->private_data;
if (dev == NULL)
return -ENODEV;
-
+
switch (cmd) {
case IOCTL_GET_HARD_VERSION:
mutex_lock(&lcd_mutex);
bcdDevice = le16_to_cpu((dev->udev)->descriptor.bcdDevice);
- sprintf(buf,"%1d%1d.%1d%1d",
+ sprintf(buf, "%1d%1d.%1d%1d",
(bcdDevice & 0xF000)>>12,
(bcdDevice & 0xF00)>>8,
(bcdDevice & 0xF0)>>4,
(bcdDevice & 0xF));
mutex_unlock(&lcd_mutex);
- if (copy_to_user((void __user *)arg,buf,strlen(buf))!=0)
+ if (copy_to_user((void __user *)arg, buf, strlen(buf)) != 0)
return -EFAULT;
break;
case IOCTL_GET_DRV_VERSION:
- sprintf(buf,DRIVER_VERSION);
- if (copy_to_user((void __user *)arg,buf,strlen(buf))!=0)
+ sprintf(buf, DRIVER_VERSION);
+ if (copy_to_user((void __user *)arg, buf, strlen(buf)) != 0)
return -EFAULT;
break;
default:
@@ -199,7 +208,7 @@ static void lcd_write_bulk_callback(struct urb *urb)
if (status &&
!(status == -ENOENT ||
status == -ECONNRESET ||
- status == -ESHUTDOWN)) {
+ status == -ESHUTDOWN)) {
dbg("USBLCD: %s - nonzero write bulk status received: %d",
__func__, status);
}
@@ -210,15 +219,16 @@ static void lcd_write_bulk_callback(struct urb *urb)
up(&dev->limit_sem);
}
-static ssize_t lcd_write(struct file *file, const char __user * user_buffer, size_t count, loff_t *ppos)
+static ssize_t lcd_write(struct file *file, const char __user * user_buffer,
+ size_t count, loff_t *ppos)
{
struct usb_lcd *dev;
- int retval = 0, r;
+ int retval = 0, r;
struct urb *urb = NULL;
char *buf = NULL;
-
+
dev = file->private_data;
-
+
/* verify that we actually have some data to write */
if (count == 0)
goto exit;
@@ -233,34 +243,38 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, siz
retval = -ENOMEM;
goto err_no_buf;
}
-
- buf = usb_alloc_coherent(dev->udev, count, GFP_KERNEL, &urb->transfer_dma);
+
+ buf = usb_alloc_coherent(dev->udev, count, GFP_KERNEL,
+ &urb->transfer_dma);
if (!buf) {
retval = -ENOMEM;
goto error;
}
-
+
if (copy_from_user(buf, user_buffer, count)) {
retval = -EFAULT;
goto error;
}
-
+
/* initialize the urb properly */
usb_fill_bulk_urb(urb, dev->udev,
- usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
+ usb_sndbulkpipe(dev->udev,
+ dev->bulk_out_endpointAddr),
buf, count, lcd_write_bulk_callback, dev);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_anchor_urb(urb, &dev->submitted);
-
+
/* send the data out the bulk port */
retval = usb_submit_urb(urb, GFP_KERNEL);
if (retval) {
- err("USBLCD: %s - failed submitting write urb, error %d", __func__, retval);
+ err("USBLCD: %s - failed submitting write urb, error %d",
+ __func__, retval);
goto error_unanchor;
}
-
- /* release our reference to this urb, the USB core will eventually free it entirely */
+
+ /* release our reference to this urb,
+ the USB core will eventually free it entirely */
usb_free_urb(urb);
exit:
@@ -276,13 +290,13 @@ err_no_buf:
}
static const struct file_operations lcd_fops = {
- .owner = THIS_MODULE,
- .read = lcd_read,
- .write = lcd_write,
- .open = lcd_open,
+ .owner = THIS_MODULE,
+ .read = lcd_read,
+ .write = lcd_write,
+ .open = lcd_open,
.unlocked_ioctl = lcd_ioctl,
- .release = lcd_release,
- .llseek = noop_llseek,
+ .release = lcd_release,
+ .llseek = noop_llseek,
};
/*
@@ -290,12 +304,13 @@ static const struct file_operations lcd_fops = {
* and to have the device registered with the driver core
*/
static struct usb_class_driver lcd_class = {
- .name = "lcd%d",
- .fops = &lcd_fops,
- .minor_base = USBLCD_MINOR,
+ .name = "lcd%d",
+ .fops = &lcd_fops,
+ .minor_base = USBLCD_MINOR,
};
-static int lcd_probe(struct usb_interface *interface, const struct usb_device_id *id)
+static int lcd_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
{
struct usb_lcd *dev = NULL;
struct usb_host_interface *iface_desc;
@@ -322,7 +337,7 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
retval = -ENODEV;
goto error;
}
-
+
/* set up the endpoint information */
/* use only the first bulk-in and bulk-out endpoints */
iface_desc = interface->cur_altsetting;
@@ -332,7 +347,7 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
if (!dev->bulk_in_endpointAddr &&
usb_endpoint_is_bulk_in(endpoint)) {
/* we found a bulk in endpoint */
- buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ buffer_size = usb_endpoint_maxp(endpoint);
dev->bulk_in_size = buffer_size;
dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
@@ -369,7 +384,7 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
dev_info(&interface->dev, "USBLCD Version %1d%1d.%1d%1d found "
"at address %d\n", (i & 0xF000)>>12, (i & 0xF00)>>8,
- (i & 0xF0)>>4,(i & 0xF), dev->udev->devnum);
+ (i & 0xF0)>>4, (i & 0xF), dev->udev->devnum);
/* let the user know what node this device is now attached to */
dev_info(&interface->dev, "USB LCD device now attached to USBLCD-%d\n",
@@ -401,7 +416,7 @@ static int lcd_suspend(struct usb_interface *intf, pm_message_t message)
return 0;
}
-static int lcd_resume (struct usb_interface *intf)
+static int lcd_resume(struct usb_interface *intf)
{
return 0;
}
@@ -409,16 +424,16 @@ static int lcd_resume (struct usb_interface *intf)
static void lcd_disconnect(struct usb_interface *interface)
{
struct usb_lcd *dev;
- int minor = interface->minor;
+ int minor = interface->minor;
mutex_lock(&open_disc_mutex);
- dev = usb_get_intfdata(interface);
- usb_set_intfdata(interface, NULL);
+ dev = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
mutex_unlock(&open_disc_mutex);
- /* give back our minor */
- usb_deregister_dev(interface, &lcd_class);
-
+ /* give back our minor */
+ usb_deregister_dev(interface, &lcd_class);
+
/* decrement our usage count */
kref_put(&dev->kref, lcd_delete);
@@ -438,7 +453,7 @@ static struct usb_driver lcd_driver = {
static int __init usb_lcd_init(void)
{
int result;
-
+
result = usb_register(&lcd_driver);
if (result)
err("usb_register failed. Error number %d", result);
diff --git a/drivers/usb/misc/usbled.c b/drivers/usb/misc/usbled.c
index 1616ad1793a4..43f84e50d514 100644
--- a/drivers/usb/misc/usbled.c
+++ b/drivers/usb/misc/usbled.c
@@ -33,10 +33,10 @@ static const struct usb_device_id id_table[] = {
.driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER },
{ },
};
-MODULE_DEVICE_TABLE (usb, id_table);
+MODULE_DEVICE_TABLE(usb, id_table);
struct usb_led {
- struct usb_device * udev;
+ struct usb_device *udev;
unsigned char blue;
unsigned char red;
unsigned char green;
@@ -113,14 +113,16 @@ static void change_color(struct usb_led *led)
}
#define show_set(value) \
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
+static ssize_t show_##value(struct device *dev, struct device_attribute *attr,\
+ char *buf) \
{ \
struct usb_interface *intf = to_usb_interface(dev); \
struct usb_led *led = usb_get_intfdata(intf); \
\
return sprintf(buf, "%d\n", led->value); \
} \
-static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
+static ssize_t set_##value(struct device *dev, struct device_attribute *attr,\
+ const char *buf, size_t count) \
{ \
struct usb_interface *intf = to_usb_interface(dev); \
struct usb_led *led = usb_get_intfdata(intf); \
@@ -135,7 +137,8 @@ show_set(blue);
show_set(red);
show_set(green);
-static int led_probe(struct usb_interface *interface, const struct usb_device_id *id)
+static int led_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(interface);
struct usb_led *dev = NULL;
@@ -150,7 +153,7 @@ static int led_probe(struct usb_interface *interface, const struct usb_device_id
dev->udev = usb_get_dev(udev);
dev->type = id->driver_info;
- usb_set_intfdata (interface, dev);
+ usb_set_intfdata(interface, dev);
retval = device_create_file(&interface->dev, &dev_attr_blue);
if (retval)
@@ -194,7 +197,7 @@ error:
device_remove_file(&interface->dev, &dev_attr_blue);
device_remove_file(&interface->dev, &dev_attr_red);
device_remove_file(&interface->dev, &dev_attr_green);
- usb_set_intfdata (interface, NULL);
+ usb_set_intfdata(interface, NULL);
usb_put_dev(dev->udev);
kfree(dev);
error_mem:
@@ -205,14 +208,14 @@ static void led_disconnect(struct usb_interface *interface)
{
struct usb_led *dev;
- dev = usb_get_intfdata (interface);
+ dev = usb_get_intfdata(interface);
device_remove_file(&interface->dev, &dev_attr_blue);
device_remove_file(&interface->dev, &dev_attr_red);
device_remove_file(&interface->dev, &dev_attr_green);
/* first remove the files, then set the pointer to NULL */
- usb_set_intfdata (interface, NULL);
+ usb_set_intfdata(interface, NULL);
usb_put_dev(dev->udev);
@@ -243,8 +246,8 @@ static void __exit usb_led_exit(void)
usb_deregister(&led_driver);
}
-module_init (usb_led_init);
-module_exit (usb_led_exit);
+module_init(usb_led_init);
+module_exit(usb_led_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index bb10846affc3..bd6d00802eab 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -359,8 +359,10 @@ static int simple_io(
urb->context = &completion;
while (retval == 0 && iterations-- > 0) {
init_completion(&completion);
- if (usb_pipeout(urb->pipe))
+ if (usb_pipeout(urb->pipe)) {
simple_fill_buf(urb);
+ urb->transfer_flags |= URB_ZERO_PACKET;
+ }
retval = usb_submit_urb(urb, GFP_KERNEL);
if (retval != 0)
break;
@@ -1583,8 +1585,8 @@ static struct urb *iso_alloc_urb(
if (bytes < 0 || !desc)
return NULL;
- maxp = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);
- maxp *= 1 + (0x3 & (le16_to_cpu(desc->wMaxPacketSize) >> 11));
+ maxp = 0x7ff & usb_endpoint_maxp(desc);
+ maxp *= 1 + (0x3 & (usb_endpoint_maxp(desc) >> 11));
packets = DIV_ROUND_UP(bytes, maxp);
urb = usb_alloc_urb(packets, GFP_KERNEL);
@@ -1654,7 +1656,7 @@ test_iso_queue(struct usbtest_dev *dev, struct usbtest_param *param,
"... iso period %d %sframes, wMaxPacket %04x\n",
1 << (desc->bInterval - 1),
(udev->speed == USB_SPEED_HIGH) ? "micro" : "",
- le16_to_cpu(desc->wMaxPacketSize));
+ usb_endpoint_maxp(desc));
for (i = 0; i < param->sglen; i++) {
urbs[i] = iso_alloc_urb(udev, pipe, desc,
@@ -2298,25 +2300,8 @@ usbtest_probe(struct usb_interface *intf, const struct usb_device_id *id)
usb_set_intfdata(intf, dev);
dev_info(&intf->dev, "%s\n", info->name);
- dev_info(&intf->dev, "%s speed {control%s%s%s%s%s} tests%s\n",
- ({ char *tmp;
- switch (udev->speed) {
- case USB_SPEED_LOW:
- tmp = "low";
- break;
- case USB_SPEED_FULL:
- tmp = "full";
- break;
- case USB_SPEED_HIGH:
- tmp = "high";
- break;
- case USB_SPEED_SUPER:
- tmp = "super";
- break;
- default:
- tmp = "unknown";
- break;
- }; tmp; }),
+ dev_info(&intf->dev, "%s {control%s%s%s%s%s} tests%s\n",
+ usb_speed_string(udev->speed),
info->ctrl_out ? " in/out" : "",
rtest, wtest,
irtest, iwtest,
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index a09dbd243eb3..a04b2ff9dd83 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -1101,7 +1101,7 @@ static long mon_bin_ioctl(struct file *file, unsigned int cmd, unsigned long arg
nevents = mon_bin_queued(rp);
sp = (struct mon_bin_stats __user *)arg;
- if (put_user(rp->cnt_lost, &sp->dropped))
+ if (put_user(ndropped, &sp->dropped))
return -EFAULT;
if (put_user(nevents, &sp->queued))
return -EFAULT;
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index ae8c39617743..5e7cfba5b079 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -17,6 +17,7 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/prefetch.h>
#include <asm/cacheflush.h>
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
index 149f3f310a0a..318fb4e8a885 100644
--- a/drivers/usb/musb/cppi_dma.c
+++ b/drivers/usb/musb/cppi_dma.c
@@ -226,8 +226,10 @@ static int cppi_controller_stop(struct dma_controller *c)
struct cppi *controller;
void __iomem *tibase;
int i;
+ struct musb *musb;
controller = container_of(c, struct cppi, controller);
+ musb = controller->musb;
tibase = controller->tibase;
/* DISABLE INDIVIDUAL CHANNEL Interrupts */
@@ -289,9 +291,11 @@ cppi_channel_allocate(struct dma_controller *c,
u8 index;
struct cppi_channel *cppi_ch;
void __iomem *tibase;
+ struct musb *musb;
controller = container_of(c, struct cppi, controller);
tibase = controller->tibase;
+ musb = controller->musb;
/* ep0 doesn't use DMA; remember cppi indices are 0..N-1 */
index = ep->epnum - 1;
@@ -339,7 +343,8 @@ static void cppi_channel_release(struct dma_channel *channel)
c = container_of(channel, struct cppi_channel, channel);
tibase = c->controller->tibase;
if (!c->hw_ep)
- dev_dbg(musb->controller, "releasing idle DMA channel %p\n", c);
+ dev_dbg(c->controller->musb->controller,
+ "releasing idle DMA channel %p\n", c);
else if (!c->transmit)
core_rxirq_enable(tibase, c->index + 1);
@@ -357,10 +362,11 @@ cppi_dump_rx(int level, struct cppi_channel *c, const char *tag)
musb_ep_select(base, c->index + 1);
- DBG(level, "RX DMA%d%s: %d left, csr %04x, "
- "%08x H%08x S%08x C%08x, "
- "B%08x L%08x %08x .. %08x"
- "\n",
+ dev_dbg(c->controller->musb->controller,
+ "RX DMA%d%s: %d left, csr %04x, "
+ "%08x H%08x S%08x C%08x, "
+ "B%08x L%08x %08x .. %08x"
+ "\n",
c->index, tag,
musb_readl(c->controller->tibase,
DAVINCI_RXCPPI_BUFCNT0_REG + 4 * c->index),
@@ -387,10 +393,11 @@ cppi_dump_tx(int level, struct cppi_channel *c, const char *tag)
musb_ep_select(base, c->index + 1);
- DBG(level, "TX DMA%d%s: csr %04x, "
- "H%08x S%08x C%08x %08x, "
- "F%08x L%08x .. %08x"
- "\n",
+ dev_dbg(c->controller->musb->controller,
+ "TX DMA%d%s: csr %04x, "
+ "H%08x S%08x C%08x %08x, "
+ "F%08x L%08x .. %08x"
+ "\n",
c->index, tag,
musb_readw(c->hw_ep->regs, MUSB_TXCSR),
@@ -1022,6 +1029,7 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)
int i;
dma_addr_t safe2ack;
void __iomem *regs = rx->hw_ep->regs;
+ struct musb *musb = cppi->musb;
cppi_dump_rx(6, rx, "/K");
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index 668eeef601ae..b3c065ab9dbc 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -172,7 +172,8 @@ enum musb_g_ep0_state {
#endif
/* TUSB mapping: "flat" plus ep0 special cases */
-#if defined(CONFIG_USB_MUSB_TUSB6010)
+#if defined(CONFIG_USB_MUSB_TUSB6010) || \
+ defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
#define musb_ep_select(_mbase, _epnum) \
musb_writeb((_mbase), MUSB_INDEX, (_epnum))
#define MUSB_EP_OFFSET MUSB_TUSB_OFFSET
@@ -241,7 +242,8 @@ struct musb_hw_ep {
void __iomem *fifo;
void __iomem *regs;
-#ifdef CONFIG_USB_MUSB_TUSB6010
+#if defined(CONFIG_USB_MUSB_TUSB6010) || \
+ defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
void __iomem *conf;
#endif
@@ -258,7 +260,8 @@ struct musb_hw_ep {
struct dma_channel *tx_channel;
struct dma_channel *rx_channel;
-#ifdef CONFIG_USB_MUSB_TUSB6010
+#if defined(CONFIG_USB_MUSB_TUSB6010) || \
+ defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
/* TUSB has "asynchronous" and "synchronous" dma modes */
dma_addr_t fifo_async;
dma_addr_t fifo_sync;
@@ -356,7 +359,8 @@ struct musb {
void __iomem *ctrl_base;
void __iomem *mregs;
-#ifdef CONFIG_USB_MUSB_TUSB6010
+#if defined(CONFIG_USB_MUSB_TUSB6010) || \
+ defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
dma_addr_t async;
dma_addr_t sync;
void __iomem *sync_va;
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 8c41a2e6ea77..ae4a20acef6c 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -634,6 +634,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
u16 len;
u16 csr = musb_readw(epio, MUSB_RXCSR);
struct musb_hw_ep *hw_ep = &musb->endpoints[epnum];
+ u8 use_mode_1;
if (hw_ep->is_shared_fifo)
musb_ep = &hw_ep->ep_in;
@@ -683,6 +684,18 @@ static void rxstate(struct musb *musb, struct musb_request *req)
if (csr & MUSB_RXCSR_RXPKTRDY) {
len = musb_readw(epio, MUSB_RXCOUNT);
+
+ /*
+ * Enable Mode 1 on RX transfers only when short_not_ok flag
+ * is set. Currently short_not_ok flag is set only from
+ * file_storage and f_mass_storage drivers
+ */
+
+ if (request->short_not_ok && len == musb_ep->packet_sz)
+ use_mode_1 = 1;
+ else
+ use_mode_1 = 0;
+
if (request->actual < request->length) {
#ifdef CONFIG_USB_INVENTRA_DMA
if (is_buffer_mapped(req)) {
@@ -704,7 +717,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
* most these gadgets, end of is signified either by a short packet,
* or filling the last byte of the buffer. (Sending extra data in
* that last pckate should trigger an overflow fault.) But in mode 1,
- * we don't get DMA completion interrrupt for short packets.
+ * we don't get DMA completion interrupt for short packets.
*
* Theoretically, we could enable DMAReq irq (MUSB_RXCSR_DMAMODE = 1),
* to get endpoint interrupt on every DMA req, but that didn't seem
@@ -714,37 +727,41 @@ static void rxstate(struct musb *musb, struct musb_request *req)
* then becomes usable as a runtime "use mode 1" hint...
*/
- csr |= MUSB_RXCSR_DMAENAB;
-#ifdef USE_MODE1
- csr |= MUSB_RXCSR_AUTOCLEAR;
- /* csr |= MUSB_RXCSR_DMAMODE; */
-
- /* this special sequence (enabling and then
- * disabling MUSB_RXCSR_DMAMODE) is required
- * to get DMAReq to activate
- */
- musb_writew(epio, MUSB_RXCSR,
- csr | MUSB_RXCSR_DMAMODE);
-#else
- if (!musb_ep->hb_mult &&
- musb_ep->hw_ep->rx_double_buffered)
+ /* Experimental: Mode1 works with mass storage use cases */
+ if (use_mode_1) {
csr |= MUSB_RXCSR_AUTOCLEAR;
-#endif
- musb_writew(epio, MUSB_RXCSR, csr);
+ musb_writew(epio, MUSB_RXCSR, csr);
+ csr |= MUSB_RXCSR_DMAENAB;
+ musb_writew(epio, MUSB_RXCSR, csr);
+
+ /*
+ * this special sequence (enabling and then
+ * disabling MUSB_RXCSR_DMAMODE) is required
+ * to get DMAReq to activate
+ */
+ musb_writew(epio, MUSB_RXCSR,
+ csr | MUSB_RXCSR_DMAMODE);
+ musb_writew(epio, MUSB_RXCSR, csr);
+
+ } else {
+ if (!musb_ep->hb_mult &&
+ musb_ep->hw_ep->rx_double_buffered)
+ csr |= MUSB_RXCSR_AUTOCLEAR;
+ csr |= MUSB_RXCSR_DMAENAB;
+ musb_writew(epio, MUSB_RXCSR, csr);
+ }
if (request->actual < request->length) {
int transfer_size = 0;
-#ifdef USE_MODE1
- transfer_size = min(request->length - request->actual,
- channel->max_len);
-#else
- transfer_size = min(request->length - request->actual,
- (unsigned)len);
-#endif
- if (transfer_size <= musb_ep->packet_sz)
- musb_ep->dma->desired_mode = 0;
- else
+ if (use_mode_1) {
+ transfer_size = min(request->length - request->actual,
+ channel->max_len);
musb_ep->dma->desired_mode = 1;
+ } else {
+ transfer_size = min(request->length - request->actual,
+ (unsigned)len);
+ musb_ep->dma->desired_mode = 0;
+ }
use_dma = c->channel_program(
channel,
@@ -1020,7 +1037,7 @@ static int musb_gadget_enable(struct usb_ep *ep,
goto fail;
/* REVISIT this rules out high bandwidth periodic transfers */
- tmp = le16_to_cpu(desc->wMaxPacketSize);
+ tmp = usb_endpoint_maxp(desc);
if (tmp & ~0x07ff) {
int ok;
@@ -1856,6 +1873,7 @@ int __init musb_gadget_setup(struct musb *musb)
return 0;
err:
+ musb->g.dev.parent = NULL;
device_unregister(&musb->g.dev);
return status;
}
@@ -1863,7 +1881,8 @@ err:
void musb_gadget_cleanup(struct musb *musb)
{
usb_del_gadget_udc(&musb->g);
- device_unregister(&musb->g.dev);
+ if (musb->g.dev.parent)
+ device_unregister(&musb->g.dev);
}
/*
diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
index 9378b359c1f0..6a0d0467ec74 100644
--- a/drivers/usb/musb/musb_gadget_ep0.c
+++ b/drivers/usb/musb/musb_gadget_ep0.c
@@ -679,6 +679,14 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
musb_readb(mbase, MUSB_FADDR),
decode_ep0stage(musb->ep0_state));
+ if (csr & MUSB_CSR0_P_DATAEND) {
+ /*
+ * If DATAEND is set we should not call the callback,
+ * hence the status stage is not complete.
+ */
+ return IRQ_HANDLED;
+ }
+
/* I sent a stall.. need to acknowledge it now.. */
if (csr & MUSB_CSR0_P_SENTSTALL) {
musb_writew(regs, MUSB_CSR0,
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 8b2473fa0f47..60ddba8066ea 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -1932,7 +1932,7 @@ static int musb_urb_enqueue(
INIT_LIST_HEAD(&qh->ring);
qh->is_ready = 1;
- qh->maxpacket = le16_to_cpu(epd->wMaxPacketSize);
+ qh->maxpacket = usb_endpoint_maxp(epd);
qh->type = usb_endpoint_type(epd);
/* Bits 11 & 12 of wMaxPacketSize encode high bandwidth multiplier.
diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h
index 82410703dcd3..03f2655af290 100644
--- a/drivers/usb/musb/musb_regs.h
+++ b/drivers/usb/musb/musb_regs.h
@@ -234,7 +234,8 @@
#define MUSB_TESTMODE 0x0F /* 8 bit */
/* Get offset for a given FIFO from musb->mregs */
-#ifdef CONFIG_USB_MUSB_TUSB6010
+#if defined(CONFIG_USB_MUSB_TUSB6010) || \
+ defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
#define MUSB_FIFO_OFFSET(epnum) (0x200 + ((epnum) * 0x20))
#else
#define MUSB_FIFO_OFFSET(epnum) (0x20 + ((epnum) * 4))
@@ -295,7 +296,8 @@
#define MUSB_FLAT_OFFSET(_epnum, _offset) \
(0x100 + (0x10*(_epnum)) + (_offset))
-#ifdef CONFIG_USB_MUSB_TUSB6010
+#if defined(CONFIG_USB_MUSB_TUSB6010) || \
+ defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
/* TUSB6010 EP0 configuration register is special */
#define MUSB_TUSB_OFFSET(_epnum, _offset) \
(0x10 + _offset)
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
index f70c5a577736..57a608584e16 100644
--- a/drivers/usb/musb/musbhsdma.c
+++ b/drivers/usb/musb/musbhsdma.c
@@ -408,7 +408,7 @@ dma_controller_create(struct musb *musb, void __iomem *base)
controller->controller.channel_program = dma_channel_program;
controller->controller.channel_abort = dma_channel_abort;
- if (request_irq(irq, dma_controller_irq, IRQF_DISABLED,
+ if (request_irq(irq, dma_controller_irq, 0,
dev_name(musb->controller), &controller->controller)) {
dev_err(dev, "request_irq %d failed!\n", irq);
dma_controller_destroy(&controller->controller);
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index 9eec41fbf3a4..ec1480191f78 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -18,6 +18,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/prefetch.h>
#include <linux/usb.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c
index 07c8a73dfe41..b67b4bc596c1 100644
--- a/drivers/usb/musb/tusb6010_omap.c
+++ b/drivers/usb/musb/tusb6010_omap.c
@@ -20,6 +20,7 @@
#include <plat/mux.h>
#include "musb_core.h"
+#include "tusb6010.h"
#define to_chdat(c) ((struct tusb_omap_dma_ch *)(c)->private_data)
diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c
index cecace411832..ef4333f4bbe0 100644
--- a/drivers/usb/musb/ux500_dma.c
+++ b/drivers/usb/musb/ux500_dma.c
@@ -65,7 +65,8 @@ static void ux500_tx_work(struct work_struct *data)
struct musb *musb = hw_ep->musb;
unsigned long flags;
- DBG(4, "DMA tx transfer done on hw_ep=%d\n", hw_ep->epnum);
+ dev_dbg(musb->controller, "DMA tx transfer done on hw_ep=%d\n",
+ hw_ep->epnum);
spin_lock_irqsave(&musb->lock, flags);
ux500_channel->channel.actual_len = ux500_channel->cur_len;
@@ -84,7 +85,8 @@ static void ux500_rx_work(struct work_struct *data)
struct musb *musb = hw_ep->musb;
unsigned long flags;
- DBG(4, "DMA rx transfer done on hw_ep=%d\n", hw_ep->epnum);
+ dev_dbg(musb->controller, "DMA rx transfer done on hw_ep=%d\n",
+ hw_ep->epnum);
spin_lock_irqsave(&musb->lock, flags);
ux500_channel->channel.actual_len = ux500_channel->cur_len;
@@ -116,9 +118,11 @@ static bool ux500_configure_channel(struct dma_channel *channel,
enum dma_slave_buswidth addr_width;
dma_addr_t usb_fifo_addr = (MUSB_FIFO_OFFSET(hw_ep->epnum) +
ux500_channel->controller->phy_base);
+ struct musb *musb = ux500_channel->controller->private_data;
- DBG(4, "packet_sz=%d, mode=%d, dma_addr=0x%x, len=%d is_tx=%d\n",
- packet_sz, mode, dma_addr, len, ux500_channel->is_tx);
+ dev_dbg(musb->controller,
+ "packet_sz=%d, mode=%d, dma_addr=0x%x, len=%d is_tx=%d\n",
+ packet_sz, mode, dma_addr, len, ux500_channel->is_tx);
ux500_channel->cur_len = len;
@@ -133,15 +137,13 @@ static bool ux500_configure_channel(struct dma_channel *channel,
DMA_SLAVE_BUSWIDTH_4_BYTES;
slave_conf.direction = direction;
- if (direction == DMA_FROM_DEVICE) {
- slave_conf.src_addr = usb_fifo_addr;
- slave_conf.src_addr_width = addr_width;
- slave_conf.src_maxburst = 16;
- } else {
- slave_conf.dst_addr = usb_fifo_addr;
- slave_conf.dst_addr_width = addr_width;
- slave_conf.dst_maxburst = 16;
- }
+ slave_conf.src_addr = usb_fifo_addr;
+ slave_conf.src_addr_width = addr_width;
+ slave_conf.src_maxburst = 16;
+ slave_conf.dst_addr = usb_fifo_addr;
+ slave_conf.dst_addr_width = addr_width;
+ slave_conf.dst_maxburst = 16;
+
dma_chan->device->device_control(dma_chan, DMA_SLAVE_CONFIG,
(unsigned long) &slave_conf);
@@ -166,6 +168,7 @@ static struct dma_channel *ux500_dma_channel_allocate(struct dma_controller *c,
struct ux500_dma_controller *controller = container_of(c,
struct ux500_dma_controller, controller);
struct ux500_dma_channel *ux500_channel = NULL;
+ struct musb *musb = controller->private_data;
u8 ch_num = hw_ep->epnum - 1;
u32 max_ch;
@@ -192,7 +195,7 @@ static struct dma_channel *ux500_dma_channel_allocate(struct dma_controller *c,
ux500_channel->hw_ep = hw_ep;
ux500_channel->is_allocated = 1;
- DBG(7, "hw_ep=%d, is_tx=0x%x, channel=%d\n",
+ dev_dbg(musb->controller, "hw_ep=%d, is_tx=0x%x, channel=%d\n",
hw_ep->epnum, is_tx, ch_num);
return &(ux500_channel->channel);
@@ -201,8 +204,9 @@ static struct dma_channel *ux500_dma_channel_allocate(struct dma_controller *c,
static void ux500_dma_channel_release(struct dma_channel *channel)
{
struct ux500_dma_channel *ux500_channel = channel->private_data;
+ struct musb *musb = ux500_channel->controller->private_data;
- DBG(7, "channel=%d\n", ux500_channel->ch_num);
+ dev_dbg(musb->controller, "channel=%d\n", ux500_channel->ch_num);
if (ux500_channel->is_allocated) {
ux500_channel->is_allocated = 0;
@@ -252,8 +256,8 @@ static int ux500_dma_channel_abort(struct dma_channel *channel)
void __iomem *epio = musb->endpoints[ux500_channel->hw_ep->epnum].regs;
u16 csr;
- DBG(4, "channel=%d, is_tx=%d\n", ux500_channel->ch_num,
- ux500_channel->is_tx);
+ dev_dbg(musb->controller, "channel=%d, is_tx=%d\n",
+ ux500_channel->ch_num, ux500_channel->is_tx);
if (channel->status == MUSB_DMA_STATUS_BUSY) {
if (ux500_channel->is_tx) {
diff --git a/drivers/usb/otg/isp1301_omap.c b/drivers/usb/otg/isp1301_omap.c
index ca9b690a7e40..8c86787c2f09 100644
--- a/drivers/usb/otg/isp1301_omap.c
+++ b/drivers/usb/otg/isp1301_omap.c
@@ -899,7 +899,7 @@ static int otg_bind(struct isp1301 *isp)
if (otg_dev)
status = request_irq(otg_dev->resource[1].start, omap_otg_irq,
- IRQF_DISABLED, DRIVER_NAME, isp);
+ 0, DRIVER_NAME, isp);
else
status = -ENODEV;
diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/otg/twl6030-usb.c
index b4d2c0972b3d..ed2b26cfe814 100644
--- a/drivers/usb/otg/twl6030-usb.c
+++ b/drivers/usb/otg/twl6030-usb.c
@@ -137,22 +137,6 @@ static inline u8 twl6030_readb(struct twl6030_usb *twl, u8 module, u8 address)
return ret;
}
-/*-------------------------------------------------------------------------*/
-static int twl6030_set_phy_clk(struct otg_transceiver *x, int on)
-{
- struct twl6030_usb *twl;
- struct device *dev;
- struct twl4030_usb_data *pdata;
-
- twl = xceiv_to_twl(x);
- dev = twl->dev;
- pdata = dev->platform_data;
-
- pdata->phy_set_clock(twl->dev, on);
-
- return 0;
-}
-
static int twl6030_phy_init(struct otg_transceiver *x)
{
struct twl6030_usb *twl;
diff --git a/drivers/usb/renesas_usbhs/Kconfig b/drivers/usb/renesas_usbhs/Kconfig
index 286cbf1ca7de..6f4afa436381 100644
--- a/drivers/usb/renesas_usbhs/Kconfig
+++ b/drivers/usb/renesas_usbhs/Kconfig
@@ -4,7 +4,7 @@
config USB_RENESAS_USBHS
tristate 'Renesas USBHS controller'
- depends on SUPERH || ARCH_SHMOBILE
+ depends on USB && USB_GADGET
default n
help
Renesas USBHS is a discrete USB host and peripheral controller chip
diff --git a/drivers/usb/renesas_usbhs/Makefile b/drivers/usb/renesas_usbhs/Makefile
index ce08345fa15a..bc8aef4311a1 100644
--- a/drivers/usb/renesas_usbhs/Makefile
+++ b/drivers/usb/renesas_usbhs/Makefile
@@ -6,4 +6,10 @@ obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs.o
renesas_usbhs-y := common.o mod.o pipe.o fifo.o
-renesas_usbhs-$(CONFIG_USB_RENESAS_USBHS_UDC) += mod_gadget.o
+ifneq ($(CONFIG_USB_RENESAS_USBHS_HCD),)
+ renesas_usbhs-y += mod_host.o
+endif
+
+ifneq ($(CONFIG_USB_RENESAS_USBHS_UDC),)
+ renesas_usbhs-y += mod_gadget.o
+endif
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index d8239e5efa66..d2e2efaba658 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -61,8 +61,8 @@
*/
#define usbhs_platform_call(priv, func, args...)\
(!(priv) ? -ENODEV : \
- !((priv)->pfunc->func) ? 0 : \
- (priv)->pfunc->func(args))
+ !((priv)->pfunc.func) ? 0 : \
+ (priv)->pfunc.func(args))
/*
* common functions
@@ -114,6 +114,10 @@ void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable)
{
u16 mask = DCFM | DRPD | DPRPU;
u16 val = DCFM | DRPD;
+ int has_otg = usbhs_get_dparam(priv, has_otg);
+
+ if (has_otg)
+ usbhs_bset(priv, DVSTCTR, (EXTLP | PWEN), (EXTLP | PWEN));
/*
* if enable
@@ -147,19 +151,133 @@ int usbhs_frame_get_num(struct usbhs_priv *priv)
}
/*
+ * usb request functions
+ */
+void usbhs_usbreq_get_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req)
+{
+ u16 val;
+
+ val = usbhs_read(priv, USBREQ);
+ req->bRequest = (val >> 8) & 0xFF;
+ req->bRequestType = (val >> 0) & 0xFF;
+
+ req->wValue = usbhs_read(priv, USBVAL);
+ req->wIndex = usbhs_read(priv, USBINDX);
+ req->wLength = usbhs_read(priv, USBLENG);
+}
+
+void usbhs_usbreq_set_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req)
+{
+ usbhs_write(priv, USBREQ, (req->bRequest << 8) | req->bRequestType);
+ usbhs_write(priv, USBVAL, req->wValue);
+ usbhs_write(priv, USBINDX, req->wIndex);
+ usbhs_write(priv, USBLENG, req->wLength);
+
+ usbhs_bset(priv, DCPCTR, SUREQ, SUREQ);
+}
+
+/*
+ * bus/vbus functions
+ */
+void usbhs_bus_send_sof_enable(struct usbhs_priv *priv)
+{
+ u16 status = usbhs_read(priv, DVSTCTR) & (USBRST | UACT);
+
+ if (status != USBRST) {
+ struct device *dev = usbhs_priv_to_dev(priv);
+ dev_err(dev, "usbhs should be reset\n");
+ }
+
+ usbhs_bset(priv, DVSTCTR, (USBRST | UACT), UACT);
+}
+
+void usbhs_bus_send_reset(struct usbhs_priv *priv)
+{
+ usbhs_bset(priv, DVSTCTR, (USBRST | UACT), USBRST);
+}
+
+int usbhs_bus_get_speed(struct usbhs_priv *priv)
+{
+ u16 dvstctr = usbhs_read(priv, DVSTCTR);
+
+ switch (RHST & dvstctr) {
+ case RHST_LOW_SPEED:
+ return USB_SPEED_LOW;
+ case RHST_FULL_SPEED:
+ return USB_SPEED_FULL;
+ case RHST_HIGH_SPEED:
+ return USB_SPEED_HIGH;
+ }
+
+ return USB_SPEED_UNKNOWN;
+}
+
+int usbhs_vbus_ctrl(struct usbhs_priv *priv, int enable)
+{
+ struct platform_device *pdev = usbhs_priv_to_pdev(priv);
+
+ return usbhs_platform_call(priv, set_vbus, pdev, enable);
+}
+
+static void usbhsc_bus_init(struct usbhs_priv *priv)
+{
+ usbhs_write(priv, DVSTCTR, 0);
+
+ usbhs_vbus_ctrl(priv, 0);
+}
+
+/*
+ * device configuration
+ */
+int usbhs_set_device_speed(struct usbhs_priv *priv, int devnum,
+ u16 upphub, u16 hubport, u16 speed)
+{
+ struct device *dev = usbhs_priv_to_dev(priv);
+ u16 usbspd = 0;
+ u32 reg = DEVADD0 + (2 * devnum);
+
+ if (devnum > 10) {
+ dev_err(dev, "cannot set speed to unknown device %d\n", devnum);
+ return -EIO;
+ }
+
+ if (upphub > 0xA) {
+ dev_err(dev, "unsupported hub number %d\n", upphub);
+ return -EIO;
+ }
+
+ switch (speed) {
+ case USB_SPEED_LOW:
+ usbspd = USBSPD_SPEED_LOW;
+ break;
+ case USB_SPEED_FULL:
+ usbspd = USBSPD_SPEED_FULL;
+ break;
+ case USB_SPEED_HIGH:
+ usbspd = USBSPD_SPEED_HIGH;
+ break;
+ default:
+ dev_err(dev, "unsupported speed %d\n", speed);
+ return -EIO;
+ }
+
+ usbhs_write(priv, reg, UPPHUB(upphub) |
+ HUBPORT(hubport)|
+ USBSPD(usbspd));
+
+ return 0;
+}
+
+/*
* local functions
*/
-static void usbhsc_bus_ctrl(struct usbhs_priv *priv, int enable)
+static void usbhsc_set_buswait(struct usbhs_priv *priv)
{
int wait = usbhs_get_dparam(priv, buswait_bwait);
- u16 data = 0;
- if (enable) {
- /* set bus wait if platform have */
- if (wait)
- usbhs_bset(priv, BUSWAIT, 0x000F, wait);
- }
- usbhs_write(priv, DVSTCTR, data);
+ /* set bus wait if platform have */
+ if (wait)
+ usbhs_bset(priv, BUSWAIT, 0x000F, wait);
}
/*
@@ -191,10 +309,8 @@ static void usbhsc_power_ctrl(struct usbhs_priv *priv, int enable)
/* USB on */
usbhs_sys_clock_ctrl(priv, enable);
- usbhsc_bus_ctrl(priv, enable);
} else {
/* USB off */
- usbhsc_bus_ctrl(priv, enable);
usbhs_sys_clock_ctrl(priv, enable);
/* disable PM */
@@ -203,13 +319,10 @@ static void usbhsc_power_ctrl(struct usbhs_priv *priv, int enable)
}
/*
- * notify hotplug
+ * hotplug
*/
-static void usbhsc_notify_hotplug(struct work_struct *work)
+static void usbhsc_hotplug(struct usbhs_priv *priv)
{
- struct usbhs_priv *priv = container_of(work,
- struct usbhs_priv,
- notify_hotplug_work.work);
struct platform_device *pdev = usbhs_priv_to_pdev(priv);
struct usbhs_mod *mod = usbhs_mod_get_current(priv);
int id;
@@ -237,6 +350,10 @@ static void usbhsc_notify_hotplug(struct work_struct *work)
if (usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
usbhsc_power_ctrl(priv, enable);
+ /* bus init */
+ usbhsc_set_buswait(priv);
+ usbhsc_bus_init(priv);
+
/* module start */
usbhs_mod_call(priv, start, priv);
@@ -246,6 +363,9 @@ static void usbhsc_notify_hotplug(struct work_struct *work)
/* module stop */
usbhs_mod_call(priv, stop, priv);
+ /* bus init */
+ usbhsc_bus_init(priv);
+
/* power off */
if (usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
usbhsc_power_ctrl(priv, enable);
@@ -257,6 +377,17 @@ static void usbhsc_notify_hotplug(struct work_struct *work)
}
}
+/*
+ * notify hotplug
+ */
+static void usbhsc_notify_hotplug(struct work_struct *work)
+{
+ struct usbhs_priv *priv = container_of(work,
+ struct usbhs_priv,
+ notify_hotplug_work.work);
+ usbhsc_hotplug(priv);
+}
+
int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev)
{
struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
@@ -315,24 +446,28 @@ static int __devinit usbhs_probe(struct platform_device *pdev)
/*
* care platform info
*/
- priv->pfunc = &info->platform_callback;
- priv->dparam = &info->driver_param;
+ memcpy(&priv->pfunc,
+ &info->platform_callback,
+ sizeof(struct renesas_usbhs_platform_callback));
+ memcpy(&priv->dparam,
+ &info->driver_param,
+ sizeof(struct renesas_usbhs_driver_param));
/* set driver callback functions for platform */
dfunc = &info->driver_callback;
dfunc->notify_hotplug = usbhsc_drvcllbck_notify_hotplug;
/* set default param if platform doesn't have */
- if (!priv->dparam->pipe_type) {
- priv->dparam->pipe_type = usbhsc_default_pipe_type;
- priv->dparam->pipe_size = ARRAY_SIZE(usbhsc_default_pipe_type);
+ if (!priv->dparam.pipe_type) {
+ priv->dparam.pipe_type = usbhsc_default_pipe_type;
+ priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_default_pipe_type);
}
- if (!priv->dparam->pio_dma_border)
- priv->dparam->pio_dma_border = 64; /* 64byte */
+ if (!priv->dparam.pio_dma_border)
+ priv->dparam.pio_dma_border = 64; /* 64byte */
/* FIXME */
/* runtime power control ? */
- if (priv->pfunc->get_vbus)
+ if (priv->pfunc.get_vbus)
usbhsc_flags_set(priv, USBHSF_RUNTIME_PWCTRL);
/*
@@ -443,9 +578,60 @@ static int __devexit usbhs_remove(struct platform_device *pdev)
return 0;
}
+static int usbhsc_suspend(struct device *dev)
+{
+ struct usbhs_priv *priv = dev_get_drvdata(dev);
+ struct usbhs_mod *mod = usbhs_mod_get_current(priv);
+
+ if (mod) {
+ usbhs_mod_call(priv, stop, priv);
+ usbhs_mod_change(priv, -1);
+ }
+
+ if (mod || !usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
+ usbhsc_power_ctrl(priv, 0);
+
+ return 0;
+}
+
+static int usbhsc_resume(struct device *dev)
+{
+ struct usbhs_priv *priv = dev_get_drvdata(dev);
+ struct platform_device *pdev = usbhs_priv_to_pdev(priv);
+
+ usbhs_platform_call(priv, phy_reset, pdev);
+
+ if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
+ usbhsc_power_ctrl(priv, 1);
+
+ usbhsc_hotplug(priv);
+
+ return 0;
+}
+
+static int usbhsc_runtime_nop(struct device *dev)
+{
+ /* Runtime PM callback shared between ->runtime_suspend()
+ * and ->runtime_resume(). Simply returns success.
+ *
+ * This driver re-initializes all registers after
+ * pm_runtime_get_sync() anyway so there is no need
+ * to save and restore registers here.
+ */
+ return 0;
+}
+
+static const struct dev_pm_ops usbhsc_pm_ops = {
+ .suspend = usbhsc_suspend,
+ .resume = usbhsc_resume,
+ .runtime_suspend = usbhsc_runtime_nop,
+ .runtime_resume = usbhsc_runtime_nop,
+};
+
static struct platform_driver renesas_usbhs_driver = {
.driver = {
.name = "renesas_usbhs",
+ .pm = &usbhsc_pm_ops,
},
.probe = usbhs_probe,
.remove = __devexit_p(usbhs_remove),
diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h
index b410463a1212..8729da5c3be6 100644
--- a/drivers/usb/renesas_usbhs/common.h
+++ b/drivers/usb/renesas_usbhs/common.h
@@ -90,6 +90,17 @@ struct usbhs_priv;
#define PIPE9TRN 0x00BA
#define PIPEATRE 0x00BC
#define PIPEATRN 0x00BE
+#define DEVADD0 0x00D0 /* Device address n configuration */
+#define DEVADD1 0x00D2
+#define DEVADD2 0x00D4
+#define DEVADD3 0x00D6
+#define DEVADD4 0x00D8
+#define DEVADD5 0x00DA
+#define DEVADD6 0x00DC
+#define DEVADD7 0x00DE
+#define DEVADD8 0x00E0
+#define DEVADD9 0x00E2
+#define DEVADDA 0x00E4
/* SYSCFG */
#define SCKE (1 << 10) /* USB Module Clock Enable */
@@ -102,6 +113,8 @@ struct usbhs_priv;
/* DVSTCTR */
#define EXTLP (1 << 10) /* Controls the EXTLP pin output state */
#define PWEN (1 << 9) /* Controls the PWEN pin output state */
+#define USBRST (1 << 6) /* Bus Reset Output */
+#define UACT (1 << 4) /* USB Bus Enable */
#define RHST (0x7) /* Reset Handshake */
#define RHST_LOW_SPEED 1 /* Low-speed connection */
#define RHST_FULL_SPEED 2 /* Full-speed connection */
@@ -159,6 +172,15 @@ struct usbhs_priv;
#define NODATA_STATUS_STAGE 5 /* Control write NoData status stage */
#define SEQUENCE_ERROR 6 /* Control transfer sequence error */
+/* INTSTS1 */
+#define OVRCR (1 << 15) /* OVRCR Interrupt Status */
+#define BCHG (1 << 14) /* USB Bus Change Interrupt Status */
+#define DTCH (1 << 12) /* USB Disconnection Detect Interrupt Status */
+#define ATTCH (1 << 11) /* ATTCH Interrupt Status */
+#define EOFERR (1 << 6) /* EOF Error Detect Interrupt Status */
+#define SIGN (1 << 5) /* Setup Transaction Error Interrupt Status */
+#define SACK (1 << 4) /* Setup Transaction ACK Response Interrupt Status */
+
/* PIPECFG */
/* DCPCFG */
#define TYPE_NONE (0 << 14) /* Transfer Type */
@@ -183,9 +205,11 @@ struct usbhs_priv;
/* PIPEnCTR */
/* DCPCTR */
#define BSTS (1 << 15) /* Buffer Status */
+#define SUREQ (1 << 14) /* Sending SETUP Token */
#define CSSTS (1 << 12) /* CSSTS Status */
-#define SQCLR (1 << 8) /* Toggle Bit Clear */
#define ACLRM (1 << 9) /* Buffer Auto-Clear Mode */
+#define SQCLR (1 << 8) /* Toggle Bit Clear */
+#define SQSET (1 << 7) /* Toggle Bit Set */
#define PBUSY (1 << 5) /* Pipe Busy */
#define PID_MASK (0x3) /* Response PID */
#define PID_NAK 0
@@ -202,6 +226,14 @@ struct usbhs_priv;
/* FRMNUM */
#define FRNM_MASK (0x7FF)
+/* DEVADDn */
+#define UPPHUB(x) (((x) & 0xF) << 11) /* HUB Register */
+#define HUBPORT(x) (((x) & 0x7) << 8) /* HUB Port for Target Device */
+#define USBSPD(x) (((x) & 0x3) << 6) /* Device Transfer Rate */
+#define USBSPD_SPEED_LOW 0x1
+#define USBSPD_SPEED_FULL 0x2
+#define USBSPD_SPEED_HIGH 0x3
+
/*
* struct
*/
@@ -210,8 +242,8 @@ struct usbhs_priv {
void __iomem *base;
unsigned int irq;
- struct renesas_usbhs_platform_callback *pfunc;
- struct renesas_usbhs_driver_param *dparam;
+ struct renesas_usbhs_platform_callback pfunc;
+ struct renesas_usbhs_driver_param dparam;
struct delayed_work notify_hotplug_work;
struct platform_device *pdev;
@@ -258,15 +290,35 @@ void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable);
void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable);
/*
+ * usb request
+ */
+void usbhs_usbreq_get_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req);
+void usbhs_usbreq_set_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req);
+
+/*
+ * bus
+ */
+void usbhs_bus_send_sof_enable(struct usbhs_priv *priv);
+void usbhs_bus_send_reset(struct usbhs_priv *priv);
+int usbhs_bus_get_speed(struct usbhs_priv *priv);
+int usbhs_vbus_ctrl(struct usbhs_priv *priv, int enable);
+
+/*
* frame
*/
int usbhs_frame_get_num(struct usbhs_priv *priv);
/*
+ * device config
+ */
+int usbhs_set_device_speed(struct usbhs_priv *priv, int devnum, u16 upphub,
+ u16 hubport, u16 speed);
+
+/*
* data
*/
struct usbhs_priv *usbhs_pdev_to_priv(struct platform_device *pdev);
-#define usbhs_get_dparam(priv, param) (priv->dparam->param)
+#define usbhs_get_dparam(priv, param) (priv->dparam.param)
#define usbhs_priv_to_pdev(priv) (priv->pdev)
#define usbhs_priv_to_dev(priv) (&priv->pdev->dev)
#define usbhs_priv_to_lock(priv) (&priv->lock)
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index a34430f55fb7..8da685e796d1 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -54,35 +54,45 @@ static struct usbhs_pkt_handle usbhsf_null_handler = {
};
void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
- struct usbhs_pkt_handle *handler,
+ void (*done)(struct usbhs_priv *priv,
+ struct usbhs_pkt *pkt),
void *buf, int len, int zero)
{
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
struct device *dev = usbhs_priv_to_dev(priv);
unsigned long flags;
+ if (!done) {
+ dev_err(dev, "no done function\n");
+ return;
+ }
+
/******************** spin lock ********************/
usbhs_lock(priv, flags);
- if (!handler) {
+ if (!pipe->handler) {
dev_err(dev, "no handler function\n");
- handler = &usbhsf_null_handler;
+ pipe->handler = &usbhsf_null_handler;
}
list_del_init(&pkt->node);
list_add_tail(&pkt->node, &pipe->list);
+ /*
+ * each pkt must hold own handler.
+ * because handler might be changed by its situation.
+ * dma handler -> pio handler.
+ */
pkt->pipe = pipe;
pkt->buf = buf;
- pkt->handler = handler;
+ pkt->handler = pipe->handler;
pkt->length = len;
pkt->zero = zero;
pkt->actual = 0;
+ pkt->done = done;
usbhs_unlock(priv, flags);
/******************** spin unlock ******************/
-
- usbhs_pkt_start(pipe);
}
static void __usbhsf_pkt_del(struct usbhs_pkt *pkt)
@@ -118,10 +128,15 @@ struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt)
return pkt;
}
-int __usbhs_pkt_handler(struct usbhs_pipe *pipe, int type)
+enum {
+ USBHSF_PKT_PREPARE,
+ USBHSF_PKT_TRY_RUN,
+ USBHSF_PKT_DMA_DONE,
+};
+
+static int usbhsf_pkt_handler(struct usbhs_pipe *pipe, int type)
{
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
- struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
struct usbhs_pkt *pkt;
struct device *dev = usbhs_priv_to_dev(priv);
int (*func)(struct usbhs_pkt *pkt, int *is_done);
@@ -161,13 +176,18 @@ __usbhs_pkt_handler_end:
/******************** spin unlock ******************/
if (is_done) {
- info->done(pkt);
+ pkt->done(priv, pkt);
usbhs_pkt_start(pipe);
}
return ret;
}
+void usbhs_pkt_start(struct usbhs_pipe *pipe)
+{
+ usbhsf_pkt_handler(pipe, USBHSF_PKT_PREPARE);
+}
+
/*
* irq enable/disable function
*/
@@ -276,9 +296,13 @@ static int usbhsf_fifo_select(struct usbhs_pipe *pipe,
usbhsf_fifo_is_busy(fifo))
return -EBUSY;
- if (usbhs_pipe_is_dcp(pipe))
+ if (usbhs_pipe_is_dcp(pipe)) {
base |= (1 == write) << 5; /* ISEL */
+ if (usbhs_mod_is_host(priv))
+ usbhs_dcp_dir_for_host(pipe, write);
+ }
+
/* "base" will be used below */
usbhs_write(priv, fifo->sel, base | MBW_32);
@@ -297,6 +321,151 @@ static int usbhsf_fifo_select(struct usbhs_pipe *pipe,
}
/*
+ * DCP status stage
+ */
+static int usbhs_dcp_dir_switch_to_write(struct usbhs_pkt *pkt, int *is_done)
+{
+ struct usbhs_pipe *pipe = pkt->pipe;
+ struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
+ struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */
+ struct device *dev = usbhs_priv_to_dev(priv);
+ int ret;
+
+ usbhs_pipe_disable(pipe);
+
+ ret = usbhsf_fifo_select(pipe, fifo, 1);
+ if (ret < 0) {
+ dev_err(dev, "%s() faile\n", __func__);
+ return ret;
+ }
+
+ usbhs_pipe_sequence_data1(pipe); /* DATA1 */
+
+ usbhsf_fifo_clear(pipe, fifo);
+ usbhsf_send_terminator(pipe, fifo);
+
+ usbhsf_fifo_unselect(pipe, fifo);
+
+ usbhsf_tx_irq_ctrl(pipe, 1);
+ usbhs_pipe_enable(pipe);
+
+ return ret;
+}
+
+static int usbhs_dcp_dir_switch_to_read(struct usbhs_pkt *pkt, int *is_done)
+{
+ struct usbhs_pipe *pipe = pkt->pipe;
+ struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
+ struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */
+ struct device *dev = usbhs_priv_to_dev(priv);
+ int ret;
+
+ usbhs_pipe_disable(pipe);
+
+ ret = usbhsf_fifo_select(pipe, fifo, 0);
+ if (ret < 0) {
+ dev_err(dev, "%s() fail\n", __func__);
+ return ret;
+ }
+
+ usbhs_pipe_sequence_data1(pipe); /* DATA1 */
+ usbhsf_fifo_clear(pipe, fifo);
+
+ usbhsf_fifo_unselect(pipe, fifo);
+
+ usbhsf_rx_irq_ctrl(pipe, 1);
+ usbhs_pipe_enable(pipe);
+
+ return ret;
+
+}
+
+static int usbhs_dcp_dir_switch_done(struct usbhs_pkt *pkt, int *is_done)
+{
+ struct usbhs_pipe *pipe = pkt->pipe;
+
+ if (pkt->handler == &usbhs_dcp_status_stage_in_handler)
+ usbhsf_tx_irq_ctrl(pipe, 0);
+ else
+ usbhsf_rx_irq_ctrl(pipe, 0);
+
+ pkt->actual = pkt->length;
+ *is_done = 1;
+
+ return 0;
+}
+
+struct usbhs_pkt_handle usbhs_dcp_status_stage_in_handler = {
+ .prepare = usbhs_dcp_dir_switch_to_write,
+ .try_run = usbhs_dcp_dir_switch_done,
+};
+
+struct usbhs_pkt_handle usbhs_dcp_status_stage_out_handler = {
+ .prepare = usbhs_dcp_dir_switch_to_read,
+ .try_run = usbhs_dcp_dir_switch_done,
+};
+
+/*
+ * DCP data stage (push)
+ */
+static int usbhsf_dcp_data_stage_try_push(struct usbhs_pkt *pkt, int *is_done)
+{
+ struct usbhs_pipe *pipe = pkt->pipe;
+
+ usbhs_pipe_sequence_data1(pipe); /* DATA1 */
+
+ /*
+ * change handler to PIO push
+ */
+ pkt->handler = &usbhs_fifo_pio_push_handler;
+
+ return pkt->handler->prepare(pkt, is_done);
+}
+
+struct usbhs_pkt_handle usbhs_dcp_data_stage_out_handler = {
+ .prepare = usbhsf_dcp_data_stage_try_push,
+};
+
+/*
+ * DCP data stage (pop)
+ */
+static int usbhsf_dcp_data_stage_prepare_pop(struct usbhs_pkt *pkt,
+ int *is_done)
+{
+ struct usbhs_pipe *pipe = pkt->pipe;
+ struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
+ struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv);
+
+ if (usbhs_pipe_is_busy(pipe))
+ return 0;
+
+ /*
+ * prepare pop for DCP should
+ * - change DCP direction,
+ * - clear fifo
+ * - DATA1
+ */
+ usbhs_pipe_disable(pipe);
+
+ usbhs_pipe_sequence_data1(pipe); /* DATA1 */
+
+ usbhsf_fifo_select(pipe, fifo, 0);
+ usbhsf_fifo_clear(pipe, fifo);
+ usbhsf_fifo_unselect(pipe, fifo);
+
+ /*
+ * change handler to PIO pop
+ */
+ pkt->handler = &usbhs_fifo_pio_pop_handler;
+
+ return pkt->handler->prepare(pkt, is_done);
+}
+
+struct usbhs_pkt_handle usbhs_dcp_data_stage_in_handler = {
+ .prepare = usbhsf_dcp_data_stage_prepare_pop,
+};
+
+/*
* PIO push handler
*/
static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done)
@@ -452,6 +621,20 @@ static int usbhsf_pio_try_pop(struct usbhs_pkt *pkt, int *is_done)
total_len = len;
/*
+ * update actual length first here to decide disable pipe.
+ * if this pipe keeps BUF status and all data were popped,
+ * then, next interrupt/token will be issued again
+ */
+ pkt->actual += total_len;
+
+ if ((pkt->actual == pkt->length) || /* receive all data */
+ (total_len < maxp)) { /* short packet */
+ *is_done = 1;
+ usbhsf_rx_irq_ctrl(pipe, 0);
+ usbhs_pipe_disable(pipe); /* disable pipe first */
+ }
+
+ /*
* Buffer clear if Zero-Length packet
*
* see
@@ -481,16 +664,7 @@ static int usbhsf_pio_try_pop(struct usbhs_pkt *pkt, int *is_done)
buf[i] = (data >> ((i & 0x03) * 8)) & 0xff;
}
- pkt->actual += total_len;
-
usbhs_fifo_read_end:
- if ((pkt->actual == pkt->length) || /* receive all data */
- (total_len < maxp)) { /* short packet */
- *is_done = 1;
- usbhsf_rx_irq_ctrl(pipe, 0);
- usbhs_pipe_disable(pipe);
- }
-
dev_dbg(dev, " recv %d (%d/ %d/ %d/ %d)\n",
usbhs_pipe_number(pipe),
pkt->length, pkt->actual, *is_done, pkt->zero);
@@ -646,7 +820,7 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done)
if (len % 4) /* 32bit alignment */
goto usbhsf_pio_prepare_push;
- if (((u32)pkt->buf + pkt->actual) & 0x7) /* 8byte alignment */
+ if ((*(u32 *) pkt->buf + pkt->actual) & 0x7) /* 8byte alignment */
goto usbhsf_pio_prepare_push;
/* get enable DMA fifo */
@@ -723,7 +897,7 @@ static int usbhsf_dma_try_pop(struct usbhs_pkt *pkt, int *is_done)
if (!fifo)
goto usbhsf_pio_prepare_pop;
- if (((u32)pkt->buf + pkt->actual) & 0x7) /* 8byte alignment */
+ if ((*(u32 *) pkt->buf + pkt->actual) & 0x7) /* 8byte alignment */
goto usbhsf_pio_prepare_pop;
ret = usbhsf_fifo_select(pipe, fifo, 0);
@@ -884,7 +1058,7 @@ static int usbhsf_irq_empty(struct usbhs_priv *priv,
if (!(irq_state->bempsts & (1 << i)))
continue;
- ret = usbhs_pkt_run(pipe);
+ ret = usbhsf_pkt_handler(pipe, USBHSF_PKT_TRY_RUN);
if (ret < 0)
dev_err(dev, "irq_empty run_error %d : %d\n", i, ret);
}
@@ -914,7 +1088,7 @@ static int usbhsf_irq_ready(struct usbhs_priv *priv,
if (!(irq_state->brdysts & (1 << i)))
continue;
- ret = usbhs_pkt_run(pipe);
+ ret = usbhsf_pkt_handler(pipe, USBHSF_PKT_TRY_RUN);
if (ret < 0)
dev_err(dev, "irq_ready run_error %d : %d\n", i, ret);
}
@@ -929,7 +1103,7 @@ static void usbhsf_dma_complete(void *arg)
struct device *dev = usbhs_priv_to_dev(priv);
int ret;
- ret = usbhs_pkt_dmadone(pipe);
+ ret = usbhsf_pkt_handler(pipe, USBHSF_PKT_DMA_DONE);
if (ret < 0)
dev_err(dev, "dma_complete run_error %d : %d\n",
usbhs_pipe_number(pipe), ret);
diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h
index ed6d8e56c13c..32a7b246b28d 100644
--- a/drivers/usb/renesas_usbhs/fifo.h
+++ b/drivers/usb/renesas_usbhs/fifo.h
@@ -51,6 +51,8 @@ struct usbhs_pkt {
struct list_head node;
struct usbhs_pipe *pipe;
struct usbhs_pkt_handle *handler;
+ void (*done)(struct usbhs_priv *priv,
+ struct usbhs_pkt *pkt);
dma_addr_t dma;
void *buf;
int length;
@@ -76,12 +78,6 @@ void usbhs_fifo_quit(struct usbhs_priv *priv);
/*
* packet info
*/
-enum {
- USBHSF_PKT_PREPARE,
- USBHSF_PKT_TRY_RUN,
- USBHSF_PKT_DMA_DONE,
-};
-
extern struct usbhs_pkt_handle usbhs_fifo_pio_push_handler;
extern struct usbhs_pkt_handle usbhs_fifo_pio_pop_handler;
extern struct usbhs_pkt_handle usbhs_ctrl_stage_end_handler;
@@ -89,16 +85,18 @@ extern struct usbhs_pkt_handle usbhs_ctrl_stage_end_handler;
extern struct usbhs_pkt_handle usbhs_fifo_dma_push_handler;
extern struct usbhs_pkt_handle usbhs_fifo_dma_pop_handler;
+extern struct usbhs_pkt_handle usbhs_dcp_status_stage_in_handler;
+extern struct usbhs_pkt_handle usbhs_dcp_status_stage_out_handler;
+
+extern struct usbhs_pkt_handle usbhs_dcp_data_stage_in_handler;
+extern struct usbhs_pkt_handle usbhs_dcp_data_stage_out_handler;
void usbhs_pkt_init(struct usbhs_pkt *pkt);
void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
- struct usbhs_pkt_handle *handler,
+ void (*done)(struct usbhs_priv *priv,
+ struct usbhs_pkt *pkt),
void *buf, int len, int zero);
struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt);
-int __usbhs_pkt_handler(struct usbhs_pipe *pipe, int type);
-
-#define usbhs_pkt_start(p) __usbhs_pkt_handler(p, USBHSF_PKT_PREPARE)
-#define usbhs_pkt_run(p) __usbhs_pkt_handler(p, USBHSF_PKT_TRY_RUN)
-#define usbhs_pkt_dmadone(p) __usbhs_pkt_handler(p, USBHSF_PKT_DMA_DONE)
+void usbhs_pkt_start(struct usbhs_pipe *pipe);
#endif /* RENESAS_USB_FIFO_H */
diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c
index a577f8f4064c..053f86d70009 100644
--- a/drivers/usb/renesas_usbhs/mod.c
+++ b/drivers/usb/renesas_usbhs/mod.c
@@ -58,7 +58,7 @@ void usbhs_mod_autonomy_mode(struct usbhs_priv *priv)
struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
info->irq_vbus = usbhsm_autonomy_irq_vbus;
- priv->pfunc->get_vbus = usbhsm_autonomy_get_vbus;
+ priv->pfunc.get_vbus = usbhsm_autonomy_get_vbus;
usbhs_irq_callback_update(priv, NULL);
}
@@ -93,8 +93,9 @@ struct usbhs_mod *usbhs_mod_get(struct usbhs_priv *priv, int id)
return ret;
}
-int usbhs_mod_is_host(struct usbhs_priv *priv, struct usbhs_mod *mod)
+int usbhs_mod_is_host(struct usbhs_priv *priv)
{
+ struct usbhs_mod *mod = usbhs_mod_get_current(priv);
struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
if (!mod)
@@ -139,13 +140,17 @@ int usbhs_mod_probe(struct usbhs_priv *priv)
/*
* install host/gadget driver
*/
- ret = usbhs_mod_gadget_probe(priv);
+ ret = usbhs_mod_host_probe(priv);
if (ret < 0)
return ret;
+ ret = usbhs_mod_gadget_probe(priv);
+ if (ret < 0)
+ goto mod_init_host_err;
+
/* irq settings */
ret = request_irq(priv->irq, usbhs_interrupt,
- IRQF_DISABLED, dev_name(dev), priv);
+ 0, dev_name(dev), priv);
if (ret) {
dev_err(dev, "irq request err\n");
goto mod_init_gadget_err;
@@ -155,12 +160,15 @@ int usbhs_mod_probe(struct usbhs_priv *priv)
mod_init_gadget_err:
usbhs_mod_gadget_remove(priv);
+mod_init_host_err:
+ usbhs_mod_host_remove(priv);
return ret;
}
void usbhs_mod_remove(struct usbhs_priv *priv)
{
+ usbhs_mod_host_remove(priv);
usbhs_mod_gadget_remove(priv);
free_irq(priv->irq, priv);
}
@@ -168,20 +176,6 @@ void usbhs_mod_remove(struct usbhs_priv *priv)
/*
* status functions
*/
-int usbhs_status_get_usb_speed(struct usbhs_irq_state *irq_state)
-{
- switch (irq_state->dvstctr & RHST) {
- case RHST_LOW_SPEED:
- return USB_SPEED_LOW;
- case RHST_FULL_SPEED:
- return USB_SPEED_FULL;
- case RHST_HIGH_SPEED:
- return USB_SPEED_HIGH;
- }
-
- return USB_SPEED_UNKNOWN;
-}
-
int usbhs_status_get_device_state(struct usbhs_irq_state *irq_state)
{
int state = irq_state->intsts0 & DVSQ_MASK;
@@ -221,8 +215,6 @@ static void usbhs_status_get_each_irq(struct usbhs_priv *priv,
state->intsts0 = usbhs_read(priv, INTSTS0);
state->intsts1 = usbhs_read(priv, INTSTS1);
- state->dvstctr = usbhs_read(priv, DVSTCTR);
-
/* mask */
if (mod) {
state->brdysts = usbhs_read(priv, BRDYSTS);
@@ -269,6 +261,8 @@ static irqreturn_t usbhs_interrupt(int irq, void *data)
* see also
* usbhs_irq_setting_update
*/
+
+ /* INTSTS0 */
if (irq_state.intsts0 & VBINT)
usbhs_mod_info_call(priv, irq_vbus, priv, &irq_state);
@@ -284,15 +278,38 @@ static irqreturn_t usbhs_interrupt(int irq, void *data)
if (irq_state.intsts0 & BRDY)
usbhs_mod_call(priv, irq_ready, priv, &irq_state);
+ /* INTSTS1 */
+ if (irq_state.intsts1 & ATTCH)
+ usbhs_mod_call(priv, irq_attch, priv, &irq_state);
+
+ if (irq_state.intsts1 & DTCH)
+ usbhs_mod_call(priv, irq_dtch, priv, &irq_state);
+
+ if (irq_state.intsts1 & SIGN)
+ usbhs_mod_call(priv, irq_sign, priv, &irq_state);
+
+ if (irq_state.intsts1 & SACK)
+ usbhs_mod_call(priv, irq_sack, priv, &irq_state);
+
return IRQ_HANDLED;
}
void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod)
{
u16 intenb0 = 0;
+ u16 intenb1 = 0;
struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
+ /*
+ * BEMPENB/BRDYENB are picky.
+ * below method is required
+ *
+ * - clear INTSTS0
+ * - update BEMPENB/BRDYENB
+ * - update INTSTS0
+ */
usbhs_write(priv, INTENB0, 0);
+ usbhs_write(priv, INTENB1, 0);
usbhs_write(priv, BEMPENB, 0);
usbhs_write(priv, BRDYENB, 0);
@@ -310,6 +327,9 @@ void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod)
intenb0 |= VBSE;
if (mod) {
+ /*
+ * INTSTS0
+ */
if (mod->irq_ctrl_stage)
intenb0 |= CTRE;
@@ -322,7 +342,26 @@ void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod)
usbhs_write(priv, BRDYENB, mod->irq_brdysts);
intenb0 |= BRDYE;
}
+
+ /*
+ * INTSTS1
+ */
+ if (mod->irq_attch)
+ intenb1 |= ATTCHE;
+
+ if (mod->irq_attch)
+ intenb1 |= DTCHE;
+
+ if (mod->irq_sign)
+ intenb1 |= SIGNE;
+
+ if (mod->irq_sack)
+ intenb1 |= SACKE;
}
- usbhs_write(priv, INTENB0, intenb0);
+ if (intenb0)
+ usbhs_write(priv, INTENB0, intenb0);
+
+ if (intenb1)
+ usbhs_write(priv, INTENB1, intenb1);
}
diff --git a/drivers/usb/renesas_usbhs/mod.h b/drivers/usb/renesas_usbhs/mod.h
index 5c845a28a21c..8ae3733031cd 100644
--- a/drivers/usb/renesas_usbhs/mod.h
+++ b/drivers/usb/renesas_usbhs/mod.h
@@ -30,7 +30,6 @@ struct usbhs_irq_state {
u16 brdysts;
u16 nrdysts;
u16 bempsts;
- u16 dvstctr;
};
struct usbhs_mod {
@@ -42,26 +41,48 @@ struct usbhs_mod {
int (*start)(struct usbhs_priv *priv);
int (*stop)(struct usbhs_priv *priv);
- /* INTSTS0 :: DVST (DVSQ) */
+ /*
+ * INTSTS0
+ */
+
+ /* DVST (DVSQ) */
int (*irq_dev_state)(struct usbhs_priv *priv,
struct usbhs_irq_state *irq_state);
- /* INTSTS0 :: CTRT (CTSQ) */
+ /* CTRT (CTSQ) */
int (*irq_ctrl_stage)(struct usbhs_priv *priv,
struct usbhs_irq_state *irq_state);
- /* INTSTS0 :: BEMP */
- /* BEMPSTS */
+ /* BEMP / BEMPSTS */
int (*irq_empty)(struct usbhs_priv *priv,
struct usbhs_irq_state *irq_state);
u16 irq_bempsts;
- /* INTSTS0 :: BRDY */
- /* BRDYSTS */
+ /* BRDY / BRDYSTS */
int (*irq_ready)(struct usbhs_priv *priv,
struct usbhs_irq_state *irq_state);
u16 irq_brdysts;
+ /*
+ * INTSTS1
+ */
+
+ /* ATTCHE */
+ int (*irq_attch)(struct usbhs_priv *priv,
+ struct usbhs_irq_state *irq_state);
+
+ /* DTCHE */
+ int (*irq_dtch)(struct usbhs_priv *priv,
+ struct usbhs_irq_state *irq_state);
+
+ /* SIGN */
+ int (*irq_sign)(struct usbhs_priv *priv,
+ struct usbhs_irq_state *irq_state);
+
+ /* SACK */
+ int (*irq_sack)(struct usbhs_priv *priv,
+ struct usbhs_irq_state *irq_state);
+
struct usbhs_priv *priv;
};
@@ -89,7 +110,7 @@ struct usbhs_mod_info {
struct usbhs_mod *usbhs_mod_get(struct usbhs_priv *priv, int id);
struct usbhs_mod *usbhs_mod_get_current(struct usbhs_priv *priv);
void usbhs_mod_register(struct usbhs_priv *priv, struct usbhs_mod *usb, int id);
-int usbhs_mod_is_host(struct usbhs_priv *priv, struct usbhs_mod *mod);
+int usbhs_mod_is_host(struct usbhs_priv *priv);
int usbhs_mod_change(struct usbhs_priv *priv, int id);
int usbhs_mod_probe(struct usbhs_priv *priv);
void usbhs_mod_remove(struct usbhs_priv *priv);
@@ -99,7 +120,6 @@ void usbhs_mod_autonomy_mode(struct usbhs_priv *priv);
/*
* status functions
*/
-int usbhs_status_get_usb_speed(struct usbhs_irq_state *irq_state);
int usbhs_status_get_device_state(struct usbhs_irq_state *irq_state);
int usbhs_status_get_ctrl_stage(struct usbhs_irq_state *irq_state);
@@ -119,9 +139,24 @@ void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod);
})
/*
- * gadget control
+ * host / gadget control
*/
-#ifdef CONFIG_USB_RENESAS_USBHS_UDC
+#if defined(CONFIG_USB_RENESAS_USBHS_HCD) || \
+ defined(CONFIG_USB_RENESAS_USBHS_HCD_MODULE)
+extern int __devinit usbhs_mod_host_probe(struct usbhs_priv *priv);
+extern int __devexit usbhs_mod_host_remove(struct usbhs_priv *priv);
+#else
+static inline int usbhs_mod_host_probe(struct usbhs_priv *priv)
+{
+ return 0;
+}
+static inline void usbhs_mod_host_remove(struct usbhs_priv *priv)
+{
+}
+#endif
+
+#if defined(CONFIG_USB_RENESAS_USBHS_UDC) || \
+ defined(CONFIG_USB_RENESAS_USBHS_UDC_MODULE)
extern int __devinit usbhs_mod_gadget_probe(struct usbhs_priv *priv);
extern void __devexit usbhs_mod_gadget_remove(struct usbhs_priv *priv);
#else
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index cb2d451d511e..4cc7ee0babc6 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -39,7 +39,6 @@ struct usbhsg_uep {
char ep_name[EP_NAME_SIZE];
struct usbhsg_gpriv *gpriv;
- struct usbhs_pkt_handle *handler;
};
struct usbhsg_gpriv {
@@ -128,25 +127,6 @@ LIST_HEAD(the_controller_link);
/*
* queue push/pop
*/
-static void usbhsg_queue_push(struct usbhsg_uep *uep,
- struct usbhsg_request *ureq)
-{
- struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
- struct device *dev = usbhsg_gpriv_to_dev(gpriv);
- struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
- struct usbhs_pkt *pkt = usbhsg_ureq_to_pkt(ureq);
- struct usb_request *req = &ureq->req;
-
- req->actual = 0;
- req->status = -EINPROGRESS;
- usbhs_pkt_push(pipe, pkt, uep->handler,
- req->buf, req->length, req->zero);
-
- dev_dbg(dev, "pipe %d : queue push (%d)\n",
- usbhs_pipe_number(pipe),
- req->length);
-}
-
static void usbhsg_queue_pop(struct usbhsg_uep *uep,
struct usbhsg_request *ureq,
int status)
@@ -161,7 +141,7 @@ static void usbhsg_queue_pop(struct usbhsg_uep *uep,
ureq->req.complete(&uep->ep, &ureq->req);
}
-static void usbhsg_queue_done(struct usbhs_pkt *pkt)
+static void usbhsg_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt)
{
struct usbhs_pipe *pipe = pkt->pipe;
struct usbhsg_uep *uep = usbhsg_pipe_to_uep(pipe);
@@ -172,6 +152,26 @@ static void usbhsg_queue_done(struct usbhs_pkt *pkt)
usbhsg_queue_pop(uep, ureq, 0);
}
+static void usbhsg_queue_push(struct usbhsg_uep *uep,
+ struct usbhsg_request *ureq)
+{
+ struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
+ struct device *dev = usbhsg_gpriv_to_dev(gpriv);
+ struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
+ struct usbhs_pkt *pkt = usbhsg_ureq_to_pkt(ureq);
+ struct usb_request *req = &ureq->req;
+
+ req->actual = 0;
+ req->status = -EINPROGRESS;
+ usbhs_pkt_push(pipe, pkt, usbhsg_queue_done,
+ req->buf, req->length, req->zero);
+ usbhs_pkt_start(pipe);
+
+ dev_dbg(dev, "pipe %d : queue push (%d)\n",
+ usbhs_pipe_number(pipe),
+ req->length);
+}
+
/*
* dma map/unmap
*/
@@ -265,7 +265,7 @@ static int usbhsg_recip_handler_std_clear_endpoint(struct usbhs_priv *priv,
if (!usbhsg_status_has(gpriv, USBHSG_STATUS_WEDGE)) {
usbhs_pipe_disable(pipe);
- usbhs_pipe_clear_sequence(pipe);
+ usbhs_pipe_sequence_data0(pipe);
usbhs_pipe_enable(pipe);
}
@@ -355,7 +355,7 @@ static int usbhsg_irq_dev_state(struct usbhs_priv *priv,
struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv);
struct device *dev = usbhsg_gpriv_to_dev(gpriv);
- gpriv->gadget.speed = usbhs_status_get_usb_speed(irq_state);
+ gpriv->gadget.speed = usbhs_bus_get_speed(priv);
dev_dbg(dev, "state = %x : speed : %d\n",
usbhs_status_get_device_state(irq_state),
@@ -389,13 +389,13 @@ static int usbhsg_irq_ctrl_stage(struct usbhs_priv *priv,
switch (stage) {
case READ_DATA_STAGE:
- dcp->handler = &usbhs_fifo_pio_push_handler;
+ pipe->handler = &usbhs_fifo_pio_push_handler;
break;
case WRITE_DATA_STAGE:
- dcp->handler = &usbhs_fifo_pio_pop_handler;
+ pipe->handler = &usbhs_fifo_pio_pop_handler;
break;
case NODATA_STATUS_STAGE:
- dcp->handler = &usbhs_ctrl_stage_end_handler;
+ pipe->handler = &usbhs_ctrl_stage_end_handler;
break;
default:
return ret;
@@ -479,24 +479,31 @@ static int usbhsg_ep_enable(struct usb_ep *ep,
*/
if (uep->pipe) {
usbhs_pipe_clear(uep->pipe);
- usbhs_pipe_clear_sequence(uep->pipe);
+ usbhs_pipe_sequence_data0(uep->pipe);
return 0;
}
- pipe = usbhs_pipe_malloc(priv, desc);
+ pipe = usbhs_pipe_malloc(priv,
+ usb_endpoint_type(desc),
+ usb_endpoint_dir_in(desc));
if (pipe) {
uep->pipe = pipe;
pipe->mod_private = uep;
+ /* set epnum / maxp */
+ usbhs_pipe_config_update(pipe, 0,
+ usb_endpoint_num(desc),
+ usb_endpoint_maxp(desc));
+
/*
* usbhs_fifo_dma_push/pop_handler try to
* use dmaengine if possible.
* It will use pio handler if impossible.
*/
if (usb_endpoint_dir_in(desc))
- uep->handler = &usbhs_fifo_dma_push_handler;
+ pipe->handler = &usbhs_fifo_dma_push_handler;
else
- uep->handler = &usbhs_fifo_dma_pop_handler;
+ pipe->handler = &usbhs_fifo_dma_pop_handler;
ret = 0;
}
@@ -659,7 +666,6 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status)
* pipe initialize and enable DCP
*/
usbhs_pipe_init(priv,
- usbhsg_queue_done,
usbhsg_dma_map_ctrl);
usbhs_fifo_init(priv);
usbhsg_uep_init(gpriv);
@@ -667,6 +673,7 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status)
/* dcp init */
dcp->pipe = usbhs_dcp_malloc(priv);
dcp->pipe->mod_private = dcp;
+ usbhs_pipe_config_update(dcp->pipe, 0, 0, 64);
/*
* system config enble
@@ -730,10 +737,6 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status)
usbhsg_pipe_disable(dcp);
- if (gpriv->driver &&
- gpriv->driver->disconnect)
- gpriv->driver->disconnect(&gpriv->gadget);
-
dev_dbg(dev, "stop gadget\n");
return 0;
@@ -744,31 +747,19 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status)
* linux usb function
*
*/
-static int usbhsg_gadget_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *))
+static int usbhsg_gadget_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
- struct usbhsg_gpriv *gpriv;
+ struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget);
struct usbhs_priv *priv;
struct device *dev;
int ret;
- if (!bind ||
- !driver ||
+ if (!driver ||
!driver->setup ||
driver->speed != USB_SPEED_HIGH)
return -EINVAL;
- /*
- * find unused controller
- */
- usbhsg_for_each_controller(gpriv) {
- if (!gpriv->driver)
- goto find_unused_controller;
- }
- return -ENODEV;
-
-find_unused_controller:
-
dev = usbhsg_gpriv_to_dev(gpriv);
priv = usbhsg_gpriv_to_priv(gpriv);
@@ -782,19 +773,8 @@ find_unused_controller:
goto add_fail;
}
- ret = bind(&gpriv->gadget);
- if (ret) {
- dev_err(dev, "bind to driver %s error %d\n",
- driver->driver.name, ret);
- goto bind_fail;
- }
-
- dev_dbg(dev, "bind %s\n", driver->driver.name);
-
return usbhsg_try_start(priv, USBHSG_STATUS_REGISTERD);
-bind_fail:
- device_del(&gpriv->gadget.dev);
add_fail:
gpriv->driver = NULL;
gpriv->gadget.dev.driver = NULL;
@@ -802,9 +782,10 @@ add_fail:
return ret;
}
-static int usbhsg_gadget_stop(struct usb_gadget_driver *driver)
+static int usbhsg_gadget_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
- struct usbhsg_gpriv *gpriv;
+ struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget);
struct usbhs_priv *priv;
struct device *dev;
@@ -812,17 +793,6 @@ static int usbhsg_gadget_stop(struct usb_gadget_driver *driver)
!driver->unbind)
return -EINVAL;
- /*
- * find controller
- */
- usbhsg_for_each_controller(gpriv) {
- if (gpriv->driver == driver)
- goto find_matching_controller;
- }
- return -ENODEV;
-
-find_matching_controller:
-
dev = usbhsg_gpriv_to_dev(gpriv);
priv = usbhsg_gpriv_to_priv(gpriv);
@@ -830,12 +800,6 @@ find_matching_controller:
device_del(&gpriv->gadget.dev);
gpriv->driver = NULL;
- if (driver->disconnect)
- driver->disconnect(&gpriv->gadget);
-
- driver->unbind(&gpriv->gadget);
- dev_dbg(dev, "unbind %s\n", driver->driver.name);
-
return 0;
}
@@ -852,8 +816,8 @@ static int usbhsg_get_frame(struct usb_gadget *gadget)
static struct usb_gadget_ops usbhsg_gadget_ops = {
.get_frame = usbhsg_get_frame,
- .start = usbhsg_gadget_start,
- .stop = usbhsg_gadget_stop,
+ .udc_start = usbhsg_gadget_start,
+ .udc_stop = usbhsg_gadget_stop,
};
static int usbhsg_start(struct usbhs_priv *priv)
diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c
new file mode 100644
index 000000000000..1a7208a50afc
--- /dev/null
+++ b/drivers/usb/renesas_usbhs/mod_host.c
@@ -0,0 +1,1312 @@
+/*
+ * Renesas USB driver
+ *
+ * Copyright (C) 2011 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include "common.h"
+
+/*
+ *** HARDWARE LIMITATION ***
+ *
+ * 1) renesas_usbhs has a limited number of controllable devices.
+ * it can control only 9 devices in generally.
+ * see DEVADDn / DCPMAXP / PIPEMAXP.
+ *
+ * 2) renesas_usbhs pipe number is limited.
+ * the pipe will be re-used for each devices.
+ * so, software should control DATA0/1 sequence of each devices.
+ */
+
+
+/*
+ * image of mod_host
+ *
+ * +--------+
+ * | udev 0 | --> it is used when set address
+ * +--------+
+ *
+ * +--------+ pipes are reused for each uep.
+ * | udev 1 |-+- [uep 0 (dcp) ] --+ pipe will be switched when
+ * +--------+ | | target device was changed
+ * +- [uep 1 (bulk)] --|---+ +--------------+
+ * | +--------------> | pipe0 (dcp) |
+ * +- [uep 2 (bulk)] --|---|---+ +--------------+
+ * | | | | pipe1 (isoc) |
+ * +--------+ | | | +--------------+
+ * | udev 2 |-+- [uep 0 (dcp) ] --+ +-- |------> | pipe2 (bulk) |
+ * +--------+ | | | | +--------------+
+ * +- [uep 1 (int) ] --|-+ | +------> | pipe3 (bulk) |
+ * | | | | +--------------+
+ * +--------+ | +-|---|------> | pipe4 (int) |
+ * | udev 3 |-+- [uep 0 (dcp) ] --+ | | +--------------+
+ * +--------+ | | | | .... |
+ * +- [uep 1 (bulk)] ------+ | | .... |
+ * | |
+ * +- [uep 2 (bulk)]-----------+
+ */
+
+
+/*
+ * struct
+ */
+struct usbhsh_pipe_info {
+ unsigned int usr_cnt; /* see usbhsh_endpoint_alloc() */
+};
+
+struct usbhsh_request {
+ struct urb *urb;
+ struct usbhs_pkt pkt;
+ struct list_head ureq_link; /* see hpriv :: ureq_link_xxx */
+};
+
+struct usbhsh_device {
+ struct usb_device *usbv;
+ struct list_head ep_list_head; /* list of usbhsh_ep */
+};
+
+struct usbhsh_ep {
+ struct usbhs_pipe *pipe;
+ struct usbhsh_device *udev; /* attached udev */
+ struct list_head ep_list; /* list to usbhsh_device */
+
+ int maxp;
+};
+
+#define USBHSH_DEVICE_MAX 10 /* see DEVADDn / DCPMAXP / PIPEMAXP */
+#define USBHSH_PORT_MAX 7 /* see DEVADDn :: HUBPORT */
+struct usbhsh_hpriv {
+ struct usbhs_mod mod;
+ struct usbhs_pipe *dcp;
+
+ struct usbhsh_device udev[USBHSH_DEVICE_MAX];
+
+ struct usbhsh_pipe_info *pipe_info;
+ int pipe_size;
+
+ u32 port_stat; /* USB_PORT_STAT_xxx */
+
+ struct completion *done;
+
+ /* see usbhsh_req_alloc/free */
+ struct list_head ureq_link_active;
+ struct list_head ureq_link_free;
+};
+
+
+static const char usbhsh_hcd_name[] = "renesas_usbhs host";
+
+/*
+ * macro
+ */
+#define usbhsh_priv_to_hpriv(priv) \
+ container_of(usbhs_mod_get(priv, USBHS_HOST), struct usbhsh_hpriv, mod)
+
+#define __usbhsh_for_each_hpipe(start, pos, h, i) \
+ for (i = start, pos = (h)->hpipe + i; \
+ i < (h)->hpipe_size; \
+ i++, pos = (h)->hpipe + i)
+
+#define usbhsh_for_each_hpipe(pos, hpriv, i) \
+ __usbhsh_for_each_hpipe(1, pos, hpriv, i)
+
+#define usbhsh_for_each_hpipe_with_dcp(pos, hpriv, i) \
+ __usbhsh_for_each_hpipe(0, pos, hpriv, i)
+
+#define __usbhsh_for_each_udev(start, pos, h, i) \
+ for (i = start, pos = (h)->udev + i; \
+ i < USBHSH_DEVICE_MAX; \
+ i++, pos = (h)->udev + i)
+
+#define usbhsh_for_each_udev(pos, hpriv, i) \
+ __usbhsh_for_each_udev(1, pos, hpriv, i)
+
+#define usbhsh_for_each_udev_with_dev0(pos, hpriv, i) \
+ __usbhsh_for_each_udev(0, pos, hpriv, i)
+
+#define usbhsh_hcd_to_hpriv(h) (struct usbhsh_hpriv *)((h)->hcd_priv)
+#define usbhsh_hcd_to_dev(h) ((h)->self.controller)
+
+#define usbhsh_hpriv_to_priv(h) ((h)->mod.priv)
+#define usbhsh_hpriv_to_dcp(h) ((h)->dcp)
+#define usbhsh_hpriv_to_hcd(h) \
+ container_of((void *)h, struct usb_hcd, hcd_priv)
+
+#define usbhsh_ep_to_uep(u) ((u)->hcpriv)
+#define usbhsh_uep_to_pipe(u) ((u)->pipe)
+#define usbhsh_uep_to_udev(u) ((u)->udev)
+#define usbhsh_urb_to_ureq(u) ((u)->hcpriv)
+#define usbhsh_urb_to_usbv(u) ((u)->dev)
+
+#define usbhsh_usbv_to_udev(d) dev_get_drvdata(&(d)->dev)
+
+#define usbhsh_udev_to_usbv(h) ((h)->usbv)
+
+#define usbhsh_pipe_info(p) ((p)->mod_private)
+
+#define usbhsh_device_number(h, d) ((int)((d) - (h)->udev))
+#define usbhsh_device_nth(h, d) ((h)->udev + d)
+#define usbhsh_device0(h) usbhsh_device_nth(h, 0)
+
+#define usbhsh_port_stat_init(h) ((h)->port_stat = 0)
+#define usbhsh_port_stat_set(h, s) ((h)->port_stat |= (s))
+#define usbhsh_port_stat_clear(h, s) ((h)->port_stat &= ~(s))
+#define usbhsh_port_stat_get(h) ((h)->port_stat)
+
+#define usbhsh_pkt_to_req(p) \
+ container_of((void *)p, struct usbhsh_request, pkt)
+
+/*
+ * req alloc/free
+ */
+static void usbhsh_req_list_init(struct usbhsh_hpriv *hpriv)
+{
+ INIT_LIST_HEAD(&hpriv->ureq_link_active);
+ INIT_LIST_HEAD(&hpriv->ureq_link_free);
+}
+
+static void usbhsh_req_list_quit(struct usbhsh_hpriv *hpriv)
+{
+ struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
+ struct device *dev = usbhsh_hcd_to_dev(hcd);
+ struct usbhsh_request *ureq, *next;
+
+ /* kfree all active ureq */
+ list_for_each_entry_safe(ureq, next,
+ &hpriv->ureq_link_active,
+ ureq_link) {
+ dev_err(dev, "active ureq (%p) is force freed\n", ureq);
+ kfree(ureq);
+ }
+
+ /* kfree all free ureq */
+ list_for_each_entry_safe(ureq, next, &hpriv->ureq_link_free, ureq_link)
+ kfree(ureq);
+}
+
+static struct usbhsh_request *usbhsh_req_alloc(struct usbhsh_hpriv *hpriv,
+ struct urb *urb,
+ gfp_t mem_flags)
+{
+ struct usbhsh_request *ureq;
+ struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+ struct device *dev = usbhs_priv_to_dev(priv);
+
+ if (list_empty(&hpriv->ureq_link_free)) {
+ /*
+ * create new one if there is no free ureq
+ */
+ ureq = kzalloc(sizeof(struct usbhsh_request), mem_flags);
+ if (ureq)
+ INIT_LIST_HEAD(&ureq->ureq_link);
+ } else {
+ /*
+ * reuse "free" ureq if exist
+ */
+ ureq = list_entry(hpriv->ureq_link_free.next,
+ struct usbhsh_request,
+ ureq_link);
+ if (ureq)
+ list_del_init(&ureq->ureq_link);
+ }
+
+ if (!ureq) {
+ dev_err(dev, "ureq alloc fail\n");
+ return NULL;
+ }
+
+ usbhs_pkt_init(&ureq->pkt);
+
+ /*
+ * push it to "active" list
+ */
+ list_add_tail(&ureq->ureq_link, &hpriv->ureq_link_active);
+ ureq->urb = urb;
+
+ return ureq;
+}
+
+static void usbhsh_req_free(struct usbhsh_hpriv *hpriv,
+ struct usbhsh_request *ureq)
+{
+ struct usbhs_pkt *pkt = &ureq->pkt;
+
+ usbhs_pkt_init(pkt);
+
+ /*
+ * removed from "active" list,
+ * and push it to "free" list
+ */
+ ureq->urb = NULL;
+ list_del_init(&ureq->ureq_link);
+ list_add_tail(&ureq->ureq_link, &hpriv->ureq_link_free);
+}
+
+/*
+ * device control
+ */
+
+static int usbhsh_device_has_endpoint(struct usbhsh_device *udev)
+{
+ return !list_empty(&udev->ep_list_head);
+}
+
+static struct usbhsh_device *usbhsh_device_alloc(struct usbhsh_hpriv *hpriv,
+ struct urb *urb)
+{
+ struct usbhsh_device *udev = NULL;
+ struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
+ struct device *dev = usbhsh_hcd_to_dev(hcd);
+ struct usb_device *usbv = usbhsh_urb_to_usbv(urb);
+ struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+ int i;
+
+ /*
+ * device 0
+ */
+ if (0 == usb_pipedevice(urb->pipe)) {
+ udev = usbhsh_device0(hpriv);
+ goto usbhsh_device_find;
+ }
+
+ /*
+ * find unused device
+ */
+ usbhsh_for_each_udev(udev, hpriv, i) {
+ if (usbhsh_udev_to_usbv(udev))
+ continue;
+ goto usbhsh_device_find;
+ }
+
+ dev_err(dev, "no free usbhsh_device\n");
+
+ return NULL;
+
+usbhsh_device_find:
+ if (usbhsh_device_has_endpoint(udev))
+ dev_warn(dev, "udev have old endpoint\n");
+
+ /* uep will be attached */
+ INIT_LIST_HEAD(&udev->ep_list_head);
+
+ /*
+ * usbhsh_usbv_to_udev()
+ * usbhsh_udev_to_usbv()
+ * will be enable
+ */
+ dev_set_drvdata(&usbv->dev, udev);
+ udev->usbv = usbv;
+
+ /* set device config */
+ usbhs_set_device_speed(priv,
+ usbhsh_device_number(hpriv, udev),
+ usbhsh_device_number(hpriv, udev),
+ 0, /* FIXME no parent */
+ usbv->speed);
+
+ dev_dbg(dev, "%s [%d](%p)\n", __func__,
+ usbhsh_device_number(hpriv, udev), udev);
+
+ return udev;
+}
+
+static void usbhsh_device_free(struct usbhsh_hpriv *hpriv,
+ struct usbhsh_device *udev)
+{
+ struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
+ struct device *dev = usbhsh_hcd_to_dev(hcd);
+ struct usb_device *usbv = usbhsh_udev_to_usbv(udev);
+
+ dev_dbg(dev, "%s [%d](%p)\n", __func__,
+ usbhsh_device_number(hpriv, udev), udev);
+
+ if (usbhsh_device_has_endpoint(udev))
+ dev_warn(dev, "udev still have endpoint\n");
+
+ /*
+ * usbhsh_usbv_to_udev()
+ * usbhsh_udev_to_usbv()
+ * will be disable
+ */
+ dev_set_drvdata(&usbv->dev, NULL);
+ udev->usbv = NULL;
+}
+
+/*
+ * end-point control
+ */
+struct usbhsh_ep *usbhsh_endpoint_alloc(struct usbhsh_hpriv *hpriv,
+ struct usbhsh_device *udev,
+ struct usb_host_endpoint *ep,
+ gfp_t mem_flags)
+{
+ struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+ struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
+ struct usbhsh_ep *uep;
+ struct usbhsh_pipe_info *info;
+ struct usbhs_pipe *pipe, *best_pipe;
+ struct device *dev = usbhsh_hcd_to_dev(hcd);
+ struct usb_endpoint_descriptor *desc = &ep->desc;
+ int type, i;
+ unsigned int min_usr;
+
+ uep = kzalloc(sizeof(struct usbhsh_ep), mem_flags);
+ if (!uep) {
+ dev_err(dev, "usbhsh_ep alloc fail\n");
+ return NULL;
+ }
+ type = usb_endpoint_type(desc);
+
+ /*
+ * find best pipe for endpoint
+ * see
+ * HARDWARE LIMITATION
+ */
+ min_usr = ~0;
+ best_pipe = NULL;
+ usbhs_for_each_pipe_with_dcp(pipe, priv, i) {
+ if (!usbhs_pipe_type_is(pipe, type))
+ continue;
+
+ info = usbhsh_pipe_info(pipe);
+
+ if (min_usr > info->usr_cnt) {
+ min_usr = info->usr_cnt;
+ best_pipe = pipe;
+ }
+ }
+
+ if (unlikely(!best_pipe)) {
+ dev_err(dev, "couldn't find best pipe\n");
+ kfree(uep);
+ return NULL;
+ }
+
+ /*
+ * init uep
+ */
+ uep->pipe = best_pipe;
+ uep->maxp = usb_endpoint_maxp(desc);
+ usbhsh_uep_to_udev(uep) = udev;
+ usbhsh_ep_to_uep(ep) = uep;
+
+ /*
+ * update pipe user count
+ */
+ info = usbhsh_pipe_info(best_pipe);
+ info->usr_cnt++;
+
+ /* init this endpoint, and attach it to udev */
+ INIT_LIST_HEAD(&uep->ep_list);
+ list_add_tail(&uep->ep_list, &udev->ep_list_head);
+
+ /*
+ * usbhs_pipe_config_update() should be called after
+ * usbhs_device_config()
+ * see
+ * DCPMAXP/PIPEMAXP
+ */
+ usbhs_pipe_config_update(uep->pipe,
+ usbhsh_device_number(hpriv, udev),
+ usb_endpoint_num(desc),
+ uep->maxp);
+
+ dev_dbg(dev, "%s [%d-%s](%p)\n", __func__,
+ usbhsh_device_number(hpriv, udev),
+ usbhs_pipe_name(pipe), uep);
+
+ return uep;
+}
+
+void usbhsh_endpoint_free(struct usbhsh_hpriv *hpriv,
+ struct usb_host_endpoint *ep)
+{
+ struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+ struct device *dev = usbhs_priv_to_dev(priv);
+ struct usbhsh_ep *uep = usbhsh_ep_to_uep(ep);
+ struct usbhsh_pipe_info *info;
+
+ if (!uep)
+ return;
+
+ dev_dbg(dev, "%s [%d-%s](%p)\n", __func__,
+ usbhsh_device_number(hpriv, usbhsh_uep_to_udev(uep)),
+ usbhs_pipe_name(uep->pipe), uep);
+
+ info = usbhsh_pipe_info(uep->pipe);
+ info->usr_cnt--;
+
+ /* remove this endpoint from udev */
+ list_del_init(&uep->ep_list);
+
+ usbhsh_uep_to_udev(uep) = NULL;
+ usbhsh_ep_to_uep(ep) = NULL;
+
+ kfree(uep);
+}
+
+/*
+ * queue push/pop
+ */
+static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt)
+{
+ struct usbhsh_request *ureq = usbhsh_pkt_to_req(pkt);
+ struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv);
+ struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
+ struct urb *urb = ureq->urb;
+ struct device *dev = usbhs_priv_to_dev(priv);
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ if (!urb) {
+ dev_warn(dev, "pkt doesn't have urb\n");
+ return;
+ }
+
+ urb->actual_length = pkt->actual;
+ usbhsh_req_free(hpriv, ureq);
+ usbhsh_urb_to_ureq(urb) = NULL;
+
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ usb_hcd_giveback_urb(hcd, urb, 0);
+}
+
+static int usbhsh_queue_push(struct usb_hcd *hcd,
+ struct usbhs_pipe *pipe,
+ struct urb *urb)
+{
+ struct usbhsh_request *ureq = usbhsh_urb_to_ureq(urb);
+ struct usbhs_pkt *pkt = &ureq->pkt;
+ struct device *dev = usbhsh_hcd_to_dev(hcd);
+ void *buf;
+ int len;
+
+ if (usb_pipeisoc(urb->pipe)) {
+ dev_err(dev, "pipe iso is not supported now\n");
+ return -EIO;
+ }
+
+ if (usb_pipein(urb->pipe))
+ pipe->handler = &usbhs_fifo_pio_pop_handler;
+ else
+ pipe->handler = &usbhs_fifo_pio_push_handler;
+
+ buf = (void *)(urb->transfer_buffer + urb->actual_length);
+ len = urb->transfer_buffer_length - urb->actual_length;
+
+ dev_dbg(dev, "%s\n", __func__);
+ usbhs_pkt_push(pipe, pkt, usbhsh_queue_done,
+ buf, len, (urb->transfer_flags & URB_ZERO_PACKET));
+ usbhs_pkt_start(pipe);
+
+ return 0;
+}
+
+/*
+ * DCP setup stage
+ */
+static int usbhsh_is_request_address(struct urb *urb)
+{
+ struct usb_ctrlrequest *cmd;
+
+ cmd = (struct usb_ctrlrequest *)urb->setup_packet;
+
+ if ((DeviceOutRequest == cmd->bRequestType << 8) &&
+ (USB_REQ_SET_ADDRESS == cmd->bRequest))
+ return 1;
+ else
+ return 0;
+}
+
+static void usbhsh_setup_stage_packet_push(struct usbhsh_hpriv *hpriv,
+ struct urb *urb,
+ struct usbhs_pipe *pipe)
+{
+ struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+ struct usb_ctrlrequest req;
+ struct device *dev = usbhs_priv_to_dev(priv);
+
+ /*
+ * wait setup packet ACK
+ * see
+ * usbhsh_irq_setup_ack()
+ * usbhsh_irq_setup_err()
+ */
+ DECLARE_COMPLETION(done);
+ hpriv->done = &done;
+
+ /* copy original request */
+ memcpy(&req, urb->setup_packet, sizeof(struct usb_ctrlrequest));
+
+ /*
+ * renesas_usbhs can not use original usb address.
+ * see HARDWARE LIMITATION.
+ * modify usb address here.
+ */
+ if (usbhsh_is_request_address(urb)) {
+ /* FIXME */
+ req.wValue = 1;
+ dev_dbg(dev, "create new address - %d\n", req.wValue);
+ }
+
+ /* set request */
+ usbhs_usbreq_set_val(priv, &req);
+
+ /*
+ * wait setup packet ACK
+ */
+ wait_for_completion(&done);
+ hpriv->done = NULL;
+
+ dev_dbg(dev, "%s done\n", __func__);
+}
+
+/*
+ * DCP data stage
+ */
+static void usbhsh_data_stage_packet_done(struct usbhs_priv *priv,
+ struct usbhs_pkt *pkt)
+{
+ struct usbhsh_request *ureq = usbhsh_pkt_to_req(pkt);
+ struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv);
+ struct urb *urb = ureq->urb;
+
+ /* this ureq was connected to urb when usbhsh_urb_enqueue() */
+
+ usbhsh_req_free(hpriv, ureq);
+ usbhsh_urb_to_ureq(urb) = NULL;
+}
+
+static void usbhsh_data_stage_packet_push(struct usbhsh_hpriv *hpriv,
+ struct urb *urb,
+ struct usbhs_pipe *pipe)
+{
+ struct usbhsh_request *ureq;
+ struct usbhs_pkt *pkt;
+
+ /*
+ * FIXME
+ *
+ * data stage uses ureq which is connected to urb
+ * see usbhsh_urb_enqueue() :: alloc new request.
+ * it will be freed in usbhsh_data_stage_packet_done()
+ */
+ ureq = usbhsh_urb_to_ureq(urb);
+ pkt = &ureq->pkt;
+
+ if (usb_pipein(urb->pipe))
+ pipe->handler = &usbhs_dcp_data_stage_in_handler;
+ else
+ pipe->handler = &usbhs_dcp_data_stage_out_handler;
+
+ usbhs_pkt_push(pipe, pkt,
+ usbhsh_data_stage_packet_done,
+ urb->transfer_buffer,
+ urb->transfer_buffer_length,
+ (urb->transfer_flags & URB_ZERO_PACKET));
+}
+
+/*
+ * DCP status stage
+ */
+static void usbhsh_status_stage_packet_push(struct usbhsh_hpriv *hpriv,
+ struct urb *urb,
+ struct usbhs_pipe *pipe)
+{
+ struct usbhsh_request *ureq;
+ struct usbhs_pkt *pkt;
+
+ /*
+ * FIXME
+ *
+ * status stage uses allocated ureq.
+ * it will be freed on usbhsh_queue_done()
+ */
+ ureq = usbhsh_req_alloc(hpriv, urb, GFP_KERNEL);
+ pkt = &ureq->pkt;
+
+ if (usb_pipein(urb->pipe))
+ pipe->handler = &usbhs_dcp_status_stage_in_handler;
+ else
+ pipe->handler = &usbhs_dcp_status_stage_out_handler;
+
+ usbhs_pkt_push(pipe, pkt,
+ usbhsh_queue_done,
+ NULL,
+ urb->transfer_buffer_length,
+ 0);
+}
+
+static int usbhsh_dcp_queue_push(struct usb_hcd *hcd,
+ struct usbhsh_hpriv *hpriv,
+ struct usbhs_pipe *pipe,
+ struct urb *urb)
+{
+ struct device *dev = usbhsh_hcd_to_dev(hcd);
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ /*
+ * setup stage
+ *
+ * usbhsh_send_setup_stage_packet() wait SACK/SIGN
+ */
+ usbhsh_setup_stage_packet_push(hpriv, urb, pipe);
+
+ /*
+ * data stage
+ *
+ * It is pushed only when urb has buffer.
+ */
+ if (urb->transfer_buffer_length)
+ usbhsh_data_stage_packet_push(hpriv, urb, pipe);
+
+ /*
+ * status stage
+ */
+ usbhsh_status_stage_packet_push(hpriv, urb, pipe);
+
+ /*
+ * start pushed packets
+ */
+ usbhs_pkt_start(pipe);
+
+ return 0;
+}
+
+/*
+ * dma map functions
+ */
+static int usbhsh_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
+{
+ return 0;
+}
+
+/*
+ * for hc_driver
+ */
+static int usbhsh_host_start(struct usb_hcd *hcd)
+{
+ return 0;
+}
+
+static void usbhsh_host_stop(struct usb_hcd *hcd)
+{
+}
+
+static int usbhsh_urb_enqueue(struct usb_hcd *hcd,
+ struct urb *urb,
+ gfp_t mem_flags)
+{
+ struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd);
+ struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+ struct device *dev = usbhs_priv_to_dev(priv);
+ struct usb_device *usbv = usbhsh_urb_to_usbv(urb);
+ struct usb_host_endpoint *ep = urb->ep;
+ struct usbhsh_request *ureq;
+ struct usbhsh_device *udev, *new_udev = NULL;
+ struct usbhs_pipe *pipe;
+ struct usbhsh_ep *uep;
+
+ int ret;
+
+ dev_dbg(dev, "%s (%s)\n",
+ __func__, usb_pipein(urb->pipe) ? "in" : "out");
+
+ ret = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (ret)
+ goto usbhsh_urb_enqueue_error_not_linked;
+
+ /*
+ * get udev
+ */
+ udev = usbhsh_usbv_to_udev(usbv);
+ if (!udev) {
+ new_udev = usbhsh_device_alloc(hpriv, urb);
+ if (!new_udev)
+ goto usbhsh_urb_enqueue_error_not_linked;
+
+ udev = new_udev;
+ }
+
+ /*
+ * get uep
+ */
+ uep = usbhsh_ep_to_uep(ep);
+ if (!uep) {
+ uep = usbhsh_endpoint_alloc(hpriv, udev, ep, mem_flags);
+ if (!uep)
+ goto usbhsh_urb_enqueue_error_free_device;
+ }
+ pipe = usbhsh_uep_to_pipe(uep);
+
+ /*
+ * alloc new request
+ */
+ ureq = usbhsh_req_alloc(hpriv, urb, mem_flags);
+ if (unlikely(!ureq)) {
+ ret = -ENOMEM;
+ goto usbhsh_urb_enqueue_error_free_endpoint;
+ }
+ usbhsh_urb_to_ureq(urb) = ureq;
+
+ /*
+ * push packet
+ */
+ if (usb_pipecontrol(urb->pipe))
+ usbhsh_dcp_queue_push(hcd, hpriv, pipe, urb);
+ else
+ usbhsh_queue_push(hcd, pipe, urb);
+
+ return 0;
+
+usbhsh_urb_enqueue_error_free_endpoint:
+ usbhsh_endpoint_free(hpriv, ep);
+usbhsh_urb_enqueue_error_free_device:
+ if (new_udev)
+ usbhsh_device_free(hpriv, new_udev);
+usbhsh_urb_enqueue_error_not_linked:
+
+ dev_dbg(dev, "%s error\n", __func__);
+
+ return ret;
+}
+
+static int usbhsh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+ struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd);
+ struct usbhsh_request *ureq = usbhsh_urb_to_ureq(urb);
+
+ if (ureq) {
+ usbhsh_req_free(hpriv, ureq);
+ usbhsh_urb_to_ureq(urb) = NULL;
+ }
+
+ return 0;
+}
+
+static void usbhsh_endpoint_disable(struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct usbhsh_ep *uep = usbhsh_ep_to_uep(ep);
+ struct usbhsh_device *udev;
+ struct usbhsh_hpriv *hpriv;
+
+ /*
+ * this function might be called manytimes by same hcd/ep
+ * in-endpoitn == out-endpoint if ep == dcp.
+ */
+ if (!uep)
+ return;
+
+ udev = usbhsh_uep_to_udev(uep);
+ hpriv = usbhsh_hcd_to_hpriv(hcd);
+
+ usbhsh_endpoint_free(hpriv, ep);
+ ep->hcpriv = NULL;
+
+ /*
+ * if there is no endpoint,
+ * free device
+ */
+ if (!usbhsh_device_has_endpoint(udev))
+ usbhsh_device_free(hpriv, udev);
+}
+
+static int usbhsh_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+ struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd);
+ struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+ struct device *dev = usbhs_priv_to_dev(priv);
+ int roothub_id = 1; /* only 1 root hub */
+
+ /*
+ * does port stat was changed ?
+ * check USB_PORT_STAT_C_xxx << 16
+ */
+ if (usbhsh_port_stat_get(hpriv) & 0xFFFF0000)
+ *buf = (1 << roothub_id);
+ else
+ *buf = 0;
+
+ dev_dbg(dev, "%s (%02x)\n", __func__, *buf);
+
+ return !!(*buf);
+}
+
+static int __usbhsh_hub_hub_feature(struct usbhsh_hpriv *hpriv,
+ u16 typeReq, u16 wValue,
+ u16 wIndex, char *buf, u16 wLength)
+{
+ struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+ struct device *dev = usbhs_priv_to_dev(priv);
+
+ switch (wValue) {
+ case C_HUB_OVER_CURRENT:
+ case C_HUB_LOCAL_POWER:
+ dev_dbg(dev, "%s :: C_HUB_xx\n", __func__);
+ return 0;
+ }
+
+ return -EPIPE;
+}
+
+static int __usbhsh_hub_port_feature(struct usbhsh_hpriv *hpriv,
+ u16 typeReq, u16 wValue,
+ u16 wIndex, char *buf, u16 wLength)
+{
+ struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+ struct device *dev = usbhs_priv_to_dev(priv);
+ int enable = (typeReq == SetPortFeature);
+ int speed, i, timeout = 128;
+ int roothub_id = 1; /* only 1 root hub */
+
+ /* common error */
+ if (wIndex > roothub_id || wLength != 0)
+ return -EPIPE;
+
+ /* check wValue */
+ switch (wValue) {
+ case USB_PORT_FEAT_POWER:
+ usbhs_vbus_ctrl(priv, enable);
+ dev_dbg(dev, "%s :: USB_PORT_FEAT_POWER\n", __func__);
+ break;
+
+ case USB_PORT_FEAT_ENABLE:
+ case USB_PORT_FEAT_SUSPEND:
+ case USB_PORT_FEAT_C_ENABLE:
+ case USB_PORT_FEAT_C_SUSPEND:
+ case USB_PORT_FEAT_C_CONNECTION:
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ case USB_PORT_FEAT_C_RESET:
+ dev_dbg(dev, "%s :: USB_PORT_FEAT_xxx\n", __func__);
+ break;
+
+ case USB_PORT_FEAT_RESET:
+ if (!enable)
+ break;
+
+ usbhsh_port_stat_clear(hpriv,
+ USB_PORT_STAT_HIGH_SPEED |
+ USB_PORT_STAT_LOW_SPEED);
+
+ usbhs_bus_send_reset(priv);
+ msleep(20);
+ usbhs_bus_send_sof_enable(priv);
+
+ for (i = 0; i < timeout ; i++) {
+ switch (usbhs_bus_get_speed(priv)) {
+ case USB_SPEED_LOW:
+ speed = USB_PORT_STAT_LOW_SPEED;
+ goto got_usb_bus_speed;
+ case USB_SPEED_HIGH:
+ speed = USB_PORT_STAT_HIGH_SPEED;
+ goto got_usb_bus_speed;
+ case USB_SPEED_FULL:
+ speed = 0;
+ goto got_usb_bus_speed;
+ }
+
+ msleep(20);
+ }
+ return -EPIPE;
+
+got_usb_bus_speed:
+ usbhsh_port_stat_set(hpriv, speed);
+ usbhsh_port_stat_set(hpriv, USB_PORT_STAT_ENABLE);
+
+ dev_dbg(dev, "%s :: USB_PORT_FEAT_RESET (speed = %d)\n",
+ __func__, speed);
+
+ /* status change is not needed */
+ return 0;
+
+ default:
+ return -EPIPE;
+ }
+
+ /* set/clear status */
+ if (enable)
+ usbhsh_port_stat_set(hpriv, (1 << wValue));
+ else
+ usbhsh_port_stat_clear(hpriv, (1 << wValue));
+
+ return 0;
+}
+
+static int __usbhsh_hub_get_status(struct usbhsh_hpriv *hpriv,
+ u16 typeReq, u16 wValue,
+ u16 wIndex, char *buf, u16 wLength)
+{
+ struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+ struct usb_hub_descriptor *desc = (struct usb_hub_descriptor *)buf;
+ struct device *dev = usbhs_priv_to_dev(priv);
+ int roothub_id = 1; /* only 1 root hub */
+
+ switch (typeReq) {
+ case GetHubStatus:
+ dev_dbg(dev, "%s :: GetHubStatus\n", __func__);
+
+ *buf = 0x00;
+ break;
+
+ case GetPortStatus:
+ if (wIndex != roothub_id)
+ return -EPIPE;
+
+ dev_dbg(dev, "%s :: GetPortStatus\n", __func__);
+ *(__le32 *)buf = cpu_to_le32(usbhsh_port_stat_get(hpriv));
+ break;
+
+ case GetHubDescriptor:
+ desc->bDescriptorType = 0x29;
+ desc->bHubContrCurrent = 0;
+ desc->bNbrPorts = roothub_id;
+ desc->bDescLength = 9;
+ desc->bPwrOn2PwrGood = 0;
+ desc->wHubCharacteristics = cpu_to_le16(0x0011);
+ desc->u.hs.DeviceRemovable[0] = (roothub_id << 1);
+ desc->u.hs.DeviceRemovable[1] = ~0;
+ dev_dbg(dev, "%s :: GetHubDescriptor\n", __func__);
+ break;
+ }
+
+ return 0;
+}
+
+static int usbhsh_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+ u16 wIndex, char *buf, u16 wLength)
+{
+ struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd);
+ struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+ struct device *dev = usbhs_priv_to_dev(priv);
+ int ret = -EPIPE;
+
+ switch (typeReq) {
+
+ /* Hub Feature */
+ case ClearHubFeature:
+ case SetHubFeature:
+ ret = __usbhsh_hub_hub_feature(hpriv, typeReq,
+ wValue, wIndex, buf, wLength);
+ break;
+
+ /* Port Feature */
+ case SetPortFeature:
+ case ClearPortFeature:
+ ret = __usbhsh_hub_port_feature(hpriv, typeReq,
+ wValue, wIndex, buf, wLength);
+ break;
+
+ /* Get status */
+ case GetHubStatus:
+ case GetPortStatus:
+ case GetHubDescriptor:
+ ret = __usbhsh_hub_get_status(hpriv, typeReq,
+ wValue, wIndex, buf, wLength);
+ break;
+ }
+
+ dev_dbg(dev, "typeReq = %x, ret = %d, port_stat = %x\n",
+ typeReq, ret, usbhsh_port_stat_get(hpriv));
+
+ return ret;
+}
+
+static struct hc_driver usbhsh_driver = {
+ .description = usbhsh_hcd_name,
+ .hcd_priv_size = sizeof(struct usbhsh_hpriv),
+
+ /*
+ * generic hardware linkage
+ */
+ .flags = HCD_USB2,
+
+ .start = usbhsh_host_start,
+ .stop = usbhsh_host_stop,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = usbhsh_urb_enqueue,
+ .urb_dequeue = usbhsh_urb_dequeue,
+ .endpoint_disable = usbhsh_endpoint_disable,
+
+ /*
+ * root hub
+ */
+ .hub_status_data = usbhsh_hub_status_data,
+ .hub_control = usbhsh_hub_control,
+};
+
+/*
+ * interrupt functions
+ */
+static int usbhsh_irq_attch(struct usbhs_priv *priv,
+ struct usbhs_irq_state *irq_state)
+{
+ struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv);
+ struct device *dev = usbhs_priv_to_dev(priv);
+
+ dev_dbg(dev, "device attached\n");
+
+ usbhsh_port_stat_set(hpriv, USB_PORT_STAT_CONNECTION);
+ usbhsh_port_stat_set(hpriv, USB_PORT_STAT_C_CONNECTION << 16);
+
+ return 0;
+}
+
+static int usbhsh_irq_dtch(struct usbhs_priv *priv,
+ struct usbhs_irq_state *irq_state)
+{
+ struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv);
+ struct device *dev = usbhs_priv_to_dev(priv);
+
+ dev_dbg(dev, "device detached\n");
+
+ usbhsh_port_stat_clear(hpriv, USB_PORT_STAT_CONNECTION);
+ usbhsh_port_stat_set(hpriv, USB_PORT_STAT_C_CONNECTION << 16);
+
+ return 0;
+}
+
+static int usbhsh_irq_setup_ack(struct usbhs_priv *priv,
+ struct usbhs_irq_state *irq_state)
+{
+ struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv);
+ struct device *dev = usbhs_priv_to_dev(priv);
+
+ dev_dbg(dev, "setup packet OK\n");
+
+ if (unlikely(!hpriv->done))
+ dev_err(dev, "setup ack happen without necessary data\n");
+ else
+ complete(hpriv->done); /* see usbhsh_urb_enqueue() */
+
+ return 0;
+}
+
+static int usbhsh_irq_setup_err(struct usbhs_priv *priv,
+ struct usbhs_irq_state *irq_state)
+{
+ struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv);
+ struct device *dev = usbhs_priv_to_dev(priv);
+
+ dev_dbg(dev, "setup packet Err\n");
+
+ if (unlikely(!hpriv->done))
+ dev_err(dev, "setup err happen without necessary data\n");
+ else
+ complete(hpriv->done); /* see usbhsh_urb_enqueue() */
+
+ return 0;
+}
+
+/*
+ * module start/stop
+ */
+static void usbhsh_pipe_init_for_host(struct usbhs_priv *priv)
+{
+ struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv);
+ struct usbhsh_pipe_info *pipe_info = hpriv->pipe_info;
+ struct usbhs_pipe *pipe;
+ u32 *pipe_type = usbhs_get_dparam(priv, pipe_type);
+ int pipe_size = usbhs_get_dparam(priv, pipe_size);
+ int old_type, dir_in, i;
+
+ /* init all pipe */
+ old_type = USB_ENDPOINT_XFER_CONTROL;
+ for (i = 0; i < pipe_size; i++) {
+ pipe_info[i].usr_cnt = 0;
+
+ /*
+ * data "output" will be finished as soon as possible,
+ * but there is no guaranty at data "input" case.
+ *
+ * "input" needs "standby" pipe.
+ * So, "input" direction pipe > "output" direction pipe
+ * is good idea.
+ *
+ * 1st USB_ENDPOINT_XFER_xxx will be output direction,
+ * and the other will be input direction here.
+ *
+ * ex)
+ * ...
+ * USB_ENDPOINT_XFER_ISOC -> dir out
+ * USB_ENDPOINT_XFER_ISOC -> dir in
+ * USB_ENDPOINT_XFER_BULK -> dir out
+ * USB_ENDPOINT_XFER_BULK -> dir in
+ * USB_ENDPOINT_XFER_BULK -> dir in
+ * ...
+ */
+ dir_in = (pipe_type[i] == old_type);
+ old_type = pipe_type[i];
+
+ if (USB_ENDPOINT_XFER_CONTROL == pipe_type[i]) {
+ pipe = usbhs_dcp_malloc(priv);
+ usbhsh_hpriv_to_dcp(hpriv) = pipe;
+ } else {
+ pipe = usbhs_pipe_malloc(priv,
+ pipe_type[i],
+ dir_in);
+ }
+
+ pipe->mod_private = pipe_info + i;
+ }
+}
+
+static int usbhsh_start(struct usbhs_priv *priv)
+{
+ struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv);
+ struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
+ struct usbhs_mod *mod = usbhs_mod_get_current(priv);
+ struct device *dev = usbhs_priv_to_dev(priv);
+ int ret;
+
+ /* add hcd */
+ ret = usb_add_hcd(hcd, 0, 0);
+ if (ret < 0)
+ return 0;
+
+ /*
+ * pipe initialize and enable DCP
+ */
+ usbhs_pipe_init(priv,
+ usbhsh_dma_map_ctrl);
+ usbhs_fifo_init(priv);
+ usbhsh_pipe_init_for_host(priv);
+
+ /*
+ * system config enble
+ * - HI speed
+ * - host
+ * - usb module
+ */
+ usbhs_sys_hispeed_ctrl(priv, 1);
+ usbhs_sys_host_ctrl(priv, 1);
+ usbhs_sys_usb_ctrl(priv, 1);
+
+ /*
+ * enable irq callback
+ */
+ mod->irq_attch = usbhsh_irq_attch;
+ mod->irq_dtch = usbhsh_irq_dtch;
+ mod->irq_sack = usbhsh_irq_setup_ack;
+ mod->irq_sign = usbhsh_irq_setup_err;
+ usbhs_irq_callback_update(priv, mod);
+
+ dev_dbg(dev, "start host\n");
+
+ return ret;
+}
+
+static int usbhsh_stop(struct usbhs_priv *priv)
+{
+ struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv);
+ struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
+ struct device *dev = usbhs_priv_to_dev(priv);
+
+ usb_remove_hcd(hcd);
+
+ /* disable sys */
+ usbhs_sys_hispeed_ctrl(priv, 0);
+ usbhs_sys_host_ctrl(priv, 0);
+ usbhs_sys_usb_ctrl(priv, 0);
+
+ dev_dbg(dev, "quit host\n");
+
+ return 0;
+}
+
+int __devinit usbhs_mod_host_probe(struct usbhs_priv *priv)
+{
+ struct usbhsh_hpriv *hpriv;
+ struct usb_hcd *hcd;
+ struct usbhsh_pipe_info *pipe_info;
+ struct usbhsh_device *udev;
+ struct device *dev = usbhs_priv_to_dev(priv);
+ int pipe_size = usbhs_get_dparam(priv, pipe_size);
+ int i;
+
+ /* initialize hcd */
+ hcd = usb_create_hcd(&usbhsh_driver, dev, usbhsh_hcd_name);
+ if (!hcd) {
+ dev_err(dev, "Failed to create hcd\n");
+ return -ENOMEM;
+ }
+
+ pipe_info = kzalloc(sizeof(*pipe_info) * pipe_size, GFP_KERNEL);
+ if (!pipe_info) {
+ dev_err(dev, "Could not allocate pipe_info\n");
+ goto usbhs_mod_host_probe_err;
+ }
+
+ /*
+ * CAUTION
+ *
+ * There is no guarantee that it is possible to access usb module here.
+ * Don't accesses to it.
+ * The accesse will be enable after "usbhsh_start"
+ */
+
+ hpriv = usbhsh_hcd_to_hpriv(hcd);
+
+ /*
+ * register itself
+ */
+ usbhs_mod_register(priv, &hpriv->mod, USBHS_HOST);
+
+ /* init hpriv */
+ hpriv->mod.name = "host";
+ hpriv->mod.start = usbhsh_start;
+ hpriv->mod.stop = usbhsh_stop;
+ hpriv->pipe_info = pipe_info;
+ hpriv->pipe_size = pipe_size;
+ hpriv->done = NULL;
+ usbhsh_req_list_init(hpriv);
+ usbhsh_port_stat_init(hpriv);
+
+ /* init all device */
+ usbhsh_for_each_udev_with_dev0(udev, hpriv, i) {
+ udev->usbv = NULL;
+ INIT_LIST_HEAD(&udev->ep_list_head);
+ }
+
+ dev_info(dev, "host probed\n");
+
+ return 0;
+
+usbhs_mod_host_probe_err:
+ usb_put_hcd(hcd);
+
+ return -ENOMEM;
+}
+
+int __devexit usbhs_mod_host_remove(struct usbhs_priv *priv)
+{
+ struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv);
+ struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
+
+ usbhsh_req_list_quit(hpriv);
+
+ usb_put_hcd(hcd);
+
+ return 0;
+}
diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c
index 1b14cae45704..c74389ce2177 100644
--- a/drivers/usb/renesas_usbhs/pipe.c
+++ b/drivers/usb/renesas_usbhs/pipe.c
@@ -29,9 +29,6 @@
#define usbhsp_flags_has(p, f) ((p)->flags & USBHS_PIPE_FLAGS_##f)
#define usbhsp_flags_init(p) do {(p)->flags = 0; } while (0)
-#define usbhsp_type(p) ((p)->pipe_type)
-#define usbhsp_type_is(p, t) ((p)->pipe_type == t)
-
/*
* for debug
*/
@@ -42,28 +39,9 @@ static char *usbhsp_pipe_name[] = {
[USB_ENDPOINT_XFER_ISOC] = "ISO",
};
-/*
- * usb request functions
- */
-void usbhs_usbreq_get_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req)
+char *usbhs_pipe_name(struct usbhs_pipe *pipe)
{
- u16 val;
-
- val = usbhs_read(priv, USBREQ);
- req->bRequest = (val >> 8) & 0xFF;
- req->bRequestType = (val >> 0) & 0xFF;
-
- req->wValue = usbhs_read(priv, USBVAL);
- req->wIndex = usbhs_read(priv, USBINDX);
- req->wLength = usbhs_read(priv, USBLENG);
-}
-
-void usbhs_usbreq_set_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req)
-{
- usbhs_write(priv, USBREQ, (req->bRequest << 8) | req->bRequestType);
- usbhs_write(priv, USBVAL, req->wValue);
- usbhs_write(priv, USBINDX, req->wIndex);
- usbhs_write(priv, USBLENG, req->wLength);
+ return usbhsp_pipe_name[usbhs_pipe_type(pipe)];
}
/*
@@ -106,17 +84,6 @@ static void __usbhsp_pipe_xxx_set(struct usbhs_pipe *pipe,
usbhs_bset(priv, pipe_reg, mask, val);
}
-static u16 __usbhsp_pipe_xxx_get(struct usbhs_pipe *pipe,
- u16 dcp_reg, u16 pipe_reg)
-{
- struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
-
- if (usbhs_pipe_is_dcp(pipe))
- return usbhs_read(priv, dcp_reg);
- else
- return usbhs_read(priv, pipe_reg);
-}
-
/*
* DCPCFG/PIPECFG functions
*/
@@ -144,11 +111,6 @@ static void usbhsp_pipe_maxp_set(struct usbhs_pipe *pipe, u16 mask, u16 val)
__usbhsp_pipe_xxx_set(pipe, DCPMAXP, PIPEMAXP, mask, val);
}
-static u16 usbhsp_pipe_maxp_get(struct usbhs_pipe *pipe)
-{
- return __usbhsp_pipe_xxx_get(pipe, DCPMAXP, PIPEMAXP);
-}
-
/*
* pipe control functions
*/
@@ -303,16 +265,16 @@ static int usbhsp_possible_double_buffer(struct usbhs_pipe *pipe)
/*
* only ISO / BULK pipe can use double buffer
*/
- if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_BULK) ||
- usbhsp_type_is(pipe, USB_ENDPOINT_XFER_ISOC))
+ if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK) ||
+ usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_ISOC))
return 1;
return 0;
}
static u16 usbhsp_setup_pipecfg(struct usbhs_pipe *pipe,
- const struct usb_endpoint_descriptor *desc,
- int is_host)
+ int is_host,
+ int dir_in)
{
u16 type = 0;
u16 bfre = 0;
@@ -341,40 +303,40 @@ static u16 usbhsp_setup_pipecfg(struct usbhs_pipe *pipe,
*/
/* TYPE */
- type = type_array[usbhsp_type(pipe)];
+ type = type_array[usbhs_pipe_type(pipe)];
/* BFRE */
- if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_ISOC) ||
- usbhsp_type_is(pipe, USB_ENDPOINT_XFER_BULK))
+ if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_ISOC) ||
+ usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK))
bfre = 0; /* FIXME */
/* DBLB */
- if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_ISOC) ||
- usbhsp_type_is(pipe, USB_ENDPOINT_XFER_BULK))
+ if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_ISOC) ||
+ usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK))
dblb = (is_double) ? DBLB : 0;
/* CNTMD */
- if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_BULK))
+ if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK))
cntmd = 0; /* FIXME */
/* DIR */
- if (usb_endpoint_dir_in(desc))
+ if (dir_in)
usbhsp_flags_set(pipe, IS_DIR_HOST);
- if ((is_host && usb_endpoint_dir_out(desc)) ||
- (!is_host && usb_endpoint_dir_in(desc)))
+ if ((is_host && !dir_in) ||
+ (!is_host && dir_in))
dir |= DIR_OUT;
if (!dir)
usbhsp_flags_set(pipe, IS_DIR_IN);
/* SHTNAK */
- if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_BULK) &&
+ if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK) &&
!dir)
shtnak = SHTNAK;
/* EPNUM */
- epnum = 0xF & usb_endpoint_num(desc);
+ epnum = 0; /* see usbhs_pipe_config_update() */
return type |
bfre |
@@ -385,19 +347,7 @@ static u16 usbhsp_setup_pipecfg(struct usbhs_pipe *pipe,
epnum;
}
-static u16 usbhsp_setup_pipemaxp(struct usbhs_pipe *pipe,
- const struct usb_endpoint_descriptor *desc,
- int is_host)
-{
- /* host should set DEVSEL */
-
- /* reutn MXPS */
- return PIPE_MAXP_MASK & le16_to_cpu(desc->wMaxPacketSize);
-}
-
-static u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe,
- const struct usb_endpoint_descriptor *desc,
- int is_host)
+static u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe)
{
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
@@ -441,9 +391,9 @@ static u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe,
* INT : 64 byte
* ISOC: 512 byte
*/
- if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_CONTROL))
+ if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_CONTROL))
buff_size = 256;
- else if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_INT))
+ else if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_INT))
buff_size = 64;
else
buff_size = 512;
@@ -453,7 +403,7 @@ static u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe,
/* BUFNMB has been reserved for INT pipe
* see above */
- if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_INT)) {
+ if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_INT)) {
bufnmb = pipe_num - 2;
} else {
bufnmb = info->bufnmb_last;
@@ -473,16 +423,42 @@ static u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe,
(0xff & bufnmb) << 0;
}
+void usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 devsel,
+ u16 epnum, u16 maxp)
+{
+ if (devsel > 0xA) {
+ struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
+ struct device *dev = usbhs_priv_to_dev(priv);
+
+ dev_err(dev, "devsel error %d\n", devsel);
+
+ devsel = 0;
+ }
+
+ usbhsp_pipe_barrier(pipe);
+
+ pipe->maxp = maxp;
+
+ usbhsp_pipe_select(pipe);
+ usbhsp_pipe_maxp_set(pipe, 0xFFFF,
+ (devsel << 12) |
+ maxp);
+
+ if (!usbhs_pipe_is_dcp(pipe))
+ usbhsp_pipe_cfg_set(pipe, 0x000F, epnum);
+}
+
/*
* pipe control
*/
int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe)
{
- u16 mask = usbhs_pipe_is_dcp(pipe) ? DCP_MAXP_MASK : PIPE_MAXP_MASK;
-
- usbhsp_pipe_select(pipe);
-
- return (int)(usbhsp_pipe_maxp_get(pipe) & mask);
+ /*
+ * see
+ * usbhs_pipe_config_update()
+ * usbhs_dcp_malloc()
+ */
+ return pipe->maxp;
}
int usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe)
@@ -495,9 +471,12 @@ int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe)
return usbhsp_flags_has(pipe, IS_DIR_HOST);
}
-void usbhs_pipe_clear_sequence(struct usbhs_pipe *pipe)
+void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int data)
{
- usbhsp_pipectrl_set(pipe, SQCLR, SQCLR);
+ u16 mask = (SQCLR | SQSET);
+ u16 val = (data) ? SQSET : SQCLR;
+
+ usbhsp_pipectrl_set(pipe, mask, val);
}
void usbhs_pipe_clear(struct usbhs_pipe *pipe)
@@ -516,7 +495,7 @@ static struct usbhs_pipe *usbhsp_get_pipe(struct usbhs_priv *priv, u32 type)
*/
pipe = NULL;
usbhs_for_each_pipe_with_dcp(pos, priv, i) {
- if (!usbhsp_type_is(pos, type))
+ if (!usbhs_pipe_type_is(pos, type))
continue;
if (usbhsp_flags_has(pos, IS_USED))
continue;
@@ -538,19 +517,12 @@ static struct usbhs_pipe *usbhsp_get_pipe(struct usbhs_priv *priv, u32 type)
}
void usbhs_pipe_init(struct usbhs_priv *priv,
- void (*done)(struct usbhs_pkt *pkt),
int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map))
{
struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
- struct device *dev = usbhs_priv_to_dev(priv);
struct usbhs_pipe *pipe;
int i;
- if (!done) {
- dev_err(dev, "no done function\n");
- return;
- }
-
/*
* FIXME
*
@@ -565,7 +537,7 @@ void usbhs_pipe_init(struct usbhs_priv *priv,
*/
info->bufnmb_last = 4;
usbhs_for_each_pipe_with_dcp(pipe, priv, i) {
- if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_INT))
+ if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_INT))
info->bufnmb_last++;
usbhsp_flags_init(pipe);
@@ -577,24 +549,23 @@ void usbhs_pipe_init(struct usbhs_priv *priv,
usbhs_pipe_clear(pipe);
}
- info->done = done;
info->dma_map_ctrl = dma_map_ctrl;
}
struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv,
- const struct usb_endpoint_descriptor *desc)
+ int endpoint_type,
+ int dir_in)
{
struct device *dev = usbhs_priv_to_dev(priv);
- struct usbhs_mod *mod = usbhs_mod_get_current(priv);
struct usbhs_pipe *pipe;
- int is_host = usbhs_mod_is_host(priv, mod);
+ int is_host = usbhs_mod_is_host(priv);
int ret;
- u16 pipecfg, pipebuf, pipemaxp;
+ u16 pipecfg, pipebuf;
- pipe = usbhsp_get_pipe(priv, usb_endpoint_type(desc));
+ pipe = usbhsp_get_pipe(priv, endpoint_type);
if (!pipe) {
dev_err(dev, "can't get pipe (%s)\n",
- usbhsp_pipe_name[usb_endpoint_type(desc)]);
+ usbhsp_pipe_name[endpoint_type]);
return NULL;
}
@@ -609,22 +580,25 @@ struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv,
return NULL;
}
- pipecfg = usbhsp_setup_pipecfg(pipe, desc, is_host);
- pipebuf = usbhsp_setup_pipebuff(pipe, desc, is_host);
- pipemaxp = usbhsp_setup_pipemaxp(pipe, desc, is_host);
+ pipecfg = usbhsp_setup_pipecfg(pipe, is_host, dir_in);
+ pipebuf = usbhsp_setup_pipebuff(pipe);
usbhsp_pipe_select(pipe);
usbhsp_pipe_cfg_set(pipe, 0xFFFF, pipecfg);
usbhsp_pipe_buf_set(pipe, 0xFFFF, pipebuf);
- usbhsp_pipe_maxp_set(pipe, 0xFFFF, pipemaxp);
- usbhs_pipe_clear_sequence(pipe);
+ usbhs_pipe_sequence_data0(pipe);
dev_dbg(dev, "enable pipe %d : %s (%s)\n",
usbhs_pipe_number(pipe),
- usbhsp_pipe_name[usb_endpoint_type(desc)],
+ usbhs_pipe_name(pipe),
usbhs_pipe_is_dir_in(pipe) ? "in" : "out");
+ /*
+ * epnum / maxp are still not set to this pipe.
+ * call usbhs_pipe_config_update() after this function !!
+ */
+
return pipe;
}
@@ -651,25 +625,31 @@ struct usbhs_pipe *usbhs_dcp_malloc(struct usbhs_priv *priv)
if (!pipe)
return NULL;
+ INIT_LIST_HEAD(&pipe->list);
+
/*
- * dcpcfg : default
- * dcpmaxp : default
- * pipebuf : nothing to do
+ * call usbhs_pipe_config_update() after this function !!
*/
- usbhsp_pipe_select(pipe);
- usbhs_pipe_clear_sequence(pipe);
- INIT_LIST_HEAD(&pipe->list);
-
return pipe;
}
void usbhs_dcp_control_transfer_done(struct usbhs_pipe *pipe)
{
+ struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
+
WARN_ON(!usbhs_pipe_is_dcp(pipe));
usbhs_pipe_enable(pipe);
- usbhsp_pipectrl_set(pipe, CCPL, CCPL);
+
+ if (!usbhs_mod_is_host(priv)) /* funconly */
+ usbhsp_pipectrl_set(pipe, CCPL, CCPL);
+}
+
+void usbhs_dcp_dir_for_host(struct usbhs_pipe *pipe, int dir_out)
+{
+ usbhsp_pipe_cfg_set(pipe, DIR_OUT,
+ dir_out ? DIR_OUT : 0);
}
/*
@@ -703,7 +683,9 @@ int usbhs_pipe_probe(struct usbhs_priv *priv)
*/
usbhs_for_each_pipe_with_dcp(pipe, priv, i) {
pipe->priv = priv;
- usbhsp_type(pipe) = pipe_type[i] & USB_ENDPOINT_XFERTYPE_MASK;
+
+ usbhs_pipe_type(pipe) =
+ pipe_type[i] & USB_ENDPOINT_XFERTYPE_MASK;
dev_dbg(dev, "pipe %x\t: %s\n",
i, usbhsp_pipe_name[pipe_type[i]]);
diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h
index 41534cb0e734..6334fc644cc0 100644
--- a/drivers/usb/renesas_usbhs/pipe.h
+++ b/drivers/usb/renesas_usbhs/pipe.h
@@ -30,11 +30,15 @@ struct usbhs_pipe {
struct usbhs_fifo *fifo;
struct list_head list;
+ int maxp;
+
u32 flags;
#define USBHS_PIPE_FLAGS_IS_USED (1 << 0)
#define USBHS_PIPE_FLAGS_IS_DIR_IN (1 << 1)
#define USBHS_PIPE_FLAGS_IS_DIR_HOST (1 << 2)
+ struct usbhs_pkt_handle *handler;
+
void *mod_private;
};
@@ -43,7 +47,6 @@ struct usbhs_pipe_info {
int size; /* array size of "pipe" */
int bufnmb_last; /* FIXME : driver needs good allocator */
- void (*done)(struct usbhs_pkt *pkt);
int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map);
};
@@ -67,32 +70,30 @@ struct usbhs_pipe_info {
#define usbhs_priv_to_pipeinfo(pr) (&(pr)->pipe_info)
/*
- * usb request
- */
-void usbhs_usbreq_get_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req);
-void usbhs_usbreq_set_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req);
-
-/*
* pipe control
*/
+char *usbhs_pipe_name(struct usbhs_pipe *pipe);
struct usbhs_pipe
-*usbhs_pipe_malloc(struct usbhs_priv *priv,
- const struct usb_endpoint_descriptor *desc);
+*usbhs_pipe_malloc(struct usbhs_priv *priv, int endpoint_type, int dir_in);
int usbhs_pipe_probe(struct usbhs_priv *priv);
void usbhs_pipe_remove(struct usbhs_priv *priv);
int usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe);
int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe);
void usbhs_pipe_init(struct usbhs_priv *priv,
- void (*done)(struct usbhs_pkt *pkt),
int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map));
int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe);
-void usbhs_pipe_clear_sequence(struct usbhs_pipe *pipe);
void usbhs_pipe_clear(struct usbhs_pipe *pipe);
int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe);
void usbhs_pipe_enable(struct usbhs_pipe *pipe);
void usbhs_pipe_disable(struct usbhs_pipe *pipe);
void usbhs_pipe_stall(struct usbhs_pipe *pipe);
void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo);
+void usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 devsel,
+ u16 epnum, u16 maxp);
+
+#define usbhs_pipe_sequence_data0(pipe) usbhs_pipe_data_sequence(pipe, 0)
+#define usbhs_pipe_sequence_data1(pipe) usbhs_pipe_data_sequence(pipe, 1)
+void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int data);
#define usbhs_pipe_to_priv(p) ((p)->priv)
#define usbhs_pipe_number(p) (int)((p) - (p)->priv->pipe_info.pipe)
@@ -100,10 +101,14 @@ void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo);
#define usbhs_pipe_to_fifo(p) ((p)->fifo)
#define usbhs_pipe_is_busy(p) usbhs_pipe_to_fifo(p)
+#define usbhs_pipe_type(p) ((p)->pipe_type)
+#define usbhs_pipe_type_is(p, t) ((p)->pipe_type == t)
+
/*
* dcp control
*/
struct usbhs_pipe *usbhs_dcp_malloc(struct usbhs_priv *priv);
void usbhs_dcp_control_transfer_done(struct usbhs_pipe *pipe);
+void usbhs_dcp_dir_for_host(struct usbhs_pipe *pipe, int dir_out);
#endif /* RENESAS_USB_PIPE_H */
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index b71e309116a3..677f577c0243 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -252,6 +252,7 @@ config USB_SERIAL_GARMIN
config USB_SERIAL_IPW
tristate "USB IPWireless (3G UMTS TDD) Driver"
+ select USB_SERIAL_WWAN
help
Say Y here if you want to use a IPWireless USB modem such as
the ones supplied by Axity3G/Sentech South Africa.
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 86fbba6336c9..e92cbefc0f88 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -227,7 +227,7 @@
* - All sleeps use a timeout of DIGI_RETRY_TIMEOUT before looping to
* recheck the condition they are sleeping on. This is defensive,
* in case a wake up is lost.
-* - Following Documentation/DocBook/kernel-locking.pdf no spin locks
+* - Following Documentation/DocBook/kernel-locking.tmpl no spin locks
* are held when calling copy_to/from_user or printk.
*/
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 78a2cf9551cc..8fe034d2d3e7 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -73,6 +73,7 @@ struct ftdi_private {
*/
int flags; /* some ASYNC_xxxx flags are supported */
unsigned long last_dtr_rts; /* saved modem control outputs */
+ struct async_icount icount;
wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
char prev_status, diff_status; /* Used for TIOCMIWAIT */
char transmit_empty; /* If transmitter is empty or not */
@@ -101,6 +102,7 @@ static int ftdi_jtag_probe(struct usb_serial *serial);
static int ftdi_mtxorb_hack_setup(struct usb_serial *serial);
static int ftdi_NDI_device_setup(struct usb_serial *serial);
static int ftdi_stmclite_probe(struct usb_serial *serial);
+static int ftdi_8u2232c_probe(struct usb_serial *serial);
static void ftdi_USB_UIRT_setup(struct ftdi_private *priv);
static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv);
@@ -128,6 +130,10 @@ static struct ftdi_sio_quirk ftdi_stmclite_quirk = {
.probe = ftdi_stmclite_probe,
};
+static struct ftdi_sio_quirk ftdi_8u2232c_quirk = {
+ .probe = ftdi_8u2232c_probe,
+};
+
/*
* The 8U232AM has the same API as the sio except for:
* - it can support MUCH higher baudrates; up to:
@@ -178,7 +184,8 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_232RL_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) ,
+ .driver_info = (kernel_ulong_t)&ftdi_8u2232c_quirk },
{ USB_DEVICE(FTDI_VID, FTDI_4232H_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_232H_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) },
@@ -201,6 +208,8 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_XF_640_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_XF_642_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_URBAN_0_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_URBAN_1_PID) },
{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_0_PID) },
@@ -739,6 +748,8 @@ static struct usb_device_id id_table_combined [] = {
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ { USB_DEVICE(FTDI_VID, LMI_LM3S_ICDI_BOARD_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
@@ -879,6 +890,8 @@ static void ftdi_set_termios(struct tty_struct *tty,
static int ftdi_tiocmget(struct tty_struct *tty);
static int ftdi_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
+static int ftdi_get_icount(struct tty_struct *tty,
+ struct serial_icounter_struct *icount);
static int ftdi_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg);
static void ftdi_break_ctl(struct tty_struct *tty, int break_state);
@@ -913,6 +926,7 @@ static struct usb_serial_driver ftdi_sio_device = {
.prepare_write_buffer = ftdi_prepare_write_buffer,
.tiocmget = ftdi_tiocmget,
.tiocmset = ftdi_tiocmset,
+ .get_icount = ftdi_get_icount,
.ioctl = ftdi_ioctl,
.set_termios = ftdi_set_termios,
.break_ctl = ftdi_break_ctl,
@@ -1480,7 +1494,7 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port)
}
/* set max packet size based on descriptor */
- priv->max_packet_size = le16_to_cpu(ep_desc->wMaxPacketSize);
+ priv->max_packet_size = usb_endpoint_maxp(ep_desc);
dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size);
}
@@ -1640,6 +1654,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
kref_init(&priv->kref);
mutex_init(&priv->cfg_lock);
+ memset(&priv->icount, 0x00, sizeof(priv->icount));
init_waitqueue_head(&priv->delta_msr_wait);
priv->flags = ASYNC_LOW_LATENCY;
@@ -1737,6 +1752,18 @@ static int ftdi_jtag_probe(struct usb_serial *serial)
return 0;
}
+static int ftdi_8u2232c_probe(struct usb_serial *serial)
+{
+ struct usb_device *udev = serial->dev;
+
+ dbg("%s", __func__);
+
+ if (strcmp(udev->manufacturer, "CALAO Systems") == 0)
+ return ftdi_jtag_probe(serial);
+
+ return 0;
+}
+
/*
* First and second port on STMCLiteadaptors is reserved for JTAG interface
* and the forth port for pio
@@ -1891,6 +1918,7 @@ static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
c = kfifo_out(&port->write_fifo, &buffer[i + 1], len);
if (!c)
break;
+ priv->icount.tx += c;
buffer[i] = (c << 2) + 1;
count += c + 1;
}
@@ -1898,6 +1926,7 @@ static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
} else {
count = kfifo_out_locked(&port->write_fifo, dest, size,
&port->lock);
+ priv->icount.tx += count;
}
return count;
@@ -1925,6 +1954,14 @@ static int ftdi_process_packet(struct tty_struct *tty,
N.B. packet may be processed more than once, but differences
are only processed once. */
status = packet[0] & FTDI_STATUS_B0_MASK;
+ if (status & FTDI_RS0_CTS)
+ priv->icount.cts++;
+ if (status & FTDI_RS0_DSR)
+ priv->icount.dsr++;
+ if (status & FTDI_RS0_RI)
+ priv->icount.rng++;
+ if (status & FTDI_RS0_RLSD)
+ priv->icount.dcd++;
if (status != priv->prev_status) {
priv->diff_status |= status ^ priv->prev_status;
wake_up_interruptible(&priv->delta_msr_wait);
@@ -1937,15 +1974,20 @@ static int ftdi_process_packet(struct tty_struct *tty,
* over framing errors */
if (packet[1] & FTDI_RS_BI) {
flag = TTY_BREAK;
+ priv->icount.brk++;
usb_serial_handle_break(port);
} else if (packet[1] & FTDI_RS_PE) {
flag = TTY_PARITY;
+ priv->icount.parity++;
} else if (packet[1] & FTDI_RS_FE) {
flag = TTY_FRAME;
+ priv->icount.frame++;
}
/* Overrun is special, not associated with a char */
- if (packet[1] & FTDI_RS_OE)
+ if (packet[1] & FTDI_RS_OE) {
+ priv->icount.overrun++;
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ }
}
/* save if the transmitter is empty or not */
@@ -1957,6 +1999,7 @@ static int ftdi_process_packet(struct tty_struct *tty,
len -= 2;
if (!len)
return 0; /* status only */
+ priv->icount.rx += len;
ch = packet + 2;
if (port->port.console && port->sysrq) {
@@ -2259,11 +2302,34 @@ static int ftdi_tiocmset(struct tty_struct *tty,
return update_mctrl(port, set, clear);
}
+static int ftdi_get_icount(struct tty_struct *tty,
+ struct serial_icounter_struct *icount)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ struct async_icount *ic = &priv->icount;
+
+ icount->cts = ic->cts;
+ icount->dsr = ic->dsr;
+ icount->rng = ic->rng;
+ icount->dcd = ic->dcd;
+ icount->tx = ic->tx;
+ icount->rx = ic->rx;
+ icount->frame = ic->frame;
+ icount->parity = ic->parity;
+ icount->overrun = ic->overrun;
+ icount->brk = ic->brk;
+ icount->buf_overrun = ic->buf_overrun;
+ return 0;
+}
+
static int ftdi_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = tty->driver_data;
struct ftdi_private *priv = usb_get_serial_port_data(port);
+ struct async_icount cnow;
+ struct async_icount cprev;
dbg("%s cmd 0x%04x", __func__, cmd);
@@ -2283,41 +2349,30 @@ static int ftdi_ioctl(struct tty_struct *tty,
* - mask passed in arg for lines of interest
* (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
* Caller should use TIOCGICOUNT to see which one it was.
- * (except that the driver doesn't support it !)
*
* This code is borrowed from linux/drivers/char/serial.c
*/
case TIOCMIWAIT:
- while (priv != NULL) {
+ cprev = priv->icount;
+ while (1) {
interruptible_sleep_on(&priv->delta_msr_wait);
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;
- else {
- char diff = priv->diff_status;
-
- if (diff == 0)
- return -EIO; /* no change => error */
-
- /* Consume all events */
- priv->diff_status = 0;
-
- /* Return 0 if caller wanted to know about
- these bits */
- if (((arg & TIOCM_RNG) && (diff & FTDI_RS0_RI)) ||
- ((arg & TIOCM_DSR) && (diff & FTDI_RS0_DSR)) ||
- ((arg & TIOCM_CD) && (diff & FTDI_RS0_RLSD)) ||
- ((arg & TIOCM_CTS) && (diff & FTDI_RS0_CTS))) {
- return 0;
- }
- /*
- * Otherwise caller can't care less about what
- * happened,and so we continue to wait for more
- * events.
- */
+ cnow = priv->icount;
+ if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+ cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+ return -EIO; /* no change => error */
+ if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
+ return 0;
}
+ cprev = cnow;
}
- return 0;
+ /* not reached */
+ break;
case TIOCSERGETLSR:
return get_lsr_info(port, (struct serial_struct __user *)arg);
break;
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index bf5227ad3ef7..571fa96b49c7 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -54,6 +54,7 @@
/* FTDI 2332C Dual channel device, side A=245 FIFO (JTAG), Side B=RS232 UART */
#define LMI_LM3S_DEVEL_BOARD_PID 0xbcd8
#define LMI_LM3S_EVAL_BOARD_PID 0xbcd9
+#define LMI_LM3S_ICDI_BOARD_PID 0xbcda
#define FTDI_TURTELIZER_PID 0xBDC8 /* JTAG/RS-232 adapter by egnite GmbH */
@@ -420,9 +421,11 @@
#define PROTEGO_SPECIAL_4 0xFC73 /* special/unknown device */
/*
- * DSS-20 Sync Station for Sony Ericsson P800
+ * Sony Ericsson product ids
*/
-#define FTDI_DSS20_PID 0xFC82
+#define FTDI_DSS20_PID 0xFC82 /* DSS-20 Sync Station for Sony Ericsson P800 */
+#define FTDI_URBAN_0_PID 0xFC8A /* Sony Ericsson Urban, uart #0 */
+#define FTDI_URBAN_1_PID 0xFC8B /* Sony Ericsson Urban, uart #1 */
/* www.irtrans.de device */
#define FTDI_IRTRANS_PID 0xFC60 /* Product Id */
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index abf095be5753..2ee807523f53 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -3042,7 +3042,7 @@ static int edge_startup(struct usb_serial *serial)
endpoint = &serial->interface->altsetting[0].
endpoint[i].desc;
- buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ buffer_size = usb_endpoint_maxp(endpoint);
if (!interrupt_in_found &&
(usb_endpoint_is_int_in(endpoint))) {
/* we found a interrupt in endpoint */
@@ -3107,7 +3107,7 @@ static int edge_startup(struct usb_serial *serial)
usb_rcvbulkpipe(dev,
endpoint->bEndpointAddress),
edge_serial->bulk_in_buffer,
- le16_to_cpu(endpoint->wMaxPacketSize),
+ usb_endpoint_maxp(endpoint),
edge_bulk_in_callback,
edge_serial);
bulk_in_found = true;
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index ca77e88836bd..5170799d6e94 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -47,6 +47,7 @@
#include <linux/usb.h>
#include <linux/usb/serial.h>
#include <linux/uaccess.h>
+#include "usb-wwan.h"
/*
* Version Information
@@ -185,7 +186,7 @@ static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port)
/*--2: Start reading from the device */
dbg("%s: setting up bulk read callback", __func__);
- usb_serial_generic_open(tty, port);
+ usb_wwan_open(tty, port);
/*--3: Tell the modem to open the floodgates on the rx bulk channel */
dbg("%s:asking modem for RxRead (RXBULK_ON)", __func__);
@@ -219,6 +220,29 @@ static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port)
return 0;
}
+/* fake probe - only to allocate data structures */
+static int ipw_probe(struct usb_serial *serial, const struct usb_device_id *id)
+{
+ struct usb_wwan_intf_private *data;
+
+ data = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ spin_lock_init(&data->susp_lock);
+ usb_set_serial_data(serial, data);
+ return 0;
+}
+
+static void ipw_release(struct usb_serial *serial)
+{
+ struct usb_wwan_intf_private *data = usb_get_serial_data(serial);
+
+ usb_wwan_release(serial);
+ usb_set_serial_data(serial, NULL);
+ kfree(data);
+}
+
static void ipw_dtr_rts(struct usb_serial_port *port, int on)
{
struct usb_device *dev = port->serial->dev;
@@ -285,7 +309,7 @@ static void ipw_close(struct usb_serial_port *port)
dev_err(&port->dev,
"Disabling bulk RxRead failed (error = %d)\n", result);
- usb_serial_generic_close(port);
+ usb_wwan_close(port);
}
static struct usb_serial_driver ipw_device = {
@@ -297,9 +321,14 @@ static struct usb_serial_driver ipw_device = {
.usb_driver = &usb_ipw_driver,
.id_table = usb_ipw_ids,
.num_ports = 1,
+ .disconnect = usb_wwan_disconnect,
.open = ipw_open,
.close = ipw_close,
+ .probe = ipw_probe,
+ .attach = usb_wwan_startup,
+ .release = ipw_release,
.dtr_rts = ipw_dtr_rts,
+ .write = usb_wwan_write,
};
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 40abedbc5943..3524a105d042 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -2006,7 +2006,6 @@ static int mos7720_ioctl(struct tty_struct *tty,
dbg("%s (%d) TIOCSERGETLSR", __func__, port->number);
return get_lsr_info(tty, mos7720_port,
(unsigned int __user *)arg);
- return 0;
/* FIXME: These should be using the mode methods */
case TIOCMBIS:
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 7b50aa122752..c72abd524983 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -2263,7 +2263,6 @@ static int mos7840_ioctl(struct tty_struct *tty,
case TIOCSERGETLSR:
dbg("%s (%d) TIOCSERGETLSR", __func__, port->number);
return mos7840_get_lsr_info(tty, argp);
- return 0;
case TIOCGSERIAL:
dbg("%s (%d) TIOCGSERIAL", __func__, port->number);
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
index 96423f3c8ef3..c248a9147439 100644
--- a/drivers/usb/serial/opticon.c
+++ b/drivers/usb/serial/opticon.c
@@ -523,7 +523,7 @@ static int opticon_startup(struct usb_serial *serial)
goto error;
}
- priv->buffer_size = le16_to_cpu(endpoint->wMaxPacketSize) * 2;
+ priv->buffer_size = usb_endpoint_maxp(endpoint) * 2;
priv->bulk_in_buffer = kmalloc(priv->buffer_size, GFP_KERNEL);
if (!priv->bulk_in_buffer) {
dev_err(&priv->udev->dev, "out of memory\n");
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 815656198914..89ae1f65e1b1 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -148,6 +148,8 @@ static void option_instat_callback(struct urb *urb);
#define HUAWEI_PRODUCT_K4505 0x1464
#define HUAWEI_PRODUCT_K3765 0x1465
#define HUAWEI_PRODUCT_E14AC 0x14AC
+#define HUAWEI_PRODUCT_K3806 0x14AE
+#define HUAWEI_PRODUCT_K4605 0x14C6
#define HUAWEI_PRODUCT_K3770 0x14C9
#define HUAWEI_PRODUCT_K3771 0x14CA
#define HUAWEI_PRODUCT_K4510 0x14CB
@@ -416,6 +418,56 @@ static void option_instat_callback(struct urb *urb);
#define SAMSUNG_VENDOR_ID 0x04e8
#define SAMSUNG_PRODUCT_GT_B3730 0x6889
+/* YUGA products www.yuga-info.com*/
+#define YUGA_VENDOR_ID 0x257A
+#define YUGA_PRODUCT_CEM600 0x1601
+#define YUGA_PRODUCT_CEM610 0x1602
+#define YUGA_PRODUCT_CEM500 0x1603
+#define YUGA_PRODUCT_CEM510 0x1604
+#define YUGA_PRODUCT_CEM800 0x1605
+#define YUGA_PRODUCT_CEM900 0x1606
+
+#define YUGA_PRODUCT_CEU818 0x1607
+#define YUGA_PRODUCT_CEU816 0x1608
+#define YUGA_PRODUCT_CEU828 0x1609
+#define YUGA_PRODUCT_CEU826 0x160A
+#define YUGA_PRODUCT_CEU518 0x160B
+#define YUGA_PRODUCT_CEU516 0x160C
+#define YUGA_PRODUCT_CEU528 0x160D
+#define YUGA_PRODUCT_CEU526 0x160F
+
+#define YUGA_PRODUCT_CWM600 0x2601
+#define YUGA_PRODUCT_CWM610 0x2602
+#define YUGA_PRODUCT_CWM500 0x2603
+#define YUGA_PRODUCT_CWM510 0x2604
+#define YUGA_PRODUCT_CWM800 0x2605
+#define YUGA_PRODUCT_CWM900 0x2606
+
+#define YUGA_PRODUCT_CWU718 0x2607
+#define YUGA_PRODUCT_CWU716 0x2608
+#define YUGA_PRODUCT_CWU728 0x2609
+#define YUGA_PRODUCT_CWU726 0x260A
+#define YUGA_PRODUCT_CWU518 0x260B
+#define YUGA_PRODUCT_CWU516 0x260C
+#define YUGA_PRODUCT_CWU528 0x260D
+#define YUGA_PRODUCT_CWU526 0x260F
+
+#define YUGA_PRODUCT_CLM600 0x2601
+#define YUGA_PRODUCT_CLM610 0x2602
+#define YUGA_PRODUCT_CLM500 0x2603
+#define YUGA_PRODUCT_CLM510 0x2604
+#define YUGA_PRODUCT_CLM800 0x2605
+#define YUGA_PRODUCT_CLM900 0x2606
+
+#define YUGA_PRODUCT_CLU718 0x2607
+#define YUGA_PRODUCT_CLU716 0x2608
+#define YUGA_PRODUCT_CLU728 0x2609
+#define YUGA_PRODUCT_CLU726 0x260A
+#define YUGA_PRODUCT_CLU518 0x260B
+#define YUGA_PRODUCT_CLU516 0x260C
+#define YUGA_PRODUCT_CLU528 0x260D
+#define YUGA_PRODUCT_CLU526 0x260F
+
/* some devices interfaces need special handling due to a number of reasons */
enum option_blacklist_reason {
OPTION_BLACKLIST_NONE = 0,
@@ -423,31 +475,54 @@ enum option_blacklist_reason {
OPTION_BLACKLIST_RESERVED_IF = 2
};
+#define MAX_BL_NUM 8
struct option_blacklist_info {
- const u32 infolen; /* number of interface numbers on blacklist */
- const u8 *ifaceinfo; /* pointer to the array holding the numbers */
- enum option_blacklist_reason reason;
+ /* bitfield of interface numbers for OPTION_BLACKLIST_SENDSETUP */
+ const unsigned long sendsetup;
+ /* bitfield of interface numbers for OPTION_BLACKLIST_RESERVED_IF */
+ const unsigned long reserved;
};
-static const u8 four_g_w14_no_sendsetup[] = { 0, 1 };
static const struct option_blacklist_info four_g_w14_blacklist = {
- .infolen = ARRAY_SIZE(four_g_w14_no_sendsetup),
- .ifaceinfo = four_g_w14_no_sendsetup,
- .reason = OPTION_BLACKLIST_SENDSETUP
+ .sendsetup = BIT(0) | BIT(1),
};
-static const u8 alcatel_x200_no_sendsetup[] = { 0, 1 };
static const struct option_blacklist_info alcatel_x200_blacklist = {
- .infolen = ARRAY_SIZE(alcatel_x200_no_sendsetup),
- .ifaceinfo = alcatel_x200_no_sendsetup,
- .reason = OPTION_BLACKLIST_SENDSETUP
+ .sendsetup = BIT(0) | BIT(1),
+};
+
+static const struct option_blacklist_info zte_0037_blacklist = {
+ .sendsetup = BIT(0) | BIT(1),
};
-static const u8 zte_k3765_z_no_sendsetup[] = { 0, 1, 2 };
static const struct option_blacklist_info zte_k3765_z_blacklist = {
- .infolen = ARRAY_SIZE(zte_k3765_z_no_sendsetup),
- .ifaceinfo = zte_k3765_z_no_sendsetup,
- .reason = OPTION_BLACKLIST_SENDSETUP
+ .sendsetup = BIT(0) | BIT(1) | BIT(2),
+ .reserved = BIT(4),
+};
+
+static const struct option_blacklist_info huawei_cdc12_blacklist = {
+ .reserved = BIT(1) | BIT(2),
+};
+
+static const struct option_blacklist_info net_intf1_blacklist = {
+ .reserved = BIT(1),
+};
+
+static const struct option_blacklist_info net_intf3_blacklist = {
+ .reserved = BIT(3),
+};
+
+static const struct option_blacklist_info net_intf4_blacklist = {
+ .reserved = BIT(4),
+};
+
+static const struct option_blacklist_info net_intf5_blacklist = {
+ .reserved = BIT(5),
+};
+
+static const struct option_blacklist_info zte_mf626_blacklist = {
+ .sendsetup = BIT(0) | BIT(1),
+ .reserved = BIT(4),
};
static const struct usb_device_id option_ids[] = {
@@ -547,10 +622,15 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143D, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143E, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143F, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ETS1220, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3806, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x31) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x32) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3771, 0xff, 0x02, 0x31) },
@@ -651,7 +731,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864G) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0003, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0004, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0005, 0xff, 0xff, 0xff) },
@@ -666,51 +747,62 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000f, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0010, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0011, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0012, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0012, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0013, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0014, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0016, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0017, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0017, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0018, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0019, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0020, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0021, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0021, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0022, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0023, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0024, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0025, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0025, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
/* { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0026, 0xff, 0xff, 0xff) }, */
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0028, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0029, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0030, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626, 0xff,
- 0xff, 0xff), .driver_info = (kernel_ulong_t)&four_g_w14_blacklist },
+ 0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_mf626_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0032, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0033, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0034, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0037, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0037, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&zte_0037_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0038, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0039, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0040, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0042, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0042, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0043, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0044, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0048, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0049, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0049, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0050, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0051, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0052, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0052, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
/* { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0053, 0xff, 0xff, 0xff) }, */
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0054, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0055, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0055, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0056, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0057, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0058, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0058, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0059, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0061, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0062, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0063, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0063, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0064, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0065, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0066, 0xff, 0xff, 0xff) },
@@ -725,11 +817,13 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0083, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0086, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0087, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0104, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0104, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0105, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0106, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0108, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0113, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0113, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0117, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0118, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0121, 0xff, 0xff, 0xff) },
@@ -1005,6 +1099,48 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */
{ USB_DEVICE(ONDA_VENDOR_ID, ONDA_MT825UP) }, /* ONDA MT825UP modem */
{ USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730 LTE USB modem.*/
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM600) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM610) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM500) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM510) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM800) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM900) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU818) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU816) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU828) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU826) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU518) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU516) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU528) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU526) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM600) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM610) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM500) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM510) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM800) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM900) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU718) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU716) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU728) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU726) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU518) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU516) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU528) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU526) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM600) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM610) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM500) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM510) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM800) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM900) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU718) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU716) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU728) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU726) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU518) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU516) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU528) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU526) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
@@ -1118,10 +1254,35 @@ static void __exit option_exit(void)
module_init(option_init);
module_exit(option_exit);
+static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason,
+ const struct option_blacklist_info *blacklist)
+{
+ unsigned long num;
+ const unsigned long *intf_list;
+
+ if (blacklist) {
+ if (reason == OPTION_BLACKLIST_SENDSETUP)
+ intf_list = &blacklist->sendsetup;
+ else if (reason == OPTION_BLACKLIST_RESERVED_IF)
+ intf_list = &blacklist->reserved;
+ else {
+ BUG_ON(reason);
+ return false;
+ }
+
+ for_each_set_bit(num, intf_list, MAX_BL_NUM + 1) {
+ if (num == ifnum)
+ return true;
+ }
+ }
+ return false;
+}
+
static int option_probe(struct usb_serial *serial,
const struct usb_device_id *id)
{
struct usb_wwan_intf_private *data;
+
/* D-Link DWM 652 still exposes CD-Rom emulation interface in modem mode */
if (serial->dev->descriptor.idVendor == DLINK_VENDOR_ID &&
serial->dev->descriptor.idProduct == DLINK_PRODUCT_DWM_652 &&
@@ -1134,12 +1295,14 @@ static int option_probe(struct usb_serial *serial,
serial->interface->cur_altsetting->desc.bInterfaceClass != 0xff)
return -ENODEV;
- /* Don't bind network interfaces on Huawei K3765 & K4505 */
- if (serial->dev->descriptor.idVendor == HUAWEI_VENDOR_ID &&
- (serial->dev->descriptor.idProduct == HUAWEI_PRODUCT_K3765 ||
- serial->dev->descriptor.idProduct == HUAWEI_PRODUCT_K4505) &&
- serial->interface->cur_altsetting->desc.bInterfaceNumber == 1)
- return -ENODEV;
+ /* Don't bind reserved interfaces (like network ones) which often have
+ * the same class/subclass/protocol as the serial interfaces. Look at
+ * the Windows driver .INF files for reserved interface numbers.
+ */
+ if (is_blacklisted(
+ serial->interface->cur_altsetting->desc.bInterfaceNumber,
+ OPTION_BLACKLIST_RESERVED_IF,
+ (const struct option_blacklist_info *) id->driver_info))
/* Don't bind network interface on Samsung GT-B3730, it is handled by a separate module */
if (serial->dev->descriptor.idVendor == SAMSUNG_VENDOR_ID &&
@@ -1148,7 +1311,6 @@ static int option_probe(struct usb_serial *serial,
return -ENODEV;
data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL);
-
if (!data)
return -ENOMEM;
data->send_setup = option_send_setup;
@@ -1157,23 +1319,6 @@ static int option_probe(struct usb_serial *serial,
return 0;
}
-static enum option_blacklist_reason is_blacklisted(const u8 ifnum,
- const struct option_blacklist_info *blacklist)
-{
- const u8 *info;
- int i;
-
- if (blacklist) {
- info = blacklist->ifaceinfo;
-
- for (i = 0; i < blacklist->infolen; i++) {
- if (info[i] == ifnum)
- return blacklist->reason;
- }
- }
- return OPTION_BLACKLIST_NONE;
-}
-
static void option_instat_callback(struct urb *urb)
{
int err;
@@ -1245,9 +1390,8 @@ static int option_send_setup(struct usb_serial_port *port)
int val = 0;
dbg("%s", __func__);
- if (is_blacklisted(ifNum,
- (struct option_blacklist_info *) intfdata->private)
- == OPTION_BLACKLIST_SENDSETUP) {
+ if (is_blacklisted(ifNum, OPTION_BLACKLIST_SENDSETUP,
+ (struct option_blacklist_info *) intfdata->private)) {
dbg("No send_setup on blacklisted interface #%d\n", ifNum);
return -EIO;
}
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 1d33260de014..9083d1e616b4 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -92,6 +92,7 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
{ USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
{ USB_DEVICE(WINCHIPHEAD_VENDOR_ID, WINCHIPHEAD_USBSER_PRODUCT_ID) },
+ { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) },
{ } /* Terminating entry */
};
@@ -360,9 +361,6 @@ static void pl2303_set_termios(struct tty_struct *tty,
tmp >>= 2;
buf[1] <<= 1;
}
- if (tmp > 256) {
- tmp %= 256;
- }
buf[0] = tmp;
}
}
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index ca0d237683b3..3d10d7f02072 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -148,3 +148,8 @@
/* WinChipHead USB->RS 232 adapter */
#define WINCHIPHEAD_VENDOR_ID 0x4348
#define WINCHIPHEAD_USBSER_PRODUCT_ID 0x5523
+
+/* SMART USB Serial Adapter */
+#define SMART_VENDOR_ID 0x0b8c
+#define SMART_PRODUCT_ID 0x2303
+
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index aeccc7f0a93c..b9bb24729c99 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -28,6 +28,7 @@ static const struct usb_device_id id_table[] = {
{USB_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */
{USB_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */
{USB_DEVICE(0x03f0, 0x201d)}, /* HP un2400 Gobi QDL Device */
+ {USB_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */
{USB_DEVICE(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */
{USB_DEVICE(0x04da, 0x250c)}, /* Panasonic Gobi QDL device */
{USB_DEVICE(0x413c, 0x8172)}, /* Dell Gobi Modem device */
@@ -84,6 +85,7 @@ static const struct usb_device_id id_table[] = {
{USB_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */
{USB_DEVICE(0x05c6, 0x9204)}, /* Gobi 2000 QDL device */
{USB_DEVICE(0x05c6, 0x9205)}, /* Gobi 2000 Modem device */
+ {USB_DEVICE(0x1199, 0x9013)}, /* Sierra Wireless Gobi 3000 Modem device (MC8355) */
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, id_table);
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index d5d136a53b61..b18179bda0d8 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -1009,7 +1009,7 @@ static int sierra_suspend(struct usb_serial *serial, pm_message_t message)
struct sierra_intf_private *intfdata;
int b;
- if (message.event & PM_EVENT_AUTO) {
+ if (PMSG_IS_AUTO(message)) {
intfdata = serial->private;
spin_lock_irq(&intfdata->susp_lock);
b = intfdata->in_flight;
diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c
index d9457bd4fe10..7096f799b071 100644
--- a/drivers/usb/serial/symbolserial.c
+++ b/drivers/usb/serial/symbolserial.c
@@ -226,7 +226,7 @@ static int symbol_startup(struct usb_serial *serial)
goto error;
}
- priv->buffer_size = le16_to_cpu(endpoint->wMaxPacketSize) * 2;
+ priv->buffer_size = usb_endpoint_maxp(endpoint) * 2;
priv->int_buffer = kmalloc(priv->buffer_size, GFP_KERNEL);
if (!priv->int_buffer) {
dev_err(&priv->udev->dev, "out of memory\n");
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 1c031309ab25..cc274fdf2627 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -912,7 +912,7 @@ int usb_serial_probe(struct usb_interface *interface,
goto probe_error;
}
buffer_size = max_t(int, serial->type->bulk_in_size,
- le16_to_cpu(endpoint->wMaxPacketSize));
+ usb_endpoint_maxp(endpoint));
port->bulk_in_size = buffer_size;
port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
@@ -942,7 +942,7 @@ int usb_serial_probe(struct usb_interface *interface,
goto probe_error;
buffer_size = serial->type->bulk_out_size;
if (!buffer_size)
- buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ buffer_size = usb_endpoint_maxp(endpoint);
port->bulk_out_size = buffer_size;
port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
port->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
@@ -990,7 +990,7 @@ int usb_serial_probe(struct usb_interface *interface,
"No free urbs available\n");
goto probe_error;
}
- buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ buffer_size = usb_endpoint_maxp(endpoint);
port->interrupt_in_endpointAddress =
endpoint->bEndpointAddress;
port->interrupt_in_buffer = kmalloc(buffer_size,
@@ -1021,7 +1021,7 @@ int usb_serial_probe(struct usb_interface *interface,
"No free urbs available\n");
goto probe_error;
}
- buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ buffer_size = usb_endpoint_maxp(endpoint);
port->interrupt_out_size = buffer_size;
port->interrupt_out_endpointAddress =
endpoint->bEndpointAddress;
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index e4fad5e643d7..d555ca9567b8 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -651,7 +651,7 @@ int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message)
dbg("%s entered", __func__);
- if (message.event & PM_EVENT_AUTO) {
+ if (PMSG_IS_AUTO(message)) {
spin_lock_irq(&intfdata->susp_lock);
b = intfdata->in_flight;
spin_unlock_irq(&intfdata->susp_lock);
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index bedc4b9f2ac4..fe2d803a6347 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -42,7 +42,7 @@ config USB_STORAGE_REALTEK
config REALTEK_AUTOPM
bool "Realtek Card Reader autosuspend support"
- depends on USB_STORAGE_REALTEK && CONFIG_PM_RUNTIME
+ depends on USB_STORAGE_REALTEK && PM_RUNTIME
default y
config USB_STORAGE_DATAFAB
diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c
index 34adc4b42ceb..0ce5f79197e7 100644
--- a/drivers/usb/storage/realtek_cr.c
+++ b/drivers/usb/storage/realtek_cr.c
@@ -25,7 +25,6 @@
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/kernel.h>
-#include <linux/version.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -293,6 +292,52 @@ static int rts51x_bulk_transport(struct us_data *us, u8 lun,
return USB_STOR_TRANSPORT_ERROR;
}
+static int rts51x_bulk_transport_special(struct us_data *us, u8 lun,
+ u8 *cmd, int cmd_len, u8 *buf, int buf_len,
+ enum dma_data_direction dir, int *act_len)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
+ int result;
+ unsigned int cswlen;
+ unsigned int cbwlen = US_BULK_CB_WRAP_LEN;
+
+ /* set up the command wrapper */
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = cpu_to_le32(buf_len);
+ bcb->Flags = (dir == DMA_FROM_DEVICE) ? 1 << 7 : 0;
+ bcb->Tag = ++us->tag;
+ bcb->Lun = lun;
+ bcb->Length = cmd_len;
+
+ /* copy the command payload */
+ memset(bcb->CDB, 0, sizeof(bcb->CDB));
+ memcpy(bcb->CDB, cmd, bcb->Length);
+
+ /* send it to out endpoint */
+ result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+ bcb, cbwlen, NULL);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ /* DATA STAGE */
+ /* send/receive data payload, if there is any */
+
+ if (buf && buf_len) {
+ unsigned int pipe = (dir == DMA_FROM_DEVICE) ?
+ us->recv_bulk_pipe : us->send_bulk_pipe;
+ result = usb_stor_bulk_transfer_buf(us, pipe,
+ buf, buf_len, NULL);
+ if (result == USB_STOR_XFER_ERROR)
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* get CSW for device status */
+ result = usb_bulk_msg(us->pusb_dev, us->recv_bulk_pipe, bcs,
+ US_BULK_CS_WRAP_LEN, &cswlen, 250);
+ return result;
+}
+
/* Determine what the maximum LUN supported is */
static int rts51x_get_max_lun(struct us_data *us)
{
@@ -320,6 +365,11 @@ static int rts51x_read_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
{
int retval;
u8 cmnd[12] = { 0 };
+ u8 *buf;
+
+ buf = kmalloc(len, GFP_NOIO);
+ if (buf == NULL)
+ return USB_STOR_TRANSPORT_ERROR;
US_DEBUGP("%s, addr = 0x%x, len = %d\n", __func__, addr, len);
@@ -331,10 +381,14 @@ static int rts51x_read_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
cmnd[5] = (u8) len;
retval = rts51x_bulk_transport(us, 0, cmnd, 12,
- data, len, DMA_FROM_DEVICE, NULL);
- if (retval != USB_STOR_TRANSPORT_GOOD)
+ buf, len, DMA_FROM_DEVICE, NULL);
+ if (retval != USB_STOR_TRANSPORT_GOOD) {
+ kfree(buf);
return -EIO;
+ }
+ memcpy(data, buf, len);
+ kfree(buf);
return 0;
}
@@ -342,6 +396,12 @@ static int rts51x_write_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
{
int retval;
u8 cmnd[12] = { 0 };
+ u8 *buf;
+
+ buf = kmalloc(len, GFP_NOIO);
+ if (buf == NULL)
+ return USB_STOR_TRANSPORT_ERROR;
+ memcpy(buf, data, len);
US_DEBUGP("%s, addr = 0x%x, len = %d\n", __func__, addr, len);
@@ -353,7 +413,8 @@ static int rts51x_write_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
cmnd[5] = (u8) len;
retval = rts51x_bulk_transport(us, 0, cmnd, 12,
- data, len, DMA_TO_DEVICE, NULL);
+ buf, len, DMA_TO_DEVICE, NULL);
+ kfree(buf);
if (retval != USB_STOR_TRANSPORT_GOOD)
return -EIO;
@@ -365,6 +426,11 @@ static int rts51x_read_status(struct us_data *us,
{
int retval;
u8 cmnd[12] = { 0 };
+ u8 *buf;
+
+ buf = kmalloc(len, GFP_NOIO);
+ if (buf == NULL)
+ return USB_STOR_TRANSPORT_ERROR;
US_DEBUGP("%s, lun = %d\n", __func__, lun);
@@ -372,10 +438,14 @@ static int rts51x_read_status(struct us_data *us,
cmnd[1] = 0x09;
retval = rts51x_bulk_transport(us, lun, cmnd, 12,
- status, len, DMA_FROM_DEVICE, actlen);
- if (retval != USB_STOR_TRANSPORT_GOOD)
+ buf, len, DMA_FROM_DEVICE, actlen);
+ if (retval != USB_STOR_TRANSPORT_GOOD) {
+ kfree(buf);
return -EIO;
+ }
+ memcpy(status, buf, len);
+ kfree(buf);
return 0;
}
@@ -434,6 +504,29 @@ static int enable_oscillator(struct us_data *us)
return 0;
}
+static int __do_config_autodelink(struct us_data *us, u8 *data, u16 len)
+{
+ int retval;
+ u16 addr = 0xFE47;
+ u8 cmnd[12] = {0};
+
+ US_DEBUGP("%s, addr = 0x%x, len = %d\n", __FUNCTION__, addr, len);
+
+ cmnd[0] = 0xF0;
+ cmnd[1] = 0x0E;
+ cmnd[2] = (u8)(addr >> 8);
+ cmnd[3] = (u8)addr;
+ cmnd[4] = (u8)(len >> 8);
+ cmnd[5] = (u8)len;
+
+ retval = rts51x_bulk_transport_special(us, 0, cmnd, 12, data, len, DMA_TO_DEVICE, NULL);
+ if (retval != USB_STOR_TRANSPORT_GOOD) {
+ return -EIO;
+ }
+
+ return 0;
+}
+
static int do_config_autodelink(struct us_data *us, int enable, int force)
{
int retval;
@@ -454,7 +547,8 @@ static int do_config_autodelink(struct us_data *us, int enable, int force)
US_DEBUGP("In %s,set 0xfe47 to 0x%x\n", __func__, value);
- retval = rts51x_write_mem(us, 0xFE47, &value, 1);
+ /* retval = rts51x_write_mem(us, 0xFE47, &value, 1); */
+ retval = __do_config_autodelink(us, &value, 1);
if (retval < 0)
return -EIO;
@@ -486,7 +580,8 @@ static int config_autodelink_after_power_on(struct us_data *us)
SET_BIT(value, 7);
- retval = rts51x_write_mem(us, 0xFE47, &value, 1);
+ /* retval = rts51x_write_mem(us, 0xFE47, &value, 1); */
+ retval = __do_config_autodelink(us, &value, 1);
if (retval < 0)
return -EIO;
@@ -507,7 +602,8 @@ static int config_autodelink_after_power_on(struct us_data *us)
CLR_BIT(value, 7);
}
- retval = rts51x_write_mem(us, 0xFE47, &value, 1);
+ /* retval = rts51x_write_mem(us, 0xFE47, &value, 1); */
+ retval = __do_config_autodelink(us, &value, 1);
if (retval < 0)
return -EIO;
@@ -584,7 +680,8 @@ static int config_autodelink_before_power_down(struct us_data *us)
if (CHECK_ID(chip, 0x0138, 0x3882))
SET_BIT(value, 2);
- retval = rts51x_write_mem(us, 0xFE47, &value, 1);
+ /* retval = rts51x_write_mem(us, 0xFE47, &value, 1); */
+ retval = __do_config_autodelink(us, &value, 1);
if (retval < 0)
return -EIO;
}
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index e8ae21b2d387..ff32390d61e5 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -691,6 +691,9 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
int temp_result;
struct scsi_eh_save ses;
int sense_size = US_SENSE_SIZE;
+ struct scsi_sense_hdr sshdr;
+ const u8 *scdd;
+ u8 fm_ili;
/* device supports and needs bigger sense buffer */
if (us->fflags & US_FL_SANE_SENSE)
@@ -774,32 +777,30 @@ Retry_Sense:
srb->sense_buffer[7] = (US_SENSE_SIZE - 8);
}
+ scsi_normalize_sense(srb->sense_buffer, SCSI_SENSE_BUFFERSIZE,
+ &sshdr);
+
US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
- srb->sense_buffer[0],
- srb->sense_buffer[2] & 0xf,
- srb->sense_buffer[12],
- srb->sense_buffer[13]);
+ sshdr.response_code, sshdr.sense_key,
+ sshdr.asc, sshdr.ascq);
#ifdef CONFIG_USB_STORAGE_DEBUG
- usb_stor_show_sense(
- srb->sense_buffer[2] & 0xf,
- srb->sense_buffer[12],
- srb->sense_buffer[13]);
+ usb_stor_show_sense(sshdr.sense_key, sshdr.asc, sshdr.ascq);
#endif
/* set the result so the higher layers expect this data */
srb->result = SAM_STAT_CHECK_CONDITION;
+ scdd = scsi_sense_desc_find(srb->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE, 4);
+ fm_ili = (scdd ? scdd[3] : srb->sense_buffer[2]) & 0xA0;
+
/* We often get empty sense data. This could indicate that
* everything worked or that there was an unspecified
* problem. We have to decide which.
*/
- if ( /* Filemark 0, ignore EOM, ILI 0, no sense */
- (srb->sense_buffer[2] & 0xaf) == 0 &&
- /* No ASC or ASCQ */
- srb->sense_buffer[12] == 0 &&
- srb->sense_buffer[13] == 0) {
-
+ if (sshdr.sense_key == 0 && sshdr.asc == 0 && sshdr.ascq == 0 &&
+ fm_ili == 0) {
/* If things are really okay, then let's show that.
* Zero out the sense buffer so the higher layers
* won't realize we did an unsolicited auto-sense.
@@ -814,7 +815,10 @@ Retry_Sense:
*/
} else {
srb->result = DID_ERROR << 16;
- srb->sense_buffer[2] = HARDWARE_ERROR;
+ if ((sshdr.response_code & 0x72) == 0x72)
+ srb->sense_buffer[1] = HARDWARE_ERROR;
+ else
+ srb->sense_buffer[2] = HARDWARE_ERROR;
}
}
}
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 0ca095820f3e..c325e69415a1 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -831,12 +831,22 @@ static int usb_stor_scan_thread(void * __us)
dev_dbg(dev, "device found\n");
- set_freezable();
- /* Wait for the timeout to expire or for a disconnect */
+ set_freezable_with_signal();
+ /*
+ * Wait for the timeout to expire or for a disconnect
+ *
+ * We can't freeze in this thread or we risk causing khubd to
+ * fail to freeze, but we can't be non-freezable either. Nor can
+ * khubd freeze while waiting for scanning to complete as it may
+ * hold the device lock, causing a hang when suspending devices.
+ * So we request a fake signal when freezing and use
+ * interruptible sleep to kick us out of our wait early when
+ * freezing happens.
+ */
if (delay_use > 0) {
dev_dbg(dev, "waiting for device to settle "
"before scanning\n");
- wait_event_freezable_timeout(us->delay_wait,
+ wait_event_interruptible_timeout(us->delay_wait,
test_bit(US_FLIDX_DONT_SCAN, &us->dflags),
delay_use * HZ);
}
diff --git a/drivers/usb/usb-common.c b/drivers/usb/usb-common.c
new file mode 100644
index 000000000000..d29503e954ab
--- /dev/null
+++ b/drivers/usb/usb-common.c
@@ -0,0 +1,35 @@
+/*
+ * Provides code common for host and device side USB.
+ *
+ * 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.
+ *
+ * If either host side (ie. CONFIG_USB=y) or device side USB stack
+ * (ie. CONFIG_USB_GADGET=y) is compiled in the kernel, this module is
+ * compiled-in as well. Otherwise, if either of the two stacks is
+ * compiled as module, this file is compiled as module as well.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb/ch9.h>
+
+const char *usb_speed_string(enum usb_device_speed speed)
+{
+ static const char *const names[] = {
+ [USB_SPEED_UNKNOWN] = "UNKNOWN",
+ [USB_SPEED_LOW] = "low-speed",
+ [USB_SPEED_FULL] = "full-speed",
+ [USB_SPEED_HIGH] = "high-speed",
+ [USB_SPEED_WIRELESS] = "wireless",
+ [USB_SPEED_SUPER] = "super-speed",
+ };
+
+ if (speed < 0 || speed >= ARRAY_SIZE(names))
+ speed = USB_SPEED_UNKNOWN;
+ return names[speed];
+}
+EXPORT_SYMBOL_GPL(usb_speed_string);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index e24ce3123071..32d6fc953904 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -555,7 +555,7 @@ static int skel_probe(struct usb_interface *interface,
if (!dev->bulk_in_endpointAddr &&
usb_endpoint_is_bulk_in(endpoint)) {
/* we found a bulk in endpoint */
- buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ buffer_size = usb_endpoint_maxp(endpoint);
dev->bulk_in_size = buffer_size;
dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
diff --git a/drivers/usb/wusbcore/wa-hc.c b/drivers/usb/wusbcore/wa-hc.c
index 59a748a0e5da..0d1863c9edde 100644
--- a/drivers/usb/wusbcore/wa-hc.c
+++ b/drivers/usb/wusbcore/wa-hc.c
@@ -43,7 +43,7 @@ int wa_create(struct wahc *wa, struct usb_interface *iface)
/* Fill up Data Transfer EP pointers */
wa->dti_epd = &iface->cur_altsetting->endpoint[1].desc;
wa->dto_epd = &iface->cur_altsetting->endpoint[2].desc;
- wa->xfer_result_size = le16_to_cpu(wa->dti_epd->wMaxPacketSize);
+ wa->xfer_result_size = usb_endpoint_maxp(wa->dti_epd);
wa->xfer_result = kmalloc(wa->xfer_result_size, GFP_KERNEL);
if (wa->xfer_result == NULL)
goto error_xfer_result_alloc;
diff --git a/drivers/uwb/uwb-internal.h b/drivers/uwb/uwb-internal.h
index 157485c862c0..a7494bf10081 100644
--- a/drivers/uwb/uwb-internal.h
+++ b/drivers/uwb/uwb-internal.h
@@ -28,7 +28,6 @@
#ifndef __UWB_INTERNAL_H__
#define __UWB_INTERNAL_H__
-#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/uwb.h>
diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c
index 05a8832bb3eb..d06886a2bfb5 100644
--- a/drivers/video/backlight/adp8870_bl.c
+++ b/drivers/video/backlight/adp8870_bl.c
@@ -1009,4 +1009,4 @@ module_exit(adp8870_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("ADP8870 Backlight driver");
-MODULE_ALIAS("platform:adp8870-backlight");
+MODULE_ALIAS("i2c:adp8870-backlight");
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 80d292fb92d8..7363c1b169e8 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -19,7 +19,7 @@
#include <asm/backlight.h>
#endif
-static const char const *backlight_types[] = {
+static const char *const backlight_types[] = {
[BACKLIGHT_RAW] = "raw",
[BACKLIGHT_PLATFORM] = "platform",
[BACKLIGHT_FIRMWARE] = "firmware",
diff --git a/drivers/video/backlight/ep93xx_bl.c b/drivers/video/backlight/ep93xx_bl.c
index 9f1e389d51d2..b0582917f0c8 100644
--- a/drivers/video/backlight/ep93xx_bl.c
+++ b/drivers/video/backlight/ep93xx_bl.c
@@ -11,7 +11,7 @@
* BRIGHT, on the Cirrus EP9307, EP9312, and EP9315 processors.
*/
-
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/fb.h>
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index b8f38ec6eb18..8b5b2a4124c7 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -28,6 +28,8 @@ struct pwm_bl_data {
unsigned int lth_brightness;
int (*notify)(struct device *,
int brightness);
+ void (*notify_after)(struct device *,
+ int brightness);
int (*check_fb)(struct device *, struct fb_info *);
};
@@ -55,6 +57,10 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
pwm_config(pb->pwm, brightness, pb->period);
pwm_enable(pb->pwm);
}
+
+ if (pb->notify_after)
+ pb->notify_after(pb->dev, brightness);
+
return 0;
}
@@ -105,6 +111,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->period = data->pwm_period_ns;
pb->notify = data->notify;
+ pb->notify_after = data->notify_after;
pb->check_fb = data->check_fb;
pb->lth_brightness = data->lth_brightness *
(data->pwm_period_ns / data->max_brightness);
@@ -172,6 +179,8 @@ static int pwm_backlight_suspend(struct platform_device *pdev,
pb->notify(pb->dev, 0);
pwm_config(pb->pwm, 0, pb->period);
pwm_disable(pb->pwm);
+ if (pb->notify_after)
+ pb->notify_after(pb->dev, 0);
return 0;
}
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index d885c770eb84..2d97752f79a5 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -428,7 +428,7 @@ static int __init igafb_init(void)
*
* IGS2000 has its I/O memory mapped and we want
* to generate memory cycles on PCI, e.g. do ioremap(),
- * then readb/writeb() as in Documentation/IO-mapping.txt.
+ * then readb/writeb() as in Documentation/io-mapping.txt.
*
* IGS1682 is more traditional, it responds to PCI I/O
* cycles, so we want to access it with inb()/outb().
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 68b9136847af..4acf88884f9b 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -529,4 +529,14 @@ void vring_transport_features(struct virtio_device *vdev)
}
EXPORT_SYMBOL_GPL(vring_transport_features);
+/* return the size of the vring within the virtqueue */
+unsigned int virtqueue_get_vring_size(struct virtqueue *_vq)
+{
+
+ struct vring_virtqueue *vq = to_vvq(_vq);
+
+ return vq->vring.num;
+}
+EXPORT_SYMBOL_GPL(virtqueue_get_vring_size);
+
MODULE_LICENSE("GPL");
diff --git a/drivers/w1/masters/ds2490.c b/drivers/w1/masters/ds2490.c
index 02bf7bf7160b..b5abaae38e97 100644
--- a/drivers/w1/masters/ds2490.c
+++ b/drivers/w1/masters/ds2490.c
@@ -1,7 +1,7 @@
/*
* dscore.c
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -1024,5 +1024,5 @@ module_init(ds_init);
module_exit(ds_fini);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
MODULE_DESCRIPTION("DS2490 USB <-> W1 bus master driver (DS9490*)");
diff --git a/drivers/w1/masters/matrox_w1.c b/drivers/w1/masters/matrox_w1.c
index 334d1ccf9c92..f667c26b2195 100644
--- a/drivers/w1/masters/matrox_w1.c
+++ b/drivers/w1/masters/matrox_w1.c
@@ -1,7 +1,7 @@
/*
* matrox_w1.c
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -39,7 +39,7 @@
#include "../w1_log.h"
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
MODULE_DESCRIPTION("Driver for transport(Dallas 1-wire prtocol) over VGA DDC(matrox gpio).");
static struct pci_device_id matrox_w1_tbl[] = {
diff --git a/drivers/w1/slaves/w1_ds2408.c b/drivers/w1/slaves/w1_ds2408.c
index c37781899d90..7c8cdb8aed26 100644
--- a/drivers/w1/slaves/w1_ds2408.c
+++ b/drivers/w1/slaves/w1_ds2408.c
@@ -373,7 +373,7 @@ static int w1_f29_add_slave(struct w1_slave *sl)
static void w1_f29_remove_slave(struct w1_slave *sl)
{
int i;
- for (i = NB_SYSFS_BIN_FILES; i <= 0; --i)
+ for (i = NB_SYSFS_BIN_FILES - 1; i >= 0; --i)
sysfs_remove_bin_file(&sl->dev.kobj,
&(w1_f29_sysfs_bin_files[i]));
}
diff --git a/drivers/w1/slaves/w1_smem.c b/drivers/w1/slaves/w1_smem.c
index cc8c02e92593..84655625c870 100644
--- a/drivers/w1/slaves/w1_smem.c
+++ b/drivers/w1/slaves/w1_smem.c
@@ -1,7 +1,7 @@
/*
* w1_smem.c
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -32,7 +32,7 @@
#include "../w1_family.h"
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, 64bit memory family.");
static struct w1_family w1_smem_family_01 = {
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c
index 402928b135d1..a1ef9b5b38cf 100644
--- a/drivers/w1/slaves/w1_therm.c
+++ b/drivers/w1/slaves/w1_therm.c
@@ -1,7 +1,7 @@
/*
* w1_therm.c
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -34,7 +34,7 @@
#include "../w1_family.h"
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, temperature family.");
/* Allow the strong pullup to be disabled, but default to enabled.
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 6c136c19e982..c37497823851 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -1,7 +1,7 @@
/*
* w1.c
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -42,7 +42,7 @@
#include "w1_netlink.h"
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol.");
static int w1_timeout = 10;
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h
index 1ce23fc6186c..4d012ca3f32c 100644
--- a/drivers/w1/w1.h
+++ b/drivers/w1/w1.h
@@ -1,7 +1,7 @@
/*
* w1.h
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c
index 4a099041f28a..63359797c8b1 100644
--- a/drivers/w1/w1_family.c
+++ b/drivers/w1/w1_family.c
@@ -1,7 +1,7 @@
/*
* w1_family.c
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h
index 98a1ac0f4693..490cda2281bc 100644
--- a/drivers/w1/w1_family.h
+++ b/drivers/w1/w1_family.h
@@ -1,7 +1,7 @@
/*
* w1_family.h
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
index b50be3f1073d..d220bce2cee4 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -1,7 +1,7 @@
/*
* w1_int.c
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/w1/w1_int.h b/drivers/w1/w1_int.h
index 4274082d2262..2ad7d4414bed 100644
--- a/drivers/w1/w1_int.h
+++ b/drivers/w1/w1_int.h
@@ -1,7 +1,7 @@
/*
* w1_int.h
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c
index 8e8b64cfafb6..765b37b62a4f 100644
--- a/drivers/w1/w1_io.c
+++ b/drivers/w1/w1_io.c
@@ -1,7 +1,7 @@
/*
* w1_io.c
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/w1/w1_log.h b/drivers/w1/w1_log.h
index e6ab7cf08f88..9c7bd62e6bdc 100644
--- a/drivers/w1/w1_log.h
+++ b/drivers/w1/w1_log.h
@@ -1,7 +1,7 @@
/*
* w1_log.h
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c
index 55aabd927c60..40788c925d1c 100644
--- a/drivers/w1/w1_netlink.c
+++ b/drivers/w1/w1_netlink.c
@@ -1,7 +1,7 @@
/*
* w1_netlink.c
*
- * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2003 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/w1/w1_netlink.h b/drivers/w1/w1_netlink.h
index 27e950f935b1..b0922dc29658 100644
--- a/drivers/w1/w1_netlink.h
+++ b/drivers/w1/w1_netlink.h
@@ -1,7 +1,7 @@
/*
* w1_netlink.h
*
- * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2003 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index bd44417c84d4..5c5f4b14fd05 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -54,12 +54,35 @@ static atomic_t ticks;
static inline void bcm47xx_wdt_hw_start(void)
{
/* this is 2,5s on 100Mhz clock and 2s on 133 Mhz */
- ssb_watchdog_timer_set(&ssb_bcm47xx, 0xfffffff);
+ switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff);
+ break;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc,
+ 0xfffffff);
+ break;
+#endif
+ }
}
static inline int bcm47xx_wdt_hw_stop(void)
{
- return ssb_watchdog_timer_set(&ssb_bcm47xx, 0);
+ switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 0);
+ return 0;
+#endif
+ }
+ return -EINVAL;
}
static void bcm47xx_timer_tick(unsigned long unused)
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 410fba45378d..809cbda03d7a 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -494,15 +494,16 @@ static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason,
asminline_call(&cmn_regs, cru_rom_addr);
die_nmi_called = 1;
spin_unlock_irqrestore(&rom_lock, rom_pl);
+
+ if (allow_kdump)
+ hpwdt_stop();
+
if (!is_icru) {
if (cmn_regs.u1.ral == 0) {
- printk(KERN_WARNING "hpwdt: An NMI occurred, "
+ panic("An NMI occurred, "
"but unable to determine source.\n");
}
}
-
- if (allow_kdump)
- hpwdt_stop();
panic("An NMI occurred, please see the Integrated "
"Management Log for details.\n");
diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c
index 7d82adac1cb2..102aed0efbf1 100644
--- a/drivers/watchdog/lantiq_wdt.c
+++ b/drivers/watchdog/lantiq_wdt.c
@@ -51,16 +51,16 @@ static int ltq_wdt_ok_to_close;
static void
ltq_wdt_enable(void)
{
- ltq_wdt_timeout = ltq_wdt_timeout *
+ unsigned long int timeout = ltq_wdt_timeout *
(ltq_io_region_clk_rate / LTQ_WDT_DIVIDER) + 0x1000;
- if (ltq_wdt_timeout > LTQ_MAX_TIMEOUT)
- ltq_wdt_timeout = LTQ_MAX_TIMEOUT;
+ if (timeout > LTQ_MAX_TIMEOUT)
+ timeout = LTQ_MAX_TIMEOUT;
/* write the first password magic */
ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR);
/* write the second magic plus the configuration and new timeout */
ltq_w32(LTQ_WDT_SR_EN | LTQ_WDT_SR_PWD | LTQ_WDT_SR_CLKDIV |
- LTQ_WDT_PW2 | ltq_wdt_timeout, ltq_wdt_membase + LTQ_WDT_CR);
+ LTQ_WDT_PW2 | timeout, ltq_wdt_membase + LTQ_WDT_CR);
}
static void
diff --git a/drivers/watchdog/sbc_epx_c3.c b/drivers/watchdog/sbc_epx_c3.c
index 3066a5127ca8..eaca366b7234 100644
--- a/drivers/watchdog/sbc_epx_c3.c
+++ b/drivers/watchdog/sbc_epx_c3.c
@@ -173,7 +173,7 @@ static struct notifier_block epx_c3_notifier = {
.notifier_call = epx_c3_notify_sys,
};
-static const char banner[] __initdata = KERN_INFO PFX
+static const char banner[] __initconst = KERN_INFO PFX
"Hardware Watchdog Timer for Winsystems EPX-C3 SBC: 0.1\n";
static int __init watchdog_init(void)
diff --git a/drivers/watchdog/smsc37b787_wdt.c b/drivers/watchdog/smsc37b787_wdt.c
index e97b0499bd0d..97b8184614ae 100644
--- a/drivers/watchdog/smsc37b787_wdt.c
+++ b/drivers/watchdog/smsc37b787_wdt.c
@@ -40,7 +40,7 @@
* mknod /dev/watchdog c 10 130
*
* For an example userspace keep-alive daemon, see:
- * Documentation/watchdog/watchdog.txt
+ * Documentation/watchdog/wdt.txt
*/
#include <linux/module.h>
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index d33520d0b4c9..1199da0f98cf 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -59,7 +59,7 @@ static struct watchdog_device *wdd;
static int watchdog_ping(struct watchdog_device *wddev)
{
- if (test_bit(WDOG_ACTIVE, &wdd->status)) {
+ if (test_bit(WDOG_ACTIVE, &wddev->status)) {
if (wddev->ops->ping)
return wddev->ops->ping(wddev); /* ping the watchdog */
else
@@ -81,12 +81,12 @@ static int watchdog_start(struct watchdog_device *wddev)
{
int err;
- if (!test_bit(WDOG_ACTIVE, &wdd->status)) {
+ if (!test_bit(WDOG_ACTIVE, &wddev->status)) {
err = wddev->ops->start(wddev);
if (err < 0)
return err;
- set_bit(WDOG_ACTIVE, &wdd->status);
+ set_bit(WDOG_ACTIVE, &wddev->status);
}
return 0;
}
@@ -105,18 +105,18 @@ static int watchdog_stop(struct watchdog_device *wddev)
{
int err = -EBUSY;
- if (test_bit(WDOG_NO_WAY_OUT, &wdd->status)) {
+ if (test_bit(WDOG_NO_WAY_OUT, &wddev->status)) {
pr_info("%s: nowayout prevents watchdog to be stopped!\n",
- wdd->info->identity);
+ wddev->info->identity);
return err;
}
- if (test_bit(WDOG_ACTIVE, &wdd->status)) {
+ if (test_bit(WDOG_ACTIVE, &wddev->status)) {
err = wddev->ops->stop(wddev);
if (err < 0)
return err;
- clear_bit(WDOG_ACTIVE, &wdd->status);
+ clear_bit(WDOG_ACTIVE, &wddev->status);
}
return 0;
}
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 5f7ff8e2fc14..8795480c2350 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -137,16 +137,6 @@ config XEN_GRANT_DEV_ALLOC
to other domains. This can be used to implement frontend drivers
or as part of an inter-domain shared memory channel.
-config XEN_PLATFORM_PCI
- tristate "xen platform pci device driver"
- depends on XEN_PVHVM && PCI
- default m
- help
- Driver for the Xen PCI Platform device: it is responsible for
- initializing xenbus and grant_table when running in a Xen HVM
- domain. As a consequence this driver is required to run any Xen PV
- frontend on Xen HVM.
-
config SWIOTLB_XEN
def_bool y
depends on PCI
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index 72bbb27d7a68..974fffdf22b2 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -14,7 +14,7 @@ obj-$(CONFIG_XEN_GNTDEV) += xen-gntdev.o
obj-$(CONFIG_XEN_GRANT_DEV_ALLOC) += xen-gntalloc.o
obj-$(CONFIG_XENFS) += xenfs/
obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o
-obj-$(CONFIG_XEN_PLATFORM_PCI) += xen-platform-pci.o
+obj-$(CONFIG_XEN_PVHVM) += platform-pci.o
obj-$(CONFIG_XEN_TMEM) += tmem.o
obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o
obj-$(CONFIG_XEN_DOM0) += pci.o
@@ -23,5 +23,3 @@ obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback/
xen-evtchn-y := evtchn.o
xen-gntdev-y := gntdev.o
xen-gntalloc-y := gntalloc.o
-
-xen-platform-pci-y := platform-pci.o
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index 5dfd8f8ff07f..5876e1ae6c2d 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -501,20 +501,24 @@ EXPORT_SYMBOL_GPL(balloon_set_new_target);
* alloc_xenballooned_pages - get pages that have been ballooned out
* @nr_pages: Number of pages to get
* @pages: pages returned
+ * @highmem: highmem or lowmem pages
* @return 0 on success, error otherwise
*/
-int alloc_xenballooned_pages(int nr_pages, struct page** pages)
+int alloc_xenballooned_pages(int nr_pages, struct page **pages, bool highmem)
{
int pgno = 0;
struct page* page;
mutex_lock(&balloon_mutex);
while (pgno < nr_pages) {
- page = balloon_retrieve(true);
- if (page) {
+ page = balloon_retrieve(highmem);
+ if (page && PageHighMem(page) == highmem) {
pages[pgno++] = page;
} else {
enum bp_state st;
- st = decrease_reservation(nr_pages - pgno, GFP_HIGHUSER);
+ if (page)
+ balloon_append(page);
+ st = decrease_reservation(nr_pages - pgno,
+ highmem ? GFP_HIGHUSER : GFP_USER);
if (st != BP_DONE)
goto out_undo;
}
@@ -555,17 +559,40 @@ void free_xenballooned_pages(int nr_pages, struct page** pages)
}
EXPORT_SYMBOL(free_xenballooned_pages);
-static int __init balloon_init(void)
+static void __init balloon_add_region(unsigned long start_pfn,
+ unsigned long pages)
{
unsigned long pfn, extra_pfn_end;
struct page *page;
+ /*
+ * If the amount of usable memory has been limited (e.g., with
+ * the 'mem' command line parameter), don't add pages beyond
+ * this limit.
+ */
+ extra_pfn_end = min(max_pfn, start_pfn + pages);
+
+ for (pfn = start_pfn; pfn < extra_pfn_end; pfn++) {
+ page = pfn_to_page(pfn);
+ /* totalram_pages and totalhigh_pages do not
+ include the boot-time balloon extension, so
+ don't subtract from it. */
+ __balloon_append(page);
+ }
+}
+
+static int __init balloon_init(void)
+{
+ int i;
+
if (!xen_domain())
return -ENODEV;
pr_info("xen/balloon: Initialising balloon driver.\n");
- balloon_stats.current_pages = xen_pv_domain() ? min(xen_start_info->nr_pages, max_pfn) : max_pfn;
+ balloon_stats.current_pages = xen_pv_domain()
+ ? min(xen_start_info->nr_pages - xen_released_pages, max_pfn)
+ : max_pfn;
balloon_stats.target_pages = balloon_stats.current_pages;
balloon_stats.balloon_low = 0;
balloon_stats.balloon_high = 0;
@@ -584,24 +611,13 @@ static int __init balloon_init(void)
#endif
/*
- * Initialise the balloon with excess memory space. We need
- * to make sure we don't add memory which doesn't exist or
- * logically exist. The E820 map can be trimmed to be smaller
- * than the amount of physical memory due to the mem= command
- * line parameter. And if this is a 32-bit non-HIGHMEM kernel
- * on a system with memory which requires highmem to access,
- * don't try to use it.
+ * Initialize the balloon with pages from the extra memory
+ * regions (see arch/x86/xen/setup.c).
*/
- extra_pfn_end = min(min(max_pfn, e820_end_of_ram_pfn()),
- (unsigned long)PFN_DOWN(xen_extra_mem_start + xen_extra_mem_size));
- for (pfn = PFN_UP(xen_extra_mem_start);
- pfn < extra_pfn_end;
- pfn++) {
- page = pfn_to_page(pfn);
- /* totalram_pages and totalhigh_pages do not include the boot-time
- balloon extension, so don't subtract from it. */
- __balloon_append(page);
- }
+ for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++)
+ if (xen_extra_mem[i].size)
+ balloon_add_region(PFN_UP(xen_extra_mem[i].start),
+ PFN_DOWN(xen_extra_mem[i].size));
return 0;
}
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index da70f5c32eb9..7a55b292bf39 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -54,7 +54,7 @@
* This lock protects updates to the following mapping and reference-count
* arrays. The lock does not need to be acquired to read the mapping tables.
*/
-static DEFINE_SPINLOCK(irq_mapping_update_lock);
+static DEFINE_MUTEX(irq_mapping_update_lock);
static LIST_HEAD(xen_irq_list_head);
@@ -432,7 +432,8 @@ static int __must_check xen_allocate_irq_dynamic(void)
irq = irq_alloc_desc_from(first, -1);
- xen_irq_init(irq);
+ if (irq >= 0)
+ xen_irq_init(irq);
return irq;
}
@@ -631,7 +632,7 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi,
int irq = -1;
struct physdev_irq irq_op;
- spin_lock(&irq_mapping_update_lock);
+ mutex_lock(&irq_mapping_update_lock);
irq = find_irq_by_gsi(gsi);
if (irq != -1) {
@@ -684,7 +685,7 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi,
handle_edge_irq, name);
out:
- spin_unlock(&irq_mapping_update_lock);
+ mutex_unlock(&irq_mapping_update_lock);
return irq;
}
@@ -710,10 +711,10 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
{
int irq, ret;
- spin_lock(&irq_mapping_update_lock);
+ mutex_lock(&irq_mapping_update_lock);
irq = xen_allocate_irq_dynamic();
- if (irq == -1)
+ if (irq < 0)
goto out;
irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_edge_irq,
@@ -724,12 +725,12 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
if (ret < 0)
goto error_irq;
out:
- spin_unlock(&irq_mapping_update_lock);
+ mutex_unlock(&irq_mapping_update_lock);
return irq;
error_irq:
- spin_unlock(&irq_mapping_update_lock);
+ mutex_unlock(&irq_mapping_update_lock);
xen_free_irq(irq);
- return -1;
+ return ret;
}
#endif
@@ -740,7 +741,7 @@ int xen_destroy_irq(int irq)
struct irq_info *info = info_for_irq(irq);
int rc = -ENOENT;
- spin_lock(&irq_mapping_update_lock);
+ mutex_lock(&irq_mapping_update_lock);
desc = irq_to_desc(irq);
if (!desc)
@@ -766,7 +767,7 @@ int xen_destroy_irq(int irq)
xen_free_irq(irq);
out:
- spin_unlock(&irq_mapping_update_lock);
+ mutex_unlock(&irq_mapping_update_lock);
return rc;
}
@@ -776,10 +777,10 @@ int xen_irq_from_pirq(unsigned pirq)
struct irq_info *info;
- spin_lock(&irq_mapping_update_lock);
+ mutex_lock(&irq_mapping_update_lock);
list_for_each_entry(info, &xen_irq_list_head, list) {
- if (info == NULL || info->type != IRQT_PIRQ)
+ if (info->type != IRQT_PIRQ)
continue;
irq = info->irq;
if (info->u.pirq.pirq == pirq)
@@ -787,7 +788,7 @@ int xen_irq_from_pirq(unsigned pirq)
}
irq = -1;
out:
- spin_unlock(&irq_mapping_update_lock);
+ mutex_unlock(&irq_mapping_update_lock);
return irq;
}
@@ -802,7 +803,7 @@ int bind_evtchn_to_irq(unsigned int evtchn)
{
int irq;
- spin_lock(&irq_mapping_update_lock);
+ mutex_lock(&irq_mapping_update_lock);
irq = evtchn_to_irq[evtchn];
@@ -818,7 +819,7 @@ int bind_evtchn_to_irq(unsigned int evtchn)
}
out:
- spin_unlock(&irq_mapping_update_lock);
+ mutex_unlock(&irq_mapping_update_lock);
return irq;
}
@@ -829,7 +830,7 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
struct evtchn_bind_ipi bind_ipi;
int evtchn, irq;
- spin_lock(&irq_mapping_update_lock);
+ mutex_lock(&irq_mapping_update_lock);
irq = per_cpu(ipi_to_irq, cpu)[ipi];
@@ -853,7 +854,7 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
}
out:
- spin_unlock(&irq_mapping_update_lock);
+ mutex_unlock(&irq_mapping_update_lock);
return irq;
}
@@ -872,13 +873,34 @@ static int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
return err ? : bind_evtchn_to_irq(bind_interdomain.local_port);
}
+static int find_virq(unsigned int virq, unsigned int cpu)
+{
+ struct evtchn_status status;
+ int port, rc = -ENOENT;
+
+ memset(&status, 0, sizeof(status));
+ for (port = 0; port <= NR_EVENT_CHANNELS; port++) {
+ status.dom = DOMID_SELF;
+ status.port = port;
+ rc = HYPERVISOR_event_channel_op(EVTCHNOP_status, &status);
+ if (rc < 0)
+ continue;
+ if (status.status != EVTCHNSTAT_virq)
+ continue;
+ if (status.u.virq == virq && status.vcpu == cpu) {
+ rc = port;
+ break;
+ }
+ }
+ return rc;
+}
int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
{
struct evtchn_bind_virq bind_virq;
- int evtchn, irq;
+ int evtchn, irq, ret;
- spin_lock(&irq_mapping_update_lock);
+ mutex_lock(&irq_mapping_update_lock);
irq = per_cpu(virq_to_irq, cpu)[virq];
@@ -892,10 +914,16 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
bind_virq.virq = virq;
bind_virq.vcpu = cpu;
- if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
- &bind_virq) != 0)
- BUG();
- evtchn = bind_virq.port;
+ ret = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
+ &bind_virq);
+ if (ret == 0)
+ evtchn = bind_virq.port;
+ else {
+ if (ret == -EEXIST)
+ ret = find_virq(virq, cpu);
+ BUG_ON(ret < 0);
+ evtchn = ret;
+ }
xen_irq_info_virq_init(cpu, irq, evtchn, virq);
@@ -903,7 +931,7 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
}
out:
- spin_unlock(&irq_mapping_update_lock);
+ mutex_unlock(&irq_mapping_update_lock);
return irq;
}
@@ -913,7 +941,7 @@ static void unbind_from_irq(unsigned int irq)
struct evtchn_close close;
int evtchn = evtchn_from_irq(irq);
- spin_lock(&irq_mapping_update_lock);
+ mutex_lock(&irq_mapping_update_lock);
if (VALID_EVTCHN(evtchn)) {
close.port = evtchn;
@@ -943,7 +971,7 @@ static void unbind_from_irq(unsigned int irq)
xen_free_irq(irq);
- spin_unlock(&irq_mapping_update_lock);
+ mutex_unlock(&irq_mapping_update_lock);
}
int bind_evtchn_to_irqhandler(unsigned int evtchn,
@@ -1279,7 +1307,7 @@ void rebind_evtchn_irq(int evtchn, int irq)
will also be masked. */
disable_irq(irq);
- spin_lock(&irq_mapping_update_lock);
+ mutex_lock(&irq_mapping_update_lock);
/* After resume the irq<->evtchn mappings are all cleared out */
BUG_ON(evtchn_to_irq[evtchn] != -1);
@@ -1289,7 +1317,7 @@ void rebind_evtchn_irq(int evtchn, int irq)
xen_irq_info_evtchn_init(irq, evtchn);
- spin_unlock(&irq_mapping_update_lock);
+ mutex_unlock(&irq_mapping_update_lock);
/* new event channels are always bound to cpu 0 */
irq_set_affinity(irq, cpumask_of(0));
@@ -1670,6 +1698,7 @@ void __init xen_init_IRQ(void)
evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq),
GFP_KERNEL);
+ BUG_ON(!evtchn_to_irq);
for (i = 0; i < NR_EVENT_CHANNELS; i++)
evtchn_to_irq[i] = -1;
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
index f914b26cf0c2..880798aae2f2 100644
--- a/drivers/xen/gntdev.c
+++ b/drivers/xen/gntdev.c
@@ -83,6 +83,7 @@ struct grant_map {
struct ioctl_gntdev_grant_ref *grants;
struct gnttab_map_grant_ref *map_ops;
struct gnttab_unmap_grant_ref *unmap_ops;
+ struct gnttab_map_grant_ref *kmap_ops;
struct page **pages;
};
@@ -116,19 +117,22 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count)
add->grants = kzalloc(sizeof(add->grants[0]) * count, GFP_KERNEL);
add->map_ops = kzalloc(sizeof(add->map_ops[0]) * count, GFP_KERNEL);
add->unmap_ops = kzalloc(sizeof(add->unmap_ops[0]) * count, GFP_KERNEL);
+ add->kmap_ops = kzalloc(sizeof(add->kmap_ops[0]) * count, GFP_KERNEL);
add->pages = kzalloc(sizeof(add->pages[0]) * count, GFP_KERNEL);
if (NULL == add->grants ||
NULL == add->map_ops ||
NULL == add->unmap_ops ||
+ NULL == add->kmap_ops ||
NULL == add->pages)
goto err;
- if (alloc_xenballooned_pages(count, add->pages))
+ if (alloc_xenballooned_pages(count, add->pages, false /* lowmem */))
goto err;
for (i = 0; i < count; i++) {
add->map_ops[i].handle = -1;
add->unmap_ops[i].handle = -1;
+ add->kmap_ops[i].handle = -1;
}
add->index = 0;
@@ -142,6 +146,7 @@ err:
kfree(add->grants);
kfree(add->map_ops);
kfree(add->unmap_ops);
+ kfree(add->kmap_ops);
kfree(add);
return NULL;
}
@@ -243,10 +248,35 @@ static int map_grant_pages(struct grant_map *map)
gnttab_set_unmap_op(&map->unmap_ops[i], addr,
map->flags, -1 /* handle */);
}
+ } else {
+ /*
+ * Setup the map_ops corresponding to the pte entries pointing
+ * to the kernel linear addresses of the struct pages.
+ * These ptes are completely different from the user ptes dealt
+ * with find_grant_ptes.
+ */
+ for (i = 0; i < map->count; i++) {
+ unsigned level;
+ unsigned long address = (unsigned long)
+ pfn_to_kaddr(page_to_pfn(map->pages[i]));
+ pte_t *ptep;
+ u64 pte_maddr = 0;
+ BUG_ON(PageHighMem(map->pages[i]));
+
+ ptep = lookup_address(address, &level);
+ pte_maddr = arbitrary_virt_to_machine(ptep).maddr;
+ gnttab_set_map_op(&map->kmap_ops[i], pte_maddr,
+ map->flags |
+ GNTMAP_host_map |
+ GNTMAP_contains_pte,
+ map->grants[i].ref,
+ map->grants[i].domid);
+ }
}
pr_debug("map %d+%d\n", map->index, map->count);
- err = gnttab_map_refs(map->map_ops, map->pages, map->count);
+ err = gnttab_map_refs(map->map_ops, use_ptemod ? map->kmap_ops : NULL,
+ map->pages, map->count);
if (err)
return err;
@@ -462,13 +492,11 @@ static int gntdev_release(struct inode *inode, struct file *flip)
pr_debug("priv %p\n", priv);
- spin_lock(&priv->lock);
while (!list_empty(&priv->maps)) {
map = list_entry(priv->maps.next, struct grant_map, next);
list_del(&map->next);
gntdev_put_map(map);
}
- spin_unlock(&priv->lock);
if (use_ptemod)
mmu_notifier_unregister(&priv->mn, priv->mm);
@@ -532,10 +560,11 @@ static long gntdev_ioctl_unmap_grant_ref(struct gntdev_priv *priv,
map = gntdev_find_map_index(priv, op.index >> PAGE_SHIFT, op.count);
if (map) {
list_del(&map->next);
- gntdev_put_map(map);
err = 0;
}
spin_unlock(&priv->lock);
+ if (map)
+ gntdev_put_map(map);
return err;
}
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index 4f44b347b24a..8c71ab801756 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -448,7 +448,8 @@ unsigned int gnttab_max_grant_frames(void)
EXPORT_SYMBOL_GPL(gnttab_max_grant_frames);
int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
- struct page **pages, unsigned int count)
+ struct gnttab_map_grant_ref *kmap_ops,
+ struct page **pages, unsigned int count)
{
int i, ret;
pte_t *pte;
@@ -488,8 +489,7 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
*/
return -EOPNOTSUPP;
}
- ret = m2p_add_override(mfn, pages[i],
- map_ops[i].flags & GNTMAP_contains_pte);
+ ret = m2p_add_override(mfn, pages[i], &kmap_ops[i]);
if (ret)
return ret;
}
diff --git a/drivers/xen/pci.c b/drivers/xen/pci.c
index cef4bafc07dc..66057075d6e2 100644
--- a/drivers/xen/pci.c
+++ b/drivers/xen/pci.c
@@ -18,6 +18,7 @@
*/
#include <linux/pci.h>
+#include <linux/acpi.h>
#include <xen/xen.h>
#include <xen/interface/physdev.h>
#include <xen/interface/xen.h>
@@ -26,26 +27,85 @@
#include <asm/xen/hypercall.h>
#include "../pci/pci.h"
+static bool __read_mostly pci_seg_supported = true;
+
static int xen_add_device(struct device *dev)
{
int r;
struct pci_dev *pci_dev = to_pci_dev(dev);
+#ifdef CONFIG_PCI_IOV
+ struct pci_dev *physfn = pci_dev->physfn;
+#endif
+
+ if (pci_seg_supported) {
+ struct physdev_pci_device_add add = {
+ .seg = pci_domain_nr(pci_dev->bus),
+ .bus = pci_dev->bus->number,
+ .devfn = pci_dev->devfn
+ };
+#ifdef CONFIG_ACPI
+ acpi_handle handle;
+#endif
+
+#ifdef CONFIG_PCI_IOV
+ if (pci_dev->is_virtfn) {
+ add.flags = XEN_PCI_DEV_VIRTFN;
+ add.physfn.bus = physfn->bus->number;
+ add.physfn.devfn = physfn->devfn;
+ } else
+#endif
+ if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn))
+ add.flags = XEN_PCI_DEV_EXTFN;
+
+#ifdef CONFIG_ACPI
+ handle = DEVICE_ACPI_HANDLE(&pci_dev->dev);
+ if (!handle)
+ handle = DEVICE_ACPI_HANDLE(pci_dev->bus->bridge);
+#ifdef CONFIG_PCI_IOV
+ if (!handle && pci_dev->is_virtfn)
+ handle = DEVICE_ACPI_HANDLE(physfn->bus->bridge);
+#endif
+ if (handle) {
+ acpi_status status;
+
+ do {
+ unsigned long long pxm;
+
+ status = acpi_evaluate_integer(handle, "_PXM",
+ NULL, &pxm);
+ if (ACPI_SUCCESS(status)) {
+ add.optarr[0] = pxm;
+ add.flags |= XEN_PCI_DEV_PXM;
+ break;
+ }
+ status = acpi_get_parent(handle, &handle);
+ } while (ACPI_SUCCESS(status));
+ }
+#endif /* CONFIG_ACPI */
+
+ r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_add, &add);
+ if (r != -ENOSYS)
+ return r;
+ pci_seg_supported = false;
+ }
+ if (pci_domain_nr(pci_dev->bus))
+ r = -ENOSYS;
#ifdef CONFIG_PCI_IOV
- if (pci_dev->is_virtfn) {
+ else if (pci_dev->is_virtfn) {
struct physdev_manage_pci_ext manage_pci_ext = {
.bus = pci_dev->bus->number,
.devfn = pci_dev->devfn,
.is_virtfn = 1,
- .physfn.bus = pci_dev->physfn->bus->number,
- .physfn.devfn = pci_dev->physfn->devfn,
+ .physfn.bus = physfn->bus->number,
+ .physfn.devfn = physfn->devfn,
};
r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext,
&manage_pci_ext);
- } else
+ }
#endif
- if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) {
+ else if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) {
struct physdev_manage_pci_ext manage_pci_ext = {
.bus = pci_dev->bus->number,
.devfn = pci_dev->devfn,
@@ -71,13 +131,27 @@ static int xen_remove_device(struct device *dev)
{
int r;
struct pci_dev *pci_dev = to_pci_dev(dev);
- struct physdev_manage_pci manage_pci;
- manage_pci.bus = pci_dev->bus->number;
- manage_pci.devfn = pci_dev->devfn;
+ if (pci_seg_supported) {
+ struct physdev_pci_device device = {
+ .seg = pci_domain_nr(pci_dev->bus),
+ .bus = pci_dev->bus->number,
+ .devfn = pci_dev->devfn
+ };
- r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_remove,
- &manage_pci);
+ r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_remove,
+ &device);
+ } else if (pci_domain_nr(pci_dev->bus))
+ r = -ENOSYS;
+ else {
+ struct physdev_manage_pci manage_pci = {
+ .bus = pci_dev->bus->number,
+ .devfn = pci_dev->devfn
+ };
+
+ r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_remove,
+ &manage_pci);
+ }
return r;
}
@@ -96,13 +170,16 @@ static int xen_pci_notifier(struct notifier_block *nb,
r = xen_remove_device(dev);
break;
default:
- break;
+ return NOTIFY_DONE;
}
-
- return r;
+ if (r)
+ dev_err(dev, "Failed to %s - passthrough or MSI/MSI-X might fail!\n",
+ action == BUS_NOTIFY_ADD_DEVICE ? "add" :
+ (action == BUS_NOTIFY_DEL_DEVICE ? "delete" : "?"));
+ return NOTIFY_OK;
}
-struct notifier_block device_nb = {
+static struct notifier_block device_nb = {
.notifier_call = xen_pci_notifier,
};
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index 6e8c15a23201..c984768d98ca 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -38,6 +38,7 @@
#include <xen/swiotlb-xen.h>
#include <xen/page.h>
#include <xen/xen-ops.h>
+#include <xen/hvc-console.h>
/*
* Used to do a quick range check in swiotlb_tbl_unmap_single and
* swiotlb_tbl_sync_single_*, to see if the memory was in fact allocated by this
@@ -146,8 +147,10 @@ xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
void __init xen_swiotlb_init(int verbose)
{
unsigned long bytes;
- int rc;
+ int rc = -ENOMEM;
unsigned long nr_tbl;
+ char *m = NULL;
+ unsigned int repeat = 3;
nr_tbl = swioltb_nr_tbl();
if (nr_tbl)
@@ -156,16 +159,17 @@ void __init xen_swiotlb_init(int verbose)
xen_io_tlb_nslabs = (64 * 1024 * 1024 >> IO_TLB_SHIFT);
xen_io_tlb_nslabs = ALIGN(xen_io_tlb_nslabs, IO_TLB_SEGSIZE);
}
-
+retry:
bytes = xen_io_tlb_nslabs << IO_TLB_SHIFT;
/*
* Get IO TLB memory from any location.
*/
xen_io_tlb_start = alloc_bootmem(bytes);
- if (!xen_io_tlb_start)
- panic("Cannot allocate SWIOTLB buffer");
-
+ if (!xen_io_tlb_start) {
+ m = "Cannot allocate Xen-SWIOTLB buffer!\n";
+ goto error;
+ }
xen_io_tlb_end = xen_io_tlb_start + bytes;
/*
* And replace that memory with pages under 4GB.
@@ -173,17 +177,28 @@ void __init xen_swiotlb_init(int verbose)
rc = xen_swiotlb_fixup(xen_io_tlb_start,
bytes,
xen_io_tlb_nslabs);
- if (rc)
+ if (rc) {
+ free_bootmem(__pa(xen_io_tlb_start), bytes);
+ m = "Failed to get contiguous memory for DMA from Xen!\n"\
+ "You either: don't have the permissions, do not have"\
+ " enough free memory under 4GB, or the hypervisor memory"\
+ "is too fragmented!";
goto error;
-
+ }
start_dma_addr = xen_virt_to_bus(xen_io_tlb_start);
swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs, verbose);
return;
error:
- panic("DMA(%d): Failed to exchange pages allocated for DMA with Xen! "\
- "We either don't have the permission or you do not have enough"\
- "free memory under 4GB!\n", rc);
+ if (repeat--) {
+ xen_io_tlb_nslabs = max(1024UL, /* Min is 2MB */
+ (xen_io_tlb_nslabs >> 1));
+ printk(KERN_INFO "Xen-SWIOTLB: Lowering to %luMB\n",
+ (xen_io_tlb_nslabs << IO_TLB_SHIFT) >> 20);
+ goto retry;
+ }
+ xen_raw_printk("%s (rc:%d)", m, rc);
+ panic("%s (rc:%d)", m, rc);
}
void *
@@ -194,6 +209,8 @@ xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
int order = get_order(size);
u64 dma_mask = DMA_BIT_MASK(32);
unsigned long vstart;
+ phys_addr_t phys;
+ dma_addr_t dev_addr;
/*
* Ignore region specifiers - the kernel's ideas of
@@ -209,18 +226,26 @@ xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
vstart = __get_free_pages(flags, order);
ret = (void *)vstart;
+ if (!ret)
+ return ret;
+
if (hwdev && hwdev->coherent_dma_mask)
- dma_mask = dma_alloc_coherent_mask(hwdev, flags);
+ dma_mask = hwdev->coherent_dma_mask;
- if (ret) {
+ phys = virt_to_phys(ret);
+ dev_addr = xen_phys_to_bus(phys);
+ if (((dev_addr + size - 1 <= dma_mask)) &&
+ !range_straddles_page_boundary(phys, size))
+ *dma_handle = dev_addr;
+ else {
if (xen_create_contiguous_region(vstart, order,
fls64(dma_mask)) != 0) {
free_pages(vstart, order);
return NULL;
}
- memset(ret, 0, size);
*dma_handle = virt_to_machine(ret).maddr;
}
+ memset(ret, 0, size);
return ret;
}
EXPORT_SYMBOL_GPL(xen_swiotlb_alloc_coherent);
@@ -230,11 +255,21 @@ xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
dma_addr_t dev_addr)
{
int order = get_order(size);
+ phys_addr_t phys;
+ u64 dma_mask = DMA_BIT_MASK(32);
if (dma_release_from_coherent(hwdev, order, vaddr))
return;
- xen_destroy_contiguous_region((unsigned long)vaddr, order);
+ if (hwdev && hwdev->coherent_dma_mask)
+ dma_mask = hwdev->coherent_dma_mask;
+
+ phys = virt_to_phys(vaddr);
+
+ if (((dev_addr + size - 1 > dma_mask)) ||
+ range_straddles_page_boundary(phys, size))
+ xen_destroy_contiguous_region((unsigned long)vaddr, order);
+
free_pages((unsigned long)vaddr, order);
}
EXPORT_SYMBOL_GPL(xen_swiotlb_free_coherent);
@@ -278,9 +313,10 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
/*
* Ensure that the address returned is DMA'ble
*/
- if (!dma_capable(dev, dev_addr, size))
- panic("map_single: bounce buffer is not DMA'ble");
-
+ if (!dma_capable(dev, dev_addr, size)) {
+ swiotlb_tbl_unmap_single(dev, map, size, dir);
+ dev_addr = 0;
+ }
return dev_addr;
}
EXPORT_SYMBOL_GPL(xen_swiotlb_map_page);
diff --git a/drivers/xen/xen-pciback/conf_space.c b/drivers/xen/xen-pciback/conf_space.c
index a8031445d94e..444345afbd5c 100644
--- a/drivers/xen/xen-pciback/conf_space.c
+++ b/drivers/xen/xen-pciback/conf_space.c
@@ -15,7 +15,6 @@
#include "conf_space.h"
#include "conf_space_quirks.h"
-#define DRV_NAME "xen-pciback"
static int permissive;
module_param(permissive, bool, 0644);
diff --git a/drivers/xen/xen-pciback/conf_space_header.c b/drivers/xen/xen-pciback/conf_space_header.c
index da3cbdfcb5dc..3daf862d739d 100644
--- a/drivers/xen/xen-pciback/conf_space_header.c
+++ b/drivers/xen/xen-pciback/conf_space_header.c
@@ -15,7 +15,6 @@ struct pci_bar_info {
int which;
};
-#define DRV_NAME "xen-pciback"
#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
@@ -25,7 +24,7 @@ static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
int ret;
ret = xen_pcibk_read_config_word(dev, offset, value, data);
- if (!atomic_read(&dev->enable_cnt))
+ if (!pci_is_enabled(dev))
return ret;
for (i = 0; i < PCI_ROM_RESOURCE; i++) {
@@ -187,7 +186,7 @@ static inline void read_dev_bar(struct pci_dev *dev,
bar_info->val = res[pos].start |
(res[pos].flags & PCI_REGION_FLAG_MASK);
- bar_info->len_val = res[pos].end - res[pos].start + 1;
+ bar_info->len_val = resource_size(&res[pos]);
}
static void *bar_init(struct pci_dev *dev, int offset)
diff --git a/drivers/xen/xen-pciback/conf_space_quirks.c b/drivers/xen/xen-pciback/conf_space_quirks.c
index 921a889e65eb..7476791cab40 100644
--- a/drivers/xen/xen-pciback/conf_space_quirks.c
+++ b/drivers/xen/xen-pciback/conf_space_quirks.c
@@ -12,7 +12,6 @@
#include "conf_space_quirks.h"
LIST_HEAD(xen_pcibk_quirks);
-#define DRV_NAME "xen-pciback"
static inline const struct pci_device_id *
match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)
{
@@ -36,7 +35,7 @@ static struct xen_pcibk_config_quirk *xen_pcibk_find_quirk(struct pci_dev *dev)
goto out;
tmp_quirk = NULL;
printk(KERN_DEBUG DRV_NAME
- ":quirk didn't match any device xen_pciback knows about\n");
+ ": quirk didn't match any device known\n");
out:
return tmp_quirk;
}
diff --git a/drivers/xen/xen-pciback/passthrough.c b/drivers/xen/xen-pciback/passthrough.c
index 1d32a9a42c01..828dddc360df 100644
--- a/drivers/xen/xen-pciback/passthrough.c
+++ b/drivers/xen/xen-pciback/passthrough.c
@@ -7,13 +7,13 @@
#include <linux/list.h>
#include <linux/pci.h>
-#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include "pciback.h"
struct passthrough_dev_data {
/* Access to dev_list must be protected by lock */
struct list_head dev_list;
- spinlock_t lock;
+ struct mutex lock;
};
static struct pci_dev *__xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev,
@@ -24,9 +24,8 @@ static struct pci_dev *__xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev,
struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
struct pci_dev_entry *dev_entry;
struct pci_dev *dev = NULL;
- unsigned long flags;
- spin_lock_irqsave(&dev_data->lock, flags);
+ mutex_lock(&dev_data->lock);
list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus)
@@ -37,7 +36,7 @@ static struct pci_dev *__xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev,
}
}
- spin_unlock_irqrestore(&dev_data->lock, flags);
+ mutex_unlock(&dev_data->lock);
return dev;
}
@@ -48,7 +47,6 @@ static int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev,
{
struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
struct pci_dev_entry *dev_entry;
- unsigned long flags;
unsigned int domain, bus, devfn;
int err;
@@ -57,9 +55,9 @@ static int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev,
return -ENOMEM;
dev_entry->dev = dev;
- spin_lock_irqsave(&dev_data->lock, flags);
+ mutex_lock(&dev_data->lock);
list_add_tail(&dev_entry->list, &dev_data->dev_list);
- spin_unlock_irqrestore(&dev_data->lock, flags);
+ mutex_unlock(&dev_data->lock);
/* Publish this device. */
domain = (unsigned int)pci_domain_nr(dev->bus);
@@ -76,9 +74,8 @@ static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev,
struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
struct pci_dev_entry *dev_entry, *t;
struct pci_dev *found_dev = NULL;
- unsigned long flags;
- spin_lock_irqsave(&dev_data->lock, flags);
+ mutex_lock(&dev_data->lock);
list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
if (dev_entry->dev == dev) {
@@ -88,7 +85,7 @@ static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev,
}
}
- spin_unlock_irqrestore(&dev_data->lock, flags);
+ mutex_unlock(&dev_data->lock);
if (found_dev)
pcistub_put_pci_dev(found_dev);
@@ -102,7 +99,7 @@ static int __xen_pcibk_init_devices(struct xen_pcibk_device *pdev)
if (!dev_data)
return -ENOMEM;
- spin_lock_init(&dev_data->lock);
+ mutex_init(&dev_data->lock);
INIT_LIST_HEAD(&dev_data->dev_list);
@@ -116,14 +113,14 @@ static int __xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev,
{
int err = 0;
struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
- struct pci_dev_entry *dev_entry, *e, *tmp;
+ struct pci_dev_entry *dev_entry, *e;
struct pci_dev *dev;
int found;
unsigned int domain, bus;
- spin_lock(&dev_data->lock);
+ mutex_lock(&dev_data->lock);
- list_for_each_entry_safe(dev_entry, tmp, &dev_data->dev_list, list) {
+ list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
/* Only publish this device as a root if none of its
* parent bridges are exported
*/
@@ -142,16 +139,13 @@ static int __xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev,
bus = (unsigned int)dev_entry->dev->bus->number;
if (!found) {
- spin_unlock(&dev_data->lock);
err = publish_root_cb(pdev, domain, bus);
if (err)
break;
- spin_lock(&dev_data->lock);
}
}
- if (!err)
- spin_unlock(&dev_data->lock);
+ mutex_unlock(&dev_data->lock);
return err;
}
@@ -182,7 +176,7 @@ static int __xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev,
return 1;
}
-struct xen_pcibk_backend xen_pcibk_passthrough_backend = {
+const struct xen_pcibk_backend xen_pcibk_passthrough_backend = {
.name = "passthrough",
.init = __xen_pcibk_init_devices,
.free = __xen_pcibk_release_devices,
diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c
index aec214ac0a14..8f06e1ed028c 100644
--- a/drivers/xen/xen-pciback/pci_stub.c
+++ b/drivers/xen/xen-pciback/pci_stub.c
@@ -21,8 +21,6 @@
#include "conf_space.h"
#include "conf_space_quirks.h"
-#define DRV_NAME "xen-pciback"
-
static char *pci_devs_to_hide;
wait_queue_head_t xen_pcibk_aer_wait_queue;
/*Add sem for sync AER handling and xen_pcibk remove/reconfigue ops,
@@ -222,6 +220,8 @@ void pcistub_put_pci_dev(struct pci_dev *dev)
}
spin_unlock_irqrestore(&pcistub_devices_lock, flags);
+ if (WARN_ON(!found_psdev))
+ return;
/*hold this lock for avoiding breaking link between
* pcistub and xen_pcibk when AER is in processing
@@ -514,12 +514,9 @@ static void kill_domain_by_device(struct pcistub_device *psdev)
int err;
char nodename[PCI_NODENAME_MAX];
- if (!psdev)
- dev_err(&psdev->dev->dev,
- "device is NULL when do AER recovery/kill_domain\n");
+ BUG_ON(!psdev);
snprintf(nodename, PCI_NODENAME_MAX, "/local/domain/0/backend/pci/%d/0",
psdev->pdev->xdev->otherend_id);
- nodename[strlen(nodename)] = '\0';
again:
err = xenbus_transaction_start(&xbt);
@@ -605,7 +602,7 @@ static pci_ers_result_t common_process(struct pcistub_device *psdev,
if (test_bit(_XEN_PCIF_active,
(unsigned long *)&psdev->pdev->sh_info->flags)) {
dev_dbg(&psdev->dev->dev,
- "schedule pci_conf service in xen_pcibk\n");
+ "schedule pci_conf service in " DRV_NAME "\n");
xen_pcibk_test_and_schedule_op(psdev->pdev);
}
@@ -995,8 +992,7 @@ out:
err = count;
return err;
}
-
-DRIVER_ATTR(new_slot, S_IWUSR, NULL, pcistub_slot_add);
+static DRIVER_ATTR(new_slot, S_IWUSR, NULL, pcistub_slot_add);
static ssize_t pcistub_slot_remove(struct device_driver *drv, const char *buf,
size_t count)
@@ -1015,8 +1011,7 @@ out:
err = count;
return err;
}
-
-DRIVER_ATTR(remove_slot, S_IWUSR, NULL, pcistub_slot_remove);
+static DRIVER_ATTR(remove_slot, S_IWUSR, NULL, pcistub_slot_remove);
static ssize_t pcistub_slot_show(struct device_driver *drv, char *buf)
{
@@ -1039,8 +1034,7 @@ static ssize_t pcistub_slot_show(struct device_driver *drv, char *buf)
return count;
}
-
-DRIVER_ATTR(slots, S_IRUSR, pcistub_slot_show, NULL);
+static DRIVER_ATTR(slots, S_IRUSR, pcistub_slot_show, NULL);
static ssize_t pcistub_irq_handler_show(struct device_driver *drv, char *buf)
{
@@ -1069,8 +1063,7 @@ static ssize_t pcistub_irq_handler_show(struct device_driver *drv, char *buf)
spin_unlock_irqrestore(&pcistub_devices_lock, flags);
return count;
}
-
-DRIVER_ATTR(irq_handlers, S_IRUSR, pcistub_irq_handler_show, NULL);
+static DRIVER_ATTR(irq_handlers, S_IRUSR, pcistub_irq_handler_show, NULL);
static ssize_t pcistub_irq_handler_switch(struct device_driver *drv,
const char *buf,
@@ -1106,7 +1099,8 @@ out:
err = count;
return err;
}
-DRIVER_ATTR(irq_handler_state, S_IWUSR, NULL, pcistub_irq_handler_switch);
+static DRIVER_ATTR(irq_handler_state, S_IWUSR, NULL,
+ pcistub_irq_handler_switch);
static ssize_t pcistub_quirk_add(struct device_driver *drv, const char *buf,
size_t count)
@@ -1170,8 +1164,8 @@ out:
return count;
}
-
-DRIVER_ATTR(quirks, S_IRUSR | S_IWUSR, pcistub_quirk_show, pcistub_quirk_add);
+static DRIVER_ATTR(quirks, S_IRUSR | S_IWUSR, pcistub_quirk_show,
+ pcistub_quirk_add);
static ssize_t permissive_add(struct device_driver *drv, const char *buf,
size_t count)
@@ -1236,8 +1230,8 @@ static ssize_t permissive_show(struct device_driver *drv, char *buf)
spin_unlock_irqrestore(&pcistub_devices_lock, flags);
return count;
}
-
-DRIVER_ATTR(permissive, S_IRUSR | S_IWUSR, permissive_show, permissive_add);
+static DRIVER_ATTR(permissive, S_IRUSR | S_IWUSR, permissive_show,
+ permissive_add);
static void pcistub_exit(void)
{
@@ -1374,3 +1368,4 @@ module_init(xen_pcibk_init);
module_exit(xen_pcibk_cleanup);
MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("xen-backend:pci");
diff --git a/drivers/xen/xen-pciback/pciback.h b/drivers/xen/xen-pciback/pciback.h
index a0e131a81503..e9b4011c5f9a 100644
--- a/drivers/xen/xen-pciback/pciback.h
+++ b/drivers/xen/xen-pciback/pciback.h
@@ -15,6 +15,8 @@
#include <linux/atomic.h>
#include <xen/interface/io/pciif.h>
+#define DRV_NAME "xen-pciback"
+
struct pci_dev_entry {
struct list_head list;
struct pci_dev *dev;
@@ -27,7 +29,7 @@ struct pci_dev_entry {
struct xen_pcibk_device {
void *pci_dev_data;
- spinlock_t dev_lock;
+ struct mutex dev_lock;
struct xenbus_device *xdev;
struct xenbus_watch be_watch;
u8 be_watching;
@@ -89,7 +91,7 @@ typedef int (*publish_pci_root_cb) (struct xen_pcibk_device *pdev,
* passthrough - BDFs are exactly like in the host.
*/
struct xen_pcibk_backend {
- char *name;
+ const char *name;
int (*init)(struct xen_pcibk_device *pdev);
void (*free)(struct xen_pcibk_device *pdev);
int (*find)(struct pci_dev *pcidev, struct xen_pcibk_device *pdev,
@@ -104,9 +106,9 @@ struct xen_pcibk_backend {
unsigned int devfn);
};
-extern struct xen_pcibk_backend xen_pcibk_vpci_backend;
-extern struct xen_pcibk_backend xen_pcibk_passthrough_backend;
-extern struct xen_pcibk_backend *xen_pcibk_backend;
+extern const struct xen_pcibk_backend xen_pcibk_vpci_backend;
+extern const struct xen_pcibk_backend xen_pcibk_passthrough_backend;
+extern const struct xen_pcibk_backend *xen_pcibk_backend;
static inline int xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev,
struct pci_dev *dev,
@@ -116,13 +118,14 @@ static inline int xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev,
if (xen_pcibk_backend && xen_pcibk_backend->add)
return xen_pcibk_backend->add(pdev, dev, devid, publish_cb);
return -1;
-};
+}
+
static inline void xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev,
struct pci_dev *dev)
{
if (xen_pcibk_backend && xen_pcibk_backend->free)
return xen_pcibk_backend->release(pdev, dev);
-};
+}
static inline struct pci_dev *
xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev, unsigned int domain,
@@ -131,7 +134,8 @@ xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev, unsigned int domain,
if (xen_pcibk_backend && xen_pcibk_backend->get)
return xen_pcibk_backend->get(pdev, domain, bus, devfn);
return NULL;
-};
+}
+
/**
* Add for domain0 PCIE-AER handling. Get guest domain/bus/devfn in xen_pcibk
* before sending aer request to pcifront, so that guest could identify
@@ -148,25 +152,29 @@ static inline int xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev,
return xen_pcibk_backend->find(pcidev, pdev, domain, bus,
devfn);
return -1;
-};
+}
+
static inline int xen_pcibk_init_devices(struct xen_pcibk_device *pdev)
{
if (xen_pcibk_backend && xen_pcibk_backend->init)
return xen_pcibk_backend->init(pdev);
return -1;
-};
+}
+
static inline int xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev,
publish_pci_root_cb cb)
{
if (xen_pcibk_backend && xen_pcibk_backend->publish)
return xen_pcibk_backend->publish(pdev, cb);
return -1;
-};
+}
+
static inline void xen_pcibk_release_devices(struct xen_pcibk_device *pdev)
{
if (xen_pcibk_backend && xen_pcibk_backend->free)
return xen_pcibk_backend->free(pdev);
-};
+}
+
/* Handles events from front-end */
irqreturn_t xen_pcibk_handle_event(int irq, void *dev_id);
void xen_pcibk_do_op(struct work_struct *data);
diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c
index 8c95c3415b75..63616d7453e6 100644
--- a/drivers/xen/xen-pciback/pciback_ops.c
+++ b/drivers/xen/xen-pciback/pciback_ops.c
@@ -10,7 +10,6 @@
#include <linux/sched.h>
#include "pciback.h"
-#define DRV_NAME "xen-pciback"
int verbose_request;
module_param(verbose_request, int, 0644);
diff --git a/drivers/xen/xen-pciback/vpci.c b/drivers/xen/xen-pciback/vpci.c
index 4a42cfb0959d..46d140baebd8 100644
--- a/drivers/xen/xen-pciback/vpci.c
+++ b/drivers/xen/xen-pciback/vpci.c
@@ -8,16 +8,15 @@
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/pci.h>
-#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include "pciback.h"
#define PCI_SLOT_MAX 32
-#define DRV_NAME "xen-pciback"
struct vpci_dev_data {
/* Access to dev_list must be protected by lock */
struct list_head dev_list[PCI_SLOT_MAX];
- spinlock_t lock;
+ struct mutex lock;
};
static inline struct list_head *list_first(struct list_head *head)
@@ -33,13 +32,12 @@ static struct pci_dev *__xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev,
struct pci_dev_entry *entry;
struct pci_dev *dev = NULL;
struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
- unsigned long flags;
if (domain != 0 || bus != 0)
return NULL;
if (PCI_SLOT(devfn) < PCI_SLOT_MAX) {
- spin_lock_irqsave(&vpci_dev->lock, flags);
+ mutex_lock(&vpci_dev->lock);
list_for_each_entry(entry,
&vpci_dev->dev_list[PCI_SLOT(devfn)],
@@ -50,7 +48,7 @@ static struct pci_dev *__xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev,
}
}
- spin_unlock_irqrestore(&vpci_dev->lock, flags);
+ mutex_unlock(&vpci_dev->lock);
}
return dev;
}
@@ -71,7 +69,6 @@ static int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev,
int err = 0, slot, func = -1;
struct pci_dev_entry *t, *dev_entry;
struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
- unsigned long flags;
if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
err = -EFAULT;
@@ -90,7 +87,7 @@ static int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev,
dev_entry->dev = dev;
- spin_lock_irqsave(&vpci_dev->lock, flags);
+ mutex_lock(&vpci_dev->lock);
/* Keep multi-function devices together on the virtual PCI bus */
for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
@@ -129,7 +126,7 @@ static int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev,
"No more space on root virtual PCI bus");
unlock:
- spin_unlock_irqrestore(&vpci_dev->lock, flags);
+ mutex_unlock(&vpci_dev->lock);
/* Publish this device. */
if (!err)
@@ -145,14 +142,13 @@ static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev,
int slot;
struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
struct pci_dev *found_dev = NULL;
- unsigned long flags;
- spin_lock_irqsave(&vpci_dev->lock, flags);
+ mutex_lock(&vpci_dev->lock);
for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
- struct pci_dev_entry *e, *tmp;
- list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
- list) {
+ struct pci_dev_entry *e;
+
+ list_for_each_entry(e, &vpci_dev->dev_list[slot], list) {
if (e->dev == dev) {
list_del(&e->list);
found_dev = e->dev;
@@ -163,7 +159,7 @@ static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev,
}
out:
- spin_unlock_irqrestore(&vpci_dev->lock, flags);
+ mutex_unlock(&vpci_dev->lock);
if (found_dev)
pcistub_put_pci_dev(found_dev);
@@ -178,7 +174,7 @@ static int __xen_pcibk_init_devices(struct xen_pcibk_device *pdev)
if (!vpci_dev)
return -ENOMEM;
- spin_lock_init(&vpci_dev->lock);
+ mutex_init(&vpci_dev->lock);
for (slot = 0; slot < PCI_SLOT_MAX; slot++)
INIT_LIST_HEAD(&vpci_dev->dev_list[slot]);
@@ -222,10 +218,9 @@ static int __xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev,
struct pci_dev_entry *entry;
struct pci_dev *dev = NULL;
struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
- unsigned long flags;
int found = 0, slot;
- spin_lock_irqsave(&vpci_dev->lock, flags);
+ mutex_lock(&vpci_dev->lock);
for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
list_for_each_entry(entry,
&vpci_dev->dev_list[slot],
@@ -243,11 +238,11 @@ static int __xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev,
}
}
}
- spin_unlock_irqrestore(&vpci_dev->lock, flags);
+ mutex_unlock(&vpci_dev->lock);
return found;
}
-struct xen_pcibk_backend xen_pcibk_vpci_backend = {
+const struct xen_pcibk_backend xen_pcibk_vpci_backend = {
.name = "vpci",
.init = __xen_pcibk_init_devices,
.free = __xen_pcibk_release_devices,
diff --git a/drivers/xen/xen-pciback/xenbus.c b/drivers/xen/xen-pciback/xenbus.c
index 978d2c6f5dca..075525945e36 100644
--- a/drivers/xen/xen-pciback/xenbus.c
+++ b/drivers/xen/xen-pciback/xenbus.c
@@ -13,7 +13,6 @@
#include <asm/xen/pci.h>
#include "pciback.h"
-#define DRV_NAME "xen-pciback"
#define INVALID_EVTCHN_IRQ (-1)
struct workqueue_struct *xen_pcibk_wq;
@@ -44,7 +43,7 @@ static struct xen_pcibk_device *alloc_pdev(struct xenbus_device *xdev)
pdev->xdev = xdev;
dev_set_drvdata(&xdev->dev, pdev);
- spin_lock_init(&pdev->dev_lock);
+ mutex_init(&pdev->dev_lock);
pdev->sh_info = NULL;
pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
@@ -62,14 +61,12 @@ out:
static void xen_pcibk_disconnect(struct xen_pcibk_device *pdev)
{
- spin_lock(&pdev->dev_lock);
-
+ mutex_lock(&pdev->dev_lock);
/* Ensure the guest can't trigger our handler before removing devices */
if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ) {
unbind_from_irqhandler(pdev->evtchn_irq, pdev);
pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
}
- spin_unlock(&pdev->dev_lock);
/* If the driver domain started an op, make sure we complete it
* before releasing the shared memory */
@@ -77,13 +74,11 @@ static void xen_pcibk_disconnect(struct xen_pcibk_device *pdev)
/* Note, the workqueue does not use spinlocks at all.*/
flush_workqueue(xen_pcibk_wq);
- spin_lock(&pdev->dev_lock);
if (pdev->sh_info != NULL) {
xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info);
pdev->sh_info = NULL;
}
- spin_unlock(&pdev->dev_lock);
-
+ mutex_unlock(&pdev->dev_lock);
}
static void free_pdev(struct xen_pcibk_device *pdev)
@@ -120,9 +115,7 @@ static int xen_pcibk_do_attach(struct xen_pcibk_device *pdev, int gnt_ref,
goto out;
}
- spin_lock(&pdev->dev_lock);
pdev->sh_info = vaddr;
- spin_unlock(&pdev->dev_lock);
err = bind_interdomain_evtchn_to_irqhandler(
pdev->xdev->otherend_id, remote_evtchn, xen_pcibk_handle_event,
@@ -132,10 +125,7 @@ static int xen_pcibk_do_attach(struct xen_pcibk_device *pdev, int gnt_ref,
"Error binding event channel to IRQ");
goto out;
}
-
- spin_lock(&pdev->dev_lock);
pdev->evtchn_irq = err;
- spin_unlock(&pdev->dev_lock);
err = 0;
dev_dbg(&pdev->xdev->dev, "Attached!\n");
@@ -150,6 +140,7 @@ static int xen_pcibk_attach(struct xen_pcibk_device *pdev)
char *magic = NULL;
+ mutex_lock(&pdev->dev_lock);
/* Make sure we only do this setup once */
if (xenbus_read_driver_state(pdev->xdev->nodename) !=
XenbusStateInitialised)
@@ -176,7 +167,7 @@ static int xen_pcibk_attach(struct xen_pcibk_device *pdev)
if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) {
xenbus_dev_fatal(pdev->xdev, -EFAULT,
"version mismatch (%s/%s) with pcifront - "
- "halting xen_pcibk",
+ "halting " DRV_NAME,
magic, XEN_PCI_MAGIC);
goto out;
}
@@ -194,6 +185,7 @@ static int xen_pcibk_attach(struct xen_pcibk_device *pdev)
dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
out:
+ mutex_unlock(&pdev->dev_lock);
kfree(magic);
@@ -249,6 +241,7 @@ static int xen_pcibk_export_device(struct xen_pcibk_device *pdev,
goto out;
dev_dbg(&dev->dev, "registering for %d\n", pdev->xdev->otherend_id);
+ dev->dev_flags |= PCI_DEV_FLAGS_ASSIGNED;
if (xen_register_device_domain_owner(dev,
pdev->xdev->otherend_id) != 0) {
dev_err(&dev->dev, "device has been assigned to another " \
@@ -288,6 +281,7 @@ static int xen_pcibk_remove_device(struct xen_pcibk_device *pdev,
}
dev_dbg(&dev->dev, "unregistering for %d\n", pdev->xdev->otherend_id);
+ dev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED;
xen_unregister_device_domain_owner(dev);
xen_pcibk_release_pci_dev(pdev, dev);
@@ -369,6 +363,7 @@ static int xen_pcibk_reconfigure(struct xen_pcibk_device *pdev)
dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n");
+ mutex_lock(&pdev->dev_lock);
/* Make sure we only reconfigure once */
if (xenbus_read_driver_state(pdev->xdev->nodename) !=
XenbusStateReconfiguring)
@@ -506,6 +501,7 @@ static int xen_pcibk_reconfigure(struct xen_pcibk_device *pdev)
}
out:
+ mutex_unlock(&pdev->dev_lock);
return 0;
}
@@ -562,6 +558,7 @@ static int xen_pcibk_setup_backend(struct xen_pcibk_device *pdev)
char dev_str[64];
char state_str[64];
+ mutex_lock(&pdev->dev_lock);
/* It's possible we could get the call to setup twice, so make sure
* we're not already connected.
*/
@@ -642,10 +639,10 @@ static int xen_pcibk_setup_backend(struct xen_pcibk_device *pdev)
"Error switching to initialised state!");
out:
+ mutex_unlock(&pdev->dev_lock);
if (!err)
/* see if pcifront is already configured (if not, we'll wait) */
xen_pcibk_attach(pdev);
-
return err;
}
@@ -724,7 +721,7 @@ static struct xenbus_driver xenbus_xen_pcibk_driver = {
.otherend_changed = xen_pcibk_frontend_changed,
};
-struct xen_pcibk_backend *xen_pcibk_backend;
+const struct xen_pcibk_backend *__read_mostly xen_pcibk_backend;
int __init xen_pcibk_xenbus_register(void)
{
diff --git a/drivers/xen/xen-selfballoon.c b/drivers/xen/xen-selfballoon.c
index 6ea852e25162..d93c70857e03 100644
--- a/drivers/xen/xen-selfballoon.c
+++ b/drivers/xen/xen-selfballoon.c
@@ -68,6 +68,8 @@
*/
#include <linux/kernel.h>
+#include <linux/bootmem.h>
+#include <linux/swap.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/module.h>
@@ -93,6 +95,15 @@ static unsigned int selfballoon_uphysteresis __read_mostly = 1;
/* In HZ, controls frequency of worker invocation. */
static unsigned int selfballoon_interval __read_mostly = 5;
+/*
+ * Minimum usable RAM in MB for selfballooning target for balloon.
+ * If non-zero, it is added to totalreserve_pages and self-ballooning
+ * will not balloon below the sum. If zero, a piecewise linear function
+ * is calculated as a minimum and added to totalreserve_pages. Note that
+ * setting this value indiscriminately may cause OOMs and crashes.
+ */
+static unsigned int selfballoon_min_usable_mb;
+
static void selfballoon_process(struct work_struct *work);
static DECLARE_DELAYED_WORK(selfballoon_worker, selfballoon_process);
@@ -189,20 +200,23 @@ static int __init xen_selfballooning_setup(char *s)
__setup("selfballooning", xen_selfballooning_setup);
#endif /* CONFIG_FRONTSWAP */
+#define MB2PAGES(mb) ((mb) << (20 - PAGE_SHIFT))
+
/*
* Use current balloon size, the goal (vm_committed_as), and hysteresis
* parameters to set a new target balloon size
*/
static void selfballoon_process(struct work_struct *work)
{
- unsigned long cur_pages, goal_pages, tgt_pages;
+ unsigned long cur_pages, goal_pages, tgt_pages, floor_pages;
+ unsigned long useful_pages;
bool reset_timer = false;
if (xen_selfballooning_enabled) {
- cur_pages = balloon_stats.current_pages;
+ cur_pages = totalram_pages;
tgt_pages = cur_pages; /* default is no change */
goal_pages = percpu_counter_read_positive(&vm_committed_as) +
- balloon_stats.current_pages - totalram_pages;
+ totalreserve_pages;
#ifdef CONFIG_FRONTSWAP
/* allow space for frontswap pages to be repatriated */
if (frontswap_selfshrinking && frontswap_enabled)
@@ -217,7 +231,26 @@ static void selfballoon_process(struct work_struct *work)
((goal_pages - cur_pages) /
selfballoon_uphysteresis);
/* else if cur_pages == goal_pages, no change */
- balloon_set_new_target(tgt_pages);
+ useful_pages = max_pfn - totalreserve_pages;
+ if (selfballoon_min_usable_mb != 0)
+ floor_pages = totalreserve_pages +
+ MB2PAGES(selfballoon_min_usable_mb);
+ /* piecewise linear function ending in ~3% slope */
+ else if (useful_pages < MB2PAGES(16))
+ floor_pages = max_pfn; /* not worth ballooning */
+ else if (useful_pages < MB2PAGES(64))
+ floor_pages = totalreserve_pages + MB2PAGES(16) +
+ ((useful_pages - MB2PAGES(16)) >> 1);
+ else if (useful_pages < MB2PAGES(512))
+ floor_pages = totalreserve_pages + MB2PAGES(40) +
+ ((useful_pages - MB2PAGES(40)) >> 3);
+ else /* useful_pages >= MB2PAGES(512) */
+ floor_pages = totalreserve_pages + MB2PAGES(99) +
+ ((useful_pages - MB2PAGES(99)) >> 5);
+ if (tgt_pages < floor_pages)
+ tgt_pages = floor_pages;
+ balloon_set_new_target(tgt_pages +
+ balloon_stats.current_pages - totalram_pages);
reset_timer = true;
}
#ifdef CONFIG_FRONTSWAP
@@ -340,6 +373,31 @@ static ssize_t store_selfballoon_uphys(struct sys_device *dev,
static SYSDEV_ATTR(selfballoon_uphysteresis, S_IRUGO | S_IWUSR,
show_selfballoon_uphys, store_selfballoon_uphys);
+SELFBALLOON_SHOW(selfballoon_min_usable_mb, "%d\n",
+ selfballoon_min_usable_mb);
+
+static ssize_t store_selfballoon_min_usable_mb(struct sys_device *dev,
+ struct sysdev_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ unsigned long val;
+ int err;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ err = strict_strtoul(buf, 10, &val);
+ if (err || val == 0)
+ return -EINVAL;
+ selfballoon_min_usable_mb = val;
+ return count;
+}
+
+static SYSDEV_ATTR(selfballoon_min_usable_mb, S_IRUGO | S_IWUSR,
+ show_selfballoon_min_usable_mb,
+ store_selfballoon_min_usable_mb);
+
+
#ifdef CONFIG_FRONTSWAP
SELFBALLOON_SHOW(frontswap_selfshrinking, "%d\n", frontswap_selfshrinking);
@@ -421,6 +479,7 @@ static struct attribute *selfballoon_attrs[] = {
&attr_selfballoon_interval.attr,
&attr_selfballoon_downhysteresis.attr,
&attr_selfballoon_uphysteresis.attr,
+ &attr_selfballoon_min_usable_mb.attr,
#ifdef CONFIG_FRONTSWAP
&attr_frontswap_selfshrinking.attr,
&attr_frontswap_hysteresis.attr,
diff --git a/drivers/xen/xenbus/xenbus_comms.c b/drivers/xen/xenbus/xenbus_comms.c
index 090c61ee8fd0..2eff7a6aaa20 100644
--- a/drivers/xen/xenbus/xenbus_comms.c
+++ b/drivers/xen/xenbus/xenbus_comms.c
@@ -212,7 +212,9 @@ int xb_init_comms(void)
printk(KERN_WARNING "XENBUS response ring is not quiescent "
"(%08x:%08x): fixing up\n",
intf->rsp_cons, intf->rsp_prod);
- intf->rsp_cons = intf->rsp_prod;
+ /* breaks kdump */
+ if (!reset_devices)
+ intf->rsp_cons = intf->rsp_prod;
}
if (xenbus_irq) {
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index bd2f90c9ac8b..cef9b0bf63d5 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -684,64 +684,74 @@ static int __init xenbus_probe_initcall(void)
device_initcall(xenbus_probe_initcall);
-static int __init xenbus_init(void)
+/* Set up event channel for xenstored which is run as a local process
+ * (this is normally used only in dom0)
+ */
+static int __init xenstored_local_init(void)
{
int err = 0;
unsigned long page = 0;
+ struct evtchn_alloc_unbound alloc_unbound;
- DPRINTK("");
+ /* Allocate Xenstore page */
+ page = get_zeroed_page(GFP_KERNEL);
+ if (!page)
+ goto out_err;
- err = -ENODEV;
- if (!xen_domain())
- return err;
+ xen_store_mfn = xen_start_info->store_mfn =
+ pfn_to_mfn(virt_to_phys((void *)page) >>
+ PAGE_SHIFT);
- /*
- * Domain0 doesn't have a store_evtchn or store_mfn yet.
- */
- if (xen_initial_domain()) {
- struct evtchn_alloc_unbound alloc_unbound;
+ /* Next allocate a local port which xenstored can bind to */
+ alloc_unbound.dom = DOMID_SELF;
+ alloc_unbound.remote_dom = DOMID_SELF;
- /* Allocate Xenstore page */
- page = get_zeroed_page(GFP_KERNEL);
- if (!page)
- goto out_error;
+ err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
+ &alloc_unbound);
+ if (err == -ENOSYS)
+ goto out_err;
- xen_store_mfn = xen_start_info->store_mfn =
- pfn_to_mfn(virt_to_phys((void *)page) >>
- PAGE_SHIFT);
+ BUG_ON(err);
+ xen_store_evtchn = xen_start_info->store_evtchn =
+ alloc_unbound.port;
- /* Next allocate a local port which xenstored can bind to */
- alloc_unbound.dom = DOMID_SELF;
- alloc_unbound.remote_dom = 0;
+ return 0;
- err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
- &alloc_unbound);
- if (err == -ENOSYS)
- goto out_error;
+ out_err:
+ if (page != 0)
+ free_page(page);
+ return err;
+}
- BUG_ON(err);
- xen_store_evtchn = xen_start_info->store_evtchn =
- alloc_unbound.port;
+static int __init xenbus_init(void)
+{
+ int err = 0;
- xen_store_interface = mfn_to_virt(xen_store_mfn);
+ if (!xen_domain())
+ return -ENODEV;
+
+ if (xen_hvm_domain()) {
+ uint64_t v = 0;
+ err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v);
+ if (err)
+ goto out_error;
+ xen_store_evtchn = (int)v;
+ err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v);
+ if (err)
+ goto out_error;
+ xen_store_mfn = (unsigned long)v;
+ xen_store_interface = ioremap(xen_store_mfn << PAGE_SHIFT, PAGE_SIZE);
} else {
- if (xen_hvm_domain()) {
- uint64_t v = 0;
- err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v);
- if (err)
- goto out_error;
- xen_store_evtchn = (int)v;
- err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v);
+ xen_store_evtchn = xen_start_info->store_evtchn;
+ xen_store_mfn = xen_start_info->store_mfn;
+ if (xen_store_evtchn)
+ xenstored_ready = 1;
+ else {
+ err = xenstored_local_init();
if (err)
goto out_error;
- xen_store_mfn = (unsigned long)v;
- xen_store_interface = ioremap(xen_store_mfn << PAGE_SHIFT, PAGE_SIZE);
- } else {
- xen_store_evtchn = xen_start_info->store_evtchn;
- xen_store_mfn = xen_start_info->store_mfn;
- xen_store_interface = mfn_to_virt(xen_store_mfn);
- xenstored_ready = 1;
}
+ xen_store_interface = mfn_to_virt(xen_store_mfn);
}
/* Initialize the interface to xenstore. */
@@ -760,12 +770,7 @@ static int __init xenbus_init(void)
proc_mkdir("xen", NULL);
#endif
- return 0;
-
- out_error:
- if (page != 0)
- free_page(page);
-
+ out_error:
return err;
}
diff --git a/drivers/xen/xenbus/xenbus_probe_backend.c b/drivers/xen/xenbus/xenbus_probe_backend.c
index 60adf919d78d..32417b5064fd 100644
--- a/drivers/xen/xenbus/xenbus_probe_backend.c
+++ b/drivers/xen/xenbus/xenbus_probe_backend.c
@@ -104,8 +104,6 @@ static int xenbus_uevent_backend(struct device *dev,
xdev = to_xenbus_device(dev);
bus = container_of(xdev->dev.bus, struct xen_bus_type, bus);
- if (xdev == NULL)
- return -ENODEV;
if (add_uevent_var(env, "MODALIAS=xen-backend:%s", xdev->devicetype))
return -ENOMEM;
diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c
index ed2ba474a560..540587e18a94 100644
--- a/drivers/xen/xenbus/xenbus_probe_frontend.c
+++ b/drivers/xen/xenbus/xenbus_probe_frontend.c
@@ -248,10 +248,131 @@ int __xenbus_register_frontend(struct xenbus_driver *drv,
}
EXPORT_SYMBOL_GPL(__xenbus_register_frontend);
+static DECLARE_WAIT_QUEUE_HEAD(backend_state_wq);
+static int backend_state;
+
+static void xenbus_reset_backend_state_changed(struct xenbus_watch *w,
+ const char **v, unsigned int l)
+{
+ xenbus_scanf(XBT_NIL, v[XS_WATCH_PATH], "", "%i", &backend_state);
+ printk(KERN_DEBUG "XENBUS: backend %s %s\n",
+ v[XS_WATCH_PATH], xenbus_strstate(backend_state));
+ wake_up(&backend_state_wq);
+}
+
+static void xenbus_reset_wait_for_backend(char *be, int expected)
+{
+ long timeout;
+ timeout = wait_event_interruptible_timeout(backend_state_wq,
+ backend_state == expected, 5 * HZ);
+ if (timeout <= 0)
+ printk(KERN_INFO "XENBUS: backend %s timed out.\n", be);
+}
+
+/*
+ * Reset frontend if it is in Connected or Closed state.
+ * Wait for backend to catch up.
+ * State Connected happens during kdump, Closed after kexec.
+ */
+static void xenbus_reset_frontend(char *fe, char *be, int be_state)
+{
+ struct xenbus_watch be_watch;
+
+ printk(KERN_DEBUG "XENBUS: backend %s %s\n",
+ be, xenbus_strstate(be_state));
+
+ memset(&be_watch, 0, sizeof(be_watch));
+ be_watch.node = kasprintf(GFP_NOIO | __GFP_HIGH, "%s/state", be);
+ if (!be_watch.node)
+ return;
+
+ be_watch.callback = xenbus_reset_backend_state_changed;
+ backend_state = XenbusStateUnknown;
+
+ printk(KERN_INFO "XENBUS: triggering reconnect on %s\n", be);
+ register_xenbus_watch(&be_watch);
+
+ /* fall through to forward backend to state XenbusStateInitialising */
+ switch (be_state) {
+ case XenbusStateConnected:
+ xenbus_printf(XBT_NIL, fe, "state", "%d", XenbusStateClosing);
+ xenbus_reset_wait_for_backend(be, XenbusStateClosing);
+
+ case XenbusStateClosing:
+ xenbus_printf(XBT_NIL, fe, "state", "%d", XenbusStateClosed);
+ xenbus_reset_wait_for_backend(be, XenbusStateClosed);
+
+ case XenbusStateClosed:
+ xenbus_printf(XBT_NIL, fe, "state", "%d", XenbusStateInitialising);
+ xenbus_reset_wait_for_backend(be, XenbusStateInitWait);
+ }
+
+ unregister_xenbus_watch(&be_watch);
+ printk(KERN_INFO "XENBUS: reconnect done on %s\n", be);
+ kfree(be_watch.node);
+}
+
+static void xenbus_check_frontend(char *class, char *dev)
+{
+ int be_state, fe_state, err;
+ char *backend, *frontend;
+
+ frontend = kasprintf(GFP_NOIO | __GFP_HIGH, "device/%s/%s", class, dev);
+ if (!frontend)
+ return;
+
+ err = xenbus_scanf(XBT_NIL, frontend, "state", "%i", &fe_state);
+ if (err != 1)
+ goto out;
+
+ switch (fe_state) {
+ case XenbusStateConnected:
+ case XenbusStateClosed:
+ printk(KERN_DEBUG "XENBUS: frontend %s %s\n",
+ frontend, xenbus_strstate(fe_state));
+ backend = xenbus_read(XBT_NIL, frontend, "backend", NULL);
+ if (!backend || IS_ERR(backend))
+ goto out;
+ err = xenbus_scanf(XBT_NIL, backend, "state", "%i", &be_state);
+ if (err == 1)
+ xenbus_reset_frontend(frontend, backend, be_state);
+ kfree(backend);
+ break;
+ default:
+ break;
+ }
+out:
+ kfree(frontend);
+}
+
+static void xenbus_reset_state(void)
+{
+ char **devclass, **dev;
+ int devclass_n, dev_n;
+ int i, j;
+
+ devclass = xenbus_directory(XBT_NIL, "device", "", &devclass_n);
+ if (IS_ERR(devclass))
+ return;
+
+ for (i = 0; i < devclass_n; i++) {
+ dev = xenbus_directory(XBT_NIL, "device", devclass[i], &dev_n);
+ if (IS_ERR(dev))
+ continue;
+ for (j = 0; j < dev_n; j++)
+ xenbus_check_frontend(devclass[i], dev[j]);
+ kfree(dev);
+ }
+ kfree(devclass);
+}
+
static int frontend_probe_and_watch(struct notifier_block *notifier,
unsigned long event,
void *data)
{
+ /* reset devices in Connected or Closed state */
+ if (xen_hvm_domain())
+ xenbus_reset_state();
/* Enumerate devices in xenstore and watch for changes. */
xenbus_probe_devices(&xenbus_frontend);
register_xenbus_watch(&fe_watch);
diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c
index 5534690075af..b3b8f2f3ad10 100644
--- a/drivers/xen/xenbus/xenbus_xs.c
+++ b/drivers/xen/xenbus/xenbus_xs.c
@@ -45,6 +45,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <xen/xenbus.h>
+#include <xen/xen.h>
#include "xenbus_comms.h"
struct xs_stored_msg {
@@ -620,6 +621,15 @@ static struct xenbus_watch *find_watch(const char *token)
return NULL;
}
+static void xs_reset_watches(void)
+{
+ int err;
+
+ err = xs_error(xs_single(XBT_NIL, XS_RESET_WATCHES, "", NULL));
+ if (err && err != -EEXIST)
+ printk(KERN_WARNING "xs_reset_watches failed: %d\n", err);
+}
+
/* Register callback to watch this node. */
int register_xenbus_watch(struct xenbus_watch *watch)
{
@@ -638,8 +648,7 @@ int register_xenbus_watch(struct xenbus_watch *watch)
err = xs_watch(watch->node, token);
- /* Ignore errors due to multiple registration. */
- if ((err != 0) && (err != -EEXIST)) {
+ if (err) {
spin_lock(&watches_lock);
list_del(&watch->list);
spin_unlock(&watches_lock);
@@ -897,5 +906,9 @@ int xs_init(void)
if (IS_ERR(task))
return PTR_ERR(task);
+ /* shutdown watches for kexec boot */
+ if (xen_hvm_domain())
+ xs_reset_watches();
+
return 0;
}
diff --git a/drivers/zorro/zorro-driver.c b/drivers/zorro/zorro-driver.c
index 7ee2b6e71786..229624f867d3 100644
--- a/drivers/zorro/zorro-driver.c
+++ b/drivers/zorro/zorro-driver.c
@@ -37,6 +37,7 @@ zorro_match_device(const struct zorro_device_id *ids,
}
return NULL;
}
+EXPORT_SYMBOL(zorro_match_device);
static int zorro_device_probe(struct device *dev)
@@ -91,6 +92,7 @@ int zorro_register_driver(struct zorro_driver *drv)
/* register with core */
return driver_register(&drv->driver);
}
+EXPORT_SYMBOL(zorro_register_driver);
/**
@@ -107,6 +109,7 @@ void zorro_unregister_driver(struct zorro_driver *drv)
{
driver_unregister(&drv->driver);
}
+EXPORT_SYMBOL(zorro_unregister_driver);
/**
@@ -168,6 +171,7 @@ struct bus_type zorro_bus_type = {
.probe = zorro_device_probe,
.remove = zorro_device_remove,
};
+EXPORT_SYMBOL(zorro_bus_type);
static int __init zorro_driver_init(void)
@@ -177,7 +181,3 @@ static int __init zorro_driver_init(void)
postcore_initcall(zorro_driver_init);
-EXPORT_SYMBOL(zorro_match_device);
-EXPORT_SYMBOL(zorro_register_driver);
-EXPORT_SYMBOL(zorro_unregister_driver);
-EXPORT_SYMBOL(zorro_bus_type);
diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c
index e0c2807b0970..181fa8158a8b 100644
--- a/drivers/zorro/zorro.c
+++ b/drivers/zorro/zorro.c
@@ -148,10 +148,10 @@ static int __init amiga_zorro_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, bus);
- /* Register all devices */
pr_info("Zorro: Probing AutoConfig expansion devices: %u device%s\n",
zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s");
+ /* First identify all devices ... */
for (i = 0; i < zorro_num_autocon; i++) {
z = &zorro_autocon[i];
z->id = (z->rom.er_Manufacturer<<16) | (z->rom.er_Product<<8);
@@ -172,6 +172,11 @@ static int __init amiga_zorro_probe(struct platform_device *pdev)
dev_set_name(&z->dev, "%02x", i);
z->dev.parent = &bus->dev;
z->dev.bus = &zorro_bus_type;
+ }
+
+ /* ... then register them */
+ for (i = 0; i < zorro_num_autocon; i++) {
+ z = &zorro_autocon[i];
error = device_register(&z->dev);
if (error) {
dev_err(&bus->dev, "Error registering device %s\n",
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index ef9661886112..2b78014a124a 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -132,21 +132,19 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
options = tmp_options;
while ((p = strsep(&options, ",")) != NULL) {
- int token;
+ int token, r;
if (!*p)
continue;
token = match_token(p, tokens, args);
- if (token < Opt_uname) {
- int r = match_int(&args[0], &option);
+ switch (token) {
+ case Opt_debug:
+ r = match_int(&args[0], &option);
if (r < 0) {
P9_DPRINTK(P9_DEBUG_ERROR,
- "integer field, but no integer?\n");
+ "integer field, but no integer?\n");
ret = r;
continue;
}
- }
- switch (token) {
- case Opt_debug:
v9ses->debug = option;
#ifdef CONFIG_NET_9P_DEBUG
p9_debug_level = option;
@@ -154,12 +152,33 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
break;
case Opt_dfltuid:
+ r = match_int(&args[0], &option);
+ if (r < 0) {
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "integer field, but no integer?\n");
+ ret = r;
+ continue;
+ }
v9ses->dfltuid = option;
break;
case Opt_dfltgid:
+ r = match_int(&args[0], &option);
+ if (r < 0) {
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "integer field, but no integer?\n");
+ ret = r;
+ continue;
+ }
v9ses->dfltgid = option;
break;
case Opt_afid:
+ r = match_int(&args[0], &option);
+ if (r < 0) {
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "integer field, but no integer?\n");
+ ret = r;
+ continue;
+ }
v9ses->afid = option;
break;
case Opt_uname:
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index 46ce357ca1ab..410ffd6ceb5f 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -54,9 +54,9 @@ extern struct kmem_cache *v9fs_inode_cache;
struct inode *v9fs_alloc_inode(struct super_block *sb);
void v9fs_destroy_inode(struct inode *inode);
-struct inode *v9fs_get_inode(struct super_block *sb, int mode);
+struct inode *v9fs_get_inode(struct super_block *sb, int mode, dev_t);
int v9fs_init_inode(struct v9fs_session_info *v9ses,
- struct inode *inode, int mode);
+ struct inode *inode, int mode, dev_t);
void v9fs_evict_inode(struct inode *inode);
ino_t v9fs_qid2ino(struct p9_qid *qid);
void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *);
@@ -83,4 +83,6 @@ static inline void v9fs_invalidate_inode_attr(struct inode *inode)
v9inode->cache_validity |= V9FS_INO_INVALID_ATTR;
return;
}
+
+int v9fs_open_to_dotl_flags(int flags);
#endif
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index 9c2bdda5cd9d..598fff1a54e5 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -165,9 +165,8 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
while (rdir->head < rdir->tail) {
p9stat_init(&st);
- err = p9stat_read(rdir->buf + rdir->head,
- rdir->tail - rdir->head, &st,
- fid->clnt->proto_version);
+ err = p9stat_read(fid->clnt, rdir->buf + rdir->head,
+ rdir->tail - rdir->head, &st);
if (err) {
P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
err = -EIO;
@@ -231,7 +230,7 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
while (err == 0) {
if (rdir->tail == rdir->head) {
err = p9_client_readdir(fid, rdir->buf, buflen,
- filp->f_pos);
+ filp->f_pos);
if (err <= 0)
goto unlock_and_exit;
@@ -241,10 +240,9 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
while (rdir->head < rdir->tail) {
- err = p9dirent_read(rdir->buf + rdir->head,
- rdir->tail - rdir->head,
- &curdirent,
- fid->clnt->proto_version);
+ err = p9dirent_read(fid->clnt, rdir->buf + rdir->head,
+ rdir->tail - rdir->head,
+ &curdirent);
if (err < 0) {
P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
err = -EIO;
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index 3c173fcc2c5a..62857a810a79 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -65,7 +65,7 @@ int v9fs_file_open(struct inode *inode, struct file *file)
v9inode = V9FS_I(inode);
v9ses = v9fs_inode2v9ses(inode);
if (v9fs_proto_dotl(v9ses))
- omode = file->f_flags;
+ omode = v9fs_open_to_dotl_flags(file->f_flags);
else
omode = v9fs_uflags2omode(file->f_flags,
v9fs_proto_dotu(v9ses));
@@ -169,7 +169,18 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
/* convert posix lock to p9 tlock args */
memset(&flock, 0, sizeof(flock));
- flock.type = fl->fl_type;
+ /* map the lock type */
+ switch (fl->fl_type) {
+ case F_RDLCK:
+ flock.type = P9_LOCK_TYPE_RDLCK;
+ break;
+ case F_WRLCK:
+ flock.type = P9_LOCK_TYPE_WRLCK;
+ break;
+ case F_UNLCK:
+ flock.type = P9_LOCK_TYPE_UNLCK;
+ break;
+ }
flock.start = fl->fl_start;
if (fl->fl_end == OFFSET_MAX)
flock.length = 0;
@@ -245,7 +256,7 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
/* convert posix lock to p9 tgetlock args */
memset(&glock, 0, sizeof(glock));
- glock.type = fl->fl_type;
+ glock.type = P9_LOCK_TYPE_UNLCK;
glock.start = fl->fl_start;
if (fl->fl_end == OFFSET_MAX)
glock.length = 0;
@@ -257,17 +268,26 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
res = p9_client_getlock_dotl(fid, &glock);
if (res < 0)
return res;
- if (glock.type != F_UNLCK) {
- fl->fl_type = glock.type;
+ /* map 9p lock type to os lock type */
+ switch (glock.type) {
+ case P9_LOCK_TYPE_RDLCK:
+ fl->fl_type = F_RDLCK;
+ break;
+ case P9_LOCK_TYPE_WRLCK:
+ fl->fl_type = F_WRLCK;
+ break;
+ case P9_LOCK_TYPE_UNLCK:
+ fl->fl_type = F_UNLCK;
+ break;
+ }
+ if (glock.type != P9_LOCK_TYPE_UNLCK) {
fl->fl_start = glock.start;
if (glock.length == 0)
fl->fl_end = OFFSET_MAX;
else
fl->fl_end = glock.start + glock.length - 1;
fl->fl_pid = glock.proc_id;
- } else
- fl->fl_type = F_UNLCK;
-
+ }
return res;
}
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 8bb5507e822f..b5a1076aaa6c 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -95,15 +95,18 @@ static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode)
/**
* p9mode2unixmode- convert plan9 mode bits to unix mode bits
* @v9ses: v9fs session information
- * @mode: mode to convert
+ * @stat: p9_wstat from which mode need to be derived
+ * @rdev: major number, minor number in case of device files.
*
*/
-
-static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
+static int p9mode2unixmode(struct v9fs_session_info *v9ses,
+ struct p9_wstat *stat, dev_t *rdev)
{
int res;
+ int mode = stat->mode;
- res = mode & 0777;
+ res = mode & S_IALLUGO;
+ *rdev = 0;
if ((mode & P9_DMDIR) == P9_DMDIR)
res |= S_IFDIR;
@@ -116,9 +119,26 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
&& (v9ses->nodev == 0))
res |= S_IFIFO;
else if ((mode & P9_DMDEVICE) && (v9fs_proto_dotu(v9ses))
- && (v9ses->nodev == 0))
- res |= S_IFBLK;
- else
+ && (v9ses->nodev == 0)) {
+ char type = 0, ext[32];
+ int major = -1, minor = -1;
+
+ strncpy(ext, stat->extension, sizeof(ext));
+ sscanf(ext, "%c %u %u", &type, &major, &minor);
+ switch (type) {
+ case 'c':
+ res |= S_IFCHR;
+ break;
+ case 'b':
+ res |= S_IFBLK;
+ break;
+ default:
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "Unknown special type %c %s\n", type,
+ stat->extension);
+ };
+ *rdev = MKDEV(major, minor);
+ } else
res |= S_IFREG;
if (v9fs_proto_dotu(v9ses)) {
@@ -131,7 +151,6 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
if ((mode & P9_DMSETVTX) == P9_DMSETVTX)
res |= S_ISVTX;
}
-
return res;
}
@@ -242,13 +261,13 @@ void v9fs_destroy_inode(struct inode *inode)
}
int v9fs_init_inode(struct v9fs_session_info *v9ses,
- struct inode *inode, int mode)
+ struct inode *inode, int mode, dev_t rdev)
{
int err = 0;
inode_init_owner(inode, NULL, mode);
inode->i_blocks = 0;
- inode->i_rdev = 0;
+ inode->i_rdev = rdev;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_mapping->a_ops = &v9fs_addr_operations;
@@ -259,10 +278,8 @@ int v9fs_init_inode(struct v9fs_session_info *v9ses,
case S_IFSOCK:
if (v9fs_proto_dotl(v9ses)) {
inode->i_op = &v9fs_file_inode_operations_dotl;
- inode->i_fop = &v9fs_file_operations_dotl;
} else if (v9fs_proto_dotu(v9ses)) {
inode->i_op = &v9fs_file_inode_operations;
- inode->i_fop = &v9fs_file_operations;
} else {
P9_DPRINTK(P9_DEBUG_ERROR,
"special files without extended mode\n");
@@ -335,7 +352,7 @@ error:
*
*/
-struct inode *v9fs_get_inode(struct super_block *sb, int mode)
+struct inode *v9fs_get_inode(struct super_block *sb, int mode, dev_t rdev)
{
int err;
struct inode *inode;
@@ -348,7 +365,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n");
return ERR_PTR(-ENOMEM);
}
- err = v9fs_init_inode(v9ses, inode, mode);
+ err = v9fs_init_inode(v9ses, inode, mode, rdev);
if (err) {
iput(inode);
return ERR_PTR(err);
@@ -435,11 +452,12 @@ void v9fs_evict_inode(struct inode *inode)
static int v9fs_test_inode(struct inode *inode, void *data)
{
int umode;
+ dev_t rdev;
struct v9fs_inode *v9inode = V9FS_I(inode);
struct p9_wstat *st = (struct p9_wstat *)data;
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
- umode = p9mode2unixmode(v9ses, st->mode);
+ umode = p9mode2unixmode(v9ses, st, &rdev);
/* don't match inode of different type */
if ((inode->i_mode & S_IFMT) != (umode & S_IFMT))
return 0;
@@ -473,6 +491,7 @@ static struct inode *v9fs_qid_iget(struct super_block *sb,
struct p9_wstat *st,
int new)
{
+ dev_t rdev;
int retval, umode;
unsigned long i_ino;
struct inode *inode;
@@ -496,8 +515,8 @@ static struct inode *v9fs_qid_iget(struct super_block *sb,
* later.
*/
inode->i_ino = i_ino;
- umode = p9mode2unixmode(v9ses, st->mode);
- retval = v9fs_init_inode(v9ses, inode, umode);
+ umode = p9mode2unixmode(v9ses, st, &rdev);
+ retval = v9fs_init_inode(v9ses, inode, umode, rdev);
if (retval)
goto error;
@@ -532,6 +551,19 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
}
/**
+ * v9fs_at_to_dotl_flags- convert Linux specific AT flags to
+ * plan 9 AT flag.
+ * @flags: flags to convert
+ */
+static int v9fs_at_to_dotl_flags(int flags)
+{
+ int rflags = 0;
+ if (flags & AT_REMOVEDIR)
+ rflags |= P9_DOTL_AT_REMOVEDIR;
+ return rflags;
+}
+
+/**
* v9fs_remove - helper function to remove files and directories
* @dir: directory inode that is being deleted
* @dentry: dentry that is being deleted
@@ -558,7 +590,8 @@ static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags)
return retval;
}
if (v9fs_proto_dotl(v9ses))
- retval = p9_client_unlinkat(dfid, dentry->d_name.name, flags);
+ retval = p9_client_unlinkat(dfid, dentry->d_name.name,
+ v9fs_at_to_dotl_flags(flags));
if (retval == -EOPNOTSUPP) {
/* Try the one based on path */
v9fid = v9fs_fid_clone(dentry);
@@ -645,13 +678,11 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);
goto error;
}
- d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid);
if (err < 0)
goto error;
-
+ d_instantiate(dentry, inode);
return ofid;
-
error:
if (ofid)
p9_client_clunk(ofid);
@@ -792,6 +823,7 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nameidata)
{
+ struct dentry *res;
struct super_block *sb;
struct v9fs_session_info *v9ses;
struct p9_fid *dfid, *fid;
@@ -823,22 +855,35 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
return ERR_PTR(result);
}
-
- inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
+ /*
+ * Make sure we don't use a wrong inode due to parallel
+ * unlink. For cached mode create calls request for new
+ * inode. But with cache disabled, lookup should do this.
+ */
+ if (v9ses->cache)
+ inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
+ else
+ inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
if (IS_ERR(inode)) {
result = PTR_ERR(inode);
inode = NULL;
goto error;
}
-
result = v9fs_fid_add(dentry, fid);
if (result < 0)
goto error_iput;
-
inst_out:
- d_add(dentry, inode);
- return NULL;
-
+ /*
+ * If we had a rename on the server and a parallel lookup
+ * for the new name, then make sure we instantiate with
+ * the new name. ie look up for a/b, while on server somebody
+ * moved b under k and client parallely did a lookup for
+ * k/b.
+ */
+ res = d_materialise_unique(dentry, inode);
+ if (!IS_ERR(res))
+ return res;
+ result = PTR_ERR(res);
error_iput:
iput(inode);
error:
@@ -1002,7 +1047,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
return PTR_ERR(st);
v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb);
- generic_fillattr(dentry->d_inode, stat);
+ generic_fillattr(dentry->d_inode, stat);
p9stat_free(st);
kfree(st);
@@ -1086,6 +1131,7 @@ void
v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
struct super_block *sb)
{
+ mode_t mode;
char ext[32];
char tag_name[14];
unsigned int i_nlink;
@@ -1121,31 +1167,9 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
inode->i_nlink = i_nlink;
}
}
- inode->i_mode = p9mode2unixmode(v9ses, stat->mode);
- if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) {
- char type = 0;
- int major = -1;
- int minor = -1;
-
- strncpy(ext, stat->extension, sizeof(ext));
- sscanf(ext, "%c %u %u", &type, &major, &minor);
- switch (type) {
- case 'c':
- inode->i_mode &= ~S_IFBLK;
- inode->i_mode |= S_IFCHR;
- break;
- case 'b':
- break;
- default:
- P9_DPRINTK(P9_DEBUG_ERROR,
- "Unknown special type %c %s\n", type,
- stat->extension);
- };
- inode->i_rdev = MKDEV(major, minor);
- init_special_inode(inode, inode->i_mode, inode->i_rdev);
- } else
- inode->i_rdev = 0;
-
+ mode = stat->mode & S_IALLUGO;
+ mode |= inode->i_mode & ~S_IALLUGO;
+ inode->i_mode = mode;
i_size_write(inode, stat->length);
/* not real number of blocks, but 512 byte ones ... */
@@ -1411,6 +1435,8 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode)
{
+ int umode;
+ dev_t rdev;
loff_t i_size;
struct p9_wstat *st;
struct v9fs_session_info *v9ses;
@@ -1419,6 +1445,12 @@ int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode)
st = p9_client_stat(fid);
if (IS_ERR(st))
return PTR_ERR(st);
+ /*
+ * Don't update inode if the file type is different
+ */
+ umode = p9mode2unixmode(v9ses, st, &rdev);
+ if ((inode->i_mode & S_IFMT) != (umode & S_IFMT))
+ goto out;
spin_lock(&inode->i_lock);
/*
@@ -1430,6 +1462,7 @@ int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode)
if (v9ses->cache)
inode->i_size = i_size;
spin_unlock(&inode->i_lock);
+out:
p9stat_free(st);
kfree(st);
return 0;
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
index b6c8ed205192..aded79fcd5cf 100644
--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -153,7 +153,8 @@ static struct inode *v9fs_qid_iget_dotl(struct super_block *sb,
* later.
*/
inode->i_ino = i_ino;
- retval = v9fs_init_inode(v9ses, inode, st->st_mode);
+ retval = v9fs_init_inode(v9ses, inode,
+ st->st_mode, new_decode_dev(st->st_rdev));
if (retval)
goto error;
@@ -190,6 +191,58 @@ v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid,
return inode;
}
+struct dotl_openflag_map {
+ int open_flag;
+ int dotl_flag;
+};
+
+static int v9fs_mapped_dotl_flags(int flags)
+{
+ int i;
+ int rflags = 0;
+ struct dotl_openflag_map dotl_oflag_map[] = {
+ { O_CREAT, P9_DOTL_CREATE },
+ { O_EXCL, P9_DOTL_EXCL },
+ { O_NOCTTY, P9_DOTL_NOCTTY },
+ { O_TRUNC, P9_DOTL_TRUNC },
+ { O_APPEND, P9_DOTL_APPEND },
+ { O_NONBLOCK, P9_DOTL_NONBLOCK },
+ { O_DSYNC, P9_DOTL_DSYNC },
+ { FASYNC, P9_DOTL_FASYNC },
+ { O_DIRECT, P9_DOTL_DIRECT },
+ { O_LARGEFILE, P9_DOTL_LARGEFILE },
+ { O_DIRECTORY, P9_DOTL_DIRECTORY },
+ { O_NOFOLLOW, P9_DOTL_NOFOLLOW },
+ { O_NOATIME, P9_DOTL_NOATIME },
+ { O_CLOEXEC, P9_DOTL_CLOEXEC },
+ { O_SYNC, P9_DOTL_SYNC},
+ };
+ for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) {
+ if (flags & dotl_oflag_map[i].open_flag)
+ rflags |= dotl_oflag_map[i].dotl_flag;
+ }
+ return rflags;
+}
+
+/**
+ * v9fs_open_to_dotl_flags- convert Linux specific open flags to
+ * plan 9 open flag.
+ * @flags: flags to convert
+ */
+int v9fs_open_to_dotl_flags(int flags)
+{
+ int rflags = 0;
+
+ /*
+ * We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY
+ * and P9_DOTL_NOACCESS
+ */
+ rflags |= flags & O_ACCMODE;
+ rflags |= v9fs_mapped_dotl_flags(flags);
+
+ return rflags;
+}
+
/**
* v9fs_vfs_create_dotl - VFS hook to create files for 9P2000.L protocol.
* @dir: directory inode that is being created
@@ -258,7 +311,8 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
"Failed to get acl values in creat %d\n", err);
goto error;
}
- err = p9_client_create_dotl(ofid, name, flags, mode, gid, &qid);
+ err = p9_client_create_dotl(ofid, name, v9fs_open_to_dotl_flags(flags),
+ mode, gid, &qid);
if (err < 0) {
P9_DPRINTK(P9_DEBUG_VFS,
"p9_client_open_dotl failed in creat %d\n",
@@ -281,10 +335,10 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);
goto error;
}
- d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid);
if (err < 0)
goto error;
+ d_instantiate(dentry, inode);
/* Now set the ACL based on the default value */
v9fs_set_create_acl(dentry, &dacl, &pacl);
@@ -403,10 +457,10 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
err);
goto error;
}
- d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid);
if (err < 0)
goto error;
+ d_instantiate(dentry, inode);
fid = NULL;
} else {
/*
@@ -414,7 +468,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
* inode with stat. We need to get an inode
* so that we can set the acl with dentry
*/
- inode = v9fs_get_inode(dir->i_sb, mode);
+ inode = v9fs_get_inode(dir->i_sb, mode, 0);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
goto error;
@@ -540,6 +594,7 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
void
v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
{
+ mode_t mode;
struct v9fs_inode *v9inode = V9FS_I(inode);
if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) {
@@ -552,11 +607,10 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
inode->i_uid = stat->st_uid;
inode->i_gid = stat->st_gid;
inode->i_nlink = stat->st_nlink;
- inode->i_mode = stat->st_mode;
- inode->i_rdev = new_decode_dev(stat->st_rdev);
- if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode)))
- init_special_inode(inode, inode->i_mode, inode->i_rdev);
+ mode = stat->st_mode & S_IALLUGO;
+ mode |= inode->i_mode & ~S_IALLUGO;
+ inode->i_mode = mode;
i_size_write(inode, stat->st_size);
inode->i_blocks = stat->st_blocks;
@@ -657,14 +711,14 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
err);
goto error;
}
- d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid);
if (err < 0)
goto error;
+ d_instantiate(dentry, inode);
fid = NULL;
} else {
/* Not in cached mode. No need to populate inode with stat */
- inode = v9fs_get_inode(dir->i_sb, S_IFLNK);
+ inode = v9fs_get_inode(dir->i_sb, S_IFLNK, 0);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
goto error;
@@ -810,17 +864,17 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode,
err);
goto error;
}
- d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid);
if (err < 0)
goto error;
+ d_instantiate(dentry, inode);
fid = NULL;
} else {
/*
* Not in cached mode. No need to populate inode with stat.
* socket syscall returns a fd, so we need instantiate
*/
- inode = v9fs_get_inode(dir->i_sb, mode);
+ inode = v9fs_get_inode(dir->i_sb, mode, rdev);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
goto error;
@@ -886,6 +940,11 @@ int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)
st = p9_client_getattr_dotl(fid, P9_STATS_ALL);
if (IS_ERR(st))
return PTR_ERR(st);
+ /*
+ * Don't update inode if the file type is different
+ */
+ if ((inode->i_mode & S_IFMT) != (st->st_mode & S_IFMT))
+ goto out;
spin_lock(&inode->i_lock);
/*
@@ -897,6 +956,7 @@ int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)
if (v9ses->cache)
inode->i_size = i_size;
spin_unlock(&inode->i_lock);
+out:
kfree(st);
return 0;
}
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index feef6cdc1fd2..c70251d47ed1 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -149,7 +149,7 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
else
sb->s_d_op = &v9fs_dentry_operations;
- inode = v9fs_get_inode(sb, S_IFDIR | mode);
+ inode = v9fs_get_inode(sb, S_IFDIR | mode, 0);
if (IS_ERR(inode)) {
retval = PTR_ERR(inode);
goto release_sb;
diff --git a/fs/attr.c b/fs/attr.c
index 538e27959d3f..7ee7ba488313 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -13,6 +13,7 @@
#include <linux/fsnotify.h>
#include <linux/fcntl.h>
#include <linux/security.h>
+#include <linux/evm.h>
/**
* inode_change_ok - check if attribute changes to an inode are allowed
@@ -237,8 +238,10 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
else
error = simple_setattr(dentry, attr);
- if (!error)
+ if (!error) {
fsnotify_change(dentry, ia_valid);
+ evm_inode_post_setattr(dentry, ia_valid);
+ }
return error;
}
diff --git a/fs/block_dev.c b/fs/block_dev.c
index ff77262e887c..95f786ec7f08 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -1429,6 +1429,11 @@ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part)
WARN_ON_ONCE(bdev->bd_holders);
sync_blockdev(bdev);
kill_bdev(bdev);
+ /* ->release can cause the old bdi to disappear,
+ * so must switch it out first
+ */
+ bdev_inode_switch_bdi(bdev->bd_inode,
+ &default_backing_dev_info);
}
if (bdev->bd_contains == bdev) {
if (disk->fops->release)
@@ -1442,8 +1447,6 @@ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part)
disk_put_part(bdev->bd_part);
bdev->bd_part = NULL;
bdev->bd_disk = NULL;
- bdev_inode_switch_bdi(bdev->bd_inode,
- &default_backing_dev_info);
if (bdev != bdev->bd_contains)
victim = bdev->bd_contains;
bdev->bd_contains = NULL;
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index 502b9e988679..d9f99a16edd6 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -176,7 +176,11 @@ static inline u64 btrfs_ino(struct inode *inode)
{
u64 ino = BTRFS_I(inode)->location.objectid;
- if (ino <= BTRFS_FIRST_FREE_OBJECTID)
+ /*
+ * !ino: btree_inode
+ * type == BTRFS_ROOT_ITEM_KEY: subvol dir
+ */
+ if (!ino || BTRFS_I(inode)->location.type == BTRFS_ROOT_ITEM_KEY)
ino = inode->i_ino;
return ino;
}
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index b910694f61ed..a1cb7821becd 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -183,8 +183,10 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
* read from the commit root and sidestep a nasty deadlock
* between reading the free space cache and updating the csum tree.
*/
- if (btrfs_is_free_space_inode(root, inode))
+ if (btrfs_is_free_space_inode(root, inode)) {
path->search_commit_root = 1;
+ path->skip_locking = 1;
+ }
disk_bytenr = (u64)bio->bi_sector << 9;
if (dio)
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index e7872e485f13..e4e57d59edb7 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1036,11 +1036,13 @@ out:
* on error we return an unlocked page and the error value
* on success we return a locked page and 0
*/
-static int prepare_uptodate_page(struct page *page, u64 pos)
+static int prepare_uptodate_page(struct page *page, u64 pos,
+ bool force_uptodate)
{
int ret = 0;
- if ((pos & (PAGE_CACHE_SIZE - 1)) && !PageUptodate(page)) {
+ if (((pos & (PAGE_CACHE_SIZE - 1)) || force_uptodate) &&
+ !PageUptodate(page)) {
ret = btrfs_readpage(NULL, page);
if (ret)
return ret;
@@ -1061,7 +1063,7 @@ static int prepare_uptodate_page(struct page *page, u64 pos)
static noinline int prepare_pages(struct btrfs_root *root, struct file *file,
struct page **pages, size_t num_pages,
loff_t pos, unsigned long first_index,
- size_t write_bytes)
+ size_t write_bytes, bool force_uptodate)
{
struct extent_state *cached_state = NULL;
int i;
@@ -1075,12 +1077,6 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file,
start_pos = pos & ~((u64)root->sectorsize - 1);
last_pos = ((u64)index + num_pages) << PAGE_CACHE_SHIFT;
- if (start_pos > inode->i_size) {
- err = btrfs_cont_expand(inode, i_size_read(inode), start_pos);
- if (err)
- return err;
- }
-
again:
for (i = 0; i < num_pages; i++) {
pages[i] = find_or_create_page(inode->i_mapping, index + i,
@@ -1092,10 +1088,11 @@ again:
}
if (i == 0)
- err = prepare_uptodate_page(pages[i], pos);
+ err = prepare_uptodate_page(pages[i], pos,
+ force_uptodate);
if (i == num_pages - 1)
err = prepare_uptodate_page(pages[i],
- pos + write_bytes);
+ pos + write_bytes, false);
if (err) {
page_cache_release(pages[i]);
faili = i - 1;
@@ -1164,6 +1161,7 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
size_t num_written = 0;
int nrptrs;
int ret = 0;
+ bool force_page_uptodate = false;
nrptrs = min((iov_iter_count(i) + PAGE_CACHE_SIZE - 1) /
PAGE_CACHE_SIZE, PAGE_CACHE_SIZE /
@@ -1206,7 +1204,8 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
* contents of pages from loop to loop
*/
ret = prepare_pages(root, file, pages, num_pages,
- pos, first_index, write_bytes);
+ pos, first_index, write_bytes,
+ force_page_uptodate);
if (ret) {
btrfs_delalloc_release_space(inode,
num_pages << PAGE_CACHE_SHIFT);
@@ -1223,12 +1222,15 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
if (copied < write_bytes)
nrptrs = 1;
- if (copied == 0)
+ if (copied == 0) {
+ force_page_uptodate = true;
dirty_pages = 0;
- else
+ } else {
+ force_page_uptodate = false;
dirty_pages = (copied + offset +
PAGE_CACHE_SIZE - 1) >>
PAGE_CACHE_SHIFT;
+ }
/*
* If we had a short copy we need to release the excess delaloc
@@ -1338,6 +1340,7 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
struct inode *inode = fdentry(file)->d_inode;
struct btrfs_root *root = BTRFS_I(inode)->root;
loff_t *ppos = &iocb->ki_pos;
+ u64 start_pos;
ssize_t num_written = 0;
ssize_t err = 0;
size_t count, ocount;
@@ -1386,6 +1389,15 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
file_update_time(file);
BTRFS_I(inode)->sequence++;
+ start_pos = round_down(pos, root->sectorsize);
+ if (start_pos > i_size_read(inode)) {
+ err = btrfs_cont_expand(inode, i_size_read(inode), start_pos);
+ if (err) {
+ mutex_unlock(&inode->i_mutex);
+ goto out;
+ }
+ }
+
if (unlikely(file->f_flags & O_DIRECT)) {
num_written = __btrfs_direct_write(iocb, iov, nr_segs,
pos, ppos, count, ocount);
@@ -1813,6 +1825,11 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int origin)
goto out;
case SEEK_DATA:
case SEEK_HOLE:
+ if (offset >= i_size_read(inode)) {
+ mutex_unlock(&inode->i_mutex);
+ return -ENXIO;
+ }
+
ret = find_desired_extent(inode, &offset, origin);
if (ret) {
mutex_unlock(&inode->i_mutex);
@@ -1821,11 +1838,11 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int origin)
}
if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET)) {
- ret = -EINVAL;
+ offset = -EINVAL;
goto out;
}
if (offset > inode->i_sb->s_maxbytes) {
- ret = -EINVAL;
+ offset = -EINVAL;
goto out;
}
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index 6a265b9f85f2..41ac927401d0 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -190,9 +190,11 @@ int btrfs_truncate_free_space_cache(struct btrfs_root *root,
struct btrfs_path *path,
struct inode *inode)
{
+ struct btrfs_block_rsv *rsv;
loff_t oldsize;
int ret = 0;
+ rsv = trans->block_rsv;
trans->block_rsv = root->orphan_block_rsv;
ret = btrfs_block_rsv_check(trans, root,
root->orphan_block_rsv,
@@ -210,6 +212,8 @@ int btrfs_truncate_free_space_cache(struct btrfs_root *root,
*/
ret = btrfs_truncate_inode_items(trans, root, inode,
0, BTRFS_EXTENT_DATA_KEY);
+
+ trans->block_rsv = rsv;
if (ret) {
WARN_ON(1);
return ret;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 0ccc7438ad34..b2d004ad66a0 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1786,7 +1786,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
&ordered_extent->list);
ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);
- if (!ret) {
+ if (!ret || !test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) {
ret = btrfs_update_inode(trans, root, inode);
BUG_ON(ret);
}
@@ -3510,15 +3510,19 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
err = btrfs_drop_extents(trans, inode, cur_offset,
cur_offset + hole_size,
&hint_byte, 1);
- if (err)
+ if (err) {
+ btrfs_end_transaction(trans, root);
break;
+ }
err = btrfs_insert_file_extent(trans, root,
btrfs_ino(inode), cur_offset, 0,
0, hole_size, 0, hole_size,
0, 0, 0);
- if (err)
+ if (err) {
+ btrfs_end_transaction(trans, root);
break;
+ }
btrfs_drop_extent_cache(inode, hole_start,
last_byte - 1, 0);
@@ -3952,7 +3956,6 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
struct btrfs_root *root, int *new)
{
struct inode *inode;
- int bad_inode = 0;
inode = btrfs_iget_locked(s, location->objectid, root);
if (!inode)
@@ -3968,15 +3971,12 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
if (new)
*new = 1;
} else {
- bad_inode = 1;
+ unlock_new_inode(inode);
+ iput(inode);
+ inode = ERR_PTR(-ESTALE);
}
}
- if (bad_inode) {
- iput(inode);
- inode = ERR_PTR(-ESTALE);
- }
-
return inode;
}
@@ -4018,7 +4018,8 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
memcpy(&location, dentry->d_fsdata, sizeof(struct btrfs_key));
kfree(dentry->d_fsdata);
dentry->d_fsdata = NULL;
- d_clear_need_lookup(dentry);
+ /* This thing is hashed, drop it for now */
+ d_drop(dentry);
} else {
ret = btrfs_inode_by_name(dir, dentry, &location);
}
@@ -4085,7 +4086,15 @@ static void btrfs_dentry_release(struct dentry *dentry)
static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nd)
{
- return d_splice_alias(btrfs_lookup_dentry(dir, dentry), dentry);
+ struct dentry *ret;
+
+ ret = d_splice_alias(btrfs_lookup_dentry(dir, dentry), dentry);
+ if (unlikely(d_need_lookup(dentry))) {
+ spin_lock(&dentry->d_lock);
+ dentry->d_flags &= ~DCACHE_NEED_LOOKUP;
+ spin_unlock(&dentry->d_lock);
+ }
+ return ret;
}
unsigned char btrfs_filetype_table[] = {
@@ -4125,7 +4134,8 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
/* special case for "." */
if (filp->f_pos == 0) {
- over = filldir(dirent, ".", 1, 1, btrfs_ino(inode), DT_DIR);
+ over = filldir(dirent, ".", 1,
+ filp->f_pos, btrfs_ino(inode), DT_DIR);
if (over)
return 0;
filp->f_pos = 1;
@@ -4134,7 +4144,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
if (filp->f_pos == 1) {
u64 pino = parent_ino(filp->f_path.dentry);
over = filldir(dirent, "..", 2,
- 2, pino, DT_DIR);
+ filp->f_pos, pino, DT_DIR);
if (over)
return 0;
filp->f_pos = 2;
@@ -5823,7 +5833,7 @@ again:
add_pending_csums(trans, inode, ordered->file_offset, &ordered->list);
ret = btrfs_ordered_update_i_size(inode, 0, ordered);
- if (!ret)
+ if (!ret || !test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags))
btrfs_update_inode(trans, root, inode);
ret = 0;
out_unlock:
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 970977aab224..dae5dfe41ba5 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -1047,7 +1047,16 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
if (!max_to_defrag)
max_to_defrag = last_index - 1;
- while (i <= last_index && defrag_count < max_to_defrag) {
+ /*
+ * make writeback starts from i, so the defrag range can be
+ * written sequentially.
+ */
+ if (i < inode->i_mapping->writeback_index)
+ inode->i_mapping->writeback_index = i;
+
+ while (i <= last_index && defrag_count < max_to_defrag &&
+ (i < (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
+ PAGE_CACHE_SHIFT)) {
/*
* make sure we stop running if someone unmounts
* the FS
@@ -2177,6 +2186,11 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
if (!(src_file->f_mode & FMODE_READ))
goto out_fput;
+ /* don't make the dst file partly checksummed */
+ if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) !=
+ (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM))
+ goto out_fput;
+
ret = -EISDIR;
if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode))
goto out_fput;
@@ -2220,6 +2234,16 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
!IS_ALIGNED(destoff, bs))
goto out_unlock;
+ if (destoff > inode->i_size) {
+ ret = btrfs_cont_expand(inode, inode->i_size, destoff);
+ if (ret)
+ goto out_unlock;
+ }
+
+ /* truncate page cache pages from target inode range */
+ truncate_inode_pages_range(&inode->i_data, destoff,
+ PAGE_CACHE_ALIGN(destoff + len) - 1);
+
/* do any pending delalloc/csum calc on src, one way or
another, and lock file content */
while (1) {
@@ -2236,10 +2260,6 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
btrfs_wait_ordered_range(src, off, len);
}
- /* truncate page cache pages from target inode range */
- truncate_inode_pages_range(&inode->i_data, off,
- ALIGN(off + len, PAGE_CACHE_SIZE) - 1);
-
/* clone data */
key.objectid = btrfs_ino(src);
key.type = BTRFS_EXTENT_DATA_KEY;
@@ -2317,7 +2337,12 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
else
new_key.offset = destoff;
- trans = btrfs_start_transaction(root, 1);
+ /*
+ * 1 - adjusting old extent (we may have to split it)
+ * 1 - add new extent
+ * 1 - inode update
+ */
+ trans = btrfs_start_transaction(root, 3);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
goto out;
@@ -2325,14 +2350,21 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
if (type == BTRFS_FILE_EXTENT_REG ||
type == BTRFS_FILE_EXTENT_PREALLOC) {
+ /*
+ * a | --- range to clone ---| b
+ * | ------------- extent ------------- |
+ */
+
+ /* substract range b */
+ if (key.offset + datal > off + len)
+ datal = off + len - key.offset;
+
+ /* substract range a */
if (off > key.offset) {
datao += off - key.offset;
datal -= off - key.offset;
}
- if (key.offset + datal > off + len)
- datal = off + len - key.offset;
-
ret = btrfs_drop_extents(trans, inode,
new_key.offset,
new_key.offset + datal,
@@ -2429,7 +2461,6 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
if (endoff > inode->i_size)
btrfs_i_size_write(inode, endoff);
- BTRFS_I(inode)->flags = BTRFS_I(src)->flags;
ret = btrfs_update_inode(trans, root, inode);
BUG_ON(ret);
btrfs_end_transaction(trans, root);
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 7dc36fab4afc..e24b7964a155 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -884,6 +884,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
struct btrfs_root *tree_root = fs_info->tree_root;
struct btrfs_root *root = pending->root;
struct btrfs_root *parent_root;
+ struct btrfs_block_rsv *rsv;
struct inode *parent_inode;
struct dentry *parent;
struct dentry *dentry;
@@ -895,6 +896,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
u64 objectid;
u64 root_flags;
+ rsv = trans->block_rsv;
+
new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS);
if (!new_root_item) {
pending->error = -ENOMEM;
@@ -1002,6 +1005,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
btrfs_orphan_post_snapshot(trans, pending);
fail:
kfree(new_root_item);
+ trans->block_rsv = rsv;
btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1);
return 0;
}
diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c
index d733b9cfea34..426aa464f1af 100644
--- a/fs/btrfs/xattr.c
+++ b/fs/btrfs/xattr.c
@@ -116,6 +116,12 @@ static int do_setxattr(struct btrfs_trans_handle *trans,
if (ret)
goto out;
btrfs_release_path(path);
+
+ /*
+ * remove the attribute
+ */
+ if (!value)
+ goto out;
}
again:
@@ -158,6 +164,9 @@ out:
return ret;
}
+/*
+ * @value: "" makes the attribute to empty, NULL removes it
+ */
int __btrfs_setxattr(struct btrfs_trans_handle *trans,
struct inode *inode, const char *name,
const void *value, size_t size, int flags)
@@ -374,36 +383,36 @@ int btrfs_removexattr(struct dentry *dentry, const char *name)
XATTR_REPLACE);
}
-int btrfs_xattr_security_init(struct btrfs_trans_handle *trans,
- struct inode *inode, struct inode *dir,
- const struct qstr *qstr)
+int btrfs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
+ void *fs_info)
{
- int err;
- size_t len;
- void *value;
- char *suffix;
+ const struct xattr *xattr;
+ struct btrfs_trans_handle *trans = fs_info;
char *name;
+ int err = 0;
- err = security_inode_init_security(inode, dir, qstr, &suffix, &value,
- &len);
- if (err) {
- if (err == -EOPNOTSUPP)
- return 0;
- return err;
- }
-
- name = kmalloc(XATTR_SECURITY_PREFIX_LEN + strlen(suffix) + 1,
- GFP_NOFS);
- if (!name) {
- err = -ENOMEM;
- } else {
+ for (xattr = xattr_array; xattr->name != NULL; xattr++) {
+ name = kmalloc(XATTR_SECURITY_PREFIX_LEN +
+ strlen(xattr->name) + 1, GFP_NOFS);
+ if (!name) {
+ err = -ENOMEM;
+ break;
+ }
strcpy(name, XATTR_SECURITY_PREFIX);
- strcpy(name + XATTR_SECURITY_PREFIX_LEN, suffix);
- err = __btrfs_setxattr(trans, inode, name, value, len, 0);
+ strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name);
+ err = __btrfs_setxattr(trans, inode, name,
+ xattr->value, xattr->value_len, 0);
kfree(name);
+ if (err < 0)
+ break;
}
-
- kfree(suffix);
- kfree(value);
return err;
}
+
+int btrfs_xattr_security_init(struct btrfs_trans_handle *trans,
+ struct inode *inode, struct inode *dir,
+ const struct qstr *qstr)
+{
+ return security_inode_init_security(inode, dir, qstr,
+ &btrfs_initxattrs, trans);
+}
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index fee028b5332e..86c59e16ba74 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -1595,7 +1595,7 @@ static int set_request_path_attr(struct inode *rinode, struct dentry *rdentry,
r = build_dentry_path(rdentry, ppath, pathlen, ino, freepath);
dout(" dentry %p %llx/%.*s\n", rdentry, *ino, *pathlen,
*ppath);
- } else if (rpath) {
+ } else if (rpath || rino) {
*ino = rino;
*ppath = rpath;
*pathlen = strlen(rpath);
diff --git a/fs/ceph/super.c b/fs/ceph/super.c
index d47c5ec7fb1f..88bacaf385d9 100644
--- a/fs/ceph/super.c
+++ b/fs/ceph/super.c
@@ -813,8 +813,8 @@ static struct dentry *ceph_mount(struct file_system_type *fs_type,
fsc = create_fs_client(fsopt, opt);
if (IS_ERR(fsc)) {
res = ERR_CAST(fsc);
- kfree(fsopt);
- kfree(opt);
+ destroy_mount_options(fsopt);
+ ceph_destroy_options(opt);
goto out_final;
}
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index e76bfeb68267..30acd22147e1 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -351,9 +351,7 @@ static int
build_avpair_blob(struct cifs_ses *ses, const struct nls_table *nls_cp)
{
unsigned int dlen;
- unsigned int wlen;
- unsigned int size = 6 * sizeof(struct ntlmssp2_name);
- __le64 curtime;
+ unsigned int size = 2 * sizeof(struct ntlmssp2_name);
char *defdmname = "WORKGROUP";
unsigned char *blobptr;
struct ntlmssp2_name *attrptr;
@@ -365,15 +363,14 @@ build_avpair_blob(struct cifs_ses *ses, const struct nls_table *nls_cp)
}
dlen = strlen(ses->domainName);
- wlen = strlen(ses->server->hostname);
- /* The length of this blob is a size which is
- * six times the size of a structure which holds name/size +
- * two times the unicode length of a domain name +
- * two times the unicode length of a server name +
- * size of a timestamp (which is 8 bytes).
+ /*
+ * The length of this blob is two times the size of a
+ * structure (av pair) which holds name/size
+ * ( for NTLMSSP_AV_NB_DOMAIN_NAME followed by NTLMSSP_AV_EOL ) +
+ * unicode length of a netbios domain name
*/
- ses->auth_key.len = size + 2 * (2 * dlen) + 2 * (2 * wlen) + 8;
+ ses->auth_key.len = size + 2 * dlen;
ses->auth_key.response = kzalloc(ses->auth_key.len, GFP_KERNEL);
if (!ses->auth_key.response) {
ses->auth_key.len = 0;
@@ -384,44 +381,15 @@ build_avpair_blob(struct cifs_ses *ses, const struct nls_table *nls_cp)
blobptr = ses->auth_key.response;
attrptr = (struct ntlmssp2_name *) blobptr;
+ /*
+ * As defined in MS-NTLM 3.3.2, just this av pair field
+ * is sufficient as part of the temp
+ */
attrptr->type = cpu_to_le16(NTLMSSP_AV_NB_DOMAIN_NAME);
attrptr->length = cpu_to_le16(2 * dlen);
blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name);
cifs_strtoUCS((__le16 *)blobptr, ses->domainName, dlen, nls_cp);
- blobptr += 2 * dlen;
- attrptr = (struct ntlmssp2_name *) blobptr;
-
- attrptr->type = cpu_to_le16(NTLMSSP_AV_NB_COMPUTER_NAME);
- attrptr->length = cpu_to_le16(2 * wlen);
- blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name);
- cifs_strtoUCS((__le16 *)blobptr, ses->server->hostname, wlen, nls_cp);
-
- blobptr += 2 * wlen;
- attrptr = (struct ntlmssp2_name *) blobptr;
-
- attrptr->type = cpu_to_le16(NTLMSSP_AV_DNS_DOMAIN_NAME);
- attrptr->length = cpu_to_le16(2 * dlen);
- blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name);
- cifs_strtoUCS((__le16 *)blobptr, ses->domainName, dlen, nls_cp);
-
- blobptr += 2 * dlen;
- attrptr = (struct ntlmssp2_name *) blobptr;
-
- attrptr->type = cpu_to_le16(NTLMSSP_AV_DNS_COMPUTER_NAME);
- attrptr->length = cpu_to_le16(2 * wlen);
- blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name);
- cifs_strtoUCS((__le16 *)blobptr, ses->server->hostname, wlen, nls_cp);
-
- blobptr += 2 * wlen;
- attrptr = (struct ntlmssp2_name *) blobptr;
-
- attrptr->type = cpu_to_le16(NTLMSSP_AV_TIMESTAMP);
- attrptr->length = cpu_to_le16(sizeof(__le64));
- blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name);
- curtime = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
- memcpy(blobptr, &curtime, sizeof(__le64));
-
return 0;
}
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index f93eb948d071..54b8f1e7da94 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -548,6 +548,12 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
struct inode *dir = dentry->d_inode;
struct dentry *child;
+ if (!dir) {
+ dput(dentry);
+ dentry = ERR_PTR(-ENOENT);
+ break;
+ }
+
/* skip separators */
while (*s == sep)
s++;
@@ -563,10 +569,6 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
mutex_unlock(&dir->i_mutex);
dput(dentry);
dentry = child;
- if (!dentry->d_inode) {
- dput(dentry);
- dentry = ERR_PTR(-ENOENT);
- }
} while (!IS_ERR(dentry));
_FreeXid(xid);
kfree(full_path);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index aac37d99a487..a80f7bd97b90 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -4079,7 +4079,8 @@ int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
T2_FNEXT_RSP_PARMS *parms;
char *response_data;
int rc = 0;
- int bytes_returned, name_len;
+ int bytes_returned;
+ unsigned int name_len;
__u16 params, byte_count;
cFYI(1, "In FindNext");
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 633c246b6775..62abf9fd6ff0 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1298,7 +1298,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
/* ignore */
} else if (strnicmp(data, "guest", 5) == 0) {
/* ignore */
- } else if (strnicmp(data, "rw", 2) == 0) {
+ } else if (strnicmp(data, "rw", 2) == 0 && strlen(data) == 2) {
/* ignore */
} else if (strnicmp(data, "ro", 2) == 0) {
/* ignore */
@@ -1401,7 +1401,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
vol->server_ino = 1;
} else if (strnicmp(data, "noserverino", 9) == 0) {
vol->server_ino = 0;
- } else if (strnicmp(data, "rwpidforward", 4) == 0) {
+ } else if (strnicmp(data, "rwpidforward", 12) == 0) {
vol->rwpidforward = 1;
} else if (strnicmp(data, "cifsacl", 7) == 0) {
vol->cifs_acl = 1;
@@ -2018,7 +2018,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
warned_on_ntlm = true;
cERROR(1, "default security mechanism requested. The default "
"security mechanism will be upgraded from ntlm to "
- "ntlmv2 in kernel release 3.1");
+ "ntlmv2 in kernel release 3.2");
}
ses->overrideSecFlg = volume_info->secFlg;
@@ -2877,9 +2877,9 @@ cleanup_volume_info_contents(struct smb_vol *volume_info)
{
kfree(volume_info->username);
kzfree(volume_info->password);
- kfree(volume_info->UNC);
if (volume_info->UNCip != volume_info->UNC + 2)
kfree(volume_info->UNCip);
+ kfree(volume_info->UNC);
kfree(volume_info->domainname);
kfree(volume_info->iocharset);
kfree(volume_info->prepath);
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index 2a22fb2989e4..c32308882148 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -22,6 +22,7 @@
#include <linux/fs.h>
#include <linux/posix_acl_xattr.h>
#include <linux/slab.h>
+#include <linux/xattr.h>
#include "cifsfs.h"
#include "cifspdu.h"
#include "cifsglob.h"
@@ -31,16 +32,8 @@
#define MAX_EA_VALUE_SIZE 65535
#define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib"
#define CIFS_XATTR_CIFS_ACL "system.cifs_acl"
-#define CIFS_XATTR_USER_PREFIX "user."
-#define CIFS_XATTR_SYSTEM_PREFIX "system."
-#define CIFS_XATTR_OS2_PREFIX "os2."
-#define CIFS_XATTR_SECURITY_PREFIX "security."
-#define CIFS_XATTR_TRUSTED_PREFIX "trusted."
-#define XATTR_TRUSTED_PREFIX_LEN 8
-#define XATTR_SECURITY_PREFIX_LEN 9
-/* BB need to add server (Samba e.g) support for security and trusted prefix */
-
+/* BB need to add server (Samba e.g) support for security and trusted prefix */
int cifs_removexattr(struct dentry *direntry, const char *ea_name)
{
@@ -76,8 +69,8 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name)
}
if (ea_name == NULL) {
cFYI(1, "Null xattr names not supported");
- } else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5)
- && (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4))) {
+ } else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)
+ && (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN))) {
cFYI(1,
"illegal xattr request %s (only user namespace supported)",
ea_name);
@@ -88,7 +81,7 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name)
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
goto remove_ea_exit;
- ea_name += 5; /* skip past user. prefix */
+ ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, NULL,
(__u16)0, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -149,21 +142,23 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
if (ea_name == NULL) {
cFYI(1, "Null xattr names not supported");
- } else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) == 0) {
+ } else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)
+ == 0) {
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
goto set_ea_exit;
if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0)
cFYI(1, "attempt to set cifs inode metadata");
- ea_name += 5; /* skip past user. prefix */
+ ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value,
(__u16)value_size, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
- } else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) {
+ } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN)
+ == 0) {
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
goto set_ea_exit;
- ea_name += 4; /* skip past os2. prefix */
+ ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */
rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value,
(__u16)value_size, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -269,7 +264,8 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
/* return alt name if available as pseudo attr */
if (ea_name == NULL) {
cFYI(1, "Null xattr names not supported");
- } else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) == 0) {
+ } else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)
+ == 0) {
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
goto get_ea_exit;
@@ -277,15 +273,15 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
cFYI(1, "attempt to query cifs inode metadata");
/* revalidate/getattr then populate from inode */
} /* BB add else when above is implemented */
- ea_name += 5; /* skip past user. prefix */
+ ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value,
buf_size, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
- } else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) {
+ } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) {
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
goto get_ea_exit;
- ea_name += 4; /* skip past os2. prefix */
+ ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */
rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value,
buf_size, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -339,10 +335,10 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
cFYI(1, "Query CIFS ACL not supported yet");
#endif /* CONFIG_CIFS_ACL */
} else if (strncmp(ea_name,
- CIFS_XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) {
+ XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) {
cFYI(1, "Trusted xattr namespace not supported yet");
} else if (strncmp(ea_name,
- CIFS_XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) == 0) {
+ XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) == 0) {
cFYI(1, "Security xattr namespace not supported yet");
} else
cFYI(1,
diff --git a/fs/coda/coda_linux.h b/fs/coda/coda_linux.h
index 44e17e9c21ae..cc0ea9fe5ecf 100644
--- a/fs/coda/coda_linux.h
+++ b/fs/coda/coda_linux.h
@@ -59,12 +59,11 @@ void coda_sysctl_clean(void);
#define CODA_ALLOC(ptr, cast, size) do { \
if (size < PAGE_SIZE) \
- ptr = kmalloc((unsigned long) size, GFP_KERNEL); \
+ ptr = kzalloc((unsigned long) size, GFP_KERNEL); \
else \
- ptr = (cast)vmalloc((unsigned long) size); \
+ ptr = (cast)vzalloc((unsigned long) size); \
if (!ptr) \
printk("kernel malloc returns 0 at %s:%d\n", __FILE__, __LINE__); \
- else memset( ptr, 0, size ); \
} while (0)
diff --git a/fs/compat.c b/fs/compat.c
index 0b48d018e38a..05e3f3d2cd77 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -37,7 +37,6 @@
#include <linux/dirent.h>
#include <linux/fsnotify.h>
#include <linux/highuid.h>
-#include <linux/nfsd/syscall.h>
#include <linux/personality.h>
#include <linux/rwsem.h>
#include <linux/tsacct_kern.h>
@@ -1675,11 +1674,6 @@ asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds,
}
#endif /* HAVE_SET_RESTORE_SIGMASK */
-long asmlinkage compat_sys_nfsservctl(int cmd, void *notused, void *notused2)
-{
- return sys_ni_syscall();
-}
-
#ifdef CONFIG_EPOLL
#ifdef HAVE_SET_RESTORE_SIGMASK
diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c
index c83f4768eeaa..ca418aaf6352 100644
--- a/fs/configfs/inode.c
+++ b/fs/configfs/inode.c
@@ -23,7 +23,8 @@
*
* configfs Copyright (C) 2005 Oracle. All rights reserved.
*
- * Please see Documentation/filesystems/configfs.txt for more information.
+ * Please see Documentation/filesystems/configfs/configfs.txt for more
+ * information.
*/
#undef DEBUG
diff --git a/fs/configfs/item.c b/fs/configfs/item.c
index 76dc4c3e5d51..50cee7f9110b 100644
--- a/fs/configfs/item.c
+++ b/fs/configfs/item.c
@@ -23,7 +23,7 @@
*
* configfs Copyright (C) 2005 Oracle. All rights reserved.
*
- * Please see the file Documentation/filesystems/configfs.txt for
+ * Please see the file Documentation/filesystems/configfs/configfs.txt for
* critical information about using the config_item interface.
*/
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index e7a7a2f07324..f3a257d7a985 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -1,5 +1,5 @@
/*
- * file.c - part of debugfs, a tiny little debug file system
+ * inode.c - part of debugfs, a tiny little debug file system
*
* Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com>
* Copyright (C) 2004 IBM Inc.
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index fe047d966dc5..9026fc91fe3b 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -700,7 +700,7 @@ static const struct file_operations eventpoll_fops = {
.llseek = noop_llseek,
};
-/* Fast test to see if the file is an evenpoll file */
+/* Fast test to see if the file is an eventpoll file */
static inline int is_file_epoll(struct file *f)
{
return f->f_op == &eventpoll_fops;
diff --git a/fs/ext2/xattr_security.c b/fs/ext2/xattr_security.c
index 5d979b4347b0..c922adc8ef41 100644
--- a/fs/ext2/xattr_security.c
+++ b/fs/ext2/xattr_security.c
@@ -46,28 +46,30 @@ ext2_xattr_security_set(struct dentry *dentry, const char *name,
value, size, flags);
}
-int
-ext2_init_security(struct inode *inode, struct inode *dir,
- const struct qstr *qstr)
+int ext2_initxattrs(struct inode *inode, const struct xattr *xattr_array,
+ void *fs_info)
{
- int err;
- size_t len;
- void *value;
- char *name;
+ const struct xattr *xattr;
+ int err = 0;
- err = security_inode_init_security(inode, dir, qstr, &name, &value, &len);
- if (err) {
- if (err == -EOPNOTSUPP)
- return 0;
- return err;
+ for (xattr = xattr_array; xattr->name != NULL; xattr++) {
+ err = ext2_xattr_set(inode, EXT2_XATTR_INDEX_SECURITY,
+ xattr->name, xattr->value,
+ xattr->value_len, 0);
+ if (err < 0)
+ break;
}
- err = ext2_xattr_set(inode, EXT2_XATTR_INDEX_SECURITY,
- name, value, len, 0);
- kfree(name);
- kfree(value);
return err;
}
+int
+ext2_init_security(struct inode *inode, struct inode *dir,
+ const struct qstr *qstr)
+{
+ return security_inode_init_security(inode, dir, qstr,
+ &ext2_initxattrs, NULL);
+}
+
const struct xattr_handler ext2_xattr_security_handler = {
.prefix = XATTR_SECURITY_PREFIX,
.list = ext2_xattr_security_list,
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 04da6acde85d..12661e1deedd 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -1134,7 +1134,7 @@ struct buffer_head *ext3_bread(handle_t *handle, struct inode *inode,
return bh;
if (buffer_uptodate(bh))
return bh;
- ll_rw_block(READ_META, 1, &bh);
+ ll_rw_block(READ | REQ_META | REQ_PRIO, 1, &bh);
wait_on_buffer(bh);
if (buffer_uptodate(bh))
return bh;
@@ -2807,7 +2807,7 @@ make_io:
trace_ext3_load_inode(inode);
get_bh(bh);
bh->b_end_io = end_buffer_read_sync;
- submit_bh(READ_META, bh);
+ submit_bh(READ | REQ_META | REQ_PRIO, bh);
wait_on_buffer(bh);
if (!buffer_uptodate(bh)) {
ext3_error(inode->i_sb, "ext3_get_inode_loc",
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index 5571708b6a58..0629e09f6511 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -922,7 +922,8 @@ restart:
bh = ext3_getblk(NULL, dir, b++, 0, &err);
bh_use[ra_max] = bh;
if (bh)
- ll_rw_block(READ_META, 1, &bh);
+ ll_rw_block(READ | REQ_META | REQ_PRIO,
+ 1, &bh);
}
}
if ((bh = bh_use[ra_ptr++]) == NULL)
diff --git a/fs/ext3/xattr_security.c b/fs/ext3/xattr_security.c
index b8d9f83aa5c5..3c218b8a51d4 100644
--- a/fs/ext3/xattr_security.c
+++ b/fs/ext3/xattr_security.c
@@ -48,28 +48,32 @@ ext3_xattr_security_set(struct dentry *dentry, const char *name,
name, value, size, flags);
}
-int
-ext3_init_security(handle_t *handle, struct inode *inode, struct inode *dir,
- const struct qstr *qstr)
+int ext3_initxattrs(struct inode *inode, const struct xattr *xattr_array,
+ void *fs_info)
{
- int err;
- size_t len;
- void *value;
- char *name;
+ const struct xattr *xattr;
+ handle_t *handle = fs_info;
+ int err = 0;
- err = security_inode_init_security(inode, dir, qstr, &name, &value, &len);
- if (err) {
- if (err == -EOPNOTSUPP)
- return 0;
- return err;
+ for (xattr = xattr_array; xattr->name != NULL; xattr++) {
+ err = ext3_xattr_set_handle(handle, inode,
+ EXT3_XATTR_INDEX_SECURITY,
+ xattr->name, xattr->value,
+ xattr->value_len, 0);
+ if (err < 0)
+ break;
}
- err = ext3_xattr_set_handle(handle, inode, EXT3_XATTR_INDEX_SECURITY,
- name, value, len, 0);
- kfree(name);
- kfree(value);
return err;
}
+int
+ext3_init_security(handle_t *handle, struct inode *inode, struct inode *dir,
+ const struct qstr *qstr)
+{
+ return security_inode_init_security(inode, dir, qstr,
+ &ext3_initxattrs, handle);
+}
+
const struct xattr_handler ext3_xattr_security_handler = {
.prefix = XATTR_SECURITY_PREFIX,
.list = ext3_xattr_security_list,
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index e717dfd2f2b4..b7d7bd0f066e 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -175,6 +175,7 @@ struct mpage_da_data {
*/
#define EXT4_IO_END_UNWRITTEN 0x0001
#define EXT4_IO_END_ERROR 0x0002
+#define EXT4_IO_END_QUEUED 0x0004
struct ext4_io_page {
struct page *p_page;
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index c4da98a959ae..986e2388f031 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -121,9 +121,6 @@ void ext4_evict_inode(struct inode *inode)
trace_ext4_evict_inode(inode);
- mutex_lock(&inode->i_mutex);
- ext4_flush_completed_IO(inode);
- mutex_unlock(&inode->i_mutex);
ext4_ioend_wait(inode);
if (inode->i_nlink) {
@@ -650,7 +647,7 @@ struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode,
return bh;
if (buffer_uptodate(bh))
return bh;
- ll_rw_block(READ_META, 1, &bh);
+ ll_rw_block(READ | REQ_META | REQ_PRIO, 1, &bh);
wait_on_buffer(bh);
if (buffer_uptodate(bh))
return bh;
@@ -3301,7 +3298,7 @@ make_io:
trace_ext4_load_inode(inode);
get_bh(bh);
bh->b_end_io = end_buffer_read_sync;
- submit_bh(READ_META, bh);
+ submit_bh(READ | REQ_META | REQ_PRIO, bh);
wait_on_buffer(bh);
if (!buffer_uptodate(bh)) {
EXT4_ERROR_INODE_BLOCK(inode, block,
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index f8068c7bae9f..1c924faeb6c8 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -922,7 +922,8 @@ restart:
bh = ext4_getblk(NULL, dir, b++, 0, &err);
bh_use[ra_max] = bh;
if (bh)
- ll_rw_block(READ_META, 1, &bh);
+ ll_rw_block(READ | REQ_META | REQ_PRIO,
+ 1, &bh);
}
}
if ((bh = bh_use[ra_ptr++]) == NULL)
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
index 78839af7ce29..92f38ee13f8a 100644
--- a/fs/ext4/page-io.c
+++ b/fs/ext4/page-io.c
@@ -142,7 +142,23 @@ static void ext4_end_io_work(struct work_struct *work)
unsigned long flags;
int ret;
- mutex_lock(&inode->i_mutex);
+ if (!mutex_trylock(&inode->i_mutex)) {
+ /*
+ * Requeue the work instead of waiting so that the work
+ * items queued after this can be processed.
+ */
+ queue_work(EXT4_SB(inode->i_sb)->dio_unwritten_wq, &io->work);
+ /*
+ * To prevent the ext4-dio-unwritten thread from keeping
+ * requeueing end_io requests and occupying cpu for too long,
+ * yield the cpu if it sees an end_io request that has already
+ * been requeued.
+ */
+ if (io->flag & EXT4_IO_END_QUEUED)
+ yield();
+ io->flag |= EXT4_IO_END_QUEUED;
+ return;
+ }
ret = ext4_end_io_nolock(io);
if (ret < 0) {
mutex_unlock(&inode->i_mutex);
diff --git a/fs/ext4/xattr_security.c b/fs/ext4/xattr_security.c
index 007c3bfbf094..34e4350dd4d9 100644
--- a/fs/ext4/xattr_security.c
+++ b/fs/ext4/xattr_security.c
@@ -48,28 +48,32 @@ ext4_xattr_security_set(struct dentry *dentry, const char *name,
name, value, size, flags);
}
-int
-ext4_init_security(handle_t *handle, struct inode *inode, struct inode *dir,
- const struct qstr *qstr)
+int ext4_initxattrs(struct inode *inode, const struct xattr *xattr_array,
+ void *fs_info)
{
- int err;
- size_t len;
- void *value;
- char *name;
+ const struct xattr *xattr;
+ handle_t *handle = fs_info;
+ int err = 0;
- err = security_inode_init_security(inode, dir, qstr, &name, &value, &len);
- if (err) {
- if (err == -EOPNOTSUPP)
- return 0;
- return err;
+ for (xattr = xattr_array; xattr->name != NULL; xattr++) {
+ err = ext4_xattr_set_handle(handle, inode,
+ EXT4_XATTR_INDEX_SECURITY,
+ xattr->name, xattr->value,
+ xattr->value_len, 0);
+ if (err < 0)
+ break;
}
- err = ext4_xattr_set_handle(handle, inode, EXT4_XATTR_INDEX_SECURITY,
- name, value, len, 0);
- kfree(name);
- kfree(value);
return err;
}
+int
+ext4_init_security(handle_t *handle, struct inode *inode, struct inode *dir,
+ const struct qstr *qstr)
+{
+ return security_inode_init_security(inode, dir, qstr,
+ &ext4_initxattrs, handle);
+}
+
const struct xattr_handler ext4_xattr_security_handler = {
.prefix = XATTR_SECURITY_PREFIX,
.list = ext4_xattr_security_list,
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 640fc229df10..5cb8614508c3 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -258,10 +258,14 @@ void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget,
forget->forget_one.nlookup = nlookup;
spin_lock(&fc->lock);
- fc->forget_list_tail->next = forget;
- fc->forget_list_tail = forget;
- wake_up(&fc->waitq);
- kill_fasync(&fc->fasync, SIGIO, POLL_IN);
+ if (fc->connected) {
+ fc->forget_list_tail->next = forget;
+ fc->forget_list_tail = forget;
+ wake_up(&fc->waitq);
+ kill_fasync(&fc->fasync, SIGIO, POLL_IN);
+ } else {
+ kfree(forget);
+ }
spin_unlock(&fc->lock);
}
@@ -1358,6 +1362,10 @@ static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size,
if (outarg.namelen > FUSE_NAME_MAX)
goto err;
+ err = -EINVAL;
+ if (size != sizeof(outarg) + outarg.namelen + 1)
+ goto err;
+
name.name = buf;
name.len = outarg.namelen;
err = fuse_copy_one(cs, buf, outarg.namelen + 1);
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index d480d9af46c9..594f07a81c28 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -14,6 +14,7 @@
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/compat.h>
+#include <linux/swap.h>
static const struct file_operations fuse_direct_io_file_operations;
@@ -245,6 +246,12 @@ void fuse_release_common(struct file *file, int opcode)
req = ff->reserved_req;
fuse_prepare_release(ff, file->f_flags, opcode);
+ if (ff->flock) {
+ struct fuse_release_in *inarg = &req->misc.release.in;
+ inarg->release_flags |= FUSE_RELEASE_FLOCK_UNLOCK;
+ inarg->lock_owner = fuse_lock_owner_id(ff->fc,
+ (fl_owner_t) file);
+ }
/* Hold vfsmount and dentry until release is finished */
path_get(&file->f_path);
req->misc.release.path = file->f_path;
@@ -755,18 +762,6 @@ static size_t fuse_send_write(struct fuse_req *req, struct file *file,
return req->misc.write.out.size;
}
-static int fuse_write_begin(struct file *file, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned flags,
- struct page **pagep, void **fsdata)
-{
- pgoff_t index = pos >> PAGE_CACHE_SHIFT;
-
- *pagep = grab_cache_page_write_begin(mapping, index, flags);
- if (!*pagep)
- return -ENOMEM;
- return 0;
-}
-
void fuse_write_update_size(struct inode *inode, loff_t pos)
{
struct fuse_conn *fc = get_fuse_conn(inode);
@@ -779,62 +774,6 @@ void fuse_write_update_size(struct inode *inode, loff_t pos)
spin_unlock(&fc->lock);
}
-static int fuse_buffered_write(struct file *file, struct inode *inode,
- loff_t pos, unsigned count, struct page *page)
-{
- int err;
- size_t nres;
- struct fuse_conn *fc = get_fuse_conn(inode);
- unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
- struct fuse_req *req;
-
- if (is_bad_inode(inode))
- return -EIO;
-
- /*
- * Make sure writepages on the same page are not mixed up with
- * plain writes.
- */
- fuse_wait_on_page_writeback(inode, page->index);
-
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- req->in.argpages = 1;
- req->num_pages = 1;
- req->pages[0] = page;
- req->page_offset = offset;
- nres = fuse_send_write(req, file, pos, count, NULL);
- err = req->out.h.error;
- fuse_put_request(fc, req);
- if (!err && !nres)
- err = -EIO;
- if (!err) {
- pos += nres;
- fuse_write_update_size(inode, pos);
- if (count == PAGE_CACHE_SIZE)
- SetPageUptodate(page);
- }
- fuse_invalidate_attr(inode);
- return err ? err : nres;
-}
-
-static int fuse_write_end(struct file *file, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned copied,
- struct page *page, void *fsdata)
-{
- struct inode *inode = mapping->host;
- int res = 0;
-
- if (copied)
- res = fuse_buffered_write(file, inode, pos, copied, page);
-
- unlock_page(page);
- page_cache_release(page);
- return res;
-}
-
static size_t fuse_send_write_pages(struct fuse_req *req, struct file *file,
struct inode *inode, loff_t pos,
size_t count)
@@ -908,6 +847,8 @@ static ssize_t fuse_fill_write_pages(struct fuse_req *req,
pagefault_enable();
flush_dcache_page(page);
+ mark_page_accessed(page);
+
if (!tmp) {
unlock_page(page);
page_cache_release(page);
@@ -1559,11 +1500,14 @@ static int fuse_file_flock(struct file *file, int cmd, struct file_lock *fl)
struct fuse_conn *fc = get_fuse_conn(inode);
int err;
- if (fc->no_lock) {
+ if (fc->no_flock) {
err = flock_lock_file_wait(file, fl);
} else {
+ struct fuse_file *ff = file->private_data;
+
/* emulate flock with POSIX locks */
fl->fl_owner = (fl_owner_t) file;
+ ff->flock = true;
err = fuse_setlk(file, fl, 1);
}
@@ -2201,8 +2145,6 @@ static const struct address_space_operations fuse_file_aops = {
.readpage = fuse_readpage,
.writepage = fuse_writepage,
.launder_page = fuse_launder_page,
- .write_begin = fuse_write_begin,
- .write_end = fuse_write_end,
.readpages = fuse_readpages,
.set_page_dirty = __set_page_dirty_nobuffers,
.bmap = fuse_bmap,
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index c6aa2d4b8517..cf6db0a93219 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -135,6 +135,9 @@ struct fuse_file {
/** Wait queue head for poll */
wait_queue_head_t poll_wait;
+
+ /** Has flock been performed on this file? */
+ bool flock:1;
};
/** One input argument of a request */
@@ -448,7 +451,7 @@ struct fuse_conn {
/** Is removexattr not implemented by fs? */
unsigned no_removexattr:1;
- /** Are file locking primitives not implemented by fs? */
+ /** Are posix file locking primitives not implemented by fs? */
unsigned no_lock:1;
/** Is access not implemented by fs? */
@@ -472,6 +475,9 @@ struct fuse_conn {
/** Don't apply umask to creation modes */
unsigned dont_mask:1;
+ /** Are BSD file locking primitives not implemented by fs? */
+ unsigned no_flock:1;
+
/** The number of requests waiting for completion */
atomic_t num_waiting;
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 38f84cd48b67..add96f6ffda5 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -71,7 +71,7 @@ struct fuse_mount_data {
unsigned blksize;
};
-struct fuse_forget_link *fuse_alloc_forget()
+struct fuse_forget_link *fuse_alloc_forget(void)
{
return kzalloc(sizeof(struct fuse_forget_link), GFP_KERNEL);
}
@@ -809,6 +809,13 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
fc->async_read = 1;
if (!(arg->flags & FUSE_POSIX_LOCKS))
fc->no_lock = 1;
+ if (arg->minor >= 17) {
+ if (!(arg->flags & FUSE_FLOCK_LOCKS))
+ fc->no_flock = 1;
+ } else {
+ if (!(arg->flags & FUSE_POSIX_LOCKS))
+ fc->no_flock = 1;
+ }
if (arg->flags & FUSE_ATOMIC_O_TRUNC)
fc->atomic_o_trunc = 1;
if (arg->minor >= 9) {
@@ -823,6 +830,7 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
} else {
ra_pages = fc->max_read / PAGE_CACHE_SIZE;
fc->no_lock = 1;
+ fc->no_flock = 1;
}
fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages);
@@ -843,7 +851,8 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
arg->minor = FUSE_KERNEL_MINOR_VERSION;
arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC |
- FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK;
+ FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK |
+ FUSE_FLOCK_LOCKS;
req->in.h.opcode = FUSE_INIT;
req->in.numargs = 1;
req->in.args[0].size = sizeof(*arg);
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 900cf986aadc..6525b804d5ec 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -624,31 +624,29 @@ fail:
return error;
}
-static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
- const struct qstr *qstr)
+int gfs2_initxattrs(struct inode *inode, const struct xattr *xattr_array,
+ void *fs_info)
{
- int err;
- size_t len;
- void *value;
- char *name;
-
- err = security_inode_init_security(&ip->i_inode, &dip->i_inode, qstr,
- &name, &value, &len);
-
- if (err) {
- if (err == -EOPNOTSUPP)
- return 0;
- return err;
+ const struct xattr *xattr;
+ int err = 0;
+
+ for (xattr = xattr_array; xattr->name != NULL; xattr++) {
+ err = __gfs2_xattr_set(inode, xattr->name, xattr->value,
+ xattr->value_len, 0,
+ GFS2_EATYPE_SECURITY);
+ if (err < 0)
+ break;
}
-
- err = __gfs2_xattr_set(&ip->i_inode, name, value, len, 0,
- GFS2_EATYPE_SECURITY);
- kfree(value);
- kfree(name);
-
return err;
}
+static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
+ const struct qstr *qstr)
+{
+ return security_inode_init_security(&ip->i_inode, &dip->i_inode, qstr,
+ &gfs2_initxattrs, NULL);
+}
+
/**
* gfs2_create_inode - Create a new inode
* @dir: The parent directory
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index 85c62923ee29..598646434362 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -624,9 +624,9 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull)
bh->b_end_io = end_buffer_write_sync;
get_bh(bh);
if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags))
- submit_bh(WRITE_SYNC | REQ_META, bh);
+ submit_bh(WRITE_SYNC | REQ_META | REQ_PRIO, bh);
else
- submit_bh(WRITE_FLUSH_FUA | REQ_META, bh);
+ submit_bh(WRITE_FLUSH_FUA | REQ_META | REQ_PRIO, bh);
wait_on_buffer(bh);
if (!buffer_uptodate(bh))
diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c
index 747238cd9f96..be29858900f6 100644
--- a/fs/gfs2/meta_io.c
+++ b/fs/gfs2/meta_io.c
@@ -37,7 +37,7 @@ static int gfs2_aspace_writepage(struct page *page, struct writeback_control *wb
{
struct buffer_head *bh, *head;
int nr_underway = 0;
- int write_op = REQ_META |
+ int write_op = REQ_META | REQ_PRIO |
(wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE);
BUG_ON(!PageLocked(page));
@@ -225,7 +225,7 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
}
bh->b_end_io = end_buffer_read_sync;
get_bh(bh);
- submit_bh(READ_SYNC | REQ_META, bh);
+ submit_bh(READ_SYNC | REQ_META | REQ_PRIO, bh);
if (!(flags & DIO_WAIT))
return 0;
@@ -435,7 +435,7 @@ struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen)
if (buffer_uptodate(first_bh))
goto out;
if (!buffer_locked(first_bh))
- ll_rw_block(READ_SYNC | REQ_META, 1, &first_bh);
+ ll_rw_block(READ_SYNC | REQ_META | REQ_PRIO, 1, &first_bh);
dblock++;
extlen--;
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index 3bc073a4cf82..079587e53849 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -224,7 +224,7 @@ static int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector, int silent)
bio->bi_end_io = end_bio_io_page;
bio->bi_private = page;
- submit_bio(READ_SYNC | REQ_META, bio);
+ submit_bio(READ_SYNC | REQ_META | REQ_PRIO, bio);
wait_on_page_locked(page);
bio_put(bio);
if (!PageUptodate(page)) {
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index 42e8d23bc047..0e8bb13381e4 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -709,7 +709,7 @@ get_a_page:
set_buffer_uptodate(bh);
if (!buffer_uptodate(bh)) {
- ll_rw_block(READ_META, 1, &bh);
+ ll_rw_block(READ | REQ_META | REQ_PRIO, 1, &bh);
wait_on_buffer(bh);
if (!buffer_uptodate(bh))
goto unlock_out;
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index c106ca22e812..d24a9b666a23 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -344,6 +344,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
struct inode *root, *inode;
struct qstr str;
struct nls_table *nls = NULL;
+ u64 last_fs_block, last_fs_page;
int err;
err = -EINVAL;
@@ -399,9 +400,13 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
if (!sbi->rsrc_clump_blocks)
sbi->rsrc_clump_blocks = 1;
- err = generic_check_addressable(sbi->alloc_blksz_shift,
- sbi->total_blocks);
- if (err) {
+ err = -EFBIG;
+ last_fs_block = sbi->total_blocks - 1;
+ last_fs_page = (last_fs_block << sbi->alloc_blksz_shift) >>
+ PAGE_CACHE_SHIFT;
+
+ if ((last_fs_block > (sector_t)(~0ULL) >> (sbi->alloc_blksz_shift - 9)) ||
+ (last_fs_page > (pgoff_t)(~0ULL))) {
printk(KERN_ERR "hfs: filesystem size too large.\n");
goto out_free_vhdr;
}
@@ -525,8 +530,8 @@ out_close_cat_tree:
out_close_ext_tree:
hfs_btree_close(sbi->ext_tree);
out_free_vhdr:
- kfree(sbi->s_vhdr);
- kfree(sbi->s_backup_vhdr);
+ kfree(sbi->s_vhdr_buf);
+ kfree(sbi->s_backup_vhdr_buf);
out_unload_nls:
unload_nls(sbi->nls);
unload_nls(nls);
diff --git a/fs/hfsplus/wrapper.c b/fs/hfsplus/wrapper.c
index 10e515a0d452..7daf4b852d1c 100644
--- a/fs/hfsplus/wrapper.c
+++ b/fs/hfsplus/wrapper.c
@@ -272,9 +272,9 @@ reread:
return 0;
out_free_backup_vhdr:
- kfree(sbi->s_backup_vhdr);
+ kfree(sbi->s_backup_vhdr_buf);
out_free_vhdr:
- kfree(sbi->s_vhdr);
+ kfree(sbi->s_vhdr_buf);
out:
return error;
}
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 87b6e0421c12..ec889538e5a6 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -491,6 +491,7 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid,
inode->i_op = &page_symlink_inode_operations;
break;
}
+ lockdep_annotate_inode_mutex_key(inode);
}
return inode;
}
diff --git a/fs/inode.c b/fs/inode.c
index 73920d555c88..ec7924696a13 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -848,16 +848,9 @@ struct inode *new_inode(struct super_block *sb)
}
EXPORT_SYMBOL(new_inode);
-/**
- * unlock_new_inode - clear the I_NEW state and wake up any waiters
- * @inode: new inode to unlock
- *
- * Called when the inode is fully initialised to clear the new state of the
- * inode and wake up anyone waiting for the inode to finish initialisation.
- */
-void unlock_new_inode(struct inode *inode)
-{
#ifdef CONFIG_DEBUG_LOCK_ALLOC
+void lockdep_annotate_inode_mutex_key(struct inode *inode)
+{
if (S_ISDIR(inode->i_mode)) {
struct file_system_type *type = inode->i_sb->s_type;
@@ -873,7 +866,20 @@ void unlock_new_inode(struct inode *inode)
&type->i_mutex_dir_key);
}
}
+}
+EXPORT_SYMBOL(lockdep_annotate_inode_mutex_key);
#endif
+
+/**
+ * unlock_new_inode - clear the I_NEW state and wake up any waiters
+ * @inode: new inode to unlock
+ *
+ * Called when the inode is fully initialised to clear the new state of the
+ * inode and wake up anyone waiting for the inode to finish initialisation.
+ */
+void unlock_new_inode(struct inode *inode)
+{
+ lockdep_annotate_inode_mutex_key(inode);
spin_lock(&inode->i_lock);
WARN_ON(!(inode->i_state & I_NEW));
inode->i_state &= ~I_NEW;
diff --git a/fs/jffs2/security.c b/fs/jffs2/security.c
index cfeb7164b085..0f20208df602 100644
--- a/fs/jffs2/security.c
+++ b/fs/jffs2/security.c
@@ -22,26 +22,29 @@
#include <linux/security.h>
#include "nodelist.h"
-/* ---- Initial Security Label Attachment -------------- */
-int jffs2_init_security(struct inode *inode, struct inode *dir,
- const struct qstr *qstr)
+/* ---- Initial Security Label(s) Attachment callback --- */
+int jffs2_initxattrs(struct inode *inode, const struct xattr *xattr_array,
+ void *fs_info)
{
- int rc;
- size_t len;
- void *value;
- char *name;
+ const struct xattr *xattr;
+ int err = 0;
- rc = security_inode_init_security(inode, dir, qstr, &name, &value, &len);
- if (rc) {
- if (rc == -EOPNOTSUPP)
- return 0;
- return rc;
+ for (xattr = xattr_array; xattr->name != NULL; xattr++) {
+ err = do_jffs2_setxattr(inode, JFFS2_XPREFIX_SECURITY,
+ xattr->name, xattr->value,
+ xattr->value_len, 0);
+ if (err < 0)
+ break;
}
- rc = do_jffs2_setxattr(inode, JFFS2_XPREFIX_SECURITY, name, value, len, 0);
+ return err;
+}
- kfree(name);
- kfree(value);
- return rc;
+/* ---- Initial Security Label(s) Attachment ----------- */
+int jffs2_init_security(struct inode *inode, struct inode *dir,
+ const struct qstr *qstr)
+{
+ return security_inode_init_security(inode, dir, qstr,
+ &jffs2_initxattrs, NULL);
}
/* ---- XATTR Handler for "security.*" ----------------- */
diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c
index e87fedef23db..26683e15b3ac 100644
--- a/fs/jfs/xattr.c
+++ b/fs/jfs/xattr.c
@@ -1089,38 +1089,37 @@ int jfs_removexattr(struct dentry *dentry, const char *name)
}
#ifdef CONFIG_JFS_SECURITY
-int jfs_init_security(tid_t tid, struct inode *inode, struct inode *dir,
- const struct qstr *qstr)
+int jfs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
+ void *fs_info)
{
- int rc;
- size_t len;
- void *value;
- char *suffix;
+ const struct xattr *xattr;
+ tid_t *tid = fs_info;
char *name;
-
- rc = security_inode_init_security(inode, dir, qstr, &suffix, &value,
- &len);
- if (rc) {
- if (rc == -EOPNOTSUPP)
- return 0;
- return rc;
- }
- name = kmalloc(XATTR_SECURITY_PREFIX_LEN + 1 + strlen(suffix),
- GFP_NOFS);
- if (!name) {
- rc = -ENOMEM;
- goto kmalloc_failed;
+ int err = 0;
+
+ for (xattr = xattr_array; xattr->name != NULL; xattr++) {
+ name = kmalloc(XATTR_SECURITY_PREFIX_LEN +
+ strlen(xattr->name) + 1, GFP_NOFS);
+ if (!name) {
+ err = -ENOMEM;
+ break;
+ }
+ strcpy(name, XATTR_SECURITY_PREFIX);
+ strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name);
+
+ err = __jfs_setxattr(*tid, inode, name,
+ xattr->value, xattr->value_len, 0);
+ kfree(name);
+ if (err < 0)
+ break;
}
- strcpy(name, XATTR_SECURITY_PREFIX);
- strcpy(name + XATTR_SECURITY_PREFIX_LEN, suffix);
-
- rc = __jfs_setxattr(tid, inode, name, value, len, 0);
-
- kfree(name);
-kmalloc_failed:
- kfree(suffix);
- kfree(value);
+ return err;
+}
- return rc;
+int jfs_init_security(tid_t tid, struct inode *inode, struct inode *dir,
+ const struct qstr *qstr)
+{
+ return security_inode_init_security(inode, dir, qstr,
+ &jfs_initxattrs, &tid);
}
#endif
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index b7c99bfb3da6..6f29836ec0cb 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -316,14 +316,8 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
struct hlist_node *pos;
struct nlm_host *host = NULL;
struct nsm_handle *nsm = NULL;
- struct sockaddr_in sin = {
- .sin_family = AF_INET,
- };
- struct sockaddr_in6 sin6 = {
- .sin6_family = AF_INET6,
- };
- struct sockaddr *src_sap;
- size_t src_len = rqstp->rq_addrlen;
+ struct sockaddr *src_sap = svc_daddr(rqstp);
+ size_t src_len = rqstp->rq_daddrlen;
struct nlm_lookup_host_info ni = {
.server = 1,
.sap = svc_addr(rqstp),
@@ -340,21 +334,6 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
mutex_lock(&nlm_host_mutex);
- switch (ni.sap->sa_family) {
- case AF_INET:
- sin.sin_addr.s_addr = rqstp->rq_daddr.addr.s_addr;
- src_sap = (struct sockaddr *)&sin;
- break;
- case AF_INET6:
- ipv6_addr_copy(&sin6.sin6_addr, &rqstp->rq_daddr.addr6);
- src_sap = (struct sockaddr *)&sin6;
- break;
- default:
- dprintk("lockd: %s failed; unrecognized address family\n",
- __func__);
- goto out;
- }
-
if (time_after_eq(jiffies, next_gc))
nlm_gc_hosts();
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index abfff9d7979d..c061b9aa7ddb 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -282,7 +282,7 @@ int lockd_up(void)
/*
* Create the kernel thread and wait for it to start.
*/
- nlmsvc_rqst = svc_prepare_thread(serv, &serv->sv_pools[0]);
+ nlmsvc_rqst = svc_prepare_thread(serv, &serv->sv_pools[0], NUMA_NO_NODE);
if (IS_ERR(nlmsvc_rqst)) {
error = PTR_ERR(nlmsvc_rqst);
nlmsvc_rqst = NULL;
diff --git a/fs/locks.c b/fs/locks.c
index 703f545097de..3b0d05dcd7c1 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -60,7 +60,7 @@
*
* Initial implementation of mandatory locks. SunOS turned out to be
* a rotten model, so I implemented the "obvious" semantics.
- * See 'Documentation/mandatory.txt' for details.
+ * See 'Documentation/filesystems/mandatory-locking.txt' for details.
* Andy Walker (andy@lysaker.kvaerner.no), April 06, 1996.
*
* Don't allow mandatory locks on mmap()'ed files. Added simple functions to
@@ -133,6 +133,20 @@
#define IS_FLOCK(fl) (fl->fl_flags & FL_FLOCK)
#define IS_LEASE(fl) (fl->fl_flags & FL_LEASE)
+static bool lease_breaking(struct file_lock *fl)
+{
+ return fl->fl_flags & (FL_UNLOCK_PENDING | FL_DOWNGRADE_PENDING);
+}
+
+static int target_leasetype(struct file_lock *fl)
+{
+ if (fl->fl_flags & FL_UNLOCK_PENDING)
+ return F_UNLCK;
+ if (fl->fl_flags & FL_DOWNGRADE_PENDING)
+ return F_RDLCK;
+ return fl->fl_type;
+}
+
int leases_enable = 1;
int lease_break_time = 45;
@@ -1119,6 +1133,17 @@ int locks_mandatory_area(int read_write, struct inode *inode,
EXPORT_SYMBOL(locks_mandatory_area);
+static void lease_clear_pending(struct file_lock *fl, int arg)
+{
+ switch (arg) {
+ case F_UNLCK:
+ fl->fl_flags &= ~FL_UNLOCK_PENDING;
+ /* fall through: */
+ case F_RDLCK:
+ fl->fl_flags &= ~FL_DOWNGRADE_PENDING;
+ }
+}
+
/* We already had a lease on this file; just change its type */
int lease_modify(struct file_lock **before, int arg)
{
@@ -1127,6 +1152,7 @@ int lease_modify(struct file_lock **before, int arg)
if (error)
return error;
+ lease_clear_pending(fl, arg);
locks_wake_up_blocks(fl);
if (arg == F_UNLCK)
locks_delete_lock(before);
@@ -1135,19 +1161,25 @@ int lease_modify(struct file_lock **before, int arg)
EXPORT_SYMBOL(lease_modify);
+static bool past_time(unsigned long then)
+{
+ if (!then)
+ /* 0 is a special value meaning "this never expires": */
+ return false;
+ return time_after(jiffies, then);
+}
+
static void time_out_leases(struct inode *inode)
{
struct file_lock **before;
struct file_lock *fl;
before = &inode->i_flock;
- while ((fl = *before) && IS_LEASE(fl) && (fl->fl_type & F_INPROGRESS)) {
- if ((fl->fl_break_time == 0)
- || time_before(jiffies, fl->fl_break_time)) {
- before = &fl->fl_next;
- continue;
- }
- lease_modify(before, fl->fl_type & ~F_INPROGRESS);
+ while ((fl = *before) && IS_LEASE(fl) && lease_breaking(fl)) {
+ if (past_time(fl->fl_downgrade_time))
+ lease_modify(before, F_RDLCK);
+ if (past_time(fl->fl_break_time))
+ lease_modify(before, F_UNLCK);
if (fl == *before) /* lease_modify may have freed fl */
before = &fl->fl_next;
}
@@ -1165,7 +1197,7 @@ static void time_out_leases(struct inode *inode)
*/
int __break_lease(struct inode *inode, unsigned int mode)
{
- int error = 0, future;
+ int error = 0;
struct file_lock *new_fl, *flock;
struct file_lock *fl;
unsigned long break_time;
@@ -1182,24 +1214,13 @@ int __break_lease(struct inode *inode, unsigned int mode)
if ((flock == NULL) || !IS_LEASE(flock))
goto out;
+ if (!locks_conflict(flock, new_fl))
+ goto out;
+
for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next)
if (fl->fl_owner == current->files)
i_have_this_lease = 1;
- if (want_write) {
- /* If we want write access, we have to revoke any lease. */
- future = F_UNLCK | F_INPROGRESS;
- } else if (flock->fl_type & F_INPROGRESS) {
- /* If the lease is already being broken, we just leave it */
- future = flock->fl_type;
- } else if (flock->fl_type & F_WRLCK) {
- /* Downgrade the exclusive lease to a read-only lease. */
- future = F_RDLCK | F_INPROGRESS;
- } else {
- /* the existing lease was read-only, so we can read too. */
- goto out;
- }
-
if (IS_ERR(new_fl) && !i_have_this_lease
&& ((mode & O_NONBLOCK) == 0)) {
error = PTR_ERR(new_fl);
@@ -1214,12 +1235,18 @@ int __break_lease(struct inode *inode, unsigned int mode)
}
for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next) {
- if (fl->fl_type != future) {
- fl->fl_type = future;
+ if (want_write) {
+ if (fl->fl_flags & FL_UNLOCK_PENDING)
+ continue;
+ fl->fl_flags |= FL_UNLOCK_PENDING;
fl->fl_break_time = break_time;
- /* lease must have lmops break callback */
- fl->fl_lmops->lm_break(fl);
+ } else {
+ if (lease_breaking(flock))
+ continue;
+ fl->fl_flags |= FL_DOWNGRADE_PENDING;
+ fl->fl_downgrade_time = break_time;
}
+ fl->fl_lmops->lm_break(fl);
}
if (i_have_this_lease || (mode & O_NONBLOCK)) {
@@ -1243,10 +1270,13 @@ restart:
if (error >= 0) {
if (error == 0)
time_out_leases(inode);
- /* Wait for the next lease that has not been broken yet */
+ /*
+ * Wait for the next conflicting lease that has not been
+ * broken yet
+ */
for (flock = inode->i_flock; flock && IS_LEASE(flock);
flock = flock->fl_next) {
- if (flock->fl_type & F_INPROGRESS)
+ if (locks_conflict(new_fl, flock))
goto restart;
}
error = 0;
@@ -1314,7 +1344,7 @@ int fcntl_getlease(struct file *filp)
for (fl = filp->f_path.dentry->d_inode->i_flock; fl && IS_LEASE(fl);
fl = fl->fl_next) {
if (fl->fl_file == filp) {
- type = fl->fl_type & ~F_INPROGRESS;
+ type = target_leasetype(fl);
break;
}
}
@@ -1322,50 +1352,23 @@ int fcntl_getlease(struct file *filp)
return type;
}
-/**
- * generic_setlease - sets a lease on an open file
- * @filp: file pointer
- * @arg: type of lease to obtain
- * @flp: input - file_lock to use, output - file_lock inserted
- *
- * The (input) flp->fl_lmops->lm_break function is required
- * by break_lease().
- *
- * Called with file_lock_lock held.
- */
-int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
+int generic_add_lease(struct file *filp, long arg, struct file_lock **flp)
{
struct file_lock *fl, **before, **my_before = NULL, *lease;
struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
- int error, rdlease_count = 0, wrlease_count = 0;
+ int error;
lease = *flp;
- error = -EACCES;
- if ((current_fsuid() != inode->i_uid) && !capable(CAP_LEASE))
- goto out;
- error = -EINVAL;
- if (!S_ISREG(inode->i_mode))
+ error = -EAGAIN;
+ if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
goto out;
- error = security_file_lock(filp, arg);
- if (error)
+ if ((arg == F_WRLCK)
+ && ((dentry->d_count > 1)
+ || (atomic_read(&inode->i_count) > 1)))
goto out;
- time_out_leases(inode);
-
- BUG_ON(!(*flp)->fl_lmops->lm_break);
-
- if (arg != F_UNLCK) {
- error = -EAGAIN;
- if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
- goto out;
- if ((arg == F_WRLCK)
- && ((dentry->d_count > 1)
- || (atomic_read(&inode->i_count) > 1)))
- goto out;
- }
-
/*
* At this point, we know that if there is an exclusive
* lease on this file, then we hold it on this filp
@@ -1374,27 +1377,28 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
* then the file is not open by anyone (including us)
* except for this filp.
*/
+ error = -EAGAIN;
for (before = &inode->i_flock;
((fl = *before) != NULL) && IS_LEASE(fl);
before = &fl->fl_next) {
- if (fl->fl_file == filp)
+ if (fl->fl_file == filp) {
my_before = before;
- else if (fl->fl_type == (F_INPROGRESS | F_UNLCK))
- /*
- * Someone is in the process of opening this
- * file for writing so we may not take an
- * exclusive lease on it.
- */
- wrlease_count++;
- else
- rdlease_count++;
+ continue;
+ }
+ /*
+ * No exclusive leases if someone else has a lease on
+ * this file:
+ */
+ if (arg == F_WRLCK)
+ goto out;
+ /*
+ * Modifying our existing lease is OK, but no getting a
+ * new lease if someone else is opening for write:
+ */
+ if (fl->fl_flags & FL_UNLOCK_PENDING)
+ goto out;
}
- error = -EAGAIN;
- if ((arg == F_RDLCK && (wrlease_count > 0)) ||
- (arg == F_WRLCK && ((rdlease_count + wrlease_count) > 0)))
- goto out;
-
if (my_before != NULL) {
error = lease->fl_lmops->lm_change(my_before, arg);
if (!error)
@@ -1402,9 +1406,6 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
goto out;
}
- if (arg == F_UNLCK)
- goto out;
-
error = -EINVAL;
if (!leases_enable)
goto out;
@@ -1415,6 +1416,62 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
out:
return error;
}
+
+int generic_delete_lease(struct file *filp, struct file_lock **flp)
+{
+ struct file_lock *fl, **before;
+ struct dentry *dentry = filp->f_path.dentry;
+ struct inode *inode = dentry->d_inode;
+
+ for (before = &inode->i_flock;
+ ((fl = *before) != NULL) && IS_LEASE(fl);
+ before = &fl->fl_next) {
+ if (fl->fl_file != filp)
+ continue;
+ return (*flp)->fl_lmops->lm_change(before, F_UNLCK);
+ }
+ return -EAGAIN;
+}
+
+/**
+ * generic_setlease - sets a lease on an open file
+ * @filp: file pointer
+ * @arg: type of lease to obtain
+ * @flp: input - file_lock to use, output - file_lock inserted
+ *
+ * The (input) flp->fl_lmops->lm_break function is required
+ * by break_lease().
+ *
+ * Called with file_lock_lock held.
+ */
+int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
+{
+ struct dentry *dentry = filp->f_path.dentry;
+ struct inode *inode = dentry->d_inode;
+ int error;
+
+ if ((current_fsuid() != inode->i_uid) && !capable(CAP_LEASE))
+ return -EACCES;
+ if (!S_ISREG(inode->i_mode))
+ return -EINVAL;
+ error = security_file_lock(filp, arg);
+ if (error)
+ return error;
+
+ time_out_leases(inode);
+
+ BUG_ON(!(*flp)->fl_lmops->lm_break);
+
+ switch (arg) {
+ case F_UNLCK:
+ return generic_delete_lease(filp, flp);
+ case F_RDLCK:
+ case F_WRLCK:
+ return generic_add_lease(filp, arg, flp);
+ default:
+ BUG();
+ }
+}
EXPORT_SYMBOL(generic_setlease);
static int __vfs_setlease(struct file *filp, long arg, struct file_lock **lease)
@@ -2126,7 +2183,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
}
} else if (IS_LEASE(fl)) {
seq_printf(f, "LEASE ");
- if (fl->fl_type & F_INPROGRESS)
+ if (lease_breaking(fl))
seq_printf(f, "BREAKING ");
else if (fl->fl_file)
seq_printf(f, "ACTIVE ");
@@ -2142,7 +2199,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
: (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE ");
} else {
seq_printf(f, "%s ",
- (fl->fl_type & F_INPROGRESS)
+ (lease_breaking(fl))
? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ "
: (fl->fl_type & F_WRLCK) ? "WRITE" : "READ ");
}
diff --git a/fs/namei.c b/fs/namei.c
index 2826db35dc25..0b3138de2a3b 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -721,31 +721,22 @@ static int follow_automount(struct path *path, unsigned flags,
if (!path->dentry->d_op || !path->dentry->d_op->d_automount)
return -EREMOTE;
- /* We don't want to mount if someone supplied AT_NO_AUTOMOUNT
- * and this is the terminal part of the path.
+ /* We don't want to mount if someone's just doing a stat -
+ * unless they're stat'ing a directory and appended a '/' to
+ * the name.
+ *
+ * We do, however, want to mount if someone wants to open or
+ * create a file of any type under the mountpoint, wants to
+ * traverse through the mountpoint or wants to open the
+ * mounted directory. Also, autofs may mark negative dentries
+ * as being automount points. These will need the attentions
+ * of the daemon to instantiate them before they can be used.
*/
- if ((flags & LOOKUP_NO_AUTOMOUNT) && !(flags & LOOKUP_PARENT))
- return -EISDIR; /* we actually want to stop here */
+ if (!(flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY |
+ LOOKUP_OPEN | LOOKUP_CREATE | LOOKUP_AUTOMOUNT)) &&
+ path->dentry->d_inode)
+ return -EISDIR;
- /*
- * We don't want to mount if someone's just doing a stat and they've
- * set AT_SYMLINK_NOFOLLOW - unless they're stat'ing a directory and
- * appended a '/' to the name.
- */
- if (!(flags & LOOKUP_FOLLOW)) {
- /* We do, however, want to mount if someone wants to open or
- * create a file of any type under the mountpoint, wants to
- * traverse through the mountpoint or wants to open the mounted
- * directory.
- * Also, autofs may mark negative dentries as being automount
- * points. These will need the attentions of the daemon to
- * instantiate them before they can be used.
- */
- if (!(flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY |
- LOOKUP_OPEN | LOOKUP_CREATE)) &&
- path->dentry->d_inode)
- return -EISDIR;
- }
current->total_link_count++;
if (current->total_link_count >= 40)
return -ELOOP;
@@ -2619,6 +2610,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
if (!dir->i_op->rmdir)
return -EPERM;
+ dget(dentry);
mutex_lock(&dentry->d_inode->i_mutex);
error = -EBUSY;
@@ -2639,6 +2631,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
out:
mutex_unlock(&dentry->d_inode->i_mutex);
+ dput(dentry);
if (!error)
d_delete(dentry);
return error;
@@ -3028,6 +3021,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
if (error)
return error;
+ dget(new_dentry);
if (target)
mutex_lock(&target->i_mutex);
@@ -3048,6 +3042,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
out:
if (target)
mutex_unlock(&target->i_mutex);
+ dput(new_dentry);
if (!error)
if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
d_move(old_dentry,new_dentry);
diff --git a/fs/namespace.c b/fs/namespace.c
index 22bfe8273c68..b4febb29d3bb 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1757,7 +1757,7 @@ static int do_loopback(struct path *path, char *old_name,
return err;
if (!old_name || !*old_name)
return -EINVAL;
- err = kern_path(old_name, LOOKUP_FOLLOW, &old_path);
+ err = kern_path(old_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
if (err)
return err;
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c
index 9561c8fc8bdb..281ae95932c9 100644
--- a/fs/nfs/blocklayout/blocklayout.c
+++ b/fs/nfs/blocklayout/blocklayout.c
@@ -176,17 +176,6 @@ retry:
return bio;
}
-static void bl_set_lo_fail(struct pnfs_layout_segment *lseg)
-{
- if (lseg->pls_range.iomode == IOMODE_RW) {
- dprintk("%s Setting layout IOMODE_RW fail bit\n", __func__);
- set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
- } else {
- dprintk("%s Setting layout IOMODE_READ fail bit\n", __func__);
- set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
- }
-}
-
/* This is basically copied from mpage_end_io_read */
static void bl_end_io_read(struct bio *bio, int err)
{
@@ -206,7 +195,7 @@ static void bl_end_io_read(struct bio *bio, int err)
if (!uptodate) {
if (!rdata->pnfs_error)
rdata->pnfs_error = -EIO;
- bl_set_lo_fail(rdata->lseg);
+ pnfs_set_lo_fail(rdata->lseg);
}
bio_put(bio);
put_parallel(par);
@@ -303,6 +292,7 @@ bl_read_pagelist(struct nfs_read_data *rdata)
bl_end_io_read, par);
if (IS_ERR(bio)) {
rdata->pnfs_error = PTR_ERR(bio);
+ bio = NULL;
goto out;
}
}
@@ -370,7 +360,7 @@ static void bl_end_io_write_zero(struct bio *bio, int err)
if (!uptodate) {
if (!wdata->pnfs_error)
wdata->pnfs_error = -EIO;
- bl_set_lo_fail(wdata->lseg);
+ pnfs_set_lo_fail(wdata->lseg);
}
bio_put(bio);
put_parallel(par);
@@ -386,7 +376,7 @@ static void bl_end_io_write(struct bio *bio, int err)
if (!uptodate) {
if (!wdata->pnfs_error)
wdata->pnfs_error = -EIO;
- bl_set_lo_fail(wdata->lseg);
+ pnfs_set_lo_fail(wdata->lseg);
}
bio_put(bio);
put_parallel(par);
@@ -543,6 +533,11 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync)
fill_invalid_ext:
dprintk("%s need to zero %d pages\n", __func__, npg_zero);
for (;npg_zero > 0; npg_zero--) {
+ if (bl_is_sector_init(be->be_inval, isect)) {
+ dprintk("isect %llu already init\n",
+ (unsigned long long)isect);
+ goto next_page;
+ }
/* page ref released in bl_end_io_write_zero */
index = isect >> PAGE_CACHE_SECTOR_SHIFT;
dprintk("%s zero %dth page: index %lu isect %llu\n",
@@ -562,8 +557,7 @@ fill_invalid_ext:
* PageUptodate: It was read before
* sector_initialized: already written out
*/
- if (PageDirty(page) || PageWriteback(page) ||
- bl_is_sector_init(be->be_inval, isect)) {
+ if (PageDirty(page) || PageWriteback(page)) {
print_page(page);
unlock_page(page);
page_cache_release(page);
@@ -592,6 +586,7 @@ fill_invalid_ext:
bl_end_io_write_zero, par);
if (IS_ERR(bio)) {
wdata->pnfs_error = PTR_ERR(bio);
+ bio = NULL;
goto out;
}
/* FIXME: This should be done in bi_end_io */
@@ -640,6 +635,7 @@ next_page:
bl_end_io_write, par);
if (IS_ERR(bio)) {
wdata->pnfs_error = PTR_ERR(bio);
+ bio = NULL;
goto out;
}
isect += PAGE_CACHE_SECTORS;
@@ -805,7 +801,7 @@ nfs4_blk_get_deviceinfo(struct nfs_server *server, const struct nfs_fh *fh,
struct nfs4_deviceid *d_id)
{
struct pnfs_device *dev;
- struct pnfs_block_dev *rv = NULL;
+ struct pnfs_block_dev *rv;
u32 max_resp_sz;
int max_pages;
struct page **pages = NULL;
@@ -823,18 +819,20 @@ nfs4_blk_get_deviceinfo(struct nfs_server *server, const struct nfs_fh *fh,
dev = kmalloc(sizeof(*dev), GFP_NOFS);
if (!dev) {
dprintk("%s kmalloc failed\n", __func__);
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
pages = kzalloc(max_pages * sizeof(struct page *), GFP_NOFS);
if (pages == NULL) {
kfree(dev);
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
for (i = 0; i < max_pages; i++) {
pages[i] = alloc_page(GFP_NOFS);
- if (!pages[i])
+ if (!pages[i]) {
+ rv = ERR_PTR(-ENOMEM);
goto out_free;
+ }
}
memcpy(&dev->dev_id, d_id, sizeof(*d_id));
@@ -847,8 +845,10 @@ nfs4_blk_get_deviceinfo(struct nfs_server *server, const struct nfs_fh *fh,
dprintk("%s: dev_id: %s\n", __func__, dev->dev_id.data);
rc = nfs4_proc_getdeviceinfo(server, dev);
dprintk("%s getdevice info returns %d\n", __func__, rc);
- if (rc)
+ if (rc) {
+ rv = ERR_PTR(rc);
goto out_free;
+ }
rv = nfs4_blk_decode_device(server, dev);
out_free:
@@ -866,7 +866,7 @@ bl_set_layoutdriver(struct nfs_server *server, const struct nfs_fh *fh)
struct pnfs_devicelist *dlist = NULL;
struct pnfs_block_dev *bdev;
LIST_HEAD(block_disklist);
- int status = 0, i;
+ int status, i;
dprintk("%s enter\n", __func__);
@@ -898,8 +898,8 @@ bl_set_layoutdriver(struct nfs_server *server, const struct nfs_fh *fh)
for (i = 0; i < dlist->num_devs; i++) {
bdev = nfs4_blk_get_deviceinfo(server, fh,
&dlist->dev_id[i]);
- if (!bdev) {
- status = -ENODEV;
+ if (IS_ERR(bdev)) {
+ status = PTR_ERR(bdev);
goto out_error;
}
spin_lock(&b_mt_id->bm_lock);
@@ -960,7 +960,7 @@ static struct pnfs_layoutdriver_type blocklayout_type = {
};
static const struct rpc_pipe_ops bl_upcall_ops = {
- .upcall = bl_pipe_upcall,
+ .upcall = rpc_pipe_generic_upcall,
.downcall = bl_pipe_downcall,
.destroy_msg = bl_pipe_destroy_msg,
};
@@ -989,17 +989,20 @@ static int __init nfs4blocklayout_init(void)
mnt,
NFS_PIPE_DIRNAME, 0, &path);
if (ret)
- goto out_remove;
+ goto out_putrpc;
bl_device_pipe = rpc_mkpipe(path.dentry, "blocklayout", NULL,
&bl_upcall_ops, 0);
+ path_put(&path);
if (IS_ERR(bl_device_pipe)) {
ret = PTR_ERR(bl_device_pipe);
- goto out_remove;
+ goto out_putrpc;
}
out:
return ret;
+out_putrpc:
+ rpc_put_mount();
out_remove:
pnfs_unregister_layoutdriver(&blocklayout_type);
return ret;
@@ -1012,6 +1015,7 @@ static void __exit nfs4blocklayout_exit(void)
pnfs_unregister_layoutdriver(&blocklayout_type);
rpc_unlink(bl_device_pipe);
+ rpc_put_mount();
}
MODULE_ALIAS("nfs-layouttype4-3");
diff --git a/fs/nfs/blocklayout/blocklayout.h b/fs/nfs/blocklayout/blocklayout.h
index f27d827960a3..42acf7ef5992 100644
--- a/fs/nfs/blocklayout/blocklayout.h
+++ b/fs/nfs/blocklayout/blocklayout.h
@@ -150,7 +150,7 @@ BLK_LSEG2EXT(struct pnfs_layout_segment *lseg)
}
struct bl_dev_msg {
- int status;
+ int32_t status;
uint32_t major, minor;
};
@@ -169,8 +169,6 @@ extern wait_queue_head_t bl_wq;
#define BL_DEVICE_REQUEST_ERR 0x2 /* User level process fails */
/* blocklayoutdev.c */
-ssize_t bl_pipe_upcall(struct file *, struct rpc_pipe_msg *,
- char __user *, size_t);
ssize_t bl_pipe_downcall(struct file *, const char __user *, size_t);
void bl_pipe_destroy_msg(struct rpc_pipe_msg *);
struct block_device *nfs4_blkdev_get(dev_t dev);
diff --git a/fs/nfs/blocklayout/blocklayoutdev.c b/fs/nfs/blocklayout/blocklayoutdev.c
index a83b393fb01c..d08ba9107fde 100644
--- a/fs/nfs/blocklayout/blocklayoutdev.c
+++ b/fs/nfs/blocklayout/blocklayoutdev.c
@@ -79,28 +79,6 @@ int nfs4_blkdev_put(struct block_device *bdev)
return blkdev_put(bdev, FMODE_READ);
}
-/*
- * Shouldn't there be a rpc_generic_upcall() to do this for us?
- */
-ssize_t bl_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg,
- char __user *dst, size_t buflen)
-{
- char *data = (char *)msg->data + msg->copied;
- size_t mlen = min(msg->len - msg->copied, buflen);
- unsigned long left;
-
- left = copy_to_user(dst, data, mlen);
- if (left == mlen) {
- msg->errno = -EFAULT;
- return -EFAULT;
- }
-
- mlen -= left;
- msg->copied += mlen;
- msg->errno = 0;
- return mlen;
-}
-
static struct bl_dev_msg bl_mount_reply;
ssize_t bl_pipe_downcall(struct file *filp, const char __user *src,
@@ -131,7 +109,7 @@ struct pnfs_block_dev *
nfs4_blk_decode_device(struct nfs_server *server,
struct pnfs_device *dev)
{
- struct pnfs_block_dev *rv = NULL;
+ struct pnfs_block_dev *rv;
struct block_device *bd = NULL;
struct rpc_pipe_msg msg;
struct bl_msg_hdr bl_msg = {
@@ -141,7 +119,7 @@ nfs4_blk_decode_device(struct nfs_server *server,
uint8_t *dataptr;
DECLARE_WAITQUEUE(wq, current);
struct bl_dev_msg *reply = &bl_mount_reply;
- int offset, len, i;
+ int offset, len, i, rc;
dprintk("%s CREATING PIPEFS MESSAGE\n", __func__);
dprintk("%s: deviceid: %s, mincount: %d\n", __func__, dev->dev_id.data,
@@ -168,8 +146,10 @@ nfs4_blk_decode_device(struct nfs_server *server,
dprintk("%s CALLING USERSPACE DAEMON\n", __func__);
add_wait_queue(&bl_wq, &wq);
- if (rpc_queue_upcall(bl_device_pipe->d_inode, &msg) < 0) {
+ rc = rpc_queue_upcall(bl_device_pipe->d_inode, &msg);
+ if (rc < 0) {
remove_wait_queue(&bl_wq, &wq);
+ rv = ERR_PTR(rc);
goto out;
}
@@ -187,8 +167,9 @@ nfs4_blk_decode_device(struct nfs_server *server,
bd = nfs4_blkdev_get(MKDEV(reply->major, reply->minor));
if (IS_ERR(bd)) {
- dprintk("%s failed to open device : %ld\n",
- __func__, PTR_ERR(bd));
+ rc = PTR_ERR(bd);
+ dprintk("%s failed to open device : %d\n", __func__, rc);
+ rv = ERR_PTR(rc);
goto out;
}
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index e3d294269058..516f3375e067 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -125,7 +125,7 @@ nfs4_callback_up(struct svc_serv *serv)
else
goto out_err;
- return svc_prepare_thread(serv, &serv->sv_pools[0]);
+ return svc_prepare_thread(serv, &serv->sv_pools[0], NUMA_NO_NODE);
out_err:
if (ret == 0)
@@ -199,7 +199,7 @@ nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt)
INIT_LIST_HEAD(&serv->sv_cb_list);
spin_lock_init(&serv->sv_cb_lock);
init_waitqueue_head(&serv->sv_cb_waitq);
- rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]);
+ rqstp = svc_prepare_thread(serv, &serv->sv_pools[0], NUMA_NO_NODE);
if (IS_ERR(rqstp)) {
svc_xprt_put(serv->sv_bc_xprt);
serv->sv_bc_xprt = NULL;
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 5833fbbf59b0..873bf00d51a2 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -336,11 +336,12 @@ static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1,
const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1;
const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2;
- if (ipv6_addr_scope(&sin1->sin6_addr) == IPV6_ADDR_SCOPE_LINKLOCAL &&
- sin1->sin6_scope_id != sin2->sin6_scope_id)
+ if (!ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr))
return 0;
+ else if (ipv6_addr_type(&sin1->sin6_addr) & IPV6_ADDR_LINKLOCAL)
+ return sin1->sin6_scope_id == sin2->sin6_scope_id;
- return ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr);
+ return 1;
}
#else /* !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE) */
static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1,
@@ -1867,6 +1868,10 @@ static int nfs_server_list_show(struct seq_file *m, void *v)
/* display one transport per line on subsequent lines */
clp = list_entry(v, struct nfs_client, cl_share_link);
+ /* Check if the client is initialized */
+ if (clp->cl_cons_state != NFS_CS_READY)
+ return 0;
+
seq_printf(m, "v%u %s %s %3d %s\n",
clp->rpc_ops->version,
rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 321a66bc3846..7f2654069806 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -240,7 +240,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
sizeof(delegation->stateid.data));
delegation->type = res->delegation_type;
delegation->maxsize = res->maxsize;
- delegation->change_attr = nfsi->change_attr;
+ delegation->change_attr = inode->i_version;
delegation->cred = get_rpccred(cred);
delegation->inode = inode;
delegation->flags = 1<<NFS_DELEGATION_REFERENCED;
diff --git a/fs/nfs/fscache-index.c b/fs/nfs/fscache-index.c
index 5b1006480bc2..7cf2c4699b08 100644
--- a/fs/nfs/fscache-index.c
+++ b/fs/nfs/fscache-index.c
@@ -212,7 +212,7 @@ static uint16_t nfs_fscache_inode_get_aux(const void *cookie_netfs_data,
auxdata.ctime = nfsi->vfs_inode.i_ctime;
if (NFS_SERVER(&nfsi->vfs_inode)->nfs_client->rpc_ops->version == 4)
- auxdata.change_attr = nfsi->change_attr;
+ auxdata.change_attr = nfsi->vfs_inode.i_version;
if (bufmax > sizeof(auxdata))
bufmax = sizeof(auxdata);
@@ -244,7 +244,7 @@ enum fscache_checkaux nfs_fscache_inode_check_aux(void *cookie_netfs_data,
auxdata.ctime = nfsi->vfs_inode.i_ctime;
if (NFS_SERVER(&nfsi->vfs_inode)->nfs_client->rpc_ops->version == 4)
- auxdata.change_attr = nfsi->change_attr;
+ auxdata.change_attr = nfsi->vfs_inode.i_version;
if (memcmp(data, &auxdata, datalen) != 0)
return FSCACHE_CHECKAUX_OBSOLETE;
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
index f20801ae0a16..47d1c6ff2d8e 100644
--- a/fs/nfs/idmap.c
+++ b/fs/nfs/idmap.c
@@ -336,8 +336,6 @@ struct idmap {
struct idmap_hashtable idmap_group_hash;
};
-static ssize_t idmap_pipe_upcall(struct file *, struct rpc_pipe_msg *,
- char __user *, size_t);
static ssize_t idmap_pipe_downcall(struct file *, const char __user *,
size_t);
static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
@@ -345,7 +343,7 @@ static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
static unsigned int fnvhash32(const void *, size_t);
static const struct rpc_pipe_ops idmap_upcall_ops = {
- .upcall = idmap_pipe_upcall,
+ .upcall = rpc_pipe_generic_upcall,
.downcall = idmap_pipe_downcall,
.destroy_msg = idmap_pipe_destroy_msg,
};
@@ -595,27 +593,6 @@ nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h,
return ret;
}
-/* RPC pipefs upcall/downcall routines */
-static ssize_t
-idmap_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg,
- char __user *dst, size_t buflen)
-{
- char *data = (char *)msg->data + msg->copied;
- size_t mlen = min(msg->len, buflen);
- unsigned long left;
-
- left = copy_to_user(dst, data, mlen);
- if (left == mlen) {
- msg->errno = -EFAULT;
- return -EFAULT;
- }
-
- mlen -= left;
- msg->copied += mlen;
- msg->errno = 0;
- return mlen;
-}
-
static ssize_t
idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
{
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index fe1203797b2b..4dc6d078f108 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -318,7 +318,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
memset(&inode->i_atime, 0, sizeof(inode->i_atime));
memset(&inode->i_mtime, 0, sizeof(inode->i_mtime));
memset(&inode->i_ctime, 0, sizeof(inode->i_ctime));
- nfsi->change_attr = 0;
+ inode->i_version = 0;
inode->i_size = 0;
inode->i_nlink = 0;
inode->i_uid = -2;
@@ -344,7 +344,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
| NFS_INO_INVALID_ACCESS
| NFS_INO_INVALID_ACL;
if (fattr->valid & NFS_ATTR_FATTR_CHANGE)
- nfsi->change_attr = fattr->change_attr;
+ inode->i_version = fattr->change_attr;
else if (nfs_server_capable(inode, NFS_CAP_CHANGE_ATTR))
nfsi->cache_validity |= NFS_INO_INVALID_ATTR
| NFS_INO_INVALID_DATA;
@@ -897,8 +897,8 @@ static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr
if ((fattr->valid & NFS_ATTR_FATTR_PRECHANGE)
&& (fattr->valid & NFS_ATTR_FATTR_CHANGE)
- && nfsi->change_attr == fattr->pre_change_attr) {
- nfsi->change_attr = fattr->change_attr;
+ && inode->i_version == fattr->pre_change_attr) {
+ inode->i_version = fattr->change_attr;
if (S_ISDIR(inode->i_mode))
nfsi->cache_validity |= NFS_INO_INVALID_DATA;
ret |= NFS_INO_INVALID_ATTR;
@@ -952,7 +952,7 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
return -EIO;
if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 &&
- nfsi->change_attr != fattr->change_attr)
+ inode->i_version != fattr->change_attr)
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
/* Verify a few of the more important attributes */
@@ -1163,7 +1163,7 @@ int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fa
}
if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 &&
(fattr->valid & NFS_ATTR_FATTR_PRECHANGE) == 0) {
- fattr->pre_change_attr = NFS_I(inode)->change_attr;
+ fattr->pre_change_attr = inode->i_version;
fattr->valid |= NFS_ATTR_FATTR_PRECHANGE;
}
if ((fattr->valid & NFS_ATTR_FATTR_CTIME) != 0 &&
@@ -1244,13 +1244,13 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
/* More cache consistency checks */
if (fattr->valid & NFS_ATTR_FATTR_CHANGE) {
- if (nfsi->change_attr != fattr->change_attr) {
+ if (inode->i_version != fattr->change_attr) {
dprintk("NFS: change_attr change on server for file %s/%ld\n",
inode->i_sb->s_id, inode->i_ino);
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
if (S_ISDIR(inode->i_mode))
nfs_force_lookup_revalidate(inode);
- nfsi->change_attr = fattr->change_attr;
+ inode->i_version = fattr->change_attr;
}
} else if (server->caps & NFS_CAP_CHANGE_ATTR)
invalid |= save_cache_validity;
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index ab12913dd473..c1a1bd8ddf1c 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -457,13 +457,3 @@ unsigned int nfs_page_array_len(unsigned int base, size_t len)
PAGE_SIZE - 1) >> PAGE_SHIFT;
}
-/*
- * Helper for restarting RPC calls in the possible presence of NFSv4.1
- * sessions.
- */
-static inline int nfs_restart_rpc(struct rpc_task *task, const struct nfs_client *clp)
-{
- if (nfs4_has_session(clp))
- return rpc_restart_call_prepare(task);
- return rpc_restart_call(task);
-}
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 1ec1a85fa71c..693ae22f8731 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -13,30 +13,6 @@
struct idmap;
-/*
- * In a seqid-mutating op, this macro controls which error return
- * values trigger incrementation of the seqid.
- *
- * from rfc 3010:
- * The client MUST monotonically increment the sequence number for the
- * CLOSE, LOCK, LOCKU, OPEN, OPEN_CONFIRM, and OPEN_DOWNGRADE
- * operations. This is true even in the event that the previous
- * operation that used the sequence number received an error. The only
- * exception to this rule is if the previous operation received one of
- * the following errors: NFSERR_STALE_CLIENTID, NFSERR_STALE_STATEID,
- * NFSERR_BAD_STATEID, NFSERR_BAD_SEQID, NFSERR_BADXDR,
- * NFSERR_RESOURCE, NFSERR_NOFILEHANDLE.
- *
- */
-#define seqid_mutating_err(err) \
-(((err) != NFSERR_STALE_CLIENTID) && \
- ((err) != NFSERR_STALE_STATEID) && \
- ((err) != NFSERR_BAD_STATEID) && \
- ((err) != NFSERR_BAD_SEQID) && \
- ((err) != NFSERR_BAD_XDR) && \
- ((err) != NFSERR_RESOURCE) && \
- ((err) != NFSERR_NOFILEHANDLE))
-
enum nfs4_client_state {
NFS4CLNT_MANAGER_RUNNING = 0,
NFS4CLNT_CHECK_LEASE,
@@ -56,6 +32,9 @@ enum nfs4_session_state {
NFS4_SESSION_DRAINING,
};
+#define NFS4_RENEW_TIMEOUT 0x01
+#define NFS4_RENEW_DELEGATION_CB 0x02
+
struct nfs4_minor_version_ops {
u32 minor_version;
@@ -225,7 +204,7 @@ struct nfs4_state_recovery_ops {
};
struct nfs4_state_maintenance_ops {
- int (*sched_state_renewal)(struct nfs_client *, struct rpc_cred *);
+ int (*sched_state_renewal)(struct nfs_client *, struct rpc_cred *, unsigned);
struct rpc_cred * (*get_state_renewal_cred_locked)(struct nfs_client *);
int (*renew_lease)(struct nfs_client *, struct rpc_cred *);
};
@@ -237,8 +216,6 @@ extern const struct inode_operations nfs4_dir_inode_operations;
extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *, struct nfs4_setclientid_res *);
extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct nfs4_setclientid_res *arg, struct rpc_cred *);
extern int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred);
-extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *);
-extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *);
extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *);
extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *);
extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc);
@@ -349,6 +326,7 @@ extern void nfs4_close_sync(struct nfs4_state *, fmode_t);
extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t);
extern void nfs4_schedule_lease_recovery(struct nfs_client *);
extern void nfs4_schedule_state_manager(struct nfs_client *);
+extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp);
extern void nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs4_state *);
extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags);
extern void nfs41_handle_recall_slot(struct nfs_client *clp);
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
index e8915d4840ad..09119418402f 100644
--- a/fs/nfs/nfs4filelayout.c
+++ b/fs/nfs/nfs4filelayout.c
@@ -77,19 +77,6 @@ filelayout_get_dserver_offset(struct pnfs_layout_segment *lseg, loff_t offset)
BUG();
}
-/* For data server errors we don't recover from */
-static void
-filelayout_set_lo_fail(struct pnfs_layout_segment *lseg)
-{
- if (lseg->pls_range.iomode == IOMODE_RW) {
- dprintk("%s Setting layout IOMODE_RW fail bit\n", __func__);
- set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
- } else {
- dprintk("%s Setting layout IOMODE_READ fail bit\n", __func__);
- set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
- }
-}
-
static int filelayout_async_handle_error(struct rpc_task *task,
struct nfs4_state *state,
struct nfs_client *clp,
@@ -135,7 +122,6 @@ static int filelayout_async_handle_error(struct rpc_task *task,
static int filelayout_read_done_cb(struct rpc_task *task,
struct nfs_read_data *data)
{
- struct nfs_client *clp = data->ds_clp;
int reset = 0;
dprintk("%s DS read\n", __func__);
@@ -145,11 +131,10 @@ static int filelayout_read_done_cb(struct rpc_task *task,
dprintk("%s calling restart ds_clp %p ds_clp->cl_session %p\n",
__func__, data->ds_clp, data->ds_clp->cl_session);
if (reset) {
- filelayout_set_lo_fail(data->lseg);
+ pnfs_set_lo_fail(data->lseg);
nfs4_reset_read(task, data);
- clp = NFS_SERVER(data->inode)->nfs_client;
}
- nfs_restart_rpc(task, clp);
+ rpc_restart_call_prepare(task);
return -EAGAIN;
}
@@ -216,17 +201,13 @@ static int filelayout_write_done_cb(struct rpc_task *task,
if (filelayout_async_handle_error(task, data->args.context->state,
data->ds_clp, &reset) == -EAGAIN) {
- struct nfs_client *clp;
-
dprintk("%s calling restart ds_clp %p ds_clp->cl_session %p\n",
__func__, data->ds_clp, data->ds_clp->cl_session);
if (reset) {
- filelayout_set_lo_fail(data->lseg);
+ pnfs_set_lo_fail(data->lseg);
nfs4_reset_write(task, data);
- clp = NFS_SERVER(data->inode)->nfs_client;
- } else
- clp = data->ds_clp;
- nfs_restart_rpc(task, clp);
+ }
+ rpc_restart_call_prepare(task);
return -EAGAIN;
}
@@ -256,9 +237,9 @@ static int filelayout_commit_done_cb(struct rpc_task *task,
__func__, data->ds_clp, data->ds_clp->cl_session);
if (reset) {
prepare_to_resend_writes(data);
- filelayout_set_lo_fail(data->lseg);
+ pnfs_set_lo_fail(data->lseg);
} else
- nfs_restart_rpc(task, data->ds_clp);
+ rpc_restart_call_prepare(task);
return -EAGAIN;
}
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 8c77039e7a81..d2ae413c986a 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -73,9 +73,6 @@ static int _nfs4_proc_open(struct nfs4_opendata *data);
static int _nfs4_recover_proc_open(struct nfs4_opendata *data);
static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *);
-static int _nfs4_proc_lookup(struct rpc_clnt *client, struct inode *dir,
- const struct qstr *name, struct nfs_fh *fhandle,
- struct nfs_fattr *fattr);
static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
struct nfs_fattr *fattr, struct iattr *sattr,
@@ -753,9 +750,9 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
spin_lock(&dir->i_lock);
nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA;
- if (!cinfo->atomic || cinfo->before != nfsi->change_attr)
+ if (!cinfo->atomic || cinfo->before != dir->i_version)
nfs_force_lookup_revalidate(dir);
- nfsi->change_attr = cinfo->after;
+ dir->i_version = cinfo->after;
spin_unlock(&dir->i_lock);
}
@@ -1596,8 +1593,14 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
int status;
status = nfs4_run_open_task(data, 0);
- if (status != 0 || !data->rpc_done)
+ if (!data->rpc_done)
+ return status;
+ if (status != 0) {
+ if (status == -NFS4ERR_BADNAME &&
+ !(o_arg->open_flags & O_CREAT))
+ return -ENOENT;
return status;
+ }
if (o_arg->open_flags & O_CREAT) {
update_changeattr(dir, &o_res->cinfo);
@@ -2408,14 +2411,15 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
return status;
}
-static int _nfs4_proc_lookupfh(struct rpc_clnt *clnt, struct nfs_server *server,
- const struct nfs_fh *dirfh, const struct qstr *name,
- struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
+ const struct qstr *name, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr)
{
+ struct nfs_server *server = NFS_SERVER(dir);
int status;
struct nfs4_lookup_arg args = {
.bitmask = server->attr_bitmask,
- .dir_fh = dirfh,
+ .dir_fh = NFS_FH(dir),
.name = name,
};
struct nfs4_lookup_res res = {
@@ -2431,40 +2435,8 @@ static int _nfs4_proc_lookupfh(struct rpc_clnt *clnt, struct nfs_server *server,
nfs_fattr_init(fattr);
- dprintk("NFS call lookupfh %s\n", name->name);
- status = nfs4_call_sync(clnt, server, &msg, &args.seq_args, &res.seq_res, 0);
- dprintk("NFS reply lookupfh: %d\n", status);
- return status;
-}
-
-static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh,
- struct qstr *name, struct nfs_fh *fhandle,
- struct nfs_fattr *fattr)
-{
- struct nfs4_exception exception = { };
- int err;
- do {
- err = _nfs4_proc_lookupfh(server->client, server, dirfh, name, fhandle, fattr);
- /* FIXME: !!!! */
- if (err == -NFS4ERR_MOVED) {
- err = -EREMOTE;
- break;
- }
- err = nfs4_handle_exception(server, err, &exception);
- } while (exception.retry);
- return err;
-}
-
-static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
- const struct qstr *name, struct nfs_fh *fhandle,
- struct nfs_fattr *fattr)
-{
- int status;
-
dprintk("NFS call lookup %s\n", name->name);
- status = _nfs4_proc_lookupfh(clnt, NFS_SERVER(dir), NFS_FH(dir), name, fhandle, fattr);
- if (status == -NFS4ERR_MOVED)
- status = nfs4_get_referral(dir, name, fattr, fhandle);
+ status = nfs4_call_sync(clnt, server, &msg, &args.seq_args, &res.seq_res, 0);
dprintk("NFS reply lookup: %d\n", status);
return status;
}
@@ -2485,11 +2457,20 @@ static int nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, struct qst
struct nfs4_exception exception = { };
int err;
do {
- err = nfs4_handle_exception(NFS_SERVER(dir),
- _nfs4_proc_lookup(clnt, dir, name, fhandle, fattr),
- &exception);
- if (err == -EPERM)
+ int status;
+
+ status = _nfs4_proc_lookup(clnt, dir, name, fhandle, fattr);
+ switch (status) {
+ case -NFS4ERR_BADNAME:
+ return -ENOENT;
+ case -NFS4ERR_MOVED:
+ err = nfs4_get_referral(dir, name, fattr, fhandle);
+ break;
+ case -NFS4ERR_WRONGSEC:
nfs_fixup_secinfo_attributes(fattr, fhandle);
+ }
+ err = nfs4_handle_exception(NFS_SERVER(dir),
+ status, &exception);
} while (exception.retry);
return err;
}
@@ -3210,7 +3191,7 @@ static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_read_data *data)
struct nfs_server *server = NFS_SERVER(data->inode);
if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) {
- nfs_restart_rpc(task, server->nfs_client);
+ rpc_restart_call_prepare(task);
return -EAGAIN;
}
@@ -3260,7 +3241,7 @@ static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_write_data *data
struct inode *inode = data->inode;
if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) {
- nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client);
+ rpc_restart_call_prepare(task);
return -EAGAIN;
}
if (task->tk_status >= 0) {
@@ -3317,7 +3298,7 @@ static int nfs4_commit_done_cb(struct rpc_task *task, struct nfs_write_data *dat
struct inode *inode = data->inode;
if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) {
- nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client);
+ rpc_restart_call_prepare(task);
return -EAGAIN;
}
nfs_refresh_inode(inode, data->res.fattr);
@@ -3374,9 +3355,13 @@ static void nfs4_renew_done(struct rpc_task *task, void *calldata)
if (task->tk_status < 0) {
/* Unless we're shutting down, schedule state recovery! */
- if (test_bit(NFS_CS_RENEWD, &clp->cl_res_state) != 0)
+ if (test_bit(NFS_CS_RENEWD, &clp->cl_res_state) == 0)
+ return;
+ if (task->tk_status != NFS4ERR_CB_PATH_DOWN) {
nfs4_schedule_lease_recovery(clp);
- return;
+ return;
+ }
+ nfs4_schedule_path_down_recovery(clp);
}
do_renew_lease(clp, timestamp);
}
@@ -3386,7 +3371,7 @@ static const struct rpc_call_ops nfs4_renew_ops = {
.rpc_release = nfs4_renew_release,
};
-int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred)
+static int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred, unsigned renew_flags)
{
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW],
@@ -3395,9 +3380,11 @@ int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred)
};
struct nfs4_renewdata *data;
+ if (renew_flags == 0)
+ return 0;
if (!atomic_inc_not_zero(&clp->cl_count))
return -EIO;
- data = kmalloc(sizeof(*data), GFP_KERNEL);
+ data = kmalloc(sizeof(*data), GFP_NOFS);
if (data == NULL)
return -ENOMEM;
data->client = clp;
@@ -3406,7 +3393,7 @@ int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred)
&nfs4_renew_ops, data);
}
-int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred)
+static int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred)
{
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW],
@@ -3851,7 +3838,7 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
default:
if (nfs4_async_handle_error(task, data->res.server, NULL) ==
-EAGAIN) {
- nfs_restart_rpc(task, data->res.server->nfs_client);
+ rpc_restart_call_prepare(task);
return;
}
}
@@ -4105,8 +4092,7 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
break;
default:
if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN)
- nfs_restart_rpc(task,
- calldata->server->nfs_client);
+ rpc_restart_call_prepare(task);
}
}
@@ -4939,7 +4925,7 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata)
task->tk_status = 0;
/* fall through */
case -NFS4ERR_RETRY_UNCACHED_REP:
- nfs_restart_rpc(task, data->clp);
+ rpc_restart_call_prepare(task);
return;
}
dprintk("<-- %s\n", __func__);
@@ -5504,11 +5490,13 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_
return rpc_run_task(&task_setup_data);
}
-static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cred)
+static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cred, unsigned renew_flags)
{
struct rpc_task *task;
int ret = 0;
+ if ((renew_flags & NFS4_RENEW_TIMEOUT) == 0)
+ return 0;
task = _nfs41_proc_sequence(clp, cred);
if (IS_ERR(task))
ret = PTR_ERR(task);
@@ -5778,7 +5766,7 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
server = NFS_SERVER(lrp->args.inode);
if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) {
- nfs_restart_rpc(task, lrp->clp);
+ rpc_restart_call_prepare(task);
return;
}
spin_lock(&lo->plh_inode->i_lock);
@@ -5949,7 +5937,7 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata)
}
if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) {
- nfs_restart_rpc(task, server->nfs_client);
+ rpc_restart_call_prepare(task);
return;
}
@@ -6262,7 +6250,6 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
.getroot = nfs4_proc_get_root,
.getattr = nfs4_proc_getattr,
.setattr = nfs4_proc_setattr,
- .lookupfh = nfs4_proc_lookupfh,
.lookup = nfs4_proc_lookup,
.access = nfs4_proc_access,
.readlink = nfs4_proc_readlink,
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c
index df8e7f3ca56d..dc484c0eae7f 100644
--- a/fs/nfs/nfs4renewd.c
+++ b/fs/nfs/nfs4renewd.c
@@ -60,6 +60,7 @@ nfs4_renew_state(struct work_struct *work)
struct rpc_cred *cred;
long lease;
unsigned long last, now;
+ unsigned renew_flags = 0;
ops = clp->cl_mvops->state_renewal_ops;
dprintk("%s: start\n", __func__);
@@ -72,18 +73,23 @@ nfs4_renew_state(struct work_struct *work)
last = clp->cl_last_renewal;
now = jiffies;
/* Are we close to a lease timeout? */
- if (time_after(now, last + lease/3)) {
+ if (time_after(now, last + lease/3))
+ renew_flags |= NFS4_RENEW_TIMEOUT;
+ if (nfs_delegations_present(clp))
+ renew_flags |= NFS4_RENEW_DELEGATION_CB;
+
+ if (renew_flags != 0) {
cred = ops->get_state_renewal_cred_locked(clp);
spin_unlock(&clp->cl_lock);
if (cred == NULL) {
- if (!nfs_delegations_present(clp)) {
+ if (!(renew_flags & NFS4_RENEW_DELEGATION_CB)) {
set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
goto out;
}
nfs_expire_all_delegations(clp);
} else {
/* Queue an asynchronous RENEW. */
- ops->sched_state_renewal(clp, cred);
+ ops->sched_state_renewal(clp, cred, renew_flags);
put_rpccred(cred);
goto out_exp;
}
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 72ab97ef3d61..39914be40b03 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -1038,6 +1038,12 @@ void nfs4_schedule_lease_recovery(struct nfs_client *clp)
nfs4_schedule_state_manager(clp);
}
+void nfs4_schedule_path_down_recovery(struct nfs_client *clp)
+{
+ nfs_handle_cb_pathdown(clp);
+ nfs4_schedule_state_manager(clp);
+}
+
static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state)
{
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index e550e8836c37..ee73d9a4f700 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -1168,23 +1168,17 @@ EXPORT_SYMBOL_GPL(pnfs_generic_pg_test);
/*
* Called by non rpc-based layout drivers
*/
-int
-pnfs_ld_write_done(struct nfs_write_data *data)
+void pnfs_ld_write_done(struct nfs_write_data *data)
{
- int status;
-
- if (!data->pnfs_error) {
+ if (likely(!data->pnfs_error)) {
pnfs_set_layoutcommit(data);
data->mds_ops->rpc_call_done(&data->task, data);
- data->mds_ops->rpc_release(data);
- return 0;
+ } else {
+ put_lseg(data->lseg);
+ data->lseg = NULL;
+ dprintk("pnfs write error = %d\n", data->pnfs_error);
}
-
- dprintk("%s: pnfs_error=%d, retry via MDS\n", __func__,
- data->pnfs_error);
- status = nfs_initiate_write(data, NFS_CLIENT(data->inode),
- data->mds_ops, NFS_FILE_SYNC);
- return status ? : -EAGAIN;
+ data->mds_ops->rpc_release(data);
}
EXPORT_SYMBOL_GPL(pnfs_ld_write_done);
@@ -1268,23 +1262,17 @@ EXPORT_SYMBOL_GPL(pnfs_generic_pg_writepages);
/*
* Called by non rpc-based layout drivers
*/
-int
-pnfs_ld_read_done(struct nfs_read_data *data)
+void pnfs_ld_read_done(struct nfs_read_data *data)
{
- int status;
-
- if (!data->pnfs_error) {
+ if (likely(!data->pnfs_error)) {
__nfs4_read_done_cb(data);
data->mds_ops->rpc_call_done(&data->task, data);
- data->mds_ops->rpc_release(data);
- return 0;
+ } else {
+ put_lseg(data->lseg);
+ data->lseg = NULL;
+ dprintk("pnfs write error = %d\n", data->pnfs_error);
}
-
- dprintk("%s: pnfs_error=%d, retry via MDS\n", __func__,
- data->pnfs_error);
- status = nfs_initiate_read(data, NFS_CLIENT(data->inode),
- data->mds_ops);
- return status ? : -EAGAIN;
+ data->mds_ops->rpc_release(data);
}
EXPORT_SYMBOL_GPL(pnfs_ld_read_done);
@@ -1381,6 +1369,18 @@ static void pnfs_list_write_lseg(struct inode *inode, struct list_head *listp)
}
}
+void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg)
+{
+ if (lseg->pls_range.iomode == IOMODE_RW) {
+ dprintk("%s Setting layout IOMODE_RW fail bit\n", __func__);
+ set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
+ } else {
+ dprintk("%s Setting layout IOMODE_READ fail bit\n", __func__);
+ set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
+ }
+}
+EXPORT_SYMBOL_GPL(pnfs_set_lo_fail);
+
void
pnfs_set_layoutcommit(struct nfs_write_data *wdata)
{
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index 01cbfd54f3cb..1509530cb111 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -178,6 +178,7 @@ int pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc);
void pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *, struct nfs_page *);
int pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc);
bool pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, struct nfs_page *req);
+void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg);
int pnfs_layout_process(struct nfs4_layoutget *lgp);
void pnfs_free_lseg_list(struct list_head *tmp_list);
void pnfs_destroy_layout(struct nfs_inode *);
@@ -200,8 +201,8 @@ void pnfs_set_layoutcommit(struct nfs_write_data *wdata);
void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data);
int pnfs_layoutcommit_inode(struct inode *inode, bool sync);
int _pnfs_return_layout(struct inode *);
-int pnfs_ld_write_done(struct nfs_write_data *);
-int pnfs_ld_read_done(struct nfs_read_data *);
+void pnfs_ld_write_done(struct nfs_write_data *);
+void pnfs_ld_read_done(struct nfs_read_data *);
struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino,
struct nfs_open_context *ctx,
loff_t pos,
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 2171c043ab08..8b48ec63f722 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -35,16 +35,13 @@ static const struct rpc_call_ops nfs_read_partial_ops;
static const struct rpc_call_ops nfs_read_full_ops;
static struct kmem_cache *nfs_rdata_cachep;
-static mempool_t *nfs_rdata_mempool;
-
-#define MIN_POOL_READ (32)
struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount)
{
- struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, GFP_KERNEL);
+ struct nfs_read_data *p;
+ p = kmem_cache_zalloc(nfs_rdata_cachep, GFP_KERNEL);
if (p) {
- memset(p, 0, sizeof(*p));
INIT_LIST_HEAD(&p->pages);
p->npages = pagecount;
if (pagecount <= ARRAY_SIZE(p->page_array))
@@ -52,7 +49,7 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount)
else {
p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_KERNEL);
if (!p->pagevec) {
- mempool_free(p, nfs_rdata_mempool);
+ kmem_cache_free(nfs_rdata_cachep, p);
p = NULL;
}
}
@@ -64,7 +61,7 @@ void nfs_readdata_free(struct nfs_read_data *p)
{
if (p && (p->pagevec != &p->page_array[0]))
kfree(p->pagevec);
- mempool_free(p, nfs_rdata_mempool);
+ kmem_cache_free(nfs_rdata_cachep, p);
}
void nfs_readdata_release(struct nfs_read_data *rdata)
@@ -276,7 +273,6 @@ nfs_async_read_error(struct list_head *head)
while (!list_empty(head)) {
req = nfs_list_entry(head->next);
nfs_list_remove_request(req);
- SetPageError(req->wb_page);
nfs_readpage_release(req);
}
}
@@ -322,7 +318,6 @@ static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc, struct list_head
offset += len;
} while(nbytes != 0);
atomic_set(&req->wb_complete, requests);
- ClearPageError(page);
desc->pg_rpc_callops = &nfs_read_partial_ops;
return ret;
out_bad:
@@ -331,7 +326,6 @@ out_bad:
list_del(&data->list);
nfs_readdata_free(data);
}
- SetPageError(page);
nfs_readpage_release(req);
return -ENOMEM;
}
@@ -357,7 +351,6 @@ static int nfs_pagein_one(struct nfs_pageio_descriptor *desc, struct list_head *
req = nfs_list_entry(head->next);
nfs_list_remove_request(req);
nfs_list_add_request(req, &data->pages);
- ClearPageError(req->wb_page);
*pages++ = req->wb_page;
}
req = nfs_list_entry(data->pages.next);
@@ -435,7 +428,7 @@ static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data
argp->offset += resp->count;
argp->pgbase += resp->count;
argp->count -= resp->count;
- nfs_restart_rpc(task, NFS_SERVER(data->inode)->nfs_client);
+ rpc_restart_call_prepare(task);
}
/*
@@ -462,10 +455,10 @@ static void nfs_readpage_release_partial(void *calldata)
int status = data->task.tk_status;
if (status < 0)
- SetPageError(page);
+ set_bit(PG_PARTIAL_READ_FAILED, &req->wb_flags);
if (atomic_dec_and_test(&req->wb_complete)) {
- if (!PageError(page))
+ if (!test_bit(PG_PARTIAL_READ_FAILED, &req->wb_flags))
SetPageUptodate(page);
nfs_readpage_release(req);
}
@@ -541,13 +534,23 @@ static void nfs_readpage_result_full(struct rpc_task *task, void *calldata)
static void nfs_readpage_release_full(void *calldata)
{
struct nfs_read_data *data = calldata;
+ struct nfs_pageio_descriptor pgio;
+ if (data->pnfs_error) {
+ nfs_pageio_init_read_mds(&pgio, data->inode);
+ pgio.pg_recoalesce = 1;
+ }
while (!list_empty(&data->pages)) {
struct nfs_page *req = nfs_list_entry(data->pages.next);
nfs_list_remove_request(req);
- nfs_readpage_release(req);
+ if (!data->pnfs_error)
+ nfs_readpage_release(req);
+ else
+ nfs_pageio_add_request(&pgio, req);
}
+ if (data->pnfs_error)
+ nfs_pageio_complete(&pgio);
nfs_readdata_release(calldata);
}
@@ -648,7 +651,6 @@ readpage_async_filler(void *data, struct page *page)
return 0;
out_error:
error = PTR_ERR(new);
- SetPageError(page);
out_unlock:
unlock_page(page);
return error;
@@ -711,16 +713,10 @@ int __init nfs_init_readpagecache(void)
if (nfs_rdata_cachep == NULL)
return -ENOMEM;
- nfs_rdata_mempool = mempool_create_slab_pool(MIN_POOL_READ,
- nfs_rdata_cachep);
- if (nfs_rdata_mempool == NULL)
- return -ENOMEM;
-
return 0;
}
void nfs_destroy_readpagecache(void)
{
- mempool_destroy(nfs_rdata_mempool);
kmem_cache_destroy(nfs_rdata_cachep);
}
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index b961ceac66b4..480b3b6bf71e 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -733,18 +733,22 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
return 0;
}
+
+#ifdef CONFIG_NFS_V4
#ifdef CONFIG_NFS_V4_1
-void show_sessions(struct seq_file *m, struct nfs_server *server)
+static void show_sessions(struct seq_file *m, struct nfs_server *server)
{
if (nfs4_has_session(server->nfs_client))
seq_printf(m, ",sessions");
}
#else
-void show_sessions(struct seq_file *m, struct nfs_server *server) {}
+static void show_sessions(struct seq_file *m, struct nfs_server *server) {}
+#endif
#endif
+#ifdef CONFIG_NFS_V4
#ifdef CONFIG_NFS_V4_1
-void show_pnfs(struct seq_file *m, struct nfs_server *server)
+static void show_pnfs(struct seq_file *m, struct nfs_server *server)
{
seq_printf(m, ",pnfs=");
if (server->pnfs_curr_ld)
@@ -752,9 +756,10 @@ void show_pnfs(struct seq_file *m, struct nfs_server *server)
else
seq_printf(m, "not configured");
}
-#else /* CONFIG_NFS_V4_1 */
-void show_pnfs(struct seq_file *m, struct nfs_server *server) {}
-#endif /* CONFIG_NFS_V4_1 */
+#else
+static void show_pnfs(struct seq_file *m, struct nfs_server *server) {}
+#endif
+#endif
static int nfs_show_devname(struct seq_file *m, struct vfsmount *mnt)
{
@@ -2035,9 +2040,6 @@ static inline void nfs_initialise_sb(struct super_block *sb)
sb->s_blocksize = nfs_block_bits(server->wsize,
&sb->s_blocksize_bits);
- if (server->flags & NFS_MOUNT_NOAC)
- sb->s_flags |= MS_SYNCHRONOUS;
-
sb->s_bdi = &server->backing_dev_info;
nfs_super_set_maxbytes(sb, server->maxfilesize);
@@ -2249,6 +2251,10 @@ static struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
if (server->flags & NFS_MOUNT_UNSHARED)
compare_super = NULL;
+ /* -o noac implies -o sync */
+ if (server->flags & NFS_MOUNT_NOAC)
+ sb_mntdata.mntflags |= MS_SYNCHRONOUS;
+
/* Get a superblock - note that we may end up sharing one that already exists */
s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata);
if (IS_ERR(s)) {
@@ -2361,6 +2367,10 @@ nfs_xdev_mount(struct file_system_type *fs_type, int flags,
if (server->flags & NFS_MOUNT_UNSHARED)
compare_super = NULL;
+ /* -o noac implies -o sync */
+ if (server->flags & NFS_MOUNT_NOAC)
+ sb_mntdata.mntflags |= MS_SYNCHRONOUS;
+
/* Get a superblock - note that we may end up sharing one that already exists */
s = sget(&nfs_fs_type, compare_super, nfs_set_super, &sb_mntdata);
if (IS_ERR(s)) {
@@ -2628,6 +2638,10 @@ nfs4_remote_mount(struct file_system_type *fs_type, int flags,
if (server->flags & NFS4_MOUNT_UNSHARED)
compare_super = NULL;
+ /* -o noac implies -o sync */
+ if (server->flags & NFS_MOUNT_NOAC)
+ sb_mntdata.mntflags |= MS_SYNCHRONOUS;
+
/* Get a superblock - note that we may end up sharing one that already exists */
s = sget(&nfs4_fs_type, compare_super, nfs_set_super, &sb_mntdata);
if (IS_ERR(s)) {
@@ -2789,7 +2803,7 @@ static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt,
goto out_put_mnt_ns;
ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt,
- export_path, LOOKUP_FOLLOW, &path);
+ export_path, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path);
nfs_referral_loop_unprotect();
put_mnt_ns(ns_private);
@@ -2916,6 +2930,10 @@ nfs4_xdev_mount(struct file_system_type *fs_type, int flags,
if (server->flags & NFS4_MOUNT_UNSHARED)
compare_super = NULL;
+ /* -o noac implies -o sync */
+ if (server->flags & NFS_MOUNT_NOAC)
+ sb_mntdata.mntflags |= MS_SYNCHRONOUS;
+
/* Get a superblock - note that we may end up sharing one that already exists */
s = sget(&nfs4_fs_type, compare_super, nfs_set_super, &sb_mntdata);
if (IS_ERR(s)) {
@@ -3003,6 +3021,10 @@ nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags,
if (server->flags & NFS4_MOUNT_UNSHARED)
compare_super = NULL;
+ /* -o noac implies -o sync */
+ if (server->flags & NFS_MOUNT_NOAC)
+ sb_mntdata.mntflags |= MS_SYNCHRONOUS;
+
/* Get a superblock - note that we may end up sharing one that already exists */
s = sget(&nfs4_fs_type, compare_super, nfs_set_super, &sb_mntdata);
if (IS_ERR(s)) {
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c
index b2fbbde58e44..4f9319a2e567 100644
--- a/fs/nfs/unlink.c
+++ b/fs/nfs/unlink.c
@@ -87,7 +87,7 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
struct inode *dir = data->dir;
if (!NFS_PROTO(dir)->unlink_done(task, dir))
- nfs_restart_rpc(task, NFS_SERVER(dir)->nfs_client);
+ rpc_restart_call_prepare(task);
}
/**
@@ -369,7 +369,7 @@ static void nfs_async_rename_done(struct rpc_task *task, void *calldata)
struct dentry *new_dentry = data->new_dentry;
if (!NFS_PROTO(old_dir)->rename_done(task, old_dir, new_dir)) {
- nfs_restart_rpc(task, NFS_SERVER(old_dir)->nfs_client);
+ rpc_restart_call_prepare(task);
return;
}
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index b39b37f80913..2219c88d96b2 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -390,7 +390,7 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req);
BUG_ON(error);
if (!nfsi->npages && nfs_have_delegation(inode, FMODE_WRITE))
- nfsi->change_attr++;
+ inode->i_version++;
set_bit(PG_MAPPED, &req->wb_flags);
SetPagePrivate(req->wb_page);
set_page_private(req->wb_page, (unsigned long)req);
@@ -428,7 +428,6 @@ static void
nfs_mark_request_dirty(struct nfs_page *req)
{
__set_page_dirty_nobuffers(req->wb_page);
- __mark_inode_dirty(req->wb_page->mapping->host, I_DIRTY_DATASYNC);
}
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
@@ -762,6 +761,8 @@ int nfs_updatepage(struct file *file, struct page *page,
status = nfs_writepage_setup(ctx, page, offset, count);
if (status < 0)
nfs_set_pageerror(page);
+ else
+ __set_page_dirty_nobuffers(page);
dprintk("NFS: nfs_updatepage returns %d (isize %lld)\n",
status, (long long)i_size_read(inode));
@@ -958,7 +959,7 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc, struct list_head
if (!data)
goto out_bad;
data->pagevec[0] = page;
- nfs_write_rpcsetup(req, data, wsize, offset, desc->pg_ioflags);
+ nfs_write_rpcsetup(req, data, len, offset, desc->pg_ioflags);
list_add(&data->list, res);
requests++;
nbytes -= len;
@@ -1010,7 +1011,6 @@ static int nfs_flush_one(struct nfs_pageio_descriptor *desc, struct list_head *r
req = nfs_list_entry(head->next);
nfs_list_remove_request(req);
nfs_list_add_request(req, &data->pages);
- ClearPageError(req->wb_page);
*pages++ = req->wb_page;
}
req = nfs_list_entry(data->pages.next);
@@ -1165,7 +1165,13 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata)
static void nfs_writeback_release_full(void *calldata)
{
struct nfs_write_data *data = calldata;
- int status = data->task.tk_status;
+ int ret, status = data->task.tk_status;
+ struct nfs_pageio_descriptor pgio;
+
+ if (data->pnfs_error) {
+ nfs_pageio_init_write_mds(&pgio, data->inode, FLUSH_STABLE);
+ pgio.pg_recoalesce = 1;
+ }
/* Update attributes as result of writeback. */
while (!list_empty(&data->pages)) {
@@ -1181,6 +1187,11 @@ static void nfs_writeback_release_full(void *calldata)
req->wb_bytes,
(long long)req_offset(req));
+ if (data->pnfs_error) {
+ dprintk(", pnfs error = %d\n", data->pnfs_error);
+ goto next;
+ }
+
if (status < 0) {
nfs_set_pageerror(page);
nfs_context_set_write_error(req->wb_context, status);
@@ -1200,7 +1211,19 @@ remove_request:
next:
nfs_clear_page_tag_locked(req);
nfs_end_page_writeback(page);
+ if (data->pnfs_error) {
+ lock_page(page);
+ nfs_pageio_cond_complete(&pgio, page->index);
+ ret = nfs_page_async_flush(&pgio, page, 0);
+ if (ret) {
+ nfs_set_pageerror(page);
+ dprintk("rewrite to MDS error = %d\n", ret);
+ }
+ unlock_page(page);
+ }
}
+ if (data->pnfs_error)
+ nfs_pageio_complete(&pgio);
nfs_writedata_release(calldata);
}
@@ -1281,7 +1304,7 @@ void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
*/
argp->stable = NFS_FILE_SYNC;
}
- nfs_restart_rpc(task, server->nfs_client);
+ rpc_restart_call_prepare(task);
return;
}
if (time_before(complain, jiffies)) {
@@ -1553,6 +1576,10 @@ static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_contr
int flags = FLUSH_SYNC;
int ret = 0;
+ /* no commits means nothing needs to be done */
+ if (!nfsi->ncommit)
+ return ret;
+
if (wbc->sync_mode == WB_SYNC_NONE) {
/* Don't commit yet if this is a non-blocking flush and there
* are a lot of outstanding writes for this mapping.
@@ -1686,34 +1713,20 @@ out_error:
int nfs_migrate_page(struct address_space *mapping, struct page *newpage,
struct page *page)
{
- struct nfs_page *req;
- int ret;
+ /*
+ * If PagePrivate is set, then the page is currently associated with
+ * an in-progress read or write request. Don't try to migrate it.
+ *
+ * FIXME: we could do this in principle, but we'll need a way to ensure
+ * that we can safely release the inode reference while holding
+ * the page lock.
+ */
+ if (PagePrivate(page))
+ return -EBUSY;
nfs_fscache_release_page(page, GFP_KERNEL);
- req = nfs_find_and_lock_request(page, false);
- ret = PTR_ERR(req);
- if (IS_ERR(req))
- goto out;
-
- ret = migrate_page(mapping, newpage, page);
- if (!req)
- goto out;
- if (ret)
- goto out_unlock;
- page_cache_get(newpage);
- spin_lock(&mapping->host->i_lock);
- req->wb_page = newpage;
- SetPagePrivate(newpage);
- set_page_private(newpage, (unsigned long)req);
- ClearPagePrivate(page);
- set_page_private(page, 0);
- spin_unlock(&mapping->host->i_lock);
- page_cache_release(page);
-out_unlock:
- nfs_clear_page_tag_locked(req);
-out:
- return ret;
+ return migrate_page(mapping, newpage, page);
}
#endif
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index f4cc1e2bfc54..62f3b9074e84 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -16,7 +16,6 @@
#include <linux/module.h>
#include <linux/exportfs.h>
-#include <linux/nfsd/syscall.h>
#include <net/ipv6.h>
#include "nfsd.h"
@@ -318,7 +317,6 @@ static void svc_export_put(struct kref *ref)
struct svc_export *exp = container_of(ref, struct svc_export, h.ref);
path_put(&exp->ex_path);
auth_domain_put(exp->ex_client);
- kfree(exp->ex_pathname);
nfsd4_fslocs_free(&exp->ex_fslocs);
kfree(exp);
}
@@ -528,11 +526,6 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
exp.ex_client = dom;
- err = -ENOMEM;
- exp.ex_pathname = kstrdup(buf, GFP_KERNEL);
- if (!exp.ex_pathname)
- goto out2;
-
/* expiry */
err = -EINVAL;
exp.h.expiry_time = get_expiry(&mesg);
@@ -613,8 +606,6 @@ out4:
nfsd4_fslocs_free(&exp.ex_fslocs);
kfree(exp.ex_uuid);
out3:
- kfree(exp.ex_pathname);
-out2:
path_put(&exp.ex_path);
out1:
auth_domain_put(dom);
@@ -678,7 +669,6 @@ static void svc_export_init(struct cache_head *cnew, struct cache_head *citem)
new->ex_client = item->ex_client;
new->ex_path.dentry = dget(item->ex_path.dentry);
new->ex_path.mnt = mntget(item->ex_path.mnt);
- new->ex_pathname = NULL;
new->ex_fslocs.locations = NULL;
new->ex_fslocs.locations_count = 0;
new->ex_fslocs.migrated = 0;
@@ -696,8 +686,6 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem)
new->ex_fsid = item->ex_fsid;
new->ex_uuid = item->ex_uuid;
item->ex_uuid = NULL;
- new->ex_pathname = item->ex_pathname;
- item->ex_pathname = NULL;
new->ex_fslocs.locations = item->ex_fslocs.locations;
item->ex_fslocs.locations = NULL;
new->ex_fslocs.locations_count = item->ex_fslocs.locations_count;
@@ -1010,7 +998,7 @@ rqst_exp_parent(struct svc_rqst *rqstp, struct path *path)
return exp;
}
-static struct svc_export *find_fsidzero_export(struct svc_rqst *rqstp)
+struct svc_export *rqst_find_fsidzero_export(struct svc_rqst *rqstp)
{
u32 fsidv[2];
@@ -1030,7 +1018,7 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
struct svc_export *exp;
__be32 rv;
- exp = find_fsidzero_export(rqstp);
+ exp = rqst_find_fsidzero_export(rqstp);
if (IS_ERR(exp))
return nfserrno(PTR_ERR(exp));
rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL);
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 02eb4edf0ece..7748d6a18d97 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -39,6 +39,8 @@
#define NFSDDBG_FACILITY NFSDDBG_PROC
+static void nfsd4_mark_cb_fault(struct nfs4_client *, int reason);
+
#define NFSPROC4_CB_NULL 0
#define NFSPROC4_CB_COMPOUND 1
@@ -351,7 +353,7 @@ static void encode_cb_recall4args(struct xdr_stream *xdr,
__be32 *p;
encode_nfs_cb_opnum4(xdr, OP_CB_RECALL);
- encode_stateid4(xdr, &dp->dl_stateid);
+ encode_stateid4(xdr, &dp->dl_stid.sc_stateid);
p = xdr_reserve_space(xdr, 4);
*p++ = xdr_zero; /* truncate */
@@ -460,6 +462,8 @@ static int decode_cb_sequence4resok(struct xdr_stream *xdr,
*/
status = 0;
out:
+ if (status)
+ nfsd4_mark_cb_fault(cb->cb_clp, status);
return status;
out_overflow:
print_overflow_msg(__func__, xdr);
@@ -686,6 +690,12 @@ static void nfsd4_mark_cb_down(struct nfs4_client *clp, int reason)
warn_no_callback_path(clp, reason);
}
+static void nfsd4_mark_cb_fault(struct nfs4_client *clp, int reason)
+{
+ clp->cl_cb_state = NFSD4_CB_FAULT;
+ warn_no_callback_path(clp, reason);
+}
+
static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata)
{
struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null);
@@ -787,7 +797,7 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
{
struct nfsd4_callback *cb = calldata;
struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
- struct nfs4_client *clp = dp->dl_client;
+ struct nfs4_client *clp = dp->dl_stid.sc_client;
u32 minorversion = clp->cl_minorversion;
cb->cb_minorversion = minorversion;
@@ -809,7 +819,7 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
{
struct nfsd4_callback *cb = calldata;
struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
- struct nfs4_client *clp = dp->dl_client;
+ struct nfs4_client *clp = dp->dl_stid.sc_client;
dprintk("%s: minorversion=%d\n", __func__,
clp->cl_minorversion);
@@ -832,7 +842,7 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
{
struct nfsd4_callback *cb = calldata;
struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
- struct nfs4_client *clp = dp->dl_client;
+ struct nfs4_client *clp = dp->dl_stid.sc_client;
struct rpc_clnt *current_rpc_client = clp->cl_cb_client;
nfsd4_cb_done(task, calldata);
@@ -1006,7 +1016,7 @@ void nfsd4_do_callback_rpc(struct work_struct *w)
void nfsd4_cb_recall(struct nfs4_delegation *dp)
{
struct nfsd4_callback *cb = &dp->dl_recall;
- struct nfs4_client *clp = dp->dl_client;
+ struct nfs4_client *clp = dp->dl_stid.sc_client;
dp->dl_retries = 1;
cb->cb_op = dp;
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index e80777666618..fa383361bc61 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -35,6 +35,7 @@
#include <linux/file.h>
#include <linux/slab.h>
+#include "idmap.h"
#include "cache.h"
#include "xdr4.h"
#include "vfs.h"
@@ -156,6 +157,8 @@ do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs
!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
return nfserr_inval;
+ accmode |= NFSD_MAY_READ_IF_EXEC;
+
if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
accmode |= NFSD_MAY_READ;
if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
@@ -168,12 +171,29 @@ do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs
return status;
}
+static __be32 nfsd_check_obj_isreg(struct svc_fh *fh)
+{
+ umode_t mode = fh->fh_dentry->d_inode->i_mode;
+
+ if (S_ISREG(mode))
+ return nfs_ok;
+ if (S_ISDIR(mode))
+ return nfserr_isdir;
+ /*
+ * Using err_symlink as our catch-all case may look odd; but
+ * there's no other obvious error for this case in 4.0, and we
+ * happen to know that it will cause the linux v4 client to do
+ * the right thing on attempts to open something other than a
+ * regular file.
+ */
+ return nfserr_symlink;
+}
+
static __be32
do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
{
struct svc_fh resfh;
__be32 status;
- int created = 0;
fh_init(&resfh, NFS4_FHSIZE);
open->op_truncate = 0;
@@ -202,7 +222,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
open->op_fname.len, &open->op_iattr,
&resfh, open->op_createmode,
(u32 *)open->op_verf.data,
- &open->op_truncate, &created);
+ &open->op_truncate, &open->op_created);
/*
* Following rfc 3530 14.2.16, use the returned bitmask
@@ -216,6 +236,9 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
status = nfsd_lookup(rqstp, current_fh,
open->op_fname.data, open->op_fname.len, &resfh);
fh_unlock(current_fh);
+ if (status)
+ goto out;
+ status = nfsd_check_obj_isreg(&resfh);
}
if (status)
goto out;
@@ -227,9 +250,9 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
fh_dup2(current_fh, &resfh);
/* set reply cache */
- fh_copy_shallow(&open->op_stateowner->so_replay.rp_openfh,
+ fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh,
&resfh.fh_handle);
- if (!created)
+ if (!open->op_created)
status = do_open_permission(rqstp, current_fh, open,
NFSD_MAY_NOP);
@@ -254,7 +277,7 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_
memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info));
/* set replay cache */
- fh_copy_shallow(&open->op_stateowner->so_replay.rp_openfh,
+ fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh,
&current_fh->fh_handle);
open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) &&
@@ -283,14 +306,18 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
__be32 status;
struct nfsd4_compoundres *resp;
- dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n",
+ dprintk("NFSD: nfsd4_open filename %.*s op_openowner %p\n",
(int)open->op_fname.len, open->op_fname.data,
- open->op_stateowner);
+ open->op_openowner);
/* This check required by spec. */
if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
return nfserr_inval;
+ /* We don't yet support WANT bits: */
+ open->op_share_access &= NFS4_SHARE_ACCESS_MASK;
+
+ open->op_created = 0;
/*
* RFC5661 18.51.3
* Before RECLAIM_COMPLETE done, server should deny new lock
@@ -309,7 +336,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
resp = rqstp->rq_resp;
status = nfsd4_process_open1(&resp->cstate, open);
if (status == nfserr_replay_me) {
- struct nfs4_replay *rp = &open->op_stateowner->so_replay;
+ struct nfs4_replay *rp = &open->op_openowner->oo_owner.so_replay;
fh_put(&cstate->current_fh);
fh_copy_shallow(&cstate->current_fh.fh_handle,
&rp->rp_openfh);
@@ -339,32 +366,23 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
switch (open->op_claim_type) {
case NFS4_OPEN_CLAIM_DELEGATE_CUR:
case NFS4_OPEN_CLAIM_NULL:
- /*
- * (1) set CURRENT_FH to the file being opened,
- * creating it if necessary, (2) set open->op_cinfo,
- * (3) set open->op_truncate if the file is to be
- * truncated after opening, (4) do permission checking.
- */
status = do_open_lookup(rqstp, &cstate->current_fh,
open);
if (status)
goto out;
break;
case NFS4_OPEN_CLAIM_PREVIOUS:
- open->op_stateowner->so_confirmed = 1;
- /*
- * The CURRENT_FH is already set to the file being
- * opened. (1) set open->op_cinfo, (2) set
- * open->op_truncate if the file is to be truncated
- * after opening, (3) do permission checking.
- */
+ open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
+ case NFS4_OPEN_CLAIM_FH:
+ case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
status = do_open_fhandle(rqstp, &cstate->current_fh,
open);
if (status)
goto out;
break;
+ case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
case NFS4_OPEN_CLAIM_DELEGATE_PREV:
- open->op_stateowner->so_confirmed = 1;
+ open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
dprintk("NFSD: unsupported OPEN claim type %d\n",
open->op_claim_type);
status = nfserr_notsupp;
@@ -381,12 +399,13 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
* set, (2) sets open->op_stateid, (3) sets open->op_delegation.
*/
status = nfsd4_process_open2(rqstp, &cstate->current_fh, open);
+ WARN_ON(status && open->op_created);
out:
- if (open->op_stateowner) {
- nfs4_get_stateowner(open->op_stateowner);
- cstate->replay_owner = open->op_stateowner;
- }
- nfs4_unlock_state();
+ nfsd4_cleanup_open_state(open, status);
+ if (open->op_openowner)
+ cstate->replay_owner = &open->op_openowner->oo_owner;
+ else
+ nfs4_unlock_state();
return status;
}
@@ -467,17 +486,12 @@ static __be32
nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_commit *commit)
{
- __be32 status;
-
u32 *p = (u32 *)commit->co_verf.data;
*p++ = nfssvc_boot.tv_sec;
*p++ = nfssvc_boot.tv_usec;
- status = nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset,
+ return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset,
commit->co_count);
- if (status == nfserr_symlink)
- status = nfserr_inval;
- return status;
}
static __be32
@@ -492,8 +506,6 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR,
NFSD_MAY_CREATE);
- if (status == nfserr_symlink)
- status = nfserr_notdir;
if (status)
return status;
@@ -691,7 +703,7 @@ nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
readdir->rd_bmval[1] &= nfsd_suppattrs1(cstate->minorversion);
readdir->rd_bmval[2] &= nfsd_suppattrs2(cstate->minorversion);
- if ((cookie > ~(u32)0) || (cookie == 1) || (cookie == 2) ||
+ if ((cookie == 1) || (cookie == 2) ||
(cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE)))
return nfserr_bad_cookie;
@@ -719,8 +731,6 @@ nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
return nfserr_grace;
status = nfsd_unlink(rqstp, &cstate->current_fh, 0,
remove->rm_name, remove->rm_namelen);
- if (status == nfserr_symlink)
- return nfserr_notdir;
if (!status) {
fh_unlock(&cstate->current_fh);
set_change_info(&remove->rm_cinfo, &cstate->current_fh);
@@ -751,8 +761,6 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
(S_ISDIR(cstate->save_fh.fh_dentry->d_inode->i_mode) &&
S_ISDIR(cstate->current_fh.fh_dentry->d_inode->i_mode)))
status = nfserr_exist;
- else if (status == nfserr_symlink)
- status = nfserr_notdir;
if (!status) {
set_change_info(&rename->rn_sinfo, &cstate->current_fh);
@@ -892,8 +900,6 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
write->wr_bytes_written = cnt;
- if (status == nfserr_symlink)
- status = nfserr_inval;
return status;
}
@@ -930,7 +936,7 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
count = 4 + (verify->ve_attrlen >> 2);
buf = kmalloc(count << 2, GFP_KERNEL);
if (!buf)
- return nfserr_resource;
+ return nfserr_jukebox;
status = nfsd4_encode_fattr(&cstate->current_fh,
cstate->current_fh.fh_export,
@@ -994,6 +1000,8 @@ static inline void nfsd4_increment_op_stats(u32 opnum)
typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *,
void *);
+typedef u32(*nfsd4op_rsize)(struct svc_rqst *, struct nfsd4_op *op);
+
enum nfsd4_op_flags {
ALLOWED_WITHOUT_FH = 1 << 0, /* No current filehandle required */
ALLOWED_ON_ABSENT_FS = 1 << 1, /* ops processed on absent fs */
@@ -1001,13 +1009,15 @@ enum nfsd4_op_flags {
/* For rfc 5661 section 2.6.3.1.1: */
OP_HANDLES_WRONGSEC = 1 << 3,
OP_IS_PUTFH_LIKE = 1 << 4,
-};
-
-struct nfsd4_operation {
- nfsd4op_func op_func;
- u32 op_flags;
- char *op_name;
/*
+ * These are the ops whose result size we estimate before
+ * encoding, to avoid performing an op then not being able to
+ * respond or cache a response. This includes writes and setattrs
+ * as well as the operations usually called "nonidempotent":
+ */
+ OP_MODIFIES_SOMETHING = 1 << 5,
+ /*
+ * Cache compounds containing these ops in the xid-based drc:
* We use the DRC for compounds containing non-idempotent
* operations, *except* those that are 4.1-specific (since
* sessions provide their own EOS), and except for stateful
@@ -1015,7 +1025,15 @@ struct nfsd4_operation {
* (since sequence numbers provide EOS for open, lock, etc in
* the v4.0 case).
*/
- bool op_cacheresult;
+ OP_CACHEME = 1 << 6,
+};
+
+struct nfsd4_operation {
+ nfsd4op_func op_func;
+ u32 op_flags;
+ char *op_name;
+ /* Try to get response size before operation */
+ nfsd4op_rsize op_rsize_bop;
};
static struct nfsd4_operation nfsd4_ops[];
@@ -1062,7 +1080,7 @@ static inline struct nfsd4_operation *OPDESC(struct nfsd4_op *op)
bool nfsd4_cache_this_op(struct nfsd4_op *op)
{
- return OPDESC(op)->op_cacheresult;
+ return OPDESC(op)->op_flags & OP_CACHEME;
}
static bool need_wrongsec_check(struct svc_rqst *rqstp)
@@ -1110,6 +1128,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
struct nfsd4_operation *opdesc;
struct nfsd4_compound_state *cstate = &resp->cstate;
int slack_bytes;
+ u32 plen = 0;
__be32 status;
resp->xbuf = &rqstp->rq_res;
@@ -1188,6 +1207,15 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
goto encode_op;
}
+ /* If op is non-idempotent */
+ if (opdesc->op_flags & OP_MODIFIES_SOMETHING) {
+ plen = opdesc->op_rsize_bop(rqstp, op);
+ op->status = nfsd4_check_resp_size(resp, plen);
+ }
+
+ if (op->status)
+ goto encode_op;
+
if (opdesc->op_func)
op->status = opdesc->op_func(rqstp, cstate, &op->u);
else
@@ -1217,7 +1245,7 @@ encode_op:
be32_to_cpu(status));
if (cstate->replay_owner) {
- nfs4_put_stateowner(cstate->replay_owner);
+ nfs4_unlock_state();
cstate->replay_owner = NULL;
}
/* XXX Ugh, we need to get rid of this kind of special case: */
@@ -1238,6 +1266,144 @@ out:
return status;
}
+#define op_encode_hdr_size (2)
+#define op_encode_stateid_maxsz (XDR_QUADLEN(NFS4_STATEID_SIZE))
+#define op_encode_verifier_maxsz (XDR_QUADLEN(NFS4_VERIFIER_SIZE))
+#define op_encode_change_info_maxsz (5)
+#define nfs4_fattr_bitmap_maxsz (4)
+
+#define op_encode_lockowner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ))
+#define op_encode_lock_denied_maxsz (8 + op_encode_lockowner_maxsz)
+
+#define nfs4_owner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ))
+
+#define op_encode_ace_maxsz (3 + nfs4_owner_maxsz)
+#define op_encode_delegation_maxsz (1 + op_encode_stateid_maxsz + 1 + \
+ op_encode_ace_maxsz)
+
+#define op_encode_channel_attrs_maxsz (6 + 1 + 1)
+
+static inline u32 nfsd4_only_status_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
+{
+ return (op_encode_hdr_size) * sizeof(__be32);
+}
+
+static inline u32 nfsd4_status_stateid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
+{
+ return (op_encode_hdr_size + op_encode_stateid_maxsz)* sizeof(__be32);
+}
+
+static inline u32 nfsd4_commit_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
+{
+ return (op_encode_hdr_size + op_encode_verifier_maxsz) * sizeof(__be32);
+}
+
+static inline u32 nfsd4_create_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
+{
+ return (op_encode_hdr_size + op_encode_change_info_maxsz
+ + nfs4_fattr_bitmap_maxsz) * sizeof(__be32);
+}
+
+static inline u32 nfsd4_link_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
+{
+ return (op_encode_hdr_size + op_encode_change_info_maxsz)
+ * sizeof(__be32);
+}
+
+static inline u32 nfsd4_lock_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
+{
+ return (op_encode_hdr_size + op_encode_lock_denied_maxsz)
+ * sizeof(__be32);
+}
+
+static inline u32 nfsd4_open_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
+{
+ return (op_encode_hdr_size + op_encode_stateid_maxsz
+ + op_encode_change_info_maxsz + 1
+ + nfs4_fattr_bitmap_maxsz
+ + op_encode_delegation_maxsz) * sizeof(__be32);
+}
+
+static inline u32 nfsd4_read_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
+{
+ u32 maxcount = 0, rlen = 0;
+
+ maxcount = svc_max_payload(rqstp);
+ rlen = op->u.read.rd_length;
+
+ if (rlen > maxcount)
+ rlen = maxcount;
+
+ return (op_encode_hdr_size + 2) * sizeof(__be32) + rlen;
+}
+
+static inline u32 nfsd4_readdir_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
+{
+ u32 rlen = op->u.readdir.rd_maxcount;
+
+ if (rlen > PAGE_SIZE)
+ rlen = PAGE_SIZE;
+
+ return (op_encode_hdr_size + op_encode_verifier_maxsz)
+ * sizeof(__be32) + rlen;
+}
+
+static inline u32 nfsd4_remove_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
+{
+ return (op_encode_hdr_size + op_encode_change_info_maxsz)
+ * sizeof(__be32);
+}
+
+static inline u32 nfsd4_rename_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
+{
+ return (op_encode_hdr_size + op_encode_change_info_maxsz
+ + op_encode_change_info_maxsz) * sizeof(__be32);
+}
+
+static inline u32 nfsd4_setattr_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
+{
+ return (op_encode_hdr_size + nfs4_fattr_bitmap_maxsz) * sizeof(__be32);
+}
+
+static inline u32 nfsd4_setclientid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
+{
+ return (op_encode_hdr_size + 2 + 1024) * sizeof(__be32);
+}
+
+static inline u32 nfsd4_write_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
+{
+ return (op_encode_hdr_size + op_encode_verifier_maxsz) * sizeof(__be32);
+}
+
+static inline u32 nfsd4_exchange_id_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
+{
+ return (op_encode_hdr_size + 2 + 1 + /* eir_clientid, eir_sequenceid */\
+ 1 + 1 + 0 + /* eir_flags, spr_how, SP4_NONE (for now) */\
+ 2 + /*eir_server_owner.so_minor_id */\
+ /* eir_server_owner.so_major_id<> */\
+ XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\
+ /* eir_server_scope<> */\
+ XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\
+ 1 + /* eir_server_impl_id array length */\
+ 0 /* ignored eir_server_impl_id contents */) * sizeof(__be32);
+}
+
+static inline u32 nfsd4_bind_conn_to_session_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
+{
+ return (op_encode_hdr_size + \
+ XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + /* bctsr_sessid */\
+ 2 /* bctsr_dir, use_conn_in_rdma_mode */) * sizeof(__be32);
+}
+
+static inline u32 nfsd4_create_session_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
+{
+ return (op_encode_hdr_size + \
+ XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + /* sessionid */\
+ 2 + /* csr_sequence, csr_flags */\
+ op_encode_channel_attrs_maxsz + \
+ op_encode_channel_attrs_maxsz) * sizeof(__be32);
+}
+
static struct nfsd4_operation nfsd4_ops[] = {
[OP_ACCESS] = {
.op_func = (nfsd4op_func)nfsd4_access,
@@ -1245,20 +1411,27 @@ static struct nfsd4_operation nfsd4_ops[] = {
},
[OP_CLOSE] = {
.op_func = (nfsd4op_func)nfsd4_close,
+ .op_flags = OP_MODIFIES_SOMETHING,
.op_name = "OP_CLOSE",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize,
},
[OP_COMMIT] = {
.op_func = (nfsd4op_func)nfsd4_commit,
+ .op_flags = OP_MODIFIES_SOMETHING,
.op_name = "OP_COMMIT",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_commit_rsize,
},
[OP_CREATE] = {
.op_func = (nfsd4op_func)nfsd4_create,
+ .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
.op_name = "OP_CREATE",
- .op_cacheresult = true,
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_create_rsize,
},
[OP_DELEGRETURN] = {
.op_func = (nfsd4op_func)nfsd4_delegreturn,
+ .op_flags = OP_MODIFIES_SOMETHING,
.op_name = "OP_DELEGRETURN",
+ .op_rsize_bop = nfsd4_only_status_rsize,
},
[OP_GETATTR] = {
.op_func = (nfsd4op_func)nfsd4_getattr,
@@ -1271,12 +1444,16 @@ static struct nfsd4_operation nfsd4_ops[] = {
},
[OP_LINK] = {
.op_func = (nfsd4op_func)nfsd4_link,
+ .op_flags = ALLOWED_ON_ABSENT_FS | OP_MODIFIES_SOMETHING
+ | OP_CACHEME,
.op_name = "OP_LINK",
- .op_cacheresult = true,
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_link_rsize,
},
[OP_LOCK] = {
.op_func = (nfsd4op_func)nfsd4_lock,
+ .op_flags = OP_MODIFIES_SOMETHING,
.op_name = "OP_LOCK",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_lock_rsize,
},
[OP_LOCKT] = {
.op_func = (nfsd4op_func)nfsd4_lockt,
@@ -1284,7 +1461,9 @@ static struct nfsd4_operation nfsd4_ops[] = {
},
[OP_LOCKU] = {
.op_func = (nfsd4op_func)nfsd4_locku,
+ .op_flags = OP_MODIFIES_SOMETHING,
.op_name = "OP_LOCKU",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize,
},
[OP_LOOKUP] = {
.op_func = (nfsd4op_func)nfsd4_lookup,
@@ -1302,42 +1481,54 @@ static struct nfsd4_operation nfsd4_ops[] = {
},
[OP_OPEN] = {
.op_func = (nfsd4op_func)nfsd4_open,
- .op_flags = OP_HANDLES_WRONGSEC,
+ .op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING,
.op_name = "OP_OPEN",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_open_rsize,
},
[OP_OPEN_CONFIRM] = {
.op_func = (nfsd4op_func)nfsd4_open_confirm,
+ .op_flags = OP_MODIFIES_SOMETHING,
.op_name = "OP_OPEN_CONFIRM",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize,
},
[OP_OPEN_DOWNGRADE] = {
.op_func = (nfsd4op_func)nfsd4_open_downgrade,
+ .op_flags = OP_MODIFIES_SOMETHING,
.op_name = "OP_OPEN_DOWNGRADE",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize,
},
[OP_PUTFH] = {
.op_func = (nfsd4op_func)nfsd4_putfh,
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
- | OP_IS_PUTFH_LIKE,
+ | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING,
.op_name = "OP_PUTFH",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
},
[OP_PUTPUBFH] = {
.op_func = (nfsd4op_func)nfsd4_putrootfh,
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
- | OP_IS_PUTFH_LIKE,
+ | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING,
.op_name = "OP_PUTPUBFH",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
},
[OP_PUTROOTFH] = {
.op_func = (nfsd4op_func)nfsd4_putrootfh,
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
- | OP_IS_PUTFH_LIKE,
+ | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING,
.op_name = "OP_PUTROOTFH",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
},
[OP_READ] = {
.op_func = (nfsd4op_func)nfsd4_read,
+ .op_flags = OP_MODIFIES_SOMETHING,
.op_name = "OP_READ",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_read_rsize,
},
[OP_READDIR] = {
.op_func = (nfsd4op_func)nfsd4_readdir,
+ .op_flags = OP_MODIFIES_SOMETHING,
.op_name = "OP_READDIR",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_readdir_rsize,
},
[OP_READLINK] = {
.op_func = (nfsd4op_func)nfsd4_readlink,
@@ -1345,29 +1536,36 @@ static struct nfsd4_operation nfsd4_ops[] = {
},
[OP_REMOVE] = {
.op_func = (nfsd4op_func)nfsd4_remove,
+ .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
.op_name = "OP_REMOVE",
- .op_cacheresult = true,
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_remove_rsize,
},
[OP_RENAME] = {
- .op_name = "OP_RENAME",
.op_func = (nfsd4op_func)nfsd4_rename,
- .op_cacheresult = true,
+ .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
+ .op_name = "OP_RENAME",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_rename_rsize,
},
[OP_RENEW] = {
.op_func = (nfsd4op_func)nfsd4_renew,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
+ .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
+ | OP_MODIFIES_SOMETHING,
.op_name = "OP_RENEW",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+
},
[OP_RESTOREFH] = {
.op_func = (nfsd4op_func)nfsd4_restorefh,
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
- | OP_IS_PUTFH_LIKE,
+ | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING,
.op_name = "OP_RESTOREFH",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
},
[OP_SAVEFH] = {
.op_func = (nfsd4op_func)nfsd4_savefh,
- .op_flags = OP_HANDLES_WRONGSEC,
+ .op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING,
.op_name = "OP_SAVEFH",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
},
[OP_SECINFO] = {
.op_func = (nfsd4op_func)nfsd4_secinfo,
@@ -1377,19 +1575,22 @@ static struct nfsd4_operation nfsd4_ops[] = {
[OP_SETATTR] = {
.op_func = (nfsd4op_func)nfsd4_setattr,
.op_name = "OP_SETATTR",
- .op_cacheresult = true,
+ .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_setattr_rsize,
},
[OP_SETCLIENTID] = {
.op_func = (nfsd4op_func)nfsd4_setclientid,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
+ .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
+ | OP_MODIFIES_SOMETHING | OP_CACHEME,
.op_name = "OP_SETCLIENTID",
- .op_cacheresult = true,
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_setclientid_rsize,
},
[OP_SETCLIENTID_CONFIRM] = {
.op_func = (nfsd4op_func)nfsd4_setclientid_confirm,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
+ .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
+ | OP_MODIFIES_SOMETHING | OP_CACHEME,
.op_name = "OP_SETCLIENTID_CONFIRM",
- .op_cacheresult = true,
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
},
[OP_VERIFY] = {
.op_func = (nfsd4op_func)nfsd4_verify,
@@ -1397,35 +1598,46 @@ static struct nfsd4_operation nfsd4_ops[] = {
},
[OP_WRITE] = {
.op_func = (nfsd4op_func)nfsd4_write,
+ .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
.op_name = "OP_WRITE",
- .op_cacheresult = true,
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_write_rsize,
},
[OP_RELEASE_LOCKOWNER] = {
.op_func = (nfsd4op_func)nfsd4_release_lockowner,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
+ .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
+ | OP_MODIFIES_SOMETHING,
.op_name = "OP_RELEASE_LOCKOWNER",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
},
/* NFSv4.1 operations */
[OP_EXCHANGE_ID] = {
.op_func = (nfsd4op_func)nfsd4_exchange_id,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
+ .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
+ | OP_MODIFIES_SOMETHING,
.op_name = "OP_EXCHANGE_ID",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_exchange_id_rsize,
},
[OP_BIND_CONN_TO_SESSION] = {
.op_func = (nfsd4op_func)nfsd4_bind_conn_to_session,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
+ .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
+ | OP_MODIFIES_SOMETHING,
.op_name = "OP_BIND_CONN_TO_SESSION",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_bind_conn_to_session_rsize,
},
[OP_CREATE_SESSION] = {
.op_func = (nfsd4op_func)nfsd4_create_session,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
+ .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
+ | OP_MODIFIES_SOMETHING,
.op_name = "OP_CREATE_SESSION",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_create_session_rsize,
},
[OP_DESTROY_SESSION] = {
.op_func = (nfsd4op_func)nfsd4_destroy_session,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
+ .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
+ | OP_MODIFIES_SOMETHING,
.op_name = "OP_DESTROY_SESSION",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
},
[OP_SEQUENCE] = {
.op_func = (nfsd4op_func)nfsd4_sequence,
@@ -1433,14 +1645,17 @@ static struct nfsd4_operation nfsd4_ops[] = {
.op_name = "OP_SEQUENCE",
},
[OP_DESTROY_CLIENTID] = {
- .op_func = NULL,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
+ .op_func = (nfsd4op_func)nfsd4_destroy_clientid,
+ .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
+ | OP_MODIFIES_SOMETHING,
.op_name = "OP_DESTROY_CLIENTID",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
},
[OP_RECLAIM_COMPLETE] = {
.op_func = (nfsd4op_func)nfsd4_reclaim_complete,
- .op_flags = ALLOWED_WITHOUT_FH,
+ .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING,
.op_name = "OP_RECLAIM_COMPLETE",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
},
[OP_SECINFO_NO_NAME] = {
.op_func = (nfsd4op_func)nfsd4_secinfo_no_name,
@@ -1454,8 +1669,9 @@ static struct nfsd4_operation nfsd4_ops[] = {
},
[OP_FREE_STATEID] = {
.op_func = (nfsd4op_func)nfsd4_free_stateid,
- .op_flags = ALLOWED_WITHOUT_FH,
+ .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING,
.op_name = "OP_FREE_STATEID",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
},
};
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 29d77f60585b..ed083b9a731b 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -45,6 +45,7 @@
/* Globals */
static struct file *rec_file;
+static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
static int
nfs4_save_creds(const struct cred **original_creds)
@@ -88,7 +89,7 @@ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
struct xdr_netobj cksum;
struct hash_desc desc;
struct scatterlist sg;
- __be32 status = nfserr_resource;
+ __be32 status = nfserr_jukebox;
dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n",
clname->len, clname->data);
@@ -129,6 +130,7 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
if (!rec_file || clp->cl_firststate)
return 0;
+ clp->cl_firststate = 1;
status = nfs4_save_creds(&original_cred);
if (status < 0)
return status;
@@ -143,10 +145,8 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
goto out_unlock;
}
status = -EEXIST;
- if (dentry->d_inode) {
- dprintk("NFSD: nfsd4_create_clid_dir: DIRECTORY EXISTS\n");
+ if (dentry->d_inode)
goto out_put;
- }
status = mnt_want_write(rec_file->f_path.mnt);
if (status)
goto out_put;
@@ -156,12 +156,14 @@ out_put:
dput(dentry);
out_unlock:
mutex_unlock(&dir->d_inode->i_mutex);
- if (status == 0) {
- clp->cl_firststate = 1;
+ if (status == 0)
vfs_fsync(rec_file, 0);
- }
+ else
+ printk(KERN_ERR "NFSD: failed to write recovery record"
+ " (err %d); please check that %s exists"
+ " and is writeable", status,
+ user_recovery_dirname);
nfs4_reset_creds(original_cred);
- dprintk("NFSD: nfsd4_create_clid_dir returns %d\n", status);
return status;
}
@@ -354,13 +356,13 @@ nfsd4_recdir_load(void) {
*/
void
-nfsd4_init_recdir(char *rec_dirname)
+nfsd4_init_recdir()
{
const struct cred *original_cred;
int status;
printk("NFSD: Using %s as the NFSv4 state recovery directory\n",
- rec_dirname);
+ user_recovery_dirname);
BUG_ON(rec_file);
@@ -372,10 +374,10 @@ nfsd4_init_recdir(char *rec_dirname)
return;
}
- rec_file = filp_open(rec_dirname, O_RDONLY | O_DIRECTORY, 0);
+ rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0);
if (IS_ERR(rec_file)) {
printk("NFSD: unable to find recovery directory %s\n",
- rec_dirname);
+ user_recovery_dirname);
rec_file = NULL;
}
@@ -390,3 +392,30 @@ nfsd4_shutdown_recdir(void)
fput(rec_file);
rec_file = NULL;
}
+
+/*
+ * Change the NFSv4 recovery directory to recdir.
+ */
+int
+nfs4_reset_recoverydir(char *recdir)
+{
+ int status;
+ struct path path;
+
+ status = kern_path(recdir, LOOKUP_FOLLOW, &path);
+ if (status)
+ return status;
+ status = -ENOTDIR;
+ if (S_ISDIR(path.dentry->d_inode->i_mode)) {
+ strcpy(user_recovery_dirname, recdir);
+ status = 0;
+ }
+ path_put(&path);
+ return status;
+}
+
+char *
+nfs4_recoverydir(void)
+{
+ return user_recovery_dirname;
+}
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 3787ec117400..47e94e33a975 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -49,9 +49,6 @@
time_t nfsd4_lease = 90; /* default lease time */
time_t nfsd4_grace = 90;
static time_t boot_time;
-static u32 current_ownerid = 1;
-static u32 current_fileid = 1;
-static u32 current_delegid = 1;
static stateid_t zerostateid; /* bits all 0 */
static stateid_t onestateid; /* bits all 1 */
static u64 current_sessionid = 1;
@@ -60,13 +57,7 @@ static u64 current_sessionid = 1;
#define ONE_STATEID(stateid) (!memcmp((stateid), &onestateid, sizeof(stateid_t)))
/* forward declarations */
-static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags);
-static struct nfs4_stateid * search_for_stateid(stateid_t *stid);
-static struct nfs4_delegation * search_for_delegation(stateid_t *stid);
-static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid);
-static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
-static void nfs4_set_recdir(char *recdir);
-static int check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner);
+static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner);
/* Locking: */
@@ -80,7 +71,8 @@ static DEFINE_MUTEX(client_mutex);
*/
static DEFINE_SPINLOCK(recall_lock);
-static struct kmem_cache *stateowner_slab = NULL;
+static struct kmem_cache *openowner_slab = NULL;
+static struct kmem_cache *lockowner_slab = NULL;
static struct kmem_cache *file_slab = NULL;
static struct kmem_cache *stateid_slab = NULL;
static struct kmem_cache *deleg_slab = NULL;
@@ -112,6 +104,11 @@ opaque_hashval(const void *ptr, int nbytes)
static struct list_head del_recall_lru;
+static void nfsd4_free_file(struct nfs4_file *f)
+{
+ kmem_cache_free(file_slab, f);
+}
+
static inline void
put_nfs4_file(struct nfs4_file *fi)
{
@@ -119,7 +116,7 @@ put_nfs4_file(struct nfs4_file *fi)
list_del(&fi->fi_hash);
spin_unlock(&recall_lock);
iput(fi->fi_inode);
- kmem_cache_free(file_slab, fi);
+ nfsd4_free_file(fi);
}
}
@@ -136,35 +133,33 @@ unsigned int max_delegations;
* Open owner state (share locks)
*/
-/* hash tables for nfs4_stateowner */
-#define OWNER_HASH_BITS 8
-#define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS)
-#define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1)
+/* hash tables for open owners */
+#define OPEN_OWNER_HASH_BITS 8
+#define OPEN_OWNER_HASH_SIZE (1 << OPEN_OWNER_HASH_BITS)
+#define OPEN_OWNER_HASH_MASK (OPEN_OWNER_HASH_SIZE - 1)
-#define ownerid_hashval(id) \
- ((id) & OWNER_HASH_MASK)
-#define ownerstr_hashval(clientid, ownername) \
- (((clientid) + opaque_hashval((ownername.data), (ownername.len))) & OWNER_HASH_MASK)
+static unsigned int open_ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername)
+{
+ unsigned int ret;
-static struct list_head ownerid_hashtbl[OWNER_HASH_SIZE];
-static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE];
+ ret = opaque_hashval(ownername->data, ownername->len);
+ ret += clientid;
+ return ret & OPEN_OWNER_HASH_MASK;
+}
+
+static struct list_head open_ownerstr_hashtbl[OPEN_OWNER_HASH_SIZE];
/* hash table for nfs4_file */
#define FILE_HASH_BITS 8
#define FILE_HASH_SIZE (1 << FILE_HASH_BITS)
-/* hash table for (open)nfs4_stateid */
-#define STATEID_HASH_BITS 10
-#define STATEID_HASH_SIZE (1 << STATEID_HASH_BITS)
-#define STATEID_HASH_MASK (STATEID_HASH_SIZE - 1)
-
-#define file_hashval(x) \
- hash_ptr(x, FILE_HASH_BITS)
-#define stateid_hashval(owner_id, file_id) \
- (((owner_id) + (file_id)) & STATEID_HASH_MASK)
+static unsigned int file_hashval(struct inode *ino)
+{
+ /* XXX: why are we hashing on inode pointer, anyway? */
+ return hash_ptr(ino, FILE_HASH_BITS);
+}
static struct list_head file_hashtbl[FILE_HASH_SIZE];
-static struct list_head stateid_hashtbl[STATEID_HASH_SIZE];
static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag)
{
@@ -192,8 +187,15 @@ static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag)
static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
{
if (atomic_dec_and_test(&fp->fi_access[oflag])) {
- nfs4_file_put_fd(fp, O_RDWR);
nfs4_file_put_fd(fp, oflag);
+ /*
+ * It's also safe to get rid of the RDWR open *if*
+ * we no longer have need of the other kind of access
+ * or if we already have the other kind of open:
+ */
+ if (fp->fi_fds[1-oflag]
+ || atomic_read(&fp->fi_access[1 - oflag]) == 0)
+ nfs4_file_put_fd(fp, O_RDWR);
}
}
@@ -206,8 +208,73 @@ static void nfs4_file_put_access(struct nfs4_file *fp, int oflag)
__nfs4_file_put_access(fp, oflag);
}
+static inline int get_new_stid(struct nfs4_stid *stid)
+{
+ static int min_stateid = 0;
+ struct idr *stateids = &stid->sc_client->cl_stateids;
+ int new_stid;
+ int error;
+
+ error = idr_get_new_above(stateids, stid, min_stateid, &new_stid);
+ /*
+ * Note: the necessary preallocation was done in
+ * nfs4_alloc_stateid(). The idr code caps the number of
+ * preallocations that can exist at a time, but the state lock
+ * prevents anyone from using ours before we get here:
+ */
+ BUG_ON(error);
+ /*
+ * It shouldn't be a problem to reuse an opaque stateid value.
+ * I don't think it is for 4.1. But with 4.0 I worry that, for
+ * example, a stray write retransmission could be accepted by
+ * the server when it should have been rejected. Therefore,
+ * adopt a trick from the sctp code to attempt to maximize the
+ * amount of time until an id is reused, by ensuring they always
+ * "increase" (mod INT_MAX):
+ */
+
+ min_stateid = new_stid+1;
+ if (min_stateid == INT_MAX)
+ min_stateid = 0;
+ return new_stid;
+}
+
+static void init_stid(struct nfs4_stid *stid, struct nfs4_client *cl, unsigned char type)
+{
+ stateid_t *s = &stid->sc_stateid;
+ int new_id;
+
+ stid->sc_type = type;
+ stid->sc_client = cl;
+ s->si_opaque.so_clid = cl->cl_clientid;
+ new_id = get_new_stid(stid);
+ s->si_opaque.so_id = (u32)new_id;
+ /* Will be incremented before return to client: */
+ s->si_generation = 0;
+}
+
+static struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab)
+{
+ struct idr *stateids = &cl->cl_stateids;
+
+ if (!idr_pre_get(stateids, GFP_KERNEL))
+ return NULL;
+ /*
+ * Note: if we fail here (or any time between now and the time
+ * we actually get the new idr), we won't need to undo the idr
+ * preallocation, since the idr code caps the number of
+ * preallocated entries.
+ */
+ return kmem_cache_alloc(slab, GFP_KERNEL);
+}
+
+static struct nfs4_ol_stateid * nfs4_alloc_stateid(struct nfs4_client *clp)
+{
+ return openlockstateid(nfs4_alloc_stid(clp, stateid_slab));
+}
+
static struct nfs4_delegation *
-alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type)
+alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh, u32 type)
{
struct nfs4_delegation *dp;
struct nfs4_file *fp = stp->st_file;
@@ -224,21 +291,23 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
return NULL;
if (num_delegations > max_delegations)
return NULL;
- dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL);
+ dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab));
if (dp == NULL)
return dp;
+ init_stid(&dp->dl_stid, clp, NFS4_DELEG_STID);
+ /*
+ * delegation seqid's are never incremented. The 4.1 special
+ * meaning of seqid 0 isn't meaningful, really, but let's avoid
+ * 0 anyway just for consistency and use 1:
+ */
+ dp->dl_stid.sc_stateid.si_generation = 1;
num_delegations++;
INIT_LIST_HEAD(&dp->dl_perfile);
INIT_LIST_HEAD(&dp->dl_perclnt);
INIT_LIST_HEAD(&dp->dl_recall_lru);
- dp->dl_client = clp;
get_nfs4_file(fp);
dp->dl_file = fp;
dp->dl_type = type;
- dp->dl_stateid.si_boot = boot_time;
- dp->dl_stateid.si_stateownerid = current_delegid++;
- dp->dl_stateid.si_fileid = 0;
- dp->dl_stateid.si_generation = 0;
fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle);
dp->dl_time = 0;
atomic_set(&dp->dl_count, 1);
@@ -267,10 +336,18 @@ static void nfs4_put_deleg_lease(struct nfs4_file *fp)
}
}
+static void unhash_stid(struct nfs4_stid *s)
+{
+ struct idr *stateids = &s->sc_client->cl_stateids;
+
+ idr_remove(stateids, s->sc_stateid.si_opaque.so_id);
+}
+
/* Called under the state lock. */
static void
unhash_delegation(struct nfs4_delegation *dp)
{
+ unhash_stid(&dp->dl_stid);
list_del_init(&dp->dl_perclnt);
spin_lock(&recall_lock);
list_del_init(&dp->dl_perfile);
@@ -292,10 +369,16 @@ static DEFINE_SPINLOCK(client_lock);
#define CLIENT_HASH_SIZE (1 << CLIENT_HASH_BITS)
#define CLIENT_HASH_MASK (CLIENT_HASH_SIZE - 1)
-#define clientid_hashval(id) \
- ((id) & CLIENT_HASH_MASK)
-#define clientstr_hashval(name) \
- (opaque_hashval((name), 8) & CLIENT_HASH_MASK)
+static unsigned int clientid_hashval(u32 id)
+{
+ return id & CLIENT_HASH_MASK;
+}
+
+static unsigned int clientstr_hashval(const char *name)
+{
+ return opaque_hashval(name, 8) & CLIENT_HASH_MASK;
+}
+
/*
* reclaim_str_hashtbl[] holds known client info from previous reset/reboot
* used in reboot/reset lease grace period processing
@@ -362,7 +445,7 @@ set_deny(unsigned int *deny, unsigned long bmap) {
}
static int
-test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) {
+test_share(struct nfs4_ol_stateid *stp, struct nfsd4_open *open) {
unsigned int access, deny;
set_access(&access, stp->st_access_bmap);
@@ -385,14 +468,13 @@ static int nfs4_access_to_omode(u32 access)
BUG();
}
-static void unhash_generic_stateid(struct nfs4_stateid *stp)
+static void unhash_generic_stateid(struct nfs4_ol_stateid *stp)
{
- list_del(&stp->st_hash);
list_del(&stp->st_perfile);
list_del(&stp->st_perstateowner);
}
-static void free_generic_stateid(struct nfs4_stateid *stp)
+static void close_generic_stateid(struct nfs4_ol_stateid *stp)
{
int i;
@@ -401,84 +483,106 @@ static void free_generic_stateid(struct nfs4_stateid *stp)
if (test_bit(i, &stp->st_access_bmap))
nfs4_file_put_access(stp->st_file,
nfs4_access_to_omode(i));
+ __clear_bit(i, &stp->st_access_bmap);
}
}
put_nfs4_file(stp->st_file);
+ stp->st_file = NULL;
+}
+
+static void free_generic_stateid(struct nfs4_ol_stateid *stp)
+{
kmem_cache_free(stateid_slab, stp);
}
-static void release_lock_stateid(struct nfs4_stateid *stp)
+static void release_lock_stateid(struct nfs4_ol_stateid *stp)
{
struct file *file;
unhash_generic_stateid(stp);
+ unhash_stid(&stp->st_stid);
file = find_any_file(stp->st_file);
if (file)
- locks_remove_posix(file, (fl_owner_t)stp->st_stateowner);
+ locks_remove_posix(file, (fl_owner_t)lockowner(stp->st_stateowner));
+ close_generic_stateid(stp);
free_generic_stateid(stp);
}
-static void unhash_lockowner(struct nfs4_stateowner *sop)
+static void unhash_lockowner(struct nfs4_lockowner *lo)
{
- struct nfs4_stateid *stp;
+ struct nfs4_ol_stateid *stp;
- list_del(&sop->so_idhash);
- list_del(&sop->so_strhash);
- list_del(&sop->so_perstateid);
- while (!list_empty(&sop->so_stateids)) {
- stp = list_first_entry(&sop->so_stateids,
- struct nfs4_stateid, st_perstateowner);
+ list_del(&lo->lo_owner.so_strhash);
+ list_del(&lo->lo_perstateid);
+ while (!list_empty(&lo->lo_owner.so_stateids)) {
+ stp = list_first_entry(&lo->lo_owner.so_stateids,
+ struct nfs4_ol_stateid, st_perstateowner);
release_lock_stateid(stp);
}
}
-static void release_lockowner(struct nfs4_stateowner *sop)
+static void release_lockowner(struct nfs4_lockowner *lo)
{
- unhash_lockowner(sop);
- nfs4_put_stateowner(sop);
+ unhash_lockowner(lo);
+ nfs4_free_lockowner(lo);
}
static void
-release_stateid_lockowners(struct nfs4_stateid *open_stp)
+release_stateid_lockowners(struct nfs4_ol_stateid *open_stp)
{
- struct nfs4_stateowner *lock_sop;
+ struct nfs4_lockowner *lo;
while (!list_empty(&open_stp->st_lockowners)) {
- lock_sop = list_entry(open_stp->st_lockowners.next,
- struct nfs4_stateowner, so_perstateid);
- /* list_del(&open_stp->st_lockowners); */
- BUG_ON(lock_sop->so_is_open_owner);
- release_lockowner(lock_sop);
+ lo = list_entry(open_stp->st_lockowners.next,
+ struct nfs4_lockowner, lo_perstateid);
+ release_lockowner(lo);
}
}
-static void release_open_stateid(struct nfs4_stateid *stp)
+static void unhash_open_stateid(struct nfs4_ol_stateid *stp)
{
unhash_generic_stateid(stp);
release_stateid_lockowners(stp);
+ close_generic_stateid(stp);
+}
+
+static void release_open_stateid(struct nfs4_ol_stateid *stp)
+{
+ unhash_open_stateid(stp);
+ unhash_stid(&stp->st_stid);
free_generic_stateid(stp);
}
-static void unhash_openowner(struct nfs4_stateowner *sop)
+static void unhash_openowner(struct nfs4_openowner *oo)
{
- struct nfs4_stateid *stp;
+ struct nfs4_ol_stateid *stp;
- list_del(&sop->so_idhash);
- list_del(&sop->so_strhash);
- list_del(&sop->so_perclient);
- list_del(&sop->so_perstateid); /* XXX: necessary? */
- while (!list_empty(&sop->so_stateids)) {
- stp = list_first_entry(&sop->so_stateids,
- struct nfs4_stateid, st_perstateowner);
+ list_del(&oo->oo_owner.so_strhash);
+ list_del(&oo->oo_perclient);
+ while (!list_empty(&oo->oo_owner.so_stateids)) {
+ stp = list_first_entry(&oo->oo_owner.so_stateids,
+ struct nfs4_ol_stateid, st_perstateowner);
release_open_stateid(stp);
}
}
-static void release_openowner(struct nfs4_stateowner *sop)
+static void release_last_closed_stateid(struct nfs4_openowner *oo)
{
- unhash_openowner(sop);
- list_del(&sop->so_close_lru);
- nfs4_put_stateowner(sop);
+ struct nfs4_ol_stateid *s = oo->oo_last_closed_stid;
+
+ if (s) {
+ unhash_stid(&s->st_stid);
+ free_generic_stateid(s);
+ oo->oo_last_closed_stid = NULL;
+ }
+}
+
+static void release_openowner(struct nfs4_openowner *oo)
+{
+ unhash_openowner(oo);
+ list_del(&oo->oo_close_lru);
+ release_last_closed_stateid(oo);
+ nfs4_free_openowner(oo);
}
#define SESSION_HASH_SIZE 512
@@ -843,9 +947,6 @@ renew_client_locked(struct nfs4_client *clp)
return;
}
- /*
- * Move client to the end to the LRU list.
- */
dprintk("renewing client (clientid %08x/%08x)\n",
clp->cl_clientid.cl_boot,
clp->cl_clientid.cl_id);
@@ -943,7 +1044,7 @@ unhash_client_locked(struct nfs4_client *clp)
static void
expire_client(struct nfs4_client *clp)
{
- struct nfs4_stateowner *sop;
+ struct nfs4_openowner *oo;
struct nfs4_delegation *dp;
struct list_head reaplist;
@@ -961,8 +1062,8 @@ expire_client(struct nfs4_client *clp)
unhash_delegation(dp);
}
while (!list_empty(&clp->cl_openowners)) {
- sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient);
- release_openowner(sop);
+ oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient);
+ release_openowner(oo);
}
nfsd4_shutdown_callback(clp);
if (clp->cl_cb_conn.cb_xprt)
@@ -1038,6 +1139,23 @@ static void gen_confirm(struct nfs4_client *clp)
*p++ = i++;
}
+static struct nfs4_stid *find_stateid(struct nfs4_client *cl, stateid_t *t)
+{
+ return idr_find(&cl->cl_stateids, t->si_opaque.so_id);
+}
+
+static struct nfs4_stid *find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask)
+{
+ struct nfs4_stid *s;
+
+ s = find_stateid(cl, t);
+ if (!s)
+ return NULL;
+ if (typemask & s->sc_type)
+ return s;
+ return NULL;
+}
+
static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
struct svc_rqst *rqstp, nfs4_verifier *verf)
{
@@ -1060,6 +1178,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
}
}
+ idr_init(&clp->cl_stateids);
memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
atomic_set(&clp->cl_refcount, 0);
clp->cl_cb_state = NFSD4_CB_UNKNOWN;
@@ -1083,17 +1202,6 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
return clp;
}
-static int check_name(struct xdr_netobj name)
-{
- if (name.len == 0)
- return 0;
- if (name.len > NFS4_OPAQUE_LIMIT) {
- dprintk("NFSD: check_name: name too long(%d)!\n", name.len);
- return 0;
- }
- return 1;
-}
-
static void
add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval)
{
@@ -1125,8 +1233,10 @@ find_confirmed_client(clientid_t *clid)
unsigned int idhashval = clientid_hashval(clid->cl_id);
list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
- if (same_clid(&clp->cl_clientid, clid))
+ if (same_clid(&clp->cl_clientid, clid)) {
+ renew_client(clp);
return clp;
+ }
}
return NULL;
}
@@ -1173,20 +1283,6 @@ find_unconfirmed_client_by_str(const char *dname, unsigned int hashval)
return NULL;
}
-static void rpc_svcaddr2sockaddr(struct sockaddr *sa, unsigned short family, union svc_addr_u *svcaddr)
-{
- switch (family) {
- case AF_INET:
- ((struct sockaddr_in *)sa)->sin_family = AF_INET;
- ((struct sockaddr_in *)sa)->sin_addr = svcaddr->addr;
- return;
- case AF_INET6:
- ((struct sockaddr_in6 *)sa)->sin6_family = AF_INET6;
- ((struct sockaddr_in6 *)sa)->sin6_addr = svcaddr->addr6;
- return;
- }
-}
-
static void
gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp)
{
@@ -1218,7 +1314,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_r
conn->cb_prog = se->se_callback_prog;
conn->cb_ident = se->se_callback_ident;
- rpc_svcaddr2sockaddr((struct sockaddr *)&conn->cb_saddr, expected_family, &rqstp->rq_daddr);
+ memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen);
return;
out_err:
conn->cb_addr.ss_family = AF_UNSPEC;
@@ -1350,7 +1446,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
__func__, rqstp, exid, exid->clname.len, exid->clname.data,
addr_str, exid->flags, exid->spa_how);
- if (!check_name(exid->clname) || (exid->flags & ~EXCHGID4_FLAG_MASK_A))
+ if (exid->flags & ~EXCHGID4_FLAG_MASK_A)
return nfserr_inval;
/* Currently only support SP4_NONE */
@@ -1849,8 +1945,16 @@ out:
nfsd4_get_session(cstate->session);
atomic_inc(&clp->cl_refcount);
- if (clp->cl_cb_state == NFSD4_CB_DOWN)
- seq->status_flags |= SEQ4_STATUS_CB_PATH_DOWN;
+ switch (clp->cl_cb_state) {
+ case NFSD4_CB_DOWN:
+ seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN;
+ break;
+ case NFSD4_CB_FAULT:
+ seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT;
+ break;
+ default:
+ seq->status_flags = 0;
+ }
}
kfree(conn);
spin_unlock(&client_lock);
@@ -1858,6 +1962,50 @@ out:
return status;
}
+static inline bool has_resources(struct nfs4_client *clp)
+{
+ return !list_empty(&clp->cl_openowners)
+ || !list_empty(&clp->cl_delegations)
+ || !list_empty(&clp->cl_sessions);
+}
+
+__be32
+nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc)
+{
+ struct nfs4_client *conf, *unconf, *clp;
+ int status = 0;
+
+ nfs4_lock_state();
+ unconf = find_unconfirmed_client(&dc->clientid);
+ conf = find_confirmed_client(&dc->clientid);
+
+ if (conf) {
+ clp = conf;
+
+ if (!is_client_expired(conf) && has_resources(conf)) {
+ status = nfserr_clientid_busy;
+ goto out;
+ }
+
+ /* rfc5661 18.50.3 */
+ if (cstate->session && conf == cstate->session->se_client) {
+ status = nfserr_clientid_busy;
+ goto out;
+ }
+ } else if (unconf)
+ clp = unconf;
+ else {
+ status = nfserr_stale_clientid;
+ goto out;
+ }
+
+ expire_client(clp);
+out:
+ nfs4_unlock_state();
+ dprintk("%s return %d\n", __func__, ntohl(status));
+ return status;
+}
+
__be32
nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc)
{
@@ -1900,19 +2048,13 @@ __be32
nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_setclientid *setclid)
{
- struct xdr_netobj clname = {
- .len = setclid->se_namelen,
- .data = setclid->se_name,
- };
+ struct xdr_netobj clname = setclid->se_name;
nfs4_verifier clverifier = setclid->se_verf;
unsigned int strhashval;
struct nfs4_client *conf, *unconf, *new;
__be32 status;
char dname[HEXDIR_LEN];
- if (!check_name(clname))
- return nfserr_inval;
-
status = nfs4_make_rec_clidname(dname, &clname);
if (status)
return status;
@@ -1946,7 +2088,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
* of 5 bullet points, labeled as CASE0 - CASE4 below.
*/
unconf = find_unconfirmed_client_by_str(dname, strhashval);
- status = nfserr_resource;
+ status = nfserr_jukebox;
if (!conf) {
/*
* RFC 3530 14.2.33 CASE 4:
@@ -2116,31 +2258,28 @@ out:
return status;
}
+static struct nfs4_file *nfsd4_alloc_file(void)
+{
+ return kmem_cache_alloc(file_slab, GFP_KERNEL);
+}
+
/* OPEN Share state helper functions */
-static inline struct nfs4_file *
-alloc_init_file(struct inode *ino)
+static void nfsd4_init_file(struct nfs4_file *fp, struct inode *ino)
{
- struct nfs4_file *fp;
unsigned int hashval = file_hashval(ino);
- fp = kmem_cache_alloc(file_slab, GFP_KERNEL);
- if (fp) {
- atomic_set(&fp->fi_ref, 1);
- INIT_LIST_HEAD(&fp->fi_hash);
- INIT_LIST_HEAD(&fp->fi_stateids);
- INIT_LIST_HEAD(&fp->fi_delegations);
- fp->fi_inode = igrab(ino);
- fp->fi_id = current_fileid++;
- fp->fi_had_conflict = false;
- fp->fi_lease = NULL;
- memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
- memset(fp->fi_access, 0, sizeof(fp->fi_access));
- spin_lock(&recall_lock);
- list_add(&fp->fi_hash, &file_hashtbl[hashval]);
- spin_unlock(&recall_lock);
- return fp;
- }
- return NULL;
+ atomic_set(&fp->fi_ref, 1);
+ INIT_LIST_HEAD(&fp->fi_hash);
+ INIT_LIST_HEAD(&fp->fi_stateids);
+ INIT_LIST_HEAD(&fp->fi_delegations);
+ fp->fi_inode = igrab(ino);
+ fp->fi_had_conflict = false;
+ fp->fi_lease = NULL;
+ memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
+ memset(fp->fi_access, 0, sizeof(fp->fi_access));
+ spin_lock(&recall_lock);
+ list_add(&fp->fi_hash, &file_hashtbl[hashval]);
+ spin_unlock(&recall_lock);
}
static void
@@ -2155,7 +2294,8 @@ nfsd4_free_slab(struct kmem_cache **slab)
void
nfsd4_free_slabs(void)
{
- nfsd4_free_slab(&stateowner_slab);
+ nfsd4_free_slab(&openowner_slab);
+ nfsd4_free_slab(&lockowner_slab);
nfsd4_free_slab(&file_slab);
nfsd4_free_slab(&stateid_slab);
nfsd4_free_slab(&deleg_slab);
@@ -2164,16 +2304,20 @@ nfsd4_free_slabs(void)
static int
nfsd4_init_slabs(void)
{
- stateowner_slab = kmem_cache_create("nfsd4_stateowners",
- sizeof(struct nfs4_stateowner), 0, 0, NULL);
- if (stateowner_slab == NULL)
+ openowner_slab = kmem_cache_create("nfsd4_openowners",
+ sizeof(struct nfs4_openowner), 0, 0, NULL);
+ if (openowner_slab == NULL)
+ goto out_nomem;
+ lockowner_slab = kmem_cache_create("nfsd4_lockowners",
+ sizeof(struct nfs4_openowner), 0, 0, NULL);
+ if (lockowner_slab == NULL)
goto out_nomem;
file_slab = kmem_cache_create("nfsd4_files",
sizeof(struct nfs4_file), 0, 0, NULL);
if (file_slab == NULL)
goto out_nomem;
stateid_slab = kmem_cache_create("nfsd4_stateids",
- sizeof(struct nfs4_stateid), 0, 0, NULL);
+ sizeof(struct nfs4_ol_stateid), 0, 0, NULL);
if (stateid_slab == NULL)
goto out_nomem;
deleg_slab = kmem_cache_create("nfsd4_delegations",
@@ -2187,97 +2331,94 @@ out_nomem:
return -ENOMEM;
}
-void
-nfs4_free_stateowner(struct kref *kref)
+void nfs4_free_openowner(struct nfs4_openowner *oo)
{
- struct nfs4_stateowner *sop =
- container_of(kref, struct nfs4_stateowner, so_ref);
- kfree(sop->so_owner.data);
- kmem_cache_free(stateowner_slab, sop);
+ kfree(oo->oo_owner.so_owner.data);
+ kmem_cache_free(openowner_slab, oo);
}
-static inline struct nfs4_stateowner *
-alloc_stateowner(struct xdr_netobj *owner)
+void nfs4_free_lockowner(struct nfs4_lockowner *lo)
{
- struct nfs4_stateowner *sop;
+ kfree(lo->lo_owner.so_owner.data);
+ kmem_cache_free(lockowner_slab, lo);
+}
- if ((sop = kmem_cache_alloc(stateowner_slab, GFP_KERNEL))) {
- if ((sop->so_owner.data = kmalloc(owner->len, GFP_KERNEL))) {
- memcpy(sop->so_owner.data, owner->data, owner->len);
- sop->so_owner.len = owner->len;
- kref_init(&sop->so_ref);
- return sop;
- }
- kmem_cache_free(stateowner_slab, sop);
- }
- return NULL;
+static void init_nfs4_replay(struct nfs4_replay *rp)
+{
+ rp->rp_status = nfserr_serverfault;
+ rp->rp_buflen = 0;
+ rp->rp_buf = rp->rp_ibuf;
}
-static struct nfs4_stateowner *
-alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) {
+static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp)
+{
struct nfs4_stateowner *sop;
- struct nfs4_replay *rp;
- unsigned int idhashval;
- if (!(sop = alloc_stateowner(&open->op_owner)))
+ sop = kmem_cache_alloc(slab, GFP_KERNEL);
+ if (!sop)
+ return NULL;
+
+ sop->so_owner.data = kmemdup(owner->data, owner->len, GFP_KERNEL);
+ if (!sop->so_owner.data) {
+ kmem_cache_free(slab, sop);
return NULL;
- idhashval = ownerid_hashval(current_ownerid);
- INIT_LIST_HEAD(&sop->so_idhash);
- INIT_LIST_HEAD(&sop->so_strhash);
- INIT_LIST_HEAD(&sop->so_perclient);
+ }
+ sop->so_owner.len = owner->len;
+
INIT_LIST_HEAD(&sop->so_stateids);
- INIT_LIST_HEAD(&sop->so_perstateid); /* not used */
- INIT_LIST_HEAD(&sop->so_close_lru);
- sop->so_time = 0;
- list_add(&sop->so_idhash, &ownerid_hashtbl[idhashval]);
- list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]);
- list_add(&sop->so_perclient, &clp->cl_openowners);
- sop->so_is_open_owner = 1;
- sop->so_id = current_ownerid++;
sop->so_client = clp;
- sop->so_seqid = open->op_seqid;
- sop->so_confirmed = 0;
- rp = &sop->so_replay;
- rp->rp_status = nfserr_serverfault;
- rp->rp_buflen = 0;
- rp->rp_buf = rp->rp_ibuf;
+ init_nfs4_replay(&sop->so_replay);
return sop;
}
-static inline void
-init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
- struct nfs4_stateowner *sop = open->op_stateowner;
- unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id);
+static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval)
+{
+ list_add(&oo->oo_owner.so_strhash, &open_ownerstr_hashtbl[strhashval]);
+ list_add(&oo->oo_perclient, &clp->cl_openowners);
+}
- INIT_LIST_HEAD(&stp->st_hash);
- INIT_LIST_HEAD(&stp->st_perstateowner);
+static struct nfs4_openowner *
+alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) {
+ struct nfs4_openowner *oo;
+
+ oo = alloc_stateowner(openowner_slab, &open->op_owner, clp);
+ if (!oo)
+ return NULL;
+ oo->oo_owner.so_is_open_owner = 1;
+ oo->oo_owner.so_seqid = open->op_seqid;
+ oo->oo_flags = NFS4_OO_NEW;
+ oo->oo_time = 0;
+ oo->oo_last_closed_stid = NULL;
+ INIT_LIST_HEAD(&oo->oo_close_lru);
+ hash_openowner(oo, clp, strhashval);
+ return oo;
+}
+
+static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
+ struct nfs4_openowner *oo = open->op_openowner;
+ struct nfs4_client *clp = oo->oo_owner.so_client;
+
+ init_stid(&stp->st_stid, clp, NFS4_OPEN_STID);
INIT_LIST_HEAD(&stp->st_lockowners);
- INIT_LIST_HEAD(&stp->st_perfile);
- list_add(&stp->st_hash, &stateid_hashtbl[hashval]);
- list_add(&stp->st_perstateowner, &sop->so_stateids);
+ list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
list_add(&stp->st_perfile, &fp->fi_stateids);
- stp->st_stateowner = sop;
+ stp->st_stateowner = &oo->oo_owner;
get_nfs4_file(fp);
stp->st_file = fp;
- stp->st_stateid.si_boot = boot_time;
- stp->st_stateid.si_stateownerid = sop->so_id;
- stp->st_stateid.si_fileid = fp->fi_id;
- stp->st_stateid.si_generation = 0;
stp->st_access_bmap = 0;
stp->st_deny_bmap = 0;
- __set_bit(open->op_share_access & ~NFS4_SHARE_WANT_MASK,
- &stp->st_access_bmap);
+ __set_bit(open->op_share_access, &stp->st_access_bmap);
__set_bit(open->op_share_deny, &stp->st_deny_bmap);
stp->st_openstp = NULL;
}
static void
-move_to_close_lru(struct nfs4_stateowner *sop)
+move_to_close_lru(struct nfs4_openowner *oo)
{
- dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop);
+ dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo);
- list_move_tail(&sop->so_close_lru, &close_lru);
- sop->so_time = get_seconds();
+ list_move_tail(&oo->oo_close_lru, &close_lru);
+ oo->oo_time = get_seconds();
}
static int
@@ -2289,14 +2430,18 @@ same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner,
(sop->so_client->cl_clientid.cl_id == clid->cl_id);
}
-static struct nfs4_stateowner *
+static struct nfs4_openowner *
find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open)
{
- struct nfs4_stateowner *so = NULL;
+ struct nfs4_stateowner *so;
+ struct nfs4_openowner *oo;
- list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) {
- if (same_owner_str(so, &open->op_owner, &open->op_clientid))
- return so;
+ list_for_each_entry(so, &open_ownerstr_hashtbl[hashval], so_strhash) {
+ if (same_owner_str(so, &open->op_owner, &open->op_clientid)) {
+ oo = openowner(so);
+ renew_client(oo->oo_owner.so_client);
+ return oo;
+ }
}
return NULL;
}
@@ -2320,31 +2465,6 @@ find_file(struct inode *ino)
return NULL;
}
-static inline int access_valid(u32 x, u32 minorversion)
-{
- if ((x & NFS4_SHARE_ACCESS_MASK) < NFS4_SHARE_ACCESS_READ)
- return 0;
- if ((x & NFS4_SHARE_ACCESS_MASK) > NFS4_SHARE_ACCESS_BOTH)
- return 0;
- x &= ~NFS4_SHARE_ACCESS_MASK;
- if (minorversion && x) {
- if ((x & NFS4_SHARE_WANT_MASK) > NFS4_SHARE_WANT_CANCEL)
- return 0;
- if ((x & NFS4_SHARE_WHEN_MASK) > NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED)
- return 0;
- x &= ~(NFS4_SHARE_WANT_MASK | NFS4_SHARE_WHEN_MASK);
- }
- if (x)
- return 0;
- return 1;
-}
-
-static inline int deny_valid(u32 x)
-{
- /* Note: unlike access bits, deny bits may be zero. */
- return x <= NFS4_SHARE_DENY_BOTH;
-}
-
/*
* Called to check deny when READ with all zero stateid or
* WRITE with all zero or all one stateid
@@ -2354,7 +2474,7 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
{
struct inode *ino = current_fh->fh_dentry->d_inode;
struct nfs4_file *fp;
- struct nfs4_stateid *stp;
+ struct nfs4_ol_stateid *stp;
__be32 ret;
dprintk("NFSD: nfs4_share_conflict\n");
@@ -2429,6 +2549,16 @@ static const struct lock_manager_operations nfsd_lease_mng_ops = {
.lm_change = nfsd_change_deleg_cb,
};
+static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid)
+{
+ if (nfsd4_has_session(cstate))
+ return nfs_ok;
+ if (seqid == so->so_seqid - 1)
+ return nfserr_replay_me;
+ if (seqid == so->so_seqid)
+ return nfs_ok;
+ return nfserr_bad_seqid;
+}
__be32
nfsd4_process_open1(struct nfsd4_compound_state *cstate,
@@ -2437,57 +2567,49 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
clientid_t *clientid = &open->op_clientid;
struct nfs4_client *clp = NULL;
unsigned int strhashval;
- struct nfs4_stateowner *sop = NULL;
-
- if (!check_name(open->op_owner))
- return nfserr_inval;
+ struct nfs4_openowner *oo = NULL;
+ __be32 status;
if (STALE_CLIENTID(&open->op_clientid))
return nfserr_stale_clientid;
+ /*
+ * In case we need it later, after we've already created the
+ * file and don't want to risk a further failure:
+ */
+ open->op_file = nfsd4_alloc_file();
+ if (open->op_file == NULL)
+ return nfserr_jukebox;
- strhashval = ownerstr_hashval(clientid->cl_id, open->op_owner);
- sop = find_openstateowner_str(strhashval, open);
- open->op_stateowner = sop;
- if (!sop) {
- /* Make sure the client's lease hasn't expired. */
+ strhashval = open_ownerstr_hashval(clientid->cl_id, &open->op_owner);
+ oo = find_openstateowner_str(strhashval, open);
+ open->op_openowner = oo;
+ if (!oo) {
clp = find_confirmed_client(clientid);
if (clp == NULL)
return nfserr_expired;
- goto renew;
+ goto new_owner;
}
- /* When sessions are used, skip open sequenceid processing */
- if (nfsd4_has_session(cstate))
- goto renew;
- if (!sop->so_confirmed) {
+ if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
/* Replace unconfirmed owners without checking for replay. */
- clp = sop->so_client;
- release_openowner(sop);
- open->op_stateowner = NULL;
- goto renew;
- }
- if (open->op_seqid == sop->so_seqid - 1) {
- if (sop->so_replay.rp_buflen)
- return nfserr_replay_me;
- /* The original OPEN failed so spectacularly
- * that we don't even have replay data saved!
- * Therefore, we have no choice but to continue
- * processing this OPEN; presumably, we'll
- * fail again for the same reason.
- */
- dprintk("nfsd4_process_open1: replay with no replay cache\n");
- goto renew;
- }
- if (open->op_seqid != sop->so_seqid)
- return nfserr_bad_seqid;
-renew:
- if (open->op_stateowner == NULL) {
- sop = alloc_init_open_stateowner(strhashval, clp, open);
- if (sop == NULL)
- return nfserr_resource;
- open->op_stateowner = sop;
+ clp = oo->oo_owner.so_client;
+ release_openowner(oo);
+ open->op_openowner = NULL;
+ goto new_owner;
}
- list_del_init(&sop->so_close_lru);
- renew_client(sop->so_client);
+ status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid);
+ if (status)
+ return status;
+ clp = oo->oo_owner.so_client;
+ goto alloc_stateid;
+new_owner:
+ oo = alloc_init_open_stateowner(strhashval, clp, open);
+ if (oo == NULL)
+ return nfserr_jukebox;
+ open->op_openowner = oo;
+alloc_stateid:
+ open->op_stp = nfs4_alloc_stateid(clp);
+ if (!open->op_stp)
+ return nfserr_jukebox;
return nfs_ok;
}
@@ -2500,36 +2622,37 @@ nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
return nfs_ok;
}
-static struct nfs4_delegation *
-find_delegation_file(struct nfs4_file *fp, stateid_t *stid)
+static int share_access_to_flags(u32 share_access)
{
- struct nfs4_delegation *dp;
+ share_access &= ~NFS4_SHARE_WANT_MASK;
- spin_lock(&recall_lock);
- list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
- if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid) {
- spin_unlock(&recall_lock);
- return dp;
- }
- spin_unlock(&recall_lock);
- return NULL;
+ return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE;
}
-static int share_access_to_flags(u32 share_access)
+static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s)
{
- share_access &= ~NFS4_SHARE_WANT_MASK;
+ struct nfs4_stid *ret;
- return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE;
+ ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID);
+ if (!ret)
+ return NULL;
+ return delegstateid(ret);
+}
+
+static bool nfsd4_is_deleg_cur(struct nfsd4_open *open)
+{
+ return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR ||
+ open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH;
}
static __be32
-nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,
+nfs4_check_deleg(struct nfs4_client *cl, struct nfs4_file *fp, struct nfsd4_open *open,
struct nfs4_delegation **dp)
{
int flags;
__be32 status = nfserr_bad_stateid;
- *dp = find_delegation_file(fp, &open->op_delegate_stateid);
+ *dp = find_deleg_stateid(cl, &open->op_delegate_stateid);
if (*dp == NULL)
goto out;
flags = share_access_to_flags(open->op_share_access);
@@ -2537,41 +2660,37 @@ nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,
if (status)
*dp = NULL;
out:
- if (open->op_claim_type != NFS4_OPEN_CLAIM_DELEGATE_CUR)
+ if (!nfsd4_is_deleg_cur(open))
return nfs_ok;
if (status)
return status;
- open->op_stateowner->so_confirmed = 1;
+ open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
return nfs_ok;
}
static __be32
-nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp)
+nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_stateid **stpp)
{
- struct nfs4_stateid *local;
- __be32 status = nfserr_share_denied;
- struct nfs4_stateowner *sop = open->op_stateowner;
+ struct nfs4_ol_stateid *local;
+ struct nfs4_openowner *oo = open->op_openowner;
list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
/* ignore lock owners */
if (local->st_stateowner->so_is_open_owner == 0)
continue;
/* remember if we have seen this open owner */
- if (local->st_stateowner == sop)
+ if (local->st_stateowner == &oo->oo_owner)
*stpp = local;
/* check for conflicting share reservations */
if (!test_share(local, open))
- goto out;
+ return nfserr_share_denied;
}
- status = 0;
-out:
- return status;
+ return nfs_ok;
}
-static inline struct nfs4_stateid *
-nfs4_alloc_stateid(void)
+static void nfs4_free_stateid(struct nfs4_ol_stateid *s)
{
- return kmem_cache_alloc(stateid_slab, GFP_KERNEL);
+ kmem_cache_free(stateid_slab, s);
}
static inline int nfs4_access_to_access(u32 nfs4_access)
@@ -2592,12 +2711,6 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
int oflag = nfs4_access_to_omode(open->op_share_access);
int access = nfs4_access_to_access(open->op_share_access);
- /* CLAIM_DELEGATE_CUR is used in response to a broken lease;
- * allowing it to break the lease and return EAGAIN leaves the
- * client unable to make progress in returning the delegation */
- if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR)
- access |= NFSD_MAY_NOT_BREAK_LEASE;
-
if (!fp->fi_fds[oflag]) {
status = nfsd_open(rqstp, cur_fh, S_IFREG, access,
&fp->fi_fds[oflag]);
@@ -2609,27 +2722,6 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
return nfs_ok;
}
-static __be32
-nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp,
- struct nfs4_file *fp, struct svc_fh *cur_fh,
- struct nfsd4_open *open)
-{
- struct nfs4_stateid *stp;
- __be32 status;
-
- stp = nfs4_alloc_stateid();
- if (stp == NULL)
- return nfserr_resource;
-
- status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open);
- if (status) {
- kmem_cache_free(stateid_slab, stp);
- return status;
- }
- *stpp = stp;
- return 0;
-}
-
static inline __be32
nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
struct nfsd4_open *open)
@@ -2646,9 +2738,9 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
}
static __be32
-nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open)
+nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, struct nfsd4_open *open)
{
- u32 op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK;
+ u32 op_share_access = open->op_share_access;
bool new_access;
__be32 status;
@@ -2677,8 +2769,8 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c
static void
nfs4_set_claim_prev(struct nfsd4_open *open)
{
- open->op_stateowner->so_confirmed = 1;
- open->op_stateowner->so_client->cl_firststate = 1;
+ open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
+ open->op_openowner->oo_owner.so_client->cl_firststate = 1;
}
/* Should we give out recallable state?: */
@@ -2721,7 +2813,7 @@ static int nfs4_setlease(struct nfs4_delegation *dp, int flag)
if (!fl)
return -ENOMEM;
fl->fl_file = find_readable_file(fp);
- list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations);
+ list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
status = vfs_setlease(fl->fl_file, fl->fl_type, &fl);
if (status) {
list_del_init(&dp->dl_perclnt);
@@ -2750,7 +2842,7 @@ static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag)
atomic_inc(&fp->fi_delegees);
list_add(&dp->dl_perfile, &fp->fi_delegations);
spin_unlock(&recall_lock);
- list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations);
+ list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
return 0;
}
@@ -2758,14 +2850,14 @@ static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag)
* Attempt to hand out a delegation.
*/
static void
-nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_stateid *stp)
+nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_ol_stateid *stp)
{
struct nfs4_delegation *dp;
- struct nfs4_stateowner *sop = stp->st_stateowner;
+ struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner);
int cb_up;
int status, flag = 0;
- cb_up = nfsd4_cb_channel_good(sop->so_client);
+ cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client);
flag = NFS4_OPEN_DELEGATE_NONE;
open->op_recall = 0;
switch (open->op_claim_type) {
@@ -2781,7 +2873,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
* had the chance to reclaim theirs.... */
if (locks_in_grace())
goto out;
- if (!cb_up || !sop->so_confirmed)
+ if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED))
goto out;
if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
flag = NFS4_OPEN_DELEGATE_WRITE;
@@ -2792,17 +2884,17 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
goto out;
}
- dp = alloc_init_deleg(sop->so_client, stp, fh, flag);
+ dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh, flag);
if (dp == NULL)
goto out_no_deleg;
status = nfs4_set_delegation(dp, flag);
if (status)
goto out_free;
- memcpy(&open->op_delegate_stateid, &dp->dl_stateid, sizeof(dp->dl_stateid));
+ memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid));
dprintk("NFSD: delegation stateid=" STATEID_FMT "\n",
- STATEID_VAL(&dp->dl_stateid));
+ STATEID_VAL(&dp->dl_stid.sc_stateid));
out:
if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS
&& flag == NFS4_OPEN_DELEGATE_NONE
@@ -2824,16 +2916,13 @@ __be32
nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
{
struct nfsd4_compoundres *resp = rqstp->rq_resp;
+ struct nfs4_client *cl = open->op_openowner->oo_owner.so_client;
struct nfs4_file *fp = NULL;
struct inode *ino = current_fh->fh_dentry->d_inode;
- struct nfs4_stateid *stp = NULL;
+ struct nfs4_ol_stateid *stp = NULL;
struct nfs4_delegation *dp = NULL;
__be32 status;
- status = nfserr_inval;
- if (!access_valid(open->op_share_access, resp->cstate.minorversion)
- || !deny_valid(open->op_share_deny))
- goto out;
/*
* Lookup file; if found, lookup stateid and check open request,
* and check for delegations in the process of being recalled.
@@ -2843,17 +2932,17 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
if (fp) {
if ((status = nfs4_check_open(fp, open, &stp)))
goto out;
- status = nfs4_check_deleg(fp, open, &dp);
+ status = nfs4_check_deleg(cl, fp, open, &dp);
if (status)
goto out;
} else {
status = nfserr_bad_stateid;
- if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR)
- goto out;
- status = nfserr_resource;
- fp = alloc_init_file(ino);
- if (fp == NULL)
+ if (nfsd4_is_deleg_cur(open))
goto out;
+ status = nfserr_jukebox;
+ fp = open->op_file;
+ open->op_file = NULL;
+ nfsd4_init_file(fp, ino);
}
/*
@@ -2865,24 +2954,24 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open);
if (status)
goto out;
- update_stateid(&stp->st_stateid);
} else {
- status = nfs4_new_open(rqstp, &stp, fp, current_fh, open);
+ status = nfs4_get_vfs_file(rqstp, fp, current_fh, open);
if (status)
goto out;
- init_stateid(stp, fp, open);
+ stp = open->op_stp;
+ open->op_stp = NULL;
+ init_open_stateid(stp, fp, open);
status = nfsd4_truncate(rqstp, current_fh, open);
if (status) {
release_open_stateid(stp);
goto out;
}
- if (nfsd4_has_session(&resp->cstate))
- update_stateid(&stp->st_stateid);
}
- memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t));
+ update_stateid(&stp->st_stid.sc_stateid);
+ memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
if (nfsd4_has_session(&resp->cstate))
- open->op_stateowner->so_confirmed = 1;
+ open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
/*
* Attempt to hand out a delegation. No error return, because the
@@ -2893,7 +2982,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
status = nfs_ok;
dprintk("%s: stateid=" STATEID_FMT "\n", __func__,
- STATEID_VAL(&stp->st_stateid));
+ STATEID_VAL(&stp->st_stid.sc_stateid));
out:
if (fp)
put_nfs4_file(fp);
@@ -2903,13 +2992,34 @@ out:
* To finish the open response, we just need to set the rflags.
*/
open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX;
- if (!open->op_stateowner->so_confirmed &&
+ if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED) &&
!nfsd4_has_session(&resp->cstate))
open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;
return status;
}
+void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status)
+{
+ if (open->op_openowner) {
+ struct nfs4_openowner *oo = open->op_openowner;
+
+ if (!list_empty(&oo->oo_owner.so_stateids))
+ list_del_init(&oo->oo_close_lru);
+ if (oo->oo_flags & NFS4_OO_NEW) {
+ if (status) {
+ release_openowner(oo);
+ open->op_openowner = NULL;
+ } else
+ oo->oo_flags &= ~NFS4_OO_NEW;
+ }
+ }
+ if (open->op_file)
+ nfsd4_free_file(open->op_file);
+ if (open->op_stp)
+ nfs4_free_stateid(open->op_stp);
+}
+
__be32
nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
clientid_t *clid)
@@ -2930,7 +3040,6 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
dprintk("nfsd4_renew: clientid not found!\n");
goto out;
}
- renew_client(clp);
status = nfserr_cb_path_down;
if (!list_empty(&clp->cl_delegations)
&& clp->cl_cb_state != NFSD4_CB_UP)
@@ -2962,7 +3071,7 @@ static time_t
nfs4_laundromat(void)
{
struct nfs4_client *clp;
- struct nfs4_stateowner *sop;
+ struct nfs4_openowner *oo;
struct nfs4_delegation *dp;
struct list_head *pos, *next, reaplist;
time_t cutoff = get_seconds() - nfsd4_lease;
@@ -3019,16 +3128,14 @@ nfs4_laundromat(void)
}
test_val = nfsd4_lease;
list_for_each_safe(pos, next, &close_lru) {
- sop = list_entry(pos, struct nfs4_stateowner, so_close_lru);
- if (time_after((unsigned long)sop->so_time, (unsigned long)cutoff)) {
- u = sop->so_time - cutoff;
+ oo = container_of(pos, struct nfs4_openowner, oo_close_lru);
+ if (time_after((unsigned long)oo->oo_time, (unsigned long)cutoff)) {
+ u = oo->oo_time - cutoff;
if (test_val > u)
test_val = u;
break;
}
- dprintk("NFSD: purging unused open stateowner (so_id %d)\n",
- sop->so_id);
- release_openowner(sop);
+ release_openowner(oo);
}
if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT)
clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT;
@@ -3050,30 +3157,17 @@ laundromat_main(struct work_struct *not_used)
queue_delayed_work(laundry_wq, &laundromat_work, t*HZ);
}
-static struct nfs4_stateowner *
-search_close_lru(u32 st_id, int flags)
+static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp)
{
- struct nfs4_stateowner *local = NULL;
-
- if (flags & CLOSE_STATE) {
- list_for_each_entry(local, &close_lru, so_close_lru) {
- if (local->so_id == st_id)
- return local;
- }
- }
- return NULL;
-}
-
-static inline int
-nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp)
-{
- return fhp->fh_dentry->d_inode != stp->st_file->fi_inode;
+ if (fhp->fh_dentry->d_inode != stp->st_file->fi_inode)
+ return nfserr_bad_stateid;
+ return nfs_ok;
}
static int
STALE_STATEID(stateid_t *stateid)
{
- if (stateid->si_boot == boot_time)
+ if (stateid->si_opaque.so_clid.cl_boot == boot_time)
return 0;
dprintk("NFSD: stale stateid " STATEID_FMT "!\n",
STATEID_VAL(stateid));
@@ -3096,7 +3190,7 @@ access_permit_write(unsigned long access_bmap)
}
static
-__be32 nfs4_check_openmode(struct nfs4_stateid *stp, int flags)
+__be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags)
{
__be32 status = nfserr_openmode;
@@ -3139,68 +3233,80 @@ grace_disallows_io(struct inode *inode)
return locks_in_grace() && mandatory_lock(inode);
}
-static int check_stateid_generation(stateid_t *in, stateid_t *ref, int flags)
+/* Returns true iff a is later than b: */
+static bool stateid_generation_after(stateid_t *a, stateid_t *b)
+{
+ return (s32)a->si_generation - (s32)b->si_generation > 0;
+}
+
+static int check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session)
{
/*
* When sessions are used the stateid generation number is ignored
* when it is zero.
*/
- if ((flags & HAS_SESSION) && in->si_generation == 0)
- goto out;
+ if (has_session && in->si_generation == 0)
+ return nfs_ok;
+
+ if (in->si_generation == ref->si_generation)
+ return nfs_ok;
/* If the client sends us a stateid from the future, it's buggy: */
- if (in->si_generation > ref->si_generation)
+ if (stateid_generation_after(in, ref))
return nfserr_bad_stateid;
/*
- * The following, however, can happen. For example, if the
- * client sends an open and some IO at the same time, the open
- * may bump si_generation while the IO is still in flight.
- * Thanks to hard links and renames, the client never knows what
- * file an open will affect. So it could avoid that situation
- * only by serializing all opens and IO from the same open
- * owner. To recover from the old_stateid error, the client
- * will just have to retry the IO:
+ * However, we could see a stateid from the past, even from a
+ * non-buggy client. For example, if the client sends a lock
+ * while some IO is outstanding, the lock may bump si_generation
+ * while the IO is still in flight. The client could avoid that
+ * situation by waiting for responses on all the IO requests,
+ * but better performance may result in retrying IO that
+ * receives an old_stateid error if requests are rarely
+ * reordered in flight:
*/
- if (in->si_generation < ref->si_generation)
- return nfserr_old_stateid;
-out:
- return nfs_ok;
+ return nfserr_old_stateid;
}
-static int is_delegation_stateid(stateid_t *stateid)
+__be32 nfs4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
{
- return stateid->si_fileid == 0;
-}
+ struct nfs4_stid *s;
+ struct nfs4_ol_stateid *ols;
+ __be32 status;
-static int is_open_stateid(struct nfs4_stateid *stateid)
-{
- return stateid->st_openstp == NULL;
+ if (STALE_STATEID(stateid))
+ return nfserr_stale_stateid;
+
+ s = find_stateid(cl, stateid);
+ if (!s)
+ return nfserr_stale_stateid;
+ status = check_stateid_generation(stateid, &s->sc_stateid, 1);
+ if (status)
+ return status;
+ if (!(s->sc_type & (NFS4_OPEN_STID | NFS4_LOCK_STID)))
+ return nfs_ok;
+ ols = openlockstateid(s);
+ if (ols->st_stateowner->so_is_open_owner
+ && !(openowner(ols->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED))
+ return nfserr_bad_stateid;
+ return nfs_ok;
}
-__be32 nfs4_validate_stateid(stateid_t *stateid, int flags)
+static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s)
{
- struct nfs4_stateid *stp = NULL;
- __be32 status = nfserr_stale_stateid;
+ struct nfs4_client *cl;
+ if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
+ return nfserr_bad_stateid;
if (STALE_STATEID(stateid))
- goto out;
-
- status = nfserr_expired;
- stp = search_for_stateid(stateid);
- if (!stp)
- goto out;
- status = nfserr_bad_stateid;
-
- if (!stp->st_stateowner->so_confirmed)
- goto out;
-
- status = check_stateid_generation(stateid, &stp->st_stateid, flags);
- if (status)
- goto out;
+ return nfserr_stale_stateid;
+ cl = find_confirmed_client(&stateid->si_opaque.so_clid);
+ if (!cl)
+ return nfserr_expired;
+ *s = find_stateid_by_type(cl, stateid, typemask);
+ if (!*s)
+ return nfserr_bad_stateid;
+ return nfs_ok;
- status = nfs_ok;
-out:
- return status;
}
/*
@@ -3210,7 +3316,8 @@ __be32
nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
stateid_t *stateid, int flags, struct file **filpp)
{
- struct nfs4_stateid *stp = NULL;
+ struct nfs4_stid *s;
+ struct nfs4_ol_stateid *stp = NULL;
struct nfs4_delegation *dp = NULL;
struct svc_fh *current_fh = &cstate->current_fh;
struct inode *ino = current_fh->fh_dentry->d_inode;
@@ -3222,60 +3329,47 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
if (grace_disallows_io(ino))
return nfserr_grace;
- if (nfsd4_has_session(cstate))
- flags |= HAS_SESSION;
-
if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
return check_special_stateids(current_fh, stateid, flags);
- status = nfserr_stale_stateid;
- if (STALE_STATEID(stateid))
+ status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s);
+ if (status)
+ return status;
+ status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate));
+ if (status)
goto out;
-
- /*
- * We assume that any stateid that has the current boot time,
- * but that we can't find, is expired:
- */
- status = nfserr_expired;
- if (is_delegation_stateid(stateid)) {
- dp = find_delegation_stateid(ino, stateid);
- if (!dp)
- goto out;
- status = check_stateid_generation(stateid, &dp->dl_stateid,
- flags);
- if (status)
- goto out;
+ switch (s->sc_type) {
+ case NFS4_DELEG_STID:
+ dp = delegstateid(s);
status = nfs4_check_delegmode(dp, flags);
if (status)
goto out;
- renew_client(dp->dl_client);
if (filpp) {
*filpp = dp->dl_file->fi_deleg_file;
BUG_ON(!*filpp);
}
- } else { /* open or lock stateid */
- stp = find_stateid(stateid, flags);
- if (!stp)
- goto out;
- status = nfserr_bad_stateid;
- if (nfs4_check_fh(current_fh, stp))
- goto out;
- if (!stp->st_stateowner->so_confirmed)
- goto out;
- status = check_stateid_generation(stateid, &stp->st_stateid,
- flags);
+ break;
+ case NFS4_OPEN_STID:
+ case NFS4_LOCK_STID:
+ stp = openlockstateid(s);
+ status = nfs4_check_fh(current_fh, stp);
if (status)
goto out;
+ if (stp->st_stateowner->so_is_open_owner
+ && !(openowner(stp->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED))
+ goto out;
status = nfs4_check_openmode(stp, flags);
if (status)
goto out;
- renew_client(stp->st_stateowner->so_client);
if (filpp) {
if (flags & RD_STATE)
*filpp = find_readable_file(stp->st_file);
else
*filpp = find_writeable_file(stp->st_file);
}
+ break;
+ default:
+ return nfserr_bad_stateid;
}
status = nfs_ok;
out:
@@ -3283,18 +3377,9 @@ out:
}
static __be32
-nfsd4_free_delegation_stateid(stateid_t *stateid)
+nfsd4_free_lock_stateid(struct nfs4_ol_stateid *stp)
{
- struct nfs4_delegation *dp = search_for_delegation(stateid);
- if (dp)
- return nfserr_locks_held;
- return nfserr_bad_stateid;
-}
-
-static __be32
-nfsd4_free_lock_stateid(struct nfs4_stateid *stp)
-{
- if (check_for_locks(stp->st_file, stp->st_stateowner))
+ if (check_for_locks(stp->st_file, lockowner(stp->st_stateowner)))
return nfserr_locks_held;
release_lock_stateid(stp);
return nfs_ok;
@@ -3307,51 +3392,40 @@ __be32
nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_test_stateid *test_stateid)
{
- test_stateid->ts_has_session = nfsd4_has_session(cstate);
+ /* real work is done during encoding */
return nfs_ok;
}
-/*
- * Free a state id
- */
__be32
nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_free_stateid *free_stateid)
{
stateid_t *stateid = &free_stateid->fr_stateid;
- struct nfs4_stateid *stp;
- __be32 ret;
+ struct nfs4_stid *s;
+ struct nfs4_client *cl = cstate->session->se_client;
+ __be32 ret = nfserr_bad_stateid;
nfs4_lock_state();
- if (is_delegation_stateid(stateid)) {
- ret = nfsd4_free_delegation_stateid(stateid);
- goto out;
- }
-
- stp = search_for_stateid(stateid);
- if (!stp) {
- ret = nfserr_bad_stateid;
+ s = find_stateid(cl, stateid);
+ if (!s)
goto out;
- }
- if (stateid->si_generation != 0) {
- if (stateid->si_generation < stp->st_stateid.si_generation) {
- ret = nfserr_old_stateid;
- goto out;
- }
- if (stateid->si_generation > stp->st_stateid.si_generation) {
- ret = nfserr_bad_stateid;
- goto out;
- }
- }
-
- if (is_open_stateid(stp)) {
+ switch (s->sc_type) {
+ case NFS4_DELEG_STID:
ret = nfserr_locks_held;
goto out;
- } else {
- ret = nfsd4_free_lock_stateid(stp);
- goto out;
+ case NFS4_OPEN_STID:
+ case NFS4_LOCK_STID:
+ ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
+ if (ret)
+ goto out;
+ if (s->sc_type == NFS4_LOCK_STID)
+ ret = nfsd4_free_lock_stateid(openlockstateid(s));
+ else
+ ret = nfserr_locks_held;
+ break;
+ default:
+ ret = nfserr_bad_stateid;
}
-
out:
nfs4_unlock_state();
return ret;
@@ -3364,124 +3438,64 @@ setlkflg (int type)
RD_STATE : WR_STATE;
}
+static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp)
+{
+ struct svc_fh *current_fh = &cstate->current_fh;
+ struct nfs4_stateowner *sop = stp->st_stateowner;
+ __be32 status;
+
+ status = nfsd4_check_seqid(cstate, sop, seqid);
+ if (status)
+ return status;
+ if (stp->st_stid.sc_type == NFS4_CLOSED_STID)
+ /*
+ * "Closed" stateid's exist *only* to return
+ * nfserr_replay_me from the previous step.
+ */
+ return nfserr_bad_stateid;
+ status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
+ if (status)
+ return status;
+ return nfs4_check_fh(current_fh, stp);
+}
+
/*
* Checks for sequence id mutating operations.
*/
static __be32
nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
- stateid_t *stateid, int flags,
- struct nfs4_stateowner **sopp,
- struct nfs4_stateid **stpp, struct nfsd4_lock *lock)
+ stateid_t *stateid, char typemask,
+ struct nfs4_ol_stateid **stpp)
{
- struct nfs4_stateid *stp;
- struct nfs4_stateowner *sop;
- struct svc_fh *current_fh = &cstate->current_fh;
__be32 status;
+ struct nfs4_stid *s;
dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__,
seqid, STATEID_VAL(stateid));
*stpp = NULL;
- *sopp = NULL;
-
- if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) {
- dprintk("NFSD: preprocess_seqid_op: magic stateid!\n");
- return nfserr_bad_stateid;
- }
-
- if (STALE_STATEID(stateid))
- return nfserr_stale_stateid;
-
- if (nfsd4_has_session(cstate))
- flags |= HAS_SESSION;
-
- /*
- * We return BAD_STATEID if filehandle doesn't match stateid,
- * the confirmed flag is incorrecly set, or the generation
- * number is incorrect.
- */
- stp = find_stateid(stateid, flags);
- if (stp == NULL) {
- /*
- * Also, we should make sure this isn't just the result of
- * a replayed close:
- */
- sop = search_close_lru(stateid->si_stateownerid, flags);
- /* It's not stale; let's assume it's expired: */
- if (sop == NULL)
- return nfserr_expired;
- *sopp = sop;
- goto check_replay;
- }
-
- *stpp = stp;
- *sopp = sop = stp->st_stateowner;
-
- if (lock) {
- clientid_t *lockclid = &lock->v.new.clientid;
- struct nfs4_client *clp = sop->so_client;
- int lkflg = 0;
- __be32 status;
-
- lkflg = setlkflg(lock->lk_type);
-
- if (lock->lk_is_new) {
- if (!sop->so_is_open_owner)
- return nfserr_bad_stateid;
- if (!(flags & HAS_SESSION) &&
- !same_clid(&clp->cl_clientid, lockclid))
- return nfserr_bad_stateid;
- /* stp is the open stateid */
- status = nfs4_check_openmode(stp, lkflg);
- if (status)
- return status;
- } else {
- /* stp is the lock stateid */
- status = nfs4_check_openmode(stp->st_openstp, lkflg);
- if (status)
- return status;
- }
- }
+ status = nfsd4_lookup_stateid(stateid, typemask, &s);
+ if (status)
+ return status;
+ *stpp = openlockstateid(s);
+ cstate->replay_owner = (*stpp)->st_stateowner;
- if (nfs4_check_fh(current_fh, stp)) {
- dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
- return nfserr_bad_stateid;
- }
+ return nfs4_seqid_op_checks(cstate, stateid, seqid, *stpp);
+}
- /*
- * We now validate the seqid and stateid generation numbers.
- * For the moment, we ignore the possibility of
- * generation number wraparound.
- */
- if (!(flags & HAS_SESSION) && seqid != sop->so_seqid)
- goto check_replay;
+static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, stateid_t *stateid, struct nfs4_ol_stateid **stpp)
+{
+ __be32 status;
+ struct nfs4_openowner *oo;
- if (sop->so_confirmed && flags & CONFIRM) {
- dprintk("NFSD: preprocess_seqid_op: expected"
- " unconfirmed stateowner!\n");
- return nfserr_bad_stateid;
- }
- if (!sop->so_confirmed && !(flags & CONFIRM)) {
- dprintk("NFSD: preprocess_seqid_op: stateowner not"
- " confirmed yet!\n");
- return nfserr_bad_stateid;
- }
- status = check_stateid_generation(stateid, &stp->st_stateid, flags);
+ status = nfs4_preprocess_seqid_op(cstate, seqid, stateid,
+ NFS4_OPEN_STID, stpp);
if (status)
return status;
- renew_client(sop->so_client);
+ oo = openowner((*stpp)->st_stateowner);
+ if (!(oo->oo_flags & NFS4_OO_CONFIRMED))
+ return nfserr_bad_stateid;
return nfs_ok;
-
-check_replay:
- if (seqid == sop->so_seqid - 1) {
- dprintk("NFSD: preprocess_seqid_op: retransmission?\n");
- /* indicate replay to calling function */
- return nfserr_replay_me;
- }
- dprintk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n",
- sop->so_seqid, seqid);
- *sopp = NULL;
- return nfserr_bad_seqid;
}
__be32
@@ -3489,8 +3503,8 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_open_confirm *oc)
{
__be32 status;
- struct nfs4_stateowner *sop;
- struct nfs4_stateid *stp;
+ struct nfs4_openowner *oo;
+ struct nfs4_ol_stateid *stp;
dprintk("NFSD: nfsd4_open_confirm on file %.*s\n",
(int)cstate->current_fh.fh_dentry->d_name.len,
@@ -3502,38 +3516,52 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
nfs4_lock_state();
- if ((status = nfs4_preprocess_seqid_op(cstate,
+ status = nfs4_preprocess_seqid_op(cstate,
oc->oc_seqid, &oc->oc_req_stateid,
- CONFIRM | OPEN_STATE,
- &oc->oc_stateowner, &stp, NULL)))
- goto out;
-
- sop = oc->oc_stateowner;
- sop->so_confirmed = 1;
- update_stateid(&stp->st_stateid);
- memcpy(&oc->oc_resp_stateid, &stp->st_stateid, sizeof(stateid_t));
+ NFS4_OPEN_STID, &stp);
+ if (status)
+ goto out;
+ oo = openowner(stp->st_stateowner);
+ status = nfserr_bad_stateid;
+ if (oo->oo_flags & NFS4_OO_CONFIRMED)
+ goto out;
+ oo->oo_flags |= NFS4_OO_CONFIRMED;
+ update_stateid(&stp->st_stid.sc_stateid);
+ memcpy(&oc->oc_resp_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n",
- __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stateid));
+ __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid));
- nfsd4_create_clid_dir(sop->so_client);
+ nfsd4_create_clid_dir(oo->oo_owner.so_client);
+ status = nfs_ok;
out:
- if (oc->oc_stateowner) {
- nfs4_get_stateowner(oc->oc_stateowner);
- cstate->replay_owner = oc->oc_stateowner;
- }
- nfs4_unlock_state();
+ if (!cstate->replay_owner)
+ nfs4_unlock_state();
return status;
}
-static inline void nfs4_file_downgrade(struct nfs4_stateid *stp, unsigned int to_access)
+static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access)
{
- int i;
+ if (!test_bit(access, &stp->st_access_bmap))
+ return;
+ nfs4_file_put_access(stp->st_file, nfs4_access_to_omode(access));
+ __clear_bit(access, &stp->st_access_bmap);
+}
- for (i = 1; i < 4; i++) {
- if (test_bit(i, &stp->st_access_bmap) && !(i & to_access)) {
- nfs4_file_put_access(stp->st_file, i);
- __clear_bit(i, &stp->st_access_bmap);
- }
+static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access)
+{
+ switch (to_access) {
+ case NFS4_SHARE_ACCESS_READ:
+ nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE);
+ nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH);
+ break;
+ case NFS4_SHARE_ACCESS_WRITE:
+ nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ);
+ nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH);
+ break;
+ case NFS4_SHARE_ACCESS_BOTH:
+ break;
+ default:
+ BUG();
}
}
@@ -3553,24 +3581,20 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
struct nfsd4_open_downgrade *od)
{
__be32 status;
- struct nfs4_stateid *stp;
+ struct nfs4_ol_stateid *stp;
dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n",
(int)cstate->current_fh.fh_dentry->d_name.len,
cstate->current_fh.fh_dentry->d_name.name);
- if (!access_valid(od->od_share_access, cstate->minorversion)
- || !deny_valid(od->od_share_deny))
- return nfserr_inval;
+ /* We don't yet support WANT bits: */
+ od->od_share_access &= NFS4_SHARE_ACCESS_MASK;
nfs4_lock_state();
- if ((status = nfs4_preprocess_seqid_op(cstate,
- od->od_seqid,
- &od->od_stateid,
- OPEN_STATE,
- &od->od_stateowner, &stp, NULL)))
+ status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid,
+ &od->od_stateid, &stp);
+ if (status)
goto out;
-
status = nfserr_inval;
if (!test_bit(od->od_share_access, &stp->st_access_bmap)) {
dprintk("NFSD:access not a subset current bitmap: 0x%lx, input access=%08x\n",
@@ -3582,22 +3606,45 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
stp->st_deny_bmap, od->od_share_deny);
goto out;
}
- nfs4_file_downgrade(stp, od->od_share_access);
+ nfs4_stateid_downgrade(stp, od->od_share_access);
reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap);
- update_stateid(&stp->st_stateid);
- memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t));
+ update_stateid(&stp->st_stid.sc_stateid);
+ memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
status = nfs_ok;
out:
- if (od->od_stateowner) {
- nfs4_get_stateowner(od->od_stateowner);
- cstate->replay_owner = od->od_stateowner;
- }
- nfs4_unlock_state();
+ if (!cstate->replay_owner)
+ nfs4_unlock_state();
return status;
}
+void nfsd4_purge_closed_stateid(struct nfs4_stateowner *so)
+{
+ struct nfs4_openowner *oo;
+ struct nfs4_ol_stateid *s;
+
+ if (!so->so_is_open_owner)
+ return;
+ oo = openowner(so);
+ s = oo->oo_last_closed_stid;
+ if (!s)
+ return;
+ if (!(oo->oo_flags & NFS4_OO_PURGE_CLOSE)) {
+ /* Release the last_closed_stid on the next seqid bump: */
+ oo->oo_flags |= NFS4_OO_PURGE_CLOSE;
+ return;
+ }
+ oo->oo_flags &= ~NFS4_OO_PURGE_CLOSE;
+ release_last_closed_stateid(oo);
+}
+
+static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
+{
+ unhash_open_stateid(s);
+ s->st_stid.sc_type = NFS4_CLOSED_STID;
+}
+
/*
* nfs4_unlock_state() called after encode
*/
@@ -3606,39 +3653,37 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_close *close)
{
__be32 status;
- struct nfs4_stateid *stp;
+ struct nfs4_openowner *oo;
+ struct nfs4_ol_stateid *stp;
dprintk("NFSD: nfsd4_close on file %.*s\n",
(int)cstate->current_fh.fh_dentry->d_name.len,
cstate->current_fh.fh_dentry->d_name.name);
nfs4_lock_state();
- /* check close_lru for replay */
- if ((status = nfs4_preprocess_seqid_op(cstate,
- close->cl_seqid,
- &close->cl_stateid,
- OPEN_STATE | CLOSE_STATE,
- &close->cl_stateowner, &stp, NULL)))
+ status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid,
+ &close->cl_stateid,
+ NFS4_OPEN_STID|NFS4_CLOSED_STID,
+ &stp);
+ if (status)
goto out;
+ oo = openowner(stp->st_stateowner);
status = nfs_ok;
- update_stateid(&stp->st_stateid);
- memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t));
+ update_stateid(&stp->st_stid.sc_stateid);
+ memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
- /* release_stateid() calls nfsd_close() if needed */
- release_open_stateid(stp);
+ nfsd4_close_open_stateid(stp);
+ oo->oo_last_closed_stid = stp;
/* place unused nfs4_stateowners on so_close_lru list to be
* released by the laundromat service after the lease period
* to enable us to handle CLOSE replay
*/
- if (list_empty(&close->cl_stateowner->so_stateids))
- move_to_close_lru(close->cl_stateowner);
+ if (list_empty(&oo->oo_owner.so_stateids))
+ move_to_close_lru(oo);
out:
- if (close->cl_stateowner) {
- nfs4_get_stateowner(close->cl_stateowner);
- cstate->replay_owner = close->cl_stateowner;
- }
- nfs4_unlock_state();
+ if (!cstate->replay_owner)
+ nfs4_unlock_state();
return status;
}
@@ -3648,34 +3693,22 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
{
struct nfs4_delegation *dp;
stateid_t *stateid = &dr->dr_stateid;
+ struct nfs4_stid *s;
struct inode *inode;
__be32 status;
- int flags = 0;
if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
return status;
inode = cstate->current_fh.fh_dentry->d_inode;
- if (nfsd4_has_session(cstate))
- flags |= HAS_SESSION;
nfs4_lock_state();
- status = nfserr_bad_stateid;
- if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
- goto out;
- status = nfserr_stale_stateid;
- if (STALE_STATEID(stateid))
- goto out;
- status = nfserr_bad_stateid;
- if (!is_delegation_stateid(stateid))
- goto out;
- status = nfserr_expired;
- dp = find_delegation_stateid(inode, stateid);
- if (!dp)
+ status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s);
+ if (status)
goto out;
- status = check_stateid_generation(stateid, &dp->dl_stateid, flags);
+ dp = delegstateid(s);
+ status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate));
if (status)
goto out;
- renew_client(dp->dl_client);
unhash_delegation(dp);
out:
@@ -3713,9 +3746,6 @@ last_byte_offset(u64 start, u64 len)
return end > start ? end - 1: NFS4_MAX_UINT64;
}
-#define lockownerid_hashval(id) \
- ((id) & LOCK_HASH_MASK)
-
static inline unsigned int
lock_ownerstr_hashval(struct inode *inode, u32 cl_id,
struct xdr_netobj *ownername)
@@ -3725,101 +3755,7 @@ lock_ownerstr_hashval(struct inode *inode, u32 cl_id,
& LOCK_HASH_MASK;
}
-static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE];
static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE];
-static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE];
-
-static int
-same_stateid(stateid_t *id_one, stateid_t *id_two)
-{
- if (id_one->si_stateownerid != id_two->si_stateownerid)
- return 0;
- return id_one->si_fileid == id_two->si_fileid;
-}
-
-static struct nfs4_stateid *
-find_stateid(stateid_t *stid, int flags)
-{
- struct nfs4_stateid *local;
- u32 st_id = stid->si_stateownerid;
- u32 f_id = stid->si_fileid;
- unsigned int hashval;
-
- dprintk("NFSD: find_stateid flags 0x%x\n",flags);
- if (flags & (LOCK_STATE | RD_STATE | WR_STATE)) {
- hashval = stateid_hashval(st_id, f_id);
- list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) {
- if ((local->st_stateid.si_stateownerid == st_id) &&
- (local->st_stateid.si_fileid == f_id))
- return local;
- }
- }
-
- if (flags & (OPEN_STATE | RD_STATE | WR_STATE)) {
- hashval = stateid_hashval(st_id, f_id);
- list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) {
- if ((local->st_stateid.si_stateownerid == st_id) &&
- (local->st_stateid.si_fileid == f_id))
- return local;
- }
- }
- return NULL;
-}
-
-static struct nfs4_stateid *
-search_for_stateid(stateid_t *stid)
-{
- struct nfs4_stateid *local;
- unsigned int hashval = stateid_hashval(stid->si_stateownerid, stid->si_fileid);
-
- list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) {
- if (same_stateid(&local->st_stateid, stid))
- return local;
- }
-
- list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) {
- if (same_stateid(&local->st_stateid, stid))
- return local;
- }
- return NULL;
-}
-
-static struct nfs4_delegation *
-search_for_delegation(stateid_t *stid)
-{
- struct nfs4_file *fp;
- struct nfs4_delegation *dp;
- struct list_head *pos;
- int i;
-
- for (i = 0; i < FILE_HASH_SIZE; i++) {
- list_for_each_entry(fp, &file_hashtbl[i], fi_hash) {
- list_for_each(pos, &fp->fi_delegations) {
- dp = list_entry(pos, struct nfs4_delegation, dl_perfile);
- if (same_stateid(&dp->dl_stateid, stid))
- return dp;
- }
- }
- }
- return NULL;
-}
-
-static struct nfs4_delegation *
-find_delegation_stateid(struct inode *ino, stateid_t *stid)
-{
- struct nfs4_file *fp;
- struct nfs4_delegation *dl;
-
- dprintk("NFSD: %s: stateid=" STATEID_FMT "\n", __func__,
- STATEID_VAL(stid));
-
- fp = find_file(ino);
- if (!fp)
- return NULL;
- dl = find_delegation_file(fp, stid);
- put_nfs4_file(fp);
- return dl;
-}
/*
* TODO: Linux file offsets are _signed_ 64-bit quantities, which means that
@@ -3846,15 +3782,21 @@ static const struct lock_manager_operations nfsd_posix_mng_ops = {
static inline void
nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
{
- struct nfs4_stateowner *sop;
+ struct nfs4_lockowner *lo;
if (fl->fl_lmops == &nfsd_posix_mng_ops) {
- sop = (struct nfs4_stateowner *) fl->fl_owner;
- kref_get(&sop->so_ref);
- deny->ld_sop = sop;
- deny->ld_clientid = sop->so_client->cl_clientid;
+ lo = (struct nfs4_lockowner *) fl->fl_owner;
+ deny->ld_owner.data = kmemdup(lo->lo_owner.so_owner.data,
+ lo->lo_owner.so_owner.len, GFP_KERNEL);
+ if (!deny->ld_owner.data)
+ /* We just don't care that much */
+ goto nevermind;
+ deny->ld_owner.len = lo->lo_owner.so_owner.len;
+ deny->ld_clientid = lo->lo_owner.so_client->cl_clientid;
} else {
- deny->ld_sop = NULL;
+nevermind:
+ deny->ld_owner.len = 0;
+ deny->ld_owner.data = NULL;
deny->ld_clientid.cl_boot = 0;
deny->ld_clientid.cl_id = 0;
}
@@ -3867,8 +3809,8 @@ nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
deny->ld_type = NFS4_WRITE_LT;
}
-static struct nfs4_stateowner *
-find_lockstateowner_str(struct inode *inode, clientid_t *clid,
+static struct nfs4_lockowner *
+find_lockowner_str(struct inode *inode, clientid_t *clid,
struct xdr_netobj *owner)
{
unsigned int hashval = lock_ownerstr_hashval(inode, clid->cl_id, owner);
@@ -3876,11 +3818,17 @@ find_lockstateowner_str(struct inode *inode, clientid_t *clid,
list_for_each_entry(op, &lock_ownerstr_hashtbl[hashval], so_strhash) {
if (same_owner_str(op, owner, clid))
- return op;
+ return lockowner(op);
}
return NULL;
}
+static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp)
+{
+ list_add(&lo->lo_owner.so_strhash, &lock_ownerstr_hashtbl[strhashval]);
+ list_add(&lo->lo_perstateid, &open_stp->st_lockowners);
+}
+
/*
* Alloc a lock owner structure.
* Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has
@@ -3889,67 +3837,40 @@ find_lockstateowner_str(struct inode *inode, clientid_t *clid,
* strhashval = lock_ownerstr_hashval
*/
-static struct nfs4_stateowner *
-alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfs4_stateid *open_stp, struct nfsd4_lock *lock) {
- struct nfs4_stateowner *sop;
- struct nfs4_replay *rp;
- unsigned int idhashval;
+static struct nfs4_lockowner *
+alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp, struct nfsd4_lock *lock) {
+ struct nfs4_lockowner *lo;
- if (!(sop = alloc_stateowner(&lock->lk_new_owner)))
+ lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp);
+ if (!lo)
return NULL;
- idhashval = lockownerid_hashval(current_ownerid);
- INIT_LIST_HEAD(&sop->so_idhash);
- INIT_LIST_HEAD(&sop->so_strhash);
- INIT_LIST_HEAD(&sop->so_perclient);
- INIT_LIST_HEAD(&sop->so_stateids);
- INIT_LIST_HEAD(&sop->so_perstateid);
- INIT_LIST_HEAD(&sop->so_close_lru); /* not used */
- sop->so_time = 0;
- list_add(&sop->so_idhash, &lock_ownerid_hashtbl[idhashval]);
- list_add(&sop->so_strhash, &lock_ownerstr_hashtbl[strhashval]);
- list_add(&sop->so_perstateid, &open_stp->st_lockowners);
- sop->so_is_open_owner = 0;
- sop->so_id = current_ownerid++;
- sop->so_client = clp;
+ INIT_LIST_HEAD(&lo->lo_owner.so_stateids);
+ lo->lo_owner.so_is_open_owner = 0;
/* It is the openowner seqid that will be incremented in encode in the
* case of new lockowners; so increment the lock seqid manually: */
- sop->so_seqid = lock->lk_new_lock_seqid + 1;
- sop->so_confirmed = 1;
- rp = &sop->so_replay;
- rp->rp_status = nfserr_serverfault;
- rp->rp_buflen = 0;
- rp->rp_buf = rp->rp_ibuf;
- return sop;
+ lo->lo_owner.so_seqid = lock->lk_new_lock_seqid + 1;
+ hash_lockowner(lo, strhashval, clp, open_stp);
+ return lo;
}
-static struct nfs4_stateid *
-alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struct nfs4_stateid *open_stp)
+static struct nfs4_ol_stateid *
+alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct nfs4_ol_stateid *open_stp)
{
- struct nfs4_stateid *stp;
- unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id);
+ struct nfs4_ol_stateid *stp;
+ struct nfs4_client *clp = lo->lo_owner.so_client;
- stp = nfs4_alloc_stateid();
+ stp = nfs4_alloc_stateid(clp);
if (stp == NULL)
- goto out;
- INIT_LIST_HEAD(&stp->st_hash);
- INIT_LIST_HEAD(&stp->st_perfile);
- INIT_LIST_HEAD(&stp->st_perstateowner);
- INIT_LIST_HEAD(&stp->st_lockowners); /* not used */
- list_add(&stp->st_hash, &lockstateid_hashtbl[hashval]);
+ return NULL;
+ init_stid(&stp->st_stid, clp, NFS4_LOCK_STID);
list_add(&stp->st_perfile, &fp->fi_stateids);
- list_add(&stp->st_perstateowner, &sop->so_stateids);
- stp->st_stateowner = sop;
+ list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
+ stp->st_stateowner = &lo->lo_owner;
get_nfs4_file(fp);
stp->st_file = fp;
- stp->st_stateid.si_boot = boot_time;
- stp->st_stateid.si_stateownerid = sop->so_id;
- stp->st_stateid.si_fileid = fp->fi_id;
- stp->st_stateid.si_generation = 0;
stp->st_access_bmap = 0;
stp->st_deny_bmap = open_stp->st_deny_bmap;
stp->st_openstp = open_stp;
-
-out:
return stp;
}
@@ -3960,7 +3881,7 @@ check_lock_length(u64 offset, u64 length)
LOFF_OVERFLOW(offset, length)));
}
-static void get_lock_access(struct nfs4_stateid *lock_stp, u32 access)
+static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access)
{
struct nfs4_file *fp = lock_stp->st_file;
int oflag = nfs4_access_to_omode(access);
@@ -3978,15 +3899,16 @@ __be32
nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_lock *lock)
{
- struct nfs4_stateowner *open_sop = NULL;
- struct nfs4_stateowner *lock_sop = NULL;
- struct nfs4_stateid *lock_stp;
+ struct nfs4_openowner *open_sop = NULL;
+ struct nfs4_lockowner *lock_sop = NULL;
+ struct nfs4_ol_stateid *lock_stp;
struct nfs4_file *fp;
struct file *filp = NULL;
struct file_lock file_lock;
struct file_lock conflock;
__be32 status = 0;
unsigned int strhashval;
+ int lkflg;
int err;
dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
@@ -4010,7 +3932,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
* Use open owner and open stateid to create lock owner and
* lock stateid.
*/
- struct nfs4_stateid *open_stp = NULL;
+ struct nfs4_ol_stateid *open_stp = NULL;
status = nfserr_stale_clientid;
if (!nfsd4_has_session(cstate) &&
@@ -4018,26 +3940,29 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out;
/* validate and update open stateid and open seqid */
- status = nfs4_preprocess_seqid_op(cstate,
+ status = nfs4_preprocess_confirmed_seqid_op(cstate,
lock->lk_new_open_seqid,
&lock->lk_new_open_stateid,
- OPEN_STATE,
- &lock->lk_replay_owner, &open_stp,
- lock);
+ &open_stp);
if (status)
goto out;
- open_sop = lock->lk_replay_owner;
+ open_sop = openowner(open_stp->st_stateowner);
+ status = nfserr_bad_stateid;
+ if (!nfsd4_has_session(cstate) &&
+ !same_clid(&open_sop->oo_owner.so_client->cl_clientid,
+ &lock->v.new.clientid))
+ goto out;
/* create lockowner and lock stateid */
fp = open_stp->st_file;
- strhashval = lock_ownerstr_hashval(fp->fi_inode,
- open_sop->so_client->cl_clientid.cl_id,
+ strhashval = lock_ownerstr_hashval(fp->fi_inode,
+ open_sop->oo_owner.so_client->cl_clientid.cl_id,
&lock->v.new.owner);
/* XXX: Do we need to check for duplicate stateowners on
* the same file, or should they just be allowed (and
* create new stateids)? */
- status = nfserr_resource;
+ status = nfserr_jukebox;
lock_sop = alloc_init_lock_stateowner(strhashval,
- open_sop->so_client, open_stp, lock);
+ open_sop->oo_owner.so_client, open_stp, lock);
if (lock_sop == NULL)
goto out;
lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp);
@@ -4046,16 +3971,20 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
} else {
/* lock (lock owner + lock stateid) already exists */
status = nfs4_preprocess_seqid_op(cstate,
- lock->lk_old_lock_seqid,
- &lock->lk_old_lock_stateid,
- LOCK_STATE,
- &lock->lk_replay_owner, &lock_stp, lock);
+ lock->lk_old_lock_seqid,
+ &lock->lk_old_lock_stateid,
+ NFS4_LOCK_STID, &lock_stp);
if (status)
goto out;
- lock_sop = lock->lk_replay_owner;
+ lock_sop = lockowner(lock_stp->st_stateowner);
fp = lock_stp->st_file;
}
- /* lock->lk_replay_owner and lock_stp have been created or found */
+ /* lock_sop and lock_stp have been created or found */
+
+ lkflg = setlkflg(lock->lk_type);
+ status = nfs4_check_openmode(lock_stp, lkflg);
+ if (status)
+ goto out;
status = nfserr_grace;
if (locks_in_grace() && !lock->lk_reclaim)
@@ -4106,8 +4035,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
err = vfs_lock_file(filp, F_SETLK, &file_lock, &conflock);
switch (-err) {
case 0: /* success! */
- update_stateid(&lock_stp->st_stateid);
- memcpy(&lock->lk_resp_stateid, &lock_stp->st_stateid,
+ update_stateid(&lock_stp->st_stid.sc_stateid);
+ memcpy(&lock->lk_resp_stateid, &lock_stp->st_stid.sc_stateid,
sizeof(stateid_t));
status = 0;
break;
@@ -4119,19 +4048,16 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
case (EDEADLK):
status = nfserr_deadlock;
break;
- default:
+ default:
dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err);
- status = nfserr_resource;
+ status = nfserrno(err);
break;
}
out:
if (status && lock->lk_is_new && lock_sop)
release_lockowner(lock_sop);
- if (lock->lk_replay_owner) {
- nfs4_get_stateowner(lock->lk_replay_owner);
- cstate->replay_owner = lock->lk_replay_owner;
- }
- nfs4_unlock_state();
+ if (!cstate->replay_owner)
+ nfs4_unlock_state();
return status;
}
@@ -4163,6 +4089,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
{
struct inode *inode;
struct file_lock file_lock;
+ struct nfs4_lockowner *lo;
int error;
__be32 status;
@@ -4172,19 +4099,14 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
if (check_lock_length(lockt->lt_offset, lockt->lt_length))
return nfserr_inval;
- lockt->lt_stateowner = NULL;
nfs4_lock_state();
status = nfserr_stale_clientid;
if (!nfsd4_has_session(cstate) && STALE_CLIENTID(&lockt->lt_clientid))
goto out;
- if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) {
- dprintk("NFSD: nfsd4_lockt: fh_verify() failed!\n");
- if (status == nfserr_symlink)
- status = nfserr_inval;
+ if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
goto out;
- }
inode = cstate->current_fh.fh_dentry->d_inode;
locks_init_lock(&file_lock);
@@ -4203,10 +4125,9 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out;
}
- lockt->lt_stateowner = find_lockstateowner_str(inode,
- &lockt->lt_clientid, &lockt->lt_owner);
- if (lockt->lt_stateowner)
- file_lock.fl_owner = (fl_owner_t)lockt->lt_stateowner;
+ lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner);
+ if (lo)
+ file_lock.fl_owner = (fl_owner_t)lo;
file_lock.fl_pid = current->tgid;
file_lock.fl_flags = FL_POSIX;
@@ -4234,7 +4155,7 @@ __be32
nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_locku *locku)
{
- struct nfs4_stateid *stp;
+ struct nfs4_ol_stateid *stp;
struct file *filp = NULL;
struct file_lock file_lock;
__be32 status;
@@ -4249,13 +4170,10 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
nfs4_lock_state();
- if ((status = nfs4_preprocess_seqid_op(cstate,
- locku->lu_seqid,
- &locku->lu_stateid,
- LOCK_STATE,
- &locku->lu_stateowner, &stp, NULL)))
+ status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid,
+ &locku->lu_stateid, NFS4_LOCK_STID, &stp);
+ if (status)
goto out;
-
filp = find_any_file(stp->st_file);
if (!filp) {
status = nfserr_lock_range;
@@ -4264,7 +4182,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
BUG_ON(!filp);
locks_init_lock(&file_lock);
file_lock.fl_type = F_UNLCK;
- file_lock.fl_owner = (fl_owner_t) locku->lu_stateowner;
+ file_lock.fl_owner = (fl_owner_t)lockowner(stp->st_stateowner);
file_lock.fl_pid = current->tgid;
file_lock.fl_file = filp;
file_lock.fl_flags = FL_POSIX;
@@ -4285,15 +4203,12 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
/*
* OK, unlock succeeded; the only thing left to do is update the stateid.
*/
- update_stateid(&stp->st_stateid);
- memcpy(&locku->lu_stateid, &stp->st_stateid, sizeof(stateid_t));
+ update_stateid(&stp->st_stid.sc_stateid);
+ memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
out:
- if (locku->lu_stateowner) {
- nfs4_get_stateowner(locku->lu_stateowner);
- cstate->replay_owner = locku->lu_stateowner;
- }
- nfs4_unlock_state();
+ if (!cstate->replay_owner)
+ nfs4_unlock_state();
return status;
out_nfserr:
@@ -4307,7 +4222,7 @@ out_nfserr:
* 0: no locks held by lockowner
*/
static int
-check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner)
+check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner)
{
struct file_lock **flpp;
struct inode *inode = filp->fi_inode;
@@ -4332,7 +4247,8 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
{
clientid_t *clid = &rlockowner->rl_clientid;
struct nfs4_stateowner *sop;
- struct nfs4_stateid *stp;
+ struct nfs4_lockowner *lo;
+ struct nfs4_ol_stateid *stp;
struct xdr_netobj *owner = &rlockowner->rl_owner;
struct list_head matches;
int i;
@@ -4356,16 +4272,15 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
* data structures. */
INIT_LIST_HEAD(&matches);
for (i = 0; i < LOCK_HASH_SIZE; i++) {
- list_for_each_entry(sop, &lock_ownerid_hashtbl[i], so_idhash) {
+ list_for_each_entry(sop, &lock_ownerstr_hashtbl[i], so_strhash) {
if (!same_owner_str(sop, owner, clid))
continue;
list_for_each_entry(stp, &sop->so_stateids,
st_perstateowner) {
- if (check_for_locks(stp->st_file, sop))
+ lo = lockowner(sop);
+ if (check_for_locks(stp->st_file, lo))
goto out;
- /* Note: so_perclient unused for lockowners,
- * so it's OK to fool with here. */
- list_add(&sop->so_perclient, &matches);
+ list_add(&lo->lo_list, &matches);
}
}
}
@@ -4374,12 +4289,12 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
* have been checked. */
status = nfs_ok;
while (!list_empty(&matches)) {
- sop = list_entry(matches.next, struct nfs4_stateowner,
- so_perclient);
+ lo = list_entry(matches.next, struct nfs4_lockowner,
+ lo_list);
/* unhash_stateowner deletes so_perclient only
* for openowners. */
- list_del(&sop->so_perclient);
- release_lockowner(sop);
+ list_del(&lo->lo_list);
+ release_lockowner(lo);
}
out:
nfs4_unlock_state();
@@ -4501,16 +4416,10 @@ nfs4_state_init(void)
for (i = 0; i < FILE_HASH_SIZE; i++) {
INIT_LIST_HEAD(&file_hashtbl[i]);
}
- for (i = 0; i < OWNER_HASH_SIZE; i++) {
- INIT_LIST_HEAD(&ownerstr_hashtbl[i]);
- INIT_LIST_HEAD(&ownerid_hashtbl[i]);
- }
- for (i = 0; i < STATEID_HASH_SIZE; i++) {
- INIT_LIST_HEAD(&stateid_hashtbl[i]);
- INIT_LIST_HEAD(&lockstateid_hashtbl[i]);
+ for (i = 0; i < OPEN_OWNER_HASH_SIZE; i++) {
+ INIT_LIST_HEAD(&open_ownerstr_hashtbl[i]);
}
for (i = 0; i < LOCK_HASH_SIZE; i++) {
- INIT_LIST_HEAD(&lock_ownerid_hashtbl[i]);
INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]);
}
memset(&onestateid, ~0, sizeof(stateid_t));
@@ -4527,7 +4436,7 @@ nfsd4_load_reboot_recovery_data(void)
int status;
nfs4_lock_state();
- nfsd4_init_recdir(user_recovery_dirname);
+ nfsd4_init_recdir();
status = nfsd4_recdir_load();
nfs4_unlock_state();
if (status)
@@ -4636,40 +4545,3 @@ nfs4_state_shutdown(void)
nfs4_unlock_state();
nfsd4_destroy_callback_queue();
}
-
-/*
- * user_recovery_dirname is protected by the nfsd_mutex since it's only
- * accessed when nfsd is starting.
- */
-static void
-nfs4_set_recdir(char *recdir)
-{
- strcpy(user_recovery_dirname, recdir);
-}
-
-/*
- * Change the NFSv4 recovery directory to recdir.
- */
-int
-nfs4_reset_recoverydir(char *recdir)
-{
- int status;
- struct path path;
-
- status = kern_path(recdir, LOOKUP_FOLLOW, &path);
- if (status)
- return status;
- status = -ENOTDIR;
- if (S_ISDIR(path.dentry->d_inode->i_mode)) {
- nfs4_set_recdir(recdir);
- status = 0;
- }
- path_put(&path);
- return status;
-}
-
-char *
-nfs4_recoverydir(void)
-{
- return user_recovery_dirname;
-}
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index c8bf405d19de..66d095d7955e 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -456,7 +456,6 @@ nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
{
DECODE_HEAD;
- close->cl_stateowner = NULL;
READ_BUF(4);
READ32(close->cl_seqid);
return nfsd4_decode_stateid(argp, &close->cl_stateid);
@@ -551,7 +550,6 @@ nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock)
{
DECODE_HEAD;
- lock->lk_replay_owner = NULL;
/*
* type, reclaim(boolean), offset, length, new_lock_owner(boolean)
*/
@@ -611,7 +609,6 @@ nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku)
{
DECODE_HEAD;
- locku->lu_stateowner = NULL;
READ_BUF(8);
READ32(locku->lu_type);
if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT))
@@ -642,6 +639,83 @@ nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup
DECODE_TAIL;
}
+static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *x)
+{
+ __be32 *p;
+ u32 w;
+
+ READ_BUF(4);
+ READ32(w);
+ *x = w;
+ switch (w & NFS4_SHARE_ACCESS_MASK) {
+ case NFS4_SHARE_ACCESS_READ:
+ case NFS4_SHARE_ACCESS_WRITE:
+ case NFS4_SHARE_ACCESS_BOTH:
+ break;
+ default:
+ return nfserr_bad_xdr;
+ }
+ w &= !NFS4_SHARE_ACCESS_MASK;
+ if (!w)
+ return nfs_ok;
+ if (!argp->minorversion)
+ return nfserr_bad_xdr;
+ switch (w & NFS4_SHARE_WANT_MASK) {
+ case NFS4_SHARE_WANT_NO_PREFERENCE:
+ case NFS4_SHARE_WANT_READ_DELEG:
+ case NFS4_SHARE_WANT_WRITE_DELEG:
+ case NFS4_SHARE_WANT_ANY_DELEG:
+ case NFS4_SHARE_WANT_NO_DELEG:
+ case NFS4_SHARE_WANT_CANCEL:
+ break;
+ default:
+ return nfserr_bad_xdr;
+ }
+ w &= ~NFS4_SHARE_WANT_MASK;
+ if (!w)
+ return nfs_ok;
+ switch (w) {
+ case NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL:
+ case NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED:
+ case (NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL |
+ NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED):
+ return nfs_ok;
+ }
+xdr_error:
+ return nfserr_bad_xdr;
+}
+
+static __be32 nfsd4_decode_share_deny(struct nfsd4_compoundargs *argp, u32 *x)
+{
+ __be32 *p;
+
+ READ_BUF(4);
+ READ32(*x);
+ /* Note: unlinke access bits, deny bits may be zero. */
+ if (*x & ~NFS4_SHARE_DENY_BOTH)
+ return nfserr_bad_xdr;
+ return nfs_ok;
+xdr_error:
+ return nfserr_bad_xdr;
+}
+
+static __be32 nfsd4_decode_opaque(struct nfsd4_compoundargs *argp, struct xdr_netobj *o)
+{
+ __be32 *p;
+
+ READ_BUF(4);
+ READ32(o->len);
+
+ if (o->len == 0 || o->len > NFS4_OPAQUE_LIMIT)
+ return nfserr_bad_xdr;
+
+ READ_BUF(o->len);
+ SAVEMEM(o->data, o->len);
+ return nfs_ok;
+xdr_error:
+ return nfserr_bad_xdr;
+}
+
static __be32
nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
{
@@ -649,19 +723,23 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
memset(open->op_bmval, 0, sizeof(open->op_bmval));
open->op_iattr.ia_valid = 0;
- open->op_stateowner = NULL;
+ open->op_openowner = NULL;
/* seqid, share_access, share_deny, clientid, ownerlen */
- READ_BUF(16 + sizeof(clientid_t));
+ READ_BUF(4);
READ32(open->op_seqid);
- READ32(open->op_share_access);
- READ32(open->op_share_deny);
+ status = nfsd4_decode_share_access(argp, &open->op_share_access);
+ if (status)
+ goto xdr_error;
+ status = nfsd4_decode_share_deny(argp, &open->op_share_deny);
+ if (status)
+ goto xdr_error;
+ READ_BUF(sizeof(clientid_t));
COPYMEM(&open->op_clientid, sizeof(clientid_t));
- READ32(open->op_owner.len);
-
- /* owner, open_flag */
- READ_BUF(open->op_owner.len + 4);
- SAVEMEM(open->op_owner.data, open->op_owner.len);
+ status = nfsd4_decode_opaque(argp, &open->op_owner);
+ if (status)
+ goto xdr_error;
+ READ_BUF(4);
READ32(open->op_create);
switch (open->op_create) {
case NFS4_OPEN_NOCREATE:
@@ -727,6 +805,19 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
if ((status = check_filename(open->op_fname.data, open->op_fname.len, nfserr_inval)))
return status;
break;
+ case NFS4_OPEN_CLAIM_FH:
+ case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
+ if (argp->minorversion < 1)
+ goto xdr_error;
+ /* void */
+ break;
+ case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
+ if (argp->minorversion < 1)
+ goto xdr_error;
+ status = nfsd4_decode_stateid(argp, &open->op_delegate_stateid);
+ if (status)
+ return status;
+ break;
default:
goto xdr_error;
}
@@ -739,7 +830,6 @@ nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_con
{
DECODE_HEAD;
- open_conf->oc_stateowner = NULL;
status = nfsd4_decode_stateid(argp, &open_conf->oc_req_stateid);
if (status)
return status;
@@ -754,15 +844,17 @@ nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_d
{
DECODE_HEAD;
- open_down->od_stateowner = NULL;
status = nfsd4_decode_stateid(argp, &open_down->od_stateid);
if (status)
return status;
- READ_BUF(12);
+ READ_BUF(4);
READ32(open_down->od_seqid);
- READ32(open_down->od_share_access);
- READ32(open_down->od_share_deny);
-
+ status = nfsd4_decode_share_access(argp, &open_down->od_share_access);
+ if (status)
+ return status;
+ status = nfsd4_decode_share_deny(argp, &open_down->od_share_deny);
+ if (status)
+ return status;
DECODE_TAIL;
}
@@ -903,12 +995,13 @@ nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclient
{
DECODE_HEAD;
- READ_BUF(12);
+ READ_BUF(8);
COPYMEM(setclientid->se_verf.data, 8);
- READ32(setclientid->se_namelen);
- READ_BUF(setclientid->se_namelen + 8);
- SAVEMEM(setclientid->se_name, setclientid->se_namelen);
+ status = nfsd4_decode_opaque(argp, &setclientid->se_name);
+ if (status)
+ return nfserr_bad_xdr;
+ READ_BUF(8);
READ32(setclientid->se_callback_prog);
READ32(setclientid->se_callback_netid_len);
@@ -1051,11 +1144,9 @@ nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp,
READ_BUF(NFS4_VERIFIER_SIZE);
COPYMEM(exid->verifier.data, NFS4_VERIFIER_SIZE);
- READ_BUF(4);
- READ32(exid->clname.len);
-
- READ_BUF(exid->clname.len);
- SAVEMEM(exid->clname.data, exid->clname.len);
+ status = nfsd4_decode_opaque(argp, &exid->clname);
+ if (status)
+ return nfserr_bad_xdr;
READ_BUF(4);
READ32(exid->flags);
@@ -1326,6 +1417,16 @@ xdr_error:
goto out;
}
+static __be32 nfsd4_decode_destroy_clientid(struct nfsd4_compoundargs *argp, struct nfsd4_destroy_clientid *dc)
+{
+ DECODE_HEAD;
+
+ READ_BUF(8);
+ COPYMEM(&dc->clientid, 8);
+
+ DECODE_TAIL;
+}
+
static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, struct nfsd4_reclaim_complete *rc)
{
DECODE_HEAD;
@@ -1447,7 +1548,7 @@ static nfsd4_dec nfsd41_dec_ops[] = {
[OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_test_stateid,
[OP_WANT_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_DESTROY_CLIENTID] = (nfsd4_dec)nfsd4_decode_notsupp,
+ [OP_DESTROY_CLIENTID] = (nfsd4_dec)nfsd4_decode_destroy_clientid,
[OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_reclaim_complete,
};
@@ -1630,15 +1731,20 @@ static void write_cinfo(__be32 **p, struct nfsd4_change_info *c)
* we know whether the error to be returned is a sequence id mutating error.
*/
-#define ENCODE_SEQID_OP_TAIL(stateowner) do { \
- if (seqid_mutating_err(nfserr) && stateowner) { \
- stateowner->so_seqid++; \
- stateowner->so_replay.rp_status = nfserr; \
- stateowner->so_replay.rp_buflen = \
- (((char *)(resp)->p - (char *)save)); \
- memcpy(stateowner->so_replay.rp_buf, save, \
- stateowner->so_replay.rp_buflen); \
- } } while (0);
+static void encode_seqid_op_tail(struct nfsd4_compoundres *resp, __be32 *save, __be32 nfserr)
+{
+ struct nfs4_stateowner *stateowner = resp->cstate.replay_owner;
+
+ if (seqid_mutating_err(ntohl(nfserr)) && stateowner) {
+ stateowner->so_seqid++;
+ stateowner->so_replay.rp_status = nfserr;
+ stateowner->so_replay.rp_buflen =
+ (char *)resp->p - (char *)save;
+ memcpy(stateowner->so_replay.rp_buf, save,
+ stateowner->so_replay.rp_buflen);
+ nfsd4_purge_closed_stateid(stateowner);
+ }
+}
/* Encode as an array of strings the string given with components
* separated @sep.
@@ -1697,36 +1803,89 @@ static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location,
}
/*
- * Return the path to an export point in the pseudo filesystem namespace
- * Returned string is safe to use as long as the caller holds a reference
- * to @exp.
+ * Encode a path in RFC3530 'pathname4' format
*/
-static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *stat)
+static __be32 nfsd4_encode_path(const struct path *root,
+ const struct path *path, __be32 **pp, int *buflen)
{
- struct svc_fh tmp_fh;
- char *path = NULL, *rootpath;
- size_t rootlen;
+ struct path cur = {
+ .mnt = path->mnt,
+ .dentry = path->dentry,
+ };
+ __be32 *p = *pp;
+ struct dentry **components = NULL;
+ unsigned int ncomponents = 0;
+ __be32 err = nfserr_jukebox;
- fh_init(&tmp_fh, NFS4_FHSIZE);
- *stat = exp_pseudoroot(rqstp, &tmp_fh);
- if (*stat)
- return NULL;
- rootpath = tmp_fh.fh_export->ex_pathname;
+ dprintk("nfsd4_encode_components(");
- path = exp->ex_pathname;
+ path_get(&cur);
+ /* First walk the path up to the nfsd root, and store the
+ * dentries/path components in an array.
+ */
+ for (;;) {
+ if (cur.dentry == root->dentry && cur.mnt == root->mnt)
+ break;
+ if (cur.dentry == cur.mnt->mnt_root) {
+ if (follow_up(&cur))
+ continue;
+ goto out_free;
+ }
+ if ((ncomponents & 15) == 0) {
+ struct dentry **new;
+ new = krealloc(components,
+ sizeof(*new) * (ncomponents + 16),
+ GFP_KERNEL);
+ if (!new)
+ goto out_free;
+ components = new;
+ }
+ components[ncomponents++] = cur.dentry;
+ cur.dentry = dget_parent(cur.dentry);
+ }
- rootlen = strlen(rootpath);
- if (strncmp(path, rootpath, rootlen)) {
- dprintk("nfsd: fs_locations failed;"
- "%s is not contained in %s\n", path, rootpath);
- *stat = nfserr_notsupp;
- path = NULL;
- goto out;
+ *buflen -= 4;
+ if (*buflen < 0)
+ goto out_free;
+ WRITE32(ncomponents);
+
+ while (ncomponents) {
+ struct dentry *dentry = components[ncomponents - 1];
+ unsigned int len = dentry->d_name.len;
+
+ *buflen -= 4 + (XDR_QUADLEN(len) << 2);
+ if (*buflen < 0)
+ goto out_free;
+ WRITE32(len);
+ WRITEMEM(dentry->d_name.name, len);
+ dprintk("/%s", dentry->d_name.name);
+ dput(dentry);
+ ncomponents--;
}
- path += rootlen;
-out:
- fh_put(&tmp_fh);
- return path;
+
+ *pp = p;
+ err = 0;
+out_free:
+ dprintk(")\n");
+ while (ncomponents)
+ dput(components[--ncomponents]);
+ kfree(components);
+ path_put(&cur);
+ return err;
+}
+
+static __be32 nfsd4_encode_fsloc_fsroot(struct svc_rqst *rqstp,
+ const struct path *path, __be32 **pp, int *buflen)
+{
+ struct svc_export *exp_ps;
+ __be32 res;
+
+ exp_ps = rqst_find_fsidzero_export(rqstp);
+ if (IS_ERR(exp_ps))
+ return nfserrno(PTR_ERR(exp_ps));
+ res = nfsd4_encode_path(&exp_ps->ex_path, path, pp, buflen);
+ exp_put(exp_ps);
+ return res;
}
/*
@@ -1740,11 +1899,8 @@ static __be32 nfsd4_encode_fs_locations(struct svc_rqst *rqstp,
int i;
__be32 *p = *pp;
struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs;
- char *root = nfsd4_path(rqstp, exp, &status);
- if (status)
- return status;
- status = nfsd4_encode_components('/', root, &p, buflen);
+ status = nfsd4_encode_fsloc_fsroot(rqstp, &exp->ex_path, &p, buflen);
if (status)
return status;
if ((*buflen -= 4) < 0)
@@ -1760,12 +1916,19 @@ static __be32 nfsd4_encode_fs_locations(struct svc_rqst *rqstp,
return 0;
}
-static u32 nfs4_ftypes[16] = {
- NF4BAD, NF4FIFO, NF4CHR, NF4BAD,
- NF4DIR, NF4BAD, NF4BLK, NF4BAD,
- NF4REG, NF4BAD, NF4LNK, NF4BAD,
- NF4SOCK, NF4BAD, NF4LNK, NF4BAD,
-};
+static u32 nfs4_file_type(umode_t mode)
+{
+ switch (mode & S_IFMT) {
+ case S_IFIFO: return NF4FIFO;
+ case S_IFCHR: return NF4CHR;
+ case S_IFDIR: return NF4DIR;
+ case S_IFBLK: return NF4BLK;
+ case S_IFLNK: return NF4LNK;
+ case S_IFREG: return NF4REG;
+ case S_IFSOCK: return NF4SOCK;
+ default: return NF4BAD;
+ };
+}
static __be32
nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
@@ -1954,7 +2117,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
if (bmval0 & FATTR4_WORD0_TYPE) {
if ((buflen -= 4) < 0)
goto out_resource;
- dummy = nfs4_ftypes[(stat.mode & S_IFMT) >> 12];
+ dummy = nfs4_file_type(stat.mode);
if (dummy == NF4BAD)
goto out_serverfault;
WRITE32(dummy);
@@ -2488,7 +2651,7 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_c
if (!nfserr)
nfsd4_encode_stateid(resp, &close->cl_stateid);
- ENCODE_SEQID_OP_TAIL(close->cl_stateowner);
+ encode_seqid_op_tail(resp, save, nfserr);
return nfserr;
}
@@ -2564,17 +2727,18 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh
static void
nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denied *ld)
{
+ struct xdr_netobj *conf = &ld->ld_owner;
__be32 *p;
- RESERVE_SPACE(32 + XDR_LEN(ld->ld_sop ? ld->ld_sop->so_owner.len : 0));
+ RESERVE_SPACE(32 + XDR_LEN(conf->len));
WRITE64(ld->ld_start);
WRITE64(ld->ld_length);
WRITE32(ld->ld_type);
- if (ld->ld_sop) {
+ if (conf->len) {
WRITEMEM(&ld->ld_clientid, 8);
- WRITE32(ld->ld_sop->so_owner.len);
- WRITEMEM(ld->ld_sop->so_owner.data, ld->ld_sop->so_owner.len);
- kref_put(&ld->ld_sop->so_ref, nfs4_free_stateowner);
+ WRITE32(conf->len);
+ WRITEMEM(conf->data, conf->len);
+ kfree(conf->data);
} else { /* non - nfsv4 lock in conflict, no clientid nor owner */
WRITE64((u64)0); /* clientid */
WRITE32(0); /* length of owner name */
@@ -2592,7 +2756,7 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lo
else if (nfserr == nfserr_denied)
nfsd4_encode_lock_denied(resp, &lock->lk_denied);
- ENCODE_SEQID_OP_TAIL(lock->lk_replay_owner);
+ encode_seqid_op_tail(resp, save, nfserr);
return nfserr;
}
@@ -2612,7 +2776,7 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l
if (!nfserr)
nfsd4_encode_stateid(resp, &locku->lu_stateid);
- ENCODE_SEQID_OP_TAIL(locku->lu_stateowner);
+ encode_seqid_op_tail(resp, save, nfserr);
return nfserr;
}
@@ -2693,7 +2857,7 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op
}
/* XXX save filehandle here */
out:
- ENCODE_SEQID_OP_TAIL(open->op_stateowner);
+ encode_seqid_op_tail(resp, save, nfserr);
return nfserr;
}
@@ -2705,7 +2869,7 @@ nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct
if (!nfserr)
nfsd4_encode_stateid(resp, &oc->oc_resp_stateid);
- ENCODE_SEQID_OP_TAIL(oc->oc_stateowner);
+ encode_seqid_op_tail(resp, save, nfserr);
return nfserr;
}
@@ -2717,7 +2881,7 @@ nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struc
if (!nfserr)
nfsd4_encode_stateid(resp, &od->od_stateid);
- ENCODE_SEQID_OP_TAIL(od->od_stateowner);
+ encode_seqid_op_tail(resp, save, nfserr);
return nfserr;
}
@@ -2759,8 +2923,6 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen,
&maxcount);
- if (nfserr == nfserr_symlink)
- nfserr = nfserr_inval;
if (nfserr)
return nfserr;
eof = (read->rd_offset + maxcount >=
@@ -2886,8 +3048,6 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
readdir->common.err == nfserr_toosmall &&
readdir->buffer == page)
nfserr = nfserr_toosmall;
- if (nfserr == nfserr_symlink)
- nfserr = nfserr_notdir;
if (nfserr)
goto err_no_verf;
@@ -3218,9 +3378,9 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
WRITEMEM(seq->sessionid.data, NFS4_MAX_SESSIONID_LEN);
WRITE32(seq->seqid);
WRITE32(seq->slotid);
- WRITE32(seq->maxslots);
- /* For now: target_maxslots = maxslots */
- WRITE32(seq->maxslots);
+ /* Note slotid's are numbered from zero: */
+ WRITE32(seq->maxslots - 1); /* sr_highest_slotid */
+ WRITE32(seq->maxslots - 1); /* sr_target_highest_slotid */
WRITE32(seq->status_flags);
ADJUST_ARGS();
@@ -3233,6 +3393,7 @@ nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, int nfserr,
struct nfsd4_test_stateid *test_stateid)
{
struct nfsd4_compoundargs *argp;
+ struct nfs4_client *cl = resp->cstate.session->se_client;
stateid_t si;
__be32 *p;
int i;
@@ -3248,7 +3409,7 @@ nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, int nfserr,
nfs4_lock_state();
for (i = 0; i < test_stateid->ts_num_ids; i++) {
nfsd4_decode_stateid(argp, &si);
- valid = nfs4_validate_stateid(&si, test_stateid->ts_has_session);
+ valid = nfs4_validate_stateid(cl, &si);
RESERVE_SPACE(4);
*p++ = htonl(valid);
resp->p = p;
@@ -3334,34 +3495,29 @@ static nfsd4_enc nfsd4_enc_ops[] = {
/*
* Calculate the total amount of memory that the compound response has taken
- * after encoding the current operation.
+ * after encoding the current operation with pad.
*
- * pad: add on 8 bytes for the next operation's op_code and status so that
- * there is room to cache a failure on the next operation.
+ * pad: if operation is non-idempotent, pad was calculate by op_rsize_bop()
+ * which was specified at nfsd4_operation, else pad is zero.
*
- * Compare this length to the session se_fmaxresp_cached.
+ * Compare this length to the session se_fmaxresp_sz and se_fmaxresp_cached.
*
* Our se_fmaxresp_cached will always be a multiple of PAGE_SIZE, and so
* will be at least a page and will therefore hold the xdr_buf head.
*/
-static int nfsd4_check_drc_limit(struct nfsd4_compoundres *resp)
+int nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad)
{
- int status = 0;
struct xdr_buf *xb = &resp->rqstp->rq_res;
- struct nfsd4_compoundargs *args = resp->rqstp->rq_argp;
struct nfsd4_session *session = NULL;
struct nfsd4_slot *slot = resp->cstate.slot;
- u32 length, tlen = 0, pad = 8;
+ u32 length, tlen = 0;
if (!nfsd4_has_session(&resp->cstate))
- return status;
+ return 0;
session = resp->cstate.session;
- if (session == NULL || slot->sl_cachethis == 0)
- return status;
-
- if (resp->opcnt >= args->opcnt)
- pad = 0; /* this is the last operation */
+ if (session == NULL)
+ return 0;
if (xb->page_len == 0) {
length = (char *)resp->p - (char *)xb->head[0].iov_base + pad;
@@ -3374,10 +3530,14 @@ static int nfsd4_check_drc_limit(struct nfsd4_compoundres *resp)
dprintk("%s length %u, xb->page_len %u tlen %u pad %u\n", __func__,
length, xb->page_len, tlen, pad);
- if (length <= session->se_fchannel.maxresp_cached)
- return status;
- else
+ if (length > session->se_fchannel.maxresp_sz)
+ return nfserr_rep_too_big;
+
+ if (slot->sl_cachethis == 1 &&
+ length > session->se_fchannel.maxresp_cached)
return nfserr_rep_too_big_to_cache;
+
+ return 0;
}
void
@@ -3397,8 +3557,8 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
!nfsd4_enc_ops[op->opnum]);
op->status = nfsd4_enc_ops[op->opnum](resp, op->status, &op->u);
/* nfsd4_check_drc_limit guarantees enough room for error status */
- if (!op->status && nfsd4_check_drc_limit(resp))
- op->status = nfserr_rep_too_big_to_cache;
+ if (!op->status)
+ op->status = nfsd4_check_resp_size(resp, 0);
status:
/*
* Note: We write the status directly, instead of using WRITE32(),
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index c7716143cbd1..db34a585e112 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -9,7 +9,6 @@
#include <linux/ctype.h>
#include <linux/sunrpc/svcsock.h>
-#include <linux/nfsd/syscall.h>
#include <linux/lockd/lockd.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/gss_api.h>
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index 7ecfa2420307..58134a23fdfb 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -11,13 +11,39 @@
#include <linux/types.h>
#include <linux/mount.h>
+#include <linux/nfs.h>
+#include <linux/nfs2.h>
+#include <linux/nfs3.h>
+#include <linux/nfs4.h>
+#include <linux/sunrpc/msg_prot.h>
+
#include <linux/nfsd/debug.h>
#include <linux/nfsd/export.h>
#include <linux/nfsd/stats.h>
+
/*
* nfsd version
*/
#define NFSD_SUPPORTED_MINOR_VERSION 1
+/*
+ * Maximum blocksizes supported by daemon under various circumstances.
+ */
+#define NFSSVC_MAXBLKSIZE RPCSVC_MAXPAYLOAD
+/* NFSv2 is limited by the protocol specification, see RFC 1094 */
+#define NFSSVC_MAXBLKSIZE_V2 (8*1024)
+
+
+/*
+ * Largest number of bytes we need to allocate for an NFS
+ * call or reply. Used to control buffer sizes. We use
+ * the length of v3 WRITE, READDIR and READDIR replies
+ * which are an RPC header, up to 26 XDR units of reply
+ * data, and some page data.
+ *
+ * Note that accuracy here doesn't matter too much as the
+ * size is rounded up to a page size when allocating space.
+ */
+#define NFSD_BUFSIZE ((RPC_MAX_HEADER_WITH_AUTH+26)*XDR_UNIT + NFSSVC_MAXBLKSIZE)
struct readdir_cd {
__be32 err; /* 0, nfserr, or nfserr_eof */
@@ -335,6 +361,13 @@ static inline u32 nfsd_suppattrs2(u32 minorversion)
#define NFSD_SUPPATTR_EXCLCREAT_WORD2 \
NFSD_WRITEABLE_ATTRS_WORD2
+extern int nfsd4_is_junction(struct dentry *dentry);
+#else
+static inline int nfsd4_is_junction(struct dentry *dentry)
+{
+ return 0;
+}
+
#endif /* CONFIG_NFSD_V4 */
#endif /* LINUX_NFSD_NFSD_H */
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 90c6aa6d5e0f..c763de5c1157 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -59,28 +59,25 @@ static int nfsd_acceptable(void *expv, struct dentry *dentry)
* the write call).
*/
static inline __be32
-nfsd_mode_check(struct svc_rqst *rqstp, umode_t mode, int type)
+nfsd_mode_check(struct svc_rqst *rqstp, umode_t mode, int requested)
{
- /* Type can be negative when creating hardlinks - not to a dir */
- if (type > 0 && (mode & S_IFMT) != type) {
- if (rqstp->rq_vers == 4 && (mode & S_IFMT) == S_IFLNK)
- return nfserr_symlink;
- else if (type == S_IFDIR)
- return nfserr_notdir;
- else if ((mode & S_IFMT) == S_IFDIR)
- return nfserr_isdir;
- else
- return nfserr_inval;
- }
- if (type < 0 && (mode & S_IFMT) == -type) {
- if (rqstp->rq_vers == 4 && (mode & S_IFMT) == S_IFLNK)
- return nfserr_symlink;
- else if (type == -S_IFDIR)
- return nfserr_isdir;
- else
- return nfserr_notdir;
- }
- return 0;
+ mode &= S_IFMT;
+
+ if (requested == 0) /* the caller doesn't care */
+ return nfs_ok;
+ if (mode == requested)
+ return nfs_ok;
+ /*
+ * v4 has an error more specific than err_notdir which we should
+ * return in preference to err_notdir:
+ */
+ if (rqstp->rq_vers == 4 && mode == S_IFLNK)
+ return nfserr_symlink;
+ if (requested == S_IFDIR)
+ return nfserr_notdir;
+ if (mode == S_IFDIR)
+ return nfserr_isdir;
+ return nfserr_inval;
}
static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp,
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 4eefaf1b42e8..a3cf38476a1b 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -35,6 +35,7 @@
#ifndef _NFSD4_STATE_H
#define _NFSD4_STATE_H
+#include <linux/idr.h>
#include <linux/sunrpc/svc_xprt.h>
#include <linux/nfsd/nfsfh.h>
#include "nfsfh.h"
@@ -45,24 +46,20 @@ typedef struct {
} clientid_t;
typedef struct {
- u32 so_boot;
- u32 so_stateownerid;
- u32 so_fileid;
+ clientid_t so_clid;
+ u32 so_id;
} stateid_opaque_t;
typedef struct {
u32 si_generation;
stateid_opaque_t si_opaque;
} stateid_t;
-#define si_boot si_opaque.so_boot
-#define si_stateownerid si_opaque.so_stateownerid
-#define si_fileid si_opaque.so_fileid
#define STATEID_FMT "(%08x/%08x/%08x/%08x)"
#define STATEID_VAL(s) \
- (s)->si_boot, \
- (s)->si_stateownerid, \
- (s)->si_fileid, \
+ (s)->si_opaque.so_clid.cl_boot, \
+ (s)->si_opaque.so_clid.cl_id, \
+ (s)->si_opaque.so_id, \
(s)->si_generation
struct nfsd4_callback {
@@ -76,17 +73,27 @@ struct nfsd4_callback {
bool cb_done;
};
+struct nfs4_stid {
+#define NFS4_OPEN_STID 1
+#define NFS4_LOCK_STID 2
+#define NFS4_DELEG_STID 4
+/* For an open stateid kept around *only* to process close replays: */
+#define NFS4_CLOSED_STID 8
+ unsigned char sc_type;
+ stateid_t sc_stateid;
+ struct nfs4_client *sc_client;
+};
+
struct nfs4_delegation {
+ struct nfs4_stid dl_stid; /* must be first field */
struct list_head dl_perfile;
struct list_head dl_perclnt;
struct list_head dl_recall_lru; /* delegation recalled */
atomic_t dl_count; /* ref count */
- struct nfs4_client *dl_client;
struct nfs4_file *dl_file;
u32 dl_type;
time_t dl_time;
/* For recall: */
- stateid_t dl_stateid;
struct knfsd_fh dl_fh;
int dl_retries;
struct nfsd4_callback dl_recall;
@@ -104,6 +111,11 @@ struct nfs4_cb_conn {
struct svc_xprt *cb_xprt; /* minorversion 1 only */
};
+static inline struct nfs4_delegation *delegstateid(struct nfs4_stid *s)
+{
+ return container_of(s, struct nfs4_delegation, dl_stid);
+}
+
/* Maximum number of slots per session. 160 is useful for long haul TCP */
#define NFSD_MAX_SLOTS_PER_SESSION 160
/* Maximum number of operations per session compound */
@@ -220,6 +232,7 @@ struct nfs4_client {
struct list_head cl_idhash; /* hash by cl_clientid.id */
struct list_head cl_strhash; /* hash by cl_name */
struct list_head cl_openowners;
+ struct idr cl_stateids; /* stateid lookup */
struct list_head cl_delegations;
struct list_head cl_lru; /* tail queue */
struct xdr_netobj cl_name; /* id generated by client */
@@ -245,6 +258,7 @@ struct nfs4_client {
#define NFSD4_CB_UP 0
#define NFSD4_CB_UNKNOWN 1
#define NFSD4_CB_DOWN 2
+#define NFSD4_CB_FAULT 3
int cl_cb_state;
struct nfsd4_callback cl_cb_null;
struct nfsd4_session *cl_cb_session;
@@ -293,6 +307,9 @@ static inline void
update_stateid(stateid_t *stateid)
{
stateid->si_generation++;
+ /* Wraparound recommendation from 3530bis-13 9.1.3.2: */
+ if (stateid->si_generation == 0)
+ stateid->si_generation = 1;
}
/* A reasonable value for REPLAY_ISIZE was estimated as follows:
@@ -312,49 +329,57 @@ struct nfs4_replay {
__be32 rp_status;
unsigned int rp_buflen;
char *rp_buf;
- unsigned intrp_allocated;
struct knfsd_fh rp_openfh;
char rp_ibuf[NFSD4_REPLAY_ISIZE];
};
-/*
-* nfs4_stateowner can either be an open_owner, or a lock_owner
-*
-* so_idhash: stateid_hashtbl[] for open owner, lockstateid_hashtbl[]
-* for lock_owner
-* so_strhash: ownerstr_hashtbl[] for open_owner, lock_ownerstr_hashtbl[]
-* for lock_owner
-* so_perclient: nfs4_client->cl_perclient entry - used when nfs4_client
-* struct is reaped.
-* so_perfilestate: heads the list of nfs4_stateid (either open or lock)
-* and is used to ensure no dangling nfs4_stateid references when we
-* release a stateowner.
-* so_perlockowner: (open) nfs4_stateid->st_perlockowner entry - used when
-* close is called to reap associated byte-range locks
-* so_close_lru: (open) stateowner is placed on this list instead of being
-* reaped (when so_perfilestate is empty) to hold the last close replay.
-* reaped by laundramat thread after lease period.
-*/
struct nfs4_stateowner {
- struct kref so_ref;
- struct list_head so_idhash; /* hash by so_id */
struct list_head so_strhash; /* hash by op_name */
- struct list_head so_perclient;
struct list_head so_stateids;
- struct list_head so_perstateid; /* for lockowners only */
- struct list_head so_close_lru; /* tail queue */
- time_t so_time; /* time of placement on so_close_lru */
- int so_is_open_owner; /* 1=openowner,0=lockowner */
- u32 so_id;
struct nfs4_client * so_client;
/* after increment in ENCODE_SEQID_OP_TAIL, represents the next
* sequence id expected from the client: */
u32 so_seqid;
struct xdr_netobj so_owner; /* open owner name */
- int so_confirmed; /* successful OPEN_CONFIRM? */
struct nfs4_replay so_replay;
+ bool so_is_open_owner;
};
+struct nfs4_openowner {
+ struct nfs4_stateowner oo_owner; /* must be first field */
+ struct list_head oo_perclient;
+ /*
+ * We keep around openowners a little while after last close,
+ * which saves clients from having to confirm, and allows us to
+ * handle close replays if they come soon enough. The close_lru
+ * is a list of such openowners, to be reaped by the laundromat
+ * thread eventually if they remain unused:
+ */
+ struct list_head oo_close_lru;
+ struct nfs4_ol_stateid *oo_last_closed_stid;
+ time_t oo_time; /* time of placement on so_close_lru */
+#define NFS4_OO_CONFIRMED 1
+#define NFS4_OO_PURGE_CLOSE 2
+#define NFS4_OO_NEW 4
+ unsigned char oo_flags;
+};
+
+struct nfs4_lockowner {
+ struct nfs4_stateowner lo_owner; /* must be first element */
+ struct list_head lo_perstateid; /* for lockowners only */
+ struct list_head lo_list; /* for temporary uses */
+};
+
+static inline struct nfs4_openowner * openowner(struct nfs4_stateowner *so)
+{
+ return container_of(so, struct nfs4_openowner, oo_owner);
+}
+
+static inline struct nfs4_lockowner * lockowner(struct nfs4_stateowner *so)
+{
+ return container_of(so, struct nfs4_lockowner, lo_owner);
+}
+
/*
* nfs4_file: a file opened by some number of (open) nfs4_stateowners.
* o fi_perfile list is used to search for conflicting
@@ -368,17 +393,17 @@ struct nfs4_file {
/* One each for O_RDONLY, O_WRONLY, O_RDWR: */
struct file * fi_fds[3];
/*
- * Each open or lock stateid contributes 1 to either
- * fi_access[O_RDONLY], fi_access[O_WRONLY], or both, depending
- * on open or lock mode:
+ * Each open or lock stateid contributes 0-4 to the counts
+ * below depending on which bits are set in st_access_bitmap:
+ * 1 to fi_access[O_RDONLY] if NFS4_SHARE_ACCES_READ is set
+ * + 1 to fi_access[O_WRONLY] if NFS4_SHARE_ACCESS_WRITE is set
+ * + 1 to both of the above if NFS4_SHARE_ACCESS_BOTH is set.
*/
atomic_t fi_access[2];
struct file *fi_deleg_file;
struct file_lock *fi_lease;
atomic_t fi_delegees;
struct inode *fi_inode;
- u32 fi_id; /* used with stateowner->so_id
- * for stateid_hashtbl hash */
bool fi_had_conflict;
};
@@ -408,50 +433,27 @@ static inline struct file *find_any_file(struct nfs4_file *f)
return f->fi_fds[O_RDONLY];
}
-/*
-* nfs4_stateid can either be an open stateid or (eventually) a lock stateid
-*
-* (open)nfs4_stateid: one per (open)nfs4_stateowner, nfs4_file
-*
-* st_hash: stateid_hashtbl[] entry or lockstateid_hashtbl entry
-* st_perfile: file_hashtbl[] entry.
-* st_perfile_state: nfs4_stateowner->so_perfilestate
-* st_perlockowner: (open stateid) list of lock nfs4_stateowners
-* st_access_bmap: used only for open stateid
-* st_deny_bmap: used only for open stateid
-* st_openstp: open stateid lock stateid was derived from
-*
-* XXX: open stateids and lock stateids have diverged sufficiently that
-* we should consider defining separate structs for the two cases.
-*/
-
-struct nfs4_stateid {
- struct list_head st_hash;
+/* "ol" stands for "Open or Lock". Better suggestions welcome. */
+struct nfs4_ol_stateid {
+ struct nfs4_stid st_stid; /* must be first field */
struct list_head st_perfile;
struct list_head st_perstateowner;
struct list_head st_lockowners;
struct nfs4_stateowner * st_stateowner;
struct nfs4_file * st_file;
- stateid_t st_stateid;
unsigned long st_access_bmap;
unsigned long st_deny_bmap;
- struct nfs4_stateid * st_openstp;
+ struct nfs4_ol_stateid * st_openstp;
};
+static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s)
+{
+ return container_of(s, struct nfs4_ol_stateid, st_stid);
+}
+
/* flags for preprocess_seqid_op() */
-#define HAS_SESSION 0x00000001
-#define CONFIRM 0x00000002
-#define OPEN_STATE 0x00000004
-#define LOCK_STATE 0x00000008
#define RD_STATE 0x00000010
#define WR_STATE 0x00000020
-#define CLOSE_STATE 0x00000040
-
-#define seqid_mutating_err(err) \
- (((err) != nfserr_stale_clientid) && \
- ((err) != nfserr_bad_seqid) && \
- ((err) != nfserr_stale_stateid) && \
- ((err) != nfserr_bad_stateid))
struct nfsd4_compound_state;
@@ -461,7 +463,8 @@ extern void nfs4_lock_state(void);
extern void nfs4_unlock_state(void);
extern int nfs4_in_grace(void);
extern __be32 nfs4_check_open_reclaim(clientid_t *clid);
-extern void nfs4_free_stateowner(struct kref *kref);
+extern void nfs4_free_openowner(struct nfs4_openowner *);
+extern void nfs4_free_lockowner(struct nfs4_lockowner *);
extern int set_callback_cred(void);
extern void nfsd4_probe_callback(struct nfs4_client *clp);
extern void nfsd4_probe_callback_sync(struct nfs4_client *clp);
@@ -473,7 +476,7 @@ extern void nfsd4_destroy_callback_queue(void);
extern void nfsd4_shutdown_callback(struct nfs4_client *);
extern void nfs4_put_delegation(struct nfs4_delegation *dp);
extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
-extern void nfsd4_init_recdir(char *recdir_name);
+extern void nfsd4_init_recdir(void);
extern int nfsd4_recdir_load(void);
extern void nfsd4_shutdown_recdir(void);
extern int nfs4_client_to_reclaim(const char *name);
@@ -482,18 +485,7 @@ extern void nfsd4_recdir_purge_old(void);
extern int nfsd4_create_clid_dir(struct nfs4_client *clp);
extern void nfsd4_remove_clid_dir(struct nfs4_client *clp);
extern void release_session_client(struct nfsd4_session *);
-extern __be32 nfs4_validate_stateid(stateid_t *, int);
-
-static inline void
-nfs4_put_stateowner(struct nfs4_stateowner *so)
-{
- kref_put(&so->so_ref, nfs4_free_stateowner);
-}
-
-static inline void
-nfs4_get_stateowner(struct nfs4_stateowner *so)
-{
- kref_get(&so->so_ref);
-}
+extern __be32 nfs4_validate_stateid(struct nfs4_client *, stateid_t *);
+extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *);
#endif /* NFSD4_STATE_H */
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index fd0acca5370a..7a2e442623c8 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -168,6 +168,8 @@ int nfsd_mountpoint(struct dentry *dentry, struct svc_export *exp)
{
if (d_mountpoint(dentry))
return 1;
+ if (nfsd4_is_junction(dentry))
+ return 1;
if (!(exp->ex_flags & NFSEXP_V4ROOT))
return 0;
return dentry->d_inode != NULL;
@@ -502,7 +504,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
unsigned int flags = 0;
/* Get inode */
- error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, NFSD_MAY_SATTR);
+ error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR);
if (error)
return error;
@@ -592,6 +594,22 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_ac
return error;
}
+#define NFSD_XATTR_JUNCTION_PREFIX XATTR_TRUSTED_PREFIX "junction."
+#define NFSD_XATTR_JUNCTION_TYPE NFSD_XATTR_JUNCTION_PREFIX "type"
+int nfsd4_is_junction(struct dentry *dentry)
+{
+ struct inode *inode = dentry->d_inode;
+
+ if (inode == NULL)
+ return 0;
+ if (inode->i_mode & S_IXUGO)
+ return 0;
+ if (!(inode->i_mode & S_ISVTX))
+ return 0;
+ if (vfs_getxattr(dentry, NFSD_XATTR_JUNCTION_TYPE, NULL, 0) <= 0)
+ return 0;
+ return 1;
+}
#endif /* defined(CONFIG_NFSD_V4) */
#ifdef CONFIG_NFSD_V3
@@ -1352,7 +1370,7 @@ __be32
do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
char *fname, int flen, struct iattr *iap,
struct svc_fh *resfhp, int createmode, u32 *verifier,
- int *truncp, int *created)
+ bool *truncp, bool *created)
{
struct dentry *dentry, *dchild = NULL;
struct inode *dirp;
@@ -1632,10 +1650,12 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
err = fh_verify(rqstp, ffhp, S_IFDIR, NFSD_MAY_CREATE);
if (err)
goto out;
- err = fh_verify(rqstp, tfhp, -S_IFDIR, NFSD_MAY_NOP);
+ err = fh_verify(rqstp, tfhp, 0, NFSD_MAY_NOP);
if (err)
goto out;
-
+ err = nfserr_isdir;
+ if (S_ISDIR(tfhp->fh_dentry->d_inode->i_mode))
+ goto out;
err = nfserr_perm;
if (!len)
goto out;
@@ -2114,7 +2134,8 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
/* Allow read access to binaries even when mode 111 */
if (err == -EACCES && S_ISREG(inode->i_mode) &&
- acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE))
+ (acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE) ||
+ acc == (NFSD_MAY_READ | NFSD_MAY_READ_IF_EXEC)))
err = inode_permission(inode, MAY_EXEC);
return err? nfserrno(err) : 0;
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index e0bbac04d1dd..3f54ad03bb2b 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -10,21 +10,22 @@
/*
* Flags for nfsd_permission
*/
-#define NFSD_MAY_NOP 0
-#define NFSD_MAY_EXEC 1 /* == MAY_EXEC */
-#define NFSD_MAY_WRITE 2 /* == MAY_WRITE */
-#define NFSD_MAY_READ 4 /* == MAY_READ */
-#define NFSD_MAY_SATTR 8
-#define NFSD_MAY_TRUNC 16
-#define NFSD_MAY_LOCK 32
-#define NFSD_MAY_MASK 63
+#define NFSD_MAY_NOP 0
+#define NFSD_MAY_EXEC 0x001 /* == MAY_EXEC */
+#define NFSD_MAY_WRITE 0x002 /* == MAY_WRITE */
+#define NFSD_MAY_READ 0x004 /* == MAY_READ */
+#define NFSD_MAY_SATTR 0x008
+#define NFSD_MAY_TRUNC 0x010
+#define NFSD_MAY_LOCK 0x020
+#define NFSD_MAY_MASK 0x03f
/* extra hints to permission and open routines: */
-#define NFSD_MAY_OWNER_OVERRIDE 64
-#define NFSD_MAY_LOCAL_ACCESS 128 /* IRIX doing local access check on device special file*/
-#define NFSD_MAY_BYPASS_GSS_ON_ROOT 256
-#define NFSD_MAY_NOT_BREAK_LEASE 512
-#define NFSD_MAY_BYPASS_GSS 1024
+#define NFSD_MAY_OWNER_OVERRIDE 0x040
+#define NFSD_MAY_LOCAL_ACCESS 0x080 /* for device special files */
+#define NFSD_MAY_BYPASS_GSS_ON_ROOT 0x100
+#define NFSD_MAY_NOT_BREAK_LEASE 0x200
+#define NFSD_MAY_BYPASS_GSS 0x400
+#define NFSD_MAY_READ_IF_EXEC 0x800
#define NFSD_MAY_CREATE (NFSD_MAY_EXEC|NFSD_MAY_WRITE)
#define NFSD_MAY_REMOVE (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC)
@@ -61,7 +62,7 @@ __be32 nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *);
__be32 do_nfsd_create(struct svc_rqst *, struct svc_fh *,
char *name, int len, struct iattr *attrs,
struct svc_fh *res, int createmode,
- u32 *verifier, int *truncp, int *created);
+ u32 *verifier, bool *truncp, bool *created);
__be32 nfsd_commit(struct svc_rqst *, struct svc_fh *,
loff_t, unsigned long);
#endif /* CONFIG_NFSD_V3 */
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index d2a8d04428c7..2364747ee97d 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -81,7 +81,6 @@ struct nfsd4_access {
struct nfsd4_close {
u32 cl_seqid; /* request */
stateid_t cl_stateid; /* request+response */
- struct nfs4_stateowner * cl_stateowner; /* response */
};
struct nfsd4_commit {
@@ -131,7 +130,7 @@ struct nfsd4_link {
struct nfsd4_lock_denied {
clientid_t ld_clientid;
- struct nfs4_stateowner *ld_sop;
+ struct xdr_netobj ld_owner;
u64 ld_start;
u64 ld_length;
u32 ld_type;
@@ -165,9 +164,6 @@ struct nfsd4_lock {
} ok;
struct nfsd4_lock_denied denied;
} u;
- /* The lk_replay_owner is the open owner in the open_to_lock_owner
- * case and the lock owner otherwise: */
- struct nfs4_stateowner *lk_replay_owner;
};
#define lk_new_open_seqid v.new.open_seqid
#define lk_new_open_stateid v.new.open_stateid
@@ -188,7 +184,6 @@ struct nfsd4_lockt {
struct xdr_netobj lt_owner;
u64 lt_offset;
u64 lt_length;
- struct nfs4_stateowner * lt_stateowner;
struct nfsd4_lock_denied lt_denied;
};
@@ -199,7 +194,6 @@ struct nfsd4_locku {
stateid_t lu_stateid;
u64 lu_offset;
u64 lu_length;
- struct nfs4_stateowner *lu_stateowner;
};
@@ -232,8 +226,11 @@ struct nfsd4_open {
u32 op_recall; /* recall */
struct nfsd4_change_info op_cinfo; /* response */
u32 op_rflags; /* response */
- int op_truncate; /* used during processing */
- struct nfs4_stateowner *op_stateowner; /* used during processing */
+ bool op_truncate; /* used during processing */
+ bool op_created; /* used during processing */
+ struct nfs4_openowner *op_openowner; /* used during processing */
+ struct nfs4_file *op_file; /* used during processing */
+ struct nfs4_ol_stateid *op_stp; /* used during processing */
struct nfs4_acl *op_acl;
};
#define op_iattr iattr
@@ -243,7 +240,6 @@ struct nfsd4_open_confirm {
stateid_t oc_req_stateid /* request */;
u32 oc_seqid /* request */;
stateid_t oc_resp_stateid /* response */;
- struct nfs4_stateowner * oc_stateowner; /* response */
};
struct nfsd4_open_downgrade {
@@ -251,7 +247,6 @@ struct nfsd4_open_downgrade {
u32 od_seqid;
u32 od_share_access;
u32 od_share_deny;
- struct nfs4_stateowner *od_stateowner;
};
@@ -325,8 +320,7 @@ struct nfsd4_setattr {
struct nfsd4_setclientid {
nfs4_verifier se_verf; /* request */
- u32 se_namelen; /* request */
- char * se_name; /* request */
+ struct xdr_netobj se_name;
u32 se_callback_prog; /* request */
u32 se_callback_netid_len; /* request */
char * se_callback_netid_val; /* request */
@@ -351,7 +345,6 @@ struct nfsd4_saved_compoundargs {
struct nfsd4_test_stateid {
__be32 ts_num_ids;
- __be32 ts_has_session;
struct nfsd4_compoundargs *ts_saved_args;
struct nfsd4_saved_compoundargs ts_savedp;
};
@@ -405,6 +398,10 @@ struct nfsd4_destroy_session {
struct nfs4_sessionid sessionid;
};
+struct nfsd4_destroy_clientid {
+ clientid_t clientid;
+};
+
struct nfsd4_reclaim_complete {
u32 rca_one_fs;
};
@@ -532,6 +529,7 @@ int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *,
struct nfsd4_compoundargs *);
int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *,
struct nfsd4_compoundres *);
+int nfsd4_check_resp_size(struct nfsd4_compoundres *, u32);
void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *);
void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op);
__be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
@@ -558,11 +556,13 @@ extern __be32 nfsd4_sequence(struct svc_rqst *,
extern __be32 nfsd4_destroy_session(struct svc_rqst *,
struct nfsd4_compound_state *,
struct nfsd4_destroy_session *);
+extern __be32 nfsd4_destroy_clientid(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_destroy_clientid *);
__be32 nfsd4_reclaim_complete(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_reclaim_complete *);
extern __be32 nfsd4_process_open1(struct nfsd4_compound_state *,
struct nfsd4_open *open);
extern __be32 nfsd4_process_open2(struct svc_rqst *rqstp,
struct svc_fh *current_fh, struct nfsd4_open *open);
+extern void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status);
extern __be32 nfsd4_open_confirm(struct svc_rqst *rqstp,
struct nfsd4_compound_state *, struct nfsd4_open_confirm *oc);
extern __be32 nfsd4_close(struct svc_rqst *rqstp,
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
index 81ecf9c0bf0a..194fb22ef79d 100644
--- a/fs/ocfs2/xattr.c
+++ b/fs/ocfs2/xattr.c
@@ -7185,20 +7185,9 @@ int ocfs2_init_security_and_acl(struct inode *dir,
{
int ret = 0;
struct buffer_head *dir_bh = NULL;
- struct ocfs2_security_xattr_info si = {
- .enable = 1,
- };
- ret = ocfs2_init_security_get(inode, dir, qstr, &si);
+ ret = ocfs2_init_security_get(inode, dir, qstr, NULL);
if (!ret) {
- ret = ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_SECURITY,
- si.name, si.value, si.value_len,
- XATTR_CREATE);
- if (ret) {
- mlog_errno(ret);
- goto leave;
- }
- } else if (ret != -EOPNOTSUPP) {
mlog_errno(ret);
goto leave;
}
@@ -7255,6 +7244,22 @@ static int ocfs2_xattr_security_set(struct dentry *dentry, const char *name,
name, value, size, flags);
}
+int ocfs2_initxattrs(struct inode *inode, const struct xattr *xattr_array,
+ void *fs_info)
+{
+ const struct xattr *xattr;
+ int err = 0;
+
+ for (xattr = xattr_array; xattr->name != NULL; xattr++) {
+ err = ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_SECURITY,
+ xattr->name, xattr->value,
+ xattr->value_len, XATTR_CREATE);
+ if (err)
+ break;
+ }
+ return err;
+}
+
int ocfs2_init_security_get(struct inode *inode,
struct inode *dir,
const struct qstr *qstr,
@@ -7263,8 +7268,13 @@ int ocfs2_init_security_get(struct inode *inode,
/* check whether ocfs2 support feature xattr */
if (!ocfs2_supports_xattr(OCFS2_SB(dir->i_sb)))
return -EOPNOTSUPP;
- return security_inode_init_security(inode, dir, qstr, &si->name,
- &si->value, &si->value_len);
+ if (si)
+ return security_old_inode_init_security(inode, dir, qstr,
+ &si->name, &si->value,
+ &si->value_len);
+
+ return security_inode_init_security(inode, dir, qstr,
+ &ocfs2_initxattrs, NULL);
}
int ocfs2_init_security_set(handle_t *handle,
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 25b6a887adb9..5afaa58a8630 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -877,30 +877,54 @@ struct numa_maps_private {
struct numa_maps md;
};
-static void gather_stats(struct page *page, struct numa_maps *md, int pte_dirty)
+static void gather_stats(struct page *page, struct numa_maps *md, int pte_dirty,
+ unsigned long nr_pages)
{
int count = page_mapcount(page);
- md->pages++;
+ md->pages += nr_pages;
if (pte_dirty || PageDirty(page))
- md->dirty++;
+ md->dirty += nr_pages;
if (PageSwapCache(page))
- md->swapcache++;
+ md->swapcache += nr_pages;
if (PageActive(page) || PageUnevictable(page))
- md->active++;
+ md->active += nr_pages;
if (PageWriteback(page))
- md->writeback++;
+ md->writeback += nr_pages;
if (PageAnon(page))
- md->anon++;
+ md->anon += nr_pages;
if (count > md->mapcount_max)
md->mapcount_max = count;
- md->node[page_to_nid(page)]++;
+ md->node[page_to_nid(page)] += nr_pages;
+}
+
+static struct page *can_gather_numa_stats(pte_t pte, struct vm_area_struct *vma,
+ unsigned long addr)
+{
+ struct page *page;
+ int nid;
+
+ if (!pte_present(pte))
+ return NULL;
+
+ page = vm_normal_page(vma, addr, pte);
+ if (!page)
+ return NULL;
+
+ if (PageReserved(page))
+ return NULL;
+
+ nid = page_to_nid(page);
+ if (!node_isset(nid, node_states[N_HIGH_MEMORY]))
+ return NULL;
+
+ return page;
}
static int gather_pte_stats(pmd_t *pmd, unsigned long addr,
@@ -912,26 +936,32 @@ static int gather_pte_stats(pmd_t *pmd, unsigned long addr,
pte_t *pte;
md = walk->private;
- orig_pte = pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl);
- do {
- struct page *page;
- int nid;
+ spin_lock(&walk->mm->page_table_lock);
+ if (pmd_trans_huge(*pmd)) {
+ if (pmd_trans_splitting(*pmd)) {
+ spin_unlock(&walk->mm->page_table_lock);
+ wait_split_huge_page(md->vma->anon_vma, pmd);
+ } else {
+ pte_t huge_pte = *(pte_t *)pmd;
+ struct page *page;
- if (!pte_present(*pte))
- continue;
+ page = can_gather_numa_stats(huge_pte, md->vma, addr);
+ if (page)
+ gather_stats(page, md, pte_dirty(huge_pte),
+ HPAGE_PMD_SIZE/PAGE_SIZE);
+ spin_unlock(&walk->mm->page_table_lock);
+ return 0;
+ }
+ } else {
+ spin_unlock(&walk->mm->page_table_lock);
+ }
- page = vm_normal_page(md->vma, addr, *pte);
+ orig_pte = pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl);
+ do {
+ struct page *page = can_gather_numa_stats(*pte, md->vma, addr);
if (!page)
continue;
-
- if (PageReserved(page))
- continue;
-
- nid = page_to_nid(page);
- if (!node_isset(nid, node_states[N_HIGH_MEMORY]))
- continue;
-
- gather_stats(page, md, pte_dirty(*pte));
+ gather_stats(page, md, pte_dirty(*pte), 1);
} while (pte++, addr += PAGE_SIZE, addr != end);
pte_unmap_unlock(orig_pte, ptl);
@@ -952,7 +982,7 @@ static int gather_hugetbl_stats(pte_t *pte, unsigned long hmask,
return 0;
md = walk->private;
- gather_stats(page, md, pte_dirty(*pte));
+ gather_stats(page, md, pte_dirty(*pte), 1);
return 0;
}
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index b34bdb25490c..10b6be3ca280 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -355,7 +355,7 @@ SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
* resolution (think about autofs) and thus deadlocks could arise.
*/
if (cmds == Q_QUOTAON) {
- ret = user_path_at(AT_FDCWD, addr, LOOKUP_FOLLOW, &path);
+ ret = user_path_at(AT_FDCWD, addr, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path);
if (ret)
pathp = ERR_PTR(ret);
else
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index a159ba5a35e7..eb711060a6f2 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -291,14 +291,13 @@ int reiserfs_allocate_list_bitmaps(struct super_block *sb,
for (i = 0; i < JOURNAL_NUM_BITMAPS; i++) {
jb = jb_array + i;
jb->journal_list = NULL;
- jb->bitmaps = vmalloc(mem);
+ jb->bitmaps = vzalloc(mem);
if (!jb->bitmaps) {
reiserfs_warning(sb, "clm-2000", "unable to "
"allocate bitmaps for journal lists");
failed = 1;
break;
}
- memset(jb->bitmaps, 0, mem);
}
if (failed) {
free_list_bitmaps(sb, jb_array);
@@ -353,11 +352,10 @@ static struct reiserfs_journal_cnode *allocate_cnodes(int num_cnodes)
if (num_cnodes <= 0) {
return NULL;
}
- head = vmalloc(num_cnodes * sizeof(struct reiserfs_journal_cnode));
+ head = vzalloc(num_cnodes * sizeof(struct reiserfs_journal_cnode));
if (!head) {
return NULL;
}
- memset(head, 0, num_cnodes * sizeof(struct reiserfs_journal_cnode));
head[0].prev = NULL;
head[0].next = head + 1;
for (i = 1; i < num_cnodes; i++) {
@@ -2685,14 +2683,13 @@ int journal_init(struct super_block *sb, const char *j_dev_name,
* dependency inversion warnings.
*/
reiserfs_write_unlock(sb);
- journal = SB_JOURNAL(sb) = vmalloc(sizeof(struct reiserfs_journal));
+ journal = SB_JOURNAL(sb) = vzalloc(sizeof(struct reiserfs_journal));
if (!journal) {
reiserfs_warning(sb, "journal-1256",
"unable to get memory for journal structure");
reiserfs_write_lock(sb);
return 1;
}
- memset(journal, 0, sizeof(struct reiserfs_journal));
INIT_LIST_HEAD(&journal->j_bitmap_nodes);
INIT_LIST_HEAD(&journal->j_prealloc_list);
INIT_LIST_HEAD(&journal->j_working_list);
diff --git a/fs/reiserfs/resize.c b/fs/reiserfs/resize.c
index b6b9b1fe33b0..7483279b482d 100644
--- a/fs/reiserfs/resize.c
+++ b/fs/reiserfs/resize.c
@@ -111,15 +111,13 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new)
/* allocate additional bitmap blocks, reallocate array of bitmap
* block pointers */
bitmap =
- vmalloc(sizeof(struct reiserfs_bitmap_info) * bmap_nr_new);
+ vzalloc(sizeof(struct reiserfs_bitmap_info) * bmap_nr_new);
if (!bitmap) {
/* Journal bitmaps are still supersized, but the memory isn't
* leaked, so I guess it's ok */
printk("reiserfs_resize: unable to allocate memory.\n");
return -ENOMEM;
}
- memset(bitmap, 0,
- sizeof(struct reiserfs_bitmap_info) * bmap_nr_new);
for (i = 0; i < bmap_nr; i++)
bitmap[i] = old_bitmap[i];
diff --git a/fs/reiserfs/xattr_security.c b/fs/reiserfs/xattr_security.c
index ef66c18a9332..534668fa41be 100644
--- a/fs/reiserfs/xattr_security.c
+++ b/fs/reiserfs/xattr_security.c
@@ -66,8 +66,8 @@ int reiserfs_security_init(struct inode *dir, struct inode *inode,
if (IS_PRIVATE(dir))
return 0;
- error = security_inode_init_security(inode, dir, qstr, &sec->name,
- &sec->value, &sec->length);
+ error = security_old_inode_init_security(inode, dir, qstr, &sec->name,
+ &sec->value, &sec->length);
if (error) {
if (error == -EOPNOTSUPP)
error = 0;
diff --git a/fs/squashfs/Kconfig b/fs/squashfs/Kconfig
index 1360d4f88f41..048b59d5b2f0 100644
--- a/fs/squashfs/Kconfig
+++ b/fs/squashfs/Kconfig
@@ -19,9 +19,9 @@ config SQUASHFS
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
- say M here and read <file:Documentation/modules.txt>. The module
- will be called squashfs. Note that the root file system (the one
- containing the directory /) cannot be compiled as a module.
+ say M here. The module will be called squashfs. Note that the root
+ file system (the one containing the directory /) cannot be compiled
+ as a module.
If unsure, say N.
diff --git a/fs/stat.c b/fs/stat.c
index ba5316ffac61..78a3aa83c7ea 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -81,8 +81,6 @@ int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,
if (!(flag & AT_SYMLINK_NOFOLLOW))
lookup_flags |= LOOKUP_FOLLOW;
- if (flag & AT_NO_AUTOMOUNT)
- lookup_flags |= LOOKUP_NO_AUTOMOUNT;
if (flag & AT_EMPTY_PATH)
lookup_flags |= LOOKUP_EMPTY;
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index ea9120a830d8..48ffbdf0d017 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -43,20 +43,48 @@ static DEFINE_IDA(sysfs_ino_ida);
static void sysfs_link_sibling(struct sysfs_dirent *sd)
{
struct sysfs_dirent *parent_sd = sd->s_parent;
- struct sysfs_dirent **pos;
- BUG_ON(sd->s_sibling);
-
- /* Store directory entries in order by ino. This allows
- * readdir to properly restart without having to add a
- * cursor into the s_dir.children list.
- */
- for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) {
- if (sd->s_ino < (*pos)->s_ino)
- break;
+ struct rb_node **p;
+ struct rb_node *parent;
+
+ if (sysfs_type(sd) == SYSFS_DIR)
+ parent_sd->s_dir.subdirs++;
+
+ p = &parent_sd->s_dir.inode_tree.rb_node;
+ parent = NULL;
+ while (*p) {
+ parent = *p;
+#define node rb_entry(parent, struct sysfs_dirent, inode_node)
+ if (sd->s_ino < node->s_ino) {
+ p = &node->inode_node.rb_left;
+ } else if (sd->s_ino > node->s_ino) {
+ p = &node->inode_node.rb_right;
+ } else {
+ printk(KERN_CRIT "sysfs: inserting duplicate inode '%lx'\n",
+ (unsigned long) sd->s_ino);
+ BUG();
+ }
+#undef node
}
- sd->s_sibling = *pos;
- *pos = sd;
+ rb_link_node(&sd->inode_node, parent, p);
+ rb_insert_color(&sd->inode_node, &parent_sd->s_dir.inode_tree);
+
+ p = &parent_sd->s_dir.name_tree.rb_node;
+ parent = NULL;
+ while (*p) {
+ int c;
+ parent = *p;
+#define node rb_entry(parent, struct sysfs_dirent, name_node)
+ c = strcmp(sd->s_name, node->s_name);
+ if (c < 0) {
+ p = &node->name_node.rb_left;
+ } else {
+ p = &node->name_node.rb_right;
+ }
+#undef node
+ }
+ rb_link_node(&sd->name_node, parent, p);
+ rb_insert_color(&sd->name_node, &parent_sd->s_dir.name_tree);
}
/**
@@ -71,16 +99,11 @@ static void sysfs_link_sibling(struct sysfs_dirent *sd)
*/
static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
{
- struct sysfs_dirent **pos;
+ if (sysfs_type(sd) == SYSFS_DIR)
+ sd->s_parent->s_dir.subdirs--;
- for (pos = &sd->s_parent->s_dir.children; *pos;
- pos = &(*pos)->s_sibling) {
- if (*pos == sd) {
- *pos = sd->s_sibling;
- sd->s_sibling = NULL;
- break;
- }
- }
+ rb_erase(&sd->inode_node, &sd->s_parent->s_dir.inode_tree);
+ rb_erase(&sd->name_node, &sd->s_parent->s_dir.name_tree);
}
/**
@@ -126,7 +149,6 @@ struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd)
*/
void sysfs_put_active(struct sysfs_dirent *sd)
{
- struct completion *cmpl;
int v;
if (unlikely(!sd))
@@ -138,10 +160,9 @@ void sysfs_put_active(struct sysfs_dirent *sd)
return;
/* atomic_dec_return() is a mb(), we'll always see the updated
- * sd->s_sibling.
+ * sd->u.completion.
*/
- cmpl = (void *)sd->s_sibling;
- complete(cmpl);
+ complete(sd->u.completion);
}
/**
@@ -155,16 +176,16 @@ static void sysfs_deactivate(struct sysfs_dirent *sd)
DECLARE_COMPLETION_ONSTACK(wait);
int v;
- BUG_ON(sd->s_sibling || !(sd->s_flags & SYSFS_FLAG_REMOVED));
+ BUG_ON(!(sd->s_flags & SYSFS_FLAG_REMOVED));
if (!(sysfs_type(sd) & SYSFS_ACTIVE_REF))
return;
- sd->s_sibling = (void *)&wait;
+ sd->u.completion = (void *)&wait;
rwsem_acquire(&sd->dep_map, 0, 0, _RET_IP_);
/* atomic_add_return() is a mb(), put_active() will always see
- * the updated sd->s_sibling.
+ * the updated sd->u.completion.
*/
v = atomic_add_return(SD_DEACTIVATED_BIAS, &sd->s_active);
@@ -173,8 +194,6 @@ static void sysfs_deactivate(struct sysfs_dirent *sd)
wait_for_completion(&wait);
}
- sd->s_sibling = NULL;
-
lock_acquired(&sd->dep_map, _RET_IP_);
rwsem_release(&sd->dep_map, 1, _RET_IP_);
}
@@ -384,6 +403,13 @@ int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
{
struct sysfs_inode_attrs *ps_iattr;
+ if (!!sysfs_ns_type(acxt->parent_sd) != !!sd->s_ns) {
+ WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n",
+ sysfs_ns_type(acxt->parent_sd)? "required": "invalid",
+ acxt->parent_sd->s_name, sd->s_name);
+ return -EINVAL;
+ }
+
if (sysfs_find_dirent(acxt->parent_sd, sd->s_ns, sd->s_name))
return -EEXIST;
@@ -490,7 +516,7 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
}
sd->s_flags |= SYSFS_FLAG_REMOVED;
- sd->s_sibling = acxt->removed;
+ sd->u.removed_list = acxt->removed;
acxt->removed = sd;
}
@@ -514,8 +540,7 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
while (acxt->removed) {
struct sysfs_dirent *sd = acxt->removed;
- acxt->removed = sd->s_sibling;
- sd->s_sibling = NULL;
+ acxt->removed = sd->u.removed_list;
sysfs_deactivate(sd);
unmap_bin_file(sd);
@@ -540,15 +565,43 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
const void *ns,
const unsigned char *name)
{
- struct sysfs_dirent *sd;
+ struct rb_node *p = parent_sd->s_dir.name_tree.rb_node;
+ struct sysfs_dirent *found = NULL;
- for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling) {
- if (ns && sd->s_ns && (sd->s_ns != ns))
- continue;
- if (!strcmp(sd->s_name, name))
- return sd;
+ if (!!sysfs_ns_type(parent_sd) != !!ns) {
+ WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n",
+ sysfs_ns_type(parent_sd)? "required": "invalid",
+ parent_sd->s_name, name);
+ return NULL;
}
- return NULL;
+
+ while (p) {
+ int c;
+#define node rb_entry(p, struct sysfs_dirent, name_node)
+ c = strcmp(name, node->s_name);
+ if (c < 0) {
+ p = node->name_node.rb_left;
+ } else if (c > 0) {
+ p = node->name_node.rb_right;
+ } else {
+ found = node;
+ p = node->name_node.rb_left;
+ }
+#undef node
+ }
+
+ if (found) {
+ while (found->s_ns != ns) {
+ p = rb_next(&found->name_node);
+ if (!p)
+ return NULL;
+ found = rb_entry(p, struct sysfs_dirent, name_node);
+ if (strcmp(name, found->s_name))
+ return NULL;
+ }
+ }
+
+ return found;
}
/**
@@ -744,21 +797,19 @@ void sysfs_remove_subdir(struct sysfs_dirent *sd)
static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
{
struct sysfs_addrm_cxt acxt;
- struct sysfs_dirent **pos;
+ struct rb_node *pos;
if (!dir_sd)
return;
pr_debug("sysfs %s: removing dir\n", dir_sd->s_name);
sysfs_addrm_start(&acxt, dir_sd);
- pos = &dir_sd->s_dir.children;
- while (*pos) {
- struct sysfs_dirent *sd = *pos;
-
+ pos = rb_first(&dir_sd->s_dir.inode_tree);
+ while (pos) {
+ struct sysfs_dirent *sd = rb_entry(pos, struct sysfs_dirent, inode_node);
+ pos = rb_next(pos);
if (sysfs_type(sd) != SYSFS_DIR)
sysfs_remove_one(&acxt, sd);
- else
- pos = &(*pos)->s_sibling;
}
sysfs_addrm_finish(&acxt);
@@ -881,12 +932,28 @@ static struct sysfs_dirent *sysfs_dir_pos(const void *ns,
pos = NULL;
}
if (!pos && (ino > 1) && (ino < INT_MAX)) {
- pos = parent_sd->s_dir.children;
- while (pos && (ino > pos->s_ino))
- pos = pos->s_sibling;
+ struct rb_node *p = parent_sd->s_dir.inode_tree.rb_node;
+ while (p) {
+#define node rb_entry(p, struct sysfs_dirent, inode_node)
+ if (ino < node->s_ino) {
+ pos = node;
+ p = node->inode_node.rb_left;
+ } else if (ino > node->s_ino) {
+ p = node->inode_node.rb_right;
+ } else {
+ pos = node;
+ break;
+ }
+#undef node
+ }
+ }
+ while (pos && pos->s_ns != ns) {
+ struct rb_node *p = rb_next(&pos->inode_node);
+ if (!p)
+ pos = NULL;
+ else
+ pos = rb_entry(p, struct sysfs_dirent, inode_node);
}
- while (pos && pos->s_ns && pos->s_ns != ns)
- pos = pos->s_sibling;
return pos;
}
@@ -894,10 +961,13 @@ static struct sysfs_dirent *sysfs_dir_next_pos(const void *ns,
struct sysfs_dirent *parent_sd, ino_t ino, struct sysfs_dirent *pos)
{
pos = sysfs_dir_pos(ns, parent_sd, ino, pos);
- if (pos)
- pos = pos->s_sibling;
- while (pos && pos->s_ns && pos->s_ns != ns)
- pos = pos->s_sibling;
+ if (pos) do {
+ struct rb_node *p = rb_next(&pos->inode_node);
+ if (!p)
+ pos = NULL;
+ else
+ pos = rb_entry(p, struct sysfs_dirent, inode_node);
+ } while (pos && pos->s_ns != ns);
return pos;
}
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 1ad8c93c1b85..d4e6080b4b20 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -466,9 +466,6 @@ void sysfs_notify(struct kobject *k, const char *dir, const char *attr)
mutex_lock(&sysfs_mutex);
if (sd && dir)
- /* Only directories are tagged, so no need to pass
- * a tag explicitly.
- */
sd = sysfs_find_dirent(sd, NULL, dir);
if (sd && attr)
sd = sysfs_find_dirent(sd, NULL, attr);
@@ -488,17 +485,56 @@ const struct file_operations sysfs_file_operations = {
.poll = sysfs_poll,
};
+int sysfs_attr_ns(struct kobject *kobj, const struct attribute *attr,
+ const void **pns)
+{
+ struct sysfs_dirent *dir_sd = kobj->sd;
+ const struct sysfs_ops *ops;
+ const void *ns = NULL;
+ int err;
+
+ err = 0;
+ if (!sysfs_ns_type(dir_sd))
+ goto out;
+
+ err = -EINVAL;
+ if (!kobj->ktype)
+ goto out;
+ ops = kobj->ktype->sysfs_ops;
+ if (!ops)
+ goto out;
+ if (!ops->namespace)
+ goto out;
+
+ err = 0;
+ ns = ops->namespace(kobj, attr);
+out:
+ if (err) {
+ WARN(1, KERN_ERR "missing sysfs namespace attribute operation for "
+ "kobject: %s\n", kobject_name(kobj));
+ }
+ *pns = ns;
+ return err;
+}
+
int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,
const struct attribute *attr, int type, mode_t amode)
{
umode_t mode = (amode & S_IALLUGO) | S_IFREG;
struct sysfs_addrm_cxt acxt;
struct sysfs_dirent *sd;
+ const void *ns;
int rc;
+ rc = sysfs_attr_ns(dir_sd->s_dir.kobj, attr, &ns);
+ if (rc)
+ return rc;
+
sd = sysfs_new_dirent(attr->name, mode, type);
if (!sd)
return -ENOMEM;
+
+ sd->s_ns = ns;
sd->s_attr.attr = (void *)attr;
sysfs_dirent_init_lockdep(sd);
@@ -586,12 +622,17 @@ int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr,
{
struct sysfs_dirent *sd;
struct iattr newattrs;
+ const void *ns;
int rc;
+ rc = sysfs_attr_ns(kobj, attr, &ns);
+ if (rc)
+ return rc;
+
mutex_lock(&sysfs_mutex);
rc = -ENOENT;
- sd = sysfs_find_dirent(kobj->sd, NULL, attr->name);
+ sd = sysfs_find_dirent(kobj->sd, ns, attr->name);
if (!sd)
goto out;
@@ -616,7 +657,12 @@ EXPORT_SYMBOL_GPL(sysfs_chmod_file);
void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr)
{
- sysfs_hash_and_remove(kobj->sd, NULL, attr->name);
+ const void *ns;
+
+ if (sysfs_attr_ns(kobj, attr, &ns))
+ return;
+
+ sysfs_hash_and_remove(kobj->sd, ns, attr->name);
}
void sysfs_remove_files(struct kobject * kobj, const struct attribute **ptr)
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index e3f091a81c72..e23f28894a3a 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -202,18 +202,6 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr)
inode->i_ctime = iattr->ia_ctime;
}
-static int sysfs_count_nlink(struct sysfs_dirent *sd)
-{
- struct sysfs_dirent *child;
- int nr = 0;
-
- for (child = sd->s_dir.children; child; child = child->s_sibling)
- if (sysfs_type(child) == SYSFS_DIR)
- nr++;
-
- return nr + 2;
-}
-
static void sysfs_refresh_inode(struct sysfs_dirent *sd, struct inode *inode)
{
struct sysfs_inode_attrs *iattrs = sd->s_iattr;
@@ -230,7 +218,7 @@ static void sysfs_refresh_inode(struct sysfs_dirent *sd, struct inode *inode)
}
if (sysfs_type(sd) == SYSFS_DIR)
- inode->i_nlink = sysfs_count_nlink(sd);
+ inode->i_nlink = sd->s_dir.subdirs + 2;
}
int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
@@ -336,8 +324,6 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, const cha
sysfs_addrm_start(&acxt, dir_sd);
sd = sysfs_find_dirent(dir_sd, ns, name);
- if (sd && (sd->s_ns != ns))
- sd = NULL;
if (sd)
sysfs_remove_one(&acxt, sd);
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 845ab3ad229d..ce29e28b766d 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -11,14 +11,18 @@
#include <linux/lockdep.h>
#include <linux/kobject_ns.h>
#include <linux/fs.h>
+#include <linux/rbtree.h>
struct sysfs_open_dirent;
/* type-specific structures for sysfs_dirent->s_* union members */
struct sysfs_elem_dir {
struct kobject *kobj;
- /* children list starts here and goes through sd->s_sibling */
- struct sysfs_dirent *children;
+
+ unsigned long subdirs;
+
+ struct rb_root inode_tree;
+ struct rb_root name_tree;
};
struct sysfs_elem_symlink {
@@ -56,9 +60,16 @@ struct sysfs_dirent {
struct lockdep_map dep_map;
#endif
struct sysfs_dirent *s_parent;
- struct sysfs_dirent *s_sibling;
const char *s_name;
+ struct rb_node inode_node;
+ struct rb_node name_node;
+
+ union {
+ struct completion *completion;
+ struct sysfs_dirent *removed_list;
+ } u;
+
const void *s_ns; /* namespace tag */
union {
struct sysfs_elem_dir s_dir;
diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h
index 45174b534377..feb361e252ac 100644
--- a/fs/ubifs/debug.h
+++ b/fs/ubifs/debug.h
@@ -335,9 +335,9 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
#define DBGKEY(key) ((char *)(key))
#define DBGKEY1(key) ((char *)(key))
-#define ubifs_dbg_msg(fmt, ...) do { \
- if (0) \
- pr_debug(fmt "\n", ##__VA_ARGS__); \
+#define ubifs_dbg_msg(fmt, ...) do { \
+ if (0) \
+ printk(KERN_DEBUG fmt "\n", ##__VA_ARGS__); \
} while (0)
#define dbg_dump_stack()
diff --git a/fs/xattr.c b/fs/xattr.c
index f060663ab70c..67583de8218c 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -14,6 +14,7 @@
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/security.h>
+#include <linux/evm.h>
#include <linux/syscalls.h>
#include <linux/module.h>
#include <linux/fsnotify.h>
@@ -166,6 +167,64 @@ out_noalloc:
}
EXPORT_SYMBOL_GPL(xattr_getsecurity);
+/*
+ * vfs_getxattr_alloc - allocate memory, if necessary, before calling getxattr
+ *
+ * Allocate memory, if not already allocated, or re-allocate correct size,
+ * before retrieving the extended attribute.
+ *
+ * Returns the result of alloc, if failed, or the getxattr operation.
+ */
+ssize_t
+vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value,
+ size_t xattr_size, gfp_t flags)
+{
+ struct inode *inode = dentry->d_inode;
+ char *value = *xattr_value;
+ int error;
+
+ error = xattr_permission(inode, name, MAY_READ);
+ if (error)
+ return error;
+
+ if (!inode->i_op->getxattr)
+ return -EOPNOTSUPP;
+
+ error = inode->i_op->getxattr(dentry, name, NULL, 0);
+ if (error < 0)
+ return error;
+
+ if (!value || (error > xattr_size)) {
+ value = krealloc(*xattr_value, error + 1, flags);
+ if (!value)
+ return -ENOMEM;
+ memset(value, 0, error + 1);
+ }
+
+ error = inode->i_op->getxattr(dentry, name, value, error);
+ *xattr_value = value;
+ return error;
+}
+
+/* Compare an extended attribute value with the given value */
+int vfs_xattr_cmp(struct dentry *dentry, const char *xattr_name,
+ const char *value, size_t size, gfp_t flags)
+{
+ char *xattr_value = NULL;
+ int rc;
+
+ rc = vfs_getxattr_alloc(dentry, xattr_name, &xattr_value, 0, flags);
+ if (rc < 0)
+ return rc;
+
+ if ((rc != size) || (memcmp(xattr_value, value, rc) != 0))
+ rc = -EINVAL;
+ else
+ rc = 0;
+ kfree(xattr_value);
+ return rc;
+}
+
ssize_t
vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
{
@@ -243,8 +302,10 @@ vfs_removexattr(struct dentry *dentry, const char *name)
error = inode->i_op->removexattr(dentry, name);
mutex_unlock(&inode->i_mutex);
- if (!error)
+ if (!error) {
fsnotify_xattr(dentry);
+ evm_inode_post_removexattr(dentry, name);
+ }
return error;
}
EXPORT_SYMBOL_GPL(vfs_removexattr);
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index 75bb316529dd..427a4e82a588 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -16,44 +16,53 @@
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
-ccflags-y := -I$(src) -I$(src)/linux-2.6
-ccflags-$(CONFIG_XFS_DEBUG) += -g
+ccflags-y += -I$(src) # needed for trace events
-XFS_LINUX := linux-2.6
+ccflags-$(CONFIG_XFS_DEBUG) += -g
obj-$(CONFIG_XFS_FS) += xfs.o
-xfs-y += linux-2.6/xfs_trace.o
-
-xfs-$(CONFIG_XFS_QUOTA) += $(addprefix quota/, \
- xfs_dquot.o \
- xfs_dquot_item.o \
- xfs_trans_dquot.o \
- xfs_qm_syscalls.o \
- xfs_qm_bhv.o \
- xfs_qm.o)
-xfs-$(CONFIG_XFS_QUOTA) += linux-2.6/xfs_quotaops.o
-
-ifeq ($(CONFIG_XFS_QUOTA),y)
-xfs-$(CONFIG_PROC_FS) += quota/xfs_qm_stats.o
-endif
-
-xfs-$(CONFIG_XFS_RT) += xfs_rtalloc.o
-xfs-$(CONFIG_XFS_POSIX_ACL) += $(XFS_LINUX)/xfs_acl.o
-xfs-$(CONFIG_PROC_FS) += $(XFS_LINUX)/xfs_stats.o
-xfs-$(CONFIG_SYSCTL) += $(XFS_LINUX)/xfs_sysctl.o
-xfs-$(CONFIG_COMPAT) += $(XFS_LINUX)/xfs_ioctl32.o
+# this one should be compiled first, as the tracing macros can easily blow up
+xfs-y += xfs_trace.o
+# highlevel code
+xfs-y += xfs_aops.o \
+ xfs_bit.o \
+ xfs_buf.o \
+ xfs_dfrag.o \
+ xfs_discard.o \
+ xfs_error.o \
+ xfs_export.o \
+ xfs_file.o \
+ xfs_filestream.o \
+ xfs_fsops.o \
+ xfs_fs_subr.o \
+ xfs_globals.o \
+ xfs_iget.o \
+ xfs_ioctl.o \
+ xfs_iomap.o \
+ xfs_iops.o \
+ xfs_itable.o \
+ xfs_message.o \
+ xfs_mru_cache.o \
+ xfs_super.o \
+ xfs_sync.o \
+ xfs_xattr.o \
+ xfs_rename.o \
+ xfs_rw.o \
+ xfs_utils.o \
+ xfs_vnodeops.o \
+ kmem.o \
+ uuid.o
+# code shared with libxfs
xfs-y += xfs_alloc.o \
xfs_alloc_btree.o \
xfs_attr.o \
xfs_attr_leaf.o \
- xfs_bit.o \
xfs_bmap.o \
xfs_bmap_btree.o \
xfs_btree.o \
- xfs_buf_item.o \
xfs_da_btree.o \
xfs_dir2.o \
xfs_dir2_block.o \
@@ -61,49 +70,37 @@ xfs-y += xfs_alloc.o \
xfs_dir2_leaf.o \
xfs_dir2_node.o \
xfs_dir2_sf.o \
- xfs_error.o \
- xfs_extfree_item.o \
- xfs_filestream.o \
- xfs_fsops.o \
xfs_ialloc.o \
xfs_ialloc_btree.o \
- xfs_iget.o \
xfs_inode.o \
- xfs_inode_item.o \
- xfs_iomap.o \
- xfs_itable.o \
- xfs_dfrag.o \
- xfs_log.o \
- xfs_log_cil.o \
xfs_log_recover.o \
xfs_mount.o \
- xfs_mru_cache.o \
- xfs_rename.o \
- xfs_trans.o \
+ xfs_trans.o
+
+# low-level transaction/log code
+xfs-y += xfs_log.o \
+ xfs_log_cil.o \
+ xfs_buf_item.o \
+ xfs_extfree_item.o \
+ xfs_inode_item.o \
xfs_trans_ail.o \
xfs_trans_buf.o \
xfs_trans_extfree.o \
xfs_trans_inode.o \
- xfs_utils.o \
- xfs_vnodeops.o \
- xfs_rw.o
-
-# Objects in linux/
-xfs-y += $(addprefix $(XFS_LINUX)/, \
- kmem.o \
- xfs_aops.o \
- xfs_buf.o \
- xfs_discard.o \
- xfs_export.o \
- xfs_file.o \
- xfs_fs_subr.o \
- xfs_globals.o \
- xfs_ioctl.o \
- xfs_iops.o \
- xfs_message.o \
- xfs_super.o \
- xfs_sync.o \
- xfs_xattr.o)
-# Objects in support/
-xfs-y += support/uuid.o
+# optional features
+xfs-$(CONFIG_XFS_QUOTA) += xfs_dquot.o \
+ xfs_dquot_item.o \
+ xfs_trans_dquot.o \
+ xfs_qm_syscalls.o \
+ xfs_qm_bhv.o \
+ xfs_qm.o \
+ xfs_quotaops.o
+ifeq ($(CONFIG_XFS_QUOTA),y)
+xfs-$(CONFIG_PROC_FS) += xfs_qm_stats.o
+endif
+xfs-$(CONFIG_XFS_RT) += xfs_rtalloc.o
+xfs-$(CONFIG_XFS_POSIX_ACL) += xfs_acl.o
+xfs-$(CONFIG_PROC_FS) += xfs_stats.o
+xfs-$(CONFIG_SYSCTL) += xfs_sysctl.o
+xfs-$(CONFIG_COMPAT) += xfs_ioctl32.o
diff --git a/fs/xfs/linux-2.6/kmem.c b/fs/xfs/kmem.c
index a907de565db3..a907de565db3 100644
--- a/fs/xfs/linux-2.6/kmem.c
+++ b/fs/xfs/kmem.c
diff --git a/fs/xfs/linux-2.6/kmem.h b/fs/xfs/kmem.h
index f7c8f7a9ea6d..292eff198030 100644
--- a/fs/xfs/linux-2.6/kmem.h
+++ b/fs/xfs/kmem.h
@@ -61,12 +61,7 @@ extern void kmem_free(const void *);
static inline void *kmem_zalloc_large(size_t size)
{
- void *ptr;
-
- ptr = vmalloc(size);
- if (ptr)
- memset(ptr, 0, size);
- return ptr;
+ return vzalloc(size);
}
static inline void kmem_free_large(void *ptr)
{
diff --git a/fs/xfs/linux-2.6/mrlock.h b/fs/xfs/mrlock.h
index ff6a19873e5c..ff6a19873e5c 100644
--- a/fs/xfs/linux-2.6/mrlock.h
+++ b/fs/xfs/mrlock.h
diff --git a/fs/xfs/linux-2.6/time.h b/fs/xfs/time.h
index 387e695a184c..387e695a184c 100644
--- a/fs/xfs/linux-2.6/time.h
+++ b/fs/xfs/time.h
diff --git a/fs/xfs/support/uuid.c b/fs/xfs/uuid.c
index b83f76b6d410..b83f76b6d410 100644
--- a/fs/xfs/support/uuid.c
+++ b/fs/xfs/uuid.c
diff --git a/fs/xfs/support/uuid.h b/fs/xfs/uuid.h
index 4732d71262cc..4732d71262cc 100644
--- a/fs/xfs/support/uuid.h
+++ b/fs/xfs/uuid.h
diff --git a/fs/xfs/xfs.h b/fs/xfs/xfs.h
index 53ec3ea9a625..d8b11b7f94aa 100644
--- a/fs/xfs/xfs.h
+++ b/fs/xfs/xfs.h
@@ -24,5 +24,6 @@
#define XFS_BUF_LOCK_TRACKING 1
#endif
-#include <linux-2.6/xfs_linux.h>
+#include "xfs_linux.h"
+
#endif /* __XFS_H__ */
diff --git a/fs/xfs/linux-2.6/xfs_acl.c b/fs/xfs/xfs_acl.c
index b6c4b3795c4a..b6c4b3795c4a 100644
--- a/fs/xfs/linux-2.6/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/xfs_aops.c
index 63e971e2b837..8c37dde4c521 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -1300,6 +1300,7 @@ xfs_end_io_direct_write(
bool is_async)
{
struct xfs_ioend *ioend = iocb->private;
+ struct inode *inode = ioend->io_inode;
/*
* blockdev_direct_IO can return an error even after the I/O
@@ -1331,7 +1332,7 @@ xfs_end_io_direct_write(
}
/* XXX: probably should move into the real I/O completion handler */
- inode_dio_done(ioend->io_inode);
+ inode_dio_done(inode);
}
STATIC ssize_t
diff --git a/fs/xfs/linux-2.6/xfs_aops.h b/fs/xfs/xfs_aops.h
index 71f721e1a71f..71f721e1a71f 100644
--- a/fs/xfs/linux-2.6/xfs_aops.h
+++ b/fs/xfs/xfs_aops.h
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/xfs_buf.c
index c57836dc778f..c57836dc778f 100644
--- a/fs/xfs/linux-2.6/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/xfs_buf.h
index 620972b8094d..620972b8094d 100644
--- a/fs/xfs/linux-2.6/xfs_buf.h
+++ b/fs/xfs/xfs_buf.h
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index cac2ecfa6746..ef43fce519a1 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -629,7 +629,7 @@ xfs_buf_item_push(
* the xfsbufd to get this buffer written. We have to unlock the buffer
* to allow the xfsbufd to write it, too.
*/
-STATIC void
+STATIC bool
xfs_buf_item_pushbuf(
struct xfs_log_item *lip)
{
@@ -643,6 +643,7 @@ xfs_buf_item_pushbuf(
xfs_buf_delwri_promote(bp);
xfs_buf_relse(bp);
+ return true;
}
STATIC void
diff --git a/fs/xfs/linux-2.6/xfs_discard.c b/fs/xfs/xfs_discard.c
index 244e797dae32..244e797dae32 100644
--- a/fs/xfs/linux-2.6/xfs_discard.c
+++ b/fs/xfs/xfs_discard.c
diff --git a/fs/xfs/linux-2.6/xfs_discard.h b/fs/xfs/xfs_discard.h
index 344879aea646..344879aea646 100644
--- a/fs/xfs/linux-2.6/xfs_discard.h
+++ b/fs/xfs/xfs_discard.h
diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index db62959bed13..db62959bed13 100644
--- a/fs/xfs/quota/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
diff --git a/fs/xfs/quota/xfs_dquot.h b/fs/xfs/xfs_dquot.h
index 34b7e945dbfa..34b7e945dbfa 100644
--- a/fs/xfs/quota/xfs_dquot.h
+++ b/fs/xfs/xfs_dquot.h
diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/xfs_dquot_item.c
index 9e0e2fa3f2c8..bb3f71d236d2 100644
--- a/fs/xfs/quota/xfs_dquot_item.c
+++ b/fs/xfs/xfs_dquot_item.c
@@ -183,13 +183,14 @@ xfs_qm_dqunpin_wait(
* search the buffer cache can be a time consuming thing, and AIL lock is a
* spinlock.
*/
-STATIC void
+STATIC bool
xfs_qm_dquot_logitem_pushbuf(
struct xfs_log_item *lip)
{
struct xfs_dq_logitem *qlip = DQUOT_ITEM(lip);
struct xfs_dquot *dqp = qlip->qli_dquot;
struct xfs_buf *bp;
+ bool ret = true;
ASSERT(XFS_DQ_IS_LOCKED(dqp));
@@ -201,17 +202,20 @@ xfs_qm_dquot_logitem_pushbuf(
if (completion_done(&dqp->q_flush) ||
!(lip->li_flags & XFS_LI_IN_AIL)) {
xfs_dqunlock(dqp);
- return;
+ return true;
}
bp = xfs_incore(dqp->q_mount->m_ddev_targp, qlip->qli_format.qlf_blkno,
dqp->q_mount->m_quotainfo->qi_dqchunklen, XBF_TRYLOCK);
xfs_dqunlock(dqp);
if (!bp)
- return;
+ return true;
if (XFS_BUF_ISDELAYWRITE(bp))
xfs_buf_delwri_promote(bp);
+ if (xfs_buf_ispinned(bp))
+ ret = false;
xfs_buf_relse(bp);
+ return ret;
}
/*
diff --git a/fs/xfs/quota/xfs_dquot_item.h b/fs/xfs/xfs_dquot_item.h
index 5acae2ada70b..5acae2ada70b 100644
--- a/fs/xfs/quota/xfs_dquot_item.h
+++ b/fs/xfs/xfs_dquot_item.h
diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/xfs_export.c
index 75e5d322e48f..75e5d322e48f 100644
--- a/fs/xfs/linux-2.6/xfs_export.c
+++ b/fs/xfs/xfs_export.c
diff --git a/fs/xfs/linux-2.6/xfs_export.h b/fs/xfs/xfs_export.h
index 3272b6ae7a35..3272b6ae7a35 100644
--- a/fs/xfs/linux-2.6/xfs_export.h
+++ b/fs/xfs/xfs_export.h
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/xfs_file.c
index 7f7b42469ea7..7f7b42469ea7 100644
--- a/fs/xfs/linux-2.6/xfs_file.c
+++ b/fs/xfs/xfs_file.c
diff --git a/fs/xfs/linux-2.6/xfs_fs_subr.c b/fs/xfs/xfs_fs_subr.c
index ed88ed16811c..ed88ed16811c 100644
--- a/fs/xfs/linux-2.6/xfs_fs_subr.c
+++ b/fs/xfs/xfs_fs_subr.c
diff --git a/fs/xfs/linux-2.6/xfs_globals.c b/fs/xfs/xfs_globals.c
index 76e81cff70b9..76e81cff70b9 100644
--- a/fs/xfs/linux-2.6/xfs_globals.c
+++ b/fs/xfs/xfs_globals.c
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index 588406dc6a35..836ad80d4f2b 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -708,13 +708,14 @@ xfs_inode_item_committed(
* marked delayed write. If that's the case, we'll promote it and that will
* allow the caller to write the buffer by triggering the xfsbufd to run.
*/
-STATIC void
+STATIC bool
xfs_inode_item_pushbuf(
struct xfs_log_item *lip)
{
struct xfs_inode_log_item *iip = INODE_ITEM(lip);
struct xfs_inode *ip = iip->ili_inode;
struct xfs_buf *bp;
+ bool ret = true;
ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED));
@@ -725,7 +726,7 @@ xfs_inode_item_pushbuf(
if (completion_done(&ip->i_flush) ||
!(lip->li_flags & XFS_LI_IN_AIL)) {
xfs_iunlock(ip, XFS_ILOCK_SHARED);
- return;
+ return true;
}
bp = xfs_incore(ip->i_mount->m_ddev_targp, iip->ili_format.ilf_blkno,
@@ -733,10 +734,13 @@ xfs_inode_item_pushbuf(
xfs_iunlock(ip, XFS_ILOCK_SHARED);
if (!bp)
- return;
+ return true;
if (XFS_BUF_ISDELAYWRITE(bp))
xfs_buf_delwri_promote(bp);
+ if (xfs_buf_ispinned(bp))
+ ret = false;
xfs_buf_relse(bp);
+ return ret;
}
/*
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index f7ce7debe14c..f7ce7debe14c 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.h b/fs/xfs/xfs_ioctl.h
index d56173b34a2a..d56173b34a2a 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.h
+++ b/fs/xfs/xfs_ioctl.h
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c
index 54e623bfbb85..54e623bfbb85 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl32.c
+++ b/fs/xfs/xfs_ioctl32.c
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.h b/fs/xfs/xfs_ioctl32.h
index 80f4060e8970..80f4060e8970 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl32.h
+++ b/fs/xfs/xfs_ioctl32.h
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/xfs_iops.c
index b9c172b3fbbe..28856accb4fa 100644
--- a/fs/xfs/linux-2.6/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -70,9 +70,8 @@ xfs_synchronize_times(
}
/*
- * If the linux inode is valid, mark it dirty.
- * Used when committing a dirty inode into a transaction so that
- * the inode will get written back by the linux code
+ * If the linux inode is valid, mark it dirty, else mark the dirty state
+ * in the XFS inode to make sure we pick it up when reclaiming the inode.
*/
void
xfs_mark_inode_dirty_sync(
@@ -82,6 +81,10 @@ xfs_mark_inode_dirty_sync(
if (!(inode->i_state & (I_WILL_FREE|I_FREEING)))
mark_inode_dirty_sync(inode);
+ else {
+ barrier();
+ ip->i_update_core = 1;
+ }
}
void
@@ -92,6 +95,28 @@ xfs_mark_inode_dirty(
if (!(inode->i_state & (I_WILL_FREE|I_FREEING)))
mark_inode_dirty(inode);
+ else {
+ barrier();
+ ip->i_update_core = 1;
+ }
+
+}
+
+
+int xfs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
+ void *fs_info)
+{
+ const struct xattr *xattr;
+ struct xfs_inode *ip = XFS_I(inode);
+ int error = 0;
+
+ for (xattr = xattr_array; xattr->name != NULL; xattr++) {
+ error = xfs_attr_set(ip, xattr->name, xattr->value,
+ xattr->value_len, ATTR_SECURE);
+ if (error < 0)
+ break;
+ }
+ return error;
}
/*
@@ -100,31 +125,15 @@ xfs_mark_inode_dirty(
* these attrs can be journalled at inode creation time (along with the
* inode, of course, such that log replay can't cause these to be lost).
*/
+
STATIC int
xfs_init_security(
struct inode *inode,
struct inode *dir,
const struct qstr *qstr)
{
- struct xfs_inode *ip = XFS_I(inode);
- size_t length;
- void *value;
- unsigned char *name;
- int error;
-
- error = security_inode_init_security(inode, dir, qstr, (char **)&name,
- &value, &length);
- if (error) {
- if (error == -EOPNOTSUPP)
- return 0;
- return -error;
- }
-
- error = xfs_attr_set(ip, name, value, length, ATTR_SECURE);
-
- kfree(name);
- kfree(value);
- return error;
+ return security_inode_init_security(inode, dir, qstr,
+ &xfs_initxattrs, NULL);
}
static void
diff --git a/fs/xfs/linux-2.6/xfs_iops.h b/fs/xfs/xfs_iops.h
index ef41c92ce66e..ef41c92ce66e 100644
--- a/fs/xfs/linux-2.6/xfs_iops.h
+++ b/fs/xfs/xfs_iops.h
diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/xfs_linux.h
index d42f814e4d35..828662f70d64 100644
--- a/fs/xfs/linux-2.6/xfs_linux.h
+++ b/fs/xfs/xfs_linux.h
@@ -32,13 +32,12 @@
# define XFS_BIG_INUMS 0
#endif
-#include <xfs_types.h>
+#include "xfs_types.h"
-#include <kmem.h>
-#include <mrlock.h>
-#include <time.h>
-
-#include <support/uuid.h>
+#include "kmem.h"
+#include "mrlock.h"
+#include "time.h"
+#include "uuid.h"
#include <linux/semaphore.h>
#include <linux/mm.h>
@@ -69,6 +68,8 @@
#include <linux/ctype.h>
#include <linux/writeback.h>
#include <linux/capability.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
#include <linux/list_sort.h>
#include <asm/page.h>
@@ -78,14 +79,14 @@
#include <asm/byteorder.h>
#include <asm/unaligned.h>
-#include <xfs_vnode.h>
-#include <xfs_stats.h>
-#include <xfs_sysctl.h>
-#include <xfs_iops.h>
-#include <xfs_aops.h>
-#include <xfs_super.h>
-#include <xfs_buf.h>
-#include <xfs_message.h>
+#include "xfs_vnode.h"
+#include "xfs_stats.h"
+#include "xfs_sysctl.h"
+#include "xfs_iops.h"
+#include "xfs_aops.h"
+#include "xfs_super.h"
+#include "xfs_buf.h"
+#include "xfs_message.h"
#ifdef __BIG_ENDIAN
#define XFS_NATIVE_HOST 1
diff --git a/fs/xfs/linux-2.6/xfs_message.c b/fs/xfs/xfs_message.c
index bd672def95ac..bd672def95ac 100644
--- a/fs/xfs/linux-2.6/xfs_message.c
+++ b/fs/xfs/xfs_message.c
diff --git a/fs/xfs/linux-2.6/xfs_message.h b/fs/xfs/xfs_message.h
index 7fb7ea007672..7fb7ea007672 100644
--- a/fs/xfs/linux-2.6/xfs_message.h
+++ b/fs/xfs/xfs_message.h
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/xfs_qm.c
index 9a0aa76facdf..9a0aa76facdf 100644
--- a/fs/xfs/quota/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
diff --git a/fs/xfs/quota/xfs_qm.h b/fs/xfs/xfs_qm.h
index 43b9abe1052c..43b9abe1052c 100644
--- a/fs/xfs/quota/xfs_qm.h
+++ b/fs/xfs/xfs_qm.h
diff --git a/fs/xfs/quota/xfs_qm_bhv.c b/fs/xfs/xfs_qm_bhv.c
index a0a829addca9..a0a829addca9 100644
--- a/fs/xfs/quota/xfs_qm_bhv.c
+++ b/fs/xfs/xfs_qm_bhv.c
diff --git a/fs/xfs/quota/xfs_qm_stats.c b/fs/xfs/xfs_qm_stats.c
index 8671a0b32644..8671a0b32644 100644
--- a/fs/xfs/quota/xfs_qm_stats.c
+++ b/fs/xfs/xfs_qm_stats.c
diff --git a/fs/xfs/quota/xfs_qm_stats.h b/fs/xfs/xfs_qm_stats.h
index 5b964fc0dc09..5b964fc0dc09 100644
--- a/fs/xfs/quota/xfs_qm_stats.h
+++ b/fs/xfs/xfs_qm_stats.h
diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index 609246f42e6c..609246f42e6c 100644
--- a/fs/xfs/quota/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
diff --git a/fs/xfs/quota/xfs_quota_priv.h b/fs/xfs/xfs_quota_priv.h
index 94a3d927d716..94a3d927d716 100644
--- a/fs/xfs/quota/xfs_quota_priv.h
+++ b/fs/xfs/xfs_quota_priv.h
diff --git a/fs/xfs/linux-2.6/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
index 29b9d642e93d..7e76f537abb7 100644
--- a/fs/xfs/linux-2.6/xfs_quotaops.c
+++ b/fs/xfs/xfs_quotaops.c
@@ -25,7 +25,7 @@
#include "xfs_trans.h"
#include "xfs_bmap_btree.h"
#include "xfs_inode.h"
-#include "quota/xfs_qm.h"
+#include "xfs_qm.h"
#include <linux/quota.h>
diff --git a/fs/xfs/linux-2.6/xfs_stats.c b/fs/xfs/xfs_stats.c
index 76fdc5861932..76fdc5861932 100644
--- a/fs/xfs/linux-2.6/xfs_stats.c
+++ b/fs/xfs/xfs_stats.c
diff --git a/fs/xfs/linux-2.6/xfs_stats.h b/fs/xfs/xfs_stats.h
index 736854b1ca1a..736854b1ca1a 100644
--- a/fs/xfs/linux-2.6/xfs_stats.h
+++ b/fs/xfs/xfs_stats.h
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/xfs_super.c
index 9a72dda58bd0..5cf06b85fd9d 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -356,6 +356,8 @@ xfs_parseargs(
mp->m_flags |= XFS_MOUNT_DELAYLOG;
} else if (!strcmp(this_char, MNTOPT_NODELAYLOG)) {
mp->m_flags &= ~XFS_MOUNT_DELAYLOG;
+ xfs_warn(mp,
+ "nodelaylog is deprecated and will be removed in Linux 3.3");
} else if (!strcmp(this_char, MNTOPT_DISCARD)) {
mp->m_flags |= XFS_MOUNT_DISCARD;
} else if (!strcmp(this_char, MNTOPT_NODISCARD)) {
@@ -877,33 +879,17 @@ xfs_log_inode(
struct xfs_trans *tp;
int error;
- xfs_iunlock(ip, XFS_ILOCK_SHARED);
tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);
error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
-
if (error) {
xfs_trans_cancel(tp, 0);
- /* we need to return with the lock hold shared */
- xfs_ilock(ip, XFS_ILOCK_SHARED);
return error;
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
-
- /*
- * Note - it's possible that we might have pushed ourselves out of the
- * way during trans_reserve which would flush the inode. But there's
- * no guarantee that the inode buffer has actually gone out yet (it's
- * delwri). Plus the buffer could be pinned anyway if it's part of
- * an inode in another recent transaction. So we play it safe and
- * fire off the transaction anyway.
- */
- xfs_trans_ijoin(tp, ip);
+ xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
- error = xfs_trans_commit(tp, 0);
- xfs_ilock_demote(ip, XFS_ILOCK_EXCL);
-
- return error;
+ return xfs_trans_commit(tp, 0);
}
STATIC int
@@ -918,7 +904,9 @@ xfs_fs_write_inode(
trace_xfs_write_inode(ip);
if (XFS_FORCED_SHUTDOWN(mp))
- return XFS_ERROR(EIO);
+ return -XFS_ERROR(EIO);
+ if (!ip->i_update_core)
+ return 0;
if (wbc->sync_mode == WB_SYNC_ALL) {
/*
@@ -929,12 +917,10 @@ xfs_fs_write_inode(
* of synchronous log foces dramatically.
*/
xfs_ioend_wait(ip);
- xfs_ilock(ip, XFS_ILOCK_SHARED);
- if (ip->i_update_core) {
- error = xfs_log_inode(ip);
- if (error)
- goto out_unlock;
- }
+ error = xfs_log_inode(ip);
+ if (error)
+ goto out;
+ return 0;
} else {
/*
* We make this non-blocking if the inode is contended, return
@@ -1666,24 +1652,13 @@ xfs_init_workqueues(void)
*/
xfs_syncd_wq = alloc_workqueue("xfssyncd", WQ_CPU_INTENSIVE, 8);
if (!xfs_syncd_wq)
- goto out;
-
- xfs_ail_wq = alloc_workqueue("xfsail", WQ_CPU_INTENSIVE, 8);
- if (!xfs_ail_wq)
- goto out_destroy_syncd;
-
+ return -ENOMEM;
return 0;
-
-out_destroy_syncd:
- destroy_workqueue(xfs_syncd_wq);
-out:
- return -ENOMEM;
}
STATIC void
xfs_destroy_workqueues(void)
{
- destroy_workqueue(xfs_ail_wq);
destroy_workqueue(xfs_syncd_wq);
}
diff --git a/fs/xfs/linux-2.6/xfs_super.h b/fs/xfs/xfs_super.h
index 50a3266c999e..50a3266c999e 100644
--- a/fs/xfs/linux-2.6/xfs_super.h
+++ b/fs/xfs/xfs_super.h
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/xfs_sync.c
index 4604f90f86a3..4604f90f86a3 100644
--- a/fs/xfs/linux-2.6/xfs_sync.c
+++ b/fs/xfs/xfs_sync.c
diff --git a/fs/xfs/linux-2.6/xfs_sync.h b/fs/xfs/xfs_sync.h
index 941202e7ac6e..941202e7ac6e 100644
--- a/fs/xfs/linux-2.6/xfs_sync.h
+++ b/fs/xfs/xfs_sync.h
diff --git a/fs/xfs/linux-2.6/xfs_sysctl.c b/fs/xfs/xfs_sysctl.c
index ee2d2adaa438..ee2d2adaa438 100644
--- a/fs/xfs/linux-2.6/xfs_sysctl.c
+++ b/fs/xfs/xfs_sysctl.c
diff --git a/fs/xfs/linux-2.6/xfs_sysctl.h b/fs/xfs/xfs_sysctl.h
index b9937d450f8e..b9937d450f8e 100644
--- a/fs/xfs/linux-2.6/xfs_sysctl.h
+++ b/fs/xfs/xfs_sysctl.h
diff --git a/fs/xfs/linux-2.6/xfs_trace.c b/fs/xfs/xfs_trace.c
index 88d25d4aa56e..9010ce885e6a 100644
--- a/fs/xfs/linux-2.6/xfs_trace.c
+++ b/fs/xfs/xfs_trace.c
@@ -43,8 +43,8 @@
#include "xfs_quota.h"
#include "xfs_iomap.h"
#include "xfs_aops.h"
-#include "quota/xfs_dquot_item.h"
-#include "quota/xfs_dquot.h"
+#include "xfs_dquot_item.h"
+#include "xfs_dquot.h"
#include "xfs_log_recover.h"
#include "xfs_inode_item.h"
diff --git a/fs/xfs/linux-2.6/xfs_trace.h b/fs/xfs/xfs_trace.h
index 690fc7a7bd72..690fc7a7bd72 100644
--- a/fs/xfs/linux-2.6/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index 06a9759b6352..53597f4db9b5 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -350,7 +350,7 @@ typedef struct xfs_item_ops {
void (*iop_unlock)(xfs_log_item_t *);
xfs_lsn_t (*iop_committed)(xfs_log_item_t *, xfs_lsn_t);
void (*iop_push)(xfs_log_item_t *);
- void (*iop_pushbuf)(xfs_log_item_t *);
+ bool (*iop_pushbuf)(xfs_log_item_t *);
void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t);
} xfs_item_ops_t;
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
index c15aa29fa169..3a1e7ca54c2d 100644
--- a/fs/xfs/xfs_trans_ail.c
+++ b/fs/xfs/xfs_trans_ail.c
@@ -28,8 +28,6 @@
#include "xfs_trans_priv.h"
#include "xfs_error.h"
-struct workqueue_struct *xfs_ail_wq; /* AIL workqueue */
-
#ifdef DEBUG
/*
* Check that the list is sorted as it should be.
@@ -356,16 +354,10 @@ xfs_ail_delete(
xfs_trans_ail_cursor_clear(ailp, lip);
}
-/*
- * xfs_ail_worker does the work of pushing on the AIL. It will requeue itself
- * to run at a later time if there is more work to do to complete the push.
- */
-STATIC void
-xfs_ail_worker(
- struct work_struct *work)
+static long
+xfsaild_push(
+ struct xfs_ail *ailp)
{
- struct xfs_ail *ailp = container_of(to_delayed_work(work),
- struct xfs_ail, xa_work);
xfs_mount_t *mp = ailp->xa_mount;
struct xfs_ail_cursor cur;
xfs_log_item_t *lip;
@@ -427,8 +419,13 @@ xfs_ail_worker(
case XFS_ITEM_PUSHBUF:
XFS_STATS_INC(xs_push_ail_pushbuf);
- IOP_PUSHBUF(lip);
- ailp->xa_last_pushed_lsn = lsn;
+
+ if (!IOP_PUSHBUF(lip)) {
+ stuck++;
+ flush_log = 1;
+ } else {
+ ailp->xa_last_pushed_lsn = lsn;
+ }
push_xfsbufd = 1;
break;
@@ -440,7 +437,6 @@ xfs_ail_worker(
case XFS_ITEM_LOCKED:
XFS_STATS_INC(xs_push_ail_locked);
- ailp->xa_last_pushed_lsn = lsn;
stuck++;
break;
@@ -501,20 +497,6 @@ out_done:
/* We're past our target or empty, so idle */
ailp->xa_last_pushed_lsn = 0;
- /*
- * We clear the XFS_AIL_PUSHING_BIT first before checking
- * whether the target has changed. If the target has changed,
- * this pushes the requeue race directly onto the result of the
- * atomic test/set bit, so we are guaranteed that either the
- * the pusher that changed the target or ourselves will requeue
- * the work (but not both).
- */
- clear_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags);
- smp_rmb();
- if (XFS_LSN_CMP(ailp->xa_target, target) == 0 ||
- test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags))
- return;
-
tout = 50;
} else if (XFS_LSN_CMP(lsn, target) >= 0) {
/*
@@ -537,9 +519,30 @@ out_done:
tout = 20;
}
- /* There is more to do, requeue us. */
- queue_delayed_work(xfs_syncd_wq, &ailp->xa_work,
- msecs_to_jiffies(tout));
+ return tout;
+}
+
+static int
+xfsaild(
+ void *data)
+{
+ struct xfs_ail *ailp = data;
+ long tout = 0; /* milliseconds */
+
+ while (!kthread_should_stop()) {
+ if (tout && tout <= 20)
+ __set_current_state(TASK_KILLABLE);
+ else
+ __set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(tout ?
+ msecs_to_jiffies(tout) : MAX_SCHEDULE_TIMEOUT);
+
+ try_to_freeze();
+
+ tout = xfsaild_push(ailp);
+ }
+
+ return 0;
}
/*
@@ -574,8 +577,9 @@ xfs_ail_push(
*/
smp_wmb();
xfs_trans_ail_copy_lsn(ailp, &ailp->xa_target, &threshold_lsn);
- if (!test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags))
- queue_delayed_work(xfs_syncd_wq, &ailp->xa_work, 0);
+ smp_wmb();
+
+ wake_up_process(ailp->xa_task);
}
/*
@@ -813,9 +817,18 @@ xfs_trans_ail_init(
INIT_LIST_HEAD(&ailp->xa_ail);
INIT_LIST_HEAD(&ailp->xa_cursors);
spin_lock_init(&ailp->xa_lock);
- INIT_DELAYED_WORK(&ailp->xa_work, xfs_ail_worker);
+
+ ailp->xa_task = kthread_run(xfsaild, ailp, "xfsaild/%s",
+ ailp->xa_mount->m_fsname);
+ if (IS_ERR(ailp->xa_task))
+ goto out_free_ailp;
+
mp->m_ail = ailp;
return 0;
+
+out_free_ailp:
+ kmem_free(ailp);
+ return ENOMEM;
}
void
@@ -824,6 +837,6 @@ xfs_trans_ail_destroy(
{
struct xfs_ail *ailp = mp->m_ail;
- cancel_delayed_work_sync(&ailp->xa_work);
+ kthread_stop(ailp->xa_task);
kmem_free(ailp);
}
diff --git a/fs/xfs/quota/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index 4d00ee67792d..4d00ee67792d 100644
--- a/fs/xfs/quota/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h
index 212946b97239..22750b5e4a8f 100644
--- a/fs/xfs/xfs_trans_priv.h
+++ b/fs/xfs/xfs_trans_priv.h
@@ -64,23 +64,17 @@ struct xfs_ail_cursor {
*/
struct xfs_ail {
struct xfs_mount *xa_mount;
+ struct task_struct *xa_task;
struct list_head xa_ail;
xfs_lsn_t xa_target;
struct list_head xa_cursors;
spinlock_t xa_lock;
- struct delayed_work xa_work;
xfs_lsn_t xa_last_pushed_lsn;
- unsigned long xa_flags;
};
-#define XFS_AIL_PUSHING_BIT 0
-
/*
* From xfs_trans_ail.c
*/
-
-extern struct workqueue_struct *xfs_ail_wq; /* AIL workqueue */
-
void xfs_trans_ail_update_bulk(struct xfs_ail *ailp,
struct xfs_ail_cursor *cur,
struct xfs_log_item **log_items, int nr_items,
diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/xfs_vnode.h
index 7c220b4227bc..7c220b4227bc 100644
--- a/fs/xfs/linux-2.6/xfs_vnode.h
+++ b/fs/xfs/xfs_vnode.h
diff --git a/fs/xfs/linux-2.6/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index 87d3e03878c8..87d3e03878c8 100644
--- a/fs/xfs/linux-2.6/xfs_xattr.c
+++ b/fs/xfs/xfs_xattr.c
diff --git a/include/asm-generic/fcntl.h b/include/asm-generic/fcntl.h
index 84793c7025e2..9e5b0356e2bb 100644
--- a/include/asm-generic/fcntl.h
+++ b/include/asm-generic/fcntl.h
@@ -145,11 +145,6 @@ struct f_owner_ex {
#define F_SHLCK 8 /* or 4 */
#endif
-/* for leases */
-#ifndef F_INPROGRESS
-#define F_INPROGRESS 16
-#endif
-
/* operations for bsd flock(), also used by the kernel implementation */
#define LOCK_SH 1 /* shared lock */
#define LOCK_EX 2 /* exclusive lock */
diff --git a/include/asm-generic/unistd.h b/include/asm-generic/unistd.h
index 4f76959397fa..f4c38d8c6674 100644
--- a/include/asm-generic/unistd.h
+++ b/include/asm-generic/unistd.h
@@ -143,7 +143,7 @@ __SYSCALL(__NR_pivot_root, sys_pivot_root)
/* fs/nfsctl.c */
#define __NR_nfsservctl 42
-__SC_COMP(__NR_nfsservctl, sys_nfsservctl, compat_sys_nfsservctl)
+__SYSCALL(__NR_nfsservctl, sys_ni_syscall)
/* fs/open.c */
#define __NR3264_statfs 43
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index db22d136ad08..b5e2e4c6b017 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -222,7 +222,6 @@
VMLINUX_SYMBOL(__start___tracepoints_ptrs) = .; \
*(__tracepoints_ptrs) /* Tracepoints: pointer array */\
VMLINUX_SYMBOL(__stop___tracepoints_ptrs) = .; \
- *(__markers_strings) /* Markers: strings */ \
*(__tracepoints_strings)/* Tracepoints: strings */ \
} \
\
diff --git a/include/linux/atalk.h b/include/linux/atalk.h
index d34c187432ed..f57c36881c48 100644
--- a/include/linux/atalk.h
+++ b/include/linux/atalk.h
@@ -3,6 +3,7 @@
#include <linux/types.h>
#include <asm/byteorder.h>
+#include <linux/socket.h>
/*
* AppleTalk networking structures
@@ -28,7 +29,7 @@ struct atalk_addr {
};
struct sockaddr_at {
- sa_family_t sat_family;
+ __kernel_sa_family_t sat_family;
__u8 sat_port;
struct atalk_addr sat_addr;
char sat_zero[8];
diff --git a/include/linux/ax25.h b/include/linux/ax25.h
index 56c11f0dbd80..74c89a41732d 100644
--- a/include/linux/ax25.h
+++ b/include/linux/ax25.h
@@ -47,7 +47,7 @@ typedef struct {
} ax25_address;
struct sockaddr_ax25 {
- sa_family_t sax25_family;
+ __kernel_sa_family_t sax25_family;
ax25_address sax25_call;
int sax25_ndigis;
/* Digipeater ax25_address sets follow */
diff --git a/include/linux/basic_mmio_gpio.h b/include/linux/basic_mmio_gpio.h
index 98999cf107ce..feb912196745 100644
--- a/include/linux/basic_mmio_gpio.h
+++ b/include/linux/basic_mmio_gpio.h
@@ -63,15 +63,10 @@ static inline struct bgpio_chip *to_bgpio_chip(struct gpio_chip *gc)
return container_of(gc, struct bgpio_chip, gc);
}
-int __devexit bgpio_remove(struct bgpio_chip *bgc);
-int __devinit bgpio_init(struct bgpio_chip *bgc,
- struct device *dev,
- unsigned long sz,
- void __iomem *dat,
- void __iomem *set,
- void __iomem *clr,
- void __iomem *dirout,
- void __iomem *dirin,
- bool big_endian);
+int bgpio_remove(struct bgpio_chip *bgc);
+int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
+ unsigned long sz, void __iomem *dat, void __iomem *set,
+ void __iomem *clr, void __iomem *dirout, void __iomem *dirin,
+ bool big_endian);
#endif /* __BASIC_MMIO_GPIO_H */
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index 8c96654bef16..5dbd7055cb86 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -6,6 +6,7 @@
#include <linux/bcma/bcma_driver_chipcommon.h>
#include <linux/bcma/bcma_driver_pci.h>
+#include <linux/bcma/bcma_driver_mips.h>
#include <linux/ssb/ssb.h> /* SPROM sharing */
#include "bcma_regs.h"
@@ -14,9 +15,9 @@ struct bcma_device;
struct bcma_bus;
enum bcma_hosttype {
- BCMA_HOSTTYPE_NONE,
BCMA_HOSTTYPE_PCI,
BCMA_HOSTTYPE_SDIO,
+ BCMA_HOSTTYPE_SOC,
};
struct bcma_chipinfo {
@@ -130,6 +131,7 @@ struct bcma_device {
struct device dev;
struct device *dma_dev;
+
unsigned int irq;
bool dev_registered;
@@ -138,6 +140,9 @@ struct bcma_device {
u32 addr;
u32 wrap;
+ void __iomem *io_addr;
+ void __iomem *io_wrap;
+
void *drvdata;
struct list_head list;
};
@@ -190,9 +195,11 @@ struct bcma_bus {
struct bcma_device *mapped_core;
struct list_head cores;
u8 nr_cores;
+ u8 init_done:1;
struct bcma_drv_cc drv_cc;
struct bcma_drv_pci drv_pci;
+ struct bcma_drv_mips drv_mips;
/* We decided to share SPROM struct with SSB as long as we do not need
* any hacks for BCMA. This simplifies drivers code. */
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index a0f684615ae5..1526d965ed06 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -24,6 +24,7 @@
#define BCMA_CC_FLASHT_NONE 0x00000000 /* No flash */
#define BCMA_CC_FLASHT_STSER 0x00000100 /* ST serial flash */
#define BCMA_CC_FLASHT_ATSER 0x00000200 /* Atmel serial flash */
+#define BCMA_CC_FLASHT_NFLASH 0x00000200
#define BCMA_CC_FLASHT_PARA 0x00000700 /* Parallel flash */
#define BCMA_CC_CAP_PLLT 0x00038000 /* PLL Type */
#define BCMA_PLLTYPE_NONE 0x00000000
@@ -178,6 +179,7 @@
#define BCMA_CC_PROG_CFG 0x0120
#define BCMA_CC_PROG_WAITCNT 0x0124
#define BCMA_CC_FLASH_CFG 0x0128
+#define BCMA_CC_FLASH_CFG_DS 0x0010 /* Data size, 0=8bit, 1=16bit */
#define BCMA_CC_FLASH_WAITCNT 0x012C
/* 0x1E0 is defined as shared BCMA_CLKCTLST */
#define BCMA_CC_HW_WORKAROUND 0x01E4 /* Hardware workaround (rev >= 20) */
@@ -239,6 +241,64 @@
#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
+#define BCMA_CC_PMU5_MAINPLL_MEM 2
+#define BCMA_CC_PMU5_MAINPLL_SSB 3
+
+/* PLL usage in 4716/47162 */
+#define BCMA_CC_PMU4716_MAINPLL_PLL0 12
+
+/* PLL usage in 5356/5357 */
+#define BCMA_CC_PMU5356_MAINPLL_PLL0 0
+#define BCMA_CC_PMU5357_MAINPLL_PLL0 0
+
+/* 4706 PMU */
+#define BCMA_CC_PMU4706_MAINPLL_PLL0 0
+
+/* ALP clock on pre-PMU chips */
+#define BCMA_CC_PMU_ALP_CLOCK 20000000
+/* HT clock for systems with PMU-enabled chipcommon */
+#define BCMA_CC_PMU_HT_CLOCK 80000000
+
+/* PMU rev 5 (& 6) */
+#define BCMA_CC_PPL_P1P2_OFF 0
+#define BCMA_CC_PPL_P1_MASK 0x0f000000
+#define BCMA_CC_PPL_P1_SHIFT 24
+#define BCMA_CC_PPL_P2_MASK 0x00f00000
+#define BCMA_CC_PPL_P2_SHIFT 20
+#define BCMA_CC_PPL_M14_OFF 1
+#define BCMA_CC_PPL_MDIV_MASK 0x000000ff
+#define BCMA_CC_PPL_MDIV_WIDTH 8
+#define BCMA_CC_PPL_NM5_OFF 2
+#define BCMA_CC_PPL_NDIV_MASK 0xfff00000
+#define BCMA_CC_PPL_NDIV_SHIFT 20
+#define BCMA_CC_PPL_FMAB_OFF 3
+#define BCMA_CC_PPL_MRAT_MASK 0xf0000000
+#define BCMA_CC_PPL_MRAT_SHIFT 28
+#define BCMA_CC_PPL_ABRAT_MASK 0x08000000
+#define BCMA_CC_PPL_ABRAT_SHIFT 27
+#define BCMA_CC_PPL_FDIV_MASK 0x07ffffff
+#define BCMA_CC_PPL_PLLCTL_OFF 4
+#define BCMA_CC_PPL_PCHI_OFF 5
+#define BCMA_CC_PPL_PCHI_MASK 0x0000003f
+
+/* BCM4331 ChipControl numbers. */
+#define BCMA_CHIPCTL_4331_BT_COEXIST BIT(0) /* 0 disable */
+#define BCMA_CHIPCTL_4331_SECI BIT(1) /* 0 SECI is disabled (JATG functional) */
+#define BCMA_CHIPCTL_4331_EXT_LNA BIT(2) /* 0 disable */
+#define BCMA_CHIPCTL_4331_SPROM_GPIO13_15 BIT(3) /* sprom/gpio13-15 mux */
+#define BCMA_CHIPCTL_4331_EXTPA_EN BIT(4) /* 0 ext pa disable, 1 ext pa enabled */
+#define BCMA_CHIPCTL_4331_GPIOCLK_ON_SPROMCS BIT(5) /* set drive out GPIO_CLK on sprom_cs pin */
+#define BCMA_CHIPCTL_4331_PCIE_MDIO_ON_SPROMCS BIT(6) /* use sprom_cs pin as PCIE mdio interface */
+#define BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5 BIT(7) /* aband extpa will be at gpio2/5 and sprom_dout */
+#define BCMA_CHIPCTL_4331_OVR_PIPEAUXCLKEN BIT(8) /* override core control on pipe_AuxClkEnable */
+#define BCMA_CHIPCTL_4331_OVR_PIPEAUXPWRDOWN BIT(9) /* override core control on pipe_AuxPowerDown */
+#define BCMA_CHIPCTL_4331_PCIE_AUXCLKEN BIT(10) /* pcie_auxclkenable */
+#define BCMA_CHIPCTL_4331_PCIE_PIPE_PLLDOWN BIT(11) /* pcie_pipe_pllpowerdown */
+#define BCMA_CHIPCTL_4331_BT_SHD0_ON_GPIO4 BIT(16) /* enable bt_shd0 at gpio4 */
+#define BCMA_CHIPCTL_4331_BT_SHD1_ON_GPIO5 BIT(17) /* enable bt_shd1 at gpio5 */
+
/* Data for the PMU, if available.
* Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
*/
@@ -247,14 +307,37 @@ struct bcma_chipcommon_pmu {
u32 crystalfreq; /* The active crystal frequency (in kHz) */
};
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+struct bcma_pflash {
+ u8 buswidth;
+ u32 window;
+ u32 window_size;
+};
+
+struct bcma_serial_port {
+ void *regs;
+ unsigned long clockspeed;
+ unsigned int irq;
+ unsigned int baud_base;
+ unsigned int reg_shift;
+};
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
+
struct bcma_drv_cc {
struct bcma_device *core;
u32 status;
u32 capabilities;
u32 capabilities_ext;
+ u8 setup_done:1;
/* Fast Powerup Delay constant */
u16 fast_pwrup_delay;
struct bcma_chipcommon_pmu pmu;
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+ struct bcma_pflash pflash;
+
+ int nr_serial_ports;
+ struct bcma_serial_port serial_ports[4];
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
};
/* Register access */
@@ -275,6 +358,8 @@ extern void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
extern void bcma_chipco_suspend(struct bcma_drv_cc *cc);
extern void bcma_chipco_resume(struct bcma_drv_cc *cc);
+void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
+
extern void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc,
u32 ticks);
@@ -293,4 +378,13 @@ u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value);
/* PMU support */
extern void bcma_pmu_init(struct bcma_drv_cc *cc);
+extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
+ u32 value);
+extern void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset,
+ u32 mask, u32 set);
+extern void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
+ u32 offset, u32 mask, u32 set);
+extern void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc,
+ u32 offset, u32 mask, u32 set);
+
#endif /* LINUX_BCMA_DRIVER_CC_H_ */
diff --git a/include/linux/bcma/bcma_driver_mips.h b/include/linux/bcma/bcma_driver_mips.h
new file mode 100644
index 000000000000..c0043645cdcb
--- /dev/null
+++ b/include/linux/bcma/bcma_driver_mips.h
@@ -0,0 +1,51 @@
+#ifndef LINUX_BCMA_DRIVER_MIPS_H_
+#define LINUX_BCMA_DRIVER_MIPS_H_
+
+#define BCMA_MIPS_IPSFLAG 0x0F08
+/* which sbflags get routed to mips interrupt 1 */
+#define BCMA_MIPS_IPSFLAG_IRQ1 0x0000003F
+#define BCMA_MIPS_IPSFLAG_IRQ1_SHIFT 0
+/* which sbflags get routed to mips interrupt 2 */
+#define BCMA_MIPS_IPSFLAG_IRQ2 0x00003F00
+#define BCMA_MIPS_IPSFLAG_IRQ2_SHIFT 8
+/* which sbflags get routed to mips interrupt 3 */
+#define BCMA_MIPS_IPSFLAG_IRQ3 0x003F0000
+#define BCMA_MIPS_IPSFLAG_IRQ3_SHIFT 16
+/* which sbflags get routed to mips interrupt 4 */
+#define BCMA_MIPS_IPSFLAG_IRQ4 0x3F000000
+#define BCMA_MIPS_IPSFLAG_IRQ4_SHIFT 24
+
+/* MIPS 74K core registers */
+#define BCMA_MIPS_MIPS74K_CORECTL 0x0000
+#define BCMA_MIPS_MIPS74K_EXCEPTBASE 0x0004
+#define BCMA_MIPS_MIPS74K_BIST 0x000C
+#define BCMA_MIPS_MIPS74K_INTMASK_INT0 0x0014
+#define BCMA_MIPS_MIPS74K_INTMASK(int) \
+ ((int) * 4 + BCMA_MIPS_MIPS74K_INTMASK_INT0)
+#define BCMA_MIPS_MIPS74K_NMIMASK 0x002C
+#define BCMA_MIPS_MIPS74K_GPIOSEL 0x0040
+#define BCMA_MIPS_MIPS74K_GPIOOUT 0x0044
+#define BCMA_MIPS_MIPS74K_GPIOEN 0x0048
+#define BCMA_MIPS_MIPS74K_CLKCTLST 0x01E0
+
+#define BCMA_MIPS_OOBSELOUTA30 0x100
+
+struct bcma_device;
+
+struct bcma_drv_mips {
+ struct bcma_device *core;
+ u8 setup_done:1;
+ unsigned int assigned_irqs;
+};
+
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
+#else
+static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
+#endif
+
+extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
+
+extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
+
+#endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
diff --git a/include/linux/bcma/bcma_soc.h b/include/linux/bcma/bcma_soc.h
new file mode 100644
index 000000000000..4203c5593b9f
--- /dev/null
+++ b/include/linux/bcma/bcma_soc.h
@@ -0,0 +1,16 @@
+#ifndef LINUX_BCMA_SOC_H_
+#define LINUX_BCMA_SOC_H_
+
+#include <linux/bcma/bcma.h>
+
+struct bcma_soc {
+ struct bcma_bus bus;
+ struct bcma_device core_cc;
+ struct bcma_device core_mips;
+};
+
+int __init bcma_host_soc_register(struct bcma_soc *soc);
+
+int bcma_bus_register(struct bcma_bus *bus);
+
+#endif /* LINUX_BCMA_SOC_H_ */
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 32f0076e844b..71fc53bb8f1c 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -124,6 +124,7 @@ enum rq_flag_bits {
__REQ_SYNC, /* request is sync (sync write or read) */
__REQ_META, /* metadata io request */
+ __REQ_PRIO, /* boost priority in cfq */
__REQ_DISCARD, /* request to discard sectors */
__REQ_SECURE, /* secure discard (used with __REQ_DISCARD) */
@@ -161,14 +162,15 @@ enum rq_flag_bits {
#define REQ_FAILFAST_DRIVER (1 << __REQ_FAILFAST_DRIVER)
#define REQ_SYNC (1 << __REQ_SYNC)
#define REQ_META (1 << __REQ_META)
+#define REQ_PRIO (1 << __REQ_PRIO)
#define REQ_DISCARD (1 << __REQ_DISCARD)
#define REQ_NOIDLE (1 << __REQ_NOIDLE)
#define REQ_FAILFAST_MASK \
(REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER)
#define REQ_COMMON_MASK \
- (REQ_WRITE | REQ_FAILFAST_MASK | REQ_SYNC | REQ_META | REQ_DISCARD | \
- REQ_NOIDLE | REQ_FLUSH | REQ_FUA | REQ_SECURE)
+ (REQ_WRITE | REQ_FAILFAST_MASK | REQ_SYNC | REQ_META | REQ_PRIO | \
+ REQ_DISCARD | REQ_NOIDLE | REQ_FLUSH | REQ_FUA | REQ_SECURE)
#define REQ_CLONE_MASK REQ_COMMON_MASK
#define REQ_RAHEAD (1 << __REQ_RAHEAD)
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 84b15d54f8c2..7fbaa9103344 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -873,7 +873,6 @@ struct blk_plug {
struct list_head list;
struct list_head cb_list;
unsigned int should_sort;
- unsigned int count;
};
#define BLK_MAX_REQUEST_COUNT 16
diff --git a/include/linux/caif/caif_socket.h b/include/linux/caif/caif_socket.h
index d9cb19b7cff7..3f3bac6af7bc 100644
--- a/include/linux/caif/caif_socket.h
+++ b/include/linux/caif/caif_socket.h
@@ -9,12 +9,7 @@
#define _LINUX_CAIF_SOCKET_H
#include <linux/types.h>
-
-#ifdef __KERNEL__
#include <linux/socket.h>
-#else
-#include <sys/socket.h>
-#endif
/**
* enum caif_link_selector - Physical Link Selection.
@@ -144,7 +139,7 @@ enum caif_debug_service {
* CAIF Channel. It defines the service to connect to on the modem.
*/
struct sockaddr_caif {
- sa_family_t family;
+ __kernel_sa_family_t family;
union {
struct {
__u8 type; /* type: enum caif_at_type */
diff --git a/include/linux/can.h b/include/linux/can.h
index d18333302cbd..9a19bcb3eeaf 100644
--- a/include/linux/can.h
+++ b/include/linux/can.h
@@ -8,8 +8,6 @@
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research
* All rights reserved.
*
- * Send feedback to <socketcan-users@lists.berlios.de>
- *
*/
#ifndef CAN_H
@@ -78,7 +76,7 @@ struct can_frame {
* @can_addr: protocol specific address information
*/
struct sockaddr_can {
- sa_family_t can_family;
+ __kernel_sa_family_t can_family;
int can_ifindex;
union {
/* transport protocol class address information (e.g. ISOTP) */
diff --git a/include/linux/can/Kbuild b/include/linux/can/Kbuild
index 8cb05aae661c..c62b7f1728f9 100644
--- a/include/linux/can/Kbuild
+++ b/include/linux/can/Kbuild
@@ -1,4 +1,5 @@
header-y += raw.h
header-y += bcm.h
+header-y += gw.h
header-y += error.h
header-y += netlink.h
diff --git a/include/linux/can/bcm.h b/include/linux/can/bcm.h
index 1432b278c52d..3ebe387fea4d 100644
--- a/include/linux/can/bcm.h
+++ b/include/linux/can/bcm.h
@@ -7,14 +7,13 @@
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research
* All rights reserved.
*
- * Send feedback to <socketcan-users@lists.berlios.de>
- *
*/
#ifndef CAN_BCM_H
#define CAN_BCM_H
#include <linux/types.h>
+#include <linux/can.h>
/**
* struct bcm_msg_head - head of messages to/from the broadcast manager
diff --git a/include/linux/can/core.h b/include/linux/can/core.h
index 5ce6b5d62ecc..0ccc1cd28b95 100644
--- a/include/linux/can/core.h
+++ b/include/linux/can/core.h
@@ -8,8 +8,6 @@
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research
* All rights reserved.
*
- * Send feedback to <socketcan-users@lists.berlios.de>
- *
*/
#ifndef CAN_CORE_H
diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h
index cc0bb4961669..a0969fcb72b9 100644
--- a/include/linux/can/dev.h
+++ b/include/linux/can/dev.h
@@ -8,7 +8,6 @@
*
* Copyright (C) 2008 Wolfgang Grandegger <wg@grandegger.com>
*
- * Send feedback to <socketcan-users@lists.berlios.de>
*/
#ifndef CAN_DEV_H
diff --git a/include/linux/can/error.h b/include/linux/can/error.h
index 5958074302a4..63e855ea6b84 100644
--- a/include/linux/can/error.h
+++ b/include/linux/can/error.h
@@ -7,8 +7,6 @@
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research
* All rights reserved.
*
- * Send feedback to <socketcan-users@lists.berlios.de>
- *
*/
#ifndef CAN_ERROR_H
diff --git a/include/linux/can/gw.h b/include/linux/can/gw.h
new file mode 100644
index 000000000000..8e1db18c3cb6
--- /dev/null
+++ b/include/linux/can/gw.h
@@ -0,0 +1,162 @@
+/*
+ * linux/can/gw.h
+ *
+ * Definitions for CAN frame Gateway/Router/Bridge
+ *
+ * Author: Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
+ * Copyright (c) 2011 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ */
+
+#ifndef CAN_GW_H
+#define CAN_GW_H
+
+#include <linux/types.h>
+#include <linux/can.h>
+
+struct rtcanmsg {
+ __u8 can_family;
+ __u8 gwtype;
+ __u16 flags;
+};
+
+/* CAN gateway types */
+enum {
+ CGW_TYPE_UNSPEC,
+ CGW_TYPE_CAN_CAN, /* CAN->CAN routing */
+ __CGW_TYPE_MAX
+};
+
+#define CGW_TYPE_MAX (__CGW_TYPE_MAX - 1)
+
+/* CAN rtnetlink attribute definitions */
+enum {
+ CGW_UNSPEC,
+ CGW_MOD_AND, /* CAN frame modification binary AND */
+ CGW_MOD_OR, /* CAN frame modification binary OR */
+ CGW_MOD_XOR, /* CAN frame modification binary XOR */
+ CGW_MOD_SET, /* CAN frame modification set alternate values */
+ CGW_CS_XOR, /* set data[] XOR checksum into data[index] */
+ CGW_CS_CRC8, /* set data[] CRC8 checksum into data[index] */
+ CGW_HANDLED, /* number of handled CAN frames */
+ CGW_DROPPED, /* number of dropped CAN frames */
+ CGW_SRC_IF, /* ifindex of source network interface */
+ CGW_DST_IF, /* ifindex of destination network interface */
+ CGW_FILTER, /* specify struct can_filter on source CAN device */
+ __CGW_MAX
+};
+
+#define CGW_MAX (__CGW_MAX - 1)
+
+#define CGW_FLAGS_CAN_ECHO 0x01
+#define CGW_FLAGS_CAN_SRC_TSTAMP 0x02
+
+#define CGW_MOD_FUNCS 4 /* AND OR XOR SET */
+
+/* CAN frame elements that are affected by curr. 3 CAN frame modifications */
+#define CGW_MOD_ID 0x01
+#define CGW_MOD_DLC 0x02
+#define CGW_MOD_DATA 0x04
+
+#define CGW_FRAME_MODS 3 /* ID DLC DATA */
+
+#define MAX_MODFUNCTIONS (CGW_MOD_FUNCS * CGW_FRAME_MODS)
+
+struct cgw_frame_mod {
+ struct can_frame cf;
+ __u8 modtype;
+} __attribute__((packed));
+
+#define CGW_MODATTR_LEN sizeof(struct cgw_frame_mod)
+
+struct cgw_csum_xor {
+ __s8 from_idx;
+ __s8 to_idx;
+ __s8 result_idx;
+ __u8 init_xor_val;
+} __attribute__((packed));
+
+struct cgw_csum_crc8 {
+ __s8 from_idx;
+ __s8 to_idx;
+ __s8 result_idx;
+ __u8 init_crc_val;
+ __u8 final_xor_val;
+ __u8 crctab[256];
+ __u8 profile;
+ __u8 profile_data[20];
+} __attribute__((packed));
+
+/* length of checksum operation parameters. idx = index in CAN frame data[] */
+#define CGW_CS_XOR_LEN sizeof(struct cgw_csum_xor)
+#define CGW_CS_CRC8_LEN sizeof(struct cgw_csum_crc8)
+
+/* CRC8 profiles (compute CRC for additional data elements - see below) */
+enum {
+ CGW_CRC8PRF_UNSPEC,
+ CGW_CRC8PRF_1U8, /* compute one additional u8 value */
+ CGW_CRC8PRF_16U8, /* u8 value table indexed by data[1] & 0xF */
+ CGW_CRC8PRF_SFFID_XOR, /* (can_id & 0xFF) ^ (can_id >> 8 & 0xFF) */
+ __CGW_CRC8PRF_MAX
+};
+
+#define CGW_CRC8PRF_MAX (__CGW_CRC8PRF_MAX - 1)
+
+/*
+ * CAN rtnetlink attribute contents in detail
+ *
+ * CGW_XXX_IF (length 4 bytes):
+ * Sets an interface index for source/destination network interfaces.
+ * For the CAN->CAN gwtype the indices of _two_ CAN interfaces are mandatory.
+ *
+ * CGW_FILTER (length 8 bytes):
+ * Sets a CAN receive filter for the gateway job specified by the
+ * struct can_filter described in include/linux/can.h
+ *
+ * CGW_MOD_XXX (length 17 bytes):
+ * Specifies a modification that's done to a received CAN frame before it is
+ * send out to the destination interface.
+ *
+ * <struct can_frame> data used as operator
+ * <u8> affected CAN frame elements
+ *
+ * CGW_CS_XOR (length 4 bytes):
+ * Set a simple XOR checksum starting with an initial value into
+ * data[result-idx] using data[start-idx] .. data[end-idx]
+ *
+ * The XOR checksum is calculated like this:
+ *
+ * xor = init_xor_val
+ *
+ * for (i = from_idx .. to_idx)
+ * xor ^= can_frame.data[i]
+ *
+ * can_frame.data[ result_idx ] = xor
+ *
+ * CGW_CS_CRC8 (length 282 bytes):
+ * Set a CRC8 value into data[result-idx] using a given 256 byte CRC8 table,
+ * a given initial value and a defined input data[start-idx] .. data[end-idx].
+ * Finally the result value is XOR'ed with the final_xor_val.
+ *
+ * The CRC8 checksum is calculated like this:
+ *
+ * crc = init_crc_val
+ *
+ * for (i = from_idx .. to_idx)
+ * crc = crctab[ crc ^ can_frame.data[i] ]
+ *
+ * can_frame.data[ result_idx ] = crc ^ final_xor_val
+ *
+ * The calculated CRC may contain additional source data elements that can be
+ * defined in the handling of 'checksum profiles' e.g. shown in AUTOSAR specs
+ * like http://www.autosar.org/download/R4.0/AUTOSAR_SWS_E2ELibrary.pdf
+ * E.g. the profile_data[] may contain additional u8 values (called DATA_IDs)
+ * that are used depending on counter values inside the CAN frame data[].
+ * So far only three profiles have been implemented for illustration.
+ *
+ * Remark: In general the attribute data is a linear buffer.
+ * Beware of sending unpacked or aligned structs!
+ */
+
+#endif
diff --git a/include/linux/can/netlink.h b/include/linux/can/netlink.h
index 34542d374dd8..14966ddb7df1 100644
--- a/include/linux/can/netlink.h
+++ b/include/linux/can/netlink.h
@@ -5,8 +5,6 @@
*
* Copyright (c) 2009 Wolfgang Grandegger <wg@grandegger.com>
*
- * Send feedback to <socketcan-users@lists.berlios.de>
- *
*/
#ifndef CAN_NETLINK_H
diff --git a/include/linux/can/raw.h b/include/linux/can/raw.h
index b2a0f87492c5..781f3a3701be 100644
--- a/include/linux/can/raw.h
+++ b/include/linux/can/raw.h
@@ -8,8 +8,6 @@
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research
* All rights reserved.
*
- * Send feedback to <socketcan-users@lists.berlios.de>
- *
*/
#ifndef CAN_RAW_H
diff --git a/include/linux/capability.h b/include/linux/capability.h
index c42112350003..a63d13d84ad8 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -198,7 +198,7 @@ struct cpu_vfs_cap_data {
/* Allow modification of routing tables */
/* Allow setting arbitrary process / process group ownership on
sockets */
-/* Allow binding to any address for transparent proxying */
+/* Allow binding to any address for transparent proxying (also via NET_RAW) */
/* Allow setting TOS (type of service) */
/* Allow setting promiscuous mode */
/* Allow clearing driver statistics */
@@ -210,6 +210,7 @@ struct cpu_vfs_cap_data {
/* Allow use of RAW sockets */
/* Allow use of PACKET sockets */
+/* Allow binding to any address for transparent proxying (also via NET_ADMIN) */
#define CAP_NET_RAW 13
diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h
index d7adf151d335..ca768ae729b4 100644
--- a/include/linux/ceph/messenger.h
+++ b/include/linux/ceph/messenger.h
@@ -6,7 +6,6 @@
#include <linux/net.h>
#include <linux/radix-tree.h>
#include <linux/uio.h>
-#include <linux/version.h>
#include <linux/workqueue.h>
#include "types.h"
diff --git a/include/linux/cn_proc.h b/include/linux/cn_proc.h
index 12c517b51ca2..d03612b196e1 100644
--- a/include/linux/cn_proc.h
+++ b/include/linux/cn_proc.h
@@ -54,6 +54,7 @@ struct proc_event {
PROC_EVENT_GID = 0x00000040,
PROC_EVENT_SID = 0x00000080,
PROC_EVENT_PTRACE = 0x00000100,
+ PROC_EVENT_COMM = 0x00000200,
/* "next" should be 0x00000400 */
/* "last" is the last process event: exit */
PROC_EVENT_EXIT = 0x80000000
@@ -103,6 +104,12 @@ struct proc_event {
__kernel_pid_t tracer_tgid;
} ptrace;
+ struct comm_proc_event {
+ __kernel_pid_t process_pid;
+ __kernel_pid_t process_tgid;
+ char comm[16];
+ } comm;
+
struct exit_proc_event {
__kernel_pid_t process_pid;
__kernel_pid_t process_tgid;
@@ -118,6 +125,7 @@ void proc_exec_connector(struct task_struct *task);
void proc_id_connector(struct task_struct *task, int which_id);
void proc_sid_connector(struct task_struct *task);
void proc_ptrace_connector(struct task_struct *task, int which_id);
+void proc_comm_connector(struct task_struct *task);
void proc_exit_connector(struct task_struct *task);
#else
static inline void proc_fork_connector(struct task_struct *task)
@@ -133,6 +141,9 @@ static inline void proc_id_connector(struct task_struct *task,
static inline void proc_sid_connector(struct task_struct *task)
{}
+static inline void proc_comm_connector(struct task_struct *task)
+{}
+
static inline void proc_ptrace_connector(struct task_struct *task,
int ptrace_id)
{}
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 8779405e15a8..c6e7523bf765 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -438,7 +438,6 @@ asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds,
struct compat_timespec __user *tsp,
const compat_sigset_t __user *sigmask,
compat_size_t sigsetsize);
-asmlinkage long compat_sys_nfsservctl(int cmd, void *notused, void *notused2);
asmlinkage long compat_sys_signalfd4(int ufd,
const compat_sigset_t __user *sigmask,
compat_size_t sigsetsize, int flags);
diff --git a/include/linux/connector.h b/include/linux/connector.h
index 0c69ad825b39..3c9c54fd5690 100644
--- a/include/linux/connector.h
+++ b/include/linux/connector.h
@@ -1,7 +1,7 @@
/*
* connector.h
*
- * 2004-2005 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * 2004-2005 Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
new file mode 100644
index 000000000000..afb94583960c
--- /dev/null
+++ b/include/linux/devfreq.h
@@ -0,0 +1,238 @@
+/*
+ * devfreq: Generic Dynamic Voltage and Frequency Scaling (DVFS) Framework
+ * for Non-CPU Devices.
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_DEVFREQ_H__
+#define __LINUX_DEVFREQ_H__
+
+#include <linux/device.h>
+#include <linux/notifier.h>
+#include <linux/opp.h>
+
+#define DEVFREQ_NAME_LEN 16
+
+struct devfreq;
+
+/**
+ * struct devfreq_dev_status - Data given from devfreq user device to
+ * governors. Represents the performance
+ * statistics.
+ * @total_time The total time represented by this instance of
+ * devfreq_dev_status
+ * @busy_time The time that the device was working among the
+ * total_time.
+ * @current_frequency The operating frequency.
+ * @private_data An entry not specified by the devfreq framework.
+ * A device and a specific governor may have their
+ * own protocol with private_data. However, because
+ * this is governor-specific, a governor using this
+ * will be only compatible with devices aware of it.
+ */
+struct devfreq_dev_status {
+ /* both since the last measure */
+ unsigned long total_time;
+ unsigned long busy_time;
+ unsigned long current_frequency;
+ void *private_date;
+};
+
+/**
+ * struct devfreq_dev_profile - Devfreq's user device profile
+ * @initial_freq The operating frequency when devfreq_add_device() is
+ * called.
+ * @polling_ms The polling interval in ms. 0 disables polling.
+ * @target The device should set its operating frequency at
+ * freq or lowest-upper-than-freq value. If freq is
+ * higher than any operable frequency, set maximum.
+ * Before returning, target function should set
+ * freq at the current frequency.
+ * @get_dev_status The device should provide the current performance
+ * status to devfreq, which is used by governors.
+ * @exit An optional callback that is called when devfreq
+ * is removing the devfreq object due to error or
+ * from devfreq_remove_device() call. If the user
+ * has registered devfreq->nb at a notifier-head,
+ * this is the time to unregister it.
+ */
+struct devfreq_dev_profile {
+ unsigned long initial_freq;
+ unsigned int polling_ms;
+
+ int (*target)(struct device *dev, unsigned long *freq);
+ int (*get_dev_status)(struct device *dev,
+ struct devfreq_dev_status *stat);
+ void (*exit)(struct device *dev);
+};
+
+/**
+ * struct devfreq_governor - Devfreq policy governor
+ * @name Governor's name
+ * @get_target_freq Returns desired operating frequency for the device.
+ * Basically, get_target_freq will run
+ * devfreq_dev_profile.get_dev_status() to get the
+ * status of the device (load = busy_time / total_time).
+ * If no_central_polling is set, this callback is called
+ * only with update_devfreq() notified by OPP.
+ * @init Called when the devfreq is being attached to a device
+ * @exit Called when the devfreq is being removed from a
+ * device. Governor should stop any internal routines
+ * before return because related data may be
+ * freed after exit().
+ * @no_central_polling Do not use devfreq's central polling mechanism.
+ * When this is set, devfreq will not call
+ * get_target_freq with devfreq_monitor(). However,
+ * devfreq will call get_target_freq with
+ * devfreq_update() notified by OPP framework.
+ *
+ * Note that the callbacks are called with devfreq->lock locked by devfreq.
+ */
+struct devfreq_governor {
+ const char name[DEVFREQ_NAME_LEN];
+ int (*get_target_freq)(struct devfreq *this, unsigned long *freq);
+ int (*init)(struct devfreq *this);
+ void (*exit)(struct devfreq *this);
+ const bool no_central_polling;
+};
+
+/**
+ * struct devfreq - Device devfreq structure
+ * @node list node - contains the devices with devfreq that have been
+ * registered.
+ * @lock a mutex to protect accessing devfreq.
+ * @dev device registered by devfreq class. dev.parent is the device
+ * using devfreq.
+ * @profile device-specific devfreq profile
+ * @governor method how to choose frequency based on the usage.
+ * @nb notifier block used to notify devfreq object that it should
+ * reevaluate operable frequencies. Devfreq users may use
+ * devfreq.nb to the corresponding register notifier call chain.
+ * @polling_jiffies interval in jiffies.
+ * @previous_freq previously configured frequency value.
+ * @next_polling the number of remaining jiffies to poll with
+ * "devfreq_monitor" executions to reevaluate
+ * frequency/voltage of the device. Set by
+ * profile's polling_ms interval.
+ * @data Private data of the governor. The devfreq framework does not
+ * touch this.
+ * @being_removed a flag to mark that this object is being removed in
+ * order to prevent trying to remove the object multiple times.
+ *
+ * This structure stores the devfreq information for a give device.
+ *
+ * Note that when a governor accesses entries in struct devfreq in its
+ * functions except for the context of callbacks defined in struct
+ * devfreq_governor, the governor should protect its access with the
+ * struct mutex lock in struct devfreq. A governor may use this mutex
+ * to protect its own private data in void *data as well.
+ */
+struct devfreq {
+ struct list_head node;
+
+ struct mutex lock;
+ struct device dev;
+ struct devfreq_dev_profile *profile;
+ const struct devfreq_governor *governor;
+ struct notifier_block nb;
+
+ unsigned long polling_jiffies;
+ unsigned long previous_freq;
+ unsigned int next_polling;
+
+ void *data; /* private data for governors */
+
+ bool being_removed;
+};
+
+#if defined(CONFIG_PM_DEVFREQ)
+extern struct devfreq *devfreq_add_device(struct device *dev,
+ struct devfreq_dev_profile *profile,
+ const struct devfreq_governor *governor,
+ void *data);
+extern int devfreq_remove_device(struct devfreq *devfreq);
+
+/* Helper functions for devfreq user device driver with OPP. */
+extern struct opp *devfreq_recommended_opp(struct device *dev,
+ unsigned long *freq);
+extern int devfreq_register_opp_notifier(struct device *dev,
+ struct devfreq *devfreq);
+extern int devfreq_unregister_opp_notifier(struct device *dev,
+ struct devfreq *devfreq);
+
+#ifdef CONFIG_DEVFREQ_GOV_POWERSAVE
+extern const struct devfreq_governor devfreq_powersave;
+#endif
+#ifdef CONFIG_DEVFREQ_GOV_PERFORMANCE
+extern const struct devfreq_governor devfreq_performance;
+#endif
+#ifdef CONFIG_DEVFREQ_GOV_USERSPACE
+extern const struct devfreq_governor devfreq_userspace;
+#endif
+#ifdef CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND
+extern const struct devfreq_governor devfreq_simple_ondemand;
+/**
+ * struct devfreq_simple_ondemand_data - void *data fed to struct devfreq
+ * and devfreq_add_device
+ * @ upthreshold If the load is over this value, the frequency jumps.
+ * Specify 0 to use the default. Valid value = 0 to 100.
+ * @ downdifferential If the load is under upthreshold - downdifferential,
+ * the governor may consider slowing the frequency down.
+ * Specify 0 to use the default. Valid value = 0 to 100.
+ * downdifferential < upthreshold must hold.
+ *
+ * If the fed devfreq_simple_ondemand_data pointer is NULL to the governor,
+ * the governor uses the default values.
+ */
+struct devfreq_simple_ondemand_data {
+ unsigned int upthreshold;
+ unsigned int downdifferential;
+};
+#endif
+
+#else /* !CONFIG_PM_DEVFREQ */
+static struct devfreq *devfreq_add_device(struct device *dev,
+ struct devfreq_dev_profile *profile,
+ struct devfreq_governor *governor,
+ void *data);
+{
+ return NULL;
+}
+
+static int devfreq_remove_device(struct devfreq *devfreq);
+{
+ return 0;
+}
+
+static struct opp *devfreq_recommended_opp(struct device *dev,
+ unsigned long *freq)
+{
+ return -EINVAL;
+}
+
+static int devfreq_register_opp_notifier(struct device *dev,
+ struct devfreq *devfreq)
+{
+ return -EINVAL;
+}
+
+static int devfreq_unregister_opp_notifier(struct device *dev,
+ struct devfreq *devfreq)
+{
+ return -EINVAL;
+}
+
+#define devfreq_powersave NULL
+#define devfreq_performance NULL
+#define devfreq_userspace NULL
+#define devfreq_simple_ondemand NULL
+
+#endif /* CONFIG_PM_DEVFREQ */
+
+#endif /* __LINUX_DEVFREQ_H__ */
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index 3fa1f3d90ce0..99e3e50b5c57 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -197,6 +197,11 @@ struct dm_target {
* whether or not its underlying devices have support.
*/
unsigned discards_supported:1;
+
+ /*
+ * Set if this target does not return zeroes on discarded blocks.
+ */
+ unsigned discard_zeroes_data_unsupported:1;
};
/* Each target can link one of these into the table */
diff --git a/include/linux/device.h b/include/linux/device.h
index c20dfbfc49b4..bdcf361ca938 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -350,6 +350,8 @@ struct class_attribute {
char *buf);
ssize_t (*store)(struct class *class, struct class_attribute *attr,
const char *buf, size_t count);
+ const void *(*namespace)(struct class *class,
+ const struct class_attribute *attr);
};
#define CLASS_ATTR(_name, _mode, _show, _store) \
@@ -636,6 +638,11 @@ static inline void set_dev_node(struct device *dev, int node)
}
#endif
+static inline struct pm_subsys_data *dev_to_psd(struct device *dev)
+{
+ return dev ? dev->power.subsys_data : NULL;
+}
+
static inline unsigned int dev_get_uevent_suppress(const struct device *dev)
{
return dev->kobj.uevent_suppress;
@@ -785,6 +792,8 @@ extern const char *dev_driver_string(const struct device *dev);
#ifdef CONFIG_PRINTK
+extern int __dev_printk(const char *level, const struct device *dev,
+ struct va_format *vaf);
extern int dev_printk(const char *level, const struct device *dev,
const char *fmt, ...)
__attribute__ ((format (printf, 3, 4)));
@@ -805,6 +814,9 @@ extern int _dev_info(const struct device *dev, const char *fmt, ...)
#else
+static inline int __dev_printk(const char *level, const struct device *dev,
+ struct va_format *vaf)
+ { return 0; }
static inline int dev_printk(const char *level, const struct device *dev,
const char *fmt, ...)
__attribute__ ((format (printf, 3, 4)));
diff --git a/include/linux/drbd_tag_magic.h b/include/linux/drbd_tag_magic.h
index 069543190516..81f52f2c5724 100644
--- a/include/linux/drbd_tag_magic.h
+++ b/include/linux/drbd_tag_magic.h
@@ -28,7 +28,7 @@ enum packet_types {
#define NL_STRING(pn, pr, member, len) \
unsigned char member[len]; int member ## _len; \
int tag_and_len ## member;
-#include "linux/drbd_nl.h"
+#include <linux/drbd_nl.h>
/* declare tag-list-sizes */
static const int tag_list_sizes[] = {
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index e747ecd48e1c..13aae8087b56 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -1,13 +1,6 @@
#ifndef _DYNAMIC_DEBUG_H
#define _DYNAMIC_DEBUG_H
-/* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which
- * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They
- * use independent hash functions, to reduce the chance of false positives.
- */
-extern long long dynamic_debug_enabled;
-extern long long dynamic_debug_enabled2;
-
/*
* An instance of this structure is created in a special
* ELF section at every dynamic debug callsite. At runtime,
@@ -47,26 +40,55 @@ extern int ddebug_remove_module(const char *mod_name);
extern int __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...)
__attribute__ ((format (printf, 2, 3)));
-#define dynamic_pr_debug(fmt, ...) do { \
- static struct _ddebug descriptor \
- __used \
- __attribute__((section("__verbose"), aligned(8))) = \
- { KBUILD_MODNAME, __func__, __FILE__, fmt, __LINE__, \
- _DPRINTK_FLAGS_DEFAULT }; \
- if (unlikely(descriptor.enabled)) \
- __dynamic_pr_debug(&descriptor, pr_fmt(fmt), ##__VA_ARGS__); \
- } while (0)
-
-
-#define dynamic_dev_dbg(dev, fmt, ...) do { \
- static struct _ddebug descriptor \
- __used \
- __attribute__((section("__verbose"), aligned(8))) = \
- { KBUILD_MODNAME, __func__, __FILE__, fmt, __LINE__, \
- _DPRINTK_FLAGS_DEFAULT }; \
- if (unlikely(descriptor.enabled)) \
- dev_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__); \
- } while (0)
+struct device;
+
+extern int __dynamic_dev_dbg(struct _ddebug *descriptor,
+ const struct device *dev,
+ const char *fmt, ...)
+ __attribute__ ((format (printf, 3, 4)));
+
+struct net_device;
+
+extern int __dynamic_netdev_dbg(struct _ddebug *descriptor,
+ const struct net_device *dev,
+ const char *fmt, ...)
+ __attribute__ ((format (printf, 3, 4)));
+
+#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt) \
+ static struct _ddebug __used __aligned(8) \
+ __attribute__((section("__verbose"))) name = { \
+ .modname = KBUILD_MODNAME, \
+ .function = __func__, \
+ .filename = __FILE__, \
+ .format = (fmt), \
+ .lineno = __LINE__, \
+ .flags = _DPRINTK_FLAGS_DEFAULT, \
+ .enabled = false, \
+ }
+
+#define dynamic_pr_debug(fmt, ...) \
+do { \
+ DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \
+ if (unlikely(descriptor.enabled)) \
+ __dynamic_pr_debug(&descriptor, pr_fmt(fmt), \
+ ##__VA_ARGS__); \
+} while (0)
+
+#define dynamic_dev_dbg(dev, fmt, ...) \
+do { \
+ DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \
+ if (unlikely(descriptor.enabled)) \
+ __dynamic_dev_dbg(&descriptor, dev, fmt, \
+ ##__VA_ARGS__); \
+} while (0)
+
+#define dynamic_netdev_dbg(dev, fmt, ...) \
+do { \
+ DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \
+ if (unlikely(descriptor.enabled)) \
+ __dynamic_netdev_dbg(&descriptor, dev, fmt, \
+ ##__VA_ARGS__); \
+} while (0)
#else
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index c6e427ab65fe..45f00b61c096 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -117,99 +117,101 @@ struct ethtool_eeprom {
__u8 data[0];
};
-/* for configuring coalescing parameters of chip */
+/**
+ * struct ethtool_coalesce - coalescing parameters for IRQs and stats updates
+ * @cmd: ETHTOOL_{G,S}COALESCE
+ * @rx_coalesce_usecs: How many usecs to delay an RX interrupt after
+ * a packet arrives.
+ * @rx_max_coalesced_frames: Maximum number of packets to receive
+ * before an RX interrupt.
+ * @rx_coalesce_usecs_irq: Same as @rx_coalesce_usecs, except that
+ * this value applies while an IRQ is being serviced by the host.
+ * @rx_max_coalesced_frames_irq: Same as @rx_max_coalesced_frames,
+ * except that this value applies while an IRQ is being serviced
+ * by the host.
+ * @tx_coalesce_usecs: How many usecs to delay a TX interrupt after
+ * a packet is sent.
+ * @tx_max_coalesced_frames: Maximum number of packets to be sent
+ * before a TX interrupt.
+ * @tx_coalesce_usecs_irq: Same as @tx_coalesce_usecs, except that
+ * this value applies while an IRQ is being serviced by the host.
+ * @tx_max_coalesced_frames_irq: Same as @tx_max_coalesced_frames,
+ * except that this value applies while an IRQ is being serviced
+ * by the host.
+ * @stats_block_coalesce_usecs: How many usecs to delay in-memory
+ * statistics block updates. Some drivers do not have an
+ * in-memory statistic block, and in such cases this value is
+ * ignored. This value must not be zero.
+ * @use_adaptive_rx_coalesce: Enable adaptive RX coalescing.
+ * @use_adaptive_tx_coalesce: Enable adaptive TX coalescing.
+ * @pkt_rate_low: Threshold for low packet rate (packets per second).
+ * @rx_coalesce_usecs_low: How many usecs to delay an RX interrupt after
+ * a packet arrives, when the packet rate is below @pkt_rate_low.
+ * @rx_max_coalesced_frames_low: Maximum number of packets to be received
+ * before an RX interrupt, when the packet rate is below @pkt_rate_low.
+ * @tx_coalesce_usecs_low: How many usecs to delay a TX interrupt after
+ * a packet is sent, when the packet rate is below @pkt_rate_low.
+ * @tx_max_coalesced_frames_low: Maximum nuumber of packets to be sent before
+ * a TX interrupt, when the packet rate is below @pkt_rate_low.
+ * @pkt_rate_high: Threshold for high packet rate (packets per second).
+ * @rx_coalesce_usecs_high: How many usecs to delay an RX interrupt after
+ * a packet arrives, when the packet rate is above @pkt_rate_high.
+ * @rx_max_coalesced_frames_high: Maximum number of packets to be received
+ * before an RX interrupt, when the packet rate is above @pkt_rate_high.
+ * @tx_coalesce_usecs_high: How many usecs to delay a TX interrupt after
+ * a packet is sent, when the packet rate is above @pkt_rate_high.
+ * @tx_max_coalesced_frames_high: Maximum number of packets to be sent before
+ * a TX interrupt, when the packet rate is above @pkt_rate_high.
+ * @rate_sample_interval: How often to do adaptive coalescing packet rate
+ * sampling, measured in seconds. Must not be zero.
+ *
+ * Each pair of (usecs, max_frames) fields specifies this exit
+ * condition for interrupt coalescing:
+ * (usecs > 0 && time_since_first_completion >= usecs) ||
+ * (max_frames > 0 && completed_frames >= max_frames)
+ * It is illegal to set both usecs and max_frames to zero as this
+ * would cause interrupts to never be generated. To disable
+ * coalescing, set usecs = 0 and max_frames = 1.
+ *
+ * Some implementations ignore the value of max_frames and use the
+ * condition:
+ * time_since_first_completion >= usecs
+ * This is deprecated. Drivers for hardware that does not support
+ * counting completions should validate that max_frames == !rx_usecs.
+ *
+ * Adaptive RX/TX coalescing is an algorithm implemented by some
+ * drivers to improve latency under low packet rates and improve
+ * throughput under high packet rates. Some drivers only implement
+ * one of RX or TX adaptive coalescing. Anything not implemented by
+ * the driver causes these values to be silently ignored.
+ *
+ * When the packet rate is below @pkt_rate_high but above
+ * @pkt_rate_low (both measured in packets per second) the
+ * normal {rx,tx}_* coalescing parameters are used.
+ */
struct ethtool_coalesce {
- __u32 cmd; /* ETHTOOL_{G,S}COALESCE */
-
- /* How many usecs to delay an RX interrupt after
- * a packet arrives. If 0, only rx_max_coalesced_frames
- * is used.
- */
+ __u32 cmd;
__u32 rx_coalesce_usecs;
-
- /* How many packets to delay an RX interrupt after
- * a packet arrives. If 0, only rx_coalesce_usecs is
- * used. It is illegal to set both usecs and max frames
- * to zero as this would cause RX interrupts to never be
- * generated.
- */
__u32 rx_max_coalesced_frames;
-
- /* Same as above two parameters, except that these values
- * apply while an IRQ is being serviced by the host. Not
- * all cards support this feature and the values are ignored
- * in that case.
- */
__u32 rx_coalesce_usecs_irq;
__u32 rx_max_coalesced_frames_irq;
-
- /* How many usecs to delay a TX interrupt after
- * a packet is sent. If 0, only tx_max_coalesced_frames
- * is used.
- */
__u32 tx_coalesce_usecs;
-
- /* How many packets to delay a TX interrupt after
- * a packet is sent. If 0, only tx_coalesce_usecs is
- * used. It is illegal to set both usecs and max frames
- * to zero as this would cause TX interrupts to never be
- * generated.
- */
__u32 tx_max_coalesced_frames;
-
- /* Same as above two parameters, except that these values
- * apply while an IRQ is being serviced by the host. Not
- * all cards support this feature and the values are ignored
- * in that case.
- */
__u32 tx_coalesce_usecs_irq;
__u32 tx_max_coalesced_frames_irq;
-
- /* How many usecs to delay in-memory statistics
- * block updates. Some drivers do not have an in-memory
- * statistic block, and in such cases this value is ignored.
- * This value must not be zero.
- */
__u32 stats_block_coalesce_usecs;
-
- /* Adaptive RX/TX coalescing is an algorithm implemented by
- * some drivers to improve latency under low packet rates and
- * improve throughput under high packet rates. Some drivers
- * only implement one of RX or TX adaptive coalescing. Anything
- * not implemented by the driver causes these values to be
- * silently ignored.
- */
__u32 use_adaptive_rx_coalesce;
__u32 use_adaptive_tx_coalesce;
-
- /* When the packet rate (measured in packets per second)
- * is below pkt_rate_low, the {rx,tx}_*_low parameters are
- * used.
- */
__u32 pkt_rate_low;
__u32 rx_coalesce_usecs_low;
__u32 rx_max_coalesced_frames_low;
__u32 tx_coalesce_usecs_low;
__u32 tx_max_coalesced_frames_low;
-
- /* When the packet rate is below pkt_rate_high but above
- * pkt_rate_low (both measured in packets per second) the
- * normal {rx,tx}_* coalescing parameters are used.
- */
-
- /* When the packet rate is (measured in packets per second)
- * is above pkt_rate_high, the {rx,tx}_*_high parameters are
- * used.
- */
__u32 pkt_rate_high;
__u32 rx_coalesce_usecs_high;
__u32 rx_max_coalesced_frames_high;
__u32 tx_coalesce_usecs_high;
__u32 tx_max_coalesced_frames_high;
-
- /* How often to do adaptive coalescing packet rate sampling,
- * measured in seconds. Must not be zero.
- */
__u32 rate_sample_interval;
};
@@ -444,7 +446,7 @@ struct ethtool_flow_ext {
};
/**
- * struct ethtool_rx_flow_spec - specification for RX flow filter
+ * struct ethtool_rx_flow_spec - classification rule for RX flows
* @flow_type: Type of match to perform, e.g. %TCP_V4_FLOW
* @h_u: Flow fields to match (dependent on @flow_type)
* @h_ext: Additional fields to match
@@ -454,7 +456,9 @@ struct ethtool_flow_ext {
* includes the %FLOW_EXT flag.
* @ring_cookie: RX ring/queue index to deliver to, or %RX_CLS_FLOW_DISC
* if packets should be discarded
- * @location: Index of filter in hardware table
+ * @location: Location of rule in the table. Locations must be
+ * numbered such that a flow matching multiple rules will be
+ * classified according to the first (lowest numbered) rule.
*/
struct ethtool_rx_flow_spec {
__u32 flow_type;
@@ -473,9 +477,9 @@ struct ethtool_rx_flow_spec {
* %ETHTOOL_GRXCLSRLALL, %ETHTOOL_SRXCLSRLDEL or %ETHTOOL_SRXCLSRLINS
* @flow_type: Type of flow to be affected, e.g. %TCP_V4_FLOW
* @data: Command-dependent value
- * @fs: Flow filter specification
+ * @fs: Flow classification rule
* @rule_cnt: Number of rules to be affected
- * @rule_locs: Array of valid rule indices
+ * @rule_locs: Array of used rule locations
*
* For %ETHTOOL_GRXFH and %ETHTOOL_SRXFH, @data is a bitmask indicating
* the fields included in the flow hash, e.g. %RXH_IP_SRC. The following
@@ -487,23 +491,20 @@ struct ethtool_rx_flow_spec {
* For %ETHTOOL_GRXCLSRLCNT, @rule_cnt is set to the number of defined
* rules on return.
*
- * For %ETHTOOL_GRXCLSRULE, @fs.@location specifies the index of an
- * existing filter rule on entry and @fs contains the rule on return.
+ * For %ETHTOOL_GRXCLSRULE, @fs.@location specifies the location of an
+ * existing rule on entry and @fs contains the rule on return.
*
* For %ETHTOOL_GRXCLSRLALL, @rule_cnt specifies the array size of the
* user buffer for @rule_locs on entry. On return, @data is the size
- * of the filter table and @rule_locs contains the indices of the
- * defined rules.
+ * of the rule table, @rule_cnt is the number of defined rules, and
+ * @rule_locs contains the locations of the defined rules. Drivers
+ * must use the second parameter to get_rxnfc() instead of @rule_locs.
*
- * For %ETHTOOL_SRXCLSRLINS, @fs specifies the filter rule to add or
- * update. @fs.@location specifies the index to use and must not be
- * ignored.
+ * For %ETHTOOL_SRXCLSRLINS, @fs specifies the rule to add or update.
+ * @fs.@location specifies the location to use and must not be ignored.
*
- * For %ETHTOOL_SRXCLSRLDEL, @fs.@location specifies the index of an
- * existing filter rule on entry.
- *
- * Implementation of indexed classification rules generally requires a
- * TCAM.
+ * For %ETHTOOL_SRXCLSRLDEL, @fs.@location specifies the location of an
+ * existing rule on entry.
*/
struct ethtool_rxnfc {
__u32 cmd;
@@ -726,6 +727,9 @@ enum ethtool_sfeatures_retval_bits {
/* needed by dev_disable_lro() */
extern int __ethtool_set_flags(struct net_device *dev, u32 flags);
+extern int __ethtool_get_settings(struct net_device *dev,
+ struct ethtool_cmd *cmd);
+
/**
* enum ethtool_phys_id_state - indicator state for physical identification
* @ETHTOOL_ID_INACTIVE: Physical ID indicator should be deactivated
@@ -936,7 +940,7 @@ struct ethtool_ops {
int (*set_priv_flags)(struct net_device *, u32);
int (*get_sset_count)(struct net_device *, int);
int (*get_rxnfc)(struct net_device *,
- struct ethtool_rxnfc *, void *);
+ struct ethtool_rxnfc *, u32 *rule_locs);
int (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *);
int (*flash_device)(struct net_device *, struct ethtool_flash *);
int (*reset)(struct net_device *, u32 *);
diff --git a/include/linux/evm.h b/include/linux/evm.h
new file mode 100644
index 000000000000..9fc13a760928
--- /dev/null
+++ b/include/linux/evm.h
@@ -0,0 +1,100 @@
+/*
+ * evm.h
+ *
+ * Copyright (c) 2009 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ */
+
+#ifndef _LINUX_EVM_H
+#define _LINUX_EVM_H
+
+#include <linux/integrity.h>
+#include <linux/xattr.h>
+
+struct integrity_iint_cache;
+
+#ifdef CONFIG_EVM
+extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
+ const char *xattr_name,
+ void *xattr_value,
+ size_t xattr_value_len,
+ struct integrity_iint_cache *iint);
+extern int evm_inode_setattr(struct dentry *dentry, struct iattr *attr);
+extern void evm_inode_post_setattr(struct dentry *dentry, int ia_valid);
+extern int evm_inode_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size);
+extern void evm_inode_post_setxattr(struct dentry *dentry,
+ const char *xattr_name,
+ const void *xattr_value,
+ size_t xattr_value_len);
+extern int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name);
+extern void evm_inode_post_removexattr(struct dentry *dentry,
+ const char *xattr_name);
+extern int evm_inode_init_security(struct inode *inode,
+ const struct xattr *xattr_array,
+ struct xattr *evm);
+#ifdef CONFIG_FS_POSIX_ACL
+extern int posix_xattr_acl(const char *xattrname);
+#else
+static inline int posix_xattr_acl(const char *xattrname)
+{
+ return 0;
+}
+#endif
+#else
+#ifdef CONFIG_INTEGRITY
+static inline enum integrity_status evm_verifyxattr(struct dentry *dentry,
+ const char *xattr_name,
+ void *xattr_value,
+ size_t xattr_value_len,
+ struct integrity_iint_cache *iint)
+{
+ return INTEGRITY_UNKNOWN;
+}
+#endif
+
+static inline int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ return 0;
+}
+
+static inline void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
+{
+ return;
+}
+
+static inline int evm_inode_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size)
+{
+ return 0;
+}
+
+static inline void evm_inode_post_setxattr(struct dentry *dentry,
+ const char *xattr_name,
+ const void *xattr_value,
+ size_t xattr_value_len)
+{
+ return;
+}
+
+static inline int evm_inode_removexattr(struct dentry *dentry,
+ const char *xattr_name)
+{
+ return 0;
+}
+
+static inline void evm_inode_post_removexattr(struct dentry *dentry,
+ const char *xattr_name)
+{
+ return;
+}
+
+static inline int evm_inode_init_security(struct inode *inode,
+ const struct xattr *xattr_array,
+ struct xattr *evm)
+{
+ return 0;
+}
+
+#endif /* CONFIG_EVM_H */
+#endif /* LINUX_EVM_H */
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 741956fa5bfd..8eeb205f298b 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -155,7 +155,7 @@ extern unsigned int sk_run_filter(const struct sk_buff *skb,
const struct sock_filter *filter);
extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk);
extern int sk_detach_filter(struct sock *sk);
-extern int sk_chk_filter(struct sock_filter *filter, int flen);
+extern int sk_chk_filter(struct sock_filter *filter, unsigned int flen);
#ifdef CONFIG_BPF_JIT
extern void bpf_jit_compile(struct sk_filter *fp);
diff --git a/include/linux/freezer.h b/include/linux/freezer.h
index 1effc8b56b4e..aa56cf31f7ff 100644
--- a/include/linux/freezer.h
+++ b/include/linux/freezer.h
@@ -49,6 +49,7 @@ extern int thaw_process(struct task_struct *p);
extern void refrigerator(void);
extern int freeze_processes(void);
+extern int freeze_kernel_threads(void);
extern void thaw_processes(void);
static inline int try_to_freeze(void)
@@ -171,7 +172,8 @@ static inline void clear_freeze_flag(struct task_struct *p) {}
static inline int thaw_process(struct task_struct *p) { return 1; }
static inline void refrigerator(void) {}
-static inline int freeze_processes(void) { BUG(); return 0; }
+static inline int freeze_processes(void) { return -ENOSYS; }
+static inline int freeze_kernel_threads(void) { return -ENOSYS; }
static inline void thaw_processes(void) {}
static inline int try_to_freeze(void) { return 0; }
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 178cdb4f1d4a..ba98668a1826 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -162,10 +162,8 @@ struct inodes_stat_t {
#define READA RWA_MASK
#define READ_SYNC (READ | REQ_SYNC)
-#define READ_META (READ | REQ_META)
#define WRITE_SYNC (WRITE | REQ_SYNC | REQ_NOIDLE)
#define WRITE_ODIRECT (WRITE | REQ_SYNC)
-#define WRITE_META (WRITE | REQ_META)
#define WRITE_FLUSH (WRITE | REQ_SYNC | REQ_NOIDLE | REQ_FLUSH)
#define WRITE_FUA (WRITE | REQ_SYNC | REQ_NOIDLE | REQ_FUA)
#define WRITE_FLUSH_FUA (WRITE | REQ_SYNC | REQ_NOIDLE | REQ_FLUSH | REQ_FUA)
@@ -1065,6 +1063,8 @@ static inline int file_check_writeable(struct file *filp)
#define FL_LEASE 32 /* lease held on this file */
#define FL_CLOSE 64 /* unlock on close */
#define FL_SLEEP 128 /* A blocking lock */
+#define FL_DOWNGRADE_PENDING 256 /* Lease is being downgraded */
+#define FL_UNLOCK_PENDING 512 /* Lease is being broken */
/*
* Special return value from posix_lock_file() and vfs_lock_file() for
@@ -1111,7 +1111,7 @@ struct file_lock {
struct list_head fl_link; /* doubly linked list of all locks */
struct list_head fl_block; /* circular list of blocked processes */
fl_owner_t fl_owner;
- unsigned char fl_flags;
+ unsigned int fl_flags;
unsigned char fl_type;
unsigned int fl_pid;
struct pid *fl_nspid;
@@ -1121,7 +1121,9 @@ struct file_lock {
loff_t fl_end;
struct fasync_struct * fl_fasync; /* for lease break notifications */
- unsigned long fl_break_time; /* for nonblocking lease breaks */
+ /* for lease breaks: */
+ unsigned long fl_break_time;
+ unsigned long fl_downgrade_time;
const struct file_lock_operations *fl_ops; /* Callbacks for filesystems */
const struct lock_manager_operations *fl_lmops; /* Callbacks for lockmanagers */
@@ -2318,6 +2320,11 @@ extern struct inode * iget5_locked(struct super_block *, unsigned long, int (*te
extern struct inode * iget_locked(struct super_block *, unsigned long);
extern int insert_inode_locked4(struct inode *, unsigned long, int (*test)(struct inode *, void *), void *);
extern int insert_inode_locked(struct inode *);
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+extern void lockdep_annotate_inode_mutex_key(struct inode *inode);
+#else
+static inline void lockdep_annotate_inode_mutex_key(struct inode *inode) { };
+#endif
extern void unlock_new_inode(struct inode *);
extern unsigned int get_next_ino(void);
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index d464de53db43..464cff526860 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -47,6 +47,9 @@
* - FUSE_IOCTL_UNRESTRICTED shall now return with array of 'struct
* fuse_ioctl_iovec' instead of ambiguous 'struct iovec'
* - add FUSE_IOCTL_32BIT flag
+ *
+ * 7.17
+ * - add FUSE_FLOCK_LOCKS and FUSE_RELEASE_FLOCK_UNLOCK
*/
#ifndef _LINUX_FUSE_H
@@ -78,7 +81,7 @@
#define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 16
+#define FUSE_KERNEL_MINOR_VERSION 17
/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
@@ -153,8 +156,10 @@ struct fuse_file_lock {
/**
* INIT request/reply flags
*
+ * FUSE_POSIX_LOCKS: remote locking for POSIX file locks
* FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
* FUSE_DONT_MASK: don't apply umask to file mode on create operations
+ * FUSE_FLOCK_LOCKS: remote locking for BSD style file locks
*/
#define FUSE_ASYNC_READ (1 << 0)
#define FUSE_POSIX_LOCKS (1 << 1)
@@ -163,6 +168,7 @@ struct fuse_file_lock {
#define FUSE_EXPORT_SUPPORT (1 << 4)
#define FUSE_BIG_WRITES (1 << 5)
#define FUSE_DONT_MASK (1 << 6)
+#define FUSE_FLOCK_LOCKS (1 << 10)
/**
* CUSE INIT request/reply flags
@@ -175,6 +181,7 @@ struct fuse_file_lock {
* Release flags
*/
#define FUSE_RELEASE_FLUSH (1 << 0)
+#define FUSE_RELEASE_FLOCK_UNLOCK (1 << 1)
/**
* Getattr flags
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 9cf8e7ae7450..deed5f9a1e1c 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -71,6 +71,7 @@
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/input.h>
+#include <linux/semaphore.h>
/*
* We parse each description item into this structure. Short items data
@@ -312,6 +313,7 @@ struct hid_item {
#define HID_QUIRK_BADPAD 0x00000020
#define HID_QUIRK_MULTI_INPUT 0x00000040
#define HID_QUIRK_HIDINPUT_FORCE 0x00000080
+#define HID_QUIRK_MULTITOUCH 0x00000100
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000
#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000
#define HID_QUIRK_NO_INIT_REPORTS 0x20000000
@@ -475,6 +477,7 @@ struct hid_device { /* device report descriptor */
unsigned country; /* HID country */
struct hid_report_enum report_enum[HID_REPORT_TYPES];
+ struct semaphore driver_lock; /* protects the current driver */
struct device dev; /* device */
struct hid_driver *driver;
struct hid_ll_driver *ll_driver;
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 54c878960872..48363c3c40f8 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -130,6 +130,8 @@
#define IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK 0x0060
/* A-MSDU 802.11n */
#define IEEE80211_QOS_CTL_A_MSDU_PRESENT 0x0080
+/* Mesh Control 802.11s */
+#define IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT 0x0100
/* U-APSD queue for WMM IEs sent by AP */
#define IEEE80211_WMM_IE_AP_QOSINFO_UAPSD (1<<7)
@@ -629,9 +631,14 @@ struct ieee80211_rann_ie {
u8 rann_ttl;
u8 rann_addr[6];
u32 rann_seq;
+ u32 rann_interval;
u32 rann_metric;
} __attribute__ ((packed));
+enum ieee80211_rann_flags {
+ RANN_FLAG_IS_GATE = 1 << 0,
+};
+
#define WLAN_SA_QUERY_TR_ID_LEN 2
struct ieee80211_mgmt {
@@ -736,19 +743,10 @@ struct ieee80211_mgmt {
__le16 params;
__le16 reason_code;
} __attribute__((packed)) delba;
- struct{
+ struct {
u8 action_code;
- /* capab_info for open and confirm,
- * reason for close
- */
- __le16 aux;
- /* Followed in plink_confirm by status
- * code, AID and supported rates,
- * and directly by supported rates in
- * plink_open and plink_close
- */
u8 variable[0];
- } __attribute__((packed)) plink_action;
+ } __attribute__((packed)) self_prot;
struct{
u8 action_code;
u8 variable[0];
@@ -761,6 +759,12 @@ struct ieee80211_mgmt {
u8 action;
u8 smps_control;
} __attribute__ ((packed)) ht_smps;
+ struct {
+ u8 action_code;
+ u8 dialog_token;
+ __le16 capability;
+ u8 variable[0];
+ } __packed tdls_discover_resp;
} u;
} __attribute__ ((packed)) action;
} u;
@@ -779,6 +783,13 @@ struct ieee80211_mmie {
u8 mic[8];
} __attribute__ ((packed));
+struct ieee80211_vendor_ie {
+ u8 element_id;
+ u8 len;
+ u8 oui[3];
+ u8 oui_type;
+} __packed;
+
/* Control frames */
struct ieee80211_rts {
__le16 frame_control;
@@ -800,6 +811,52 @@ struct ieee80211_pspoll {
u8 ta[6];
} __attribute__ ((packed));
+/* TDLS */
+
+/* Link-id information element */
+struct ieee80211_tdls_lnkie {
+ u8 ie_type; /* Link Identifier IE */
+ u8 ie_len;
+ u8 bssid[6];
+ u8 init_sta[6];
+ u8 resp_sta[6];
+} __packed;
+
+struct ieee80211_tdls_data {
+ u8 da[6];
+ u8 sa[6];
+ __be16 ether_type;
+ u8 payload_type;
+ u8 category;
+ u8 action_code;
+ union {
+ struct {
+ u8 dialog_token;
+ __le16 capability;
+ u8 variable[0];
+ } __packed setup_req;
+ struct {
+ __le16 status_code;
+ u8 dialog_token;
+ __le16 capability;
+ u8 variable[0];
+ } __packed setup_resp;
+ struct {
+ __le16 status_code;
+ u8 dialog_token;
+ u8 variable[0];
+ } __packed setup_cfm;
+ struct {
+ __le16 reason_code;
+ u8 variable[0];
+ } __packed teardown;
+ struct {
+ u8 dialog_token;
+ u8 variable[0];
+ } __packed discover_req;
+ } u;
+} __packed;
+
/**
* struct ieee80211_bar - HT Block Ack Request
*
@@ -816,9 +873,11 @@ struct ieee80211_bar {
} __attribute__((packed));
/* 802.11 BAR control masks */
-#define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL 0x0000
-#define IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA 0x0004
-
+#define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL 0x0000
+#define IEEE80211_BAR_CTRL_MULTI_TID 0x0002
+#define IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA 0x0004
+#define IEEE80211_BAR_CTRL_TID_INFO_MASK 0xf000
+#define IEEE80211_BAR_CTRL_TID_INFO_SHIFT 12
#define IEEE80211_HT_MCS_MASK_LEN 10
@@ -1189,16 +1248,13 @@ enum ieee80211_eid {
WLAN_EID_TS_DELAY = 43,
WLAN_EID_TCLAS_PROCESSING = 44,
WLAN_EID_QOS_CAPA = 46,
+ /* 802.11z */
+ WLAN_EID_LINK_ID = 101,
/* 802.11s */
WLAN_EID_MESH_CONFIG = 113,
WLAN_EID_MESH_ID = 114,
WLAN_EID_LINK_METRIC_REPORT = 115,
WLAN_EID_CONGESTION_NOTIFICATION = 116,
- /* Note that the Peer Link IE has been replaced with the similar
- * Peer Management IE. We will keep the former definition until mesh
- * code is changed to comply with latest 802.11s drafts.
- */
- WLAN_EID_PEER_LINK = 55, /* no longer in 802.11s drafts */
WLAN_EID_PEER_MGMT = 117,
WLAN_EID_CHAN_SWITCH_PARAM = 118,
WLAN_EID_MESH_AWAKE_WINDOW = 119,
@@ -1277,13 +1333,11 @@ enum ieee80211_category {
WLAN_CATEGORY_HT = 7,
WLAN_CATEGORY_SA_QUERY = 8,
WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9,
+ WLAN_CATEGORY_TDLS = 12,
WLAN_CATEGORY_MESH_ACTION = 13,
WLAN_CATEGORY_MULTIHOP_ACTION = 14,
WLAN_CATEGORY_SELF_PROTECTED = 15,
WLAN_CATEGORY_WMM = 17,
- /* TODO: remove MESH_PATH_SEL after mesh is updated
- * to current 802.11s draft */
- WLAN_CATEGORY_MESH_PATH_SEL = 32,
WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126,
WLAN_CATEGORY_VENDOR_SPECIFIC = 127,
};
@@ -1309,6 +1363,31 @@ enum ieee80211_ht_actioncode {
WLAN_HT_ACTION_ASEL_IDX_FEEDBACK = 7,
};
+/* Self Protected Action codes */
+enum ieee80211_self_protected_actioncode {
+ WLAN_SP_RESERVED = 0,
+ WLAN_SP_MESH_PEERING_OPEN = 1,
+ WLAN_SP_MESH_PEERING_CONFIRM = 2,
+ WLAN_SP_MESH_PEERING_CLOSE = 3,
+ WLAN_SP_MGK_INFORM = 4,
+ WLAN_SP_MGK_ACK = 5,
+};
+
+/* Mesh action codes */
+enum ieee80211_mesh_actioncode {
+ WLAN_MESH_ACTION_LINK_METRIC_REPORT,
+ WLAN_MESH_ACTION_HWMP_PATH_SELECTION,
+ WLAN_MESH_ACTION_GATE_ANNOUNCEMENT,
+ WLAN_MESH_ACTION_CONGESTION_CONTROL_NOTIFICATION,
+ WLAN_MESH_ACTION_MCCA_SETUP_REQUEST,
+ WLAN_MESH_ACTION_MCCA_SETUP_REPLY,
+ WLAN_MESH_ACTION_MCCA_ADVERTISEMENT_REQUEST,
+ WLAN_MESH_ACTION_MCCA_ADVERTISEMENT,
+ WLAN_MESH_ACTION_MCCA_TEARDOWN,
+ WLAN_MESH_ACTION_TBTT_ADJUSTMENT_REQUEST,
+ WLAN_MESH_ACTION_TBTT_ADJUSTMENT_RESPONSE,
+};
+
/* Security key length */
enum ieee80211_key_len {
WLAN_KEY_LEN_WEP40 = 5,
@@ -1318,6 +1397,36 @@ enum ieee80211_key_len {
WLAN_KEY_LEN_AES_CMAC = 16,
};
+/* Public action codes */
+enum ieee80211_pub_actioncode {
+ WLAN_PUB_ACTION_TDLS_DISCOVER_RES = 14,
+};
+
+/* TDLS action codes */
+enum ieee80211_tdls_actioncode {
+ WLAN_TDLS_SETUP_REQUEST = 0,
+ WLAN_TDLS_SETUP_RESPONSE = 1,
+ WLAN_TDLS_SETUP_CONFIRM = 2,
+ WLAN_TDLS_TEARDOWN = 3,
+ WLAN_TDLS_PEER_TRAFFIC_INDICATION = 4,
+ WLAN_TDLS_CHANNEL_SWITCH_REQUEST = 5,
+ WLAN_TDLS_CHANNEL_SWITCH_RESPONSE = 6,
+ WLAN_TDLS_PEER_PSM_REQUEST = 7,
+ WLAN_TDLS_PEER_PSM_RESPONSE = 8,
+ WLAN_TDLS_PEER_TRAFFIC_RESPONSE = 9,
+ WLAN_TDLS_DISCOVERY_REQUEST = 10,
+};
+
+/*
+ * TDLS capabililites to be enabled in the 5th byte of the
+ * @WLAN_EID_EXT_CAPABILITY information element
+ */
+#define WLAN_EXT_CAPA5_TDLS_ENABLED BIT(5)
+#define WLAN_EXT_CAPA5_TDLS_PROHIBITED BIT(6)
+
+/* TDLS specific payload type in the LLC/SNAP header */
+#define WLAN_TDLS_SNAP_RFTYPE 0x2
+
/**
* enum - mesh path selection protocol identifier
*
@@ -1453,6 +1562,9 @@ enum ieee80211_sa_query_action {
#define WLAN_PMKID_LEN 16
+#define WLAN_OUI_WFA 0x506f9a
+#define WLAN_OUI_TYPE_WFA_P2P 9
+
/*
* WMM/802.11e Tspec Element
*/
diff --git a/include/linux/if.h b/include/linux/if.h
index 03489ca92ded..db20bd4fd16b 100644
--- a/include/linux/if.h
+++ b/include/linux/if.h
@@ -78,6 +78,7 @@
* datapath port */
#define IFF_TX_SKB_SHARING 0x10000 /* The interface supports sharing
* skbs on transmit */
+#define IFF_UNICAST_FLT 0x20000 /* Supports unicast filtering */
#define IF_GET_IFACE 0x0001 /* for querying only */
#define IF_GET_PROTO 0x0002
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index a3d99ff6e3b5..e473003e4bda 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -83,11 +83,13 @@
#define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */
#define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */
#define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */
+#define ETH_P_TDLS 0x890D /* TDLS */
#define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */
#define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_QINQ3 0x9300 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_EDSA 0xDADA /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_AF_IUCV 0xFBFB /* IBM af_iucv [ NOT AN OFFICIALLY REGISTERED ID ] */
/*
* Non DIX types. Won't clash for 1500 types.
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 0ee969a5593d..c52d4b5f872a 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -279,6 +279,7 @@ enum {
IFLA_VF_MAC, /* Hardware queue specific attributes */
IFLA_VF_VLAN,
IFLA_VF_TX_RATE, /* TX Bandwidth Allocation */
+ IFLA_VF_SPOOFCHK, /* Spoof Checking on/off switch */
__IFLA_VF_MAX,
};
@@ -300,13 +301,22 @@ struct ifla_vf_tx_rate {
__u32 rate; /* Max TX bandwidth in Mbps, 0 disables throttling */
};
+struct ifla_vf_spoofchk {
+ __u32 vf;
+ __u32 setting;
+};
+#ifdef __KERNEL__
+
+/* We don't want this structure exposed to user space */
struct ifla_vf_info {
__u32 vf;
__u8 mac[32];
__u32 vlan;
__u32 qos;
__u32 tx_rate;
+ __u32 spoofchk;
};
+#endif
/* VF ports management section
*
diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h
index e28b2e4959d4..d103dca5c563 100644
--- a/include/linux/if_macvlan.h
+++ b/include/linux/if_macvlan.h
@@ -64,6 +64,7 @@ struct macvlan_dev {
int (*forward)(struct net_device *dev, struct sk_buff *skb);
struct macvtap_queue *taps[MAX_MACVTAP_QUEUES];
int numvtaps;
+ int minor;
};
static inline void macvlan_count_rx(const struct macvlan_dev *vlan,
diff --git a/include/linux/if_packet.h b/include/linux/if_packet.h
index c1486060f5ed..f3799295d231 100644
--- a/include/linux/if_packet.h
+++ b/include/linux/if_packet.h
@@ -61,6 +61,17 @@ struct tpacket_stats {
unsigned int tp_drops;
};
+struct tpacket_stats_v3 {
+ unsigned int tp_packets;
+ unsigned int tp_drops;
+ unsigned int tp_freeze_q_cnt;
+};
+
+union tpacket_stats_u {
+ struct tpacket_stats stats1;
+ struct tpacket_stats_v3 stats3;
+};
+
struct tpacket_auxdata {
__u32 tp_status;
__u32 tp_len;
@@ -78,6 +89,7 @@ struct tpacket_auxdata {
#define TP_STATUS_LOSING 0x4
#define TP_STATUS_CSUMNOTREADY 0x8
#define TP_STATUS_VLAN_VALID 0x10 /* auxdata has valid tp_vlan_tci */
+#define TP_STATUS_BLK_TMO 0x20
/* Tx ring - header status */
#define TP_STATUS_AVAILABLE 0x0
@@ -85,6 +97,9 @@ struct tpacket_auxdata {
#define TP_STATUS_SENDING 0x2
#define TP_STATUS_WRONG_FORMAT 0x4
+/* Rx ring - feature request bits */
+#define TP_FT_REQ_FILL_RXHASH 0x1
+
struct tpacket_hdr {
unsigned long tp_status;
unsigned int tp_len;
@@ -111,11 +126,100 @@ struct tpacket2_hdr {
__u16 tp_padding;
};
+struct tpacket_hdr_variant1 {
+ __u32 tp_rxhash;
+ __u32 tp_vlan_tci;
+};
+
+struct tpacket3_hdr {
+ __u32 tp_next_offset;
+ __u32 tp_sec;
+ __u32 tp_nsec;
+ __u32 tp_snaplen;
+ __u32 tp_len;
+ __u32 tp_status;
+ __u16 tp_mac;
+ __u16 tp_net;
+ /* pkt_hdr variants */
+ union {
+ struct tpacket_hdr_variant1 hv1;
+ };
+};
+
+struct tpacket_bd_ts {
+ unsigned int ts_sec;
+ union {
+ unsigned int ts_usec;
+ unsigned int ts_nsec;
+ };
+};
+
+struct tpacket_hdr_v1 {
+ __u32 block_status;
+ __u32 num_pkts;
+ __u32 offset_to_first_pkt;
+
+ /* Number of valid bytes (including padding)
+ * blk_len <= tp_block_size
+ */
+ __u32 blk_len;
+
+ /*
+ * Quite a few uses of sequence number:
+ * 1. Make sure cache flush etc worked.
+ * Well, one can argue - why not use the increasing ts below?
+ * But look at 2. below first.
+ * 2. When you pass around blocks to other user space decoders,
+ * you can see which blk[s] is[are] outstanding etc.
+ * 3. Validate kernel code.
+ */
+ __aligned_u64 seq_num;
+
+ /*
+ * ts_last_pkt:
+ *
+ * Case 1. Block has 'N'(N >=1) packets and TMO'd(timed out)
+ * ts_last_pkt == 'time-stamp of last packet' and NOT the
+ * time when the timer fired and the block was closed.
+ * By providing the ts of the last packet we can absolutely
+ * guarantee that time-stamp wise, the first packet in the
+ * next block will never precede the last packet of the
+ * previous block.
+ * Case 2. Block has zero packets and TMO'd
+ * ts_last_pkt = time when the timer fired and the block
+ * was closed.
+ * Case 3. Block has 'N' packets and NO TMO.
+ * ts_last_pkt = time-stamp of the last pkt in the block.
+ *
+ * ts_first_pkt:
+ * Is always the time-stamp when the block was opened.
+ * Case a) ZERO packets
+ * No packets to deal with but atleast you know the
+ * time-interval of this block.
+ * Case b) Non-zero packets
+ * Use the ts of the first packet in the block.
+ *
+ */
+ struct tpacket_bd_ts ts_first_pkt, ts_last_pkt;
+};
+
+union tpacket_bd_header_u {
+ struct tpacket_hdr_v1 bh1;
+};
+
+struct tpacket_block_desc {
+ __u32 version;
+ __u32 offset_to_priv;
+ union tpacket_bd_header_u hdr;
+};
+
#define TPACKET2_HDRLEN (TPACKET_ALIGN(sizeof(struct tpacket2_hdr)) + sizeof(struct sockaddr_ll))
+#define TPACKET3_HDRLEN (TPACKET_ALIGN(sizeof(struct tpacket3_hdr)) + sizeof(struct sockaddr_ll))
enum tpacket_versions {
TPACKET_V1,
TPACKET_V2,
+ TPACKET_V3
};
/*
@@ -138,6 +242,21 @@ struct tpacket_req {
unsigned int tp_frame_nr; /* Total number of frames */
};
+struct tpacket_req3 {
+ unsigned int tp_block_size; /* Minimal size of contiguous block */
+ unsigned int tp_block_nr; /* Number of blocks */
+ unsigned int tp_frame_size; /* Size of frame */
+ unsigned int tp_frame_nr; /* Total number of frames */
+ unsigned int tp_retire_blk_tov; /* timeout in msecs */
+ unsigned int tp_sizeof_priv; /* offset to private data area */
+ unsigned int tp_feature_req_word;
+};
+
+union tpacket_req_u {
+ struct tpacket_req req;
+ struct tpacket_req3 req3;
+};
+
struct packet_mreq {
int mr_ifindex;
unsigned short mr_type;
diff --git a/include/linux/if_pppol2tp.h b/include/linux/if_pppol2tp.h
index 184bc5566207..23cefa1111bf 100644
--- a/include/linux/if_pppol2tp.h
+++ b/include/linux/if_pppol2tp.h
@@ -39,7 +39,7 @@ struct pppol2tp_addr {
* bits. So we need a different sockaddr structure.
*/
struct pppol2tpv3_addr {
- pid_t pid; /* pid that owns the fd.
+ __kernel_pid_t pid; /* pid that owns the fd.
* 0 => current */
int fd; /* FD of UDP or IP socket to use */
diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h
index 397921b09ef9..b5f927f59f26 100644
--- a/include/linux/if_pppox.h
+++ b/include/linux/if_pppox.h
@@ -20,8 +20,9 @@
#include <linux/types.h>
#include <asm/byteorder.h>
-#ifdef __KERNEL__
+#include <linux/socket.h>
#include <linux/if_ether.h>
+#ifdef __KERNEL__
#include <linux/if.h>
#include <linux/netdevice.h>
#include <linux/ppp_channel.h>
@@ -63,7 +64,7 @@ struct pptp_addr {
#define PX_MAX_PROTO 3
struct sockaddr_pppox {
- sa_family_t sa_family; /* address family, AF_PPPOX */
+ __kernel_sa_family_t sa_family; /* address family, AF_PPPOX */
unsigned int sa_protocol; /* protocol identifier */
union {
struct pppoe_addr pppoe;
@@ -77,7 +78,7 @@ struct sockaddr_pppox {
* type instead.
*/
struct sockaddr_pppol2tp {
- sa_family_t sa_family; /* address family, AF_PPPOX */
+ __kernel_sa_family_t sa_family; /* address family, AF_PPPOX */
unsigned int sa_protocol; /* protocol identifier */
struct pppol2tp_addr pppol2tp;
} __attribute__((packed));
@@ -86,7 +87,7 @@ struct sockaddr_pppol2tp {
* bits. So we need a different sockaddr structure.
*/
struct sockaddr_pppol2tpv3 {
- sa_family_t sa_family; /* address family, AF_PPPOX */
+ __kernel_sa_family_t sa_family; /* address family, AF_PPPOX */
unsigned int sa_protocol; /* protocol identifier */
struct pppol2tpv3_addr pppol2tp;
} __attribute__((packed));
diff --git a/include/linux/ima.h b/include/linux/ima.h
index 09e6e62f9953..6ac8e50c6cf5 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -15,8 +15,6 @@ struct linux_binprm;
#ifdef CONFIG_IMA
extern int ima_bprm_check(struct linux_binprm *bprm);
-extern int ima_inode_alloc(struct inode *inode);
-extern void ima_inode_free(struct inode *inode);
extern int ima_file_check(struct file *file, int mask);
extern void ima_file_free(struct file *file);
extern int ima_file_mmap(struct file *file, unsigned long prot);
@@ -27,16 +25,6 @@ static inline int ima_bprm_check(struct linux_binprm *bprm)
return 0;
}
-static inline int ima_inode_alloc(struct inode *inode)
-{
- return 0;
-}
-
-static inline void ima_inode_free(struct inode *inode)
-{
- return;
-}
-
static inline int ima_file_check(struct file *file, int mask)
{
return 0;
@@ -51,6 +39,5 @@ static inline int ima_file_mmap(struct file *file, unsigned long prot)
{
return 0;
}
-
#endif /* CONFIG_IMA_H */
#endif /* _LINUX_IMA_H */
diff --git a/include/linux/in.h b/include/linux/in.h
index beeb6dee2b49..01129c0ea87c 100644
--- a/include/linux/in.h
+++ b/include/linux/in.h
@@ -182,7 +182,7 @@ struct in_pktinfo {
/* Structure describing an Internet (IP) socket address. */
#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */
struct sockaddr_in {
- sa_family_t sin_family; /* Address family */
+ __kernel_sa_family_t sin_family; /* Address family */
__be16 sin_port; /* Port number */
struct in_addr sin_addr; /* Internet address */
diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h
index bc8c49022084..80b480c97532 100644
--- a/include/linux/inet_diag.h
+++ b/include/linux/inet_diag.h
@@ -97,9 +97,10 @@ enum {
INET_DIAG_INFO,
INET_DIAG_VEGASINFO,
INET_DIAG_CONG,
+ INET_DIAG_TOS,
};
-#define INET_DIAG_MAX INET_DIAG_CONG
+#define INET_DIAG_MAX INET_DIAG_TOS
/* INET_DIAG_MEM */
diff --git a/include/linux/integrity.h b/include/linux/integrity.h
new file mode 100644
index 000000000000..a0c41256cb92
--- /dev/null
+++ b/include/linux/integrity.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2009 IBM Corporation
+ * Author: Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ */
+
+#ifndef _LINUX_INTEGRITY_H
+#define _LINUX_INTEGRITY_H
+
+#include <linux/fs.h>
+
+enum integrity_status {
+ INTEGRITY_PASS = 0,
+ INTEGRITY_FAIL,
+ INTEGRITY_NOLABEL,
+ INTEGRITY_NOXATTRS,
+ INTEGRITY_UNKNOWN,
+};
+
+/* List of EVM protected security xattrs */
+#ifdef CONFIG_INTEGRITY
+extern int integrity_inode_alloc(struct inode *inode);
+extern void integrity_inode_free(struct inode *inode);
+
+#else
+static inline int integrity_inode_alloc(struct inode *inode)
+{
+ return 0;
+}
+
+static inline void integrity_inode_free(struct inode *inode)
+{
+ return;
+}
+#endif /* CONFIG_INTEGRITY_H */
+#endif /* _LINUX_INTEGRITY_H */
diff --git a/include/linux/io-mapping.h b/include/linux/io-mapping.h
index 8cdcc2a199ad..c81ed2ac16bd 100644
--- a/include/linux/io-mapping.h
+++ b/include/linux/io-mapping.h
@@ -27,7 +27,7 @@
* The io_mapping mechanism provides an abstraction for mapping
* individual pages from an io device to the CPU in an efficient fashion.
*
- * See Documentation/io_mapping.txt
+ * See Documentation/io-mapping.txt
*/
#ifdef CONFIG_HAVE_ATOMIC_IOMAP
diff --git a/include/linux/ip6_tunnel.h b/include/linux/ip6_tunnel.h
index acb9ad684d63..bf22b0317902 100644
--- a/include/linux/ip6_tunnel.h
+++ b/include/linux/ip6_tunnel.h
@@ -16,6 +16,8 @@
#define IP6_TNL_F_MIP6_DEV 0x8
/* copy DSCP from the outer packet */
#define IP6_TNL_F_RCV_DSCP_COPY 0x10
+/* copy fwmark from inner packet */
+#define IP6_TNL_F_USE_ORIG_FWMARK 0x20
struct ip6_tnl_parm {
char name[IFNAMSIZ]; /* name of tunnel device */
diff --git a/include/linux/ipx.h b/include/linux/ipx.h
index aabb1d294025..3d48014cdd71 100644
--- a/include/linux/ipx.h
+++ b/include/linux/ipx.h
@@ -7,7 +7,7 @@
#define IPX_MTU 576
struct sockaddr_ipx {
- sa_family_t sipx_family;
+ __kernel_sa_family_t sipx_family;
__be16 sipx_port;
__be32 sipx_network;
unsigned char sipx_node[IPX_NODE_LEN];
diff --git a/include/linux/irda.h b/include/linux/irda.h
index 00bdad0e8515..a014c3252311 100644
--- a/include/linux/irda.h
+++ b/include/linux/irda.h
@@ -26,12 +26,9 @@
#define KERNEL_IRDA_H
#include <linux/types.h>
+#include <linux/socket.h>
-/* Please do *not* add any #include in this file, this file is
- * included as-is in user space.
- * Please fix the calling file to properly included needed files before
- * this one, or preferably to include <net/irda/irda.h> instead.
- * Jean II */
+/* Note that this file is shared with user space. */
/* Hint bit positions for first hint byte */
#define HINT_PNP 0x01
@@ -125,7 +122,7 @@ enum {
#define LSAP_ANY 0xff
struct sockaddr_irda {
- sa_family_t sir_family; /* AF_IRDA */
+ __kernel_sa_family_t sir_family; /* AF_IRDA */
__u8 sir_lsap_sel; /* LSAP selector */
__u32 sir_addr; /* Device address */
char sir_name[25]; /* Usually <service>:IrDA:TinyTP */
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index e807ad687a07..3ad553e8eae2 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -80,6 +80,7 @@ extern void irq_domain_del(struct irq_domain *domain);
#endif /* CONFIG_IRQ_DOMAIN */
#if defined(CONFIG_IRQ_DOMAIN) && defined(CONFIG_OF_IRQ)
+extern struct irq_domain_ops irq_domain_simple_ops;
extern void irq_domain_add_simple(struct device_node *controller, int irq_base);
extern void irq_domain_generate_simple(const struct of_device_id *match,
u64 phys_base, unsigned int irq_start);
diff --git a/include/linux/isdn.h b/include/linux/isdn.h
index 44cd663c53b6..4ccf95d681b4 100644
--- a/include/linux/isdn.h
+++ b/include/linux/isdn.h
@@ -68,7 +68,7 @@
#define ISDN_NET_ENCAP_SYNCPPP 4
#define ISDN_NET_ENCAP_UIHDLC 5
#define ISDN_NET_ENCAP_CISCOHDLCK 6 /* With SLARP and keepalive */
-#define ISDN_NET_ENCAP_X25IFACE 7 /* Documentation/networking/x25-iface.txt*/
+#define ISDN_NET_ENCAP_X25IFACE 7 /* Documentation/networking/x25-iface.txt */
#define ISDN_NET_ENCAP_MAX_ENCAP ISDN_NET_ENCAP_X25IFACE
/* Facility which currently uses an ISDN-channel */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 46ac9a50528d..8eefcf7e95eb 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -382,7 +382,7 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
}
extern int hex_to_bin(char ch);
-extern void hex2bin(u8 *dst, const char *src, size_t count);
+extern int __must_check hex2bin(u8 *dst, const char *src, size_t count);
/*
* General tracing related utility functions - trace_printk(),
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 2c366b52f505..aace6b8691a2 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -553,6 +553,7 @@ struct kvm_ppc_pvinfo {
#define KVM_CAP_SPAPR_TCE 63
#define KVM_CAP_PPC_SMT 64
#define KVM_CAP_PPC_RMA 65
+#define KVM_CAP_S390_GMAP 71
#ifdef KVM_CAP_IRQ_ROUTING
diff --git a/include/linux/l2tp.h b/include/linux/l2tp.h
index 4bdb31df8e72..e77d7f9bb246 100644
--- a/include/linux/l2tp.h
+++ b/include/linux/l2tp.h
@@ -8,8 +8,8 @@
#define _LINUX_L2TP_H_
#include <linux/types.h>
-#ifdef __KERNEL__
#include <linux/socket.h>
+#ifdef __KERNEL__
#include <linux/in.h>
#else
#include <netinet/in.h>
@@ -26,14 +26,15 @@
#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */
struct sockaddr_l2tpip {
/* The first fields must match struct sockaddr_in */
- sa_family_t l2tp_family; /* AF_INET */
+ __kernel_sa_family_t l2tp_family; /* AF_INET */
__be16 l2tp_unused; /* INET port number (unused) */
struct in_addr l2tp_addr; /* Internet address */
__u32 l2tp_conn_id; /* Connection ID of tunnel */
/* Pad to size of `struct sockaddr'. */
- unsigned char __pad[sizeof(struct sockaddr) - sizeof(sa_family_t) -
+ unsigned char __pad[sizeof(struct sockaddr) -
+ sizeof(__kernel_sa_family_t) -
sizeof(__be16) - sizeof(struct in_addr) -
sizeof(__u32)];
};
diff --git a/include/linux/lapb.h b/include/linux/lapb.h
index ce709e1885cc..873c1eb635e4 100644
--- a/include/linux/lapb.h
+++ b/include/linux/lapb.h
@@ -44,7 +44,8 @@ struct lapb_parms_struct {
unsigned int mode;
};
-extern int lapb_register(struct net_device *dev, struct lapb_register_struct *callbacks);
+extern int lapb_register(struct net_device *dev,
+ const struct lapb_register_struct *callbacks);
extern int lapb_unregister(struct net_device *dev);
extern int lapb_getparms(struct net_device *dev, struct lapb_parms_struct *parms);
extern int lapb_setparms(struct net_device *dev, struct lapb_parms_struct *parms);
diff --git a/include/linux/llc.h b/include/linux/llc.h
index ad7074ba81af..a2418ae13ee9 100644
--- a/include/linux/llc.h
+++ b/include/linux/llc.h
@@ -12,16 +12,20 @@
*
* See the GNU General Public License for more details.
*/
+
+#include <linux/socket.h>
+
#define __LLC_SOCK_SIZE__ 16 /* sizeof(sockaddr_llc), word align. */
struct sockaddr_llc {
- sa_family_t sllc_family; /* AF_LLC */
- sa_family_t sllc_arphrd; /* ARPHRD_ETHER */
+ __kernel_sa_family_t sllc_family; /* AF_LLC */
+ __kernel_sa_family_t sllc_arphrd; /* ARPHRD_ETHER */
unsigned char sllc_test;
unsigned char sllc_xid;
unsigned char sllc_ua; /* UA data, only for SOCK_STREAM. */
unsigned char sllc_sap;
unsigned char sllc_mac[IFHWADDRLEN];
- unsigned char __pad[__LLC_SOCK_SIZE__ - sizeof(sa_family_t) * 2 -
+ unsigned char __pad[__LLC_SOCK_SIZE__ -
+ sizeof(__kernel_sa_family_t) * 2 -
sizeof(unsigned char) * 4 - IFHWADDRLEN];
};
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 3b535db00a94..343bd7661f2a 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -39,16 +39,6 @@ extern unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
struct mem_cgroup *mem_cont,
int active, int file);
-struct memcg_scanrecord {
- struct mem_cgroup *mem; /* scanend memory cgroup */
- struct mem_cgroup *root; /* scan target hierarchy root */
- int context; /* scanning context (see memcontrol.c) */
- unsigned long nr_scanned[2]; /* the number of scanned pages */
- unsigned long nr_rotated[2]; /* the number of rotated pages */
- unsigned long nr_freed[2]; /* the number of freed pages */
- unsigned long elapsed; /* nsec of time elapsed while scanning */
-};
-
#ifdef CONFIG_CGROUP_MEM_RES_CTLR
/*
* All "charge" functions with gfp_mask should use GFP_KERNEL or
@@ -127,15 +117,6 @@ mem_cgroup_get_reclaim_stat_from_page(struct page *page);
extern void mem_cgroup_print_oom_info(struct mem_cgroup *memcg,
struct task_struct *p);
-extern unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem,
- gfp_t gfp_mask, bool noswap,
- struct memcg_scanrecord *rec);
-extern unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
- gfp_t gfp_mask, bool noswap,
- struct zone *zone,
- struct memcg_scanrecord *rec,
- unsigned long *nr_scanned);
-
#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
extern int do_swap_account;
#endif
diff --git a/include/linux/mfd/wm831x/core.h b/include/linux/mfd/wm831x/core.h
index 8dda8ded5cda..ed8fe0d04097 100644
--- a/include/linux/mfd/wm831x/core.h
+++ b/include/linux/mfd/wm831x/core.h
@@ -18,6 +18,7 @@
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/list.h>
+#include <linux/regmap.h>
/*
* Register values.
@@ -361,12 +362,8 @@ struct wm831x {
struct mutex io_lock;
struct device *dev;
- int (*read_dev)(struct wm831x *wm831x, unsigned short reg,
- int bytes, void *dest);
- int (*write_dev)(struct wm831x *wm831x, unsigned short reg,
- int bytes, void *src);
- void *control_data;
+ struct regmap *regmap;
int irq; /* Our chip IRQ */
struct mutex irq_lock;
@@ -374,6 +371,8 @@ struct wm831x {
int irq_masks_cur[WM831X_NUM_IRQ_REGS]; /* Currently active value */
int irq_masks_cache[WM831X_NUM_IRQ_REGS]; /* Cached hardware value */
+ bool soft_shutdown;
+
/* Chip revision based flags */
unsigned has_gpio_ena:1; /* Has GPIO enable bit */
unsigned has_cs_sts:1; /* Has current sink status bit */
@@ -412,8 +411,11 @@ int wm831x_bulk_read(struct wm831x *wm831x, unsigned short reg,
int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq);
void wm831x_device_exit(struct wm831x *wm831x);
int wm831x_device_suspend(struct wm831x *wm831x);
+void wm831x_device_shutdown(struct wm831x *wm831x);
int wm831x_irq_init(struct wm831x *wm831x, int irq);
void wm831x_irq_exit(struct wm831x *wm831x);
void wm831x_auxadc_init(struct wm831x *wm831x);
+extern struct regmap_config wm831x_regmap_config;
+
#endif
diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h
index 0ba24599fe51..1d7a3f7b3b5d 100644
--- a/include/linux/mfd/wm831x/pdata.h
+++ b/include/linux/mfd/wm831x/pdata.h
@@ -123,6 +123,9 @@ struct wm831x_pdata {
/** Disable the touchscreen */
bool disable_touch;
+ /** The driver should initiate a power off sequence during shutdown */
+ bool soft_shutdown;
+
int irq_base;
int gpio_base;
int gpio_defaults[WM831X_GPIO_NUM];
diff --git a/include/linux/mfd/wm8400-private.h b/include/linux/mfd/wm8400-private.h
index 2aab4e93a5c9..0147b6968510 100644
--- a/include/linux/mfd/wm8400-private.h
+++ b/include/linux/mfd/wm8400-private.h
@@ -25,16 +25,15 @@
#include <linux/mutex.h>
#include <linux/platform_device.h>
+struct regmap;
+
#define WM8400_REGISTER_COUNT 0x55
struct wm8400 {
struct device *dev;
- int (*read_dev)(void *data, char reg, int count, u16 *dst);
- int (*write_dev)(void *data, char reg, int count, const u16 *src);
-
struct mutex io_lock;
- void *io_data;
+ struct regmap *regmap;
u16 reg_cache[WM8400_REGISTER_COUNT];
diff --git a/include/linux/mfd/wm8994/core.h b/include/linux/mfd/wm8994/core.h
index f0b69cdae41c..45df450d869f 100644
--- a/include/linux/mfd/wm8994/core.h
+++ b/include/linux/mfd/wm8994/core.h
@@ -24,6 +24,7 @@ enum wm8994_type {
struct regulator_dev;
struct regulator_bulk_data;
+struct regmap;
#define WM8994_NUM_GPIO_REGS 11
#define WM8994_NUM_LDO_REGS 2
@@ -50,18 +51,12 @@ struct regulator_bulk_data;
#define WM8994_IRQ_GPIO(x) (x + WM8994_IRQ_TEMP_WARN)
struct wm8994 {
- struct mutex io_lock;
struct mutex irq_lock;
enum wm8994_type type;
struct device *dev;
- int (*read_dev)(struct wm8994 *wm8994, unsigned short reg,
- int bytes, void *dest);
- int (*write_dev)(struct wm8994 *wm8994, unsigned short reg,
- int bytes, const void *src);
-
- void *control_data;
+ struct regmap *regmap;
int gpio_base;
int irq_base;
diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h
index d12f8d635a81..97cf4f27d647 100644
--- a/include/linux/mfd/wm8994/pdata.h
+++ b/include/linux/mfd/wm8994/pdata.h
@@ -26,7 +26,7 @@ struct wm8994_ldo_pdata {
struct regulator_init_data *init_data;
};
-#define WM8994_CONFIGURE_GPIO 0x8000
+#define WM8994_CONFIGURE_GPIO 0x10000
#define WM8994_DRC_REGS 5
#define WM8994_EQ_REGS 20
diff --git a/include/linux/mii.h b/include/linux/mii.h
index 103113a2fd18..27748230aa69 100644
--- a/include/linux/mii.h
+++ b/include/linux/mii.h
@@ -11,131 +11,130 @@
#include <linux/types.h>
/* Generic MII registers. */
-
-#define MII_BMCR 0x00 /* Basic mode control register */
-#define MII_BMSR 0x01 /* Basic mode status register */
-#define MII_PHYSID1 0x02 /* PHYS ID 1 */
-#define MII_PHYSID2 0x03 /* PHYS ID 2 */
-#define MII_ADVERTISE 0x04 /* Advertisement control reg */
-#define MII_LPA 0x05 /* Link partner ability reg */
-#define MII_EXPANSION 0x06 /* Expansion register */
-#define MII_CTRL1000 0x09 /* 1000BASE-T control */
-#define MII_STAT1000 0x0a /* 1000BASE-T status */
-#define MII_ESTATUS 0x0f /* Extended Status */
-#define MII_DCOUNTER 0x12 /* Disconnect counter */
-#define MII_FCSCOUNTER 0x13 /* False carrier counter */
-#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */
-#define MII_RERRCOUNTER 0x15 /* Receive error counter */
-#define MII_SREVISION 0x16 /* Silicon revision */
-#define MII_RESV1 0x17 /* Reserved... */
-#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */
-#define MII_PHYADDR 0x19 /* PHY address */
-#define MII_RESV2 0x1a /* Reserved... */
-#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */
-#define MII_NCONFIG 0x1c /* Network interface config */
+#define MII_BMCR 0x00 /* Basic mode control register */
+#define MII_BMSR 0x01 /* Basic mode status register */
+#define MII_PHYSID1 0x02 /* PHYS ID 1 */
+#define MII_PHYSID2 0x03 /* PHYS ID 2 */
+#define MII_ADVERTISE 0x04 /* Advertisement control reg */
+#define MII_LPA 0x05 /* Link partner ability reg */
+#define MII_EXPANSION 0x06 /* Expansion register */
+#define MII_CTRL1000 0x09 /* 1000BASE-T control */
+#define MII_STAT1000 0x0a /* 1000BASE-T status */
+#define MII_ESTATUS 0x0f /* Extended Status */
+#define MII_DCOUNTER 0x12 /* Disconnect counter */
+#define MII_FCSCOUNTER 0x13 /* False carrier counter */
+#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */
+#define MII_RERRCOUNTER 0x15 /* Receive error counter */
+#define MII_SREVISION 0x16 /* Silicon revision */
+#define MII_RESV1 0x17 /* Reserved... */
+#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */
+#define MII_PHYADDR 0x19 /* PHY address */
+#define MII_RESV2 0x1a /* Reserved... */
+#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */
+#define MII_NCONFIG 0x1c /* Network interface config */
/* Basic mode control register. */
-#define BMCR_RESV 0x003f /* Unused... */
-#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */
-#define BMCR_CTST 0x0080 /* Collision test */
-#define BMCR_FULLDPLX 0x0100 /* Full duplex */
-#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */
-#define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */
-#define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */
-#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */
-#define BMCR_SPEED100 0x2000 /* Select 100Mbps */
-#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */
-#define BMCR_RESET 0x8000 /* Reset the DP83840 */
+#define BMCR_RESV 0x003f /* Unused... */
+#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */
+#define BMCR_CTST 0x0080 /* Collision test */
+#define BMCR_FULLDPLX 0x0100 /* Full duplex */
+#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */
+#define BMCR_ISOLATE 0x0400 /* Isolate data paths from MII */
+#define BMCR_PDOWN 0x0800 /* Enable low power state */
+#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */
+#define BMCR_SPEED100 0x2000 /* Select 100Mbps */
+#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */
+#define BMCR_RESET 0x8000 /* Reset to default state */
/* Basic mode status register. */
-#define BMSR_ERCAP 0x0001 /* Ext-reg capability */
-#define BMSR_JCD 0x0002 /* Jabber detected */
-#define BMSR_LSTATUS 0x0004 /* Link status */
-#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */
-#define BMSR_RFAULT 0x0010 /* Remote fault detected */
-#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */
-#define BMSR_RESV 0x00c0 /* Unused... */
-#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */
-#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */
-#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */
-#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */
-#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */
-#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */
-#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */
-#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */
+#define BMSR_ERCAP 0x0001 /* Ext-reg capability */
+#define BMSR_JCD 0x0002 /* Jabber detected */
+#define BMSR_LSTATUS 0x0004 /* Link status */
+#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */
+#define BMSR_RFAULT 0x0010 /* Remote fault detected */
+#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */
+#define BMSR_RESV 0x00c0 /* Unused... */
+#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */
+#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */
+#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */
+#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */
+#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */
+#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */
+#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */
+#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */
/* Advertisement control register. */
-#define ADVERTISE_SLCT 0x001f /* Selector bits */
-#define ADVERTISE_CSMA 0x0001 /* Only selector supported */
-#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
-#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */
-#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
-#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */
-#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
-#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */
-#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
-#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */
-#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */
-#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */
-#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */
-#define ADVERTISE_RESV 0x1000 /* Unused... */
-#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */
-#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */
-#define ADVERTISE_NPAGE 0x8000 /* Next page bit */
-
-#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \
- ADVERTISE_CSMA)
-#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
- ADVERTISE_100HALF | ADVERTISE_100FULL)
+#define ADVERTISE_SLCT 0x001f /* Selector bits */
+#define ADVERTISE_CSMA 0x0001 /* Only selector supported */
+#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
+#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */
+#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
+#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */
+#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
+#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */
+#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
+#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */
+#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */
+#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */
+#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */
+#define ADVERTISE_RESV 0x1000 /* Unused... */
+#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */
+#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */
+#define ADVERTISE_NPAGE 0x8000 /* Next page bit */
+
+#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \
+ ADVERTISE_CSMA)
+#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
+ ADVERTISE_100HALF | ADVERTISE_100FULL)
/* Link partner ability register. */
-#define LPA_SLCT 0x001f /* Same as advertise selector */
-#define LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */
-#define LPA_1000XFULL 0x0020 /* Can do 1000BASE-X full-duplex */
-#define LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */
-#define LPA_1000XHALF 0x0040 /* Can do 1000BASE-X half-duplex */
-#define LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */
-#define LPA_1000XPAUSE 0x0080 /* Can do 1000BASE-X pause */
-#define LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */
-#define LPA_1000XPAUSE_ASYM 0x0100 /* Can do 1000BASE-X pause asym*/
-#define LPA_100BASE4 0x0200 /* Can do 100mbps 4k packets */
-#define LPA_PAUSE_CAP 0x0400 /* Can pause */
-#define LPA_PAUSE_ASYM 0x0800 /* Can pause asymetrically */
-#define LPA_RESV 0x1000 /* Unused... */
-#define LPA_RFAULT 0x2000 /* Link partner faulted */
-#define LPA_LPACK 0x4000 /* Link partner acked us */
-#define LPA_NPAGE 0x8000 /* Next page bit */
+#define LPA_SLCT 0x001f /* Same as advertise selector */
+#define LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */
+#define LPA_1000XFULL 0x0020 /* Can do 1000BASE-X full-duplex */
+#define LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */
+#define LPA_1000XHALF 0x0040 /* Can do 1000BASE-X half-duplex */
+#define LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */
+#define LPA_1000XPAUSE 0x0080 /* Can do 1000BASE-X pause */
+#define LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */
+#define LPA_1000XPAUSE_ASYM 0x0100 /* Can do 1000BASE-X pause asym*/
+#define LPA_100BASE4 0x0200 /* Can do 100mbps 4k packets */
+#define LPA_PAUSE_CAP 0x0400 /* Can pause */
+#define LPA_PAUSE_ASYM 0x0800 /* Can pause asymetrically */
+#define LPA_RESV 0x1000 /* Unused... */
+#define LPA_RFAULT 0x2000 /* Link partner faulted */
+#define LPA_LPACK 0x4000 /* Link partner acked us */
+#define LPA_NPAGE 0x8000 /* Next page bit */
#define LPA_DUPLEX (LPA_10FULL | LPA_100FULL)
#define LPA_100 (LPA_100FULL | LPA_100HALF | LPA_100BASE4)
/* Expansion register for auto-negotiation. */
-#define EXPANSION_NWAY 0x0001 /* Can do N-way auto-nego */
-#define EXPANSION_LCWP 0x0002 /* Got new RX page code word */
-#define EXPANSION_ENABLENPAGE 0x0004 /* This enables npage words */
-#define EXPANSION_NPCAPABLE 0x0008 /* Link partner supports npage */
-#define EXPANSION_MFAULTS 0x0010 /* Multiple faults detected */
-#define EXPANSION_RESV 0xffe0 /* Unused... */
+#define EXPANSION_NWAY 0x0001 /* Can do N-way auto-nego */
+#define EXPANSION_LCWP 0x0002 /* Got new RX page code word */
+#define EXPANSION_ENABLENPAGE 0x0004 /* This enables npage words */
+#define EXPANSION_NPCAPABLE 0x0008 /* Link partner supports npage */
+#define EXPANSION_MFAULTS 0x0010 /* Multiple faults detected */
+#define EXPANSION_RESV 0xffe0 /* Unused... */
-#define ESTATUS_1000_TFULL 0x2000 /* Can do 1000BT Full */
-#define ESTATUS_1000_THALF 0x1000 /* Can do 1000BT Half */
+#define ESTATUS_1000_TFULL 0x2000 /* Can do 1000BT Full */
+#define ESTATUS_1000_THALF 0x1000 /* Can do 1000BT Half */
/* N-way test register. */
-#define NWAYTEST_RESV1 0x00ff /* Unused... */
-#define NWAYTEST_LOOPBACK 0x0100 /* Enable loopback for N-way */
-#define NWAYTEST_RESV2 0xfe00 /* Unused... */
+#define NWAYTEST_RESV1 0x00ff /* Unused... */
+#define NWAYTEST_LOOPBACK 0x0100 /* Enable loopback for N-way */
+#define NWAYTEST_RESV2 0xfe00 /* Unused... */
/* 1000BASE-T Control register */
-#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */
-#define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */
+#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */
+#define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */
#define CTL1000_AS_MASTER 0x0800
#define CTL1000_ENABLE_MASTER 0x1000
/* 1000BASE-T Status register */
-#define LPA_1000LOCALRXOK 0x2000 /* Link partner local receiver status */
-#define LPA_1000REMRXOK 0x1000 /* Link partner remote receiver status */
-#define LPA_1000FULL 0x0800 /* Link partner 1000BASE-T full duplex */
-#define LPA_1000HALF 0x0400 /* Link partner 1000BASE-T half duplex */
+#define LPA_1000LOCALRXOK 0x2000 /* Link partner local receiver status */
+#define LPA_1000REMRXOK 0x1000 /* Link partner remote receiver status */
+#define LPA_1000FULL 0x0800 /* Link partner 1000BASE-T full duplex */
+#define LPA_1000HALF 0x0400 /* Link partner 1000BASE-T half duplex */
/* Flow control flags */
#define FLOW_CTRL_TX 0x01
@@ -149,7 +148,7 @@ struct mii_ioctl_data {
__u16 val_out;
};
-#ifdef __KERNEL__
+#ifdef __KERNEL__
#include <linux/if.h>
@@ -180,7 +179,7 @@ extern unsigned int mii_check_media (struct mii_if_info *mii,
unsigned int ok_to_print,
unsigned int init_media);
extern int generic_mii_ioctl(struct mii_if_info *mii_if,
- struct mii_ioctl_data *mii_data, int cmd,
+ struct mii_ioctl_data *mii_data, int cmd,
unsigned int *duplex_changed);
@@ -189,7 +188,6 @@ static inline struct mii_ioctl_data *if_mii(struct ifreq *rq)
return (struct mii_ioctl_data *) &rq->ifr_ifru;
}
-
/**
* mii_nway_result
* @negotiated: value of MII ANAR and'd with ANLPAR
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index 53ef894bfa05..2366f94a095a 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -75,6 +75,7 @@ enum {
MLX4_DEV_CAP_FLAG_UD_MCAST = 1LL << 21,
MLX4_DEV_CAP_FLAG_IBOE = 1LL << 30,
MLX4_DEV_CAP_FLAG_UC_LOOPBACK = 1LL << 32,
+ MLX4_DEV_CAP_FLAG_FCS_KEEP = 1LL << 34,
MLX4_DEV_CAP_FLAG_WOL = 1LL << 38,
MLX4_DEV_CAP_FLAG_UDP_RSS = 1LL << 40,
MLX4_DEV_CAP_FLAG_VEP_UC_STEER = 1LL << 41,
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 774b8952deb4..29971a589ff2 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -135,6 +135,17 @@ struct page {
#endif
;
+struct page_frag {
+ struct page *page;
+#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536)
+ __u32 offset;
+ __u32 size;
+#else
+ __u16 offset;
+ __u16 size;
+#endif
+};
+
typedef unsigned long __nocast vm_flags_t;
/*
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
index ddaae98c53f9..fffb10bd5514 100644
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -262,6 +262,26 @@ static inline void __kernel_param_unlock(void)
.str = &__param_string_##name, 0, perm); \
__MODULE_PARM_TYPE(name, "string")
+/**
+ * parameq - checks if two parameter names match
+ * @name1: parameter name 1
+ * @name2: parameter name 2
+ *
+ * Returns true if the two parameter names are equal.
+ * Dashes (-) are considered equal to underscores (_).
+ */
+extern bool parameq(const char *name1, const char *name2);
+
+/**
+ * parameqn - checks if two parameter names match
+ * @name1: parameter name 1
+ * @name2: parameter name 2
+ * @n: the length to compare
+ *
+ * Similar to parameq(), except it compares @n characters.
+ */
+extern bool parameqn(const char *name1, const char *name2, size_t n);
+
/* Called on module insert or kernel boot */
extern int parse_args(const char *name,
char *args,
diff --git a/include/linux/namei.h b/include/linux/namei.h
index 76fe2c62ae71..409328d1cbbb 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -48,11 +48,12 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
*/
#define LOOKUP_FOLLOW 0x0001
#define LOOKUP_DIRECTORY 0x0002
+#define LOOKUP_AUTOMOUNT 0x0004
#define LOOKUP_PARENT 0x0010
#define LOOKUP_REVAL 0x0020
#define LOOKUP_RCU 0x0040
-#define LOOKUP_NO_AUTOMOUNT 0x0080
+
/*
* Intent data
*/
diff --git a/include/linux/net_tstamp.h b/include/linux/net_tstamp.h
index a3b8546354ac..ae5df122e42f 100644
--- a/include/linux/net_tstamp.h
+++ b/include/linux/net_tstamp.h
@@ -45,7 +45,7 @@ struct hwtstamp_config {
};
/* possible values for hwtstamp_config->tx_type */
-enum {
+enum hwtstamp_tx_types {
/*
* No outgoing packet will need hardware time stamping;
* should a packet arrive which asks for it, no hardware
@@ -60,10 +60,19 @@ enum {
* before sending the packet.
*/
HWTSTAMP_TX_ON,
+
+ /*
+ * Enables time stamping for outgoing packets just as
+ * HWTSTAMP_TX_ON does, but also enables time stamp insertion
+ * directly into Sync packets. In this case, transmitted Sync
+ * packets will not received a time stamp via the socket error
+ * queue.
+ */
+ HWTSTAMP_TX_ONESTEP_SYNC,
};
/* possible values for hwtstamp_config->rx_filter */
-enum {
+enum hwtstamp_rx_filters {
/* time stamp no incoming packet at all */
HWTSTAMP_FILTER_NONE,
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index ddee79bb8f15..df1c836e6948 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -31,7 +31,7 @@
#include <linux/if_link.h>
#ifdef __KERNEL__
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/atomic.h>
@@ -723,9 +723,8 @@ struct netdev_tc_txq {
*
* void (*ndo_set_rx_mode)(struct net_device *dev);
* This function is called device changes address list filtering.
- *
- * void (*ndo_set_multicast_list)(struct net_device *dev);
- * This function is called when the multicast address list changes.
+ * If driver handles unicast address filtering, it should set
+ * IFF_UNICAST_FLT to its priv_flags.
*
* int (*ndo_set_mac_address)(struct net_device *dev, void *addr);
* This function is called when the Media Access Control address
@@ -782,6 +781,7 @@ struct netdev_tc_txq {
* int (*ndo_set_vf_mac)(struct net_device *dev, int vf, u8* mac);
* int (*ndo_set_vf_vlan)(struct net_device *dev, int vf, u16 vlan, u8 qos);
* int (*ndo_set_vf_tx_rate)(struct net_device *dev, int vf, int rate);
+ * int (*ndo_set_vf_spoofchk)(struct net_device *dev, int vf, bool setting);
* int (*ndo_get_vf_config)(struct net_device *dev,
* int vf, struct ifla_vf_info *ivf);
* int (*ndo_set_vf_port)(struct net_device *dev, int vf,
@@ -868,7 +868,6 @@ struct net_device_ops {
void (*ndo_change_rx_flags)(struct net_device *dev,
int flags);
void (*ndo_set_rx_mode)(struct net_device *dev);
- void (*ndo_set_multicast_list)(struct net_device *dev);
int (*ndo_set_mac_address)(struct net_device *dev,
void *addr);
int (*ndo_validate_addr)(struct net_device *dev);
@@ -902,6 +901,8 @@ struct net_device_ops {
int queue, u16 vlan, u8 qos);
int (*ndo_set_vf_tx_rate)(struct net_device *dev,
int vf, int rate);
+ int (*ndo_set_vf_spoofchk)(struct net_device *dev,
+ int vf, bool setting);
int (*ndo_get_vf_config)(struct net_device *dev,
int vf,
struct ifla_vf_info *ivf);
@@ -924,11 +925,15 @@ struct net_device_ops {
u16 xid,
struct scatterlist *sgl,
unsigned int sgc);
+#endif
+
+#if defined(CONFIG_LIBFCOE) || defined(CONFIG_LIBFCOE_MODULE)
#define NETDEV_FCOE_WWNN 0
#define NETDEV_FCOE_WWPN 1
int (*ndo_fcoe_get_wwn)(struct net_device *dev,
u64 *wwn, int type);
#endif
+
#ifdef CONFIG_RFS_ACCEL
int (*ndo_rx_flow_steer)(struct net_device *dev,
const struct sk_buff *skb,
@@ -964,7 +969,7 @@ struct net_device {
*/
char name[IFNAMSIZ];
- struct pm_qos_request_list pm_qos_req;
+ struct pm_qos_request pm_qos_req;
/* device name hash chain */
struct hlist_node name_hlist;
@@ -2587,9 +2592,6 @@ static inline int netif_is_bond_slave(struct net_device *dev)
extern struct pernet_operations __net_initdata loopback_net_ops;
-int dev_ethtool_get_settings(struct net_device *dev,
- struct ethtool_cmd *cmd);
-
static inline u32 dev_ethtool_get_rx_csum(struct net_device *dev)
{
if (dev->features & NETIF_F_RXCSUM)
@@ -2617,6 +2619,9 @@ static inline const char *netdev_name(const struct net_device *dev)
return dev->name;
}
+extern int __netdev_printk(const char *level, const struct net_device *dev,
+ struct va_format *vaf);
+
extern int netdev_printk(const char *level, const struct net_device *dev,
const char *format, ...)
__attribute__ ((format (printf, 3, 4)));
@@ -2644,8 +2649,7 @@ extern int netdev_info(const struct net_device *dev, const char *format, ...)
#elif defined(CONFIG_DYNAMIC_DEBUG)
#define netdev_dbg(__dev, format, args...) \
do { \
- dynamic_dev_dbg((__dev)->dev.parent, "%s: " format, \
- netdev_name(__dev), ##args); \
+ dynamic_netdev_dbg(__dev, format, ##args); \
} while (0)
#else
#define netdev_dbg(__dev, format, args...) \
@@ -2712,9 +2716,7 @@ do { \
#define netif_dbg(priv, type, netdev, format, args...) \
do { \
if (netif_msg_##type(priv)) \
- dynamic_dev_dbg((netdev)->dev.parent, \
- "%s: " format, \
- netdev_name(netdev), ##args); \
+ dynamic_netdev_dbg(netdev, format, ##args); \
} while (0)
#else
#define netif_dbg(priv, type, dev, format, args...) \
diff --git a/include/linux/netfilter/xt_connlimit.h b/include/linux/netfilter/xt_connlimit.h
index 0ca66e97acbc..d1366f05d1b2 100644
--- a/include/linux/netfilter/xt_connlimit.h
+++ b/include/linux/netfilter/xt_connlimit.h
@@ -2,6 +2,7 @@
#define _XT_CONNLIMIT_H
#include <linux/types.h>
+#include <linux/netfilter.h>
struct xt_connlimit_data;
diff --git a/include/linux/netfilter/xt_conntrack.h b/include/linux/netfilter/xt_conntrack.h
index 74b904d8f99c..e3c041d54020 100644
--- a/include/linux/netfilter/xt_conntrack.h
+++ b/include/linux/netfilter/xt_conntrack.h
@@ -6,6 +6,7 @@
#define _XT_CONNTRACK_H
#include <linux/types.h>
+#include <linux/netfilter.h>
#include <linux/netfilter/nf_conntrack_tuple_common.h>
#define XT_CONNTRACK_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
diff --git a/include/linux/netfilter/xt_iprange.h b/include/linux/netfilter/xt_iprange.h
index c1f21a779a45..25fd7cf851f0 100644
--- a/include/linux/netfilter/xt_iprange.h
+++ b/include/linux/netfilter/xt_iprange.h
@@ -2,6 +2,7 @@
#define _LINUX_NETFILTER_XT_IPRANGE_H 1
#include <linux/types.h>
+#include <linux/netfilter.h>
enum {
IPRANGE_SRC = 1 << 0, /* match source IP address */
diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h
index adbf4bff87ed..e08565d45178 100644
--- a/include/linux/netfilter_arp/arp_tables.h
+++ b/include/linux/netfilter_arp/arp_tables.h
@@ -52,7 +52,7 @@ struct arpt_arp {
struct in_addr smsk, tmsk;
/* Device hw address length, src+target device addresses */
- u_int8_t arhln, arhln_mask;
+ __u8 arhln, arhln_mask;
struct arpt_devaddr_info src_devaddr;
struct arpt_devaddr_info tgt_devaddr;
@@ -71,9 +71,9 @@ struct arpt_arp {
unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
/* Flags word */
- u_int8_t flags;
+ __u8 flags;
/* Inverse flags */
- u_int16_t invflags;
+ __u16 invflags;
};
/* Values for "flag" field in struct arpt_ip (general arp structure).
@@ -102,9 +102,9 @@ struct arpt_entry
struct arpt_arp arp;
/* Size of arpt_entry + matches */
- u_int16_t target_offset;
+ __u16 target_offset;
/* Size of arpt_entry + matches + target */
- u_int16_t next_offset;
+ __u16 next_offset;
/* Back pointer */
unsigned int comefrom;
@@ -260,8 +260,8 @@ extern unsigned int arpt_do_table(struct sk_buff *skb,
struct compat_arpt_entry {
struct arpt_arp arp;
- u_int16_t target_offset;
- u_int16_t next_offset;
+ __u16 target_offset;
+ __u16 next_offset;
compat_uint_t comefrom;
struct compat_xt_counters counters;
unsigned char elems[0];
diff --git a/include/linux/netfilter_decnet.h b/include/linux/netfilter_decnet.h
index 6f425369ee29..0b09732aacd5 100644
--- a/include/linux/netfilter_decnet.h
+++ b/include/linux/netfilter_decnet.h
@@ -11,6 +11,9 @@
/* only for userspace compatibility */
#ifndef __KERNEL__
+
+#include <limits.h> /* for INT_MIN, INT_MAX */
+
/* IP Cache bits. */
/* Src IP address. */
#define NFC_DN_SRC 0x0001
diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h
index 29c7727ff0e8..fa0946c549d3 100644
--- a/include/linux/netfilter_ipv4.h
+++ b/include/linux/netfilter_ipv4.h
@@ -9,6 +9,9 @@
/* only for userspace compatibility */
#ifndef __KERNEL__
+
+#include <limits.h> /* for INT_MIN, INT_MAX */
+
/* IP Cache bits. */
/* Src IP address. */
#define NFC_IP_SRC 0x0001
diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h
index 64a5d95c58e8..db79231914ce 100644
--- a/include/linux/netfilter_ipv4/ip_tables.h
+++ b/include/linux/netfilter_ipv4/ip_tables.h
@@ -81,12 +81,12 @@ struct ipt_ip {
unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
/* Protocol, 0 = ANY */
- u_int16_t proto;
+ __u16 proto;
/* Flags word */
- u_int8_t flags;
+ __u8 flags;
/* Inverse flags */
- u_int8_t invflags;
+ __u8 invflags;
};
/* Values for "flag" field in struct ipt_ip (general ip structure). */
@@ -114,9 +114,9 @@ struct ipt_entry {
unsigned int nfcache;
/* Size of ipt_entry + matches */
- u_int16_t target_offset;
+ __u16 target_offset;
/* Size of ipt_entry + matches + target */
- u_int16_t next_offset;
+ __u16 next_offset;
/* Back pointer */
unsigned int comefrom;
@@ -149,9 +149,9 @@ struct ipt_entry {
/* ICMP matching stuff */
struct ipt_icmp {
- u_int8_t type; /* type to match */
- u_int8_t code[2]; /* range of code */
- u_int8_t invflags; /* Inverse flags */
+ __u8 type; /* type to match */
+ __u8 code[2]; /* range of code */
+ __u8 invflags; /* Inverse flags */
};
/* Values for "inv" field for struct ipt_icmp. */
@@ -288,8 +288,8 @@ extern unsigned int ipt_do_table(struct sk_buff *skb,
struct compat_ipt_entry {
struct ipt_ip ip;
compat_uint_t nfcache;
- u_int16_t target_offset;
- u_int16_t next_offset;
+ __u16 target_offset;
+ __u16 next_offset;
compat_uint_t comefrom;
struct compat_xt_counters counters;
unsigned char elems[0];
diff --git a/include/linux/netfilter_ipv6.h b/include/linux/netfilter_ipv6.h
index 1f7e300094cd..57c025127f1d 100644
--- a/include/linux/netfilter_ipv6.h
+++ b/include/linux/netfilter_ipv6.h
@@ -12,6 +12,9 @@
/* only for userspace compatibility */
#ifndef __KERNEL__
+
+#include <limits.h> /* for INT_MIN, INT_MAX */
+
/* IP Cache bits. */
/* Src IP address. */
#define NFC_IP6_SRC 0x0001
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h
index c9784f7a9c1f..f549adccc94c 100644
--- a/include/linux/netfilter_ipv6/ip6_tables.h
+++ b/include/linux/netfilter_ipv6/ip6_tables.h
@@ -81,14 +81,14 @@ struct ip6t_ip6 {
* MH do not match any packets.
* - You also need to set IP6T_FLAGS_PROTO to "flags" to check protocol.
*/
- u_int16_t proto;
+ __u16 proto;
/* TOS to match iff flags & IP6T_F_TOS */
- u_int8_t tos;
+ __u8 tos;
/* Flags word */
- u_int8_t flags;
+ __u8 flags;
/* Inverse flags */
- u_int8_t invflags;
+ __u8 invflags;
};
/* Values for "flag" field in struct ip6t_ip6 (general ip6 structure). */
@@ -118,9 +118,9 @@ struct ip6t_entry {
unsigned int nfcache;
/* Size of ipt_entry + matches */
- u_int16_t target_offset;
+ __u16 target_offset;
/* Size of ipt_entry + matches + target */
- u_int16_t next_offset;
+ __u16 next_offset;
/* Back pointer */
unsigned int comefrom;
@@ -186,9 +186,9 @@ struct ip6t_error {
/* ICMP matching stuff */
struct ip6t_icmp {
- u_int8_t type; /* type to match */
- u_int8_t code[2]; /* range of code */
- u_int8_t invflags; /* Inverse flags */
+ __u8 type; /* type to match */
+ __u8 code[2]; /* range of code */
+ __u8 invflags; /* Inverse flags */
};
/* Values for "inv" field for struct ipt_icmp. */
@@ -298,8 +298,8 @@ extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
struct compat_ip6t_entry {
struct ip6t_ip6 ipv6;
compat_uint_t nfcache;
- u_int16_t target_offset;
- u_int16_t next_offset;
+ __u16 target_offset;
+ __u16 next_offset;
compat_uint_t comefrom;
struct compat_xt_counters counters;
unsigned char elems[0];
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 180540a84d37..8180cd9d73d5 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -1,7 +1,7 @@
#ifndef __LINUX_NETLINK_H
#define __LINUX_NETLINK_H
-#include <linux/socket.h> /* for sa_family_t */
+#include <linux/socket.h> /* for __kernel_sa_family_t */
#include <linux/types.h>
#define NETLINK_ROUTE 0 /* Routing/device hook */
diff --git a/include/linux/netrom.h b/include/linux/netrom.h
index 6939b32f66a0..af7313cc9cb6 100644
--- a/include/linux/netrom.h
+++ b/include/linux/netrom.h
@@ -7,6 +7,8 @@
#ifndef NETROM_KERNEL_H
#define NETROM_KERNEL_H
+#include <linux/ax25.h>
+
#define NETROM_MTU 236
#define NETROM_T1 1
diff --git a/include/linux/nfc.h b/include/linux/nfc.h
index 330a4c5db588..36cb955b05cc 100644
--- a/include/linux/nfc.h
+++ b/include/linux/nfc.h
@@ -39,6 +39,10 @@
*
* @NFC_CMD_GET_DEVICE: request information about a device (requires
* %NFC_ATTR_DEVICE_INDEX) or dump request to get a list of all nfc devices
+ * @NFC_CMD_DEV_UP: turn on the nfc device
+ * (requires %NFC_ATTR_DEVICE_INDEX)
+ * @NFC_CMD_DEV_DOWN: turn off the nfc device
+ * (requires %NFC_ATTR_DEVICE_INDEX)
* @NFC_CMD_START_POLL: start polling for targets using the given protocols
* (requires %NFC_ATTR_DEVICE_INDEX and %NFC_ATTR_PROTOCOLS)
* @NFC_CMD_STOP_POLL: stop polling for targets (requires
@@ -56,6 +60,8 @@
enum nfc_commands {
NFC_CMD_UNSPEC,
NFC_CMD_GET_DEVICE,
+ NFC_CMD_DEV_UP,
+ NFC_CMD_DEV_DOWN,
NFC_CMD_START_POLL,
NFC_CMD_STOP_POLL,
NFC_CMD_GET_TARGET,
@@ -123,4 +129,6 @@ struct sockaddr_nfc {
#define NFC_SOCKPROTO_RAW 0
#define NFC_SOCKPROTO_MAX 1
+#define NFC_HEADER_SIZE 1
+
#endif /*__LINUX_NFC_H */
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 76f99e8714f3..32345c2805c0 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -373,6 +373,22 @@ enum nfsstat4 {
NFS4ERR_DELEG_REVOKED = 10087, /* deleg./layout revoked */
};
+static inline bool seqid_mutating_err(u32 err)
+{
+ /* rfc 3530 section 8.1.5: */
+ switch (err) {
+ case NFS4ERR_STALE_CLIENTID:
+ case NFS4ERR_STALE_STATEID:
+ case NFS4ERR_BAD_STATEID:
+ case NFS4ERR_BAD_SEQID:
+ case NFS4ERR_BADXDR:
+ case NFS4ERR_RESOURCE:
+ case NFS4ERR_NOFILEHANDLE:
+ return false;
+ };
+ return true;
+}
+
/*
* Note: NF4BAD is not actually part of the protocol; it is just used
* internally by nfsd.
@@ -394,7 +410,10 @@ enum open_claim_type4 {
NFS4_OPEN_CLAIM_NULL = 0,
NFS4_OPEN_CLAIM_PREVIOUS = 1,
NFS4_OPEN_CLAIM_DELEGATE_CUR = 2,
- NFS4_OPEN_CLAIM_DELEGATE_PREV = 3
+ NFS4_OPEN_CLAIM_DELEGATE_PREV = 3,
+ NFS4_OPEN_CLAIM_FH = 4, /* 4.1 */
+ NFS4_OPEN_CLAIM_DELEG_CUR_FH = 5, /* 4.1 */
+ NFS4_OPEN_CLAIM_DELEG_PREV_FH = 6, /* 4.1 */
};
enum opentype4 {
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index eaac770f886e..60a137b7f171 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -149,7 +149,6 @@ struct nfs_inode {
unsigned long read_cache_jiffies;
unsigned long attrtimeo;
unsigned long attrtimeo_timestamp;
- __u64 change_attr; /* v4 only */
unsigned long attr_gencount;
/* "Generation counter" for the attribute cache. This is
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h
index e2791a27a901..ab465fe8c3d6 100644
--- a/include/linux/nfs_page.h
+++ b/include/linux/nfs_page.h
@@ -34,6 +34,7 @@ enum {
PG_NEED_COMMIT,
PG_NEED_RESCHED,
PG_PNFS_COMMIT,
+ PG_PARTIAL_READ_FAILED,
};
struct nfs_inode;
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index abd615d74a29..c74595ba7094 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1133,7 +1133,6 @@ struct nfs_page;
#define NFS_PAGEVEC_SIZE (8U)
struct nfs_read_data {
- int flags;
struct rpc_task task;
struct inode *inode;
struct rpc_cred *cred;
@@ -1156,7 +1155,6 @@ struct nfs_read_data {
};
struct nfs_write_data {
- int flags;
struct rpc_task task;
struct inode *inode;
struct rpc_cred *cred;
@@ -1197,9 +1195,6 @@ struct nfs_rpc_ops {
int (*getroot) (struct nfs_server *, struct nfs_fh *,
struct nfs_fsinfo *);
- int (*lookupfh)(struct nfs_server *, struct nfs_fh *,
- struct qstr *, struct nfs_fh *,
- struct nfs_fattr *);
int (*getattr) (struct nfs_server *, struct nfs_fh *,
struct nfs_fattr *);
int (*setattr) (struct dentry *, struct nfs_fattr *,
diff --git a/include/linux/nfsd/Kbuild b/include/linux/nfsd/Kbuild
index 55d1467de3c1..b8d4001212b3 100644
--- a/include/linux/nfsd/Kbuild
+++ b/include/linux/nfsd/Kbuild
@@ -1,6 +1,4 @@
-header-y += const.h
header-y += debug.h
header-y += export.h
header-y += nfsfh.h
header-y += stats.h
-header-y += syscall.h
diff --git a/include/linux/nfsd/const.h b/include/linux/nfsd/const.h
deleted file mode 100644
index 323f8cfa060a..000000000000
--- a/include/linux/nfsd/const.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * include/linux/nfsd/const.h
- *
- * Various constants related to NFS.
- *
- * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
- */
-
-#ifndef _LINUX_NFSD_CONST_H
-#define _LINUX_NFSD_CONST_H
-
-#include <linux/nfs.h>
-#include <linux/nfs2.h>
-#include <linux/nfs3.h>
-#include <linux/nfs4.h>
-
-/*
- * Maximum protocol version supported by knfsd
- */
-#define NFSSVC_MAXVERS 3
-
-/*
- * Maximum blocksizes supported by daemon under various circumstances.
- */
-#define NFSSVC_MAXBLKSIZE RPCSVC_MAXPAYLOAD
-/* NFSv2 is limited by the protocol specification, see RFC 1094 */
-#define NFSSVC_MAXBLKSIZE_V2 (8*1024)
-
-#ifdef __KERNEL__
-
-#include <linux/sunrpc/msg_prot.h>
-
-/*
- * Largest number of bytes we need to allocate for an NFS
- * call or reply. Used to control buffer sizes. We use
- * the length of v3 WRITE, READDIR and READDIR replies
- * which are an RPC header, up to 26 XDR units of reply
- * data, and some page data.
- *
- * Note that accuracy here doesn't matter too much as the
- * size is rounded up to a page size when allocating space.
- */
-#define NFSD_BUFSIZE ((RPC_MAX_HEADER_WITH_AUTH+26)*XDR_UNIT + NFSSVC_MAXBLKSIZE)
-
-#ifdef CONFIG_NFSD_V4
-# define NFSSVC_XDRSIZE NFS4_SVC_XDRSIZE
-#elif defined(CONFIG_NFSD_V3)
-# define NFSSVC_XDRSIZE NFS3_SVC_XDRSIZE
-#else
-# define NFSSVC_XDRSIZE NFS2_SVC_XDRSIZE
-#endif
-
-#endif /* __KERNEL__ */
-
-#endif /* _LINUX_NFSD_CONST_H */
diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
index 8a31a20efe7e..f85308e688fd 100644
--- a/include/linux/nfsd/export.h
+++ b/include/linux/nfsd/export.h
@@ -96,7 +96,6 @@ struct svc_export {
struct auth_domain * ex_client;
int ex_flags;
struct path ex_path;
- char *ex_pathname;
uid_t ex_anon_uid;
gid_t ex_anon_gid;
int ex_fsid;
@@ -137,6 +136,7 @@ struct svc_export * rqst_exp_get_by_name(struct svc_rqst *,
struct path *);
struct svc_export * rqst_exp_parent(struct svc_rqst *,
struct path *);
+struct svc_export * rqst_find_fsidzero_export(struct svc_rqst *);
int exp_rootfh(struct auth_domain *,
char *path, struct knfsd_fh *, int maxsize);
__be32 exp_pseudoroot(struct svc_rqst *, struct svc_fh *);
diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h
index f76d80ccec10..ce4743a26015 100644
--- a/include/linux/nfsd/nfsfh.h
+++ b/include/linux/nfsd/nfsfh.h
@@ -14,11 +14,14 @@
#ifndef _LINUX_NFSD_FH_H
#define _LINUX_NFSD_FH_H
-# include <linux/types.h>
+#include <linux/types.h>
+#include <linux/nfs.h>
+#include <linux/nfs2.h>
+#include <linux/nfs3.h>
+#include <linux/nfs4.h>
#ifdef __KERNEL__
# include <linux/sunrpc/svc.h>
#endif
-#include <linux/nfsd/const.h>
/*
* This is the old "dentry style" Linux NFSv2 file handle.
diff --git a/include/linux/nfsd/syscall.h b/include/linux/nfsd/syscall.h
deleted file mode 100644
index 812bc1e160dc..000000000000
--- a/include/linux/nfsd/syscall.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * include/linux/nfsd/syscall.h
- *
- * This file holds all declarations for the knfsd syscall interface.
- *
- * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
- */
-
-#ifndef NFSD_SYSCALL_H
-#define NFSD_SYSCALL_H
-
-#include <linux/types.h>
-#include <linux/nfsd/export.h>
-
-/*
- * Version of the syscall interface
- */
-#define NFSCTL_VERSION 0x0201
-
-/*
- * These are the commands understood by nfsctl().
- */
-#define NFSCTL_SVC 0 /* This is a server process. */
-#define NFSCTL_ADDCLIENT 1 /* Add an NFS client. */
-#define NFSCTL_DELCLIENT 2 /* Remove an NFS client. */
-#define NFSCTL_EXPORT 3 /* export a file system. */
-#define NFSCTL_UNEXPORT 4 /* unexport a file system. */
-/*#define NFSCTL_UGIDUPDATE 5 / * update a client's uid/gid map. DISCARDED */
-/*#define NFSCTL_GETFH 6 / * get an fh by ino DISCARDED */
-#define NFSCTL_GETFD 7 /* get an fh by path (used by mountd) */
-#define NFSCTL_GETFS 8 /* get an fh by path with max FH len */
-
-/* SVC */
-struct nfsctl_svc {
- unsigned short svc_port;
- int svc_nthreads;
-};
-
-/* ADDCLIENT/DELCLIENT */
-struct nfsctl_client {
- char cl_ident[NFSCLNT_IDMAX+1];
- int cl_naddr;
- struct in_addr cl_addrlist[NFSCLNT_ADDRMAX];
- int cl_fhkeytype;
- int cl_fhkeylen;
- unsigned char cl_fhkey[NFSCLNT_KEYMAX];
-};
-
-/* EXPORT/UNEXPORT */
-struct nfsctl_export {
- char ex_client[NFSCLNT_IDMAX+1];
- char ex_path[NFS_MAXPATHLEN+1];
- __kernel_old_dev_t ex_dev;
- __kernel_ino_t ex_ino;
- int ex_flags;
- __kernel_uid_t ex_anon_uid;
- __kernel_gid_t ex_anon_gid;
-};
-
-/* GETFD */
-struct nfsctl_fdparm {
- struct sockaddr gd_addr;
- char gd_path[NFS_MAXPATHLEN+1];
- int gd_version;
-};
-
-/* GETFS - GET Filehandle with Size */
-struct nfsctl_fsparm {
- struct sockaddr gd_addr;
- char gd_path[NFS_MAXPATHLEN+1];
- int gd_maxlen;
-};
-
-/*
- * This is the argument union.
- */
-struct nfsctl_arg {
- int ca_version; /* safeguard */
- union {
- struct nfsctl_svc u_svc;
- struct nfsctl_client u_client;
- struct nfsctl_export u_export;
- struct nfsctl_fdparm u_getfd;
- struct nfsctl_fsparm u_getfs;
- /*
- * The following dummy member is needed to preserve binary compatibility
- * on platforms where alignof(void*)>alignof(int). It's needed because
- * this union used to contain a member (u_umap) which contained a
- * pointer.
- */
- void *u_ptr;
- } u;
-#define ca_svc u.u_svc
-#define ca_client u.u_client
-#define ca_export u.u_export
-#define ca_getfd u.u_getfd
-#define ca_getfs u.u_getfs
-};
-
-union nfsctl_res {
- __u8 cr_getfh[NFS_FHSIZE];
- struct knfsd_fh cr_getfs;
-};
-
-#ifdef __KERNEL__
-/*
- * Kernel syscall implementation.
- */
-extern int exp_addclient(struct nfsctl_client *ncp);
-extern int exp_delclient(struct nfsctl_client *ncp);
-extern int exp_export(struct nfsctl_export *nxp);
-extern int exp_unexport(struct nfsctl_export *nxp);
-
-#endif /* __KERNEL__ */
-
-#endif /* NFSD_SYSCALL_H */
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 8ad70dcac3f9..8049bf77d799 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -161,6 +161,13 @@
* @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_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
@@ -231,6 +238,8 @@
*
* @NL80211_CMD_GET_SCAN: get scan results
* @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters
+ * %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
+ * probe requests at CCK rate or not.
* @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to
* NL80211_CMD_GET_SCAN and on the "scan" multicast group)
* @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
@@ -425,6 +434,8 @@
* specified using %NL80211_ATTR_DURATION. When called, this operation
* returns a cookie (%NL80211_ATTR_COOKIE) that will be included with the
* TX status event pertaining to the TX request.
+ * %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
+ * management frames at CCK rate or not in 2GHz band.
* @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this
* command may be used with the corresponding cookie to cancel the wait
* time if it is known that it is no longer necessary.
@@ -492,6 +503,12 @@
* this command may also be sent by the driver as an MLME event to
* inform userspace of the new replay counter.
*
+ * @NL80211_CMD_PMKSA_CANDIDATE: This is used as an event to inform userspace
+ * of PMKSA caching dandidates.
+ *
+ * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup).
+ * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -616,6 +633,11 @@ enum nl80211_commands {
NL80211_CMD_SET_REKEY_OFFLOAD,
+ NL80211_CMD_PMKSA_CANDIDATE,
+
+ NL80211_CMD_TDLS_OPER,
+ NL80211_CMD_TDLS_MGMT,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -762,6 +784,8 @@ enum nl80211_commands {
* that can be added to a scan request
* @NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN: maximum length of information
* elements that can be added to a scheduled scan request
+ * @NL80211_ATTR_MAX_MATCH_SETS: maximum number of sets that can be
+ * used with @NL80211_ATTR_SCHED_SCAN_MATCH, a wiphy attribute.
*
* @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
* @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
@@ -842,18 +866,20 @@ enum nl80211_commands {
* @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT
* event (u16)
* @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating
- * that protected APs should be used.
+ * that protected APs should be used. This is also used with NEW_BEACON to
+ * indicate that the BSS is to use protection.
*
- * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT and ASSOCIATE to
- * indicate which unicast key ciphers will be used with the connection
+ * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT, ASSOCIATE, and NEW_BEACON
+ * to indicate which unicast key ciphers will be used with the connection
* (an array of u32).
- * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT and ASSOCIATE to indicate
- * which group key cipher will be used with the connection (a u32).
- * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT and ASSOCIATE to indicate
- * which WPA version(s) the AP we want to associate with is using
+ * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ * indicate which group key cipher will be used with the connection (a
+ * u32).
+ * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ * indicate which WPA version(s) the AP we want to associate with is using
* (a u32 with flags from &enum nl80211_wpa_versions).
- * @NL80211_ATTR_AKM_SUITES: Used with CONNECT and ASSOCIATE to indicate
- * which key management algorithm(s) to use (an array of u32).
+ * @NL80211_ATTR_AKM_SUITES: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ * indicate which key management algorithm(s) to use (an array of u32).
*
* @NL80211_ATTR_REQ_IE: (Re)association request information elements as
* sent out by the card, for ROAM and successful CONNECT events.
@@ -1002,6 +1028,24 @@ enum nl80211_commands {
* @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan
* cycles, in msecs.
+
+ * @NL80211_ATTR_SCHED_SCAN_MATCH: Nested attribute with one or more
+ * sets of attributes to match during scheduled scans. Only BSSs
+ * that match any of the sets will be reported. These are
+ * pass-thru filter rules.
+ * For a match to succeed, the BSS must match all attributes of a
+ * set. Since not every hardware supports matching all types of
+ * attributes, there is no guarantee that the reported BSSs are
+ * fully complying with the match sets and userspace needs to be
+ * able to ignore them by itself.
+ * Thus, the implementation is somewhat hardware-dependent, but
+ * this is only an optimization and the userspace application
+ * needs to handle all the non-filtered results anyway.
+ * If the match attributes don't make sense when combined with
+ * the values passed in @NL80211_ATTR_SCAN_SSIDS (eg. if an SSID
+ * is included in the probe request, but the match attributes
+ * will never let it go through), -EINVAL may be returned.
+ * If ommited, no filtering is done.
*
* @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported
* interface combinations. In each nested item, it contains attributes
@@ -1019,6 +1063,52 @@ enum nl80211_commands {
* being a list of supported rates as defined by IEEE 802.11 7.3.2.2 but
* without the length restriction (at most %NL80211_MAX_SUPP_RATES).
*
+ * @NL80211_ATTR_HIDDEN_SSID: indicates whether SSID is to be hidden from Beacon
+ * and Probe Response (when response to wildcard Probe Request); see
+ * &enum nl80211_hidden_ssid, represented as a u32
+ *
+ * @NL80211_ATTR_IE_PROBE_RESP: Information element(s) for Probe Response frame.
+ * This is used with %NL80211_CMD_NEW_BEACON and %NL80211_CMD_SET_BEACON to
+ * provide extra IEs (e.g., WPS/P2P IE) into Probe Response frames when the
+ * driver (or firmware) replies to Probe Request frames.
+ * @NL80211_ATTR_IE_ASSOC_RESP: Information element(s) for (Re)Association
+ * Response frames. This is used with %NL80211_CMD_NEW_BEACON and
+ * %NL80211_CMD_SET_BEACON to provide extra IEs (e.g., WPS/P2P IE) into
+ * (Re)Association Response frames when the driver (or firmware) replies to
+ * (Re)Association Request frames.
+ *
+ * @NL80211_ATTR_STA_WME: Nested attribute containing the wme configuration
+ * of the station, see &enum nl80211_sta_wme_attr.
+ * @NL80211_ATTR_SUPPORT_AP_UAPSD: the device supports uapsd when working
+ * as AP.
+ *
+ * @NL80211_ATTR_ROAM_SUPPORT: Indicates whether the firmware is capable of
+ * roaming to another AP in the same ESS if the signal lever is low.
+ *
+ * @NL80211_ATTR_PMKSA_CANDIDATE: Nested attribute containing the PMKSA caching
+ * candidate information, see &enum nl80211_pmksa_candidate_attr.
+ *
+ * @NL80211_ATTR_TX_NO_CCK_RATE: Indicates whether to use CCK rate or not
+ * for management frames transmission. In order to avoid p2p probe/action
+ * frames are being transmitted at CCK rate in 2GHz band, the user space
+ * applications use this attribute.
+ * This attribute is used with %NL80211_CMD_TRIGGER_SCAN and
+ * %NL80211_CMD_FRAME commands.
+ *
+ * @NL80211_ATTR_TDLS_ACTION: Low level TDLS action code (e.g. link setup
+ * request, link setup confirm, link teardown, etc.). Values are
+ * described in the TDLS (802.11z) specification.
+ * @NL80211_ATTR_TDLS_DIALOG_TOKEN: Non-zero token for uniquely identifying a
+ * TDLS conversation between two devices.
+ * @NL80211_ATTR_TDLS_OPERATION: High level TDLS operation; see
+ * &enum nl80211_tdls_operation, represented as a u8.
+ * @NL80211_ATTR_TDLS_SUPPORT: A flag indicating the device can operate
+ * as a TDLS peer sta.
+ * @NL80211_ATTR_TDLS_EXTERNAL_SETUP: The TDLS discovery/setup and teardown
+ * procedures should be performed by sending TDLS packets via
+ * %NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be
+ * used for asking the driver to perform a TDLS operation.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1224,6 +1314,29 @@ enum nl80211_attrs {
NL80211_ATTR_SCAN_SUPP_RATES,
+ NL80211_ATTR_HIDDEN_SSID,
+
+ NL80211_ATTR_IE_PROBE_RESP,
+ NL80211_ATTR_IE_ASSOC_RESP,
+
+ NL80211_ATTR_STA_WME,
+ NL80211_ATTR_SUPPORT_AP_UAPSD,
+
+ NL80211_ATTR_ROAM_SUPPORT,
+
+ NL80211_ATTR_SCHED_SCAN_MATCH,
+ NL80211_ATTR_MAX_MATCH_SETS,
+
+ NL80211_ATTR_PMKSA_CANDIDATE,
+
+ NL80211_ATTR_TX_NO_CCK_RATE,
+
+ NL80211_ATTR_TDLS_ACTION,
+ NL80211_ATTR_TDLS_DIALOG_TOKEN,
+ NL80211_ATTR_TDLS_OPERATION,
+ NL80211_ATTR_TDLS_SUPPORT,
+ NL80211_ATTR_TDLS_EXTERNAL_SETUP,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -1321,6 +1434,7 @@ enum nl80211_iftype {
* @NL80211_STA_FLAG_WME: station is WME/QoS capable
* @NL80211_STA_FLAG_MFP: station uses management frame protection
* @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated
+ * @NL80211_STA_FLAG_TDLS_PEER: station is a TDLS peer
* @NL80211_STA_FLAG_MAX: highest station flag number currently defined
* @__NL80211_STA_FLAG_AFTER_LAST: internal use
*/
@@ -1331,6 +1445,7 @@ enum nl80211_sta_flags {
NL80211_STA_FLAG_WME,
NL80211_STA_FLAG_MFP,
NL80211_STA_FLAG_AUTHENTICATED,
+ NL80211_STA_FLAG_TDLS_PEER,
/* keep last */
__NL80211_STA_FLAG_AFTER_LAST,
@@ -1433,6 +1548,7 @@ enum nl80211_sta_bss_param {
* @NL80211_STA_INFO_BSS_PARAM: current station's view of BSS, nested attribute
* containing info as possible, see &enum nl80211_sta_bss_param
* @NL80211_STA_INFO_CONNECTED_TIME: time since the station is last connected
+ * @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update.
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
@@ -1454,6 +1570,7 @@ enum nl80211_sta_info {
NL80211_STA_INFO_RX_BITRATE,
NL80211_STA_INFO_BSS_PARAM,
NL80211_STA_INFO_CONNECTED_TIME,
+ NL80211_STA_INFO_STA_FLAGS,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
@@ -1683,6 +1800,26 @@ enum nl80211_reg_rule_attr {
};
/**
+ * enum nl80211_sched_scan_match_attr - scheduled scan match attributes
+ * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching,
+ * only report BSS with matching SSID.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
+ * attribute number currently defined
+ * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_sched_scan_match_attr {
+ __NL80211_SCHED_SCAN_MATCH_ATTR_INVALID,
+
+ NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+
+ /* keep last */
+ __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
+ NL80211_SCHED_SCAN_MATCH_ATTR_MAX =
+ __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST - 1
+};
+
+/**
* enum nl80211_reg_rule_flags - regulatory rule flags
*
* @NL80211_RRF_NO_OFDM: OFDM modulation not allowed
@@ -1833,6 +1970,13 @@ enum nl80211_mntr_flags {
* @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
* source mesh point for path selection elements.
*
+ * @NL80211_MESHCONF_HWMP_RANN_INTERVAL: The interval of time (in TUs) between
+ * root announcements are transmitted.
+ *
+ * @NL80211_MESHCONF_GATE_ANNOUNCEMENTS: Advertise that this mesh station has
+ * access to a broader network beyond the MBSS. This is done via Root
+ * Announcement frames.
+ *
* @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
*
* @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
@@ -1854,6 +1998,8 @@ enum nl80211_meshconf_params {
NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
NL80211_MESHCONF_HWMP_ROOTMODE,
NL80211_MESHCONF_ELEMENT_TTL,
+ NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+ NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
/* keep last */
__NL80211_MESHCONF_ATTR_AFTER_LAST,
@@ -2430,4 +2576,78 @@ enum nl80211_rekey_data {
MAX_NL80211_REKEY_DATA = NUM_NL80211_REKEY_DATA - 1
};
+/**
+ * enum nl80211_hidden_ssid - values for %NL80211_ATTR_HIDDEN_SSID
+ * @NL80211_HIDDEN_SSID_NOT_IN_USE: do not hide SSID (i.e., broadcast it in
+ * Beacon frames)
+ * @NL80211_HIDDEN_SSID_ZERO_LEN: hide SSID by using zero-length SSID element
+ * in Beacon frames
+ * @NL80211_HIDDEN_SSID_ZERO_CONTENTS: hide SSID by using correct length of SSID
+ * element in Beacon frames but zero out each byte in the SSID
+ */
+enum nl80211_hidden_ssid {
+ NL80211_HIDDEN_SSID_NOT_IN_USE,
+ NL80211_HIDDEN_SSID_ZERO_LEN,
+ NL80211_HIDDEN_SSID_ZERO_CONTENTS
+};
+
+/**
+ * enum nl80211_sta_wme_attr - station WME attributes
+ * @__NL80211_STA_WME_INVALID: invalid number for nested attribute
+ * @NL80211_STA_WME_UAPSD_QUEUES: bitmap of uapsd queues. the format
+ * is the same as the AC bitmap in the QoS info field.
+ * @NL80211_STA_WME_MAX_SP: max service period. the format is the same
+ * as the MAX_SP field in the QoS info field (but already shifted down).
+ * @__NL80211_STA_WME_AFTER_LAST: internal
+ * @NL80211_STA_WME_MAX: highest station WME attribute
+ */
+enum nl80211_sta_wme_attr {
+ __NL80211_STA_WME_INVALID,
+ NL80211_STA_WME_UAPSD_QUEUES,
+ NL80211_STA_WME_MAX_SP,
+
+ /* keep last */
+ __NL80211_STA_WME_AFTER_LAST,
+ NL80211_STA_WME_MAX = __NL80211_STA_WME_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_pmksa_candidate_attr - attributes for PMKSA caching candidates
+ * @__NL80211_PMKSA_CANDIDATE_INVALID: invalid number for nested attributes
+ * @NL80211_PMKSA_CANDIDATE_INDEX: candidate index (u32; the smaller, the higher
+ * priority)
+ * @NL80211_PMKSA_CANDIDATE_BSSID: candidate BSSID (6 octets)
+ * @NL80211_PMKSA_CANDIDATE_PREAUTH: RSN pre-authentication supported (flag)
+ * @NUM_NL80211_PMKSA_CANDIDATE: number of PMKSA caching candidate attributes
+ * (internal)
+ * @MAX_NL80211_PMKSA_CANDIDATE: highest PMKSA caching candidate attribute
+ * (internal)
+ */
+enum nl80211_pmksa_candidate_attr {
+ __NL80211_PMKSA_CANDIDATE_INVALID,
+ NL80211_PMKSA_CANDIDATE_INDEX,
+ NL80211_PMKSA_CANDIDATE_BSSID,
+ NL80211_PMKSA_CANDIDATE_PREAUTH,
+
+ /* keep last */
+ NUM_NL80211_PMKSA_CANDIDATE,
+ MAX_NL80211_PMKSA_CANDIDATE = NUM_NL80211_PMKSA_CANDIDATE - 1
+};
+
+/**
+ * enum nl80211_tdls_operation - values for %NL80211_ATTR_TDLS_OPERATION
+ * @NL80211_TDLS_DISCOVERY_REQ: Send a TDLS discovery request
+ * @NL80211_TDLS_SETUP: Setup TDLS link
+ * @NL80211_TDLS_TEARDOWN: Teardown a TDLS link which is already established
+ * @NL80211_TDLS_ENABLE_LINK: Enable TDLS link
+ * @NL80211_TDLS_DISABLE_LINK: Disable TDLS link
+ */
+enum nl80211_tdls_operation {
+ NL80211_TDLS_DISCOVERY_REQ,
+ NL80211_TDLS_SETUP,
+ NL80211_TDLS_TEARDOWN,
+ NL80211_TDLS_ENABLE_LINK,
+ NL80211_TDLS_DISABLE_LINK,
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/include/linux/opp.h b/include/linux/opp.h
index 7020e9736fc5..87a9208f8aec 100644
--- a/include/linux/opp.h
+++ b/include/linux/opp.h
@@ -16,9 +16,14 @@
#include <linux/err.h>
#include <linux/cpufreq.h>
+#include <linux/notifier.h>
struct opp;
+enum opp_event {
+ OPP_EVENT_ADD, OPP_EVENT_ENABLE, OPP_EVENT_DISABLE,
+};
+
#if defined(CONFIG_PM_OPP)
unsigned long opp_get_voltage(struct opp *opp);
@@ -40,6 +45,8 @@ int opp_enable(struct device *dev, unsigned long freq);
int opp_disable(struct device *dev, unsigned long freq);
+struct srcu_notifier_head *opp_get_notifier(struct device *dev);
+
#else
static inline unsigned long opp_get_voltage(struct opp *opp)
{
@@ -89,6 +96,11 @@ static inline int opp_disable(struct device *dev, unsigned long freq)
{
return 0;
}
+
+struct srcu_notifier_head *opp_get_notifier(struct device *dev)
+{
+ return ERR_PTR(-EINVAL);
+}
#endif /* CONFIG_PM */
#if defined(CONFIG_CPU_FREQ) && defined(CONFIG_PM_OPP)
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 8c230cbcbb48..f1b1ca1a09e1 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -174,6 +174,8 @@ enum pci_dev_flags {
PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG = (__force pci_dev_flags_t) 1,
/* Device configuration is irrevocably lost if disabled into D3 */
PCI_DEV_FLAGS_NO_D3 = (__force pci_dev_flags_t) 2,
+ /* Provide indication device is assigned by a Virtual Machine Manager */
+ PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) 4,
};
enum pci_irq_reroute_variant {
@@ -621,8 +623,9 @@ struct pci_driver {
extern void pcie_bus_configure_settings(struct pci_bus *bus, u8 smpss);
enum pcie_bus_config_types {
- PCIE_BUS_PERFORMANCE,
+ PCIE_BUS_TUNE_OFF,
PCIE_BUS_SAFE,
+ PCIE_BUS_PERFORMANCE,
PCIE_BUS_PEER2PEER,
};
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 245bafdafd5e..c816075c01ce 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -944,8 +944,10 @@ extern void perf_pmu_unregister(struct pmu *pmu);
extern int perf_num_counters(void);
extern const char *perf_pmu_name(void);
-extern void __perf_event_task_sched_in(struct task_struct *task);
-extern void __perf_event_task_sched_out(struct task_struct *task, struct task_struct *next);
+extern void __perf_event_task_sched_in(struct task_struct *prev,
+ struct task_struct *task);
+extern void __perf_event_task_sched_out(struct task_struct *prev,
+ struct task_struct *next);
extern int perf_event_init_task(struct task_struct *child);
extern void perf_event_exit_task(struct task_struct *child);
extern void perf_event_free_task(struct task_struct *task);
@@ -1059,17 +1061,20 @@ perf_sw_event(u32 event_id, u64 nr, struct pt_regs *regs, u64 addr)
extern struct jump_label_key perf_sched_events;
-static inline void perf_event_task_sched_in(struct task_struct *task)
+static inline void perf_event_task_sched_in(struct task_struct *prev,
+ struct task_struct *task)
{
if (static_branch(&perf_sched_events))
- __perf_event_task_sched_in(task);
+ __perf_event_task_sched_in(prev, task);
}
-static inline void perf_event_task_sched_out(struct task_struct *task, struct task_struct *next)
+static inline void perf_event_task_sched_out(struct task_struct *prev,
+ struct task_struct *next)
{
perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, NULL, 0);
- __perf_event_task_sched_out(task, next);
+ if (static_branch(&perf_sched_events))
+ __perf_event_task_sched_out(prev, next);
}
extern void perf_event_mmap(struct vm_area_struct *vma);
@@ -1139,10 +1144,11 @@ extern void perf_event_disable(struct perf_event *event);
extern void perf_event_task_tick(void);
#else
static inline void
-perf_event_task_sched_in(struct task_struct *task) { }
+perf_event_task_sched_in(struct task_struct *prev,
+ struct task_struct *task) { }
static inline void
-perf_event_task_sched_out(struct task_struct *task,
- struct task_struct *next) { }
+perf_event_task_sched_out(struct task_struct *prev,
+ struct task_struct *next) { }
static inline int perf_event_init_task(struct task_struct *child) { return 0; }
static inline void perf_event_exit_task(struct task_struct *child) { }
static inline void perf_event_free_task(struct task_struct *task) { }
diff --git a/include/linux/personality.h b/include/linux/personality.h
index eec3bae164d4..8fc7dd1a57ff 100644
--- a/include/linux/personality.h
+++ b/include/linux/personality.h
@@ -22,6 +22,7 @@ extern int __set_personality(unsigned int);
* These occupy the top three bytes.
*/
enum {
+ UNAME26 = 0x0020000,
ADDR_NO_RANDOMIZE = 0x0040000, /* disable randomization of VA space */
FDPIC_FUNCPTRS = 0x0080000, /* userspace function ptrs point to descriptors
* (signal handling)
diff --git a/include/linux/phonet.h b/include/linux/phonet.h
index 6fb13841db45..f53a4167c5f4 100644
--- a/include/linux/phonet.h
+++ b/include/linux/phonet.h
@@ -24,6 +24,7 @@
#define LINUX_PHONET_H
#include <linux/types.h>
+#include <linux/socket.h>
/* Automatic protocol selection */
#define PN_PROTO_TRANSPORT 0
@@ -96,11 +97,11 @@ struct phonetmsg {
/* Phonet socket address structure */
struct sockaddr_pn {
- sa_family_t spn_family;
+ __kernel_sa_family_t spn_family;
__u8 spn_obj;
__u8 spn_dev;
__u8 spn_resource;
- __u8 spn_zero[sizeof(struct sockaddr) - sizeof(sa_family_t) - 3];
+ __u8 spn_zero[sizeof(struct sockaddr) - sizeof(__kernel_sa_family_t) - 3];
} __attribute__((packed));
/* Well known address */
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 54fc4138955f..79f337c47388 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -420,7 +420,7 @@ struct phy_driver {
/*
* Requests a Tx timestamp for 'skb'. The phy driver promises
- * to deliver it to the socket's error queue as soon as a
+ * to deliver it using skb_complete_tx_timestamp() as soon as a
* timestamp becomes available. One of the PTP_CLASS_ values
* is passed in 'type'.
*/
diff --git a/include/linux/pinctrl/machine.h b/include/linux/pinctrl/machine.h
new file mode 100644
index 000000000000..88863531d862
--- /dev/null
+++ b/include/linux/pinctrl/machine.h
@@ -0,0 +1,107 @@
+/*
+ * Machine interface for the pinctrl subsystem.
+ *
+ * Copyright (C) 2011 ST-Ericsson SA
+ * Written on behalf of Linaro for ST-Ericsson
+ * Based on bits of regulator core, gpio core and clk core
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#ifndef __LINUX_PINMUX_MACHINE_H
+#define __LINUX_PINMUX_MACHINE_H
+
+/**
+ * struct pinmux_map - boards/machines shall provide this map for devices
+ * @name: the name of this specific map entry for the particular machine.
+ * This is the second parameter passed to pinmux_get() when you want
+ * to have several mappings to the same device
+ * @ctrl_dev: the pin control device to be used by this mapping, may be NULL
+ * if you provide .ctrl_dev_name instead (this is more common)
+ * @ctrl_dev_name: the name of the device controlling this specific mapping,
+ * the name must be the same as in your struct device*, may be NULL if
+ * you provide .ctrl_dev instead
+ * @function: a function in the driver to use for this mapping, the driver
+ * will lookup the function referenced by this ID on the specified
+ * pin control device
+ * @group: sometimes a function can map to different pin groups, so this
+ * selects a certain specific pin group to activate for the function, if
+ * left as NULL, the first applicable group will be used
+ * @dev: the device using this specific mapping, may be NULL if you provide
+ * .dev_name instead (this is more common)
+ * @dev_name: the name of the device using this specific mapping, the name
+ * must be the same as in your struct device*, may be NULL if you
+ * provide .dev instead
+ * @hog_on_boot: if this is set to true, the pin control subsystem will itself
+ * hog the mappings as the pinmux device drivers are attached, so this is
+ * typically used with system maps (mux mappings without an assigned
+ * device) that you want to get hogged and enabled by default as soon as
+ * a pinmux device supporting it is registered. These maps will not be
+ * disabled and put until the system shuts down.
+ */
+struct pinmux_map {
+ const char *name;
+ struct device *ctrl_dev;
+ const char *ctrl_dev_name;
+ const char *function;
+ const char *group;
+ struct device *dev;
+ const char *dev_name;
+ const bool hog_on_boot;
+};
+
+/*
+ * Convenience macro to set a simple map from a certain pin controller and a
+ * certain function to a named device
+ */
+#define PINMUX_MAP(a, b, c, d) \
+ { .name = a, .ctrl_dev_name = b, .function = c, .dev_name = d }
+
+/*
+ * Convenience macro to map a system function onto a certain pinctrl device.
+ * System functions are not assigned to a particular device.
+ */
+#define PINMUX_MAP_SYS(a, b, c) \
+ { .name = a, .ctrl_dev_name = b, .function = c }
+
+/*
+ * Convenience macro to map a function onto the primary device pinctrl device
+ * this is especially helpful on systems that have only one pin controller
+ * or need to set up a lot of mappings on the primary controller.
+ */
+#define PINMUX_MAP_PRIMARY(a, b, c) \
+ { .name = a, .ctrl_dev_name = "pinctrl.0", .function = b, \
+ .dev_name = c }
+
+/*
+ * Convenience macro to map a system function onto the primary pinctrl device.
+ * System functions are not assigned to a particular device.
+ */
+#define PINMUX_MAP_PRIMARY_SYS(a, b) \
+ { .name = a, .ctrl_dev_name = "pinctrl.0", .function = b }
+
+/*
+ * Convenience macro to map a system function onto the primary pinctrl device,
+ * to be hogged by the pinmux core until the system shuts down.
+ */
+#define PINMUX_MAP_PRIMARY_SYS_HOG(a, b) \
+ { .name = a, .ctrl_dev_name = "pinctrl.0", .function = b, \
+ .hog_on_boot = true }
+
+
+#ifdef CONFIG_PINMUX
+
+extern int pinmux_register_mappings(struct pinmux_map const *map,
+ unsigned num_maps);
+
+#else
+
+static inline int pinmux_register_mappings(struct pinmux_map const *map,
+ unsigned num_maps)
+{
+ return 0;
+}
+
+#endif /* !CONFIG_PINMUX */
+#endif
diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
new file mode 100644
index 000000000000..3605e947fa90
--- /dev/null
+++ b/include/linux/pinctrl/pinctrl.h
@@ -0,0 +1,133 @@
+/*
+ * Interface the pinctrl subsystem
+ *
+ * Copyright (C) 2011 ST-Ericsson SA
+ * Written on behalf of Linaro for ST-Ericsson
+ * This interface is used in the core to keep track of pins.
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#ifndef __LINUX_PINCTRL_PINCTRL_H
+#define __LINUX_PINCTRL_PINCTRL_H
+
+#ifdef CONFIG_PINCTRL
+
+#include <linux/radix-tree.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/seq_file.h>
+
+struct pinctrl_dev;
+struct pinmux_ops;
+struct gpio_chip;
+
+/**
+ * struct pinctrl_pin_desc - boards/machines provide information on their
+ * pins, pads or other muxable units in this struct
+ * @number: unique pin number from the global pin number space
+ * @name: a name for this pin
+ */
+struct pinctrl_pin_desc {
+ unsigned number;
+ const char *name;
+};
+
+/* Convenience macro to define a single named or anonymous pin descriptor */
+#define PINCTRL_PIN(a, b) { .number = a, .name = b }
+#define PINCTRL_PIN_ANON(a) { .number = a }
+
+/**
+ * struct pinctrl_gpio_range - each pin controller can provide subranges of
+ * the GPIO number space to be handled by the controller
+ * @node: list node for internal use
+ * @name: a name for the chip in this range
+ * @id: an ID number for the chip in this range
+ * @base: base offset of the GPIO range
+ * @npins: number of pins in the GPIO range, including the base number
+ * @gc: an optional pointer to a gpio_chip
+ */
+struct pinctrl_gpio_range {
+ struct list_head node;
+ const char *name;
+ unsigned int id;
+ unsigned int base;
+ unsigned int npins;
+ struct gpio_chip *gc;
+};
+
+/**
+ * struct pinctrl_ops - global pin control operations, to be implemented by
+ * pin controller drivers.
+ * @list_groups: list the number of selectable named groups available
+ * in this pinmux driver, the core will begin on 0 and call this
+ * repeatedly as long as it returns >= 0 to enumerate the groups
+ * @get_group_name: return the group name of the pin group
+ * @get_group_pins: return an array of pins corresponding to a certain
+ * group selector @pins, and the size of the array in @num_pins
+ * @pin_dbg_show: optional debugfs display hook that will provide per-device
+ * info for a certain pin in debugfs
+ */
+struct pinctrl_ops {
+ int (*list_groups) (struct pinctrl_dev *pctldev, unsigned selector);
+ const char *(*get_group_name) (struct pinctrl_dev *pctldev,
+ unsigned selector);
+ int (*get_group_pins) (struct pinctrl_dev *pctldev,
+ unsigned selector,
+ const unsigned **pins,
+ unsigned *num_pins);
+ void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s,
+ unsigned offset);
+};
+
+/**
+ * struct pinctrl_desc - pin controller descriptor, register this to pin
+ * control subsystem
+ * @name: name for the pin controller
+ * @pins: an array of pin descriptors describing all the pins handled by
+ * this pin controller
+ * @npins: number of descriptors in the array, usually just ARRAY_SIZE()
+ * of the pins field above
+ * @maxpin: since pin spaces may be sparse, there can he "holes" in the
+ * pin range, this attribute gives the maximum pin number in the
+ * total range. This should not be lower than npins for example,
+ * but may be equal to npins if you have no holes in the pin range.
+ * @pctlops: pin control operation vtable, to support global concepts like
+ * grouping of pins, this is optional.
+ * @pmxops: pinmux operation vtable, if you support pinmuxing in your driver
+ * @owner: module providing the pin controller, used for refcounting
+ */
+struct pinctrl_desc {
+ const char *name;
+ struct pinctrl_pin_desc const *pins;
+ unsigned int npins;
+ unsigned int maxpin;
+ struct pinctrl_ops *pctlops;
+ struct pinmux_ops *pmxops;
+ struct module *owner;
+};
+
+/* External interface to pin controller */
+extern struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
+ struct device *dev, void *driver_data);
+extern void pinctrl_unregister(struct pinctrl_dev *pctldev);
+extern bool pin_is_valid(struct pinctrl_dev *pctldev, int pin);
+extern void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range);
+extern void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range);
+extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev);
+extern void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev);
+#else
+
+
+/* Sufficiently stupid default function when pinctrl is not in use */
+static inline bool pin_is_valid(struct pinctrl_dev *pctldev, int pin)
+{
+ return pin >= 0;
+}
+
+#endif /* !CONFIG_PINCTRL */
+
+#endif /* __LINUX_PINCTRL_PINCTRL_H */
diff --git a/include/linux/pinctrl/pinmux.h b/include/linux/pinctrl/pinmux.h
new file mode 100644
index 000000000000..3c430e797efc
--- /dev/null
+++ b/include/linux/pinctrl/pinmux.h
@@ -0,0 +1,117 @@
+/*
+ * Interface the pinmux subsystem
+ *
+ * Copyright (C) 2011 ST-Ericsson SA
+ * Written on behalf of Linaro for ST-Ericsson
+ * Based on bits of regulator core, gpio core and clk core
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#ifndef __LINUX_PINCTRL_PINMUX_H
+#define __LINUX_PINCTRL_PINMUX_H
+
+#include <linux/list.h>
+#include <linux/seq_file.h>
+#include "pinctrl.h"
+
+/* This struct is private to the core and should be regarded as a cookie */
+struct pinmux;
+
+#ifdef CONFIG_PINMUX
+
+struct pinctrl_dev;
+
+/**
+ * struct pinmux_ops - pinmux operations, to be implemented by pin controller
+ * drivers that support pinmuxing
+ * @request: called by the core to see if a certain pin can be made available
+ * available for muxing. This is called by the core to acquire the pins
+ * before selecting any actual mux setting across a function. The driver
+ * is allowed to answer "no" by returning a negative error code
+ * @free: the reverse function of the request() callback, frees a pin after
+ * being requested
+ * @list_functions: list the number of selectable named functions available
+ * in this pinmux driver, the core will begin on 0 and call this
+ * repeatedly as long as it returns >= 0 to enumerate mux settings
+ * @get_function_name: return the function name of the muxing selector,
+ * called by the core to figure out which mux setting it shall map a
+ * certain device to
+ * @get_function_groups: return an array of groups names (in turn
+ * referencing pins) connected to a certain function selector. The group
+ * name can be used with the generic @pinctrl_ops to retrieve the
+ * actual pins affected. The applicable groups will be returned in
+ * @groups and the number of groups in @num_groups
+ * @enable: enable a certain muxing function with a certain pin group. The
+ * driver does not need to figure out whether enabling this function
+ * conflicts some other use of the pins in that group, such collisions
+ * are handled by the pinmux subsystem. The @func_selector selects a
+ * certain function whereas @group_selector selects a certain set of pins
+ * to be used. On simple controllers the latter argument may be ignored
+ * @disable: disable a certain muxing selector with a certain pin group
+ * @gpio_request_enable: requests and enables GPIO on a certain pin.
+ * Implement this only if you can mux every pin individually as GPIO. The
+ * affected GPIO range is passed along with an offset into that
+ * specific GPIO range - function selectors and pin groups are orthogonal
+ * to this, the core will however make sure the pins do not collide
+ */
+struct pinmux_ops {
+ int (*request) (struct pinctrl_dev *pctldev, unsigned offset);
+ int (*free) (struct pinctrl_dev *pctldev, unsigned offset);
+ int (*list_functions) (struct pinctrl_dev *pctldev, unsigned selector);
+ const char *(*get_function_name) (struct pinctrl_dev *pctldev,
+ unsigned selector);
+ int (*get_function_groups) (struct pinctrl_dev *pctldev,
+ unsigned selector,
+ const char * const **groups,
+ unsigned * const num_groups);
+ int (*enable) (struct pinctrl_dev *pctldev, unsigned func_selector,
+ unsigned group_selector);
+ void (*disable) (struct pinctrl_dev *pctldev, unsigned func_selector,
+ unsigned group_selector);
+ int (*gpio_request_enable) (struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset);
+};
+
+/* External interface to pinmux */
+extern int pinmux_request_gpio(unsigned gpio);
+extern void pinmux_free_gpio(unsigned gpio);
+extern struct pinmux * __must_check pinmux_get(struct device *dev, const char *name);
+extern void pinmux_put(struct pinmux *pmx);
+extern int pinmux_enable(struct pinmux *pmx);
+extern void pinmux_disable(struct pinmux *pmx);
+
+#else /* !CONFIG_PINMUX */
+
+static inline int pinmux_request_gpio(unsigned gpio)
+{
+ return 0;
+}
+
+static inline void pinmux_free_gpio(unsigned gpio)
+{
+}
+
+static inline struct pinmux * __must_check pinmux_get(struct device *dev, const char *name)
+{
+ return NULL;
+}
+
+static inline void pinmux_put(struct pinmux *pmx)
+{
+}
+
+static inline int pinmux_enable(struct pinmux *pmx)
+{
+ return 0;
+}
+
+static inline void pinmux_disable(struct pinmux *pmx)
+{
+}
+
+#endif /* CONFIG_PINMUX */
+
+#endif /* __LINUX_PINCTRL_PINMUX_H */
diff --git a/include/linux/platform_data/dwc3-omap.h b/include/linux/platform_data/dwc3-omap.h
new file mode 100644
index 000000000000..ada401244e0b
--- /dev/null
+++ b/include/linux/platform_data/dwc3-omap.h
@@ -0,0 +1,47 @@
+/**
+ * dwc3-omap.h - OMAP Specific Glue layer, header.
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ * All rights reserved.
+ *
+ * Author: Felipe Balbi <balbi@ti.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * 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.
+ */
+
+enum dwc3_omap_utmi_mode {
+ DWC3_OMAP_UTMI_MODE_UNKNOWN = 0,
+ DWC3_OMAP_UTMI_MODE_HW,
+ DWC3_OMAP_UTMI_MODE_SW,
+};
+
+struct dwc3_omap_data {
+ enum dwc3_omap_utmi_mode utmi_mode;
+};
diff --git a/include/linux/platform_data/exynos4_tmu.h b/include/linux/platform_data/exynos4_tmu.h
new file mode 100644
index 000000000000..39e038cca590
--- /dev/null
+++ b/include/linux/platform_data/exynos4_tmu.h
@@ -0,0 +1,83 @@
+/*
+ * exynos4_tmu.h - Samsung EXYNOS4 TMU (Thermal Management Unit)
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * Donggeun Kim <dg77.kim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _LINUX_EXYNOS4_TMU_H
+#define _LINUX_EXYNOS4_TMU_H
+
+enum calibration_type {
+ TYPE_ONE_POINT_TRIMMING,
+ TYPE_TWO_POINT_TRIMMING,
+ TYPE_NONE,
+};
+
+/**
+ * struct exynos4_tmu_platform_data
+ * @threshold: basic temperature for generating interrupt
+ * 25 <= threshold <= 125 [unit: degree Celsius]
+ * @trigger_levels: array for each interrupt levels
+ * [unit: degree Celsius]
+ * 0: temperature for trigger_level0 interrupt
+ * condition for trigger_level0 interrupt:
+ * current temperature > threshold + trigger_levels[0]
+ * 1: temperature for trigger_level1 interrupt
+ * condition for trigger_level1 interrupt:
+ * current temperature > threshold + trigger_levels[1]
+ * 2: temperature for trigger_level2 interrupt
+ * condition for trigger_level2 interrupt:
+ * current temperature > threshold + trigger_levels[2]
+ * 3: temperature for trigger_level3 interrupt
+ * condition for trigger_level3 interrupt:
+ * current temperature > threshold + trigger_levels[3]
+ * @trigger_level0_en:
+ * 1 = enable trigger_level0 interrupt,
+ * 0 = disable trigger_level0 interrupt
+ * @trigger_level1_en:
+ * 1 = enable trigger_level1 interrupt,
+ * 0 = disable trigger_level1 interrupt
+ * @trigger_level2_en:
+ * 1 = enable trigger_level2 interrupt,
+ * 0 = disable trigger_level2 interrupt
+ * @trigger_level3_en:
+ * 1 = enable trigger_level3 interrupt,
+ * 0 = disable trigger_level3 interrupt
+ * @gain: gain of amplifier in the positive-TC generator block
+ * 0 <= gain <= 15
+ * @reference_voltage: reference voltage of amplifier
+ * in the positive-TC generator block
+ * 0 <= reference_voltage <= 31
+ * @cal_type: calibration type for temperature
+ *
+ * This structure is required for configuration of exynos4_tmu driver.
+ */
+struct exynos4_tmu_platform_data {
+ u8 threshold;
+ u8 trigger_levels[4];
+ bool trigger_level0_en;
+ bool trigger_level1_en;
+ bool trigger_level2_en;
+ bool trigger_level3_en;
+
+ u8 gain;
+ u8 reference_voltage;
+
+ enum calibration_type cal_type;
+};
+#endif /* _LINUX_EXYNOS4_TMU_H */
diff --git a/include/linux/platform_data/mv_usb.h b/include/linux/platform_data/mv_usb.h
new file mode 100644
index 000000000000..e9d9149ddf38
--- /dev/null
+++ b/include/linux/platform_data/mv_usb.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __MV_PLATFORM_USB_H
+#define __MV_PLATFORM_USB_H
+
+enum pxa_ehci_type {
+ EHCI_UNDEFINED = 0,
+ PXA_U2OEHCI, /* pxa 168, 9xx */
+ PXA_SPH, /* pxa 168, 9xx SPH */
+ MMP3_HSIC, /* mmp3 hsic */
+ MMP3_FSIC, /* mmp3 fsic */
+};
+
+enum {
+ MV_USB_MODE_OTG,
+ MV_USB_MODE_HOST,
+};
+
+enum {
+ VBUS_LOW = 0,
+ VBUS_HIGH = 1 << 0,
+};
+
+struct mv_usb_addon_irq {
+ unsigned int irq;
+ int (*poll)(void);
+};
+
+struct mv_usb_platform_data {
+ unsigned int clknum;
+ char **clkname;
+ struct mv_usb_addon_irq *id; /* Only valid for OTG. ID pin change*/
+ struct mv_usb_addon_irq *vbus; /* valid for OTG/UDC. VBUS change*/
+
+ /* only valid for HCD. OTG or Host only*/
+ unsigned int mode;
+
+ int (*phy_init)(unsigned int regbase);
+ void (*phy_deinit)(unsigned int regbase);
+ int (*set_vbus)(unsigned int vbus);
+};
+
+#endif
diff --git a/include/linux/platform_data/ntc_thermistor.h b/include/linux/platform_data/ntc_thermistor.h
index abd286215279..88734e871e3a 100644
--- a/include/linux/platform_data/ntc_thermistor.h
+++ b/include/linux/platform_data/ntc_thermistor.h
@@ -36,7 +36,7 @@ struct ntc_thermistor_platform_data {
* read_uV()
*
* How to setup pullup_ohm, pulldown_ohm, and connect is
- * described at Documentation/hwmon/ntc
+ * described at Documentation/hwmon/ntc_thermistor
*
* pullup/down_ohm: 0 for infinite / not-connected
*/
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index 27bb05aae70d..651a066686ac 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -49,10 +49,54 @@ extern struct resource *platform_get_resource_byname(struct platform_device *, u
extern int platform_get_irq_byname(struct platform_device *, const char *);
extern int platform_add_devices(struct platform_device **, int);
-extern struct platform_device *platform_device_register_resndata(
+struct platform_device_info {
+ struct device *parent;
+
+ const char *name;
+ int id;
+
+ const struct resource *res;
+ unsigned int num_res;
+
+ const void *data;
+ size_t size_data;
+ u64 dma_mask;
+};
+extern struct platform_device *platform_device_register_full(
+ struct platform_device_info *pdevinfo);
+
+/**
+ * platform_device_register_resndata - add a platform-level device with
+ * resources and platform-specific data
+ *
+ * @parent: parent device for the device we're adding
+ * @name: base name of the device we're adding
+ * @id: instance id
+ * @res: set of resources that needs to be allocated for the device
+ * @num: number of resources
+ * @data: platform specific data for this platform device
+ * @size: size of platform specific data
+ *
+ * Returns &struct platform_device pointer on success, or ERR_PTR() on error.
+ */
+static inline struct platform_device *platform_device_register_resndata(
struct device *parent, const char *name, int id,
const struct resource *res, unsigned int num,
- const void *data, size_t size);
+ const void *data, size_t size) {
+
+ struct platform_device_info pdevinfo = {
+ .parent = parent,
+ .name = name,
+ .id = id,
+ .res = res,
+ .num_res = num,
+ .data = data,
+ .size_data = size,
+ .dma_mask = 0,
+ };
+
+ return platform_device_register_full(&pdevinfo);
+}
/**
* platform_device_register_simple - add a platform-level device and its resources
diff --git a/include/linux/pm.h b/include/linux/pm.h
index f7c84c9abd30..f15acb646813 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -326,6 +326,7 @@ extern struct dev_pm_ops generic_subsys_pm_ops;
* requested by a driver.
*/
+#define PM_EVENT_INVALID (-1)
#define PM_EVENT_ON 0x0000
#define PM_EVENT_FREEZE 0x0001
#define PM_EVENT_SUSPEND 0x0002
@@ -346,6 +347,7 @@ extern struct dev_pm_ops generic_subsys_pm_ops;
#define PM_EVENT_AUTO_SUSPEND (PM_EVENT_AUTO | PM_EVENT_SUSPEND)
#define PM_EVENT_AUTO_RESUME (PM_EVENT_AUTO | PM_EVENT_RESUME)
+#define PMSG_INVALID ((struct pm_message){ .event = PM_EVENT_INVALID, })
#define PMSG_ON ((struct pm_message){ .event = PM_EVENT_ON, })
#define PMSG_FREEZE ((struct pm_message){ .event = PM_EVENT_FREEZE, })
#define PMSG_QUIESCE ((struct pm_message){ .event = PM_EVENT_QUIESCE, })
@@ -366,6 +368,8 @@ extern struct dev_pm_ops generic_subsys_pm_ops;
#define PMSG_AUTO_RESUME ((struct pm_message) \
{ .event = PM_EVENT_AUTO_RESUME, })
+#define PMSG_IS_AUTO(msg) (((msg).event & PM_EVENT_AUTO) != 0)
+
/**
* Device run-time power management status.
*
@@ -421,6 +425,22 @@ enum rpm_request {
struct wakeup_source;
+struct pm_domain_data {
+ struct list_head list_node;
+ struct device *dev;
+};
+
+struct pm_subsys_data {
+ spinlock_t lock;
+ unsigned int refcount;
+#ifdef CONFIG_PM_CLK
+ struct list_head clock_list;
+#endif
+#ifdef CONFIG_PM_GENERIC_DOMAINS
+ struct pm_domain_data *domain_data;
+#endif
+};
+
struct dev_pm_info {
pm_message_t power_state;
unsigned int can_wakeup:1;
@@ -432,6 +452,7 @@ struct dev_pm_info {
struct list_head entry;
struct completion completion;
struct wakeup_source *wakeup;
+ bool wakeup_path:1;
#else
unsigned int should_wakeup:1;
#endif
@@ -462,10 +483,13 @@ struct dev_pm_info {
unsigned long suspended_jiffies;
unsigned long accounting_timestamp;
#endif
- void *subsys_data; /* Owned by the subsystem. */
+ struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */
+ struct pm_qos_constraints *constraints;
};
extern void update_pm_runtime_accounting(struct device *dev);
+extern int dev_pm_get_subsys_data(struct device *dev);
+extern int dev_pm_put_subsys_data(struct device *dev);
/*
* Power domains provide callbacks that are executed during system suspend,
diff --git a/include/linux/pm_clock.h b/include/linux/pm_clock.h
new file mode 100644
index 000000000000..8348866e7b05
--- /dev/null
+++ b/include/linux/pm_clock.h
@@ -0,0 +1,71 @@
+/*
+ * pm_clock.h - Definitions and headers related to device clocks.
+ *
+ * Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef _LINUX_PM_CLOCK_H
+#define _LINUX_PM_CLOCK_H
+
+#include <linux/device.h>
+#include <linux/notifier.h>
+
+struct pm_clk_notifier_block {
+ struct notifier_block nb;
+ struct dev_pm_domain *pm_domain;
+ char *con_ids[];
+};
+
+#ifdef CONFIG_PM_CLK
+static inline bool pm_clk_no_clocks(struct device *dev)
+{
+ return dev && dev->power.subsys_data
+ && list_empty(&dev->power.subsys_data->clock_list);
+}
+
+extern void pm_clk_init(struct device *dev);
+extern int pm_clk_create(struct device *dev);
+extern void pm_clk_destroy(struct device *dev);
+extern int pm_clk_add(struct device *dev, const char *con_id);
+extern void pm_clk_remove(struct device *dev, const char *con_id);
+extern int pm_clk_suspend(struct device *dev);
+extern int pm_clk_resume(struct device *dev);
+#else
+static inline bool pm_clk_no_clocks(struct device *dev)
+{
+ return true;
+}
+static inline void pm_clk_init(struct device *dev)
+{
+}
+static inline int pm_clk_create(struct device *dev)
+{
+ return -EINVAL;
+}
+static inline void pm_clk_destroy(struct device *dev)
+{
+}
+static inline int pm_clk_add(struct device *dev, const char *con_id)
+{
+ return -EINVAL;
+}
+static inline void pm_clk_remove(struct device *dev, const char *con_id)
+{
+}
+#define pm_clk_suspend NULL
+#define pm_clk_resume NULL
+#endif
+
+#ifdef CONFIG_HAVE_CLK
+extern void pm_clk_add_notifier(struct bus_type *bus,
+ struct pm_clk_notifier_block *clknb);
+#else
+static inline void pm_clk_add_notifier(struct bus_type *bus,
+ struct pm_clk_notifier_block *clknb)
+{
+}
+#endif
+
+#endif
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index f9ec1736a116..65633e5a2bc0 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -13,6 +13,7 @@
enum gpd_status {
GPD_STATE_ACTIVE = 0, /* PM domain is active */
+ GPD_STATE_WAIT_MASTER, /* PM domain's master is being waited for */
GPD_STATE_BUSY, /* Something is happening to the PM domain */
GPD_STATE_REPEAT, /* Power off in progress, to be repeated */
GPD_STATE_POWER_OFF, /* PM domain is off */
@@ -25,15 +26,14 @@ struct dev_power_governor {
struct generic_pm_domain {
struct dev_pm_domain domain; /* PM domain operations */
struct list_head gpd_list_node; /* Node in the global PM domains list */
- struct list_head sd_node; /* Node in the parent's subdomain list */
- struct generic_pm_domain *parent; /* Parent PM domain */
- struct list_head sd_list; /* List of dubdomains */
+ struct list_head master_links; /* Links with PM domain as a master */
+ struct list_head slave_links; /* Links with PM domain as a slave */
struct list_head dev_list; /* List of devices */
struct mutex lock;
struct dev_power_governor *gov;
struct work_struct power_off_work;
unsigned int in_progress; /* Number of devices being suspended now */
- unsigned int sd_count; /* Number of subdomains with power "on" */
+ atomic_t sd_count; /* Number of subdomains with power "on" */
enum gpd_status status; /* Current state of the domain */
wait_queue_head_t status_wait_queue;
struct task_struct *poweroff_task; /* Powering off task */
@@ -42,6 +42,7 @@ struct generic_pm_domain {
unsigned int suspended_count; /* System suspend device counter */
unsigned int prepared_count; /* Suspend counter of prepared devices */
bool suspend_power_off; /* Power status before system suspend */
+ bool dev_irq_safe; /* Device callbacks are IRQ-safe */
int (*power_off)(struct generic_pm_domain *domain);
int (*power_on)(struct generic_pm_domain *domain);
int (*start_device)(struct device *dev);
@@ -54,12 +55,23 @@ static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
return container_of(pd, struct generic_pm_domain, domain);
}
-struct dev_list_entry {
- struct list_head node;
- struct device *dev;
+struct gpd_link {
+ struct generic_pm_domain *master;
+ struct list_head master_node;
+ struct generic_pm_domain *slave;
+ struct list_head slave_node;
+};
+
+struct generic_pm_domain_data {
+ struct pm_domain_data base;
bool need_restore;
};
+static inline struct generic_pm_domain_data *to_gpd_data(struct pm_domain_data *pdd)
+{
+ return container_of(pdd, struct generic_pm_domain_data, base);
+}
+
#ifdef CONFIG_PM_GENERIC_DOMAINS
extern int pm_genpd_add_device(struct generic_pm_domain *genpd,
struct device *dev);
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
new file mode 100644
index 000000000000..83b0ea302a80
--- /dev/null
+++ b/include/linux/pm_qos.h
@@ -0,0 +1,155 @@
+#ifndef _LINUX_PM_QOS_H
+#define _LINUX_PM_QOS_H
+/* interface for the pm_qos_power infrastructure of the linux kernel.
+ *
+ * Mark Gross <mgross@linux.intel.com>
+ */
+#include <linux/plist.h>
+#include <linux/notifier.h>
+#include <linux/miscdevice.h>
+#include <linux/device.h>
+
+#define PM_QOS_RESERVED 0
+#define PM_QOS_CPU_DMA_LATENCY 1
+#define PM_QOS_NETWORK_LATENCY 2
+#define PM_QOS_NETWORK_THROUGHPUT 3
+
+#define PM_QOS_NUM_CLASSES 4
+#define PM_QOS_DEFAULT_VALUE -1
+
+#define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC)
+#define PM_QOS_NETWORK_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC)
+#define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE 0
+#define PM_QOS_DEV_LAT_DEFAULT_VALUE 0
+
+struct pm_qos_request {
+ struct plist_node node;
+ int pm_qos_class;
+};
+
+struct dev_pm_qos_request {
+ struct plist_node node;
+ struct device *dev;
+};
+
+enum pm_qos_type {
+ PM_QOS_UNITIALIZED,
+ PM_QOS_MAX, /* return the largest value */
+ PM_QOS_MIN /* return the smallest value */
+};
+
+/*
+ * Note: The lockless read path depends on the CPU accessing
+ * target_value atomically. Atomic access is only guaranteed on all CPU
+ * types linux supports for 32 bit quantites
+ */
+struct pm_qos_constraints {
+ struct plist_head list;
+ s32 target_value; /* Do not change to 64 bit */
+ s32 default_value;
+ enum pm_qos_type type;
+ struct blocking_notifier_head *notifiers;
+};
+
+/* Action requested to pm_qos_update_target */
+enum pm_qos_req_action {
+ PM_QOS_ADD_REQ, /* Add a new request */
+ PM_QOS_UPDATE_REQ, /* Update an existing request */
+ PM_QOS_REMOVE_REQ /* Remove an existing request */
+};
+
+static inline int dev_pm_qos_request_active(struct dev_pm_qos_request *req)
+{
+ return req->dev != 0;
+}
+
+#ifdef CONFIG_PM
+int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node,
+ enum pm_qos_req_action action, int value);
+void pm_qos_add_request(struct pm_qos_request *req, int pm_qos_class,
+ s32 value);
+void pm_qos_update_request(struct pm_qos_request *req,
+ s32 new_value);
+void pm_qos_remove_request(struct pm_qos_request *req);
+
+int pm_qos_request(int pm_qos_class);
+int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier);
+int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier);
+int pm_qos_request_active(struct pm_qos_request *req);
+s32 pm_qos_read_value(struct pm_qos_constraints *c);
+
+s32 dev_pm_qos_read_value(struct device *dev);
+int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
+ s32 value);
+int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value);
+int dev_pm_qos_remove_request(struct dev_pm_qos_request *req);
+int dev_pm_qos_add_notifier(struct device *dev,
+ struct notifier_block *notifier);
+int dev_pm_qos_remove_notifier(struct device *dev,
+ struct notifier_block *notifier);
+int dev_pm_qos_add_global_notifier(struct notifier_block *notifier);
+int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier);
+void dev_pm_qos_constraints_init(struct device *dev);
+void dev_pm_qos_constraints_destroy(struct device *dev);
+#else
+static inline int pm_qos_update_target(struct pm_qos_constraints *c,
+ struct plist_node *node,
+ enum pm_qos_req_action action,
+ int value)
+ { return 0; }
+static inline void pm_qos_add_request(struct pm_qos_request *req,
+ int pm_qos_class, s32 value)
+ { return; }
+static inline void pm_qos_update_request(struct pm_qos_request *req,
+ s32 new_value)
+ { return; }
+static inline void pm_qos_remove_request(struct pm_qos_request *req)
+ { return; }
+
+static inline int pm_qos_request(int pm_qos_class)
+ { return 0; }
+static inline int pm_qos_add_notifier(int pm_qos_class,
+ struct notifier_block *notifier)
+ { return 0; }
+static inline int pm_qos_remove_notifier(int pm_qos_class,
+ struct notifier_block *notifier)
+ { return 0; }
+static inline int pm_qos_request_active(struct pm_qos_request *req)
+ { return 0; }
+static inline s32 pm_qos_read_value(struct pm_qos_constraints *c)
+ { return 0; }
+
+static inline s32 dev_pm_qos_read_value(struct device *dev)
+ { return 0; }
+static inline int dev_pm_qos_add_request(struct device *dev,
+ struct dev_pm_qos_request *req,
+ s32 value)
+ { return 0; }
+static inline int dev_pm_qos_update_request(struct dev_pm_qos_request *req,
+ s32 new_value)
+ { return 0; }
+static inline int dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
+ { return 0; }
+static inline int dev_pm_qos_add_notifier(struct device *dev,
+ struct notifier_block *notifier)
+ { return 0; }
+static inline int dev_pm_qos_remove_notifier(struct device *dev,
+ struct notifier_block *notifier)
+ { return 0; }
+static inline int dev_pm_qos_add_global_notifier(
+ struct notifier_block *notifier)
+ { return 0; }
+static inline int dev_pm_qos_remove_global_notifier(
+ struct notifier_block *notifier)
+ { return 0; }
+static inline void dev_pm_qos_constraints_init(struct device *dev)
+{
+ dev->power.power_state = PMSG_ON;
+}
+static inline void dev_pm_qos_constraints_destroy(struct device *dev)
+{
+ dev->power.power_state = PMSG_INVALID;
+}
+#endif
+
+#endif
diff --git a/include/linux/pm_qos_params.h b/include/linux/pm_qos_params.h
deleted file mode 100644
index a7d87f911cab..000000000000
--- a/include/linux/pm_qos_params.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef _LINUX_PM_QOS_PARAMS_H
-#define _LINUX_PM_QOS_PARAMS_H
-/* interface for the pm_qos_power infrastructure of the linux kernel.
- *
- * Mark Gross <mgross@linux.intel.com>
- */
-#include <linux/plist.h>
-#include <linux/notifier.h>
-#include <linux/miscdevice.h>
-
-#define PM_QOS_RESERVED 0
-#define PM_QOS_CPU_DMA_LATENCY 1
-#define PM_QOS_NETWORK_LATENCY 2
-#define PM_QOS_NETWORK_THROUGHPUT 3
-
-#define PM_QOS_NUM_CLASSES 4
-#define PM_QOS_DEFAULT_VALUE -1
-
-#define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC)
-#define PM_QOS_NETWORK_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC)
-#define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE 0
-
-struct pm_qos_request_list {
- struct plist_node list;
- int pm_qos_class;
-};
-
-void pm_qos_add_request(struct pm_qos_request_list *l, int pm_qos_class, s32 value);
-void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
- s32 new_value);
-void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req);
-
-int pm_qos_request(int pm_qos_class);
-int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier);
-int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier);
-int pm_qos_request_active(struct pm_qos_request_list *req);
-
-#endif
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index daac05d751b2..70b284024d9e 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -251,46 +251,4 @@ static inline void pm_runtime_dont_use_autosuspend(struct device *dev)
__pm_runtime_use_autosuspend(dev, false);
}
-struct pm_clk_notifier_block {
- struct notifier_block nb;
- struct dev_pm_domain *pm_domain;
- char *con_ids[];
-};
-
-#ifdef CONFIG_PM_CLK
-extern int pm_clk_init(struct device *dev);
-extern void pm_clk_destroy(struct device *dev);
-extern int pm_clk_add(struct device *dev, const char *con_id);
-extern void pm_clk_remove(struct device *dev, const char *con_id);
-extern int pm_clk_suspend(struct device *dev);
-extern int pm_clk_resume(struct device *dev);
-#else
-static inline int pm_clk_init(struct device *dev)
-{
- return -EINVAL;
-}
-static inline void pm_clk_destroy(struct device *dev)
-{
-}
-static inline int pm_clk_add(struct device *dev, const char *con_id)
-{
- return -EINVAL;
-}
-static inline void pm_clk_remove(struct device *dev, const char *con_id)
-{
-}
-#define pm_clk_suspend NULL
-#define pm_clk_resume NULL
-#endif
-
-#ifdef CONFIG_HAVE_CLK
-extern void pm_clk_add_notifier(struct bus_type *bus,
- struct pm_clk_notifier_block *clknb);
-#else
-static inline void pm_clk_add_notifier(struct bus_type *bus,
- struct pm_clk_notifier_block *clknb)
-{
-}
-#endif
-
#endif
diff --git a/include/linux/ptp_classify.h b/include/linux/ptp_classify.h
index e07e2742a865..1dc420ba213a 100644
--- a/include/linux/ptp_classify.h
+++ b/include/linux/ptp_classify.h
@@ -51,6 +51,7 @@
#define PTP_CLASS_V2_VLAN (PTP_CLASS_V2 | PTP_CLASS_VLAN)
#define PTP_EV_PORT 319
+#define PTP_GEN_BIT 0x08 /* indicates general message, if set in message type */
#define OFF_ETYPE 12
#define OFF_IHL 14
@@ -116,14 +117,20 @@ static inline int ptp_filter_init(struct sock_filter *f, int len)
{OP_OR, 0, 0, PTP_CLASS_IPV6 }, /* */ \
{OP_RETA, 0, 0, 0 }, /* */ \
/*L3x*/ {OP_RETK, 0, 0, PTP_CLASS_NONE }, /* */ \
-/*L40*/ {OP_JEQ, 0, 6, ETH_P_8021Q }, /* f goto L50 */ \
+/*L40*/ {OP_JEQ, 0, 9, ETH_P_8021Q }, /* f goto L50 */ \
{OP_LDH, 0, 0, OFF_ETYPE + 4 }, /* */ \
- {OP_JEQ, 0, 9, ETH_P_1588 }, /* f goto L60 */ \
+ {OP_JEQ, 0, 15, ETH_P_1588 }, /* f goto L60 */ \
+ {OP_LDB, 0, 0, ETH_HLEN + VLAN_HLEN }, /* */ \
+ {OP_AND, 0, 0, PTP_GEN_BIT }, /* */ \
+ {OP_JEQ, 0, 12, 0 }, /* f goto L6x */ \
{OP_LDH, 0, 0, ETH_HLEN + VLAN_HLEN }, /* */ \
{OP_AND, 0, 0, PTP_CLASS_VMASK }, /* */ \
{OP_OR, 0, 0, PTP_CLASS_VLAN }, /* */ \
{OP_RETA, 0, 0, 0 }, /* */ \
-/*L50*/ {OP_JEQ, 0, 4, ETH_P_1588 }, /* f goto L61 */ \
+/*L50*/ {OP_JEQ, 0, 7, ETH_P_1588 }, /* f goto L61 */ \
+ {OP_LDB, 0, 0, ETH_HLEN }, /* */ \
+ {OP_AND, 0, 0, PTP_GEN_BIT }, /* */ \
+ {OP_JEQ, 0, 4, 0 }, /* f goto L6x */ \
{OP_LDH, 0, 0, ETH_HLEN }, /* */ \
{OP_AND, 0, 0, PTP_CLASS_VMASK }, /* */ \
{OP_OR, 0, 0, PTP_CLASS_L2 }, /* */ \
diff --git a/include/linux/pwm_backlight.h b/include/linux/pwm_backlight.h
index 5e3e25a3c9c3..63d2df43e61a 100644
--- a/include/linux/pwm_backlight.h
+++ b/include/linux/pwm_backlight.h
@@ -14,6 +14,7 @@ struct platform_pwm_backlight_data {
unsigned int pwm_period_ns;
int (*init)(struct device *dev);
int (*notify)(struct device *dev, int brightness);
+ void (*notify_after)(struct device *dev, int brightness);
void (*exit)(struct device *dev);
int (*check_fb)(struct device *dev, struct fb_info *info);
};
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 60a65cd7e1a0..3daac2d8dc37 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -20,9 +20,77 @@
struct i2c_client;
struct spi_device;
+/* An enum of all the supported cache types */
+enum regcache_type {
+ REGCACHE_NONE,
+ REGCACHE_INDEXED,
+ REGCACHE_RBTREE,
+ REGCACHE_LZO
+};
+
+/**
+ * Default value for a register. We use an array of structs rather
+ * than a simple array as many modern devices have very sparse
+ * register maps.
+ *
+ * @reg: Register address.
+ * @def: Register default value.
+ */
+struct reg_default {
+ unsigned int reg;
+ unsigned int def;
+};
+
+/**
+ * Configuration for the register map of a device.
+ *
+ * @reg_bits: Number of bits in a register address, mandatory.
+ * @val_bits: Number of bits in a register value, mandatory.
+ *
+ * @writeable_reg: Optional callback returning true if the register
+ * can be written to.
+ * @readable_reg: Optional callback returning true if the register
+ * can be read from.
+ * @volatile_reg: Optional callback returning true if the register
+ * value can't be cached.
+ * @precious_reg: Optional callback returning true if the rgister
+ * should not be read outside of a call from the driver
+ * (eg, a clear on read interrupt status register).
+ *
+ * @max_register: Optional, specifies the maximum valid register index.
+ * @reg_defaults: Power on reset values for registers (for use with
+ * register cache support).
+ * @num_reg_defaults: Number of elements in reg_defaults.
+ *
+ * @read_flag_mask: Mask to be set in the top byte of the register when doing
+ * a read.
+ * @write_flag_mask: Mask to be set in the top byte of the register when doing
+ * a write. If both read_flag_mask and write_flag_mask are
+ * empty the regmap_bus default masks are used.
+ *
+ * @cache_type: The actual cache type.
+ * @reg_defaults_raw: Power on reset values for registers (for use with
+ * register cache support).
+ * @num_reg_defaults_raw: Number of elements in reg_defaults_raw.
+ */
struct regmap_config {
int reg_bits;
int val_bits;
+
+ bool (*writeable_reg)(struct device *dev, unsigned int reg);
+ bool (*readable_reg)(struct device *dev, unsigned int reg);
+ bool (*volatile_reg)(struct device *dev, unsigned int reg);
+ bool (*precious_reg)(struct device *dev, unsigned int reg);
+
+ unsigned int max_register;
+ struct reg_default *reg_defaults;
+ unsigned int num_reg_defaults;
+ enum regcache_type cache_type;
+ const void *reg_defaults_raw;
+ unsigned int num_reg_defaults_raw;
+
+ u8 read_flag_mask;
+ u8 write_flag_mask;
};
typedef int (*regmap_hw_write)(struct device *dev, const void *data,
@@ -37,25 +105,18 @@ typedef int (*regmap_hw_read)(struct device *dev,
/**
* Description of a hardware bus for the register map infrastructure.
*
- * @list: Internal use.
- * @type: Bus type, used to identify bus to be used for a device.
* @write: Write operation.
* @gather_write: Write operation with split register/value, return -ENOTSUPP
* if not implemented on a given device.
* @read: Read operation. Data is returned in the buffer used to transmit
* data.
- * @owner: Module with the bus implementation, used to pin the implementation
- * in memory.
* @read_flag_mask: Mask to be set in the top byte of the register when doing
* a read.
*/
struct regmap_bus {
- struct list_head list;
- struct bus_type *type;
regmap_hw_write write;
regmap_hw_gather_write gather_write;
regmap_hw_read read;
- struct module *owner;
u8 read_flag_mask;
};
@@ -79,4 +140,8 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
int regmap_update_bits(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val);
+int regcache_sync(struct regmap *map);
+void regcache_cache_only(struct regmap *map, bool enable);
+void regcache_cache_bypass(struct regmap *map, bool enable);
+
#endif
diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
index 26f6ea4444e3..b47771aa5718 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -123,7 +123,7 @@ struct regulator_bulk_data {
const char *supply;
struct regulator *consumer;
- /* Internal use */
+ /* private: Internal use */
int ret;
};
diff --git a/include/linux/rfkill-gpio.h b/include/linux/rfkill-gpio.h
index a175d0598033..4d09f6eab359 100644
--- a/include/linux/rfkill-gpio.h
+++ b/include/linux/rfkill-gpio.h
@@ -30,6 +30,8 @@
* @reset_gpio: GPIO which is used for reseting rfkill switch
* @shutdown_gpio: GPIO which is used for shutdown of rfkill switch
* @power_clk_name: [optional] name of clk to turn off while blocked
+ * @gpio_runtime_close: clean up platform specific gpio configuration
+ * @gpio_runtime_setup: set up platform specific gpio configuration
*/
struct rfkill_gpio_platform_data {
@@ -38,6 +40,8 @@ struct rfkill_gpio_platform_data {
int shutdown_gpio;
const char *power_clk_name;
enum rfkill_type type;
+ void (*gpio_runtime_close)(struct platform_device *);
+ int (*gpio_runtime_setup)(struct platform_device *);
};
#endif /* __RFKILL_GPIO_H */
diff --git a/include/linux/rio_regs.h b/include/linux/rio_regs.h
index 9026b30238f3..218168a2b5e9 100644
--- a/include/linux/rio_regs.h
+++ b/include/linux/rio_regs.h
@@ -36,12 +36,12 @@
#define RIO_PEF_PROCESSOR 0x20000000 /* [I] Processor */
#define RIO_PEF_SWITCH 0x10000000 /* [I] Switch */
#define RIO_PEF_MULTIPORT 0x08000000 /* [VI, 2.1] Multiport */
-#define RIO_PEF_INB_MBOX 0x00f00000 /* [II] Mailboxes */
-#define RIO_PEF_INB_MBOX0 0x00800000 /* [II] Mailbox 0 */
-#define RIO_PEF_INB_MBOX1 0x00400000 /* [II] Mailbox 1 */
-#define RIO_PEF_INB_MBOX2 0x00200000 /* [II] Mailbox 2 */
-#define RIO_PEF_INB_MBOX3 0x00100000 /* [II] Mailbox 3 */
-#define RIO_PEF_INB_DOORBELL 0x00080000 /* [II] Doorbells */
+#define RIO_PEF_INB_MBOX 0x00f00000 /* [II, <= 1.2] Mailboxes */
+#define RIO_PEF_INB_MBOX0 0x00800000 /* [II, <= 1.2] Mailbox 0 */
+#define RIO_PEF_INB_MBOX1 0x00400000 /* [II, <= 1.2] Mailbox 1 */
+#define RIO_PEF_INB_MBOX2 0x00200000 /* [II, <= 1.2] Mailbox 2 */
+#define RIO_PEF_INB_MBOX3 0x00100000 /* [II, <= 1.2] Mailbox 3 */
+#define RIO_PEF_INB_DOORBELL 0x00080000 /* [II, <= 1.2] Doorbells */
#define RIO_PEF_EXT_RT 0x00000200 /* [III, 1.3] Extended route table support */
#define RIO_PEF_STD_RT 0x00000100 /* [III, 1.3] Standard route table support */
#define RIO_PEF_CTLS 0x00000010 /* [III] CTLS */
@@ -102,7 +102,7 @@
#define RIO_SWITCH_RT_LIMIT 0x34 /* [III, 1.3] Switch Route Table Destination ID Limit CAR */
#define RIO_RT_MAX_DESTID 0x0000ffff
-#define RIO_MBOX_CSR 0x40 /* [II] Mailbox CSR */
+#define RIO_MBOX_CSR 0x40 /* [II, <= 1.2] Mailbox CSR */
#define RIO_MBOX0_AVAIL 0x80000000 /* [II] Mbox 0 avail */
#define RIO_MBOX0_FULL 0x40000000 /* [II] Mbox 0 full */
#define RIO_MBOX0_EMPTY 0x20000000 /* [II] Mbox 0 empty */
@@ -128,8 +128,8 @@
#define RIO_MBOX3_FAIL 0x00000008 /* [II] Mbox 3 fail */
#define RIO_MBOX3_ERROR 0x00000004 /* [II] Mbox 3 error */
-#define RIO_WRITE_PORT_CSR 0x44 /* [I] Write Port CSR */
-#define RIO_DOORBELL_CSR 0x44 /* [II] Doorbell CSR */
+#define RIO_WRITE_PORT_CSR 0x44 /* [I, <= 1.2] Write Port CSR */
+#define RIO_DOORBELL_CSR 0x44 /* [II, <= 1.2] Doorbell CSR */
#define RIO_DOORBELL_AVAIL 0x80000000 /* [II] Doorbell avail */
#define RIO_DOORBELL_FULL 0x40000000 /* [II] Doorbell full */
#define RIO_DOORBELL_EMPTY 0x20000000 /* [II] Doorbell empty */
diff --git a/include/linux/rose.h b/include/linux/rose.h
index c7b4b184c82e..1fcfe95893b8 100644
--- a/include/linux/rose.h
+++ b/include/linux/rose.h
@@ -7,6 +7,9 @@
#ifndef ROSE_KERNEL_H
#define ROSE_KERNEL_H
+#include <linux/socket.h>
+#include <linux/ax25.h>
+
#define ROSE_MTU 251
#define ROSE_MAX_DIGIS 6
@@ -44,7 +47,7 @@ typedef struct {
} rose_address;
struct sockaddr_rose {
- sa_family_t srose_family;
+ __kernel_sa_family_t srose_family;
rose_address srose_addr;
ax25_address srose_call;
int srose_ndigis;
@@ -52,7 +55,7 @@ struct sockaddr_rose {
};
struct full_sockaddr_rose {
- sa_family_t srose_family;
+ __kernel_sa_family_t srose_family;
rose_address srose_addr;
ax25_address srose_call;
unsigned int srose_ndigis;
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 4ac2c0578e0f..600eb0a6f89a 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1956,7 +1956,6 @@ static inline void disable_sched_clock_irqtime(void) {}
extern unsigned long long
task_sched_runtime(struct task_struct *task);
-extern unsigned long long thread_group_sched_runtime(struct task_struct *task);
/* sched_exec is called by processes performing an exec */
#ifdef CONFIG_SMP
@@ -2166,7 +2165,8 @@ extern int force_sigsegv(int, struct task_struct *);
extern int force_sig_info(int, struct siginfo *, struct task_struct *);
extern int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp);
extern int kill_pid_info(int sig, struct siginfo *info, struct pid *pid);
-extern int kill_pid_info_as_uid(int, struct siginfo *, struct pid *, uid_t, uid_t, u32);
+extern int kill_pid_info_as_cred(int, struct siginfo *, struct pid *,
+ const struct cred *, u32);
extern int kill_pgrp(struct pid *pid, int sig, int priv);
extern int kill_pid(struct pid *pid, int sig, int priv);
extern int kill_proc_info(int, struct siginfo *, pid_t);
diff --git a/include/linux/security.h b/include/linux/security.h
index ebd2a53a3d07..19d8e04e1688 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -36,6 +36,7 @@
#include <linux/key.h>
#include <linux/xfrm.h>
#include <linux/slab.h>
+#include <linux/xattr.h>
#include <net/flow.h>
/* Maximum number of letters for an LSM name string */
@@ -147,6 +148,10 @@ extern int mmap_min_addr_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos);
#endif
+/* security_inode_init_security callback function to write xattrs */
+typedef int (*initxattrs) (struct inode *inode,
+ const struct xattr *xattr_array, void *fs_data);
+
#ifdef CONFIG_SECURITY
struct security_mnt_opts {
@@ -1367,7 +1372,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @inode_getsecctx:
* Returns a string containing all relavent security context information
*
- * @inode we wish to set the security context of.
+ * @inode we wish to get the security context of.
* @ctx is a pointer in which to place the allocated security context.
* @ctxlen points to the place to put the length of @ctx.
* This is the main security structure.
@@ -1655,6 +1660,8 @@ struct security_operations {
extern int security_init(void);
extern int security_module_enable(struct security_operations *ops);
extern int register_security(struct security_operations *ops);
+extern void __init security_fixup_ops(struct security_operations *ops);
+
/* Security operations */
int security_ptrace_access_check(struct task_struct *child, unsigned int mode);
@@ -1704,8 +1711,11 @@ int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts);
int security_inode_alloc(struct inode *inode);
void security_inode_free(struct inode *inode);
int security_inode_init_security(struct inode *inode, struct inode *dir,
- const struct qstr *qstr, char **name,
- void **value, size_t *len);
+ const struct qstr *qstr,
+ initxattrs initxattrs, void *fs_data);
+int security_old_inode_init_security(struct inode *inode, struct inode *dir,
+ const struct qstr *qstr, char **name,
+ void **value, size_t *len);
int security_inode_create(struct inode *dir, struct dentry *dentry, int mode);
int security_inode_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *new_dentry);
@@ -2034,11 +2044,19 @@ static inline void security_inode_free(struct inode *inode)
static inline int security_inode_init_security(struct inode *inode,
struct inode *dir,
const struct qstr *qstr,
- char **name,
- void **value,
- size_t *len)
+ initxattrs initxattrs,
+ void *fs_data)
{
- return -EOPNOTSUPP;
+ return 0;
+}
+
+static inline int security_old_inode_init_security(struct inode *inode,
+ struct inode *dir,
+ const struct qstr *qstr,
+ char **name, void **value,
+ size_t *len)
+{
+ return 0;
}
static inline int security_inode_create(struct inode *dir,
diff --git a/arch/sh/include/asm/sh_eth.h b/include/linux/sh_eth.h
index 0f325da0f923..2076acf8294d 100644
--- a/arch/sh/include/asm/sh_eth.h
+++ b/include/linux/sh_eth.h
@@ -15,7 +15,7 @@ struct sh_eth_plat_data {
int edmac_endian;
int register_type;
phy_interface_t phy_interface;
- void (*set_mdio_gate)(unsigned long addr);
+ void (*set_mdio_gate)(void *addr);
unsigned char mac_addr[6];
unsigned no_ether_link:1;
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 7b996ed86d5b..6a6b352326d7 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -29,6 +29,7 @@
#include <linux/rcupdate.h>
#include <linux/dmaengine.h>
#include <linux/hrtimer.h>
+#include <linux/dma-mapping.h>
/* Don't change this without changing skb_csum_unnecessary! */
#define CHECKSUM_NONE 0
@@ -45,6 +46,11 @@
#define SKB_MAX_HEAD(X) (SKB_MAX_ORDER((X), 0))
#define SKB_MAX_ALLOC (SKB_MAX_ORDER(0, 2))
+/* return minimum truesize of one skb containing X bytes of data */
+#define SKB_TRUESIZE(X) ((X) + \
+ SKB_DATA_ALIGN(sizeof(struct sk_buff)) + \
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
+
/* A. Checksumming of received packets by device.
*
* NONE: device failed to checksum this packet.
@@ -134,7 +140,9 @@ struct sk_buff;
typedef struct skb_frag_struct skb_frag_t;
struct skb_frag_struct {
- struct page *page;
+ struct {
+ struct page *p;
+ } page;
#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536)
__u32 page_offset;
__u32 size;
@@ -144,6 +152,26 @@ struct skb_frag_struct {
#endif
};
+static inline unsigned int skb_frag_size(const skb_frag_t *frag)
+{
+ return frag->size;
+}
+
+static inline void skb_frag_size_set(skb_frag_t *frag, unsigned int size)
+{
+ frag->size = size;
+}
+
+static inline void skb_frag_size_add(skb_frag_t *frag, int delta)
+{
+ frag->size += delta;
+}
+
+static inline void skb_frag_size_sub(skb_frag_t *frag, int delta)
+{
+ frag->size -= delta;
+}
+
#define HAVE_HW_TIME_STAMP
/**
@@ -322,6 +350,8 @@ typedef unsigned char *sk_buff_data_t;
* @queue_mapping: Queue mapping for multiqueue devices
* @ndisc_nodetype: router type (from link layer)
* @ooo_okay: allow the mapping of a socket to a queue to be changed
+ * @l4_rxhash: indicate rxhash is a canonical 4-tuple hash over transport
+ * ports.
* @dma_cookie: a cookie to one of several possible DMA operations
* done by skb DMA functions
* @secmark: security marking
@@ -414,6 +444,7 @@ struct sk_buff {
__u8 ndisc_nodetype:2;
#endif
__u8 ooo_okay:1;
+ __u8 l4_rxhash:1;
kmemcheck_bitfield_end(flags2);
/* 0/13 bit hole */
@@ -521,9 +552,11 @@ static inline struct sk_buff *alloc_skb_fclone(unsigned int size,
return __alloc_skb(size, priority, 1, NUMA_NO_NODE);
}
+extern void skb_recycle(struct sk_buff *skb);
extern bool skb_recycle_check(struct sk_buff *skb, int skb_size);
extern struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src);
+extern int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask);
extern struct sk_buff *skb_clone(struct sk_buff *skb,
gfp_t priority);
extern struct sk_buff *skb_copy(const struct sk_buff *skb,
@@ -572,11 +605,11 @@ extern unsigned int skb_find_text(struct sk_buff *skb, unsigned int from,
unsigned int to, struct ts_config *config,
struct ts_state *state);
-extern __u32 __skb_get_rxhash(struct sk_buff *skb);
+extern void __skb_get_rxhash(struct sk_buff *skb);
static inline __u32 skb_get_rxhash(struct sk_buff *skb)
{
if (!skb->rxhash)
- skb->rxhash = __skb_get_rxhash(skb);
+ __skb_get_rxhash(skb);
return skb->rxhash;
}
@@ -822,9 +855,9 @@ static inline struct sk_buff *skb_unshare(struct sk_buff *skb,
* The reference count is not incremented and the reference is therefore
* volatile. Use with caution.
*/
-static inline struct sk_buff *skb_peek(struct sk_buff_head *list_)
+static inline struct sk_buff *skb_peek(const struct sk_buff_head *list_)
{
- struct sk_buff *list = ((struct sk_buff *)list_)->next;
+ struct sk_buff *list = ((const struct sk_buff *)list_)->next;
if (list == (struct sk_buff *)list_)
list = NULL;
return list;
@@ -843,9 +876,9 @@ static inline struct sk_buff *skb_peek(struct sk_buff_head *list_)
* The reference count is not incremented and the reference is therefore
* volatile. Use with caution.
*/
-static inline struct sk_buff *skb_peek_tail(struct sk_buff_head *list_)
+static inline struct sk_buff *skb_peek_tail(const struct sk_buff_head *list_)
{
- struct sk_buff *list = ((struct sk_buff *)list_)->prev;
+ struct sk_buff *list = ((const struct sk_buff *)list_)->prev;
if (list == (struct sk_buff *)list_)
list = NULL;
return list;
@@ -1122,18 +1155,51 @@ static inline int skb_pagelen(const struct sk_buff *skb)
int i, len = 0;
for (i = (int)skb_shinfo(skb)->nr_frags - 1; i >= 0; i--)
- len += skb_shinfo(skb)->frags[i].size;
+ len += skb_frag_size(&skb_shinfo(skb)->frags[i]);
return len + skb_headlen(skb);
}
-static inline void skb_fill_page_desc(struct sk_buff *skb, int i,
- struct page *page, int off, int size)
+/**
+ * __skb_fill_page_desc - initialise a paged fragment in an skb
+ * @skb: buffer containing fragment to be initialised
+ * @i: paged fragment index to initialise
+ * @page: the page to use for this fragment
+ * @off: the offset to the data with @page
+ * @size: the length of the data
+ *
+ * Initialises the @i'th fragment of @skb to point to &size bytes at
+ * offset @off within @page.
+ *
+ * Does not take any additional reference on the fragment.
+ */
+static inline void __skb_fill_page_desc(struct sk_buff *skb, int i,
+ struct page *page, int off, int size)
{
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- frag->page = page;
+ frag->page.p = page;
frag->page_offset = off;
- frag->size = size;
+ skb_frag_size_set(frag, size);
+}
+
+/**
+ * skb_fill_page_desc - initialise a paged fragment in an skb
+ * @skb: buffer containing fragment to be initialised
+ * @i: paged fragment index to initialise
+ * @page: the page to use for this fragment
+ * @off: the offset to the data with @page
+ * @size: the length of the data
+ *
+ * As per __skb_fill_page_desc() -- initialises the @i'th fragment of
+ * @skb to point to &size bytes at offset @off within @page. In
+ * addition updates @skb such that @i is the last fragment.
+ *
+ * Does not take any additional reference on the fragment.
+ */
+static inline void skb_fill_page_desc(struct sk_buff *skb, int i,
+ struct page *page, int off, int size)
+{
+ __skb_fill_page_desc(skb, i, page, off, size);
skb_shinfo(skb)->nr_frags = i + 1;
}
@@ -1628,6 +1694,137 @@ static inline void netdev_free_page(struct net_device *dev, struct page *page)
}
/**
+ * skb_frag_page - retrieve the page refered to by a paged fragment
+ * @frag: the paged fragment
+ *
+ * Returns the &struct page associated with @frag.
+ */
+static inline struct page *skb_frag_page(const skb_frag_t *frag)
+{
+ return frag->page.p;
+}
+
+/**
+ * __skb_frag_ref - take an addition reference on a paged fragment.
+ * @frag: the paged fragment
+ *
+ * Takes an additional reference on the paged fragment @frag.
+ */
+static inline void __skb_frag_ref(skb_frag_t *frag)
+{
+ get_page(skb_frag_page(frag));
+}
+
+/**
+ * skb_frag_ref - take an addition reference on a paged fragment of an skb.
+ * @skb: the buffer
+ * @f: the fragment offset.
+ *
+ * Takes an additional reference on the @f'th paged fragment of @skb.
+ */
+static inline void skb_frag_ref(struct sk_buff *skb, int f)
+{
+ __skb_frag_ref(&skb_shinfo(skb)->frags[f]);
+}
+
+/**
+ * __skb_frag_unref - release a reference on a paged fragment.
+ * @frag: the paged fragment
+ *
+ * Releases a reference on the paged fragment @frag.
+ */
+static inline void __skb_frag_unref(skb_frag_t *frag)
+{
+ put_page(skb_frag_page(frag));
+}
+
+/**
+ * skb_frag_unref - release a reference on a paged fragment of an skb.
+ * @skb: the buffer
+ * @f: the fragment offset
+ *
+ * Releases a reference on the @f'th paged fragment of @skb.
+ */
+static inline void skb_frag_unref(struct sk_buff *skb, int f)
+{
+ __skb_frag_unref(&skb_shinfo(skb)->frags[f]);
+}
+
+/**
+ * skb_frag_address - gets the address of the data contained in a paged fragment
+ * @frag: the paged fragment buffer
+ *
+ * Returns the address of the data within @frag. The page must already
+ * be mapped.
+ */
+static inline void *skb_frag_address(const skb_frag_t *frag)
+{
+ return page_address(skb_frag_page(frag)) + frag->page_offset;
+}
+
+/**
+ * skb_frag_address_safe - gets the address of the data contained in a paged fragment
+ * @frag: the paged fragment buffer
+ *
+ * Returns the address of the data within @frag. Checks that the page
+ * is mapped and returns %NULL otherwise.
+ */
+static inline void *skb_frag_address_safe(const skb_frag_t *frag)
+{
+ void *ptr = page_address(skb_frag_page(frag));
+ if (unlikely(!ptr))
+ return NULL;
+
+ return ptr + frag->page_offset;
+}
+
+/**
+ * __skb_frag_set_page - sets the page contained in a paged fragment
+ * @frag: the paged fragment
+ * @page: the page to set
+ *
+ * Sets the fragment @frag to contain @page.
+ */
+static inline void __skb_frag_set_page(skb_frag_t *frag, struct page *page)
+{
+ frag->page.p = page;
+}
+
+/**
+ * skb_frag_set_page - sets the page contained in a paged fragment of an skb
+ * @skb: the buffer
+ * @f: the fragment offset
+ * @page: the page to set
+ *
+ * Sets the @f'th fragment of @skb to contain @page.
+ */
+static inline void skb_frag_set_page(struct sk_buff *skb, int f,
+ struct page *page)
+{
+ __skb_frag_set_page(&skb_shinfo(skb)->frags[f], page);
+}
+
+/**
+ * skb_frag_dma_map - maps a paged fragment via the DMA API
+ * @device: the device to map the fragment to
+ * @frag: the paged fragment to map
+ * @offset: the offset within the fragment (starting at the
+ * fragment's own offset)
+ * @size: the number of bytes to map
+ * @direction: the direction of the mapping (%PCI_DMA_*)
+ *
+ * Maps the page associated with @frag to @device.
+ */
+static inline dma_addr_t skb_frag_dma_map(struct device *dev,
+ const skb_frag_t *frag,
+ size_t offset, size_t size,
+ enum dma_data_direction dir)
+{
+ return dma_map_page(dev, skb_frag_page(frag),
+ frag->page_offset + offset, size, dir);
+}
+
+/**
* skb_clone_writable - is the header of a clone writable
* @skb: buffer to check
* @len: length up to which to write
@@ -1635,7 +1832,7 @@ static inline void netdev_free_page(struct net_device *dev, struct page *page)
* Returns true if modifying the header part of the cloned buffer
* does not requires the data to be copied.
*/
-static inline int skb_clone_writable(struct sk_buff *skb, unsigned int len)
+static inline int skb_clone_writable(const struct sk_buff *skb, unsigned int len)
{
return !skb_header_cloned(skb) &&
skb_headroom(skb) + len <= skb->hdr_len;
@@ -1729,13 +1926,13 @@ static inline int skb_add_data(struct sk_buff *skb,
}
static inline int skb_can_coalesce(struct sk_buff *skb, int i,
- struct page *page, int off)
+ const struct page *page, int off)
{
if (i) {
- struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i - 1];
+ const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i - 1];
- return page == frag->page &&
- off == frag->page_offset + frag->size;
+ return page == skb_frag_page(frag) &&
+ off == frag->page_offset + skb_frag_size(frag);
}
return 0;
}
@@ -2019,8 +2216,13 @@ static inline bool skb_defer_rx_timestamp(struct sk_buff *skb)
/**
* skb_complete_tx_timestamp() - deliver cloned skb with tx timestamps
*
+ * PHY drivers may accept clones of transmitted packets for
+ * timestamping via their phy_driver.txtstamp method. These drivers
+ * must call this function to return the skb back to the stack, with
+ * or without a timestamp.
+ *
* @skb: clone of the the original outgoing packet
- * @hwtstamps: hardware time stamps
+ * @hwtstamps: hardware time stamps, may be NULL if not available
*
*/
void skb_complete_tx_timestamp(struct sk_buff *skb,
@@ -2256,7 +2458,8 @@ static inline bool skb_warn_if_lro(const struct sk_buff *skb)
{
/* LRO sets gso_size but not gso_type, whereas if GSO is really
* wanted then gso_type will be set. */
- struct skb_shared_info *shinfo = skb_shinfo(skb);
+ const struct skb_shared_info *shinfo = skb_shinfo(skb);
+
if (skb_is_nonlinear(skb) && shinfo->gso_size != 0 &&
unlikely(shinfo->gso_type == 0)) {
__skb_warn_lro_forwarding(skb);
@@ -2280,7 +2483,7 @@ static inline void skb_forward_csum(struct sk_buff *skb)
* Instead of forcing ip_summed to CHECKSUM_NONE, we can
* use this helper, to document places where we make this assertion.
*/
-static inline void skb_checksum_none_assert(struct sk_buff *skb)
+static inline void skb_checksum_none_assert(const struct sk_buff *skb)
{
#ifdef DEBUG
BUG_ON(skb->ip_summed != CHECKSUM_NONE);
@@ -2289,5 +2492,25 @@ static inline void skb_checksum_none_assert(struct sk_buff *skb)
bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off);
+static inline bool skb_is_recycleable(const struct sk_buff *skb, int skb_size)
+{
+ if (irqs_disabled())
+ return false;
+
+ if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY)
+ return false;
+
+ if (skb_is_nonlinear(skb) || skb->fclone != SKB_FCLONE_UNAVAILABLE)
+ return false;
+
+ skb_size = SKB_DATA_ALIGN(skb_size + NET_SKB_PAD);
+ if (skb_end_pointer(skb) - skb->head < skb_size)
+ return false;
+
+ if (skb_shared(skb) || skb_cloned(skb))
+ return false;
+
+ return true;
+}
#endif /* __KERNEL__ */
#endif /* _LINUX_SKBUFF_H */
diff --git a/include/linux/snmp.h b/include/linux/snmp.h
index 12b2b18e50c1..e16557a357e5 100644
--- a/include/linux/snmp.h
+++ b/include/linux/snmp.h
@@ -231,6 +231,8 @@ enum
LINUX_MIB_TCPDEFERACCEPTDROP,
LINUX_MIB_IPRPFILTER, /* IP Reverse Path Filter (rp_filter) */
LINUX_MIB_TCPTIMEWAITOVERFLOW, /* TCPTimeWaitOverflow */
+ LINUX_MIB_TCPREQQFULLDOCOOKIES, /* TCPReqQFullDoCookies */
+ LINUX_MIB_TCPREQQFULLDROP, /* TCPReqQFullDrop */
__LINUX_MIB_MAX
};
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
index 8623217f84d0..f10ed7b4a714 100644
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -25,7 +25,7 @@ struct ssb_sprom {
u8 et1phyaddr; /* MII address for enet1 */
u8 et0mdcport; /* MDIO for enet0 */
u8 et1mdcport; /* MDIO for enet1 */
- u8 board_rev; /* Board revision number from SPROM. */
+ u16 board_rev; /* Board revision number 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 */
diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h
index efbf459d571c..98941203a27f 100644
--- a/include/linux/ssb/ssb_regs.h
+++ b/include/linux/ssb/ssb_regs.h
@@ -462,6 +462,46 @@
#define SSB_SPROM8_OFDM5GLPO 0x014A /* 5.2GHz OFDM power offset */
#define SSB_SPROM8_OFDM5GHPO 0x014E /* 5.8GHz OFDM power offset */
+/* Values for boardflags_lo read from SPROM */
+#define SSB_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */
+#define SSB_BFL_PACTRL 0x0002 /* GPIO 9 controlling the PA */
+#define SSB_BFL_AIRLINEMODE 0x0004 /* implements GPIO 13 radio disable indication */
+#define SSB_BFL_RSSI 0x0008 /* software calculates nrssi slope. */
+#define SSB_BFL_ENETSPI 0x0010 /* has ephy roboswitch spi */
+#define SSB_BFL_XTAL_NOSLOW 0x0020 /* no slow clock available */
+#define SSB_BFL_CCKHIPWR 0x0040 /* can do high power CCK transmission */
+#define SSB_BFL_ENETADM 0x0080 /* has ADMtek switch */
+#define SSB_BFL_ENETVLAN 0x0100 /* can do vlan */
+#define SSB_BFL_AFTERBURNER 0x0200 /* supports Afterburner mode */
+#define SSB_BFL_NOPCI 0x0400 /* board leaves PCI floating */
+#define SSB_BFL_FEM 0x0800 /* supports the Front End Module */
+#define SSB_BFL_EXTLNA 0x1000 /* has an external LNA */
+#define SSB_BFL_HGPA 0x2000 /* had high gain PA */
+#define SSB_BFL_BTCMOD 0x4000 /* BFL_BTCOEXIST is given in alternate GPIOs */
+#define SSB_BFL_ALTIQ 0x8000 /* alternate I/Q settings */
+
+/* Values for boardflags_hi read from SPROM */
+#define SSB_BFH_NOPA 0x0001 /* has no PA */
+#define SSB_BFH_RSSIINV 0x0002 /* RSSI uses positive slope (not TSSI) */
+#define SSB_BFH_PAREF 0x0004 /* uses the PARef LDO */
+#define SSB_BFH_3TSWITCH 0x0008 /* uses a triple throw switch shared with bluetooth */
+#define SSB_BFH_PHASESHIFT 0x0010 /* can support phase shifter */
+#define SSB_BFH_BUCKBOOST 0x0020 /* has buck/booster */
+#define SSB_BFH_FEM_BT 0x0040 /* has FEM and switch to share antenna with bluetooth */
+
+/* Values for boardflags2_lo read from SPROM */
+#define SSB_BFL2_RXBB_INT_REG_DIS 0x0001 /* external RX BB regulator present */
+#define SSB_BFL2_APLL_WAR 0x0002 /* alternative A-band PLL settings implemented */
+#define SSB_BFL2_TXPWRCTRL_EN 0x0004 /* permits enabling TX Power Control */
+#define SSB_BFL2_2X4_DIV 0x0008 /* 2x4 diversity switch */
+#define SSB_BFL2_5G_PWRGAIN 0x0010 /* supports 5G band power gain */
+#define SSB_BFL2_PCIEWAR_OVR 0x0020 /* overrides ASPM and Clkreq settings */
+#define SSB_BFL2_CAESERS_BRD 0x0040 /* is Caesers board (unused) */
+#define SSB_BFL2_BTC3WIRE 0x0080 /* used 3-wire bluetooth coexist */
+#define SSB_BFL2_SKWRKFEM_BRD 0x0100 /* 4321mcm93 uses Skyworks FEM */
+#define SSB_BFL2_SPUR_WAR 0x0200 /* has a workaround for clock-harmonic spurs */
+#define SSB_BFL2_GPLL_WAR 0x0400 /* altenative G-band PLL settings implemented */
+
/* Values for SSB_SPROM1_BINF_CCODE */
enum {
SSB_SPROM1CCODE_WORLD = 0,
diff --git a/drivers/net/sungem_phy.h b/include/linux/sungem_phy.h
index af02f9479cbb..bd9be9f59d3a 100644
--- a/drivers/net/sungem_phy.h
+++ b/include/linux/sungem_phy.h
@@ -61,7 +61,7 @@ struct mii_phy
/* Pass in a struct mii_phy with dev, mdio_read and mdio_write
* filled, the remaining fields will be filled on return
*/
-extern int mii_phy_probe(struct mii_phy *phy, int mii_id);
+extern int sungem_phy_probe(struct mii_phy *phy, int mii_id);
/* MII definitions missing from mii.h */
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index db7bcaf7c5bd..492486a74484 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -9,6 +9,7 @@
#ifndef _LINUX_SUNRPC_CLNT_H
#define _LINUX_SUNRPC_CLNT_H
+#include <linux/types.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/in6.h>
@@ -161,7 +162,7 @@ const char *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t);
size_t rpc_ntop(const struct sockaddr *, char *, const size_t);
size_t rpc_pton(const char *, const size_t,
struct sockaddr *, const size_t);
-char * rpc_sockaddr2uaddr(const struct sockaddr *);
+char * rpc_sockaddr2uaddr(const struct sockaddr *, gfp_t);
size_t rpc_uaddr2sockaddr(const char *, const size_t,
struct sockaddr *, const size_t);
@@ -218,7 +219,13 @@ static inline bool __rpc_cmp_addr6(const struct sockaddr *sap1,
{
const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sap1;
const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sap2;
- return ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr);
+
+ if (!ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr))
+ return false;
+ else if (ipv6_addr_type(&sin1->sin6_addr) & IPV6_ADDR_LINKLOCAL)
+ return sin1->sin6_scope_id == sin2->sin6_scope_id;
+
+ return true;
}
static inline bool __rpc_copy_addr6(struct sockaddr *dst,
diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h
index cf14db975da0..e4ea43058d8f 100644
--- a/include/linux/sunrpc/rpc_pipe_fs.h
+++ b/include/linux/sunrpc/rpc_pipe_fs.h
@@ -44,6 +44,8 @@ RPC_I(struct inode *inode)
return container_of(inode, struct rpc_inode, vfs_inode);
}
+extern ssize_t rpc_pipe_generic_upcall(struct file *, struct rpc_pipe_msg *,
+ char __user *, size_t);
extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *);
struct rpc_clnt;
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 223588a976a0..d8d5d93071b3 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -212,11 +212,6 @@ static inline void svc_putu32(struct kvec *iov, __be32 val)
iov->iov_len += sizeof(__be32);
}
-union svc_addr_u {
- struct in_addr addr;
- struct in6_addr addr6;
-};
-
/*
* The context of a single thread, including the request currently being
* processed.
@@ -225,8 +220,12 @@ struct svc_rqst {
struct list_head rq_list; /* idle list */
struct list_head rq_all; /* all threads list */
struct svc_xprt * rq_xprt; /* transport ptr */
+
struct sockaddr_storage rq_addr; /* peer address */
size_t rq_addrlen;
+ struct sockaddr_storage rq_daddr; /* dest addr of request
+ * - reply from here */
+ size_t rq_daddrlen;
struct svc_serv * rq_server; /* RPC service definition */
struct svc_pool * rq_pool; /* thread pool */
@@ -255,9 +254,6 @@ struct svc_rqst {
unsigned short
rq_secure : 1; /* secure port */
- union svc_addr_u rq_daddr; /* dest addr of request
- * - reply from here */
-
void * rq_argp; /* decoded arguments */
void * rq_resp; /* xdr'd results */
void * rq_auth_data; /* flavor-specific data */
@@ -300,6 +296,21 @@ static inline struct sockaddr *svc_addr(const struct svc_rqst *rqst)
return (struct sockaddr *) &rqst->rq_addr;
}
+static inline struct sockaddr_in *svc_daddr_in(const struct svc_rqst *rqst)
+{
+ return (struct sockaddr_in *) &rqst->rq_daddr;
+}
+
+static inline struct sockaddr_in6 *svc_daddr_in6(const struct svc_rqst *rqst)
+{
+ return (struct sockaddr_in6 *) &rqst->rq_daddr;
+}
+
+static inline struct sockaddr *svc_daddr(const struct svc_rqst *rqst)
+{
+ return (struct sockaddr *) &rqst->rq_daddr;
+}
+
/*
* Check buffer bounds after decoding arguments
*/
@@ -340,7 +351,8 @@ struct svc_deferred_req {
struct svc_xprt *xprt;
struct sockaddr_storage addr; /* where reply must go */
size_t addrlen;
- union svc_addr_u daddr; /* where reply must come from */
+ struct sockaddr_storage daddr; /* where reply must come from */
+ size_t daddrlen;
struct cache_deferred_req handle;
size_t xprt_hlen;
int argslen;
@@ -404,7 +416,7 @@ struct svc_procedure {
struct svc_serv *svc_create(struct svc_program *, unsigned int,
void (*shutdown)(struct svc_serv *));
struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
- struct svc_pool *pool);
+ struct svc_pool *pool, int node);
void svc_exit_thread(struct svc_rqst *);
struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int,
void (*shutdown)(struct svc_serv *),
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 6bbcef22e105..57a692432f8a 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -8,15 +8,18 @@
#include <linux/mm.h>
#include <asm/errno.h>
-#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE)
+#ifdef CONFIG_VT
extern void pm_set_vt_switch(int);
-extern int pm_prepare_console(void);
-extern void pm_restore_console(void);
#else
static inline void pm_set_vt_switch(int do_switch)
{
}
+#endif
+#ifdef CONFIG_VT_CONSOLE_SLEEP
+extern int pm_prepare_console(void);
+extern void pm_restore_console(void);
+#else
static inline int pm_prepare_console(void)
{
return 0;
@@ -34,6 +37,58 @@ typedef int __bitwise suspend_state_t;
#define PM_SUSPEND_MEM ((__force suspend_state_t) 3)
#define PM_SUSPEND_MAX ((__force suspend_state_t) 4)
+enum suspend_stat_step {
+ SUSPEND_FREEZE = 1,
+ SUSPEND_PREPARE,
+ SUSPEND_SUSPEND,
+ SUSPEND_SUSPEND_NOIRQ,
+ SUSPEND_RESUME_NOIRQ,
+ SUSPEND_RESUME
+};
+
+struct suspend_stats {
+ int success;
+ int fail;
+ int failed_freeze;
+ int failed_prepare;
+ int failed_suspend;
+ int failed_suspend_noirq;
+ int failed_resume;
+ int failed_resume_noirq;
+#define REC_FAILED_NUM 2
+ int last_failed_dev;
+ char failed_devs[REC_FAILED_NUM][40];
+ int last_failed_errno;
+ int errno[REC_FAILED_NUM];
+ int last_failed_step;
+ enum suspend_stat_step failed_steps[REC_FAILED_NUM];
+};
+
+extern struct suspend_stats suspend_stats;
+
+static inline void dpm_save_failed_dev(const char *name)
+{
+ strlcpy(suspend_stats.failed_devs[suspend_stats.last_failed_dev],
+ name,
+ sizeof(suspend_stats.failed_devs[0]));
+ suspend_stats.last_failed_dev++;
+ suspend_stats.last_failed_dev %= REC_FAILED_NUM;
+}
+
+static inline void dpm_save_failed_errno(int err)
+{
+ suspend_stats.errno[suspend_stats.last_failed_errno] = err;
+ suspend_stats.last_failed_errno++;
+ suspend_stats.last_failed_errno %= REC_FAILED_NUM;
+}
+
+static inline void dpm_save_failed_step(enum suspend_stat_step step)
+{
+ suspend_stats.failed_steps[suspend_stats.last_failed_step] = step;
+ suspend_stats.last_failed_step++;
+ suspend_stats.last_failed_step %= REC_FAILED_NUM;
+}
+
/**
* struct platform_suspend_ops - Callbacks for managing platform dependent
* system sleep states.
@@ -334,4 +389,38 @@ static inline void unlock_system_sleep(void)
}
#endif
+#ifdef CONFIG_ARCH_SAVE_PAGE_KEYS
+/*
+ * The ARCH_SAVE_PAGE_KEYS functions can be used by an architecture
+ * to save/restore additional information to/from the array of page
+ * frame numbers in the hibernation image. For s390 this is used to
+ * save and restore the storage key for each page that is included
+ * in the hibernation image.
+ */
+unsigned long page_key_additional_pages(unsigned long pages);
+int page_key_alloc(unsigned long pages);
+void page_key_free(void);
+void page_key_read(unsigned long *pfn);
+void page_key_memorize(unsigned long *pfn);
+void page_key_write(void *address);
+
+#else /* !CONFIG_ARCH_SAVE_PAGE_KEYS */
+
+static inline unsigned long page_key_additional_pages(unsigned long pages)
+{
+ return 0;
+}
+
+static inline int page_key_alloc(unsigned long pages)
+{
+ return 0;
+}
+
+static inline void page_key_free(void) {}
+static inline void page_key_read(unsigned long *pfn) {}
+static inline void page_key_memorize(unsigned long *pfn) {}
+static inline void page_key_write(void *address) {}
+
+#endif /* !CONFIG_ARCH_SAVE_PAGE_KEYS */
+
#endif /* _LINUX_SUSPEND_H */
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 14d62490922e..c71f84bb62ec 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -252,6 +252,12 @@ static inline void lru_cache_add_file(struct page *page)
extern unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
gfp_t gfp_mask, nodemask_t *mask);
extern int __isolate_lru_page(struct page *page, int mode, int file);
+extern unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem,
+ gfp_t gfp_mask, bool noswap);
+extern unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
+ gfp_t gfp_mask, bool noswap,
+ struct zone *zone,
+ unsigned long *nr_scanned);
extern unsigned long shrink_all_memory(unsigned long nr_pages);
extern int vm_swappiness;
extern int remove_mapping(struct address_space *mapping, struct page *page);
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 8c03b98df5f9..1ff0ec2a5e8d 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -702,9 +702,6 @@ asmlinkage long sys_sysctl(struct __sysctl_args __user *args);
asmlinkage long sys_sysinfo(struct sysinfo __user *info);
asmlinkage long sys_sysfs(int option,
unsigned long arg1, unsigned long arg2);
-asmlinkage long sys_nfsservctl(int cmd,
- struct nfsctl_arg __user *arg,
- void __user *res);
asmlinkage long sys_syslog(int type, char __user *buf, int len);
asmlinkage long sys_uselib(const char __user *library);
asmlinkage long sys_ni_syscall(void);
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 11684d9e6bd2..9a1ec10fd504 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -435,7 +435,7 @@ enum {
NET_IPV4_ROUTE_MAX_SIZE=5,
NET_IPV4_ROUTE_GC_MIN_INTERVAL=6,
NET_IPV4_ROUTE_GC_TIMEOUT=7,
- NET_IPV4_ROUTE_GC_INTERVAL=8,
+ NET_IPV4_ROUTE_GC_INTERVAL=8, /* obsolete since 2.6.38 */
NET_IPV4_ROUTE_REDIRECT_LOAD=9,
NET_IPV4_ROUTE_REDIRECT_NUMBER=10,
NET_IPV4_ROUTE_REDIRECT_SILENCE=11,
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index d7d2f2158142..dac0859e6440 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -112,6 +112,7 @@ struct bin_attribute {
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *,char *);
ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);
+ const void *(*namespace)(struct kobject *, const struct attribute *);
};
struct sysfs_dirent;
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 531ede8006d9..7f59ee946983 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -111,7 +111,8 @@ enum {
#define TCPI_OPT_TIMESTAMPS 1
#define TCPI_OPT_SACK 2
#define TCPI_OPT_WSCALE 4
-#define TCPI_OPT_ECN 8
+#define TCPI_OPT_ECN 8 /* ECN was negociated at TCP session init */
+#define TCPI_OPT_ECN_SEEN 16 /* we received at least one packet with ECT */
enum tcp_ca_state {
TCP_CA_Open = 0,
@@ -379,6 +380,10 @@ struct tcp_sock {
u32 snd_cwnd_clamp; /* Do not allow snd_cwnd to grow above this */
u32 snd_cwnd_used;
u32 snd_cwnd_stamp;
+ u32 prior_cwnd; /* Congestion window at start of Recovery. */
+ u32 prr_delivered; /* Number of newly delivered packets to
+ * receiver in Recovery. */
+ u32 prr_out; /* Total number of pkts sent during Recovery. */
u32 rcv_wnd; /* Current receiver window */
u32 write_seq; /* Tail(+1) of data held in tcp send buffer */
diff --git a/include/linux/ti_wilink_st.h b/include/linux/ti_wilink_st.h
index b004e557caa9..2ef4385da6bf 100644
--- a/include/linux/ti_wilink_st.h
+++ b/include/linux/ti_wilink_st.h
@@ -410,7 +410,28 @@ struct gps_event_hdr {
u16 plen;
} __attribute__ ((packed));
-/* platform data */
+/**
+ * struct ti_st_plat_data - platform data shared between ST driver and
+ * platform specific board file which adds the ST device.
+ * @nshutdown_gpio: Host's GPIO line to which chip's BT_EN is connected.
+ * @dev_name: The UART/TTY name to which chip is interfaced. (eg: /dev/ttyS1)
+ * @flow_cntrl: Should always be 1, since UART's CTS/RTS is used for PM
+ * purposes.
+ * @baud_rate: The baud rate supported by the Host UART controller, this will
+ * be shared across with the chip via a HCI VS command from User-Space Init
+ * Mgr application.
+ * @suspend:
+ * @resume: legacy PM routines hooked to platform specific board file, so as
+ * to take chip-host interface specific action.
+ * @chip_enable:
+ * @chip_disable: Platform/Interface specific mux mode setting, GPIO
+ * configuring, Host side PM disabling etc.. can be done here.
+ * @chip_asleep:
+ * @chip_awake: Chip specific deep sleep states is communicated to Host
+ * specific board-xx.c to take actions such as cut UART clocks when chip
+ * asleep or run host faster when chip awake etc..
+ *
+ */
struct ti_st_plat_data {
long nshutdown_gpio;
unsigned char dev_name[UART_DEV_NAME_LEN]; /* uart name */
@@ -418,6 +439,10 @@ struct ti_st_plat_data {
unsigned long baud_rate;
int (*suspend)(struct platform_device *, pm_message_t);
int (*resume)(struct platform_device *);
+ int (*chip_enable) (struct kim_data_s *);
+ int (*chip_disable) (struct kim_data_s *);
+ int (*chip_asleep) (struct kim_data_s *);
+ int (*chip_awake) (struct kim_data_s *);
};
#endif /* TI_WILINK_ST_H */
diff --git a/include/linux/tipc_config.h b/include/linux/tipc_config.h
index 0db239590b4d..9730b0e51e46 100644
--- a/include/linux/tipc_config.h
+++ b/include/linux/tipc_config.h
@@ -41,6 +41,10 @@
#include <linux/string.h>
#include <asm/byteorder.h>
+#ifndef __KERNEL__
+#include <arpa/inet.h> /* for ntohs etc. */
+#endif
+
/*
* Configuration
*
diff --git a/include/linux/tty.h b/include/linux/tty.h
index ff2925aa4e79..5dbb3cb05a82 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -421,6 +421,8 @@ extern void tty_driver_flush_buffer(struct tty_struct *tty);
extern void tty_throttle(struct tty_struct *tty);
extern void tty_unthrottle(struct tty_struct *tty);
extern int tty_do_resize(struct tty_struct *tty, struct winsize *ws);
+extern void tty_driver_remove_tty(struct tty_driver *driver,
+ struct tty_struct *tty);
extern void tty_shutdown(struct tty_struct *tty);
extern void tty_free_termios(struct tty_struct *tty);
extern int is_current_pgrp_orphaned(void);
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 9deeac855240..ecdaeb98b293 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -47,6 +47,9 @@
*
* This routine is called synchronously when a particular tty device
* is closed for the last time freeing up the resources.
+ * Note that tty_shutdown() is not called if ops->shutdown is defined.
+ * This means one is responsible to take care of calling ops->remove (e.g.
+ * via tty_driver_remove_tty) and releasing tty->termios.
*
*
* void (*cleanup)(struct tty_struct * tty);
diff --git a/include/linux/uio_driver.h b/include/linux/uio_driver.h
index 665517c05eaf..fd99ff9298c6 100644
--- a/include/linux/uio_driver.h
+++ b/include/linux/uio_driver.h
@@ -23,7 +23,10 @@ struct uio_map;
/**
* struct uio_mem - description of a UIO memory region
* @name: name of the memory region for identification
- * @addr: address of the device's memory
+ * @addr: address of the device's memory (phys_addr is used since
+ * addr can be logical, virtual, or physical & phys_addr_t
+ * should always be large enough to handle any of the
+ * address types)
* @size: size of IO
* @memtype: type of memory addr points to
* @internal_addr: ioremap-ped version of addr, for driver internal use
@@ -31,7 +34,7 @@ struct uio_map;
*/
struct uio_mem {
const char *name;
- unsigned long addr;
+ phys_addr_t addr;
unsigned long size;
int memtype;
void __iomem *internal_addr;
diff --git a/include/linux/un.h b/include/linux/un.h
index 45561c564b8e..3ed3e46c1b1f 100644
--- a/include/linux/un.h
+++ b/include/linux/un.h
@@ -1,10 +1,12 @@
#ifndef _LINUX_UN_H
#define _LINUX_UN_H
+#include <linux/socket.h>
+
#define UNIX_PATH_MAX 108
struct sockaddr_un {
- sa_family_t sun_family; /* AF_UNIX */
+ __kernel_sa_family_t sun_family; /* AF_UNIX */
char sun_path[UNIX_PATH_MAX]; /* pathname */
};
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 73c7df489607..6f49a1b39fa6 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -292,6 +292,16 @@ struct usb_host_config {
int extralen;
};
+/* USB2.0 and USB3.0 device BOS descriptor set */
+struct usb_host_bos {
+ struct usb_bos_descriptor *desc;
+
+ /* wireless cap descriptor is handled by wusb */
+ struct usb_ext_cap_descriptor *ext_cap;
+ struct usb_ss_cap_descriptor *ss_cap;
+ struct usb_ss_container_id_descriptor *ss_id;
+};
+
int __usb_get_extra_descriptor(char *buffer, unsigned size,
unsigned char type, void **ptr);
#define usb_get_extra_descriptor(ifpoint, type, ptr) \
@@ -381,6 +391,7 @@ struct usb_tt;
* @ep0: endpoint 0 data (default control pipe)
* @dev: generic device interface
* @descriptor: USB device descriptor
+ * @bos: USB device BOS descriptor set
* @config: all of the device's configs
* @actconfig: the active configuration
* @ep_in: array of IN endpoints
@@ -399,6 +410,9 @@ struct usb_tt;
* FIXME -- complete doc
* @authenticated: Crypto authentication passed
* @wusb: device is Wireless USB
+ * @lpm_capable: device supports LPM
+ * @usb2_hw_lpm_capable: device can perform USB2 hardware LPM
+ * @usb2_hw_lpm_enabled: USB2 hardware LPM enabled
* @string_langid: language ID for strings
* @product: iProduct string, if present (static)
* @manufacturer: iManufacturer string, if present (static)
@@ -442,6 +456,7 @@ struct usb_device {
struct device dev;
struct usb_device_descriptor descriptor;
+ struct usb_host_bos *bos;
struct usb_host_config *config;
struct usb_host_config *actconfig;
@@ -460,6 +475,9 @@ struct usb_device {
unsigned authorized:1;
unsigned authenticated:1;
unsigned wusb:1;
+ unsigned lpm_capable:1;
+ unsigned usb2_hw_lpm_capable:1;
+ unsigned usb2_hw_lpm_enabled:1;
int string_langid;
/* static strings from the device */
@@ -1574,7 +1592,7 @@ usb_maxpacket(struct usb_device *udev, int pipe, int is_out)
return 0;
/* NOTE: only 0x07ff bits are for packet size... */
- return le16_to_cpu(ep->desc.wMaxPacketSize);
+ return usb_endpoint_maxp(&ep->desc);
}
/* ----------------------------------------------------------------------- */
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index 0fd3fbdd8283..f32a64e57f97 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -34,6 +34,7 @@
#define __LINUX_USB_CH9_H
#include <linux/types.h> /* __u8 etc */
+#include <asm/byteorder.h> /* le16_to_cpu */
/*-------------------------------------------------------------------------*/
@@ -143,6 +144,11 @@
#define USB_INTRF_FUNC_SUSPEND 0 /* function suspend */
#define USB_INTR_FUNC_SUSPEND_OPT_MASK 0xFF00
+/*
+ * Suspend Options, Table 9-7 USB 3.0 spec
+ */
+#define USB_INTRF_FUNC_SUSPEND_LP (1 << (8 + 0))
+#define USB_INTRF_FUNC_SUSPEND_RW (1 << (8 + 1))
#define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */
@@ -570,6 +576,17 @@ static inline int usb_endpoint_is_isoc_out(
return usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd);
}
+/**
+ * usb_endpoint_maxp - get endpoint's max packet size
+ * @epd: endpoint to be checked
+ *
+ * Returns @epd's max packet
+ */
+static inline int usb_endpoint_maxp(const struct usb_endpoint_descriptor *epd)
+{
+ return le16_to_cpu(epd->wMaxPacketSize);
+}
+
/*-------------------------------------------------------------------------*/
/* USB_DT_SS_ENDPOINT_COMP: SuperSpeed Endpoint Companion descriptor */
@@ -851,6 +868,18 @@ enum usb_device_speed {
USB_SPEED_SUPER, /* usb 3.0 */
};
+#ifdef __KERNEL__
+
+/**
+ * usb_speed_string() - Returns human readable-name of the speed.
+ * @speed: The speed to return human-readable name for. If it's not
+ * any of the speeds defined in usb_device_speed enum, string for
+ * USB_SPEED_UNKNOWN will be returned.
+ */
+extern const char *usb_speed_string(enum usb_device_speed speed);
+
+#endif
+
enum usb_device_state {
/* NOTATTACHED isn't in the USB spec, and this state acts
* the same as ATTACHED ... but it's clearer this way.
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 087f4b931833..1d3a67523ffc 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -437,9 +437,9 @@ static inline void usb_ep_fifo_flush(struct usb_ep *ep)
struct usb_dcd_config_params {
__u8 bU1devExitLat; /* U1 Device exit Latency */
-#define USB_DEFULT_U1_DEV_EXIT_LAT 0x01 /* Less then 1 microsec */
+#define USB_DEFAULT_U1_DEV_EXIT_LAT 0x01 /* Less then 1 microsec */
__le16 bU2DevExitLat; /* U2 Device exit Latency */
-#define USB_DEFULT_U2_DEV_EXIT_LAT 0x1F4 /* Less then 500 microsec */
+#define USB_DEFAULT_U2_DEV_EXIT_LAT 0x1F4 /* Less then 500 microsec */
};
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 0097136ba45d..03354d557b79 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -178,7 +178,7 @@ struct usb_hcd {
* this structure.
*/
unsigned long hcd_priv[0]
- __attribute__ ((aligned(sizeof(unsigned long))));
+ __attribute__ ((aligned(sizeof(s64))));
};
/* 2.4 does this a bit differently ... */
@@ -343,6 +343,7 @@ struct hc_driver {
* address is set
*/
int (*update_device)(struct usb_hcd *, struct usb_device *);
+ int (*set_usb2_hw_lpm)(struct usb_hcd *, struct usb_device *, int);
};
extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
diff --git a/include/linux/usb/r8a66597.h b/include/linux/usb/r8a66597.h
index b6b8660d0c68..55805f9dcf21 100644
--- a/include/linux/usb/r8a66597.h
+++ b/include/linux/usb/r8a66597.h
@@ -48,6 +48,9 @@ struct r8a66597_platdata {
/* (external controller only) set one = WR0_N shorted to WR1_N */
unsigned wr0_shorted_to_wr1:1;
+
+ /* set one = using SUDMAC */
+ unsigned sudmac:1;
};
/* Register definitions */
@@ -417,5 +420,62 @@ struct r8a66597_platdata {
#define USBSPD 0x00C0
#define RTPORT 0x0001
+/* SUDMAC registers */
+#define CH0CFG 0x00
+#define CH1CFG 0x04
+#define CH0BA 0x10
+#define CH1BA 0x14
+#define CH0BBC 0x18
+#define CH1BBC 0x1C
+#define CH0CA 0x20
+#define CH1CA 0x24
+#define CH0CBC 0x28
+#define CH1CBC 0x2C
+#define CH0DEN 0x30
+#define CH1DEN 0x34
+#define DSTSCLR 0x38
+#define DBUFCTRL 0x3C
+#define DINTCTRL 0x40
+#define DINTSTS 0x44
+#define DINTSTSCLR 0x48
+#define CH0SHCTRL 0x50
+#define CH1SHCTRL 0x54
+
+/* SUDMAC Configuration Registers */
+#define SENDBUFM 0x1000 /* b12: Transmit Buffer Mode */
+#define RCVENDM 0x0100 /* b8: Receive Data Transfer End Mode */
+#define LBA_WAIT 0x0030 /* b5-4: Local Bus Access Wait */
+
+/* DMA Enable Registers */
+#define DEN 0x0001 /* b1: DMA Transfer Enable */
+
+/* DMA Status Clear Register */
+#define CH1STCLR 0x0002 /* b2: Ch1 DMA Status Clear */
+#define CH0STCLR 0x0001 /* b1: Ch0 DMA Status Clear */
+
+/* DMA Buffer Control Register */
+#define CH1BUFW 0x0200 /* b9: Ch1 DMA Buffer Data Transfer Enable */
+#define CH0BUFW 0x0100 /* b8: Ch0 DMA Buffer Data Transfer Enable */
+#define CH1BUFS 0x0002 /* b2: Ch1 DMA Buffer Data Status */
+#define CH0BUFS 0x0001 /* b1: Ch0 DMA Buffer Data Status */
+
+/* DMA Interrupt Control Register */
+#define CH1ERRE 0x0200 /* b9: Ch1 SHwy Res Err Detect Int Enable */
+#define CH0ERRE 0x0100 /* b8: Ch0 SHwy Res Err Detect Int Enable */
+#define CH1ENDE 0x0002 /* b2: Ch1 DMA Transfer End Int Enable */
+#define CH0ENDE 0x0001 /* b1: Ch0 DMA Transfer End Int Enable */
+
+/* DMA Interrupt Status Register */
+#define CH1ERRS 0x0200 /* b9: Ch1 SHwy Res Err Detect Int Status */
+#define CH0ERRS 0x0100 /* b8: Ch0 SHwy Res Err Detect Int Status */
+#define CH1ENDS 0x0002 /* b2: Ch1 DMA Transfer End Int Status */
+#define CH0ENDS 0x0001 /* b1: Ch0 DMA Transfer End Int Status */
+
+/* DMA Interrupt Status Clear Register */
+#define CH1ERRC 0x0200 /* b9: Ch1 SHwy Res Err Detect Int Stat Clear */
+#define CH0ERRC 0x0100 /* b8: Ch0 SHwy Res Err Detect Int Stat Clear */
+#define CH1ENDC 0x0002 /* b2: Ch1 DMA Transfer End Int Stat Clear */
+#define CH0ENDC 0x0001 /* b1: Ch0 DMA Transfer End Int Stat Clear */
+
#endif /* __LINUX_USB_R8A66597_H */
diff --git a/include/linux/usb/renesas_usbhs.h b/include/linux/usb/renesas_usbhs.h
index 8977431259c6..e5a40c318548 100644
--- a/include/linux/usb/renesas_usbhs.h
+++ b/include/linux/usb/renesas_usbhs.h
@@ -82,6 +82,13 @@ struct renesas_usbhs_platform_callback {
* get VBUS status function.
*/
int (*get_vbus)(struct platform_device *pdev);
+
+ /*
+ * option:
+ *
+ * VBUS control is needed for Host
+ */
+ int (*set_vbus)(struct platform_device *pdev, int enable);
};
/*
@@ -101,6 +108,8 @@ struct renesas_usbhs_driver_param {
* option:
*
* for BUSWAIT :: BWAIT
+ * see
+ * renesas_usbhs/common.c :: usbhsc_set_buswait()
* */
int buswait_bwait;
@@ -127,6 +136,11 @@ struct renesas_usbhs_driver_param {
* pio <--> dma border.
*/
int pio_dma_border; /* default is 64byte */
+
+ /*
+ * option:
+ */
+ u32 has_otg:1; /* for controlling PWEN/EXTLP */
};
/*
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index 710885749605..851ebf1a4476 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -61,6 +61,9 @@ struct virtqueue {
* virtqueue_detach_unused_buf: detach first unused buffer
* vq: the struct virtqueue we're talking about.
* Returns NULL or the "data" token handed to add_buf
+ * virtqueue_get_vring_size: return the size of the virtqueue's vring
+ * vq: the struct virtqueue containing the vring of interest.
+ * Returns the size of the vring.
*
* Locking rules are straightforward: the driver is responsible for
* locking. No two operations may be invoked simultaneously, with the exception
@@ -97,6 +100,8 @@ bool virtqueue_enable_cb_delayed(struct virtqueue *vq);
void *virtqueue_detach_unused_buf(struct virtqueue *vq);
+unsigned int virtqueue_get_vring_size(struct virtqueue *vq);
+
/**
* virtio_device - representation of a device using virtio
* @index: unique position on the virtio bus
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index f1bfa12ea246..2b8963ff0f35 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -12,15 +12,6 @@
*
* (thresh - thresh/DIRTY_FULL_SCOPE, thresh)
*
- * The 1/16 region above the global dirty limit will be put to maximum pauses:
- *
- * (limit, limit + limit/DIRTY_MAXPAUSE_AREA)
- *
- * The 1/16 region above the max-pause region, dirty exceeded bdi's will be put
- * to loops:
- *
- * (limit + limit/DIRTY_MAXPAUSE_AREA, limit + limit/DIRTY_PASSGOOD_AREA)
- *
* Further beyond, all dirtier tasks will enter a loop waiting (possibly long
* time) for the dirty pages to drop, unless written enough pages.
*
@@ -31,8 +22,6 @@
*/
#define DIRTY_SCOPE 8
#define DIRTY_FULL_SCOPE (DIRTY_SCOPE / 2)
-#define DIRTY_MAXPAUSE_AREA 16
-#define DIRTY_PASSGOOD_AREA 8
/*
* 4MB minimal write chunk size
diff --git a/include/linux/x25.h b/include/linux/x25.h
index 6450a7f12074..810cce6737ea 100644
--- a/include/linux/x25.h
+++ b/include/linux/x25.h
@@ -12,6 +12,7 @@
#define X25_KERNEL_H
#include <linux/types.h>
+#include <linux/socket.h>
#define SIOCX25GSUBSCRIP (SIOCPROTOPRIVATE + 0)
#define SIOCX25SSUBSCRIP (SIOCPROTOPRIVATE + 1)
@@ -57,7 +58,7 @@ struct x25_address {
* Linux X.25 Address structure, used for bind, and connect mostly.
*/
struct sockaddr_x25 {
- sa_family_t sx25_family; /* Must be AF_X25 */
+ __kernel_sa_family_t sx25_family; /* Must be AF_X25 */
struct x25_address sx25_addr; /* X.121 Address */
};
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
index aed54c50aa66..e5d122031542 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -30,6 +30,9 @@
#define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1)
/* Security namespace */
+#define XATTR_EVM_SUFFIX "evm"
+#define XATTR_NAME_EVM XATTR_SECURITY_PREFIX XATTR_EVM_SUFFIX
+
#define XATTR_SELINUX_SUFFIX "selinux"
#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
@@ -49,6 +52,11 @@
#define XATTR_CAPS_SUFFIX "capability"
#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
+#define XATTR_POSIX_ACL_ACCESS "posix_acl_access"
+#define XATTR_NAME_POSIX_ACL_ACCESS XATTR_SYSTEM_PREFIX XATTR_POSIX_ACL_ACCESS
+#define XATTR_POSIX_ACL_DEFAULT "posix_acl_default"
+#define XATTR_NAME_POSIX_ACL_DEFAULT XATTR_SYSTEM_PREFIX XATTR_POSIX_ACL_DEFAULT
+
#ifdef __KERNEL__
#include <linux/types.h>
@@ -67,6 +75,12 @@ struct xattr_handler {
size_t size, int flags, int handler_flags);
};
+struct xattr {
+ char *name;
+ void *value;
+ size_t value_len;
+};
+
ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t);
ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
@@ -78,7 +92,10 @@ ssize_t generic_getxattr(struct dentry *dentry, const char *name, void *buffer,
ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size);
int generic_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags);
int generic_removexattr(struct dentry *dentry, const char *name);
-
+ssize_t vfs_getxattr_alloc(struct dentry *dentry, const char *name,
+ char **xattr_value, size_t size, gfp_t flags);
+int vfs_xattr_cmp(struct dentry *dentry, const char *xattr_name,
+ const char *value, size_t size, gfp_t flags);
#endif /* __KERNEL__ */
#endif /* _LINUX_XATTR_H */
diff --git a/include/media/pwc-ioctl.h b/include/media/pwc-ioctl.h
index 0f19779c4634..1ed1e616fe33 100644
--- a/include/media/pwc-ioctl.h
+++ b/include/media/pwc-ioctl.h
@@ -53,7 +53,6 @@
*/
#include <linux/types.h>
-#include <linux/version.h>
/* Enumeration of image sizes */
#define PSZ_SQCIF 0x00
diff --git a/include/media/videobuf-dma-sg.h b/include/media/videobuf-dma-sg.h
index 1c647e8148c4..d8fb6012c10d 100644
--- a/include/media/videobuf-dma-sg.h
+++ b/include/media/videobuf-dma-sg.h
@@ -34,7 +34,7 @@
* does memory allocation too using vmalloc_32().
*
* videobuf_dma_*()
- * see Documentation/PCI/PCI-DMA-mapping.txt, these functions to
+ * see Documentation/DMA-API-HOWTO.txt, these functions to
* basically the same. The map function does also build a
* scatterlist for the buffer (and unmap frees it ...)
*
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h
index 342dcf13d039..2d70b95b3b55 100644
--- a/include/net/9p/9p.h
+++ b/include/net/9p/9p.h
@@ -76,11 +76,8 @@ do { \
} \
} while (0)
-#define P9_DUMP_PKT(way, pdu) p9pdu_dump(way, pdu)
-
#else
#define P9_DPRINTK(level, format, arg...) do { } while (0)
-#define P9_DUMP_PKT(way, pdu) do { } while (0)
#endif
@@ -288,6 +285,35 @@ enum p9_perm_t {
P9_DMSETVTX = 0x00010000,
};
+/* 9p2000.L open flags */
+#define P9_DOTL_RDONLY 00000000
+#define P9_DOTL_WRONLY 00000001
+#define P9_DOTL_RDWR 00000002
+#define P9_DOTL_NOACCESS 00000003
+#define P9_DOTL_CREATE 00000100
+#define P9_DOTL_EXCL 00000200
+#define P9_DOTL_NOCTTY 00000400
+#define P9_DOTL_TRUNC 00001000
+#define P9_DOTL_APPEND 00002000
+#define P9_DOTL_NONBLOCK 00004000
+#define P9_DOTL_DSYNC 00010000
+#define P9_DOTL_FASYNC 00020000
+#define P9_DOTL_DIRECT 00040000
+#define P9_DOTL_LARGEFILE 00100000
+#define P9_DOTL_DIRECTORY 00200000
+#define P9_DOTL_NOFOLLOW 00400000
+#define P9_DOTL_NOATIME 01000000
+#define P9_DOTL_CLOEXEC 02000000
+#define P9_DOTL_SYNC 04000000
+
+/* 9p2000.L at flags */
+#define P9_DOTL_AT_REMOVEDIR 0x200
+
+/* 9p2000.L lock type */
+#define P9_LOCK_TYPE_RDLCK 0
+#define P9_LOCK_TYPE_WRLCK 1
+#define P9_LOCK_TYPE_UNLCK 2
+
/**
* enum p9_qid_t - QID types
* @P9_QTDIR: directory
@@ -330,6 +356,9 @@ enum p9_qid_t {
/* Room for readdir header */
#define P9_READDIRHDRSZ 24
+/* size of header for zero copy read/write */
+#define P9_ZC_HDR_SZ 4096
+
/**
* struct p9_qid - file system entity information
* @type: 8-bit type &p9_qid_t
@@ -526,10 +555,6 @@ struct p9_rstatfs {
* @tag: transaction id of the request
* @offset: used by marshalling routines to track current position in buffer
* @capacity: used by marshalling routines to track total malloc'd capacity
- * @pubuf: Payload user buffer given by the caller
- * @pkbuf: Payload kernel buffer given by the caller
- * @pbuf_size: pubuf/pkbuf(only one will be !NULL) size to be read/write.
- * @private: For transport layer's use.
* @sdata: payload
*
* &p9_fcall represents the structure for all 9P RPC
@@ -546,10 +571,6 @@ struct p9_fcall {
size_t offset;
size_t capacity;
- char __user *pubuf;
- char *pkbuf;
- size_t pbuf_size;
- void *private;
u8 *sdata;
};
diff --git a/include/net/9p/client.h b/include/net/9p/client.h
index 55ce72ce9861..fc9b90b0c052 100644
--- a/include/net/9p/client.h
+++ b/include/net/9p/client.h
@@ -151,7 +151,7 @@ struct p9_req_t {
struct p9_client {
spinlock_t lock; /* protect client structure */
- int msize;
+ unsigned int msize;
unsigned char proto_version;
struct p9_trans_module *trans_mod;
enum p9_trans_status status;
@@ -240,8 +240,8 @@ int p9_client_read(struct p9_fid *fid, char *data, char __user *udata,
int p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
u64 offset, u32 count);
int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset);
-int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,
- int proto_version);
+int p9dirent_read(struct p9_client *clnt, char *buf, int len,
+ struct p9_dirent *dirent);
struct p9_wstat *p9_client_stat(struct p9_fid *fid);
int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst);
int p9_client_setattr(struct p9_fid *fid, struct p9_iattr_dotl *attr);
@@ -259,7 +259,7 @@ struct p9_req_t *p9_tag_lookup(struct p9_client *, u16);
void p9_client_cb(struct p9_client *c, struct p9_req_t *req);
int p9_parse_header(struct p9_fcall *, int32_t *, int8_t *, int16_t *, int);
-int p9stat_read(char *, int, struct p9_wstat *, int);
+int p9stat_read(struct p9_client *, char *, int, struct p9_wstat *);
void p9stat_free(struct p9_wstat *);
int p9_is_proto_dotu(struct p9_client *clnt);
diff --git a/include/net/9p/transport.h b/include/net/9p/transport.h
index 83531ebeee99..adcbb20f6511 100644
--- a/include/net/9p/transport.h
+++ b/include/net/9p/transport.h
@@ -26,13 +26,6 @@
#ifndef NET_9P_TRANSPORT_H
#define NET_9P_TRANSPORT_H
-#define P9_TRANS_PREF_PAYLOAD_MASK 0x1
-
-/* Default. Add Payload to PDU before sending it down to transport layer */
-#define P9_TRANS_PREF_PAYLOAD_DEF 0x0
-/* Send pay load separately to transport layer along with PDU.*/
-#define P9_TRANS_PREF_PAYLOAD_SEP 0x1
-
/**
* struct p9_trans_module - transport module interface
* @list: used to maintain a list of currently available transports
@@ -56,13 +49,14 @@ struct p9_trans_module {
struct list_head list;
char *name; /* name of transport */
int maxsize; /* max message size of transport */
- int pref; /* Preferences of this transport */
int def; /* this transport should be default */
struct module *owner;
int (*create)(struct p9_client *, const char *, char *);
void (*close) (struct p9_client *);
int (*request) (struct p9_client *, struct p9_req_t *req);
int (*cancel) (struct p9_client *, struct p9_req_t *req);
+ int (*zc_request)(struct p9_client *, struct p9_req_t *,
+ char *, char *, int , int, int, int);
};
void v9fs_register_trans(struct p9_trans_module *m);
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index 582e4ae70753..cbc6bb0a6838 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -8,7 +8,7 @@
#define TEMP_VALID_LIFETIME (7*86400)
#define TEMP_PREFERRED_LIFETIME (86400)
-#define REGEN_MAX_RETRY (5)
+#define REGEN_MAX_RETRY (3)
#define MAX_DESYNC_FACTOR (600)
#define ADDR_CHECK_FREQUENCY (120*HZ)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index be30aabe7b88..aaf79af72432 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -716,6 +716,16 @@ struct hci_rp_read_bd_addr {
bdaddr_t bdaddr;
} __packed;
+#define HCI_OP_WRITE_PAGE_SCAN_ACTIVITY 0x0c1c
+struct hci_cp_write_page_scan_activity {
+ __le16 interval;
+ __le16 window;
+} __packed;
+
+#define HCI_OP_WRITE_PAGE_SCAN_TYPE 0x0c47
+ #define PAGE_SCAN_TYPE_STANDARD 0x00
+ #define PAGE_SCAN_TYPE_INTERLACED 0x01
+
#define HCI_OP_LE_SET_EVENT_MASK 0x2001
struct hci_cp_le_set_event_mask {
__u8 mask[8];
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 8f441b8b2963..5b924423cf20 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -195,8 +195,6 @@ struct hci_dev {
__u16 init_last_cmd;
- struct crypto_blkcipher *tfm;
-
struct inquiry_cache inq_cache;
struct hci_conn_hash conn_hash;
struct list_head blacklist;
@@ -348,6 +346,7 @@ enum {
HCI_CONN_RSWITCH_PEND,
HCI_CONN_MODE_CHANGE_PEND,
HCI_CONN_SCO_SETUP_PEND,
+ HCI_CONN_LE_SMP_PEND,
};
static inline void hci_conn_hash_init(struct hci_dev *hdev)
@@ -395,6 +394,22 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
}
}
+static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type)
+{
+ struct hci_conn_hash *h = &hdev->conn_hash;
+ switch (type) {
+ case ACL_LINK:
+ return h->acl_num;
+ case LE_LINK:
+ return h->le_num;
+ case SCO_LINK:
+ case ESCO_LINK:
+ return h->sco_num;
+ default:
+ return 0;
+ }
+}
+
static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
__u16 handle)
{
@@ -475,7 +490,7 @@ static inline void hci_conn_put(struct hci_conn *conn)
{
if (atomic_dec_and_test(&conn->refcnt)) {
unsigned long timeo;
- if (conn->type == ACL_LINK) {
+ if (conn->type == ACL_LINK || conn->type == LE_LINK) {
del_timer(&conn->idle_timer);
if (conn->state == BT_CONNECTED) {
timeo = msecs_to_jiffies(conn->disc_timeout);
@@ -838,7 +853,7 @@ int mgmt_powered(u16 index, u8 powered);
int mgmt_discoverable(u16 index, u8 discoverable);
int mgmt_connectable(u16 index, u8 connectable);
int mgmt_new_key(u16 index, struct link_key *key, u8 persistent);
-int mgmt_connected(u16 index, bdaddr_t *bdaddr);
+int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type);
int mgmt_disconnected(u16 index, bdaddr_t *bdaddr);
int mgmt_disconnect_failed(u16 index);
int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
@@ -858,6 +873,8 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
u8 *eir);
int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name);
int mgmt_discovering(u16 index, u8 discovering);
+int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr);
+int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr);
/* HCI info for socket */
#define hci_pi(sk) ((struct hci_pinfo *) sk)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 4f34ad25e75c..ab90ae0970a6 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -354,8 +354,8 @@ struct l2cap_chan {
__u8 retry_count;
__u8 num_acked;
__u16 sdu_len;
- __u16 partial_sdu_len;
struct sk_buff *sdu;
+ struct sk_buff *sdu_last_frag;
__u8 remote_tx_win;
__u8 remote_max_tx;
@@ -409,14 +409,8 @@ struct l2cap_conn {
__u8 disc_reason;
- __u8 preq[7]; /* SMP Pairing Request */
- __u8 prsp[7]; /* SMP Pairing Response */
- __u8 prnd[16]; /* SMP Pairing Random */
- __u8 pcnf[16]; /* SMP Pairing Confirm */
- __u8 tk[16]; /* SMP Temporary Key */
- __u8 smp_key_size;
-
struct timer_list security_timer;
+ struct smp_chan *smp_chan;
struct list_head chan_l;
rwlock_t chan_lock;
@@ -454,7 +448,6 @@ enum {
#define L2CAP_CONF_MAX_CONF_RSP 2
enum {
- CONN_SAR_SDU,
CONN_SREJ_SENT,
CONN_WAIT_F,
CONN_SREJ_ACT,
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 5428fd32ccec..d66da0f94f95 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -211,6 +211,11 @@ struct mgmt_cp_unblock_device {
bdaddr_t bdaddr;
} __packed;
+#define MGMT_OP_SET_FAST_CONNECTABLE 0x001F
+struct mgmt_cp_set_fast_connectable {
+ __u8 enable;
+} __packed;
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
@@ -249,6 +254,7 @@ struct mgmt_ev_new_key {
#define MGMT_EV_CONNECTED 0x000B
struct mgmt_ev_connected {
bdaddr_t bdaddr;
+ __u8 link_type;
} __packed;
#define MGMT_EV_DISCONNECTED 0x000C
@@ -301,3 +307,13 @@ struct mgmt_ev_remote_name {
} __packed;
#define MGMT_EV_DISCOVERING 0x0014
+
+#define MGMT_EV_DEVICE_BLOCKED 0x0015
+struct mgmt_ev_device_blocked {
+ bdaddr_t bdaddr;
+} __packed;
+
+#define MGMT_EV_DEVICE_UNBLOCKED 0x0016
+struct mgmt_ev_device_unblocked {
+ bdaddr_t bdaddr;
+} __packed;
diff --git a/include/net/bluetooth/smp.h b/include/net/bluetooth/smp.h
index 46c457612300..15b97d549441 100644
--- a/include/net/bluetooth/smp.h
+++ b/include/net/bluetooth/smp.h
@@ -115,9 +115,26 @@ struct smp_cmd_security_req {
#define SMP_MIN_ENC_KEY_SIZE 7
#define SMP_MAX_ENC_KEY_SIZE 16
+struct smp_chan {
+ struct l2cap_conn *conn;
+ u8 preq[7]; /* SMP Pairing Request */
+ u8 prsp[7]; /* SMP Pairing Response */
+ u8 prnd[16]; /* SMP Pairing Random (local) */
+ u8 rrnd[16]; /* SMP Pairing Random (remote) */
+ u8 pcnf[16]; /* SMP Pairing Confirm */
+ u8 tk[16]; /* SMP Temporary Key */
+ u8 smp_key_size;
+ struct crypto_blkcipher *tfm;
+ struct work_struct confirm;
+ struct work_struct random;
+
+};
+
/* SMP Commands */
int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level);
int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb);
int smp_distribute_keys(struct l2cap_conn *conn, __u8 force);
+void smp_chan_destroy(struct l2cap_conn *conn);
+
#endif /* __SMP_H */
diff --git a/include/net/caif/caif_hsi.h b/include/net/caif/caif_hsi.h
index c5dedd87b4cb..8d552519ff67 100644
--- a/include/net/caif/caif_hsi.h
+++ b/include/net/caif/caif_hsi.h
@@ -52,8 +52,9 @@ struct cfhsi_desc {
/*
* Maximum bytes transferred in one transfer.
*/
-/* TODO: 4096 is temporary... */
-#define CFHSI_MAX_PAYLOAD_SZ (CFHSI_MAX_PKTS * 4096)
+#define CFHSI_MAX_CAIF_FRAME_SZ 4096
+
+#define CFHSI_MAX_PAYLOAD_SZ (CFHSI_MAX_PKTS * CFHSI_MAX_CAIF_FRAME_SZ)
/* Size of the complete HSI TX buffer. */
#define CFHSI_BUF_SZ_TX (CFHSI_DESC_SZ + CFHSI_MAX_PAYLOAD_SZ)
@@ -75,18 +76,21 @@ struct cfhsi_desc {
#define CFHSI_WAKE_UP_ACK 1
#define CFHSI_WAKE_DOWN_ACK 2
#define CFHSI_AWAKE 3
-#define CFHSI_PENDING_RX 4
-#define CFHSI_SHUTDOWN 6
-#define CFHSI_FLUSH_FIFO 7
+#define CFHSI_WAKELOCK_HELD 4
+#define CFHSI_SHUTDOWN 5
+#define CFHSI_FLUSH_FIFO 6
#ifndef CFHSI_INACTIVITY_TOUT
#define CFHSI_INACTIVITY_TOUT (1 * HZ)
#endif /* CFHSI_INACTIVITY_TOUT */
-#ifndef CFHSI_WAKEUP_TOUT
-#define CFHSI_WAKEUP_TOUT (3 * HZ)
-#endif /* CFHSI_WAKEUP_TOUT */
+#ifndef CFHSI_WAKE_TOUT
+#define CFHSI_WAKE_TOUT (3 * HZ)
+#endif /* CFHSI_WAKE_TOUT */
+#ifndef CFHSI_MAX_RX_RETRIES
+#define CFHSI_MAX_RX_RETRIES (10 * HZ)
+#endif
/* Structure implemented by the CAIF HSI driver. */
struct cfhsi_drv {
@@ -104,11 +108,21 @@ struct cfhsi_dev {
int (*cfhsi_rx) (u8 *ptr, int len, struct cfhsi_dev *dev);
int (*cfhsi_wake_up) (struct cfhsi_dev *dev);
int (*cfhsi_wake_down) (struct cfhsi_dev *dev);
+ int (*cfhsi_get_peer_wake) (struct cfhsi_dev *dev, bool *status);
int (*cfhsi_fifo_occupancy)(struct cfhsi_dev *dev, size_t *occupancy);
int (*cfhsi_rx_cancel)(struct cfhsi_dev *dev);
struct cfhsi_drv *drv;
};
+/* Structure holds status of received CAIF frames processing */
+struct cfhsi_rx_state {
+ int state;
+ int nfrms;
+ int pld_len;
+ int retries;
+ bool piggy_desc;
+};
+
/* Structure implemented by CAIF HSI drivers. */
struct cfhsi {
struct caif_dev_common cfdev;
@@ -118,7 +132,8 @@ struct cfhsi {
struct cfhsi_drv drv;
struct cfhsi_dev *dev;
int tx_state;
- int rx_state;
+ struct cfhsi_rx_state rx_state;
+ unsigned long inactivity_timeout;
int rx_len;
u8 *rx_ptr;
u8 *tx_buf;
@@ -130,13 +145,13 @@ struct cfhsi {
struct list_head list;
struct work_struct wake_up_work;
struct work_struct wake_down_work;
- struct work_struct rx_done_work;
- struct work_struct tx_done_work;
+ struct work_struct out_of_sync_work;
struct workqueue_struct *wq;
wait_queue_head_t wake_up_wait;
wait_queue_head_t wake_down_wait;
wait_queue_head_t flush_fifo_wait;
struct timer_list timer;
+ struct timer_list rx_slowpath_timer;
unsigned long bits;
};
diff --git a/include/net/cfg80211-wext.h b/include/net/cfg80211-wext.h
new file mode 100644
index 000000000000..25baddc4fbed
--- /dev/null
+++ b/include/net/cfg80211-wext.h
@@ -0,0 +1,55 @@
+#ifndef __NET_CFG80211_WEXT_H
+#define __NET_CFG80211_WEXT_H
+/*
+ * 802.11 device and configuration interface -- wext handlers
+ *
+ * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+
+/*
+ * Temporary wext handlers & helper functions
+ *
+ * These are used only by drivers that aren't yet fully
+ * converted to cfg80211.
+ */
+int cfg80211_wext_giwname(struct net_device *dev,
+ struct iw_request_info *info,
+ char *name, char *extra);
+int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
+ u32 *mode, char *extra);
+int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
+ u32 *mode, char *extra);
+int cfg80211_wext_siwscan(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra);
+int cfg80211_wext_giwscan(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra);
+int cfg80211_wext_giwrange(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra);
+int cfg80211_wext_siwrts(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rts, char *extra);
+int cfg80211_wext_giwrts(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rts, char *extra);
+int cfg80211_wext_siwfrag(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *frag, char *extra);
+int cfg80211_wext_giwfrag(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *frag, char *extra);
+int cfg80211_wext_giwretry(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *retry, char *extra);
+
+#endif /* __NET_CFG80211_WEXT_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index d17f47fc9e31..92cf1c2c30c9 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -20,11 +20,6 @@
#include <linux/ieee80211.h>
#include <net/regulatory.h>
-/* remove once we remove the wext stuff */
-#include <net/iw_handler.h>
-#include <linux/wireless.h>
-
-
/**
* DOC: Introduction
*
@@ -339,6 +334,36 @@ struct survey_info {
};
/**
+ * struct cfg80211_crypto_settings - Crypto settings
+ * @wpa_versions: indicates which, if any, WPA versions are enabled
+ * (from enum nl80211_wpa_versions)
+ * @cipher_group: group key cipher suite (or 0 if unset)
+ * @n_ciphers_pairwise: number of AP supported unicast ciphers
+ * @ciphers_pairwise: unicast key cipher suites
+ * @n_akm_suites: number of AKM suites
+ * @akm_suites: AKM suites
+ * @control_port: Whether user space controls IEEE 802.1X port, i.e.,
+ * sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
+ * required to assume that the port is unauthorized until authorized by
+ * user space. Otherwise, port is marked authorized by default.
+ * @control_port_ethertype: the control port protocol that should be
+ * allowed through even on unauthorized ports
+ * @control_port_no_encrypt: TRUE to prevent encryption of control port
+ * protocol frames.
+ */
+struct cfg80211_crypto_settings {
+ u32 wpa_versions;
+ u32 cipher_group;
+ int n_ciphers_pairwise;
+ u32 ciphers_pairwise[NL80211_MAX_NR_CIPHER_SUITES];
+ int n_akm_suites;
+ u32 akm_suites[NL80211_MAX_NR_AKM_SUITES];
+ bool control_port;
+ __be16 control_port_ethertype;
+ bool control_port_no_encrypt;
+};
+
+/**
* struct beacon_parameters - beacon parameters
*
* Used to configure the beacon for an interface.
@@ -351,11 +376,38 @@ struct survey_info {
* @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
+ * frames or %NULL
+ * @proberesp_ies_len: length of proberesp_ies in octets
+ * @assocresp_ies: extra information element(s) to add into (Re)Association
+ * Response frames or %NULL
+ * @assocresp_ies_len: length of assocresp_ies in octets
*/
struct beacon_parameters {
u8 *head, *tail;
int interval, dtim_period;
int head_len, tail_len;
+ 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;
};
/**
@@ -372,6 +424,17 @@ enum plink_actions {
};
/**
+ * enum station_parameters_apply_mask - station parameter values to apply
+ * @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp)
+ *
+ * Not all station parameters have in-band "no change" signalling,
+ * for those that don't these flags will are used.
+ */
+enum station_parameters_apply_mask {
+ STATION_PARAM_APPLY_UAPSD = BIT(0),
+};
+
+/**
* struct station_parameters - station parameters
*
* Used to change and create a new station.
@@ -389,17 +452,24 @@ enum plink_actions {
* @plink_action: plink action to take
* @plink_state: set the peer link state for a station
* @ht_capa: HT capabilities of station
+ * @uapsd_queues: bitmap of queues configured for uapsd. same format
+ * as the AC bitmap in the QoS info field
+ * @max_sp: max Service Period. same format as the MAX_SP in the
+ * QoS info field (but already shifted down)
*/
struct station_parameters {
u8 *supported_rates;
struct net_device *vlan;
u32 sta_flags_mask, sta_flags_set;
+ u32 sta_modify_mask;
int listen_interval;
u16 aid;
u8 supported_rates_len;
u8 plink_action;
u8 plink_state;
struct ieee80211_ht_cap *ht_capa;
+ u8 uapsd_queues;
+ u8 max_sp;
};
/**
@@ -426,6 +496,8 @@ struct station_parameters {
* @STATION_INFO_RX_BITRATE: @rxrate fields are filled
* @STATION_INFO_BSS_PARAM: @bss_param filled
* @STATION_INFO_CONNECTED_TIME: @connected_time filled
+ * @STATION_INFO_ASSOC_REQ_IES: @assoc_req_ies filled
+ * @STATION_INFO_STA_FLAGS: @sta_flags filled
*/
enum station_info_flags {
STATION_INFO_INACTIVE_TIME = 1<<0,
@@ -444,7 +516,9 @@ enum station_info_flags {
STATION_INFO_SIGNAL_AVG = 1<<13,
STATION_INFO_RX_BITRATE = 1<<14,
STATION_INFO_BSS_PARAM = 1<<15,
- STATION_INFO_CONNECTED_TIME = 1<<16
+ STATION_INFO_CONNECTED_TIME = 1<<16,
+ STATION_INFO_ASSOC_REQ_IES = 1<<17,
+ STATION_INFO_STA_FLAGS = 1<<18
};
/**
@@ -536,6 +610,11 @@ struct sta_bss_parameters {
* This number should increase every time the list of stations
* changes, i.e. when a station is added or removed, so that
* userspace can tell whether it got a consistent snapshot.
+ * @assoc_req_ies: IEs from (Re)Association Request.
+ * This is used only when in AP mode with drivers that do not use
+ * user space MLME/SME implementation. The information is provided for
+ * the cfg80211_new_sta() calls to notify user space of the IEs.
+ * @assoc_req_ies_len: Length of assoc_req_ies buffer in octets.
*/
struct station_info {
u32 filled;
@@ -556,8 +635,17 @@ struct station_info {
u32 tx_failed;
u32 rx_dropped_misc;
struct sta_bss_parameters bss_param;
+ struct nl80211_sta_flag_update sta_flags;
int generation;
+
+ const u8 *assoc_req_ies;
+ size_t assoc_req_ies_len;
+
+ /*
+ * Note: Add a new enum station_info_flags value for each new field and
+ * use it to check which fields are initialized.
+ */
};
/**
@@ -688,6 +776,12 @@ struct mesh_config {
u16 dot11MeshHWMPpreqMinInterval;
u16 dot11MeshHWMPnetDiameterTraversalTime;
u8 dot11MeshHWMPRootMode;
+ u16 dot11MeshHWMPRannInterval;
+ /* This is missnamed in draft 12.0: dot11MeshGateAnnouncementProtocol
+ * set to true only means that the station will announce others it's a
+ * mesh gate, but not necessarily using the gate announcement protocol.
+ * Still keeping the same nomenclature to be in sync with the spec. */
+ bool dot11MeshGateAnnouncementProtocol;
};
/**
@@ -781,6 +875,7 @@ struct cfg80211_ssid {
* @wiphy: the wiphy this was for
* @dev: the interface
* @aborted: (internal) scan request was notified as aborted
+ * @no_cck: used to send probe requests at non CCK rate in 2GHz band
*/
struct cfg80211_scan_request {
struct cfg80211_ssid *ssids;
@@ -795,12 +890,22 @@ struct cfg80211_scan_request {
struct wiphy *wiphy;
struct net_device *dev;
bool aborted;
+ bool no_cck;
/* keep last */
struct ieee80211_channel *channels[0];
};
/**
+ * struct cfg80211_match_set - sets of attributes to match
+ *
+ * @ssid: SSID to be matched
+ */
+struct cfg80211_match_set {
+ struct cfg80211_ssid ssid;
+};
+
+/**
* struct cfg80211_sched_scan_request - scheduled scan request description
*
* @ssids: SSIDs to scan for (passed in the probe_reqs in active scans)
@@ -809,6 +914,11 @@ struct cfg80211_scan_request {
* @interval: interval between each scheduled scan cycle
* @ie: optional information element(s) to add into Probe Request or %NULL
* @ie_len: length of ie in octets
+ * @match_sets: sets of parameters to be matched for a scan result
+ * entry to be considered valid and to be passed to the host
+ * (others are filtered out).
+ * If ommited, all results are passed.
+ * @n_match_sets: number of match sets
* @wiphy: the wiphy this was for
* @dev: the interface
* @channels: channels to scan
@@ -820,6 +930,8 @@ struct cfg80211_sched_scan_request {
u32 interval;
const u8 *ie;
size_t ie_len;
+ struct cfg80211_match_set *match_sets;
+ int n_match_sets;
/* internal */
struct wiphy *wiphy;
@@ -896,36 +1008,6 @@ const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie);
/**
- * struct cfg80211_crypto_settings - Crypto settings
- * @wpa_versions: indicates which, if any, WPA versions are enabled
- * (from enum nl80211_wpa_versions)
- * @cipher_group: group key cipher suite (or 0 if unset)
- * @n_ciphers_pairwise: number of AP supported unicast ciphers
- * @ciphers_pairwise: unicast key cipher suites
- * @n_akm_suites: number of AKM suites
- * @akm_suites: AKM suites
- * @control_port: Whether user space controls IEEE 802.1X port, i.e.,
- * sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
- * required to assume that the port is unauthorized until authorized by
- * user space. Otherwise, port is marked authorized by default.
- * @control_port_ethertype: the control port protocol that should be
- * allowed through even on unauthorized ports
- * @control_port_no_encrypt: TRUE to prevent encryption of control port
- * protocol frames.
- */
-struct cfg80211_crypto_settings {
- u32 wpa_versions;
- u32 cipher_group;
- int n_ciphers_pairwise;
- u32 ciphers_pairwise[NL80211_MAX_NR_CIPHER_SUITES];
- int n_akm_suites;
- u32 akm_suites[NL80211_MAX_NR_AKM_SUITES];
- bool control_port;
- __be16 control_port_ethertype;
- bool control_port_no_encrypt;
-};
-
-/**
* struct cfg80211_auth_request - Authentication request data
*
* This structure provides information needed to complete IEEE 802.11
@@ -1343,6 +1425,9 @@ struct cfg80211_gtk_rekey_data {
* @set_ringparam: Set tx and rx ring sizes.
*
* @get_ringparam: Get tx and rx ring current and maximum sizes.
+ *
+ * @tdls_mgmt: Transmit a TDLS management frame.
+ * @tdls_oper: Perform a high-level TDLS operation (e.g. TDLS link setup).
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -1419,7 +1504,7 @@ struct cfg80211_ops {
int (*change_bss)(struct wiphy *wiphy, struct net_device *dev,
struct bss_parameters *params);
- int (*set_txq_params)(struct wiphy *wiphy,
+ int (*set_txq_params)(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_txq_params *params);
int (*set_channel)(struct wiphy *wiphy, struct net_device *dev,
@@ -1495,7 +1580,8 @@ struct cfg80211_ops {
struct ieee80211_channel *chan, bool offchan,
enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait,
- const u8 *buf, size_t len, u64 *cookie);
+ const u8 *buf, size_t len, bool no_cck,
+ u64 *cookie);
int (*mgmt_tx_cancel_wait)(struct wiphy *wiphy,
struct net_device *dev,
u64 cookie);
@@ -1525,6 +1611,12 @@ struct cfg80211_ops {
int (*set_rekey_data)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_gtk_rekey_data *data);
+
+ int (*tdls_mgmt)(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, u8 action_code, u8 dialog_token,
+ u16 status_code, const u8 *buf, size_t len);
+ int (*tdls_oper)(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, enum nl80211_tdls_operation oper);
};
/*
@@ -1574,6 +1666,15 @@ struct cfg80211_ops {
* @WIPHY_FLAG_MESH_AUTH: The device supports mesh authentication by routing
* auth frames to userspace. See @NL80211_MESH_SETUP_USERSPACE_AUTH.
* @WIPHY_FLAG_SUPPORTS_SCHED_SCAN: The device supports scheduled scans.
+ * @WIPHY_FLAG_SUPPORTS_FW_ROAM: The device supports roaming feature in the
+ * firmware.
+ * @WIPHY_FLAG_AP_UAPSD: The device supports uapsd on AP.
+ * @WIPHY_FLAG_SUPPORTS_TDLS: The device supports TDLS (802.11z) operation.
+ * @WIPHY_FLAG_TDLS_EXTERNAL_SETUP: The device does not handle TDLS (802.11z)
+ * link setup/discovery operations internally. Setup, discovery and
+ * teardown packets should be sent through the @NL80211_CMD_TDLS_MGMT
+ * command. When this flag is not set, @NL80211_CMD_TDLS_OPER should be
+ * used for asking the driver/firmware to perform a TDLS operation.
*/
enum wiphy_flags {
WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
@@ -1588,6 +1689,10 @@ enum wiphy_flags {
WIPHY_FLAG_MESH_AUTH = BIT(10),
WIPHY_FLAG_SUPPORTS_SCHED_SCAN = BIT(11),
WIPHY_FLAG_ENFORCE_COMBINATIONS = BIT(12),
+ WIPHY_FLAG_SUPPORTS_FW_ROAM = BIT(13),
+ WIPHY_FLAG_AP_UAPSD = BIT(14),
+ WIPHY_FLAG_SUPPORTS_TDLS = BIT(15),
+ WIPHY_FLAG_TDLS_EXTERNAL_SETUP = BIT(16),
};
/**
@@ -1744,9 +1849,12 @@ struct wiphy_wowlan_support {
* by default for perm_addr. In this case, the mask should be set to
* all-zeroes. In this case it is assumed that the device can handle
* the same number of arbitrary MAC addresses.
+ * @registered: protects ->resume and ->suspend sysfs callbacks against
+ * unregister hardware
* @debugfsdir: debugfs directory used for this wiphy, will be renamed
* automatically on wiphy renames
* @dev: (virtual) struct device for this wiphy
+ * @registered: helps synchronize suspend/resume with wiphy unregister
* @wext: wireless extension handlers
* @priv: driver private data (sized according to wiphy_new() parameter)
* @interface_modes: bitmask of interfaces types valid for this wiphy,
@@ -1763,6 +1871,9 @@ struct wiphy_wowlan_support {
* any given scan
* @max_sched_scan_ssids: maximum number of SSIDs the device can scan
* for in any given scheduled scan
+ * @max_match_sets: maximum number of match sets the device can handle
+ * when performing a scheduled scan, 0 if filtering is not
+ * supported.
* @max_scan_ie_len: maximum length of user-controlled IEs device can
* add to probe request frames transmitted during a scan, must not
* include fixed IEs like supported rates
@@ -1820,6 +1931,7 @@ struct wiphy {
int bss_priv_size;
u8 max_scan_ssids;
u8 max_sched_scan_ssids;
+ u8 max_match_sets;
u16 max_scan_ie_len;
u16 max_sched_scan_ie_len;
@@ -1865,6 +1977,9 @@ struct wiphy {
* you need use set_wiphy_dev() (see below) */
struct device dev;
+ /* protects ->resume, ->suspend sysfs callbacks against unregister hw */
+ bool registered;
+
/* dir in debugfs: ieee80211/<wiphyname> */
struct dentry *debugfsdir;
@@ -2230,6 +2345,69 @@ extern int ieee80211_radiotap_iterator_next(
extern const unsigned char rfc1042_header[6];
extern const unsigned char bridge_tunnel_header[6];
+/* Parsed Information Elements */
+struct ieee802_11_elems {
+ u8 *ie_start;
+ size_t total_len;
+
+ /* pointers to IEs */
+ u8 *ssid;
+ u8 *supp_rates;
+ u8 *fh_params;
+ u8 *ds_params;
+ u8 *cf_params;
+ struct ieee80211_tim_ie *tim;
+ u8 *ibss_params;
+ u8 *challenge;
+ u8 *wpa;
+ u8 *rsn;
+ u8 *erp_info;
+ u8 *ext_supp_rates;
+ u8 *wmm_info;
+ u8 *wmm_param;
+ struct ieee80211_ht_cap *ht_cap_elem;
+ struct ieee80211_ht_info *ht_info_elem;
+ struct ieee80211_meshconf_ie *mesh_config;
+ u8 *mesh_id;
+ u8 *peering;
+ u8 *preq;
+ u8 *prep;
+ u8 *perr;
+ struct ieee80211_rann_ie *rann;
+ u8 *ch_switch_elem;
+ u8 *country_elem;
+ u8 *pwr_constr_elem;
+ u8 *quiet_elem; /* first quite element */
+ u8 *timeout_int;
+
+ /* length of them, respectively */
+ u8 ssid_len;
+ u8 supp_rates_len;
+ u8 fh_params_len;
+ u8 ds_params_len;
+ u8 cf_params_len;
+ u8 tim_len;
+ u8 ibss_params_len;
+ u8 challenge_len;
+ u8 wpa_len;
+ u8 rsn_len;
+ u8 erp_info_len;
+ u8 ext_supp_rates_len;
+ u8 wmm_info_len;
+ u8 wmm_param_len;
+ u8 mesh_id_len;
+ u8 peering_len;
+ u8 preq_len;
+ u8 prep_len;
+ u8 perr_len;
+ u8 ch_switch_elem_len;
+ u8 country_elem_len;
+ u8 pwr_constr_elem_len;
+ u8 quiet_elem_len;
+ u8 num_of_quiet_elem; /* can be more the one */
+ u8 timeout_int_len;
+};
+
/**
* ieee80211_get_hdrlen_from_skb - get header length from data
*
@@ -2319,6 +2497,24 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb);
const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len);
/**
+ * cfg80211_find_vendor_ie - find vendor specific information element in data
+ *
+ * @oui: vendor OUI
+ * @oui_type: vendor-specific OUI type
+ * @ies: data consisting of IEs
+ * @len: length of data
+ *
+ * This function will return %NULL if the vendor specific element ID
+ * could not be found or if the element is invalid (claims to be
+ * longer than the given data), or a pointer to the first byte
+ * of the requested element, that is the byte containing the
+ * element ID. There are no checks on the element length
+ * other than having to fit into the given data.
+ */
+const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type,
+ const u8 *ies, int len);
+
+/**
* DOC: Regulatory enforcement infrastructure
*
* TODO
@@ -2393,113 +2589,6 @@ extern int freq_reg_info(struct wiphy *wiphy,
const struct ieee80211_reg_rule **reg_rule);
/*
- * Temporary wext handlers & helper functions
- *
- * In the future cfg80211 will simply assign the entire wext handler
- * structure to netdevs it manages, but we're not there yet.
- */
-int cfg80211_wext_giwname(struct net_device *dev,
- struct iw_request_info *info,
- char *name, char *extra);
-int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
- u32 *mode, char *extra);
-int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
- u32 *mode, char *extra);
-int cfg80211_wext_siwscan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-int cfg80211_wext_giwscan(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *extra);
-int cfg80211_wext_siwmlme(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *extra);
-int cfg80211_wext_giwrange(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *extra);
-int cfg80211_wext_siwgenie(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *extra);
-int cfg80211_wext_siwauth(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *data, char *extra);
-int cfg80211_wext_giwauth(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *data, char *extra);
-
-int cfg80211_wext_siwfreq(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_freq *freq, char *extra);
-int cfg80211_wext_giwfreq(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_freq *freq, char *extra);
-int cfg80211_wext_siwessid(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *ssid);
-int cfg80211_wext_giwessid(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *ssid);
-int cfg80211_wext_siwrate(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *rate, char *extra);
-int cfg80211_wext_giwrate(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *rate, char *extra);
-
-int cfg80211_wext_siwrts(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *rts, char *extra);
-int cfg80211_wext_giwrts(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *rts, char *extra);
-int cfg80211_wext_siwfrag(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *frag, char *extra);
-int cfg80211_wext_giwfrag(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *frag, char *extra);
-int cfg80211_wext_siwretry(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *retry, char *extra);
-int cfg80211_wext_giwretry(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *retry, char *extra);
-int cfg80211_wext_siwencodeext(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *extra);
-int cfg80211_wext_siwencode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *keybuf);
-int cfg80211_wext_giwencode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *keybuf);
-int cfg80211_wext_siwtxpower(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *data, char *keybuf);
-int cfg80211_wext_giwtxpower(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *data, char *keybuf);
-struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev);
-
-int cfg80211_wext_siwpower(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq, char *extra);
-int cfg80211_wext_giwpower(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq, char *extra);
-
-int cfg80211_wext_siwap(struct net_device *dev,
- struct iw_request_info *info,
- struct sockaddr *ap_addr, char *extra);
-int cfg80211_wext_giwap(struct net_device *dev,
- struct iw_request_info *info,
- struct sockaddr *ap_addr, char *extra);
-
-int cfg80211_wext_siwpmksa(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *extra);
-
-/*
* callbacks for asynchronous cfg80211 methods, notification
* functions and BSS handling helpers
*/
@@ -3085,6 +3174,17 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev,
void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
const u8 *replay_ctr, gfp_t gfp);
+/**
+ * cfg80211_pmksa_candidate_notify - notify about PMKSA caching candidate
+ * @dev: network device
+ * @index: candidate index (the smaller the index, the higher the priority)
+ * @bssid: BSSID of AP
+ * @preauth: Whether AP advertises support for RSN pre-authentication
+ * @gfp: allocation flags
+ */
+void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
+ const u8 *bssid, bool preauth, gfp_t gfp);
+
/* Logging, debugging and troubleshooting/diagnostic helpers. */
/* wiphy_printk helpers, similar to dev_printk */
diff --git a/include/net/dcbevent.h b/include/net/dcbevent.h
index bc1e7ef40171..443626ed4cbc 100644
--- a/include/net/dcbevent.h
+++ b/include/net/dcbevent.h
@@ -24,8 +24,26 @@ enum dcbevent_notif_type {
DCB_APP_EVENT = 1,
};
+#ifdef CONFIG_DCB
extern int register_dcbevent_notifier(struct notifier_block *nb);
extern int unregister_dcbevent_notifier(struct notifier_block *nb);
extern int call_dcbevent_notifiers(unsigned long val, void *v);
+#else
+static inline int
+register_dcbevent_notifier(struct notifier_block *nb)
+{
+ return 0;
+}
+
+static inline int unregister_dcbevent_notifier(struct notifier_block *nb)
+{
+ return 0;
+}
+
+static inline int call_dcbevent_notifiers(unsigned long val, void *v)
+{
+ return 0;
+}
+#endif /* CONFIG_DCB */
#endif
diff --git a/include/net/dcbnl.h b/include/net/dcbnl.h
index f5aa39997f0b..2cd66d0be348 100644
--- a/include/net/dcbnl.h
+++ b/include/net/dcbnl.h
@@ -23,9 +23,10 @@
#include <linux/dcbnl.h>
struct dcb_app_type {
- char name[IFNAMSIZ];
+ int ifindex;
struct dcb_app app;
struct list_head list;
+ u8 dcbx;
};
int dcb_setapp(struct net_device *, struct dcb_app *);
diff --git a/include/net/dst.h b/include/net/dst.h
index 13d507d69ddb..4fb6c4381791 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -325,7 +325,14 @@ static inline void skb_dst_force(struct sk_buff *skb)
static inline void __skb_tunnel_rx(struct sk_buff *skb, struct net_device *dev)
{
skb->dev = dev;
- skb->rxhash = 0;
+
+ /*
+ * Clear rxhash so that we can recalulate the hash for the
+ * encapsulated packet, unless we have already determine the hash
+ * over the L4 4-tuple.
+ */
+ if (!skb->l4_rxhash)
+ skb->rxhash = 0;
skb_set_queue_mapping(skb, 0);
skb_dst_drop(skb);
nf_reset(skb);
diff --git a/include/net/flow.h b/include/net/flow.h
index 78113daadd63..a09447749e2d 100644
--- a/include/net/flow.h
+++ b/include/net/flow.h
@@ -7,6 +7,7 @@
#ifndef _NET_FLOW_H
#define _NET_FLOW_H
+#include <linux/socket.h>
#include <linux/in6.h>
#include <linux/atomic.h>
@@ -68,7 +69,7 @@ struct flowi4 {
#define fl4_ipsec_spi uli.spi
#define fl4_mh_type uli.mht.type
#define fl4_gre_key uli.gre_key
-};
+} __attribute__((__aligned__(BITS_PER_LONG/8)));
static inline void flowi4_init_output(struct flowi4 *fl4, int oif,
__u32 mark, __u8 tos, __u8 scope,
@@ -112,7 +113,7 @@ struct flowi6 {
#define fl6_ipsec_spi uli.spi
#define fl6_mh_type uli.mht.type
#define fl6_gre_key uli.gre_key
-};
+} __attribute__((__aligned__(BITS_PER_LONG/8)));
struct flowidn {
struct flowi_common __fl_common;
@@ -127,7 +128,7 @@ struct flowidn {
union flowi_uli uli;
#define fld_sport uli.ports.sport
#define fld_dport uli.ports.dport
-};
+} __attribute__((__aligned__(BITS_PER_LONG/8)));
struct flowi {
union {
@@ -161,6 +162,24 @@ static inline struct flowi *flowidn_to_flowi(struct flowidn *fldn)
return container_of(fldn, struct flowi, u.dn);
}
+typedef unsigned long flow_compare_t;
+
+static inline size_t flow_key_size(u16 family)
+{
+ switch (family) {
+ case AF_INET:
+ BUILD_BUG_ON(sizeof(struct flowi4) % sizeof(flow_compare_t));
+ return sizeof(struct flowi4) / sizeof(flow_compare_t);
+ case AF_INET6:
+ BUILD_BUG_ON(sizeof(struct flowi6) % sizeof(flow_compare_t));
+ return sizeof(struct flowi6) / sizeof(flow_compare_t);
+ case AF_DECnet:
+ BUILD_BUG_ON(sizeof(struct flowidn) % sizeof(flow_compare_t));
+ return sizeof(struct flowidn) / sizeof(flow_compare_t);
+ }
+ return 0;
+}
+
#define FLOW_DIR_IN 0
#define FLOW_DIR_OUT 1
#define FLOW_DIR_FWD 2
diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h
index b0be5fb9de19..7e2c4d483ad0 100644
--- a/include/net/ieee80211_radiotap.h
+++ b/include/net/ieee80211_radiotap.h
@@ -251,6 +251,7 @@ enum ieee80211_radiotap_type {
* retries */
#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */
#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
+#define IEEE80211_RADIOTAP_F_TX_NOACK 0x0008 /* don't expect an ack */
/* For IEEE80211_RADIOTAP_MCS */
diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h
index 11cf373970a9..51a7031b4aa3 100644
--- a/include/net/if_inet6.h
+++ b/include/net/if_inet6.h
@@ -41,6 +41,7 @@ struct inet6_ifaddr {
struct in6_addr addr;
__u32 prefix_len;
+ /* In seconds, relative to tstamp. Expiry is at tstamp + HZ * lft. */
__u32 valid_lft;
__u32 prefered_lft;
atomic_t refcnt;
diff --git a/include/net/inet_ecn.h b/include/net/inet_ecn.h
index 2fa8d1341a0a..2fa14691869c 100644
--- a/include/net/inet_ecn.h
+++ b/include/net/inet_ecn.h
@@ -30,6 +30,14 @@ static inline int INET_ECN_is_capable(__u8 dsfield)
return dsfield & INET_ECN_ECT_0;
}
+/*
+ * RFC 3168 9.1.1
+ * The full-functionality option for ECN encapsulation is to copy the
+ * ECN codepoint of the inside header to the outside header on
+ * encapsulation if the inside header is not-ECT or ECT, and to set the
+ * ECN codepoint of the outside header to ECT(0) if the ECN codepoint of
+ * the inside header is CE.
+ */
static inline __u8 INET_ECN_encapsulate(__u8 outer, __u8 inner)
{
outer &= ~INET_ECN_MASK;
diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h
index f1a770977c4f..180231c5bbbe 100644
--- a/include/net/inet_timewait_sock.h
+++ b/include/net/inet_timewait_sock.h
@@ -126,7 +126,8 @@ struct inet_timewait_sock {
/* And these are ours. */
unsigned int tw_ipv6only : 1,
tw_transparent : 1,
- tw_pad : 14, /* 14 bits hole */
+ tw_pad : 6, /* 6 bits hole */
+ tw_tos : 8,
tw_ipv6_offset : 16;
kmemcheck_bitfield_end(flags);
unsigned long tw_ttd;
diff --git a/include/net/ip.h b/include/net/ip.h
index aa76c7a4d9c3..eca0ef7a495e 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -165,6 +165,7 @@ struct ip_reply_arg {
int csumoffset; /* u16 offset of csum in iov[0].iov_base */
/* -1 if not needed */
int bound_dev_if;
+ u8 tos;
};
#define IP_REPLY_ARG_NOSRCCHECK 1
@@ -175,7 +176,7 @@ static inline __u8 ip_reply_arg_flowi_flags(const struct ip_reply_arg *arg)
}
void ip_send_reply(struct sock *sk, struct sk_buff *skb, __be32 daddr,
- struct ip_reply_arg *arg, unsigned int len);
+ const struct ip_reply_arg *arg, unsigned int len);
struct ipv4_config {
int log_martians;
@@ -406,9 +407,18 @@ enum ip_defrag_users {
IP_DEFRAG_VS_OUT,
IP_DEFRAG_VS_FWD,
IP_DEFRAG_AF_PACKET,
+ IP_DEFRAG_MACVLAN,
};
int ip_defrag(struct sk_buff *skb, u32 user);
+#ifdef CONFIG_INET
+struct sk_buff *ip_check_defrag(struct sk_buff *skb, u32 user);
+#else
+static inline struct sk_buff *ip_check_defrag(struct sk_buff *skb, u32 user)
+{
+ return skb;
+}
+#endif
int ip_frag_mem(struct net *net);
int ip_frag_nqueues(struct net *net);
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 1aaf915656f3..8fa4430f99c1 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -900,6 +900,7 @@ struct netns_ipvs {
volatile int sync_state;
volatile int master_syncid;
volatile int backup_syncid;
+ struct mutex sync_mutex;
/* multicast interface name */
char master_mcast_ifn[IP_VS_IFNAME_MAXLEN];
char backup_mcast_ifn[IP_VS_IFNAME_MAXLEN];
diff --git a/include/net/iucv/af_iucv.h b/include/net/iucv/af_iucv.h
index f82a1e877372..f2419cf44cef 100644
--- a/include/net/iucv/af_iucv.h
+++ b/include/net/iucv/af_iucv.h
@@ -14,6 +14,7 @@
#include <linux/list.h>
#include <linux/poll.h>
#include <linux/socket.h>
+#include <net/iucv/iucv.h>
#ifndef AF_IUCV
#define AF_IUCV 32
@@ -33,6 +34,7 @@ enum {
};
#define IUCV_QUEUELEN_DEFAULT 65535
+#define IUCV_HIPER_MSGLIM_DEFAULT 128
#define IUCV_CONN_TIMEOUT (HZ * 40)
#define IUCV_DISCONN_TIMEOUT (HZ * 2)
#define IUCV_CONN_IDLE_TIMEOUT (HZ * 60)
@@ -57,8 +59,51 @@ struct sock_msg_q {
spinlock_t lock;
};
+#define AF_IUCV_FLAG_ACK 0x1
+#define AF_IUCV_FLAG_SYN 0x2
+#define AF_IUCV_FLAG_FIN 0x4
+#define AF_IUCV_FLAG_WIN 0x8
+
+struct af_iucv_trans_hdr {
+ u16 magic;
+ u8 version;
+ u8 flags;
+ u16 window;
+ char destNodeID[8];
+ char destUserID[8];
+ char destAppName[16];
+ char srcNodeID[8];
+ char srcUserID[8];
+ char srcAppName[16]; /* => 70 bytes */
+ struct iucv_message iucv_hdr; /* => 33 bytes */
+ u8 pad; /* total 104 bytes */
+} __packed;
+
+enum iucv_tx_notify {
+ /* transmission of skb is completed and was successful */
+ TX_NOTIFY_OK = 0,
+ /* target is unreachable */
+ TX_NOTIFY_UNREACHABLE = 1,
+ /* transfer pending queue full */
+ TX_NOTIFY_TPQFULL = 2,
+ /* general error */
+ TX_NOTIFY_GENERALERROR = 3,
+ /* transmission of skb is pending - may interleave
+ * with TX_NOTIFY_DELAYED_* */
+ TX_NOTIFY_PENDING = 4,
+ /* transmission of skb was done successfully (delayed) */
+ TX_NOTIFY_DELAYED_OK = 5,
+ /* target unreachable (detected delayed) */
+ TX_NOTIFY_DELAYED_UNREACHABLE = 6,
+ /* general error (detected delayed) */
+ TX_NOTIFY_DELAYED_GENERALERROR = 7,
+};
+
#define iucv_sk(__sk) ((struct iucv_sock *) __sk)
+#define AF_IUCV_TRANS_IUCV 0
+#define AF_IUCV_TRANS_HIPER 1
+
struct iucv_sock {
struct sock sk;
char src_user_id[8];
@@ -75,6 +120,13 @@ struct iucv_sock {
unsigned int send_tag;
u8 flags;
u16 msglimit;
+ u16 msglimit_peer;
+ atomic_t msg_sent;
+ atomic_t msg_recv;
+ atomic_t pendings;
+ int transport;
+ void (*sk_txnotify)(struct sk_buff *skb,
+ enum iucv_tx_notify n);
};
/* iucv socket options (SOL_IUCV) */
diff --git a/include/net/iucv/iucv.h b/include/net/iucv/iucv.h
index 1121baa9f695..0894ced31957 100644
--- a/include/net/iucv/iucv.h
+++ b/include/net/iucv/iucv.h
@@ -120,7 +120,7 @@ struct iucv_message {
u32 reply_size;
u8 rmmsg[8];
u8 flags;
-};
+} __packed;
/*
* struct iucv_handler
@@ -459,3 +459,37 @@ int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg,
u8 flags, u32 srccls, void *buffer, size_t size,
void *answer, size_t asize, size_t *residual);
+
+struct iucv_interface {
+ int (*message_receive)(struct iucv_path *path, struct iucv_message *msg,
+ u8 flags, void *buffer, size_t size, size_t *residual);
+ int (*__message_receive)(struct iucv_path *path,
+ struct iucv_message *msg, u8 flags, void *buffer, size_t size,
+ size_t *residual);
+ int (*message_reply)(struct iucv_path *path, struct iucv_message *msg,
+ u8 flags, void *reply, size_t size);
+ int (*message_reject)(struct iucv_path *path, struct iucv_message *msg);
+ int (*message_send)(struct iucv_path *path, struct iucv_message *msg,
+ u8 flags, u32 srccls, void *buffer, size_t size);
+ int (*__message_send)(struct iucv_path *path, struct iucv_message *msg,
+ u8 flags, u32 srccls, void *buffer, size_t size);
+ int (*message_send2way)(struct iucv_path *path,
+ struct iucv_message *msg, u8 flags, u32 srccls, void *buffer,
+ size_t size, void *answer, size_t asize, size_t *residual);
+ int (*message_purge)(struct iucv_path *path, struct iucv_message *msg,
+ u32 srccls);
+ int (*path_accept)(struct iucv_path *path, struct iucv_handler *handler,
+ u8 userdata[16], void *private);
+ int (*path_connect)(struct iucv_path *path,
+ struct iucv_handler *handler,
+ u8 userid[8], u8 system[8], u8 userdata[16], void *private);
+ int (*path_quiesce)(struct iucv_path *path, u8 userdata[16]);
+ int (*path_resume)(struct iucv_path *path, u8 userdata[16]);
+ int (*path_sever)(struct iucv_path *path, u8 userdata[16]);
+ int (*iucv_register)(struct iucv_handler *handler, int smp);
+ void (*iucv_unregister)(struct iucv_handler *handler, int smp);
+ struct bus_type *bus;
+ struct device *root;
+};
+
+extern struct iucv_interface iucv_if;
diff --git a/include/net/lapb.h b/include/net/lapb.h
index 96cb5ddaa9f1..fd2bf572ee1d 100644
--- a/include/net/lapb.h
+++ b/include/net/lapb.h
@@ -95,7 +95,7 @@ struct lapb_cb {
struct sk_buff_head write_queue;
struct sk_buff_head ack_queue;
unsigned char window;
- struct lapb_register_struct callbacks;
+ const struct lapb_register_struct *callbacks;
/* FRMR control information */
struct lapb_frame frmr_data;
diff --git a/include/net/lib80211.h b/include/net/lib80211.h
index b95bbb083ee8..2ec896bb72b2 100644
--- a/include/net/lib80211.h
+++ b/include/net/lib80211.h
@@ -117,10 +117,7 @@ void lib80211_crypt_info_free(struct lib80211_crypt_info *info);
int lib80211_register_crypto_ops(struct lib80211_crypto_ops *ops);
int lib80211_unregister_crypto_ops(struct lib80211_crypto_ops *ops);
struct lib80211_crypto_ops *lib80211_get_crypto_ops(const char *name);
-void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *, int);
-void lib80211_crypt_deinit_handler(unsigned long);
void lib80211_crypt_delayed_deinit(struct lib80211_crypt_info *info,
struct lib80211_crypt_data **crypt);
-void lib80211_crypt_quiescing(struct lib80211_crypt_info *info);
#endif /* LIB80211_H */
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 9259e97864d7..dc1123aa8181 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -16,7 +16,6 @@
#include <linux/kernel.h>
#include <linux/if_ether.h>
#include <linux/skbuff.h>
-#include <linux/wireless.h>
#include <linux/device.h>
#include <linux/ieee80211.h>
#include <net/cfg80211.h>
@@ -110,6 +109,7 @@ enum ieee80211_ac_numbers {
IEEE80211_AC_BE = 2,
IEEE80211_AC_BK = 3,
};
+#define IEEE80211_NUM_ACS 4
/**
* struct ieee80211_tx_queue_params - transmit queue configuration
@@ -165,13 +165,14 @@ struct ieee80211_low_level_stats {
* @BSS_CHANGED_QOS: QoS for this association was enabled/disabled. Note
* that it is only ever disabled for station mode.
* @BSS_CHANGED_IDLE: Idle changed for this BSS/interface.
+ * @BSS_CHANGED_SSID: SSID changed for this BSS (AP mode)
*/
enum ieee80211_bss_change {
BSS_CHANGED_ASSOC = 1<<0,
BSS_CHANGED_ERP_CTS_PROT = 1<<1,
BSS_CHANGED_ERP_PREAMBLE = 1<<2,
BSS_CHANGED_ERP_SLOT = 1<<3,
- BSS_CHANGED_HT = 1<<4,
+ BSS_CHANGED_HT = 1<<4,
BSS_CHANGED_BASIC_RATES = 1<<5,
BSS_CHANGED_BEACON_INT = 1<<6,
BSS_CHANGED_BSSID = 1<<7,
@@ -182,6 +183,7 @@ enum ieee80211_bss_change {
BSS_CHANGED_ARP_FILTER = 1<<12,
BSS_CHANGED_QOS = 1<<13,
BSS_CHANGED_IDLE = 1<<14,
+ BSS_CHANGED_SSID = 1<<15,
/* when adding here, make sure to change ieee80211_reconfig */
};
@@ -255,6 +257,9 @@ enum ieee80211_rssi_event {
* @idle: This interface is idle. There's also a global idle flag in the
* hardware config which may be more appropriate depending on what
* your driver/device needs to do.
+ * @ssid: The SSID of the current vif. Only valid in AP-mode.
+ * @ssid_len: Length of SSID given in @ssid.
+ * @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode.
*/
struct ieee80211_bss_conf {
const u8 *bssid;
@@ -281,6 +286,9 @@ struct ieee80211_bss_conf {
bool arp_filter_enabled;
bool qos;
bool idle;
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ size_t ssid_len;
+ bool hidden_ssid;
};
/**
@@ -331,9 +339,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_PSPOLL_RESPONSE: (internal?)
- * This frame is a response to a PS-poll frame and should be sent
- * although the station is in powersave mode.
+ * @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_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
@@ -341,8 +349,6 @@ struct ieee80211_bss_conf {
* @IEEE80211_TX_INTFL_RETRANSMISSION: This frame is being retransmitted
* after TX status because the destination was asleep, it must not
* be modified again (no seqno assignment, crypto, etc.)
- * @IEEE80211_TX_INTFL_HAS_RADIOTAP: This frame was injected and still
- * has a radiotap header at skb->data.
* @IEEE80211_TX_INTFL_NL80211_FRAME_TX: Frame was requested through nl80211
* MLME command (internal to mac80211 to figure out whether to send TX
* status to user space)
@@ -356,6 +362,20 @@ struct ieee80211_bss_conf {
* @IEEE80211_TX_INTFL_TKIP_MIC_FAILURE: Marks this packet to be used for TKIP
* testing. It will be sent out with incorrect Michael MIC key to allow
* TKIP countermeasures to be tested.
+ * @IEEE80211_TX_CTL_NO_CCK_RATE: This frame will be sent at non CCK rate.
+ * This flag is actually used for management frame especially for P2P
+ * frames not being sent at CCK rate in 2GHz band.
+ * @IEEE80211_TX_STATUS_EOSP: This packet marks the end of service period,
+ * when its status is reported the service period ends. For frames in
+ * an SP that mac80211 transmits, it is already set; for driver frames
+ * the driver may set this flag. It is also used to do the same for
+ * PS-Poll responses.
+ * @IEEE80211_TX_CTL_USE_MINRATE: This frame will be sent at lowest rate.
+ * This flag is used to send nullfunc frame at minimum rate when
+ * the nullfunc is used for connection monitoring purpose.
+ * @IEEE80211_TX_CTL_DONTFRAG: Don't fragment this packet even if it
+ * would be fragmented by size (this is optional, only used for
+ * monitor injection).
*
* Note: If you have to add new flags to the enumeration, then don't
* forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary.
@@ -377,15 +397,19 @@ 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_PSPOLL_RESPONSE = BIT(17),
+ IEEE80211_TX_CTL_POLL_RESPONSE = BIT(17),
IEEE80211_TX_CTL_MORE_FRAMES = BIT(18),
IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19),
- IEEE80211_TX_INTFL_HAS_RADIOTAP = BIT(20),
+ /* hole at 20, use later */
IEEE80211_TX_INTFL_NL80211_FRAME_TX = BIT(21),
IEEE80211_TX_CTL_LDPC = BIT(22),
IEEE80211_TX_CTL_STBC = BIT(23) | BIT(24),
IEEE80211_TX_CTL_TX_OFFCHAN = BIT(25),
IEEE80211_TX_INTFL_TKIP_MIC_FAILURE = BIT(26),
+ IEEE80211_TX_CTL_NO_CCK_RATE = BIT(27),
+ IEEE80211_TX_STATUS_EOSP = BIT(28),
+ IEEE80211_TX_CTL_USE_MINRATE = BIT(29),
+ IEEE80211_TX_CTL_DONTFRAG = BIT(30),
};
#define IEEE80211_TX_CTL_STBC_SHIFT 23
@@ -399,9 +423,9 @@ 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_PSPOLL_RESPONSE | \
+ IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_POLL_RESPONSE | \
IEEE80211_TX_CTL_MORE_FRAMES | IEEE80211_TX_CTL_LDPC | \
- IEEE80211_TX_CTL_STBC)
+ IEEE80211_TX_CTL_STBC | IEEE80211_TX_STATUS_EOSP)
/**
* enum mac80211_rate_control_flags - per-rate flags set by the
@@ -948,6 +972,9 @@ enum set_key_cmd {
* @wme: indicates whether the STA supports WME. Only valid during AP-mode.
* @drv_priv: data area for driver use, will always be aligned to
* sizeof(void *), size is determined in hw information.
+ * @uapsd_queues: bitmap of queues configured for uapsd. Only valid
+ * if wme is supported.
+ * @max_sp: max Service Period. Only valid if wme is supported.
*/
struct ieee80211_sta {
u32 supp_rates[IEEE80211_NUM_BANDS];
@@ -955,6 +982,8 @@ struct ieee80211_sta {
u16 aid;
struct ieee80211_sta_ht_cap ht_cap;
bool wme;
+ u8 uapsd_queues;
+ u8 max_sp;
/* must be last */
u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
@@ -1095,6 +1124,10 @@ enum sta_notify_cmd {
* stations based on the PM bit of incoming frames.
* Use ieee80211_start_ps()/ieee8021_end_ps() to manually configure
* the PS mode of connected stations.
+ *
+ * @IEEE80211_HW_TX_AMPDU_SETUP_IN_HW: The device handles TX A-MPDU session
+ * setup strictly in HW. mac80211 should not attempt to do this in
+ * software.
*/
enum ieee80211_hw_flags {
IEEE80211_HW_HAS_RATE_CONTROL = 1<<0,
@@ -1120,6 +1153,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_SUPPORTS_CQM_RSSI = 1<<20,
IEEE80211_HW_SUPPORTS_PER_STA_GTK = 1<<21,
IEEE80211_HW_AP_LINK_PS = 1<<22,
+ IEEE80211_HW_TX_AMPDU_SETUP_IN_HW = 1<<23,
};
/**
@@ -1511,6 +1545,95 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
*/
/**
+ * DOC: AP support for powersaving clients
+ *
+ * In order to implement AP and P2P GO modes, mac80211 has support for
+ * client powersaving, both "legacy" PS (PS-Poll/null data) and uAPSD.
+ * There currently is no support for sAPSD.
+ *
+ * There is one assumption that mac80211 makes, namely that a client
+ * will not poll with PS-Poll and trigger with uAPSD at the same time.
+ * Both are supported, and both can be used by the same client, but
+ * they can't be used concurrently by the same client. This simplifies
+ * the driver code.
+ *
+ * The first thing to keep in mind is that there is a flag for complete
+ * driver implementation: %IEEE80211_HW_AP_LINK_PS. If this flag is set,
+ * mac80211 expects the driver to handle most of the state machine for
+ * powersaving clients and will ignore the PM bit in incoming frames.
+ * Drivers then use ieee80211_sta_ps_transition() to inform mac80211 of
+ * stations' powersave transitions. In this mode, mac80211 also doesn't
+ * handle PS-Poll/uAPSD.
+ *
+ * In the mode without %IEEE80211_HW_AP_LINK_PS, mac80211 will check the
+ * PM bit in incoming frames for client powersave transitions. When a
+ * station goes to sleep, we will stop transmitting to it. There is,
+ * however, a race condition: a station might go to sleep while there is
+ * data buffered on hardware queues. If the device has support for this
+ * it will reject frames, and the driver should give the frames back to
+ * mac80211 with the %IEEE80211_TX_STAT_TX_FILTERED flag set which will
+ * cause mac80211 to retry the frame when the station wakes up. The
+ * driver is also notified of powersave transitions by calling its
+ * @sta_notify callback.
+ *
+ * When the station is asleep, it has three choices: it can wake up,
+ * it can PS-Poll, or it can possibly start a uAPSD service period.
+ * Waking up is implemented by simply transmitting all buffered (and
+ * filtered) frames to the station. This is the easiest case. When
+ * 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
+ * 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
+ * TX status report it also sets %IEEE80211_TX_CTL_REQ_TX_STATUS.
+ * 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.
+ *
+ * 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
+ * transmitted first instead, causing reordering and/or wrong
+ * processing of the EOSP. The cause is that allowing frames to be
+ * transmitted to a certain station is out-of-band communication to
+ * the device. To allow this problem to be solved, the driver can
+ * call ieee80211_sta_block_awake() if frames are buffered when it
+ * is notified that the station went to sleep. When all these frames
+ * have been filtered (see above), it must call the function again
+ * to indicate that the station is no longer blocked.
+ *
+ * If the driver buffers frames in the driver for aggregation in any
+ * way, it must use the ieee80211_sta_set_buffered() call when it is
+ * notified of the station going to sleep to inform mac80211 of any
+ * TIDs that have frames buffered. Note that when a station wakes up
+ * this information is reset (hence the requirement to call it when
+ * informed of the station going to sleep). Then, when a service
+ * period starts for any reason, @release_buffered_frames is called
+ * with the number of frames to be released and which TIDs they are
+ * to come from. In this case, the driver is responsible for setting
+ * the EOSP (for uAPSD) and MORE_DATA bits in the released frames,
+ * to help the @more_data paramter is passed to tell the driver if
+ * there is more data on other TIDs -- the TIDs to release frames
+ * from are ignored since mac80211 doesn't know how many frames the
+ * buffers for those TIDs contain.
+ *
+ * If the driver also implement GO mode, where absence periods may
+ * shorten service periods (or abort PS-Poll responses), it must
+ * filter those response frames except in the case of frames that
+ * are buffered in the driver -- those must remain buffered to avoid
+ * reordering. Because it is possible that no frames are released
+ * in this case, the driver must call ieee80211_sta_eosp_irqsafe()
+ * to indicate to mac80211 that the service period ended anyway.
+ *
+ * Finally, if frames from multiple TIDs are released from mac80211
+ * but the driver might reorder them, it must clear & set the flags
+ * appropriately (only the last frame may have %IEEE80211_TX_STATUS_EOSP)
+ * and also take care of the EOSP and MORE_DATA bits in the frame.
+ * The driver may also use ieee80211_sta_eosp_irqsafe() in this case.
+ */
+
+/**
* enum ieee80211_filter_flags - hardware filter flags
*
* These flags determine what the filter in hardware should be
@@ -1600,6 +1723,17 @@ enum ieee80211_tx_sync_type {
};
/**
+ * enum ieee80211_frame_release_type - frame release reason
+ * @IEEE80211_FRAME_RELEASE_PSPOLL: frame released for PS-Poll
+ * @IEEE80211_FRAME_RELEASE_UAPSD: frame(s) released due to
+ * frame received on trigger-enabled AC
+ */
+enum ieee80211_frame_release_type {
+ IEEE80211_FRAME_RELEASE_PSPOLL,
+ IEEE80211_FRAME_RELEASE_UAPSD,
+};
+
+/**
* struct ieee80211_ops - callbacks from mac80211 to the driver
*
* This structure contains various callbacks that the driver may
@@ -1896,11 +2030,6 @@ enum ieee80211_tx_sync_type {
* ieee80211_remain_on_channel_expired(). This callback may sleep.
* @cancel_remain_on_channel: Requests that an ongoing off-channel period is
* aborted before it expires. This callback may sleep.
- * @offchannel_tx: Transmit frame on another channel, wait for a response
- * and return. Reliable TX status must be reported for the frame. If the
- * return value is 1, then the @remain_on_channel will be used with a
- * regular transmission (if supported.)
- * @offchannel_tx_cancel_wait: cancel wait associated with offchannel TX
*
* @set_ringparam: Set tx and rx ring sizes.
*
@@ -1914,6 +2043,45 @@ enum ieee80211_tx_sync_type {
* The callback can sleep.
* @rssi_callback: Notify driver when the average RSSI goes above/below
* thresholds that were registered previously. The callback can sleep.
+ *
+ * @release_buffered_frames: Release buffered frames according to the given
+ * parameters. In the case where the driver buffers some frames for
+ * sleeping stations mac80211 will use this callback to tell the driver
+ * to release some frames, either for PS-poll or uAPSD.
+ * Note that if the @more_data paramter is %false the driver must check
+ * if there are more frames on the given TIDs, and if there are more than
+ * the frames being released then it must still set the more-data bit in
+ * the frame. If the @more_data parameter is %true, then of course the
+ * more-data bit must always be set.
+ * The @tids parameter tells the driver which TIDs to release frames
+ * from, for PS-poll it will always have only a single bit set.
+ * In the case this is used for a PS-poll initiated release, the
+ * @num_frames parameter will always be 1 so code can be shared. In
+ * this case the driver must also set %IEEE80211_TX_STATUS_EOSP flag
+ * on the TX status (and must report TX status) so that the PS-poll
+ * period is properly ended. This is used to avoid sending multiple
+ * responses for a retried PS-poll frame.
+ * In the case this is used for uAPSD, the @num_frames parameter may be
+ * bigger than one, but the driver may send fewer frames (it must send
+ * at least one, however). In this case it is also responsible for
+ * setting the EOSP flag in the QoS header of the frames. Also, when the
+ * service period ends, the driver must set %IEEE80211_TX_STATUS_EOSP
+ * on the last frame in the SP. Alternatively, it may call the function
+ * ieee80211_sta_eosp_irqsafe() to inform mac80211 of the end of the SP.
+ * This callback must be atomic.
+ * @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
+ * 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
+ * on the last frame and clear it on all others and also handle the EOSP
+ * bit in the QoS header correctly. Alternatively, it can also call the
+ * ieee80211_sta_eosp_irqsafe() function.
+ * The @tids parameter is a bitmap and tells the driver which TIDs the
+ * frames will be on; it will at most have two bits set.
+ * This callback must be atomic.
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -1986,11 +2154,13 @@ struct ieee80211_ops {
struct ieee80211_sta *sta);
void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum sta_notify_cmd, struct ieee80211_sta *sta);
- int (*conf_tx)(struct ieee80211_hw *hw, u16 queue,
+ int (*conf_tx)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params);
- u64 (*get_tsf)(struct ieee80211_hw *hw);
- void (*set_tsf)(struct ieee80211_hw *hw, u64 tsf);
- void (*reset_tsf)(struct ieee80211_hw *hw);
+ u64 (*get_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+ void (*set_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ u64 tsf);
+ void (*reset_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
int (*tx_last_beacon)(struct ieee80211_hw *hw);
int (*ampdu_action)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
@@ -2019,11 +2189,6 @@ struct ieee80211_ops {
enum nl80211_channel_type channel_type,
int duration);
int (*cancel_remain_on_channel)(struct ieee80211_hw *hw);
- int (*offchannel_tx)(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
- unsigned int wait);
- int (*offchannel_tx_cancel_wait)(struct ieee80211_hw *hw);
int (*set_ringparam)(struct ieee80211_hw *hw, u32 tx, u32 rx);
void (*get_ringparam)(struct ieee80211_hw *hw,
u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max);
@@ -2032,6 +2197,17 @@ struct ieee80211_ops {
const struct cfg80211_bitrate_mask *mask);
void (*rssi_callback)(struct ieee80211_hw *hw,
enum ieee80211_rssi_event rssi_event);
+
+ void (*allow_buffered_frames)(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ u16 tids, int num_frames,
+ enum ieee80211_frame_release_type reason,
+ bool more_data);
+ void (*release_buffered_frames)(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ u16 tids, int num_frames,
+ enum ieee80211_frame_release_type reason,
+ bool more_data);
};
/**
@@ -2346,20 +2522,38 @@ static inline int ieee80211_sta_ps_transition_ni(struct ieee80211_sta *sta,
* The TX headroom reserved by mac80211 for its own tx_status functions.
* This is enough for the radiotap header.
*/
-#define IEEE80211_TX_STATUS_HEADROOM 13
+#define IEEE80211_TX_STATUS_HEADROOM 14
/**
- * ieee80211_sta_set_tim - set the TIM bit for a sleeping station
+ * ieee80211_sta_set_buffered - inform mac80211 about driver-buffered frames
* @sta: &struct ieee80211_sta pointer for the sleeping station
+ * @tid: the TID that has buffered frames
+ * @buffered: indicates whether or not frames are buffered for this TID
*
* If a driver buffers frames for a powersave station instead of passing
- * them back to mac80211 for retransmission, the station needs to be told
- * to wake up using the TIM bitmap in the beacon.
+ * them back to mac80211 for retransmission, the station may still need
+ * to be told that there are buffered frames via the TIM bit.
*
- * This function sets the station's TIM bit - it will be cleared when the
- * station wakes up.
+ * This function informs mac80211 whether or not there are frames that are
+ * buffered in the driver for a given TID; mac80211 can then use this data
+ * to set the TIM bit (NOTE: This may call back into the driver's set_tim
+ * call! Beware of the locking!)
+ *
+ * If all frames are released to the station (due to PS-poll or uAPSD)
+ * then the driver needs to inform mac80211 that there no longer are
+ * frames buffered. However, when the station wakes up mac80211 assumes
+ * that all buffered frames will be transmitted and clears this data,
+ * drivers need to make sure they inform mac80211 about all buffered
+ * frames on the sleep transition (sta_notify() with %STA_NOTIFY_SLEEP).
+ *
+ * Note that technically mac80211 only needs to know this per AC, not per
+ * TID, but since driver buffering will inevitably happen per TID (since
+ * it is related to aggregation) it is easier to make mac80211 map the
+ * TID to the AC as required instead of keeping track in all drivers that
+ * use this API.
*/
-void ieee80211_sta_set_tim(struct ieee80211_sta *sta);
+void ieee80211_sta_set_buffered(struct ieee80211_sta *sta,
+ u8 tid, bool buffered);
/**
* ieee80211_tx_status - transmit status callback
@@ -3017,6 +3211,24 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
struct ieee80211_sta *pubsta, bool block);
/**
+ * ieee80211_sta_eosp - notify mac80211 about end of SP
+ * @pubsta: the station
+ *
+ * When a device transmits frames in a way that it can't tell
+ * mac80211 in the TX status about the EOSP, it must clear the
+ * %IEEE80211_TX_STATUS_EOSP bit and call this function instead.
+ * This applies for PS-Poll as well as uAPSD.
+ *
+ * Note that there is no non-_irqsafe version right now as
+ * it wasn't needed, but just like _tx_status() and _rx()
+ * must not be mixed in irqsafe/non-irqsafe versions, this
+ * function must not be mixed with those either. Use the
+ * all irqsafe, or all non-irqsafe, don't mix! If you need
+ * the non-irqsafe version of this, you need to add it.
+ */
+void ieee80211_sta_eosp_irqsafe(struct ieee80211_sta *pubsta);
+
+/**
* ieee80211_iter_keys - iterate keys programmed into the device
* @hw: pointer obtained from ieee80211_alloc_hw()
* @vif: virtual interface to iterate, may be %NULL for all
@@ -3229,6 +3441,19 @@ void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw);
void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap,
const u8 *addr);
+/**
+ * ieee80211_send_bar - send a BlockAckReq frame
+ *
+ * can be used to flush pending frames from the peer's aggregation reorder
+ * buffer.
+ *
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ * @ra: the peer's destination address
+ * @tid: the TID of the aggregation session
+ * @ssn: the new starting sequence number for the receiver
+ */
+void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn);
+
/* Rate control API */
/**
@@ -3419,4 +3644,9 @@ void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif,
int rssi_max_thold);
void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif);
+
+int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb);
+
+int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif,
+ struct sk_buff *skb);
#endif /* MAC80211_H */
diff --git a/include/net/nfc/nci.h b/include/net/nfc/nci.h
new file mode 100644
index 000000000000..39b85bc0804f
--- /dev/null
+++ b/include/net/nfc/nci.h
@@ -0,0 +1,313 @@
+/*
+ * The NFC Controller Interface is the communication protocol between an
+ * NFC Controller (NFCC) and a Device Host (DH).
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ * Written by Ilan Elias <ilane@ti.com>
+ *
+ * Acknowledgements:
+ * This file is based on hci.h, which was written
+ * by Maxim Krasnyansky.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __NCI_H
+#define __NCI_H
+
+/* NCI constants */
+#define NCI_MAX_NUM_MAPPING_CONFIGS 10
+#define NCI_MAX_NUM_RF_CONFIGS 10
+#define NCI_MAX_NUM_CONN 10
+
+/* NCI Status Codes */
+#define NCI_STATUS_OK 0x00
+#define NCI_STATUS_REJECTED 0x01
+#define NCI_STATUS_MESSAGE_CORRUPTED 0x02
+#define NCI_STATUS_BUFFER_FULL 0x03
+#define NCI_STATUS_FAILED 0x04
+#define NCI_STATUS_NOT_INITIALIZED 0x05
+#define NCI_STATUS_SYNTAX_ERROR 0x06
+#define NCI_STATUS_SEMANTIC_ERROR 0x07
+#define NCI_STATUS_UNKNOWN_GID 0x08
+#define NCI_STATUS_UNKNOWN_OID 0x09
+#define NCI_STATUS_INVALID_PARAM 0x0a
+#define NCI_STATUS_MESSAGE_SIZE_EXCEEDED 0x0b
+/* Discovery Specific Status Codes */
+#define NCI_STATUS_DISCOVERY_ALREADY_STARTED 0xa0
+#define NCI_STATUS_DISCOVERY_TARGET_ACTIVATION_FAILED 0xa1
+/* RF Interface Specific Status Codes */
+#define NCI_STATUS_RF_TRANSMISSION_ERROR 0xb0
+#define NCI_STATUS_RF_PROTOCOL_ERROR 0xb1
+#define NCI_STATUS_RF_TIMEOUT_ERROR 0xb2
+#define NCI_STATUS_RF_LINK_LOSS_ERROR 0xb3
+/* NFCEE Interface Specific Status Codes */
+#define NCI_STATUS_MAX_ACTIVE_NFCEE_INTERFACES_REACHED 0xc0
+#define NCI_STATUS_NFCEE_INTERFACE_ACTIVATION_FAILED 0xc1
+#define NCI_STATUS_NFCEE_TRANSMISSION_ERROR 0xc2
+#define NCI_STATUS_NFCEE_PROTOCOL_ERROR 0xc3
+#define NCI_STATUS_NFCEE_TIMEOUT_ERROR 0xc4
+
+/* NCI RF Technology and Mode */
+#define NCI_NFC_A_PASSIVE_POLL_MODE 0x00
+#define NCI_NFC_B_PASSIVE_POLL_MODE 0x01
+#define NCI_NFC_F_PASSIVE_POLL_MODE 0x02
+#define NCI_NFC_A_ACTIVE_POLL_MODE 0x03
+#define NCI_NFC_F_ACTIVE_POLL_MODE 0x05
+#define NCI_NFC_A_PASSIVE_LISTEN_MODE 0x80
+#define NCI_NFC_B_PASSIVE_LISTEN_MODE 0x81
+#define NCI_NFC_F_PASSIVE_LISTEN_MODE 0x82
+#define NCI_NFC_A_ACTIVE_LISTEN_MODE 0x83
+#define NCI_NFC_F_ACTIVE_LISTEN_MODE 0x85
+
+/* NCI RF Protocols */
+#define NCI_RF_PROTOCOL_UNKNOWN 0x00
+#define NCI_RF_PROTOCOL_T1T 0x01
+#define NCI_RF_PROTOCOL_T2T 0x02
+#define NCI_RF_PROTOCOL_T3T 0x03
+#define NCI_RF_PROTOCOL_ISO_DEP 0x04
+#define NCI_RF_PROTOCOL_NFC_DEP 0x05
+
+/* NCI RF Interfaces */
+#define NCI_RF_INTERFACE_RFU 0x00
+#define NCI_RF_INTERFACE_FRAME 0x01
+#define NCI_RF_INTERFACE_ISO_DEP 0x02
+#define NCI_RF_INTERFACE_NFC_DEP 0x03
+
+/* NCI RF_DISCOVER_MAP_CMD modes */
+#define NCI_DISC_MAP_MODE_POLL 0x01
+#define NCI_DISC_MAP_MODE_LISTEN 0x02
+#define NCI_DISC_MAP_MODE_BOTH 0x03
+
+/* NCI Discovery Types */
+#define NCI_DISCOVERY_TYPE_POLL_A_PASSIVE 0x00
+#define NCI_DISCOVERY_TYPE_POLL_B_PASSIVE 0x01
+#define NCI_DISCOVERY_TYPE_POLL_F_PASSIVE 0x02
+#define NCI_DISCOVERY_TYPE_POLL_A_ACTIVE 0x03
+#define NCI_DISCOVERY_TYPE_POLL_F_ACTIVE 0x05
+#define NCI_DISCOVERY_TYPE_WAKEUP_A_PASSIVE 0x06
+#define NCI_DISCOVERY_TYPE_WAKEUP_B_PASSIVE 0x07
+#define NCI_DISCOVERY_TYPE_WAKEUP_A_ACTIVE 0x09
+#define NCI_DISCOVERY_TYPE_LISTEN_A_PASSIVE 0x80
+#define NCI_DISCOVERY_TYPE_LISTEN_B_PASSIVE 0x81
+#define NCI_DISCOVERY_TYPE_LISTEN_F_PASSIVE 0x82
+#define NCI_DISCOVERY_TYPE_LISTEN_A_ACTIVE 0x83
+#define NCI_DISCOVERY_TYPE_LISTEN_F_ACTIVE 0x85
+
+/* NCI Deactivation Type */
+#define NCI_DEACTIVATE_TYPE_IDLE_MODE 0x00
+#define NCI_DEACTIVATE_TYPE_SLEEP_MODE 0x01
+#define NCI_DEACTIVATE_TYPE_SLEEP_AF_MODE 0x02
+#define NCI_DEACTIVATE_TYPE_RF_LINK_LOSS 0x03
+#define NCI_DEACTIVATE_TYPE_DISCOVERY_ERROR 0x04
+
+/* Message Type (MT) */
+#define NCI_MT_DATA_PKT 0x00
+#define NCI_MT_CMD_PKT 0x01
+#define NCI_MT_RSP_PKT 0x02
+#define NCI_MT_NTF_PKT 0x03
+
+#define nci_mt(hdr) (((hdr)[0]>>5)&0x07)
+#define nci_mt_set(hdr, mt) ((hdr)[0] |= (__u8)(((mt)&0x07)<<5))
+
+/* Packet Boundary Flag (PBF) */
+#define NCI_PBF_LAST 0x00
+#define NCI_PBF_CONT 0x01
+
+#define nci_pbf(hdr) (__u8)(((hdr)[0]>>4)&0x01)
+#define nci_pbf_set(hdr, pbf) ((hdr)[0] |= (__u8)(((pbf)&0x01)<<4))
+
+/* Control Opcode manipulation */
+#define nci_opcode_pack(gid, oid) (__u16)((((__u16)((gid)&0x0f))<<8)|\
+ ((__u16)((oid)&0x3f)))
+#define nci_opcode(hdr) nci_opcode_pack(hdr[0], hdr[1])
+#define nci_opcode_gid(op) (__u8)(((op)&0x0f00)>>8)
+#define nci_opcode_oid(op) (__u8)((op)&0x003f)
+
+/* Payload Length */
+#define nci_plen(hdr) (__u8)((hdr)[2])
+
+/* Connection ID */
+#define nci_conn_id(hdr) (__u8)(((hdr)[0])&0x0f)
+
+/* GID values */
+#define NCI_GID_CORE 0x0
+#define NCI_GID_RF_MGMT 0x1
+#define NCI_GID_NFCEE_MGMT 0x2
+#define NCI_GID_PROPRIETARY 0xf
+
+/* ---- NCI Packet structures ---- */
+#define NCI_CTRL_HDR_SIZE 3
+#define NCI_DATA_HDR_SIZE 3
+
+struct nci_ctrl_hdr {
+ __u8 gid; /* MT & PBF & GID */
+ __u8 oid;
+ __u8 plen;
+} __packed;
+
+struct nci_data_hdr {
+ __u8 conn_id; /* MT & PBF & ConnID */
+ __u8 rfu;
+ __u8 plen;
+} __packed;
+
+/* ------------------------ */
+/* ----- NCI Commands ---- */
+/* ------------------------ */
+#define NCI_OP_CORE_RESET_CMD nci_opcode_pack(NCI_GID_CORE, 0x00)
+
+#define NCI_OP_CORE_INIT_CMD nci_opcode_pack(NCI_GID_CORE, 0x01)
+
+#define NCI_OP_CORE_SET_CONFIG_CMD nci_opcode_pack(NCI_GID_CORE, 0x02)
+
+#define NCI_OP_CORE_CONN_CREATE_CMD nci_opcode_pack(NCI_GID_CORE, 0x04)
+struct nci_core_conn_create_cmd {
+ __u8 target_handle;
+ __u8 num_target_specific_params;
+} __packed;
+
+#define NCI_OP_CORE_CONN_CLOSE_CMD nci_opcode_pack(NCI_GID_CORE, 0x06)
+
+#define NCI_OP_RF_DISCOVER_MAP_CMD nci_opcode_pack(NCI_GID_RF_MGMT, 0x00)
+struct disc_map_config {
+ __u8 rf_protocol;
+ __u8 mode;
+ __u8 rf_interface_type;
+} __packed;
+
+struct nci_rf_disc_map_cmd {
+ __u8 num_mapping_configs;
+ struct disc_map_config mapping_configs
+ [NCI_MAX_NUM_MAPPING_CONFIGS];
+} __packed;
+
+#define NCI_OP_RF_DISCOVER_CMD nci_opcode_pack(NCI_GID_RF_MGMT, 0x03)
+struct disc_config {
+ __u8 type;
+ __u8 frequency;
+} __packed;
+
+struct nci_rf_disc_cmd {
+ __u8 num_disc_configs;
+ struct disc_config disc_configs[NCI_MAX_NUM_RF_CONFIGS];
+} __packed;
+
+#define NCI_OP_RF_DEACTIVATE_CMD nci_opcode_pack(NCI_GID_RF_MGMT, 0x06)
+struct nci_rf_deactivate_cmd {
+ __u8 type;
+} __packed;
+
+/* ----------------------- */
+/* ---- NCI Responses ---- */
+/* ----------------------- */
+#define NCI_OP_CORE_RESET_RSP nci_opcode_pack(NCI_GID_CORE, 0x00)
+struct nci_core_reset_rsp {
+ __u8 status;
+ __u8 nci_ver;
+} __packed;
+
+#define NCI_OP_CORE_INIT_RSP nci_opcode_pack(NCI_GID_CORE, 0x01)
+struct nci_core_init_rsp_1 {
+ __u8 status;
+ __le32 nfcc_features;
+ __u8 num_supported_rf_interfaces;
+ __u8 supported_rf_interfaces[0]; /* variable size array */
+ /* continuted in nci_core_init_rsp_2 */
+} __packed;
+
+struct nci_core_init_rsp_2 {
+ __u8 max_logical_connections;
+ __le16 max_routing_table_size;
+ __u8 max_control_packet_payload_length;
+ __le16 rf_sending_buffer_size;
+ __le16 rf_receiving_buffer_size;
+ __le16 manufacturer_id;
+} __packed;
+
+#define NCI_OP_CORE_SET_CONFIG_RSP nci_opcode_pack(NCI_GID_CORE, 0x02)
+
+#define NCI_OP_CORE_CONN_CREATE_RSP nci_opcode_pack(NCI_GID_CORE, 0x04)
+struct nci_core_conn_create_rsp {
+ __u8 status;
+ __u8 max_pkt_payload_size;
+ __u8 initial_num_credits;
+ __u8 conn_id;
+} __packed;
+
+#define NCI_OP_CORE_CONN_CLOSE_RSP nci_opcode_pack(NCI_GID_CORE, 0x06)
+
+#define NCI_OP_RF_DISCOVER_MAP_RSP nci_opcode_pack(NCI_GID_RF_MGMT, 0x00)
+
+#define NCI_OP_RF_DISCOVER_RSP nci_opcode_pack(NCI_GID_RF_MGMT, 0x03)
+
+#define NCI_OP_RF_DEACTIVATE_RSP nci_opcode_pack(NCI_GID_RF_MGMT, 0x06)
+
+/* --------------------------- */
+/* ---- NCI Notifications ---- */
+/* --------------------------- */
+#define NCI_OP_CORE_CONN_CREDITS_NTF nci_opcode_pack(NCI_GID_CORE, 0x07)
+struct conn_credit_entry {
+ __u8 conn_id;
+ __u8 credits;
+} __packed;
+
+struct nci_core_conn_credit_ntf {
+ __u8 num_entries;
+ struct conn_credit_entry conn_entries[NCI_MAX_NUM_CONN];
+} __packed;
+
+#define NCI_OP_RF_FIELD_INFO_NTF nci_opcode_pack(NCI_GID_CORE, 0x08)
+struct nci_rf_field_info_ntf {
+ __u8 rf_field_status;
+} __packed;
+
+#define NCI_OP_RF_ACTIVATE_NTF nci_opcode_pack(NCI_GID_RF_MGMT, 0x05)
+struct rf_tech_specific_params_nfca_poll {
+ __u16 sens_res;
+ __u8 nfcid1_len; /* 0, 4, 7, or 10 Bytes */
+ __u8 nfcid1[10];
+ __u8 sel_res_len; /* 0 or 1 Bytes */
+ __u8 sel_res;
+} __packed;
+
+struct activation_params_nfca_poll_iso_dep {
+ __u8 rats_res_len;
+ __u8 rats_res[20];
+};
+
+struct nci_rf_activate_ntf {
+ __u8 target_handle;
+ __u8 rf_protocol;
+ __u8 rf_tech_and_mode;
+ __u8 rf_tech_specific_params_len;
+
+ union {
+ struct rf_tech_specific_params_nfca_poll nfca_poll;
+ } rf_tech_specific_params;
+
+ __u8 rf_interface_type;
+ __u8 activation_params_len;
+
+ union {
+ struct activation_params_nfca_poll_iso_dep nfca_poll_iso_dep;
+ } activation_params;
+
+} __packed;
+
+#define NCI_OP_RF_DEACTIVATE_NTF nci_opcode_pack(NCI_GID_RF_MGMT, 0x06)
+
+#endif /* __NCI_H */
diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h
new file mode 100644
index 000000000000..b8b4bbd7e0fc
--- /dev/null
+++ b/include/net/nfc/nci_core.h
@@ -0,0 +1,184 @@
+/*
+ * The NFC Controller Interface is the communication protocol between an
+ * NFC Controller (NFCC) and a Device Host (DH).
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ * Written by Ilan Elias <ilane@ti.com>
+ *
+ * Acknowledgements:
+ * This file is based on hci_core.h, which was written
+ * by Maxim Krasnyansky.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __NCI_CORE_H
+#define __NCI_CORE_H
+
+#include <linux/interrupt.h>
+#include <linux/skbuff.h>
+
+#include <net/nfc/nfc.h>
+#include <net/nfc/nci.h>
+
+/* NCI device state */
+enum {
+ NCI_INIT,
+ NCI_UP,
+ NCI_DISCOVERY,
+ NCI_POLL_ACTIVE,
+ NCI_DATA_EXCHANGE,
+};
+
+/* NCI timeouts */
+#define NCI_RESET_TIMEOUT 5000
+#define NCI_INIT_TIMEOUT 5000
+#define NCI_RF_DISC_TIMEOUT 5000
+#define NCI_RF_DEACTIVATE_TIMEOUT 5000
+#define NCI_CMD_TIMEOUT 5000
+
+struct nci_dev;
+
+struct nci_ops {
+ int (*open)(struct nci_dev *ndev);
+ int (*close)(struct nci_dev *ndev);
+ int (*send)(struct sk_buff *skb);
+};
+
+#define NCI_MAX_SUPPORTED_RF_INTERFACES 4
+
+/* NCI Core structures */
+struct nci_dev {
+ struct nfc_dev *nfc_dev;
+ struct nci_ops *ops;
+
+ int tx_headroom;
+ int tx_tailroom;
+
+ unsigned long flags;
+
+ atomic_t cmd_cnt;
+ atomic_t credits_cnt;
+
+ struct timer_list cmd_timer;
+
+ struct workqueue_struct *cmd_wq;
+ struct work_struct cmd_work;
+
+ struct workqueue_struct *rx_wq;
+ struct work_struct rx_work;
+
+ struct workqueue_struct *tx_wq;
+ struct work_struct tx_work;
+
+ struct sk_buff_head cmd_q;
+ struct sk_buff_head rx_q;
+ struct sk_buff_head tx_q;
+
+ struct mutex req_lock;
+ struct completion req_completion;
+ __u32 req_status;
+ __u32 req_result;
+
+ void *driver_data;
+
+ __u32 poll_prots;
+ __u32 target_available_prots;
+ __u32 target_active_prot;
+
+ /* received during NCI_OP_CORE_RESET_RSP */
+ __u8 nci_ver;
+
+ /* received during NCI_OP_CORE_INIT_RSP */
+ __u32 nfcc_features;
+ __u8 num_supported_rf_interfaces;
+ __u8 supported_rf_interfaces
+ [NCI_MAX_SUPPORTED_RF_INTERFACES];
+ __u8 max_logical_connections;
+ __u16 max_routing_table_size;
+ __u8 max_control_packet_payload_length;
+ __u16 rf_sending_buffer_size;
+ __u16 rf_receiving_buffer_size;
+ __u16 manufacturer_id;
+
+ /* received during NCI_OP_CORE_CONN_CREATE_RSP for static conn 0 */
+ __u8 max_pkt_payload_size;
+ __u8 initial_num_credits;
+ __u8 conn_id;
+
+ /* stored during nci_data_exchange */
+ data_exchange_cb_t data_exchange_cb;
+ void *data_exchange_cb_context;
+ struct sk_buff *rx_data_reassembly;
+};
+
+/* ----- NCI Devices ----- */
+struct nci_dev *nci_allocate_device(struct nci_ops *ops,
+ __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)
+{
+ struct sk_buff *skb;
+
+ skb = alloc_skb(len + ndev->tx_headroom + ndev->tx_tailroom, how);
+ if (skb)
+ skb_reserve(skb, ndev->tx_headroom);
+
+ return skb;
+}
+
+static inline void nci_set_parent_dev(struct nci_dev *ndev, struct device *dev)
+{
+ nfc_set_parent_dev(ndev->nfc_dev, dev);
+}
+
+static inline void nci_set_drvdata(struct nci_dev *ndev, void *data)
+{
+ ndev->driver_data = data;
+}
+
+static inline void *nci_get_drvdata(struct nci_dev *ndev)
+{
+ return ndev->driver_data;
+}
+
+void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb);
+void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb);
+void nci_rx_data_packet(struct nci_dev *ndev, struct sk_buff *skb);
+int nci_send_cmd(struct nci_dev *ndev, __u16 opcode, __u8 plen, void *payload);
+int nci_send_data(struct nci_dev *ndev, __u8 conn_id, struct sk_buff *skb);
+void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
+ int err);
+
+/* ----- NCI requests ----- */
+#define NCI_REQ_DONE 0
+#define NCI_REQ_PEND 1
+#define NCI_REQ_CANCELED 2
+
+void nci_req_complete(struct nci_dev *ndev, int result);
+
+/* ----- NCI status code ----- */
+int nci_to_errno(__u8 code);
+
+#endif /* __NCI_CORE_H */
diff --git a/include/net/nfc.h b/include/net/nfc/nfc.h
index cc0130312f70..6a7f602aa841 100644
--- a/include/net/nfc.h
+++ b/include/net/nfc/nfc.h
@@ -48,6 +48,8 @@ typedef void (*data_exchange_cb_t)(void *context, struct sk_buff *skb,
int err);
struct nfc_ops {
+ int (*dev_up)(struct nfc_dev *dev);
+ int (*dev_down)(struct nfc_dev *dev);
int (*start_poll)(struct nfc_dev *dev, u32 protocols);
void (*stop_poll)(struct nfc_dev *dev);
int (*activate_target)(struct nfc_dev *dev, u32 target_idx,
@@ -78,10 +80,15 @@ struct nfc_dev {
int targets_generation;
spinlock_t targets_lock;
struct device dev;
+ bool dev_up;
bool polling;
+ bool remote_activated;
struct nfc_genl_data genl_data;
u32 supported_protocols;
+ int tx_headroom;
+ int tx_tailroom;
+
struct nfc_ops *ops;
};
#define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev)
@@ -89,7 +96,9 @@ struct nfc_dev {
extern struct class nfc_class;
struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
- u32 supported_protocols);
+ u32 supported_protocols,
+ int tx_headroom,
+ int tx_tailroom);
/**
* nfc_free_device - free nfc device
diff --git a/include/net/regulatory.h b/include/net/regulatory.h
index 356d6e3dc20a..eb7d3c2d4274 100644
--- a/include/net/regulatory.h
+++ b/include/net/regulatory.h
@@ -3,11 +3,19 @@
/*
* regulatory support structures
*
- * Copyright 2008-2009 Luis R. Rodriguez <lrodriguez@atheros.com>
+ * Copyright 2008-2009 Luis R. Rodriguez <mcgrof@qca.qualcomm.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.
+ * 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.
*/
diff --git a/include/net/request_sock.h b/include/net/request_sock.h
index 99e6e19b57c2..4c0766e201e3 100644
--- a/include/net/request_sock.h
+++ b/include/net/request_sock.h
@@ -96,7 +96,8 @@ extern int sysctl_max_syn_backlog;
*/
struct listen_sock {
u8 max_qlen_log;
- /* 3 bytes hole, try to use */
+ u8 synflood_warned;
+ /* 2 bytes hole, try to use */
int qlen;
int qlen_young;
int clock_hand;
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 4fc88f3ccd5f..2eb207ea4eaf 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -46,14 +46,14 @@ struct qdisc_size_table {
struct Qdisc {
int (*enqueue)(struct sk_buff *skb, struct Qdisc *dev);
struct sk_buff * (*dequeue)(struct Qdisc *dev);
- unsigned flags;
+ unsigned int flags;
#define TCQ_F_BUILTIN 1
#define TCQ_F_INGRESS 2
#define TCQ_F_CAN_BYPASS 4
#define TCQ_F_MQROOT 8
#define TCQ_F_WARN_NONWC (1 << 16)
int padded;
- struct Qdisc_ops *ops;
+ const struct Qdisc_ops *ops;
struct qdisc_size_table __rcu *stab;
struct list_head list;
u32 handle;
@@ -224,7 +224,7 @@ struct qdisc_skb_cb {
long data[];
};
-static inline int qdisc_qlen(struct Qdisc *q)
+static inline int qdisc_qlen(const struct Qdisc *q)
{
return q->q.qlen;
}
@@ -239,12 +239,12 @@ static inline spinlock_t *qdisc_lock(struct Qdisc *qdisc)
return &qdisc->q.lock;
}
-static inline struct Qdisc *qdisc_root(struct Qdisc *qdisc)
+static inline struct Qdisc *qdisc_root(const struct Qdisc *qdisc)
{
return qdisc->dev_queue->qdisc;
}
-static inline struct Qdisc *qdisc_root_sleeping(struct Qdisc *qdisc)
+static inline struct Qdisc *qdisc_root_sleeping(const struct Qdisc *qdisc)
{
return qdisc->dev_queue->qdisc_sleeping;
}
@@ -260,7 +260,7 @@ static inline struct Qdisc *qdisc_root_sleeping(struct Qdisc *qdisc)
* root. This is enforced by holding the RTNL semaphore, which
* all users of this lock accessor must do.
*/
-static inline spinlock_t *qdisc_root_lock(struct Qdisc *qdisc)
+static inline spinlock_t *qdisc_root_lock(const struct Qdisc *qdisc)
{
struct Qdisc *root = qdisc_root(qdisc);
@@ -268,7 +268,7 @@ static inline spinlock_t *qdisc_root_lock(struct Qdisc *qdisc)
return qdisc_lock(root);
}
-static inline spinlock_t *qdisc_root_sleeping_lock(struct Qdisc *qdisc)
+static inline spinlock_t *qdisc_root_sleeping_lock(const struct Qdisc *qdisc)
{
struct Qdisc *root = qdisc_root_sleeping(qdisc);
@@ -276,17 +276,17 @@ static inline spinlock_t *qdisc_root_sleeping_lock(struct Qdisc *qdisc)
return qdisc_lock(root);
}
-static inline struct net_device *qdisc_dev(struct Qdisc *qdisc)
+static inline struct net_device *qdisc_dev(const struct Qdisc *qdisc)
{
return qdisc->dev_queue->dev;
}
-static inline void sch_tree_lock(struct Qdisc *q)
+static inline void sch_tree_lock(const struct Qdisc *q)
{
spin_lock_bh(qdisc_root_sleeping_lock(q));
}
-static inline void sch_tree_unlock(struct Qdisc *q)
+static inline void sch_tree_unlock(const struct Qdisc *q)
{
spin_unlock_bh(qdisc_root_sleeping_lock(q));
}
@@ -319,7 +319,7 @@ static inline unsigned int qdisc_class_hash(u32 id, u32 mask)
}
static inline struct Qdisc_class_common *
-qdisc_class_find(struct Qdisc_class_hash *hash, u32 id)
+qdisc_class_find(const struct Qdisc_class_hash *hash, u32 id)
{
struct Qdisc_class_common *cl;
struct hlist_node *n;
@@ -393,7 +393,7 @@ static inline bool qdisc_all_tx_empty(const struct net_device *dev)
}
/* Are any of the TX qdiscs changing? */
-static inline bool qdisc_tx_changing(struct net_device *dev)
+static inline bool qdisc_tx_changing(const struct net_device *dev)
{
unsigned int i;
for (i = 0; i < dev->num_tx_queues; i++) {
diff --git a/include/net/scm.h b/include/net/scm.h
index 745460fa2f02..d456f4c71a32 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -49,7 +49,7 @@ static __inline__ void scm_set_cred(struct scm_cookie *scm,
struct pid *pid, const struct cred *cred)
{
scm->pid = get_pid(pid);
- scm->cred = get_cred(cred);
+ scm->cred = cred ? get_cred(cred) : NULL;
cred_to_ucred(pid, cred, &scm->creds);
}
@@ -73,8 +73,7 @@ static __inline__ void scm_destroy(struct scm_cookie *scm)
static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
struct scm_cookie *scm)
{
- scm_set_cred(scm, task_tgid(current), current_cred());
- scm->fp = NULL;
+ memset(scm, 0, sizeof(*scm));
unix_get_peersec_dgram(sock, scm);
if (msg->msg_controllen <= 0)
return 0;
diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h
index 6506458ccd33..712b3bebeda7 100644
--- a/include/net/sctp/command.h
+++ b/include/net/sctp/command.h
@@ -109,6 +109,7 @@ typedef enum {
SCTP_CMD_SEND_MSG, /* Send the whole use message */
SCTP_CMD_SEND_NEXT_ASCONF, /* Send the next ASCONF after ACK */
SCTP_CMD_PURGE_ASCONF_QUEUE, /* Purge all asconf queues.*/
+ SCTP_CMD_SET_ASOC, /* Restore association context */
SCTP_CMD_LAST
} sctp_verb_t;
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index f7d9c3fc06fd..e90e7a9935dd 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -1915,6 +1915,7 @@ struct sctp_association {
__u32 addip_serial;
union sctp_addr *asconf_addr_del_pending;
int src_out_of_asoc_ok;
+ struct sctp_transport *new_transport;
/* SCTP AUTH: list of the endpoint shared keys. These
* keys are provided out of band by the user applicaton
diff --git a/include/net/secure_seq.h b/include/net/secure_seq.h
index d97f6892c019..c2e542b27a5a 100644
--- a/include/net/secure_seq.h
+++ b/include/net/secure_seq.h
@@ -10,7 +10,7 @@ extern u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
__be16 dport);
extern __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
__be16 sport, __be16 dport);
-extern __u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr,
+extern __u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
__be16 sport, __be16 dport);
extern u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
__be16 sport, __be16 dport);
diff --git a/include/net/sock.h b/include/net/sock.h
index 8e4062f165b8..5ac682f73d63 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -686,16 +686,25 @@ static inline void sock_rps_reset_flow(const struct sock *sk)
#endif
}
-static inline void sock_rps_save_rxhash(struct sock *sk, u32 rxhash)
+static inline void sock_rps_save_rxhash(struct sock *sk,
+ const struct sk_buff *skb)
{
#ifdef CONFIG_RPS
- if (unlikely(sk->sk_rxhash != rxhash)) {
+ if (unlikely(sk->sk_rxhash != skb->rxhash)) {
sock_rps_reset_flow(sk);
- sk->sk_rxhash = rxhash;
+ sk->sk_rxhash = skb->rxhash;
}
#endif
}
+static inline void sock_rps_reset_rxhash(struct sock *sk)
+{
+#ifdef CONFIG_RPS
+ sock_rps_reset_flow(sk);
+ sk->sk_rxhash = 0;
+#endif
+}
+
#define sk_wait_event(__sk, __timeo, __condition) \
({ int __rc; \
release_sock(__sk); \
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 149a415d1e0a..e147f42d643d 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -18,7 +18,6 @@
#ifndef _TCP_H
#define _TCP_H
-#define TCP_DEBUG 1
#define FASTRETRANS_DEBUG 1
#include <linux/list.h>
@@ -327,9 +326,9 @@ extern int tcp_sendpage(struct sock *sk, struct page *page, int offset,
size_t size, int flags);
extern int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg);
extern int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
- struct tcphdr *th, unsigned len);
+ const struct tcphdr *th, unsigned int len);
extern int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
- struct tcphdr *th, unsigned len);
+ const struct tcphdr *th, unsigned int len);
extern void tcp_rcv_space_adjust(struct sock *sk);
extern void tcp_cleanup_rbuf(struct sock *sk, int copied);
extern int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp);
@@ -356,6 +355,7 @@ static inline void tcp_dec_quickack_mode(struct sock *sk,
#define TCP_ECN_OK 1
#define TCP_ECN_QUEUE_CWR 2
#define TCP_ECN_DEMAND_CWR 4
+#define TCP_ECN_SEEN 8
static __inline__ void
TCP_ECN_create_request(struct request_sock *req, struct tcphdr *th)
@@ -400,10 +400,10 @@ extern void tcp_set_keepalive(struct sock *sk, int val);
extern void tcp_syn_ack_timeout(struct sock *sk, struct request_sock *req);
extern int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t len, int nonblock, int flags, int *addr_len);
-extern void tcp_parse_options(struct sk_buff *skb,
- struct tcp_options_received *opt_rx, u8 **hvpp,
+extern void tcp_parse_options(const struct sk_buff *skb,
+ struct tcp_options_received *opt_rx, const u8 **hvpp,
int estab);
-extern u8 *tcp_parse_md5sig_option(struct tcphdr *th);
+extern const u8 *tcp_parse_md5sig_option(const struct tcphdr *th);
/*
* TCP v4 functions exported for the inet6 API
@@ -431,17 +431,34 @@ extern int tcp_disconnect(struct sock *sk, int flags);
extern __u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS];
extern struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
struct ip_options *opt);
+#ifdef CONFIG_SYN_COOKIES
extern __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb,
__u16 *mss);
+#else
+static inline __u32 cookie_v4_init_sequence(struct sock *sk,
+ struct sk_buff *skb,
+ __u16 *mss)
+{
+ return 0;
+}
+#endif
extern __u32 cookie_init_timestamp(struct request_sock *req);
extern bool cookie_check_timestamp(struct tcp_options_received *opt, bool *);
/* From net/ipv6/syncookies.c */
extern struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb);
-extern __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb,
+#ifdef CONFIG_SYN_COOKIES
+extern __u32 cookie_v6_init_sequence(struct sock *sk, const struct sk_buff *skb,
__u16 *mss);
-
+#else
+static inline __u32 cookie_v6_init_sequence(struct sock *sk,
+ struct sk_buff *skb,
+ __u16 *mss)
+{
+ return 0;
+}
+#endif
/* tcp_output.c */
extern void __tcp_push_pending_frames(struct sock *sk, unsigned int cur_mss,
@@ -460,6 +477,9 @@ extern int tcp_write_wakeup(struct sock *);
extern void tcp_send_fin(struct sock *sk);
extern void tcp_send_active_reset(struct sock *sk, gfp_t priority);
extern int tcp_send_synack(struct sock *);
+extern int tcp_syn_flood_action(struct sock *sk,
+ const struct sk_buff *skb,
+ const char *proto);
extern void tcp_push_one(struct sock *, unsigned int mss_now);
extern void tcp_send_ack(struct sock *sk);
extern void tcp_send_delayed_ack(struct sock *sk);
@@ -501,7 +521,7 @@ static inline int tcp_bound_to_half_wnd(struct tcp_sock *tp, int pktsize)
}
/* tcp.c */
-extern void tcp_get_info(struct sock *, struct tcp_info *);
+extern void tcp_get_info(const struct sock *, struct tcp_info *);
/* Read 'sendfile()'-style from a TCP socket */
typedef int (*sk_read_actor_t)(read_descriptor_t *, struct sk_buff *,
@@ -511,8 +531,8 @@ extern int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
extern void tcp_initialize_rcv_mss(struct sock *sk);
-extern int tcp_mtu_to_mss(struct sock *sk, int pmtu);
-extern int tcp_mss_to_mtu(struct sock *sk, int mss);
+extern int tcp_mtu_to_mss(const struct sock *sk, int pmtu);
+extern int tcp_mss_to_mtu(const struct sock *sk, int mss);
extern void tcp_mtup_init(struct sock *sk);
extern void tcp_valid_rtt_meas(struct sock *sk, u32 seq_rtt);
@@ -553,7 +573,7 @@ static inline void tcp_fast_path_check(struct sock *sk)
/* Compute the actual rto_min value */
static inline u32 tcp_rto_min(struct sock *sk)
{
- struct dst_entry *dst = __sk_dst_get(sk);
+ const struct dst_entry *dst = __sk_dst_get(sk);
u32 rto_min = TCP_RTO_MIN;
if (dst && dst_metric_locked(dst, RTAX_RTO_MIN))
@@ -615,13 +635,14 @@ struct tcp_skb_cb {
__u32 seq; /* Starting sequence number */
__u32 end_seq; /* SEQ + FIN + SYN + datalen */
__u32 when; /* used to compute rtt's */
- __u8 flags; /* TCP header flags. */
+ __u8 tcp_flags; /* TCP header flags. (tcp[13]) */
__u8 sacked; /* State flags for SACK/FACK. */
#define TCPCB_SACKED_ACKED 0x01 /* SKB ACK'd by a SACK block */
#define TCPCB_SACKED_RETRANS 0x02 /* SKB retransmitted */
#define TCPCB_LOST 0x04 /* SKB is lost */
#define TCPCB_TAGBITS 0x07 /* All tag bits */
-
+ __u8 ip_dsfield; /* IPv4 tos or IPv6 dsfield */
+ /* 1 byte hole */
#define TCPCB_EVER_RETRANS 0x80 /* Ever retransmitted frame */
#define TCPCB_RETRANS (TCPCB_SACKED_RETRANS|TCPCB_EVER_RETRANS)
@@ -798,6 +819,7 @@ static inline bool tcp_in_initial_slowstart(const struct tcp_sock *tp)
static inline __u32 tcp_current_ssthresh(const struct sock *sk)
{
const struct tcp_sock *tp = tcp_sk(sk);
+
if ((1 << inet_csk(sk)->icsk_ca_state) & (TCPF_CA_CWR | TCPF_CA_Recovery))
return tp->snd_ssthresh;
else
@@ -810,7 +832,7 @@ static inline __u32 tcp_current_ssthresh(const struct sock *sk)
#define tcp_verify_left_out(tp) WARN_ON(tcp_left_out(tp) > tp->packets_out)
extern void tcp_enter_cwr(struct sock *sk, const int set_ssthresh);
-extern __u32 tcp_init_cwnd(struct tcp_sock *tp, struct dst_entry *dst);
+extern __u32 tcp_init_cwnd(const struct tcp_sock *tp, const struct dst_entry *dst);
/* Slow start with delack produces 3 packets of burst, so that
* it is safe "de facto". This will be the default - same as
@@ -839,7 +861,7 @@ static inline void tcp_minshall_update(struct tcp_sock *tp, unsigned int mss,
static inline void tcp_check_probe_timer(struct sock *sk)
{
- struct tcp_sock *tp = tcp_sk(sk);
+ const struct tcp_sock *tp = tcp_sk(sk);
const struct inet_connection_sock *icsk = inet_csk(sk);
if (!tp->packets_out && !icsk->icsk_pending)
@@ -1162,8 +1184,9 @@ struct tcp_md5sig_pool {
/* - functions */
extern int tcp_v4_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,
- struct sock *sk, struct request_sock *req,
- struct sk_buff *skb);
+ const struct sock *sk,
+ const struct request_sock *req,
+ const struct sk_buff *skb);
extern struct tcp_md5sig_key * tcp_v4_md5_lookup(struct sock *sk,
struct sock *addr_sk);
extern int tcp_v4_md5_do_add(struct sock *sk, __be32 addr, u8 *newkey,
@@ -1180,17 +1203,17 @@ extern int tcp_v4_md5_do_del(struct sock *sk, __be32 addr);
#define tcp_twsk_md5_key(twsk) NULL
#endif
-extern struct tcp_md5sig_pool * __percpu *tcp_alloc_md5sig_pool(struct sock *);
+extern struct tcp_md5sig_pool __percpu *tcp_alloc_md5sig_pool(struct sock *);
extern void tcp_free_md5sig_pool(void);
extern struct tcp_md5sig_pool *tcp_get_md5sig_pool(void);
extern void tcp_put_md5sig_pool(void);
-extern int tcp_md5_hash_header(struct tcp_md5sig_pool *, struct tcphdr *);
-extern int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *, struct sk_buff *,
+extern int tcp_md5_hash_header(struct tcp_md5sig_pool *, const struct tcphdr *);
+extern int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *, const struct sk_buff *,
unsigned header_len);
extern int tcp_md5_hash_key(struct tcp_md5sig_pool *hp,
- struct tcp_md5sig_key *key);
+ const struct tcp_md5sig_key *key);
/* write queue abstraction */
static inline void tcp_write_queue_purge(struct sock *sk)
@@ -1203,22 +1226,24 @@ static inline void tcp_write_queue_purge(struct sock *sk)
tcp_clear_all_retrans_hints(tcp_sk(sk));
}
-static inline struct sk_buff *tcp_write_queue_head(struct sock *sk)
+static inline struct sk_buff *tcp_write_queue_head(const struct sock *sk)
{
return skb_peek(&sk->sk_write_queue);
}
-static inline struct sk_buff *tcp_write_queue_tail(struct sock *sk)
+static inline struct sk_buff *tcp_write_queue_tail(const struct sock *sk)
{
return skb_peek_tail(&sk->sk_write_queue);
}
-static inline struct sk_buff *tcp_write_queue_next(struct sock *sk, struct sk_buff *skb)
+static inline struct sk_buff *tcp_write_queue_next(const struct sock *sk,
+ const struct sk_buff *skb)
{
return skb_queue_next(&sk->sk_write_queue, skb);
}
-static inline struct sk_buff *tcp_write_queue_prev(struct sock *sk, struct sk_buff *skb)
+static inline struct sk_buff *tcp_write_queue_prev(const struct sock *sk,
+ const struct sk_buff *skb)
{
return skb_queue_prev(&sk->sk_write_queue, skb);
}
@@ -1232,7 +1257,7 @@ static inline struct sk_buff *tcp_write_queue_prev(struct sock *sk, struct sk_bu
#define tcp_for_write_queue_from_safe(skb, tmp, sk) \
skb_queue_walk_from_safe(&(sk)->sk_write_queue, skb, tmp)
-static inline struct sk_buff *tcp_send_head(struct sock *sk)
+static inline struct sk_buff *tcp_send_head(const struct sock *sk)
{
return sk->sk_send_head;
}
@@ -1243,7 +1268,7 @@ static inline bool tcp_skb_is_last(const struct sock *sk,
return skb_queue_is_last(&sk->sk_write_queue, skb);
}
-static inline void tcp_advance_send_head(struct sock *sk, struct sk_buff *skb)
+static inline void tcp_advance_send_head(struct sock *sk, const struct sk_buff *skb)
{
if (tcp_skb_is_last(sk, skb))
sk->sk_send_head = NULL;
@@ -1423,9 +1448,9 @@ struct tcp_sock_af_ops {
struct sock *addr_sk);
int (*calc_md5_hash) (char *location,
struct tcp_md5sig_key *md5,
- struct sock *sk,
- struct request_sock *req,
- struct sk_buff *skb);
+ const struct sock *sk,
+ const struct request_sock *req,
+ const struct sk_buff *skb);
int (*md5_add) (struct sock *sk,
struct sock *addr_sk,
u8 *newkey,
@@ -1442,9 +1467,9 @@ struct tcp_request_sock_ops {
struct request_sock *req);
int (*calc_md5_hash) (char *location,
struct tcp_md5sig_key *md5,
- struct sock *sk,
- struct request_sock *req,
- struct sk_buff *skb);
+ const struct sock *sk,
+ const struct request_sock *req,
+ const struct sk_buff *skb);
#endif
};
diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h
index 5271a741c3a3..498433dd067d 100644
--- a/include/net/transp_v6.h
+++ b/include/net/transp_v6.h
@@ -39,6 +39,7 @@ extern int datagram_recv_ctl(struct sock *sk,
struct sk_buff *skb);
extern int datagram_send_ctl(struct net *net,
+ struct sock *sk,
struct msghdr *msg,
struct flowi6 *fl6,
struct ipv6_txoptions *opt,
diff --git a/include/net/udplite.h b/include/net/udplite.h
index 673a024c6b2a..5f097ca7d5c5 100644
--- a/include/net/udplite.h
+++ b/include/net/udplite.h
@@ -66,40 +66,34 @@ static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh)
return 0;
}
-static inline int udplite_sender_cscov(struct udp_sock *up, struct udphdr *uh)
+/* Slow-path computation of checksum. Socket is locked. */
+static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb)
{
+ const struct udp_sock *up = udp_sk(skb->sk);
int cscov = up->len;
+ __wsum csum = 0;
- /*
- * Sender has set `partial coverage' option on UDP-Lite socket
- */
- if (up->pcflag & UDPLITE_SEND_CC) {
+ if (up->pcflag & UDPLITE_SEND_CC) {
+ /*
+ * Sender has set `partial coverage' option on UDP-Lite socket.
+ * The special case "up->pcslen == 0" signifies full coverage.
+ */
if (up->pcslen < up->len) {
- /* up->pcslen == 0 means that full coverage is required,
- * partial coverage only if 0 < up->pcslen < up->len */
- if (0 < up->pcslen) {
- cscov = up->pcslen;
- }
- uh->len = htons(up->pcslen);
+ if (0 < up->pcslen)
+ cscov = up->pcslen;
+ udp_hdr(skb)->len = htons(up->pcslen);
}
- /*
- * NOTE: Causes for the error case `up->pcslen > up->len':
- * (i) Application error (will not be penalized).
- * (ii) Payload too big for send buffer: data is split
- * into several packets, each with its own header.
- * In this case (e.g. last segment), coverage may
- * exceed packet length.
- * Since packets with coverage length > packet length are
- * illegal, we fall back to the defaults here.
- */
+ /*
+ * NOTE: Causes for the error case `up->pcslen > up->len':
+ * (i) Application error (will not be penalized).
+ * (ii) Payload too big for send buffer: data is split
+ * into several packets, each with its own header.
+ * In this case (e.g. last segment), coverage may
+ * exceed packet length.
+ * Since packets with coverage length > packet length are
+ * illegal, we fall back to the defaults here.
+ */
}
- return cscov;
-}
-
-static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb)
-{
- int cscov = udplite_sender_cscov(udp_sk(sk), udp_hdr(skb));
- __wsum csum = 0;
skb->ip_summed = CHECKSUM_NONE; /* no HW support for checksumming */
@@ -115,16 +109,21 @@ static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb)
return csum;
}
+/* Fast-path computation of checksum. Socket may not be locked. */
static inline __wsum udplite_csum(struct sk_buff *skb)
{
- struct sock *sk = skb->sk;
- int cscov = udplite_sender_cscov(udp_sk(sk), udp_hdr(skb));
+ const struct udp_sock *up = udp_sk(skb->sk);
const int off = skb_transport_offset(skb);
- const int len = skb->len - off;
+ int len = skb->len - off;
+ if ((up->pcflag & UDPLITE_SEND_CC) && up->pcslen < len) {
+ if (0 < up->pcslen)
+ len = up->pcslen;
+ udp_hdr(skb)->len = htons(up->pcslen);
+ }
skb->ip_summed = CHECKSUM_NONE; /* no HW support for checksumming */
- return skb_checksum(skb, off, min(cscov, len), 0);
+ return skb_checksum(skb, off, len, 0);
}
extern void udplite4_register(void);
diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h
index ae8c68f30f1b..639a4491fc0d 100644
--- a/include/rdma/ib_addr.h
+++ b/include/rdma/ib_addr.h
@@ -218,8 +218,12 @@ static inline int iboe_get_rate(struct net_device *dev)
{
struct ethtool_cmd cmd;
u32 speed;
+ int err;
- if (dev_ethtool_get_settings(dev, &cmd))
+ rtnl_lock();
+ err = __ethtool_get_settings(dev, &cmd);
+ rtnl_unlock();
+ if (err)
return IB_RATE_PORT_CURRENT;
speed = ethtool_cmd_speed(&cmd);
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 57e71fa33f7c..54cb079b7bf1 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -29,7 +29,7 @@
#include <linux/poll.h>
#include <linux/mm.h>
#include <linux/bitops.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
#define snd_pcm_substream_chip(substream) ((substream)->private_data)
#define snd_pcm_chip(pcm) ((pcm)->private_data)
@@ -373,7 +373,7 @@ struct snd_pcm_substream {
int number;
char name[32]; /* substream name */
int stream; /* stream (direction) */
- struct pm_qos_request_list latency_pm_qos_req; /* pm_qos request */
+ struct pm_qos_request latency_pm_qos_req; /* pm_qos request */
size_t buffer_bytes_max; /* limit ring buffer size */
struct snd_dma_buffer dma_buffer;
unsigned int dma_buf_id;
diff --git a/include/target/configfs_macros.h b/include/target/configfs_macros.h
index 7fe74608b437..a0fc85bbe2da 100644
--- a/include/target/configfs_macros.h
+++ b/include/target/configfs_macros.h
@@ -30,8 +30,8 @@
* Added CONFIGFS_EATTR() macros from original configfs.h macros
* Copright (C) 2008-2009 Nicholas A. Bellinger <nab@linux-iscsi.org>
*
- * Please read Documentation/filesystems/configfs.txt before using the
- * configfs interface, ESPECIALLY the parts about reference counts and
+ * Please read Documentation/filesystems/configfs/configfs.txt before using
+ * the configfs interface, ESPECIALLY the parts about reference counts and
* item destructors.
*/
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index 27040653005e..35aa786f93da 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -10,10 +10,7 @@
#include <net/tcp.h>
#define TARGET_CORE_MOD_VERSION "v4.1.0-rc1-ml"
-#define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGABRT))
-/* Used by transport_generic_allocate_iovecs() */
-#define TRANSPORT_IOV_DATA_BUFFER 5
/* Maximum Number of LUNs per Target Portal Group */
/* Don't raise above 511 or REPORT_LUNS needs to handle >1 page */
#define TRANSPORT_MAX_LUNS_PER_TPG 256
@@ -75,32 +72,26 @@ enum transport_tpg_type_table {
};
/* Used for generate timer flags */
-enum timer_flags_table {
- TF_RUNNING = 0x01,
- TF_STOP = 0x02,
+enum se_task_flags {
+ TF_ACTIVE = (1 << 0),
+ TF_SENT = (1 << 1),
+ TF_REQUEST_STOP = (1 << 2),
};
/* Special transport agnostic struct se_cmd->t_states */
enum transport_state_table {
TRANSPORT_NO_STATE = 0,
TRANSPORT_NEW_CMD = 1,
- TRANSPORT_DEFERRED_CMD = 2,
TRANSPORT_WRITE_PENDING = 3,
TRANSPORT_PROCESS_WRITE = 4,
TRANSPORT_PROCESSING = 5,
- TRANSPORT_COMPLETE_OK = 6,
- TRANSPORT_COMPLETE_FAILURE = 7,
- TRANSPORT_COMPLETE_TIMEOUT = 8,
+ TRANSPORT_COMPLETE = 6,
TRANSPORT_PROCESS_TMR = 9,
- TRANSPORT_TMR_COMPLETE = 10,
TRANSPORT_ISTATE_PROCESSING = 11,
- TRANSPORT_ISTATE_PROCESSED = 12,
- TRANSPORT_KILL = 13,
- TRANSPORT_REMOVE = 14,
- TRANSPORT_FREE = 15,
TRANSPORT_NEW_CMD_MAP = 16,
TRANSPORT_FREE_CMD_INTR = 17,
TRANSPORT_COMPLETE_QF_WP = 18,
+ TRANSPORT_COMPLETE_QF_OK = 19,
};
/* Used for struct se_cmd->se_cmd_flags */
@@ -125,7 +116,6 @@ enum se_cmd_flags_table {
SCF_UNUSED = 0x00100000,
SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00400000,
SCF_EMULATE_CDB_ASYNC = 0x01000000,
- SCF_EMULATE_QUEUE_FULL = 0x02000000,
};
/* struct se_dev_entry->lun_flags and struct se_lun->lun_access */
@@ -401,34 +391,22 @@ struct se_queue_obj {
} ____cacheline_aligned;
struct se_task {
- unsigned char task_sense;
- struct scatterlist *task_sg;
- u32 task_sg_nents;
- struct scatterlist *task_sg_bidi;
- u8 task_scsi_status;
- u8 task_flags;
- int task_error_status;
- int task_state_flags;
- bool task_padded_sg;
unsigned long long task_lba;
- u32 task_no;
- u32 task_sectors;
- u32 task_size;
+ u32 task_sectors;
+ u32 task_size;
+ struct se_cmd *task_se_cmd;
+ struct scatterlist *task_sg;
+ u32 task_sg_nents;
+ u16 task_flags;
+ u8 task_sense;
+ u8 task_scsi_status;
+ int task_error_status;
enum dma_data_direction task_data_direction;
- struct se_cmd *task_se_cmd;
- struct se_device *se_dev;
+ atomic_t task_state_active;
+ struct list_head t_list;
+ struct list_head t_execute_list;
+ struct list_head t_state_list;
struct completion task_stop_comp;
- atomic_t task_active;
- atomic_t task_execute_queue;
- atomic_t task_timeout;
- atomic_t task_sent;
- atomic_t task_stop;
- atomic_t task_state_active;
- struct timer_list task_timer;
- struct se_device *se_obj_ptr;
- struct list_head t_list;
- struct list_head t_execute_list;
- struct list_head t_state_list;
} ____cacheline_aligned;
struct se_cmd {
@@ -446,8 +424,6 @@ struct se_cmd {
int sam_task_attr;
/* Transport protocol dependent state, see transport_state_table */
enum transport_state_table t_state;
- /* Transport protocol dependent state for out of order CmdSNs */
- int deferred_t_state;
/* Transport specific error status */
int transport_error_status;
/* See se_cmd_flags_table */
@@ -461,7 +437,6 @@ struct se_cmd {
u32 orig_fe_lun;
/* Persistent Reservation key */
u64 pr_res_key;
- atomic_t transport_sent;
/* Used for sense data */
void *sense_buffer;
struct list_head se_delayed_node;
@@ -479,10 +454,7 @@ struct se_cmd {
struct list_head se_queue_node;
struct target_core_fabric_ops *se_tfo;
int (*transport_emulate_cdb)(struct se_cmd *);
- void (*transport_split_cdb)(unsigned long long, u32, unsigned char *);
- void (*transport_wait_for_tasks)(struct se_cmd *, int, int);
void (*transport_complete_callback)(struct se_cmd *);
- int (*transport_qf_callback)(struct se_cmd *);
unsigned char *t_task_cdb;
unsigned char __t_task_cdb[TCM_MAX_COMMAND_SIZE];
@@ -495,7 +467,6 @@ struct se_cmd {
atomic_t t_se_count;
atomic_t t_task_cdbs_left;
atomic_t t_task_cdbs_ex_left;
- atomic_t t_task_cdbs_timeout_left;
atomic_t t_task_cdbs_sent;
atomic_t t_transport_aborted;
atomic_t t_transport_active;
@@ -503,7 +474,6 @@ struct se_cmd {
atomic_t t_transport_queue_active;
atomic_t t_transport_sent;
atomic_t t_transport_stop;
- atomic_t t_transport_timeout;
atomic_t transport_dev_active;
atomic_t transport_lun_active;
atomic_t transport_lun_fe_stop;
@@ -514,6 +484,8 @@ struct se_cmd {
struct completion transport_lun_stop_comp;
struct scatterlist *t_tasks_sg_chained;
+ struct work_struct work;
+
/*
* Used for pre-registered fabric SGL passthrough WRITE and READ
* with the special SCF_PASSTHROUGH_CONTIG_TO_SG case for TCM_Loop
@@ -670,7 +642,6 @@ struct se_dev_attrib {
u32 optimal_sectors;
u32 hw_queue_depth;
u32 queue_depth;
- u32 task_timeout;
u32 max_unmap_lba_count;
u32 max_unmap_block_desc_count;
u32 unmap_granularity;
diff --git a/include/target/target_core_fabric_ops.h b/include/target/target_core_fabric_ops.h
index 2de8fe907596..126c675f4f14 100644
--- a/include/target/target_core_fabric_ops.h
+++ b/include/target/target_core_fabric_ops.h
@@ -27,6 +27,12 @@ struct target_core_fabric_ops {
int (*tpg_check_demo_mode_cache)(struct se_portal_group *);
int (*tpg_check_demo_mode_write_protect)(struct se_portal_group *);
int (*tpg_check_prod_mode_write_protect)(struct se_portal_group *);
+ /*
+ * Optionally used by fabrics to allow demo-mode login, but not
+ * expose any TPG LUNs, and return 'not connected' in standard
+ * inquiry response
+ */
+ int (*tpg_check_demo_mode_login_only)(struct se_portal_group *);
struct se_node_acl *(*tpg_alloc_fabric_acl)(
struct se_portal_group *);
void (*tpg_release_fabric_acl)(struct se_portal_group *,
diff --git a/include/target/target_core_tmr.h b/include/target/target_core_tmr.h
index bd5596807478..d5876e17d3fb 100644
--- a/include/target/target_core_tmr.h
+++ b/include/target/target_core_tmr.h
@@ -27,7 +27,7 @@ enum tcm_tmrsp_table {
extern struct kmem_cache *se_tmr_req_cache;
-extern struct se_tmr_req *core_tmr_alloc_req(struct se_cmd *, void *, u8);
+extern struct se_tmr_req *core_tmr_alloc_req(struct se_cmd *, void *, u8, gfp_t);
extern void core_tmr_release_req(struct se_tmr_req *);
extern int core_tmr_lun_reset(struct se_device *, struct se_tmr_req *,
struct list_head *, struct se_cmd *);
diff --git a/include/target/target_core_transport.h b/include/target/target_core_transport.h
index 46aae4f94ede..a037a1a6fbba 100644
--- a/include/target/target_core_transport.h
+++ b/include/target/target_core_transport.h
@@ -22,10 +22,9 @@
#define PYX_TRANSPORT_LU_COMM_FAILURE -7
#define PYX_TRANSPORT_UNKNOWN_MODE_PAGE -8
#define PYX_TRANSPORT_WRITE_PROTECTED -9
-#define PYX_TRANSPORT_TASK_TIMEOUT -10
-#define PYX_TRANSPORT_RESERVATION_CONFLICT -11
-#define PYX_TRANSPORT_ILLEGAL_REQUEST -12
-#define PYX_TRANSPORT_USE_SENSE_REASON -13
+#define PYX_TRANSPORT_RESERVATION_CONFLICT -10
+#define PYX_TRANSPORT_ILLEGAL_REQUEST -11
+#define PYX_TRANSPORT_USE_SENSE_REASON -12
#ifndef SAM_STAT_RESERVATION_CONFLICT
#define SAM_STAT_RESERVATION_CONFLICT 0x18
@@ -38,16 +37,6 @@
#define TRANSPORT_PLUGIN_VHBA_PDEV 2
#define TRANSPORT_PLUGIN_VHBA_VDEV 3
-/* For SE OBJ Plugins, in seconds */
-#define TRANSPORT_TIMEOUT_TUR 10
-#define TRANSPORT_TIMEOUT_TYPE_DISK 60
-#define TRANSPORT_TIMEOUT_TYPE_ROM 120
-#define TRANSPORT_TIMEOUT_TYPE_TAPE 600
-#define TRANSPORT_TIMEOUT_TYPE_OTHER 300
-
-/* For se_task->task_state_flags */
-#define TSF_EXCEPTION_CLEARED 0x01
-
/*
* struct se_subsystem_dev->su_dev_flags
*/
@@ -64,8 +53,6 @@
#define DF_SPC2_RESERVATIONS_WITH_ISID 0x00000004
/* struct se_dev_attrib sanity values */
-/* 10 Minutes */
-#define DA_TASK_TIMEOUT_MAX 600
/* Default max_unmap_lba_count */
#define DA_MAX_UNMAP_LBA_COUNT 0
/* Default max_unmap_block_desc_count */
@@ -110,16 +97,13 @@
#define MOD_MAX_SECTORS(ms, bs) (ms % (PAGE_SIZE / bs))
-struct se_mem;
struct se_subsystem_api;
-extern struct kmem_cache *se_mem_cache;
-
extern int init_se_kmem_caches(void);
extern void release_se_kmem_caches(void);
extern u32 scsi_get_new_index(scsi_index_t);
extern void transport_init_queue_obj(struct se_queue_obj *);
-extern int transport_subsystem_check_init(void);
+extern void transport_subsystem_check_init(void);
extern int transport_subsystem_register(struct se_subsystem_api *);
extern void transport_subsystem_release(struct se_subsystem_api *);
extern void transport_load_plugins(void);
@@ -134,7 +118,6 @@ extern void transport_free_session(struct se_session *);
extern void transport_deregister_session_configfs(struct se_session *);
extern void transport_deregister_session(struct se_session *);
extern void transport_cmd_finish_abort(struct se_cmd *, int);
-extern void transport_cmd_finish_abort_tmr(struct se_cmd *);
extern void transport_complete_sync_cache(struct se_cmd *, int);
extern void transport_complete_task(struct se_task *, int);
extern void transport_add_task_to_execute_queue(struct se_task *,
@@ -142,6 +125,8 @@ extern void transport_add_task_to_execute_queue(struct se_task *,
struct se_device *);
extern void transport_remove_task_from_execute_queue(struct se_task *,
struct se_device *);
+extern void __transport_remove_task_from_execute_queue(struct se_task *,
+ struct se_device *);
unsigned char *transport_dump_cmd_direction(struct se_cmd *);
extern void transport_dump_dev_state(struct se_device *, char *, int *);
extern void transport_dump_dev_info(struct se_device *, struct se_lun *,
@@ -169,29 +154,24 @@ extern void transport_init_se_cmd(struct se_cmd *,
unsigned char *);
void *transport_kmap_first_data_page(struct se_cmd *cmd);
void transport_kunmap_first_data_page(struct se_cmd *cmd);
-extern void transport_free_se_cmd(struct se_cmd *);
extern int transport_generic_allocate_tasks(struct se_cmd *, unsigned char *);
-extern int transport_generic_handle_cdb(struct se_cmd *);
extern int transport_handle_cdb_direct(struct se_cmd *);
extern int transport_generic_handle_cdb_map(struct se_cmd *);
extern int transport_generic_handle_data(struct se_cmd *);
extern void transport_new_cmd_failure(struct se_cmd *);
extern int transport_generic_handle_tmr(struct se_cmd *);
extern void transport_generic_free_cmd_intr(struct se_cmd *);
-extern void __transport_stop_task_timer(struct se_task *, unsigned long *);
+extern bool target_stop_task(struct se_task *task, unsigned long *flags);
extern int transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *, u32,
struct scatterlist *, u32);
extern int transport_clear_lun_from_sessions(struct se_lun *);
+extern void transport_wait_for_tasks(struct se_cmd *);
extern int transport_check_aborted_status(struct se_cmd *, int);
extern int transport_send_check_condition_and_sense(struct se_cmd *, u8, int);
extern void transport_send_task_abort(struct se_cmd *);
extern void transport_release_cmd(struct se_cmd *);
-extern void transport_generic_free_cmd(struct se_cmd *, int, int);
+extern void transport_generic_free_cmd(struct se_cmd *, int);
extern void transport_generic_wait_for_cmds(struct se_cmd *, int);
-extern int transport_init_task_sg(struct se_task *, struct se_mem *, u32);
-extern int transport_map_mem_to_sg(struct se_task *, struct list_head *,
- struct scatterlist *, struct se_mem *,
- struct se_mem **, u32 *, u32 *);
extern void transport_do_task_sg_chain(struct se_cmd *);
extern void transport_generic_process_write(struct se_cmd *);
extern int transport_generic_new_cmd(struct se_cmd *);
@@ -200,6 +180,7 @@ extern int transport_generic_do_tmr(struct se_cmd *);
extern int core_alua_check_nonop_delay(struct se_cmd *);
/* From target_core_cdb.c */
extern int transport_emulate_control_cdb(struct se_task *);
+extern void target_get_task_cdb(struct se_task *task, unsigned char *cdb);
/*
* Each se_transport_task_t can have N number of possible struct se_task's
@@ -227,6 +208,10 @@ struct se_subsystem_api {
* Transport Type.
*/
u8 transport_type;
+
+ unsigned int fua_write_emulated : 1;
+ unsigned int write_cache_emulated : 1;
+
/*
* struct module for struct se_hba references
*/
@@ -236,18 +221,6 @@ struct se_subsystem_api {
*/
struct list_head sub_api_list;
/*
- * For SCF_SCSI_NON_DATA_CDB
- */
- int (*cdb_none)(struct se_task *);
- /*
- * For SCF_SCSI_DATA_SG_IO_CDB
- */
- int (*map_data_SG)(struct se_task *);
- /*
- * For SCF_SCSI_CONTROL_SG_IO_CDB
- */
- int (*map_control_SG)(struct se_task *);
- /*
* attach_hba():
*/
int (*attach_hba)(struct se_hba *, u32);
@@ -275,22 +248,6 @@ struct se_subsystem_api {
void (*free_device)(void *);
/*
- * dpo_emulated():
- */
- int (*dpo_emulated)(struct se_device *);
- /*
- * fua_write_emulated():
- */
- int (*fua_write_emulated)(struct se_device *);
- /*
- * fua_read_emulated():
- */
- int (*fua_read_emulated)(struct se_device *);
- /*
- * write_cache_emulated():
- */
- int (*write_cache_emulated)(struct se_device *);
- /*
* transport_complete():
*
* Use transport_generic_complete() for majority of DAS transport
@@ -331,10 +288,6 @@ struct se_subsystem_api {
ssize_t (*show_configfs_dev_params)(struct se_hba *, struct se_subsystem_dev *,
char *);
/*
- * get_cdb():
- */
- unsigned char *(*get_cdb)(struct se_task *);
- /*
* get_device_rev():
*/
u32 (*get_device_rev)(struct se_device *);
diff --git a/include/trace/events/9p.h b/include/trace/events/9p.h
new file mode 100644
index 000000000000..beeaed8398ec
--- /dev/null
+++ b/include/trace/events/9p.h
@@ -0,0 +1,176 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM 9p
+
+#if !defined(_TRACE_9P_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_9P_H
+
+#include <linux/tracepoint.h>
+
+#define show_9p_op(type) \
+ __print_symbolic(type, \
+ { P9_TLERROR, "P9_TLERROR" }, \
+ { P9_RLERROR, "P9_RLERROR" }, \
+ { P9_TSTATFS, "P9_TSTATFS" }, \
+ { P9_RSTATFS, "P9_RSTATFS" }, \
+ { P9_TLOPEN, "P9_TLOPEN" }, \
+ { P9_RLOPEN, "P9_RLOPEN" }, \
+ { P9_TLCREATE, "P9_TLCREATE" }, \
+ { P9_RLCREATE, "P9_RLCREATE" }, \
+ { P9_TSYMLINK, "P9_TSYMLINK" }, \
+ { P9_RSYMLINK, "P9_RSYMLINK" }, \
+ { P9_TMKNOD, "P9_TMKNOD" }, \
+ { P9_RMKNOD, "P9_RMKNOD" }, \
+ { P9_TRENAME, "P9_TRENAME" }, \
+ { P9_RRENAME, "P9_RRENAME" }, \
+ { P9_TREADLINK, "P9_TREADLINK" }, \
+ { P9_RREADLINK, "P9_RREADLINK" }, \
+ { P9_TGETATTR, "P9_TGETATTR" }, \
+ { P9_RGETATTR, "P9_RGETATTR" }, \
+ { P9_TSETATTR, "P9_TSETATTR" }, \
+ { P9_RSETATTR, "P9_RSETATTR" }, \
+ { P9_TXATTRWALK, "P9_TXATTRWALK" }, \
+ { P9_RXATTRWALK, "P9_RXATTRWALK" }, \
+ { P9_TXATTRCREATE, "P9_TXATTRCREATE" }, \
+ { P9_RXATTRCREATE, "P9_RXATTRCREATE" }, \
+ { P9_TREADDIR, "P9_TREADDIR" }, \
+ { P9_RREADDIR, "P9_RREADDIR" }, \
+ { P9_TFSYNC, "P9_TFSYNC" }, \
+ { P9_RFSYNC, "P9_RFSYNC" }, \
+ { P9_TLOCK, "P9_TLOCK" }, \
+ { P9_RLOCK, "P9_RLOCK" }, \
+ { P9_TGETLOCK, "P9_TGETLOCK" }, \
+ { P9_RGETLOCK, "P9_RGETLOCK" }, \
+ { P9_TLINK, "P9_TLINK" }, \
+ { P9_RLINK, "P9_RLINK" }, \
+ { P9_TMKDIR, "P9_TMKDIR" }, \
+ { P9_RMKDIR, "P9_RMKDIR" }, \
+ { P9_TRENAMEAT, "P9_TRENAMEAT" }, \
+ { P9_RRENAMEAT, "P9_RRENAMEAT" }, \
+ { P9_TUNLINKAT, "P9_TUNLINKAT" }, \
+ { P9_RUNLINKAT, "P9_RUNLINKAT" }, \
+ { P9_TVERSION, "P9_TVERSION" }, \
+ { P9_RVERSION, "P9_RVERSION" }, \
+ { P9_TAUTH, "P9_TAUTH" }, \
+ { P9_RAUTH, "P9_RAUTH" }, \
+ { P9_TATTACH, "P9_TATTACH" }, \
+ { P9_RATTACH, "P9_RATTACH" }, \
+ { P9_TERROR, "P9_TERROR" }, \
+ { P9_RERROR, "P9_RERROR" }, \
+ { P9_TFLUSH, "P9_TFLUSH" }, \
+ { P9_RFLUSH, "P9_RFLUSH" }, \
+ { P9_TWALK, "P9_TWALK" }, \
+ { P9_RWALK, "P9_RWALK" }, \
+ { P9_TOPEN, "P9_TOPEN" }, \
+ { P9_ROPEN, "P9_ROPEN" }, \
+ { P9_TCREATE, "P9_TCREATE" }, \
+ { P9_RCREATE, "P9_RCREATE" }, \
+ { P9_TREAD, "P9_TREAD" }, \
+ { P9_RREAD, "P9_RREAD" }, \
+ { P9_TWRITE, "P9_TWRITE" }, \
+ { P9_RWRITE, "P9_RWRITE" }, \
+ { P9_TCLUNK, "P9_TCLUNK" }, \
+ { P9_RCLUNK, "P9_RCLUNK" }, \
+ { P9_TREMOVE, "P9_TREMOVE" }, \
+ { P9_RREMOVE, "P9_RREMOVE" }, \
+ { P9_TSTAT, "P9_TSTAT" }, \
+ { P9_RSTAT, "P9_RSTAT" }, \
+ { P9_TWSTAT, "P9_TWSTAT" }, \
+ { P9_RWSTAT, "P9_RWSTAT" })
+
+TRACE_EVENT(9p_client_req,
+ TP_PROTO(struct p9_client *clnt, int8_t type, int tag),
+
+ TP_ARGS(clnt, type, tag),
+
+ TP_STRUCT__entry(
+ __field( void *, clnt )
+ __field( __u8, type )
+ __field( __u32, tag )
+ ),
+
+ TP_fast_assign(
+ __entry->clnt = clnt;
+ __entry->type = type;
+ __entry->tag = tag;
+ ),
+
+ TP_printk("client %lu request %s tag %d",
+ (long)__entry->clnt, show_9p_op(__entry->type),
+ __entry->tag)
+ );
+
+TRACE_EVENT(9p_client_res,
+ TP_PROTO(struct p9_client *clnt, int8_t type, int tag, int err),
+
+ TP_ARGS(clnt, type, tag, err),
+
+ TP_STRUCT__entry(
+ __field( void *, clnt )
+ __field( __u8, type )
+ __field( __u32, tag )
+ __field( __u32, err )
+ ),
+
+ TP_fast_assign(
+ __entry->clnt = clnt;
+ __entry->type = type;
+ __entry->tag = tag;
+ __entry->err = err;
+ ),
+
+ TP_printk("client %lu response %s tag %d err %d",
+ (long)__entry->clnt, show_9p_op(__entry->type),
+ __entry->tag, __entry->err)
+);
+
+/* dump 32 bytes of protocol data */
+#define P9_PROTO_DUMP_SZ 32
+TRACE_EVENT(9p_protocol_dump,
+ TP_PROTO(struct p9_client *clnt, struct p9_fcall *pdu),
+
+ TP_ARGS(clnt, pdu),
+
+ TP_STRUCT__entry(
+ __field( void *, clnt )
+ __field( __u8, type )
+ __field( __u16, tag )
+ __array( unsigned char, line, P9_PROTO_DUMP_SZ )
+ ),
+
+ TP_fast_assign(
+ __entry->clnt = clnt;
+ __entry->type = pdu->id;
+ __entry->tag = pdu->tag;
+ memcpy(__entry->line, pdu->sdata, P9_PROTO_DUMP_SZ);
+ ),
+ TP_printk("clnt %lu %s(tag = %d)\n%.3x: "
+ "%02x %02x %02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x %02x %02x %02x\n"
+ "%.3x: "
+ "%02x %02x %02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ (long)__entry->clnt, show_9p_op(__entry->type),
+ __entry->tag, 0,
+ __entry->line[0], __entry->line[1],
+ __entry->line[2], __entry->line[3],
+ __entry->line[4], __entry->line[5],
+ __entry->line[6], __entry->line[7],
+ __entry->line[8], __entry->line[9],
+ __entry->line[10], __entry->line[11],
+ __entry->line[12], __entry->line[13],
+ __entry->line[14], __entry->line[15],
+ 16,
+ __entry->line[16], __entry->line[17],
+ __entry->line[18], __entry->line[19],
+ __entry->line[20], __entry->line[21],
+ __entry->line[22], __entry->line[23],
+ __entry->line[24], __entry->line[25],
+ __entry->line[26], __entry->line[27],
+ __entry->line[28], __entry->line[29],
+ __entry->line[30], __entry->line[31])
+ );
+
+#endif /* _TRACE_9P_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/regmap.h b/include/trace/events/regmap.h
new file mode 100644
index 000000000000..1e3193b8fcc8
--- /dev/null
+++ b/include/trace/events/regmap.h
@@ -0,0 +1,136 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM regmap
+
+#if !defined(_TRACE_REGMAP_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_REGMAP_H
+
+#include <linux/device.h>
+#include <linux/ktime.h>
+#include <linux/tracepoint.h>
+
+struct regmap;
+
+/*
+ * Log register events
+ */
+DECLARE_EVENT_CLASS(regmap_reg,
+
+ TP_PROTO(struct device *dev, unsigned int reg,
+ unsigned int val),
+
+ TP_ARGS(dev, reg, val),
+
+ TP_STRUCT__entry(
+ __string( name, dev_name(dev) )
+ __field( unsigned int, reg )
+ __field( unsigned int, val )
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, dev_name(dev));
+ __entry->reg = reg;
+ __entry->val = val;
+ ),
+
+ TP_printk("%s reg=%x val=%x", __get_str(name),
+ (unsigned int)__entry->reg,
+ (unsigned int)__entry->val)
+);
+
+DEFINE_EVENT(regmap_reg, regmap_reg_write,
+
+ TP_PROTO(struct device *dev, unsigned int reg,
+ unsigned int val),
+
+ TP_ARGS(dev, reg, val)
+
+);
+
+DEFINE_EVENT(regmap_reg, regmap_reg_read,
+
+ TP_PROTO(struct device *dev, unsigned int reg,
+ unsigned int val),
+
+ TP_ARGS(dev, reg, val)
+
+);
+
+DECLARE_EVENT_CLASS(regmap_block,
+
+ TP_PROTO(struct device *dev, unsigned int reg, int count),
+
+ TP_ARGS(dev, reg, count),
+
+ TP_STRUCT__entry(
+ __string( name, dev_name(dev) )
+ __field( unsigned int, reg )
+ __field( int, count )
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, dev_name(dev));
+ __entry->reg = reg;
+ __entry->count = count;
+ ),
+
+ TP_printk("%s reg=%x count=%d", __get_str(name),
+ (unsigned int)__entry->reg,
+ (int)__entry->count)
+);
+
+DEFINE_EVENT(regmap_block, regmap_hw_read_start,
+
+ TP_PROTO(struct device *dev, unsigned int reg, int count),
+
+ TP_ARGS(dev, reg, count)
+);
+
+DEFINE_EVENT(regmap_block, regmap_hw_read_done,
+
+ TP_PROTO(struct device *dev, unsigned int reg, int count),
+
+ TP_ARGS(dev, reg, count)
+);
+
+DEFINE_EVENT(regmap_block, regmap_hw_write_start,
+
+ TP_PROTO(struct device *dev, unsigned int reg, int count),
+
+ TP_ARGS(dev, reg, count)
+);
+
+DEFINE_EVENT(regmap_block, regmap_hw_write_done,
+
+ TP_PROTO(struct device *dev, unsigned int reg, int count),
+
+ TP_ARGS(dev, reg, count)
+);
+
+TRACE_EVENT(regcache_sync,
+
+ TP_PROTO(struct device *dev, const char *type,
+ const char *status),
+
+ TP_ARGS(dev, type, status),
+
+ TP_STRUCT__entry(
+ __string( name, dev_name(dev) )
+ __string( status, status )
+ __string( type, type )
+ __field( int, type )
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, dev_name(dev));
+ __assign_str(status, status);
+ __assign_str(type, type);
+ ),
+
+ TP_printk("%s type=%s status=%s", __get_str(name),
+ __get_str(type), __get_str(status))
+);
+
+#endif /* _TRACE_REGMAP_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/rpm.h b/include/trace/events/rpm.h
new file mode 100644
index 000000000000..d62c558bf64b
--- /dev/null
+++ b/include/trace/events/rpm.h
@@ -0,0 +1,99 @@
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM rpm
+
+#if !defined(_TRACE_RUNTIME_POWER_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_RUNTIME_POWER_H
+
+#include <linux/ktime.h>
+#include <linux/tracepoint.h>
+#include <linux/device.h>
+
+/*
+ * The rpm_internal events are used for tracing some important
+ * runtime pm internal functions.
+ */
+DECLARE_EVENT_CLASS(rpm_internal,
+
+ TP_PROTO(struct device *dev, int flags),
+
+ TP_ARGS(dev, flags),
+
+ TP_STRUCT__entry(
+ __string( name, dev_name(dev) )
+ __field( int, flags )
+ __field( int , usage_count )
+ __field( int , disable_depth )
+ __field( int , runtime_auto )
+ __field( int , request_pending )
+ __field( int , irq_safe )
+ __field( int , child_count )
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, dev_name(dev));
+ __entry->flags = flags;
+ __entry->usage_count = atomic_read(
+ &dev->power.usage_count);
+ __entry->disable_depth = dev->power.disable_depth;
+ __entry->runtime_auto = dev->power.runtime_auto;
+ __entry->request_pending = dev->power.request_pending;
+ __entry->irq_safe = dev->power.irq_safe;
+ __entry->child_count = atomic_read(
+ &dev->power.child_count);
+ ),
+
+ TP_printk("%s flags-%x cnt-%-2d dep-%-2d auto-%-1d p-%-1d"
+ " irq-%-1d child-%d",
+ __get_str(name), __entry->flags,
+ __entry->usage_count,
+ __entry->disable_depth,
+ __entry->runtime_auto,
+ __entry->request_pending,
+ __entry->irq_safe,
+ __entry->child_count
+ )
+);
+DEFINE_EVENT(rpm_internal, rpm_suspend,
+
+ TP_PROTO(struct device *dev, int flags),
+
+ TP_ARGS(dev, flags)
+);
+DEFINE_EVENT(rpm_internal, rpm_resume,
+
+ TP_PROTO(struct device *dev, int flags),
+
+ TP_ARGS(dev, flags)
+);
+DEFINE_EVENT(rpm_internal, rpm_idle,
+
+ TP_PROTO(struct device *dev, int flags),
+
+ TP_ARGS(dev, flags)
+);
+
+TRACE_EVENT(rpm_return_int,
+ TP_PROTO(struct device *dev, unsigned long ip, int ret),
+ TP_ARGS(dev, ip, ret),
+
+ TP_STRUCT__entry(
+ __string( name, dev_name(dev))
+ __field( unsigned long, ip )
+ __field( int, ret )
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, dev_name(dev));
+ __entry->ip = ip;
+ __entry->ret = ret;
+ ),
+
+ TP_printk("%pS:%s ret=%d", (void *)__entry->ip, __get_str(name),
+ __entry->ret)
+);
+
+#endif /* _TRACE_RUNTIME_POWER_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h
index 6bca4cc0063c..5f172703eb4f 100644
--- a/include/trace/events/writeback.h
+++ b/include/trace/events/writeback.h
@@ -298,7 +298,7 @@ DECLARE_EVENT_CLASS(writeback_single_inode_template,
__array(char, name, 32)
__field(unsigned long, ino)
__field(unsigned long, state)
- __field(unsigned long, age)
+ __field(unsigned long, dirtied_when)
__field(unsigned long, writeback_index)
__field(long, nr_to_write)
__field(unsigned long, wrote)
@@ -309,19 +309,19 @@ DECLARE_EVENT_CLASS(writeback_single_inode_template,
dev_name(inode->i_mapping->backing_dev_info->dev), 32);
__entry->ino = inode->i_ino;
__entry->state = inode->i_state;
- __entry->age = (jiffies - inode->dirtied_when) *
- 1000 / HZ;
+ __entry->dirtied_when = inode->dirtied_when;
__entry->writeback_index = inode->i_mapping->writeback_index;
__entry->nr_to_write = nr_to_write;
__entry->wrote = nr_to_write - wbc->nr_to_write;
),
- TP_printk("bdi %s: ino=%lu state=%s age=%lu "
+ TP_printk("bdi %s: ino=%lu state=%s dirtied_when=%lu age=%lu "
"index=%lu to_write=%ld wrote=%lu",
__entry->name,
__entry->ino,
show_inode_state(__entry->state),
- __entry->age,
+ __entry->dirtied_when,
+ (jiffies - __entry->dirtied_when) / HZ,
__entry->writeback_index,
__entry->nr_to_write,
__entry->wrote
diff --git a/include/xen/balloon.h b/include/xen/balloon.h
index 76f7538bb339..d29c153705bc 100644
--- a/include/xen/balloon.h
+++ b/include/xen/balloon.h
@@ -25,8 +25,9 @@ extern struct balloon_stats balloon_stats;
void balloon_set_new_target(unsigned long target);
-int alloc_xenballooned_pages(int nr_pages, struct page** pages);
-void free_xenballooned_pages(int nr_pages, struct page** pages);
+int alloc_xenballooned_pages(int nr_pages, struct page **pages,
+ bool highmem);
+void free_xenballooned_pages(int nr_pages, struct page **pages);
struct sys_device;
#ifdef CONFIG_XEN_SELFBALLOONING
diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h
index b1fab6b5b3ef..6b99bfbd785d 100644
--- a/include/xen/grant_table.h
+++ b/include/xen/grant_table.h
@@ -156,6 +156,7 @@ unsigned int gnttab_max_grant_frames(void);
#define gnttab_map_vaddr(map) ((void *)(map.host_virt_addr))
int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
+ struct gnttab_map_grant_ref *kmap_ops,
struct page **pages, unsigned int count);
int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
struct page **pages, unsigned int count);
diff --git a/include/xen/interface/io/xs_wire.h b/include/xen/interface/io/xs_wire.h
index 99fcffb372d1..f0b6890370be 100644
--- a/include/xen/interface/io/xs_wire.h
+++ b/include/xen/interface/io/xs_wire.h
@@ -26,7 +26,11 @@ enum xsd_sockmsg_type
XS_SET_PERMS,
XS_WATCH_EVENT,
XS_ERROR,
- XS_IS_DOMAIN_INTRODUCED
+ XS_IS_DOMAIN_INTRODUCED,
+ XS_RESUME,
+ XS_SET_TARGET,
+ XS_RESTRICT,
+ XS_RESET_WATCHES
};
#define XS_WRITE_NONE "NONE"
diff --git a/include/xen/interface/physdev.h b/include/xen/interface/physdev.h
index 534cac89a77d..c1080d9c705d 100644
--- a/include/xen/interface/physdev.h
+++ b/include/xen/interface/physdev.h
@@ -109,6 +109,7 @@ struct physdev_irq {
#define MAP_PIRQ_TYPE_MSI 0x0
#define MAP_PIRQ_TYPE_GSI 0x1
#define MAP_PIRQ_TYPE_UNKNOWN 0x2
+#define MAP_PIRQ_TYPE_MSI_SEG 0x3
#define PHYSDEVOP_map_pirq 13
struct physdev_map_pirq {
@@ -119,7 +120,7 @@ struct physdev_map_pirq {
int index;
/* IN or OUT */
int pirq;
- /* IN */
+ /* IN - high 16 bits hold segment for MAP_PIRQ_TYPE_MSI_SEG */
int bus;
/* IN */
int devfn;
@@ -198,6 +199,37 @@ struct physdev_get_free_pirq {
uint32_t pirq;
};
+#define XEN_PCI_DEV_EXTFN 0x1
+#define XEN_PCI_DEV_VIRTFN 0x2
+#define XEN_PCI_DEV_PXM 0x4
+
+#define PHYSDEVOP_pci_device_add 25
+struct physdev_pci_device_add {
+ /* IN */
+ uint16_t seg;
+ uint8_t bus;
+ uint8_t devfn;
+ uint32_t flags;
+ struct {
+ uint8_t bus;
+ uint8_t devfn;
+ } physfn;
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+ uint32_t optarr[];
+#elif defined(__GNUC__)
+ uint32_t optarr[0];
+#endif
+};
+
+#define PHYSDEVOP_pci_device_remove 26
+#define PHYSDEVOP_restore_msi_ext 27
+struct physdev_pci_device {
+ /* IN */
+ uint16_t seg;
+ uint8_t bus;
+ uint8_t devfn;
+};
+
/*
* Notify that some PIRQ-bound event channels have been unmasked.
* ** This command is obsolete since interface version 0x00030202 and is **
diff --git a/include/xen/page.h b/include/xen/page.h
index 0be36b976f4b..12765b6f9517 100644
--- a/include/xen/page.h
+++ b/include/xen/page.h
@@ -3,6 +3,16 @@
#include <asm/xen/page.h>
-extern phys_addr_t xen_extra_mem_start, xen_extra_mem_size;
+struct xen_memory_region {
+ phys_addr_t start;
+ phys_addr_t size;
+};
+
+#define XEN_EXTRA_MEM_MAX_REGIONS 128 /* == E820MAX */
+
+extern __initdata
+struct xen_memory_region xen_extra_mem[XEN_EXTRA_MEM_MAX_REGIONS];
+
+extern unsigned long xen_released_pages;
#endif /* _XEN_PAGE_H */
diff --git a/init/main.c b/init/main.c
index 9c51ee7adf3d..63f5f6f8dc3b 100644
--- a/init/main.c
+++ b/init/main.c
@@ -163,7 +163,7 @@ static int __init obsolete_checksetup(char *line)
p = __setup_start;
do {
int n = strlen(p->str);
- if (!strncmp(line, p->str, n)) {
+ if (parameqn(line, p->str, n)) {
if (p->early) {
/* Already done in parse_early_param?
* (Needs exact match on param part).
@@ -209,8 +209,19 @@ early_param("quiet", quiet_kernel);
static int __init loglevel(char *str)
{
- get_option(&str, &console_loglevel);
- return 0;
+ int newlevel;
+
+ /*
+ * Only update loglevel value when a correct setting was passed,
+ * to prevent blind crashes (when loglevel being set to 0) that
+ * are quite hard to debug
+ */
+ if (get_option(&str, &newlevel)) {
+ console_loglevel = newlevel;
+ return 0;
+ }
+
+ return -EINVAL;
}
early_param("loglevel", loglevel);
@@ -370,9 +381,6 @@ static noinline void __init_refok rest_init(void)
preempt_enable_no_resched();
schedule();
- /* At this point, we can enable user mode helper functionality */
- usermodehelper_enable();
-
/* Call into cpu_idle with preempt disabled */
preempt_disable();
cpu_idle();
@@ -384,7 +392,7 @@ static int __init do_early_param(char *param, char *val)
const struct obs_kernel_param *p;
for (p = __setup_start; p < __setup_end; p++) {
- if ((p->early && strcmp(param, p->str) == 0) ||
+ if ((p->early && parameq(param, p->str)) ||
(strcmp(param, "console") == 0 &&
strcmp(p->str, "earlycon") == 0)
) {
@@ -722,6 +730,7 @@ static void __init do_basic_setup(void)
driver_init();
init_irq_proc();
do_ctors();
+ usermodehelper_enable();
do_initcalls();
}
diff --git a/kernel/Makefile b/kernel/Makefile
index eca595e2fd52..2da48d3515eb 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -9,7 +9,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o \
rcupdate.o extable.o params.o posix-timers.o \
kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
- notifier.o ksysfs.o pm_qos_params.o sched_clock.o cred.o \
+ notifier.o ksysfs.o sched_clock.o cred.o \
async.o range.o
obj-y += groups.o
diff --git a/kernel/async.c b/kernel/async.c
index d5fe7af0de2e..4c2843c0043e 100644
--- a/kernel/async.c
+++ b/kernel/async.c
@@ -120,7 +120,7 @@ static void async_run_entry_fn(struct work_struct *work)
struct async_entry *entry =
container_of(work, struct async_entry, work);
unsigned long flags;
- ktime_t calltime, delta, rettime;
+ ktime_t uninitialized_var(calltime), delta, rettime;
/* 1) move self to the running queue */
spin_lock_irqsave(&async_lock, flags);
@@ -269,7 +269,7 @@ EXPORT_SYMBOL_GPL(async_synchronize_full_domain);
void async_synchronize_cookie_domain(async_cookie_t cookie,
struct list_head *running)
{
- ktime_t starttime, delta, endtime;
+ ktime_t uninitialized_var(starttime), delta, endtime;
if (initcall_debug && system_state == SYSTEM_BOOTING) {
printk(KERN_DEBUG "async_waiting @ %i\n", task_pid_nr(current));
diff --git a/kernel/cred.c b/kernel/cred.c
index 8ef31f53c44c..bb55d052d858 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -644,6 +644,9 @@ void __init cred_init(void)
*/
struct cred *prepare_kernel_cred(struct task_struct *daemon)
{
+#ifdef CONFIG_KEYS
+ struct thread_group_cred *tgcred;
+#endif
const struct cred *old;
struct cred *new;
@@ -651,6 +654,14 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
if (!new)
return NULL;
+#ifdef CONFIG_KEYS
+ tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
+ if (!tgcred) {
+ kmem_cache_free(cred_jar, new);
+ return NULL;
+ }
+#endif
+
kdebug("prepare_kernel_cred() alloc %p", new);
if (daemon)
@@ -667,8 +678,11 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
get_group_info(new->group_info);
#ifdef CONFIG_KEYS
- atomic_inc(&init_tgcred.usage);
- new->tgcred = &init_tgcred;
+ atomic_set(&tgcred->usage, 1);
+ spin_lock_init(&tgcred->lock);
+ tgcred->process_keyring = NULL;
+ tgcred->session_keyring = NULL;
+ new->tgcred = tgcred;
new->request_key_auth = NULL;
new->thread_keyring = NULL;
new->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
diff --git a/kernel/events/core.c b/kernel/events/core.c
index b8785e26ee1c..0f857782d06f 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -399,14 +399,54 @@ void perf_cgroup_switch(struct task_struct *task, int mode)
local_irq_restore(flags);
}
-static inline void perf_cgroup_sched_out(struct task_struct *task)
+static inline void perf_cgroup_sched_out(struct task_struct *task,
+ struct task_struct *next)
{
- perf_cgroup_switch(task, PERF_CGROUP_SWOUT);
+ struct perf_cgroup *cgrp1;
+ struct perf_cgroup *cgrp2 = NULL;
+
+ /*
+ * we come here when we know perf_cgroup_events > 0
+ */
+ cgrp1 = perf_cgroup_from_task(task);
+
+ /*
+ * next is NULL when called from perf_event_enable_on_exec()
+ * that will systematically cause a cgroup_switch()
+ */
+ if (next)
+ cgrp2 = perf_cgroup_from_task(next);
+
+ /*
+ * only schedule out current cgroup events if we know
+ * that we are switching to a different cgroup. Otherwise,
+ * do no touch the cgroup events.
+ */
+ if (cgrp1 != cgrp2)
+ perf_cgroup_switch(task, PERF_CGROUP_SWOUT);
}
-static inline void perf_cgroup_sched_in(struct task_struct *task)
+static inline void perf_cgroup_sched_in(struct task_struct *prev,
+ struct task_struct *task)
{
- perf_cgroup_switch(task, PERF_CGROUP_SWIN);
+ struct perf_cgroup *cgrp1;
+ struct perf_cgroup *cgrp2 = NULL;
+
+ /*
+ * we come here when we know perf_cgroup_events > 0
+ */
+ cgrp1 = perf_cgroup_from_task(task);
+
+ /* prev can never be NULL */
+ cgrp2 = perf_cgroup_from_task(prev);
+
+ /*
+ * only need to schedule in cgroup events if we are changing
+ * cgroup during ctxsw. Cgroup events were not scheduled
+ * out of ctxsw out if that was not the case.
+ */
+ if (cgrp1 != cgrp2)
+ perf_cgroup_switch(task, PERF_CGROUP_SWIN);
}
static inline int perf_cgroup_connect(int fd, struct perf_event *event,
@@ -518,11 +558,13 @@ static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx)
{
}
-static inline void perf_cgroup_sched_out(struct task_struct *task)
+static inline void perf_cgroup_sched_out(struct task_struct *task,
+ struct task_struct *next)
{
}
-static inline void perf_cgroup_sched_in(struct task_struct *task)
+static inline void perf_cgroup_sched_in(struct task_struct *prev,
+ struct task_struct *task)
{
}
@@ -1988,7 +2030,7 @@ void __perf_event_task_sched_out(struct task_struct *task,
* cgroup event are system-wide mode only
*/
if (atomic_read(&__get_cpu_var(perf_cgroup_events)))
- perf_cgroup_sched_out(task);
+ perf_cgroup_sched_out(task, next);
}
static void task_ctx_sched_out(struct perf_event_context *ctx)
@@ -2153,7 +2195,8 @@ static void perf_event_context_sched_in(struct perf_event_context *ctx,
* accessing the event control register. If a NMI hits, then it will
* keep the event running.
*/
-void __perf_event_task_sched_in(struct task_struct *task)
+void __perf_event_task_sched_in(struct task_struct *prev,
+ struct task_struct *task)
{
struct perf_event_context *ctx;
int ctxn;
@@ -2171,7 +2214,7 @@ void __perf_event_task_sched_in(struct task_struct *task)
* cgroup event are system-wide mode only
*/
if (atomic_read(&__get_cpu_var(perf_cgroup_events)))
- perf_cgroup_sched_in(task);
+ perf_cgroup_sched_in(prev, task);
}
static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count)
@@ -2427,7 +2470,7 @@ static void perf_event_enable_on_exec(struct perf_event_context *ctx)
* ctxswin cgroup events which are already scheduled
* in.
*/
- perf_cgroup_sched_out(current);
+ perf_cgroup_sched_out(current, NULL);
raw_spin_lock(&ctx->lock);
task_ctx_sched_out(ctx);
@@ -3353,8 +3396,8 @@ static int perf_event_index(struct perf_event *event)
}
static void calc_timer_values(struct perf_event *event,
- u64 *running,
- u64 *enabled)
+ u64 *enabled,
+ u64 *running)
{
u64 now, ctx_time;
diff --git a/kernel/freezer.c b/kernel/freezer.c
index 7b01de98bb6a..66a594e8ad2f 100644
--- a/kernel/freezer.c
+++ b/kernel/freezer.c
@@ -67,7 +67,7 @@ static void fake_signal_wake_up(struct task_struct *p)
unsigned long flags;
spin_lock_irqsave(&p->sighand->siglock, flags);
- signal_wake_up(p, 0);
+ signal_wake_up(p, 1);
spin_unlock_irqrestore(&p->sighand->siglock, flags);
}
diff --git a/kernel/futex.c b/kernel/futex.c
index 11cbe052b2e8..1511dff0cfd6 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -854,7 +854,7 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
{
struct task_struct *new_owner;
struct futex_pi_state *pi_state = this->pi_state;
- u32 curval, newval;
+ u32 uninitialized_var(curval), newval;
if (!pi_state)
return -EINVAL;
@@ -916,7 +916,7 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
static int unlock_futex_pi(u32 __user *uaddr, u32 uval)
{
- u32 oldval;
+ u32 uninitialized_var(oldval);
/*
* There is no waiter, so we unlock the futex. The owner died
@@ -1576,7 +1576,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
u32 newtid = task_pid_vnr(newowner) | FUTEX_WAITERS;
struct futex_pi_state *pi_state = q->pi_state;
struct task_struct *oldowner = pi_state->owner;
- u32 uval, curval, newval;
+ u32 uval, uninitialized_var(curval), newval;
int ret;
/* Owner died? */
@@ -1793,7 +1793,7 @@ static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q,
*
* Returns:
* 0 - uaddr contains val and hb has been locked
- * <1 - -EFAULT or -EWOULDBLOCK (uaddr does not contain val) and hb is unlcoked
+ * <1 - -EFAULT or -EWOULDBLOCK (uaddr does not contain val) and hb is unlocked
*/
static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
struct futex_q *q, struct futex_hash_bucket **hb)
@@ -2481,7 +2481,7 @@ err_unlock:
*/
int handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi)
{
- u32 uval, nval, mval;
+ u32 uval, uninitialized_var(nval), mval;
retry:
if (get_user(uval, uaddr))
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index d5a3009da71a..dc5114b4c16c 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -178,7 +178,7 @@ void irq_shutdown(struct irq_desc *desc)
desc->depth = 1;
if (desc->irq_data.chip->irq_shutdown)
desc->irq_data.chip->irq_shutdown(&desc->irq_data);
- if (desc->irq_data.chip->irq_disable)
+ else if (desc->irq_data.chip->irq_disable)
desc->irq_data.chip->irq_disable(&desc->irq_data);
else
desc->irq_data.chip->irq_mask(&desc->irq_data);
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index d5828da3fd38..b57a3776de44 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -29,7 +29,11 @@ void irq_domain_add(struct irq_domain *domain)
*/
for (hwirq = 0; hwirq < domain->nr_irq; hwirq++) {
d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq));
- if (d || d->domain) {
+ if (!d) {
+ WARN(1, "error: assigning domain to non existant irq_desc");
+ return;
+ }
+ if (d->domain) {
/* things are broken; just report, don't clean up */
WARN(1, "error: irq_desc already assigned to a domain");
return;
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 2e9425889fa8..9b956fa20308 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -1331,7 +1331,6 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler,
if (!thread_fn)
return -EINVAL;
handler = irq_default_primary_handler;
- irqflags |= IRQF_ONESHOT;
}
action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
diff --git a/kernel/kmod.c b/kernel/kmod.c
index ddc7644c1305..a4bea97c75b6 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -114,10 +114,12 @@ int __request_module(bool wait, const char *fmt, ...)
atomic_inc(&kmod_concurrent);
if (atomic_read(&kmod_concurrent) > max_modprobes) {
/* We may be blaming an innocent here, but unlikely */
- if (kmod_loop_msg++ < 5)
+ if (kmod_loop_msg < 5) {
printk(KERN_ERR
"request_module: runaway loop modprobe %s\n",
module_name);
+ kmod_loop_msg++;
+ }
atomic_dec(&kmod_concurrent);
return -ENOMEM;
}
diff --git a/kernel/params.c b/kernel/params.c
index 22df3e0d142a..821788947e40 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -67,20 +67,27 @@ static void maybe_kfree_parameter(void *param)
}
}
-static inline char dash2underscore(char c)
+static char dash2underscore(char c)
{
if (c == '-')
return '_';
return c;
}
-static inline int parameq(const char *input, const char *paramname)
+bool parameqn(const char *a, const char *b, size_t n)
{
- unsigned int i;
- for (i = 0; dash2underscore(input[i]) == paramname[i]; i++)
- if (input[i] == '\0')
- return 1;
- return 0;
+ size_t i;
+
+ for (i = 0; i < n; i++) {
+ if (dash2underscore(a[i]) != dash2underscore(b[i]))
+ return false;
+ }
+ return true;
+}
+
+bool parameq(const char *a, const char *b)
+{
+ return parameqn(a, b, strlen(a)+1);
}
static int parse_one(char *param,
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
index 58f405b581e7..640ded8f5c48 100644
--- a/kernel/posix-cpu-timers.c
+++ b/kernel/posix-cpu-timers.c
@@ -250,7 +250,7 @@ void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times)
do {
times->utime = cputime_add(times->utime, t->utime);
times->stime = cputime_add(times->stime, t->stime);
- times->sum_exec_runtime += t->se.sum_exec_runtime;
+ times->sum_exec_runtime += task_sched_runtime(t);
} while_each_thread(tsk, t);
out:
rcu_read_unlock();
@@ -274,9 +274,7 @@ void thread_group_cputimer(struct task_struct *tsk, struct task_cputime *times)
struct task_cputime sum;
unsigned long flags;
- spin_lock_irqsave(&cputimer->lock, flags);
if (!cputimer->running) {
- cputimer->running = 1;
/*
* The POSIX timer interface allows for absolute time expiry
* values through the TIMER_ABSTIME flag, therefore we have
@@ -284,8 +282,11 @@ void thread_group_cputimer(struct task_struct *tsk, struct task_cputime *times)
* it.
*/
thread_group_cputime(tsk, &sum);
+ spin_lock_irqsave(&cputimer->lock, flags);
+ cputimer->running = 1;
update_gt_cputime(&cputimer->cputime, &sum);
- }
+ } else
+ spin_lock_irqsave(&cputimer->lock, flags);
*times = cputimer->cputime;
spin_unlock_irqrestore(&cputimer->lock, flags);
}
@@ -312,7 +313,8 @@ static int cpu_clock_sample_group(const clockid_t which_clock,
cpu->cpu = cputime.utime;
break;
case CPUCLOCK_SCHED:
- cpu->sched = thread_group_sched_runtime(p);
+ thread_group_cputime(p, &cputime);
+ cpu->sched = cputime.sum_exec_runtime;
break;
}
return 0;
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 3744c594b19b..cedd9982306a 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -27,6 +27,7 @@ config HIBERNATION
select HIBERNATE_CALLBACKS
select LZO_COMPRESS
select LZO_DECOMPRESS
+ select CRC32
---help---
Enable the suspend to disk (STD) functionality, which is usually
called "hibernation" in user interfaces. STD checkpoints the
@@ -65,6 +66,9 @@ config HIBERNATION
For more information take a look at <file:Documentation/power/swsusp.txt>.
+config ARCH_SAVE_PAGE_KEYS
+ bool
+
config PM_STD_PARTITION
string "Default resume partition"
depends on HIBERNATION
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index c5ebc6a90643..07e0e28ffba7 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -1,8 +1,8 @@
ccflags-$(CONFIG_PM_DEBUG) := -DDEBUG
-obj-$(CONFIG_PM) += main.o
-obj-$(CONFIG_PM_SLEEP) += console.o
+obj-$(CONFIG_PM) += main.o qos.o
+obj-$(CONFIG_VT_CONSOLE_SLEEP) += console.o
obj-$(CONFIG_FREEZER) += process.o
obj-$(CONFIG_SUSPEND) += suspend.o
obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o
diff --git a/kernel/power/console.c b/kernel/power/console.c
index 218e5af90156..b1dc456474b5 100644
--- a/kernel/power/console.c
+++ b/kernel/power/console.c
@@ -1,5 +1,5 @@
/*
- * drivers/power/process.c - Functions for saving/restoring console.
+ * Functions for saving/restoring console.
*
* Originally from swsusp.
*/
@@ -10,7 +10,6 @@
#include <linux/module.h>
#include "power.h"
-#if defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE)
#define SUSPEND_CONSOLE (MAX_NR_CONSOLES-1)
static int orig_fgconsole, orig_kmsg;
@@ -32,4 +31,3 @@ void pm_restore_console(void)
vt_kmsg_redirect(orig_kmsg);
}
}
-#endif
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 8f7b1db1ece1..1c53f7fad5f7 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -14,6 +14,7 @@
#include <linux/reboot.h>
#include <linux/string.h>
#include <linux/device.h>
+#include <linux/async.h>
#include <linux/kmod.h>
#include <linux/delay.h>
#include <linux/fs.h>
@@ -29,12 +30,14 @@
#include "power.h"
-static int nocompress = 0;
-static int noresume = 0;
+static int nocompress;
+static int noresume;
+static int resume_wait;
+static int resume_delay;
static char resume_file[256] = CONFIG_PM_STD_PARTITION;
dev_t swsusp_resume_device;
sector_t swsusp_resume_block;
-int in_suspend __nosavedata = 0;
+int in_suspend __nosavedata;
enum {
HIBERNATION_INVALID,
@@ -334,13 +337,17 @@ int hibernation_snapshot(int platform_mode)
if (error)
goto Close;
- error = dpm_prepare(PMSG_FREEZE);
- if (error)
- goto Complete_devices;
-
/* Preallocate image memory before shutting down devices. */
error = hibernate_preallocate_memory();
if (error)
+ goto Close;
+
+ error = freeze_kernel_threads();
+ if (error)
+ goto Close;
+
+ error = dpm_prepare(PMSG_FREEZE);
+ if (error)
goto Complete_devices;
suspend_console();
@@ -463,7 +470,7 @@ static int resume_target_kernel(bool platform_mode)
* @platform_mode: If set, use platform driver to prepare for the transition.
*
* This routine must be called with pm_mutex held. If it is successful, control
- * reappears in the restored target kernel in hibernation_snaphot().
+ * reappears in the restored target kernel in hibernation_snapshot().
*/
int hibernation_restore(int platform_mode)
{
@@ -650,6 +657,9 @@ int hibernate(void)
flags |= SF_PLATFORM_MODE;
if (nocompress)
flags |= SF_NOCOMPRESS_MODE;
+ else
+ flags |= SF_CRC32_MODE;
+
pr_debug("PM: writing image.\n");
error = swsusp_write(flags);
swsusp_free();
@@ -724,6 +734,12 @@ static int software_resume(void)
pr_debug("PM: Checking hibernation image partition %s\n", resume_file);
+ if (resume_delay) {
+ printk(KERN_INFO "Waiting %dsec before reading resume device...\n",
+ resume_delay);
+ ssleep(resume_delay);
+ }
+
/* Check if the device is there */
swsusp_resume_device = name_to_dev_t(resume_file);
if (!swsusp_resume_device) {
@@ -732,6 +748,13 @@ static int software_resume(void)
* to wait for this to finish.
*/
wait_for_device_probe();
+
+ if (resume_wait) {
+ while ((swsusp_resume_device = name_to_dev_t(resume_file)) == 0)
+ msleep(10);
+ async_synchronize_full();
+ }
+
/*
* We can't depend on SCSI devices being available after loading
* one of their modules until scsi_complete_async_scans() is
@@ -1060,7 +1083,21 @@ static int __init noresume_setup(char *str)
return 1;
}
+static int __init resumewait_setup(char *str)
+{
+ resume_wait = 1;
+ return 1;
+}
+
+static int __init resumedelay_setup(char *str)
+{
+ resume_delay = simple_strtoul(str, NULL, 0);
+ return 1;
+}
+
__setup("noresume", noresume_setup);
__setup("resume_offset=", resume_offset_setup);
__setup("resume=", resume_setup);
__setup("hibernate=", hibernate_setup);
+__setup("resumewait", resumewait_setup);
+__setup("resumedelay=", resumedelay_setup);
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 6c601f871964..a52e88425a31 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -12,6 +12,8 @@
#include <linux/string.h>
#include <linux/resume-trace.h>
#include <linux/workqueue.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
#include "power.h"
@@ -131,6 +133,101 @@ static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr,
power_attr(pm_test);
#endif /* CONFIG_PM_DEBUG */
+#ifdef CONFIG_DEBUG_FS
+static char *suspend_step_name(enum suspend_stat_step step)
+{
+ switch (step) {
+ case SUSPEND_FREEZE:
+ return "freeze";
+ case SUSPEND_PREPARE:
+ return "prepare";
+ case SUSPEND_SUSPEND:
+ return "suspend";
+ case SUSPEND_SUSPEND_NOIRQ:
+ return "suspend_noirq";
+ case SUSPEND_RESUME_NOIRQ:
+ return "resume_noirq";
+ case SUSPEND_RESUME:
+ return "resume";
+ default:
+ return "";
+ }
+}
+
+static int suspend_stats_show(struct seq_file *s, void *unused)
+{
+ int i, index, last_dev, last_errno, last_step;
+
+ last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1;
+ last_dev %= REC_FAILED_NUM;
+ last_errno = suspend_stats.last_failed_errno + REC_FAILED_NUM - 1;
+ last_errno %= REC_FAILED_NUM;
+ last_step = suspend_stats.last_failed_step + REC_FAILED_NUM - 1;
+ last_step %= REC_FAILED_NUM;
+ seq_printf(s, "%s: %d\n%s: %d\n%s: %d\n%s: %d\n"
+ "%s: %d\n%s: %d\n%s: %d\n%s: %d\n",
+ "success", suspend_stats.success,
+ "fail", suspend_stats.fail,
+ "failed_freeze", suspend_stats.failed_freeze,
+ "failed_prepare", suspend_stats.failed_prepare,
+ "failed_suspend", suspend_stats.failed_suspend,
+ "failed_suspend_noirq",
+ suspend_stats.failed_suspend_noirq,
+ "failed_resume", suspend_stats.failed_resume,
+ "failed_resume_noirq",
+ suspend_stats.failed_resume_noirq);
+ seq_printf(s, "failures:\n last_failed_dev:\t%-s\n",
+ suspend_stats.failed_devs[last_dev]);
+ for (i = 1; i < REC_FAILED_NUM; i++) {
+ index = last_dev + REC_FAILED_NUM - i;
+ index %= REC_FAILED_NUM;
+ seq_printf(s, "\t\t\t%-s\n",
+ suspend_stats.failed_devs[index]);
+ }
+ seq_printf(s, " last_failed_errno:\t%-d\n",
+ suspend_stats.errno[last_errno]);
+ for (i = 1; i < REC_FAILED_NUM; i++) {
+ index = last_errno + REC_FAILED_NUM - i;
+ index %= REC_FAILED_NUM;
+ seq_printf(s, "\t\t\t%-d\n",
+ suspend_stats.errno[index]);
+ }
+ seq_printf(s, " last_failed_step:\t%-s\n",
+ suspend_step_name(
+ suspend_stats.failed_steps[last_step]));
+ for (i = 1; i < REC_FAILED_NUM; i++) {
+ index = last_step + REC_FAILED_NUM - i;
+ index %= REC_FAILED_NUM;
+ seq_printf(s, "\t\t\t%-s\n",
+ suspend_step_name(
+ suspend_stats.failed_steps[index]));
+ }
+
+ return 0;
+}
+
+static int suspend_stats_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, suspend_stats_show, NULL);
+}
+
+static const struct file_operations suspend_stats_operations = {
+ .open = suspend_stats_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int __init pm_debugfs_init(void)
+{
+ debugfs_create_file("suspend_stats", S_IFREG | S_IRUGO,
+ NULL, NULL, &suspend_stats_operations);
+ return 0;
+}
+
+late_initcall(pm_debugfs_init);
+#endif /* CONFIG_DEBUG_FS */
+
#endif /* CONFIG_PM_SLEEP */
struct kobject *power_kobj;
@@ -194,6 +291,11 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
}
if (state < PM_SUSPEND_MAX && *s)
error = enter_state(state);
+ if (error) {
+ suspend_stats.fail++;
+ dpm_save_failed_errno(error);
+ } else
+ suspend_stats.success++;
#endif
Exit:
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 9a00a0a26280..23a2db1ec442 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -146,6 +146,7 @@ extern int swsusp_swap_in_use(void);
*/
#define SF_PLATFORM_MODE 1
#define SF_NOCOMPRESS_MODE 2
+#define SF_CRC32_MODE 4
/* kernel/power/hibernate.c */
extern int swsusp_check(void);
@@ -228,7 +229,8 @@ extern int pm_test_level;
#ifdef CONFIG_SUSPEND_FREEZER
static inline int suspend_freeze_processes(void)
{
- return freeze_processes();
+ int error = freeze_processes();
+ return error ? : freeze_kernel_threads();
}
static inline void suspend_thaw_processes(void)
diff --git a/kernel/power/process.c b/kernel/power/process.c
index 0cf3a27a6c9d..addbbe5531bc 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -135,7 +135,7 @@ static int try_to_freeze_tasks(bool sig_only)
}
/**
- * freeze_processes - tell processes to enter the refrigerator
+ * freeze_processes - Signal user space processes to enter the refrigerator.
*/
int freeze_processes(void)
{
@@ -143,20 +143,30 @@ int freeze_processes(void)
printk("Freezing user space processes ... ");
error = try_to_freeze_tasks(true);
- if (error)
- goto Exit;
- printk("done.\n");
+ if (!error) {
+ printk("done.");
+ oom_killer_disable();
+ }
+ printk("\n");
+ BUG_ON(in_atomic());
+
+ return error;
+}
+
+/**
+ * freeze_kernel_threads - Make freezable kernel threads go to the refrigerator.
+ */
+int freeze_kernel_threads(void)
+{
+ int error;
printk("Freezing remaining freezable tasks ... ");
error = try_to_freeze_tasks(false);
- if (error)
- goto Exit;
- printk("done.");
+ if (!error)
+ printk("done.");
- oom_killer_disable();
- Exit:
- BUG_ON(in_atomic());
printk("\n");
+ BUG_ON(in_atomic());
return error;
}
diff --git a/kernel/pm_qos_params.c b/kernel/power/qos.c
index 37f05d0f0793..1c1797dd1d1d 100644
--- a/kernel/pm_qos_params.c
+++ b/kernel/power/qos.c
@@ -29,7 +29,7 @@
/*#define DEBUG*/
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -45,62 +45,57 @@
#include <linux/uaccess.h>
/*
- * locking rule: all changes to requests or notifiers lists
+ * locking rule: all changes to constraints or notifiers lists
* or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
* held, taken with _irqsave. One lock to rule them all
*/
-enum pm_qos_type {
- PM_QOS_MAX, /* return the largest value */
- PM_QOS_MIN /* return the smallest value */
-};
-
-/*
- * Note: The lockless read path depends on the CPU accessing
- * target_value atomically. Atomic access is only guaranteed on all CPU
- * types linux supports for 32 bit quantites
- */
struct pm_qos_object {
- struct plist_head requests;
- struct blocking_notifier_head *notifiers;
+ struct pm_qos_constraints *constraints;
struct miscdevice pm_qos_power_miscdev;
char *name;
- s32 target_value; /* Do not change to 64 bit */
- s32 default_value;
- enum pm_qos_type type;
};
static DEFINE_SPINLOCK(pm_qos_lock);
static struct pm_qos_object null_pm_qos;
+
static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
-static struct pm_qos_object cpu_dma_pm_qos = {
- .requests = PLIST_HEAD_INIT(cpu_dma_pm_qos.requests),
- .notifiers = &cpu_dma_lat_notifier,
- .name = "cpu_dma_latency",
+static struct pm_qos_constraints cpu_dma_constraints = {
+ .list = PLIST_HEAD_INIT(cpu_dma_constraints.list),
.target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
.default_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
.type = PM_QOS_MIN,
+ .notifiers = &cpu_dma_lat_notifier,
+};
+static struct pm_qos_object cpu_dma_pm_qos = {
+ .constraints = &cpu_dma_constraints,
};
static BLOCKING_NOTIFIER_HEAD(network_lat_notifier);
-static struct pm_qos_object network_lat_pm_qos = {
- .requests = PLIST_HEAD_INIT(network_lat_pm_qos.requests),
- .notifiers = &network_lat_notifier,
- .name = "network_latency",
+static struct pm_qos_constraints network_lat_constraints = {
+ .list = PLIST_HEAD_INIT(network_lat_constraints.list),
.target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
.default_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
- .type = PM_QOS_MIN
+ .type = PM_QOS_MIN,
+ .notifiers = &network_lat_notifier,
+};
+static struct pm_qos_object network_lat_pm_qos = {
+ .constraints = &network_lat_constraints,
+ .name = "network_latency",
};
static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
-static struct pm_qos_object network_throughput_pm_qos = {
- .requests = PLIST_HEAD_INIT(network_throughput_pm_qos.requests),
- .notifiers = &network_throughput_notifier,
- .name = "network_throughput",
+static struct pm_qos_constraints network_tput_constraints = {
+ .list = PLIST_HEAD_INIT(network_tput_constraints.list),
.target_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
.default_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
.type = PM_QOS_MAX,
+ .notifiers = &network_throughput_notifier,
+};
+static struct pm_qos_object network_throughput_pm_qos = {
+ .constraints = &network_tput_constraints,
+ .name = "network_throughput",
};
@@ -127,17 +122,17 @@ static const struct file_operations pm_qos_power_fops = {
};
/* unlocked internal variant */
-static inline int pm_qos_get_value(struct pm_qos_object *o)
+static inline int pm_qos_get_value(struct pm_qos_constraints *c)
{
- if (plist_head_empty(&o->requests))
- return o->default_value;
+ if (plist_head_empty(&c->list))
+ return c->default_value;
- switch (o->type) {
+ switch (c->type) {
case PM_QOS_MIN:
- return plist_first(&o->requests)->prio;
+ return plist_first(&c->list)->prio;
case PM_QOS_MAX:
- return plist_last(&o->requests)->prio;
+ return plist_last(&c->list)->prio;
default:
/* runtime check for not using enum */
@@ -145,69 +140,73 @@ static inline int pm_qos_get_value(struct pm_qos_object *o)
}
}
-static inline s32 pm_qos_read_value(struct pm_qos_object *o)
+s32 pm_qos_read_value(struct pm_qos_constraints *c)
{
- return o->target_value;
+ return c->target_value;
}
-static inline void pm_qos_set_value(struct pm_qos_object *o, s32 value)
+static inline void pm_qos_set_value(struct pm_qos_constraints *c, s32 value)
{
- o->target_value = value;
+ c->target_value = value;
}
-static void update_target(struct pm_qos_object *o, struct plist_node *node,
- int del, int value)
+/**
+ * pm_qos_update_target - manages the constraints list and calls the notifiers
+ * if needed
+ * @c: constraints data struct
+ * @node: request to add to the list, to update or to remove
+ * @action: action to take on the constraints list
+ * @value: value of the request to add or update
+ *
+ * This function returns 1 if the aggregated constraint value has changed, 0
+ * otherwise.
+ */
+int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node,
+ enum pm_qos_req_action action, int value)
{
unsigned long flags;
- int prev_value, curr_value;
+ int prev_value, curr_value, new_value;
spin_lock_irqsave(&pm_qos_lock, flags);
- prev_value = pm_qos_get_value(o);
- /* PM_QOS_DEFAULT_VALUE is a signal that the value is unchanged */
- if (value != PM_QOS_DEFAULT_VALUE) {
+ prev_value = pm_qos_get_value(c);
+ if (value == PM_QOS_DEFAULT_VALUE)
+ new_value = c->default_value;
+ else
+ new_value = value;
+
+ switch (action) {
+ case PM_QOS_REMOVE_REQ:
+ plist_del(node, &c->list);
+ break;
+ case PM_QOS_UPDATE_REQ:
/*
* to change the list, we atomically remove, reinit
* with new value and add, then see if the extremal
* changed
*/
- plist_del(node, &o->requests);
- plist_node_init(node, value);
- plist_add(node, &o->requests);
- } else if (del) {
- plist_del(node, &o->requests);
- } else {
- plist_add(node, &o->requests);
+ plist_del(node, &c->list);
+ case PM_QOS_ADD_REQ:
+ plist_node_init(node, new_value);
+ plist_add(node, &c->list);
+ break;
+ default:
+ /* no action */
+ ;
}
- curr_value = pm_qos_get_value(o);
- pm_qos_set_value(o, curr_value);
+
+ curr_value = pm_qos_get_value(c);
+ pm_qos_set_value(c, curr_value);
+
spin_unlock_irqrestore(&pm_qos_lock, flags);
- if (prev_value != curr_value)
- blocking_notifier_call_chain(o->notifiers,
+ if (prev_value != curr_value) {
+ blocking_notifier_call_chain(c->notifiers,
(unsigned long)curr_value,
NULL);
-}
-
-static int register_pm_qos_misc(struct pm_qos_object *qos)
-{
- qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
- qos->pm_qos_power_miscdev.name = qos->name;
- qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
-
- return misc_register(&qos->pm_qos_power_miscdev);
-}
-
-static int find_pm_qos_object_by_minor(int minor)
-{
- int pm_qos_class;
-
- for (pm_qos_class = 0;
- pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
- if (minor ==
- pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
- return pm_qos_class;
+ return 1;
+ } else {
+ return 0;
}
- return -1;
}
/**
@@ -218,11 +217,11 @@ static int find_pm_qos_object_by_minor(int minor)
*/
int pm_qos_request(int pm_qos_class)
{
- return pm_qos_read_value(pm_qos_array[pm_qos_class]);
+ return pm_qos_read_value(pm_qos_array[pm_qos_class]->constraints);
}
EXPORT_SYMBOL_GPL(pm_qos_request);
-int pm_qos_request_active(struct pm_qos_request_list *req)
+int pm_qos_request_active(struct pm_qos_request *req)
{
return req->pm_qos_class != 0;
}
@@ -230,40 +229,36 @@ EXPORT_SYMBOL_GPL(pm_qos_request_active);
/**
* pm_qos_add_request - inserts new qos request into the list
- * @dep: pointer to a preallocated handle
+ * @req: pointer to a preallocated handle
* @pm_qos_class: identifies which list of qos request to use
* @value: defines the qos request
*
* This function inserts a new entry in the pm_qos_class list of requested qos
* performance characteristics. It recomputes the aggregate QoS expectations
- * for the pm_qos_class of parameters and initializes the pm_qos_request_list
+ * for the pm_qos_class of parameters and initializes the pm_qos_request
* handle. Caller needs to save this handle for later use in updates and
* removal.
*/
-void pm_qos_add_request(struct pm_qos_request_list *dep,
+void pm_qos_add_request(struct pm_qos_request *req,
int pm_qos_class, s32 value)
{
- struct pm_qos_object *o = pm_qos_array[pm_qos_class];
- int new_value;
+ if (!req) /*guard against callers passing in null */
+ return;
- if (pm_qos_request_active(dep)) {
+ if (pm_qos_request_active(req)) {
WARN(1, KERN_ERR "pm_qos_add_request() called for already added request\n");
return;
}
- if (value == PM_QOS_DEFAULT_VALUE)
- new_value = o->default_value;
- else
- new_value = value;
- plist_node_init(&dep->list, new_value);
- dep->pm_qos_class = pm_qos_class;
- update_target(o, &dep->list, 0, PM_QOS_DEFAULT_VALUE);
+ req->pm_qos_class = pm_qos_class;
+ pm_qos_update_target(pm_qos_array[pm_qos_class]->constraints,
+ &req->node, PM_QOS_ADD_REQ, value);
}
EXPORT_SYMBOL_GPL(pm_qos_add_request);
/**
* pm_qos_update_request - modifies an existing qos request
- * @pm_qos_req : handle to list element holding a pm_qos request to use
+ * @req : handle to list element holding a pm_qos request to use
* @value: defines the qos request
*
* Updates an existing qos request for the pm_qos_class of parameters along
@@ -271,56 +266,47 @@ EXPORT_SYMBOL_GPL(pm_qos_add_request);
*
* Attempts are made to make this code callable on hot code paths.
*/
-void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
+void pm_qos_update_request(struct pm_qos_request *req,
s32 new_value)
{
- s32 temp;
- struct pm_qos_object *o;
-
- if (!pm_qos_req) /*guard against callers passing in null */
+ if (!req) /*guard against callers passing in null */
return;
- if (!pm_qos_request_active(pm_qos_req)) {
+ if (!pm_qos_request_active(req)) {
WARN(1, KERN_ERR "pm_qos_update_request() called for unknown object\n");
return;
}
- o = pm_qos_array[pm_qos_req->pm_qos_class];
-
- if (new_value == PM_QOS_DEFAULT_VALUE)
- temp = o->default_value;
- else
- temp = new_value;
-
- if (temp != pm_qos_req->list.prio)
- update_target(o, &pm_qos_req->list, 0, temp);
+ if (new_value != req->node.prio)
+ pm_qos_update_target(
+ pm_qos_array[req->pm_qos_class]->constraints,
+ &req->node, PM_QOS_UPDATE_REQ, new_value);
}
EXPORT_SYMBOL_GPL(pm_qos_update_request);
/**
* pm_qos_remove_request - modifies an existing qos request
- * @pm_qos_req: handle to request list element
+ * @req: handle to request list element
*
- * Will remove pm qos request from the list of requests and
+ * Will remove pm qos request from the list of constraints and
* recompute the current target value for the pm_qos_class. Call this
* on slow code paths.
*/
-void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req)
+void pm_qos_remove_request(struct pm_qos_request *req)
{
- struct pm_qos_object *o;
-
- if (pm_qos_req == NULL)
+ if (!req) /*guard against callers passing in null */
return;
/* silent return to keep pcm code cleaner */
- if (!pm_qos_request_active(pm_qos_req)) {
+ if (!pm_qos_request_active(req)) {
WARN(1, KERN_ERR "pm_qos_remove_request() called for unknown object\n");
return;
}
- o = pm_qos_array[pm_qos_req->pm_qos_class];
- update_target(o, &pm_qos_req->list, 1, PM_QOS_DEFAULT_VALUE);
- memset(pm_qos_req, 0, sizeof(*pm_qos_req));
+ pm_qos_update_target(pm_qos_array[req->pm_qos_class]->constraints,
+ &req->node, PM_QOS_REMOVE_REQ,
+ PM_QOS_DEFAULT_VALUE);
+ memset(req, 0, sizeof(*req));
}
EXPORT_SYMBOL_GPL(pm_qos_remove_request);
@@ -337,7 +323,8 @@ int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier)
int retval;
retval = blocking_notifier_chain_register(
- pm_qos_array[pm_qos_class]->notifiers, notifier);
+ pm_qos_array[pm_qos_class]->constraints->notifiers,
+ notifier);
return retval;
}
@@ -356,19 +343,43 @@ int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier)
int retval;
retval = blocking_notifier_chain_unregister(
- pm_qos_array[pm_qos_class]->notifiers, notifier);
+ pm_qos_array[pm_qos_class]->constraints->notifiers,
+ notifier);
return retval;
}
EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
+/* User space interface to PM QoS classes via misc devices */
+static int register_pm_qos_misc(struct pm_qos_object *qos)
+{
+ qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
+ qos->pm_qos_power_miscdev.name = qos->name;
+ qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
+
+ return misc_register(&qos->pm_qos_power_miscdev);
+}
+
+static int find_pm_qos_object_by_minor(int minor)
+{
+ int pm_qos_class;
+
+ for (pm_qos_class = 0;
+ pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
+ if (minor ==
+ pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
+ return pm_qos_class;
+ }
+ return -1;
+}
+
static int pm_qos_power_open(struct inode *inode, struct file *filp)
{
long pm_qos_class;
pm_qos_class = find_pm_qos_object_by_minor(iminor(inode));
if (pm_qos_class >= 0) {
- struct pm_qos_request_list *req = kzalloc(sizeof(*req), GFP_KERNEL);
+ struct pm_qos_request *req = kzalloc(sizeof(*req), GFP_KERNEL);
if (!req)
return -ENOMEM;
@@ -383,7 +394,7 @@ static int pm_qos_power_open(struct inode *inode, struct file *filp)
static int pm_qos_power_release(struct inode *inode, struct file *filp)
{
- struct pm_qos_request_list *req;
+ struct pm_qos_request *req;
req = filp->private_data;
pm_qos_remove_request(req);
@@ -398,17 +409,15 @@ static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
{
s32 value;
unsigned long flags;
- struct pm_qos_object *o;
- struct pm_qos_request_list *pm_qos_req = filp->private_data;
+ struct pm_qos_request *req = filp->private_data;
- if (!pm_qos_req)
+ if (!req)
return -EINVAL;
- if (!pm_qos_request_active(pm_qos_req))
+ if (!pm_qos_request_active(req))
return -EINVAL;
- o = pm_qos_array[pm_qos_req->pm_qos_class];
spin_lock_irqsave(&pm_qos_lock, flags);
- value = pm_qos_get_value(o);
+ value = pm_qos_get_value(pm_qos_array[req->pm_qos_class]->constraints);
spin_unlock_irqrestore(&pm_qos_lock, flags);
return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32));
@@ -418,7 +427,7 @@ static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
size_t count, loff_t *f_pos)
{
s32 value;
- struct pm_qos_request_list *pm_qos_req;
+ struct pm_qos_request *req;
if (count == sizeof(s32)) {
if (copy_from_user(&value, buf, sizeof(s32)))
@@ -449,8 +458,8 @@ static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
return -EINVAL;
}
- pm_qos_req = filp->private_data;
- pm_qos_update_request(pm_qos_req, value);
+ req = filp->private_data;
+ pm_qos_update_request(req, value);
return count;
}
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 06efa54f93d6..cbe2c1441392 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -1339,6 +1339,9 @@ int hibernate_preallocate_memory(void)
count += highmem;
count -= totalreserve_pages;
+ /* Add number of pages required for page keys (s390 only). */
+ size += page_key_additional_pages(saveable);
+
/* Compute the maximum number of saveable pages to leave in memory. */
max_size = (count - (size + PAGES_FOR_IO)) / 2
- 2 * DIV_ROUND_UP(reserved_size, PAGE_SIZE);
@@ -1662,6 +1665,8 @@ pack_pfns(unsigned long *buf, struct memory_bitmap *bm)
buf[j] = memory_bm_next_pfn(bm);
if (unlikely(buf[j] == BM_END_OF_MAP))
break;
+ /* Save page key for data page (s390 only). */
+ page_key_read(buf + j);
}
}
@@ -1821,6 +1826,9 @@ static int unpack_orig_pfns(unsigned long *buf, struct memory_bitmap *bm)
if (unlikely(buf[j] == BM_END_OF_MAP))
break;
+ /* Extract and buffer page key for data page (s390 only). */
+ page_key_memorize(buf + j);
+
if (memory_bm_pfn_present(bm, buf[j]))
memory_bm_set_bit(bm, buf[j]);
else
@@ -2223,6 +2231,11 @@ int snapshot_write_next(struct snapshot_handle *handle)
if (error)
return error;
+ /* Allocate buffer for page keys. */
+ error = page_key_alloc(nr_copy_pages);
+ if (error)
+ return error;
+
} else if (handle->cur <= nr_meta_pages + 1) {
error = unpack_orig_pfns(buffer, &copy_bm);
if (error)
@@ -2243,6 +2256,8 @@ int snapshot_write_next(struct snapshot_handle *handle)
}
} else {
copy_last_highmem_page();
+ /* Restore page key for data page (s390 only). */
+ page_key_write(handle->buffer);
handle->buffer = get_buffer(&orig_bm, &ca);
if (IS_ERR(handle->buffer))
return PTR_ERR(handle->buffer);
@@ -2264,6 +2279,9 @@ int snapshot_write_next(struct snapshot_handle *handle)
void snapshot_write_finalize(struct snapshot_handle *handle)
{
copy_last_highmem_page();
+ /* Restore page key for data page (s390 only). */
+ page_key_write(handle->buffer);
+ page_key_free();
/* Free only if we have loaded the image entirely */
if (handle->cur > 1 && handle->cur > nr_meta_pages + nr_copy_pages) {
memory_bm_free(&orig_bm, PG_UNSAFE_CLEAR);
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index b6b71ad2208f..fdd4263b995d 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -104,7 +104,10 @@ static int suspend_prepare(void)
goto Finish;
error = suspend_freeze_processes();
- if (!error)
+ if (error) {
+ suspend_stats.failed_freeze++;
+ dpm_save_failed_step(SUSPEND_FREEZE);
+ } else
return 0;
suspend_thaw_processes();
@@ -315,8 +318,16 @@ int enter_state(suspend_state_t state)
*/
int pm_suspend(suspend_state_t state)
{
- if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX)
- return enter_state(state);
+ int ret;
+ if (state > PM_SUSPEND_ON && state < PM_SUSPEND_MAX) {
+ ret = enter_state(state);
+ if (ret) {
+ suspend_stats.fail++;
+ dpm_save_failed_errno(ret);
+ } else
+ suspend_stats.success++;
+ return ret;
+ }
return -EINVAL;
}
EXPORT_SYMBOL(pm_suspend);
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 7c97c3a0eee3..11a594c4ba25 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -27,6 +27,10 @@
#include <linux/slab.h>
#include <linux/lzo.h>
#include <linux/vmalloc.h>
+#include <linux/cpumask.h>
+#include <linux/atomic.h>
+#include <linux/kthread.h>
+#include <linux/crc32.h>
#include "power.h"
@@ -43,8 +47,7 @@
* allocated and populated one at a time, so we only need one memory
* page to set up the entire structure.
*
- * During resume we also only need to use one swap_map_page structure
- * at a time.
+ * During resume we pick up all swap_map_page structures into a list.
*/
#define MAP_PAGE_ENTRIES (PAGE_SIZE / sizeof(sector_t) - 1)
@@ -54,6 +57,11 @@ struct swap_map_page {
sector_t next_swap;
};
+struct swap_map_page_list {
+ struct swap_map_page *map;
+ struct swap_map_page_list *next;
+};
+
/**
* The swap_map_handle structure is used for handling swap in
* a file-alike way
@@ -61,13 +69,18 @@ struct swap_map_page {
struct swap_map_handle {
struct swap_map_page *cur;
+ struct swap_map_page_list *maps;
sector_t cur_swap;
sector_t first_sector;
unsigned int k;
+ unsigned long nr_free_pages, written;
+ u32 crc32;
};
struct swsusp_header {
- char reserved[PAGE_SIZE - 20 - sizeof(sector_t) - sizeof(int)];
+ char reserved[PAGE_SIZE - 20 - sizeof(sector_t) - sizeof(int) -
+ sizeof(u32)];
+ u32 crc32;
sector_t image;
unsigned int flags; /* Flags to pass to the "boot" kernel */
char orig_sig[10];
@@ -199,6 +212,8 @@ static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags)
memcpy(swsusp_header->sig, HIBERNATE_SIG, 10);
swsusp_header->image = handle->first_sector;
swsusp_header->flags = flags;
+ if (flags & SF_CRC32_MODE)
+ swsusp_header->crc32 = handle->crc32;
error = hib_bio_write_page(swsusp_resume_block,
swsusp_header, NULL);
} else {
@@ -245,6 +260,7 @@ static int swsusp_swap_check(void)
static int write_page(void *buf, sector_t offset, struct bio **bio_chain)
{
void *src;
+ int ret;
if (!offset)
return -ENOSPC;
@@ -254,9 +270,17 @@ static int write_page(void *buf, sector_t offset, struct bio **bio_chain)
if (src) {
copy_page(src, buf);
} else {
- WARN_ON_ONCE(1);
- bio_chain = NULL; /* Go synchronous */
- src = buf;
+ ret = hib_wait_on_bio_chain(bio_chain); /* Free pages */
+ if (ret)
+ return ret;
+ src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
+ if (src) {
+ copy_page(src, buf);
+ } else {
+ WARN_ON_ONCE(1);
+ bio_chain = NULL; /* Go synchronous */
+ src = buf;
+ }
}
} else {
src = buf;
@@ -293,6 +317,8 @@ static int get_swap_writer(struct swap_map_handle *handle)
goto err_rel;
}
handle->k = 0;
+ handle->nr_free_pages = nr_free_pages() >> 1;
+ handle->written = 0;
handle->first_sector = handle->cur_swap;
return 0;
err_rel:
@@ -316,20 +342,23 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
return error;
handle->cur->entries[handle->k++] = offset;
if (handle->k >= MAP_PAGE_ENTRIES) {
- error = hib_wait_on_bio_chain(bio_chain);
- if (error)
- goto out;
offset = alloc_swapdev_block(root_swap);
if (!offset)
return -ENOSPC;
handle->cur->next_swap = offset;
- error = write_page(handle->cur, handle->cur_swap, NULL);
+ error = write_page(handle->cur, handle->cur_swap, bio_chain);
if (error)
goto out;
clear_page(handle->cur);
handle->cur_swap = offset;
handle->k = 0;
}
+ if (bio_chain && ++handle->written > handle->nr_free_pages) {
+ error = hib_wait_on_bio_chain(bio_chain);
+ if (error)
+ goto out;
+ handle->written = 0;
+ }
out:
return error;
}
@@ -372,6 +401,13 @@ static int swap_writer_finish(struct swap_map_handle *handle,
LZO_HEADER, PAGE_SIZE)
#define LZO_CMP_SIZE (LZO_CMP_PAGES * PAGE_SIZE)
+/* Maximum number of threads for compression/decompression. */
+#define LZO_THREADS 3
+
+/* Maximum number of pages for read buffering. */
+#define LZO_READ_PAGES (MAP_PAGE_ENTRIES * 8)
+
+
/**
* save_image - save the suspend image data
*/
@@ -419,6 +455,92 @@ static int save_image(struct swap_map_handle *handle,
return ret;
}
+/**
+ * Structure used for CRC32.
+ */
+struct crc_data {
+ struct task_struct *thr; /* thread */
+ atomic_t ready; /* ready to start flag */
+ atomic_t stop; /* ready to stop flag */
+ unsigned run_threads; /* nr current threads */
+ wait_queue_head_t go; /* start crc update */
+ wait_queue_head_t done; /* crc update done */
+ u32 *crc32; /* points to handle's crc32 */
+ size_t *unc_len[LZO_THREADS]; /* uncompressed lengths */
+ unsigned char *unc[LZO_THREADS]; /* uncompressed data */
+};
+
+/**
+ * CRC32 update function that runs in its own thread.
+ */
+static int crc32_threadfn(void *data)
+{
+ struct crc_data *d = data;
+ unsigned i;
+
+ while (1) {
+ wait_event(d->go, atomic_read(&d->ready) ||
+ kthread_should_stop());
+ if (kthread_should_stop()) {
+ d->thr = NULL;
+ atomic_set(&d->stop, 1);
+ wake_up(&d->done);
+ break;
+ }
+ atomic_set(&d->ready, 0);
+
+ for (i = 0; i < d->run_threads; i++)
+ *d->crc32 = crc32_le(*d->crc32,
+ d->unc[i], *d->unc_len[i]);
+ atomic_set(&d->stop, 1);
+ wake_up(&d->done);
+ }
+ return 0;
+}
+/**
+ * Structure used for LZO data compression.
+ */
+struct cmp_data {
+ struct task_struct *thr; /* thread */
+ atomic_t ready; /* ready to start flag */
+ atomic_t stop; /* ready to stop flag */
+ int ret; /* return code */
+ wait_queue_head_t go; /* start compression */
+ wait_queue_head_t done; /* compression done */
+ size_t unc_len; /* uncompressed length */
+ size_t cmp_len; /* compressed length */
+ unsigned char unc[LZO_UNC_SIZE]; /* uncompressed buffer */
+ unsigned char cmp[LZO_CMP_SIZE]; /* compressed buffer */
+ unsigned char wrk[LZO1X_1_MEM_COMPRESS]; /* compression workspace */
+};
+
+/**
+ * Compression function that runs in its own thread.
+ */
+static int lzo_compress_threadfn(void *data)
+{
+ struct cmp_data *d = data;
+
+ while (1) {
+ wait_event(d->go, atomic_read(&d->ready) ||
+ kthread_should_stop());
+ if (kthread_should_stop()) {
+ d->thr = NULL;
+ d->ret = -1;
+ atomic_set(&d->stop, 1);
+ wake_up(&d->done);
+ break;
+ }
+ atomic_set(&d->ready, 0);
+
+ d->ret = lzo1x_1_compress(d->unc, d->unc_len,
+ d->cmp + LZO_HEADER, &d->cmp_len,
+ d->wrk);
+ atomic_set(&d->stop, 1);
+ wake_up(&d->done);
+ }
+ return 0;
+}
/**
* save_image_lzo - Save the suspend image data compressed with LZO.
@@ -437,42 +559,93 @@ static int save_image_lzo(struct swap_map_handle *handle,
struct bio *bio;
struct timeval start;
struct timeval stop;
- size_t off, unc_len, cmp_len;
- unsigned char *unc, *cmp, *wrk, *page;
+ size_t off;
+ unsigned thr, run_threads, nr_threads;
+ unsigned char *page = NULL;
+ struct cmp_data *data = NULL;
+ struct crc_data *crc = NULL;
+
+ /*
+ * We'll limit the number of threads for compression to limit memory
+ * footprint.
+ */
+ nr_threads = num_online_cpus() - 1;
+ nr_threads = clamp_val(nr_threads, 1, LZO_THREADS);
page = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
if (!page) {
printk(KERN_ERR "PM: Failed to allocate LZO page\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out_clean;
}
- wrk = vmalloc(LZO1X_1_MEM_COMPRESS);
- if (!wrk) {
- printk(KERN_ERR "PM: Failed to allocate LZO workspace\n");
- free_page((unsigned long)page);
- return -ENOMEM;
+ data = vmalloc(sizeof(*data) * nr_threads);
+ if (!data) {
+ printk(KERN_ERR "PM: Failed to allocate LZO data\n");
+ ret = -ENOMEM;
+ goto out_clean;
}
+ for (thr = 0; thr < nr_threads; thr++)
+ memset(&data[thr], 0, offsetof(struct cmp_data, go));
- unc = vmalloc(LZO_UNC_SIZE);
- if (!unc) {
- printk(KERN_ERR "PM: Failed to allocate LZO uncompressed\n");
- vfree(wrk);
- free_page((unsigned long)page);
- return -ENOMEM;
+ crc = kmalloc(sizeof(*crc), GFP_KERNEL);
+ if (!crc) {
+ printk(KERN_ERR "PM: Failed to allocate crc\n");
+ ret = -ENOMEM;
+ goto out_clean;
+ }
+ memset(crc, 0, offsetof(struct crc_data, go));
+
+ /*
+ * Start the compression threads.
+ */
+ for (thr = 0; thr < nr_threads; thr++) {
+ init_waitqueue_head(&data[thr].go);
+ init_waitqueue_head(&data[thr].done);
+
+ data[thr].thr = kthread_run(lzo_compress_threadfn,
+ &data[thr],
+ "image_compress/%u", thr);
+ if (IS_ERR(data[thr].thr)) {
+ data[thr].thr = NULL;
+ printk(KERN_ERR
+ "PM: Cannot start compression threads\n");
+ ret = -ENOMEM;
+ goto out_clean;
+ }
}
- cmp = vmalloc(LZO_CMP_SIZE);
- if (!cmp) {
- printk(KERN_ERR "PM: Failed to allocate LZO compressed\n");
- vfree(unc);
- vfree(wrk);
- free_page((unsigned long)page);
- return -ENOMEM;
+ /*
+ * Adjust number of free pages after all allocations have been done.
+ * We don't want to run out of pages when writing.
+ */
+ handle->nr_free_pages = nr_free_pages() >> 1;
+
+ /*
+ * Start the CRC32 thread.
+ */
+ init_waitqueue_head(&crc->go);
+ init_waitqueue_head(&crc->done);
+
+ handle->crc32 = 0;
+ crc->crc32 = &handle->crc32;
+ for (thr = 0; thr < nr_threads; thr++) {
+ crc->unc[thr] = data[thr].unc;
+ crc->unc_len[thr] = &data[thr].unc_len;
+ }
+
+ crc->thr = kthread_run(crc32_threadfn, crc, "image_crc32");
+ if (IS_ERR(crc->thr)) {
+ crc->thr = NULL;
+ printk(KERN_ERR "PM: Cannot start CRC32 thread\n");
+ ret = -ENOMEM;
+ goto out_clean;
}
printk(KERN_INFO
+ "PM: Using %u thread(s) for compression.\n"
"PM: Compressing and saving image data (%u pages) ... ",
- nr_to_write);
+ nr_threads, nr_to_write);
m = nr_to_write / 100;
if (!m)
m = 1;
@@ -480,55 +653,83 @@ static int save_image_lzo(struct swap_map_handle *handle,
bio = NULL;
do_gettimeofday(&start);
for (;;) {
- for (off = 0; off < LZO_UNC_SIZE; off += PAGE_SIZE) {
- ret = snapshot_read_next(snapshot);
- if (ret < 0)
- goto out_finish;
-
- if (!ret)
+ for (thr = 0; thr < nr_threads; thr++) {
+ for (off = 0; off < LZO_UNC_SIZE; off += PAGE_SIZE) {
+ ret = snapshot_read_next(snapshot);
+ if (ret < 0)
+ goto out_finish;
+
+ if (!ret)
+ break;
+
+ memcpy(data[thr].unc + off,
+ data_of(*snapshot), PAGE_SIZE);
+
+ if (!(nr_pages % m))
+ printk(KERN_CONT "\b\b\b\b%3d%%",
+ nr_pages / m);
+ nr_pages++;
+ }
+ if (!off)
break;
- memcpy(unc + off, data_of(*snapshot), PAGE_SIZE);
+ data[thr].unc_len = off;
- if (!(nr_pages % m))
- printk(KERN_CONT "\b\b\b\b%3d%%", nr_pages / m);
- nr_pages++;
+ atomic_set(&data[thr].ready, 1);
+ wake_up(&data[thr].go);
}
- if (!off)
+ if (!thr)
break;
- unc_len = off;
- ret = lzo1x_1_compress(unc, unc_len,
- cmp + LZO_HEADER, &cmp_len, wrk);
- if (ret < 0) {
- printk(KERN_ERR "PM: LZO compression failed\n");
- break;
- }
+ crc->run_threads = thr;
+ atomic_set(&crc->ready, 1);
+ wake_up(&crc->go);
- if (unlikely(!cmp_len ||
- cmp_len > lzo1x_worst_compress(unc_len))) {
- printk(KERN_ERR "PM: Invalid LZO compressed length\n");
- ret = -1;
- break;
- }
+ for (run_threads = thr, thr = 0; thr < run_threads; thr++) {
+ wait_event(data[thr].done,
+ atomic_read(&data[thr].stop));
+ atomic_set(&data[thr].stop, 0);
- *(size_t *)cmp = cmp_len;
+ ret = data[thr].ret;
- /*
- * Given we are writing one page at a time to disk, we copy
- * that much from the buffer, although the last bit will likely
- * be smaller than full page. This is OK - we saved the length
- * of the compressed data, so any garbage at the end will be
- * discarded when we read it.
- */
- for (off = 0; off < LZO_HEADER + cmp_len; off += PAGE_SIZE) {
- memcpy(page, cmp + off, PAGE_SIZE);
+ if (ret < 0) {
+ printk(KERN_ERR "PM: LZO compression failed\n");
+ goto out_finish;
+ }
- ret = swap_write_page(handle, page, &bio);
- if (ret)
+ if (unlikely(!data[thr].cmp_len ||
+ data[thr].cmp_len >
+ lzo1x_worst_compress(data[thr].unc_len))) {
+ printk(KERN_ERR
+ "PM: Invalid LZO compressed length\n");
+ ret = -1;
goto out_finish;
+ }
+
+ *(size_t *)data[thr].cmp = data[thr].cmp_len;
+
+ /*
+ * Given we are writing one page at a time to disk, we
+ * copy that much from the buffer, although the last
+ * bit will likely be smaller than full page. This is
+ * OK - we saved the length of the compressed data, so
+ * any garbage at the end will be discarded when we
+ * read it.
+ */
+ for (off = 0;
+ off < LZO_HEADER + data[thr].cmp_len;
+ off += PAGE_SIZE) {
+ memcpy(page, data[thr].cmp + off, PAGE_SIZE);
+
+ ret = swap_write_page(handle, page, &bio);
+ if (ret)
+ goto out_finish;
+ }
}
+
+ wait_event(crc->done, atomic_read(&crc->stop));
+ atomic_set(&crc->stop, 0);
}
out_finish:
@@ -536,16 +737,25 @@ out_finish:
do_gettimeofday(&stop);
if (!ret)
ret = err2;
- if (!ret)
+ if (!ret) {
printk(KERN_CONT "\b\b\b\bdone\n");
- else
+ } else {
printk(KERN_CONT "\n");
+ }
swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
-
- vfree(cmp);
- vfree(unc);
- vfree(wrk);
- free_page((unsigned long)page);
+out_clean:
+ if (crc) {
+ if (crc->thr)
+ kthread_stop(crc->thr);
+ kfree(crc);
+ }
+ if (data) {
+ for (thr = 0; thr < nr_threads; thr++)
+ if (data[thr].thr)
+ kthread_stop(data[thr].thr);
+ vfree(data);
+ }
+ if (page) free_page((unsigned long)page);
return ret;
}
@@ -625,8 +835,15 @@ out_finish:
static void release_swap_reader(struct swap_map_handle *handle)
{
- if (handle->cur)
- free_page((unsigned long)handle->cur);
+ struct swap_map_page_list *tmp;
+
+ while (handle->maps) {
+ if (handle->maps->map)
+ free_page((unsigned long)handle->maps->map);
+ tmp = handle->maps;
+ handle->maps = handle->maps->next;
+ kfree(tmp);
+ }
handle->cur = NULL;
}
@@ -634,22 +851,46 @@ static int get_swap_reader(struct swap_map_handle *handle,
unsigned int *flags_p)
{
int error;
+ struct swap_map_page_list *tmp, *last;
+ sector_t offset;
*flags_p = swsusp_header->flags;
if (!swsusp_header->image) /* how can this happen? */
return -EINVAL;
- handle->cur = (struct swap_map_page *)get_zeroed_page(__GFP_WAIT | __GFP_HIGH);
- if (!handle->cur)
- return -ENOMEM;
+ handle->cur = NULL;
+ last = handle->maps = NULL;
+ offset = swsusp_header->image;
+ while (offset) {
+ tmp = kmalloc(sizeof(*handle->maps), GFP_KERNEL);
+ if (!tmp) {
+ release_swap_reader(handle);
+ return -ENOMEM;
+ }
+ memset(tmp, 0, sizeof(*tmp));
+ if (!handle->maps)
+ handle->maps = tmp;
+ if (last)
+ last->next = tmp;
+ last = tmp;
+
+ tmp->map = (struct swap_map_page *)
+ __get_free_page(__GFP_WAIT | __GFP_HIGH);
+ if (!tmp->map) {
+ release_swap_reader(handle);
+ return -ENOMEM;
+ }
- error = hib_bio_read_page(swsusp_header->image, handle->cur, NULL);
- if (error) {
- release_swap_reader(handle);
- return error;
+ error = hib_bio_read_page(offset, tmp->map, NULL);
+ if (error) {
+ release_swap_reader(handle);
+ return error;
+ }
+ offset = tmp->map->next_swap;
}
handle->k = 0;
+ handle->cur = handle->maps->map;
return 0;
}
@@ -658,6 +899,7 @@ static int swap_read_page(struct swap_map_handle *handle, void *buf,
{
sector_t offset;
int error;
+ struct swap_map_page_list *tmp;
if (!handle->cur)
return -EINVAL;
@@ -668,13 +910,15 @@ static int swap_read_page(struct swap_map_handle *handle, void *buf,
if (error)
return error;
if (++handle->k >= MAP_PAGE_ENTRIES) {
- error = hib_wait_on_bio_chain(bio_chain);
handle->k = 0;
- offset = handle->cur->next_swap;
- if (!offset)
+ free_page((unsigned long)handle->maps->map);
+ tmp = handle->maps;
+ handle->maps = handle->maps->next;
+ kfree(tmp);
+ if (!handle->maps)
release_swap_reader(handle);
- else if (!error)
- error = hib_bio_read_page(offset, handle->cur, NULL);
+ else
+ handle->cur = handle->maps->map;
}
return error;
}
@@ -697,7 +941,7 @@ static int load_image(struct swap_map_handle *handle,
unsigned int nr_to_read)
{
unsigned int m;
- int error = 0;
+ int ret = 0;
struct timeval start;
struct timeval stop;
struct bio *bio;
@@ -713,15 +957,15 @@ static int load_image(struct swap_map_handle *handle,
bio = NULL;
do_gettimeofday(&start);
for ( ; ; ) {
- error = snapshot_write_next(snapshot);
- if (error <= 0)
+ ret = snapshot_write_next(snapshot);
+ if (ret <= 0)
break;
- error = swap_read_page(handle, data_of(*snapshot), &bio);
- if (error)
+ ret = swap_read_page(handle, data_of(*snapshot), &bio);
+ if (ret)
break;
if (snapshot->sync_read)
- error = hib_wait_on_bio_chain(&bio);
- if (error)
+ ret = hib_wait_on_bio_chain(&bio);
+ if (ret)
break;
if (!(nr_pages % m))
printk("\b\b\b\b%3d%%", nr_pages / m);
@@ -729,17 +973,61 @@ static int load_image(struct swap_map_handle *handle,
}
err2 = hib_wait_on_bio_chain(&bio);
do_gettimeofday(&stop);
- if (!error)
- error = err2;
- if (!error) {
+ if (!ret)
+ ret = err2;
+ if (!ret) {
printk("\b\b\b\bdone\n");
snapshot_write_finalize(snapshot);
if (!snapshot_image_loaded(snapshot))
- error = -ENODATA;
+ ret = -ENODATA;
} else
printk("\n");
swsusp_show_speed(&start, &stop, nr_to_read, "Read");
- return error;
+ return ret;
+}
+
+/**
+ * Structure used for LZO data decompression.
+ */
+struct dec_data {
+ struct task_struct *thr; /* thread */
+ atomic_t ready; /* ready to start flag */
+ atomic_t stop; /* ready to stop flag */
+ int ret; /* return code */
+ wait_queue_head_t go; /* start decompression */
+ wait_queue_head_t done; /* decompression done */
+ size_t unc_len; /* uncompressed length */
+ size_t cmp_len; /* compressed length */
+ unsigned char unc[LZO_UNC_SIZE]; /* uncompressed buffer */
+ unsigned char cmp[LZO_CMP_SIZE]; /* compressed buffer */
+};
+
+/**
+ * Deompression function that runs in its own thread.
+ */
+static int lzo_decompress_threadfn(void *data)
+{
+ struct dec_data *d = data;
+
+ while (1) {
+ wait_event(d->go, atomic_read(&d->ready) ||
+ kthread_should_stop());
+ if (kthread_should_stop()) {
+ d->thr = NULL;
+ d->ret = -1;
+ atomic_set(&d->stop, 1);
+ wake_up(&d->done);
+ break;
+ }
+ atomic_set(&d->ready, 0);
+
+ d->unc_len = LZO_UNC_SIZE;
+ d->ret = lzo1x_decompress_safe(d->cmp + LZO_HEADER, d->cmp_len,
+ d->unc, &d->unc_len);
+ atomic_set(&d->stop, 1);
+ wake_up(&d->done);
+ }
+ return 0;
}
/**
@@ -753,50 +1041,120 @@ static int load_image_lzo(struct swap_map_handle *handle,
unsigned int nr_to_read)
{
unsigned int m;
- int error = 0;
+ int ret = 0;
+ int eof = 0;
struct bio *bio;
struct timeval start;
struct timeval stop;
unsigned nr_pages;
- size_t i, off, unc_len, cmp_len;
- unsigned char *unc, *cmp, *page[LZO_CMP_PAGES];
-
- for (i = 0; i < LZO_CMP_PAGES; i++) {
- page[i] = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
- if (!page[i]) {
- printk(KERN_ERR "PM: Failed to allocate LZO page\n");
+ size_t off;
+ unsigned i, thr, run_threads, nr_threads;
+ unsigned ring = 0, pg = 0, ring_size = 0,
+ have = 0, want, need, asked = 0;
+ unsigned long read_pages;
+ unsigned char **page = NULL;
+ struct dec_data *data = NULL;
+ struct crc_data *crc = NULL;
+
+ /*
+ * We'll limit the number of threads for decompression to limit memory
+ * footprint.
+ */
+ nr_threads = num_online_cpus() - 1;
+ nr_threads = clamp_val(nr_threads, 1, LZO_THREADS);
+
+ page = vmalloc(sizeof(*page) * LZO_READ_PAGES);
+ if (!page) {
+ printk(KERN_ERR "PM: Failed to allocate LZO page\n");
+ ret = -ENOMEM;
+ goto out_clean;
+ }
- while (i)
- free_page((unsigned long)page[--i]);
+ data = vmalloc(sizeof(*data) * nr_threads);
+ if (!data) {
+ printk(KERN_ERR "PM: Failed to allocate LZO data\n");
+ ret = -ENOMEM;
+ goto out_clean;
+ }
+ for (thr = 0; thr < nr_threads; thr++)
+ memset(&data[thr], 0, offsetof(struct dec_data, go));
- return -ENOMEM;
+ crc = kmalloc(sizeof(*crc), GFP_KERNEL);
+ if (!crc) {
+ printk(KERN_ERR "PM: Failed to allocate crc\n");
+ ret = -ENOMEM;
+ goto out_clean;
+ }
+ memset(crc, 0, offsetof(struct crc_data, go));
+
+ /*
+ * Start the decompression threads.
+ */
+ for (thr = 0; thr < nr_threads; thr++) {
+ init_waitqueue_head(&data[thr].go);
+ init_waitqueue_head(&data[thr].done);
+
+ data[thr].thr = kthread_run(lzo_decompress_threadfn,
+ &data[thr],
+ "image_decompress/%u", thr);
+ if (IS_ERR(data[thr].thr)) {
+ data[thr].thr = NULL;
+ printk(KERN_ERR
+ "PM: Cannot start decompression threads\n");
+ ret = -ENOMEM;
+ goto out_clean;
}
}
- unc = vmalloc(LZO_UNC_SIZE);
- if (!unc) {
- printk(KERN_ERR "PM: Failed to allocate LZO uncompressed\n");
-
- for (i = 0; i < LZO_CMP_PAGES; i++)
- free_page((unsigned long)page[i]);
-
- return -ENOMEM;
+ /*
+ * Start the CRC32 thread.
+ */
+ init_waitqueue_head(&crc->go);
+ init_waitqueue_head(&crc->done);
+
+ handle->crc32 = 0;
+ crc->crc32 = &handle->crc32;
+ for (thr = 0; thr < nr_threads; thr++) {
+ crc->unc[thr] = data[thr].unc;
+ crc->unc_len[thr] = &data[thr].unc_len;
}
- cmp = vmalloc(LZO_CMP_SIZE);
- if (!cmp) {
- printk(KERN_ERR "PM: Failed to allocate LZO compressed\n");
+ crc->thr = kthread_run(crc32_threadfn, crc, "image_crc32");
+ if (IS_ERR(crc->thr)) {
+ crc->thr = NULL;
+ printk(KERN_ERR "PM: Cannot start CRC32 thread\n");
+ ret = -ENOMEM;
+ goto out_clean;
+ }
- vfree(unc);
- for (i = 0; i < LZO_CMP_PAGES; i++)
- free_page((unsigned long)page[i]);
+ /*
+ * Adjust number of pages for read buffering, in case we are short.
+ */
+ read_pages = (nr_free_pages() - snapshot_get_image_size()) >> 1;
+ read_pages = clamp_val(read_pages, LZO_CMP_PAGES, LZO_READ_PAGES);
- return -ENOMEM;
+ for (i = 0; i < read_pages; i++) {
+ page[i] = (void *)__get_free_page(i < LZO_CMP_PAGES ?
+ __GFP_WAIT | __GFP_HIGH :
+ __GFP_WAIT);
+ if (!page[i]) {
+ if (i < LZO_CMP_PAGES) {
+ ring_size = i;
+ printk(KERN_ERR
+ "PM: Failed to allocate LZO pages\n");
+ ret = -ENOMEM;
+ goto out_clean;
+ } else {
+ break;
+ }
+ }
}
+ want = ring_size = i;
printk(KERN_INFO
+ "PM: Using %u thread(s) for decompression.\n"
"PM: Loading and decompressing image data (%u pages) ... ",
- nr_to_read);
+ nr_threads, nr_to_read);
m = nr_to_read / 100;
if (!m)
m = 1;
@@ -804,85 +1162,189 @@ static int load_image_lzo(struct swap_map_handle *handle,
bio = NULL;
do_gettimeofday(&start);
- error = snapshot_write_next(snapshot);
- if (error <= 0)
+ ret = snapshot_write_next(snapshot);
+ if (ret <= 0)
goto out_finish;
- for (;;) {
- error = swap_read_page(handle, page[0], NULL); /* sync */
- if (error)
- break;
-
- cmp_len = *(size_t *)page[0];
- if (unlikely(!cmp_len ||
- cmp_len > lzo1x_worst_compress(LZO_UNC_SIZE))) {
- printk(KERN_ERR "PM: Invalid LZO compressed length\n");
- error = -1;
- break;
+ for(;;) {
+ for (i = 0; !eof && i < want; i++) {
+ ret = swap_read_page(handle, page[ring], &bio);
+ if (ret) {
+ /*
+ * On real read error, finish. On end of data,
+ * set EOF flag and just exit the read loop.
+ */
+ if (handle->cur &&
+ handle->cur->entries[handle->k]) {
+ goto out_finish;
+ } else {
+ eof = 1;
+ break;
+ }
+ }
+ if (++ring >= ring_size)
+ ring = 0;
}
+ asked += i;
+ want -= i;
- for (off = PAGE_SIZE, i = 1;
- off < LZO_HEADER + cmp_len; off += PAGE_SIZE, i++) {
- error = swap_read_page(handle, page[i], &bio);
- if (error)
+ /*
+ * We are out of data, wait for some more.
+ */
+ if (!have) {
+ if (!asked)
+ break;
+
+ ret = hib_wait_on_bio_chain(&bio);
+ if (ret)
goto out_finish;
+ have += asked;
+ asked = 0;
+ if (eof)
+ eof = 2;
}
- error = hib_wait_on_bio_chain(&bio); /* need all data now */
- if (error)
- goto out_finish;
-
- for (off = 0, i = 0;
- off < LZO_HEADER + cmp_len; off += PAGE_SIZE, i++) {
- memcpy(cmp + off, page[i], PAGE_SIZE);
+ if (crc->run_threads) {
+ wait_event(crc->done, atomic_read(&crc->stop));
+ atomic_set(&crc->stop, 0);
+ crc->run_threads = 0;
}
- unc_len = LZO_UNC_SIZE;
- error = lzo1x_decompress_safe(cmp + LZO_HEADER, cmp_len,
- unc, &unc_len);
- if (error < 0) {
- printk(KERN_ERR "PM: LZO decompression failed\n");
- break;
+ for (thr = 0; have && thr < nr_threads; thr++) {
+ data[thr].cmp_len = *(size_t *)page[pg];
+ if (unlikely(!data[thr].cmp_len ||
+ data[thr].cmp_len >
+ lzo1x_worst_compress(LZO_UNC_SIZE))) {
+ printk(KERN_ERR
+ "PM: Invalid LZO compressed length\n");
+ ret = -1;
+ goto out_finish;
+ }
+
+ need = DIV_ROUND_UP(data[thr].cmp_len + LZO_HEADER,
+ PAGE_SIZE);
+ if (need > have) {
+ if (eof > 1) {
+ ret = -1;
+ goto out_finish;
+ }
+ break;
+ }
+
+ for (off = 0;
+ off < LZO_HEADER + data[thr].cmp_len;
+ off += PAGE_SIZE) {
+ memcpy(data[thr].cmp + off,
+ page[pg], PAGE_SIZE);
+ have--;
+ want++;
+ if (++pg >= ring_size)
+ pg = 0;
+ }
+
+ atomic_set(&data[thr].ready, 1);
+ wake_up(&data[thr].go);
}
- if (unlikely(!unc_len ||
- unc_len > LZO_UNC_SIZE ||
- unc_len & (PAGE_SIZE - 1))) {
- printk(KERN_ERR "PM: Invalid LZO uncompressed length\n");
- error = -1;
- break;
+ /*
+ * Wait for more data while we are decompressing.
+ */
+ if (have < LZO_CMP_PAGES && asked) {
+ ret = hib_wait_on_bio_chain(&bio);
+ if (ret)
+ goto out_finish;
+ have += asked;
+ asked = 0;
+ if (eof)
+ eof = 2;
}
- for (off = 0; off < unc_len; off += PAGE_SIZE) {
- memcpy(data_of(*snapshot), unc + off, PAGE_SIZE);
+ for (run_threads = thr, thr = 0; thr < run_threads; thr++) {
+ wait_event(data[thr].done,
+ atomic_read(&data[thr].stop));
+ atomic_set(&data[thr].stop, 0);
+
+ ret = data[thr].ret;
- if (!(nr_pages % m))
- printk("\b\b\b\b%3d%%", nr_pages / m);
- nr_pages++;
+ if (ret < 0) {
+ printk(KERN_ERR
+ "PM: LZO decompression failed\n");
+ goto out_finish;
+ }
- error = snapshot_write_next(snapshot);
- if (error <= 0)
+ if (unlikely(!data[thr].unc_len ||
+ data[thr].unc_len > LZO_UNC_SIZE ||
+ data[thr].unc_len & (PAGE_SIZE - 1))) {
+ printk(KERN_ERR
+ "PM: Invalid LZO uncompressed length\n");
+ ret = -1;
goto out_finish;
+ }
+
+ for (off = 0;
+ off < data[thr].unc_len; off += PAGE_SIZE) {
+ memcpy(data_of(*snapshot),
+ data[thr].unc + off, PAGE_SIZE);
+
+ if (!(nr_pages % m))
+ printk("\b\b\b\b%3d%%", nr_pages / m);
+ nr_pages++;
+
+ ret = snapshot_write_next(snapshot);
+ if (ret <= 0) {
+ crc->run_threads = thr + 1;
+ atomic_set(&crc->ready, 1);
+ wake_up(&crc->go);
+ goto out_finish;
+ }
+ }
}
+
+ crc->run_threads = thr;
+ atomic_set(&crc->ready, 1);
+ wake_up(&crc->go);
}
out_finish:
+ if (crc->run_threads) {
+ wait_event(crc->done, atomic_read(&crc->stop));
+ atomic_set(&crc->stop, 0);
+ }
do_gettimeofday(&stop);
- if (!error) {
+ if (!ret) {
printk("\b\b\b\bdone\n");
snapshot_write_finalize(snapshot);
if (!snapshot_image_loaded(snapshot))
- error = -ENODATA;
+ ret = -ENODATA;
+ if (!ret) {
+ if (swsusp_header->flags & SF_CRC32_MODE) {
+ if(handle->crc32 != swsusp_header->crc32) {
+ printk(KERN_ERR
+ "PM: Invalid image CRC32!\n");
+ ret = -ENODATA;
+ }
+ }
+ }
} else
printk("\n");
swsusp_show_speed(&start, &stop, nr_to_read, "Read");
-
- vfree(cmp);
- vfree(unc);
- for (i = 0; i < LZO_CMP_PAGES; i++)
+out_clean:
+ for (i = 0; i < ring_size; i++)
free_page((unsigned long)page[i]);
+ if (crc) {
+ if (crc->thr)
+ kthread_stop(crc->thr);
+ kfree(crc);
+ }
+ if (data) {
+ for (thr = 0; thr < nr_threads; thr++)
+ if (data[thr].thr)
+ kthread_stop(data[thr].thr);
+ vfree(data);
+ }
+ if (page) vfree(page);
- return error;
+ return ret;
}
/**
diff --git a/kernel/printk.c b/kernel/printk.c
index 836a2ae0ac31..28a40d8171b8 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -1604,7 +1604,7 @@ static int __init printk_late_init(void)
struct console *con;
for_each_console(con) {
- if (con->flags & CON_BOOT) {
+ if (!keep_bootcon && con->flags & CON_BOOT) {
printk(KERN_INFO "turn off boot console %s%d\n",
con->name, con->index);
unregister_console(con);
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 9de3ecfd20f9..a70d2a5d8c7b 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -744,20 +744,17 @@ int ptrace_request(struct task_struct *child, long request,
break;
si = child->last_siginfo;
- if (unlikely(!si || si->si_code >> 8 != PTRACE_EVENT_STOP))
- break;
-
- child->jobctl |= JOBCTL_LISTENING;
-
- /*
- * If NOTIFY is set, it means event happened between start
- * of this trap and now. Trigger re-trap immediately.
- */
- if (child->jobctl & JOBCTL_TRAP_NOTIFY)
- signal_wake_up(child, true);
-
+ if (likely(si && (si->si_code >> 8) == PTRACE_EVENT_STOP)) {
+ child->jobctl |= JOBCTL_LISTENING;
+ /*
+ * If NOTIFY is set, it means event happened between
+ * start of this trap and now. Trigger re-trap.
+ */
+ if (child->jobctl & JOBCTL_TRAP_NOTIFY)
+ signal_wake_up(child, true);
+ ret = 0;
+ }
unlock_task_sighand(child, &flags);
- ret = 0;
break;
case PTRACE_DETACH: /* detach a process that was attached. */
diff --git a/kernel/resource.c b/kernel/resource.c
index 3b3cedc52592..c8dc249da5ce 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -419,6 +419,9 @@ static int __find_resource(struct resource *root, struct resource *old,
else
tmp.end = root->end;
+ if (tmp.end < tmp.start)
+ goto next;
+
resource_clip(&tmp, constraint->min, constraint->max);
arch_remove_reservations(&tmp);
@@ -436,8 +439,10 @@ static int __find_resource(struct resource *root, struct resource *old,
return 0;
}
}
- if (!this)
+
+next: if (!this || this->end == root->end)
break;
+
if (this != old)
tmp.start = this->end + 1;
this = this->sibling;
diff --git a/kernel/sched.c b/kernel/sched.c
index ccacdbdecf45..8aa00803c1ec 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -1739,7 +1739,7 @@ static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu)
#ifdef CONFIG_SMP
/*
* After ->cpu is set up to a new value, task_rq_lock(p, ...) can be
- * successfuly executed on another CPU. We must ensure that updates of
+ * successfully executed on another CPU. We must ensure that updates of
* per-task data have been completed by this moment.
*/
smp_wmb();
@@ -3065,7 +3065,7 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev)
#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
local_irq_disable();
#endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */
- perf_event_task_sched_in(current);
+ perf_event_task_sched_in(prev, current);
#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
local_irq_enable();
#endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */
@@ -3725,30 +3725,6 @@ unsigned long long task_sched_runtime(struct task_struct *p)
}
/*
- * Return sum_exec_runtime for the thread group.
- * In case the task is currently running, return the sum plus current's
- * pending runtime that have not been accounted yet.
- *
- * Note that the thread group might have other running tasks as well,
- * so the return value not includes other pending runtime that other
- * running tasks might have.
- */
-unsigned long long thread_group_sched_runtime(struct task_struct *p)
-{
- struct task_cputime totals;
- unsigned long flags;
- struct rq *rq;
- u64 ns;
-
- rq = task_rq_lock(p, &flags);
- thread_group_cputime(p, &totals);
- ns = totals.sum_exec_runtime + do_task_delta_exec(p, rq);
- task_rq_unlock(rq, p, &flags);
-
- return ns;
-}
-
-/*
* Account user cpu time to a process.
* @p: the process that the cpu time gets accounted to
* @cputime: the cpu time spent in user space since the last update
@@ -4279,9 +4255,9 @@ pick_next_task(struct rq *rq)
}
/*
- * schedule() is the main scheduler function.
+ * __schedule() is the main scheduler function.
*/
-asmlinkage void __sched schedule(void)
+static void __sched __schedule(void)
{
struct task_struct *prev, *next;
unsigned long *switch_count;
@@ -4322,16 +4298,6 @@ need_resched:
if (to_wakeup)
try_to_wake_up_local(to_wakeup);
}
-
- /*
- * If we are going to sleep and we have plugged IO
- * queued, make sure to submit it to avoid deadlocks.
- */
- if (blk_needs_flush_plug(prev)) {
- raw_spin_unlock(&rq->lock);
- blk_schedule_flush_plug(prev);
- raw_spin_lock(&rq->lock);
- }
}
switch_count = &prev->nvcsw;
}
@@ -4369,6 +4335,26 @@ need_resched:
if (need_resched())
goto need_resched;
}
+
+static inline void sched_submit_work(struct task_struct *tsk)
+{
+ if (!tsk->state)
+ return;
+ /*
+ * If we are going to sleep and we have plugged IO queued,
+ * make sure to submit it to avoid deadlocks.
+ */
+ if (blk_needs_flush_plug(tsk))
+ blk_schedule_flush_plug(tsk);
+}
+
+asmlinkage void __sched schedule(void)
+{
+ struct task_struct *tsk = current;
+
+ sched_submit_work(tsk);
+ __schedule();
+}
EXPORT_SYMBOL(schedule);
#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
@@ -4435,7 +4421,7 @@ asmlinkage void __sched notrace preempt_schedule(void)
do {
add_preempt_count_notrace(PREEMPT_ACTIVE);
- schedule();
+ __schedule();
sub_preempt_count_notrace(PREEMPT_ACTIVE);
/*
@@ -4463,7 +4449,7 @@ asmlinkage void __sched preempt_schedule_irq(void)
do {
add_preempt_count(PREEMPT_ACTIVE);
local_irq_enable();
- schedule();
+ __schedule();
local_irq_disable();
sub_preempt_count(PREEMPT_ACTIVE);
@@ -5588,7 +5574,7 @@ static inline int should_resched(void)
static void __cond_resched(void)
{
add_preempt_count(PREEMPT_ACTIVE);
- schedule();
+ __schedule();
sub_preempt_count(PREEMPT_ACTIVE);
}
@@ -7443,6 +7429,7 @@ static void __sdt_free(const struct cpumask *cpu_map)
struct sched_domain *sd = *per_cpu_ptr(sdd->sd, j);
if (sd && (sd->flags & SD_OVERLAP))
free_sched_groups(sd->groups, 0);
+ kfree(*per_cpu_ptr(sdd->sd, j));
kfree(*per_cpu_ptr(sdd->sg, j));
kfree(*per_cpu_ptr(sdd->sgp, j));
}
diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c
index 97540f0c9e47..af1177858be3 100644
--- a/kernel/sched_rt.c
+++ b/kernel/sched_rt.c
@@ -1050,7 +1050,7 @@ select_task_rq_rt(struct task_struct *p, int sd_flag, int flags)
*/
if (curr && unlikely(rt_task(curr)) &&
(curr->rt.nr_cpus_allowed < 2 ||
- curr->prio < p->prio) &&
+ curr->prio <= p->prio) &&
(p->rt.nr_cpus_allowed > 1)) {
int target = find_lowest_rq(p);
@@ -1581,7 +1581,7 @@ static void task_woken_rt(struct rq *rq, struct task_struct *p)
p->rt.nr_cpus_allowed > 1 &&
rt_task(rq->curr) &&
(rq->curr->rt.nr_cpus_allowed < 2 ||
- rq->curr->prio < p->prio))
+ rq->curr->prio <= p->prio))
push_rt_tasks(rq);
}
diff --git a/kernel/signal.c b/kernel/signal.c
index 291c9700be75..d252be2d3de5 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1344,13 +1344,24 @@ int kill_proc_info(int sig, struct siginfo *info, pid_t pid)
return error;
}
+static int kill_as_cred_perm(const struct cred *cred,
+ struct task_struct *target)
+{
+ const struct cred *pcred = __task_cred(target);
+ if (cred->user_ns != pcred->user_ns)
+ return 0;
+ if (cred->euid != pcred->suid && cred->euid != pcred->uid &&
+ cred->uid != pcred->suid && cred->uid != pcred->uid)
+ return 0;
+ return 1;
+}
+
/* like kill_pid_info(), but doesn't use uid/euid of "current" */
-int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid,
- uid_t uid, uid_t euid, u32 secid)
+int kill_pid_info_as_cred(int sig, struct siginfo *info, struct pid *pid,
+ const struct cred *cred, u32 secid)
{
int ret = -EINVAL;
struct task_struct *p;
- const struct cred *pcred;
unsigned long flags;
if (!valid_signal(sig))
@@ -1362,10 +1373,7 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid,
ret = -ESRCH;
goto out_unlock;
}
- pcred = __task_cred(p);
- if (si_fromuser(info) &&
- euid != pcred->suid && euid != pcred->uid &&
- uid != pcred->suid && uid != pcred->uid) {
+ if (si_fromuser(info) && !kill_as_cred_perm(cred, p)) {
ret = -EPERM;
goto out_unlock;
}
@@ -1384,7 +1392,7 @@ out_unlock:
rcu_read_unlock();
return ret;
}
-EXPORT_SYMBOL_GPL(kill_pid_info_as_uid);
+EXPORT_SYMBOL_GPL(kill_pid_info_as_cred);
/*
* kill_something_info() interprets pid in interesting ways just like kill(2).
diff --git a/kernel/sys.c b/kernel/sys.c
index dd948a1fca4c..58459509b14c 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -37,6 +37,8 @@
#include <linux/fs_struct.h>
#include <linux/gfp.h>
#include <linux/syscore_ops.h>
+#include <linux/version.h>
+#include <linux/ctype.h>
#include <linux/compat.h>
#include <linux/syscalls.h>
@@ -44,6 +46,8 @@
#include <linux/user_namespace.h>
#include <linux/kmsg_dump.h>
+/* Move somewhere else to avoid recompiling? */
+#include <generated/utsrelease.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -1161,6 +1165,34 @@ DECLARE_RWSEM(uts_sem);
#define override_architecture(name) 0
#endif
+/*
+ * Work around broken programs that cannot handle "Linux 3.0".
+ * Instead we map 3.x to 2.6.40+x, so e.g. 3.0 would be 2.6.40
+ */
+static int override_release(char __user *release, int len)
+{
+ int ret = 0;
+ char buf[65];
+
+ if (current->personality & UNAME26) {
+ char *rest = UTS_RELEASE;
+ int ndots = 0;
+ unsigned v;
+
+ while (*rest) {
+ if (*rest == '.' && ++ndots >= 3)
+ break;
+ if (!isdigit(*rest) && *rest != '.')
+ break;
+ rest++;
+ }
+ v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 40;
+ snprintf(buf, len, "2.6.%u%s", v, rest);
+ ret = copy_to_user(release, buf, len);
+ }
+ return ret;
+}
+
SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
{
int errno = 0;
@@ -1170,6 +1202,8 @@ SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
errno = -EFAULT;
up_read(&uts_sem);
+ if (!errno && override_release(name->release, sizeof(name->release)))
+ errno = -EFAULT;
if (!errno && override_architecture(name))
errno = -EFAULT;
return errno;
@@ -1191,6 +1225,8 @@ SYSCALL_DEFINE1(uname, struct old_utsname __user *, name)
error = -EFAULT;
up_read(&uts_sem);
+ if (!error && override_release(name->release, sizeof(name->release)))
+ error = -EFAULT;
if (!error && override_architecture(name))
error = -EFAULT;
return error;
@@ -1225,6 +1261,8 @@ SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name)
if (!error && override_architecture(name))
error = -EFAULT;
+ if (!error && override_release(name->release, sizeof(name->release)))
+ error = -EFAULT;
return error ? -EFAULT : 0;
}
#endif
@@ -1721,6 +1759,7 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
sizeof(me->comm) - 1) < 0)
return -EFAULT;
set_task_comm(me, comm);
+ proc_comm_connector(me);
return 0;
case PR_GET_NAME:
get_task_comm(comm, me);
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 62cbc8877fef..a9a5de07c4f1 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -16,7 +16,6 @@ asmlinkage long sys_ni_syscall(void)
return -ENOSYS;
}
-cond_syscall(sys_nfsservctl);
cond_syscall(sys_quotactl);
cond_syscall(sys32_quotactl);
cond_syscall(sys_acct);
diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c
index 3b8e028b9601..6318b511afa1 100644
--- a/kernel/sysctl_binary.c
+++ b/kernel/sysctl_binary.c
@@ -1,6 +1,6 @@
#include <linux/stat.h>
#include <linux/sysctl.h>
-#include "../fs/xfs/linux-2.6/xfs_sysctl.h"
+#include "../fs/xfs/xfs_sysctl.h"
#include <linux/sunrpc/debug.h>
#include <linux/string.h>
#include <net/ip_vs.h>
@@ -214,7 +214,7 @@ static const struct bin_table bin_net_ipv4_route_table[] = {
{ CTL_INT, NET_IPV4_ROUTE_GC_MIN_INTERVAL, "gc_min_interval" },
{ CTL_INT, NET_IPV4_ROUTE_GC_MIN_INTERVAL_MS, "gc_min_interval_ms" },
{ CTL_INT, NET_IPV4_ROUTE_GC_TIMEOUT, "gc_timeout" },
- { CTL_INT, NET_IPV4_ROUTE_GC_INTERVAL, "gc_interval" },
+ /* NET_IPV4_ROUTE_GC_INTERVAL "gc_interval" no longer used */
{ CTL_INT, NET_IPV4_ROUTE_REDIRECT_LOAD, "redirect_load" },
{ CTL_INT, NET_IPV4_ROUTE_REDIRECT_NUMBER, "redirect_number" },
{ CTL_INT, NET_IPV4_ROUTE_REDIRECT_SILENCE, "redirect_silence" },
diff --git a/kernel/sysctl_check.c b/kernel/sysctl_check.c
index 4e4932a7b360..362da653813d 100644
--- a/kernel/sysctl_check.c
+++ b/kernel/sysctl_check.c
@@ -1,6 +1,6 @@
#include <linux/stat.h>
#include <linux/sysctl.h>
-#include "../fs/xfs/linux-2.6/xfs_sysctl.h"
+#include "../fs/xfs/xfs_sysctl.h"
#include <linux/sunrpc/debug.h>
#include <linux/string.h>
#include <net/ip_vs.h>
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index e19ce1454ee1..e66046456f4f 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -655,6 +655,7 @@ static struct genl_ops taskstats_ops = {
.cmd = TASKSTATS_CMD_GET,
.doit = taskstats_user_cmd,
.policy = taskstats_cmd_get_policy,
+ .flags = GENL_ADMIN_PERM,
};
static struct genl_ops cgroupstats_ops = {
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
index 59f369f98a04..ea5e1a928d5b 100644
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -441,6 +441,8 @@ static int alarm_timer_create(struct k_itimer *new_timer)
static void alarm_timer_get(struct k_itimer *timr,
struct itimerspec *cur_setting)
{
+ memset(cur_setting, 0, sizeof(struct itimerspec));
+
cur_setting->it_interval =
ktime_to_timespec(timr->it.alarmtimer.period);
cur_setting->it_value =
@@ -479,11 +481,17 @@ static int alarm_timer_set(struct k_itimer *timr, int flags,
if (!rtcdev)
return -ENOTSUPP;
- /* Save old values */
- old_setting->it_interval =
- ktime_to_timespec(timr->it.alarmtimer.period);
- old_setting->it_value =
- ktime_to_timespec(timr->it.alarmtimer.node.expires);
+ /*
+ * XXX HACK! Currently we can DOS a system if the interval
+ * period on alarmtimers is too small. Cap the interval here
+ * to 100us and solve this properly in a future patch! -jstultz
+ */
+ if ((new_setting->it_interval.tv_sec == 0) &&
+ (new_setting->it_interval.tv_nsec < 100000))
+ new_setting->it_interval.tv_nsec = 100000;
+
+ if (old_setting)
+ alarm_timer_get(timr, old_setting);
/* If the timer was already set, cancel it */
alarm_cancel(&timr->it.alarmtimer);
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index 761c510a06c5..f49405f842f4 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -53,6 +53,9 @@ endif
obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o
obj-$(CONFIG_KPROBE_EVENT) += trace_kprobe.o
obj-$(CONFIG_TRACEPOINTS) += power-traces.o
+ifeq ($(CONFIG_PM_RUNTIME),y)
+obj-$(CONFIG_TRACEPOINTS) += rpm-traces.o
+endif
ifeq ($(CONFIG_TRACING),y)
obj-$(CONFIG_KGDB_KDB) += trace_kdb.o
endif
diff --git a/kernel/trace/rpm-traces.c b/kernel/trace/rpm-traces.c
new file mode 100644
index 000000000000..4b3b5eaf94d1
--- /dev/null
+++ b/kernel/trace/rpm-traces.c
@@ -0,0 +1,20 @@
+/*
+ * Power trace points
+ *
+ * Copyright (C) 2009 Ming Lei <ming.lei@canonical.com>
+ */
+
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/rpm.h>
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(rpm_return_int);
+EXPORT_TRACEPOINT_SYMBOL_GPL(rpm_idle);
+EXPORT_TRACEPOINT_SYMBOL_GPL(rpm_suspend);
+EXPORT_TRACEPOINT_SYMBOL_GPL(rpm_resume);
diff --git a/kernel/tsacct.c b/kernel/tsacct.c
index 24dc60d9fa1f..5bbfac85866e 100644
--- a/kernel/tsacct.c
+++ b/kernel/tsacct.c
@@ -78,6 +78,7 @@ void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk)
#define KB 1024
#define MB (1024*KB)
+#define KB_MASK (~(KB-1))
/*
* fill in extended accounting fields
*/
@@ -95,14 +96,14 @@ void xacct_add_tsk(struct taskstats *stats, struct task_struct *p)
stats->hiwater_vm = get_mm_hiwater_vm(mm) * PAGE_SIZE / KB;
mmput(mm);
}
- stats->read_char = p->ioac.rchar;
- stats->write_char = p->ioac.wchar;
- stats->read_syscalls = p->ioac.syscr;
- stats->write_syscalls = p->ioac.syscw;
+ stats->read_char = p->ioac.rchar & KB_MASK;
+ stats->write_char = p->ioac.wchar & KB_MASK;
+ stats->read_syscalls = p->ioac.syscr & KB_MASK;
+ stats->write_syscalls = p->ioac.syscw & KB_MASK;
#ifdef CONFIG_TASK_IO_ACCOUNTING
- stats->read_bytes = p->ioac.read_bytes;
- stats->write_bytes = p->ioac.write_bytes;
- stats->cancelled_write_bytes = p->ioac.cancelled_write_bytes;
+ stats->read_bytes = p->ioac.read_bytes & KB_MASK;
+ stats->write_bytes = p->ioac.write_bytes & KB_MASK;
+ stats->cancelled_write_bytes = p->ioac.cancelled_write_bytes & KB_MASK;
#else
stats->read_bytes = 0;
stats->write_bytes = 0;
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 25fb1b0e53fa..1783aabc6128 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -2412,8 +2412,13 @@ reflush:
for_each_cwq_cpu(cpu, wq) {
struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
+ bool drained;
- if (!cwq->nr_active && list_empty(&cwq->delayed_works))
+ spin_lock_irq(&cwq->gcwq->lock);
+ drained = !cwq->nr_active && list_empty(&cwq->delayed_works);
+ spin_unlock_irq(&cwq->gcwq->lock);
+
+ if (drained)
continue;
if (++flush_cnt == 10 ||
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index c0cb9c4bc46d..75330bd87565 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -117,31 +117,31 @@ config DEBUG_SECTION_MISMATCH
help
The section mismatch analysis checks if there are illegal
references from one section to another section.
- Linux will during link or during runtime drop some sections
- and any use of code/data previously in these sections will
+ During linktime or runtime, some sections are dropped;
+ any use of code/data previously in these sections would
most likely result in an oops.
- In the code functions and variables are annotated with
- __init, __devinit etc. (see full list in include/linux/init.h)
+ In the code, functions and variables are annotated with
+ __init, __devinit, etc. (see the full list in include/linux/init.h),
which results in the code/data being placed in specific sections.
- The section mismatch analysis is always done after a full
- kernel build but enabling this option will in addition
- do the following:
- - Add the option -fno-inline-functions-called-once to gcc
- When inlining a function annotated __init in a non-init
- function we would lose the section information and thus
+ The section mismatch analysis is always performed after a full
+ kernel build, and enabling this option causes the following
+ additional steps to occur:
+ - Add the option -fno-inline-functions-called-once to gcc commands.
+ When inlining a function annotated with __init in a non-init
+ function, we would lose the section information and thus
the analysis would not catch the illegal reference.
- This option tells gcc to inline less but will also
- result in a larger kernel.
- - Run the section mismatch analysis for each module/built-in.o
- When we run the section mismatch analysis on vmlinux.o we
+ This option tells gcc to inline less (but it does result in
+ a larger kernel).
+ - Run the section mismatch analysis for each module/built-in.o file.
+ When we run the section mismatch analysis on vmlinux.o, we
lose valueble information about where the mismatch was
introduced.
Running the analysis for each module/built-in.o file
- will tell where the mismatch happens much closer to the
- source. The drawback is that we will report the same
- mismatch at least twice.
- - Enable verbose reporting from modpost to help solving
- the section mismatches reported.
+ tells where the mismatch happens much closer to the
+ source. The drawback is that the same mismatch is
+ reported at least twice.
+ - Enable verbose reporting from modpost in order to help resolve
+ the section mismatches that are reported.
config DEBUG_KERNEL
bool "Kernel debugging"
@@ -835,7 +835,7 @@ config DEBUG_CREDENTIALS
#
# Select this config option from the architecture Kconfig, if it
-# it is preferred to always offer frame pointers as a config
+# is preferred to always offer frame pointers as a config
# option on the architecture (regardless of KERNEL_DEBUG):
#
config ARCH_WANT_FRAME_POINTERS
@@ -1081,7 +1081,7 @@ config FAULT_INJECTION_STACKTRACE_FILTER
depends on FAULT_INJECTION_DEBUG_FS && STACKTRACE_SUPPORT
depends on !X86_64
select STACKTRACE
- select FRAME_POINTER if !PPC && !S390 && !MICROBLAZE
+ select FRAME_POINTER if !PPC && !S390 && !MICROBLAZE && !ARM_UNWIND
help
Provide stacktrace filter for fault-injection capabilities
@@ -1091,7 +1091,7 @@ config LATENCYTOP
depends on DEBUG_KERNEL
depends on STACKTRACE_SUPPORT
depends on PROC_FS
- select FRAME_POINTER if !MIPS && !PPC && !S390 && !MICROBLAZE
+ select FRAME_POINTER if !MIPS && !PPC && !S390 && !MICROBLAZE && !ARM_UNWIND
select KALLSYMS
select KALLSYMS_ALL
select STACKTRACE
diff --git a/lib/Makefile b/lib/Makefile
index d5d175c8a6ca..3f5bc6d903e0 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -12,7 +12,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
idr.o int_sqrt.o extable.o prio_tree.o \
sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \
proportions.o prio_heap.o ratelimit.o show_mem.o \
- is_single_threaded.o plist.o decompress.o find_next_bit.o
+ is_single_threaded.o plist.o decompress.o
lib-$(CONFIG_MMU) += ioremap.o
lib-$(CONFIG_SMP) += cpumask.o
@@ -22,7 +22,7 @@ lib-y += kobject.o kref.o klist.o
obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
string_helpers.o gcd.o lcm.o list_sort.o uuid.o flex_array.o \
- bsearch.o find_last_bit.o
+ bsearch.o find_last_bit.o find_next_bit.o
obj-y += kstrtox.o
obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 75ca78f3a8c9..dcdade39e47f 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -10,11 +10,12 @@
* Copyright (C) 2011 Bart Van Assche. All Rights Reserved.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kallsyms.h>
-#include <linux/version.h>
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
@@ -30,6 +31,8 @@
#include <linux/jump_label.h>
#include <linux/hardirq.h>
#include <linux/sched.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
extern struct _ddebug __start___verbose[];
extern struct _ddebug __stop___verbose[];
@@ -38,7 +41,6 @@ struct ddebug_table {
struct list_head link;
char *mod_name;
unsigned int num_ddebugs;
- unsigned int num_enabled;
struct _ddebug *ddebugs;
};
@@ -148,19 +150,13 @@ static void ddebug_change(const struct ddebug_query *query,
newflags = (dp->flags & mask) | flags;
if (newflags == dp->flags)
continue;
-
- if (!newflags)
- dt->num_enabled--;
- else if (!dp->flags)
- dt->num_enabled++;
dp->flags = newflags;
if (newflags)
dp->enabled = 1;
else
dp->enabled = 0;
if (verbose)
- printk(KERN_INFO
- "ddebug: changed %s:%d [%s]%s %s\n",
+ pr_info("changed %s:%d [%s]%s %s\n",
dp->filename, dp->lineno,
dt->mod_name, dp->function,
ddebug_describe_flags(dp, flagbuf,
@@ -170,7 +166,7 @@ static void ddebug_change(const struct ddebug_query *query,
mutex_unlock(&ddebug_lock);
if (!nfound && verbose)
- printk(KERN_INFO "ddebug: no matches for query\n");
+ pr_info("no matches for query\n");
}
/*
@@ -215,10 +211,10 @@ static int ddebug_tokenize(char *buf, char *words[], int maxwords)
if (verbose) {
int i;
- printk(KERN_INFO "%s: split into words:", __func__);
+ pr_info("split into words:");
for (i = 0 ; i < nwords ; i++)
- printk(" \"%s\"", words[i]);
- printk("\n");
+ pr_cont(" \"%s\"", words[i]);
+ pr_cont("\n");
}
return nwords;
@@ -330,16 +326,15 @@ static int ddebug_parse_query(char *words[], int nwords,
}
} else {
if (verbose)
- printk(KERN_ERR "%s: unknown keyword \"%s\"\n",
- __func__, words[i]);
+ pr_err("unknown keyword \"%s\"\n", words[i]);
return -EINVAL;
}
}
if (verbose)
- printk(KERN_INFO "%s: q->function=\"%s\" q->filename=\"%s\" "
- "q->module=\"%s\" q->format=\"%s\" q->lineno=%u-%u\n",
- __func__, query->function, query->filename,
+ pr_info("q->function=\"%s\" q->filename=\"%s\" "
+ "q->module=\"%s\" q->format=\"%s\" q->lineno=%u-%u\n",
+ query->function, query->filename,
query->module, query->format, query->first_lineno,
query->last_lineno);
@@ -368,7 +363,7 @@ static int ddebug_parse_flags(const char *str, unsigned int *flagsp,
return -EINVAL;
}
if (verbose)
- printk(KERN_INFO "%s: op='%c'\n", __func__, op);
+ pr_info("op='%c'\n", op);
for ( ; *str ; ++str) {
for (i = ARRAY_SIZE(opt_array) - 1; i >= 0; i--) {
@@ -383,7 +378,7 @@ static int ddebug_parse_flags(const char *str, unsigned int *flagsp,
if (flags == 0)
return -EINVAL;
if (verbose)
- printk(KERN_INFO "%s: flags=0x%x\n", __func__, flags);
+ pr_info("flags=0x%x\n", flags);
/* calculate final *flagsp, *maskp according to mask and op */
switch (op) {
@@ -401,8 +396,7 @@ static int ddebug_parse_flags(const char *str, unsigned int *flagsp,
break;
}
if (verbose)
- printk(KERN_INFO "%s: *flagsp=0x%x *maskp=0x%x\n",
- __func__, *flagsp, *maskp);
+ pr_info("*flagsp=0x%x *maskp=0x%x\n", *flagsp, *maskp);
return 0;
}
@@ -427,40 +421,117 @@ static int ddebug_exec_query(char *query_string)
return 0;
}
+#define PREFIX_SIZE 64
+
+static int remaining(int wrote)
+{
+ if (PREFIX_SIZE - wrote > 0)
+ return PREFIX_SIZE - wrote;
+ return 0;
+}
+
+static char *dynamic_emit_prefix(const struct _ddebug *desc, char *buf)
+{
+ int pos_after_tid;
+ int pos = 0;
+
+ pos += snprintf(buf + pos, remaining(pos), "%s", KERN_DEBUG);
+ if (desc->flags & _DPRINTK_FLAGS_INCL_TID) {
+ if (in_interrupt())
+ pos += snprintf(buf + pos, remaining(pos), "%s ",
+ "<intr>");
+ else
+ pos += snprintf(buf + pos, remaining(pos), "[%d] ",
+ task_pid_vnr(current));
+ }
+ pos_after_tid = pos;
+ if (desc->flags & _DPRINTK_FLAGS_INCL_MODNAME)
+ pos += snprintf(buf + pos, remaining(pos), "%s:",
+ desc->modname);
+ if (desc->flags & _DPRINTK_FLAGS_INCL_FUNCNAME)
+ pos += snprintf(buf + pos, remaining(pos), "%s:",
+ desc->function);
+ if (desc->flags & _DPRINTK_FLAGS_INCL_LINENO)
+ pos += snprintf(buf + pos, remaining(pos), "%d:", desc->lineno);
+ if (pos - pos_after_tid)
+ pos += snprintf(buf + pos, remaining(pos), " ");
+ if (pos >= PREFIX_SIZE)
+ buf[PREFIX_SIZE - 1] = '\0';
+
+ return buf;
+}
+
int __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...)
{
va_list args;
int res;
+ struct va_format vaf;
+ char buf[PREFIX_SIZE];
BUG_ON(!descriptor);
BUG_ON(!fmt);
va_start(args, fmt);
- res = printk(KERN_DEBUG);
- if (descriptor->flags & _DPRINTK_FLAGS_INCL_TID) {
- if (in_interrupt())
- res += printk(KERN_CONT "<intr> ");
- else
- res += printk(KERN_CONT "[%d] ", task_pid_vnr(current));
- }
- if (descriptor->flags & _DPRINTK_FLAGS_INCL_MODNAME)
- res += printk(KERN_CONT "%s:", descriptor->modname);
- if (descriptor->flags & _DPRINTK_FLAGS_INCL_FUNCNAME)
- res += printk(KERN_CONT "%s:", descriptor->function);
- if (descriptor->flags & _DPRINTK_FLAGS_INCL_LINENO)
- res += printk(KERN_CONT "%d ", descriptor->lineno);
- res += vprintk(fmt, args);
+ vaf.fmt = fmt;
+ vaf.va = &args;
+ res = printk("%s%pV", dynamic_emit_prefix(descriptor, buf), &vaf);
va_end(args);
return res;
}
EXPORT_SYMBOL(__dynamic_pr_debug);
+int __dynamic_dev_dbg(struct _ddebug *descriptor,
+ const struct device *dev, const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+ int res;
+ char buf[PREFIX_SIZE];
+
+ BUG_ON(!descriptor);
+ BUG_ON(!fmt);
+
+ va_start(args, fmt);
+ vaf.fmt = fmt;
+ vaf.va = &args;
+ res = __dev_printk(dynamic_emit_prefix(descriptor, buf), dev, &vaf);
+ va_end(args);
+
+ return res;
+}
+EXPORT_SYMBOL(__dynamic_dev_dbg);
+
+#ifdef CONFIG_NET
+
+int __dynamic_netdev_dbg(struct _ddebug *descriptor,
+ const struct net_device *dev, const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+ int res;
+ char buf[PREFIX_SIZE];
+
+ BUG_ON(!descriptor);
+ BUG_ON(!fmt);
+
+ va_start(args, fmt);
+ vaf.fmt = fmt;
+ vaf.va = &args;
+ res = __netdev_printk(dynamic_emit_prefix(descriptor, buf), dev, &vaf);
+ va_end(args);
+
+ return res;
+}
+EXPORT_SYMBOL(__dynamic_netdev_dbg);
+
+#endif
+
static __initdata char ddebug_setup_string[1024];
static __init int ddebug_setup_query(char *str)
{
if (strlen(str) >= 1024) {
- pr_warning("ddebug boot param string too large\n");
+ pr_warn("ddebug boot param string too large\n");
return 0;
}
strcpy(ddebug_setup_string, str);
@@ -488,8 +559,7 @@ static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf,
return -EFAULT;
tmpbuf[len] = '\0';
if (verbose)
- printk(KERN_INFO "%s: read %d bytes from userspace\n",
- __func__, (int)len);
+ pr_info("read %d bytes from userspace\n", (int)len);
ret = ddebug_exec_query(tmpbuf);
if (ret)
@@ -552,8 +622,7 @@ static void *ddebug_proc_start(struct seq_file *m, loff_t *pos)
int n = *pos;
if (verbose)
- printk(KERN_INFO "%s: called m=%p *pos=%lld\n",
- __func__, m, (unsigned long long)*pos);
+ pr_info("called m=%p *pos=%lld\n", m, (unsigned long long)*pos);
mutex_lock(&ddebug_lock);
@@ -578,8 +647,8 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
struct _ddebug *dp;
if (verbose)
- printk(KERN_INFO "%s: called m=%p p=%p *pos=%lld\n",
- __func__, m, p, (unsigned long long)*pos);
+ pr_info("called m=%p p=%p *pos=%lld\n",
+ m, p, (unsigned long long)*pos);
if (p == SEQ_START_TOKEN)
dp = ddebug_iter_first(iter);
@@ -602,8 +671,7 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
char flagsbuf[8];
if (verbose)
- printk(KERN_INFO "%s: called m=%p p=%p\n",
- __func__, m, p);
+ pr_info("called m=%p p=%p\n", m, p);
if (p == SEQ_START_TOKEN) {
seq_puts(m,
@@ -628,8 +696,7 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
static void ddebug_proc_stop(struct seq_file *m, void *p)
{
if (verbose)
- printk(KERN_INFO "%s: called m=%p p=%p\n",
- __func__, m, p);
+ pr_info("called m=%p p=%p\n", m, p);
mutex_unlock(&ddebug_lock);
}
@@ -652,7 +719,7 @@ static int ddebug_proc_open(struct inode *inode, struct file *file)
int err;
if (verbose)
- printk(KERN_INFO "%s: called\n", __func__);
+ pr_info("called\n");
iter = kzalloc(sizeof(*iter), GFP_KERNEL);
if (iter == NULL)
@@ -696,7 +763,6 @@ int ddebug_add_module(struct _ddebug *tab, unsigned int n,
}
dt->mod_name = new_name;
dt->num_ddebugs = n;
- dt->num_enabled = 0;
dt->ddebugs = tab;
mutex_lock(&ddebug_lock);
@@ -704,8 +770,7 @@ int ddebug_add_module(struct _ddebug *tab, unsigned int n,
mutex_unlock(&ddebug_lock);
if (verbose)
- printk(KERN_INFO "%u debug prints in module %s\n",
- n, dt->mod_name);
+ pr_info("%u debug prints in module %s\n", n, dt->mod_name);
return 0;
}
EXPORT_SYMBOL_GPL(ddebug_add_module);
@@ -727,8 +792,7 @@ int ddebug_remove_module(const char *mod_name)
int ret = -ENOENT;
if (verbose)
- printk(KERN_INFO "%s: removing module \"%s\"\n",
- __func__, mod_name);
+ pr_info("removing module \"%s\"\n", mod_name);
mutex_lock(&ddebug_lock);
list_for_each_entry_safe(dt, nextdt, &ddebug_tables, link) {
@@ -804,8 +868,8 @@ static int __init dynamic_debug_init(void)
if (ddebug_setup_string[0] != '\0') {
ret = ddebug_exec_query(ddebug_setup_string);
if (ret)
- pr_warning("Invalid ddebug boot param %s",
- ddebug_setup_string);
+ pr_warn("Invalid ddebug boot param %s",
+ ddebug_setup_string);
else
pr_info("ddebug initialized with string %s",
ddebug_setup_string);
diff --git a/lib/hexdump.c b/lib/hexdump.c
index f5fe6ba7a3ab..51d5ae210244 100644
--- a/lib/hexdump.c
+++ b/lib/hexdump.c
@@ -38,14 +38,21 @@ EXPORT_SYMBOL(hex_to_bin);
* @dst: binary result
* @src: ascii hexadecimal string
* @count: result length
+ *
+ * Return 0 on success, -1 in case of bad input.
*/
-void hex2bin(u8 *dst, const char *src, size_t count)
+int hex2bin(u8 *dst, const char *src, size_t count)
{
while (count--) {
- *dst = hex_to_bin(*src++) << 4;
- *dst += hex_to_bin(*src++);
- dst++;
+ int hi = hex_to_bin(*src++);
+ int lo = hex_to_bin(*src++);
+
+ if ((hi < 0) || (lo < 0))
+ return -1;
+
+ *dst++ = (hi << 4) | lo;
}
+ return 0;
}
EXPORT_SYMBOL(hex2bin);
diff --git a/lib/idr.c b/lib/idr.c
index db040ce3fa73..5acf9bb10968 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -860,7 +860,7 @@ EXPORT_SYMBOL(ida_get_new_above);
* and go back to the idr_pre_get() call. If the idr is full, it will
* return %-ENOSPC.
*
- * @id returns a value in the range %0 ... %0x7fffffff.
+ * @p_id returns a value in the range %0 ... %0x7fffffff.
*/
int ida_get_new(struct ida *ida, int *p_id)
{
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index 70af0a7f97c0..ad72a03ce5e9 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -282,7 +282,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
kobj_bcast_filter,
kobj);
/* ENOBUFS should be handled in userspace */
- if (retval == -ENOBUFS)
+ if (retval == -ENOBUFS || retval == -ESRCH)
retval = 0;
} else
retval = -ENOMEM;
diff --git a/lib/sha1.c b/lib/sha1.c
index f33271dd00cb..1de509a159c8 100644
--- a/lib/sha1.c
+++ b/lib/sha1.c
@@ -8,6 +8,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/bitops.h>
+#include <linux/cryptohash.h>
#include <asm/unaligned.h>
/*
diff --git a/lib/xz/xz_dec_bcj.c b/lib/xz/xz_dec_bcj.c
index e51e2558ca9d..a768e6d28bbb 100644
--- a/lib/xz/xz_dec_bcj.c
+++ b/lib/xz/xz_dec_bcj.c
@@ -441,8 +441,12 @@ XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s,
* next filter in the chain. Apply the BCJ filter on the new data
* in the output buffer. If everything cannot be filtered, copy it
* to temp and rewind the output buffer position accordingly.
+ *
+ * This needs to be always run when temp.size == 0 to handle a special
+ * case where the output buffer is full and the next filter has no
+ * more output coming but hasn't returned XZ_STREAM_END yet.
*/
- if (s->temp.size < b->out_size - b->out_pos) {
+ if (s->temp.size < b->out_size - b->out_pos || s->temp.size == 0) {
out_start = b->out_pos;
memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size);
b->out_pos += s->temp.size;
@@ -465,16 +469,25 @@ XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s,
s->temp.size = b->out_pos - out_start;
b->out_pos -= s->temp.size;
memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size);
+
+ /*
+ * If there wasn't enough input to the next filter to fill
+ * the output buffer with unfiltered data, there's no point
+ * to try decoding more data to temp.
+ */
+ if (b->out_pos + s->temp.size < b->out_size)
+ return XZ_OK;
}
/*
- * If we have unfiltered data in temp, try to fill by decoding more
- * data from the next filter. Apply the BCJ filter on temp. Then we
- * hopefully can fill the actual output buffer by copying filtered
- * data from temp. A mix of filtered and unfiltered data may be left
- * in temp; it will be taken care on the next call to this function.
+ * We have unfiltered data in temp. If the output buffer isn't full
+ * yet, try to fill the temp buffer by decoding more data from the
+ * next filter. Apply the BCJ filter on temp. Then we hopefully can
+ * fill the actual output buffer by copying filtered data from temp.
+ * A mix of filtered and unfiltered data may be left in temp; it will
+ * be taken care on the next call to this function.
*/
- if (s->temp.size > 0) {
+ if (b->out_pos < b->out_size) {
/* Make b->out{,_pos,_size} temporarily point to s->temp. */
s->out = b->out;
s->out_pos = b->out_pos;
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index d6edf8d14f9c..a87da524a4a0 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -359,6 +359,17 @@ static unsigned long bdi_longest_inactive(void)
return max(5UL * 60 * HZ, interval);
}
+/*
+ * Clear pending bit and wakeup anybody waiting for flusher thread creation or
+ * shutdown
+ */
+static void bdi_clear_pending(struct backing_dev_info *bdi)
+{
+ clear_bit(BDI_pending, &bdi->state);
+ smp_mb__after_clear_bit();
+ wake_up_bit(&bdi->state, BDI_pending);
+}
+
static int bdi_forker_thread(void *ptr)
{
struct bdi_writeback *me = ptr;
@@ -390,6 +401,13 @@ static int bdi_forker_thread(void *ptr)
}
spin_lock_bh(&bdi_lock);
+ /*
+ * In the following loop we are going to check whether we have
+ * some work to do without any synchronization with tasks
+ * waking us up to do work for them. So we have to set task
+ * state already here so that we don't miss wakeups coming
+ * after we verify some condition.
+ */
set_current_state(TASK_INTERRUPTIBLE);
list_for_each_entry(bdi, &bdi_list, bdi_list) {
@@ -469,11 +487,13 @@ static int bdi_forker_thread(void *ptr)
spin_unlock_bh(&bdi->wb_lock);
wake_up_process(task);
}
+ bdi_clear_pending(bdi);
break;
case KILL_THREAD:
__set_current_state(TASK_RUNNING);
kthread_stop(task);
+ bdi_clear_pending(bdi);
break;
case NO_ACTION:
@@ -489,16 +509,8 @@ static int bdi_forker_thread(void *ptr)
else
schedule_timeout(msecs_to_jiffies(dirty_writeback_interval * 10));
try_to_freeze();
- /* Back to the main loop */
- continue;
+ break;
}
-
- /*
- * Clear pending bit and wakeup anybody waiting to tear us down.
- */
- clear_bit(BDI_pending, &bdi->state);
- smp_mb__after_clear_bit();
- wake_up_bit(&bdi->state, BDI_pending);
}
return 0;
diff --git a/mm/filemap.c b/mm/filemap.c
index 645a080ba4df..7771871fa353 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -827,13 +827,14 @@ unsigned find_get_pages(struct address_space *mapping, pgoff_t start,
{
unsigned int i;
unsigned int ret;
- unsigned int nr_found;
+ unsigned int nr_found, nr_skip;
rcu_read_lock();
restart:
nr_found = radix_tree_gang_lookup_slot(&mapping->page_tree,
(void ***)pages, NULL, start, nr_pages);
ret = 0;
+ nr_skip = 0;
for (i = 0; i < nr_found; i++) {
struct page *page;
repeat:
@@ -856,6 +857,7 @@ repeat:
* here as an exceptional entry: so skip over it -
* we only reach this from invalidate_mapping_pages().
*/
+ nr_skip++;
continue;
}
@@ -876,7 +878,7 @@ repeat:
* If all entries were removed before we could secure them,
* try again, because callers stop trying once 0 is returned.
*/
- if (unlikely(!ret && nr_found))
+ if (unlikely(!ret && nr_found > nr_skip))
goto restart;
rcu_read_unlock();
return ret;
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 930de9437271..3508777837c7 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -204,50 +204,6 @@ struct mem_cgroup_eventfd_list {
static void mem_cgroup_threshold(struct mem_cgroup *mem);
static void mem_cgroup_oom_notify(struct mem_cgroup *mem);
-enum {
- SCAN_BY_LIMIT,
- SCAN_BY_SYSTEM,
- NR_SCAN_CONTEXT,
- SCAN_BY_SHRINK, /* not recorded now */
-};
-
-enum {
- SCAN,
- SCAN_ANON,
- SCAN_FILE,
- ROTATE,
- ROTATE_ANON,
- ROTATE_FILE,
- FREED,
- FREED_ANON,
- FREED_FILE,
- ELAPSED,
- NR_SCANSTATS,
-};
-
-struct scanstat {
- spinlock_t lock;
- unsigned long stats[NR_SCAN_CONTEXT][NR_SCANSTATS];
- unsigned long rootstats[NR_SCAN_CONTEXT][NR_SCANSTATS];
-};
-
-const char *scanstat_string[NR_SCANSTATS] = {
- "scanned_pages",
- "scanned_anon_pages",
- "scanned_file_pages",
- "rotated_pages",
- "rotated_anon_pages",
- "rotated_file_pages",
- "freed_pages",
- "freed_anon_pages",
- "freed_file_pages",
- "elapsed_ns",
-};
-#define SCANSTAT_WORD_LIMIT "_by_limit"
-#define SCANSTAT_WORD_SYSTEM "_by_system"
-#define SCANSTAT_WORD_HIERARCHY "_under_hierarchy"
-
-
/*
* The memory controller data structure. The memory controller controls both
* page cache and RSS per cgroup. We would eventually like to provide
@@ -313,8 +269,7 @@ struct mem_cgroup {
/* For oom notifier event fd */
struct list_head oom_notify;
- /* For recording LRU-scan statistics */
- struct scanstat scanstat;
+
/*
* Should we move charges of a task when a task is moved into this
* mem_cgroup ? And what type of charges should we move ?
@@ -1678,44 +1633,6 @@ bool mem_cgroup_reclaimable(struct mem_cgroup *mem, bool noswap)
}
#endif
-static void __mem_cgroup_record_scanstat(unsigned long *stats,
- struct memcg_scanrecord *rec)
-{
-
- stats[SCAN] += rec->nr_scanned[0] + rec->nr_scanned[1];
- stats[SCAN_ANON] += rec->nr_scanned[0];
- stats[SCAN_FILE] += rec->nr_scanned[1];
-
- stats[ROTATE] += rec->nr_rotated[0] + rec->nr_rotated[1];
- stats[ROTATE_ANON] += rec->nr_rotated[0];
- stats[ROTATE_FILE] += rec->nr_rotated[1];
-
- stats[FREED] += rec->nr_freed[0] + rec->nr_freed[1];
- stats[FREED_ANON] += rec->nr_freed[0];
- stats[FREED_FILE] += rec->nr_freed[1];
-
- stats[ELAPSED] += rec->elapsed;
-}
-
-static void mem_cgroup_record_scanstat(struct memcg_scanrecord *rec)
-{
- struct mem_cgroup *mem;
- int context = rec->context;
-
- if (context >= NR_SCAN_CONTEXT)
- return;
-
- mem = rec->mem;
- spin_lock(&mem->scanstat.lock);
- __mem_cgroup_record_scanstat(mem->scanstat.stats[context], rec);
- spin_unlock(&mem->scanstat.lock);
-
- mem = rec->root;
- spin_lock(&mem->scanstat.lock);
- __mem_cgroup_record_scanstat(mem->scanstat.rootstats[context], rec);
- spin_unlock(&mem->scanstat.lock);
-}
-
/*
* Scan the hierarchy if needed to reclaim memory. We remember the last child
* we reclaimed from, so that we don't end up penalizing one child extensively
@@ -1740,9 +1657,8 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem,
bool noswap = reclaim_options & MEM_CGROUP_RECLAIM_NOSWAP;
bool shrink = reclaim_options & MEM_CGROUP_RECLAIM_SHRINK;
bool check_soft = reclaim_options & MEM_CGROUP_RECLAIM_SOFT;
- struct memcg_scanrecord rec;
unsigned long excess;
- unsigned long scanned;
+ unsigned long nr_scanned;
excess = res_counter_soft_limit_excess(&root_mem->res) >> PAGE_SHIFT;
@@ -1750,15 +1666,6 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem,
if (!check_soft && !shrink && root_mem->memsw_is_minimum)
noswap = true;
- if (shrink)
- rec.context = SCAN_BY_SHRINK;
- else if (check_soft)
- rec.context = SCAN_BY_SYSTEM;
- else
- rec.context = SCAN_BY_LIMIT;
-
- rec.root = root_mem;
-
while (1) {
victim = mem_cgroup_select_victim(root_mem);
if (victim == root_mem) {
@@ -1799,23 +1706,14 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem,
css_put(&victim->css);
continue;
}
- rec.mem = victim;
- rec.nr_scanned[0] = 0;
- rec.nr_scanned[1] = 0;
- rec.nr_rotated[0] = 0;
- rec.nr_rotated[1] = 0;
- rec.nr_freed[0] = 0;
- rec.nr_freed[1] = 0;
- rec.elapsed = 0;
/* we use swappiness of local cgroup */
if (check_soft) {
ret = mem_cgroup_shrink_node_zone(victim, gfp_mask,
- noswap, zone, &rec, &scanned);
- *total_scanned += scanned;
+ noswap, zone, &nr_scanned);
+ *total_scanned += nr_scanned;
} else
ret = try_to_free_mem_cgroup_pages(victim, gfp_mask,
- noswap, &rec);
- mem_cgroup_record_scanstat(&rec);
+ noswap);
css_put(&victim->css);
/*
* At shrinking usage, we can't check we should stop here or
@@ -1841,29 +1739,23 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem,
*/
static bool mem_cgroup_oom_lock(struct mem_cgroup *mem)
{
- int lock_count = -1;
struct mem_cgroup *iter, *failed = NULL;
bool cond = true;
for_each_mem_cgroup_tree_cond(iter, mem, cond) {
- bool locked = iter->oom_lock;
-
- iter->oom_lock = true;
- if (lock_count == -1)
- lock_count = iter->oom_lock;
- else if (lock_count != locked) {
+ if (iter->oom_lock) {
/*
* this subtree of our hierarchy is already locked
* so we cannot give a lock.
*/
- lock_count = 0;
failed = iter;
cond = false;
- }
+ } else
+ iter->oom_lock = true;
}
if (!failed)
- goto done;
+ return true;
/*
* OK, we failed to lock the whole subtree so we have to clean up
@@ -1877,8 +1769,7 @@ static bool mem_cgroup_oom_lock(struct mem_cgroup *mem)
}
iter->oom_lock = false;
}
-done:
- return lock_count;
+ return false;
}
/*
@@ -2169,13 +2060,7 @@ static void drain_all_stock(struct mem_cgroup *root_mem, bool sync)
/* Notify other cpus that system-wide "drain" is running */
get_online_cpus();
- /*
- * Get a hint for avoiding draining charges on the current cpu,
- * which must be exhausted by our charging. It is not required that
- * this be a precise check, so we use raw_smp_processor_id() instead of
- * getcpu()/putcpu().
- */
- curcpu = raw_smp_processor_id();
+ curcpu = get_cpu();
for_each_online_cpu(cpu) {
struct memcg_stock_pcp *stock = &per_cpu(memcg_stock, cpu);
struct mem_cgroup *mem;
@@ -2192,6 +2077,7 @@ static void drain_all_stock(struct mem_cgroup *root_mem, bool sync)
schedule_work_on(cpu, &stock->work);
}
}
+ put_cpu();
if (!sync)
goto out;
@@ -3866,18 +3752,14 @@ try_to_free:
/* try to free all pages in this cgroup */
shrink = 1;
while (nr_retries && mem->res.usage > 0) {
- struct memcg_scanrecord rec;
int progress;
if (signal_pending(current)) {
ret = -EINTR;
goto out;
}
- rec.context = SCAN_BY_SHRINK;
- rec.mem = mem;
- rec.root = mem;
progress = try_to_free_mem_cgroup_pages(mem, GFP_KERNEL,
- false, &rec);
+ false);
if (!progress) {
nr_retries--;
/* maybe some writeback is necessary */
@@ -4721,54 +4603,6 @@ static int mem_control_numa_stat_open(struct inode *unused, struct file *file)
}
#endif /* CONFIG_NUMA */
-static int mem_cgroup_vmscan_stat_read(struct cgroup *cgrp,
- struct cftype *cft,
- struct cgroup_map_cb *cb)
-{
- struct mem_cgroup *mem = mem_cgroup_from_cont(cgrp);
- char string[64];
- int i;
-
- for (i = 0; i < NR_SCANSTATS; i++) {
- strcpy(string, scanstat_string[i]);
- strcat(string, SCANSTAT_WORD_LIMIT);
- cb->fill(cb, string, mem->scanstat.stats[SCAN_BY_LIMIT][i]);
- }
-
- for (i = 0; i < NR_SCANSTATS; i++) {
- strcpy(string, scanstat_string[i]);
- strcat(string, SCANSTAT_WORD_SYSTEM);
- cb->fill(cb, string, mem->scanstat.stats[SCAN_BY_SYSTEM][i]);
- }
-
- for (i = 0; i < NR_SCANSTATS; i++) {
- strcpy(string, scanstat_string[i]);
- strcat(string, SCANSTAT_WORD_LIMIT);
- strcat(string, SCANSTAT_WORD_HIERARCHY);
- cb->fill(cb, string, mem->scanstat.rootstats[SCAN_BY_LIMIT][i]);
- }
- for (i = 0; i < NR_SCANSTATS; i++) {
- strcpy(string, scanstat_string[i]);
- strcat(string, SCANSTAT_WORD_SYSTEM);
- strcat(string, SCANSTAT_WORD_HIERARCHY);
- cb->fill(cb, string, mem->scanstat.rootstats[SCAN_BY_SYSTEM][i]);
- }
- return 0;
-}
-
-static int mem_cgroup_reset_vmscan_stat(struct cgroup *cgrp,
- unsigned int event)
-{
- struct mem_cgroup *mem = mem_cgroup_from_cont(cgrp);
-
- spin_lock(&mem->scanstat.lock);
- memset(&mem->scanstat.stats, 0, sizeof(mem->scanstat.stats));
- memset(&mem->scanstat.rootstats, 0, sizeof(mem->scanstat.rootstats));
- spin_unlock(&mem->scanstat.lock);
- return 0;
-}
-
-
static struct cftype mem_cgroup_files[] = {
{
.name = "usage_in_bytes",
@@ -4839,11 +4673,6 @@ static struct cftype mem_cgroup_files[] = {
.mode = S_IRUGO,
},
#endif
- {
- .name = "vmscan_stat",
- .read_map = mem_cgroup_vmscan_stat_read,
- .trigger = mem_cgroup_reset_vmscan_stat,
- },
};
#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
@@ -5107,7 +4936,6 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
atomic_set(&mem->refcnt, 1);
mem->move_charge_at_immigrate = 0;
mutex_init(&mem->thresholds_lock);
- spin_lock_init(&mem->scanstat.lock);
return &mem->css;
free_out:
__mem_cgroup_free(mem);
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 8b57173c1dd5..9c51f9f58cac 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -636,7 +636,6 @@ static int mbind_range(struct mm_struct *mm, unsigned long start,
struct vm_area_struct *prev;
struct vm_area_struct *vma;
int err = 0;
- pgoff_t pgoff;
unsigned long vmstart;
unsigned long vmend;
@@ -649,9 +648,9 @@ static int mbind_range(struct mm_struct *mm, unsigned long start,
vmstart = max(start, vma->vm_start);
vmend = min(end, vma->vm_end);
- pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
prev = vma_merge(mm, prev, vmstart, vmend, vma->vm_flags,
- vma->anon_vma, vma->vm_file, pgoff, new_pol);
+ vma->anon_vma, vma->vm_file, vma->vm_pgoff,
+ new_pol);
if (prev) {
vma = prev;
next = vma->vm_next;
@@ -1412,7 +1411,9 @@ asmlinkage long compat_sys_get_mempolicy(int __user *policy,
err = sys_get_mempolicy(policy, nm, nr_bits+1, addr, flags);
if (!err && nmask) {
- err = copy_from_user(bm, nm, alloc_size);
+ unsigned long copy_size;
+ copy_size = min_t(unsigned long, sizeof(bm), alloc_size);
+ err = copy_from_user(bm, nm, copy_size);
/* ensure entire bitmap is zeroed */
err |= clear_user(nmask, ALIGN(maxnode-1, 8) / 8);
err |= compat_put_bitmap(nmask, bm, nr_bits);
diff --git a/mm/migrate.c b/mm/migrate.c
index 666e4e677414..14d0a6a632f6 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -120,10 +120,10 @@ static int remove_migration_pte(struct page *new, struct vm_area_struct *vma,
ptep = pte_offset_map(pmd, addr);
- if (!is_swap_pte(*ptep)) {
- pte_unmap(ptep);
- goto out;
- }
+ /*
+ * Peek to check is_swap_pte() before taking ptlock? No, we
+ * can race mremap's move_ptes(), which skips anon_vma lock.
+ */
ptl = pte_lockptr(mm, pmd);
}
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index d1960744f881..0e309cd1b5b9 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -754,21 +754,10 @@ static void balance_dirty_pages(struct address_space *mapping,
* 200ms is typically more than enough to curb heavy dirtiers;
* (b) the pause time limit makes the dirtiers more responsive.
*/
- if (nr_dirty < dirty_thresh +
- dirty_thresh / DIRTY_MAXPAUSE_AREA &&
+ if (nr_dirty < dirty_thresh &&
+ bdi_dirty < (task_bdi_thresh + bdi_thresh) / 2 &&
time_after(jiffies, start_time + MAX_PAUSE))
break;
- /*
- * pass-good area. When some bdi gets blocked (eg. NFS server
- * not responding), or write bandwidth dropped dramatically due
- * to concurrent reads, or dirty threshold suddenly dropped and
- * the dirty pages cannot be brought down anytime soon (eg. on
- * slow USB stick), at least let go of the good bdi's.
- */
- if (nr_dirty < dirty_thresh +
- dirty_thresh / DIRTY_PASSGOOD_AREA &&
- bdi_dirty < bdi_thresh)
- break;
/*
* Increase the delay for each loop, up to our previous
diff --git a/mm/page_cgroup.c b/mm/page_cgroup.c
index 39d216d535ea..6bdc67dbbc28 100644
--- a/mm/page_cgroup.c
+++ b/mm/page_cgroup.c
@@ -513,11 +513,10 @@ int swap_cgroup_swapon(int type, unsigned long max_pages)
length = DIV_ROUND_UP(max_pages, SC_PER_PAGE);
array_size = length * sizeof(void *);
- array = vmalloc(array_size);
+ array = vzalloc(array_size);
if (!array)
goto nomem;
- memset(array, 0, array_size);
ctrl = &swap_cgroup_ctrl[type];
mutex_lock(&swap_cgroup_mutex);
ctrl->length = length;
diff --git a/mm/shmem.c b/mm/shmem.c
index 32f6763f16fb..2d3577295298 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1458,7 +1458,7 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
inode = shmem_get_inode(dir->i_sb, dir, mode, dev, VM_NORESERVE);
if (inode) {
error = security_inode_init_security(inode, dir,
- &dentry->d_name, NULL,
+ &dentry->d_name,
NULL, NULL);
if (error) {
if (error != -EOPNOTSUPP) {
@@ -1598,7 +1598,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
if (!inode)
return -ENOSPC;
- error = security_inode_init_security(inode, dir, &dentry->d_name, NULL,
+ error = security_inode_init_security(inode, dir, &dentry->d_name,
NULL, NULL);
if (error) {
if (error != -EOPNOTSUPP) {
diff --git a/mm/slub.c b/mm/slub.c
index 9f662d70eb47..7c54fe83a90c 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2377,7 +2377,7 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
*/
if (unlikely(!prior)) {
remove_full(s, page);
- add_partial(n, page, 0);
+ add_partial(n, page, 1);
stat(s, FREE_ADD_PARTIAL);
}
}
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 7ef0903058ee..5016f19e1661 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -2140,6 +2140,14 @@ struct vm_struct *alloc_vm_area(size_t size)
return NULL;
}
+ /*
+ * If the allocated address space is passed to a hypercall
+ * before being used then we cannot rely on a page fault to
+ * trigger an update of the page tables. So sync all the page
+ * tables here.
+ */
+ vmalloc_sync_all();
+
return area;
}
EXPORT_SYMBOL_GPL(alloc_vm_area);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 7ef69124fa3e..9fdfce7ba403 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -105,7 +105,6 @@ struct scan_control {
/* Which cgroup do we reclaim from */
struct mem_cgroup *mem_cgroup;
- struct memcg_scanrecord *memcg_record;
/*
* Nodemask of nodes allowed by the caller. If NULL, all nodes
@@ -1349,8 +1348,6 @@ putback_lru_pages(struct zone *zone, struct scan_control *sc,
int file = is_file_lru(lru);
int numpages = hpage_nr_pages(page);
reclaim_stat->recent_rotated[file] += numpages;
- if (!scanning_global_lru(sc))
- sc->memcg_record->nr_rotated[file] += numpages;
}
if (!pagevec_add(&pvec, page)) {
spin_unlock_irq(&zone->lru_lock);
@@ -1394,10 +1391,6 @@ static noinline_for_stack void update_isolated_counts(struct zone *zone,
reclaim_stat->recent_scanned[0] += *nr_anon;
reclaim_stat->recent_scanned[1] += *nr_file;
- if (!scanning_global_lru(sc)) {
- sc->memcg_record->nr_scanned[0] += *nr_anon;
- sc->memcg_record->nr_scanned[1] += *nr_file;
- }
}
/*
@@ -1423,7 +1416,7 @@ static inline bool should_reclaim_stall(unsigned long nr_taken,
if (sc->reclaim_mode & RECLAIM_MODE_SINGLE)
return false;
- /* If we have relaimed everything on the isolated list, no stall */
+ /* If we have reclaimed everything on the isolated list, no stall */
if (nr_freed == nr_taken)
return false;
@@ -1511,9 +1504,6 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
nr_reclaimed += shrink_page_list(&page_list, zone, sc);
}
- if (!scanning_global_lru(sc))
- sc->memcg_record->nr_freed[file] += nr_reclaimed;
-
local_irq_disable();
if (current_is_kswapd())
__count_vm_events(KSWAPD_STEAL, nr_reclaimed);
@@ -1613,8 +1603,6 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
}
reclaim_stat->recent_scanned[file] += nr_taken;
- if (!scanning_global_lru(sc))
- sc->memcg_record->nr_scanned[file] += nr_taken;
__count_zone_vm_events(PGREFILL, zone, pgscanned);
if (file)
@@ -1666,8 +1654,6 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
* get_scan_ratio.
*/
reclaim_stat->recent_rotated[file] += nr_rotated;
- if (!scanning_global_lru(sc))
- sc->memcg_record->nr_rotated[file] += nr_rotated;
move_active_pages_to_lru(zone, &l_active,
LRU_ACTIVE + file * LRU_FILE);
@@ -1808,23 +1794,15 @@ static void get_scan_count(struct zone *zone, struct scan_control *sc,
u64 fraction[2], denominator;
enum lru_list l;
int noswap = 0;
- int force_scan = 0;
+ bool force_scan = false;
unsigned long nr_force_scan[2];
-
- anon = zone_nr_lru_pages(zone, sc, LRU_ACTIVE_ANON) +
- zone_nr_lru_pages(zone, sc, LRU_INACTIVE_ANON);
- file = zone_nr_lru_pages(zone, sc, LRU_ACTIVE_FILE) +
- zone_nr_lru_pages(zone, sc, LRU_INACTIVE_FILE);
-
- if (((anon + file) >> priority) < SWAP_CLUSTER_MAX) {
- /* kswapd does zone balancing and need to scan this zone */
- if (scanning_global_lru(sc) && current_is_kswapd())
- force_scan = 1;
- /* memcg may have small limit and need to avoid priority drop */
- if (!scanning_global_lru(sc))
- force_scan = 1;
- }
+ /* kswapd does zone balancing and needs to scan this zone */
+ if (scanning_global_lru(sc) && current_is_kswapd())
+ force_scan = true;
+ /* memcg may have small limit and need to avoid priority drop */
+ if (!scanning_global_lru(sc))
+ force_scan = true;
/* If we have no swap space, do not bother scanning anon pages. */
if (!sc->may_swap || (nr_swap_pages <= 0)) {
@@ -1837,6 +1815,11 @@ static void get_scan_count(struct zone *zone, struct scan_control *sc,
goto out;
}
+ anon = zone_nr_lru_pages(zone, sc, LRU_ACTIVE_ANON) +
+ zone_nr_lru_pages(zone, sc, LRU_INACTIVE_ANON);
+ file = zone_nr_lru_pages(zone, sc, LRU_ACTIVE_FILE) +
+ zone_nr_lru_pages(zone, sc, LRU_INACTIVE_FILE);
+
if (scanning_global_lru(sc)) {
free = zone_page_state(zone, NR_FREE_PAGES);
/* If we have very few page cache pages,
@@ -2268,10 +2251,9 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
#ifdef CONFIG_CGROUP_MEM_RES_CTLR
unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
- gfp_t gfp_mask, bool noswap,
- struct zone *zone,
- struct memcg_scanrecord *rec,
- unsigned long *scanned)
+ gfp_t gfp_mask, bool noswap,
+ struct zone *zone,
+ unsigned long *nr_scanned)
{
struct scan_control sc = {
.nr_scanned = 0,
@@ -2281,9 +2263,7 @@ unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
.may_swap = !noswap,
.order = 0,
.mem_cgroup = mem,
- .memcg_record = rec,
};
- unsigned long start, end;
sc.gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
(GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK);
@@ -2292,7 +2272,6 @@ unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
sc.may_writepage,
sc.gfp_mask);
- start = sched_clock();
/*
* NOTE: Although we can get the priority field, using it
* here is not a good idea, since it limits the pages we can scan.
@@ -2301,25 +2280,19 @@ unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
* the priority and make it zero.
*/
shrink_zone(0, zone, &sc);
- end = sched_clock();
-
- if (rec)
- rec->elapsed += end - start;
- *scanned = sc.nr_scanned;
trace_mm_vmscan_memcg_softlimit_reclaim_end(sc.nr_reclaimed);
+ *nr_scanned = sc.nr_scanned;
return sc.nr_reclaimed;
}
unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
gfp_t gfp_mask,
- bool noswap,
- struct memcg_scanrecord *rec)
+ bool noswap)
{
struct zonelist *zonelist;
unsigned long nr_reclaimed;
- unsigned long start, end;
int nid;
struct scan_control sc = {
.may_writepage = !laptop_mode,
@@ -2328,7 +2301,6 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
.nr_to_reclaim = SWAP_CLUSTER_MAX,
.order = 0,
.mem_cgroup = mem_cont,
- .memcg_record = rec,
.nodemask = NULL, /* we don't care the placement */
.gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
(GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK),
@@ -2337,7 +2309,6 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
.gfp_mask = sc.gfp_mask,
};
- start = sched_clock();
/*
* Unlike direct reclaim via alloc_pages(), memcg's reclaim doesn't
* take care of from where we get pages. So the node where we start the
@@ -2352,9 +2323,6 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
sc.gfp_mask);
nr_reclaimed = do_try_to_free_pages(zonelist, &sc, &shrink);
- end = sched_clock();
- if (rec)
- rec->elapsed += end - start;
trace_mm_vmscan_memcg_reclaim_end(nr_reclaimed);
@@ -2529,6 +2497,9 @@ loop_again:
high_wmark_pages(zone), 0, 0)) {
end_zone = i;
break;
+ } else {
+ /* If balanced, clear the congested flag */
+ zone_clear_flag(zone, ZONE_CONGESTED);
}
}
if (i < 0)
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 20c18b7694b2..d52b13d28e8f 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -659,7 +659,7 @@ static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat,
}
#endif
-#if defined(CONFIG_PROC_FS) || defined(CONFIG_SYSFS)
+#if defined(CONFIG_PROC_FS) || defined(CONFIG_SYSFS) || defined(CONFIG_NUMA)
#ifdef CONFIG_ZONE_DMA
#define TEXT_FOR_DMA(xx) xx "_dma",
#else
@@ -788,7 +788,7 @@ const char * const vmstat_text[] = {
#endif /* CONFIG_VM_EVENTS_COUNTERS */
};
-#endif /* CONFIG_PROC_FS || CONFIG_SYSFS */
+#endif /* CONFIG_PROC_FS || CONFIG_SYSFS || CONFIG_NUMA */
#ifdef CONFIG_PROC_FS
diff --git a/net/802/garp.c b/net/802/garp.c
index 16102951d36a..070bf4403bf8 100644
--- a/net/802/garp.c
+++ b/net/802/garp.c
@@ -553,7 +553,7 @@ static void garp_release_port(struct net_device *dev)
if (rtnl_dereference(port->applicants[i]))
return;
}
- rcu_assign_pointer(dev->garp_port, NULL);
+ RCU_INIT_POINTER(dev->garp_port, NULL);
kfree_rcu(port, rcu);
}
@@ -605,7 +605,7 @@ void garp_uninit_applicant(struct net_device *dev, struct garp_application *appl
ASSERT_RTNL();
- rcu_assign_pointer(port->applicants[appl->type], NULL);
+ RCU_INIT_POINTER(port->applicants[appl->type], NULL);
/* Delete timer and generate a final TRANSMIT_PDU event to flush out
* all pending messages before the applicant is gone. */
diff --git a/net/802/stp.c b/net/802/stp.c
index 978c30b1b36b..0e136ef1e4ba 100644
--- a/net/802/stp.c
+++ b/net/802/stp.c
@@ -88,9 +88,9 @@ void stp_proto_unregister(const struct stp_proto *proto)
{
mutex_lock(&stp_proto_mutex);
if (is_zero_ether_addr(proto->group_address))
- rcu_assign_pointer(stp_proto, NULL);
+ RCU_INIT_POINTER(stp_proto, NULL);
else
- rcu_assign_pointer(garp_protos[proto->group_address[5] -
+ RCU_INIT_POINTER(garp_protos[proto->group_address[5] -
GARP_ADDR_MIN], NULL);
synchronize_rcu();
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 8970ba139d73..5471628d3ffe 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -133,7 +133,7 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
if (grp->nr_vlans == 0) {
vlan_gvrp_uninit_applicant(real_dev);
- rcu_assign_pointer(real_dev->vlgrp, NULL);
+ RCU_INIT_POINTER(real_dev->vlgrp, NULL);
/* Free the group, after all cpu's are done. */
call_rcu(&grp->rcu, vlan_rcu_free);
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index 5f27f8e30254..f1f2f7bb6661 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -167,6 +167,8 @@ struct sk_buff *vlan_untag(struct sk_buff *skb)
if (unlikely(!skb))
goto err_free;
+ skb_reset_network_header(skb);
+ skb_reset_transport_header(skb);
return skb;
err_free:
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 9d40a071d038..c8cf9391417e 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -610,7 +610,8 @@ static int vlan_ethtool_get_settings(struct net_device *dev,
struct ethtool_cmd *cmd)
{
const struct vlan_dev_info *vlan = vlan_dev_info(dev);
- return dev_ethtool_get_settings(vlan->real_dev, cmd);
+
+ return __ethtool_get_settings(vlan->real_dev, cmd);
}
static void vlan_ethtool_get_drvinfo(struct net_device *dev,
@@ -674,7 +675,6 @@ static const struct net_device_ops vlan_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = vlan_dev_set_mac_address,
.ndo_set_rx_mode = vlan_dev_set_rx_mode,
- .ndo_set_multicast_list = vlan_dev_set_rx_mode,
.ndo_change_rx_flags = vlan_dev_change_rx_flags,
.ndo_do_ioctl = vlan_dev_ioctl,
.ndo_neigh_setup = vlan_dev_neigh_setup,
diff --git a/net/9p/client.c b/net/9p/client.c
index 0505a03c374c..854ca7a911c4 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -38,6 +38,9 @@
#include <net/9p/transport.h>
#include "protocol.h"
+#define CREATE_TRACE_POINTS
+#include <trace/events/9p.h>
+
/*
* Client Option Parsing (code inspired by NFS code)
* - a little lazy - parse all client options
@@ -123,21 +126,19 @@ static int parse_opts(char *opts, struct p9_client *clnt)
options = tmp_options;
while ((p = strsep(&options, ",")) != NULL) {
- int token;
+ int token, r;
if (!*p)
continue;
token = match_token(p, tokens, args);
- if (token < Opt_trans) {
- int r = match_int(&args[0], &option);
+ switch (token) {
+ case Opt_msize:
+ r = match_int(&args[0], &option);
if (r < 0) {
P9_DPRINTK(P9_DEBUG_ERROR,
- "integer field, but no integer?\n");
+ "integer field, but no integer?\n");
ret = r;
continue;
}
- }
- switch (token) {
- case Opt_msize:
clnt->msize = option;
break;
case Opt_trans:
@@ -203,11 +204,13 @@ free_and_return:
*
*/
-static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag)
+static struct p9_req_t *
+p9_tag_alloc(struct p9_client *c, u16 tag, unsigned int max_size)
{
unsigned long flags;
int row, col;
struct p9_req_t *req;
+ int alloc_msize = min(c->msize, max_size);
/* This looks up the original request by tag so we know which
* buffer to read the data into */
@@ -245,23 +248,10 @@ static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag)
return ERR_PTR(-ENOMEM);
}
init_waitqueue_head(req->wq);
- if ((c->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) ==
- P9_TRANS_PREF_PAYLOAD_SEP) {
- int alloc_msize = min(c->msize, 4096);
- req->tc = kmalloc(sizeof(struct p9_fcall)+alloc_msize,
- GFP_NOFS);
- req->tc->capacity = alloc_msize;
- req->rc = kmalloc(sizeof(struct p9_fcall)+alloc_msize,
- GFP_NOFS);
- req->rc->capacity = alloc_msize;
- } else {
- req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize,
- GFP_NOFS);
- req->tc->capacity = c->msize;
- req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize,
- GFP_NOFS);
- req->rc->capacity = c->msize;
- }
+ req->tc = kmalloc(sizeof(struct p9_fcall) + alloc_msize,
+ GFP_NOFS);
+ req->rc = kmalloc(sizeof(struct p9_fcall) + alloc_msize,
+ GFP_NOFS);
if ((!req->tc) || (!req->rc)) {
printk(KERN_ERR "Couldn't grow tag array\n");
kfree(req->tc);
@@ -271,6 +261,8 @@ static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag)
req->wq = NULL;
return ERR_PTR(-ENOMEM);
}
+ req->tc->capacity = alloc_msize;
+ req->rc->capacity = alloc_msize;
req->tc->sdata = (char *) req->tc + sizeof(struct p9_fcall);
req->rc->sdata = (char *) req->rc + sizeof(struct p9_fcall);
}
@@ -475,37 +467,22 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
int ecode;
err = p9_parse_header(req->rc, NULL, &type, NULL, 0);
+ /*
+ * dump the response from server
+ * This should be after check errors which poplulate pdu_fcall.
+ */
+ trace_9p_protocol_dump(c, req->rc);
if (err) {
P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse header %d\n", err);
return err;
}
-
if (type != P9_RERROR && type != P9_RLERROR)
return 0;
if (!p9_is_proto_dotl(c)) {
char *ename;
-
- if (req->tc->pbuf_size) {
- /* Handle user buffers */
- size_t len = req->rc->size - req->rc->offset;
- if (req->tc->pubuf) {
- /* User Buffer */
- err = copy_from_user(
- &req->rc->sdata[req->rc->offset],
- req->tc->pubuf, len);
- if (err) {
- err = -EFAULT;
- goto out_err;
- }
- } else {
- /* Kernel Buffer */
- memmove(&req->rc->sdata[req->rc->offset],
- req->tc->pkbuf, len);
- }
- }
err = p9pdu_readf(req->rc, c->proto_version, "s?d",
- &ename, &ecode);
+ &ename, &ecode);
if (err)
goto out_err;
@@ -515,11 +492,10 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
if (!err || !IS_ERR_VALUE(err)) {
err = p9_errstr2errno(ename, strlen(ename));
- P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode,
- ename);
-
- kfree(ename);
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n",
+ -ecode, ename);
}
+ kfree(ename);
} else {
err = p9pdu_readf(req->rc, c->proto_version, "d", &ecode);
err = -ecode;
@@ -527,7 +503,6 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
P9_DPRINTK(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode);
}
-
return err;
out_err:
@@ -536,6 +511,115 @@ out_err:
return err;
}
+/**
+ * p9_check_zc_errors - check 9p packet for error return and process it
+ * @c: current client instance
+ * @req: request to parse and check for error conditions
+ * @in_hdrlen: Size of response protocol buffer.
+ *
+ * returns error code if one is discovered, otherwise returns 0
+ *
+ * this will have to be more complicated if we have multiple
+ * error packet types
+ */
+
+static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req,
+ char *uidata, int in_hdrlen, int kern_buf)
+{
+ int err;
+ int ecode;
+ int8_t type;
+ char *ename = NULL;
+
+ err = p9_parse_header(req->rc, NULL, &type, NULL, 0);
+ /*
+ * dump the response from server
+ * This should be after parse_header which poplulate pdu_fcall.
+ */
+ trace_9p_protocol_dump(c, req->rc);
+ if (err) {
+ P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse header %d\n", err);
+ return err;
+ }
+
+ if (type != P9_RERROR && type != P9_RLERROR)
+ return 0;
+
+ if (!p9_is_proto_dotl(c)) {
+ /* Error is reported in string format */
+ uint16_t len;
+ /* 7 = header size for RERROR, 2 is the size of string len; */
+ int inline_len = in_hdrlen - (7 + 2);
+
+ /* Read the size of error string */
+ err = p9pdu_readf(req->rc, c->proto_version, "w", &len);
+ if (err)
+ goto out_err;
+
+ ename = kmalloc(len + 1, GFP_NOFS);
+ if (!ename) {
+ err = -ENOMEM;
+ goto out_err;
+ }
+ if (len <= inline_len) {
+ /* We have error in protocol buffer itself */
+ if (pdu_read(req->rc, ename, len)) {
+ err = -EFAULT;
+ goto out_free;
+
+ }
+ } else {
+ /*
+ * Part of the data is in user space buffer.
+ */
+ if (pdu_read(req->rc, ename, inline_len)) {
+ err = -EFAULT;
+ goto out_free;
+
+ }
+ if (kern_buf) {
+ memcpy(ename + inline_len, uidata,
+ len - inline_len);
+ } else {
+ err = copy_from_user(ename + inline_len,
+ uidata, len - inline_len);
+ if (err) {
+ err = -EFAULT;
+ goto out_free;
+ }
+ }
+ }
+ ename[len] = 0;
+ if (p9_is_proto_dotu(c)) {
+ /* For dotu we also have error code */
+ err = p9pdu_readf(req->rc,
+ c->proto_version, "d", &ecode);
+ if (err)
+ goto out_free;
+ err = -ecode;
+ }
+ if (!err || !IS_ERR_VALUE(err)) {
+ err = p9_errstr2errno(ename, strlen(ename));
+
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n",
+ -ecode, ename);
+ }
+ kfree(ename);
+ } else {
+ err = p9pdu_readf(req->rc, c->proto_version, "d", &ecode);
+ err = -ecode;
+
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode);
+ }
+ return err;
+
+out_free:
+ kfree(ename);
+out_err:
+ P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", err);
+ return err;
+}
+
static struct p9_req_t *
p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...);
@@ -579,23 +663,12 @@ static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq)
return 0;
}
-/**
- * p9_client_rpc - issue a request and wait for a response
- * @c: client session
- * @type: type of request
- * @fmt: protocol format string (see protocol.c)
- *
- * Returns request structure (which client must free using p9_free_req)
- */
-
-static struct p9_req_t *
-p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
+static struct p9_req_t *p9_client_prepare_req(struct p9_client *c,
+ int8_t type, int req_size,
+ const char *fmt, va_list ap)
{
- va_list ap;
int tag, err;
struct p9_req_t *req;
- unsigned long flags;
- int sigpending;
P9_DPRINTK(P9_DEBUG_MUX, "client %p op %d\n", c, type);
@@ -607,12 +680,6 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
if ((c->status == BeginDisconnect) && (type != P9_TCLUNK))
return ERR_PTR(-EIO);
- if (signal_pending(current)) {
- sigpending = 1;
- clear_thread_flag(TIF_SIGPENDING);
- } else
- sigpending = 0;
-
tag = P9_NOTAG;
if (type != P9_TVERSION) {
tag = p9_idpool_get(c->tagpool);
@@ -620,18 +687,51 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
return ERR_PTR(-ENOMEM);
}
- req = p9_tag_alloc(c, tag);
+ req = p9_tag_alloc(c, tag, req_size);
if (IS_ERR(req))
return req;
/* marshall the data */
p9pdu_prepare(req->tc, tag, type);
- va_start(ap, fmt);
err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap);
- va_end(ap);
if (err)
goto reterr;
- p9pdu_finalize(req->tc);
+ p9pdu_finalize(c, req->tc);
+ trace_9p_client_req(c, type, tag);
+ return req;
+reterr:
+ p9_free_req(c, req);
+ return ERR_PTR(err);
+}
+
+/**
+ * p9_client_rpc - issue a request and wait for a response
+ * @c: client session
+ * @type: type of request
+ * @fmt: protocol format string (see protocol.c)
+ *
+ * Returns request structure (which client must free using p9_free_req)
+ */
+
+static struct p9_req_t *
+p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
+{
+ va_list ap;
+ int sigpending, err;
+ unsigned long flags;
+ struct p9_req_t *req;
+
+ va_start(ap, fmt);
+ req = p9_client_prepare_req(c, type, c->msize, fmt, ap);
+ va_end(ap);
+ if (IS_ERR(req))
+ return req;
+
+ if (signal_pending(current)) {
+ sigpending = 1;
+ clear_thread_flag(TIF_SIGPENDING);
+ } else
+ sigpending = 0;
err = c->trans_mod->request(c, req);
if (err < 0) {
@@ -639,18 +739,14 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
c->status = Disconnected;
goto reterr;
}
-
- P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d\n", req->wq, tag);
+ /* Wait for the response */
err = wait_event_interruptible(*req->wq,
- req->status >= REQ_STATUS_RCVD);
- P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d returned %d\n",
- req->wq, tag, err);
+ req->status >= REQ_STATUS_RCVD);
if (req->status == REQ_STATUS_ERROR) {
P9_DPRINTK(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
err = req->t_err;
}
-
if ((err == -ERESTARTSYS) && (c->status == Connected)) {
P9_DPRINTK(P9_DEBUG_MUX, "flushing\n");
sigpending = 1;
@@ -663,25 +759,102 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
if (req->status == REQ_STATUS_RCVD)
err = 0;
}
-
if (sigpending) {
spin_lock_irqsave(&current->sighand->siglock, flags);
recalc_sigpending();
spin_unlock_irqrestore(&current->sighand->siglock, flags);
}
-
if (err < 0)
goto reterr;
err = p9_check_errors(c, req);
- if (!err) {
- P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d\n", c, type);
+ trace_9p_client_res(c, type, req->rc->tag, err);
+ if (!err)
+ return req;
+reterr:
+ p9_free_req(c, req);
+ return ERR_PTR(err);
+}
+
+/**
+ * p9_client_zc_rpc - issue a request and wait for a response
+ * @c: client session
+ * @type: type of request
+ * @uidata: user bffer that should be ued for zero copy read
+ * @uodata: user buffer that shoud be user for zero copy write
+ * @inlen: read buffer size
+ * @olen: write buffer size
+ * @hdrlen: reader header size, This is the size of response protocol data
+ * @fmt: protocol format string (see protocol.c)
+ *
+ * Returns request structure (which client must free using p9_free_req)
+ */
+static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type,
+ char *uidata, char *uodata,
+ int inlen, int olen, int in_hdrlen,
+ int kern_buf, const char *fmt, ...)
+{
+ va_list ap;
+ int sigpending, err;
+ unsigned long flags;
+ struct p9_req_t *req;
+
+ va_start(ap, fmt);
+ /*
+ * We allocate a inline protocol data of only 4k bytes.
+ * The actual content is passed in zero-copy fashion.
+ */
+ req = p9_client_prepare_req(c, type, P9_ZC_HDR_SZ, fmt, ap);
+ va_end(ap);
+ if (IS_ERR(req))
return req;
+
+ if (signal_pending(current)) {
+ sigpending = 1;
+ clear_thread_flag(TIF_SIGPENDING);
+ } else
+ sigpending = 0;
+
+ /* If we are called with KERNEL_DS force kern_buf */
+ if (segment_eq(get_fs(), KERNEL_DS))
+ kern_buf = 1;
+
+ err = c->trans_mod->zc_request(c, req, uidata, uodata,
+ inlen, olen, in_hdrlen, kern_buf);
+ if (err < 0) {
+ if (err == -EIO)
+ c->status = Disconnected;
+ goto reterr;
+ }
+ if (req->status == REQ_STATUS_ERROR) {
+ P9_DPRINTK(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
+ err = req->t_err;
+ }
+ if ((err == -ERESTARTSYS) && (c->status == Connected)) {
+ P9_DPRINTK(P9_DEBUG_MUX, "flushing\n");
+ sigpending = 1;
+ clear_thread_flag(TIF_SIGPENDING);
+
+ if (c->trans_mod->cancel(c, req))
+ p9_client_flush(c, req);
+
+ /* if we received the response anyway, don't signal error */
+ if (req->status == REQ_STATUS_RCVD)
+ err = 0;
+ }
+ if (sigpending) {
+ spin_lock_irqsave(&current->sighand->siglock, flags);
+ recalc_sigpending();
+ spin_unlock_irqrestore(&current->sighand->siglock, flags);
}
+ if (err < 0)
+ goto reterr;
+ err = p9_check_zc_errors(c, req, uidata, in_hdrlen, kern_buf);
+ trace_9p_client_res(c, type, req->rc->tag, err);
+ if (!err)
+ return req;
reterr:
- P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d error: %d\n", c, type,
- err);
p9_free_req(c, req);
return ERR_PTR(err);
}
@@ -769,7 +942,7 @@ static int p9_client_version(struct p9_client *c)
err = p9pdu_readf(req->rc, c->proto_version, "ds", &msize, &version);
if (err) {
P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err);
- P9_DUMP_PKT(1, req->rc);
+ trace_9p_protocol_dump(c, req->rc);
goto error;
}
@@ -906,15 +1079,14 @@ EXPORT_SYMBOL(p9_client_begin_disconnect);
struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
char *uname, u32 n_uname, char *aname)
{
- int err;
+ int err = 0;
struct p9_req_t *req;
struct p9_fid *fid;
struct p9_qid qid;
- P9_DPRINTK(P9_DEBUG_9P, ">>> TATTACH afid %d uname %s aname %s\n",
- afid ? afid->fid : -1, uname, aname);
- err = 0;
+ P9_DPRINTK(P9_DEBUG_9P, ">>> TATTACH afid %d uname %s aname %s\n",
+ afid ? afid->fid : -1, uname, aname);
fid = p9_fid_create(clnt);
if (IS_ERR(fid)) {
err = PTR_ERR(fid);
@@ -931,7 +1103,7 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid);
if (err) {
- P9_DUMP_PKT(1, req->rc);
+ trace_9p_protocol_dump(clnt, req->rc);
p9_free_req(clnt, req);
goto error;
}
@@ -991,7 +1163,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname,
err = p9pdu_readf(req->rc, clnt->proto_version, "R", &nwqids, &wqids);
if (err) {
- P9_DUMP_PKT(1, req->rc);
+ trace_9p_protocol_dump(clnt, req->rc);
p9_free_req(clnt, req);
goto clunk_fid;
}
@@ -1058,7 +1230,7 @@ int p9_client_open(struct p9_fid *fid, int mode)
err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit);
if (err) {
- P9_DUMP_PKT(1, req->rc);
+ trace_9p_protocol_dump(clnt, req->rc);
goto free_and_error;
}
@@ -1101,7 +1273,7 @@ int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode,
err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", qid, &iounit);
if (err) {
- P9_DUMP_PKT(1, req->rc);
+ trace_9p_protocol_dump(clnt, req->rc);
goto free_and_error;
}
@@ -1146,7 +1318,7 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit);
if (err) {
- P9_DUMP_PKT(1, req->rc);
+ trace_9p_protocol_dump(clnt, req->rc);
goto free_and_error;
}
@@ -1185,7 +1357,7 @@ int p9_client_symlink(struct p9_fid *dfid, char *name, char *symtgt, gid_t gid,
err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid);
if (err) {
- P9_DUMP_PKT(1, req->rc);
+ trace_9p_protocol_dump(clnt, req->rc);
goto free_and_error;
}
@@ -1330,13 +1502,15 @@ int
p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
u32 count)
{
- int err, rsize;
- struct p9_client *clnt;
- struct p9_req_t *req;
char *dataptr;
+ int kernel_buf = 0;
+ struct p9_req_t *req;
+ struct p9_client *clnt;
+ int err, rsize, non_zc = 0;
+
- P9_DPRINTK(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", fid->fid,
- (long long unsigned) offset, count);
+ P9_DPRINTK(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n",
+ fid->fid, (long long unsigned) offset, count);
err = 0;
clnt = fid->clnt;
@@ -1348,13 +1522,24 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
rsize = count;
/* Don't bother zerocopy for small IO (< 1024) */
- if (((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) ==
- P9_TRANS_PREF_PAYLOAD_SEP) && (rsize > 1024)) {
- req = p9_client_rpc(clnt, P9_TREAD, "dqE", fid->fid, offset,
- rsize, data, udata);
+ if (clnt->trans_mod->zc_request && rsize > 1024) {
+ char *indata;
+ if (data) {
+ kernel_buf = 1;
+ indata = data;
+ } else
+ indata = (char *)udata;
+ /*
+ * response header len is 11
+ * PDU Header(7) + IO Size (4)
+ */
+ req = p9_client_zc_rpc(clnt, P9_TREAD, indata, NULL, rsize, 0,
+ 11, kernel_buf, "dqd", fid->fid,
+ offset, rsize);
} else {
+ non_zc = 1;
req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset,
- rsize);
+ rsize);
}
if (IS_ERR(req)) {
err = PTR_ERR(req);
@@ -1363,14 +1548,13 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr);
if (err) {
- P9_DUMP_PKT(1, req->rc);
+ trace_9p_protocol_dump(clnt, req->rc);
goto free_and_error;
}
P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count);
- P9_DUMP_PKT(1, req->rc);
- if (!req->tc->pbuf_size) {
+ if (non_zc) {
if (data) {
memmove(data, dataptr, count);
} else {
@@ -1396,6 +1580,7 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
u64 offset, u32 count)
{
int err, rsize;
+ int kernel_buf = 0;
struct p9_client *clnt;
struct p9_req_t *req;
@@ -1411,19 +1596,24 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
if (count < rsize)
rsize = count;
- /* Don't bother zerocopy form small IO (< 1024) */
- if (((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) ==
- P9_TRANS_PREF_PAYLOAD_SEP) && (rsize > 1024)) {
- req = p9_client_rpc(clnt, P9_TWRITE, "dqE", fid->fid, offset,
- rsize, data, udata);
+ /* Don't bother zerocopy for small IO (< 1024) */
+ if (clnt->trans_mod->zc_request && rsize > 1024) {
+ char *odata;
+ if (data) {
+ kernel_buf = 1;
+ odata = data;
+ } else
+ odata = (char *)udata;
+ req = p9_client_zc_rpc(clnt, P9_TWRITE, NULL, odata, 0, rsize,
+ P9_ZC_HDR_SZ, kernel_buf, "dqd",
+ fid->fid, offset, rsize);
} else {
-
if (data)
req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid,
- offset, rsize, data);
+ offset, rsize, data);
else
req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid,
- offset, rsize, udata);
+ offset, rsize, udata);
}
if (IS_ERR(req)) {
err = PTR_ERR(req);
@@ -1432,7 +1622,7 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count);
if (err) {
- P9_DUMP_PKT(1, req->rc);
+ trace_9p_protocol_dump(clnt, req->rc);
goto free_and_error;
}
@@ -1472,7 +1662,7 @@ struct p9_wstat *p9_client_stat(struct p9_fid *fid)
err = p9pdu_readf(req->rc, clnt->proto_version, "wS", &ignored, ret);
if (err) {
- P9_DUMP_PKT(1, req->rc);
+ trace_9p_protocol_dump(clnt, req->rc);
p9_free_req(clnt, req);
goto error;
}
@@ -1523,7 +1713,7 @@ struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid,
err = p9pdu_readf(req->rc, clnt->proto_version, "A", ret);
if (err) {
- P9_DUMP_PKT(1, req->rc);
+ trace_9p_protocol_dump(clnt, req->rc);
p9_free_req(clnt, req);
goto error;
}
@@ -1671,7 +1861,7 @@ int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb)
&sb->bsize, &sb->blocks, &sb->bfree, &sb->bavail,
&sb->files, &sb->ffree, &sb->fsid, &sb->namelen);
if (err) {
- P9_DUMP_PKT(1, req->rc);
+ trace_9p_protocol_dump(clnt, req->rc);
p9_free_req(clnt, req);
goto error;
}
@@ -1778,7 +1968,7 @@ struct p9_fid *p9_client_xattrwalk(struct p9_fid *file_fid,
}
err = p9pdu_readf(req->rc, clnt->proto_version, "q", attr_size);
if (err) {
- P9_DUMP_PKT(1, req->rc);
+ trace_9p_protocol_dump(clnt, req->rc);
p9_free_req(clnt, req);
goto clunk_fid;
}
@@ -1824,7 +2014,7 @@ EXPORT_SYMBOL_GPL(p9_client_xattrcreate);
int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
{
- int err, rsize;
+ int err, rsize, non_zc = 0;
struct p9_client *clnt;
struct p9_req_t *req;
char *dataptr;
@@ -1842,13 +2032,18 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
if (count < rsize)
rsize = count;
- if ((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) ==
- P9_TRANS_PREF_PAYLOAD_SEP) {
- req = p9_client_rpc(clnt, P9_TREADDIR, "dqF", fid->fid,
- offset, rsize, data);
+ /* Don't bother zerocopy for small IO (< 1024) */
+ if (clnt->trans_mod->zc_request && rsize > 1024) {
+ /*
+ * response header len is 11
+ * PDU Header(7) + IO Size (4)
+ */
+ req = p9_client_zc_rpc(clnt, P9_TREADDIR, data, NULL, rsize, 0,
+ 11, 1, "dqd", fid->fid, offset, rsize);
} else {
+ non_zc = 1;
req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid,
- offset, rsize);
+ offset, rsize);
}
if (IS_ERR(req)) {
err = PTR_ERR(req);
@@ -1857,13 +2052,13 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr);
if (err) {
- P9_DUMP_PKT(1, req->rc);
+ trace_9p_protocol_dump(clnt, req->rc);
goto free_and_error;
}
P9_DPRINTK(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count);
- if (!req->tc->pbuf_size && data)
+ if (non_zc)
memmove(data, dataptr, count);
p9_free_req(clnt, req);
@@ -1894,7 +2089,7 @@ int p9_client_mknod_dotl(struct p9_fid *fid, char *name, int mode,
err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid);
if (err) {
- P9_DUMP_PKT(1, req->rc);
+ trace_9p_protocol_dump(clnt, req->rc);
goto error;
}
P9_DPRINTK(P9_DEBUG_9P, "<<< RMKNOD qid %x.%llx.%x\n", qid->type,
@@ -1925,7 +2120,7 @@ int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode,
err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid);
if (err) {
- P9_DUMP_PKT(1, req->rc);
+ trace_9p_protocol_dump(clnt, req->rc);
goto error;
}
P9_DPRINTK(P9_DEBUG_9P, "<<< RMKDIR qid %x.%llx.%x\n", qid->type,
@@ -1960,7 +2155,7 @@ int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status)
err = p9pdu_readf(req->rc, clnt->proto_version, "b", status);
if (err) {
- P9_DUMP_PKT(1, req->rc);
+ trace_9p_protocol_dump(clnt, req->rc);
goto error;
}
P9_DPRINTK(P9_DEBUG_9P, "<<< RLOCK status %i\n", *status);
@@ -1993,7 +2188,7 @@ int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *glock)
&glock->start, &glock->length, &glock->proc_id,
&glock->client_id);
if (err) {
- P9_DUMP_PKT(1, req->rc);
+ trace_9p_protocol_dump(clnt, req->rc);
goto error;
}
P9_DPRINTK(P9_DEBUG_9P, "<<< RGETLOCK type %i start %lld length %lld "
@@ -2021,7 +2216,7 @@ int p9_client_readlink(struct p9_fid *fid, char **target)
err = p9pdu_readf(req->rc, clnt->proto_version, "s", target);
if (err) {
- P9_DUMP_PKT(1, req->rc);
+ trace_9p_protocol_dump(clnt, req->rc);
goto error;
}
P9_DPRINTK(P9_DEBUG_9P, "<<< RREADLINK target %s\n", *target);
diff --git a/net/9p/protocol.c b/net/9p/protocol.c
index df58375ea6b3..55e10a96c902 100644
--- a/net/9p/protocol.c
+++ b/net/9p/protocol.c
@@ -37,40 +37,11 @@
#include <net/9p/client.h>
#include "protocol.h"
+#include <trace/events/9p.h>
+
static int
p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
-#ifdef CONFIG_NET_9P_DEBUG
-void
-p9pdu_dump(int way, struct p9_fcall *pdu)
-{
- int len = pdu->size;
-
- if ((p9_debug_level & P9_DEBUG_VPKT) != P9_DEBUG_VPKT) {
- if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT) {
- if (len > 32)
- len = 32;
- } else {
- /* shouldn't happen */
- return;
- }
- }
-
- if (way)
- print_hex_dump_bytes("[9P] ", DUMP_PREFIX_OFFSET, pdu->sdata,
- len);
- else
- print_hex_dump_bytes("]9P[ ", DUMP_PREFIX_OFFSET, pdu->sdata,
- len);
-}
-#else
-void
-p9pdu_dump(int way, struct p9_fcall *pdu)
-{
-}
-#endif
-EXPORT_SYMBOL(p9pdu_dump);
-
void p9stat_free(struct p9_wstat *stbuf)
{
kfree(stbuf->name);
@@ -81,7 +52,7 @@ void p9stat_free(struct p9_wstat *stbuf)
}
EXPORT_SYMBOL(p9stat_free);
-static size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
+size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
{
size_t len = min(pdu->size - pdu->offset, size);
memcpy(data, &pdu->sdata[pdu->offset], len);
@@ -108,26 +79,6 @@ pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
return size - len;
}
-static size_t
-pdu_write_urw(struct p9_fcall *pdu, const char *kdata, const char __user *udata,
- size_t size)
-{
- BUG_ON(pdu->size > P9_IOHDRSZ);
- pdu->pubuf = (char __user *)udata;
- pdu->pkbuf = (char *)kdata;
- pdu->pbuf_size = size;
- return 0;
-}
-
-static size_t
-pdu_write_readdir(struct p9_fcall *pdu, const char *kdata, size_t size)
-{
- BUG_ON(pdu->size > P9_READDIRHDRSZ);
- pdu->pkbuf = (char *)kdata;
- pdu->pbuf_size = size;
- return 0;
-}
-
/*
b - int8_t
w - int16_t
@@ -459,26 +410,6 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
errcode = -EFAULT;
}
break;
- case 'E':{
- int32_t cnt = va_arg(ap, int32_t);
- const char *k = va_arg(ap, const void *);
- const char __user *u = va_arg(ap,
- const void __user *);
- errcode = p9pdu_writef(pdu, proto_version, "d",
- cnt);
- if (!errcode && pdu_write_urw(pdu, k, u, cnt))
- errcode = -EFAULT;
- }
- break;
- case 'F':{
- int32_t cnt = va_arg(ap, int32_t);
- const char *k = va_arg(ap, const void *);
- errcode = p9pdu_writef(pdu, proto_version, "d",
- cnt);
- if (!errcode && pdu_write_readdir(pdu, k, cnt))
- errcode = -EFAULT;
- }
- break;
case 'U':{
int32_t count = va_arg(ap, int32_t);
const char __user *udata =
@@ -591,7 +522,7 @@ p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
return ret;
}
-int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version)
+int p9stat_read(struct p9_client *clnt, char *buf, int len, struct p9_wstat *st)
{
struct p9_fcall fake_pdu;
int ret;
@@ -601,10 +532,10 @@ int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version)
fake_pdu.sdata = buf;
fake_pdu.offset = 0;
- ret = p9pdu_readf(&fake_pdu, proto_version, "S", st);
+ ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "S", st);
if (ret) {
P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
- P9_DUMP_PKT(0, &fake_pdu);
+ trace_9p_protocol_dump(clnt, &fake_pdu);
}
return ret;
@@ -617,7 +548,7 @@ int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
}
-int p9pdu_finalize(struct p9_fcall *pdu)
+int p9pdu_finalize(struct p9_client *clnt, struct p9_fcall *pdu)
{
int size = pdu->size;
int err;
@@ -626,7 +557,7 @@ int p9pdu_finalize(struct p9_fcall *pdu)
err = p9pdu_writef(pdu, 0, "d", size);
pdu->size = size;
- P9_DUMP_PKT(0, pdu);
+ trace_9p_protocol_dump(clnt, pdu);
P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size,
pdu->id, pdu->tag);
@@ -637,14 +568,10 @@ void p9pdu_reset(struct p9_fcall *pdu)
{
pdu->offset = 0;
pdu->size = 0;
- pdu->private = NULL;
- pdu->pubuf = NULL;
- pdu->pkbuf = NULL;
- pdu->pbuf_size = 0;
}
-int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,
- int proto_version)
+int p9dirent_read(struct p9_client *clnt, char *buf, int len,
+ struct p9_dirent *dirent)
{
struct p9_fcall fake_pdu;
int ret;
@@ -655,11 +582,11 @@ int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,
fake_pdu.sdata = buf;
fake_pdu.offset = 0;
- ret = p9pdu_readf(&fake_pdu, proto_version, "Qqbs", &dirent->qid,
- &dirent->d_off, &dirent->d_type, &nameptr);
+ ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "Qqbs", &dirent->qid,
+ &dirent->d_off, &dirent->d_type, &nameptr);
if (ret) {
P9_DPRINTK(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
- P9_DUMP_PKT(1, &fake_pdu);
+ trace_9p_protocol_dump(clnt, &fake_pdu);
goto out;
}
diff --git a/net/9p/protocol.h b/net/9p/protocol.h
index 2431c0f38d56..2cc525fa49fa 100644
--- a/net/9p/protocol.h
+++ b/net/9p/protocol.h
@@ -29,6 +29,6 @@ int p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
va_list ap);
int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type);
-int p9pdu_finalize(struct p9_fcall *pdu);
-void p9pdu_dump(int, struct p9_fcall *);
+int p9pdu_finalize(struct p9_client *clnt, struct p9_fcall *pdu);
void p9pdu_reset(struct p9_fcall *pdu);
+size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size);
diff --git a/net/9p/trans_common.c b/net/9p/trans_common.c
index 9a70ebdec56e..de8df957867d 100644
--- a/net/9p/trans_common.c
+++ b/net/9p/trans_common.c
@@ -21,30 +21,25 @@
/**
* p9_release_req_pages - Release pages after the transaction.
- * @*private: PDU's private page of struct trans_rpage_info
*/
-void
-p9_release_req_pages(struct trans_rpage_info *rpinfo)
+void p9_release_pages(struct page **pages, int nr_pages)
{
int i = 0;
-
- while (rpinfo->rp_data[i] && rpinfo->rp_nr_pages--) {
- put_page(rpinfo->rp_data[i]);
+ while (pages[i] && nr_pages--) {
+ put_page(pages[i]);
i++;
}
}
-EXPORT_SYMBOL(p9_release_req_pages);
+EXPORT_SYMBOL(p9_release_pages);
/**
* p9_nr_pages - Return number of pages needed to accommodate the payload.
*/
-int
-p9_nr_pages(struct p9_req_t *req)
+int p9_nr_pages(char *data, int len)
{
unsigned long start_page, end_page;
- start_page = (unsigned long)req->tc->pubuf >> PAGE_SHIFT;
- end_page = ((unsigned long)req->tc->pubuf + req->tc->pbuf_size +
- PAGE_SIZE - 1) >> PAGE_SHIFT;
+ start_page = (unsigned long)data >> PAGE_SHIFT;
+ end_page = ((unsigned long)data + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
return end_page - start_page;
}
EXPORT_SYMBOL(p9_nr_pages);
@@ -58,35 +53,17 @@ EXPORT_SYMBOL(p9_nr_pages);
* @nr_pages: number of pages to accommodate the payload
* @rw: Indicates if the pages are for read or write.
*/
-int
-p9_payload_gup(struct p9_req_t *req, size_t *pdata_off, int *pdata_len,
- int nr_pages, u8 rw)
-{
- uint32_t first_page_bytes = 0;
- int32_t pdata_mapped_pages;
- struct trans_rpage_info *rpinfo;
-
- *pdata_off = (__force size_t)req->tc->pubuf & (PAGE_SIZE-1);
- if (*pdata_off)
- first_page_bytes = min(((size_t)PAGE_SIZE - *pdata_off),
- req->tc->pbuf_size);
+int p9_payload_gup(char *data, int *nr_pages, struct page **pages, int write)
+{
+ int nr_mapped_pages;
- rpinfo = req->tc->private;
- pdata_mapped_pages = get_user_pages_fast((unsigned long)req->tc->pubuf,
- nr_pages, rw, &rpinfo->rp_data[0]);
- if (pdata_mapped_pages <= 0)
- return pdata_mapped_pages;
+ nr_mapped_pages = get_user_pages_fast((unsigned long)data,
+ *nr_pages, write, pages);
+ if (nr_mapped_pages <= 0)
+ return nr_mapped_pages;
- rpinfo->rp_nr_pages = pdata_mapped_pages;
- if (*pdata_off) {
- *pdata_len = first_page_bytes;
- *pdata_len += min((req->tc->pbuf_size - *pdata_len),
- ((size_t)pdata_mapped_pages - 1) << PAGE_SHIFT);
- } else {
- *pdata_len = min(req->tc->pbuf_size,
- (size_t)pdata_mapped_pages << PAGE_SHIFT);
- }
+ *nr_pages = nr_mapped_pages;
return 0;
}
EXPORT_SYMBOL(p9_payload_gup);
diff --git a/net/9p/trans_common.h b/net/9p/trans_common.h
index 76309223bb02..173bb550a9eb 100644
--- a/net/9p/trans_common.h
+++ b/net/9p/trans_common.h
@@ -12,21 +12,6 @@
*
*/
-/* TRUE if it is user context */
-#define P9_IS_USER_CONTEXT (!segment_eq(get_fs(), KERNEL_DS))
-
-/**
- * struct trans_rpage_info - To store mapped page information in PDU.
- * @rp_alloc:Set if this structure is allocd, not a reuse unused space in pdu.
- * @rp_nr_pages: Number of mapped pages
- * @rp_data: Array of page pointers
- */
-struct trans_rpage_info {
- u8 rp_alloc;
- int rp_nr_pages;
- struct page *rp_data[0];
-};
-
-void p9_release_req_pages(struct trans_rpage_info *);
-int p9_payload_gup(struct p9_req_t *, size_t *, int *, int, u8);
-int p9_nr_pages(struct p9_req_t *);
+void p9_release_pages(struct page **, int);
+int p9_payload_gup(char *, int *, struct page **, int);
+int p9_nr_pages(char *, int);
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index 175b5135bdcf..32aa9834229c 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -150,12 +150,10 @@ static void req_done(struct virtqueue *vq)
while (1) {
spin_lock_irqsave(&chan->lock, flags);
rc = virtqueue_get_buf(chan->vq, &len);
-
if (rc == NULL) {
spin_unlock_irqrestore(&chan->lock, flags);
break;
}
-
chan->ring_bufs_avail = 1;
spin_unlock_irqrestore(&chan->lock, flags);
/* Wakeup if anyone waiting for VirtIO ring space. */
@@ -163,17 +161,6 @@ static void req_done(struct virtqueue *vq)
P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc);
P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag);
req = p9_tag_lookup(chan->client, rc->tag);
- if (req->tc->private) {
- struct trans_rpage_info *rp = req->tc->private;
- int p = rp->rp_nr_pages;
- /*Release pages */
- p9_release_req_pages(rp);
- atomic_sub(p, &vp_pinned);
- wake_up(&vp_wq);
- if (rp->rp_alloc)
- kfree(rp);
- req->tc->private = NULL;
- }
req->status = REQ_STATUS_RCVD;
p9_client_cb(chan->client, req);
}
@@ -193,9 +180,8 @@ static void req_done(struct virtqueue *vq)
*
*/
-static int
-pack_sg_list(struct scatterlist *sg, int start, int limit, char *data,
- int count)
+static int pack_sg_list(struct scatterlist *sg, int start,
+ int limit, char *data, int count)
{
int s;
int index = start;
@@ -224,31 +210,36 @@ static int p9_virtio_cancel(struct p9_client *client, struct p9_req_t *req)
* this takes a list of pages.
* @sg: scatter/gather list to pack into
* @start: which segment of the sg_list to start at
- * @pdata_off: Offset into the first page
* @**pdata: a list of pages to add into sg.
+ * @nr_pages: number of pages to pack into the scatter/gather list
+ * @data: data to pack into scatter/gather list
* @count: amount of data to pack into the scatter/gather list
*/
static int
-pack_sg_list_p(struct scatterlist *sg, int start, int limit, size_t pdata_off,
- struct page **pdata, int count)
+pack_sg_list_p(struct scatterlist *sg, int start, int limit,
+ struct page **pdata, int nr_pages, char *data, int count)
{
- int s;
- int i = 0;
+ int i = 0, s;
+ int data_off;
int index = start;
- if (pdata_off) {
- s = min((int)(PAGE_SIZE - pdata_off), count);
- sg_set_page(&sg[index++], pdata[i++], s, pdata_off);
- count -= s;
- }
-
- while (count) {
- BUG_ON(index > limit);
- s = min((int)PAGE_SIZE, count);
- sg_set_page(&sg[index++], pdata[i++], s, 0);
+ BUG_ON(nr_pages > (limit - start));
+ /*
+ * if the first page doesn't start at
+ * page boundary find the offset
+ */
+ data_off = offset_in_page(data);
+ while (nr_pages) {
+ s = rest_of_page(data);
+ if (s > count)
+ s = count;
+ sg_set_page(&sg[index++], pdata[i++], s, data_off);
+ data_off = 0;
+ data += s;
count -= s;
+ nr_pages--;
}
- return index-start;
+ return index - start;
}
/**
@@ -261,114 +252,166 @@ pack_sg_list_p(struct scatterlist *sg, int start, int limit, size_t pdata_off,
static int
p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
{
- int in, out, inp, outp;
- struct virtio_chan *chan = client->trans;
- char *rdata = (char *)req->rc+sizeof(struct p9_fcall);
+ int err;
+ int in, out;
unsigned long flags;
- size_t pdata_off = 0;
- struct trans_rpage_info *rpinfo = NULL;
- int err, pdata_len = 0;
+ struct virtio_chan *chan = client->trans;
P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n");
req->status = REQ_STATUS_SENT;
+req_retry:
+ spin_lock_irqsave(&chan->lock, flags);
- if (req->tc->pbuf_size && (req->tc->pubuf && P9_IS_USER_CONTEXT)) {
- int nr_pages = p9_nr_pages(req);
- int rpinfo_size = sizeof(struct trans_rpage_info) +
- sizeof(struct page *) * nr_pages;
+ /* Handle out VirtIO ring buffers */
+ out = pack_sg_list(chan->sg, 0,
+ VIRTQUEUE_NUM, req->tc->sdata, req->tc->size);
- if (atomic_read(&vp_pinned) >= chan->p9_max_pages) {
- err = wait_event_interruptible(vp_wq,
- atomic_read(&vp_pinned) < chan->p9_max_pages);
+ in = pack_sg_list(chan->sg, out,
+ VIRTQUEUE_NUM, req->rc->sdata, req->rc->capacity);
+
+ err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc);
+ if (err < 0) {
+ if (err == -ENOSPC) {
+ chan->ring_bufs_avail = 0;
+ spin_unlock_irqrestore(&chan->lock, flags);
+ err = wait_event_interruptible(*chan->vc_wq,
+ chan->ring_bufs_avail);
if (err == -ERESTARTSYS)
return err;
- P9_DPRINTK(P9_DEBUG_TRANS, "9p: May gup pages now.\n");
- }
- if (rpinfo_size <= (req->tc->capacity - req->tc->size)) {
- /* We can use sdata */
- req->tc->private = req->tc->sdata + req->tc->size;
- rpinfo = (struct trans_rpage_info *)req->tc->private;
- rpinfo->rp_alloc = 0;
+ P9_DPRINTK(P9_DEBUG_TRANS, "9p:Retry virtio request\n");
+ goto req_retry;
} else {
- req->tc->private = kmalloc(rpinfo_size, GFP_NOFS);
- if (!req->tc->private) {
- P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: "
- "private kmalloc returned NULL");
- return -ENOMEM;
- }
- rpinfo = (struct trans_rpage_info *)req->tc->private;
- rpinfo->rp_alloc = 1;
+ spin_unlock_irqrestore(&chan->lock, flags);
+ P9_DPRINTK(P9_DEBUG_TRANS,
+ "9p debug: "
+ "virtio rpc add_buf returned failure");
+ return -EIO;
}
+ }
+ virtqueue_kick(chan->vq);
+ spin_unlock_irqrestore(&chan->lock, flags);
- err = p9_payload_gup(req, &pdata_off, &pdata_len, nr_pages,
- req->tc->id == P9_TREAD ? 1 : 0);
- if (err < 0) {
- if (rpinfo->rp_alloc)
- kfree(rpinfo);
+ P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n");
+ return 0;
+}
+
+static int p9_get_mapped_pages(struct virtio_chan *chan,
+ struct page **pages, char *data,
+ int nr_pages, int write, int kern_buf)
+{
+ int err;
+ if (!kern_buf) {
+ /*
+ * We allow only p9_max_pages pinned. We wait for the
+ * Other zc request to finish here
+ */
+ if (atomic_read(&vp_pinned) >= chan->p9_max_pages) {
+ err = wait_event_interruptible(vp_wq,
+ (atomic_read(&vp_pinned) < chan->p9_max_pages));
+ if (err == -ERESTARTSYS)
+ return err;
+ }
+ err = p9_payload_gup(data, &nr_pages, pages, write);
+ if (err < 0)
return err;
- } else {
- atomic_add(rpinfo->rp_nr_pages, &vp_pinned);
+ atomic_add(nr_pages, &vp_pinned);
+ } else {
+ /* kernel buffer, no need to pin pages */
+ int s, index = 0;
+ int count = nr_pages;
+ while (nr_pages) {
+ s = rest_of_page(data);
+ pages[index++] = virt_to_page(data);
+ data += s;
+ nr_pages--;
}
+ nr_pages = count;
}
+ return nr_pages;
+}
-req_retry_pinned:
- spin_lock_irqsave(&chan->lock, flags);
+/**
+ * p9_virtio_zc_request - issue a zero copy request
+ * @client: client instance issuing the request
+ * @req: request to be issued
+ * @uidata: user bffer that should be ued for zero copy read
+ * @uodata: user buffer that shoud be user for zero copy write
+ * @inlen: read buffer size
+ * @olen: write buffer size
+ * @hdrlen: reader header size, This is the size of response protocol data
+ *
+ */
+static int
+p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
+ char *uidata, char *uodata, int inlen,
+ int outlen, int in_hdr_len, int kern_buf)
+{
+ int in, out, err;
+ unsigned long flags;
+ int in_nr_pages = 0, out_nr_pages = 0;
+ struct page **in_pages = NULL, **out_pages = NULL;
+ struct virtio_chan *chan = client->trans;
- /* Handle out VirtIO ring buffers */
- out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, req->tc->sdata,
- req->tc->size);
-
- if (req->tc->pbuf_size && (req->tc->id == P9_TWRITE)) {
- /* We have additional write payload buffer to take care */
- if (req->tc->pubuf && P9_IS_USER_CONTEXT) {
- outp = pack_sg_list_p(chan->sg, out, VIRTQUEUE_NUM,
- pdata_off, rpinfo->rp_data, pdata_len);
- } else {
- char *pbuf;
- if (req->tc->pubuf)
- pbuf = (__force char *) req->tc->pubuf;
- else
- pbuf = req->tc->pkbuf;
- outp = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, pbuf,
- req->tc->pbuf_size);
+ P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n");
+
+ if (uodata) {
+ out_nr_pages = p9_nr_pages(uodata, outlen);
+ out_pages = kmalloc(sizeof(struct page *) * out_nr_pages,
+ GFP_NOFS);
+ if (!out_pages) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+ out_nr_pages = p9_get_mapped_pages(chan, out_pages, uodata,
+ out_nr_pages, 0, kern_buf);
+ if (out_nr_pages < 0) {
+ err = out_nr_pages;
+ kfree(out_pages);
+ out_pages = NULL;
+ goto err_out;
}
- out += outp;
}
-
- /* Handle in VirtIO ring buffers */
- if (req->tc->pbuf_size &&
- ((req->tc->id == P9_TREAD) || (req->tc->id == P9_TREADDIR))) {
- /*
- * Take care of additional Read payload.
- * 11 is the read/write header = PDU Header(7) + IO Size (4).
- * Arrange in such a way that server places header in the
- * alloced memory and payload onto the user buffer.
- */
- inp = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, rdata, 11);
- /*
- * Running executables in the filesystem may result in
- * a read request with kernel buffer as opposed to user buffer.
- */
- if (req->tc->pubuf && P9_IS_USER_CONTEXT) {
- in = pack_sg_list_p(chan->sg, out+inp, VIRTQUEUE_NUM,
- pdata_off, rpinfo->rp_data, pdata_len);
- } else {
- char *pbuf;
- if (req->tc->pubuf)
- pbuf = (__force char *) req->tc->pubuf;
- else
- pbuf = req->tc->pkbuf;
-
- in = pack_sg_list(chan->sg, out+inp, VIRTQUEUE_NUM,
- pbuf, req->tc->pbuf_size);
+ if (uidata) {
+ in_nr_pages = p9_nr_pages(uidata, inlen);
+ in_pages = kmalloc(sizeof(struct page *) * in_nr_pages,
+ GFP_NOFS);
+ if (!in_pages) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+ in_nr_pages = p9_get_mapped_pages(chan, in_pages, uidata,
+ in_nr_pages, 1, kern_buf);
+ if (in_nr_pages < 0) {
+ err = in_nr_pages;
+ kfree(in_pages);
+ in_pages = NULL;
+ goto err_out;
}
- in += inp;
- } else {
- in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, rdata,
- req->rc->capacity);
}
+ req->status = REQ_STATUS_SENT;
+req_retry_pinned:
+ spin_lock_irqsave(&chan->lock, flags);
+ /* out data */
+ out = pack_sg_list(chan->sg, 0,
+ VIRTQUEUE_NUM, req->tc->sdata, req->tc->size);
+
+ if (out_pages)
+ out += pack_sg_list_p(chan->sg, out, VIRTQUEUE_NUM,
+ out_pages, out_nr_pages, uodata, outlen);
+ /*
+ * Take care of in data
+ * For example TREAD have 11.
+ * 11 is the read/write header = PDU Header(7) + IO Size (4).
+ * Arrange in such a way that server places header in the
+ * alloced memory and payload onto the user buffer.
+ */
+ in = pack_sg_list(chan->sg, out,
+ VIRTQUEUE_NUM, req->rc->sdata, in_hdr_len);
+ if (in_pages)
+ in += pack_sg_list_p(chan->sg, out + in, VIRTQUEUE_NUM,
+ in_pages, in_nr_pages, uidata, inlen);
err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc);
if (err < 0) {
@@ -376,28 +419,45 @@ req_retry_pinned:
chan->ring_bufs_avail = 0;
spin_unlock_irqrestore(&chan->lock, flags);
err = wait_event_interruptible(*chan->vc_wq,
- chan->ring_bufs_avail);
+ chan->ring_bufs_avail);
if (err == -ERESTARTSYS)
- return err;
+ goto err_out;
P9_DPRINTK(P9_DEBUG_TRANS, "9p:Retry virtio request\n");
goto req_retry_pinned;
} else {
spin_unlock_irqrestore(&chan->lock, flags);
P9_DPRINTK(P9_DEBUG_TRANS,
- "9p debug: "
- "virtio rpc add_buf returned failure");
- if (rpinfo && rpinfo->rp_alloc)
- kfree(rpinfo);
- return -EIO;
+ "9p debug: "
+ "virtio rpc add_buf returned failure");
+ err = -EIO;
+ goto err_out;
}
}
-
virtqueue_kick(chan->vq);
spin_unlock_irqrestore(&chan->lock, flags);
-
P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n");
- return 0;
+ err = wait_event_interruptible(*req->wq,
+ req->status >= REQ_STATUS_RCVD);
+ /*
+ * Non kernel buffers are pinned, unpin them
+ */
+err_out:
+ if (!kern_buf) {
+ if (in_pages) {
+ p9_release_pages(in_pages, in_nr_pages);
+ atomic_sub(in_nr_pages, &vp_pinned);
+ }
+ if (out_pages) {
+ p9_release_pages(out_pages, out_nr_pages);
+ atomic_sub(out_nr_pages, &vp_pinned);
+ }
+ /* wakeup anybody waiting for slots to pin pages */
+ wake_up(&vp_wq);
+ }
+ kfree(in_pages);
+ kfree(out_pages);
+ return err;
}
static ssize_t p9_mount_tag_show(struct device *dev,
@@ -591,9 +651,15 @@ static struct p9_trans_module p9_virtio_trans = {
.create = p9_virtio_create,
.close = p9_virtio_close,
.request = p9_virtio_request,
+ .zc_request = p9_virtio_zc_request,
.cancel = p9_virtio_cancel,
- .maxsize = PAGE_SIZE*VIRTQUEUE_NUM,
- .pref = P9_TRANS_PREF_PAYLOAD_SEP,
+ /*
+ * We leave one entry for input and one entry for response
+ * headers. We also skip one more entry to accomodate, address
+ * that are not at page boundary, that can result in an extra
+ * page in zero copy.
+ */
+ .maxsize = PAGE_SIZE * (VIRTQUEUE_NUM - 3),
.def = 0,
.owner = THIS_MODULE,
};
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index b1fe7c35e8d1..bfa9ab93eda5 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -951,13 +951,12 @@ static unsigned long atalk_sum_skb(const struct sk_buff *skb, int offset,
/* checksum stuff in frags */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
int end;
-
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
WARN_ON(start > offset + len);
- end = start + skb_shinfo(skb)->frags[i].size;
+ end = start + skb_frag_size(frag);
if ((copy = end - offset) > 0) {
u8 *vaddr;
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
if (copy > len)
copy = len;
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index 52cfd0c3ea71..d07223c834af 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -558,12 +558,13 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
spin_unlock_irqrestore(&rq->lock, flags);
skb_queue_walk_safe(&queue, skb, tmp) {
- struct net_device *dev = skb->dev;
+ struct net_device *dev;
+
+ br2684_push(atmvcc, skb);
+ dev = skb->dev;
dev->stats.rx_bytes -= skb->len;
dev->stats.rx_packets--;
-
- br2684_push(atmvcc, skb);
}
/* initialize netdev carrier state */
diff --git a/net/atm/lec.c b/net/atm/lec.c
index 215c9fad7cdf..f1964caa0f83 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -643,7 +643,7 @@ static const struct net_device_ops lec_netdev_ops = {
.ndo_start_xmit = lec_start_xmit,
.ndo_change_mtu = lec_change_mtu,
.ndo_tx_timeout = lec_tx_timeout,
- .ndo_set_multicast_list = lec_set_multicast_list,
+ .ndo_set_rx_mode = lec_set_multicast_list,
};
static const unsigned char lec_ctrl_magic[] = {
diff --git a/net/batman-adv/Makefile b/net/batman-adv/Makefile
index 2de93d00631b..ce6861166499 100644
--- a/net/batman-adv/Makefile
+++ b/net/batman-adv/Makefile
@@ -19,8 +19,8 @@
#
obj-$(CONFIG_BATMAN_ADV) += batman-adv.o
-batman-adv-y += aggregation.o
batman-adv-y += bat_debugfs.o
+batman-adv-y += bat_iv_ogm.o
batman-adv-y += bat_sysfs.o
batman-adv-y += bitarray.o
batman-adv-y += gateway_client.o
diff --git a/net/batman-adv/aggregation.c b/net/batman-adv/aggregation.c
deleted file mode 100644
index 69467fe71ff2..000000000000
--- a/net/batman-adv/aggregation.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * 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-1301, USA
- *
- */
-
-#include "main.h"
-#include "translation-table.h"
-#include "aggregation.h"
-#include "send.h"
-#include "routing.h"
-#include "hard-interface.h"
-
-/* return true if new_packet can be aggregated with forw_packet */
-static bool can_aggregate_with(const struct batman_packet *new_batman_packet,
- struct bat_priv *bat_priv,
- int packet_len,
- unsigned long send_time,
- bool directlink,
- const struct hard_iface *if_incoming,
- const struct forw_packet *forw_packet)
-{
- struct batman_packet *batman_packet =
- (struct batman_packet *)forw_packet->skb->data;
- int aggregated_bytes = forw_packet->packet_len + packet_len;
- struct hard_iface *primary_if = NULL;
- bool res = false;
-
- /**
- * we can aggregate the current packet to this aggregated packet
- * if:
- *
- * - the send time is within our MAX_AGGREGATION_MS time
- * - the resulting packet wont be bigger than
- * MAX_AGGREGATION_BYTES
- */
-
- if (time_before(send_time, forw_packet->send_time) &&
- time_after_eq(send_time + msecs_to_jiffies(MAX_AGGREGATION_MS),
- forw_packet->send_time) &&
- (aggregated_bytes <= MAX_AGGREGATION_BYTES)) {
-
- /**
- * check aggregation compatibility
- * -> direct link packets are broadcasted on
- * their interface only
- * -> aggregate packet if the current packet is
- * a "global" packet as well as the base
- * packet
- */
-
- primary_if = primary_if_get_selected(bat_priv);
- if (!primary_if)
- goto out;
-
- /* packets without direct link flag and high TTL
- * are flooded through the net */
- if ((!directlink) &&
- (!(batman_packet->flags & DIRECTLINK)) &&
- (batman_packet->ttl != 1) &&
-
- /* own packets originating non-primary
- * interfaces leave only that interface */
- ((!forw_packet->own) ||
- (forw_packet->if_incoming == primary_if))) {
- res = true;
- goto out;
- }
-
- /* if the incoming packet is sent via this one
- * interface only - we still can aggregate */
- if ((directlink) &&
- (new_batman_packet->ttl == 1) &&
- (forw_packet->if_incoming == if_incoming) &&
-
- /* packets from direct neighbors or
- * own secondary interface packets
- * (= secondary interface packets in general) */
- (batman_packet->flags & DIRECTLINK ||
- (forw_packet->own &&
- forw_packet->if_incoming != primary_if))) {
- res = true;
- goto out;
- }
- }
-
-out:
- if (primary_if)
- hardif_free_ref(primary_if);
- return res;
-}
-
-/* create a new aggregated packet and add this packet to it */
-static void new_aggregated_packet(const unsigned char *packet_buff,
- int packet_len, unsigned long send_time,
- bool direct_link,
- struct hard_iface *if_incoming,
- int own_packet)
-{
- struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct forw_packet *forw_packet_aggr;
- unsigned char *skb_buff;
-
- if (!atomic_inc_not_zero(&if_incoming->refcount))
- return;
-
- /* own packet should always be scheduled */
- if (!own_packet) {
- if (!atomic_dec_not_zero(&bat_priv->batman_queue_left)) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "batman packet queue full\n");
- goto out;
- }
- }
-
- forw_packet_aggr = kmalloc(sizeof(*forw_packet_aggr), GFP_ATOMIC);
- if (!forw_packet_aggr) {
- if (!own_packet)
- atomic_inc(&bat_priv->batman_queue_left);
- goto out;
- }
-
- if ((atomic_read(&bat_priv->aggregated_ogms)) &&
- (packet_len < MAX_AGGREGATION_BYTES))
- forw_packet_aggr->skb = dev_alloc_skb(MAX_AGGREGATION_BYTES +
- sizeof(struct ethhdr));
- else
- forw_packet_aggr->skb = dev_alloc_skb(packet_len +
- sizeof(struct ethhdr));
-
- if (!forw_packet_aggr->skb) {
- if (!own_packet)
- atomic_inc(&bat_priv->batman_queue_left);
- kfree(forw_packet_aggr);
- goto out;
- }
- skb_reserve(forw_packet_aggr->skb, sizeof(struct ethhdr));
-
- INIT_HLIST_NODE(&forw_packet_aggr->list);
-
- skb_buff = skb_put(forw_packet_aggr->skb, packet_len);
- forw_packet_aggr->packet_len = packet_len;
- memcpy(skb_buff, packet_buff, packet_len);
-
- forw_packet_aggr->own = own_packet;
- forw_packet_aggr->if_incoming = if_incoming;
- forw_packet_aggr->num_packets = 0;
- forw_packet_aggr->direct_link_flags = NO_FLAGS;
- forw_packet_aggr->send_time = send_time;
-
- /* save packet direct link flag status */
- if (direct_link)
- forw_packet_aggr->direct_link_flags |= 1;
-
- /* add new packet to packet list */
- spin_lock_bh(&bat_priv->forw_bat_list_lock);
- hlist_add_head(&forw_packet_aggr->list, &bat_priv->forw_bat_list);
- spin_unlock_bh(&bat_priv->forw_bat_list_lock);
-
- /* start timer for this packet */
- INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work,
- send_outstanding_bat_packet);
- queue_delayed_work(bat_event_workqueue,
- &forw_packet_aggr->delayed_work,
- send_time - jiffies);
-
- return;
-out:
- hardif_free_ref(if_incoming);
-}
-
-/* aggregate a new packet into the existing aggregation */
-static void aggregate(struct forw_packet *forw_packet_aggr,
- const unsigned char *packet_buff, int packet_len,
- bool direct_link)
-{
- unsigned char *skb_buff;
-
- skb_buff = skb_put(forw_packet_aggr->skb, packet_len);
- memcpy(skb_buff, packet_buff, packet_len);
- forw_packet_aggr->packet_len += packet_len;
- forw_packet_aggr->num_packets++;
-
- /* save packet direct link flag status */
- if (direct_link)
- forw_packet_aggr->direct_link_flags |=
- (1 << forw_packet_aggr->num_packets);
-}
-
-void add_bat_packet_to_list(struct bat_priv *bat_priv,
- unsigned char *packet_buff, int packet_len,
- struct hard_iface *if_incoming, int own_packet,
- unsigned long send_time)
-{
- /**
- * _aggr -> pointer to the packet we want to aggregate with
- * _pos -> pointer to the position in the queue
- */
- struct forw_packet *forw_packet_aggr = NULL, *forw_packet_pos = NULL;
- struct hlist_node *tmp_node;
- struct batman_packet *batman_packet =
- (struct batman_packet *)packet_buff;
- bool direct_link = batman_packet->flags & DIRECTLINK ? 1 : 0;
-
- /* find position for the packet in the forward queue */
- spin_lock_bh(&bat_priv->forw_bat_list_lock);
- /* own packets are not to be aggregated */
- if ((atomic_read(&bat_priv->aggregated_ogms)) && (!own_packet)) {
- hlist_for_each_entry(forw_packet_pos, tmp_node,
- &bat_priv->forw_bat_list, list) {
- if (can_aggregate_with(batman_packet,
- bat_priv,
- packet_len,
- send_time,
- direct_link,
- if_incoming,
- forw_packet_pos)) {
- forw_packet_aggr = forw_packet_pos;
- break;
- }
- }
- }
-
- /* nothing to aggregate with - either aggregation disabled or no
- * suitable aggregation packet found */
- if (!forw_packet_aggr) {
- /* the following section can run without the lock */
- spin_unlock_bh(&bat_priv->forw_bat_list_lock);
-
- /**
- * if we could not aggregate this packet with one of the others
- * we hold it back for a while, so that it might be aggregated
- * later on
- */
- if ((!own_packet) &&
- (atomic_read(&bat_priv->aggregated_ogms)))
- send_time += msecs_to_jiffies(MAX_AGGREGATION_MS);
-
- new_aggregated_packet(packet_buff, packet_len,
- send_time, direct_link,
- if_incoming, own_packet);
- } else {
- aggregate(forw_packet_aggr,
- packet_buff, packet_len,
- direct_link);
- spin_unlock_bh(&bat_priv->forw_bat_list_lock);
- }
-}
-
-/* unpack the aggregated packets and process them one by one */
-void receive_aggr_bat_packet(const struct ethhdr *ethhdr,
- unsigned char *packet_buff, int packet_len,
- struct hard_iface *if_incoming)
-{
- struct batman_packet *batman_packet;
- int buff_pos = 0;
- unsigned char *tt_buff;
-
- batman_packet = (struct batman_packet *)packet_buff;
-
- do {
- /* network to host order for our 32bit seqno and the
- orig_interval */
- batman_packet->seqno = ntohl(batman_packet->seqno);
- batman_packet->tt_crc = ntohs(batman_packet->tt_crc);
-
- tt_buff = packet_buff + buff_pos + BAT_PACKET_LEN;
-
- receive_bat_packet(ethhdr, batman_packet, tt_buff, if_incoming);
-
- buff_pos += BAT_PACKET_LEN +
- tt_len(batman_packet->tt_num_changes);
-
- batman_packet = (struct batman_packet *)
- (packet_buff + buff_pos);
- } while (aggregated_packet(buff_pos, packet_len,
- batman_packet->tt_num_changes));
-}
diff --git a/net/batman-adv/aggregation.h b/net/batman-adv/aggregation.h
deleted file mode 100644
index 216337bb841f..000000000000
--- a/net/batman-adv/aggregation.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * 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-1301, USA
- *
- */
-
-#ifndef _NET_BATMAN_ADV_AGGREGATION_H_
-#define _NET_BATMAN_ADV_AGGREGATION_H_
-
-#include "main.h"
-
-/* is there another aggregated packet here? */
-static inline int aggregated_packet(int buff_pos, int packet_len,
- int tt_num_changes)
-{
- int next_buff_pos = buff_pos + BAT_PACKET_LEN + (tt_num_changes *
- sizeof(struct tt_change));
-
- return (next_buff_pos <= packet_len) &&
- (next_buff_pos <= MAX_AGGREGATION_BYTES);
-}
-
-void add_bat_packet_to_list(struct bat_priv *bat_priv,
- unsigned char *packet_buff, int packet_len,
- struct hard_iface *if_incoming, int own_packet,
- unsigned long send_time);
-void receive_aggr_bat_packet(const struct ethhdr *ethhdr,
- unsigned char *packet_buff, int packet_len,
- struct hard_iface *if_incoming);
-
-#endif /* _NET_BATMAN_ADV_AGGREGATION_H_ */
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
new file mode 100644
index 000000000000..3512e251545b
--- /dev/null
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -0,0 +1,1170 @@
+/*
+ * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors:
+ *
+ * Marek Lindner, Simon Wunderlich
+ *
+ * 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-1301, USA
+ *
+ */
+
+#include "main.h"
+#include "bat_ogm.h"
+#include "translation-table.h"
+#include "ring_buffer.h"
+#include "originator.h"
+#include "routing.h"
+#include "gateway_common.h"
+#include "gateway_client.h"
+#include "hard-interface.h"
+#include "send.h"
+
+void bat_ogm_init(struct hard_iface *hard_iface)
+{
+ struct batman_ogm_packet *batman_ogm_packet;
+
+ hard_iface->packet_len = BATMAN_OGM_LEN;
+ hard_iface->packet_buff = kmalloc(hard_iface->packet_len, GFP_ATOMIC);
+
+ batman_ogm_packet = (struct batman_ogm_packet *)hard_iface->packet_buff;
+ batman_ogm_packet->packet_type = BAT_OGM;
+ batman_ogm_packet->version = COMPAT_VERSION;
+ batman_ogm_packet->flags = NO_FLAGS;
+ batman_ogm_packet->ttl = 2;
+ batman_ogm_packet->tq = TQ_MAX_VALUE;
+ batman_ogm_packet->tt_num_changes = 0;
+ batman_ogm_packet->ttvn = 0;
+}
+
+void bat_ogm_init_primary(struct hard_iface *hard_iface)
+{
+ struct batman_ogm_packet *batman_ogm_packet;
+
+ batman_ogm_packet = (struct batman_ogm_packet *)hard_iface->packet_buff;
+ batman_ogm_packet->flags = PRIMARIES_FIRST_HOP;
+ batman_ogm_packet->ttl = TTL;
+}
+
+void bat_ogm_update_mac(struct hard_iface *hard_iface)
+{
+ struct batman_ogm_packet *batman_ogm_packet;
+
+ batman_ogm_packet = (struct batman_ogm_packet *)hard_iface->packet_buff;
+ memcpy(batman_ogm_packet->orig,
+ hard_iface->net_dev->dev_addr, ETH_ALEN);
+ memcpy(batman_ogm_packet->prev_sender,
+ hard_iface->net_dev->dev_addr, ETH_ALEN);
+}
+
+/* when do we schedule our own ogm to be sent */
+static unsigned long bat_ogm_emit_send_time(const struct bat_priv *bat_priv)
+{
+ return jiffies + msecs_to_jiffies(
+ atomic_read(&bat_priv->orig_interval) -
+ JITTER + (random32() % 2*JITTER));
+}
+
+/* when do we schedule a ogm packet to be sent */
+static unsigned long bat_ogm_fwd_send_time(void)
+{
+ return jiffies + msecs_to_jiffies(random32() % (JITTER/2));
+}
+
+/* apply hop penalty for a normal link */
+static uint8_t hop_penalty(uint8_t tq, const struct bat_priv *bat_priv)
+{
+ int hop_penalty = atomic_read(&bat_priv->hop_penalty);
+ return (tq * (TQ_MAX_VALUE - hop_penalty)) / (TQ_MAX_VALUE);
+}
+
+/* is there another aggregated packet here? */
+static int bat_ogm_aggr_packet(int buff_pos, int packet_len,
+ int tt_num_changes)
+{
+ int next_buff_pos = buff_pos + BATMAN_OGM_LEN + tt_len(tt_num_changes);
+
+ return (next_buff_pos <= packet_len) &&
+ (next_buff_pos <= MAX_AGGREGATION_BYTES);
+}
+
+/* send a batman ogm to a given interface */
+static void bat_ogm_send_to_if(struct forw_packet *forw_packet,
+ struct hard_iface *hard_iface)
+{
+ struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
+ char *fwd_str;
+ uint8_t packet_num;
+ int16_t buff_pos;
+ struct batman_ogm_packet *batman_ogm_packet;
+ struct sk_buff *skb;
+
+ if (hard_iface->if_status != IF_ACTIVE)
+ return;
+
+ packet_num = 0;
+ buff_pos = 0;
+ batman_ogm_packet = (struct batman_ogm_packet *)forw_packet->skb->data;
+
+ /* adjust all flags and log packets */
+ while (bat_ogm_aggr_packet(buff_pos, forw_packet->packet_len,
+ batman_ogm_packet->tt_num_changes)) {
+
+ /* we might have aggregated direct link packets with an
+ * ordinary base packet */
+ if ((forw_packet->direct_link_flags & (1 << packet_num)) &&
+ (forw_packet->if_incoming == hard_iface))
+ batman_ogm_packet->flags |= DIRECTLINK;
+ else
+ batman_ogm_packet->flags &= ~DIRECTLINK;
+
+ fwd_str = (packet_num > 0 ? "Forwarding" : (forw_packet->own ?
+ "Sending own" :
+ "Forwarding"));
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d,"
+ " IDF %s, ttvn %d) on interface %s [%pM]\n",
+ fwd_str, (packet_num > 0 ? "aggregated " : ""),
+ batman_ogm_packet->orig,
+ ntohl(batman_ogm_packet->seqno),
+ batman_ogm_packet->tq, batman_ogm_packet->ttl,
+ (batman_ogm_packet->flags & DIRECTLINK ?
+ "on" : "off"),
+ batman_ogm_packet->ttvn, hard_iface->net_dev->name,
+ hard_iface->net_dev->dev_addr);
+
+ buff_pos += BATMAN_OGM_LEN +
+ tt_len(batman_ogm_packet->tt_num_changes);
+ packet_num++;
+ batman_ogm_packet = (struct batman_ogm_packet *)
+ (forw_packet->skb->data + buff_pos);
+ }
+
+ /* create clone because function is called more than once */
+ skb = skb_clone(forw_packet->skb, GFP_ATOMIC);
+ if (skb)
+ send_skb_packet(skb, hard_iface, broadcast_addr);
+}
+
+/* send a batman ogm packet */
+void bat_ogm_emit(struct forw_packet *forw_packet)
+{
+ struct hard_iface *hard_iface;
+ struct net_device *soft_iface;
+ struct bat_priv *bat_priv;
+ struct hard_iface *primary_if = NULL;
+ struct batman_ogm_packet *batman_ogm_packet;
+ unsigned char directlink;
+
+ batman_ogm_packet = (struct batman_ogm_packet *)
+ (forw_packet->skb->data);
+ directlink = (batman_ogm_packet->flags & DIRECTLINK ? 1 : 0);
+
+ if (!forw_packet->if_incoming) {
+ pr_err("Error - can't forward packet: incoming iface not "
+ "specified\n");
+ goto out;
+ }
+
+ soft_iface = forw_packet->if_incoming->soft_iface;
+ bat_priv = netdev_priv(soft_iface);
+
+ if (forw_packet->if_incoming->if_status != IF_ACTIVE)
+ goto out;
+
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ goto out;
+
+ /* multihomed peer assumed */
+ /* non-primary OGMs are only broadcasted on their interface */
+ if ((directlink && (batman_ogm_packet->ttl == 1)) ||
+ (forw_packet->own && (forw_packet->if_incoming != primary_if))) {
+
+ /* FIXME: what about aggregated packets ? */
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "%s packet (originator %pM, seqno %d, TTL %d) "
+ "on interface %s [%pM]\n",
+ (forw_packet->own ? "Sending own" : "Forwarding"),
+ batman_ogm_packet->orig,
+ ntohl(batman_ogm_packet->seqno),
+ batman_ogm_packet->ttl,
+ forw_packet->if_incoming->net_dev->name,
+ forw_packet->if_incoming->net_dev->dev_addr);
+
+ /* skb is only used once and than forw_packet is free'd */
+ send_skb_packet(forw_packet->skb, forw_packet->if_incoming,
+ broadcast_addr);
+ forw_packet->skb = NULL;
+
+ goto out;
+ }
+
+ /* broadcast on every interface */
+ rcu_read_lock();
+ list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
+ if (hard_iface->soft_iface != soft_iface)
+ continue;
+
+ bat_ogm_send_to_if(forw_packet, hard_iface);
+ }
+ rcu_read_unlock();
+
+out:
+ if (primary_if)
+ hardif_free_ref(primary_if);
+}
+
+/* return true if new_packet can be aggregated with forw_packet */
+static bool bat_ogm_can_aggregate(const struct batman_ogm_packet
+ *new_batman_ogm_packet,
+ struct bat_priv *bat_priv,
+ int packet_len, unsigned long send_time,
+ bool directlink,
+ const struct hard_iface *if_incoming,
+ const struct forw_packet *forw_packet)
+{
+ struct batman_ogm_packet *batman_ogm_packet;
+ int aggregated_bytes = forw_packet->packet_len + packet_len;
+ struct hard_iface *primary_if = NULL;
+ bool res = false;
+
+ batman_ogm_packet = (struct batman_ogm_packet *)forw_packet->skb->data;
+
+ /**
+ * we can aggregate the current packet to this aggregated packet
+ * if:
+ *
+ * - the send time is within our MAX_AGGREGATION_MS time
+ * - the resulting packet wont be bigger than
+ * MAX_AGGREGATION_BYTES
+ */
+
+ if (time_before(send_time, forw_packet->send_time) &&
+ time_after_eq(send_time + msecs_to_jiffies(MAX_AGGREGATION_MS),
+ forw_packet->send_time) &&
+ (aggregated_bytes <= MAX_AGGREGATION_BYTES)) {
+
+ /**
+ * check aggregation compatibility
+ * -> direct link packets are broadcasted on
+ * their interface only
+ * -> aggregate packet if the current packet is
+ * a "global" packet as well as the base
+ * packet
+ */
+
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ goto out;
+
+ /* packets without direct link flag and high TTL
+ * are flooded through the net */
+ if ((!directlink) &&
+ (!(batman_ogm_packet->flags & DIRECTLINK)) &&
+ (batman_ogm_packet->ttl != 1) &&
+
+ /* own packets originating non-primary
+ * interfaces leave only that interface */
+ ((!forw_packet->own) ||
+ (forw_packet->if_incoming == primary_if))) {
+ res = true;
+ goto out;
+ }
+
+ /* if the incoming packet is sent via this one
+ * interface only - we still can aggregate */
+ if ((directlink) &&
+ (new_batman_ogm_packet->ttl == 1) &&
+ (forw_packet->if_incoming == if_incoming) &&
+
+ /* packets from direct neighbors or
+ * own secondary interface packets
+ * (= secondary interface packets in general) */
+ (batman_ogm_packet->flags & DIRECTLINK ||
+ (forw_packet->own &&
+ forw_packet->if_incoming != primary_if))) {
+ res = true;
+ goto out;
+ }
+ }
+
+out:
+ if (primary_if)
+ hardif_free_ref(primary_if);
+ return res;
+}
+
+/* create a new aggregated packet and add this packet to it */
+static void bat_ogm_aggregate_new(const unsigned char *packet_buff,
+ int packet_len, unsigned long send_time,
+ bool direct_link,
+ struct hard_iface *if_incoming,
+ int own_packet)
+{
+ struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
+ struct forw_packet *forw_packet_aggr;
+ unsigned char *skb_buff;
+
+ if (!atomic_inc_not_zero(&if_incoming->refcount))
+ return;
+
+ /* own packet should always be scheduled */
+ if (!own_packet) {
+ if (!atomic_dec_not_zero(&bat_priv->batman_queue_left)) {
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "batman packet queue full\n");
+ goto out;
+ }
+ }
+
+ forw_packet_aggr = kmalloc(sizeof(*forw_packet_aggr), GFP_ATOMIC);
+ if (!forw_packet_aggr) {
+ if (!own_packet)
+ atomic_inc(&bat_priv->batman_queue_left);
+ goto out;
+ }
+
+ if ((atomic_read(&bat_priv->aggregated_ogms)) &&
+ (packet_len < MAX_AGGREGATION_BYTES))
+ forw_packet_aggr->skb = dev_alloc_skb(MAX_AGGREGATION_BYTES +
+ sizeof(struct ethhdr));
+ else
+ forw_packet_aggr->skb = dev_alloc_skb(packet_len +
+ sizeof(struct ethhdr));
+
+ if (!forw_packet_aggr->skb) {
+ if (!own_packet)
+ atomic_inc(&bat_priv->batman_queue_left);
+ kfree(forw_packet_aggr);
+ goto out;
+ }
+ skb_reserve(forw_packet_aggr->skb, sizeof(struct ethhdr));
+
+ INIT_HLIST_NODE(&forw_packet_aggr->list);
+
+ skb_buff = skb_put(forw_packet_aggr->skb, packet_len);
+ forw_packet_aggr->packet_len = packet_len;
+ memcpy(skb_buff, packet_buff, packet_len);
+
+ forw_packet_aggr->own = own_packet;
+ forw_packet_aggr->if_incoming = if_incoming;
+ forw_packet_aggr->num_packets = 0;
+ forw_packet_aggr->direct_link_flags = NO_FLAGS;
+ forw_packet_aggr->send_time = send_time;
+
+ /* save packet direct link flag status */
+ if (direct_link)
+ forw_packet_aggr->direct_link_flags |= 1;
+
+ /* add new packet to packet list */
+ spin_lock_bh(&bat_priv->forw_bat_list_lock);
+ hlist_add_head(&forw_packet_aggr->list, &bat_priv->forw_bat_list);
+ spin_unlock_bh(&bat_priv->forw_bat_list_lock);
+
+ /* start timer for this packet */
+ INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work,
+ send_outstanding_bat_ogm_packet);
+ queue_delayed_work(bat_event_workqueue,
+ &forw_packet_aggr->delayed_work,
+ send_time - jiffies);
+
+ return;
+out:
+ hardif_free_ref(if_incoming);
+}
+
+/* aggregate a new packet into the existing ogm packet */
+static void bat_ogm_aggregate(struct forw_packet *forw_packet_aggr,
+ const unsigned char *packet_buff,
+ int packet_len, bool direct_link)
+{
+ unsigned char *skb_buff;
+
+ skb_buff = skb_put(forw_packet_aggr->skb, packet_len);
+ memcpy(skb_buff, packet_buff, packet_len);
+ forw_packet_aggr->packet_len += packet_len;
+ forw_packet_aggr->num_packets++;
+
+ /* save packet direct link flag status */
+ if (direct_link)
+ forw_packet_aggr->direct_link_flags |=
+ (1 << forw_packet_aggr->num_packets);
+}
+
+static void bat_ogm_queue_add(struct bat_priv *bat_priv,
+ unsigned char *packet_buff,
+ int packet_len, struct hard_iface *if_incoming,
+ int own_packet, unsigned long send_time)
+{
+ /**
+ * _aggr -> pointer to the packet we want to aggregate with
+ * _pos -> pointer to the position in the queue
+ */
+ struct forw_packet *forw_packet_aggr = NULL, *forw_packet_pos = NULL;
+ struct hlist_node *tmp_node;
+ struct batman_ogm_packet *batman_ogm_packet;
+ bool direct_link;
+
+ batman_ogm_packet = (struct batman_ogm_packet *)packet_buff;
+ direct_link = batman_ogm_packet->flags & DIRECTLINK ? 1 : 0;
+
+ /* find position for the packet in the forward queue */
+ spin_lock_bh(&bat_priv->forw_bat_list_lock);
+ /* own packets are not to be aggregated */
+ if ((atomic_read(&bat_priv->aggregated_ogms)) && (!own_packet)) {
+ hlist_for_each_entry(forw_packet_pos, tmp_node,
+ &bat_priv->forw_bat_list, list) {
+ if (bat_ogm_can_aggregate(batman_ogm_packet,
+ bat_priv, packet_len,
+ send_time, direct_link,
+ if_incoming,
+ forw_packet_pos)) {
+ forw_packet_aggr = forw_packet_pos;
+ break;
+ }
+ }
+ }
+
+ /* nothing to aggregate with - either aggregation disabled or no
+ * suitable aggregation packet found */
+ if (!forw_packet_aggr) {
+ /* the following section can run without the lock */
+ spin_unlock_bh(&bat_priv->forw_bat_list_lock);
+
+ /**
+ * if we could not aggregate this packet with one of the others
+ * we hold it back for a while, so that it might be aggregated
+ * later on
+ */
+ if ((!own_packet) &&
+ (atomic_read(&bat_priv->aggregated_ogms)))
+ send_time += msecs_to_jiffies(MAX_AGGREGATION_MS);
+
+ bat_ogm_aggregate_new(packet_buff, packet_len,
+ send_time, direct_link,
+ if_incoming, own_packet);
+ } else {
+ bat_ogm_aggregate(forw_packet_aggr, packet_buff, packet_len,
+ direct_link);
+ spin_unlock_bh(&bat_priv->forw_bat_list_lock);
+ }
+}
+
+static void bat_ogm_forward(struct orig_node *orig_node,
+ const struct ethhdr *ethhdr,
+ struct batman_ogm_packet *batman_ogm_packet,
+ int directlink, struct hard_iface *if_incoming)
+{
+ struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
+ struct neigh_node *router;
+ uint8_t in_tq, in_ttl, tq_avg = 0;
+ uint8_t tt_num_changes;
+
+ if (batman_ogm_packet->ttl <= 1) {
+ bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n");
+ return;
+ }
+
+ router = orig_node_get_router(orig_node);
+
+ in_tq = batman_ogm_packet->tq;
+ in_ttl = batman_ogm_packet->ttl;
+ tt_num_changes = batman_ogm_packet->tt_num_changes;
+
+ batman_ogm_packet->ttl--;
+ memcpy(batman_ogm_packet->prev_sender, ethhdr->h_source, ETH_ALEN);
+
+ /* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast
+ * of our best tq value */
+ if (router && router->tq_avg != 0) {
+
+ /* rebroadcast ogm of best ranking neighbor as is */
+ if (!compare_eth(router->addr, ethhdr->h_source)) {
+ batman_ogm_packet->tq = router->tq_avg;
+
+ if (router->last_ttl)
+ batman_ogm_packet->ttl = router->last_ttl - 1;
+ }
+
+ tq_avg = router->tq_avg;
+ }
+
+ if (router)
+ neigh_node_free_ref(router);
+
+ /* apply hop penalty */
+ batman_ogm_packet->tq = hop_penalty(batman_ogm_packet->tq, bat_priv);
+
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Forwarding packet: tq_orig: %i, tq_avg: %i, "
+ "tq_forw: %i, ttl_orig: %i, ttl_forw: %i\n",
+ in_tq, tq_avg, batman_ogm_packet->tq, in_ttl - 1,
+ batman_ogm_packet->ttl);
+
+ batman_ogm_packet->seqno = htonl(batman_ogm_packet->seqno);
+ batman_ogm_packet->tt_crc = htons(batman_ogm_packet->tt_crc);
+
+ /* switch of primaries first hop flag when forwarding */
+ batman_ogm_packet->flags &= ~PRIMARIES_FIRST_HOP;
+ if (directlink)
+ batman_ogm_packet->flags |= DIRECTLINK;
+ else
+ batman_ogm_packet->flags &= ~DIRECTLINK;
+
+ bat_ogm_queue_add(bat_priv, (unsigned char *)batman_ogm_packet,
+ BATMAN_OGM_LEN + tt_len(tt_num_changes),
+ if_incoming, 0, bat_ogm_fwd_send_time());
+}
+
+void bat_ogm_schedule(struct hard_iface *hard_iface, int tt_num_changes)
+{
+ struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
+ struct batman_ogm_packet *batman_ogm_packet;
+ struct hard_iface *primary_if;
+ int vis_server;
+
+ vis_server = atomic_read(&bat_priv->vis_mode);
+ primary_if = primary_if_get_selected(bat_priv);
+
+ batman_ogm_packet = (struct batman_ogm_packet *)hard_iface->packet_buff;
+
+ /* change sequence number to network order */
+ batman_ogm_packet->seqno =
+ htonl((uint32_t)atomic_read(&hard_iface->seqno));
+
+ batman_ogm_packet->ttvn = atomic_read(&bat_priv->ttvn);
+ batman_ogm_packet->tt_crc = htons((uint16_t)
+ atomic_read(&bat_priv->tt_crc));
+ if (tt_num_changes >= 0)
+ batman_ogm_packet->tt_num_changes = tt_num_changes;
+
+ if (vis_server == VIS_TYPE_SERVER_SYNC)
+ batman_ogm_packet->flags |= VIS_SERVER;
+ else
+ batman_ogm_packet->flags &= ~VIS_SERVER;
+
+ if ((hard_iface == primary_if) &&
+ (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER))
+ batman_ogm_packet->gw_flags =
+ (uint8_t)atomic_read(&bat_priv->gw_bandwidth);
+ else
+ batman_ogm_packet->gw_flags = NO_FLAGS;
+
+ atomic_inc(&hard_iface->seqno);
+
+ slide_own_bcast_window(hard_iface);
+ bat_ogm_queue_add(bat_priv, hard_iface->packet_buff,
+ hard_iface->packet_len, hard_iface, 1,
+ bat_ogm_emit_send_time(bat_priv));
+
+ if (primary_if)
+ hardif_free_ref(primary_if);
+}
+
+static void bat_ogm_orig_update(struct bat_priv *bat_priv,
+ struct orig_node *orig_node,
+ const struct ethhdr *ethhdr,
+ const struct batman_ogm_packet
+ *batman_ogm_packet,
+ struct hard_iface *if_incoming,
+ const unsigned char *tt_buff, int is_duplicate)
+{
+ struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
+ struct neigh_node *router = NULL;
+ struct orig_node *orig_node_tmp;
+ struct hlist_node *node;
+ uint8_t bcast_own_sum_orig, bcast_own_sum_neigh;
+
+ bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): "
+ "Searching and updating originator entry of received packet\n");
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(tmp_neigh_node, node,
+ &orig_node->neigh_list, list) {
+ if (compare_eth(tmp_neigh_node->addr, ethhdr->h_source) &&
+ (tmp_neigh_node->if_incoming == if_incoming) &&
+ atomic_inc_not_zero(&tmp_neigh_node->refcount)) {
+ if (neigh_node)
+ neigh_node_free_ref(neigh_node);
+ neigh_node = tmp_neigh_node;
+ continue;
+ }
+
+ if (is_duplicate)
+ continue;
+
+ spin_lock_bh(&tmp_neigh_node->tq_lock);
+ ring_buffer_set(tmp_neigh_node->tq_recv,
+ &tmp_neigh_node->tq_index, 0);
+ tmp_neigh_node->tq_avg =
+ ring_buffer_avg(tmp_neigh_node->tq_recv);
+ spin_unlock_bh(&tmp_neigh_node->tq_lock);
+ }
+
+ if (!neigh_node) {
+ struct orig_node *orig_tmp;
+
+ orig_tmp = get_orig_node(bat_priv, ethhdr->h_source);
+ if (!orig_tmp)
+ goto unlock;
+
+ neigh_node = create_neighbor(orig_node, orig_tmp,
+ ethhdr->h_source, if_incoming);
+
+ orig_node_free_ref(orig_tmp);
+ if (!neigh_node)
+ goto unlock;
+ } else
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Updating existing last-hop neighbor of originator\n");
+
+ rcu_read_unlock();
+
+ orig_node->flags = batman_ogm_packet->flags;
+ neigh_node->last_valid = jiffies;
+
+ spin_lock_bh(&neigh_node->tq_lock);
+ ring_buffer_set(neigh_node->tq_recv,
+ &neigh_node->tq_index,
+ batman_ogm_packet->tq);
+ neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv);
+ spin_unlock_bh(&neigh_node->tq_lock);
+
+ if (!is_duplicate) {
+ orig_node->last_ttl = batman_ogm_packet->ttl;
+ neigh_node->last_ttl = batman_ogm_packet->ttl;
+ }
+
+ bonding_candidate_add(orig_node, neigh_node);
+
+ /* if this neighbor already is our next hop there is nothing
+ * to change */
+ router = orig_node_get_router(orig_node);
+ if (router == neigh_node)
+ goto update_tt;
+
+ /* if this neighbor does not offer a better TQ we won't consider it */
+ if (router && (router->tq_avg > neigh_node->tq_avg))
+ goto update_tt;
+
+ /* if the TQ is the same and the link not more symmetric we
+ * won't consider it either */
+ if (router && (neigh_node->tq_avg == router->tq_avg)) {
+ orig_node_tmp = router->orig_node;
+ spin_lock_bh(&orig_node_tmp->ogm_cnt_lock);
+ bcast_own_sum_orig =
+ orig_node_tmp->bcast_own_sum[if_incoming->if_num];
+ spin_unlock_bh(&orig_node_tmp->ogm_cnt_lock);
+
+ orig_node_tmp = neigh_node->orig_node;
+ spin_lock_bh(&orig_node_tmp->ogm_cnt_lock);
+ bcast_own_sum_neigh =
+ orig_node_tmp->bcast_own_sum[if_incoming->if_num];
+ spin_unlock_bh(&orig_node_tmp->ogm_cnt_lock);
+
+ if (bcast_own_sum_orig >= bcast_own_sum_neigh)
+ goto update_tt;
+ }
+
+ update_route(bat_priv, orig_node, neigh_node);
+
+update_tt:
+ /* I have to check for transtable changes only if the OGM has been
+ * sent through a primary interface */
+ if (((batman_ogm_packet->orig != ethhdr->h_source) &&
+ (batman_ogm_packet->ttl > 2)) ||
+ (batman_ogm_packet->flags & PRIMARIES_FIRST_HOP))
+ tt_update_orig(bat_priv, orig_node, tt_buff,
+ batman_ogm_packet->tt_num_changes,
+ batman_ogm_packet->ttvn,
+ batman_ogm_packet->tt_crc);
+
+ if (orig_node->gw_flags != batman_ogm_packet->gw_flags)
+ gw_node_update(bat_priv, orig_node,
+ batman_ogm_packet->gw_flags);
+
+ orig_node->gw_flags = batman_ogm_packet->gw_flags;
+
+ /* restart gateway selection if fast or late switching was enabled */
+ if ((orig_node->gw_flags) &&
+ (atomic_read(&bat_priv->gw_mode) == GW_MODE_CLIENT) &&
+ (atomic_read(&bat_priv->gw_sel_class) > 2))
+ gw_check_election(bat_priv, orig_node);
+
+ goto out;
+
+unlock:
+ rcu_read_unlock();
+out:
+ if (neigh_node)
+ neigh_node_free_ref(neigh_node);
+ if (router)
+ neigh_node_free_ref(router);
+}
+
+static int bat_ogm_calc_tq(struct orig_node *orig_node,
+ struct orig_node *orig_neigh_node,
+ struct batman_ogm_packet *batman_ogm_packet,
+ struct hard_iface *if_incoming)
+{
+ struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
+ struct neigh_node *neigh_node = NULL, *tmp_neigh_node;
+ struct hlist_node *node;
+ uint8_t total_count;
+ uint8_t orig_eq_count, neigh_rq_count, tq_own;
+ int tq_asym_penalty, ret = 0;
+
+ /* find corresponding one hop neighbor */
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(tmp_neigh_node, node,
+ &orig_neigh_node->neigh_list, list) {
+
+ if (!compare_eth(tmp_neigh_node->addr, orig_neigh_node->orig))
+ continue;
+
+ if (tmp_neigh_node->if_incoming != if_incoming)
+ continue;
+
+ if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
+ continue;
+
+ neigh_node = tmp_neigh_node;
+ break;
+ }
+ rcu_read_unlock();
+
+ if (!neigh_node)
+ neigh_node = create_neighbor(orig_neigh_node,
+ orig_neigh_node,
+ orig_neigh_node->orig,
+ if_incoming);
+
+ if (!neigh_node)
+ goto out;
+
+ /* if orig_node is direct neighbor update neigh_node last_valid */
+ if (orig_node == orig_neigh_node)
+ neigh_node->last_valid = jiffies;
+
+ orig_node->last_valid = jiffies;
+
+ /* find packet count of corresponding one hop neighbor */
+ spin_lock_bh(&orig_node->ogm_cnt_lock);
+ orig_eq_count = orig_neigh_node->bcast_own_sum[if_incoming->if_num];
+ neigh_rq_count = neigh_node->real_packet_count;
+ spin_unlock_bh(&orig_node->ogm_cnt_lock);
+
+ /* pay attention to not get a value bigger than 100 % */
+ total_count = (orig_eq_count > neigh_rq_count ?
+ neigh_rq_count : orig_eq_count);
+
+ /* if we have too few packets (too less data) we set tq_own to zero */
+ /* if we receive too few packets it is not considered bidirectional */
+ if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) ||
+ (neigh_rq_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM))
+ tq_own = 0;
+ else
+ /* neigh_node->real_packet_count is never zero as we
+ * only purge old information when getting new
+ * information */
+ tq_own = (TQ_MAX_VALUE * total_count) / neigh_rq_count;
+
+ /*
+ * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does
+ * affect the nearly-symmetric links only a little, but
+ * punishes asymmetric links more. This will give a value
+ * between 0 and TQ_MAX_VALUE
+ */
+ tq_asym_penalty = TQ_MAX_VALUE - (TQ_MAX_VALUE *
+ (TQ_LOCAL_WINDOW_SIZE - neigh_rq_count) *
+ (TQ_LOCAL_WINDOW_SIZE - neigh_rq_count) *
+ (TQ_LOCAL_WINDOW_SIZE - neigh_rq_count)) /
+ (TQ_LOCAL_WINDOW_SIZE *
+ TQ_LOCAL_WINDOW_SIZE *
+ TQ_LOCAL_WINDOW_SIZE);
+
+ batman_ogm_packet->tq = ((batman_ogm_packet->tq * tq_own
+ * tq_asym_penalty) /
+ (TQ_MAX_VALUE * TQ_MAX_VALUE));
+
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "bidirectional: "
+ "orig = %-15pM neigh = %-15pM => own_bcast = %2i, "
+ "real recv = %2i, local tq: %3i, asym_penalty: %3i, "
+ "total tq: %3i\n",
+ orig_node->orig, orig_neigh_node->orig, total_count,
+ neigh_rq_count, tq_own, tq_asym_penalty, batman_ogm_packet->tq);
+
+ /* if link has the minimum required transmission quality
+ * consider it bidirectional */
+ if (batman_ogm_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT)
+ ret = 1;
+
+out:
+ if (neigh_node)
+ neigh_node_free_ref(neigh_node);
+ return ret;
+}
+
+/* processes a batman packet for all interfaces, adjusts the sequence number and
+ * finds out whether it is a duplicate.
+ * returns:
+ * 1 the packet is a duplicate
+ * 0 the packet has not yet been received
+ * -1 the packet is old and has been received while the seqno window
+ * was protected. Caller should drop it.
+ */
+static int bat_ogm_update_seqnos(const struct ethhdr *ethhdr,
+ const struct batman_ogm_packet
+ *batman_ogm_packet,
+ const struct hard_iface *if_incoming)
+{
+ struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
+ struct orig_node *orig_node;
+ struct neigh_node *tmp_neigh_node;
+ struct hlist_node *node;
+ int is_duplicate = 0;
+ int32_t seq_diff;
+ int need_update = 0;
+ int set_mark, ret = -1;
+
+ orig_node = get_orig_node(bat_priv, batman_ogm_packet->orig);
+ if (!orig_node)
+ return 0;
+
+ spin_lock_bh(&orig_node->ogm_cnt_lock);
+ seq_diff = batman_ogm_packet->seqno - orig_node->last_real_seqno;
+
+ /* signalize caller that the packet is to be dropped. */
+ if (window_protected(bat_priv, seq_diff,
+ &orig_node->batman_seqno_reset))
+ goto out;
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(tmp_neigh_node, node,
+ &orig_node->neigh_list, list) {
+
+ is_duplicate |= get_bit_status(tmp_neigh_node->real_bits,
+ orig_node->last_real_seqno,
+ batman_ogm_packet->seqno);
+
+ if (compare_eth(tmp_neigh_node->addr, ethhdr->h_source) &&
+ (tmp_neigh_node->if_incoming == if_incoming))
+ set_mark = 1;
+ else
+ set_mark = 0;
+
+ /* if the window moved, set the update flag. */
+ need_update |= bit_get_packet(bat_priv,
+ tmp_neigh_node->real_bits,
+ seq_diff, set_mark);
+
+ tmp_neigh_node->real_packet_count =
+ bit_packet_count(tmp_neigh_node->real_bits);
+ }
+ rcu_read_unlock();
+
+ if (need_update) {
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "updating last_seqno: old %d, new %d\n",
+ orig_node->last_real_seqno, batman_ogm_packet->seqno);
+ orig_node->last_real_seqno = batman_ogm_packet->seqno;
+ }
+
+ ret = is_duplicate;
+
+out:
+ spin_unlock_bh(&orig_node->ogm_cnt_lock);
+ orig_node_free_ref(orig_node);
+ return ret;
+}
+
+static void bat_ogm_process(const struct ethhdr *ethhdr,
+ struct batman_ogm_packet *batman_ogm_packet,
+ const unsigned char *tt_buff,
+ struct hard_iface *if_incoming)
+{
+ struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
+ struct hard_iface *hard_iface;
+ struct orig_node *orig_neigh_node, *orig_node;
+ struct neigh_node *router = NULL, *router_router = NULL;
+ struct neigh_node *orig_neigh_router = NULL;
+ int has_directlink_flag;
+ int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
+ int is_broadcast = 0, is_bidirectional, is_single_hop_neigh;
+ int is_duplicate;
+ uint32_t if_incoming_seqno;
+
+ /* Silently drop when the batman packet is actually not a
+ * correct packet.
+ *
+ * This might happen if a packet is padded (e.g. Ethernet has a
+ * minimum frame length of 64 byte) and the aggregation interprets
+ * it as an additional length.
+ *
+ * TODO: A more sane solution would be to have a bit in the
+ * batman_ogm_packet to detect whether the packet is the last
+ * packet in an aggregation. Here we expect that the padding
+ * is always zero (or not 0x01)
+ */
+ if (batman_ogm_packet->packet_type != BAT_OGM)
+ return;
+
+ /* could be changed by schedule_own_packet() */
+ if_incoming_seqno = atomic_read(&if_incoming->seqno);
+
+ has_directlink_flag = (batman_ogm_packet->flags & DIRECTLINK ? 1 : 0);
+
+ is_single_hop_neigh = (compare_eth(ethhdr->h_source,
+ batman_ogm_packet->orig) ? 1 : 0);
+
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Received BATMAN packet via NB: %pM, IF: %s [%pM] "
+ "(from OG: %pM, via prev OG: %pM, seqno %d, ttvn %u, "
+ "crc %u, changes %u, td %d, TTL %d, V %d, IDF %d)\n",
+ ethhdr->h_source, if_incoming->net_dev->name,
+ if_incoming->net_dev->dev_addr, batman_ogm_packet->orig,
+ batman_ogm_packet->prev_sender, batman_ogm_packet->seqno,
+ batman_ogm_packet->ttvn, batman_ogm_packet->tt_crc,
+ batman_ogm_packet->tt_num_changes, batman_ogm_packet->tq,
+ batman_ogm_packet->ttl, batman_ogm_packet->version,
+ has_directlink_flag);
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
+ if (hard_iface->if_status != IF_ACTIVE)
+ continue;
+
+ if (hard_iface->soft_iface != if_incoming->soft_iface)
+ continue;
+
+ if (compare_eth(ethhdr->h_source,
+ hard_iface->net_dev->dev_addr))
+ is_my_addr = 1;
+
+ if (compare_eth(batman_ogm_packet->orig,
+ hard_iface->net_dev->dev_addr))
+ is_my_orig = 1;
+
+ if (compare_eth(batman_ogm_packet->prev_sender,
+ hard_iface->net_dev->dev_addr))
+ is_my_oldorig = 1;
+
+ if (is_broadcast_ether_addr(ethhdr->h_source))
+ is_broadcast = 1;
+ }
+ rcu_read_unlock();
+
+ if (batman_ogm_packet->version != COMPAT_VERSION) {
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Drop packet: incompatible batman version (%i)\n",
+ batman_ogm_packet->version);
+ return;
+ }
+
+ if (is_my_addr) {
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Drop packet: received my own broadcast (sender: %pM"
+ ")\n",
+ ethhdr->h_source);
+ return;
+ }
+
+ if (is_broadcast) {
+ bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
+ "ignoring all packets with broadcast source addr (sender: %pM"
+ ")\n", ethhdr->h_source);
+ return;
+ }
+
+ if (is_my_orig) {
+ unsigned long *word;
+ int offset;
+
+ orig_neigh_node = get_orig_node(bat_priv, ethhdr->h_source);
+ if (!orig_neigh_node)
+ return;
+
+ /* neighbor has to indicate direct link and it has to
+ * come via the corresponding interface */
+ /* save packet seqno for bidirectional check */
+ if (has_directlink_flag &&
+ compare_eth(if_incoming->net_dev->dev_addr,
+ batman_ogm_packet->orig)) {
+ offset = if_incoming->if_num * NUM_WORDS;
+
+ spin_lock_bh(&orig_neigh_node->ogm_cnt_lock);
+ word = &(orig_neigh_node->bcast_own[offset]);
+ bit_mark(word,
+ if_incoming_seqno -
+ batman_ogm_packet->seqno - 2);
+ orig_neigh_node->bcast_own_sum[if_incoming->if_num] =
+ bit_packet_count(word);
+ spin_unlock_bh(&orig_neigh_node->ogm_cnt_lock);
+ }
+
+ bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
+ "originator packet from myself (via neighbor)\n");
+ orig_node_free_ref(orig_neigh_node);
+ return;
+ }
+
+ if (is_my_oldorig) {
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Drop packet: ignoring all rebroadcast echos (sender: "
+ "%pM)\n", ethhdr->h_source);
+ return;
+ }
+
+ orig_node = get_orig_node(bat_priv, batman_ogm_packet->orig);
+ if (!orig_node)
+ return;
+
+ is_duplicate = bat_ogm_update_seqnos(ethhdr, batman_ogm_packet,
+ if_incoming);
+
+ if (is_duplicate == -1) {
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Drop packet: packet within seqno protection time "
+ "(sender: %pM)\n", ethhdr->h_source);
+ goto out;
+ }
+
+ if (batman_ogm_packet->tq == 0) {
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Drop packet: originator packet with tq equal 0\n");
+ goto out;
+ }
+
+ router = orig_node_get_router(orig_node);
+ if (router)
+ router_router = orig_node_get_router(router->orig_node);
+
+ /* avoid temporary routing loops */
+ if (router && router_router &&
+ (compare_eth(router->addr, batman_ogm_packet->prev_sender)) &&
+ !(compare_eth(batman_ogm_packet->orig,
+ batman_ogm_packet->prev_sender)) &&
+ (compare_eth(router->addr, router_router->addr))) {
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Drop packet: ignoring all rebroadcast packets that "
+ "may make me loop (sender: %pM)\n", ethhdr->h_source);
+ goto out;
+ }
+
+ /* if sender is a direct neighbor the sender mac equals
+ * originator mac */
+ orig_neigh_node = (is_single_hop_neigh ?
+ orig_node :
+ get_orig_node(bat_priv, ethhdr->h_source));
+ if (!orig_neigh_node)
+ goto out;
+
+ orig_neigh_router = orig_node_get_router(orig_neigh_node);
+
+ /* drop packet if sender is not a direct neighbor and if we
+ * don't route towards it */
+ if (!is_single_hop_neigh && (!orig_neigh_router)) {
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Drop packet: OGM via unknown neighbor!\n");
+ goto out_neigh;
+ }
+
+ is_bidirectional = bat_ogm_calc_tq(orig_node, orig_neigh_node,
+ batman_ogm_packet, if_incoming);
+
+ bonding_save_primary(orig_node, orig_neigh_node, batman_ogm_packet);
+
+ /* update ranking if it is not a duplicate or has the same
+ * seqno and similar ttl as the non-duplicate */
+ if (is_bidirectional &&
+ (!is_duplicate ||
+ ((orig_node->last_real_seqno == batman_ogm_packet->seqno) &&
+ (orig_node->last_ttl - 3 <= batman_ogm_packet->ttl))))
+ bat_ogm_orig_update(bat_priv, orig_node, ethhdr,
+ batman_ogm_packet, if_incoming,
+ tt_buff, is_duplicate);
+
+ /* is single hop (direct) neighbor */
+ if (is_single_hop_neigh) {
+
+ /* mark direct link on incoming interface */
+ bat_ogm_forward(orig_node, ethhdr, batman_ogm_packet,
+ 1, if_incoming);
+
+ bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: "
+ "rebroadcast neighbor packet with direct link flag\n");
+ goto out_neigh;
+ }
+
+ /* multihop originator */
+ if (!is_bidirectional) {
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Drop packet: not received via bidirectional link\n");
+ goto out_neigh;
+ }
+
+ if (is_duplicate) {
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Drop packet: duplicate packet received\n");
+ goto out_neigh;
+ }
+
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Forwarding packet: rebroadcast originator packet\n");
+ bat_ogm_forward(orig_node, ethhdr, batman_ogm_packet, 0, if_incoming);
+
+out_neigh:
+ if ((orig_neigh_node) && (!is_single_hop_neigh))
+ orig_node_free_ref(orig_neigh_node);
+out:
+ if (router)
+ neigh_node_free_ref(router);
+ if (router_router)
+ neigh_node_free_ref(router_router);
+ if (orig_neigh_router)
+ neigh_node_free_ref(orig_neigh_router);
+
+ orig_node_free_ref(orig_node);
+}
+
+void bat_ogm_receive(const struct ethhdr *ethhdr, unsigned char *packet_buff,
+ int packet_len, struct hard_iface *if_incoming)
+{
+ struct batman_ogm_packet *batman_ogm_packet;
+ int buff_pos = 0;
+ unsigned char *tt_buff;
+
+ batman_ogm_packet = (struct batman_ogm_packet *)packet_buff;
+
+ /* unpack the aggregated packets and process them one by one */
+ do {
+ /* network to host order for our 32bit seqno and the
+ orig_interval */
+ batman_ogm_packet->seqno = ntohl(batman_ogm_packet->seqno);
+ batman_ogm_packet->tt_crc = ntohs(batman_ogm_packet->tt_crc);
+
+ tt_buff = packet_buff + buff_pos + BATMAN_OGM_LEN;
+
+ bat_ogm_process(ethhdr, batman_ogm_packet,
+ tt_buff, if_incoming);
+
+ buff_pos += BATMAN_OGM_LEN +
+ tt_len(batman_ogm_packet->tt_num_changes);
+
+ batman_ogm_packet = (struct batman_ogm_packet *)
+ (packet_buff + buff_pos);
+ } while (bat_ogm_aggr_packet(buff_pos, packet_len,
+ batman_ogm_packet->tt_num_changes));
+}
diff --git a/net/batman-adv/bat_ogm.h b/net/batman-adv/bat_ogm.h
new file mode 100644
index 000000000000..69329c107e28
--- /dev/null
+++ b/net/batman-adv/bat_ogm.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors:
+ *
+ * Marek Lindner, Simon Wunderlich
+ *
+ * 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-1301, USA
+ *
+ */
+
+#ifndef _NET_BATMAN_ADV_OGM_H_
+#define _NET_BATMAN_ADV_OGM_H_
+
+#include "main.h"
+
+void bat_ogm_init(struct hard_iface *hard_iface);
+void bat_ogm_init_primary(struct hard_iface *hard_iface);
+void bat_ogm_update_mac(struct hard_iface *hard_iface);
+void bat_ogm_schedule(struct hard_iface *hard_iface, int tt_num_changes);
+void bat_ogm_emit(struct forw_packet *forw_packet);
+void bat_ogm_receive(const struct ethhdr *ethhdr, unsigned char *packet_buff,
+ int packet_len, struct hard_iface *if_incoming);
+
+#endif /* _NET_BATMAN_ADV_OGM_H_ */
diff --git a/net/batman-adv/bat_sysfs.c b/net/batman-adv/bat_sysfs.c
index cd15deba60a1..b8a7414c3571 100644
--- a/net/batman-adv/bat_sysfs.c
+++ b/net/batman-adv/bat_sysfs.c
@@ -380,6 +380,7 @@ static ssize_t store_gw_bwidth(struct kobject *kobj, struct attribute *attr,
BAT_ATTR_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL);
BAT_ATTR_BOOL(bonding, S_IRUGO | S_IWUSR, NULL);
BAT_ATTR_BOOL(fragmentation, S_IRUGO | S_IWUSR, update_min_mtu);
+BAT_ATTR_BOOL(ap_isolation, S_IRUGO | S_IWUSR, NULL);
static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode);
static BAT_ATTR(gw_mode, S_IRUGO | S_IWUSR, show_gw_mode, store_gw_mode);
BAT_ATTR_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * JITTER, INT_MAX, NULL);
@@ -396,6 +397,7 @@ static struct bat_attribute *mesh_attrs[] = {
&bat_attr_aggregated_ogms,
&bat_attr_bonding,
&bat_attr_fragmentation,
+ &bat_attr_ap_isolation,
&bat_attr_vis_mode,
&bat_attr_gw_mode,
&bat_attr_orig_interval,
diff --git a/net/batman-adv/bitarray.c b/net/batman-adv/bitarray.c
index c1f4bfc09cc3..0be9ff346fa0 100644
--- a/net/batman-adv/bitarray.c
+++ b/net/batman-adv/bitarray.c
@@ -97,12 +97,12 @@ static void bit_shift(unsigned long *seq_bits, int32_t n)
(seq_bits[i - word_num - 1] >>
(WORD_BIT_SIZE-word_offset));
/* and the upper part of the right half and shift it left to
- * it's position */
+ * its position */
/* for our example that would be: word[0] = 9800 + 0076 =
* 9876 */
}
- /* now for our last word, i==word_num, we only have the it's "left"
- * half. that's the 1000 word in our example.*/
+ /* now for our last word, i==word_num, we only have its "left" half.
+ * that's the 1000 word in our example.*/
seq_bits[i] = (seq_bits[i - word_num] << word_offset);
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index 056180ef9e1a..619fb73b3b76 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -532,14 +532,14 @@ static bool is_type_dhcprequest(struct sk_buff *skb, int header_len)
pkt_len -= header_len + DHCP_OPTIONS_OFFSET + 1;
/* Access the dhcp option lists. Each entry is made up by:
- * - octect 1: option type
- * - octect 2: option data len (only if type != 255 and 0)
- * - octect 3: option data */
+ * - octet 1: option type
+ * - octet 2: option data len (only if type != 255 and 0)
+ * - octet 3: option data */
while (*p != 255 && !ret) {
- /* p now points to the first octect: option type */
+ /* p now points to the first octet: option type */
if (*p == 53) {
/* type 53 is the message type option.
- * Jump the len octect and go to the data octect */
+ * Jump the len octet and go to the data octet */
if (pkt_len < 2)
goto out;
p += 2;
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index db7aacf1e095..7704df468e0b 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -28,6 +28,7 @@
#include "bat_sysfs.h"
#include "originator.h"
#include "hash.h"
+#include "bat_ogm.h"
#include <linux/if_arp.h>
@@ -131,7 +132,6 @@ static void primary_if_select(struct bat_priv *bat_priv,
struct hard_iface *new_hard_iface)
{
struct hard_iface *curr_hard_iface;
- struct batman_packet *batman_packet;
ASSERT_RTNL();
@@ -147,10 +147,7 @@ static void primary_if_select(struct bat_priv *bat_priv,
if (!new_hard_iface)
return;
- batman_packet = (struct batman_packet *)(new_hard_iface->packet_buff);
- batman_packet->flags = PRIMARIES_FIRST_HOP;
- batman_packet->ttl = TTL;
-
+ bat_ogm_init_primary(new_hard_iface);
primary_if_update_addr(bat_priv);
}
@@ -162,14 +159,6 @@ static bool hardif_is_iface_up(const struct hard_iface *hard_iface)
return false;
}
-static void update_mac_addresses(struct hard_iface *hard_iface)
-{
- memcpy(((struct batman_packet *)(hard_iface->packet_buff))->orig,
- hard_iface->net_dev->dev_addr, ETH_ALEN);
- memcpy(((struct batman_packet *)(hard_iface->packet_buff))->prev_sender,
- hard_iface->net_dev->dev_addr, ETH_ALEN);
-}
-
static void check_known_mac_addr(const struct net_device *net_dev)
{
const struct hard_iface *hard_iface;
@@ -244,12 +233,12 @@ static void hardif_activate_interface(struct hard_iface *hard_iface)
bat_priv = netdev_priv(hard_iface->soft_iface);
- update_mac_addresses(hard_iface);
+ bat_ogm_update_mac(hard_iface);
hard_iface->if_status = IF_TO_BE_ACTIVATED;
/**
* the first active interface becomes our primary interface or
- * the next active interface after the old primay interface was removed
+ * the next active interface after the old primary interface was removed
*/
primary_if = primary_if_get_selected(bat_priv);
if (!primary_if)
@@ -283,7 +272,6 @@ int hardif_enable_interface(struct hard_iface *hard_iface,
const char *iface_name)
{
struct bat_priv *bat_priv;
- struct batman_packet *batman_packet;
struct net_device *soft_iface;
int ret;
@@ -318,8 +306,8 @@ int hardif_enable_interface(struct hard_iface *hard_iface,
hard_iface->soft_iface = soft_iface;
bat_priv = netdev_priv(hard_iface->soft_iface);
- hard_iface->packet_len = BAT_PACKET_LEN;
- hard_iface->packet_buff = kmalloc(hard_iface->packet_len, GFP_ATOMIC);
+
+ bat_ogm_init(hard_iface);
if (!hard_iface->packet_buff) {
bat_err(hard_iface->soft_iface, "Can't add interface packet "
@@ -328,15 +316,6 @@ int hardif_enable_interface(struct hard_iface *hard_iface,
goto err;
}
- batman_packet = (struct batman_packet *)(hard_iface->packet_buff);
- batman_packet->packet_type = BAT_PACKET;
- batman_packet->version = COMPAT_VERSION;
- batman_packet->flags = NO_FLAGS;
- batman_packet->ttl = 2;
- batman_packet->tq = TQ_MAX_VALUE;
- batman_packet->tt_num_changes = 0;
- batman_packet->ttvn = 0;
-
hard_iface->if_num = bat_priv->num_ifaces;
bat_priv->num_ifaces++;
hard_iface->if_status = IF_INACTIVE;
@@ -381,7 +360,7 @@ int hardif_enable_interface(struct hard_iface *hard_iface,
hard_iface->net_dev->name);
/* begin scheduling originator messages on that interface */
- schedule_own_packet(hard_iface);
+ schedule_bat_ogm(hard_iface);
out:
return 0;
@@ -455,11 +434,8 @@ static struct hard_iface *hardif_add_interface(struct net_device *net_dev)
dev_hold(net_dev);
hard_iface = kmalloc(sizeof(*hard_iface), GFP_ATOMIC);
- if (!hard_iface) {
- pr_err("Can't add interface (%s): out of memory\n",
- net_dev->name);
+ if (!hard_iface)
goto release_dev;
- }
ret = sysfs_add_hardif(&hard_iface->hardif_obj, net_dev);
if (ret)
@@ -551,7 +527,7 @@ static int hard_if_event(struct notifier_block *this,
goto hardif_put;
check_known_mac_addr(hard_iface->net_dev);
- update_mac_addresses(hard_iface);
+ bat_ogm_update_mac(hard_iface);
bat_priv = netdev_priv(hard_iface->soft_iface);
primary_if = primary_if_get_selected(bat_priv);
@@ -573,14 +549,14 @@ out:
return NOTIFY_DONE;
}
-/* receive a packet with the batman ethertype coming on a hard
+/* incoming packets with the batman ethertype received on any active hard
* interface */
static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *ptype,
struct net_device *orig_dev)
{
struct bat_priv *bat_priv;
- struct batman_packet *batman_packet;
+ struct batman_ogm_packet *batman_ogm_packet;
struct hard_iface *hard_iface;
int ret;
@@ -612,22 +588,22 @@ static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
if (hard_iface->if_status != IF_ACTIVE)
goto err_free;
- batman_packet = (struct batman_packet *)skb->data;
+ batman_ogm_packet = (struct batman_ogm_packet *)skb->data;
- if (batman_packet->version != COMPAT_VERSION) {
+ if (batman_ogm_packet->version != COMPAT_VERSION) {
bat_dbg(DBG_BATMAN, bat_priv,
"Drop packet: incompatible batman version (%i)\n",
- batman_packet->version);
+ batman_ogm_packet->version);
goto err_free;
}
/* all receive handlers return whether they received or reused
* the supplied skb. if not, we have to free the skb. */
- switch (batman_packet->packet_type) {
+ switch (batman_ogm_packet->packet_type) {
/* batman originator packet */
- case BAT_PACKET:
- ret = recv_bat_packet(skb, hard_iface);
+ case BAT_OGM:
+ ret = recv_bat_ogm_packet(skb, hard_iface);
break;
/* batman icmp packet */
@@ -681,6 +657,36 @@ err_out:
return NET_RX_DROP;
}
+/* This function returns true if the interface represented by ifindex is a
+ * 802.11 wireless device */
+bool is_wifi_iface(int ifindex)
+{
+ struct net_device *net_device = NULL;
+ bool ret = false;
+
+ if (ifindex == NULL_IFINDEX)
+ goto out;
+
+ net_device = dev_get_by_index(&init_net, ifindex);
+ if (!net_device)
+ goto out;
+
+#ifdef CONFIG_WIRELESS_EXT
+ /* pre-cfg80211 drivers have to implement WEXT, so it is possible to
+ * check for wireless_handlers != NULL */
+ if (net_device->wireless_handlers)
+ ret = true;
+ else
+#endif
+ /* cfg80211 drivers have to set ieee80211_ptr */
+ if (net_device->ieee80211_ptr)
+ ret = true;
+out:
+ if (net_device)
+ dev_put(net_device);
+ return ret;
+}
+
struct notifier_block hard_if_notifier = {
.notifier_call = hard_if_event,
};
diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h
index 442eacbc9e3a..67f78d1a63b4 100644
--- a/net/batman-adv/hard-interface.h
+++ b/net/batman-adv/hard-interface.h
@@ -42,6 +42,7 @@ void hardif_remove_interfaces(void);
int hardif_min_mtu(struct net_device *soft_iface);
void update_min_mtu(struct net_device *soft_iface);
void hardif_free_rcu(struct rcu_head *rcu);
+bool is_wifi_iface(int ifindex);
static inline void hardif_free_ref(struct hard_iface *hard_iface)
{
diff --git a/net/batman-adv/hash.h b/net/batman-adv/hash.h
index dd5c9fd7a905..d20aa71ba1e8 100644
--- a/net/batman-adv/hash.h
+++ b/net/batman-adv/hash.h
@@ -76,19 +76,30 @@ static inline void hash_delete(struct hashtable_t *hash,
hash_destroy(hash);
}
-/* adds data to the hashtable. returns 0 on success, -1 on error */
+/**
+ * hash_add - adds data to the hashtable
+ * @hash: storage hash table
+ * @compare: callback to determine if 2 hash elements are identical
+ * @choose: callback calculating the hash index
+ * @data: data passed to the aforementioned callbacks as argument
+ * @data_node: to be added element
+ *
+ * Returns 0 on success, 1 if the element already is in the hash
+ * and -1 on error.
+ */
+
static inline int hash_add(struct hashtable_t *hash,
hashdata_compare_cb compare,
hashdata_choose_cb choose,
const void *data, struct hlist_node *data_node)
{
- int index;
+ int index, ret = -1;
struct hlist_head *head;
struct hlist_node *node;
spinlock_t *list_lock; /* spinlock to protect write access */
if (!hash)
- goto err;
+ goto out;
index = choose(data, hash->size);
head = &hash->table[index];
@@ -99,6 +110,7 @@ static inline int hash_add(struct hashtable_t *hash,
if (!compare(node, data))
continue;
+ ret = 1;
goto err_unlock;
}
rcu_read_unlock();
@@ -108,12 +120,13 @@ static inline int hash_add(struct hashtable_t *hash,
hlist_add_head_rcu(data_node, head);
spin_unlock_bh(list_lock);
- return 0;
+ ret = 0;
+ goto out;
err_unlock:
rcu_read_unlock();
-err:
- return -1;
+out:
+ return ret;
}
/* removes data from hash, if found. returns pointer do data on success, so you
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index b0f9068ade57..fb87bdc2ce9b 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -107,7 +107,7 @@ int mesh_init(struct net_device *soft_iface)
if (tt_init(bat_priv) < 1)
goto err;
- tt_local_add(soft_iface, soft_iface->dev_addr);
+ tt_local_add(soft_iface, soft_iface->dev_addr, NULL_IFINDEX);
if (vis_init(bat_priv) < 1)
goto err;
@@ -117,8 +117,6 @@ int mesh_init(struct net_device *soft_iface)
goto end;
err:
- pr_err("Unable to allocate memory for mesh information structures: "
- "out of mem ?\n");
mesh_free(soft_iface);
return -1;
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index a6df61a6933b..964ad4d8ba33 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -28,7 +28,7 @@
#define DRIVER_DEVICE "batman-adv"
#ifndef SOURCE_VERSION
-#define SOURCE_VERSION "2011.3.0"
+#define SOURCE_VERSION "2011.4.0"
#endif
/* B.A.T.M.A.N. parameters */
@@ -44,7 +44,7 @@
#define PURGE_TIMEOUT 200
#define TT_LOCAL_TIMEOUT 3600 /* in seconds */
#define TT_CLIENT_ROAM_TIMEOUT 600
-/* sliding packet range of received originator messages in squence numbers
+/* sliding packet range of received originator messages in sequence numbers
* (should be a multiple of our word size) */
#define TQ_LOCAL_WINDOW_SIZE 64
#define TT_REQUEST_TIMEOUT 3 /* seconds we have to keep pending tt_req */
@@ -62,6 +62,8 @@
#define NO_FLAGS 0
+#define NULL_IFINDEX 0 /* dummy ifindex used to avoid iface checks */
+
#define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE)
#define LOG_BUF_LEN 8192 /* has to be a power of 2 */
@@ -133,7 +135,7 @@ enum dbg_level {
#include <linux/mutex.h> /* mutex */
#include <linux/module.h> /* needed by all modules */
#include <linux/netdevice.h> /* netdevice */
-#include <linux/etherdevice.h> /* ethernet address classifaction */
+#include <linux/etherdevice.h> /* ethernet address classification */
#include <linux/if_ether.h> /* ethernet header */
#include <linux/poll.h> /* poll_table */
#include <linux/kthread.h> /* kernel threads */
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index f3c3f620d195..0e5b77255d99 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -252,7 +252,7 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, const uint8_t *addr)
hash_added = hash_add(bat_priv->orig_hash, compare_orig,
choose_orig, orig_node, &orig_node->hash_entry);
- if (hash_added < 0)
+ if (hash_added != 0)
goto free_bcast_own_sum;
return orig_node;
@@ -336,8 +336,7 @@ static bool purge_orig_node(struct bat_priv *bat_priv,
} else {
if (purge_orig_neighbors(bat_priv, orig_node,
&best_neigh_node)) {
- update_routes(bat_priv, orig_node,
- best_neigh_node);
+ update_route(bat_priv, orig_node, best_neigh_node);
}
}
@@ -493,10 +492,8 @@ static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
data_ptr = kmalloc(max_if_num * sizeof(unsigned long) * NUM_WORDS,
GFP_ATOMIC);
- if (!data_ptr) {
- pr_err("Can't resize orig: out of memory\n");
+ if (!data_ptr)
return -1;
- }
memcpy(data_ptr, orig_node->bcast_own,
(max_if_num - 1) * sizeof(unsigned long) * NUM_WORDS);
@@ -504,10 +501,8 @@ static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
orig_node->bcast_own = data_ptr;
data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC);
- if (!data_ptr) {
- pr_err("Can't resize orig: out of memory\n");
+ if (!data_ptr)
return -1;
- }
memcpy(data_ptr, orig_node->bcast_own_sum,
(max_if_num - 1) * sizeof(uint8_t));
@@ -562,10 +557,8 @@ static int orig_node_del_if(struct orig_node *orig_node,
chunk_size = sizeof(unsigned long) * NUM_WORDS;
data_ptr = kmalloc(max_if_num * chunk_size, GFP_ATOMIC);
- if (!data_ptr) {
- pr_err("Can't resize orig: out of memory\n");
+ if (!data_ptr)
return -1;
- }
/* copy first part */
memcpy(data_ptr, orig_node->bcast_own, del_if_num * chunk_size);
@@ -583,10 +576,8 @@ free_bcast_own:
goto free_own_sum;
data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC);
- if (!data_ptr) {
- pr_err("Can't resize orig: out of memory\n");
+ if (!data_ptr)
return -1;
- }
memcpy(data_ptr, orig_node->bcast_own_sum,
del_if_num * sizeof(uint8_t));
diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h
index b76b4be10b92..4d9e54c57a36 100644
--- a/net/batman-adv/packet.h
+++ b/net/batman-adv/packet.h
@@ -25,14 +25,14 @@
#define ETH_P_BATMAN 0x4305 /* unofficial/not registered Ethertype */
enum bat_packettype {
- BAT_PACKET = 0x01,
- BAT_ICMP = 0x02,
- BAT_UNICAST = 0x03,
- BAT_BCAST = 0x04,
- BAT_VIS = 0x05,
+ BAT_OGM = 0x01,
+ BAT_ICMP = 0x02,
+ BAT_UNICAST = 0x03,
+ BAT_BCAST = 0x04,
+ BAT_VIS = 0x05,
BAT_UNICAST_FRAG = 0x06,
- BAT_TT_QUERY = 0x07,
- BAT_ROAM_ADV = 0x08
+ BAT_TT_QUERY = 0x07,
+ BAT_ROAM_ADV = 0x08
};
/* this file is included by batctl which needs these defines */
@@ -84,12 +84,13 @@ enum tt_query_flags {
enum tt_client_flags {
TT_CLIENT_DEL = 1 << 0,
TT_CLIENT_ROAM = 1 << 1,
+ TT_CLIENT_WIFI = 1 << 2,
TT_CLIENT_NOPURGE = 1 << 8,
TT_CLIENT_NEW = 1 << 9,
TT_CLIENT_PENDING = 1 << 10
};
-struct batman_packet {
+struct batman_ogm_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t ttl;
@@ -104,7 +105,7 @@ struct batman_packet {
uint16_t tt_crc;
} __packed;
-#define BAT_PACKET_LEN sizeof(struct batman_packet)
+#define BATMAN_OGM_LEN sizeof(struct batman_ogm_packet)
struct icmp_packet {
uint8_t packet_type;
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 0f32c818874d..f961cc5eade5 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -22,18 +22,14 @@
#include "main.h"
#include "routing.h"
#include "send.h"
-#include "hash.h"
#include "soft-interface.h"
#include "hard-interface.h"
#include "icmp_socket.h"
#include "translation-table.h"
#include "originator.h"
-#include "ring_buffer.h"
#include "vis.h"
-#include "aggregation.h"
-#include "gateway_common.h"
-#include "gateway_client.h"
#include "unicast.h"
+#include "bat_ogm.h"
void slide_own_bcast_window(struct hard_iface *hard_iface)
{
@@ -64,69 +60,9 @@ void slide_own_bcast_window(struct hard_iface *hard_iface)
}
}
-static void update_transtable(struct bat_priv *bat_priv,
- struct orig_node *orig_node,
- const unsigned char *tt_buff,
- uint8_t tt_num_changes, uint8_t ttvn,
- uint16_t tt_crc)
-{
- uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
- bool full_table = true;
-
- /* the ttvn increased by one -> we can apply the attached changes */
- if (ttvn - orig_ttvn == 1) {
- /* the OGM could not contain the changes because they were too
- * many to fit in one frame or because they have already been
- * sent TT_OGM_APPEND_MAX times. In this case send a tt
- * request */
- if (!tt_num_changes) {
- full_table = false;
- goto request_table;
- }
-
- tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn,
- (struct tt_change *)tt_buff);
-
- /* Even if we received the crc into the OGM, we prefer
- * to recompute it to spot any possible inconsistency
- * in the global table */
- orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
-
- /* The ttvn alone is not enough to guarantee consistency
- * because a single value could repesent different states
- * (due to the wrap around). Thus a node has to check whether
- * the resulting table (after applying the changes) is still
- * consistent or not. E.g. a node could disconnect while its
- * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case
- * checking the CRC value is mandatory to detect the
- * inconsistency */
- if (orig_node->tt_crc != tt_crc)
- goto request_table;
-
- /* Roaming phase is over: tables are in sync again. I can
- * unset the flag */
- orig_node->tt_poss_change = false;
- } else {
- /* if we missed more than one change or our tables are not
- * in sync anymore -> request fresh tt data */
- if (ttvn != orig_ttvn || orig_node->tt_crc != tt_crc) {
-request_table:
- bat_dbg(DBG_TT, bat_priv, "TT inconsistency for %pM. "
- "Need to retrieve the correct information "
- "(ttvn: %u last_ttvn: %u crc: %u last_crc: "
- "%u num_changes: %u)\n", orig_node->orig, ttvn,
- orig_ttvn, tt_crc, orig_node->tt_crc,
- tt_num_changes);
- send_tt_request(bat_priv, orig_node, ttvn, tt_crc,
- full_table);
- return;
- }
- }
-}
-
-static void update_route(struct bat_priv *bat_priv,
- struct orig_node *orig_node,
- struct neigh_node *neigh_node)
+static void _update_route(struct bat_priv *bat_priv,
+ struct orig_node *orig_node,
+ struct neigh_node *neigh_node)
{
struct neigh_node *curr_router;
@@ -170,8 +106,8 @@ static void update_route(struct bat_priv *bat_priv,
neigh_node_free_ref(curr_router);
}
-void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
- struct neigh_node *neigh_node)
+void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
+ struct neigh_node *neigh_node)
{
struct neigh_node *router = NULL;
@@ -181,116 +117,13 @@ void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
router = orig_node_get_router(orig_node);
if (router != neigh_node)
- update_route(bat_priv, orig_node, neigh_node);
+ _update_route(bat_priv, orig_node, neigh_node);
out:
if (router)
neigh_node_free_ref(router);
}
-static int is_bidirectional_neigh(struct orig_node *orig_node,
- struct orig_node *orig_neigh_node,
- struct batman_packet *batman_packet,
- struct hard_iface *if_incoming)
-{
- struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct neigh_node *neigh_node = NULL, *tmp_neigh_node;
- struct hlist_node *node;
- uint8_t total_count;
- uint8_t orig_eq_count, neigh_rq_count, tq_own;
- int tq_asym_penalty, ret = 0;
-
- /* find corresponding one hop neighbor */
- rcu_read_lock();
- hlist_for_each_entry_rcu(tmp_neigh_node, node,
- &orig_neigh_node->neigh_list, list) {
-
- if (!compare_eth(tmp_neigh_node->addr, orig_neigh_node->orig))
- continue;
-
- if (tmp_neigh_node->if_incoming != if_incoming)
- continue;
-
- if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
- continue;
-
- neigh_node = tmp_neigh_node;
- break;
- }
- rcu_read_unlock();
-
- if (!neigh_node)
- neigh_node = create_neighbor(orig_neigh_node,
- orig_neigh_node,
- orig_neigh_node->orig,
- if_incoming);
-
- if (!neigh_node)
- goto out;
-
- /* if orig_node is direct neighbour update neigh_node last_valid */
- if (orig_node == orig_neigh_node)
- neigh_node->last_valid = jiffies;
-
- orig_node->last_valid = jiffies;
-
- /* find packet count of corresponding one hop neighbor */
- spin_lock_bh(&orig_node->ogm_cnt_lock);
- orig_eq_count = orig_neigh_node->bcast_own_sum[if_incoming->if_num];
- neigh_rq_count = neigh_node->real_packet_count;
- spin_unlock_bh(&orig_node->ogm_cnt_lock);
-
- /* pay attention to not get a value bigger than 100 % */
- total_count = (orig_eq_count > neigh_rq_count ?
- neigh_rq_count : orig_eq_count);
-
- /* if we have too few packets (too less data) we set tq_own to zero */
- /* if we receive too few packets it is not considered bidirectional */
- if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) ||
- (neigh_rq_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM))
- tq_own = 0;
- else
- /* neigh_node->real_packet_count is never zero as we
- * only purge old information when getting new
- * information */
- tq_own = (TQ_MAX_VALUE * total_count) / neigh_rq_count;
-
- /*
- * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does
- * affect the nearly-symmetric links only a little, but
- * punishes asymmetric links more. This will give a value
- * between 0 and TQ_MAX_VALUE
- */
- tq_asym_penalty = TQ_MAX_VALUE - (TQ_MAX_VALUE *
- (TQ_LOCAL_WINDOW_SIZE - neigh_rq_count) *
- (TQ_LOCAL_WINDOW_SIZE - neigh_rq_count) *
- (TQ_LOCAL_WINDOW_SIZE - neigh_rq_count)) /
- (TQ_LOCAL_WINDOW_SIZE *
- TQ_LOCAL_WINDOW_SIZE *
- TQ_LOCAL_WINDOW_SIZE);
-
- batman_packet->tq = ((batman_packet->tq * tq_own * tq_asym_penalty) /
- (TQ_MAX_VALUE * TQ_MAX_VALUE));
-
- bat_dbg(DBG_BATMAN, bat_priv,
- "bidirectional: "
- "orig = %-15pM neigh = %-15pM => own_bcast = %2i, "
- "real recv = %2i, local tq: %3i, asym_penalty: %3i, "
- "total tq: %3i\n",
- orig_node->orig, orig_neigh_node->orig, total_count,
- neigh_rq_count, tq_own, tq_asym_penalty, batman_packet->tq);
-
- /* if link has the minimum required transmission quality
- * consider it bidirectional */
- if (batman_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT)
- ret = 1;
-
-out:
- if (neigh_node)
- neigh_node_free_ref(neigh_node);
- return ret;
-}
-
/* caller must hold the neigh_list_lock */
void bonding_candidate_del(struct orig_node *orig_node,
struct neigh_node *neigh_node)
@@ -308,8 +141,8 @@ out:
return;
}
-static void bonding_candidate_add(struct orig_node *orig_node,
- struct neigh_node *neigh_node)
+void bonding_candidate_add(struct orig_node *orig_node,
+ struct neigh_node *neigh_node)
{
struct hlist_node *node;
struct neigh_node *tmp_neigh_node, *router = NULL;
@@ -379,162 +212,23 @@ out:
}
/* copy primary address for bonding */
-static void bonding_save_primary(const struct orig_node *orig_node,
- struct orig_node *orig_neigh_node,
- const struct batman_packet *batman_packet)
+void bonding_save_primary(const struct orig_node *orig_node,
+ struct orig_node *orig_neigh_node,
+ const struct batman_ogm_packet *batman_ogm_packet)
{
- if (!(batman_packet->flags & PRIMARIES_FIRST_HOP))
+ if (!(batman_ogm_packet->flags & PRIMARIES_FIRST_HOP))
return;
memcpy(orig_neigh_node->primary_addr, orig_node->orig, ETH_ALEN);
}
-static void update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
- const struct ethhdr *ethhdr,
- const struct batman_packet *batman_packet,
- struct hard_iface *if_incoming,
- const unsigned char *tt_buff, int is_duplicate)
-{
- struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
- struct neigh_node *router = NULL;
- struct orig_node *orig_node_tmp;
- struct hlist_node *node;
- uint8_t bcast_own_sum_orig, bcast_own_sum_neigh;
-
- bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): "
- "Searching and updating originator entry of received packet\n");
-
- rcu_read_lock();
- hlist_for_each_entry_rcu(tmp_neigh_node, node,
- &orig_node->neigh_list, list) {
- if (compare_eth(tmp_neigh_node->addr, ethhdr->h_source) &&
- (tmp_neigh_node->if_incoming == if_incoming) &&
- atomic_inc_not_zero(&tmp_neigh_node->refcount)) {
- if (neigh_node)
- neigh_node_free_ref(neigh_node);
- neigh_node = tmp_neigh_node;
- continue;
- }
-
- if (is_duplicate)
- continue;
-
- spin_lock_bh(&tmp_neigh_node->tq_lock);
- ring_buffer_set(tmp_neigh_node->tq_recv,
- &tmp_neigh_node->tq_index, 0);
- tmp_neigh_node->tq_avg =
- ring_buffer_avg(tmp_neigh_node->tq_recv);
- spin_unlock_bh(&tmp_neigh_node->tq_lock);
- }
-
- if (!neigh_node) {
- struct orig_node *orig_tmp;
-
- orig_tmp = get_orig_node(bat_priv, ethhdr->h_source);
- if (!orig_tmp)
- goto unlock;
-
- neigh_node = create_neighbor(orig_node, orig_tmp,
- ethhdr->h_source, if_incoming);
-
- orig_node_free_ref(orig_tmp);
- if (!neigh_node)
- goto unlock;
- } else
- bat_dbg(DBG_BATMAN, bat_priv,
- "Updating existing last-hop neighbor of originator\n");
-
- rcu_read_unlock();
-
- orig_node->flags = batman_packet->flags;
- neigh_node->last_valid = jiffies;
-
- spin_lock_bh(&neigh_node->tq_lock);
- ring_buffer_set(neigh_node->tq_recv,
- &neigh_node->tq_index,
- batman_packet->tq);
- neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv);
- spin_unlock_bh(&neigh_node->tq_lock);
-
- if (!is_duplicate) {
- orig_node->last_ttl = batman_packet->ttl;
- neigh_node->last_ttl = batman_packet->ttl;
- }
-
- bonding_candidate_add(orig_node, neigh_node);
-
- /* if this neighbor already is our next hop there is nothing
- * to change */
- router = orig_node_get_router(orig_node);
- if (router == neigh_node)
- goto update_tt;
-
- /* if this neighbor does not offer a better TQ we won't consider it */
- if (router && (router->tq_avg > neigh_node->tq_avg))
- goto update_tt;
-
- /* if the TQ is the same and the link not more symetric we
- * won't consider it either */
- if (router && (neigh_node->tq_avg == router->tq_avg)) {
- orig_node_tmp = router->orig_node;
- spin_lock_bh(&orig_node_tmp->ogm_cnt_lock);
- bcast_own_sum_orig =
- orig_node_tmp->bcast_own_sum[if_incoming->if_num];
- spin_unlock_bh(&orig_node_tmp->ogm_cnt_lock);
-
- orig_node_tmp = neigh_node->orig_node;
- spin_lock_bh(&orig_node_tmp->ogm_cnt_lock);
- bcast_own_sum_neigh =
- orig_node_tmp->bcast_own_sum[if_incoming->if_num];
- spin_unlock_bh(&orig_node_tmp->ogm_cnt_lock);
-
- if (bcast_own_sum_orig >= bcast_own_sum_neigh)
- goto update_tt;
- }
-
- update_routes(bat_priv, orig_node, neigh_node);
-
-update_tt:
- /* I have to check for transtable changes only if the OGM has been
- * sent through a primary interface */
- if (((batman_packet->orig != ethhdr->h_source) &&
- (batman_packet->ttl > 2)) ||
- (batman_packet->flags & PRIMARIES_FIRST_HOP))
- update_transtable(bat_priv, orig_node, tt_buff,
- batman_packet->tt_num_changes,
- batman_packet->ttvn,
- batman_packet->tt_crc);
-
- if (orig_node->gw_flags != batman_packet->gw_flags)
- gw_node_update(bat_priv, orig_node, batman_packet->gw_flags);
-
- orig_node->gw_flags = batman_packet->gw_flags;
-
- /* restart gateway selection if fast or late switching was enabled */
- if ((orig_node->gw_flags) &&
- (atomic_read(&bat_priv->gw_mode) == GW_MODE_CLIENT) &&
- (atomic_read(&bat_priv->gw_sel_class) > 2))
- gw_check_election(bat_priv, orig_node);
-
- goto out;
-
-unlock:
- rcu_read_unlock();
-out:
- if (neigh_node)
- neigh_node_free_ref(neigh_node);
- if (router)
- neigh_node_free_ref(router);
-}
-
/* checks whether the host restarted and is in the protection time.
* returns:
* 0 if the packet is to be accepted
* 1 if the packet is to be ignored.
*/
-static int window_protected(struct bat_priv *bat_priv,
- int32_t seq_num_diff,
- unsigned long *last_reset)
+int window_protected(struct bat_priv *bat_priv, int32_t seq_num_diff,
+ unsigned long *last_reset)
{
if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE)
|| (seq_num_diff >= EXPECTED_SEQNO_RANGE)) {
@@ -552,330 +246,12 @@ static int window_protected(struct bat_priv *bat_priv,
return 0;
}
-/* processes a batman packet for all interfaces, adjusts the sequence number and
- * finds out whether it is a duplicate.
- * returns:
- * 1 the packet is a duplicate
- * 0 the packet has not yet been received
- * -1 the packet is old and has been received while the seqno window
- * was protected. Caller should drop it.
- */
-static int count_real_packets(const struct ethhdr *ethhdr,
- const struct batman_packet *batman_packet,
- const struct hard_iface *if_incoming)
-{
- struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct orig_node *orig_node;
- struct neigh_node *tmp_neigh_node;
- struct hlist_node *node;
- int is_duplicate = 0;
- int32_t seq_diff;
- int need_update = 0;
- int set_mark, ret = -1;
-
- orig_node = get_orig_node(bat_priv, batman_packet->orig);
- if (!orig_node)
- return 0;
-
- spin_lock_bh(&orig_node->ogm_cnt_lock);
- seq_diff = batman_packet->seqno - orig_node->last_real_seqno;
-
- /* signalize caller that the packet is to be dropped. */
- if (window_protected(bat_priv, seq_diff,
- &orig_node->batman_seqno_reset))
- goto out;
-
- rcu_read_lock();
- hlist_for_each_entry_rcu(tmp_neigh_node, node,
- &orig_node->neigh_list, list) {
-
- is_duplicate |= get_bit_status(tmp_neigh_node->real_bits,
- orig_node->last_real_seqno,
- batman_packet->seqno);
-
- if (compare_eth(tmp_neigh_node->addr, ethhdr->h_source) &&
- (tmp_neigh_node->if_incoming == if_incoming))
- set_mark = 1;
- else
- set_mark = 0;
-
- /* if the window moved, set the update flag. */
- need_update |= bit_get_packet(bat_priv,
- tmp_neigh_node->real_bits,
- seq_diff, set_mark);
-
- tmp_neigh_node->real_packet_count =
- bit_packet_count(tmp_neigh_node->real_bits);
- }
- rcu_read_unlock();
-
- if (need_update) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "updating last_seqno: old %d, new %d\n",
- orig_node->last_real_seqno, batman_packet->seqno);
- orig_node->last_real_seqno = batman_packet->seqno;
- }
-
- ret = is_duplicate;
-
-out:
- spin_unlock_bh(&orig_node->ogm_cnt_lock);
- orig_node_free_ref(orig_node);
- return ret;
-}
-
-void receive_bat_packet(const struct ethhdr *ethhdr,
- struct batman_packet *batman_packet,
- const unsigned char *tt_buff,
- struct hard_iface *if_incoming)
-{
- struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct hard_iface *hard_iface;
- struct orig_node *orig_neigh_node, *orig_node;
- struct neigh_node *router = NULL, *router_router = NULL;
- struct neigh_node *orig_neigh_router = NULL;
- int has_directlink_flag;
- int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
- int is_broadcast = 0, is_bidirectional, is_single_hop_neigh;
- int is_duplicate;
- uint32_t if_incoming_seqno;
-
- /* Silently drop when the batman packet is actually not a
- * correct packet.
- *
- * This might happen if a packet is padded (e.g. Ethernet has a
- * minimum frame length of 64 byte) and the aggregation interprets
- * it as an additional length.
- *
- * TODO: A more sane solution would be to have a bit in the
- * batman_packet to detect whether the packet is the last
- * packet in an aggregation. Here we expect that the padding
- * is always zero (or not 0x01)
- */
- if (batman_packet->packet_type != BAT_PACKET)
- return;
-
- /* could be changed by schedule_own_packet() */
- if_incoming_seqno = atomic_read(&if_incoming->seqno);
-
- has_directlink_flag = (batman_packet->flags & DIRECTLINK ? 1 : 0);
-
- is_single_hop_neigh = (compare_eth(ethhdr->h_source,
- batman_packet->orig) ? 1 : 0);
-
- bat_dbg(DBG_BATMAN, bat_priv,
- "Received BATMAN packet via NB: %pM, IF: %s [%pM] "
- "(from OG: %pM, via prev OG: %pM, seqno %d, ttvn %u, "
- "crc %u, changes %u, td %d, TTL %d, V %d, IDF %d)\n",
- ethhdr->h_source, if_incoming->net_dev->name,
- if_incoming->net_dev->dev_addr, batman_packet->orig,
- batman_packet->prev_sender, batman_packet->seqno,
- batman_packet->ttvn, batman_packet->tt_crc,
- batman_packet->tt_num_changes, batman_packet->tq,
- batman_packet->ttl, batman_packet->version,
- has_directlink_flag);
-
- rcu_read_lock();
- list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
- if (hard_iface->if_status != IF_ACTIVE)
- continue;
-
- if (hard_iface->soft_iface != if_incoming->soft_iface)
- continue;
-
- if (compare_eth(ethhdr->h_source,
- hard_iface->net_dev->dev_addr))
- is_my_addr = 1;
-
- if (compare_eth(batman_packet->orig,
- hard_iface->net_dev->dev_addr))
- is_my_orig = 1;
-
- if (compare_eth(batman_packet->prev_sender,
- hard_iface->net_dev->dev_addr))
- is_my_oldorig = 1;
-
- if (is_broadcast_ether_addr(ethhdr->h_source))
- is_broadcast = 1;
- }
- rcu_read_unlock();
-
- if (batman_packet->version != COMPAT_VERSION) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: incompatible batman version (%i)\n",
- batman_packet->version);
- return;
- }
-
- if (is_my_addr) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: received my own broadcast (sender: %pM"
- ")\n",
- ethhdr->h_source);
- return;
- }
-
- if (is_broadcast) {
- bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
- "ignoring all packets with broadcast source addr (sender: %pM"
- ")\n", ethhdr->h_source);
- return;
- }
-
- if (is_my_orig) {
- unsigned long *word;
- int offset;
-
- orig_neigh_node = get_orig_node(bat_priv, ethhdr->h_source);
- if (!orig_neigh_node)
- return;
-
- /* neighbor has to indicate direct link and it has to
- * come via the corresponding interface */
- /* save packet seqno for bidirectional check */
- if (has_directlink_flag &&
- compare_eth(if_incoming->net_dev->dev_addr,
- batman_packet->orig)) {
- offset = if_incoming->if_num * NUM_WORDS;
-
- spin_lock_bh(&orig_neigh_node->ogm_cnt_lock);
- word = &(orig_neigh_node->bcast_own[offset]);
- bit_mark(word,
- if_incoming_seqno - batman_packet->seqno - 2);
- orig_neigh_node->bcast_own_sum[if_incoming->if_num] =
- bit_packet_count(word);
- spin_unlock_bh(&orig_neigh_node->ogm_cnt_lock);
- }
-
- bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
- "originator packet from myself (via neighbor)\n");
- orig_node_free_ref(orig_neigh_node);
- return;
- }
-
- if (is_my_oldorig) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: ignoring all rebroadcast echos (sender: "
- "%pM)\n", ethhdr->h_source);
- return;
- }
-
- orig_node = get_orig_node(bat_priv, batman_packet->orig);
- if (!orig_node)
- return;
-
- is_duplicate = count_real_packets(ethhdr, batman_packet, if_incoming);
-
- if (is_duplicate == -1) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: packet within seqno protection time "
- "(sender: %pM)\n", ethhdr->h_source);
- goto out;
- }
-
- if (batman_packet->tq == 0) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: originator packet with tq equal 0\n");
- goto out;
- }
-
- router = orig_node_get_router(orig_node);
- if (router)
- router_router = orig_node_get_router(router->orig_node);
-
- /* avoid temporary routing loops */
- if (router && router_router &&
- (compare_eth(router->addr, batman_packet->prev_sender)) &&
- !(compare_eth(batman_packet->orig, batman_packet->prev_sender)) &&
- (compare_eth(router->addr, router_router->addr))) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: ignoring all rebroadcast packets that "
- "may make me loop (sender: %pM)\n", ethhdr->h_source);
- goto out;
- }
-
- /* if sender is a direct neighbor the sender mac equals
- * originator mac */
- orig_neigh_node = (is_single_hop_neigh ?
- orig_node :
- get_orig_node(bat_priv, ethhdr->h_source));
- if (!orig_neigh_node)
- goto out;
-
- orig_neigh_router = orig_node_get_router(orig_neigh_node);
-
- /* drop packet if sender is not a direct neighbor and if we
- * don't route towards it */
- if (!is_single_hop_neigh && (!orig_neigh_router)) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: OGM via unknown neighbor!\n");
- goto out_neigh;
- }
-
- is_bidirectional = is_bidirectional_neigh(orig_node, orig_neigh_node,
- batman_packet, if_incoming);
-
- bonding_save_primary(orig_node, orig_neigh_node, batman_packet);
-
- /* update ranking if it is not a duplicate or has the same
- * seqno and similar ttl as the non-duplicate */
- if (is_bidirectional &&
- (!is_duplicate ||
- ((orig_node->last_real_seqno == batman_packet->seqno) &&
- (orig_node->last_ttl - 3 <= batman_packet->ttl))))
- update_orig(bat_priv, orig_node, ethhdr, batman_packet,
- if_incoming, tt_buff, is_duplicate);
-
- /* is single hop (direct) neighbor */
- if (is_single_hop_neigh) {
-
- /* mark direct link on incoming interface */
- schedule_forward_packet(orig_node, ethhdr, batman_packet,
- 1, if_incoming);
-
- bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: "
- "rebroadcast neighbor packet with direct link flag\n");
- goto out_neigh;
- }
-
- /* multihop originator */
- if (!is_bidirectional) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: not received via bidirectional link\n");
- goto out_neigh;
- }
-
- if (is_duplicate) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: duplicate packet received\n");
- goto out_neigh;
- }
-
- bat_dbg(DBG_BATMAN, bat_priv,
- "Forwarding packet: rebroadcast originator packet\n");
- schedule_forward_packet(orig_node, ethhdr, batman_packet,
- 0, if_incoming);
-
-out_neigh:
- if ((orig_neigh_node) && (!is_single_hop_neigh))
- orig_node_free_ref(orig_neigh_node);
-out:
- if (router)
- neigh_node_free_ref(router);
- if (router_router)
- neigh_node_free_ref(router_router);
- if (orig_neigh_router)
- neigh_node_free_ref(orig_neigh_router);
-
- orig_node_free_ref(orig_node);
-}
-
-int recv_bat_packet(struct sk_buff *skb, struct hard_iface *hard_iface)
+int recv_bat_ogm_packet(struct sk_buff *skb, struct hard_iface *hard_iface)
{
struct ethhdr *ethhdr;
/* drop packet if it has not necessary minimum size */
- if (unlikely(!pskb_may_pull(skb, sizeof(struct batman_packet))))
+ if (unlikely(!pskb_may_pull(skb, BATMAN_OGM_LEN)))
return NET_RX_DROP;
ethhdr = (struct ethhdr *)skb_mac_header(skb);
@@ -898,10 +274,7 @@ int recv_bat_packet(struct sk_buff *skb, struct hard_iface *hard_iface)
ethhdr = (struct ethhdr *)skb_mac_header(skb);
- receive_aggr_bat_packet(ethhdr,
- skb->data,
- skb_headlen(skb),
- hard_iface);
+ bat_ogm_receive(ethhdr, skb->data, skb_headlen(skb), hard_iface);
kfree_skb(skb);
return NET_RX_SUCCESS;
@@ -1243,7 +616,7 @@ int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if)
}
break;
case TT_RESPONSE:
- /* packet needs to be linearised to access the TT changes */
+ /* packet needs to be linearized to access the TT changes */
if (skb_linearize(skb) < 0)
goto out;
@@ -1300,7 +673,7 @@ int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if)
roam_adv_packet->client);
tt_global_add(bat_priv, orig_node, roam_adv_packet->client,
- atomic_read(&orig_node->last_ttvn) + 1, true);
+ atomic_read(&orig_node->last_ttvn) + 1, true, false);
/* Roaming phase starts: I have new information but the ttvn has not
* been incremented yet. This flag will make me check all the incoming
@@ -1536,7 +909,7 @@ static int check_unicast_ttvn(struct bat_priv *bat_priv,
ethhdr = (struct ethhdr *)(skb->data +
sizeof(struct unicast_packet));
- orig_node = transtable_search(bat_priv, ethhdr->h_dest);
+ orig_node = transtable_search(bat_priv, NULL, ethhdr->h_dest);
if (!orig_node) {
if (!is_my_client(bat_priv, ethhdr->h_dest))
diff --git a/net/batman-adv/routing.h b/net/batman-adv/routing.h
index fb14e9579b19..7aaee0fb0fdc 100644
--- a/net/batman-adv/routing.h
+++ b/net/batman-adv/routing.h
@@ -23,19 +23,15 @@
#define _NET_BATMAN_ADV_ROUTING_H_
void slide_own_bcast_window(struct hard_iface *hard_iface);
-void receive_bat_packet(const struct ethhdr *ethhdr,
- struct batman_packet *batman_packet,
- const unsigned char *tt_buff,
- struct hard_iface *if_incoming);
-void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
- struct neigh_node *neigh_node);
+void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
+ struct neigh_node *neigh_node);
int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_vis_packet(struct sk_buff *skb, struct hard_iface *recv_if);
-int recv_bat_packet(struct sk_buff *skb, struct hard_iface *recv_if);
+int recv_bat_ogm_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if);
struct neigh_node *find_router(struct bat_priv *bat_priv,
@@ -43,5 +39,12 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
const struct hard_iface *recv_if);
void bonding_candidate_del(struct orig_node *orig_node,
struct neigh_node *neigh_node);
+void bonding_candidate_add(struct orig_node *orig_node,
+ struct neigh_node *neigh_node);
+void bonding_save_primary(const struct orig_node *orig_node,
+ struct orig_node *orig_neigh_node,
+ const struct batman_ogm_packet *batman_ogm_packet);
+int window_protected(struct bat_priv *bat_priv, int32_t seq_num_diff,
+ unsigned long *last_reset);
#endif /* _NET_BATMAN_ADV_ROUTING_H_ */
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index 58d14472068c..8a684eb738ad 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -26,33 +26,12 @@
#include "soft-interface.h"
#include "hard-interface.h"
#include "vis.h"
-#include "aggregation.h"
#include "gateway_common.h"
#include "originator.h"
+#include "bat_ogm.h"
static void send_outstanding_bcast_packet(struct work_struct *work);
-/* apply hop penalty for a normal link */
-static uint8_t hop_penalty(uint8_t tq, const struct bat_priv *bat_priv)
-{
- int hop_penalty = atomic_read(&bat_priv->hop_penalty);
- return (tq * (TQ_MAX_VALUE - hop_penalty)) / (TQ_MAX_VALUE);
-}
-
-/* when do we schedule our own packet to be sent */
-static unsigned long own_send_time(const struct bat_priv *bat_priv)
-{
- return jiffies + msecs_to_jiffies(
- atomic_read(&bat_priv->orig_interval) -
- JITTER + (random32() % 2*JITTER));
-}
-
-/* when do we schedule a forwarded packet to be sent */
-static unsigned long forward_send_time(void)
-{
- return jiffies + msecs_to_jiffies(random32() % (JITTER/2));
-}
-
/* send out an already prepared packet to the given address via the
* specified batman interface */
int send_skb_packet(struct sk_buff *skb, struct hard_iface *hard_iface,
@@ -99,141 +78,17 @@ send_skb_err:
return NET_XMIT_DROP;
}
-/* Send a packet to a given interface */
-static void send_packet_to_if(struct forw_packet *forw_packet,
- struct hard_iface *hard_iface)
-{
- struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
- char *fwd_str;
- uint8_t packet_num;
- int16_t buff_pos;
- struct batman_packet *batman_packet;
- struct sk_buff *skb;
-
- if (hard_iface->if_status != IF_ACTIVE)
- return;
-
- packet_num = 0;
- buff_pos = 0;
- batman_packet = (struct batman_packet *)forw_packet->skb->data;
-
- /* adjust all flags and log packets */
- while (aggregated_packet(buff_pos,
- forw_packet->packet_len,
- batman_packet->tt_num_changes)) {
-
- /* we might have aggregated direct link packets with an
- * ordinary base packet */
- if ((forw_packet->direct_link_flags & (1 << packet_num)) &&
- (forw_packet->if_incoming == hard_iface))
- batman_packet->flags |= DIRECTLINK;
- else
- batman_packet->flags &= ~DIRECTLINK;
-
- fwd_str = (packet_num > 0 ? "Forwarding" : (forw_packet->own ?
- "Sending own" :
- "Forwarding"));
- bat_dbg(DBG_BATMAN, bat_priv,
- "%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d,"
- " IDF %s, hvn %d) on interface %s [%pM]\n",
- fwd_str, (packet_num > 0 ? "aggregated " : ""),
- batman_packet->orig, ntohl(batman_packet->seqno),
- batman_packet->tq, batman_packet->ttl,
- (batman_packet->flags & DIRECTLINK ?
- "on" : "off"),
- batman_packet->ttvn, hard_iface->net_dev->name,
- hard_iface->net_dev->dev_addr);
-
- buff_pos += sizeof(*batman_packet) +
- tt_len(batman_packet->tt_num_changes);
- packet_num++;
- batman_packet = (struct batman_packet *)
- (forw_packet->skb->data + buff_pos);
- }
-
- /* create clone because function is called more than once */
- skb = skb_clone(forw_packet->skb, GFP_ATOMIC);
- if (skb)
- send_skb_packet(skb, hard_iface, broadcast_addr);
-}
-
-/* send a batman packet */
-static void send_packet(struct forw_packet *forw_packet)
-{
- struct hard_iface *hard_iface;
- struct net_device *soft_iface;
- struct bat_priv *bat_priv;
- struct hard_iface *primary_if = NULL;
- struct batman_packet *batman_packet =
- (struct batman_packet *)(forw_packet->skb->data);
- int directlink = (batman_packet->flags & DIRECTLINK ? 1 : 0);
-
- if (!forw_packet->if_incoming) {
- pr_err("Error - can't forward packet: incoming iface not "
- "specified\n");
- goto out;
- }
-
- soft_iface = forw_packet->if_incoming->soft_iface;
- bat_priv = netdev_priv(soft_iface);
-
- if (forw_packet->if_incoming->if_status != IF_ACTIVE)
- goto out;
-
- primary_if = primary_if_get_selected(bat_priv);
- if (!primary_if)
- goto out;
-
- /* multihomed peer assumed */
- /* non-primary OGMs are only broadcasted on their interface */
- if ((directlink && (batman_packet->ttl == 1)) ||
- (forw_packet->own && (forw_packet->if_incoming != primary_if))) {
-
- /* FIXME: what about aggregated packets ? */
- bat_dbg(DBG_BATMAN, bat_priv,
- "%s packet (originator %pM, seqno %d, TTL %d) "
- "on interface %s [%pM]\n",
- (forw_packet->own ? "Sending own" : "Forwarding"),
- batman_packet->orig, ntohl(batman_packet->seqno),
- batman_packet->ttl,
- forw_packet->if_incoming->net_dev->name,
- forw_packet->if_incoming->net_dev->dev_addr);
-
- /* skb is only used once and than forw_packet is free'd */
- send_skb_packet(forw_packet->skb, forw_packet->if_incoming,
- broadcast_addr);
- forw_packet->skb = NULL;
-
- goto out;
- }
-
- /* broadcast on every interface */
- rcu_read_lock();
- list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
- if (hard_iface->soft_iface != soft_iface)
- continue;
-
- send_packet_to_if(forw_packet, hard_iface);
- }
- rcu_read_unlock();
-
-out:
- if (primary_if)
- hardif_free_ref(primary_if);
-}
-
static void realloc_packet_buffer(struct hard_iface *hard_iface,
- int new_len)
+ int new_len)
{
unsigned char *new_buff;
- struct batman_packet *batman_packet;
new_buff = kmalloc(new_len, GFP_ATOMIC);
/* keep old buffer if kmalloc should fail */
if (new_buff) {
memcpy(new_buff, hard_iface->packet_buff,
- sizeof(*batman_packet));
+ BATMAN_OGM_LEN);
kfree(hard_iface->packet_buff);
hard_iface->packet_buff = new_buff;
@@ -242,60 +97,48 @@ static void realloc_packet_buffer(struct hard_iface *hard_iface,
}
/* when calling this function (hard_iface == primary_if) has to be true */
-static void prepare_packet_buffer(struct bat_priv *bat_priv,
+static int prepare_packet_buffer(struct bat_priv *bat_priv,
struct hard_iface *hard_iface)
{
int new_len;
- struct batman_packet *batman_packet;
- new_len = BAT_PACKET_LEN +
+ new_len = BATMAN_OGM_LEN +
tt_len((uint8_t)atomic_read(&bat_priv->tt_local_changes));
/* if we have too many changes for one packet don't send any
* and wait for the tt table request which will be fragmented */
if (new_len > hard_iface->soft_iface->mtu)
- new_len = BAT_PACKET_LEN;
+ new_len = BATMAN_OGM_LEN;
realloc_packet_buffer(hard_iface, new_len);
- batman_packet = (struct batman_packet *)hard_iface->packet_buff;
atomic_set(&bat_priv->tt_crc, tt_local_crc(bat_priv));
/* reset the sending counter */
atomic_set(&bat_priv->tt_ogm_append_cnt, TT_OGM_APPEND_MAX);
- batman_packet->tt_num_changes = tt_changes_fill_buffer(bat_priv,
- hard_iface->packet_buff + BAT_PACKET_LEN,
- hard_iface->packet_len - BAT_PACKET_LEN);
-
+ return tt_changes_fill_buffer(bat_priv,
+ hard_iface->packet_buff + BATMAN_OGM_LEN,
+ hard_iface->packet_len - BATMAN_OGM_LEN);
}
-static void reset_packet_buffer(struct bat_priv *bat_priv,
- struct hard_iface *hard_iface)
+static int reset_packet_buffer(struct bat_priv *bat_priv,
+ struct hard_iface *hard_iface)
{
- struct batman_packet *batman_packet;
-
- realloc_packet_buffer(hard_iface, BAT_PACKET_LEN);
-
- batman_packet = (struct batman_packet *)hard_iface->packet_buff;
- batman_packet->tt_num_changes = 0;
+ realloc_packet_buffer(hard_iface, BATMAN_OGM_LEN);
+ return 0;
}
-void schedule_own_packet(struct hard_iface *hard_iface)
+void schedule_bat_ogm(struct hard_iface *hard_iface)
{
struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
struct hard_iface *primary_if;
- unsigned long send_time;
- struct batman_packet *batman_packet;
- int vis_server;
+ int tt_num_changes = -1;
if ((hard_iface->if_status == IF_NOT_IN_USE) ||
(hard_iface->if_status == IF_TO_BE_REMOVED))
return;
- vis_server = atomic_read(&bat_priv->vis_mode);
- primary_if = primary_if_get_selected(bat_priv);
-
/**
* the interface gets activated here to avoid race conditions between
* the moment of activating the interface in
@@ -306,124 +149,26 @@ void schedule_own_packet(struct hard_iface *hard_iface)
if (hard_iface->if_status == IF_TO_BE_ACTIVATED)
hard_iface->if_status = IF_ACTIVE;
+ primary_if = primary_if_get_selected(bat_priv);
+
if (hard_iface == primary_if) {
/* if at least one change happened */
if (atomic_read(&bat_priv->tt_local_changes) > 0) {
tt_commit_changes(bat_priv);
- prepare_packet_buffer(bat_priv, hard_iface);
+ tt_num_changes = prepare_packet_buffer(bat_priv,
+ hard_iface);
}
- /* if the changes have been sent enough times */
+ /* if the changes have been sent often enough */
if (!atomic_dec_not_zero(&bat_priv->tt_ogm_append_cnt))
- reset_packet_buffer(bat_priv, hard_iface);
+ tt_num_changes = reset_packet_buffer(bat_priv,
+ hard_iface);
}
- /**
- * NOTE: packet_buff might just have been re-allocated in
- * prepare_packet_buffer() or in reset_packet_buffer()
- */
- batman_packet = (struct batman_packet *)hard_iface->packet_buff;
-
- /* change sequence number to network order */
- batman_packet->seqno =
- htonl((uint32_t)atomic_read(&hard_iface->seqno));
-
- batman_packet->ttvn = atomic_read(&bat_priv->ttvn);
- batman_packet->tt_crc = htons((uint16_t)atomic_read(&bat_priv->tt_crc));
-
- if (vis_server == VIS_TYPE_SERVER_SYNC)
- batman_packet->flags |= VIS_SERVER;
- else
- batman_packet->flags &= ~VIS_SERVER;
-
- if ((hard_iface == primary_if) &&
- (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER))
- batman_packet->gw_flags =
- (uint8_t)atomic_read(&bat_priv->gw_bandwidth);
- else
- batman_packet->gw_flags = NO_FLAGS;
-
- atomic_inc(&hard_iface->seqno);
-
- slide_own_bcast_window(hard_iface);
- send_time = own_send_time(bat_priv);
- add_bat_packet_to_list(bat_priv,
- hard_iface->packet_buff,
- hard_iface->packet_len,
- hard_iface, 1, send_time);
-
if (primary_if)
hardif_free_ref(primary_if);
-}
-
-void schedule_forward_packet(struct orig_node *orig_node,
- const struct ethhdr *ethhdr,
- struct batman_packet *batman_packet,
- int directlink,
- struct hard_iface *if_incoming)
-{
- struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct neigh_node *router;
- uint8_t in_tq, in_ttl, tq_avg = 0;
- unsigned long send_time;
- uint8_t tt_num_changes;
-
- if (batman_packet->ttl <= 1) {
- bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n");
- return;
- }
-
- router = orig_node_get_router(orig_node);
-
- in_tq = batman_packet->tq;
- in_ttl = batman_packet->ttl;
- tt_num_changes = batman_packet->tt_num_changes;
-
- batman_packet->ttl--;
- memcpy(batman_packet->prev_sender, ethhdr->h_source, ETH_ALEN);
-
- /* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast
- * of our best tq value */
- if (router && router->tq_avg != 0) {
-
- /* rebroadcast ogm of best ranking neighbor as is */
- if (!compare_eth(router->addr, ethhdr->h_source)) {
- batman_packet->tq = router->tq_avg;
-
- if (router->last_ttl)
- batman_packet->ttl = router->last_ttl - 1;
- }
-
- tq_avg = router->tq_avg;
- }
-
- if (router)
- neigh_node_free_ref(router);
-
- /* apply hop penalty */
- batman_packet->tq = hop_penalty(batman_packet->tq, bat_priv);
-
- bat_dbg(DBG_BATMAN, bat_priv,
- "Forwarding packet: tq_orig: %i, tq_avg: %i, "
- "tq_forw: %i, ttl_orig: %i, ttl_forw: %i\n",
- in_tq, tq_avg, batman_packet->tq, in_ttl - 1,
- batman_packet->ttl);
-
- batman_packet->seqno = htonl(batman_packet->seqno);
- batman_packet->tt_crc = htons(batman_packet->tt_crc);
-
- /* switch of primaries first hop flag when forwarding */
- batman_packet->flags &= ~PRIMARIES_FIRST_HOP;
- if (directlink)
- batman_packet->flags |= DIRECTLINK;
- else
- batman_packet->flags &= ~DIRECTLINK;
- send_time = forward_send_time();
- add_bat_packet_to_list(bat_priv,
- (unsigned char *)batman_packet,
- sizeof(*batman_packet) + tt_len(tt_num_changes),
- if_incoming, 0, send_time);
+ bat_ogm_schedule(hard_iface, tt_num_changes);
}
static void forw_packet_free(struct forw_packet *forw_packet)
@@ -454,7 +199,7 @@ static void _add_bcast_packet_to_list(struct bat_priv *bat_priv,
}
/* add a broadcast packet to the queue and setup timers. broadcast packets
- * are sent multiple times to increase probability for beeing received.
+ * are sent multiple times to increase probability for being received.
*
* This function returns NETDEV_TX_OK on success and NETDEV_TX_BUSY on
* errors.
@@ -557,7 +302,7 @@ out:
atomic_inc(&bat_priv->bcast_queue_left);
}
-void send_outstanding_bat_packet(struct work_struct *work)
+void send_outstanding_bat_ogm_packet(struct work_struct *work)
{
struct delayed_work *delayed_work =
container_of(work, struct delayed_work, work);
@@ -573,7 +318,7 @@ void send_outstanding_bat_packet(struct work_struct *work)
if (atomic_read(&bat_priv->mesh_state) == MESH_DEACTIVATING)
goto out;
- send_packet(forw_packet);
+ bat_ogm_emit(forw_packet);
/**
* we have to have at least one packet in the queue
@@ -581,7 +326,7 @@ void send_outstanding_bat_packet(struct work_struct *work)
* shutting down
*/
if (forw_packet->own)
- schedule_own_packet(forw_packet->if_incoming);
+ schedule_bat_ogm(forw_packet->if_incoming);
out:
/* don't count own packet */
@@ -612,7 +357,7 @@ void purge_outstanding_packets(struct bat_priv *bat_priv,
&bat_priv->forw_bcast_list, list) {
/**
- * if purge_outstanding_packets() was called with an argmument
+ * if purge_outstanding_packets() was called with an argument
* we delete only packets belonging to the given interface
*/
if ((hard_iface) &&
@@ -641,7 +386,7 @@ void purge_outstanding_packets(struct bat_priv *bat_priv,
&bat_priv->forw_bat_list, list) {
/**
- * if purge_outstanding_packets() was called with an argmument
+ * if purge_outstanding_packets() was called with an argument
* we delete only packets belonging to the given interface
*/
if ((hard_iface) &&
diff --git a/net/batman-adv/send.h b/net/batman-adv/send.h
index 1f2d1e877663..c8ca3ef7385b 100644
--- a/net/batman-adv/send.h
+++ b/net/batman-adv/send.h
@@ -24,15 +24,10 @@
int send_skb_packet(struct sk_buff *skb, struct hard_iface *hard_iface,
const uint8_t *dst_addr);
-void schedule_own_packet(struct hard_iface *hard_iface);
-void schedule_forward_packet(struct orig_node *orig_node,
- const struct ethhdr *ethhdr,
- struct batman_packet *batman_packet,
- int directlink,
- struct hard_iface *if_outgoing);
+void schedule_bat_ogm(struct hard_iface *hard_iface);
int add_bcast_packet_to_list(struct bat_priv *bat_priv,
const struct sk_buff *skb, unsigned long delay);
-void send_outstanding_bat_packet(struct work_struct *work);
+void send_outstanding_bat_ogm_packet(struct work_struct *work);
void purge_outstanding_packets(struct bat_priv *bat_priv,
const struct hard_iface *hard_iface);
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index 3e2f91ffa4e2..f9cc95728989 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -445,30 +445,31 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
{
struct bat_priv *bat_priv = netdev_priv(dev);
struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
- struct batman_packet *batman_packet;
+ struct batman_ogm_packet *batman_ogm_packet;
struct softif_neigh *softif_neigh = NULL;
struct hard_iface *primary_if = NULL;
struct softif_neigh *curr_softif_neigh = NULL;
if (ntohs(ethhdr->h_proto) == ETH_P_8021Q)
- batman_packet = (struct batman_packet *)
+ batman_ogm_packet = (struct batman_ogm_packet *)
(skb->data + ETH_HLEN + VLAN_HLEN);
else
- batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN);
+ batman_ogm_packet = (struct batman_ogm_packet *)
+ (skb->data + ETH_HLEN);
- if (batman_packet->version != COMPAT_VERSION)
+ if (batman_ogm_packet->version != COMPAT_VERSION)
goto out;
- if (batman_packet->packet_type != BAT_PACKET)
+ if (batman_ogm_packet->packet_type != BAT_OGM)
goto out;
- if (!(batman_packet->flags & PRIMARIES_FIRST_HOP))
+ if (!(batman_ogm_packet->flags & PRIMARIES_FIRST_HOP))
goto out;
- if (is_my_mac(batman_packet->orig))
+ if (is_my_mac(batman_ogm_packet->orig))
goto out;
- softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid);
+ softif_neigh = softif_neigh_get(bat_priv, batman_ogm_packet->orig, vid);
if (!softif_neigh)
goto out;
@@ -532,11 +533,11 @@ static int interface_set_mac_addr(struct net_device *dev, void *p)
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
- /* only modify transtable if it has been initialised before */
+ /* only modify transtable if it has been initialized before */
if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) {
tt_local_remove(bat_priv, dev->dev_addr,
"mac address changed", false);
- tt_local_add(dev, addr->sa_data);
+ tt_local_add(dev, addr->sa_data, NULL_IFINDEX);
}
memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
@@ -565,7 +566,7 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
struct orig_node *orig_node = NULL;
int data_len = skb->len, ret;
short vid = -1;
- bool do_bcast = false;
+ bool do_bcast;
if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
goto dropped;
@@ -595,18 +596,19 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
goto dropped;
/* Register the client MAC in the transtable */
- tt_local_add(soft_iface, ethhdr->h_source);
+ tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif);
- orig_node = transtable_search(bat_priv, ethhdr->h_dest);
- if (is_multicast_ether_addr(ethhdr->h_dest) ||
- (orig_node && orig_node->gw_flags)) {
+ orig_node = transtable_search(bat_priv, ethhdr->h_source,
+ ethhdr->h_dest);
+ do_bcast = is_multicast_ether_addr(ethhdr->h_dest);
+ if (do_bcast || (orig_node && orig_node->gw_flags)) {
ret = gw_is_target(bat_priv, skb, orig_node);
if (ret < 0)
goto dropped;
- if (ret == 0)
- do_bcast = true;
+ if (ret)
+ do_bcast = false;
}
/* ethernet packet should be broadcasted */
@@ -739,6 +741,9 @@ void interface_rx(struct net_device *soft_iface,
soft_iface->last_rx = jiffies;
+ if (is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest))
+ goto dropped;
+
netif_rx(skb);
goto out;
@@ -796,10 +801,8 @@ struct net_device *softif_create(const char *name)
soft_iface = alloc_netdev(sizeof(*bat_priv), name, interface_setup);
- if (!soft_iface) {
- pr_err("Unable to allocate the batman interface: %s\n", name);
+ if (!soft_iface)
goto out;
- }
ret = register_netdevice(soft_iface);
if (ret < 0) {
@@ -812,6 +815,7 @@ struct net_device *softif_create(const char *name)
atomic_set(&bat_priv->aggregated_ogms, 1);
atomic_set(&bat_priv->bonding, 0);
+ atomic_set(&bat_priv->ap_isolation, 0);
atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE);
atomic_set(&bat_priv->gw_mode, GW_MODE_OFF);
atomic_set(&bat_priv->gw_sel_class, 20);
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index fb6931d00cd7..873fb3d8e56f 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -183,7 +183,8 @@ static int tt_local_init(struct bat_priv *bat_priv)
return 1;
}
-void tt_local_add(struct net_device *soft_iface, const uint8_t *addr)
+void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
+ int ifindex)
{
struct bat_priv *bat_priv = netdev_priv(soft_iface);
struct tt_local_entry *tt_local_entry = NULL;
@@ -207,6 +208,8 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr)
memcpy(tt_local_entry->addr, addr, ETH_ALEN);
tt_local_entry->last_seen = jiffies;
tt_local_entry->flags = NO_FLAGS;
+ if (is_wifi_iface(ifindex))
+ tt_local_entry->flags |= TT_CLIENT_WIFI;
atomic_set(&tt_local_entry->refcount, 2);
/* the batman interface mac address should never be purged */
@@ -329,7 +332,7 @@ int tt_local_seq_print_text(struct seq_file *seq, void *offset)
rcu_read_lock();
__hlist_for_each_rcu(node, head)
- buf_size += 21;
+ buf_size += 29;
rcu_read_unlock();
}
@@ -348,8 +351,19 @@ int tt_local_seq_print_text(struct seq_file *seq, void *offset)
rcu_read_lock();
hlist_for_each_entry_rcu(tt_local_entry, node,
head, hash_entry) {
- pos += snprintf(buff + pos, 22, " * %pM\n",
- tt_local_entry->addr);
+ pos += snprintf(buff + pos, 30, " * %pM "
+ "[%c%c%c%c%c]\n",
+ tt_local_entry->addr,
+ (tt_local_entry->flags &
+ TT_CLIENT_ROAM ? 'R' : '.'),
+ (tt_local_entry->flags &
+ TT_CLIENT_NOPURGE ? 'P' : '.'),
+ (tt_local_entry->flags &
+ TT_CLIENT_NEW ? 'N' : '.'),
+ (tt_local_entry->flags &
+ TT_CLIENT_PENDING ? 'X' : '.'),
+ (tt_local_entry->flags &
+ TT_CLIENT_WIFI ? 'W' : '.'));
}
rcu_read_unlock();
}
@@ -369,8 +383,8 @@ static void tt_local_set_pending(struct bat_priv *bat_priv,
tt_local_event(bat_priv, tt_local_entry->addr,
tt_local_entry->flags | flags);
- /* The local client has to be merked as "pending to be removed" but has
- * to be kept in the table in order to send it in an full tables
+ /* The local client has to be marked as "pending to be removed" but has
+ * to be kept in the table in order to send it in a full table
* response issued before the net ttvn increment (consistency check) */
tt_local_entry->flags |= TT_CLIENT_PENDING;
}
@@ -495,7 +509,8 @@ static void tt_changes_list_free(struct bat_priv *bat_priv)
/* caller must hold orig_node refcount */
int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
- const unsigned char *tt_addr, uint8_t ttvn, bool roaming)
+ const unsigned char *tt_addr, uint8_t ttvn, bool roaming,
+ bool wifi)
{
struct tt_global_entry *tt_global_entry;
struct orig_node *orig_node_tmp;
@@ -537,6 +552,9 @@ int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
tt_global_entry->roam_at = 0;
}
+ if (wifi)
+ tt_global_entry->flags |= TT_CLIENT_WIFI;
+
bat_dbg(DBG_TT, bat_priv,
"Creating new global tt entry: %pM (via %pM)\n",
tt_global_entry->addr, orig_node->orig);
@@ -582,8 +600,8 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset)
seq_printf(seq,
"Globally announced TT entries received via the mesh %s\n",
net_dev->name);
- seq_printf(seq, " %-13s %s %-15s %s\n",
- "Client", "(TTVN)", "Originator", "(Curr TTVN)");
+ seq_printf(seq, " %-13s %s %-15s %s %s\n",
+ "Client", "(TTVN)", "Originator", "(Curr TTVN)", "Flags");
buf_size = 1;
/* Estimate length for: " * xx:xx:xx:xx:xx:xx (ttvn) via
@@ -593,7 +611,7 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset)
rcu_read_lock();
__hlist_for_each_rcu(node, head)
- buf_size += 59;
+ buf_size += 67;
rcu_read_unlock();
}
@@ -612,14 +630,20 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset)
rcu_read_lock();
hlist_for_each_entry_rcu(tt_global_entry, node,
head, hash_entry) {
- pos += snprintf(buff + pos, 61,
- " * %pM (%3u) via %pM (%3u)\n",
- tt_global_entry->addr,
+ pos += snprintf(buff + pos, 69,
+ " * %pM (%3u) via %pM (%3u) "
+ "[%c%c%c]\n", tt_global_entry->addr,
tt_global_entry->ttvn,
tt_global_entry->orig_node->orig,
(uint8_t) atomic_read(
&tt_global_entry->orig_node->
- last_ttvn));
+ last_ttvn),
+ (tt_global_entry->flags &
+ TT_CLIENT_ROAM ? 'R' : '.'),
+ (tt_global_entry->flags &
+ TT_CLIENT_PENDING ? 'X' : '.'),
+ (tt_global_entry->flags &
+ TT_CLIENT_WIFI ? 'W' : '.'));
}
rcu_read_unlock();
}
@@ -774,30 +798,56 @@ static void tt_global_table_free(struct bat_priv *bat_priv)
bat_priv->tt_global_hash = NULL;
}
+static bool _is_ap_isolated(struct tt_local_entry *tt_local_entry,
+ struct tt_global_entry *tt_global_entry)
+{
+ bool ret = false;
+
+ if (tt_local_entry->flags & TT_CLIENT_WIFI &&
+ tt_global_entry->flags & TT_CLIENT_WIFI)
+ ret = true;
+
+ return ret;
+}
+
struct orig_node *transtable_search(struct bat_priv *bat_priv,
- const uint8_t *addr)
+ const uint8_t *src, const uint8_t *addr)
{
- struct tt_global_entry *tt_global_entry;
+ struct tt_local_entry *tt_local_entry = NULL;
+ struct tt_global_entry *tt_global_entry = NULL;
struct orig_node *orig_node = NULL;
- tt_global_entry = tt_global_hash_find(bat_priv, addr);
+ if (src && atomic_read(&bat_priv->ap_isolation)) {
+ tt_local_entry = tt_local_hash_find(bat_priv, src);
+ if (!tt_local_entry)
+ goto out;
+ }
+ tt_global_entry = tt_global_hash_find(bat_priv, addr);
if (!tt_global_entry)
goto out;
+ /* check whether the clients should not communicate due to AP
+ * isolation */
+ if (tt_local_entry && _is_ap_isolated(tt_local_entry, tt_global_entry))
+ goto out;
+
if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount))
- goto free_tt;
+ goto out;
/* A global client marked as PENDING has already moved from that
* originator */
if (tt_global_entry->flags & TT_CLIENT_PENDING)
- goto free_tt;
+ goto out;
orig_node = tt_global_entry->orig_node;
-free_tt:
- tt_global_entry_free_ref(tt_global_entry);
out:
+ if (tt_global_entry)
+ tt_global_entry_free_ref(tt_global_entry);
+ if (tt_local_entry)
+ tt_local_entry_free_ref(tt_local_entry);
+
return orig_node;
}
@@ -999,7 +1049,6 @@ static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
tt_response = (struct tt_query_packet *)skb_put(skb,
tt_query_size + tt_len);
tt_response->ttvn = ttvn;
- tt_response->tt_data = htons(tt_tot);
tt_change = (struct tt_change *)(skb->data + tt_query_size);
tt_count = 0;
@@ -1025,12 +1074,17 @@ static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
}
rcu_read_unlock();
+ /* store in the message the number of entries we have successfully
+ * copied */
+ tt_response->tt_data = htons(tt_count);
+
out:
return skb;
}
-int send_tt_request(struct bat_priv *bat_priv, struct orig_node *dst_orig_node,
- uint8_t ttvn, uint16_t tt_crc, bool full_table)
+static int send_tt_request(struct bat_priv *bat_priv,
+ struct orig_node *dst_orig_node,
+ uint8_t ttvn, uint16_t tt_crc, bool full_table)
{
struct sk_buff *skb = NULL;
struct tt_query_packet *tt_request;
@@ -1137,12 +1191,12 @@ static bool send_other_tt_response(struct bat_priv *bat_priv,
orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
req_ttvn = tt_request->ttvn;
- /* I have not the requested data */
+ /* I don't have the requested data */
if (orig_ttvn != req_ttvn ||
tt_request->tt_data != req_dst_orig_node->tt_crc)
goto out;
- /* If it has explicitly been requested the full table */
+ /* If the full table has been explicitly requested */
if (tt_request->flags & TT_FULL_TABLE ||
!req_dst_orig_node->tt_buff)
full_table = true;
@@ -1363,7 +1417,9 @@ static void _tt_update_changes(struct bat_priv *bat_priv,
(tt_change + i)->flags & TT_CLIENT_ROAM);
else
if (!tt_global_add(bat_priv, orig_node,
- (tt_change + i)->addr, ttvn, false))
+ (tt_change + i)->addr, ttvn, false,
+ (tt_change + i)->flags &
+ TT_CLIENT_WIFI))
/* In case of problem while storing a
* global_entry, we stop the updating
* procedure without committing the
@@ -1403,9 +1459,10 @@ out:
orig_node_free_ref(orig_node);
}
-void tt_update_changes(struct bat_priv *bat_priv, struct orig_node *orig_node,
- uint16_t tt_num_changes, uint8_t ttvn,
- struct tt_change *tt_change)
+static void tt_update_changes(struct bat_priv *bat_priv,
+ struct orig_node *orig_node,
+ uint16_t tt_num_changes, uint8_t ttvn,
+ struct tt_change *tt_change)
{
_tt_update_changes(bat_priv, orig_node, tt_change, tt_num_changes,
ttvn);
@@ -1668,6 +1725,8 @@ static void tt_local_reset_flags(struct bat_priv *bat_priv, uint16_t flags)
rcu_read_lock();
hlist_for_each_entry_rcu(tt_local_entry, node,
head, hash_entry) {
+ if (!(tt_local_entry->flags & flags))
+ continue;
tt_local_entry->flags &= ~flags;
atomic_inc(&bat_priv->num_local_tt);
}
@@ -1720,3 +1779,90 @@ void tt_commit_changes(struct bat_priv *bat_priv)
atomic_inc(&bat_priv->ttvn);
bat_priv->tt_poss_change = false;
}
+
+bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst)
+{
+ struct tt_local_entry *tt_local_entry = NULL;
+ struct tt_global_entry *tt_global_entry = NULL;
+ bool ret = true;
+
+ if (!atomic_read(&bat_priv->ap_isolation))
+ return false;
+
+ tt_local_entry = tt_local_hash_find(bat_priv, dst);
+ if (!tt_local_entry)
+ goto out;
+
+ tt_global_entry = tt_global_hash_find(bat_priv, src);
+ if (!tt_global_entry)
+ goto out;
+
+ if (_is_ap_isolated(tt_local_entry, tt_global_entry))
+ goto out;
+
+ ret = false;
+
+out:
+ if (tt_global_entry)
+ tt_global_entry_free_ref(tt_global_entry);
+ if (tt_local_entry)
+ tt_local_entry_free_ref(tt_local_entry);
+ return ret;
+}
+
+void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
+ const unsigned char *tt_buff, uint8_t tt_num_changes,
+ uint8_t ttvn, uint16_t tt_crc)
+{
+ uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
+ bool full_table = true;
+
+ /* the ttvn increased by one -> we can apply the attached changes */
+ if (ttvn - orig_ttvn == 1) {
+ /* the OGM could not contain the changes due to their size or
+ * because they have already been sent TT_OGM_APPEND_MAX times.
+ * In this case send a tt request */
+ if (!tt_num_changes) {
+ full_table = false;
+ goto request_table;
+ }
+
+ tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn,
+ (struct tt_change *)tt_buff);
+
+ /* Even if we received the precomputed crc with the OGM, we
+ * prefer to recompute it to spot any possible inconsistency
+ * in the global table */
+ orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
+
+ /* The ttvn alone is not enough to guarantee consistency
+ * because a single value could represent different states
+ * (due to the wrap around). Thus a node has to check whether
+ * the resulting table (after applying the changes) is still
+ * consistent or not. E.g. a node could disconnect while its
+ * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case
+ * checking the CRC value is mandatory to detect the
+ * inconsistency */
+ if (orig_node->tt_crc != tt_crc)
+ goto request_table;
+
+ /* Roaming phase is over: tables are in sync again. I can
+ * unset the flag */
+ orig_node->tt_poss_change = false;
+ } else {
+ /* if we missed more than one change or our tables are not
+ * in sync anymore -> request fresh tt data */
+ if (ttvn != orig_ttvn || orig_node->tt_crc != tt_crc) {
+request_table:
+ bat_dbg(DBG_TT, bat_priv, "TT inconsistency for %pM. "
+ "Need to retrieve the correct information "
+ "(ttvn: %u last_ttvn: %u crc: %u last_crc: "
+ "%u num_changes: %u)\n", orig_node->orig, ttvn,
+ orig_ttvn, tt_crc, orig_node->tt_crc,
+ tt_num_changes);
+ send_tt_request(bat_priv, orig_node, ttvn, tt_crc,
+ full_table);
+ return;
+ }
+ }
+}
diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h
index d4122cba53b8..30efd49881a3 100644
--- a/net/batman-adv/translation-table.h
+++ b/net/batman-adv/translation-table.h
@@ -26,15 +26,16 @@ int tt_len(int changes_num);
int tt_changes_fill_buffer(struct bat_priv *bat_priv,
unsigned char *buff, int buff_len);
int tt_init(struct bat_priv *bat_priv);
-void tt_local_add(struct net_device *soft_iface, const uint8_t *addr);
+void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
+ int ifindex);
void tt_local_remove(struct bat_priv *bat_priv,
const uint8_t *addr, const char *message, bool roaming);
int tt_local_seq_print_text(struct seq_file *seq, void *offset);
void tt_global_add_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
const unsigned char *tt_buff, int tt_buff_len);
-int tt_global_add(struct bat_priv *bat_priv,
- struct orig_node *orig_node, const unsigned char *addr,
- uint8_t ttvn, bool roaming);
+int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
+ const unsigned char *addr, uint8_t ttvn, bool roaming,
+ bool wifi);
int tt_global_seq_print_text(struct seq_file *seq, void *offset);
void tt_global_del_orig(struct bat_priv *bat_priv,
struct orig_node *orig_node, const char *message);
@@ -42,25 +43,23 @@ void tt_global_del(struct bat_priv *bat_priv,
struct orig_node *orig_node, const unsigned char *addr,
const char *message, bool roaming);
struct orig_node *transtable_search(struct bat_priv *bat_priv,
- const uint8_t *addr);
+ const uint8_t *src, const uint8_t *addr);
void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *orig_node,
const unsigned char *tt_buff, uint8_t tt_num_changes);
uint16_t tt_local_crc(struct bat_priv *bat_priv);
uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node);
void tt_free(struct bat_priv *bat_priv);
-int send_tt_request(struct bat_priv *bat_priv,
- struct orig_node *dst_orig_node, uint8_t hvn,
- uint16_t tt_crc, bool full_table);
bool send_tt_response(struct bat_priv *bat_priv,
struct tt_query_packet *tt_request);
-void tt_update_changes(struct bat_priv *bat_priv, struct orig_node *orig_node,
- uint16_t tt_num_changes, uint8_t ttvn,
- struct tt_change *tt_change);
bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr);
void handle_tt_response(struct bat_priv *bat_priv,
struct tt_query_packet *tt_response);
void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
struct orig_node *orig_node);
void tt_commit_changes(struct bat_priv *bat_priv);
+bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst);
+void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
+ const unsigned char *tt_buff, uint8_t tt_num_changes,
+ uint8_t ttvn, uint16_t tt_crc);
#endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 25bd1db35370..1ae355750511 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -57,7 +57,7 @@ struct hard_iface {
* @batman_seqno_reset: time when the batman seqno window was reset
* @gw_flags: flags related to gateway class
* @flags: for now only VIS_SERVER flag
- * @last_real_seqno: last and best known squence number
+ * @last_real_seqno: last and best known sequence number
* @last_ttl: ttl of last received packet
* @last_bcast_seqno: last broadcast sequence number received by this host
*
@@ -146,6 +146,7 @@ struct bat_priv {
atomic_t aggregated_ogms; /* boolean */
atomic_t bonding; /* boolean */
atomic_t fragmentation; /* boolean */
+ atomic_t ap_isolation; /* boolean */
atomic_t vis_mode; /* VIS_TYPE_* */
atomic_t gw_mode; /* GW_MODE_* */
atomic_t gw_sel_class; /* uint */
@@ -156,7 +157,7 @@ struct bat_priv {
atomic_t bcast_seqno;
atomic_t bcast_queue_left;
atomic_t batman_queue_left;
- atomic_t ttvn; /* tranlation table version number */
+ atomic_t ttvn; /* translation table version number */
atomic_t tt_ogm_append_cnt;
atomic_t tt_local_changes; /* changes registered in a OGM interval */
/* The tt_poss_change flag is used to detect an ongoing roaming phase.
diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c
index 32b125fb3d3b..07d1c1da89dd 100644
--- a/net/batman-adv/unicast.c
+++ b/net/batman-adv/unicast.c
@@ -299,8 +299,10 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
goto find_router;
}
- /* check for tt host - increases orig_node refcount */
- orig_node = transtable_search(bat_priv, ethhdr->h_dest);
+ /* check for tt host - increases orig_node refcount.
+ * returns NULL in case of AP isolation */
+ orig_node = transtable_search(bat_priv, ethhdr->h_source,
+ ethhdr->h_dest);
find_router:
/**
diff --git a/net/batman-adv/unicast.h b/net/batman-adv/unicast.h
index 62f54b954625..8fd5535544b9 100644
--- a/net/batman-adv/unicast.h
+++ b/net/batman-adv/unicast.h
@@ -24,7 +24,7 @@
#include "packet.h"
-#define FRAG_TIMEOUT 10000 /* purge frag list entrys after time in ms */
+#define FRAG_TIMEOUT 10000 /* purge frag list entries after time in ms */
#define FRAG_BUFFER_SIZE 6 /* number of list elements in buffer */
int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c
index 8a1b98589d76..f81a6b668b0c 100644
--- a/net/batman-adv/vis.c
+++ b/net/batman-adv/vis.c
@@ -131,7 +131,7 @@ static void vis_data_insert_interface(const uint8_t *interface,
return;
}
- /* its a new address, add it to the list */
+ /* it's a new address, add it to the list */
entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
if (!entry)
return;
@@ -465,7 +465,7 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv,
/* try to add it */
hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose,
info, &info->hash_entry);
- if (hash_added < 0) {
+ if (hash_added != 0) {
/* did not work (for some reason) */
kref_put(&info->refcount, free_info);
info = NULL;
@@ -887,10 +887,8 @@ int vis_init(struct bat_priv *bat_priv)
}
bat_priv->my_vis_info = kmalloc(MAX_VIS_PACKET_SIZE, GFP_ATOMIC);
- if (!bat_priv->my_vis_info) {
- pr_err("Can't initialize vis packet\n");
+ if (!bat_priv->my_vis_info)
goto err;
- }
bat_priv->my_vis_info->skb_packet = dev_alloc_skb(sizeof(*packet) +
MAX_VIS_PACKET_SIZE +
@@ -920,7 +918,7 @@ int vis_init(struct bat_priv *bat_priv)
hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose,
bat_priv->my_vis_info,
&bat_priv->my_vis_info->hash_entry);
- if (hash_added < 0) {
+ if (hash_added != 0) {
pr_err("Can't add own vis packet into hash\n");
/* not in hash, need to remove it manually. */
kref_put(&bat_priv->my_vis_info->refcount, free_info);
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 8add9b499912..062124cd89cf 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -349,7 +349,7 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
}
chunk = min_t(unsigned int, skb->len, size);
- if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
+ if (skb_copy_datagram_iovec(skb, 0, msg->msg_iov, chunk)) {
skb_queue_head(&sk->sk_receive_queue, skb);
if (!copied)
copied = -EFAULT;
@@ -361,7 +361,33 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
sock_recv_ts_and_drops(msg, sk, skb);
if (!(flags & MSG_PEEK)) {
- skb_pull(skb, chunk);
+ int skb_len = skb_headlen(skb);
+
+ if (chunk <= skb_len) {
+ __skb_pull(skb, chunk);
+ } else {
+ struct sk_buff *frag;
+
+ __skb_pull(skb, skb_len);
+ chunk -= skb_len;
+
+ skb_walk_frags(skb, frag) {
+ if (chunk <= frag->len) {
+ /* Pulling partial data */
+ skb->len -= chunk;
+ skb->data_len -= chunk;
+ __skb_pull(frag, chunk);
+ break;
+ } else if (frag->len) {
+ /* Pulling all frag data */
+ chunk -= frag->len;
+ skb->len -= frag->len;
+ skb->data_len -= frag->len;
+ __skb_pull(frag, frag->len);
+ }
+ }
+ }
+
if (skb->len) {
skb_queue_head(&sk->sk_receive_queue, skb);
break;
@@ -494,9 +520,8 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
BT_DBG("sk %p", sk);
add_wait_queue(sk_sleep(sk), &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
while (sk->sk_state != state) {
- set_current_state(TASK_INTERRUPTIBLE);
-
if (!timeo) {
err = -EINPROGRESS;
break;
@@ -510,12 +535,13 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
release_sock(sk);
timeo = schedule_timeout(timeo);
lock_sock(sk);
+ set_current_state(TASK_INTERRUPTIBLE);
err = sock_error(sk);
if (err)
break;
}
- set_current_state(TASK_RUNNING);
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
return err;
}
diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h
index 8e6c06158f8e..e7ee5314f39a 100644
--- a/net/bluetooth/bnep/bnep.h
+++ b/net/bluetooth/bnep/bnep.h
@@ -155,6 +155,7 @@ struct bnep_session {
unsigned int role;
unsigned long state;
unsigned long flags;
+ atomic_t terminate;
struct task_struct *task;
struct ethhdr eh;
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index ca39fcf010ce..91bcd3a961ec 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -484,13 +484,18 @@ static int bnep_session(void *arg)
init_waitqueue_entry(&wait, current);
add_wait_queue(sk_sleep(sk), &wait);
- while (!kthread_should_stop()) {
+ while (1) {
set_current_state(TASK_INTERRUPTIBLE);
+ if (atomic_read(&s->terminate))
+ break;
/* RX */
while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
skb_orphan(skb);
- bnep_rx_frame(s, skb);
+ if (!skb_linearize(skb))
+ bnep_rx_frame(s, skb);
+ else
+ kfree_skb(skb);
}
if (sk->sk_state != BT_CONNECTED)
@@ -504,7 +509,7 @@ static int bnep_session(void *arg)
schedule();
}
- set_current_state(TASK_RUNNING);
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
/* Cleanup session */
@@ -640,9 +645,10 @@ int bnep_del_connection(struct bnep_conndel_req *req)
down_read(&bnep_session_sem);
s = __bnep_get_session(req->dst);
- if (s)
- kthread_stop(s->task);
- else
+ if (s) {
+ atomic_inc(&s->terminate);
+ wake_up_process(s->task);
+ } else
err = -ENOENT;
up_read(&bnep_session_sem);
diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c
index d4f5dff7c955..bc4086480d97 100644
--- a/net/bluetooth/bnep/netdev.c
+++ b/net/bluetooth/bnep/netdev.c
@@ -217,7 +217,7 @@ static const struct net_device_ops bnep_netdev_ops = {
.ndo_stop = bnep_net_close,
.ndo_start_xmit = bnep_net_xmit,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = bnep_net_set_mc_list,
+ .ndo_set_rx_mode = bnep_net_set_mc_list,
.ndo_set_mac_address = bnep_net_set_mac_addr,
.ndo_tx_timeout = bnep_net_timeout,
.ndo_change_mtu = eth_change_mtu,
diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c
index 040f67b12978..50f0d135eb8f 100644
--- a/net/bluetooth/cmtp/capi.c
+++ b/net/bluetooth/cmtp/capi.c
@@ -386,7 +386,8 @@ static void cmtp_reset_ctr(struct capi_ctr *ctrl)
capi_ctr_down(ctrl);
- kthread_stop(session->task);
+ atomic_inc(&session->terminate);
+ wake_up_process(session->task);
}
static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
diff --git a/net/bluetooth/cmtp/cmtp.h b/net/bluetooth/cmtp/cmtp.h
index db43b54ac9af..c32638dddbf9 100644
--- a/net/bluetooth/cmtp/cmtp.h
+++ b/net/bluetooth/cmtp/cmtp.h
@@ -81,6 +81,7 @@ struct cmtp_session {
char name[BTNAMSIZ];
+ atomic_t terminate;
struct task_struct *task;
wait_queue_head_t wait;
diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c
index c5b11af908be..7d00ddf9e9dc 100644
--- a/net/bluetooth/cmtp/core.c
+++ b/net/bluetooth/cmtp/core.c
@@ -292,22 +292,27 @@ static int cmtp_session(void *arg)
init_waitqueue_entry(&wait, current);
add_wait_queue(sk_sleep(sk), &wait);
- while (!kthread_should_stop()) {
+ while (1) {
set_current_state(TASK_INTERRUPTIBLE);
+ if (atomic_read(&session->terminate))
+ break;
if (sk->sk_state != BT_CONNECTED)
break;
while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
skb_orphan(skb);
- cmtp_recv_frame(session, skb);
+ if (!skb_linearize(skb))
+ cmtp_recv_frame(session, skb);
+ else
+ kfree_skb(skb);
}
cmtp_process_transmit(session);
schedule();
}
- set_current_state(TASK_RUNNING);
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
down_write(&cmtp_session_sem);
@@ -380,16 +385,17 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
if (!(session->flags & (1 << CMTP_LOOPBACK))) {
err = cmtp_attach_device(session);
- if (err < 0)
- goto detach;
+ if (err < 0) {
+ atomic_inc(&session->terminate);
+ wake_up_process(session->task);
+ up_write(&cmtp_session_sem);
+ return err;
+ }
}
up_write(&cmtp_session_sem);
return 0;
-detach:
- cmtp_detach_device(session);
-
unlink:
__cmtp_unlink_session(session);
@@ -414,7 +420,8 @@ int cmtp_del_connection(struct cmtp_conndel_req *req)
skb_queue_purge(&session->transmit);
/* Stop session thread */
- kthread_stop(session->task);
+ atomic_inc(&session->terminate);
+ wake_up_process(session->task);
} else
err = -ENOENT;
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index ea7f031f3b04..c1c597e3e198 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -56,15 +56,15 @@ static void hci_le_connect(struct hci_conn *conn)
conn->sec_level = BT_SECURITY_LOW;
memset(&cp, 0, sizeof(cp));
- cp.scan_interval = cpu_to_le16(0x0004);
- cp.scan_window = cpu_to_le16(0x0004);
+ cp.scan_interval = cpu_to_le16(0x0060);
+ cp.scan_window = cpu_to_le16(0x0030);
bacpy(&cp.peer_addr, &conn->dst);
cp.peer_addr_type = conn->dst_type;
- cp.conn_interval_min = cpu_to_le16(0x0008);
- cp.conn_interval_max = cpu_to_le16(0x0100);
- cp.supervision_timeout = cpu_to_le16(0x0064);
- cp.min_ce_len = cpu_to_le16(0x0001);
- cp.max_ce_len = cpu_to_le16(0x0001);
+ cp.conn_interval_min = cpu_to_le16(0x0028);
+ cp.conn_interval_max = cpu_to_le16(0x0038);
+ cp.supervision_timeout = cpu_to_le16(0x002a);
+ cp.min_ce_len = cpu_to_le16(0x0000);
+ cp.max_ce_len = cpu_to_le16(0x0000);
hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
}
@@ -218,7 +218,7 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
cp.handle = cpu_to_le16(conn->handle);
memcpy(cp.ltk, ltk, sizeof(cp.ltk));
cp.ediv = ediv;
- memcpy(cp.rand, rand, sizeof(rand));
+ memcpy(cp.rand, rand, sizeof(cp.rand));
hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp);
}
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index ec0bc3f60f2e..b84458dcc226 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1209,7 +1209,6 @@ static void hci_cmd_timer(unsigned long arg)
BT_ERR("%s command tx timeout", hdev->name);
atomic_set(&hdev->cmd_cnt, 1);
- clear_bit(HCI_RESET, &hdev->flags);
tasklet_schedule(&hdev->cmd_task);
}
@@ -1313,59 +1312,41 @@ int hci_blacklist_clear(struct hci_dev *hdev)
int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
{
struct bdaddr_list *entry;
- int err;
if (bacmp(bdaddr, BDADDR_ANY) == 0)
return -EBADF;
- hci_dev_lock_bh(hdev);
-
- if (hci_blacklist_lookup(hdev, bdaddr)) {
- err = -EEXIST;
- goto err;
- }
+ if (hci_blacklist_lookup(hdev, bdaddr))
+ return -EEXIST;
entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL);
- if (!entry) {
+ if (!entry)
return -ENOMEM;
- goto err;
- }
bacpy(&entry->bdaddr, bdaddr);
list_add(&entry->list, &hdev->blacklist);
- err = 0;
-
-err:
- hci_dev_unlock_bh(hdev);
- return err;
+ return mgmt_device_blocked(hdev->id, bdaddr);
}
int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
{
struct bdaddr_list *entry;
- int err = 0;
-
- hci_dev_lock_bh(hdev);
if (bacmp(bdaddr, BDADDR_ANY) == 0) {
- hci_blacklist_clear(hdev);
- goto done;
+ return hci_blacklist_clear(hdev);
}
entry = hci_blacklist_lookup(hdev, bdaddr);
if (!entry) {
- err = -ENOENT;
- goto done;
+ return -ENOENT;
}
list_del(&entry->list);
kfree(entry);
-done:
- hci_dev_unlock_bh(hdev);
- return err;
+ return mgmt_device_unblocked(hdev->id, bdaddr);
}
static void hci_clear_adv_cache(unsigned long arg)
@@ -1524,11 +1505,6 @@ int hci_register_dev(struct hci_dev *hdev)
if (!hdev->workqueue)
goto nomem;
- hdev->tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(hdev->tfm))
- BT_INFO("Failed to load transform for ecb(aes): %ld",
- PTR_ERR(hdev->tfm));
-
hci_register_sysfs(hdev);
hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
@@ -1577,9 +1553,6 @@ int hci_unregister_dev(struct hci_dev *hdev)
!test_bit(HCI_SETUP, &hdev->flags))
mgmt_index_removed(hdev->id);
- if (!IS_ERR(hdev->tfm))
- crypto_free_blkcipher(hdev->tfm);
-
hci_notify(hdev, HCI_DEV_UNREG);
if (hdev->rfkill) {
@@ -2075,6 +2048,9 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
min = c->sent;
conn = c;
}
+
+ if (hci_conn_num(hdev, type) == num)
+ break;
}
if (conn) {
@@ -2132,6 +2108,9 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
+ if (!hci_conn_num(hdev, ACL_LINK))
+ return;
+
if (!test_bit(HCI_RAW, &hdev->flags)) {
/* ACL tx timeout must be longer than maximum
* link supervision timeout (40.9 seconds) */
@@ -2163,6 +2142,9 @@ static inline void hci_sched_sco(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
+ if (!hci_conn_num(hdev, SCO_LINK))
+ return;
+
while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, &quote))) {
while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
BT_DBG("skb %p len %d", skb, skb->len);
@@ -2183,6 +2165,9 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
+ if (!hci_conn_num(hdev, ESCO_LINK))
+ return;
+
while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, &quote))) {
while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
BT_DBG("skb %p len %d", skb, skb->len);
@@ -2203,6 +2188,9 @@ static inline void hci_sched_le(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
+ if (!hci_conn_num(hdev, LE_LINK))
+ return;
+
if (!test_bit(HCI_RAW, &hdev->flags)) {
/* LE tx timeout must be longer than maximum
* link supervision timeout (40.9 seconds) */
@@ -2408,7 +2396,10 @@ static void hci_cmd_task(unsigned long arg)
if (hdev->sent_cmd) {
atomic_dec(&hdev->cmd_cnt);
hci_send_frame(skb);
- mod_timer(&hdev->cmd_timer,
+ if (test_bit(HCI_RESET, &hdev->flags))
+ del_timer(&hdev->cmd_timer);
+ else
+ mod_timer(&hdev->cmd_timer,
jiffies + msecs_to_jiffies(HCI_CMD_TIMEOUT));
} else {
skb_queue_head(&hdev->cmd_q, skb);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index a40170e022e8..d7d96b6b1f0d 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -58,8 +58,8 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
if (status)
return;
- if (test_bit(HCI_MGMT, &hdev->flags) &&
- test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
+ if (test_and_clear_bit(HCI_INQUIRY, &hdev->flags) &&
+ test_bit(HCI_MGMT, &hdev->flags))
mgmt_discovering(hdev->id, 0);
hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status);
@@ -76,8 +76,8 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
if (status)
return;
- if (test_bit(HCI_MGMT, &hdev->flags) &&
- test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
+ if (test_and_clear_bit(HCI_INQUIRY, &hdev->flags) &&
+ test_bit(HCI_MGMT, &hdev->flags))
mgmt_discovering(hdev->id, 0);
hci_conn_check_pending(hdev);
@@ -898,16 +898,15 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
if (!cp)
return;
- hci_dev_lock(hdev);
-
if (cp->enable == 0x01) {
del_timer(&hdev->adv_timer);
+
+ hci_dev_lock(hdev);
hci_adv_entries_clear(hdev);
+ hci_dev_unlock(hdev);
} else if (cp->enable == 0x00) {
mod_timer(&hdev->adv_timer, jiffies + ADV_CLEAR_TIMEOUT);
}
-
- hci_dev_unlock(hdev);
}
static void hci_cc_le_ltk_reply(struct hci_dev *hdev, struct sk_buff *skb)
@@ -959,9 +958,8 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
return;
}
- if (test_bit(HCI_MGMT, &hdev->flags) &&
- !test_and_set_bit(HCI_INQUIRY,
- &hdev->flags))
+ if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags) &&
+ test_bit(HCI_MGMT, &hdev->flags))
mgmt_discovering(hdev->id, 1);
}
@@ -1104,9 +1102,10 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev,
return 0;
/* Only request authentication for SSP connections or non-SSP
- * devices with sec_level HIGH */
+ * devices with sec_level HIGH or if MITM protection is requested */
if (!(hdev->ssp_mode > 0 && conn->ssp_mode > 0) &&
- conn->pending_sec_level != BT_SECURITY_HIGH)
+ conn->pending_sec_level != BT_SECURITY_HIGH &&
+ !(conn->auth_type & 0x01))
return 0;
return 1;
@@ -1340,8 +1339,8 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff
BT_DBG("%s status %d", hdev->name, status);
- if (test_bit(HCI_MGMT, &hdev->flags) &&
- test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
+ if (test_and_clear_bit(HCI_INQUIRY, &hdev->flags) &&
+ test_bit(HCI_MGMT, &hdev->flags))
mgmt_discovering(hdev->id, 0);
hci_req_complete(hdev, HCI_OP_INQUIRY, status);
@@ -1413,7 +1412,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
conn->state = BT_CONFIG;
hci_conn_hold(conn);
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
- mgmt_connected(hdev->id, &ev->bdaddr);
+ mgmt_connected(hdev->id, &ev->bdaddr, conn->type);
} else
conn->state = BT_CONNECTED;
@@ -2175,7 +2174,10 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
- if (conn && conn->state == BT_CONNECTED) {
+ if (!conn)
+ goto unlock;
+
+ if (conn->state == BT_CONNECTED) {
hci_conn_hold(conn);
conn->disc_timeout = HCI_PAIRING_TIMEOUT;
hci_conn_put(conn);
@@ -2195,6 +2197,7 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
mgmt_pin_code_request(hdev->id, &ev->bdaddr, secure);
}
+unlock:
hci_dev_unlock(hdev);
}
@@ -2817,7 +2820,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
goto unlock;
}
- mgmt_connected(hdev->id, &ev->bdaddr);
+ mgmt_connected(hdev->id, &ev->bdaddr, conn->type);
conn->sec_level = BT_SECURITY_LOW;
conn->handle = __le16_to_cpu(ev->handle);
@@ -2835,19 +2838,17 @@ unlock:
static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
- struct hci_ev_le_advertising_info *ev;
- u8 num_reports;
-
- num_reports = skb->data[0];
- ev = (void *) &skb->data[1];
+ u8 num_reports = skb->data[0];
+ void *ptr = &skb->data[1];
hci_dev_lock(hdev);
- hci_add_adv_entry(hdev, ev);
+ while (num_reports--) {
+ struct hci_ev_le_advertising_info *ev = ptr;
- while (--num_reports) {
- ev = (void *) (ev->data + ev->length + 1);
hci_add_adv_entry(hdev, ev);
+
+ ptr += sizeof(*ev) + ev->length + 1;
}
hci_dev_unlock(hdev);
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index ff02cf5e77cc..f6afe3d76a66 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -183,21 +183,35 @@ static int hci_sock_release(struct socket *sock)
static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg)
{
bdaddr_t bdaddr;
+ int err;
if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
return -EFAULT;
- return hci_blacklist_add(hdev, &bdaddr);
+ hci_dev_lock_bh(hdev);
+
+ err = hci_blacklist_add(hdev, &bdaddr);
+
+ hci_dev_unlock_bh(hdev);
+
+ return err;
}
static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg)
{
bdaddr_t bdaddr;
+ int err;
if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
return -EFAULT;
- return hci_blacklist_del(hdev, &bdaddr);
+ hci_dev_lock_bh(hdev);
+
+ err = hci_blacklist_del(hdev, &bdaddr);
+
+ hci_dev_unlock_bh(hdev);
+
+ return err;
}
/* Ioctls that require bound socket */
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index a6c3aa8be1f7..22f1a6c87035 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -23,6 +23,8 @@ static inline char *link_typetostr(int type)
return "SCO";
case ESCO_LINK:
return "eSCO";
+ case LE_LINK:
+ return "LE";
default:
return "UNKNOWN";
}
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 43b4c2deb7cc..075a3e920caf 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -716,12 +716,18 @@ static int hidp_session(void *arg)
while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
skb_orphan(skb);
- hidp_recv_ctrl_frame(session, skb);
+ if (!skb_linearize(skb))
+ hidp_recv_ctrl_frame(session, skb);
+ else
+ kfree_skb(skb);
}
while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
skb_orphan(skb);
- hidp_recv_intr_frame(session, skb);
+ if (!skb_linearize(skb))
+ hidp_recv_intr_frame(session, skb);
+ else
+ kfree_skb(skb);
}
hidp_process_transmit(session);
@@ -764,6 +770,7 @@ static int hidp_session(void *arg)
up_write(&hidp_session_sem);
+ kfree(session->rd_data);
kfree(session);
return 0;
}
@@ -841,7 +848,8 @@ static int hidp_setup_input(struct hidp_session *session,
err = input_register_device(input);
if (err < 0) {
- hci_conn_put_device(session->conn);
+ input_free_device(input);
+ session->input = NULL;
return err;
}
@@ -870,6 +878,9 @@ static int hidp_start(struct hid_device *hid)
struct hidp_session *session = hid->driver_data;
struct hid_report *report;
+ if (hid->quirks & HID_QUIRK_NO_INIT_REPORTS)
+ return 0;
+
list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].
report_list, list)
hidp_send_report(session, report);
@@ -1044,8 +1055,12 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
}
err = hid_add_device(session->hid);
- if (err < 0)
- goto err_add_device;
+ if (err < 0) {
+ atomic_inc(&session->terminate);
+ wake_up_process(session->task);
+ up_write(&hidp_session_sem);
+ return err;
+ }
if (session->input) {
hidp_send_ctrl_message(session,
@@ -1059,12 +1074,6 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
up_write(&hidp_session_sem);
return 0;
-err_add_device:
- hid_destroy_device(session->hid);
- session->hid = NULL;
- atomic_inc(&session->terminate);
- wake_up_process(session->task);
-
unlink:
hidp_del_timer(session);
@@ -1090,7 +1099,6 @@ purge:
failed:
up_write(&hidp_session_sem);
- input_free_device(session->input);
kfree(session);
return err;
}
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 3204ba8a701c..8cd12917733b 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -907,6 +907,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
if (!conn->hcon->out && conn->hcon->type == LE_LINK)
l2cap_le_conn_ready(conn);
+ if (conn->hcon->out && conn->hcon->type == LE_LINK)
+ smp_conn_security(conn, conn->hcon->pending_sec_level);
+
read_lock(&conn->chan_lock);
list_for_each_entry(chan, &conn->chan_l, list) {
@@ -986,8 +989,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
del_timer_sync(&conn->info_timer);
- if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
+ if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) {
del_timer(&conn->security_timer);
+ smp_chan_destroy(conn);
+ }
hcon->l2cap_data = NULL;
kfree(conn);
@@ -1159,9 +1164,8 @@ int __l2cap_wait_ack(struct sock *sk)
int timeo = HZ/5;
add_wait_queue(sk_sleep(sk), &wait);
- while ((chan->unacked_frames > 0 && chan->conn)) {
- set_current_state(TASK_INTERRUPTIBLE);
-
+ set_current_state(TASK_INTERRUPTIBLE);
+ while (chan->unacked_frames > 0 && chan->conn) {
if (!timeo)
timeo = HZ/5;
@@ -1173,6 +1177,7 @@ int __l2cap_wait_ack(struct sock *sk)
release_sock(sk);
timeo = schedule_timeout(timeo);
lock_sock(sk);
+ set_current_state(TASK_INTERRUPTIBLE);
err = sock_error(sk);
if (err)
@@ -1240,7 +1245,7 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
__clear_retrans_timer(chan);
}
-void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
+static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
{
struct hci_conn *hcon = chan->conn->hcon;
u16 flags;
@@ -1256,7 +1261,7 @@ void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
hci_send_acl(hcon, skb, flags);
}
-void l2cap_streaming_send(struct l2cap_chan *chan)
+static void l2cap_streaming_send(struct l2cap_chan *chan)
{
struct sk_buff *skb;
u16 control, fcs;
@@ -1322,7 +1327,7 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
l2cap_do_send(chan, tx_skb);
}
-int l2cap_ertm_send(struct l2cap_chan *chan)
+static int l2cap_ertm_send(struct l2cap_chan *chan)
{
struct sk_buff *skb, *tx_skb;
u16 control, fcs;
@@ -1460,7 +1465,7 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
return sent;
}
-struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
+static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
{
struct sock *sk = chan->sk;
struct l2cap_conn *conn = chan->conn;
@@ -1490,7 +1495,7 @@ struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr
return skb;
}
-struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
+static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
{
struct sock *sk = chan->sk;
struct l2cap_conn *conn = chan->conn;
@@ -1519,7 +1524,9 @@ struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *m
return skb;
}
-struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen)
+static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
+ struct msghdr *msg, size_t len,
+ u16 control, u16 sdulen)
{
struct sock *sk = chan->sk;
struct l2cap_conn *conn = chan->conn;
@@ -1565,7 +1572,7 @@ struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *
return skb;
}
-int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
+static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
{
struct sk_buff *skb;
struct sk_buff_head sar_queue;
@@ -3121,102 +3128,104 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb,
return 0;
}
-static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
+static void append_skb_frag(struct sk_buff *skb,
+ struct sk_buff *new_frag, struct sk_buff **last_frag)
{
- struct sk_buff *_skb;
- int err;
+ /* skb->len reflects data in skb as well as all fragments
+ * skb->data_len reflects only data in fragments
+ */
+ if (!skb_has_frag_list(skb))
+ skb_shinfo(skb)->frag_list = new_frag;
+
+ new_frag->next = NULL;
+
+ (*last_frag)->next = new_frag;
+ *last_frag = new_frag;
+
+ skb->len += new_frag->len;
+ skb->data_len += new_frag->len;
+ skb->truesize += new_frag->truesize;
+}
+
+static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
+{
+ int err = -EINVAL;
switch (control & L2CAP_CTRL_SAR) {
case L2CAP_SDU_UNSEGMENTED:
- if (test_bit(CONN_SAR_SDU, &chan->conn_state))
- goto drop;
+ if (chan->sdu)
+ break;
- return chan->ops->recv(chan->data, skb);
+ err = chan->ops->recv(chan->data, skb);
+ break;
case L2CAP_SDU_START:
- if (test_bit(CONN_SAR_SDU, &chan->conn_state))
- goto drop;
+ if (chan->sdu)
+ break;
chan->sdu_len = get_unaligned_le16(skb->data);
+ skb_pull(skb, 2);
- if (chan->sdu_len > chan->imtu)
- goto disconnect;
-
- chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
- if (!chan->sdu)
- return -ENOMEM;
+ if (chan->sdu_len > chan->imtu) {
+ err = -EMSGSIZE;
+ break;
+ }
- /* pull sdu_len bytes only after alloc, because of Local Busy
- * condition we have to be sure that this will be executed
- * only once, i.e., when alloc does not fail */
- skb_pull(skb, 2);
+ if (skb->len >= chan->sdu_len)
+ break;
- memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
+ chan->sdu = skb;
+ chan->sdu_last_frag = skb;
- set_bit(CONN_SAR_SDU, &chan->conn_state);
- chan->partial_sdu_len = skb->len;
+ skb = NULL;
+ err = 0;
break;
case L2CAP_SDU_CONTINUE:
- if (!test_bit(CONN_SAR_SDU, &chan->conn_state))
- goto disconnect;
-
if (!chan->sdu)
- goto disconnect;
+ break;
- chan->partial_sdu_len += skb->len;
- if (chan->partial_sdu_len > chan->sdu_len)
- goto drop;
+ append_skb_frag(chan->sdu, skb,
+ &chan->sdu_last_frag);
+ skb = NULL;
- memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
+ if (chan->sdu->len >= chan->sdu_len)
+ break;
+ err = 0;
break;
case L2CAP_SDU_END:
- if (!test_bit(CONN_SAR_SDU, &chan->conn_state))
- goto disconnect;
-
if (!chan->sdu)
- goto disconnect;
-
- chan->partial_sdu_len += skb->len;
+ break;
- if (chan->partial_sdu_len > chan->imtu)
- goto drop;
+ append_skb_frag(chan->sdu, skb,
+ &chan->sdu_last_frag);
+ skb = NULL;
- if (chan->partial_sdu_len != chan->sdu_len)
- goto drop;
+ if (chan->sdu->len != chan->sdu_len)
+ break;
- memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
+ err = chan->ops->recv(chan->data, chan->sdu);
- _skb = skb_clone(chan->sdu, GFP_ATOMIC);
- if (!_skb) {
- return -ENOMEM;
+ if (!err) {
+ /* Reassembly complete */
+ chan->sdu = NULL;
+ chan->sdu_last_frag = NULL;
+ chan->sdu_len = 0;
}
-
- err = chan->ops->recv(chan->data, _skb);
- if (err < 0) {
- kfree_skb(_skb);
- return err;
- }
-
- clear_bit(CONN_SAR_SDU, &chan->conn_state);
-
- kfree_skb(chan->sdu);
break;
}
- kfree_skb(skb);
- return 0;
-
-drop:
- kfree_skb(chan->sdu);
- chan->sdu = NULL;
+ if (err) {
+ kfree_skb(skb);
+ kfree_skb(chan->sdu);
+ chan->sdu = NULL;
+ chan->sdu_last_frag = NULL;
+ chan->sdu_len = 0;
+ }
-disconnect:
- l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
- kfree_skb(skb);
- return 0;
+ return err;
}
static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
@@ -3270,99 +3279,6 @@ void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
}
}
-static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
-{
- struct sk_buff *_skb;
- int err = -EINVAL;
-
- /*
- * TODO: We have to notify the userland if some data is lost with the
- * Streaming Mode.
- */
-
- switch (control & L2CAP_CTRL_SAR) {
- case L2CAP_SDU_UNSEGMENTED:
- if (test_bit(CONN_SAR_SDU, &chan->conn_state)) {
- kfree_skb(chan->sdu);
- break;
- }
-
- err = chan->ops->recv(chan->data, skb);
- if (!err)
- return 0;
-
- break;
-
- case L2CAP_SDU_START:
- if (test_bit(CONN_SAR_SDU, &chan->conn_state)) {
- kfree_skb(chan->sdu);
- break;
- }
-
- chan->sdu_len = get_unaligned_le16(skb->data);
- skb_pull(skb, 2);
-
- if (chan->sdu_len > chan->imtu) {
- err = -EMSGSIZE;
- break;
- }
-
- chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
- if (!chan->sdu) {
- err = -ENOMEM;
- break;
- }
-
- memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
-
- set_bit(CONN_SAR_SDU, &chan->conn_state);
- chan->partial_sdu_len = skb->len;
- err = 0;
- break;
-
- case L2CAP_SDU_CONTINUE:
- if (!test_bit(CONN_SAR_SDU, &chan->conn_state))
- break;
-
- memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
-
- chan->partial_sdu_len += skb->len;
- if (chan->partial_sdu_len > chan->sdu_len)
- kfree_skb(chan->sdu);
- else
- err = 0;
-
- break;
-
- case L2CAP_SDU_END:
- if (!test_bit(CONN_SAR_SDU, &chan->conn_state))
- break;
-
- memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
-
- clear_bit(CONN_SAR_SDU, &chan->conn_state);
- chan->partial_sdu_len += skb->len;
-
- if (chan->partial_sdu_len > chan->imtu)
- goto drop;
-
- if (chan->partial_sdu_len == chan->sdu_len) {
- _skb = skb_clone(chan->sdu, GFP_ATOMIC);
- err = chan->ops->recv(chan->data, _skb);
- if (err < 0)
- kfree_skb(_skb);
- }
- err = 0;
-
-drop:
- kfree_skb(chan->sdu);
- break;
- }
-
- kfree_skb(skb);
- return err;
-}
-
static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
{
struct sk_buff *skb;
@@ -3377,7 +3293,7 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
skb = skb_dequeue(&chan->srej_q);
control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
- err = l2cap_ertm_reassembly_sdu(chan, skb, control);
+ err = l2cap_reassemble_sdu(chan, skb, control);
if (err < 0) {
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
@@ -3537,7 +3453,7 @@ expected:
return 0;
}
- err = l2cap_ertm_reassembly_sdu(chan, skb, rx_control);
+ err = l2cap_reassemble_sdu(chan, skb, rx_control);
chan->buffer_seq = (chan->buffer_seq + 1) % 64;
if (err < 0) {
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
@@ -3853,12 +3769,20 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
tx_seq = __get_txseq(control);
- if (chan->expected_tx_seq == tx_seq)
- chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
- else
- chan->expected_tx_seq = (tx_seq + 1) % 64;
+ if (chan->expected_tx_seq != tx_seq) {
+ /* Frame(s) missing - must discard partial SDU */
+ kfree_skb(chan->sdu);
+ chan->sdu = NULL;
+ chan->sdu_last_frag = NULL;
+ chan->sdu_len = 0;
+
+ /* TODO: Notify userland of missing data */
+ }
+
+ chan->expected_tx_seq = (tx_seq + 1) % 64;
- l2cap_streaming_reassembly_sdu(chan, skb, control);
+ if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
+ l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
goto done;
@@ -4093,6 +4017,11 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
BT_DBG("conn %p", conn);
+ if (hcon->type == LE_LINK) {
+ smp_distribute_keys(conn, 0);
+ del_timer(&conn->security_timer);
+ }
+
read_lock(&conn->chan_lock);
list_for_each_entry(chan, &conn->chan_l, list) {
@@ -4105,9 +4034,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
if (chan->scid == L2CAP_CID_LE_DATA) {
if (!status && encrypt) {
chan->sec_level = hcon->sec_level;
- del_timer(&conn->security_timer);
l2cap_chan_ready(sk);
- smp_distribute_keys(conn, 0);
}
bh_unlock_sock(sk);
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 5c36b3e8739c..e8292369cdcf 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -26,6 +26,8 @@
/* Bluetooth L2CAP sockets. */
+#include <linux/security.h>
+
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
@@ -235,30 +237,26 @@ static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int fl
lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
- if (sk->sk_state != BT_LISTEN) {
- err = -EBADFD;
- goto done;
- }
-
timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
BT_DBG("sk %p timeo %ld", sk, timeo);
/* Wait for an incoming connection. (wake-one). */
add_wait_queue_exclusive(sk_sleep(sk), &wait);
- while (!(nsk = bt_accept_dequeue(sk, newsock))) {
+ while (1) {
set_current_state(TASK_INTERRUPTIBLE);
- if (!timeo) {
- err = -EAGAIN;
+
+ if (sk->sk_state != BT_LISTEN) {
+ err = -EBADFD;
break;
}
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
+ nsk = bt_accept_dequeue(sk, newsock);
+ if (nsk)
+ break;
- if (sk->sk_state != BT_LISTEN) {
- err = -EBADFD;
+ if (!timeo) {
+ err = -EAGAIN;
break;
}
@@ -266,8 +264,12 @@ static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int fl
err = sock_intr_errno(timeo);
break;
}
+
+ release_sock(sk);
+ timeo = schedule_timeout(timeo);
+ lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
}
- set_current_state(TASK_RUNNING);
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
if (err)
@@ -933,6 +935,8 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
chan->force_reliable = pchan->force_reliable;
chan->flushable = pchan->flushable;
chan->force_active = pchan->force_active;
+
+ security_sk_clone(parent, sk);
} else {
switch (sk->sk_type) {
@@ -993,7 +997,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);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 53e109eb043e..5a94eec06caa 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -908,7 +908,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
struct hci_dev *hdev;
struct mgmt_cp_load_keys *cp;
u16 key_count, expected_len;
- int i, err;
+ int i;
cp = (void *) data;
@@ -918,9 +918,9 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
key_count = get_unaligned_le16(&cp->key_count);
expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
- if (expected_len > len) {
- BT_ERR("load_keys: expected at least %u bytes, got %u bytes",
- expected_len, len);
+ if (expected_len != len) {
+ BT_ERR("load_keys: expected %u bytes, got %u bytes",
+ len, expected_len);
return -EINVAL;
}
@@ -942,36 +942,17 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
else
clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
- len -= sizeof(*cp);
- i = 0;
-
- while (i < len) {
- struct mgmt_key_info *key = (void *) cp->keys + i;
-
- i += sizeof(*key) + key->dlen;
-
- if (key->type == HCI_LK_SMP_LTK) {
- struct key_master_id *id = (void *) key->data;
-
- if (key->dlen != sizeof(struct key_master_id))
- continue;
-
- hci_add_ltk(hdev, 0, &key->bdaddr, key->pin_len,
- id->ediv, id->rand, key->val);
-
- continue;
- }
+ for (i = 0; i < key_count; i++) {
+ struct mgmt_key_info *key = &cp->keys[i];
hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
key->pin_len);
}
- err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
-
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
- return err;
+ return 0;
}
static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
@@ -1347,6 +1328,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
struct hci_dev *hdev;
struct mgmt_cp_pair_device *cp;
struct pending_cmd *cmd;
+ struct adv_entry *entry;
u8 sec_level, auth_type;
struct hci_conn *conn;
int err;
@@ -1364,15 +1346,20 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
hci_dev_lock_bh(hdev);
- if (cp->io_cap == 0x03) {
- sec_level = BT_SECURITY_MEDIUM;
+ sec_level = BT_SECURITY_MEDIUM;
+ if (cp->io_cap == 0x03)
auth_type = HCI_AT_DEDICATED_BONDING;
- } else {
- sec_level = BT_SECURITY_HIGH;
+ else
auth_type = HCI_AT_DEDICATED_BONDING_MITM;
- }
- conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level, auth_type);
+ entry = hci_find_adv_entry(hdev, &cp->bdaddr);
+ if (entry)
+ conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level,
+ auth_type);
+ else
+ conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level,
+ auth_type);
+
if (IS_ERR(conn)) {
err = PTR_ERR(conn);
goto unlock;
@@ -1391,7 +1378,10 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
goto unlock;
}
- conn->connect_cfm_cb = pairing_complete_cb;
+ /* For LE, just connecting isn't a proof that the pairing finished */
+ if (!entry)
+ conn->connect_cfm_cb = pairing_complete_cb;
+
conn->security_cfm_cb = pairing_complete_cb;
conn->disconn_cfm_cb = pairing_complete_cb;
conn->io_capability = cp->io_cap;
@@ -1689,13 +1679,12 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
u16 len)
{
struct hci_dev *hdev;
- struct mgmt_cp_block_device *cp;
+ struct pending_cmd *cmd;
+ struct mgmt_cp_block_device *cp = (void *) data;
int err;
BT_DBG("hci%u", index);
- cp = (void *) data;
-
if (len != sizeof(*cp))
return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
EINVAL);
@@ -1705,6 +1694,14 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
ENODEV);
+ hci_dev_lock_bh(hdev);
+
+ cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0);
+ if (!cmd) {
+ err = -ENOMEM;
+ goto failed;
+ }
+
err = hci_blacklist_add(hdev, &cp->bdaddr);
if (err < 0)
@@ -1712,6 +1709,11 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
else
err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
NULL, 0);
+
+ mgmt_pending_remove(cmd);
+
+failed:
+ hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
@@ -1721,13 +1723,12 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
u16 len)
{
struct hci_dev *hdev;
- struct mgmt_cp_unblock_device *cp;
+ struct pending_cmd *cmd;
+ struct mgmt_cp_unblock_device *cp = (void *) data;
int err;
BT_DBG("hci%u", index);
- cp = (void *) data;
-
if (len != sizeof(*cp))
return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
EINVAL);
@@ -1737,6 +1738,14 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
ENODEV);
+ hci_dev_lock_bh(hdev);
+
+ cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0);
+ if (!cmd) {
+ err = -ENOMEM;
+ goto failed;
+ }
+
err = hci_blacklist_del(hdev, &cp->bdaddr);
if (err < 0)
@@ -1744,6 +1753,67 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
else
err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
NULL, 0);
+
+ mgmt_pending_remove(cmd);
+
+failed:
+ hci_dev_unlock_bh(hdev);
+ hci_dev_put(hdev);
+
+ return err;
+}
+
+static int set_fast_connectable(struct sock *sk, u16 index,
+ unsigned char *data, u16 len)
+{
+ struct hci_dev *hdev;
+ struct mgmt_cp_set_fast_connectable *cp = (void *) data;
+ struct hci_cp_write_page_scan_activity acp;
+ u8 type;
+ int err;
+
+ BT_DBG("hci%u", index);
+
+ if (len != sizeof(*cp))
+ return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
+ EINVAL);
+
+ hdev = hci_dev_get(index);
+ if (!hdev)
+ return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
+ ENODEV);
+
+ hci_dev_lock(hdev);
+
+ if (cp->enable) {
+ type = PAGE_SCAN_TYPE_INTERLACED;
+ acp.interval = 0x0024; /* 22.5 msec page scan interval */
+ } else {
+ type = PAGE_SCAN_TYPE_STANDARD; /* default */
+ acp.interval = 0x0800; /* default 1.28 sec page scan */
+ }
+
+ acp.window = 0x0012; /* default 11.25 msec page scan window */
+
+ 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,
+ -err);
+ 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,
+ -err);
+ goto done;
+ }
+
+ err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
+ NULL, 0);
+done:
+ hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;
@@ -1869,6 +1939,10 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
case MGMT_OP_UNBLOCK_DEVICE:
err = unblock_device(sk, index, buf + sizeof(*hdr), len);
break;
+ case MGMT_OP_SET_FAST_CONNECTABLE:
+ err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
+ len);
+ break;
default:
BT_DBG("Unknown op %u", opcode);
err = cmd_status(sk, index, opcode, 0x01);
@@ -1977,35 +2051,25 @@ int mgmt_connectable(u16 index, u8 connectable)
int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
{
- struct mgmt_ev_new_key *ev;
- int err, total;
-
- total = sizeof(struct mgmt_ev_new_key) + key->dlen;
- ev = kzalloc(total, GFP_ATOMIC);
- if (!ev)
- return -ENOMEM;
-
- bacpy(&ev->key.bdaddr, &key->bdaddr);
- ev->key.type = key->type;
- memcpy(ev->key.val, key->val, 16);
- ev->key.pin_len = key->pin_len;
- ev->key.dlen = key->dlen;
- ev->store_hint = persistent;
+ struct mgmt_ev_new_key ev;
- memcpy(ev->key.data, key->data, key->dlen);
-
- err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
+ memset(&ev, 0, sizeof(ev));
- kfree(ev);
+ ev.store_hint = persistent;
+ bacpy(&ev.key.bdaddr, &key->bdaddr);
+ ev.key.type = key->type;
+ memcpy(ev.key.val, key->val, 16);
+ ev.key.pin_len = key->pin_len;
- return err;
+ return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
}
-int mgmt_connected(u16 index, bdaddr_t *bdaddr)
+int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type)
{
struct mgmt_ev_connected ev;
bacpy(&ev.bdaddr, bdaddr);
+ ev.link_type = link_type;
return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
}
@@ -2260,12 +2324,14 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
memset(&ev, 0, sizeof(ev));
bacpy(&ev.bdaddr, bdaddr);
- memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
ev.rssi = rssi;
if (eir)
memcpy(ev.eir, eir, sizeof(ev.eir));
+ if (dev_class)
+ memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
+
return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
}
@@ -2286,3 +2352,29 @@ int mgmt_discovering(u16 index, u8 discovering)
return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
sizeof(discovering), NULL);
}
+
+int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr)
+{
+ struct pending_cmd *cmd;
+ struct mgmt_ev_device_blocked ev;
+
+ cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index);
+
+ bacpy(&ev.bdaddr, bdaddr);
+
+ return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev),
+ cmd ? cmd->sk : NULL);
+}
+
+int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr)
+{
+ struct pending_cmd *cmd;
+ struct mgmt_ev_device_unblocked ev;
+
+ cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index);
+
+ bacpy(&ev.bdaddr, bdaddr);
+
+ return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev),
+ cmd ? cmd->sk : NULL);
+}
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 5759bb7054f7..38b618c96de6 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -62,7 +62,6 @@ static DEFINE_MUTEX(rfcomm_mutex);
#define rfcomm_lock() mutex_lock(&rfcomm_mutex)
#define rfcomm_unlock() mutex_unlock(&rfcomm_mutex)
-static unsigned long rfcomm_event;
static LIST_HEAD(session_list);
@@ -120,7 +119,6 @@ static inline void rfcomm_schedule(void)
{
if (!rfcomm_thread)
return;
- set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
wake_up_process(rfcomm_thread);
}
@@ -1855,7 +1853,10 @@ static inline void rfcomm_process_rx(struct rfcomm_session *s)
/* Get data directly from socket receive queue without copying it. */
while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
skb_orphan(skb);
- rfcomm_recv_frame(s, skb);
+ if (!skb_linearize(skb))
+ rfcomm_recv_frame(s, skb);
+ else
+ kfree_skb(skb);
}
if (sk->sk_state == BT_CLOSED) {
@@ -2038,19 +2039,18 @@ static int rfcomm_run(void *unused)
rfcomm_add_listener(BDADDR_ANY);
- while (!kthread_should_stop()) {
+ while (1) {
set_current_state(TASK_INTERRUPTIBLE);
- if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) {
- /* No pending events. Let's sleep.
- * Incoming connections and data will wake us up. */
- schedule();
- }
- set_current_state(TASK_RUNNING);
+
+ if (kthread_should_stop())
+ break;
/* Process stuff */
- clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
rfcomm_process_sessions();
+
+ schedule();
}
+ __set_current_state(TASK_RUNNING);
rfcomm_kill_listener();
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 8f01e6b11a70..5417f6127323 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -42,6 +42,7 @@
#include <linux/device.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
+#include <linux/security.h>
#include <net/sock.h>
#include <asm/system.h>
@@ -264,6 +265,8 @@ static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
pi->sec_level = rfcomm_pi(parent)->sec_level;
pi->role_switch = rfcomm_pi(parent)->role_switch;
+
+ security_sk_clone(parent, sk);
} else {
pi->dlc->defer_setup = 0;
@@ -485,11 +488,6 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f
lock_sock(sk);
- if (sk->sk_state != BT_LISTEN) {
- err = -EBADFD;
- goto done;
- }
-
if (sk->sk_type != SOCK_STREAM) {
err = -EINVAL;
goto done;
@@ -501,19 +499,20 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f
/* Wait for an incoming connection. (wake-one). */
add_wait_queue_exclusive(sk_sleep(sk), &wait);
- while (!(nsk = bt_accept_dequeue(sk, newsock))) {
+ while (1) {
set_current_state(TASK_INTERRUPTIBLE);
- if (!timeo) {
- err = -EAGAIN;
+
+ if (sk->sk_state != BT_LISTEN) {
+ err = -EBADFD;
break;
}
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock(sk);
+ nsk = bt_accept_dequeue(sk, newsock);
+ if (nsk)
+ break;
- if (sk->sk_state != BT_LISTEN) {
- err = -EBADFD;
+ if (!timeo) {
+ err = -EAGAIN;
break;
}
@@ -521,8 +520,12 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f
err = sock_intr_errno(timeo);
break;
}
+
+ release_sock(sk);
+ timeo = schedule_timeout(timeo);
+ lock_sock(sk);
}
- set_current_state(TASK_RUNNING);
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
if (err)
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 4c3621b5e0aa..a324b009e34b 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -41,6 +41,7 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/list.h>
+#include <linux/security.h>
#include <net/sock.h>
#include <asm/system.h>
@@ -403,8 +404,10 @@ static void sco_sock_init(struct sock *sk, struct sock *parent)
{
BT_DBG("sk %p", sk);
- if (parent)
+ if (parent) {
sk->sk_type = parent->sk_type;
+ security_sk_clone(parent, sk);
+ }
}
static struct proto sco_proto = {
@@ -564,30 +567,26 @@ static int sco_sock_accept(struct socket *sock, struct socket *newsock, int flag
lock_sock(sk);
- if (sk->sk_state != BT_LISTEN) {
- err = -EBADFD;
- goto done;
- }
-
timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
BT_DBG("sk %p timeo %ld", sk, timeo);
/* Wait for an incoming connection. (wake-one). */
add_wait_queue_exclusive(sk_sleep(sk), &wait);
- while (!(ch = bt_accept_dequeue(sk, newsock))) {
+ while (1) {
set_current_state(TASK_INTERRUPTIBLE);
- if (!timeo) {
- err = -EAGAIN;
+
+ if (sk->sk_state != BT_LISTEN) {
+ err = -EBADFD;
break;
}
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock(sk);
+ ch = bt_accept_dequeue(sk, newsock);
+ if (ch)
+ break;
- if (sk->sk_state != BT_LISTEN) {
- err = -EBADFD;
+ if (!timeo) {
+ err = -EAGAIN;
break;
}
@@ -595,8 +594,12 @@ static int sco_sock_accept(struct socket *sock, struct socket *newsock, int flag
err = sock_intr_errno(timeo);
break;
}
+
+ release_sock(sk);
+ timeo = schedule_timeout(timeo);
+ lock_sock(sk);
}
- set_current_state(TASK_RUNNING);
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
if (err)
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 391888b88a92..759b63572641 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -182,18 +182,9 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
return;
hci_send_acl(conn->hcon, skb, 0);
-}
-
-static __u8 seclevel_to_authreq(__u8 level)
-{
- switch (level) {
- case BT_SECURITY_HIGH:
- /* Right now we don't support bonding */
- return SMP_AUTH_MITM;
- default:
- return SMP_AUTH_NONE;
- }
+ mod_timer(&conn->security_timer, jiffies +
+ msecs_to_jiffies(SMP_TIMEOUT));
}
static void build_pairing_cmd(struct l2cap_conn *conn,
@@ -205,7 +196,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
dist_keys = 0;
if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->flags)) {
- dist_keys = SMP_DIST_ENC_KEY | SMP_DIST_ID_KEY | SMP_DIST_SIGN;
+ dist_keys = SMP_DIST_ENC_KEY;
authreq |= SMP_AUTH_BONDING;
}
@@ -229,24 +220,184 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
{
+ struct smp_chan *smp = conn->smp_chan;
+
if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) ||
(max_key_size < SMP_MIN_ENC_KEY_SIZE))
return SMP_ENC_KEY_SIZE;
- conn->smp_key_size = max_key_size;
+ smp->smp_key_size = max_key_size;
return 0;
}
+static void confirm_work(struct work_struct *work)
+{
+ struct smp_chan *smp = container_of(work, struct smp_chan, confirm);
+ struct l2cap_conn *conn = smp->conn;
+ struct crypto_blkcipher *tfm;
+ struct smp_cmd_pairing_confirm cp;
+ int ret;
+ u8 res[16], reason;
+
+ BT_DBG("conn %p", conn);
+
+ tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(tfm)) {
+ reason = SMP_UNSPECIFIED;
+ goto error;
+ }
+
+ smp->tfm = tfm;
+
+ 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);
+ else
+ ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
+ conn->hcon->dst_type, conn->dst, 0, conn->src,
+ res);
+ if (ret) {
+ reason = SMP_UNSPECIFIED;
+ goto error;
+ }
+
+ swap128(res, cp.confirm_val);
+ smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
+
+ return;
+
+error:
+ smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason);
+ smp_chan_destroy(conn);
+}
+
+static void random_work(struct work_struct *work)
+{
+ struct smp_chan *smp = container_of(work, struct smp_chan, random);
+ struct l2cap_conn *conn = smp->conn;
+ struct hci_conn *hcon = conn->hcon;
+ struct crypto_blkcipher *tfm = smp->tfm;
+ u8 reason, confirm[16], res[16], key[16];
+ int ret;
+
+ if (IS_ERR_OR_NULL(tfm)) {
+ reason = SMP_UNSPECIFIED;
+ goto error;
+ }
+
+ BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
+
+ if (hcon->out)
+ ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, 0,
+ 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);
+ if (ret) {
+ reason = SMP_UNSPECIFIED;
+ goto error;
+ }
+
+ swap128(res, confirm);
+
+ if (memcmp(smp->pcnf, confirm, sizeof(smp->pcnf)) != 0) {
+ BT_ERR("Pairing failed (confirmation values mismatch)");
+ reason = SMP_CONFIRM_FAILED;
+ goto error;
+ }
+
+ if (hcon->out) {
+ u8 stk[16], rand[8];
+ __le16 ediv;
+
+ memset(rand, 0, sizeof(rand));
+ ediv = 0;
+
+ 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);
+
+ if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) {
+ reason = SMP_UNSPECIFIED;
+ goto error;
+ }
+
+ hci_le_start_enc(hcon, ediv, rand, stk);
+ hcon->enc_key_size = smp->smp_key_size;
+ } else {
+ u8 stk[16], r[16], rand[8];
+ __le16 ediv;
+
+ memset(rand, 0, sizeof(rand));
+ ediv = 0;
+
+ swap128(smp->prnd, r);
+ smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r);
+
+ 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);
+
+ hci_add_ltk(hcon->hdev, 0, conn->dst, smp->smp_key_size,
+ ediv, rand, stk);
+ }
+
+ return;
+
+error:
+ smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason);
+ smp_chan_destroy(conn);
+}
+
+static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
+{
+ struct smp_chan *smp;
+
+ smp = kzalloc(sizeof(struct smp_chan), GFP_ATOMIC);
+ if (!smp)
+ return NULL;
+
+ INIT_WORK(&smp->confirm, confirm_work);
+ INIT_WORK(&smp->random, random_work);
+
+ smp->conn = conn;
+ conn->smp_chan = smp;
+
+ hci_conn_hold(conn->hcon);
+
+ return smp;
+}
+
+void smp_chan_destroy(struct l2cap_conn *conn)
+{
+ kfree(conn->smp_chan);
+ hci_conn_put(conn->hcon);
+}
+
static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_pairing rsp, *req = (void *) skb->data;
+ struct smp_chan *smp;
u8 key_size;
+ int ret;
BT_DBG("conn %p", conn);
- conn->preq[0] = SMP_CMD_PAIRING_REQ;
- memcpy(&conn->preq[1], req, sizeof(*req));
+ if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend))
+ smp = smp_chan_create(conn);
+
+ smp = conn->smp_chan;
+
+ smp->preq[0] = SMP_CMD_PAIRING_REQ;
+ memcpy(&smp->preq[1], req, sizeof(*req));
skb_pull(skb, sizeof(*req));
if (req->oob_flag)
@@ -260,32 +411,33 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
return SMP_ENC_KEY_SIZE;
/* Just works */
- memset(conn->tk, 0, sizeof(conn->tk));
+ memset(smp->tk, 0, sizeof(smp->tk));
+
+ ret = smp_rand(smp->prnd);
+ if (ret)
+ return SMP_UNSPECIFIED;
- conn->prsp[0] = SMP_CMD_PAIRING_RSP;
- memcpy(&conn->prsp[1], &rsp, sizeof(rsp));
+ smp->prsp[0] = SMP_CMD_PAIRING_RSP;
+ memcpy(&smp->prsp[1], &rsp, sizeof(rsp));
smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp);
- mod_timer(&conn->security_timer, jiffies +
- msecs_to_jiffies(SMP_TIMEOUT));
-
return 0;
}
static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
- struct smp_cmd_pairing_confirm cp;
- struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm;
+ struct smp_chan *smp = conn->smp_chan;
+ struct hci_dev *hdev = conn->hcon->hdev;
+ u8 key_size;
int ret;
- u8 res[16], key_size;
BT_DBG("conn %p", conn);
skb_pull(skb, sizeof(*rsp));
- req = (void *) &conn->preq[1];
+ req = (void *) &smp->preq[1];
key_size = min(req->max_key_size, rsp->max_key_size);
if (check_enc_key_size(conn, key_size))
@@ -295,222 +447,154 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
return SMP_OOB_NOT_AVAIL;
/* Just works */
- memset(conn->tk, 0, sizeof(conn->tk));
-
- conn->prsp[0] = SMP_CMD_PAIRING_RSP;
- memcpy(&conn->prsp[1], rsp, sizeof(*rsp));
-
- ret = smp_rand(conn->prnd);
- if (ret)
- return SMP_UNSPECIFIED;
+ memset(smp->tk, 0, sizeof(smp->tk));
- ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, 0,
- conn->src, conn->hcon->dst_type, conn->dst, res);
+ ret = smp_rand(smp->prnd);
if (ret)
return SMP_UNSPECIFIED;
- swap128(res, cp.confirm_val);
+ smp->prsp[0] = SMP_CMD_PAIRING_RSP;
+ memcpy(&smp->prsp[1], rsp, sizeof(*rsp));
- smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
+ queue_work(hdev->workqueue, &smp->confirm);
return 0;
}
static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
{
- struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm;
+ struct smp_chan *smp = conn->smp_chan;
+ struct hci_dev *hdev = conn->hcon->hdev;
BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
- memcpy(conn->pcnf, skb->data, sizeof(conn->pcnf));
- skb_pull(skb, sizeof(conn->pcnf));
+ memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf));
+ skb_pull(skb, sizeof(smp->pcnf));
if (conn->hcon->out) {
u8 random[16];
- swap128(conn->prnd, random);
+ swap128(smp->prnd, random);
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random),
random);
} else {
- struct smp_cmd_pairing_confirm cp;
- int ret;
- u8 res[16];
-
- ret = smp_rand(conn->prnd);
- if (ret)
- return SMP_UNSPECIFIED;
-
- ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp,
- conn->hcon->dst_type, conn->dst,
- 0, conn->src, res);
- if (ret)
- return SMP_CONFIRM_FAILED;
-
- swap128(res, cp.confirm_val);
-
- smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
+ queue_work(hdev->workqueue, &smp->confirm);
}
- mod_timer(&conn->security_timer, jiffies +
- msecs_to_jiffies(SMP_TIMEOUT));
-
return 0;
}
static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
{
- struct hci_conn *hcon = conn->hcon;
- struct crypto_blkcipher *tfm = hcon->hdev->tfm;
- int ret;
- u8 key[16], res[16], random[16], confirm[16];
+ struct smp_chan *smp = conn->smp_chan;
+ struct hci_dev *hdev = conn->hcon->hdev;
- swap128(skb->data, random);
- skb_pull(skb, sizeof(random));
-
- if (conn->hcon->out)
- ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp, 0,
- conn->src, conn->hcon->dst_type, conn->dst,
- res);
- else
- ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp,
- conn->hcon->dst_type, conn->dst, 0, conn->src,
- res);
- if (ret)
- return SMP_UNSPECIFIED;
-
- BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
-
- swap128(res, confirm);
-
- if (memcmp(conn->pcnf, confirm, sizeof(conn->pcnf)) != 0) {
- BT_ERR("Pairing failed (confirmation values mismatch)");
- return SMP_CONFIRM_FAILED;
- }
-
- if (conn->hcon->out) {
- u8 stk[16], rand[8];
- __le16 ediv;
-
- memset(rand, 0, sizeof(rand));
- ediv = 0;
+ BT_DBG("conn %p", conn);
- smp_s1(tfm, conn->tk, random, conn->prnd, key);
- swap128(key, stk);
+ swap128(skb->data, smp->rrnd);
+ skb_pull(skb, sizeof(smp->rrnd));
- memset(stk + conn->smp_key_size, 0,
- SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);
+ queue_work(hdev->workqueue, &smp->random);
- hci_le_start_enc(hcon, ediv, rand, stk);
- hcon->enc_key_size = conn->smp_key_size;
- } else {
- u8 stk[16], r[16], rand[8];
- __le16 ediv;
+ return 0;
+}
- memset(rand, 0, sizeof(rand));
- ediv = 0;
+static u8 smp_ltk_encrypt(struct l2cap_conn *conn)
+{
+ struct link_key *key;
+ struct key_master_id *master;
+ struct hci_conn *hcon = conn->hcon;
- swap128(conn->prnd, r);
- smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r);
+ key = hci_find_link_key_type(hcon->hdev, conn->dst,
+ HCI_LK_SMP_LTK);
+ if (!key)
+ return 0;
- smp_s1(tfm, conn->tk, conn->prnd, random, key);
- swap128(key, stk);
+ if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND,
+ &hcon->pend))
+ return 1;
- memset(stk + conn->smp_key_size, 0,
- SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);
+ master = (void *) key->data;
+ hci_le_start_enc(hcon, master->ediv, master->rand,
+ key->val);
+ hcon->enc_key_size = key->pin_len;
- hci_add_ltk(conn->hcon->hdev, 0, conn->dst, conn->smp_key_size,
- ediv, rand, stk);
- }
+ return 1;
- return 0;
}
-
static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_security_req *rp = (void *) skb->data;
struct smp_cmd_pairing cp;
struct hci_conn *hcon = conn->hcon;
+ struct smp_chan *smp;
BT_DBG("conn %p", conn);
- if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
+ hcon->pending_sec_level = BT_SECURITY_MEDIUM;
+
+ if (smp_ltk_encrypt(conn))
return 0;
+ if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend))
+ return 0;
+
+ smp = smp_chan_create(conn);
+
skb_pull(skb, sizeof(*rp));
memset(&cp, 0, sizeof(cp));
build_pairing_cmd(conn, &cp, NULL, rp->auth_req);
- conn->preq[0] = SMP_CMD_PAIRING_REQ;
- memcpy(&conn->preq[1], &cp, sizeof(cp));
+ smp->preq[0] = SMP_CMD_PAIRING_REQ;
+ memcpy(&smp->preq[1], &cp, sizeof(cp));
smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
- mod_timer(&conn->security_timer, jiffies +
- msecs_to_jiffies(SMP_TIMEOUT));
-
- set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
-
return 0;
}
int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
{
struct hci_conn *hcon = conn->hcon;
- __u8 authreq;
+ struct smp_chan *smp = conn->smp_chan;
BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
if (!lmp_host_le_capable(hcon->hdev))
return 1;
- if (IS_ERR(hcon->hdev->tfm))
- return 1;
-
- if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
- return 0;
-
if (sec_level == BT_SECURITY_LOW)
return 1;
if (hcon->sec_level >= sec_level)
return 1;
- authreq = seclevel_to_authreq(sec_level);
-
- if (hcon->link_mode & HCI_LM_MASTER) {
- struct smp_cmd_pairing cp;
- struct link_key *key;
+ if (hcon->link_mode & HCI_LM_MASTER)
+ if (smp_ltk_encrypt(conn))
+ goto done;
- key = hci_find_link_key_type(hcon->hdev, conn->dst,
- HCI_LK_SMP_LTK);
- if (key) {
- struct key_master_id *master = (void *) key->data;
+ if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend))
+ return 0;
- hci_le_start_enc(hcon, master->ediv, master->rand,
- key->val);
- hcon->enc_key_size = key->pin_len;
+ smp = smp_chan_create(conn);
- goto done;
- }
-
- build_pairing_cmd(conn, &cp, NULL, authreq);
- conn->preq[0] = SMP_CMD_PAIRING_REQ;
- memcpy(&conn->preq[1], &cp, sizeof(cp));
+ if (hcon->link_mode & HCI_LM_MASTER) {
+ struct smp_cmd_pairing cp;
- mod_timer(&conn->security_timer, jiffies +
- msecs_to_jiffies(SMP_TIMEOUT));
+ build_pairing_cmd(conn, &cp, NULL, SMP_AUTH_NONE);
+ smp->preq[0] = SMP_CMD_PAIRING_REQ;
+ memcpy(&smp->preq[1], &cp, sizeof(cp));
smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
} else {
struct smp_cmd_security_req cp;
- cp.auth_req = authreq;
+ cp.auth_req = SMP_AUTH_NONE;
smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
}
done:
hcon->pending_sec_level = sec_level;
- set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
return 0;
}
@@ -518,10 +602,11 @@ done:
static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_encrypt_info *rp = (void *) skb->data;
+ struct smp_chan *smp = conn->smp_chan;
skb_pull(skb, sizeof(*rp));
- memcpy(conn->tk, rp->ltk, sizeof(conn->tk));
+ memcpy(smp->tk, rp->ltk, sizeof(smp->tk));
return 0;
}
@@ -529,11 +614,12 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
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;
skb_pull(skb, sizeof(*rp));
- hci_add_ltk(conn->hcon->hdev, 1, conn->src, conn->smp_key_size,
- rp->ediv, rp->rand, conn->tk);
+ hci_add_ltk(conn->hcon->hdev, 1, conn->src, smp->smp_key_size,
+ rp->ediv, rp->rand, smp->tk);
smp_distribute_keys(conn, 1);
@@ -552,12 +638,6 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
goto done;
}
- if (IS_ERR(conn->hcon->hdev->tfm)) {
- err = PTR_ERR(conn->hcon->hdev->tfm);
- reason = SMP_PAIRING_NOTSUPP;
- goto done;
- }
-
skb_pull(skb, sizeof(code));
switch (code) {
@@ -621,20 +701,21 @@ done:
int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
{
struct smp_cmd_pairing *req, *rsp;
+ struct smp_chan *smp = conn->smp_chan;
__u8 *keydist;
BT_DBG("conn %p force %d", conn, force);
- if (IS_ERR(conn->hcon->hdev->tfm))
- return PTR_ERR(conn->hcon->hdev->tfm);
+ if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend))
+ return 0;
- rsp = (void *) &conn->prsp[1];
+ rsp = (void *) &smp->prsp[1];
/* The responder sends its keys first */
if (!force && conn->hcon->out && (rsp->resp_key_dist & 0x07))
return 0;
- req = (void *) &conn->preq[1];
+ req = (void *) &smp->preq[1];
if (conn->hcon->out) {
keydist = &rsp->init_key_dist;
@@ -658,7 +739,7 @@ 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, conn->smp_key_size,
+ hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->smp_key_size,
ediv, ident.rand, enc.ltk);
ident.ediv = cpu_to_le16(ediv);
@@ -698,5 +779,11 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
*keydist &= ~SMP_DIST_SIGN;
}
+ if (conn->hcon->out || force) {
+ clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend);
+ del_timer(&conn->security_timer);
+ smp_chan_destroy(conn);
+ }
+
return 0;
}
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 32b8f9f7f79e..feb77ea7b58e 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -91,7 +91,6 @@ static int br_dev_open(struct net_device *dev)
{
struct net_bridge *br = netdev_priv(dev);
- netif_carrier_off(dev);
netdev_update_features(dev);
netif_start_queue(dev);
br_stp_enable_bridge(br);
@@ -108,8 +107,6 @@ static int br_dev_stop(struct net_device *dev)
{
struct net_bridge *br = netdev_priv(dev);
- netif_carrier_off(dev);
-
br_stp_disable_bridge(br);
br_multicast_stop(br);
@@ -304,7 +301,7 @@ static const struct net_device_ops br_netdev_ops = {
.ndo_start_xmit = br_dev_xmit,
.ndo_get_stats64 = br_get_stats64,
.ndo_set_mac_address = br_set_mac_address,
- .ndo_set_multicast_list = br_dev_set_multicast_list,
+ .ndo_set_rx_mode = br_dev_set_multicast_list,
.ndo_change_mtu = br_change_mtu,
.ndo_do_ioctl = br_dev_ioctl,
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -361,6 +358,8 @@ void br_dev_setup(struct net_device *dev)
memcpy(br->group_addr, br_group_address, ETH_ALEN);
br->stp_enabled = BR_NO_STP;
+ br->group_fwd_mask = BR_GROUPFWD_DEFAULT;
+
br->designated_root = br->bridge_id;
br->bridge_max_age = br->max_age = 20 * HZ;
br->bridge_hello_time = br->hello_time = 2 * HZ;
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 68def3b7fb49..c8e7861b88b0 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -558,19 +558,28 @@ skip:
/* Create new static fdb entry */
static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
- __u16 state)
+ __u16 state, __u16 flags)
{
struct net_bridge *br = source->br;
struct hlist_head *head = &br->hash[br_mac_hash(addr)];
struct net_bridge_fdb_entry *fdb;
fdb = fdb_find(head, addr);
- if (fdb)
- return -EEXIST;
+ if (fdb == NULL) {
+ if (!(flags & NLM_F_CREATE))
+ return -ENOENT;
- fdb = fdb_create(head, source, addr);
- if (!fdb)
- return -ENOMEM;
+ fdb = fdb_create(head, source, addr);
+ if (!fdb)
+ return -ENOMEM;
+ } else {
+ if (flags & NLM_F_EXCL)
+ return -EEXIST;
+
+ if (flags & NLM_F_REPLACE)
+ fdb->updated = fdb->used = jiffies;
+ fdb->is_local = fdb->is_static = 0;
+ }
if (state & NUD_PERMANENT)
fdb->is_local = fdb->is_static = 1;
@@ -626,7 +635,7 @@ int br_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
}
spin_lock_bh(&p->br->hash_lock);
- err = fdb_add_entry(p, addr, ndm->ndm_state);
+ err = fdb_add_entry(p, addr, ndm->ndm_state, nlh->nlmsg_flags);
spin_unlock_bh(&p->br->hash_lock);
return err;
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 2cdf0070419f..f603e5b0b930 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
#include <linux/netpoll.h>
#include <linux/ethtool.h>
#include <linux/if_arp.h>
@@ -33,20 +34,18 @@
*/
static int port_cost(struct net_device *dev)
{
- if (dev->ethtool_ops && dev->ethtool_ops->get_settings) {
- struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET, };
-
- if (!dev_ethtool_get_settings(dev, &ecmd)) {
- switch (ethtool_cmd_speed(&ecmd)) {
- case SPEED_10000:
- return 2;
- case SPEED_1000:
- return 4;
- case SPEED_100:
- return 19;
- case SPEED_10:
- return 100;
- }
+ struct ethtool_cmd ecmd;
+
+ if (!__ethtool_get_settings(dev, &ecmd)) {
+ switch (ethtool_cmd_speed(&ecmd)) {
+ case SPEED_10000:
+ return 2;
+ case SPEED_1000:
+ return 4;
+ case SPEED_100:
+ return 19;
+ case SPEED_10:
+ return 100;
}
}
@@ -161,9 +160,10 @@ static void del_nbp(struct net_bridge_port *p)
call_rcu(&p->rcu, destroy_nbp_rcu);
}
-/* called with RTNL */
-static void del_br(struct net_bridge *br, struct list_head *head)
+/* Delete bridge device */
+void br_dev_delete(struct net_device *dev, struct list_head *head)
{
+ struct net_bridge *br = netdev_priv(dev);
struct net_bridge_port *p, *n;
list_for_each_entry_safe(p, n, &br->port_list, list) {
@@ -231,6 +231,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
int br_add_bridge(struct net *net, const char *name)
{
struct net_device *dev;
+ int res;
dev = alloc_netdev(sizeof(struct net_bridge), name,
br_dev_setup);
@@ -240,7 +241,10 @@ int br_add_bridge(struct net *net, const char *name)
dev_net_set(dev, net);
- return register_netdev(dev);
+ res = register_netdev(dev);
+ if (res)
+ free_netdev(dev);
+ return res;
}
int br_del_bridge(struct net *net, const char *name)
@@ -264,7 +268,7 @@ int br_del_bridge(struct net *net, const char *name)
}
else
- del_br(netdev_priv(dev), NULL);
+ br_dev_delete(dev, NULL);
rtnl_unlock();
return ret;
@@ -320,7 +324,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
/* Don't allow bridging non-ethernet like devices */
if ((dev->flags & IFF_LOOPBACK) ||
- dev->type != ARPHRD_ETHER || dev->addr_len != ETH_ALEN)
+ dev->type != ARPHRD_ETHER || dev->addr_len != ETH_ALEN ||
+ !is_valid_ether_addr(dev->dev_addr))
return -EINVAL;
/* No bridging of bridges */
@@ -348,10 +353,6 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
err = kobject_init_and_add(&p->kobj, &brport_ktype, &(dev->dev.kobj),
SYSFS_BRIDGE_PORT_ATTR);
if (err)
- goto err0;
-
- err = br_fdb_insert(br, p, dev->dev_addr);
- if (err)
goto err1;
err = br_sysfs_addif(p);
@@ -392,6 +393,9 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
dev_set_mtu(br->dev, br_min_mtu(br));
+ if (br_fdb_insert(br, p, dev->dev_addr))
+ netdev_err(dev, "failed insert local address bridge forwarding table\n");
+
kobject_uevent(&p->kobj, KOBJ_ADD);
return 0;
@@ -401,11 +405,9 @@ err4:
err3:
sysfs_remove_link(br->ifobj, p->dev->name);
err2:
- br_fdb_delete_by_port(br, p, 1);
-err1:
kobject_put(&p->kobj);
p = NULL; /* kobject_put frees */
-err0:
+err1:
dev_set_promiscuity(dev, -1);
put_back:
dev_put(dev);
@@ -445,7 +447,7 @@ void __net_exit br_net_exit(struct net *net)
rtnl_lock();
for_each_netdev(net, dev)
if (dev->priv_flags & IFF_EBRIDGE)
- del_br(netdev_priv(dev), &list);
+ br_dev_delete(dev, &list);
unregister_netdevice_many(&list);
rtnl_unlock();
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index f06ee39c73fd..6f9f8c014725 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -162,14 +162,37 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
p = br_port_get_rcu(skb->dev);
if (unlikely(is_link_local(dest))) {
- /* Pause frames shouldn't be passed up by driver anyway */
- if (skb->protocol == htons(ETH_P_PAUSE))
+ /*
+ * See IEEE 802.1D Table 7-10 Reserved addresses
+ *
+ * Assignment Value
+ * Bridge Group Address 01-80-C2-00-00-00
+ * (MAC Control) 802.3 01-80-C2-00-00-01
+ * (Link Aggregation) 802.3 01-80-C2-00-00-02
+ * 802.1X PAE address 01-80-C2-00-00-03
+ *
+ * 802.1AB LLDP 01-80-C2-00-00-0E
+ *
+ * Others reserved for future standardization
+ */
+ switch (dest[5]) {
+ case 0x00: /* Bridge Group Address */
+ /* If STP is turned off,
+ then must forward to keep loop detection */
+ if (p->br->stp_enabled == BR_NO_STP)
+ goto forward;
+ break;
+
+ case 0x01: /* IEEE MAC (Pause) */
goto drop;
- /* If STP is turned off, then forward */
- if (p->br->stp_enabled == BR_NO_STP && dest[5] == 0)
- goto forward;
+ default:
+ /* Allow selective forwarding for most other protocols */
+ if (p->br->group_fwd_mask & (1u << dest[5]))
+ goto forward;
+ }
+ /* Deliver packet to local host only */
if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,
NULL, br_handle_local_finish)) {
return RX_HANDLER_CONSUMED; /* consumed by filter */
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 2d85ca7111d3..995cbe0ac0b2 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1456,7 +1456,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
{
struct sk_buff *skb2;
const struct ipv6hdr *ip6h;
- struct icmp6hdr *icmp6h;
+ u8 icmp6_type;
u8 nexthdr;
unsigned len;
int offset;
@@ -1502,9 +1502,9 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
__skb_pull(skb2, offset);
skb_reset_transport_header(skb2);
- icmp6h = icmp6_hdr(skb2);
+ icmp6_type = icmp6_hdr(skb2)->icmp6_type;
- switch (icmp6h->icmp6_type) {
+ switch (icmp6_type) {
case ICMPV6_MGM_QUERY:
case ICMPV6_MGM_REPORT:
case ICMPV6_MGM_REDUCTION:
@@ -1520,16 +1520,23 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
err = pskb_trim_rcsum(skb2, len);
if (err)
goto out;
+ err = -EINVAL;
}
+ ip6h = ipv6_hdr(skb2);
+
switch (skb2->ip_summed) {
case CHECKSUM_COMPLETE:
- if (!csum_fold(skb2->csum))
+ if (!csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, skb2->len,
+ IPPROTO_ICMPV6, skb2->csum))
break;
/*FALLTHROUGH*/
case CHECKSUM_NONE:
- skb2->csum = 0;
- if (skb_checksum_complete(skb2))
+ skb2->csum = ~csum_unfold(csum_ipv6_magic(&ip6h->saddr,
+ &ip6h->daddr,
+ skb2->len,
+ IPPROTO_ICMPV6, 0));
+ if (__skb_checksum_complete(skb2))
goto out;
}
@@ -1537,7 +1544,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
BR_INPUT_SKB_CB(skb)->igmp = 1;
- switch (icmp6h->icmp6_type) {
+ switch (icmp6_type) {
case ICMPV6_MGM_REPORT:
{
struct mld_msg *mld;
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 5b1ed1ba9aa7..e5f9ece3c9a0 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -210,6 +210,7 @@ static struct rtnl_link_ops br_link_ops __read_mostly = {
.priv_size = sizeof(struct net_bridge),
.setup = br_dev_setup,
.validate = br_validate,
+ .dellink = br_dev_delete,
};
int __init br_netlink_init(void)
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 78cc364997d9..d7d6fb05411f 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -29,6 +29,11 @@
#define BR_VERSION "2.3"
+/* Control of forwarding link local multicast */
+#define BR_GROUPFWD_DEFAULT 0
+/* Don't allow forwarding control protocols like STP and LLDP */
+#define BR_GROUPFWD_RESTRICTED 0x4007u
+
/* Path to usermode spanning tree program */
#define BR_STP_PROG "/sbin/bridge-stp"
@@ -193,6 +198,8 @@ struct net_bridge
unsigned long flags;
#define BR_SET_MAC_ADDR 0x00000001
+ u16 group_fwd_mask;
+
/* STP */
bridge_id designated_root;
bridge_id bridge_id;
@@ -294,6 +301,7 @@ static inline int br_is_root_bridge(const struct net_bridge *br)
/* br_device.c */
extern void br_dev_setup(struct net_device *dev);
+extern void br_dev_delete(struct net_device *dev, struct list_head *list);
extern netdev_tx_t br_dev_xmit(struct sk_buff *skb,
struct net_device *dev);
#ifdef CONFIG_NET_POLL_CONTROLLER
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index 68b893ea8c3a..c236c0e43984 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -149,6 +149,39 @@ static ssize_t store_stp_state(struct device *d,
static DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
store_stp_state);
+static ssize_t show_group_fwd_mask(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct net_bridge *br = to_bridge(d);
+ return sprintf(buf, "%#x\n", br->group_fwd_mask);
+}
+
+
+static ssize_t store_group_fwd_mask(struct device *d,
+ struct device_attribute *attr, const char *buf,
+ size_t len)
+{
+ struct net_bridge *br = to_bridge(d);
+ char *endp;
+ unsigned long val;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ val = simple_strtoul(buf, &endp, 0);
+ if (endp == buf)
+ return -EINVAL;
+
+ if (val & BR_GROUPFWD_RESTRICTED)
+ return -EINVAL;
+
+ br->group_fwd_mask = val;
+
+ return len;
+}
+static DEVICE_ATTR(group_fwd_mask, S_IRUGO | S_IWUSR, show_group_fwd_mask,
+ store_group_fwd_mask);
+
static ssize_t show_priority(struct device *d, struct device_attribute *attr,
char *buf)
{
@@ -652,6 +685,7 @@ static struct attribute *bridge_attrs[] = {
&dev_attr_max_age.attr,
&dev_attr_ageing_time.attr,
&dev_attr_stp_state.attr,
+ &dev_attr_group_fwd_mask.attr,
&dev_attr_priority.attr,
&dev_attr_bridge_id.attr,
&dev_attr_root_id.attr,
diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig
index ba6f73eb06c6..a9aff9c7d027 100644
--- a/net/bridge/netfilter/Kconfig
+++ b/net/bridge/netfilter/Kconfig
@@ -4,7 +4,7 @@
menuconfig BRIDGE_NF_EBTABLES
tristate "Ethernet Bridge tables (ebtables) support"
- depends on BRIDGE && BRIDGE_NETFILTER
+ depends on BRIDGE && NETFILTER
select NETFILTER_XTABLES
help
ebtables is a general, extensible frame/packet identification
diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c
index 1bcaf36ad612..40d8258bf74f 100644
--- a/net/bridge/netfilter/ebtable_broute.c
+++ b/net/bridge/netfilter/ebtable_broute.c
@@ -87,14 +87,14 @@ static int __init ebtable_broute_init(void)
if (ret < 0)
return ret;
/* see br_input.c */
- rcu_assign_pointer(br_should_route_hook,
+ RCU_INIT_POINTER(br_should_route_hook,
(br_should_route_hook_t *)ebt_broute);
return 0;
}
static void __exit ebtable_broute_fini(void)
{
- rcu_assign_pointer(br_should_route_hook, NULL);
+ RCU_INIT_POINTER(br_should_route_hook, NULL);
synchronize_net();
unregister_pernet_subsys(&broute_net_ops);
}
diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c
index 7c2fa0a08148..7f9ac0742d19 100644
--- a/net/caif/caif_dev.c
+++ b/net/caif/caif_dev.c
@@ -93,10 +93,14 @@ static struct caif_device_entry *caif_device_alloc(struct net_device *dev)
caifdevs = caif_device_list(dev_net(dev));
BUG_ON(!caifdevs);
- caifd = kzalloc(sizeof(*caifd), GFP_ATOMIC);
+ caifd = kzalloc(sizeof(*caifd), GFP_KERNEL);
if (!caifd)
return NULL;
caifd->pcpu_refcnt = alloc_percpu(int);
+ if (!caifd->pcpu_refcnt) {
+ kfree(caifd);
+ return NULL;
+ }
caifd->netdev = dev;
dev_hold(dev);
return caifd;
diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c
index 52fe33bee029..00523ecc4ced 100644
--- a/net/caif/cfcnfg.c
+++ b/net/caif/cfcnfg.c
@@ -78,10 +78,8 @@ struct cfcnfg *cfcnfg_create(void)
/* Initiate this layer */
this = kzalloc(sizeof(struct cfcnfg), GFP_ATOMIC);
- if (!this) {
- pr_warn("Out of memory\n");
+ if (!this)
return NULL;
- }
this->mux = cfmuxl_create();
if (!this->mux)
goto out_of_mem;
@@ -108,8 +106,6 @@ struct cfcnfg *cfcnfg_create(void)
return this;
out_of_mem:
- pr_warn("Out of memory\n");
-
synchronize_rcu();
kfree(this->mux);
@@ -448,10 +444,8 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
"- unknown channel type\n");
goto unlock;
}
- if (!servicel) {
- pr_warn("Out of memory\n");
+ if (!servicel)
goto unlock;
- }
layer_set_dn(servicel, cnfg->mux);
cfmuxl_set_uplayer(cnfg->mux, servicel, channel_id);
layer_set_up(servicel, adapt_layer);
@@ -473,7 +467,7 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
{
struct cflayer *frml;
struct cflayer *phy_driver = NULL;
- struct cfcnfg_phyinfo *phyinfo;
+ struct cfcnfg_phyinfo *phyinfo = NULL;
int i;
u8 phyid;
@@ -488,25 +482,25 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
goto got_phyid;
}
pr_warn("Too many CAIF Link Layers (max 6)\n");
- goto out;
+ goto out_err;
got_phyid:
phyinfo = kzalloc(sizeof(struct cfcnfg_phyinfo), GFP_ATOMIC);
+ if (!phyinfo)
+ goto out_err;
switch (phy_type) {
case CFPHYTYPE_FRAG:
phy_driver =
cfserl_create(CFPHYTYPE_FRAG, phyid, stx);
- if (!phy_driver) {
- pr_warn("Out of memory\n");
- goto out;
- }
+ if (!phy_driver)
+ goto out_err;
break;
case CFPHYTYPE_CAIF:
phy_driver = NULL;
break;
default:
- goto out;
+ goto out_err;
}
phy_layer->id = phyid;
phyinfo->pref = pref;
@@ -520,11 +514,8 @@ got_phyid:
frml = cffrml_create(phyid, fcs);
- if (!frml) {
- pr_warn("Out of memory\n");
- kfree(phyinfo);
- goto out;
- }
+ if (!frml)
+ goto out_err;
phyinfo->frm_layer = frml;
layer_set_up(frml, cnfg->mux);
@@ -540,7 +531,12 @@ got_phyid:
}
list_add_rcu(&phyinfo->node, &cnfg->phys);
-out:
+ mutex_unlock(&cnfg->lock);
+ return;
+
+out_err:
+ kfree(phy_driver);
+ kfree(phyinfo);
mutex_unlock(&cnfg->lock);
}
EXPORT_SYMBOL(cfcnfg_add_phy_layer);
diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c
index e22671bed669..5cf52225692e 100644
--- a/net/caif/cfctrl.c
+++ b/net/caif/cfctrl.c
@@ -35,15 +35,12 @@ struct cflayer *cfctrl_create(void)
{
struct dev_info dev_info;
struct cfctrl *this =
- kmalloc(sizeof(struct cfctrl), GFP_ATOMIC);
- if (!this) {
- pr_warn("Out of memory\n");
+ kzalloc(sizeof(struct cfctrl), GFP_ATOMIC);
+ if (!this)
return NULL;
- }
caif_assert(offsetof(struct cfctrl, serv.layer) == 0);
memset(&dev_info, 0, sizeof(dev_info));
dev_info.id = 0xff;
- memset(this, 0, sizeof(*this));
cfsrvl_init(&this->serv, 0, &dev_info, false);
atomic_set(&this->req_seq_no, 1);
atomic_set(&this->rsp_seq_no, 1);
@@ -180,10 +177,8 @@ void cfctrl_enum_req(struct cflayer *layer, u8 physlinkid)
struct cfctrl *cfctrl = container_obj(layer);
struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
struct cflayer *dn = cfctrl->serv.layer.dn;
- if (!pkt) {
- pr_warn("Out of memory\n");
+ if (!pkt)
return;
- }
if (!dn) {
pr_debug("not able to send enum request\n");
return;
@@ -224,10 +219,8 @@ int cfctrl_linkup_request(struct cflayer *layer,
}
pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
- if (!pkt) {
- pr_warn("Out of memory\n");
+ if (!pkt)
return -ENOMEM;
- }
cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_SETUP);
cfpkt_addbdy(pkt, (param->chtype << 4) | param->linktype);
cfpkt_addbdy(pkt, (param->priority << 3) | param->phyid);
@@ -275,10 +268,8 @@ int cfctrl_linkup_request(struct cflayer *layer,
return -EINVAL;
}
req = kzalloc(sizeof(*req), GFP_KERNEL);
- if (!req) {
- pr_warn("Out of memory\n");
+ if (!req)
return -ENOMEM;
- }
req->client_layer = user_layer;
req->cmd = CFCTRL_CMD_LINK_SETUP;
req->param = *param;
@@ -312,10 +303,8 @@ int cfctrl_linkdown_req(struct cflayer *layer, u8 channelid,
struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
struct cflayer *dn = cfctrl->serv.layer.dn;
- if (!pkt) {
- pr_warn("Out of memory\n");
+ if (!pkt)
return -ENOMEM;
- }
if (!dn) {
pr_debug("not able to send link-down request\n");
diff --git a/net/caif/cfdbgl.c b/net/caif/cfdbgl.c
index 11a2af4c162a..65d6ef3cf9aa 100644
--- a/net/caif/cfdbgl.c
+++ b/net/caif/cfdbgl.c
@@ -19,13 +19,10 @@ static int cfdbgl_transmit(struct cflayer *layr, struct cfpkt *pkt);
struct cflayer *cfdbgl_create(u8 channel_id, struct dev_info *dev_info)
{
- struct cfsrvl *dbg = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
- if (!dbg) {
- pr_warn("Out of memory\n");
+ struct cfsrvl *dbg = kzalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
+ if (!dbg)
return NULL;
- }
caif_assert(offsetof(struct cfsrvl, layer) == 0);
- memset(dbg, 0, sizeof(struct cfsrvl));
cfsrvl_init(dbg, channel_id, dev_info, false);
dbg->layer.receive = cfdbgl_receive;
dbg->layer.transmit = cfdbgl_transmit;
diff --git a/net/caif/cfdgml.c b/net/caif/cfdgml.c
index 0382dec84fdc..0f5ff27aa41c 100644
--- a/net/caif/cfdgml.c
+++ b/net/caif/cfdgml.c
@@ -26,13 +26,10 @@ static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt);
struct cflayer *cfdgml_create(u8 channel_id, struct dev_info *dev_info)
{
- struct cfsrvl *dgm = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
- if (!dgm) {
- pr_warn("Out of memory\n");
+ struct cfsrvl *dgm = kzalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
+ if (!dgm)
return NULL;
- }
caif_assert(offsetof(struct cfsrvl, layer) == 0);
- memset(dgm, 0, sizeof(struct cfsrvl));
cfsrvl_init(dgm, channel_id, dev_info, true);
dgm->layer.receive = cfdgml_receive;
dgm->layer.transmit = cfdgml_transmit;
diff --git a/net/caif/cffrml.c b/net/caif/cffrml.c
index 04204b202718..f39921171d0d 100644
--- a/net/caif/cffrml.c
+++ b/net/caif/cffrml.c
@@ -34,11 +34,9 @@ static u32 cffrml_rcv_error;
static u32 cffrml_rcv_checsum_error;
struct cflayer *cffrml_create(u16 phyid, bool use_fcs)
{
- struct cffrml *this = kmalloc(sizeof(struct cffrml), GFP_ATOMIC);
- if (!this) {
- pr_warn("Out of memory\n");
+ struct cffrml *this = kzalloc(sizeof(struct cffrml), GFP_ATOMIC);
+ if (!this)
return NULL;
- }
this->pcpu_refcnt = alloc_percpu(int);
if (this->pcpu_refcnt == NULL) {
kfree(this);
@@ -47,7 +45,6 @@ struct cflayer *cffrml_create(u16 phyid, bool use_fcs)
caif_assert(offsetof(struct cffrml, layer) == 0);
- memset(this, 0, sizeof(struct cflayer));
this->layer.receive = cffrml_receive;
this->layer.transmit = cffrml_transmit;
this->layer.ctrlcmd = cffrml_ctrlcmd;
diff --git a/net/caif/cfmuxl.c b/net/caif/cfmuxl.c
index c23979e79dfa..b36f24a4c8e7 100644
--- a/net/caif/cfmuxl.c
+++ b/net/caif/cfmuxl.c
@@ -108,7 +108,7 @@ struct cflayer *cfmuxl_remove_dnlayer(struct cflayer *layr, u8 phyid)
int idx = phyid % DN_CACHE_SIZE;
spin_lock_bh(&muxl->transmit_lock);
- rcu_assign_pointer(muxl->dn_cache[idx], NULL);
+ RCU_INIT_POINTER(muxl->dn_cache[idx], NULL);
dn = get_from_id(&muxl->frml_list, phyid);
if (dn == NULL)
goto out;
@@ -164,7 +164,7 @@ struct cflayer *cfmuxl_remove_uplayer(struct cflayer *layr, u8 id)
if (up == NULL)
goto out;
- rcu_assign_pointer(muxl->up_cache[idx], NULL);
+ RCU_INIT_POINTER(muxl->up_cache[idx], NULL);
list_del_rcu(&up->node);
out:
spin_unlock_bh(&muxl->receive_lock);
@@ -261,7 +261,7 @@ static void cfmuxl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
idx = layer->id % UP_CACHE_SIZE;
spin_lock_bh(&muxl->receive_lock);
- rcu_assign_pointer(muxl->up_cache[idx], NULL);
+ RCU_INIT_POINTER(muxl->up_cache[idx], NULL);
list_del_rcu(&layer->node);
spin_unlock_bh(&muxl->receive_lock);
}
diff --git a/net/caif/cfrfml.c b/net/caif/cfrfml.c
index 0deabb440051..81660f809713 100644
--- a/net/caif/cfrfml.c
+++ b/net/caif/cfrfml.c
@@ -46,13 +46,10 @@ struct cflayer *cfrfml_create(u8 channel_id, struct dev_info *dev_info,
int mtu_size)
{
int tmp;
- struct cfrfml *this =
- kzalloc(sizeof(struct cfrfml), GFP_ATOMIC);
+ struct cfrfml *this = kzalloc(sizeof(struct cfrfml), GFP_ATOMIC);
- if (!this) {
- pr_warn("Out of memory\n");
+ if (!this)
return NULL;
- }
cfsrvl_init(&this->serv, channel_id, dev_info, false);
this->serv.release = cfrfml_release;
diff --git a/net/caif/cfserl.c b/net/caif/cfserl.c
index 2715c84cfa87..797c8d165993 100644
--- a/net/caif/cfserl.c
+++ b/net/caif/cfserl.c
@@ -33,13 +33,10 @@ static void cfserl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
struct cflayer *cfserl_create(int type, int instance, bool use_stx)
{
- struct cfserl *this = kmalloc(sizeof(struct cfserl), GFP_ATOMIC);
- if (!this) {
- pr_warn("Out of memory\n");
+ struct cfserl *this = kzalloc(sizeof(struct cfserl), GFP_ATOMIC);
+ if (!this)
return NULL;
- }
caif_assert(offsetof(struct cfserl, layer) == 0);
- memset(this, 0, sizeof(struct cfserl));
this->layer.receive = cfserl_receive;
this->layer.transmit = cfserl_transmit;
this->layer.ctrlcmd = cfserl_ctrlcmd;
diff --git a/net/caif/cfsrvl.c b/net/caif/cfsrvl.c
index 535a1e72b366..b99f5b22689d 100644
--- a/net/caif/cfsrvl.c
+++ b/net/caif/cfsrvl.c
@@ -108,10 +108,8 @@ static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
struct caif_payload_info *info;
u8 flow_on = SRVL_FLOW_ON;
pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
- if (!pkt) {
- pr_warn("Out of memory\n");
+ if (!pkt)
return -ENOMEM;
- }
if (cfpkt_add_head(pkt, &flow_on, 1) < 0) {
pr_err("Packet is erroneous!\n");
@@ -130,10 +128,8 @@ static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
struct caif_payload_info *info;
u8 flow_off = SRVL_FLOW_OFF;
pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
- if (!pkt) {
- pr_warn("Out of memory\n");
+ if (!pkt)
return -ENOMEM;
- }
if (cfpkt_add_head(pkt, &flow_off, 1) < 0) {
pr_err("Packet is erroneous!\n");
diff --git a/net/caif/cfutill.c b/net/caif/cfutill.c
index 98e027db18ed..53e49f3e3af3 100644
--- a/net/caif/cfutill.c
+++ b/net/caif/cfutill.c
@@ -26,13 +26,10 @@ static int cfutill_transmit(struct cflayer *layr, struct cfpkt *pkt);
struct cflayer *cfutill_create(u8 channel_id, struct dev_info *dev_info)
{
- struct cfsrvl *util = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
- if (!util) {
- pr_warn("Out of memory\n");
+ struct cfsrvl *util = kzalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
+ if (!util)
return NULL;
- }
caif_assert(offsetof(struct cfsrvl, layer) == 0);
- memset(util, 0, sizeof(struct cfsrvl));
cfsrvl_init(util, channel_id, dev_info, true);
util->layer.receive = cfutill_receive;
util->layer.transmit = cfutill_transmit;
diff --git a/net/caif/cfveil.c b/net/caif/cfveil.c
index 3ec83fbc2887..910ab0661f66 100644
--- a/net/caif/cfveil.c
+++ b/net/caif/cfveil.c
@@ -25,13 +25,10 @@ static int cfvei_transmit(struct cflayer *layr, struct cfpkt *pkt);
struct cflayer *cfvei_create(u8 channel_id, struct dev_info *dev_info)
{
- struct cfsrvl *vei = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
- if (!vei) {
- pr_warn("Out of memory\n");
+ struct cfsrvl *vei = kzalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
+ if (!vei)
return NULL;
- }
caif_assert(offsetof(struct cfsrvl, layer) == 0);
- memset(vei, 0, sizeof(struct cfsrvl));
cfsrvl_init(vei, channel_id, dev_info, true);
vei->layer.receive = cfvei_receive;
vei->layer.transmit = cfvei_transmit;
diff --git a/net/caif/cfvidl.c b/net/caif/cfvidl.c
index b2f5989ad455..e3f37db40ac3 100644
--- a/net/caif/cfvidl.c
+++ b/net/caif/cfvidl.c
@@ -21,14 +21,11 @@ static int cfvidl_transmit(struct cflayer *layr, struct cfpkt *pkt);
struct cflayer *cfvidl_create(u8 channel_id, struct dev_info *dev_info)
{
- struct cfsrvl *vid = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
- if (!vid) {
- pr_warn("Out of memory\n");
+ struct cfsrvl *vid = kzalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
+ if (!vid)
return NULL;
- }
caif_assert(offsetof(struct cfsrvl, layer) == 0);
- memset(vid, 0, sizeof(struct cfsrvl));
cfsrvl_init(vid, channel_id, dev_info, false);
vid->layer.receive = cfvidl_receive;
vid->layer.transmit = cfvidl_transmit;
diff --git a/net/can/Kconfig b/net/can/Kconfig
index 89395b2c8bca..03200699d274 100644
--- a/net/can/Kconfig
+++ b/net/can/Kconfig
@@ -40,5 +40,16 @@ config CAN_BCM
CAN messages are used on the bus (e.g. in automotive environments).
To use the Broadcast Manager, use AF_CAN with protocol CAN_BCM.
+config CAN_GW
+ tristate "CAN Gateway/Router (with netlink configuration)"
+ depends on CAN
+ default N
+ ---help---
+ The CAN Gateway/Router is used to route (and modify) CAN frames.
+ It is based on the PF_CAN core infrastructure for msg filtering and
+ msg sending and can optionally modify routed CAN frames on the fly.
+ CAN frames can be routed between CAN network interfaces (one hop).
+ They can be modified with AND/OR/XOR/SET operations as configured
+ by the netlink configuration interface known e.g. from iptables.
source "drivers/net/can/Kconfig"
diff --git a/net/can/Makefile b/net/can/Makefile
index 2d3894b32742..cef49eb1f5c7 100644
--- a/net/can/Makefile
+++ b/net/can/Makefile
@@ -10,3 +10,6 @@ can-raw-y := raw.o
obj-$(CONFIG_CAN_BCM) += can-bcm.o
can-bcm-y := bcm.o
+
+obj-$(CONFIG_CAN_GW) += can-gw.o
+can-gw-y := gw.o
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 8ce926d3b2cb..0ce2ad0696da 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -38,8 +38,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
- * Send feedback to <socketcan-users@lists.berlios.de>
- *
*/
#include <linux/module.h>
@@ -719,7 +717,7 @@ int can_proto_register(const struct can_proto *cp)
proto);
err = -EBUSY;
} else
- rcu_assign_pointer(proto_tab[proto], cp);
+ RCU_INIT_POINTER(proto_tab[proto], cp);
mutex_unlock(&proto_tab_lock);
@@ -740,7 +738,7 @@ void can_proto_unregister(const struct can_proto *cp)
mutex_lock(&proto_tab_lock);
BUG_ON(proto_tab[proto] != cp);
- rcu_assign_pointer(proto_tab[proto], NULL);
+ RCU_INIT_POINTER(proto_tab[proto], NULL);
mutex_unlock(&proto_tab_lock);
synchronize_rcu();
@@ -857,7 +855,7 @@ static __exit void can_exit(void)
struct net_device *dev;
if (stats_timer)
- del_timer(&can_stattimer);
+ del_timer_sync(&can_stattimer);
can_remove_proc();
diff --git a/net/can/af_can.h b/net/can/af_can.h
index 34253b84e30f..fd882dbadad3 100644
--- a/net/can/af_can.h
+++ b/net/can/af_can.h
@@ -35,8 +35,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
- * Send feedback to <socketcan-users@lists.berlios.de>
- *
*/
#ifndef AF_CAN_H
diff --git a/net/can/bcm.c b/net/can/bcm.c
index d6c8ae5b2e6a..151b7730c12c 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -37,8 +37,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
- * Send feedback to <socketcan-users@lists.berlios.de>
- *
*/
#include <linux/module.h>
@@ -344,6 +342,18 @@ static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head,
}
}
+static void bcm_tx_start_timer(struct bcm_op *op)
+{
+ if (op->kt_ival1.tv64 && op->count)
+ hrtimer_start(&op->timer,
+ ktime_add(ktime_get(), op->kt_ival1),
+ HRTIMER_MODE_ABS);
+ else if (op->kt_ival2.tv64)
+ hrtimer_start(&op->timer,
+ ktime_add(ktime_get(), op->kt_ival2),
+ HRTIMER_MODE_ABS);
+}
+
static void bcm_tx_timeout_tsklet(unsigned long data)
{
struct bcm_op *op = (struct bcm_op *)data;
@@ -365,26 +375,12 @@ static void bcm_tx_timeout_tsklet(unsigned long data)
bcm_send_to_user(op, &msg_head, NULL, 0);
}
- }
-
- if (op->kt_ival1.tv64 && (op->count > 0)) {
-
- /* send (next) frame */
bcm_can_tx(op);
- hrtimer_start(&op->timer,
- ktime_add(ktime_get(), op->kt_ival1),
- HRTIMER_MODE_ABS);
- } else {
- if (op->kt_ival2.tv64) {
+ } else if (op->kt_ival2.tv64)
+ bcm_can_tx(op);
- /* send (next) frame */
- bcm_can_tx(op);
- hrtimer_start(&op->timer,
- ktime_add(ktime_get(), op->kt_ival2),
- HRTIMER_MODE_ABS);
- }
- }
+ bcm_tx_start_timer(op);
}
/*
@@ -964,23 +960,20 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
hrtimer_cancel(&op->timer);
}
- if ((op->flags & STARTTIMER) &&
- ((op->kt_ival1.tv64 && op->count) || op->kt_ival2.tv64)) {
-
+ if (op->flags & STARTTIMER) {
+ hrtimer_cancel(&op->timer);
/* spec: send can_frame when starting timer */
op->flags |= TX_ANNOUNCE;
-
- if (op->kt_ival1.tv64 && (op->count > 0)) {
- /* op->count-- is done in bcm_tx_timeout_handler */
- hrtimer_start(&op->timer, op->kt_ival1,
- HRTIMER_MODE_REL);
- } else
- hrtimer_start(&op->timer, op->kt_ival2,
- HRTIMER_MODE_REL);
}
- if (op->flags & TX_ANNOUNCE)
+ if (op->flags & TX_ANNOUNCE) {
bcm_can_tx(op);
+ if (op->count)
+ op->count--;
+ }
+
+ if (op->flags & STARTTIMER)
+ bcm_tx_start_timer(op);
return msg_head->nframes * CFSIZ + MHSIZ;
}
diff --git a/net/can/gw.c b/net/can/gw.c
new file mode 100644
index 000000000000..3d79b127881e
--- /dev/null
+++ b/net/can/gw.c
@@ -0,0 +1,957 @@
+/*
+ * gw.c - CAN frame Gateway/Router/Bridge with netlink interface
+ *
+ * Copyright (c) 2011 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Volkswagen nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provisions of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * The provided data structures and external interfaces from this code
+ * are not restricted to be used by modules with a GPL compatible license.
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/rcupdate.h>
+#include <linux/rculist.h>
+#include <linux/net.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/skbuff.h>
+#include <linux/can.h>
+#include <linux/can/core.h>
+#include <linux/can/gw.h>
+#include <net/rtnetlink.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
+
+#define CAN_GW_VERSION "20101209"
+static __initdata const char banner[] =
+ KERN_INFO "can: netlink gateway (rev " CAN_GW_VERSION ")\n";
+
+MODULE_DESCRIPTION("PF_CAN netlink gateway");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>");
+MODULE_ALIAS("can-gw");
+
+HLIST_HEAD(cgw_list);
+static struct notifier_block notifier;
+
+static struct kmem_cache *cgw_cache __read_mostly;
+
+/* structure that contains the (on-the-fly) CAN frame modifications */
+struct cf_mod {
+ struct {
+ struct can_frame and;
+ struct can_frame or;
+ struct can_frame xor;
+ struct can_frame set;
+ } modframe;
+ struct {
+ u8 and;
+ u8 or;
+ u8 xor;
+ u8 set;
+ } modtype;
+ void (*modfunc[MAX_MODFUNCTIONS])(struct can_frame *cf,
+ struct cf_mod *mod);
+
+ /* CAN frame checksum calculation after CAN frame modifications */
+ struct {
+ struct cgw_csum_xor xor;
+ struct cgw_csum_crc8 crc8;
+ } csum;
+ struct {
+ void (*xor)(struct can_frame *cf, struct cgw_csum_xor *xor);
+ void (*crc8)(struct can_frame *cf, struct cgw_csum_crc8 *crc8);
+ } csumfunc;
+};
+
+
+/*
+ * So far we just support CAN -> CAN routing and frame modifications.
+ *
+ * The internal can_can_gw structure contains data and attributes for
+ * a CAN -> CAN gateway job.
+ */
+struct can_can_gw {
+ struct can_filter filter;
+ int src_idx;
+ int dst_idx;
+};
+
+/* list entry for CAN gateways jobs */
+struct cgw_job {
+ struct hlist_node list;
+ struct rcu_head rcu;
+ u32 handled_frames;
+ u32 dropped_frames;
+ struct cf_mod mod;
+ union {
+ /* CAN frame data source */
+ struct net_device *dev;
+ } src;
+ union {
+ /* CAN frame data destination */
+ struct net_device *dev;
+ } dst;
+ union {
+ struct can_can_gw ccgw;
+ /* tbc */
+ };
+ u8 gwtype;
+ u16 flags;
+};
+
+/* modification functions that are invoked in the hot path in can_can_gw_rcv */
+
+#define MODFUNC(func, op) static void func(struct can_frame *cf, \
+ struct cf_mod *mod) { op ; }
+
+MODFUNC(mod_and_id, cf->can_id &= mod->modframe.and.can_id)
+MODFUNC(mod_and_dlc, cf->can_dlc &= mod->modframe.and.can_dlc)
+MODFUNC(mod_and_data, *(u64 *)cf->data &= *(u64 *)mod->modframe.and.data)
+MODFUNC(mod_or_id, cf->can_id |= mod->modframe.or.can_id)
+MODFUNC(mod_or_dlc, cf->can_dlc |= mod->modframe.or.can_dlc)
+MODFUNC(mod_or_data, *(u64 *)cf->data |= *(u64 *)mod->modframe.or.data)
+MODFUNC(mod_xor_id, cf->can_id ^= mod->modframe.xor.can_id)
+MODFUNC(mod_xor_dlc, cf->can_dlc ^= mod->modframe.xor.can_dlc)
+MODFUNC(mod_xor_data, *(u64 *)cf->data ^= *(u64 *)mod->modframe.xor.data)
+MODFUNC(mod_set_id, cf->can_id = mod->modframe.set.can_id)
+MODFUNC(mod_set_dlc, cf->can_dlc = mod->modframe.set.can_dlc)
+MODFUNC(mod_set_data, *(u64 *)cf->data = *(u64 *)mod->modframe.set.data)
+
+static inline void canframecpy(struct can_frame *dst, struct can_frame *src)
+{
+ /*
+ * Copy the struct members separately to ensure that no uninitialized
+ * data are copied in the 3 bytes hole of the struct. This is needed
+ * to make easy compares of the data in the struct cf_mod.
+ */
+
+ dst->can_id = src->can_id;
+ dst->can_dlc = src->can_dlc;
+ *(u64 *)dst->data = *(u64 *)src->data;
+}
+
+static int cgw_chk_csum_parms(s8 fr, s8 to, s8 re)
+{
+ /*
+ * absolute dlc values 0 .. 7 => 0 .. 7, e.g. data [0]
+ * relative to received dlc -1 .. -8 :
+ * e.g. for received dlc = 8
+ * -1 => index = 7 (data[7])
+ * -3 => index = 5 (data[5])
+ * -8 => index = 0 (data[0])
+ */
+
+ if (fr > -9 && fr < 8 &&
+ to > -9 && to < 8 &&
+ re > -9 && re < 8)
+ return 0;
+ else
+ return -EINVAL;
+}
+
+static inline int calc_idx(int idx, int rx_dlc)
+{
+ if (idx < 0)
+ return rx_dlc + idx;
+ else
+ return idx;
+}
+
+static void cgw_csum_xor_rel(struct can_frame *cf, struct cgw_csum_xor *xor)
+{
+ int from = calc_idx(xor->from_idx, cf->can_dlc);
+ int to = calc_idx(xor->to_idx, cf->can_dlc);
+ int res = calc_idx(xor->result_idx, cf->can_dlc);
+ u8 val = xor->init_xor_val;
+ int i;
+
+ if (from < 0 || to < 0 || res < 0)
+ return;
+
+ if (from <= to) {
+ for (i = from; i <= to; i++)
+ val ^= cf->data[i];
+ } else {
+ for (i = from; i >= to; i--)
+ val ^= cf->data[i];
+ }
+
+ cf->data[res] = val;
+}
+
+static void cgw_csum_xor_pos(struct can_frame *cf, struct cgw_csum_xor *xor)
+{
+ u8 val = xor->init_xor_val;
+ int i;
+
+ for (i = xor->from_idx; i <= xor->to_idx; i++)
+ val ^= cf->data[i];
+
+ cf->data[xor->result_idx] = val;
+}
+
+static void cgw_csum_xor_neg(struct can_frame *cf, struct cgw_csum_xor *xor)
+{
+ u8 val = xor->init_xor_val;
+ int i;
+
+ for (i = xor->from_idx; i >= xor->to_idx; i--)
+ val ^= cf->data[i];
+
+ cf->data[xor->result_idx] = val;
+}
+
+static void cgw_csum_crc8_rel(struct can_frame *cf, struct cgw_csum_crc8 *crc8)
+{
+ int from = calc_idx(crc8->from_idx, cf->can_dlc);
+ int to = calc_idx(crc8->to_idx, cf->can_dlc);
+ int res = calc_idx(crc8->result_idx, cf->can_dlc);
+ u8 crc = crc8->init_crc_val;
+ int i;
+
+ if (from < 0 || to < 0 || res < 0)
+ return;
+
+ if (from <= to) {
+ for (i = crc8->from_idx; i <= crc8->to_idx; i++)
+ crc = crc8->crctab[crc^cf->data[i]];
+ } else {
+ for (i = crc8->from_idx; i >= crc8->to_idx; i--)
+ crc = crc8->crctab[crc^cf->data[i]];
+ }
+
+ switch (crc8->profile) {
+
+ case CGW_CRC8PRF_1U8:
+ crc = crc8->crctab[crc^crc8->profile_data[0]];
+ break;
+
+ case CGW_CRC8PRF_16U8:
+ crc = crc8->crctab[crc^crc8->profile_data[cf->data[1] & 0xF]];
+ break;
+
+ case CGW_CRC8PRF_SFFID_XOR:
+ crc = crc8->crctab[crc^(cf->can_id & 0xFF)^
+ (cf->can_id >> 8 & 0xFF)];
+ break;
+
+ }
+
+ cf->data[crc8->result_idx] = crc^crc8->final_xor_val;
+}
+
+static void cgw_csum_crc8_pos(struct can_frame *cf, struct cgw_csum_crc8 *crc8)
+{
+ u8 crc = crc8->init_crc_val;
+ int i;
+
+ for (i = crc8->from_idx; i <= crc8->to_idx; i++)
+ crc = crc8->crctab[crc^cf->data[i]];
+
+ switch (crc8->profile) {
+
+ case CGW_CRC8PRF_1U8:
+ crc = crc8->crctab[crc^crc8->profile_data[0]];
+ break;
+
+ case CGW_CRC8PRF_16U8:
+ crc = crc8->crctab[crc^crc8->profile_data[cf->data[1] & 0xF]];
+ break;
+
+ case CGW_CRC8PRF_SFFID_XOR:
+ crc = crc8->crctab[crc^(cf->can_id & 0xFF)^
+ (cf->can_id >> 8 & 0xFF)];
+ break;
+ }
+
+ cf->data[crc8->result_idx] = crc^crc8->final_xor_val;
+}
+
+static void cgw_csum_crc8_neg(struct can_frame *cf, struct cgw_csum_crc8 *crc8)
+{
+ u8 crc = crc8->init_crc_val;
+ int i;
+
+ for (i = crc8->from_idx; i >= crc8->to_idx; i--)
+ crc = crc8->crctab[crc^cf->data[i]];
+
+ switch (crc8->profile) {
+
+ case CGW_CRC8PRF_1U8:
+ crc = crc8->crctab[crc^crc8->profile_data[0]];
+ break;
+
+ case CGW_CRC8PRF_16U8:
+ crc = crc8->crctab[crc^crc8->profile_data[cf->data[1] & 0xF]];
+ break;
+
+ case CGW_CRC8PRF_SFFID_XOR:
+ crc = crc8->crctab[crc^(cf->can_id & 0xFF)^
+ (cf->can_id >> 8 & 0xFF)];
+ break;
+ }
+
+ cf->data[crc8->result_idx] = crc^crc8->final_xor_val;
+}
+
+/* the receive & process & send function */
+static void can_can_gw_rcv(struct sk_buff *skb, void *data)
+{
+ struct cgw_job *gwj = (struct cgw_job *)data;
+ struct can_frame *cf;
+ struct sk_buff *nskb;
+ int modidx = 0;
+
+ /* do not handle already routed frames - see comment below */
+ if (skb_mac_header_was_set(skb))
+ return;
+
+ if (!(gwj->dst.dev->flags & IFF_UP)) {
+ gwj->dropped_frames++;
+ return;
+ }
+
+ /*
+ * clone the given skb, which has not been done in can_rcv()
+ *
+ * When there is at least one modification function activated,
+ * we need to copy the skb as we want to modify skb->data.
+ */
+ if (gwj->mod.modfunc[0])
+ nskb = skb_copy(skb, GFP_ATOMIC);
+ else
+ nskb = skb_clone(skb, GFP_ATOMIC);
+
+ if (!nskb) {
+ gwj->dropped_frames++;
+ return;
+ }
+
+ /*
+ * Mark routed frames by setting some mac header length which is
+ * not relevant for the CAN frames located in the skb->data section.
+ *
+ * As dev->header_ops is not set in CAN netdevices no one is ever
+ * accessing the various header offsets in the CAN skbuffs anyway.
+ * E.g. using the packet socket to read CAN frames is still working.
+ */
+ skb_set_mac_header(nskb, 8);
+ nskb->dev = gwj->dst.dev;
+
+ /* pointer to modifiable CAN frame */
+ cf = (struct can_frame *)nskb->data;
+
+ /* perform preprocessed modification functions if there are any */
+ while (modidx < MAX_MODFUNCTIONS && gwj->mod.modfunc[modidx])
+ (*gwj->mod.modfunc[modidx++])(cf, &gwj->mod);
+
+ /* check for checksum updates when the CAN frame has been modified */
+ if (modidx) {
+ if (gwj->mod.csumfunc.crc8)
+ (*gwj->mod.csumfunc.crc8)(cf, &gwj->mod.csum.crc8);
+
+ if (gwj->mod.csumfunc.xor)
+ (*gwj->mod.csumfunc.xor)(cf, &gwj->mod.csum.xor);
+ }
+
+ /* clear the skb timestamp if not configured the other way */
+ if (!(gwj->flags & CGW_FLAGS_CAN_SRC_TSTAMP))
+ nskb->tstamp.tv64 = 0;
+
+ /* send to netdevice */
+ if (can_send(nskb, gwj->flags & CGW_FLAGS_CAN_ECHO))
+ gwj->dropped_frames++;
+ else
+ gwj->handled_frames++;
+}
+
+static inline int cgw_register_filter(struct cgw_job *gwj)
+{
+ return can_rx_register(gwj->src.dev, gwj->ccgw.filter.can_id,
+ gwj->ccgw.filter.can_mask, can_can_gw_rcv,
+ gwj, "gw");
+}
+
+static inline void cgw_unregister_filter(struct cgw_job *gwj)
+{
+ can_rx_unregister(gwj->src.dev, gwj->ccgw.filter.can_id,
+ gwj->ccgw.filter.can_mask, can_can_gw_rcv, gwj);
+}
+
+static int cgw_notifier(struct notifier_block *nb,
+ unsigned long msg, void *data)
+{
+ struct net_device *dev = (struct net_device *)data;
+
+ if (!net_eq(dev_net(dev), &init_net))
+ return NOTIFY_DONE;
+ if (dev->type != ARPHRD_CAN)
+ return NOTIFY_DONE;
+
+ if (msg == NETDEV_UNREGISTER) {
+
+ struct cgw_job *gwj = NULL;
+ struct hlist_node *n, *nx;
+
+ ASSERT_RTNL();
+
+ hlist_for_each_entry_safe(gwj, n, nx, &cgw_list, list) {
+
+ if (gwj->src.dev == dev || gwj->dst.dev == dev) {
+ hlist_del(&gwj->list);
+ cgw_unregister_filter(gwj);
+ kfree(gwj);
+ }
+ }
+ }
+
+ return NOTIFY_DONE;
+}
+
+static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj)
+{
+ struct cgw_frame_mod mb;
+ struct rtcanmsg *rtcan;
+ struct nlmsghdr *nlh = nlmsg_put(skb, 0, 0, 0, sizeof(*rtcan), 0);
+ if (!nlh)
+ return -EMSGSIZE;
+
+ rtcan = nlmsg_data(nlh);
+ rtcan->can_family = AF_CAN;
+ rtcan->gwtype = gwj->gwtype;
+ rtcan->flags = gwj->flags;
+
+ /* add statistics if available */
+
+ if (gwj->handled_frames) {
+ if (nla_put_u32(skb, CGW_HANDLED, gwj->handled_frames) < 0)
+ goto cancel;
+ else
+ nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(sizeof(u32));
+ }
+
+ if (gwj->dropped_frames) {
+ if (nla_put_u32(skb, CGW_DROPPED, gwj->dropped_frames) < 0)
+ goto cancel;
+ else
+ nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(sizeof(u32));
+ }
+
+ /* check non default settings of attributes */
+
+ if (gwj->mod.modtype.and) {
+ memcpy(&mb.cf, &gwj->mod.modframe.and, sizeof(mb.cf));
+ mb.modtype = gwj->mod.modtype.and;
+ if (nla_put(skb, CGW_MOD_AND, sizeof(mb), &mb) < 0)
+ goto cancel;
+ else
+ nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(sizeof(mb));
+ }
+
+ if (gwj->mod.modtype.or) {
+ memcpy(&mb.cf, &gwj->mod.modframe.or, sizeof(mb.cf));
+ mb.modtype = gwj->mod.modtype.or;
+ if (nla_put(skb, CGW_MOD_OR, sizeof(mb), &mb) < 0)
+ goto cancel;
+ else
+ nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(sizeof(mb));
+ }
+
+ if (gwj->mod.modtype.xor) {
+ memcpy(&mb.cf, &gwj->mod.modframe.xor, sizeof(mb.cf));
+ mb.modtype = gwj->mod.modtype.xor;
+ if (nla_put(skb, CGW_MOD_XOR, sizeof(mb), &mb) < 0)
+ goto cancel;
+ else
+ nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(sizeof(mb));
+ }
+
+ if (gwj->mod.modtype.set) {
+ memcpy(&mb.cf, &gwj->mod.modframe.set, sizeof(mb.cf));
+ mb.modtype = gwj->mod.modtype.set;
+ if (nla_put(skb, CGW_MOD_SET, sizeof(mb), &mb) < 0)
+ goto cancel;
+ else
+ nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(sizeof(mb));
+ }
+
+ if (gwj->mod.csumfunc.crc8) {
+ if (nla_put(skb, CGW_CS_CRC8, CGW_CS_CRC8_LEN,
+ &gwj->mod.csum.crc8) < 0)
+ goto cancel;
+ else
+ nlh->nlmsg_len += NLA_HDRLEN + \
+ NLA_ALIGN(CGW_CS_CRC8_LEN);
+ }
+
+ if (gwj->mod.csumfunc.xor) {
+ if (nla_put(skb, CGW_CS_XOR, CGW_CS_XOR_LEN,
+ &gwj->mod.csum.xor) < 0)
+ goto cancel;
+ else
+ nlh->nlmsg_len += NLA_HDRLEN + \
+ NLA_ALIGN(CGW_CS_XOR_LEN);
+ }
+
+ if (gwj->gwtype == CGW_TYPE_CAN_CAN) {
+
+ if (gwj->ccgw.filter.can_id || gwj->ccgw.filter.can_mask) {
+ if (nla_put(skb, CGW_FILTER, sizeof(struct can_filter),
+ &gwj->ccgw.filter) < 0)
+ goto cancel;
+ else
+ nlh->nlmsg_len += NLA_HDRLEN +
+ NLA_ALIGN(sizeof(struct can_filter));
+ }
+
+ if (nla_put_u32(skb, CGW_SRC_IF, gwj->ccgw.src_idx) < 0)
+ goto cancel;
+ else
+ nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(sizeof(u32));
+
+ if (nla_put_u32(skb, CGW_DST_IF, gwj->ccgw.dst_idx) < 0)
+ goto cancel;
+ else
+ nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(sizeof(u32));
+ }
+
+ return skb->len;
+
+cancel:
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
+}
+
+/* Dump information about all CAN gateway jobs, in response to RTM_GETROUTE */
+static int cgw_dump_jobs(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ struct cgw_job *gwj = NULL;
+ struct hlist_node *n;
+ int idx = 0;
+ int s_idx = cb->args[0];
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(gwj, n, &cgw_list, list) {
+ if (idx < s_idx)
+ goto cont;
+
+ if (cgw_put_job(skb, gwj) < 0)
+ break;
+cont:
+ idx++;
+ }
+ rcu_read_unlock();
+
+ cb->args[0] = idx;
+
+ return skb->len;
+}
+
+/* check for common and gwtype specific attributes */
+static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
+ u8 gwtype, void *gwtypeattr)
+{
+ struct nlattr *tb[CGW_MAX+1];
+ struct cgw_frame_mod mb;
+ int modidx = 0;
+ int err = 0;
+
+ /* initialize modification & checksum data space */
+ memset(mod, 0, sizeof(*mod));
+
+ err = nlmsg_parse(nlh, sizeof(struct rtcanmsg), tb, CGW_MAX, NULL);
+ if (err < 0)
+ return err;
+
+ /* check for AND/OR/XOR/SET modifications */
+
+ if (tb[CGW_MOD_AND] &&
+ nla_len(tb[CGW_MOD_AND]) == CGW_MODATTR_LEN) {
+ nla_memcpy(&mb, tb[CGW_MOD_AND], CGW_MODATTR_LEN);
+
+ canframecpy(&mod->modframe.and, &mb.cf);
+ mod->modtype.and = mb.modtype;
+
+ if (mb.modtype & CGW_MOD_ID)
+ mod->modfunc[modidx++] = mod_and_id;
+
+ if (mb.modtype & CGW_MOD_DLC)
+ mod->modfunc[modidx++] = mod_and_dlc;
+
+ if (mb.modtype & CGW_MOD_DATA)
+ mod->modfunc[modidx++] = mod_and_data;
+ }
+
+ if (tb[CGW_MOD_OR] &&
+ nla_len(tb[CGW_MOD_OR]) == CGW_MODATTR_LEN) {
+ nla_memcpy(&mb, tb[CGW_MOD_OR], CGW_MODATTR_LEN);
+
+ canframecpy(&mod->modframe.or, &mb.cf);
+ mod->modtype.or = mb.modtype;
+
+ if (mb.modtype & CGW_MOD_ID)
+ mod->modfunc[modidx++] = mod_or_id;
+
+ if (mb.modtype & CGW_MOD_DLC)
+ mod->modfunc[modidx++] = mod_or_dlc;
+
+ if (mb.modtype & CGW_MOD_DATA)
+ mod->modfunc[modidx++] = mod_or_data;
+ }
+
+ if (tb[CGW_MOD_XOR] &&
+ nla_len(tb[CGW_MOD_XOR]) == CGW_MODATTR_LEN) {
+ nla_memcpy(&mb, tb[CGW_MOD_XOR], CGW_MODATTR_LEN);
+
+ canframecpy(&mod->modframe.xor, &mb.cf);
+ mod->modtype.xor = mb.modtype;
+
+ if (mb.modtype & CGW_MOD_ID)
+ mod->modfunc[modidx++] = mod_xor_id;
+
+ if (mb.modtype & CGW_MOD_DLC)
+ mod->modfunc[modidx++] = mod_xor_dlc;
+
+ if (mb.modtype & CGW_MOD_DATA)
+ mod->modfunc[modidx++] = mod_xor_data;
+ }
+
+ if (tb[CGW_MOD_SET] &&
+ nla_len(tb[CGW_MOD_SET]) == CGW_MODATTR_LEN) {
+ nla_memcpy(&mb, tb[CGW_MOD_SET], CGW_MODATTR_LEN);
+
+ canframecpy(&mod->modframe.set, &mb.cf);
+ mod->modtype.set = mb.modtype;
+
+ if (mb.modtype & CGW_MOD_ID)
+ mod->modfunc[modidx++] = mod_set_id;
+
+ if (mb.modtype & CGW_MOD_DLC)
+ mod->modfunc[modidx++] = mod_set_dlc;
+
+ if (mb.modtype & CGW_MOD_DATA)
+ mod->modfunc[modidx++] = mod_set_data;
+ }
+
+ /* check for checksum operations after CAN frame modifications */
+ if (modidx) {
+
+ if (tb[CGW_CS_CRC8] &&
+ nla_len(tb[CGW_CS_CRC8]) == CGW_CS_CRC8_LEN) {
+
+ struct cgw_csum_crc8 *c = (struct cgw_csum_crc8 *)\
+ nla_data(tb[CGW_CS_CRC8]);
+
+ err = cgw_chk_csum_parms(c->from_idx, c->to_idx,
+ c->result_idx);
+ if (err)
+ return err;
+
+ nla_memcpy(&mod->csum.crc8, tb[CGW_CS_CRC8],
+ CGW_CS_CRC8_LEN);
+
+ /*
+ * select dedicated processing function to reduce
+ * runtime operations in receive hot path.
+ */
+ if (c->from_idx < 0 || c->to_idx < 0 ||
+ c->result_idx < 0)
+ mod->csumfunc.crc8 = cgw_csum_crc8_rel;
+ else if (c->from_idx <= c->to_idx)
+ mod->csumfunc.crc8 = cgw_csum_crc8_pos;
+ else
+ mod->csumfunc.crc8 = cgw_csum_crc8_neg;
+ }
+
+ if (tb[CGW_CS_XOR] &&
+ nla_len(tb[CGW_CS_XOR]) == CGW_CS_XOR_LEN) {
+
+ struct cgw_csum_xor *c = (struct cgw_csum_xor *)\
+ nla_data(tb[CGW_CS_XOR]);
+
+ err = cgw_chk_csum_parms(c->from_idx, c->to_idx,
+ c->result_idx);
+ if (err)
+ return err;
+
+ nla_memcpy(&mod->csum.xor, tb[CGW_CS_XOR],
+ CGW_CS_XOR_LEN);
+
+ /*
+ * select dedicated processing function to reduce
+ * runtime operations in receive hot path.
+ */
+ if (c->from_idx < 0 || c->to_idx < 0 ||
+ c->result_idx < 0)
+ mod->csumfunc.xor = cgw_csum_xor_rel;
+ else if (c->from_idx <= c->to_idx)
+ mod->csumfunc.xor = cgw_csum_xor_pos;
+ else
+ mod->csumfunc.xor = cgw_csum_xor_neg;
+ }
+ }
+
+ if (gwtype == CGW_TYPE_CAN_CAN) {
+
+ /* check CGW_TYPE_CAN_CAN specific attributes */
+
+ struct can_can_gw *ccgw = (struct can_can_gw *)gwtypeattr;
+ memset(ccgw, 0, sizeof(*ccgw));
+
+ /* check for can_filter in attributes */
+ if (tb[CGW_FILTER] &&
+ nla_len(tb[CGW_FILTER]) == sizeof(struct can_filter))
+ nla_memcpy(&ccgw->filter, tb[CGW_FILTER],
+ sizeof(struct can_filter));
+
+ err = -ENODEV;
+
+ /* specifying two interfaces is mandatory */
+ if (!tb[CGW_SRC_IF] || !tb[CGW_DST_IF])
+ return err;
+
+ if (nla_len(tb[CGW_SRC_IF]) == sizeof(u32))
+ nla_memcpy(&ccgw->src_idx, tb[CGW_SRC_IF],
+ sizeof(u32));
+
+ if (nla_len(tb[CGW_DST_IF]) == sizeof(u32))
+ nla_memcpy(&ccgw->dst_idx, tb[CGW_DST_IF],
+ sizeof(u32));
+
+ /* both indices set to 0 for flushing all routing entries */
+ if (!ccgw->src_idx && !ccgw->dst_idx)
+ return 0;
+
+ /* only one index set to 0 is an error */
+ if (!ccgw->src_idx || !ccgw->dst_idx)
+ return err;
+ }
+
+ /* add the checks for other gwtypes here */
+
+ return 0;
+}
+
+static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
+ void *arg)
+{
+ struct rtcanmsg *r;
+ struct cgw_job *gwj;
+ int err = 0;
+
+ if (nlmsg_len(nlh) < sizeof(*r))
+ return -EINVAL;
+
+ r = nlmsg_data(nlh);
+ if (r->can_family != AF_CAN)
+ return -EPFNOSUPPORT;
+
+ /* so far we only support CAN -> CAN routings */
+ if (r->gwtype != CGW_TYPE_CAN_CAN)
+ return -EINVAL;
+
+ gwj = kmem_cache_alloc(cgw_cache, GFP_KERNEL);
+ if (!gwj)
+ return -ENOMEM;
+
+ gwj->handled_frames = 0;
+ gwj->dropped_frames = 0;
+ gwj->flags = r->flags;
+ gwj->gwtype = r->gwtype;
+
+ err = cgw_parse_attr(nlh, &gwj->mod, CGW_TYPE_CAN_CAN, &gwj->ccgw);
+ if (err < 0)
+ goto out;
+
+ err = -ENODEV;
+
+ /* ifindex == 0 is not allowed for job creation */
+ if (!gwj->ccgw.src_idx || !gwj->ccgw.dst_idx)
+ goto out;
+
+ gwj->src.dev = dev_get_by_index(&init_net, gwj->ccgw.src_idx);
+
+ if (!gwj->src.dev)
+ goto out;
+
+ /* check for CAN netdev not using header_ops - see gw_rcv() */
+ if (gwj->src.dev->type != ARPHRD_CAN || gwj->src.dev->header_ops)
+ goto put_src_out;
+
+ gwj->dst.dev = dev_get_by_index(&init_net, gwj->ccgw.dst_idx);
+
+ if (!gwj->dst.dev)
+ goto put_src_out;
+
+ /* check for CAN netdev not using header_ops - see gw_rcv() */
+ if (gwj->dst.dev->type != ARPHRD_CAN || gwj->dst.dev->header_ops)
+ goto put_src_dst_out;
+
+ ASSERT_RTNL();
+
+ err = cgw_register_filter(gwj);
+ if (!err)
+ hlist_add_head_rcu(&gwj->list, &cgw_list);
+
+put_src_dst_out:
+ dev_put(gwj->dst.dev);
+put_src_out:
+ dev_put(gwj->src.dev);
+out:
+ if (err)
+ kmem_cache_free(cgw_cache, gwj);
+
+ return err;
+}
+
+static void cgw_remove_all_jobs(void)
+{
+ struct cgw_job *gwj = NULL;
+ struct hlist_node *n, *nx;
+
+ ASSERT_RTNL();
+
+ hlist_for_each_entry_safe(gwj, n, nx, &cgw_list, list) {
+ hlist_del(&gwj->list);
+ cgw_unregister_filter(gwj);
+ kfree(gwj);
+ }
+}
+
+static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+{
+ struct cgw_job *gwj = NULL;
+ struct hlist_node *n, *nx;
+ struct rtcanmsg *r;
+ struct cf_mod mod;
+ struct can_can_gw ccgw;
+ int err = 0;
+
+ if (nlmsg_len(nlh) < sizeof(*r))
+ return -EINVAL;
+
+ r = nlmsg_data(nlh);
+ if (r->can_family != AF_CAN)
+ return -EPFNOSUPPORT;
+
+ /* so far we only support CAN -> CAN routings */
+ if (r->gwtype != CGW_TYPE_CAN_CAN)
+ return -EINVAL;
+
+ err = cgw_parse_attr(nlh, &mod, CGW_TYPE_CAN_CAN, &ccgw);
+ if (err < 0)
+ return err;
+
+ /* two interface indices both set to 0 => remove all entries */
+ if (!ccgw.src_idx && !ccgw.dst_idx) {
+ cgw_remove_all_jobs();
+ return 0;
+ }
+
+ err = -EINVAL;
+
+ ASSERT_RTNL();
+
+ /* remove only the first matching entry */
+ hlist_for_each_entry_safe(gwj, n, nx, &cgw_list, list) {
+
+ if (gwj->flags != r->flags)
+ continue;
+
+ if (memcmp(&gwj->mod, &mod, sizeof(mod)))
+ continue;
+
+ /* if (r->gwtype == CGW_TYPE_CAN_CAN) - is made sure here */
+ if (memcmp(&gwj->ccgw, &ccgw, sizeof(ccgw)))
+ continue;
+
+ hlist_del(&gwj->list);
+ cgw_unregister_filter(gwj);
+ kfree(gwj);
+ err = 0;
+ break;
+ }
+
+ return err;
+}
+
+static __init int cgw_module_init(void)
+{
+ printk(banner);
+
+ cgw_cache = kmem_cache_create("can_gw", sizeof(struct cgw_job),
+ 0, 0, NULL);
+
+ if (!cgw_cache)
+ return -ENOMEM;
+
+ /* set notifier */
+ notifier.notifier_call = cgw_notifier;
+ register_netdevice_notifier(&notifier);
+
+ if (__rtnl_register(PF_CAN, RTM_GETROUTE, NULL, cgw_dump_jobs, NULL)) {
+ unregister_netdevice_notifier(&notifier);
+ kmem_cache_destroy(cgw_cache);
+ return -ENOBUFS;
+ }
+
+ /* Only the first call to __rtnl_register can fail */
+ __rtnl_register(PF_CAN, RTM_NEWROUTE, cgw_create_job, NULL, NULL);
+ __rtnl_register(PF_CAN, RTM_DELROUTE, cgw_remove_job, NULL, NULL);
+
+ return 0;
+}
+
+static __exit void cgw_module_exit(void)
+{
+ rtnl_unregister_all(PF_CAN);
+
+ unregister_netdevice_notifier(&notifier);
+
+ rtnl_lock();
+ cgw_remove_all_jobs();
+ rtnl_unlock();
+
+ rcu_barrier(); /* Wait for completion of call_rcu()'s */
+
+ kmem_cache_destroy(cgw_cache);
+}
+
+module_init(cgw_module_init);
+module_exit(cgw_module_exit);
diff --git a/net/can/proc.c b/net/can/proc.c
index 0016f7339699..ba873c36d2fd 100644
--- a/net/can/proc.c
+++ b/net/can/proc.c
@@ -37,8 +37,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
- * Send feedback to <socketcan-users@lists.berlios.de>
- *
*/
#include <linux/module.h>
diff --git a/net/can/raw.c b/net/can/raw.c
index dea99a6e596c..cde1b4a20f75 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -37,8 +37,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
- * Send feedback to <socketcan-users@lists.berlios.de>
- *
*/
#include <linux/module.h>
diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c
index 132963abc266..2883ea01e680 100644
--- a/net/ceph/ceph_common.c
+++ b/net/ceph/ceph_common.c
@@ -232,6 +232,7 @@ void ceph_destroy_options(struct ceph_options *opt)
ceph_crypto_key_destroy(opt->key);
kfree(opt->key);
}
+ kfree(opt->mon_addr);
kfree(opt);
}
EXPORT_SYMBOL(ceph_destroy_options);
diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
index c340e2e0765b..9918e9eb276e 100644
--- a/net/ceph/messenger.c
+++ b/net/ceph/messenger.c
@@ -2307,6 +2307,7 @@ struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags)
m->front_max = front_len;
m->front_is_vmalloc = false;
m->more_to_follow = false;
+ m->ack_stamp = 0;
m->pool = NULL;
/* middle */
diff --git a/net/ceph/msgpool.c b/net/ceph/msgpool.c
index d5f2d97ac05c..1f4cb30a42c5 100644
--- a/net/ceph/msgpool.c
+++ b/net/ceph/msgpool.c
@@ -7,27 +7,37 @@
#include <linux/ceph/msgpool.h>
-static void *alloc_fn(gfp_t gfp_mask, void *arg)
+static void *msgpool_alloc(gfp_t gfp_mask, void *arg)
{
struct ceph_msgpool *pool = arg;
- void *p;
+ struct ceph_msg *msg;
- p = ceph_msg_new(0, pool->front_len, gfp_mask);
- if (!p)
- pr_err("msgpool %s alloc failed\n", pool->name);
- return p;
+ msg = ceph_msg_new(0, pool->front_len, gfp_mask);
+ if (!msg) {
+ dout("msgpool_alloc %s failed\n", pool->name);
+ } else {
+ dout("msgpool_alloc %s %p\n", pool->name, msg);
+ msg->pool = pool;
+ }
+ return msg;
}
-static void free_fn(void *element, void *arg)
+static void msgpool_free(void *element, void *arg)
{
- ceph_msg_put(element);
+ struct ceph_msgpool *pool = arg;
+ struct ceph_msg *msg = element;
+
+ dout("msgpool_release %s %p\n", pool->name, msg);
+ msg->pool = NULL;
+ ceph_msg_put(msg);
}
int ceph_msgpool_init(struct ceph_msgpool *pool,
int front_len, int size, bool blocking, const char *name)
{
+ dout("msgpool %s init\n", name);
pool->front_len = front_len;
- pool->pool = mempool_create(size, alloc_fn, free_fn, pool);
+ pool->pool = mempool_create(size, msgpool_alloc, msgpool_free, pool);
if (!pool->pool)
return -ENOMEM;
pool->name = name;
@@ -36,14 +46,17 @@ int ceph_msgpool_init(struct ceph_msgpool *pool,
void ceph_msgpool_destroy(struct ceph_msgpool *pool)
{
+ dout("msgpool %s destroy\n", pool->name);
mempool_destroy(pool->pool);
}
struct ceph_msg *ceph_msgpool_get(struct ceph_msgpool *pool,
int front_len)
{
+ struct ceph_msg *msg;
+
if (front_len > pool->front_len) {
- pr_err("msgpool_get pool %s need front %d, pool size is %d\n",
+ dout("msgpool_get %s need front %d, pool size is %d\n",
pool->name, front_len, pool->front_len);
WARN_ON(1);
@@ -51,14 +64,19 @@ struct ceph_msg *ceph_msgpool_get(struct ceph_msgpool *pool,
return ceph_msg_new(0, front_len, GFP_NOFS);
}
- return mempool_alloc(pool->pool, GFP_NOFS);
+ msg = mempool_alloc(pool->pool, GFP_NOFS);
+ dout("msgpool_get %s %p\n", pool->name, msg);
+ return msg;
}
void ceph_msgpool_put(struct ceph_msgpool *pool, struct ceph_msg *msg)
{
+ dout("msgpool_put %s %p\n", pool->name, msg);
+
/* reset msg front_len; user may have changed it */
msg->front.iov_len = pool->front_len;
msg->hdr.front_len = cpu_to_le32(pool->front_len);
kref_init(&msg->kref); /* retake single ref */
+ mempool_free(msg, pool->pool);
}
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c
index ce310eee708d..88ad8a2501b5 100644
--- a/net/ceph/osd_client.c
+++ b/net/ceph/osd_client.c
@@ -217,6 +217,7 @@ struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc,
INIT_LIST_HEAD(&req->r_unsafe_item);
INIT_LIST_HEAD(&req->r_linger_item);
INIT_LIST_HEAD(&req->r_linger_osd);
+ INIT_LIST_HEAD(&req->r_req_lru_item);
req->r_flags = flags;
WARN_ON((flags & (CEPH_OSD_FLAG_READ|CEPH_OSD_FLAG_WRITE)) == 0);
@@ -685,6 +686,18 @@ static void __remove_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd)
put_osd(osd);
}
+static void remove_all_osds(struct ceph_osd_client *osdc)
+{
+ dout("__remove_old_osds %p\n", osdc);
+ mutex_lock(&osdc->request_mutex);
+ while (!RB_EMPTY_ROOT(&osdc->osds)) {
+ struct ceph_osd *osd = rb_entry(rb_first(&osdc->osds),
+ struct ceph_osd, o_node);
+ __remove_osd(osdc, osd);
+ }
+ mutex_unlock(&osdc->request_mutex);
+}
+
static void __move_osd_to_lru(struct ceph_osd_client *osdc,
struct ceph_osd *osd)
{
@@ -701,14 +714,14 @@ static void __remove_osd_from_lru(struct ceph_osd *osd)
list_del_init(&osd->o_osd_lru);
}
-static void remove_old_osds(struct ceph_osd_client *osdc, int remove_all)
+static void remove_old_osds(struct ceph_osd_client *osdc)
{
struct ceph_osd *osd, *nosd;
dout("__remove_old_osds %p\n", osdc);
mutex_lock(&osdc->request_mutex);
list_for_each_entry_safe(osd, nosd, &osdc->osd_lru, o_osd_lru) {
- if (!remove_all && time_before(jiffies, osd->lru_ttl))
+ if (time_before(jiffies, osd->lru_ttl))
break;
__remove_osd(osdc, osd);
}
@@ -751,6 +764,7 @@ static void __insert_osd(struct ceph_osd_client *osdc, struct ceph_osd *new)
struct rb_node *parent = NULL;
struct ceph_osd *osd = NULL;
+ dout("__insert_osd %p osd%d\n", new, new->o_osd);
while (*p) {
parent = *p;
osd = rb_entry(parent, struct ceph_osd, o_node);
@@ -803,13 +817,10 @@ static void __register_request(struct ceph_osd_client *osdc,
{
req->r_tid = ++osdc->last_tid;
req->r_request->hdr.tid = cpu_to_le64(req->r_tid);
- INIT_LIST_HEAD(&req->r_req_lru_item);
-
dout("__register_request %p tid %lld\n", req, req->r_tid);
__insert_request(osdc, req);
ceph_osdc_get_request(req);
osdc->num_requests++;
-
if (osdc->num_requests == 1) {
dout(" first request, scheduling timeout\n");
__schedule_osd_timeout(osdc);
@@ -1144,7 +1155,7 @@ static void handle_osds_timeout(struct work_struct *work)
dout("osds timeout\n");
down_read(&osdc->map_sem);
- remove_old_osds(osdc, 0);
+ remove_old_osds(osdc);
up_read(&osdc->map_sem);
schedule_delayed_work(&osdc->osds_timeout_work,
@@ -1862,8 +1873,7 @@ void ceph_osdc_stop(struct ceph_osd_client *osdc)
ceph_osdmap_destroy(osdc->osdmap);
osdc->osdmap = NULL;
}
- remove_old_osds(osdc, 1);
- WARN_ON(!RB_EMPTY_ROOT(&osdc->osds));
+ remove_all_osds(osdc);
mempool_destroy(osdc->req_mempool);
ceph_msgpool_destroy(&osdc->msgpool_op);
ceph_msgpool_destroy(&osdc->msgpool_op_reply);
diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
index e97c3588c3ec..fd863fe76934 100644
--- a/net/ceph/osdmap.c
+++ b/net/ceph/osdmap.c
@@ -339,6 +339,7 @@ static int __insert_pg_mapping(struct ceph_pg_mapping *new,
struct ceph_pg_mapping *pg = NULL;
int c;
+ dout("__insert_pg_mapping %llx %p\n", *(u64 *)&new->pgid, new);
while (*p) {
parent = *p;
pg = rb_entry(parent, struct ceph_pg_mapping, node);
@@ -366,16 +367,33 @@ static struct ceph_pg_mapping *__lookup_pg_mapping(struct rb_root *root,
while (n) {
pg = rb_entry(n, struct ceph_pg_mapping, node);
c = pgid_cmp(pgid, pg->pgid);
- if (c < 0)
+ if (c < 0) {
n = n->rb_left;
- else if (c > 0)
+ } else if (c > 0) {
n = n->rb_right;
- else
+ } else {
+ dout("__lookup_pg_mapping %llx got %p\n",
+ *(u64 *)&pgid, pg);
return pg;
+ }
}
return NULL;
}
+static int __remove_pg_mapping(struct rb_root *root, struct ceph_pg pgid)
+{
+ struct ceph_pg_mapping *pg = __lookup_pg_mapping(root, pgid);
+
+ if (pg) {
+ dout("__remove_pg_mapping %llx %p\n", *(u64 *)&pgid, pg);
+ rb_erase(&pg->node, root);
+ kfree(pg);
+ return 0;
+ }
+ dout("__remove_pg_mapping %llx dne\n", *(u64 *)&pgid);
+ return -ENOENT;
+}
+
/*
* rbtree of pg pool info
*/
@@ -711,7 +729,6 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
void *start = *p;
int err = -EINVAL;
u16 version;
- struct rb_node *rbp;
ceph_decode_16_safe(p, end, version, bad);
if (version > CEPH_OSDMAP_INC_VERSION) {
@@ -861,7 +878,6 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
}
/* new_pg_temp */
- rbp = rb_first(&map->pg_temp);
ceph_decode_32_safe(p, end, len, bad);
while (len--) {
struct ceph_pg_mapping *pg;
@@ -872,18 +888,6 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
ceph_decode_copy(p, &pgid, sizeof(pgid));
pglen = ceph_decode_32(p);
- /* remove any? */
- while (rbp && pgid_cmp(rb_entry(rbp, struct ceph_pg_mapping,
- node)->pgid, pgid) <= 0) {
- struct ceph_pg_mapping *cur =
- rb_entry(rbp, struct ceph_pg_mapping, node);
-
- rbp = rb_next(rbp);
- dout(" removed pg_temp %llx\n", *(u64 *)&cur->pgid);
- rb_erase(&cur->node, &map->pg_temp);
- kfree(cur);
- }
-
if (pglen) {
/* insert */
ceph_decode_need(p, end, pglen*sizeof(u32), bad);
@@ -903,17 +907,11 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
}
dout(" added pg_temp %llx len %d\n", *(u64 *)&pgid,
pglen);
+ } else {
+ /* remove */
+ __remove_pg_mapping(&map->pg_temp, pgid);
}
}
- while (rbp) {
- struct ceph_pg_mapping *cur =
- rb_entry(rbp, struct ceph_pg_mapping, node);
-
- rbp = rb_next(rbp);
- dout(" removed pg_temp %llx\n", *(u64 *)&cur->pgid);
- rb_erase(&cur->node, &map->pg_temp);
- kfree(cur);
- }
/* ignore the rest */
*p = end;
@@ -1046,10 +1044,25 @@ static int *calc_pg_raw(struct ceph_osdmap *osdmap, struct ceph_pg pgid,
struct ceph_pg_mapping *pg;
struct ceph_pg_pool_info *pool;
int ruleno;
- unsigned poolid, ps, pps;
+ unsigned poolid, ps, pps, t;
int preferred;
+ poolid = le32_to_cpu(pgid.pool);
+ ps = le16_to_cpu(pgid.ps);
+ preferred = (s16)le16_to_cpu(pgid.preferred);
+
+ pool = __lookup_pg_pool(&osdmap->pg_pools, poolid);
+ if (!pool)
+ return NULL;
+
/* pg_temp? */
+ if (preferred >= 0)
+ t = ceph_stable_mod(ps, le32_to_cpu(pool->v.lpg_num),
+ pool->lpgp_num_mask);
+ else
+ t = ceph_stable_mod(ps, le32_to_cpu(pool->v.pg_num),
+ pool->pgp_num_mask);
+ pgid.ps = cpu_to_le16(t);
pg = __lookup_pg_mapping(&osdmap->pg_temp, pgid);
if (pg) {
*num = pg->len;
@@ -1057,18 +1070,6 @@ static int *calc_pg_raw(struct ceph_osdmap *osdmap, struct ceph_pg pgid,
}
/* crush */
- poolid = le32_to_cpu(pgid.pool);
- ps = le16_to_cpu(pgid.ps);
- preferred = (s16)le16_to_cpu(pgid.preferred);
-
- /* don't forcefeed bad device ids to crush */
- if (preferred >= osdmap->max_osd ||
- preferred >= osdmap->crush->max_devices)
- preferred = -1;
-
- pool = __lookup_pg_pool(&osdmap->pg_pools, poolid);
- if (!pool)
- return NULL;
ruleno = crush_find_rule(osdmap->crush, pool->v.crush_ruleset,
pool->v.type, pool->v.size);
if (ruleno < 0) {
@@ -1078,6 +1079,11 @@ static int *calc_pg_raw(struct ceph_osdmap *osdmap, struct ceph_pg pgid,
return NULL;
}
+ /* don't forcefeed bad device ids to crush */
+ if (preferred >= osdmap->max_osd ||
+ preferred >= osdmap->crush->max_devices)
+ preferred = -1;
+
if (preferred >= 0)
pps = ceph_stable_mod(ps,
le32_to_cpu(pool->v.lpgp_num),
diff --git a/net/core/datagram.c b/net/core/datagram.c
index 18ac112ea7ae..68bbf9f65cb0 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -324,15 +324,15 @@ int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset,
/* Copy paged appendix. Hmm... why does this look so complicated? */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
int end;
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
WARN_ON(start > offset + len);
- end = start + skb_shinfo(skb)->frags[i].size;
+ end = start + skb_frag_size(frag);
if ((copy = end - offset) > 0) {
int err;
u8 *vaddr;
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- struct page *page = frag->page;
+ struct page *page = skb_frag_page(frag);
if (copy > len)
copy = len;
@@ -410,15 +410,15 @@ int skb_copy_datagram_const_iovec(const struct sk_buff *skb, int offset,
/* Copy paged appendix. Hmm... why does this look so complicated? */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
int end;
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
WARN_ON(start > offset + len);
- end = start + skb_shinfo(skb)->frags[i].size;
+ end = start + skb_frag_size(frag);
if ((copy = end - offset) > 0) {
int err;
u8 *vaddr;
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- struct page *page = frag->page;
+ struct page *page = skb_frag_page(frag);
if (copy > len)
copy = len;
@@ -500,15 +500,15 @@ int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset,
/* Copy paged appendix. Hmm... why does this look so complicated? */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
int end;
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
WARN_ON(start > offset + len);
- end = start + skb_shinfo(skb)->frags[i].size;
+ end = start + skb_frag_size(frag);
if ((copy = end - offset) > 0) {
int err;
u8 *vaddr;
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- struct page *page = frag->page;
+ struct page *page = skb_frag_page(frag);
if (copy > len)
copy = len;
@@ -585,16 +585,16 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
int end;
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
WARN_ON(start > offset + len);
- end = start + skb_shinfo(skb)->frags[i].size;
+ end = start + skb_frag_size(frag);
if ((copy = end - offset) > 0) {
__wsum csum2;
int err = 0;
u8 *vaddr;
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- struct page *page = frag->page;
+ struct page *page = skb_frag_page(frag);
if (copy > len)
copy = len;
diff --git a/net/core/dev.c b/net/core/dev.c
index 17d67b579beb..edcf019c056d 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -133,6 +133,10 @@
#include <linux/pci.h>
#include <linux/inetdevice.h>
#include <linux/cpu_rmap.h>
+#include <linux/if_tunnel.h>
+#include <linux/if_pppox.h>
+#include <linux/ppp_defs.h>
+#include <linux/net_tstamp.h>
#include "net-sysfs.h"
@@ -1474,6 +1478,57 @@ static inline void net_timestamp_check(struct sk_buff *skb)
__net_timestamp(skb);
}
+static int net_hwtstamp_validate(struct ifreq *ifr)
+{
+ struct hwtstamp_config cfg;
+ enum hwtstamp_tx_types tx_type;
+ enum hwtstamp_rx_filters rx_filter;
+ int tx_type_valid = 0;
+ int rx_filter_valid = 0;
+
+ if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
+ return -EFAULT;
+
+ if (cfg.flags) /* reserved for future extensions */
+ return -EINVAL;
+
+ tx_type = cfg.tx_type;
+ rx_filter = cfg.rx_filter;
+
+ switch (tx_type) {
+ case HWTSTAMP_TX_OFF:
+ case HWTSTAMP_TX_ON:
+ case HWTSTAMP_TX_ONESTEP_SYNC:
+ tx_type_valid = 1;
+ break;
+ }
+
+ switch (rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ case HWTSTAMP_FILTER_ALL:
+ case HWTSTAMP_FILTER_SOME:
+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ rx_filter_valid = 1;
+ break;
+ }
+
+ if (!tx_type_valid || !rx_filter_valid)
+ return -ERANGE;
+
+ return 0;
+}
+
static inline bool is_skb_forwardable(struct net_device *dev,
struct sk_buff *skb)
{
@@ -1515,6 +1570,14 @@ static inline bool is_skb_forwardable(struct net_device *dev,
*/
int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
{
+ if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
+ if (skb_copy_ubufs(skb, GFP_ATOMIC)) {
+ atomic_long_inc(&dev->rx_dropped);
+ kfree_skb(skb);
+ return NET_RX_DROP;
+ }
+ }
+
skb_orphan(skb);
nf_reset(skb);
@@ -1947,9 +2010,11 @@ static int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
#ifdef CONFIG_HIGHMEM
int i;
if (!(dev->features & NETIF_F_HIGHDMA)) {
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
- if (PageHighMem(skb_shinfo(skb)->frags[i].page))
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ if (PageHighMem(skb_frag_page(frag)))
return 1;
+ }
}
if (PCI_DMA_BUS_IS_PHYS) {
@@ -1958,7 +2023,8 @@ static int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
if (!pdev)
return 0;
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- dma_addr_t addr = page_to_phys(skb_shinfo(skb)->frags[i].page);
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ dma_addr_t addr = page_to_phys(skb_frag_page(frag));
if (!pdev->dma_mask || addr + PAGE_SIZE - 1 > *pdev->dma_mask)
return 1;
}
@@ -2519,25 +2585,31 @@ static inline void ____napi_schedule(struct softnet_data *sd,
/*
* __skb_get_rxhash: calculate a flow hash based on src/dst addresses
- * and src/dst port numbers. Returns a non-zero hash number on success
- * and 0 on failure.
+ * and src/dst port numbers. Sets rxhash in skb to non-zero hash value
+ * on success, zero indicates no valid hash. Also, sets l4_rxhash in skb
+ * if hash is a canonical 4-tuple hash over transport ports.
*/
-__u32 __skb_get_rxhash(struct sk_buff *skb)
+void __skb_get_rxhash(struct sk_buff *skb)
{
int nhoff, hash = 0, poff;
const struct ipv6hdr *ip6;
const struct iphdr *ip;
+ const struct vlan_hdr *vlan;
u8 ip_proto;
- u32 addr1, addr2, ihl;
+ u32 addr1, addr2;
+ u16 proto;
union {
u32 v32;
u16 v16[2];
} ports;
nhoff = skb_network_offset(skb);
+ proto = skb->protocol;
- switch (skb->protocol) {
+again:
+ switch (proto) {
case __constant_htons(ETH_P_IP):
+ip:
if (!pskb_may_pull(skb, sizeof(*ip) + nhoff))
goto done;
@@ -2548,9 +2620,10 @@ __u32 __skb_get_rxhash(struct sk_buff *skb)
ip_proto = ip->protocol;
addr1 = (__force u32) ip->saddr;
addr2 = (__force u32) ip->daddr;
- ihl = ip->ihl;
+ nhoff += ip->ihl * 4;
break;
case __constant_htons(ETH_P_IPV6):
+ipv6:
if (!pskb_may_pull(skb, sizeof(*ip6) + nhoff))
goto done;
@@ -2558,20 +2631,71 @@ __u32 __skb_get_rxhash(struct sk_buff *skb)
ip_proto = ip6->nexthdr;
addr1 = (__force u32) ip6->saddr.s6_addr32[3];
addr2 = (__force u32) ip6->daddr.s6_addr32[3];
- ihl = (40 >> 2);
+ nhoff += 40;
break;
+ case __constant_htons(ETH_P_8021Q):
+ if (!pskb_may_pull(skb, sizeof(*vlan) + nhoff))
+ goto done;
+ vlan = (const struct vlan_hdr *) (skb->data + nhoff);
+ proto = vlan->h_vlan_encapsulated_proto;
+ nhoff += sizeof(*vlan);
+ goto again;
+ case __constant_htons(ETH_P_PPP_SES):
+ if (!pskb_may_pull(skb, PPPOE_SES_HLEN + nhoff))
+ goto done;
+ proto = *((__be16 *) (skb->data + nhoff +
+ sizeof(struct pppoe_hdr)));
+ nhoff += PPPOE_SES_HLEN;
+ switch (proto) {
+ case __constant_htons(PPP_IP):
+ goto ip;
+ case __constant_htons(PPP_IPV6):
+ goto ipv6;
+ default:
+ goto done;
+ }
default:
goto done;
}
+ switch (ip_proto) {
+ case IPPROTO_GRE:
+ if (pskb_may_pull(skb, nhoff + 16)) {
+ u8 *h = skb->data + nhoff;
+ __be16 flags = *(__be16 *)h;
+
+ /*
+ * Only look inside GRE if version zero and no
+ * routing
+ */
+ if (!(flags & (GRE_VERSION|GRE_ROUTING))) {
+ proto = *(__be16 *)(h + 2);
+ nhoff += 4;
+ if (flags & GRE_CSUM)
+ nhoff += 4;
+ if (flags & GRE_KEY)
+ nhoff += 4;
+ if (flags & GRE_SEQ)
+ nhoff += 4;
+ goto again;
+ }
+ }
+ break;
+ case IPPROTO_IPIP:
+ goto again;
+ default:
+ break;
+ }
+
ports.v32 = 0;
poff = proto_ports_offset(ip_proto);
if (poff >= 0) {
- nhoff += ihl * 4 + poff;
+ nhoff += poff;
if (pskb_may_pull(skb, nhoff + 4)) {
ports.v32 = * (__force u32 *) (skb->data + nhoff);
if (ports.v16[1] < ports.v16[0])
swap(ports.v16[0], ports.v16[1]);
+ skb->l4_rxhash = 1;
}
}
@@ -2584,7 +2708,7 @@ __u32 __skb_get_rxhash(struct sk_buff *skb)
hash = 1;
done:
- return hash;
+ skb->rxhash = hash;
}
EXPORT_SYMBOL(__skb_get_rxhash);
@@ -2598,10 +2722,7 @@ static struct rps_dev_flow *
set_rps_cpu(struct net_device *dev, struct sk_buff *skb,
struct rps_dev_flow *rflow, u16 next_cpu)
{
- u16 tcpu;
-
- tcpu = rflow->cpu = next_cpu;
- if (tcpu != RPS_NO_CPU) {
+ if (next_cpu != RPS_NO_CPU) {
#ifdef CONFIG_RFS_ACCEL
struct netdev_rx_queue *rxqueue;
struct rps_dev_flow_table *flow_table;
@@ -2629,16 +2750,16 @@ set_rps_cpu(struct net_device *dev, struct sk_buff *skb,
goto out;
old_rflow = rflow;
rflow = &flow_table->flows[flow_id];
- rflow->cpu = next_cpu;
rflow->filter = rc;
if (old_rflow->filter == rflow->filter)
old_rflow->filter = RPS_NO_FILTER;
out:
#endif
rflow->last_qtail =
- per_cpu(softnet_data, tcpu).input_queue_head;
+ per_cpu(softnet_data, next_cpu).input_queue_head;
}
+ rflow->cpu = next_cpu;
return rflow;
}
@@ -2673,13 +2794,13 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
map = rcu_dereference(rxqueue->rps_map);
if (map) {
if (map->len == 1 &&
- !rcu_dereference_raw(rxqueue->rps_flow_table)) {
+ !rcu_access_pointer(rxqueue->rps_flow_table)) {
tcpu = map->cpus[0];
if (cpu_online(tcpu))
cpu = tcpu;
goto done;
}
- } else if (!rcu_dereference_raw(rxqueue->rps_flow_table)) {
+ } else if (!rcu_access_pointer(rxqueue->rps_flow_table)) {
goto done;
}
@@ -3094,8 +3215,8 @@ void netdev_rx_handler_unregister(struct net_device *dev)
{
ASSERT_RTNL();
- rcu_assign_pointer(dev->rx_handler, NULL);
- rcu_assign_pointer(dev->rx_handler_data, NULL);
+ RCU_INIT_POINTER(dev->rx_handler, NULL);
+ RCU_INIT_POINTER(dev->rx_handler_data, NULL);
}
EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);
@@ -3162,6 +3283,17 @@ another_round:
ncls:
#endif
+ if (vlan_tx_tag_present(skb)) {
+ if (pt_prev) {
+ ret = deliver_skb(skb, pt_prev, orig_dev);
+ pt_prev = NULL;
+ }
+ if (vlan_do_receive(&skb))
+ goto another_round;
+ else if (unlikely(!skb))
+ goto out;
+ }
+
rx_handler = rcu_dereference(skb->dev->rx_handler);
if (rx_handler) {
if (pt_prev) {
@@ -3182,18 +3314,6 @@ ncls:
}
}
- if (vlan_tx_tag_present(skb)) {
- if (pt_prev) {
- ret = deliver_skb(skb, pt_prev, orig_dev);
- pt_prev = NULL;
- }
- if (vlan_do_receive(&skb)) {
- ret = __netif_receive_skb(skb);
- goto out;
- } else if (unlikely(!skb))
- goto out;
- }
-
/* deliver only exact match when indicated */
null_or_dev = deliver_exact ? skb->dev : NULL;
@@ -3421,10 +3541,10 @@ pull:
skb->data_len -= grow;
skb_shinfo(skb)->frags[0].page_offset += grow;
- skb_shinfo(skb)->frags[0].size -= grow;
+ skb_frag_size_sub(&skb_shinfo(skb)->frags[0], grow);
- if (unlikely(!skb_shinfo(skb)->frags[0].size)) {
- put_page(skb_shinfo(skb)->frags[0].page);
+ if (unlikely(!skb_frag_size(&skb_shinfo(skb)->frags[0]))) {
+ skb_frag_unref(skb, 0);
memmove(skb_shinfo(skb)->frags,
skb_shinfo(skb)->frags + 1,
--skb_shinfo(skb)->nr_frags * sizeof(skb_frag_t));
@@ -3488,11 +3608,10 @@ void skb_gro_reset_offset(struct sk_buff *skb)
NAPI_GRO_CB(skb)->frag0_len = 0;
if (skb->mac_header == skb->tail &&
- !PageHighMem(skb_shinfo(skb)->frags[0].page)) {
+ !PageHighMem(skb_frag_page(&skb_shinfo(skb)->frags[0]))) {
NAPI_GRO_CB(skb)->frag0 =
- page_address(skb_shinfo(skb)->frags[0].page) +
- skb_shinfo(skb)->frags[0].page_offset;
- NAPI_GRO_CB(skb)->frag0_len = skb_shinfo(skb)->frags[0].size;
+ skb_frag_address(&skb_shinfo(skb)->frags[0]);
+ NAPI_GRO_CB(skb)->frag0_len = skb_frag_size(&skb_shinfo(skb)->frags[0]);
}
}
EXPORT_SYMBOL(skb_gro_reset_offset);
@@ -3974,6 +4093,60 @@ static int dev_ifconf(struct net *net, char __user *arg)
}
#ifdef CONFIG_PROC_FS
+
+#define BUCKET_SPACE (32 - NETDEV_HASHBITS)
+
+struct dev_iter_state {
+ struct seq_net_private p;
+ unsigned int pos; /* bucket << BUCKET_SPACE + offset */
+};
+
+#define get_bucket(x) ((x) >> BUCKET_SPACE)
+#define get_offset(x) ((x) & ((1 << BUCKET_SPACE) - 1))
+#define set_bucket_offset(b, o) ((b) << BUCKET_SPACE | (o))
+
+static inline struct net_device *dev_from_same_bucket(struct seq_file *seq)
+{
+ struct dev_iter_state *state = seq->private;
+ struct net *net = seq_file_net(seq);
+ struct net_device *dev;
+ struct hlist_node *p;
+ struct hlist_head *h;
+ unsigned int count, bucket, offset;
+
+ bucket = get_bucket(state->pos);
+ offset = get_offset(state->pos);
+ h = &net->dev_name_head[bucket];
+ count = 0;
+ hlist_for_each_entry_rcu(dev, p, h, name_hlist) {
+ if (count++ == offset) {
+ state->pos = set_bucket_offset(bucket, count);
+ return dev;
+ }
+ }
+
+ return NULL;
+}
+
+static inline struct net_device *dev_from_new_bucket(struct seq_file *seq)
+{
+ struct dev_iter_state *state = seq->private;
+ struct net_device *dev;
+ unsigned int bucket;
+
+ bucket = get_bucket(state->pos);
+ do {
+ dev = dev_from_same_bucket(seq);
+ if (dev)
+ return dev;
+
+ bucket++;
+ state->pos = set_bucket_offset(bucket, 0);
+ } while (bucket < NETDEV_HASHENTRIES);
+
+ return NULL;
+}
+
/*
* This is invoked by the /proc filesystem handler to display a device
* in detail.
@@ -3981,33 +4154,33 @@ static int dev_ifconf(struct net *net, char __user *arg)
void *dev_seq_start(struct seq_file *seq, loff_t *pos)
__acquires(RCU)
{
- struct net *net = seq_file_net(seq);
- loff_t off;
- struct net_device *dev;
+ struct dev_iter_state *state = seq->private;
rcu_read_lock();
if (!*pos)
return SEQ_START_TOKEN;
- off = 1;
- for_each_netdev_rcu(net, dev)
- if (off++ == *pos)
- return dev;
+ /* check for end of the hash */
+ if (state->pos == 0 && *pos > 1)
+ return NULL;
- return NULL;
+ return dev_from_new_bucket(seq);
}
void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
- struct net_device *dev = v;
+ struct net_device *dev;
+
+ ++*pos;
if (v == SEQ_START_TOKEN)
- dev = first_net_device_rcu(seq_file_net(seq));
- else
- dev = next_net_device_rcu(dev);
+ return dev_from_new_bucket(seq);
- ++*pos;
- return dev;
+ dev = dev_from_same_bucket(seq);
+ if (dev)
+ return dev;
+
+ return dev_from_new_bucket(seq);
}
void dev_seq_stop(struct seq_file *seq, void *v)
@@ -4106,7 +4279,7 @@ static const struct seq_operations dev_seq_ops = {
static int dev_seq_open(struct inode *inode, struct file *file)
{
return seq_open_net(inode, file, &dev_seq_ops,
- sizeof(struct seq_net_private));
+ sizeof(struct dev_iter_state));
}
static const struct file_operations dev_seq_fops = {
@@ -4489,9 +4662,7 @@ void __dev_set_rx_mode(struct net_device *dev)
if (!netif_device_present(dev))
return;
- if (ops->ndo_set_rx_mode)
- ops->ndo_set_rx_mode(dev);
- else {
+ if (!(dev->priv_flags & IFF_UNICAST_FLT)) {
/* Unicast addresses changes may only happen under the rtnl,
* therefore calling __dev_set_promiscuity here is safe.
*/
@@ -4502,10 +4673,10 @@ void __dev_set_rx_mode(struct net_device *dev)
__dev_set_promiscuity(dev, -1);
dev->uc_promisc = false;
}
-
- if (ops->ndo_set_multicast_list)
- ops->ndo_set_multicast_list(dev);
}
+
+ if (ops->ndo_set_rx_mode)
+ ops->ndo_set_rx_mode(dev);
}
void dev_set_rx_mode(struct net_device *dev)
@@ -4516,30 +4687,6 @@ void dev_set_rx_mode(struct net_device *dev)
}
/**
- * dev_ethtool_get_settings - call device's ethtool_ops::get_settings()
- * @dev: device
- * @cmd: memory area for ethtool_ops::get_settings() result
- *
- * The cmd arg is initialized properly (cleared and
- * ethtool_cmd::cmd field set to ETHTOOL_GSET).
- *
- * Return device's ethtool_ops::get_settings() result value or
- * -EOPNOTSUPP when device doesn't expose
- * ethtool_ops::get_settings() operation.
- */
-int dev_ethtool_get_settings(struct net_device *dev,
- struct ethtool_cmd *cmd)
-{
- if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings)
- return -EOPNOTSUPP;
-
- memset(cmd, 0, sizeof(struct ethtool_cmd));
- cmd->cmd = ETHTOOL_GSET;
- return dev->ethtool_ops->get_settings(dev, cmd);
-}
-EXPORT_SYMBOL(dev_ethtool_get_settings);
-
-/**
* dev_get_flags - get flags reported to userspace
* @dev: device
*
@@ -4855,7 +5002,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
return -EOPNOTSUPP;
case SIOCADDMULTI:
- if ((!ops->ndo_set_multicast_list && !ops->ndo_set_rx_mode) ||
+ if (!ops->ndo_set_rx_mode ||
ifr->ifr_hwaddr.sa_family != AF_UNSPEC)
return -EINVAL;
if (!netif_device_present(dev))
@@ -4863,7 +5010,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
return dev_mc_add_global(dev, ifr->ifr_hwaddr.sa_data);
case SIOCDELMULTI:
- if ((!ops->ndo_set_multicast_list && !ops->ndo_set_rx_mode) ||
+ if (!ops->ndo_set_rx_mode ||
ifr->ifr_hwaddr.sa_family != AF_UNSPEC)
return -EINVAL;
if (!netif_device_present(dev))
@@ -4880,6 +5027,12 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
ifr->ifr_newname[IFNAMSIZ-1] = '\0';
return dev_change_name(dev, ifr->ifr_newname);
+ case SIOCSHWTSTAMP:
+ err = net_hwtstamp_validate(ifr);
+ if (err)
+ return err;
+ /* fall through */
+
/*
* Unknown or private ioctl
*/
@@ -5194,7 +5347,7 @@ static void rollback_registered_many(struct list_head *head)
dev = list_first_entry(head, struct net_device, unreg_list);
call_netdevice_notifiers(NETDEV_UNREGISTER_BATCH, dev);
- rcu_barrier();
+ synchronize_net();
list_for_each_entry(dev, head, unreg_list)
dev_put(dev);
@@ -5707,6 +5860,12 @@ void netdev_run_todo(void)
__rtnl_unlock();
+ /* Wait for rcu callbacks to finish before attempting to drain
+ * the device list. This usually avoids a 250ms wait.
+ */
+ if (!list_empty(&list))
+ rcu_barrier();
+
while (!list_empty(&list)) {
struct net_device *dev
= list_first_entry(&list, struct net_device, todo_list);
@@ -5727,8 +5886,8 @@ void netdev_run_todo(void)
/* paranoia */
BUG_ON(netdev_refcnt_read(dev));
- WARN_ON(rcu_dereference_raw(dev->ip_ptr));
- WARN_ON(rcu_dereference_raw(dev->ip6_ptr));
+ WARN_ON(rcu_access_pointer(dev->ip_ptr));
+ WARN_ON(rcu_access_pointer(dev->ip6_ptr));
WARN_ON(dev->dn_ptr);
if (dev->destructor)
@@ -5932,7 +6091,7 @@ void free_netdev(struct net_device *dev)
kfree(dev->_rx);
#endif
- kfree(rcu_dereference_raw(dev->ingress_queue));
+ kfree(rcu_dereference_protected(dev->ingress_queue, 1));
/* Flush device addresses */
dev_addr_flush(dev);
@@ -6107,6 +6266,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
*/
call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
call_netdevice_notifiers(NETDEV_UNREGISTER_BATCH, dev);
+ rtmsg_ifinfo(RTM_DELLINK, dev, ~0U);
/*
* Flush the unicast and multicast chains
@@ -6290,7 +6450,7 @@ const char *netdev_drivername(const struct net_device *dev)
return empty;
}
-static int __netdev_printk(const char *level, const struct net_device *dev,
+int __netdev_printk(const char *level, const struct net_device *dev,
struct va_format *vaf)
{
int r;
@@ -6305,6 +6465,7 @@ static int __netdev_printk(const char *level, const struct net_device *dev,
return r;
}
+EXPORT_SYMBOL(__netdev_printk);
int netdev_printk(const char *level, const struct net_device *dev,
const char *format, ...)
diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c
index e2e66939ed00..283d1b863876 100644
--- a/net/core/dev_addr_lists.c
+++ b/net/core/dev_addr_lists.c
@@ -591,8 +591,8 @@ EXPORT_SYMBOL(dev_mc_del_global);
* addresses that have no users left. The source device must be
* locked by netif_tx_lock_bh.
*
- * This function is intended to be called from the dev->set_multicast_list
- * or dev->set_rx_mode function of layered software devices.
+ * This function is intended to be called from the ndo_set_rx_mode
+ * function of layered software devices.
*/
int dev_mc_sync(struct net_device *to, struct net_device *from)
{
diff --git a/net/core/dst.c b/net/core/dst.c
index 14b33baf0733..d5e2c4c09107 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -171,7 +171,7 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
dst_init_metrics(dst, dst_default_metrics, true);
dst->expires = 0UL;
dst->path = dst;
- dst->_neighbour = NULL;
+ RCU_INIT_POINTER(dst->_neighbour, NULL);
#ifdef CONFIG_XFRM
dst->xfrm = NULL;
#endif
@@ -229,11 +229,11 @@ struct dst_entry *dst_destroy(struct dst_entry * dst)
smp_rmb();
again:
- neigh = dst->_neighbour;
+ neigh = rcu_dereference_protected(dst->_neighbour, 1);
child = dst->child;
if (neigh) {
- dst->_neighbour = NULL;
+ RCU_INIT_POINTER(dst->_neighbour, NULL);
neigh_release(neigh);
}
@@ -360,14 +360,19 @@ static void dst_ifdown(struct dst_entry *dst, struct net_device *dev,
if (!unregister) {
dst->input = dst->output = dst_discard;
} else {
+ struct neighbour *neigh;
+
dst->dev = dev_net(dst->dev)->loopback_dev;
dev_hold(dst->dev);
dev_put(dev);
- if (dst->_neighbour && dst->_neighbour->dev == dev) {
- dst->_neighbour->dev = dst->dev;
+ rcu_read_lock();
+ neigh = dst_get_neighbour(dst);
+ if (neigh && neigh->dev == dev) {
+ neigh->dev = dst->dev;
dev_hold(dst->dev);
dev_put(dev);
}
+ rcu_read_unlock();
}
}
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 6cdba5fc2bed..f44481707124 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -569,15 +569,25 @@ int __ethtool_set_flags(struct net_device *dev, u32 data)
return 0;
}
-static int ethtool_get_settings(struct net_device *dev, void __user *useraddr)
+int __ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
- struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET };
- int err;
+ ASSERT_RTNL();
- if (!dev->ethtool_ops->get_settings)
+ if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings)
return -EOPNOTSUPP;
- err = dev->ethtool_ops->get_settings(dev, &cmd);
+ memset(cmd, 0, sizeof(struct ethtool_cmd));
+ cmd->cmd = ETHTOOL_GSET;
+ return dev->ethtool_ops->get_settings(dev, cmd);
+}
+EXPORT_SYMBOL(__ethtool_get_settings);
+
+static int ethtool_get_settings(struct net_device *dev, void __user *useraddr)
+{
+ int err;
+ struct ethtool_cmd cmd;
+
+ err = __ethtool_get_settings(dev, &cmd);
if (err < 0)
return err;
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index e7ab0c0285b5..57e8f95110e6 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -384,8 +384,8 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
*/
list_for_each_entry(r, &ops->rules_list, list) {
if (r->action == FR_ACT_GOTO &&
- r->target == rule->pref) {
- BUG_ON(rtnl_dereference(r->ctarget) != NULL);
+ r->target == rule->pref &&
+ rtnl_dereference(r->ctarget) == NULL) {
rcu_assign_pointer(r->ctarget, rule);
if (--ops->unresolved_rules == 0)
break;
@@ -475,8 +475,11 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
list_del_rcu(&rule->list);
- if (rule->action == FR_ACT_GOTO)
+ if (rule->action == FR_ACT_GOTO) {
ops->nr_goto_rules--;
+ if (rtnl_dereference(rule->ctarget) == NULL)
+ ops->unresolved_rules--;
+ }
/*
* Check if this rule is a target to any of them. If so,
@@ -487,7 +490,7 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
if (ops->nr_goto_rules > 0) {
list_for_each_entry(tmp, &ops->rules_list, list) {
if (rtnl_dereference(tmp->ctarget) == rule) {
- rcu_assign_pointer(tmp->ctarget, NULL);
+ RCU_INIT_POINTER(tmp->ctarget, NULL);
ops->unresolved_rules++;
}
}
@@ -545,7 +548,7 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,
frh->flags = rule->flags;
if (rule->action == FR_ACT_GOTO &&
- rcu_dereference_raw(rule->ctarget) == NULL)
+ rcu_access_pointer(rule->ctarget) == NULL)
frh->flags |= FIB_RULE_UNRESOLVED;
if (rule->iifname[0]) {
diff --git a/net/core/filter.c b/net/core/filter.c
index 36f975fa87cb..5dea45279215 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -436,7 +436,7 @@ error:
*
* Returns 0 if the rule set is legal or -EINVAL if not.
*/
-int sk_chk_filter(struct sock_filter *filter, int flen)
+int sk_chk_filter(struct sock_filter *filter, unsigned int flen)
{
/*
* Valid instructions are initialized to non-0.
@@ -645,7 +645,7 @@ int sk_detach_filter(struct sock *sk)
filter = rcu_dereference_protected(sk->sk_filter,
sock_owned_by_user(sk));
if (filter) {
- rcu_assign_pointer(sk->sk_filter, NULL);
+ RCU_INIT_POINTER(sk->sk_filter, NULL);
sk_filter_uncharge(sk, filter);
ret = 0;
}
diff --git a/net/core/flow.c b/net/core/flow.c
index bf32c33cad3b..8ae42de9c79e 100644
--- a/net/core/flow.c
+++ b/net/core/flow.c
@@ -30,6 +30,7 @@ struct flow_cache_entry {
struct hlist_node hlist;
struct list_head gc_list;
} u;
+ struct net *net;
u16 family;
u8 dir;
u32 genid;
@@ -172,29 +173,26 @@ static void flow_new_hash_rnd(struct flow_cache *fc,
static u32 flow_hash_code(struct flow_cache *fc,
struct flow_cache_percpu *fcp,
- const struct flowi *key)
+ const struct flowi *key,
+ size_t keysize)
{
const u32 *k = (const u32 *) key;
+ const u32 length = keysize * sizeof(flow_compare_t) / sizeof(u32);
- return jhash2(k, (sizeof(*key) / sizeof(u32)), fcp->hash_rnd)
+ return jhash2(k, length, fcp->hash_rnd)
& (flow_cache_hash_size(fc) - 1);
}
-typedef unsigned long flow_compare_t;
-
/* I hear what you're saying, use memcmp. But memcmp cannot make
- * important assumptions that we can here, such as alignment and
- * constant size.
+ * important assumptions that we can here, such as alignment.
*/
-static int flow_key_compare(const struct flowi *key1, const struct flowi *key2)
+static int flow_key_compare(const struct flowi *key1, const struct flowi *key2,
+ size_t keysize)
{
const flow_compare_t *k1, *k1_lim, *k2;
- const int n_elem = sizeof(struct flowi) / sizeof(flow_compare_t);
-
- BUILD_BUG_ON(sizeof(struct flowi) % sizeof(flow_compare_t));
k1 = (const flow_compare_t *) key1;
- k1_lim = k1 + n_elem;
+ k1_lim = k1 + keysize;
k2 = (const flow_compare_t *) key2;
@@ -215,6 +213,7 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir,
struct flow_cache_entry *fle, *tfle;
struct hlist_node *entry;
struct flow_cache_object *flo;
+ size_t keysize;
unsigned int hash;
local_bh_disable();
@@ -222,6 +221,11 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir,
fle = NULL;
flo = NULL;
+
+ keysize = flow_key_size(family);
+ if (!keysize)
+ goto nocache;
+
/* Packet really early in init? Making flow_cache_init a
* pre-smp initcall would solve this. --RR */
if (!fcp->hash_table)
@@ -230,11 +234,12 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir,
if (fcp->hash_rnd_recalc)
flow_new_hash_rnd(fc, fcp);
- hash = flow_hash_code(fc, fcp, key);
+ hash = flow_hash_code(fc, fcp, key, keysize);
hlist_for_each_entry(tfle, entry, &fcp->hash_table[hash], u.hlist) {
- if (tfle->family == family &&
+ if (tfle->net == net &&
+ tfle->family == family &&
tfle->dir == dir &&
- flow_key_compare(key, &tfle->key) == 0) {
+ flow_key_compare(key, &tfle->key, keysize) == 0) {
fle = tfle;
break;
}
@@ -246,9 +251,10 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir,
fle = kmem_cache_alloc(flow_cachep, GFP_ATOMIC);
if (fle) {
+ fle->net = net;
fle->family = family;
fle->dir = dir;
- memcpy(&fle->key, key, sizeof(*key));
+ memcpy(&fle->key, key, keysize * sizeof(flow_compare_t));
fle->object = NULL;
hlist_add_head(&fle->u.hlist, &fcp->hash_table[hash]);
fcp->hash_count++;
@@ -407,7 +413,7 @@ static int __init flow_cache_init(struct flow_cache *fc)
for_each_online_cpu(i) {
if (flow_cache_cpu_prepare(fc, i))
- return -ENOMEM;
+ goto err;
}
fc->hotcpu_notifier = (struct notifier_block){
.notifier_call = flow_cache_cpu,
@@ -420,6 +426,18 @@ static int __init flow_cache_init(struct flow_cache *fc)
add_timer(&fc->rnd_timer);
return 0;
+
+err:
+ for_each_possible_cpu(i) {
+ struct flow_cache_percpu *fcp = per_cpu_ptr(fc->percpu, i);
+ kfree(fcp->hash_table);
+ fcp->hash_table = NULL;
+ }
+
+ free_percpu(fc->percpu);
+ fc->percpu = NULL;
+
+ return -ENOMEM;
}
static int __init flow_cache_init_global(void)
diff --git a/net/core/kmap_skb.h b/net/core/kmap_skb.h
index 283c2b993fb8..81e1ed7c8383 100644
--- a/net/core/kmap_skb.h
+++ b/net/core/kmap_skb.h
@@ -7,7 +7,7 @@ static inline void *kmap_skb_frag(const skb_frag_t *frag)
local_bh_disable();
#endif
- return kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ);
+ return kmap_atomic(skb_frag_page(frag), KM_SKB_DATA_SOFTIRQ);
}
static inline void kunmap_skb_frag(void *vaddr)
diff --git a/net/core/link_watch.c b/net/core/link_watch.c
index 357bd4ee4baa..c3519c6d1b16 100644
--- a/net/core/link_watch.c
+++ b/net/core/link_watch.c
@@ -78,8 +78,13 @@ static void rfc2863_policy(struct net_device *dev)
static bool linkwatch_urgent_event(struct net_device *dev)
{
- return netif_running(dev) && netif_carrier_ok(dev) &&
- qdisc_tx_changing(dev);
+ if (!netif_running(dev))
+ return false;
+
+ if (dev->ifindex != dev->iflink)
+ return true;
+
+ return netif_carrier_ok(dev) && qdisc_tx_changing(dev);
}
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 8fab9b0bb203..909ecb3c2a33 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -844,6 +844,19 @@ static void neigh_invalidate(struct neighbour *neigh)
skb_queue_purge(&neigh->arp_queue);
}
+static void neigh_probe(struct neighbour *neigh)
+ __releases(neigh->lock)
+{
+ struct sk_buff *skb = skb_peek(&neigh->arp_queue);
+ /* keep skb alive even if arp_queue overflows */
+ if (skb)
+ skb = skb_copy(skb, GFP_ATOMIC);
+ write_unlock(&neigh->lock);
+ neigh->ops->solicit(neigh, skb);
+ atomic_inc(&neigh->probes);
+ kfree_skb(skb);
+}
+
/* Called when a timer expires for a neighbour entry. */
static void neigh_timer_handler(unsigned long arg)
@@ -920,14 +933,7 @@ static void neigh_timer_handler(unsigned long arg)
neigh_hold(neigh);
}
if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
- struct sk_buff *skb = skb_peek(&neigh->arp_queue);
- /* keep skb alive even if arp_queue overflows */
- if (skb)
- skb = skb_copy(skb, GFP_ATOMIC);
- write_unlock(&neigh->lock);
- neigh->ops->solicit(neigh, skb);
- atomic_inc(&neigh->probes);
- kfree_skb(skb);
+ neigh_probe(neigh);
} else {
out:
write_unlock(&neigh->lock);
@@ -942,7 +948,7 @@ out:
int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
{
int rc;
- unsigned long now;
+ bool immediate_probe = false;
write_lock_bh(&neigh->lock);
@@ -950,14 +956,16 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
goto out_unlock_bh;
- now = jiffies;
-
if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
if (neigh->parms->mcast_probes + neigh->parms->app_probes) {
+ unsigned long next, now = jiffies;
+
atomic_set(&neigh->probes, neigh->parms->ucast_probes);
neigh->nud_state = NUD_INCOMPLETE;
- neigh->updated = jiffies;
- neigh_add_timer(neigh, now + 1);
+ neigh->updated = now;
+ next = now + max(neigh->parms->retrans_time, HZ/2);
+ neigh_add_timer(neigh, next);
+ immediate_probe = true;
} else {
neigh->nud_state = NUD_FAILED;
neigh->updated = jiffies;
@@ -989,7 +997,11 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
rc = 1;
}
out_unlock_bh:
- write_unlock_bh(&neigh->lock);
+ if (immediate_probe)
+ neigh_probe(neigh);
+ else
+ write_unlock(&neigh->lock);
+ local_bh_enable();
return rc;
}
EXPORT_SYMBOL(__neigh_event_send);
@@ -1156,10 +1168,14 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
struct dst_entry *dst = skb_dst(skb);
struct neighbour *n2, *n1 = neigh;
write_unlock_bh(&neigh->lock);
+
+ rcu_read_lock();
/* On shaper/eql skb->dst->neighbour != neigh :( */
if (dst && (n2 = dst_get_neighbour(dst)) != NULL)
n1 = n2;
n1->output(n1, skb);
+ rcu_read_unlock();
+
write_lock_bh(&neigh->lock);
}
skb_queue_purge(&neigh->arp_queue);
@@ -1319,11 +1335,15 @@ static void neigh_proxy_process(unsigned long arg)
if (tdif <= 0) {
struct net_device *dev = skb->dev;
+
__skb_unlink(skb, &tbl->proxy_queue);
- if (tbl->proxy_redo && netif_running(dev))
+ if (tbl->proxy_redo && netif_running(dev)) {
+ rcu_read_lock();
tbl->proxy_redo(skb);
- else
+ rcu_read_unlock();
+ } else {
kfree_skb(skb);
+ }
dev_put(dev);
} else if (!sched_next || tdif < sched_next)
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 1683e5db2f27..7604a635376b 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -147,7 +147,7 @@ static ssize_t show_speed(struct device *dev,
if (netif_running(netdev)) {
struct ethtool_cmd cmd;
- if (!dev_ethtool_get_settings(netdev, &cmd))
+ if (!__ethtool_get_settings(netdev, &cmd))
ret = sprintf(buf, fmt_udec, ethtool_cmd_speed(&cmd));
}
rtnl_unlock();
@@ -165,7 +165,7 @@ static ssize_t show_duplex(struct device *dev,
if (netif_running(netdev)) {
struct ethtool_cmd cmd;
- if (!dev_ethtool_get_settings(netdev, &cmd))
+ if (!__ethtool_get_settings(netdev, &cmd))
ret = sprintf(buf, "%s\n",
cmd.duplex ? "full" : "half");
}
@@ -712,13 +712,13 @@ static void rx_queue_release(struct kobject *kobj)
struct rps_dev_flow_table *flow_table;
- map = rcu_dereference_raw(queue->rps_map);
+ map = rcu_dereference_protected(queue->rps_map, 1);
if (map) {
RCU_INIT_POINTER(queue->rps_map, NULL);
kfree_rcu(map, rcu);
}
- flow_table = rcu_dereference_raw(queue->rps_flow_table);
+ flow_table = rcu_dereference_protected(queue->rps_flow_table, 1);
if (flow_table) {
RCU_INIT_POINTER(queue->rps_flow_table, NULL);
call_rcu(&flow_table->rcu, rps_dev_flow_table_release);
@@ -987,10 +987,10 @@ static ssize_t store_xps_map(struct netdev_queue *queue,
}
if (nonempty)
- rcu_assign_pointer(dev->xps_maps, new_dev_maps);
+ RCU_INIT_POINTER(dev->xps_maps, new_dev_maps);
else {
kfree(new_dev_maps);
- rcu_assign_pointer(dev->xps_maps, NULL);
+ RCU_INIT_POINTER(dev->xps_maps, NULL);
}
if (dev_maps)
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index adf84dd8c7b5..f57d94627a2a 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -558,13 +558,14 @@ int __netpoll_rx(struct sk_buff *skb)
if (skb_shared(skb))
goto out;
- iph = (struct iphdr *)skb->data;
if (!pskb_may_pull(skb, sizeof(struct iphdr)))
goto out;
+ iph = (struct iphdr *)skb->data;
if (iph->ihl < 5 || iph->version != 4)
goto out;
if (!pskb_may_pull(skb, iph->ihl*4))
goto out;
+ iph = (struct iphdr *)skb->data;
if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
goto out;
@@ -579,6 +580,7 @@ int __netpoll_rx(struct sk_buff *skb)
if (pskb_trim_rcsum(skb, len))
goto out;
+ iph = (struct iphdr *)skb->data;
if (iph->protocol != IPPROTO_UDP)
goto out;
@@ -760,7 +762,7 @@ int __netpoll_setup(struct netpoll *np)
}
/* last thing to do is link it to the net device structure */
- rcu_assign_pointer(ndev->npinfo, npinfo);
+ RCU_INIT_POINTER(ndev->npinfo, npinfo);
return 0;
@@ -901,7 +903,7 @@ void __netpoll_cleanup(struct netpoll *np)
if (ops->ndo_netpoll_cleanup)
ops->ndo_netpoll_cleanup(np->dev);
- rcu_assign_pointer(np->dev->npinfo, NULL);
+ RCU_INIT_POINTER(np->dev->npinfo, NULL);
/* avoid racing with NAPI reading npinfo */
synchronize_rcu_bh();
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index e35a6fbb8110..0001c243b35c 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -2145,9 +2145,12 @@ static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until)
}
start_time = ktime_now();
- if (remaining < 100000)
- ndelay(remaining); /* really small just spin */
- else {
+ if (remaining < 100000) {
+ /* for small delays (<100us), just loop until limit is reached */
+ do {
+ end_time = ktime_now();
+ } while (ktime_lt(end_time, spin_until));
+ } else {
/* see do_nanosleep */
hrtimer_init_sleeper(&t, current);
do {
@@ -2162,8 +2165,8 @@ static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until)
hrtimer_cancel(&t.timer);
} while (t.task && pkt_dev->running && !signal_pending(current));
__set_current_state(TASK_RUNNING);
+ end_time = ktime_now();
}
- end_time = ktime_now();
pkt_dev->idle_acc += ktime_to_ns(ktime_sub(end_time, start_time));
pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay);
@@ -2602,18 +2605,18 @@ static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb,
if (!pkt_dev->page)
break;
}
- skb_shinfo(skb)->frags[i].page = pkt_dev->page;
get_page(pkt_dev->page);
+ skb_frag_set_page(skb, i, pkt_dev->page);
skb_shinfo(skb)->frags[i].page_offset = 0;
/*last fragment, fill rest of data*/
if (i == (frags - 1))
- skb_shinfo(skb)->frags[i].size =
- (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
+ skb_frag_size_set(&skb_shinfo(skb)->frags[i],
+ (datalen < PAGE_SIZE ? datalen : PAGE_SIZE));
else
- skb_shinfo(skb)->frags[i].size = frag_len;
- datalen -= skb_shinfo(skb)->frags[i].size;
- skb->len += skb_shinfo(skb)->frags[i].size;
- skb->data_len += skb_shinfo(skb)->frags[i].size;
+ skb_frag_size_set(&skb_shinfo(skb)->frags[i], frag_len);
+ datalen -= skb_frag_size(&skb_shinfo(skb)->frags[i]);
+ skb->len += skb_frag_size(&skb_shinfo(skb)->frags[i]);
+ skb->data_len += skb_frag_size(&skb_shinfo(skb)->frags[i]);
i++;
skb_shinfo(skb)->nr_frags = i;
}
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 99d9e953fe39..9083e82bdae5 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -731,7 +731,8 @@ static inline int rtnl_vfinfo_size(const struct net_device *dev)
size += num_vfs *
(nla_total_size(sizeof(struct ifla_vf_mac)) +
nla_total_size(sizeof(struct ifla_vf_vlan)) +
- nla_total_size(sizeof(struct ifla_vf_tx_rate)));
+ nla_total_size(sizeof(struct ifla_vf_tx_rate)) +
+ nla_total_size(sizeof(struct ifla_vf_spoofchk)));
return size;
} else
return 0;
@@ -954,13 +955,27 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
struct ifla_vf_mac vf_mac;
struct ifla_vf_vlan vf_vlan;
struct ifla_vf_tx_rate vf_tx_rate;
+ struct ifla_vf_spoofchk vf_spoofchk;
+
+ /*
+ * Not all SR-IOV capable drivers support the
+ * spoofcheck query. Preset to -1 so the user
+ * space tool can detect that the driver didn't
+ * report anything.
+ */
+ ivi.spoofchk = -1;
if (dev->netdev_ops->ndo_get_vf_config(dev, i, &ivi))
break;
- vf_mac.vf = vf_vlan.vf = vf_tx_rate.vf = ivi.vf;
+ vf_mac.vf =
+ vf_vlan.vf =
+ vf_tx_rate.vf =
+ vf_spoofchk.vf = ivi.vf;
+
memcpy(vf_mac.mac, ivi.mac, sizeof(ivi.mac));
vf_vlan.vlan = ivi.vlan;
vf_vlan.qos = ivi.qos;
vf_tx_rate.rate = ivi.tx_rate;
+ vf_spoofchk.setting = ivi.spoofchk;
vf = nla_nest_start(skb, IFLA_VF_INFO);
if (!vf) {
nla_nest_cancel(skb, vfinfo);
@@ -968,7 +983,10 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
}
NLA_PUT(skb, IFLA_VF_MAC, sizeof(vf_mac), &vf_mac);
NLA_PUT(skb, IFLA_VF_VLAN, sizeof(vf_vlan), &vf_vlan);
- NLA_PUT(skb, IFLA_VF_TX_RATE, sizeof(vf_tx_rate), &vf_tx_rate);
+ NLA_PUT(skb, IFLA_VF_TX_RATE, sizeof(vf_tx_rate),
+ &vf_tx_rate);
+ NLA_PUT(skb, IFLA_VF_SPOOFCHK, sizeof(vf_spoofchk),
+ &vf_spoofchk);
nla_nest_end(skb, vf);
}
nla_nest_end(skb, vfinfo);
@@ -1202,6 +1220,15 @@ static int do_setvfinfo(struct net_device *dev, struct nlattr *attr)
ivt->rate);
break;
}
+ case IFLA_VF_SPOOFCHK: {
+ struct ifla_vf_spoofchk *ivs;
+ ivs = nla_data(vf);
+ err = -EOPNOTSUPP;
+ if (ops->ndo_set_vf_spoofchk)
+ err = ops->ndo_set_vf_spoofchk(dev, ivs->vf,
+ ivs->setting);
+ break;
+ }
default:
err = -EINVAL;
break;
@@ -1604,7 +1631,6 @@ struct net_device *rtnl_create_link(struct net *src_net, struct net *net,
dev_net_set(dev, net);
dev->rtnl_link_ops = ops;
dev->rtnl_link_state = RTNL_LINK_INITIALIZING;
- dev->real_num_tx_queues = real_num_queues;
if (tb[IFLA_MTU])
dev->mtu = nla_get_u32(tb[IFLA_MTU]);
diff --git a/net/core/scm.c b/net/core/scm.c
index 811b53fb330e..ff52ad0a5150 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -173,7 +173,7 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
if (err)
goto error;
- if (pid_vnr(p->pid) != p->creds.pid) {
+ if (!p->pid || pid_vnr(p->pid) != p->creds.pid) {
struct pid *pid;
err = -ESRCH;
pid = find_get_pid(p->creds.pid);
@@ -183,8 +183,9 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
p->pid = pid;
}
- if ((p->cred->euid != p->creds.uid) ||
- (p->cred->egid != p->creds.gid)) {
+ if (!p->cred ||
+ (p->cred->euid != p->creds.uid) ||
+ (p->cred->egid != p->creds.gid)) {
struct cred *cred;
err = -ENOMEM;
cred = prepare_creds();
@@ -193,7 +194,8 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
cred->uid = cred->euid = p->creds.uid;
cred->gid = cred->egid = p->creds.gid;
- put_cred(p->cred);
+ if (p->cred)
+ put_cred(p->cred);
p->cred = cred;
}
break;
diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c
index 45329d7c9dd9..025233de25f9 100644
--- a/net/core/secure_seq.c
+++ b/net/core/secure_seq.c
@@ -35,7 +35,7 @@ static u32 seq_scale(u32 seq)
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-__u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr,
+__u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
__be16 sport, __be16 dport)
{
u32 secret[MD5_MESSAGE_BYTES / 4];
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 27002dffe7ed..ca4db40e75b8 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -184,11 +184,20 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
goto out;
prefetchw(skb);
- size = SKB_DATA_ALIGN(size);
- data = kmalloc_node_track_caller(size + sizeof(struct skb_shared_info),
- gfp_mask, node);
+ /* We do our best to align skb_shared_info on a separate cache
+ * line. It usually works because kmalloc(X > SMP_CACHE_BYTES) gives
+ * aligned memory blocks, unless SLUB/SLAB debug is enabled.
+ * Both skb->head and skb_shared_info are cache line aligned.
+ */
+ size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+ data = kmalloc_node_track_caller(size, gfp_mask, node);
if (!data)
goto nodata;
+ /* kmalloc(size) might give us more room than requested.
+ * Put skb_shared_info exactly at the end of allocated zone,
+ * to allow max possible filling before reallocation.
+ */
+ size = SKB_WITH_OVERHEAD(ksize(data));
prefetchw(data + size);
/*
@@ -197,7 +206,8 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
* the tail pointer in struct sk_buff!
*/
memset(skb, 0, offsetof(struct sk_buff, tail));
- skb->truesize = size + sizeof(struct sk_buff);
+ /* Account for allocated memory : skb + skb->head */
+ skb->truesize = SKB_TRUESIZE(size);
atomic_set(&skb->users, 1);
skb->head = data;
skb->data = data;
@@ -326,7 +336,7 @@ static void skb_release_data(struct sk_buff *skb)
if (skb_shinfo(skb)->nr_frags) {
int i;
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
- put_page(skb_shinfo(skb)->frags[i].page);
+ skb_frag_unref(skb, i);
}
/*
@@ -475,6 +485,30 @@ void consume_skb(struct sk_buff *skb)
EXPORT_SYMBOL(consume_skb);
/**
+ * skb_recycle - clean up an skb for reuse
+ * @skb: buffer
+ *
+ * Recycles the skb to be reused as a receive buffer. This
+ * function does any necessary reference count dropping, and
+ * cleans up the skbuff as if it just came from __alloc_skb().
+ */
+void skb_recycle(struct sk_buff *skb)
+{
+ struct skb_shared_info *shinfo;
+
+ skb_release_head_state(skb);
+
+ shinfo = skb_shinfo(skb);
+ memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
+ atomic_set(&shinfo->dataref, 1);
+
+ memset(skb, 0, offsetof(struct sk_buff, tail));
+ skb->data = skb->head + NET_SKB_PAD;
+ skb_reset_tail_pointer(skb);
+}
+EXPORT_SYMBOL(skb_recycle);
+
+/**
* skb_recycle_check - check if skb can be reused for receive
* @skb: buffer
* @skb_size: minimum receive buffer size
@@ -488,33 +522,10 @@ EXPORT_SYMBOL(consume_skb);
*/
bool skb_recycle_check(struct sk_buff *skb, int skb_size)
{
- struct skb_shared_info *shinfo;
-
- if (irqs_disabled())
+ if (!skb_is_recycleable(skb, skb_size))
return false;
- if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY)
- return false;
-
- if (skb_is_nonlinear(skb) || skb->fclone != SKB_FCLONE_UNAVAILABLE)
- return false;
-
- skb_size = SKB_DATA_ALIGN(skb_size + NET_SKB_PAD);
- if (skb_end_pointer(skb) - skb->head < skb_size)
- return false;
-
- if (skb_shared(skb) || skb_cloned(skb))
- return false;
-
- skb_release_head_state(skb);
-
- shinfo = skb_shinfo(skb);
- memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
- atomic_set(&shinfo->dataref, 1);
-
- memset(skb, 0, offsetof(struct sk_buff, tail));
- skb->data = skb->head + NET_SKB_PAD;
- skb_reset_tail_pointer(skb);
+ skb_recycle(skb);
return true;
}
@@ -529,6 +540,8 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
new->mac_header = old->mac_header;
skb_dst_copy(new, old);
new->rxhash = old->rxhash;
+ new->ooo_okay = old->ooo_okay;
+ new->l4_rxhash = old->l4_rxhash;
#ifdef CONFIG_XFRM
new->sp = secpath_get(old->sp);
#endif
@@ -611,8 +624,21 @@ struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src)
}
EXPORT_SYMBOL_GPL(skb_morph);
-/* skb frags copy userspace buffers to kernel */
-static int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
+/* skb_copy_ubufs - copy userspace skb frags buffers to kernel
+ * @skb: the skb to modify
+ * @gfp_mask: allocation priority
+ *
+ * This must be called on SKBTX_DEV_ZEROCOPY skb.
+ * It will copy all frags into kernel and drop the reference
+ * to userspace pages.
+ *
+ * If this function is called from an interrupt gfp_mask() must be
+ * %GFP_ATOMIC.
+ *
+ * Returns 0 on success or a negative error code on failure
+ * to allocate kernel memory to copy to.
+ */
+int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
{
int i;
int num_frags = skb_shinfo(skb)->nr_frags;
@@ -634,7 +660,7 @@ static int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
}
vaddr = kmap_skb_frag(&skb_shinfo(skb)->frags[i]);
memcpy(page_address(page),
- vaddr + f->page_offset, f->size);
+ vaddr + f->page_offset, skb_frag_size(f));
kunmap_skb_frag(vaddr);
page->private = (unsigned long)head;
head = page;
@@ -642,16 +668,18 @@ static int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
/* skb frags release userspace buffers */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
- put_page(skb_shinfo(skb)->frags[i].page);
+ skb_frag_unref(skb, i);
uarg->callback(uarg);
/* skb frags point to kernel buffers */
for (i = skb_shinfo(skb)->nr_frags; i > 0; i--) {
- skb_shinfo(skb)->frags[i - 1].page_offset = 0;
- skb_shinfo(skb)->frags[i - 1].page = head;
+ __skb_fill_page_desc(skb, i-1, head, 0,
+ skb_shinfo(skb)->frags[i - 1].size);
head = (struct page *)head->private;
}
+
+ skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;
return 0;
}
@@ -677,7 +705,6 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
if (skb_copy_ubufs(skb, gfp_mask))
return NULL;
- skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;
}
n = skb + 1;
@@ -803,11 +830,10 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask)
n = NULL;
goto out;
}
- skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;
}
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i];
- get_page(skb_shinfo(n)->frags[i].page);
+ skb_frag_ref(skb, i);
}
skb_shinfo(n)->nr_frags = i;
}
@@ -896,10 +922,9 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
if (skb_copy_ubufs(skb, gfp_mask))
goto nofrags;
- skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;
}
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
- get_page(skb_shinfo(skb)->frags[i].page);
+ skb_frag_ref(skb, i);
if (skb_has_frag_list(skb))
skb_clone_fraglist(skb);
@@ -1166,20 +1191,20 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len)
goto drop_pages;
for (; i < nfrags; i++) {
- int end = offset + skb_shinfo(skb)->frags[i].size;
+ int end = offset + skb_frag_size(&skb_shinfo(skb)->frags[i]);
if (end < len) {
offset = end;
continue;
}
- skb_shinfo(skb)->frags[i++].size = len - offset;
+ skb_frag_size_set(&skb_shinfo(skb)->frags[i++], len - offset);
drop_pages:
skb_shinfo(skb)->nr_frags = i;
for (; i < nfrags; i++)
- put_page(skb_shinfo(skb)->frags[i].page);
+ skb_frag_unref(skb, i);
if (skb_has_frag_list(skb))
skb_drop_fraglist(skb);
@@ -1282,9 +1307,11 @@ unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta)
/* Estimate size of pulled pages. */
eat = delta;
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- if (skb_shinfo(skb)->frags[i].size >= eat)
+ int size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
+
+ if (size >= eat)
goto pull_pages;
- eat -= skb_shinfo(skb)->frags[i].size;
+ eat -= size;
}
/* If we need update frag list, we are in troubles.
@@ -1347,14 +1374,16 @@ pull_pages:
eat = delta;
k = 0;
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- if (skb_shinfo(skb)->frags[i].size <= eat) {
- put_page(skb_shinfo(skb)->frags[i].page);
- eat -= skb_shinfo(skb)->frags[i].size;
+ int size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
+
+ if (size <= eat) {
+ skb_frag_unref(skb, i);
+ eat -= size;
} else {
skb_shinfo(skb)->frags[k] = skb_shinfo(skb)->frags[i];
if (eat) {
skb_shinfo(skb)->frags[k].page_offset += eat;
- skb_shinfo(skb)->frags[k].size -= eat;
+ skb_frag_size_sub(&skb_shinfo(skb)->frags[k], eat);
eat = 0;
}
k++;
@@ -1409,7 +1438,7 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
WARN_ON(start > offset + len);
- end = start + skb_shinfo(skb)->frags[i].size;
+ end = start + skb_frag_size(&skb_shinfo(skb)->frags[i]);
if ((copy = end - offset) > 0) {
u8 *vaddr;
@@ -1607,7 +1636,8 @@ static int __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe,
for (seg = 0; seg < skb_shinfo(skb)->nr_frags; seg++) {
const skb_frag_t *f = &skb_shinfo(skb)->frags[seg];
- if (__splice_segment(f->page, f->page_offset, f->size,
+ if (__splice_segment(skb_frag_page(f),
+ f->page_offset, skb_frag_size(f),
offset, len, skb, spd, 0, sk, pipe))
return 1;
}
@@ -1717,7 +1747,7 @@ int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len)
WARN_ON(start > offset + len);
- end = start + frag->size;
+ end = start + skb_frag_size(frag);
if ((copy = end - offset) > 0) {
u8 *vaddr;
@@ -1790,7 +1820,7 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
WARN_ON(start > offset + len);
- end = start + skb_shinfo(skb)->frags[i].size;
+ end = start + skb_frag_size(&skb_shinfo(skb)->frags[i]);
if ((copy = end - offset) > 0) {
__wsum csum2;
u8 *vaddr;
@@ -1865,7 +1895,7 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
WARN_ON(start > offset + len);
- end = start + skb_shinfo(skb)->frags[i].size;
+ end = start + skb_frag_size(&skb_shinfo(skb)->frags[i]);
if ((copy = end - offset) > 0) {
__wsum csum2;
u8 *vaddr;
@@ -2138,7 +2168,7 @@ static inline void skb_split_no_header(struct sk_buff *skb,
skb->data_len = len - pos;
for (i = 0; i < nfrags; i++) {
- int size = skb_shinfo(skb)->frags[i].size;
+ int size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
if (pos + size > len) {
skb_shinfo(skb1)->frags[k] = skb_shinfo(skb)->frags[i];
@@ -2152,10 +2182,10 @@ static inline void skb_split_no_header(struct sk_buff *skb,
* where splitting is expensive.
* 2. Split is accurately. We make this.
*/
- get_page(skb_shinfo(skb)->frags[i].page);
+ skb_frag_ref(skb, i);
skb_shinfo(skb1)->frags[0].page_offset += len - pos;
- skb_shinfo(skb1)->frags[0].size -= len - pos;
- skb_shinfo(skb)->frags[i].size = len - pos;
+ skb_frag_size_sub(&skb_shinfo(skb1)->frags[0], len - pos);
+ skb_frag_size_set(&skb_shinfo(skb)->frags[i], len - pos);
skb_shinfo(skb)->nr_frags++;
}
k++;
@@ -2227,12 +2257,13 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen)
* commit all, so that we don't have to undo partial changes
*/
if (!to ||
- !skb_can_coalesce(tgt, to, fragfrom->page, fragfrom->page_offset)) {
+ !skb_can_coalesce(tgt, to, skb_frag_page(fragfrom),
+ fragfrom->page_offset)) {
merge = -1;
} else {
merge = to - 1;
- todo -= fragfrom->size;
+ todo -= skb_frag_size(fragfrom);
if (todo < 0) {
if (skb_prepare_for_shift(skb) ||
skb_prepare_for_shift(tgt))
@@ -2242,8 +2273,8 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen)
fragfrom = &skb_shinfo(skb)->frags[from];
fragto = &skb_shinfo(tgt)->frags[merge];
- fragto->size += shiftlen;
- fragfrom->size -= shiftlen;
+ skb_frag_size_add(fragto, shiftlen);
+ skb_frag_size_sub(fragfrom, shiftlen);
fragfrom->page_offset += shiftlen;
goto onlymerged;
@@ -2267,20 +2298,20 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen)
fragfrom = &skb_shinfo(skb)->frags[from];
fragto = &skb_shinfo(tgt)->frags[to];
- if (todo >= fragfrom->size) {
+ if (todo >= skb_frag_size(fragfrom)) {
*fragto = *fragfrom;
- todo -= fragfrom->size;
+ todo -= skb_frag_size(fragfrom);
from++;
to++;
} else {
- get_page(fragfrom->page);
+ __skb_frag_ref(fragfrom);
fragto->page = fragfrom->page;
fragto->page_offset = fragfrom->page_offset;
- fragto->size = todo;
+ skb_frag_size_set(fragto, todo);
fragfrom->page_offset += todo;
- fragfrom->size -= todo;
+ skb_frag_size_sub(fragfrom, todo);
todo = 0;
to++;
@@ -2295,8 +2326,8 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen)
fragfrom = &skb_shinfo(skb)->frags[0];
fragto = &skb_shinfo(tgt)->frags[merge];
- fragto->size += fragfrom->size;
- put_page(fragfrom->page);
+ skb_frag_size_add(fragto, skb_frag_size(fragfrom));
+ __skb_frag_unref(fragfrom);
}
/* Reposition in the original skb */
@@ -2393,7 +2424,7 @@ next_skb:
while (st->frag_idx < skb_shinfo(st->cur_skb)->nr_frags) {
frag = &skb_shinfo(st->cur_skb)->frags[st->frag_idx];
- block_limit = frag->size + st->stepped_offset;
+ block_limit = skb_frag_size(frag) + st->stepped_offset;
if (abs_offset < block_limit) {
if (!st->frag_data)
@@ -2411,7 +2442,7 @@ next_skb:
}
st->frag_idx++;
- st->stepped_offset += frag->size;
+ st->stepped_offset += skb_frag_size(frag);
}
if (st->frag_data) {
@@ -2541,14 +2572,13 @@ int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb,
left = PAGE_SIZE - frag->page_offset;
copy = (length > left)? left : length;
- ret = getfrag(from, (page_address(frag->page) +
- frag->page_offset + frag->size),
+ ret = getfrag(from, skb_frag_address(frag) + skb_frag_size(frag),
offset, copy, 0, skb);
if (ret < 0)
return -EFAULT;
/* copy was successful so update the size parameters */
- frag->size += copy;
+ skb_frag_size_add(frag, copy);
skb->len += copy;
skb->data_len += copy;
offset += copy;
@@ -2694,12 +2724,12 @@ struct sk_buff *skb_segment(struct sk_buff *skb, u32 features)
while (pos < offset + len && i < nfrags) {
*frag = skb_shinfo(skb)->frags[i];
- get_page(frag->page);
- size = frag->size;
+ __skb_frag_ref(frag);
+ size = skb_frag_size(frag);
if (pos < offset) {
frag->page_offset += offset - pos;
- frag->size -= offset - pos;
+ skb_frag_size_sub(frag, offset - pos);
}
skb_shinfo(nskb)->nr_frags++;
@@ -2708,7 +2738,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, u32 features)
i++;
pos += size;
} else {
- frag->size -= pos + size - (offset + len);
+ skb_frag_size_sub(frag, pos + size - (offset + len));
goto skip_fraglist;
}
@@ -2788,7 +2818,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
} while (--i);
frag->page_offset += offset;
- frag->size -= offset;
+ skb_frag_size_sub(frag, offset);
skb->truesize -= skb->data_len;
skb->len -= skb->data_len;
@@ -2840,7 +2870,7 @@ merge:
unsigned int eat = offset - headlen;
skbinfo->frags[0].page_offset += eat;
- skbinfo->frags[0].size -= eat;
+ skb_frag_size_sub(&skbinfo->frags[0], eat);
skb->data_len -= eat;
skb->len -= eat;
offset = headlen;
@@ -2911,13 +2941,13 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
WARN_ON(start > offset + len);
- end = start + skb_shinfo(skb)->frags[i].size;
+ end = start + skb_frag_size(&skb_shinfo(skb)->frags[i]);
if ((copy = end - offset) > 0) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
if (copy > len)
copy = len;
- sg_set_page(&sg[elt], frag->page, copy,
+ sg_set_page(&sg[elt], skb_frag_page(frag), copy,
frag->page_offset+offset-start);
elt++;
if (!(len -= copy))
diff --git a/net/core/sock.c b/net/core/sock.c
index bc745d00ea4d..5a087626bb3a 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -207,7 +207,7 @@ static struct lock_class_key af_callback_keys[AF_MAX];
* not depend upon such differences.
*/
#define _SK_MEM_PACKETS 256
-#define _SK_MEM_OVERHEAD (sizeof(struct sk_buff) + 256)
+#define _SK_MEM_OVERHEAD SKB_TRUESIZE(256)
#define SK_WMEM_MAX (_SK_MEM_OVERHEAD * _SK_MEM_PACKETS)
#define SK_RMEM_MAX (_SK_MEM_OVERHEAD * _SK_MEM_PACKETS)
@@ -387,7 +387,7 @@ struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie)
if (dst && dst->obsolete && dst->ops->check(dst, cookie) == NULL) {
sk_tx_queue_clear(sk);
- rcu_assign_pointer(sk->sk_dst_cache, NULL);
+ RCU_INIT_POINTER(sk->sk_dst_cache, NULL);
dst_release(dst);
return NULL;
}
@@ -738,10 +738,7 @@ set_rcvbuf:
/* We implement the SO_SNDLOWAT etc to
not be settable (1003.1g 5.3) */
case SO_RXQ_OVFL:
- if (valbool)
- sock_set_flag(sk, SOCK_RXQ_OVFL);
- else
- sock_reset_flag(sk, SOCK_RXQ_OVFL);
+ sock_valbool_flag(sk, SOCK_RXQ_OVFL, valbool);
break;
default:
ret = -ENOPROTOOPT;
@@ -1158,7 +1155,7 @@ static void __sk_free(struct sock *sk)
atomic_read(&sk->sk_wmem_alloc) == 0);
if (filter) {
sk_filter_uncharge(sk, filter);
- rcu_assign_pointer(sk->sk_filter, NULL);
+ RCU_INIT_POINTER(sk->sk_filter, NULL);
}
sock_disable_timestamp(sk, SOCK_TIMESTAMP);
@@ -1533,7 +1530,6 @@ struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,
skb_shinfo(skb)->nr_frags = npages;
for (i = 0; i < npages; i++) {
struct page *page;
- skb_frag_t *frag;
page = alloc_pages(sk->sk_allocation, 0);
if (!page) {
@@ -1543,12 +1539,11 @@ struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,
goto failure;
}
- frag = &skb_shinfo(skb)->frags[i];
- frag->page = page;
- frag->page_offset = 0;
- frag->size = (data_len >= PAGE_SIZE ?
- PAGE_SIZE :
- data_len);
+ __skb_fill_page_desc(skb, i,
+ page, 0,
+ (data_len >= PAGE_SIZE ?
+ PAGE_SIZE :
+ data_len));
data_len -= PAGE_SIZE;
}
diff --git a/net/core/timestamping.c b/net/core/timestamping.c
index 98a52640e7cd..82fb28857b64 100644
--- a/net/core/timestamping.c
+++ b/net/core/timestamping.c
@@ -57,9 +57,13 @@ void skb_clone_tx_timestamp(struct sk_buff *skb)
case PTP_CLASS_V2_VLAN:
phydev = skb->dev->phydev;
if (likely(phydev->drv->txtstamp)) {
+ if (!atomic_inc_not_zero(&sk->sk_refcnt))
+ return;
clone = skb_clone(skb, GFP_ATOMIC);
- if (!clone)
+ if (!clone) {
+ sock_put(sk);
return;
+ }
clone->sk = sk;
phydev->drv->txtstamp(phydev, clone, type);
}
@@ -77,8 +81,11 @@ void skb_complete_tx_timestamp(struct sk_buff *skb,
struct sock_exterr_skb *serr;
int err;
- if (!hwtstamps)
+ if (!hwtstamps) {
+ sock_put(sk);
+ kfree_skb(skb);
return;
+ }
*skb_hwtstamps(skb) = *hwtstamps;
serr = SKB_EXT_ERR(skb);
@@ -87,6 +94,7 @@ void skb_complete_tx_timestamp(struct sk_buff *skb,
serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
skb->sk = NULL;
err = sock_queue_err_skb(sk, skb);
+ sock_put(sk);
if (err)
kfree_skb(skb);
}
diff --git a/net/core/user_dma.c b/net/core/user_dma.c
index 25d717ebc92e..2d7cf3d52b4c 100644
--- a/net/core/user_dma.c
+++ b/net/core/user_dma.c
@@ -71,14 +71,14 @@ int dma_skb_copy_datagram_iovec(struct dma_chan *chan,
/* Copy paged appendix. Hmm... why does this look so complicated? */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
int end;
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
WARN_ON(start > offset + len);
- end = start + skb_shinfo(skb)->frags[i].size;
+ end = start + skb_frag_size(frag);
copy = end - offset;
if (copy > 0) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- struct page *page = frag->page;
+ struct page *page = skb_frag_page(frag);
if (copy > len)
copy = len;
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c
index 3cb56af4e13c..9bfbc1d1b50c 100644
--- a/net/dcb/dcbnl.c
+++ b/net/dcb/dcbnl.c
@@ -1255,7 +1255,7 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
spin_lock(&dcb_lock);
list_for_each_entry(itr, &dcb_app_list, list) {
- if (strncmp(itr->name, netdev->name, IFNAMSIZ) == 0) {
+ if (itr->ifindex == netdev->ifindex) {
err = nla_put(skb, DCB_ATTR_IEEE_APP, sizeof(itr->app),
&itr->app);
if (err) {
@@ -1412,7 +1412,7 @@ static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev)
goto dcb_unlock;
list_for_each_entry(itr, &dcb_app_list, list) {
- if (strncmp(itr->name, netdev->name, IFNAMSIZ) == 0) {
+ if (itr->ifindex == netdev->ifindex) {
struct nlattr *app_nest = nla_nest_start(skb,
DCB_ATTR_APP);
if (!app_nest)
@@ -2050,7 +2050,7 @@ u8 dcb_getapp(struct net_device *dev, struct dcb_app *app)
list_for_each_entry(itr, &dcb_app_list, list) {
if (itr->app.selector == app->selector &&
itr->app.protocol == app->protocol &&
- (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) {
+ itr->ifindex == dev->ifindex) {
prio = itr->app.priority;
break;
}
@@ -2073,15 +2073,17 @@ int dcb_setapp(struct net_device *dev, struct dcb_app *new)
struct dcb_app_type *itr;
struct dcb_app_type event;
- memcpy(&event.name, dev->name, sizeof(event.name));
+ event.ifindex = dev->ifindex;
memcpy(&event.app, new, sizeof(event.app));
+ if (dev->dcbnl_ops->getdcbx)
+ event.dcbx = dev->dcbnl_ops->getdcbx(dev);
spin_lock(&dcb_lock);
/* Search for existing match and replace */
list_for_each_entry(itr, &dcb_app_list, list) {
if (itr->app.selector == new->selector &&
itr->app.protocol == new->protocol &&
- (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) {
+ itr->ifindex == dev->ifindex) {
if (new->priority)
itr->app.priority = new->priority;
else {
@@ -2101,7 +2103,7 @@ int dcb_setapp(struct net_device *dev, struct dcb_app *new)
}
memcpy(&entry->app, new, sizeof(*new));
- strncpy(entry->name, dev->name, IFNAMSIZ);
+ entry->ifindex = dev->ifindex;
list_add(&entry->list, &dcb_app_list);
}
out:
@@ -2127,7 +2129,7 @@ u8 dcb_ieee_getapp_mask(struct net_device *dev, struct dcb_app *app)
list_for_each_entry(itr, &dcb_app_list, list) {
if (itr->app.selector == app->selector &&
itr->app.protocol == app->protocol &&
- (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) {
+ itr->ifindex == dev->ifindex) {
prio |= 1 << itr->app.priority;
}
}
@@ -2150,8 +2152,10 @@ int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new)
struct dcb_app_type event;
int err = 0;
- memcpy(&event.name, dev->name, sizeof(event.name));
+ event.ifindex = dev->ifindex;
memcpy(&event.app, new, sizeof(event.app));
+ if (dev->dcbnl_ops->getdcbx)
+ event.dcbx = dev->dcbnl_ops->getdcbx(dev);
spin_lock(&dcb_lock);
/* Search for existing match and abort if found */
@@ -2159,7 +2163,7 @@ int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new)
if (itr->app.selector == new->selector &&
itr->app.protocol == new->protocol &&
itr->app.priority == new->priority &&
- (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) {
+ itr->ifindex == dev->ifindex) {
err = -EEXIST;
goto out;
}
@@ -2173,7 +2177,7 @@ int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new)
}
memcpy(&entry->app, new, sizeof(*new));
- strncpy(entry->name, dev->name, IFNAMSIZ);
+ entry->ifindex = dev->ifindex;
list_add(&entry->list, &dcb_app_list);
out:
spin_unlock(&dcb_lock);
@@ -2194,8 +2198,10 @@ int dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del)
struct dcb_app_type event;
int err = -ENOENT;
- memcpy(&event.name, dev->name, sizeof(event.name));
+ event.ifindex = dev->ifindex;
memcpy(&event.app, del, sizeof(event.app));
+ if (dev->dcbnl_ops->getdcbx)
+ event.dcbx = dev->dcbnl_ops->getdcbx(dev);
spin_lock(&dcb_lock);
/* Search for existing match and remove it. */
@@ -2203,7 +2209,7 @@ int dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del)
if (itr->app.selector == del->selector &&
itr->app.protocol == del->protocol &&
itr->app.priority == del->priority &&
- (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) {
+ itr->ifindex == dev->ifindex) {
list_del(&itr->list);
kfree(itr);
err = 0;
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c
index 0462040fc818..67164bb6ae4d 100644
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -85,7 +85,6 @@ static int ccid2_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val)
{
- struct dccp_sock *dp = dccp_sk(sk);
u32 max_ratio = DIV_ROUND_UP(ccid2_hc_tx_sk(sk)->tx_cwnd, 2);
/*
@@ -98,14 +97,33 @@ static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val)
DCCP_WARN("Limiting Ack Ratio (%u) to %u\n", val, max_ratio);
val = max_ratio;
}
- if (val > DCCPF_ACK_RATIO_MAX)
- val = DCCPF_ACK_RATIO_MAX;
+ dccp_feat_signal_nn_change(sk, DCCPF_ACK_RATIO,
+ min_t(u32, val, DCCPF_ACK_RATIO_MAX));
+}
- if (val == dp->dccps_l_ack_ratio)
- return;
+static void ccid2_check_l_ack_ratio(struct sock *sk)
+{
+ struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
- ccid2_pr_debug("changing local ack ratio to %u\n", val);
- dp->dccps_l_ack_ratio = val;
+ /*
+ * After a loss, idle period, application limited period, or RTO we
+ * need to check that the ack ratio is still less than the congestion
+ * window. Otherwise, we will send an entire congestion window of
+ * packets and got no response because we haven't sent ack ratio
+ * packets yet.
+ * If the ack ratio does need to be reduced, we reduce it to half of
+ * the congestion window (or 1 if that's zero) instead of to the
+ * congestion window. This prevents problems if one ack is lost.
+ */
+ if (dccp_feat_nn_get(sk, DCCPF_ACK_RATIO) > hc->tx_cwnd)
+ ccid2_change_l_ack_ratio(sk, hc->tx_cwnd/2 ? : 1U);
+}
+
+static void ccid2_change_l_seq_window(struct sock *sk, u64 val)
+{
+ dccp_feat_signal_nn_change(sk, DCCPF_SEQUENCE_WINDOW,
+ clamp_val(val, DCCPF_SEQ_WMIN,
+ DCCPF_SEQ_WMAX));
}
static void ccid2_hc_tx_rto_expire(unsigned long data)
@@ -187,6 +205,8 @@ static void ccid2_cwnd_application_limited(struct sock *sk, const u32 now)
}
hc->tx_cwnd_used = 0;
hc->tx_cwnd_stamp = now;
+
+ ccid2_check_l_ack_ratio(sk);
}
/* This borrows the code of tcp_cwnd_restart() */
@@ -205,6 +225,8 @@ static void ccid2_cwnd_restart(struct sock *sk, const u32 now)
hc->tx_cwnd_stamp = now;
hc->tx_cwnd_used = 0;
+
+ ccid2_check_l_ack_ratio(sk);
}
static void ccid2_hc_tx_packet_sent(struct sock *sk, unsigned int len)
@@ -405,17 +427,37 @@ static void ccid2_new_ack(struct sock *sk, struct ccid2_seq *seqp,
unsigned int *maxincr)
{
struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
-
- if (hc->tx_cwnd < hc->tx_ssthresh) {
- if (*maxincr > 0 && ++hc->tx_packets_acked == 2) {
+ struct dccp_sock *dp = dccp_sk(sk);
+ int r_seq_used = hc->tx_cwnd / dp->dccps_l_ack_ratio;
+
+ if (hc->tx_cwnd < dp->dccps_l_seq_win &&
+ r_seq_used < dp->dccps_r_seq_win) {
+ if (hc->tx_cwnd < hc->tx_ssthresh) {
+ if (*maxincr > 0 && ++hc->tx_packets_acked >= 2) {
+ hc->tx_cwnd += 1;
+ *maxincr -= 1;
+ hc->tx_packets_acked = 0;
+ }
+ } else if (++hc->tx_packets_acked >= hc->tx_cwnd) {
hc->tx_cwnd += 1;
- *maxincr -= 1;
hc->tx_packets_acked = 0;
}
- } else if (++hc->tx_packets_acked >= hc->tx_cwnd) {
- hc->tx_cwnd += 1;
- hc->tx_packets_acked = 0;
}
+
+ /*
+ * Adjust the local sequence window and the ack ratio to allow about
+ * 5 times the number of packets in the network (RFC 4340 7.5.2)
+ */
+ if (r_seq_used * CCID2_WIN_CHANGE_FACTOR >= dp->dccps_r_seq_win)
+ ccid2_change_l_ack_ratio(sk, dp->dccps_l_ack_ratio * 2);
+ else if (r_seq_used * CCID2_WIN_CHANGE_FACTOR < dp->dccps_r_seq_win/2)
+ ccid2_change_l_ack_ratio(sk, dp->dccps_l_ack_ratio / 2 ? : 1U);
+
+ if (hc->tx_cwnd * CCID2_WIN_CHANGE_FACTOR >= dp->dccps_l_seq_win)
+ ccid2_change_l_seq_window(sk, dp->dccps_l_seq_win * 2);
+ else if (hc->tx_cwnd * CCID2_WIN_CHANGE_FACTOR < dp->dccps_l_seq_win/2)
+ ccid2_change_l_seq_window(sk, dp->dccps_l_seq_win / 2);
+
/*
* FIXME: RTT is sampled several times per acknowledgment (for each
* entry in the Ack Vector), instead of once per Ack (as in TCP SACK).
@@ -441,9 +483,7 @@ static void ccid2_congestion_event(struct sock *sk, struct ccid2_seq *seqp)
hc->tx_cwnd = hc->tx_cwnd / 2 ? : 1U;
hc->tx_ssthresh = max(hc->tx_cwnd, 2U);
- /* Avoid spurious timeouts resulting from Ack Ratio > cwnd */
- if (dccp_sk(sk)->dccps_l_ack_ratio > hc->tx_cwnd)
- ccid2_change_l_ack_ratio(sk, hc->tx_cwnd);
+ ccid2_check_l_ack_ratio(sk);
}
static int ccid2_hc_tx_parse_options(struct sock *sk, u8 packet_type,
@@ -494,8 +534,16 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
if (hc->tx_rpdupack >= NUMDUPACK) {
hc->tx_rpdupack = -1; /* XXX lame */
hc->tx_rpseq = 0;
-
+#ifdef __CCID2_COPES_GRACEFULLY_WITH_ACK_CONGESTION_CONTROL__
+ /*
+ * FIXME: Ack Congestion Control is broken; in
+ * the current state instabilities occurred with
+ * Ack Ratios greater than 1; causing hang-ups
+ * and long RTO timeouts. This needs to be fixed
+ * before opening up dynamic changes. -- gerrit
+ */
ccid2_change_l_ack_ratio(sk, 2 * dp->dccps_l_ack_ratio);
+#endif
}
}
}
diff --git a/net/dccp/ccids/ccid2.h b/net/dccp/ccids/ccid2.h
index f585d330e1e5..18c97543e522 100644
--- a/net/dccp/ccids/ccid2.h
+++ b/net/dccp/ccids/ccid2.h
@@ -43,6 +43,12 @@ struct ccid2_seq {
#define CCID2_SEQBUF_LEN 1024
#define CCID2_SEQBUF_MAX 128
+/*
+ * Multiple of congestion window to keep the sequence window at
+ * (RFC 4340 7.5.2)
+ */
+#define CCID2_WIN_CHANGE_FACTOR 5
+
/**
* struct ccid2_hc_tx_sock - CCID2 TX half connection
* @tx_{cwnd,ssthresh,pipe}: as per RFC 4341, section 5
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index 5fdb07229017..583490aaf56f 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -474,6 +474,7 @@ static inline int dccp_ack_pending(const struct sock *sk)
return dccp_ackvec_pending(sk) || inet_csk_ack_scheduled(sk);
}
+extern int dccp_feat_signal_nn_change(struct sock *sk, u8 feat, u64 nn_val);
extern int dccp_feat_finalise_settings(struct dccp_sock *dp);
extern int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq);
extern int dccp_feat_insert_opts(struct dccp_sock*, struct dccp_request_sock*,
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index 568def952722..23cea0ee3101 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -12,6 +12,7 @@
* -----------
* o Feature negotiation is coordinated with connection setup (as in TCP), wild
* changes of parameters of an established connection are not supported.
+ * o Changing non-negotiable (NN) values is supported in state OPEN/PARTOPEN.
* o All currently known SP features have 1-byte quantities. If in the future
* extensions of RFCs 4340..42 define features with item lengths larger than
* one byte, a feature-specific extension of the code will be required.
@@ -343,6 +344,20 @@ static int __dccp_feat_activate(struct sock *sk, const int idx,
return dccp_feat_table[idx].activation_hdlr(sk, val, rx);
}
+/**
+ * dccp_feat_activate - Activate feature value on socket
+ * @sk: fully connected DCCP socket (after handshake is complete)
+ * @feat_num: feature to activate, one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is meant
+ * @fval: the value (SP or NN) to activate, or NULL to use the default value
+ * For general use this function is preferable over __dccp_feat_activate().
+ */
+static int dccp_feat_activate(struct sock *sk, u8 feat_num, bool local,
+ dccp_feat_val const *fval)
+{
+ return __dccp_feat_activate(sk, dccp_feat_index(feat_num), local, fval);
+}
+
/* Test for "Req'd" feature (RFC 4340, 6.4) */
static inline int dccp_feat_must_be_understood(u8 feat_num)
{
@@ -650,11 +665,22 @@ int dccp_feat_insert_opts(struct dccp_sock *dp, struct dccp_request_sock *dreq,
return -1;
if (pos->needs_mandatory && dccp_insert_option_mandatory(skb))
return -1;
- /*
- * Enter CHANGING after transmitting the Change option (6.6.2).
- */
- if (pos->state == FEAT_INITIALISING)
- pos->state = FEAT_CHANGING;
+
+ if (skb->sk->sk_state == DCCP_OPEN &&
+ (opt == DCCPO_CONFIRM_R || opt == DCCPO_CONFIRM_L)) {
+ /*
+ * Confirms don't get retransmitted (6.6.3) once the
+ * connection is in state OPEN
+ */
+ dccp_feat_list_pop(pos);
+ } else {
+ /*
+ * Enter CHANGING after transmitting the Change
+ * option (6.6.2).
+ */
+ if (pos->state == FEAT_INITIALISING)
+ pos->state = FEAT_CHANGING;
+ }
}
return 0;
}
@@ -730,6 +756,70 @@ int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
0, list, len);
}
+/**
+ * dccp_feat_nn_get - Query current/pending value of NN feature
+ * @sk: DCCP socket of an established connection
+ * @feat: NN feature number from %dccp_feature_numbers
+ * For a known NN feature, returns value currently being negotiated, or
+ * current (confirmed) value if no negotiation is going on.
+ */
+u64 dccp_feat_nn_get(struct sock *sk, u8 feat)
+{
+ if (dccp_feat_type(feat) == FEAT_NN) {
+ struct dccp_sock *dp = dccp_sk(sk);
+ struct dccp_feat_entry *entry;
+
+ entry = dccp_feat_list_lookup(&dp->dccps_featneg, feat, 1);
+ if (entry != NULL)
+ return entry->val.nn;
+
+ switch (feat) {
+ case DCCPF_ACK_RATIO:
+ return dp->dccps_l_ack_ratio;
+ case DCCPF_SEQUENCE_WINDOW:
+ return dp->dccps_l_seq_win;
+ }
+ }
+ DCCP_BUG("attempt to look up unsupported feature %u", feat);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dccp_feat_nn_get);
+
+/**
+ * dccp_feat_signal_nn_change - Update NN values for an established connection
+ * @sk: DCCP socket of an established connection
+ * @feat: NN feature number from %dccp_feature_numbers
+ * @nn_val: the new value to use
+ * This function is used to communicate NN updates out-of-band.
+ */
+int dccp_feat_signal_nn_change(struct sock *sk, u8 feat, u64 nn_val)
+{
+ struct list_head *fn = &dccp_sk(sk)->dccps_featneg;
+ dccp_feat_val fval = { .nn = nn_val };
+ struct dccp_feat_entry *entry;
+
+ if (sk->sk_state != DCCP_OPEN && sk->sk_state != DCCP_PARTOPEN)
+ return 0;
+
+ if (dccp_feat_type(feat) != FEAT_NN ||
+ !dccp_feat_is_valid_nn_val(feat, nn_val))
+ return -EINVAL;
+
+ if (nn_val == dccp_feat_nn_get(sk, feat))
+ return 0; /* already set or negotiation under way */
+
+ entry = dccp_feat_list_lookup(fn, feat, 1);
+ if (entry != NULL) {
+ dccp_pr_debug("Clobbering existing NN entry %llu -> %llu\n",
+ (unsigned long long)entry->val.nn,
+ (unsigned long long)nn_val);
+ dccp_feat_list_pop(entry);
+ }
+
+ inet_csk_schedule_ack(sk);
+ return dccp_feat_push_change(fn, feat, 1, 0, &fval);
+}
+EXPORT_SYMBOL_GPL(dccp_feat_signal_nn_change);
/*
* Tracking features whose value depend on the choice of CCID
@@ -1187,6 +1277,100 @@ confirmation_failed:
}
/**
+ * dccp_feat_handle_nn_established - Fast-path reception of NN options
+ * @sk: socket of an established DCCP connection
+ * @mandatory: whether @opt was preceded by a Mandatory option
+ * @opt: %DCCPO_CHANGE_L | %DCCPO_CONFIRM_R (NN only)
+ * @feat: NN number, one of %dccp_feature_numbers
+ * @val: NN value
+ * @len: length of @val in bytes
+ * This function combines the functionality of change_recv/confirm_recv, with
+ * the following differences (reset codes are the same):
+ * - cleanup after receiving the Confirm;
+ * - values are directly activated after successful parsing;
+ * - deliberately restricted to NN features.
+ * The restriction to NN features is essential since SP features can have non-
+ * predictable outcomes (depending on the remote configuration), and are inter-
+ * dependent (CCIDs for instance cause further dependencies).
+ */
+static u8 dccp_feat_handle_nn_established(struct sock *sk, u8 mandatory, u8 opt,
+ u8 feat, u8 *val, u8 len)
+{
+ struct list_head *fn = &dccp_sk(sk)->dccps_featneg;
+ const bool local = (opt == DCCPO_CONFIRM_R);
+ struct dccp_feat_entry *entry;
+ u8 type = dccp_feat_type(feat);
+ dccp_feat_val fval;
+
+ dccp_feat_print_opt(opt, feat, val, len, mandatory);
+
+ /* Ignore non-mandatory unknown and non-NN features */
+ if (type == FEAT_UNKNOWN) {
+ if (local && !mandatory)
+ return 0;
+ goto fast_path_unknown;
+ } else if (type != FEAT_NN) {
+ return 0;
+ }
+
+ /*
+ * We don't accept empty Confirms, since in fast-path feature
+ * negotiation the values are enabled immediately after sending
+ * the Change option.
+ * Empty Changes on the other hand are invalid (RFC 4340, 6.1).
+ */
+ if (len == 0 || len > sizeof(fval.nn))
+ goto fast_path_unknown;
+
+ if (opt == DCCPO_CHANGE_L) {
+ fval.nn = dccp_decode_value_var(val, len);
+ if (!dccp_feat_is_valid_nn_val(feat, fval.nn))
+ goto fast_path_unknown;
+
+ if (dccp_feat_push_confirm(fn, feat, local, &fval) ||
+ dccp_feat_activate(sk, feat, local, &fval))
+ return DCCP_RESET_CODE_TOO_BUSY;
+
+ /* set the `Ack Pending' flag to piggyback a Confirm */
+ inet_csk_schedule_ack(sk);
+
+ } else if (opt == DCCPO_CONFIRM_R) {
+ entry = dccp_feat_list_lookup(fn, feat, local);
+ if (entry == NULL || entry->state != FEAT_CHANGING)
+ return 0;
+
+ fval.nn = dccp_decode_value_var(val, len);
+ /*
+ * Just ignore a value that doesn't match our current value.
+ * If the option changes twice within two RTTs, then at least
+ * one CONFIRM will be received for the old value after a
+ * new CHANGE was sent.
+ */
+ if (fval.nn != entry->val.nn)
+ return 0;
+
+ /* Only activate after receiving the Confirm option (6.6.1). */
+ dccp_feat_activate(sk, feat, local, &fval);
+
+ /* It has been confirmed - so remove the entry */
+ dccp_feat_list_pop(entry);
+
+ } else {
+ DCCP_WARN("Received illegal option %u\n", opt);
+ goto fast_path_failed;
+ }
+ return 0;
+
+fast_path_unknown:
+ if (!mandatory)
+ return dccp_push_empty_confirm(fn, feat, local);
+
+fast_path_failed:
+ return mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR
+ : DCCP_RESET_CODE_OPTION_ERROR;
+}
+
+/**
* dccp_feat_parse_options - Process Feature-Negotiation Options
* @sk: for general use and used by the client during connection setup
* @dreq: used by the server during connection setup
@@ -1221,6 +1405,14 @@ int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
return dccp_feat_confirm_recv(fn, mandatory, opt, feat,
val, len, server);
}
+ break;
+ /*
+ * Support for exchanging NN options on an established connection.
+ */
+ case DCCP_OPEN:
+ case DCCP_PARTOPEN:
+ return dccp_feat_handle_nn_established(sk, mandatory, opt, feat,
+ val, len);
}
return 0; /* ignore FN options in all other states */
}
diff --git a/net/dccp/feat.h b/net/dccp/feat.h
index e56a4e5e634e..90b957d34d26 100644
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -129,6 +129,7 @@ extern int dccp_feat_clone_list(struct list_head const *, struct list_head *);
extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len);
extern u64 dccp_decode_value_var(const u8 *bf, const u8 len);
+extern u64 dccp_feat_nn_get(struct sock *sk, u8 feat);
extern int dccp_insert_option_mandatory(struct sk_buff *skb);
extern int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 152975d942d9..e742f90a6858 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -184,7 +184,6 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
dp->dccps_rate_last = jiffies;
dp->dccps_role = DCCP_ROLE_UNDEFINED;
dp->dccps_service = DCCP_SERVICE_CODE_IS_ABSENT;
- dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1;
dp->dccps_tx_qlen = sysctl_dccp_tx_qlen;
dccp_init_xmit_timers(sk);
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
index ba4faceec405..2ab16e12520c 100644
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -388,7 +388,7 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa)
}
ifa->ifa_next = dn_db->ifa_list;
- rcu_assign_pointer(dn_db->ifa_list, ifa);
+ RCU_INIT_POINTER(dn_db->ifa_list, ifa);
dn_ifaddr_notify(RTM_NEWADDR, ifa);
blocking_notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa);
@@ -1093,7 +1093,7 @@ static struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
memcpy(&dn_db->parms, p, sizeof(struct dn_dev_parms));
- rcu_assign_pointer(dev->dn_ptr, dn_db);
+ RCU_INIT_POINTER(dev->dn_ptr, dn_db);
dn_db->dev = dev;
init_timer(&dn_db->timer);
@@ -1101,7 +1101,7 @@ static struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
dn_db->neigh_parms = neigh_parms_alloc(dev, &dn_neigh_table);
if (!dn_db->neigh_parms) {
- rcu_assign_pointer(dev->dn_ptr, NULL);
+ RCU_INIT_POINTER(dev->dn_ptr, NULL);
kfree(dn_db);
return NULL;
}
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 0a47b6c37038..56cf9b8e1c7c 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -301,7 +301,6 @@ static const struct net_device_ops dsa_netdev_ops = {
.ndo_start_xmit = dsa_xmit,
.ndo_change_rx_flags = dsa_slave_change_rx_flags,
.ndo_set_rx_mode = dsa_slave_set_rx_mode,
- .ndo_set_multicast_list = dsa_slave_set_rx_mode,
.ndo_set_mac_address = dsa_slave_set_mac_address,
.ndo_do_ioctl = dsa_slave_ioctl,
};
@@ -314,7 +313,6 @@ static const struct net_device_ops edsa_netdev_ops = {
.ndo_start_xmit = edsa_xmit,
.ndo_change_rx_flags = dsa_slave_change_rx_flags,
.ndo_set_rx_mode = dsa_slave_set_rx_mode,
- .ndo_set_multicast_list = dsa_slave_set_rx_mode,
.ndo_set_mac_address = dsa_slave_set_mac_address,
.ndo_do_ioctl = dsa_slave_ioctl,
};
@@ -327,7 +325,6 @@ static const struct net_device_ops trailer_netdev_ops = {
.ndo_start_xmit = trailer_xmit,
.ndo_change_rx_flags = dsa_slave_change_rx_flags,
.ndo_set_rx_mode = dsa_slave_set_rx_mode,
- .ndo_set_multicast_list = dsa_slave_set_rx_mode,
.ndo_set_mac_address = dsa_slave_set_mac_address,
.ndo_do_ioctl = dsa_slave_ioctl,
};
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index 27997d35ebd3..a2468363978e 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -340,7 +340,7 @@ void ether_setup(struct net_device *dev)
dev->addr_len = ETH_ALEN;
dev->tx_queue_len = 1000; /* Ethernet wants good queues */
dev->flags = IFF_BROADCAST|IFF_MULTICAST;
- dev->priv_flags = IFF_TX_SKB_SHARING;
+ dev->priv_flags |= IFF_TX_SKB_SHARING;
memset(dev->broadcast, 0xFF, ETH_ALEN);
diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c
new file mode 100644
index 000000000000..19d6aefe97d4
--- /dev/null
+++ b/net/ieee802154/6lowpan.c
@@ -0,0 +1,891 @@
+/*
+ * Copyright 2011, Siemens AG
+ * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
+ */
+
+/*
+ * Based on patches from Jon Smirl <jonsmirl@gmail.com>
+ * Copyright (c) 2011 Jon Smirl <jonsmirl@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* Jon's code is based on 6lowpan implementation for Contiki which is:
+ * Copyright (c) 2008, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define DEBUG
+
+#include <linux/bitops.h>
+#include <linux/if_arp.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <net/af_ieee802154.h>
+#include <net/ieee802154.h>
+#include <net/ieee802154_netdev.h>
+#include <net/ipv6.h>
+
+#include "6lowpan.h"
+
+/* TTL uncompression values */
+static const u8 lowpan_ttl_values[] = {0, 1, 64, 255};
+
+static LIST_HEAD(lowpan_devices);
+
+/*
+ * Uncompression of linklocal:
+ * 0 -> 16 bytes from packet
+ * 1 -> 2 bytes from prefix - bunch of zeroes and 8 from packet
+ * 2 -> 2 bytes from prefix - zeroes + 2 from packet
+ * 3 -> 2 bytes from prefix - infer 8 bytes from lladdr
+ *
+ * NOTE: => the uncompress function does change 0xf to 0x10
+ * NOTE: 0x00 => no-autoconfig => unspecified
+ */
+static const u8 lowpan_unc_llconf[] = {0x0f, 0x28, 0x22, 0x20};
+
+/*
+ * Uncompression of ctx-based:
+ * 0 -> 0 bits from packet [unspecified / reserved]
+ * 1 -> 8 bytes from prefix - bunch of zeroes and 8 from packet
+ * 2 -> 8 bytes from prefix - zeroes + 2 from packet
+ * 3 -> 8 bytes from prefix - infer 8 bytes from lladdr
+ */
+static const u8 lowpan_unc_ctxconf[] = {0x00, 0x88, 0x82, 0x80};
+
+/*
+ * Uncompression of ctx-base
+ * 0 -> 0 bits from packet
+ * 1 -> 2 bytes from prefix - bunch of zeroes 5 from packet
+ * 2 -> 2 bytes from prefix - zeroes + 3 from packet
+ * 3 -> 2 bytes from prefix - infer 1 bytes from lladdr
+ */
+static const u8 lowpan_unc_mxconf[] = {0x0f, 0x25, 0x23, 0x21};
+
+/* Link local prefix */
+static const u8 lowpan_llprefix[] = {0xfe, 0x80};
+
+/* private device info */
+struct lowpan_dev_info {
+ struct net_device *real_dev; /* real WPAN device ptr */
+ struct mutex dev_list_mtx; /* mutex for list ops */
+};
+
+struct lowpan_dev_record {
+ struct net_device *ldev;
+ struct list_head list;
+};
+
+static inline struct
+lowpan_dev_info *lowpan_dev_info(const struct net_device *dev)
+{
+ return netdev_priv(dev);
+}
+
+static inline void lowpan_address_flip(u8 *src, u8 *dest)
+{
+ int i;
+ for (i = 0; i < IEEE802154_ADDR_LEN; i++)
+ (dest)[IEEE802154_ADDR_LEN - i - 1] = (src)[i];
+}
+
+/* list of all 6lowpan devices, uses for package delivering */
+/* print data in line */
+static inline void lowpan_raw_dump_inline(const char *caller, char *msg,
+ unsigned char *buf, int len)
+{
+#ifdef DEBUG
+ if (msg)
+ pr_debug("(%s) %s: ", caller, msg);
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE,
+ 16, 1, buf, len, false);
+#endif /* DEBUG */
+}
+
+/*
+ * print data in a table format:
+ *
+ * addr: xx xx xx xx xx xx
+ * addr: xx xx xx xx xx xx
+ * ...
+ */
+static inline void lowpan_raw_dump_table(const char *caller, char *msg,
+ unsigned char *buf, int len)
+{
+#ifdef DEBUG
+ if (msg)
+ pr_debug("(%s) %s:\n", caller, msg);
+ print_hex_dump(KERN_DEBUG, "\t", DUMP_PREFIX_OFFSET,
+ 16, 1, buf, len, false);
+#endif /* DEBUG */
+}
+
+static u8
+lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, const struct in6_addr *ipaddr,
+ const unsigned char *lladdr)
+{
+ u8 val = 0;
+
+ if (is_addr_mac_addr_based(ipaddr, lladdr))
+ val = 3; /* 0-bits */
+ else if (lowpan_is_iid_16_bit_compressable(ipaddr)) {
+ /* compress IID to 16 bits xxxx::XXXX */
+ memcpy(*hc06_ptr, &ipaddr->s6_addr16[7], 2);
+ *hc06_ptr += 2;
+ val = 2; /* 16-bits */
+ } else {
+ /* do not compress IID => xxxx::IID */
+ memcpy(*hc06_ptr, &ipaddr->s6_addr16[4], 8);
+ *hc06_ptr += 8;
+ val = 1; /* 64-bits */
+ }
+
+ return rol8(val, shift);
+}
+
+static void
+lowpan_uip_ds6_set_addr_iid(struct in6_addr *ipaddr, unsigned char *lladdr)
+{
+ memcpy(&ipaddr->s6_addr[8], lladdr, IEEE802154_ALEN);
+ /* second bit-flip (Universe/Local) is done according RFC2464 */
+ ipaddr->s6_addr[8] ^= 0x02;
+}
+
+/*
+ * Uncompress addresses based on a prefix and a postfix with zeroes in
+ * between. If the postfix is zero in length it will use the link address
+ * to configure the IP address (autoconf style).
+ * pref_post_count takes a byte where the first nibble specify prefix count
+ * and the second postfix count (NOTE: 15/0xf => 16 bytes copy).
+ */
+static int
+lowpan_uncompress_addr(struct sk_buff *skb, struct in6_addr *ipaddr,
+ u8 const *prefix, u8 pref_post_count, unsigned char *lladdr)
+{
+ u8 prefcount = pref_post_count >> 4;
+ u8 postcount = pref_post_count & 0x0f;
+
+ /* full nibble 15 => 16 */
+ prefcount = (prefcount == 15 ? 16 : prefcount);
+ postcount = (postcount == 15 ? 16 : postcount);
+
+ if (lladdr)
+ lowpan_raw_dump_inline(__func__, "linklocal address",
+ lladdr, IEEE802154_ALEN);
+ if (prefcount > 0)
+ memcpy(ipaddr, prefix, prefcount);
+
+ if (prefcount + postcount < 16)
+ memset(&ipaddr->s6_addr[prefcount], 0,
+ 16 - (prefcount + postcount));
+
+ if (postcount > 0) {
+ memcpy(&ipaddr->s6_addr[16 - postcount], skb->data, postcount);
+ skb_pull(skb, postcount);
+ } else if (prefcount > 0) {
+ if (lladdr == NULL)
+ return -EINVAL;
+
+ /* no IID based configuration if no prefix and no data */
+ lowpan_uip_ds6_set_addr_iid(ipaddr, lladdr);
+ }
+
+ pr_debug("(%s): uncompressing %d + %d => ", __func__, prefcount,
+ postcount);
+ lowpan_raw_dump_inline(NULL, NULL, ipaddr->s6_addr, 16);
+
+ return 0;
+}
+
+static u8 lowpan_fetch_skb_u8(struct sk_buff *skb)
+{
+ u8 ret;
+
+ ret = skb->data[0];
+ skb_pull(skb, 1);
+
+ return ret;
+}
+
+static int lowpan_header_create(struct sk_buff *skb,
+ struct net_device *dev,
+ unsigned short type, const void *_daddr,
+ const void *_saddr, unsigned len)
+{
+ u8 tmp, iphc0, iphc1, *hc06_ptr;
+ struct ipv6hdr *hdr;
+ const u8 *saddr = _saddr;
+ const u8 *daddr = _daddr;
+ u8 *head;
+ struct ieee802154_addr sa, da;
+
+ if (type != ETH_P_IPV6)
+ return 0;
+ /* TODO:
+ * if this package isn't ipv6 one, where should it be routed?
+ */
+ head = kzalloc(100, GFP_KERNEL);
+ if (head == NULL)
+ return -ENOMEM;
+
+ hdr = ipv6_hdr(skb);
+ hc06_ptr = head + 2;
+
+ pr_debug("(%s): IPv6 header dump:\n\tversion = %d\n\tlength = %d\n"
+ "\tnexthdr = 0x%02x\n\thop_lim = %d\n", __func__,
+ hdr->version, ntohs(hdr->payload_len), hdr->nexthdr,
+ hdr->hop_limit);
+
+ lowpan_raw_dump_table(__func__, "raw skb network header dump",
+ skb_network_header(skb), sizeof(struct ipv6hdr));
+
+ if (!saddr)
+ saddr = dev->dev_addr;
+
+ lowpan_raw_dump_inline(__func__, "saddr", (unsigned char *)saddr, 8);
+
+ /*
+ * As we copy some bit-length fields, in the IPHC encoding bytes,
+ * we sometimes use |=
+ * If the field is 0, and the current bit value in memory is 1,
+ * this does not work. We therefore reset the IPHC encoding here
+ */
+ iphc0 = LOWPAN_DISPATCH_IPHC;
+ iphc1 = 0;
+
+ /* TODO: context lookup */
+
+ lowpan_raw_dump_inline(__func__, "daddr", (unsigned char *)daddr, 8);
+
+ /*
+ * Traffic class, flow label
+ * If flow label is 0, compress it. If traffic class is 0, compress it
+ * We have to process both in the same time as the offset of traffic
+ * class depends on the presence of version and flow label
+ */
+
+ /* hc06 format of TC is ECN | DSCP , original one is DSCP | ECN */
+ tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4);
+ tmp = ((tmp & 0x03) << 6) | (tmp >> 2);
+
+ if (((hdr->flow_lbl[0] & 0x0F) == 0) &&
+ (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) {
+ /* flow label can be compressed */
+ iphc0 |= LOWPAN_IPHC_FL_C;
+ if ((hdr->priority == 0) &&
+ ((hdr->flow_lbl[0] & 0xF0) == 0)) {
+ /* compress (elide) all */
+ iphc0 |= LOWPAN_IPHC_TC_C;
+ } else {
+ /* compress only the flow label */
+ *hc06_ptr = tmp;
+ hc06_ptr += 1;
+ }
+ } else {
+ /* Flow label cannot be compressed */
+ if ((hdr->priority == 0) &&
+ ((hdr->flow_lbl[0] & 0xF0) == 0)) {
+ /* compress only traffic class */
+ iphc0 |= LOWPAN_IPHC_TC_C;
+ *hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F);
+ memcpy(hc06_ptr + 1, &hdr->flow_lbl[1], 2);
+ hc06_ptr += 3;
+ } else {
+ /* compress nothing */
+ memcpy(hc06_ptr, &hdr, 4);
+ /* replace the top byte with new ECN | DSCP format */
+ *hc06_ptr = tmp;
+ hc06_ptr += 4;
+ }
+ }
+
+ /* NOTE: payload length is always compressed */
+
+ /* Next Header is compress if UDP */
+ if (hdr->nexthdr == UIP_PROTO_UDP)
+ iphc0 |= LOWPAN_IPHC_NH_C;
+
+/* TODO: next header compression */
+
+ if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
+ *hc06_ptr = hdr->nexthdr;
+ hc06_ptr += 1;
+ }
+
+ /*
+ * Hop limit
+ * if 1: compress, encoding is 01
+ * if 64: compress, encoding is 10
+ * if 255: compress, encoding is 11
+ * else do not compress
+ */
+ switch (hdr->hop_limit) {
+ case 1:
+ iphc0 |= LOWPAN_IPHC_TTL_1;
+ break;
+ case 64:
+ iphc0 |= LOWPAN_IPHC_TTL_64;
+ break;
+ case 255:
+ iphc0 |= LOWPAN_IPHC_TTL_255;
+ break;
+ default:
+ *hc06_ptr = hdr->hop_limit;
+ break;
+ }
+
+ /* source address compression */
+ if (is_addr_unspecified(&hdr->saddr)) {
+ pr_debug("(%s): source address is unspecified, setting SAC\n",
+ __func__);
+ iphc1 |= LOWPAN_IPHC_SAC;
+ /* TODO: context lookup */
+ } else if (is_addr_link_local(&hdr->saddr)) {
+ pr_debug("(%s): source address is link-local\n", __func__);
+ iphc1 |= lowpan_compress_addr_64(&hc06_ptr,
+ LOWPAN_IPHC_SAM_BIT, &hdr->saddr, saddr);
+ } else {
+ pr_debug("(%s): send the full source address\n", __func__);
+ memcpy(hc06_ptr, &hdr->saddr.s6_addr16[0], 16);
+ hc06_ptr += 16;
+ }
+
+ /* destination address compression */
+ if (is_addr_mcast(&hdr->daddr)) {
+ pr_debug("(%s): destination address is multicast", __func__);
+ iphc1 |= LOWPAN_IPHC_M;
+ if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) {
+ pr_debug("compressed to 1 octet\n");
+ iphc1 |= LOWPAN_IPHC_DAM_11;
+ /* use last byte */
+ *hc06_ptr = hdr->daddr.s6_addr[15];
+ hc06_ptr += 1;
+ } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) {
+ pr_debug("compressed to 4 octets\n");
+ iphc1 |= LOWPAN_IPHC_DAM_10;
+ /* second byte + the last three */
+ *hc06_ptr = hdr->daddr.s6_addr[1];
+ memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[13], 3);
+ hc06_ptr += 4;
+ } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) {
+ pr_debug("compressed to 6 octets\n");
+ iphc1 |= LOWPAN_IPHC_DAM_01;
+ /* second byte + the last five */
+ *hc06_ptr = hdr->daddr.s6_addr[1];
+ memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[11], 5);
+ hc06_ptr += 6;
+ } else {
+ pr_debug("using full address\n");
+ iphc1 |= LOWPAN_IPHC_DAM_00;
+ memcpy(hc06_ptr, &hdr->daddr.s6_addr[0], 16);
+ hc06_ptr += 16;
+ }
+ } else {
+ pr_debug("(%s): destination address is unicast: ", __func__);
+ /* TODO: context lookup */
+ if (is_addr_link_local(&hdr->daddr)) {
+ pr_debug("destination address is link-local\n");
+ iphc1 |= lowpan_compress_addr_64(&hc06_ptr,
+ LOWPAN_IPHC_DAM_BIT, &hdr->daddr, daddr);
+ } else {
+ pr_debug("using full address\n");
+ memcpy(hc06_ptr, &hdr->daddr.s6_addr16[0], 16);
+ hc06_ptr += 16;
+ }
+ }
+
+ /* TODO: UDP header compression */
+ /* TODO: Next Header compression */
+
+ head[0] = iphc0;
+ head[1] = iphc1;
+
+ skb_pull(skb, sizeof(struct ipv6hdr));
+ memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head);
+
+ kfree(head);
+
+ lowpan_raw_dump_table(__func__, "raw skb data dump", skb->data,
+ skb->len);
+
+ /*
+ * NOTE1: I'm still unsure about the fact that compression and WPAN
+ * header are created here and not later in the xmit. So wait for
+ * an opinion of net maintainers.
+ */
+ /*
+ * NOTE2: to be absolutely correct, we must derive PANid information
+ * from MAC subif of the 'dev' and 'real_dev' network devices, but
+ * this isn't implemented in mainline yet, so currently we assign 0xff
+ */
+ {
+ /* prepare wpan address data */
+ sa.addr_type = IEEE802154_ADDR_LONG;
+ sa.pan_id = 0xff;
+
+ da.addr_type = IEEE802154_ADDR_LONG;
+ da.pan_id = 0xff;
+
+ memcpy(&(da.hwaddr), daddr, 8);
+ memcpy(&(sa.hwaddr), saddr, 8);
+
+ mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA;
+ return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev,
+ type, (void *)&da, (void *)&sa, skb->len);
+ }
+}
+
+static int lowpan_skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr)
+{
+ struct sk_buff *new;
+ struct lowpan_dev_record *entry;
+ int stat = NET_RX_SUCCESS;
+
+ new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb),
+ GFP_ATOMIC);
+ kfree_skb(skb);
+
+ if (!new)
+ return -ENOMEM;
+
+ skb_push(new, sizeof(struct ipv6hdr));
+ skb_reset_network_header(new);
+ skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr));
+
+ new->protocol = htons(ETH_P_IPV6);
+ new->pkt_type = PACKET_HOST;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(entry, &lowpan_devices, list)
+ if (lowpan_dev_info(entry->ldev)->real_dev == new->dev) {
+ skb = skb_copy(new, GFP_ATOMIC);
+ if (!skb) {
+ stat = -ENOMEM;
+ break;
+ }
+
+ skb->dev = entry->ldev;
+ stat = netif_rx(skb);
+ }
+ rcu_read_unlock();
+
+ kfree_skb(new);
+
+ return stat;
+}
+
+static int
+lowpan_process_data(struct sk_buff *skb)
+{
+ struct ipv6hdr hdr;
+ u8 tmp, iphc0, iphc1, num_context = 0;
+ u8 *_saddr, *_daddr;
+ int err;
+
+ lowpan_raw_dump_table(__func__, "raw skb data dump", skb->data,
+ skb->len);
+ /* at least two bytes will be used for the encoding */
+ if (skb->len < 2)
+ goto drop;
+ iphc0 = lowpan_fetch_skb_u8(skb);
+ iphc1 = lowpan_fetch_skb_u8(skb);
+
+ _saddr = mac_cb(skb)->sa.hwaddr;
+ _daddr = mac_cb(skb)->da.hwaddr;
+
+ pr_debug("(%s): iphc0 = %02x, iphc1 = %02x\n", __func__, iphc0, iphc1);
+
+ /* another if the CID flag is set */
+ if (iphc1 & LOWPAN_IPHC_CID) {
+ pr_debug("(%s): CID flag is set, increase header with one\n",
+ __func__);
+ if (!skb->len)
+ goto drop;
+ num_context = lowpan_fetch_skb_u8(skb);
+ }
+
+ hdr.version = 6;
+
+ /* Traffic Class and Flow Label */
+ switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) {
+ /*
+ * Traffic Class and FLow Label carried in-line
+ * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes)
+ */
+ case 0: /* 00b */
+ if (!skb->len)
+ goto drop;
+ tmp = lowpan_fetch_skb_u8(skb);
+ memcpy(&hdr.flow_lbl, &skb->data[0], 3);
+ skb_pull(skb, 3);
+ hdr.priority = ((tmp >> 2) & 0x0f);
+ hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) |
+ (hdr.flow_lbl[0] & 0x0f);
+ break;
+ /*
+ * Traffic class carried in-line
+ * ECN + DSCP (1 byte), Flow Label is elided
+ */
+ case 1: /* 10b */
+ if (!skb->len)
+ goto drop;
+ tmp = lowpan_fetch_skb_u8(skb);
+ hdr.priority = ((tmp >> 2) & 0x0f);
+ hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30);
+ hdr.flow_lbl[1] = 0;
+ hdr.flow_lbl[2] = 0;
+ break;
+ /*
+ * Flow Label carried in-line
+ * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided
+ */
+ case 2: /* 01b */
+ if (!skb->len)
+ goto drop;
+ tmp = lowpan_fetch_skb_u8(skb);
+ hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30);
+ memcpy(&hdr.flow_lbl[1], &skb->data[0], 2);
+ skb_pull(skb, 2);
+ break;
+ /* Traffic Class and Flow Label are elided */
+ case 3: /* 11b */
+ hdr.priority = 0;
+ hdr.flow_lbl[0] = 0;
+ hdr.flow_lbl[1] = 0;
+ hdr.flow_lbl[2] = 0;
+ break;
+ default:
+ break;
+ }
+
+ /* Next Header */
+ if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
+ /* Next header is carried inline */
+ if (!skb->len)
+ goto drop;
+ hdr.nexthdr = lowpan_fetch_skb_u8(skb);
+ pr_debug("(%s): NH flag is set, next header is carried "
+ "inline: %02x\n", __func__, hdr.nexthdr);
+ }
+
+ /* Hop Limit */
+ if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I)
+ hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03];
+ else {
+ if (!skb->len)
+ goto drop;
+ hdr.hop_limit = lowpan_fetch_skb_u8(skb);
+ }
+
+ /* Extract SAM to the tmp variable */
+ tmp = ((iphc1 & LOWPAN_IPHC_SAM) >> LOWPAN_IPHC_SAM_BIT) & 0x03;
+
+ /* Source address uncompression */
+ pr_debug("(%s): source address stateless compression\n", __func__);
+ err = lowpan_uncompress_addr(skb, &hdr.saddr, lowpan_llprefix,
+ lowpan_unc_llconf[tmp], skb->data);
+ if (err)
+ goto drop;
+
+ /* Extract DAM to the tmp variable */
+ tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03;
+
+ /* check for Multicast Compression */
+ if (iphc1 & LOWPAN_IPHC_M) {
+ if (iphc1 & LOWPAN_IPHC_DAC) {
+ pr_debug("(%s): destination address context-based "
+ "multicast compression\n", __func__);
+ /* TODO: implement this */
+ } else {
+ u8 prefix[] = {0xff, 0x02};
+
+ pr_debug("(%s): destination address non-context-based"
+ " multicast compression\n", __func__);
+ if (0 < tmp && tmp < 3) {
+ if (!skb->len)
+ goto drop;
+ else
+ prefix[1] = lowpan_fetch_skb_u8(skb);
+ }
+
+ err = lowpan_uncompress_addr(skb, &hdr.daddr, prefix,
+ lowpan_unc_mxconf[tmp], NULL);
+ if (err)
+ goto drop;
+ }
+ } else {
+ pr_debug("(%s): destination address stateless compression\n",
+ __func__);
+ err = lowpan_uncompress_addr(skb, &hdr.daddr, lowpan_llprefix,
+ lowpan_unc_llconf[tmp], skb->data);
+ if (err)
+ goto drop;
+ }
+
+ /* TODO: UDP header parse */
+
+ /* Not fragmented package */
+ hdr.payload_len = htons(skb->len);
+
+ pr_debug("(%s): skb headroom size = %d, data length = %d\n", __func__,
+ skb_headroom(skb), skb->len);
+
+ pr_debug("(%s): IPv6 header dump:\n\tversion = %d\n\tlength = %d\n\t"
+ "nexthdr = 0x%02x\n\thop_lim = %d\n", __func__, hdr.version,
+ ntohs(hdr.payload_len), hdr.nexthdr, hdr.hop_limit);
+
+ lowpan_raw_dump_table(__func__, "raw header dump", (u8 *)&hdr,
+ sizeof(hdr));
+ return lowpan_skb_deliver(skb, &hdr);
+drop:
+ kfree_skb(skb);
+ return -EINVAL;
+}
+
+static int lowpan_set_address(struct net_device *dev, void *p)
+{
+ struct sockaddr *sa = p;
+
+ if (netif_running(dev))
+ return -EBUSY;
+
+ /* TODO: validate addr */
+ memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
+
+ return 0;
+}
+
+static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ int err = 0;
+
+ pr_debug("(%s): package xmit\n", __func__);
+
+ skb->dev = lowpan_dev_info(dev)->real_dev;
+ if (skb->dev == NULL) {
+ pr_debug("(%s) ERROR: no real wpan device found\n", __func__);
+ dev_kfree_skb(skb);
+ } else
+ err = dev_queue_xmit(skb);
+
+ return (err < 0 ? NETDEV_TX_BUSY : NETDEV_TX_OK);
+}
+
+static void lowpan_dev_free(struct net_device *dev)
+{
+ dev_put(lowpan_dev_info(dev)->real_dev);
+ free_netdev(dev);
+}
+
+static struct header_ops lowpan_header_ops = {
+ .create = lowpan_header_create,
+};
+
+static const struct net_device_ops lowpan_netdev_ops = {
+ .ndo_start_xmit = lowpan_xmit,
+ .ndo_set_mac_address = lowpan_set_address,
+};
+
+static void lowpan_setup(struct net_device *dev)
+{
+ pr_debug("(%s)\n", __func__);
+
+ dev->addr_len = IEEE802154_ADDR_LEN;
+ memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
+ dev->type = ARPHRD_IEEE802154;
+ dev->features = NETIF_F_NO_CSUM;
+ /* Frame Control + Sequence Number + Address fields + Security Header */
+ dev->hard_header_len = 2 + 1 + 20 + 14;
+ dev->needed_tailroom = 2; /* FCS */
+ dev->mtu = 1281;
+ dev->tx_queue_len = 0;
+ dev->flags = IFF_NOARP | IFF_BROADCAST;
+ dev->watchdog_timeo = 0;
+
+ dev->netdev_ops = &lowpan_netdev_ops;
+ dev->header_ops = &lowpan_header_ops;
+ dev->destructor = lowpan_dev_free;
+}
+
+static int lowpan_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+ pr_debug("(%s)\n", __func__);
+
+ if (tb[IFLA_ADDRESS]) {
+ if (nla_len(tb[IFLA_ADDRESS]) != IEEE802154_ADDR_LEN)
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *pt, struct net_device *orig_dev)
+{
+ if (!netif_running(dev))
+ goto drop;
+
+ if (dev->type != ARPHRD_IEEE802154)
+ goto drop;
+
+ /* check that it's our buffer */
+ if ((skb->data[0] & 0xe0) == 0x60)
+ lowpan_process_data(skb);
+
+ return NET_RX_SUCCESS;
+
+drop:
+ kfree_skb(skb);
+ return NET_RX_DROP;
+}
+
+static int lowpan_newlink(struct net *src_net, struct net_device *dev,
+ struct nlattr *tb[], struct nlattr *data[])
+{
+ struct net_device *real_dev;
+ struct lowpan_dev_record *entry;
+
+ pr_debug("(%s)\n", __func__);
+
+ if (!tb[IFLA_LINK])
+ return -EINVAL;
+ /* find and hold real wpan device */
+ real_dev = dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
+ if (!real_dev)
+ return -ENODEV;
+
+ lowpan_dev_info(dev)->real_dev = real_dev;
+ mutex_init(&lowpan_dev_info(dev)->dev_list_mtx);
+
+ entry = kzalloc(sizeof(struct lowpan_dev_record), GFP_KERNEL);
+ if (!entry) {
+ dev_put(real_dev);
+ lowpan_dev_info(dev)->real_dev = NULL;
+ return -ENOMEM;
+ }
+
+ entry->ldev = dev;
+
+ mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx);
+ INIT_LIST_HEAD(&entry->list);
+ list_add_tail(&entry->list, &lowpan_devices);
+ mutex_unlock(&lowpan_dev_info(dev)->dev_list_mtx);
+
+ register_netdevice(dev);
+
+ return 0;
+}
+
+static void lowpan_dellink(struct net_device *dev, struct list_head *head)
+{
+ struct lowpan_dev_info *lowpan_dev = lowpan_dev_info(dev);
+ struct net_device *real_dev = lowpan_dev->real_dev;
+ struct lowpan_dev_record *entry;
+ struct lowpan_dev_record *tmp;
+
+ ASSERT_RTNL();
+
+ mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx);
+ list_for_each_entry_safe(entry, tmp, &lowpan_devices, list) {
+ if (entry->ldev == dev) {
+ list_del(&entry->list);
+ kfree(entry);
+ }
+ }
+ mutex_unlock(&lowpan_dev_info(dev)->dev_list_mtx);
+
+ mutex_destroy(&lowpan_dev_info(dev)->dev_list_mtx);
+
+ unregister_netdevice_queue(dev, head);
+
+ dev_put(real_dev);
+}
+
+static struct rtnl_link_ops lowpan_link_ops __read_mostly = {
+ .kind = "lowpan",
+ .priv_size = sizeof(struct lowpan_dev_info),
+ .setup = lowpan_setup,
+ .newlink = lowpan_newlink,
+ .dellink = lowpan_dellink,
+ .validate = lowpan_validate,
+};
+
+static inline int __init lowpan_netlink_init(void)
+{
+ return rtnl_link_register(&lowpan_link_ops);
+}
+
+static inline void __init lowpan_netlink_fini(void)
+{
+ rtnl_link_unregister(&lowpan_link_ops);
+}
+
+static struct packet_type lowpan_packet_type = {
+ .type = __constant_htons(ETH_P_IEEE802154),
+ .func = lowpan_rcv,
+};
+
+static int __init lowpan_init_module(void)
+{
+ int err = 0;
+
+ pr_debug("(%s)\n", __func__);
+
+ err = lowpan_netlink_init();
+ if (err < 0)
+ goto out;
+
+ dev_add_pack(&lowpan_packet_type);
+out:
+ return err;
+}
+
+static void __exit lowpan_cleanup_module(void)
+{
+ pr_debug("(%s)\n", __func__);
+
+ lowpan_netlink_fini();
+
+ dev_remove_pack(&lowpan_packet_type);
+}
+
+module_init(lowpan_init_module);
+module_exit(lowpan_cleanup_module);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_RTNL_LINK("lowpan");
diff --git a/net/ieee802154/6lowpan.h b/net/ieee802154/6lowpan.h
new file mode 100644
index 000000000000..5d8cf80b930d
--- /dev/null
+++ b/net/ieee802154/6lowpan.h
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2011, Siemens AG
+ * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
+ */
+
+/*
+ * Based on patches from Jon Smirl <jonsmirl@gmail.com>
+ * Copyright (c) 2011 Jon Smirl <jonsmirl@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* Jon's code is based on 6lowpan implementation for Contiki which is:
+ * Copyright (c) 2008, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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 __6LOWPAN_H__
+#define __6LOWPAN_H__
+
+/* need to know address length to manipulate with it */
+#define IEEE802154_ALEN 8
+
+#define UIP_802154_SHORTADDR_LEN 2 /* compressed ipv6 address length */
+#define UIP_IPH_LEN 40 /* ipv6 fixed header size */
+#define UIP_PROTO_UDP 17 /* ipv6 next header value for UDP */
+#define UIP_FRAGH_LEN 8 /* ipv6 fragment header size */
+
+/*
+ * ipv6 address based on mac
+ * second bit-flip (Universe/Local) is done according RFC2464
+ */
+#define is_addr_mac_addr_based(a, m) \
+ ((((a)->s6_addr[8]) == (((m)[0]) ^ 0x02)) && \
+ (((a)->s6_addr[9]) == (m)[1]) && \
+ (((a)->s6_addr[10]) == (m)[2]) && \
+ (((a)->s6_addr[11]) == (m)[3]) && \
+ (((a)->s6_addr[12]) == (m)[4]) && \
+ (((a)->s6_addr[13]) == (m)[5]) && \
+ (((a)->s6_addr[14]) == (m)[6]) && \
+ (((a)->s6_addr[15]) == (m)[7]))
+
+/* ipv6 address is unspecified */
+#define is_addr_unspecified(a) \
+ ((((a)->s6_addr32[0]) == 0) && \
+ (((a)->s6_addr32[1]) == 0) && \
+ (((a)->s6_addr32[2]) == 0) && \
+ (((a)->s6_addr32[3]) == 0))
+
+/* compare ipv6 addresses prefixes */
+#define ipaddr_prefixcmp(addr1, addr2, length) \
+ (memcmp(addr1, addr2, length >> 3) == 0)
+
+/* local link, i.e. FE80::/10 */
+#define is_addr_link_local(a) (((a)->s6_addr16[0]) == 0x80FE)
+
+/*
+ * check whether we can compress the IID to 16 bits,
+ * it's possible for unicast adresses with first 49 bits are zero only.
+ */
+#define lowpan_is_iid_16_bit_compressable(a) \
+ ((((a)->s6_addr16[4]) == 0) && \
+ (((a)->s6_addr16[5]) == 0) && \
+ (((a)->s6_addr16[6]) == 0) && \
+ ((((a)->s6_addr[14]) & 0x80) == 0))
+
+/* multicast address */
+#define is_addr_mcast(a) (((a)->s6_addr[0]) == 0xFF)
+
+/* check whether the 112-bit gid of the multicast address is mappable to: */
+
+/* 9 bits, for FF02::1 (all nodes) and FF02::2 (all routers) addresses only. */
+#define lowpan_is_mcast_addr_compressable(a) \
+ ((((a)->s6_addr16[1]) == 0) && \
+ (((a)->s6_addr16[2]) == 0) && \
+ (((a)->s6_addr16[3]) == 0) && \
+ (((a)->s6_addr16[4]) == 0) && \
+ (((a)->s6_addr16[5]) == 0) && \
+ (((a)->s6_addr16[6]) == 0) && \
+ (((a)->s6_addr[14]) == 0) && \
+ ((((a)->s6_addr[15]) == 1) || (((a)->s6_addr[15]) == 2)))
+
+/* 48 bits, FFXX::00XX:XXXX:XXXX */
+#define lowpan_is_mcast_addr_compressable48(a) \
+ ((((a)->s6_addr16[1]) == 0) && \
+ (((a)->s6_addr16[2]) == 0) && \
+ (((a)->s6_addr16[3]) == 0) && \
+ (((a)->s6_addr16[4]) == 0) && \
+ (((a)->s6_addr[10]) == 0))
+
+/* 32 bits, FFXX::00XX:XXXX */
+#define lowpan_is_mcast_addr_compressable32(a) \
+ ((((a)->s6_addr16[1]) == 0) && \
+ (((a)->s6_addr16[2]) == 0) && \
+ (((a)->s6_addr16[3]) == 0) && \
+ (((a)->s6_addr16[4]) == 0) && \
+ (((a)->s6_addr16[5]) == 0) && \
+ (((a)->s6_addr[12]) == 0))
+
+/* 8 bits, FF02::00XX */
+#define lowpan_is_mcast_addr_compressable8(a) \
+ ((((a)->s6_addr[1]) == 2) && \
+ (((a)->s6_addr16[1]) == 0) && \
+ (((a)->s6_addr16[2]) == 0) && \
+ (((a)->s6_addr16[3]) == 0) && \
+ (((a)->s6_addr16[4]) == 0) && \
+ (((a)->s6_addr16[5]) == 0) && \
+ (((a)->s6_addr16[6]) == 0) && \
+ (((a)->s6_addr[14]) == 0))
+
+#define lowpan_is_addr_broadcast(a) \
+ ((((a)[0]) == 0xFF) && \
+ (((a)[1]) == 0xFF) && \
+ (((a)[2]) == 0xFF) && \
+ (((a)[3]) == 0xFF) && \
+ (((a)[4]) == 0xFF) && \
+ (((a)[5]) == 0xFF) && \
+ (((a)[6]) == 0xFF) && \
+ (((a)[7]) == 0xFF))
+
+#define LOWPAN_DISPATCH_IPV6 0x41 /* 01000001 = 65 */
+#define LOWPAN_DISPATCH_HC1 0x42 /* 01000010 = 66 */
+#define LOWPAN_DISPATCH_IPHC 0x60 /* 011xxxxx = ... */
+#define LOWPAN_DISPATCH_FRAG1 0xc0 /* 11000xxx */
+#define LOWPAN_DISPATCH_FRAGN 0xe0 /* 11100xxx */
+
+/*
+ * Values of fields within the IPHC encoding first byte
+ * (C stands for compressed and I for inline)
+ */
+#define LOWPAN_IPHC_TF 0x18
+
+#define LOWPAN_IPHC_FL_C 0x10
+#define LOWPAN_IPHC_TC_C 0x08
+#define LOWPAN_IPHC_NH_C 0x04
+#define LOWPAN_IPHC_TTL_1 0x01
+#define LOWPAN_IPHC_TTL_64 0x02
+#define LOWPAN_IPHC_TTL_255 0x03
+#define LOWPAN_IPHC_TTL_I 0x00
+
+
+/* Values of fields within the IPHC encoding second byte */
+#define LOWPAN_IPHC_CID 0x80
+
+#define LOWPAN_IPHC_SAC 0x40
+#define LOWPAN_IPHC_SAM_00 0x00
+#define LOWPAN_IPHC_SAM_01 0x10
+#define LOWPAN_IPHC_SAM_10 0x20
+#define LOWPAN_IPHC_SAM 0x30
+
+#define LOWPAN_IPHC_SAM_BIT 4
+
+#define LOWPAN_IPHC_M 0x08
+#define LOWPAN_IPHC_DAC 0x04
+#define LOWPAN_IPHC_DAM_00 0x00
+#define LOWPAN_IPHC_DAM_01 0x01
+#define LOWPAN_IPHC_DAM_10 0x02
+#define LOWPAN_IPHC_DAM_11 0x03
+
+#define LOWPAN_IPHC_DAM_BIT 0
+/*
+ * LOWPAN_UDP encoding (works together with IPHC)
+ */
+#define LOWPAN_NHC_UDP_MASK 0xF8
+#define LOWPAN_NHC_UDP_ID 0xF0
+#define LOWPAN_NHC_UDP_CHECKSUMC 0x04
+#define LOWPAN_NHC_UDP_CHECKSUMI 0x00
+
+/* values for port compression, _with checksum_ ie bit 5 set to 0 */
+#define LOWPAN_NHC_UDP_CS_P_00 0xF0 /* all inline */
+#define LOWPAN_NHC_UDP_CS_P_01 0xF1 /* source 16bit inline,
+ dest = 0xF0 + 8 bit inline */
+#define LOWPAN_NHC_UDP_CS_P_10 0xF2 /* source = 0xF0 + 8bit inline,
+ dest = 16 bit inline */
+#define LOWPAN_NHC_UDP_CS_P_11 0xF3 /* source & dest = 0xF0B + 4bit inline */
+
+#endif /* __6LOWPAN_H__ */
diff --git a/net/ieee802154/Kconfig b/net/ieee802154/Kconfig
index 1c1de97d264a..7dee65052925 100644
--- a/net/ieee802154/Kconfig
+++ b/net/ieee802154/Kconfig
@@ -10,3 +10,9 @@ config IEEE802154
Say Y here to compile LR-WPAN support into the kernel or say M to
compile it as modules.
+
+config IEEE802154_6LOWPAN
+ tristate "6lowpan support over IEEE 802.15.4"
+ depends on IEEE802154 && IPV6
+ ---help---
+ IPv6 compression over IEEE 802.15.4.
diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile
index 5761185f884e..d7716d64c6bb 100644
--- a/net/ieee802154/Makefile
+++ b/net/ieee802154/Makefile
@@ -1,3 +1,5 @@
-obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o
-ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o
-af_802154-y := af_ieee802154.o raw.o dgram.o
+obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o
+obj-$(CONFIG_IEEE802154_6LOWPAN) += 6lowpan.o
+
+ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o
+af_802154-y := af_ieee802154.o raw.o dgram.o
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 1b745d412cf6..1b5096a9875a 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -466,8 +466,13 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
goto out;
if (addr->sin_family != AF_INET) {
+ /* Compatibility games : accept AF_UNSPEC (mapped to AF_INET)
+ * only if s_addr is INADDR_ANY.
+ */
err = -EAFNOSUPPORT;
- goto out;
+ if (addr->sin_family != AF_UNSPEC ||
+ addr->sin_addr.s_addr != htonl(INADDR_ANY))
+ goto out;
}
chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr);
@@ -888,7 +893,7 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
EXPORT_SYMBOL(inet_ioctl);
#ifdef CONFIG_COMPAT
-int inet_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+static int inet_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct sock *sk = sock->sk;
int err = -ENOIOCTLCMD;
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index 2c2a98e402e7..86f3b885b4f3 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -476,7 +476,7 @@ int cipso_v4_doi_add(struct cipso_v4_doi *doi_def,
doi = doi_def->doi;
doi_type = doi_def->type;
- if (doi_def == NULL || doi_def->doi == CIPSO_V4_DOI_UNKNOWN)
+ if (doi_def->doi == CIPSO_V4_DOI_UNKNOWN)
goto doi_add_return;
for (iter = 0; iter < CIPSO_V4_TAG_MAXCNT; iter++) {
switch (doi_def->tags[iter]) {
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index bc19bd06dd00..c6b5092f29a1 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -258,7 +258,7 @@ static struct in_device *inetdev_init(struct net_device *dev)
ip_mc_up(in_dev);
/* we can receive as soon as ip_ptr is set -- do this last */
- rcu_assign_pointer(dev->ip_ptr, in_dev);
+ RCU_INIT_POINTER(dev->ip_ptr, in_dev);
out:
return in_dev;
out_kfree:
@@ -291,7 +291,7 @@ static void inetdev_destroy(struct in_device *in_dev)
inet_free_ifa(ifa);
}
- rcu_assign_pointer(dev->ip_ptr, NULL);
+ RCU_INIT_POINTER(dev->ip_ptr, NULL);
devinet_sysctl_unregister(in_dev);
neigh_parms_release(&arp_tbl, in_dev->arp_parms);
@@ -1175,7 +1175,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
switch (event) {
case NETDEV_REGISTER:
printk(KERN_DEBUG "inetdev_event: bug\n");
- rcu_assign_pointer(dev->ip_ptr, NULL);
+ RCU_INIT_POINTER(dev->ip_ptr, NULL);
break;
case NETDEV_UP:
if (!inetdev_valid_mtu(dev->mtu))
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 33e2c35b74b7..80106d89d548 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -142,6 +142,14 @@ const struct fib_prop fib_props[RTN_MAX + 1] = {
};
/* Release a nexthop info record */
+static void free_fib_info_rcu(struct rcu_head *head)
+{
+ struct fib_info *fi = container_of(head, struct fib_info, rcu);
+
+ if (fi->fib_metrics != (u32 *) dst_default_metrics)
+ kfree(fi->fib_metrics);
+ kfree(fi);
+}
void free_fib_info(struct fib_info *fi)
{
@@ -156,7 +164,7 @@ void free_fib_info(struct fib_info *fi)
} endfor_nexthops(fi);
fib_info_cnt--;
release_net(fi->fib_net);
- kfree_rcu(fi, rcu);
+ call_rcu(&fi->rcu, free_fib_info_rcu);
}
void fib_release_info(struct fib_info *fi)
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index de9e2978476f..89d6f71a6a99 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -204,7 +204,7 @@ static inline struct tnode *node_parent_rcu(const struct rt_trie_node *node)
return (struct tnode *)(parent & ~NODE_TYPE_MASK);
}
-/* Same as rcu_assign_pointer
+/* Same as RCU_INIT_POINTER
* but that macro() assumes that value is a pointer.
*/
static inline void node_set_parent(struct rt_trie_node *node, struct tnode *ptr)
@@ -528,7 +528,7 @@ static void tnode_put_child_reorg(struct tnode *tn, int i, struct rt_trie_node *
if (n)
node_set_parent(n, tn);
- rcu_assign_pointer(tn->child[i], n);
+ RCU_INIT_POINTER(tn->child[i], n);
}
#define MAX_WORK 10
@@ -1014,7 +1014,7 @@ static void trie_rebalance(struct trie *t, struct tnode *tn)
tp = node_parent((struct rt_trie_node *) tn);
if (!tp)
- rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
+ RCU_INIT_POINTER(t->trie, (struct rt_trie_node *)tn);
tnode_free_flush();
if (!tp)
@@ -1026,7 +1026,7 @@ static void trie_rebalance(struct trie *t, struct tnode *tn)
if (IS_TNODE(tn))
tn = (struct tnode *)resize(t, (struct tnode *)tn);
- rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
+ RCU_INIT_POINTER(t->trie, (struct rt_trie_node *)tn);
tnode_free_flush();
}
@@ -1163,7 +1163,7 @@ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen)
put_child(t, (struct tnode *)tp, cindex,
(struct rt_trie_node *)tn);
} else {
- rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
+ RCU_INIT_POINTER(t->trie, (struct rt_trie_node *)tn);
tp = tn;
}
}
@@ -1621,7 +1621,7 @@ static void trie_leaf_remove(struct trie *t, struct leaf *l)
put_child(t, (struct tnode *)tp, cindex, NULL);
trie_rebalance(t, tp);
} else
- rcu_assign_pointer(t->trie, NULL);
+ RCU_INIT_POINTER(t->trie, NULL);
free_leaf(l);
}
diff --git a/net/ipv4/gre.c b/net/ipv4/gre.c
index dbfc21de3479..8cb1ebb7cd74 100644
--- a/net/ipv4/gre.c
+++ b/net/ipv4/gre.c
@@ -34,7 +34,7 @@ int gre_add_protocol(const struct gre_protocol *proto, u8 version)
if (gre_proto[version])
goto err_out_unlock;
- rcu_assign_pointer(gre_proto[version], proto);
+ RCU_INIT_POINTER(gre_proto[version], proto);
spin_unlock(&gre_proto_lock);
return 0;
@@ -54,7 +54,7 @@ int gre_del_protocol(const struct gre_protocol *proto, u8 version)
if (rcu_dereference_protected(gre_proto[version],
lockdep_is_held(&gre_proto_lock)) != proto)
goto err_out_unlock;
- rcu_assign_pointer(gre_proto[version], NULL);
+ RCU_INIT_POINTER(gre_proto[version], NULL);
spin_unlock(&gre_proto_lock);
synchronize_rcu();
return 0;
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 23ef31baa1af..ab188ae12fd9 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -1152,10 +1152,9 @@ static int __net_init icmp_sk_init(struct net *net)
net->ipv4.icmp_sk[i] = sk;
/* Enough space for 2 64K ICMP packets, including
- * sk_buff struct overhead.
+ * sk_buff/skb_shared_info struct overhead.
*/
- sk->sk_sndbuf =
- (2 * ((64 * 1024) + sizeof(struct sk_buff)));
+ sk->sk_sndbuf = 2 * SKB_TRUESIZE(64 * 1024);
/*
* Speedup sock_wfree()
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 283c0a26e03f..c7472eff2d51 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -767,7 +767,7 @@ static int igmp_xmarksources(struct ip_mc_list *pmc, int nsrcs, __be32 *srcs)
break;
for (i=0; i<nsrcs; i++) {
/* skip inactive filters */
- if (pmc->sfcount[MCAST_INCLUDE] ||
+ if (psf->sf_count[MCAST_INCLUDE] ||
pmc->sfcount[MCAST_EXCLUDE] !=
psf->sf_count[MCAST_EXCLUDE])
continue;
@@ -1009,7 +1009,7 @@ static void ip_mc_filter_add(struct in_device *in_dev, __be32 addr)
/* Checking for IFF_MULTICAST here is WRONG-WRONG-WRONG.
We will get multicast token leakage, when IFF_MULTICAST
- is changed. This check should be done in dev->set_multicast_list
+ is changed. This check should be done in ndo_set_rx_mode
routine. Something sort of:
if (dev->mc_list && dev->flags&IFF_MULTICAST) { do it; }
--ANK
@@ -1242,7 +1242,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
im->next_rcu = in_dev->mc_list;
in_dev->mc_count++;
- rcu_assign_pointer(in_dev->mc_list, im);
+ RCU_INIT_POINTER(in_dev->mc_list, im);
#ifdef CONFIG_IP_MULTICAST
igmpv3_del_delrec(in_dev, im->multiaddr);
@@ -1813,7 +1813,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
iml->next_rcu = inet->mc_list;
iml->sflist = NULL;
iml->sfmode = MCAST_EXCLUDE;
- rcu_assign_pointer(inet->mc_list, iml);
+ RCU_INIT_POINTER(inet->mc_list, iml);
ip_mc_inc_group(in_dev, addr);
err = 0;
done:
@@ -1835,7 +1835,7 @@ static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml,
}
err = ip_mc_del_src(in_dev, &iml->multi.imr_multiaddr.s_addr,
iml->sfmode, psf->sl_count, psf->sl_addr, 0);
- rcu_assign_pointer(iml->sflist, NULL);
+ RCU_INIT_POINTER(iml->sflist, NULL);
/* decrease mem now to avoid the memleak warning */
atomic_sub(IP_SFLSIZE(psf->sl_max), &sk->sk_omem_alloc);
kfree_rcu(psf, rcu);
@@ -2000,7 +2000,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc);
kfree_rcu(psl, rcu);
}
- rcu_assign_pointer(pmc->sflist, newpsl);
+ RCU_INIT_POINTER(pmc->sflist, newpsl);
psl = newpsl;
}
rv = 1; /* > 0 for insert logic below if sl_count is 0 */
@@ -2103,7 +2103,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
} else
(void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode,
0, NULL, 0);
- rcu_assign_pointer(pmc->sflist, newpsl);
+ RCU_INIT_POINTER(pmc->sflist, newpsl);
pmc->sfmode = msf->imsf_fmode;
err = 0;
done:
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 389a2e6a17fd..f5e2bdaef949 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -108,6 +108,9 @@ static int inet_csk_diag_fill(struct sock *sk,
icsk->icsk_ca_ops->name);
}
+ if ((ext & (1 << (INET_DIAG_TOS - 1))) && (sk->sk_family != AF_INET6))
+ RTA_PUT_U8(skb, INET_DIAG_TOS, inet->tos);
+
r->idiag_family = sk->sk_family;
r->idiag_state = sk->sk_state;
r->idiag_timer = 0;
@@ -130,6 +133,8 @@ static int inet_csk_diag_fill(struct sock *sk,
&np->rcv_saddr);
ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst,
&np->daddr);
+ if (ext & (1 << (INET_DIAG_TOS - 1)))
+ RTA_PUT_U8(skb, INET_DIAG_TOS, np->tclass);
}
#endif
diff --git a/net/ipv4/inet_lro.c b/net/ipv4/inet_lro.c
index ef7ae6049a51..cc280a3f4f96 100644
--- a/net/ipv4/inet_lro.c
+++ b/net/ipv4/inet_lro.c
@@ -244,11 +244,11 @@ static void lro_add_frags(struct net_lro_desc *lro_desc,
skb->truesize += truesize;
skb_frags[0].page_offset += hlen;
- skb_frags[0].size -= hlen;
+ skb_frag_size_sub(&skb_frags[0], hlen);
while (tcp_data_len > 0) {
*(lro_desc->next_frag) = *skb_frags;
- tcp_data_len -= skb_frags->size;
+ tcp_data_len -= skb_frag_size(skb_frags);
lro_desc->next_frag++;
skb_frags++;
skb_shinfo(skb)->nr_frags++;
@@ -400,14 +400,14 @@ static struct sk_buff *lro_gen_skb(struct net_lro_mgr *lro_mgr,
skb_frags = skb_shinfo(skb)->frags;
while (data_len > 0) {
*skb_frags = *frags;
- data_len -= frags->size;
+ data_len -= skb_frag_size(frags);
skb_frags++;
frags++;
skb_shinfo(skb)->nr_frags++;
}
skb_shinfo(skb)->frags[0].page_offset += hdr_len;
- skb_shinfo(skb)->frags[0].size -= hdr_len;
+ skb_frag_size_sub(&skb_shinfo(skb)->frags[0], hdr_len);
skb->ip_summed = ip_summed;
skb->csum = sum;
@@ -433,7 +433,7 @@ static struct sk_buff *__lro_proc_segment(struct net_lro_mgr *lro_mgr,
if (!lro_mgr->get_frag_header ||
lro_mgr->get_frag_header(frags, (void *)&mac_hdr, (void *)&iph,
(void *)&tcph, &flags, priv)) {
- mac_hdr = page_address(frags->page) + frags->page_offset;
+ mac_hdr = skb_frag_address(frags);
goto out1;
}
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
index 3c8dfa16614d..44d65d546e30 100644
--- a/net/ipv4/inet_timewait_sock.c
+++ b/net/ipv4/inet_timewait_sock.c
@@ -183,6 +183,7 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int stat
tw->tw_daddr = inet->inet_daddr;
tw->tw_rcv_saddr = inet->inet_rcv_saddr;
tw->tw_bound_dev_if = sk->sk_bound_dev_if;
+ tw->tw_tos = inet->tos;
tw->tw_num = inet->inet_num;
tw->tw_state = TCP_TIME_WAIT;
tw->tw_substate = state;
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 0e0ab98abc6f..fdaabf2f2b68 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -599,8 +599,8 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
head->next = clone;
skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
skb_frag_list_init(head);
- for (i=0; i<skb_shinfo(head)->nr_frags; i++)
- plen += skb_shinfo(head)->frags[i].size;
+ for (i = 0; i < skb_shinfo(head)->nr_frags; i++)
+ plen += skb_frag_size(&skb_shinfo(head)->frags[i]);
clone->len = clone->data_len = head->data_len - plen;
head->data_len -= clone->len;
head->len -= clone->len;
@@ -682,6 +682,42 @@ int ip_defrag(struct sk_buff *skb, u32 user)
}
EXPORT_SYMBOL(ip_defrag);
+struct sk_buff *ip_check_defrag(struct sk_buff *skb, u32 user)
+{
+ const struct iphdr *iph;
+ u32 len;
+
+ if (skb->protocol != htons(ETH_P_IP))
+ return skb;
+
+ if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+ return skb;
+
+ iph = ip_hdr(skb);
+ if (iph->ihl < 5 || iph->version != 4)
+ return skb;
+ if (!pskb_may_pull(skb, iph->ihl*4))
+ return skb;
+ iph = ip_hdr(skb);
+ len = ntohs(iph->tot_len);
+ if (skb->len < len || len < (iph->ihl * 4))
+ return skb;
+
+ if (ip_is_fragment(ip_hdr(skb))) {
+ skb = skb_share_check(skb, GFP_ATOMIC);
+ if (skb) {
+ if (pskb_trim_rcsum(skb, len))
+ return skb;
+ memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
+ if (ip_defrag(skb, user))
+ return NULL;
+ skb->rxhash = 0;
+ }
+ }
+ return skb;
+}
+EXPORT_SYMBOL(ip_check_defrag);
+
#ifdef CONFIG_SYSCTL
static int zero;
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index d7bb94c48345..d55110e93120 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -835,8 +835,6 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
if (skb_headroom(skb) < max_headroom || skb_shared(skb)||
(skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
- if (max_headroom > dev->needed_headroom)
- dev->needed_headroom = max_headroom;
if (!new_skb) {
ip_rt_put(rt);
dev->stats.tx_dropped++;
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 8c6563361ab5..0bc95f3977d2 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -989,13 +989,13 @@ alloc_new_skb:
if (page && (left = PAGE_SIZE - off) > 0) {
if (copy >= left)
copy = left;
- if (page != frag->page) {
+ if (page != skb_frag_page(frag)) {
if (i == MAX_SKB_FRAGS) {
err = -EMSGSIZE;
goto error;
}
- get_page(page);
skb_fill_page_desc(skb, i, page, off, 0);
+ skb_frag_ref(skb, i);
frag = &skb_shinfo(skb)->frags[i];
}
} else if (i < MAX_SKB_FRAGS) {
@@ -1015,12 +1015,13 @@ alloc_new_skb:
err = -EMSGSIZE;
goto error;
}
- if (getfrag(from, page_address(frag->page)+frag->page_offset+frag->size, offset, copy, skb->len, skb) < 0) {
+ if (getfrag(from, skb_frag_address(frag)+skb_frag_size(frag),
+ offset, copy, skb->len, skb) < 0) {
err = -EFAULT;
goto error;
}
cork->off += copy;
- frag->size += copy;
+ skb_frag_size_add(frag, copy);
skb->len += copy;
skb->data_len += copy;
skb->truesize += copy;
@@ -1229,7 +1230,7 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page,
if (len > size)
len = size;
if (skb_can_coalesce(skb, i, page, offset)) {
- skb_shinfo(skb)->frags[i-1].size += len;
+ skb_frag_size_add(&skb_shinfo(skb)->frags[i-1], len);
} else if (i < MAX_SKB_FRAGS) {
get_page(page);
skb_fill_page_desc(skb, i, page, offset, len);
@@ -1465,7 +1466,7 @@ static int ip_reply_glue_bits(void *dptr, char *to, int offset,
* structure to pass arguments.
*/
void ip_send_reply(struct sock *sk, struct sk_buff *skb, __be32 daddr,
- struct ip_reply_arg *arg, unsigned int len)
+ const struct ip_reply_arg *arg, unsigned int len)
{
struct inet_sock *inet = inet_sk(sk);
struct ip_options_data replyopts;
@@ -1488,7 +1489,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, __be32 daddr,
}
flowi4_init_output(&fl4, arg->bound_dev_if, 0,
- RT_TOS(ip_hdr(skb)->tos),
+ RT_TOS(arg->tos),
RT_SCOPE_UNIVERSE, sk->sk_protocol,
ip_reply_arg_flowi_flags(arg),
daddr, rt->rt_spec_dst,
@@ -1505,7 +1506,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, __be32 daddr,
with locally disabled BH and that sk cannot be already spinlocked.
*/
bh_lock_sock(sk);
- inet->tos = ip_hdr(skb)->tos;
+ inet->tos = arg->tos;
sk->sk_priority = skb->priority;
sk->sk_protocol = ip_hdr(skb)->protocol;
sk->sk_bound_dev_if = arg->bound_dev_if;
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 8905e92f896a..09ff51bf16a4 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -33,6 +33,7 @@
#include <linux/netfilter.h>
#include <linux/route.h>
#include <linux/mroute.h>
+#include <net/inet_ecn.h>
#include <net/route.h>
#include <net/xfrm.h>
#include <net/compat.h>
@@ -578,8 +579,8 @@ static int do_ip_setsockopt(struct sock *sk, int level,
break;
case IP_TOS: /* This sets both TOS and Precedence */
if (sk->sk_type == SOCK_STREAM) {
- val &= ~3;
- val |= inet->tos & 3;
+ val &= ~INET_ECN_MASK;
+ val |= inet->tos & INET_ECN_MASK;
}
if (inet->tos != val) {
inet->tos = val;
@@ -961,7 +962,7 @@ mc_msf_out:
break;
case IP_TRANSPARENT:
- if (!capable(CAP_NET_ADMIN)) {
+ if (!!val && !capable(CAP_NET_RAW) && !capable(CAP_NET_ADMIN)) {
err = -EPERM;
break;
}
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 378b20b7ca6e..065effd8349a 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -231,7 +231,7 @@ static void ipip_tunnel_unlink(struct ipip_net *ipn, struct ip_tunnel *t)
(iter = rtnl_dereference(*tp)) != NULL;
tp = &iter->next) {
if (t == iter) {
- rcu_assign_pointer(*tp, t->next);
+ RCU_INIT_POINTER(*tp, t->next);
break;
}
}
@@ -241,8 +241,8 @@ static void ipip_tunnel_link(struct ipip_net *ipn, struct ip_tunnel *t)
{
struct ip_tunnel __rcu **tp = ipip_bucket(ipn, t);
- rcu_assign_pointer(t->next, rtnl_dereference(*tp));
- rcu_assign_pointer(*tp, t);
+ RCU_INIT_POINTER(t->next, rtnl_dereference(*tp));
+ RCU_INIT_POINTER(*tp, t);
}
static struct ip_tunnel * ipip_tunnel_locate(struct net *net,
@@ -301,7 +301,7 @@ static void ipip_tunnel_uninit(struct net_device *dev)
struct ipip_net *ipn = net_generic(net, ipip_net_id);
if (dev == ipn->fb_tunnel_dev)
- rcu_assign_pointer(ipn->tunnels_wc[0], NULL);
+ RCU_INIT_POINTER(ipn->tunnels_wc[0], NULL);
else
ipip_tunnel_unlink(ipn, netdev_priv(dev));
dev_put(dev);
@@ -791,7 +791,7 @@ static int __net_init ipip_fb_tunnel_init(struct net_device *dev)
return -ENOMEM;
dev_hold(dev);
- rcu_assign_pointer(ipn->tunnels_wc[0], tunnel);
+ RCU_INIT_POINTER(ipn->tunnels_wc[0], tunnel);
return 0;
}
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 58e879157976..6164e982e0ef 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1176,7 +1176,7 @@ static void mrtsock_destruct(struct sock *sk)
ipmr_for_each_table(mrt, net) {
if (sk == rtnl_dereference(mrt->mroute_sk)) {
IPV4_DEVCONF_ALL(net, MC_FORWARDING)--;
- rcu_assign_pointer(mrt->mroute_sk, NULL);
+ RCU_INIT_POINTER(mrt->mroute_sk, NULL);
mroute_clean_tables(mrt);
}
}
@@ -1203,7 +1203,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
return -ENOENT;
if (optname != MRT_INIT) {
- if (sk != rcu_dereference_raw(mrt->mroute_sk) &&
+ if (sk != rcu_access_pointer(mrt->mroute_sk) &&
!capable(CAP_NET_ADMIN))
return -EACCES;
}
@@ -1224,13 +1224,13 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
ret = ip_ra_control(sk, 1, mrtsock_destruct);
if (ret == 0) {
- rcu_assign_pointer(mrt->mroute_sk, sk);
+ RCU_INIT_POINTER(mrt->mroute_sk, sk);
IPV4_DEVCONF_ALL(net, MC_FORWARDING)++;
}
rtnl_unlock();
return ret;
case MRT_DONE:
- if (sk != rcu_dereference_raw(mrt->mroute_sk))
+ if (sk != rcu_access_pointer(mrt->mroute_sk))
return -EACCES;
return ip_ra_control(sk, 0, NULL);
case MRT_ADD_VIF:
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index 5c9b9d963918..e59aabd0eae4 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -218,6 +218,7 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
return skb;
nlmsg_failure:
+ kfree_skb(skb);
*errp = -EINVAL;
printk(KERN_ERR "ip_queue: error creating packet message\n");
return NULL;
@@ -313,7 +314,7 @@ ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len)
{
struct nf_queue_entry *entry;
- if (vmsg->value > NF_MAX_VERDICT)
+ if (vmsg->value > NF_MAX_VERDICT || vmsg->value == NF_STOLEN)
return -EINVAL;
entry = ipq_find_dequeue_entry(vmsg->id);
@@ -358,12 +359,9 @@ ipq_receive_peer(struct ipq_peer_msg *pmsg,
break;
case IPQM_VERDICT:
- if (pmsg->msg.verdict.value > NF_MAX_VERDICT)
- status = -EINVAL;
- else
- status = ipq_set_verdict(&pmsg->msg.verdict,
- len - sizeof(*pmsg));
- break;
+ status = ipq_set_verdict(&pmsg->msg.verdict,
+ len - sizeof(*pmsg));
+ break;
default:
status = -EINVAL;
}
diff --git a/net/ipv4/netfilter/nf_nat_amanda.c b/net/ipv4/netfilter/nf_nat_amanda.c
index 703f366fd235..7b22382ff0e9 100644
--- a/net/ipv4/netfilter/nf_nat_amanda.c
+++ b/net/ipv4/netfilter/nf_nat_amanda.c
@@ -70,14 +70,14 @@ static unsigned int help(struct sk_buff *skb,
static void __exit nf_nat_amanda_fini(void)
{
- rcu_assign_pointer(nf_nat_amanda_hook, NULL);
+ RCU_INIT_POINTER(nf_nat_amanda_hook, NULL);
synchronize_rcu();
}
static int __init nf_nat_amanda_init(void)
{
BUG_ON(nf_nat_amanda_hook != NULL);
- rcu_assign_pointer(nf_nat_amanda_hook, help);
+ RCU_INIT_POINTER(nf_nat_amanda_hook, help);
return 0;
}
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index 3346de5d94d0..447bc5cfdc6c 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -514,7 +514,7 @@ int nf_nat_protocol_register(const struct nf_nat_protocol *proto)
ret = -EBUSY;
goto out;
}
- rcu_assign_pointer(nf_nat_protos[proto->protonum], proto);
+ RCU_INIT_POINTER(nf_nat_protos[proto->protonum], proto);
out:
spin_unlock_bh(&nf_nat_lock);
return ret;
@@ -525,7 +525,7 @@ EXPORT_SYMBOL(nf_nat_protocol_register);
void nf_nat_protocol_unregister(const struct nf_nat_protocol *proto)
{
spin_lock_bh(&nf_nat_lock);
- rcu_assign_pointer(nf_nat_protos[proto->protonum],
+ RCU_INIT_POINTER(nf_nat_protos[proto->protonum],
&nf_nat_unknown_protocol);
spin_unlock_bh(&nf_nat_lock);
synchronize_rcu();
@@ -736,10 +736,10 @@ static int __init nf_nat_init(void)
/* Sew in builtin protocols. */
spin_lock_bh(&nf_nat_lock);
for (i = 0; i < MAX_IP_NAT_PROTO; i++)
- rcu_assign_pointer(nf_nat_protos[i], &nf_nat_unknown_protocol);
- rcu_assign_pointer(nf_nat_protos[IPPROTO_TCP], &nf_nat_protocol_tcp);
- rcu_assign_pointer(nf_nat_protos[IPPROTO_UDP], &nf_nat_protocol_udp);
- rcu_assign_pointer(nf_nat_protos[IPPROTO_ICMP], &nf_nat_protocol_icmp);
+ RCU_INIT_POINTER(nf_nat_protos[i], &nf_nat_unknown_protocol);
+ RCU_INIT_POINTER(nf_nat_protos[IPPROTO_TCP], &nf_nat_protocol_tcp);
+ RCU_INIT_POINTER(nf_nat_protos[IPPROTO_UDP], &nf_nat_protocol_udp);
+ RCU_INIT_POINTER(nf_nat_protos[IPPROTO_ICMP], &nf_nat_protocol_icmp);
spin_unlock_bh(&nf_nat_lock);
/* Initialize fake conntrack so that NAT will skip it */
@@ -748,12 +748,12 @@ static int __init nf_nat_init(void)
l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET);
BUG_ON(nf_nat_seq_adjust_hook != NULL);
- rcu_assign_pointer(nf_nat_seq_adjust_hook, nf_nat_seq_adjust);
+ RCU_INIT_POINTER(nf_nat_seq_adjust_hook, nf_nat_seq_adjust);
BUG_ON(nfnetlink_parse_nat_setup_hook != NULL);
- rcu_assign_pointer(nfnetlink_parse_nat_setup_hook,
+ RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook,
nfnetlink_parse_nat_setup);
BUG_ON(nf_ct_nat_offset != NULL);
- rcu_assign_pointer(nf_ct_nat_offset, nf_nat_get_offset);
+ RCU_INIT_POINTER(nf_ct_nat_offset, nf_nat_get_offset);
return 0;
cleanup_extend:
@@ -766,9 +766,9 @@ 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);
- rcu_assign_pointer(nf_nat_seq_adjust_hook, NULL);
- rcu_assign_pointer(nfnetlink_parse_nat_setup_hook, NULL);
- rcu_assign_pointer(nf_ct_nat_offset, NULL);
+ 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);
synchronize_net();
}
diff --git a/net/ipv4/netfilter/nf_nat_ftp.c b/net/ipv4/netfilter/nf_nat_ftp.c
index dc73abb3fe27..e462a957d080 100644
--- a/net/ipv4/netfilter/nf_nat_ftp.c
+++ b/net/ipv4/netfilter/nf_nat_ftp.c
@@ -113,14 +113,14 @@ out:
static void __exit nf_nat_ftp_fini(void)
{
- rcu_assign_pointer(nf_nat_ftp_hook, NULL);
+ RCU_INIT_POINTER(nf_nat_ftp_hook, NULL);
synchronize_rcu();
}
static int __init nf_nat_ftp_init(void)
{
BUG_ON(nf_nat_ftp_hook != NULL);
- rcu_assign_pointer(nf_nat_ftp_hook, nf_nat_ftp);
+ RCU_INIT_POINTER(nf_nat_ftp_hook, nf_nat_ftp);
return 0;
}
diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c
index 790f3160e012..b9a1136addbd 100644
--- a/net/ipv4/netfilter/nf_nat_h323.c
+++ b/net/ipv4/netfilter/nf_nat_h323.c
@@ -581,30 +581,30 @@ static int __init init(void)
BUG_ON(nat_callforwarding_hook != NULL);
BUG_ON(nat_q931_hook != NULL);
- rcu_assign_pointer(set_h245_addr_hook, set_h245_addr);
- rcu_assign_pointer(set_h225_addr_hook, set_h225_addr);
- rcu_assign_pointer(set_sig_addr_hook, set_sig_addr);
- rcu_assign_pointer(set_ras_addr_hook, set_ras_addr);
- rcu_assign_pointer(nat_rtp_rtcp_hook, nat_rtp_rtcp);
- rcu_assign_pointer(nat_t120_hook, nat_t120);
- rcu_assign_pointer(nat_h245_hook, nat_h245);
- rcu_assign_pointer(nat_callforwarding_hook, nat_callforwarding);
- rcu_assign_pointer(nat_q931_hook, nat_q931);
+ RCU_INIT_POINTER(set_h245_addr_hook, set_h245_addr);
+ RCU_INIT_POINTER(set_h225_addr_hook, set_h225_addr);
+ RCU_INIT_POINTER(set_sig_addr_hook, set_sig_addr);
+ RCU_INIT_POINTER(set_ras_addr_hook, set_ras_addr);
+ RCU_INIT_POINTER(nat_rtp_rtcp_hook, nat_rtp_rtcp);
+ RCU_INIT_POINTER(nat_t120_hook, nat_t120);
+ RCU_INIT_POINTER(nat_h245_hook, nat_h245);
+ RCU_INIT_POINTER(nat_callforwarding_hook, nat_callforwarding);
+ RCU_INIT_POINTER(nat_q931_hook, nat_q931);
return 0;
}
/****************************************************************************/
static void __exit fini(void)
{
- rcu_assign_pointer(set_h245_addr_hook, NULL);
- rcu_assign_pointer(set_h225_addr_hook, NULL);
- rcu_assign_pointer(set_sig_addr_hook, NULL);
- rcu_assign_pointer(set_ras_addr_hook, NULL);
- rcu_assign_pointer(nat_rtp_rtcp_hook, NULL);
- rcu_assign_pointer(nat_t120_hook, NULL);
- rcu_assign_pointer(nat_h245_hook, NULL);
- rcu_assign_pointer(nat_callforwarding_hook, NULL);
- rcu_assign_pointer(nat_q931_hook, NULL);
+ RCU_INIT_POINTER(set_h245_addr_hook, NULL);
+ RCU_INIT_POINTER(set_h225_addr_hook, NULL);
+ RCU_INIT_POINTER(set_sig_addr_hook, NULL);
+ RCU_INIT_POINTER(set_ras_addr_hook, NULL);
+ RCU_INIT_POINTER(nat_rtp_rtcp_hook, NULL);
+ RCU_INIT_POINTER(nat_t120_hook, NULL);
+ RCU_INIT_POINTER(nat_h245_hook, NULL);
+ RCU_INIT_POINTER(nat_callforwarding_hook, NULL);
+ RCU_INIT_POINTER(nat_q931_hook, NULL);
synchronize_rcu();
}
diff --git a/net/ipv4/netfilter/nf_nat_irc.c b/net/ipv4/netfilter/nf_nat_irc.c
index 535e1a802356..979ae165f4ef 100644
--- a/net/ipv4/netfilter/nf_nat_irc.c
+++ b/net/ipv4/netfilter/nf_nat_irc.c
@@ -75,14 +75,14 @@ static unsigned int help(struct sk_buff *skb,
static void __exit nf_nat_irc_fini(void)
{
- rcu_assign_pointer(nf_nat_irc_hook, NULL);
+ RCU_INIT_POINTER(nf_nat_irc_hook, NULL);
synchronize_rcu();
}
static int __init nf_nat_irc_init(void)
{
BUG_ON(nf_nat_irc_hook != NULL);
- rcu_assign_pointer(nf_nat_irc_hook, help);
+ RCU_INIT_POINTER(nf_nat_irc_hook, help);
return 0;
}
diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_pptp.c
index 4c060038d29f..3e8284ba46b8 100644
--- a/net/ipv4/netfilter/nf_nat_pptp.c
+++ b/net/ipv4/netfilter/nf_nat_pptp.c
@@ -282,25 +282,25 @@ static int __init nf_nat_helper_pptp_init(void)
nf_nat_need_gre();
BUG_ON(nf_nat_pptp_hook_outbound != NULL);
- rcu_assign_pointer(nf_nat_pptp_hook_outbound, pptp_outbound_pkt);
+ RCU_INIT_POINTER(nf_nat_pptp_hook_outbound, pptp_outbound_pkt);
BUG_ON(nf_nat_pptp_hook_inbound != NULL);
- rcu_assign_pointer(nf_nat_pptp_hook_inbound, pptp_inbound_pkt);
+ RCU_INIT_POINTER(nf_nat_pptp_hook_inbound, pptp_inbound_pkt);
BUG_ON(nf_nat_pptp_hook_exp_gre != NULL);
- rcu_assign_pointer(nf_nat_pptp_hook_exp_gre, pptp_exp_gre);
+ RCU_INIT_POINTER(nf_nat_pptp_hook_exp_gre, pptp_exp_gre);
BUG_ON(nf_nat_pptp_hook_expectfn != NULL);
- rcu_assign_pointer(nf_nat_pptp_hook_expectfn, pptp_nat_expected);
+ RCU_INIT_POINTER(nf_nat_pptp_hook_expectfn, pptp_nat_expected);
return 0;
}
static void __exit nf_nat_helper_pptp_fini(void)
{
- rcu_assign_pointer(nf_nat_pptp_hook_expectfn, NULL);
- rcu_assign_pointer(nf_nat_pptp_hook_exp_gre, NULL);
- rcu_assign_pointer(nf_nat_pptp_hook_inbound, NULL);
- rcu_assign_pointer(nf_nat_pptp_hook_outbound, NULL);
+ RCU_INIT_POINTER(nf_nat_pptp_hook_expectfn, NULL);
+ RCU_INIT_POINTER(nf_nat_pptp_hook_exp_gre, NULL);
+ RCU_INIT_POINTER(nf_nat_pptp_hook_inbound, NULL);
+ RCU_INIT_POINTER(nf_nat_pptp_hook_outbound, NULL);
synchronize_rcu();
}
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index e40cf7816fdb..78844d9208f1 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -528,13 +528,13 @@ err1:
static void __exit nf_nat_sip_fini(void)
{
- rcu_assign_pointer(nf_nat_sip_hook, NULL);
- rcu_assign_pointer(nf_nat_sip_seq_adjust_hook, NULL);
- rcu_assign_pointer(nf_nat_sip_expect_hook, NULL);
- rcu_assign_pointer(nf_nat_sdp_addr_hook, NULL);
- rcu_assign_pointer(nf_nat_sdp_port_hook, NULL);
- rcu_assign_pointer(nf_nat_sdp_session_hook, NULL);
- rcu_assign_pointer(nf_nat_sdp_media_hook, NULL);
+ RCU_INIT_POINTER(nf_nat_sip_hook, NULL);
+ RCU_INIT_POINTER(nf_nat_sip_seq_adjust_hook, NULL);
+ RCU_INIT_POINTER(nf_nat_sip_expect_hook, NULL);
+ RCU_INIT_POINTER(nf_nat_sdp_addr_hook, NULL);
+ 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);
synchronize_rcu();
}
@@ -547,13 +547,13 @@ static int __init nf_nat_sip_init(void)
BUG_ON(nf_nat_sdp_port_hook != NULL);
BUG_ON(nf_nat_sdp_session_hook != NULL);
BUG_ON(nf_nat_sdp_media_hook != NULL);
- rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip);
- rcu_assign_pointer(nf_nat_sip_seq_adjust_hook, ip_nat_sip_seq_adjust);
- rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect);
- rcu_assign_pointer(nf_nat_sdp_addr_hook, ip_nat_sdp_addr);
- rcu_assign_pointer(nf_nat_sdp_port_hook, ip_nat_sdp_port);
- rcu_assign_pointer(nf_nat_sdp_session_hook, ip_nat_sdp_session);
- rcu_assign_pointer(nf_nat_sdp_media_hook, ip_nat_sdp_media);
+ RCU_INIT_POINTER(nf_nat_sip_hook, ip_nat_sip);
+ RCU_INIT_POINTER(nf_nat_sip_seq_adjust_hook, ip_nat_sip_seq_adjust);
+ RCU_INIT_POINTER(nf_nat_sip_expect_hook, ip_nat_sip_expect);
+ RCU_INIT_POINTER(nf_nat_sdp_addr_hook, ip_nat_sdp_addr);
+ 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);
return 0;
}
diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c
index 076b7c8c4aa4..d1cb412c18e0 100644
--- a/net/ipv4/netfilter/nf_nat_snmp_basic.c
+++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c
@@ -1310,7 +1310,7 @@ static int __init nf_nat_snmp_basic_init(void)
int ret = 0;
BUG_ON(nf_nat_snmp_hook != NULL);
- rcu_assign_pointer(nf_nat_snmp_hook, help);
+ RCU_INIT_POINTER(nf_nat_snmp_hook, help);
ret = nf_conntrack_helper_register(&snmp_trap_helper);
if (ret < 0) {
@@ -1322,7 +1322,7 @@ static int __init nf_nat_snmp_basic_init(void)
static void __exit nf_nat_snmp_basic_fini(void)
{
- rcu_assign_pointer(nf_nat_snmp_hook, NULL);
+ RCU_INIT_POINTER(nf_nat_snmp_hook, NULL);
nf_conntrack_helper_unregister(&snmp_trap_helper);
}
diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c
index a6e606e84820..92900482edea 100644
--- a/net/ipv4/netfilter/nf_nat_standalone.c
+++ b/net/ipv4/netfilter/nf_nat_standalone.c
@@ -284,7 +284,7 @@ static int __init nf_nat_standalone_init(void)
#ifdef CONFIG_XFRM
BUG_ON(ip_nat_decode_session != NULL);
- rcu_assign_pointer(ip_nat_decode_session, nat_decode_session);
+ RCU_INIT_POINTER(ip_nat_decode_session, nat_decode_session);
#endif
ret = nf_nat_rule_init();
if (ret < 0) {
@@ -302,7 +302,7 @@ static int __init nf_nat_standalone_init(void)
nf_nat_rule_cleanup();
cleanup_decode_session:
#ifdef CONFIG_XFRM
- rcu_assign_pointer(ip_nat_decode_session, NULL);
+ RCU_INIT_POINTER(ip_nat_decode_session, NULL);
synchronize_net();
#endif
return ret;
@@ -313,7 +313,7 @@ static void __exit nf_nat_standalone_fini(void)
nf_unregister_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops));
nf_nat_rule_cleanup();
#ifdef CONFIG_XFRM
- rcu_assign_pointer(ip_nat_decode_session, NULL);
+ RCU_INIT_POINTER(ip_nat_decode_session, NULL);
synchronize_net();
#endif
/* Conntrack caches are unregistered in nf_conntrack_cleanup */
diff --git a/net/ipv4/netfilter/nf_nat_tftp.c b/net/ipv4/netfilter/nf_nat_tftp.c
index 7274a43c7a12..a2901bf829c0 100644
--- a/net/ipv4/netfilter/nf_nat_tftp.c
+++ b/net/ipv4/netfilter/nf_nat_tftp.c
@@ -36,14 +36,14 @@ static unsigned int help(struct sk_buff *skb,
static void __exit nf_nat_tftp_fini(void)
{
- rcu_assign_pointer(nf_nat_tftp_hook, NULL);
+ RCU_INIT_POINTER(nf_nat_tftp_hook, NULL);
synchronize_rcu();
}
static int __init nf_nat_tftp_init(void)
{
BUG_ON(nf_nat_tftp_hook != NULL);
- rcu_assign_pointer(nf_nat_tftp_hook, help);
+ RCU_INIT_POINTER(nf_nat_tftp_hook, help);
return 0;
}
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index b14ec7d03b6e..4bfad5da94f4 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -254,6 +254,8 @@ static const struct snmp_mib snmp4_net_list[] = {
SNMP_MIB_ITEM("TCPDeferAcceptDrop", LINUX_MIB_TCPDEFERACCEPTDROP),
SNMP_MIB_ITEM("IPReversePathFilter", LINUX_MIB_IPRPFILTER),
SNMP_MIB_ITEM("TCPTimeWaitOverflow", LINUX_MIB_TCPTIMEWAITOVERFLOW),
+ SNMP_MIB_ITEM("TCPReqQFullDoCookies", LINUX_MIB_TCPREQQFULLDOCOOKIES),
+ SNMP_MIB_ITEM("TCPReqQFullDrop", LINUX_MIB_TCPREQQFULLDROP),
SNMP_MIB_SENTINEL
};
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 075212e41b83..155138d8ec8b 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -120,7 +120,6 @@
static int ip_rt_max_size;
static int ip_rt_gc_timeout __read_mostly = RT_GC_TIMEOUT;
-static int ip_rt_gc_interval __read_mostly = 60 * HZ;
static int ip_rt_gc_min_interval __read_mostly = HZ / 2;
static int ip_rt_redirect_number __read_mostly = 9;
static int ip_rt_redirect_load __read_mostly = HZ / 50;
@@ -324,7 +323,7 @@ static struct rtable *rt_cache_get_first(struct seq_file *seq)
struct rtable *r = NULL;
for (st->bucket = rt_hash_mask; st->bucket >= 0; --st->bucket) {
- if (!rcu_dereference_raw(rt_hash_table[st->bucket].chain))
+ if (!rcu_access_pointer(rt_hash_table[st->bucket].chain))
continue;
rcu_read_lock_bh();
r = rcu_dereference_bh(rt_hash_table[st->bucket].chain);
@@ -350,7 +349,7 @@ static struct rtable *__rt_cache_get_next(struct seq_file *seq,
do {
if (--st->bucket < 0)
return NULL;
- } while (!rcu_dereference_raw(rt_hash_table[st->bucket].chain));
+ } while (!rcu_access_pointer(rt_hash_table[st->bucket].chain));
rcu_read_lock_bh();
r = rcu_dereference_bh(rt_hash_table[st->bucket].chain);
}
@@ -761,7 +760,7 @@ static void rt_do_flush(struct net *net, int process_context)
if (process_context && need_resched())
cond_resched();
- rth = rcu_dereference_raw(rt_hash_table[i].chain);
+ rth = rcu_access_pointer(rt_hash_table[i].chain);
if (!rth)
continue;
@@ -1309,7 +1308,12 @@ static void rt_del(unsigned hash, struct rtable *rt)
void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
__be32 saddr, struct net_device *dev)
{
+ int s, i;
struct in_device *in_dev = __in_dev_get_rcu(dev);
+ struct rtable *rt;
+ __be32 skeys[2] = { saddr, 0 };
+ int ikeys[2] = { dev->ifindex, 0 };
+ struct flowi4 fl4;
struct inet_peer *peer;
struct net *net;
@@ -1332,13 +1336,34 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
goto reject_redirect;
}
- peer = inet_getpeer_v4(daddr, 1);
- if (peer) {
- peer->redirect_learned.a4 = new_gw;
+ memset(&fl4, 0, sizeof(fl4));
+ fl4.daddr = daddr;
+ for (s = 0; s < 2; s++) {
+ for (i = 0; i < 2; i++) {
+ fl4.flowi4_oif = ikeys[i];
+ fl4.saddr = skeys[s];
+ rt = __ip_route_output_key(net, &fl4);
+ if (IS_ERR(rt))
+ continue;
- inet_putpeer(peer);
+ if (rt->dst.error || rt->dst.dev != dev ||
+ rt->rt_gateway != old_gw) {
+ ip_rt_put(rt);
+ continue;
+ }
+
+ if (!rt->peer)
+ rt_bind_peer(rt, rt->rt_dst, 1);
+
+ peer = rt->peer;
+ if (peer) {
+ peer->redirect_learned.a4 = new_gw;
+ atomic_inc(&__rt_peer_genid);
+ }
- atomic_inc(&__rt_peer_genid);
+ ip_rt_put(rt);
+ return;
+ }
}
return;
@@ -1568,11 +1593,10 @@ unsigned short ip_rt_frag_needed(struct net *net, const struct iphdr *iph,
est_mtu = mtu;
peer->pmtu_learned = mtu;
peer->pmtu_expires = pmtu_expires;
+ atomic_inc(&__rt_peer_genid);
}
inet_putpeer(peer);
-
- atomic_inc(&__rt_peer_genid);
}
return est_mtu ? : new_mtu;
}
@@ -3121,13 +3145,6 @@ static ctl_table ipv4_route_table[] = {
.proc_handler = proc_dointvec_jiffies,
},
{
- .procname = "gc_interval",
- .data = &ip_rt_gc_interval,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_jiffies,
- },
- {
.procname = "redirect_load",
.data = &ip_rt_redirect_load,
.maxlen = sizeof(int),
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 3bc5c8f7c71b..d7b89b12f6d8 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -265,7 +265,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
struct ip_options *opt)
{
struct tcp_options_received tcp_opt;
- u8 *hash_location;
+ const u8 *hash_location;
struct inet_request_sock *ireq;
struct tcp_request_sock *treq;
struct tcp_sock *tp = tcp_sk(sk);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 46febcacb729..34f5db1e1c8b 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -374,7 +374,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
{
unsigned int mask;
struct sock *sk = sock->sk;
- struct tcp_sock *tp = tcp_sk(sk);
+ const struct tcp_sock *tp = tcp_sk(sk);
sock_poll_wait(file, sk_sleep(sk), wait);
if (sk->sk_state == TCP_LISTEN)
@@ -524,11 +524,11 @@ EXPORT_SYMBOL(tcp_ioctl);
static inline void tcp_mark_push(struct tcp_sock *tp, struct sk_buff *skb)
{
- TCP_SKB_CB(skb)->flags |= TCPHDR_PSH;
+ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_PSH;
tp->pushed_seq = tp->write_seq;
}
-static inline int forced_push(struct tcp_sock *tp)
+static inline int forced_push(const struct tcp_sock *tp)
{
return after(tp->write_seq, tp->pushed_seq + (tp->max_window >> 1));
}
@@ -540,7 +540,7 @@ static inline void skb_entail(struct sock *sk, struct sk_buff *skb)
skb->csum = 0;
tcb->seq = tcb->end_seq = tp->write_seq;
- tcb->flags = TCPHDR_ACK;
+ tcb->tcp_flags = TCPHDR_ACK;
tcb->sacked = 0;
skb_header_release(skb);
tcp_add_write_queue_tail(sk, skb);
@@ -813,7 +813,7 @@ new_segment:
goto wait_for_memory;
if (can_coalesce) {
- skb_shinfo(skb)->frags[i - 1].size += copy;
+ skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
} else {
get_page(page);
skb_fill_page_desc(skb, i, page, offset, copy);
@@ -830,7 +830,7 @@ new_segment:
skb_shinfo(skb)->gso_segs = 0;
if (!copied)
- TCP_SKB_CB(skb)->flags &= ~TCPHDR_PSH;
+ TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_PSH;
copied += copy;
poffset += copy;
@@ -891,9 +891,9 @@ EXPORT_SYMBOL(tcp_sendpage);
#define TCP_PAGE(sk) (sk->sk_sndmsg_page)
#define TCP_OFF(sk) (sk->sk_sndmsg_off)
-static inline int select_size(struct sock *sk, int sg)
+static inline int select_size(const struct sock *sk, int sg)
{
- struct tcp_sock *tp = tcp_sk(sk);
+ const struct tcp_sock *tp = tcp_sk(sk);
int tmp = tp->mss_cache;
if (sg) {
@@ -1058,8 +1058,7 @@ new_segment:
/* Update the skb. */
if (merge) {
- skb_shinfo(skb)->frags[i - 1].size +=
- copy;
+ skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
} else {
skb_fill_page_desc(skb, i, page, off, copy);
if (TCP_PAGE(sk)) {
@@ -1074,7 +1073,7 @@ new_segment:
}
if (!copied)
- TCP_SKB_CB(skb)->flags &= ~TCPHDR_PSH;
+ TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_PSH;
tp->write_seq += copy;
TCP_SKB_CB(skb)->end_seq += copy;
@@ -1194,13 +1193,11 @@ void tcp_cleanup_rbuf(struct sock *sk, int copied)
struct tcp_sock *tp = tcp_sk(sk);
int time_to_ack = 0;
-#if TCP_DEBUG
struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
WARN(skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq),
"cleanup rbuf bug: copied %X seq %X rcvnxt %X\n",
tp->copied_seq, TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt);
-#endif
if (inet_csk_ack_scheduled(sk)) {
const struct inet_connection_sock *icsk = inet_csk(sk);
@@ -2409,7 +2406,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
unsigned int optlen)
{
- struct inet_connection_sock *icsk = inet_csk(sk);
+ const struct inet_connection_sock *icsk = inet_csk(sk);
if (level != SOL_TCP)
return icsk->icsk_af_ops->setsockopt(sk, level, optname,
@@ -2431,9 +2428,9 @@ EXPORT_SYMBOL(compat_tcp_setsockopt);
#endif
/* Return information about state of tcp endpoint in API format. */
-void tcp_get_info(struct sock *sk, struct tcp_info *info)
+void tcp_get_info(const struct sock *sk, struct tcp_info *info)
{
- struct tcp_sock *tp = tcp_sk(sk);
+ const struct tcp_sock *tp = tcp_sk(sk);
const struct inet_connection_sock *icsk = inet_csk(sk);
u32 now = tcp_time_stamp;
@@ -2455,8 +2452,10 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
info->tcpi_rcv_wscale = tp->rx_opt.rcv_wscale;
}
- if (tp->ecn_flags&TCP_ECN_OK)
+ if (tp->ecn_flags & TCP_ECN_OK)
info->tcpi_options |= TCPI_OPT_ECN;
+ if (tp->ecn_flags & TCP_ECN_SEEN)
+ info->tcpi_options |= TCPI_OPT_ECN_SEEN;
info->tcpi_rto = jiffies_to_usecs(icsk->icsk_rto);
info->tcpi_ato = jiffies_to_usecs(icsk->icsk_ack.ato);
@@ -2857,26 +2856,25 @@ EXPORT_SYMBOL(tcp_gro_complete);
#ifdef CONFIG_TCP_MD5SIG
static unsigned long tcp_md5sig_users;
-static struct tcp_md5sig_pool * __percpu *tcp_md5sig_pool;
+static struct tcp_md5sig_pool __percpu *tcp_md5sig_pool;
static DEFINE_SPINLOCK(tcp_md5sig_pool_lock);
-static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool * __percpu *pool)
+static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool __percpu *pool)
{
int cpu;
+
for_each_possible_cpu(cpu) {
- struct tcp_md5sig_pool *p = *per_cpu_ptr(pool, cpu);
- if (p) {
- if (p->md5_desc.tfm)
- crypto_free_hash(p->md5_desc.tfm);
- kfree(p);
- }
+ struct tcp_md5sig_pool *p = per_cpu_ptr(pool, cpu);
+
+ if (p->md5_desc.tfm)
+ crypto_free_hash(p->md5_desc.tfm);
}
free_percpu(pool);
}
void tcp_free_md5sig_pool(void)
{
- struct tcp_md5sig_pool * __percpu *pool = NULL;
+ struct tcp_md5sig_pool __percpu *pool = NULL;
spin_lock_bh(&tcp_md5sig_pool_lock);
if (--tcp_md5sig_users == 0) {
@@ -2889,30 +2887,24 @@ void tcp_free_md5sig_pool(void)
}
EXPORT_SYMBOL(tcp_free_md5sig_pool);
-static struct tcp_md5sig_pool * __percpu *
+static struct tcp_md5sig_pool __percpu *
__tcp_alloc_md5sig_pool(struct sock *sk)
{
int cpu;
- struct tcp_md5sig_pool * __percpu *pool;
+ struct tcp_md5sig_pool __percpu *pool;
- pool = alloc_percpu(struct tcp_md5sig_pool *);
+ pool = alloc_percpu(struct tcp_md5sig_pool);
if (!pool)
return NULL;
for_each_possible_cpu(cpu) {
- struct tcp_md5sig_pool *p;
struct crypto_hash *hash;
- p = kzalloc(sizeof(*p), sk->sk_allocation);
- if (!p)
- goto out_free;
- *per_cpu_ptr(pool, cpu) = p;
-
hash = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
if (!hash || IS_ERR(hash))
goto out_free;
- p->md5_desc.tfm = hash;
+ per_cpu_ptr(pool, cpu)->md5_desc.tfm = hash;
}
return pool;
out_free:
@@ -2920,9 +2912,9 @@ out_free:
return NULL;
}
-struct tcp_md5sig_pool * __percpu *tcp_alloc_md5sig_pool(struct sock *sk)
+struct tcp_md5sig_pool __percpu *tcp_alloc_md5sig_pool(struct sock *sk)
{
- struct tcp_md5sig_pool * __percpu *pool;
+ struct tcp_md5sig_pool __percpu *pool;
int alloc = 0;
retry:
@@ -2941,7 +2933,7 @@ retry:
if (alloc) {
/* we cannot hold spinlock here because this may sleep. */
- struct tcp_md5sig_pool * __percpu *p;
+ struct tcp_md5sig_pool __percpu *p;
p = __tcp_alloc_md5sig_pool(sk);
spin_lock_bh(&tcp_md5sig_pool_lock);
@@ -2974,7 +2966,7 @@ EXPORT_SYMBOL(tcp_alloc_md5sig_pool);
*/
struct tcp_md5sig_pool *tcp_get_md5sig_pool(void)
{
- struct tcp_md5sig_pool * __percpu *p;
+ struct tcp_md5sig_pool __percpu *p;
local_bh_disable();
@@ -2985,7 +2977,7 @@ struct tcp_md5sig_pool *tcp_get_md5sig_pool(void)
spin_unlock(&tcp_md5sig_pool_lock);
if (p)
- return *this_cpu_ptr(p);
+ return this_cpu_ptr(p);
local_bh_enable();
return NULL;
@@ -3000,23 +2992,25 @@ void tcp_put_md5sig_pool(void)
EXPORT_SYMBOL(tcp_put_md5sig_pool);
int tcp_md5_hash_header(struct tcp_md5sig_pool *hp,
- struct tcphdr *th)
+ const struct tcphdr *th)
{
struct scatterlist sg;
+ struct tcphdr hdr;
int err;
- __sum16 old_checksum = th->check;
- th->check = 0;
+ /* We are not allowed to change tcphdr, make a local copy */
+ memcpy(&hdr, th, sizeof(hdr));
+ hdr.check = 0;
+
/* options aren't included in the hash */
- sg_init_one(&sg, th, sizeof(struct tcphdr));
- err = crypto_hash_update(&hp->md5_desc, &sg, sizeof(struct tcphdr));
- th->check = old_checksum;
+ sg_init_one(&sg, &hdr, sizeof(hdr));
+ err = crypto_hash_update(&hp->md5_desc, &sg, sizeof(hdr));
return err;
}
EXPORT_SYMBOL(tcp_md5_hash_header);
int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *hp,
- struct sk_buff *skb, unsigned header_len)
+ const struct sk_buff *skb, unsigned int header_len)
{
struct scatterlist sg;
const struct tcphdr *tp = tcp_hdr(skb);
@@ -3035,8 +3029,9 @@ int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *hp,
for (i = 0; i < shi->nr_frags; ++i) {
const struct skb_frag_struct *f = &shi->frags[i];
- sg_set_page(&sg, f->page, f->size, f->page_offset);
- if (crypto_hash_update(desc, &sg, f->size))
+ struct page *page = skb_frag_page(f);
+ sg_set_page(&sg, page, skb_frag_size(f), f->page_offset);
+ if (crypto_hash_update(desc, &sg, skb_frag_size(f)))
return 1;
}
@@ -3048,7 +3043,7 @@ int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *hp,
}
EXPORT_SYMBOL(tcp_md5_hash_skb_data);
-int tcp_md5_hash_key(struct tcp_md5sig_pool *hp, struct tcp_md5sig_key *key)
+int tcp_md5_hash_key(struct tcp_md5sig_pool *hp, const struct tcp_md5sig_key *key)
{
struct scatterlist sg;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index ea0d2183df4b..52b5c2d0ecd0 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -206,7 +206,7 @@ static inline void TCP_ECN_queue_cwr(struct tcp_sock *tp)
tp->ecn_flags |= TCP_ECN_QUEUE_CWR;
}
-static inline void TCP_ECN_accept_cwr(struct tcp_sock *tp, struct sk_buff *skb)
+static inline void TCP_ECN_accept_cwr(struct tcp_sock *tp, const struct sk_buff *skb)
{
if (tcp_hdr(skb)->cwr)
tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR;
@@ -217,32 +217,41 @@ static inline void TCP_ECN_withdraw_cwr(struct tcp_sock *tp)
tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR;
}
-static inline void TCP_ECN_check_ce(struct tcp_sock *tp, struct sk_buff *skb)
+static inline void TCP_ECN_check_ce(struct tcp_sock *tp, const struct sk_buff *skb)
{
- if (tp->ecn_flags & TCP_ECN_OK) {
- if (INET_ECN_is_ce(TCP_SKB_CB(skb)->flags))
- tp->ecn_flags |= TCP_ECN_DEMAND_CWR;
+ if (!(tp->ecn_flags & TCP_ECN_OK))
+ return;
+
+ switch (TCP_SKB_CB(skb)->ip_dsfield & INET_ECN_MASK) {
+ case INET_ECN_NOT_ECT:
/* Funny extension: if ECT is not set on a segment,
- * it is surely retransmit. It is not in ECN RFC,
- * but Linux follows this rule. */
- else if (INET_ECN_is_not_ect((TCP_SKB_CB(skb)->flags)))
+ * and we already seen ECT on a previous segment,
+ * it is probably a retransmit.
+ */
+ if (tp->ecn_flags & TCP_ECN_SEEN)
tcp_enter_quickack_mode((struct sock *)tp);
+ break;
+ case INET_ECN_CE:
+ tp->ecn_flags |= TCP_ECN_DEMAND_CWR;
+ /* fallinto */
+ default:
+ tp->ecn_flags |= TCP_ECN_SEEN;
}
}
-static inline void TCP_ECN_rcv_synack(struct tcp_sock *tp, struct tcphdr *th)
+static inline void TCP_ECN_rcv_synack(struct tcp_sock *tp, const struct tcphdr *th)
{
if ((tp->ecn_flags & TCP_ECN_OK) && (!th->ece || th->cwr))
tp->ecn_flags &= ~TCP_ECN_OK;
}
-static inline void TCP_ECN_rcv_syn(struct tcp_sock *tp, struct tcphdr *th)
+static inline void TCP_ECN_rcv_syn(struct tcp_sock *tp, const struct tcphdr *th)
{
if ((tp->ecn_flags & TCP_ECN_OK) && (!th->ece || !th->cwr))
tp->ecn_flags &= ~TCP_ECN_OK;
}
-static inline int TCP_ECN_rcv_ecn_echo(struct tcp_sock *tp, struct tcphdr *th)
+static inline int TCP_ECN_rcv_ecn_echo(const struct tcp_sock *tp, const struct tcphdr *th)
{
if (th->ece && !th->syn && (tp->ecn_flags & TCP_ECN_OK))
return 1;
@@ -256,14 +265,11 @@ static inline int TCP_ECN_rcv_ecn_echo(struct tcp_sock *tp, struct tcphdr *th)
static void tcp_fixup_sndbuf(struct sock *sk)
{
- int sndmem = tcp_sk(sk)->rx_opt.mss_clamp + MAX_TCP_HEADER + 16 +
- sizeof(struct sk_buff);
+ int sndmem = SKB_TRUESIZE(tcp_sk(sk)->rx_opt.mss_clamp + MAX_TCP_HEADER);
- if (sk->sk_sndbuf < 3 * sndmem) {
- sk->sk_sndbuf = 3 * sndmem;
- if (sk->sk_sndbuf > sysctl_tcp_wmem[2])
- sk->sk_sndbuf = sysctl_tcp_wmem[2];
- }
+ sndmem *= TCP_INIT_CWND;
+ if (sk->sk_sndbuf < sndmem)
+ sk->sk_sndbuf = min(sndmem, sysctl_tcp_wmem[2]);
}
/* 2. Tuning advertised window (window_clamp, rcv_ssthresh)
@@ -309,7 +315,7 @@ static int __tcp_grow_window(const struct sock *sk, const struct sk_buff *skb)
return 0;
}
-static void tcp_grow_window(struct sock *sk, struct sk_buff *skb)
+static void tcp_grow_window(struct sock *sk, const struct sk_buff *skb)
{
struct tcp_sock *tp = tcp_sk(sk);
@@ -339,17 +345,24 @@ static void tcp_grow_window(struct sock *sk, struct sk_buff *skb)
static void tcp_fixup_rcvbuf(struct sock *sk)
{
- struct tcp_sock *tp = tcp_sk(sk);
- int rcvmem = tp->advmss + MAX_TCP_HEADER + 16 + sizeof(struct sk_buff);
+ u32 mss = tcp_sk(sk)->advmss;
+ u32 icwnd = TCP_DEFAULT_INIT_RCVWND;
+ int rcvmem;
- /* Try to select rcvbuf so that 4 mss-sized segments
- * will fit to window and corresponding skbs will fit to our rcvbuf.
- * (was 3; 4 is minimum to allow fast retransmit to work.)
+ /* Limit to 10 segments if mss <= 1460,
+ * or 14600/mss segments, with a minimum of two segments.
*/
- while (tcp_win_from_space(rcvmem) < tp->advmss)
+ if (mss > 1460)
+ icwnd = max_t(u32, (1460 * TCP_DEFAULT_INIT_RCVWND) / mss, 2);
+
+ rcvmem = SKB_TRUESIZE(mss + MAX_TCP_HEADER);
+ while (tcp_win_from_space(rcvmem) < mss)
rcvmem += 128;
- if (sk->sk_rcvbuf < 4 * rcvmem)
- sk->sk_rcvbuf = min(4 * rcvmem, sysctl_tcp_rmem[2]);
+
+ rcvmem *= icwnd;
+
+ if (sk->sk_rcvbuf < rcvmem)
+ sk->sk_rcvbuf = min(rcvmem, sysctl_tcp_rmem[2]);
}
/* 4. Try to fixup all. It is made immediately after connection enters
@@ -416,7 +429,7 @@ static void tcp_clamp_window(struct sock *sk)
*/
void tcp_initialize_rcv_mss(struct sock *sk)
{
- struct tcp_sock *tp = tcp_sk(sk);
+ const struct tcp_sock *tp = tcp_sk(sk);
unsigned int hint = min_t(unsigned int, tp->advmss, tp->mss_cache);
hint = min(hint, tp->rcv_wnd / 2);
@@ -531,8 +544,7 @@ void tcp_rcv_space_adjust(struct sock *sk)
space /= tp->advmss;
if (!space)
space = 1;
- rcvmem = (tp->advmss + MAX_TCP_HEADER +
- 16 + sizeof(struct sk_buff));
+ rcvmem = SKB_TRUESIZE(tp->advmss + MAX_TCP_HEADER);
while (tcp_win_from_space(rcvmem) < tp->advmss)
rcvmem += 128;
space *= rcvmem;
@@ -812,7 +824,7 @@ void tcp_update_metrics(struct sock *sk)
}
}
-__u32 tcp_init_cwnd(struct tcp_sock *tp, struct dst_entry *dst)
+__u32 tcp_init_cwnd(const struct tcp_sock *tp, const struct dst_entry *dst)
{
__u32 cwnd = (dst ? dst_metric(dst, RTAX_INITCWND) : 0);
@@ -1124,7 +1136,7 @@ static int tcp_is_sackblock_valid(struct tcp_sock *tp, int is_dsack,
return 0;
/* ...Then it's D-SACK, and must reside below snd_una completely */
- if (!after(end_seq, tp->snd_una))
+ if (after(end_seq, tp->snd_una))
return 0;
if (!before(start_seq, tp->undo_marker))
@@ -1204,7 +1216,7 @@ static void tcp_mark_lost_retrans(struct sock *sk)
tp->lost_retrans_low = new_low_seq;
}
-static int tcp_check_dsack(struct sock *sk, struct sk_buff *ack_skb,
+static int tcp_check_dsack(struct sock *sk, const struct sk_buff *ack_skb,
struct tcp_sack_block_wire *sp, int num_sacks,
u32 prior_snd_una)
{
@@ -1298,7 +1310,7 @@ static int tcp_match_skb_to_sack(struct sock *sk, struct sk_buff *skb,
return in_sack;
}
-static u8 tcp_sacktag_one(struct sk_buff *skb, struct sock *sk,
+static u8 tcp_sacktag_one(const struct sk_buff *skb, struct sock *sk,
struct tcp_sacktag_state *state,
int dup_sack, int pcount)
{
@@ -1389,9 +1401,7 @@ static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,
BUG_ON(!pcount);
- /* Tweak before seqno plays */
- if (!tcp_is_fack(tp) && tcp_is_sack(tp) && tp->lost_skb_hint &&
- !before(TCP_SKB_CB(tp->lost_skb_hint)->seq, TCP_SKB_CB(skb)->seq))
+ if (skb == tp->lost_skb_hint)
tp->lost_cnt_hint += pcount;
TCP_SKB_CB(prev)->end_seq += shifted;
@@ -1440,7 +1450,7 @@ static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,
tp->lost_cnt_hint -= tcp_skb_pcount(prev);
}
- TCP_SKB_CB(skb)->flags |= TCP_SKB_CB(prev)->flags;
+ TCP_SKB_CB(skb)->tcp_flags |= TCP_SKB_CB(prev)->tcp_flags;
if (skb == tcp_highest_sack(sk))
tcp_advance_highest_sack(sk, skb);
@@ -1455,13 +1465,13 @@ static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,
/* I wish gso_size would have a bit more sane initialization than
* something-or-zero which complicates things
*/
-static int tcp_skb_seglen(struct sk_buff *skb)
+static int tcp_skb_seglen(const struct sk_buff *skb)
{
return tcp_skb_pcount(skb) == 1 ? skb->len : tcp_skb_mss(skb);
}
/* Shifting pages past head area doesn't work */
-static int skb_can_shift(struct sk_buff *skb)
+static int skb_can_shift(const struct sk_buff *skb)
{
return !skb_headlen(skb) && skb_is_nonlinear(skb);
}
@@ -1710,19 +1720,19 @@ static struct sk_buff *tcp_maybe_skipping_dsack(struct sk_buff *skb,
return skb;
}
-static int tcp_sack_cache_ok(struct tcp_sock *tp, struct tcp_sack_block *cache)
+static int tcp_sack_cache_ok(const struct tcp_sock *tp, const struct tcp_sack_block *cache)
{
return cache < tp->recv_sack_cache + ARRAY_SIZE(tp->recv_sack_cache);
}
static int
-tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb,
+tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb,
u32 prior_snd_una)
{
const struct inet_connection_sock *icsk = inet_csk(sk);
struct tcp_sock *tp = tcp_sk(sk);
- unsigned char *ptr = (skb_transport_header(ack_skb) +
- TCP_SKB_CB(ack_skb)->sacked);
+ const unsigned char *ptr = (skb_transport_header(ack_skb) +
+ TCP_SKB_CB(ack_skb)->sacked);
struct tcp_sack_block_wire *sp_wire = (struct tcp_sack_block_wire *)(ptr+2);
struct tcp_sack_block sp[TCP_NUM_SACKS];
struct tcp_sack_block *cache;
@@ -2286,7 +2296,7 @@ static int tcp_check_sack_reneging(struct sock *sk, int flag)
return 0;
}
-static inline int tcp_fackets_out(struct tcp_sock *tp)
+static inline int tcp_fackets_out(const struct tcp_sock *tp)
{
return tcp_is_reno(tp) ? tp->sacked_out + 1 : tp->fackets_out;
}
@@ -2306,19 +2316,20 @@ static inline int tcp_fackets_out(struct tcp_sock *tp)
* they differ. Since neither occurs due to loss, TCP should really
* ignore them.
*/
-static inline int tcp_dupack_heuristics(struct tcp_sock *tp)
+static inline int tcp_dupack_heuristics(const struct tcp_sock *tp)
{
return tcp_is_fack(tp) ? tp->fackets_out : tp->sacked_out + 1;
}
-static inline int tcp_skb_timedout(struct sock *sk, struct sk_buff *skb)
+static inline int tcp_skb_timedout(const struct sock *sk,
+ const struct sk_buff *skb)
{
return tcp_time_stamp - TCP_SKB_CB(skb)->when > inet_csk(sk)->icsk_rto;
}
-static inline int tcp_head_timedout(struct sock *sk)
+static inline int tcp_head_timedout(const struct sock *sk)
{
- struct tcp_sock *tp = tcp_sk(sk);
+ const struct tcp_sock *tp = tcp_sk(sk);
return tp->packets_out &&
tcp_skb_timedout(sk, tcp_write_queue_head(sk));
@@ -2629,7 +2640,7 @@ static void tcp_cwnd_down(struct sock *sk, int flag)
/* Nothing was retransmitted or returned timestamp is less
* than timestamp of the first retransmission.
*/
-static inline int tcp_packet_delayed(struct tcp_sock *tp)
+static inline int tcp_packet_delayed(const struct tcp_sock *tp)
{
return !tp->retrans_stamp ||
(tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr &&
@@ -2690,7 +2701,7 @@ static void tcp_undo_cwr(struct sock *sk, const bool undo_ssthresh)
tp->snd_cwnd_stamp = tcp_time_stamp;
}
-static inline int tcp_may_undo(struct tcp_sock *tp)
+static inline int tcp_may_undo(const struct tcp_sock *tp)
{
return tp->undo_marker && (!tp->undo_retrans || tcp_packet_delayed(tp));
}
@@ -2754,9 +2765,9 @@ static void tcp_try_undo_dsack(struct sock *sk)
* that successive retransmissions of a segment must not advance
* retrans_stamp under any conditions.
*/
-static int tcp_any_retrans_done(struct sock *sk)
+static int tcp_any_retrans_done(const struct sock *sk)
{
- struct tcp_sock *tp = tcp_sk(sk);
+ const struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb;
if (tp->retrans_out)
@@ -2830,9 +2841,13 @@ static int tcp_try_undo_loss(struct sock *sk)
static inline void tcp_complete_cwr(struct sock *sk)
{
struct tcp_sock *tp = tcp_sk(sk);
- /* Do not moderate cwnd if it's already undone in cwr or recovery */
- if (tp->undo_marker && tp->snd_cwnd > tp->snd_ssthresh) {
- tp->snd_cwnd = tp->snd_ssthresh;
+
+ /* Do not moderate cwnd if it's already undone in cwr or recovery. */
+ if (tp->undo_marker) {
+ if (inet_csk(sk)->icsk_ca_state == TCP_CA_CWR)
+ tp->snd_cwnd = min(tp->snd_cwnd, tp->snd_ssthresh);
+ else /* PRR */
+ tp->snd_cwnd = tp->snd_ssthresh;
tp->snd_cwnd_stamp = tcp_time_stamp;
}
tcp_ca_event(sk, CA_EVENT_COMPLETE_CWR);
@@ -2950,6 +2965,38 @@ void tcp_simple_retransmit(struct sock *sk)
}
EXPORT_SYMBOL(tcp_simple_retransmit);
+/* This function implements the PRR algorithm, specifcally the PRR-SSRB
+ * (proportional rate reduction with slow start reduction bound) as described in
+ * http://www.ietf.org/id/draft-mathis-tcpm-proportional-rate-reduction-01.txt.
+ * It computes the number of packets to send (sndcnt) based on packets newly
+ * delivered:
+ * 1) If the packets in flight is larger than ssthresh, PRR spreads the
+ * cwnd reductions across a full RTT.
+ * 2) If packets in flight is lower than ssthresh (such as due to excess
+ * losses and/or application stalls), do not perform any further cwnd
+ * reductions, but instead slow start up to ssthresh.
+ */
+static void tcp_update_cwnd_in_recovery(struct sock *sk, int newly_acked_sacked,
+ int fast_rexmit, int flag)
+{
+ struct tcp_sock *tp = tcp_sk(sk);
+ int sndcnt = 0;
+ int delta = tp->snd_ssthresh - tcp_packets_in_flight(tp);
+
+ if (tcp_packets_in_flight(tp) > tp->snd_ssthresh) {
+ u64 dividend = (u64)tp->snd_ssthresh * tp->prr_delivered +
+ tp->prior_cwnd - 1;
+ sndcnt = div_u64(dividend, tp->prior_cwnd) - tp->prr_out;
+ } else {
+ sndcnt = min_t(int, delta,
+ max_t(int, tp->prr_delivered - tp->prr_out,
+ newly_acked_sacked) + 1);
+ }
+
+ sndcnt = max(sndcnt, (fast_rexmit ? 1 : 0));
+ tp->snd_cwnd = tcp_packets_in_flight(tp) + sndcnt;
+}
+
/* Process an event, which can update packets-in-flight not trivially.
* Main goal of this function is to calculate new estimate for left_out,
* taking into account both packets sitting in receiver's buffer and
@@ -2961,7 +3008,8 @@ EXPORT_SYMBOL(tcp_simple_retransmit);
* It does _not_ decide what to send, it is made in function
* tcp_xmit_retransmit_queue().
*/
-static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag)
+static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked,
+ int newly_acked_sacked, int flag)
{
struct inet_connection_sock *icsk = inet_csk(sk);
struct tcp_sock *tp = tcp_sk(sk);
@@ -3111,13 +3159,17 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag)
tp->bytes_acked = 0;
tp->snd_cwnd_cnt = 0;
+ tp->prior_cwnd = tp->snd_cwnd;
+ tp->prr_delivered = 0;
+ tp->prr_out = 0;
tcp_set_ca_state(sk, TCP_CA_Recovery);
fast_rexmit = 1;
}
if (do_lost || (tcp_is_fack(tp) && tcp_head_timedout(sk)))
tcp_update_scoreboard(sk, fast_rexmit);
- tcp_cwnd_down(sk, flag);
+ tp->prr_delivered += newly_acked_sacked;
+ tcp_update_cwnd_in_recovery(sk, newly_acked_sacked, fast_rexmit, flag);
tcp_xmit_retransmit_queue(sk);
}
@@ -3194,7 +3246,7 @@ static void tcp_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
*/
static void tcp_rearm_rto(struct sock *sk)
{
- struct tcp_sock *tp = tcp_sk(sk);
+ const struct tcp_sock *tp = tcp_sk(sk);
if (!tp->packets_out) {
inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
@@ -3298,7 +3350,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
* connection startup slow start one packet too
* quickly. This is severely frowned upon behavior.
*/
- if (!(scb->flags & TCPHDR_SYN)) {
+ if (!(scb->tcp_flags & TCPHDR_SYN)) {
flag |= FLAG_DATA_ACKED;
} else {
flag |= FLAG_SYN_ACKED;
@@ -3446,7 +3498,7 @@ static inline int tcp_may_update_window(const struct tcp_sock *tp,
* Window update algorithm, described in RFC793/RFC1122 (used in linux-2.2
* and in FreeBSD. NetBSD's one is even worse.) is wrong.
*/
-static int tcp_ack_update_window(struct sock *sk, struct sk_buff *skb, u32 ack,
+static int tcp_ack_update_window(struct sock *sk, const struct sk_buff *skb, u32 ack,
u32 ack_seq)
{
struct tcp_sock *tp = tcp_sk(sk);
@@ -3622,7 +3674,7 @@ static int tcp_process_frto(struct sock *sk, int flag)
}
/* This routine deals with incoming acks, but not outgoing ones. */
-static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
+static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
{
struct inet_connection_sock *icsk = inet_csk(sk);
struct tcp_sock *tp = tcp_sk(sk);
@@ -3632,6 +3684,8 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
u32 prior_in_flight;
u32 prior_fackets;
int prior_packets;
+ int prior_sacked = tp->sacked_out;
+ int newly_acked_sacked = 0;
int frto_cwnd = 0;
/* If the ack is older than previous acks
@@ -3703,6 +3757,9 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
/* See if we can take anything off of the retransmit queue. */
flag |= tcp_clean_rtx_queue(sk, prior_fackets, prior_snd_una);
+ newly_acked_sacked = (prior_packets - prior_sacked) -
+ (tp->packets_out - tp->sacked_out);
+
if (tp->frto_counter)
frto_cwnd = tcp_process_frto(sk, flag);
/* Guarantee sacktag reordering detection against wrap-arounds */
@@ -3715,7 +3772,7 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
tcp_may_raise_cwnd(sk, flag))
tcp_cong_avoid(sk, ack, prior_in_flight);
tcp_fastretrans_alert(sk, prior_packets - tp->packets_out,
- flag);
+ newly_acked_sacked, flag);
} else {
if ((flag & FLAG_DATA_ACKED) && !frto_cwnd)
tcp_cong_avoid(sk, ack, prior_in_flight);
@@ -3754,14 +3811,14 @@ old_ack:
* But, this can also be called on packets in the established flow when
* the fast version below fails.
*/
-void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx,
- u8 **hvpp, int estab)
+void tcp_parse_options(const struct sk_buff *skb, struct tcp_options_received *opt_rx,
+ const u8 **hvpp, int estab)
{
- unsigned char *ptr;
- struct tcphdr *th = tcp_hdr(skb);
+ const unsigned char *ptr;
+ const struct tcphdr *th = tcp_hdr(skb);
int length = (th->doff * 4) - sizeof(struct tcphdr);
- ptr = (unsigned char *)(th + 1);
+ ptr = (const unsigned char *)(th + 1);
opt_rx->saw_tstamp = 0;
while (length > 0) {
@@ -3872,9 +3929,9 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx,
}
EXPORT_SYMBOL(tcp_parse_options);
-static int tcp_parse_aligned_timestamp(struct tcp_sock *tp, struct tcphdr *th)
+static int tcp_parse_aligned_timestamp(struct tcp_sock *tp, const struct tcphdr *th)
{
- __be32 *ptr = (__be32 *)(th + 1);
+ const __be32 *ptr = (const __be32 *)(th + 1);
if (*ptr == htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
| (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) {
@@ -3891,8 +3948,9 @@ static int tcp_parse_aligned_timestamp(struct tcp_sock *tp, struct tcphdr *th)
/* Fast parse options. This hopes to only see timestamps.
* If it is wrong it falls back on tcp_parse_options().
*/
-static int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th,
- struct tcp_sock *tp, u8 **hvpp)
+static int tcp_fast_parse_options(const struct sk_buff *skb,
+ const struct tcphdr *th,
+ struct tcp_sock *tp, const u8 **hvpp)
{
/* In the spirit of fast parsing, compare doff directly to constant
* values. Because equality is used, short doff can be ignored here.
@@ -3913,10 +3971,10 @@ static int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th,
/*
* Parse MD5 Signature option
*/
-u8 *tcp_parse_md5sig_option(struct tcphdr *th)
+const u8 *tcp_parse_md5sig_option(const struct tcphdr *th)
{
- int length = (th->doff << 2) - sizeof (*th);
- u8 *ptr = (u8*)(th + 1);
+ int length = (th->doff << 2) - sizeof(*th);
+ const u8 *ptr = (const u8 *)(th + 1);
/* If the TCP option is too short, we can short cut */
if (length < TCPOLEN_MD5SIG)
@@ -3993,8 +4051,8 @@ static inline void tcp_replace_ts_recent(struct tcp_sock *tp, u32 seq)
static int tcp_disordered_ack(const struct sock *sk, const struct sk_buff *skb)
{
- struct tcp_sock *tp = tcp_sk(sk);
- struct tcphdr *th = tcp_hdr(skb);
+ const struct tcp_sock *tp = tcp_sk(sk);
+ const struct tcphdr *th = tcp_hdr(skb);
u32 seq = TCP_SKB_CB(skb)->seq;
u32 ack = TCP_SKB_CB(skb)->ack_seq;
@@ -4033,7 +4091,7 @@ static inline int tcp_paws_discard(const struct sock *sk,
* (borrowed from freebsd)
*/
-static inline int tcp_sequence(struct tcp_sock *tp, u32 seq, u32 end_seq)
+static inline int tcp_sequence(const struct tcp_sock *tp, u32 seq, u32 end_seq)
{
return !before(end_seq, tp->rcv_wup) &&
!after(seq, tp->rcv_nxt + tcp_receive_window(tp));
@@ -4078,7 +4136,7 @@ static void tcp_reset(struct sock *sk)
*
* If we are in FINWAIT-2, a received FIN moves us to TIME-WAIT.
*/
-static void tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
+static void tcp_fin(struct sock *sk)
{
struct tcp_sock *tp = tcp_sk(sk);
@@ -4190,7 +4248,7 @@ static void tcp_dsack_extend(struct sock *sk, u32 seq, u32 end_seq)
tcp_sack_extend(tp->duplicate_sack, seq, end_seq);
}
-static void tcp_send_dupack(struct sock *sk, struct sk_buff *skb)
+static void tcp_send_dupack(struct sock *sk, const struct sk_buff *skb)
{
struct tcp_sock *tp = tcp_sk(sk);
@@ -4349,7 +4407,7 @@ static void tcp_ofo_queue(struct sock *sk)
__skb_queue_tail(&sk->sk_receive_queue, skb);
tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
if (tcp_hdr(skb)->fin)
- tcp_fin(skb, sk, tcp_hdr(skb));
+ tcp_fin(sk);
}
}
@@ -4377,7 +4435,7 @@ static inline int tcp_try_rmem_schedule(struct sock *sk, unsigned int size)
static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
{
- struct tcphdr *th = tcp_hdr(skb);
+ const struct tcphdr *th = tcp_hdr(skb);
struct tcp_sock *tp = tcp_sk(sk);
int eaten = -1;
@@ -4431,7 +4489,7 @@ queue_and_out:
if (skb->len)
tcp_event_data_recv(sk, skb);
if (th->fin)
- tcp_fin(skb, sk, th);
+ tcp_fin(sk);
if (!skb_queue_empty(&tp->out_of_order_queue)) {
tcp_ofo_queue(sk);
@@ -4861,9 +4919,9 @@ void tcp_cwnd_application_limited(struct sock *sk)
tp->snd_cwnd_stamp = tcp_time_stamp;
}
-static int tcp_should_expand_sndbuf(struct sock *sk)
+static int tcp_should_expand_sndbuf(const struct sock *sk)
{
- struct tcp_sock *tp = tcp_sk(sk);
+ const struct tcp_sock *tp = tcp_sk(sk);
/* If the user specified a specific send buffer setting, do
* not modify it.
@@ -4897,8 +4955,10 @@ static void tcp_new_space(struct sock *sk)
struct tcp_sock *tp = tcp_sk(sk);
if (tcp_should_expand_sndbuf(sk)) {
- int sndmem = max_t(u32, tp->rx_opt.mss_clamp, tp->mss_cache) +
- MAX_TCP_HEADER + 16 + sizeof(struct sk_buff);
+ int sndmem = SKB_TRUESIZE(max_t(u32,
+ tp->rx_opt.mss_clamp,
+ tp->mss_cache) +
+ MAX_TCP_HEADER);
int demanded = max_t(unsigned int, tp->snd_cwnd,
tp->reordering + 1);
sndmem *= 2 * demanded;
@@ -4970,7 +5030,7 @@ static inline void tcp_ack_snd_check(struct sock *sk)
* either form (or just set the sysctl tcp_stdurg).
*/
-static void tcp_check_urg(struct sock *sk, struct tcphdr *th)
+static void tcp_check_urg(struct sock *sk, const struct tcphdr *th)
{
struct tcp_sock *tp = tcp_sk(sk);
u32 ptr = ntohs(th->urg_ptr);
@@ -5036,7 +5096,7 @@ static void tcp_check_urg(struct sock *sk, struct tcphdr *th)
}
/* This is the 'fast' part of urgent handling. */
-static void tcp_urg(struct sock *sk, struct sk_buff *skb, struct tcphdr *th)
+static void tcp_urg(struct sock *sk, struct sk_buff *skb, const struct tcphdr *th)
{
struct tcp_sock *tp = tcp_sk(sk);
@@ -5157,9 +5217,9 @@ out:
* play significant role here.
*/
static int tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
- struct tcphdr *th, int syn_inerr)
+ const struct tcphdr *th, int syn_inerr)
{
- u8 *hash_location;
+ const u8 *hash_location;
struct tcp_sock *tp = tcp_sk(sk);
/* RFC1323: H1. Apply PAWS check first. */
@@ -5240,7 +5300,7 @@ discard:
* tcp_data_queue when everything is OK.
*/
int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
- struct tcphdr *th, unsigned len)
+ const struct tcphdr *th, unsigned int len)
{
struct tcp_sock *tp = tcp_sk(sk);
int res;
@@ -5451,9 +5511,9 @@ discard:
EXPORT_SYMBOL(tcp_rcv_established);
static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
- struct tcphdr *th, unsigned len)
+ const struct tcphdr *th, unsigned int len)
{
- u8 *hash_location;
+ const u8 *hash_location;
struct inet_connection_sock *icsk = inet_csk(sk);
struct tcp_sock *tp = tcp_sk(sk);
struct tcp_cookie_values *cvp = tp->cookie_values;
@@ -5728,7 +5788,7 @@ reset_and_undo:
*/
int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
- struct tcphdr *th, unsigned len)
+ const struct tcphdr *th, unsigned int len)
{
struct tcp_sock *tp = tcp_sk(sk);
struct inet_connection_sock *icsk = inet_csk(sk);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 1c12b8ec849d..0ea10eefa60f 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -92,7 +92,7 @@ EXPORT_SYMBOL(sysctl_tcp_low_latency);
static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk,
__be32 addr);
static int tcp_v4_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
- __be32 daddr, __be32 saddr, struct tcphdr *th);
+ __be32 daddr, __be32 saddr, const struct tcphdr *th);
#else
static inline
struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr)
@@ -104,7 +104,7 @@ struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr)
struct inet_hashinfo tcp_hashinfo;
EXPORT_SYMBOL(tcp_hashinfo);
-static inline __u32 tcp_v4_init_sequence(struct sk_buff *skb)
+static inline __u32 tcp_v4_init_sequence(const struct sk_buff *skb)
{
return secure_tcp_sequence_number(ip_hdr(skb)->daddr,
ip_hdr(skb)->saddr,
@@ -552,7 +552,7 @@ static void __tcp_v4_send_check(struct sk_buff *skb,
/* This routine computes an IPv4 TCP checksum. */
void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb)
{
- struct inet_sock *inet = inet_sk(sk);
+ const struct inet_sock *inet = inet_sk(sk);
__tcp_v4_send_check(skb, inet->inet_saddr, inet->inet_daddr);
}
@@ -590,7 +590,7 @@ int tcp_v4_gso_send_check(struct sk_buff *skb)
static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
{
- struct tcphdr *th = tcp_hdr(skb);
+ const struct tcphdr *th = tcp_hdr(skb);
struct {
struct tcphdr th;
#ifdef CONFIG_TCP_MD5SIG
@@ -652,6 +652,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
arg.flags = (sk && inet_sk(sk)->transparent) ? IP_REPLY_ARG_NOSRCCHECK : 0;
net = dev_net(skb_dst(skb)->dev);
+ arg.tos = ip_hdr(skb)->tos;
ip_send_reply(net->ipv4.tcp_sock, skb, ip_hdr(skb)->saddr,
&arg, arg.iov[0].iov_len);
@@ -666,9 +667,9 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
u32 win, u32 ts, int oif,
struct tcp_md5sig_key *key,
- int reply_flags)
+ int reply_flags, u8 tos)
{
- struct tcphdr *th = tcp_hdr(skb);
+ const struct tcphdr *th = tcp_hdr(skb);
struct {
struct tcphdr th;
__be32 opt[(TCPOLEN_TSTAMP_ALIGNED >> 2)
@@ -726,7 +727,7 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
arg.csumoffset = offsetof(struct tcphdr, check) / 2;
if (oif)
arg.bound_dev_if = oif;
-
+ arg.tos = tos;
ip_send_reply(net->ipv4.tcp_sock, skb, ip_hdr(skb)->saddr,
&arg, arg.iov[0].iov_len);
@@ -743,7 +744,8 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb)
tcptw->tw_ts_recent,
tw->tw_bound_dev_if,
tcp_twsk_md5_key(tcptw),
- tw->tw_transparent ? IP_REPLY_ARG_NOSRCCHECK : 0
+ tw->tw_transparent ? IP_REPLY_ARG_NOSRCCHECK : 0,
+ tw->tw_tos
);
inet_twsk_put(tw);
@@ -757,7 +759,8 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
req->ts_recent,
0,
tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->daddr),
- inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0);
+ inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0,
+ ip_hdr(skb)->tos);
}
/*
@@ -808,20 +811,38 @@ static void tcp_v4_reqsk_destructor(struct request_sock *req)
kfree(inet_rsk(req)->opt);
}
-static void syn_flood_warning(const struct sk_buff *skb)
+/*
+ * Return 1 if a syncookie should be sent
+ */
+int tcp_syn_flood_action(struct sock *sk,
+ const struct sk_buff *skb,
+ const char *proto)
{
- const char *msg;
+ const char *msg = "Dropping request";
+ int want_cookie = 0;
+ struct listen_sock *lopt;
+
+
#ifdef CONFIG_SYN_COOKIES
- if (sysctl_tcp_syncookies)
+ if (sysctl_tcp_syncookies) {
msg = "Sending cookies";
- else
+ want_cookie = 1;
+ NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPREQQFULLDOCOOKIES);
+ } else
#endif
- msg = "Dropping request";
+ NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPREQQFULLDROP);
- pr_info("TCP: Possible SYN flooding on port %d. %s.\n",
- ntohs(tcp_hdr(skb)->dest), msg);
+ lopt = inet_csk(sk)->icsk_accept_queue.listen_opt;
+ if (!lopt->synflood_warned) {
+ lopt->synflood_warned = 1;
+ pr_info("%s: Possible SYN flooding on port %d. %s. "
+ " Check SNMP counters.\n",
+ proto, ntohs(tcp_hdr(skb)->dest), msg);
+ }
+ return want_cookie;
}
+EXPORT_SYMBOL(tcp_syn_flood_action);
/*
* Save and compile IPv4 options into the request_sock if needed.
@@ -909,18 +930,21 @@ int tcp_v4_md5_do_add(struct sock *sk, __be32 addr,
}
sk_nocaps_add(sk, NETIF_F_GSO_MASK);
}
- if (tcp_alloc_md5sig_pool(sk) == NULL) {
+
+ md5sig = tp->md5sig_info;
+ if (md5sig->entries4 == 0 &&
+ tcp_alloc_md5sig_pool(sk) == NULL) {
kfree(newkey);
return -ENOMEM;
}
- md5sig = tp->md5sig_info;
if (md5sig->alloced4 == md5sig->entries4) {
keys = kmalloc((sizeof(*keys) *
(md5sig->entries4 + 1)), GFP_ATOMIC);
if (!keys) {
kfree(newkey);
- tcp_free_md5sig_pool();
+ if (md5sig->entries4 == 0)
+ tcp_free_md5sig_pool();
return -ENOMEM;
}
@@ -964,6 +988,7 @@ int tcp_v4_md5_do_del(struct sock *sk, __be32 addr)
kfree(tp->md5sig_info->keys4);
tp->md5sig_info->keys4 = NULL;
tp->md5sig_info->alloced4 = 0;
+ tcp_free_md5sig_pool();
} else if (tp->md5sig_info->entries4 != i) {
/* Need to do some manipulation */
memmove(&tp->md5sig_info->keys4[i],
@@ -971,7 +996,6 @@ int tcp_v4_md5_do_del(struct sock *sk, __be32 addr)
(tp->md5sig_info->entries4 - i) *
sizeof(struct tcp4_md5sig_key));
}
- tcp_free_md5sig_pool();
return 0;
}
}
@@ -1069,7 +1093,7 @@ static int tcp_v4_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
}
static int tcp_v4_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
- __be32 daddr, __be32 saddr, struct tcphdr *th)
+ __be32 daddr, __be32 saddr, const struct tcphdr *th)
{
struct tcp_md5sig_pool *hp;
struct hash_desc *desc;
@@ -1101,12 +1125,12 @@ clear_hash_noput:
}
int tcp_v4_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,
- struct sock *sk, struct request_sock *req,
- struct sk_buff *skb)
+ const struct sock *sk, const struct request_sock *req,
+ const struct sk_buff *skb)
{
struct tcp_md5sig_pool *hp;
struct hash_desc *desc;
- struct tcphdr *th = tcp_hdr(skb);
+ const struct tcphdr *th = tcp_hdr(skb);
__be32 saddr, daddr;
if (sk) {
@@ -1151,7 +1175,7 @@ clear_hash_noput:
}
EXPORT_SYMBOL(tcp_v4_md5_hash_skb);
-static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb)
+static int tcp_v4_inbound_md5_hash(struct sock *sk, const struct sk_buff *skb)
{
/*
* This gets called for each TCP segment that arrives
@@ -1161,10 +1185,10 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb)
* o MD5 hash and we're not expecting one.
* o MD5 hash and its wrong.
*/
- __u8 *hash_location = NULL;
+ const __u8 *hash_location = NULL;
struct tcp_md5sig_key *hash_expected;
const struct iphdr *iph = ip_hdr(skb);
- struct tcphdr *th = tcp_hdr(skb);
+ const struct tcphdr *th = tcp_hdr(skb);
int genhash;
unsigned char newhash[16];
@@ -1227,7 +1251,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
{
struct tcp_extend_values tmp_ext;
struct tcp_options_received tmp_opt;
- u8 *hash_location;
+ const u8 *hash_location;
struct request_sock *req;
struct inet_request_sock *ireq;
struct tcp_sock *tp = tcp_sk(sk);
@@ -1235,11 +1259,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
__be32 saddr = ip_hdr(skb)->saddr;
__be32 daddr = ip_hdr(skb)->daddr;
__u32 isn = TCP_SKB_CB(skb)->when;
-#ifdef CONFIG_SYN_COOKIES
int want_cookie = 0;
-#else
-#define want_cookie 0 /* Argh, why doesn't gcc optimize this :( */
-#endif
/* Never answer to SYNs send to broadcast or multicast */
if (skb_rtable(skb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
@@ -1250,14 +1270,9 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
* evidently real one.
*/
if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
- if (net_ratelimit())
- syn_flood_warning(skb);
-#ifdef CONFIG_SYN_COOKIES
- if (sysctl_tcp_syncookies) {
- want_cookie = 1;
- } else
-#endif
- goto drop;
+ want_cookie = tcp_syn_flood_action(sk, skb, "TCP");
+ if (!want_cookie)
+ goto drop;
}
/* Accept backlog is full. If we have already queued enough
@@ -1303,9 +1318,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
while (l-- > 0)
*c++ ^= *hash_location++;
-#ifdef CONFIG_SYN_COOKIES
want_cookie = 0; /* not our kind of cookie */
-#endif
tmp_ext.cookie_out_never = 0; /* false */
tmp_ext.cookie_plus = tmp_opt.cookie_plus;
} else if (!tp->rx_opt.cookie_in_always) {
@@ -1578,7 +1591,7 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
#endif
if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
- sock_rps_save_rxhash(sk, skb->rxhash);
+ sock_rps_save_rxhash(sk, skb);
if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) {
rsk = sk;
goto reset;
@@ -1595,7 +1608,7 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
goto discard;
if (nsk != sk) {
- sock_rps_save_rxhash(nsk, skb->rxhash);
+ sock_rps_save_rxhash(nsk, skb);
if (tcp_child_process(sk, nsk, skb)) {
rsk = nsk;
goto reset;
@@ -1603,7 +1616,7 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
return 0;
}
} else
- sock_rps_save_rxhash(sk, skb->rxhash);
+ sock_rps_save_rxhash(sk, skb);
if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len)) {
rsk = sk;
@@ -1635,7 +1648,7 @@ EXPORT_SYMBOL(tcp_v4_do_rcv);
int tcp_v4_rcv(struct sk_buff *skb)
{
const struct iphdr *iph;
- struct tcphdr *th;
+ const struct tcphdr *th;
struct sock *sk;
int ret;
struct net *net = dev_net(skb->dev);
@@ -1670,7 +1683,7 @@ int tcp_v4_rcv(struct sk_buff *skb)
skb->len - th->doff * 4);
TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
TCP_SKB_CB(skb)->when = 0;
- TCP_SKB_CB(skb)->flags = iph->tos;
+ TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph);
TCP_SKB_CB(skb)->sacked = 0;
sk = __inet_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
@@ -1799,7 +1812,7 @@ EXPORT_SYMBOL(tcp_v4_get_peer);
void *tcp_v4_tw_get_peer(struct sock *sk)
{
- struct inet_timewait_sock *tw = inet_twsk(sk);
+ const struct inet_timewait_sock *tw = inet_twsk(sk);
return inet_getpeer_v4(tw->tw_daddr, 1);
}
@@ -2371,7 +2384,7 @@ void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo)
}
EXPORT_SYMBOL(tcp_proc_unregister);
-static void get_openreq4(struct sock *sk, struct request_sock *req,
+static void get_openreq4(const struct sock *sk, const struct request_sock *req,
struct seq_file *f, int i, int uid, int *len)
{
const struct inet_request_sock *ireq = inet_rsk(req);
@@ -2401,9 +2414,9 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
{
int timer_active;
unsigned long timer_expires;
- struct tcp_sock *tp = tcp_sk(sk);
+ const struct tcp_sock *tp = tcp_sk(sk);
const struct inet_connection_sock *icsk = inet_csk(sk);
- struct inet_sock *inet = inet_sk(sk);
+ const struct inet_sock *inet = inet_sk(sk);
__be32 dest = inet->inet_daddr;
__be32 src = inet->inet_rcv_saddr;
__u16 destp = ntohs(inet->inet_dport);
@@ -2452,7 +2465,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
len);
}
-static void get_timewait4_sock(struct inet_timewait_sock *tw,
+static void get_timewait4_sock(const struct inet_timewait_sock *tw,
struct seq_file *f, int i, int *len)
{
__be32 dest, src;
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index d2fe4e06b472..85a2fbebd7ef 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -141,7 +141,7 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
const struct tcphdr *th)
{
struct tcp_options_received tmp_opt;
- u8 *hash_location;
+ const u8 *hash_location;
struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
int paws_reject = 0;
@@ -328,6 +328,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1);
+ tw->tw_transparent = inet_sk(sk)->transparent;
tw->tw_rcv_wscale = tp->rx_opt.rcv_wscale;
tcptw->tw_rcv_nxt = tp->rcv_nxt;
tcptw->tw_snd_nxt = tp->snd_nxt;
@@ -566,7 +567,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
struct request_sock **prev)
{
struct tcp_options_received tmp_opt;
- u8 *hash_location;
+ const u8 *hash_location;
struct sock *child;
const struct tcphdr *th = tcp_hdr(skb);
__be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK);
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 882e0b0964d0..980b98f6288c 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -65,7 +65,7 @@ EXPORT_SYMBOL_GPL(sysctl_tcp_cookie_size);
/* Account for new data that has been sent to the network. */
-static void tcp_event_new_data_sent(struct sock *sk, struct sk_buff *skb)
+static void tcp_event_new_data_sent(struct sock *sk, const struct sk_buff *skb)
{
struct tcp_sock *tp = tcp_sk(sk);
unsigned int prior_packets = tp->packets_out;
@@ -89,9 +89,9 @@ static void tcp_event_new_data_sent(struct sock *sk, struct sk_buff *skb)
* Anything in between SND.UNA...SND.UNA+SND.WND also can be already
* invalid. OK, let's make this for now:
*/
-static inline __u32 tcp_acceptable_seq(struct sock *sk)
+static inline __u32 tcp_acceptable_seq(const struct sock *sk)
{
- struct tcp_sock *tp = tcp_sk(sk);
+ const struct tcp_sock *tp = tcp_sk(sk);
if (!before(tcp_wnd_end(tp), tp->snd_nxt))
return tp->snd_nxt;
@@ -116,7 +116,7 @@ static inline __u32 tcp_acceptable_seq(struct sock *sk)
static __u16 tcp_advertise_mss(struct sock *sk)
{
struct tcp_sock *tp = tcp_sk(sk);
- struct dst_entry *dst = __sk_dst_get(sk);
+ const struct dst_entry *dst = __sk_dst_get(sk);
int mss = tp->advmss;
if (dst) {
@@ -133,7 +133,7 @@ static __u16 tcp_advertise_mss(struct sock *sk)
/* RFC2861. Reset CWND after idle period longer RTO to "restart window".
* This is the first part of cwnd validation mechanism. */
-static void tcp_cwnd_restart(struct sock *sk, struct dst_entry *dst)
+static void tcp_cwnd_restart(struct sock *sk, const struct dst_entry *dst)
{
struct tcp_sock *tp = tcp_sk(sk);
s32 delta = tcp_time_stamp - tp->lsndtime;
@@ -154,7 +154,7 @@ static void tcp_cwnd_restart(struct sock *sk, struct dst_entry *dst)
/* Congestion state accounting after a packet has been sent. */
static void tcp_event_data_sent(struct tcp_sock *tp,
- struct sk_buff *skb, struct sock *sk)
+ struct sock *sk)
{
struct inet_connection_sock *icsk = inet_csk(sk);
const u32 now = tcp_time_stamp;
@@ -295,11 +295,11 @@ static u16 tcp_select_window(struct sock *sk)
}
/* Packet ECN state for a SYN-ACK */
-static inline void TCP_ECN_send_synack(struct tcp_sock *tp, struct sk_buff *skb)
+static inline void TCP_ECN_send_synack(const struct tcp_sock *tp, struct sk_buff *skb)
{
- TCP_SKB_CB(skb)->flags &= ~TCPHDR_CWR;
+ TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_CWR;
if (!(tp->ecn_flags & TCP_ECN_OK))
- TCP_SKB_CB(skb)->flags &= ~TCPHDR_ECE;
+ TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_ECE;
}
/* Packet ECN state for a SYN. */
@@ -309,13 +309,13 @@ static inline void TCP_ECN_send_syn(struct sock *sk, struct sk_buff *skb)
tp->ecn_flags = 0;
if (sysctl_tcp_ecn == 1) {
- TCP_SKB_CB(skb)->flags |= TCPHDR_ECE | TCPHDR_CWR;
+ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_ECE | TCPHDR_CWR;
tp->ecn_flags = TCP_ECN_OK;
}
}
static __inline__ void
-TCP_ECN_make_synack(struct request_sock *req, struct tcphdr *th)
+TCP_ECN_make_synack(const struct request_sock *req, struct tcphdr *th)
{
if (inet_rsk(req)->ecn_ok)
th->ece = 1;
@@ -356,7 +356,7 @@ static void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags)
skb->ip_summed = CHECKSUM_PARTIAL;
skb->csum = 0;
- TCP_SKB_CB(skb)->flags = flags;
+ TCP_SKB_CB(skb)->tcp_flags = flags;
TCP_SKB_CB(skb)->sacked = 0;
skb_shinfo(skb)->gso_segs = 1;
@@ -565,7 +565,8 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
*/
static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb,
struct tcp_out_options *opts,
- struct tcp_md5sig_key **md5) {
+ struct tcp_md5sig_key **md5)
+{
struct tcp_sock *tp = tcp_sk(sk);
struct tcp_cookie_values *cvp = tp->cookie_values;
unsigned remaining = MAX_TCP_OPTION_SPACE;
@@ -743,7 +744,8 @@ static unsigned tcp_synack_options(struct sock *sk,
*/
static unsigned tcp_established_options(struct sock *sk, struct sk_buff *skb,
struct tcp_out_options *opts,
- struct tcp_md5sig_key **md5) {
+ struct tcp_md5sig_key **md5)
+{
struct tcp_skb_cb *tcb = skb ? TCP_SKB_CB(skb) : NULL;
struct tcp_sock *tp = tcp_sk(sk);
unsigned size = 0;
@@ -826,7 +828,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
tcb = TCP_SKB_CB(skb);
memset(&opts, 0, sizeof(opts));
- if (unlikely(tcb->flags & TCPHDR_SYN))
+ if (unlikely(tcb->tcp_flags & TCPHDR_SYN))
tcp_options_size = tcp_syn_options(sk, skb, &opts, &md5);
else
tcp_options_size = tcp_established_options(sk, skb, &opts,
@@ -850,9 +852,9 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
th->seq = htonl(tcb->seq);
th->ack_seq = htonl(tp->rcv_nxt);
*(((__be16 *)th) + 6) = htons(((tcp_header_size >> 2) << 12) |
- tcb->flags);
+ tcb->tcp_flags);
- if (unlikely(tcb->flags & TCPHDR_SYN)) {
+ if (unlikely(tcb->tcp_flags & TCPHDR_SYN)) {
/* RFC1323: The window in SYN & SYN/ACK segments
* is never scaled.
*/
@@ -875,7 +877,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
}
tcp_options_write((__be32 *)(th + 1), tp, &opts);
- if (likely((tcb->flags & TCPHDR_SYN) == 0))
+ if (likely((tcb->tcp_flags & TCPHDR_SYN) == 0))
TCP_ECN_send(sk, skb, tcp_header_size);
#ifdef CONFIG_TCP_MD5SIG
@@ -889,11 +891,11 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
icsk->icsk_af_ops->send_check(sk, skb);
- if (likely(tcb->flags & TCPHDR_ACK))
+ if (likely(tcb->tcp_flags & TCPHDR_ACK))
tcp_event_ack_sent(sk, tcp_skb_pcount(skb));
if (skb->len != tcp_header_size)
- tcp_event_data_sent(tp, skb, sk);
+ tcp_event_data_sent(tp, sk);
if (after(tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq)
TCP_ADD_STATS(sock_net(sk), TCP_MIB_OUTSEGS,
@@ -926,7 +928,7 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb)
}
/* Initialize TSO segments for a packet. */
-static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb,
+static void tcp_set_skb_tso_segs(const struct sock *sk, struct sk_buff *skb,
unsigned int mss_now)
{
if (skb->len <= mss_now || !sk_can_gso(sk) ||
@@ -947,7 +949,7 @@ static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb,
/* When a modification to fackets out becomes necessary, we need to check
* skb is counted to fackets_out or not.
*/
-static void tcp_adjust_fackets_out(struct sock *sk, struct sk_buff *skb,
+static void tcp_adjust_fackets_out(struct sock *sk, const struct sk_buff *skb,
int decr)
{
struct tcp_sock *tp = tcp_sk(sk);
@@ -962,7 +964,7 @@ static void tcp_adjust_fackets_out(struct sock *sk, struct sk_buff *skb,
/* Pcount in the middle of the write queue got changed, we need to do various
* tweaks to fix counters
*/
-static void tcp_adjust_pcount(struct sock *sk, struct sk_buff *skb, int decr)
+static void tcp_adjust_pcount(struct sock *sk, const struct sk_buff *skb, int decr)
{
struct tcp_sock *tp = tcp_sk(sk);
@@ -1032,9 +1034,9 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len,
TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(buff)->seq;
/* PSH and FIN should only be set in the second packet. */
- flags = TCP_SKB_CB(skb)->flags;
- TCP_SKB_CB(skb)->flags = flags & ~(TCPHDR_FIN | TCPHDR_PSH);
- TCP_SKB_CB(buff)->flags = flags;
+ flags = TCP_SKB_CB(skb)->tcp_flags;
+ TCP_SKB_CB(skb)->tcp_flags = flags & ~(TCPHDR_FIN | TCPHDR_PSH);
+ TCP_SKB_CB(buff)->tcp_flags = flags;
TCP_SKB_CB(buff)->sacked = TCP_SKB_CB(skb)->sacked;
if (!skb_shinfo(skb)->nr_frags && skb->ip_summed != CHECKSUM_PARTIAL) {
@@ -1094,14 +1096,16 @@ static void __pskb_trim_head(struct sk_buff *skb, int len)
eat = len;
k = 0;
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- if (skb_shinfo(skb)->frags[i].size <= eat) {
- put_page(skb_shinfo(skb)->frags[i].page);
- eat -= skb_shinfo(skb)->frags[i].size;
+ int size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
+
+ if (size <= eat) {
+ skb_frag_unref(skb, i);
+ eat -= size;
} else {
skb_shinfo(skb)->frags[k] = skb_shinfo(skb)->frags[i];
if (eat) {
skb_shinfo(skb)->frags[k].page_offset += eat;
- skb_shinfo(skb)->frags[k].size -= eat;
+ skb_frag_size_sub(&skb_shinfo(skb)->frags[k], eat);
eat = 0;
}
k++;
@@ -1144,10 +1148,10 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len)
}
/* Calculate MSS. Not accounting for SACKs here. */
-int tcp_mtu_to_mss(struct sock *sk, int pmtu)
+int tcp_mtu_to_mss(const struct sock *sk, int pmtu)
{
- struct tcp_sock *tp = tcp_sk(sk);
- struct inet_connection_sock *icsk = inet_csk(sk);
+ const struct tcp_sock *tp = tcp_sk(sk);
+ const struct inet_connection_sock *icsk = inet_csk(sk);
int mss_now;
/* Calculate base mss without TCP options:
@@ -1173,10 +1177,10 @@ int tcp_mtu_to_mss(struct sock *sk, int pmtu)
}
/* Inverse of above */
-int tcp_mss_to_mtu(struct sock *sk, int mss)
+int tcp_mss_to_mtu(const struct sock *sk, int mss)
{
- struct tcp_sock *tp = tcp_sk(sk);
- struct inet_connection_sock *icsk = inet_csk(sk);
+ const struct tcp_sock *tp = tcp_sk(sk);
+ const struct inet_connection_sock *icsk = inet_csk(sk);
int mtu;
mtu = mss +
@@ -1250,8 +1254,8 @@ EXPORT_SYMBOL(tcp_sync_mss);
*/
unsigned int tcp_current_mss(struct sock *sk)
{
- struct tcp_sock *tp = tcp_sk(sk);
- struct dst_entry *dst = __sk_dst_get(sk);
+ const struct tcp_sock *tp = tcp_sk(sk);
+ const struct dst_entry *dst = __sk_dst_get(sk);
u32 mss_now;
unsigned header_len;
struct tcp_out_options opts;
@@ -1311,10 +1315,10 @@ static void tcp_cwnd_validate(struct sock *sk)
* modulo only when the receiver window alone is the limiting factor or
* when we would be allowed to send the split-due-to-Nagle skb fully.
*/
-static unsigned int tcp_mss_split_point(struct sock *sk, struct sk_buff *skb,
+static unsigned int tcp_mss_split_point(const struct sock *sk, const struct sk_buff *skb,
unsigned int mss_now, unsigned int cwnd)
{
- struct tcp_sock *tp = tcp_sk(sk);
+ const struct tcp_sock *tp = tcp_sk(sk);
u32 needed, window, cwnd_len;
window = tcp_wnd_end(tp) - TCP_SKB_CB(skb)->seq;
@@ -1334,13 +1338,14 @@ static unsigned int tcp_mss_split_point(struct sock *sk, struct sk_buff *skb,
/* Can at least one segment of SKB be sent right now, according to the
* congestion window rules? If so, return how many segments are allowed.
*/
-static inline unsigned int tcp_cwnd_test(struct tcp_sock *tp,
- struct sk_buff *skb)
+static inline unsigned int tcp_cwnd_test(const struct tcp_sock *tp,
+ const struct sk_buff *skb)
{
u32 in_flight, cwnd;
/* Don't be strict about the congestion window for the final FIN. */
- if ((TCP_SKB_CB(skb)->flags & TCPHDR_FIN) && tcp_skb_pcount(skb) == 1)
+ if ((TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) &&
+ tcp_skb_pcount(skb) == 1)
return 1;
in_flight = tcp_packets_in_flight(tp);
@@ -1355,7 +1360,7 @@ static inline unsigned int tcp_cwnd_test(struct tcp_sock *tp,
* This must be invoked the first time we consider transmitting
* SKB onto the wire.
*/
-static int tcp_init_tso_segs(struct sock *sk, struct sk_buff *skb,
+static int tcp_init_tso_segs(const struct sock *sk, struct sk_buff *skb,
unsigned int mss_now)
{
int tso_segs = tcp_skb_pcount(skb);
@@ -1393,7 +1398,7 @@ static inline int tcp_nagle_check(const struct tcp_sock *tp,
/* Return non-zero if the Nagle test allows this packet to be
* sent now.
*/
-static inline int tcp_nagle_test(struct tcp_sock *tp, struct sk_buff *skb,
+static inline int tcp_nagle_test(const struct tcp_sock *tp, const struct sk_buff *skb,
unsigned int cur_mss, int nonagle)
{
/* Nagle rule does not apply to frames, which sit in the middle of the
@@ -1409,7 +1414,7 @@ static inline int tcp_nagle_test(struct tcp_sock *tp, struct sk_buff *skb,
* Nagle can be ignored during F-RTO too (see RFC4138).
*/
if (tcp_urg_mode(tp) || (tp->frto_counter == 2) ||
- (TCP_SKB_CB(skb)->flags & TCPHDR_FIN))
+ (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN))
return 1;
if (!tcp_nagle_check(tp, skb, cur_mss, nonagle))
@@ -1419,7 +1424,7 @@ static inline int tcp_nagle_test(struct tcp_sock *tp, struct sk_buff *skb,
}
/* Does at least the first segment of SKB fit into the send window? */
-static inline int tcp_snd_wnd_test(struct tcp_sock *tp, struct sk_buff *skb,
+static inline int tcp_snd_wnd_test(const struct tcp_sock *tp, const struct sk_buff *skb,
unsigned int cur_mss)
{
u32 end_seq = TCP_SKB_CB(skb)->end_seq;
@@ -1434,10 +1439,10 @@ static inline int tcp_snd_wnd_test(struct tcp_sock *tp, struct sk_buff *skb,
* should be put on the wire right now. If so, it returns the number of
* packets allowed by the congestion window.
*/
-static unsigned int tcp_snd_test(struct sock *sk, struct sk_buff *skb,
+static unsigned int tcp_snd_test(const struct sock *sk, struct sk_buff *skb,
unsigned int cur_mss, int nonagle)
{
- struct tcp_sock *tp = tcp_sk(sk);
+ const struct tcp_sock *tp = tcp_sk(sk);
unsigned int cwnd_quota;
tcp_init_tso_segs(sk, skb, cur_mss);
@@ -1455,7 +1460,7 @@ static unsigned int tcp_snd_test(struct sock *sk, struct sk_buff *skb,
/* Test if sending is allowed right now. */
int tcp_may_send_now(struct sock *sk)
{
- struct tcp_sock *tp = tcp_sk(sk);
+ const struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb = tcp_send_head(sk);
return skb &&
@@ -1497,9 +1502,9 @@ static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len,
TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(buff)->seq;
/* PSH and FIN should only be set in the second packet. */
- flags = TCP_SKB_CB(skb)->flags;
- TCP_SKB_CB(skb)->flags = flags & ~(TCPHDR_FIN | TCPHDR_PSH);
- TCP_SKB_CB(buff)->flags = flags;
+ flags = TCP_SKB_CB(skb)->tcp_flags;
+ TCP_SKB_CB(skb)->tcp_flags = flags & ~(TCPHDR_FIN | TCPHDR_PSH);
+ TCP_SKB_CB(buff)->tcp_flags = flags;
/* This packet was never sent out yet, so no SACK bits. */
TCP_SKB_CB(buff)->sacked = 0;
@@ -1530,7 +1535,7 @@ static int tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb)
u32 send_win, cong_win, limit, in_flight;
int win_divisor;
- if (TCP_SKB_CB(skb)->flags & TCPHDR_FIN)
+ if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)
goto send_now;
if (icsk->icsk_ca_state != TCP_CA_Open)
@@ -1657,7 +1662,7 @@ static int tcp_mtu_probe(struct sock *sk)
TCP_SKB_CB(nskb)->seq = TCP_SKB_CB(skb)->seq;
TCP_SKB_CB(nskb)->end_seq = TCP_SKB_CB(skb)->seq + probe_size;
- TCP_SKB_CB(nskb)->flags = TCPHDR_ACK;
+ TCP_SKB_CB(nskb)->tcp_flags = TCPHDR_ACK;
TCP_SKB_CB(nskb)->sacked = 0;
nskb->csum = 0;
nskb->ip_summed = skb->ip_summed;
@@ -1677,11 +1682,11 @@ static int tcp_mtu_probe(struct sock *sk)
if (skb->len <= copy) {
/* We've eaten all the data from this skb.
* Throw it away. */
- TCP_SKB_CB(nskb)->flags |= TCP_SKB_CB(skb)->flags;
+ TCP_SKB_CB(nskb)->tcp_flags |= TCP_SKB_CB(skb)->tcp_flags;
tcp_unlink_write_queue(skb, sk);
sk_wmem_free_skb(sk, skb);
} else {
- TCP_SKB_CB(nskb)->flags |= TCP_SKB_CB(skb)->flags &
+ TCP_SKB_CB(nskb)->tcp_flags |= TCP_SKB_CB(skb)->tcp_flags &
~(TCPHDR_FIN|TCPHDR_PSH);
if (!skb_shinfo(skb)->nr_frags) {
skb_pull(skb, copy);
@@ -1796,11 +1801,13 @@ static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
tcp_event_new_data_sent(sk, skb);
tcp_minshall_update(tp, mss_now, skb);
- sent_pkts++;
+ sent_pkts += tcp_skb_pcount(skb);
if (push_one)
break;
}
+ if (inet_csk(sk)->icsk_ca_state == TCP_CA_Recovery)
+ tp->prr_out += sent_pkts;
if (likely(sent_pkts)) {
tcp_cwnd_validate(sk);
@@ -1985,7 +1992,7 @@ static void tcp_collapse_retrans(struct sock *sk, struct sk_buff *skb)
TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(next_skb)->end_seq;
/* Merge over control information. This moves PSH/FIN etc. over */
- TCP_SKB_CB(skb)->flags |= TCP_SKB_CB(next_skb)->flags;
+ TCP_SKB_CB(skb)->tcp_flags |= TCP_SKB_CB(next_skb)->tcp_flags;
/* All done, get rid of second SKB and account for it so
* packet counting does not break.
@@ -2003,7 +2010,7 @@ static void tcp_collapse_retrans(struct sock *sk, struct sk_buff *skb)
}
/* Check if coalescing SKBs is legal. */
-static int tcp_can_collapse(struct sock *sk, struct sk_buff *skb)
+static int tcp_can_collapse(const struct sock *sk, const struct sk_buff *skb)
{
if (tcp_skb_pcount(skb) > 1)
return 0;
@@ -2033,7 +2040,7 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *to,
if (!sysctl_tcp_retrans_collapse)
return;
- if (TCP_SKB_CB(skb)->flags & TCPHDR_SYN)
+ if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN)
return;
tcp_for_write_queue_from_safe(skb, tmp, sk) {
@@ -2125,12 +2132,12 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
* since it is cheap to do so and saves bytes on the network.
*/
if (skb->len > 0 &&
- (TCP_SKB_CB(skb)->flags & TCPHDR_FIN) &&
+ (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) &&
tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) {
if (!pskb_trim(skb, 0)) {
/* Reuse, even though it does some unnecessary work */
tcp_init_nondata_skb(skb, TCP_SKB_CB(skb)->end_seq - 1,
- TCP_SKB_CB(skb)->flags);
+ TCP_SKB_CB(skb)->tcp_flags);
skb->ip_summed = CHECKSUM_NONE;
}
}
@@ -2179,7 +2186,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
static int tcp_can_forward_retransmit(struct sock *sk)
{
const struct inet_connection_sock *icsk = inet_csk(sk);
- struct tcp_sock *tp = tcp_sk(sk);
+ const struct tcp_sock *tp = tcp_sk(sk);
/* Forward retransmissions are possible only during Recovery. */
if (icsk->icsk_ca_state != TCP_CA_Recovery)
@@ -2294,6 +2301,9 @@ begin_fwd:
return;
NET_INC_STATS_BH(sock_net(sk), mib_idx);
+ if (inet_csk(sk)->icsk_ca_state == TCP_CA_Recovery)
+ tp->prr_out += tcp_skb_pcount(skb);
+
if (skb == tcp_write_queue_head(sk))
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
inet_csk(sk)->icsk_rto,
@@ -2317,7 +2327,7 @@ void tcp_send_fin(struct sock *sk)
mss_now = tcp_current_mss(sk);
if (tcp_send_head(sk) != NULL) {
- TCP_SKB_CB(skb)->flags |= TCPHDR_FIN;
+ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_FIN;
TCP_SKB_CB(skb)->end_seq++;
tp->write_seq++;
} else {
@@ -2379,11 +2389,11 @@ int tcp_send_synack(struct sock *sk)
struct sk_buff *skb;
skb = tcp_write_queue_head(sk);
- if (skb == NULL || !(TCP_SKB_CB(skb)->flags & TCPHDR_SYN)) {
+ if (skb == NULL || !(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN)) {
printk(KERN_DEBUG "tcp_send_synack: wrong queue state\n");
return -EFAULT;
}
- if (!(TCP_SKB_CB(skb)->flags & TCPHDR_ACK)) {
+ if (!(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_ACK)) {
if (skb_cloned(skb)) {
struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC);
if (nskb == NULL)
@@ -2397,7 +2407,7 @@ int tcp_send_synack(struct sock *sk)
skb = nskb;
}
- TCP_SKB_CB(skb)->flags |= TCPHDR_ACK;
+ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_ACK;
TCP_ECN_send_synack(tcp_sk(sk), skb);
}
TCP_SKB_CB(skb)->when = tcp_time_stamp;
@@ -2542,7 +2552,7 @@ EXPORT_SYMBOL(tcp_make_synack);
/* Do all connect socket setups that can be done AF independent. */
static void tcp_connect_init(struct sock *sk)
{
- struct dst_entry *dst = __sk_dst_get(sk);
+ const struct dst_entry *dst = __sk_dst_get(sk);
struct tcp_sock *tp = tcp_sk(sk);
__u8 rcv_wscale;
@@ -2794,13 +2804,13 @@ int tcp_write_wakeup(struct sock *sk)
if (seg_size < TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq ||
skb->len > mss) {
seg_size = min(seg_size, mss);
- TCP_SKB_CB(skb)->flags |= TCPHDR_PSH;
+ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_PSH;
if (tcp_fragment(sk, skb, seg_size, mss))
return -1;
} else if (!tcp_skb_pcount(skb))
tcp_set_skb_tso_segs(sk, skb, mss);
- TCP_SKB_CB(skb)->flags |= TCPHDR_PSH;
+ TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_PSH;
TCP_SKB_CB(skb)->when = tcp_time_stamp;
err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
if (!err)
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index ecd44b0c45f1..2e0f0af76c19 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -334,7 +334,6 @@ void tcp_retransmit_timer(struct sock *sk)
* connection. If the socket is an orphan, time it out,
* we cannot allow such beasts to hang infinitely.
*/
-#ifdef TCP_DEBUG
struct inet_sock *inet = inet_sk(sk);
if (sk->sk_family == AF_INET) {
LIMIT_NETDEBUG(KERN_DEBUG "TCP: Peer %pI4:%u/%u unexpectedly shrunk window %u:%u (repaired)\n",
@@ -349,7 +348,6 @@ void tcp_retransmit_timer(struct sock *sk)
inet->inet_num, tp->snd_una, tp->snd_nxt);
}
#endif
-#endif
if (tcp_time_stamp - tp->rcv_tstamp > TCP_RTO_MAX) {
tcp_write_err(sk);
goto out;
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 1b5a19340a95..ebaa96bd3464 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1267,7 +1267,7 @@ int udp_disconnect(struct sock *sk, int flags)
sk->sk_state = TCP_CLOSE;
inet->inet_daddr = 0;
inet->inet_dport = 0;
- sock_rps_save_rxhash(sk, 0);
+ sock_rps_reset_rxhash(sk);
sk->sk_bound_dev_if = 0;
if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK))
inet_reset_saddr(sk);
@@ -1355,7 +1355,7 @@ static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
int rc;
if (inet_sk(sk)->inet_daddr)
- sock_rps_save_rxhash(sk, skb->rxhash);
+ sock_rps_save_rxhash(sk, skb);
rc = ip_queue_rcv_skb(sk, skb);
if (rc < 0) {
@@ -1461,10 +1461,9 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
}
}
- if (rcu_dereference_raw(sk->sk_filter)) {
- if (udp_lib_checksum_complete(skb))
- goto drop;
- }
+ if (rcu_access_pointer(sk->sk_filter) &&
+ udp_lib_checksum_complete(skb))
+ goto drop;
if (sk_rcvqueues_full(sk, skb))
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index fc5368ad2b0d..a0b4c5da8d43 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -79,13 +79,13 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
struct rtable *rt = (struct rtable *)xdst->route;
const struct flowi4 *fl4 = &fl->u.ip4;
- rt->rt_key_dst = fl4->daddr;
- rt->rt_key_src = fl4->saddr;
- rt->rt_key_tos = fl4->flowi4_tos;
- rt->rt_route_iif = fl4->flowi4_iif;
- rt->rt_iif = fl4->flowi4_iif;
- rt->rt_oif = fl4->flowi4_oif;
- rt->rt_mark = fl4->flowi4_mark;
+ xdst->u.rt.rt_key_dst = fl4->daddr;
+ xdst->u.rt.rt_key_src = fl4->saddr;
+ xdst->u.rt.rt_key_tos = fl4->flowi4_tos;
+ xdst->u.rt.rt_route_iif = fl4->flowi4_iif;
+ xdst->u.rt.rt_iif = fl4->flowi4_iif;
+ xdst->u.rt.rt_oif = fl4->flowi4_oif;
+ xdst->u.rt.rt_mark = fl4->flowi4_mark;
xdst->u.dst.dev = dev;
dev_hold(dev);
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index f012ebd87b43..e39239e6426e 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -374,8 +374,8 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
"%s(): cannot allocate memory for statistics; dev=%s.\n",
__func__, dev->name));
neigh_parms_release(&nd_tbl, ndev->nd_parms);
- ndev->dead = 1;
- in6_dev_finish_destroy(ndev);
+ dev_put(dev);
+ kfree(ndev);
return NULL;
}
@@ -428,7 +428,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
ndev->tstamp = jiffies;
addrconf_sysctl_register(ndev);
/* protected by rtnl_lock */
- rcu_assign_pointer(dev->ip6_ptr, ndev);
+ RCU_INIT_POINTER(dev->ip6_ptr, ndev);
/* Join all-node multicast group */
ipv6_dev_mc_inc(dev, &in6addr_linklocal_allnodes);
@@ -824,12 +824,13 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i
{
struct inet6_dev *idev = ifp->idev;
struct in6_addr addr, *tmpaddr;
- unsigned long tmp_prefered_lft, tmp_valid_lft, tmp_cstamp, tmp_tstamp, age;
+ unsigned long tmp_prefered_lft, tmp_valid_lft, tmp_tstamp, age;
unsigned long regen_advance;
int tmp_plen;
int ret = 0;
int max_addresses;
u32 addr_flags;
+ unsigned long now = jiffies;
write_lock(&idev->lock);
if (ift) {
@@ -874,7 +875,7 @@ retry:
goto out;
}
memcpy(&addr.s6_addr[8], idev->rndid, 8);
- age = (jiffies - ifp->tstamp) / HZ;
+ age = (now - ifp->tstamp) / HZ;
tmp_valid_lft = min_t(__u32,
ifp->valid_lft,
idev->cnf.temp_valid_lft + age);
@@ -884,7 +885,6 @@ retry:
idev->cnf.max_desync_factor);
tmp_plen = ifp->prefix_len;
max_addresses = idev->cnf.max_addresses;
- tmp_cstamp = ifp->cstamp;
tmp_tstamp = ifp->tstamp;
spin_unlock_bh(&ifp->lock);
@@ -929,7 +929,7 @@ retry:
ift->ifpub = ifp;
ift->valid_lft = tmp_valid_lft;
ift->prefered_lft = tmp_prefered_lft;
- ift->cstamp = tmp_cstamp;
+ ift->cstamp = now;
ift->tstamp = tmp_tstamp;
spin_unlock_bh(&ift->lock);
@@ -1999,25 +1999,50 @@ ok:
#ifdef CONFIG_IPV6_PRIVACY
read_lock_bh(&in6_dev->lock);
/* update all temporary addresses in the list */
- list_for_each_entry(ift, &in6_dev->tempaddr_list, tmp_list) {
- /*
- * When adjusting the lifetimes of an existing
- * temporary address, only lower the lifetimes.
- * Implementations must not increase the
- * lifetimes of an existing temporary address
- * when processing a Prefix Information Option.
- */
+ list_for_each_entry(ift, &in6_dev->tempaddr_list,
+ tmp_list) {
+ int age, max_valid, max_prefered;
+
if (ifp != ift->ifpub)
continue;
+ /*
+ * RFC 4941 section 3.3:
+ * If a received option will extend the lifetime
+ * of a public address, the lifetimes of
+ * temporary addresses should be extended,
+ * subject to the overall constraint that no
+ * temporary addresses should ever remain
+ * "valid" or "preferred" for a time longer than
+ * (TEMP_VALID_LIFETIME) or
+ * (TEMP_PREFERRED_LIFETIME - DESYNC_FACTOR),
+ * respectively.
+ */
+ age = (now - ift->cstamp) / HZ;
+ max_valid = in6_dev->cnf.temp_valid_lft - age;
+ if (max_valid < 0)
+ max_valid = 0;
+
+ max_prefered = in6_dev->cnf.temp_prefered_lft -
+ in6_dev->cnf.max_desync_factor -
+ age;
+ if (max_prefered < 0)
+ max_prefered = 0;
+
+ if (valid_lft > max_valid)
+ valid_lft = max_valid;
+
+ if (prefered_lft > max_prefered)
+ prefered_lft = max_prefered;
+
spin_lock(&ift->lock);
flags = ift->flags;
- if (ift->valid_lft > valid_lft &&
- ift->valid_lft - valid_lft > (jiffies - ift->tstamp) / HZ)
- ift->valid_lft = valid_lft + (jiffies - ift->tstamp) / HZ;
- if (ift->prefered_lft > prefered_lft &&
- ift->prefered_lft - prefered_lft > (jiffies - ift->tstamp) / HZ)
- ift->prefered_lft = prefered_lft + (jiffies - ift->tstamp) / HZ;
+ ift->valid_lft = valid_lft;
+ ift->prefered_lft = prefered_lft;
+ ift->tstamp = now;
+ if (prefered_lft > 0)
+ ift->flags &= ~IFA_F_DEPRECATED;
+
spin_unlock(&ift->lock);
if (!(flags&IFA_F_TENTATIVE))
ipv6_ifa_notify(0, ift);
@@ -2025,9 +2050,11 @@ ok:
if ((create || list_empty(&in6_dev->tempaddr_list)) && in6_dev->cnf.use_tempaddr > 0) {
/*
- * When a new public address is created as described in [ADDRCONF],
- * also create a new temporary address. Also create a temporary
- * address if it's enabled but no temporary address currently exists.
+ * When a new public address is created as
+ * described in [ADDRCONF], also create a new
+ * temporary address. Also create a temporary
+ * address if it's enabled but no temporary
+ * address currently exists.
*/
read_unlock_bh(&in6_dev->lock);
ipv6_create_tempaddr(ifp, NULL);
@@ -2706,7 +2733,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
idev->dead = 1;
/* protected by rtnl_lock */
- rcu_assign_pointer(dev->ip6_ptr, NULL);
+ RCU_INIT_POINTER(dev->ip6_ptr, NULL);
/* Step 1.5: remove snmp6 entry */
snmp6_unregister_dev(idev);
@@ -2969,12 +2996,12 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
ipv6_ifa_notify(RTM_NEWADDR, ifp);
- /* If added prefix is link local and forwarding is off,
- start sending router solicitations.
+ /* If added prefix is link local and we are prepared to process
+ router advertisements, start sending router solicitations.
*/
- if ((ifp->idev->cnf.forwarding == 0 ||
- ifp->idev->cnf.forwarding == 2) &&
+ if (((ifp->idev->cnf.accept_ra == 1 && !ifp->idev->cnf.forwarding) ||
+ ifp->idev->cnf.accept_ra == 2) &&
ifp->idev->cnf.rtr_solicits > 0 &&
(dev->flags&IFF_LOOPBACK) == 0 &&
(ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) {
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 3b5669a2582d..d27c797f9f05 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -875,6 +875,7 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
skb_reset_transport_header(skb);
__skb_push(skb, skb_gro_offset(skb));
+ ops = rcu_dereference(inet6_protos[proto]);
if (!ops || !ops->gro_receive)
goto out_unlock;
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 9ef1831746ef..e2480691c220 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -297,10 +297,6 @@ void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu)
ipv6_addr_copy(&iph->daddr, &fl6->daddr);
mtu_info = IP6CBMTU(skb);
- if (!mtu_info) {
- kfree_skb(skb);
- return;
- }
mtu_info->ip6m_mtu = mtu;
mtu_info->ip6m_addr.sin6_family = AF_INET6;
@@ -599,7 +595,7 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
return 0;
}
-int datagram_send_ctl(struct net *net,
+int datagram_send_ctl(struct net *net, struct sock *sk,
struct msghdr *msg, struct flowi6 *fl6,
struct ipv6_txoptions *opt,
int *hlimit, int *tclass, int *dontfrag)
@@ -658,7 +654,8 @@ int datagram_send_ctl(struct net *net,
if (addr_type != IPV6_ADDR_ANY) {
int strict = __ipv6_addr_src_scope(addr_type) <= IPV6_ADDR_SCOPE_LINKLOCAL;
- if (!ipv6_chk_addr(net, &src_info->ipi6_addr,
+ if (!inet_sk(sk)->transparent &&
+ !ipv6_chk_addr(net, &src_info->ipi6_addr,
strict ? dev : NULL, 0))
err = -EINVAL;
else
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 79a485e8a700..1318de4c3e8d 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -273,12 +273,12 @@ static int ipv6_destopt_rcv(struct sk_buff *skb)
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
__u16 dstbuf;
#endif
- struct dst_entry *dst;
+ struct dst_entry *dst = skb_dst(skb);
if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
!pskb_may_pull(skb, (skb_transport_offset(skb) +
((skb_transport_header(skb)[1] + 1) << 3)))) {
- IP6_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ip6_dst_idev(skb_dst(skb)),
+ IP6_INC_STATS_BH(dev_net(dst->dev), ip6_dst_idev(dst),
IPSTATS_MIB_INHDRERRORS);
kfree_skb(skb);
return -1;
@@ -289,9 +289,7 @@ static int ipv6_destopt_rcv(struct sk_buff *skb)
dstbuf = opt->dst1;
#endif
- dst = dst_clone(skb_dst(skb));
if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) {
- dst_release(dst);
skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3;
opt = IP6CB(skb);
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
@@ -304,7 +302,6 @@ static int ipv6_destopt_rcv(struct sk_buff *skb)
IP6_INC_STATS_BH(dev_net(dst->dev),
ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS);
- dst_release(dst);
return -1;
}
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 11900417b1cc..90868fb42757 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -490,7 +490,8 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
goto out_dst_release;
}
- idev = in6_dev_get(skb->dev);
+ rcu_read_lock();
+ idev = __in6_dev_get(skb->dev);
err = ip6_append_data(sk, icmpv6_getfrag, &msg,
len + sizeof(struct icmp6hdr),
@@ -500,19 +501,16 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
if (err) {
ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS);
ip6_flush_pending_frames(sk);
- goto out_put;
+ } else {
+ err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
+ len + sizeof(struct icmp6hdr));
}
- err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr, len + sizeof(struct icmp6hdr));
-
-out_put:
- if (likely(idev != NULL))
- in6_dev_put(idev);
+ rcu_read_unlock();
out_dst_release:
dst_release(dst);
out:
icmpv6_xmit_unlock(sk);
}
-
EXPORT_SYMBOL(icmpv6_send);
static void icmpv6_echo_reply(struct sk_buff *skb)
@@ -569,7 +567,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
if (hlimit < 0)
hlimit = ip6_dst_hoplimit(dst);
- idev = in6_dev_get(skb->dev);
+ idev = __in6_dev_get(skb->dev);
msg.skb = skb;
msg.offset = 0;
@@ -583,13 +581,10 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
if (err) {
ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS);
ip6_flush_pending_frames(sk);
- goto out_put;
+ } else {
+ err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
+ skb->len + sizeof(struct icmp6hdr));
}
- err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr, skb->len + sizeof(struct icmp6hdr));
-
-out_put:
- if (likely(idev != NULL))
- in6_dev_put(idev);
dst_release(dst);
out:
icmpv6_xmit_unlock(sk);
@@ -840,8 +835,7 @@ static int __net_init icmpv6_sk_init(struct net *net)
/* Enough space for 2 64K ICMP packets, including
* sk_buff struct overhead.
*/
- sk->sk_sndbuf =
- (2 * ((64 * 1024) + sizeof(struct sk_buff)));
+ sk->sk_sndbuf = 2 * SKB_TRUESIZE(64 * 1024);
}
return 0;
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index 8a58e8cf6646..2916200f90c1 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -211,6 +211,7 @@ int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused)
struct flowi6 fl6;
struct dst_entry *dst;
struct in6_addr *final_p, final;
+ int res;
memset(&fl6, 0, sizeof(fl6));
fl6.flowi6_proto = sk->sk_protocol;
@@ -241,12 +242,14 @@ int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused)
__inet6_csk_dst_store(sk, dst, NULL, NULL);
}
- skb_dst_set(skb, dst_clone(dst));
+ rcu_read_lock();
+ skb_dst_set_noref(skb, dst);
/* Restore final destination back after routing done */
ipv6_addr_copy(&fl6.daddr, &np->daddr);
- return ip6_xmit(sk, skb, &fl6, np->opt);
+ res = ip6_xmit(sk, skb, &fl6, np->opt);
+ rcu_read_unlock();
+ return res;
}
-
EXPORT_SYMBOL_GPL(inet6_csk_xmit);
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 320d91d20ad7..93718f3db79b 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -28,10 +28,6 @@
#include <linux/list.h>
#include <linux/slab.h>
-#ifdef CONFIG_PROC_FS
-#include <linux/proc_fs.h>
-#endif
-
#include <net/ipv6.h>
#include <net/ndisc.h>
#include <net/addrconf.h>
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index f3caf1b8d572..543039450193 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -322,8 +322,8 @@ static int fl6_renew(struct ip6_flowlabel *fl, unsigned long linger, unsigned lo
}
static struct ip6_flowlabel *
-fl_create(struct net *net, struct in6_flowlabel_req *freq, char __user *optval,
- int optlen, int *err_p)
+fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq,
+ char __user *optval, int optlen, int *err_p)
{
struct ip6_flowlabel *fl = NULL;
int olen;
@@ -360,7 +360,7 @@ fl_create(struct net *net, struct in6_flowlabel_req *freq, char __user *optval,
msg.msg_control = (void*)(fl->opt+1);
memset(&flowi6, 0, sizeof(flowi6));
- err = datagram_send_ctl(net, &msg, &flowi6, fl->opt, &junk,
+ err = datagram_send_ctl(net, sk, &msg, &flowi6, fl->opt, &junk,
&junk, &junk);
if (err)
goto done;
@@ -528,7 +528,7 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
if (freq.flr_label & ~IPV6_FLOWLABEL_MASK)
return -EINVAL;
- fl = fl_create(net, &freq, optval, optlen, &err);
+ fl = fl_create(net, sk, &freq, optval, optlen, &err);
if (fl == NULL)
return err;
sfl1 = kmalloc(sizeof(*sfl1), GFP_KERNEL);
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 4c882cf4e8a1..1c9bf8b5c30a 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1193,6 +1193,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
struct sk_buff *skb;
unsigned int maxfraglen, fragheaderlen;
int exthdrlen;
+ int dst_exthdrlen;
int hh_len;
int mtu;
int copy;
@@ -1248,7 +1249,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
np->cork.hop_limit = hlimit;
np->cork.tclass = tclass;
mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ?
- rt->dst.dev->mtu : dst_mtu(rt->dst.path);
+ rt->dst.dev->mtu : dst_mtu(&rt->dst);
if (np->frag_size < mtu) {
if (np->frag_size)
mtu = np->frag_size;
@@ -1259,16 +1260,17 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
cork->length = 0;
sk->sk_sndmsg_page = NULL;
sk->sk_sndmsg_off = 0;
- exthdrlen = rt->dst.header_len + (opt ? opt->opt_flen : 0) -
- rt->rt6i_nfheader_len;
+ exthdrlen = (opt ? opt->opt_flen : 0) - rt->rt6i_nfheader_len;
length += exthdrlen;
transhdrlen += exthdrlen;
+ dst_exthdrlen = rt->dst.header_len;
} else {
rt = (struct rt6_info *)cork->dst;
fl6 = &inet->cork.fl.u.ip6;
opt = np->cork.opt;
transhdrlen = 0;
exthdrlen = 0;
+ dst_exthdrlen = 0;
mtu = cork->fragsize;
}
@@ -1368,6 +1370,8 @@ alloc_new_skb:
else
alloclen = datalen + fragheaderlen;
+ alloclen += dst_exthdrlen;
+
/*
* The last fragment gets additional space at tail.
* Note: we overallocate on fragments with MSG_MODE
@@ -1419,9 +1423,9 @@ alloc_new_skb:
/*
* Find where to start putting bytes
*/
- data = skb_put(skb, fraglen);
- skb_set_network_header(skb, exthdrlen);
- data += fragheaderlen;
+ data = skb_put(skb, fraglen + dst_exthdrlen);
+ skb_set_network_header(skb, exthdrlen + dst_exthdrlen);
+ data += fragheaderlen + dst_exthdrlen;
skb->transport_header = (skb->network_header +
fragheaderlen);
if (fraggap) {
@@ -1434,6 +1438,7 @@ alloc_new_skb:
pskb_trim_unique(skb_prev, maxfraglen);
}
copy = datalen - transhdrlen - fraggap;
+
if (copy < 0) {
err = -EINVAL;
kfree_skb(skb);
@@ -1448,6 +1453,7 @@ alloc_new_skb:
length -= datalen - fraggap;
transhdrlen = 0;
exthdrlen = 0;
+ dst_exthdrlen = 0;
csummode = CHECKSUM_NONE;
/*
@@ -1480,13 +1486,13 @@ alloc_new_skb:
if (page && (left = PAGE_SIZE - off) > 0) {
if (copy >= left)
copy = left;
- if (page != frag->page) {
+ if (page != skb_frag_page(frag)) {
if (i == MAX_SKB_FRAGS) {
err = -EMSGSIZE;
goto error;
}
- get_page(page);
skb_fill_page_desc(skb, i, page, sk->sk_sndmsg_off, 0);
+ skb_frag_ref(skb, i);
frag = &skb_shinfo(skb)->frags[i];
}
} else if(i < MAX_SKB_FRAGS) {
@@ -1506,12 +1512,14 @@ alloc_new_skb:
err = -EMSGSIZE;
goto error;
}
- if (getfrag(from, page_address(frag->page)+frag->page_offset+frag->size, offset, copy, skb->len, skb) < 0) {
+ if (getfrag(from,
+ skb_frag_address(frag) + skb_frag_size(frag),
+ offset, copy, skb->len, skb) < 0) {
err = -EFAULT;
goto error;
}
sk->sk_sndmsg_off += copy;
- frag->size += copy;
+ skb_frag_size_add(frag, copy);
skb->len += copy;
skb->data_len += copy;
skb->truesize += copy;
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 0bc98886c383..bdc15c9003d7 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -218,8 +218,8 @@ ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
{
struct ip6_tnl __rcu **tp = ip6_tnl_bucket(ip6n, &t->parms);
- rcu_assign_pointer(t->next , rtnl_dereference(*tp));
- rcu_assign_pointer(*tp, t);
+ RCU_INIT_POINTER(t->next , rtnl_dereference(*tp));
+ RCU_INIT_POINTER(*tp, t);
}
/**
@@ -237,7 +237,7 @@ ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
(iter = rtnl_dereference(*tp)) != NULL;
tp = &iter->next) {
if (t == iter) {
- rcu_assign_pointer(*tp, t->next);
+ RCU_INIT_POINTER(*tp, t->next);
break;
}
}
@@ -350,7 +350,7 @@ ip6_tnl_dev_uninit(struct net_device *dev)
struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
if (dev == ip6n->fb_tnl_dev)
- rcu_assign_pointer(ip6n->tnls_wc[0], NULL);
+ RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL);
else
ip6_tnl_unlink(ip6n, t);
ip6_tnl_dst_reset(t);
@@ -889,7 +889,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
struct net_device_stats *stats = &t->dev->stats;
struct ipv6hdr *ipv6h = ipv6_hdr(skb);
struct ipv6_tel_txoption opt;
- struct dst_entry *dst;
+ struct dst_entry *dst = NULL, *ndst = NULL;
struct net_device *tdev;
int mtu;
unsigned int max_headroom = sizeof(struct ipv6hdr);
@@ -897,19 +897,20 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
int err = -1;
int pkt_len;
- if ((dst = ip6_tnl_dst_check(t)) != NULL)
- dst_hold(dst);
- else {
- dst = ip6_route_output(net, NULL, fl6);
+ if (!fl6->flowi6_mark)
+ dst = ip6_tnl_dst_check(t);
+ if (!dst) {
+ ndst = ip6_route_output(net, NULL, fl6);
- if (dst->error)
+ if (ndst->error)
goto tx_err_link_failure;
- dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), NULL, 0);
- if (IS_ERR(dst)) {
- err = PTR_ERR(dst);
- dst = NULL;
+ ndst = xfrm_lookup(net, ndst, flowi6_to_flowi(fl6), NULL, 0);
+ if (IS_ERR(ndst)) {
+ err = PTR_ERR(ndst);
+ ndst = NULL;
goto tx_err_link_failure;
}
+ dst = ndst;
}
tdev = dst->dev;
@@ -955,8 +956,12 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
skb = new_skb;
}
skb_dst_drop(skb);
- skb_dst_set(skb, dst_clone(dst));
-
+ if (fl6->flowi6_mark) {
+ skb_dst_set(skb, dst);
+ ndst = NULL;
+ } else {
+ skb_dst_set_noref(skb, dst);
+ }
skb->transport_header = skb->network_header;
proto = fl6->flowi6_proto;
@@ -987,13 +992,14 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
stats->tx_errors++;
stats->tx_aborted_errors++;
}
- ip6_tnl_dst_store(t, dst);
+ if (ndst)
+ ip6_tnl_dst_store(t, ndst);
return 0;
tx_err_link_failure:
stats->tx_carrier_errors++;
dst_link_failure(skb);
tx_err_dst_release:
- dst_release(dst);
+ dst_release(ndst);
return err;
}
@@ -1020,9 +1026,11 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
dsfield = ipv4_get_dsfield(iph);
- if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS))
+ if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
fl6.flowlabel |= htonl((__u32)iph->tos << IPV6_TCLASS_SHIFT)
& IPV6_TCLASS_MASK;
+ if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
+ fl6.flowi6_mark = skb->mark;
err = ip6_tnl_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu);
if (err != 0) {
@@ -1069,10 +1077,12 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
fl6.flowi6_proto = IPPROTO_IPV6;
dsfield = ipv6_get_dsfield(ipv6h);
- if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS))
+ if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_TCLASS_MASK);
- if ((t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL))
+ if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_FLOWLABEL_MASK);
+ if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
+ fl6.flowi6_mark = skb->mark;
err = ip6_tnl_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu);
if (err != 0) {
@@ -1439,7 +1449,7 @@ static int __net_init ip6_fb_tnl_dev_init(struct net_device *dev)
t->parms.proto = IPPROTO_IPV6;
dev_hold(dev);
- rcu_assign_pointer(ip6n->tnls_wc[0], t);
+ RCU_INIT_POINTER(ip6n->tnls_wc[0], t);
return 0;
}
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 705c82886281..def0538e2413 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -696,8 +696,10 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,
int err;
err = ip6mr_fib_lookup(net, &fl6, &mrt);
- if (err < 0)
+ if (err < 0) {
+ kfree_skb(skb);
return err;
+ }
read_lock(&mrt_lock);
dev->stats.tx_bytes += skb->len;
@@ -2052,8 +2054,10 @@ int ip6_mr_input(struct sk_buff *skb)
int err;
err = ip6mr_fib_lookup(net, &fl6, &mrt);
- if (err < 0)
+ if (err < 0) {
+ kfree_skb(skb);
return err;
+ }
read_lock(&mrt_lock);
cache = ip6mr_cache_find(mrt,
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 9cb191ecaba8..c99e3ee9781f 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -343,7 +343,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
break;
case IPV6_TRANSPARENT:
- if (!capable(CAP_NET_ADMIN)) {
+ if (valbool && !capable(CAP_NET_ADMIN) && !capable(CAP_NET_RAW)) {
retv = -EPERM;
break;
}
@@ -475,7 +475,7 @@ sticky_done:
msg.msg_controllen = optlen;
msg.msg_control = (void*)(opt+1);
- retv = datagram_send_ctl(net, &msg, &fl6, opt, &junk, &junk,
+ retv = datagram_send_ctl(net, sk, &msg, &fl6, opt, &junk, &junk,
&junk);
if (retv)
goto done;
@@ -913,7 +913,7 @@ static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt,
}
static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
- char __user *optval, int __user *optlen)
+ char __user *optval, int __user *optlen, unsigned flags)
{
struct ipv6_pinfo *np = inet6_sk(sk);
int len;
@@ -962,7 +962,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
msg.msg_control = optval;
msg.msg_controllen = len;
- msg.msg_flags = 0;
+ msg.msg_flags = flags;
lock_sock(sk);
skb = np->pktoptions;
@@ -1222,7 +1222,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
if(level != SOL_IPV6)
return -ENOPROTOOPT;
- err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
+ err = do_ipv6_getsockopt(sk, level, optname, optval, optlen, 0);
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {
@@ -1264,7 +1264,8 @@ int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
return compat_mc_getsockopt(sk, level, optname, optval, optlen,
ipv6_getsockopt);
- err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
+ err = do_ipv6_getsockopt(sk, level, optname, optval, optlen,
+ MSG_CMSG_COMPAT);
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 3e6ebcdb4779..ee7839f4d6e3 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -1059,7 +1059,7 @@ static int mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs,
break;
for (i=0; i<nsrcs; i++) {
/* skip inactive filters */
- if (pmc->mca_sfcount[MCAST_INCLUDE] ||
+ if (psf->sf_count[MCAST_INCLUDE] ||
pmc->mca_sfcount[MCAST_EXCLUDE] !=
psf->sf_count[MCAST_EXCLUDE])
continue;
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 9da6e02eaaeb..44e5b7f2a6c1 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -370,17 +370,14 @@ static int ndisc_constructor(struct neighbour *neigh)
struct neigh_parms *parms;
int is_multicast = ipv6_addr_is_multicast(addr);
- rcu_read_lock();
in6_dev = in6_dev_get(dev);
if (in6_dev == NULL) {
- rcu_read_unlock();
return -EINVAL;
}
parms = in6_dev->nd_parms;
__neigh_parms_put(neigh->parms);
neigh->parms = neigh_parms_clone(parms);
- rcu_read_unlock();
neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST;
if (!dev->header_ops) {
@@ -533,7 +530,8 @@ void ndisc_send_skb(struct sk_buff *skb,
skb_dst_set(skb, dst);
- idev = in6_dev_get(dst->dev);
+ rcu_read_lock();
+ idev = __in6_dev_get(dst->dev);
IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
@@ -543,8 +541,7 @@ void ndisc_send_skb(struct sk_buff *skb,
ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
}
- if (likely(idev != NULL))
- in6_dev_put(idev);
+ rcu_read_unlock();
}
EXPORT_SYMBOL(ndisc_send_skb);
@@ -1039,7 +1036,7 @@ static void ndisc_recv_rs(struct sk_buff *skb)
if (skb->len < sizeof(*rs_msg))
return;
- idev = in6_dev_get(skb->dev);
+ idev = __in6_dev_get(skb->dev);
if (!idev) {
if (net_ratelimit())
ND_PRINTK1("ICMP6 RS: can't find in6 device\n");
@@ -1080,7 +1077,7 @@ static void ndisc_recv_rs(struct sk_buff *skb)
neigh_release(neigh);
}
out:
- in6_dev_put(idev);
+ return;
}
static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
@@ -1179,7 +1176,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
* set the RA_RECV flag in the interface
*/
- in6_dev = in6_dev_get(skb->dev);
+ in6_dev = __in6_dev_get(skb->dev);
if (in6_dev == NULL) {
ND_PRINTK0(KERN_ERR
"ICMPv6 RA: can't find inet6 device for %s.\n",
@@ -1188,7 +1185,6 @@ static void ndisc_router_discovery(struct sk_buff *skb)
}
if (!ndisc_parse_options(opt, optlen, &ndopts)) {
- in6_dev_put(in6_dev);
ND_PRINTK2(KERN_WARNING
"ICMP6 RA: invalid ND options\n");
return;
@@ -1225,6 +1221,9 @@ static void ndisc_router_discovery(struct sk_buff *skb)
if (!in6_dev->cnf.accept_ra_defrtr)
goto skip_defrtr;
+ if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, NULL, 0))
+ goto skip_defrtr;
+
lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
#ifdef CONFIG_IPV6_ROUTER_PREF
@@ -1255,7 +1254,6 @@ static void ndisc_router_discovery(struct sk_buff *skb)
ND_PRINTK0(KERN_ERR
"ICMPv6 RA: %s() failed to add default route.\n",
__func__);
- in6_dev_put(in6_dev);
return;
}
@@ -1265,7 +1263,6 @@ static void ndisc_router_discovery(struct sk_buff *skb)
"ICMPv6 RA: %s() got default router without neighbour.\n",
__func__);
dst_release(&rt->dst);
- in6_dev_put(in6_dev);
return;
}
neigh->flags |= NTF_ROUTER;
@@ -1349,6 +1346,9 @@ skip_linkparms:
goto out;
#ifdef CONFIG_IPV6_ROUTE_INFO
+ if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, NULL, 0))
+ goto skip_routeinfo;
+
if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
struct nd_opt_hdr *p;
for (p = ndopts.nd_opts_ri;
@@ -1366,6 +1366,8 @@ skip_linkparms:
&ipv6_hdr(skb)->saddr);
}
}
+
+skip_routeinfo:
#endif
#ifdef CONFIG_IPV6_NDISC_NODETYPE
@@ -1422,7 +1424,6 @@ out:
dst_release(&rt->dst);
else if (neigh)
neigh_release(neigh);
- in6_dev_put(in6_dev);
}
static void ndisc_redirect_rcv(struct sk_buff *skb)
@@ -1481,13 +1482,11 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
return;
}
- in6_dev = in6_dev_get(skb->dev);
+ in6_dev = __in6_dev_get(skb->dev);
if (!in6_dev)
return;
- if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects) {
- in6_dev_put(in6_dev);
+ if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
return;
- }
/* RFC2461 8.1:
* The IP source address of the Redirect MUST be the same as the current
@@ -1497,7 +1496,6 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
if (!ndisc_parse_options((u8*)(dest + 1), optlen, &ndopts)) {
ND_PRINTK2(KERN_WARNING
"ICMPv6 Redirect: invalid ND options\n");
- in6_dev_put(in6_dev);
return;
}
if (ndopts.nd_opts_tgt_lladdr) {
@@ -1506,7 +1504,6 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
if (!lladdr) {
ND_PRINTK2(KERN_WARNING
"ICMPv6 Redirect: invalid link-layer address length\n");
- in6_dev_put(in6_dev);
return;
}
}
@@ -1518,7 +1515,6 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
on_link);
neigh_release(neigh);
}
- in6_dev_put(in6_dev);
}
void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
@@ -1651,7 +1647,8 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
csum_partial(icmph, len, 0));
skb_dst_set(buff, dst);
- idev = in6_dev_get(dst->dev);
+ rcu_read_lock();
+ idev = __in6_dev_get(dst->dev);
IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev,
dst_output);
@@ -1660,8 +1657,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
}
- if (likely(idev != NULL))
- in6_dev_put(idev);
+ rcu_read_unlock();
return;
release:
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index 249394863284..e63c3972a739 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -218,6 +218,7 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
return skb;
nlmsg_failure:
+ kfree_skb(skb);
*errp = -EINVAL;
printk(KERN_ERR "ip6_queue: error creating packet message\n");
return NULL;
@@ -313,7 +314,7 @@ ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len)
{
struct nf_queue_entry *entry;
- if (vmsg->value > NF_MAX_VERDICT)
+ if (vmsg->value > NF_MAX_VERDICT || vmsg->value == NF_STOLEN)
return -EINVAL;
entry = ipq_find_dequeue_entry(vmsg->id);
@@ -358,12 +359,9 @@ ipq_receive_peer(struct ipq_peer_msg *pmsg,
break;
case IPQM_VERDICT:
- if (pmsg->msg.verdict.value > NF_MAX_VERDICT)
- status = -EINVAL;
- else
- status = ipq_set_verdict(&pmsg->msg.verdict,
- len - sizeof(*pmsg));
- break;
+ status = ipq_set_verdict(&pmsg->msg.verdict,
+ len - sizeof(*pmsg));
+ break;
default:
status = -EINVAL;
}
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 085727263812..e8762c73b170 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -378,8 +378,8 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
head->next = clone;
skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
skb_frag_list_init(head);
- for (i=0; i<skb_shinfo(head)->nr_frags; i++)
- plen += skb_shinfo(head)->frags[i].size;
+ for (i = 0; i < skb_shinfo(head)->nr_frags; i++)
+ plen += skb_frag_size(&skb_shinfo(head)->frags[i]);
clone->len = clone->data_len = head->data_len - plen;
head->data_len -= clone->len;
head->len -= clone->len;
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 6a79f3081bdb..6f7824e1cea4 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -130,14 +130,14 @@ static mh_filter_t __rcu *mh_filter __read_mostly;
int rawv6_mh_filter_register(mh_filter_t filter)
{
- rcu_assign_pointer(mh_filter, filter);
+ RCU_INIT_POINTER(mh_filter, filter);
return 0;
}
EXPORT_SYMBOL(rawv6_mh_filter_register);
int rawv6_mh_filter_unregister(mh_filter_t filter)
{
- rcu_assign_pointer(mh_filter, NULL);
+ RCU_INIT_POINTER(mh_filter, NULL);
synchronize_rcu();
return 0;
}
@@ -372,9 +372,9 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr,
read_unlock(&raw_v6_hashinfo.lock);
}
-static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb)
+static inline int rawv6_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
- if ((raw6_sk(sk)->checksum || rcu_dereference_raw(sk->sk_filter)) &&
+ if ((raw6_sk(sk)->checksum || rcu_access_pointer(sk->sk_filter)) &&
skb_checksum_complete(skb)) {
atomic_inc(&sk->sk_drops);
kfree_skb(skb);
@@ -542,8 +542,7 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
goto out;
offset = rp->offset;
- total_len = inet_sk(sk)->cork.base.length - (skb_network_header(skb) -
- skb->data);
+ total_len = inet_sk(sk)->cork.base.length;
if (offset >= total_len - 1) {
err = -EINVAL;
ip6_flush_pending_frames(sk);
@@ -817,8 +816,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
memset(opt, 0, sizeof(struct ipv6_txoptions));
opt->tot_len = sizeof(struct ipv6_txoptions);
- err = datagram_send_ctl(sock_net(sk), msg, &fl6, opt, &hlimit,
- &tclass, &dontfrag);
+ err = datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt,
+ &hlimit, &tclass, &dontfrag);
if (err < 0) {
fl6_sock_release(flowlabel);
return err;
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 7b954e2539d0..cc22099ac8b6 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -464,8 +464,8 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
head->next = clone;
skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
skb_frag_list_init(head);
- for (i=0; i<skb_shinfo(head)->nr_frags; i++)
- plen += skb_shinfo(head)->frags[i].size;
+ for (i = 0; i < skb_shinfo(head)->nr_frags; i++)
+ plen += skb_frag_size(&skb_shinfo(head)->frags[i]);
clone->len = clone->data_len = head->data_len - plen;
head->data_len -= clone->len;
head->len -= clone->len;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 9e69eb0ec6dd..fb545edef6ea 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -104,6 +104,9 @@ static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
struct inet_peer *peer;
u32 *p = NULL;
+ if (!(rt->dst.flags & DST_HOST))
+ return NULL;
+
if (!rt->rt6i_peer)
rt6_bind_peer(rt, 1);
@@ -241,7 +244,9 @@ static inline struct rt6_info *ip6_dst_alloc(struct dst_ops *ops,
{
struct rt6_info *rt = dst_alloc(ops, dev, 0, 0, flags);
- memset(&rt->rt6i_table, 0, sizeof(*rt) - sizeof(struct dst_entry));
+ if (rt != NULL)
+ memset(&rt->rt6i_table, 0,
+ sizeof(*rt) - sizeof(struct dst_entry));
return rt;
}
@@ -252,6 +257,9 @@ static void ip6_dst_destroy(struct dst_entry *dst)
struct inet6_dev *idev = rt->rt6i_idev;
struct inet_peer *peer = rt->rt6i_peer;
+ if (!(rt->dst.flags & DST_HOST))
+ dst_destroy_metrics_generic(dst);
+
if (idev != NULL) {
rt->rt6i_idev = NULL;
in6_dev_put(idev);
@@ -723,9 +731,7 @@ static struct rt6_info *rt6_alloc_cow(const struct rt6_info *ort,
ipv6_addr_copy(&rt->rt6i_gateway, daddr);
}
- rt->rt6i_dst.plen = 128;
rt->rt6i_flags |= RTF_CACHE;
- rt->dst.flags |= DST_HOST;
#ifdef CONFIG_IPV6_SUBTREES
if (rt->rt6i_src.plen && saddr) {
@@ -775,9 +781,7 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort,
struct rt6_info *rt = ip6_rt_copy(ort, daddr);
if (rt) {
- rt->rt6i_dst.plen = 128;
rt->rt6i_flags |= RTF_CACHE;
- rt->dst.flags |= DST_HOST;
dst_set_neighbour(&rt->dst, neigh_clone(dst_get_neighbour_raw(&ort->dst)));
}
return rt;
@@ -1078,12 +1082,15 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
neigh = NULL;
}
- rt->rt6i_idev = idev;
+ rt->dst.flags |= DST_HOST;
+ rt->dst.output = ip6_output;
dst_set_neighbour(&rt->dst, neigh);
atomic_set(&rt->dst.__refcnt, 1);
- ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255);
- rt->dst.output = ip6_output;
+
+ ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
+ rt->rt6i_dst.plen = 128;
+ rt->rt6i_idev = idev;
spin_lock_bh(&icmp6_dst_lock);
rt->dst.next = icmp6_dst_gc_list;
@@ -1261,6 +1268,14 @@ int ip6_route_add(struct fib6_config *cfg)
if (rt->rt6i_dst.plen == 128)
rt->dst.flags |= DST_HOST;
+ if (!(rt->dst.flags & DST_HOST) && cfg->fc_mx) {
+ u32 *metrics = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
+ if (!metrics) {
+ err = -ENOMEM;
+ goto out;
+ }
+ dst_init_metrics(&rt->dst, metrics, 0);
+ }
#ifdef CONFIG_IPV6_SUBTREES
ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
rt->rt6i_src.plen = cfg->fc_src_len;
@@ -1607,9 +1622,6 @@ void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src,
if (on_link)
nrt->rt6i_flags &= ~RTF_GATEWAY;
- nrt->rt6i_dst.plen = 128;
- nrt->dst.flags |= DST_HOST;
-
ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key);
dst_set_neighbour(&nrt->dst, neigh_clone(neigh));
@@ -1754,9 +1766,10 @@ static struct rt6_info *ip6_rt_copy(const struct rt6_info *ort,
if (rt) {
rt->dst.input = ort->dst.input;
rt->dst.output = ort->dst.output;
+ rt->dst.flags |= DST_HOST;
ipv6_addr_copy(&rt->rt6i_dst.addr, dest);
- rt->rt6i_dst.plen = ort->rt6i_dst.plen;
+ rt->rt6i_dst.plen = 128;
dst_copy_metrics(&rt->dst, &ort->dst);
rt->dst.error = ort->dst.error;
rt->rt6i_idev = ort->rt6i_idev;
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 07bf1085458f..a7a18602a046 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -182,7 +182,7 @@ static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t)
(iter = rtnl_dereference(*tp)) != NULL;
tp = &iter->next) {
if (t == iter) {
- rcu_assign_pointer(*tp, t->next);
+ RCU_INIT_POINTER(*tp, t->next);
break;
}
}
@@ -192,8 +192,8 @@ static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t)
{
struct ip_tunnel __rcu **tp = ipip6_bucket(sitn, t);
- rcu_assign_pointer(t->next, rtnl_dereference(*tp));
- rcu_assign_pointer(*tp, t);
+ RCU_INIT_POINTER(t->next, rtnl_dereference(*tp));
+ RCU_INIT_POINTER(*tp, t);
}
static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn)
@@ -391,7 +391,7 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
p->addr = a->addr;
p->flags = a->flags;
t->prl_count++;
- rcu_assign_pointer(t->prl, p);
+ RCU_INIT_POINTER(t->prl, p);
out:
return err;
}
@@ -474,7 +474,7 @@ static void ipip6_tunnel_uninit(struct net_device *dev)
struct sit_net *sitn = net_generic(net, sit_net_id);
if (dev == sitn->fb_tunnel_dev) {
- rcu_assign_pointer(sitn->tunnels_wc[0], NULL);
+ RCU_INIT_POINTER(sitn->tunnels_wc[0], NULL);
} else {
ipip6_tunnel_unlink(sitn, netdev_priv(dev));
ipip6_tunnel_del_prl(netdev_priv(dev), NULL);
@@ -672,6 +672,9 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
if (skb->protocol != htons(ETH_P_IPV6))
goto tx_error;
+ if (tos == 1)
+ tos = ipv6_get_dsfield(iph6);
+
/* ISATAP (RFC4214) - must come before 6to4 */
if (dev->priv_flags & IFF_ISATAP) {
struct neighbour *neigh = NULL;
@@ -1173,7 +1176,7 @@ static int __net_init ipip6_fb_tunnel_init(struct net_device *dev)
if (!dev->tstats)
return -ENOMEM;
dev_hold(dev);
- rcu_assign_pointer(sitn->tunnels_wc[0], tunnel);
+ RCU_INIT_POINTER(sitn->tunnels_wc[0], tunnel);
return 0;
}
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index ac838965ff34..5a0d6648bbbc 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -115,7 +115,7 @@ static __u32 check_tcp_syn_cookie(__u32 cookie, const struct in6_addr *saddr,
& COOKIEMASK;
}
-__u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp)
+__u32 cookie_v6_init_sequence(struct sock *sk, const struct sk_buff *skb, __u16 *mssp)
{
const struct ipv6hdr *iph = ipv6_hdr(skb);
const struct tcphdr *th = tcp_hdr(skb);
@@ -137,7 +137,7 @@ __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp)
jiffies / (HZ * 60), mssind);
}
-static inline int cookie_check(struct sk_buff *skb, __u32 cookie)
+static inline int cookie_check(const struct sk_buff *skb, __u32 cookie)
{
const struct ipv6hdr *iph = ipv6_hdr(skb);
const struct tcphdr *th = tcp_hdr(skb);
@@ -152,7 +152,7 @@ static inline int cookie_check(struct sk_buff *skb, __u32 cookie)
struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
{
struct tcp_options_received tcp_opt;
- u8 *hash_location;
+ const u8 *hash_location;
struct inet_request_sock *ireq;
struct inet6_request_sock *ireq6;
struct tcp_request_sock *treq;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index d1fb63f4aeb7..c8683fcc487a 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -114,7 +114,7 @@ static __inline__ __sum16 tcp_v6_check(int len,
return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base);
}
-static __u32 tcp_v6_init_sequence(struct sk_buff *skb)
+static __u32 tcp_v6_init_sequence(const struct sk_buff *skb)
{
return secure_tcpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
ipv6_hdr(skb)->saddr.s6_addr32,
@@ -531,20 +531,6 @@ static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req,
return tcp_v6_send_synack(sk, req, rvp);
}
-static inline void syn_flood_warning(struct sk_buff *skb)
-{
-#ifdef CONFIG_SYN_COOKIES
- if (sysctl_tcp_syncookies)
- printk(KERN_INFO
- "TCPv6: Possible SYN flooding on port %d. "
- "Sending cookies.\n", ntohs(tcp_hdr(skb)->dest));
- else
-#endif
- printk(KERN_INFO
- "TCPv6: Possible SYN flooding on port %d. "
- "Dropping request.\n", ntohs(tcp_hdr(skb)->dest));
-}
-
static void tcp_v6_reqsk_destructor(struct request_sock *req)
{
kfree_skb(inet6_rsk(req)->pktopts);
@@ -605,7 +591,8 @@ static int tcp_v6_md5_do_add(struct sock *sk, const struct in6_addr *peer,
}
sk_nocaps_add(sk, NETIF_F_GSO_MASK);
}
- if (tcp_alloc_md5sig_pool(sk) == NULL) {
+ if (tp->md5sig_info->entries6 == 0 &&
+ tcp_alloc_md5sig_pool(sk) == NULL) {
kfree(newkey);
return -ENOMEM;
}
@@ -614,8 +601,9 @@ static int tcp_v6_md5_do_add(struct sock *sk, const struct in6_addr *peer,
(tp->md5sig_info->entries6 + 1)), GFP_ATOMIC);
if (!keys) {
- tcp_free_md5sig_pool();
kfree(newkey);
+ if (tp->md5sig_info->entries6 == 0)
+ tcp_free_md5sig_pool();
return -ENOMEM;
}
@@ -661,6 +649,7 @@ static int tcp_v6_md5_do_del(struct sock *sk, const struct in6_addr *peer)
kfree(tp->md5sig_info->keys6);
tp->md5sig_info->keys6 = NULL;
tp->md5sig_info->alloced6 = 0;
+ tcp_free_md5sig_pool();
} else {
/* shrink the database */
if (tp->md5sig_info->entries6 != i)
@@ -669,7 +658,6 @@ static int tcp_v6_md5_do_del(struct sock *sk, const struct in6_addr *peer)
(tp->md5sig_info->entries6 - i)
* sizeof (tp->md5sig_info->keys6[0]));
}
- tcp_free_md5sig_pool();
return 0;
}
}
@@ -773,7 +761,7 @@ static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
const struct in6_addr *daddr, struct in6_addr *saddr,
- struct tcphdr *th)
+ const struct tcphdr *th)
{
struct tcp_md5sig_pool *hp;
struct hash_desc *desc;
@@ -805,13 +793,14 @@ clear_hash_noput:
}
static int tcp_v6_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,
- struct sock *sk, struct request_sock *req,
- struct sk_buff *skb)
+ const struct sock *sk,
+ const struct request_sock *req,
+ const struct sk_buff *skb)
{
const struct in6_addr *saddr, *daddr;
struct tcp_md5sig_pool *hp;
struct hash_desc *desc;
- struct tcphdr *th = tcp_hdr(skb);
+ const struct tcphdr *th = tcp_hdr(skb);
if (sk) {
saddr = &inet6_sk(sk)->saddr;
@@ -854,12 +843,12 @@ clear_hash_noput:
return 1;
}
-static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
+static int tcp_v6_inbound_md5_hash(struct sock *sk, const struct sk_buff *skb)
{
- __u8 *hash_location = NULL;
+ const __u8 *hash_location = NULL;
struct tcp_md5sig_key *hash_expected;
const struct ipv6hdr *ip6h = ipv6_hdr(skb);
- struct tcphdr *th = tcp_hdr(skb);
+ const struct tcphdr *th = tcp_hdr(skb);
int genhash;
u8 newhash[16];
@@ -992,7 +981,8 @@ static int tcp6_gro_complete(struct sk_buff *skb)
static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
u32 ts, struct tcp_md5sig_key *key, int rst)
{
- struct tcphdr *th = tcp_hdr(skb), *t1;
+ const struct tcphdr *th = tcp_hdr(skb);
+ struct tcphdr *t1;
struct sk_buff *buff;
struct flowi6 fl6;
struct net *net = dev_net(skb_dst(skb)->dev);
@@ -1082,7 +1072,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
{
- struct tcphdr *th = tcp_hdr(skb);
+ const struct tcphdr *th = tcp_hdr(skb);
u32 seq = 0, ack_seq = 0;
struct tcp_md5sig_key *key = NULL;
@@ -1172,18 +1162,14 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
{
struct tcp_extend_values tmp_ext;
struct tcp_options_received tmp_opt;
- u8 *hash_location;
+ const u8 *hash_location;
struct request_sock *req;
struct inet6_request_sock *treq;
struct ipv6_pinfo *np = inet6_sk(sk);
struct tcp_sock *tp = tcp_sk(sk);
__u32 isn = TCP_SKB_CB(skb)->when;
struct dst_entry *dst = NULL;
-#ifdef CONFIG_SYN_COOKIES
int want_cookie = 0;
-#else
-#define want_cookie 0
-#endif
if (skb->protocol == htons(ETH_P_IP))
return tcp_v4_conn_request(sk, skb);
@@ -1192,14 +1178,9 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
goto drop;
if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
- if (net_ratelimit())
- syn_flood_warning(skb);
-#ifdef CONFIG_SYN_COOKIES
- if (sysctl_tcp_syncookies)
- want_cookie = 1;
- else
-#endif
- goto drop;
+ want_cookie = tcp_syn_flood_action(sk, skb, "TCPv6");
+ if (!want_cookie)
+ goto drop;
}
if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
@@ -1249,9 +1230,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
while (l-- > 0)
*c++ ^= *hash_location++;
-#ifdef CONFIG_SYN_COOKIES
want_cookie = 0; /* not our kind of cookie */
-#endif
tmp_ext.cookie_out_never = 0; /* false */
tmp_ext.cookie_plus = tmp_opt.cookie_plus;
} else if (!tp->rx_opt.cookie_in_always) {
@@ -1408,6 +1387,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
newtp->af_specific = &tcp_sock_ipv6_mapped_specific;
#endif
+ newnp->ipv6_ac_list = NULL;
+ newnp->ipv6_fl_list = NULL;
newnp->pktoptions = NULL;
newnp->opt = NULL;
newnp->mcast_oif = inet6_iif(skb);
@@ -1472,6 +1453,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
First: no IPv4 options.
*/
newinet->inet_opt = NULL;
+ newnp->ipv6_ac_list = NULL;
newnp->ipv6_fl_list = NULL;
/* Clone RX bits */
@@ -1628,7 +1610,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
opt_skb = skb_clone(skb, GFP_ATOMIC);
if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
- sock_rps_save_rxhash(sk, skb->rxhash);
+ sock_rps_save_rxhash(sk, skb);
if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len))
goto reset;
if (opt_skb)
@@ -1650,7 +1632,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
* the new socket..
*/
if(nsk != sk) {
- sock_rps_save_rxhash(nsk, skb->rxhash);
+ sock_rps_save_rxhash(nsk, skb);
if (tcp_child_process(sk, nsk, skb))
goto reset;
if (opt_skb)
@@ -1658,7 +1640,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
return 0;
}
} else
- sock_rps_save_rxhash(sk, skb->rxhash);
+ sock_rps_save_rxhash(sk, skb);
if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len))
goto reset;
@@ -1708,7 +1690,7 @@ ipv6_pktoptions:
static int tcp_v6_rcv(struct sk_buff *skb)
{
- struct tcphdr *th;
+ const struct tcphdr *th;
const struct ipv6hdr *hdr;
struct sock *sk;
int ret;
@@ -1742,7 +1724,7 @@ static int tcp_v6_rcv(struct sk_buff *skb)
skb->len - th->doff*4);
TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
TCP_SKB_CB(skb)->when = 0;
- TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(hdr);
+ TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr);
TCP_SKB_CB(skb)->sacked = 0;
sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
@@ -1876,8 +1858,8 @@ static struct inet_peer *tcp_v6_get_peer(struct sock *sk, bool *release_it)
static void *tcp_v6_tw_get_peer(struct sock *sk)
{
- struct inet6_timewait_sock *tw6 = inet6_twsk(sk);
- struct inet_timewait_sock *tw = inet_twsk(sk);
+ const struct inet6_timewait_sock *tw6 = inet6_twsk(sk);
+ const struct inet_timewait_sock *tw = inet_twsk(sk);
if (tw->tw_family == AF_INET)
return tcp_v4_tw_get_peer(sk);
@@ -2032,7 +2014,7 @@ static void tcp_v6_destroy_sock(struct sock *sk)
#ifdef CONFIG_PROC_FS
/* Proc filesystem TCPv6 sock list dumping. */
static void get_openreq6(struct seq_file *seq,
- struct sock *sk, struct request_sock *req, int i, int uid)
+ const struct sock *sk, struct request_sock *req, int i, int uid)
{
int ttd = req->expires - jiffies;
const struct in6_addr *src = &inet6_rsk(req)->loc_addr;
@@ -2068,10 +2050,10 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
__u16 destp, srcp;
int timer_active;
unsigned long timer_expires;
- struct inet_sock *inet = inet_sk(sp);
- struct tcp_sock *tp = tcp_sk(sp);
+ const struct inet_sock *inet = inet_sk(sp);
+ const struct tcp_sock *tp = tcp_sk(sp);
const struct inet_connection_sock *icsk = inet_csk(sp);
- struct ipv6_pinfo *np = inet6_sk(sp);
+ const struct ipv6_pinfo *np = inet6_sk(sp);
dest = &np->daddr;
src = &np->rcv_saddr;
@@ -2123,7 +2105,7 @@ static void get_timewait6_sock(struct seq_file *seq,
{
const struct in6_addr *dest, *src;
__u16 destp, srcp;
- struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw);
+ const struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw);
int ttd = tw->tw_ttd - jiffies;
if (ttd < 0)
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 29213b51c499..f4ca0a5b3457 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -509,7 +509,7 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
int is_udplite = IS_UDPLITE(sk);
if (!ipv6_addr_any(&inet6_sk(sk)->daddr))
- sock_rps_save_rxhash(sk, skb->rxhash);
+ sock_rps_save_rxhash(sk, skb);
if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
goto drop;
@@ -533,7 +533,7 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
}
}
- if (rcu_dereference_raw(sk->sk_filter)) {
+ if (rcu_access_pointer(sk->sk_filter)) {
if (udp_lib_checksum_complete(skb))
goto drop;
}
@@ -1090,8 +1090,8 @@ do_udp_sendmsg:
memset(opt, 0, sizeof(struct ipv6_txoptions));
opt->tot_len = sizeof(*opt);
- err = datagram_send_ctl(sock_net(sk), msg, &fl6, opt, &hlimit,
- &tclass, &dontfrag);
+ err = datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt,
+ &hlimit, &tclass, &dontfrag);
if (err < 0) {
fl6_sock_release(flowlabel);
return err;
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index 49a91c5f5623..faae41737fca 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -28,6 +28,43 @@ int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
EXPORT_SYMBOL(xfrm6_find_1stfragopt);
+static int xfrm6_local_dontfrag(struct sk_buff *skb)
+{
+ int proto;
+ struct sock *sk = skb->sk;
+
+ if (sk) {
+ proto = sk->sk_protocol;
+
+ if (proto == IPPROTO_UDP || proto == IPPROTO_RAW)
+ return inet6_sk(sk)->dontfrag;
+ }
+
+ return 0;
+}
+
+static void xfrm6_local_rxpmtu(struct sk_buff *skb, u32 mtu)
+{
+ struct flowi6 fl6;
+ struct sock *sk = skb->sk;
+
+ fl6.flowi6_oif = sk->sk_bound_dev_if;
+ ipv6_addr_copy(&fl6.daddr, &ipv6_hdr(skb)->daddr);
+
+ ipv6_local_rxpmtu(sk, &fl6, mtu);
+}
+
+static void xfrm6_local_error(struct sk_buff *skb, u32 mtu)
+{
+ struct flowi6 fl6;
+ struct sock *sk = skb->sk;
+
+ fl6.fl6_dport = inet_sk(sk)->inet_dport;
+ ipv6_addr_copy(&fl6.daddr, &ipv6_hdr(skb)->daddr);
+
+ ipv6_local_error(sk, EMSGSIZE, &fl6, mtu);
+}
+
static int xfrm6_tunnel_check_size(struct sk_buff *skb)
{
int mtu, ret = 0;
@@ -39,7 +76,13 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb)
if (!skb->local_df && skb->len > mtu) {
skb->dev = dst->dev;
- icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+
+ if (xfrm6_local_dontfrag(skb))
+ xfrm6_local_rxpmtu(skb, mtu);
+ else if (skb->sk)
+ xfrm6_local_error(skb, mtu);
+ else
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
ret = -EMSGSIZE;
}
@@ -93,9 +136,18 @@ static int __xfrm6_output(struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
struct xfrm_state *x = dst->xfrm;
+ int mtu = ip6_skb_dst_mtu(skb);
+
+ if (skb->len > mtu && xfrm6_local_dontfrag(skb)) {
+ xfrm6_local_rxpmtu(skb, mtu);
+ return -EMSGSIZE;
+ } else if (!skb->local_df && skb->len > mtu && skb->sk) {
+ xfrm6_local_error(skb, mtu);
+ return -EMSGSIZE;
+ }
if ((x && x->props.mode == XFRM_MODE_TUNNEL) &&
- ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
+ ((skb->len > mtu && !skb_is_gso(skb)) ||
dst_allfrag(skb_dst(skb)))) {
return ip6_fragment(skb, x->outer_mode->afinfo->output_finish);
}
diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c
index e8d5f4405d68..d14152e866d9 100644
--- a/net/irda/irlan/irlan_eth.c
+++ b/net/irda/irlan/irlan_eth.c
@@ -50,7 +50,7 @@ static const struct net_device_ops irlan_eth_netdev_ops = {
.ndo_open = irlan_eth_open,
.ndo_stop = irlan_eth_close,
.ndo_start_xmit = irlan_eth_xmit,
- .ndo_set_multicast_list = irlan_eth_set_multicast_list,
+ .ndo_set_rx_mode = irlan_eth_set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
};
diff --git a/net/irda/irsysctl.c b/net/irda/irsysctl.c
index d0b70dadf73b..2615ffc8e785 100644
--- a/net/irda/irsysctl.c
+++ b/net/irda/irsysctl.c
@@ -40,9 +40,9 @@ extern int sysctl_slot_timeout;
extern int sysctl_fast_poll_increase;
extern char sysctl_devname[];
extern int sysctl_max_baud_rate;
-extern int sysctl_min_tx_turn_time;
-extern int sysctl_max_tx_data_size;
-extern int sysctl_max_tx_window;
+extern unsigned int sysctl_min_tx_turn_time;
+extern unsigned int sysctl_max_tx_data_size;
+extern unsigned int sysctl_max_tx_window;
extern int sysctl_max_noreply_time;
extern int sysctl_warn_noreply_time;
extern int sysctl_lap_keepalive_time;
diff --git a/net/irda/qos.c b/net/irda/qos.c
index 1b51bcf42394..4369f7f41bcb 100644
--- a/net/irda/qos.c
+++ b/net/irda/qos.c
@@ -60,7 +60,7 @@ int sysctl_max_noreply_time = 12;
* Default is 10us which means using the unmodified value given by the
* peer except if it's 0 (0 is likely a bug in the other stack).
*/
-unsigned sysctl_min_tx_turn_time = 10;
+unsigned int sysctl_min_tx_turn_time = 10;
/*
* Maximum data size to be used in transmission in payload of LAP frame.
* There is a bit of confusion in the IrDA spec :
@@ -75,13 +75,13 @@ unsigned sysctl_min_tx_turn_time = 10;
* bytes frames or all negotiated frame sizes, but you can use the sysctl
* to play with this value anyway.
* Jean II */
-unsigned sysctl_max_tx_data_size = 2042;
+unsigned int sysctl_max_tx_data_size = 2042;
/*
* Maximum transmit window, i.e. number of LAP frames between turn-around.
* This allow to override what the peer told us. Some peers are buggy and
* don't always support what they tell us.
* Jean II */
-unsigned sysctl_max_tx_window = 7;
+unsigned int sysctl_max_tx_window = 7;
static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get);
static int irlap_param_link_disconnect(void *instance, irda_param_t *parm,
diff --git a/net/iucv/Kconfig b/net/iucv/Kconfig
index 16ce9cd4f39e..497fbe732def 100644
--- a/net/iucv/Kconfig
+++ b/net/iucv/Kconfig
@@ -1,15 +1,17 @@
config IUCV
- tristate "IUCV support (S390 - z/VM only)"
depends on S390
+ def_tristate y if S390
+ prompt "IUCV support (S390 - z/VM only)"
help
Select this option if you want to use inter-user communication
under VM or VIF. If you run on z/VM, say "Y" to enable a fast
communication link between VM guests.
config AFIUCV
- tristate "AF_IUCV support (S390 - z/VM only)"
- depends on IUCV
+ depends on S390
+ def_tristate m if QETH_L3 || IUCV
+ prompt "AF_IUCV Socket support (S390 - z/VM and HiperSockets transport)"
help
- Select this option if you want to use inter-user communication under
- VM or VIF sockets. If you run on z/VM, say "Y" to enable a fast
- communication link between VM guests.
+ Select this option if you want to use AF_IUCV socket applications
+ based on z/VM inter-user communication vehicle or based on
+ HiperSockets.
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index e2013e434d03..274d150320c0 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -27,10 +27,9 @@
#include <asm/cpcmd.h>
#include <linux/kmod.h>
-#include <net/iucv/iucv.h>
#include <net/iucv/af_iucv.h>
-#define VERSION "1.1"
+#define VERSION "1.2"
static char iucv_userid[80];
@@ -42,6 +41,8 @@ static struct proto iucv_proto = {
.obj_size = sizeof(struct iucv_sock),
};
+static struct iucv_interface *pr_iucv;
+
/* special AF_IUCV IPRM messages */
static const u8 iprm_shutdown[8] =
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
@@ -90,6 +91,12 @@ do { \
static void iucv_sock_kill(struct sock *sk);
static void iucv_sock_close(struct sock *sk);
+static int afiucv_hs_rcv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *pt, struct net_device *orig_dev);
+static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock,
+ struct sk_buff *skb, u8 flags);
+static void afiucv_hs_callback_txnotify(struct sk_buff *, enum iucv_tx_notify);
+
/* Call Back functions */
static void iucv_callback_rx(struct iucv_path *, struct iucv_message *);
static void iucv_callback_txdone(struct iucv_path *, struct iucv_message *);
@@ -165,7 +172,7 @@ static int afiucv_pm_freeze(struct device *dev)
case IUCV_CLOSING:
case IUCV_CONNECTED:
if (iucv->path) {
- err = iucv_path_sever(iucv->path, NULL);
+ err = pr_iucv->path_sever(iucv->path, NULL);
iucv_path_free(iucv->path);
iucv->path = NULL;
}
@@ -229,7 +236,7 @@ static const struct dev_pm_ops afiucv_pm_ops = {
static struct device_driver af_iucv_driver = {
.owner = THIS_MODULE,
.name = "afiucv",
- .bus = &iucv_bus,
+ .bus = NULL,
.pm = &afiucv_pm_ops,
};
@@ -294,7 +301,11 @@ static inline int iucv_below_msglim(struct sock *sk)
if (sk->sk_state != IUCV_CONNECTED)
return 1;
- return (skb_queue_len(&iucv->send_skb_q) < iucv->path->msglim);
+ if (iucv->transport == AF_IUCV_TRANS_IUCV)
+ return (skb_queue_len(&iucv->send_skb_q) < iucv->path->msglim);
+ else
+ return ((atomic_read(&iucv->msg_sent) < iucv->msglimit_peer) &&
+ (atomic_read(&iucv->pendings) <= 0));
}
/**
@@ -312,6 +323,79 @@ static void iucv_sock_wake_msglim(struct sock *sk)
rcu_read_unlock();
}
+/**
+ * afiucv_hs_send() - send a message through HiperSockets transport
+ */
+static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock,
+ struct sk_buff *skb, u8 flags)
+{
+ struct net *net = sock_net(sock);
+ struct iucv_sock *iucv = iucv_sk(sock);
+ struct af_iucv_trans_hdr *phs_hdr;
+ struct sk_buff *nskb;
+ int err, confirm_recv = 0;
+
+ memset(skb->head, 0, ETH_HLEN);
+ phs_hdr = (struct af_iucv_trans_hdr *)skb_push(skb,
+ sizeof(struct af_iucv_trans_hdr));
+ skb_reset_mac_header(skb);
+ skb_reset_network_header(skb);
+ skb_push(skb, ETH_HLEN);
+ skb_reset_mac_header(skb);
+ memset(phs_hdr, 0, sizeof(struct af_iucv_trans_hdr));
+
+ phs_hdr->magic = ETH_P_AF_IUCV;
+ phs_hdr->version = 1;
+ phs_hdr->flags = flags;
+ if (flags == AF_IUCV_FLAG_SYN)
+ phs_hdr->window = iucv->msglimit;
+ else if ((flags == AF_IUCV_FLAG_WIN) || !flags) {
+ confirm_recv = atomic_read(&iucv->msg_recv);
+ phs_hdr->window = confirm_recv;
+ if (confirm_recv)
+ phs_hdr->flags = phs_hdr->flags | AF_IUCV_FLAG_WIN;
+ }
+ memcpy(phs_hdr->destUserID, iucv->dst_user_id, 8);
+ memcpy(phs_hdr->destAppName, iucv->dst_name, 8);
+ memcpy(phs_hdr->srcUserID, iucv->src_user_id, 8);
+ memcpy(phs_hdr->srcAppName, iucv->src_name, 8);
+ ASCEBC(phs_hdr->destUserID, sizeof(phs_hdr->destUserID));
+ ASCEBC(phs_hdr->destAppName, sizeof(phs_hdr->destAppName));
+ ASCEBC(phs_hdr->srcUserID, sizeof(phs_hdr->srcUserID));
+ ASCEBC(phs_hdr->srcAppName, sizeof(phs_hdr->srcAppName));
+ if (imsg)
+ memcpy(&phs_hdr->iucv_hdr, imsg, sizeof(struct iucv_message));
+
+ rcu_read_lock();
+ skb->dev = dev_get_by_index_rcu(net, sock->sk_bound_dev_if);
+ rcu_read_unlock();
+ if (!skb->dev)
+ return -ENODEV;
+ if (!(skb->dev->flags & IFF_UP))
+ return -ENETDOWN;
+ if (skb->len > skb->dev->mtu) {
+ if (sock->sk_type == SOCK_SEQPACKET)
+ return -EMSGSIZE;
+ else
+ skb_trim(skb, skb->dev->mtu);
+ }
+ skb->protocol = ETH_P_AF_IUCV;
+ skb_shinfo(skb)->tx_flags |= SKBTX_DRV_NEEDS_SK_REF;
+ nskb = skb_clone(skb, GFP_ATOMIC);
+ if (!nskb)
+ return -ENOMEM;
+ skb_queue_tail(&iucv->send_skb_q, nskb);
+ err = dev_queue_xmit(skb);
+ if (err) {
+ skb_unlink(nskb, &iucv->send_skb_q);
+ kfree_skb(nskb);
+ } else {
+ atomic_sub(confirm_recv, &iucv->msg_recv);
+ WARN_ON(atomic_read(&iucv->msg_recv) < 0);
+ }
+ return err;
+}
+
/* Timers */
static void iucv_sock_timeout(unsigned long arg)
{
@@ -380,6 +464,8 @@ static void iucv_sock_close(struct sock *sk)
unsigned char user_data[16];
struct iucv_sock *iucv = iucv_sk(sk);
unsigned long timeo;
+ int err, blen;
+ struct sk_buff *skb;
iucv_sock_clear_timer(sk);
lock_sock(sk);
@@ -390,6 +476,20 @@ static void iucv_sock_close(struct sock *sk)
break;
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,
+ sizeof(struct af_iucv_trans_hdr) +
+ ETH_HLEN);
+ err = afiucv_hs_send(NULL, sk, skb,
+ AF_IUCV_FLAG_FIN);
+ }
+ sk->sk_state = IUCV_DISCONN;
+ sk->sk_state_change(sk);
+ }
case IUCV_DISCONN:
sk->sk_state = IUCV_CLOSING;
sk->sk_state_change(sk);
@@ -412,7 +512,7 @@ static void iucv_sock_close(struct sock *sk)
low_nmcpy(user_data, iucv->src_name);
high_nmcpy(user_data, iucv->dst_name);
ASCEBC(user_data, sizeof(user_data));
- iucv_path_sever(iucv->path, user_data);
+ pr_iucv->path_sever(iucv->path, user_data);
iucv_path_free(iucv->path);
iucv->path = NULL;
}
@@ -444,23 +544,33 @@ static void iucv_sock_init(struct sock *sk, struct sock *parent)
static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio)
{
struct sock *sk;
+ struct iucv_sock *iucv;
sk = sk_alloc(&init_net, PF_IUCV, prio, &iucv_proto);
if (!sk)
return NULL;
+ iucv = iucv_sk(sk);
sock_init_data(sock, sk);
- INIT_LIST_HEAD(&iucv_sk(sk)->accept_q);
- spin_lock_init(&iucv_sk(sk)->accept_q_lock);
- skb_queue_head_init(&iucv_sk(sk)->send_skb_q);
- INIT_LIST_HEAD(&iucv_sk(sk)->message_q.list);
- spin_lock_init(&iucv_sk(sk)->message_q.lock);
- skb_queue_head_init(&iucv_sk(sk)->backlog_skb_q);
- iucv_sk(sk)->send_tag = 0;
- iucv_sk(sk)->flags = 0;
- iucv_sk(sk)->msglimit = IUCV_QUEUELEN_DEFAULT;
- iucv_sk(sk)->path = NULL;
- memset(&iucv_sk(sk)->src_user_id , 0, 32);
+ INIT_LIST_HEAD(&iucv->accept_q);
+ spin_lock_init(&iucv->accept_q_lock);
+ skb_queue_head_init(&iucv->send_skb_q);
+ INIT_LIST_HEAD(&iucv->message_q.list);
+ spin_lock_init(&iucv->message_q.lock);
+ skb_queue_head_init(&iucv->backlog_skb_q);
+ iucv->send_tag = 0;
+ atomic_set(&iucv->pendings, 0);
+ iucv->flags = 0;
+ iucv->msglimit = 0;
+ atomic_set(&iucv->msg_sent, 0);
+ atomic_set(&iucv->msg_recv, 0);
+ iucv->path = NULL;
+ iucv->sk_txnotify = afiucv_hs_callback_txnotify;
+ memset(&iucv->src_user_id , 0, 32);
+ if (pr_iucv)
+ iucv->transport = AF_IUCV_TRANS_IUCV;
+ else
+ iucv->transport = AF_IUCV_TRANS_HIPER;
sk->sk_destruct = iucv_sock_destruct;
sk->sk_sndtimeo = IUCV_CONN_TIMEOUT;
@@ -591,7 +701,9 @@ static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr,
struct sockaddr_iucv *sa = (struct sockaddr_iucv *) addr;
struct sock *sk = sock->sk;
struct iucv_sock *iucv;
- int err;
+ int err = 0;
+ struct net_device *dev;
+ char uid[9];
/* Verify the input sockaddr */
if (!addr || addr->sa_family != AF_IUCV)
@@ -610,19 +722,46 @@ static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr,
err = -EADDRINUSE;
goto done_unlock;
}
- if (iucv->path) {
- err = 0;
+ if (iucv->path)
goto done_unlock;
- }
/* Bind the socket */
- memcpy(iucv->src_name, sa->siucv_name, 8);
- /* Copy the user id */
- memcpy(iucv->src_user_id, iucv_userid, 8);
- sk->sk_state = IUCV_BOUND;
- err = 0;
+ if (pr_iucv)
+ if (!memcmp(sa->siucv_user_id, iucv_userid, 8))
+ goto vm_bind; /* VM IUCV transport */
+ /* try hiper transport */
+ memcpy(uid, sa->siucv_user_id, sizeof(uid));
+ ASCEBC(uid, 8);
+ rcu_read_lock();
+ for_each_netdev_rcu(&init_net, dev) {
+ if (!memcmp(dev->perm_addr, uid, 8)) {
+ memcpy(iucv->src_name, sa->siucv_name, 8);
+ memcpy(iucv->src_user_id, sa->siucv_user_id, 8);
+ sock->sk->sk_bound_dev_if = dev->ifindex;
+ sk->sk_state = IUCV_BOUND;
+ iucv->transport = AF_IUCV_TRANS_HIPER;
+ if (!iucv->msglimit)
+ iucv->msglimit = IUCV_HIPER_MSGLIM_DEFAULT;
+ rcu_read_unlock();
+ goto done_unlock;
+ }
+ }
+ rcu_read_unlock();
+vm_bind:
+ if (pr_iucv) {
+ /* use local userid for backward compat */
+ memcpy(iucv->src_name, sa->siucv_name, 8);
+ memcpy(iucv->src_user_id, iucv_userid, 8);
+ sk->sk_state = IUCV_BOUND;
+ iucv->transport = AF_IUCV_TRANS_IUCV;
+ if (!iucv->msglimit)
+ iucv->msglimit = IUCV_QUEUELEN_DEFAULT;
+ goto done_unlock;
+ }
+ /* found no dev to bind */
+ err = -ENODEV;
done_unlock:
/* Release the socket list lock */
write_unlock_bh(&iucv_sk_list.lock);
@@ -658,45 +797,44 @@ static int iucv_sock_autobind(struct sock *sk)
memcpy(&iucv->src_name, name, 8);
+ if (!iucv->msglimit)
+ iucv->msglimit = IUCV_QUEUELEN_DEFAULT;
+
return err;
}
-/* Connect an unconnected socket */
-static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr,
- int alen, int flags)
+static int afiucv_hs_connect(struct socket *sock)
{
- struct sockaddr_iucv *sa = (struct sockaddr_iucv *) addr;
struct sock *sk = sock->sk;
- struct iucv_sock *iucv;
- unsigned char user_data[16];
- int err;
-
- if (addr->sa_family != AF_IUCV || alen < sizeof(struct sockaddr_iucv))
- return -EINVAL;
-
- if (sk->sk_state != IUCV_OPEN && sk->sk_state != IUCV_BOUND)
- return -EBADFD;
-
- if (sk->sk_type != SOCK_STREAM && sk->sk_type != SOCK_SEQPACKET)
- return -EINVAL;
+ struct sk_buff *skb;
+ int blen = sizeof(struct af_iucv_trans_hdr) + ETH_HLEN;
+ int err = 0;
- if (sk->sk_state == IUCV_OPEN) {
- err = iucv_sock_autobind(sk);
- if (unlikely(err))
- return err;
+ /* 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;
+}
- lock_sock(sk);
-
- /* Set the destination information */
- memcpy(iucv_sk(sk)->dst_user_id, sa->siucv_user_id, 8);
- memcpy(iucv_sk(sk)->dst_name, sa->siucv_name, 8);
+static int afiucv_path_connect(struct socket *sock, struct sockaddr *addr)
+{
+ struct sockaddr_iucv *sa = (struct sockaddr_iucv *) addr;
+ struct sock *sk = sock->sk;
+ struct iucv_sock *iucv = iucv_sk(sk);
+ unsigned char user_data[16];
+ int err;
high_nmcpy(user_data, sa->siucv_name);
- low_nmcpy(user_data, iucv_sk(sk)->src_name);
+ low_nmcpy(user_data, iucv->src_name);
ASCEBC(user_data, sizeof(user_data));
- iucv = iucv_sk(sk);
/* Create path. */
iucv->path = iucv_path_alloc(iucv->msglimit,
IUCV_IPRMDATA, GFP_KERNEL);
@@ -704,8 +842,9 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr,
err = -ENOMEM;
goto done;
}
- err = iucv_path_connect(iucv->path, &af_iucv_handler,
- sa->siucv_user_id, NULL, user_data, sk);
+ err = pr_iucv->path_connect(iucv->path, &af_iucv_handler,
+ sa->siucv_user_id, NULL, user_data,
+ sk);
if (err) {
iucv_path_free(iucv->path);
iucv->path = NULL;
@@ -724,21 +863,62 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr,
err = -ECONNREFUSED;
break;
}
- goto done;
}
+done:
+ return err;
+}
- if (sk->sk_state != IUCV_CONNECTED) {
+/* Connect an unconnected socket */
+static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr,
+ int alen, int flags)
+{
+ struct sockaddr_iucv *sa = (struct sockaddr_iucv *) addr;
+ struct sock *sk = sock->sk;
+ struct iucv_sock *iucv = iucv_sk(sk);
+ int err;
+
+ if (addr->sa_family != AF_IUCV || alen < sizeof(struct sockaddr_iucv))
+ return -EINVAL;
+
+ if (sk->sk_state != IUCV_OPEN && sk->sk_state != IUCV_BOUND)
+ return -EBADFD;
+
+ if (sk->sk_state == IUCV_OPEN &&
+ iucv->transport == AF_IUCV_TRANS_HIPER)
+ return -EBADFD; /* explicit bind required */
+
+ if (sk->sk_type != SOCK_STREAM && sk->sk_type != SOCK_SEQPACKET)
+ return -EINVAL;
+
+ if (sk->sk_state == IUCV_OPEN) {
+ err = iucv_sock_autobind(sk);
+ if (unlikely(err))
+ return err;
+ }
+
+ lock_sock(sk);
+
+ /* Set the destination information */
+ memcpy(iucv->dst_user_id, sa->siucv_user_id, 8);
+ memcpy(iucv->dst_name, sa->siucv_name, 8);
+
+ if (iucv->transport == AF_IUCV_TRANS_HIPER)
+ err = afiucv_hs_connect(sock);
+ else
+ err = afiucv_path_connect(sock, addr);
+ if (err)
+ goto done;
+
+ if (sk->sk_state != IUCV_CONNECTED)
err = iucv_sock_wait(sk, iucv_sock_in_state(sk, IUCV_CONNECTED,
IUCV_DISCONN),
sock_sndtimeo(sk, flags & O_NONBLOCK));
- }
- if (sk->sk_state == IUCV_DISCONN) {
+ if (sk->sk_state == IUCV_DISCONN || sk->sk_state == IUCV_CLOSED)
err = -ECONNREFUSED;
- }
- if (err) {
- iucv_path_sever(iucv->path, NULL);
+ if (err && iucv->transport == AF_IUCV_TRANS_IUCV) {
+ pr_iucv->path_sever(iucv->path, NULL);
iucv_path_free(iucv->path);
iucv->path = NULL;
}
@@ -833,20 +1013,21 @@ static int iucv_sock_getname(struct socket *sock, struct sockaddr *addr,
{
struct sockaddr_iucv *siucv = (struct sockaddr_iucv *) addr;
struct sock *sk = sock->sk;
+ struct iucv_sock *iucv = iucv_sk(sk);
addr->sa_family = AF_IUCV;
*len = sizeof(struct sockaddr_iucv);
if (peer) {
- memcpy(siucv->siucv_user_id, iucv_sk(sk)->dst_user_id, 8);
- memcpy(siucv->siucv_name, &iucv_sk(sk)->dst_name, 8);
+ memcpy(siucv->siucv_user_id, iucv->dst_user_id, 8);
+ memcpy(siucv->siucv_name, iucv->dst_name, 8);
} else {
- memcpy(siucv->siucv_user_id, iucv_sk(sk)->src_user_id, 8);
- memcpy(siucv->siucv_name, iucv_sk(sk)->src_name, 8);
+ memcpy(siucv->siucv_user_id, iucv->src_user_id, 8);
+ memcpy(siucv->siucv_name, iucv->src_name, 8);
}
memset(&siucv->siucv_port, 0, sizeof(siucv->siucv_port));
memset(&siucv->siucv_addr, 0, sizeof(siucv->siucv_addr));
- memset(siucv->siucv_nodeid, 0, sizeof(siucv->siucv_nodeid));
+ memset(&siucv->siucv_nodeid, 0, sizeof(siucv->siucv_nodeid));
return 0;
}
@@ -871,7 +1052,7 @@ static int iucv_send_iprm(struct iucv_path *path, struct iucv_message *msg,
memcpy(prmdata, (void *) skb->data, skb->len);
prmdata[7] = 0xff - (u8) skb->len;
- return iucv_message_send(path, msg, IUCV_IPRMDATA, 0,
+ return pr_iucv->message_send(path, msg, IUCV_IPRMDATA, 0,
(void *) prmdata, 8);
}
@@ -960,9 +1141,16 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
* this is fine for SOCK_SEQPACKET (unless we want to support
* segmented records using the MSG_EOR flag), but
* for SOCK_STREAM we might want to improve it in future */
- skb = sock_alloc_send_skb(sk, len, noblock, &err);
+ if (iucv->transport == AF_IUCV_TRANS_HIPER)
+ skb = sock_alloc_send_skb(sk,
+ len + sizeof(struct af_iucv_trans_hdr) + ETH_HLEN,
+ noblock, &err);
+ else
+ skb = sock_alloc_send_skb(sk, len, noblock, &err);
if (!skb)
goto out;
+ if (iucv->transport == AF_IUCV_TRANS_HIPER)
+ skb_reserve(skb, sizeof(struct af_iucv_trans_hdr) + ETH_HLEN);
if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
err = -EFAULT;
goto fail;
@@ -983,6 +1171,15 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
/* increment and save iucv message tag for msg_completion cbk */
txmsg.tag = iucv->send_tag++;
memcpy(CB_TAG(skb), &txmsg.tag, CB_TAG_LEN);
+ if (iucv->transport == AF_IUCV_TRANS_HIPER) {
+ atomic_inc(&iucv->msg_sent);
+ err = afiucv_hs_send(&txmsg, sk, skb, 0);
+ if (err) {
+ atomic_dec(&iucv->msg_sent);
+ goto fail;
+ }
+ goto release;
+ }
skb_queue_tail(&iucv->send_skb_q, skb);
if (((iucv->path->flags & IUCV_IPRMDATA) & iucv->flags)
@@ -999,13 +1196,13 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
/* this error should never happen since the
* IUCV_IPRMDATA path flag is set... sever path */
if (err == 0x15) {
- iucv_path_sever(iucv->path, NULL);
+ pr_iucv->path_sever(iucv->path, NULL);
skb_unlink(skb, &iucv->send_skb_q);
err = -EPIPE;
goto fail;
}
} else
- err = iucv_message_send(iucv->path, &txmsg, 0, 0,
+ err = pr_iucv->message_send(iucv->path, &txmsg, 0, 0,
(void *) skb->data, skb->len);
if (err) {
if (err == 3) {
@@ -1023,6 +1220,7 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
goto fail;
}
+release:
release_sock(sk);
return len;
@@ -1095,8 +1293,9 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb,
skb->len = 0;
}
} else {
- rc = iucv_message_receive(path, msg, msg->flags & IUCV_IPRMDATA,
- skb->data, len, NULL);
+ rc = pr_iucv->message_receive(path, msg,
+ msg->flags & IUCV_IPRMDATA,
+ skb->data, len, NULL);
if (rc) {
kfree_skb(skb);
return;
@@ -1110,7 +1309,7 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb,
kfree_skb(skb);
skb = NULL;
if (rc) {
- iucv_path_sever(path, NULL);
+ pr_iucv->path_sever(path, NULL);
return;
}
skb = skb_dequeue(&iucv_sk(sk)->backlog_skb_q);
@@ -1154,7 +1353,8 @@ 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;
+ struct sk_buff *skb, *rskb, *cskb, *sskb;
+ int blen;
int err = 0;
if ((sk->sk_state == IUCV_DISCONN || sk->sk_state == IUCV_SEVERED) &&
@@ -1179,7 +1379,7 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
copied = min_t(unsigned int, rlen, len);
cskb = skb;
- if (memcpy_toiovec(msg->msg_iov, cskb->data, copied)) {
+ if (skb_copy_datagram_iovec(cskb, 0, msg->msg_iov, copied)) {
if (!(flags & MSG_PEEK))
skb_queue_head(&sk->sk_receive_queue, skb);
return -EFAULT;
@@ -1217,6 +1417,7 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
}
kfree_skb(skb);
+ atomic_inc(&iucv->msg_recv);
/* Queue backlog skbs */
spin_lock_bh(&iucv->message_q.lock);
@@ -1233,6 +1434,24 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
if (skb_queue_empty(&iucv->backlog_skb_q)) {
if (!list_empty(&iucv->message_q.list))
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,
+ sizeof(struct af_iucv_trans_hdr)
+ + ETH_HLEN);
+ err = afiucv_hs_send(NULL, sk, sskb,
+ AF_IUCV_FLAG_WIN);
+ }
+ if (err) {
+ sk->sk_state = IUCV_DISCONN;
+ sk->sk_state_change(sk);
+ }
+ }
}
spin_unlock_bh(&iucv->message_q.lock);
}
@@ -1327,8 +1546,8 @@ static int iucv_sock_shutdown(struct socket *sock, int how)
if (how == SEND_SHUTDOWN || how == SHUTDOWN_MASK) {
txmsg.class = 0;
txmsg.tag = 0;
- err = iucv_message_send(iucv->path, &txmsg, IUCV_IPRMDATA, 0,
- (void *) iprm_shutdown, 8);
+ err = pr_iucv->message_send(iucv->path, &txmsg, IUCV_IPRMDATA,
+ 0, (void *) iprm_shutdown, 8);
if (err) {
switch (err) {
case 1:
@@ -1345,7 +1564,7 @@ static int iucv_sock_shutdown(struct socket *sock, int how)
}
if (how == RCV_SHUTDOWN || how == SHUTDOWN_MASK) {
- err = iucv_path_quiesce(iucv_sk(sk)->path, NULL);
+ err = pr_iucv->path_quiesce(iucv->path, NULL);
if (err)
err = -ENOTCONN;
@@ -1372,7 +1591,7 @@ static int iucv_sock_release(struct socket *sock)
/* Unregister with IUCV base support */
if (iucv_sk(sk)->path) {
- iucv_path_sever(iucv_sk(sk)->path, NULL);
+ pr_iucv->path_sever(iucv_sk(sk)->path, NULL);
iucv_path_free(iucv_sk(sk)->path);
iucv_sk(sk)->path = NULL;
}
@@ -1514,14 +1733,14 @@ static int iucv_callback_connreq(struct iucv_path *path,
high_nmcpy(user_data, iucv->dst_name);
ASCEBC(user_data, sizeof(user_data));
if (sk->sk_state != IUCV_LISTEN) {
- err = iucv_path_sever(path, user_data);
+ err = pr_iucv->path_sever(path, user_data);
iucv_path_free(path);
goto fail;
}
/* Check for backlog size */
if (sk_acceptq_is_full(sk)) {
- err = iucv_path_sever(path, user_data);
+ err = pr_iucv->path_sever(path, user_data);
iucv_path_free(path);
goto fail;
}
@@ -1529,7 +1748,7 @@ static int iucv_callback_connreq(struct iucv_path *path,
/* Create the new socket */
nsk = iucv_sock_alloc(NULL, sk->sk_type, GFP_ATOMIC);
if (!nsk) {
- err = iucv_path_sever(path, user_data);
+ err = pr_iucv->path_sever(path, user_data);
iucv_path_free(path);
goto fail;
}
@@ -1553,9 +1772,9 @@ static int iucv_callback_connreq(struct iucv_path *path,
/* set message limit for path based on msglimit of accepting socket */
niucv->msglimit = iucv->msglimit;
path->msglim = iucv->msglimit;
- err = iucv_path_accept(path, &af_iucv_handler, nuser_data, nsk);
+ err = pr_iucv->path_accept(path, &af_iucv_handler, nuser_data, nsk);
if (err) {
- err = iucv_path_sever(path, user_data);
+ err = pr_iucv->path_sever(path, user_data);
iucv_path_free(path);
iucv_sock_kill(nsk);
goto fail;
@@ -1589,7 +1808,7 @@ static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg)
int len;
if (sk->sk_shutdown & RCV_SHUTDOWN) {
- iucv_message_reject(path, msg);
+ pr_iucv->message_reject(path, msg);
return;
}
@@ -1600,7 +1819,7 @@ static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg)
goto save_message;
len = atomic_read(&sk->sk_rmem_alloc);
- len += iucv_msg_length(msg) + sizeof(struct sk_buff);
+ len += SKB_TRUESIZE(iucv_msg_length(msg));
if (len > sk->sk_rcvbuf)
goto save_message;
@@ -1692,6 +1911,389 @@ static void iucv_callback_shutdown(struct iucv_path *path, u8 ipuser[16])
bh_unlock_sock(sk);
}
+/***************** HiperSockets transport callbacks ********************/
+static void afiucv_swap_src_dest(struct sk_buff *skb)
+{
+ struct af_iucv_trans_hdr *trans_hdr =
+ (struct af_iucv_trans_hdr *)skb->data;
+ char tmpID[8];
+ char tmpName[8];
+
+ ASCEBC(trans_hdr->destUserID, sizeof(trans_hdr->destUserID));
+ ASCEBC(trans_hdr->destAppName, sizeof(trans_hdr->destAppName));
+ ASCEBC(trans_hdr->srcUserID, sizeof(trans_hdr->srcUserID));
+ ASCEBC(trans_hdr->srcAppName, sizeof(trans_hdr->srcAppName));
+ memcpy(tmpID, trans_hdr->srcUserID, 8);
+ memcpy(tmpName, trans_hdr->srcAppName, 8);
+ memcpy(trans_hdr->srcUserID, trans_hdr->destUserID, 8);
+ memcpy(trans_hdr->srcAppName, trans_hdr->destAppName, 8);
+ memcpy(trans_hdr->destUserID, tmpID, 8);
+ memcpy(trans_hdr->destAppName, tmpName, 8);
+ skb_push(skb, ETH_HLEN);
+ memset(skb->data, 0, ETH_HLEN);
+}
+
+/**
+ * afiucv_hs_callback_syn - react on received SYN
+ **/
+static int afiucv_hs_callback_syn(struct sock *sk, struct sk_buff *skb)
+{
+ struct sock *nsk;
+ struct iucv_sock *iucv, *niucv;
+ struct af_iucv_trans_hdr *trans_hdr;
+ int err;
+
+ iucv = iucv_sk(sk);
+ trans_hdr = (struct af_iucv_trans_hdr *)skb->data;
+ if (!iucv) {
+ /* no sock - connection refused */
+ afiucv_swap_src_dest(skb);
+ trans_hdr->flags = AF_IUCV_FLAG_SYN | AF_IUCV_FLAG_FIN;
+ err = dev_queue_xmit(skb);
+ goto out;
+ }
+
+ nsk = iucv_sock_alloc(NULL, sk->sk_type, GFP_ATOMIC);
+ bh_lock_sock(sk);
+ if ((sk->sk_state != IUCV_LISTEN) ||
+ sk_acceptq_is_full(sk) ||
+ !nsk) {
+ /* error on server socket - connection refused */
+ if (nsk)
+ sk_free(nsk);
+ afiucv_swap_src_dest(skb);
+ trans_hdr->flags = AF_IUCV_FLAG_SYN | AF_IUCV_FLAG_FIN;
+ err = dev_queue_xmit(skb);
+ bh_unlock_sock(sk);
+ goto out;
+ }
+
+ niucv = iucv_sk(nsk);
+ iucv_sock_init(nsk, sk);
+ niucv->transport = AF_IUCV_TRANS_HIPER;
+ niucv->msglimit = iucv->msglimit;
+ if (!trans_hdr->window)
+ niucv->msglimit_peer = IUCV_HIPER_MSGLIM_DEFAULT;
+ else
+ niucv->msglimit_peer = trans_hdr->window;
+ memcpy(niucv->dst_name, trans_hdr->srcAppName, 8);
+ memcpy(niucv->dst_user_id, trans_hdr->srcUserID, 8);
+ memcpy(niucv->src_name, iucv->src_name, 8);
+ memcpy(niucv->src_user_id, iucv->src_user_id, 8);
+ nsk->sk_bound_dev_if = sk->sk_bound_dev_if;
+ afiucv_swap_src_dest(skb);
+ trans_hdr->flags = AF_IUCV_FLAG_SYN | AF_IUCV_FLAG_ACK;
+ trans_hdr->window = niucv->msglimit;
+ /* if receiver acks the xmit connection is established */
+ err = dev_queue_xmit(skb);
+ if (!err) {
+ iucv_accept_enqueue(sk, nsk);
+ nsk->sk_state = IUCV_CONNECTED;
+ sk->sk_data_ready(sk, 1);
+ } else
+ iucv_sock_kill(nsk);
+ bh_unlock_sock(sk);
+
+out:
+ return NET_RX_SUCCESS;
+}
+
+/**
+ * afiucv_hs_callback_synack() - react on received SYN-ACK
+ **/
+static int afiucv_hs_callback_synack(struct sock *sk, struct sk_buff *skb)
+{
+ struct iucv_sock *iucv = iucv_sk(sk);
+ struct af_iucv_trans_hdr *trans_hdr =
+ (struct af_iucv_trans_hdr *)skb->data;
+
+ if (!iucv)
+ goto out;
+ if (sk->sk_state != IUCV_BOUND)
+ goto out;
+ bh_lock_sock(sk);
+ iucv->msglimit_peer = trans_hdr->window;
+ sk->sk_state = IUCV_CONNECTED;
+ sk->sk_state_change(sk);
+ bh_unlock_sock(sk);
+out:
+ kfree_skb(skb);
+ return NET_RX_SUCCESS;
+}
+
+/**
+ * afiucv_hs_callback_synfin() - react on received SYN_FIN
+ **/
+static int afiucv_hs_callback_synfin(struct sock *sk, struct sk_buff *skb)
+{
+ struct iucv_sock *iucv = iucv_sk(sk);
+
+ if (!iucv)
+ goto out;
+ if (sk->sk_state != IUCV_BOUND)
+ goto out;
+ bh_lock_sock(sk);
+ sk->sk_state = IUCV_DISCONN;
+ sk->sk_state_change(sk);
+ bh_unlock_sock(sk);
+out:
+ kfree_skb(skb);
+ return NET_RX_SUCCESS;
+}
+
+/**
+ * afiucv_hs_callback_fin() - react on received FIN
+ **/
+static int afiucv_hs_callback_fin(struct sock *sk, struct sk_buff *skb)
+{
+ struct iucv_sock *iucv = iucv_sk(sk);
+
+ /* other end of connection closed */
+ if (iucv) {
+ bh_lock_sock(sk);
+ if (!list_empty(&iucv->accept_q))
+ sk->sk_state = IUCV_SEVERED;
+ else
+ sk->sk_state = IUCV_DISCONN;
+ sk->sk_state_change(sk);
+ bh_unlock_sock(sk);
+ }
+ kfree_skb(skb);
+ return NET_RX_SUCCESS;
+}
+
+/**
+ * afiucv_hs_callback_win() - react on received WIN
+ **/
+static int afiucv_hs_callback_win(struct sock *sk, struct sk_buff *skb)
+{
+ struct iucv_sock *iucv = iucv_sk(sk);
+ struct af_iucv_trans_hdr *trans_hdr =
+ (struct af_iucv_trans_hdr *)skb->data;
+
+ if (!iucv)
+ return NET_RX_SUCCESS;
+
+ if (sk->sk_state != IUCV_CONNECTED)
+ return NET_RX_SUCCESS;
+
+ atomic_sub(trans_hdr->window, &iucv->msg_sent);
+ iucv_sock_wake_msglim(sk);
+ return NET_RX_SUCCESS;
+}
+
+/**
+ * afiucv_hs_callback_rx() - react on received data
+ **/
+static int afiucv_hs_callback_rx(struct sock *sk, struct sk_buff *skb)
+{
+ struct iucv_sock *iucv = iucv_sk(sk);
+
+ if (!iucv) {
+ kfree_skb(skb);
+ return NET_RX_SUCCESS;
+ }
+
+ if (sk->sk_state != IUCV_CONNECTED) {
+ kfree_skb(skb);
+ return NET_RX_SUCCESS;
+ }
+
+ /* write stuff from iucv_msg to skb cb */
+ if (skb->len <= sizeof(struct af_iucv_trans_hdr)) {
+ kfree_skb(skb);
+ return NET_RX_SUCCESS;
+ }
+ skb_pull(skb, sizeof(struct af_iucv_trans_hdr));
+ skb_reset_transport_header(skb);
+ skb_reset_network_header(skb);
+ spin_lock(&iucv->message_q.lock);
+ if (skb_queue_empty(&iucv->backlog_skb_q)) {
+ if (sock_queue_rcv_skb(sk, skb)) {
+ /* handle rcv queue full */
+ skb_queue_tail(&iucv->backlog_skb_q, skb);
+ }
+ } else
+ skb_queue_tail(&iucv_sk(sk)->backlog_skb_q, skb);
+ spin_unlock(&iucv->message_q.lock);
+ return NET_RX_SUCCESS;
+}
+
+/**
+ * afiucv_hs_rcv() - base function for arriving data through HiperSockets
+ * transport
+ * called from netif RX softirq
+ **/
+static int afiucv_hs_rcv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *pt, struct net_device *orig_dev)
+{
+ struct hlist_node *node;
+ struct sock *sk;
+ struct iucv_sock *iucv;
+ struct af_iucv_trans_hdr *trans_hdr;
+ char nullstring[8];
+ int err = 0;
+
+ skb_pull(skb, ETH_HLEN);
+ trans_hdr = (struct af_iucv_trans_hdr *)skb->data;
+ EBCASC(trans_hdr->destAppName, sizeof(trans_hdr->destAppName));
+ EBCASC(trans_hdr->destUserID, sizeof(trans_hdr->destUserID));
+ EBCASC(trans_hdr->srcAppName, sizeof(trans_hdr->srcAppName));
+ EBCASC(trans_hdr->srcUserID, sizeof(trans_hdr->srcUserID));
+ memset(nullstring, 0, sizeof(nullstring));
+ iucv = NULL;
+ sk = NULL;
+ read_lock(&iucv_sk_list.lock);
+ sk_for_each(sk, node, &iucv_sk_list.head) {
+ if (trans_hdr->flags == AF_IUCV_FLAG_SYN) {
+ if ((!memcmp(&iucv_sk(sk)->src_name,
+ trans_hdr->destAppName, 8)) &&
+ (!memcmp(&iucv_sk(sk)->src_user_id,
+ trans_hdr->destUserID, 8)) &&
+ (!memcmp(&iucv_sk(sk)->dst_name, nullstring, 8)) &&
+ (!memcmp(&iucv_sk(sk)->dst_user_id,
+ nullstring, 8))) {
+ iucv = iucv_sk(sk);
+ break;
+ }
+ } else {
+ if ((!memcmp(&iucv_sk(sk)->src_name,
+ trans_hdr->destAppName, 8)) &&
+ (!memcmp(&iucv_sk(sk)->src_user_id,
+ trans_hdr->destUserID, 8)) &&
+ (!memcmp(&iucv_sk(sk)->dst_name,
+ trans_hdr->srcAppName, 8)) &&
+ (!memcmp(&iucv_sk(sk)->dst_user_id,
+ trans_hdr->srcUserID, 8))) {
+ iucv = iucv_sk(sk);
+ break;
+ }
+ }
+ }
+ read_unlock(&iucv_sk_list.lock);
+ if (!iucv)
+ sk = NULL;
+
+ /* no sock
+ how should we send with no sock
+ 1) send without sock no send rc checking?
+ 2) introduce default sock to handle this cases
+
+ SYN -> send SYN|ACK in good case, send SYN|FIN in bad case
+ data -> send FIN
+ SYN|ACK, SYN|FIN, FIN -> no action? */
+
+ switch (trans_hdr->flags) {
+ case AF_IUCV_FLAG_SYN:
+ /* connect request */
+ err = afiucv_hs_callback_syn(sk, skb);
+ break;
+ case (AF_IUCV_FLAG_SYN | AF_IUCV_FLAG_ACK):
+ /* connect request confirmed */
+ err = afiucv_hs_callback_synack(sk, skb);
+ break;
+ case (AF_IUCV_FLAG_SYN | AF_IUCV_FLAG_FIN):
+ /* connect request refused */
+ err = afiucv_hs_callback_synfin(sk, skb);
+ break;
+ case (AF_IUCV_FLAG_FIN):
+ /* close request */
+ err = afiucv_hs_callback_fin(sk, skb);
+ break;
+ case (AF_IUCV_FLAG_WIN):
+ err = afiucv_hs_callback_win(sk, skb);
+ if (skb->len > sizeof(struct af_iucv_trans_hdr))
+ err = afiucv_hs_callback_rx(sk, skb);
+ else
+ kfree(skb);
+ break;
+ case 0:
+ /* plain data frame */
+ err = afiucv_hs_callback_rx(sk, skb);
+ break;
+ default:
+ ;
+ }
+
+ return err;
+}
+
+/**
+ * afiucv_hs_callback_txnotify() - handle send notifcations from HiperSockets
+ * transport
+ **/
+static void afiucv_hs_callback_txnotify(struct sk_buff *skb,
+ enum iucv_tx_notify n)
+{
+ struct sock *isk = skb->sk;
+ struct sock *sk = NULL;
+ struct iucv_sock *iucv = NULL;
+ struct sk_buff_head *list;
+ struct sk_buff *list_skb;
+ struct sk_buff *this = NULL;
+ unsigned long flags;
+ struct hlist_node *node;
+
+ read_lock(&iucv_sk_list.lock);
+ sk_for_each(sk, node, &iucv_sk_list.head)
+ if (sk == isk) {
+ iucv = iucv_sk(sk);
+ break;
+ }
+ read_unlock(&iucv_sk_list.lock);
+
+ if (!iucv)
+ return;
+
+ bh_lock_sock(sk);
+ list = &iucv->send_skb_q;
+ list_skb = list->next;
+ if (skb_queue_empty(list))
+ goto out_unlock;
+
+ spin_lock_irqsave(&list->lock, flags);
+ while (list_skb != (struct sk_buff *)list) {
+ if (skb_shinfo(list_skb) == skb_shinfo(skb)) {
+ this = list_skb;
+ switch (n) {
+ case TX_NOTIFY_OK:
+ __skb_unlink(this, list);
+ iucv_sock_wake_msglim(sk);
+ kfree_skb(this);
+ break;
+ case TX_NOTIFY_PENDING:
+ atomic_inc(&iucv->pendings);
+ break;
+ case TX_NOTIFY_DELAYED_OK:
+ __skb_unlink(this, list);
+ atomic_dec(&iucv->pendings);
+ if (atomic_read(&iucv->pendings) <= 0)
+ iucv_sock_wake_msglim(sk);
+ kfree_skb(this);
+ break;
+ case TX_NOTIFY_UNREACHABLE:
+ case TX_NOTIFY_DELAYED_UNREACHABLE:
+ case TX_NOTIFY_TPQFULL: /* not yet used */
+ case TX_NOTIFY_GENERALERROR:
+ case TX_NOTIFY_DELAYED_GENERALERROR:
+ __skb_unlink(this, list);
+ kfree_skb(this);
+ if (!list_empty(&iucv->accept_q))
+ sk->sk_state = IUCV_SEVERED;
+ else
+ sk->sk_state = IUCV_DISCONN;
+ sk->sk_state_change(sk);
+ break;
+ }
+ break;
+ }
+ list_skb = list_skb->next;
+ }
+ spin_unlock_irqrestore(&list->lock, flags);
+
+out_unlock:
+ bh_unlock_sock(sk);
+}
static const struct proto_ops iucv_sock_ops = {
.family = PF_IUCV,
.owner = THIS_MODULE,
@@ -1718,71 +2320,104 @@ static const struct net_proto_family iucv_sock_family_ops = {
.create = iucv_sock_create,
};
-static int __init afiucv_init(void)
+static struct packet_type iucv_packet_type = {
+ .type = cpu_to_be16(ETH_P_AF_IUCV),
+ .func = afiucv_hs_rcv,
+};
+
+static int afiucv_iucv_init(void)
{
int err;
- if (!MACHINE_IS_VM) {
- pr_err("The af_iucv module cannot be loaded"
- " without z/VM\n");
- err = -EPROTONOSUPPORT;
- goto out;
- }
- cpcmd("QUERY USERID", iucv_userid, sizeof(iucv_userid), &err);
- if (unlikely(err)) {
- WARN_ON(err);
- err = -EPROTONOSUPPORT;
- goto out;
- }
-
- err = iucv_register(&af_iucv_handler, 0);
+ err = pr_iucv->iucv_register(&af_iucv_handler, 0);
if (err)
goto out;
- err = proto_register(&iucv_proto, 0);
- if (err)
- goto out_iucv;
- err = sock_register(&iucv_sock_family_ops);
- if (err)
- goto out_proto;
/* establish dummy device */
+ af_iucv_driver.bus = pr_iucv->bus;
err = driver_register(&af_iucv_driver);
if (err)
- goto out_sock;
+ goto out_iucv;
af_iucv_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
if (!af_iucv_dev) {
err = -ENOMEM;
goto out_driver;
}
dev_set_name(af_iucv_dev, "af_iucv");
- af_iucv_dev->bus = &iucv_bus;
- af_iucv_dev->parent = iucv_root;
+ af_iucv_dev->bus = pr_iucv->bus;
+ af_iucv_dev->parent = pr_iucv->root;
af_iucv_dev->release = (void (*)(struct device *))kfree;
af_iucv_dev->driver = &af_iucv_driver;
err = device_register(af_iucv_dev);
if (err)
goto out_driver;
-
return 0;
out_driver:
driver_unregister(&af_iucv_driver);
+out_iucv:
+ pr_iucv->iucv_unregister(&af_iucv_handler, 0);
+out:
+ return err;
+}
+
+static int __init afiucv_init(void)
+{
+ int err;
+
+ if (MACHINE_IS_VM) {
+ cpcmd("QUERY USERID", iucv_userid, sizeof(iucv_userid), &err);
+ if (unlikely(err)) {
+ WARN_ON(err);
+ err = -EPROTONOSUPPORT;
+ goto out;
+ }
+
+ pr_iucv = try_then_request_module(symbol_get(iucv_if), "iucv");
+ if (!pr_iucv) {
+ printk(KERN_WARNING "iucv_if lookup failed\n");
+ memset(&iucv_userid, 0, sizeof(iucv_userid));
+ }
+ } else {
+ memset(&iucv_userid, 0, sizeof(iucv_userid));
+ pr_iucv = NULL;
+ }
+
+ err = proto_register(&iucv_proto, 0);
+ if (err)
+ goto out;
+ err = sock_register(&iucv_sock_family_ops);
+ if (err)
+ goto out_proto;
+
+ if (pr_iucv) {
+ err = afiucv_iucv_init();
+ if (err)
+ goto out_sock;
+ }
+ dev_add_pack(&iucv_packet_type);
+ return 0;
+
out_sock:
sock_unregister(PF_IUCV);
out_proto:
proto_unregister(&iucv_proto);
-out_iucv:
- iucv_unregister(&af_iucv_handler, 0);
out:
+ if (pr_iucv)
+ symbol_put(iucv_if);
return err;
}
static void __exit afiucv_exit(void)
{
- device_unregister(af_iucv_dev);
- driver_unregister(&af_iucv_driver);
+ if (pr_iucv) {
+ device_unregister(af_iucv_dev);
+ driver_unregister(&af_iucv_driver);
+ pr_iucv->iucv_unregister(&af_iucv_handler, 0);
+ symbol_put(iucv_if);
+ }
+ dev_remove_pack(&iucv_packet_type);
sock_unregister(PF_IUCV);
proto_unregister(&iucv_proto);
- iucv_unregister(&af_iucv_handler, 0);
}
module_init(afiucv_init);
@@ -1793,3 +2428,4 @@ MODULE_DESCRIPTION("IUCV Sockets ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
MODULE_ALIAS_NETPROTO(PF_IUCV);
+
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
index 075a3808aa40..403be43b793d 100644
--- a/net/iucv/iucv.c
+++ b/net/iucv/iucv.c
@@ -1974,6 +1974,27 @@ out:
return rc;
}
+struct iucv_interface iucv_if = {
+ .message_receive = iucv_message_receive,
+ .__message_receive = __iucv_message_receive,
+ .message_reply = iucv_message_reply,
+ .message_reject = iucv_message_reject,
+ .message_send = iucv_message_send,
+ .__message_send = __iucv_message_send,
+ .message_send2way = iucv_message_send2way,
+ .message_purge = iucv_message_purge,
+ .path_accept = iucv_path_accept,
+ .path_connect = iucv_path_connect,
+ .path_quiesce = iucv_path_quiesce,
+ .path_resume = iucv_path_resume,
+ .path_sever = iucv_path_sever,
+ .iucv_register = iucv_register,
+ .iucv_unregister = iucv_unregister,
+ .bus = NULL,
+ .root = NULL,
+};
+EXPORT_SYMBOL(iucv_if);
+
/**
* iucv_init
*
@@ -2038,6 +2059,8 @@ static int __init iucv_init(void)
rc = bus_register(&iucv_bus);
if (rc)
goto out_reboot;
+ iucv_if.root = iucv_root;
+ iucv_if.bus = &iucv_bus;
return 0;
out_reboot:
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index ad4ac2601a56..34b2ddeacb67 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1045,8 +1045,10 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len
headroom = NET_SKB_PAD + sizeof(struct iphdr) +
uhlen + hdr_len;
old_headroom = skb_headroom(skb);
- if (skb_cow_head(skb, headroom))
+ if (skb_cow_head(skb, headroom)) {
+ dev_kfree_skb(skb);
goto abort;
+ }
new_headroom = skb_headroom(skb);
skb_orphan(skb);
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index f42cd0915966..8a90d756c904 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -395,6 +395,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
struct pppol2tp_session *ps;
int old_headroom;
int new_headroom;
+ int uhlen, headroom;
if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
goto abort;
@@ -413,7 +414,13 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
goto abort_put_sess;
old_headroom = skb_headroom(skb);
- if (skb_cow_head(skb, sizeof(ppph)))
+ uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(struct udphdr) : 0;
+ headroom = NET_SKB_PAD +
+ sizeof(struct iphdr) + /* IP header */
+ uhlen + /* UDP header (if L2TP_ENCAPTYPE_UDP) */
+ session->hdr_len + /* L2TP header */
+ sizeof(ppph); /* PPP header */
+ if (skb_cow_head(skb, headroom))
goto abort_put_sess_tun;
new_headroom = skb_headroom(skb);
diff --git a/net/lapb/lapb_iface.c b/net/lapb/lapb_iface.c
index 956b7e47dc52..8d0324bac01c 100644
--- a/net/lapb/lapb_iface.c
+++ b/net/lapb/lapb_iface.c
@@ -139,7 +139,8 @@ out:
return lapb;
}
-int lapb_register(struct net_device *dev, struct lapb_register_struct *callbacks)
+int lapb_register(struct net_device *dev,
+ const struct lapb_register_struct *callbacks)
{
struct lapb_cb *lapb;
int rc = LAPB_BADTOKEN;
@@ -158,7 +159,7 @@ int lapb_register(struct net_device *dev, struct lapb_register_struct *callbacks
goto out;
lapb->dev = dev;
- lapb->callbacks = *callbacks;
+ lapb->callbacks = callbacks;
__lapb_insert_cb(lapb);
@@ -380,32 +381,32 @@ int lapb_data_received(struct net_device *dev, struct sk_buff *skb)
void lapb_connect_confirmation(struct lapb_cb *lapb, int reason)
{
- if (lapb->callbacks.connect_confirmation)
- lapb->callbacks.connect_confirmation(lapb->dev, reason);
+ if (lapb->callbacks->connect_confirmation)
+ lapb->callbacks->connect_confirmation(lapb->dev, reason);
}
void lapb_connect_indication(struct lapb_cb *lapb, int reason)
{
- if (lapb->callbacks.connect_indication)
- lapb->callbacks.connect_indication(lapb->dev, reason);
+ if (lapb->callbacks->connect_indication)
+ lapb->callbacks->connect_indication(lapb->dev, reason);
}
void lapb_disconnect_confirmation(struct lapb_cb *lapb, int reason)
{
- if (lapb->callbacks.disconnect_confirmation)
- lapb->callbacks.disconnect_confirmation(lapb->dev, reason);
+ if (lapb->callbacks->disconnect_confirmation)
+ lapb->callbacks->disconnect_confirmation(lapb->dev, reason);
}
void lapb_disconnect_indication(struct lapb_cb *lapb, int reason)
{
- if (lapb->callbacks.disconnect_indication)
- lapb->callbacks.disconnect_indication(lapb->dev, reason);
+ if (lapb->callbacks->disconnect_indication)
+ lapb->callbacks->disconnect_indication(lapb->dev, reason);
}
int lapb_data_indication(struct lapb_cb *lapb, struct sk_buff *skb)
{
- if (lapb->callbacks.data_indication)
- return lapb->callbacks.data_indication(lapb->dev, skb);
+ if (lapb->callbacks->data_indication)
+ return lapb->callbacks->data_indication(lapb->dev, skb);
kfree_skb(skb);
return NET_RX_SUCCESS; /* For now; must be != NET_RX_DROP */
@@ -415,8 +416,8 @@ int lapb_data_transmit(struct lapb_cb *lapb, struct sk_buff *skb)
{
int used = 0;
- if (lapb->callbacks.data_transmit) {
- lapb->callbacks.data_transmit(lapb->dev, skb);
+ if (lapb->callbacks->data_transmit) {
+ lapb->callbacks->data_transmit(lapb->dev, skb);
used = 1;
}
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index f5fdfcbf552a..7d3b438755f0 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -199,6 +199,19 @@ config MAC80211_VERBOSE_MPL_DEBUG
Do not select this option.
+config MAC80211_VERBOSE_MPATH_DEBUG
+ bool "Verbose mesh path debugging"
+ depends on MAC80211_DEBUG_MENU
+ depends on MAC80211_MESH
+ ---help---
+ Selecting this option causes mac80211 to print out very
+ verbose mesh path selection debugging messages (when mac80211
+ is taking part in a mesh network).
+ It should not be selected on production systems as those
+ messages are remotely triggerable.
+
+ Do not select this option.
+
config MAC80211_VERBOSE_MHWMP_DEBUG
bool "Verbose mesh HWMP routing debugging"
depends on MAC80211_DEBUG_MENU
@@ -212,6 +225,18 @@ config MAC80211_VERBOSE_MHWMP_DEBUG
Do not select this option.
+config MAC80211_VERBOSE_TDLS_DEBUG
+ bool "Verbose TDLS debugging"
+ depends on MAC80211_DEBUG_MENU
+ ---help---
+ Selecting this option causes mac80211 to print out very
+ verbose TDLS selection debugging messages (when mac80211
+ is a TDLS STA).
+ It should not be selected on production systems as those
+ messages are remotely triggerable.
+
+ Do not select this option.
+
config MAC80211_DEBUG_COUNTERS
bool "Extra statistics for TX/RX debugging"
depends on MAC80211_DEBUG_MENU
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index fd1aaf2a4a6c..97f33588b65f 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -69,7 +69,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
if (!tid_rx)
return;
- rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], NULL);
+ RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL);
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n",
@@ -167,12 +167,8 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
u16 capab;
skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
-
- if (!skb) {
- printk(KERN_DEBUG "%s: failed to allocate buffer "
- "for addba resp frame\n", sdata->name);
+ if (!skb)
return;
- }
skb_reserve(skb, local->hw.extra_tx_headroom);
mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
@@ -227,7 +223,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
status = WLAN_STATUS_REQUEST_DECLINED;
- if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) {
+ if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Suspend in progress. "
"Denying ADDBA request\n");
@@ -279,14 +275,8 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
/* prepare A-MPDU MLME for Rx aggregation */
tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL);
- if (!tid_agg_rx) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- if (net_ratelimit())
- printk(KERN_ERR "allocate rx mlme to tid %d failed\n",
- tid);
-#endif
+ if (!tid_agg_rx)
goto end;
- }
spin_lock_init(&tid_agg_rx->reorder_lock);
@@ -306,11 +296,6 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
tid_agg_rx->reorder_time =
kcalloc(buf_size, sizeof(unsigned long), GFP_KERNEL);
if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- if (net_ratelimit())
- printk(KERN_ERR "can not allocate reordering buffer "
- "to tid %d\n", tid);
-#endif
kfree(tid_agg_rx->reorder_buf);
kfree(tid_agg_rx->reorder_time);
kfree(tid_agg_rx);
@@ -340,7 +325,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
status = WLAN_STATUS_SUCCESS;
/* activate it for RX */
- rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx);
+ RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx);
if (timeout)
mod_timer(&tid_agg_rx->session_timer, TU_TO_EXP_TIME(timeout));
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index c8be8eff70da..2ac033989e01 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -68,11 +68,9 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
- if (!skb) {
- printk(KERN_ERR "%s: failed to allocate buffer "
- "for addba request frame\n", sdata->name);
+ if (!skb)
return;
- }
+
skb_reserve(skb, local->hw.extra_tx_headroom);
mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
memset(mgmt, 0, 24);
@@ -106,19 +104,18 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
ieee80211_tx_skb(sdata, skb);
}
-void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn)
+void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn)
{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
struct ieee80211_bar *bar;
u16 bar_control = 0;
skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom);
- if (!skb) {
- printk(KERN_ERR "%s: failed to allocate buffer for "
- "bar frame\n", sdata->name);
+ if (!skb)
return;
- }
+
skb_reserve(skb, local->hw.extra_tx_headroom);
bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar));
memset(bar, 0, sizeof(*bar));
@@ -128,13 +125,14 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1
memcpy(bar->ta, sdata->vif.addr, ETH_ALEN);
bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL;
bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA;
- bar_control |= (u16)(tid << 12);
+ bar_control |= (u16)(tid << IEEE80211_BAR_CTRL_TID_INFO_SHIFT);
bar->control = cpu_to_le16(bar_control);
bar->start_seq_num = cpu_to_le16(ssn);
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
ieee80211_tx_skb(sdata, skb);
}
+EXPORT_SYMBOL(ieee80211_send_bar);
void ieee80211_assign_tid_tx(struct sta_info *sta, int tid,
struct tid_ampdu_tx *tid_tx)
@@ -364,7 +362,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
return -EINVAL;
if ((tid >= STA_TID_NUM) ||
- !(local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION))
+ !(local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) ||
+ (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW))
return -EINVAL;
#ifdef CONFIG_MAC80211_HT_DEBUG
@@ -383,7 +382,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
sdata->vif.type != NL80211_IFTYPE_AP)
return -EINVAL;
- if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) {
+ if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "BA sessions blocked. "
"Denying BA session request\n");
@@ -413,11 +412,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
/* prepare A-MPDU MLME for Tx aggregation */
tid_tx = kzalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
if (!tid_tx) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- if (net_ratelimit())
- printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
- tid);
-#endif
ret = -ENOMEM;
goto err_unlock_sta;
}
@@ -574,14 +568,9 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
struct ieee80211_ra_tid *ra_tid;
struct sk_buff *skb = dev_alloc_skb(0);
- if (unlikely(!skb)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- if (net_ratelimit())
- printk(KERN_WARNING "%s: Not enough memory, "
- "dropping start BA session", sdata->name);
-#endif
+ if (unlikely(!skb))
return;
- }
+
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
memcpy(&ra_tid->ra, ra, ETH_ALEN);
ra_tid->tid = tid;
@@ -727,14 +716,9 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
struct ieee80211_ra_tid *ra_tid;
struct sk_buff *skb = dev_alloc_skb(0);
- if (unlikely(!skb)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- if (net_ratelimit())
- printk(KERN_WARNING "%s: Not enough memory, "
- "dropping stop BA session", sdata->name);
-#endif
+ if (unlikely(!skb))
return;
- }
+
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
memcpy(&ra_tid->ra, ra, ETH_ALEN);
ra_tid->tid = tid;
@@ -777,18 +761,14 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid);
#endif
-
+ /*
+ * IEEE 802.11-2007 7.3.1.14:
+ * In an ADDBA Response frame, when the Status Code field
+ * is set to 0, the Buffer Size subfield is set to a value
+ * of at least 1.
+ */
if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
- == WLAN_STATUS_SUCCESS) {
- /*
- * IEEE 802.11-2007 7.3.1.14:
- * In an ADDBA Response frame, when the Status Code field
- * is set to 0, the Buffer Size subfield is set to a value
- * of at least 1.
- */
- if (!buf_size)
- goto out;
-
+ == WLAN_STATUS_SUCCESS && buf_size) {
if (test_and_set_bit(HT_AGG_STATE_RESPONSE_RECEIVED,
&tid_tx->state)) {
/* ignore duplicate response */
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 3d1b091d9b2e..ebd7fb101fbf 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <net/net_namespace.h>
#include <linux/rcupdate.h>
+#include <linux/if_ether.h>
#include <net/cfg80211.h>
#include "ieee80211_i.h"
#include "driver-ops.h"
@@ -62,7 +63,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
if (type == NL80211_IFTYPE_AP_VLAN &&
params && params->use_4addr == 0)
- rcu_assign_pointer(sdata->u.vlan.sta, NULL);
+ RCU_INIT_POINTER(sdata->u.vlan.sta, NULL);
else if (type == NL80211_IFTYPE_STATION &&
params && params->use_4addr >= 0)
sdata->u.mgd.use_4addr = params->use_4addr;
@@ -343,7 +344,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
STATION_INFO_RX_BITRATE |
STATION_INFO_RX_DROP_MISC |
STATION_INFO_BSS_PARAM |
- STATION_INFO_CONNECTED_TIME;
+ STATION_INFO_CONNECTED_TIME |
+ STATION_INFO_STA_FLAGS;
do_posix_clock_monotonic_gettime(&uptime);
sinfo->connected_time = uptime.tv_sec - sta->last_connected;
@@ -403,6 +405,23 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
sinfo->bss_param.dtim_period = sdata->local->hw.conf.ps_dtim_period;
sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int;
+
+ sinfo->sta_flags.set = 0;
+ sinfo->sta_flags.mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
+ BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
+ BIT(NL80211_STA_FLAG_WME) |
+ BIT(NL80211_STA_FLAG_MFP) |
+ BIT(NL80211_STA_FLAG_AUTHENTICATED);
+ if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+ sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
+ if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE))
+ sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
+ if (test_sta_flag(sta, WLAN_STA_WME))
+ sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_WME);
+ if (test_sta_flag(sta, WLAN_STA_MFP))
+ sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP);
+ if (test_sta_flag(sta, WLAN_STA_AUTH))
+ sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
}
@@ -455,6 +474,20 @@ 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);
+}
+
/*
* This handles both adding a beacon and setting new beacon info
*/
@@ -542,14 +575,17 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
sdata->vif.bss_conf.dtim_period = new->dtim_period;
- rcu_assign_pointer(sdata->u.ap.beacon, new);
+ RCU_INIT_POINTER(sdata->u.ap.beacon, new);
synchronize_rcu();
kfree(old);
+ ieee80211_config_ap_ssid(sdata, params);
+
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
- BSS_CHANGED_BEACON);
+ BSS_CHANGED_BEACON |
+ BSS_CHANGED_SSID);
return 0;
}
@@ -594,7 +630,7 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
if (!old)
return -ENOENT;
- rcu_assign_pointer(sdata->u.ap.beacon, NULL);
+ RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
synchronize_rcu();
kfree(old);
@@ -650,7 +686,6 @@ static void sta_apply_parameters(struct ieee80211_local *local,
struct sta_info *sta,
struct station_parameters *params)
{
- unsigned long flags;
u32 rates;
int i, j;
struct ieee80211_supported_band *sband;
@@ -659,43 +694,58 @@ static void sta_apply_parameters(struct ieee80211_local *local,
sband = local->hw.wiphy->bands[local->oper_channel->band];
- spin_lock_irqsave(&sta->flaglock, flags);
mask = params->sta_flags_mask;
set = params->sta_flags_set;
if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
- sta->flags &= ~WLAN_STA_AUTHORIZED;
if (set & BIT(NL80211_STA_FLAG_AUTHORIZED))
- sta->flags |= WLAN_STA_AUTHORIZED;
+ set_sta_flag(sta, WLAN_STA_AUTHORIZED);
+ else
+ clear_sta_flag(sta, WLAN_STA_AUTHORIZED);
}
if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
- sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE))
- sta->flags |= WLAN_STA_SHORT_PREAMBLE;
+ set_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE);
+ else
+ clear_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE);
}
if (mask & BIT(NL80211_STA_FLAG_WME)) {
- sta->flags &= ~WLAN_STA_WME;
- sta->sta.wme = false;
if (set & BIT(NL80211_STA_FLAG_WME)) {
- sta->flags |= WLAN_STA_WME;
+ set_sta_flag(sta, WLAN_STA_WME);
sta->sta.wme = true;
+ } else {
+ clear_sta_flag(sta, WLAN_STA_WME);
+ sta->sta.wme = false;
}
}
if (mask & BIT(NL80211_STA_FLAG_MFP)) {
- sta->flags &= ~WLAN_STA_MFP;
if (set & BIT(NL80211_STA_FLAG_MFP))
- sta->flags |= WLAN_STA_MFP;
+ set_sta_flag(sta, WLAN_STA_MFP);
+ else
+ clear_sta_flag(sta, WLAN_STA_MFP);
}
if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
- sta->flags &= ~WLAN_STA_AUTH;
if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED))
- sta->flags |= WLAN_STA_AUTH;
+ set_sta_flag(sta, WLAN_STA_AUTH);
+ else
+ clear_sta_flag(sta, WLAN_STA_AUTH);
+ }
+
+ if (mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
+ if (set & BIT(NL80211_STA_FLAG_TDLS_PEER))
+ set_sta_flag(sta, WLAN_STA_TDLS_PEER);
+ else
+ clear_sta_flag(sta, WLAN_STA_TDLS_PEER);
+ }
+
+ if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD) {
+ sta->sta.uapsd_queues = params->uapsd_queues;
+ sta->sta.max_sp = params->max_sp;
}
- spin_unlock_irqrestore(&sta->flaglock, flags);
/*
* cfg80211 validates this (1-2007) and allows setting the AID
@@ -786,10 +836,17 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
if (!sta)
return -ENOMEM;
- sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
+ set_sta_flag(sta, WLAN_STA_AUTH);
+ set_sta_flag(sta, WLAN_STA_ASSOC);
sta_apply_parameters(local, sta, params);
+ /* Only TDLS-supporting stations can add TDLS peers */
+ if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
+ !((wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
+ sdata->vif.type == NL80211_IFTYPE_STATION))
+ return -ENOTSUPP;
+
rate_control_rate_init(sta);
layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
@@ -842,6 +899,14 @@ static int ieee80211_change_station(struct wiphy *wiphy,
return -ENOENT;
}
+ /* The TDLS bit cannot be toggled after the STA was added */
+ if ((params->sta_flags_mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
+ !!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) !=
+ !!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+
if (params->vlan && params->vlan != sta->sdata->dev) {
vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
@@ -857,7 +922,7 @@ static int ieee80211_change_station(struct wiphy *wiphy,
return -EBUSY;
}
- rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
+ RCU_INIT_POINTER(vlansdata->u.vlan.sta, sta);
}
sta->sdata = vlansdata;
@@ -918,7 +983,7 @@ static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev,
if (dst)
return mesh_path_del(dst, sdata);
- mesh_path_flush(sdata);
+ mesh_path_flush_by_iface(sdata);
return 0;
}
@@ -1137,6 +1202,22 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
conf->dot11MeshHWMPRootMode = nconf->dot11MeshHWMPRootMode;
ieee80211_mesh_root_setup(ifmsh);
}
+ if (_chg_mesh_attr(NL80211_MESHCONF_GATE_ANNOUNCEMENTS, mask)) {
+ /* our current gate announcement implementation rides on root
+ * announcements, so require this ifmsh to also be a root node
+ * */
+ if (nconf->dot11MeshGateAnnouncementProtocol &&
+ !conf->dot11MeshHWMPRootMode) {
+ conf->dot11MeshHWMPRootMode = 1;
+ ieee80211_mesh_root_setup(ifmsh);
+ }
+ conf->dot11MeshGateAnnouncementProtocol =
+ nconf->dot11MeshGateAnnouncementProtocol;
+ }
+ if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_RANN_INTERVAL, mask)) {
+ conf->dot11MeshHWMPRannInterval =
+ nconf->dot11MeshHWMPRannInterval;
+ }
return 0;
}
@@ -1235,9 +1316,11 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
}
static int ieee80211_set_txq_params(struct wiphy *wiphy,
+ struct net_device *dev,
struct ieee80211_txq_params *params)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_tx_queue_params p;
if (!local->ops->conf_tx)
@@ -1258,8 +1341,8 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
if (params->queue >= local->hw.queues)
return -EINVAL;
- local->tx_conf[params->queue] = p;
- if (drv_conf_tx(local, params->queue, &p)) {
+ sdata->tx_conf[params->queue] = p;
+ if (drv_conf_tx(local, sdata, params->queue, &p)) {
wiphy_debug(local->hw.wiphy,
"failed to set TX queue parameters for queue %d\n",
params->queue);
@@ -1821,7 +1904,7 @@ ieee80211_offchan_tx_done(struct ieee80211_work *wk, struct sk_buff *skb)
* so in that case userspace will have to deal with it.
*/
- if (wk->offchan_tx.wait && wk->offchan_tx.frame)
+ if (wk->offchan_tx.wait && !wk->offchan_tx.status)
cfg80211_mgmt_tx_status(wk->sdata->dev,
(unsigned long) wk->offchan_tx.frame,
wk->ie, wk->ie_len, false, GFP_KERNEL);
@@ -1833,7 +1916,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan, bool offchan,
enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait,
- const u8 *buf, size_t len, u64 *cookie)
+ const u8 *buf, size_t len, bool no_cck,
+ u64 *cookie)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
@@ -1860,6 +1944,9 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
}
+ if (no_cck)
+ flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
+
if (is_offchan && !offchan)
return -EBUSY;
@@ -1898,33 +1985,6 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
*cookie = (unsigned long) skb;
- if (is_offchan && local->ops->offchannel_tx) {
- int ret;
-
- IEEE80211_SKB_CB(skb)->band = chan->band;
-
- mutex_lock(&local->mtx);
-
- if (local->hw_offchan_tx_cookie) {
- mutex_unlock(&local->mtx);
- return -EBUSY;
- }
-
- /* TODO: bitrate control, TX processing? */
- ret = drv_offchannel_tx(local, skb, chan, channel_type, wait);
-
- if (ret == 0)
- local->hw_offchan_tx_cookie = *cookie;
- mutex_unlock(&local->mtx);
-
- /*
- * Allow driver to return 1 to indicate it wants to have the
- * frame transmitted with a remain_on_channel + regular TX.
- */
- if (ret != 1)
- return ret;
- }
-
if (is_offchan && local->ops->remain_on_channel) {
unsigned int duration;
int ret;
@@ -2011,18 +2071,6 @@ static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
mutex_lock(&local->mtx);
- if (local->ops->offchannel_tx_cancel_wait &&
- local->hw_offchan_tx_cookie == cookie) {
- ret = drv_offchannel_tx_cancel_wait(local);
-
- if (!ret)
- local->hw_offchan_tx_cookie = 0;
-
- mutex_unlock(&local->mtx);
-
- return ret;
- }
-
if (local->ops->cancel_remain_on_channel) {
cookie ^= 2;
ret = ieee80211_cancel_remain_on_channel_hw(local, cookie);
@@ -2123,6 +2171,323 @@ static int ieee80211_set_rekey_data(struct wiphy *wiphy,
return 0;
}
+static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb)
+{
+ u8 *pos = (void *)skb_put(skb, 7);
+
+ *pos++ = WLAN_EID_EXT_CAPABILITY;
+ *pos++ = 5; /* len */
+ *pos++ = 0x0;
+ *pos++ = 0x0;
+ *pos++ = 0x0;
+ *pos++ = 0x0;
+ *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED;
+}
+
+static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ u16 capab;
+
+ capab = 0;
+ if (local->oper_channel->band != IEEE80211_BAND_2GHZ)
+ return capab;
+
+ if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
+ capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
+ if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
+ capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
+
+ return capab;
+}
+
+static void ieee80211_tdls_add_link_ie(struct sk_buff *skb, u8 *src_addr,
+ u8 *peer, u8 *bssid)
+{
+ struct ieee80211_tdls_lnkie *lnkid;
+
+ lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie));
+
+ lnkid->ie_type = WLAN_EID_LINK_ID;
+ lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2;
+
+ memcpy(lnkid->bssid, bssid, ETH_ALEN);
+ memcpy(lnkid->init_sta, src_addr, ETH_ALEN);
+ memcpy(lnkid->resp_sta, peer, ETH_ALEN);
+}
+
+static int
+ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, u8 action_code, u8 dialog_token,
+ u16 status_code, struct sk_buff *skb)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_tdls_data *tf;
+
+ tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
+
+ memcpy(tf->da, peer, ETH_ALEN);
+ memcpy(tf->sa, sdata->vif.addr, ETH_ALEN);
+ tf->ether_type = cpu_to_be16(ETH_P_TDLS);
+ tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;
+
+ switch (action_code) {
+ case WLAN_TDLS_SETUP_REQUEST:
+ tf->category = WLAN_CATEGORY_TDLS;
+ tf->action_code = WLAN_TDLS_SETUP_REQUEST;
+
+ skb_put(skb, sizeof(tf->u.setup_req));
+ tf->u.setup_req.dialog_token = dialog_token;
+ tf->u.setup_req.capability =
+ cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
+
+ ieee80211_add_srates_ie(&sdata->vif, skb);
+ ieee80211_add_ext_srates_ie(&sdata->vif, skb);
+ ieee80211_tdls_add_ext_capab(skb);
+ break;
+ case WLAN_TDLS_SETUP_RESPONSE:
+ tf->category = WLAN_CATEGORY_TDLS;
+ tf->action_code = WLAN_TDLS_SETUP_RESPONSE;
+
+ skb_put(skb, sizeof(tf->u.setup_resp));
+ tf->u.setup_resp.status_code = cpu_to_le16(status_code);
+ tf->u.setup_resp.dialog_token = dialog_token;
+ tf->u.setup_resp.capability =
+ cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
+
+ ieee80211_add_srates_ie(&sdata->vif, skb);
+ ieee80211_add_ext_srates_ie(&sdata->vif, skb);
+ ieee80211_tdls_add_ext_capab(skb);
+ break;
+ case WLAN_TDLS_SETUP_CONFIRM:
+ tf->category = WLAN_CATEGORY_TDLS;
+ tf->action_code = WLAN_TDLS_SETUP_CONFIRM;
+
+ skb_put(skb, sizeof(tf->u.setup_cfm));
+ tf->u.setup_cfm.status_code = cpu_to_le16(status_code);
+ tf->u.setup_cfm.dialog_token = dialog_token;
+ break;
+ case WLAN_TDLS_TEARDOWN:
+ tf->category = WLAN_CATEGORY_TDLS;
+ tf->action_code = WLAN_TDLS_TEARDOWN;
+
+ skb_put(skb, sizeof(tf->u.teardown));
+ tf->u.teardown.reason_code = cpu_to_le16(status_code);
+ break;
+ case WLAN_TDLS_DISCOVERY_REQUEST:
+ tf->category = WLAN_CATEGORY_TDLS;
+ tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST;
+
+ skb_put(skb, sizeof(tf->u.discover_req));
+ tf->u.discover_req.dialog_token = dialog_token;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, u8 action_code, u8 dialog_token,
+ u16 status_code, struct sk_buff *skb)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_mgmt *mgmt;
+
+ mgmt = (void *)skb_put(skb, 24);
+ memset(mgmt, 0, 24);
+ memcpy(mgmt->da, peer, ETH_ALEN);
+ memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
+ memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
+
+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION);
+
+ switch (action_code) {
+ case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
+ skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp));
+ mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
+ mgmt->u.action.u.tdls_discover_resp.action_code =
+ WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
+ mgmt->u.action.u.tdls_discover_resp.dialog_token =
+ dialog_token;
+ mgmt->u.action.u.tdls_discover_resp.capability =
+ cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
+
+ ieee80211_add_srates_ie(&sdata->vif, skb);
+ ieee80211_add_ext_srates_ie(&sdata->vif, skb);
+ ieee80211_tdls_add_ext_capab(skb);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, u8 action_code, u8 dialog_token,
+ u16 status_code, const u8 *extra_ies,
+ size_t extra_ies_len)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_tx_info *info;
+ struct sk_buff *skb = NULL;
+ bool send_direct;
+ int ret;
+
+ if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
+ return -ENOTSUPP;
+
+ /* make sure we are in managed mode, and associated */
+ if (sdata->vif.type != NL80211_IFTYPE_STATION ||
+ !sdata->u.mgd.associated)
+ return -EINVAL;
+
+#ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG
+ printk(KERN_DEBUG "TDLS mgmt action %d peer %pM\n", action_code, peer);
+#endif
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+ max(sizeof(struct ieee80211_mgmt),
+ sizeof(struct ieee80211_tdls_data)) +
+ 50 + /* supported rates */
+ 7 + /* ext capab */
+ extra_ies_len +
+ sizeof(struct ieee80211_tdls_lnkie));
+ if (!skb)
+ return -ENOMEM;
+
+ info = IEEE80211_SKB_CB(skb);
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ switch (action_code) {
+ case WLAN_TDLS_SETUP_REQUEST:
+ case WLAN_TDLS_SETUP_RESPONSE:
+ case WLAN_TDLS_SETUP_CONFIRM:
+ case WLAN_TDLS_TEARDOWN:
+ case WLAN_TDLS_DISCOVERY_REQUEST:
+ ret = ieee80211_prep_tdls_encap_data(wiphy, dev, peer,
+ action_code, dialog_token,
+ status_code, skb);
+ send_direct = false;
+ break;
+ case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
+ ret = ieee80211_prep_tdls_direct(wiphy, dev, peer, action_code,
+ dialog_token, status_code,
+ skb);
+ send_direct = true;
+ break;
+ default:
+ ret = -ENOTSUPP;
+ break;
+ }
+
+ if (ret < 0)
+ goto fail;
+
+ if (extra_ies_len)
+ memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len);
+
+ /* the TDLS link IE is always added last */
+ switch (action_code) {
+ case WLAN_TDLS_SETUP_REQUEST:
+ case WLAN_TDLS_SETUP_CONFIRM:
+ case WLAN_TDLS_TEARDOWN:
+ case WLAN_TDLS_DISCOVERY_REQUEST:
+ /* we are the initiator */
+ ieee80211_tdls_add_link_ie(skb, sdata->vif.addr, peer,
+ sdata->u.mgd.bssid);
+ break;
+ case WLAN_TDLS_SETUP_RESPONSE:
+ case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
+ /* we are the responder */
+ ieee80211_tdls_add_link_ie(skb, peer, sdata->vif.addr,
+ sdata->u.mgd.bssid);
+ break;
+ default:
+ ret = -ENOTSUPP;
+ goto fail;
+ }
+
+ if (send_direct) {
+ ieee80211_tx_skb(sdata, skb);
+ return 0;
+ }
+
+ /*
+ * According to 802.11z: Setup req/resp are sent in AC_BK, otherwise
+ * we should default to AC_VI.
+ */
+ switch (action_code) {
+ case WLAN_TDLS_SETUP_REQUEST:
+ case WLAN_TDLS_SETUP_RESPONSE:
+ skb_set_queue_mapping(skb, IEEE80211_AC_BK);
+ skb->priority = 2;
+ break;
+ default:
+ skb_set_queue_mapping(skb, IEEE80211_AC_VI);
+ skb->priority = 5;
+ break;
+ }
+
+ /* disable bottom halves when entering the Tx path */
+ local_bh_disable();
+ ret = ieee80211_subif_start_xmit(skb, dev);
+ local_bh_enable();
+
+ return ret;
+
+fail:
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, enum nl80211_tdls_operation oper)
+{
+ struct sta_info *sta;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
+ return -ENOTSUPP;
+
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ return -EINVAL;
+
+#ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG
+ printk(KERN_DEBUG "TDLS oper %d peer %pM\n", oper, peer);
+#endif
+
+ switch (oper) {
+ case NL80211_TDLS_ENABLE_LINK:
+ rcu_read_lock();
+ sta = sta_info_get(sdata, peer);
+ if (!sta) {
+ rcu_read_unlock();
+ return -ENOLINK;
+ }
+
+ set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH);
+ rcu_read_unlock();
+ break;
+ case NL80211_TDLS_DISABLE_LINK:
+ return sta_info_destroy_addr(sdata, peer);
+ case NL80211_TDLS_TEARDOWN:
+ case NL80211_TDLS_SETUP:
+ case NL80211_TDLS_DISCOVERY_REQ:
+ /* We don't support in-driver setup/teardown/discovery */
+ return -ENOTSUPP;
+ default:
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -2186,4 +2551,6 @@ struct cfg80211_ops mac80211_config_ops = {
.set_ringparam = ieee80211_set_ringparam,
.get_ringparam = ieee80211_get_ringparam,
.set_rekey_data = ieee80211_set_rekey_data,
+ .tdls_oper = ieee80211_tdls_oper,
+ .tdls_mgmt = ieee80211_tdls_mgmt,
};
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 186e02f7cc32..883996b2f99f 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -78,57 +78,6 @@ DEBUGFS_READONLY_FILE(wep_iv, "%#08x",
DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s",
local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver");
-static ssize_t tsf_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ieee80211_local *local = file->private_data;
- u64 tsf;
-
- tsf = drv_get_tsf(local);
-
- return mac80211_format_buffer(user_buf, count, ppos, "0x%016llx\n",
- (unsigned long long) tsf);
-}
-
-static ssize_t tsf_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ieee80211_local *local = file->private_data;
- unsigned long long tsf;
- char buf[100];
- size_t len;
-
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
- buf[len] = '\0';
-
- if (strncmp(buf, "reset", 5) == 0) {
- if (local->ops->reset_tsf) {
- drv_reset_tsf(local);
- wiphy_info(local->hw.wiphy, "debugfs reset TSF\n");
- }
- } else {
- tsf = simple_strtoul(buf, NULL, 0);
- if (local->ops->set_tsf) {
- drv_set_tsf(local, tsf);
- wiphy_info(local->hw.wiphy,
- "debugfs set TSF to %#018llx\n", tsf);
-
- }
- }
-
- return count;
-}
-
-static const struct file_operations tsf_ops = {
- .read = tsf_read,
- .write = tsf_write,
- .open = mac80211_open_file_generic,
- .llseek = default_llseek,
-};
-
static ssize_t reset_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
@@ -195,20 +144,12 @@ static ssize_t uapsd_queues_write(struct file *file,
size_t count, loff_t *ppos)
{
struct ieee80211_local *local = file->private_data;
- unsigned long val;
- char buf[10];
- size_t len;
+ u8 val;
int ret;
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
- buf[len] = '\0';
-
- ret = strict_strtoul(buf, 0, &val);
-
+ ret = kstrtou8_from_user(user_buf, count, 0, &val);
if (ret)
- return -EINVAL;
+ return ret;
if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
return -ERANGE;
@@ -305,6 +246,9 @@ static ssize_t hwflags_read(struct file *file, char __user *user_buf,
char *buf = kzalloc(mxln, GFP_KERNEL);
int sf = 0; /* how many written so far */
+ if (!buf)
+ return 0;
+
sf += snprintf(buf, mxln - sf, "0x%x\n", local->hw.flags);
if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
sf += snprintf(buf + sf, mxln - sf, "HAS_RATE_CONTROL\n");
@@ -355,6 +299,8 @@ static ssize_t hwflags_read(struct file *file, char __user *user_buf,
sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PER_STA_GTK\n");
if (local->hw.flags & IEEE80211_HW_AP_LINK_PS)
sf += snprintf(buf + sf, mxln - sf, "AP_LINK_PS\n");
+ if (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW)
+ sf += snprintf(buf + sf, mxln - sf, "TX_AMPDU_SETUP_IN_HW\n");
rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
kfree(buf);
@@ -450,7 +396,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
DEBUGFS_ADD(frequency);
DEBUGFS_ADD(total_ps_buffered);
DEBUGFS_ADD(wep_iv);
- DEBUGFS_ADD(tsf);
DEBUGFS_ADD(queues);
DEBUGFS_ADD_MODE(reset, 0200);
DEBUGFS_ADD(noack);
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 9ea7c0d0103f..9352819a986b 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -21,6 +21,7 @@
#include "rate.h"
#include "debugfs.h"
#include "debugfs_netdev.h"
+#include "driver-ops.h"
static ssize_t ieee80211_if_read(
struct ieee80211_sub_if_data *sdata,
@@ -331,6 +332,46 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast(
}
__IEEE80211_IF_FILE(num_buffered_multicast, NULL);
+/* IBSS attributes */
+static ssize_t ieee80211_if_fmt_tsf(
+ const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
+{
+ struct ieee80211_local *local = sdata->local;
+ u64 tsf;
+
+ tsf = drv_get_tsf(local, (struct ieee80211_sub_if_data *)sdata);
+
+ return scnprintf(buf, buflen, "0x%016llx\n", (unsigned long long) tsf);
+}
+
+static ssize_t ieee80211_if_parse_tsf(
+ struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
+{
+ struct ieee80211_local *local = sdata->local;
+ unsigned long long tsf;
+ int ret;
+
+ if (strncmp(buf, "reset", 5) == 0) {
+ if (local->ops->reset_tsf) {
+ drv_reset_tsf(local, sdata);
+ wiphy_info(local->hw.wiphy, "debugfs reset TSF\n");
+ }
+ } else {
+ ret = kstrtoull(buf, 10, &tsf);
+ if (ret < 0)
+ return -EINVAL;
+ if (local->ops->set_tsf) {
+ drv_set_tsf(local, sdata, tsf);
+ wiphy_info(local->hw.wiphy,
+ "debugfs set TSF to %#018llx\n", tsf);
+ }
+ }
+
+ return buflen;
+}
+__IEEE80211_IF_FILE_W(tsf);
+
+
/* WDS attributes */
IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
@@ -340,6 +381,8 @@ IEEE80211_IF_FILE(fwded_mcast, u.mesh.mshstats.fwded_mcast, DEC);
IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC);
IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC);
IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC);
+IEEE80211_IF_FILE(dropped_frames_congestion,
+ u.mesh.mshstats.dropped_frames_congestion, DEC);
IEEE80211_IF_FILE(dropped_frames_no_route,
u.mesh.mshstats.dropped_frames_no_route, DEC);
IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC);
@@ -372,6 +415,10 @@ IEEE80211_IF_FILE(min_discovery_timeout,
u.mesh.mshcfg.min_discovery_timeout, DEC);
IEEE80211_IF_FILE(dot11MeshHWMPRootMode,
u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC);
+IEEE80211_IF_FILE(dot11MeshGateAnnouncementProtocol,
+ u.mesh.mshcfg.dot11MeshGateAnnouncementProtocol, DEC);
+IEEE80211_IF_FILE(dot11MeshHWMPRannInterval,
+ u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC);
#endif
@@ -415,6 +462,11 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
}
+static void add_ibss_files(struct ieee80211_sub_if_data *sdata)
+{
+ DEBUGFS_ADD_MODE(tsf, 0600);
+}
+
static void add_wds_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_ADD(drop_unencrypted);
@@ -459,6 +511,7 @@ static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
MESHSTATS_ADD(fwded_frames);
MESHSTATS_ADD(dropped_frames_ttl);
MESHSTATS_ADD(dropped_frames_no_route);
+ MESHSTATS_ADD(dropped_frames_congestion);
MESHSTATS_ADD(estab_plinks);
#undef MESHSTATS_ADD
}
@@ -485,7 +538,9 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries);
MESHPARAMS_ADD(path_refresh_time);
MESHPARAMS_ADD(min_discovery_timeout);
-
+ MESHPARAMS_ADD(dot11MeshHWMPRootMode);
+ MESHPARAMS_ADD(dot11MeshHWMPRannInterval);
+ MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol);
#undef MESHPARAMS_ADD
}
#endif
@@ -506,7 +561,7 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
add_sta_files(sdata);
break;
case NL80211_IFTYPE_ADHOC:
- /* XXX */
+ add_ibss_files(sdata);
break;
case NL80211_IFTYPE_AP:
add_ap_files(sdata);
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index a01d2137fddc..c5f341798c16 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -56,19 +56,22 @@ STA_FILE(last_signal, last_signal, D);
static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
- char buf[100];
+ char buf[121];
struct sta_info *sta = file->private_data;
- u32 staflags = get_sta_flags(sta);
- int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s",
- staflags & WLAN_STA_AUTH ? "AUTH\n" : "",
- staflags & WLAN_STA_ASSOC ? "ASSOC\n" : "",
- staflags & WLAN_STA_PS_STA ? "PS (sta)\n" : "",
- staflags & WLAN_STA_PS_DRIVER ? "PS (driver)\n" : "",
- staflags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
- staflags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "",
- staflags & WLAN_STA_WME ? "WME\n" : "",
- staflags & WLAN_STA_WDS ? "WDS\n" : "",
- staflags & WLAN_STA_MFP ? "MFP\n" : "");
+
+#define TEST(flg) \
+ test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : ""
+
+ int res = scnprintf(buf, sizeof(buf),
+ "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
+ TEST(PS_DRIVER), TEST(AUTHORIZED),
+ TEST(SHORT_PREAMBLE), TEST(ASSOC_AP),
+ TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT),
+ TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
+ TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
+ TEST(TDLS_PEER_AUTH));
+#undef TEST
return simple_read_from_buffer(userbuf, count, ppos, buf, res);
}
STA_OPS(flags);
@@ -78,8 +81,14 @@ static ssize_t sta_num_ps_buf_frames_read(struct file *file,
size_t count, loff_t *ppos)
{
struct sta_info *sta = file->private_data;
- return mac80211_format_buffer(userbuf, count, ppos, "%u\n",
- skb_queue_len(&sta->ps_tx_buf));
+ char buf[17*IEEE80211_NUM_ACS], *p = buf;
+ int ac;
+
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+ p += scnprintf(p, sizeof(buf)+buf-p, "AC%d: %d\n", ac,
+ skb_queue_len(&sta->ps_tx_buf[ac]) +
+ skb_queue_len(&sta->tx_filtered[ac]));
+ return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
}
STA_OPS(num_ps_buf_frames);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 1425380983f7..5f165d7eb2db 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -413,50 +413,56 @@ static inline void drv_sta_remove(struct ieee80211_local *local,
trace_drv_return_void(local);
}
-static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue,
+static inline int drv_conf_tx(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
int ret = -EOPNOTSUPP;
might_sleep();
- trace_drv_conf_tx(local, queue, params);
+ trace_drv_conf_tx(local, sdata, queue, params);
if (local->ops->conf_tx)
- ret = local->ops->conf_tx(&local->hw, queue, params);
+ ret = local->ops->conf_tx(&local->hw, &sdata->vif,
+ queue, params);
trace_drv_return_int(local, ret);
return ret;
}
-static inline u64 drv_get_tsf(struct ieee80211_local *local)
+static inline u64 drv_get_tsf(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata)
{
u64 ret = -1ULL;
might_sleep();
- trace_drv_get_tsf(local);
+ trace_drv_get_tsf(local, sdata);
if (local->ops->get_tsf)
- ret = local->ops->get_tsf(&local->hw);
+ ret = local->ops->get_tsf(&local->hw, &sdata->vif);
trace_drv_return_u64(local, ret);
return ret;
}
-static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf)
+static inline void drv_set_tsf(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ u64 tsf)
{
might_sleep();
- trace_drv_set_tsf(local, tsf);
+ trace_drv_set_tsf(local, sdata, tsf);
if (local->ops->set_tsf)
- local->ops->set_tsf(&local->hw, tsf);
+ local->ops->set_tsf(&local->hw, &sdata->vif, tsf);
trace_drv_return_void(local);
}
-static inline void drv_reset_tsf(struct ieee80211_local *local)
+static inline void drv_reset_tsf(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata)
{
might_sleep();
- trace_drv_reset_tsf(local);
+ trace_drv_reset_tsf(local, sdata);
if (local->ops->reset_tsf)
- local->ops->reset_tsf(&local->hw);
+ local->ops->reset_tsf(&local->hw, &sdata->vif);
trace_drv_return_void(local);
}
@@ -590,37 +596,6 @@ static inline int drv_cancel_remain_on_channel(struct ieee80211_local *local)
return ret;
}
-static inline int drv_offchannel_tx(struct ieee80211_local *local,
- struct sk_buff *skb,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
- unsigned int wait)
-{
- int ret;
-
- might_sleep();
-
- trace_drv_offchannel_tx(local, skb, chan, channel_type, wait);
- ret = local->ops->offchannel_tx(&local->hw, skb, chan,
- channel_type, wait);
- trace_drv_return_int(local, ret);
-
- return ret;
-}
-
-static inline int drv_offchannel_tx_cancel_wait(struct ieee80211_local *local)
-{
- int ret;
-
- might_sleep();
-
- trace_drv_offchannel_tx_cancel_wait(local);
- ret = local->ops->offchannel_tx_cancel_wait(&local->hw);
- trace_drv_return_int(local, ret);
-
- return ret;
-}
-
static inline int drv_set_ringparam(struct ieee80211_local *local,
u32 tx, u32 rx)
{
@@ -696,4 +671,34 @@ static inline void drv_rssi_callback(struct ieee80211_local *local,
local->ops->rssi_callback(&local->hw, event);
trace_drv_return_void(local);
}
+
+static inline void
+drv_release_buffered_frames(struct ieee80211_local *local,
+ struct sta_info *sta, u16 tids, int num_frames,
+ enum ieee80211_frame_release_type reason,
+ bool more_data)
+{
+ trace_drv_release_buffered_frames(local, &sta->sta, tids, num_frames,
+ reason, more_data);
+ if (local->ops->release_buffered_frames)
+ local->ops->release_buffered_frames(&local->hw, &sta->sta, tids,
+ num_frames, reason,
+ more_data);
+ trace_drv_return_void(local);
+}
+
+static inline void
+drv_allow_buffered_frames(struct ieee80211_local *local,
+ struct sta_info *sta, u16 tids, int num_frames,
+ enum ieee80211_frame_release_type reason,
+ bool more_data)
+{
+ trace_drv_allow_buffered_frames(local, &sta->sta, tids, num_frames,
+ reason, more_data);
+ if (local->ops->allow_buffered_frames)
+ local->ops->allow_buffered_frames(&local->hw, &sta->sta,
+ tids, num_frames, reason,
+ more_data);
+ trace_drv_return_void(local);
+}
#endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index f47b00dc7afd..2af4fca55337 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -697,64 +697,76 @@ TRACE_EVENT(drv_sta_remove,
);
TRACE_EVENT(drv_conf_tx,
- TP_PROTO(struct ieee80211_local *local, u16 queue,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ u16 queue,
const struct ieee80211_tx_queue_params *params),
- TP_ARGS(local, queue, params),
+ TP_ARGS(local, sdata, queue, params),
TP_STRUCT__entry(
LOCAL_ENTRY
+ VIF_ENTRY
__field(u16, queue)
__field(u16, txop)
__field(u16, cw_min)
__field(u16, cw_max)
__field(u8, aifs)
+ __field(bool, uapsd)
),
TP_fast_assign(
LOCAL_ASSIGN;
+ VIF_ASSIGN;
__entry->queue = queue;
__entry->txop = params->txop;
__entry->cw_max = params->cw_max;
__entry->cw_min = params->cw_min;
__entry->aifs = params->aifs;
+ __entry->uapsd = params->uapsd;
),
TP_printk(
- LOCAL_PR_FMT " queue:%d",
- LOCAL_PR_ARG, __entry->queue
+ LOCAL_PR_FMT VIF_PR_FMT " queue:%d",
+ LOCAL_PR_ARG, VIF_PR_ARG, __entry->queue
)
);
-DEFINE_EVENT(local_only_evt, drv_get_tsf,
- TP_PROTO(struct ieee80211_local *local),
- TP_ARGS(local)
+DEFINE_EVENT(local_sdata_evt, drv_get_tsf,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata),
+ TP_ARGS(local, sdata)
);
TRACE_EVENT(drv_set_tsf,
- TP_PROTO(struct ieee80211_local *local, u64 tsf),
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ u64 tsf),
- TP_ARGS(local, tsf),
+ TP_ARGS(local, sdata, tsf),
TP_STRUCT__entry(
LOCAL_ENTRY
+ VIF_ENTRY
__field(u64, tsf)
),
TP_fast_assign(
LOCAL_ASSIGN;
+ VIF_ASSIGN;
__entry->tsf = tsf;
),
TP_printk(
- LOCAL_PR_FMT " tsf:%llu",
- LOCAL_PR_ARG, (unsigned long long)__entry->tsf
+ LOCAL_PR_FMT VIF_PR_FMT " tsf:%llu",
+ LOCAL_PR_ARG, VIF_PR_ARG, (unsigned long long)__entry->tsf
)
);
-DEFINE_EVENT(local_only_evt, drv_reset_tsf,
- TP_PROTO(struct ieee80211_local *local),
- TP_ARGS(local)
+DEFINE_EVENT(local_sdata_evt, drv_reset_tsf,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata),
+ TP_ARGS(local, sdata)
);
DEFINE_EVENT(local_only_evt, drv_tx_last_beacon,
@@ -1117,6 +1129,61 @@ TRACE_EVENT(drv_rssi_callback,
)
);
+DECLARE_EVENT_CLASS(release_evt,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sta *sta,
+ u16 tids, int num_frames,
+ enum ieee80211_frame_release_type reason,
+ bool more_data),
+
+ TP_ARGS(local, sta, tids, num_frames, reason, more_data),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ STA_ENTRY
+ __field(u16, tids)
+ __field(int, num_frames)
+ __field(int, reason)
+ __field(bool, more_data)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ STA_ASSIGN;
+ __entry->tids = tids;
+ __entry->num_frames = num_frames;
+ __entry->reason = reason;
+ __entry->more_data = more_data;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT STA_PR_FMT
+ " TIDs:0x%.4x frames:%d reason:%d more:%d",
+ LOCAL_PR_ARG, STA_PR_ARG, __entry->tids, __entry->num_frames,
+ __entry->reason, __entry->more_data
+ )
+);
+
+DEFINE_EVENT(release_evt, drv_release_buffered_frames,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sta *sta,
+ u16 tids, int num_frames,
+ enum ieee80211_frame_release_type reason,
+ bool more_data),
+
+ TP_ARGS(local, sta, tids, num_frames, reason, more_data)
+);
+
+DEFINE_EVENT(release_evt, drv_allow_buffered_frames,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sta *sta,
+ u16 tids, int num_frames,
+ enum ieee80211_frame_release_type reason,
+ bool more_data),
+
+ TP_ARGS(local, sta, tids, num_frames, reason, more_data)
+);
+
/*
* Tracing for API calls that drivers call.
*/
@@ -1431,6 +1498,28 @@ TRACE_EVENT(api_enable_rssi_reports,
)
);
+TRACE_EVENT(api_eosp,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sta *sta),
+
+ TP_ARGS(local, sta),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ STA_ENTRY
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ STA_ASSIGN;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT STA_PR_FMT,
+ LOCAL_PR_ARG, STA_PR_FMT
+ )
+);
+
/*
* Tracing for internal functions
* (which may also be called in response to driver calls)
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 7cfc286946c0..f80a35c0d000 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -130,7 +130,7 @@ void ieee80211_ba_session_work(struct work_struct *work)
* down by the code that set the flag, so this
* need not run.
*/
- if (test_sta_flags(sta, WLAN_STA_BLOCK_BA))
+ if (test_sta_flag(sta, WLAN_STA_BLOCK_BA))
return;
mutex_lock(&sta->ampdu_mlme.mtx);
@@ -186,12 +186,8 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
u16 params;
skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
-
- if (!skb) {
- printk(KERN_ERR "%s: failed to allocate buffer "
- "for delba frame\n", sdata->name);
+ if (!skb)
return;
- }
skb_reserve(skb, local->hw.extra_tx_headroom);
mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 56c24cabf26d..ede9a8b341ac 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -81,10 +81,10 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
lockdep_assert_held(&ifibss->mtx);
/* Reset own TSF to allow time synchronization work. */
- drv_reset_tsf(local);
+ drv_reset_tsf(local, sdata);
skb = ifibss->skb;
- rcu_assign_pointer(ifibss->presp, NULL);
+ RCU_INIT_POINTER(ifibss->presp, NULL);
synchronize_rcu();
skb->data = skb->head;
skb->len = 0;
@@ -184,7 +184,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
*pos++ = 0; /* U-APSD no in use */
}
- rcu_assign_pointer(ifibss->presp, skb);
+ RCU_INIT_POINTER(ifibss->presp, skb);
sdata->vif.bss_conf.beacon_int = beacon_int;
sdata->vif.bss_conf.basic_rates = basic_rates;
@@ -314,7 +314,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
}
if (sta && elems->wmm_info)
- set_sta_flags(sta, WLAN_STA_WME);
+ set_sta_flag(sta, WLAN_STA_WME);
rcu_read_unlock();
}
@@ -382,7 +382,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
* second best option: get current TSF
* (will return -1 if not supported)
*/
- rx_timestamp = drv_get_tsf(local);
+ rx_timestamp = drv_get_tsf(local, sdata);
}
#ifdef CONFIG_MAC80211_IBSS_DEBUG
@@ -417,7 +417,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
* must be callable in atomic context.
*/
struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
- u8 *bssid,u8 *addr, u32 supp_rates,
+ u8 *bssid, u8 *addr, u32 supp_rates,
gfp_t gfp)
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
@@ -452,7 +452,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
return NULL;
sta->last_rx = jiffies;
- set_sta_flags(sta, WLAN_STA_AUTHORIZED);
+ set_sta_flag(sta, WLAN_STA_AUTHORIZED);
/* make sure mandatory rates are always added */
sta->sta.supp_rates[band] = supp_rates |
@@ -995,7 +995,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
kfree(sdata->u.ibss.ie);
skb = rcu_dereference_protected(sdata->u.ibss.presp,
lockdep_is_held(&sdata->u.ibss.mtx));
- rcu_assign_pointer(sdata->u.ibss.presp, NULL);
+ RCU_INIT_POINTER(sdata->u.ibss.presp, NULL);
sdata->vif.bss_conf.ibss_joined = false;
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
BSS_CHANGED_IBSS);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 400c09bea639..4c3d1f591bec 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -136,7 +136,6 @@ typedef unsigned __bitwise__ ieee80211_tx_result;
#define TX_DROP ((__force ieee80211_tx_result) 1u)
#define TX_QUEUED ((__force ieee80211_tx_result) 2u)
-#define IEEE80211_TX_FRAGMENTED BIT(0)
#define IEEE80211_TX_UNICAST BIT(1)
#define IEEE80211_TX_PS_BUFFERED BIT(2)
@@ -149,7 +148,6 @@ struct ieee80211_tx_data {
struct ieee80211_channel *channel;
- u16 ethertype;
unsigned int flags;
};
@@ -261,6 +259,7 @@ struct mesh_stats {
__u32 fwded_frames; /* Mesh total forwarded frames */
__u32 dropped_frames_ttl; /* Not transmitted since mesh_ttl == 0*/
__u32 dropped_frames_no_route; /* Not transmitted, no route found */
+ __u32 dropped_frames_congestion;/* Not forwarded due to congestion */
atomic_t estab_plinks;
};
@@ -345,6 +344,7 @@ struct ieee80211_work {
struct {
struct sk_buff *frame;
u32 wait;
+ bool status;
} offchan_tx;
};
@@ -514,6 +514,7 @@ struct ieee80211_if_mesh {
struct mesh_config mshcfg;
u32 mesh_seqnum;
bool accepting_plinks;
+ int num_gates;
const u8 *ie;
u8 ie_len;
enum {
@@ -607,6 +608,8 @@ struct ieee80211_sub_if_data {
__be16 control_port_protocol;
bool control_port_no_encrypt;
+ struct ieee80211_tx_queue_params tx_conf[IEEE80211_MAX_QUEUES];
+
struct work_struct work;
struct sk_buff_head skb_queue;
@@ -660,6 +663,11 @@ enum sdata_queue_type {
enum {
IEEE80211_RX_MSG = 1,
IEEE80211_TX_STATUS_MSG = 2,
+ IEEE80211_EOSP_MSG = 3,
+};
+
+struct skb_eosp_msg_data {
+ u8 sta[ETH_ALEN], iface[ETH_ALEN];
};
enum queue_stop_reason {
@@ -669,6 +677,7 @@ enum queue_stop_reason {
IEEE80211_QUEUE_STOP_REASON_AGGREGATION,
IEEE80211_QUEUE_STOP_REASON_SUSPEND,
IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
+ IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE,
};
#ifdef CONFIG_MAC80211_LEDS
@@ -748,7 +757,6 @@ struct ieee80211_local {
struct workqueue_struct *workqueue;
unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES];
- struct ieee80211_tx_queue_params tx_conf[IEEE80211_MAX_QUEUES];
/* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */
spinlock_t queue_stop_reason_lock;
@@ -1002,7 +1010,6 @@ struct ieee80211_local {
unsigned int hw_roc_duration;
u32 hw_roc_cookie;
bool hw_roc_for_tx;
- unsigned long hw_offchan_tx_cookie;
/* dummy netdev for use w/ NAPI */
struct net_device napi_dev;
@@ -1022,69 +1029,6 @@ struct ieee80211_ra_tid {
u16 tid;
};
-/* Parsed Information Elements */
-struct ieee802_11_elems {
- u8 *ie_start;
- size_t total_len;
-
- /* pointers to IEs */
- u8 *ssid;
- u8 *supp_rates;
- u8 *fh_params;
- u8 *ds_params;
- u8 *cf_params;
- struct ieee80211_tim_ie *tim;
- u8 *ibss_params;
- u8 *challenge;
- u8 *wpa;
- u8 *rsn;
- u8 *erp_info;
- u8 *ext_supp_rates;
- u8 *wmm_info;
- u8 *wmm_param;
- struct ieee80211_ht_cap *ht_cap_elem;
- struct ieee80211_ht_info *ht_info_elem;
- struct ieee80211_meshconf_ie *mesh_config;
- u8 *mesh_id;
- u8 *peer_link;
- u8 *preq;
- u8 *prep;
- u8 *perr;
- struct ieee80211_rann_ie *rann;
- u8 *ch_switch_elem;
- u8 *country_elem;
- u8 *pwr_constr_elem;
- u8 *quiet_elem; /* first quite element */
- u8 *timeout_int;
-
- /* length of them, respectively */
- u8 ssid_len;
- u8 supp_rates_len;
- u8 fh_params_len;
- u8 ds_params_len;
- u8 cf_params_len;
- u8 tim_len;
- u8 ibss_params_len;
- u8 challenge_len;
- u8 wpa_len;
- u8 rsn_len;
- u8 erp_info_len;
- u8 ext_supp_rates_len;
- u8 wmm_info_len;
- u8 wmm_param_len;
- u8 mesh_id_len;
- u8 peer_link_len;
- u8 preq_len;
- u8 prep_len;
- u8 perr_len;
- u8 ch_switch_elem_len;
- u8 country_elem_len;
- u8 pwr_constr_elem_len;
- u8 quiet_elem_len;
- u8 num_of_quiet_elem; /* can be more the one */
- u8 timeout_int_len;
-};
-
static inline struct ieee80211_local *hw_to_local(
struct ieee80211_hw *hw)
{
@@ -1233,23 +1177,10 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev);
-/*
- * radiotap header for status frames
- */
-struct ieee80211_tx_status_rtap_hdr {
- struct ieee80211_radiotap_header hdr;
- u8 rate;
- u8 padding_for_rate;
- __le16 tx_flags;
- u8 data_retries;
-} __packed;
-
-
/* HT */
void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
struct ieee80211_ht_cap *ht_cap_ie,
struct ieee80211_sta_ht_cap *ht_cap);
-void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn);
void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
const u8 *da, u16 tid,
u16 initiator, u16 reason_code);
@@ -1333,6 +1264,7 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke
struct ieee80211_hdr *hdr, const u8 *tsc,
gfp_t gfp);
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata);
+void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
void ieee802_11_parse_elems(u8 *start, size_t len,
struct ieee802_11_elems *elems);
@@ -1364,11 +1296,11 @@ void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
enum queue_stop_reason reason);
void ieee80211_add_pending_skb(struct ieee80211_local *local,
struct sk_buff *skb);
-int ieee80211_add_pending_skbs(struct ieee80211_local *local,
- struct sk_buff_head *skbs);
-int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
- struct sk_buff_head *skbs,
- void (*fn)(void *data), void *data);
+void ieee80211_add_pending_skbs(struct ieee80211_local *local,
+ struct sk_buff_head *skbs);
+void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
+ struct sk_buff_head *skbs,
+ void (*fn)(void *data), void *data);
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg,
@@ -1386,7 +1318,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
const u8 *ssid, size_t ssid_len,
const u8 *ie, size_t ie_len,
- u32 ratemask, bool directed);
+ u32 ratemask, bool directed, bool no_cck);
void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
const size_t supp_rates_len,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 556e7e6ddf0a..30d73552e9ab 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -299,8 +299,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
goto err_del_interface;
}
- /* no locking required since STA is not live yet */
- sta->flags |= WLAN_STA_AUTHORIZED;
+ /* no atomic bitop required since STA is not live yet */
+ set_sta_flag(sta, WLAN_STA_AUTHORIZED);
res = sta_info_insert(sta);
if (res) {
@@ -456,21 +456,19 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
BSS_CHANGED_BEACON_ENABLED);
/* remove beacon */
- rcu_assign_pointer(sdata->u.ap.beacon, NULL);
+ RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
synchronize_rcu();
kfree(old_beacon);
- /* free all potentially still buffered bcast frames */
- while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
- local->total_ps_buffered--;
- dev_kfree_skb(skb);
- }
-
/* down all dependent devices, that is VLANs */
list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
u.vlan.list)
dev_close(vlan->dev);
WARN_ON(!list_empty(&sdata->u.ap.vlans));
+
+ /* free all potentially still buffered bcast frames */
+ local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps_bc_buf);
+ skb_queue_purge(&sdata->u.ap.ps_bc_buf);
}
if (going_down)
@@ -645,7 +643,7 @@ static const struct net_device_ops ieee80211_dataif_ops = {
.ndo_stop = ieee80211_stop,
.ndo_uninit = ieee80211_teardown_sdata,
.ndo_start_xmit = ieee80211_subif_start_xmit,
- .ndo_set_multicast_list = ieee80211_set_multicast_list,
+ .ndo_set_rx_mode = ieee80211_set_multicast_list,
.ndo_change_mtu = ieee80211_change_mtu,
.ndo_set_mac_address = ieee80211_change_mac,
.ndo_select_queue = ieee80211_netdev_select_queue,
@@ -689,7 +687,7 @@ static const struct net_device_ops ieee80211_monitorif_ops = {
.ndo_stop = ieee80211_stop,
.ndo_uninit = ieee80211_teardown_sdata,
.ndo_start_xmit = ieee80211_monitor_start_xmit,
- .ndo_set_multicast_list = ieee80211_set_multicast_list,
+ .ndo_set_rx_mode = ieee80211_set_multicast_list,
.ndo_change_mtu = ieee80211_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_select_queue = ieee80211_monitor_select_queue,
@@ -1214,6 +1212,9 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
list_del_rcu(&sdata->list);
mutex_unlock(&sdata->local->iflist_mtx);
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ mesh_path_flush_by_iface(sdata);
+
synchronize_rcu();
unregister_netdevice(sdata->dev);
}
@@ -1233,6 +1234,9 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
list_del(&sdata->list);
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ mesh_path_flush_by_iface(sdata);
+
unregister_netdevice_queue(sdata->dev, &unreg_list);
}
mutex_unlock(&local->iflist_mtx);
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 5150c6d11b57..756b157c2edd 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -464,7 +464,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
* some hardware cannot handle TKIP with QoS, so
* we indicate whether QoS could be in use.
*/
- if (test_sta_flags(sta, WLAN_STA_WME))
+ if (test_sta_flag(sta, WLAN_STA_WME))
key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA;
} else {
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
@@ -478,7 +478,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
/* same here, the AP could be using QoS */
ap = sta_info_get(key->sdata, key->sdata->u.mgd.bssid);
if (ap) {
- if (test_sta_flags(ap, WLAN_STA_WME))
+ if (test_sta_flag(ap, WLAN_STA_WME))
key->conf.flags |=
IEEE80211_KEY_FLAG_WMM_STA;
}
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 866f269183cf..d999bf3b84e1 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -19,7 +19,7 @@
#include <linux/if_arp.h>
#include <linux/rtnetlink.h>
#include <linux/bitmap.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
#include <linux/inetdevice.h>
#include <net/net_namespace.h>
#include <net/cfg80211.h>
@@ -325,6 +325,8 @@ u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
static void ieee80211_tasklet_handler(unsigned long data)
{
struct ieee80211_local *local = (struct ieee80211_local *) data;
+ struct sta_info *sta, *tmp;
+ struct skb_eosp_msg_data *eosp_data;
struct sk_buff *skb;
while ((skb = skb_dequeue(&local->skb_queue)) ||
@@ -340,6 +342,18 @@ static void ieee80211_tasklet_handler(unsigned long data)
skb->pkt_type = 0;
ieee80211_tx_status(local_to_hw(local), skb);
break;
+ case IEEE80211_EOSP_MSG:
+ eosp_data = (void *)skb->cb;
+ for_each_sta_info(local, eosp_data->sta, sta, tmp) {
+ /* skip wrong virtual interface */
+ if (memcmp(eosp_data->iface,
+ sta->sdata->vif.addr, ETH_ALEN))
+ continue;
+ clear_sta_flag(sta, WLAN_STA_SP);
+ break;
+ }
+ dev_kfree_skb(skb);
+ break;
default:
WARN(1, "mac80211: Packet is of unknown type %d\n",
skb->pkt_type);
@@ -608,6 +622,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
local->hw.max_rates = 1;
local->hw.max_report_rates = 0;
local->hw.max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
+ local->hw.max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
local->hw.conf.long_frame_max_tx_count = wiphy->retry_long;
local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;
local->user_power_level = -1;
@@ -862,6 +877,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (local->ops->sched_scan_start)
local->hw.wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+ /* mac80211 based drivers don't support internal TDLS setup */
+ if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)
+ local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP;
+
result = wiphy_register(local->hw.wiphy);
if (result < 0)
goto fail_wiphy_register;
@@ -885,12 +904,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
* and we need some headroom for passing the frame to monitor
* interfaces, but never both at the same time.
*/
-#ifndef __CHECKER__
- BUILD_BUG_ON(IEEE80211_TX_STATUS_HEADROOM !=
- sizeof(struct ieee80211_tx_status_rtap_hdr));
-#endif
local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom,
- sizeof(struct ieee80211_tx_status_rtap_hdr));
+ IEEE80211_TX_STATUS_HEADROOM);
debugfs_hw_add(local);
@@ -1012,7 +1027,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
cancel_work_sync(&local->reconfig_filter);
ieee80211_clear_tx_pending(local);
- sta_info_stop(local);
rate_control_deinitialize(local);
if (skb_queue_len(&local->skb_queue) ||
@@ -1024,6 +1038,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
destroy_workqueue(local->workqueue);
wiphy_unregister(local->hw.wiphy);
+ sta_info_stop(local);
ieee80211_wep_free(local);
ieee80211_led_exit(local);
kfree(local->int_scan_req);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 29e9980c8e60..a7078fdba8ca 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -13,10 +13,6 @@
#include "ieee80211_i.h"
#include "mesh.h"
-#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
-#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
-#define IEEE80211_MESH_RANN_INTERVAL (1 * HZ)
-
#define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01
#define MESHCONF_CAPAB_FORWARDING 0x08
@@ -27,6 +23,17 @@
int mesh_allocated;
static struct kmem_cache *rm_cache;
+#ifdef CONFIG_MAC80211_MESH
+bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt)
+{
+ return (mgmt->u.action.u.mesh_action.action_code ==
+ WLAN_MESH_ACTION_HWMP_PATH_SELECTION);
+}
+#else
+bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt)
+{ return false; }
+#endif
+
void ieee80211s_init(void)
{
mesh_pathtbl_init();
@@ -193,10 +200,9 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
}
p = kmem_cache_alloc(rm_cache, GFP_ATOMIC);
- if (!p) {
- printk(KERN_DEBUG "o11s: could not allocate RMC entry\n");
+ if (!p)
return 0;
- }
+
p->seqnum = seqnum;
p->exp_time = jiffies + RMC_TIMEOUT;
memcpy(p->sa, sa, ETH_ALEN);
@@ -204,89 +210,136 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
return 0;
}
-void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
+int
+mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
{
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_supported_band *sband;
- u8 *pos;
- int len, i, rate;
- u8 neighbors;
-
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- len = sband->n_bitrates;
- if (len > 8)
- len = 8;
- pos = skb_put(skb, len + 2);
- *pos++ = WLAN_EID_SUPP_RATES;
- *pos++ = len;
- for (i = 0; i < len; i++) {
- rate = sband->bitrates[i].bitrate;
- *pos++ = (u8) (rate / 5);
- }
-
- if (sband->n_bitrates > len) {
- pos = skb_put(skb, sband->n_bitrates - len + 2);
- *pos++ = WLAN_EID_EXT_SUPP_RATES;
- *pos++ = sband->n_bitrates - len;
- for (i = len; i < sband->n_bitrates; i++) {
- rate = sband->bitrates[i].bitrate;
- *pos++ = (u8) (rate / 5);
- }
- }
-
- if (sband->band == IEEE80211_BAND_2GHZ) {
- pos = skb_put(skb, 2 + 1);
- *pos++ = WLAN_EID_DS_PARAMS;
- *pos++ = 1;
- *pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq);
- }
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ u8 *pos, neighbors;
+ u8 meshconf_len = sizeof(struct ieee80211_meshconf_ie);
- pos = skb_put(skb, 2 + sdata->u.mesh.mesh_id_len);
- *pos++ = WLAN_EID_MESH_ID;
- *pos++ = sdata->u.mesh.mesh_id_len;
- if (sdata->u.mesh.mesh_id_len)
- memcpy(pos, sdata->u.mesh.mesh_id, sdata->u.mesh.mesh_id_len);
+ if (skb_tailroom(skb) < 2 + meshconf_len)
+ return -ENOMEM;
- pos = skb_put(skb, 2 + sizeof(struct ieee80211_meshconf_ie));
+ pos = skb_put(skb, 2 + meshconf_len);
*pos++ = WLAN_EID_MESH_CONFIG;
- *pos++ = sizeof(struct ieee80211_meshconf_ie);
+ *pos++ = meshconf_len;
/* Active path selection protocol ID */
- *pos++ = sdata->u.mesh.mesh_pp_id;
-
+ *pos++ = ifmsh->mesh_pp_id;
/* Active path selection metric ID */
- *pos++ = sdata->u.mesh.mesh_pm_id;
-
+ *pos++ = ifmsh->mesh_pm_id;
/* Congestion control mode identifier */
- *pos++ = sdata->u.mesh.mesh_cc_id;
-
+ *pos++ = ifmsh->mesh_cc_id;
/* Synchronization protocol identifier */
- *pos++ = sdata->u.mesh.mesh_sp_id;
-
+ *pos++ = ifmsh->mesh_sp_id;
/* Authentication Protocol identifier */
- *pos++ = sdata->u.mesh.mesh_auth_id;
-
+ *pos++ = ifmsh->mesh_auth_id;
/* Mesh Formation Info - number of neighbors */
- neighbors = atomic_read(&sdata->u.mesh.mshstats.estab_plinks);
+ neighbors = atomic_read(&ifmsh->mshstats.estab_plinks);
/* Number of neighbor mesh STAs or 15 whichever is smaller */
neighbors = (neighbors > 15) ? 15 : neighbors;
*pos++ = neighbors << 1;
-
/* Mesh capability */
- sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata);
+ ifmsh->accepting_plinks = mesh_plink_availables(sdata);
*pos = MESHCONF_CAPAB_FORWARDING;
- *pos++ |= sdata->u.mesh.accepting_plinks ?
+ *pos++ |= ifmsh->accepting_plinks ?
MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
*pos++ = 0x00;
- if (sdata->u.mesh.ie) {
- int len = sdata->u.mesh.ie_len;
- const u8 *data = sdata->u.mesh.ie;
- if (skb_tailroom(skb) > len)
- memcpy(skb_put(skb, len), data, len);
+ return 0;
+}
+
+int
+mesh_add_meshid_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ u8 *pos;
+
+ if (skb_tailroom(skb) < 2 + ifmsh->mesh_id_len)
+ return -ENOMEM;
+
+ pos = skb_put(skb, 2 + ifmsh->mesh_id_len);
+ *pos++ = WLAN_EID_MESH_ID;
+ *pos++ = ifmsh->mesh_id_len;
+ if (ifmsh->mesh_id_len)
+ memcpy(pos, ifmsh->mesh_id, ifmsh->mesh_id_len);
+
+ return 0;
+}
+
+int
+mesh_add_vendor_ies(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ u8 offset, len;
+ const u8 *data;
+
+ if (!ifmsh->ie || !ifmsh->ie_len)
+ return 0;
+
+ /* fast-forward to vendor IEs */
+ offset = ieee80211_ie_split_vendor(ifmsh->ie, ifmsh->ie_len, 0);
+
+ if (offset) {
+ len = ifmsh->ie_len - offset;
+ data = ifmsh->ie + offset;
+ if (skb_tailroom(skb) < len)
+ return -ENOMEM;
+ memcpy(skb_put(skb, len), data, len);
}
+
+ return 0;
}
+int
+mesh_add_rsn_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ u8 len = 0;
+ const u8 *data;
+
+ if (!ifmsh->ie || !ifmsh->ie_len)
+ return 0;
+
+ /* find RSN IE */
+ data = ifmsh->ie;
+ while (data < ifmsh->ie + ifmsh->ie_len) {
+ if (*data == WLAN_EID_RSN) {
+ len = data[1] + 2;
+ break;
+ }
+ data++;
+ }
+
+ if (len) {
+ if (skb_tailroom(skb) < len)
+ return -ENOMEM;
+ memcpy(skb_put(skb, len), data, len);
+ }
+
+ return 0;
+}
+
+int mesh_add_ds_params_ie(struct sk_buff *skb,
+ struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_supported_band *sband;
+ u8 *pos;
+
+ if (skb_tailroom(skb) < 3)
+ return -ENOMEM;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ if (sband->band == IEEE80211_BAND_2GHZ) {
+ pos = skb_put(skb, 2 + 1);
+ *pos++ = WLAN_EID_DS_PARAMS;
+ *pos++ = 1;
+ *pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq);
+ }
+
+ return 0;
+}
static void ieee80211_mesh_path_timer(unsigned long data)
{
@@ -352,8 +405,7 @@ int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
memcpy(hdr->addr3, meshsa, ETH_ALEN);
return 24;
} else {
- *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |
- IEEE80211_FCTL_TODS);
+ *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
/* RA TA DA SA */
memset(hdr->addr1, 0, ETH_ALEN); /* RA is resolved later */
memcpy(hdr->addr2, meshsa, ETH_ALEN);
@@ -425,7 +477,8 @@ static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata)
mesh_path_tx_root_frame(sdata);
mod_timer(&ifmsh->mesh_path_root_timer,
- round_jiffies(jiffies + IEEE80211_MESH_RANN_INTERVAL));
+ round_jiffies(TU_TO_EXP_TIME(
+ ifmsh->mshcfg.dot11MeshHWMPRannInterval)));
}
#ifdef CONFIG_PM
@@ -433,7 +486,7 @@ void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
- /* use atomic bitops in case both timers fire at the same time */
+ /* use atomic bitops in case all timers fire at the same time */
if (del_timer_sync(&ifmsh->housekeeping_timer))
set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
@@ -557,11 +610,18 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
struct ieee80211_rx_status *rx_status)
{
switch (mgmt->u.action.category) {
- case WLAN_CATEGORY_MESH_ACTION:
- mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
+ case WLAN_CATEGORY_SELF_PROTECTED:
+ switch (mgmt->u.action.u.self_prot.action_code) {
+ case WLAN_SP_MESH_PEERING_OPEN:
+ case WLAN_SP_MESH_PEERING_CLOSE:
+ case WLAN_SP_MESH_PEERING_CONFIRM:
+ mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
+ break;
+ }
break;
- case WLAN_CATEGORY_MESH_PATH_SEL:
- mesh_rx_path_sel_frame(sdata, mgmt, len);
+ case WLAN_CATEGORY_MESH_ACTION:
+ if (mesh_action_is_path_sel(mgmt))
+ mesh_rx_path_sel_frame(sdata, mgmt, len);
break;
}
}
@@ -633,6 +693,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
ifmsh->accepting_plinks = true;
ifmsh->preq_id = 0;
ifmsh->sn = 0;
+ ifmsh->num_gates = 0;
atomic_set(&ifmsh->mpaths, 0);
mesh_rmc_init(sdata);
ifmsh->last_preq = jiffies;
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 249e733362e7..8c00e2d1d636 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -80,7 +80,10 @@ enum mesh_deferred_task_flags {
* retry
* @discovery_retries: number of discovery retries
* @flags: mesh path flags, as specified on &enum mesh_path_flags
- * @state_lock: mesh path state lock
+ * @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.
+ * @is_gate: the destination station of this path is a mesh gate
*
*
* The combination of dst and sdata is unique in the mesh path table. Since the
@@ -104,6 +107,7 @@ struct mesh_path {
u8 discovery_retries;
enum mesh_path_flags flags;
spinlock_t state_lock;
+ bool is_gate;
};
/**
@@ -120,6 +124,9 @@ struct mesh_path {
* buckets
* @mean_chain_len: maximum average length for the hash buckets' list, if it is
* reached, the table will grow
+ * @known_gates: list of known mesh gates and their mpaths by the station. The
+ * gate's mpath may or may not be resolved and active.
+ *
* rcu_head: RCU head to free the table
*/
struct mesh_table {
@@ -133,6 +140,8 @@ struct mesh_table {
int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
int size_order;
int mean_chain_len;
+ struct hlist_head *known_gates;
+ spinlock_t gates_lock;
struct rcu_head rcu_head;
};
@@ -166,6 +175,8 @@ struct mesh_rmc {
u32 idx_mask;
};
+#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
+#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
#define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units */
@@ -177,14 +188,6 @@ struct mesh_rmc {
/* Maximum number of paths per interface */
#define MESH_MAX_MPATHS 1024
-/* Pending ANA approval */
-#define MESH_PATH_SEL_ACTION 0
-
-/* PERR reason codes */
-#define PEER_RCODE_UNSPECIFIED 11
-#define PERR_RCODE_NO_ROUTE 12
-#define PERR_RCODE_DEST_UNREACH 13
-
/* Public interfaces */
/* Various */
int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
@@ -199,6 +202,16 @@ bool mesh_matches_local(struct ieee802_11_elems *ie,
void mesh_ids_set_default(struct ieee80211_if_mesh *mesh);
void mesh_mgmt_ies_add(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata);
+int mesh_add_meshconf_ie(struct sk_buff *skb,
+ struct ieee80211_sub_if_data *sdata);
+int mesh_add_meshid_ie(struct sk_buff *skb,
+ struct ieee80211_sub_if_data *sdata);
+int mesh_add_rsn_ie(struct sk_buff *skb,
+ struct ieee80211_sub_if_data *sdata);
+int mesh_add_vendor_ies(struct sk_buff *skb,
+ struct ieee80211_sub_if_data *sdata);
+int mesh_add_ds_params_ie(struct sk_buff *skb,
+ struct ieee80211_sub_if_data *sdata);
void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
void ieee80211s_init(void);
@@ -223,10 +236,13 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx,
struct ieee80211_sub_if_data *sdata);
void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop);
void mesh_path_expire(struct ieee80211_sub_if_data *sdata);
-void mesh_path_flush(struct ieee80211_sub_if_data *sdata);
void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt, size_t len);
int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata);
+
+int mesh_path_add_gate(struct mesh_path *mpath);
+int mesh_path_send_to_gates(struct mesh_path *mpath);
+int mesh_gate_num(struct ieee80211_sub_if_data *sdata);
/* Mesh plinks */
void mesh_neighbour_update(u8 *hw_addr, u32 rates,
struct ieee80211_sub_if_data *sdata,
@@ -256,12 +272,14 @@ void mesh_pathtbl_unregister(void);
int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata);
void mesh_path_timer(unsigned long data);
void mesh_path_flush_by_nexthop(struct sta_info *sta);
+void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata);
void mesh_path_discard_frame(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata);
void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata);
void mesh_path_restart(struct ieee80211_sub_if_data *sdata);
void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata);
+bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt);
extern int mesh_paths_generation;
#ifdef CONFIG_MAC80211_MESH
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 3460108810d5..174040a42887 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -8,10 +8,12 @@
*/
#include <linux/slab.h>
+#include "wme.h"
#include "mesh.h"
#ifdef CONFIG_MAC80211_VERBOSE_MHWMP_DEBUG
-#define mhwmp_dbg(fmt, args...) printk(KERN_DEBUG "Mesh HWMP: " fmt, ##args)
+#define mhwmp_dbg(fmt, args...) \
+ printk(KERN_DEBUG "Mesh HWMP (%s): " fmt "\n", sdata->name, ##args)
#else
#define mhwmp_dbg(fmt, args...) do { (void)(0); } while (0)
#endif
@@ -68,12 +70,12 @@ static inline u32 u16_field_get(u8 *preq_elem, int offset, bool ae)
#define PREP_IE_FLAGS(x) PREQ_IE_FLAGS(x)
#define PREP_IE_HOPCOUNT(x) PREQ_IE_HOPCOUNT(x)
#define PREP_IE_TTL(x) PREQ_IE_TTL(x)
-#define PREP_IE_ORIG_ADDR(x) (x + 3)
-#define PREP_IE_ORIG_SN(x) u32_field_get(x, 9, 0)
+#define PREP_IE_ORIG_ADDR(x) (AE_F_SET(x) ? x + 27 : x + 21)
+#define PREP_IE_ORIG_SN(x) u32_field_get(x, 27, AE_F_SET(x))
#define PREP_IE_LIFETIME(x) u32_field_get(x, 13, AE_F_SET(x))
#define PREP_IE_METRIC(x) u32_field_get(x, 17, AE_F_SET(x))
-#define PREP_IE_TARGET_ADDR(x) (AE_F_SET(x) ? x + 27 : x + 21)
-#define PREP_IE_TARGET_SN(x) u32_field_get(x, 27, AE_F_SET(x))
+#define PREP_IE_TARGET_ADDR(x) (x + 3)
+#define PREP_IE_TARGET_SN(x) u32_field_get(x, 9, 0)
#define PERR_IE_TTL(x) (*(x))
#define PERR_IE_TARGET_FLAGS(x) (*(x + 2))
@@ -132,24 +134,25 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
/* BSSID == SA */
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
- mgmt->u.action.category = WLAN_CATEGORY_MESH_PATH_SEL;
- mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION;
+ mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION;
+ mgmt->u.action.u.mesh_action.action_code =
+ WLAN_MESH_ACTION_HWMP_PATH_SELECTION;
switch (action) {
case MPATH_PREQ:
- mhwmp_dbg("sending PREQ to %pM\n", target);
+ mhwmp_dbg("sending PREQ to %pM", target);
ie_len = 37;
pos = skb_put(skb, 2 + ie_len);
*pos++ = WLAN_EID_PREQ;
break;
case MPATH_PREP:
- mhwmp_dbg("sending PREP to %pM\n", target);
+ mhwmp_dbg("sending PREP to %pM", target);
ie_len = 31;
pos = skb_put(skb, 2 + ie_len);
*pos++ = WLAN_EID_PREP;
break;
case MPATH_RANN:
- mhwmp_dbg("sending RANN from %pM\n", orig_addr);
+ mhwmp_dbg("sending RANN from %pM", orig_addr);
ie_len = sizeof(struct ieee80211_rann_ie);
pos = skb_put(skb, 2 + ie_len);
*pos++ = WLAN_EID_RANN;
@@ -163,35 +166,63 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
*pos++ = flags;
*pos++ = hop_count;
*pos++ = ttl;
- if (action == MPATH_PREQ) {
- memcpy(pos, &preq_id, 4);
+ if (action == MPATH_PREP) {
+ memcpy(pos, target, ETH_ALEN);
+ pos += ETH_ALEN;
+ memcpy(pos, &target_sn, 4);
pos += 4;
- }
- memcpy(pos, orig_addr, ETH_ALEN);
- pos += ETH_ALEN;
- memcpy(pos, &orig_sn, 4);
- pos += 4;
- if (action != MPATH_RANN) {
- memcpy(pos, &lifetime, 4);
+ } else {
+ if (action == MPATH_PREQ) {
+ memcpy(pos, &preq_id, 4);
+ pos += 4;
+ }
+ memcpy(pos, orig_addr, ETH_ALEN);
+ pos += ETH_ALEN;
+ memcpy(pos, &orig_sn, 4);
pos += 4;
}
+ memcpy(pos, &lifetime, 4); /* interval for RANN */
+ pos += 4;
memcpy(pos, &metric, 4);
pos += 4;
if (action == MPATH_PREQ) {
- /* destination count */
- *pos++ = 1;
+ *pos++ = 1; /* destination count */
*pos++ = target_flags;
- }
- if (action != MPATH_RANN) {
memcpy(pos, target, ETH_ALEN);
pos += ETH_ALEN;
memcpy(pos, &target_sn, 4);
+ pos += 4;
+ } else if (action == MPATH_PREP) {
+ memcpy(pos, orig_addr, ETH_ALEN);
+ pos += ETH_ALEN;
+ memcpy(pos, &orig_sn, 4);
+ pos += 4;
}
ieee80211_tx_skb(sdata, skb);
return 0;
}
+
+/* Headroom is not adjusted. Caller should ensure that skb has sufficient
+ * headroom in case the frame is encrypted. */
+static void prepare_frame_for_deferred_tx(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ skb_set_mac_header(skb, 0);
+ skb_set_network_header(skb, 0);
+ skb_set_transport_header(skb, 0);
+
+ /* Send all internal mgmt frames on VO. Accordingly set TID to 7. */
+ skb_set_queue_mapping(skb, IEEE80211_AC_VO);
+ skb->priority = 7;
+
+ info->control.vif = &sdata->vif;
+ ieee80211_set_qos_hdr(sdata, skb);
+}
+
/**
* mesh_send_path error - Sends a PERR mesh management frame
*
@@ -199,6 +230,10 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
* @target_sn: SN of the broken destination
* @target_rcode: reason code for this PERR
* @ra: node this frame is addressed to
+ *
+ * Note: This function may be called with driver locks taken that the driver
+ * also acquires in the TX path. To avoid a deadlock we don't transmit the
+ * frame directly but add it to the pending queue instead.
*/
int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
__le16 target_rcode, const u8 *ra,
@@ -212,7 +247,7 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
if (!skb)
return -1;
- skb_reserve(skb, local->hw.extra_tx_headroom);
+ skb_reserve(skb, local->tx_headroom + local->hw.extra_tx_headroom);
/* 25 is the size of the common mgmt part (24) plus the size of the
* common action part (1)
*/
@@ -224,9 +259,11 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
memcpy(mgmt->da, ra, ETH_ALEN);
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
- /* BSSID is left zeroed, wildcard value */
- mgmt->u.action.category = WLAN_CATEGORY_MESH_PATH_SEL;
- mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION;
+ /* BSSID == SA */
+ memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
+ mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION;
+ mgmt->u.action.u.mesh_action.action_code =
+ WLAN_MESH_ACTION_HWMP_PATH_SELECTION;
ie_len = 15;
pos = skb_put(skb, 2 + ie_len);
*pos++ = WLAN_EID_PERR;
@@ -251,7 +288,9 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
pos += 4;
memcpy(pos, &target_rcode, 2);
- ieee80211_tx_skb(sdata, skb);
+ /* see note in function header */
+ prepare_frame_for_deferred_tx(sdata, skb);
+ ieee80211_add_pending_skb(local, skb);
return 0;
}
@@ -449,7 +488,6 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
if (fresh_info) {
mesh_path_assign_nexthop(mpath, sta);
- mpath->flags &= ~MESH_PATH_SN_VALID;
mpath->metric = last_hop_metric;
mpath->exp_time = time_after(mpath->exp_time, exp_time)
? mpath->exp_time : exp_time;
@@ -484,10 +522,10 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
orig_sn = PREQ_IE_ORIG_SN(preq_elem);
target_flags = PREQ_IE_TARGET_F(preq_elem);
- mhwmp_dbg("received PREQ from %pM\n", orig_addr);
+ mhwmp_dbg("received PREQ from %pM", orig_addr);
if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0) {
- mhwmp_dbg("PREQ is for us\n");
+ mhwmp_dbg("PREQ is for us");
forward = false;
reply = true;
metric = 0;
@@ -523,7 +561,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
lifetime = PREQ_IE_LIFETIME(preq_elem);
ttl = ifmsh->mshcfg.element_ttl;
if (ttl != 0) {
- mhwmp_dbg("replying to the PREQ\n");
+ mhwmp_dbg("replying to the PREQ");
mesh_path_sel_frame_tx(MPATH_PREP, 0, target_addr,
cpu_to_le32(target_sn), 0, orig_addr,
cpu_to_le32(orig_sn), mgmt->sa, 0, ttl,
@@ -543,7 +581,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
ifmsh->mshstats.dropped_frames_ttl++;
return;
}
- mhwmp_dbg("forwarding the PREQ from %pM\n", orig_addr);
+ mhwmp_dbg("forwarding the PREQ from %pM", orig_addr);
--ttl;
flags = PREQ_IE_FLAGS(preq_elem);
preq_id = PREQ_IE_PREQ_ID(preq_elem);
@@ -578,7 +616,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
u8 next_hop[ETH_ALEN];
u32 target_sn, orig_sn, lifetime;
- mhwmp_dbg("received PREP from %pM\n", PREP_IE_ORIG_ADDR(prep_elem));
+ mhwmp_dbg("received PREP from %pM", PREP_IE_ORIG_ADDR(prep_elem));
/* Note that we divert from the draft nomenclature and denominate
* destination to what the draft refers to as origininator. So in this
@@ -684,6 +722,8 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
u8 ttl, flags, hopcount;
u8 *orig_addr;
u32 orig_sn, metric;
+ u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
+ bool root_is_gate;
ttl = rann->rann_ttl;
if (ttl <= 1) {
@@ -692,12 +732,19 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
}
ttl--;
flags = rann->rann_flags;
+ root_is_gate = !!(flags & RANN_FLAG_IS_GATE);
orig_addr = rann->rann_addr;
orig_sn = rann->rann_seq;
hopcount = rann->rann_hopcount;
hopcount++;
metric = rann->rann_metric;
- mhwmp_dbg("received RANN from %pM\n", orig_addr);
+
+ /* Ignore our own RANNs */
+ if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0)
+ return;
+
+ mhwmp_dbg("received RANN from %pM (is_gate=%d)", orig_addr,
+ root_is_gate);
rcu_read_lock();
mpath = mesh_path_lookup(orig_addr, sdata);
@@ -709,18 +756,28 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
sdata->u.mesh.mshstats.dropped_frames_no_route++;
return;
}
- mesh_queue_preq(mpath,
- PREQ_Q_F_START | PREQ_Q_F_REFRESH);
}
+
+ if ((!(mpath->flags & (MESH_PATH_ACTIVE | MESH_PATH_RESOLVING)) ||
+ time_after(jiffies, mpath->exp_time - 1*HZ)) &&
+ !(mpath->flags & MESH_PATH_FIXED)) {
+ mhwmp_dbg("%s time to refresh root mpath %pM", sdata->name,
+ orig_addr);
+ mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH);
+ }
+
if (mpath->sn < orig_sn) {
mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
cpu_to_le32(orig_sn),
0, NULL, 0, broadcast_addr,
- hopcount, ttl, 0,
+ hopcount, ttl, cpu_to_le32(interval),
cpu_to_le32(metric + mpath->metric),
0, sdata);
mpath->sn = orig_sn;
}
+ if (root_is_gate)
+ mesh_path_add_gate(mpath);
+
rcu_read_unlock();
}
@@ -732,11 +789,20 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems elems;
size_t baselen;
u32 last_hop_metric;
+ struct sta_info *sta;
/* need action_code */
if (len < IEEE80211_MIN_ACTION_SIZE + 1)
return;
+ rcu_read_lock();
+ sta = sta_info_get(sdata, mgmt->sa);
+ if (!sta || sta->plink_state != NL80211_PLINK_ESTAB) {
+ rcu_read_unlock();
+ return;
+ }
+ rcu_read_unlock();
+
baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt;
ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
len - baselen, &elems);
@@ -788,16 +854,16 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC);
if (!preq_node) {
- mhwmp_dbg("could not allocate PREQ node\n");
+ mhwmp_dbg("could not allocate PREQ node");
return;
}
- spin_lock(&ifmsh->mesh_preq_queue_lock);
+ spin_lock_bh(&ifmsh->mesh_preq_queue_lock);
if (ifmsh->preq_queue_len == MAX_PREQ_QUEUE_LEN) {
- spin_unlock(&ifmsh->mesh_preq_queue_lock);
+ spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
kfree(preq_node);
if (printk_ratelimit())
- mhwmp_dbg("PREQ node queue full\n");
+ mhwmp_dbg("PREQ node queue full");
return;
}
@@ -806,7 +872,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
list_add_tail(&preq_node->list, &ifmsh->preq_queue.list);
++ifmsh->preq_queue_len;
- spin_unlock(&ifmsh->mesh_preq_queue_lock);
+ spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata)))
ieee80211_queue_work(&sdata->local->hw, &sdata->work);
@@ -982,35 +1048,46 @@ void mesh_path_timer(unsigned long data)
{
struct mesh_path *mpath = (void *) data;
struct ieee80211_sub_if_data *sdata = mpath->sdata;
+ int ret;
if (sdata->local->quiescing)
return;
spin_lock_bh(&mpath->state_lock);
if (mpath->flags & MESH_PATH_RESOLVED ||
- (!(mpath->flags & MESH_PATH_RESOLVING)))
+ (!(mpath->flags & MESH_PATH_RESOLVING))) {
mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED);
- else if (mpath->discovery_retries < max_preq_retries(sdata)) {
+ spin_unlock_bh(&mpath->state_lock);
+ } else if (mpath->discovery_retries < max_preq_retries(sdata)) {
++mpath->discovery_retries;
mpath->discovery_timeout *= 2;
+ spin_unlock_bh(&mpath->state_lock);
mesh_queue_preq(mpath, 0);
} else {
mpath->flags = 0;
mpath->exp_time = jiffies;
- mesh_path_flush_pending(mpath);
+ spin_unlock_bh(&mpath->state_lock);
+ if (!mpath->is_gate && mesh_gate_num(sdata) > 0) {
+ ret = mesh_path_send_to_gates(mpath);
+ if (ret)
+ mhwmp_dbg("no gate was reachable");
+ } else
+ mesh_path_flush_pending(mpath);
}
-
- spin_unlock_bh(&mpath->state_lock);
}
void
mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
+ u8 flags;
- mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->vif.addr,
+ flags = (ifmsh->mshcfg.dot11MeshGateAnnouncementProtocol)
+ ? RANN_FLAG_IS_GATE : 0;
+ mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr,
cpu_to_le32(++ifmsh->sn),
0, NULL, 0, broadcast_addr,
0, sdata->u.mesh.mshcfg.element_ttl,
- 0, 0, 0, sdata);
+ cpu_to_le32(interval), 0, 0, sdata);
}
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 068ee6518254..7f54c5042235 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -14,9 +14,16 @@
#include <linux/spinlock.h>
#include <linux/string.h>
#include <net/mac80211.h>
+#include "wme.h"
#include "ieee80211_i.h"
#include "mesh.h"
+#ifdef CONFIG_MAC80211_VERBOSE_MPATH_DEBUG
+#define mpath_dbg(fmt, args...) printk(KERN_DEBUG fmt, ##args)
+#else
+#define mpath_dbg(fmt, args...) do { (void)(0); } while (0)
+#endif
+
/* There will be initially 2^INIT_PATHS_SIZE_ORDER buckets */
#define INIT_PATHS_SIZE_ORDER 2
@@ -42,8 +49,10 @@ static struct mesh_table __rcu *mpp_paths; /* Store paths for MPP&MAP */
int mesh_paths_generation;
/* This lock will have the grow table function as writer and add / delete nodes
- * as readers. When reading the table (i.e. doing lookups) we are well protected
- * by RCU
+ * as readers. RCU provides sufficient protection only when reading the table
+ * (i.e. doing lookups). Adding or adding or removing nodes requires we take
+ * the read lock or we risk operating on an old table. The write lock is only
+ * needed when modifying the number of buckets a table.
*/
static DEFINE_RWLOCK(pathtbl_resize_lock);
@@ -60,6 +69,8 @@ static inline struct mesh_table *resize_dereference_mpp_paths(void)
lockdep_is_held(&pathtbl_resize_lock));
}
+static int mesh_gate_add(struct mesh_table *tbl, struct mesh_path *mpath);
+
/*
* CAREFUL -- "tbl" must not be an expression,
* in particular not an rcu_dereference(), since
@@ -103,6 +114,7 @@ static struct mesh_table *mesh_table_alloc(int size_order)
sizeof(newtbl->hash_rnd));
for (i = 0; i <= newtbl->hash_mask; i++)
spin_lock_init(&newtbl->hashwlock[i]);
+ spin_lock_init(&newtbl->gates_lock);
return newtbl;
}
@@ -118,6 +130,7 @@ static void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
{
struct hlist_head *mesh_hash;
struct hlist_node *p, *q;
+ struct mpath_node *gate;
int i;
mesh_hash = tbl->hash_buckets;
@@ -129,6 +142,17 @@ static void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
}
spin_unlock_bh(&tbl->hashwlock[i]);
}
+ if (free_leafs) {
+ spin_lock_bh(&tbl->gates_lock);
+ hlist_for_each_entry_safe(gate, p, q,
+ tbl->known_gates, list) {
+ hlist_del(&gate->list);
+ kfree(gate);
+ }
+ kfree(tbl->known_gates);
+ spin_unlock_bh(&tbl->gates_lock);
+ }
+
__mesh_table_free(tbl);
}
@@ -146,6 +170,7 @@ static int mesh_table_grow(struct mesh_table *oldtbl,
newtbl->free_node = oldtbl->free_node;
newtbl->mean_chain_len = oldtbl->mean_chain_len;
newtbl->copy_node = oldtbl->copy_node;
+ newtbl->known_gates = oldtbl->known_gates;
atomic_set(&newtbl->entries, atomic_read(&oldtbl->entries));
oldhash = oldtbl->hash_buckets;
@@ -188,6 +213,7 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
struct ieee80211_hdr *hdr;
struct sk_buff_head tmpq;
unsigned long flags;
+ struct ieee80211_sub_if_data *sdata = mpath->sdata;
rcu_assign_pointer(mpath->next_hop, sta);
@@ -198,6 +224,8 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
while ((skb = __skb_dequeue(&mpath->frame_queue)) != NULL) {
hdr = (struct ieee80211_hdr *) skb->data;
memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
+ skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, skb));
+ ieee80211_set_qos_hdr(sdata, skb);
__skb_queue_tail(&tmpq, skb);
}
@@ -205,62 +233,128 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
spin_unlock_irqrestore(&mpath->frame_queue.lock, flags);
}
+static void prepare_for_gate(struct sk_buff *skb, char *dst_addr,
+ struct mesh_path *gate_mpath)
+{
+ struct ieee80211_hdr *hdr;
+ struct ieee80211s_hdr *mshdr;
+ int mesh_hdrlen, hdrlen;
+ char *next_hop;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ hdrlen = ieee80211_hdrlen(hdr->frame_control);
+ mshdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
+
+ if (!(mshdr->flags & MESH_FLAGS_AE)) {
+ /* size of the fixed part of the mesh header */
+ mesh_hdrlen = 6;
+
+ /* make room for the two extended addresses */
+ skb_push(skb, 2 * ETH_ALEN);
+ memmove(skb->data, hdr, hdrlen + mesh_hdrlen);
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+
+ /* we preserve the previous mesh header and only add
+ * the new addreses */
+ mshdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
+ mshdr->flags = MESH_FLAGS_AE_A5_A6;
+ memcpy(mshdr->eaddr1, hdr->addr3, ETH_ALEN);
+ memcpy(mshdr->eaddr2, hdr->addr4, ETH_ALEN);
+ }
+
+ /* update next hop */
+ hdr = (struct ieee80211_hdr *) skb->data;
+ rcu_read_lock();
+ next_hop = rcu_dereference(gate_mpath->next_hop)->sta.addr;
+ memcpy(hdr->addr1, next_hop, ETH_ALEN);
+ rcu_read_unlock();
+ memcpy(hdr->addr3, dst_addr, ETH_ALEN);
+}
/**
- * mesh_path_lookup - look up a path in the mesh path table
- * @dst: hardware address (ETH_ALEN length) of destination
- * @sdata: local subif
*
- * Returns: pointer to the mesh path structure, or NULL if not found
+ * mesh_path_move_to_queue - Move or copy frames from one mpath queue to another
*
- * Locking: must be called within a read rcu section.
+ * This function is used to transfer or copy frames from an unresolved mpath to
+ * a gate mpath. The function also adds the Address Extension field and
+ * updates the next hop.
+ *
+ * If a frame already has an Address Extension field, only the next hop and
+ * destination addresses are updated.
+ *
+ * The gate mpath must be an active mpath with a valid mpath->next_hop.
+ *
+ * @mpath: An active mpath the frames will be sent to (i.e. the gate)
+ * @from_mpath: The failed mpath
+ * @copy: When true, copy all the frames to the new mpath queue. When false,
+ * move them.
*/
-struct mesh_path *mesh_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
+static void mesh_path_move_to_queue(struct mesh_path *gate_mpath,
+ struct mesh_path *from_mpath,
+ bool copy)
{
- struct mesh_path *mpath;
- struct hlist_node *n;
- struct hlist_head *bucket;
- struct mesh_table *tbl;
- struct mpath_node *node;
+ struct sk_buff *skb, *cp_skb = NULL;
+ struct sk_buff_head gateq, failq;
+ unsigned long flags;
+ int num_skbs;
- tbl = rcu_dereference(mesh_paths);
+ BUG_ON(gate_mpath == from_mpath);
+ BUG_ON(!gate_mpath->next_hop);
- bucket = &tbl->hash_buckets[mesh_table_hash(dst, sdata, tbl)];
- hlist_for_each_entry_rcu(node, n, bucket, list) {
- mpath = node->mpath;
- if (mpath->sdata == sdata &&
- memcmp(dst, mpath->dst, ETH_ALEN) == 0) {
- if (MPATH_EXPIRED(mpath)) {
- spin_lock_bh(&mpath->state_lock);
- if (MPATH_EXPIRED(mpath))
- mpath->flags &= ~MESH_PATH_ACTIVE;
- spin_unlock_bh(&mpath->state_lock);
- }
- return mpath;
+ __skb_queue_head_init(&gateq);
+ __skb_queue_head_init(&failq);
+
+ spin_lock_irqsave(&from_mpath->frame_queue.lock, flags);
+ skb_queue_splice_init(&from_mpath->frame_queue, &failq);
+ spin_unlock_irqrestore(&from_mpath->frame_queue.lock, flags);
+
+ num_skbs = skb_queue_len(&failq);
+
+ while (num_skbs--) {
+ skb = __skb_dequeue(&failq);
+ if (copy) {
+ cp_skb = skb_copy(skb, GFP_ATOMIC);
+ if (cp_skb)
+ __skb_queue_tail(&failq, cp_skb);
}
+
+ prepare_for_gate(skb, gate_mpath->dst, gate_mpath);
+ __skb_queue_tail(&gateq, skb);
}
- return NULL;
+
+ spin_lock_irqsave(&gate_mpath->frame_queue.lock, flags);
+ skb_queue_splice(&gateq, &gate_mpath->frame_queue);
+ mpath_dbg("Mpath queue for gate %pM has %d frames\n",
+ gate_mpath->dst,
+ skb_queue_len(&gate_mpath->frame_queue));
+ spin_unlock_irqrestore(&gate_mpath->frame_queue.lock, flags);
+
+ if (!copy)
+ return;
+
+ spin_lock_irqsave(&from_mpath->frame_queue.lock, flags);
+ skb_queue_splice(&failq, &from_mpath->frame_queue);
+ spin_unlock_irqrestore(&from_mpath->frame_queue.lock, flags);
}
-struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
+
+static struct mesh_path *path_lookup(struct mesh_table *tbl, u8 *dst,
+ struct ieee80211_sub_if_data *sdata)
{
struct mesh_path *mpath;
struct hlist_node *n;
struct hlist_head *bucket;
- struct mesh_table *tbl;
struct mpath_node *node;
- tbl = rcu_dereference(mpp_paths);
-
bucket = &tbl->hash_buckets[mesh_table_hash(dst, sdata, tbl)];
hlist_for_each_entry_rcu(node, n, bucket, list) {
mpath = node->mpath;
if (mpath->sdata == sdata &&
- memcmp(dst, mpath->dst, ETH_ALEN) == 0) {
+ memcmp(dst, mpath->dst, ETH_ALEN) == 0) {
if (MPATH_EXPIRED(mpath)) {
spin_lock_bh(&mpath->state_lock);
- if (MPATH_EXPIRED(mpath))
- mpath->flags &= ~MESH_PATH_ACTIVE;
+ mpath->flags &= ~MESH_PATH_ACTIVE;
spin_unlock_bh(&mpath->state_lock);
}
return mpath;
@@ -269,6 +363,25 @@ struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
return NULL;
}
+/**
+ * mesh_path_lookup - look up a path in the mesh path table
+ * @dst: hardware address (ETH_ALEN length) of destination
+ * @sdata: local subif
+ *
+ * Returns: pointer to the mesh path structure, or NULL if not found
+ *
+ * Locking: must be called within a read rcu section.
+ */
+struct mesh_path *mesh_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
+{
+ return path_lookup(rcu_dereference(mesh_paths), dst, sdata);
+}
+
+struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
+{
+ return path_lookup(rcu_dereference(mpp_paths), dst, sdata);
+}
+
/**
* mesh_path_lookup_by_idx - look up a path in the mesh path table by its index
@@ -293,8 +406,7 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data
if (j++ == idx) {
if (MPATH_EXPIRED(node->mpath)) {
spin_lock_bh(&node->mpath->state_lock);
- if (MPATH_EXPIRED(node->mpath))
- node->mpath->flags &= ~MESH_PATH_ACTIVE;
+ node->mpath->flags &= ~MESH_PATH_ACTIVE;
spin_unlock_bh(&node->mpath->state_lock);
}
return node->mpath;
@@ -304,6 +416,109 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data
return NULL;
}
+static void mesh_gate_node_reclaim(struct rcu_head *rp)
+{
+ struct mpath_node *node = container_of(rp, struct mpath_node, rcu);
+ kfree(node);
+}
+
+/**
+ * mesh_gate_add - mark mpath as path to a mesh gate and add to known_gates
+ * @mesh_tbl: table which contains known_gates list
+ * @mpath: mpath to known mesh gate
+ *
+ * Returns: 0 on success
+ *
+ */
+static int mesh_gate_add(struct mesh_table *tbl, struct mesh_path *mpath)
+{
+ struct mpath_node *gate, *new_gate;
+ struct hlist_node *n;
+ int err;
+
+ rcu_read_lock();
+ tbl = rcu_dereference(tbl);
+
+ hlist_for_each_entry_rcu(gate, n, tbl->known_gates, list)
+ if (gate->mpath == mpath) {
+ err = -EEXIST;
+ goto err_rcu;
+ }
+
+ new_gate = kzalloc(sizeof(struct mpath_node), GFP_ATOMIC);
+ if (!new_gate) {
+ err = -ENOMEM;
+ goto err_rcu;
+ }
+
+ mpath->is_gate = true;
+ mpath->sdata->u.mesh.num_gates++;
+ new_gate->mpath = mpath;
+ spin_lock_bh(&tbl->gates_lock);
+ hlist_add_head_rcu(&new_gate->list, tbl->known_gates);
+ spin_unlock_bh(&tbl->gates_lock);
+ rcu_read_unlock();
+ mpath_dbg("Mesh path (%s): Recorded new gate: %pM. %d known gates\n",
+ mpath->sdata->name, mpath->dst,
+ mpath->sdata->u.mesh.num_gates);
+ return 0;
+err_rcu:
+ rcu_read_unlock();
+ return err;
+}
+
+/**
+ * mesh_gate_del - remove a mesh gate from the list of known gates
+ * @tbl: table which holds our list of known gates
+ * @mpath: gate mpath
+ *
+ * Returns: 0 on success
+ *
+ * Locking: must be called inside rcu_read_lock() section
+ */
+static int mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath)
+{
+ struct mpath_node *gate;
+ struct hlist_node *p, *q;
+
+ tbl = rcu_dereference(tbl);
+
+ hlist_for_each_entry_safe(gate, p, q, tbl->known_gates, list)
+ if (gate->mpath == mpath) {
+ spin_lock_bh(&tbl->gates_lock);
+ hlist_del_rcu(&gate->list);
+ call_rcu(&gate->rcu, mesh_gate_node_reclaim);
+ spin_unlock_bh(&tbl->gates_lock);
+ mpath->sdata->u.mesh.num_gates--;
+ mpath->is_gate = false;
+ mpath_dbg("Mesh path (%s): Deleted gate: %pM. "
+ "%d known gates\n", mpath->sdata->name,
+ mpath->dst, mpath->sdata->u.mesh.num_gates);
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ *
+ * mesh_path_add_gate - add the given mpath to a mesh gate to our path table
+ * @mpath: gate path to add to table
+ */
+int mesh_path_add_gate(struct mesh_path *mpath)
+{
+ return mesh_gate_add(mesh_paths, mpath);
+}
+
+/**
+ * mesh_gate_num - number of gates known to this interface
+ * @sdata: subif data
+ */
+int mesh_gate_num(struct ieee80211_sub_if_data *sdata)
+{
+ return sdata->u.mesh.num_gates;
+}
+
/**
* mesh_path_add - allocate and add a new path to the mesh path table
* @addr: destination address of the path (ETH_ALEN length)
@@ -481,6 +696,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
new_mpath->flags = 0;
skb_queue_head_init(&new_mpath->frame_queue);
new_node->mpath = new_mpath;
+ init_timer(&new_mpath->timer);
new_mpath->exp_time = jiffies;
spin_lock_init(&new_mpath->state_lock);
@@ -539,28 +755,53 @@ void mesh_plink_broken(struct sta_info *sta)
struct hlist_node *p;
struct ieee80211_sub_if_data *sdata = sta->sdata;
int i;
+ __le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_DEST_UNREACHABLE);
rcu_read_lock();
tbl = rcu_dereference(mesh_paths);
for_each_mesh_entry(tbl, p, node, i) {
mpath = node->mpath;
- spin_lock_bh(&mpath->state_lock);
if (rcu_dereference(mpath->next_hop) == sta &&
mpath->flags & MESH_PATH_ACTIVE &&
!(mpath->flags & MESH_PATH_FIXED)) {
+ spin_lock_bh(&mpath->state_lock);
mpath->flags &= ~MESH_PATH_ACTIVE;
++mpath->sn;
spin_unlock_bh(&mpath->state_lock);
mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl,
mpath->dst, cpu_to_le32(mpath->sn),
- cpu_to_le16(PERR_RCODE_DEST_UNREACH),
- bcast, sdata);
- } else
- spin_unlock_bh(&mpath->state_lock);
+ reason, bcast, sdata);
+ }
}
rcu_read_unlock();
}
+static void mesh_path_node_reclaim(struct rcu_head *rp)
+{
+ struct mpath_node *node = container_of(rp, struct mpath_node, rcu);
+ struct ieee80211_sub_if_data *sdata = node->mpath->sdata;
+
+ del_timer_sync(&node->mpath->timer);
+ atomic_dec(&sdata->u.mesh.mpaths);
+ kfree(node->mpath);
+ kfree(node);
+}
+
+/* needs to be called with the corresponding hashwlock taken */
+static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node)
+{
+ struct mesh_path *mpath;
+ mpath = node->mpath;
+ spin_lock(&mpath->state_lock);
+ mpath->flags |= MESH_PATH_RESOLVING;
+ if (mpath->is_gate)
+ mesh_gate_del(tbl, mpath);
+ hlist_del_rcu(&node->list);
+ call_rcu(&node->rcu, mesh_path_node_reclaim);
+ spin_unlock(&mpath->state_lock);
+ atomic_dec(&tbl->entries);
+}
+
/**
* mesh_path_flush_by_nexthop - Deletes mesh paths if their next hop matches
*
@@ -581,42 +822,59 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta)
int i;
rcu_read_lock();
- tbl = rcu_dereference(mesh_paths);
+ read_lock_bh(&pathtbl_resize_lock);
+ tbl = resize_dereference_mesh_paths();
for_each_mesh_entry(tbl, p, node, i) {
mpath = node->mpath;
- if (rcu_dereference(mpath->next_hop) == sta)
- mesh_path_del(mpath->dst, mpath->sdata);
+ if (rcu_dereference(mpath->next_hop) == sta) {
+ spin_lock_bh(&tbl->hashwlock[i]);
+ __mesh_path_del(tbl, node);
+ spin_unlock_bh(&tbl->hashwlock[i]);
+ }
}
+ read_unlock_bh(&pathtbl_resize_lock);
rcu_read_unlock();
}
-void mesh_path_flush(struct ieee80211_sub_if_data *sdata)
+static void table_flush_by_iface(struct mesh_table *tbl,
+ struct ieee80211_sub_if_data *sdata)
{
- struct mesh_table *tbl;
struct mesh_path *mpath;
struct mpath_node *node;
struct hlist_node *p;
int i;
- rcu_read_lock();
- tbl = rcu_dereference(mesh_paths);
+ WARN_ON(!rcu_read_lock_held());
for_each_mesh_entry(tbl, p, node, i) {
mpath = node->mpath;
- if (mpath->sdata == sdata)
- mesh_path_del(mpath->dst, mpath->sdata);
+ if (mpath->sdata != sdata)
+ continue;
+ spin_lock_bh(&tbl->hashwlock[i]);
+ __mesh_path_del(tbl, node);
+ spin_unlock_bh(&tbl->hashwlock[i]);
}
- rcu_read_unlock();
}
-static void mesh_path_node_reclaim(struct rcu_head *rp)
+/**
+ * mesh_path_flush_by_iface - Deletes all mesh paths associated with a given iface
+ *
+ * This function deletes both mesh paths as well as mesh portal paths.
+ *
+ * @sdata - interface data to match
+ *
+ */
+void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
{
- struct mpath_node *node = container_of(rp, struct mpath_node, rcu);
- struct ieee80211_sub_if_data *sdata = node->mpath->sdata;
+ struct mesh_table *tbl;
- del_timer_sync(&node->mpath->timer);
- atomic_dec(&sdata->u.mesh.mpaths);
- kfree(node->mpath);
- kfree(node);
+ rcu_read_lock();
+ read_lock_bh(&pathtbl_resize_lock);
+ tbl = resize_dereference_mesh_paths();
+ table_flush_by_iface(tbl, sdata);
+ tbl = resize_dereference_mpp_paths();
+ table_flush_by_iface(tbl, sdata);
+ read_unlock_bh(&pathtbl_resize_lock);
+ rcu_read_unlock();
}
/**
@@ -647,12 +905,7 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata)
mpath = node->mpath;
if (mpath->sdata == sdata &&
memcmp(addr, mpath->dst, ETH_ALEN) == 0) {
- spin_lock(&mpath->state_lock);
- mpath->flags |= MESH_PATH_RESOLVING;
- hlist_del_rcu(&node->list);
- call_rcu(&node->rcu, mesh_path_node_reclaim);
- atomic_dec(&tbl->entries);
- spin_unlock(&mpath->state_lock);
+ __mesh_path_del(tbl, node);
goto enddel;
}
}
@@ -681,6 +934,58 @@ void mesh_path_tx_pending(struct mesh_path *mpath)
}
/**
+ * mesh_path_send_to_gates - sends pending frames to all known mesh gates
+ *
+ * @mpath: mesh path whose queue will be emptied
+ *
+ * If there is only one gate, the frames are transferred from the failed mpath
+ * queue to that gate's queue. If there are more than one gates, the frames
+ * are copied from each gate to the next. After frames are copied, the
+ * mpath queues are emptied onto the transmission queue.
+ */
+int mesh_path_send_to_gates(struct mesh_path *mpath)
+{
+ struct ieee80211_sub_if_data *sdata = mpath->sdata;
+ struct hlist_node *n;
+ struct mesh_table *tbl;
+ struct mesh_path *from_mpath = mpath;
+ struct mpath_node *gate = NULL;
+ bool copy = false;
+ struct hlist_head *known_gates;
+
+ rcu_read_lock();
+ tbl = rcu_dereference(mesh_paths);
+ known_gates = tbl->known_gates;
+ rcu_read_unlock();
+
+ if (!known_gates)
+ return -EHOSTUNREACH;
+
+ hlist_for_each_entry_rcu(gate, n, known_gates, list) {
+ if (gate->mpath->sdata != sdata)
+ continue;
+
+ if (gate->mpath->flags & MESH_PATH_ACTIVE) {
+ mpath_dbg("Forwarding to %pM\n", gate->mpath->dst);
+ mesh_path_move_to_queue(gate->mpath, from_mpath, copy);
+ from_mpath = gate->mpath;
+ copy = true;
+ } else {
+ mpath_dbg("Not forwarding %p\n", gate->mpath);
+ mpath_dbg("flags %x\n", gate->mpath->flags);
+ }
+ }
+
+ hlist_for_each_entry_rcu(gate, n, known_gates, list)
+ if (gate->mpath->sdata == sdata) {
+ mpath_dbg("Sending to %pM\n", gate->mpath->dst);
+ mesh_path_tx_pending(gate->mpath);
+ }
+
+ return (from_mpath == mpath) ? -EHOSTUNREACH : 0;
+}
+
+/**
* mesh_path_discard_frame - discard a frame whose path could not be resolved
*
* @skb: frame to discard
@@ -699,18 +1004,23 @@ void mesh_path_discard_frame(struct sk_buff *skb,
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct mesh_path *mpath;
u32 sn = 0;
+ __le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_NOFORWARD);
if (memcmp(hdr->addr4, sdata->vif.addr, ETH_ALEN) != 0) {
u8 *ra, *da;
da = hdr->addr3;
ra = hdr->addr1;
+ rcu_read_lock();
mpath = mesh_path_lookup(da, sdata);
- if (mpath)
+ if (mpath) {
+ spin_lock_bh(&mpath->state_lock);
sn = ++mpath->sn;
+ spin_unlock_bh(&mpath->state_lock);
+ }
+ rcu_read_unlock();
mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, skb->data,
- cpu_to_le32(sn),
- cpu_to_le16(PERR_RCODE_NO_ROUTE), ra, sdata);
+ cpu_to_le32(sn), reason, ra, sdata);
}
kfree_skb(skb);
@@ -728,8 +1038,7 @@ void mesh_path_flush_pending(struct mesh_path *mpath)
{
struct sk_buff *skb;
- while ((skb = skb_dequeue(&mpath->frame_queue)) &&
- (mpath->flags & MESH_PATH_ACTIVE))
+ while ((skb = skb_dequeue(&mpath->frame_queue)) != NULL)
mesh_path_discard_frame(skb, mpath->sdata);
}
@@ -790,6 +1099,7 @@ static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
int mesh_pathtbl_init(void)
{
struct mesh_table *tbl_path, *tbl_mpp;
+ int ret;
tbl_path = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
if (!tbl_path)
@@ -797,21 +1107,40 @@ int mesh_pathtbl_init(void)
tbl_path->free_node = &mesh_path_node_free;
tbl_path->copy_node = &mesh_path_node_copy;
tbl_path->mean_chain_len = MEAN_CHAIN_LEN;
+ tbl_path->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC);
+ if (!tbl_path->known_gates) {
+ ret = -ENOMEM;
+ goto free_path;
+ }
+ INIT_HLIST_HEAD(tbl_path->known_gates);
+
tbl_mpp = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
if (!tbl_mpp) {
- mesh_table_free(tbl_path, true);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto free_path;
}
tbl_mpp->free_node = &mesh_path_node_free;
tbl_mpp->copy_node = &mesh_path_node_copy;
tbl_mpp->mean_chain_len = MEAN_CHAIN_LEN;
+ tbl_mpp->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC);
+ if (!tbl_mpp->known_gates) {
+ ret = -ENOMEM;
+ goto free_mpp;
+ }
+ INIT_HLIST_HEAD(tbl_mpp->known_gates);
/* Need no locking since this is during init */
RCU_INIT_POINTER(mesh_paths, tbl_path);
RCU_INIT_POINTER(mpp_paths, tbl_mpp);
return 0;
+
+free_mpp:
+ mesh_table_free(tbl_mpp, true);
+free_path:
+ mesh_table_free(tbl_path, true);
+ return ret;
}
void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
@@ -828,14 +1157,10 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
if (node->mpath->sdata != sdata)
continue;
mpath = node->mpath;
- spin_lock_bh(&mpath->state_lock);
if ((!(mpath->flags & MESH_PATH_RESOLVING)) &&
(!(mpath->flags & MESH_PATH_FIXED)) &&
- time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) {
- spin_unlock_bh(&mpath->state_lock);
+ time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE))
mesh_path_del(mpath->dst, mpath->sdata);
- } else
- spin_unlock_bh(&mpath->state_lock);
}
rcu_read_unlock();
}
@@ -843,6 +1168,6 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
void mesh_pathtbl_unregister(void)
{
/* no need for locking during exit path */
- mesh_table_free(rcu_dereference_raw(mesh_paths), true);
- mesh_table_free(rcu_dereference_raw(mpp_paths), true);
+ mesh_table_free(rcu_dereference_protected(mesh_paths, 1), true);
+ mesh_table_free(rcu_dereference_protected(mpp_paths, 1), true);
}
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index f4adc0917888..7e57f5d07f66 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -19,35 +19,18 @@
#define mpl_dbg(fmt, args...) do { (void)(0); } while (0)
#endif
-#define PLINK_GET_LLID(p) (p + 4)
-#define PLINK_GET_PLID(p) (p + 6)
+#define PLINK_GET_LLID(p) (p + 2)
+#define PLINK_GET_PLID(p) (p + 4)
#define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \
jiffies + HZ * t / 1000))
-/* Peer link cancel reasons, all subject to ANA approval */
-#define MESH_LINK_CANCELLED 2
-#define MESH_MAX_NEIGHBORS 3
-#define MESH_CAPABILITY_POLICY_VIOLATION 4
-#define MESH_CLOSE_RCVD 5
-#define MESH_MAX_RETRIES 6
-#define MESH_CONFIRM_TIMEOUT 7
-#define MESH_SECURITY_ROLE_NEGOTIATION_DIFFERS 8
-#define MESH_SECURITY_AUTHENTICATION_IMPOSSIBLE 9
-#define MESH_SECURITY_FAILED_VERIFICATION 10
-
#define dot11MeshMaxRetries(s) (s->u.mesh.mshcfg.dot11MeshMaxRetries)
#define dot11MeshRetryTimeout(s) (s->u.mesh.mshcfg.dot11MeshRetryTimeout)
#define dot11MeshConfirmTimeout(s) (s->u.mesh.mshcfg.dot11MeshConfirmTimeout)
#define dot11MeshHoldingTimeout(s) (s->u.mesh.mshcfg.dot11MeshHoldingTimeout)
#define dot11MeshMaxPeerLinks(s) (s->u.mesh.mshcfg.dot11MeshMaxPeerLinks)
-enum plink_frame_type {
- PLINK_OPEN = 1,
- PLINK_CONFIRM,
- PLINK_CLOSE
-};
-
enum plink_event {
PLINK_UNDEFINED,
OPN_ACPT,
@@ -60,6 +43,10 @@ enum plink_event {
CLS_IGNR
};
+static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
+ enum ieee80211_self_protected_actioncode action,
+ u8 *da, __le16 llid, __le16 plid, __le16 reason);
+
static inline
void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
{
@@ -105,7 +92,9 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
if (!sta)
return NULL;
- sta->flags = WLAN_STA_AUTHORIZED | WLAN_STA_AUTH;
+ set_sta_flag(sta, WLAN_STA_AUTH);
+ set_sta_flag(sta, WLAN_STA_AUTHORIZED);
+ set_sta_flag(sta, WLAN_STA_WME);
sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
rate_control_rate_init(sta);
@@ -150,6 +139,10 @@ void mesh_plink_deactivate(struct sta_info *sta)
spin_lock_bh(&sta->lock);
deactivated = __mesh_plink_deactivate(sta);
+ sta->reason = cpu_to_le16(WLAN_REASON_MESH_PEER_CANCELED);
+ mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
+ sta->sta.addr, sta->llid, sta->plid,
+ sta->reason);
spin_unlock_bh(&sta->lock);
if (deactivated)
@@ -157,16 +150,16 @@ void mesh_plink_deactivate(struct sta_info *sta)
}
static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
- enum plink_frame_type action, u8 *da, __le16 llid, __le16 plid,
- __le16 reason) {
+ enum ieee80211_self_protected_actioncode action,
+ u8 *da, __le16 llid, __le16 plid, __le16 reason) {
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 +
sdata->u.mesh.ie_len);
struct ieee80211_mgmt *mgmt;
bool include_plid = false;
- static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A };
+ int ie_len = 4;
+ u16 peering_proto = 0;
u8 *pos;
- int ie_len;
if (!skb)
return -1;
@@ -175,63 +168,75 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
* common action part (1)
*/
mgmt = (struct ieee80211_mgmt *)
- skb_put(skb, 25 + sizeof(mgmt->u.action.u.plink_action));
- memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.plink_action));
+ skb_put(skb, 25 + sizeof(mgmt->u.action.u.self_prot));
+ memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.self_prot));
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION);
memcpy(mgmt->da, da, ETH_ALEN);
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
- mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION;
- mgmt->u.action.u.plink_action.action_code = action;
-
- if (action == PLINK_CLOSE)
- mgmt->u.action.u.plink_action.aux = reason;
- else {
- mgmt->u.action.u.plink_action.aux = cpu_to_le16(0x0);
- if (action == PLINK_CONFIRM) {
- pos = skb_put(skb, 4);
- /* two-byte status code followed by two-byte AID */
- memset(pos, 0, 2);
+ mgmt->u.action.category = WLAN_CATEGORY_SELF_PROTECTED;
+ mgmt->u.action.u.self_prot.action_code = action;
+
+ if (action != WLAN_SP_MESH_PEERING_CLOSE) {
+ /* capability info */
+ pos = skb_put(skb, 2);
+ memset(pos, 0, 2);
+ if (action == WLAN_SP_MESH_PEERING_CONFIRM) {
+ /* AID */
+ pos = skb_put(skb, 2);
memcpy(pos + 2, &plid, 2);
}
- mesh_mgmt_ies_add(skb, sdata);
+ if (ieee80211_add_srates_ie(&sdata->vif, skb) ||
+ ieee80211_add_ext_srates_ie(&sdata->vif, skb) ||
+ mesh_add_rsn_ie(skb, sdata) ||
+ mesh_add_meshid_ie(skb, sdata) ||
+ mesh_add_meshconf_ie(skb, sdata))
+ return -1;
+ } else { /* WLAN_SP_MESH_PEERING_CLOSE */
+ if (mesh_add_meshid_ie(skb, sdata))
+ return -1;
}
- /* Add Peer Link Management element */
+ /* Add Mesh Peering Management element */
switch (action) {
- case PLINK_OPEN:
- ie_len = 6;
+ case WLAN_SP_MESH_PEERING_OPEN:
break;
- case PLINK_CONFIRM:
- ie_len = 8;
+ case WLAN_SP_MESH_PEERING_CONFIRM:
+ ie_len += 2;
include_plid = true;
break;
- case PLINK_CLOSE:
- default:
- if (!plid)
- ie_len = 8;
- else {
- ie_len = 10;
+ case WLAN_SP_MESH_PEERING_CLOSE:
+ if (plid) {
+ ie_len += 2;
include_plid = true;
}
+ ie_len += 2; /* reason code */
break;
+ default:
+ return -EINVAL;
}
+ if (WARN_ON(skb_tailroom(skb) < 2 + ie_len))
+ return -ENOMEM;
+
pos = skb_put(skb, 2 + ie_len);
- *pos++ = WLAN_EID_PEER_LINK;
+ *pos++ = WLAN_EID_PEER_MGMT;
*pos++ = ie_len;
- memcpy(pos, meshpeeringproto, sizeof(meshpeeringproto));
- pos += 4;
+ memcpy(pos, &peering_proto, 2);
+ pos += 2;
memcpy(pos, &llid, 2);
+ pos += 2;
if (include_plid) {
- pos += 2;
memcpy(pos, &plid, 2);
- }
- if (action == PLINK_CLOSE) {
pos += 2;
+ }
+ if (action == WLAN_SP_MESH_PEERING_CLOSE) {
memcpy(pos, &reason, 2);
+ pos += 2;
}
+ if (mesh_add_vendor_ies(skb, sdata))
+ return -1;
ieee80211_tx_skb(sdata, skb);
return 0;
@@ -322,21 +327,21 @@ static void mesh_plink_timer(unsigned long data)
++sta->plink_retries;
mod_plink_timer(sta, sta->plink_timeout);
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, PLINK_OPEN, sta->sta.addr, llid,
- 0, 0);
+ mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,
+ sta->sta.addr, llid, 0, 0);
break;
}
- reason = cpu_to_le16(MESH_MAX_RETRIES);
+ reason = cpu_to_le16(WLAN_REASON_MESH_MAX_RETRIES);
/* fall through on else */
case NL80211_PLINK_CNF_RCVD:
/* confirm timer */
if (!reason)
- reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT);
+ reason = cpu_to_le16(WLAN_REASON_MESH_CONFIRM_TIMEOUT);
sta->plink_state = NL80211_PLINK_HOLDING;
mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, plid,
- reason);
+ mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
+ sta->sta.addr, llid, plid, reason);
break;
case NL80211_PLINK_HOLDING:
/* holding timer */
@@ -380,7 +385,7 @@ int mesh_plink_open(struct sta_info *sta)
__le16 llid;
struct ieee80211_sub_if_data *sdata = sta->sdata;
- if (!test_sta_flags(sta, WLAN_STA_AUTH))
+ if (!test_sta_flag(sta, WLAN_STA_AUTH))
return -EPERM;
spin_lock_bh(&sta->lock);
@@ -396,7 +401,7 @@ int mesh_plink_open(struct sta_info *sta)
mpl_dbg("Mesh plink: starting establishment with %pM\n",
sta->sta.addr);
- return mesh_plink_frame_tx(sdata, PLINK_OPEN,
+ return mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,
sta->sta.addr, llid, 0, 0);
}
@@ -422,7 +427,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
struct ieee802_11_elems elems;
struct sta_info *sta;
enum plink_event event;
- enum plink_frame_type ftype;
+ enum ieee80211_self_protected_actioncode ftype;
size_t baselen;
bool deactivated, matches_local = true;
u8 ie_len;
@@ -449,14 +454,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
return;
}
- baseaddr = mgmt->u.action.u.plink_action.variable;
- baselen = (u8 *) mgmt->u.action.u.plink_action.variable - (u8 *) mgmt;
- if (mgmt->u.action.u.plink_action.action_code == PLINK_CONFIRM) {
+ baseaddr = mgmt->u.action.u.self_prot.variable;
+ baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt;
+ if (mgmt->u.action.u.self_prot.action_code ==
+ WLAN_SP_MESH_PEERING_CONFIRM) {
baseaddr += 4;
baselen += 4;
}
ieee802_11_parse_elems(baseaddr, len - baselen, &elems);
- if (!elems.peer_link) {
+ if (!elems.peering) {
mpl_dbg("Mesh plink: missing necessary peer link ie\n");
return;
}
@@ -466,37 +472,40 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
return;
}
- ftype = mgmt->u.action.u.plink_action.action_code;
- ie_len = elems.peer_link_len;
- if ((ftype == PLINK_OPEN && ie_len != 6) ||
- (ftype == PLINK_CONFIRM && ie_len != 8) ||
- (ftype == PLINK_CLOSE && ie_len != 8 && ie_len != 10)) {
+ ftype = mgmt->u.action.u.self_prot.action_code;
+ ie_len = elems.peering_len;
+ if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) ||
+ (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||
+ (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6
+ && ie_len != 8)) {
mpl_dbg("Mesh plink: incorrect plink ie length %d %d\n",
ftype, ie_len);
return;
}
- if (ftype != PLINK_CLOSE && (!elems.mesh_id || !elems.mesh_config)) {
+ if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
+ (!elems.mesh_id || !elems.mesh_config)) {
mpl_dbg("Mesh plink: missing necessary ie\n");
return;
}
/* Note the lines below are correct, the llid in the frame is the plid
* from the point of view of this host.
*/
- memcpy(&plid, PLINK_GET_LLID(elems.peer_link), 2);
- if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 10))
- memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2);
+ memcpy(&plid, PLINK_GET_LLID(elems.peering), 2);
+ if (ftype == WLAN_SP_MESH_PEERING_CONFIRM ||
+ (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8))
+ memcpy(&llid, PLINK_GET_PLID(elems.peering), 2);
rcu_read_lock();
sta = sta_info_get(sdata, mgmt->sa);
- if (!sta && ftype != PLINK_OPEN) {
+ if (!sta && ftype != WLAN_SP_MESH_PEERING_OPEN) {
mpl_dbg("Mesh plink: cls or cnf from unknown peer\n");
rcu_read_unlock();
return;
}
- if (sta && !test_sta_flags(sta, WLAN_STA_AUTH)) {
+ if (sta && !test_sta_flag(sta, WLAN_STA_AUTH)) {
mpl_dbg("Mesh plink: Action frame from non-authed peer\n");
rcu_read_unlock();
return;
@@ -509,30 +518,30 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
/* Now we will figure out the appropriate event... */
event = PLINK_UNDEFINED;
- if (ftype != PLINK_CLOSE && (!mesh_matches_local(&elems, sdata))) {
+ if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
+ (!mesh_matches_local(&elems, sdata))) {
matches_local = false;
switch (ftype) {
- case PLINK_OPEN:
+ case WLAN_SP_MESH_PEERING_OPEN:
event = OPN_RJCT;
break;
- case PLINK_CONFIRM:
+ case WLAN_SP_MESH_PEERING_CONFIRM:
event = CNF_RJCT;
break;
- case PLINK_CLOSE:
- /* avoid warning */
+ default:
break;
}
}
if (!sta && !matches_local) {
rcu_read_unlock();
- reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
+ reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
llid = 0;
- mesh_plink_frame_tx(sdata, PLINK_CLOSE, mgmt->sa, llid,
- plid, reason);
+ mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
+ mgmt->sa, llid, plid, reason);
return;
} else if (!sta) {
- /* ftype == PLINK_OPEN */
+ /* ftype == WLAN_SP_MESH_PEERING_OPEN */
u32 rates;
rcu_read_unlock();
@@ -557,21 +566,21 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
} else if (matches_local) {
spin_lock_bh(&sta->lock);
switch (ftype) {
- case PLINK_OPEN:
+ case WLAN_SP_MESH_PEERING_OPEN:
if (!mesh_plink_free_count(sdata) ||
(sta->plid && sta->plid != plid))
event = OPN_IGNR;
else
event = OPN_ACPT;
break;
- case PLINK_CONFIRM:
+ case WLAN_SP_MESH_PEERING_CONFIRM:
if (!mesh_plink_free_count(sdata) ||
(sta->llid != llid || sta->plid != plid))
event = CNF_IGNR;
else
event = CNF_ACPT;
break;
- case PLINK_CLOSE:
+ case WLAN_SP_MESH_PEERING_CLOSE:
if (sta->plink_state == NL80211_PLINK_ESTAB)
/* Do not check for llid or plid. This does not
* follow the standard but since multiple plinks
@@ -620,10 +629,12 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
sta->llid = llid;
mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, PLINK_OPEN, sta->sta.addr, llid,
- 0, 0);
- mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr,
- llid, plid, 0);
+ mesh_plink_frame_tx(sdata,
+ WLAN_SP_MESH_PEERING_OPEN,
+ sta->sta.addr, llid, 0, 0);
+ mesh_plink_frame_tx(sdata,
+ WLAN_SP_MESH_PEERING_CONFIRM,
+ sta->sta.addr, llid, plid, 0);
break;
default:
spin_unlock_bh(&sta->lock);
@@ -635,10 +646,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
- reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
+ reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
case CLS_ACPT:
if (!reason)
- reason = cpu_to_le16(MESH_CLOSE_RCVD);
+ reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
sta->reason = reason;
sta->plink_state = NL80211_PLINK_HOLDING;
if (!mod_plink_timer(sta,
@@ -647,8 +658,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
llid = sta->llid;
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
- plid, reason);
+ mesh_plink_frame_tx(sdata,
+ WLAN_SP_MESH_PEERING_CLOSE,
+ sta->sta.addr, llid, plid, reason);
break;
case OPN_ACPT:
/* retry timer is left untouched */
@@ -656,8 +668,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
sta->plid = plid;
llid = sta->llid;
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
- plid, 0);
+ mesh_plink_frame_tx(sdata,
+ WLAN_SP_MESH_PEERING_CONFIRM,
+ sta->sta.addr, llid, plid, 0);
break;
case CNF_ACPT:
sta->plink_state = NL80211_PLINK_CNF_RCVD;
@@ -677,10 +690,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
- reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
+ reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
case CLS_ACPT:
if (!reason)
- reason = cpu_to_le16(MESH_CLOSE_RCVD);
+ reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
sta->reason = reason;
sta->plink_state = NL80211_PLINK_HOLDING;
if (!mod_plink_timer(sta,
@@ -689,14 +702,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
llid = sta->llid;
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
- plid, reason);
+ mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
+ sta->sta.addr, llid, plid, reason);
break;
case OPN_ACPT:
llid = sta->llid;
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
- plid, 0);
+ mesh_plink_frame_tx(sdata,
+ WLAN_SP_MESH_PEERING_CONFIRM,
+ sta->sta.addr, llid, plid, 0);
break;
case CNF_ACPT:
del_timer(&sta->plink_timer);
@@ -717,10 +731,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
- reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
+ reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
case CLS_ACPT:
if (!reason)
- reason = cpu_to_le16(MESH_CLOSE_RCVD);
+ reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
sta->reason = reason;
sta->plink_state = NL80211_PLINK_HOLDING;
if (!mod_plink_timer(sta,
@@ -729,8 +743,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
llid = sta->llid;
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
- plid, reason);
+ mesh_plink_frame_tx(sdata,
+ WLAN_SP_MESH_PEERING_CLOSE,
+ sta->sta.addr, llid, plid, reason);
break;
case OPN_ACPT:
del_timer(&sta->plink_timer);
@@ -740,8 +755,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
sta->sta.addr);
- mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
- plid, 0);
+ mesh_plink_frame_tx(sdata,
+ WLAN_SP_MESH_PEERING_CONFIRM,
+ sta->sta.addr, llid, plid, 0);
break;
default:
spin_unlock_bh(&sta->lock);
@@ -752,7 +768,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
case NL80211_PLINK_ESTAB:
switch (event) {
case CLS_ACPT:
- reason = cpu_to_le16(MESH_CLOSE_RCVD);
+ reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
sta->reason = reason;
deactivated = __mesh_plink_deactivate(sta);
sta->plink_state = NL80211_PLINK_HOLDING;
@@ -761,14 +777,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
spin_unlock_bh(&sta->lock);
if (deactivated)
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
- mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
- plid, reason);
+ mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
+ sta->sta.addr, llid, plid, reason);
break;
case OPN_ACPT:
llid = sta->llid;
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
- plid, 0);
+ mesh_plink_frame_tx(sdata,
+ WLAN_SP_MESH_PEERING_CONFIRM,
+ sta->sta.addr, llid, plid, 0);
break;
default:
spin_unlock_bh(&sta->lock);
@@ -790,8 +807,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
llid = sta->llid;
reason = sta->reason;
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr,
- llid, plid, reason);
+ mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
+ sta->sta.addr, llid, plid, reason);
break;
default:
spin_unlock_bh(&sta->lock);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index d6470c7fd6ce..ba2da11a997b 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -17,7 +17,7 @@
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
#include <linux/rtnetlink.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
#include <linux/crc32.h>
#include <linux/slab.h>
#include <net/mac80211.h>
@@ -160,7 +160,8 @@ static int ecw2cw(int ecw)
*/
static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
struct ieee80211_ht_info *hti,
- const u8 *bssid, u16 ap_ht_cap_flags)
+ const u8 *bssid, u16 ap_ht_cap_flags,
+ bool beacon_htcap_ie)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
@@ -232,6 +233,21 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
WARN_ON(!ieee80211_set_channel_type(local, sdata, channel_type));
}
+ if (beacon_htcap_ie && (prev_chantype != channel_type)) {
+ /*
+ * Whenever the AP announces the HT mode change that can be
+ * 40MHz intolerant or etc., it would be safer to stop tx
+ * queues before doing hw config to avoid buffer overflow.
+ */
+ ieee80211_stop_queues_by_reason(&sdata->local->hw,
+ IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE);
+
+ /* flush out all packets */
+ synchronize_net();
+
+ drv_flush(local, false);
+ }
+
/* channel_type change automatically detected */
ieee80211_hw_config(local, 0);
@@ -243,6 +259,10 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
IEEE80211_RC_HT_CHANGED,
channel_type);
rcu_read_unlock();
+
+ if (beacon_htcap_ie)
+ ieee80211_wake_queues_by_reason(&sdata->local->hw,
+ IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE);
}
ht_opmode = le16_to_cpu(hti->operation_mode);
@@ -271,11 +291,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt;
skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt));
- if (!skb) {
- printk(KERN_DEBUG "%s: failed to allocate buffer for "
- "deauth/disassoc frame\n", sdata->name);
+ if (!skb)
return;
- }
+
skb_reserve(skb, local->hw.extra_tx_headroom);
mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
@@ -330,6 +348,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
{
struct sk_buff *skb;
struct ieee80211_hdr_3addr *nullfunc;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif);
if (!skb)
@@ -340,6 +359,10 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
nullfunc->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+ if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL))
+ IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE;
+
ieee80211_tx_skb(sdata, skb);
}
@@ -354,11 +377,9 @@ static void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local,
return;
skb = dev_alloc_skb(local->hw.extra_tx_headroom + 30);
- if (!skb) {
- printk(KERN_DEBUG "%s: failed to allocate buffer for 4addr "
- "nullfunc frame\n", sdata->name);
+ if (!skb)
return;
- }
+
skb_reserve(skb, local->hw.extra_tx_headroom);
nullfunc = (struct ieee80211_hdr *) skb_put(skb, 30);
@@ -394,6 +415,9 @@ static void ieee80211_chswitch_work(struct work_struct *work)
/* call "hw_config" only if doing sw channel switch */
ieee80211_hw_config(sdata->local,
IEEE80211_CONF_CHANGE_CHANNEL);
+ } else {
+ /* update the device channel directly */
+ sdata->local->hw.conf.channel = sdata->local->oper_channel;
}
/* XXX: shouldn't really modify cfg80211-owned data! */
@@ -608,7 +632,7 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_managed *mgd = &sdata->u.mgd;
struct sta_info *sta = NULL;
- u32 sta_flags = 0;
+ bool authorized = false;
if (!mgd->powersave)
return false;
@@ -626,13 +650,10 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata)
rcu_read_lock();
sta = sta_info_get(sdata, mgd->bssid);
if (sta)
- sta_flags = get_sta_flags(sta);
+ authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
rcu_read_unlock();
- if (!(sta_flags & WLAN_STA_AUTHORIZED))
- return false;
-
- return true;
+ return authorized;
}
/* need to hold RTNL or interface lock */
@@ -917,8 +938,8 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
params.aifs, params.cw_min, params.cw_max,
params.txop, params.uapsd);
#endif
- local->tx_conf[queue] = params;
- if (drv_conf_tx(local, queue, &params))
+ sdata->tx_conf[queue] = params;
+ if (drv_conf_tx(local, sdata, queue, &params))
wiphy_debug(local->hw.wiphy,
"failed to set TX queue parameters for queue %d\n",
queue);
@@ -1076,7 +1097,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
mutex_lock(&local->sta_mtx);
sta = sta_info_get(sdata, bssid);
if (sta) {
- set_sta_flags(sta, WLAN_STA_BLOCK_BA);
+ set_sta_flag(sta, WLAN_STA_BLOCK_BA);
ieee80211_sta_tear_down_BA_sessions(sta, tx);
}
mutex_unlock(&local->sta_mtx);
@@ -1118,8 +1139,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
ieee80211_bss_info_change_notify(sdata, changed);
+ /* remove AP and TDLS peers */
if (remove_sta)
- sta_info_destroy_addr(sdata, bssid);
+ sta_info_flush(local, sdata);
del_timer_sync(&sdata->u.mgd.conn_mon_timer);
del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
@@ -1220,7 +1242,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
} else {
ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0,
- (u32) -1, true);
+ (u32) -1, true, false);
}
ifmgd->probe_send_count++;
@@ -1482,17 +1504,22 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
ifmgd->aid = aid;
- sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL);
- if (!sta) {
- printk(KERN_DEBUG "%s: failed to alloc STA entry for"
- " the AP\n", sdata->name);
+ mutex_lock(&sdata->local->sta_mtx);
+ /*
+ * station info was already allocated and inserted before
+ * the association and should be available to us
+ */
+ sta = sta_info_get_rx(sdata, cbss->bssid);
+ if (WARN_ON(!sta)) {
+ mutex_unlock(&sdata->local->sta_mtx);
return false;
}
- set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC |
- WLAN_STA_ASSOC_AP);
+ set_sta_flag(sta, WLAN_STA_AUTH);
+ set_sta_flag(sta, WLAN_STA_ASSOC);
+ set_sta_flag(sta, WLAN_STA_ASSOC_AP);
if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
- set_sta_flags(sta, WLAN_STA_AUTHORIZED);
+ set_sta_flag(sta, WLAN_STA_AUTHORIZED);
rates = 0;
basic_rates = 0;
@@ -1551,12 +1578,13 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
rate_control_rate_init(sta);
if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED)
- set_sta_flags(sta, WLAN_STA_MFP);
+ set_sta_flag(sta, WLAN_STA_MFP);
if (elems.wmm_param)
- set_sta_flags(sta, WLAN_STA_WME);
+ set_sta_flag(sta, WLAN_STA_WME);
- err = sta_info_insert(sta);
+ /* sta_info_reinsert will also unlock the mutex lock */
+ err = sta_info_reinsert(sta);
sta = NULL;
if (err) {
printk(KERN_DEBUG "%s: failed to insert STA entry for"
@@ -1584,7 +1612,8 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
(sdata->local->hw.queues >= 4) &&
!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
- cbss->bssid, ap_ht_cap_flags);
+ cbss->bssid, ap_ht_cap_flags,
+ false);
/* set AID and assoc capability,
* ieee80211_set_associated() will tell the driver */
@@ -1918,7 +1947,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
rcu_read_unlock();
changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
- bssid, ap_ht_cap_flags);
+ bssid, ap_ht_cap_flags, true);
}
/* Note: country IE parsing is done for us by cfg80211 */
@@ -2429,6 +2458,29 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
return 0;
}
+/* create and insert a dummy station entry */
+static int ieee80211_pre_assoc(struct ieee80211_sub_if_data *sdata,
+ u8 *bssid) {
+ struct sta_info *sta;
+ int err;
+
+ sta = sta_info_alloc(sdata, bssid, GFP_KERNEL);
+ if (!sta)
+ return -ENOMEM;
+
+ sta->dummy = true;
+
+ err = sta_info_insert(sta);
+ sta = NULL;
+ if (err) {
+ printk(KERN_DEBUG "%s: failed to insert Dummy STA entry for"
+ " the AP (error %d)\n", sdata->name, err);
+ return err;
+ }
+
+ return 0;
+}
+
static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
struct sk_buff *skb)
{
@@ -2436,9 +2488,11 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
struct ieee80211_mgmt *mgmt;
struct ieee80211_rx_status *rx_status;
struct ieee802_11_elems elems;
+ struct cfg80211_bss *cbss = wk->assoc.bss;
u16 status;
if (!skb) {
+ sta_info_destroy_addr(wk->sdata, cbss->bssid);
cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta);
goto destroy;
}
@@ -2468,12 +2522,16 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
if (!ieee80211_assoc_success(wk, mgmt, skb->len)) {
mutex_unlock(&wk->sdata->u.mgd.mtx);
/* oops -- internal error -- send timeout for now */
+ sta_info_destroy_addr(wk->sdata, cbss->bssid);
cfg80211_send_assoc_timeout(wk->sdata->dev,
wk->filter_ta);
return WORK_DONE_DESTROY;
}
mutex_unlock(&wk->sdata->u.mgd.mtx);
+ } else {
+ /* assoc failed - destroy the dummy station entry */
+ sta_info_destroy_addr(wk->sdata, cbss->bssid);
}
cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len);
@@ -2492,7 +2550,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
struct ieee80211_bss *bss = (void *)req->bss->priv;
struct ieee80211_work *wk;
const u8 *ssid;
- int i;
+ int i, err;
mutex_lock(&ifmgd->mtx);
if (ifmgd->associated) {
@@ -2517,6 +2575,16 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
if (!wk)
return -ENOMEM;
+ /*
+ * create a dummy station info entry in order
+ * to start accepting incoming EAPOL packets from the station
+ */
+ err = ieee80211_pre_assoc(sdata, req->bss->bssid);
+ if (err) {
+ kfree(wk);
+ return err;
+ }
+
ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N;
ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
@@ -2674,7 +2742,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
req->reason_code, cookie,
!req->local_state_change);
if (assoc_bss)
- sta_info_destroy_addr(sdata, bssid);
+ sta_info_flush(sdata->local, sdata);
mutex_lock(&sdata->local->mtx);
ieee80211_recalc_idle(sdata->local);
@@ -2714,7 +2782,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
ieee80211_send_deauth_disassoc(sdata, req->bss->bssid,
IEEE80211_STYPE_DISASSOC, req->reason_code,
cookie, !req->local_state_change);
- sta_info_destroy_addr(sdata, bssid);
+ sta_info_flush(sdata->local, sdata);
mutex_lock(&sdata->local->mtx);
ieee80211_recalc_idle(sdata->local);
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index 6326d3439861..9ee7164b207c 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -42,7 +42,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
mutex_lock(&local->sta_mtx);
list_for_each_entry(sta, &local->sta_list, list) {
- set_sta_flags(sta, WLAN_STA_BLOCK_BA);
+ set_sta_flag(sta, WLAN_STA_BLOCK_BA);
ieee80211_sta_tear_down_BA_sessions(sta, true);
}
mutex_unlock(&local->sta_mtx);
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index 3d5a2cb835c4..ff5c3aa48a15 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -199,7 +199,7 @@ static void rate_control_release(struct kref *kref)
kfree(ctrl_ref);
}
-static bool rc_no_data_or_no_ack(struct ieee80211_tx_rate_control *txrc)
+static bool rc_no_data_or_no_ack_use_min(struct ieee80211_tx_rate_control *txrc)
{
struct sk_buff *skb = txrc->skb;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -208,7 +208,9 @@ static bool rc_no_data_or_no_ack(struct ieee80211_tx_rate_control *txrc)
fc = hdr->frame_control;
- return (info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc);
+ return (info->flags & (IEEE80211_TX_CTL_NO_ACK |
+ IEEE80211_TX_CTL_USE_MINRATE)) ||
+ !ieee80211_is_data(fc);
}
static void rc_send_low_broadcast(s8 *idx, u32 basic_rates,
@@ -233,6 +235,27 @@ static void rc_send_low_broadcast(s8 *idx, u32 basic_rates,
/* could not find a basic rate; use original selection */
}
+static inline s8
+rate_lowest_non_cck_index(struct ieee80211_supported_band *sband,
+ struct ieee80211_sta *sta)
+{
+ int i;
+
+ for (i = 0; i < sband->n_bitrates; i++) {
+ struct ieee80211_rate *srate = &sband->bitrates[i];
+ if ((srate->bitrate == 10) || (srate->bitrate == 20) ||
+ (srate->bitrate == 55) || (srate->bitrate == 110))
+ continue;
+
+ if (rate_supported(sta, sband->band, i))
+ return i;
+ }
+
+ /* No matching rate found */
+ return 0;
+}
+
+
bool rate_control_send_low(struct ieee80211_sta *sta,
void *priv_sta,
struct ieee80211_tx_rate_control *txrc)
@@ -241,8 +264,14 @@ bool rate_control_send_low(struct ieee80211_sta *sta,
struct ieee80211_supported_band *sband = txrc->sband;
int mcast_rate;
- if (!sta || !priv_sta || rc_no_data_or_no_ack(txrc)) {
- info->control.rates[0].idx = rate_lowest_index(txrc->sband, sta);
+ if (!sta || !priv_sta || rc_no_data_or_no_ack_use_min(txrc)) {
+ if ((sband->band != IEEE80211_BAND_2GHZ) ||
+ !(info->flags & IEEE80211_TX_CTL_NO_CCK_RATE))
+ info->control.rates[0].idx =
+ rate_lowest_index(txrc->sband, sta);
+ else
+ info->control.rates[0].idx =
+ rate_lowest_non_cck_index(txrc->sband, sta);
info->control.rates[0].count =
(info->flags & IEEE80211_TX_CTL_NO_ACK) ?
1 : txrc->hw->max_rate_tries;
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index 66a1eeb279c6..cdb28535716b 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -281,6 +281,8 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
mr = minstrel_get_ratestats(mi, mg->max_tp_rate);
if (cur_tp < mr->cur_tp) {
+ mi->max_tp_rate2 = mi->max_tp_rate;
+ cur_tp2 = cur_tp;
mi->max_tp_rate = mg->max_tp_rate;
cur_tp = mr->cur_tp;
}
@@ -452,7 +454,8 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) {
minstrel_ht_update_stats(mp, mi);
- minstrel_aggr_check(mp, sta, skb);
+ if (!(info->flags & IEEE80211_TX_CTL_AMPDU))
+ minstrel_aggr_check(mp, sta, skb);
}
}
@@ -608,7 +611,13 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc);
info->flags |= mi->tx_flags;
- sample_idx = minstrel_get_sample_rate(mp, mi);
+
+ /* Don't use EAPOL frames for sampling on non-mrr hw */
+ if (mp->hw->max_rates == 1 &&
+ txrc->skb->protocol == cpu_to_be16(ETH_P_PAE))
+ sample_idx = -1;
+ else
+ sample_idx = minstrel_get_sample_rate(mp, mi);
#ifdef CONFIG_MAC80211_DEBUGFS
/* use fixed index if set */
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index fe2c2a717793..b867bd55de7a 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -476,7 +476,6 @@ static ieee80211_rx_result
ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
- unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control);
char *dev_addr = rx->sdata->vif.addr;
if (ieee80211_is_data(hdr->frame_control)) {
@@ -524,14 +523,6 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
}
-#define msh_h_get(h, l) ((struct ieee80211s_hdr *) ((u8 *)h + l))
-
- if (ieee80211_is_data(hdr->frame_control) &&
- is_multicast_ether_addr(hdr->addr1) &&
- mesh_rmc_check(hdr->addr3, msh_h_get(hdr, hdrlen), rx->sdata))
- return RX_DROP_MONITOR;
-#undef msh_h_get
-
return RX_CONTINUE;
}
@@ -850,8 +841,21 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
ieee80211_is_pspoll(hdr->frame_control)) &&
rx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
rx->sdata->vif.type != NL80211_IFTYPE_WDS &&
- (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC))))
+ (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) {
+ if (rx->sta && rx->sta->dummy &&
+ ieee80211_is_data_present(hdr->frame_control)) {
+ u16 ethertype;
+ u8 *payload;
+
+ payload = rx->skb->data +
+ ieee80211_hdrlen(hdr->frame_control);
+ ethertype = (payload[6] << 8) | payload[7];
+ if (cpu_to_be16(ethertype) ==
+ rx->sdata->control_port_protocol)
+ return RX_CONTINUE;
+ }
return RX_DROP_MONITOR;
+ }
return RX_CONTINUE;
}
@@ -1106,7 +1110,7 @@ static void ap_sta_ps_start(struct sta_info *sta)
struct ieee80211_local *local = sdata->local;
atomic_inc(&sdata->bss->num_sta_ps);
- set_sta_flags(sta, WLAN_STA_PS_STA);
+ set_sta_flag(sta, WLAN_STA_PS_STA);
if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta);
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
@@ -1126,7 +1130,7 @@ static void ap_sta_ps_end(struct sta_info *sta)
sdata->name, sta->sta.addr, sta->sta.aid);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
- if (test_sta_flags(sta, WLAN_STA_PS_DRIVER)) {
+ if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n",
sdata->name, sta->sta.addr, sta->sta.aid);
@@ -1145,7 +1149,7 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start)
WARN_ON(!(sta_inf->local->hw.flags & IEEE80211_HW_AP_LINK_PS));
/* Don't let the same PS state be set twice */
- in_ps = test_sta_flags(sta_inf, WLAN_STA_PS_STA);
+ in_ps = test_sta_flag(sta_inf, WLAN_STA_PS_STA);
if ((start && in_ps) || (!start && !in_ps))
return -EINVAL;
@@ -1159,6 +1163,81 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start)
EXPORT_SYMBOL(ieee80211_sta_ps_transition);
static ieee80211_rx_result debug_noinline
+ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx)
+{
+ struct ieee80211_sub_if_data *sdata = rx->sdata;
+ struct ieee80211_hdr *hdr = (void *)rx->skb->data;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+ int tid, ac;
+
+ if (!rx->sta || !(status->rx_flags & IEEE80211_RX_RA_MATCH))
+ return RX_CONTINUE;
+
+ if (sdata->vif.type != NL80211_IFTYPE_AP &&
+ sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
+ return RX_CONTINUE;
+
+ /*
+ * The device handles station powersave, so don't do anything about
+ * uAPSD and PS-Poll frames (the latter shouldn't even come up from
+ * it to mac80211 since they're handled.)
+ */
+ if (sdata->local->hw.flags & IEEE80211_HW_AP_LINK_PS)
+ return RX_CONTINUE;
+
+ /*
+ * Don't do anything if the station isn't already asleep. In
+ * the uAPSD case, the station will probably be marked asleep,
+ * in the PS-Poll case the station must be confused ...
+ */
+ if (!test_sta_flag(rx->sta, WLAN_STA_PS_STA))
+ return RX_CONTINUE;
+
+ if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) {
+ if (!test_sta_flag(rx->sta, WLAN_STA_SP)) {
+ if (!test_sta_flag(rx->sta, WLAN_STA_PS_DRIVER))
+ ieee80211_sta_ps_deliver_poll_response(rx->sta);
+ else
+ set_sta_flag(rx->sta, WLAN_STA_PSPOLL);
+ }
+
+ /* Free PS Poll skb here instead of returning RX_DROP that would
+ * count as an dropped frame. */
+ dev_kfree_skb(rx->skb);
+
+ return RX_QUEUED;
+ } else if (!ieee80211_has_morefrags(hdr->frame_control) &&
+ !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) &&
+ ieee80211_has_pm(hdr->frame_control) &&
+ (ieee80211_is_data_qos(hdr->frame_control) ||
+ ieee80211_is_qos_nullfunc(hdr->frame_control))) {
+ tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
+ ac = ieee802_1d_to_ac[tid & 7];
+
+ /*
+ * If this AC is not trigger-enabled do nothing.
+ *
+ * NB: This could/should check a separate bitmap of trigger-
+ * enabled queues, but for now we only implement uAPSD w/o
+ * TSPEC changes to the ACs, so they're always the same.
+ */
+ if (!(rx->sta->sta.uapsd_queues & BIT(ac)))
+ return RX_CONTINUE;
+
+ /* if we are in a service period, do nothing */
+ if (test_sta_flag(rx->sta, WLAN_STA_SP))
+ return RX_CONTINUE;
+
+ if (!test_sta_flag(rx->sta, WLAN_STA_PS_DRIVER))
+ ieee80211_sta_ps_deliver_uapsd(rx->sta);
+ else
+ set_sta_flag(rx->sta, WLAN_STA_UAPSD);
+ }
+
+ return RX_CONTINUE;
+}
+
+static ieee80211_rx_result debug_noinline
ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
{
struct sta_info *sta = rx->sta;
@@ -1216,7 +1295,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
!(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) &&
(rx->sdata->vif.type == NL80211_IFTYPE_AP ||
rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) {
- if (test_sta_flags(sta, WLAN_STA_PS_STA)) {
+ if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
/*
* Ignore doze->wake transitions that are
* indicated by non-data frames, the standard
@@ -1469,33 +1548,6 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
}
static ieee80211_rx_result debug_noinline
-ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
-{
- struct ieee80211_sub_if_data *sdata = rx->sdata;
- __le16 fc = ((struct ieee80211_hdr *)rx->skb->data)->frame_control;
- struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
-
- if (likely(!rx->sta || !ieee80211_is_pspoll(fc) ||
- !(status->rx_flags & IEEE80211_RX_RA_MATCH)))
- return RX_CONTINUE;
-
- if ((sdata->vif.type != NL80211_IFTYPE_AP) &&
- (sdata->vif.type != NL80211_IFTYPE_AP_VLAN))
- return RX_DROP_UNUSABLE;
-
- if (!test_sta_flags(rx->sta, WLAN_STA_PS_DRIVER))
- ieee80211_sta_ps_deliver_poll_response(rx->sta);
- else
- set_sta_flags(rx->sta, WLAN_STA_PSPOLL);
-
- /* Free PS Poll skb here instead of returning RX_DROP that would
- * count as an dropped frame. */
- dev_kfree_skb(rx->skb);
-
- return RX_QUEUED;
-}
-
-static ieee80211_rx_result debug_noinline
ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx)
{
u8 *data = rx->skb->data;
@@ -1518,7 +1570,7 @@ static int
ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
{
if (unlikely(!rx->sta ||
- !test_sta_flags(rx->sta, WLAN_STA_AUTHORIZED)))
+ !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED)))
return -EACCES;
return 0;
@@ -1561,7 +1613,7 @@ ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
if (status->flag & RX_FLAG_DECRYPTED)
return 0;
- if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) {
+ if (rx->sta && test_sta_flag(rx->sta, WLAN_STA_MFP)) {
if (unlikely(!ieee80211_has_protected(fc) &&
ieee80211_is_unicast_robust_mgmt_frame(rx->skb) &&
rx->key)) {
@@ -1827,6 +1879,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
hdrlen = ieee80211_hdrlen(hdr->frame_control);
mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
+ /* frame is in RMC, don't forward */
+ if (ieee80211_is_data(hdr->frame_control) &&
+ is_multicast_ether_addr(hdr->addr1) &&
+ mesh_rmc_check(hdr->addr3, mesh_hdr, rx->sdata))
+ return RX_DROP_MONITOR;
+
if (!ieee80211_is_data(hdr->frame_control))
return RX_CONTINUE;
@@ -1834,6 +1892,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
/* illegal frame */
return RX_DROP_MONITOR;
+ if (ieee80211_queue_stopped(&local->hw, skb_get_queue_mapping(skb))) {
+ IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
+ dropped_frames_congestion);
+ return RX_DROP_MONITOR;
+ }
+
if (mesh_hdr->flags & MESH_FLAGS_AE) {
struct mesh_path *mppath;
char *proxied_addr;
@@ -1889,13 +1953,13 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
memset(info, 0, sizeof(*info));
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
info->control.vif = &rx->sdata->vif;
- skb_set_queue_mapping(skb,
- ieee80211_select_queue(rx->sdata, fwd_skb));
- ieee80211_set_qos_hdr(local, skb);
- if (is_multicast_ether_addr(fwd_hdr->addr1))
+ if (is_multicast_ether_addr(fwd_hdr->addr1)) {
IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
fwded_mcast);
- else {
+ skb_set_queue_mapping(fwd_skb,
+ ieee80211_select_queue(sdata, fwd_skb));
+ ieee80211_set_qos_hdr(sdata, fwd_skb);
+ } else {
int err;
/*
* Save TA to addr1 to send TA a path error if a
@@ -2220,12 +2284,29 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
goto handled;
}
break;
+ case WLAN_CATEGORY_SELF_PROTECTED:
+ switch (mgmt->u.action.u.self_prot.action_code) {
+ case WLAN_SP_MESH_PEERING_OPEN:
+ case WLAN_SP_MESH_PEERING_CLOSE:
+ case WLAN_SP_MESH_PEERING_CONFIRM:
+ if (!ieee80211_vif_is_mesh(&sdata->vif))
+ goto invalid;
+ if (sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)
+ /* userspace handles this frame */
+ break;
+ goto queue;
+ case WLAN_SP_MGK_INFORM:
+ case WLAN_SP_MGK_ACK:
+ if (!ieee80211_vif_is_mesh(&sdata->vif))
+ goto invalid;
+ break;
+ }
+ break;
case WLAN_CATEGORY_MESH_ACTION:
if (!ieee80211_vif_is_mesh(&sdata->vif))
break;
- goto queue;
- case WLAN_CATEGORY_MESH_PATH_SEL:
- if (!mesh_path_sel_is_hwmp(sdata))
+ if (mesh_action_is_path_sel(mgmt) &&
+ (!mesh_path_sel_is_hwmp(sdata)))
break;
goto queue;
}
@@ -2534,17 +2615,17 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx)
CALL_RXH(ieee80211_rx_h_decrypt)
CALL_RXH(ieee80211_rx_h_check_more_data)
+ CALL_RXH(ieee80211_rx_h_uapsd_and_pspoll)
CALL_RXH(ieee80211_rx_h_sta_process)
CALL_RXH(ieee80211_rx_h_defragment)
- CALL_RXH(ieee80211_rx_h_ps_poll)
CALL_RXH(ieee80211_rx_h_michael_mic_verify)
/* must be after MMIC verify so header is counted in MPDU mic */
- CALL_RXH(ieee80211_rx_h_remove_qos_control)
- CALL_RXH(ieee80211_rx_h_amsdu)
#ifdef CONFIG_MAC80211_MESH
if (ieee80211_vif_is_mesh(&rx->sdata->vif))
CALL_RXH(ieee80211_rx_h_mesh_fwding);
#endif
+ CALL_RXH(ieee80211_rx_h_remove_qos_control)
+ CALL_RXH(ieee80211_rx_h_amsdu)
CALL_RXH(ieee80211_rx_h_data)
CALL_RXH(ieee80211_rx_h_ctrl);
CALL_RXH(ieee80211_rx_h_mgmt_check)
@@ -2686,7 +2767,9 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
} else if (!ieee80211_bssid_match(bssid,
sdata->vif.addr)) {
if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) &&
- !ieee80211_is_beacon(hdr->frame_control))
+ !ieee80211_is_beacon(hdr->frame_control) &&
+ !(ieee80211_is_action(hdr->frame_control) &&
+ sdata->vif.p2p))
return 0;
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
}
@@ -2791,7 +2874,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
if (ieee80211_is_data(fc)) {
prev_sta = NULL;
- for_each_sta_info(local, hdr->addr2, sta, tmp) {
+ for_each_sta_info_rx(local, hdr->addr2, sta, tmp) {
if (!prev_sta) {
prev_sta = sta;
continue;
@@ -2835,7 +2918,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
continue;
}
- rx.sta = sta_info_get_bss(prev, hdr->addr2);
+ rx.sta = sta_info_get_bss_rx(prev, hdr->addr2);
rx.sdata = prev;
ieee80211_prepare_and_rx_handle(&rx, skb, false);
@@ -2843,7 +2926,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
}
if (prev) {
- rx.sta = sta_info_get_bss(prev, hdr->addr2);
+ rx.sta = sta_info_get_bss_rx(prev, hdr->addr2);
rx.sdata = prev;
if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 6f09eca01112..83a0b050b374 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -14,7 +14,7 @@
#include <linux/if_arp.h>
#include <linux/rtnetlink.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
#include <net/sch_generic.h>
#include <linux/slab.h>
#include <net/mac80211.h>
@@ -254,6 +254,7 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
req->ie, req->ie_len, band,
req->rates[band], 0);
local->hw_scan_req->ie_len = ielen;
+ local->hw_scan_req->no_cck = req->no_cck;
return true;
}
@@ -660,7 +661,8 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
local->scan_req->ssids[i].ssid,
local->scan_req->ssids[i].ssid_len,
local->scan_req->ie, local->scan_req->ie_len,
- local->scan_req->rates[band], false);
+ local->scan_req->rates[band], false,
+ local->scan_req->no_cck);
/*
* After sending probe requests, wait for probe responses
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index 7733f66ee2c4..578eea3fc04d 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -32,12 +32,8 @@ static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_da
skb = dev_alloc_skb(sizeof(*msr_report) + local->hw.extra_tx_headroom +
sizeof(struct ieee80211_msrment_ie));
-
- if (!skb) {
- printk(KERN_ERR "%s: failed to allocate buffer for "
- "measurement report frame\n", sdata->name);
+ if (!skb)
return;
- }
skb_reserve(skb, local->hw.extra_tx_headroom);
msr_report = (struct ieee80211_mgmt *)skb_put(skb, 24);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 3db78b696c5c..ce962d2c8782 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -24,6 +24,7 @@
#include "sta_info.h"
#include "debugfs_sta.h"
#include "mesh.h"
+#include "wme.h"
/**
* DOC: STA information lifetime rules
@@ -72,7 +73,7 @@ static int sta_info_hash_del(struct ieee80211_local *local,
if (!s)
return -ENOENT;
if (s == sta) {
- rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)],
+ RCU_INIT_POINTER(local->sta_hash[STA_HASH(sta->sta.addr)],
s->hnext);
return 0;
}
@@ -82,7 +83,7 @@ static int sta_info_hash_del(struct ieee80211_local *local,
s = rcu_dereference_protected(s->hnext,
lockdep_is_held(&local->sta_lock));
if (rcu_access_pointer(s->hnext)) {
- rcu_assign_pointer(s->hnext, sta->hnext);
+ RCU_INIT_POINTER(s->hnext, sta->hnext);
return 0;
}
@@ -100,6 +101,27 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
lockdep_is_held(&local->sta_lock) ||
lockdep_is_held(&local->sta_mtx));
while (sta) {
+ if (sta->sdata == sdata && !sta->dummy &&
+ memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
+ break;
+ sta = rcu_dereference_check(sta->hnext,
+ lockdep_is_held(&local->sta_lock) ||
+ lockdep_is_held(&local->sta_mtx));
+ }
+ return sta;
+}
+
+/* get a station info entry even if it is a dummy station*/
+struct sta_info *sta_info_get_rx(struct ieee80211_sub_if_data *sdata,
+ const u8 *addr)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct sta_info *sta;
+
+ sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)],
+ lockdep_is_held(&local->sta_lock) ||
+ lockdep_is_held(&local->sta_mtx));
+ while (sta) {
if (sta->sdata == sdata &&
memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
break;
@@ -126,6 +148,32 @@ 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)) &&
+ !sta->dummy &&
+ memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
+ break;
+ sta = rcu_dereference_check(sta->hnext,
+ lockdep_is_held(&local->sta_lock) ||
+ lockdep_is_held(&local->sta_mtx));
+ }
+ return sta;
+}
+
+/*
+ * Get sta info either from the specified interface
+ * or from one of its vlans (including dummy stations)
+ */
+struct sta_info *sta_info_get_bss_rx(struct ieee80211_sub_if_data *sdata,
+ const u8 *addr)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct sta_info *sta;
+
+ sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)],
+ lockdep_is_held(&local->sta_lock) ||
+ lockdep_is_held(&local->sta_mtx));
+ while (sta) {
+ if ((sta->sdata == sdata ||
+ (sta->sdata->bss && sta->sdata->bss == sdata->bss)) &&
memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
break;
sta = rcu_dereference_check(sta->hnext,
@@ -184,7 +232,7 @@ static void sta_info_hash_add(struct ieee80211_local *local,
struct sta_info *sta)
{
sta->hnext = local->sta_hash[STA_HASH(sta->sta.addr)];
- rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta);
+ RCU_INIT_POINTER(local->sta_hash[STA_HASH(sta->sta.addr)], sta);
}
static void sta_unblock(struct work_struct *wk)
@@ -196,13 +244,22 @@ static void sta_unblock(struct work_struct *wk)
if (sta->dead)
return;
- if (!test_sta_flags(sta, WLAN_STA_PS_STA))
+ if (!test_sta_flag(sta, WLAN_STA_PS_STA))
ieee80211_sta_ps_deliver_wakeup(sta);
- else if (test_and_clear_sta_flags(sta, WLAN_STA_PSPOLL)) {
- clear_sta_flags(sta, WLAN_STA_PS_DRIVER);
+ else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL)) {
+ clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
+
+ local_bh_disable();
ieee80211_sta_ps_deliver_poll_response(sta);
+ local_bh_enable();
+ } else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD)) {
+ clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
+
+ local_bh_disable();
+ ieee80211_sta_ps_deliver_uapsd(sta);
+ local_bh_enable();
} else
- clear_sta_flags(sta, WLAN_STA_PS_DRIVER);
+ clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
}
static int sta_prepare_rate_control(struct ieee80211_local *local,
@@ -235,7 +292,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
return NULL;
spin_lock_init(&sta->lock);
- spin_lock_init(&sta->flaglock);
INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
mutex_init(&sta->ampdu_mlme.mtx);
@@ -262,8 +318,10 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
*/
sta->timer_to_tid[i] = i;
}
- skb_queue_head_init(&sta->ps_tx_buf);
- skb_queue_head_init(&sta->tx_filtered);
+ for (i = 0; i < IEEE80211_NUM_ACS; i++) {
+ skb_queue_head_init(&sta->ps_tx_buf[i]);
+ skb_queue_head_init(&sta->tx_filtered[i]);
+ }
for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX);
@@ -280,7 +338,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
return sta;
}
-static int sta_info_finish_insert(struct sta_info *sta, bool async)
+static int sta_info_finish_insert(struct sta_info *sta,
+ bool async, bool dummy_reinsert)
{
struct ieee80211_local *local = sta->local;
struct ieee80211_sub_if_data *sdata = sta->sdata;
@@ -290,50 +349,58 @@ static int sta_info_finish_insert(struct sta_info *sta, bool async)
lockdep_assert_held(&local->sta_mtx);
- /* notify driver */
- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
- sdata = container_of(sdata->bss,
- struct ieee80211_sub_if_data,
- u.ap);
- err = drv_sta_add(local, sdata, &sta->sta);
- if (err) {
- if (!async)
- return err;
- printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to driver (%d)"
- " - keeping it anyway.\n",
- sdata->name, sta->sta.addr, err);
- } else {
- sta->uploaded = true;
+ if (!sta->dummy || dummy_reinsert) {
+ /* notify driver */
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ sdata = container_of(sdata->bss,
+ struct ieee80211_sub_if_data,
+ u.ap);
+ err = drv_sta_add(local, sdata, &sta->sta);
+ if (err) {
+ if (!async)
+ return err;
+ printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to "
+ "driver (%d) - keeping it anyway.\n",
+ sdata->name, sta->sta.addr, err);
+ } else {
+ sta->uploaded = true;
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- if (async)
- wiphy_debug(local->hw.wiphy,
- "Finished adding IBSS STA %pM\n",
- sta->sta.addr);
+ if (async)
+ wiphy_debug(local->hw.wiphy,
+ "Finished adding IBSS STA %pM\n",
+ sta->sta.addr);
#endif
+ }
+
+ sdata = sta->sdata;
}
- sdata = sta->sdata;
+ if (!dummy_reinsert) {
+ if (!async) {
+ local->num_sta++;
+ local->sta_generation++;
+ smp_mb();
- if (!async) {
- local->num_sta++;
- local->sta_generation++;
- smp_mb();
+ /* make the station visible */
+ spin_lock_irqsave(&local->sta_lock, flags);
+ sta_info_hash_add(local, sta);
+ spin_unlock_irqrestore(&local->sta_lock, flags);
+ }
- /* make the station visible */
- spin_lock_irqsave(&local->sta_lock, flags);
- sta_info_hash_add(local, sta);
- spin_unlock_irqrestore(&local->sta_lock, flags);
+ list_add(&sta->list, &local->sta_list);
+ } else {
+ sta->dummy = false;
}
- list_add(&sta->list, &local->sta_list);
-
- ieee80211_sta_debugfs_add(sta);
- rate_control_add_sta_debugfs(sta);
-
- sinfo.filled = 0;
- sinfo.generation = local->sta_generation;
- cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
+ if (!sta->dummy) {
+ ieee80211_sta_debugfs_add(sta);
+ rate_control_add_sta_debugfs(sta);
+ memset(&sinfo, 0, sizeof(sinfo));
+ sinfo.filled = 0;
+ sinfo.generation = local->sta_generation;
+ cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
+ }
return 0;
}
@@ -350,7 +417,7 @@ static void sta_info_finish_pending(struct ieee80211_local *local)
list_del(&sta->list);
spin_unlock_irqrestore(&local->sta_lock, flags);
- sta_info_finish_insert(sta, true);
+ sta_info_finish_insert(sta, true, false);
spin_lock_irqsave(&local->sta_lock, flags);
}
@@ -367,106 +434,117 @@ static void sta_info_finish_work(struct work_struct *work)
mutex_unlock(&local->sta_mtx);
}
-int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
+static int sta_info_insert_check(struct sta_info *sta)
{
- struct ieee80211_local *local = sta->local;
struct ieee80211_sub_if_data *sdata = sta->sdata;
- unsigned long flags;
- int err = 0;
/*
* Can't be a WARN_ON because it can be triggered through a race:
* something inserts a STA (on one CPU) without holding the RTNL
* and another CPU turns off the net device.
*/
- if (unlikely(!ieee80211_sdata_running(sdata))) {
- err = -ENETDOWN;
- rcu_read_lock();
- goto out_free;
- }
+ if (unlikely(!ieee80211_sdata_running(sdata)))
+ return -ENETDOWN;
if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->vif.addr) == 0 ||
- is_multicast_ether_addr(sta->sta.addr))) {
- err = -EINVAL;
+ is_multicast_ether_addr(sta->sta.addr)))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int sta_info_insert_ibss(struct sta_info *sta) __acquires(RCU)
+{
+ struct ieee80211_local *local = sta->local;
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ unsigned long flags;
+
+ spin_lock_irqsave(&local->sta_lock, flags);
+ /* check if STA exists already */
+ if (sta_info_get_bss_rx(sdata, sta->sta.addr)) {
+ spin_unlock_irqrestore(&local->sta_lock, flags);
rcu_read_lock();
- goto out_free;
+ return -EEXIST;
}
- /*
- * In ad-hoc mode, we sometimes need to insert stations
- * from tasklet context from the RX path. To avoid races,
- * always do so in that case -- see the comment below.
- */
- if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
- spin_lock_irqsave(&local->sta_lock, flags);
- /* check if STA exists already */
- if (sta_info_get_bss(sdata, sta->sta.addr)) {
- spin_unlock_irqrestore(&local->sta_lock, flags);
- rcu_read_lock();
- err = -EEXIST;
- goto out_free;
- }
-
- local->num_sta++;
- local->sta_generation++;
- smp_mb();
- sta_info_hash_add(local, sta);
+ local->num_sta++;
+ local->sta_generation++;
+ smp_mb();
+ sta_info_hash_add(local, sta);
- list_add_tail(&sta->list, &local->sta_pending_list);
+ list_add_tail(&sta->list, &local->sta_pending_list);
- rcu_read_lock();
- spin_unlock_irqrestore(&local->sta_lock, flags);
+ rcu_read_lock();
+ spin_unlock_irqrestore(&local->sta_lock, flags);
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- wiphy_debug(local->hw.wiphy, "Added IBSS STA %pM\n",
- sta->sta.addr);
+ wiphy_debug(local->hw.wiphy, "Added IBSS STA %pM\n",
+ sta->sta.addr);
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
- ieee80211_queue_work(&local->hw, &local->sta_finish_work);
+ ieee80211_queue_work(&local->hw, &local->sta_finish_work);
- return 0;
- }
+ return 0;
+}
+
+/*
+ * should be called with sta_mtx locked
+ * this function replaces the mutex lock
+ * with a RCU lock
+ */
+static int sta_info_insert_non_ibss(struct sta_info *sta) __acquires(RCU)
+{
+ struct ieee80211_local *local = sta->local;
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ unsigned long flags;
+ struct sta_info *exist_sta;
+ bool dummy_reinsert = false;
+ int err = 0;
+
+ lockdep_assert_held(&local->sta_mtx);
/*
* On first glance, this will look racy, because the code
- * below this point, which inserts a station with sleeping,
+ * in this function, which inserts a station with sleeping,
* unlocks the sta_lock between checking existence in the
* hash table and inserting into it.
*
* However, it is not racy against itself because it keeps
- * the mutex locked. It still seems to race against the
- * above code that atomically inserts the station... That,
- * however, is not true because the above code can only
- * be invoked for IBSS interfaces, and the below code will
- * not be -- and the two do not race against each other as
- * the hash table also keys off the interface.
+ * the mutex locked.
*/
- might_sleep();
-
- mutex_lock(&local->sta_mtx);
-
spin_lock_irqsave(&local->sta_lock, flags);
- /* check if STA exists already */
- if (sta_info_get_bss(sdata, sta->sta.addr)) {
- spin_unlock_irqrestore(&local->sta_lock, flags);
- mutex_unlock(&local->sta_mtx);
- rcu_read_lock();
- err = -EEXIST;
- goto out_free;
+ /*
+ * check if STA exists already.
+ * only accept a scenario of a second call to sta_info_insert_non_ibss
+ * with a dummy station entry that was inserted earlier
+ * in that case - assume that the dummy station flag should
+ * be removed.
+ */
+ exist_sta = sta_info_get_bss_rx(sdata, sta->sta.addr);
+ if (exist_sta) {
+ if (exist_sta == sta && sta->dummy) {
+ dummy_reinsert = true;
+ } else {
+ spin_unlock_irqrestore(&local->sta_lock, flags);
+ mutex_unlock(&local->sta_mtx);
+ rcu_read_lock();
+ return -EEXIST;
+ }
}
spin_unlock_irqrestore(&local->sta_lock, flags);
- err = sta_info_finish_insert(sta, false);
+ err = sta_info_finish_insert(sta, false, dummy_reinsert);
if (err) {
mutex_unlock(&local->sta_mtx);
rcu_read_lock();
- goto out_free;
+ return err;
}
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- wiphy_debug(local->hw.wiphy, "Inserted STA %pM\n", sta->sta.addr);
+ wiphy_debug(local->hw.wiphy, "Inserted %sSTA %pM\n",
+ sta->dummy ? "dummy " : "", sta->sta.addr);
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
/* move reference to rcu-protected */
@@ -477,6 +555,51 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
mesh_accept_plinks_update(sdata);
return 0;
+}
+
+int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
+{
+ struct ieee80211_local *local = sta->local;
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ int err = 0;
+
+ err = sta_info_insert_check(sta);
+ if (err) {
+ rcu_read_lock();
+ goto out_free;
+ }
+
+ /*
+ * In ad-hoc mode, we sometimes need to insert stations
+ * from tasklet context from the RX path. To avoid races,
+ * always do so in that case -- see the comment below.
+ */
+ if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+ err = sta_info_insert_ibss(sta);
+ if (err)
+ goto out_free;
+
+ return 0;
+ }
+
+ /*
+ * It might seem that the function called below is in race against
+ * the function call above that atomically inserts the station... That,
+ * however, is not true because the above code can only
+ * be invoked for IBSS interfaces, and the below code will
+ * not be -- and the two do not race against each other as
+ * the hash table also keys off the interface.
+ */
+
+ might_sleep();
+
+ mutex_lock(&local->sta_mtx);
+
+ err = sta_info_insert_non_ibss(sta);
+ if (err)
+ goto out_free;
+
+ return 0;
out_free:
BUG_ON(!err);
__sta_info_free(local, sta);
@@ -492,6 +615,25 @@ int sta_info_insert(struct sta_info *sta)
return err;
}
+/* Caller must hold sta->local->sta_mtx */
+int sta_info_reinsert(struct sta_info *sta)
+{
+ struct ieee80211_local *local = sta->local;
+ int err = 0;
+
+ err = sta_info_insert_check(sta);
+ if (err) {
+ mutex_unlock(&local->sta_mtx);
+ return err;
+ }
+
+ might_sleep();
+
+ err = sta_info_insert_non_ibss(sta);
+ rcu_read_unlock();
+ return err;
+}
+
static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid)
{
/*
@@ -510,64 +652,93 @@ static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid)
bss->tim[aid / 8] &= ~(1 << (aid % 8));
}
-static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss,
- struct sta_info *sta)
+static unsigned long ieee80211_tids_for_ac(int ac)
{
- BUG_ON(!bss);
-
- __bss_tim_set(bss, sta->sta.aid);
-
- if (sta->local->ops->set_tim) {
- sta->local->tim_in_locked_section = true;
- drv_set_tim(sta->local, &sta->sta, true);
- sta->local->tim_in_locked_section = false;
+ /* If we ever support TIDs > 7, this obviously needs to be adjusted */
+ switch (ac) {
+ case IEEE80211_AC_VO:
+ return BIT(6) | BIT(7);
+ case IEEE80211_AC_VI:
+ return BIT(4) | BIT(5);
+ case IEEE80211_AC_BE:
+ return BIT(0) | BIT(3);
+ case IEEE80211_AC_BK:
+ return BIT(1) | BIT(2);
+ default:
+ WARN_ON(1);
+ return 0;
}
}
-void sta_info_set_tim_bit(struct sta_info *sta)
+void sta_info_recalc_tim(struct sta_info *sta)
{
+ struct ieee80211_local *local = sta->local;
+ struct ieee80211_if_ap *bss = sta->sdata->bss;
unsigned long flags;
+ bool indicate_tim = false;
+ u8 ignore_for_tim = sta->sta.uapsd_queues;
+ int ac;
- BUG_ON(!sta->sdata->bss);
+ if (WARN_ON_ONCE(!sta->sdata->bss))
+ return;
- spin_lock_irqsave(&sta->local->sta_lock, flags);
- __sta_info_set_tim_bit(sta->sdata->bss, sta);
- spin_unlock_irqrestore(&sta->local->sta_lock, flags);
-}
+ /* No need to do anything if the driver does all */
+ if (local->hw.flags & IEEE80211_HW_AP_LINK_PS)
+ return;
-static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss,
- struct sta_info *sta)
-{
- BUG_ON(!bss);
+ if (sta->dead)
+ goto done;
+
+ /*
+ * If all ACs are delivery-enabled then we should build
+ * the TIM bit for all ACs anyway; if only some are then
+ * we ignore those and build the TIM bit using only the
+ * non-enabled ones.
+ */
+ if (ignore_for_tim == BIT(IEEE80211_NUM_ACS) - 1)
+ ignore_for_tim = 0;
+
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ unsigned long tids;
- __bss_tim_clear(bss, sta->sta.aid);
+ if (ignore_for_tim & BIT(ac))
+ continue;
+
+ indicate_tim |= !skb_queue_empty(&sta->tx_filtered[ac]) ||
+ !skb_queue_empty(&sta->ps_tx_buf[ac]);
+ if (indicate_tim)
+ break;
- if (sta->local->ops->set_tim) {
- sta->local->tim_in_locked_section = true;
- drv_set_tim(sta->local, &sta->sta, false);
- sta->local->tim_in_locked_section = false;
+ tids = ieee80211_tids_for_ac(ac);
+
+ indicate_tim |=
+ sta->driver_buffered_tids & tids;
}
-}
-void sta_info_clear_tim_bit(struct sta_info *sta)
-{
- unsigned long flags;
+ done:
+ spin_lock_irqsave(&local->sta_lock, flags);
- BUG_ON(!sta->sdata->bss);
+ if (indicate_tim)
+ __bss_tim_set(bss, sta->sta.aid);
+ else
+ __bss_tim_clear(bss, sta->sta.aid);
- spin_lock_irqsave(&sta->local->sta_lock, flags);
- __sta_info_clear_tim_bit(sta->sdata->bss, sta);
- spin_unlock_irqrestore(&sta->local->sta_lock, flags);
+ if (local->ops->set_tim) {
+ local->tim_in_locked_section = true;
+ drv_set_tim(local, &sta->sta, indicate_tim);
+ local->tim_in_locked_section = false;
+ }
+
+ spin_unlock_irqrestore(&local->sta_lock, flags);
}
-static int sta_info_buffer_expired(struct sta_info *sta,
- struct sk_buff *skb)
+static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb)
{
struct ieee80211_tx_info *info;
int timeout;
if (!skb)
- return 0;
+ return false;
info = IEEE80211_SKB_CB(skb);
@@ -581,24 +752,59 @@ static int sta_info_buffer_expired(struct sta_info *sta,
}
-static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
- struct sta_info *sta)
+static bool sta_info_cleanup_expire_buffered_ac(struct ieee80211_local *local,
+ struct sta_info *sta, int ac)
{
unsigned long flags;
struct sk_buff *skb;
- if (skb_queue_empty(&sta->ps_tx_buf))
- return false;
+ /*
+ * First check for frames that should expire on the filtered
+ * queue. Frames here were rejected by the driver and are on
+ * a separate queue to avoid reordering with normal PS-buffered
+ * frames. They also aren't accounted for right now in the
+ * total_ps_buffered counter.
+ */
+ for (;;) {
+ spin_lock_irqsave(&sta->tx_filtered[ac].lock, flags);
+ skb = skb_peek(&sta->tx_filtered[ac]);
+ if (sta_info_buffer_expired(sta, skb))
+ skb = __skb_dequeue(&sta->tx_filtered[ac]);
+ else
+ skb = NULL;
+ spin_unlock_irqrestore(&sta->tx_filtered[ac].lock, flags);
+ /*
+ * Frames are queued in order, so if this one
+ * hasn't expired yet we can stop testing. If
+ * we actually reached the end of the queue we
+ * also need to stop, of course.
+ */
+ if (!skb)
+ break;
+ dev_kfree_skb(skb);
+ }
+
+ /*
+ * Now also check the normal PS-buffered queue, this will
+ * only find something if the filtered queue was emptied
+ * since the filtered frames are all before the normal PS
+ * buffered frames.
+ */
for (;;) {
- spin_lock_irqsave(&sta->ps_tx_buf.lock, flags);
- skb = skb_peek(&sta->ps_tx_buf);
+ spin_lock_irqsave(&sta->ps_tx_buf[ac].lock, flags);
+ skb = skb_peek(&sta->ps_tx_buf[ac]);
if (sta_info_buffer_expired(sta, skb))
- skb = __skb_dequeue(&sta->ps_tx_buf);
+ skb = __skb_dequeue(&sta->ps_tx_buf[ac]);
else
skb = NULL;
- spin_unlock_irqrestore(&sta->ps_tx_buf.lock, flags);
+ spin_unlock_irqrestore(&sta->ps_tx_buf[ac].lock, flags);
+ /*
+ * frames are queued in order, so if this one
+ * hasn't expired yet (or we reached the end of
+ * the queue) we can stop testing
+ */
if (!skb)
break;
@@ -608,22 +814,47 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
sta->sta.addr);
#endif
dev_kfree_skb(skb);
-
- if (skb_queue_empty(&sta->ps_tx_buf) &&
- !test_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF))
- sta_info_clear_tim_bit(sta);
}
- return true;
+ /*
+ * Finally, recalculate the TIM bit for this station -- it might
+ * now be clear because the station was too slow to retrieve its
+ * frames.
+ */
+ sta_info_recalc_tim(sta);
+
+ /*
+ * Return whether there are any frames still buffered, this is
+ * used to check whether the cleanup timer still needs to run,
+ * if there are no frames we don't need to rearm the timer.
+ */
+ return !(skb_queue_empty(&sta->ps_tx_buf[ac]) &&
+ skb_queue_empty(&sta->tx_filtered[ac]));
+}
+
+static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
+ struct sta_info *sta)
+{
+ bool have_buffered = false;
+ int ac;
+
+ /* This is only necessary for stations on BSS interfaces */
+ if (!sta->sdata->bss)
+ return false;
+
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+ have_buffered |=
+ sta_info_cleanup_expire_buffered_ac(local, sta, ac);
+
+ return have_buffered;
}
static int __must_check __sta_info_destroy(struct sta_info *sta)
{
struct ieee80211_local *local;
struct ieee80211_sub_if_data *sdata;
- struct sk_buff *skb;
unsigned long flags;
- int ret, i;
+ int ret, i, ac;
might_sleep();
@@ -639,7 +870,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
* sessions -- block that to make sure the tear-down
* will be sufficient.
*/
- set_sta_flags(sta, WLAN_STA_BLOCK_BA);
+ set_sta_flag(sta, WLAN_STA_BLOCK_BA);
ieee80211_sta_tear_down_BA_sessions(sta, true);
spin_lock_irqsave(&local->sta_lock, flags);
@@ -660,19 +891,22 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
sta->dead = true;
- if (test_and_clear_sta_flags(sta,
- WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) {
+ if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
+ test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
BUG_ON(!sdata->bss);
+ clear_sta_flag(sta, WLAN_STA_PS_STA);
+ clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
+
atomic_dec(&sdata->bss->num_sta_ps);
- __sta_info_clear_tim_bit(sdata->bss, sta);
+ sta_info_recalc_tim(sta);
}
local->num_sta--;
local->sta_generation++;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
- rcu_assign_pointer(sdata->u.vlan.sta, NULL);
+ RCU_INIT_POINTER(sdata->u.vlan.sta, NULL);
if (sta->uploaded) {
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
@@ -691,6 +925,12 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
*/
synchronize_rcu();
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]);
+ __skb_queue_purge(&sta->ps_tx_buf[ac]);
+ __skb_queue_purge(&sta->tx_filtered[ac]);
+ }
+
#ifdef CONFIG_MAC80211_MESH
if (ieee80211_vif_is_mesh(&sdata->vif))
mesh_accept_plinks_update(sdata);
@@ -713,14 +953,6 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
}
#endif
- while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
- local->total_ps_buffered--;
- dev_kfree_skb_any(skb);
- }
-
- while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL)
- dev_kfree_skb_any(skb);
-
__sta_info_free(local, sta);
return 0;
@@ -732,7 +964,7 @@ int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, const u8 *addr)
int ret;
mutex_lock(&sdata->local->sta_mtx);
- sta = sta_info_get(sdata, addr);
+ sta = sta_info_get_rx(sdata, addr);
ret = __sta_info_destroy(sta);
mutex_unlock(&sdata->local->sta_mtx);
@@ -746,7 +978,7 @@ int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata,
int ret;
mutex_lock(&sdata->local->sta_mtx);
- sta = sta_info_get_bss(sdata, addr);
+ sta = sta_info_get_bss_rx(sdata, addr);
ret = __sta_info_destroy(sta);
mutex_unlock(&sdata->local->sta_mtx);
@@ -886,7 +1118,8 @@ static void clear_sta_ps_flags(void *_sta)
{
struct sta_info *sta = _sta;
- clear_sta_flags(sta, WLAN_STA_PS_DRIVER | WLAN_STA_PS_STA);
+ clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
+ clear_sta_flag(sta, WLAN_STA_PS_STA);
}
/* powersave support code */
@@ -894,88 +1127,341 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
- int sent, buffered;
+ struct sk_buff_head pending;
+ int filtered = 0, buffered = 0, ac;
+
+ clear_sta_flag(sta, WLAN_STA_SP);
+
+ BUILD_BUG_ON(BITS_TO_LONGS(STA_TID_NUM) > 1);
+ sta->driver_buffered_tids = 0;
- clear_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
- if (!skb_queue_empty(&sta->ps_tx_buf))
- sta_info_clear_tim_bit(sta);
+ skb_queue_head_init(&pending);
/* Send all buffered frames to the station */
- sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered);
- buffered = ieee80211_add_pending_skbs_fn(local, &sta->ps_tx_buf,
- clear_sta_ps_flags, sta);
- sent += buffered;
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ int count = skb_queue_len(&pending), tmp;
+
+ skb_queue_splice_tail_init(&sta->tx_filtered[ac], &pending);
+ tmp = skb_queue_len(&pending);
+ filtered += tmp - count;
+ count = tmp;
+
+ skb_queue_splice_tail_init(&sta->ps_tx_buf[ac], &pending);
+ tmp = skb_queue_len(&pending);
+ buffered += tmp - count;
+ }
+
+ ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta);
+
local->total_ps_buffered -= buffered;
+ sta_info_recalc_tim(sta);
+
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames "
"since STA not sleeping anymore\n", sdata->name,
- sta->sta.addr, sta->sta.aid, sent - buffered, buffered);
+ sta->sta.addr, sta->sta.aid, filtered, buffered);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
}
-void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta)
+static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta, int tid,
+ enum ieee80211_frame_release_type reason)
{
- struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
+ struct ieee80211_qos_hdr *nullfunc;
struct sk_buff *skb;
- int no_pending_pkts;
+ int size = sizeof(*nullfunc);
+ __le16 fc;
+ bool qos = test_sta_flag(sta, WLAN_STA_WME);
+ struct ieee80211_tx_info *info;
- skb = skb_dequeue(&sta->tx_filtered);
- if (!skb) {
- skb = skb_dequeue(&sta->ps_tx_buf);
- if (skb)
- local->total_ps_buffered--;
+ if (qos) {
+ fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
+ IEEE80211_STYPE_QOS_NULLFUNC |
+ IEEE80211_FCTL_FROMDS);
+ } else {
+ size -= 2;
+ fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
+ IEEE80211_STYPE_NULLFUNC |
+ IEEE80211_FCTL_FROMDS);
+ }
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + size);
+ if (!skb)
+ return;
+
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ nullfunc = (void *) skb_put(skb, size);
+ nullfunc->frame_control = fc;
+ nullfunc->duration_id = 0;
+ memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN);
+ memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
+ memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN);
+
+ skb->priority = tid;
+ skb_set_queue_mapping(skb, ieee802_1d_to_ac[tid]);
+ if (qos) {
+ nullfunc->qos_ctrl = cpu_to_le16(tid);
+
+ if (reason == IEEE80211_FRAME_RELEASE_UAPSD)
+ nullfunc->qos_ctrl |=
+ cpu_to_le16(IEEE80211_QOS_CTL_EOSP);
}
- no_pending_pkts = skb_queue_empty(&sta->tx_filtered) &&
- skb_queue_empty(&sta->ps_tx_buf);
- if (skb) {
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_hdr *hdr =
- (struct ieee80211_hdr *) skb->data;
+ info = IEEE80211_SKB_CB(skb);
+
+ /*
+ * Tell TX path to send this frame even though the
+ * STA may still remain is PS mode after this frame
+ * exchange. Also set EOSP to indicate this packet
+ * ends the poll/service period.
+ */
+ info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE |
+ IEEE80211_TX_STATUS_EOSP |
+ IEEE80211_TX_CTL_REQ_TX_STATUS;
+
+ drv_allow_buffered_frames(local, sta, BIT(tid), 1, reason, false);
+
+ ieee80211_xmit(sdata, skb);
+}
+
+static void
+ieee80211_sta_ps_deliver_response(struct sta_info *sta,
+ int n_frames, u8 ignored_acs,
+ enum ieee80211_frame_release_type reason)
+{
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ struct ieee80211_local *local = sdata->local;
+ bool found = false;
+ bool more_data = false;
+ int ac;
+ unsigned long driver_release_tids = 0;
+ struct sk_buff_head frames;
+
+ /* Service or PS-Poll period starts */
+ set_sta_flag(sta, WLAN_STA_SP);
+
+ __skb_queue_head_init(&frames);
+
+ /*
+ * Get response frame(s) and more data bit for it.
+ */
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ unsigned long tids;
+
+ if (ignored_acs & BIT(ac))
+ continue;
+
+ tids = ieee80211_tids_for_ac(ac);
+
+ if (!found) {
+ driver_release_tids = sta->driver_buffered_tids & tids;
+ if (driver_release_tids) {
+ found = true;
+ } else {
+ struct sk_buff *skb;
+
+ while (n_frames > 0) {
+ skb = skb_dequeue(&sta->tx_filtered[ac]);
+ if (!skb) {
+ skb = skb_dequeue(
+ &sta->ps_tx_buf[ac]);
+ if (skb)
+ local->total_ps_buffered--;
+ }
+ if (!skb)
+ break;
+ n_frames--;
+ found = true;
+ __skb_queue_tail(&frames, skb);
+ }
+ }
+
+ /*
+ * If the driver has data on more than one TID then
+ * certainly there's more data if we release just a
+ * single frame now (from a single TID).
+ */
+ if (reason == IEEE80211_FRAME_RELEASE_PSPOLL &&
+ hweight16(driver_release_tids) > 1) {
+ more_data = true;
+ driver_release_tids =
+ BIT(ffs(driver_release_tids) - 1);
+ break;
+ }
+ }
+
+ if (!skb_queue_empty(&sta->tx_filtered[ac]) ||
+ !skb_queue_empty(&sta->ps_tx_buf[ac])) {
+ more_data = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ int tid;
/*
- * Tell TX path to send this frame even though the STA may
- * still remain is PS mode after this frame exchange.
+ * For PS-Poll, this can only happen due to a race condition
+ * when we set the TIM bit and the station notices it, but
+ * before it can poll for the frame we expire it.
+ *
+ * For uAPSD, this is said in the standard (11.2.1.5 h):
+ * At each unscheduled SP for a non-AP STA, the AP shall
+ * attempt to transmit at least one MSDU or MMPDU, but no
+ * more than the value specified in the Max SP Length field
+ * in the QoS Capability element from delivery-enabled ACs,
+ * that are destined for the non-AP STA.
+ *
+ * Since we have no other MSDU/MMPDU, transmit a QoS null frame.
*/
- info->flags |= IEEE80211_TX_CTL_PSPOLL_RESPONSE;
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
- printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n",
- sta->sta.addr, sta->sta.aid,
- skb_queue_len(&sta->ps_tx_buf));
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+ /* This will evaluate to 1, 3, 5 or 7. */
+ tid = 7 - ((ffs(~ignored_acs) - 1) << 1);
- /* Use MoreData flag to indicate whether there are more
- * buffered frames for this STA */
- if (no_pending_pkts)
- hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
- else
- hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+ ieee80211_send_null_response(sdata, sta, tid, reason);
+ return;
+ }
+
+ if (!driver_release_tids) {
+ struct sk_buff_head pending;
+ struct sk_buff *skb;
+ int num = 0;
+ u16 tids = 0;
+
+ skb_queue_head_init(&pending);
+
+ while ((skb = __skb_dequeue(&frames))) {
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_hdr *hdr = (void *) skb->data;
+ u8 *qoshdr = NULL;
+
+ num++;
+
+ /*
+ * Tell TX path to send this frame even though the
+ * STA may still remain is PS mode after this frame
+ * exchange.
+ */
+ info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE;
+
+ /*
+ * Use MoreData flag to indicate whether there are
+ * more buffered frames for this STA
+ */
+ if (!more_data)
+ hdr->frame_control &=
+ cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
+ else
+ hdr->frame_control |=
+ cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+
+ if (ieee80211_is_data_qos(hdr->frame_control) ||
+ ieee80211_is_qos_nullfunc(hdr->frame_control))
+ qoshdr = ieee80211_get_qos_ctl(hdr);
+
+ /* set EOSP for the frame */
+ if (reason == IEEE80211_FRAME_RELEASE_UAPSD &&
+ qoshdr && skb_queue_empty(&frames))
+ *qoshdr |= IEEE80211_QOS_CTL_EOSP;
+
+ info->flags |= IEEE80211_TX_STATUS_EOSP |
+ IEEE80211_TX_CTL_REQ_TX_STATUS;
+
+ if (qoshdr)
+ tids |= BIT(*qoshdr & IEEE80211_QOS_CTL_TID_MASK);
+ else
+ tids |= BIT(0);
+
+ __skb_queue_tail(&pending, skb);
+ }
- ieee80211_add_pending_skb(local, skb);
+ drv_allow_buffered_frames(local, sta, tids, num,
+ reason, more_data);
- if (no_pending_pkts)
- sta_info_clear_tim_bit(sta);
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+ ieee80211_add_pending_skbs(local, &pending);
+
+ sta_info_recalc_tim(sta);
} else {
/*
- * FIXME: This can be the result of a race condition between
- * us expiring a frame and the station polling for it.
- * Should we send it a null-func frame indicating we
- * have nothing buffered for it?
+ * We need to release a frame that is buffered somewhere in the
+ * driver ... it'll have to handle that.
+ * Note that, as per the comment above, it'll also have to see
+ * if there is more than just one frame on the specific TID that
+ * we're releasing from, and it needs to set the more-data bit
+ * accordingly if we tell it that there's no more data. If we do
+ * tell it there's more data, then of course the more-data bit
+ * needs to be set anyway.
+ */
+ drv_release_buffered_frames(local, sta, driver_release_tids,
+ n_frames, reason, more_data);
+
+ /*
+ * Note that we don't recalculate the TIM bit here as it would
+ * most likely have no effect at all unless the driver told us
+ * that the TID became empty before returning here from the
+ * release function.
+ * Either way, however, when the driver tells us that the TID
+ * became empty we'll do the TIM recalculation.
*/
- printk(KERN_DEBUG "%s: STA %pM sent PS Poll even "
- "though there are no buffered frames for it\n",
- sdata->name, sta->sta.addr);
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
}
}
+void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta)
+{
+ u8 ignore_for_response = sta->sta.uapsd_queues;
+
+ /*
+ * If all ACs are delivery-enabled then we should reply
+ * from any of them, if only some are enabled we reply
+ * only from the non-enabled ones.
+ */
+ if (ignore_for_response == BIT(IEEE80211_NUM_ACS) - 1)
+ ignore_for_response = 0;
+
+ ieee80211_sta_ps_deliver_response(sta, 1, ignore_for_response,
+ IEEE80211_FRAME_RELEASE_PSPOLL);
+}
+
+void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta)
+{
+ int n_frames = sta->sta.max_sp;
+ u8 delivery_enabled = sta->sta.uapsd_queues;
+
+ /*
+ * If we ever grow support for TSPEC this might happen if
+ * the TSPEC update from hostapd comes in between a trigger
+ * frame setting WLAN_STA_UAPSD in the RX path and this
+ * actually getting called.
+ */
+ if (!delivery_enabled)
+ return;
+
+ switch (sta->sta.max_sp) {
+ case 1:
+ n_frames = 2;
+ break;
+ case 2:
+ n_frames = 4;
+ break;
+ case 3:
+ n_frames = 6;
+ break;
+ case 0:
+ /* XXX: what is a good value? */
+ n_frames = 8;
+ break;
+ }
+
+ ieee80211_sta_ps_deliver_response(sta, n_frames, ~delivery_enabled,
+ IEEE80211_FRAME_RELEASE_UAPSD);
+}
+
void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
struct ieee80211_sta *pubsta, bool block)
{
@@ -984,17 +1470,50 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
trace_api_sta_block_awake(sta->local, pubsta, block);
if (block)
- set_sta_flags(sta, WLAN_STA_PS_DRIVER);
- else if (test_sta_flags(sta, WLAN_STA_PS_DRIVER))
+ set_sta_flag(sta, WLAN_STA_PS_DRIVER);
+ else if (test_sta_flag(sta, WLAN_STA_PS_DRIVER))
ieee80211_queue_work(hw, &sta->drv_unblock_wk);
}
EXPORT_SYMBOL(ieee80211_sta_block_awake);
-void ieee80211_sta_set_tim(struct ieee80211_sta *pubsta)
+void ieee80211_sta_eosp_irqsafe(struct ieee80211_sta *pubsta)
{
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
+ struct ieee80211_local *local = sta->local;
+ struct sk_buff *skb;
+ struct skb_eosp_msg_data *data;
+
+ trace_api_eosp(local, pubsta);
+
+ skb = alloc_skb(0, GFP_ATOMIC);
+ if (!skb) {
+ /* too bad ... but race is better than loss */
+ clear_sta_flag(sta, WLAN_STA_SP);
+ return;
+ }
+
+ data = (void *)skb->cb;
+ memcpy(data->sta, pubsta->addr, ETH_ALEN);
+ memcpy(data->iface, sta->sdata->vif.addr, ETH_ALEN);
+ skb->pkt_type = IEEE80211_EOSP_MSG;
+ skb_queue_tail(&local->skb_queue, skb);
+ tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_sta_eosp_irqsafe);
+
+void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta,
+ u8 tid, bool buffered)
+{
+ struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
+
+ if (WARN_ON(tid >= STA_TID_NUM))
+ return;
+
+ if (buffered)
+ set_bit(tid, &sta->driver_buffered_tids);
+ else
+ clear_bit(tid, &sta->driver_buffered_tids);
- set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
- sta_info_set_tim_bit(sta);
+ sta_info_recalc_tim(sta);
}
-EXPORT_SYMBOL(ieee80211_sta_set_tim);
+EXPORT_SYMBOL(ieee80211_sta_set_buffered);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 28beb78e601e..8c8ce05ad26f 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -19,7 +19,8 @@
/**
* enum ieee80211_sta_info_flags - Stations flags
*
- * These flags are used with &struct sta_info's @flags member.
+ * These flags are used with &struct sta_info's @flags member, but
+ * only indirectly with set_sta_flag() and friends.
*
* @WLAN_STA_AUTH: Station is authenticated.
* @WLAN_STA_ASSOC: Station is associated.
@@ -43,24 +44,33 @@
* be in the queues
* @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping
* station in power-save mode, reply when the driver unblocks.
- * @WLAN_STA_PS_DRIVER_BUF: Station has frames pending in driver internal
- * buffers. Automatically cleared on station wake-up.
+ * @WLAN_STA_TDLS_PEER: Station is a TDLS peer.
+ * @WLAN_STA_TDLS_PEER_AUTH: This TDLS peer is authorized to send direct
+ * packets. This means the link is enabled.
+ * @WLAN_STA_UAPSD: Station requested unscheduled SP while driver was
+ * keeping station in power-save mode, reply when the driver
+ * unblocks the station.
+ * @WLAN_STA_SP: Station is in a service period, so don't try to
+ * reply to other uAPSD trigger frames or PS-Poll.
*/
enum ieee80211_sta_info_flags {
- WLAN_STA_AUTH = 1<<0,
- WLAN_STA_ASSOC = 1<<1,
- WLAN_STA_PS_STA = 1<<2,
- WLAN_STA_AUTHORIZED = 1<<3,
- WLAN_STA_SHORT_PREAMBLE = 1<<4,
- WLAN_STA_ASSOC_AP = 1<<5,
- WLAN_STA_WME = 1<<6,
- WLAN_STA_WDS = 1<<7,
- WLAN_STA_CLEAR_PS_FILT = 1<<9,
- WLAN_STA_MFP = 1<<10,
- WLAN_STA_BLOCK_BA = 1<<11,
- WLAN_STA_PS_DRIVER = 1<<12,
- WLAN_STA_PSPOLL = 1<<13,
- WLAN_STA_PS_DRIVER_BUF = 1<<14,
+ WLAN_STA_AUTH,
+ WLAN_STA_ASSOC,
+ WLAN_STA_PS_STA,
+ WLAN_STA_AUTHORIZED,
+ WLAN_STA_SHORT_PREAMBLE,
+ WLAN_STA_ASSOC_AP,
+ WLAN_STA_WME,
+ WLAN_STA_WDS,
+ WLAN_STA_CLEAR_PS_FILT,
+ WLAN_STA_MFP,
+ WLAN_STA_BLOCK_BA,
+ WLAN_STA_PS_DRIVER,
+ WLAN_STA_PSPOLL,
+ WLAN_STA_TDLS_PEER,
+ WLAN_STA_TDLS_PEER_AUTH,
+ WLAN_STA_UAPSD,
+ WLAN_STA_SP,
};
#define STA_TID_NUM 16
@@ -86,6 +96,8 @@ enum ieee80211_sta_info_flags {
* @stop_initiator: initiator of a session stop
* @tx_stop: TX DelBA frame when stopping
* @buf_size: reorder buffer size at receiver
+ * @failed_bar_ssn: ssn of the last failed BAR tx attempt
+ * @bar_pending: BAR needs to be re-sent
*
* This structure's lifetime is managed by RCU, assignments to
* the array holding it must hold the aggregation mutex.
@@ -106,6 +118,9 @@ struct tid_ampdu_tx {
u8 stop_initiator;
bool tx_stop;
u8 buf_size;
+
+ u16 failed_bar_ssn;
+ bool bar_pending;
};
/**
@@ -198,15 +213,16 @@ struct sta_ampdu_mlme {
* @last_rx_rate_flag: rx status flag of the last data packet
* @lock: used for locking all fields that require locking, see comments
* in the header file.
- * @flaglock: spinlock for flags accesses
* @drv_unblock_wk: used for driver PS unblocking
* @listen_interval: listen interval of this station, when we're acting as AP
- * @flags: STA flags, see &enum ieee80211_sta_info_flags
- * @ps_tx_buf: buffer of frames to transmit to this station
- * when it leaves power saving state
- * @tx_filtered: buffer of frames we already tried to transmit
- * but were filtered by hardware due to STA having entered
- * power saving state
+ * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly
+ * @ps_tx_buf: buffers (per AC) of frames to transmit to this station
+ * when it leaves power saving state or polls
+ * @tx_filtered: buffers (per AC) of frames we already tried to
+ * transmit but were filtered by hardware due to STA having
+ * entered power saving state, these are also delivered to
+ * the station when it leaves powersave or polls for frames
+ * @driver_buffered_tids: bitmap of TIDs the driver has data buffered on
* @rx_packets: Number of MSDUs received from this STA
* @rx_bytes: Number of bytes received from this STA
* @wep_weak_iv_count: number of weak WEP IVs received from this station
@@ -238,10 +254,12 @@ struct sta_ampdu_mlme {
* @plink_timer: peer link watch timer
* @plink_timer_was_running: used by suspend/resume to restore timers
* @debugfs: debug filesystem info
- * @sta: station information we share with the driver
* @dead: set to true when sta is unlinked
* @uploaded: set to true when sta is uploaded to the driver
* @lost_packets: number of consecutive lost packets
+ * @dummy: indicate a dummy station created for receiving
+ * EAP frames before association
+ * @sta: station information we share with the driver
*/
struct sta_info {
/* General information, mostly static */
@@ -254,7 +272,6 @@ struct sta_info {
struct rate_control_ref *rate_ctrl;
void *rate_ctrl_priv;
spinlock_t lock;
- spinlock_t flaglock;
struct work_struct drv_unblock_wk;
@@ -264,18 +281,16 @@ struct sta_info {
bool uploaded;
- /*
- * frequently updated, locked with own spinlock (flaglock),
- * use the accessors defined below
- */
- u32 flags;
+ /* use the accessors defined below */
+ unsigned long _flags;
/*
* STA powersave frame queues, no more than the internal
* locking required.
*/
- struct sk_buff_head ps_tx_buf;
- struct sk_buff_head tx_filtered;
+ struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS];
+ struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS];
+ unsigned long driver_buffered_tids;
/* Updated from RX path only, no locking requirements */
unsigned long rx_packets, rx_bytes;
@@ -336,6 +351,9 @@ struct sta_info {
unsigned int lost_packets;
+ /* should be right in front of sta to be in the same cache line */
+ bool dummy;
+
/* keep last! */
struct ieee80211_sta sta;
};
@@ -348,60 +366,28 @@ static inline enum nl80211_plink_state sta_plink_state(struct sta_info *sta)
return NL80211_PLINK_LISTEN;
}
-static inline void set_sta_flags(struct sta_info *sta, const u32 flags)
+static inline void set_sta_flag(struct sta_info *sta,
+ enum ieee80211_sta_info_flags flag)
{
- unsigned long irqfl;
-
- spin_lock_irqsave(&sta->flaglock, irqfl);
- sta->flags |= flags;
- spin_unlock_irqrestore(&sta->flaglock, irqfl);
+ set_bit(flag, &sta->_flags);
}
-static inline void clear_sta_flags(struct sta_info *sta, const u32 flags)
+static inline void clear_sta_flag(struct sta_info *sta,
+ enum ieee80211_sta_info_flags flag)
{
- unsigned long irqfl;
-
- spin_lock_irqsave(&sta->flaglock, irqfl);
- sta->flags &= ~flags;
- spin_unlock_irqrestore(&sta->flaglock, irqfl);
+ clear_bit(flag, &sta->_flags);
}
-static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags)
+static inline int test_sta_flag(struct sta_info *sta,
+ enum ieee80211_sta_info_flags flag)
{
- u32 ret;
- unsigned long irqfl;
-
- spin_lock_irqsave(&sta->flaglock, irqfl);
- ret = sta->flags & flags;
- spin_unlock_irqrestore(&sta->flaglock, irqfl);
-
- return ret;
-}
-
-static inline u32 test_and_clear_sta_flags(struct sta_info *sta,
- const u32 flags)
-{
- u32 ret;
- unsigned long irqfl;
-
- spin_lock_irqsave(&sta->flaglock, irqfl);
- ret = sta->flags & flags;
- sta->flags &= ~flags;
- spin_unlock_irqrestore(&sta->flaglock, irqfl);
-
- return ret;
+ return test_bit(flag, &sta->_flags);
}
-static inline u32 get_sta_flags(struct sta_info *sta)
+static inline int test_and_clear_sta_flag(struct sta_info *sta,
+ enum ieee80211_sta_info_flags flag)
{
- u32 ret;
- unsigned long irqfl;
-
- spin_lock_irqsave(&sta->flaglock, irqfl);
- ret = sta->flags;
- spin_unlock_irqrestore(&sta->flaglock, irqfl);
-
- return ret;
+ return test_and_clear_bit(flag, &sta->_flags);
}
void ieee80211_assign_tid_tx(struct sta_info *sta, int tid,
@@ -419,8 +405,8 @@ rcu_dereference_protected_tid_tx(struct sta_info *sta, int tid)
#define STA_HASH(sta) (sta[5])
-/* Maximum number of frames to buffer per power saving station */
-#define STA_MAX_TX_BUFFER 128
+/* Maximum number of frames to buffer per power saving station per AC */
+#define STA_MAX_TX_BUFFER 64
/* Minimum buffered frame expiry time. If STA uses listen interval that is
* smaller than this value, the minimum value here is used instead. */
@@ -436,9 +422,15 @@ rcu_dereference_protected_tid_tx(struct sta_info *sta, int tid)
struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
const u8 *addr);
+struct sta_info *sta_info_get_rx(struct ieee80211_sub_if_data *sdata,
+ const u8 *addr);
+
struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
const u8 *addr);
+struct sta_info *sta_info_get_bss_rx(struct ieee80211_sub_if_data *sdata,
+ const u8 *addr);
+
static inline
void for_each_sta_info_type_check(struct ieee80211_local *local,
const u8 *addr,
@@ -459,6 +451,22 @@ void for_each_sta_info_type_check(struct ieee80211_local *local,
_sta = nxt, \
nxt = _sta ? rcu_dereference(_sta->hnext) : NULL \
) \
+ /* run code only if address matches and it's not a dummy sta */ \
+ if (memcmp(_sta->sta.addr, (_addr), ETH_ALEN) == 0 && \
+ !_sta->dummy)
+
+#define for_each_sta_info_rx(local, _addr, _sta, nxt) \
+ for ( /* initialise loop */ \
+ _sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\
+ nxt = _sta ? rcu_dereference(_sta->hnext) : NULL; \
+ /* typecheck */ \
+ for_each_sta_info_type_check(local, (_addr), _sta, nxt),\
+ /* continue condition */ \
+ _sta; \
+ /* advance loop */ \
+ _sta = nxt, \
+ 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)
@@ -484,14 +492,14 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
int sta_info_insert(struct sta_info *sta);
int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU);
int sta_info_insert_atomic(struct sta_info *sta);
+int sta_info_reinsert(struct sta_info *sta);
int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata,
const u8 *addr);
int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata,
const u8 *addr);
-void sta_info_set_tim_bit(struct sta_info *sta);
-void sta_info_clear_tim_bit(struct sta_info *sta);
+void sta_info_recalc_tim(struct sta_info *sta);
void sta_info_init(struct ieee80211_local *local);
void sta_info_stop(struct ieee80211_local *local);
@@ -502,5 +510,6 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta);
void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta);
+void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta);
#endif /* STA_INFO_H */
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 1658efaa2e8e..df643cedf9b9 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -14,6 +14,7 @@
#include "rate.h"
#include "mesh.h"
#include "led.h"
+#include "wme.h"
void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
@@ -43,6 +44,8 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_hdr *hdr = (void *)skb->data;
+ int ac;
/*
* This skb 'survived' a round-trip through the driver, and
@@ -63,11 +66,37 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
sta->tx_filtered_count++;
/*
+ * Clear more-data bit on filtered frames, it might be set
+ * but later frames might time out so it might have to be
+ * clear again ... It's all rather unlikely (this frame
+ * should time out first, right?) but let's not confuse
+ * peers unnecessarily.
+ */
+ if (hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_MOREDATA))
+ hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+
+ if (ieee80211_is_data_qos(hdr->frame_control)) {
+ u8 *p = ieee80211_get_qos_ctl(hdr);
+ int tid = *p & IEEE80211_QOS_CTL_TID_MASK;
+
+ /*
+ * Clear EOSP if set, this could happen e.g.
+ * if an absence period (us being a P2P GO)
+ * shortens the SP.
+ */
+ if (*p & IEEE80211_QOS_CTL_EOSP)
+ *p &= ~IEEE80211_QOS_CTL_EOSP;
+ ac = ieee802_1d_to_ac[tid & 7];
+ } else {
+ ac = IEEE80211_AC_BE;
+ }
+
+ /*
* Clear the TX filter mask for this STA when sending the next
* packet. If the STA went to power save mode, this will happen
* when it wakes up for the next time.
*/
- set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT);
+ set_sta_flag(sta, WLAN_STA_CLEAR_PS_FILT);
/*
* This code races in the following way:
@@ -103,13 +132,19 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
* changes before calling TX status events if ordering can be
* unknown.
*/
- if (test_sta_flags(sta, WLAN_STA_PS_STA) &&
- skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
- skb_queue_tail(&sta->tx_filtered, skb);
+ if (test_sta_flag(sta, WLAN_STA_PS_STA) &&
+ skb_queue_len(&sta->tx_filtered[ac]) < STA_MAX_TX_BUFFER) {
+ skb_queue_tail(&sta->tx_filtered[ac], skb);
+ sta_info_recalc_tim(sta);
+
+ if (!timer_pending(&local->sta_cleanup))
+ mod_timer(&local->sta_cleanup,
+ round_jiffies(jiffies +
+ STA_INFO_CLEANUP_INTERVAL));
return;
}
- if (!test_sta_flags(sta, WLAN_STA_PS_STA) &&
+ if (!test_sta_flag(sta, WLAN_STA_PS_STA) &&
!(info->flags & IEEE80211_TX_INTFL_RETRIED)) {
/* Software retry the packet once */
info->flags |= IEEE80211_TX_INTFL_RETRIED;
@@ -121,18 +156,38 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
if (net_ratelimit())
wiphy_debug(local->hw.wiphy,
"dropped TX filtered frame, queue_len=%d PS=%d @%lu\n",
- skb_queue_len(&sta->tx_filtered),
- !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies);
+ skb_queue_len(&sta->tx_filtered[ac]),
+ !!test_sta_flag(sta, WLAN_STA_PS_STA), jiffies);
#endif
dev_kfree_skb(skb);
}
+static void ieee80211_check_pending_bar(struct sta_info *sta, u8 *addr, u8 tid)
+{
+ struct tid_ampdu_tx *tid_tx;
+
+ tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
+ if (!tid_tx || !tid_tx->bar_pending)
+ return;
+
+ tid_tx->bar_pending = false;
+ ieee80211_send_bar(&sta->sdata->vif, addr, tid, tid_tx->failed_bar_ssn);
+}
+
static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
{
struct ieee80211_mgmt *mgmt = (void *) skb->data;
struct ieee80211_local *local = sta->local;
struct ieee80211_sub_if_data *sdata = sta->sdata;
+ if (ieee80211_is_data_qos(mgmt->frame_control)) {
+ struct ieee80211_hdr *hdr = (void *) skb->data;
+ u8 *qc = ieee80211_get_qos_ctl(hdr);
+ u16 tid = qc[0] & 0xf;
+
+ ieee80211_check_pending_bar(sta, hdr->addr1, tid);
+ }
+
if (ieee80211_is_action(mgmt->frame_control) &&
sdata->vif.type == NL80211_IFTYPE_STATION &&
mgmt->u.action.category == WLAN_CATEGORY_HT &&
@@ -161,6 +216,114 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
}
}
+static void ieee80211_set_bar_pending(struct sta_info *sta, u8 tid, u16 ssn)
+{
+ struct tid_ampdu_tx *tid_tx;
+
+ tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
+ if (!tid_tx)
+ return;
+
+ tid_tx->failed_bar_ssn = ssn;
+ tid_tx->bar_pending = true;
+}
+
+static int ieee80211_tx_radiotap_len(struct ieee80211_tx_info *info)
+{
+ int len = sizeof(struct ieee80211_radiotap_header);
+
+ /* IEEE80211_RADIOTAP_RATE rate */
+ if (info->status.rates[0].idx >= 0 &&
+ !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS))
+ len += 2;
+
+ /* IEEE80211_RADIOTAP_TX_FLAGS */
+ len += 2;
+
+ /* IEEE80211_RADIOTAP_DATA_RETRIES */
+ len += 1;
+
+ /* IEEE80211_TX_RC_MCS */
+ if (info->status.rates[0].idx >= 0 &&
+ info->status.rates[0].flags & IEEE80211_TX_RC_MCS)
+ len += 3;
+
+ return len;
+}
+
+static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band
+ *sband, struct sk_buff *skb,
+ int retry_count, int rtap_len)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_radiotap_header *rthdr;
+ unsigned char *pos;
+ __le16 txflags;
+
+ rthdr = (struct ieee80211_radiotap_header *) skb_push(skb, rtap_len);
+
+ memset(rthdr, 0, rtap_len);
+ rthdr->it_len = cpu_to_le16(rtap_len);
+ rthdr->it_present =
+ cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
+ (1 << IEEE80211_RADIOTAP_DATA_RETRIES));
+ pos = (unsigned char *)(rthdr + 1);
+
+ /*
+ * XXX: Once radiotap gets the bitmap reset thing the vendor
+ * extensions proposal contains, we can actually report
+ * the whole set of tries we did.
+ */
+
+ /* IEEE80211_RADIOTAP_RATE */
+ if (info->status.rates[0].idx >= 0 &&
+ !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) {
+ rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE);
+ *pos = sband->bitrates[info->status.rates[0].idx].bitrate / 5;
+ /* padding for tx flags */
+ pos += 2;
+ }
+
+ /* IEEE80211_RADIOTAP_TX_FLAGS */
+ txflags = 0;
+ if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
+ !is_multicast_ether_addr(hdr->addr1))
+ txflags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
+
+ if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+ (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
+ txflags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
+ else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
+ txflags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
+
+ put_unaligned_le16(txflags, pos);
+ pos += 2;
+
+ /* IEEE80211_RADIOTAP_DATA_RETRIES */
+ /* for now report the total retry_count */
+ *pos = retry_count;
+ pos++;
+
+ /* IEEE80211_TX_RC_MCS */
+ if (info->status.rates[0].idx >= 0 &&
+ info->status.rates[0].flags & IEEE80211_TX_RC_MCS) {
+ rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS);
+ pos[0] = IEEE80211_RADIOTAP_MCS_HAVE_MCS |
+ IEEE80211_RADIOTAP_MCS_HAVE_GI |
+ IEEE80211_RADIOTAP_MCS_HAVE_BW;
+ if (info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)
+ pos[1] |= IEEE80211_RADIOTAP_MCS_SGI;
+ if (info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ pos[1] |= IEEE80211_RADIOTAP_MCS_BW_40;
+ if (info->status.rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)
+ pos[1] |= IEEE80211_RADIOTAP_MCS_FMT_GF;
+ pos[2] = info->status.rates[0].idx;
+ pos += 3;
+ }
+
+}
+
/*
* Use a static threshold for now, best value to be determined
* by testing ...
@@ -179,7 +342,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
u16 frag, type;
__le16 fc;
struct ieee80211_supported_band *sband;
- struct ieee80211_tx_status_rtap_hdr *rthdr;
struct ieee80211_sub_if_data *sdata;
struct net_device *prev_dev = NULL;
struct sta_info *sta, *tmp;
@@ -187,6 +349,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
int rates_idx = -1;
bool send_to_cooked;
bool acked;
+ struct ieee80211_bar *bar;
+ u16 tid;
+ int rtap_len;
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
if (info->status.rates[i].idx < 0) {
@@ -215,8 +380,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
if (memcmp(hdr->addr2, sta->sdata->vif.addr, ETH_ALEN))
continue;
+ if (info->flags & IEEE80211_TX_STATUS_EOSP)
+ clear_sta_flag(sta, WLAN_STA_SP);
+
acked = !!(info->flags & IEEE80211_TX_STAT_ACK);
- if (!acked && test_sta_flags(sta, WLAN_STA_PS_STA)) {
+ if (!acked && test_sta_flag(sta, WLAN_STA_PS_STA)) {
/*
* The STA is in power save mode, so assume
* that this TX packet failed because of that.
@@ -239,10 +407,31 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
tid = qc[0] & 0xf;
ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10)
& IEEE80211_SCTL_SEQ);
- ieee80211_send_bar(sta->sdata, hdr->addr1,
+ ieee80211_send_bar(&sta->sdata->vif, hdr->addr1,
tid, ssn);
}
+ if (!acked && ieee80211_is_back_req(fc)) {
+ u16 control;
+
+ /*
+ * BAR failed, store the last SSN and retry sending
+ * the BAR when the next unicast transmission on the
+ * same TID succeeds.
+ */
+ bar = (struct ieee80211_bar *) skb->data;
+ control = le16_to_cpu(bar->control);
+ if (!(control & IEEE80211_BAR_CTRL_MULTI_TID)) {
+ u16 ssn = le16_to_cpu(bar->start_seq_num);
+
+ tid = (control &
+ IEEE80211_BAR_CTRL_TID_INFO_MASK) >>
+ IEEE80211_BAR_CTRL_TID_INFO_SHIFT;
+
+ ieee80211_set_bar_pending(sta, tid, ssn);
+ }
+ }
+
if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
ieee80211_handle_filtered_frame(local, sta, skb);
rcu_read_unlock();
@@ -336,7 +525,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
continue;
if (wk->offchan_tx.frame != skb)
continue;
- wk->offchan_tx.frame = NULL;
+ wk->offchan_tx.status = true;
break;
}
rcu_read_unlock();
@@ -345,9 +534,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
local->hw_roc_skb_for_status = NULL;
}
- if (cookie == local->hw_offchan_tx_cookie)
- local->hw_offchan_tx_cookie = 0;
-
cfg80211_mgmt_tx_status(
skb->dev, cookie, skb->data, skb->len,
!!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC);
@@ -370,44 +556,13 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
}
/* send frame to monitor interfaces now */
-
- if (skb_headroom(skb) < sizeof(*rthdr)) {
+ rtap_len = ieee80211_tx_radiotap_len(info);
+ if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) {
printk(KERN_ERR "ieee80211_tx_status: headroom too small\n");
dev_kfree_skb(skb);
return;
}
-
- rthdr = (struct ieee80211_tx_status_rtap_hdr *)
- 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_TX_FLAGS) |
- (1 << IEEE80211_RADIOTAP_DATA_RETRIES) |
- (1 << IEEE80211_RADIOTAP_RATE));
-
- if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
- !is_multicast_ether_addr(hdr->addr1))
- rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
-
- /*
- * XXX: Once radiotap gets the bitmap reset thing the vendor
- * extensions proposal contains, we can actually report
- * the whole set of tries we did.
- */
- if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
- (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
- rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
- else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
- rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
- if (info->status.rates[0].idx >= 0 &&
- !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS))
- rthdr->rate = sband->bitrates[
- info->status.rates[0].idx].bitrate / 5;
-
- /* for now report the total retry_count */
- rthdr->data_retries = retry_count;
+ ieee80211_add_tx_radiotap_header(sband, skb, retry_count, rtap_len);
/* XXX: is this sufficient for BPF? */
skb_set_mac_header(skb, 0);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 8cb0d2d0ac69..48bbb96d8edb 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -253,7 +253,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
- u32 sta_flags;
+ bool assoc = false;
if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED))
return TX_CONTINUE;
@@ -284,10 +284,11 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
if (tx->flags & IEEE80211_TX_PS_BUFFERED)
return TX_CONTINUE;
- sta_flags = tx->sta ? get_sta_flags(tx->sta) : 0;
+ if (tx->sta)
+ assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC);
if (likely(tx->flags & IEEE80211_TX_UNICAST)) {
- if (unlikely(!(sta_flags & WLAN_STA_ASSOC) &&
+ if (unlikely(!assoc &&
tx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
ieee80211_is_data(hdr->frame_control))) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
@@ -343,13 +344,22 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
total += skb_queue_len(&ap->ps_bc_buf);
}
+ /*
+ * Drop one frame from each station from the lowest-priority
+ * AC that has frames at all.
+ */
list_for_each_entry_rcu(sta, &local->sta_list, list) {
- skb = skb_dequeue(&sta->ps_tx_buf);
- if (skb) {
- purged++;
- dev_kfree_skb(skb);
+ int ac;
+
+ for (ac = IEEE80211_AC_BK; ac >= IEEE80211_AC_VO; ac--) {
+ skb = skb_dequeue(&sta->ps_tx_buf[ac]);
+ total += skb_queue_len(&sta->ps_tx_buf[ac]);
+ if (skb) {
+ purged++;
+ dev_kfree_skb(skb);
+ break;
+ }
}
- total += skb_queue_len(&sta->ps_tx_buf);
}
rcu_read_unlock();
@@ -418,7 +428,7 @@ static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta,
if (!ieee80211_is_mgmt(fc))
return 0;
- if (sta == NULL || !test_sta_flags(sta, WLAN_STA_MFP))
+ if (sta == NULL || !test_sta_flag(sta, WLAN_STA_MFP))
return 0;
if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *)
@@ -435,7 +445,6 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
struct ieee80211_local *local = tx->local;
- u32 staflags;
if (unlikely(!sta ||
ieee80211_is_probe_resp(hdr->frame_control) ||
@@ -444,57 +453,52 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
ieee80211_is_reassoc_resp(hdr->frame_control)))
return TX_CONTINUE;
- staflags = get_sta_flags(sta);
+ 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))) {
+ int ac = skb_get_queue_mapping(tx->skb);
- if (unlikely((staflags & (WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) &&
- !(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE))) {
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
- printk(KERN_DEBUG "STA %pM aid %d: PS buffer (entries "
- "before %d)\n",
- sta->sta.addr, sta->sta.aid,
- skb_queue_len(&sta->ps_tx_buf));
+ printk(KERN_DEBUG "STA %pM aid %d: PS buffer for AC %d\n",
+ sta->sta.addr, sta->sta.aid, ac);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
purge_old_ps_buffers(tx->local);
- if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) {
- struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf);
+ if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) {
+ struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]);
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: STA %pM TX "
- "buffer full - dropping oldest frame\n",
- tx->sdata->name, sta->sta.addr);
- }
+ if (net_ratelimit())
+ printk(KERN_DEBUG "%s: STA %pM TX buffer for "
+ "AC %d full - dropping oldest frame\n",
+ tx->sdata->name, sta->sta.addr, ac);
#endif
dev_kfree_skb(old);
} else
tx->local->total_ps_buffered++;
- /*
- * Queue frame to be sent after STA wakes up/polls,
- * but don't set the TIM bit if the driver is blocking
- * wakeup or poll response transmissions anyway.
- */
- if (skb_queue_empty(&sta->ps_tx_buf) &&
- !(staflags & WLAN_STA_PS_DRIVER))
- sta_info_set_tim_bit(sta);
-
info->control.jiffies = jiffies;
info->control.vif = &tx->sdata->vif;
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
- skb_queue_tail(&sta->ps_tx_buf, tx->skb);
+ skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb);
if (!timer_pending(&local->sta_cleanup))
mod_timer(&local->sta_cleanup,
round_jiffies(jiffies +
STA_INFO_CLEANUP_INTERVAL));
+ /*
+ * We queued up some frames, so the TIM bit might
+ * need to be set, recalculate it.
+ */
+ sta_info_recalc_tim(sta);
+
return TX_QUEUED;
}
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
- else if (unlikely(staflags & WLAN_STA_PS_STA)) {
- printk(KERN_DEBUG "%s: STA %pM in PS mode, but pspoll "
- "set -> send frame\n", tx->sdata->name,
- sta->sta.addr);
+ else if (unlikely(test_sta_flag(sta, WLAN_STA_PS_STA))) {
+ printk(KERN_DEBUG
+ "%s: STA %pM in PS mode, but polling/in SP -> send frame\n",
+ tx->sdata->name, sta->sta.addr);
}
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
@@ -552,7 +556,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
!(info->flags & IEEE80211_TX_CTL_INJECTED) &&
(!ieee80211_is_robust_mgmt_frame(hdr) ||
(ieee80211_is_action(hdr->frame_control) &&
- tx->sta && test_sta_flags(tx->sta, WLAN_STA_MFP)))) {
+ tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP)))) {
I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
return TX_DROP;
} else
@@ -611,7 +615,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
u32 len;
bool inval = false, rts = false, short_preamble = false;
struct ieee80211_tx_rate_control txrc;
- u32 sta_flags;
+ bool assoc = false;
memset(&txrc, 0, sizeof(txrc));
@@ -647,17 +651,17 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
*/
if (tx->sdata->vif.bss_conf.use_short_preamble &&
(ieee80211_is_data(hdr->frame_control) ||
- (tx->sta && test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))))
+ (tx->sta && test_sta_flag(tx->sta, WLAN_STA_SHORT_PREAMBLE))))
txrc.short_preamble = short_preamble = true;
- sta_flags = tx->sta ? get_sta_flags(tx->sta) : 0;
+ if (tx->sta)
+ assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC);
/*
* Lets not bother rate control if we're associated and cannot
* talk to the sta. This should not happen.
*/
- if (WARN(test_bit(SCAN_SW_SCANNING, &tx->local->scanning) &&
- (sta_flags & WLAN_STA_ASSOC) &&
+ if (WARN(test_bit(SCAN_SW_SCANNING, &tx->local->scanning) && assoc &&
!rate_usable_index_exists(sband, &tx->sta->sta),
"%s: Dropped data frame as no usable bitrate found while "
"scanning and associated. Target station: "
@@ -800,6 +804,9 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
if (ieee80211_hdrlen(hdr->frame_control) < 24)
return TX_CONTINUE;
+ if (ieee80211_is_qos_nullfunc(hdr->frame_control))
+ return TX_CONTINUE;
+
/*
* Anything but QoS data that has a sequence number field
* (is long enough) gets a sequence number from the global
@@ -891,7 +898,10 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
int hdrlen;
int fragnum;
- if (!(tx->flags & IEEE80211_TX_FRAGMENTED))
+ if (info->flags & IEEE80211_TX_CTL_DONTFRAG)
+ return TX_CONTINUE;
+
+ if (tx->local->ops->set_frag_threshold)
return TX_CONTINUE;
/*
@@ -904,7 +914,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
hdrlen = ieee80211_hdrlen(hdr->frame_control);
- /* internal error, why is TX_FRAGMENTED set? */
+ /* internal error, why isn't DONTFRAG set? */
if (WARN_ON(skb->len + FCS_LEN <= frag_threshold))
return TX_DROP;
@@ -1025,100 +1035,6 @@ ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx)
/* actual transmit path */
-/*
- * deal with packet injection down monitor interface
- * with Radiotap Header -- only called for monitor mode interface
- */
-static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
- struct sk_buff *skb)
-{
- /*
- * this is the moment to interpret and discard the radiotap header that
- * must be at the start of the packet injected in Monitor mode
- *
- * Need to take some care with endian-ness since radiotap
- * args are little-endian
- */
-
- struct ieee80211_radiotap_iterator iterator;
- struct ieee80211_radiotap_header *rthdr =
- (struct ieee80211_radiotap_header *) skb->data;
- bool hw_frag;
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
- NULL);
-
- info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
- tx->flags &= ~IEEE80211_TX_FRAGMENTED;
-
- /* packet is fragmented in HW if we have a non-NULL driver callback */
- hw_frag = (tx->local->ops->set_frag_threshold != NULL);
-
- /*
- * for every radiotap entry that is present
- * (ieee80211_radiotap_iterator_next returns -ENOENT when no more
- * entries present, or -EINVAL on error)
- */
-
- while (!ret) {
- ret = ieee80211_radiotap_iterator_next(&iterator);
-
- if (ret)
- continue;
-
- /* see if this argument is something we can use */
- switch (iterator.this_arg_index) {
- /*
- * You must take care when dereferencing iterator.this_arg
- * for multibyte types... the pointer is not aligned. Use
- * get_unaligned((type *)iterator.this_arg) to dereference
- * iterator.this_arg for type "type" safely on all arches.
- */
- case IEEE80211_RADIOTAP_FLAGS:
- if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) {
- /*
- * this indicates that the skb we have been
- * handed has the 32-bit FCS CRC at the end...
- * we should react to that by snipping it off
- * because it will be recomputed and added
- * on transmission
- */
- if (skb->len < (iterator._max_length + FCS_LEN))
- return false;
-
- skb_trim(skb, skb->len - FCS_LEN);
- }
- if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP)
- info->flags &= ~IEEE80211_TX_INTFL_DONT_ENCRYPT;
- if ((*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) &&
- !hw_frag)
- tx->flags |= IEEE80211_TX_FRAGMENTED;
- break;
-
- /*
- * Please update the file
- * Documentation/networking/mac80211-injection.txt
- * when parsing new fields here.
- */
-
- default:
- break;
- }
- }
-
- if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
- return false;
-
- /*
- * remove the radiotap header
- * iterator->_max_length was sanity-checked against
- * skb->len by iterator init
- */
- skb_pull(skb, iterator._max_length);
-
- return true;
-}
-
static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
struct sk_buff *skb,
struct ieee80211_tx_info *info,
@@ -1183,7 +1099,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local;
struct ieee80211_hdr *hdr;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- int hdrlen, tid;
+ int tid;
u8 *qc;
memset(tx, 0, sizeof(*tx));
@@ -1191,26 +1107,6 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
tx->local = local;
tx->sdata = sdata;
tx->channel = local->hw.conf.channel;
- /*
- * Set this flag (used below to indicate "automatic fragmentation"),
- * it will be cleared/left by radiotap as desired.
- * Only valid when fragmentation is done by the stack.
- */
- if (!local->ops->set_frag_threshold)
- tx->flags |= IEEE80211_TX_FRAGMENTED;
-
- /* process and remove the injection radiotap header */
- if (unlikely(info->flags & IEEE80211_TX_INTFL_HAS_RADIOTAP)) {
- if (!__ieee80211_parse_tx_radiotap(tx, skb))
- return TX_DROP;
-
- /*
- * __ieee80211_parse_tx_radiotap has now removed
- * the radiotap header that was present and pre-filled
- * 'tx' with tx control information.
- */
- info->flags &= ~IEEE80211_TX_INTFL_HAS_RADIOTAP;
- }
/*
* If this flag is set to true anywhere, and we get here,
@@ -1232,7 +1128,9 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
tx->sta = sta_info_get(sdata, hdr->addr1);
if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
- (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) {
+ !ieee80211_is_qos_nullfunc(hdr->frame_control) &&
+ (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) &&
+ !(local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW)) {
struct tid_ampdu_tx *tid_tx;
qc = ieee80211_get_qos_ctl(hdr);
@@ -1257,29 +1155,25 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
tx->flags |= IEEE80211_TX_UNICAST;
if (unlikely(local->wifi_wme_noack_test))
info->flags |= IEEE80211_TX_CTL_NO_ACK;
- else
- info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
+ /*
+ * Flags are initialized to 0. Hence, no need to
+ * explicitly unset IEEE80211_TX_CTL_NO_ACK since
+ * it might already be set for injected frames.
+ */
}
- if (tx->flags & IEEE80211_TX_FRAGMENTED) {
- if ((tx->flags & IEEE80211_TX_UNICAST) &&
- skb->len + FCS_LEN > local->hw.wiphy->frag_threshold &&
- !(info->flags & IEEE80211_TX_CTL_AMPDU))
- tx->flags |= IEEE80211_TX_FRAGMENTED;
- else
- tx->flags &= ~IEEE80211_TX_FRAGMENTED;
+ if (!(info->flags & IEEE80211_TX_CTL_DONTFRAG)) {
+ if (!(tx->flags & IEEE80211_TX_UNICAST) ||
+ skb->len + FCS_LEN <= local->hw.wiphy->frag_threshold ||
+ info->flags & IEEE80211_TX_CTL_AMPDU)
+ info->flags |= IEEE80211_TX_CTL_DONTFRAG;
}
if (!tx->sta)
info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
- else if (test_and_clear_sta_flags(tx->sta, WLAN_STA_CLEAR_PS_FILT))
+ else if (test_and_clear_sta_flag(tx->sta, WLAN_STA_CLEAR_PS_FILT))
info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
- hdrlen = ieee80211_hdrlen(hdr->frame_control);
- if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) {
- u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)];
- tx->ethertype = (pos[0] << 8) | pos[1];
- }
info->flags |= IEEE80211_TX_CTL_FIRST_FRAGMENT;
return TX_CONTINUE;
@@ -1490,11 +1384,6 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata,
tail_need = max_t(int, tail_need, 0);
}
- if (head_need || tail_need) {
- /* Sorry. Can't account for this any more */
- skb_orphan(skb);
- }
-
if (skb_cloned(skb))
I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
else if (head_need || tail_need)
@@ -1508,67 +1397,19 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata,
return -ENOMEM;
}
- /* update truesize too */
- skb->truesize += head_need + tail_need;
-
return 0;
}
-static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb)
+void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- struct ieee80211_sub_if_data *tmp_sdata;
int headroom;
bool may_encrypt;
rcu_read_lock();
- if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) {
- int hdrlen;
- u16 len_rthdr;
-
- info->flags |= IEEE80211_TX_CTL_INJECTED |
- IEEE80211_TX_INTFL_HAS_RADIOTAP;
-
- len_rthdr = ieee80211_get_radiotap_len(skb->data);
- hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr);
- hdrlen = ieee80211_hdrlen(hdr->frame_control);
-
- /* check the header is complete in the frame */
- if (likely(skb->len >= len_rthdr + hdrlen)) {
- /*
- * We process outgoing injected frames that have a
- * local address we handle as though they are our
- * own frames.
- * This code here isn't entirely correct, the local
- * MAC address is not necessarily enough to find
- * the interface to use; for that proper VLAN/WDS
- * support we will need a different mechanism.
- */
-
- list_for_each_entry_rcu(tmp_sdata, &local->interfaces,
- list) {
- if (!ieee80211_sdata_running(tmp_sdata))
- continue;
- if (tmp_sdata->vif.type ==
- NL80211_IFTYPE_MONITOR ||
- tmp_sdata->vif.type ==
- NL80211_IFTYPE_AP_VLAN ||
- tmp_sdata->vif.type ==
- NL80211_IFTYPE_WDS)
- continue;
- if (compare_ether_addr(tmp_sdata->vif.addr,
- hdr->addr2) == 0) {
- sdata = tmp_sdata;
- break;
- }
- }
- }
- }
-
may_encrypt = !(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT);
headroom = local->tx_headroom;
@@ -1595,11 +1436,94 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
return;
}
- ieee80211_set_qos_hdr(local, skb);
+ ieee80211_set_qos_hdr(sdata, skb);
ieee80211_tx(sdata, skb, false);
rcu_read_unlock();
}
+static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
+{
+ struct ieee80211_radiotap_iterator iterator;
+ struct ieee80211_radiotap_header *rthdr =
+ (struct ieee80211_radiotap_header *) skb->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
+ NULL);
+ u16 txflags;
+
+ info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
+ IEEE80211_TX_CTL_DONTFRAG;
+
+ /*
+ * for every radiotap entry that is present
+ * (ieee80211_radiotap_iterator_next returns -ENOENT when no more
+ * entries present, or -EINVAL on error)
+ */
+
+ while (!ret) {
+ ret = ieee80211_radiotap_iterator_next(&iterator);
+
+ if (ret)
+ continue;
+
+ /* see if this argument is something we can use */
+ switch (iterator.this_arg_index) {
+ /*
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned. Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ */
+ case IEEE80211_RADIOTAP_FLAGS:
+ if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) {
+ /*
+ * this indicates that the skb we have been
+ * handed has the 32-bit FCS CRC at the end...
+ * we should react to that by snipping it off
+ * because it will be recomputed and added
+ * on transmission
+ */
+ if (skb->len < (iterator._max_length + FCS_LEN))
+ return false;
+
+ skb_trim(skb, skb->len - FCS_LEN);
+ }
+ if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP)
+ info->flags &= ~IEEE80211_TX_INTFL_DONT_ENCRYPT;
+ if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG)
+ info->flags &= ~IEEE80211_TX_CTL_DONTFRAG;
+ break;
+
+ case IEEE80211_RADIOTAP_TX_FLAGS:
+ txflags = get_unaligned_le16(iterator.this_arg);
+ if (txflags & IEEE80211_RADIOTAP_F_TX_NOACK)
+ info->flags |= IEEE80211_TX_CTL_NO_ACK;
+ break;
+
+ /*
+ * Please update the file
+ * Documentation/networking/mac80211-injection.txt
+ * when parsing new fields here.
+ */
+
+ default:
+ break;
+ }
+ }
+
+ if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
+ return false;
+
+ /*
+ * remove the radiotap header
+ * iterator->_max_length was sanity-checked against
+ * skb->len by iterator init
+ */
+ skb_pull(skb, iterator._max_length);
+
+ return true;
+}
+
netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
@@ -1608,7 +1532,10 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
struct ieee80211_radiotap_header *prthdr =
(struct ieee80211_radiotap_header *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_hdr *hdr;
+ struct ieee80211_sub_if_data *tmp_sdata, *sdata;
u16 len_rthdr;
+ int hdrlen;
/*
* Frame injection is not allowed if beaconing is not allowed
@@ -1659,12 +1586,65 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
skb_set_network_header(skb, len_rthdr);
skb_set_transport_header(skb, len_rthdr);
+ if (skb->len < len_rthdr + 2)
+ goto fail;
+
+ hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr);
+ hdrlen = ieee80211_hdrlen(hdr->frame_control);
+
+ if (skb->len < len_rthdr + hdrlen)
+ goto fail;
+
+ /*
+ * Initialize skb->protocol if the injected frame is a data frame
+ * carrying a rfc1042 header
+ */
+ if (ieee80211_is_data(hdr->frame_control) &&
+ skb->len >= len_rthdr + hdrlen + sizeof(rfc1042_header) + 2) {
+ u8 *payload = (u8 *)hdr + hdrlen;
+
+ if (compare_ether_addr(payload, rfc1042_header) == 0)
+ skb->protocol = cpu_to_be16((payload[6] << 8) |
+ payload[7]);
+ }
+
memset(info, 0, sizeof(*info));
- info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+ info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
+ IEEE80211_TX_CTL_INJECTED;
+
+ /* process and remove the injection radiotap header */
+ if (!ieee80211_parse_tx_radiotap(skb))
+ goto fail;
+
+ rcu_read_lock();
+
+ /*
+ * We process outgoing injected frames that have a local address
+ * we handle as though they are non-injected frames.
+ * This code here isn't entirely correct, the local MAC address
+ * isn't always enough to find the interface to use; for proper
+ * VLAN/WDS support we will need a different mechanism (which
+ * likely isn't going to be monitor interfaces).
+ */
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ list_for_each_entry_rcu(tmp_sdata, &local->interfaces, list) {
+ if (!ieee80211_sdata_running(tmp_sdata))
+ continue;
+ if (tmp_sdata->vif.type == NL80211_IFTYPE_MONITOR ||
+ tmp_sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+ tmp_sdata->vif.type == NL80211_IFTYPE_WDS)
+ continue;
+ if (compare_ether_addr(tmp_sdata->vif.addr, hdr->addr2) == 0) {
+ sdata = tmp_sdata;
+ break;
+ }
+ }
+
+ ieee80211_xmit(sdata, skb);
+ rcu_read_unlock();
- /* pass the radiotap header up to xmit */
- ieee80211_xmit(IEEE80211_DEV_TO_SUB_IF(dev), skb);
return NETDEV_TX_OK;
fail:
@@ -1703,8 +1683,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
int encaps_len, skip_header_bytes;
int nh_pos, h_pos;
struct sta_info *sta = NULL;
- u32 sta_flags = 0;
+ bool wme_sta = false, authorized = false, tdls_auth = false;
struct sk_buff *tmp_skb;
+ bool tdls_direct = false;
if (unlikely(skb->len < ETH_HLEN)) {
ret = NETDEV_TX_OK;
@@ -1728,7 +1709,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
memcpy(hdr.addr3, skb->data, ETH_ALEN);
memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
hdrlen = 30;
- sta_flags = get_sta_flags(sta);
+ authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
+ wme_sta = test_sta_flag(sta, WLAN_STA_WME);
}
rcu_read_unlock();
if (sta)
@@ -1816,11 +1798,50 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
break;
#endif
case NL80211_IFTYPE_STATION:
- memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
- if (sdata->u.mgd.use_4addr &&
- cpu_to_be16(ethertype) != sdata->control_port_protocol) {
- fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
+ if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) {
+ bool tdls_peer = false;
+
+ rcu_read_lock();
+ sta = sta_info_get(sdata, skb->data);
+ if (sta) {
+ authorized = test_sta_flag(sta,
+ WLAN_STA_AUTHORIZED);
+ wme_sta = test_sta_flag(sta, WLAN_STA_WME);
+ tdls_peer = test_sta_flag(sta,
+ WLAN_STA_TDLS_PEER);
+ tdls_auth = test_sta_flag(sta,
+ WLAN_STA_TDLS_PEER_AUTH);
+ }
+ rcu_read_unlock();
+
+ /*
+ * If the TDLS link is enabled, send everything
+ * directly. Otherwise, allow TDLS setup frames
+ * to be transmitted indirectly.
+ */
+ tdls_direct = tdls_peer && (tdls_auth ||
+ !(ethertype == ETH_P_TDLS && skb->len > 14 &&
+ skb->data[14] == WLAN_TDLS_SNAP_RFTYPE));
+ }
+
+ if (tdls_direct) {
+ /* link during setup - throw out frames to peer */
+ if (!tdls_auth) {
+ ret = NETDEV_TX_OK;
+ goto fail;
+ }
+
+ /* DA SA BSSID */
+ memcpy(hdr.addr1, skb->data, ETH_ALEN);
+ memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
+ memcpy(hdr.addr3, sdata->u.mgd.bssid, ETH_ALEN);
+ hdrlen = 24;
+ } else if (sdata->u.mgd.use_4addr &&
+ cpu_to_be16(ethertype) != sdata->control_port_protocol) {
+ fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |
+ IEEE80211_FCTL_TODS);
/* RA TA DA SA */
+ memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
memcpy(hdr.addr3, skb->data, ETH_ALEN);
memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
@@ -1828,6 +1849,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
} else {
fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
/* BSSID SA DA */
+ memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
memcpy(hdr.addr3, skb->data, ETH_ALEN);
hdrlen = 24;
@@ -1853,13 +1875,19 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
if (!is_multicast_ether_addr(hdr.addr1)) {
rcu_read_lock();
sta = sta_info_get(sdata, hdr.addr1);
- if (sta)
- sta_flags = get_sta_flags(sta);
+ if (sta) {
+ authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
+ wme_sta = test_sta_flag(sta, WLAN_STA_WME);
+ }
rcu_read_unlock();
}
+ /* For mesh, the use of the QoS header is mandatory */
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ wme_sta = true;
+
/* receiver and we are QoS enabled, use a QoS type frame */
- if ((sta_flags & WLAN_STA_WME) && local->hw.queues >= 4) {
+ if (wme_sta && local->hw.queues >= 4) {
fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
hdrlen += 2;
}
@@ -1868,12 +1896,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
* Drop unicast frames to unauthorised stations unless they are
* EAPOL frames from the local station.
*/
- if (!ieee80211_vif_is_mesh(&sdata->vif) &&
- unlikely(!is_multicast_ether_addr(hdr.addr1) &&
- !(sta_flags & WLAN_STA_AUTHORIZED) &&
- !(cpu_to_be16(ethertype) == sdata->control_port_protocol &&
- compare_ether_addr(sdata->vif.addr,
- skb->data + ETH_ALEN) == 0))) {
+ if (unlikely(!ieee80211_vif_is_mesh(&sdata->vif) &&
+ !is_multicast_ether_addr(hdr.addr1) && !authorized &&
+ (cpu_to_be16(ethertype) != sdata->control_port_protocol ||
+ compare_ether_addr(sdata->vif.addr, skb->data + ETH_ALEN)))) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "%s: dropped frame to %pM"
@@ -2275,13 +2301,23 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
mgmt->u.beacon.beacon_int =
cpu_to_le16(sdata->vif.bss_conf.beacon_int);
- mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */
+ mgmt->u.beacon.capab_info |= cpu_to_le16(
+ sdata->u.mesh.security ? WLAN_CAPABILITY_PRIVACY : 0);
pos = skb_put(skb, 2);
*pos++ = WLAN_EID_SSID;
*pos++ = 0x0;
- mesh_mgmt_ies_add(skb, sdata);
+ if (ieee80211_add_srates_ie(&sdata->vif, skb) ||
+ mesh_add_ds_params_ie(skb, sdata) ||
+ ieee80211_add_ext_srates_ie(&sdata->vif, skb) ||
+ mesh_add_rsn_ie(skb, sdata) ||
+ mesh_add_meshid_ie(skb, sdata) ||
+ mesh_add_meshconf_ie(skb, sdata) ||
+ mesh_add_vendor_ies(skb, sdata)) {
+ pr_err("o11s: couldn't add ies!\n");
+ goto out;
+ }
} else {
WARN_ON(1);
goto out;
@@ -2335,11 +2371,9 @@ struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
local = sdata->local;
skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll));
- if (!skb) {
- printk(KERN_DEBUG "%s: failed to allocate buffer for "
- "pspoll template\n", sdata->name);
+ if (!skb)
return NULL;
- }
+
skb_reserve(skb, local->hw.extra_tx_headroom);
pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll));
@@ -2375,11 +2409,9 @@ struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw,
local = sdata->local;
skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*nullfunc));
- if (!skb) {
- printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "
- "template\n", sdata->name);
+ if (!skb)
return NULL;
- }
+
skb_reserve(skb, local->hw.extra_tx_headroom);
nullfunc = (struct ieee80211_hdr_3addr *) skb_put(skb,
@@ -2414,11 +2446,8 @@ struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw,
skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*hdr) +
ie_ssid_len + ie_len);
- if (!skb) {
- printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
- "request template\n", sdata->name);
+ if (!skb)
return NULL;
- }
skb_reserve(skb, local->hw.extra_tx_headroom);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index ddeb1b998383..7439d26bf5f9 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -19,7 +19,6 @@
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
#include <linux/bitmap.h>
-#include <linux/crc32.h>
#include <net/net_namespace.h>
#include <net/cfg80211.h>
#include <net/rtnetlink.h>
@@ -368,14 +367,14 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
}
-int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
- struct sk_buff_head *skbs,
- void (*fn)(void *data), void *data)
+void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
+ struct sk_buff_head *skbs,
+ void (*fn)(void *data), void *data)
{
struct ieee80211_hw *hw = &local->hw;
struct sk_buff *skb;
unsigned long flags;
- int queue, ret = 0, i;
+ int queue, i;
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
for (i = 0; i < hw->queues; i++)
@@ -390,7 +389,6 @@ int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
continue;
}
- ret++;
queue = skb_get_queue_mapping(skb);
__skb_queue_tail(&local->pending[queue], skb);
}
@@ -402,14 +400,12 @@ int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
__ieee80211_wake_queue(hw, i,
IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
-
- return ret;
}
-int ieee80211_add_pending_skbs(struct ieee80211_local *local,
- struct sk_buff_head *skbs)
+void ieee80211_add_pending_skbs(struct ieee80211_local *local,
+ struct sk_buff_head *skbs)
{
- return ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
+ ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
}
void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
@@ -573,172 +569,6 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
ieee802_11_parse_elems_crc(start, len, elems, 0, 0);
}
-u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
- struct ieee802_11_elems *elems,
- u64 filter, u32 crc)
-{
- size_t left = len;
- u8 *pos = start;
- bool calc_crc = filter != 0;
-
- memset(elems, 0, sizeof(*elems));
- elems->ie_start = start;
- elems->total_len = len;
-
- while (left >= 2) {
- u8 id, elen;
-
- id = *pos++;
- elen = *pos++;
- left -= 2;
-
- if (elen > left)
- break;
-
- if (calc_crc && id < 64 && (filter & (1ULL << id)))
- crc = crc32_be(crc, pos - 2, elen + 2);
-
- switch (id) {
- case WLAN_EID_SSID:
- elems->ssid = pos;
- elems->ssid_len = elen;
- break;
- case WLAN_EID_SUPP_RATES:
- elems->supp_rates = pos;
- elems->supp_rates_len = elen;
- break;
- case WLAN_EID_FH_PARAMS:
- elems->fh_params = pos;
- elems->fh_params_len = elen;
- break;
- case WLAN_EID_DS_PARAMS:
- elems->ds_params = pos;
- elems->ds_params_len = elen;
- break;
- case WLAN_EID_CF_PARAMS:
- elems->cf_params = pos;
- elems->cf_params_len = elen;
- break;
- case WLAN_EID_TIM:
- if (elen >= sizeof(struct ieee80211_tim_ie)) {
- elems->tim = (void *)pos;
- elems->tim_len = elen;
- }
- break;
- case WLAN_EID_IBSS_PARAMS:
- elems->ibss_params = pos;
- elems->ibss_params_len = elen;
- break;
- case WLAN_EID_CHALLENGE:
- elems->challenge = pos;
- elems->challenge_len = elen;
- break;
- case WLAN_EID_VENDOR_SPECIFIC:
- if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
- pos[2] == 0xf2) {
- /* Microsoft OUI (00:50:F2) */
-
- if (calc_crc)
- crc = crc32_be(crc, pos - 2, elen + 2);
-
- if (pos[3] == 1) {
- /* OUI Type 1 - WPA IE */
- elems->wpa = pos;
- elems->wpa_len = elen;
- } else if (elen >= 5 && pos[3] == 2) {
- /* OUI Type 2 - WMM IE */
- if (pos[4] == 0) {
- elems->wmm_info = pos;
- elems->wmm_info_len = elen;
- } else if (pos[4] == 1) {
- elems->wmm_param = pos;
- elems->wmm_param_len = elen;
- }
- }
- }
- break;
- case WLAN_EID_RSN:
- elems->rsn = pos;
- elems->rsn_len = elen;
- break;
- case WLAN_EID_ERP_INFO:
- elems->erp_info = pos;
- elems->erp_info_len = elen;
- break;
- case WLAN_EID_EXT_SUPP_RATES:
- elems->ext_supp_rates = pos;
- elems->ext_supp_rates_len = elen;
- break;
- case WLAN_EID_HT_CAPABILITY:
- if (elen >= sizeof(struct ieee80211_ht_cap))
- elems->ht_cap_elem = (void *)pos;
- break;
- case WLAN_EID_HT_INFORMATION:
- if (elen >= sizeof(struct ieee80211_ht_info))
- elems->ht_info_elem = (void *)pos;
- break;
- case WLAN_EID_MESH_ID:
- elems->mesh_id = pos;
- elems->mesh_id_len = elen;
- break;
- case WLAN_EID_MESH_CONFIG:
- if (elen >= sizeof(struct ieee80211_meshconf_ie))
- elems->mesh_config = (void *)pos;
- break;
- case WLAN_EID_PEER_LINK:
- elems->peer_link = pos;
- elems->peer_link_len = elen;
- break;
- case WLAN_EID_PREQ:
- elems->preq = pos;
- elems->preq_len = elen;
- break;
- case WLAN_EID_PREP:
- elems->prep = pos;
- elems->prep_len = elen;
- break;
- case WLAN_EID_PERR:
- elems->perr = pos;
- elems->perr_len = elen;
- break;
- case WLAN_EID_RANN:
- if (elen >= sizeof(struct ieee80211_rann_ie))
- elems->rann = (void *)pos;
- break;
- case WLAN_EID_CHANNEL_SWITCH:
- elems->ch_switch_elem = pos;
- elems->ch_switch_elem_len = elen;
- break;
- case WLAN_EID_QUIET:
- if (!elems->quiet_elem) {
- elems->quiet_elem = pos;
- elems->quiet_elem_len = elen;
- }
- elems->num_of_quiet_elem++;
- break;
- case WLAN_EID_COUNTRY:
- elems->country_elem = pos;
- elems->country_elem_len = elen;
- break;
- case WLAN_EID_PWR_CONSTRAINT:
- elems->pwr_constr_elem = pos;
- elems->pwr_constr_elem_len = elen;
- break;
- case WLAN_EID_TIMEOUT_INTERVAL:
- elems->timeout_int = pos;
- elems->timeout_int_len = elen;
- break;
- default:
- break;
- }
-
- left -= elen;
- pos += elen;
- }
-
- return crc;
-}
-
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
@@ -799,8 +629,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
qparam.uapsd = false;
- local->tx_conf[queue] = qparam;
- drv_conf_tx(local, queue, &qparam);
+ sdata->tx_conf[queue] = qparam;
+ drv_conf_tx(local, sdata, queue, &qparam);
}
/* after reinitialize QoS TX queues setting to default,
@@ -874,11 +704,9 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
skb = dev_alloc_skb(local->hw.extra_tx_headroom +
sizeof(*mgmt) + 6 + extra_len);
- if (!skb) {
- printk(KERN_DEBUG "%s: failed to allocate buffer for auth "
- "frame\n", sdata->name);
+ if (!skb)
return;
- }
+
skb_reserve(skb, local->hw.extra_tx_headroom);
mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6);
@@ -1031,11 +859,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
/* FIXME: come up with a proper value */
buf = kmalloc(200 + ie_len, GFP_KERNEL);
- if (!buf) {
- printk(KERN_DEBUG "%s: failed to allocate temporary IE "
- "buffer\n", sdata->name);
+ if (!buf)
return NULL;
- }
/*
* Do not send DS Channel parameter for directed probe requests
@@ -1071,14 +896,18 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
const u8 *ssid, size_t ssid_len,
const u8 *ie, size_t ie_len,
- u32 ratemask, bool directed)
+ u32 ratemask, bool directed, bool no_cck)
{
struct sk_buff *skb;
skb = ieee80211_build_probe_req(sdata, dst, ratemask, ssid, ssid_len,
ie, ie_len, directed);
- if (skb)
+ if (skb) {
+ if (no_cck)
+ IEEE80211_SKB_CB(skb)->flags |=
+ IEEE80211_TX_CTL_NO_CCK_RATE;
ieee80211_tx_skb(sdata, skb);
+ }
}
u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
@@ -1205,14 +1034,22 @@ int ieee80211_reconfig(struct ieee80211_local *local)
struct ieee80211_sub_if_data,
u.ap);
+ memset(&sta->sta.drv_priv, 0, hw->sta_data_size);
WARN_ON(drv_sta_add(local, sdata, &sta->sta));
}
}
mutex_unlock(&local->sta_mtx);
/* reconfigure tx conf */
- for (i = 0; i < hw->queues; i++)
- drv_conf_tx(local, i, &local->tx_conf[i]);
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+ sdata->vif.type == NL80211_IFTYPE_MONITOR ||
+ !ieee80211_sdata_running(sdata))
+ continue;
+
+ for (i = 0; i < hw->queues; i++)
+ drv_conf_tx(local, sdata, i, &sdata->tx_conf[i]);
+ }
/* reconfigure hardware */
ieee80211_hw_config(local, ~0);
@@ -1248,6 +1085,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
changed |= BSS_CHANGED_IBSS;
/* fall through */
case NL80211_IFTYPE_AP:
+ changed |= BSS_CHANGED_SSID;
+ /* fall through */
case NL80211_IFTYPE_MESH_POINT:
changed |= BSS_CHANGED_BEACON |
BSS_CHANGED_BEACON_ENABLED;
@@ -1283,7 +1122,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
list_for_each_entry(sta, &local->sta_list, list) {
ieee80211_sta_tear_down_BA_sessions(sta, true);
- clear_sta_flags(sta, WLAN_STA_BLOCK_BA);
+ clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
}
mutex_unlock(&local->sta_mtx);
@@ -1522,3 +1361,60 @@ void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif)
_ieee80211_enable_rssi_reports(sdata, 0, 0);
}
EXPORT_SYMBOL(ieee80211_disable_rssi_reports);
+
+int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_supported_band *sband;
+ int rate;
+ u8 i, rates, *pos;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ rates = sband->n_bitrates;
+ if (rates > 8)
+ rates = 8;
+
+ if (skb_tailroom(skb) < rates + 2)
+ return -ENOMEM;
+
+ pos = skb_put(skb, rates + 2);
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos++ = rates;
+ for (i = 0; i < rates; i++) {
+ rate = sband->bitrates[i].bitrate;
+ *pos++ = (u8) (rate / 5);
+ }
+
+ return 0;
+}
+
+int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_supported_band *sband;
+ int rate;
+ u8 i, exrates, *pos;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ exrates = sband->n_bitrates;
+ if (exrates > 8)
+ exrates -= 8;
+ else
+ exrates = 0;
+
+ if (skb_tailroom(skb) < exrates + 2)
+ return -ENOMEM;
+
+ if (exrates) {
+ pos = skb_put(skb, exrates + 2);
+ *pos++ = WLAN_EID_EXT_SUPP_RATES;
+ *pos++ = exrates;
+ for (i = 8; i < sband->n_bitrates; i++) {
+ rate = sband->bitrates[i].bitrate;
+ *pos++ = (u8) (rate / 5);
+ }
+ }
+ return 0;
+}
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 7a49532f14cb..fd52e695c071 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -72,7 +72,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
case NL80211_IFTYPE_AP_VLAN:
sta = rcu_dereference(sdata->u.vlan.sta);
if (sta) {
- qos = get_sta_flags(sta) & WLAN_STA_WME;
+ qos = test_sta_flag(sta, WLAN_STA_WME);
break;
}
case NL80211_IFTYPE_AP:
@@ -83,11 +83,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
break;
#ifdef CONFIG_MAC80211_MESH
case NL80211_IFTYPE_MESH_POINT:
- /*
- * XXX: This is clearly broken ... but already was before,
- * because ieee80211_fill_mesh_addresses() would clear A1
- * except for multicast addresses.
- */
+ ra = skb->data;
break;
#endif
case NL80211_IFTYPE_STATION:
@@ -103,7 +99,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
if (!sta && ra && !is_multicast_ether_addr(ra)) {
sta = sta_info_get(sdata, ra);
if (sta)
- qos = get_sta_flags(sta) & WLAN_STA_WME;
+ qos = test_sta_flag(sta, WLAN_STA_WME);
}
rcu_read_unlock();
@@ -139,7 +135,8 @@ u16 ieee80211_downgrade_queue(struct ieee80211_local *local,
return ieee802_1d_to_ac[skb->priority];
}
-void ieee80211_set_qos_hdr(struct ieee80211_local *local, struct sk_buff *skb)
+void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (void *)skb->data;
@@ -150,10 +147,11 @@ void ieee80211_set_qos_hdr(struct ieee80211_local *local, struct sk_buff *skb)
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
- if (unlikely(local->wifi_wme_noack_test))
+ if (unlikely(sdata->local->wifi_wme_noack_test))
ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK;
- /* qos header is 2 bytes, second reserved */
+ /* qos header is 2 bytes */
*p++ = ack_policy | tid;
- *p = 0;
+ *p = ieee80211_vif_is_mesh(&sdata->vif) ?
+ (IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT >> 8) : 0;
}
}
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h
index faead6d02026..34e166fbf4d4 100644
--- a/net/mac80211/wme.h
+++ b/net/mac80211/wme.h
@@ -17,7 +17,8 @@ extern const int ieee802_1d_to_ac[8];
u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
-void ieee80211_set_qos_hdr(struct ieee80211_local *local, struct sk_buff *skb);
+void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb);
u16 ieee80211_downgrade_queue(struct ieee80211_local *local,
struct sk_buff *skb);
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index 380b9a7462b6..94472eb34d76 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -229,11 +229,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
wk->ie_len + /* extra IEs */
9, /* WMM */
GFP_KERNEL);
- if (!skb) {
- printk(KERN_DEBUG "%s: failed to allocate buffer for assoc "
- "frame\n", sdata->name);
+ if (!skb)
return;
- }
+
skb_reserve(skb, local->hw.extra_tx_headroom);
capab = WLAN_CAPABILITY_ESS;
@@ -460,7 +458,7 @@ ieee80211_direct_probe(struct ieee80211_work *wk)
*/
ieee80211_send_probe_req(sdata, NULL, wk->probe_auth.ssid,
wk->probe_auth.ssid_len, NULL, 0,
- (u32) -1, true);
+ (u32) -1, true, false);
wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
run_again(local, wk->timeout);
@@ -579,7 +577,7 @@ ieee80211_offchannel_tx(struct ieee80211_work *wk)
/*
* After this, offchan_tx.frame remains but now is no
* longer a valid pointer -- we still need it as the
- * cookie for canceling this work.
+ * cookie for canceling this work/status matching.
*/
ieee80211_tx_skb(wk->sdata, wk->offchan_tx.frame);
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 7bc8702808fa..f614ce7bb6e3 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -53,7 +53,8 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
}
if (info->control.hw_key &&
- !(tx->flags & IEEE80211_TX_FRAGMENTED) &&
+ (info->flags & IEEE80211_TX_CTL_DONTFRAG ||
+ tx->local->ops->set_frag_threshold) &&
!(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) {
/* hwaccel - with no need for SW-generated MMIC */
return TX_CONTINUE;
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 32bff6d86cb2..8260b13d93c9 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -505,7 +505,7 @@ config NETFILTER_XT_TARGET_LED
echo netfilter-ssh > /sys/class/leds/<ledname>/trigger
For more information on the LEDs available on your system, see
- Documentation/leds-class.txt
+ Documentation/leds/leds-class.txt
config NETFILTER_XT_TARGET_MARK
tristate '"MARK" target support'
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 899b71c0ff5d..3346829ea07f 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -37,7 +37,7 @@ int nf_register_afinfo(const struct nf_afinfo *afinfo)
err = mutex_lock_interruptible(&afinfo_mutex);
if (err < 0)
return err;
- rcu_assign_pointer(nf_afinfo[afinfo->family], afinfo);
+ RCU_INIT_POINTER(nf_afinfo[afinfo->family], afinfo);
mutex_unlock(&afinfo_mutex);
return 0;
}
@@ -46,7 +46,7 @@ EXPORT_SYMBOL_GPL(nf_register_afinfo);
void nf_unregister_afinfo(const struct nf_afinfo *afinfo)
{
mutex_lock(&afinfo_mutex);
- rcu_assign_pointer(nf_afinfo[afinfo->family], NULL);
+ RCU_INIT_POINTER(nf_afinfo[afinfo->family], NULL);
mutex_unlock(&afinfo_mutex);
synchronize_rcu();
}
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 2b771dc708a3..e3be48bf4dcd 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -2283,6 +2283,7 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
struct ip_vs_service *svc;
struct ip_vs_dest_user *udest_compat;
struct ip_vs_dest_user_kern udest;
+ struct netns_ipvs *ipvs = net_ipvs(net);
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -2303,6 +2304,24 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
/* increase the module use count */
ip_vs_use_count_inc();
+ /* Handle daemons since they have another lock */
+ if (cmd == IP_VS_SO_SET_STARTDAEMON ||
+ cmd == IP_VS_SO_SET_STOPDAEMON) {
+ struct ip_vs_daemon_user *dm = (struct ip_vs_daemon_user *)arg;
+
+ if (mutex_lock_interruptible(&ipvs->sync_mutex)) {
+ ret = -ERESTARTSYS;
+ goto out_dec;
+ }
+ if (cmd == IP_VS_SO_SET_STARTDAEMON)
+ ret = start_sync_thread(net, dm->state, dm->mcast_ifn,
+ dm->syncid);
+ else
+ ret = stop_sync_thread(net, dm->state);
+ mutex_unlock(&ipvs->sync_mutex);
+ goto out_dec;
+ }
+
if (mutex_lock_interruptible(&__ip_vs_mutex)) {
ret = -ERESTARTSYS;
goto out_dec;
@@ -2316,15 +2335,6 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
/* Set timeout values for (tcp tcpfin udp) */
ret = ip_vs_set_timeout(net, (struct ip_vs_timeout_user *)arg);
goto out_unlock;
- } else if (cmd == IP_VS_SO_SET_STARTDAEMON) {
- struct ip_vs_daemon_user *dm = (struct ip_vs_daemon_user *)arg;
- ret = start_sync_thread(net, dm->state, dm->mcast_ifn,
- dm->syncid);
- goto out_unlock;
- } else if (cmd == IP_VS_SO_SET_STOPDAEMON) {
- struct ip_vs_daemon_user *dm = (struct ip_vs_daemon_user *)arg;
- ret = stop_sync_thread(net, dm->state);
- goto out_unlock;
}
usvc_compat = (struct ip_vs_service_user *)arg;
@@ -2584,6 +2594,33 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
if (copy_from_user(arg, user, copylen) != 0)
return -EFAULT;
+ /*
+ * Handle daemons first since it has its own locking
+ */
+ if (cmd == IP_VS_SO_GET_DAEMON) {
+ struct ip_vs_daemon_user d[2];
+
+ memset(&d, 0, sizeof(d));
+ if (mutex_lock_interruptible(&ipvs->sync_mutex))
+ return -ERESTARTSYS;
+
+ if (ipvs->sync_state & IP_VS_STATE_MASTER) {
+ d[0].state = IP_VS_STATE_MASTER;
+ strlcpy(d[0].mcast_ifn, ipvs->master_mcast_ifn,
+ sizeof(d[0].mcast_ifn));
+ d[0].syncid = ipvs->master_syncid;
+ }
+ if (ipvs->sync_state & IP_VS_STATE_BACKUP) {
+ d[1].state = IP_VS_STATE_BACKUP;
+ strlcpy(d[1].mcast_ifn, ipvs->backup_mcast_ifn,
+ sizeof(d[1].mcast_ifn));
+ d[1].syncid = ipvs->backup_syncid;
+ }
+ if (copy_to_user(user, &d, sizeof(d)) != 0)
+ ret = -EFAULT;
+ mutex_unlock(&ipvs->sync_mutex);
+ return ret;
+ }
if (mutex_lock_interruptible(&__ip_vs_mutex))
return -ERESTARTSYS;
@@ -2681,28 +2718,6 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
}
break;
- case IP_VS_SO_GET_DAEMON:
- {
- struct ip_vs_daemon_user d[2];
-
- memset(&d, 0, sizeof(d));
- if (ipvs->sync_state & IP_VS_STATE_MASTER) {
- d[0].state = IP_VS_STATE_MASTER;
- strlcpy(d[0].mcast_ifn, ipvs->master_mcast_ifn,
- sizeof(d[0].mcast_ifn));
- d[0].syncid = ipvs->master_syncid;
- }
- if (ipvs->sync_state & IP_VS_STATE_BACKUP) {
- d[1].state = IP_VS_STATE_BACKUP;
- strlcpy(d[1].mcast_ifn, ipvs->backup_mcast_ifn,
- sizeof(d[1].mcast_ifn));
- d[1].syncid = ipvs->backup_syncid;
- }
- if (copy_to_user(user, &d, sizeof(d)) != 0)
- ret = -EFAULT;
- }
- break;
-
default:
ret = -EINVAL;
}
@@ -3205,7 +3220,7 @@ static int ip_vs_genl_dump_daemons(struct sk_buff *skb,
struct net *net = skb_sknet(skb);
struct netns_ipvs *ipvs = net_ipvs(net);
- mutex_lock(&__ip_vs_mutex);
+ mutex_lock(&ipvs->sync_mutex);
if ((ipvs->sync_state & IP_VS_STATE_MASTER) && !cb->args[0]) {
if (ip_vs_genl_dump_daemon(skb, IP_VS_STATE_MASTER,
ipvs->master_mcast_ifn,
@@ -3225,7 +3240,7 @@ static int ip_vs_genl_dump_daemons(struct sk_buff *skb,
}
nla_put_failure:
- mutex_unlock(&__ip_vs_mutex);
+ mutex_unlock(&ipvs->sync_mutex);
return skb->len;
}
@@ -3271,13 +3286,9 @@ static int ip_vs_genl_set_config(struct net *net, struct nlattr **attrs)
return ip_vs_set_timeout(net, &t);
}
-static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
+static int ip_vs_genl_set_daemon(struct sk_buff *skb, struct genl_info *info)
{
- struct ip_vs_service *svc = NULL;
- struct ip_vs_service_user_kern usvc;
- struct ip_vs_dest_user_kern udest;
int ret = 0, cmd;
- int need_full_svc = 0, need_full_dest = 0;
struct net *net;
struct netns_ipvs *ipvs;
@@ -3285,19 +3296,10 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
ipvs = net_ipvs(net);
cmd = info->genlhdr->cmd;
- mutex_lock(&__ip_vs_mutex);
-
- if (cmd == IPVS_CMD_FLUSH) {
- ret = ip_vs_flush(net);
- goto out;
- } else if (cmd == IPVS_CMD_SET_CONFIG) {
- ret = ip_vs_genl_set_config(net, info->attrs);
- goto out;
- } else if (cmd == IPVS_CMD_NEW_DAEMON ||
- cmd == IPVS_CMD_DEL_DAEMON) {
-
+ if (cmd == IPVS_CMD_NEW_DAEMON || cmd == IPVS_CMD_DEL_DAEMON) {
struct nlattr *daemon_attrs[IPVS_DAEMON_ATTR_MAX + 1];
+ mutex_lock(&ipvs->sync_mutex);
if (!info->attrs[IPVS_CMD_ATTR_DAEMON] ||
nla_parse_nested(daemon_attrs, IPVS_DAEMON_ATTR_MAX,
info->attrs[IPVS_CMD_ATTR_DAEMON],
@@ -3310,6 +3312,33 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
ret = ip_vs_genl_new_daemon(net, daemon_attrs);
else
ret = ip_vs_genl_del_daemon(net, daemon_attrs);
+out:
+ mutex_unlock(&ipvs->sync_mutex);
+ }
+ return ret;
+}
+
+static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
+{
+ struct ip_vs_service *svc = NULL;
+ struct ip_vs_service_user_kern usvc;
+ struct ip_vs_dest_user_kern udest;
+ int ret = 0, cmd;
+ int need_full_svc = 0, need_full_dest = 0;
+ struct net *net;
+ struct netns_ipvs *ipvs;
+
+ net = skb_sknet(skb);
+ ipvs = net_ipvs(net);
+ cmd = info->genlhdr->cmd;
+
+ mutex_lock(&__ip_vs_mutex);
+
+ if (cmd == IPVS_CMD_FLUSH) {
+ ret = ip_vs_flush(net);
+ goto out;
+ } else if (cmd == IPVS_CMD_SET_CONFIG) {
+ ret = ip_vs_genl_set_config(net, info->attrs);
goto out;
} else if (cmd == IPVS_CMD_ZERO &&
!info->attrs[IPVS_CMD_ATTR_SERVICE]) {
@@ -3536,13 +3565,13 @@ static struct genl_ops ip_vs_genl_ops[] __read_mostly = {
.cmd = IPVS_CMD_NEW_DAEMON,
.flags = GENL_ADMIN_PERM,
.policy = ip_vs_cmd_policy,
- .doit = ip_vs_genl_set_cmd,
+ .doit = ip_vs_genl_set_daemon,
},
{
.cmd = IPVS_CMD_DEL_DAEMON,
.flags = GENL_ADMIN_PERM,
.policy = ip_vs_cmd_policy,
- .doit = ip_vs_genl_set_cmd,
+ .doit = ip_vs_genl_set_daemon,
},
{
.cmd = IPVS_CMD_GET_DAEMON,
@@ -3679,7 +3708,7 @@ int __net_init ip_vs_control_net_init(struct net *net)
int idx;
struct netns_ipvs *ipvs = net_ipvs(net);
- ipvs->rs_lock = __RW_LOCK_UNLOCKED(ipvs->rs_lock);
+ rwlock_init(&ipvs->rs_lock);
/* Initialize rs_table */
for (idx = 0; idx < IP_VS_RTAB_SIZE; idx++)
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c
index 7ee7215b8ba0..3cdd479f9b5d 100644
--- a/net/netfilter/ipvs/ip_vs_sync.c
+++ b/net/netfilter/ipvs/ip_vs_sync.c
@@ -61,6 +61,7 @@
#define SYNC_PROTO_VER 1 /* Protocol version in header */
+static struct lock_class_key __ipvs_sync_key;
/*
* IPVS sync connection entry
* Version 0, i.e. original version.
@@ -1545,6 +1546,7 @@ int start_sync_thread(struct net *net, int state, char *mcast_ifn, __u8 syncid)
IP_VS_DBG(7, "Each ip_vs_sync_conn entry needs %Zd bytes\n",
sizeof(struct ip_vs_sync_conn_v0));
+
if (state == IP_VS_STATE_MASTER) {
if (ipvs->master_thread)
return -EEXIST;
@@ -1667,6 +1669,7 @@ int __net_init ip_vs_sync_net_init(struct net *net)
{
struct netns_ipvs *ipvs = net_ipvs(net);
+ __mutex_init(&ipvs->sync_mutex, "ipvs->sync_mutex", &__ipvs_sync_key);
INIT_LIST_HEAD(&ipvs->sync_queue);
spin_lock_init(&ipvs->sync_lock);
spin_lock_init(&ipvs->sync_buff_lock);
@@ -1680,7 +1683,9 @@ int __net_init ip_vs_sync_net_init(struct net *net)
void ip_vs_sync_net_cleanup(struct net *net)
{
int retc;
+ struct netns_ipvs *ipvs = net_ipvs(net);
+ mutex_lock(&ipvs->sync_mutex);
retc = stop_sync_thread(net, IP_VS_STATE_MASTER);
if (retc && retc != -ESRCH)
pr_err("Failed to stop Master Daemon\n");
@@ -1688,4 +1693,5 @@ void ip_vs_sync_net_cleanup(struct net *net)
retc = stop_sync_thread(net, IP_VS_STATE_BACKUP);
if (retc && retc != -ESRCH)
pr_err("Failed to stop Backup Daemon\n");
+ mutex_unlock(&ipvs->sync_mutex);
}
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index f7af8b866017..5acfaf59a9c3 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -779,7 +779,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
if (exp->helper) {
help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
if (help)
- rcu_assign_pointer(help->helper, exp->helper);
+ RCU_INIT_POINTER(help->helper, exp->helper);
}
#ifdef CONFIG_NF_CONNTRACK_MARK
@@ -1317,7 +1317,7 @@ static void nf_conntrack_cleanup_net(struct net *net)
void nf_conntrack_cleanup(struct net *net)
{
if (net_eq(net, &init_net))
- rcu_assign_pointer(ip_ct_attach, NULL);
+ RCU_INIT_POINTER(ip_ct_attach, NULL);
/* This makes sure all current packets have passed through
netfilter framework. Roll on, two-stage module
@@ -1327,7 +1327,7 @@ void nf_conntrack_cleanup(struct net *net)
nf_conntrack_cleanup_net(net);
if (net_eq(net, &init_net)) {
- rcu_assign_pointer(nf_ct_destroy, NULL);
+ RCU_INIT_POINTER(nf_ct_destroy, NULL);
nf_conntrack_cleanup_init_net();
}
}
@@ -1576,11 +1576,11 @@ int nf_conntrack_init(struct net *net)
if (net_eq(net, &init_net)) {
/* For use by REJECT target */
- rcu_assign_pointer(ip_ct_attach, nf_conntrack_attach);
- rcu_assign_pointer(nf_ct_destroy, destroy_conntrack);
+ RCU_INIT_POINTER(ip_ct_attach, nf_conntrack_attach);
+ RCU_INIT_POINTER(nf_ct_destroy, destroy_conntrack);
/* Howto get NAT offsets */
- rcu_assign_pointer(nf_ct_nat_offset, NULL);
+ RCU_INIT_POINTER(nf_ct_nat_offset, NULL);
}
return 0;
diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c
index 63a1b915a7e4..3add99439059 100644
--- a/net/netfilter/nf_conntrack_ecache.c
+++ b/net/netfilter/nf_conntrack_ecache.c
@@ -94,7 +94,7 @@ int nf_conntrack_register_notifier(struct nf_ct_event_notifier *new)
ret = -EBUSY;
goto out_unlock;
}
- rcu_assign_pointer(nf_conntrack_event_cb, new);
+ RCU_INIT_POINTER(nf_conntrack_event_cb, new);
mutex_unlock(&nf_ct_ecache_mutex);
return ret;
@@ -112,7 +112,7 @@ void nf_conntrack_unregister_notifier(struct nf_ct_event_notifier *new)
notify = rcu_dereference_protected(nf_conntrack_event_cb,
lockdep_is_held(&nf_ct_ecache_mutex));
BUG_ON(notify != new);
- rcu_assign_pointer(nf_conntrack_event_cb, NULL);
+ RCU_INIT_POINTER(nf_conntrack_event_cb, NULL);
mutex_unlock(&nf_ct_ecache_mutex);
}
EXPORT_SYMBOL_GPL(nf_conntrack_unregister_notifier);
@@ -129,7 +129,7 @@ int nf_ct_expect_register_notifier(struct nf_exp_event_notifier *new)
ret = -EBUSY;
goto out_unlock;
}
- rcu_assign_pointer(nf_expect_event_cb, new);
+ RCU_INIT_POINTER(nf_expect_event_cb, new);
mutex_unlock(&nf_ct_ecache_mutex);
return ret;
@@ -147,7 +147,7 @@ void nf_ct_expect_unregister_notifier(struct nf_exp_event_notifier *new)
notify = rcu_dereference_protected(nf_expect_event_cb,
lockdep_is_held(&nf_ct_ecache_mutex));
BUG_ON(notify != new);
- rcu_assign_pointer(nf_expect_event_cb, NULL);
+ RCU_INIT_POINTER(nf_expect_event_cb, NULL);
mutex_unlock(&nf_ct_ecache_mutex);
}
EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier);
diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c
index 05ecdc281a53..4605c947dcc4 100644
--- a/net/netfilter/nf_conntrack_extend.c
+++ b/net/netfilter/nf_conntrack_extend.c
@@ -169,7 +169,7 @@ int nf_ct_extend_register(struct nf_ct_ext_type *type)
before updating alloc_size */
type->alloc_size = ALIGN(sizeof(struct nf_ct_ext), type->align)
+ type->len;
- rcu_assign_pointer(nf_ct_ext_types[type->id], type);
+ RCU_INIT_POINTER(nf_ct_ext_types[type->id], type);
update_alloc_size(type);
out:
mutex_unlock(&nf_ct_ext_type_mutex);
@@ -181,7 +181,7 @@ EXPORT_SYMBOL_GPL(nf_ct_extend_register);
void nf_ct_extend_unregister(struct nf_ct_ext_type *type)
{
mutex_lock(&nf_ct_ext_type_mutex);
- rcu_assign_pointer(nf_ct_ext_types[type->id], NULL);
+ RCU_INIT_POINTER(nf_ct_ext_types[type->id], NULL);
update_alloc_size(type);
mutex_unlock(&nf_ct_ext_type_mutex);
rcu_barrier(); /* Wait for completion of call_rcu()'s */
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index 1bdfea357955..93c4bdbfc1ae 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -131,7 +131,7 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
helper = __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
if (helper == NULL) {
if (help)
- rcu_assign_pointer(help->helper, NULL);
+ RCU_INIT_POINTER(help->helper, NULL);
goto out;
}
@@ -145,7 +145,7 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
memset(&help->help, 0, sizeof(help->help));
}
- rcu_assign_pointer(help->helper, helper);
+ RCU_INIT_POINTER(help->helper, helper);
out:
return ret;
}
@@ -162,7 +162,7 @@ static inline int unhelp(struct nf_conntrack_tuple_hash *i,
lockdep_is_held(&nf_conntrack_lock)
) == me) {
nf_conntrack_event(IPCT_HELPER, ct);
- rcu_assign_pointer(help->helper, NULL);
+ RCU_INIT_POINTER(help->helper, NULL);
}
return 0;
}
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 7dec88a1755b..e58aa9b1fe8a 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1125,7 +1125,7 @@ ctnetlink_change_helper(struct nf_conn *ct, const struct nlattr * const cda[])
if (help && help->helper) {
/* we had a helper before ... */
nf_ct_remove_expectations(ct);
- rcu_assign_pointer(help->helper, NULL);
+ RCU_INIT_POINTER(help->helper, NULL);
}
return 0;
@@ -1163,7 +1163,7 @@ ctnetlink_change_helper(struct nf_conn *ct, const struct nlattr * const cda[])
return -EOPNOTSUPP;
}
- rcu_assign_pointer(help->helper, helper);
+ RCU_INIT_POINTER(help->helper, helper);
return 0;
}
@@ -1386,7 +1386,7 @@ ctnetlink_create_conntrack(struct net *net, u16 zone,
}
/* not in hash table yet so not strictly necessary */
- rcu_assign_pointer(help->helper, helper);
+ RCU_INIT_POINTER(help->helper, helper);
}
} else {
/* try an implicit helper assignation */
diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c
index 2fd4565144de..31d56b23b9e9 100644
--- a/net/netfilter/nf_conntrack_pptp.c
+++ b/net/netfilter/nf_conntrack_pptp.c
@@ -364,6 +364,7 @@ pptp_inbound_pkt(struct sk_buff *skb,
break;
case PPTP_WAN_ERROR_NOTIFY:
+ case PPTP_SET_LINK_INFO:
case PPTP_ECHO_REQUEST:
case PPTP_ECHO_REPLY:
/* I don't have to explain these ;) */
diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c
index cf616e55ca41..d69facdd9a7a 100644
--- a/net/netfilter/nf_conntrack_proto_gre.c
+++ b/net/netfilter/nf_conntrack_proto_gre.c
@@ -241,8 +241,8 @@ static int gre_packet(struct nf_conn *ct,
nf_ct_refresh_acct(ct, ctinfo, skb,
ct->proto.gre.stream_timeout);
/* Also, more likely to be important, and not a probe. */
- set_bit(IPS_ASSURED_BIT, &ct->status);
- nf_conntrack_event_cache(IPCT_ASSURED, ct);
+ 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,
ct->proto.gre.timeout);
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index 37bf94394be0..8235b86b4e87 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -409,7 +409,7 @@ static void tcp_options(const struct sk_buff *skb,
if (opsize < 2) /* "silly options" */
return;
if (opsize > length)
- break; /* don't parse partial options */
+ return; /* don't parse partial options */
if (opcode == TCPOPT_SACK_PERM
&& opsize == TCPOLEN_SACK_PERM)
@@ -447,7 +447,7 @@ static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff,
BUG_ON(ptr == NULL);
/* Fast path for timestamp-only option */
- if (length == TCPOLEN_TSTAMP_ALIGNED*4
+ if (length == TCPOLEN_TSTAMP_ALIGNED
&& *(__be32 *)ptr == htonl((TCPOPT_NOP << 24)
| (TCPOPT_NOP << 16)
| (TCPOPT_TIMESTAMP << 8)
@@ -469,7 +469,7 @@ static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff,
if (opsize < 2) /* "silly options" */
return;
if (opsize > length)
- break; /* don't parse partial options */
+ return; /* don't parse partial options */
if (opcode == TCPOPT_SACK
&& opsize >= (TCPOLEN_SACK_BASE
diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c
index 20714edf6cd2..ce0c406f58a8 100644
--- a/net/netfilter/nf_log.c
+++ b/net/netfilter/nf_log.c
@@ -55,7 +55,7 @@ int nf_log_register(u_int8_t pf, struct nf_logger *logger)
llog = rcu_dereference_protected(nf_loggers[pf],
lockdep_is_held(&nf_log_mutex));
if (llog == NULL)
- rcu_assign_pointer(nf_loggers[pf], logger);
+ RCU_INIT_POINTER(nf_loggers[pf], logger);
}
mutex_unlock(&nf_log_mutex);
@@ -74,7 +74,7 @@ void nf_log_unregister(struct nf_logger *logger)
c_logger = rcu_dereference_protected(nf_loggers[i],
lockdep_is_held(&nf_log_mutex));
if (c_logger == logger)
- rcu_assign_pointer(nf_loggers[i], NULL);
+ RCU_INIT_POINTER(nf_loggers[i], NULL);
list_del(&logger->list[i]);
}
mutex_unlock(&nf_log_mutex);
@@ -92,7 +92,7 @@ int nf_log_bind_pf(u_int8_t pf, const struct nf_logger *logger)
mutex_unlock(&nf_log_mutex);
return -ENOENT;
}
- rcu_assign_pointer(nf_loggers[pf], logger);
+ RCU_INIT_POINTER(nf_loggers[pf], logger);
mutex_unlock(&nf_log_mutex);
return 0;
}
@@ -103,7 +103,7 @@ void nf_log_unbind_pf(u_int8_t pf)
if (pf >= ARRAY_SIZE(nf_loggers))
return;
mutex_lock(&nf_log_mutex);
- rcu_assign_pointer(nf_loggers[pf], NULL);
+ RCU_INIT_POINTER(nf_loggers[pf], NULL);
mutex_unlock(&nf_log_mutex);
}
EXPORT_SYMBOL(nf_log_unbind_pf);
@@ -250,7 +250,7 @@ static int nf_log_proc_dostring(ctl_table *table, int write,
mutex_unlock(&nf_log_mutex);
return -ENOENT;
}
- rcu_assign_pointer(nf_loggers[tindex], logger);
+ RCU_INIT_POINTER(nf_loggers[tindex], logger);
mutex_unlock(&nf_log_mutex);
} else {
mutex_lock(&nf_log_mutex);
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index 84d0fd47636a..99ffd2885088 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -40,7 +40,7 @@ int nf_register_queue_handler(u_int8_t pf, const struct nf_queue_handler *qh)
else if (old)
ret = -EBUSY;
else {
- rcu_assign_pointer(queue_handler[pf], qh);
+ RCU_INIT_POINTER(queue_handler[pf], qh);
ret = 0;
}
mutex_unlock(&queue_handler_mutex);
@@ -65,7 +65,7 @@ int nf_unregister_queue_handler(u_int8_t pf, const struct nf_queue_handler *qh)
return -EINVAL;
}
- rcu_assign_pointer(queue_handler[pf], NULL);
+ RCU_INIT_POINTER(queue_handler[pf], NULL);
mutex_unlock(&queue_handler_mutex);
synchronize_rcu();
@@ -84,7 +84,7 @@ void nf_unregister_queue_handlers(const struct nf_queue_handler *qh)
queue_handler[pf],
lockdep_is_held(&queue_handler_mutex)
) == qh)
- rcu_assign_pointer(queue_handler[pf], NULL);
+ RCU_INIT_POINTER(queue_handler[pf], NULL);
}
mutex_unlock(&queue_handler_mutex);
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index 1905976b5135..c879c1a2370e 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -59,7 +59,7 @@ int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n)
nfnl_unlock();
return -EBUSY;
}
- rcu_assign_pointer(subsys_table[n->subsys_id], n);
+ RCU_INIT_POINTER(subsys_table[n->subsys_id], n);
nfnl_unlock();
return 0;
@@ -210,7 +210,7 @@ static int __net_init nfnetlink_net_init(struct net *net)
if (!nfnl)
return -ENOMEM;
net->nfnl_stash = nfnl;
- rcu_assign_pointer(net->nfnl, nfnl);
+ RCU_INIT_POINTER(net->nfnl, nfnl);
return 0;
}
@@ -219,7 +219,7 @@ static void __net_exit nfnetlink_net_exit_batch(struct list_head *net_exit_list)
struct net *net;
list_for_each_entry(net, net_exit_list, exit_list)
- rcu_assign_pointer(net->nfnl, NULL);
+ RCU_INIT_POINTER(net->nfnl, NULL);
synchronize_net();
list_for_each_entry(net, net_exit_list, exit_list)
netlink_kernel_release(net->nfnl_stash);
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 00bd475eab4b..a80b0cb03f17 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -646,8 +646,8 @@ verdicthdr_get(const struct nlattr * const nfqa[])
return NULL;
vhdr = nla_data(nfqa[NFQA_VERDICT_HDR]);
- verdict = ntohl(vhdr->verdict);
- if ((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT)
+ verdict = ntohl(vhdr->verdict) & NF_VERDICT_MASK;
+ if (verdict > NF_MAX_VERDICT || verdict == NF_STOLEN)
return NULL;
return vhdr;
}
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index b0869fe3633b..71441b934ffd 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -776,12 +776,11 @@ static int xt_jumpstack_alloc(struct xt_table_info *i)
size = sizeof(void **) * nr_cpu_ids;
if (size > PAGE_SIZE)
- i->jumpstack = vmalloc(size);
+ i->jumpstack = vzalloc(size);
else
- i->jumpstack = kmalloc(size, GFP_KERNEL);
+ i->jumpstack = kzalloc(size, GFP_KERNEL);
if (i->jumpstack == NULL)
return -ENOMEM;
- memset(i->jumpstack, 0, size);
i->stacksize *= xt_jumpstack_multiplier;
size = sizeof(void *) * i->stacksize;
diff --git a/net/netfilter/xt_rateest.c b/net/netfilter/xt_rateest.c
index 76a083184d8e..ed0db15ab00e 100644
--- a/net/netfilter/xt_rateest.c
+++ b/net/netfilter/xt_rateest.c
@@ -78,7 +78,7 @@ static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par)
{
struct xt_rateest_match_info *info = par->matchinfo;
struct xt_rateest *est1, *est2;
- int ret = false;
+ int ret = -EINVAL;
if (hweight32(info->flags & (XT_RATEEST_MATCH_ABS |
XT_RATEEST_MATCH_REL)) != 1)
@@ -101,13 +101,12 @@ static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par)
if (!est1)
goto err1;
+ est2 = NULL;
if (info->flags & XT_RATEEST_MATCH_REL) {
est2 = xt_rateest_lookup(info->name2);
if (!est2)
goto err2;
- } else
- est2 = NULL;
-
+ }
info->est1 = est1;
info->est2 = est2;
@@ -116,7 +115,7 @@ static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par)
err2:
xt_rateest_put(est1);
err1:
- return -EINVAL;
+ return ret;
}
static void xt_rateest_mt_destroy(const struct xt_mtdtor_param *par)
diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c
index 7d8083cde34f..3f905e5370c2 100644
--- a/net/netlabel/netlabel_domainhash.c
+++ b/net/netlabel/netlabel_domainhash.c
@@ -282,7 +282,7 @@ int __init netlbl_domhsh_init(u32 size)
INIT_LIST_HEAD(&hsh_tbl->tbl[iter]);
spin_lock(&netlbl_domhsh_lock);
- rcu_assign_pointer(netlbl_domhsh, hsh_tbl);
+ RCU_INIT_POINTER(netlbl_domhsh, hsh_tbl);
spin_unlock(&netlbl_domhsh_lock);
return 0;
@@ -330,7 +330,7 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
&rcu_dereference(netlbl_domhsh)->tbl[bkt]);
} else {
INIT_LIST_HEAD(&entry->list);
- rcu_assign_pointer(netlbl_domhsh_def, entry);
+ RCU_INIT_POINTER(netlbl_domhsh_def, entry);
}
if (entry->type == NETLBL_NLTYPE_ADDRSELECT) {
@@ -451,7 +451,7 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
if (entry != rcu_dereference(netlbl_domhsh_def))
list_del_rcu(&entry->list);
else
- rcu_assign_pointer(netlbl_domhsh_def, NULL);
+ RCU_INIT_POINTER(netlbl_domhsh_def, NULL);
} else
ret_val = -ENOENT;
spin_unlock(&netlbl_domhsh_lock);
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index e6e823656f9d..e251c2c88521 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -354,7 +354,7 @@ static struct netlbl_unlhsh_iface *netlbl_unlhsh_add_iface(int ifindex)
INIT_LIST_HEAD(&iface->list);
if (netlbl_unlhsh_rcu_deref(netlbl_unlhsh_def) != NULL)
goto add_iface_failure;
- rcu_assign_pointer(netlbl_unlhsh_def, iface);
+ RCU_INIT_POINTER(netlbl_unlhsh_def, iface);
}
spin_unlock(&netlbl_unlhsh_lock);
@@ -621,7 +621,7 @@ static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface)
if (iface->ifindex > 0)
list_del_rcu(&iface->list);
else
- rcu_assign_pointer(netlbl_unlhsh_def, NULL);
+ RCU_INIT_POINTER(netlbl_unlhsh_def, NULL);
spin_unlock(&netlbl_unlhsh_lock);
call_rcu(&iface->rcu, netlbl_unlhsh_free_iface);
@@ -1449,7 +1449,7 @@ int __init netlbl_unlabel_init(u32 size)
rcu_read_lock();
spin_lock(&netlbl_unlhsh_lock);
- rcu_assign_pointer(netlbl_unlhsh, hsh_tbl);
+ RCU_INIT_POINTER(netlbl_unlhsh, hsh_tbl);
spin_unlock(&netlbl_unlhsh_lock);
rcu_read_unlock();
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 0a4db0211da0..1201b6d4183d 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1324,10 +1324,9 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
if (msg->msg_flags&MSG_OOB)
return -EOPNOTSUPP;
- if (NULL == siocb->scm) {
+ if (NULL == siocb->scm)
siocb->scm = &scm;
- memset(&scm, 0, sizeof(scm));
- }
+
err = scm_send(sock, msg, siocb->scm);
if (err < 0)
return err;
@@ -1578,7 +1577,7 @@ int __netlink_change_ngroups(struct sock *sk, unsigned int groups)
new = kzalloc(sizeof(*new) + NLGRPSZ(groups), GFP_ATOMIC);
if (!new)
return -ENOMEM;
- old = rcu_dereference_raw(tbl->listeners);
+ old = rcu_dereference_protected(tbl->listeners, 1);
memcpy(new->masks, old->masks, NLGRPSZ(tbl->groups));
rcu_assign_pointer(tbl->listeners, new);
diff --git a/net/nfc/Kconfig b/net/nfc/Kconfig
index 33e095b124b3..58cddadf8e8e 100644
--- a/net/nfc/Kconfig
+++ b/net/nfc/Kconfig
@@ -13,4 +13,6 @@ menuconfig NFC
To compile this support as a module, choose M here: the module will
be called nfc.
+source "net/nfc/nci/Kconfig"
+
source "drivers/nfc/Kconfig"
diff --git a/net/nfc/Makefile b/net/nfc/Makefile
index 16250c353851..fbb550f2377b 100644
--- a/net/nfc/Makefile
+++ b/net/nfc/Makefile
@@ -3,5 +3,6 @@
#
obj-$(CONFIG_NFC) += nfc.o
+obj-$(CONFIG_NFC_NCI) += nci/
nfc-objs := core.o netlink.o af_nfc.o rawsock.o
diff --git a/net/nfc/core.c b/net/nfc/core.c
index b6fd4e1f2057..47e02c1b8c02 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -53,6 +53,80 @@ int nfc_printk(const char *level, const char *format, ...)
EXPORT_SYMBOL(nfc_printk);
/**
+ * nfc_dev_up - turn on the NFC device
+ *
+ * @dev: The nfc device to be turned on
+ *
+ * The device remains up until the nfc_dev_down function is called.
+ */
+int nfc_dev_up(struct nfc_dev *dev)
+{
+ int rc = 0;
+
+ nfc_dbg("dev_name=%s", dev_name(&dev->dev));
+
+ device_lock(&dev->dev);
+
+ if (!device_is_registered(&dev->dev)) {
+ rc = -ENODEV;
+ goto error;
+ }
+
+ if (dev->dev_up) {
+ rc = -EALREADY;
+ goto error;
+ }
+
+ if (dev->ops->dev_up)
+ rc = dev->ops->dev_up(dev);
+
+ if (!rc)
+ dev->dev_up = true;
+
+error:
+ device_unlock(&dev->dev);
+ return rc;
+}
+
+/**
+ * nfc_dev_down - turn off the NFC device
+ *
+ * @dev: The nfc device to be turned off
+ */
+int nfc_dev_down(struct nfc_dev *dev)
+{
+ int rc = 0;
+
+ nfc_dbg("dev_name=%s", dev_name(&dev->dev));
+
+ device_lock(&dev->dev);
+
+ if (!device_is_registered(&dev->dev)) {
+ rc = -ENODEV;
+ goto error;
+ }
+
+ if (!dev->dev_up) {
+ rc = -EALREADY;
+ goto error;
+ }
+
+ if (dev->polling || dev->remote_activated) {
+ rc = -EBUSY;
+ goto error;
+ }
+
+ if (dev->ops->dev_down)
+ dev->ops->dev_down(dev);
+
+ dev->dev_up = false;
+
+error:
+ device_unlock(&dev->dev);
+ return rc;
+}
+
+/**
* nfc_start_poll - start polling for nfc targets
*
* @dev: The nfc device that must start polling
@@ -144,6 +218,8 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol)
}
rc = dev->ops->activate_target(dev, target_idx, protocol);
+ if (!rc)
+ dev->remote_activated = true;
error:
device_unlock(&dev->dev);
@@ -170,6 +246,7 @@ int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx)
}
dev->ops->deactivate_target(dev, target_idx);
+ dev->remote_activated = false;
error:
device_unlock(&dev->dev);
@@ -322,7 +399,9 @@ 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)
+ u32 supported_protocols,
+ int tx_headroom,
+ int tx_tailroom)
{
static atomic_t dev_no = ATOMIC_INIT(0);
struct nfc_dev *dev;
@@ -345,6 +424,8 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
dev->ops = ops;
dev->supported_protocols = supported_protocols;
+ dev->tx_headroom = tx_headroom;
+ dev->tx_tailroom = tx_tailroom;
spin_lock_init(&dev->targets_lock);
nfc_genl_data_init(&dev->genl_data);
diff --git a/net/nfc/nci/Kconfig b/net/nfc/nci/Kconfig
new file mode 100644
index 000000000000..decdc49b26d8
--- /dev/null
+++ b/net/nfc/nci/Kconfig
@@ -0,0 +1,10 @@
+config NFC_NCI
+ depends on NFC && EXPERIMENTAL
+ tristate "NCI protocol support (EXPERIMENTAL)"
+ default n
+ help
+ NCI (NFC Controller Interface) is a communication protocol between
+ an NFC Controller (NFCC) and a Device Host (DH).
+
+ Say Y here to compile NCI support into the kernel or say M to
+ compile it as module (nci).
diff --git a/net/nfc/nci/Makefile b/net/nfc/nci/Makefile
new file mode 100644
index 000000000000..cdb3a2e44471
--- /dev/null
+++ b/net/nfc/nci/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Linux NFC NCI layer.
+#
+
+obj-$(CONFIG_NFC_NCI) += nci.o
+
+nci-objs := core.o data.o lib.o ntf.o rsp.o \ No newline at end of file
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
new file mode 100644
index 000000000000..4047e29acb3b
--- /dev/null
+++ b/net/nfc/nci/core.c
@@ -0,0 +1,797 @@
+/*
+ * The NFC Controller Interface is the communication protocol between an
+ * NFC Controller (NFCC) and a Device Host (DH).
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ * Written by Ilan Elias <ilane@ti.com>
+ *
+ * Acknowledgements:
+ * This file is based on hci_core.c, which was written
+ * by Maxim Krasnyansky.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/sched.h>
+#include <linux/bitops.h>
+#include <linux/skbuff.h>
+
+#include "../nfc.h"
+#include <net/nfc/nci.h>
+#include <net/nfc/nci_core.h>
+#include <linux/nfc.h>
+
+static void nci_cmd_work(struct work_struct *work);
+static void nci_rx_work(struct work_struct *work);
+static void nci_tx_work(struct work_struct *work);
+
+/* ---- NCI requests ---- */
+
+void nci_req_complete(struct nci_dev *ndev, int result)
+{
+ if (ndev->req_status == NCI_REQ_PEND) {
+ ndev->req_result = result;
+ ndev->req_status = NCI_REQ_DONE;
+ complete(&ndev->req_completion);
+ }
+}
+
+static void nci_req_cancel(struct nci_dev *ndev, int err)
+{
+ if (ndev->req_status == NCI_REQ_PEND) {
+ ndev->req_result = err;
+ ndev->req_status = NCI_REQ_CANCELED;
+ complete(&ndev->req_completion);
+ }
+}
+
+/* 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)
+{
+ int rc = 0;
+ unsigned long completion_rc;
+
+ ndev->req_status = NCI_REQ_PEND;
+
+ init_completion(&ndev->req_completion);
+ req(ndev, opt);
+ completion_rc = wait_for_completion_interruptible_timeout(
+ &ndev->req_completion,
+ timeout);
+
+ nfc_dbg("wait_for_completion return %ld", completion_rc);
+
+ if (completion_rc > 0) {
+ switch (ndev->req_status) {
+ case NCI_REQ_DONE:
+ rc = nci_to_errno(ndev->req_result);
+ break;
+
+ case NCI_REQ_CANCELED:
+ rc = -ndev->req_result;
+ break;
+
+ default:
+ rc = -ETIMEDOUT;
+ break;
+ }
+ } else {
+ nfc_err("wait_for_completion_interruptible_timeout failed %ld",
+ completion_rc);
+
+ rc = ((completion_rc == 0) ? (-ETIMEDOUT) : (completion_rc));
+ }
+
+ ndev->req_status = ndev->req_result = 0;
+
+ return rc;
+}
+
+static inline int nci_request(struct nci_dev *ndev,
+ void (*req)(struct nci_dev *ndev, unsigned long opt),
+ unsigned long opt, __u32 timeout)
+{
+ int rc;
+
+ if (!test_bit(NCI_UP, &ndev->flags))
+ return -ENETDOWN;
+
+ /* Serialize all requests */
+ mutex_lock(&ndev->req_lock);
+ rc = __nci_request(ndev, req, opt, timeout);
+ mutex_unlock(&ndev->req_lock);
+
+ return rc;
+}
+
+static void nci_reset_req(struct nci_dev *ndev, unsigned long opt)
+{
+ nci_send_cmd(ndev, NCI_OP_CORE_RESET_CMD, 0, NULL);
+}
+
+static void nci_init_req(struct nci_dev *ndev, unsigned long opt)
+{
+ nci_send_cmd(ndev, NCI_OP_CORE_INIT_CMD, 0, NULL);
+}
+
+static void nci_init_complete_req(struct nci_dev *ndev, unsigned long opt)
+{
+ struct nci_core_conn_create_cmd conn_cmd;
+ struct nci_rf_disc_map_cmd cmd;
+ struct disc_map_config *cfg = cmd.mapping_configs;
+ __u8 *num = &cmd.num_mapping_configs;
+ int i;
+
+ /* create static rf connection */
+ conn_cmd.target_handle = 0;
+ conn_cmd.num_target_specific_params = 0;
+ nci_send_cmd(ndev, NCI_OP_CORE_CONN_CREATE_CMD, 2, &conn_cmd);
+
+ /* set rf mapping configurations */
+ *num = 0;
+
+ /* 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) {
+ cfg[*num].rf_protocol = NCI_RF_PROTOCOL_ISO_DEP;
+ cfg[*num].mode = NCI_DISC_MAP_MODE_BOTH;
+ cfg[*num].rf_interface_type = NCI_RF_INTERFACE_ISO_DEP;
+ (*num)++;
+ } else if (ndev->supported_rf_interfaces[i] ==
+ NCI_RF_INTERFACE_NFC_DEP) {
+ cfg[*num].rf_protocol = NCI_RF_PROTOCOL_NFC_DEP;
+ cfg[*num].mode = NCI_DISC_MAP_MODE_BOTH;
+ cfg[*num].rf_interface_type = NCI_RF_INTERFACE_NFC_DEP;
+ (*num)++;
+ }
+
+ if (*num == NCI_MAX_NUM_MAPPING_CONFIGS)
+ break;
+ }
+
+ nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_MAP_CMD,
+ (1 + ((*num)*sizeof(struct disc_map_config))),
+ &cmd);
+}
+
+static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt)
+{
+ struct nci_rf_disc_cmd cmd;
+ __u32 protocols = 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)) {
+ cmd.disc_configs[cmd.num_disc_configs].type =
+ NCI_DISCOVERY_TYPE_POLL_A_PASSIVE;
+ 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)) {
+ cmd.disc_configs[cmd.num_disc_configs].type =
+ NCI_DISCOVERY_TYPE_POLL_B_PASSIVE;
+ 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)) {
+ cmd.disc_configs[cmd.num_disc_configs].type =
+ NCI_DISCOVERY_TYPE_POLL_F_PASSIVE;
+ 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);
+}
+
+static void nci_rf_deactivate_req(struct nci_dev *ndev, unsigned long opt)
+{
+ struct nci_rf_deactivate_cmd cmd;
+
+ cmd.type = NCI_DEACTIVATE_TYPE_IDLE_MODE;
+
+ nci_send_cmd(ndev, NCI_OP_RF_DEACTIVATE_CMD,
+ sizeof(struct nci_rf_deactivate_cmd),
+ &cmd);
+}
+
+static int nci_open_device(struct nci_dev *ndev)
+{
+ int rc = 0;
+
+ mutex_lock(&ndev->req_lock);
+
+ if (test_bit(NCI_UP, &ndev->flags)) {
+ rc = -EALREADY;
+ goto done;
+ }
+
+ if (ndev->ops->open(ndev)) {
+ rc = -EIO;
+ goto done;
+ }
+
+ atomic_set(&ndev->cmd_cnt, 1);
+
+ set_bit(NCI_INIT, &ndev->flags);
+
+ rc = __nci_request(ndev, nci_reset_req, 0,
+ msecs_to_jiffies(NCI_RESET_TIMEOUT));
+
+ if (!rc) {
+ rc = __nci_request(ndev, nci_init_req, 0,
+ msecs_to_jiffies(NCI_INIT_TIMEOUT));
+ }
+
+ if (!rc) {
+ rc = __nci_request(ndev, nci_init_complete_req, 0,
+ msecs_to_jiffies(NCI_INIT_TIMEOUT));
+ }
+
+ clear_bit(NCI_INIT, &ndev->flags);
+
+ if (!rc) {
+ set_bit(NCI_UP, &ndev->flags);
+ } else {
+ /* Init failed, cleanup */
+ skb_queue_purge(&ndev->cmd_q);
+ skb_queue_purge(&ndev->rx_q);
+ skb_queue_purge(&ndev->tx_q);
+
+ ndev->ops->close(ndev);
+ ndev->flags = 0;
+ }
+
+done:
+ mutex_unlock(&ndev->req_lock);
+ return rc;
+}
+
+static int nci_close_device(struct nci_dev *ndev)
+{
+ nci_req_cancel(ndev, ENODEV);
+ mutex_lock(&ndev->req_lock);
+
+ if (!test_and_clear_bit(NCI_UP, &ndev->flags)) {
+ del_timer_sync(&ndev->cmd_timer);
+ mutex_unlock(&ndev->req_lock);
+ return 0;
+ }
+
+ /* Drop RX and TX queues */
+ skb_queue_purge(&ndev->rx_q);
+ skb_queue_purge(&ndev->tx_q);
+
+ /* Flush RX and TX wq */
+ flush_workqueue(ndev->rx_wq);
+ flush_workqueue(ndev->tx_wq);
+
+ /* Reset device */
+ skb_queue_purge(&ndev->cmd_q);
+ atomic_set(&ndev->cmd_cnt, 1);
+
+ set_bit(NCI_INIT, &ndev->flags);
+ __nci_request(ndev, nci_reset_req, 0,
+ msecs_to_jiffies(NCI_RESET_TIMEOUT));
+ clear_bit(NCI_INIT, &ndev->flags);
+
+ /* Flush cmd wq */
+ flush_workqueue(ndev->cmd_wq);
+
+ /* After this point our queues are empty
+ * and no works are scheduled. */
+ ndev->ops->close(ndev);
+
+ /* Clear flags */
+ ndev->flags = 0;
+
+ mutex_unlock(&ndev->req_lock);
+
+ return 0;
+}
+
+/* NCI command timer function */
+static void nci_cmd_timer(unsigned long arg)
+{
+ struct nci_dev *ndev = (void *) arg;
+
+ nfc_dbg("entry");
+
+ atomic_set(&ndev->cmd_cnt, 1);
+ queue_work(ndev->cmd_wq, &ndev->cmd_work);
+}
+
+static int nci_dev_up(struct nfc_dev *nfc_dev)
+{
+ struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
+
+ nfc_dbg("entry");
+
+ return nci_open_device(ndev);
+}
+
+static int nci_dev_down(struct nfc_dev *nfc_dev)
+{
+ struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
+
+ nfc_dbg("entry");
+
+ return nci_close_device(ndev);
+}
+
+static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols)
+{
+ struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
+ int rc;
+
+ nfc_dbg("entry");
+
+ if (test_bit(NCI_DISCOVERY, &ndev->flags)) {
+ nfc_err("unable to start poll, since poll is already active");
+ return -EBUSY;
+ }
+
+ if (ndev->target_active_prot) {
+ nfc_err("there is an active target");
+ return -EBUSY;
+ }
+
+ if (test_bit(NCI_POLL_ACTIVE, &ndev->flags)) {
+ nfc_dbg("target is active, implicitly deactivate...");
+
+ rc = nci_request(ndev, nci_rf_deactivate_req, 0,
+ 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));
+
+ if (!rc)
+ ndev->poll_prots = protocols;
+
+ return rc;
+}
+
+static void nci_stop_poll(struct nfc_dev *nfc_dev)
+{
+ struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
+
+ nfc_dbg("entry");
+
+ if (!test_bit(NCI_DISCOVERY, &ndev->flags)) {
+ nfc_err("unable to stop poll, since poll is not active");
+ return;
+ }
+
+ nci_request(ndev, nci_rf_deactivate_req, 0,
+ msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
+}
+
+static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx,
+ __u32 protocol)
+{
+ struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
+
+ nfc_dbg("entry, target_idx %d, protocol 0x%x", target_idx, protocol);
+
+ if (!test_bit(NCI_POLL_ACTIVE, &ndev->flags)) {
+ nfc_err("there is no available target to activate");
+ return -EINVAL;
+ }
+
+ if (ndev->target_active_prot) {
+ nfc_err("there is already an active target");
+ return -EBUSY;
+ }
+
+ if (!(ndev->target_available_prots & (1 << protocol))) {
+ nfc_err("target does not support the requested protocol 0x%x",
+ protocol);
+ return -EINVAL;
+ }
+
+ ndev->target_active_prot = protocol;
+ ndev->target_available_prots = 0;
+
+ return 0;
+}
+
+static void nci_deactivate_target(struct nfc_dev *nfc_dev, __u32 target_idx)
+{
+ struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
+
+ nfc_dbg("entry, target_idx %d", target_idx);
+
+ if (!ndev->target_active_prot) {
+ nfc_err("unable to deactivate target, no active target");
+ return;
+ }
+
+ ndev->target_active_prot = 0;
+
+ if (test_bit(NCI_POLL_ACTIVE, &ndev->flags)) {
+ nci_request(ndev, nci_rf_deactivate_req, 0,
+ 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 nci_dev *ndev = nfc_get_drvdata(nfc_dev);
+ int rc;
+
+ nfc_dbg("entry, target_idx %d, len %d", target_idx, skb->len);
+
+ if (!ndev->target_active_prot) {
+ nfc_err("unable to exchange data, no active target");
+ return -EINVAL;
+ }
+
+ if (test_and_set_bit(NCI_DATA_EXCHANGE, &ndev->flags))
+ return -EBUSY;
+
+ /* store cb and context to be used on receiving data */
+ ndev->data_exchange_cb = cb;
+ ndev->data_exchange_cb_context = cb_context;
+
+ rc = nci_send_data(ndev, ndev->conn_id, skb);
+ if (rc)
+ clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
+
+ return rc;
+}
+
+static struct nfc_ops nci_nfc_ops = {
+ .dev_up = nci_dev_up,
+ .dev_down = nci_dev_down,
+ .start_poll = nci_start_poll,
+ .stop_poll = nci_stop_poll,
+ .activate_target = nci_activate_target,
+ .deactivate_target = nci_deactivate_target,
+ .data_exchange = nci_data_exchange,
+};
+
+/* ---- Interface to NCI drivers ---- */
+
+/**
+ * nci_allocate_device - allocate a new nci device
+ *
+ * @ops: device operations
+ * @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)
+{
+ struct nci_dev *ndev;
+
+ nfc_dbg("entry, supported_protocols 0x%x", supported_protocols);
+
+ if (!ops->open || !ops->close || !ops->send)
+ return NULL;
+
+ if (!supported_protocols)
+ return NULL;
+
+ ndev = kzalloc(sizeof(struct nci_dev), GFP_KERNEL);
+ if (!ndev)
+ return NULL;
+
+ ndev->ops = ops;
+ ndev->tx_headroom = tx_headroom;
+ ndev->tx_tailroom = tx_tailroom;
+
+ ndev->nfc_dev = nfc_allocate_device(&nci_nfc_ops,
+ supported_protocols,
+ tx_headroom + NCI_DATA_HDR_SIZE,
+ tx_tailroom);
+ if (!ndev->nfc_dev)
+ goto free_exit;
+
+ nfc_set_drvdata(ndev->nfc_dev, ndev);
+
+ return ndev;
+
+free_exit:
+ kfree(ndev);
+ return NULL;
+}
+EXPORT_SYMBOL(nci_allocate_device);
+
+/**
+ * nci_free_device - deallocate nci device
+ *
+ * @ndev: The nci device to deallocate
+ */
+void nci_free_device(struct nci_dev *ndev)
+{
+ nfc_dbg("entry");
+
+ nfc_free_device(ndev->nfc_dev);
+ kfree(ndev);
+}
+EXPORT_SYMBOL(nci_free_device);
+
+/**
+ * nci_register_device - register a nci device in the nfc subsystem
+ *
+ * @dev: The nci device to register
+ */
+int nci_register_device(struct nci_dev *ndev)
+{
+ int rc;
+ struct device *dev = &ndev->nfc_dev->dev;
+ char name[32];
+
+ nfc_dbg("entry");
+
+ rc = nfc_register_device(ndev->nfc_dev);
+ if (rc)
+ goto exit;
+
+ ndev->flags = 0;
+
+ INIT_WORK(&ndev->cmd_work, nci_cmd_work);
+ snprintf(name, sizeof(name), "%s_nci_cmd_wq", dev_name(dev));
+ ndev->cmd_wq = create_singlethread_workqueue(name);
+ if (!ndev->cmd_wq) {
+ rc = -ENOMEM;
+ goto unreg_exit;
+ }
+
+ INIT_WORK(&ndev->rx_work, nci_rx_work);
+ snprintf(name, sizeof(name), "%s_nci_rx_wq", dev_name(dev));
+ ndev->rx_wq = create_singlethread_workqueue(name);
+ if (!ndev->rx_wq) {
+ rc = -ENOMEM;
+ goto destroy_cmd_wq_exit;
+ }
+
+ INIT_WORK(&ndev->tx_work, nci_tx_work);
+ snprintf(name, sizeof(name), "%s_nci_tx_wq", dev_name(dev));
+ ndev->tx_wq = create_singlethread_workqueue(name);
+ if (!ndev->tx_wq) {
+ rc = -ENOMEM;
+ goto destroy_rx_wq_exit;
+ }
+
+ skb_queue_head_init(&ndev->cmd_q);
+ skb_queue_head_init(&ndev->rx_q);
+ skb_queue_head_init(&ndev->tx_q);
+
+ setup_timer(&ndev->cmd_timer, nci_cmd_timer,
+ (unsigned long) ndev);
+
+ mutex_init(&ndev->req_lock);
+
+ goto exit;
+
+destroy_rx_wq_exit:
+ destroy_workqueue(ndev->rx_wq);
+
+destroy_cmd_wq_exit:
+ destroy_workqueue(ndev->cmd_wq);
+
+unreg_exit:
+ nfc_unregister_device(ndev->nfc_dev);
+
+exit:
+ return rc;
+}
+EXPORT_SYMBOL(nci_register_device);
+
+/**
+ * nci_unregister_device - unregister a nci device in the nfc subsystem
+ *
+ * @dev: The nci device to unregister
+ */
+void nci_unregister_device(struct nci_dev *ndev)
+{
+ nfc_dbg("entry");
+
+ nci_close_device(ndev);
+
+ destroy_workqueue(ndev->cmd_wq);
+ destroy_workqueue(ndev->rx_wq);
+ destroy_workqueue(ndev->tx_wq);
+
+ nfc_unregister_device(ndev->nfc_dev);
+}
+EXPORT_SYMBOL(nci_unregister_device);
+
+/**
+ * nci_recv_frame - receive frame from NCI drivers
+ *
+ * @skb: The sk_buff to receive
+ */
+int nci_recv_frame(struct sk_buff *skb)
+{
+ struct nci_dev *ndev = (struct nci_dev *) skb->dev;
+
+ nfc_dbg("entry, len %d", skb->len);
+
+ if (!ndev || (!test_bit(NCI_UP, &ndev->flags)
+ && !test_bit(NCI_INIT, &ndev->flags))) {
+ kfree_skb(skb);
+ return -ENXIO;
+ }
+
+ /* Queue frame for rx worker thread */
+ skb_queue_tail(&ndev->rx_q, skb);
+ queue_work(ndev->rx_wq, &ndev->rx_work);
+
+ return 0;
+}
+EXPORT_SYMBOL(nci_recv_frame);
+
+static int nci_send_frame(struct sk_buff *skb)
+{
+ struct nci_dev *ndev = (struct nci_dev *) skb->dev;
+
+ nfc_dbg("entry, len %d", skb->len);
+
+ if (!ndev) {
+ kfree_skb(skb);
+ return -ENODEV;
+ }
+
+ /* Get rid of skb owner, prior to sending to the driver. */
+ skb_orphan(skb);
+
+ return ndev->ops->send(skb);
+}
+
+/* Send NCI command */
+int nci_send_cmd(struct nci_dev *ndev, __u16 opcode, __u8 plen, void *payload)
+{
+ struct nci_ctrl_hdr *hdr;
+ struct sk_buff *skb;
+
+ nfc_dbg("entry, opcode 0x%x, plen %d", opcode, plen);
+
+ skb = nci_skb_alloc(ndev, (NCI_CTRL_HDR_SIZE + plen), GFP_KERNEL);
+ if (!skb) {
+ nfc_err("no memory for command");
+ return -ENOMEM;
+ }
+
+ hdr = (struct nci_ctrl_hdr *) skb_put(skb, NCI_CTRL_HDR_SIZE);
+ hdr->gid = nci_opcode_gid(opcode);
+ hdr->oid = nci_opcode_oid(opcode);
+ hdr->plen = plen;
+
+ nci_mt_set((__u8 *)hdr, NCI_MT_CMD_PKT);
+ nci_pbf_set((__u8 *)hdr, NCI_PBF_LAST);
+
+ if (plen)
+ memcpy(skb_put(skb, plen), payload, plen);
+
+ skb->dev = (void *) ndev;
+
+ skb_queue_tail(&ndev->cmd_q, skb);
+ queue_work(ndev->cmd_wq, &ndev->cmd_work);
+
+ return 0;
+}
+
+/* ---- NCI TX Data worker thread ---- */
+
+static void nci_tx_work(struct work_struct *work)
+{
+ struct nci_dev *ndev = container_of(work, struct nci_dev, tx_work);
+ struct sk_buff *skb;
+
+ nfc_dbg("entry, credits_cnt %d", atomic_read(&ndev->credits_cnt));
+
+ /* Send queued tx data */
+ while (atomic_read(&ndev->credits_cnt)) {
+ skb = skb_dequeue(&ndev->tx_q);
+ if (!skb)
+ return;
+
+ atomic_dec(&ndev->credits_cnt);
+
+ nfc_dbg("NCI TX: MT=data, PBF=%d, conn_id=%d, plen=%d",
+ nci_pbf(skb->data),
+ nci_conn_id(skb->data),
+ nci_plen(skb->data));
+
+ nci_send_frame(skb);
+ }
+}
+
+/* ----- NCI RX worker thread (data & control) ----- */
+
+static void nci_rx_work(struct work_struct *work)
+{
+ struct nci_dev *ndev = container_of(work, struct nci_dev, rx_work);
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&ndev->rx_q))) {
+ /* Process frame */
+ switch (nci_mt(skb->data)) {
+ case NCI_MT_RSP_PKT:
+ nci_rsp_packet(ndev, skb);
+ break;
+
+ case NCI_MT_NTF_PKT:
+ nci_ntf_packet(ndev, skb);
+ break;
+
+ case NCI_MT_DATA_PKT:
+ nci_rx_data_packet(ndev, skb);
+ break;
+
+ default:
+ nfc_err("unknown MT 0x%x", nci_mt(skb->data));
+ kfree_skb(skb);
+ break;
+ }
+ }
+}
+
+/* ----- NCI TX CMD worker thread ----- */
+
+static void nci_cmd_work(struct work_struct *work)
+{
+ struct nci_dev *ndev = container_of(work, struct nci_dev, cmd_work);
+ struct sk_buff *skb;
+
+ nfc_dbg("entry, cmd_cnt %d", atomic_read(&ndev->cmd_cnt));
+
+ /* Send queued command */
+ if (atomic_read(&ndev->cmd_cnt)) {
+ skb = skb_dequeue(&ndev->cmd_q);
+ if (!skb)
+ return;
+
+ atomic_dec(&ndev->cmd_cnt);
+
+ nfc_dbg("NCI TX: MT=cmd, PBF=%d, GID=0x%x, OID=0x%x, plen=%d",
+ nci_pbf(skb->data),
+ nci_opcode_gid(nci_opcode(skb->data)),
+ nci_opcode_oid(nci_opcode(skb->data)),
+ nci_plen(skb->data));
+
+ nci_send_frame(skb);
+
+ mod_timer(&ndev->cmd_timer,
+ jiffies + msecs_to_jiffies(NCI_CMD_TIMEOUT));
+ }
+}
diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c
new file mode 100644
index 000000000000..e5ed90fc1a9c
--- /dev/null
+++ b/net/nfc/nci/data.c
@@ -0,0 +1,247 @@
+/*
+ * The NFC Controller Interface is the communication protocol between an
+ * NFC Controller (NFCC) and a Device Host (DH).
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ * Written by Ilan Elias <ilane@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/skbuff.h>
+
+#include "../nfc.h"
+#include <net/nfc/nci.h>
+#include <net/nfc/nci_core.h>
+#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,
+ int err)
+{
+ data_exchange_cb_t cb = ndev->data_exchange_cb;
+ void *cb_context = ndev->data_exchange_cb_context;
+
+ nfc_dbg("entry, len %d, err %d", ((skb) ? (skb->len) : (0)), err);
+
+ if (cb) {
+ ndev->data_exchange_cb = NULL;
+ ndev->data_exchange_cb_context = 0;
+
+ /* forward skb to nfc core */
+ cb(cb_context, skb, err);
+ } else if (skb) {
+ nfc_err("no rx callback, dropping rx data...");
+
+ /* no waiting callback, free skb */
+ kfree_skb(skb);
+ }
+
+ clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
+}
+
+/* ----------------- NCI TX Data ----------------- */
+
+static inline void nci_push_data_hdr(struct nci_dev *ndev,
+ __u8 conn_id,
+ struct sk_buff *skb,
+ __u8 pbf)
+{
+ struct nci_data_hdr *hdr;
+ int plen = skb->len;
+
+ hdr = (struct nci_data_hdr *) skb_push(skb, NCI_DATA_HDR_SIZE);
+ hdr->conn_id = conn_id;
+ hdr->rfu = 0;
+ hdr->plen = plen;
+
+ nci_mt_set((__u8 *)hdr, NCI_MT_DATA_PKT);
+ nci_pbf_set((__u8 *)hdr, pbf);
+
+ skb->dev = (void *) ndev;
+}
+
+static int nci_queue_tx_data_frags(struct nci_dev *ndev,
+ __u8 conn_id,
+ struct sk_buff *skb) {
+ int total_len = skb->len;
+ unsigned char *data = skb->data;
+ unsigned long flags;
+ struct sk_buff_head frags_q;
+ struct sk_buff *skb_frag;
+ int frag_len;
+ int rc = 0;
+
+ nfc_dbg("entry, conn_id 0x%x, total_len %d", conn_id, total_len);
+
+ __skb_queue_head_init(&frags_q);
+
+ while (total_len) {
+ frag_len = min_t(int, total_len, ndev->max_pkt_payload_size);
+
+ skb_frag = nci_skb_alloc(ndev,
+ (NCI_DATA_HDR_SIZE + frag_len),
+ GFP_KERNEL);
+ if (skb_frag == NULL) {
+ rc = -ENOMEM;
+ goto free_exit;
+ }
+ skb_reserve(skb_frag, NCI_DATA_HDR_SIZE);
+
+ /* first, copy the data */
+ memcpy(skb_put(skb_frag, frag_len), data, frag_len);
+
+ /* second, set the header */
+ nci_push_data_hdr(ndev, conn_id, skb_frag,
+ ((total_len == frag_len) ? (NCI_PBF_LAST) : (NCI_PBF_CONT)));
+
+ __skb_queue_tail(&frags_q, skb_frag);
+
+ data += frag_len;
+ total_len -= frag_len;
+
+ nfc_dbg("frag_len %d, remaining total_len %d",
+ frag_len, total_len);
+ }
+
+ /* queue all fragments atomically */
+ spin_lock_irqsave(&ndev->tx_q.lock, flags);
+
+ while ((skb_frag = __skb_dequeue(&frags_q)) != NULL)
+ __skb_queue_tail(&ndev->tx_q, skb_frag);
+
+ spin_unlock_irqrestore(&ndev->tx_q.lock, flags);
+
+ /* free the original skb */
+ kfree_skb(skb);
+
+ goto exit;
+
+free_exit:
+ while ((skb_frag = __skb_dequeue(&frags_q)) != NULL)
+ kfree_skb(skb_frag);
+
+exit:
+ return rc;
+}
+
+/* Send NCI data */
+int nci_send_data(struct nci_dev *ndev, __u8 conn_id, struct sk_buff *skb)
+{
+ int rc = 0;
+
+ nfc_dbg("entry, conn_id 0x%x, plen %d", conn_id, skb->len);
+
+ /* check if the packet need to be fragmented */
+ if (skb->len <= ndev->max_pkt_payload_size) {
+ /* no need to fragment packet */
+ nci_push_data_hdr(ndev, conn_id, skb, NCI_PBF_LAST);
+
+ skb_queue_tail(&ndev->tx_q, skb);
+ } else {
+ /* fragment packet and queue the fragments */
+ rc = nci_queue_tx_data_frags(ndev, conn_id, skb);
+ if (rc) {
+ nfc_err("failed to fragment tx data packet");
+ goto free_exit;
+ }
+ }
+
+ queue_work(ndev->tx_wq, &ndev->tx_work);
+
+ goto exit;
+
+free_exit:
+ kfree_skb(skb);
+
+exit:
+ return rc;
+}
+
+/* ----------------- NCI RX Data ----------------- */
+
+static void nci_add_rx_data_frag(struct nci_dev *ndev,
+ struct sk_buff *skb,
+ __u8 pbf)
+{
+ int reassembly_len;
+ int err = 0;
+
+ if (ndev->rx_data_reassembly) {
+ reassembly_len = ndev->rx_data_reassembly->len;
+
+ /* first, make enough room for the already accumulated data */
+ if (skb_cow_head(skb, reassembly_len)) {
+ nfc_err("error adding room for accumulated rx data");
+
+ kfree_skb(skb);
+ skb = 0;
+
+ kfree_skb(ndev->rx_data_reassembly);
+ ndev->rx_data_reassembly = 0;
+
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ /* second, combine the two fragments */
+ memcpy(skb_push(skb, reassembly_len),
+ ndev->rx_data_reassembly->data,
+ reassembly_len);
+
+ /* third, free old reassembly */
+ kfree_skb(ndev->rx_data_reassembly);
+ ndev->rx_data_reassembly = 0;
+ }
+
+ if (pbf == NCI_PBF_CONT) {
+ /* need to wait for next fragment, store skb and exit */
+ ndev->rx_data_reassembly = skb;
+ return;
+ }
+
+exit:
+ nci_data_exchange_complete(ndev, skb, err);
+}
+
+/* Rx Data packet */
+void nci_rx_data_packet(struct nci_dev *ndev, struct sk_buff *skb)
+{
+ __u8 pbf = nci_pbf(skb->data);
+
+ nfc_dbg("entry, len %d", skb->len);
+
+ nfc_dbg("NCI RX: MT=data, PBF=%d, conn_id=%d, plen=%d",
+ nci_pbf(skb->data),
+ nci_conn_id(skb->data),
+ nci_plen(skb->data));
+
+ /* strip the nci data header */
+ skb_pull(skb, NCI_DATA_HDR_SIZE);
+
+ if (ndev->target_active_prot == NFC_PROTO_MIFARE) {
+ /* frame I/F => remove the status byte */
+ nfc_dbg("NFC_PROTO_MIFARE => remove the status byte");
+ skb_trim(skb, (skb->len - 1));
+ }
+
+ nci_add_rx_data_frag(ndev, skb, pbf);
+}
diff --git a/net/nfc/nci/lib.c b/net/nfc/nci/lib.c
new file mode 100644
index 000000000000..b19dc2fa90e1
--- /dev/null
+++ b/net/nfc/nci/lib.c
@@ -0,0 +1,94 @@
+/*
+ * The NFC Controller Interface is the communication protocol between an
+ * NFC Controller (NFCC) and a Device Host (DH).
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ * Written by Ilan Elias <ilane@ti.com>
+ *
+ * Acknowledgements:
+ * This file is based on lib.c, which was written
+ * by Maxim Krasnyansky.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+
+#include <net/nfc/nci.h>
+
+/* NCI status codes to Unix errno mapping */
+int nci_to_errno(__u8 code)
+{
+ switch (code) {
+ case NCI_STATUS_OK:
+ return 0;
+
+ case NCI_STATUS_REJECTED:
+ return -EBUSY;
+
+ case NCI_STATUS_MESSAGE_CORRUPTED:
+ return -EBADMSG;
+
+ case NCI_STATUS_BUFFER_FULL:
+ return -ENOBUFS;
+
+ case NCI_STATUS_NOT_INITIALIZED:
+ return -EHOSTDOWN;
+
+ case NCI_STATUS_SYNTAX_ERROR:
+ case NCI_STATUS_SEMANTIC_ERROR:
+ case NCI_STATUS_INVALID_PARAM:
+ case NCI_STATUS_RF_PROTOCOL_ERROR:
+ case NCI_STATUS_NFCEE_PROTOCOL_ERROR:
+ return -EPROTO;
+
+ case NCI_STATUS_UNKNOWN_GID:
+ case NCI_STATUS_UNKNOWN_OID:
+ return -EBADRQC;
+
+ case NCI_STATUS_MESSAGE_SIZE_EXCEEDED:
+ return -EMSGSIZE;
+
+ case NCI_STATUS_DISCOVERY_ALREADY_STARTED:
+ return -EALREADY;
+
+ case NCI_STATUS_DISCOVERY_TARGET_ACTIVATION_FAILED:
+ case NCI_STATUS_NFCEE_INTERFACE_ACTIVATION_FAILED:
+ return -ECONNREFUSED;
+
+ case NCI_STATUS_RF_TRANSMISSION_ERROR:
+ case NCI_STATUS_NFCEE_TRANSMISSION_ERROR:
+ return -ECOMM;
+
+ case NCI_STATUS_RF_TIMEOUT_ERROR:
+ case NCI_STATUS_NFCEE_TIMEOUT_ERROR:
+ return -ETIMEDOUT;
+
+ case NCI_STATUS_RF_LINK_LOSS_ERROR:
+ return -ENOLINK;
+
+ case NCI_STATUS_MAX_ACTIVE_NFCEE_INTERFACES_REACHED:
+ return -EDQUOT;
+
+ case NCI_STATUS_FAILED:
+ default:
+ return -ENOSYS;
+ }
+}
+EXPORT_SYMBOL(nci_to_errno);
diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c
new file mode 100644
index 000000000000..96633f5cda4f
--- /dev/null
+++ b/net/nfc/nci/ntf.c
@@ -0,0 +1,258 @@
+/*
+ * The NFC Controller Interface is the communication protocol between an
+ * NFC Controller (NFCC) and a Device Host (DH).
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ * Written by Ilan Elias <ilane@ti.com>
+ *
+ * Acknowledgements:
+ * This file is based on hci_event.c, which was written
+ * by Maxim Krasnyansky.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/skbuff.h>
+
+#include "../nfc.h"
+#include <net/nfc/nci.h>
+#include <net/nfc/nci_core.h>
+#include <linux/nfc.h>
+
+/* Handle NCI Notification packets */
+
+static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
+ struct sk_buff *skb)
+{
+ struct nci_core_conn_credit_ntf *ntf = (void *) skb->data;
+ int i;
+
+ nfc_dbg("entry, num_entries %d", ntf->num_entries);
+
+ if (ntf->num_entries > NCI_MAX_NUM_CONN)
+ ntf->num_entries = NCI_MAX_NUM_CONN;
+
+ /* update the credits */
+ for (i = 0; i < ntf->num_entries; i++) {
+ nfc_dbg("entry[%d]: conn_id %d, credits %d", i,
+ ntf->conn_entries[i].conn_id,
+ ntf->conn_entries[i].credits);
+
+ if (ntf->conn_entries[i].conn_id == ndev->conn_id) {
+ /* found static rf connection */
+ atomic_add(ntf->conn_entries[i].credits,
+ &ndev->credits_cnt);
+ }
+ }
+
+ /* trigger the next tx */
+ if (!skb_queue_empty(&ndev->tx_q))
+ queue_work(ndev->tx_wq, &ndev->tx_work);
+}
+
+static void nci_rf_field_info_ntf_packet(struct nci_dev *ndev,
+ struct sk_buff *skb)
+{
+ struct nci_rf_field_info_ntf *ntf = (void *) skb->data;
+
+ nfc_dbg("entry, rf_field_status %d", ntf->rf_field_status);
+}
+
+static int nci_rf_activate_nfca_passive_poll(struct nci_dev *ndev,
+ struct nci_rf_activate_ntf *ntf, __u8 *data)
+{
+ struct rf_tech_specific_params_nfca_poll *nfca_poll;
+ struct activation_params_nfca_poll_iso_dep *nfca_poll_iso_dep;
+
+ nfca_poll = &ntf->rf_tech_specific_params.nfca_poll;
+ nfca_poll_iso_dep = &ntf->activation_params.nfca_poll_iso_dep;
+
+ nfca_poll->sens_res = __le16_to_cpu(*((__u16 *)data));
+ data += 2;
+
+ nfca_poll->nfcid1_len = *data++;
+
+ nfc_dbg("sens_res 0x%x, nfcid1_len %d",
+ nfca_poll->sens_res,
+ nfca_poll->nfcid1_len);
+
+ memcpy(nfca_poll->nfcid1, data, nfca_poll->nfcid1_len);
+ data += nfca_poll->nfcid1_len;
+
+ nfca_poll->sel_res_len = *data++;
+
+ if (nfca_poll->sel_res_len != 0)
+ nfca_poll->sel_res = *data++;
+
+ ntf->rf_interface_type = *data++;
+ ntf->activation_params_len = *data++;
+
+ nfc_dbg("sel_res_len %d, sel_res 0x%x, rf_interface_type %d, activation_params_len %d",
+ nfca_poll->sel_res_len,
+ nfca_poll->sel_res,
+ ntf->rf_interface_type,
+ ntf->activation_params_len);
+
+ switch (ntf->rf_interface_type) {
+ case NCI_RF_INTERFACE_ISO_DEP:
+ nfca_poll_iso_dep->rats_res_len = *data++;
+ if (nfca_poll_iso_dep->rats_res_len > 0) {
+ memcpy(nfca_poll_iso_dep->rats_res,
+ data,
+ nfca_poll_iso_dep->rats_res_len);
+ }
+ break;
+
+ case NCI_RF_INTERFACE_FRAME:
+ /* no activation params */
+ break;
+
+ default:
+ nfc_err("unsupported rf_interface_type 0x%x",
+ ntf->rf_interface_type);
+ return -EPROTO;
+ }
+
+ return 0;
+}
+
+static void nci_target_found(struct nci_dev *ndev,
+ struct nci_rf_activate_ntf *ntf)
+{
+ struct nfc_target nfc_tgt;
+
+ if (ntf->rf_protocol == NCI_RF_PROTOCOL_T2T) /* T2T MifareUL */
+ nfc_tgt.supported_protocols = NFC_PROTO_MIFARE_MASK;
+ else if (ntf->rf_protocol == NCI_RF_PROTOCOL_ISO_DEP) /* 4A */
+ nfc_tgt.supported_protocols = NFC_PROTO_ISO14443_MASK;
+
+ nfc_tgt.sens_res = ntf->rf_tech_specific_params.nfca_poll.sens_res;
+ nfc_tgt.sel_res = ntf->rf_tech_specific_params.nfca_poll.sel_res;
+
+ if (!(nfc_tgt.supported_protocols & ndev->poll_prots)) {
+ nfc_dbg("the target found does not have the desired protocol");
+ return;
+ }
+
+ nfc_dbg("new target found, supported_protocols 0x%x",
+ nfc_tgt.supported_protocols);
+
+ ndev->target_available_prots = nfc_tgt.supported_protocols;
+
+ nfc_targets_found(ndev->nfc_dev, &nfc_tgt, 1);
+}
+
+static void nci_rf_activate_ntf_packet(struct nci_dev *ndev,
+ struct sk_buff *skb)
+{
+ struct nci_rf_activate_ntf ntf;
+ __u8 *data = skb->data;
+ int rc = -1;
+
+ clear_bit(NCI_DISCOVERY, &ndev->flags);
+ set_bit(NCI_POLL_ACTIVE, &ndev->flags);
+
+ ntf.target_handle = *data++;
+ ntf.rf_protocol = *data++;
+ ntf.rf_tech_and_mode = *data++;
+ ntf.rf_tech_specific_params_len = *data++;
+
+ nfc_dbg("target_handle %d, rf_protocol 0x%x, rf_tech_and_mode 0x%x, rf_tech_specific_params_len %d",
+ ntf.target_handle,
+ ntf.rf_protocol,
+ ntf.rf_tech_and_mode,
+ ntf.rf_tech_specific_params_len);
+
+ switch (ntf.rf_tech_and_mode) {
+ case NCI_NFC_A_PASSIVE_POLL_MODE:
+ rc = nci_rf_activate_nfca_passive_poll(ndev, &ntf,
+ data);
+ break;
+
+ default:
+ nfc_err("unsupported rf_tech_and_mode 0x%x",
+ ntf.rf_tech_and_mode);
+ return;
+ }
+
+ if (!rc)
+ nci_target_found(ndev, &ntf);
+}
+
+static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev,
+ struct sk_buff *skb)
+{
+ __u8 type = skb->data[0];
+
+ nfc_dbg("entry, type 0x%x", type);
+
+ clear_bit(NCI_POLL_ACTIVE, &ndev->flags);
+ ndev->target_active_prot = 0;
+
+ /* drop tx data queue */
+ skb_queue_purge(&ndev->tx_q);
+
+ /* drop partial rx data packet */
+ if (ndev->rx_data_reassembly) {
+ kfree_skb(ndev->rx_data_reassembly);
+ ndev->rx_data_reassembly = 0;
+ }
+
+ /* complete the data exchange transaction, if exists */
+ if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
+ nci_data_exchange_complete(ndev, NULL, -EIO);
+}
+
+void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb)
+{
+ __u16 ntf_opcode = nci_opcode(skb->data);
+
+ nfc_dbg("NCI RX: MT=ntf, PBF=%d, GID=0x%x, OID=0x%x, plen=%d",
+ nci_pbf(skb->data),
+ nci_opcode_gid(ntf_opcode),
+ nci_opcode_oid(ntf_opcode),
+ nci_plen(skb->data));
+
+ /* strip the nci control header */
+ skb_pull(skb, NCI_CTRL_HDR_SIZE);
+
+ switch (ntf_opcode) {
+ case NCI_OP_CORE_CONN_CREDITS_NTF:
+ nci_core_conn_credits_ntf_packet(ndev, skb);
+ break;
+
+ case NCI_OP_RF_FIELD_INFO_NTF:
+ nci_rf_field_info_ntf_packet(ndev, skb);
+ break;
+
+ case NCI_OP_RF_ACTIVATE_NTF:
+ nci_rf_activate_ntf_packet(ndev, skb);
+ break;
+
+ case NCI_OP_RF_DEACTIVATE_NTF:
+ nci_rf_deactivate_ntf_packet(ndev, skb);
+ break;
+
+ default:
+ nfc_err("unknown ntf opcode 0x%x", ntf_opcode);
+ break;
+ }
+
+ kfree_skb(skb);
+}
diff --git a/net/nfc/nci/rsp.c b/net/nfc/nci/rsp.c
new file mode 100644
index 000000000000..0403d4cd0917
--- /dev/null
+++ b/net/nfc/nci/rsp.c
@@ -0,0 +1,226 @@
+/*
+ * The NFC Controller Interface is the communication protocol between an
+ * NFC Controller (NFCC) and a Device Host (DH).
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ * Written by Ilan Elias <ilane@ti.com>
+ *
+ * Acknowledgements:
+ * This file is based on hci_event.c, which was written
+ * by Maxim Krasnyansky.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/skbuff.h>
+
+#include "../nfc.h"
+#include <net/nfc/nci.h>
+#include <net/nfc/nci_core.h>
+
+/* Handle NCI Response packets */
+
+static void nci_core_reset_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
+{
+ struct nci_core_reset_rsp *rsp = (void *) skb->data;
+
+ nfc_dbg("entry, status 0x%x", rsp->status);
+
+ if (rsp->status == NCI_STATUS_OK)
+ ndev->nci_ver = rsp->nci_ver;
+
+ nfc_dbg("nci_ver 0x%x", ndev->nci_ver);
+
+ nci_req_complete(ndev, rsp->status);
+}
+
+static void nci_core_init_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
+{
+ struct nci_core_init_rsp_1 *rsp_1 = (void *) skb->data;
+ struct nci_core_init_rsp_2 *rsp_2;
+
+ nfc_dbg("entry, status 0x%x", rsp_1->status);
+
+ if (rsp_1->status != NCI_STATUS_OK)
+ return;
+
+ ndev->nfcc_features = __le32_to_cpu(rsp_1->nfcc_features);
+ ndev->num_supported_rf_interfaces = rsp_1->num_supported_rf_interfaces;
+
+ if (ndev->num_supported_rf_interfaces >
+ NCI_MAX_SUPPORTED_RF_INTERFACES) {
+ 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_2 = (void *) (skb->data + 6 + ndev->num_supported_rf_interfaces);
+
+ ndev->max_logical_connections =
+ rsp_2->max_logical_connections;
+ ndev->max_routing_table_size =
+ __le16_to_cpu(rsp_2->max_routing_table_size);
+ ndev->max_control_packet_payload_length =
+ rsp_2->max_control_packet_payload_length;
+ ndev->rf_sending_buffer_size =
+ __le16_to_cpu(rsp_2->rf_sending_buffer_size);
+ ndev->rf_receiving_buffer_size =
+ __le16_to_cpu(rsp_2->rf_receiving_buffer_size);
+ ndev->manufacturer_id =
+ __le16_to_cpu(rsp_2->manufacturer_id);
+
+ nfc_dbg("nfcc_features 0x%x",
+ ndev->nfcc_features);
+ nfc_dbg("num_supported_rf_interfaces %d",
+ ndev->num_supported_rf_interfaces);
+ nfc_dbg("supported_rf_interfaces[0] 0x%x",
+ ndev->supported_rf_interfaces[0]);
+ nfc_dbg("supported_rf_interfaces[1] 0x%x",
+ ndev->supported_rf_interfaces[1]);
+ nfc_dbg("supported_rf_interfaces[2] 0x%x",
+ ndev->supported_rf_interfaces[2]);
+ nfc_dbg("supported_rf_interfaces[3] 0x%x",
+ ndev->supported_rf_interfaces[3]);
+ nfc_dbg("max_logical_connections %d",
+ ndev->max_logical_connections);
+ nfc_dbg("max_routing_table_size %d",
+ ndev->max_routing_table_size);
+ nfc_dbg("max_control_packet_payload_length %d",
+ ndev->max_control_packet_payload_length);
+ nfc_dbg("rf_sending_buffer_size %d",
+ ndev->rf_sending_buffer_size);
+ nfc_dbg("rf_receiving_buffer_size %d",
+ ndev->rf_receiving_buffer_size);
+ nfc_dbg("manufacturer_id 0x%x",
+ ndev->manufacturer_id);
+
+ nci_req_complete(ndev, rsp_1->status);
+}
+
+static void nci_core_conn_create_rsp_packet(struct nci_dev *ndev,
+ struct sk_buff *skb)
+{
+ struct nci_core_conn_create_rsp *rsp = (void *) skb->data;
+
+ nfc_dbg("entry, status 0x%x", rsp->status);
+
+ if (rsp->status != NCI_STATUS_OK)
+ return;
+
+ ndev->max_pkt_payload_size = rsp->max_pkt_payload_size;
+ ndev->initial_num_credits = rsp->initial_num_credits;
+ ndev->conn_id = rsp->conn_id;
+
+ atomic_set(&ndev->credits_cnt, ndev->initial_num_credits);
+
+ nfc_dbg("max_pkt_payload_size %d", ndev->max_pkt_payload_size);
+ nfc_dbg("initial_num_credits %d", ndev->initial_num_credits);
+ nfc_dbg("conn_id %d", ndev->conn_id);
+}
+
+static void nci_rf_disc_map_rsp_packet(struct nci_dev *ndev,
+ struct sk_buff *skb)
+{
+ __u8 status = skb->data[0];
+
+ nfc_dbg("entry, status 0x%x", status);
+
+ nci_req_complete(ndev, status);
+}
+
+static void nci_rf_disc_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
+{
+ __u8 status = skb->data[0];
+
+ nfc_dbg("entry, status 0x%x", status);
+
+ if (status == NCI_STATUS_OK)
+ set_bit(NCI_DISCOVERY, &ndev->flags);
+
+ nci_req_complete(ndev, status);
+}
+
+static void nci_rf_deactivate_rsp_packet(struct nci_dev *ndev,
+ struct sk_buff *skb)
+{
+ __u8 status = skb->data[0];
+
+ nfc_dbg("entry, status 0x%x", status);
+
+ clear_bit(NCI_DISCOVERY, &ndev->flags);
+
+ nci_req_complete(ndev, status);
+}
+
+void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
+{
+ __u16 rsp_opcode = nci_opcode(skb->data);
+
+ /* we got a rsp, stop the cmd timer */
+ del_timer(&ndev->cmd_timer);
+
+ nfc_dbg("NCI RX: MT=rsp, PBF=%d, GID=0x%x, OID=0x%x, plen=%d",
+ nci_pbf(skb->data),
+ nci_opcode_gid(rsp_opcode),
+ nci_opcode_oid(rsp_opcode),
+ nci_plen(skb->data));
+
+ /* strip the nci control header */
+ skb_pull(skb, NCI_CTRL_HDR_SIZE);
+
+ switch (rsp_opcode) {
+ case NCI_OP_CORE_RESET_RSP:
+ nci_core_reset_rsp_packet(ndev, skb);
+ break;
+
+ case NCI_OP_CORE_INIT_RSP:
+ nci_core_init_rsp_packet(ndev, skb);
+ break;
+
+ case NCI_OP_CORE_CONN_CREATE_RSP:
+ nci_core_conn_create_rsp_packet(ndev, skb);
+ break;
+
+ case NCI_OP_RF_DISCOVER_MAP_RSP:
+ nci_rf_disc_map_rsp_packet(ndev, skb);
+ break;
+
+ case NCI_OP_RF_DISCOVER_RSP:
+ nci_rf_disc_rsp_packet(ndev, skb);
+ break;
+
+ case NCI_OP_RF_DEACTIVATE_RSP:
+ nci_rf_deactivate_rsp_packet(ndev, skb);
+ break;
+
+ default:
+ nfc_err("unknown rsp opcode 0x%x", rsp_opcode);
+ break;
+ }
+
+ kfree_skb(skb);
+
+ /* trigger the next cmd */
+ atomic_set(&ndev->cmd_cnt, 1);
+ if (!skb_queue_empty(&ndev->cmd_q))
+ queue_work(ndev->cmd_wq, &ndev->cmd_work);
+}
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
index ccdff7953f7d..03f8818e1f16 100644
--- a/net/nfc/netlink.c
+++ b/net/nfc/netlink.c
@@ -367,6 +367,52 @@ out_putdev:
return rc;
}
+static int nfc_genl_dev_up(struct sk_buff *skb, struct genl_info *info)
+{
+ struct nfc_dev *dev;
+ int rc;
+ u32 idx;
+
+ nfc_dbg("entry");
+
+ if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
+ return -EINVAL;
+
+ idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
+
+ dev = nfc_get_device(idx);
+ if (!dev)
+ return -ENODEV;
+
+ rc = nfc_dev_up(dev);
+
+ nfc_put_device(dev);
+ return rc;
+}
+
+static int nfc_genl_dev_down(struct sk_buff *skb, struct genl_info *info)
+{
+ struct nfc_dev *dev;
+ int rc;
+ u32 idx;
+
+ nfc_dbg("entry");
+
+ if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
+ return -EINVAL;
+
+ idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
+
+ dev = nfc_get_device(idx);
+ if (!dev)
+ return -ENODEV;
+
+ rc = nfc_dev_down(dev);
+
+ nfc_put_device(dev);
+ return rc;
+}
+
static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)
{
struct nfc_dev *dev;
@@ -441,6 +487,16 @@ static struct genl_ops nfc_genl_ops[] = {
.policy = nfc_genl_policy,
},
{
+ .cmd = NFC_CMD_DEV_UP,
+ .doit = nfc_genl_dev_up,
+ .policy = nfc_genl_policy,
+ },
+ {
+ .cmd = NFC_CMD_DEV_DOWN,
+ .doit = nfc_genl_dev_down,
+ .policy = nfc_genl_policy,
+ },
+ {
.cmd = NFC_CMD_START_POLL,
.doit = nfc_genl_start_poll,
.policy = nfc_genl_policy,
diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h
index aaf9832298f3..b6753f45624e 100644
--- a/net/nfc/nfc.h
+++ b/net/nfc/nfc.h
@@ -24,7 +24,7 @@
#ifndef __LOCAL_NFC_H
#define __LOCAL_NFC_H
-#include <net/nfc.h>
+#include <net/nfc/nfc.h>
#include <net/sock.h>
__attribute__((format (printf, 2, 3)))
@@ -101,6 +101,10 @@ static inline void nfc_device_iter_exit(struct class_dev_iter *iter)
class_dev_iter_exit(iter);
}
+int nfc_dev_up(struct nfc_dev *dev);
+
+int nfc_dev_down(struct nfc_dev *dev);
+
int nfc_start_poll(struct nfc_dev *dev, u32 protocols);
int nfc_stop_poll(struct nfc_dev *dev);
diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c
index 52de84a55115..9fd652a51424 100644
--- a/net/nfc/rawsock.c
+++ b/net/nfc/rawsock.c
@@ -123,11 +123,7 @@ error:
static int rawsock_add_header(struct sk_buff *skb)
{
-
- if (skb_cow_head(skb, 1))
- return -ENOMEM;
-
- *skb_push(skb, 1) = 0;
+ *skb_push(skb, NFC_HEADER_SIZE) = 0;
return 0;
}
@@ -197,6 +193,7 @@ static int rawsock_sendmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t len)
{
struct sock *sk = sock->sk;
+ struct nfc_dev *dev = nfc_rawsock(sk)->dev;
struct sk_buff *skb;
int rc;
@@ -208,11 +205,13 @@ static int rawsock_sendmsg(struct kiocb *iocb, struct socket *sock,
if (sock->state != SS_CONNECTED)
return -ENOTCONN;
- skb = sock_alloc_send_skb(sk, len, msg->msg_flags & MSG_DONTWAIT,
- &rc);
+ skb = sock_alloc_send_skb(sk, len + dev->tx_headroom + dev->tx_tailroom + NFC_HEADER_SIZE,
+ msg->msg_flags & MSG_DONTWAIT, &rc);
if (!skb)
return rc;
+ skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE);
+
rc = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
if (rc < 0) {
kfree_skb(skb);
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index c698cec0a445..03bb45adf2fc 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -40,6 +40,10 @@
* byte arrays at the end of sockaddr_ll
* and packet_mreq.
* Johann Baudy : Added TX RING.
+ * Chetan Loke : Implemented TPACKET_V3 block abstraction
+ * layer.
+ * Copyright (C) 2011, <lokec@ccs.neu.edu>
+ *
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -161,9 +165,56 @@ struct packet_mreq_max {
unsigned char mr_address[MAX_ADDR_LEN];
};
-static int packet_set_ring(struct sock *sk, struct tpacket_req *req,
+static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
int closing, int tx_ring);
+
+#define V3_ALIGNMENT (8)
+
+#define BLK_HDR_LEN (ALIGN(sizeof(struct tpacket_block_desc), V3_ALIGNMENT))
+
+#define BLK_PLUS_PRIV(sz_of_priv) \
+ (BLK_HDR_LEN + ALIGN((sz_of_priv), V3_ALIGNMENT))
+
+/* kbdq - kernel block descriptor queue */
+struct tpacket_kbdq_core {
+ struct pgv *pkbdq;
+ unsigned int feature_req_word;
+ unsigned int hdrlen;
+ unsigned char reset_pending_on_curr_blk;
+ unsigned char delete_blk_timer;
+ unsigned short kactive_blk_num;
+ unsigned short blk_sizeof_priv;
+
+ /* last_kactive_blk_num:
+ * trick to see if user-space has caught up
+ * in order to avoid refreshing timer when every single pkt arrives.
+ */
+ unsigned short last_kactive_blk_num;
+
+ char *pkblk_start;
+ char *pkblk_end;
+ int kblk_size;
+ unsigned int knum_blocks;
+ uint64_t knxt_seq_num;
+ char *prev;
+ char *nxt_offset;
+ struct sk_buff *skb;
+
+ atomic_t blk_fill_in_prog;
+
+ /* Default is set to 8ms */
+#define DEFAULT_PRB_RETIRE_TOV (8)
+
+ unsigned short retire_blk_tov;
+ unsigned short version;
+ unsigned long tov_in_jiffies;
+
+ /* timer to retire an outstanding block */
+ struct timer_list retire_blk_timer;
+};
+
+#define PGV_FROM_VMALLOC 1
struct pgv {
char *buffer;
};
@@ -179,12 +230,44 @@ struct packet_ring_buffer {
unsigned int pg_vec_pages;
unsigned int pg_vec_len;
+ struct tpacket_kbdq_core prb_bdqc;
atomic_t pending;
};
+#define BLOCK_STATUS(x) ((x)->hdr.bh1.block_status)
+#define BLOCK_NUM_PKTS(x) ((x)->hdr.bh1.num_pkts)
+#define BLOCK_O2FP(x) ((x)->hdr.bh1.offset_to_first_pkt)
+#define BLOCK_LEN(x) ((x)->hdr.bh1.blk_len)
+#define BLOCK_SNUM(x) ((x)->hdr.bh1.seq_num)
+#define BLOCK_O2PRIV(x) ((x)->offset_to_priv)
+#define BLOCK_PRIV(x) ((void *)((char *)(x) + BLOCK_O2PRIV(x)))
+
struct packet_sock;
static int tpacket_snd(struct packet_sock *po, struct msghdr *msg);
+static void *packet_previous_frame(struct packet_sock *po,
+ struct packet_ring_buffer *rb,
+ int status);
+static void packet_increment_head(struct packet_ring_buffer *buff);
+static int prb_curr_blk_in_use(struct tpacket_kbdq_core *,
+ struct tpacket_block_desc *);
+static void *prb_dispatch_next_block(struct tpacket_kbdq_core *,
+ struct packet_sock *);
+static void prb_retire_current_block(struct tpacket_kbdq_core *,
+ struct packet_sock *, unsigned int status);
+static int prb_queue_frozen(struct tpacket_kbdq_core *);
+static void prb_open_block(struct tpacket_kbdq_core *,
+ struct tpacket_block_desc *);
+static void prb_retire_rx_blk_timer_expired(unsigned long);
+static void _prb_refresh_rx_retire_blk_timer(struct tpacket_kbdq_core *);
+static void prb_init_blk_timer(struct packet_sock *,
+ struct tpacket_kbdq_core *,
+ void (*func) (unsigned long));
+static void prb_fill_rxhash(struct tpacket_kbdq_core *, struct tpacket3_hdr *);
+static void prb_clear_rxhash(struct tpacket_kbdq_core *,
+ struct tpacket3_hdr *);
+static void prb_fill_vlan_info(struct tpacket_kbdq_core *,
+ struct tpacket3_hdr *);
static void packet_flush_mclist(struct sock *sk);
struct packet_fanout;
@@ -193,6 +276,7 @@ struct packet_sock {
struct sock sk;
struct packet_fanout *fanout;
struct tpacket_stats stats;
+ union tpacket_stats_u stats_u;
struct packet_ring_buffer rx_ring;
struct packet_ring_buffer tx_ring;
int copy_thresh;
@@ -242,6 +326,15 @@ struct packet_skb_cb {
#define PACKET_SKB_CB(__skb) ((struct packet_skb_cb *)((__skb)->cb))
+#define GET_PBDQC_FROM_RB(x) ((struct tpacket_kbdq_core *)(&(x)->prb_bdqc))
+#define GET_PBLOCK_DESC(x, bid) \
+ ((struct tpacket_block_desc *)((x)->pkbdq[(bid)].buffer))
+#define GET_CURR_PBLOCK_DESC_FROM_CORE(x) \
+ ((struct tpacket_block_desc *)((x)->pkbdq[(x)->kactive_blk_num].buffer))
+#define GET_NEXT_PRB_BLK_NUM(x) \
+ (((x)->kactive_blk_num < ((x)->knum_blocks-1)) ? \
+ ((x)->kactive_blk_num+1) : 0)
+
static inline struct packet_sock *pkt_sk(struct sock *sk)
{
return (struct packet_sock *)sk;
@@ -325,8 +418,9 @@ static void __packet_set_status(struct packet_sock *po, void *frame, int status)
h.h2->tp_status = status;
flush_dcache_page(pgv_to_page(&h.h2->tp_status));
break;
+ case TPACKET_V3:
default:
- pr_err("TPACKET version not supported\n");
+ WARN(1, "TPACKET version not supported.\n");
BUG();
}
@@ -351,8 +445,9 @@ static int __packet_get_status(struct packet_sock *po, void *frame)
case TPACKET_V2:
flush_dcache_page(pgv_to_page(&h.h2->tp_status));
return h.h2->tp_status;
+ case TPACKET_V3:
default:
- pr_err("TPACKET version not supported\n");
+ WARN(1, "TPACKET version not supported.\n");
BUG();
return 0;
}
@@ -389,6 +484,670 @@ static inline void *packet_current_frame(struct packet_sock *po,
return packet_lookup_frame(po, rb, rb->head, status);
}
+static void prb_del_retire_blk_timer(struct tpacket_kbdq_core *pkc)
+{
+ del_timer_sync(&pkc->retire_blk_timer);
+}
+
+static void prb_shutdown_retire_blk_timer(struct packet_sock *po,
+ int tx_ring,
+ struct sk_buff_head *rb_queue)
+{
+ struct tpacket_kbdq_core *pkc;
+
+ pkc = tx_ring ? &po->tx_ring.prb_bdqc : &po->rx_ring.prb_bdqc;
+
+ spin_lock(&rb_queue->lock);
+ pkc->delete_blk_timer = 1;
+ spin_unlock(&rb_queue->lock);
+
+ prb_del_retire_blk_timer(pkc);
+}
+
+static void prb_init_blk_timer(struct packet_sock *po,
+ struct tpacket_kbdq_core *pkc,
+ void (*func) (unsigned long))
+{
+ init_timer(&pkc->retire_blk_timer);
+ pkc->retire_blk_timer.data = (long)po;
+ pkc->retire_blk_timer.function = func;
+ pkc->retire_blk_timer.expires = jiffies;
+}
+
+static void prb_setup_retire_blk_timer(struct packet_sock *po, int tx_ring)
+{
+ struct tpacket_kbdq_core *pkc;
+
+ if (tx_ring)
+ BUG();
+
+ pkc = tx_ring ? &po->tx_ring.prb_bdqc : &po->rx_ring.prb_bdqc;
+ prb_init_blk_timer(po, pkc, prb_retire_rx_blk_timer_expired);
+}
+
+static int prb_calc_retire_blk_tmo(struct packet_sock *po,
+ int blk_size_in_bytes)
+{
+ struct net_device *dev;
+ unsigned int mbits = 0, msec = 0, div = 0, tmo = 0;
+ struct ethtool_cmd ecmd;
+ int err;
+
+ rtnl_lock();
+ dev = __dev_get_by_index(sock_net(&po->sk), po->ifindex);
+ if (unlikely(!dev)) {
+ rtnl_unlock();
+ return DEFAULT_PRB_RETIRE_TOV;
+ }
+ err = __ethtool_get_settings(dev, &ecmd);
+ rtnl_unlock();
+ if (!err) {
+ switch (ecmd.speed) {
+ case SPEED_10000:
+ msec = 1;
+ div = 10000/1000;
+ break;
+ case SPEED_1000:
+ msec = 1;
+ div = 1000/1000;
+ break;
+ /*
+ * If the link speed is so slow you don't really
+ * need to worry about perf anyways
+ */
+ case SPEED_100:
+ case SPEED_10:
+ default:
+ return DEFAULT_PRB_RETIRE_TOV;
+ }
+ }
+
+ mbits = (blk_size_in_bytes * 8) / (1024 * 1024);
+
+ if (div)
+ mbits /= div;
+
+ tmo = mbits * msec;
+
+ if (div)
+ return tmo+1;
+ return tmo;
+}
+
+static void prb_init_ft_ops(struct tpacket_kbdq_core *p1,
+ union tpacket_req_u *req_u)
+{
+ p1->feature_req_word = req_u->req3.tp_feature_req_word;
+}
+
+static void init_prb_bdqc(struct packet_sock *po,
+ struct packet_ring_buffer *rb,
+ struct pgv *pg_vec,
+ union tpacket_req_u *req_u, int tx_ring)
+{
+ struct tpacket_kbdq_core *p1 = &rb->prb_bdqc;
+ struct tpacket_block_desc *pbd;
+
+ memset(p1, 0x0, sizeof(*p1));
+
+ p1->knxt_seq_num = 1;
+ p1->pkbdq = pg_vec;
+ pbd = (struct tpacket_block_desc *)pg_vec[0].buffer;
+ p1->pkblk_start = (char *)pg_vec[0].buffer;
+ p1->kblk_size = req_u->req3.tp_block_size;
+ p1->knum_blocks = req_u->req3.tp_block_nr;
+ p1->hdrlen = po->tp_hdrlen;
+ p1->version = po->tp_version;
+ p1->last_kactive_blk_num = 0;
+ po->stats_u.stats3.tp_freeze_q_cnt = 0;
+ if (req_u->req3.tp_retire_blk_tov)
+ p1->retire_blk_tov = req_u->req3.tp_retire_blk_tov;
+ else
+ p1->retire_blk_tov = prb_calc_retire_blk_tmo(po,
+ req_u->req3.tp_block_size);
+ p1->tov_in_jiffies = msecs_to_jiffies(p1->retire_blk_tov);
+ p1->blk_sizeof_priv = req_u->req3.tp_sizeof_priv;
+
+ prb_init_ft_ops(p1, req_u);
+ prb_setup_retire_blk_timer(po, tx_ring);
+ prb_open_block(p1, pbd);
+}
+
+/* Do NOT update the last_blk_num first.
+ * Assumes sk_buff_head lock is held.
+ */
+static void _prb_refresh_rx_retire_blk_timer(struct tpacket_kbdq_core *pkc)
+{
+ mod_timer(&pkc->retire_blk_timer,
+ jiffies + pkc->tov_in_jiffies);
+ pkc->last_kactive_blk_num = pkc->kactive_blk_num;
+}
+
+/*
+ * Timer logic:
+ * 1) We refresh the timer only when we open a block.
+ * By doing this we don't waste cycles refreshing the timer
+ * on packet-by-packet basis.
+ *
+ * With a 1MB block-size, on a 1Gbps line, it will take
+ * i) ~8 ms to fill a block + ii) memcpy etc.
+ * In this cut we are not accounting for the memcpy time.
+ *
+ * So, if the user sets the 'tmo' to 10ms then the timer
+ * will never fire while the block is still getting filled
+ * (which is what we want). However, the user could choose
+ * to close a block early and that's fine.
+ *
+ * But when the timer does fire, we check whether or not to refresh it.
+ * Since the tmo granularity is in msecs, it is not too expensive
+ * to refresh the timer, lets say every '8' msecs.
+ * Either the user can set the 'tmo' or we can derive it based on
+ * a) line-speed and b) block-size.
+ * prb_calc_retire_blk_tmo() calculates the tmo.
+ *
+ */
+static void prb_retire_rx_blk_timer_expired(unsigned long data)
+{
+ struct packet_sock *po = (struct packet_sock *)data;
+ struct tpacket_kbdq_core *pkc = &po->rx_ring.prb_bdqc;
+ unsigned int frozen;
+ struct tpacket_block_desc *pbd;
+
+ spin_lock(&po->sk.sk_receive_queue.lock);
+
+ frozen = prb_queue_frozen(pkc);
+ pbd = GET_CURR_PBLOCK_DESC_FROM_CORE(pkc);
+
+ if (unlikely(pkc->delete_blk_timer))
+ goto out;
+
+ /* We only need to plug the race when the block is partially filled.
+ * tpacket_rcv:
+ * lock(); increment BLOCK_NUM_PKTS; unlock()
+ * copy_bits() is in progress ...
+ * timer fires on other cpu:
+ * we can't retire the current block because copy_bits
+ * is in progress.
+ *
+ */
+ if (BLOCK_NUM_PKTS(pbd)) {
+ while (atomic_read(&pkc->blk_fill_in_prog)) {
+ /* Waiting for skb_copy_bits to finish... */
+ cpu_relax();
+ }
+ }
+
+ if (pkc->last_kactive_blk_num == pkc->kactive_blk_num) {
+ if (!frozen) {
+ prb_retire_current_block(pkc, po, TP_STATUS_BLK_TMO);
+ if (!prb_dispatch_next_block(pkc, po))
+ goto refresh_timer;
+ else
+ goto out;
+ } else {
+ /* Case 1. Queue was frozen because user-space was
+ * lagging behind.
+ */
+ if (prb_curr_blk_in_use(pkc, pbd)) {
+ /*
+ * Ok, user-space is still behind.
+ * So just refresh the timer.
+ */
+ goto refresh_timer;
+ } else {
+ /* Case 2. queue was frozen,user-space caught up,
+ * now the link went idle && the timer fired.
+ * We don't have a block to close.So we open this
+ * block and restart the timer.
+ * opening a block thaws the queue,restarts timer
+ * Thawing/timer-refresh is a side effect.
+ */
+ prb_open_block(pkc, pbd);
+ goto out;
+ }
+ }
+ }
+
+refresh_timer:
+ _prb_refresh_rx_retire_blk_timer(pkc);
+
+out:
+ spin_unlock(&po->sk.sk_receive_queue.lock);
+}
+
+static inline void prb_flush_block(struct tpacket_kbdq_core *pkc1,
+ struct tpacket_block_desc *pbd1, __u32 status)
+{
+ /* Flush everything minus the block header */
+
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE == 1
+ u8 *start, *end;
+
+ start = (u8 *)pbd1;
+
+ /* Skip the block header(we know header WILL fit in 4K) */
+ start += PAGE_SIZE;
+
+ end = (u8 *)PAGE_ALIGN((unsigned long)pkc1->pkblk_end);
+ for (; start < end; start += PAGE_SIZE)
+ flush_dcache_page(pgv_to_page(start));
+
+ smp_wmb();
+#endif
+
+ /* Now update the block status. */
+
+ BLOCK_STATUS(pbd1) = status;
+
+ /* Flush the block header */
+
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE == 1
+ start = (u8 *)pbd1;
+ flush_dcache_page(pgv_to_page(start));
+
+ smp_wmb();
+#endif
+}
+
+/*
+ * Side effect:
+ *
+ * 1) flush the block
+ * 2) Increment active_blk_num
+ *
+ * Note:We DONT refresh the timer on purpose.
+ * Because almost always the next block will be opened.
+ */
+static void prb_close_block(struct tpacket_kbdq_core *pkc1,
+ struct tpacket_block_desc *pbd1,
+ struct packet_sock *po, unsigned int stat)
+{
+ __u32 status = TP_STATUS_USER | stat;
+
+ struct tpacket3_hdr *last_pkt;
+ struct tpacket_hdr_v1 *h1 = &pbd1->hdr.bh1;
+
+ if (po->stats.tp_drops)
+ status |= TP_STATUS_LOSING;
+
+ last_pkt = (struct tpacket3_hdr *)pkc1->prev;
+ last_pkt->tp_next_offset = 0;
+
+ /* Get the ts of the last pkt */
+ if (BLOCK_NUM_PKTS(pbd1)) {
+ h1->ts_last_pkt.ts_sec = last_pkt->tp_sec;
+ h1->ts_last_pkt.ts_nsec = last_pkt->tp_nsec;
+ } else {
+ /* Ok, we tmo'd - so get the current time */
+ struct timespec ts;
+ getnstimeofday(&ts);
+ h1->ts_last_pkt.ts_sec = ts.tv_sec;
+ h1->ts_last_pkt.ts_nsec = ts.tv_nsec;
+ }
+
+ smp_wmb();
+
+ /* Flush the block */
+ prb_flush_block(pkc1, pbd1, status);
+
+ pkc1->kactive_blk_num = GET_NEXT_PRB_BLK_NUM(pkc1);
+}
+
+static inline void prb_thaw_queue(struct tpacket_kbdq_core *pkc)
+{
+ pkc->reset_pending_on_curr_blk = 0;
+}
+
+/*
+ * Side effect of opening a block:
+ *
+ * 1) prb_queue is thawed.
+ * 2) retire_blk_timer is refreshed.
+ *
+ */
+static void prb_open_block(struct tpacket_kbdq_core *pkc1,
+ struct tpacket_block_desc *pbd1)
+{
+ struct timespec ts;
+ struct tpacket_hdr_v1 *h1 = &pbd1->hdr.bh1;
+
+ smp_rmb();
+
+ if (likely(TP_STATUS_KERNEL == BLOCK_STATUS(pbd1))) {
+
+ /* We could have just memset this but we will lose the
+ * flexibility of making the priv area sticky
+ */
+ BLOCK_SNUM(pbd1) = pkc1->knxt_seq_num++;
+ BLOCK_NUM_PKTS(pbd1) = 0;
+ BLOCK_LEN(pbd1) = BLK_PLUS_PRIV(pkc1->blk_sizeof_priv);
+ getnstimeofday(&ts);
+ h1->ts_first_pkt.ts_sec = ts.tv_sec;
+ h1->ts_first_pkt.ts_nsec = ts.tv_nsec;
+ pkc1->pkblk_start = (char *)pbd1;
+ pkc1->nxt_offset = (char *)(pkc1->pkblk_start +
+ BLK_PLUS_PRIV(pkc1->blk_sizeof_priv));
+ BLOCK_O2FP(pbd1) = (__u32)BLK_PLUS_PRIV(pkc1->blk_sizeof_priv);
+ BLOCK_O2PRIV(pbd1) = BLK_HDR_LEN;
+ pbd1->version = pkc1->version;
+ pkc1->prev = pkc1->nxt_offset;
+ pkc1->pkblk_end = pkc1->pkblk_start + pkc1->kblk_size;
+ prb_thaw_queue(pkc1);
+ _prb_refresh_rx_retire_blk_timer(pkc1);
+
+ smp_wmb();
+
+ return;
+ }
+
+ WARN(1, "ERROR block:%p is NOT FREE status:%d kactive_blk_num:%d\n",
+ pbd1, BLOCK_STATUS(pbd1), pkc1->kactive_blk_num);
+ dump_stack();
+ BUG();
+}
+
+/*
+ * Queue freeze logic:
+ * 1) Assume tp_block_nr = 8 blocks.
+ * 2) At time 't0', user opens Rx ring.
+ * 3) Some time past 't0', kernel starts filling blocks starting from 0 .. 7
+ * 4) user-space is either sleeping or processing block '0'.
+ * 5) tpacket_rcv is currently filling block '7', since there is no space left,
+ * it will close block-7,loop around and try to fill block '0'.
+ * call-flow:
+ * __packet_lookup_frame_in_block
+ * prb_retire_current_block()
+ * prb_dispatch_next_block()
+ * |->(BLOCK_STATUS == USER) evaluates to true
+ * 5.1) Since block-0 is currently in-use, we just freeze the queue.
+ * 6) Now there are two cases:
+ * 6.1) Link goes idle right after the queue is frozen.
+ * But remember, the last open_block() refreshed the timer.
+ * When this timer expires,it will refresh itself so that we can
+ * re-open block-0 in near future.
+ * 6.2) Link is busy and keeps on receiving packets. This is a simple
+ * case and __packet_lookup_frame_in_block will check if block-0
+ * is free and can now be re-used.
+ */
+static inline void prb_freeze_queue(struct tpacket_kbdq_core *pkc,
+ struct packet_sock *po)
+{
+ pkc->reset_pending_on_curr_blk = 1;
+ po->stats_u.stats3.tp_freeze_q_cnt++;
+}
+
+#define TOTAL_PKT_LEN_INCL_ALIGN(length) (ALIGN((length), V3_ALIGNMENT))
+
+/*
+ * If the next block is free then we will dispatch it
+ * and return a good offset.
+ * Else, we will freeze the queue.
+ * So, caller must check the return value.
+ */
+static void *prb_dispatch_next_block(struct tpacket_kbdq_core *pkc,
+ struct packet_sock *po)
+{
+ struct tpacket_block_desc *pbd;
+
+ smp_rmb();
+
+ /* 1. Get current block num */
+ pbd = GET_CURR_PBLOCK_DESC_FROM_CORE(pkc);
+
+ /* 2. If this block is currently in_use then freeze the queue */
+ if (TP_STATUS_USER & BLOCK_STATUS(pbd)) {
+ prb_freeze_queue(pkc, po);
+ return NULL;
+ }
+
+ /*
+ * 3.
+ * open this block and return the offset where the first packet
+ * needs to get stored.
+ */
+ prb_open_block(pkc, pbd);
+ return (void *)pkc->nxt_offset;
+}
+
+static void prb_retire_current_block(struct tpacket_kbdq_core *pkc,
+ struct packet_sock *po, unsigned int status)
+{
+ struct tpacket_block_desc *pbd = GET_CURR_PBLOCK_DESC_FROM_CORE(pkc);
+
+ /* retire/close the current block */
+ if (likely(TP_STATUS_KERNEL == BLOCK_STATUS(pbd))) {
+ /*
+ * Plug the case where copy_bits() is in progress on
+ * cpu-0 and tpacket_rcv() got invoked on cpu-1, didn't
+ * have space to copy the pkt in the current block and
+ * called prb_retire_current_block()
+ *
+ * We don't need to worry about the TMO case because
+ * the timer-handler already handled this case.
+ */
+ if (!(status & TP_STATUS_BLK_TMO)) {
+ while (atomic_read(&pkc->blk_fill_in_prog)) {
+ /* Waiting for skb_copy_bits to finish... */
+ cpu_relax();
+ }
+ }
+ prb_close_block(pkc, pbd, po, status);
+ return;
+ }
+
+ WARN(1, "ERROR-pbd[%d]:%p\n", pkc->kactive_blk_num, pbd);
+ dump_stack();
+ BUG();
+}
+
+static inline int prb_curr_blk_in_use(struct tpacket_kbdq_core *pkc,
+ struct tpacket_block_desc *pbd)
+{
+ return TP_STATUS_USER & BLOCK_STATUS(pbd);
+}
+
+static inline int prb_queue_frozen(struct tpacket_kbdq_core *pkc)
+{
+ return pkc->reset_pending_on_curr_blk;
+}
+
+static inline void prb_clear_blk_fill_status(struct packet_ring_buffer *rb)
+{
+ struct tpacket_kbdq_core *pkc = GET_PBDQC_FROM_RB(rb);
+ atomic_dec(&pkc->blk_fill_in_prog);
+}
+
+static inline void prb_fill_rxhash(struct tpacket_kbdq_core *pkc,
+ struct tpacket3_hdr *ppd)
+{
+ ppd->hv1.tp_rxhash = skb_get_rxhash(pkc->skb);
+}
+
+static inline void prb_clear_rxhash(struct tpacket_kbdq_core *pkc,
+ struct tpacket3_hdr *ppd)
+{
+ ppd->hv1.tp_rxhash = 0;
+}
+
+static inline void prb_fill_vlan_info(struct tpacket_kbdq_core *pkc,
+ struct tpacket3_hdr *ppd)
+{
+ if (vlan_tx_tag_present(pkc->skb)) {
+ ppd->hv1.tp_vlan_tci = vlan_tx_tag_get(pkc->skb);
+ ppd->tp_status = TP_STATUS_VLAN_VALID;
+ } else {
+ ppd->hv1.tp_vlan_tci = ppd->tp_status = 0;
+ }
+}
+
+static void prb_run_all_ft_ops(struct tpacket_kbdq_core *pkc,
+ struct tpacket3_hdr *ppd)
+{
+ prb_fill_vlan_info(pkc, ppd);
+
+ if (pkc->feature_req_word & TP_FT_REQ_FILL_RXHASH)
+ prb_fill_rxhash(pkc, ppd);
+ else
+ prb_clear_rxhash(pkc, ppd);
+}
+
+static inline void prb_fill_curr_block(char *curr,
+ struct tpacket_kbdq_core *pkc,
+ struct tpacket_block_desc *pbd,
+ unsigned int len)
+{
+ struct tpacket3_hdr *ppd;
+
+ ppd = (struct tpacket3_hdr *)curr;
+ ppd->tp_next_offset = TOTAL_PKT_LEN_INCL_ALIGN(len);
+ pkc->prev = curr;
+ pkc->nxt_offset += TOTAL_PKT_LEN_INCL_ALIGN(len);
+ BLOCK_LEN(pbd) += TOTAL_PKT_LEN_INCL_ALIGN(len);
+ BLOCK_NUM_PKTS(pbd) += 1;
+ atomic_inc(&pkc->blk_fill_in_prog);
+ prb_run_all_ft_ops(pkc, ppd);
+}
+
+/* Assumes caller has the sk->rx_queue.lock */
+static void *__packet_lookup_frame_in_block(struct packet_sock *po,
+ struct sk_buff *skb,
+ int status,
+ unsigned int len
+ )
+{
+ struct tpacket_kbdq_core *pkc;
+ struct tpacket_block_desc *pbd;
+ char *curr, *end;
+
+ pkc = GET_PBDQC_FROM_RB(((struct packet_ring_buffer *)&po->rx_ring));
+ pbd = GET_CURR_PBLOCK_DESC_FROM_CORE(pkc);
+
+ /* Queue is frozen when user space is lagging behind */
+ if (prb_queue_frozen(pkc)) {
+ /*
+ * Check if that last block which caused the queue to freeze,
+ * is still in_use by user-space.
+ */
+ if (prb_curr_blk_in_use(pkc, pbd)) {
+ /* Can't record this packet */
+ return NULL;
+ } else {
+ /*
+ * Ok, the block was released by user-space.
+ * Now let's open that block.
+ * opening a block also thaws the queue.
+ * Thawing is a side effect.
+ */
+ prb_open_block(pkc, pbd);
+ }
+ }
+
+ smp_mb();
+ curr = pkc->nxt_offset;
+ pkc->skb = skb;
+ end = (char *) ((char *)pbd + pkc->kblk_size);
+
+ /* first try the current block */
+ if (curr+TOTAL_PKT_LEN_INCL_ALIGN(len) < end) {
+ prb_fill_curr_block(curr, pkc, pbd, len);
+ return (void *)curr;
+ }
+
+ /* Ok, close the current block */
+ prb_retire_current_block(pkc, po, 0);
+
+ /* Now, try to dispatch the next block */
+ curr = (char *)prb_dispatch_next_block(pkc, po);
+ if (curr) {
+ pbd = GET_CURR_PBLOCK_DESC_FROM_CORE(pkc);
+ prb_fill_curr_block(curr, pkc, pbd, len);
+ return (void *)curr;
+ }
+
+ /*
+ * No free blocks are available.user_space hasn't caught up yet.
+ * Queue was just frozen and now this packet will get dropped.
+ */
+ return NULL;
+}
+
+static inline void *packet_current_rx_frame(struct packet_sock *po,
+ struct sk_buff *skb,
+ int status, unsigned int len)
+{
+ char *curr = NULL;
+ switch (po->tp_version) {
+ case TPACKET_V1:
+ case TPACKET_V2:
+ curr = packet_lookup_frame(po, &po->rx_ring,
+ po->rx_ring.head, status);
+ return curr;
+ case TPACKET_V3:
+ return __packet_lookup_frame_in_block(po, skb, status, len);
+ default:
+ WARN(1, "TPACKET version not supported\n");
+ BUG();
+ return 0;
+ }
+}
+
+static inline void *prb_lookup_block(struct packet_sock *po,
+ struct packet_ring_buffer *rb,
+ unsigned int previous,
+ int status)
+{
+ struct tpacket_kbdq_core *pkc = GET_PBDQC_FROM_RB(rb);
+ struct tpacket_block_desc *pbd = GET_PBLOCK_DESC(pkc, previous);
+
+ if (status != BLOCK_STATUS(pbd))
+ return NULL;
+ return pbd;
+}
+
+static inline int prb_previous_blk_num(struct packet_ring_buffer *rb)
+{
+ unsigned int prev;
+ if (rb->prb_bdqc.kactive_blk_num)
+ prev = rb->prb_bdqc.kactive_blk_num-1;
+ else
+ prev = rb->prb_bdqc.knum_blocks-1;
+ return prev;
+}
+
+/* Assumes caller has held the rx_queue.lock */
+static inline void *__prb_previous_block(struct packet_sock *po,
+ struct packet_ring_buffer *rb,
+ int status)
+{
+ unsigned int previous = prb_previous_blk_num(rb);
+ return prb_lookup_block(po, rb, previous, status);
+}
+
+static inline void *packet_previous_rx_frame(struct packet_sock *po,
+ struct packet_ring_buffer *rb,
+ int status)
+{
+ if (po->tp_version <= TPACKET_V2)
+ return packet_previous_frame(po, rb, status);
+
+ return __prb_previous_block(po, rb, status);
+}
+
+static inline void packet_increment_rx_head(struct packet_sock *po,
+ struct packet_ring_buffer *rb)
+{
+ switch (po->tp_version) {
+ case TPACKET_V1:
+ case TPACKET_V2:
+ return packet_increment_head(rb);
+ case TPACKET_V3:
+ default:
+ WARN(1, "TPACKET version not supported.\n");
+ BUG();
+ return;
+ }
+}
+
static inline void *packet_previous_frame(struct packet_sock *po,
struct packet_ring_buffer *rb,
int status)
@@ -454,43 +1213,6 @@ static struct sock *fanout_demux_cpu(struct packet_fanout *f, struct sk_buff *sk
return f->arr[cpu % num];
}
-static struct sk_buff *fanout_check_defrag(struct sk_buff *skb)
-{
-#ifdef CONFIG_INET
- const struct iphdr *iph;
- u32 len;
-
- if (skb->protocol != htons(ETH_P_IP))
- return skb;
-
- if (!pskb_may_pull(skb, sizeof(struct iphdr)))
- return skb;
-
- iph = ip_hdr(skb);
- if (iph->ihl < 5 || iph->version != 4)
- return skb;
- if (!pskb_may_pull(skb, iph->ihl*4))
- return skb;
- iph = ip_hdr(skb);
- len = ntohs(iph->tot_len);
- if (skb->len < len || len < (iph->ihl * 4))
- return skb;
-
- if (ip_is_fragment(ip_hdr(skb))) {
- skb = skb_share_check(skb, GFP_ATOMIC);
- if (skb) {
- if (pskb_trim_rcsum(skb, len))
- return skb;
- memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
- if (ip_defrag(skb, IP_DEFRAG_AF_PACKET))
- return NULL;
- skb->rxhash = 0;
- }
- }
-#endif
- return skb;
-}
-
static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
@@ -509,7 +1231,7 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev,
case PACKET_FANOUT_HASH:
default:
if (f->defrag) {
- skb = fanout_check_defrag(skb);
+ skb = ip_check_defrag(skb, IP_DEFRAG_AF_PACKET);
if (!skb)
return 0;
}
@@ -961,7 +1683,10 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev,
return 0;
drop_n_acct:
- po->stats.tp_drops = atomic_inc_return(&sk->sk_drops);
+ spin_lock(&sk->sk_receive_queue.lock);
+ po->stats.tp_drops++;
+ atomic_inc(&sk->sk_drops);
+ spin_unlock(&sk->sk_receive_queue.lock);
drop_n_restore:
if (skb_head != skb->data && skb_shared(skb)) {
@@ -982,12 +1707,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
union {
struct tpacket_hdr *h1;
struct tpacket2_hdr *h2;
+ struct tpacket3_hdr *h3;
void *raw;
} h;
u8 *skb_head = skb->data;
int skb_len = skb->len;
unsigned int snaplen, res;
- unsigned long status = TP_STATUS_LOSING|TP_STATUS_USER;
+ unsigned long status = TP_STATUS_USER;
unsigned short macoff, netoff, hdrlen;
struct sk_buff *copy_skb = NULL;
struct timeval tv;
@@ -1033,37 +1759,46 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
po->tp_reserve;
macoff = netoff - maclen;
}
-
- if (macoff + snaplen > po->rx_ring.frame_size) {
- if (po->copy_thresh &&
- atomic_read(&sk->sk_rmem_alloc) + skb->truesize <
- (unsigned)sk->sk_rcvbuf) {
- if (skb_shared(skb)) {
- copy_skb = skb_clone(skb, GFP_ATOMIC);
- } else {
- copy_skb = skb_get(skb);
- skb_head = skb->data;
+ if (po->tp_version <= TPACKET_V2) {
+ if (macoff + snaplen > po->rx_ring.frame_size) {
+ if (po->copy_thresh &&
+ atomic_read(&sk->sk_rmem_alloc) + skb->truesize
+ < (unsigned)sk->sk_rcvbuf) {
+ if (skb_shared(skb)) {
+ copy_skb = skb_clone(skb, GFP_ATOMIC);
+ } else {
+ copy_skb = skb_get(skb);
+ skb_head = skb->data;
+ }
+ if (copy_skb)
+ skb_set_owner_r(copy_skb, sk);
}
- if (copy_skb)
- skb_set_owner_r(copy_skb, sk);
+ snaplen = po->rx_ring.frame_size - macoff;
+ if ((int)snaplen < 0)
+ snaplen = 0;
}
- snaplen = po->rx_ring.frame_size - macoff;
- if ((int)snaplen < 0)
- snaplen = 0;
}
-
spin_lock(&sk->sk_receive_queue.lock);
- h.raw = packet_current_frame(po, &po->rx_ring, TP_STATUS_KERNEL);
+ h.raw = packet_current_rx_frame(po, skb,
+ TP_STATUS_KERNEL, (macoff+snaplen));
if (!h.raw)
goto ring_is_full;
- packet_increment_head(&po->rx_ring);
+ if (po->tp_version <= TPACKET_V2) {
+ packet_increment_rx_head(po, &po->rx_ring);
+ /*
+ * LOSING will be reported till you read the stats,
+ * because it's COR - Clear On Read.
+ * Anyways, moving it for V1/V2 only as V3 doesn't need this
+ * at packet level.
+ */
+ if (po->stats.tp_drops)
+ status |= TP_STATUS_LOSING;
+ }
po->stats.tp_packets++;
if (copy_skb) {
status |= TP_STATUS_COPY;
__skb_queue_tail(&sk->sk_receive_queue, copy_skb);
}
- if (!po->stats.tp_drops)
- status &= ~TP_STATUS_LOSING;
spin_unlock(&sk->sk_receive_queue.lock);
skb_copy_bits(skb, 0, h.raw + macoff, snaplen);
@@ -1114,6 +1849,29 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
h.h2->tp_padding = 0;
hdrlen = sizeof(*h.h2);
break;
+ case TPACKET_V3:
+ /* tp_nxt_offset,vlan are already populated above.
+ * So DONT clear those fields here
+ */
+ h.h3->tp_status |= status;
+ h.h3->tp_len = skb->len;
+ h.h3->tp_snaplen = snaplen;
+ h.h3->tp_mac = macoff;
+ h.h3->tp_net = netoff;
+ if ((po->tp_tstamp & SOF_TIMESTAMPING_SYS_HARDWARE)
+ && shhwtstamps->syststamp.tv64)
+ ts = ktime_to_timespec(shhwtstamps->syststamp);
+ else if ((po->tp_tstamp & SOF_TIMESTAMPING_RAW_HARDWARE)
+ && shhwtstamps->hwtstamp.tv64)
+ ts = ktime_to_timespec(shhwtstamps->hwtstamp);
+ else if (skb->tstamp.tv64)
+ ts = ktime_to_timespec(skb->tstamp);
+ else
+ getnstimeofday(&ts);
+ h.h3->tp_sec = ts.tv_sec;
+ h.h3->tp_nsec = ts.tv_nsec;
+ hdrlen = sizeof(*h.h3);
+ break;
default:
BUG();
}
@@ -1134,13 +1892,19 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
{
u8 *start, *end;
- end = (u8 *)PAGE_ALIGN((unsigned long)h.raw + macoff + snaplen);
- for (start = h.raw; start < end; start += PAGE_SIZE)
- flush_dcache_page(pgv_to_page(start));
+ if (po->tp_version <= TPACKET_V2) {
+ end = (u8 *)PAGE_ALIGN((unsigned long)h.raw
+ + macoff + snaplen);
+ for (start = h.raw; start < end; start += PAGE_SIZE)
+ flush_dcache_page(pgv_to_page(start));
+ }
smp_wmb();
}
#endif
- __packet_set_status(po, h.raw, status);
+ if (po->tp_version <= TPACKET_V2)
+ __packet_set_status(po, h.raw, status);
+ else
+ prb_clear_blk_fill_status(&po->rx_ring);
sk->sk_data_ready(sk, 0);
@@ -1167,8 +1931,6 @@ static void tpacket_destruct_skb(struct sk_buff *skb)
struct packet_sock *po = pkt_sk(skb->sk);
void *ph;
- BUG_ON(skb == NULL);
-
if (likely(po->tx_ring.pg_vec)) {
ph = skb_shinfo(skb)->destructor_arg;
BUG_ON(__packet_get_status(po, ph) != TP_STATUS_SENDING);
@@ -1631,7 +2393,7 @@ static int packet_release(struct socket *sock)
struct sock *sk = sock->sk;
struct packet_sock *po;
struct net *net;
- struct tpacket_req req;
+ union tpacket_req_u req_u;
if (!sk)
return 0;
@@ -1654,13 +2416,13 @@ static int packet_release(struct socket *sock)
packet_flush_mclist(sk);
- memset(&req, 0, sizeof(req));
+ memset(&req_u, 0, sizeof(req_u));
if (po->rx_ring.pg_vec)
- packet_set_ring(sk, &req, 1, 0);
+ packet_set_ring(sk, &req_u, 1, 0);
if (po->tx_ring.pg_vec)
- packet_set_ring(sk, &req, 1, 1);
+ packet_set_ring(sk, &req_u, 1, 1);
fanout_release(sk);
@@ -2280,15 +3042,27 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
case PACKET_RX_RING:
case PACKET_TX_RING:
{
- struct tpacket_req req;
+ union tpacket_req_u req_u;
+ int len;
- if (optlen < sizeof(req))
+ switch (po->tp_version) {
+ case TPACKET_V1:
+ case TPACKET_V2:
+ len = sizeof(req_u.req);
+ break;
+ case TPACKET_V3:
+ default:
+ len = sizeof(req_u.req3);
+ break;
+ }
+ if (optlen < len)
return -EINVAL;
if (pkt_sk(sk)->has_vnet_hdr)
return -EINVAL;
- if (copy_from_user(&req, optval, sizeof(req)))
+ if (copy_from_user(&req_u.req, optval, len))
return -EFAULT;
- return packet_set_ring(sk, &req, 0, optname == PACKET_TX_RING);
+ return packet_set_ring(sk, &req_u, 0,
+ optname == PACKET_TX_RING);
}
case PACKET_COPY_THRESH:
{
@@ -2315,6 +3089,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
switch (val) {
case TPACKET_V1:
case TPACKET_V2:
+ case TPACKET_V3:
po->tp_version = val;
return 0;
default:
@@ -2424,6 +3199,7 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
struct packet_sock *po = pkt_sk(sk);
void *data;
struct tpacket_stats st;
+ union tpacket_stats_u st_u;
if (level != SOL_PACKET)
return -ENOPROTOOPT;
@@ -2436,15 +3212,27 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
switch (optname) {
case PACKET_STATISTICS:
- if (len > sizeof(struct tpacket_stats))
- len = sizeof(struct tpacket_stats);
+ if (po->tp_version == TPACKET_V3) {
+ len = sizeof(struct tpacket_stats_v3);
+ } else {
+ if (len > sizeof(struct tpacket_stats))
+ len = sizeof(struct tpacket_stats);
+ }
spin_lock_bh(&sk->sk_receive_queue.lock);
- st = po->stats;
+ if (po->tp_version == TPACKET_V3) {
+ memcpy(&st_u.stats3, &po->stats,
+ sizeof(struct tpacket_stats));
+ st_u.stats3.tp_freeze_q_cnt =
+ po->stats_u.stats3.tp_freeze_q_cnt;
+ st_u.stats3.tp_packets += po->stats.tp_drops;
+ data = &st_u.stats3;
+ } else {
+ st = po->stats;
+ st.tp_packets += st.tp_drops;
+ data = &st;
+ }
memset(&po->stats, 0, sizeof(st));
spin_unlock_bh(&sk->sk_receive_queue.lock);
- st.tp_packets += st.tp_drops;
-
- data = &st;
break;
case PACKET_AUXDATA:
if (len > sizeof(int))
@@ -2485,6 +3273,9 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
case TPACKET_V2:
val = sizeof(struct tpacket2_hdr);
break;
+ case TPACKET_V3:
+ val = sizeof(struct tpacket3_hdr);
+ break;
default:
return -EINVAL;
}
@@ -2641,7 +3432,8 @@ static unsigned int packet_poll(struct file *file, struct socket *sock,
spin_lock_bh(&sk->sk_receive_queue.lock);
if (po->rx_ring.pg_vec) {
- if (!packet_previous_frame(po, &po->rx_ring, TP_STATUS_KERNEL))
+ if (!packet_previous_rx_frame(po, &po->rx_ring,
+ TP_STATUS_KERNEL))
mask |= POLLIN | POLLRDNORM;
}
spin_unlock_bh(&sk->sk_receive_queue.lock);
@@ -2760,7 +3552,7 @@ out_free_pgvec:
goto out;
}
-static int packet_set_ring(struct sock *sk, struct tpacket_req *req,
+static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
int closing, int tx_ring)
{
struct pgv *pg_vec = NULL;
@@ -2769,7 +3561,15 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req,
struct packet_ring_buffer *rb;
struct sk_buff_head *rb_queue;
__be16 num;
- int err;
+ int err = -EINVAL;
+ /* Added to avoid minimal code churn */
+ struct tpacket_req *req = &req_u->req;
+
+ /* Opening a Tx-ring is NOT supported in TPACKET_V3 */
+ if (!closing && tx_ring && (po->tp_version > TPACKET_V2)) {
+ WARN(1, "Tx-ring is not supported.\n");
+ goto out;
+ }
rb = tx_ring ? &po->tx_ring : &po->rx_ring;
rb_queue = tx_ring ? &sk->sk_write_queue : &sk->sk_receive_queue;
@@ -2795,6 +3595,9 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req,
case TPACKET_V2:
po->tp_hdrlen = TPACKET2_HDRLEN;
break;
+ case TPACKET_V3:
+ po->tp_hdrlen = TPACKET3_HDRLEN;
+ break;
}
err = -EINVAL;
@@ -2820,6 +3623,17 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req,
pg_vec = alloc_pg_vec(req, order);
if (unlikely(!pg_vec))
goto out;
+ switch (po->tp_version) {
+ case TPACKET_V3:
+ /* Transmit path is not supported. We checked
+ * it above but just being paranoid
+ */
+ if (!tx_ring)
+ init_prb_bdqc(po, rb, pg_vec, req_u, tx_ring);
+ break;
+ default:
+ break;
+ }
}
/* Done */
else {
@@ -2872,7 +3686,11 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req,
register_prot_hook(sk);
}
spin_unlock(&po->bind_lock);
-
+ if (closing && (po->tp_version > TPACKET_V2)) {
+ /* Because we don't support block-based V3 on tx-ring */
+ if (!tx_ring)
+ prb_shutdown_retire_blk_timer(po, tx_ring, rb_queue);
+ }
release_sock(sk);
if (pg_vec)
diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c
index c6fffd946d42..bf10ea8fbbf9 100644
--- a/net/phonet/af_phonet.c
+++ b/net/phonet/af_phonet.c
@@ -480,7 +480,7 @@ int __init_or_module phonet_proto_register(unsigned int protocol,
if (proto_tab[protocol])
err = -EBUSY;
else
- rcu_assign_pointer(proto_tab[protocol], pp);
+ RCU_INIT_POINTER(proto_tab[protocol], pp);
mutex_unlock(&proto_tab_lock);
return err;
@@ -491,7 +491,7 @@ void phonet_proto_unregister(unsigned int protocol, struct phonet_protocol *pp)
{
mutex_lock(&proto_tab_lock);
BUG_ON(proto_tab[protocol] != pp);
- rcu_assign_pointer(proto_tab[protocol], NULL);
+ RCU_INIT_POINTER(proto_tab[protocol], NULL);
mutex_unlock(&proto_tab_lock);
synchronize_rcu();
proto_unregister(pp->prot);
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index d2df8f33160b..c5827614376b 100644
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@ -276,7 +276,7 @@ static void phonet_route_autodel(struct net_device *dev)
mutex_lock(&pnn->routes.lock);
for (i = 0; i < 64; i++)
if (dev == pnn->routes.table[i]) {
- rcu_assign_pointer(pnn->routes.table[i], NULL);
+ RCU_INIT_POINTER(pnn->routes.table[i], NULL);
set_bit(i, deleted);
}
mutex_unlock(&pnn->routes.lock);
@@ -390,7 +390,7 @@ int phonet_route_add(struct net_device *dev, u8 daddr)
daddr = daddr >> 2;
mutex_lock(&routes->lock);
if (routes->table[daddr] == NULL) {
- rcu_assign_pointer(routes->table[daddr], dev);
+ RCU_INIT_POINTER(routes->table[daddr], dev);
dev_hold(dev);
err = 0;
}
@@ -406,7 +406,7 @@ int phonet_route_del(struct net_device *dev, u8 daddr)
daddr = daddr >> 2;
mutex_lock(&routes->lock);
if (dev == routes->table[daddr])
- rcu_assign_pointer(routes->table[daddr], NULL);
+ RCU_INIT_POINTER(routes->table[daddr], NULL);
else
dev = NULL;
mutex_unlock(&routes->lock);
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index ab07711cf2f4..676d18dc75b7 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -679,7 +679,7 @@ int pn_sock_bind_res(struct sock *sk, u8 res)
mutex_lock(&resource_mutex);
if (pnres.sk[res] == NULL) {
sock_hold(sk);
- rcu_assign_pointer(pnres.sk[res], sk);
+ RCU_INIT_POINTER(pnres.sk[res], sk);
ret = 0;
}
mutex_unlock(&resource_mutex);
@@ -695,7 +695,7 @@ int pn_sock_unbind_res(struct sock *sk, u8 res)
mutex_lock(&resource_mutex);
if (pnres.sk[res] == sk) {
- rcu_assign_pointer(pnres.sk[res], NULL);
+ RCU_INIT_POINTER(pnres.sk[res], NULL);
ret = 0;
}
mutex_unlock(&resource_mutex);
@@ -714,7 +714,7 @@ void pn_sock_unbind_all_res(struct sock *sk)
mutex_lock(&resource_mutex);
for (res = 0; res < 256; res++) {
if (pnres.sk[res] == sk) {
- rcu_assign_pointer(pnres.sk[res], NULL);
+ RCU_INIT_POINTER(pnres.sk[res], NULL);
match++;
}
}
diff --git a/net/rds/Kconfig b/net/rds/Kconfig
index ec753b3ae72a..4cf6dc7910e4 100644
--- a/net/rds/Kconfig
+++ b/net/rds/Kconfig
@@ -9,6 +9,7 @@ config RDS
config RDS_RDMA
tristate "RDS over Infiniband and iWARP"
+ select LLIST
depends on RDS && INFINIBAND && INFINIBAND_ADDR_TRANS
---help---
Allow RDS to use Infiniband and iWARP as a transport.
diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c
index cd67026be2d5..51c868923f64 100644
--- a/net/rds/ib_cm.c
+++ b/net/rds/ib_cm.c
@@ -375,23 +375,21 @@ static int rds_ib_setup_qp(struct rds_connection *conn)
goto out;
}
- ic->i_sends = vmalloc_node(ic->i_send_ring.w_nr * sizeof(struct rds_ib_send_work),
+ ic->i_sends = vzalloc_node(ic->i_send_ring.w_nr * sizeof(struct rds_ib_send_work),
ibdev_to_node(dev));
if (!ic->i_sends) {
ret = -ENOMEM;
rdsdebug("send allocation failed\n");
goto out;
}
- memset(ic->i_sends, 0, ic->i_send_ring.w_nr * sizeof(struct rds_ib_send_work));
- ic->i_recvs = vmalloc_node(ic->i_recv_ring.w_nr * sizeof(struct rds_ib_recv_work),
+ ic->i_recvs = vzalloc_node(ic->i_recv_ring.w_nr * sizeof(struct rds_ib_recv_work),
ibdev_to_node(dev));
if (!ic->i_recvs) {
ret = -ENOMEM;
rdsdebug("recv allocation failed\n");
goto out;
}
- memset(ic->i_recvs, 0, ic->i_recv_ring.w_nr * sizeof(struct rds_ib_recv_work));
rds_ib_recv_init_ack(ic);
diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c
index 819c35a0d9cb..e8fdb172adbb 100644
--- a/net/rds/ib_rdma.c
+++ b/net/rds/ib_rdma.c
@@ -33,10 +33,10 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/rculist.h>
+#include <linux/llist.h>
#include "rds.h"
#include "ib.h"
-#include "xlist.h"
static DEFINE_PER_CPU(unsigned long, clean_list_grace);
#define CLEAN_LIST_BUSY_BIT 0
@@ -49,7 +49,7 @@ struct rds_ib_mr {
struct rds_ib_mr_pool *pool;
struct ib_fmr *fmr;
- struct xlist_head xlist;
+ struct llist_node llnode;
/* unmap_list is for freeing */
struct list_head unmap_list;
@@ -71,9 +71,9 @@ struct rds_ib_mr_pool {
atomic_t item_count; /* total # of MRs */
atomic_t dirty_count; /* # dirty of MRs */
- struct xlist_head drop_list; /* MRs that have reached their max_maps limit */
- struct xlist_head free_list; /* unused MRs */
- struct xlist_head clean_list; /* global unused & unamapped MRs */
+ struct llist_head drop_list; /* MRs that have reached their max_maps limit */
+ struct llist_head free_list; /* unused MRs */
+ struct llist_head clean_list; /* global unused & unamapped MRs */
wait_queue_head_t flush_wait;
atomic_t free_pinned; /* memory pinned by free MRs */
@@ -220,9 +220,9 @@ struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *rds_ibdev)
if (!pool)
return ERR_PTR(-ENOMEM);
- INIT_XLIST_HEAD(&pool->free_list);
- INIT_XLIST_HEAD(&pool->drop_list);
- INIT_XLIST_HEAD(&pool->clean_list);
+ init_llist_head(&pool->free_list);
+ init_llist_head(&pool->drop_list);
+ init_llist_head(&pool->clean_list);
mutex_init(&pool->flush_lock);
init_waitqueue_head(&pool->flush_wait);
INIT_DELAYED_WORK(&pool->flush_worker, rds_ib_mr_pool_flush_worker);
@@ -260,26 +260,18 @@ void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *pool)
kfree(pool);
}
-static void refill_local(struct rds_ib_mr_pool *pool, struct xlist_head *xl,
- struct rds_ib_mr **ibmr_ret)
-{
- struct xlist_head *ibmr_xl;
- ibmr_xl = xlist_del_head_fast(xl);
- *ibmr_ret = list_entry(ibmr_xl, struct rds_ib_mr, xlist);
-}
-
static inline struct rds_ib_mr *rds_ib_reuse_fmr(struct rds_ib_mr_pool *pool)
{
struct rds_ib_mr *ibmr = NULL;
- struct xlist_head *ret;
+ struct llist_node *ret;
unsigned long *flag;
preempt_disable();
flag = &__get_cpu_var(clean_list_grace);
set_bit(CLEAN_LIST_BUSY_BIT, flag);
- ret = xlist_del_head(&pool->clean_list);
+ ret = llist_del_first(&pool->clean_list);
if (ret)
- ibmr = list_entry(ret, struct rds_ib_mr, xlist);
+ ibmr = llist_entry(ret, struct rds_ib_mr, llnode);
clear_bit(CLEAN_LIST_BUSY_BIT, flag);
preempt_enable();
@@ -529,46 +521,44 @@ static inline unsigned int rds_ib_flush_goal(struct rds_ib_mr_pool *pool, int fr
}
/*
- * given an xlist of mrs, put them all into the list_head for more processing
+ * given an llist of mrs, put them all into the list_head for more processing
*/
-static void xlist_append_to_list(struct xlist_head *xlist, struct list_head *list)
+static void llist_append_to_list(struct llist_head *llist, struct list_head *list)
{
struct rds_ib_mr *ibmr;
- struct xlist_head splice;
- struct xlist_head *cur;
- struct xlist_head *next;
-
- splice.next = NULL;
- xlist_splice(xlist, &splice);
- cur = splice.next;
- while (cur) {
- next = cur->next;
- ibmr = list_entry(cur, struct rds_ib_mr, xlist);
+ struct llist_node *node;
+ struct llist_node *next;
+
+ node = llist_del_all(llist);
+ while (node) {
+ next = node->next;
+ ibmr = llist_entry(node, struct rds_ib_mr, llnode);
list_add_tail(&ibmr->unmap_list, list);
- cur = next;
+ node = next;
}
}
/*
- * this takes a list head of mrs and turns it into an xlist of clusters.
- * each cluster has an xlist of MR_CLUSTER_SIZE mrs that are ready for
- * reuse.
+ * this takes a list head of mrs and turns it into linked llist nodes
+ * of clusters. Each cluster has linked llist nodes of
+ * MR_CLUSTER_SIZE mrs that are ready for reuse.
*/
-static void list_append_to_xlist(struct rds_ib_mr_pool *pool,
- struct list_head *list, struct xlist_head *xlist,
- struct xlist_head **tail_ret)
+static void list_to_llist_nodes(struct rds_ib_mr_pool *pool,
+ struct list_head *list,
+ struct llist_node **nodes_head,
+ struct llist_node **nodes_tail)
{
struct rds_ib_mr *ibmr;
- struct xlist_head *cur_mr = xlist;
- struct xlist_head *tail_mr = NULL;
+ struct llist_node *cur = NULL;
+ struct llist_node **next = nodes_head;
list_for_each_entry(ibmr, list, unmap_list) {
- tail_mr = &ibmr->xlist;
- tail_mr->next = NULL;
- cur_mr->next = tail_mr;
- cur_mr = tail_mr;
+ cur = &ibmr->llnode;
+ *next = cur;
+ next = &cur->next;
}
- *tail_ret = tail_mr;
+ *next = NULL;
+ *nodes_tail = cur;
}
/*
@@ -581,8 +571,8 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool,
int free_all, struct rds_ib_mr **ibmr_ret)
{
struct rds_ib_mr *ibmr, *next;
- struct xlist_head clean_xlist;
- struct xlist_head *clean_tail;
+ struct llist_node *clean_nodes;
+ struct llist_node *clean_tail;
LIST_HEAD(unmap_list);
LIST_HEAD(fmr_list);
unsigned long unpinned = 0;
@@ -603,7 +593,7 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool,
prepare_to_wait(&pool->flush_wait, &wait,
TASK_UNINTERRUPTIBLE);
- if (xlist_empty(&pool->clean_list))
+ if (llist_empty(&pool->clean_list))
schedule();
ibmr = rds_ib_reuse_fmr(pool);
@@ -628,10 +618,10 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool,
/* Get the list of all MRs to be dropped. Ordering matters -
* we want to put drop_list ahead of free_list.
*/
- xlist_append_to_list(&pool->drop_list, &unmap_list);
- xlist_append_to_list(&pool->free_list, &unmap_list);
+ llist_append_to_list(&pool->drop_list, &unmap_list);
+ llist_append_to_list(&pool->free_list, &unmap_list);
if (free_all)
- xlist_append_to_list(&pool->clean_list, &unmap_list);
+ llist_append_to_list(&pool->clean_list, &unmap_list);
free_goal = rds_ib_flush_goal(pool, free_all);
@@ -663,22 +653,22 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool,
if (!list_empty(&unmap_list)) {
/* we have to make sure that none of the things we're about
* to put on the clean list would race with other cpus trying
- * to pull items off. The xlist would explode if we managed to
+ * to pull items off. The llist would explode if we managed to
* remove something from the clean list and then add it back again
- * while another CPU was spinning on that same item in xlist_del_head.
+ * while another CPU was spinning on that same item in llist_del_first.
*
- * This is pretty unlikely, but just in case wait for an xlist grace period
+ * This is pretty unlikely, but just in case wait for an llist grace period
* here before adding anything back into the clean list.
*/
wait_clean_list_grace();
- list_append_to_xlist(pool, &unmap_list, &clean_xlist, &clean_tail);
+ list_to_llist_nodes(pool, &unmap_list, &clean_nodes, &clean_tail);
if (ibmr_ret)
- refill_local(pool, &clean_xlist, ibmr_ret);
+ *ibmr_ret = llist_entry(clean_nodes, struct rds_ib_mr, llnode);
- /* refill_local may have emptied our list */
- if (!xlist_empty(&clean_xlist))
- xlist_add(clean_xlist.next, clean_tail, &pool->clean_list);
+ /* more than one entry in llist nodes */
+ if (clean_nodes->next)
+ llist_add_batch(clean_nodes->next, clean_tail, &pool->clean_list);
}
@@ -711,9 +701,9 @@ void rds_ib_free_mr(void *trans_private, int invalidate)
/* Return it to the pool's free list */
if (ibmr->remap_count >= pool->fmr_attr.max_maps)
- xlist_add(&ibmr->xlist, &ibmr->xlist, &pool->drop_list);
+ llist_add(&ibmr->llnode, &pool->drop_list);
else
- xlist_add(&ibmr->xlist, &ibmr->xlist, &pool->free_list);
+ llist_add(&ibmr->llnode, &pool->free_list);
atomic_add(ibmr->sg_len, &pool->free_pinned);
atomic_inc(&pool->dirty_count);
diff --git a/net/rds/iw_rdma.c b/net/rds/iw_rdma.c
index 8b77edbab272..4e1de171866c 100644
--- a/net/rds/iw_rdma.c
+++ b/net/rds/iw_rdma.c
@@ -84,7 +84,8 @@ static int rds_iw_map_fastreg(struct rds_iw_mr_pool *pool,
static void rds_iw_free_fastreg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr);
static unsigned int rds_iw_unmap_fastreg_list(struct rds_iw_mr_pool *pool,
struct list_head *unmap_list,
- struct list_head *kill_list);
+ struct list_head *kill_list,
+ int *unpinned);
static void rds_iw_destroy_fastreg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr);
static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwdev, struct rdma_cm_id **cm_id)
@@ -499,7 +500,7 @@ static int rds_iw_flush_mr_pool(struct rds_iw_mr_pool *pool, int free_all)
LIST_HEAD(unmap_list);
LIST_HEAD(kill_list);
unsigned long flags;
- unsigned int nfreed = 0, ncleaned = 0, free_goal;
+ unsigned int nfreed = 0, ncleaned = 0, unpinned = 0, free_goal;
int ret = 0;
rds_iw_stats_inc(s_iw_rdma_mr_pool_flush);
@@ -524,7 +525,8 @@ static int rds_iw_flush_mr_pool(struct rds_iw_mr_pool *pool, int free_all)
* will be destroyed by the unmap function.
*/
if (!list_empty(&unmap_list)) {
- ncleaned = rds_iw_unmap_fastreg_list(pool, &unmap_list, &kill_list);
+ ncleaned = rds_iw_unmap_fastreg_list(pool, &unmap_list,
+ &kill_list, &unpinned);
/* If we've been asked to destroy all MRs, move those
* that were simply cleaned to the kill list */
if (free_all)
@@ -548,6 +550,7 @@ static int rds_iw_flush_mr_pool(struct rds_iw_mr_pool *pool, int free_all)
spin_unlock_irqrestore(&pool->list_lock, flags);
}
+ atomic_sub(unpinned, &pool->free_pinned);
atomic_sub(ncleaned, &pool->dirty_count);
atomic_sub(nfreed, &pool->item_count);
@@ -828,7 +831,8 @@ static void rds_iw_free_fastreg(struct rds_iw_mr_pool *pool,
static unsigned int rds_iw_unmap_fastreg_list(struct rds_iw_mr_pool *pool,
struct list_head *unmap_list,
- struct list_head *kill_list)
+ struct list_head *kill_list,
+ int *unpinned)
{
struct rds_iw_mapping *mapping, *next;
unsigned int ncleaned = 0;
@@ -855,6 +859,7 @@ static unsigned int rds_iw_unmap_fastreg_list(struct rds_iw_mr_pool *pool,
spin_lock_irqsave(&pool->list_lock, flags);
list_for_each_entry_safe(mapping, next, unmap_list, m_list) {
+ *unpinned += mapping->m_sg.len;
list_move(&mapping->m_list, &laundered);
ncleaned++;
}
diff --git a/net/rds/xlist.h b/net/rds/xlist.h
deleted file mode 100644
index e6b5190daddd..000000000000
--- a/net/rds/xlist.h
+++ /dev/null
@@ -1,80 +0,0 @@
-#ifndef _LINUX_XLIST_H
-#define _LINUX_XLIST_H
-
-#include <linux/stddef.h>
-#include <linux/poison.h>
-#include <linux/prefetch.h>
-#include <asm/system.h>
-
-struct xlist_head {
- struct xlist_head *next;
-};
-
-static inline void INIT_XLIST_HEAD(struct xlist_head *list)
-{
- list->next = NULL;
-}
-
-static inline int xlist_empty(struct xlist_head *head)
-{
- return head->next == NULL;
-}
-
-static inline void xlist_add(struct xlist_head *new, struct xlist_head *tail,
- struct xlist_head *head)
-{
- struct xlist_head *cur;
- struct xlist_head *check;
-
- while (1) {
- cur = head->next;
- tail->next = cur;
- check = cmpxchg(&head->next, cur, new);
- if (check == cur)
- break;
- }
-}
-
-static inline struct xlist_head *xlist_del_head(struct xlist_head *head)
-{
- struct xlist_head *cur;
- struct xlist_head *check;
- struct xlist_head *next;
-
- while (1) {
- cur = head->next;
- if (!cur)
- goto out;
-
- next = cur->next;
- check = cmpxchg(&head->next, cur, next);
- if (check == cur)
- goto out;
- }
-out:
- return cur;
-}
-
-static inline struct xlist_head *xlist_del_head_fast(struct xlist_head *head)
-{
- struct xlist_head *cur;
-
- cur = head->next;
- if (!cur)
- return NULL;
-
- head->next = cur->next;
- return cur;
-}
-
-static inline void xlist_splice(struct xlist_head *list,
- struct xlist_head *head)
-{
- struct xlist_head *cur;
-
- WARN_ON(head->next);
- cur = xchg(&list->next, NULL);
- head->next = cur;
-}
-
-#endif
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index be90640a2774..5be19575c340 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -235,7 +235,7 @@ static bool __rfkill_set_hw_state(struct rfkill *rfkill,
else
rfkill->state &= ~RFKILL_BLOCK_HW;
*change = prev != blocked;
- any = rfkill->state & RFKILL_BLOCK_ANY;
+ any = !!(rfkill->state & RFKILL_BLOCK_ANY);
spin_unlock_irqrestore(&rfkill->lock, flags);
rfkill_led_trigger_event(rfkill);
diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c
index 256c5ddd2d72..128677d69056 100644
--- a/net/rfkill/rfkill-gpio.c
+++ b/net/rfkill/rfkill-gpio.c
@@ -101,6 +101,14 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
if (!rfkill)
return -ENOMEM;
+ if (pdata->gpio_runtime_setup) {
+ ret = pdata->gpio_runtime_setup(pdev);
+ if (ret) {
+ pr_warn("%s: can't set up gpio\n", __func__);
+ return ret;
+ }
+ }
+
rfkill->pdata = pdata;
len = strlen(pdata->name);
@@ -182,7 +190,10 @@ fail_alloc:
static int rfkill_gpio_remove(struct platform_device *pdev)
{
struct rfkill_gpio_data *rfkill = platform_get_drvdata(pdev);
+ struct rfkill_gpio_platform_data *pdata = pdev->dev.platform_data;
+ if (pdata->gpio_runtime_close)
+ pdata->gpio_runtime_close(pdev);
rfkill_unregister(rfkill->rfkill_dev);
rfkill_destroy(rfkill->rfkill_dev);
if (gpio_is_valid(rfkill->pdata->shutdown_gpio))
diff --git a/net/rfkill/rfkill-regulator.c b/net/rfkill/rfkill-regulator.c
index 18dc512a10f3..3ca7277a3c36 100644
--- a/net/rfkill/rfkill-regulator.c
+++ b/net/rfkill/rfkill-regulator.c
@@ -90,7 +90,6 @@ static int __devinit rfkill_regulator_probe(struct platform_device *pdev)
pdata->type,
&rfkill_regulator_ops, rfkill_data);
if (rf_kill == NULL) {
- dev_err(&pdev->dev, "Cannot alloc rfkill device\n");
ret = -ENOMEM;
goto err_rfkill_alloc;
}
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index 102fc212cd64..e051398fdf6b 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -196,8 +196,7 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a,
skb2->skb_iif = skb->dev->ifindex;
skb2->dev = dev;
- dev_queue_xmit(skb2);
- err = 0;
+ err = dev_queue_xmit(skb2);
out:
if (err) {
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index 6994214db8f8..9e087d885675 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -65,132 +65,134 @@ static inline u32 addr_fold(void *addr)
return (a & 0xFFFFFFFF) ^ (BITS_PER_LONG > 32 ? a >> 32 : 0);
}
-static u32 flow_get_src(struct sk_buff *skb)
+static u32 flow_get_src(const struct sk_buff *skb, int nhoff)
{
+ __be32 *data = NULL, hdata;
+
switch (skb->protocol) {
case htons(ETH_P_IP):
- if (pskb_network_may_pull(skb, sizeof(struct iphdr)))
- return ntohl(ip_hdr(skb)->saddr);
+ data = skb_header_pointer(skb,
+ nhoff + offsetof(struct iphdr,
+ saddr),
+ 4, &hdata);
break;
case htons(ETH_P_IPV6):
- if (pskb_network_may_pull(skb, sizeof(struct ipv6hdr)))
- return ntohl(ipv6_hdr(skb)->saddr.s6_addr32[3]);
+ data = skb_header_pointer(skb,
+ nhoff + offsetof(struct ipv6hdr,
+ saddr.s6_addr32[3]),
+ 4, &hdata);
break;
}
+ if (data)
+ return ntohl(*data);
return addr_fold(skb->sk);
}
-static u32 flow_get_dst(struct sk_buff *skb)
+static u32 flow_get_dst(const struct sk_buff *skb, int nhoff)
{
+ __be32 *data = NULL, hdata;
+
switch (skb->protocol) {
case htons(ETH_P_IP):
- if (pskb_network_may_pull(skb, sizeof(struct iphdr)))
- return ntohl(ip_hdr(skb)->daddr);
+ data = skb_header_pointer(skb,
+ nhoff + offsetof(struct iphdr,
+ daddr),
+ 4, &hdata);
break;
case htons(ETH_P_IPV6):
- if (pskb_network_may_pull(skb, sizeof(struct ipv6hdr)))
- return ntohl(ipv6_hdr(skb)->daddr.s6_addr32[3]);
+ data = skb_header_pointer(skb,
+ nhoff + offsetof(struct ipv6hdr,
+ daddr.s6_addr32[3]),
+ 4, &hdata);
break;
}
+ if (data)
+ return ntohl(*data);
return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol;
}
-static u32 flow_get_proto(struct sk_buff *skb)
+static u32 flow_get_proto(const struct sk_buff *skb, int nhoff)
{
+ __u8 *data = NULL, hdata;
+
switch (skb->protocol) {
case htons(ETH_P_IP):
- return pskb_network_may_pull(skb, sizeof(struct iphdr)) ?
- ip_hdr(skb)->protocol : 0;
+ data = skb_header_pointer(skb,
+ nhoff + offsetof(struct iphdr,
+ protocol),
+ 1, &hdata);
+ break;
case htons(ETH_P_IPV6):
- return pskb_network_may_pull(skb, sizeof(struct ipv6hdr)) ?
- ipv6_hdr(skb)->nexthdr : 0;
- default:
- return 0;
+ data = skb_header_pointer(skb,
+ nhoff + offsetof(struct ipv6hdr,
+ nexthdr),
+ 1, &hdata);
+ break;
}
+ if (data)
+ return *data;
+ return 0;
}
-static u32 flow_get_proto_src(struct sk_buff *skb)
+/* helper function to get either src or dst port */
+static __be16 *flow_get_proto_common(const struct sk_buff *skb, int nhoff,
+ __be16 *_port, int dst)
{
+ __be16 *port = NULL;
+ int poff;
+
switch (skb->protocol) {
case htons(ETH_P_IP): {
- struct iphdr *iph;
- int poff;
+ struct iphdr *iph, _iph;
- if (!pskb_network_may_pull(skb, sizeof(*iph)))
+ iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
+ if (!iph)
break;
- iph = ip_hdr(skb);
if (ip_is_fragment(iph))
break;
poff = proto_ports_offset(iph->protocol);
- if (poff >= 0 &&
- pskb_network_may_pull(skb, iph->ihl * 4 + 2 + poff)) {
- iph = ip_hdr(skb);
- return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 +
- poff));
- }
+ if (poff >= 0)
+ port = skb_header_pointer(skb,
+ nhoff + iph->ihl * 4 + poff + dst,
+ sizeof(*_port), _port);
break;
}
case htons(ETH_P_IPV6): {
- struct ipv6hdr *iph;
- int poff;
+ struct ipv6hdr *iph, _iph;
- if (!pskb_network_may_pull(skb, sizeof(*iph)))
+ iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
+ if (!iph)
break;
- iph = ipv6_hdr(skb);
poff = proto_ports_offset(iph->nexthdr);
- if (poff >= 0 &&
- pskb_network_may_pull(skb, sizeof(*iph) + poff + 2)) {
- iph = ipv6_hdr(skb);
- return ntohs(*(__be16 *)((void *)iph + sizeof(*iph) +
- poff));
- }
+ if (poff >= 0)
+ port = skb_header_pointer(skb,
+ nhoff + sizeof(*iph) + poff + dst,
+ sizeof(*_port), _port);
break;
}
}
- return addr_fold(skb->sk);
+ return port;
}
-static u32 flow_get_proto_dst(struct sk_buff *skb)
+static u32 flow_get_proto_src(const struct sk_buff *skb, int nhoff)
{
- switch (skb->protocol) {
- case htons(ETH_P_IP): {
- struct iphdr *iph;
- int poff;
+ __be16 _port, *port = flow_get_proto_common(skb, nhoff, &_port, 0);
- if (!pskb_network_may_pull(skb, sizeof(*iph)))
- break;
- iph = ip_hdr(skb);
- if (ip_is_fragment(iph))
- break;
- poff = proto_ports_offset(iph->protocol);
- if (poff >= 0 &&
- pskb_network_may_pull(skb, iph->ihl * 4 + 4 + poff)) {
- iph = ip_hdr(skb);
- return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 +
- 2 + poff));
- }
- break;
- }
- case htons(ETH_P_IPV6): {
- struct ipv6hdr *iph;
- int poff;
+ if (port)
+ return ntohs(*port);
- if (!pskb_network_may_pull(skb, sizeof(*iph)))
- break;
- iph = ipv6_hdr(skb);
- poff = proto_ports_offset(iph->nexthdr);
- if (poff >= 0 &&
- pskb_network_may_pull(skb, sizeof(*iph) + poff + 4)) {
- iph = ipv6_hdr(skb);
- return ntohs(*(__be16 *)((void *)iph + sizeof(*iph) +
- poff + 2));
- }
- break;
- }
- }
+ return addr_fold(skb->sk);
+}
+
+static u32 flow_get_proto_dst(const struct sk_buff *skb, int nhoff)
+{
+ __be16 _port, *port = flow_get_proto_common(skb, nhoff, &_port, 2);
+
+ if (port)
+ return ntohs(*port);
return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol;
}
@@ -223,7 +225,7 @@ static u32 flow_get_nfct(const struct sk_buff *skb)
#define CTTUPLE(skb, member) \
({ \
enum ip_conntrack_info ctinfo; \
- struct nf_conn *ct = nf_ct_get(skb, &ctinfo); \
+ const struct nf_conn *ct = nf_ct_get(skb, &ctinfo); \
if (ct == NULL) \
goto fallback; \
ct->tuplehash[CTINFO2DIR(ctinfo)].tuple.member; \
@@ -236,7 +238,7 @@ static u32 flow_get_nfct(const struct sk_buff *skb)
})
#endif
-static u32 flow_get_nfct_src(struct sk_buff *skb)
+static u32 flow_get_nfct_src(const struct sk_buff *skb, int nhoff)
{
switch (skb->protocol) {
case htons(ETH_P_IP):
@@ -245,10 +247,10 @@ static u32 flow_get_nfct_src(struct sk_buff *skb)
return ntohl(CTTUPLE(skb, src.u3.ip6[3]));
}
fallback:
- return flow_get_src(skb);
+ return flow_get_src(skb, nhoff);
}
-static u32 flow_get_nfct_dst(struct sk_buff *skb)
+static u32 flow_get_nfct_dst(const struct sk_buff *skb, int nhoff)
{
switch (skb->protocol) {
case htons(ETH_P_IP):
@@ -257,21 +259,21 @@ static u32 flow_get_nfct_dst(struct sk_buff *skb)
return ntohl(CTTUPLE(skb, dst.u3.ip6[3]));
}
fallback:
- return flow_get_dst(skb);
+ return flow_get_dst(skb, nhoff);
}
-static u32 flow_get_nfct_proto_src(struct sk_buff *skb)
+static u32 flow_get_nfct_proto_src(const struct sk_buff *skb, int nhoff)
{
return ntohs(CTTUPLE(skb, src.u.all));
fallback:
- return flow_get_proto_src(skb);
+ return flow_get_proto_src(skb, nhoff);
}
-static u32 flow_get_nfct_proto_dst(struct sk_buff *skb)
+static u32 flow_get_nfct_proto_dst(const struct sk_buff *skb, int nhoff)
{
return ntohs(CTTUPLE(skb, dst.u.all));
fallback:
- return flow_get_proto_dst(skb);
+ return flow_get_proto_dst(skb, nhoff);
}
static u32 flow_get_rtclassid(const struct sk_buff *skb)
@@ -313,17 +315,19 @@ static u32 flow_get_rxhash(struct sk_buff *skb)
static u32 flow_key_get(struct sk_buff *skb, int key)
{
+ int nhoff = skb_network_offset(skb);
+
switch (key) {
case FLOW_KEY_SRC:
- return flow_get_src(skb);
+ return flow_get_src(skb, nhoff);
case FLOW_KEY_DST:
- return flow_get_dst(skb);
+ return flow_get_dst(skb, nhoff);
case FLOW_KEY_PROTO:
- return flow_get_proto(skb);
+ return flow_get_proto(skb, nhoff);
case FLOW_KEY_PROTO_SRC:
- return flow_get_proto_src(skb);
+ return flow_get_proto_src(skb, nhoff);
case FLOW_KEY_PROTO_DST:
- return flow_get_proto_dst(skb);
+ return flow_get_proto_dst(skb, nhoff);
case FLOW_KEY_IIF:
return flow_get_iif(skb);
case FLOW_KEY_PRIORITY:
@@ -333,13 +337,13 @@ static u32 flow_key_get(struct sk_buff *skb, int key)
case FLOW_KEY_NFCT:
return flow_get_nfct(skb);
case FLOW_KEY_NFCT_SRC:
- return flow_get_nfct_src(skb);
+ return flow_get_nfct_src(skb, nhoff);
case FLOW_KEY_NFCT_DST:
- return flow_get_nfct_dst(skb);
+ return flow_get_nfct_dst(skb, nhoff);
case FLOW_KEY_NFCT_PROTO_SRC:
- return flow_get_nfct_proto_src(skb);
+ return flow_get_nfct_proto_src(skb, nhoff);
case FLOW_KEY_NFCT_PROTO_DST:
- return flow_get_nfct_proto_dst(skb);
+ return flow_get_nfct_proto_dst(skb, nhoff);
case FLOW_KEY_RTCLASSID:
return flow_get_rtclassid(skb);
case FLOW_KEY_SKUID:
diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h
index be4505ee67a9..b01427924f81 100644
--- a/net/sched/cls_rsvp.h
+++ b/net/sched/cls_rsvp.h
@@ -425,7 +425,7 @@ static int rsvp_change(struct tcf_proto *tp, unsigned long base,
struct rsvp_filter *f, **fp;
struct rsvp_session *s, **sp;
struct tc_rsvp_pinfo *pinfo = NULL;
- struct nlattr *opt = tca[TCA_OPTIONS-1];
+ struct nlattr *opt = tca[TCA_OPTIONS];
struct nlattr *tb[TCA_RSVP_MAX + 1];
struct tcf_exts e;
unsigned int h1, h2;
@@ -439,7 +439,7 @@ static int rsvp_change(struct tcf_proto *tp, unsigned long base,
if (err < 0)
return err;
- err = tcf_exts_validate(tp, tb, tca[TCA_RATE-1], &e, &rsvp_ext_map);
+ err = tcf_exts_validate(tp, tb, tca[TCA_RATE], &e, &rsvp_ext_map);
if (err < 0)
return err;
@@ -449,8 +449,8 @@ static int rsvp_change(struct tcf_proto *tp, unsigned long base,
if (f->handle != handle && handle)
goto errout2;
- if (tb[TCA_RSVP_CLASSID-1]) {
- f->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID-1]);
+ if (tb[TCA_RSVP_CLASSID]) {
+ f->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID]);
tcf_bind_filter(tp, &f->res, base);
}
@@ -462,7 +462,7 @@ static int rsvp_change(struct tcf_proto *tp, unsigned long base,
err = -EINVAL;
if (handle)
goto errout2;
- if (tb[TCA_RSVP_DST-1] == NULL)
+ if (tb[TCA_RSVP_DST] == NULL)
goto errout2;
err = -ENOBUFS;
@@ -471,19 +471,19 @@ static int rsvp_change(struct tcf_proto *tp, unsigned long base,
goto errout2;
h2 = 16;
- if (tb[TCA_RSVP_SRC-1]) {
- memcpy(f->src, nla_data(tb[TCA_RSVP_SRC-1]), sizeof(f->src));
+ if (tb[TCA_RSVP_SRC]) {
+ memcpy(f->src, nla_data(tb[TCA_RSVP_SRC]), sizeof(f->src));
h2 = hash_src(f->src);
}
- if (tb[TCA_RSVP_PINFO-1]) {
- pinfo = nla_data(tb[TCA_RSVP_PINFO-1]);
+ if (tb[TCA_RSVP_PINFO]) {
+ pinfo = nla_data(tb[TCA_RSVP_PINFO]);
f->spi = pinfo->spi;
f->tunnelhdr = pinfo->tunnelhdr;
}
- if (tb[TCA_RSVP_CLASSID-1])
- f->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID-1]);
+ if (tb[TCA_RSVP_CLASSID])
+ f->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID]);
- dst = nla_data(tb[TCA_RSVP_DST-1]);
+ dst = nla_data(tb[TCA_RSVP_DST]);
h1 = hash_dst(dst, pinfo ? pinfo->protocol : 0, pinfo ? pinfo->tunnelid : 0);
err = -ENOMEM;
@@ -642,8 +642,7 @@ nla_put_failure:
return -1;
}
-static struct tcf_proto_ops RSVP_OPS = {
- .next = NULL,
+static struct tcf_proto_ops RSVP_OPS __read_mostly = {
.kind = RSVP_ID,
.classify = rsvp_classify,
.init = rsvp_init,
diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c
index 0a833d0c1f61..e83c272c0325 100644
--- a/net/sched/sch_sfb.c
+++ b/net/sched/sch_sfb.c
@@ -287,6 +287,12 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch)
u32 r, slot, salt, sfbhash;
int ret = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
+ if (unlikely(sch->q.qlen >= q->limit)) {
+ sch->qstats.overlimits++;
+ q->stats.queuedrop++;
+ goto drop;
+ }
+
if (q->rehash_interval > 0) {
unsigned long limit = q->rehash_time + q->rehash_interval;
@@ -332,12 +338,9 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch)
slot ^= 1;
sfb_skb_cb(skb)->hashes[slot] = 0;
- if (unlikely(minqlen >= q->max || sch->q.qlen >= q->limit)) {
+ if (unlikely(minqlen >= q->max)) {
sch->qstats.overlimits++;
- if (minqlen >= q->max)
- q->stats.bucketdrop++;
- else
- q->stats.queuedrop++;
+ q->stats.bucketdrop++;
goto drop;
}
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index dc16b90ddb6f..152b5b3c3fff 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -282,6 +282,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
asoc->peer.asconf_capable = 1;
asoc->asconf_addr_del_pending = NULL;
asoc->src_out_of_asoc_ok = 0;
+ asoc->new_transport = NULL;
/* Create an input queue. */
sctp_inq_init(&asoc->base.inqueue);
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index a6d27bf563a5..14c2b06028ff 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -917,6 +917,8 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
* current cwnd).
*/
if (!list_empty(&q->retransmit)) {
+ if (asoc->peer.retran_path->state == SCTP_UNCONFIRMED)
+ goto sctp_flush_out;
if (transport == asoc->peer.retran_path)
goto retran;
@@ -989,6 +991,8 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
((new_transport->state == SCTP_INACTIVE) ||
(new_transport->state == SCTP_UNCONFIRMED)))
new_transport = asoc->peer.active_path;
+ if (new_transport->state == SCTP_UNCONFIRMED)
+ continue;
/* Change packets if necessary. */
if (new_transport != transport) {
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 91784f44a2e2..61b9fca5a173 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -1299,7 +1299,7 @@ SCTP_STATIC __init int sctp_init(void)
max_share = min(4UL*1024*1024, limit);
sysctl_sctp_rmem[0] = SK_MEM_QUANTUM; /* give each asoc 1 page min */
- sysctl_sctp_rmem[1] = (1500 *(sizeof(struct sk_buff) + 1));
+ sysctl_sctp_rmem[1] = 1500 * SKB_TRUESIZE(1);
sysctl_sctp_rmem[2] = max(sysctl_sctp_rmem[1], max_share);
sysctl_sctp_wmem[0] = SK_MEM_QUANTUM;
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 81db4e385352..0121e0ab0351 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -3015,6 +3015,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
/* Start the heartbeat timer. */
if (!mod_timer(&peer->hb_timer, sctp_transport_timeout(peer)))
sctp_transport_hold(peer);
+ asoc->new_transport = peer;
break;
case SCTP_PARAM_DEL_IP:
/* ADDIP 4.3 D7) If a request is received to delete the
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index 167c880cf8da..76388b083f28 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -1689,6 +1689,11 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
case SCTP_CMD_PURGE_ASCONF_QUEUE:
sctp_asconf_queue_teardown(asoc);
break;
+
+ case SCTP_CMD_SET_ASOC:
+ asoc = cmd->obj.asoc;
+ break;
+
default:
pr_warn("Impossible command: %u, %p\n",
cmd->verb, cmd->obj.ptr);
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 49b847b00f99..891f5db8cc31 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -2047,6 +2047,12 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const struct sctp_endpoint *ep,
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc));
sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
+ /* Restore association pointer to provide SCTP command interpeter
+ * with a valid context in case it needs to manipulate
+ * the queues */
+ sctp_add_cmd_sf(commands, SCTP_CMD_SET_ASOC,
+ SCTP_ASOC((struct sctp_association *)asoc));
+
return retval;
nomem:
@@ -3612,6 +3618,11 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
*/
asconf_ack->dest = chunk->source;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(asconf_ack));
+ if (asoc->new_transport) {
+ sctp_sf_heartbeat(ep, asoc, type, asoc->new_transport,
+ commands);
+ ((struct sctp_association *)asoc)->new_transport = NULL;
+ }
return SCTP_DISPOSITION_CONSUME;
}
diff --git a/net/socket.c b/net/socket.c
index 24a77400b65e..2877647f347b 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1965,8 +1965,9 @@ static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
* used_address->name_len is initialized to UINT_MAX so that the first
* destination address never matches.
*/
- if (used_address && used_address->name_len == msg_sys->msg_namelen &&
- !memcmp(&used_address->name, msg->msg_name,
+ if (used_address && msg_sys->msg_name &&
+ used_address->name_len == msg_sys->msg_namelen &&
+ !memcmp(&used_address->name, msg_sys->msg_name,
used_address->name_len)) {
err = sock_sendmsg_nosec(sock, msg_sys, total_len);
goto out_freectl;
@@ -1978,8 +1979,9 @@ static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
*/
if (used_address && err >= 0) {
used_address->name_len = msg_sys->msg_namelen;
- memcpy(&used_address->name, msg->msg_name,
- used_address->name_len);
+ if (msg_sys->msg_name)
+ memcpy(&used_address->name, msg_sys->msg_name,
+ used_address->name_len);
}
out_freectl:
@@ -2470,7 +2472,7 @@ int sock_register(const struct net_proto_family *ops)
lockdep_is_held(&net_family_lock)))
err = -EEXIST;
else {
- rcu_assign_pointer(net_families[ops->family], ops);
+ RCU_INIT_POINTER(net_families[ops->family], ops);
err = 0;
}
spin_unlock(&net_family_lock);
@@ -2498,7 +2500,7 @@ void sock_unregister(int family)
BUG_ON(family < 0 || family >= NPROTO);
spin_lock(&net_family_lock);
- rcu_assign_pointer(net_families[family], NULL);
+ RCU_INIT_POINTER(net_families[family], NULL);
spin_unlock(&net_family_lock);
synchronize_rcu();
diff --git a/net/sunrpc/addr.c b/net/sunrpc/addr.c
index 4195233c4914..4548757c9871 100644
--- a/net/sunrpc/addr.c
+++ b/net/sunrpc/addr.c
@@ -255,12 +255,13 @@ EXPORT_SYMBOL_GPL(rpc_pton);
/**
* rpc_sockaddr2uaddr - Construct a universal address string from @sap.
* @sap: socket address
+ * @gfp_flags: allocation mode
*
* Returns a %NUL-terminated string in dynamically allocated memory;
* otherwise NULL is returned if an error occurred. Caller must
* free the returned string.
*/
-char *rpc_sockaddr2uaddr(const struct sockaddr *sap)
+char *rpc_sockaddr2uaddr(const struct sockaddr *sap, gfp_t gfp_flags)
{
char portbuf[RPCBIND_MAXUADDRPLEN];
char addrbuf[RPCBIND_MAXUADDRLEN];
@@ -288,9 +289,8 @@ char *rpc_sockaddr2uaddr(const struct sockaddr *sap)
if (strlcat(addrbuf, portbuf, sizeof(addrbuf)) > sizeof(addrbuf))
return NULL;
- return kstrdup(addrbuf, GFP_KERNEL);
+ return kstrdup(addrbuf, gfp_flags);
}
-EXPORT_SYMBOL_GPL(rpc_sockaddr2uaddr);
/**
* rpc_uaddr2sockaddr - convert a universal address to a socket address.
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 364eb45e989d..afb56553dfe7 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -122,7 +122,7 @@ gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx)
if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags))
return;
gss_get_ctx(ctx);
- rcu_assign_pointer(gss_cred->gc_ctx, ctx);
+ RCU_INIT_POINTER(gss_cred->gc_ctx, ctx);
set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
smp_mb__before_clear_bit();
clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags);
@@ -603,26 +603,6 @@ out:
return err;
}
-static ssize_t
-gss_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg,
- char __user *dst, size_t buflen)
-{
- char *data = (char *)msg->data + msg->copied;
- size_t mlen = min(msg->len, buflen);
- unsigned long left;
-
- left = copy_to_user(dst, data, mlen);
- if (left == mlen) {
- msg->errno = -EFAULT;
- return -EFAULT;
- }
-
- mlen -= left;
- msg->copied += mlen;
- msg->errno = 0;
- return mlen;
-}
-
#define MSG_BUF_MAXSIZE 1024
static ssize_t
@@ -970,7 +950,7 @@ gss_destroy_nullcred(struct rpc_cred *cred)
struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth);
struct gss_cl_ctx *ctx = gss_cred->gc_ctx;
- rcu_assign_pointer(gss_cred->gc_ctx, NULL);
+ RCU_INIT_POINTER(gss_cred->gc_ctx, NULL);
call_rcu(&cred->cr_rcu, gss_free_cred_callback);
if (ctx)
gss_put_ctx(ctx);
@@ -1590,7 +1570,7 @@ static const struct rpc_credops gss_nullops = {
};
static const struct rpc_pipe_ops gss_upcall_ops_v0 = {
- .upcall = gss_pipe_upcall,
+ .upcall = rpc_pipe_generic_upcall,
.downcall = gss_pipe_downcall,
.destroy_msg = gss_pipe_destroy_msg,
.open_pipe = gss_pipe_open_v0,
@@ -1598,7 +1578,7 @@ static const struct rpc_pipe_ops gss_upcall_ops_v0 = {
};
static const struct rpc_pipe_ops gss_upcall_ops_v1 = {
- .upcall = gss_pipe_upcall,
+ .upcall = rpc_pipe_generic_upcall,
.downcall = gss_pipe_downcall,
.destroy_msg = gss_pipe_destroy_msg,
.open_pipe = gss_pipe_open_v1,
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index c5347d29cfb7..f0268ea7e711 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -850,7 +850,9 @@ rpc_restart_call_prepare(struct rpc_task *task)
{
if (RPC_ASSASSINATED(task))
return 0;
- task->tk_action = rpc_prepare_task;
+ task->tk_action = call_start;
+ if (task->tk_ops->rpc_call_prepare != NULL)
+ task->tk_action = rpc_prepare_task;
return 1;
}
EXPORT_SYMBOL_GPL(rpc_restart_call_prepare);
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index b181e3441323..bfddd68b31d3 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -77,6 +77,26 @@ rpc_timeout_upcall_queue(struct work_struct *work)
rpc_purge_list(rpci, &free_list, destroy_msg, -ETIMEDOUT);
}
+ssize_t rpc_pipe_generic_upcall(struct file *filp, struct rpc_pipe_msg *msg,
+ char __user *dst, size_t buflen)
+{
+ char *data = (char *)msg->data + msg->copied;
+ size_t mlen = min(msg->len - msg->copied, buflen);
+ unsigned long left;
+
+ left = copy_to_user(dst, data, mlen);
+ if (left == mlen) {
+ msg->errno = -EFAULT;
+ return -EFAULT;
+ }
+
+ mlen -= left;
+ msg->copied += mlen;
+ msg->errno = 0;
+ return mlen;
+}
+EXPORT_SYMBOL_GPL(rpc_pipe_generic_upcall);
+
/**
* rpc_queue_upcall - queue an upcall message to userspace
* @inode: inode of upcall pipe on which to queue given message
@@ -1084,3 +1104,6 @@ void unregister_rpc_pipefs(void)
kmem_cache_destroy(rpc_inode_cachep);
unregister_filesystem(&rpc_pipe_fs_type);
}
+
+/* Make 'mount -t rpc_pipefs ...' autoload this module. */
+MODULE_ALIAS("rpc_pipefs");
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index e45d2fbbe5a8..f588b852d41c 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -410,7 +410,7 @@ static int rpcb_register_inet4(const struct sockaddr *sap,
unsigned short port = ntohs(sin->sin_port);
int result;
- map->r_addr = rpc_sockaddr2uaddr(sap);
+ map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL);
dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with "
"local rpcbind\n", (port ? "" : "un"),
@@ -437,7 +437,7 @@ static int rpcb_register_inet6(const struct sockaddr *sap,
unsigned short port = ntohs(sin6->sin6_port);
int result;
- map->r_addr = rpc_sockaddr2uaddr(sap);
+ map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL);
dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with "
"local rpcbind\n", (port ? "" : "un"),
@@ -686,7 +686,7 @@ void rpcb_getport_async(struct rpc_task *task)
case RPCBVERS_4:
case RPCBVERS_3:
map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID);
- map->r_addr = rpc_sockaddr2uaddr(sap);
+ map->r_addr = rpc_sockaddr2uaddr(sap, GFP_ATOMIC);
map->r_owner = "";
break;
case RPCBVERS_2:
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 6a69a1131fb7..30d70abb4e2c 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -295,6 +295,18 @@ svc_pool_map_put(void)
}
+static int svc_pool_map_get_node(unsigned int pidx)
+{
+ const struct svc_pool_map *m = &svc_pool_map;
+
+ if (m->count) {
+ if (m->mode == SVC_POOL_PERCPU)
+ return cpu_to_node(m->pool_to[pidx]);
+ if (m->mode == SVC_POOL_PERNODE)
+ return m->pool_to[pidx];
+ }
+ return NUMA_NO_NODE;
+}
/*
* Set the given thread's cpus_allowed mask so that it
* will only run on cpus in the given pool.
@@ -499,7 +511,7 @@ EXPORT_SYMBOL_GPL(svc_destroy);
* We allocate pages and place them in rq_argpages.
*/
static int
-svc_init_buffer(struct svc_rqst *rqstp, unsigned int size)
+svc_init_buffer(struct svc_rqst *rqstp, unsigned int size, int node)
{
unsigned int pages, arghi;
@@ -513,7 +525,7 @@ svc_init_buffer(struct svc_rqst *rqstp, unsigned int size)
arghi = 0;
BUG_ON(pages > RPCSVC_MAXPAGES);
while (pages) {
- struct page *p = alloc_page(GFP_KERNEL);
+ struct page *p = alloc_pages_node(node, GFP_KERNEL, 0);
if (!p)
break;
rqstp->rq_pages[arghi++] = p;
@@ -536,11 +548,11 @@ svc_release_buffer(struct svc_rqst *rqstp)
}
struct svc_rqst *
-svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool)
+svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node)
{
struct svc_rqst *rqstp;
- rqstp = kzalloc(sizeof(*rqstp), GFP_KERNEL);
+ rqstp = kzalloc_node(sizeof(*rqstp), GFP_KERNEL, node);
if (!rqstp)
goto out_enomem;
@@ -554,15 +566,15 @@ svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool)
rqstp->rq_server = serv;
rqstp->rq_pool = pool;
- rqstp->rq_argp = kmalloc(serv->sv_xdrsize, GFP_KERNEL);
+ rqstp->rq_argp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node);
if (!rqstp->rq_argp)
goto out_thread;
- rqstp->rq_resp = kmalloc(serv->sv_xdrsize, GFP_KERNEL);
+ rqstp->rq_resp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node);
if (!rqstp->rq_resp)
goto out_thread;
- if (!svc_init_buffer(rqstp, serv->sv_max_mesg))
+ if (!svc_init_buffer(rqstp, serv->sv_max_mesg, node))
goto out_thread;
return rqstp;
@@ -647,6 +659,7 @@ svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
struct svc_pool *chosen_pool;
int error = 0;
unsigned int state = serv->sv_nrthreads-1;
+ int node;
if (pool == NULL) {
/* The -1 assumes caller has done a svc_get() */
@@ -662,14 +675,16 @@ svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
nrservs--;
chosen_pool = choose_pool(serv, pool, &state);
- rqstp = svc_prepare_thread(serv, chosen_pool);
+ node = svc_pool_map_get_node(chosen_pool->sp_id);
+ rqstp = svc_prepare_thread(serv, chosen_pool, node);
if (IS_ERR(rqstp)) {
error = PTR_ERR(rqstp);
break;
}
__module_get(serv->sv_module);
- task = kthread_create(serv->sv_function, rqstp, serv->sv_name);
+ task = kthread_create_on_node(serv->sv_function, rqstp,
+ node, serv->sv_name);
if (IS_ERR(task)) {
error = PTR_ERR(task);
module_put(serv->sv_module);
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index bd31208bbb61..d86bb673e1f6 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -254,8 +254,6 @@ EXPORT_SYMBOL_GPL(svc_create_xprt);
*/
void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt)
{
- struct sockaddr *sin;
-
memcpy(&rqstp->rq_addr, &xprt->xpt_remote, xprt->xpt_remotelen);
rqstp->rq_addrlen = xprt->xpt_remotelen;
@@ -263,15 +261,8 @@ void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt)
* Destination address in request is needed for binding the
* source address in RPC replies/callbacks later.
*/
- sin = (struct sockaddr *)&xprt->xpt_local;
- switch (sin->sa_family) {
- case AF_INET:
- rqstp->rq_daddr.addr = ((struct sockaddr_in *)sin)->sin_addr;
- break;
- case AF_INET6:
- rqstp->rq_daddr.addr6 = ((struct sockaddr_in6 *)sin)->sin6_addr;
- break;
- }
+ memcpy(&rqstp->rq_daddr, &xprt->xpt_local, xprt->xpt_locallen);
+ rqstp->rq_daddrlen = xprt->xpt_locallen;
}
EXPORT_SYMBOL_GPL(svc_xprt_copy_addrs);
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 767d494de7a2..dfd686eb0b7f 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -143,19 +143,20 @@ static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh)
cmh->cmsg_level = SOL_IP;
cmh->cmsg_type = IP_PKTINFO;
pki->ipi_ifindex = 0;
- pki->ipi_spec_dst.s_addr = rqstp->rq_daddr.addr.s_addr;
+ pki->ipi_spec_dst.s_addr =
+ svc_daddr_in(rqstp)->sin_addr.s_addr;
cmh->cmsg_len = CMSG_LEN(sizeof(*pki));
}
break;
case AF_INET6: {
struct in6_pktinfo *pki = CMSG_DATA(cmh);
+ struct sockaddr_in6 *daddr = svc_daddr_in6(rqstp);
cmh->cmsg_level = SOL_IPV6;
cmh->cmsg_type = IPV6_PKTINFO;
- pki->ipi6_ifindex = 0;
- ipv6_addr_copy(&pki->ipi6_addr,
- &rqstp->rq_daddr.addr6);
+ pki->ipi6_ifindex = daddr->sin6_scope_id;
+ ipv6_addr_copy(&pki->ipi6_addr, &daddr->sin6_addr);
cmh->cmsg_len = CMSG_LEN(sizeof(*pki));
}
break;
@@ -498,9 +499,13 @@ static int svc_udp_get_dest_address4(struct svc_rqst *rqstp,
struct cmsghdr *cmh)
{
struct in_pktinfo *pki = CMSG_DATA(cmh);
+ struct sockaddr_in *daddr = svc_daddr_in(rqstp);
+
if (cmh->cmsg_type != IP_PKTINFO)
return 0;
- rqstp->rq_daddr.addr.s_addr = pki->ipi_spec_dst.s_addr;
+
+ daddr->sin_family = AF_INET;
+ daddr->sin_addr.s_addr = pki->ipi_spec_dst.s_addr;
return 1;
}
@@ -511,9 +516,14 @@ static int svc_udp_get_dest_address6(struct svc_rqst *rqstp,
struct cmsghdr *cmh)
{
struct in6_pktinfo *pki = CMSG_DATA(cmh);
+ struct sockaddr_in6 *daddr = svc_daddr_in6(rqstp);
+
if (cmh->cmsg_type != IPV6_PKTINFO)
return 0;
- ipv6_addr_copy(&rqstp->rq_daddr.addr6, &pki->ipi6_addr);
+
+ daddr->sin6_family = AF_INET6;
+ ipv6_addr_copy(&daddr->sin6_addr, &pki->ipi6_addr);
+ daddr->sin6_scope_id = pki->ipi6_ifindex;
return 1;
}
@@ -614,6 +624,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
skb_free_datagram_locked(svsk->sk_sk, skb);
return 0;
}
+ rqstp->rq_daddrlen = svc_addr_len(svc_daddr(rqstp));
if (skb_is_nonlinear(skb)) {
/* we have to copy */
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index 759b318b5ffb..28908f54459e 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -39,6 +39,7 @@
#include "link.h"
#include "port.h"
#include "bcast.h"
+#include "name_distr.h"
#define MAX_PKT_DEFAULT_MCAST 1500 /* bcast link max packet size (fixed) */
@@ -298,14 +299,9 @@ static void bclink_send_nack(struct tipc_node *n_ptr)
msg_set_bcgap_to(msg, n_ptr->bclink.gap_to);
msg_set_bcast_tag(msg, tipc_own_tag);
- if (tipc_bearer_send(&bcbearer->bearer, buf, NULL)) {
- bcl->stats.sent_nacks++;
- buf_discard(buf);
- } else {
- tipc_bearer_schedule(bcl->b_ptr, bcl);
- bcl->proto_msg_queue = buf;
- bcl->stats.bearer_congs++;
- }
+ tipc_bearer_send(&bcbearer->bearer, buf, NULL);
+ bcl->stats.sent_nacks++;
+ buf_discard(buf);
/*
* Ensure we doesn't send another NACK msg to the node
@@ -426,20 +422,28 @@ int tipc_bclink_send_msg(struct sk_buff *buf)
void tipc_bclink_recv_pkt(struct sk_buff *buf)
{
struct tipc_msg *msg = buf_msg(buf);
- struct tipc_node *node = tipc_node_find(msg_prevnode(msg));
+ struct tipc_node *node;
u32 next_in;
u32 seqno;
struct sk_buff *deferred;
- if (unlikely(!node || !tipc_node_is_up(node) || !node->bclink.supported ||
- (msg_mc_netid(msg) != tipc_net_id))) {
- buf_discard(buf);
- return;
- }
+ /* Screen out unwanted broadcast messages */
+
+ if (msg_mc_netid(msg) != tipc_net_id)
+ goto exit;
+
+ node = tipc_node_find(msg_prevnode(msg));
+ if (unlikely(!node))
+ goto exit;
+
+ tipc_node_lock(node);
+ if (unlikely(!node->bclink.supported))
+ goto unlock;
if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) {
+ if (msg_type(msg) != STATE_MSG)
+ goto unlock;
if (msg_destnode(msg) == tipc_own_addr) {
- tipc_node_lock(node);
tipc_bclink_acknowledge(node, msg_bcast_ack(msg));
tipc_node_unlock(node);
spin_lock_bh(&bc_lock);
@@ -449,18 +453,18 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf)
msg_bcgap_to(msg));
spin_unlock_bh(&bc_lock);
} else {
+ tipc_node_unlock(node);
tipc_bclink_peek_nack(msg_destnode(msg),
msg_bcast_tag(msg),
msg_bcgap_after(msg),
msg_bcgap_to(msg));
}
- buf_discard(buf);
- return;
+ goto exit;
}
- tipc_node_lock(node);
+ /* Handle in-sequence broadcast message */
+
receive:
- deferred = node->bclink.deferred_head;
next_in = mod(node->bclink.last_in + 1);
seqno = msg_seqno(msg);
@@ -474,7 +478,10 @@ receive:
}
if (likely(msg_isdata(msg))) {
tipc_node_unlock(node);
- tipc_port_recv_mcast(buf, NULL);
+ if (likely(msg_mcast(msg)))
+ tipc_port_recv_mcast(buf, NULL);
+ else
+ buf_discard(buf);
} else if (msg_user(msg) == MSG_BUNDLER) {
bcl->stats.recv_bundles++;
bcl->stats.recv_bundled += msg_msgcnt(msg);
@@ -487,18 +494,22 @@ receive:
bcl->stats.recv_fragmented++;
tipc_node_unlock(node);
tipc_net_route_msg(buf);
+ } else if (msg_user(msg) == NAME_DISTRIBUTOR) {
+ tipc_node_unlock(node);
+ tipc_named_recv(buf);
} else {
tipc_node_unlock(node);
- tipc_net_route_msg(buf);
+ buf_discard(buf);
}
+ buf = NULL;
+ tipc_node_lock(node);
+ deferred = node->bclink.deferred_head;
if (deferred && (buf_seqno(deferred) == mod(next_in + 1))) {
- tipc_node_lock(node);
buf = deferred;
msg = buf_msg(buf);
node->bclink.deferred_head = deferred->next;
goto receive;
}
- return;
} else if (less(next_in, seqno)) {
u32 gap_after = node->bclink.gap_after;
u32 gap_to = node->bclink.gap_to;
@@ -513,6 +524,7 @@ receive:
else if (less(gap_after, seqno) && less(seqno, gap_to))
node->bclink.gap_to = seqno;
}
+ buf = NULL;
if (bclink_ack_allowed(node->bclink.nack_sync)) {
if (gap_to != gap_after)
bclink_send_nack(node);
@@ -520,9 +532,11 @@ receive:
}
} else {
bcl->stats.duplicates++;
- buf_discard(buf);
}
+unlock:
tipc_node_unlock(node);
+exit:
+ buf_discard(buf);
}
u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr)
@@ -535,10 +549,11 @@ u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr)
/**
* tipc_bcbearer_send - send a packet through the broadcast pseudo-bearer
*
- * Send through as many bearers as necessary to reach all nodes
- * that support TIPC multicasting.
+ * Send packet over as many bearers as necessary to reach all nodes
+ * that have joined the broadcast link.
*
- * Returns 0 if packet sent successfully, non-zero if not
+ * Returns 0 (packet sent successfully) under all circumstances,
+ * since the broadcast link's pseudo-bearer never blocks
*/
static int tipc_bcbearer_send(struct sk_buff *buf,
@@ -547,7 +562,12 @@ static int tipc_bcbearer_send(struct sk_buff *buf,
{
int bp_index;
- /* Prepare buffer for broadcasting (if first time trying to send it) */
+ /*
+ * Prepare broadcast link message for reliable transmission,
+ * if first time trying to send it;
+ * preparation is skipped for broadcast link protocol messages
+ * since they are sent in an unreliable manner and don't need it
+ */
if (likely(!msg_non_seq(buf_msg(buf)))) {
struct tipc_msg *msg;
@@ -596,18 +616,12 @@ static int tipc_bcbearer_send(struct sk_buff *buf,
}
if (bcbearer->remains_new.count == 0)
- return 0;
+ break; /* all targets reached */
bcbearer->remains = bcbearer->remains_new;
}
- /*
- * Unable to reach all targets (indicate success, since currently
- * there isn't code in place to properly block & unblock the
- * pseudo-bearer used by the broadcast link)
- */
-
- return TIPC_OK;
+ return 0;
}
/**
@@ -667,27 +681,6 @@ void tipc_bcbearer_sort(void)
spin_unlock_bh(&bc_lock);
}
-/**
- * tipc_bcbearer_push - resolve bearer congestion
- *
- * Forces bclink to push out any unsent packets, until all packets are gone
- * or congestion reoccurs.
- * No locks set when function called
- */
-
-void tipc_bcbearer_push(void)
-{
- struct tipc_bearer *b_ptr;
-
- spin_lock_bh(&bc_lock);
- b_ptr = &bcbearer->bearer;
- if (b_ptr->blocked) {
- b_ptr->blocked = 0;
- tipc_bearer_lock_push(b_ptr);
- }
- spin_unlock_bh(&bc_lock);
-}
-
int tipc_bclink_stats(char *buf, const u32 buf_size)
{
@@ -764,7 +757,7 @@ int tipc_bclink_init(void)
bcbearer = kzalloc(sizeof(*bcbearer), GFP_ATOMIC);
bclink = kzalloc(sizeof(*bclink), GFP_ATOMIC);
if (!bcbearer || !bclink) {
- warn("Multicast link creation failed, no memory\n");
+ warn("Broadcast link creation failed, no memory\n");
kfree(bcbearer);
bcbearer = NULL;
kfree(bclink);
@@ -775,7 +768,7 @@ int tipc_bclink_init(void)
INIT_LIST_HEAD(&bcbearer->bearer.cong_links);
bcbearer->bearer.media = &bcbearer->media;
bcbearer->media.send_msg = tipc_bcbearer_send;
- sprintf(bcbearer->media.name, "tipc-multicast");
+ sprintf(bcbearer->media.name, "tipc-broadcast");
bcl = &bclink->link;
INIT_LIST_HEAD(&bcl->waiting_ports);
diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h
index 500c97f1c859..06740da5ae61 100644
--- a/net/tipc/bcast.h
+++ b/net/tipc/bcast.h
@@ -101,6 +101,5 @@ int tipc_bclink_stats(char *stats_buf, const u32 buf_size);
int tipc_bclink_reset_stats(void);
int tipc_bclink_set_queue_limits(u32 limit);
void tipc_bcbearer_sort(void);
-void tipc_bcbearer_push(void);
#endif
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 85eba9c08ee9..e2202de3d93e 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -385,13 +385,9 @@ static int bearer_push(struct tipc_bearer *b_ptr)
void tipc_bearer_lock_push(struct tipc_bearer *b_ptr)
{
- int res;
-
spin_lock_bh(&b_ptr->lock);
- res = bearer_push(b_ptr);
+ bearer_push(b_ptr);
spin_unlock_bh(&b_ptr->lock);
- if (res)
- tipc_bcbearer_push();
}
@@ -608,6 +604,7 @@ int tipc_block_bearer(const char *name)
info("Blocking bearer <%s>\n", name);
spin_lock_bh(&b_ptr->lock);
b_ptr->blocked = 1;
+ list_splice_init(&b_ptr->cong_links, &b_ptr->links);
list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
struct tipc_node *n_ptr = l_ptr->owner;
@@ -635,6 +632,7 @@ static void bearer_disable(struct tipc_bearer *b_ptr)
spin_lock_bh(&b_ptr->lock);
b_ptr->blocked = 1;
b_ptr->media->disable_bearer(b_ptr);
+ list_splice_init(&b_ptr->cong_links, &b_ptr->links);
list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
tipc_link_delete(l_ptr);
}
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
index 5ad70eff1ebf..d696f9e414e3 100644
--- a/net/tipc/bearer.h
+++ b/net/tipc/bearer.h
@@ -39,8 +39,8 @@
#include "bcast.h"
-#define MAX_BEARERS 8
-#define MAX_MEDIA 4
+#define MAX_BEARERS 2
+#define MAX_MEDIA 2
/*
* Identifiers of supported TIPC media types
diff --git a/net/tipc/config.h b/net/tipc/config.h
index 443159a166fd..80da6ebc2785 100644
--- a/net/tipc/config.h
+++ b/net/tipc/config.h
@@ -65,7 +65,6 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd,
const void *req_tlv_area, int req_tlv_space,
int headroom);
-void tipc_cfg_link_event(u32 addr, char *name, int up);
int tipc_cfg_init(void);
void tipc_cfg_stop(void);
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
index 0987933155b9..f2fb96e86ee8 100644
--- a/net/tipc/discover.c
+++ b/net/tipc/discover.c
@@ -159,12 +159,6 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr)
}
tipc_node_lock(n_ptr);
- /* Don't talk to neighbor during cleanup after last session */
- if (n_ptr->cleanup_required) {
- tipc_node_unlock(n_ptr);
- return;
- }
-
link = n_ptr->links[b_ptr->identity];
/* Create a link endpoint for this bearer, if necessary */
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c
index b69092eb95d8..e728d4ce2a1b 100644
--- a/net/tipc/eth_media.c
+++ b/net/tipc/eth_media.c
@@ -2,7 +2,7 @@
* net/tipc/eth_media.c: Ethernet bearer support for TIPC
*
* Copyright (c) 2001-2007, Ericsson AB
- * Copyright (c) 2005-2007, Wind River Systems
+ * Copyright (c) 2005-2008, 2011, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -37,7 +37,7 @@
#include "core.h"
#include "bearer.h"
-#define MAX_ETH_BEARERS 2
+#define MAX_ETH_BEARERS MAX_BEARERS
#define ETH_LINK_PRIORITY TIPC_DEF_LINK_PRI
#define ETH_LINK_TOLERANCE TIPC_DEF_LINK_TOL
#define ETH_LINK_WINDOW TIPC_DEF_LINK_WIN
@@ -144,31 +144,27 @@ static int enable_bearer(struct tipc_bearer *tb_ptr)
/* Find device with specified name */
+ read_lock(&dev_base_lock);
for_each_netdev(&init_net, pdev) {
if (!strncmp(pdev->name, driver_name, IFNAMSIZ)) {
dev = pdev;
+ dev_hold(dev);
break;
}
}
+ read_unlock(&dev_base_lock);
if (!dev)
return -ENODEV;
- /* Find Ethernet bearer for device (or create one) */
-
- while ((eb_ptr != stop) && eb_ptr->dev && (eb_ptr->dev != dev))
- eb_ptr++;
- if (eb_ptr == stop)
- return -EDQUOT;
- if (!eb_ptr->dev) {
- eb_ptr->dev = dev;
- eb_ptr->tipc_packet_type.type = htons(ETH_P_TIPC);
- eb_ptr->tipc_packet_type.dev = dev;
- eb_ptr->tipc_packet_type.func = recv_msg;
- eb_ptr->tipc_packet_type.af_packet_priv = eb_ptr;
- INIT_LIST_HEAD(&(eb_ptr->tipc_packet_type.list));
- dev_hold(dev);
- dev_add_pack(&eb_ptr->tipc_packet_type);
- }
+ /* Create Ethernet bearer for device */
+
+ eb_ptr->dev = dev;
+ eb_ptr->tipc_packet_type.type = htons(ETH_P_TIPC);
+ eb_ptr->tipc_packet_type.dev = dev;
+ eb_ptr->tipc_packet_type.func = recv_msg;
+ eb_ptr->tipc_packet_type.af_packet_priv = eb_ptr;
+ INIT_LIST_HEAD(&(eb_ptr->tipc_packet_type.list));
+ dev_add_pack(&eb_ptr->tipc_packet_type);
/* Associate TIPC bearer with Ethernet bearer */
diff --git a/net/tipc/link.c b/net/tipc/link.c
index f89570c54f54..ae98a72da11a 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -332,15 +332,16 @@ struct link *tipc_link_create(struct tipc_node *n_ptr,
l_ptr->addr = peer;
if_name = strchr(b_ptr->name, ':') + 1;
- sprintf(l_ptr->name, "%u.%u.%u:%s-%u.%u.%u:",
+ sprintf(l_ptr->name, "%u.%u.%u:%s-%u.%u.%u:unknown",
tipc_zone(tipc_own_addr), tipc_cluster(tipc_own_addr),
tipc_node(tipc_own_addr),
if_name,
tipc_zone(peer), tipc_cluster(peer), tipc_node(peer));
- /* note: peer i/f is appended to link name by reset/activate */
+ /* note: peer i/f name is updated by reset/activate message */
memcpy(&l_ptr->media_addr, media_addr, sizeof(*media_addr));
l_ptr->owner = n_ptr;
l_ptr->checkpoint = 1;
+ l_ptr->peer_session = INVALID_SESSION;
l_ptr->b_ptr = b_ptr;
link_set_supervision_props(l_ptr, b_ptr->media->tolerance);
l_ptr->state = RESET_UNKNOWN;
@@ -536,9 +537,6 @@ void tipc_link_stop(struct link *l_ptr)
l_ptr->proto_msg_queue = NULL;
}
-/* LINK EVENT CODE IS NOT SUPPORTED AT PRESENT */
-#define link_send_event(fcn, l_ptr, up) do { } while (0)
-
void tipc_link_reset(struct link *l_ptr)
{
struct sk_buff *buf;
@@ -596,10 +594,6 @@ void tipc_link_reset(struct link *l_ptr)
l_ptr->fsm_msg_cnt = 0;
l_ptr->stale_count = 0;
link_reset_statistics(l_ptr);
-
- link_send_event(tipc_cfg_link_event, l_ptr, 0);
- if (!in_own_cluster(l_ptr->addr))
- link_send_event(tipc_disc_link_event, l_ptr, 0);
}
@@ -608,9 +602,6 @@ static void link_activate(struct link *l_ptr)
l_ptr->next_in_no = l_ptr->stats.recv_info = 1;
tipc_node_link_up(l_ptr->owner, l_ptr);
tipc_bearer_add_dest(l_ptr->b_ptr, l_ptr->addr);
- link_send_event(tipc_cfg_link_event, l_ptr, 1);
- if (!in_own_cluster(l_ptr->addr))
- link_send_event(tipc_disc_link_event, l_ptr, 1);
}
/**
@@ -985,6 +976,51 @@ int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector)
}
/*
+ * tipc_link_send_names - send name table entries to new neighbor
+ *
+ * Send routine for bulk delivery of name table messages when contact
+ * with a new neighbor occurs. No link congestion checking is performed
+ * because name table messages *must* be delivered. The messages must be
+ * small enough not to require fragmentation.
+ * Called without any locks held.
+ */
+
+void tipc_link_send_names(struct list_head *message_list, u32 dest)
+{
+ struct tipc_node *n_ptr;
+ struct link *l_ptr;
+ struct sk_buff *buf;
+ struct sk_buff *temp_buf;
+
+ if (list_empty(message_list))
+ return;
+
+ read_lock_bh(&tipc_net_lock);
+ n_ptr = tipc_node_find(dest);
+ if (n_ptr) {
+ tipc_node_lock(n_ptr);
+ l_ptr = n_ptr->active_links[0];
+ if (l_ptr) {
+ /* convert circular list to linear list */
+ ((struct sk_buff *)message_list->prev)->next = NULL;
+ link_add_chain_to_outqueue(l_ptr,
+ (struct sk_buff *)message_list->next, 0);
+ tipc_link_push_queue(l_ptr);
+ INIT_LIST_HEAD(message_list);
+ }
+ tipc_node_unlock(n_ptr);
+ }
+ read_unlock_bh(&tipc_net_lock);
+
+ /* discard the messages if they couldn't be sent */
+
+ list_for_each_safe(buf, temp_buf, ((struct sk_buff *)message_list)) {
+ list_del((struct list_head *)buf);
+ buf_discard(buf);
+ }
+}
+
+/*
* link_send_buf_fast: Entry for data messages where the
* destination link is known and the header is complete,
* inclusive total message length. Very time critical.
@@ -1031,9 +1067,6 @@ int tipc_send_buf_fast(struct sk_buff *buf, u32 destnode)
u32 selector = msg_origport(buf_msg(buf)) & 1;
u32 dummy;
- if (destnode == tipc_own_addr)
- return tipc_port_recv_msg(buf);
-
read_lock_bh(&tipc_net_lock);
n_ptr = tipc_node_find(destnode);
if (likely(n_ptr)) {
@@ -1658,19 +1691,12 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr)
continue;
}
+ /* Discard unicast link messages destined for another node */
+
if (unlikely(!msg_short(msg) &&
(msg_destnode(msg) != tipc_own_addr)))
goto cont;
- /* Discard non-routeable messages destined for another node */
-
- if (unlikely(!msg_isdata(msg) &&
- (msg_destnode(msg) != tipc_own_addr))) {
- if ((msg_user(msg) != CONN_MANAGER) &&
- (msg_user(msg) != MSG_FRAGMENTER))
- goto cont;
- }
-
/* Locate neighboring node that sent message */
n_ptr = tipc_node_find(msg_prevnode(msg));
@@ -1678,17 +1704,24 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr)
goto cont;
tipc_node_lock(n_ptr);
- /* Don't talk to neighbor during cleanup after last session */
+ /* Locate unicast link endpoint that should handle message */
- if (n_ptr->cleanup_required) {
+ l_ptr = n_ptr->links[b_ptr->identity];
+ if (unlikely(!l_ptr)) {
tipc_node_unlock(n_ptr);
goto cont;
}
- /* Locate unicast link endpoint that should handle message */
+ /* Verify that communication with node is currently allowed */
- l_ptr = n_ptr->links[b_ptr->identity];
- if (unlikely(!l_ptr)) {
+ if ((n_ptr->block_setup & WAIT_PEER_DOWN) &&
+ msg_user(msg) == LINK_PROTOCOL &&
+ (msg_type(msg) == RESET_MSG ||
+ msg_type(msg) == ACTIVATE_MSG) &&
+ !msg_redundant_link(msg))
+ n_ptr->block_setup &= ~WAIT_PEER_DOWN;
+
+ if (n_ptr->block_setup) {
tipc_node_unlock(n_ptr);
goto cont;
}
@@ -1923,6 +1956,12 @@ void tipc_link_send_proto_msg(struct link *l_ptr, u32 msg_typ, int probe_msg,
if (link_blocked(l_ptr))
return;
+
+ /* Abort non-RESET send if communication with node is prohibited */
+
+ if ((l_ptr->owner->block_setup) && (msg_typ != RESET_MSG))
+ return;
+
msg_set_type(msg, msg_typ);
msg_set_net_plane(msg, l_ptr->b_ptr->net_plane);
msg_set_bcast_ack(msg, mod(l_ptr->owner->bclink.last_in));
@@ -2051,9 +2090,19 @@ static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf)
case RESET_MSG:
if (!link_working_unknown(l_ptr) &&
(l_ptr->peer_session != INVALID_SESSION)) {
- if (msg_session(msg) == l_ptr->peer_session)
- break; /* duplicate: ignore */
+ if (less_eq(msg_session(msg), l_ptr->peer_session))
+ break; /* duplicate or old reset: ignore */
+ }
+
+ if (!msg_redundant_link(msg) && (link_working_working(l_ptr) ||
+ link_working_unknown(l_ptr))) {
+ /*
+ * peer has lost contact -- don't allow peer's links
+ * to reactivate before we recognize loss & clean up
+ */
+ l_ptr->owner->block_setup = WAIT_NODE_DOWN;
}
+
/* fall thru' */
case ACTIVATE_MSG:
/* Update link settings according other endpoint's values */
diff --git a/net/tipc/link.h b/net/tipc/link.h
index 74fbecab1ea0..e56cb532913e 100644
--- a/net/tipc/link.h
+++ b/net/tipc/link.h
@@ -223,6 +223,7 @@ struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area, int req_tlv_s
struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_space);
void tipc_link_reset(struct link *l_ptr);
int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector);
+void tipc_link_send_names(struct list_head *message_list, u32 dest);
int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf);
u32 tipc_link_get_max_pkt(u32 dest, u32 selector);
int tipc_link_send_sections_fast(struct tipc_port *sender,
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
index cd356e504332..b7ca1bd7b151 100644
--- a/net/tipc/name_distr.c
+++ b/net/tipc/name_distr.c
@@ -173,18 +173,40 @@ void tipc_named_withdraw(struct publication *publ)
* tipc_named_node_up - tell specified node about all publications by this node
*/
-void tipc_named_node_up(unsigned long node)
+void tipc_named_node_up(unsigned long nodearg)
{
+ struct tipc_node *n_ptr;
+ struct link *l_ptr;
struct publication *publ;
struct distr_item *item = NULL;
struct sk_buff *buf = NULL;
+ struct list_head message_list;
+ u32 node = (u32)nodearg;
u32 left = 0;
u32 rest;
- u32 max_item_buf;
+ u32 max_item_buf = 0;
+
+ /* compute maximum amount of publication data to send per message */
+
+ read_lock_bh(&tipc_net_lock);
+ n_ptr = tipc_node_find(node);
+ if (n_ptr) {
+ tipc_node_lock(n_ptr);
+ l_ptr = n_ptr->active_links[0];
+ if (l_ptr)
+ max_item_buf = ((l_ptr->max_pkt - INT_H_SIZE) /
+ ITEM_SIZE) * ITEM_SIZE;
+ tipc_node_unlock(n_ptr);
+ }
+ read_unlock_bh(&tipc_net_lock);
+ if (!max_item_buf)
+ return;
+
+ /* create list of publication messages, then send them as a unit */
+
+ INIT_LIST_HEAD(&message_list);
read_lock_bh(&tipc_nametbl_lock);
- max_item_buf = TIPC_MAX_USER_MSG_SIZE / ITEM_SIZE;
- max_item_buf *= ITEM_SIZE;
rest = publ_cnt * ITEM_SIZE;
list_for_each_entry(publ, &publ_root, local_list) {
@@ -202,13 +224,14 @@ void tipc_named_node_up(unsigned long node)
item++;
left -= ITEM_SIZE;
if (!left) {
- msg_set_link_selector(buf_msg(buf), node);
- tipc_link_send(buf, node, node);
+ list_add_tail((struct list_head *)buf, &message_list);
buf = NULL;
}
}
exit:
read_unlock_bh(&tipc_nametbl_lock);
+
+ tipc_link_send_names(&message_list, (u32)node);
}
/**
diff --git a/net/tipc/net.c b/net/tipc/net.c
index 68b3dd637291..fafef6c3c0f6 100644
--- a/net/tipc/net.c
+++ b/net/tipc/net.c
@@ -141,17 +141,6 @@ void tipc_net_route_msg(struct sk_buff *buf)
return;
msg = buf_msg(buf);
- msg_incr_reroute_cnt(msg);
- if (msg_reroute_cnt(msg) > 6) {
- if (msg_errcode(msg)) {
- buf_discard(buf);
- } else {
- tipc_reject_msg(buf, msg_destport(msg) ?
- TIPC_ERR_NO_PORT : TIPC_ERR_NO_NAME);
- }
- return;
- }
-
/* Handle message for this node */
dnode = msg_short(msg) ? tipc_own_addr : msg_destnode(msg);
if (tipc_in_scope(dnode, tipc_own_addr)) {
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 2d106ef4fa4c..27b4bb0cca6c 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -112,6 +112,7 @@ struct tipc_node *tipc_node_create(u32 addr)
break;
}
list_add_tail(&n_ptr->list, &temp_node->list);
+ n_ptr->block_setup = WAIT_PEER_DOWN;
tipc_num_nodes++;
@@ -312,7 +313,7 @@ static void node_established_contact(struct tipc_node *n_ptr)
}
}
-static void node_cleanup_finished(unsigned long node_addr)
+static void node_name_purge_complete(unsigned long node_addr)
{
struct tipc_node *n_ptr;
@@ -320,7 +321,7 @@ static void node_cleanup_finished(unsigned long node_addr)
n_ptr = tipc_node_find(node_addr);
if (n_ptr) {
tipc_node_lock(n_ptr);
- n_ptr->cleanup_required = 0;
+ n_ptr->block_setup &= ~WAIT_NAMES_GONE;
tipc_node_unlock(n_ptr);
}
read_unlock_bh(&tipc_net_lock);
@@ -331,28 +332,32 @@ static void node_lost_contact(struct tipc_node *n_ptr)
char addr_string[16];
u32 i;
- /* Clean up broadcast reception remains */
- n_ptr->bclink.gap_after = n_ptr->bclink.gap_to = 0;
- while (n_ptr->bclink.deferred_head) {
- struct sk_buff *buf = n_ptr->bclink.deferred_head;
- n_ptr->bclink.deferred_head = buf->next;
- buf_discard(buf);
- }
- if (n_ptr->bclink.defragm) {
- buf_discard(n_ptr->bclink.defragm);
- n_ptr->bclink.defragm = NULL;
- }
+ info("Lost contact with %s\n",
+ tipc_addr_string_fill(addr_string, n_ptr->addr));
+
+ /* Flush broadcast link info associated with lost node */
if (n_ptr->bclink.supported) {
+ n_ptr->bclink.gap_after = n_ptr->bclink.gap_to = 0;
+ while (n_ptr->bclink.deferred_head) {
+ struct sk_buff *buf = n_ptr->bclink.deferred_head;
+ n_ptr->bclink.deferred_head = buf->next;
+ buf_discard(buf);
+ }
+
+ if (n_ptr->bclink.defragm) {
+ buf_discard(n_ptr->bclink.defragm);
+ n_ptr->bclink.defragm = NULL;
+ }
+
+ tipc_nmap_remove(&tipc_bcast_nmap, n_ptr->addr);
tipc_bclink_acknowledge(n_ptr,
mod(n_ptr->bclink.acked + 10000));
- tipc_nmap_remove(&tipc_bcast_nmap, n_ptr->addr);
if (n_ptr->addr < tipc_own_addr)
tipc_own_tag--;
- }
- info("Lost contact with %s\n",
- tipc_addr_string_fill(addr_string, n_ptr->addr));
+ n_ptr->bclink.supported = 0;
+ }
/* Abort link changeover */
for (i = 0; i < MAX_BEARERS; i++) {
@@ -367,10 +372,10 @@ static void node_lost_contact(struct tipc_node *n_ptr)
/* Notify subscribers */
tipc_nodesub_notify(n_ptr);
- /* Prevent re-contact with node until all cleanup is done */
+ /* Prevent re-contact with node until cleanup is done */
- n_ptr->cleanup_required = 1;
- tipc_k_signal((Handler)node_cleanup_finished, n_ptr->addr);
+ n_ptr->block_setup = WAIT_PEER_DOWN | WAIT_NAMES_GONE;
+ tipc_k_signal((Handler)node_name_purge_complete, n_ptr->addr);
}
struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
diff --git a/net/tipc/node.h b/net/tipc/node.h
index 5c61afc7a0b9..4f15cb40aaa4 100644
--- a/net/tipc/node.h
+++ b/net/tipc/node.h
@@ -42,6 +42,12 @@
#include "net.h"
#include "bearer.h"
+/* Flags used to block (re)establishment of contact with a neighboring node */
+
+#define WAIT_PEER_DOWN 0x0001 /* wait to see that peer's links are down */
+#define WAIT_NAMES_GONE 0x0002 /* wait for peer's publications to be purged */
+#define WAIT_NODE_DOWN 0x0004 /* wait until peer node is declared down */
+
/**
* struct tipc_node - TIPC node structure
* @addr: network address of node
@@ -52,7 +58,7 @@
* @active_links: pointers to active links to node
* @links: pointers to all links to node
* @working_links: number of working links to node (both active and standby)
- * @cleanup_required: non-zero if cleaning up after a prior loss of contact
+ * @block_setup: bit mask of conditions preventing link establishment to node
* @link_cnt: number of links to node
* @permit_changeover: non-zero if node has redundant links to this system
* @bclink: broadcast-related info
@@ -77,7 +83,7 @@ struct tipc_node {
struct link *links[MAX_BEARERS];
int link_cnt;
int working_links;
- int cleanup_required;
+ int block_setup;
int permit_changeover;
struct {
int supported;
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index adb2eff4a102..9440a3d48ca0 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -49,7 +49,7 @@ struct tipc_sock {
struct sock sk;
struct tipc_port *p;
struct tipc_portid peer_name;
- long conn_timeout;
+ unsigned int conn_timeout;
};
#define tipc_sk(sk) ((struct tipc_sock *)(sk))
@@ -231,7 +231,7 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol,
sock_init_data(sock, sk);
sk->sk_backlog_rcv = backlog_rcv;
tipc_sk(sk)->p = tp_ptr;
- tipc_sk(sk)->conn_timeout = msecs_to_jiffies(CONN_TIMEOUT_DEFAULT);
+ tipc_sk(sk)->conn_timeout = CONN_TIMEOUT_DEFAULT;
spin_unlock_bh(tp_ptr->lock);
@@ -525,6 +525,7 @@ static int send_msg(struct kiocb *iocb, struct socket *sock,
struct tipc_port *tport = tipc_sk_port(sk);
struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name;
int needs_conn;
+ long timeout_val;
int res = -EINVAL;
if (unlikely(!dest))
@@ -564,6 +565,8 @@ static int send_msg(struct kiocb *iocb, struct socket *sock,
reject_rx_queue(sk);
}
+ timeout_val = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT);
+
do {
if (dest->addrtype == TIPC_ADDR_NAME) {
res = dest_name_check(dest, m);
@@ -600,16 +603,14 @@ static int send_msg(struct kiocb *iocb, struct socket *sock,
sock->state = SS_CONNECTING;
break;
}
- if (m->msg_flags & MSG_DONTWAIT) {
- res = -EWOULDBLOCK;
+ if (timeout_val <= 0L) {
+ res = timeout_val ? timeout_val : -EWOULDBLOCK;
break;
}
release_sock(sk);
- res = wait_event_interruptible(*sk_sleep(sk),
- !tport->congested);
+ timeout_val = wait_event_interruptible_timeout(*sk_sleep(sk),
+ !tport->congested, timeout_val);
lock_sock(sk);
- if (res)
- break;
} while (1);
exit:
@@ -636,6 +637,7 @@ static int send_packet(struct kiocb *iocb, struct socket *sock,
struct sock *sk = sock->sk;
struct tipc_port *tport = tipc_sk_port(sk);
struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name;
+ long timeout_val;
int res;
/* Handle implied connection establishment */
@@ -650,6 +652,8 @@ static int send_packet(struct kiocb *iocb, struct socket *sock,
if (iocb)
lock_sock(sk);
+ timeout_val = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT);
+
do {
if (unlikely(sock->state != SS_CONNECTED)) {
if (sock->state == SS_DISCONNECTING)
@@ -663,16 +667,14 @@ static int send_packet(struct kiocb *iocb, struct socket *sock,
total_len);
if (likely(res != -ELINKCONG))
break;
- if (m->msg_flags & MSG_DONTWAIT) {
- res = -EWOULDBLOCK;
+ if (timeout_val <= 0L) {
+ res = timeout_val ? timeout_val : -EWOULDBLOCK;
break;
}
release_sock(sk);
- res = wait_event_interruptible(*sk_sleep(sk),
- (!tport->congested || !tport->connected));
+ timeout_val = wait_event_interruptible_timeout(*sk_sleep(sk),
+ (!tport->congested || !tport->connected), timeout_val);
lock_sock(sk);
- if (res)
- break;
} while (1);
if (iocb)
@@ -1369,7 +1371,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
struct msghdr m = {NULL,};
struct sk_buff *buf;
struct tipc_msg *msg;
- long timeout;
+ unsigned int timeout;
int res;
lock_sock(sk);
@@ -1434,7 +1436,8 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
res = wait_event_interruptible_timeout(*sk_sleep(sk),
(!skb_queue_empty(&sk->sk_receive_queue) ||
(sock->state != SS_CONNECTING)),
- timeout ? timeout : MAX_SCHEDULE_TIMEOUT);
+ timeout ? (long)msecs_to_jiffies(timeout)
+ : MAX_SCHEDULE_TIMEOUT);
lock_sock(sk);
if (res > 0) {
@@ -1480,9 +1483,7 @@ static int listen(struct socket *sock, int len)
lock_sock(sk);
- if (sock->state == SS_READY)
- res = -EOPNOTSUPP;
- else if (sock->state != SS_UNCONNECTED)
+ if (sock->state != SS_UNCONNECTED)
res = -EINVAL;
else {
sock->state = SS_LISTENING;
@@ -1510,10 +1511,6 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags)
lock_sock(sk);
- if (sock->state == SS_READY) {
- res = -EOPNOTSUPP;
- goto exit;
- }
if (sock->state != SS_LISTENING) {
res = -EINVAL;
goto exit;
@@ -1696,7 +1693,7 @@ static int setsockopt(struct socket *sock,
res = tipc_set_portunreturnable(tport->ref, value);
break;
case TIPC_CONN_TIMEOUT:
- tipc_sk(sk)->conn_timeout = msecs_to_jiffies(value);
+ tipc_sk(sk)->conn_timeout = value;
/* no need to set "res", since already 0 at this point */
break;
default:
@@ -1752,7 +1749,7 @@ static int getsockopt(struct socket *sock,
res = tipc_portunreturnable(tport->ref, &value);
break;
case TIPC_CONN_TIMEOUT:
- value = jiffies_to_msecs(tipc_sk(sk)->conn_timeout);
+ value = tipc_sk(sk)->conn_timeout;
/* no need to set "res", since already 0 at this point */
break;
case TIPC_NODE_RECVQ_DEPTH:
@@ -1790,11 +1787,11 @@ static const struct proto_ops msg_ops = {
.bind = bind,
.connect = connect,
.socketpair = sock_no_socketpair,
- .accept = accept,
+ .accept = sock_no_accept,
.getname = get_name,
.poll = poll,
.ioctl = sock_no_ioctl,
- .listen = listen,
+ .listen = sock_no_listen,
.shutdown = shutdown,
.setsockopt = setsockopt,
.getsockopt = getsockopt,
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
index 6cf726863485..198371723b41 100644
--- a/net/tipc/subscr.c
+++ b/net/tipc/subscr.c
@@ -151,7 +151,7 @@ void tipc_subscr_report_overlap(struct subscription *sub,
if (!must && !(sub->filter & TIPC_SUB_PORTS))
return;
- sub->event_cb(sub, found_lower, found_upper, event, port_ref, node);
+ subscr_send_event(sub, found_lower, found_upper, event, port_ref, node);
}
/**
@@ -365,7 +365,6 @@ static struct subscription *subscr_subscribe(struct tipc_subscr *s,
subscr_terminate(subscriber);
return NULL;
}
- sub->event_cb = subscr_send_event;
INIT_LIST_HEAD(&sub->nameseq_list);
list_add(&sub->subscription_list, &subscriber->subscription_list);
sub->server_ref = subscriber->port_ref;
diff --git a/net/tipc/subscr.h b/net/tipc/subscr.h
index 45d89bf4d202..4b06ef6f8401 100644
--- a/net/tipc/subscr.h
+++ b/net/tipc/subscr.h
@@ -39,16 +39,11 @@
struct subscription;
-typedef void (*tipc_subscr_event) (struct subscription *sub,
- u32 found_lower, u32 found_upper,
- u32 event, u32 port_ref, u32 node);
-
/**
* struct subscription - TIPC network topology subscription object
* @seq: name sequence associated with subscription
* @timeout: duration of subscription (in ms)
* @filter: event filtering to be done for subscription
- * @event_cb: routine invoked when a subscription event is detected
* @timer: timer governing subscription duration (optional)
* @nameseq_list: adjacent subscriptions in name sequence's subscription list
* @subscription_list: adjacent subscriptions in subscriber's subscription list
@@ -61,7 +56,6 @@ struct subscription {
struct tipc_name_seq seq;
u32 timeout;
u32 filter;
- tipc_subscr_event event_cb;
struct timer_list timer;
struct list_head nameseq_list;
struct list_head subscription_list;
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index ec68e1c05b85..466fbcc5cf77 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1381,8 +1381,10 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds)
{
int err = 0;
+
UNIXCB(skb).pid = get_pid(scm->pid);
- UNIXCB(skb).cred = get_cred(scm->cred);
+ if (scm->cred)
+ UNIXCB(skb).cred = get_cred(scm->cred);
UNIXCB(skb).fp = NULL;
if (scm->fp && send_fds)
err = unix_attach_fds(scm, skb);
@@ -1392,6 +1394,24 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
}
/*
+ * Some apps rely on write() giving SCM_CREDENTIALS
+ * We include credentials if source or destination socket
+ * asserted SOCK_PASSCRED.
+ */
+static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
+ const struct sock *other)
+{
+ if (UNIXCB(skb).cred)
+ return;
+ if (test_bit(SOCK_PASSCRED, &sock->flags) ||
+ !other->sk_socket ||
+ test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) {
+ UNIXCB(skb).pid = get_pid(task_tgid(current));
+ UNIXCB(skb).cred = get_current_cred();
+ }
+}
+
+/*
* Send AF_UNIX data.
*/
@@ -1538,6 +1558,7 @@ restart:
if (sock_flag(other, SOCK_RCVTSTAMP))
__net_timestamp(skb);
+ maybe_add_creds(skb, sock, other);
skb_queue_tail(&other->sk_receive_queue, skb);
if (max_level > unix_sk(other)->recursion_level)
unix_sk(other)->recursion_level = max_level;
@@ -1652,6 +1673,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
(other->sk_shutdown & RCV_SHUTDOWN))
goto pipe_err_free;
+ maybe_add_creds(skb, sock, other);
skb_queue_tail(&other->sk_receive_queue, skb);
if (max_level > unix_sk(other)->recursion_level)
unix_sk(other)->recursion_level = max_level;
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 645437cfc464..220f3bd176f8 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -582,7 +582,7 @@ int wiphy_register(struct wiphy *wiphy)
}
/* set up regulatory info */
- wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
+ regulatory_update(wiphy, NL80211_REGDOM_SET_BY_CORE);
list_add_rcu(&rdev->list, &cfg80211_rdev_list);
cfg80211_rdev_list_generation++;
@@ -616,6 +616,9 @@ int wiphy_register(struct wiphy *wiphy)
if (res)
goto out_rm_dev;
+ rtnl_lock();
+ rdev->wiphy.registered = true;
+ rtnl_unlock();
return 0;
out_rm_dev:
@@ -647,6 +650,10 @@ void wiphy_unregister(struct wiphy *wiphy)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+ rtnl_lock();
+ rdev->wiphy.registered = false;
+ rtnl_unlock();
+
rfkill_unregister(rdev->rfkill);
/* protect the device list */
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 8672e028022f..b9ec3061ed72 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -279,8 +279,6 @@ extern int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
char *newname);
void ieee80211_set_bitrate_flags(struct wiphy *wiphy);
-void wiphy_update_regulatory(struct wiphy *wiphy,
- enum nl80211_reg_initiator setby);
void cfg80211_bss_expire(struct cfg80211_registered_device *dev);
void cfg80211_bss_age(struct cfg80211_registered_device *dev,
@@ -377,7 +375,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
struct ieee80211_channel *chan, bool offchan,
enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait,
- const u8 *buf, size_t len, u64 *cookie);
+ const u8 *buf, size_t len, bool no_cck,
+ u64 *cookie);
/* SME */
int __cfg80211_connect(struct cfg80211_registered_device *rdev,
@@ -408,6 +407,7 @@ void cfg80211_sme_failed_assoc(struct wireless_dev *wdev);
bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev);
/* internal helpers */
+bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher);
int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
struct key_params *params, int key_idx,
bool pairwise, const u8 *mac_addr);
diff --git a/net/wireless/lib80211.c b/net/wireless/lib80211.c
index 3268fac5ab22..a55c27b75ee5 100644
--- a/net/wireless/lib80211.c
+++ b/net/wireless/lib80211.c
@@ -41,6 +41,11 @@ struct lib80211_crypto_alg {
static LIST_HEAD(lib80211_crypto_algs);
static DEFINE_SPINLOCK(lib80211_crypto_lock);
+static void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *info,
+ int force);
+static void lib80211_crypt_quiescing(struct lib80211_crypt_info *info);
+static void lib80211_crypt_deinit_handler(unsigned long data);
+
const char *print_ssid(char *buf, const char *ssid, u8 ssid_len)
{
const char *s = ssid;
@@ -111,7 +116,8 @@ void lib80211_crypt_info_free(struct lib80211_crypt_info *info)
}
EXPORT_SYMBOL(lib80211_crypt_info_free);
-void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *info, int force)
+static void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *info,
+ int force)
{
struct lib80211_crypt_data *entry, *next;
unsigned long flags;
@@ -131,10 +137,9 @@ void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *info, int force)
}
spin_unlock_irqrestore(info->lock, flags);
}
-EXPORT_SYMBOL(lib80211_crypt_deinit_entries);
/* After this, crypt_deinit_list won't accept new members */
-void lib80211_crypt_quiescing(struct lib80211_crypt_info *info)
+static void lib80211_crypt_quiescing(struct lib80211_crypt_info *info)
{
unsigned long flags;
@@ -142,9 +147,8 @@ void lib80211_crypt_quiescing(struct lib80211_crypt_info *info)
info->crypt_quiesced = 1;
spin_unlock_irqrestore(info->lock, flags);
}
-EXPORT_SYMBOL(lib80211_crypt_quiescing);
-void lib80211_crypt_deinit_handler(unsigned long data)
+static void lib80211_crypt_deinit_handler(unsigned long data)
{
struct lib80211_crypt_info *info = (struct lib80211_crypt_info *)data;
unsigned long flags;
@@ -160,7 +164,6 @@ void lib80211_crypt_deinit_handler(unsigned long data)
}
spin_unlock_irqrestore(info->lock, flags);
}
-EXPORT_SYMBOL(lib80211_crypt_deinit_handler);
void lib80211_crypt_delayed_deinit(struct lib80211_crypt_info *info,
struct lib80211_crypt_data **crypt)
diff --git a/net/wireless/lib80211_crypt_ccmp.c b/net/wireless/lib80211_crypt_ccmp.c
index dacb3b4b1bdb..755738d26bb4 100644
--- a/net/wireless/lib80211_crypt_ccmp.c
+++ b/net/wireless/lib80211_crypt_ccmp.c
@@ -77,8 +77,6 @@ static void *lib80211_ccmp_init(int key_idx)
priv->tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->tfm)) {
- printk(KERN_DEBUG "lib80211_crypt_ccmp: could not allocate "
- "crypto API aes\n");
priv->tfm = NULL;
goto fail;
}
diff --git a/net/wireless/lib80211_crypt_tkip.c b/net/wireless/lib80211_crypt_tkip.c
index 7ea4f2b0770e..38734846c19e 100644
--- a/net/wireless/lib80211_crypt_tkip.c
+++ b/net/wireless/lib80211_crypt_tkip.c
@@ -101,7 +101,6 @@ static void *lib80211_tkip_init(int key_idx)
priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->tx_tfm_arc4)) {
- printk(KERN_DEBUG pr_fmt("could not allocate crypto API arc4\n"));
priv->tx_tfm_arc4 = NULL;
goto fail;
}
@@ -109,7 +108,6 @@ static void *lib80211_tkip_init(int key_idx)
priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->tx_tfm_michael)) {
- printk(KERN_DEBUG pr_fmt("could not allocate crypto API michael_mic\n"));
priv->tx_tfm_michael = NULL;
goto fail;
}
@@ -117,7 +115,6 @@ static void *lib80211_tkip_init(int key_idx)
priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->rx_tfm_arc4)) {
- printk(KERN_DEBUG pr_fmt("could not allocate crypto API arc4\n"));
priv->rx_tfm_arc4 = NULL;
goto fail;
}
@@ -125,7 +122,6 @@ static void *lib80211_tkip_init(int key_idx)
priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->rx_tfm_michael)) {
- printk(KERN_DEBUG pr_fmt("could not allocate crypto API michael_mic\n"));
priv->rx_tfm_michael = NULL;
goto fail;
}
diff --git a/net/wireless/lib80211_crypt_wep.c b/net/wireless/lib80211_crypt_wep.c
index 2f265e033ae2..c1304018fc1c 100644
--- a/net/wireless/lib80211_crypt_wep.c
+++ b/net/wireless/lib80211_crypt_wep.c
@@ -50,16 +50,12 @@ static void *lib80211_wep_init(int keyidx)
priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->tx_tfm)) {
- printk(KERN_DEBUG "lib80211_crypt_wep: could not allocate "
- "crypto API arc4\n");
priv->tx_tfm = NULL;
goto fail;
}
priv->rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->rx_tfm)) {
- printk(KERN_DEBUG "lib80211_crypt_wep: could not allocate "
- "crypto API arc4\n");
priv->rx_tfm = NULL;
goto fail;
}
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 5c116083eeca..4423e64c7d98 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -12,6 +12,7 @@
#define MESH_HOLD_T 100
#define MESH_PATH_TIMEOUT 5000
+#define MESH_RANN_INTERVAL 5000
/*
* Minimum interval between two consecutive PREQs originated by the same
@@ -49,6 +50,8 @@ const struct mesh_config default_mesh_config = {
.dot11MeshHWMPmaxPREQretries = MESH_MAX_PREQ_RETRIES,
.path_refresh_time = MESH_PATH_REFRESH_TIME,
.min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT,
+ .dot11MeshHWMPRannInterval = MESH_RANN_INTERVAL,
+ .dot11MeshGateAnnouncementProtocol = false,
};
const struct mesh_setup default_mesh_setup = {
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 832f6574e4ed..21fc9702f81c 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -900,7 +900,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
struct ieee80211_channel *chan, bool offchan,
enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait,
- const u8 *buf, size_t len, u64 *cookie)
+ const u8 *buf, size_t len, bool no_cck,
+ u64 *cookie)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
const struct ieee80211_mgmt *mgmt;
@@ -991,7 +992,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
/* Transmit the Action frame as requested by user space */
return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, offchan,
channel_type, channel_type_valid,
- wait, buf, len, cookie);
+ wait, buf, len, no_cck, cookie);
}
bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf,
@@ -1095,3 +1096,14 @@ void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
}
EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);
+
+void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
+ const u8 *bssid, bool preauth, gfp_t gfp)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+ nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
+}
+EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index e83e7fee3bc0..48260c2d092a 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -23,6 +23,12 @@
#include "nl80211.h"
#include "reg.h"
+static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type);
+static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
+ struct genl_info *info,
+ struct cfg80211_crypto_settings *settings,
+ int cipher_limit);
+
static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
struct genl_info *info);
static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb,
@@ -178,6 +184,19 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 },
[NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED },
[NL80211_ATTR_SCAN_SUPP_RATES] = { .type = NLA_NESTED },
+ [NL80211_ATTR_HIDDEN_SSID] = { .type = NLA_U32 },
+ [NL80211_ATTR_IE_PROBE_RESP] = { .type = NLA_BINARY,
+ .len = IEEE80211_MAX_DATA_LEN },
+ [NL80211_ATTR_IE_ASSOC_RESP] = { .type = NLA_BINARY,
+ .len = IEEE80211_MAX_DATA_LEN },
+ [NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG },
+ [NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED },
+ [NL80211_ATTR_TX_NO_CCK_RATE] = { .type = NLA_FLAG },
+ [NL80211_ATTR_TDLS_ACTION] = { .type = NLA_U8 },
+ [NL80211_ATTR_TDLS_DIALOG_TOKEN] = { .type = NLA_U8 },
+ [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 },
+ [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG },
+ [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG },
};
/* policy for the key attributes */
@@ -220,6 +239,12 @@ nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
[NL80211_REKEY_DATA_REPLAY_CTR] = { .len = NL80211_REPLAY_CTR_LEN },
};
+static const struct nla_policy
+nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
+ [NL80211_ATTR_SCHED_SCAN_MATCH_SSID] = { .type = NLA_BINARY,
+ .len = IEEE80211_MAX_SSID_LEN },
+};
+
/* ifidx get helper */
static int nl80211_get_ifidx(struct netlink_callback *cb)
{
@@ -703,11 +728,21 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
dev->wiphy.max_scan_ie_len);
NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
dev->wiphy.max_sched_scan_ie_len);
+ NLA_PUT_U8(msg, NL80211_ATTR_MAX_MATCH_SETS,
+ dev->wiphy.max_match_sets);
if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)
NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN);
if (dev->wiphy.flags & WIPHY_FLAG_MESH_AUTH)
NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_MESH_AUTH);
+ if (dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_AP_UAPSD);
+ if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_ROAM_SUPPORT);
+ if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_TDLS_SUPPORT);
+ if (dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP);
NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES,
sizeof(u32) * dev->wiphy.n_cipher_suites,
@@ -850,6 +885,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
}
CMD(set_channel, SET_CHANNEL);
CMD(set_wds_peer, SET_WDS_PEER);
+ if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
+ CMD(tdls_mgmt, TDLS_MGMT);
+ CMD(tdls_oper, TDLS_OPER);
+ }
if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
CMD(sched_scan_start, START_SCHED_SCAN);
@@ -871,8 +910,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
NLA_PUT_U32(msg, NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
dev->wiphy.max_remain_on_channel_duration);
- /* for now at least assume all drivers have it */
- if (dev->ops->mgmt_tx)
+ if (dev->ops->mgmt_tx_cancel_wait)
NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
if (mgmt_stypes) {
@@ -1210,6 +1248,11 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
goto bad_res;
}
+ if (!netdev) {
+ result = -EINVAL;
+ goto bad_res;
+ }
+
nla_for_each_nested(nl_txq_params,
info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
rem_txq_params) {
@@ -1222,6 +1265,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
goto bad_res;
result = rdev->ops->set_txq_params(&rdev->wiphy,
+ netdev,
&txq_params);
if (result)
goto bad_res;
@@ -1985,7 +2029,10 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
struct beacon_parameters params;
int haveinfo = 0, err;
- if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]))
+ if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]) ||
+ !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]) ||
+ !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_PROBE_RESP]) ||
+ !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]))
return -EINVAL;
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
@@ -2011,6 +2058,49 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
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:
@@ -2041,6 +2131,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
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]);
+ }
+
+ if (info->attrs[NL80211_ATTR_IE_PROBE_RESP]) {
+ params.proberesp_ies =
+ nla_data(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
+ params.proberesp_ies_len =
+ nla_len(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
+ }
+
+ if (info->attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
+ params.assocresp_ies =
+ nla_data(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
+ params.assocresp_ies_len =
+ nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
+ }
+
err = call(&rdev->wiphy, dev, &params);
if (!err && params.interval)
wdev->beacon_interval = params.interval;
@@ -2235,8 +2344,16 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
nla_nest_end(msg, bss_param);
}
+ if (sinfo->filled & STATION_INFO_STA_FLAGS)
+ NLA_PUT(msg, NL80211_STA_INFO_STA_FLAGS,
+ sizeof(struct nl80211_sta_flag_update),
+ &sinfo->sta_flags);
nla_nest_end(msg, sinfoattr);
+ if (sinfo->filled & STATION_INFO_ASSOC_REQ_IES)
+ NLA_PUT(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len,
+ sinfo->assoc_req_ies);
+
return genlmsg_end(msg, hdr);
nla_put_failure:
@@ -2264,6 +2381,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
}
while (1) {
+ memset(&sinfo, 0, sizeof(sinfo));
err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx,
mac_addr, &sinfo);
if (err == -ENOENT)
@@ -2416,18 +2534,25 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
break;
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION:
- /* disallow everything but AUTHORIZED flag */
+ /* disallow things sta doesn't support */
if (params.plink_action)
err = -EINVAL;
if (params.vlan)
err = -EINVAL;
- if (params.supported_rates)
+ if (params.supported_rates &&
+ !(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
err = -EINVAL;
if (params.ht_capa)
err = -EINVAL;
if (params.listen_interval >= 0)
err = -EINVAL;
- if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED))
+ if (params.sta_flags_mask &
+ ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
+ BIT(NL80211_STA_FLAG_TDLS_PEER)))
+ err = -EINVAL;
+ /* can't change the TDLS bit */
+ if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
+ (params.sta_flags_mask & BIT(NL80211_STA_FLAG_TDLS_PEER)))
err = -EINVAL;
break;
case NL80211_IFTYPE_MESH_POINT:
@@ -2465,6 +2590,12 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
return err;
}
+static struct nla_policy
+nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = {
+ [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 },
+ [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 },
+};
+
static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -2510,10 +2641,50 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
if (parse_station_flags(info, &params))
return -EINVAL;
+ /* parse WME attributes if sta is WME capable */
+ if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
+ (params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)) &&
+ info->attrs[NL80211_ATTR_STA_WME]) {
+ struct nlattr *tb[NL80211_STA_WME_MAX + 1];
+ struct nlattr *nla;
+
+ nla = info->attrs[NL80211_ATTR_STA_WME];
+ err = nla_parse_nested(tb, NL80211_STA_WME_MAX, nla,
+ nl80211_sta_wme_policy);
+ if (err)
+ return err;
+
+ if (tb[NL80211_STA_WME_UAPSD_QUEUES])
+ params.uapsd_queues =
+ nla_get_u8(tb[NL80211_STA_WME_UAPSD_QUEUES]);
+ if (params.uapsd_queues & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
+ return -EINVAL;
+
+ if (tb[NL80211_STA_WME_MAX_SP])
+ params.max_sp =
+ nla_get_u8(tb[NL80211_STA_WME_MAX_SP]);
+
+ if (params.max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
+ return -EINVAL;
+
+ params.sta_modify_mask |= STATION_PARAM_APPLY_UAPSD;
+ }
+
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
- dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION)
+ return -EINVAL;
+
+ /*
+ * Only managed stations can add TDLS peers, and only when the
+ * wiphy supports external TDLS setup.
+ */
+ if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION &&
+ !((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
+ (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
+ (rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)))
return -EINVAL;
err = get_vlan(info, rdev, &params.vlan);
@@ -2955,6 +3126,10 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
cur_params.dot11MeshHWMPnetDiameterTraversalTime);
NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
cur_params.dot11MeshHWMPRootMode);
+ NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+ cur_params.dot11MeshHWMPRannInterval);
+ NLA_PUT_U8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
+ cur_params.dot11MeshGateAnnouncementProtocol);
nla_nest_end(msg, pinfoattr);
genlmsg_end(msg, hdr);
return genlmsg_reply(msg, info);
@@ -2982,6 +3157,9 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
[NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
[NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 },
[NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
+ [NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
+ [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
+ [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 },
};
static const struct nla_policy
@@ -3060,6 +3238,14 @@ do {\
dot11MeshHWMPRootMode, mask,
NL80211_MESHCONF_HWMP_ROOTMODE,
nla_get_u8);
+ FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
+ dot11MeshHWMPRannInterval, mask,
+ NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+ nla_get_u16);
+ FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
+ dot11MeshGateAnnouncementProtocol, mask,
+ NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
+ nla_get_u8);
if (mask_out)
*mask_out = mask;
@@ -3477,6 +3663,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
}
}
+ request->no_cck =
+ nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
+
request->dev = dev;
request->wiphy = &rdev->wiphy;
@@ -3503,10 +3692,11 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
struct net_device *dev = info->user_ptr[1];
struct nlattr *attr;
struct wiphy *wiphy;
- int err, tmp, n_ssids = 0, n_channels, i;
+ int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i;
u32 interval;
enum ieee80211_band band;
size_t ie_len;
+ struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
!rdev->ops->sched_scan_start)
@@ -3545,6 +3735,15 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
if (n_ssids > wiphy->max_sched_scan_ssids)
return -EINVAL;
+ if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH])
+ nla_for_each_nested(attr,
+ info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
+ tmp)
+ n_match_sets++;
+
+ if (n_match_sets > wiphy->max_match_sets)
+ return -EINVAL;
+
if (info->attrs[NL80211_ATTR_IE])
ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
else
@@ -3562,6 +3761,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
request = kzalloc(sizeof(*request)
+ sizeof(*request->ssids) * n_ssids
+ + sizeof(*request->match_sets) * n_match_sets
+ sizeof(*request->channels) * n_channels
+ ie_len, GFP_KERNEL);
if (!request) {
@@ -3579,6 +3779,18 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
request->ie = (void *)(request->channels + n_channels);
}
+ if (n_match_sets) {
+ if (request->ie)
+ request->match_sets = (void *)(request->ie + ie_len);
+ else if (request->ssids)
+ request->match_sets =
+ (void *)(request->ssids + n_ssids);
+ else
+ request->match_sets =
+ (void *)(request->channels + n_channels);
+ }
+ request->n_match_sets = n_match_sets;
+
i = 0;
if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
/* user specified, bail out if channel not found */
@@ -3643,6 +3855,31 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
}
}
+ i = 0;
+ if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
+ nla_for_each_nested(attr,
+ info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
+ tmp) {
+ struct nlattr *ssid;
+
+ nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
+ nla_data(attr), nla_len(attr),
+ nl80211_match_policy);
+ ssid = tb[NL80211_ATTR_SCHED_SCAN_MATCH_SSID];
+ if (ssid) {
+ if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) {
+ err = -EINVAL;
+ goto out_free;
+ }
+ memcpy(request->match_sets[i].ssid.ssid,
+ nla_data(ssid), nla_len(ssid));
+ request->match_sets[i].ssid.ssid_len =
+ nla_len(ssid);
+ }
+ i++;
+ }
+ }
+
if (info->attrs[NL80211_ATTR_IE]) {
request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
memcpy((void *)request->ie,
@@ -3935,22 +4172,6 @@ static bool nl80211_valid_wpa_versions(u32 wpa_versions)
NL80211_WPA_VERSION_2));
}
-static bool nl80211_valid_akm_suite(u32 akm)
-{
- return akm == WLAN_AKM_SUITE_8021X ||
- akm == WLAN_AKM_SUITE_PSK;
-}
-
-static bool nl80211_valid_cipher_suite(u32 cipher)
-{
- return cipher == WLAN_CIPHER_SUITE_WEP40 ||
- cipher == WLAN_CIPHER_SUITE_WEP104 ||
- cipher == WLAN_CIPHER_SUITE_TKIP ||
- cipher == WLAN_CIPHER_SUITE_CCMP ||
- cipher == WLAN_CIPHER_SUITE_AES_CMAC;
-}
-
-
static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -4083,7 +4304,8 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
memcpy(settings->ciphers_pairwise, data, len);
for (i = 0; i < settings->n_ciphers_pairwise; i++)
- if (!nl80211_valid_cipher_suite(
+ if (!cfg80211_supported_cipher_suite(
+ &rdev->wiphy,
settings->ciphers_pairwise[i]))
return -EINVAL;
}
@@ -4091,7 +4313,8 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
if (info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]) {
settings->cipher_group =
nla_get_u32(info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]);
- if (!nl80211_valid_cipher_suite(settings->cipher_group))
+ if (!cfg80211_supported_cipher_suite(&rdev->wiphy,
+ settings->cipher_group))
return -EINVAL;
}
@@ -4104,7 +4327,7 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
if (info->attrs[NL80211_ATTR_AKM_SUITES]) {
void *data;
- int len, i;
+ int len;
data = nla_data(info->attrs[NL80211_ATTR_AKM_SUITES]);
len = nla_len(info->attrs[NL80211_ATTR_AKM_SUITES]);
@@ -4113,11 +4336,10 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
if (len % sizeof(u32))
return -EINVAL;
- memcpy(settings->akm_suites, data, len);
+ if (settings->n_akm_suites > NL80211_MAX_NR_AKM_SUITES)
+ return -EINVAL;
- for (i = 0; i < settings->n_ciphers_pairwise; i++)
- if (!nl80211_valid_akm_suite(settings->akm_suites[i]))
- return -EINVAL;
+ memcpy(settings->akm_suites, data, len);
}
return 0;
@@ -4336,8 +4558,12 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
wiphy = &rdev->wiphy;
- if (info->attrs[NL80211_ATTR_MAC])
+ if (info->attrs[NL80211_ATTR_MAC]) {
ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ if (!is_valid_ether_addr(ibss.bssid))
+ return -EINVAL;
+ }
ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
@@ -4774,6 +5000,57 @@ static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
return rdev->ops->flush_pmksa(&rdev->wiphy, dev);
}
+static int nl80211_tdls_mgmt(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];
+ u8 action_code, dialog_token;
+ u16 status_code;
+ u8 *peer;
+
+ if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
+ !rdev->ops->tdls_mgmt)
+ return -EOPNOTSUPP;
+
+ if (!info->attrs[NL80211_ATTR_TDLS_ACTION] ||
+ !info->attrs[NL80211_ATTR_STATUS_CODE] ||
+ !info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN] ||
+ !info->attrs[NL80211_ATTR_IE] ||
+ !info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]);
+ status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
+ dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]);
+
+ return rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code,
+ dialog_token, status_code,
+ nla_data(info->attrs[NL80211_ATTR_IE]),
+ nla_len(info->attrs[NL80211_ATTR_IE]));
+}
+
+static int nl80211_tdls_oper(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];
+ enum nl80211_tdls_operation operation;
+ u8 *peer;
+
+ if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) ||
+ !rdev->ops->tdls_oper)
+ return -EOPNOTSUPP;
+
+ if (!info->attrs[NL80211_ATTR_TDLS_OPERATION] ||
+ !info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ operation = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_OPERATION]);
+ peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ return rdev->ops->tdls_oper(&rdev->wiphy, dev, peer, operation);
+}
+
static int nl80211_remain_on_channel(struct sk_buff *skb,
struct genl_info *info)
{
@@ -4994,6 +5271,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
struct sk_buff *msg;
unsigned int wait = 0;
bool offchan;
+ bool no_cck;
if (!info->attrs[NL80211_ATTR_FRAME] ||
!info->attrs[NL80211_ATTR_WIPHY_FREQ])
@@ -5030,6 +5308,8 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
+ no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
+
freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
chan = rdev_freq_to_chan(rdev, freq, channel_type);
if (chan == NULL)
@@ -5050,7 +5330,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
channel_type_valid, wait,
nla_data(info->attrs[NL80211_ATTR_FRAME]),
nla_len(info->attrs[NL80211_ATTR_FRAME]),
- &cookie);
+ no_cck, &cookie);
if (err)
goto free_msg;
@@ -6086,6 +6366,22 @@ static struct genl_ops nl80211_ops[] = {
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL80211_CMD_TDLS_MGMT,
+ .doit = nl80211_tdls_mgmt,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
+ .cmd = NL80211_CMD_TDLS_OPER,
+ .doit = nl80211_tdls_oper,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
};
static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -7075,6 +7371,52 @@ void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
nlmsg_free(msg);
}
+void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, int index,
+ const u8 *bssid, bool preauth, gfp_t gfp)
+{
+ struct sk_buff *msg;
+ struct nlattr *attr;
+ void *hdr;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+ if (!msg)
+ return;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PMKSA_CANDIDATE);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+
+ attr = nla_nest_start(msg, NL80211_ATTR_PMKSA_CANDIDATE);
+ if (!attr)
+ goto nla_put_failure;
+
+ NLA_PUT_U32(msg, NL80211_PMKSA_CANDIDATE_INDEX, index);
+ NLA_PUT(msg, NL80211_PMKSA_CANDIDATE_BSSID, ETH_ALEN, bssid);
+ if (preauth)
+ NLA_PUT_FLAG(msg, NL80211_PMKSA_CANDIDATE_PREAUTH);
+
+ nla_nest_end(msg, attr);
+
+ if (genlmsg_end(msg, hdr) < 0) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_mlme_mcgrp.id, gfp);
+ return;
+
+ nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ nlmsg_free(msg);
+}
+
void
nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *peer,
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 5d69c56400ae..f24a1fbeaf19 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -113,4 +113,8 @@ void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *bssid,
const u8 *replay_ctr, gfp_t gfp);
+void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, int index,
+ const u8 *bssid, bool preauth, gfp_t gfp);
+
#endif /* __NET_WIRELESS_NL80211_H */
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 02751dbc5a97..2520a1b7e7db 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -49,10 +49,8 @@
#include "nl80211.h"
#ifdef CONFIG_CFG80211_REG_DEBUG
-#define REG_DBG_PRINT(format, args...) \
- do { \
- printk(KERN_DEBUG pr_fmt(format), ##args); \
- } while (0)
+#define REG_DBG_PRINT(format, args...) \
+ printk(KERN_DEBUG pr_fmt(format), ##args)
#else
#define REG_DBG_PRINT(args...)
#endif
@@ -753,9 +751,10 @@ static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan,
chan->center_freq,
KHZ_TO_MHZ(desired_bw_khz));
- REG_DBG_PRINT("%d KHz - %d KHz @ KHz), (%s mBi, %d mBm)\n",
+ REG_DBG_PRINT("%d KHz - %d KHz @ %d KHz), (%s mBi, %d mBm)\n",
freq_range->start_freq_khz,
freq_range->end_freq_khz,
+ freq_range->max_bandwidth_khz,
max_antenna_gain,
power_rule->max_eirp);
}
@@ -852,6 +851,7 @@ static void handle_channel(struct wiphy *wiphy,
return;
}
+ chan->beacon_found = false;
chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags);
chan->max_antenna_gain = min(chan->orig_mag,
(int) MBI_TO_DBI(power_rule->max_antenna_gain));
@@ -890,7 +890,7 @@ static bool ignore_reg_update(struct wiphy *wiphy,
wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) {
REG_DBG_PRINT("Ignoring regulatory request %s "
"since the driver uses its own custom "
- "regulatory domain ",
+ "regulatory domain\n",
reg_initiator_name(initiator));
return true;
}
@@ -904,7 +904,7 @@ static bool ignore_reg_update(struct wiphy *wiphy,
!is_world_regdom(last_request->alpha2)) {
REG_DBG_PRINT("Ignoring regulatory request %s "
"since the driver requires its own regulatory "
- "domain to be set first",
+ "domain to be set first\n",
reg_initiator_name(initiator));
return true;
}
@@ -912,14 +912,6 @@ static bool ignore_reg_update(struct wiphy *wiphy,
return false;
}
-static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
-{
- struct cfg80211_registered_device *rdev;
-
- list_for_each_entry(rdev, &cfg80211_rdev_list, list)
- wiphy_update_regulatory(&rdev->wiphy, initiator);
-}
-
static void handle_reg_beacon(struct wiphy *wiphy,
unsigned int chan_idx,
struct reg_beacon *reg_beacon)
@@ -1119,11 +1111,13 @@ static void reg_process_ht_flags(struct wiphy *wiphy)
}
-void wiphy_update_regulatory(struct wiphy *wiphy,
- enum nl80211_reg_initiator initiator)
+static void wiphy_update_regulatory(struct wiphy *wiphy,
+ enum nl80211_reg_initiator initiator)
{
enum ieee80211_band band;
+ assert_reg_lock();
+
if (ignore_reg_update(wiphy, initiator))
return;
@@ -1138,6 +1132,22 @@ void wiphy_update_regulatory(struct wiphy *wiphy,
wiphy->reg_notifier(wiphy, last_request);
}
+void regulatory_update(struct wiphy *wiphy,
+ enum nl80211_reg_initiator setby)
+{
+ mutex_lock(&reg_mutex);
+ wiphy_update_regulatory(wiphy, setby);
+ mutex_unlock(&reg_mutex);
+}
+
+static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
+{
+ struct cfg80211_registered_device *rdev;
+
+ list_for_each_entry(rdev, &cfg80211_rdev_list, list)
+ wiphy_update_regulatory(&rdev->wiphy, initiator);
+}
+
static void handle_channel_custom(struct wiphy *wiphy,
enum ieee80211_band band,
unsigned int chan_idx,
@@ -1474,7 +1484,7 @@ static void reg_process_pending_hints(void)
/* When last_request->processed becomes true this will be rescheduled */
if (last_request && !last_request->processed) {
REG_DBG_PRINT("Pending regulatory request, waiting "
- "for it to be processed...");
+ "for it to be processed...\n");
goto out;
}
@@ -2187,7 +2197,7 @@ out:
static void reg_timeout_work(struct work_struct *work)
{
REG_DBG_PRINT("Timeout while waiting for CRDA to reply, "
- "restoring regulatory settings");
+ "restoring regulatory settings\n");
restore_regulatory_settings(true);
}
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index b67d1c3a2fb9..4a56799d868d 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -16,6 +16,8 @@ void regulatory_exit(void);
int set_regdom(const struct ieee80211_regdomain *rd);
+void regulatory_update(struct wiphy *wiphy, enum nl80211_reg_initiator setby);
+
/**
* regulatory_hint_found_beacon - hints a beacon was found on a channel
* @wiphy: the wireless device where the beacon was found on
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 2936cb809152..0fb142410404 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -12,6 +12,7 @@
#include <linux/etherdevice.h>
#include <net/arp.h>
#include <net/cfg80211.h>
+#include <net/cfg80211-wext.h>
#include <net/iw_handler.h>
#include "core.h"
#include "nl80211.h"
@@ -227,6 +228,33 @@ const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len)
}
EXPORT_SYMBOL(cfg80211_find_ie);
+const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type,
+ const u8 *ies, int len)
+{
+ struct ieee80211_vendor_ie *ie;
+ const u8 *pos = ies, *end = ies + len;
+ int ie_oui;
+
+ while (pos < end) {
+ pos = cfg80211_find_ie(WLAN_EID_VENDOR_SPECIFIC, pos,
+ end - pos);
+ if (!pos)
+ return NULL;
+
+ if (end - pos < sizeof(*ie))
+ return NULL;
+
+ ie = (struct ieee80211_vendor_ie *)pos;
+ ie_oui = ie->oui[0] << 16 | ie->oui[1] << 8 | ie->oui[2];
+ if (ie_oui == oui && ie->oui_type == oui_type)
+ return pos;
+
+ pos += 2 + ie->len;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(cfg80211_find_vendor_ie);
+
static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2)
{
const u8 *ie1 = cfg80211_find_ie(num, ies1, len1);
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index b7b6ff8be553..6e86d5acf145 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -110,15 +110,22 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
else {
int i = 0, j;
enum ieee80211_band band;
+ struct ieee80211_supported_band *bands;
+ struct ieee80211_channel *channel;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
- if (!wdev->wiphy->bands[band])
+ bands = wdev->wiphy->bands[band];
+ if (!bands)
continue;
- for (j = 0; j < wdev->wiphy->bands[band]->n_channels;
- i++, j++)
- request->channels[i] =
- &wdev->wiphy->bands[band]->channels[j];
+ for (j = 0; j < bands->n_channels; j++) {
+ channel = &bands->channels[j];
+ if (channel->flags & IEEE80211_CHAN_DISABLED)
+ continue;
+ request->channels[i++] = channel;
+ }
+ request->rates[band] = (1 << bands->n_bitrates) - 1;
}
+ n_channels = i;
}
request->n_channels = n_channels;
request->ssids = (void *)&request->channels[n_channels];
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c
index c6e4ca6a7d2e..ff574597a854 100644
--- a/net/wireless/sysfs.c
+++ b/net/wireless/sysfs.c
@@ -93,7 +93,8 @@ static int wiphy_suspend(struct device *dev, pm_message_t state)
if (rdev->ops->suspend) {
rtnl_lock();
- ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan);
+ if (rdev->wiphy.registered)
+ ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan);
rtnl_unlock();
}
@@ -112,7 +113,8 @@ static int wiphy_resume(struct device *dev)
if (rdev->ops->resume) {
rtnl_lock();
- ret = rdev->ops->resume(&rdev->wiphy);
+ if (rdev->wiphy.registered)
+ ret = rdev->ops->resume(&rdev->wiphy);
rtnl_unlock();
}
diff --git a/net/wireless/util.c b/net/wireless/util.c
index be75a3a0424e..2f178f73943f 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -6,6 +6,7 @@
#include <linux/bitops.h>
#include <linux/etherdevice.h>
#include <linux/slab.h>
+#include <linux/crc32.h>
#include <net/cfg80211.h>
#include <net/ip.h>
#include "core.h"
@@ -150,12 +151,19 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
set_mandatory_flags_band(wiphy->bands[band], band);
}
+bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher)
+{
+ int i;
+ for (i = 0; i < wiphy->n_cipher_suites; i++)
+ if (cipher == wiphy->cipher_suites[i])
+ return true;
+ return false;
+}
+
int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
struct key_params *params, int key_idx,
bool pairwise, const u8 *mac_addr)
{
- int i;
-
if (key_idx > 5)
return -EINVAL;
@@ -225,10 +233,7 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
}
}
- for (i = 0; i < rdev->wiphy.n_cipher_suites; i++)
- if (params->cipher == rdev->wiphy.cipher_suites[i])
- break;
- if (i == rdev->wiphy.n_cipher_suites)
+ if (!cfg80211_supported_cipher_suite(&rdev->wiphy, params->cipher))
return -EINVAL;
return 0;
@@ -391,8 +396,9 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
}
break;
case cpu_to_le16(0):
- if (iftype != NL80211_IFTYPE_ADHOC)
- return -1;
+ if (iftype != NL80211_IFTYPE_ADHOC &&
+ iftype != NL80211_IFTYPE_STATION)
+ return -1;
break;
}
@@ -512,10 +518,9 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
if (head_need)
skb_orphan(skb);
- if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) {
- pr_err("failed to reallocate Tx buffer\n");
+ if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC))
return -ENOMEM;
- }
+
skb->truesize += head_need;
}
@@ -1044,3 +1049,170 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
return 0;
}
+
+u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
+ struct ieee802_11_elems *elems,
+ u64 filter, u32 crc)
+{
+ size_t left = len;
+ u8 *pos = start;
+ bool calc_crc = filter != 0;
+
+ memset(elems, 0, sizeof(*elems));
+ elems->ie_start = start;
+ elems->total_len = len;
+
+ while (left >= 2) {
+ u8 id, elen;
+
+ id = *pos++;
+ elen = *pos++;
+ left -= 2;
+
+ if (elen > left)
+ break;
+
+ if (calc_crc && id < 64 && (filter & (1ULL << id)))
+ crc = crc32_be(crc, pos - 2, elen + 2);
+
+ switch (id) {
+ case WLAN_EID_SSID:
+ elems->ssid = pos;
+ elems->ssid_len = elen;
+ break;
+ case WLAN_EID_SUPP_RATES:
+ elems->supp_rates = pos;
+ elems->supp_rates_len = elen;
+ break;
+ case WLAN_EID_FH_PARAMS:
+ elems->fh_params = pos;
+ elems->fh_params_len = elen;
+ break;
+ case WLAN_EID_DS_PARAMS:
+ elems->ds_params = pos;
+ elems->ds_params_len = elen;
+ break;
+ case WLAN_EID_CF_PARAMS:
+ elems->cf_params = pos;
+ elems->cf_params_len = elen;
+ break;
+ case WLAN_EID_TIM:
+ if (elen >= sizeof(struct ieee80211_tim_ie)) {
+ elems->tim = (void *)pos;
+ elems->tim_len = elen;
+ }
+ break;
+ case WLAN_EID_IBSS_PARAMS:
+ elems->ibss_params = pos;
+ elems->ibss_params_len = elen;
+ break;
+ case WLAN_EID_CHALLENGE:
+ elems->challenge = pos;
+ elems->challenge_len = elen;
+ break;
+ case WLAN_EID_VENDOR_SPECIFIC:
+ if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
+ pos[2] == 0xf2) {
+ /* Microsoft OUI (00:50:F2) */
+
+ if (calc_crc)
+ crc = crc32_be(crc, pos - 2, elen + 2);
+
+ if (pos[3] == 1) {
+ /* OUI Type 1 - WPA IE */
+ elems->wpa = pos;
+ elems->wpa_len = elen;
+ } else if (elen >= 5 && pos[3] == 2) {
+ /* OUI Type 2 - WMM IE */
+ if (pos[4] == 0) {
+ elems->wmm_info = pos;
+ elems->wmm_info_len = elen;
+ } else if (pos[4] == 1) {
+ elems->wmm_param = pos;
+ elems->wmm_param_len = elen;
+ }
+ }
+ }
+ break;
+ case WLAN_EID_RSN:
+ elems->rsn = pos;
+ elems->rsn_len = elen;
+ break;
+ case WLAN_EID_ERP_INFO:
+ elems->erp_info = pos;
+ elems->erp_info_len = elen;
+ break;
+ case WLAN_EID_EXT_SUPP_RATES:
+ elems->ext_supp_rates = pos;
+ elems->ext_supp_rates_len = elen;
+ break;
+ case WLAN_EID_HT_CAPABILITY:
+ if (elen >= sizeof(struct ieee80211_ht_cap))
+ elems->ht_cap_elem = (void *)pos;
+ break;
+ case WLAN_EID_HT_INFORMATION:
+ if (elen >= sizeof(struct ieee80211_ht_info))
+ elems->ht_info_elem = (void *)pos;
+ break;
+ case WLAN_EID_MESH_ID:
+ elems->mesh_id = pos;
+ elems->mesh_id_len = elen;
+ break;
+ case WLAN_EID_MESH_CONFIG:
+ if (elen >= sizeof(struct ieee80211_meshconf_ie))
+ elems->mesh_config = (void *)pos;
+ break;
+ case WLAN_EID_PEER_MGMT:
+ elems->peering = pos;
+ elems->peering_len = elen;
+ break;
+ case WLAN_EID_PREQ:
+ elems->preq = pos;
+ elems->preq_len = elen;
+ break;
+ case WLAN_EID_PREP:
+ elems->prep = pos;
+ elems->prep_len = elen;
+ break;
+ case WLAN_EID_PERR:
+ elems->perr = pos;
+ elems->perr_len = elen;
+ break;
+ case WLAN_EID_RANN:
+ if (elen >= sizeof(struct ieee80211_rann_ie))
+ elems->rann = (void *)pos;
+ break;
+ case WLAN_EID_CHANNEL_SWITCH:
+ elems->ch_switch_elem = pos;
+ elems->ch_switch_elem_len = elen;
+ break;
+ case WLAN_EID_QUIET:
+ if (!elems->quiet_elem) {
+ elems->quiet_elem = pos;
+ elems->quiet_elem_len = elen;
+ }
+ elems->num_of_quiet_elem++;
+ break;
+ case WLAN_EID_COUNTRY:
+ elems->country_elem = pos;
+ elems->country_elem_len = elen;
+ break;
+ case WLAN_EID_PWR_CONSTRAINT:
+ elems->pwr_constr_elem = pos;
+ elems->pwr_constr_elem_len = elen;
+ break;
+ case WLAN_EID_TIMEOUT_INTERVAL:
+ elems->timeout_int = pos;
+ elems->timeout_int_len = elen;
+ break;
+ default:
+ break;
+ }
+
+ left -= elen;
+ pos += elen;
+ }
+
+ return crc;
+}
+EXPORT_SYMBOL(ieee802_11_parse_elems_crc);
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 0bf169bb770e..62f121d1d9cb 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -15,6 +15,7 @@
#include <linux/slab.h>
#include <net/iw_handler.h>
#include <net/cfg80211.h>
+#include <net/cfg80211-wext.h>
#include "wext-compat.h"
#include "core.h"
@@ -363,9 +364,9 @@ int cfg80211_wext_giwfrag(struct net_device *dev,
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwfrag);
-int cfg80211_wext_siwretry(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *retry, char *extra)
+static int cfg80211_wext_siwretry(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *retry, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
@@ -402,7 +403,6 @@ int cfg80211_wext_siwretry(struct net_device *dev,
return err;
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_siwretry);
int cfg80211_wext_giwretry(struct net_device *dev,
struct iw_request_info *info,
@@ -593,9 +593,9 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
return err;
}
-int cfg80211_wext_siwencode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *keybuf)
+static int cfg80211_wext_siwencode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *keybuf)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
@@ -652,11 +652,10 @@ int cfg80211_wext_siwencode(struct net_device *dev,
wdev->wext.default_key == -1,
idx, &params);
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_siwencode);
-int cfg80211_wext_siwencodeext(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *extra)
+static int cfg80211_wext_siwencodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
@@ -744,11 +743,10 @@ int cfg80211_wext_siwencodeext(struct net_device *dev,
ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
idx, &params);
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext);
-int cfg80211_wext_giwencode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *keybuf)
+static int cfg80211_wext_giwencode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *keybuf)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
int idx;
@@ -782,11 +780,10 @@ int cfg80211_wext_giwencode(struct net_device *dev,
return 0;
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode);
-int cfg80211_wext_siwfreq(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_freq *wextfreq, char *extra)
+static int cfg80211_wext_siwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *wextfreq, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
@@ -815,11 +812,10 @@ int cfg80211_wext_siwfreq(struct net_device *dev,
return -EOPNOTSUPP;
}
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq);
-int cfg80211_wext_giwfreq(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_freq *freq, char *extra)
+static int cfg80211_wext_giwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -836,11 +832,10 @@ int cfg80211_wext_giwfreq(struct net_device *dev,
return 0;
}
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_giwfreq);
-int cfg80211_wext_siwtxpower(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *data, char *extra)
+static int cfg80211_wext_siwtxpower(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *data, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
@@ -889,11 +884,10 @@ int cfg80211_wext_siwtxpower(struct net_device *dev,
return rdev->ops->set_tx_power(wdev->wiphy, type, DBM_TO_MBM(dbm));
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_siwtxpower);
-int cfg80211_wext_giwtxpower(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *data, char *extra)
+static int cfg80211_wext_giwtxpower(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *data, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
@@ -919,7 +913,6 @@ int cfg80211_wext_giwtxpower(struct net_device *dev,
return 0;
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_giwtxpower);
static int cfg80211_set_auth_alg(struct wireless_dev *wdev,
s32 auth_alg)
@@ -1070,9 +1063,9 @@ static int cfg80211_set_key_mgt(struct wireless_dev *wdev, u32 key_mgt)
return 0;
}
-int cfg80211_wext_siwauth(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *data, char *extra)
+static int cfg80211_wext_siwauth(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *data, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -1102,21 +1095,19 @@ int cfg80211_wext_siwauth(struct net_device *dev,
return -EOPNOTSUPP;
}
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_siwauth);
-int cfg80211_wext_giwauth(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *data, char *extra)
+static int cfg80211_wext_giwauth(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *data, char *extra)
{
/* XXX: what do we need? */
return -EOPNOTSUPP;
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_giwauth);
-int cfg80211_wext_siwpower(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq, char *extra)
+static int cfg80211_wext_siwpower(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *wrq, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
@@ -1160,11 +1151,10 @@ int cfg80211_wext_siwpower(struct net_device *dev,
return 0;
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_siwpower);
-int cfg80211_wext_giwpower(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq, char *extra)
+static int cfg80211_wext_giwpower(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *wrq, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -1172,7 +1162,6 @@ int cfg80211_wext_giwpower(struct net_device *dev,
return 0;
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_giwpower);
static int cfg80211_wds_wext_siwap(struct net_device *dev,
struct iw_request_info *info,
@@ -1218,9 +1207,9 @@ static int cfg80211_wds_wext_giwap(struct net_device *dev,
return 0;
}
-int cfg80211_wext_siwrate(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *rate, char *extra)
+static int cfg80211_wext_siwrate(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rate, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
@@ -1268,11 +1257,10 @@ int cfg80211_wext_siwrate(struct net_device *dev,
return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask);
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate);
-int cfg80211_wext_giwrate(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *rate, char *extra)
+static int cfg80211_wext_giwrate(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rate, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
@@ -1308,10 +1296,9 @@ int cfg80211_wext_giwrate(struct net_device *dev,
return 0;
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_giwrate);
/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */
-struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
+static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
@@ -1376,11 +1363,10 @@ struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
return &wstats;
}
-EXPORT_SYMBOL_GPL(cfg80211_wireless_stats);
-int cfg80211_wext_siwap(struct net_device *dev,
- struct iw_request_info *info,
- struct sockaddr *ap_addr, char *extra)
+static int cfg80211_wext_siwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -1395,11 +1381,10 @@ int cfg80211_wext_siwap(struct net_device *dev,
return -EOPNOTSUPP;
}
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_siwap);
-int cfg80211_wext_giwap(struct net_device *dev,
- struct iw_request_info *info,
- struct sockaddr *ap_addr, char *extra)
+static int cfg80211_wext_giwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -1414,11 +1399,10 @@ int cfg80211_wext_giwap(struct net_device *dev,
return -EOPNOTSUPP;
}
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_giwap);
-int cfg80211_wext_siwessid(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *ssid)
+static int cfg80211_wext_siwessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *ssid)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -1431,11 +1415,10 @@ int cfg80211_wext_siwessid(struct net_device *dev,
return -EOPNOTSUPP;
}
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_siwessid);
-int cfg80211_wext_giwessid(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *ssid)
+static int cfg80211_wext_giwessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *ssid)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -1451,11 +1434,10 @@ int cfg80211_wext_giwessid(struct net_device *dev,
return -EOPNOTSUPP;
}
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_giwessid);
-int cfg80211_wext_siwpmksa(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *extra)
+static int cfg80211_wext_siwpmksa(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
@@ -1493,7 +1475,6 @@ int cfg80211_wext_siwpmksa(struct net_device *dev,
return -EOPNOTSUPP;
}
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_siwpmksa);
static const iw_handler cfg80211_handlers[] = {
[IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname,
diff --git a/net/wireless/wext-compat.h b/net/wireless/wext-compat.h
index 20b3daef6964..5d766b0118e8 100644
--- a/net/wireless/wext-compat.h
+++ b/net/wireless/wext-compat.h
@@ -42,6 +42,14 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *ssid);
+int cfg80211_wext_siwmlme(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra);
+int cfg80211_wext_siwgenie(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra);
+
+
int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq);
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index 6fffe62d7c25..0d4b8c3033ff 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -9,6 +9,7 @@
#include <linux/if_arp.h>
#include <linux/slab.h>
#include <net/cfg80211.h>
+#include <net/cfg80211-wext.h>
#include "wext-compat.h"
#include "nl80211.h"
@@ -365,7 +366,6 @@ int cfg80211_wext_siwgenie(struct net_device *dev,
wdev_unlock(wdev);
return err;
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_siwgenie);
int cfg80211_wext_siwmlme(struct net_device *dev,
struct iw_request_info *info,
@@ -402,4 +402,3 @@ int cfg80211_wext_siwmlme(struct net_device *dev,
return err;
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme);
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index d30615419b4d..5f03e4ea65bf 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -91,7 +91,7 @@ int x25_parse_address_block(struct sk_buff *skb,
int needed;
int rc;
- if (skb->len < 1) {
+ if (!pskb_may_pull(skb, 1)) {
/* packet has no address block */
rc = 0;
goto empty;
@@ -100,7 +100,7 @@ int x25_parse_address_block(struct sk_buff *skb,
len = *skb->data;
needed = 1 + (len >> 4) + (len & 0x0f);
- if (skb->len < needed) {
+ if (!pskb_may_pull(skb, needed)) {
/* packet is too short to hold the addresses it claims
to hold */
rc = -1;
@@ -295,7 +295,8 @@ static struct sock *x25_find_listener(struct x25_address *addr,
* Found a listening socket, now check the incoming
* call user data vs this sockets call user data
*/
- if(skb->len > 0 && x25_sk(s)->cudmatchlength > 0) {
+ if (x25_sk(s)->cudmatchlength > 0 &&
+ skb->len >= x25_sk(s)->cudmatchlength) {
if((memcmp(x25_sk(s)->calluserdata.cuddata,
skb->data,
x25_sk(s)->cudmatchlength)) == 0) {
@@ -951,14 +952,27 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
*
* Facilities length is mandatory in call request packets
*/
- if (skb->len < 1)
+ if (!pskb_may_pull(skb, 1))
goto out_clear_request;
len = skb->data[0] + 1;
- if (skb->len < len)
+ if (!pskb_may_pull(skb, len))
goto out_clear_request;
skb_pull(skb,len);
/*
+ * Ensure that the amount of call user data is valid.
+ */
+ if (skb->len > X25_MAX_CUD_LEN)
+ goto out_clear_request;
+
+ /*
+ * Get all the call user data so it can be used in
+ * x25_find_listener and skb_copy_from_linear_data up ahead.
+ */
+ if (!pskb_may_pull(skb, skb->len))
+ goto out_clear_request;
+
+ /*
* Find a listener for the particular address/cud pair.
*/
sk = x25_find_listener(&source_addr,skb);
@@ -1166,6 +1180,9 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
* byte of the user data is the logical value of the Q Bit.
*/
if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) {
+ if (!pskb_may_pull(skb, 1))
+ goto out_kfree_skb;
+
qbit = skb->data[0];
skb_pull(skb, 1);
}
@@ -1244,7 +1261,9 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
struct x25_sock *x25 = x25_sk(sk);
struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name;
size_t copied;
- int qbit;
+ int qbit, header_len = x25->neighbour->extended ?
+ X25_EXT_MIN_LEN : X25_STD_MIN_LEN;
+
struct sk_buff *skb;
unsigned char *asmptr;
int rc = -ENOTCONN;
@@ -1265,6 +1284,9 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
skb = skb_dequeue(&x25->interrupt_in_queue);
+ if (!pskb_may_pull(skb, X25_STD_MIN_LEN))
+ goto out_free_dgram;
+
skb_pull(skb, X25_STD_MIN_LEN);
/*
@@ -1285,10 +1307,12 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
if (!skb)
goto out;
+ if (!pskb_may_pull(skb, header_len))
+ goto out_free_dgram;
+
qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT;
- skb_pull(skb, x25->neighbour->extended ?
- X25_EXT_MIN_LEN : X25_STD_MIN_LEN);
+ skb_pull(skb, header_len);
if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) {
asmptr = skb_push(skb, 1);
diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c
index e547ca1578c3..fa2b41888bd9 100644
--- a/net/x25/x25_dev.c
+++ b/net/x25/x25_dev.c
@@ -32,6 +32,9 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)
unsigned short frametype;
unsigned int lci;
+ if (!pskb_may_pull(skb, X25_STD_MIN_LEN))
+ return 0;
+
frametype = skb->data[2];
lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF);
@@ -115,6 +118,9 @@ int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev,
goto drop;
}
+ if (!pskb_may_pull(skb, 1))
+ return 0;
+
switch (skb->data[0]) {
case X25_IFACE_DATA:
diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c
index f77e4e75f914..36384a1fa9f2 100644
--- a/net/x25/x25_facilities.c
+++ b/net/x25/x25_facilities.c
@@ -44,7 +44,7 @@
int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask)
{
- unsigned char *p = skb->data;
+ unsigned char *p;
unsigned int len;
*vc_fac_mask = 0;
@@ -60,14 +60,16 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
memset(dte_facs->called_ae, '\0', sizeof(dte_facs->called_ae));
memset(dte_facs->calling_ae, '\0', sizeof(dte_facs->calling_ae));
- if (skb->len < 1)
+ if (!pskb_may_pull(skb, 1))
return 0;
- len = *p++;
+ len = skb->data[0];
- if (len >= skb->len)
+ if (!pskb_may_pull(skb, 1 + len))
return -1;
+ p = skb->data + 1;
+
while (len > 0) {
switch (*p & X25_FAC_CLASS_MASK) {
case X25_FAC_CLASS_A:
diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
index 0b073b51b183..a49cd4ec551a 100644
--- a/net/x25/x25_in.c
+++ b/net/x25/x25_in.c
@@ -107,6 +107,8 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
/*
* Parse the data in the frame.
*/
+ if (!pskb_may_pull(skb, X25_STD_MIN_LEN))
+ goto out_clear;
skb_pull(skb, X25_STD_MIN_LEN);
len = x25_parse_address_block(skb, &source_addr,
@@ -127,9 +129,11 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
* Copy any Call User Data.
*/
if (skb->len > 0) {
- skb_copy_from_linear_data(skb,
- x25->calluserdata.cuddata,
- skb->len);
+ if (skb->len > X25_MAX_CUD_LEN)
+ goto out_clear;
+
+ skb_copy_bits(skb, 0, x25->calluserdata.cuddata,
+ skb->len);
x25->calluserdata.cudlength = skb->len;
}
if (!sock_flag(sk, SOCK_DEAD))
@@ -137,6 +141,9 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
break;
}
case X25_CLEAR_REQUEST:
+ if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
+ goto out_clear;
+
x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]);
break;
@@ -164,6 +171,9 @@ static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametyp
switch (frametype) {
case X25_CLEAR_REQUEST:
+ if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
+ goto out_clear;
+
x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
break;
@@ -177,6 +187,11 @@ static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametyp
}
return 0;
+
+out_clear:
+ x25_write_internal(sk, X25_CLEAR_REQUEST);
+ x25_start_t23timer(sk);
+ return 0;
}
/*
@@ -206,6 +221,9 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
break;
case X25_CLEAR_REQUEST:
+ if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
+ goto out_clear;
+
x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
break;
@@ -304,6 +322,12 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
}
return queued;
+
+out_clear:
+ x25_write_internal(sk, X25_CLEAR_REQUEST);
+ x25->state = X25_STATE_2;
+ x25_start_t23timer(sk);
+ return 0;
}
/*
@@ -313,13 +337,13 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
*/
static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype)
{
+ struct x25_sock *x25 = x25_sk(sk);
+
switch (frametype) {
case X25_RESET_REQUEST:
x25_write_internal(sk, X25_RESET_CONFIRMATION);
case X25_RESET_CONFIRMATION: {
- struct x25_sock *x25 = x25_sk(sk);
-
x25_stop_timer(sk);
x25->condition = 0x00;
x25->va = 0;
@@ -331,6 +355,9 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp
break;
}
case X25_CLEAR_REQUEST:
+ if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2))
+ goto out_clear;
+
x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
break;
@@ -340,6 +367,12 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp
}
return 0;
+
+out_clear:
+ x25_write_internal(sk, X25_CLEAR_REQUEST);
+ x25->state = X25_STATE_2;
+ x25_start_t23timer(sk);
+ return 0;
}
/* Higher level upcall for a LAPB frame */
diff --git a/net/x25/x25_link.c b/net/x25/x25_link.c
index 037958ff8eed..4acacf3c6617 100644
--- a/net/x25/x25_link.c
+++ b/net/x25/x25_link.c
@@ -90,6 +90,9 @@ void x25_link_control(struct sk_buff *skb, struct x25_neigh *nb,
break;
case X25_DIAGNOSTIC:
+ if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 4))
+ break;
+
printk(KERN_WARNING "x25: diagnostic #%d - %02X %02X %02X\n",
skb->data[3], skb->data[4],
skb->data[5], skb->data[6]);
diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c
index 24a342ebc7f5..5170d52bfd96 100644
--- a/net/x25/x25_subr.c
+++ b/net/x25/x25_subr.c
@@ -269,7 +269,11 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
int *d, int *m)
{
struct x25_sock *x25 = x25_sk(sk);
- unsigned char *frame = skb->data;
+ unsigned char *frame;
+
+ if (!pskb_may_pull(skb, X25_STD_MIN_LEN))
+ return X25_ILLEGAL;
+ frame = skb->data;
*ns = *nr = *q = *d = *m = 0;
@@ -294,6 +298,10 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
if (frame[2] == X25_RR ||
frame[2] == X25_RNR ||
frame[2] == X25_REJ) {
+ if (!pskb_may_pull(skb, X25_EXT_MIN_LEN))
+ return X25_ILLEGAL;
+ frame = skb->data;
+
*nr = (frame[3] >> 1) & 0x7F;
return frame[2];
}
@@ -308,6 +316,10 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
if (x25->neighbour->extended) {
if ((frame[2] & 0x01) == X25_DATA) {
+ if (!pskb_may_pull(skb, X25_EXT_MIN_LEN))
+ return X25_ILLEGAL;
+ frame = skb->data;
+
*q = (frame[0] & X25_Q_BIT) == X25_Q_BIT;
*d = (frame[0] & X25_D_BIT) == X25_D_BIT;
*m = (frame[3] & X25_EXT_M_BIT) == X25_EXT_M_BIT;
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index a026b0ef2443..54a0dc2e2f8d 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -212,6 +212,11 @@ resume:
/* only the first xfrm gets the encap type */
encap_type = 0;
+ if (async && x->repl->check(x, skb, seq)) {
+ XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
+ goto drop_unlock;
+ }
+
x->repl->advance(x, seq);
x->curlft.bytes += skb->len;
diff --git a/net/xfrm/xfrm_ipcomp.c b/net/xfrm/xfrm_ipcomp.c
index fc91ad7ee26e..e5246fbe36c4 100644
--- a/net/xfrm/xfrm_ipcomp.c
+++ b/net/xfrm/xfrm_ipcomp.c
@@ -70,26 +70,29 @@ static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb)
while ((scratch += len, dlen -= len) > 0) {
skb_frag_t *frag;
+ struct page *page;
err = -EMSGSIZE;
if (WARN_ON(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS))
goto out;
frag = skb_shinfo(skb)->frags + skb_shinfo(skb)->nr_frags;
- frag->page = alloc_page(GFP_ATOMIC);
+ page = alloc_page(GFP_ATOMIC);
err = -ENOMEM;
- if (!frag->page)
+ if (!page)
goto out;
+ __skb_frag_set_page(frag, page);
+
len = PAGE_SIZE;
if (dlen < len)
len = dlen;
- memcpy(page_address(frag->page), scratch, len);
-
frag->page_offset = 0;
- frag->size = len;
+ skb_frag_size_set(frag, len);
+ memcpy(skb_frag_address(frag), scratch, len);
+
skb->truesize += len;
skb->data_len += len;
skb->len += len;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 94fdcc7f1030..552df27dcf53 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1349,14 +1349,16 @@ static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family)
BUG();
}
xdst = dst_alloc(dst_ops, NULL, 0, 0, 0);
- memset(&xdst->u.rt6.rt6i_table, 0, sizeof(*xdst) - sizeof(struct dst_entry));
- xfrm_policy_put_afinfo(afinfo);
- if (likely(xdst))
+ if (likely(xdst)) {
+ memset(&xdst->u.rt6.rt6i_table, 0,
+ sizeof(*xdst) - sizeof(struct dst_entry));
xdst->flo.ops = &xfrm_bundle_fc_ops;
- else
+ } else
xdst = ERR_PTR(-ENOBUFS);
+ xfrm_policy_put_afinfo(afinfo);
+
return xdst;
}
diff --git a/net/xfrm/xfrm_replay.c b/net/xfrm/xfrm_replay.c
index b11ea692bd7d..6ca357406ea8 100644
--- a/net/xfrm/xfrm_replay.c
+++ b/net/xfrm/xfrm_replay.c
@@ -203,8 +203,6 @@ static int xfrm_replay_check_bmp(struct xfrm_state *x,
if (!replay_esn->replay_window)
return 0;
- pos = (replay_esn->seq - 1) % replay_esn->replay_window;
-
if (unlikely(seq == 0))
goto err;
@@ -216,19 +214,18 @@ static int xfrm_replay_check_bmp(struct xfrm_state *x,
goto err;
}
- if (pos >= diff) {
+ pos = (replay_esn->seq - 1) % replay_esn->replay_window;
+
+ if (pos >= diff)
bitnr = (pos - diff) % replay_esn->replay_window;
- nr = bitnr >> 5;
- bitnr = bitnr & 0x1F;
- if (replay_esn->bmp[nr] & (1U << bitnr))
- goto err_replay;
- } else {
+ else
bitnr = replay_esn->replay_window - (diff - pos);
- nr = bitnr >> 5;
- bitnr = bitnr & 0x1F;
- if (replay_esn->bmp[nr] & (1U << bitnr))
- goto err_replay;
- }
+
+ nr = bitnr >> 5;
+ bitnr = bitnr & 0x1F;
+ if (replay_esn->bmp[nr] & (1U << bitnr))
+ goto err_replay;
+
return 0;
err_replay:
@@ -259,39 +256,27 @@ static void xfrm_replay_advance_bmp(struct xfrm_state *x, __be32 net_seq)
bitnr = bitnr & 0x1F;
replay_esn->bmp[nr] &= ~(1U << bitnr);
}
-
- bitnr = (pos + diff) % replay_esn->replay_window;
- nr = bitnr >> 5;
- bitnr = bitnr & 0x1F;
- replay_esn->bmp[nr] |= (1U << bitnr);
} else {
nr = (replay_esn->replay_window - 1) >> 5;
for (i = 0; i <= nr; i++)
replay_esn->bmp[i] = 0;
-
- bitnr = (pos + diff) % replay_esn->replay_window;
- nr = bitnr >> 5;
- bitnr = bitnr & 0x1F;
- replay_esn->bmp[nr] |= (1U << bitnr);
}
+ bitnr = (pos + diff) % replay_esn->replay_window;
replay_esn->seq = seq;
} else {
diff = replay_esn->seq - seq;
- if (pos >= diff) {
+ if (pos >= diff)
bitnr = (pos - diff) % replay_esn->replay_window;
- nr = bitnr >> 5;
- bitnr = bitnr & 0x1F;
- replay_esn->bmp[nr] |= (1U << bitnr);
- } else {
+ else
bitnr = replay_esn->replay_window - (diff - pos);
- nr = bitnr >> 5;
- bitnr = bitnr & 0x1F;
- replay_esn->bmp[nr] |= (1U << bitnr);
- }
}
+ nr = bitnr >> 5;
+ bitnr = bitnr & 0x1F;
+ replay_esn->bmp[nr] |= (1U << bitnr);
+
if (xfrm_aevent_is_on(xs_net(x)))
xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
}
@@ -390,8 +375,6 @@ static int xfrm_replay_check_esn(struct xfrm_state *x,
if (!wsize)
return 0;
- pos = (replay_esn->seq - 1) % replay_esn->replay_window;
-
if (unlikely(seq == 0 && replay_esn->seq_hi == 0 &&
(replay_esn->seq < replay_esn->replay_window - 1)))
goto err;
@@ -415,19 +398,18 @@ static int xfrm_replay_check_esn(struct xfrm_state *x,
goto err;
}
- if (pos >= diff) {
+ pos = (replay_esn->seq - 1) % replay_esn->replay_window;
+
+ if (pos >= diff)
bitnr = (pos - diff) % replay_esn->replay_window;
- nr = bitnr >> 5;
- bitnr = bitnr & 0x1F;
- if (replay_esn->bmp[nr] & (1U << bitnr))
- goto err_replay;
- } else {
+ else
bitnr = replay_esn->replay_window - (diff - pos);
- nr = bitnr >> 5;
- bitnr = bitnr & 0x1F;
- if (replay_esn->bmp[nr] & (1U << bitnr))
- goto err_replay;
- }
+
+ nr = bitnr >> 5;
+ bitnr = bitnr & 0x1F;
+ if (replay_esn->bmp[nr] & (1U << bitnr))
+ goto err_replay;
+
return 0;
err_replay:
@@ -465,22 +447,13 @@ static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq)
bitnr = bitnr & 0x1F;
replay_esn->bmp[nr] &= ~(1U << bitnr);
}
-
- bitnr = (pos + diff) % replay_esn->replay_window;
- nr = bitnr >> 5;
- bitnr = bitnr & 0x1F;
- replay_esn->bmp[nr] |= (1U << bitnr);
} else {
nr = (replay_esn->replay_window - 1) >> 5;
for (i = 0; i <= nr; i++)
replay_esn->bmp[i] = 0;
-
- bitnr = (pos + diff) % replay_esn->replay_window;
- nr = bitnr >> 5;
- bitnr = bitnr & 0x1F;
- replay_esn->bmp[nr] |= (1U << bitnr);
}
+ bitnr = (pos + diff) % replay_esn->replay_window;
replay_esn->seq = seq;
if (unlikely(wrap > 0))
@@ -488,19 +461,16 @@ static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq)
} else {
diff = replay_esn->seq - seq;
- if (pos >= diff) {
+ if (pos >= diff)
bitnr = (pos - diff) % replay_esn->replay_window;
- nr = bitnr >> 5;
- bitnr = bitnr & 0x1F;
- replay_esn->bmp[nr] |= (1U << bitnr);
- } else {
+ else
bitnr = replay_esn->replay_window - (diff - pos);
- nr = bitnr >> 5;
- bitnr = bitnr & 0x1F;
- replay_esn->bmp[nr] |= (1U << bitnr);
- }
}
+ nr = bitnr >> 5;
+ bitnr = bitnr & 0x1F;
+ replay_esn->bmp[nr] |= (1U << bitnr);
+
if (xfrm_aevent_is_on(xs_net(x)))
xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
}
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 0256b8a0a7cf..d0a42df5160e 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -2927,7 +2927,7 @@ static int __net_init xfrm_user_net_init(struct net *net)
if (nlsk == NULL)
return -ENOMEM;
net->xfrm.nlsk_stash = nlsk; /* Don't set to NULL */
- rcu_assign_pointer(net->xfrm.nlsk, nlsk);
+ RCU_INIT_POINTER(net->xfrm.nlsk, nlsk);
return 0;
}
@@ -2935,7 +2935,7 @@ static void __net_exit xfrm_user_net_exit(struct list_head *net_exit_list)
{
struct net *net;
list_for_each_entry(net, net_exit_list, exit_list)
- rcu_assign_pointer(net->xfrm.nlsk, NULL);
+ RCU_INIT_POINTER(net->xfrm.nlsk, NULL);
synchronize_net();
list_for_each_entry(net, net_exit_list, exit_list)
netlink_kernel_release(net->xfrm.nlsk_stash);
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 9d761c95eca2..0b3e35c9ef08 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -2574,7 +2574,8 @@ sub process {
} else {
$cast = $cast2;
}
- WARN("$call() should probably be ${call}_t($cast, $arg1, $arg2)\n" . $herecurr);
+ WARN("MINMAX",
+ "$call() should probably be ${call}_t($cast, $arg1, $arg2)\n" . $herecurr);
}
}
@@ -2931,11 +2932,11 @@ sub process {
}
}
if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) {
- my $herectx = $here . "\n";;
+ my $herectx = $here . "\n";
my $cnt = statement_rawlines($block);
for (my $n = 0; $n < $cnt; $n++) {
- $herectx .= raw_line($linenr, $n) . "\n";;
+ $herectx .= raw_line($linenr, $n) . "\n";
}
WARN("BRACES",
diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl
index eb2f1e64edf7..4594f3341051 100755
--- a/scripts/get_maintainer.pl
+++ b/scripts/get_maintainer.pl
@@ -1389,7 +1389,7 @@ sub vcs_exists {
warn("$P: No supported VCS found. Add --nogit to options?\n");
warn("Using a git repository produces better results.\n");
warn("Try Linus Torvalds' latest git repository using:\n");
- warn("git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git\n");
+ warn("git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git\n");
$printed_novcs = 1;
}
return 0;
diff --git a/security/Kconfig b/security/Kconfig
index e0f08b52e4ab..51bd5a0b69ae 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -38,7 +38,9 @@ config TRUSTED_KEYS
config ENCRYPTED_KEYS
tristate "ENCRYPTED KEYS"
- depends on KEYS && TRUSTED_KEYS
+ depends on KEYS
+ select CRYPTO
+ select CRYPTO_HMAC
select CRYPTO_AES
select CRYPTO_CBC
select CRYPTO_SHA256
@@ -186,7 +188,7 @@ source security/smack/Kconfig
source security/tomoyo/Kconfig
source security/apparmor/Kconfig
-source security/integrity/ima/Kconfig
+source security/integrity/Kconfig
choice
prompt "Default security module"
diff --git a/security/Makefile b/security/Makefile
index 8bb0fe9e1ca9..a5e502f8a05b 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -24,5 +24,5 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/built-in.o
obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
# Object integrity file lists
-subdir-$(CONFIG_IMA) += integrity/ima
-obj-$(CONFIG_IMA) += integrity/ima/built-in.o
+subdir-$(CONFIG_INTEGRITY) += integrity
+obj-$(CONFIG_INTEGRITY) += integrity/built-in.o
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 0848292982a2..69ddb47787b2 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -200,7 +200,7 @@ void __init aa_destroy_aafs(void)
*
* Returns: error on failure
*/
-int __init aa_create_aafs(void)
+static int __init aa_create_aafs(void)
{
int error;
diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c
index 649fad88869b..7ee05c6f3c64 100644
--- a/security/apparmor/ipc.c
+++ b/security/apparmor/ipc.c
@@ -19,6 +19,7 @@
#include "include/capability.h"
#include "include/context.h"
#include "include/policy.h"
+#include "include/ipc.h"
/* call back to audit ptrace fields */
static void audit_cb(struct audit_buffer *ab, void *va)
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c
index b82e383beb77..9516948041ad 100644
--- a/security/apparmor/lib.c
+++ b/security/apparmor/lib.c
@@ -18,6 +18,7 @@
#include <linux/vmalloc.h>
#include "include/audit.h"
+#include "include/apparmor.h"
/**
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index d6d9a57b5652..741dd13e089b 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -381,11 +381,11 @@ static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
profile->file.trans.size = size;
for (i = 0; i < size; i++) {
char *str;
- int c, j, size = unpack_strdup(e, &str, NULL);
+ int c, j, size2 = unpack_strdup(e, &str, NULL);
/* unpack_strdup verifies that the last character is
* null termination byte.
*/
- if (!size)
+ if (!size2)
goto fail;
profile->file.trans.table[i] = str;
/* verify that name doesn't start with space */
@@ -393,7 +393,7 @@ static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
goto fail;
/* count internal # of internal \0 */
- for (c = j = 0; j < size - 2; j++) {
+ for (c = j = 0; j < size2 - 2; j++) {
if (!str[j])
c++;
}
@@ -440,11 +440,11 @@ static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
if (size > RLIM_NLIMITS)
goto fail;
for (i = 0; i < size; i++) {
- u64 tmp = 0;
+ u64 tmp2 = 0;
int a = aa_map_resource(i);
- if (!unpack_u64(e, &tmp, NULL))
+ if (!unpack_u64(e, &tmp2, NULL))
goto fail;
- profile->rlimits.limits[a].rlim_max = tmp;
+ profile->rlimits.limits[a].rlim_max = tmp2;
}
if (!unpack_nameX(e, AA_ARRAYEND, NULL))
goto fail;
diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c
index 04a2cf8d1b65..1b41c542d376 100644
--- a/security/apparmor/procattr.c
+++ b/security/apparmor/procattr.c
@@ -16,6 +16,7 @@
#include "include/context.h"
#include "include/policy.h"
#include "include/domain.h"
+#include "include/procattr.h"
/**
diff --git a/security/commoncap.c b/security/commoncap.c
index a93b3b733079..ee4f8486e5f5 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -332,7 +332,8 @@ int cap_inode_killpriv(struct dentry *dentry)
*/
static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
struct linux_binprm *bprm,
- bool *effective)
+ bool *effective,
+ bool *has_cap)
{
struct cred *new = bprm->cred;
unsigned i;
@@ -341,6 +342,9 @@ static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
if (caps->magic_etc & VFS_CAP_FLAGS_EFFECTIVE)
*effective = true;
+ if (caps->magic_etc & VFS_CAP_REVISION_MASK)
+ *has_cap = true;
+
CAP_FOR_EACH_U32(i) {
__u32 permitted = caps->permitted.cap[i];
__u32 inheritable = caps->inheritable.cap[i];
@@ -424,7 +428,7 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data
* its xattrs and, if present, apply them to the proposed credentials being
* constructed by execve().
*/
-static int get_file_caps(struct linux_binprm *bprm, bool *effective)
+static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_cap)
{
struct dentry *dentry;
int rc = 0;
@@ -450,7 +454,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective)
goto out;
}
- rc = bprm_caps_from_vfs_caps(&vcaps, bprm, effective);
+ rc = bprm_caps_from_vfs_caps(&vcaps, bprm, effective, has_cap);
if (rc == -EINVAL)
printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
__func__, rc, bprm->filename);
@@ -475,11 +479,11 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
{
const struct cred *old = current_cred();
struct cred *new = bprm->cred;
- bool effective;
+ bool effective, has_cap = false;
int ret;
effective = false;
- ret = get_file_caps(bprm, &effective);
+ ret = get_file_caps(bprm, &effective, &has_cap);
if (ret < 0)
return ret;
@@ -489,7 +493,7 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
* for a setuid root binary run by a non-root user. Do set it
* for a root user just to cause least surprise to an admin.
*/
- if (effective && new->uid != 0 && new->euid == 0) {
+ if (has_cap && new->uid != 0 && new->euid == 0) {
warn_setuid_and_fcaps_mixed(bprm->filename);
goto skip;
}
diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig
new file mode 100644
index 000000000000..4bf00acf7937
--- /dev/null
+++ b/security/integrity/Kconfig
@@ -0,0 +1,7 @@
+#
+config INTEGRITY
+ def_bool y
+ depends on IMA || EVM
+
+source security/integrity/ima/Kconfig
+source security/integrity/evm/Kconfig
diff --git a/security/integrity/Makefile b/security/integrity/Makefile
new file mode 100644
index 000000000000..0ae44aea6516
--- /dev/null
+++ b/security/integrity/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for caching inode integrity data (iint)
+#
+
+obj-$(CONFIG_INTEGRITY) += integrity.o
+
+integrity-y := iint.o
+
+subdir-$(CONFIG_IMA) += ima
+obj-$(CONFIG_IMA) += ima/built-in.o
+subdir-$(CONFIG_EVM) += evm
+obj-$(CONFIG_EVM) += evm/built-in.o
diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig
new file mode 100644
index 000000000000..afbb59dd262d
--- /dev/null
+++ b/security/integrity/evm/Kconfig
@@ -0,0 +1,13 @@
+config EVM
+ boolean "EVM support"
+ depends on SECURITY && KEYS && (TRUSTED_KEYS=y || TRUSTED_KEYS=n)
+ select CRYPTO_HMAC
+ select CRYPTO_MD5
+ select CRYPTO_SHA1
+ select ENCRYPTED_KEYS
+ default n
+ help
+ EVM protects a file's security extended attributes against
+ integrity attacks.
+
+ If you are unsure how to answer this question, answer N.
diff --git a/security/integrity/evm/Makefile b/security/integrity/evm/Makefile
new file mode 100644
index 000000000000..7393c415a066
--- /dev/null
+++ b/security/integrity/evm/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for building the Extended Verification Module(EVM)
+#
+obj-$(CONFIG_EVM) += evm.o
+
+evm-y := evm_main.o evm_crypto.o evm_secfs.o
+evm-$(CONFIG_FS_POSIX_ACL) += evm_posix_acl.o
diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h
new file mode 100644
index 000000000000..d320f5197437
--- /dev/null
+++ b/security/integrity/evm/evm.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2005-2010 IBM Corporation
+ *
+ * Authors:
+ * Mimi Zohar <zohar@us.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: evm.h
+ *
+ */
+#include <linux/xattr.h>
+#include <linux/security.h>
+#include "../integrity.h"
+
+extern int evm_initialized;
+extern char *evm_hmac;
+
+extern struct crypto_shash *hmac_tfm;
+
+/* List of EVM protected security xattrs */
+extern char *evm_config_xattrnames[];
+
+extern int evm_init_key(void);
+extern int evm_update_evmxattr(struct dentry *dentry,
+ const char *req_xattr_name,
+ const char *req_xattr_value,
+ size_t req_xattr_value_len);
+extern int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
+ const char *req_xattr_value,
+ size_t req_xattr_value_len, char *digest);
+extern int evm_init_hmac(struct inode *inode, const struct xattr *xattr,
+ char *hmac_val);
+extern int evm_init_secfs(void);
+extern void evm_cleanup_secfs(void);
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
new file mode 100644
index 000000000000..5dd5b140242c
--- /dev/null
+++ b/security/integrity/evm/evm_crypto.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2005-2010 IBM Corporation
+ *
+ * Authors:
+ * Mimi Zohar <zohar@us.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: evm_crypto.c
+ * Using root's kernel master key (kmk), calculate the HMAC
+ */
+
+#include <linux/module.h>
+#include <linux/crypto.h>
+#include <linux/xattr.h>
+#include <keys/encrypted-type.h>
+#include <crypto/hash.h>
+#include "evm.h"
+
+#define EVMKEY "evm-key"
+#define MAX_KEY_SIZE 128
+static unsigned char evmkey[MAX_KEY_SIZE];
+static int evmkey_len = MAX_KEY_SIZE;
+
+struct crypto_shash *hmac_tfm;
+
+static struct shash_desc *init_desc(void)
+{
+ int rc;
+ struct shash_desc *desc;
+
+ if (hmac_tfm == NULL) {
+ hmac_tfm = crypto_alloc_shash(evm_hmac, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(hmac_tfm)) {
+ pr_err("Can not allocate %s (reason: %ld)\n",
+ evm_hmac, PTR_ERR(hmac_tfm));
+ rc = PTR_ERR(hmac_tfm);
+ hmac_tfm = NULL;
+ return ERR_PTR(rc);
+ }
+ }
+
+ desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(hmac_tfm),
+ GFP_KERNEL);
+ if (!desc)
+ return ERR_PTR(-ENOMEM);
+
+ desc->tfm = hmac_tfm;
+ desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ rc = crypto_shash_setkey(hmac_tfm, evmkey, evmkey_len);
+ if (rc)
+ goto out;
+ rc = crypto_shash_init(desc);
+out:
+ if (rc) {
+ kfree(desc);
+ return ERR_PTR(rc);
+ }
+ return desc;
+}
+
+/* Protect against 'cutting & pasting' security.evm xattr, include inode
+ * specific info.
+ *
+ * (Additional directory/file metadata needs to be added for more complete
+ * protection.)
+ */
+static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
+ char *digest)
+{
+ struct h_misc {
+ unsigned long ino;
+ __u32 generation;
+ uid_t uid;
+ gid_t gid;
+ umode_t mode;
+ } hmac_misc;
+
+ memset(&hmac_misc, 0, sizeof hmac_misc);
+ hmac_misc.ino = inode->i_ino;
+ hmac_misc.generation = inode->i_generation;
+ hmac_misc.uid = inode->i_uid;
+ hmac_misc.gid = inode->i_gid;
+ hmac_misc.mode = inode->i_mode;
+ crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof hmac_misc);
+ crypto_shash_final(desc, digest);
+}
+
+/*
+ * Calculate the HMAC value across the set of protected security xattrs.
+ *
+ * Instead of retrieving the requested xattr, for performance, calculate
+ * the hmac using the requested xattr value. Don't alloc/free memory for
+ * each xattr, but attempt to re-use the previously allocated memory.
+ */
+int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
+ const char *req_xattr_value, size_t req_xattr_value_len,
+ char *digest)
+{
+ struct inode *inode = dentry->d_inode;
+ struct shash_desc *desc;
+ char **xattrname;
+ size_t xattr_size = 0;
+ char *xattr_value = NULL;
+ int error;
+ int size;
+
+ if (!inode->i_op || !inode->i_op->getxattr)
+ return -EOPNOTSUPP;
+ desc = init_desc();
+ if (IS_ERR(desc))
+ return PTR_ERR(desc);
+
+ error = -ENODATA;
+ for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) {
+ if ((req_xattr_name && req_xattr_value)
+ && !strcmp(*xattrname, req_xattr_name)) {
+ error = 0;
+ crypto_shash_update(desc, (const u8 *)req_xattr_value,
+ req_xattr_value_len);
+ continue;
+ }
+ size = vfs_getxattr_alloc(dentry, *xattrname,
+ &xattr_value, xattr_size, GFP_NOFS);
+ if (size == -ENOMEM) {
+ error = -ENOMEM;
+ goto out;
+ }
+ if (size < 0)
+ continue;
+
+ error = 0;
+ xattr_size = size;
+ crypto_shash_update(desc, (const u8 *)xattr_value, xattr_size);
+ }
+ hmac_add_misc(desc, inode, digest);
+
+out:
+ kfree(xattr_value);
+ kfree(desc);
+ return error;
+}
+
+/*
+ * Calculate the hmac and update security.evm xattr
+ *
+ * Expects to be called with i_mutex locked.
+ */
+int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
+ const char *xattr_value, size_t xattr_value_len)
+{
+ struct inode *inode = dentry->d_inode;
+ struct evm_ima_xattr_data xattr_data;
+ int rc = 0;
+
+ rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
+ xattr_value_len, xattr_data.digest);
+ if (rc == 0) {
+ xattr_data.type = EVM_XATTR_HMAC;
+ rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_EVM,
+ &xattr_data,
+ sizeof(xattr_data), 0);
+ }
+ else if (rc == -ENODATA)
+ rc = inode->i_op->removexattr(dentry, XATTR_NAME_EVM);
+ return rc;
+}
+
+int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr,
+ char *hmac_val)
+{
+ struct shash_desc *desc;
+
+ desc = init_desc();
+ if (IS_ERR(desc)) {
+ printk(KERN_INFO "init_desc failed\n");
+ return PTR_ERR(desc);
+ }
+
+ crypto_shash_update(desc, lsm_xattr->value, lsm_xattr->value_len);
+ hmac_add_misc(desc, inode, hmac_val);
+ kfree(desc);
+ return 0;
+}
+
+/*
+ * Get the key from the TPM for the SHA1-HMAC
+ */
+int evm_init_key(void)
+{
+ struct key *evm_key;
+ struct encrypted_key_payload *ekp;
+ int rc = 0;
+
+ evm_key = request_key(&key_type_encrypted, EVMKEY, NULL);
+ if (IS_ERR(evm_key))
+ return -ENOENT;
+
+ down_read(&evm_key->sem);
+ ekp = evm_key->payload.data;
+ if (ekp->decrypted_datalen > MAX_KEY_SIZE) {
+ rc = -EINVAL;
+ goto out;
+ }
+ memcpy(evmkey, ekp->decrypted_data, ekp->decrypted_datalen);
+out:
+ /* burn the original key contents */
+ memset(ekp->decrypted_data, 0, ekp->decrypted_datalen);
+ up_read(&evm_key->sem);
+ key_put(evm_key);
+ return rc;
+}
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
new file mode 100644
index 000000000000..92d3d99a9f7b
--- /dev/null
+++ b/security/integrity/evm/evm_main.c
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2005-2010 IBM Corporation
+ *
+ * Author:
+ * Mimi Zohar <zohar@us.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: evm_main.c
+ * implements evm_inode_setxattr, evm_inode_post_setxattr,
+ * evm_inode_removexattr, and evm_verifyxattr
+ */
+
+#include <linux/module.h>
+#include <linux/crypto.h>
+#include <linux/xattr.h>
+#include <linux/integrity.h>
+#include <linux/evm.h>
+#include <crypto/hash.h>
+#include "evm.h"
+
+int evm_initialized;
+
+char *evm_hmac = "hmac(sha1)";
+
+char *evm_config_xattrnames[] = {
+#ifdef CONFIG_SECURITY_SELINUX
+ XATTR_NAME_SELINUX,
+#endif
+#ifdef CONFIG_SECURITY_SMACK
+ XATTR_NAME_SMACK,
+#endif
+ XATTR_NAME_CAPS,
+ NULL
+};
+
+static int evm_fixmode;
+static int __init evm_set_fixmode(char *str)
+{
+ if (strncmp(str, "fix", 3) == 0)
+ evm_fixmode = 1;
+ return 0;
+}
+__setup("evm=", evm_set_fixmode);
+
+/*
+ * evm_verify_hmac - calculate and compare the HMAC with the EVM xattr
+ *
+ * Compute the HMAC on the dentry's protected set of extended attributes
+ * and compare it against the stored security.evm xattr.
+ *
+ * For performance:
+ * - use the previoulsy retrieved xattr value and length to calculate the
+ * HMAC.)
+ * - cache the verification result in the iint, when available.
+ *
+ * Returns integrity status
+ */
+static enum integrity_status evm_verify_hmac(struct dentry *dentry,
+ const char *xattr_name,
+ char *xattr_value,
+ size_t xattr_value_len,
+ struct integrity_iint_cache *iint)
+{
+ struct evm_ima_xattr_data xattr_data;
+ enum integrity_status evm_status = INTEGRITY_PASS;
+ int rc;
+
+ if (iint && iint->evm_status == INTEGRITY_PASS)
+ return iint->evm_status;
+
+ /* if status is not PASS, try to check again - against -ENOMEM */
+
+ rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
+ xattr_value_len, xattr_data.digest);
+ if (rc < 0) {
+ evm_status = (rc == -ENODATA)
+ ? INTEGRITY_NOXATTRS : INTEGRITY_FAIL;
+ goto out;
+ }
+
+ xattr_data.type = EVM_XATTR_HMAC;
+ rc = vfs_xattr_cmp(dentry, XATTR_NAME_EVM, (u8 *)&xattr_data,
+ sizeof xattr_data, GFP_NOFS);
+ if (rc < 0)
+ evm_status = (rc == -ENODATA)
+ ? INTEGRITY_NOLABEL : INTEGRITY_FAIL;
+out:
+ if (iint)
+ iint->evm_status = evm_status;
+ return evm_status;
+}
+
+static int evm_protected_xattr(const char *req_xattr_name)
+{
+ char **xattrname;
+ int namelen;
+ int found = 0;
+
+ namelen = strlen(req_xattr_name);
+ for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) {
+ if ((strlen(*xattrname) == namelen)
+ && (strncmp(req_xattr_name, *xattrname, namelen) == 0)) {
+ found = 1;
+ break;
+ }
+ if (strncmp(req_xattr_name,
+ *xattrname + XATTR_SECURITY_PREFIX_LEN,
+ strlen(req_xattr_name)) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ return found;
+}
+
+/**
+ * evm_verifyxattr - verify the integrity of the requested xattr
+ * @dentry: object of the verify xattr
+ * @xattr_name: requested xattr
+ * @xattr_value: requested xattr value
+ * @xattr_value_len: requested xattr value length
+ *
+ * Calculate the HMAC for the given dentry and verify it against the stored
+ * security.evm xattr. For performance, use the xattr value and length
+ * previously retrieved to calculate the HMAC.
+ *
+ * Returns the xattr integrity status.
+ *
+ * This function requires the caller to lock the inode's i_mutex before it
+ * is executed.
+ */
+enum integrity_status evm_verifyxattr(struct dentry *dentry,
+ const char *xattr_name,
+ void *xattr_value, size_t xattr_value_len,
+ struct integrity_iint_cache *iint)
+{
+ if (!evm_initialized || !evm_protected_xattr(xattr_name))
+ return INTEGRITY_UNKNOWN;
+
+ if (!iint) {
+ iint = integrity_iint_find(dentry->d_inode);
+ if (!iint)
+ return INTEGRITY_UNKNOWN;
+ }
+ return evm_verify_hmac(dentry, xattr_name, xattr_value,
+ xattr_value_len, iint);
+}
+EXPORT_SYMBOL_GPL(evm_verifyxattr);
+
+/*
+ * evm_verify_current_integrity - verify the dentry's metadata integrity
+ * @dentry: pointer to the affected dentry
+ *
+ * Verify and return the dentry's metadata integrity. The exceptions are
+ * before EVM is initialized or in 'fix' mode.
+ */
+static enum integrity_status evm_verify_current_integrity(struct dentry *dentry)
+{
+ struct inode *inode = dentry->d_inode;
+
+ if (!evm_initialized || !S_ISREG(inode->i_mode) || evm_fixmode)
+ return 0;
+ return evm_verify_hmac(dentry, NULL, NULL, 0, NULL);
+}
+
+/*
+ * evm_protect_xattr - protect the EVM extended attribute
+ *
+ * Prevent security.evm from being modified or removed without the
+ * necessary permissions or when the existing value is invalid.
+ *
+ * The posix xattr acls are 'system' prefixed, which normally would not
+ * affect security.evm. An interesting side affect of writing posix xattr
+ * acls is their modifying of the i_mode, which is included in security.evm.
+ * For posix xattr acls only, permit security.evm, even if it currently
+ * doesn't exist, to be updated.
+ */
+static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
+ const void *xattr_value, size_t xattr_value_len)
+{
+ enum integrity_status evm_status;
+
+ if (strcmp(xattr_name, XATTR_NAME_EVM) == 0) {
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ } else if (!evm_protected_xattr(xattr_name)) {
+ if (!posix_xattr_acl(xattr_name))
+ return 0;
+ evm_status = evm_verify_current_integrity(dentry);
+ if ((evm_status == INTEGRITY_PASS) ||
+ (evm_status == INTEGRITY_NOXATTRS))
+ return 0;
+ return -EPERM;
+ }
+ evm_status = evm_verify_current_integrity(dentry);
+ return evm_status == INTEGRITY_PASS ? 0 : -EPERM;
+}
+
+/**
+ * evm_inode_setxattr - protect the EVM extended attribute
+ * @dentry: pointer to the affected dentry
+ * @xattr_name: pointer to the affected extended attribute name
+ * @xattr_value: pointer to the new extended attribute value
+ * @xattr_value_len: pointer to the new extended attribute value length
+ *
+ * Updating 'security.evm' requires CAP_SYS_ADMIN privileges and that
+ * the current value is valid.
+ */
+int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name,
+ const void *xattr_value, size_t xattr_value_len)
+{
+ return evm_protect_xattr(dentry, xattr_name, xattr_value,
+ xattr_value_len);
+}
+
+/**
+ * evm_inode_removexattr - protect the EVM extended attribute
+ * @dentry: pointer to the affected dentry
+ * @xattr_name: pointer to the affected extended attribute name
+ *
+ * Removing 'security.evm' requires CAP_SYS_ADMIN privileges and that
+ * the current value is valid.
+ */
+int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name)
+{
+ return evm_protect_xattr(dentry, xattr_name, NULL, 0);
+}
+
+/**
+ * evm_inode_post_setxattr - update 'security.evm' to reflect the changes
+ * @dentry: pointer to the affected dentry
+ * @xattr_name: pointer to the affected extended attribute name
+ * @xattr_value: pointer to the new extended attribute value
+ * @xattr_value_len: pointer to the new extended attribute value length
+ *
+ * Update the HMAC stored in 'security.evm' to reflect the change.
+ *
+ * No need to take the i_mutex lock here, as this function is called from
+ * __vfs_setxattr_noperm(). The caller of which has taken the inode's
+ * i_mutex lock.
+ */
+void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
+ const void *xattr_value, size_t xattr_value_len)
+{
+ if (!evm_initialized || (!evm_protected_xattr(xattr_name)
+ && !posix_xattr_acl(xattr_name)))
+ return;
+
+ evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
+ return;
+}
+
+/**
+ * evm_inode_post_removexattr - update 'security.evm' after removing the xattr
+ * @dentry: pointer to the affected dentry
+ * @xattr_name: pointer to the affected extended attribute name
+ *
+ * Update the HMAC stored in 'security.evm' to reflect removal of the xattr.
+ */
+void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
+{
+ struct inode *inode = dentry->d_inode;
+
+ if (!evm_initialized || !evm_protected_xattr(xattr_name))
+ return;
+
+ mutex_lock(&inode->i_mutex);
+ evm_update_evmxattr(dentry, xattr_name, NULL, 0);
+ mutex_unlock(&inode->i_mutex);
+ return;
+}
+
+/**
+ * evm_inode_setattr - prevent updating an invalid EVM extended attribute
+ * @dentry: pointer to the affected dentry
+ */
+int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ unsigned int ia_valid = attr->ia_valid;
+ enum integrity_status evm_status;
+
+ if (!(ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)))
+ return 0;
+ evm_status = evm_verify_current_integrity(dentry);
+ if ((evm_status == INTEGRITY_PASS) ||
+ (evm_status == INTEGRITY_NOXATTRS))
+ return 0;
+ return -EPERM;
+}
+
+/**
+ * evm_inode_post_setattr - update 'security.evm' after modifying metadata
+ * @dentry: pointer to the affected dentry
+ * @ia_valid: for the UID and GID status
+ *
+ * For now, update the HMAC stored in 'security.evm' to reflect UID/GID
+ * changes.
+ *
+ * This function is called from notify_change(), which expects the caller
+ * to lock the inode's i_mutex.
+ */
+void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
+{
+ if (!evm_initialized)
+ return;
+
+ if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
+ evm_update_evmxattr(dentry, NULL, NULL, 0);
+ return;
+}
+
+/*
+ * evm_inode_init_security - initializes security.evm
+ */
+int evm_inode_init_security(struct inode *inode,
+ const struct xattr *lsm_xattr,
+ struct xattr *evm_xattr)
+{
+ struct evm_ima_xattr_data *xattr_data;
+ int rc;
+
+ if (!evm_initialized || !evm_protected_xattr(lsm_xattr->name))
+ return 0;
+
+ xattr_data = kzalloc(sizeof(*xattr_data), GFP_NOFS);
+ if (!xattr_data)
+ return -ENOMEM;
+
+ xattr_data->type = EVM_XATTR_HMAC;
+ rc = evm_init_hmac(inode, lsm_xattr, xattr_data->digest);
+ if (rc < 0)
+ goto out;
+
+ evm_xattr->value = xattr_data;
+ evm_xattr->value_len = sizeof(*xattr_data);
+ evm_xattr->name = kstrdup(XATTR_EVM_SUFFIX, GFP_NOFS);
+ return 0;
+out:
+ kfree(xattr_data);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(evm_inode_init_security);
+
+static int __init init_evm(void)
+{
+ int error;
+
+ error = evm_init_secfs();
+ if (error < 0) {
+ printk(KERN_INFO "EVM: Error registering secfs\n");
+ goto err;
+ }
+err:
+ return error;
+}
+
+static void __exit cleanup_evm(void)
+{
+ evm_cleanup_secfs();
+ if (hmac_tfm)
+ crypto_free_shash(hmac_tfm);
+}
+
+/*
+ * evm_display_config - list the EVM protected security extended attributes
+ */
+static int __init evm_display_config(void)
+{
+ char **xattrname;
+
+ for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++)
+ printk(KERN_INFO "EVM: %s\n", *xattrname);
+ return 0;
+}
+
+pure_initcall(evm_display_config);
+late_initcall(init_evm);
+
+MODULE_DESCRIPTION("Extended Verification Module");
+MODULE_LICENSE("GPL");
diff --git a/security/integrity/evm/evm_posix_acl.c b/security/integrity/evm/evm_posix_acl.c
new file mode 100644
index 000000000000..b1753e98bf9a
--- /dev/null
+++ b/security/integrity/evm/evm_posix_acl.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2011 IBM Corporation
+ *
+ * Author:
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/xattr.h>
+
+int posix_xattr_acl(char *xattr)
+{
+ int xattr_len = strlen(xattr);
+
+ if ((strlen(XATTR_NAME_POSIX_ACL_ACCESS) == xattr_len)
+ && (strncmp(XATTR_NAME_POSIX_ACL_ACCESS, xattr, xattr_len) == 0))
+ return 1;
+ if ((strlen(XATTR_NAME_POSIX_ACL_DEFAULT) == xattr_len)
+ && (strncmp(XATTR_NAME_POSIX_ACL_DEFAULT, xattr, xattr_len) == 0))
+ return 1;
+ return 0;
+}
diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c
new file mode 100644
index 000000000000..ac7629950578
--- /dev/null
+++ b/security/integrity/evm/evm_secfs.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2010 IBM Corporation
+ *
+ * Authors:
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: evm_secfs.c
+ * - Used to signal when key is on keyring
+ * - Get the key and enable EVM
+ */
+
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include "evm.h"
+
+static struct dentry *evm_init_tpm;
+
+/**
+ * evm_read_key - read() for <securityfs>/evm
+ *
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @count: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t evm_read_key(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char temp[80];
+ ssize_t rc;
+
+ if (*ppos != 0)
+ return 0;
+
+ sprintf(temp, "%d", evm_initialized);
+ rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
+
+ return rc;
+}
+
+/**
+ * evm_write_key - write() for <securityfs>/evm
+ * @file: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Used to signal that key is on the kernel key ring.
+ * - get the integrity hmac key from the kernel key ring
+ * - create list of hmac protected extended attributes
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t evm_write_key(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char temp[80];
+ int i, error;
+
+ if (!capable(CAP_SYS_ADMIN) || evm_initialized)
+ return -EPERM;
+
+ if (count >= sizeof(temp) || count == 0)
+ return -EINVAL;
+
+ if (copy_from_user(temp, buf, count) != 0)
+ return -EFAULT;
+
+ temp[count] = '\0';
+
+ if ((sscanf(temp, "%d", &i) != 1) || (i != 1))
+ return -EINVAL;
+
+ error = evm_init_key();
+ if (!error) {
+ evm_initialized = 1;
+ pr_info("EVM: initialized\n");
+ } else
+ pr_err("EVM: initialization failed\n");
+ return count;
+}
+
+static const struct file_operations evm_key_ops = {
+ .read = evm_read_key,
+ .write = evm_write_key,
+};
+
+int __init evm_init_secfs(void)
+{
+ int error = 0;
+
+ evm_init_tpm = securityfs_create_file("evm", S_IRUSR | S_IRGRP,
+ NULL, NULL, &evm_key_ops);
+ if (!evm_init_tpm || IS_ERR(evm_init_tpm))
+ error = -EFAULT;
+ return error;
+}
+
+void __exit evm_cleanup_secfs(void)
+{
+ if (evm_init_tpm)
+ securityfs_remove(evm_init_tpm);
+}
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
new file mode 100644
index 000000000000..399641c3e846
--- /dev/null
+++ b/security/integrity/iint.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2008 IBM Corporation
+ *
+ * Authors:
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: integrity_iint.c
+ * - implements the integrity hooks: integrity_inode_alloc,
+ * integrity_inode_free
+ * - cache integrity information associated with an inode
+ * using a rbtree tree.
+ */
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/rbtree.h>
+#include "integrity.h"
+
+static struct rb_root integrity_iint_tree = RB_ROOT;
+static DEFINE_SPINLOCK(integrity_iint_lock);
+static struct kmem_cache *iint_cache __read_mostly;
+
+int iint_initialized;
+
+/*
+ * __integrity_iint_find - return the iint associated with an inode
+ */
+static struct integrity_iint_cache *__integrity_iint_find(struct inode *inode)
+{
+ struct integrity_iint_cache *iint;
+ struct rb_node *n = integrity_iint_tree.rb_node;
+
+ assert_spin_locked(&integrity_iint_lock);
+
+ while (n) {
+ iint = rb_entry(n, struct integrity_iint_cache, rb_node);
+
+ if (inode < iint->inode)
+ n = n->rb_left;
+ else if (inode > iint->inode)
+ n = n->rb_right;
+ else
+ break;
+ }
+ if (!n)
+ return NULL;
+
+ return iint;
+}
+
+/*
+ * integrity_iint_find - return the iint associated with an inode
+ */
+struct integrity_iint_cache *integrity_iint_find(struct inode *inode)
+{
+ struct integrity_iint_cache *iint;
+
+ if (!IS_IMA(inode))
+ return NULL;
+
+ spin_lock(&integrity_iint_lock);
+ iint = __integrity_iint_find(inode);
+ spin_unlock(&integrity_iint_lock);
+
+ return iint;
+}
+
+static void iint_free(struct integrity_iint_cache *iint)
+{
+ iint->version = 0;
+ iint->flags = 0UL;
+ iint->evm_status = INTEGRITY_UNKNOWN;
+ kmem_cache_free(iint_cache, iint);
+}
+
+/**
+ * integrity_inode_alloc - allocate an iint associated with an inode
+ * @inode: pointer to the inode
+ */
+int integrity_inode_alloc(struct inode *inode)
+{
+ struct rb_node **p;
+ struct rb_node *new_node, *parent = NULL;
+ struct integrity_iint_cache *new_iint, *test_iint;
+ int rc;
+
+ new_iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
+ if (!new_iint)
+ return -ENOMEM;
+
+ new_iint->inode = inode;
+ new_node = &new_iint->rb_node;
+
+ mutex_lock(&inode->i_mutex); /* i_flags */
+ spin_lock(&integrity_iint_lock);
+
+ p = &integrity_iint_tree.rb_node;
+ while (*p) {
+ parent = *p;
+ test_iint = rb_entry(parent, struct integrity_iint_cache,
+ rb_node);
+ rc = -EEXIST;
+ if (inode < test_iint->inode)
+ p = &(*p)->rb_left;
+ else if (inode > test_iint->inode)
+ p = &(*p)->rb_right;
+ else
+ goto out_err;
+ }
+
+ inode->i_flags |= S_IMA;
+ rb_link_node(new_node, parent, p);
+ rb_insert_color(new_node, &integrity_iint_tree);
+
+ spin_unlock(&integrity_iint_lock);
+ mutex_unlock(&inode->i_mutex); /* i_flags */
+
+ return 0;
+out_err:
+ spin_unlock(&integrity_iint_lock);
+ mutex_unlock(&inode->i_mutex); /* i_flags */
+ iint_free(new_iint);
+
+ return rc;
+}
+
+/**
+ * integrity_inode_free - called on security_inode_free
+ * @inode: pointer to the inode
+ *
+ * Free the integrity information(iint) associated with an inode.
+ */
+void integrity_inode_free(struct inode *inode)
+{
+ struct integrity_iint_cache *iint;
+
+ if (!IS_IMA(inode))
+ return;
+
+ spin_lock(&integrity_iint_lock);
+ iint = __integrity_iint_find(inode);
+ rb_erase(&iint->rb_node, &integrity_iint_tree);
+ spin_unlock(&integrity_iint_lock);
+
+ iint_free(iint);
+}
+
+static void init_once(void *foo)
+{
+ struct integrity_iint_cache *iint = foo;
+
+ memset(iint, 0, sizeof *iint);
+ iint->version = 0;
+ iint->flags = 0UL;
+ mutex_init(&iint->mutex);
+ iint->evm_status = INTEGRITY_UNKNOWN;
+}
+
+static int __init integrity_iintcache_init(void)
+{
+ iint_cache =
+ kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
+ 0, SLAB_PANIC, init_once);
+ iint_initialized = 1;
+ return 0;
+}
+security_initcall(integrity_iintcache_init);
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index b6ecfd4d8d78..19c053b82303 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -3,6 +3,7 @@
config IMA
bool "Integrity Measurement Architecture(IMA)"
depends on SECURITY
+ select INTEGRITY
select SECURITYFS
select CRYPTO
select CRYPTO_HMAC
diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile
index 787c4cb916cd..5690c021de8f 100644
--- a/security/integrity/ima/Makefile
+++ b/security/integrity/ima/Makefile
@@ -6,4 +6,4 @@
obj-$(CONFIG_IMA) += ima.o
ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
- ima_policy.o ima_iint.o ima_audit.o
+ ima_policy.o ima_audit.o
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 08408bd71462..3ccf7acac6df 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -24,18 +24,19 @@
#include <linux/tpm.h>
#include <linux/audit.h>
+#include "../integrity.h"
+
enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_ASCII };
enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
/* digest size for IMA, fits SHA1 or MD5 */
-#define IMA_DIGEST_SIZE 20
+#define IMA_DIGEST_SIZE SHA1_DIGEST_SIZE
#define IMA_EVENT_NAME_LEN_MAX 255
#define IMA_HASH_BITS 9
#define IMA_MEASURE_HTABLE_SIZE (1 << IMA_HASH_BITS)
/* set during initialization */
-extern int iint_initialized;
extern int ima_initialized;
extern int ima_used_chip;
extern char *ima_hash;
@@ -96,34 +97,21 @@ static inline unsigned long ima_hash_key(u8 *digest)
return hash_long(*digest, IMA_HASH_BITS);
}
-/* iint cache flags */
-#define IMA_MEASURED 0x01
-
-/* integrity data associated with an inode */
-struct ima_iint_cache {
- struct rb_node rb_node; /* rooted in ima_iint_tree */
- struct inode *inode; /* back pointer to inode in question */
- u64 version; /* track inode changes */
- unsigned char flags;
- u8 digest[IMA_DIGEST_SIZE];
- struct mutex mutex; /* protects: version, flags, digest */
-};
-
/* LIM API function definitions */
int ima_must_measure(struct inode *inode, int mask, int function);
-int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file);
-void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
+int ima_collect_measurement(struct integrity_iint_cache *iint,
+ struct file *file);
+void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
const unsigned char *filename);
int ima_store_template(struct ima_template_entry *entry, int violation,
struct inode *inode);
-void ima_template_show(struct seq_file *m, void *e,
- enum ima_show_type show);
+void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show);
/* rbtree tree calls to lookup, insert, delete
* integrity data associated with an inode.
*/
-struct ima_iint_cache *ima_iint_insert(struct inode *inode);
-struct ima_iint_cache *ima_iint_find(struct inode *inode);
+struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
+struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
/* IMA policy related functions */
enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK };
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index da36d2c085a4..0d50df04ccc4 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -126,7 +126,8 @@ int ima_must_measure(struct inode *inode, int mask, int function)
*
* Return 0 on success, error code otherwise
*/
-int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file)
+int ima_collect_measurement(struct integrity_iint_cache *iint,
+ struct file *file)
{
int result = -EEXIST;
@@ -156,8 +157,8 @@ int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file)
*
* Must be called with iint->mutex held.
*/
-void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
- const unsigned char *filename)
+void ima_store_measurement(struct integrity_iint_cache *iint,
+ struct file *file, const unsigned char *filename)
{
const char *op = "add_template_measure";
const char *audit_cause = "ENOMEM";
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index ef21b96a0b42..e1aa2b482dd2 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -287,7 +287,7 @@ static atomic_t policy_opencount = ATOMIC_INIT(1);
/*
* ima_open_policy: sequentialize access to the policy file
*/
-int ima_open_policy(struct inode * inode, struct file * filp)
+static int ima_open_policy(struct inode * inode, struct file * filp)
{
/* No point in being allowed to open it if you aren't going to write */
if (!(filp->f_flags & O_WRONLY))
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c
deleted file mode 100644
index 4ae73040ab7b..000000000000
--- a/security/integrity/ima/ima_iint.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2008 IBM Corporation
- *
- * Authors:
- * Mimi Zohar <zohar@us.ibm.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2 of the
- * License.
- *
- * File: ima_iint.c
- * - implements the IMA hooks: ima_inode_alloc, ima_inode_free
- * - cache integrity information associated with an inode
- * using a rbtree tree.
- */
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/rbtree.h>
-#include "ima.h"
-
-static struct rb_root ima_iint_tree = RB_ROOT;
-static DEFINE_SPINLOCK(ima_iint_lock);
-static struct kmem_cache *iint_cache __read_mostly;
-
-int iint_initialized = 0;
-
-/*
- * __ima_iint_find - return the iint associated with an inode
- */
-static struct ima_iint_cache *__ima_iint_find(struct inode *inode)
-{
- struct ima_iint_cache *iint;
- struct rb_node *n = ima_iint_tree.rb_node;
-
- assert_spin_locked(&ima_iint_lock);
-
- while (n) {
- iint = rb_entry(n, struct ima_iint_cache, rb_node);
-
- if (inode < iint->inode)
- n = n->rb_left;
- else if (inode > iint->inode)
- n = n->rb_right;
- else
- break;
- }
- if (!n)
- return NULL;
-
- return iint;
-}
-
-/*
- * ima_iint_find - return the iint associated with an inode
- */
-struct ima_iint_cache *ima_iint_find(struct inode *inode)
-{
- struct ima_iint_cache *iint;
-
- if (!IS_IMA(inode))
- return NULL;
-
- spin_lock(&ima_iint_lock);
- iint = __ima_iint_find(inode);
- spin_unlock(&ima_iint_lock);
-
- return iint;
-}
-
-static void iint_free(struct ima_iint_cache *iint)
-{
- iint->version = 0;
- iint->flags = 0UL;
- kmem_cache_free(iint_cache, iint);
-}
-
-/**
- * ima_inode_alloc - allocate an iint associated with an inode
- * @inode: pointer to the inode
- */
-int ima_inode_alloc(struct inode *inode)
-{
- struct rb_node **p;
- struct rb_node *new_node, *parent = NULL;
- struct ima_iint_cache *new_iint, *test_iint;
- int rc;
-
- new_iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
- if (!new_iint)
- return -ENOMEM;
-
- new_iint->inode = inode;
- new_node = &new_iint->rb_node;
-
- mutex_lock(&inode->i_mutex); /* i_flags */
- spin_lock(&ima_iint_lock);
-
- p = &ima_iint_tree.rb_node;
- while (*p) {
- parent = *p;
- test_iint = rb_entry(parent, struct ima_iint_cache, rb_node);
-
- rc = -EEXIST;
- if (inode < test_iint->inode)
- p = &(*p)->rb_left;
- else if (inode > test_iint->inode)
- p = &(*p)->rb_right;
- else
- goto out_err;
- }
-
- inode->i_flags |= S_IMA;
- rb_link_node(new_node, parent, p);
- rb_insert_color(new_node, &ima_iint_tree);
-
- spin_unlock(&ima_iint_lock);
- mutex_unlock(&inode->i_mutex); /* i_flags */
-
- return 0;
-out_err:
- spin_unlock(&ima_iint_lock);
- mutex_unlock(&inode->i_mutex); /* i_flags */
- iint_free(new_iint);
-
- return rc;
-}
-
-/**
- * ima_inode_free - called on security_inode_free
- * @inode: pointer to the inode
- *
- * Free the integrity information(iint) associated with an inode.
- */
-void ima_inode_free(struct inode *inode)
-{
- struct ima_iint_cache *iint;
-
- if (!IS_IMA(inode))
- return;
-
- spin_lock(&ima_iint_lock);
- iint = __ima_iint_find(inode);
- rb_erase(&iint->rb_node, &ima_iint_tree);
- spin_unlock(&ima_iint_lock);
-
- iint_free(iint);
-}
-
-static void init_once(void *foo)
-{
- struct ima_iint_cache *iint = foo;
-
- memset(iint, 0, sizeof *iint);
- iint->version = 0;
- iint->flags = 0UL;
- mutex_init(&iint->mutex);
-}
-
-static int __init ima_iintcache_init(void)
-{
- iint_cache =
- kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0,
- SLAB_PANIC, init_once);
- iint_initialized = 1;
- return 0;
-}
-security_initcall(ima_iintcache_init);
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 26b46ff74663..1eff5cb001e5 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -22,6 +22,7 @@
#include <linux/mount.h>
#include <linux/mman.h>
#include <linux/slab.h>
+#include <linux/ima.h>
#include "ima.h"
@@ -82,7 +83,7 @@ out:
"open_writers");
}
-static void ima_check_last_writer(struct ima_iint_cache *iint,
+static void ima_check_last_writer(struct integrity_iint_cache *iint,
struct inode *inode,
struct file *file)
{
@@ -105,12 +106,12 @@ static void ima_check_last_writer(struct ima_iint_cache *iint,
void ima_file_free(struct file *file)
{
struct inode *inode = file->f_dentry->d_inode;
- struct ima_iint_cache *iint;
+ struct integrity_iint_cache *iint;
if (!iint_initialized || !S_ISREG(inode->i_mode))
return;
- iint = ima_iint_find(inode);
+ iint = integrity_iint_find(inode);
if (!iint)
return;
@@ -121,7 +122,7 @@ static int process_measurement(struct file *file, const unsigned char *filename,
int mask, int function)
{
struct inode *inode = file->f_dentry->d_inode;
- struct ima_iint_cache *iint;
+ struct integrity_iint_cache *iint;
int rc = 0;
if (!ima_initialized || !S_ISREG(inode->i_mode))
@@ -131,9 +132,9 @@ static int process_measurement(struct file *file, const unsigned char *filename,
if (rc != 0)
return rc;
retry:
- iint = ima_iint_find(inode);
+ iint = integrity_iint_find(inode);
if (!iint) {
- rc = ima_inode_alloc(inode);
+ rc = integrity_inode_alloc(inode);
if (!rc || rc == -EEXIST)
goto retry;
return rc;
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
new file mode 100644
index 000000000000..3143a3c39868
--- /dev/null
+++ b/security/integrity/integrity.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2009-2010 IBM Corporation
+ *
+ * Authors:
+ * Mimi Zohar <zohar@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/integrity.h>
+#include <crypto/sha.h>
+
+/* iint cache flags */
+#define IMA_MEASURED 0x01
+
+enum evm_ima_xattr_type {
+ IMA_XATTR_DIGEST = 0x01,
+ EVM_XATTR_HMAC,
+ EVM_IMA_XATTR_DIGSIG,
+};
+
+struct evm_ima_xattr_data {
+ u8 type;
+ u8 digest[SHA1_DIGEST_SIZE];
+} __attribute__((packed));
+
+/* integrity data associated with an inode */
+struct integrity_iint_cache {
+ struct rb_node rb_node; /* rooted in integrity_iint_tree */
+ struct inode *inode; /* back pointer to inode in question */
+ u64 version; /* track inode changes */
+ unsigned char flags;
+ u8 digest[SHA1_DIGEST_SIZE];
+ struct mutex mutex; /* protects: version, flags, digest */
+ enum integrity_status evm_status;
+};
+
+/* rbtree tree calls to lookup, insert, delete
+ * integrity data associated with an inode.
+ */
+struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
+struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
+
+/* set during initialization */
+extern int iint_initialized;
diff --git a/security/keys/Makefile b/security/keys/Makefile
index b34cc6ee6900..a56f1ffdc64d 100644
--- a/security/keys/Makefile
+++ b/security/keys/Makefile
@@ -14,7 +14,7 @@ obj-y := \
user_defined.o
obj-$(CONFIG_TRUSTED_KEYS) += trusted.o
-obj-$(CONFIG_ENCRYPTED_KEYS) += ecryptfs_format.o encrypted.o
+obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/
obj-$(CONFIG_KEYS_COMPAT) += compat.o
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSCTL) += sysctl.o
diff --git a/security/keys/encrypted-keys/Makefile b/security/keys/encrypted-keys/Makefile
new file mode 100644
index 000000000000..6bc7a86d1027
--- /dev/null
+++ b/security/keys/encrypted-keys/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for encrypted keys
+#
+
+obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted.o ecryptfs_format.o
+obj-$(CONFIG_TRUSTED_KEYS) += masterkey_trusted.o
diff --git a/security/keys/ecryptfs_format.c b/security/keys/encrypted-keys/ecryptfs_format.c
index 6daa3b6ff9ed..6daa3b6ff9ed 100644
--- a/security/keys/ecryptfs_format.c
+++ b/security/keys/encrypted-keys/ecryptfs_format.c
diff --git a/security/keys/ecryptfs_format.h b/security/keys/encrypted-keys/ecryptfs_format.h
index 40294de238bb..40294de238bb 100644
--- a/security/keys/ecryptfs_format.h
+++ b/security/keys/encrypted-keys/ecryptfs_format.h
diff --git a/security/keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
index e7eca9ec4c65..f33804c1b4c8 100644
--- a/security/keys/encrypted.c
+++ b/security/keys/encrypted-keys/encrypted.c
@@ -299,31 +299,6 @@ out:
}
/*
- * request_trusted_key - request the trusted key
- *
- * Trusted keys are sealed to PCRs and other metadata. Although userspace
- * manages both trusted/encrypted key-types, like the encrypted key type
- * data, trusted key type data is not visible decrypted from userspace.
- */
-static struct key *request_trusted_key(const char *trusted_desc,
- u8 **master_key, size_t *master_keylen)
-{
- struct trusted_key_payload *tpayload;
- struct key *tkey;
-
- tkey = request_key(&key_type_trusted, trusted_desc, NULL);
- if (IS_ERR(tkey))
- goto error;
-
- down_read(&tkey->sem);
- tpayload = rcu_dereference(tkey->payload.data);
- *master_key = tpayload->key;
- *master_keylen = tpayload->key_len;
-error:
- return tkey;
-}
-
-/*
* request_user_key - request the user key
*
* Use a user provided key to encrypt/decrypt an encrypted-key.
@@ -469,8 +444,14 @@ static struct key *request_master_key(struct encrypted_key_payload *epayload,
goto out;
if (IS_ERR(mkey)) {
- pr_info("encrypted_key: key %s not found",
- epayload->master_desc);
+ int ret = PTR_ERR(epayload);
+
+ if (ret == -ENOTSUPP)
+ pr_info("encrypted_key: key %s not supported",
+ epayload->master_desc);
+ else
+ pr_info("encrypted_key: key %s not found",
+ epayload->master_desc);
goto out;
}
@@ -686,11 +667,19 @@ static int encrypted_key_decrypt(struct encrypted_key_payload *epayload,
return -EINVAL;
hex_encoded_data = hex_encoded_iv + (2 * ivsize) + 2;
- hex2bin(epayload->iv, hex_encoded_iv, ivsize);
- hex2bin(epayload->encrypted_data, hex_encoded_data, encrypted_datalen);
+ ret = hex2bin(epayload->iv, hex_encoded_iv, ivsize);
+ if (ret < 0)
+ return -EINVAL;
+ ret = hex2bin(epayload->encrypted_data, hex_encoded_data,
+ encrypted_datalen);
+ if (ret < 0)
+ return -EINVAL;
hmac = epayload->format + epayload->datablob_len;
- hex2bin(hmac, hex_encoded_data + (encrypted_datalen * 2), HASH_SIZE);
+ ret = hex2bin(hmac, hex_encoded_data + (encrypted_datalen * 2),
+ HASH_SIZE);
+ if (ret < 0)
+ return -EINVAL;
mkey = request_master_key(epayload, &master_key, &master_keylen);
if (IS_ERR(mkey))
diff --git a/security/keys/encrypted.h b/security/keys/encrypted-keys/encrypted.h
index cef5e2f2b7d1..b6ade8945250 100644
--- a/security/keys/encrypted.h
+++ b/security/keys/encrypted-keys/encrypted.h
@@ -2,6 +2,17 @@
#define __ENCRYPTED_KEY_H
#define ENCRYPTED_DEBUG 0
+#ifdef CONFIG_TRUSTED_KEYS
+extern struct key *request_trusted_key(const char *trusted_desc,
+ u8 **master_key, size_t *master_keylen);
+#else
+static inline struct key *request_trusted_key(const char *trusted_desc,
+ u8 **master_key,
+ size_t *master_keylen)
+{
+ return ERR_PTR(-EOPNOTSUPP);
+}
+#endif
#if ENCRYPTED_DEBUG
static inline void dump_master_key(const u8 *master_key, size_t master_keylen)
diff --git a/security/keys/encrypted-keys/masterkey_trusted.c b/security/keys/encrypted-keys/masterkey_trusted.c
new file mode 100644
index 000000000000..df87272e3f51
--- /dev/null
+++ b/security/keys/encrypted-keys/masterkey_trusted.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 IBM Corporation
+ * Copyright (C) 2010 Politecnico di Torino, Italy
+ * TORSEC group -- http://security.polito.it
+ *
+ * Authors:
+ * Mimi Zohar <zohar@us.ibm.com>
+ * Roberto Sassu <roberto.sassu@polito.it>
+ *
+ * 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.
+ *
+ * See Documentation/security/keys-trusted-encrypted.txt
+ */
+
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <keys/trusted-type.h>
+
+/*
+ * request_trusted_key - request the trusted key
+ *
+ * Trusted keys are sealed to PCRs and other metadata. Although userspace
+ * manages both trusted/encrypted key-types, like the encrypted key type
+ * data, trusted key type data is not visible decrypted from userspace.
+ */
+struct key *request_trusted_key(const char *trusted_desc,
+ u8 **master_key, size_t *master_keylen)
+{
+ struct trusted_key_payload *tpayload;
+ struct key *tkey;
+
+ tkey = request_key(&key_type_trusted, trusted_desc, NULL);
+ if (IS_ERR(tkey))
+ goto error;
+
+ down_read(&tkey->sem);
+ tpayload = rcu_dereference(tkey->payload.data);
+ *master_key = tpayload->key;
+ *master_keylen = tpayload->key_len;
+error:
+ return tkey;
+}
diff --git a/security/keys/gc.c b/security/keys/gc.c
index 89df6b5f203c..bf4d8da5a795 100644
--- a/security/keys/gc.c
+++ b/security/keys/gc.c
@@ -1,6 +1,6 @@
/* Key garbage collector
*
- * Copyright (C) 2009 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2009-2011 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
@@ -10,6 +10,8 @@
*/
#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/security.h>
#include <keys/keyring-type.h>
#include "internal.h"
@@ -19,17 +21,33 @@
unsigned key_gc_delay = 5 * 60;
/*
- * Reaper
+ * Reaper for unused keys.
+ */
+static void key_garbage_collector(struct work_struct *work);
+DECLARE_WORK(key_gc_work, key_garbage_collector);
+
+/*
+ * Reaper for links from keyrings to dead keys.
*/
static void key_gc_timer_func(unsigned long);
-static void key_garbage_collector(struct work_struct *);
static DEFINE_TIMER(key_gc_timer, key_gc_timer_func, 0, 0);
-static DECLARE_WORK(key_gc_work, key_garbage_collector);
-static key_serial_t key_gc_cursor; /* the last key the gc considered */
-static bool key_gc_again;
-static unsigned long key_gc_executing;
+
static time_t key_gc_next_run = LONG_MAX;
-static time_t key_gc_new_timer;
+static struct key_type *key_gc_dead_keytype;
+
+static unsigned long key_gc_flags;
+#define KEY_GC_KEY_EXPIRED 0 /* A key expired and needs unlinking */
+#define KEY_GC_REAP_KEYTYPE 1 /* A keytype is being unregistered */
+#define KEY_GC_REAPING_KEYTYPE 2 /* Cleared when keytype reaped */
+
+
+/*
+ * Any key whose type gets unregistered will be re-typed to this if it can't be
+ * immediately unlinked.
+ */
+struct key_type key_type_dead = {
+ .name = "dead",
+};
/*
* Schedule a garbage collection run.
@@ -42,31 +60,75 @@ void key_schedule_gc(time_t gc_at)
kenter("%ld", gc_at - now);
- if (gc_at <= now) {
- schedule_work(&key_gc_work);
+ if (gc_at <= now || test_bit(KEY_GC_REAP_KEYTYPE, &key_gc_flags)) {
+ kdebug("IMMEDIATE");
+ queue_work(system_nrt_wq, &key_gc_work);
} else if (gc_at < key_gc_next_run) {
+ kdebug("DEFERRED");
+ key_gc_next_run = gc_at;
expires = jiffies + (gc_at - now) * HZ;
mod_timer(&key_gc_timer, expires);
}
}
/*
- * The garbage collector timer kicked off
+ * Some key's cleanup time was met after it expired, so we need to get the
+ * reaper to go through a cycle finding expired keys.
*/
static void key_gc_timer_func(unsigned long data)
{
kenter("");
key_gc_next_run = LONG_MAX;
- schedule_work(&key_gc_work);
+ set_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags);
+ queue_work(system_nrt_wq, &key_gc_work);
+}
+
+/*
+ * wait_on_bit() sleep function for uninterruptible waiting
+ */
+static int key_gc_wait_bit(void *flags)
+{
+ schedule();
+ return 0;
+}
+
+/*
+ * Reap keys of dead type.
+ *
+ * We use three flags to make sure we see three complete cycles of the garbage
+ * collector: the first to mark keys of that type as being dead, the second to
+ * collect dead links and the third to clean up the dead keys. We have to be
+ * careful as there may already be a cycle in progress.
+ *
+ * The caller must be holding key_types_sem.
+ */
+void key_gc_keytype(struct key_type *ktype)
+{
+ kenter("%s", ktype->name);
+
+ key_gc_dead_keytype = ktype;
+ set_bit(KEY_GC_REAPING_KEYTYPE, &key_gc_flags);
+ smp_mb();
+ set_bit(KEY_GC_REAP_KEYTYPE, &key_gc_flags);
+
+ kdebug("schedule");
+ queue_work(system_nrt_wq, &key_gc_work);
+
+ kdebug("sleep");
+ wait_on_bit(&key_gc_flags, KEY_GC_REAPING_KEYTYPE, key_gc_wait_bit,
+ TASK_UNINTERRUPTIBLE);
+
+ key_gc_dead_keytype = NULL;
+ kleave("");
}
/*
* Garbage collect pointers from a keyring.
*
- * Return true if we altered the keyring.
+ * Not called with any locks held. The keyring's key struct will not be
+ * deallocated under us as only our caller may deallocate it.
*/
-static bool key_gc_keyring(struct key *keyring, time_t limit)
- __releases(key_serial_lock)
+static void key_gc_keyring(struct key *keyring, time_t limit)
{
struct keyring_list *klist;
struct key *key;
@@ -93,130 +155,234 @@ static bool key_gc_keyring(struct key *keyring, time_t limit)
unlock_dont_gc:
rcu_read_unlock();
dont_gc:
- kleave(" = false");
- return false;
+ kleave(" [no gc]");
+ return;
do_gc:
rcu_read_unlock();
- key_gc_cursor = keyring->serial;
- key_get(keyring);
- spin_unlock(&key_serial_lock);
+
keyring_gc(keyring, limit);
- key_put(keyring);
- kleave(" = true");
- return true;
+ kleave(" [gc]");
}
/*
- * Garbage collector for keys. This involves scanning the keyrings for dead,
- * expired and revoked keys that have overstayed their welcome
+ * Garbage collect an unreferenced, detached key
*/
-static void key_garbage_collector(struct work_struct *work)
+static noinline void key_gc_unused_key(struct key *key)
{
- struct rb_node *rb;
- key_serial_t cursor;
- struct key *key, *xkey;
- time_t new_timer = LONG_MAX, limit, now;
-
- now = current_kernel_time().tv_sec;
- kenter("[%x,%ld]", key_gc_cursor, key_gc_new_timer - now);
-
- if (test_and_set_bit(0, &key_gc_executing)) {
- key_schedule_gc(current_kernel_time().tv_sec + 1);
- kleave(" [busy; deferring]");
- return;
+ key_check(key);
+
+ security_key_free(key);
+
+ /* deal with the user's key tracking and quota */
+ if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
+ spin_lock(&key->user->lock);
+ key->user->qnkeys--;
+ key->user->qnbytes -= key->quotalen;
+ spin_unlock(&key->user->lock);
}
- limit = now;
+ atomic_dec(&key->user->nkeys);
+ if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
+ atomic_dec(&key->user->nikeys);
+
+ key_user_put(key->user);
+
+ /* now throw away the key memory */
+ if (key->type->destroy)
+ key->type->destroy(key);
+
+ kfree(key->description);
+
+#ifdef KEY_DEBUGGING
+ key->magic = KEY_DEBUG_MAGIC_X;
+#endif
+ kmem_cache_free(key_jar, key);
+}
+
+/*
+ * Garbage collector for unused keys.
+ *
+ * This is done in process context so that we don't have to disable interrupts
+ * all over the place. key_put() schedules this rather than trying to do the
+ * cleanup itself, which means key_put() doesn't have to sleep.
+ */
+static void key_garbage_collector(struct work_struct *work)
+{
+ static u8 gc_state; /* Internal persistent state */
+#define KEY_GC_REAP_AGAIN 0x01 /* - Need another cycle */
+#define KEY_GC_REAPING_LINKS 0x02 /* - We need to reap links */
+#define KEY_GC_SET_TIMER 0x04 /* - We need to restart the timer */
+#define KEY_GC_REAPING_DEAD_1 0x10 /* - We need to mark dead keys */
+#define KEY_GC_REAPING_DEAD_2 0x20 /* - We need to reap dead key links */
+#define KEY_GC_REAPING_DEAD_3 0x40 /* - We need to reap dead keys */
+#define KEY_GC_FOUND_DEAD_KEY 0x80 /* - We found at least one dead key */
+
+ struct rb_node *cursor;
+ struct key *key;
+ time_t new_timer, limit;
+
+ kenter("[%lx,%x]", key_gc_flags, gc_state);
+
+ limit = current_kernel_time().tv_sec;
if (limit > key_gc_delay)
limit -= key_gc_delay;
else
limit = key_gc_delay;
+ /* Work out what we're going to be doing in this pass */
+ gc_state &= KEY_GC_REAPING_DEAD_1 | KEY_GC_REAPING_DEAD_2;
+ gc_state <<= 1;
+ if (test_and_clear_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags))
+ gc_state |= KEY_GC_REAPING_LINKS | KEY_GC_SET_TIMER;
+
+ if (test_and_clear_bit(KEY_GC_REAP_KEYTYPE, &key_gc_flags))
+ gc_state |= KEY_GC_REAPING_DEAD_1;
+ kdebug("new pass %x", gc_state);
+
+ new_timer = LONG_MAX;
+
+ /* As only this function is permitted to remove things from the key
+ * serial tree, if cursor is non-NULL then it will always point to a
+ * valid node in the tree - even if lock got dropped.
+ */
spin_lock(&key_serial_lock);
+ cursor = rb_first(&key_serial_tree);
- if (unlikely(RB_EMPTY_ROOT(&key_serial_tree))) {
- spin_unlock(&key_serial_lock);
- clear_bit(0, &key_gc_executing);
- return;
- }
+continue_scanning:
+ while (cursor) {
+ key = rb_entry(cursor, struct key, serial_node);
+ cursor = rb_next(cursor);
- cursor = key_gc_cursor;
- if (cursor < 0)
- cursor = 0;
- if (cursor > 0)
- new_timer = key_gc_new_timer;
- else
- key_gc_again = false;
-
- /* find the first key above the cursor */
- key = NULL;
- rb = key_serial_tree.rb_node;
- while (rb) {
- xkey = rb_entry(rb, struct key, serial_node);
- if (cursor < xkey->serial) {
- key = xkey;
- rb = rb->rb_left;
- } else if (cursor > xkey->serial) {
- rb = rb->rb_right;
- } else {
- rb = rb_next(rb);
- if (!rb)
- goto reached_the_end;
- key = rb_entry(rb, struct key, serial_node);
- break;
+ if (atomic_read(&key->usage) == 0)
+ goto found_unreferenced_key;
+
+ if (unlikely(gc_state & KEY_GC_REAPING_DEAD_1)) {
+ if (key->type == key_gc_dead_keytype) {
+ gc_state |= KEY_GC_FOUND_DEAD_KEY;
+ set_bit(KEY_FLAG_DEAD, &key->flags);
+ key->perm = 0;
+ goto skip_dead_key;
+ }
+ }
+
+ if (gc_state & KEY_GC_SET_TIMER) {
+ if (key->expiry > limit && key->expiry < new_timer) {
+ kdebug("will expire %x in %ld",
+ key_serial(key), key->expiry - limit);
+ new_timer = key->expiry;
+ }
}
- }
- if (!key)
- goto reached_the_end;
+ if (unlikely(gc_state & KEY_GC_REAPING_DEAD_2))
+ if (key->type == key_gc_dead_keytype)
+ gc_state |= KEY_GC_FOUND_DEAD_KEY;
- /* trawl through the keys looking for keyrings */
- for (;;) {
- if (key->expiry > limit && key->expiry < new_timer) {
- kdebug("will expire %x in %ld",
- key_serial(key), key->expiry - limit);
- new_timer = key->expiry;
+ if ((gc_state & KEY_GC_REAPING_LINKS) ||
+ unlikely(gc_state & KEY_GC_REAPING_DEAD_2)) {
+ if (key->type == &key_type_keyring)
+ goto found_keyring;
}
- if (key->type == &key_type_keyring &&
- key_gc_keyring(key, limit))
- /* the gc had to release our lock so that the keyring
- * could be modified, so we have to get it again */
- goto gc_released_our_lock;
+ if (unlikely(gc_state & KEY_GC_REAPING_DEAD_3))
+ if (key->type == key_gc_dead_keytype)
+ goto destroy_dead_key;
- rb = rb_next(&key->serial_node);
- if (!rb)
- goto reached_the_end;
- key = rb_entry(rb, struct key, serial_node);
+ skip_dead_key:
+ if (spin_is_contended(&key_serial_lock) || need_resched())
+ goto contended;
}
-gc_released_our_lock:
- kdebug("gc_released_our_lock");
- key_gc_new_timer = new_timer;
- key_gc_again = true;
- clear_bit(0, &key_gc_executing);
- schedule_work(&key_gc_work);
- kleave(" [continue]");
- return;
-
- /* when we reach the end of the run, we set the timer for the next one */
-reached_the_end:
- kdebug("reached_the_end");
+contended:
spin_unlock(&key_serial_lock);
- key_gc_new_timer = new_timer;
- key_gc_cursor = 0;
- clear_bit(0, &key_gc_executing);
-
- if (key_gc_again) {
- /* there may have been a key that expired whilst we were
- * scanning, so if we discarded any links we should do another
- * scan */
- new_timer = now + 1;
- key_schedule_gc(new_timer);
- } else if (new_timer < LONG_MAX) {
+
+maybe_resched:
+ if (cursor) {
+ cond_resched();
+ spin_lock(&key_serial_lock);
+ goto continue_scanning;
+ }
+
+ /* We've completed the pass. Set the timer if we need to and queue a
+ * new cycle if necessary. We keep executing cycles until we find one
+ * where we didn't reap any keys.
+ */
+ kdebug("pass complete");
+
+ if (gc_state & KEY_GC_SET_TIMER && new_timer != (time_t)LONG_MAX) {
new_timer += key_gc_delay;
key_schedule_gc(new_timer);
}
- kleave(" [end]");
+
+ if (unlikely(gc_state & KEY_GC_REAPING_DEAD_2)) {
+ /* Make sure everyone revalidates their keys if we marked a
+ * bunch as being dead and make sure all keyring ex-payloads
+ * are destroyed.
+ */
+ kdebug("dead sync");
+ synchronize_rcu();
+ }
+
+ if (unlikely(gc_state & (KEY_GC_REAPING_DEAD_1 |
+ KEY_GC_REAPING_DEAD_2))) {
+ if (!(gc_state & KEY_GC_FOUND_DEAD_KEY)) {
+ /* No remaining dead keys: short circuit the remaining
+ * keytype reap cycles.
+ */
+ kdebug("dead short");
+ gc_state &= ~(KEY_GC_REAPING_DEAD_1 | KEY_GC_REAPING_DEAD_2);
+ gc_state |= KEY_GC_REAPING_DEAD_3;
+ } else {
+ gc_state |= KEY_GC_REAP_AGAIN;
+ }
+ }
+
+ if (unlikely(gc_state & KEY_GC_REAPING_DEAD_3)) {
+ kdebug("dead wake");
+ smp_mb();
+ clear_bit(KEY_GC_REAPING_KEYTYPE, &key_gc_flags);
+ wake_up_bit(&key_gc_flags, KEY_GC_REAPING_KEYTYPE);
+ }
+
+ if (gc_state & KEY_GC_REAP_AGAIN)
+ queue_work(system_nrt_wq, &key_gc_work);
+ kleave(" [end %x]", gc_state);
+ return;
+
+ /* We found an unreferenced key - once we've removed it from the tree,
+ * we can safely drop the lock.
+ */
+found_unreferenced_key:
+ kdebug("unrefd key %d", key->serial);
+ rb_erase(&key->serial_node, &key_serial_tree);
+ spin_unlock(&key_serial_lock);
+
+ key_gc_unused_key(key);
+ gc_state |= KEY_GC_REAP_AGAIN;
+ goto maybe_resched;
+
+ /* We found a keyring and we need to check the payload for links to
+ * dead or expired keys. We don't flag another reap immediately as we
+ * have to wait for the old payload to be destroyed by RCU before we
+ * can reap the keys to which it refers.
+ */
+found_keyring:
+ spin_unlock(&key_serial_lock);
+ kdebug("scan keyring %d", key->serial);
+ key_gc_keyring(key, limit);
+ goto maybe_resched;
+
+ /* We found a dead key that is still referenced. Reset its type and
+ * destroy its payload with its semaphore held.
+ */
+destroy_dead_key:
+ spin_unlock(&key_serial_lock);
+ kdebug("destroy key %d", key->serial);
+ down_write(&key->sem);
+ key->type = &key_type_dead;
+ if (key_gc_dead_keytype->destroy)
+ key_gc_dead_keytype->destroy(key);
+ memset(&key->payload, KEY_DESTROY, sizeof(key->payload));
+ up_write(&key->sem);
+ goto maybe_resched;
}
diff --git a/security/keys/internal.h b/security/keys/internal.h
index f375152a2500..c7a7caec4830 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -31,6 +31,7 @@
no_printk(KERN_DEBUG FMT"\n", ##__VA_ARGS__)
#endif
+extern struct key_type key_type_dead;
extern struct key_type key_type_user;
/*****************************************************************************/
@@ -75,6 +76,7 @@ extern unsigned key_quota_maxbytes;
#define KEYQUOTA_LINK_BYTES 4 /* a link in a keyring is worth 4 bytes */
+extern struct kmem_cache *key_jar;
extern struct rb_root key_serial_tree;
extern spinlock_t key_serial_lock;
extern struct mutex key_construction_mutex;
@@ -146,9 +148,11 @@ extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
extern long join_session_keyring(const char *name);
+extern struct work_struct key_gc_work;
extern unsigned key_gc_delay;
extern void keyring_gc(struct key *keyring, time_t limit);
extern void key_schedule_gc(time_t expiry_at);
+extern void key_gc_keytype(struct key_type *ktype);
extern int key_task_permission(const key_ref_t key_ref,
const struct cred *cred,
diff --git a/security/keys/key.c b/security/keys/key.c
index f7f9d93f08d9..4414abddcb5b 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -21,7 +21,7 @@
#include <linux/user_namespace.h>
#include "internal.h"
-static struct kmem_cache *key_jar;
+struct kmem_cache *key_jar;
struct rb_root key_serial_tree; /* tree of keys indexed by serial */
DEFINE_SPINLOCK(key_serial_lock);
@@ -36,17 +36,9 @@ unsigned int key_quota_maxbytes = 20000; /* general key space quota */
static LIST_HEAD(key_types_list);
static DECLARE_RWSEM(key_types_sem);
-static void key_cleanup(struct work_struct *work);
-static DECLARE_WORK(key_cleanup_task, key_cleanup);
-
/* We serialise key instantiation and link */
DEFINE_MUTEX(key_construction_mutex);
-/* Any key who's type gets unegistered will be re-typed to this */
-static struct key_type key_type_dead = {
- .name = "dead",
-};
-
#ifdef KEY_DEBUGGING
void __key_check(const struct key *key)
{
@@ -591,71 +583,6 @@ int key_reject_and_link(struct key *key,
}
EXPORT_SYMBOL(key_reject_and_link);
-/*
- * Garbage collect keys in process context so that we don't have to disable
- * interrupts all over the place.
- *
- * key_put() schedules this rather than trying to do the cleanup itself, which
- * means key_put() doesn't have to sleep.
- */
-static void key_cleanup(struct work_struct *work)
-{
- struct rb_node *_n;
- struct key *key;
-
-go_again:
- /* look for a dead key in the tree */
- spin_lock(&key_serial_lock);
-
- for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) {
- key = rb_entry(_n, struct key, serial_node);
-
- if (atomic_read(&key->usage) == 0)
- goto found_dead_key;
- }
-
- spin_unlock(&key_serial_lock);
- return;
-
-found_dead_key:
- /* we found a dead key - once we've removed it from the tree, we can
- * drop the lock */
- rb_erase(&key->serial_node, &key_serial_tree);
- spin_unlock(&key_serial_lock);
-
- key_check(key);
-
- security_key_free(key);
-
- /* deal with the user's key tracking and quota */
- if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
- spin_lock(&key->user->lock);
- key->user->qnkeys--;
- key->user->qnbytes -= key->quotalen;
- spin_unlock(&key->user->lock);
- }
-
- atomic_dec(&key->user->nkeys);
- if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
- atomic_dec(&key->user->nikeys);
-
- key_user_put(key->user);
-
- /* now throw away the key memory */
- if (key->type->destroy)
- key->type->destroy(key);
-
- kfree(key->description);
-
-#ifdef KEY_DEBUGGING
- key->magic = KEY_DEBUG_MAGIC_X;
-#endif
- kmem_cache_free(key_jar, key);
-
- /* there may, of course, be more than one key to destroy */
- goto go_again;
-}
-
/**
* key_put - Discard a reference to a key.
* @key: The key to discard a reference from.
@@ -670,7 +597,7 @@ void key_put(struct key *key)
key_check(key);
if (atomic_dec_and_test(&key->usage))
- schedule_work(&key_cleanup_task);
+ queue_work(system_nrt_wq, &key_gc_work);
}
}
EXPORT_SYMBOL(key_put);
@@ -1048,49 +975,11 @@ EXPORT_SYMBOL(register_key_type);
*/
void unregister_key_type(struct key_type *ktype)
{
- struct rb_node *_n;
- struct key *key;
-
down_write(&key_types_sem);
-
- /* withdraw the key type */
list_del_init(&ktype->link);
-
- /* mark all the keys of this type dead */
- spin_lock(&key_serial_lock);
-
- for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) {
- key = rb_entry(_n, struct key, serial_node);
-
- if (key->type == ktype) {
- key->type = &key_type_dead;
- set_bit(KEY_FLAG_DEAD, &key->flags);
- }
- }
-
- spin_unlock(&key_serial_lock);
-
- /* make sure everyone revalidates their keys */
- synchronize_rcu();
-
- /* we should now be able to destroy the payloads of all the keys of
- * this type with impunity */
- spin_lock(&key_serial_lock);
-
- for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) {
- key = rb_entry(_n, struct key, serial_node);
-
- if (key->type == ktype) {
- if (ktype->destroy)
- ktype->destroy(key);
- memset(&key->payload, KEY_DESTROY, sizeof(key->payload));
- }
- }
-
- spin_unlock(&key_serial_lock);
- up_write(&key_types_sem);
-
- key_schedule_gc(0);
+ downgrade_write(&key_types_sem);
+ key_gc_keytype(ktype);
+ up_read(&key_types_sem);
}
EXPORT_SYMBOL(unregister_key_type);
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 30e242f7bd0e..37a7f3b28852 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -860,8 +860,7 @@ void __key_link(struct key *keyring, struct key *key,
kenter("%d,%d,%p", keyring->serial, key->serial, nklist);
- klist = rcu_dereference_protected(keyring->payload.subscriptions,
- rwsem_is_locked(&keyring->sem));
+ klist = rcu_dereference_locked_keyring(keyring);
atomic_inc(&key->usage);
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index a3063eb3dc23..1068cb1939b3 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -270,7 +270,7 @@ static int install_session_keyring(struct key *keyring)
if (!new)
return -ENOMEM;
- ret = install_session_keyring_to_cred(new, NULL);
+ ret = install_session_keyring_to_cred(new, keyring);
if (ret < 0) {
abort_creds(new);
return ret;
@@ -589,12 +589,22 @@ try_again:
ret = install_user_keyrings();
if (ret < 0)
goto error;
- ret = install_session_keyring(
- cred->user->session_keyring);
+ if (lflags & KEY_LOOKUP_CREATE)
+ ret = join_session_keyring(NULL);
+ else
+ ret = install_session_keyring(
+ cred->user->session_keyring);
if (ret < 0)
goto error;
goto reget_creds;
+ } else if (cred->tgcred->session_keyring ==
+ cred->user->session_keyring &&
+ lflags & KEY_LOOKUP_CREATE) {
+ ret = join_session_keyring(NULL);
+ if (ret < 0)
+ goto error;
+ goto reget_creds;
}
rcu_read_lock();
diff --git a/security/keys/trusted.c b/security/keys/trusted.c
index 0c33e2ea1f3c..0964fc236946 100644
--- a/security/keys/trusted.c
+++ b/security/keys/trusted.c
@@ -779,7 +779,10 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
opt->pcrinfo_len = strlen(args[0].from) / 2;
if (opt->pcrinfo_len > MAX_PCRINFO_SIZE)
return -EINVAL;
- hex2bin(opt->pcrinfo, args[0].from, opt->pcrinfo_len);
+ res = hex2bin(opt->pcrinfo, args[0].from,
+ opt->pcrinfo_len);
+ if (res < 0)
+ return -EINVAL;
break;
case Opt_keyhandle:
res = strict_strtoul(args[0].from, 16, &handle);
@@ -791,12 +794,18 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
case Opt_keyauth:
if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE)
return -EINVAL;
- hex2bin(opt->keyauth, args[0].from, SHA1_DIGEST_SIZE);
+ res = hex2bin(opt->keyauth, args[0].from,
+ SHA1_DIGEST_SIZE);
+ if (res < 0)
+ return -EINVAL;
break;
case Opt_blobauth:
if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE)
return -EINVAL;
- hex2bin(opt->blobauth, args[0].from, SHA1_DIGEST_SIZE);
+ res = hex2bin(opt->blobauth, args[0].from,
+ SHA1_DIGEST_SIZE);
+ if (res < 0)
+ return -EINVAL;
break;
case Opt_migratable:
if (*args[0].from == '0')
@@ -860,7 +869,9 @@ static int datablob_parse(char *datablob, struct trusted_key_payload *p,
p->blob_len = strlen(c) / 2;
if (p->blob_len > MAX_BLOB_SIZE)
return -EINVAL;
- hex2bin(p->blob, c, p->blob_len);
+ ret = hex2bin(p->blob, c, p->blob_len);
+ if (ret < 0)
+ return -EINVAL;
ret = getoptions(datablob, p, o);
if (ret < 0)
return ret;
diff --git a/security/security.c b/security/security.c
index 0e4fccfef12c..0c6cc69c8f86 100644
--- a/security/security.c
+++ b/security/security.c
@@ -16,15 +16,16 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/security.h>
+#include <linux/integrity.h>
#include <linux/ima.h>
+#include <linux/evm.h>
+
+#define MAX_LSM_EVM_XATTR 2
/* Boot-time LSM user choice */
static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
CONFIG_DEFAULT_SECURITY;
-/* things that live in capability.c */
-extern void __init security_fixup_ops(struct security_operations *ops);
-
static struct security_operations *security_ops;
static struct security_operations default_security_ops = {
.name = "default",
@@ -334,20 +335,57 @@ int security_inode_alloc(struct inode *inode)
void security_inode_free(struct inode *inode)
{
- ima_inode_free(inode);
+ integrity_inode_free(inode);
security_ops->inode_free_security(inode);
}
int security_inode_init_security(struct inode *inode, struct inode *dir,
- const struct qstr *qstr, char **name,
- void **value, size_t *len)
+ const struct qstr *qstr,
+ const initxattrs initxattrs, void *fs_data)
{
+ struct xattr new_xattrs[MAX_LSM_EVM_XATTR + 1];
+ struct xattr *lsm_xattr, *evm_xattr, *xattr;
+ int ret;
+
if (unlikely(IS_PRIVATE(inode)))
- return -EOPNOTSUPP;
+ return 0;
+
+ memset(new_xattrs, 0, sizeof new_xattrs);
+ if (!initxattrs)
+ return security_ops->inode_init_security(inode, dir, qstr,
+ NULL, NULL, NULL);
+ lsm_xattr = new_xattrs;
+ ret = security_ops->inode_init_security(inode, dir, qstr,
+ &lsm_xattr->name,
+ &lsm_xattr->value,
+ &lsm_xattr->value_len);
+ if (ret)
+ goto out;
+
+ evm_xattr = lsm_xattr + 1;
+ ret = evm_inode_init_security(inode, lsm_xattr, evm_xattr);
+ if (ret)
+ goto out;
+ ret = initxattrs(inode, new_xattrs, fs_data);
+out:
+ for (xattr = new_xattrs; xattr->name != NULL; xattr++) {
+ kfree(xattr->name);
+ kfree(xattr->value);
+ }
+ return (ret == -EOPNOTSUPP) ? 0 : ret;
+}
+EXPORT_SYMBOL(security_inode_init_security);
+
+int security_old_inode_init_security(struct inode *inode, struct inode *dir,
+ const struct qstr *qstr, char **name,
+ void **value, size_t *len)
+{
+ if (unlikely(IS_PRIVATE(inode)))
+ return 0;
return security_ops->inode_init_security(inode, dir, qstr, name, value,
len);
}
-EXPORT_SYMBOL(security_inode_init_security);
+EXPORT_SYMBOL(security_old_inode_init_security);
#ifdef CONFIG_SECURITY_PATH
int security_path_mknod(struct path *dir, struct dentry *dentry, int mode,
@@ -523,9 +561,14 @@ int security_inode_permission(struct inode *inode, int mask)
int security_inode_setattr(struct dentry *dentry, struct iattr *attr)
{
+ int ret;
+
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
- return security_ops->inode_setattr(dentry, attr);
+ ret = security_ops->inode_setattr(dentry, attr);
+ if (ret)
+ return ret;
+ return evm_inode_setattr(dentry, attr);
}
EXPORT_SYMBOL_GPL(security_inode_setattr);
@@ -539,9 +582,14 @@ int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
int security_inode_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
+ int ret;
+
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
- return security_ops->inode_setxattr(dentry, name, value, size, flags);
+ ret = security_ops->inode_setxattr(dentry, name, value, size, flags);
+ if (ret)
+ return ret;
+ return evm_inode_setxattr(dentry, name, value, size);
}
void security_inode_post_setxattr(struct dentry *dentry, const char *name,
@@ -550,6 +598,7 @@ void security_inode_post_setxattr(struct dentry *dentry, const char *name,
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return;
security_ops->inode_post_setxattr(dentry, name, value, size, flags);
+ evm_inode_post_setxattr(dentry, name, value, size);
}
int security_inode_getxattr(struct dentry *dentry, const char *name)
@@ -568,9 +617,14 @@ int security_inode_listxattr(struct dentry *dentry)
int security_inode_removexattr(struct dentry *dentry, const char *name)
{
+ int ret;
+
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
- return security_ops->inode_removexattr(dentry, name);
+ ret = security_ops->inode_removexattr(dentry, name);
+ if (ret)
+ return ret;
+ return evm_inode_removexattr(dentry, name);
}
int security_inode_need_killpriv(struct dentry *dentry)
@@ -1097,6 +1151,7 @@ void security_sk_clone(const struct sock *sk, struct sock *newsk)
{
security_ops->sk_clone_security(sk, newsk);
}
+EXPORT_SYMBOL(security_sk_clone);
void security_sk_classify_flow(struct sock *sk, struct flowi *fl)
{
diff --git a/security/selinux/exports.c b/security/selinux/exports.c
index 90664385dead..e75dd94e2d2b 100644
--- a/security/selinux/exports.c
+++ b/security/selinux/exports.c
@@ -12,6 +12,7 @@
* as published by the Free Software Foundation.
*/
#include <linux/module.h>
+#include <linux/selinux.h>
#include "security.h"
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 266a2292451d..e545b9f67072 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -89,14 +89,14 @@
#include "xfrm.h"
#include "netlabel.h"
#include "audit.h"
+#include "avc_ss.h"
#define NUM_SEL_MNT_OPTS 5
-extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
extern struct security_operations *security_ops;
/* SECMARK reference count */
-atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
+static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
int selinux_enforcing;
@@ -279,10 +279,6 @@ static void superblock_free_security(struct super_block *sb)
kfree(sbsec);
}
-/* The security server must be initialized before
- any labeling or access decisions can be provided. */
-extern int ss_initialized;
-
/* The file system's label must be initialized prior to use. */
static const char *labeling_behaviors[6] = {
@@ -2097,9 +2093,6 @@ static int selinux_bprm_secureexec(struct linux_binprm *bprm)
return (atsecure || cap_bprm_secureexec(bprm));
}
-extern struct vfsmount *selinuxfs_mount;
-extern struct dentry *selinux_null;
-
/* Derived from fs/exec.c:flush_old_files. */
static inline void flush_unauthorized_files(const struct cred *cred,
struct files_struct *files)
@@ -5803,8 +5796,6 @@ static int selinux_disabled;
int selinux_disable(void)
{
- extern void exit_sel_fs(void);
-
if (ss_initialized) {
/* Not permitted after initial policy load. */
return -EINVAL;
diff --git a/security/selinux/include/avc_ss.h b/security/selinux/include/avc_ss.h
index 4677aa519b04..d5c328452df0 100644
--- a/security/selinux/include/avc_ss.h
+++ b/security/selinux/include/avc_ss.h
@@ -18,5 +18,11 @@ struct security_class_mapping {
extern struct security_class_mapping secclass_map[];
+/*
+ * The security server must be initialized before
+ * any labeling or access decisions can be provided.
+ */
+extern int ss_initialized;
+
#endif /* _SELINUX_AVC_SS_H_ */
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 3ba4feba048a..d871e8ad2103 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -216,6 +216,14 @@ struct selinux_kernel_status {
extern void selinux_status_update_setenforce(int enforcing);
extern void selinux_status_update_policyload(int seqno);
+extern void selinux_complete_init(void);
+extern int selinux_disable(void);
+extern void exit_sel_fs(void);
+extern struct dentry *selinux_null;
+extern struct vfsmount *selinuxfs_mount;
+extern void selnl_notify_setenforce(int val);
+extern void selnl_notify_policyload(u32 seqno);
+extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
#endif /* _SELINUX_SECURITY_H_ */
diff --git a/security/selinux/netlink.c b/security/selinux/netlink.c
index 36ac257cec9a..ce3f481558d8 100644
--- a/security/selinux/netlink.c
+++ b/security/selinux/netlink.c
@@ -19,6 +19,8 @@
#include <linux/selinux_netlink.h>
#include <net/net_namespace.h>
+#include "security.h"
+
static struct sock *selnl;
static int selnl_msglen(int msgtype)
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c
index 8b02b2137da2..0920ea3bf599 100644
--- a/security/selinux/nlmsgtab.c
+++ b/security/selinux/nlmsgtab.c
@@ -21,6 +21,7 @@
#include "flask.h"
#include "av_permissions.h"
+#include "security.h"
struct nlmsg_perm {
u16 nlmsg_type;
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 55d92cbb177a..f46658722c78 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -75,8 +75,6 @@ static char policy_opened;
/* global data for policy capabilities */
static struct dentry *policycap_dir;
-extern void selnl_notify_setenforce(int val);
-
/* Check whether a task is allowed to use a security operation. */
static int task_has_security(struct task_struct *tsk,
u32 perms)
@@ -278,7 +276,6 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf,
char *page = NULL;
ssize_t length;
int new_value;
- extern int selinux_disable(void);
length = -ENOMEM;
if (count >= PAGE_SIZE)
@@ -478,7 +475,7 @@ static struct vm_operations_struct sel_mmap_policy_ops = {
.page_mkwrite = sel_mmap_policy_fault,
};
-int sel_mmap_policy(struct file *filp, struct vm_area_struct *vma)
+static int sel_mmap_policy(struct file *filp, struct vm_area_struct *vma)
{
if (vma->vm_flags & VM_SHARED) {
/* do not allow mprotect to make mapping writable */
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index a53373207fb4..2ec904177fe0 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -555,7 +555,7 @@ static int cond_write_av_list(struct policydb *p,
return 0;
}
-int cond_write_node(struct policydb *p, struct cond_node *node,
+static int cond_write_node(struct policydb *p, struct cond_node *node,
struct policy_file *fp)
{
struct cond_expr *cur_expr;
diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h
index 3f209c635295..4d1f87466508 100644
--- a/security/selinux/ss/conditional.h
+++ b/security/selinux/ss/conditional.h
@@ -13,6 +13,7 @@
#include "avtab.h"
#include "symtab.h"
#include "policydb.h"
+#include "../include/conditional.h"
#define COND_EXPR_MAXDEPTH 10
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 2381d0ded228..a7f61d52f05c 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -1743,8 +1743,6 @@ static int policydb_bounds_sanity_check(struct policydb *p)
return 0;
}
-extern int ss_initialized;
-
u16 string_to_security_class(struct policydb *p, const char *name)
{
struct class_datum *cladatum;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index f6917bc0aa05..185f849a26f6 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -70,8 +70,6 @@
#include "ebitmap.h"
#include "audit.h"
-extern void selnl_notify_policyload(u32 seqno);
-
int selinux_policycap_netpeer;
int selinux_policycap_openperm;
@@ -1790,7 +1788,6 @@ static void security_load_policycaps(void)
POLICYDB_CAPABILITY_OPENPERM);
}
-extern void selinux_complete_init(void);
static int security_preserve_bools(struct policydb *p);
/**
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 2b6c6a516123..2ad00657b801 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -41,9 +41,9 @@ struct superblock_smack {
};
struct socket_smack {
- char *smk_out; /* outbound label */
- char *smk_in; /* inbound label */
- char smk_packet[SMK_LABELLEN]; /* TCP peer label */
+ char *smk_out; /* outbound label */
+ char *smk_in; /* inbound label */
+ char *smk_packet; /* TCP peer label */
};
/*
@@ -116,13 +116,19 @@ struct smk_netlbladdr {
* If there is a cipso value associated with the label it
* gets stored here, too. This will most likely be rare as
* the cipso direct mapping in used internally.
+ *
+ * Keep the access rules for this subject label here so that
+ * the entire set of rules does not need to be examined every
+ * time.
*/
struct smack_known {
struct list_head list;
char smk_known[SMK_LABELLEN];
u32 smk_secid;
struct smack_cipso *smk_cipso;
- spinlock_t smk_cipsolock; /* for changing cipso map */
+ spinlock_t smk_cipsolock; /* for changing cipso map */
+ struct list_head smk_rules; /* access rules */
+ struct mutex smk_rules_lock; /* lock for the rules */
};
/*
@@ -150,7 +156,6 @@ struct smack_known {
/*
* smackfs magic number
- * smackfs macic number
*/
#define SMACK_MAGIC 0x43415d53 /* "SMAC" */
@@ -176,9 +181,9 @@ struct smack_known {
#define MAY_NOT 0
/*
- * Number of access types used by Smack (rwxa)
+ * Number of access types used by Smack (rwxat)
*/
-#define SMK_NUM_ACCESS_TYPE 4
+#define SMK_NUM_ACCESS_TYPE 5
/*
* Smack audit data; is empty if CONFIG_AUDIT not set
@@ -201,10 +206,12 @@ int smk_access_entry(char *, char *, struct list_head *);
int smk_access(char *, char *, int, struct smk_audit_info *);
int smk_curacc(char *, u32, struct smk_audit_info *);
int smack_to_cipso(const char *, struct smack_cipso *);
-void smack_from_cipso(u32, char *, char *);
+char *smack_from_cipso(u32, char *);
char *smack_from_secid(const u32);
+void smk_parse_smack(const char *string, int len, char *smack);
char *smk_import(const char *, int);
struct smack_known *smk_import_entry(const char *, int);
+struct smack_known *smk_find_entry(const char *);
u32 smack_to_secid(const char *);
/*
@@ -223,7 +230,6 @@ extern struct smack_known smack_known_star;
extern struct smack_known smack_known_web;
extern struct list_head smack_known_list;
-extern struct list_head smack_rule_list;
extern struct list_head smk_netlbladdr_list;
extern struct security_operations smack_ops;
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index 9637e107f7ea..cc7cb6edba08 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -77,14 +77,19 @@ int log_policy = SMACK_AUDIT_DENIED;
* entry is found returns -ENOENT.
*
* NOTE:
- * Even though Smack labels are usually shared on smack_list
- * labels that come in off the network can't be imported
- * and added to the list for locking reasons.
*
- * Therefore, it is necessary to check the contents of the labels,
- * not just the pointer values. Of course, in most cases the labels
- * will be on the list, so checking the pointers may be a worthwhile
- * optimization.
+ * Earlier versions of this function allowed for labels that
+ * were not on the label list. This was done to allow for
+ * labels to come over the network that had never been seen
+ * before on this host. Unless the receiving socket has the
+ * star label this will always result in a failure check. The
+ * star labeled socket case is now handled in the networking
+ * hooks so there is no case where the label is not on the
+ * label list. Checking to see if the address of two labels
+ * is the same is now a reliable test.
+ *
+ * Do the object check first because that is more
+ * likely to differ.
*/
int smk_access_entry(char *subject_label, char *object_label,
struct list_head *rule_list)
@@ -93,13 +98,10 @@ int smk_access_entry(char *subject_label, char *object_label,
struct smack_rule *srp;
list_for_each_entry_rcu(srp, rule_list, list) {
- if (srp->smk_subject == subject_label ||
- strcmp(srp->smk_subject, subject_label) == 0) {
- if (srp->smk_object == object_label ||
- strcmp(srp->smk_object, object_label) == 0) {
- may = srp->smk_access;
- break;
- }
+ if (srp->smk_object == object_label &&
+ srp->smk_subject == subject_label) {
+ may = srp->smk_access;
+ break;
}
}
@@ -117,18 +119,12 @@ int smk_access_entry(char *subject_label, char *object_label,
* access rule list and returns 0 if the access is permitted,
* non zero otherwise.
*
- * Even though Smack labels are usually shared on smack_list
- * labels that come in off the network can't be imported
- * and added to the list for locking reasons.
- *
- * Therefore, it is necessary to check the contents of the labels,
- * not just the pointer values. Of course, in most cases the labels
- * will be on the list, so checking the pointers may be a worthwhile
- * optimization.
+ * Smack labels are shared on smack_list
*/
int smk_access(char *subject_label, char *object_label, int request,
struct smk_audit_info *a)
{
+ struct smack_known *skp;
int may = MAY_NOT;
int rc = 0;
@@ -137,8 +133,7 @@ int smk_access(char *subject_label, char *object_label, int request,
*
* A star subject can't access any object.
*/
- if (subject_label == smack_known_star.smk_known ||
- strcmp(subject_label, smack_known_star.smk_known) == 0) {
+ if (subject_label == smack_known_star.smk_known) {
rc = -EACCES;
goto out_audit;
}
@@ -148,33 +143,27 @@ int smk_access(char *subject_label, char *object_label, int request,
* An internet subject can access any object.
*/
if (object_label == smack_known_web.smk_known ||
- subject_label == smack_known_web.smk_known ||
- strcmp(object_label, smack_known_web.smk_known) == 0 ||
- strcmp(subject_label, smack_known_web.smk_known) == 0)
+ subject_label == smack_known_web.smk_known)
goto out_audit;
/*
* A star object can be accessed by any subject.
*/
- if (object_label == smack_known_star.smk_known ||
- strcmp(object_label, smack_known_star.smk_known) == 0)
+ if (object_label == smack_known_star.smk_known)
goto out_audit;
/*
* An object can be accessed in any way by a subject
* with the same label.
*/
- if (subject_label == object_label ||
- strcmp(subject_label, object_label) == 0)
+ if (subject_label == object_label)
goto out_audit;
/*
* A hat subject can read any object.
* A floor object can be read by any subject.
*/
if ((request & MAY_ANYREAD) == request) {
- if (object_label == smack_known_floor.smk_known ||
- strcmp(object_label, smack_known_floor.smk_known) == 0)
+ if (object_label == smack_known_floor.smk_known)
goto out_audit;
- if (subject_label == smack_known_hat.smk_known ||
- strcmp(subject_label, smack_known_hat.smk_known) == 0)
+ if (subject_label == smack_known_hat.smk_known)
goto out_audit;
}
/*
@@ -184,8 +173,9 @@ int smk_access(char *subject_label, char *object_label, int request,
* good. A negative response from smk_access_entry()
* indicates there is no entry for this pair.
*/
+ skp = smk_find_entry(subject_label);
rcu_read_lock();
- may = smk_access_entry(subject_label, object_label, &smack_rule_list);
+ may = smk_access_entry(subject_label, object_label, &skp->smk_rules);
rcu_read_unlock();
if (may > 0 && (request & may) == request)
@@ -344,17 +334,32 @@ void smack_log(char *subject_label, char *object_label, int request,
static DEFINE_MUTEX(smack_known_lock);
/**
- * smk_import_entry - import a label, return the list entry
+ * smk_find_entry - find a label on the list, return the list entry
* @string: a text string that might be a Smack label
- * @len: the maximum size, or zero if it is NULL terminated.
*
* Returns a pointer to the entry in the label list that
- * matches the passed string, adding it if necessary.
+ * matches the passed string.
*/
-struct smack_known *smk_import_entry(const char *string, int len)
+struct smack_known *smk_find_entry(const char *string)
{
struct smack_known *skp;
- char smack[SMK_LABELLEN];
+
+ list_for_each_entry_rcu(skp, &smack_known_list, list) {
+ if (strncmp(skp->smk_known, string, SMK_MAXLEN) == 0)
+ return skp;
+ }
+
+ return NULL;
+}
+
+/**
+ * smk_parse_smack - parse smack label from a text string
+ * @string: a text string that might contain a Smack label
+ * @len: the maximum size, or zero if it is NULL terminated.
+ * @smack: parsed smack label, or NULL if parse error
+ */
+void smk_parse_smack(const char *string, int len, char *smack)
+{
int found;
int i;
@@ -372,27 +377,38 @@ struct smack_known *smk_import_entry(const char *string, int len)
} else
smack[i] = string[i];
}
+}
+
+/**
+ * smk_import_entry - import a label, return the list entry
+ * @string: a text string that might be a Smack label
+ * @len: the maximum size, or zero if it is NULL terminated.
+ *
+ * Returns a pointer to the entry in the label list that
+ * matches the passed string, adding it if necessary.
+ */
+struct smack_known *smk_import_entry(const char *string, int len)
+{
+ struct smack_known *skp;
+ char smack[SMK_LABELLEN];
+ smk_parse_smack(string, len, smack);
if (smack[0] == '\0')
return NULL;
mutex_lock(&smack_known_lock);
- found = 0;
- list_for_each_entry_rcu(skp, &smack_known_list, list) {
- if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) {
- found = 1;
- break;
- }
- }
+ skp = smk_find_entry(smack);
- if (found == 0) {
+ if (skp == NULL) {
skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL);
if (skp != NULL) {
strncpy(skp->smk_known, smack, SMK_MAXLEN);
skp->smk_secid = smack_next_secid++;
skp->smk_cipso = NULL;
+ INIT_LIST_HEAD(&skp->smk_rules);
spin_lock_init(&skp->smk_cipsolock);
+ mutex_init(&skp->smk_rules_lock);
/*
* Make sure that the entry is actually
* filled before putting it on the list.
@@ -480,19 +496,12 @@ u32 smack_to_secid(const char *smack)
* smack_from_cipso - find the Smack label associated with a CIPSO option
* @level: Bell & LaPadula level from the network
* @cp: Bell & LaPadula categories from the network
- * @result: where to put the Smack value
*
* This is a simple lookup in the label table.
*
- * This is an odd duck as far as smack handling goes in that
- * it sends back a copy of the smack label rather than a pointer
- * to the master list. This is done because it is possible for
- * a foreign host to send a smack label that is new to this
- * machine and hence not on the list. That would not be an
- * issue except that adding an entry to the master list can't
- * be done at that point.
+ * Return the matching label from the label list or NULL.
*/
-void smack_from_cipso(u32 level, char *cp, char *result)
+char *smack_from_cipso(u32 level, char *cp)
{
struct smack_known *kp;
char *final = NULL;
@@ -509,12 +518,13 @@ void smack_from_cipso(u32 level, char *cp, char *result)
final = kp->smk_known;
spin_unlock_bh(&kp->smk_cipsolock);
+
+ if (final != NULL)
+ break;
}
rcu_read_unlock();
- if (final == NULL)
- final = smack_known_huh.smk_known;
- strncpy(result, final, SMK_MAXLEN);
- return;
+
+ return final;
}
/**
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index b9c5e149903b..7db62b48eb42 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -5,12 +5,13 @@
*
* Authors:
* Casey Schaufler <casey@schaufler-ca.com>
- * Jarkko Sakkinen <ext-jarkko.2.sakkinen@nokia.com>
+ * Jarkko Sakkinen <jarkko.sakkinen@intel.com>
*
* Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
* Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
* Paul Moore <paul@paul-moore.com>
* Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2011 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,
@@ -34,6 +35,7 @@
#include <linux/audit.h>
#include <linux/magic.h>
#include <linux/dcache.h>
+#include <linux/personality.h>
#include "smack.h"
#define task_security(task) (task_cred_xxx((task), security))
@@ -441,11 +443,17 @@ static int smack_sb_umount(struct vfsmount *mnt, int flags)
* BPRM hooks
*/
+/**
+ * smack_bprm_set_creds - set creds for exec
+ * @bprm: the exec information
+ *
+ * Returns 0 if it gets a blob, -ENOMEM otherwise
+ */
static int smack_bprm_set_creds(struct linux_binprm *bprm)
{
- struct task_smack *tsp = bprm->cred->security;
+ struct inode *inode = bprm->file->f_path.dentry->d_inode;
+ struct task_smack *bsp = bprm->cred->security;
struct inode_smack *isp;
- struct dentry *dp;
int rc;
rc = cap_bprm_set_creds(bprm);
@@ -455,20 +463,48 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm)
if (bprm->cred_prepared)
return 0;
- if (bprm->file == NULL || bprm->file->f_dentry == NULL)
+ isp = inode->i_security;
+ if (isp->smk_task == NULL || isp->smk_task == bsp->smk_task)
return 0;
- dp = bprm->file->f_dentry;
+ if (bprm->unsafe)
+ return -EPERM;
- if (dp->d_inode == NULL)
- return 0;
+ bsp->smk_task = isp->smk_task;
+ bprm->per_clear |= PER_CLEAR_ON_SETID;
- isp = dp->d_inode->i_security;
+ return 0;
+}
- if (isp->smk_task != NULL)
- tsp->smk_task = isp->smk_task;
+/**
+ * smack_bprm_committing_creds - Prepare to install the new credentials
+ * from bprm.
+ *
+ * @bprm: binprm for exec
+ */
+static void smack_bprm_committing_creds(struct linux_binprm *bprm)
+{
+ struct task_smack *bsp = bprm->cred->security;
- return 0;
+ if (bsp->smk_task != bsp->smk_forked)
+ current->pdeath_signal = 0;
+}
+
+/**
+ * smack_bprm_secureexec - Return the decision to use secureexec.
+ * @bprm: binprm for exec
+ *
+ * Returns 0 on success.
+ */
+static int smack_bprm_secureexec(struct linux_binprm *bprm)
+{
+ struct task_smack *tsp = current_security();
+ int ret = cap_bprm_secureexec(bprm);
+
+ if (!ret && (tsp->smk_task != tsp->smk_forked))
+ ret = 1;
+
+ return ret;
}
/*
@@ -516,6 +552,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr, char **name,
void **value, size_t *len)
{
+ struct smack_known *skp;
+ char *csp = smk_of_current();
char *isp = smk_of_inode(inode);
char *dsp = smk_of_inode(dir);
int may;
@@ -527,8 +565,9 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
}
if (value) {
+ skp = smk_find_entry(csp);
rcu_read_lock();
- may = smk_access_entry(smk_of_current(), dsp, &smack_rule_list);
+ may = smk_access_entry(csp, dsp, &skp->smk_rules);
rcu_read_unlock();
/*
@@ -841,7 +880,7 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
return;
}
-/*
+/**
* smack_inode_getxattr - Smack check on getxattr
* @dentry: the object
* @name: unused
@@ -858,7 +897,7 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name)
return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
}
-/*
+/**
* smack_inode_removexattr - Smack check on removexattr
* @dentry: the object
* @name: name of the attribute
@@ -1088,36 +1127,31 @@ static int smack_file_lock(struct file *file, unsigned int cmd)
* @cmd: what action to check
* @arg: unused
*
+ * Generally these operations are harmless.
+ * File locking operations present an obvious mechanism
+ * for passing information, so they require write access.
+ *
* Returns 0 if current has access, error code otherwise
*/
static int smack_file_fcntl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct smk_audit_info ad;
- int rc;
+ int rc = 0;
- smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
- smk_ad_setfield_u_fs_path(&ad, file->f_path);
switch (cmd) {
- case F_DUPFD:
- case F_GETFD:
- case F_GETFL:
case F_GETLK:
- case F_GETOWN:
- case F_GETSIG:
- rc = smk_curacc(file->f_security, MAY_READ, &ad);
- break;
- case F_SETFD:
- case F_SETFL:
case F_SETLK:
case F_SETLKW:
case F_SETOWN:
case F_SETSIG:
+ smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
+ smk_ad_setfield_u_fs_path(&ad, file->f_path);
rc = smk_curacc(file->f_security, MAY_WRITE, &ad);
break;
default:
- rc = smk_curacc(file->f_security, MAY_READWRITE, &ad);
+ break;
}
return rc;
@@ -1138,6 +1172,7 @@ static int smack_file_mmap(struct file *file,
unsigned long flags, unsigned long addr,
unsigned long addr_only)
{
+ struct smack_known *skp;
struct smack_rule *srp;
struct task_smack *tsp;
char *sp;
@@ -1170,6 +1205,7 @@ static int smack_file_mmap(struct file *file,
tsp = current_security();
sp = smk_of_current();
+ skp = smk_find_entry(sp);
rc = 0;
rcu_read_lock();
@@ -1177,15 +1213,8 @@ static int smack_file_mmap(struct file *file,
* For each Smack rule associated with the subject
* label verify that the SMACK64MMAP also has access
* to that rule's object label.
- *
- * Because neither of the labels comes
- * from the networking code it is sufficient
- * to compare pointers.
*/
- list_for_each_entry_rcu(srp, &smack_rule_list, list) {
- if (srp->smk_subject != sp)
- continue;
-
+ list_for_each_entry_rcu(srp, &skp->smk_rules, list) {
osmack = srp->smk_object;
/*
* Matching labels always allows access.
@@ -1214,7 +1243,8 @@ static int smack_file_mmap(struct file *file,
* If there isn't one a SMACK64MMAP subject
* can't have as much access as current.
*/
- mmay = smk_access_entry(msmack, osmack, &smack_rule_list);
+ skp = smk_find_entry(msmack);
+ mmay = smk_access_entry(msmack, osmack, &skp->smk_rules);
if (mmay == -ENOENT) {
rc = -EACCES;
break;
@@ -1315,6 +1345,24 @@ static int smack_file_receive(struct file *file)
return smk_curacc(file->f_security, may, &ad);
}
+/**
+ * smack_dentry_open - Smack dentry open processing
+ * @file: the object
+ * @cred: unused
+ *
+ * Set the security blob in the file structure.
+ *
+ * Returns 0
+ */
+static int smack_dentry_open(struct file *file, const struct cred *cred)
+{
+ struct inode_smack *isp = file->f_path.dentry->d_inode->i_security;
+
+ file->f_security = isp->smk_inode;
+
+ return 0;
+}
+
/*
* Task hooks
*/
@@ -1455,15 +1503,17 @@ static int smack_kernel_create_files_as(struct cred *new,
/**
* smk_curacc_on_task - helper to log task related access
* @p: the task object
- * @access : the access requested
+ * @access: the access requested
+ * @caller: name of the calling function for audit
*
* Return 0 if access is permitted
*/
-static int smk_curacc_on_task(struct task_struct *p, int access)
+static int smk_curacc_on_task(struct task_struct *p, int access,
+ const char *caller)
{
struct smk_audit_info ad;
- smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
+ smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK);
smk_ad_setfield_u_tsk(&ad, p);
return smk_curacc(smk_of_task(task_security(p)), access, &ad);
}
@@ -1477,7 +1527,7 @@ static int smk_curacc_on_task(struct task_struct *p, int access)
*/
static int smack_task_setpgid(struct task_struct *p, pid_t pgid)
{
- return smk_curacc_on_task(p, MAY_WRITE);
+ return smk_curacc_on_task(p, MAY_WRITE, __func__);
}
/**
@@ -1488,7 +1538,7 @@ static int smack_task_setpgid(struct task_struct *p, pid_t pgid)
*/
static int smack_task_getpgid(struct task_struct *p)
{
- return smk_curacc_on_task(p, MAY_READ);
+ return smk_curacc_on_task(p, MAY_READ, __func__);
}
/**
@@ -1499,7 +1549,7 @@ static int smack_task_getpgid(struct task_struct *p)
*/
static int smack_task_getsid(struct task_struct *p)
{
- return smk_curacc_on_task(p, MAY_READ);
+ return smk_curacc_on_task(p, MAY_READ, __func__);
}
/**
@@ -1527,7 +1577,7 @@ static int smack_task_setnice(struct task_struct *p, int nice)
rc = cap_task_setnice(p, nice);
if (rc == 0)
- rc = smk_curacc_on_task(p, MAY_WRITE);
+ rc = smk_curacc_on_task(p, MAY_WRITE, __func__);
return rc;
}
@@ -1544,7 +1594,7 @@ static int smack_task_setioprio(struct task_struct *p, int ioprio)
rc = cap_task_setioprio(p, ioprio);
if (rc == 0)
- rc = smk_curacc_on_task(p, MAY_WRITE);
+ rc = smk_curacc_on_task(p, MAY_WRITE, __func__);
return rc;
}
@@ -1556,7 +1606,7 @@ static int smack_task_setioprio(struct task_struct *p, int ioprio)
*/
static int smack_task_getioprio(struct task_struct *p)
{
- return smk_curacc_on_task(p, MAY_READ);
+ return smk_curacc_on_task(p, MAY_READ, __func__);
}
/**
@@ -1573,7 +1623,7 @@ static int smack_task_setscheduler(struct task_struct *p)
rc = cap_task_setscheduler(p);
if (rc == 0)
- rc = smk_curacc_on_task(p, MAY_WRITE);
+ rc = smk_curacc_on_task(p, MAY_WRITE, __func__);
return rc;
}
@@ -1585,7 +1635,7 @@ static int smack_task_setscheduler(struct task_struct *p)
*/
static int smack_task_getscheduler(struct task_struct *p)
{
- return smk_curacc_on_task(p, MAY_READ);
+ return smk_curacc_on_task(p, MAY_READ, __func__);
}
/**
@@ -1596,7 +1646,7 @@ static int smack_task_getscheduler(struct task_struct *p)
*/
static int smack_task_movememory(struct task_struct *p)
{
- return smk_curacc_on_task(p, MAY_WRITE);
+ return smk_curacc_on_task(p, MAY_WRITE, __func__);
}
/**
@@ -1711,7 +1761,7 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
ssp->smk_in = csp;
ssp->smk_out = csp;
- ssp->smk_packet[0] = '\0';
+ ssp->smk_packet = NULL;
sk->sk_security = ssp;
@@ -2753,6 +2803,7 @@ static int smack_unix_stream_connect(struct sock *sock,
{
struct socket_smack *ssp = sock->sk_security;
struct socket_smack *osp = other->sk_security;
+ struct socket_smack *nsp = newsk->sk_security;
struct smk_audit_info ad;
int rc = 0;
@@ -2762,6 +2813,14 @@ static int smack_unix_stream_connect(struct sock *sock,
if (!capable(CAP_MAC_OVERRIDE))
rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad);
+ /*
+ * Cross reference the peer labels for SO_PEERSEC.
+ */
+ if (rc == 0) {
+ nsp->smk_packet = ssp->smk_out;
+ ssp->smk_packet = osp->smk_out;
+ }
+
return rc;
}
@@ -2813,16 +2872,17 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
return smack_netlabel_send(sock->sk, sip);
}
-
/**
* smack_from_secattr - Convert a netlabel attr.mls.lvl/attr.mls.cat pair to smack
* @sap: netlabel secattr
- * @sip: where to put the result
+ * @ssp: socket security information
*
- * Copies a smack label into sip
+ * Returns a pointer to a Smack label found on the label list.
*/
-static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip)
+static char *smack_from_secattr(struct netlbl_lsm_secattr *sap,
+ struct socket_smack *ssp)
{
+ struct smack_known *skp;
char smack[SMK_LABELLEN];
char *sp;
int pcat;
@@ -2852,15 +2912,43 @@ static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip)
* we are already done. WeeHee.
*/
if (sap->attr.mls.lvl == smack_cipso_direct) {
- memcpy(sip, smack, SMK_MAXLEN);
- return;
+ /*
+ * The label sent is usually on the label list.
+ *
+ * If it is not we may still want to allow the
+ * delivery.
+ *
+ * If the recipient is accepting all packets
+ * because it is using the star ("*") label
+ * for SMACK64IPIN provide the web ("@") label
+ * so that a directed response will succeed.
+ * This is not very correct from a MAC point
+ * of view, but gets around the problem that
+ * locking prevents adding the newly discovered
+ * label to the list.
+ * The case where the recipient is not using
+ * the star label should obviously fail.
+ * The easy way to do this is to provide the
+ * star label as the subject label.
+ */
+ skp = smk_find_entry(smack);
+ if (skp != NULL)
+ return skp->smk_known;
+ if (ssp != NULL &&
+ ssp->smk_in == smack_known_star.smk_known)
+ return smack_known_web.smk_known;
+ return smack_known_star.smk_known;
}
/*
* Look it up in the supplied table if it is not
* a direct mapping.
*/
- smack_from_cipso(sap->attr.mls.lvl, smack, sip);
- return;
+ sp = smack_from_cipso(sap->attr.mls.lvl, smack);
+ if (sp != NULL)
+ return sp;
+ if (ssp != NULL && ssp->smk_in == smack_known_star.smk_known)
+ return smack_known_web.smk_known;
+ return smack_known_star.smk_known;
}
if ((sap->flags & NETLBL_SECATTR_SECID) != 0) {
/*
@@ -2875,16 +2963,14 @@ static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip)
* secid is from a fallback.
*/
BUG_ON(sp == NULL);
- strncpy(sip, sp, SMK_MAXLEN);
- return;
+ return sp;
}
/*
* Without guidance regarding the smack value
* for the packet fall back on the network
* ambient value.
*/
- strncpy(sip, smack_net_ambient, SMK_MAXLEN);
- return;
+ return smack_net_ambient;
}
/**
@@ -2898,7 +2984,6 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
struct netlbl_lsm_secattr secattr;
struct socket_smack *ssp = sk->sk_security;
- char smack[SMK_LABELLEN];
char *csp;
int rc;
struct smk_audit_info ad;
@@ -2911,10 +2996,9 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
netlbl_secattr_init(&secattr);
rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr);
- if (rc == 0) {
- smack_from_secattr(&secattr, smack);
- csp = smack;
- } else
+ if (rc == 0)
+ csp = smack_from_secattr(&secattr, ssp);
+ else
csp = smack_net_ambient;
netlbl_secattr_destroy(&secattr);
@@ -2951,15 +3035,19 @@ static int smack_socket_getpeersec_stream(struct socket *sock,
int __user *optlen, unsigned len)
{
struct socket_smack *ssp;
- int slen;
+ char *rcp = "";
+ int slen = 1;
int rc = 0;
ssp = sock->sk->sk_security;
- slen = strlen(ssp->smk_packet) + 1;
+ if (ssp->smk_packet != NULL) {
+ rcp = ssp->smk_packet;
+ slen = strlen(rcp) + 1;
+ }
if (slen > len)
rc = -ERANGE;
- else if (copy_to_user(optval, ssp->smk_packet, slen) != 0)
+ else if (copy_to_user(optval, rcp, slen) != 0)
rc = -EFAULT;
if (put_user(slen, optlen) != 0)
@@ -2982,8 +3070,8 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
{
struct netlbl_lsm_secattr secattr;
- struct socket_smack *sp;
- char smack[SMK_LABELLEN];
+ struct socket_smack *ssp = NULL;
+ char *sp;
int family = PF_UNSPEC;
u32 s = 0; /* 0 is the invalid secid */
int rc;
@@ -2998,17 +3086,19 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
family = sock->sk->sk_family;
if (family == PF_UNIX) {
- sp = sock->sk->sk_security;
- s = smack_to_secid(sp->smk_out);
+ ssp = sock->sk->sk_security;
+ s = smack_to_secid(ssp->smk_out);
} else if (family == PF_INET || family == PF_INET6) {
/*
* Translate what netlabel gave us.
*/
+ if (sock != NULL && sock->sk != NULL)
+ ssp = sock->sk->sk_security;
netlbl_secattr_init(&secattr);
rc = netlbl_skbuff_getattr(skb, family, &secattr);
if (rc == 0) {
- smack_from_secattr(&secattr, smack);
- s = smack_to_secid(smack);
+ sp = smack_from_secattr(&secattr, ssp);
+ s = smack_to_secid(sp);
}
netlbl_secattr_destroy(&secattr);
}
@@ -3056,7 +3146,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
struct netlbl_lsm_secattr secattr;
struct sockaddr_in addr;
struct iphdr *hdr;
- char smack[SMK_LABELLEN];
+ char *sp;
int rc;
struct smk_audit_info ad;
@@ -3067,9 +3157,9 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
netlbl_secattr_init(&secattr);
rc = netlbl_skbuff_getattr(skb, family, &secattr);
if (rc == 0)
- smack_from_secattr(&secattr, smack);
+ sp = smack_from_secattr(&secattr, ssp);
else
- strncpy(smack, smack_known_huh.smk_known, SMK_MAXLEN);
+ sp = smack_known_huh.smk_known;
netlbl_secattr_destroy(&secattr);
#ifdef CONFIG_AUDIT
@@ -3082,7 +3172,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
* Receiving a packet requires that the other end be able to write
* here. Read access is not required.
*/
- rc = smk_access(smack, ssp->smk_in, MAY_WRITE, &ad);
+ rc = smk_access(sp, ssp->smk_in, MAY_WRITE, &ad);
if (rc != 0)
return rc;
@@ -3090,7 +3180,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
* Save the peer's label in the request_sock so we can later setup
* smk_packet in the child socket so that SO_PEERCRED can report it.
*/
- req->peer_secid = smack_to_secid(smack);
+ req->peer_secid = smack_to_secid(sp);
/*
* We need to decide if we want to label the incoming connection here
@@ -3103,7 +3193,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
if (smack_host_label(&addr) == NULL) {
rcu_read_unlock();
netlbl_secattr_init(&secattr);
- smack_to_secattr(smack, &secattr);
+ smack_to_secattr(sp, &secattr);
rc = netlbl_req_setattr(req, &secattr);
netlbl_secattr_destroy(&secattr);
} else {
@@ -3125,13 +3215,11 @@ static void smack_inet_csk_clone(struct sock *sk,
const struct request_sock *req)
{
struct socket_smack *ssp = sk->sk_security;
- char *smack;
- if (req->peer_secid != 0) {
- smack = smack_from_secid(req->peer_secid);
- strncpy(ssp->smk_packet, smack, SMK_MAXLEN);
- } else
- ssp->smk_packet[0] = '\0';
+ if (req->peer_secid != 0)
+ ssp->smk_packet = smack_from_secid(req->peer_secid);
+ else
+ ssp->smk_packet = NULL;
}
/*
@@ -3409,6 +3497,8 @@ struct security_operations smack_ops = {
.sb_umount = smack_sb_umount,
.bprm_set_creds = smack_bprm_set_creds,
+ .bprm_committing_creds = smack_bprm_committing_creds,
+ .bprm_secureexec = smack_bprm_secureexec,
.inode_alloc_security = smack_inode_alloc_security,
.inode_free_security = smack_inode_free_security,
@@ -3440,6 +3530,8 @@ struct security_operations smack_ops = {
.file_send_sigiotask = smack_file_send_sigiotask,
.file_receive = smack_file_receive,
+ .dentry_open = smack_dentry_open,
+
.cred_alloc_blank = smack_cred_alloc_blank,
.cred_free = smack_cred_free,
.cred_prepare = smack_cred_prepare,
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index f93460156dce..6aceef518a41 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -44,6 +44,7 @@ enum smk_inos {
SMK_ONLYCAP = 9, /* the only "capable" label */
SMK_LOGGING = 10, /* logging */
SMK_LOAD_SELF = 11, /* task specific rules */
+ SMK_ACCESSES = 12, /* access policy */
};
/*
@@ -85,6 +86,16 @@ char *smack_onlycap;
*/
LIST_HEAD(smk_netlbladdr_list);
+
+/*
+ * Rule lists are maintained for each label.
+ * This master list is just for reading /smack/load.
+ */
+struct smack_master_list {
+ struct list_head list;
+ struct smack_rule *smk_rule;
+};
+
LIST_HEAD(smack_rule_list);
static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
@@ -92,7 +103,7 @@ static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
const char *smack_cipso_option = SMACK_CIPSO_OPTION;
-#define SEQ_READ_FINISHED 1
+#define SEQ_READ_FINISHED ((loff_t)-1)
/*
* Values for parsing cipso rules
@@ -159,9 +170,13 @@ static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list,
mutex_lock(rule_lock);
+ /*
+ * Because the object label is less likely to match
+ * than the subject label check it first
+ */
list_for_each_entry_rcu(sp, rule_list, list) {
- if (sp->smk_subject == srp->smk_subject &&
- sp->smk_object == srp->smk_object) {
+ if (sp->smk_object == srp->smk_object &&
+ sp->smk_subject == srp->smk_subject) {
found = 1;
sp->smk_access = srp->smk_access;
break;
@@ -176,6 +191,99 @@ static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list,
}
/**
+ * smk_parse_rule - parse Smack rule from load string
+ * @data: string to be parsed whose size is SMK_LOADLEN
+ * @rule: Smack rule
+ * @import: if non-zero, import labels
+ */
+static int smk_parse_rule(const char *data, struct smack_rule *rule, int import)
+{
+ char smack[SMK_LABELLEN];
+ struct smack_known *skp;
+
+ if (import) {
+ rule->smk_subject = smk_import(data, 0);
+ if (rule->smk_subject == NULL)
+ return -1;
+
+ rule->smk_object = smk_import(data + SMK_LABELLEN, 0);
+ if (rule->smk_object == NULL)
+ return -1;
+ } else {
+ smk_parse_smack(data, 0, smack);
+ skp = smk_find_entry(smack);
+ if (skp == NULL)
+ return -1;
+ rule->smk_subject = skp->smk_known;
+
+ smk_parse_smack(data + SMK_LABELLEN, 0, smack);
+ skp = smk_find_entry(smack);
+ if (skp == NULL)
+ return -1;
+ rule->smk_object = skp->smk_known;
+ }
+
+ rule->smk_access = 0;
+
+ switch (data[SMK_LABELLEN + SMK_LABELLEN]) {
+ case '-':
+ break;
+ case 'r':
+ case 'R':
+ rule->smk_access |= MAY_READ;
+ break;
+ default:
+ return -1;
+ }
+
+ switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) {
+ case '-':
+ break;
+ case 'w':
+ case 'W':
+ rule->smk_access |= MAY_WRITE;
+ break;
+ default:
+ return -1;
+ }
+
+ switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) {
+ case '-':
+ break;
+ case 'x':
+ case 'X':
+ rule->smk_access |= MAY_EXEC;
+ break;
+ default:
+ return -1;
+ }
+
+ switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) {
+ case '-':
+ break;
+ case 'a':
+ case 'A':
+ rule->smk_access |= MAY_APPEND;
+ break;
+ default:
+ return -1;
+ }
+
+ switch (data[SMK_LABELLEN + SMK_LABELLEN + 4]) {
+ case '-':
+ break;
+ case 't':
+ case 'T':
+ rule->smk_access |= MAY_TRANSMUTE;
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
* smk_write_load_list - write() for any /smack/load
* @file: file pointer, not actually used
* @buf: where to get the data from
@@ -197,9 +305,12 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf,
struct list_head *rule_list,
struct mutex *rule_lock)
{
+ struct smack_master_list *smlp;
+ struct smack_known *skp;
struct smack_rule *rule;
char *data;
int rc = -EINVAL;
+ int load = 0;
/*
* No partial writes.
@@ -234,69 +345,14 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf,
goto out;
}
- rule->smk_subject = smk_import(data, 0);
- if (rule->smk_subject == NULL)
- goto out_free_rule;
-
- rule->smk_object = smk_import(data + SMK_LABELLEN, 0);
- if (rule->smk_object == NULL)
+ if (smk_parse_rule(data, rule, 1))
goto out_free_rule;
- rule->smk_access = 0;
-
- switch (data[SMK_LABELLEN + SMK_LABELLEN]) {
- case '-':
- break;
- case 'r':
- case 'R':
- rule->smk_access |= MAY_READ;
- break;
- default:
- goto out_free_rule;
- }
-
- switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) {
- case '-':
- break;
- case 'w':
- case 'W':
- rule->smk_access |= MAY_WRITE;
- break;
- default:
- goto out_free_rule;
- }
-
- switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) {
- case '-':
- break;
- case 'x':
- case 'X':
- rule->smk_access |= MAY_EXEC;
- break;
- default:
- goto out_free_rule;
- }
-
- switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) {
- case '-':
- break;
- case 'a':
- case 'A':
- rule->smk_access |= MAY_APPEND;
- break;
- default:
- goto out_free_rule;
- }
-
- switch (data[SMK_LABELLEN + SMK_LABELLEN + 4]) {
- case '-':
- break;
- case 't':
- case 'T':
- rule->smk_access |= MAY_TRANSMUTE;
- break;
- default:
- goto out_free_rule;
+ if (rule_list == NULL) {
+ load = 1;
+ skp = smk_find_entry(rule->smk_subject);
+ rule_list = &skp->smk_rules;
+ rule_lock = &skp->smk_rules_lock;
}
rc = count;
@@ -304,8 +360,15 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf,
* smk_set_access returns true if there was already a rule
* for the subject/object pair, and false if it was new.
*/
- if (!smk_set_access(rule, rule_list, rule_lock))
+ if (!smk_set_access(rule, rule_list, rule_lock)) {
+ smlp = kzalloc(sizeof(*smlp), GFP_KERNEL);
+ if (smlp != NULL) {
+ smlp->smk_rule = rule;
+ list_add_rcu(&smlp->list, &smack_rule_list);
+ } else
+ rc = -ENOMEM;
goto out;
+ }
out_free_rule:
kfree(rule);
@@ -321,11 +384,24 @@ out:
static void *load_seq_start(struct seq_file *s, loff_t *pos)
{
- if (*pos == SEQ_READ_FINISHED)
+ struct list_head *list;
+
+ /*
+ * This is 0 the first time through.
+ */
+ if (s->index == 0)
+ s->private = &smack_rule_list;
+
+ if (s->private == NULL)
return NULL;
- if (list_empty(&smack_rule_list))
+
+ list = s->private;
+ if (list_empty(list))
return NULL;
- return smack_rule_list.next;
+
+ if (s->index == 0)
+ return list->next;
+ return list;
}
static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
@@ -333,17 +409,19 @@ static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
struct list_head *list = v;
if (list_is_last(list, &smack_rule_list)) {
- *pos = SEQ_READ_FINISHED;
+ s->private = NULL;
return NULL;
}
+ s->private = list->next;
return list->next;
}
static int load_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
- struct smack_rule *srp =
- list_entry(list, struct smack_rule, list);
+ struct smack_master_list *smlp =
+ list_entry(list, struct smack_master_list, list);
+ struct smack_rule *srp = smlp->smk_rule;
seq_printf(s, "%s %s", (char *)srp->smk_subject,
(char *)srp->smk_object);
@@ -412,8 +490,7 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
if (!capable(CAP_MAC_ADMIN))
return -EPERM;
- return smk_write_load_list(file, buf, count, ppos, &smack_rule_list,
- &smack_list_lock);
+ return smk_write_load_list(file, buf, count, ppos, NULL, NULL);
}
static const struct file_operations smk_load_ops = {
@@ -1425,6 +1502,44 @@ static const struct file_operations smk_load_self_ops = {
.write = smk_write_load_self,
.release = seq_release,
};
+
+/**
+ * smk_write_access - handle access check transaction
+ * @file: file pointer
+ * @buf: data from user space
+ * @count: bytes sent
+ * @ppos: where to start - must be 0
+ */
+static ssize_t smk_write_access(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct smack_rule rule;
+ char *data;
+ int res;
+
+ data = simple_transaction_get(file, buf, count);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ if (count < SMK_LOADLEN || smk_parse_rule(data, &rule, 0))
+ return -EINVAL;
+
+ res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access,
+ NULL);
+ data[0] = res == 0 ? '1' : '0';
+ data[1] = '\0';
+
+ simple_transaction_set(file, 2);
+ return SMK_LOADLEN;
+}
+
+static const struct file_operations smk_access_ops = {
+ .write = smk_write_access,
+ .read = simple_transaction_read,
+ .release = simple_transaction_release,
+ .llseek = generic_file_llseek,
+};
+
/**
* smk_fill_super - fill the /smackfs superblock
* @sb: the empty superblock
@@ -1459,6 +1574,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
"logging", &smk_logging_ops, S_IRUGO|S_IWUSR},
[SMK_LOAD_SELF] = {
"load-self", &smk_load_self_ops, S_IRUGO|S_IWUGO},
+ [SMK_ACCESSES] = {
+ "access", &smk_access_ops, S_IRUGO|S_IWUGO},
/* last one */
{""}
};
@@ -1534,6 +1651,20 @@ static int __init init_smk_fs(void)
smk_cipso_doi();
smk_unlbl_ambient(NULL);
+ mutex_init(&smack_known_floor.smk_rules_lock);
+ mutex_init(&smack_known_hat.smk_rules_lock);
+ mutex_init(&smack_known_huh.smk_rules_lock);
+ mutex_init(&smack_known_invalid.smk_rules_lock);
+ mutex_init(&smack_known_star.smk_rules_lock);
+ mutex_init(&smack_known_web.smk_rules_lock);
+
+ INIT_LIST_HEAD(&smack_known_floor.smk_rules);
+ INIT_LIST_HEAD(&smack_known_hat.smk_rules);
+ INIT_LIST_HEAD(&smack_known_huh.smk_rules);
+ INIT_LIST_HEAD(&smack_known_invalid.smk_rules);
+ INIT_LIST_HEAD(&smack_known_star.smk_rules);
+ INIT_LIST_HEAD(&smack_known_web.smk_rules);
+
return err;
}
diff --git a/security/tomoyo/Kconfig b/security/tomoyo/Kconfig
index 7c7f8c16c10f..8eb779b9d77f 100644
--- a/security/tomoyo/Kconfig
+++ b/security/tomoyo/Kconfig
@@ -1,8 +1,10 @@
config SECURITY_TOMOYO
bool "TOMOYO Linux Support"
depends on SECURITY
+ depends on NET
select SECURITYFS
select SECURITY_PATH
+ select SECURITY_NETWORK
default n
help
This selects TOMOYO Linux, pathname-based access control.
diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile
index 95278b71fc21..56a0c7be409e 100644
--- a/security/tomoyo/Makefile
+++ b/security/tomoyo/Makefile
@@ -1,4 +1,4 @@
-obj-y = audit.o common.o condition.o domain.o file.o gc.o group.o load_policy.o memory.o mount.o realpath.o securityfs_if.o tomoyo.o util.o
+obj-y = audit.o common.o condition.o domain.o environ.o file.o gc.o group.o load_policy.o memory.o mount.o network.o realpath.o securityfs_if.o tomoyo.o util.o
$(obj)/policy/profile.conf:
@mkdir -p $(obj)/policy/
@@ -27,7 +27,7 @@ $(obj)/policy/stat.conf:
@touch $@
$(obj)/builtin-policy.h: $(obj)/policy/profile.conf $(obj)/policy/exception_policy.conf $(obj)/policy/domain_policy.conf $(obj)/policy/manager.conf $(obj)/policy/stat.conf
- @echo Generating built-in policy for TOMOYO 2.4.x.
+ @echo Generating built-in policy for TOMOYO 2.5.x.
@echo "static char tomoyo_builtin_profile[] __initdata =" > $@.tmp
@sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/profile.conf >> $@.tmp
@echo "\"\";" >> $@.tmp
diff --git a/security/tomoyo/audit.c b/security/tomoyo/audit.c
index 5dbb1f7617c0..075c3a6d1649 100644
--- a/security/tomoyo/audit.c
+++ b/security/tomoyo/audit.c
@@ -313,6 +313,7 @@ static unsigned int tomoyo_log_count;
*/
static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns,
const u8 profile, const u8 index,
+ const struct tomoyo_acl_info *matched_acl,
const bool is_granted)
{
u8 mode;
@@ -324,6 +325,9 @@ static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns,
p = tomoyo_profile(ns, profile);
if (tomoyo_log_count >= p->pref[TOMOYO_PREF_MAX_AUDIT_LOG])
return false;
+ if (is_granted && matched_acl && matched_acl->cond &&
+ matched_acl->cond->grant_log != TOMOYO_GRANTLOG_AUTO)
+ return matched_acl->cond->grant_log == TOMOYO_GRANTLOG_YES;
mode = p->config[index];
if (mode == TOMOYO_CONFIG_USE_DEFAULT)
mode = p->config[category];
@@ -350,7 +354,8 @@ void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
char *buf;
struct tomoyo_log *entry;
bool quota_exceeded = false;
- if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type, r->granted))
+ if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type,
+ r->matched_acl, r->granted))
goto out;
buf = tomoyo_init_log(r, len, fmt, args);
if (!buf)
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c
index 2e43aec1c36b..150911c7ff08 100644
--- a/security/tomoyo/common.c
+++ b/security/tomoyo/common.c
@@ -20,6 +20,7 @@ const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE] = {
/* String table for /sys/kernel/security/tomoyo/profile */
const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
+ TOMOYO_MAX_MAC_CATEGORY_INDEX] = {
+ /* CONFIG::file group */
[TOMOYO_MAC_FILE_EXECUTE] = "execute",
[TOMOYO_MAC_FILE_OPEN] = "open",
[TOMOYO_MAC_FILE_CREATE] = "create",
@@ -43,7 +44,28 @@ const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
[TOMOYO_MAC_FILE_MOUNT] = "mount",
[TOMOYO_MAC_FILE_UMOUNT] = "unmount",
[TOMOYO_MAC_FILE_PIVOT_ROOT] = "pivot_root",
+ /* CONFIG::network group */
+ [TOMOYO_MAC_NETWORK_INET_STREAM_BIND] = "inet_stream_bind",
+ [TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN] = "inet_stream_listen",
+ [TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT] = "inet_stream_connect",
+ [TOMOYO_MAC_NETWORK_INET_DGRAM_BIND] = "inet_dgram_bind",
+ [TOMOYO_MAC_NETWORK_INET_DGRAM_SEND] = "inet_dgram_send",
+ [TOMOYO_MAC_NETWORK_INET_RAW_BIND] = "inet_raw_bind",
+ [TOMOYO_MAC_NETWORK_INET_RAW_SEND] = "inet_raw_send",
+ [TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND] = "unix_stream_bind",
+ [TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN] = "unix_stream_listen",
+ [TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT] = "unix_stream_connect",
+ [TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND] = "unix_dgram_bind",
+ [TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND] = "unix_dgram_send",
+ [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND] = "unix_seqpacket_bind",
+ [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN] = "unix_seqpacket_listen",
+ [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = "unix_seqpacket_connect",
+ /* CONFIG::misc group */
+ [TOMOYO_MAC_ENVIRON] = "env",
+ /* CONFIG group */
[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file",
+ [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_NETWORK] = "network",
+ [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_MISC] = "misc",
};
/* String table for conditions. */
@@ -130,10 +152,20 @@ const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
[TOMOYO_TYPE_UMOUNT] = "unmount",
};
+/* String table for socket's operation. */
+const char * const tomoyo_socket_keyword[TOMOYO_MAX_NETWORK_OPERATION] = {
+ [TOMOYO_NETWORK_BIND] = "bind",
+ [TOMOYO_NETWORK_LISTEN] = "listen",
+ [TOMOYO_NETWORK_CONNECT] = "connect",
+ [TOMOYO_NETWORK_SEND] = "send",
+};
+
/* String table for categories. */
static const char * const tomoyo_category_keywords
[TOMOYO_MAX_MAC_CATEGORY_INDEX] = {
- [TOMOYO_MAC_CATEGORY_FILE] = "file",
+ [TOMOYO_MAC_CATEGORY_FILE] = "file",
+ [TOMOYO_MAC_CATEGORY_NETWORK] = "network",
+ [TOMOYO_MAC_CATEGORY_MISC] = "misc",
};
/* Permit policy management by non-root user? */
@@ -230,13 +262,17 @@ static void tomoyo_set_string(struct tomoyo_io_buffer *head, const char *string)
WARN_ON(1);
}
+static void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt,
+ ...) __printf(2, 3);
+
/**
* tomoyo_io_printf - printf() to "struct tomoyo_io_buffer" structure.
*
* @head: Pointer to "struct tomoyo_io_buffer".
* @fmt: The printf()'s format string, followed by parameters.
*/
-void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
+static void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt,
+ ...)
{
va_list args;
size_t len;
@@ -313,7 +349,7 @@ void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns)
INIT_LIST_HEAD(&ns->group_list[idx]);
for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++)
INIT_LIST_HEAD(&ns->policy_list[idx]);
- ns->profile_version = 20100903;
+ ns->profile_version = 20110903;
tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list);
list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list);
}
@@ -466,8 +502,10 @@ static struct tomoyo_profile *tomoyo_assign_profile
TOMOYO_CONFIG_WANT_REJECT_LOG;
memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT,
sizeof(ptr->config));
- ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] = 1024;
- ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] = 2048;
+ ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] =
+ CONFIG_SECURITY_TOMOYO_MAX_AUDIT_LOG;
+ ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] =
+ CONFIG_SECURITY_TOMOYO_MAX_ACCEPT_ENTRY;
mb(); /* Avoid out-of-order execution. */
ns->profile_ptr[profile] = ptr;
entry = NULL;
@@ -951,14 +989,12 @@ static bool tomoyo_select_domain(struct tomoyo_io_buffer *head,
(global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
struct task_struct *p;
rcu_read_lock();
- read_lock(&tasklist_lock);
if (global_pid)
p = find_task_by_pid_ns(pid, &init_pid_ns);
else
p = find_task_by_vpid(pid);
if (p)
domain = tomoyo_real_domain(p);
- read_unlock(&tasklist_lock);
rcu_read_unlock();
} else if (!strncmp(data, "domain=", 7)) {
if (tomoyo_domain_def(data + 7))
@@ -982,6 +1018,48 @@ static bool tomoyo_select_domain(struct tomoyo_io_buffer *head,
}
/**
+ * tomoyo_same_task_acl - Check for duplicated "struct tomoyo_task_acl" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_info".
+ * @b: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static bool tomoyo_same_task_acl(const struct tomoyo_acl_info *a,
+ const struct tomoyo_acl_info *b)
+{
+ const struct tomoyo_task_acl *p1 = container_of(a, typeof(*p1), head);
+ const struct tomoyo_task_acl *p2 = container_of(b, typeof(*p2), head);
+ return p1->domainname == p2->domainname;
+}
+
+/**
+ * tomoyo_write_task - Update task related list.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_write_task(struct tomoyo_acl_param *param)
+{
+ int error = -EINVAL;
+ if (tomoyo_str_starts(&param->data, "manual_domain_transition ")) {
+ struct tomoyo_task_acl e = {
+ .head.type = TOMOYO_TYPE_MANUAL_TASK_ACL,
+ .domainname = tomoyo_get_domainname(param),
+ };
+ if (e.domainname)
+ error = tomoyo_update_domain(&e.head, sizeof(e), param,
+ tomoyo_same_task_acl,
+ NULL);
+ tomoyo_put_name(e.domainname);
+ }
+ return error;
+}
+
+/**
* tomoyo_delete_domain - Delete a domain.
*
* @domainname: The name of domain.
@@ -1039,11 +1117,16 @@ static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns,
static const struct {
const char *keyword;
int (*write) (struct tomoyo_acl_param *);
- } tomoyo_callback[1] = {
+ } tomoyo_callback[5] = {
{ "file ", tomoyo_write_file },
+ { "network inet ", tomoyo_write_inet_network },
+ { "network unix ", tomoyo_write_unix_network },
+ { "misc ", tomoyo_write_misc },
+ { "task ", tomoyo_write_task },
};
u8 i;
- for (i = 0; i < 1; i++) {
+
+ for (i = 0; i < ARRAY_SIZE(tomoyo_callback); i++) {
if (!tomoyo_str_starts(&param.data,
tomoyo_callback[i].keyword))
continue;
@@ -1127,6 +1210,10 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
case 0:
head->r.cond_index = 0;
head->r.cond_step++;
+ if (cond->transit) {
+ tomoyo_set_space(head);
+ tomoyo_set_string(head, cond->transit->name);
+ }
/* fall through */
case 1:
{
@@ -1239,6 +1326,10 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
head->r.cond_step++;
/* fall through */
case 3:
+ if (cond->grant_log != TOMOYO_GRANTLOG_AUTO)
+ tomoyo_io_printf(head, " grant_log=%s",
+ tomoyo_yesno(cond->grant_log ==
+ TOMOYO_GRANTLOG_YES));
tomoyo_set_lf(head);
return true;
}
@@ -1306,6 +1397,12 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
if (first)
return true;
tomoyo_print_name_union(head, &ptr->name);
+ } else if (acl_type == TOMOYO_TYPE_MANUAL_TASK_ACL) {
+ struct tomoyo_task_acl *ptr =
+ container_of(acl, typeof(*ptr), head);
+ tomoyo_set_group(head, "task ");
+ tomoyo_set_string(head, "manual_domain_transition ");
+ tomoyo_set_string(head, ptr->domainname->name);
} else if (head->r.print_transition_related_only) {
return true;
} else if (acl_type == TOMOYO_TYPE_PATH2_ACL) {
@@ -1370,6 +1467,60 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
tomoyo_print_number_union(head, &ptr->mode);
tomoyo_print_number_union(head, &ptr->major);
tomoyo_print_number_union(head, &ptr->minor);
+ } else if (acl_type == TOMOYO_TYPE_INET_ACL) {
+ struct tomoyo_inet_acl *ptr =
+ container_of(acl, typeof(*ptr), head);
+ const u8 perm = ptr->perm;
+
+ for (bit = 0; bit < TOMOYO_MAX_NETWORK_OPERATION; bit++) {
+ if (!(perm & (1 << bit)))
+ continue;
+ if (first) {
+ tomoyo_set_group(head, "network inet ");
+ tomoyo_set_string(head, tomoyo_proto_keyword
+ [ptr->protocol]);
+ tomoyo_set_space(head);
+ first = false;
+ } else {
+ tomoyo_set_slash(head);
+ }
+ tomoyo_set_string(head, tomoyo_socket_keyword[bit]);
+ }
+ if (first)
+ return true;
+ tomoyo_set_space(head);
+ if (ptr->address.group) {
+ tomoyo_set_string(head, "@");
+ tomoyo_set_string(head, ptr->address.group->group_name
+ ->name);
+ } else {
+ char buf[128];
+ tomoyo_print_ip(buf, sizeof(buf), &ptr->address);
+ tomoyo_io_printf(head, "%s", buf);
+ }
+ tomoyo_print_number_union(head, &ptr->port);
+ } else if (acl_type == TOMOYO_TYPE_UNIX_ACL) {
+ struct tomoyo_unix_acl *ptr =
+ container_of(acl, typeof(*ptr), head);
+ const u8 perm = ptr->perm;
+
+ for (bit = 0; bit < TOMOYO_MAX_NETWORK_OPERATION; bit++) {
+ if (!(perm & (1 << bit)))
+ continue;
+ if (first) {
+ tomoyo_set_group(head, "network unix ");
+ tomoyo_set_string(head, tomoyo_proto_keyword
+ [ptr->protocol]);
+ tomoyo_set_space(head);
+ first = false;
+ } else {
+ tomoyo_set_slash(head);
+ }
+ tomoyo_set_string(head, tomoyo_socket_keyword[bit]);
+ }
+ if (first)
+ return true;
+ tomoyo_print_name_union(head, &ptr->name);
} else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) {
struct tomoyo_mount_acl *ptr =
container_of(acl, typeof(*ptr), head);
@@ -1378,6 +1529,12 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
tomoyo_print_name_union(head, &ptr->dir_name);
tomoyo_print_name_union(head, &ptr->fs_type);
tomoyo_print_number_union(head, &ptr->flags);
+ } else if (acl_type == TOMOYO_TYPE_ENV_ACL) {
+ struct tomoyo_env_acl *ptr =
+ container_of(acl, typeof(*ptr), head);
+
+ tomoyo_set_group(head, "misc env ");
+ tomoyo_set_string(head, ptr->env->name);
}
if (acl->cond) {
head->r.print_cond_part = true;
@@ -1510,14 +1667,12 @@ static void tomoyo_read_pid(struct tomoyo_io_buffer *head)
global_pid = true;
pid = (unsigned int) simple_strtoul(buf, NULL, 10);
rcu_read_lock();
- read_lock(&tasklist_lock);
if (global_pid)
p = find_task_by_pid_ns(pid, &init_pid_ns);
else
p = find_task_by_vpid(pid);
if (p)
domain = tomoyo_real_domain(p);
- read_unlock(&tasklist_lock);
rcu_read_unlock();
if (!domain)
return;
@@ -1537,8 +1692,9 @@ static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = {
/* String table for grouping keywords. */
static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = {
- [TOMOYO_PATH_GROUP] = "path_group ",
- [TOMOYO_NUMBER_GROUP] = "number_group ",
+ [TOMOYO_PATH_GROUP] = "path_group ",
+ [TOMOYO_NUMBER_GROUP] = "number_group ",
+ [TOMOYO_ADDRESS_GROUP] = "address_group ",
};
/**
@@ -1580,7 +1736,7 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
}
/**
- * tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group" list.
+ * tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group"/"struct tomoyo_address_group" list.
*
* @head: Pointer to "struct tomoyo_io_buffer".
* @idx: Index number.
@@ -1617,6 +1773,15 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx)
(ptr,
struct tomoyo_number_group,
head)->number);
+ } else if (idx == TOMOYO_ADDRESS_GROUP) {
+ char buffer[128];
+
+ struct tomoyo_address_group *member =
+ container_of(ptr, typeof(*member),
+ head);
+ tomoyo_print_ip(buffer, sizeof(buffer),
+ &member->address);
+ tomoyo_io_printf(head, " %s", buffer);
}
tomoyo_set_lf(head);
}
@@ -2066,27 +2231,7 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head)
static void tomoyo_read_version(struct tomoyo_io_buffer *head)
{
if (!head->r.eof) {
- tomoyo_io_printf(head, "2.4.0");
- head->r.eof = true;
- }
-}
-
-/**
- * tomoyo_read_self_domain - Get the current process's domainname.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns the current process's domainname.
- */
-static void tomoyo_read_self_domain(struct tomoyo_io_buffer *head)
-{
- if (!head->r.eof) {
- /*
- * tomoyo_domain()->domainname != NULL
- * because every process belongs to a domain and
- * the domain's name cannot be NULL.
- */
- tomoyo_io_printf(head, "%s", tomoyo_domain()->domainname->name);
+ tomoyo_io_printf(head, "2.5.0");
head->r.eof = true;
}
}
@@ -2221,10 +2366,6 @@ int tomoyo_open_control(const u8 type, struct file *file)
head->poll = tomoyo_poll_log;
head->read = tomoyo_read_log;
break;
- case TOMOYO_SELFDOMAIN:
- /* /sys/kernel/security/tomoyo/self_domain */
- head->read = tomoyo_read_self_domain;
- break;
case TOMOYO_PROCESS_STATUS:
/* /sys/kernel/security/tomoyo/.process_status */
head->write = tomoyo_write_pid;
@@ -2453,6 +2594,7 @@ ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head,
return -EFAULT;
if (mutex_lock_interruptible(&head->io_sem))
return -EINTR;
+ head->read_user_buf_avail = 0;
idx = tomoyo_read_lock();
/* Read a line and dispatch it to the policy handler. */
while (avail_len > 0) {
@@ -2562,11 +2704,11 @@ void tomoyo_check_profile(void)
struct tomoyo_domain_info *domain;
const int idx = tomoyo_read_lock();
tomoyo_policy_loaded = true;
- printk(KERN_INFO "TOMOYO: 2.4.0\n");
+ printk(KERN_INFO "TOMOYO: 2.5.0\n");
list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
const u8 profile = domain->profile;
const struct tomoyo_policy_namespace *ns = domain->ns;
- if (ns->profile_version != 20100903)
+ if (ns->profile_version != 20110903)
printk(KERN_ERR
"Profile version %u is not supported.\n",
ns->profile_version);
@@ -2577,9 +2719,9 @@ void tomoyo_check_profile(void)
else
continue;
printk(KERN_ERR
- "Userland tools for TOMOYO 2.4 must be installed and "
+ "Userland tools for TOMOYO 2.5 must be installed and "
"policy must be initialized.\n");
- printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.4/ "
+ printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.5/ "
"for more information.\n");
panic("STOP!");
}
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index f7fbaa66e443..ed311d7a8ce0 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -3,7 +3,7 @@
*
* Header file for TOMOYO.
*
- * Copyright (C) 2005-2010 NTT DATA CORPORATION
+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
*/
#ifndef _SECURITY_TOMOYO_COMMON_H
@@ -23,6 +23,16 @@
#include <linux/poll.h>
#include <linux/binfmts.h>
#include <linux/highmem.h>
+#include <linux/net.h>
+#include <linux/inet.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/un.h>
+#include <net/sock.h>
+#include <net/af_unix.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <net/udp.h>
/********** Constants definitions. **********/
@@ -34,8 +44,17 @@
#define TOMOYO_HASH_BITS 8
#define TOMOYO_MAX_HASH (1u<<TOMOYO_HASH_BITS)
+/*
+ * TOMOYO checks only SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_SEQPACKET.
+ * Therefore, we don't need SOCK_MAX.
+ */
+#define TOMOYO_SOCK_MAX 6
+
#define TOMOYO_EXEC_TMPSIZE 4096
+/* Garbage collector is trying to kfree() this element. */
+#define TOMOYO_GC_IN_PROGRESS -1
+
/* Profile number is an integer between 0 and 255. */
#define TOMOYO_MAX_PROFILES 256
@@ -136,6 +155,7 @@ enum tomoyo_mode_index {
/* Index numbers for entry type. */
enum tomoyo_policy_id {
TOMOYO_ID_GROUP,
+ TOMOYO_ID_ADDRESS_GROUP,
TOMOYO_ID_PATH_GROUP,
TOMOYO_ID_NUMBER_GROUP,
TOMOYO_ID_TRANSITION_CONTROL,
@@ -162,10 +182,21 @@ enum tomoyo_domain_info_flags_index {
TOMOYO_MAX_DOMAIN_INFO_FLAGS
};
+/* Index numbers for audit type. */
+enum tomoyo_grant_log {
+ /* Follow profile's configuration. */
+ TOMOYO_GRANTLOG_AUTO,
+ /* Do not generate grant log. */
+ TOMOYO_GRANTLOG_NO,
+ /* Generate grant_log. */
+ TOMOYO_GRANTLOG_YES,
+};
+
/* Index numbers for group entries. */
enum tomoyo_group_id {
TOMOYO_PATH_GROUP,
TOMOYO_NUMBER_GROUP,
+ TOMOYO_ADDRESS_GROUP,
TOMOYO_MAX_GROUP
};
@@ -196,6 +227,10 @@ enum tomoyo_acl_entry_type_index {
TOMOYO_TYPE_PATH_NUMBER_ACL,
TOMOYO_TYPE_MKDEV_ACL,
TOMOYO_TYPE_MOUNT_ACL,
+ TOMOYO_TYPE_INET_ACL,
+ TOMOYO_TYPE_UNIX_ACL,
+ TOMOYO_TYPE_ENV_ACL,
+ TOMOYO_TYPE_MANUAL_TASK_ACL,
};
/* Index numbers for access controls with one pathname. */
@@ -228,6 +263,15 @@ enum tomoyo_mkdev_acl_index {
TOMOYO_MAX_MKDEV_OPERATION
};
+/* Index numbers for socket operations. */
+enum tomoyo_network_acl_index {
+ TOMOYO_NETWORK_BIND, /* bind() operation. */
+ TOMOYO_NETWORK_LISTEN, /* listen() operation. */
+ TOMOYO_NETWORK_CONNECT, /* connect() operation. */
+ TOMOYO_NETWORK_SEND, /* send() operation. */
+ TOMOYO_MAX_NETWORK_OPERATION
+};
+
/* Index numbers for access controls with two pathnames. */
enum tomoyo_path2_acl_index {
TOMOYO_TYPE_LINK,
@@ -255,7 +299,6 @@ enum tomoyo_securityfs_interface_index {
TOMOYO_EXCEPTIONPOLICY,
TOMOYO_PROCESS_STATUS,
TOMOYO_STAT,
- TOMOYO_SELFDOMAIN,
TOMOYO_AUDIT,
TOMOYO_VERSION,
TOMOYO_PROFILE,
@@ -300,12 +343,30 @@ enum tomoyo_mac_index {
TOMOYO_MAC_FILE_MOUNT,
TOMOYO_MAC_FILE_UMOUNT,
TOMOYO_MAC_FILE_PIVOT_ROOT,
+ TOMOYO_MAC_NETWORK_INET_STREAM_BIND,
+ TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN,
+ TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT,
+ TOMOYO_MAC_NETWORK_INET_DGRAM_BIND,
+ TOMOYO_MAC_NETWORK_INET_DGRAM_SEND,
+ TOMOYO_MAC_NETWORK_INET_RAW_BIND,
+ TOMOYO_MAC_NETWORK_INET_RAW_SEND,
+ TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND,
+ TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN,
+ TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT,
+ TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND,
+ TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND,
+ TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND,
+ TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN,
+ TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT,
+ TOMOYO_MAC_ENVIRON,
TOMOYO_MAX_MAC_INDEX
};
/* Index numbers for category of functionality. */
enum tomoyo_mac_category_index {
TOMOYO_MAC_CATEGORY_FILE,
+ TOMOYO_MAC_CATEGORY_NETWORK,
+ TOMOYO_MAC_CATEGORY_MISC,
TOMOYO_MAX_MAC_CATEGORY_INDEX
};
@@ -340,7 +401,7 @@ enum tomoyo_pref_index {
/* Common header for holding ACL entries. */
struct tomoyo_acl_head {
struct list_head list;
- bool is_deleted;
+ s8 is_deleted; /* true or false or TOMOYO_GC_IN_PROGRESS */
} __packed;
/* Common header for shared entries. */
@@ -397,13 +458,36 @@ struct tomoyo_request_info {
u8 operation;
} path_number;
struct {
+ const struct tomoyo_path_info *name;
+ } environ;
+ struct {
+ const __be32 *address;
+ u16 port;
+ /* One of values smaller than TOMOYO_SOCK_MAX. */
+ u8 protocol;
+ /* One of values in "enum tomoyo_network_acl_index". */
+ u8 operation;
+ bool is_ipv6;
+ } inet_network;
+ struct {
+ const struct tomoyo_path_info *address;
+ /* One of values smaller than TOMOYO_SOCK_MAX. */
+ u8 protocol;
+ /* One of values in "enum tomoyo_network_acl_index". */
+ u8 operation;
+ } unix_network;
+ struct {
const struct tomoyo_path_info *type;
const struct tomoyo_path_info *dir;
const struct tomoyo_path_info *dev;
unsigned long flags;
int need_dev;
} mount;
+ struct {
+ const struct tomoyo_path_info *domainname;
+ } task;
} param;
+ struct tomoyo_acl_info *matched_acl;
u8 param_type;
bool granted;
u8 retry;
@@ -442,7 +526,14 @@ struct tomoyo_number_union {
u8 value_type[2];
};
-/* Structure for "path_group"/"number_group" directive. */
+/* Structure for holding an IP address. */
+struct tomoyo_ipaddr_union {
+ struct in6_addr ip[2]; /* Big endian. */
+ struct tomoyo_group *group; /* Pointer to address group. */
+ bool is_ipv6; /* Valid only if @group == NULL. */
+};
+
+/* Structure for "path_group"/"number_group"/"address_group" directive. */
struct tomoyo_group {
struct tomoyo_shared_acl_head head;
const struct tomoyo_path_info *group_name;
@@ -461,6 +552,13 @@ struct tomoyo_number_group {
struct tomoyo_number_union number;
};
+/* Structure for "address_group" directive. */
+struct tomoyo_address_group {
+ struct tomoyo_acl_head head;
+ /* Structure for holding an IP address. */
+ struct tomoyo_ipaddr_union address;
+};
+
/* Subset of "struct stat". Used by conditional ACL and audit logs. */
struct tomoyo_mini_stat {
uid_t uid;
@@ -520,6 +618,7 @@ struct tomoyo_execve {
struct tomoyo_request_info r;
struct tomoyo_obj_info obj;
struct linux_binprm *bprm;
+ const struct tomoyo_path_info *transition;
/* For dumping argv[] and envp[]. */
struct tomoyo_page_dump dump;
/* For temporary use. */
@@ -554,6 +653,8 @@ struct tomoyo_condition {
u16 names_count; /* Number of "struct tomoyo_name_union names". */
u16 argc; /* Number of "struct tomoyo_argv". */
u16 envc; /* Number of "struct tomoyo_envp". */
+ u8 grant_log; /* One of values in "enum tomoyo_grant_log". */
+ const struct tomoyo_path_info *transit; /* Maybe NULL. */
/*
* struct tomoyo_condition_element condition[condc];
* struct tomoyo_number_union values[numbers_count];
@@ -567,7 +668,7 @@ struct tomoyo_condition {
struct tomoyo_acl_info {
struct list_head list;
struct tomoyo_condition *cond; /* Maybe NULL. */
- bool is_deleted;
+ s8 is_deleted; /* true or false or TOMOYO_GC_IN_PROGRESS */
u8 type; /* One of values in "enum tomoyo_acl_entry_type_index". */
} __packed;
@@ -587,6 +688,15 @@ struct tomoyo_domain_info {
};
/*
+ * Structure for "task manual_domain_transition" directive.
+ */
+struct tomoyo_task_acl {
+ struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MANUAL_TASK_ACL */
+ /* Pointer to domainname. */
+ const struct tomoyo_path_info *domainname;
+};
+
+/*
* Structure for "file execute", "file read", "file write", "file append",
* "file unlink", "file getattr", "file rmdir", "file truncate",
* "file symlink", "file chroot" and "file unmount" directive.
@@ -638,6 +748,29 @@ struct tomoyo_mount_acl {
struct tomoyo_number_union flags;
};
+/* Structure for "misc env" directive in domain policy. */
+struct tomoyo_env_acl {
+ struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_ENV_ACL */
+ const struct tomoyo_path_info *env; /* environment variable */
+};
+
+/* Structure for "network inet" directive. */
+struct tomoyo_inet_acl {
+ struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_INET_ACL */
+ u8 protocol;
+ u8 perm; /* Bitmask of values in "enum tomoyo_network_acl_index" */
+ struct tomoyo_ipaddr_union address;
+ struct tomoyo_number_union port;
+};
+
+/* Structure for "network unix" directive. */
+struct tomoyo_unix_acl {
+ struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_UNIX_ACL */
+ u8 protocol;
+ u8 perm; /* Bitmask of values in "enum tomoyo_network_acl_index" */
+ struct tomoyo_name_union name;
+};
+
/* Structure for holding a line from /sys/kernel/security/tomoyo/ interface. */
struct tomoyo_acl_param {
char *data;
@@ -773,7 +906,7 @@ struct tomoyo_policy_namespace {
struct list_head acl_group[TOMOYO_MAX_ACL_GROUPS];
/* List for connecting to tomoyo_namespace_list list. */
struct list_head namespace_list;
- /* Profile version. Currently only 20100903 is defined. */
+ /* Profile version. Currently only 20110903 is defined. */
unsigned int profile_version;
/* Name of this namespace (e.g. "<kernel>", "</usr/sbin/httpd>" ). */
const char *name;
@@ -781,6 +914,8 @@ struct tomoyo_policy_namespace {
/********** Function prototypes. **********/
+bool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *address,
+ const struct tomoyo_group *group);
bool tomoyo_compare_number_union(const unsigned long value,
const struct tomoyo_number_union *ptr);
bool tomoyo_condition(struct tomoyo_request_info *r,
@@ -796,6 +931,8 @@ bool tomoyo_memory_ok(void *ptr);
bool tomoyo_number_matches_group(const unsigned long min,
const unsigned long max,
const struct tomoyo_group *group);
+bool tomoyo_parse_ipaddr_union(struct tomoyo_acl_param *param,
+ struct tomoyo_ipaddr_union *ptr);
bool tomoyo_parse_name_union(struct tomoyo_acl_param *param,
struct tomoyo_name_union *ptr);
bool tomoyo_parse_number_union(struct tomoyo_acl_param *param,
@@ -805,6 +942,7 @@ bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
bool tomoyo_permstr(const char *string, const char *keyword);
bool tomoyo_str_starts(char **src, const char *find);
char *tomoyo_encode(const char *str);
+char *tomoyo_encode2(const char *str, int str_len);
char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt,
va_list args);
char *tomoyo_read_token(struct tomoyo_acl_param *param);
@@ -814,12 +952,17 @@ const char *tomoyo_get_exe(void);
const char *tomoyo_yesno(const unsigned int value);
const struct tomoyo_path_info *tomoyo_compare_name_union
(const struct tomoyo_path_info *name, const struct tomoyo_name_union *ptr);
+const struct tomoyo_path_info *tomoyo_get_domainname
+(struct tomoyo_acl_param *param);
const struct tomoyo_path_info *tomoyo_get_name(const char *name);
const struct tomoyo_path_info *tomoyo_path_matches_group
(const struct tomoyo_path_info *pathname, const struct tomoyo_group *group);
int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
struct path *path, const int flag);
int tomoyo_close_control(struct tomoyo_io_buffer *head);
+int tomoyo_env_perm(struct tomoyo_request_info *r, const char *env);
+int tomoyo_execute_permission(struct tomoyo_request_info *r,
+ const struct tomoyo_path_info *filename);
int tomoyo_find_next_domain(struct linux_binprm *bprm);
int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile,
const u8 index);
@@ -838,10 +981,15 @@ int tomoyo_path_number_perm(const u8 operation, struct path *path,
unsigned long number);
int tomoyo_path_perm(const u8 operation, struct path *path,
const char *target);
-int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
- const struct tomoyo_path_info *filename);
int tomoyo_poll_control(struct file *file, poll_table *wait);
int tomoyo_poll_log(struct file *file, poll_table *wait);
+int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr,
+ int addr_len);
+int tomoyo_socket_connect_permission(struct socket *sock,
+ struct sockaddr *addr, int addr_len);
+int tomoyo_socket_listen_permission(struct socket *sock);
+int tomoyo_socket_sendmsg_permission(struct socket *sock, struct msghdr *msg,
+ int size);
int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
__printf(2, 3);
int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
@@ -860,8 +1008,11 @@ int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
int tomoyo_write_aggregator(struct tomoyo_acl_param *param);
int tomoyo_write_file(struct tomoyo_acl_param *param);
int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type);
+int tomoyo_write_misc(struct tomoyo_acl_param *param);
+int tomoyo_write_inet_network(struct tomoyo_acl_param *param);
int tomoyo_write_transition_control(struct tomoyo_acl_param *param,
const u8 type);
+int tomoyo_write_unix_network(struct tomoyo_acl_param *param);
ssize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer,
const int buffer_len);
ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head,
@@ -891,12 +1042,11 @@ void tomoyo_del_condition(struct list_head *element);
void tomoyo_fill_path_info(struct tomoyo_path_info *ptr);
void tomoyo_get_attributes(struct tomoyo_obj_info *obj);
void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns);
-void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
- __printf(2, 3);
void tomoyo_load_policy(const char *filename);
-void tomoyo_memory_free(void *ptr);
void tomoyo_normalize_line(unsigned char *buffer);
void tomoyo_notify_gc(struct tomoyo_io_buffer *head, const bool is_register);
+void tomoyo_print_ip(char *buf, const unsigned int size,
+ const struct tomoyo_ipaddr_union *ptr);
void tomoyo_print_ulong(char *buffer, const int buffer_len,
const unsigned long value, const u8 type);
void tomoyo_put_name_union(struct tomoyo_name_union *ptr);
@@ -919,6 +1069,8 @@ extern const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
+ TOMOYO_MAX_MAC_CATEGORY_INDEX];
extern const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE];
extern const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION];
+extern const char * const tomoyo_proto_keyword[TOMOYO_SOCK_MAX];
+extern const char * const tomoyo_socket_keyword[TOMOYO_MAX_NETWORK_OPERATION];
extern const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX];
extern const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION];
extern const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION];
@@ -1098,6 +1250,21 @@ static inline bool tomoyo_same_number_union
}
/**
+ * tomoyo_same_ipaddr_union - Check for duplicated "struct tomoyo_ipaddr_union" entry.
+ *
+ * @a: Pointer to "struct tomoyo_ipaddr_union".
+ * @b: Pointer to "struct tomoyo_ipaddr_union".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static inline bool tomoyo_same_ipaddr_union
+(const struct tomoyo_ipaddr_union *a, const struct tomoyo_ipaddr_union *b)
+{
+ return !memcmp(a->ip, b->ip, sizeof(a->ip)) && a->group == b->group &&
+ a->is_ipv6 == b->is_ipv6;
+}
+
+/**
* tomoyo_current_namespace - Get "struct tomoyo_policy_namespace" for current thread.
*
* Returns pointer to "struct tomoyo_policy_namespace" for current thread.
diff --git a/security/tomoyo/condition.c b/security/tomoyo/condition.c
index 8a05f71eaf67..986330b8c73e 100644
--- a/security/tomoyo/condition.c
+++ b/security/tomoyo/condition.c
@@ -348,6 +348,7 @@ static inline bool tomoyo_same_condition(const struct tomoyo_condition *a,
a->numbers_count == b->numbers_count &&
a->names_count == b->names_count &&
a->argc == b->argc && a->envc == b->envc &&
+ a->grant_log == b->grant_log && a->transit == b->transit &&
!memcmp(a + 1, b + 1, a->size - sizeof(*a));
}
@@ -399,8 +400,9 @@ static struct tomoyo_condition *tomoyo_commit_condition
found = true;
goto out;
}
- list_for_each_entry_rcu(ptr, &tomoyo_condition_list, head.list) {
- if (!tomoyo_same_condition(ptr, entry))
+ list_for_each_entry(ptr, &tomoyo_condition_list, head.list) {
+ if (!tomoyo_same_condition(ptr, entry) ||
+ atomic_read(&ptr->head.users) == TOMOYO_GC_IN_PROGRESS)
continue;
/* Same entry found. Share this entry. */
atomic_inc(&ptr->head.users);
@@ -410,8 +412,7 @@ static struct tomoyo_condition *tomoyo_commit_condition
if (!found) {
if (tomoyo_memory_ok(entry)) {
atomic_set(&entry->head.users, 1);
- list_add_rcu(&entry->head.list,
- &tomoyo_condition_list);
+ list_add(&entry->head.list, &tomoyo_condition_list);
} else {
found = true;
ptr = NULL;
@@ -428,6 +429,46 @@ out:
}
/**
+ * tomoyo_get_transit_preference - Parse domain transition preference for execve().
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ * @e: Pointer to "struct tomoyo_condition".
+ *
+ * Returns the condition string part.
+ */
+static char *tomoyo_get_transit_preference(struct tomoyo_acl_param *param,
+ struct tomoyo_condition *e)
+{
+ char * const pos = param->data;
+ bool flag;
+ if (*pos == '<') {
+ e->transit = tomoyo_get_domainname(param);
+ goto done;
+ }
+ {
+ char *cp = strchr(pos, ' ');
+ if (cp)
+ *cp = '\0';
+ flag = tomoyo_correct_path(pos) || !strcmp(pos, "keep") ||
+ !strcmp(pos, "initialize") || !strcmp(pos, "reset") ||
+ !strcmp(pos, "child") || !strcmp(pos, "parent");
+ if (cp)
+ *cp = ' ';
+ }
+ if (!flag)
+ return pos;
+ e->transit = tomoyo_get_name(tomoyo_read_token(param));
+done:
+ if (e->transit)
+ return param->data;
+ /*
+ * Return a bad read-only condition string that will let
+ * tomoyo_get_condition() return NULL.
+ */
+ return "/";
+}
+
+/**
* tomoyo_get_condition - Parse condition part.
*
* @param: Pointer to "struct tomoyo_acl_param".
@@ -443,7 +484,8 @@ struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param)
struct tomoyo_argv *argv = NULL;
struct tomoyo_envp *envp = NULL;
struct tomoyo_condition e = { };
- char * const start_of_string = param->data;
+ char * const start_of_string =
+ tomoyo_get_transit_preference(param, &e);
char * const end_of_string = start_of_string + strlen(start_of_string);
char *pos;
rerun:
@@ -486,6 +528,20 @@ rerun:
goto out;
dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word,
is_not ? "!" : "", right_word);
+ if (!strcmp(left_word, "grant_log")) {
+ if (entry) {
+ if (is_not ||
+ entry->grant_log != TOMOYO_GRANTLOG_AUTO)
+ goto out;
+ else if (!strcmp(right_word, "yes"))
+ entry->grant_log = TOMOYO_GRANTLOG_YES;
+ else if (!strcmp(right_word, "no"))
+ entry->grant_log = TOMOYO_GRANTLOG_NO;
+ else
+ goto out;
+ }
+ continue;
+ }
if (!strncmp(left_word, "exec.argv[", 10)) {
if (!argv) {
e.argc++;
@@ -593,8 +649,9 @@ store_value:
+ e.envc * sizeof(struct tomoyo_envp);
entry = kzalloc(e.size, GFP_NOFS);
if (!entry)
- return NULL;
+ goto out2;
*entry = e;
+ e.transit = NULL;
condp = (struct tomoyo_condition_element *) (entry + 1);
numbers_p = (struct tomoyo_number_union *) (condp + e.condc);
names_p = (struct tomoyo_name_union *) (numbers_p + e.numbers_count);
@@ -621,6 +678,8 @@ out:
tomoyo_del_condition(&entry->head.list);
kfree(entry);
}
+out2:
+ tomoyo_put_name(e.transit);
return NULL;
}
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
index cd0f92d88bb4..9027ac1534af 100644
--- a/security/tomoyo/domain.c
+++ b/security/tomoyo/domain.c
@@ -39,6 +39,8 @@ int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
if (mutex_lock_interruptible(&tomoyo_policy_lock))
return -ENOMEM;
list_for_each_entry_rcu(entry, list, list) {
+ if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS)
+ continue;
if (!check_duplicate(entry, new_entry))
continue;
entry->is_deleted = param->is_delete;
@@ -102,10 +104,21 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
new_entry->cond = tomoyo_get_condition(param);
if (!new_entry->cond)
return -EINVAL;
+ /*
+ * Domain transition preference is allowed for only
+ * "file execute" entries.
+ */
+ if (new_entry->cond->transit &&
+ !(new_entry->type == TOMOYO_TYPE_PATH_ACL &&
+ container_of(new_entry, struct tomoyo_path_acl, head)
+ ->perm == 1 << TOMOYO_TYPE_EXECUTE))
+ goto out;
}
if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out;
list_for_each_entry_rcu(entry, list, list) {
+ if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS)
+ continue;
if (!tomoyo_same_acl_head(entry, new_entry) ||
!check_duplicate(entry, new_entry))
continue;
@@ -157,6 +170,7 @@ retry:
continue;
if (!tomoyo_condition(r, ptr->cond))
continue;
+ r->matched_acl = ptr;
r->granted = true;
return;
}
@@ -501,7 +515,8 @@ struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
* that domain. Do not perform domain transition if
* profile for that domain is not yet created.
*/
- if (!entry->ns->profile_ptr[entry->profile])
+ if (tomoyo_policy_loaded &&
+ !entry->ns->profile_ptr[entry->profile])
return NULL;
}
return entry;
@@ -557,12 +572,99 @@ out:
tomoyo_write_log(&r, "use_profile %u\n",
entry->profile);
tomoyo_write_log(&r, "use_group %u\n", entry->group);
+ tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES);
}
}
return entry;
}
/**
+ * tomoyo_environ - Check permission for environment variable names.
+ *
+ * @ee: Pointer to "struct tomoyo_execve".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_environ(struct tomoyo_execve *ee)
+{
+ struct tomoyo_request_info *r = &ee->r;
+ struct linux_binprm *bprm = ee->bprm;
+ /* env_page.data is allocated by tomoyo_dump_page(). */
+ struct tomoyo_page_dump env_page = { };
+ char *arg_ptr; /* Size is TOMOYO_EXEC_TMPSIZE bytes */
+ int arg_len = 0;
+ unsigned long pos = bprm->p;
+ int offset = pos % PAGE_SIZE;
+ int argv_count = bprm->argc;
+ int envp_count = bprm->envc;
+ int error = -ENOMEM;
+
+ ee->r.type = TOMOYO_MAC_ENVIRON;
+ ee->r.profile = r->domain->profile;
+ ee->r.mode = tomoyo_get_mode(r->domain->ns, ee->r.profile,
+ TOMOYO_MAC_ENVIRON);
+ if (!r->mode || !envp_count)
+ return 0;
+ arg_ptr = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
+ if (!arg_ptr)
+ goto out;
+ while (error == -ENOMEM) {
+ if (!tomoyo_dump_page(bprm, pos, &env_page))
+ goto out;
+ pos += PAGE_SIZE - offset;
+ /* Read. */
+ while (argv_count && offset < PAGE_SIZE) {
+ if (!env_page.data[offset++])
+ argv_count--;
+ }
+ if (argv_count) {
+ offset = 0;
+ continue;
+ }
+ while (offset < PAGE_SIZE) {
+ const unsigned char c = env_page.data[offset++];
+
+ if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) {
+ if (c == '=') {
+ arg_ptr[arg_len++] = '\0';
+ } else if (c == '\\') {
+ arg_ptr[arg_len++] = '\\';
+ arg_ptr[arg_len++] = '\\';
+ } else if (c > ' ' && c < 127) {
+ arg_ptr[arg_len++] = c;
+ } else {
+ arg_ptr[arg_len++] = '\\';
+ arg_ptr[arg_len++] = (c >> 6) + '0';
+ arg_ptr[arg_len++]
+ = ((c >> 3) & 7) + '0';
+ arg_ptr[arg_len++] = (c & 7) + '0';
+ }
+ } else {
+ arg_ptr[arg_len] = '\0';
+ }
+ if (c)
+ continue;
+ if (tomoyo_env_perm(r, arg_ptr)) {
+ error = -EPERM;
+ break;
+ }
+ if (!--envp_count) {
+ error = 0;
+ break;
+ }
+ arg_len = 0;
+ }
+ offset = 0;
+ }
+out:
+ if (r->mode != TOMOYO_CONFIG_ENFORCING)
+ error = 0;
+ kfree(env_page.data);
+ kfree(arg_ptr);
+ return error;
+}
+
+/**
* tomoyo_find_next_domain - Find a domain.
*
* @bprm: Pointer to "struct linux_binprm".
@@ -577,10 +679,11 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
struct tomoyo_domain_info *domain = NULL;
const char *original_name = bprm->filename;
int retval = -ENOMEM;
- bool need_kfree = false;
bool reject_on_transition_failure = false;
- struct tomoyo_path_info rn = { }; /* real name */
+ const struct tomoyo_path_info *candidate;
+ struct tomoyo_path_info exename;
struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS);
+
if (!ee)
return -ENOMEM;
ee->tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
@@ -594,40 +697,32 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
ee->bprm = bprm;
ee->r.obj = &ee->obj;
ee->obj.path1 = bprm->file->f_path;
- retry:
- if (need_kfree) {
- kfree(rn.name);
- need_kfree = false;
- }
/* Get symlink's pathname of program. */
retval = -ENOENT;
- rn.name = tomoyo_realpath_nofollow(original_name);
- if (!rn.name)
+ exename.name = tomoyo_realpath_nofollow(original_name);
+ if (!exename.name)
goto out;
- tomoyo_fill_path_info(&rn);
- need_kfree = true;
-
+ tomoyo_fill_path_info(&exename);
+retry:
/* Check 'aggregator' directive. */
{
struct tomoyo_aggregator *ptr;
struct list_head *list =
&old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR];
/* Check 'aggregator' directive. */
+ candidate = &exename;
list_for_each_entry_rcu(ptr, list, head.list) {
if (ptr->head.is_deleted ||
- !tomoyo_path_matches_pattern(&rn,
+ !tomoyo_path_matches_pattern(&exename,
ptr->original_name))
continue;
- kfree(rn.name);
- need_kfree = false;
- /* This is OK because it is read only. */
- rn = *ptr->aggregated_name;
+ candidate = ptr->aggregated_name;
break;
}
}
/* Check execute permission. */
- retval = tomoyo_path_permission(&ee->r, TOMOYO_TYPE_EXECUTE, &rn);
+ retval = tomoyo_execute_permission(&ee->r, candidate);
if (retval == TOMOYO_RETRY_REQUEST)
goto retry;
if (retval < 0)
@@ -638,20 +733,51 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
* wildcard) rather than the pathname passed to execve()
* (which never contains wildcard).
*/
- if (ee->r.param.path.matched_path) {
- if (need_kfree)
- kfree(rn.name);
- need_kfree = false;
- /* This is OK because it is read only. */
- rn = *ee->r.param.path.matched_path;
- }
+ if (ee->r.param.path.matched_path)
+ candidate = ee->r.param.path.matched_path;
- /* Calculate domain to transit to. */
+ /*
+ * Check for domain transition preference if "file execute" matched.
+ * If preference is given, make do_execve() fail if domain transition
+ * has failed, for domain transition preference should be used with
+ * destination domain defined.
+ */
+ if (ee->transition) {
+ const char *domainname = ee->transition->name;
+ reject_on_transition_failure = true;
+ if (!strcmp(domainname, "keep"))
+ goto force_keep_domain;
+ if (!strcmp(domainname, "child"))
+ goto force_child_domain;
+ if (!strcmp(domainname, "reset"))
+ goto force_reset_domain;
+ if (!strcmp(domainname, "initialize"))
+ goto force_initialize_domain;
+ if (!strcmp(domainname, "parent")) {
+ char *cp;
+ strncpy(ee->tmp, old_domain->domainname->name,
+ TOMOYO_EXEC_TMPSIZE - 1);
+ cp = strrchr(ee->tmp, ' ');
+ if (cp)
+ *cp = '\0';
+ } else if (*domainname == '<')
+ strncpy(ee->tmp, domainname, TOMOYO_EXEC_TMPSIZE - 1);
+ else
+ snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
+ old_domain->domainname->name, domainname);
+ goto force_jump_domain;
+ }
+ /*
+ * No domain transition preference specified.
+ * Calculate domain to transit to.
+ */
switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname,
- &rn)) {
+ candidate)) {
case TOMOYO_TRANSITION_CONTROL_RESET:
+force_reset_domain:
/* Transit to the root of specified namespace. */
- snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", rn.name);
+ snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>",
+ candidate->name);
/*
* Make do_execve() fail if domain transition across namespaces
* has failed.
@@ -659,11 +785,13 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
reject_on_transition_failure = true;
break;
case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
+force_initialize_domain:
/* Transit to the child of current namespace's root. */
snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
- old_domain->ns->name, rn.name);
+ old_domain->ns->name, candidate->name);
break;
case TOMOYO_TRANSITION_CONTROL_KEEP:
+force_keep_domain:
/* Keep current domain. */
domain = old_domain;
break;
@@ -677,13 +805,15 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
* before /sbin/init.
*/
domain = old_domain;
- } else {
- /* Normal domain transition. */
- snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
- old_domain->domainname->name, rn.name);
+ break;
}
+force_child_domain:
+ /* Normal domain transition. */
+ snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
+ old_domain->domainname->name, candidate->name);
break;
}
+force_jump_domain:
if (!domain)
domain = tomoyo_assign_domain(ee->tmp, true);
if (domain)
@@ -711,8 +841,11 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
/* Update reference count on "struct tomoyo_domain_info". */
atomic_inc(&domain->users);
bprm->cred->security = domain;
- if (need_kfree)
- kfree(rn.name);
+ kfree(exename.name);
+ if (!retval) {
+ ee->r.domain = domain;
+ retval = tomoyo_environ(ee);
+ }
kfree(ee->tmp);
kfree(ee->dump.data);
kfree(ee);
@@ -732,7 +865,8 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
struct tomoyo_page_dump *dump)
{
struct page *page;
- /* dump->data is released by tomoyo_finish_execve(). */
+
+ /* dump->data is released by tomoyo_find_next_domain(). */
if (!dump->data) {
dump->data = kzalloc(PAGE_SIZE, GFP_NOFS);
if (!dump->data)
@@ -753,6 +887,7 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
* So do I.
*/
char *kaddr = kmap_atomic(page, KM_USER0);
+
dump->page = page;
memcpy(dump->data + offset, kaddr + offset,
PAGE_SIZE - offset);
diff --git a/security/tomoyo/environ.c b/security/tomoyo/environ.c
new file mode 100644
index 000000000000..ad4c6e18a437
--- /dev/null
+++ b/security/tomoyo/environ.c
@@ -0,0 +1,122 @@
+/*
+ * security/tomoyo/environ.c
+ *
+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
+ */
+
+#include "common.h"
+
+/**
+ * tomoyo_check_env_acl - Check permission for environment variable's name.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ * @ptr: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if granted, false otherwise.
+ */
+static bool tomoyo_check_env_acl(struct tomoyo_request_info *r,
+ const struct tomoyo_acl_info *ptr)
+{
+ const struct tomoyo_env_acl *acl =
+ container_of(ptr, typeof(*acl), head);
+
+ return tomoyo_path_matches_pattern(r->param.environ.name, acl->env);
+}
+
+/**
+ * tomoyo_audit_env_log - Audit environment variable name log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_env_log(struct tomoyo_request_info *r)
+{
+ return tomoyo_supervisor(r, "misc env %s\n",
+ r->param.environ.name->name);
+}
+
+/**
+ * tomoyo_env_perm - Check permission for environment variable's name.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ * @env: The name of environment variable.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+int tomoyo_env_perm(struct tomoyo_request_info *r, const char *env)
+{
+ struct tomoyo_path_info environ;
+ int error;
+
+ if (!env || !*env)
+ return 0;
+ environ.name = env;
+ tomoyo_fill_path_info(&environ);
+ r->param_type = TOMOYO_TYPE_ENV_ACL;
+ r->param.environ.name = &environ;
+ do {
+ tomoyo_check_acl(r, tomoyo_check_env_acl);
+ error = tomoyo_audit_env_log(r);
+ } while (error == TOMOYO_RETRY_REQUEST);
+ return error;
+}
+
+/**
+ * tomoyo_same_env_acl - Check for duplicated "struct tomoyo_env_acl" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_info".
+ * @b: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static bool tomoyo_same_env_acl(const struct tomoyo_acl_info *a,
+ const struct tomoyo_acl_info *b)
+{
+ const struct tomoyo_env_acl *p1 = container_of(a, typeof(*p1), head);
+ const struct tomoyo_env_acl *p2 = container_of(b, typeof(*p2), head);
+
+ return p1->env == p2->env;
+}
+
+/**
+ * tomoyo_write_env - Write "struct tomoyo_env_acl" list.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_write_env(struct tomoyo_acl_param *param)
+{
+ struct tomoyo_env_acl e = { .head.type = TOMOYO_TYPE_ENV_ACL };
+ int error = -ENOMEM;
+ const char *data = tomoyo_read_token(param);
+
+ if (!tomoyo_correct_word(data) || strchr(data, '='))
+ return -EINVAL;
+ e.env = tomoyo_get_name(data);
+ if (!e.env)
+ return error;
+ error = tomoyo_update_domain(&e.head, sizeof(e), param,
+ tomoyo_same_env_acl, NULL);
+ tomoyo_put_name(e.env);
+ return error;
+}
+
+/**
+ * tomoyo_write_misc - Update environment variable list.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_write_misc(struct tomoyo_acl_param *param)
+{
+ if (tomoyo_str_starts(&param->data, "env "))
+ return tomoyo_write_env(param);
+ return -EINVAL;
+}
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c
index 743c35f5084a..400390790745 100644
--- a/security/tomoyo/file.c
+++ b/security/tomoyo/file.c
@@ -555,8 +555,8 @@ static int tomoyo_update_path2_acl(const u8 perm,
*
* Caller holds tomoyo_read_lock().
*/
-int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
- const struct tomoyo_path_info *filename)
+static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
+ const struct tomoyo_path_info *filename)
{
int error;
@@ -570,16 +570,42 @@ int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
do {
tomoyo_check_acl(r, tomoyo_check_path_acl);
error = tomoyo_audit_path_log(r);
- /*
- * Do not retry for execute request, for alias may have
- * changed.
- */
- } while (error == TOMOYO_RETRY_REQUEST &&
- operation != TOMOYO_TYPE_EXECUTE);
+ } while (error == TOMOYO_RETRY_REQUEST);
return error;
}
/**
+ * tomoyo_execute_permission - Check permission for execute operation.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ * @filename: Filename to check.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+int tomoyo_execute_permission(struct tomoyo_request_info *r,
+ const struct tomoyo_path_info *filename)
+{
+ /*
+ * Unlike other permission checks, this check is done regardless of
+ * profile mode settings in order to check for domain transition
+ * preference.
+ */
+ r->type = TOMOYO_MAC_FILE_EXECUTE;
+ r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type);
+ r->param_type = TOMOYO_TYPE_PATH_ACL;
+ r->param.path.filename = filename;
+ r->param.path.operation = TOMOYO_TYPE_EXECUTE;
+ tomoyo_check_acl(r, tomoyo_check_path_acl);
+ r->ee->transition = r->matched_acl && r->matched_acl->cond ?
+ r->matched_acl->cond->transit : NULL;
+ if (r->mode != TOMOYO_CONFIG_DISABLED)
+ return tomoyo_audit_path_log(r);
+ return 0;
+}
+
+/**
* tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry.
*
* @a: Pointer to "struct tomoyo_acl_info".
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c
index ae135fbbbe95..986a6a756868 100644
--- a/security/tomoyo/gc.c
+++ b/security/tomoyo/gc.c
@@ -8,36 +8,26 @@
#include <linux/kthread.h>
#include <linux/slab.h>
+/**
+ * tomoyo_memory_free - Free memory for elements.
+ *
+ * @ptr: Pointer to allocated memory.
+ *
+ * Returns nothing.
+ *
+ * Caller holds tomoyo_policy_lock mutex.
+ */
+static inline void tomoyo_memory_free(void *ptr)
+{
+ tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= ksize(ptr);
+ kfree(ptr);
+}
+
/* The list for "struct tomoyo_io_buffer". */
static LIST_HEAD(tomoyo_io_buffer_list);
/* Lock for protecting tomoyo_io_buffer_list. */
static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock);
-/* Size of an element. */
-static const u8 tomoyo_element_size[TOMOYO_MAX_POLICY] = {
- [TOMOYO_ID_GROUP] = sizeof(struct tomoyo_group),
- [TOMOYO_ID_PATH_GROUP] = sizeof(struct tomoyo_path_group),
- [TOMOYO_ID_NUMBER_GROUP] = sizeof(struct tomoyo_number_group),
- [TOMOYO_ID_AGGREGATOR] = sizeof(struct tomoyo_aggregator),
- [TOMOYO_ID_TRANSITION_CONTROL] =
- sizeof(struct tomoyo_transition_control),
- [TOMOYO_ID_MANAGER] = sizeof(struct tomoyo_manager),
- /* [TOMOYO_ID_CONDITION] = "struct tomoyo_condition"->size, */
- /* [TOMOYO_ID_NAME] = "struct tomoyo_name"->size, */
- /* [TOMOYO_ID_ACL] =
- tomoyo_acl_size["struct tomoyo_acl_info"->type], */
- [TOMOYO_ID_DOMAIN] = sizeof(struct tomoyo_domain_info),
-};
-
-/* Size of a domain ACL element. */
-static const u8 tomoyo_acl_size[] = {
- [TOMOYO_TYPE_PATH_ACL] = sizeof(struct tomoyo_path_acl),
- [TOMOYO_TYPE_PATH2_ACL] = sizeof(struct tomoyo_path2_acl),
- [TOMOYO_TYPE_PATH_NUMBER_ACL] = sizeof(struct tomoyo_path_number_acl),
- [TOMOYO_TYPE_MKDEV_ACL] = sizeof(struct tomoyo_mkdev_acl),
- [TOMOYO_TYPE_MOUNT_ACL] = sizeof(struct tomoyo_mount_acl),
-};
-
/**
* tomoyo_struct_used_by_io_buffer - Check whether the list element is used by /sys/kernel/security/tomoyo/ users or not.
*
@@ -55,15 +45,11 @@ static bool tomoyo_struct_used_by_io_buffer(const struct list_head *element)
list_for_each_entry(head, &tomoyo_io_buffer_list, list) {
head->users++;
spin_unlock(&tomoyo_io_buffer_list_lock);
- if (mutex_lock_interruptible(&head->io_sem)) {
- in_use = true;
- goto out;
- }
+ mutex_lock(&head->io_sem);
if (head->r.domain == element || head->r.group == element ||
head->r.acl == element || &head->w.domain->list == element)
in_use = true;
mutex_unlock(&head->io_sem);
-out:
spin_lock(&tomoyo_io_buffer_list_lock);
head->users--;
if (in_use)
@@ -77,15 +63,14 @@ out:
* tomoyo_name_used_by_io_buffer - Check whether the string is used by /sys/kernel/security/tomoyo/ users or not.
*
* @string: String to check.
- * @size: Memory allocated for @string .
*
* Returns true if @string is used by /sys/kernel/security/tomoyo/ users,
* false otherwise.
*/
-static bool tomoyo_name_used_by_io_buffer(const char *string,
- const size_t size)
+static bool tomoyo_name_used_by_io_buffer(const char *string)
{
struct tomoyo_io_buffer *head;
+ const size_t size = strlen(string) + 1;
bool in_use = false;
spin_lock(&tomoyo_io_buffer_list_lock);
@@ -93,10 +78,7 @@ static bool tomoyo_name_used_by_io_buffer(const char *string,
int i;
head->users++;
spin_unlock(&tomoyo_io_buffer_list_lock);
- if (mutex_lock_interruptible(&head->io_sem)) {
- in_use = true;
- goto out;
- }
+ mutex_lock(&head->io_sem);
for (i = 0; i < TOMOYO_MAX_IO_READ_QUEUE; i++) {
const char *w = head->r.w[i];
if (w < string || w > string + size)
@@ -105,7 +87,6 @@ static bool tomoyo_name_used_by_io_buffer(const char *string,
break;
}
mutex_unlock(&head->io_sem);
-out:
spin_lock(&tomoyo_io_buffer_list_lock);
head->users--;
if (in_use)
@@ -115,84 +96,6 @@ out:
return in_use;
}
-/* Structure for garbage collection. */
-struct tomoyo_gc {
- struct list_head list;
- enum tomoyo_policy_id type;
- size_t size;
- struct list_head *element;
-};
-/* List of entries to be deleted. */
-static LIST_HEAD(tomoyo_gc_list);
-/* Length of tomoyo_gc_list. */
-static int tomoyo_gc_list_len;
-
-/**
- * tomoyo_add_to_gc - Add an entry to to be deleted list.
- *
- * @type: One of values in "enum tomoyo_policy_id".
- * @element: Pointer to "struct list_head".
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_policy_lock mutex.
- *
- * Adding an entry needs kmalloc(). Thus, if we try to add thousands of
- * entries at once, it will take too long time. Thus, do not add more than 128
- * entries per a scan. But to be able to handle worst case where all entries
- * are in-use, we accept one more entry per a scan.
- *
- * If we use singly linked list using "struct list_head"->prev (which is
- * LIST_POISON2), we can avoid kmalloc().
- */
-static bool tomoyo_add_to_gc(const int type, struct list_head *element)
-{
- struct tomoyo_gc *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
- if (!entry)
- return false;
- entry->type = type;
- if (type == TOMOYO_ID_ACL)
- entry->size = tomoyo_acl_size[
- container_of(element,
- typeof(struct tomoyo_acl_info),
- list)->type];
- else if (type == TOMOYO_ID_NAME)
- entry->size = strlen(container_of(element,
- typeof(struct tomoyo_name),
- head.list)->entry.name) + 1;
- else if (type == TOMOYO_ID_CONDITION)
- entry->size =
- container_of(element, typeof(struct tomoyo_condition),
- head.list)->size;
- else
- entry->size = tomoyo_element_size[type];
- entry->element = element;
- list_add(&entry->list, &tomoyo_gc_list);
- list_del_rcu(element);
- return tomoyo_gc_list_len++ < 128;
-}
-
-/**
- * tomoyo_element_linked_by_gc - Validate next element of an entry.
- *
- * @element: Pointer to an element.
- * @size: Size of @element in byte.
- *
- * Returns true if @element is linked by other elements in the garbage
- * collector's queue, false otherwise.
- */
-static bool tomoyo_element_linked_by_gc(const u8 *element, const size_t size)
-{
- struct tomoyo_gc *p;
- list_for_each_entry(p, &tomoyo_gc_list, list) {
- const u8 *ptr = (const u8 *) p->element->next;
- if (ptr < element || element + size < ptr)
- continue;
- return true;
- }
- return false;
-}
-
/**
* tomoyo_del_transition_control - Delete members in "struct tomoyo_transition_control".
*
@@ -200,7 +103,7 @@ static bool tomoyo_element_linked_by_gc(const u8 *element, const size_t size)
*
* Returns nothing.
*/
-static void tomoyo_del_transition_control(struct list_head *element)
+static inline void tomoyo_del_transition_control(struct list_head *element)
{
struct tomoyo_transition_control *ptr =
container_of(element, typeof(*ptr), head.list);
@@ -215,7 +118,7 @@ static void tomoyo_del_transition_control(struct list_head *element)
*
* Returns nothing.
*/
-static void tomoyo_del_aggregator(struct list_head *element)
+static inline void tomoyo_del_aggregator(struct list_head *element)
{
struct tomoyo_aggregator *ptr =
container_of(element, typeof(*ptr), head.list);
@@ -230,7 +133,7 @@ static void tomoyo_del_aggregator(struct list_head *element)
*
* Returns nothing.
*/
-static void tomoyo_del_manager(struct list_head *element)
+static inline void tomoyo_del_manager(struct list_head *element)
{
struct tomoyo_manager *ptr =
container_of(element, typeof(*ptr), head.list);
@@ -293,6 +196,38 @@ static void tomoyo_del_acl(struct list_head *element)
tomoyo_put_number_union(&entry->flags);
}
break;
+ case TOMOYO_TYPE_ENV_ACL:
+ {
+ struct tomoyo_env_acl *entry =
+ container_of(acl, typeof(*entry), head);
+
+ tomoyo_put_name(entry->env);
+ }
+ break;
+ case TOMOYO_TYPE_INET_ACL:
+ {
+ struct tomoyo_inet_acl *entry =
+ container_of(acl, typeof(*entry), head);
+
+ tomoyo_put_group(entry->address.group);
+ tomoyo_put_number_union(&entry->port);
+ }
+ break;
+ case TOMOYO_TYPE_UNIX_ACL:
+ {
+ struct tomoyo_unix_acl *entry =
+ container_of(acl, typeof(*entry), head);
+
+ tomoyo_put_name_union(&entry->name);
+ }
+ break;
+ case TOMOYO_TYPE_MANUAL_TASK_ACL:
+ {
+ struct tomoyo_task_acl *entry =
+ container_of(acl, typeof(*entry), head);
+ tomoyo_put_name(entry->domainname);
+ }
+ break;
}
}
@@ -301,44 +236,26 @@ static void tomoyo_del_acl(struct list_head *element)
*
* @element: Pointer to "struct list_head".
*
- * Returns true if deleted, false otherwise.
+ * Returns nothing.
+ *
+ * Caller holds tomoyo_policy_lock mutex.
*/
-static bool tomoyo_del_domain(struct list_head *element)
+static inline void tomoyo_del_domain(struct list_head *element)
{
struct tomoyo_domain_info *domain =
container_of(element, typeof(*domain), list);
struct tomoyo_acl_info *acl;
struct tomoyo_acl_info *tmp;
/*
- * Since we don't protect whole execve() operation using SRCU,
- * we need to recheck domain->users at this point.
- *
- * (1) Reader starts SRCU section upon execve().
- * (2) Reader traverses tomoyo_domain_list and finds this domain.
- * (3) Writer marks this domain as deleted.
- * (4) Garbage collector removes this domain from tomoyo_domain_list
- * because this domain is marked as deleted and used by nobody.
- * (5) Reader saves reference to this domain into
- * "struct linux_binprm"->cred->security .
- * (6) Reader finishes SRCU section, although execve() operation has
- * not finished yet.
- * (7) Garbage collector waits for SRCU synchronization.
- * (8) Garbage collector kfree() this domain because this domain is
- * used by nobody.
- * (9) Reader finishes execve() operation and restores this domain from
- * "struct linux_binprm"->cred->security.
- *
- * By updating domain->users at (5), we can solve this race problem
- * by rechecking domain->users at (8).
+ * Since this domain is referenced from neither
+ * "struct tomoyo_io_buffer" nor "struct cred"->security, we can delete
+ * elements without checking for is_deleted flag.
*/
- if (atomic_read(&domain->users))
- return false;
list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
tomoyo_del_acl(&acl->list);
tomoyo_memory_free(acl);
}
tomoyo_put_name(domain->domainname);
- return true;
}
/**
@@ -387,10 +304,9 @@ void tomoyo_del_condition(struct list_head *element)
*
* Returns nothing.
*/
-static void tomoyo_del_name(struct list_head *element)
+static inline void tomoyo_del_name(struct list_head *element)
{
- const struct tomoyo_name *ptr =
- container_of(element, typeof(*ptr), head.list);
+ /* Nothing to do. */
}
/**
@@ -400,7 +316,7 @@ static void tomoyo_del_name(struct list_head *element)
*
* Returns nothing.
*/
-static void tomoyo_del_path_group(struct list_head *element)
+static inline void tomoyo_del_path_group(struct list_head *element)
{
struct tomoyo_path_group *member =
container_of(element, typeof(*member), head.list);
@@ -414,7 +330,7 @@ static void tomoyo_del_path_group(struct list_head *element)
*
* Returns nothing.
*/
-static void tomoyo_del_group(struct list_head *element)
+static inline void tomoyo_del_group(struct list_head *element)
{
struct tomoyo_group *group =
container_of(element, typeof(*group), head.list);
@@ -422,16 +338,128 @@ static void tomoyo_del_group(struct list_head *element)
}
/**
+ * tomoyo_del_address_group - Delete members in "struct tomoyo_address_group".
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ */
+static inline void tomoyo_del_address_group(struct list_head *element)
+{
+ /* Nothing to do. */
+}
+
+/**
* tomoyo_del_number_group - Delete members in "struct tomoyo_number_group".
*
* @element: Pointer to "struct list_head".
*
* Returns nothing.
*/
-static void tomoyo_del_number_group(struct list_head *element)
+static inline void tomoyo_del_number_group(struct list_head *element)
{
- struct tomoyo_number_group *member =
- container_of(element, typeof(*member), head.list);
+ /* Nothing to do. */
+}
+
+/**
+ * tomoyo_try_to_gc - Try to kfree() an entry.
+ *
+ * @type: One of values in "enum tomoyo_policy_id".
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ *
+ * Caller holds tomoyo_policy_lock mutex.
+ */
+static void tomoyo_try_to_gc(const enum tomoyo_policy_id type,
+ struct list_head *element)
+{
+ /*
+ * __list_del_entry() guarantees that the list element became no longer
+ * reachable from the list which the element was originally on (e.g.
+ * tomoyo_domain_list). Also, synchronize_srcu() guarantees that the
+ * list element became no longer referenced by syscall users.
+ */
+ __list_del_entry(element);
+ mutex_unlock(&tomoyo_policy_lock);
+ synchronize_srcu(&tomoyo_ss);
+ /*
+ * However, there are two users which may still be using the list
+ * element. We need to defer until both users forget this element.
+ *
+ * Don't kfree() until "struct tomoyo_io_buffer"->r.{domain,group,acl}
+ * and "struct tomoyo_io_buffer"->w.domain forget this element.
+ */
+ if (tomoyo_struct_used_by_io_buffer(element))
+ goto reinject;
+ switch (type) {
+ case TOMOYO_ID_TRANSITION_CONTROL:
+ tomoyo_del_transition_control(element);
+ break;
+ case TOMOYO_ID_MANAGER:
+ tomoyo_del_manager(element);
+ break;
+ case TOMOYO_ID_AGGREGATOR:
+ tomoyo_del_aggregator(element);
+ break;
+ case TOMOYO_ID_GROUP:
+ tomoyo_del_group(element);
+ break;
+ case TOMOYO_ID_PATH_GROUP:
+ tomoyo_del_path_group(element);
+ break;
+ case TOMOYO_ID_ADDRESS_GROUP:
+ tomoyo_del_address_group(element);
+ break;
+ case TOMOYO_ID_NUMBER_GROUP:
+ tomoyo_del_number_group(element);
+ break;
+ case TOMOYO_ID_CONDITION:
+ tomoyo_del_condition(element);
+ break;
+ case TOMOYO_ID_NAME:
+ /*
+ * Don't kfree() until all "struct tomoyo_io_buffer"->r.w[]
+ * forget this element.
+ */
+ if (tomoyo_name_used_by_io_buffer
+ (container_of(element, typeof(struct tomoyo_name),
+ head.list)->entry.name))
+ goto reinject;
+ tomoyo_del_name(element);
+ break;
+ case TOMOYO_ID_ACL:
+ tomoyo_del_acl(element);
+ break;
+ case TOMOYO_ID_DOMAIN:
+ /*
+ * Don't kfree() until all "struct cred"->security forget this
+ * element.
+ */
+ if (atomic_read(&container_of
+ (element, typeof(struct tomoyo_domain_info),
+ list)->users))
+ goto reinject;
+ break;
+ case TOMOYO_MAX_POLICY:
+ break;
+ }
+ mutex_lock(&tomoyo_policy_lock);
+ if (type == TOMOYO_ID_DOMAIN)
+ tomoyo_del_domain(element);
+ tomoyo_memory_free(element);
+ return;
+reinject:
+ /*
+ * We can safely reinject this element here bacause
+ * (1) Appending list elements and removing list elements are protected
+ * by tomoyo_policy_lock mutex.
+ * (2) Only this function removes list elements and this function is
+ * exclusively executed by tomoyo_gc_mutex mutex.
+ * are true.
+ */
+ mutex_lock(&tomoyo_policy_lock);
+ list_add_rcu(element, element->prev);
}
/**
@@ -440,19 +468,19 @@ static void tomoyo_del_number_group(struct list_head *element)
* @id: One of values in "enum tomoyo_policy_id".
* @member_list: Pointer to "struct list_head".
*
- * Returns true if some elements are deleted, false otherwise.
+ * Returns nothing.
*/
-static bool tomoyo_collect_member(const enum tomoyo_policy_id id,
+static void tomoyo_collect_member(const enum tomoyo_policy_id id,
struct list_head *member_list)
{
struct tomoyo_acl_head *member;
- list_for_each_entry(member, member_list, list) {
+ struct tomoyo_acl_head *tmp;
+ list_for_each_entry_safe(member, tmp, member_list, list) {
if (!member->is_deleted)
continue;
- if (!tomoyo_add_to_gc(id, &member->list))
- return false;
+ member->is_deleted = TOMOYO_GC_IN_PROGRESS;
+ tomoyo_try_to_gc(id, &member->list);
}
- return true;
}
/**
@@ -460,22 +488,22 @@ static bool tomoyo_collect_member(const enum tomoyo_policy_id id,
*
* @list: Pointer to "struct list_head".
*
- * Returns true if some elements are deleted, false otherwise.
+ * Returns nothing.
*/
-static bool tomoyo_collect_acl(struct list_head *list)
+static void tomoyo_collect_acl(struct list_head *list)
{
struct tomoyo_acl_info *acl;
- list_for_each_entry(acl, list, list) {
+ struct tomoyo_acl_info *tmp;
+ list_for_each_entry_safe(acl, tmp, list, list) {
if (!acl->is_deleted)
continue;
- if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list))
- return false;
+ acl->is_deleted = TOMOYO_GC_IN_PROGRESS;
+ tomoyo_try_to_gc(TOMOYO_ID_ACL, &acl->list);
}
- return true;
}
/**
- * tomoyo_collect_entry - Scan lists for deleted elements.
+ * tomoyo_collect_entry - Try to kfree() deleted elements.
*
* Returns nothing.
*/
@@ -484,174 +512,82 @@ static void tomoyo_collect_entry(void)
int i;
enum tomoyo_policy_id id;
struct tomoyo_policy_namespace *ns;
- int idx;
- if (mutex_lock_interruptible(&tomoyo_policy_lock))
- return;
- idx = tomoyo_read_lock();
+ mutex_lock(&tomoyo_policy_lock);
{
struct tomoyo_domain_info *domain;
- list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
- if (!tomoyo_collect_acl(&domain->acl_info_list))
- goto unlock;
+ struct tomoyo_domain_info *tmp;
+ list_for_each_entry_safe(domain, tmp, &tomoyo_domain_list,
+ list) {
+ tomoyo_collect_acl(&domain->acl_info_list);
if (!domain->is_deleted || atomic_read(&domain->users))
continue;
- /*
- * Nobody is referring this domain. But somebody may
- * refer this domain after successful execve().
- * We recheck domain->users after SRCU synchronization.
- */
- if (!tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, &domain->list))
- goto unlock;
+ tomoyo_try_to_gc(TOMOYO_ID_DOMAIN, &domain->list);
}
}
- list_for_each_entry_rcu(ns, &tomoyo_namespace_list, namespace_list) {
+ list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) {
for (id = 0; id < TOMOYO_MAX_POLICY; id++)
- if (!tomoyo_collect_member(id, &ns->policy_list[id]))
- goto unlock;
+ tomoyo_collect_member(id, &ns->policy_list[id]);
for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++)
- if (!tomoyo_collect_acl(&ns->acl_group[i]))
- goto unlock;
+ tomoyo_collect_acl(&ns->acl_group[i]);
+ }
+ {
+ struct tomoyo_shared_acl_head *ptr;
+ struct tomoyo_shared_acl_head *tmp;
+ list_for_each_entry_safe(ptr, tmp, &tomoyo_condition_list,
+ list) {
+ if (atomic_read(&ptr->users) > 0)
+ continue;
+ atomic_set(&ptr->users, TOMOYO_GC_IN_PROGRESS);
+ tomoyo_try_to_gc(TOMOYO_ID_CONDITION, &ptr->list);
+ }
+ }
+ list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) {
for (i = 0; i < TOMOYO_MAX_GROUP; i++) {
struct list_head *list = &ns->group_list[i];
struct tomoyo_group *group;
+ struct tomoyo_group *tmp;
switch (i) {
case 0:
id = TOMOYO_ID_PATH_GROUP;
break;
- default:
+ case 1:
id = TOMOYO_ID_NUMBER_GROUP;
break;
+ default:
+ id = TOMOYO_ID_ADDRESS_GROUP;
+ break;
}
- list_for_each_entry(group, list, head.list) {
- if (!tomoyo_collect_member
- (id, &group->member_list))
- goto unlock;
+ list_for_each_entry_safe(group, tmp, list, head.list) {
+ tomoyo_collect_member(id, &group->member_list);
if (!list_empty(&group->member_list) ||
- atomic_read(&group->head.users))
+ atomic_read(&group->head.users) > 0)
continue;
- if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP,
- &group->head.list))
- goto unlock;
+ atomic_set(&group->head.users,
+ TOMOYO_GC_IN_PROGRESS);
+ tomoyo_try_to_gc(TOMOYO_ID_GROUP,
+ &group->head.list);
}
}
}
- id = TOMOYO_ID_CONDITION;
- for (i = 0; i < TOMOYO_MAX_HASH + 1; i++) {
- struct list_head *list = !i ?
- &tomoyo_condition_list : &tomoyo_name_list[i - 1];
+ for (i = 0; i < TOMOYO_MAX_HASH; i++) {
+ struct list_head *list = &tomoyo_name_list[i];
struct tomoyo_shared_acl_head *ptr;
- list_for_each_entry(ptr, list, list) {
- if (atomic_read(&ptr->users))
+ struct tomoyo_shared_acl_head *tmp;
+ list_for_each_entry_safe(ptr, tmp, list, list) {
+ if (atomic_read(&ptr->users) > 0)
continue;
- if (!tomoyo_add_to_gc(id, &ptr->list))
- goto unlock;
+ atomic_set(&ptr->users, TOMOYO_GC_IN_PROGRESS);
+ tomoyo_try_to_gc(TOMOYO_ID_NAME, &ptr->list);
}
- id = TOMOYO_ID_NAME;
}
-unlock:
- tomoyo_read_unlock(idx);
mutex_unlock(&tomoyo_policy_lock);
}
/**
- * tomoyo_kfree_entry - Delete entries in tomoyo_gc_list.
- *
- * Returns true if some entries were kfree()d, false otherwise.
- */
-static bool tomoyo_kfree_entry(void)
-{
- struct tomoyo_gc *p;
- struct tomoyo_gc *tmp;
- bool result = false;
-
- list_for_each_entry_safe(p, tmp, &tomoyo_gc_list, list) {
- struct list_head *element = p->element;
-
- /*
- * list_del_rcu() in tomoyo_add_to_gc() guarantees that the
- * list element became no longer reachable from the list which
- * the element was originally on (e.g. tomoyo_domain_list).
- * Also, synchronize_srcu() in tomoyo_gc_thread() guarantees
- * that the list element became no longer referenced by syscall
- * users.
- *
- * However, there are three users which may still be using the
- * list element. We need to defer until all of these users
- * forget the list element.
- *
- * Firstly, defer until "struct tomoyo_io_buffer"->r.{domain,
- * group,acl} and "struct tomoyo_io_buffer"->w.domain forget
- * the list element.
- */
- if (tomoyo_struct_used_by_io_buffer(element))
- continue;
- /*
- * Secondly, defer until all other elements in the
- * tomoyo_gc_list list forget the list element.
- */
- if (tomoyo_element_linked_by_gc((const u8 *) element, p->size))
- continue;
- switch (p->type) {
- case TOMOYO_ID_TRANSITION_CONTROL:
- tomoyo_del_transition_control(element);
- break;
- case TOMOYO_ID_AGGREGATOR:
- tomoyo_del_aggregator(element);
- break;
- case TOMOYO_ID_MANAGER:
- tomoyo_del_manager(element);
- break;
- case TOMOYO_ID_CONDITION:
- tomoyo_del_condition(element);
- break;
- case TOMOYO_ID_NAME:
- /*
- * Thirdly, defer until all "struct tomoyo_io_buffer"
- * ->r.w[] forget the list element.
- */
- if (tomoyo_name_used_by_io_buffer(
- container_of(element, typeof(struct tomoyo_name),
- head.list)->entry.name, p->size))
- continue;
- tomoyo_del_name(element);
- break;
- case TOMOYO_ID_ACL:
- tomoyo_del_acl(element);
- break;
- case TOMOYO_ID_DOMAIN:
- if (!tomoyo_del_domain(element))
- continue;
- break;
- case TOMOYO_ID_PATH_GROUP:
- tomoyo_del_path_group(element);
- break;
- case TOMOYO_ID_GROUP:
- tomoyo_del_group(element);
- break;
- case TOMOYO_ID_NUMBER_GROUP:
- tomoyo_del_number_group(element);
- break;
- case TOMOYO_MAX_POLICY:
- break;
- }
- tomoyo_memory_free(element);
- list_del(&p->list);
- kfree(p);
- tomoyo_gc_list_len--;
- result = true;
- }
- return result;
-}
-
-/**
* tomoyo_gc_thread - Garbage collector thread function.
*
* @unused: Unused.
*
- * In case OOM-killer choose this thread for termination, we create this thread
- * as a short live thread whenever /sys/kernel/security/tomoyo/ interface was
- * close()d.
- *
* Returns 0.
*/
static int tomoyo_gc_thread(void *unused)
@@ -660,13 +596,7 @@ static int tomoyo_gc_thread(void *unused)
static DEFINE_MUTEX(tomoyo_gc_mutex);
if (!mutex_trylock(&tomoyo_gc_mutex))
goto out;
- daemonize("GC for TOMOYO");
- do {
- tomoyo_collect_entry();
- if (list_empty(&tomoyo_gc_list))
- break;
- synchronize_srcu(&tomoyo_ss);
- } while (tomoyo_kfree_entry());
+ tomoyo_collect_entry();
{
struct tomoyo_io_buffer *head;
struct tomoyo_io_buffer *tmp;
diff --git a/security/tomoyo/group.c b/security/tomoyo/group.c
index 5fb0e1298400..50092534ec54 100644
--- a/security/tomoyo/group.c
+++ b/security/tomoyo/group.c
@@ -42,7 +42,26 @@ static bool tomoyo_same_number_group(const struct tomoyo_acl_head *a,
}
/**
- * tomoyo_write_group - Write "struct tomoyo_path_group"/"struct tomoyo_number_group" list.
+ * tomoyo_same_address_group - Check for duplicated "struct tomoyo_address_group" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_head".
+ * @b: Pointer to "struct tomoyo_acl_head".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static bool tomoyo_same_address_group(const struct tomoyo_acl_head *a,
+ const struct tomoyo_acl_head *b)
+{
+ const struct tomoyo_address_group *p1 = container_of(a, typeof(*p1),
+ head);
+ const struct tomoyo_address_group *p2 = container_of(b, typeof(*p2),
+ head);
+
+ return tomoyo_same_ipaddr_union(&p1->address, &p2->address);
+}
+
+/**
+ * tomoyo_write_group - Write "struct tomoyo_path_group"/"struct tomoyo_number_group"/"struct tomoyo_address_group" list.
*
* @param: Pointer to "struct tomoyo_acl_param".
* @type: Type of this group.
@@ -77,6 +96,14 @@ int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type)
* tomoyo_put_number_union() is not needed because
* param->data[0] != '@'.
*/
+ } else {
+ struct tomoyo_address_group e = { };
+
+ if (param->data[0] == '@' ||
+ !tomoyo_parse_ipaddr_union(param, &e.address))
+ goto out;
+ error = tomoyo_update_policy(&e.head, sizeof(e), param,
+ tomoyo_same_address_group);
}
out:
tomoyo_put_group(group);
@@ -137,3 +164,35 @@ bool tomoyo_number_matches_group(const unsigned long min,
}
return matched;
}
+
+/**
+ * tomoyo_address_matches_group - Check whether the given address matches members of the given address group.
+ *
+ * @is_ipv6: True if @address is an IPv6 address.
+ * @address: An IPv4 or IPv6 address.
+ * @group: Pointer to "struct tomoyo_address_group".
+ *
+ * Returns true if @address matches addresses in @group group, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+bool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *address,
+ const struct tomoyo_group *group)
+{
+ struct tomoyo_address_group *member;
+ bool matched = false;
+ const u8 size = is_ipv6 ? 16 : 4;
+
+ list_for_each_entry_rcu(member, &group->member_list, head.list) {
+ if (member->head.is_deleted)
+ continue;
+ if (member->address.is_ipv6 != is_ipv6)
+ continue;
+ if (memcmp(&member->address.ip[0], address, size) > 0 ||
+ memcmp(address, &member->address.ip[1], size) > 0)
+ continue;
+ matched = true;
+ break;
+ }
+ return matched;
+}
diff --git a/security/tomoyo/memory.c b/security/tomoyo/memory.c
index 7a56051146c2..0e995716cc25 100644
--- a/security/tomoyo/memory.c
+++ b/security/tomoyo/memory.c
@@ -27,8 +27,6 @@ void tomoyo_warn_oom(const char *function)
panic("MAC Initialization failed.\n");
}
-/* Lock for protecting tomoyo_memory_used. */
-static DEFINE_SPINLOCK(tomoyo_policy_memory_lock);
/* Memoy currently used by policy/audit log/query. */
unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT];
/* Memory quota for "policy"/"audit log"/"query". */
@@ -42,22 +40,19 @@ unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT];
* Returns true on success, false otherwise.
*
* Returns true if @ptr is not NULL and quota not exceeded, false otherwise.
+ *
+ * Caller holds tomoyo_policy_lock mutex.
*/
bool tomoyo_memory_ok(void *ptr)
{
if (ptr) {
const size_t s = ksize(ptr);
- bool result;
- spin_lock(&tomoyo_policy_memory_lock);
tomoyo_memory_used[TOMOYO_MEMORY_POLICY] += s;
- result = !tomoyo_memory_quota[TOMOYO_MEMORY_POLICY] ||
- tomoyo_memory_used[TOMOYO_MEMORY_POLICY] <=
- tomoyo_memory_quota[TOMOYO_MEMORY_POLICY];
- if (!result)
- tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s;
- spin_unlock(&tomoyo_policy_memory_lock);
- if (result)
+ if (!tomoyo_memory_quota[TOMOYO_MEMORY_POLICY] ||
+ tomoyo_memory_used[TOMOYO_MEMORY_POLICY] <=
+ tomoyo_memory_quota[TOMOYO_MEMORY_POLICY])
return true;
+ tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s;
}
tomoyo_warn_oom(__func__);
return false;
@@ -71,6 +66,8 @@ bool tomoyo_memory_ok(void *ptr)
*
* Returns pointer to allocated memory on success, NULL otherwise.
* @data is zero-cleared on success.
+ *
+ * Caller holds tomoyo_policy_lock mutex.
*/
void *tomoyo_commit_ok(void *data, const unsigned int size)
{
@@ -85,20 +82,6 @@ void *tomoyo_commit_ok(void *data, const unsigned int size)
}
/**
- * tomoyo_memory_free - Free memory for elements.
- *
- * @ptr: Pointer to allocated memory.
- */
-void tomoyo_memory_free(void *ptr)
-{
- size_t s = ksize(ptr);
- spin_lock(&tomoyo_policy_memory_lock);
- tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s;
- spin_unlock(&tomoyo_policy_memory_lock);
- kfree(ptr);
-}
-
-/**
* tomoyo_get_group - Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group".
*
* @param: Pointer to "struct tomoyo_acl_param".
@@ -123,7 +106,8 @@ struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param,
goto out;
list = &param->ns->group_list[idx];
list_for_each_entry(group, list, head.list) {
- if (e.group_name != group->group_name)
+ if (e.group_name != group->group_name ||
+ atomic_read(&group->head.users) == TOMOYO_GC_IN_PROGRESS)
continue;
atomic_inc(&group->head.users);
found = true;
@@ -175,7 +159,8 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name)
if (mutex_lock_interruptible(&tomoyo_policy_lock))
return NULL;
list_for_each_entry(ptr, head, head.list) {
- if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
+ if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name) ||
+ atomic_read(&ptr->head.users) == TOMOYO_GC_IN_PROGRESS)
continue;
atomic_inc(&ptr->head.users);
goto out;
diff --git a/security/tomoyo/network.c b/security/tomoyo/network.c
new file mode 100644
index 000000000000..97527710a72a
--- /dev/null
+++ b/security/tomoyo/network.c
@@ -0,0 +1,771 @@
+/*
+ * security/tomoyo/network.c
+ *
+ * Copyright (C) 2005-2011 NTT DATA CORPORATION
+ */
+
+#include "common.h"
+#include <linux/slab.h>
+
+/* Structure for holding inet domain socket's address. */
+struct tomoyo_inet_addr_info {
+ __be16 port; /* In network byte order. */
+ const __be32 *address; /* In network byte order. */
+ bool is_ipv6;
+};
+
+/* Structure for holding unix domain socket's address. */
+struct tomoyo_unix_addr_info {
+ u8 *addr; /* This may not be '\0' terminated string. */
+ unsigned int addr_len;
+};
+
+/* Structure for holding socket address. */
+struct tomoyo_addr_info {
+ u8 protocol;
+ u8 operation;
+ struct tomoyo_inet_addr_info inet;
+ struct tomoyo_unix_addr_info unix0;
+};
+
+/* String table for socket's protocols. */
+const char * const tomoyo_proto_keyword[TOMOYO_SOCK_MAX] = {
+ [SOCK_STREAM] = "stream",
+ [SOCK_DGRAM] = "dgram",
+ [SOCK_RAW] = "raw",
+ [SOCK_SEQPACKET] = "seqpacket",
+ [0] = " ", /* Dummy for avoiding NULL pointer dereference. */
+ [4] = " ", /* Dummy for avoiding NULL pointer dereference. */
+};
+
+/**
+ * tomoyo_parse_ipaddr_union - Parse an IP address.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ * @ptr: Pointer to "struct tomoyo_ipaddr_union".
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_parse_ipaddr_union(struct tomoyo_acl_param *param,
+ struct tomoyo_ipaddr_union *ptr)
+{
+ u8 * const min = ptr->ip[0].in6_u.u6_addr8;
+ u8 * const max = ptr->ip[1].in6_u.u6_addr8;
+ char *address = tomoyo_read_token(param);
+ const char *end;
+
+ if (!strchr(address, ':') &&
+ in4_pton(address, -1, min, '-', &end) > 0) {
+ ptr->is_ipv6 = false;
+ if (!*end)
+ ptr->ip[1].s6_addr32[0] = ptr->ip[0].s6_addr32[0];
+ else if (*end++ != '-' ||
+ in4_pton(end, -1, max, '\0', &end) <= 0 || *end)
+ return false;
+ return true;
+ }
+ if (in6_pton(address, -1, min, '-', &end) > 0) {
+ ptr->is_ipv6 = true;
+ if (!*end)
+ memmove(max, min, sizeof(u16) * 8);
+ else if (*end++ != '-' ||
+ in6_pton(end, -1, max, '\0', &end) <= 0 || *end)
+ return false;
+ return true;
+ }
+ return false;
+}
+
+/**
+ * tomoyo_print_ipv4 - Print an IPv4 address.
+ *
+ * @buffer: Buffer to write to.
+ * @buffer_len: Size of @buffer.
+ * @min_ip: Pointer to __be32.
+ * @max_ip: Pointer to __be32.
+ *
+ * Returns nothing.
+ */
+static void tomoyo_print_ipv4(char *buffer, const unsigned int buffer_len,
+ const __be32 *min_ip, const __be32 *max_ip)
+{
+ snprintf(buffer, buffer_len, "%pI4%c%pI4", min_ip,
+ *min_ip == *max_ip ? '\0' : '-', max_ip);
+}
+
+/**
+ * tomoyo_print_ipv6 - Print an IPv6 address.
+ *
+ * @buffer: Buffer to write to.
+ * @buffer_len: Size of @buffer.
+ * @min_ip: Pointer to "struct in6_addr".
+ * @max_ip: Pointer to "struct in6_addr".
+ *
+ * Returns nothing.
+ */
+static void tomoyo_print_ipv6(char *buffer, const unsigned int buffer_len,
+ const struct in6_addr *min_ip,
+ const struct in6_addr *max_ip)
+{
+ snprintf(buffer, buffer_len, "%pI6c%c%pI6c", min_ip,
+ !memcmp(min_ip, max_ip, 16) ? '\0' : '-', max_ip);
+}
+
+/**
+ * tomoyo_print_ip - Print an IP address.
+ *
+ * @buf: Buffer to write to.
+ * @size: Size of @buf.
+ * @ptr: Pointer to "struct ipaddr_union".
+ *
+ * Returns nothing.
+ */
+void tomoyo_print_ip(char *buf, const unsigned int size,
+ const struct tomoyo_ipaddr_union *ptr)
+{
+ if (ptr->is_ipv6)
+ tomoyo_print_ipv6(buf, size, &ptr->ip[0], &ptr->ip[1]);
+ else
+ tomoyo_print_ipv4(buf, size, &ptr->ip[0].s6_addr32[0],
+ &ptr->ip[1].s6_addr32[0]);
+}
+
+/*
+ * Mapping table from "enum tomoyo_network_acl_index" to
+ * "enum tomoyo_mac_index" for inet domain socket.
+ */
+static const u8 tomoyo_inet2mac
+[TOMOYO_SOCK_MAX][TOMOYO_MAX_NETWORK_OPERATION] = {
+ [SOCK_STREAM] = {
+ [TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_INET_STREAM_BIND,
+ [TOMOYO_NETWORK_LISTEN] =
+ TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN,
+ [TOMOYO_NETWORK_CONNECT] =
+ TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT,
+ },
+ [SOCK_DGRAM] = {
+ [TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_INET_DGRAM_BIND,
+ [TOMOYO_NETWORK_SEND] = TOMOYO_MAC_NETWORK_INET_DGRAM_SEND,
+ },
+ [SOCK_RAW] = {
+ [TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_INET_RAW_BIND,
+ [TOMOYO_NETWORK_SEND] = TOMOYO_MAC_NETWORK_INET_RAW_SEND,
+ },
+};
+
+/*
+ * Mapping table from "enum tomoyo_network_acl_index" to
+ * "enum tomoyo_mac_index" for unix domain socket.
+ */
+static const u8 tomoyo_unix2mac
+[TOMOYO_SOCK_MAX][TOMOYO_MAX_NETWORK_OPERATION] = {
+ [SOCK_STREAM] = {
+ [TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND,
+ [TOMOYO_NETWORK_LISTEN] =
+ TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN,
+ [TOMOYO_NETWORK_CONNECT] =
+ TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT,
+ },
+ [SOCK_DGRAM] = {
+ [TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND,
+ [TOMOYO_NETWORK_SEND] = TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND,
+ },
+ [SOCK_SEQPACKET] = {
+ [TOMOYO_NETWORK_BIND] =
+ TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND,
+ [TOMOYO_NETWORK_LISTEN] =
+ TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN,
+ [TOMOYO_NETWORK_CONNECT] =
+ TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT,
+ },
+};
+
+/**
+ * tomoyo_same_inet_acl - Check for duplicated "struct tomoyo_inet_acl" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_info".
+ * @b: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if @a == @b except permission bits, false otherwise.
+ */
+static bool tomoyo_same_inet_acl(const struct tomoyo_acl_info *a,
+ const struct tomoyo_acl_info *b)
+{
+ const struct tomoyo_inet_acl *p1 = container_of(a, typeof(*p1), head);
+ const struct tomoyo_inet_acl *p2 = container_of(b, typeof(*p2), head);
+
+ return p1->protocol == p2->protocol &&
+ tomoyo_same_ipaddr_union(&p1->address, &p2->address) &&
+ tomoyo_same_number_union(&p1->port, &p2->port);
+}
+
+/**
+ * tomoyo_same_unix_acl - Check for duplicated "struct tomoyo_unix_acl" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_info".
+ * @b: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if @a == @b except permission bits, false otherwise.
+ */
+static bool tomoyo_same_unix_acl(const struct tomoyo_acl_info *a,
+ const struct tomoyo_acl_info *b)
+{
+ const struct tomoyo_unix_acl *p1 = container_of(a, typeof(*p1), head);
+ const struct tomoyo_unix_acl *p2 = container_of(b, typeof(*p2), head);
+
+ return p1->protocol == p2->protocol &&
+ tomoyo_same_name_union(&p1->name, &p2->name);
+}
+
+/**
+ * tomoyo_merge_inet_acl - Merge duplicated "struct tomoyo_inet_acl" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_info".
+ * @b: Pointer to "struct tomoyo_acl_info".
+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
+ *
+ * Returns true if @a is empty, false otherwise.
+ */
+static bool tomoyo_merge_inet_acl(struct tomoyo_acl_info *a,
+ struct tomoyo_acl_info *b,
+ const bool is_delete)
+{
+ u8 * const a_perm =
+ &container_of(a, struct tomoyo_inet_acl, head)->perm;
+ u8 perm = *a_perm;
+ const u8 b_perm = container_of(b, struct tomoyo_inet_acl, head)->perm;
+
+ if (is_delete)
+ perm &= ~b_perm;
+ else
+ perm |= b_perm;
+ *a_perm = perm;
+ return !perm;
+}
+
+/**
+ * tomoyo_merge_unix_acl - Merge duplicated "struct tomoyo_unix_acl" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_info".
+ * @b: Pointer to "struct tomoyo_acl_info".
+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
+ *
+ * Returns true if @a is empty, false otherwise.
+ */
+static bool tomoyo_merge_unix_acl(struct tomoyo_acl_info *a,
+ struct tomoyo_acl_info *b,
+ const bool is_delete)
+{
+ u8 * const a_perm =
+ &container_of(a, struct tomoyo_unix_acl, head)->perm;
+ u8 perm = *a_perm;
+ const u8 b_perm = container_of(b, struct tomoyo_unix_acl, head)->perm;
+
+ if (is_delete)
+ perm &= ~b_perm;
+ else
+ perm |= b_perm;
+ *a_perm = perm;
+ return !perm;
+}
+
+/**
+ * tomoyo_write_inet_network - Write "struct tomoyo_inet_acl" list.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+int tomoyo_write_inet_network(struct tomoyo_acl_param *param)
+{
+ struct tomoyo_inet_acl e = { .head.type = TOMOYO_TYPE_INET_ACL };
+ int error = -EINVAL;
+ u8 type;
+ const char *protocol = tomoyo_read_token(param);
+ const char *operation = tomoyo_read_token(param);
+
+ for (e.protocol = 0; e.protocol < TOMOYO_SOCK_MAX; e.protocol++)
+ if (!strcmp(protocol, tomoyo_proto_keyword[e.protocol]))
+ break;
+ for (type = 0; type < TOMOYO_MAX_NETWORK_OPERATION; type++)
+ if (tomoyo_permstr(operation, tomoyo_socket_keyword[type]))
+ e.perm |= 1 << type;
+ if (e.protocol == TOMOYO_SOCK_MAX || !e.perm)
+ return -EINVAL;
+ if (param->data[0] == '@') {
+ param->data++;
+ e.address.group =
+ tomoyo_get_group(param, TOMOYO_ADDRESS_GROUP);
+ if (!e.address.group)
+ return -ENOMEM;
+ } else {
+ if (!tomoyo_parse_ipaddr_union(param, &e.address))
+ goto out;
+ }
+ if (!tomoyo_parse_number_union(param, &e.port) ||
+ e.port.values[1] > 65535)
+ goto out;
+ error = tomoyo_update_domain(&e.head, sizeof(e), param,
+ tomoyo_same_inet_acl,
+ tomoyo_merge_inet_acl);
+out:
+ tomoyo_put_group(e.address.group);
+ tomoyo_put_number_union(&e.port);
+ return error;
+}
+
+/**
+ * tomoyo_write_unix_network - Write "struct tomoyo_unix_acl" list.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_write_unix_network(struct tomoyo_acl_param *param)
+{
+ struct tomoyo_unix_acl e = { .head.type = TOMOYO_TYPE_UNIX_ACL };
+ int error;
+ u8 type;
+ const char *protocol = tomoyo_read_token(param);
+ const char *operation = tomoyo_read_token(param);
+
+ for (e.protocol = 0; e.protocol < TOMOYO_SOCK_MAX; e.protocol++)
+ if (!strcmp(protocol, tomoyo_proto_keyword[e.protocol]))
+ break;
+ for (type = 0; type < TOMOYO_MAX_NETWORK_OPERATION; type++)
+ if (tomoyo_permstr(operation, tomoyo_socket_keyword[type]))
+ e.perm |= 1 << type;
+ if (e.protocol == TOMOYO_SOCK_MAX || !e.perm)
+ return -EINVAL;
+ if (!tomoyo_parse_name_union(param, &e.name))
+ return -EINVAL;
+ error = tomoyo_update_domain(&e.head, sizeof(e), param,
+ tomoyo_same_unix_acl,
+ tomoyo_merge_unix_acl);
+ tomoyo_put_name_union(&e.name);
+ return error;
+}
+
+/**
+ * tomoyo_audit_net_log - Audit network log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ * @family: Name of socket family ("inet" or "unix").
+ * @protocol: Name of protocol in @family.
+ * @operation: Name of socket operation.
+ * @address: Name of address.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_net_log(struct tomoyo_request_info *r,
+ const char *family, const u8 protocol,
+ const u8 operation, const char *address)
+{
+ return tomoyo_supervisor(r, "network %s %s %s %s\n", family,
+ tomoyo_proto_keyword[protocol],
+ tomoyo_socket_keyword[operation], address);
+}
+
+/**
+ * tomoyo_audit_inet_log - Audit INET network log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_inet_log(struct tomoyo_request_info *r)
+{
+ char buf[128];
+ int len;
+ const __be32 *address = r->param.inet_network.address;
+
+ if (r->param.inet_network.is_ipv6)
+ tomoyo_print_ipv6(buf, sizeof(buf), (const struct in6_addr *)
+ address, (const struct in6_addr *) address);
+ else
+ tomoyo_print_ipv4(buf, sizeof(buf), address, address);
+ len = strlen(buf);
+ snprintf(buf + len, sizeof(buf) - len, " %u",
+ r->param.inet_network.port);
+ return tomoyo_audit_net_log(r, "inet", r->param.inet_network.protocol,
+ r->param.inet_network.operation, buf);
+}
+
+/**
+ * tomoyo_audit_unix_log - Audit UNIX network log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_unix_log(struct tomoyo_request_info *r)
+{
+ return tomoyo_audit_net_log(r, "unix", r->param.unix_network.protocol,
+ r->param.unix_network.operation,
+ r->param.unix_network.address->name);
+}
+
+/**
+ * tomoyo_check_inet_acl - Check permission for inet domain socket operation.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ * @ptr: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if granted, false otherwise.
+ */
+static bool tomoyo_check_inet_acl(struct tomoyo_request_info *r,
+ const struct tomoyo_acl_info *ptr)
+{
+ const struct tomoyo_inet_acl *acl =
+ container_of(ptr, typeof(*acl), head);
+ const u8 size = r->param.inet_network.is_ipv6 ? 16 : 4;
+
+ if (!(acl->perm & (1 << r->param.inet_network.operation)) ||
+ !tomoyo_compare_number_union(r->param.inet_network.port,
+ &acl->port))
+ return false;
+ if (acl->address.group)
+ return tomoyo_address_matches_group
+ (r->param.inet_network.is_ipv6,
+ r->param.inet_network.address, acl->address.group);
+ return acl->address.is_ipv6 == r->param.inet_network.is_ipv6 &&
+ memcmp(&acl->address.ip[0],
+ r->param.inet_network.address, size) <= 0 &&
+ memcmp(r->param.inet_network.address,
+ &acl->address.ip[1], size) <= 0;
+}
+
+/**
+ * tomoyo_check_unix_acl - Check permission for unix domain socket operation.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ * @ptr: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if granted, false otherwise.
+ */
+static bool tomoyo_check_unix_acl(struct tomoyo_request_info *r,
+ const struct tomoyo_acl_info *ptr)
+{
+ const struct tomoyo_unix_acl *acl =
+ container_of(ptr, typeof(*acl), head);
+
+ return (acl->perm & (1 << r->param.unix_network.operation)) &&
+ tomoyo_compare_name_union(r->param.unix_network.address,
+ &acl->name);
+}
+
+/**
+ * tomoyo_inet_entry - Check permission for INET network operation.
+ *
+ * @address: Pointer to "struct tomoyo_addr_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_inet_entry(const struct tomoyo_addr_info *address)
+{
+ const int idx = tomoyo_read_lock();
+ struct tomoyo_request_info r;
+ int error = 0;
+ const u8 type = tomoyo_inet2mac[address->protocol][address->operation];
+
+ if (type && tomoyo_init_request_info(&r, NULL, type)
+ != TOMOYO_CONFIG_DISABLED) {
+ r.param_type = TOMOYO_TYPE_INET_ACL;
+ r.param.inet_network.protocol = address->protocol;
+ r.param.inet_network.operation = address->operation;
+ r.param.inet_network.is_ipv6 = address->inet.is_ipv6;
+ r.param.inet_network.address = address->inet.address;
+ r.param.inet_network.port = ntohs(address->inet.port);
+ do {
+ tomoyo_check_acl(&r, tomoyo_check_inet_acl);
+ error = tomoyo_audit_inet_log(&r);
+ } while (error == TOMOYO_RETRY_REQUEST);
+ }
+ tomoyo_read_unlock(idx);
+ return error;
+}
+
+/**
+ * tomoyo_check_inet_address - Check permission for inet domain socket's operation.
+ *
+ * @addr: Pointer to "struct sockaddr".
+ * @addr_len: Size of @addr.
+ * @port: Port number.
+ * @address: Pointer to "struct tomoyo_addr_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_check_inet_address(const struct sockaddr *addr,
+ const unsigned int addr_len,
+ const u16 port,
+ struct tomoyo_addr_info *address)
+{
+ struct tomoyo_inet_addr_info *i = &address->inet;
+
+ switch (addr->sa_family) {
+ case AF_INET6:
+ if (addr_len < SIN6_LEN_RFC2133)
+ goto skip;
+ i->is_ipv6 = true;
+ i->address = (__be32 *)
+ ((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr;
+ i->port = ((struct sockaddr_in6 *) addr)->sin6_port;
+ break;
+ case AF_INET:
+ if (addr_len < sizeof(struct sockaddr_in))
+ goto skip;
+ i->is_ipv6 = false;
+ i->address = (__be32 *)
+ &((struct sockaddr_in *) addr)->sin_addr;
+ i->port = ((struct sockaddr_in *) addr)->sin_port;
+ break;
+ default:
+ goto skip;
+ }
+ if (address->protocol == SOCK_RAW)
+ i->port = htons(port);
+ return tomoyo_inet_entry(address);
+skip:
+ return 0;
+}
+
+/**
+ * tomoyo_unix_entry - Check permission for UNIX network operation.
+ *
+ * @address: Pointer to "struct tomoyo_addr_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_unix_entry(const struct tomoyo_addr_info *address)
+{
+ const int idx = tomoyo_read_lock();
+ struct tomoyo_request_info r;
+ int error = 0;
+ const u8 type = tomoyo_unix2mac[address->protocol][address->operation];
+
+ if (type && tomoyo_init_request_info(&r, NULL, type)
+ != TOMOYO_CONFIG_DISABLED) {
+ char *buf = address->unix0.addr;
+ int len = address->unix0.addr_len - sizeof(sa_family_t);
+
+ if (len <= 0) {
+ buf = "anonymous";
+ len = 9;
+ } else if (buf[0]) {
+ len = strnlen(buf, len);
+ }
+ buf = tomoyo_encode2(buf, len);
+ if (buf) {
+ struct tomoyo_path_info addr;
+
+ addr.name = buf;
+ tomoyo_fill_path_info(&addr);
+ r.param_type = TOMOYO_TYPE_UNIX_ACL;
+ r.param.unix_network.protocol = address->protocol;
+ r.param.unix_network.operation = address->operation;
+ r.param.unix_network.address = &addr;
+ do {
+ tomoyo_check_acl(&r, tomoyo_check_unix_acl);
+ error = tomoyo_audit_unix_log(&r);
+ } while (error == TOMOYO_RETRY_REQUEST);
+ kfree(buf);
+ } else
+ error = -ENOMEM;
+ }
+ tomoyo_read_unlock(idx);
+ return error;
+}
+
+/**
+ * tomoyo_check_unix_address - Check permission for unix domain socket's operation.
+ *
+ * @addr: Pointer to "struct sockaddr".
+ * @addr_len: Size of @addr.
+ * @address: Pointer to "struct tomoyo_addr_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_check_unix_address(struct sockaddr *addr,
+ const unsigned int addr_len,
+ struct tomoyo_addr_info *address)
+{
+ struct tomoyo_unix_addr_info *u = &address->unix0;
+
+ if (addr->sa_family != AF_UNIX)
+ return 0;
+ u->addr = ((struct sockaddr_un *) addr)->sun_path;
+ u->addr_len = addr_len;
+ return tomoyo_unix_entry(address);
+}
+
+/**
+ * tomoyo_kernel_service - Check whether I'm kernel service or not.
+ *
+ * Returns true if I'm kernel service, false otherwise.
+ */
+static bool tomoyo_kernel_service(void)
+{
+ /* Nothing to do if I am a kernel service. */
+ return segment_eq(get_fs(), KERNEL_DS);
+}
+
+/**
+ * tomoyo_sock_family - Get socket's family.
+ *
+ * @sk: Pointer to "struct sock".
+ *
+ * Returns one of PF_INET, PF_INET6, PF_UNIX or 0.
+ */
+static u8 tomoyo_sock_family(struct sock *sk)
+{
+ u8 family;
+
+ if (tomoyo_kernel_service())
+ return 0;
+ family = sk->sk_family;
+ switch (family) {
+ case PF_INET:
+ case PF_INET6:
+ case PF_UNIX:
+ return family;
+ default:
+ return 0;
+ }
+}
+
+/**
+ * tomoyo_socket_listen_permission - Check permission for listening a socket.
+ *
+ * @sock: Pointer to "struct socket".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_socket_listen_permission(struct socket *sock)
+{
+ struct tomoyo_addr_info address;
+ const u8 family = tomoyo_sock_family(sock->sk);
+ const unsigned int type = sock->type;
+ struct sockaddr_storage addr;
+ int addr_len;
+
+ if (!family || (type != SOCK_STREAM && type != SOCK_SEQPACKET))
+ return 0;
+ {
+ const int error = sock->ops->getname(sock, (struct sockaddr *)
+ &addr, &addr_len, 0);
+
+ if (error)
+ return error;
+ }
+ address.protocol = type;
+ address.operation = TOMOYO_NETWORK_LISTEN;
+ if (family == PF_UNIX)
+ return tomoyo_check_unix_address((struct sockaddr *) &addr,
+ addr_len, &address);
+ return tomoyo_check_inet_address((struct sockaddr *) &addr, addr_len,
+ 0, &address);
+}
+
+/**
+ * tomoyo_socket_connect_permission - Check permission for setting the remote address of a socket.
+ *
+ * @sock: Pointer to "struct socket".
+ * @addr: Pointer to "struct sockaddr".
+ * @addr_len: Size of @addr.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_socket_connect_permission(struct socket *sock,
+ struct sockaddr *addr, int addr_len)
+{
+ struct tomoyo_addr_info address;
+ const u8 family = tomoyo_sock_family(sock->sk);
+ const unsigned int type = sock->type;
+
+ if (!family)
+ return 0;
+ address.protocol = type;
+ switch (type) {
+ case SOCK_DGRAM:
+ case SOCK_RAW:
+ address.operation = TOMOYO_NETWORK_SEND;
+ break;
+ case SOCK_STREAM:
+ case SOCK_SEQPACKET:
+ address.operation = TOMOYO_NETWORK_CONNECT;
+ break;
+ default:
+ return 0;
+ }
+ if (family == PF_UNIX)
+ return tomoyo_check_unix_address(addr, addr_len, &address);
+ return tomoyo_check_inet_address(addr, addr_len, sock->sk->sk_protocol,
+ &address);
+}
+
+/**
+ * tomoyo_socket_bind_permission - Check permission for setting the local address of a socket.
+ *
+ * @sock: Pointer to "struct socket".
+ * @addr: Pointer to "struct sockaddr".
+ * @addr_len: Size of @addr.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr,
+ int addr_len)
+{
+ struct tomoyo_addr_info address;
+ const u8 family = tomoyo_sock_family(sock->sk);
+ const unsigned int type = sock->type;
+
+ if (!family)
+ return 0;
+ switch (type) {
+ case SOCK_STREAM:
+ case SOCK_DGRAM:
+ case SOCK_RAW:
+ case SOCK_SEQPACKET:
+ address.protocol = type;
+ address.operation = TOMOYO_NETWORK_BIND;
+ break;
+ default:
+ return 0;
+ }
+ if (family == PF_UNIX)
+ return tomoyo_check_unix_address(addr, addr_len, &address);
+ return tomoyo_check_inet_address(addr, addr_len, sock->sk->sk_protocol,
+ &address);
+}
+
+/**
+ * tomoyo_socket_sendmsg_permission - Check permission for sending a datagram.
+ *
+ * @sock: Pointer to "struct socket".
+ * @msg: Pointer to "struct msghdr".
+ * @size: Unused.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_socket_sendmsg_permission(struct socket *sock, struct msghdr *msg,
+ int size)
+{
+ struct tomoyo_addr_info address;
+ const u8 family = tomoyo_sock_family(sock->sk);
+ const unsigned int type = sock->type;
+
+ if (!msg->msg_name || !family ||
+ (type != SOCK_DGRAM && type != SOCK_RAW))
+ return 0;
+ address.protocol = type;
+ address.operation = TOMOYO_NETWORK_SEND;
+ if (family == PF_UNIX)
+ return tomoyo_check_unix_address((struct sockaddr *)
+ msg->msg_name,
+ msg->msg_namelen, &address);
+ return tomoyo_check_inet_address((struct sockaddr *) msg->msg_name,
+ msg->msg_namelen,
+ sock->sk->sk_protocol, &address);
+}
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c
index 6c601bd300f3..738bbdf8d4c7 100644
--- a/security/tomoyo/realpath.c
+++ b/security/tomoyo/realpath.c
@@ -15,17 +15,19 @@
#include "../../fs/internal.h"
/**
- * tomoyo_encode: Convert binary string to ascii string.
+ * tomoyo_encode2 - Encode binary string to ascii string.
*
- * @str: String in binary format.
+ * @str: String in binary format.
+ * @str_len: Size of @str in byte.
*
* Returns pointer to @str in ascii format on success, NULL otherwise.
*
* This function uses kzalloc(), so caller must kfree() if this function
* didn't return NULL.
*/
-char *tomoyo_encode(const char *str)
+char *tomoyo_encode2(const char *str, int str_len)
{
+ int i;
int len = 0;
const char *p = str;
char *cp;
@@ -33,8 +35,9 @@ char *tomoyo_encode(const char *str)
if (!p)
return NULL;
- while (*p) {
- const unsigned char c = *p++;
+ for (i = 0; i < str_len; i++) {
+ const unsigned char c = p[i];
+
if (c == '\\')
len += 2;
else if (c > ' ' && c < 127)
@@ -49,8 +52,8 @@ char *tomoyo_encode(const char *str)
return NULL;
cp0 = cp;
p = str;
- while (*p) {
- const unsigned char c = *p++;
+ for (i = 0; i < str_len; i++) {
+ const unsigned char c = p[i];
if (c == '\\') {
*cp++ = '\\';
@@ -68,6 +71,21 @@ char *tomoyo_encode(const char *str)
}
/**
+ * tomoyo_encode - Encode binary string to ascii string.
+ *
+ * @str: String in binary format.
+ *
+ * Returns pointer to @str in ascii format on success, NULL otherwise.
+ *
+ * This function uses kzalloc(), so caller must kfree() if this function
+ * didn't return NULL.
+ */
+char *tomoyo_encode(const char *str)
+{
+ return str ? tomoyo_encode2(str, strlen(str)) : NULL;
+}
+
+/**
* tomoyo_get_absolute_path - Get the path of a dentry but ignores chroot'ed root.
*
* @path: Pointer to "struct path".
diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c
index a49c3bfd4dd5..2672ac4f3beb 100644
--- a/security/tomoyo/securityfs_if.c
+++ b/security/tomoyo/securityfs_if.c
@@ -8,6 +8,124 @@
#include "common.h"
/**
+ * tomoyo_check_task_acl - Check permission for task operation.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ * @ptr: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if granted, false otherwise.
+ */
+static bool tomoyo_check_task_acl(struct tomoyo_request_info *r,
+ const struct tomoyo_acl_info *ptr)
+{
+ const struct tomoyo_task_acl *acl = container_of(ptr, typeof(*acl),
+ head);
+ return !tomoyo_pathcmp(r->param.task.domainname, acl->domainname);
+}
+
+/**
+ * tomoyo_write_self - write() for /sys/kernel/security/tomoyo/self_domain interface.
+ *
+ * @file: Pointer to "struct file".
+ * @buf: Domainname to transit to.
+ * @count: Size of @buf.
+ * @ppos: Unused.
+ *
+ * Returns @count on success, negative value otherwise.
+ *
+ * If domain transition was permitted but the domain transition failed, this
+ * function returns error rather than terminating current thread with SIGKILL.
+ */
+static ssize_t tomoyo_write_self(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char *data;
+ int error;
+ if (!count || count >= TOMOYO_EXEC_TMPSIZE - 10)
+ return -ENOMEM;
+ data = kzalloc(count + 1, GFP_NOFS);
+ if (!data)
+ return -ENOMEM;
+ if (copy_from_user(data, buf, count)) {
+ error = -EFAULT;
+ goto out;
+ }
+ tomoyo_normalize_line(data);
+ if (tomoyo_correct_domain(data)) {
+ const int idx = tomoyo_read_lock();
+ struct tomoyo_path_info name;
+ struct tomoyo_request_info r;
+ name.name = data;
+ tomoyo_fill_path_info(&name);
+ /* Check "task manual_domain_transition" permission. */
+ tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE);
+ r.param_type = TOMOYO_TYPE_MANUAL_TASK_ACL;
+ r.param.task.domainname = &name;
+ tomoyo_check_acl(&r, tomoyo_check_task_acl);
+ if (!r.granted)
+ error = -EPERM;
+ else {
+ struct tomoyo_domain_info *new_domain =
+ tomoyo_assign_domain(data, true);
+ if (!new_domain) {
+ error = -ENOENT;
+ } else {
+ struct cred *cred = prepare_creds();
+ if (!cred) {
+ error = -ENOMEM;
+ } else {
+ struct tomoyo_domain_info *old_domain =
+ cred->security;
+ cred->security = new_domain;
+ atomic_inc(&new_domain->users);
+ atomic_dec(&old_domain->users);
+ commit_creds(cred);
+ error = 0;
+ }
+ }
+ }
+ tomoyo_read_unlock(idx);
+ } else
+ error = -EINVAL;
+out:
+ kfree(data);
+ return error ? error : count;
+}
+
+/**
+ * tomoyo_read_self - read() for /sys/kernel/security/tomoyo/self_domain interface.
+ *
+ * @file: Pointer to "struct file".
+ * @buf: Domainname which current thread belongs to.
+ * @count: Size of @buf.
+ * @ppos: Bytes read by now.
+ *
+ * Returns read size on success, negative value otherwise.
+ */
+static ssize_t tomoyo_read_self(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ const char *domain = tomoyo_domain()->domainname->name;
+ loff_t len = strlen(domain);
+ loff_t pos = *ppos;
+ if (pos >= len || !count)
+ return 0;
+ len -= pos;
+ if (count < len)
+ len = count;
+ if (copy_to_user(buf, domain + pos, len))
+ return -EFAULT;
+ *ppos += len;
+ return len;
+}
+
+/* Operations for /sys/kernel/security/tomoyo/self_domain interface. */
+static const struct file_operations tomoyo_self_operations = {
+ .write = tomoyo_write_self,
+ .read = tomoyo_read_self,
+};
+
+/**
* tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface.
*
* @inode: Pointer to "struct inode".
@@ -135,8 +253,6 @@ static int __init tomoyo_initerface_init(void)
TOMOYO_EXCEPTIONPOLICY);
tomoyo_create_entry("audit", 0400, tomoyo_dir,
TOMOYO_AUDIT);
- tomoyo_create_entry("self_domain", 0400, tomoyo_dir,
- TOMOYO_SELFDOMAIN);
tomoyo_create_entry(".process_status", 0600, tomoyo_dir,
TOMOYO_PROCESS_STATUS);
tomoyo_create_entry("stat", 0644, tomoyo_dir,
@@ -147,6 +263,9 @@ static int __init tomoyo_initerface_init(void)
TOMOYO_MANAGER);
tomoyo_create_entry("version", 0400, tomoyo_dir,
TOMOYO_VERSION);
+ securityfs_create_file("self_domain", 0666, tomoyo_dir, NULL,
+ &tomoyo_self_operations);
+ tomoyo_load_builtin_policy();
return 0;
}
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index f776400a8f31..4b327b691745 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -442,6 +442,64 @@ static int tomoyo_sb_pivotroot(struct path *old_path, struct path *new_path)
return tomoyo_path2_perm(TOMOYO_TYPE_PIVOT_ROOT, new_path, old_path);
}
+/**
+ * tomoyo_socket_listen - Check permission for listen().
+ *
+ * @sock: Pointer to "struct socket".
+ * @backlog: Backlog parameter.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_socket_listen(struct socket *sock, int backlog)
+{
+ return tomoyo_socket_listen_permission(sock);
+}
+
+/**
+ * tomoyo_socket_connect - Check permission for connect().
+ *
+ * @sock: Pointer to "struct socket".
+ * @addr: Pointer to "struct sockaddr".
+ * @addr_len: Size of @addr.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_socket_connect(struct socket *sock, struct sockaddr *addr,
+ int addr_len)
+{
+ return tomoyo_socket_connect_permission(sock, addr, addr_len);
+}
+
+/**
+ * tomoyo_socket_bind - Check permission for bind().
+ *
+ * @sock: Pointer to "struct socket".
+ * @addr: Pointer to "struct sockaddr".
+ * @addr_len: Size of @addr.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_socket_bind(struct socket *sock, struct sockaddr *addr,
+ int addr_len)
+{
+ return tomoyo_socket_bind_permission(sock, addr, addr_len);
+}
+
+/**
+ * tomoyo_socket_sendmsg - Check permission for sendmsg().
+ *
+ * @sock: Pointer to "struct socket".
+ * @msg: Pointer to "struct msghdr".
+ * @size: Size of message.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_socket_sendmsg(struct socket *sock, struct msghdr *msg,
+ int size)
+{
+ return tomoyo_socket_sendmsg_permission(sock, msg, size);
+}
+
/*
* tomoyo_security_ops is a "struct security_operations" which is used for
* registering TOMOYO.
@@ -472,6 +530,10 @@ static struct security_operations tomoyo_security_ops = {
.sb_mount = tomoyo_sb_mount,
.sb_umount = tomoyo_sb_umount,
.sb_pivotroot = tomoyo_sb_pivotroot,
+ .socket_bind = tomoyo_socket_bind,
+ .socket_connect = tomoyo_socket_connect,
+ .socket_listen = tomoyo_socket_listen,
+ .socket_sendmsg = tomoyo_socket_sendmsg,
};
/* Lock for GC. */
diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c
index c36bd1107fc8..4a9b4b2eb755 100644
--- a/security/tomoyo/util.c
+++ b/security/tomoyo/util.c
@@ -42,6 +42,39 @@ const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = {
[TOMOYO_MAC_FILE_MOUNT] = TOMOYO_MAC_CATEGORY_FILE,
[TOMOYO_MAC_FILE_UMOUNT] = TOMOYO_MAC_CATEGORY_FILE,
[TOMOYO_MAC_FILE_PIVOT_ROOT] = TOMOYO_MAC_CATEGORY_FILE,
+ /* CONFIG::network group */
+ [TOMOYO_MAC_NETWORK_INET_STREAM_BIND] =
+ TOMOYO_MAC_CATEGORY_NETWORK,
+ [TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN] =
+ TOMOYO_MAC_CATEGORY_NETWORK,
+ [TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT] =
+ TOMOYO_MAC_CATEGORY_NETWORK,
+ [TOMOYO_MAC_NETWORK_INET_DGRAM_BIND] =
+ TOMOYO_MAC_CATEGORY_NETWORK,
+ [TOMOYO_MAC_NETWORK_INET_DGRAM_SEND] =
+ TOMOYO_MAC_CATEGORY_NETWORK,
+ [TOMOYO_MAC_NETWORK_INET_RAW_BIND] =
+ TOMOYO_MAC_CATEGORY_NETWORK,
+ [TOMOYO_MAC_NETWORK_INET_RAW_SEND] =
+ TOMOYO_MAC_CATEGORY_NETWORK,
+ [TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND] =
+ TOMOYO_MAC_CATEGORY_NETWORK,
+ [TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN] =
+ TOMOYO_MAC_CATEGORY_NETWORK,
+ [TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT] =
+ TOMOYO_MAC_CATEGORY_NETWORK,
+ [TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND] =
+ TOMOYO_MAC_CATEGORY_NETWORK,
+ [TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND] =
+ TOMOYO_MAC_CATEGORY_NETWORK,
+ [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND] =
+ TOMOYO_MAC_CATEGORY_NETWORK,
+ [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN] =
+ TOMOYO_MAC_CATEGORY_NETWORK,
+ [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] =
+ TOMOYO_MAC_CATEGORY_NETWORK,
+ /* CONFIG::misc group */
+ [TOMOYO_MAC_ENVIRON] = TOMOYO_MAC_CATEGORY_MISC,
};
/**
@@ -126,6 +159,31 @@ char *tomoyo_read_token(struct tomoyo_acl_param *param)
}
/**
+ * tomoyo_get_domainname - Read a domainname from a line.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns a domainname on success, NULL otherwise.
+ */
+const struct tomoyo_path_info *tomoyo_get_domainname
+(struct tomoyo_acl_param *param)
+{
+ char *start = param->data;
+ char *pos = start;
+ while (*pos) {
+ if (*pos++ != ' ' || *pos++ == '/')
+ continue;
+ pos -= 2;
+ *pos++ = '\0';
+ break;
+ }
+ param->data = pos;
+ if (tomoyo_correct_domain(start))
+ return tomoyo_get_name(start);
+ return NULL;
+}
+
+/**
* tomoyo_parse_ulong - Parse an "unsigned long" value.
*
* @result: Pointer to "unsigned long".
@@ -920,14 +978,17 @@ int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile,
const u8 index)
{
u8 mode;
- const u8 category = TOMOYO_MAC_CATEGORY_FILE;
+ struct tomoyo_profile *p;
+
if (!tomoyo_policy_loaded)
return TOMOYO_CONFIG_DISABLED;
- mode = tomoyo_profile(ns, profile)->config[index];
+ p = tomoyo_profile(ns, profile);
+ mode = p->config[index];
if (mode == TOMOYO_CONFIG_USE_DEFAULT)
- mode = tomoyo_profile(ns, profile)->config[category];
+ mode = p->config[tomoyo_index2category[index]
+ + TOMOYO_MAX_MAC_INDEX];
if (mode == TOMOYO_CONFIG_USE_DEFAULT)
- mode = tomoyo_profile(ns, profile)->default_config;
+ mode = p->default_config;
return mode & 3;
}
@@ -996,6 +1057,17 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
perm = container_of(ptr, struct tomoyo_mkdev_acl,
head)->perm;
break;
+ case TOMOYO_TYPE_INET_ACL:
+ perm = container_of(ptr, struct tomoyo_inet_acl,
+ head)->perm;
+ break;
+ case TOMOYO_TYPE_UNIX_ACL:
+ perm = container_of(ptr, struct tomoyo_unix_acl,
+ head)->perm;
+ break;
+ case TOMOYO_TYPE_MANUAL_TASK_ACL:
+ perm = 0;
+ break;
default:
perm = 1;
}
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index 16bd9c03679b..691569238435 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -176,7 +176,7 @@ static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr,
* Calls the memory-allocator function for the corresponding
* buffer type.
*
- * Returns zero if the buffer with the given size is allocated successfuly,
+ * Returns zero if the buffer with the given size is allocated successfully,
* other a negative value at error.
*/
int snd_dma_alloc_pages(int type, struct device *device, size_t size,
@@ -230,7 +230,7 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
* tries to allocate again. The size actually allocated is stored in
* res_size argument.
*
- * Returns zero if the buffer with the given size is allocated successfuly,
+ * Returns zero if the buffer with the given size is allocated successfully,
* other a negative value at error.
*/
int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size,
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 86d0caf91b35..62e90b862a0d 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -1761,6 +1761,10 @@ static int wait_for_avail(struct snd_pcm_substream *substream,
snd_pcm_uframes_t avail = 0;
long wait_time, tout;
+ init_waitqueue_entry(&wait, current);
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&runtime->tsleep, &wait);
+
if (runtime->no_period_wakeup)
wait_time = MAX_SCHEDULE_TIMEOUT;
else {
@@ -1771,16 +1775,32 @@ static int wait_for_avail(struct snd_pcm_substream *substream,
}
wait_time = msecs_to_jiffies(wait_time * 1000);
}
- init_waitqueue_entry(&wait, current);
- add_wait_queue(&runtime->tsleep, &wait);
+
for (;;) {
if (signal_pending(current)) {
err = -ERESTARTSYS;
break;
}
+
+ /*
+ * We need to check if space became available already
+ * (and thus the wakeup happened already) first to close
+ * the race of space already having become available.
+ * This check must happen after been added to the waitqueue
+ * and having current state be INTERRUPTIBLE.
+ */
+ if (is_playback)
+ avail = snd_pcm_playback_avail(runtime);
+ else
+ avail = snd_pcm_capture_avail(runtime);
+ if (avail >= runtime->twake)
+ break;
snd_pcm_stream_unlock_irq(substream);
- tout = schedule_timeout_interruptible(wait_time);
+
+ tout = schedule_timeout(wait_time);
+
snd_pcm_stream_lock_irq(substream);
+ set_current_state(TASK_INTERRUPTIBLE);
switch (runtime->status->state) {
case SNDRV_PCM_STATE_SUSPENDED:
err = -ESTRPIPE;
@@ -1806,14 +1826,9 @@ static int wait_for_avail(struct snd_pcm_substream *substream,
err = -EIO;
break;
}
- if (is_playback)
- avail = snd_pcm_playback_avail(runtime);
- else
- avail = snd_pcm_capture_avail(runtime);
- if (avail >= runtime->twake)
- break;
}
_endloop:
+ set_current_state(TASK_RUNNING);
remove_wait_queue(&runtime->tsleep, &wait);
*availp = avail;
return err;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 1c6be91dfb98..c74e228731ed 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -23,7 +23,7 @@
#include <linux/file.h>
#include <linux/slab.h>
#include <linux/time.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
#include <linux/uio.h>
#include <linux/dma-mapping.h>
#include <sound/core.h>
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index 6c93e051f9ae..6c9e8e8f45f8 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -432,9 +432,7 @@ config SOUND_SB
ALS-007 and ALS-1X0 chips (read <file:Documentation/sound/oss/ALS>) and
for cards based on ESS chips (read
<file:Documentation/sound/oss/ESS1868> and
- <file:Documentation/sound/oss/ESS>). If you have an SB AWE 32 or SB AWE
- 64, say Y here and also to "AWE32 synth" below and read
- <file:Documentation/sound/oss/INSTALL.awe>. If you have an IBM Mwave
+ <file:Documentation/sound/oss/ESS>). If you have an IBM Mwave
card, say Y here and read <file:Documentation/sound/oss/mwave>.
If you compile the driver into the kernel and don't want to use
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index f9123f09e83e..32b02d906703 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -68,6 +68,7 @@ MODULE_PARM_DESC(enable, "Enable FM801 soundcard.");
module_param_array(tea575x_tuner, int, NULL, 0444);
MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (0 = auto, 1 = SF256-PCS, 2=SF256-PCP, 3=SF64-PCR, 8=disable, +16=tuner-only).");
+#define TUNER_DISABLED (1<<3)
#define TUNER_ONLY (1<<4)
#define TUNER_TYPE_MASK (~TUNER_ONLY & 0xFFFF)
@@ -1150,7 +1151,8 @@ static int snd_fm801_free(struct fm801 *chip)
__end_hw:
#ifdef CONFIG_SND_FM801_TEA575X_BOOL
- snd_tea575x_exit(&chip->tea);
+ if (!(chip->tea575x_tuner & TUNER_DISABLED))
+ snd_tea575x_exit(&chip->tea);
#endif
if (chip->irq >= 0)
free_irq(chip->irq, chip);
@@ -1236,7 +1238,6 @@ static int __devinit snd_fm801_create(struct snd_card *card,
(tea575x_tuner & TUNER_TYPE_MASK) < 4) {
if (snd_tea575x_init(&chip->tea)) {
snd_printk(KERN_ERR "TEA575x radio not found\n");
- snd_fm801_free(chip);
return -ENODEV;
}
} else if ((tea575x_tuner & TUNER_TYPE_MASK) == 0) {
@@ -1251,11 +1252,15 @@ static int __devinit snd_fm801_create(struct snd_card *card,
}
if (tea575x_tuner == 4) {
snd_printk(KERN_ERR "TEA575x radio not found\n");
- snd_fm801_free(chip);
- return -ENODEV;
+ chip->tea575x_tuner = TUNER_DISABLED;
}
}
- strlcpy(chip->tea.card, snd_fm801_tea575x_gpios[(tea575x_tuner & TUNER_TYPE_MASK) - 1].name, sizeof(chip->tea.card));
+ if (!(chip->tea575x_tuner & TUNER_DISABLED)) {
+ strlcpy(chip->tea.card,
+ snd_fm801_tea575x_gpios[(tea575x_tuner &
+ TUNER_TYPE_MASK) - 1].name,
+ sizeof(chip->tea.card));
+ }
#endif
*rchip = chip;
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 3e7850c238c3..f3aefef37216 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -579,9 +579,13 @@ int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
return -1;
}
recursive++;
- for (i = 0; i < nums; i++)
+ for (i = 0; i < nums; i++) {
+ unsigned int type = get_wcaps_type(get_wcaps(codec, conn[i]));
+ if (type == AC_WID_PIN || type == AC_WID_AUD_OUT)
+ continue;
if (snd_hda_get_conn_index(codec, conn[i], nid, recursive) >= 0)
return i;
+ }
return -1;
}
EXPORT_SYMBOL_HDA(snd_hda_get_conn_index);
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index be6982289c0d..191284a1c0ae 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1924,7 +1924,8 @@ static unsigned int azx_via_get_position(struct azx *chip,
}
static unsigned int azx_get_position(struct azx *chip,
- struct azx_dev *azx_dev)
+ struct azx_dev *azx_dev,
+ bool with_check)
{
unsigned int pos;
int stream = azx_dev->substream->stream;
@@ -1940,7 +1941,7 @@ static unsigned int azx_get_position(struct azx *chip,
default:
/* use the position buffer */
pos = le32_to_cpu(*azx_dev->posbuf);
- if (chip->position_fix[stream] == POS_FIX_AUTO) {
+ if (with_check && chip->position_fix[stream] == POS_FIX_AUTO) {
if (!pos || pos == (u32)-1) {
printk(KERN_WARNING
"hda-intel: Invalid position buffer, "
@@ -1964,7 +1965,7 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
struct azx *chip = apcm->chip;
struct azx_dev *azx_dev = get_azx_dev(substream);
return bytes_to_frames(substream->runtime,
- azx_get_position(chip, azx_dev));
+ azx_get_position(chip, azx_dev, false));
}
/*
@@ -1987,7 +1988,7 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
return -1; /* bogus (too early) interrupt */
stream = azx_dev->substream->stream;
- pos = azx_get_position(chip, azx_dev);
+ pos = azx_get_position(chip, azx_dev, true);
if (WARN_ONCE(!azx_dev->period_bytes,
"hda-intel: zero azx_dev->period_bytes"))
@@ -2369,6 +2370,7 @@ static int azx_dev_free(struct snd_device *device)
static struct snd_pci_quirk position_fix_list[] __devinitdata = {
SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
+ SND_PCI_QUIRK(0x1028, 0x02c6, "Dell Inspiron 1010", POS_FIX_LPIB),
SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB),
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index d6c93d92b550..c45f3e69bcf0 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -535,7 +535,7 @@ static int add_volume(struct hda_codec *codec, const char *name,
int index, unsigned int pval, int dir,
struct snd_kcontrol **kctlp)
{
- char tmp[32];
+ char tmp[44];
struct snd_kcontrol_new knew =
HDA_CODEC_VOLUME_IDX(tmp, index, 0, 0, HDA_OUTPUT);
knew.private_value = pval;
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 502fc9499453..76752d8ea733 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -3110,6 +3110,7 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS),
SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD),
+ SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520 & W520", CXT5066_AUTO),
SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT5066_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS),
@@ -3348,6 +3349,8 @@ static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t pin,
#define MAX_AUTO_DACS 5
+#define DAC_SLAVE_FLAG 0x8000 /* filled dac is a slave */
+
/* fill analog DAC list from the widget tree */
static int fill_cx_auto_dacs(struct hda_codec *codec, hda_nid_t *dacs)
{
@@ -3370,16 +3373,26 @@ static int fill_cx_auto_dacs(struct hda_codec *codec, hda_nid_t *dacs)
/* fill pin_dac_pair list from the pin and dac list */
static int fill_dacs_for_pins(struct hda_codec *codec, hda_nid_t *pins,
int num_pins, hda_nid_t *dacs, int *rest,
- struct pin_dac_pair *filled, int type)
+ struct pin_dac_pair *filled, int nums,
+ int type)
{
- int i, nums;
+ int i, start = nums;
- nums = 0;
- for (i = 0; i < num_pins; i++) {
+ for (i = 0; i < num_pins; i++, nums++) {
filled[nums].pin = pins[i];
filled[nums].type = type;
filled[nums].dac = get_unassigned_dac(codec, pins[i], dacs, rest);
- nums++;
+ if (filled[nums].dac)
+ continue;
+ if (filled[start].dac && get_connection_index(codec, pins[i], filled[start].dac) >= 0) {
+ filled[nums].dac = filled[start].dac | DAC_SLAVE_FLAG;
+ continue;
+ }
+ if (filled[0].dac && get_connection_index(codec, pins[i], filled[0].dac) >= 0) {
+ filled[nums].dac = filled[0].dac | DAC_SLAVE_FLAG;
+ continue;
+ }
+ snd_printdd("Failed to find a DAC for pin 0x%x", pins[i]);
}
return nums;
}
@@ -3395,19 +3408,19 @@ static void cx_auto_parse_output(struct hda_codec *codec)
rest = fill_cx_auto_dacs(codec, dacs);
/* parse all analog output pins */
nums = fill_dacs_for_pins(codec, cfg->line_out_pins, cfg->line_outs,
- dacs, &rest, spec->dac_info,
- AUTO_PIN_LINE_OUT);
- nums += fill_dacs_for_pins(codec, cfg->hp_pins, cfg->hp_outs,
- dacs, &rest, spec->dac_info + nums,
- AUTO_PIN_HP_OUT);
- nums += fill_dacs_for_pins(codec, cfg->speaker_pins, cfg->speaker_outs,
- dacs, &rest, spec->dac_info + nums,
- AUTO_PIN_SPEAKER_OUT);
+ dacs, &rest, spec->dac_info, 0,
+ AUTO_PIN_LINE_OUT);
+ nums = fill_dacs_for_pins(codec, cfg->hp_pins, cfg->hp_outs,
+ dacs, &rest, spec->dac_info, nums,
+ AUTO_PIN_HP_OUT);
+ nums = fill_dacs_for_pins(codec, cfg->speaker_pins, cfg->speaker_outs,
+ dacs, &rest, spec->dac_info, nums,
+ AUTO_PIN_SPEAKER_OUT);
spec->dac_info_filled = nums;
/* fill multiout struct */
for (i = 0; i < nums; i++) {
hda_nid_t dac = spec->dac_info[i].dac;
- if (!dac)
+ if (!dac || (dac & DAC_SLAVE_FLAG))
continue;
switch (spec->dac_info[i].type) {
case AUTO_PIN_LINE_OUT:
@@ -3862,7 +3875,7 @@ static void cx_auto_parse_input(struct hda_codec *codec)
}
if (imux->num_items >= 2 && cfg->num_inputs == imux->num_items)
cx_auto_check_auto_mic(codec);
- if (imux->num_items > 1 && !spec->auto_mic) {
+ if (imux->num_items > 1) {
for (i = 1; i < imux->num_items; i++) {
if (spec->imux_info[i].adc != spec->imux_info[0].adc) {
spec->adc_switching = 1;
@@ -4035,6 +4048,8 @@ static void cx_auto_init_output(struct hda_codec *codec)
nid = spec->dac_info[i].dac;
if (!nid)
nid = spec->multiout.dac_nids[0];
+ else if (nid & DAC_SLAVE_FLAG)
+ nid &= ~DAC_SLAVE_FLAG;
select_connection(codec, spec->dac_info[i].pin, nid);
}
if (spec->auto_mute) {
@@ -4167,9 +4182,11 @@ static int try_add_pb_volume(struct hda_codec *codec, hda_nid_t dac,
hda_nid_t pin, const char *name, int idx)
{
unsigned int caps;
- caps = query_amp_caps(codec, dac, HDA_OUTPUT);
- if (caps & AC_AMPCAP_NUM_STEPS)
- return cx_auto_add_pb_volume(codec, dac, name, idx);
+ if (dac && !(dac & DAC_SLAVE_FLAG)) {
+ caps = query_amp_caps(codec, dac, HDA_OUTPUT);
+ if (caps & AC_AMPCAP_NUM_STEPS)
+ return cx_auto_add_pb_volume(codec, dac, name, idx);
+ }
caps = query_amp_caps(codec, pin, HDA_OUTPUT);
if (caps & AC_AMPCAP_NUM_STEPS)
return cx_auto_add_pb_volume(codec, pin, name, idx);
@@ -4191,8 +4208,7 @@ static int cx_auto_build_output_controls(struct hda_codec *codec)
for (i = 0; i < spec->dac_info_filled; i++) {
const char *label;
int idx, type;
- if (!spec->dac_info[i].dac)
- continue;
+ hda_nid_t dac = spec->dac_info[i].dac;
type = spec->dac_info[i].type;
if (type == AUTO_PIN_LINE_OUT)
type = spec->autocfg.line_out_type;
@@ -4211,7 +4227,7 @@ static int cx_auto_build_output_controls(struct hda_codec *codec)
idx = num_spk++;
break;
}
- err = try_add_pb_volume(codec, spec->dac_info[i].dac,
+ err = try_add_pb_volume(codec, dac,
spec->dac_info[i].pin,
label, idx);
if (err < 0)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index fcb11af9ad24..7a73621a8909 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -168,7 +168,7 @@ struct alc_spec {
unsigned int auto_mic_valid_imux:1; /* valid imux for auto-mic */
unsigned int automute:1; /* HP automute enabled */
unsigned int detect_line:1; /* Line-out detection enabled */
- unsigned int automute_lines:1; /* automute line-out as well */
+ unsigned int automute_lines:1; /* automute line-out as well; NOP when automute_hp_lo isn't set */
unsigned int automute_hp_lo:1; /* both HP and LO available */
/* other flags */
@@ -551,7 +551,7 @@ static void update_speakers(struct hda_codec *codec)
if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
return;
- if (!spec->automute_lines || !spec->automute)
+ if (!spec->automute || (spec->automute_hp_lo && !spec->automute_lines))
on = 0;
else
on = spec->jack_present;
@@ -565,11 +565,11 @@ static void alc_hp_automute(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- if (!spec->automute)
- return;
spec->jack_present =
detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
spec->autocfg.hp_pins);
+ if (!spec->automute)
+ return;
update_speakers(codec);
}
@@ -578,11 +578,15 @@ static void alc_line_automute(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- if (!spec->automute || !spec->detect_line)
+ /* check LO jack only when it's different from HP */
+ if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0])
return;
+
spec->line_jack_present =
detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
spec->autocfg.line_out_pins);
+ if (!spec->automute || !spec->detect_line)
+ return;
update_speakers(codec);
}
@@ -803,7 +807,7 @@ static int alc_automute_mode_get(struct snd_kcontrol *kcontrol,
unsigned int val;
if (!spec->automute)
val = 0;
- else if (!spec->automute_lines)
+ else if (!spec->automute_hp_lo || !spec->automute_lines)
val = 1;
else
val = 2;
@@ -824,7 +828,8 @@ static int alc_automute_mode_put(struct snd_kcontrol *kcontrol,
spec->automute = 0;
break;
case 1:
- if (spec->automute && !spec->automute_lines)
+ if (spec->automute &&
+ (!spec->automute_hp_lo || !spec->automute_lines))
return 0;
spec->automute = 1;
spec->automute_lines = 0;
@@ -1320,7 +1325,9 @@ do_sku:
* 15 : 1 --> enable the function "Mute internal speaker
* when the external headphone out jack is plugged"
*/
- if (!spec->autocfg.hp_pins[0]) {
+ if (!spec->autocfg.hp_pins[0] &&
+ !(spec->autocfg.line_out_pins[0] &&
+ spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)) {
hda_nid_t nid;
tmp = (ass >> 11) & 0x3; /* HP to chassis */
if (tmp == 0)
@@ -3083,16 +3090,22 @@ static void alc_auto_init_multi_out(struct hda_codec *codec)
static void alc_auto_init_extra_out(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- hda_nid_t pin;
+ hda_nid_t pin, dac;
pin = spec->autocfg.hp_pins[0];
- if (pin)
- alc_auto_set_output_and_unmute(codec, pin, PIN_HP,
- spec->multiout.hp_nid);
+ if (pin) {
+ dac = spec->multiout.hp_nid;
+ if (!dac)
+ dac = spec->multiout.dac_nids[0];
+ alc_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
+ }
pin = spec->autocfg.speaker_pins[0];
- if (pin)
- alc_auto_set_output_and_unmute(codec, pin, PIN_OUT,
- spec->multiout.extra_out_nid[0]);
+ if (pin) {
+ dac = spec->multiout.extra_out_nid[0];
+ if (!dac)
+ dac = spec->multiout.dac_nids[0];
+ alc_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
+ }
}
/*
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 5145b663ef6e..987e3cf71a0b 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -5630,6 +5630,7 @@ again:
switch (codec->vendor_id) {
case 0x111d76d1:
case 0x111d76d9:
+ case 0x111d76df:
case 0x111d76e5:
case 0x111d7666:
case 0x111d7667:
@@ -6573,6 +6574,7 @@ static const struct hda_codec_preset snd_hda_preset_sigmatel[] = {
{ .id = 0x111d76cc, .name = "92HD89F3", .patch = patch_stac92hd73xx },
{ .id = 0x111d76cd, .name = "92HD89F2", .patch = patch_stac92hd73xx },
{ .id = 0x111d76ce, .name = "92HD89F1", .patch = patch_stac92hd73xx },
+ { .id = 0x111d76df, .name = "92HD93BXX", .patch = patch_stac92hd83xxx},
{ .id = 0x111d76e0, .name = "92HD91BXX", .patch = patch_stac92hd83xxx},
{ .id = 0x111d76e3, .name = "92HD98BXX", .patch = patch_stac92hd83xxx},
{ .id = 0x111d76e5, .name = "92HD99BXX", .patch = patch_stac92hd83xxx},
diff --git a/sound/soc/blackfin/bf5xx-ad193x.c b/sound/soc/blackfin/bf5xx-ad193x.c
index d6651c033cb7..5956584ea3a4 100644
--- a/sound/soc/blackfin/bf5xx-ad193x.c
+++ b/sound/soc/blackfin/bf5xx-ad193x.c
@@ -56,7 +56,7 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
switch (params_rate(params)) {
case 48000:
- clk = 12288000;
+ clk = 24576000;
break;
}
@@ -103,7 +103,7 @@ static struct snd_soc_dai_link bf5xx_ad193x_dai[] = {
.cpu_dai_name = "bfin-tdm.0",
.codec_dai_name ="ad193x-hifi",
.platform_name = "bfin-tdm-pcm-audio",
- .codec_name = "ad193x.5",
+ .codec_name = "spi0.5",
.ops = &bf5xx_ad193x_ops,
},
{
@@ -112,7 +112,7 @@ static struct snd_soc_dai_link bf5xx_ad193x_dai[] = {
.cpu_dai_name = "bfin-tdm.1",
.codec_dai_name ="ad193x-hifi",
.platform_name = "bfin-tdm-pcm-audio",
- .codec_name = "ad193x.5",
+ .codec_name = "spi0.5",
.ops = &bf5xx_ad193x_ops,
},
};
diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c
index 732a247f2527..b94eb7ef7d16 100644
--- a/sound/soc/blackfin/bf5xx-ad73311.c
+++ b/sound/soc/blackfin/bf5xx-ad73311.c
@@ -128,7 +128,7 @@ static int snd_ad73311_configure(void)
return 0;
}
-static int bf5xx_probe(struct platform_device *pdev)
+static int bf5xx_probe(struct snd_soc_card *card)
{
int err;
if (gpio_request(GPIO_SE, "AD73311_SE")) {
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index 2374ca5ffe68..eedb6f5e5823 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -27,11 +27,6 @@ struct ad193x_priv {
int sysclk;
};
-/* ad193x register cache & default register settings */
-static const u8 ad193x_reg[AD193X_NUM_REGS] = {
- 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0,
-};
-
/*
* AD193X volume/mute/de-emphasis etc. controls
*/
@@ -307,7 +302,8 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, reg);
reg = snd_soc_read(codec, AD193X_DAC_CTRL2);
- reg = (reg & (~AD193X_DAC_WORD_LEN_MASK)) | word_len;
+ reg = (reg & (~AD193X_DAC_WORD_LEN_MASK))
+ | (word_len << AD193X_DAC_WORD_LEN_SHFT);
snd_soc_write(codec, AD193X_DAC_CTRL2, reg);
reg = snd_soc_read(codec, AD193X_ADC_CTRL1);
@@ -389,9 +385,6 @@ static int ad193x_probe(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver soc_codec_dev_ad193x = {
.probe = ad193x_probe,
- .reg_cache_default = ad193x_reg,
- .reg_cache_size = AD193X_NUM_REGS,
- .reg_word_size = sizeof(u16),
};
#if defined(CONFIG_SPI_MASTER)
diff --git a/sound/soc/codecs/ad193x.h b/sound/soc/codecs/ad193x.h
index 9747b5497877..cccc2e8e5fbd 100644
--- a/sound/soc/codecs/ad193x.h
+++ b/sound/soc/codecs/ad193x.h
@@ -34,7 +34,8 @@
#define AD193X_DAC_LEFT_HIGH (1 << 3)
#define AD193X_DAC_BCLK_INV (1 << 7)
#define AD193X_DAC_CTRL2 0x804
-#define AD193X_DAC_WORD_LEN_MASK 0xC
+#define AD193X_DAC_WORD_LEN_SHFT 3
+#define AD193X_DAC_WORD_LEN_MASK 0x18
#define AD193X_DAC_MASTER_MUTE 1
#define AD193X_DAC_CHNL_MUTE 0x805
#define AD193X_DACL1_MUTE 0
@@ -63,7 +64,7 @@
#define AD193X_ADC_CTRL1 0x80f
#define AD193X_ADC_SERFMT_MASK 0x60
#define AD193X_ADC_SERFMT_STEREO (0 << 5)
-#define AD193X_ADC_SERFMT_TDM (1 << 2)
+#define AD193X_ADC_SERFMT_TDM (1 << 5)
#define AD193X_ADC_SERFMT_AUX (2 << 5)
#define AD193X_ADC_WORD_LEN_MASK 0x3
#define AD193X_ADC_CTRL2 0x810
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 84f4ad568556..9801cd7cfcb5 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -431,7 +431,8 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- u16 reg = snd_soc_read(codec, SSM2602_PWR) & 0xff7f;
+ u16 reg = snd_soc_read(codec, SSM2602_PWR);
+ reg &= ~(PWR_POWER_OFF | PWR_OSC_PDN);
switch (level) {
case SND_SOC_BIAS_ON:
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index 409d89d1f34c..fbd7eb9e61ce 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -857,6 +857,7 @@ static __devinit int sta32x_i2c_probe(struct i2c_client *i2c,
ret = snd_soc_register_codec(&i2c->dev, &sta32x_codec, &sta32x_dai, 1);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to register codec (%d)\n", ret);
+ kfree(sta32x);
return ret;
}
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index ffa2ffe5ec11..aa091a0d8187 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -1454,8 +1454,8 @@ static int wm8753_probe(struct snd_soc_codec *codec)
/* set the update bits */
snd_soc_update_bits(codec, WM8753_LDAC, 0x0100, 0x0100);
snd_soc_update_bits(codec, WM8753_RDAC, 0x0100, 0x0100);
- snd_soc_update_bits(codec, WM8753_LDAC, 0x0100, 0x0100);
- snd_soc_update_bits(codec, WM8753_RDAC, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8753_LADC, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, WM8753_RADC, 0x0100, 0x0100);
snd_soc_update_bits(codec, WM8753_LOUT1V, 0x0100, 0x0100);
snd_soc_update_bits(codec, WM8753_ROUT1V, 0x0100, 0x0100);
snd_soc_update_bits(codec, WM8753_LOUT2V, 0x0100, 0x0100);
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 60d740ebeb5b..d2c315fa1b9b 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -2221,6 +2221,8 @@ static int sysclk_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
if (fll) {
+ try_wait_for_completion(&wm8962->fll_lock);
+
snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
WM8962_FLL_ENA, WM8962_FLL_ENA);
if (wm8962->irq) {
@@ -2927,10 +2929,6 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec,
WM8962_BIAS_ENA | 0x180);
msleep(5);
-
- snd_soc_update_bits(codec, WM8962_CLOCKING2,
- WM8962_CLKREG_OVD,
- WM8962_CLKREG_OVD);
}
/* VMID 2*250k */
@@ -3288,6 +3286,8 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
snd_soc_write(codec, WM8962_FLL_CONTROL_7, fll_div.lambda);
snd_soc_write(codec, WM8962_FLL_CONTROL_8, fll_div.n);
+ try_wait_for_completion(&wm8962->fll_lock);
+
snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
WM8962_FLL_FRAC | WM8962_FLL_REFCLK_SRC_MASK |
WM8962_FLL_ENA, fll1);
@@ -3479,31 +3479,6 @@ int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
}
EXPORT_SYMBOL_GPL(wm8962_mic_detect);
-#ifdef CONFIG_PM
-static int wm8962_resume(struct snd_soc_codec *codec)
-{
- u16 *reg_cache = codec->reg_cache;
- int i;
-
- /* Restore the registers */
- for (i = 1; i < codec->driver->reg_cache_size; i++) {
- switch (i) {
- case WM8962_SOFTWARE_RESET:
- continue;
- default:
- break;
- }
-
- if (reg_cache[i] != wm8962_reg[i])
- snd_soc_write(codec, i, reg_cache[i]);
- }
-
- return 0;
-}
-#else
-#define wm8962_resume NULL
-#endif
-
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
static int beep_rates[] = {
500, 1000, 2000, 4000,
@@ -3868,6 +3843,10 @@ static int wm8962_probe(struct snd_soc_codec *codec)
*/
snd_soc_update_bits(codec, WM8962_CLOCKING2, WM8962_SYSCLK_ENA, 0);
+ /* Ensure we have soft control over all registers */
+ snd_soc_update_bits(codec, WM8962_CLOCKING2,
+ WM8962_CLKREG_OVD, WM8962_CLKREG_OVD);
+
regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
if (pdata) {
@@ -4011,7 +3990,6 @@ static int wm8962_remove(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver soc_codec_dev_wm8962 = {
.probe = wm8962_probe,
.remove = wm8962_remove,
- .resume = wm8962_resume,
.set_bias_level = wm8962_set_bias_level,
.reg_cache_size = WM8962_MAX_REGISTER + 1,
.reg_word_size = sizeof(u16),
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index ab8e9d1aaff0..0cdb9d105671 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -420,7 +420,7 @@ static const char *sidetone_hpf_text[] = {
};
static const struct soc_enum sidetone_hpf =
- SOC_ENUM_SINGLE(WM8996_SIDETONE, 7, 6, sidetone_hpf_text);
+ SOC_ENUM_SINGLE(WM8996_SIDETONE, 7, 7, sidetone_hpf_text);
static const char *hpf_mode_text[] = {
"HiFi", "Custom", "Voice"
@@ -988,15 +988,10 @@ SND_SOC_DAPM_MICBIAS("MICB1", WM8996_POWER_MANAGEMENT_1, 8, 0),
SND_SOC_DAPM_PGA("IN1L PGA", WM8996_POWER_MANAGEMENT_2, 5, 0, NULL, 0),
SND_SOC_DAPM_PGA("IN1R PGA", WM8996_POWER_MANAGEMENT_2, 4, 0, NULL, 0),
-SND_SOC_DAPM_MUX("IN1L Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
-SND_SOC_DAPM_MUX("IN1R Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
-SND_SOC_DAPM_MUX("IN2L Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
-SND_SOC_DAPM_MUX("IN2R Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
-
-SND_SOC_DAPM_PGA("IN1L", WM8996_POWER_MANAGEMENT_7, 2, 0, NULL, 0),
-SND_SOC_DAPM_PGA("IN1R", WM8996_POWER_MANAGEMENT_7, 3, 0, NULL, 0),
-SND_SOC_DAPM_PGA("IN2L", WM8996_POWER_MANAGEMENT_7, 6, 0, NULL, 0),
-SND_SOC_DAPM_PGA("IN2R", WM8996_POWER_MANAGEMENT_7, 7, 0, NULL, 0),
+SND_SOC_DAPM_MUX("IN1L Mux", WM8996_POWER_MANAGEMENT_7, 2, 0, &in1_mux),
+SND_SOC_DAPM_MUX("IN1R Mux", WM8996_POWER_MANAGEMENT_7, 3, 0, &in1_mux),
+SND_SOC_DAPM_MUX("IN2L Mux", WM8996_POWER_MANAGEMENT_7, 6, 0, &in2_mux),
+SND_SOC_DAPM_MUX("IN2R Mux", WM8996_POWER_MANAGEMENT_7, 7, 0, &in2_mux),
SND_SOC_DAPM_SUPPLY("DMIC2", WM8996_POWER_MANAGEMENT_7, 9, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("DMIC1", WM8996_POWER_MANAGEMENT_7, 8, 0, NULL, 0),
@@ -1213,6 +1208,16 @@ static const struct snd_soc_dapm_route wm8996_dapm_routes[] = {
{ "AIF2RX0", NULL, "AIFCLK" },
{ "AIF2RX1", NULL, "AIFCLK" },
+ { "AIF1TX0", NULL, "AIFCLK" },
+ { "AIF1TX1", NULL, "AIFCLK" },
+ { "AIF1TX2", NULL, "AIFCLK" },
+ { "AIF1TX3", NULL, "AIFCLK" },
+ { "AIF1TX4", NULL, "AIFCLK" },
+ { "AIF1TX5", NULL, "AIFCLK" },
+
+ { "AIF2TX0", NULL, "AIFCLK" },
+ { "AIF2TX1", NULL, "AIFCLK" },
+
{ "DSP1RXL", NULL, "SYSDSPCLK" },
{ "DSP1RXR", NULL, "SYSDSPCLK" },
{ "DSP2RXL", NULL, "SYSDSPCLK" },
@@ -2106,6 +2111,9 @@ static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
snd_soc_write(codec, WM8996_FLL_EFS_1, fll_div.lambda);
+ /* Clear any pending completions (eg, from failed startups) */
+ try_wait_for_completion(&wm8996->fll_lock);
+
snd_soc_update_bits(codec, WM8996_FLL_CONTROL_1,
WM8996_FLL_ENA, WM8996_FLL_ENA);
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
index 6bbf001f6591..9e11a14d1b45 100644
--- a/sound/soc/davinci/Kconfig
+++ b/sound/soc/davinci/Kconfig
@@ -29,7 +29,6 @@ choice
prompt "DM365 codec select"
depends on SND_DAVINCI_SOC_EVM
depends on MACH_DAVINCI_DM365_EVM
- default SND_DM365_EXTERNAL_CODEC
config SND_DM365_AIC3X_CODEC
bool "Audio Codec - AIC3101"
diff --git a/sound/soc/ep93xx/ep93xx-i2s.c b/sound/soc/ep93xx/ep93xx-i2s.c
index 56efa0c1c9a9..099614e16651 100644
--- a/sound/soc/ep93xx/ep93xx-i2s.c
+++ b/sound/soc/ep93xx/ep93xx-i2s.c
@@ -385,14 +385,14 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
err = -ENODEV;
- goto fail;
+ goto fail_free_info;
}
info->mem = request_mem_region(res->start, resource_size(res),
pdev->name);
if (!info->mem) {
err = -EBUSY;
- goto fail;
+ goto fail_free_info;
}
info->regs = ioremap(info->mem->start, resource_size(info->mem));
@@ -435,6 +435,7 @@ fail_unmap_mem:
iounmap(info->regs);
fail_release_mem:
release_mem_region(info->mem->start, resource_size(info->mem));
+fail_free_info:
kfree(info);
fail:
return err;
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index 732208c8c0b4..cb50598338e9 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -879,10 +879,12 @@ static struct device_node *find_ssi_node(struct device_node *dma_channel_np)
* assume that device_node pointers are a valid comparison.
*/
np = of_parse_phandle(ssi_np, "fsl,playback-dma", 0);
+ of_node_put(np);
if (np == dma_channel_np)
return ssi_np;
np = of_parse_phandle(ssi_np, "fsl,capture-dma", 0);
+ of_node_put(np);
if (np == dma_channel_np)
return ssi_np;
}
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index fd0dc46afc34..5c6c2457386e 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -369,7 +369,7 @@ static struct snd_soc_platform_driver mpc5200_audio_dma_platform = {
.pcm_free = &psc_dma_free,
};
-static int mpc5200_hpcd_probe(struct of_device *op)
+static int mpc5200_hpcd_probe(struct platform_device *op)
{
phys_addr_t fifo;
struct psc_dma *psc_dma;
@@ -487,7 +487,7 @@ out_unmap:
return ret;
}
-static int mpc5200_hpcd_remove(struct of_device *op)
+static int mpc5200_hpcd_remove(struct platform_device *op)
{
struct psc_dma *psc_dma = dev_get_drvdata(&op->dev);
@@ -519,7 +519,7 @@ MODULE_DEVICE_TABLE(of, mpc5200_hpcd_match);
static struct platform_driver mpc5200_hpcd_of_driver = {
.probe = mpc5200_hpcd_probe,
.remove = mpc5200_hpcd_remove,
- .dev = {
+ .driver = {
.owner = THIS_MODULE,
.name = "mpc5200-pcm-audio",
.of_match_table = mpc5200_hpcd_match,
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index a19297959587..358f0baaf71b 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -345,8 +345,10 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
}
machine_data = kzalloc(sizeof(struct mpc8610_hpcd_data), GFP_KERNEL);
- if (!machine_data)
- return -ENOMEM;
+ if (!machine_data) {
+ ret = -ENOMEM;
+ goto error_alloc;
+ }
machine_data->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev);
machine_data->dai[0].ops = &mpc8610_hpcd_ops;
@@ -494,7 +496,7 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
ret = platform_device_add(sound_device);
if (ret) {
dev_err(&pdev->dev, "platform device add failed\n");
- goto error;
+ goto error_sound;
}
dev_set_drvdata(&pdev->dev, sound_device);
@@ -502,14 +504,12 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
return 0;
+error_sound:
+ platform_device_unregister(sound_device);
error:
- of_node_put(codec_np);
-
- if (sound_device)
- platform_device_unregister(sound_device);
-
kfree(machine_data);
-
+error_alloc:
+ of_node_put(codec_np);
return ret;
}
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c
index 8fa4d5f8eda1..fcb862eb0c73 100644
--- a/sound/soc/fsl/p1022_ds.c
+++ b/sound/soc/fsl/p1022_ds.c
@@ -297,8 +297,10 @@ static int get_dma_channel(struct device_node *ssi_np,
* dai->platform name should already point to an allocated buffer.
*/
ret = of_address_to_resource(dma_channel_np, 0, &res);
- if (ret)
+ if (ret) {
+ of_node_put(dma_channel_np);
return ret;
+ }
snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
(unsigned long long) res.start, dma_channel_np->name);
diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/imx/imx-pcm-fiq.c
index 309c59e6fb6c..7945625e0e08 100644
--- a/sound/soc/imx/imx-pcm-fiq.c
+++ b/sound/soc/imx/imx-pcm-fiq.c
@@ -240,7 +240,6 @@ static int ssi_irq = 0;
static int imx_pcm_fiq_new(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_card *card = rtd->card->snd_card;
struct snd_soc_dai *dai = rtd->cpu_dai;
struct snd_pcm *pcm = rtd->pcm;
int ret;
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
index a33fc51f363b..d0bcf3fcea01 100644
--- a/sound/soc/kirkwood/kirkwood-i2s.c
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -424,7 +424,7 @@ static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
if (!priv->mem) {
dev_err(&pdev->dev, "request_mem_region failed\n");
err = -EBUSY;
- goto error;
+ goto err_alloc;
}
priv->io = ioremap(priv->mem->start, SZ_16K);
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index 30fe0d0efe1c..0aa475f92efa 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -514,7 +514,7 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
}
/* Set codec bias level */
- ams_delta_set_bias_level(card, SND_SOC_BIAS_STANDBY);
+ ams_delta_set_bias_level(card, dapm, SND_SOC_BIAS_STANDBY);
/* Add hook switch - can be used to control the codec from userspace
* even if line discipline fails */
@@ -649,7 +649,9 @@ static void __exit ams_delta_module_exit(void)
ams_delta_hook_switch_gpios);
/* Keep modem power on */
- ams_delta_set_bias_level(&ams_delta_audio_card, SND_SOC_BIAS_STANDBY);
+ ams_delta_set_bias_level(&ams_delta_audio_card,
+ &ams_delta_audio_card.rtd[0].codec->dapm,
+ SND_SOC_BIAS_STANDBY);
platform_device_unregister(cx20442_platform_device);
platform_device_unregister(ams_delta_audio_platform_device);
diff --git a/sound/soc/omap/mcpdm.c b/sound/soc/omap/mcpdm.c
index 928f03707451..50e59194ad81 100644
--- a/sound/soc/omap/mcpdm.c
+++ b/sound/soc/omap/mcpdm.c
@@ -449,7 +449,7 @@ exit:
return ret;
}
-int __devexit omap_mcpdm_remove(struct platform_device *pdev)
+int omap_mcpdm_remove(struct platform_device *pdev)
{
struct omap_mcpdm *mcpdm_ptr = platform_get_drvdata(pdev);
diff --git a/sound/soc/omap/mcpdm.h b/sound/soc/omap/mcpdm.h
index df3e16fb51f3..20c20a8649fe 100644
--- a/sound/soc/omap/mcpdm.h
+++ b/sound/soc/omap/mcpdm.h
@@ -150,4 +150,4 @@ extern int omap_mcpdm_request(void);
extern void omap_mcpdm_free(void);
extern int omap_mcpdm_set_offset(int offset1, int offset2);
int __devinit omap_mcpdm_probe(struct platform_device *pdev);
-int __devexit omap_mcpdm_remove(struct platform_device *pdev);
+int omap_mcpdm_remove(struct platform_device *pdev);
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index ebcc2d4d2b18..478d60778453 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -516,6 +516,12 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
int err = 0;
+ if (mcbsp_data->active)
+ if (freq == mcbsp_data->in_freq)
+ return 0;
+ else
+ return -EBUSY;
+
/* The McBSP signal muxing functions are only available on McBSP1 */
if (clk_id == OMAP_MCBSP_CLKR_SRC_CLKR ||
clk_id == OMAP_MCBSP_CLKR_SRC_CLKX ||
diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c
index b6445757fc54..2b8350b52232 100644
--- a/sound/soc/pxa/zylonite.c
+++ b/sound/soc/pxa/zylonite.c
@@ -196,20 +196,20 @@ static int zylonite_probe(struct snd_soc_card *card)
if (clk_pout) {
pout = clk_get(NULL, "CLK_POUT");
if (IS_ERR(pout)) {
- dev_err(&pdev->dev, "Unable to obtain CLK_POUT: %ld\n",
+ dev_err(card->dev, "Unable to obtain CLK_POUT: %ld\n",
PTR_ERR(pout));
return PTR_ERR(pout);
}
ret = clk_enable(pout);
if (ret != 0) {
- dev_err(&pdev->dev, "Unable to enable CLK_POUT: %d\n",
+ dev_err(card->dev, "Unable to enable CLK_POUT: %d\n",
ret);
clk_put(pout);
return ret;
}
- dev_dbg(&pdev->dev, "MCLK enabled at %luHz\n",
+ dev_dbg(card->dev, "MCLK enabled at %luHz\n",
clk_get_rate(pout));
}
@@ -241,7 +241,7 @@ static int zylonite_resume_pre(struct snd_soc_card *card)
if (clk_pout) {
ret = clk_enable(pout);
if (ret != 0)
- dev_err(&pdev->dev, "Unable to enable CLK_POUT: %d\n",
+ dev_err(card->dev, "Unable to enable CLK_POUT: %d\n",
ret);
}
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index b99091fc34eb..65f980ef2870 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -185,6 +185,7 @@ config SND_SOC_SPEYSIDE
select SND_SAMSUNG_I2S
select SND_SOC_WM8996
select SND_SOC_WM9081
+ select SND_SOC_WM1250_EV1
config SND_SOC_SPEYSIDE_WM8962
tristate "Audio support for Wolfson Speyside with WM8962"
diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c
index 241f55d00660..c6c65892294e 100644
--- a/sound/soc/samsung/h1940_uda1380.c
+++ b/sound/soc/samsung/h1940_uda1380.c
@@ -13,6 +13,7 @@
*
*/
+#include <linux/types.h>
#include <linux/gpio.h>
#include <sound/soc.h>
diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c
index 1e574a5d440d..bc8c1676459f 100644
--- a/sound/soc/samsung/rx1950_uda1380.c
+++ b/sound/soc/samsung/rx1950_uda1380.c
@@ -17,6 +17,7 @@
*
*/
+#include <linux/types.h>
#include <linux/gpio.h>
#include <sound/soc.h>
diff --git a/sound/soc/samsung/speyside_wm8962.c b/sound/soc/samsung/speyside_wm8962.c
index 0b9eb5f7ec4c..72535f2daaf2 100644
--- a/sound/soc/samsung/speyside_wm8962.c
+++ b/sound/soc/samsung/speyside_wm8962.c
@@ -23,6 +23,9 @@ static int speyside_wm8962_set_bias_level(struct snd_soc_card *card,
struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
int ret;
+ if (dapm->dev != codec_dai->dev)
+ return 0;
+
switch (level) {
case SND_SOC_BIAS_PREPARE:
if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
@@ -57,6 +60,9 @@ static int speyside_wm8962_set_bias_level_post(struct snd_soc_card *card,
struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
int ret;
+ if (dapm->dev != codec_dai->dev)
+ return 0;
+
switch (level) {
case SND_SOC_BIAS_STANDBY:
ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK,
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
index d9f8aded51f3..20b7f3b003a3 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -203,14 +203,14 @@ static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)
rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
for (i = 0; i < rbnode->blklen; ++i) {
regtmp = rbnode->base_reg + i;
- WARN_ON(codec->writable_register &&
- codec->writable_register(codec, regtmp));
val = snd_soc_rbtree_get_register(rbnode, i);
def = snd_soc_get_cache_val(codec->reg_def_copy, i,
rbnode->word_size);
if (val == def)
continue;
+ WARN_ON(!snd_soc_codec_writable_register(codec, regtmp));
+
codec->cache_bypass = 1;
ret = snd_soc_write(codec, regtmp, val);
codec->cache_bypass = 0;
@@ -563,8 +563,7 @@ static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec)
lzo_blocks = codec->reg_cache;
for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) {
- WARN_ON(codec->writable_register &&
- codec->writable_register(codec, i));
+ WARN_ON(!snd_soc_codec_writable_register(codec, i));
ret = snd_soc_cache_read(codec, i, &val);
if (ret)
return ret;
@@ -823,8 +822,6 @@ static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
codec_drv = codec->driver;
for (i = 0; i < codec_drv->reg_cache_size; ++i) {
- WARN_ON(codec->writable_register &&
- codec->writable_register(codec, i));
ret = snd_soc_cache_read(codec, i, &val);
if (ret)
return ret;
@@ -832,6 +829,9 @@ static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
if (snd_soc_get_cache_val(codec->reg_def_copy,
i, codec_drv->reg_word_size) == val)
continue;
+
+ WARN_ON(!snd_soc_codec_writable_register(codec, i));
+
ret = snd_soc_write(codec, i, val);
if (ret)
return ret;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 83ad8ca27490..ef69f5a02709 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -30,6 +30,7 @@
#include <linux/bitops.h>
#include <linux/debugfs.h>
#include <linux/platform_device.h>
+#include <linux/ctype.h>
#include <linux/slab.h>
#include <sound/ac97_codec.h>
#include <sound/core.h>
@@ -1434,9 +1435,20 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
"%s", card->name);
snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
"%s", card->long_name ? card->long_name : card->name);
- if (card->driver_name)
- strlcpy(card->snd_card->driver, card->driver_name,
- sizeof(card->snd_card->driver));
+ snprintf(card->snd_card->driver, sizeof(card->snd_card->driver),
+ "%s", card->driver_name ? card->driver_name : card->name);
+ for (i = 0; i < ARRAY_SIZE(card->snd_card->driver); i++) {
+ switch (card->snd_card->driver[i]) {
+ case '_':
+ case '-':
+ case '\0':
+ break;
+ default:
+ if (!isalnum(card->snd_card->driver[i]))
+ card->snd_card->driver[i] = '_';
+ break;
+ }
+ }
if (card->late_probe) {
ret = card->late_probe(card);
@@ -1633,7 +1645,7 @@ int snd_soc_codec_readable_register(struct snd_soc_codec *codec,
if (codec->readable_register)
return codec->readable_register(codec, reg);
else
- return 0;
+ return 1;
}
EXPORT_SYMBOL_GPL(snd_soc_codec_readable_register);
@@ -1651,7 +1663,7 @@ int snd_soc_codec_writable_register(struct snd_soc_codec *codec,
if (codec->writable_register)
return codec->writable_register(codec, reg);
else
- return 0;
+ return 1;
}
EXPORT_SYMBOL_GPL(snd_soc_codec_writable_register);
@@ -1913,7 +1925,7 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
if (prefix) {
name_len = strlen(long_name) + strlen(prefix) + 2;
- name = kmalloc(name_len, GFP_ATOMIC);
+ name = kmalloc(name_len, GFP_KERNEL);
if (!name)
return NULL;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 7e15914b3633..d67c637557a7 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2763,7 +2763,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
/**
* snd_soc_dapm_free - free dapm resources
- * @card: SoC device
+ * @dapm: DAPM context
*
* Free all dapm widgets and resources.
*/
diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c
index cca490c80589..a62f7dd4ba96 100644
--- a/sound/soc/soc-io.c
+++ b/sound/soc/soc-io.c
@@ -205,6 +205,25 @@ static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
#define snd_soc_16_8_read_i2c NULL
#endif
+#if defined(CONFIG_SPI_MASTER)
+static unsigned int snd_soc_16_8_read_spi(struct snd_soc_codec *codec,
+ unsigned int r)
+{
+ struct spi_device *spi = codec->control_data;
+
+ const u16 reg = cpu_to_be16(r | 0x100);
+ u8 data;
+ int ret;
+
+ ret = spi_write_then_read(spi, &reg, 2, &data, 1);
+ if (ret < 0)
+ return 0;
+ return data;
+}
+#else
+#define snd_soc_16_8_read_spi NULL
+#endif
+
static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
@@ -295,6 +314,7 @@ static struct {
int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
+ unsigned int (*spi_read)(struct snd_soc_codec *, unsigned int);
} io_types[] = {
{
.addr_bits = 4, .data_bits = 12,
@@ -318,6 +338,7 @@ static struct {
.addr_bits = 16, .data_bits = 8,
.write = snd_soc_16_8_write,
.i2c_read = snd_soc_16_8_read_i2c,
+ .spi_read = snd_soc_16_8_read_spi,
},
{
.addr_bits = 16, .data_bits = 16,
@@ -383,6 +404,8 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
#ifdef CONFIG_SPI_MASTER
codec->hw_write = do_spi_write;
#endif
+ if (io_types[i].spi_read)
+ codec->hw_read = io_types[i].spi_read;
codec->control_data = container_of(codec->dev,
struct spi_device,
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index 7c17b98d5846..fa31d9c2abd8 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -105,7 +105,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
snd_soc_dapm_sync(dapm);
- snd_jack_report(jack->jack, status);
+ snd_jack_report(jack->jack, jack->status);
out:
mutex_unlock(&codec->mutex);
@@ -327,7 +327,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
IRQF_TRIGGER_FALLING,
gpios[i].name,
&gpios[i]);
- if (ret)
+ if (ret < 0)
goto err;
if (gpios[i].wake) {
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index b5759397afa3..2879c883eebc 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -290,6 +290,9 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
codec_dai->active--;
codec->active--;
+ if (!cpu_dai->active && !codec_dai->active)
+ rtd->rate = 0;
+
/* Muting the DAC suppresses artifacts caused during digital
* shutdown, for example from stopping clocks.
*/
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index 661373c2352a..be27f1d229af 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -319,7 +319,7 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
/* FIXME: Calculate automatically based on DAPM routes? */
- if (!machine_is_harmony() && !machine_is_ventana())
+ if (!machine_is_harmony())
snd_soc_dapm_nc_pin(dapm, "IN1L");
if (!machine_is_seaboard() && !machine_is_aebl())
snd_soc_dapm_nc_pin(dapm, "IN1R");
@@ -395,7 +395,7 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, machine);
- if (machine_is_harmony() || machine_is_ventana()) {
+ if (machine_is_harmony()) {
card->dapm_routes = harmony_audio_map;
card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map);
} else if (machine_is_seaboard()) {
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 781d9e61adfb..3068f043099a 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -530,8 +530,11 @@ snd_usb_audio_probe(struct usb_device *dev,
return chip;
__error:
- if (chip && !chip->num_interfaces)
- snd_card_free(chip->card);
+ if (chip) {
+ if (!chip->num_interfaces)
+ snd_card_free(chip->card);
+ chip->probing = 0;
+ }
mutex_unlock(&register_mutex);
__err_val:
return NULL;
@@ -628,7 +631,7 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
if (chip == (void *)-1L)
return 0;
- if (!(message.event & PM_EVENT_AUTO)) {
+ if (!PMSG_IS_AUTO(message)) {
snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
if (!chip->num_suspended_intf++) {
list_for_each(p, &chip->pcm_list) {
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 3b8f7b80376b..e9d5c271db69 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -30,6 +30,8 @@ endif
# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.
#
# Define NO_DWARF if you do not want debug-info analysis feature at all.
+#
+# Define WERROR=0 to disable treating any warnings as errors.
$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
@$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
@@ -63,6 +65,11 @@ ifeq ($(ARCH),x86_64)
endif
endif
+# Treat warnings as errors unless directed not to
+ifneq ($(WERROR),0)
+ CFLAGS_WERROR := -Werror
+endif
+
#
# Include saner warnings here, which can catch bugs:
#
@@ -95,7 +102,7 @@ ifndef PERF_DEBUG
CFLAGS_OPTIMIZE = -O6
endif
-CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
+CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
EXTLIBS = -lpthread -lrt -lelf -lm
ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
ALL_LDFLAGS = $(LDFLAGS)
diff --git a/tools/perf/arch/arm/util/dwarf-regs.c b/tools/perf/arch/arm/util/dwarf-regs.c
index fff6450c8c99..e8d5c551c69c 100644
--- a/tools/perf/arch/arm/util/dwarf-regs.c
+++ b/tools/perf/arch/arm/util/dwarf-regs.c
@@ -8,7 +8,10 @@
* published by the Free Software Foundation.
*/
+#include <stdlib.h>
+#ifndef __UCLIBC__
#include <libio.h>
+#endif
#include <dwarf-regs.h>
struct pt_regs_dwarfnum {
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 6b0519f885e4..f4c3fbee4bad 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -161,6 +161,7 @@ static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist)
struct perf_event_attr *attr = &evsel->attr;
int track = !evsel->idx; /* only the first counter needs these */
+ attr->disabled = 1;
attr->inherit = !no_inherit;
attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
PERF_FORMAT_TOTAL_TIME_RUNNING |
@@ -671,6 +672,8 @@ static int __cmd_record(int argc, const char **argv)
}
}
+ perf_evlist__enable(evsel_list);
+
/*
* Let the child rip
*/
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 55f4c76f2821..efe696f936e2 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -561,7 +561,7 @@ static int test__basic_mmap(void)
}
err = perf_event__parse_sample(event, attr.sample_type, sample_size,
- false, &sample);
+ false, &sample, false);
if (err) {
pr_err("Can't parse sample, err = %d\n", err);
goto out_munmap;
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index a43433f08300..d28013b7d61c 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -191,7 +191,8 @@ static void __zero_source_counters(struct sym_entry *syme)
symbol__annotate_zero_histograms(sym);
}
-static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
+static void record_precise_ip(struct sym_entry *syme, struct map *map,
+ int counter, u64 ip)
{
struct annotation *notes;
struct symbol *sym;
@@ -205,8 +206,8 @@ static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
if (pthread_mutex_trylock(&notes->lock))
return;
- ip = syme->map->map_ip(syme->map, ip);
- symbol__inc_addr_samples(sym, syme->map, counter, ip);
+ ip = map->map_ip(map, ip);
+ symbol__inc_addr_samples(sym, map, counter, ip);
pthread_mutex_unlock(&notes->lock);
}
@@ -810,7 +811,7 @@ static void perf_event__process_sample(const union perf_event *event,
evsel = perf_evlist__id2evsel(top.evlist, sample->id);
assert(evsel != NULL);
syme->count[evsel->idx]++;
- record_precise_ip(syme, evsel->idx, ip);
+ record_precise_ip(syme, al.map, evsel->idx, ip);
pthread_mutex_lock(&top.active_symbols_lock);
if (list_empty(&syme->node) || !syme->node.next) {
static bool first = true;
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index fe02903f7d0f..80d9598db31a 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -341,7 +341,7 @@ const char *perf_config_dirname(const char *name, const char *value)
static int perf_default_core_config(const char *var __used, const char *value __used)
{
- /* Add other config variables here and to Documentation/config.txt. */
+ /* Add other config variables here. */
return 0;
}
@@ -350,7 +350,7 @@ int perf_default_config(const char *var, const char *value, void *dummy __used)
if (!prefixcmp(var, "core."))
return perf_default_core_config(var, value);
- /* Add other config variables here and to Documentation/config.txt. */
+ /* Add other config variables here. */
return 0;
}
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 3c1b8a632101..437f8ca679a0 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -169,12 +169,17 @@ static int perf_event__synthesize_mmap_events(union perf_event *event,
continue;
pbf += n + 3;
if (*pbf == 'x') { /* vm_exec */
+ char anonstr[] = "//anon\n";
char *execname = strchr(bf, '/');
/* Catch VDSO */
if (execname == NULL)
execname = strstr(bf, "[vdso]");
+ /* Catch anonymous mmaps */
+ if ((execname == NULL) && !strstr(bf, "["))
+ execname = anonstr;
+
if (execname == NULL)
continue;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 1d7f66488a88..357a85b85248 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -186,6 +186,6 @@ const char *perf_event__name(unsigned int id);
int perf_event__parse_sample(const union perf_event *event, u64 type,
int sample_size, bool sample_id_all,
- struct perf_sample *sample);
+ struct perf_sample *sample, bool swapped);
#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index c12bd476c6f7..72e9f4886b6d 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -113,6 +113,19 @@ void perf_evlist__disable(struct perf_evlist *evlist)
}
}
+void perf_evlist__enable(struct perf_evlist *evlist)
+{
+ int cpu, thread;
+ struct perf_evsel *pos;
+
+ for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
+ list_for_each_entry(pos, &evlist->entries, node) {
+ for (thread = 0; thread < evlist->threads->nr; thread++)
+ ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_ENABLE);
+ }
+ }
+}
+
int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
{
int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index ce85ae9ae57a..f34915002745 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -54,6 +54,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite);
void perf_evlist__munmap(struct perf_evlist *evlist);
void perf_evlist__disable(struct perf_evlist *evlist);
+void perf_evlist__enable(struct perf_evlist *evlist);
static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
struct cpu_map *cpus,
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index a03a36b7908a..e389815078d3 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -7,6 +7,8 @@
* Released under the GPL v2. (and only v2, not any later version)
*/
+#include <byteswap.h>
+#include "asm/bug.h"
#include "evsel.h"
#include "evlist.h"
#include "util.h"
@@ -342,10 +344,20 @@ static bool sample_overlap(const union perf_event *event,
int perf_event__parse_sample(const union perf_event *event, u64 type,
int sample_size, bool sample_id_all,
- struct perf_sample *data)
+ struct perf_sample *data, bool swapped)
{
const u64 *array;
+ /*
+ * used for cross-endian analysis. See git commit 65014ab3
+ * for why this goofiness is needed.
+ */
+ union {
+ u64 val64;
+ u32 val32[2];
+ } u;
+
+
data->cpu = data->pid = data->tid = -1;
data->stream_id = data->id = data->time = -1ULL;
@@ -366,9 +378,16 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
}
if (type & PERF_SAMPLE_TID) {
- u32 *p = (u32 *)array;
- data->pid = p[0];
- data->tid = p[1];
+ u.val64 = *array;
+ if (swapped) {
+ /* undo swap of u64, then swap on individual u32s */
+ u.val64 = bswap_64(u.val64);
+ u.val32[0] = bswap_32(u.val32[0]);
+ u.val32[1] = bswap_32(u.val32[1]);
+ }
+
+ data->pid = u.val32[0];
+ data->tid = u.val32[1];
array++;
}
@@ -395,8 +414,15 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
}
if (type & PERF_SAMPLE_CPU) {
- u32 *p = (u32 *)array;
- data->cpu = *p;
+
+ u.val64 = *array;
+ if (swapped) {
+ /* undo swap of u64, then swap on individual u32s */
+ u.val64 = bswap_64(u.val64);
+ u.val32[0] = bswap_32(u.val32[0]);
+ }
+
+ data->cpu = u.val32[0];
array++;
}
@@ -423,18 +449,27 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
}
if (type & PERF_SAMPLE_RAW) {
- u32 *p = (u32 *)array;
+ const u64 *pdata;
+
+ u.val64 = *array;
+ if (WARN_ONCE(swapped,
+ "Endianness of raw data not corrected!\n")) {
+ /* undo swap of u64, then swap on individual u32s */
+ u.val64 = bswap_64(u.val64);
+ u.val32[0] = bswap_32(u.val32[0]);
+ u.val32[1] = bswap_32(u.val32[1]);
+ }
if (sample_overlap(event, array, sizeof(u32)))
return -EFAULT;
- data->raw_size = *p;
- p++;
+ data->raw_size = u.val32[0];
+ pdata = (void *) array + sizeof(u32);
- if (sample_overlap(event, p, data->raw_size))
+ if (sample_overlap(event, pdata, data->raw_size))
return -EFAULT;
- data->raw_data = p;
+ data->raw_data = (void *) pdata;
}
return 0;
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 555fc3864b90..5d732621a462 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -659,7 +659,7 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die))
ret = -ENOENT;
}
- if (ret == 0)
+ if (ret >= 0)
ret = convert_variable(&vr_die, pf);
if (ret < 0)
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index cbc8f215d4b7..7624324efad4 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -803,7 +803,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
first = list_entry(evlist->entries.next, struct perf_evsel, node);
err = perf_event__parse_sample(event, first->attr.sample_type,
perf_evsel__sample_size(first),
- sample_id_all, &pevent->sample);
+ sample_id_all, &pevent->sample, false);
if (err)
return PyErr_Format(PyExc_OSError,
"perf: can't parse sample, err=%d", err);
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 170601e67d6b..974d0cbee5e9 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -162,7 +162,8 @@ static inline int perf_session__parse_sample(struct perf_session *session,
{
return perf_event__parse_sample(event, session->sample_type,
session->sample_size,
- session->sample_id_all, sample);
+ session->sample_id_all, sample,
+ session->header.needs_swap);
}
struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 401e220566fd..1ee8f1e40f18 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -151,11 +151,17 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
{
u64 ip_l, ip_r;
+ if (!left->ms.sym && !right->ms.sym)
+ return right->level - left->level;
+
+ if (!left->ms.sym || !right->ms.sym)
+ return cmp_null(left->ms.sym, right->ms.sym);
+
if (left->ms.sym == right->ms.sym)
return 0;
- ip_l = left->ms.sym ? left->ms.sym->start : left->ip;
- ip_r = right->ms.sym ? right->ms.sym->start : right->ip;
+ ip_l = left->ms.sym->start;
+ ip_r = right->ms.sym->start;
return (int64_t)(ip_r - ip_l);
}
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 469c0264ed29..40eeaf07725b 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -74,16 +74,104 @@ static void dso__set_sorted_by_name(struct dso *dso, enum map_type type)
bool symbol_type__is_a(char symbol_type, enum map_type map_type)
{
+ symbol_type = toupper(symbol_type);
+
switch (map_type) {
case MAP__FUNCTION:
return symbol_type == 'T' || symbol_type == 'W';
case MAP__VARIABLE:
- return symbol_type == 'D' || symbol_type == 'd';
+ return symbol_type == 'D';
default:
return false;
}
}
+static int prefix_underscores_count(const char *str)
+{
+ const char *tail = str;
+
+ while (*tail == '_')
+ tail++;
+
+ return tail - str;
+}
+
+#define SYMBOL_A 0
+#define SYMBOL_B 1
+
+static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
+{
+ s64 a;
+ s64 b;
+
+ /* Prefer a symbol with non zero length */
+ a = syma->end - syma->start;
+ b = symb->end - symb->start;
+ if ((b == 0) && (a > 0))
+ return SYMBOL_A;
+ else if ((a == 0) && (b > 0))
+ return SYMBOL_B;
+
+ /* Prefer a non weak symbol over a weak one */
+ a = syma->binding == STB_WEAK;
+ b = symb->binding == STB_WEAK;
+ if (b && !a)
+ return SYMBOL_A;
+ if (a && !b)
+ return SYMBOL_B;
+
+ /* Prefer a global symbol over a non global one */
+ a = syma->binding == STB_GLOBAL;
+ b = symb->binding == STB_GLOBAL;
+ if (a && !b)
+ return SYMBOL_A;
+ if (b && !a)
+ return SYMBOL_B;
+
+ /* Prefer a symbol with less underscores */
+ a = prefix_underscores_count(syma->name);
+ b = prefix_underscores_count(symb->name);
+ if (b > a)
+ return SYMBOL_A;
+ else if (a > b)
+ return SYMBOL_B;
+
+ /* If all else fails, choose the symbol with the longest name */
+ if (strlen(syma->name) >= strlen(symb->name))
+ return SYMBOL_A;
+ else
+ return SYMBOL_B;
+}
+
+static void symbols__fixup_duplicate(struct rb_root *symbols)
+{
+ struct rb_node *nd;
+ struct symbol *curr, *next;
+
+ nd = rb_first(symbols);
+
+ while (nd) {
+ curr = rb_entry(nd, struct symbol, rb_node);
+again:
+ nd = rb_next(&curr->rb_node);
+ next = rb_entry(nd, struct symbol, rb_node);
+
+ if (!nd)
+ break;
+
+ if (curr->start != next->start)
+ continue;
+
+ if (choose_best_symbol(curr, next) == SYMBOL_A) {
+ rb_erase(&next->rb_node, symbols);
+ goto again;
+ } else {
+ nd = rb_next(&curr->rb_node);
+ rb_erase(&curr->rb_node, symbols);
+ }
+ }
+}
+
static void symbols__fixup_end(struct rb_root *symbols)
{
struct rb_node *nd, *prevnd = rb_first(symbols);
@@ -438,18 +526,11 @@ int kallsyms__parse(const char *filename, void *arg,
char *line = NULL;
size_t n;
int err = -1;
- u64 prev_start = 0;
- char prev_symbol_type = 0;
- char *prev_symbol_name;
FILE *file = fopen(filename, "r");
if (file == NULL)
goto out_failure;
- prev_symbol_name = malloc(KSYM_NAME_LEN);
- if (prev_symbol_name == NULL)
- goto out_close;
-
err = 0;
while (!feof(file)) {
@@ -470,7 +551,7 @@ int kallsyms__parse(const char *filename, void *arg,
if (len + 2 >= line_len)
continue;
- symbol_type = toupper(line[len]);
+ symbol_type = line[len];
len += 2;
symbol_name = line + len;
len = line_len - len;
@@ -480,24 +561,18 @@ int kallsyms__parse(const char *filename, void *arg,
break;
}
- if (prev_symbol_type) {
- u64 end = start;
- if (end != prev_start)
- --end;
- err = process_symbol(arg, prev_symbol_name,
- prev_symbol_type, prev_start, end);
- if (err)
- break;
- }
-
- memcpy(prev_symbol_name, symbol_name, len + 1);
- prev_symbol_type = symbol_type;
- prev_start = start;
+ /*
+ * module symbols are not sorted so we add all
+ * symbols with zero length and rely on
+ * symbols__fixup_end() to fix it up.
+ */
+ err = process_symbol(arg, symbol_name,
+ symbol_type, start, start);
+ if (err)
+ break;
}
- free(prev_symbol_name);
free(line);
-out_close:
fclose(file);
return err;
@@ -703,6 +778,9 @@ int dso__load_kallsyms(struct dso *dso, const char *filename,
if (dso__load_all_kallsyms(dso, filename, map) < 0)
return -1;
+ symbols__fixup_duplicate(&dso->symbols[map->type]);
+ symbols__fixup_end(&dso->symbols[map->type]);
+
if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
dso->symtab_type = SYMTAB__GUEST_KALLSYMS;
else
@@ -1092,8 +1170,7 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
if (dso->has_build_id) {
u8 build_id[BUILD_ID_SIZE];
- if (elf_read_build_id(elf, build_id,
- BUILD_ID_SIZE) != BUILD_ID_SIZE)
+ if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0)
goto out_elf_end;
if (!dso__build_id_equal(dso, build_id))
@@ -1111,6 +1188,8 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
}
opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
+ if (opdshdr.sh_type != SHT_PROGBITS)
+ opdsec = NULL;
if (opdsec)
opddata = elf_rawdata(opdsec, NULL);
@@ -1276,6 +1355,7 @@ new_symbol:
* For misannotated, zeroed, ASM function sizes.
*/
if (nr > 0) {
+ symbols__fixup_duplicate(&dso->symbols[map->type]);
symbols__fixup_end(&dso->symbols[map->type]);
if (kmap) {
/*
@@ -1362,8 +1442,8 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size)
ptr = data->d_buf;
while (ptr < (data->d_buf + data->d_size)) {
GElf_Nhdr *nhdr = ptr;
- int namesz = NOTE_ALIGN(nhdr->n_namesz),
- descsz = NOTE_ALIGN(nhdr->n_descsz);
+ size_t namesz = NOTE_ALIGN(nhdr->n_namesz),
+ descsz = NOTE_ALIGN(nhdr->n_descsz);
const char *name;
ptr += sizeof(*nhdr);
@@ -1372,8 +1452,10 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size)
if (nhdr->n_type == NT_GNU_BUILD_ID &&
nhdr->n_namesz == sizeof("GNU")) {
if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
- memcpy(bf, ptr, BUILD_ID_SIZE);
- err = BUILD_ID_SIZE;
+ size_t sz = min(size, descsz);
+ memcpy(bf, ptr, sz);
+ memset(bf + sz, 0, size - sz);
+ err = descsz;
break;
}
}
@@ -1425,7 +1507,7 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
while (1) {
char bf[BUFSIZ];
GElf_Nhdr nhdr;
- int namesz, descsz;
+ size_t namesz, descsz;
if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
break;
@@ -1434,15 +1516,16 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
descsz = NOTE_ALIGN(nhdr.n_descsz);
if (nhdr.n_type == NT_GNU_BUILD_ID &&
nhdr.n_namesz == sizeof("GNU")) {
- if (read(fd, bf, namesz) != namesz)
+ if (read(fd, bf, namesz) != (ssize_t)namesz)
break;
if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
- if (read(fd, build_id,
- BUILD_ID_SIZE) == BUILD_ID_SIZE) {
+ size_t sz = min(descsz, size);
+ if (read(fd, build_id, sz) == (ssize_t)sz) {
+ memset(build_id + sz, 0, size - sz);
err = 0;
break;
}
- } else if (read(fd, bf, descsz) != descsz)
+ } else if (read(fd, bf, descsz) != (ssize_t)descsz)
break;
} else {
int n = namesz + descsz;
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile
index 94c2cf0a98b8..e8a03aceceb1 100644
--- a/tools/power/cpupower/Makefile
+++ b/tools/power/cpupower/Makefile
@@ -24,7 +24,7 @@
# Set the following to `true' to make a unstripped, unoptimized
# binary. Leave this set to `false' for production use.
-DEBUG ?= false
+DEBUG ?= true
# make the build silent. Set this to something else to make it noisy again.
V ?= false
@@ -35,7 +35,7 @@ NLS ?= true
# Set the following to 'true' to build/install the
# cpufreq-bench benchmarking tool
-CPUFRQ_BENCH ?= true
+CPUFREQ_BENCH ?= true
# Prefix to the directories we're installing to
DESTDIR ?=
@@ -137,9 +137,10 @@ CFLAGS += -pipe
ifeq ($(strip $(NLS)),true)
INSTALL_NLS += install-gmo
COMPILE_NLS += create-gmo
+ CFLAGS += -DNLS
endif
-ifeq ($(strip $(CPUFRQ_BENCH)),true)
+ifeq ($(strip $(CPUFREQ_BENCH)),true)
INSTALL_BENCH += install-bench
COMPILE_BENCH += compile-bench
endif
diff --git a/tools/power/cpupower/debug/x86_64/Makefile b/tools/power/cpupower/debug/x86_64/Makefile
index dbf13998462a..3326217dd311 100644
--- a/tools/power/cpupower/debug/x86_64/Makefile
+++ b/tools/power/cpupower/debug/x86_64/Makefile
@@ -1,10 +1,10 @@
default: all
-centrino-decode: centrino-decode.c
- $(CC) $(CFLAGS) -o centrino-decode centrino-decode.c
+centrino-decode: ../i386/centrino-decode.c
+ $(CC) $(CFLAGS) -o $@ $<
-powernow-k8-decode: powernow-k8-decode.c
- $(CC) $(CFLAGS) -o powernow-k8-decode powernow-k8-decode.c
+powernow-k8-decode: ../i386/powernow-k8-decode.c
+ $(CC) $(CFLAGS) -o $@ $<
all: centrino-decode powernow-k8-decode
diff --git a/tools/power/cpupower/debug/x86_64/centrino-decode.c b/tools/power/cpupower/debug/x86_64/centrino-decode.c
deleted file mode 120000
index 26fb3f1d8fc7..000000000000
--- a/tools/power/cpupower/debug/x86_64/centrino-decode.c
+++ /dev/null
@@ -1 +0,0 @@
-../i386/centrino-decode.c \ No newline at end of file
diff --git a/tools/power/cpupower/debug/x86_64/powernow-k8-decode.c b/tools/power/cpupower/debug/x86_64/powernow-k8-decode.c
deleted file mode 120000
index eb30c79cf9df..000000000000
--- a/tools/power/cpupower/debug/x86_64/powernow-k8-decode.c
+++ /dev/null
@@ -1 +0,0 @@
-../i386/powernow-k8-decode.c \ No newline at end of file
diff --git a/tools/power/cpupower/man/cpupower-frequency-info.1 b/tools/power/cpupower/man/cpupower-frequency-info.1
index 3194811d58f5..bb60a8d1e45a 100644
--- a/tools/power/cpupower/man/cpupower-frequency-info.1
+++ b/tools/power/cpupower/man/cpupower-frequency-info.1
@@ -1,10 +1,10 @@
-.TH "cpufreq-info" "1" "0.1" "Mattia Dongili" ""
+.TH "cpupower-frequency-info" "1" "0.1" "Mattia Dongili" ""
.SH "NAME"
.LP
-cpufreq\-info \- Utility to retrieve cpufreq kernel information
+cpupower frequency\-info \- Utility to retrieve cpufreq kernel information
.SH "SYNTAX"
.LP
-cpufreq\-info [\fIoptions\fP]
+cpupower [ \-c cpulist ] frequency\-info [\fIoptions\fP]
.SH "DESCRIPTION"
.LP
A small tool which prints out cpufreq information helpful to developers and interested users.
diff --git a/tools/power/cpupower/man/cpupower-frequency-set.1 b/tools/power/cpupower/man/cpupower-frequency-set.1
index 26e3e13eee3b..685f469093ad 100644
--- a/tools/power/cpupower/man/cpupower-frequency-set.1
+++ b/tools/power/cpupower/man/cpupower-frequency-set.1
@@ -1,13 +1,13 @@
-.TH "cpufreq-set" "1" "0.1" "Mattia Dongili" ""
+.TH "cpupower-freqency-set" "1" "0.1" "Mattia Dongili" ""
.SH "NAME"
.LP
-cpufreq\-set \- A small tool which allows to modify cpufreq settings.
+cpupower frequency\-set \- A small tool which allows to modify cpufreq settings.
.SH "SYNTAX"
.LP
-cpufreq\-set [\fIoptions\fP]
+cpupower [ \-c cpu ] frequency\-set [\fIoptions\fP]
.SH "DESCRIPTION"
.LP
-cpufreq\-set allows you to modify cpufreq settings without having to type e.g. "/sys/devices/system/cpu/cpu0/cpufreq/scaling_set_speed" all the time.
+cpupower frequency\-set allows you to modify cpufreq settings without having to type e.g. "/sys/devices/system/cpu/cpu0/cpufreq/scaling_set_speed" all the time.
.SH "OPTIONS"
.LP
.TP
diff --git a/tools/power/cpupower/man/cpupower.1 b/tools/power/cpupower/man/cpupower.1
index 78c20feab85c..baf741d06e82 100644
--- a/tools/power/cpupower/man/cpupower.1
+++ b/tools/power/cpupower/man/cpupower.1
@@ -3,7 +3,7 @@
cpupower \- Shows and sets processor power related values
.SH SYNOPSIS
.ft B
-.B cpupower [ \-c cpulist ] subcommand [ARGS]
+.B cpupower [ \-c cpulist ] <command> [ARGS]
.B cpupower \-v|\-\-version
@@ -13,24 +13,24 @@ cpupower \- Shows and sets processor power related values
\fBcpupower \fP is a collection of tools to examine and tune power saving
related features of your processor.
-The manpages of the subcommands (cpupower\-<subcommand>(1)) provide detailed
+The manpages of the commands (cpupower\-<command>(1)) provide detailed
descriptions of supported features. Run \fBcpupower help\fP to get an overview
-of supported subcommands.
+of supported commands.
.SH Options
.PP
\-\-help, \-h
.RS 4
-Shows supported subcommands and general usage.
+Shows supported commands and general usage.
.RE
.PP
\-\-cpu cpulist, \-c cpulist
.RS 4
Only show or set values for specific cores.
-This option is not supported by all subcommands, details can be found in the
-manpages of the subcommands.
+This option is not supported by all commands, details can be found in the
+manpages of the commands.
-Some subcommands access all cores (typically the *\-set commands), some only
+Some commands access all cores (typically the *\-set commands), some only
the first core (typically the *\-info commands) by default.
The syntax for <cpulist> is based on how the kernel exports CPU bitmasks via
diff --git a/tools/power/cpupower/utils/builtin.h b/tools/power/cpupower/utils/builtin.h
index c870ffba5219..c10496fbe3c6 100644
--- a/tools/power/cpupower/utils/builtin.h
+++ b/tools/power/cpupower/utils/builtin.h
@@ -8,11 +8,4 @@ extern int cmd_freq_info(int argc, const char **argv);
extern int cmd_idle_info(int argc, const char **argv);
extern int cmd_monitor(int argc, const char **argv);
-extern void set_help(void);
-extern void info_help(void);
-extern void freq_set_help(void);
-extern void freq_info_help(void);
-extern void idle_info_help(void);
-extern void monitor_help(void);
-
#endif
diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c
index 5a1d25f056b3..28953c9a7bd5 100644
--- a/tools/power/cpupower/utils/cpufreq-info.c
+++ b/tools/power/cpupower/utils/cpufreq-info.c
@@ -510,37 +510,6 @@ static int get_latency(unsigned int cpu, unsigned int human)
return 0;
}
-void freq_info_help(void)
-{
- printf(_("Usage: cpupower freqinfo [options]\n"));
- printf(_("Options:\n"));
- printf(_(" -e, --debug Prints out debug information [default]\n"));
- printf(_(" -f, --freq Get frequency the CPU currently runs at, according\n"
- " to the cpufreq core *\n"));
- printf(_(" -w, --hwfreq Get frequency the CPU currently runs at, by reading\n"
- " it from hardware (only available to root) *\n"));
- printf(_(" -l, --hwlimits Determine the minimum and maximum CPU frequency allowed *\n"));
- printf(_(" -d, --driver Determines the used cpufreq kernel driver *\n"));
- printf(_(" -p, --policy Gets the currently used cpufreq policy *\n"));
- printf(_(" -g, --governors Determines available cpufreq governors *\n"));
- printf(_(" -r, --related-cpus Determines which CPUs run at the same hardware frequency *\n"));
- printf(_(" -a, --affected-cpus Determines which CPUs need to have their frequency\n"
- " coordinated by software *\n"));
- printf(_(" -s, --stats Shows cpufreq statistics if available\n"));
- printf(_(" -y, --latency Determines the maximum latency on CPU frequency changes *\n"));
- printf(_(" -b, --boost Checks for turbo or boost modes *\n"));
- printf(_(" -o, --proc Prints out information like provided by the /proc/cpufreq\n"
- " interface in 2.4. and early 2.6. kernels\n"));
- printf(_(" -m, --human human-readable output for the -f, -w, -s and -y parameters\n"));
- printf(_(" -h, --help Prints out this screen\n"));
-
- printf("\n");
- printf(_("If no argument is given, full output about\n"
- "cpufreq is printed which is useful e.g. for reporting bugs.\n\n"));
- printf(_("By default info of CPU 0 is shown which can be overridden\n"
- "with the cpupower --cpu main command option.\n"));
-}
-
static struct option info_opts[] = {
{ .name = "debug", .has_arg = no_argument, .flag = NULL, .val = 'e'},
{ .name = "boost", .has_arg = no_argument, .flag = NULL, .val = 'b'},
@@ -556,7 +525,6 @@ static struct option info_opts[] = {
{ .name = "latency", .has_arg = no_argument, .flag = NULL, .val = 'y'},
{ .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'},
{ .name = "human", .has_arg = no_argument, .flag = NULL, .val = 'm'},
- { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'},
{ },
};
@@ -570,16 +538,12 @@ int cmd_freq_info(int argc, char **argv)
int output_param = 0;
do {
- ret = getopt_long(argc, argv, "hoefwldpgrasmyb", info_opts, NULL);
+ ret = getopt_long(argc, argv, "oefwldpgrasmyb", info_opts, NULL);
switch (ret) {
case '?':
output_param = '?';
cont = 0;
break;
- case 'h':
- output_param = 'h';
- cont = 0;
- break;
case -1:
cont = 0;
break;
@@ -642,11 +606,7 @@ int cmd_freq_info(int argc, char **argv)
return -EINVAL;
case '?':
printf(_("invalid or unknown argument\n"));
- freq_info_help();
return -EINVAL;
- case 'h':
- freq_info_help();
- return EXIT_SUCCESS;
case 'o':
proc_cpufreq_output();
return EXIT_SUCCESS;
diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c
index 5f783622bf31..dd1539eb8c63 100644
--- a/tools/power/cpupower/utils/cpufreq-set.c
+++ b/tools/power/cpupower/utils/cpufreq-set.c
@@ -20,34 +20,11 @@
#define NORM_FREQ_LEN 32
-void freq_set_help(void)
-{
- printf(_("Usage: cpupower frequency-set [options]\n"));
- printf(_("Options:\n"));
- printf(_(" -d FREQ, --min FREQ new minimum CPU frequency the governor may select\n"));
- printf(_(" -u FREQ, --max FREQ new maximum CPU frequency the governor may select\n"));
- printf(_(" -g GOV, --governor GOV new cpufreq governor\n"));
- printf(_(" -f FREQ, --freq FREQ specific frequency to be set. Requires userspace\n"
- " governor to be available and loaded\n"));
- printf(_(" -r, --related Switches all hardware-related CPUs\n"));
- printf(_(" -h, --help Prints out this screen\n"));
- printf("\n");
- printf(_("Notes:\n"
- "1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n"));
- printf(_("2. The -f FREQ, --freq FREQ parameter cannot be combined with any other parameter\n"
- " except the -c CPU, --cpu CPU parameter\n"
- "3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n"
- " by postfixing the value with the wanted unit name, without any space\n"
- " (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"));
-
-}
-
static struct option set_opts[] = {
{ .name = "min", .has_arg = required_argument, .flag = NULL, .val = 'd'},
{ .name = "max", .has_arg = required_argument, .flag = NULL, .val = 'u'},
{ .name = "governor", .has_arg = required_argument, .flag = NULL, .val = 'g'},
{ .name = "freq", .has_arg = required_argument, .flag = NULL, .val = 'f'},
- { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'},
{ .name = "related", .has_arg = no_argument, .flag = NULL, .val='r'},
{ },
};
@@ -80,7 +57,6 @@ const struct freq_units def_units[] = {
static void print_unknown_arg(void)
{
printf(_("invalid or unknown argument\n"));
- freq_set_help();
}
static unsigned long string_to_frequency(const char *str)
@@ -231,14 +207,11 @@ int cmd_freq_set(int argc, char **argv)
/* parameter parsing */
do {
- ret = getopt_long(argc, argv, "d:u:g:f:hr", set_opts, NULL);
+ ret = getopt_long(argc, argv, "d:u:g:f:r", set_opts, NULL);
switch (ret) {
case '?':
print_unknown_arg();
return -EINVAL;
- case 'h':
- freq_set_help();
- return 0;
case -1:
cont = 0;
break;
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c
index 70da3574f1e9..b028267c1376 100644
--- a/tools/power/cpupower/utils/cpuidle-info.c
+++ b/tools/power/cpupower/utils/cpuidle-info.c
@@ -139,30 +139,14 @@ static void proc_cpuidle_cpu_output(unsigned int cpu)
}
}
-/* --freq / -f */
-
-void idle_info_help(void)
-{
- printf(_ ("Usage: cpupower idleinfo [options]\n"));
- printf(_ ("Options:\n"));
- printf(_ (" -s, --silent Only show general C-state information\n"));
- printf(_ (" -o, --proc Prints out information like provided by the /proc/acpi/processor/*/power\n"
- " interface in older kernels\n"));
- printf(_ (" -h, --help Prints out this screen\n"));
-
- printf("\n");
-}
-
static struct option info_opts[] = {
{ .name = "silent", .has_arg = no_argument, .flag = NULL, .val = 's'},
{ .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'},
- { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'},
{ },
};
static inline void cpuidle_exit(int fail)
{
- idle_info_help();
exit(EXIT_FAILURE);
}
@@ -174,7 +158,7 @@ int cmd_idle_info(int argc, char **argv)
unsigned int cpu = 0;
do {
- ret = getopt_long(argc, argv, "hos", info_opts, NULL);
+ ret = getopt_long(argc, argv, "os", info_opts, NULL);
if (ret == -1)
break;
switch (ret) {
@@ -182,10 +166,6 @@ int cmd_idle_info(int argc, char **argv)
output_param = '?';
cont = 0;
break;
- case 'h':
- output_param = 'h';
- cont = 0;
- break;
case 's':
verbose = 0;
break;
@@ -211,8 +191,6 @@ int cmd_idle_info(int argc, char **argv)
case '?':
printf(_("invalid or unknown argument\n"));
cpuidle_exit(EXIT_FAILURE);
- case 'h':
- cpuidle_exit(EXIT_SUCCESS);
}
/* Default is: show output of CPU 0 only */
diff --git a/tools/power/cpupower/utils/cpupower-info.c b/tools/power/cpupower/utils/cpupower-info.c
index 85253cb7600e..3f68632c28c7 100644
--- a/tools/power/cpupower/utils/cpupower-info.c
+++ b/tools/power/cpupower/utils/cpupower-info.c
@@ -16,31 +16,16 @@
#include "helpers/helpers.h"
#include "helpers/sysfs.h"
-void info_help(void)
-{
- printf(_("Usage: cpupower info [ -b ] [ -m ] [ -s ]\n"));
- printf(_("Options:\n"));
- printf(_(" -b, --perf-bias Gets CPU's power vs performance policy on some\n"
- " Intel models [0-15], see manpage for details\n"));
- printf(_(" -m, --sched-mc Gets the kernel's multi core scheduler policy.\n"));
- printf(_(" -s, --sched-smt Gets the kernel's thread sibling scheduler policy.\n"));
- printf(_(" -h, --help Prints out this screen\n"));
- printf(_("\nPassing no option will show all info, by default only on core 0\n"));
- printf("\n");
-}
-
static struct option set_opts[] = {
{ .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'},
{ .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'},
{ .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'},
- { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'},
{ },
};
static void print_wrong_arg_exit(void)
{
printf(_("invalid or unknown argument\n"));
- info_help();
exit(EXIT_FAILURE);
}
@@ -64,11 +49,8 @@ int cmd_info(int argc, char **argv)
textdomain(PACKAGE);
/* parameter parsing */
- while ((ret = getopt_long(argc, argv, "msbh", set_opts, NULL)) != -1) {
+ while ((ret = getopt_long(argc, argv, "msb", set_opts, NULL)) != -1) {
switch (ret) {
- case 'h':
- info_help();
- return 0;
case 'b':
if (params.perf_bias)
print_wrong_arg_exit();
diff --git a/tools/power/cpupower/utils/cpupower-set.c b/tools/power/cpupower/utils/cpupower-set.c
index bc1b391e46f0..dc4de3762111 100644
--- a/tools/power/cpupower/utils/cpupower-set.c
+++ b/tools/power/cpupower/utils/cpupower-set.c
@@ -17,30 +17,16 @@
#include "helpers/sysfs.h"
#include "helpers/bitmask.h"
-void set_help(void)
-{
- printf(_("Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n"));
- printf(_("Options:\n"));
- printf(_(" -b, --perf-bias [VAL] Sets CPU's power vs performance policy on some\n"
- " Intel models [0-15], see manpage for details\n"));
- printf(_(" -m, --sched-mc [VAL] Sets the kernel's multi core scheduler policy.\n"));
- printf(_(" -s, --sched-smt [VAL] Sets the kernel's thread sibling scheduler policy.\n"));
- printf(_(" -h, --help Prints out this screen\n"));
- printf("\n");
-}
-
static struct option set_opts[] = {
{ .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'},
{ .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'},
{ .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'},
- { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'},
{ },
};
static void print_wrong_arg_exit(void)
{
printf(_("invalid or unknown argument\n"));
- set_help();
exit(EXIT_FAILURE);
}
@@ -66,12 +52,9 @@ int cmd_set(int argc, char **argv)
params.params = 0;
/* parameter parsing */
- while ((ret = getopt_long(argc, argv, "m:s:b:h",
+ while ((ret = getopt_long(argc, argv, "m:s:b:",
set_opts, NULL)) != -1) {
switch (ret) {
- case 'h':
- set_help();
- return 0;
case 'b':
if (params.perf_bias)
print_wrong_arg_exit();
@@ -110,10 +93,8 @@ int cmd_set(int argc, char **argv)
}
};
- if (!params.params) {
- set_help();
- return -EINVAL;
- }
+ if (!params.params)
+ print_wrong_arg_exit();
if (params.sched_mc) {
ret = sysfs_set_sched("mc", sched_mc);
diff --git a/tools/power/cpupower/utils/cpupower.c b/tools/power/cpupower/utils/cpupower.c
index 5844ae0f786f..52bee591c1c5 100644
--- a/tools/power/cpupower/utils/cpupower.c
+++ b/tools/power/cpupower/utils/cpupower.c
@@ -11,6 +11,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <errno.h>
#include "builtin.h"
#include "helpers/helpers.h"
@@ -19,13 +20,12 @@
struct cmd_struct {
const char *cmd;
int (*main)(int, const char **);
- void (*usage)(void);
int needs_root;
};
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
-int cmd_help(int argc, const char **argv);
+static int cmd_help(int argc, const char **argv);
/* Global cpu_info object available for all binaries
* Info only retrieved from CPU 0
@@ -44,55 +44,66 @@ int be_verbose;
static void print_help(void);
static struct cmd_struct commands[] = {
- { "frequency-info", cmd_freq_info, freq_info_help, 0 },
- { "frequency-set", cmd_freq_set, freq_set_help, 1 },
- { "idle-info", cmd_idle_info, idle_info_help, 0 },
- { "set", cmd_set, set_help, 1 },
- { "info", cmd_info, info_help, 0 },
- { "monitor", cmd_monitor, monitor_help, 0 },
- { "help", cmd_help, print_help, 0 },
- /* { "bench", cmd_bench, NULL, 1 }, */
+ { "frequency-info", cmd_freq_info, 0 },
+ { "frequency-set", cmd_freq_set, 1 },
+ { "idle-info", cmd_idle_info, 0 },
+ { "set", cmd_set, 1 },
+ { "info", cmd_info, 0 },
+ { "monitor", cmd_monitor, 0 },
+ { "help", cmd_help, 0 },
+ /* { "bench", cmd_bench, 1 }, */
};
-int cmd_help(int argc, const char **argv)
-{
- unsigned int i;
-
- if (argc > 1) {
- for (i = 0; i < ARRAY_SIZE(commands); i++) {
- struct cmd_struct *p = commands + i;
- if (strcmp(p->cmd, argv[1]))
- continue;
- if (p->usage) {
- p->usage();
- return EXIT_SUCCESS;
- }
- }
- }
- print_help();
- if (argc == 1)
- return EXIT_SUCCESS; /* cpupower help */
- return EXIT_FAILURE;
-}
-
static void print_help(void)
{
unsigned int i;
#ifdef DEBUG
- printf(_("cpupower [ -d ][ -c cpulist ] subcommand [ARGS]\n"));
- printf(_(" -d, --debug May increase output (stderr) on some subcommands\n"));
+ printf(_("Usage:\tcpupower [-d|--debug] [-c|--cpu cpulist ] <command> [<args>]\n"));
#else
- printf(_("cpupower [ -c cpulist ] subcommand [ARGS]\n"));
+ printf(_("Usage:\tcpupower [-c|--cpu cpulist ] <command> [<args>]\n"));
#endif
- printf(_("cpupower --version\n"));
- printf(_("Supported subcommands are:\n"));
+ printf(_("Supported commands are:\n"));
for (i = 0; i < ARRAY_SIZE(commands); i++)
printf("\t%s\n", commands[i].cmd);
- printf(_("\nSome subcommands can make use of the -c cpulist option.\n"));
- printf(_("Look at the general cpupower manpage how to use it\n"));
- printf(_("and read up the subcommand's manpage whether it is supported.\n"));
- printf(_("\nUse cpupower help subcommand for getting help for above subcommands.\n"));
+ printf(_("\nNot all commands can make use of the -c cpulist option.\n"));
+ printf(_("\nUse 'cpupower help <command>' for getting help for above commands.\n"));
+}
+
+static int print_man_page(const char *subpage)
+{
+ int len;
+ char *page;
+
+ len = 10; /* enough for "cpupower-" */
+ if (subpage != NULL)
+ len += strlen(subpage);
+
+ page = malloc(len);
+ if (!page)
+ return -ENOMEM;
+
+ sprintf(page, "cpupower");
+ if ((subpage != NULL) && strcmp(subpage, "help")) {
+ strcat(page, "-");
+ strcat(page, subpage);
+ }
+
+ execlp("man", "man", page, NULL);
+
+ /* should not be reached */
+ return -EINVAL;
+}
+
+static int cmd_help(int argc, const char **argv)
+{
+ if (argc > 1) {
+ print_man_page(argv[1]); /* exits within execlp() */
+ return EXIT_FAILURE;
+ }
+
+ print_help();
+ return EXIT_SUCCESS;
}
static void print_version(void)
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h
index 592ee362b877..2747e738efb0 100644
--- a/tools/power/cpupower/utils/helpers/helpers.h
+++ b/tools/power/cpupower/utils/helpers/helpers.h
@@ -16,11 +16,20 @@
#include "helpers/bitmask.h"
/* Internationalization ****************************/
+#ifdef NLS
+
#define _(String) gettext(String)
#ifndef gettext_noop
#define gettext_noop(String) String
#endif
#define N_(String) gettext_noop(String)
+
+#else /* !NLS */
+
+#define _(String) String
+#define N_(String) String
+
+#endif
/* Internationalization ****************************/
extern int run_as_root;
@@ -96,6 +105,9 @@ struct cpupower_topology {
int pkg;
int core;
int cpu;
+
+ /* flags */
+ unsigned int is_online:1;
} *core_info;
};
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c
index 55e2466674c6..c6343024a611 100644
--- a/tools/power/cpupower/utils/helpers/sysfs.c
+++ b/tools/power/cpupower/utils/helpers/sysfs.c
@@ -56,6 +56,56 @@ static unsigned int sysfs_write_file(const char *path,
return (unsigned int) numwrite;
}
+/*
+ * Detect whether a CPU is online
+ *
+ * Returns:
+ * 1 -> if CPU is online
+ * 0 -> if CPU is offline
+ * negative errno values in error case
+ */
+int sysfs_is_cpu_online(unsigned int cpu)
+{
+ char path[SYSFS_PATH_MAX];
+ int fd;
+ ssize_t numread;
+ unsigned long long value;
+ char linebuf[MAX_LINE_LEN];
+ char *endp;
+ struct stat statbuf;
+
+ snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu);
+
+ if (stat(path, &statbuf) != 0)
+ return 0;
+
+ /*
+ * kernel without CONFIG_HOTPLUG_CPU
+ * -> cpuX directory exists, but not cpuX/online file
+ */
+ snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu);
+ if (stat(path, &statbuf) != 0)
+ return 1;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return -errno;
+
+ numread = read(fd, linebuf, MAX_LINE_LEN - 1);
+ if (numread < 1) {
+ close(fd);
+ return -EIO;
+ }
+ linebuf[numread] = '\0';
+ close(fd);
+
+ value = strtoull(linebuf, &endp, 0);
+ if (value > 1 || value < 0)
+ return -EINVAL;
+
+ return value;
+}
+
/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
/*
diff --git a/tools/power/cpupower/utils/helpers/sysfs.h b/tools/power/cpupower/utils/helpers/sysfs.h
index f9373e090637..8cb797bbceb0 100644
--- a/tools/power/cpupower/utils/helpers/sysfs.h
+++ b/tools/power/cpupower/utils/helpers/sysfs.h
@@ -7,6 +7,8 @@
extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen);
+extern int sysfs_is_cpu_online(unsigned int cpu);
+
extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
unsigned int idlestate);
extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c
index 385ee5c7570c..4eae2c47ba48 100644
--- a/tools/power/cpupower/utils/helpers/topology.c
+++ b/tools/power/cpupower/utils/helpers/topology.c
@@ -41,6 +41,8 @@ struct cpuid_core_info {
unsigned int pkg;
unsigned int thread;
unsigned int cpu;
+ /* flags */
+ unsigned int is_online:1;
};
static int __compare(const void *t1, const void *t2)
@@ -78,6 +80,8 @@ int get_cpu_topology(struct cpupower_topology *cpu_top)
return -ENOMEM;
cpu_top->pkgs = cpu_top->cores = 0;
for (cpu = 0; cpu < cpus; cpu++) {
+ cpu_top->core_info[cpu].cpu = cpu;
+ cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu);
cpu_top->core_info[cpu].pkg =
sysfs_topology_read_file(cpu, "physical_package_id");
if ((int)cpu_top->core_info[cpu].pkg != -1 &&
@@ -85,7 +89,6 @@ int get_cpu_topology(struct cpupower_topology *cpu_top)
cpu_top->pkgs = cpu_top->core_info[cpu].pkg;
cpu_top->core_info[cpu].core =
sysfs_topology_read_file(cpu, "core_id");
- cpu_top->core_info[cpu].cpu = cpu;
}
cpu_top->pkgs++;
diff --git a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
index d048b96a6155..bcd22a1a3970 100644
--- a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
+++ b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
@@ -134,7 +134,7 @@ static struct cpuidle_monitor *cpuidle_register(void)
/* Assume idle state count is the same for all CPUs */
cpuidle_sysfs_monitor.hw_states_num = sysfs_get_idlestate_count(0);
- if (cpuidle_sysfs_monitor.hw_states_num == 0)
+ if (cpuidle_sysfs_monitor.hw_states_num <= 0)
return NULL;
for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) {
diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
index ba4bf068380d..0d6571e418db 100644
--- a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
+++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
@@ -43,6 +43,12 @@ static struct cpupower_topology cpu_top;
/* ToDo: Document this in the manpage */
static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', };
+static void print_wrong_arg_exit(void)
+{
+ printf(_("invalid or unknown argument\n"));
+ exit(EXIT_FAILURE);
+}
+
long long timespec_diff_us(struct timespec start, struct timespec end)
{
struct timespec temp;
@@ -56,21 +62,6 @@ long long timespec_diff_us(struct timespec start, struct timespec end)
return (temp.tv_sec * 1000000) + (temp.tv_nsec / 1000);
}
-void monitor_help(void)
-{
- printf(_("cpupower monitor: [-m <mon1>,[<mon2>],.. ] command\n"));
- printf(_("cpupower monitor: [-m <mon1>,[<mon2>],.. ] [ -i interval_sec ]\n"));
- printf(_("cpupower monitor: -l\n"));
- printf(_("\t command: pass an arbitrary command to measure specific workload\n"));
- printf(_("\t -i: time intervall to measure for in seconds (default 1)\n"));
- printf(_("\t -l: list available CPU sleep monitors (for use with -m)\n"));
- printf(_("\t -m: show specific CPU sleep monitors only (in same order)\n"));
- printf(_("\t -h: print this help\n"));
- printf("\n");
- printf(_("only one of: -l, -m are allowed\nIf none of them is passed,"));
- printf(_(" all supported monitors are shown\n"));
-}
-
void print_n_spaces(int n)
{
int x;
@@ -149,6 +140,10 @@ void print_results(int topology_depth, int cpu)
unsigned long long result;
cstate_t s;
+ /* Be careful CPUs may got resorted for pkg value do not just use cpu */
+ if (!bitmask_isbitset(cpus_chosen, cpu_top.core_info[cpu].cpu))
+ return;
+
if (topology_depth > 2)
printf("%4d|", cpu_top.core_info[cpu].pkg);
if (topology_depth > 1)
@@ -190,9 +185,13 @@ void print_results(int topology_depth, int cpu)
}
}
}
- /* cpu offline */
- if (cpu_top.core_info[cpu].pkg == -1 ||
- cpu_top.core_info[cpu].core == -1) {
+ /*
+ * The monitor could still provide useful data, for example
+ * AMD HW counters partly sit in PCI config space.
+ * It's up to the monitor plug-in to check .is_online, this one
+ * is just for additional info.
+ */
+ if (!cpu_top.core_info[cpu].is_online) {
printf(_(" *is offline\n"));
return;
} else
@@ -238,7 +237,6 @@ static void parse_monitor_param(char *param)
if (hits == 0) {
printf(_("No matching monitor found in %s, "
"try -l option\n"), param);
- monitor_help();
exit(EXIT_FAILURE);
}
/* Override detected/registerd monitors array with requested one */
@@ -335,37 +333,27 @@ static void cmdline(int argc, char *argv[])
int opt;
progname = basename(argv[0]);
- while ((opt = getopt(argc, argv, "+hli:m:")) != -1) {
+ while ((opt = getopt(argc, argv, "+li:m:")) != -1) {
switch (opt) {
- case 'h':
- monitor_help();
- exit(EXIT_SUCCESS);
case 'l':
- if (mode) {
- monitor_help();
- exit(EXIT_FAILURE);
- }
+ if (mode)
+ print_wrong_arg_exit();
mode = list;
break;
case 'i':
/* only allow -i with -m or no option */
- if (mode && mode != show) {
- monitor_help();
- exit(EXIT_FAILURE);
- }
+ if (mode && mode != show)
+ print_wrong_arg_exit();
interval = atoi(optarg);
break;
case 'm':
- if (mode) {
- monitor_help();
- exit(EXIT_FAILURE);
- }
+ if (mode)
+ print_wrong_arg_exit();
mode = show;
show_monitors_param = optarg;
break;
default:
- monitor_help();
- exit(EXIT_FAILURE);
+ print_wrong_arg_exit();
}
}
if (!mode)
@@ -385,6 +373,10 @@ int cmd_monitor(int argc, char **argv)
return EXIT_FAILURE;
}
+ /* Default is: monitor all CPUs */
+ if (bitmask_isallclear(cpus_chosen))
+ bitmask_setall(cpus_chosen);
+
dprint("System has up to %d CPU cores\n", cpu_count);
for (num = 0; all_monitors[num]; num++) {
diff --git a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
index 63ca87a05e5f..5650ab5a2c20 100644
--- a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
+++ b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
@@ -22,12 +22,15 @@
#define MSR_TSC 0x10
+#define MSR_AMD_HWCR 0xc0010015
+
enum mperf_id { C0 = 0, Cx, AVG_FREQ, MPERF_CSTATE_COUNT };
static int mperf_get_count_percent(unsigned int self_id, double *percent,
unsigned int cpu);
static int mperf_get_count_freq(unsigned int id, unsigned long long *count,
unsigned int cpu);
+static struct timespec time_start, time_end;
static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = {
{
@@ -54,19 +57,33 @@ static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = {
},
};
+enum MAX_FREQ_MODE { MAX_FREQ_SYSFS, MAX_FREQ_TSC_REF };
+static int max_freq_mode;
+/*
+ * The max frequency mperf is ticking at (in C0), either retrieved via:
+ * 1) calculated after measurements if we know TSC ticks at mperf/P0 frequency
+ * 2) cpufreq /sys/devices/.../cpu0/cpufreq/cpuinfo_max_freq at init time
+ * 1. Is preferred as it also works without cpufreq subsystem (e.g. on Xen)
+ */
+static unsigned long max_frequency;
+
static unsigned long long tsc_at_measure_start;
static unsigned long long tsc_at_measure_end;
-static unsigned long max_frequency;
static unsigned long long *mperf_previous_count;
static unsigned long long *aperf_previous_count;
static unsigned long long *mperf_current_count;
static unsigned long long *aperf_current_count;
+
/* valid flag for all CPUs. If a MSR read failed it will be zero */
static int *is_valid;
static int mperf_get_tsc(unsigned long long *tsc)
{
- return read_msr(0, MSR_TSC, tsc);
+ int ret;
+ ret = read_msr(0, MSR_TSC, tsc);
+ if (ret)
+ dprint("Reading TSC MSR failed, returning %llu\n", *tsc);
+ return ret;
}
static int mperf_init_stats(unsigned int cpu)
@@ -97,36 +114,11 @@ static int mperf_measure_stats(unsigned int cpu)
return 0;
}
-/*
- * get_average_perf()
- *
- * Returns the average performance (also considers boosted frequencies)
- *
- * Input:
- * aperf_diff: Difference of the aperf register over a time period
- * mperf_diff: Difference of the mperf register over the same time period
- * max_freq: Maximum frequency (P0)
- *
- * Returns:
- * Average performance over the time period
- */
-static unsigned long get_average_perf(unsigned long long aperf_diff,
- unsigned long long mperf_diff)
-{
- unsigned int perf_percent = 0;
- if (((unsigned long)(-1) / 100) < aperf_diff) {
- int shift_count = 7;
- aperf_diff >>= shift_count;
- mperf_diff >>= shift_count;
- }
- perf_percent = (aperf_diff * 100) / mperf_diff;
- return (max_frequency * perf_percent) / 100;
-}
-
static int mperf_get_count_percent(unsigned int id, double *percent,
unsigned int cpu)
{
unsigned long long aperf_diff, mperf_diff, tsc_diff;
+ unsigned long long timediff;
if (!is_valid[cpu])
return -1;
@@ -136,11 +128,19 @@ static int mperf_get_count_percent(unsigned int id, double *percent,
mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu];
aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu];
- tsc_diff = tsc_at_measure_end - tsc_at_measure_start;
- *percent = 100.0 * mperf_diff / tsc_diff;
- dprint("%s: mperf_diff: %llu, tsc_diff: %llu\n",
- mperf_cstates[id].name, mperf_diff, tsc_diff);
+ if (max_freq_mode == MAX_FREQ_TSC_REF) {
+ tsc_diff = tsc_at_measure_end - tsc_at_measure_start;
+ *percent = 100.0 * mperf_diff / tsc_diff;
+ dprint("%s: TSC Ref - mperf_diff: %llu, tsc_diff: %llu\n",
+ mperf_cstates[id].name, mperf_diff, tsc_diff);
+ } else if (max_freq_mode == MAX_FREQ_SYSFS) {
+ timediff = timespec_diff_us(time_start, time_end);
+ *percent = 100.0 * mperf_diff / timediff;
+ dprint("%s: MAXFREQ - mperf_diff: %llu, time_diff: %llu\n",
+ mperf_cstates[id].name, mperf_diff, timediff);
+ } else
+ return -1;
if (id == Cx)
*percent = 100.0 - *percent;
@@ -154,7 +154,7 @@ static int mperf_get_count_percent(unsigned int id, double *percent,
static int mperf_get_count_freq(unsigned int id, unsigned long long *count,
unsigned int cpu)
{
- unsigned long long aperf_diff, mperf_diff;
+ unsigned long long aperf_diff, mperf_diff, time_diff, tsc_diff;
if (id != AVG_FREQ)
return 1;
@@ -165,11 +165,21 @@ static int mperf_get_count_freq(unsigned int id, unsigned long long *count,
mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu];
aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu];
- /* Return MHz for now, might want to return KHz if column width is more
- generic */
- *count = get_average_perf(aperf_diff, mperf_diff) / 1000;
- dprint("%s: %llu\n", mperf_cstates[id].name, *count);
+ if (max_freq_mode == MAX_FREQ_TSC_REF) {
+ /* Calculate max_freq from TSC count */
+ tsc_diff = tsc_at_measure_end - tsc_at_measure_start;
+ time_diff = timespec_diff_us(time_start, time_end);
+ max_frequency = tsc_diff / time_diff;
+ }
+ *count = max_frequency * ((double)aperf_diff / mperf_diff);
+ dprint("%s: Average freq based on %s maximum frequency:\n",
+ mperf_cstates[id].name,
+ (max_freq_mode == MAX_FREQ_TSC_REF) ? "TSC calculated" : "sysfs read");
+ dprint("%max_frequency: %lu", max_frequency);
+ dprint("aperf_diff: %llu\n", aperf_diff);
+ dprint("mperf_diff: %llu\n", mperf_diff);
+ dprint("avg freq: %llu\n", *count);
return 0;
}
@@ -178,6 +188,7 @@ static int mperf_start(void)
int cpu;
unsigned long long dbg;
+ clock_gettime(CLOCK_REALTIME, &time_start);
mperf_get_tsc(&tsc_at_measure_start);
for (cpu = 0; cpu < cpu_count; cpu++)
@@ -193,32 +204,104 @@ static int mperf_stop(void)
unsigned long long dbg;
int cpu;
- mperf_get_tsc(&tsc_at_measure_end);
-
for (cpu = 0; cpu < cpu_count; cpu++)
mperf_measure_stats(cpu);
+ mperf_get_tsc(&tsc_at_measure_end);
+ clock_gettime(CLOCK_REALTIME, &time_end);
+
mperf_get_tsc(&dbg);
dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end);
return 0;
}
-struct cpuidle_monitor mperf_monitor;
-
-struct cpuidle_monitor *mperf_register(void)
+/*
+ * Mperf register is defined to tick at P0 (maximum) frequency
+ *
+ * Instead of reading out P0 which can be tricky to read out from HW,
+ * we use TSC counter if it reliably ticks at P0/mperf frequency.
+ *
+ * Still try to fall back to:
+ * /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
+ * on older Intel HW without invariant TSC feature.
+ * Or on AMD machines where TSC does not tick at P0 (do not exist yet, but
+ * it's still double checked (MSR_AMD_HWCR)).
+ *
+ * On these machines the user would still get useful mperf
+ * stats when acpi-cpufreq driver is loaded.
+ */
+static int init_maxfreq_mode(void)
{
+ int ret;
+ unsigned long long hwcr;
unsigned long min;
- if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF))
- return NULL;
-
- /* Assume min/max all the same on all cores */
+ if (!cpupower_cpu_info.caps & CPUPOWER_CAP_INV_TSC)
+ goto use_sysfs;
+
+ if (cpupower_cpu_info.vendor == X86_VENDOR_AMD) {
+ /* MSR_AMD_HWCR tells us whether TSC runs at P0/mperf
+ * freq.
+ * A test whether hwcr is accessable/available would be:
+ * (cpupower_cpu_info.family > 0x10 ||
+ * cpupower_cpu_info.family == 0x10 &&
+ * cpupower_cpu_info.model >= 0x2))
+ * This should be the case for all aperf/mperf
+ * capable AMD machines and is therefore safe to test here.
+ * Compare with Linus kernel git commit: acf01734b1747b1ec4
+ */
+ ret = read_msr(0, MSR_AMD_HWCR, &hwcr);
+ /*
+ * If the MSR read failed, assume a Xen system that did
+ * not explicitly provide access to it and assume TSC works
+ */
+ if (ret != 0) {
+ dprint("TSC read 0x%x failed - assume TSC working\n",
+ MSR_AMD_HWCR);
+ return 0;
+ } else if (1 & (hwcr >> 24)) {
+ max_freq_mode = MAX_FREQ_TSC_REF;
+ return 0;
+ } else { /* Use sysfs max frequency if available */ }
+ } else if (cpupower_cpu_info.vendor == X86_VENDOR_INTEL) {
+ /*
+ * On Intel we assume mperf (in C0) is ticking at same
+ * rate than TSC
+ */
+ max_freq_mode = MAX_FREQ_TSC_REF;
+ return 0;
+ }
+use_sysfs:
if (cpufreq_get_hardware_limits(0, &min, &max_frequency)) {
dprint("Cannot retrieve max freq from cpufreq kernel "
"subsystem\n");
- return NULL;
+ return -1;
}
+ max_freq_mode = MAX_FREQ_SYSFS;
+ return 0;
+}
+
+/*
+ * This monitor provides:
+ *
+ * 1) Average frequency a CPU resided in
+ * This always works if the CPU has aperf/mperf capabilities
+ *
+ * 2) C0 and Cx (any sleep state) time a CPU resided in
+ * Works if mperf timer stops ticking in sleep states which
+ * seem to be the case on all current HW.
+ * Both is directly retrieved from HW registers and is independent
+ * from kernel statistics.
+ */
+struct cpuidle_monitor mperf_monitor;
+struct cpuidle_monitor *mperf_register(void)
+{
+ if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF))
+ return NULL;
+
+ if (init_maxfreq_mode())
+ return NULL;
/* Free this at program termination */
is_valid = calloc(cpu_count, sizeof(int));
diff --git a/virt/kvm/assigned-dev.c b/virt/kvm/assigned-dev.c
index 4e9eaeb518c7..eaf3a50f9769 100644
--- a/virt/kvm/assigned-dev.c
+++ b/virt/kvm/assigned-dev.c
@@ -205,6 +205,8 @@ static void kvm_free_assigned_device(struct kvm *kvm,
else
pci_restore_state(assigned_dev->dev);
+ assigned_dev->dev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED;
+
pci_release_regions(assigned_dev->dev);
pci_disable_device(assigned_dev->dev);
pci_dev_put(assigned_dev->dev);
diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c
index 78c80f67f535..967aba133a62 100644
--- a/virt/kvm/iommu.c
+++ b/virt/kvm/iommu.c
@@ -187,6 +187,8 @@ int kvm_assign_device(struct kvm *kvm,
goto out_unmap;
}
+ pdev->dev_flags |= PCI_DEV_FLAGS_ASSIGNED;
+
printk(KERN_DEBUG "assign device %x:%x:%x.%x\n",
assigned_dev->host_segnr,
assigned_dev->host_busnr,
@@ -215,6 +217,8 @@ int kvm_deassign_device(struct kvm *kvm,
iommu_detach_device(domain, &pdev->dev);
+ pdev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED;
+
printk(KERN_DEBUG "deassign device %x:%x:%x.%x\n",
assigned_dev->host_segnr,
assigned_dev->host_busnr,